1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd 4 * Author:Mark Yao <mark.yao@rock-chips.com> 5 * 6 * based on exynos_drm_drv.c 7 */ 8 9 #include <linux/dma-mapping.h> 10 #include <linux/pm_runtime.h> 11 #include <linux/module.h> 12 #include <linux/of_graph.h> 13 #include <linux/of_platform.h> 14 #include <linux/component.h> 15 #include <linux/console.h> 16 #include <linux/iommu.h> 17 18 #include <drm/drm_aperture.h> 19 #include <drm/drm_drv.h> 20 #include <drm/drm_fb_helper.h> 21 #include <drm/drm_gem_cma_helper.h> 22 #include <drm/drm_of.h> 23 #include <drm/drm_probe_helper.h> 24 #include <drm/drm_vblank.h> 25 26 #if defined(CONFIG_ARM_DMA_USE_IOMMU) 27 #include <asm/dma-iommu.h> 28 #else 29 #define arm_iommu_detach_device(...) ({ }) 30 #define arm_iommu_release_mapping(...) ({ }) 31 #define to_dma_iommu_mapping(dev) NULL 32 #endif 33 34 #include "rockchip_drm_drv.h" 35 #include "rockchip_drm_fb.h" 36 #include "rockchip_drm_gem.h" 37 38 #define DRIVER_NAME "rockchip" 39 #define DRIVER_DESC "RockChip Soc DRM" 40 #define DRIVER_DATE "20140818" 41 #define DRIVER_MAJOR 1 42 #define DRIVER_MINOR 0 43 44 static const struct drm_driver rockchip_drm_driver; 45 46 /* 47 * Attach a (component) device to the shared drm dma mapping from master drm 48 * device. This is used by the VOPs to map GEM buffers to a common DMA 49 * mapping. 50 */ 51 int rockchip_drm_dma_attach_device(struct drm_device *drm_dev, 52 struct device *dev) 53 { 54 struct rockchip_drm_private *private = drm_dev->dev_private; 55 int ret; 56 57 if (!private->domain) 58 return 0; 59 60 if (IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)) { 61 struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev); 62 63 if (mapping) { 64 arm_iommu_detach_device(dev); 65 arm_iommu_release_mapping(mapping); 66 } 67 } 68 69 ret = iommu_attach_device(private->domain, dev); 70 if (ret) { 71 DRM_DEV_ERROR(dev, "Failed to attach iommu device\n"); 72 return ret; 73 } 74 75 return 0; 76 } 77 78 void rockchip_drm_dma_detach_device(struct drm_device *drm_dev, 79 struct device *dev) 80 { 81 struct rockchip_drm_private *private = drm_dev->dev_private; 82 83 if (!private->domain) 84 return; 85 86 iommu_detach_device(private->domain, dev); 87 } 88 89 void rockchip_drm_dma_init_device(struct drm_device *drm_dev, 90 struct device *dev) 91 { 92 struct rockchip_drm_private *private = drm_dev->dev_private; 93 94 if (!device_iommu_mapped(dev)) 95 private->iommu_dev = ERR_PTR(-ENODEV); 96 else if (!private->iommu_dev) 97 private->iommu_dev = dev; 98 } 99 100 static int rockchip_drm_init_iommu(struct drm_device *drm_dev) 101 { 102 struct rockchip_drm_private *private = drm_dev->dev_private; 103 struct iommu_domain_geometry *geometry; 104 u64 start, end; 105 106 if (IS_ERR_OR_NULL(private->iommu_dev)) 107 return 0; 108 109 private->domain = iommu_domain_alloc(private->iommu_dev->bus); 110 if (!private->domain) 111 return -ENOMEM; 112 113 geometry = &private->domain->geometry; 114 start = geometry->aperture_start; 115 end = geometry->aperture_end; 116 117 DRM_DEBUG("IOMMU context initialized (aperture: %#llx-%#llx)\n", 118 start, end); 119 drm_mm_init(&private->mm, start, end - start + 1); 120 mutex_init(&private->mm_lock); 121 122 return 0; 123 } 124 125 static void rockchip_iommu_cleanup(struct drm_device *drm_dev) 126 { 127 struct rockchip_drm_private *private = drm_dev->dev_private; 128 129 if (!private->domain) 130 return; 131 132 drm_mm_takedown(&private->mm); 133 iommu_domain_free(private->domain); 134 } 135 136 static int rockchip_drm_bind(struct device *dev) 137 { 138 struct drm_device *drm_dev; 139 struct rockchip_drm_private *private; 140 int ret; 141 142 /* Remove existing drivers that may own the framebuffer memory. */ 143 ret = drm_aperture_remove_framebuffers(false, &rockchip_drm_driver); 144 if (ret) { 145 DRM_DEV_ERROR(dev, 146 "Failed to remove existing framebuffers - %d.\n", 147 ret); 148 return ret; 149 } 150 151 drm_dev = drm_dev_alloc(&rockchip_drm_driver, dev); 152 if (IS_ERR(drm_dev)) 153 return PTR_ERR(drm_dev); 154 155 dev_set_drvdata(dev, drm_dev); 156 157 private = devm_kzalloc(drm_dev->dev, sizeof(*private), GFP_KERNEL); 158 if (!private) { 159 ret = -ENOMEM; 160 goto err_free; 161 } 162 163 drm_dev->dev_private = private; 164 165 ret = drmm_mode_config_init(drm_dev); 166 if (ret) 167 goto err_free; 168 169 rockchip_drm_mode_config_init(drm_dev); 170 171 /* Try to bind all sub drivers. */ 172 ret = component_bind_all(dev, drm_dev); 173 if (ret) 174 goto err_free; 175 176 ret = rockchip_drm_init_iommu(drm_dev); 177 if (ret) 178 goto err_unbind_all; 179 180 ret = drm_vblank_init(drm_dev, drm_dev->mode_config.num_crtc); 181 if (ret) 182 goto err_iommu_cleanup; 183 184 drm_mode_config_reset(drm_dev); 185 186 /* init kms poll for handling hpd */ 187 drm_kms_helper_poll_init(drm_dev); 188 189 ret = drm_dev_register(drm_dev, 0); 190 if (ret) 191 goto err_kms_helper_poll_fini; 192 193 drm_fbdev_generic_setup(drm_dev, 0); 194 195 return 0; 196 err_kms_helper_poll_fini: 197 drm_kms_helper_poll_fini(drm_dev); 198 err_iommu_cleanup: 199 rockchip_iommu_cleanup(drm_dev); 200 err_unbind_all: 201 component_unbind_all(dev, drm_dev); 202 err_free: 203 drm_dev_put(drm_dev); 204 return ret; 205 } 206 207 static void rockchip_drm_unbind(struct device *dev) 208 { 209 struct drm_device *drm_dev = dev_get_drvdata(dev); 210 211 drm_dev_unregister(drm_dev); 212 213 drm_kms_helper_poll_fini(drm_dev); 214 215 drm_atomic_helper_shutdown(drm_dev); 216 component_unbind_all(dev, drm_dev); 217 rockchip_iommu_cleanup(drm_dev); 218 219 drm_dev_put(drm_dev); 220 } 221 222 DEFINE_DRM_GEM_FOPS(rockchip_drm_driver_fops); 223 224 static const struct drm_driver rockchip_drm_driver = { 225 .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC, 226 .dumb_create = rockchip_gem_dumb_create, 227 .prime_handle_to_fd = drm_gem_prime_handle_to_fd, 228 .prime_fd_to_handle = drm_gem_prime_fd_to_handle, 229 .gem_prime_import_sg_table = rockchip_gem_prime_import_sg_table, 230 .gem_prime_mmap = drm_gem_prime_mmap, 231 .fops = &rockchip_drm_driver_fops, 232 .name = DRIVER_NAME, 233 .desc = DRIVER_DESC, 234 .date = DRIVER_DATE, 235 .major = DRIVER_MAJOR, 236 .minor = DRIVER_MINOR, 237 }; 238 239 #ifdef CONFIG_PM_SLEEP 240 static int rockchip_drm_sys_suspend(struct device *dev) 241 { 242 struct drm_device *drm = dev_get_drvdata(dev); 243 244 return drm_mode_config_helper_suspend(drm); 245 } 246 247 static int rockchip_drm_sys_resume(struct device *dev) 248 { 249 struct drm_device *drm = dev_get_drvdata(dev); 250 251 return drm_mode_config_helper_resume(drm); 252 } 253 #endif 254 255 static const struct dev_pm_ops rockchip_drm_pm_ops = { 256 SET_SYSTEM_SLEEP_PM_OPS(rockchip_drm_sys_suspend, 257 rockchip_drm_sys_resume) 258 }; 259 260 #define MAX_ROCKCHIP_SUB_DRIVERS 16 261 static struct platform_driver *rockchip_sub_drivers[MAX_ROCKCHIP_SUB_DRIVERS]; 262 static int num_rockchip_sub_drivers; 263 264 /* 265 * Get the endpoint id of the remote endpoint of the given encoder. This 266 * information is used by the VOP2 driver to identify the encoder. 267 * 268 * @rkencoder: The encoder to get the remote endpoint id from 269 * @np: The encoder device node 270 * @port: The number of the port leading to the VOP2 271 * @reg: The endpoint number leading to the VOP2 272 */ 273 int rockchip_drm_encoder_set_crtc_endpoint_id(struct rockchip_encoder *rkencoder, 274 struct device_node *np, int port, int reg) 275 { 276 struct of_endpoint ep; 277 struct device_node *en, *ren; 278 int ret; 279 280 en = of_graph_get_endpoint_by_regs(np, port, reg); 281 if (!en) 282 return -ENOENT; 283 284 ren = of_graph_get_remote_endpoint(en); 285 if (!ren) 286 return -ENOENT; 287 288 ret = of_graph_parse_endpoint(ren, &ep); 289 if (ret) 290 return ret; 291 292 rkencoder->crtc_endpoint_id = ep.id; 293 294 return 0; 295 } 296 297 /* 298 * Check if a vop endpoint is leading to a rockchip subdriver or bridge. 299 * Should be called from the component bind stage of the drivers 300 * to ensure that all subdrivers are probed. 301 * 302 * @ep: endpoint of a rockchip vop 303 * 304 * returns true if subdriver, false if external bridge and -ENODEV 305 * if remote port does not contain a device. 306 */ 307 int rockchip_drm_endpoint_is_subdriver(struct device_node *ep) 308 { 309 struct device_node *node = of_graph_get_remote_port_parent(ep); 310 struct platform_device *pdev; 311 struct device_driver *drv; 312 int i; 313 314 if (!node) 315 return -ENODEV; 316 317 /* status disabled will prevent creation of platform-devices */ 318 if (!of_device_is_available(node)) { 319 of_node_put(node); 320 return -ENODEV; 321 } 322 323 pdev = of_find_device_by_node(node); 324 of_node_put(node); 325 326 /* enabled non-platform-devices can immediately return here */ 327 if (!pdev) 328 return false; 329 330 /* 331 * All rockchip subdrivers have probed at this point, so 332 * any device not having a driver now is an external bridge. 333 */ 334 drv = pdev->dev.driver; 335 if (!drv) { 336 platform_device_put(pdev); 337 return false; 338 } 339 340 for (i = 0; i < num_rockchip_sub_drivers; i++) { 341 if (rockchip_sub_drivers[i] == to_platform_driver(drv)) { 342 platform_device_put(pdev); 343 return true; 344 } 345 } 346 347 platform_device_put(pdev); 348 return false; 349 } 350 351 static void rockchip_drm_match_remove(struct device *dev) 352 { 353 struct device_link *link; 354 355 list_for_each_entry(link, &dev->links.consumers, s_node) 356 device_link_del(link); 357 } 358 359 static struct component_match *rockchip_drm_match_add(struct device *dev) 360 { 361 struct component_match *match = NULL; 362 int i; 363 364 for (i = 0; i < num_rockchip_sub_drivers; i++) { 365 struct platform_driver *drv = rockchip_sub_drivers[i]; 366 struct device *p = NULL, *d; 367 368 do { 369 d = platform_find_device_by_driver(p, &drv->driver); 370 put_device(p); 371 p = d; 372 373 if (!d) 374 break; 375 376 device_link_add(dev, d, DL_FLAG_STATELESS); 377 component_match_add(dev, &match, component_compare_dev, d); 378 } while (true); 379 } 380 381 if (IS_ERR(match)) 382 rockchip_drm_match_remove(dev); 383 384 return match ?: ERR_PTR(-ENODEV); 385 } 386 387 static const struct component_master_ops rockchip_drm_ops = { 388 .bind = rockchip_drm_bind, 389 .unbind = rockchip_drm_unbind, 390 }; 391 392 static int rockchip_drm_platform_of_probe(struct device *dev) 393 { 394 struct device_node *np = dev->of_node; 395 struct device_node *port; 396 bool found = false; 397 int i; 398 399 if (!np) 400 return -ENODEV; 401 402 for (i = 0;; i++) { 403 port = of_parse_phandle(np, "ports", i); 404 if (!port) 405 break; 406 407 if (!of_device_is_available(port->parent)) { 408 of_node_put(port); 409 continue; 410 } 411 412 found = true; 413 of_node_put(port); 414 } 415 416 if (i == 0) { 417 DRM_DEV_ERROR(dev, "missing 'ports' property\n"); 418 return -ENODEV; 419 } 420 421 if (!found) { 422 DRM_DEV_ERROR(dev, 423 "No available vop found for display-subsystem.\n"); 424 return -ENODEV; 425 } 426 427 return 0; 428 } 429 430 static int rockchip_drm_platform_probe(struct platform_device *pdev) 431 { 432 struct device *dev = &pdev->dev; 433 struct component_match *match = NULL; 434 int ret; 435 436 ret = rockchip_drm_platform_of_probe(dev); 437 if (ret) 438 return ret; 439 440 match = rockchip_drm_match_add(dev); 441 if (IS_ERR(match)) 442 return PTR_ERR(match); 443 444 ret = component_master_add_with_match(dev, &rockchip_drm_ops, match); 445 if (ret < 0) { 446 rockchip_drm_match_remove(dev); 447 return ret; 448 } 449 450 return 0; 451 } 452 453 static int rockchip_drm_platform_remove(struct platform_device *pdev) 454 { 455 component_master_del(&pdev->dev, &rockchip_drm_ops); 456 457 rockchip_drm_match_remove(&pdev->dev); 458 459 return 0; 460 } 461 462 static void rockchip_drm_platform_shutdown(struct platform_device *pdev) 463 { 464 struct drm_device *drm = platform_get_drvdata(pdev); 465 466 if (drm) 467 drm_atomic_helper_shutdown(drm); 468 } 469 470 static const struct of_device_id rockchip_drm_dt_ids[] = { 471 { .compatible = "rockchip,display-subsystem", }, 472 { /* sentinel */ }, 473 }; 474 MODULE_DEVICE_TABLE(of, rockchip_drm_dt_ids); 475 476 static struct platform_driver rockchip_drm_platform_driver = { 477 .probe = rockchip_drm_platform_probe, 478 .remove = rockchip_drm_platform_remove, 479 .shutdown = rockchip_drm_platform_shutdown, 480 .driver = { 481 .name = "rockchip-drm", 482 .of_match_table = rockchip_drm_dt_ids, 483 .pm = &rockchip_drm_pm_ops, 484 }, 485 }; 486 487 #define ADD_ROCKCHIP_SUB_DRIVER(drv, cond) { \ 488 if (IS_ENABLED(cond) && \ 489 !WARN_ON(num_rockchip_sub_drivers >= MAX_ROCKCHIP_SUB_DRIVERS)) \ 490 rockchip_sub_drivers[num_rockchip_sub_drivers++] = &drv; \ 491 } 492 493 static int __init rockchip_drm_init(void) 494 { 495 int ret; 496 497 if (drm_firmware_drivers_only()) 498 return -ENODEV; 499 500 num_rockchip_sub_drivers = 0; 501 ADD_ROCKCHIP_SUB_DRIVER(vop_platform_driver, CONFIG_ROCKCHIP_VOP); 502 ADD_ROCKCHIP_SUB_DRIVER(vop2_platform_driver, CONFIG_ROCKCHIP_VOP2); 503 ADD_ROCKCHIP_SUB_DRIVER(rockchip_lvds_driver, 504 CONFIG_ROCKCHIP_LVDS); 505 ADD_ROCKCHIP_SUB_DRIVER(rockchip_dp_driver, 506 CONFIG_ROCKCHIP_ANALOGIX_DP); 507 ADD_ROCKCHIP_SUB_DRIVER(cdn_dp_driver, CONFIG_ROCKCHIP_CDN_DP); 508 ADD_ROCKCHIP_SUB_DRIVER(dw_hdmi_rockchip_pltfm_driver, 509 CONFIG_ROCKCHIP_DW_HDMI); 510 ADD_ROCKCHIP_SUB_DRIVER(dw_mipi_dsi_rockchip_driver, 511 CONFIG_ROCKCHIP_DW_MIPI_DSI); 512 ADD_ROCKCHIP_SUB_DRIVER(inno_hdmi_driver, CONFIG_ROCKCHIP_INNO_HDMI); 513 ADD_ROCKCHIP_SUB_DRIVER(rk3066_hdmi_driver, 514 CONFIG_ROCKCHIP_RK3066_HDMI); 515 516 ret = platform_register_drivers(rockchip_sub_drivers, 517 num_rockchip_sub_drivers); 518 if (ret) 519 return ret; 520 521 ret = platform_driver_register(&rockchip_drm_platform_driver); 522 if (ret) 523 goto err_unreg_drivers; 524 525 return 0; 526 527 err_unreg_drivers: 528 platform_unregister_drivers(rockchip_sub_drivers, 529 num_rockchip_sub_drivers); 530 return ret; 531 } 532 533 static void __exit rockchip_drm_fini(void) 534 { 535 platform_driver_unregister(&rockchip_drm_platform_driver); 536 537 platform_unregister_drivers(rockchip_sub_drivers, 538 num_rockchip_sub_drivers); 539 } 540 541 module_init(rockchip_drm_init); 542 module_exit(rockchip_drm_fini); 543 544 MODULE_AUTHOR("Mark Yao <mark.yao@rock-chips.com>"); 545 MODULE_DESCRIPTION("ROCKCHIP DRM Driver"); 546 MODULE_LICENSE("GPL v2"); 547