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