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