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.0-rc5 656 lines 16 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/fb.h> 19#include <linux/module.h> 20#include <linux/of_graph.h> 21#include <linux/platform_device.h> 22#include <drm/drmP.h> 23#include <drm/drm_fb_helper.h> 24#include <drm/drm_crtc_helper.h> 25#include <drm/drm_gem_cma_helper.h> 26#include <drm/drm_fb_cma_helper.h> 27#include <drm/drm_plane_helper.h> 28#include <drm/drm_of.h> 29 30#include "imx-drm.h" 31 32#define MAX_CRTC 4 33 34struct imx_drm_component { 35 struct device_node *of_node; 36 struct list_head list; 37}; 38 39struct imx_drm_device { 40 struct drm_device *drm; 41 struct imx_drm_crtc *crtc[MAX_CRTC]; 42 int pipes; 43 struct drm_fbdev_cma *fbhelper; 44}; 45 46struct imx_drm_crtc { 47 struct drm_crtc *crtc; 48 int pipe; 49 struct imx_drm_crtc_helper_funcs imx_drm_helper_funcs; 50}; 51 52static int legacyfb_depth = 16; 53module_param(legacyfb_depth, int, 0444); 54 55int imx_drm_crtc_id(struct imx_drm_crtc *crtc) 56{ 57 return crtc->pipe; 58} 59EXPORT_SYMBOL_GPL(imx_drm_crtc_id); 60 61static void imx_drm_driver_lastclose(struct drm_device *drm) 62{ 63#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER) 64 struct imx_drm_device *imxdrm = drm->dev_private; 65 66 if (imxdrm->fbhelper) 67 drm_fbdev_cma_restore_mode(imxdrm->fbhelper); 68#endif 69} 70 71static int imx_drm_driver_unload(struct drm_device *drm) 72{ 73#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER) 74 struct imx_drm_device *imxdrm = drm->dev_private; 75#endif 76 77 drm_kms_helper_poll_fini(drm); 78 79#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER) 80 if (imxdrm->fbhelper) 81 drm_fbdev_cma_fini(imxdrm->fbhelper); 82#endif 83 84 component_unbind_all(drm->dev, drm); 85 86 drm_vblank_cleanup(drm); 87 drm_mode_config_cleanup(drm); 88 89 platform_set_drvdata(drm->platformdev, NULL); 90 91 return 0; 92} 93 94static struct imx_drm_crtc *imx_drm_find_crtc(struct drm_crtc *crtc) 95{ 96 struct imx_drm_device *imxdrm = crtc->dev->dev_private; 97 unsigned i; 98 99 for (i = 0; i < MAX_CRTC; i++) 100 if (imxdrm->crtc[i] && imxdrm->crtc[i]->crtc == crtc) 101 return imxdrm->crtc[i]; 102 103 return NULL; 104} 105 106int imx_drm_panel_format_pins(struct drm_encoder *encoder, 107 u32 interface_pix_fmt, int hsync_pin, int vsync_pin) 108{ 109 struct imx_drm_crtc_helper_funcs *helper; 110 struct imx_drm_crtc *imx_crtc; 111 112 imx_crtc = imx_drm_find_crtc(encoder->crtc); 113 if (!imx_crtc) 114 return -EINVAL; 115 116 helper = &imx_crtc->imx_drm_helper_funcs; 117 if (helper->set_interface_pix_fmt) 118 return helper->set_interface_pix_fmt(encoder->crtc, 119 interface_pix_fmt, hsync_pin, vsync_pin); 120 return 0; 121} 122EXPORT_SYMBOL_GPL(imx_drm_panel_format_pins); 123 124int imx_drm_panel_format(struct drm_encoder *encoder, u32 interface_pix_fmt) 125{ 126 return imx_drm_panel_format_pins(encoder, interface_pix_fmt, 2, 3); 127} 128EXPORT_SYMBOL_GPL(imx_drm_panel_format); 129 130int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc) 131{ 132 return drm_vblank_get(imx_drm_crtc->crtc->dev, imx_drm_crtc->pipe); 133} 134EXPORT_SYMBOL_GPL(imx_drm_crtc_vblank_get); 135 136void imx_drm_crtc_vblank_put(struct imx_drm_crtc *imx_drm_crtc) 137{ 138 drm_vblank_put(imx_drm_crtc->crtc->dev, imx_drm_crtc->pipe); 139} 140EXPORT_SYMBOL_GPL(imx_drm_crtc_vblank_put); 141 142void imx_drm_handle_vblank(struct imx_drm_crtc *imx_drm_crtc) 143{ 144 drm_handle_vblank(imx_drm_crtc->crtc->dev, imx_drm_crtc->pipe); 145} 146EXPORT_SYMBOL_GPL(imx_drm_handle_vblank); 147 148static int imx_drm_enable_vblank(struct drm_device *drm, int crtc) 149{ 150 struct imx_drm_device *imxdrm = drm->dev_private; 151 struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[crtc]; 152 int ret; 153 154 if (!imx_drm_crtc) 155 return -EINVAL; 156 157 if (!imx_drm_crtc->imx_drm_helper_funcs.enable_vblank) 158 return -ENOSYS; 159 160 ret = imx_drm_crtc->imx_drm_helper_funcs.enable_vblank( 161 imx_drm_crtc->crtc); 162 163 return ret; 164} 165 166static void imx_drm_disable_vblank(struct drm_device *drm, int crtc) 167{ 168 struct imx_drm_device *imxdrm = drm->dev_private; 169 struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[crtc]; 170 171 if (!imx_drm_crtc) 172 return; 173 174 if (!imx_drm_crtc->imx_drm_helper_funcs.disable_vblank) 175 return; 176 177 imx_drm_crtc->imx_drm_helper_funcs.disable_vblank(imx_drm_crtc->crtc); 178} 179 180static void imx_drm_driver_preclose(struct drm_device *drm, 181 struct drm_file *file) 182{ 183 int i; 184 185 if (!file->is_master) 186 return; 187 188 for (i = 0; i < MAX_CRTC; i++) 189 imx_drm_disable_vblank(drm, i); 190} 191 192static const struct file_operations imx_drm_driver_fops = { 193 .owner = THIS_MODULE, 194 .open = drm_open, 195 .release = drm_release, 196 .unlocked_ioctl = drm_ioctl, 197 .mmap = drm_gem_cma_mmap, 198 .poll = drm_poll, 199 .read = drm_read, 200 .llseek = noop_llseek, 201}; 202 203void imx_drm_connector_destroy(struct drm_connector *connector) 204{ 205 drm_connector_unregister(connector); 206 drm_connector_cleanup(connector); 207} 208EXPORT_SYMBOL_GPL(imx_drm_connector_destroy); 209 210void imx_drm_encoder_destroy(struct drm_encoder *encoder) 211{ 212 drm_encoder_cleanup(encoder); 213} 214EXPORT_SYMBOL_GPL(imx_drm_encoder_destroy); 215 216static void imx_drm_output_poll_changed(struct drm_device *drm) 217{ 218#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER) 219 struct imx_drm_device *imxdrm = drm->dev_private; 220 221 drm_fbdev_cma_hotplug_event(imxdrm->fbhelper); 222#endif 223} 224 225static struct drm_mode_config_funcs imx_drm_mode_config_funcs = { 226 .fb_create = drm_fb_cma_create, 227 .output_poll_changed = imx_drm_output_poll_changed, 228}; 229 230/* 231 * Main DRM initialisation. This binds, initialises and registers 232 * with DRM the subcomponents of the driver. 233 */ 234static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags) 235{ 236 struct imx_drm_device *imxdrm; 237 struct drm_connector *connector; 238 int ret; 239 240 imxdrm = devm_kzalloc(drm->dev, sizeof(*imxdrm), GFP_KERNEL); 241 if (!imxdrm) 242 return -ENOMEM; 243 244 imxdrm->drm = drm; 245 246 drm->dev_private = imxdrm; 247 248 /* 249 * enable drm irq mode. 250 * - with irq_enabled = true, we can use the vblank feature. 251 * 252 * P.S. note that we wouldn't use drm irq handler but 253 * just specific driver own one instead because 254 * drm framework supports only one irq handler and 255 * drivers can well take care of their interrupts 256 */ 257 drm->irq_enabled = true; 258 259 /* 260 * set max width and height as default value(4096x4096). 261 * this value would be used to check framebuffer size limitation 262 * at drm_mode_addfb(). 263 */ 264 drm->mode_config.min_width = 64; 265 drm->mode_config.min_height = 64; 266 drm->mode_config.max_width = 4096; 267 drm->mode_config.max_height = 4096; 268 drm->mode_config.funcs = &imx_drm_mode_config_funcs; 269 270 drm_mode_config_init(drm); 271 272 ret = drm_vblank_init(drm, MAX_CRTC); 273 if (ret) 274 goto err_kms; 275 276 /* 277 * with vblank_disable_allowed = true, vblank interrupt will be 278 * disabled by drm timer once a current process gives up ownership 279 * of vblank event. (after drm_vblank_put function is called) 280 */ 281 drm->vblank_disable_allowed = true; 282 283 platform_set_drvdata(drm->platformdev, drm); 284 285 /* Now try and bind all our sub-components */ 286 ret = component_bind_all(drm->dev, drm); 287 if (ret) 288 goto err_vblank; 289 290 /* 291 * All components are now added, we can publish the connector sysfs 292 * entries to userspace. This will generate hotplug events and so 293 * userspace will expect to be able to access DRM at this point. 294 */ 295 list_for_each_entry(connector, &drm->mode_config.connector_list, head) { 296 ret = drm_connector_register(connector); 297 if (ret) { 298 dev_err(drm->dev, 299 "[CONNECTOR:%d:%s] drm_connector_register failed: %d\n", 300 connector->base.id, 301 connector->name, ret); 302 goto err_unbind; 303 } 304 } 305 306 /* 307 * All components are now initialised, so setup the fb helper. 308 * The fb helper takes copies of key hardware information, so the 309 * crtcs/connectors/encoders must not change after this point. 310 */ 311#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER) 312 if (legacyfb_depth != 16 && legacyfb_depth != 32) { 313 dev_warn(drm->dev, "Invalid legacyfb_depth. Defaulting to 16bpp\n"); 314 legacyfb_depth = 16; 315 } 316 imxdrm->fbhelper = drm_fbdev_cma_init(drm, legacyfb_depth, 317 drm->mode_config.num_crtc, MAX_CRTC); 318 if (IS_ERR(imxdrm->fbhelper)) { 319 ret = PTR_ERR(imxdrm->fbhelper); 320 imxdrm->fbhelper = NULL; 321 goto err_unbind; 322 } 323#endif 324 325 drm_kms_helper_poll_init(drm); 326 327 return 0; 328 329err_unbind: 330 component_unbind_all(drm->dev, drm); 331err_vblank: 332 drm_vblank_cleanup(drm); 333err_kms: 334 drm_mode_config_cleanup(drm); 335 336 return ret; 337} 338 339/* 340 * imx_drm_add_crtc - add a new crtc 341 */ 342int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc, 343 struct imx_drm_crtc **new_crtc, 344 const struct imx_drm_crtc_helper_funcs *imx_drm_helper_funcs, 345 struct device_node *port) 346{ 347 struct imx_drm_device *imxdrm = drm->dev_private; 348 struct imx_drm_crtc *imx_drm_crtc; 349 int ret; 350 351 /* 352 * The vblank arrays are dimensioned by MAX_CRTC - we can't 353 * pass IDs greater than this to those functions. 354 */ 355 if (imxdrm->pipes >= MAX_CRTC) 356 return -EINVAL; 357 358 if (imxdrm->drm->open_count) 359 return -EBUSY; 360 361 imx_drm_crtc = kzalloc(sizeof(*imx_drm_crtc), GFP_KERNEL); 362 if (!imx_drm_crtc) 363 return -ENOMEM; 364 365 imx_drm_crtc->imx_drm_helper_funcs = *imx_drm_helper_funcs; 366 imx_drm_crtc->pipe = imxdrm->pipes++; 367 imx_drm_crtc->crtc = crtc; 368 369 crtc->port = port; 370 371 imxdrm->crtc[imx_drm_crtc->pipe] = imx_drm_crtc; 372 373 *new_crtc = imx_drm_crtc; 374 375 ret = drm_mode_crtc_set_gamma_size(imx_drm_crtc->crtc, 256); 376 if (ret) 377 goto err_register; 378 379 drm_crtc_helper_add(crtc, 380 imx_drm_crtc->imx_drm_helper_funcs.crtc_helper_funcs); 381 382 drm_crtc_init(drm, crtc, 383 imx_drm_crtc->imx_drm_helper_funcs.crtc_funcs); 384 385 return 0; 386 387err_register: 388 imxdrm->crtc[imx_drm_crtc->pipe] = NULL; 389 kfree(imx_drm_crtc); 390 return ret; 391} 392EXPORT_SYMBOL_GPL(imx_drm_add_crtc); 393 394/* 395 * imx_drm_remove_crtc - remove a crtc 396 */ 397int imx_drm_remove_crtc(struct imx_drm_crtc *imx_drm_crtc) 398{ 399 struct imx_drm_device *imxdrm = imx_drm_crtc->crtc->dev->dev_private; 400 401 drm_crtc_cleanup(imx_drm_crtc->crtc); 402 403 imxdrm->crtc[imx_drm_crtc->pipe] = NULL; 404 405 kfree(imx_drm_crtc); 406 407 return 0; 408} 409EXPORT_SYMBOL_GPL(imx_drm_remove_crtc); 410 411int imx_drm_encoder_parse_of(struct drm_device *drm, 412 struct drm_encoder *encoder, struct device_node *np) 413{ 414 uint32_t crtc_mask = drm_of_find_possible_crtcs(drm, np); 415 416 /* 417 * If we failed to find the CRTC(s) which this encoder is 418 * supposed to be connected to, it's because the CRTC has 419 * not been registered yet. Defer probing, and hope that 420 * the required CRTC is added later. 421 */ 422 if (crtc_mask == 0) 423 return -EPROBE_DEFER; 424 425 encoder->possible_crtcs = crtc_mask; 426 427 /* FIXME: this is the mask of outputs which can clone this output. */ 428 encoder->possible_clones = ~0; 429 430 return 0; 431} 432EXPORT_SYMBOL_GPL(imx_drm_encoder_parse_of); 433 434static struct device_node *imx_drm_of_get_next_endpoint( 435 const struct device_node *parent, struct device_node *prev) 436{ 437 struct device_node *node = of_graph_get_next_endpoint(parent, prev); 438 439 of_node_put(prev); 440 return node; 441} 442 443/* 444 * @node: device tree node containing encoder input ports 445 * @encoder: drm_encoder 446 */ 447int imx_drm_encoder_get_mux_id(struct device_node *node, 448 struct drm_encoder *encoder) 449{ 450 struct imx_drm_crtc *imx_crtc = imx_drm_find_crtc(encoder->crtc); 451 struct device_node *ep = NULL; 452 struct of_endpoint endpoint; 453 struct device_node *port; 454 int ret; 455 456 if (!node || !imx_crtc) 457 return -EINVAL; 458 459 do { 460 ep = imx_drm_of_get_next_endpoint(node, ep); 461 if (!ep) 462 break; 463 464 port = of_graph_get_remote_port(ep); 465 of_node_put(port); 466 if (port == imx_crtc->crtc->port) { 467 ret = of_graph_parse_endpoint(ep, &endpoint); 468 return ret ? ret : endpoint.port; 469 } 470 } while (ep); 471 472 return -EINVAL; 473} 474EXPORT_SYMBOL_GPL(imx_drm_encoder_get_mux_id); 475 476static const struct drm_ioctl_desc imx_drm_ioctls[] = { 477 /* none so far */ 478}; 479 480static struct drm_driver imx_drm_driver = { 481 .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME, 482 .load = imx_drm_driver_load, 483 .unload = imx_drm_driver_unload, 484 .lastclose = imx_drm_driver_lastclose, 485 .preclose = imx_drm_driver_preclose, 486 .set_busid = drm_platform_set_busid, 487 .gem_free_object = drm_gem_cma_free_object, 488 .gem_vm_ops = &drm_gem_cma_vm_ops, 489 .dumb_create = drm_gem_cma_dumb_create, 490 .dumb_map_offset = drm_gem_cma_dumb_map_offset, 491 .dumb_destroy = drm_gem_dumb_destroy, 492 493 .prime_handle_to_fd = drm_gem_prime_handle_to_fd, 494 .prime_fd_to_handle = drm_gem_prime_fd_to_handle, 495 .gem_prime_import = drm_gem_prime_import, 496 .gem_prime_export = drm_gem_prime_export, 497 .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, 498 .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, 499 .gem_prime_vmap = drm_gem_cma_prime_vmap, 500 .gem_prime_vunmap = drm_gem_cma_prime_vunmap, 501 .gem_prime_mmap = drm_gem_cma_prime_mmap, 502 .get_vblank_counter = drm_vblank_count, 503 .enable_vblank = imx_drm_enable_vblank, 504 .disable_vblank = imx_drm_disable_vblank, 505 .ioctls = imx_drm_ioctls, 506 .num_ioctls = ARRAY_SIZE(imx_drm_ioctls), 507 .fops = &imx_drm_driver_fops, 508 .name = "imx-drm", 509 .desc = "i.MX DRM graphics", 510 .date = "20120507", 511 .major = 1, 512 .minor = 0, 513 .patchlevel = 0, 514}; 515 516static int compare_of(struct device *dev, void *data) 517{ 518 struct device_node *np = data; 519 520 /* Special case for LDB, one device for two channels */ 521 if (of_node_cmp(np->name, "lvds-channel") == 0) { 522 np = of_get_parent(np); 523 of_node_put(np); 524 } 525 526 return dev->of_node == np; 527} 528 529static int imx_drm_bind(struct device *dev) 530{ 531 return drm_platform_init(&imx_drm_driver, to_platform_device(dev)); 532} 533 534static void imx_drm_unbind(struct device *dev) 535{ 536 drm_put_dev(dev_get_drvdata(dev)); 537} 538 539static const struct component_master_ops imx_drm_ops = { 540 .bind = imx_drm_bind, 541 .unbind = imx_drm_unbind, 542}; 543 544static int imx_drm_platform_probe(struct platform_device *pdev) 545{ 546 struct device_node *ep, *port, *remote; 547 struct component_match *match = NULL; 548 int ret; 549 int i; 550 551 /* 552 * Bind the IPU display interface ports first, so that 553 * imx_drm_encoder_parse_of called from encoder .bind callbacks 554 * works as expected. 555 */ 556 for (i = 0; ; i++) { 557 port = of_parse_phandle(pdev->dev.of_node, "ports", i); 558 if (!port) 559 break; 560 561 component_match_add(&pdev->dev, &match, compare_of, port); 562 } 563 564 if (i == 0) { 565 dev_err(&pdev->dev, "missing 'ports' property\n"); 566 return -ENODEV; 567 } 568 569 /* Then bind all encoders */ 570 for (i = 0; ; i++) { 571 port = of_parse_phandle(pdev->dev.of_node, "ports", i); 572 if (!port) 573 break; 574 575 for_each_child_of_node(port, ep) { 576 remote = of_graph_get_remote_port_parent(ep); 577 if (!remote || !of_device_is_available(remote)) { 578 of_node_put(remote); 579 continue; 580 } else if (!of_device_is_available(remote->parent)) { 581 dev_warn(&pdev->dev, "parent device of %s is not available\n", 582 remote->full_name); 583 of_node_put(remote); 584 continue; 585 } 586 587 component_match_add(&pdev->dev, &match, compare_of, 588 remote); 589 of_node_put(remote); 590 } 591 of_node_put(port); 592 } 593 594 ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); 595 if (ret) 596 return ret; 597 598 return component_master_add_with_match(&pdev->dev, &imx_drm_ops, match); 599} 600 601static int imx_drm_platform_remove(struct platform_device *pdev) 602{ 603 component_master_del(&pdev->dev, &imx_drm_ops); 604 return 0; 605} 606 607#ifdef CONFIG_PM_SLEEP 608static int imx_drm_suspend(struct device *dev) 609{ 610 struct drm_device *drm_dev = dev_get_drvdata(dev); 611 612 /* The drm_dev is NULL before .load hook is called */ 613 if (drm_dev == NULL) 614 return 0; 615 616 drm_kms_helper_poll_disable(drm_dev); 617 618 return 0; 619} 620 621static int imx_drm_resume(struct device *dev) 622{ 623 struct drm_device *drm_dev = dev_get_drvdata(dev); 624 625 if (drm_dev == NULL) 626 return 0; 627 628 drm_helper_resume_force_mode(drm_dev); 629 drm_kms_helper_poll_enable(drm_dev); 630 631 return 0; 632} 633#endif 634 635static SIMPLE_DEV_PM_OPS(imx_drm_pm_ops, imx_drm_suspend, imx_drm_resume); 636 637static const struct of_device_id imx_drm_dt_ids[] = { 638 { .compatible = "fsl,imx-display-subsystem", }, 639 { /* sentinel */ }, 640}; 641MODULE_DEVICE_TABLE(of, imx_drm_dt_ids); 642 643static struct platform_driver imx_drm_pdrv = { 644 .probe = imx_drm_platform_probe, 645 .remove = imx_drm_platform_remove, 646 .driver = { 647 .name = "imx-drm", 648 .pm = &imx_drm_pm_ops, 649 .of_match_table = imx_drm_dt_ids, 650 }, 651}; 652module_platform_driver(imx_drm_pdrv); 653 654MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); 655MODULE_DESCRIPTION("i.MX drm driver core"); 656MODULE_LICENSE("GPL");