Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.10-rc2 527 lines 13 kB view raw
1/* 2 * Freescale i.MX drm driver 3 * 4 * Copyright (C) 2011 Sascha Hauer, Pengutronix 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation; either version 2 9 * of the License, or (at your option) any later version. 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 */ 16#include <linux/component.h> 17#include <linux/device.h> 18#include <linux/dma-buf.h> 19#include <linux/module.h> 20#include <linux/platform_device.h> 21#include <drm/drmP.h> 22#include <drm/drm_atomic.h> 23#include <drm/drm_atomic_helper.h> 24#include <drm/drm_fb_helper.h> 25#include <drm/drm_crtc_helper.h> 26#include <drm/drm_gem_cma_helper.h> 27#include <drm/drm_fb_cma_helper.h> 28#include <drm/drm_plane_helper.h> 29#include <drm/drm_of.h> 30#include <video/imx-ipu-v3.h> 31 32#include "imx-drm.h" 33 34#define MAX_CRTC 4 35 36struct imx_drm_component { 37 struct device_node *of_node; 38 struct list_head list; 39}; 40 41struct imx_drm_device { 42 struct drm_device *drm; 43 struct imx_drm_crtc *crtc[MAX_CRTC]; 44 unsigned int pipes; 45 struct drm_fbdev_cma *fbhelper; 46 struct drm_atomic_state *state; 47}; 48 49struct imx_drm_crtc { 50 struct drm_crtc *crtc; 51 struct imx_drm_crtc_helper_funcs imx_drm_helper_funcs; 52}; 53 54#if IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION) 55static int legacyfb_depth = 16; 56module_param(legacyfb_depth, int, 0444); 57#endif 58 59static void imx_drm_driver_lastclose(struct drm_device *drm) 60{ 61 struct imx_drm_device *imxdrm = drm->dev_private; 62 63 drm_fbdev_cma_restore_mode(imxdrm->fbhelper); 64} 65 66static int imx_drm_enable_vblank(struct drm_device *drm, unsigned int pipe) 67{ 68 struct imx_drm_device *imxdrm = drm->dev_private; 69 struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[pipe]; 70 int ret; 71 72 if (!imx_drm_crtc) 73 return -EINVAL; 74 75 if (!imx_drm_crtc->imx_drm_helper_funcs.enable_vblank) 76 return -ENOSYS; 77 78 ret = imx_drm_crtc->imx_drm_helper_funcs.enable_vblank( 79 imx_drm_crtc->crtc); 80 81 return ret; 82} 83 84static void imx_drm_disable_vblank(struct drm_device *drm, unsigned int pipe) 85{ 86 struct imx_drm_device *imxdrm = drm->dev_private; 87 struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[pipe]; 88 89 if (!imx_drm_crtc) 90 return; 91 92 if (!imx_drm_crtc->imx_drm_helper_funcs.disable_vblank) 93 return; 94 95 imx_drm_crtc->imx_drm_helper_funcs.disable_vblank(imx_drm_crtc->crtc); 96} 97 98static const struct file_operations imx_drm_driver_fops = { 99 .owner = THIS_MODULE, 100 .open = drm_open, 101 .release = drm_release, 102 .unlocked_ioctl = drm_ioctl, 103 .mmap = drm_gem_cma_mmap, 104 .poll = drm_poll, 105 .read = drm_read, 106 .llseek = noop_llseek, 107}; 108 109void imx_drm_connector_destroy(struct drm_connector *connector) 110{ 111 drm_connector_unregister(connector); 112 drm_connector_cleanup(connector); 113} 114EXPORT_SYMBOL_GPL(imx_drm_connector_destroy); 115 116void imx_drm_encoder_destroy(struct drm_encoder *encoder) 117{ 118 drm_encoder_cleanup(encoder); 119} 120EXPORT_SYMBOL_GPL(imx_drm_encoder_destroy); 121 122static void imx_drm_output_poll_changed(struct drm_device *drm) 123{ 124 struct imx_drm_device *imxdrm = drm->dev_private; 125 126 drm_fbdev_cma_hotplug_event(imxdrm->fbhelper); 127} 128 129static int imx_drm_atomic_check(struct drm_device *dev, 130 struct drm_atomic_state *state) 131{ 132 int ret; 133 134 ret = drm_atomic_helper_check_modeset(dev, state); 135 if (ret) 136 return ret; 137 138 ret = drm_atomic_helper_check_planes(dev, state); 139 if (ret) 140 return ret; 141 142 /* 143 * Check modeset again in case crtc_state->mode_changed is 144 * updated in plane's ->atomic_check callback. 145 */ 146 ret = drm_atomic_helper_check_modeset(dev, state); 147 if (ret) 148 return ret; 149 150 return ret; 151} 152 153static const struct drm_mode_config_funcs imx_drm_mode_config_funcs = { 154 .fb_create = drm_fb_cma_create, 155 .output_poll_changed = imx_drm_output_poll_changed, 156 .atomic_check = imx_drm_atomic_check, 157 .atomic_commit = drm_atomic_helper_commit, 158}; 159 160static void imx_drm_atomic_commit_tail(struct drm_atomic_state *state) 161{ 162 struct drm_device *dev = state->dev; 163 164 drm_atomic_helper_commit_modeset_disables(dev, state); 165 166 drm_atomic_helper_commit_planes(dev, state, 167 DRM_PLANE_COMMIT_ACTIVE_ONLY | 168 DRM_PLANE_COMMIT_NO_DISABLE_AFTER_MODESET); 169 170 drm_atomic_helper_commit_modeset_enables(dev, state); 171 172 drm_atomic_helper_commit_hw_done(state); 173 174 drm_atomic_helper_wait_for_vblanks(dev, state); 175 176 drm_atomic_helper_cleanup_planes(dev, state); 177} 178 179static struct drm_mode_config_helper_funcs imx_drm_mode_config_helpers = { 180 .atomic_commit_tail = imx_drm_atomic_commit_tail, 181}; 182 183/* 184 * imx_drm_add_crtc - add a new crtc 185 */ 186int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc, 187 struct imx_drm_crtc **new_crtc, struct drm_plane *primary_plane, 188 const struct imx_drm_crtc_helper_funcs *imx_drm_helper_funcs, 189 struct device_node *port) 190{ 191 struct imx_drm_device *imxdrm = drm->dev_private; 192 struct imx_drm_crtc *imx_drm_crtc; 193 194 /* 195 * The vblank arrays are dimensioned by MAX_CRTC - we can't 196 * pass IDs greater than this to those functions. 197 */ 198 if (imxdrm->pipes >= MAX_CRTC) 199 return -EINVAL; 200 201 if (imxdrm->drm->open_count) 202 return -EBUSY; 203 204 imx_drm_crtc = kzalloc(sizeof(*imx_drm_crtc), GFP_KERNEL); 205 if (!imx_drm_crtc) 206 return -ENOMEM; 207 208 imx_drm_crtc->imx_drm_helper_funcs = *imx_drm_helper_funcs; 209 imx_drm_crtc->crtc = crtc; 210 211 crtc->port = port; 212 213 imxdrm->crtc[imxdrm->pipes++] = imx_drm_crtc; 214 215 *new_crtc = imx_drm_crtc; 216 217 drm_crtc_helper_add(crtc, 218 imx_drm_crtc->imx_drm_helper_funcs.crtc_helper_funcs); 219 220 drm_crtc_init_with_planes(drm, crtc, primary_plane, NULL, 221 imx_drm_crtc->imx_drm_helper_funcs.crtc_funcs, NULL); 222 223 return 0; 224} 225EXPORT_SYMBOL_GPL(imx_drm_add_crtc); 226 227/* 228 * imx_drm_remove_crtc - remove a crtc 229 */ 230int imx_drm_remove_crtc(struct imx_drm_crtc *imx_drm_crtc) 231{ 232 struct imx_drm_device *imxdrm = imx_drm_crtc->crtc->dev->dev_private; 233 unsigned int pipe = drm_crtc_index(imx_drm_crtc->crtc); 234 235 drm_crtc_cleanup(imx_drm_crtc->crtc); 236 237 imxdrm->crtc[pipe] = NULL; 238 239 kfree(imx_drm_crtc); 240 241 return 0; 242} 243EXPORT_SYMBOL_GPL(imx_drm_remove_crtc); 244 245int imx_drm_encoder_parse_of(struct drm_device *drm, 246 struct drm_encoder *encoder, struct device_node *np) 247{ 248 uint32_t crtc_mask = drm_of_find_possible_crtcs(drm, np); 249 250 /* 251 * If we failed to find the CRTC(s) which this encoder is 252 * supposed to be connected to, it's because the CRTC has 253 * not been registered yet. Defer probing, and hope that 254 * the required CRTC is added later. 255 */ 256 if (crtc_mask == 0) 257 return -EPROBE_DEFER; 258 259 encoder->possible_crtcs = crtc_mask; 260 261 /* FIXME: this is the mask of outputs which can clone this output. */ 262 encoder->possible_clones = ~0; 263 264 return 0; 265} 266EXPORT_SYMBOL_GPL(imx_drm_encoder_parse_of); 267 268static const struct drm_ioctl_desc imx_drm_ioctls[] = { 269 /* none so far */ 270}; 271 272static struct drm_driver imx_drm_driver = { 273 .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME | 274 DRIVER_ATOMIC, 275 .lastclose = imx_drm_driver_lastclose, 276 .gem_free_object_unlocked = drm_gem_cma_free_object, 277 .gem_vm_ops = &drm_gem_cma_vm_ops, 278 .dumb_create = drm_gem_cma_dumb_create, 279 .dumb_map_offset = drm_gem_cma_dumb_map_offset, 280 .dumb_destroy = drm_gem_dumb_destroy, 281 282 .prime_handle_to_fd = drm_gem_prime_handle_to_fd, 283 .prime_fd_to_handle = drm_gem_prime_fd_to_handle, 284 .gem_prime_import = drm_gem_prime_import, 285 .gem_prime_export = drm_gem_prime_export, 286 .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, 287 .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, 288 .gem_prime_vmap = drm_gem_cma_prime_vmap, 289 .gem_prime_vunmap = drm_gem_cma_prime_vunmap, 290 .gem_prime_mmap = drm_gem_cma_prime_mmap, 291 .get_vblank_counter = drm_vblank_no_hw_counter, 292 .enable_vblank = imx_drm_enable_vblank, 293 .disable_vblank = imx_drm_disable_vblank, 294 .ioctls = imx_drm_ioctls, 295 .num_ioctls = ARRAY_SIZE(imx_drm_ioctls), 296 .fops = &imx_drm_driver_fops, 297 .name = "imx-drm", 298 .desc = "i.MX DRM graphics", 299 .date = "20120507", 300 .major = 1, 301 .minor = 0, 302 .patchlevel = 0, 303}; 304 305static int compare_of(struct device *dev, void *data) 306{ 307 struct device_node *np = data; 308 309 /* Special case for DI, dev->of_node may not be set yet */ 310 if (strcmp(dev->driver->name, "imx-ipuv3-crtc") == 0) { 311 struct ipu_client_platformdata *pdata = dev->platform_data; 312 313 return pdata->of_node == np; 314 } 315 316 /* Special case for LDB, one device for two channels */ 317 if (of_node_cmp(np->name, "lvds-channel") == 0) { 318 np = of_get_parent(np); 319 of_node_put(np); 320 } 321 322 return dev->of_node == np; 323} 324 325static int imx_drm_bind(struct device *dev) 326{ 327 struct drm_device *drm; 328 struct imx_drm_device *imxdrm; 329 int ret; 330 331 drm = drm_dev_alloc(&imx_drm_driver, dev); 332 if (IS_ERR(drm)) 333 return PTR_ERR(drm); 334 335 imxdrm = devm_kzalloc(dev, sizeof(*imxdrm), GFP_KERNEL); 336 if (!imxdrm) { 337 ret = -ENOMEM; 338 goto err_unref; 339 } 340 341 imxdrm->drm = drm; 342 drm->dev_private = imxdrm; 343 344 /* 345 * enable drm irq mode. 346 * - with irq_enabled = true, we can use the vblank feature. 347 * 348 * P.S. note that we wouldn't use drm irq handler but 349 * just specific driver own one instead because 350 * drm framework supports only one irq handler and 351 * drivers can well take care of their interrupts 352 */ 353 drm->irq_enabled = true; 354 355 /* 356 * set max width and height as default value(4096x4096). 357 * this value would be used to check framebuffer size limitation 358 * at drm_mode_addfb(). 359 */ 360 drm->mode_config.min_width = 64; 361 drm->mode_config.min_height = 64; 362 drm->mode_config.max_width = 4096; 363 drm->mode_config.max_height = 4096; 364 drm->mode_config.funcs = &imx_drm_mode_config_funcs; 365 drm->mode_config.helper_private = &imx_drm_mode_config_helpers; 366 367 drm_mode_config_init(drm); 368 369 ret = drm_vblank_init(drm, MAX_CRTC); 370 if (ret) 371 goto err_kms; 372 373 dev_set_drvdata(dev, drm); 374 375 /* Now try and bind all our sub-components */ 376 ret = component_bind_all(dev, drm); 377 if (ret) 378 goto err_vblank; 379 380 drm_mode_config_reset(drm); 381 382 /* 383 * All components are now initialised, so setup the fb helper. 384 * The fb helper takes copies of key hardware information, so the 385 * crtcs/connectors/encoders must not change after this point. 386 */ 387#if IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION) 388 if (legacyfb_depth != 16 && legacyfb_depth != 32) { 389 dev_warn(dev, "Invalid legacyfb_depth. Defaulting to 16bpp\n"); 390 legacyfb_depth = 16; 391 } 392 imxdrm->fbhelper = drm_fbdev_cma_init(drm, legacyfb_depth, 393 drm->mode_config.num_crtc, MAX_CRTC); 394 if (IS_ERR(imxdrm->fbhelper)) { 395 ret = PTR_ERR(imxdrm->fbhelper); 396 imxdrm->fbhelper = NULL; 397 goto err_unbind; 398 } 399#endif 400 401 drm_kms_helper_poll_init(drm); 402 403 ret = drm_dev_register(drm, 0); 404 if (ret) 405 goto err_fbhelper; 406 407 return 0; 408 409err_fbhelper: 410 drm_kms_helper_poll_fini(drm); 411#if IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION) 412 if (imxdrm->fbhelper) 413 drm_fbdev_cma_fini(imxdrm->fbhelper); 414err_unbind: 415#endif 416 component_unbind_all(drm->dev, drm); 417err_vblank: 418 drm_vblank_cleanup(drm); 419err_kms: 420 drm_mode_config_cleanup(drm); 421err_unref: 422 drm_dev_unref(drm); 423 424 return ret; 425} 426 427static void imx_drm_unbind(struct device *dev) 428{ 429 struct drm_device *drm = dev_get_drvdata(dev); 430 struct imx_drm_device *imxdrm = drm->dev_private; 431 432 drm_dev_unregister(drm); 433 434 drm_kms_helper_poll_fini(drm); 435 436 if (imxdrm->fbhelper) 437 drm_fbdev_cma_fini(imxdrm->fbhelper); 438 439 drm_mode_config_cleanup(drm); 440 441 component_unbind_all(drm->dev, drm); 442 dev_set_drvdata(dev, NULL); 443 444 drm_dev_unref(drm); 445} 446 447static const struct component_master_ops imx_drm_ops = { 448 .bind = imx_drm_bind, 449 .unbind = imx_drm_unbind, 450}; 451 452static int imx_drm_platform_probe(struct platform_device *pdev) 453{ 454 int ret = drm_of_component_probe(&pdev->dev, compare_of, &imx_drm_ops); 455 456 if (!ret) 457 ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); 458 459 return ret; 460} 461 462static int imx_drm_platform_remove(struct platform_device *pdev) 463{ 464 component_master_del(&pdev->dev, &imx_drm_ops); 465 return 0; 466} 467 468#ifdef CONFIG_PM_SLEEP 469static int imx_drm_suspend(struct device *dev) 470{ 471 struct drm_device *drm_dev = dev_get_drvdata(dev); 472 struct imx_drm_device *imxdrm; 473 474 /* The drm_dev is NULL before .load hook is called */ 475 if (drm_dev == NULL) 476 return 0; 477 478 drm_kms_helper_poll_disable(drm_dev); 479 480 imxdrm = drm_dev->dev_private; 481 imxdrm->state = drm_atomic_helper_suspend(drm_dev); 482 if (IS_ERR(imxdrm->state)) { 483 drm_kms_helper_poll_enable(drm_dev); 484 return PTR_ERR(imxdrm->state); 485 } 486 487 return 0; 488} 489 490static int imx_drm_resume(struct device *dev) 491{ 492 struct drm_device *drm_dev = dev_get_drvdata(dev); 493 struct imx_drm_device *imx_drm; 494 495 if (drm_dev == NULL) 496 return 0; 497 498 imx_drm = drm_dev->dev_private; 499 drm_atomic_helper_resume(drm_dev, imx_drm->state); 500 drm_kms_helper_poll_enable(drm_dev); 501 502 return 0; 503} 504#endif 505 506static SIMPLE_DEV_PM_OPS(imx_drm_pm_ops, imx_drm_suspend, imx_drm_resume); 507 508static const struct of_device_id imx_drm_dt_ids[] = { 509 { .compatible = "fsl,imx-display-subsystem", }, 510 { /* sentinel */ }, 511}; 512MODULE_DEVICE_TABLE(of, imx_drm_dt_ids); 513 514static struct platform_driver imx_drm_pdrv = { 515 .probe = imx_drm_platform_probe, 516 .remove = imx_drm_platform_remove, 517 .driver = { 518 .name = "imx-drm", 519 .pm = &imx_drm_pm_ops, 520 .of_match_table = imx_drm_dt_ids, 521 }, 522}; 523module_platform_driver(imx_drm_pdrv); 524 525MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); 526MODULE_DESCRIPTION("i.MX drm driver core"); 527MODULE_LICENSE("GPL");