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 <drm/drm_gem_cma_helper.h> 23 #include <drm/drm_of.h> 24 #include <linux/dma-mapping.h> 25 #include <linux/pm_runtime.h> 26 #include <linux/module.h> 27 #include <linux/of_graph.h> 28 #include <linux/component.h> 29 #include <linux/console.h> 30 31 #include "rockchip_drm_drv.h" 32 #include "rockchip_drm_fb.h" 33 #include "rockchip_drm_fbdev.h" 34 #include "rockchip_drm_gem.h" 35 36 #define DRIVER_NAME "rockchip" 37 #define DRIVER_DESC "RockChip Soc DRM" 38 #define DRIVER_DATE "20140818" 39 #define DRIVER_MAJOR 1 40 #define DRIVER_MINOR 0 41 42 static bool is_support_iommu = true; 43 static struct drm_driver rockchip_drm_driver; 44 45 /* 46 * Attach a (component) device to the shared drm dma mapping from master drm 47 * device. This is used by the VOPs to map GEM buffers to a common DMA 48 * mapping. 49 */ 50 int rockchip_drm_dma_attach_device(struct drm_device *drm_dev, 51 struct device *dev) 52 { 53 struct dma_iommu_mapping *mapping = drm_dev->dev->archdata.mapping; 54 int ret; 55 56 if (!is_support_iommu) 57 return 0; 58 59 ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32)); 60 if (ret) 61 return ret; 62 63 dma_set_max_seg_size(dev, DMA_BIT_MASK(32)); 64 65 return arm_iommu_attach_device(dev, mapping); 66 } 67 68 void rockchip_drm_dma_detach_device(struct drm_device *drm_dev, 69 struct device *dev) 70 { 71 if (!is_support_iommu) 72 return; 73 74 arm_iommu_detach_device(dev); 75 } 76 77 int rockchip_register_crtc_funcs(struct drm_crtc *crtc, 78 const struct rockchip_crtc_funcs *crtc_funcs) 79 { 80 int pipe = drm_crtc_index(crtc); 81 struct rockchip_drm_private *priv = crtc->dev->dev_private; 82 83 if (pipe >= ROCKCHIP_MAX_CRTC) 84 return -EINVAL; 85 86 priv->crtc_funcs[pipe] = crtc_funcs; 87 88 return 0; 89 } 90 91 void rockchip_unregister_crtc_funcs(struct drm_crtc *crtc) 92 { 93 int pipe = drm_crtc_index(crtc); 94 struct rockchip_drm_private *priv = crtc->dev->dev_private; 95 96 if (pipe >= ROCKCHIP_MAX_CRTC) 97 return; 98 99 priv->crtc_funcs[pipe] = NULL; 100 } 101 102 static int rockchip_drm_crtc_enable_vblank(struct drm_device *dev, 103 unsigned int pipe) 104 { 105 struct rockchip_drm_private *priv = dev->dev_private; 106 struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe); 107 108 if (crtc && priv->crtc_funcs[pipe] && 109 priv->crtc_funcs[pipe]->enable_vblank) 110 return priv->crtc_funcs[pipe]->enable_vblank(crtc); 111 112 return 0; 113 } 114 115 static void rockchip_drm_crtc_disable_vblank(struct drm_device *dev, 116 unsigned int pipe) 117 { 118 struct rockchip_drm_private *priv = dev->dev_private; 119 struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe); 120 121 if (crtc && priv->crtc_funcs[pipe] && 122 priv->crtc_funcs[pipe]->enable_vblank) 123 priv->crtc_funcs[pipe]->disable_vblank(crtc); 124 } 125 126 static int rockchip_drm_bind(struct device *dev) 127 { 128 struct drm_device *drm_dev; 129 struct rockchip_drm_private *private; 130 struct dma_iommu_mapping *mapping = NULL; 131 int ret; 132 133 drm_dev = drm_dev_alloc(&rockchip_drm_driver, dev); 134 if (IS_ERR(drm_dev)) 135 return PTR_ERR(drm_dev); 136 137 dev_set_drvdata(dev, drm_dev); 138 139 private = devm_kzalloc(drm_dev->dev, sizeof(*private), GFP_KERNEL); 140 if (!private) { 141 ret = -ENOMEM; 142 goto err_free; 143 } 144 145 drm_dev->dev_private = private; 146 147 INIT_LIST_HEAD(&private->psr_list); 148 spin_lock_init(&private->psr_list_lock); 149 150 drm_mode_config_init(drm_dev); 151 152 rockchip_drm_mode_config_init(drm_dev); 153 154 dev->dma_parms = devm_kzalloc(dev, sizeof(*dev->dma_parms), 155 GFP_KERNEL); 156 if (!dev->dma_parms) { 157 ret = -ENOMEM; 158 goto err_config_cleanup; 159 } 160 161 if (is_support_iommu) { 162 /* TODO(djkurtz): fetch the mapping start/size from somewhere */ 163 mapping = arm_iommu_create_mapping(&platform_bus_type, 164 0x00000000, 165 SZ_2G); 166 if (IS_ERR(mapping)) { 167 ret = PTR_ERR(mapping); 168 goto err_config_cleanup; 169 } 170 171 ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); 172 if (ret) 173 goto err_release_mapping; 174 175 dma_set_max_seg_size(dev, DMA_BIT_MASK(32)); 176 177 ret = arm_iommu_attach_device(dev, mapping); 178 if (ret) 179 goto err_release_mapping; 180 } 181 182 /* Try to bind all sub drivers. */ 183 ret = component_bind_all(dev, drm_dev); 184 if (ret) 185 goto err_detach_device; 186 187 /* init kms poll for handling hpd */ 188 drm_kms_helper_poll_init(drm_dev); 189 190 /* 191 * enable drm irq mode. 192 * - with irq_enabled = true, we can use the vblank feature. 193 */ 194 drm_dev->irq_enabled = true; 195 196 ret = drm_vblank_init(drm_dev, ROCKCHIP_MAX_CRTC); 197 if (ret) 198 goto err_kms_helper_poll_fini; 199 200 drm_mode_config_reset(drm_dev); 201 202 ret = rockchip_drm_fbdev_init(drm_dev); 203 if (ret) 204 goto err_vblank_cleanup; 205 206 ret = drm_dev_register(drm_dev, 0); 207 if (ret) 208 goto err_fbdev_fini; 209 210 if (is_support_iommu) 211 arm_iommu_release_mapping(mapping); 212 return 0; 213 err_fbdev_fini: 214 rockchip_drm_fbdev_fini(drm_dev); 215 err_vblank_cleanup: 216 drm_vblank_cleanup(drm_dev); 217 err_kms_helper_poll_fini: 218 drm_kms_helper_poll_fini(drm_dev); 219 component_unbind_all(dev, drm_dev); 220 err_detach_device: 221 if (is_support_iommu) 222 arm_iommu_detach_device(dev); 223 err_release_mapping: 224 if (is_support_iommu) 225 arm_iommu_release_mapping(mapping); 226 err_config_cleanup: 227 drm_mode_config_cleanup(drm_dev); 228 drm_dev->dev_private = NULL; 229 err_free: 230 drm_dev_unref(drm_dev); 231 return ret; 232 } 233 234 static void rockchip_drm_unbind(struct device *dev) 235 { 236 struct drm_device *drm_dev = dev_get_drvdata(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 if (is_support_iommu) 243 arm_iommu_detach_device(dev); 244 drm_mode_config_cleanup(drm_dev); 245 drm_dev->dev_private = NULL; 246 drm_dev_unregister(drm_dev); 247 drm_dev_unref(drm_dev); 248 dev_set_drvdata(dev, NULL); 249 } 250 251 static void rockchip_drm_lastclose(struct drm_device *dev) 252 { 253 struct rockchip_drm_private *priv = dev->dev_private; 254 255 drm_fb_helper_restore_fbdev_mode_unlocked(&priv->fbdev_helper); 256 } 257 258 static const struct file_operations rockchip_drm_driver_fops = { 259 .owner = THIS_MODULE, 260 .open = drm_open, 261 .mmap = rockchip_gem_mmap, 262 .poll = drm_poll, 263 .read = drm_read, 264 .unlocked_ioctl = drm_ioctl, 265 .compat_ioctl = drm_compat_ioctl, 266 .release = drm_release, 267 }; 268 269 static struct drm_driver rockchip_drm_driver = { 270 .driver_features = DRIVER_MODESET | DRIVER_GEM | 271 DRIVER_PRIME | DRIVER_ATOMIC, 272 .lastclose = rockchip_drm_lastclose, 273 .get_vblank_counter = drm_vblank_no_hw_counter, 274 .enable_vblank = rockchip_drm_crtc_enable_vblank, 275 .disable_vblank = rockchip_drm_crtc_disable_vblank, 276 .gem_vm_ops = &drm_gem_cma_vm_ops, 277 .gem_free_object_unlocked = rockchip_gem_free_object, 278 .dumb_create = rockchip_gem_dumb_create, 279 .dumb_map_offset = rockchip_gem_dumb_map_offset, 280 .dumb_destroy = drm_gem_dumb_destroy, 281 .prime_handle_to_fd = drm_gem_prime_handle_to_fd, 282 .prime_fd_to_handle = drm_gem_prime_fd_to_handle, 283 .gem_prime_import = drm_gem_prime_import, 284 .gem_prime_export = drm_gem_prime_export, 285 .gem_prime_get_sg_table = rockchip_gem_prime_get_sg_table, 286 .gem_prime_vmap = rockchip_gem_prime_vmap, 287 .gem_prime_vunmap = rockchip_gem_prime_vunmap, 288 .gem_prime_mmap = rockchip_gem_mmap_buf, 289 .fops = &rockchip_drm_driver_fops, 290 .name = DRIVER_NAME, 291 .desc = DRIVER_DESC, 292 .date = DRIVER_DATE, 293 .major = DRIVER_MAJOR, 294 .minor = DRIVER_MINOR, 295 }; 296 297 #ifdef CONFIG_PM_SLEEP 298 static void rockchip_drm_fb_suspend(struct drm_device *drm) 299 { 300 struct rockchip_drm_private *priv = drm->dev_private; 301 302 console_lock(); 303 drm_fb_helper_set_suspend(&priv->fbdev_helper, 1); 304 console_unlock(); 305 } 306 307 static void rockchip_drm_fb_resume(struct drm_device *drm) 308 { 309 struct rockchip_drm_private *priv = drm->dev_private; 310 311 console_lock(); 312 drm_fb_helper_set_suspend(&priv->fbdev_helper, 0); 313 console_unlock(); 314 } 315 316 static int rockchip_drm_sys_suspend(struct device *dev) 317 { 318 struct drm_device *drm = dev_get_drvdata(dev); 319 struct rockchip_drm_private *priv = drm->dev_private; 320 321 drm_kms_helper_poll_disable(drm); 322 rockchip_drm_fb_suspend(drm); 323 324 priv->state = drm_atomic_helper_suspend(drm); 325 if (IS_ERR(priv->state)) { 326 rockchip_drm_fb_resume(drm); 327 drm_kms_helper_poll_enable(drm); 328 return PTR_ERR(priv->state); 329 } 330 331 return 0; 332 } 333 334 static int rockchip_drm_sys_resume(struct device *dev) 335 { 336 struct drm_device *drm = dev_get_drvdata(dev); 337 struct rockchip_drm_private *priv = drm->dev_private; 338 339 drm_atomic_helper_resume(drm, priv->state); 340 rockchip_drm_fb_resume(drm); 341 drm_kms_helper_poll_enable(drm); 342 343 return 0; 344 } 345 #endif 346 347 static const struct dev_pm_ops rockchip_drm_pm_ops = { 348 SET_SYSTEM_SLEEP_PM_OPS(rockchip_drm_sys_suspend, 349 rockchip_drm_sys_resume) 350 }; 351 352 static int compare_of(struct device *dev, void *data) 353 { 354 struct device_node *np = data; 355 356 return dev->of_node == np; 357 } 358 359 static void rockchip_add_endpoints(struct device *dev, 360 struct component_match **match, 361 struct device_node *port) 362 { 363 struct device_node *ep, *remote; 364 365 for_each_child_of_node(port, ep) { 366 remote = of_graph_get_remote_port_parent(ep); 367 if (!remote || !of_device_is_available(remote)) { 368 of_node_put(remote); 369 continue; 370 } else if (!of_device_is_available(remote->parent)) { 371 dev_warn(dev, "parent device of %s is not available\n", 372 remote->full_name); 373 of_node_put(remote); 374 continue; 375 } 376 377 drm_of_component_match_add(dev, match, compare_of, remote); 378 of_node_put(remote); 379 } 380 } 381 382 static const struct component_master_ops rockchip_drm_ops = { 383 .bind = rockchip_drm_bind, 384 .unbind = rockchip_drm_unbind, 385 }; 386 387 static int rockchip_drm_platform_probe(struct platform_device *pdev) 388 { 389 struct device *dev = &pdev->dev; 390 struct component_match *match = NULL; 391 struct device_node *np = dev->of_node; 392 struct device_node *port; 393 int i; 394 395 if (!np) 396 return -ENODEV; 397 /* 398 * Bind the crtc ports first, so that 399 * drm_of_find_possible_crtcs called from encoder .bind callbacks 400 * works as expected. 401 */ 402 for (i = 0;; i++) { 403 struct device_node *iommu; 404 405 port = of_parse_phandle(np, "ports", i); 406 if (!port) 407 break; 408 409 if (!of_device_is_available(port->parent)) { 410 of_node_put(port); 411 continue; 412 } 413 414 iommu = of_parse_phandle(port->parent, "iommus", 0); 415 if (!iommu || !of_device_is_available(iommu->parent)) { 416 dev_dbg(dev, "no iommu attached for %s, using non-iommu buffers\n", 417 port->parent->full_name); 418 /* 419 * if there is a crtc not support iommu, force set all 420 * crtc use non-iommu buffer. 421 */ 422 is_support_iommu = false; 423 } 424 425 of_node_put(iommu); 426 drm_of_component_match_add(dev, &match, compare_of, 427 port->parent); 428 of_node_put(port); 429 } 430 431 if (i == 0) { 432 dev_err(dev, "missing 'ports' property\n"); 433 return -ENODEV; 434 } 435 436 if (!match) { 437 dev_err(dev, "No available vop found for display-subsystem.\n"); 438 return -ENODEV; 439 } 440 /* 441 * For each bound crtc, bind the encoders attached to its 442 * remote endpoint. 443 */ 444 for (i = 0;; i++) { 445 port = of_parse_phandle(np, "ports", i); 446 if (!port) 447 break; 448 449 if (!of_device_is_available(port->parent)) { 450 of_node_put(port); 451 continue; 452 } 453 454 rockchip_add_endpoints(dev, &match, port); 455 of_node_put(port); 456 } 457 458 return component_master_add_with_match(dev, &rockchip_drm_ops, match); 459 } 460 461 static int rockchip_drm_platform_remove(struct platform_device *pdev) 462 { 463 component_master_del(&pdev->dev, &rockchip_drm_ops); 464 465 return 0; 466 } 467 468 static const struct of_device_id rockchip_drm_dt_ids[] = { 469 { .compatible = "rockchip,display-subsystem", }, 470 { /* sentinel */ }, 471 }; 472 MODULE_DEVICE_TABLE(of, rockchip_drm_dt_ids); 473 474 static struct platform_driver rockchip_drm_platform_driver = { 475 .probe = rockchip_drm_platform_probe, 476 .remove = rockchip_drm_platform_remove, 477 .driver = { 478 .name = "rockchip-drm", 479 .of_match_table = rockchip_drm_dt_ids, 480 .pm = &rockchip_drm_pm_ops, 481 }, 482 }; 483 484 module_platform_driver(rockchip_drm_platform_driver); 485 486 MODULE_AUTHOR("Mark Yao <mark.yao@rock-chips.com>"); 487 MODULE_DESCRIPTION("ROCKCHIP DRM Driver"); 488 MODULE_LICENSE("GPL v2"); 489