fsl-ldb.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Copyright (C) 2022 Marek Vasut <[email protected]>
  4. */
  5. #include <linux/clk.h>
  6. #include <linux/media-bus-format.h>
  7. #include <linux/mfd/syscon.h>
  8. #include <linux/module.h>
  9. #include <linux/of.h>
  10. #include <linux/of_device.h>
  11. #include <linux/of_graph.h>
  12. #include <linux/platform_device.h>
  13. #include <linux/regmap.h>
  14. #include <drm/drm_atomic_helper.h>
  15. #include <drm/drm_bridge.h>
  16. #include <drm/drm_of.h>
  17. #include <drm/drm_panel.h>
  18. #define LDB_CTRL 0x5c
  19. #define LDB_CTRL_CH0_ENABLE BIT(0)
  20. #define LDB_CTRL_CH0_DI_SELECT BIT(1)
  21. #define LDB_CTRL_CH1_ENABLE BIT(2)
  22. #define LDB_CTRL_CH1_DI_SELECT BIT(3)
  23. #define LDB_CTRL_SPLIT_MODE BIT(4)
  24. #define LDB_CTRL_CH0_DATA_WIDTH BIT(5)
  25. #define LDB_CTRL_CH0_BIT_MAPPING BIT(6)
  26. #define LDB_CTRL_CH1_DATA_WIDTH BIT(7)
  27. #define LDB_CTRL_CH1_BIT_MAPPING BIT(8)
  28. #define LDB_CTRL_DI0_VSYNC_POLARITY BIT(9)
  29. #define LDB_CTRL_DI1_VSYNC_POLARITY BIT(10)
  30. #define LDB_CTRL_REG_CH0_FIFO_RESET BIT(11)
  31. #define LDB_CTRL_REG_CH1_FIFO_RESET BIT(12)
  32. #define LDB_CTRL_ASYNC_FIFO_ENABLE BIT(24)
  33. #define LDB_CTRL_ASYNC_FIFO_THRESHOLD_MASK GENMASK(27, 25)
  34. #define LVDS_CTRL 0x128
  35. #define LVDS_CTRL_CH0_EN BIT(0)
  36. #define LVDS_CTRL_CH1_EN BIT(1)
  37. #define LVDS_CTRL_VBG_EN BIT(2)
  38. #define LVDS_CTRL_HS_EN BIT(3)
  39. #define LVDS_CTRL_PRE_EMPH_EN BIT(4)
  40. #define LVDS_CTRL_PRE_EMPH_ADJ(n) (((n) & 0x7) << 5)
  41. #define LVDS_CTRL_PRE_EMPH_ADJ_MASK GENMASK(7, 5)
  42. #define LVDS_CTRL_CM_ADJ(n) (((n) & 0x7) << 8)
  43. #define LVDS_CTRL_CM_ADJ_MASK GENMASK(10, 8)
  44. #define LVDS_CTRL_CC_ADJ(n) (((n) & 0x7) << 11)
  45. #define LVDS_CTRL_CC_ADJ_MASK GENMASK(13, 11)
  46. #define LVDS_CTRL_SLEW_ADJ(n) (((n) & 0x7) << 14)
  47. #define LVDS_CTRL_SLEW_ADJ_MASK GENMASK(16, 14)
  48. #define LVDS_CTRL_VBG_ADJ(n) (((n) & 0x7) << 17)
  49. #define LVDS_CTRL_VBG_ADJ_MASK GENMASK(19, 17)
  50. struct fsl_ldb {
  51. struct device *dev;
  52. struct drm_bridge bridge;
  53. struct drm_bridge *panel_bridge;
  54. struct clk *clk;
  55. struct regmap *regmap;
  56. bool lvds_dual_link;
  57. };
  58. static inline struct fsl_ldb *to_fsl_ldb(struct drm_bridge *bridge)
  59. {
  60. return container_of(bridge, struct fsl_ldb, bridge);
  61. }
  62. static int fsl_ldb_attach(struct drm_bridge *bridge,
  63. enum drm_bridge_attach_flags flags)
  64. {
  65. struct fsl_ldb *fsl_ldb = to_fsl_ldb(bridge);
  66. return drm_bridge_attach(bridge->encoder, fsl_ldb->panel_bridge,
  67. bridge, flags);
  68. }
  69. static void fsl_ldb_atomic_enable(struct drm_bridge *bridge,
  70. struct drm_bridge_state *old_bridge_state)
  71. {
  72. struct fsl_ldb *fsl_ldb = to_fsl_ldb(bridge);
  73. struct drm_atomic_state *state = old_bridge_state->base.state;
  74. const struct drm_bridge_state *bridge_state;
  75. const struct drm_crtc_state *crtc_state;
  76. const struct drm_display_mode *mode;
  77. struct drm_connector *connector;
  78. struct drm_crtc *crtc;
  79. bool lvds_format_24bpp;
  80. bool lvds_format_jeida;
  81. u32 reg;
  82. /* Get the LVDS format from the bridge state. */
  83. bridge_state = drm_atomic_get_new_bridge_state(state, bridge);
  84. switch (bridge_state->output_bus_cfg.format) {
  85. case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
  86. lvds_format_24bpp = false;
  87. lvds_format_jeida = true;
  88. break;
  89. case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA:
  90. lvds_format_24bpp = true;
  91. lvds_format_jeida = true;
  92. break;
  93. case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG:
  94. lvds_format_24bpp = true;
  95. lvds_format_jeida = false;
  96. break;
  97. default:
  98. /*
  99. * Some bridges still don't set the correct LVDS bus pixel
  100. * format, use SPWG24 default format until those are fixed.
  101. */
  102. lvds_format_24bpp = true;
  103. lvds_format_jeida = false;
  104. dev_warn(fsl_ldb->dev,
  105. "Unsupported LVDS bus format 0x%04x, please check output bridge driver. Falling back to SPWG24.\n",
  106. bridge_state->output_bus_cfg.format);
  107. break;
  108. }
  109. /*
  110. * Retrieve the CRTC adjusted mode. This requires a little dance to go
  111. * from the bridge to the encoder, to the connector and to the CRTC.
  112. */
  113. connector = drm_atomic_get_new_connector_for_encoder(state,
  114. bridge->encoder);
  115. crtc = drm_atomic_get_new_connector_state(state, connector)->crtc;
  116. crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
  117. mode = &crtc_state->adjusted_mode;
  118. if (fsl_ldb->lvds_dual_link)
  119. clk_set_rate(fsl_ldb->clk, mode->clock * 3500);
  120. else
  121. clk_set_rate(fsl_ldb->clk, mode->clock * 7000);
  122. clk_prepare_enable(fsl_ldb->clk);
  123. /* Program LDB_CTRL */
  124. reg = LDB_CTRL_CH0_ENABLE;
  125. if (fsl_ldb->lvds_dual_link)
  126. reg |= LDB_CTRL_CH1_ENABLE | LDB_CTRL_SPLIT_MODE;
  127. if (lvds_format_24bpp) {
  128. reg |= LDB_CTRL_CH0_DATA_WIDTH;
  129. if (fsl_ldb->lvds_dual_link)
  130. reg |= LDB_CTRL_CH1_DATA_WIDTH;
  131. }
  132. if (lvds_format_jeida) {
  133. reg |= LDB_CTRL_CH0_BIT_MAPPING;
  134. if (fsl_ldb->lvds_dual_link)
  135. reg |= LDB_CTRL_CH1_BIT_MAPPING;
  136. }
  137. if (mode->flags & DRM_MODE_FLAG_PVSYNC) {
  138. reg |= LDB_CTRL_DI0_VSYNC_POLARITY;
  139. if (fsl_ldb->lvds_dual_link)
  140. reg |= LDB_CTRL_DI1_VSYNC_POLARITY;
  141. }
  142. regmap_write(fsl_ldb->regmap, LDB_CTRL, reg);
  143. /* Program LVDS_CTRL */
  144. reg = LVDS_CTRL_CC_ADJ(2) | LVDS_CTRL_PRE_EMPH_EN |
  145. LVDS_CTRL_PRE_EMPH_ADJ(3) | LVDS_CTRL_VBG_EN;
  146. regmap_write(fsl_ldb->regmap, LVDS_CTRL, reg);
  147. /* Wait for VBG to stabilize. */
  148. usleep_range(15, 20);
  149. reg |= LVDS_CTRL_CH0_EN;
  150. if (fsl_ldb->lvds_dual_link)
  151. reg |= LVDS_CTRL_CH1_EN;
  152. regmap_write(fsl_ldb->regmap, LVDS_CTRL, reg);
  153. }
  154. static void fsl_ldb_atomic_disable(struct drm_bridge *bridge,
  155. struct drm_bridge_state *old_bridge_state)
  156. {
  157. struct fsl_ldb *fsl_ldb = to_fsl_ldb(bridge);
  158. /* Stop both channels. */
  159. regmap_write(fsl_ldb->regmap, LVDS_CTRL, 0);
  160. regmap_write(fsl_ldb->regmap, LDB_CTRL, 0);
  161. clk_disable_unprepare(fsl_ldb->clk);
  162. }
  163. #define MAX_INPUT_SEL_FORMATS 1
  164. static u32 *
  165. fsl_ldb_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
  166. struct drm_bridge_state *bridge_state,
  167. struct drm_crtc_state *crtc_state,
  168. struct drm_connector_state *conn_state,
  169. u32 output_fmt,
  170. unsigned int *num_input_fmts)
  171. {
  172. u32 *input_fmts;
  173. *num_input_fmts = 0;
  174. input_fmts = kcalloc(MAX_INPUT_SEL_FORMATS, sizeof(*input_fmts),
  175. GFP_KERNEL);
  176. if (!input_fmts)
  177. return NULL;
  178. input_fmts[0] = MEDIA_BUS_FMT_RGB888_1X24;
  179. *num_input_fmts = MAX_INPUT_SEL_FORMATS;
  180. return input_fmts;
  181. }
  182. static enum drm_mode_status
  183. fsl_ldb_mode_valid(struct drm_bridge *bridge,
  184. const struct drm_display_info *info,
  185. const struct drm_display_mode *mode)
  186. {
  187. struct fsl_ldb *fsl_ldb = to_fsl_ldb(bridge);
  188. if (mode->clock > (fsl_ldb->lvds_dual_link ? 160000 : 80000))
  189. return MODE_CLOCK_HIGH;
  190. return MODE_OK;
  191. }
  192. static const struct drm_bridge_funcs funcs = {
  193. .attach = fsl_ldb_attach,
  194. .atomic_enable = fsl_ldb_atomic_enable,
  195. .atomic_disable = fsl_ldb_atomic_disable,
  196. .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
  197. .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
  198. .atomic_get_input_bus_fmts = fsl_ldb_atomic_get_input_bus_fmts,
  199. .atomic_reset = drm_atomic_helper_bridge_reset,
  200. .mode_valid = fsl_ldb_mode_valid,
  201. };
  202. static int fsl_ldb_probe(struct platform_device *pdev)
  203. {
  204. struct device *dev = &pdev->dev;
  205. struct device_node *panel_node;
  206. struct device_node *port1, *port2;
  207. struct drm_panel *panel;
  208. struct fsl_ldb *fsl_ldb;
  209. int dual_link;
  210. fsl_ldb = devm_kzalloc(dev, sizeof(*fsl_ldb), GFP_KERNEL);
  211. if (!fsl_ldb)
  212. return -ENOMEM;
  213. fsl_ldb->dev = &pdev->dev;
  214. fsl_ldb->bridge.funcs = &funcs;
  215. fsl_ldb->bridge.of_node = dev->of_node;
  216. fsl_ldb->clk = devm_clk_get(dev, "ldb");
  217. if (IS_ERR(fsl_ldb->clk))
  218. return PTR_ERR(fsl_ldb->clk);
  219. fsl_ldb->regmap = syscon_node_to_regmap(dev->of_node->parent);
  220. if (IS_ERR(fsl_ldb->regmap))
  221. return PTR_ERR(fsl_ldb->regmap);
  222. /* Locate the panel DT node. */
  223. panel_node = of_graph_get_remote_node(dev->of_node, 1, 0);
  224. if (!panel_node)
  225. return -ENXIO;
  226. panel = of_drm_find_panel(panel_node);
  227. of_node_put(panel_node);
  228. if (IS_ERR(panel))
  229. return PTR_ERR(panel);
  230. fsl_ldb->panel_bridge = devm_drm_panel_bridge_add(dev, panel);
  231. if (IS_ERR(fsl_ldb->panel_bridge))
  232. return PTR_ERR(fsl_ldb->panel_bridge);
  233. /* Determine whether this is dual-link configuration */
  234. port1 = of_graph_get_port_by_id(dev->of_node, 1);
  235. port2 = of_graph_get_port_by_id(dev->of_node, 2);
  236. dual_link = drm_of_lvds_get_dual_link_pixel_order(port1, port2);
  237. of_node_put(port1);
  238. of_node_put(port2);
  239. if (dual_link == DRM_LVDS_DUAL_LINK_EVEN_ODD_PIXELS) {
  240. dev_err(dev, "LVDS channel pixel swap not supported.\n");
  241. return -EINVAL;
  242. }
  243. if (dual_link == DRM_LVDS_DUAL_LINK_ODD_EVEN_PIXELS)
  244. fsl_ldb->lvds_dual_link = true;
  245. platform_set_drvdata(pdev, fsl_ldb);
  246. drm_bridge_add(&fsl_ldb->bridge);
  247. return 0;
  248. }
  249. static int fsl_ldb_remove(struct platform_device *pdev)
  250. {
  251. struct fsl_ldb *fsl_ldb = platform_get_drvdata(pdev);
  252. drm_bridge_remove(&fsl_ldb->bridge);
  253. return 0;
  254. }
  255. static const struct of_device_id fsl_ldb_match[] = {
  256. { .compatible = "fsl,imx8mp-ldb", },
  257. { /* sentinel */ },
  258. };
  259. MODULE_DEVICE_TABLE(of, fsl_ldb_match);
  260. static struct platform_driver fsl_ldb_driver = {
  261. .probe = fsl_ldb_probe,
  262. .remove = fsl_ldb_remove,
  263. .driver = {
  264. .name = "fsl-ldb",
  265. .of_match_table = fsl_ldb_match,
  266. },
  267. };
  268. module_platform_driver(fsl_ldb_driver);
  269. MODULE_AUTHOR("Marek Vasut <[email protected]>");
  270. MODULE_DESCRIPTION("Freescale i.MX8MP LDB");
  271. MODULE_LICENSE("GPL");