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 <asm/dma-iommu.h> 18 19 #include <drm/drmP.h> 20 #include <drm/drm_crtc_helper.h> 21 #include <drm/drm_fb_helper.h> 22 #include <linux/dma-mapping.h> 23 #include <linux/pm_runtime.h> 24 #include <linux/module.h> 25 #include <linux/of_graph.h> 26 #include <linux/component.h> 27 28 #include "rockchip_drm_drv.h" 29 #include "rockchip_drm_fb.h" 30 #include "rockchip_drm_fbdev.h" 31 #include "rockchip_drm_gem.h" 32 33 #define DRIVER_NAME "rockchip" 34 #define DRIVER_DESC "RockChip Soc DRM" 35 #define DRIVER_DATE "20140818" 36 #define DRIVER_MAJOR 1 37 #define DRIVER_MINOR 0 38 39 /* 40 * Attach a (component) device to the shared drm dma mapping from master drm 41 * device. This is used by the VOPs to map GEM buffers to a common DMA 42 * mapping. 43 */ 44 int rockchip_drm_dma_attach_device(struct drm_device *drm_dev, 45 struct device *dev) 46 { 47 struct dma_iommu_mapping *mapping = drm_dev->dev->archdata.mapping; 48 int ret; 49 50 ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32)); 51 if (ret) 52 return ret; 53 54 dma_set_max_seg_size(dev, DMA_BIT_MASK(32)); 55 56 return arm_iommu_attach_device(dev, mapping); 57 } 58 EXPORT_SYMBOL_GPL(rockchip_drm_dma_attach_device); 59 60 void rockchip_drm_dma_detach_device(struct drm_device *drm_dev, 61 struct device *dev) 62 { 63 arm_iommu_detach_device(dev); 64 } 65 EXPORT_SYMBOL_GPL(rockchip_drm_dma_detach_device); 66 67 int rockchip_register_crtc_funcs(struct drm_crtc *crtc, 68 const struct rockchip_crtc_funcs *crtc_funcs) 69 { 70 int pipe = drm_crtc_index(crtc); 71 struct rockchip_drm_private *priv = crtc->dev->dev_private; 72 73 if (pipe > ROCKCHIP_MAX_CRTC) 74 return -EINVAL; 75 76 priv->crtc_funcs[pipe] = crtc_funcs; 77 78 return 0; 79 } 80 EXPORT_SYMBOL_GPL(rockchip_register_crtc_funcs); 81 82 void rockchip_unregister_crtc_funcs(struct drm_crtc *crtc) 83 { 84 int pipe = drm_crtc_index(crtc); 85 struct rockchip_drm_private *priv = crtc->dev->dev_private; 86 87 if (pipe > ROCKCHIP_MAX_CRTC) 88 return; 89 90 priv->crtc_funcs[pipe] = NULL; 91 } 92 EXPORT_SYMBOL_GPL(rockchip_unregister_crtc_funcs); 93 94 static struct drm_crtc *rockchip_crtc_from_pipe(struct drm_device *drm, 95 int pipe) 96 { 97 struct drm_crtc *crtc; 98 int i = 0; 99 100 list_for_each_entry(crtc, &drm->mode_config.crtc_list, head) 101 if (i++ == pipe) 102 return crtc; 103 104 return NULL; 105 } 106 107 static int rockchip_drm_crtc_enable_vblank(struct drm_device *dev, 108 unsigned int pipe) 109 { 110 struct rockchip_drm_private *priv = dev->dev_private; 111 struct drm_crtc *crtc = rockchip_crtc_from_pipe(dev, pipe); 112 113 if (crtc && priv->crtc_funcs[pipe] && 114 priv->crtc_funcs[pipe]->enable_vblank) 115 return priv->crtc_funcs[pipe]->enable_vblank(crtc); 116 117 return 0; 118 } 119 120 static void rockchip_drm_crtc_disable_vblank(struct drm_device *dev, 121 unsigned int pipe) 122 { 123 struct rockchip_drm_private *priv = dev->dev_private; 124 struct drm_crtc *crtc = rockchip_crtc_from_pipe(dev, pipe); 125 126 if (crtc && priv->crtc_funcs[pipe] && 127 priv->crtc_funcs[pipe]->enable_vblank) 128 priv->crtc_funcs[pipe]->disable_vblank(crtc); 129 } 130 131 static int rockchip_drm_load(struct drm_device *drm_dev, unsigned long flags) 132 { 133 struct rockchip_drm_private *private; 134 struct dma_iommu_mapping *mapping; 135 struct device *dev = drm_dev->dev; 136 struct drm_connector *connector; 137 int ret; 138 139 private = devm_kzalloc(drm_dev->dev, sizeof(*private), GFP_KERNEL); 140 if (!private) 141 return -ENOMEM; 142 143 mutex_init(&private->commit.lock); 144 INIT_WORK(&private->commit.work, rockchip_drm_atomic_work); 145 146 drm_dev->dev_private = private; 147 148 drm_mode_config_init(drm_dev); 149 150 rockchip_drm_mode_config_init(drm_dev); 151 152 dev->dma_parms = devm_kzalloc(dev, sizeof(*dev->dma_parms), 153 GFP_KERNEL); 154 if (!dev->dma_parms) { 155 ret = -ENOMEM; 156 goto err_config_cleanup; 157 } 158 159 /* TODO(djkurtz): fetch the mapping start/size from somewhere */ 160 mapping = arm_iommu_create_mapping(&platform_bus_type, 0x00000000, 161 SZ_2G); 162 if (IS_ERR(mapping)) { 163 ret = PTR_ERR(mapping); 164 goto err_config_cleanup; 165 } 166 167 ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); 168 if (ret) 169 goto err_release_mapping; 170 171 dma_set_max_seg_size(dev, DMA_BIT_MASK(32)); 172 173 ret = arm_iommu_attach_device(dev, mapping); 174 if (ret) 175 goto err_release_mapping; 176 177 /* Try to bind all sub drivers. */ 178 ret = component_bind_all(dev, drm_dev); 179 if (ret) 180 goto err_detach_device; 181 182 /* 183 * All components are now added, we can publish the connector sysfs 184 * entries to userspace. This will generate hotplug events and so 185 * userspace will expect to be able to access DRM at this point. 186 */ 187 list_for_each_entry(connector, &drm_dev->mode_config.connector_list, 188 head) { 189 ret = drm_connector_register(connector); 190 if (ret) { 191 dev_err(drm_dev->dev, 192 "[CONNECTOR:%d:%s] drm_connector_register failed: %d\n", 193 connector->base.id, 194 connector->name, ret); 195 goto err_unbind; 196 } 197 } 198 199 /* init kms poll for handling hpd */ 200 drm_kms_helper_poll_init(drm_dev); 201 202 /* 203 * enable drm irq mode. 204 * - with irq_enabled = true, we can use the vblank feature. 205 */ 206 drm_dev->irq_enabled = true; 207 208 ret = drm_vblank_init(drm_dev, ROCKCHIP_MAX_CRTC); 209 if (ret) 210 goto err_kms_helper_poll_fini; 211 212 /* 213 * with vblank_disable_allowed = true, vblank interrupt will be disabled 214 * by drm timer once a current process gives up ownership of 215 * vblank event.(after drm_vblank_put function is called) 216 */ 217 drm_dev->vblank_disable_allowed = true; 218 219 drm_mode_config_reset(drm_dev); 220 221 ret = rockchip_drm_fbdev_init(drm_dev); 222 if (ret) 223 goto err_vblank_cleanup; 224 225 return 0; 226 err_vblank_cleanup: 227 drm_vblank_cleanup(drm_dev); 228 err_kms_helper_poll_fini: 229 drm_kms_helper_poll_fini(drm_dev); 230 err_unbind: 231 component_unbind_all(dev, drm_dev); 232 err_detach_device: 233 arm_iommu_detach_device(dev); 234 err_release_mapping: 235 arm_iommu_release_mapping(dev->archdata.mapping); 236 err_config_cleanup: 237 drm_mode_config_cleanup(drm_dev); 238 drm_dev->dev_private = NULL; 239 return ret; 240 } 241 242 static int rockchip_drm_unload(struct drm_device *drm_dev) 243 { 244 struct device *dev = drm_dev->dev; 245 246 rockchip_drm_fbdev_fini(drm_dev); 247 drm_vblank_cleanup(drm_dev); 248 drm_kms_helper_poll_fini(drm_dev); 249 component_unbind_all(dev, drm_dev); 250 arm_iommu_detach_device(dev); 251 arm_iommu_release_mapping(dev->archdata.mapping); 252 drm_mode_config_cleanup(drm_dev); 253 drm_dev->dev_private = NULL; 254 255 return 0; 256 } 257 258 void rockchip_drm_lastclose(struct drm_device *dev) 259 { 260 struct rockchip_drm_private *priv = dev->dev_private; 261 262 drm_fb_helper_restore_fbdev_mode_unlocked(&priv->fbdev_helper); 263 } 264 265 static const struct file_operations rockchip_drm_driver_fops = { 266 .owner = THIS_MODULE, 267 .open = drm_open, 268 .mmap = rockchip_gem_mmap, 269 .poll = drm_poll, 270 .read = drm_read, 271 .unlocked_ioctl = drm_ioctl, 272 #ifdef CONFIG_COMPAT 273 .compat_ioctl = drm_compat_ioctl, 274 #endif 275 .release = drm_release, 276 }; 277 278 const struct vm_operations_struct rockchip_drm_vm_ops = { 279 .open = drm_gem_vm_open, 280 .close = drm_gem_vm_close, 281 }; 282 283 static struct drm_driver rockchip_drm_driver = { 284 .driver_features = DRIVER_MODESET | DRIVER_GEM | 285 DRIVER_PRIME | DRIVER_ATOMIC, 286 .load = rockchip_drm_load, 287 .unload = rockchip_drm_unload, 288 .lastclose = rockchip_drm_lastclose, 289 .get_vblank_counter = drm_vblank_no_hw_counter, 290 .enable_vblank = rockchip_drm_crtc_enable_vblank, 291 .disable_vblank = rockchip_drm_crtc_disable_vblank, 292 .gem_vm_ops = &rockchip_drm_vm_ops, 293 .gem_free_object = rockchip_gem_free_object, 294 .dumb_create = rockchip_gem_dumb_create, 295 .dumb_map_offset = rockchip_gem_dumb_map_offset, 296 .dumb_destroy = drm_gem_dumb_destroy, 297 .prime_handle_to_fd = drm_gem_prime_handle_to_fd, 298 .prime_fd_to_handle = drm_gem_prime_fd_to_handle, 299 .gem_prime_import = drm_gem_prime_import, 300 .gem_prime_export = drm_gem_prime_export, 301 .gem_prime_get_sg_table = rockchip_gem_prime_get_sg_table, 302 .gem_prime_vmap = rockchip_gem_prime_vmap, 303 .gem_prime_vunmap = rockchip_gem_prime_vunmap, 304 .gem_prime_mmap = rockchip_gem_mmap_buf, 305 .fops = &rockchip_drm_driver_fops, 306 .name = DRIVER_NAME, 307 .desc = DRIVER_DESC, 308 .date = DRIVER_DATE, 309 .major = DRIVER_MAJOR, 310 .minor = DRIVER_MINOR, 311 }; 312 313 #ifdef CONFIG_PM_SLEEP 314 static int rockchip_drm_sys_suspend(struct device *dev) 315 { 316 struct drm_device *drm = dev_get_drvdata(dev); 317 struct drm_connector *connector; 318 319 if (!drm) 320 return 0; 321 322 drm_modeset_lock_all(drm); 323 list_for_each_entry(connector, &drm->mode_config.connector_list, head) { 324 int old_dpms = connector->dpms; 325 326 if (connector->funcs->dpms) 327 connector->funcs->dpms(connector, DRM_MODE_DPMS_OFF); 328 329 /* Set the old mode back to the connector for resume */ 330 connector->dpms = old_dpms; 331 } 332 drm_modeset_unlock_all(drm); 333 334 return 0; 335 } 336 337 static int rockchip_drm_sys_resume(struct device *dev) 338 { 339 struct drm_device *drm = dev_get_drvdata(dev); 340 struct drm_connector *connector; 341 enum drm_connector_status status; 342 bool changed = false; 343 344 if (!drm) 345 return 0; 346 347 drm_modeset_lock_all(drm); 348 list_for_each_entry(connector, &drm->mode_config.connector_list, head) { 349 int desired_mode = connector->dpms; 350 351 /* 352 * at suspend time, we save dpms to connector->dpms, 353 * restore the old_dpms, and at current time, the connector 354 * dpms status must be DRM_MODE_DPMS_OFF. 355 */ 356 connector->dpms = DRM_MODE_DPMS_OFF; 357 358 /* 359 * If the connector has been disconnected during suspend, 360 * disconnect it from the encoder and leave it off. We'll notify 361 * userspace at the end. 362 */ 363 if (desired_mode == DRM_MODE_DPMS_ON) { 364 status = connector->funcs->detect(connector, true); 365 if (status == connector_status_disconnected) { 366 connector->encoder = NULL; 367 connector->status = status; 368 changed = true; 369 continue; 370 } 371 } 372 if (connector->funcs->dpms) 373 connector->funcs->dpms(connector, desired_mode); 374 } 375 drm_modeset_unlock_all(drm); 376 377 drm_helper_resume_force_mode(drm); 378 379 if (changed) 380 drm_kms_helper_hotplug_event(drm); 381 382 return 0; 383 } 384 #endif 385 386 static const struct dev_pm_ops rockchip_drm_pm_ops = { 387 SET_SYSTEM_SLEEP_PM_OPS(rockchip_drm_sys_suspend, 388 rockchip_drm_sys_resume) 389 }; 390 391 /* 392 * @node: device tree node containing encoder input ports 393 * @encoder: drm_encoder 394 */ 395 int rockchip_drm_encoder_get_mux_id(struct device_node *node, 396 struct drm_encoder *encoder) 397 { 398 struct device_node *ep; 399 struct drm_crtc *crtc = encoder->crtc; 400 struct of_endpoint endpoint; 401 struct device_node *port; 402 int ret; 403 404 if (!node || !crtc) 405 return -EINVAL; 406 407 for_each_endpoint_of_node(node, ep) { 408 port = of_graph_get_remote_port(ep); 409 of_node_put(port); 410 if (port == crtc->port) { 411 ret = of_graph_parse_endpoint(ep, &endpoint); 412 of_node_put(ep); 413 return ret ?: endpoint.id; 414 } 415 } 416 417 return -EINVAL; 418 } 419 EXPORT_SYMBOL_GPL(rockchip_drm_encoder_get_mux_id); 420 421 static int compare_of(struct device *dev, void *data) 422 { 423 struct device_node *np = data; 424 425 return dev->of_node == np; 426 } 427 428 static void rockchip_add_endpoints(struct device *dev, 429 struct component_match **match, 430 struct device_node *port) 431 { 432 struct device_node *ep, *remote; 433 434 for_each_child_of_node(port, ep) { 435 remote = of_graph_get_remote_port_parent(ep); 436 if (!remote || !of_device_is_available(remote)) { 437 of_node_put(remote); 438 continue; 439 } else if (!of_device_is_available(remote->parent)) { 440 dev_warn(dev, "parent device of %s is not available\n", 441 remote->full_name); 442 of_node_put(remote); 443 continue; 444 } 445 446 component_match_add(dev, match, compare_of, remote); 447 of_node_put(remote); 448 } 449 } 450 451 static int rockchip_drm_bind(struct device *dev) 452 { 453 struct drm_device *drm; 454 int ret; 455 456 drm = drm_dev_alloc(&rockchip_drm_driver, dev); 457 if (!drm) 458 return -ENOMEM; 459 460 ret = drm_dev_register(drm, 0); 461 if (ret) 462 goto err_free; 463 464 dev_set_drvdata(dev, drm); 465 466 return 0; 467 468 err_free: 469 drm_dev_unref(drm); 470 return ret; 471 } 472 473 static void rockchip_drm_unbind(struct device *dev) 474 { 475 struct drm_device *drm = dev_get_drvdata(dev); 476 477 drm_dev_unregister(drm); 478 drm_dev_unref(drm); 479 dev_set_drvdata(dev, NULL); 480 } 481 482 static const struct component_master_ops rockchip_drm_ops = { 483 .bind = rockchip_drm_bind, 484 .unbind = rockchip_drm_unbind, 485 }; 486 487 static int rockchip_drm_platform_probe(struct platform_device *pdev) 488 { 489 struct device *dev = &pdev->dev; 490 struct component_match *match = NULL; 491 struct device_node *np = dev->of_node; 492 struct device_node *port; 493 int i; 494 495 if (!np) 496 return -ENODEV; 497 /* 498 * Bind the crtc ports first, so that 499 * drm_of_find_possible_crtcs called from encoder .bind callbacks 500 * works as expected. 501 */ 502 for (i = 0;; i++) { 503 port = of_parse_phandle(np, "ports", i); 504 if (!port) 505 break; 506 507 if (!of_device_is_available(port->parent)) { 508 of_node_put(port); 509 continue; 510 } 511 512 component_match_add(dev, &match, compare_of, port->parent); 513 of_node_put(port); 514 } 515 516 if (i == 0) { 517 dev_err(dev, "missing 'ports' property\n"); 518 return -ENODEV; 519 } 520 521 if (!match) { 522 dev_err(dev, "No available vop found for display-subsystem.\n"); 523 return -ENODEV; 524 } 525 /* 526 * For each bound crtc, bind the encoders attached to its 527 * remote endpoint. 528 */ 529 for (i = 0;; i++) { 530 port = of_parse_phandle(np, "ports", i); 531 if (!port) 532 break; 533 534 if (!of_device_is_available(port->parent)) { 535 of_node_put(port); 536 continue; 537 } 538 539 rockchip_add_endpoints(dev, &match, port); 540 of_node_put(port); 541 } 542 543 return component_master_add_with_match(dev, &rockchip_drm_ops, match); 544 } 545 546 static int rockchip_drm_platform_remove(struct platform_device *pdev) 547 { 548 component_master_del(&pdev->dev, &rockchip_drm_ops); 549 550 return 0; 551 } 552 553 static const struct of_device_id rockchip_drm_dt_ids[] = { 554 { .compatible = "rockchip,display-subsystem", }, 555 { /* sentinel */ }, 556 }; 557 MODULE_DEVICE_TABLE(of, rockchip_drm_dt_ids); 558 559 static struct platform_driver rockchip_drm_platform_driver = { 560 .probe = rockchip_drm_platform_probe, 561 .remove = rockchip_drm_platform_remove, 562 .driver = { 563 .name = "rockchip-drm", 564 .of_match_table = rockchip_drm_dt_ids, 565 .pm = &rockchip_drm_pm_ops, 566 }, 567 }; 568 569 module_platform_driver(rockchip_drm_platform_driver); 570 571 MODULE_AUTHOR("Mark Yao <mark.yao@rock-chips.com>"); 572 MODULE_DESCRIPTION("ROCKCHIP DRM Driver"); 573 MODULE_LICENSE("GPL v2"); 574