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