1 /* 2 * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd 3 * Author:Mark Yao <mark.yao@rock-chips.com> 4 * 5 * based on exynos_drm_drv.c 6 * 7 * This software is licensed under the terms of the GNU General Public 8 * License version 2, as published by the Free Software Foundation, and 9 * may be copied, distributed, and modified under those terms. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 */ 16 17 #include <drm/drmP.h> 18 #include <drm/drm_crtc_helper.h> 19 #include <drm/drm_fb_helper.h> 20 #include <drm/drm_gem_cma_helper.h> 21 #include <drm/drm_of.h> 22 #include <linux/dma-mapping.h> 23 #include <linux/dma-iommu.h> 24 #include <linux/pm_runtime.h> 25 #include <linux/module.h> 26 #include <linux/of_graph.h> 27 #include <linux/of_platform.h> 28 #include <linux/component.h> 29 #include <linux/console.h> 30 #include <linux/iommu.h> 31 32 #include "rockchip_drm_drv.h" 33 #include "rockchip_drm_fb.h" 34 #include "rockchip_drm_fbdev.h" 35 #include "rockchip_drm_gem.h" 36 37 #define DRIVER_NAME "rockchip" 38 #define DRIVER_DESC "RockChip Soc DRM" 39 #define DRIVER_DATE "20140818" 40 #define DRIVER_MAJOR 1 41 #define DRIVER_MINOR 0 42 43 static bool is_support_iommu = true; 44 static 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 (!is_support_iommu) 58 return 0; 59 60 ret = iommu_attach_device(private->domain, dev); 61 if (ret) { 62 DRM_DEV_ERROR(dev, "Failed to attach iommu device\n"); 63 return ret; 64 } 65 66 return 0; 67 } 68 69 void rockchip_drm_dma_detach_device(struct drm_device *drm_dev, 70 struct device *dev) 71 { 72 struct rockchip_drm_private *private = drm_dev->dev_private; 73 struct iommu_domain *domain = private->domain; 74 75 if (!is_support_iommu) 76 return; 77 78 iommu_detach_device(domain, dev); 79 } 80 81 static int rockchip_drm_init_iommu(struct drm_device *drm_dev) 82 { 83 struct rockchip_drm_private *private = drm_dev->dev_private; 84 struct iommu_domain_geometry *geometry; 85 u64 start, end; 86 87 if (!is_support_iommu) 88 return 0; 89 90 private->domain = iommu_domain_alloc(&platform_bus_type); 91 if (!private->domain) 92 return -ENOMEM; 93 94 geometry = &private->domain->geometry; 95 start = geometry->aperture_start; 96 end = geometry->aperture_end; 97 98 DRM_DEBUG("IOMMU context initialized (aperture: %#llx-%#llx)\n", 99 start, end); 100 drm_mm_init(&private->mm, start, end - start + 1); 101 mutex_init(&private->mm_lock); 102 103 return 0; 104 } 105 106 static void rockchip_iommu_cleanup(struct drm_device *drm_dev) 107 { 108 struct rockchip_drm_private *private = drm_dev->dev_private; 109 110 if (!is_support_iommu) 111 return; 112 113 drm_mm_takedown(&private->mm); 114 iommu_domain_free(private->domain); 115 } 116 117 static int rockchip_drm_bind(struct device *dev) 118 { 119 struct drm_device *drm_dev; 120 struct rockchip_drm_private *private; 121 int ret; 122 123 drm_dev = drm_dev_alloc(&rockchip_drm_driver, dev); 124 if (IS_ERR(drm_dev)) 125 return PTR_ERR(drm_dev); 126 127 dev_set_drvdata(dev, drm_dev); 128 129 private = devm_kzalloc(drm_dev->dev, sizeof(*private), GFP_KERNEL); 130 if (!private) { 131 ret = -ENOMEM; 132 goto err_free; 133 } 134 135 drm_dev->dev_private = private; 136 137 INIT_LIST_HEAD(&private->psr_list); 138 mutex_init(&private->psr_list_lock); 139 140 ret = rockchip_drm_init_iommu(drm_dev); 141 if (ret) 142 goto err_free; 143 144 drm_mode_config_init(drm_dev); 145 146 rockchip_drm_mode_config_init(drm_dev); 147 148 /* Try to bind all sub drivers. */ 149 ret = component_bind_all(dev, drm_dev); 150 if (ret) 151 goto err_mode_config_cleanup; 152 153 ret = drm_vblank_init(drm_dev, drm_dev->mode_config.num_crtc); 154 if (ret) 155 goto err_unbind_all; 156 157 drm_mode_config_reset(drm_dev); 158 159 /* 160 * enable drm irq mode. 161 * - with irq_enabled = true, we can use the vblank feature. 162 */ 163 drm_dev->irq_enabled = true; 164 165 ret = rockchip_drm_fbdev_init(drm_dev); 166 if (ret) 167 goto err_unbind_all; 168 169 /* init kms poll for handling hpd */ 170 drm_kms_helper_poll_init(drm_dev); 171 172 ret = drm_dev_register(drm_dev, 0); 173 if (ret) 174 goto err_kms_helper_poll_fini; 175 176 return 0; 177 err_kms_helper_poll_fini: 178 drm_kms_helper_poll_fini(drm_dev); 179 rockchip_drm_fbdev_fini(drm_dev); 180 err_unbind_all: 181 component_unbind_all(dev, drm_dev); 182 err_mode_config_cleanup: 183 drm_mode_config_cleanup(drm_dev); 184 rockchip_iommu_cleanup(drm_dev); 185 err_free: 186 drm_dev->dev_private = NULL; 187 dev_set_drvdata(dev, NULL); 188 drm_dev_put(drm_dev); 189 return ret; 190 } 191 192 static void rockchip_drm_unbind(struct device *dev) 193 { 194 struct drm_device *drm_dev = dev_get_drvdata(dev); 195 196 drm_dev_unregister(drm_dev); 197 198 rockchip_drm_fbdev_fini(drm_dev); 199 drm_kms_helper_poll_fini(drm_dev); 200 201 drm_atomic_helper_shutdown(drm_dev); 202 component_unbind_all(dev, drm_dev); 203 drm_mode_config_cleanup(drm_dev); 204 rockchip_iommu_cleanup(drm_dev); 205 206 drm_dev->dev_private = NULL; 207 dev_set_drvdata(dev, NULL); 208 drm_dev_put(drm_dev); 209 } 210 211 static const struct file_operations rockchip_drm_driver_fops = { 212 .owner = THIS_MODULE, 213 .open = drm_open, 214 .mmap = rockchip_gem_mmap, 215 .poll = drm_poll, 216 .read = drm_read, 217 .unlocked_ioctl = drm_ioctl, 218 .compat_ioctl = drm_compat_ioctl, 219 .release = drm_release, 220 }; 221 222 static struct drm_driver rockchip_drm_driver = { 223 .driver_features = DRIVER_MODESET | DRIVER_GEM | 224 DRIVER_PRIME | DRIVER_ATOMIC, 225 .lastclose = drm_fb_helper_lastclose, 226 .gem_vm_ops = &drm_gem_cma_vm_ops, 227 .gem_free_object_unlocked = rockchip_gem_free_object, 228 .dumb_create = rockchip_gem_dumb_create, 229 .prime_handle_to_fd = drm_gem_prime_handle_to_fd, 230 .prime_fd_to_handle = drm_gem_prime_fd_to_handle, 231 .gem_prime_import = drm_gem_prime_import, 232 .gem_prime_export = drm_gem_prime_export, 233 .gem_prime_get_sg_table = rockchip_gem_prime_get_sg_table, 234 .gem_prime_import_sg_table = rockchip_gem_prime_import_sg_table, 235 .gem_prime_vmap = rockchip_gem_prime_vmap, 236 .gem_prime_vunmap = rockchip_gem_prime_vunmap, 237 .gem_prime_mmap = rockchip_gem_mmap_buf, 238 .fops = &rockchip_drm_driver_fops, 239 .name = DRIVER_NAME, 240 .desc = DRIVER_DESC, 241 .date = DRIVER_DATE, 242 .major = DRIVER_MAJOR, 243 .minor = DRIVER_MINOR, 244 }; 245 246 #ifdef CONFIG_PM_SLEEP 247 static int rockchip_drm_sys_suspend(struct device *dev) 248 { 249 struct drm_device *drm = dev_get_drvdata(dev); 250 251 return drm_mode_config_helper_suspend(drm); 252 } 253 254 static int rockchip_drm_sys_resume(struct device *dev) 255 { 256 struct drm_device *drm = dev_get_drvdata(dev); 257 258 return drm_mode_config_helper_resume(drm); 259 } 260 #endif 261 262 static const struct dev_pm_ops rockchip_drm_pm_ops = { 263 SET_SYSTEM_SLEEP_PM_OPS(rockchip_drm_sys_suspend, 264 rockchip_drm_sys_resume) 265 }; 266 267 #define MAX_ROCKCHIP_SUB_DRIVERS 16 268 static struct platform_driver *rockchip_sub_drivers[MAX_ROCKCHIP_SUB_DRIVERS]; 269 static int num_rockchip_sub_drivers; 270 271 /* 272 * Check if a vop endpoint is leading to a rockchip subdriver or bridge. 273 * Should be called from the component bind stage of the drivers 274 * to ensure that all subdrivers are probed. 275 * 276 * @ep: endpoint of a rockchip vop 277 * 278 * returns true if subdriver, false if external bridge and -ENODEV 279 * if remote port does not contain a device. 280 */ 281 int rockchip_drm_endpoint_is_subdriver(struct device_node *ep) 282 { 283 struct device_node *node = of_graph_get_remote_port_parent(ep); 284 struct platform_device *pdev; 285 struct device_driver *drv; 286 int i; 287 288 if (!node) 289 return -ENODEV; 290 291 /* status disabled will prevent creation of platform-devices */ 292 pdev = of_find_device_by_node(node); 293 of_node_put(node); 294 if (!pdev) 295 return -ENODEV; 296 297 /* 298 * All rockchip subdrivers have probed at this point, so 299 * any device not having a driver now is an external bridge. 300 */ 301 drv = pdev->dev.driver; 302 if (!drv) { 303 platform_device_put(pdev); 304 return false; 305 } 306 307 for (i = 0; i < num_rockchip_sub_drivers; i++) { 308 if (rockchip_sub_drivers[i] == to_platform_driver(drv)) { 309 platform_device_put(pdev); 310 return true; 311 } 312 } 313 314 platform_device_put(pdev); 315 return false; 316 } 317 318 static int compare_dev(struct device *dev, void *data) 319 { 320 return dev == (struct device *)data; 321 } 322 323 static void rockchip_drm_match_remove(struct device *dev) 324 { 325 struct device_link *link; 326 327 list_for_each_entry(link, &dev->links.consumers, s_node) 328 device_link_del(link); 329 } 330 331 static struct component_match *rockchip_drm_match_add(struct device *dev) 332 { 333 struct component_match *match = NULL; 334 int i; 335 336 for (i = 0; i < num_rockchip_sub_drivers; i++) { 337 struct platform_driver *drv = rockchip_sub_drivers[i]; 338 struct device *p = NULL, *d; 339 340 do { 341 d = bus_find_device(&platform_bus_type, p, &drv->driver, 342 (void *)platform_bus_type.match); 343 put_device(p); 344 p = d; 345 346 if (!d) 347 break; 348 349 device_link_add(dev, d, DL_FLAG_STATELESS); 350 component_match_add(dev, &match, compare_dev, d); 351 } while (true); 352 } 353 354 if (IS_ERR(match)) 355 rockchip_drm_match_remove(dev); 356 357 return match ?: ERR_PTR(-ENODEV); 358 } 359 360 static const struct component_master_ops rockchip_drm_ops = { 361 .bind = rockchip_drm_bind, 362 .unbind = rockchip_drm_unbind, 363 }; 364 365 static int rockchip_drm_platform_of_probe(struct device *dev) 366 { 367 struct device_node *np = dev->of_node; 368 struct device_node *port; 369 bool found = false; 370 int i; 371 372 if (!np) 373 return -ENODEV; 374 375 for (i = 0;; i++) { 376 struct device_node *iommu; 377 378 port = of_parse_phandle(np, "ports", i); 379 if (!port) 380 break; 381 382 if (!of_device_is_available(port->parent)) { 383 of_node_put(port); 384 continue; 385 } 386 387 iommu = of_parse_phandle(port->parent, "iommus", 0); 388 if (!iommu || !of_device_is_available(iommu->parent)) { 389 DRM_DEV_DEBUG(dev, 390 "no iommu attached for %pOF, using non-iommu buffers\n", 391 port->parent); 392 /* 393 * if there is a crtc not support iommu, force set all 394 * crtc use non-iommu buffer. 395 */ 396 is_support_iommu = false; 397 } 398 399 found = true; 400 401 of_node_put(iommu); 402 of_node_put(port); 403 } 404 405 if (i == 0) { 406 DRM_DEV_ERROR(dev, "missing 'ports' property\n"); 407 return -ENODEV; 408 } 409 410 if (!found) { 411 DRM_DEV_ERROR(dev, 412 "No available vop found for display-subsystem.\n"); 413 return -ENODEV; 414 } 415 416 return 0; 417 } 418 419 static int rockchip_drm_platform_probe(struct platform_device *pdev) 420 { 421 struct device *dev = &pdev->dev; 422 struct component_match *match = NULL; 423 int ret; 424 425 ret = rockchip_drm_platform_of_probe(dev); 426 if (ret) 427 return ret; 428 429 match = rockchip_drm_match_add(dev); 430 if (IS_ERR(match)) 431 return PTR_ERR(match); 432 433 ret = component_master_add_with_match(dev, &rockchip_drm_ops, match); 434 if (ret < 0) { 435 rockchip_drm_match_remove(dev); 436 return ret; 437 } 438 439 return 0; 440 } 441 442 static int rockchip_drm_platform_remove(struct platform_device *pdev) 443 { 444 component_master_del(&pdev->dev, &rockchip_drm_ops); 445 446 rockchip_drm_match_remove(&pdev->dev); 447 448 return 0; 449 } 450 451 static void rockchip_drm_platform_shutdown(struct platform_device *pdev) 452 { 453 rockchip_drm_platform_remove(pdev); 454 } 455 456 static const struct of_device_id rockchip_drm_dt_ids[] = { 457 { .compatible = "rockchip,display-subsystem", }, 458 { /* sentinel */ }, 459 }; 460 MODULE_DEVICE_TABLE(of, rockchip_drm_dt_ids); 461 462 static struct platform_driver rockchip_drm_platform_driver = { 463 .probe = rockchip_drm_platform_probe, 464 .remove = rockchip_drm_platform_remove, 465 .shutdown = rockchip_drm_platform_shutdown, 466 .driver = { 467 .name = "rockchip-drm", 468 .of_match_table = rockchip_drm_dt_ids, 469 .pm = &rockchip_drm_pm_ops, 470 }, 471 }; 472 473 #define ADD_ROCKCHIP_SUB_DRIVER(drv, cond) { \ 474 if (IS_ENABLED(cond) && \ 475 !WARN_ON(num_rockchip_sub_drivers >= MAX_ROCKCHIP_SUB_DRIVERS)) \ 476 rockchip_sub_drivers[num_rockchip_sub_drivers++] = &drv; \ 477 } 478 479 static int __init rockchip_drm_init(void) 480 { 481 int ret; 482 483 num_rockchip_sub_drivers = 0; 484 ADD_ROCKCHIP_SUB_DRIVER(vop_platform_driver, CONFIG_DRM_ROCKCHIP); 485 ADD_ROCKCHIP_SUB_DRIVER(rockchip_lvds_driver, 486 CONFIG_ROCKCHIP_LVDS); 487 ADD_ROCKCHIP_SUB_DRIVER(rockchip_dp_driver, 488 CONFIG_ROCKCHIP_ANALOGIX_DP); 489 ADD_ROCKCHIP_SUB_DRIVER(cdn_dp_driver, CONFIG_ROCKCHIP_CDN_DP); 490 ADD_ROCKCHIP_SUB_DRIVER(dw_hdmi_rockchip_pltfm_driver, 491 CONFIG_ROCKCHIP_DW_HDMI); 492 ADD_ROCKCHIP_SUB_DRIVER(dw_mipi_dsi_driver, 493 CONFIG_ROCKCHIP_DW_MIPI_DSI); 494 ADD_ROCKCHIP_SUB_DRIVER(inno_hdmi_driver, CONFIG_ROCKCHIP_INNO_HDMI); 495 496 ret = platform_register_drivers(rockchip_sub_drivers, 497 num_rockchip_sub_drivers); 498 if (ret) 499 return ret; 500 501 ret = platform_driver_register(&rockchip_drm_platform_driver); 502 if (ret) 503 goto err_unreg_drivers; 504 505 return 0; 506 507 err_unreg_drivers: 508 platform_unregister_drivers(rockchip_sub_drivers, 509 num_rockchip_sub_drivers); 510 return ret; 511 } 512 513 static void __exit rockchip_drm_fini(void) 514 { 515 platform_driver_unregister(&rockchip_drm_platform_driver); 516 517 platform_unregister_drivers(rockchip_sub_drivers, 518 num_rockchip_sub_drivers); 519 } 520 521 module_init(rockchip_drm_init); 522 module_exit(rockchip_drm_fini); 523 524 MODULE_AUTHOR("Mark Yao <mark.yao@rock-chips.com>"); 525 MODULE_DESCRIPTION("ROCKCHIP DRM Driver"); 526 MODULE_LICENSE("GPL v2"); 527