imx8qxp-pxl2dpi.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright 2020 NXP
  4. */
  5. #include <linux/firmware/imx/svc/misc.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/pm_runtime.h>
  14. #include <linux/regmap.h>
  15. #include <drm/drm_atomic_state_helper.h>
  16. #include <drm/drm_bridge.h>
  17. #include <drm/drm_of.h>
  18. #include <drm/drm_print.h>
  19. #include <dt-bindings/firmware/imx/rsrc.h>
  20. #define PXL2DPI_CTRL 0x40
  21. #define CFG1_16BIT 0x0
  22. #define CFG2_16BIT 0x1
  23. #define CFG3_16BIT 0x2
  24. #define CFG1_18BIT 0x3
  25. #define CFG2_18BIT 0x4
  26. #define CFG_24BIT 0x5
  27. #define DRIVER_NAME "imx8qxp-pxl2dpi"
  28. struct imx8qxp_pxl2dpi {
  29. struct regmap *regmap;
  30. struct drm_bridge bridge;
  31. struct drm_bridge *next_bridge;
  32. struct drm_bridge *companion;
  33. struct device *dev;
  34. struct imx_sc_ipc *ipc_handle;
  35. u32 sc_resource;
  36. u32 in_bus_format;
  37. u32 out_bus_format;
  38. u32 pl_sel;
  39. };
  40. #define bridge_to_p2d(b) container_of(b, struct imx8qxp_pxl2dpi, bridge)
  41. static int imx8qxp_pxl2dpi_bridge_attach(struct drm_bridge *bridge,
  42. enum drm_bridge_attach_flags flags)
  43. {
  44. struct imx8qxp_pxl2dpi *p2d = bridge->driver_private;
  45. if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) {
  46. DRM_DEV_ERROR(p2d->dev,
  47. "do not support creating a drm_connector\n");
  48. return -EINVAL;
  49. }
  50. if (!bridge->encoder) {
  51. DRM_DEV_ERROR(p2d->dev, "missing encoder\n");
  52. return -ENODEV;
  53. }
  54. return drm_bridge_attach(bridge->encoder,
  55. p2d->next_bridge, bridge,
  56. DRM_BRIDGE_ATTACH_NO_CONNECTOR);
  57. }
  58. static int
  59. imx8qxp_pxl2dpi_bridge_atomic_check(struct drm_bridge *bridge,
  60. struct drm_bridge_state *bridge_state,
  61. struct drm_crtc_state *crtc_state,
  62. struct drm_connector_state *conn_state)
  63. {
  64. struct imx8qxp_pxl2dpi *p2d = bridge->driver_private;
  65. p2d->in_bus_format = bridge_state->input_bus_cfg.format;
  66. p2d->out_bus_format = bridge_state->output_bus_cfg.format;
  67. return 0;
  68. }
  69. static void
  70. imx8qxp_pxl2dpi_bridge_mode_set(struct drm_bridge *bridge,
  71. const struct drm_display_mode *mode,
  72. const struct drm_display_mode *adjusted_mode)
  73. {
  74. struct imx8qxp_pxl2dpi *p2d = bridge->driver_private;
  75. struct imx8qxp_pxl2dpi *companion_p2d;
  76. int ret;
  77. ret = pm_runtime_get_sync(p2d->dev);
  78. if (ret < 0)
  79. DRM_DEV_ERROR(p2d->dev,
  80. "failed to get runtime PM sync: %d\n", ret);
  81. ret = imx_sc_misc_set_control(p2d->ipc_handle, p2d->sc_resource,
  82. IMX_SC_C_PXL_LINK_SEL, p2d->pl_sel);
  83. if (ret)
  84. DRM_DEV_ERROR(p2d->dev,
  85. "failed to set pixel link selection(%u): %d\n",
  86. p2d->pl_sel, ret);
  87. switch (p2d->out_bus_format) {
  88. case MEDIA_BUS_FMT_RGB888_1X24:
  89. regmap_write(p2d->regmap, PXL2DPI_CTRL, CFG_24BIT);
  90. break;
  91. case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
  92. regmap_write(p2d->regmap, PXL2DPI_CTRL, CFG2_18BIT);
  93. break;
  94. default:
  95. DRM_DEV_ERROR(p2d->dev,
  96. "unsupported output bus format 0x%08x\n",
  97. p2d->out_bus_format);
  98. }
  99. if (p2d->companion) {
  100. companion_p2d = bridge_to_p2d(p2d->companion);
  101. companion_p2d->in_bus_format = p2d->in_bus_format;
  102. companion_p2d->out_bus_format = p2d->out_bus_format;
  103. p2d->companion->funcs->mode_set(p2d->companion, mode,
  104. adjusted_mode);
  105. }
  106. }
  107. static void
  108. imx8qxp_pxl2dpi_bridge_atomic_disable(struct drm_bridge *bridge,
  109. struct drm_bridge_state *old_bridge_state)
  110. {
  111. struct imx8qxp_pxl2dpi *p2d = bridge->driver_private;
  112. int ret;
  113. ret = pm_runtime_put(p2d->dev);
  114. if (ret < 0)
  115. DRM_DEV_ERROR(p2d->dev, "failed to put runtime PM: %d\n", ret);
  116. if (p2d->companion)
  117. p2d->companion->funcs->atomic_disable(p2d->companion,
  118. old_bridge_state);
  119. }
  120. static const u32 imx8qxp_pxl2dpi_bus_output_fmts[] = {
  121. MEDIA_BUS_FMT_RGB888_1X24,
  122. MEDIA_BUS_FMT_RGB666_1X24_CPADHI,
  123. };
  124. static bool imx8qxp_pxl2dpi_bus_output_fmt_supported(u32 fmt)
  125. {
  126. int i;
  127. for (i = 0; i < ARRAY_SIZE(imx8qxp_pxl2dpi_bus_output_fmts); i++) {
  128. if (imx8qxp_pxl2dpi_bus_output_fmts[i] == fmt)
  129. return true;
  130. }
  131. return false;
  132. }
  133. static u32 *
  134. imx8qxp_pxl2dpi_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
  135. struct drm_bridge_state *bridge_state,
  136. struct drm_crtc_state *crtc_state,
  137. struct drm_connector_state *conn_state,
  138. u32 output_fmt,
  139. unsigned int *num_input_fmts)
  140. {
  141. u32 *input_fmts;
  142. if (!imx8qxp_pxl2dpi_bus_output_fmt_supported(output_fmt))
  143. return NULL;
  144. *num_input_fmts = 1;
  145. input_fmts = kmalloc(sizeof(*input_fmts), GFP_KERNEL);
  146. if (!input_fmts)
  147. return NULL;
  148. switch (output_fmt) {
  149. case MEDIA_BUS_FMT_RGB888_1X24:
  150. input_fmts[0] = MEDIA_BUS_FMT_RGB888_1X36_CPADLO;
  151. break;
  152. case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
  153. input_fmts[0] = MEDIA_BUS_FMT_RGB666_1X36_CPADLO;
  154. break;
  155. default:
  156. kfree(input_fmts);
  157. input_fmts = NULL;
  158. break;
  159. }
  160. return input_fmts;
  161. }
  162. static u32 *
  163. imx8qxp_pxl2dpi_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge,
  164. struct drm_bridge_state *bridge_state,
  165. struct drm_crtc_state *crtc_state,
  166. struct drm_connector_state *conn_state,
  167. unsigned int *num_output_fmts)
  168. {
  169. *num_output_fmts = ARRAY_SIZE(imx8qxp_pxl2dpi_bus_output_fmts);
  170. return kmemdup(imx8qxp_pxl2dpi_bus_output_fmts,
  171. sizeof(imx8qxp_pxl2dpi_bus_output_fmts), GFP_KERNEL);
  172. }
  173. static const struct drm_bridge_funcs imx8qxp_pxl2dpi_bridge_funcs = {
  174. .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
  175. .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
  176. .atomic_reset = drm_atomic_helper_bridge_reset,
  177. .attach = imx8qxp_pxl2dpi_bridge_attach,
  178. .atomic_check = imx8qxp_pxl2dpi_bridge_atomic_check,
  179. .mode_set = imx8qxp_pxl2dpi_bridge_mode_set,
  180. .atomic_disable = imx8qxp_pxl2dpi_bridge_atomic_disable,
  181. .atomic_get_input_bus_fmts =
  182. imx8qxp_pxl2dpi_bridge_atomic_get_input_bus_fmts,
  183. .atomic_get_output_bus_fmts =
  184. imx8qxp_pxl2dpi_bridge_atomic_get_output_bus_fmts,
  185. };
  186. static struct device_node *
  187. imx8qxp_pxl2dpi_get_available_ep_from_port(struct imx8qxp_pxl2dpi *p2d,
  188. u32 port_id)
  189. {
  190. struct device_node *port, *ep;
  191. int ep_cnt;
  192. port = of_graph_get_port_by_id(p2d->dev->of_node, port_id);
  193. if (!port) {
  194. DRM_DEV_ERROR(p2d->dev, "failed to get port@%u\n", port_id);
  195. return ERR_PTR(-ENODEV);
  196. }
  197. ep_cnt = of_get_available_child_count(port);
  198. if (ep_cnt == 0) {
  199. DRM_DEV_ERROR(p2d->dev, "no available endpoints of port@%u\n",
  200. port_id);
  201. ep = ERR_PTR(-ENODEV);
  202. goto out;
  203. } else if (ep_cnt > 1) {
  204. DRM_DEV_ERROR(p2d->dev,
  205. "invalid available endpoints of port@%u\n",
  206. port_id);
  207. ep = ERR_PTR(-EINVAL);
  208. goto out;
  209. }
  210. ep = of_get_next_available_child(port, NULL);
  211. if (!ep) {
  212. DRM_DEV_ERROR(p2d->dev,
  213. "failed to get available endpoint of port@%u\n",
  214. port_id);
  215. ep = ERR_PTR(-ENODEV);
  216. goto out;
  217. }
  218. out:
  219. of_node_put(port);
  220. return ep;
  221. }
  222. static struct drm_bridge *
  223. imx8qxp_pxl2dpi_find_next_bridge(struct imx8qxp_pxl2dpi *p2d)
  224. {
  225. struct device_node *ep, *remote;
  226. struct drm_bridge *next_bridge;
  227. int ret;
  228. ep = imx8qxp_pxl2dpi_get_available_ep_from_port(p2d, 1);
  229. if (IS_ERR(ep)) {
  230. ret = PTR_ERR(ep);
  231. return ERR_PTR(ret);
  232. }
  233. remote = of_graph_get_remote_port_parent(ep);
  234. if (!remote || !of_device_is_available(remote)) {
  235. DRM_DEV_ERROR(p2d->dev, "no available remote\n");
  236. next_bridge = ERR_PTR(-ENODEV);
  237. goto out;
  238. } else if (!of_device_is_available(remote->parent)) {
  239. DRM_DEV_ERROR(p2d->dev, "remote parent is not available\n");
  240. next_bridge = ERR_PTR(-ENODEV);
  241. goto out;
  242. }
  243. next_bridge = of_drm_find_bridge(remote);
  244. if (!next_bridge) {
  245. next_bridge = ERR_PTR(-EPROBE_DEFER);
  246. goto out;
  247. }
  248. out:
  249. of_node_put(remote);
  250. of_node_put(ep);
  251. return next_bridge;
  252. }
  253. static int imx8qxp_pxl2dpi_set_pixel_link_sel(struct imx8qxp_pxl2dpi *p2d)
  254. {
  255. struct device_node *ep;
  256. struct of_endpoint endpoint;
  257. int ret;
  258. ep = imx8qxp_pxl2dpi_get_available_ep_from_port(p2d, 0);
  259. if (IS_ERR(ep))
  260. return PTR_ERR(ep);
  261. ret = of_graph_parse_endpoint(ep, &endpoint);
  262. if (ret) {
  263. DRM_DEV_ERROR(p2d->dev,
  264. "failed to parse endpoint of port@0: %d\n", ret);
  265. goto out;
  266. }
  267. p2d->pl_sel = endpoint.id;
  268. out:
  269. of_node_put(ep);
  270. return ret;
  271. }
  272. static int imx8qxp_pxl2dpi_parse_dt_companion(struct imx8qxp_pxl2dpi *p2d)
  273. {
  274. struct imx8qxp_pxl2dpi *companion_p2d;
  275. struct device *dev = p2d->dev;
  276. struct device_node *companion;
  277. struct device_node *port1, *port2;
  278. const struct of_device_id *match;
  279. int dual_link;
  280. int ret = 0;
  281. /* Locate the companion PXL2DPI for dual-link operation, if any. */
  282. companion = of_parse_phandle(dev->of_node, "fsl,companion-pxl2dpi", 0);
  283. if (!companion)
  284. return 0;
  285. if (!of_device_is_available(companion)) {
  286. DRM_DEV_ERROR(dev, "companion PXL2DPI is not available\n");
  287. ret = -ENODEV;
  288. goto out;
  289. }
  290. /*
  291. * Sanity check: the companion bridge must have the same compatible
  292. * string.
  293. */
  294. match = of_match_device(dev->driver->of_match_table, dev);
  295. if (!of_device_is_compatible(companion, match->compatible)) {
  296. DRM_DEV_ERROR(dev, "companion PXL2DPI is incompatible\n");
  297. ret = -ENXIO;
  298. goto out;
  299. }
  300. p2d->companion = of_drm_find_bridge(companion);
  301. if (!p2d->companion) {
  302. ret = -EPROBE_DEFER;
  303. DRM_DEV_DEBUG_DRIVER(p2d->dev,
  304. "failed to find companion bridge: %d\n",
  305. ret);
  306. goto out;
  307. }
  308. companion_p2d = bridge_to_p2d(p2d->companion);
  309. /*
  310. * We need to work out if the sink is expecting us to function in
  311. * dual-link mode. We do this by looking at the DT port nodes that
  312. * the next bridges are connected to. If they are marked as expecting
  313. * even pixels and odd pixels than we need to use the companion PXL2DPI.
  314. */
  315. port1 = of_graph_get_port_by_id(p2d->next_bridge->of_node, 1);
  316. port2 = of_graph_get_port_by_id(companion_p2d->next_bridge->of_node, 1);
  317. dual_link = drm_of_lvds_get_dual_link_pixel_order(port1, port2);
  318. of_node_put(port1);
  319. of_node_put(port2);
  320. if (dual_link < 0) {
  321. ret = dual_link;
  322. DRM_DEV_ERROR(dev, "failed to get dual link pixel order: %d\n",
  323. ret);
  324. goto out;
  325. }
  326. DRM_DEV_DEBUG_DRIVER(dev,
  327. "dual-link configuration detected (companion bridge %pOF)\n",
  328. companion);
  329. out:
  330. of_node_put(companion);
  331. return ret;
  332. }
  333. static int imx8qxp_pxl2dpi_bridge_probe(struct platform_device *pdev)
  334. {
  335. struct imx8qxp_pxl2dpi *p2d;
  336. struct device *dev = &pdev->dev;
  337. struct device_node *np = dev->of_node;
  338. int ret;
  339. p2d = devm_kzalloc(dev, sizeof(*p2d), GFP_KERNEL);
  340. if (!p2d)
  341. return -ENOMEM;
  342. p2d->regmap = syscon_node_to_regmap(np->parent);
  343. if (IS_ERR(p2d->regmap)) {
  344. ret = PTR_ERR(p2d->regmap);
  345. if (ret != -EPROBE_DEFER)
  346. DRM_DEV_ERROR(dev, "failed to get regmap: %d\n", ret);
  347. return ret;
  348. }
  349. ret = imx_scu_get_handle(&p2d->ipc_handle);
  350. if (ret) {
  351. if (ret != -EPROBE_DEFER)
  352. DRM_DEV_ERROR(dev, "failed to get SCU ipc handle: %d\n",
  353. ret);
  354. return ret;
  355. }
  356. p2d->dev = dev;
  357. ret = of_property_read_u32(np, "fsl,sc-resource", &p2d->sc_resource);
  358. if (ret) {
  359. DRM_DEV_ERROR(dev, "failed to get SC resource %d\n", ret);
  360. return ret;
  361. }
  362. p2d->next_bridge = imx8qxp_pxl2dpi_find_next_bridge(p2d);
  363. if (IS_ERR(p2d->next_bridge)) {
  364. ret = PTR_ERR(p2d->next_bridge);
  365. if (ret != -EPROBE_DEFER)
  366. DRM_DEV_ERROR(dev, "failed to find next bridge: %d\n",
  367. ret);
  368. return ret;
  369. }
  370. ret = imx8qxp_pxl2dpi_set_pixel_link_sel(p2d);
  371. if (ret)
  372. return ret;
  373. ret = imx8qxp_pxl2dpi_parse_dt_companion(p2d);
  374. if (ret)
  375. return ret;
  376. platform_set_drvdata(pdev, p2d);
  377. pm_runtime_enable(dev);
  378. p2d->bridge.driver_private = p2d;
  379. p2d->bridge.funcs = &imx8qxp_pxl2dpi_bridge_funcs;
  380. p2d->bridge.of_node = np;
  381. drm_bridge_add(&p2d->bridge);
  382. return ret;
  383. }
  384. static int imx8qxp_pxl2dpi_bridge_remove(struct platform_device *pdev)
  385. {
  386. struct imx8qxp_pxl2dpi *p2d = platform_get_drvdata(pdev);
  387. drm_bridge_remove(&p2d->bridge);
  388. pm_runtime_disable(&pdev->dev);
  389. return 0;
  390. }
  391. static const struct of_device_id imx8qxp_pxl2dpi_dt_ids[] = {
  392. { .compatible = "fsl,imx8qxp-pxl2dpi", },
  393. { /* sentinel */ }
  394. };
  395. MODULE_DEVICE_TABLE(of, imx8qxp_pxl2dpi_dt_ids);
  396. static struct platform_driver imx8qxp_pxl2dpi_bridge_driver = {
  397. .probe = imx8qxp_pxl2dpi_bridge_probe,
  398. .remove = imx8qxp_pxl2dpi_bridge_remove,
  399. .driver = {
  400. .of_match_table = imx8qxp_pxl2dpi_dt_ids,
  401. .name = DRIVER_NAME,
  402. },
  403. };
  404. module_platform_driver(imx8qxp_pxl2dpi_bridge_driver);
  405. MODULE_DESCRIPTION("i.MX8QXP pixel link to DPI bridge driver");
  406. MODULE_AUTHOR("Liu Ying <[email protected]>");
  407. MODULE_LICENSE("GPL v2");
  408. MODULE_ALIAS("platform:" DRIVER_NAME);