diff options
author | Thierry Reding <treding@nvidia.com> | 2014-10-21 07:51:53 -0400 |
---|---|---|
committer | Thierry Reding <treding@nvidia.com> | 2014-11-13 10:18:28 -0500 |
commit | c7679306a923c2feb383f709446c1110db1c56e4 (patch) | |
tree | 1652c214408efdb374d60fe1bfe8757aa1ca0f58 /drivers/gpu/drm/tegra | |
parent | 03a605697658ac7af722764cef3f0fed889d2033 (diff) |
drm/tegra: dc: Universal plane support
This allows the primary plane and cursor to be exposed as regular
DRM/KMS planes, which is a prerequisite for atomic modesetting and gives
userspace more flexibility over controlling them.
Signed-off-by: Thierry Reding <treding@nvidia.com>
Diffstat (limited to 'drivers/gpu/drm/tegra')
-rw-r--r-- | drivers/gpu/drm/tegra/dc.c | 487 |
1 files changed, 330 insertions, 157 deletions
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index 517a257cccaf..7ef16a2409b1 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c | |||
@@ -332,11 +332,255 @@ static int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index, | |||
332 | return 0; | 332 | return 0; |
333 | } | 333 | } |
334 | 334 | ||
335 | static int tegra_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, | 335 | static int tegra_window_plane_disable(struct drm_plane *plane) |
336 | struct drm_framebuffer *fb, int crtc_x, | 336 | { |
337 | int crtc_y, unsigned int crtc_w, | 337 | struct tegra_dc *dc = to_tegra_dc(plane->crtc); |
338 | unsigned int crtc_h, uint32_t src_x, | 338 | struct tegra_plane *p = to_tegra_plane(plane); |
339 | uint32_t src_y, uint32_t src_w, uint32_t src_h) | 339 | u32 value; |
340 | |||
341 | if (!plane->crtc) | ||
342 | return 0; | ||
343 | |||
344 | value = WINDOW_A_SELECT << p->index; | ||
345 | tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER); | ||
346 | |||
347 | value = tegra_dc_readl(dc, DC_WIN_WIN_OPTIONS); | ||
348 | value &= ~WIN_ENABLE; | ||
349 | tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS); | ||
350 | |||
351 | tegra_dc_window_commit(dc, p->index); | ||
352 | |||
353 | return 0; | ||
354 | } | ||
355 | |||
356 | static void tegra_plane_destroy(struct drm_plane *plane) | ||
357 | { | ||
358 | struct tegra_plane *p = to_tegra_plane(plane); | ||
359 | |||
360 | drm_plane_cleanup(plane); | ||
361 | kfree(p); | ||
362 | } | ||
363 | |||
364 | static const u32 tegra_primary_plane_formats[] = { | ||
365 | DRM_FORMAT_XBGR8888, | ||
366 | DRM_FORMAT_XRGB8888, | ||
367 | DRM_FORMAT_RGB565, | ||
368 | }; | ||
369 | |||
370 | static int tegra_primary_plane_update(struct drm_plane *plane, | ||
371 | struct drm_crtc *crtc, | ||
372 | struct drm_framebuffer *fb, int crtc_x, | ||
373 | int crtc_y, unsigned int crtc_w, | ||
374 | unsigned int crtc_h, uint32_t src_x, | ||
375 | uint32_t src_y, uint32_t src_w, | ||
376 | uint32_t src_h) | ||
377 | { | ||
378 | struct tegra_bo *bo = tegra_fb_get_plane(fb, 0); | ||
379 | struct tegra_plane *p = to_tegra_plane(plane); | ||
380 | struct tegra_dc *dc = to_tegra_dc(crtc); | ||
381 | struct tegra_dc_window window; | ||
382 | int err; | ||
383 | |||
384 | memset(&window, 0, sizeof(window)); | ||
385 | window.src.x = src_x >> 16; | ||
386 | window.src.y = src_y >> 16; | ||
387 | window.src.w = src_w >> 16; | ||
388 | window.src.h = src_h >> 16; | ||
389 | window.dst.x = crtc_x; | ||
390 | window.dst.y = crtc_y; | ||
391 | window.dst.w = crtc_w; | ||
392 | window.dst.h = crtc_h; | ||
393 | window.format = tegra_dc_format(fb->pixel_format, &window.swap); | ||
394 | window.bits_per_pixel = fb->bits_per_pixel; | ||
395 | window.bottom_up = tegra_fb_is_bottom_up(fb); | ||
396 | |||
397 | err = tegra_fb_get_tiling(fb, &window.tiling); | ||
398 | if (err < 0) | ||
399 | return err; | ||
400 | |||
401 | window.base[0] = bo->paddr + fb->offsets[0]; | ||
402 | window.stride[0] = fb->pitches[0]; | ||
403 | |||
404 | err = tegra_dc_setup_window(dc, p->index, &window); | ||
405 | if (err < 0) | ||
406 | return err; | ||
407 | |||
408 | return 0; | ||
409 | } | ||
410 | |||
411 | static void tegra_primary_plane_destroy(struct drm_plane *plane) | ||
412 | { | ||
413 | tegra_window_plane_disable(plane); | ||
414 | tegra_plane_destroy(plane); | ||
415 | } | ||
416 | |||
417 | static const struct drm_plane_funcs tegra_primary_plane_funcs = { | ||
418 | .update_plane = tegra_primary_plane_update, | ||
419 | .disable_plane = tegra_window_plane_disable, | ||
420 | .destroy = tegra_primary_plane_destroy, | ||
421 | }; | ||
422 | |||
423 | static struct drm_plane *tegra_dc_primary_plane_create(struct drm_device *drm, | ||
424 | struct tegra_dc *dc) | ||
425 | { | ||
426 | struct tegra_plane *plane; | ||
427 | unsigned int num_formats; | ||
428 | const u32 *formats; | ||
429 | int err; | ||
430 | |||
431 | plane = kzalloc(sizeof(*plane), GFP_KERNEL); | ||
432 | if (!plane) | ||
433 | return ERR_PTR(-ENOMEM); | ||
434 | |||
435 | num_formats = ARRAY_SIZE(tegra_primary_plane_formats); | ||
436 | formats = tegra_primary_plane_formats; | ||
437 | |||
438 | err = drm_universal_plane_init(drm, &plane->base, 1 << dc->pipe, | ||
439 | &tegra_primary_plane_funcs, formats, | ||
440 | num_formats, DRM_PLANE_TYPE_PRIMARY); | ||
441 | if (err < 0) { | ||
442 | kfree(plane); | ||
443 | return ERR_PTR(err); | ||
444 | } | ||
445 | |||
446 | return &plane->base; | ||
447 | } | ||
448 | |||
449 | static const u32 tegra_cursor_plane_formats[] = { | ||
450 | DRM_FORMAT_RGBA8888, | ||
451 | }; | ||
452 | |||
453 | static int tegra_cursor_plane_update(struct drm_plane *plane, | ||
454 | struct drm_crtc *crtc, | ||
455 | struct drm_framebuffer *fb, int crtc_x, | ||
456 | int crtc_y, unsigned int crtc_w, | ||
457 | unsigned int crtc_h, uint32_t src_x, | ||
458 | uint32_t src_y, uint32_t src_w, | ||
459 | uint32_t src_h) | ||
460 | { | ||
461 | struct tegra_bo *bo = tegra_fb_get_plane(fb, 0); | ||
462 | struct tegra_dc *dc = to_tegra_dc(crtc); | ||
463 | u32 value = CURSOR_CLIP_DISPLAY; | ||
464 | |||
465 | /* scaling not supported for cursor */ | ||
466 | if ((src_w >> 16 != crtc_w) || (src_h >> 16 != crtc_h)) | ||
467 | return -EINVAL; | ||
468 | |||
469 | /* only square cursors supported */ | ||
470 | if (src_w != src_h) | ||
471 | return -EINVAL; | ||
472 | |||
473 | switch (crtc_w) { | ||
474 | case 32: | ||
475 | value |= CURSOR_SIZE_32x32; | ||
476 | break; | ||
477 | |||
478 | case 64: | ||
479 | value |= CURSOR_SIZE_64x64; | ||
480 | break; | ||
481 | |||
482 | case 128: | ||
483 | value |= CURSOR_SIZE_128x128; | ||
484 | break; | ||
485 | |||
486 | case 256: | ||
487 | value |= CURSOR_SIZE_256x256; | ||
488 | break; | ||
489 | |||
490 | default: | ||
491 | return -EINVAL; | ||
492 | } | ||
493 | |||
494 | value |= (bo->paddr >> 10) & 0x3fffff; | ||
495 | tegra_dc_writel(dc, value, DC_DISP_CURSOR_START_ADDR); | ||
496 | |||
497 | #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT | ||
498 | value = (bo->paddr >> 32) & 0x3; | ||
499 | tegra_dc_writel(dc, value, DC_DISP_CURSOR_START_ADDR_HI); | ||
500 | #endif | ||
501 | |||
502 | /* enable cursor and set blend mode */ | ||
503 | value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS); | ||
504 | value |= CURSOR_ENABLE; | ||
505 | tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS); | ||
506 | |||
507 | value = tegra_dc_readl(dc, DC_DISP_BLEND_CURSOR_CONTROL); | ||
508 | value &= ~CURSOR_DST_BLEND_MASK; | ||
509 | value &= ~CURSOR_SRC_BLEND_MASK; | ||
510 | value |= CURSOR_MODE_NORMAL; | ||
511 | value |= CURSOR_DST_BLEND_NEG_K1_TIMES_SRC; | ||
512 | value |= CURSOR_SRC_BLEND_K1_TIMES_SRC; | ||
513 | value |= CURSOR_ALPHA; | ||
514 | tegra_dc_writel(dc, value, DC_DISP_BLEND_CURSOR_CONTROL); | ||
515 | |||
516 | /* position the cursor */ | ||
517 | value = (crtc_y & 0x3fff) << 16 | (crtc_x & 0x3fff); | ||
518 | tegra_dc_writel(dc, value, DC_DISP_CURSOR_POSITION); | ||
519 | |||
520 | /* apply changes */ | ||
521 | tegra_dc_cursor_commit(dc); | ||
522 | tegra_dc_commit(dc); | ||
523 | |||
524 | return 0; | ||
525 | } | ||
526 | |||
527 | static int tegra_cursor_plane_disable(struct drm_plane *plane) | ||
528 | { | ||
529 | struct tegra_dc *dc = to_tegra_dc(plane->crtc); | ||
530 | u32 value; | ||
531 | |||
532 | if (!plane->crtc) | ||
533 | return 0; | ||
534 | |||
535 | value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS); | ||
536 | value &= ~CURSOR_ENABLE; | ||
537 | tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS); | ||
538 | |||
539 | tegra_dc_cursor_commit(dc); | ||
540 | tegra_dc_commit(dc); | ||
541 | |||
542 | return 0; | ||
543 | } | ||
544 | |||
545 | static const struct drm_plane_funcs tegra_cursor_plane_funcs = { | ||
546 | .update_plane = tegra_cursor_plane_update, | ||
547 | .disable_plane = tegra_cursor_plane_disable, | ||
548 | .destroy = tegra_plane_destroy, | ||
549 | }; | ||
550 | |||
551 | static struct drm_plane *tegra_dc_cursor_plane_create(struct drm_device *drm, | ||
552 | struct tegra_dc *dc) | ||
553 | { | ||
554 | struct tegra_plane *plane; | ||
555 | unsigned int num_formats; | ||
556 | const u32 *formats; | ||
557 | int err; | ||
558 | |||
559 | plane = kzalloc(sizeof(*plane), GFP_KERNEL); | ||
560 | if (!plane) | ||
561 | return ERR_PTR(-ENOMEM); | ||
562 | |||
563 | num_formats = ARRAY_SIZE(tegra_cursor_plane_formats); | ||
564 | formats = tegra_cursor_plane_formats; | ||
565 | |||
566 | err = drm_universal_plane_init(drm, &plane->base, 1 << dc->pipe, | ||
567 | &tegra_cursor_plane_funcs, formats, | ||
568 | num_formats, DRM_PLANE_TYPE_CURSOR); | ||
569 | if (err < 0) { | ||
570 | kfree(plane); | ||
571 | return ERR_PTR(err); | ||
572 | } | ||
573 | |||
574 | return &plane->base; | ||
575 | } | ||
576 | |||
577 | static int tegra_overlay_plane_update(struct drm_plane *plane, | ||
578 | struct drm_crtc *crtc, | ||
579 | struct drm_framebuffer *fb, int crtc_x, | ||
580 | int crtc_y, unsigned int crtc_w, | ||
581 | unsigned int crtc_h, uint32_t src_x, | ||
582 | uint32_t src_y, uint32_t src_w, | ||
583 | uint32_t src_h) | ||
340 | { | 584 | { |
341 | struct tegra_plane *p = to_tegra_plane(plane); | 585 | struct tegra_plane *p = to_tegra_plane(plane); |
342 | struct tegra_dc *dc = to_tegra_dc(crtc); | 586 | struct tegra_dc *dc = to_tegra_dc(crtc); |
@@ -382,43 +626,19 @@ static int tegra_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, | |||
382 | return tegra_dc_setup_window(dc, p->index, &window); | 626 | return tegra_dc_setup_window(dc, p->index, &window); |
383 | } | 627 | } |
384 | 628 | ||
385 | static int tegra_plane_disable(struct drm_plane *plane) | 629 | static void tegra_overlay_plane_destroy(struct drm_plane *plane) |
386 | { | ||
387 | struct tegra_dc *dc = to_tegra_dc(plane->crtc); | ||
388 | struct tegra_plane *p = to_tegra_plane(plane); | ||
389 | unsigned long value; | ||
390 | |||
391 | if (!plane->crtc) | ||
392 | return 0; | ||
393 | |||
394 | value = WINDOW_A_SELECT << p->index; | ||
395 | tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER); | ||
396 | |||
397 | value = tegra_dc_readl(dc, DC_WIN_WIN_OPTIONS); | ||
398 | value &= ~WIN_ENABLE; | ||
399 | tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS); | ||
400 | |||
401 | tegra_dc_window_commit(dc, p->index); | ||
402 | |||
403 | return 0; | ||
404 | } | ||
405 | |||
406 | static void tegra_plane_destroy(struct drm_plane *plane) | ||
407 | { | 630 | { |
408 | struct tegra_plane *p = to_tegra_plane(plane); | 631 | tegra_window_plane_disable(plane); |
409 | 632 | tegra_plane_destroy(plane); | |
410 | tegra_plane_disable(plane); | ||
411 | drm_plane_cleanup(plane); | ||
412 | kfree(p); | ||
413 | } | 633 | } |
414 | 634 | ||
415 | static const struct drm_plane_funcs tegra_plane_funcs = { | 635 | static const struct drm_plane_funcs tegra_overlay_plane_funcs = { |
416 | .update_plane = tegra_plane_update, | 636 | .update_plane = tegra_overlay_plane_update, |
417 | .disable_plane = tegra_plane_disable, | 637 | .disable_plane = tegra_window_plane_disable, |
418 | .destroy = tegra_plane_destroy, | 638 | .destroy = tegra_overlay_plane_destroy, |
419 | }; | 639 | }; |
420 | 640 | ||
421 | static const uint32_t plane_formats[] = { | 641 | static const uint32_t tegra_overlay_plane_formats[] = { |
422 | DRM_FORMAT_XBGR8888, | 642 | DRM_FORMAT_XBGR8888, |
423 | DRM_FORMAT_XRGB8888, | 643 | DRM_FORMAT_XRGB8888, |
424 | DRM_FORMAT_RGB565, | 644 | DRM_FORMAT_RGB565, |
@@ -428,27 +648,44 @@ static const uint32_t plane_formats[] = { | |||
428 | DRM_FORMAT_YUV422, | 648 | DRM_FORMAT_YUV422, |
429 | }; | 649 | }; |
430 | 650 | ||
431 | static int tegra_dc_add_planes(struct drm_device *drm, struct tegra_dc *dc) | 651 | static struct drm_plane *tegra_dc_overlay_plane_create(struct drm_device *drm, |
652 | struct tegra_dc *dc, | ||
653 | unsigned int index) | ||
432 | { | 654 | { |
433 | unsigned int i; | 655 | struct tegra_plane *plane; |
434 | int err = 0; | 656 | unsigned int num_formats; |
657 | const u32 *formats; | ||
658 | int err; | ||
435 | 659 | ||
436 | for (i = 0; i < 2; i++) { | 660 | plane = kzalloc(sizeof(*plane), GFP_KERNEL); |
437 | struct tegra_plane *plane; | 661 | if (!plane) |
662 | return ERR_PTR(-ENOMEM); | ||
438 | 663 | ||
439 | plane = kzalloc(sizeof(*plane), GFP_KERNEL); | 664 | plane->index = index; |
440 | if (!plane) | ||
441 | return -ENOMEM; | ||
442 | 665 | ||
443 | plane->index = 1 + i; | 666 | num_formats = ARRAY_SIZE(tegra_overlay_plane_formats); |
667 | formats = tegra_overlay_plane_formats; | ||
444 | 668 | ||
445 | err = drm_plane_init(drm, &plane->base, 1 << dc->pipe, | 669 | err = drm_universal_plane_init(drm, &plane->base, 1 << dc->pipe, |
446 | &tegra_plane_funcs, plane_formats, | 670 | &tegra_overlay_plane_funcs, formats, |
447 | ARRAY_SIZE(plane_formats), false); | 671 | num_formats, DRM_PLANE_TYPE_OVERLAY); |
448 | if (err < 0) { | 672 | if (err < 0) { |
449 | kfree(plane); | 673 | kfree(plane); |
450 | return err; | 674 | return ERR_PTR(err); |
451 | } | 675 | } |
676 | |||
677 | return &plane->base; | ||
678 | } | ||
679 | |||
680 | static int tegra_dc_add_planes(struct drm_device *drm, struct tegra_dc *dc) | ||
681 | { | ||
682 | struct drm_plane *plane; | ||
683 | unsigned int i; | ||
684 | |||
685 | for (i = 0; i < 2; i++) { | ||
686 | plane = tegra_dc_overlay_plane_create(drm, dc, 1 + i); | ||
687 | if (IS_ERR(plane)) | ||
688 | return PTR_ERR(plane); | ||
452 | } | 689 | } |
453 | 690 | ||
454 | return 0; | 691 | return 0; |
@@ -568,103 +805,6 @@ void tegra_dc_disable_vblank(struct tegra_dc *dc) | |||
568 | spin_unlock_irqrestore(&dc->lock, flags); | 805 | spin_unlock_irqrestore(&dc->lock, flags); |
569 | } | 806 | } |
570 | 807 | ||
571 | static int tegra_dc_cursor_set2(struct drm_crtc *crtc, struct drm_file *file, | ||
572 | uint32_t handle, uint32_t width, | ||
573 | uint32_t height, int32_t hot_x, int32_t hot_y) | ||
574 | { | ||
575 | unsigned long value = CURSOR_CLIP_DISPLAY; | ||
576 | struct tegra_dc *dc = to_tegra_dc(crtc); | ||
577 | struct drm_gem_object *gem; | ||
578 | struct tegra_bo *bo = NULL; | ||
579 | |||
580 | if (!dc->soc->supports_cursor) | ||
581 | return -ENXIO; | ||
582 | |||
583 | if (width != height) | ||
584 | return -EINVAL; | ||
585 | |||
586 | switch (width) { | ||
587 | case 32: | ||
588 | value |= CURSOR_SIZE_32x32; | ||
589 | break; | ||
590 | |||
591 | case 64: | ||
592 | value |= CURSOR_SIZE_64x64; | ||
593 | break; | ||
594 | |||
595 | case 128: | ||
596 | value |= CURSOR_SIZE_128x128; | ||
597 | |||
598 | case 256: | ||
599 | value |= CURSOR_SIZE_256x256; | ||
600 | break; | ||
601 | |||
602 | default: | ||
603 | return -EINVAL; | ||
604 | } | ||
605 | |||
606 | if (handle) { | ||
607 | gem = drm_gem_object_lookup(crtc->dev, file, handle); | ||
608 | if (!gem) | ||
609 | return -ENOENT; | ||
610 | |||
611 | bo = to_tegra_bo(gem); | ||
612 | } | ||
613 | |||
614 | if (bo) { | ||
615 | unsigned long addr = (bo->paddr & 0xfffffc00) >> 10; | ||
616 | #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT | ||
617 | unsigned long high = (bo->paddr & 0xfffffffc) >> 32; | ||
618 | #endif | ||
619 | |||
620 | tegra_dc_writel(dc, value | addr, DC_DISP_CURSOR_START_ADDR); | ||
621 | |||
622 | #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT | ||
623 | tegra_dc_writel(dc, high, DC_DISP_CURSOR_START_ADDR_HI); | ||
624 | #endif | ||
625 | |||
626 | value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS); | ||
627 | value |= CURSOR_ENABLE; | ||
628 | tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS); | ||
629 | |||
630 | value = tegra_dc_readl(dc, DC_DISP_BLEND_CURSOR_CONTROL); | ||
631 | value &= ~CURSOR_DST_BLEND_MASK; | ||
632 | value &= ~CURSOR_SRC_BLEND_MASK; | ||
633 | value |= CURSOR_MODE_NORMAL; | ||
634 | value |= CURSOR_DST_BLEND_NEG_K1_TIMES_SRC; | ||
635 | value |= CURSOR_SRC_BLEND_K1_TIMES_SRC; | ||
636 | value |= CURSOR_ALPHA; | ||
637 | tegra_dc_writel(dc, value, DC_DISP_BLEND_CURSOR_CONTROL); | ||
638 | } else { | ||
639 | value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS); | ||
640 | value &= ~CURSOR_ENABLE; | ||
641 | tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS); | ||
642 | } | ||
643 | |||
644 | tegra_dc_cursor_commit(dc); | ||
645 | tegra_dc_commit(dc); | ||
646 | |||
647 | return 0; | ||
648 | } | ||
649 | |||
650 | static int tegra_dc_cursor_move(struct drm_crtc *crtc, int x, int y) | ||
651 | { | ||
652 | struct tegra_dc *dc = to_tegra_dc(crtc); | ||
653 | unsigned long value; | ||
654 | |||
655 | if (!dc->soc->supports_cursor) | ||
656 | return -ENXIO; | ||
657 | |||
658 | value = ((y & 0x3fff) << 16) | (x & 0x3fff); | ||
659 | tegra_dc_writel(dc, value, DC_DISP_CURSOR_POSITION); | ||
660 | |||
661 | tegra_dc_cursor_commit(dc); | ||
662 | /* XXX: only required on generations earlier than Tegra124? */ | ||
663 | tegra_dc_commit(dc); | ||
664 | |||
665 | return 0; | ||
666 | } | ||
667 | |||
668 | static void tegra_dc_finish_page_flip(struct tegra_dc *dc) | 808 | static void tegra_dc_finish_page_flip(struct tegra_dc *dc) |
669 | { | 809 | { |
670 | struct drm_device *drm = dc->base.dev; | 810 | struct drm_device *drm = dc->base.dev; |
@@ -741,8 +881,6 @@ static void tegra_dc_destroy(struct drm_crtc *crtc) | |||
741 | } | 881 | } |
742 | 882 | ||
743 | static const struct drm_crtc_funcs tegra_crtc_funcs = { | 883 | static const struct drm_crtc_funcs tegra_crtc_funcs = { |
744 | .cursor_set2 = tegra_dc_cursor_set2, | ||
745 | .cursor_move = tegra_dc_cursor_move, | ||
746 | .page_flip = tegra_dc_page_flip, | 884 | .page_flip = tegra_dc_page_flip, |
747 | .set_config = drm_crtc_helper_set_config, | 885 | .set_config = drm_crtc_helper_set_config, |
748 | .destroy = tegra_dc_destroy, | 886 | .destroy = tegra_dc_destroy, |
@@ -756,7 +894,7 @@ static void tegra_crtc_disable(struct drm_crtc *crtc) | |||
756 | 894 | ||
757 | drm_for_each_legacy_plane(plane, &drm->mode_config.plane_list) { | 895 | drm_for_each_legacy_plane(plane, &drm->mode_config.plane_list) { |
758 | if (plane->crtc == crtc) { | 896 | if (plane->crtc == crtc) { |
759 | tegra_plane_disable(plane); | 897 | tegra_window_plane_disable(plane); |
760 | plane->crtc = NULL; | 898 | plane->crtc = NULL; |
761 | 899 | ||
762 | if (plane->fb) { | 900 | if (plane->fb) { |
@@ -767,6 +905,7 @@ static void tegra_crtc_disable(struct drm_crtc *crtc) | |||
767 | } | 905 | } |
768 | 906 | ||
769 | drm_vblank_off(drm, dc->pipe); | 907 | drm_vblank_off(drm, dc->pipe); |
908 | tegra_dc_commit(dc); | ||
770 | } | 909 | } |
771 | 910 | ||
772 | static bool tegra_crtc_mode_fixup(struct drm_crtc *crtc, | 911 | static bool tegra_crtc_mode_fixup(struct drm_crtc *crtc, |
@@ -1293,6 +1432,8 @@ static int tegra_dc_init(struct host1x_client *client) | |||
1293 | struct drm_device *drm = dev_get_drvdata(client->parent); | 1432 | struct drm_device *drm = dev_get_drvdata(client->parent); |
1294 | struct tegra_dc *dc = host1x_client_to_dc(client); | 1433 | struct tegra_dc *dc = host1x_client_to_dc(client); |
1295 | struct tegra_drm *tegra = drm->dev_private; | 1434 | struct tegra_drm *tegra = drm->dev_private; |
1435 | struct drm_plane *primary = NULL; | ||
1436 | struct drm_plane *cursor = NULL; | ||
1296 | int err; | 1437 | int err; |
1297 | 1438 | ||
1298 | if (tegra->domain) { | 1439 | if (tegra->domain) { |
@@ -1306,7 +1447,25 @@ static int tegra_dc_init(struct host1x_client *client) | |||
1306 | dc->domain = tegra->domain; | 1447 | dc->domain = tegra->domain; |
1307 | } | 1448 | } |
1308 | 1449 | ||
1309 | drm_crtc_init(drm, &dc->base, &tegra_crtc_funcs); | 1450 | primary = tegra_dc_primary_plane_create(drm, dc); |
1451 | if (IS_ERR(primary)) { | ||
1452 | err = PTR_ERR(primary); | ||
1453 | goto cleanup; | ||
1454 | } | ||
1455 | |||
1456 | if (dc->soc->supports_cursor) { | ||
1457 | cursor = tegra_dc_cursor_plane_create(drm, dc); | ||
1458 | if (IS_ERR(cursor)) { | ||
1459 | err = PTR_ERR(cursor); | ||
1460 | goto cleanup; | ||
1461 | } | ||
1462 | } | ||
1463 | |||
1464 | err = drm_crtc_init_with_planes(drm, &dc->base, primary, cursor, | ||
1465 | &tegra_crtc_funcs); | ||
1466 | if (err < 0) | ||
1467 | goto cleanup; | ||
1468 | |||
1310 | drm_mode_crtc_set_gamma_size(&dc->base, 256); | 1469 | drm_mode_crtc_set_gamma_size(&dc->base, 256); |
1311 | drm_crtc_helper_add(&dc->base, &tegra_crtc_helper_funcs); | 1470 | drm_crtc_helper_add(&dc->base, &tegra_crtc_helper_funcs); |
1312 | 1471 | ||
@@ -1320,12 +1479,12 @@ static int tegra_dc_init(struct host1x_client *client) | |||
1320 | err = tegra_dc_rgb_init(drm, dc); | 1479 | err = tegra_dc_rgb_init(drm, dc); |
1321 | if (err < 0 && err != -ENODEV) { | 1480 | if (err < 0 && err != -ENODEV) { |
1322 | dev_err(dc->dev, "failed to initialize RGB output: %d\n", err); | 1481 | dev_err(dc->dev, "failed to initialize RGB output: %d\n", err); |
1323 | return err; | 1482 | goto cleanup; |
1324 | } | 1483 | } |
1325 | 1484 | ||
1326 | err = tegra_dc_add_planes(drm, dc); | 1485 | err = tegra_dc_add_planes(drm, dc); |
1327 | if (err < 0) | 1486 | if (err < 0) |
1328 | return err; | 1487 | goto cleanup; |
1329 | 1488 | ||
1330 | if (IS_ENABLED(CONFIG_DEBUG_FS)) { | 1489 | if (IS_ENABLED(CONFIG_DEBUG_FS)) { |
1331 | err = tegra_dc_debugfs_init(dc, drm->primary); | 1490 | err = tegra_dc_debugfs_init(dc, drm->primary); |
@@ -1338,10 +1497,24 @@ static int tegra_dc_init(struct host1x_client *client) | |||
1338 | if (err < 0) { | 1497 | if (err < 0) { |
1339 | dev_err(dc->dev, "failed to request IRQ#%u: %d\n", dc->irq, | 1498 | dev_err(dc->dev, "failed to request IRQ#%u: %d\n", dc->irq, |
1340 | err); | 1499 | err); |
1341 | return err; | 1500 | goto cleanup; |
1342 | } | 1501 | } |
1343 | 1502 | ||
1344 | return 0; | 1503 | return 0; |
1504 | |||
1505 | cleanup: | ||
1506 | if (cursor) | ||
1507 | drm_plane_cleanup(cursor); | ||
1508 | |||
1509 | if (primary) | ||
1510 | drm_plane_cleanup(primary); | ||
1511 | |||
1512 | if (tegra->domain) { | ||
1513 | iommu_detach_device(tegra->domain, dc->dev); | ||
1514 | dc->domain = NULL; | ||
1515 | } | ||
1516 | |||
1517 | return err; | ||
1345 | } | 1518 | } |
1346 | 1519 | ||
1347 | static int tegra_dc_exit(struct host1x_client *client) | 1520 | static int tegra_dc_exit(struct host1x_client *client) |