aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/tegra/dc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/tegra/dc.c')
-rw-r--r--drivers/gpu/drm/tegra/dc.c596
1 files changed, 416 insertions, 180 deletions
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
index 054a79f143ae..3367960286a6 100644
--- a/drivers/gpu/drm/tegra/dc.c
+++ b/drivers/gpu/drm/tegra/dc.c
@@ -9,17 +9,23 @@
9 9
10#include <linux/clk.h> 10#include <linux/clk.h>
11#include <linux/debugfs.h> 11#include <linux/debugfs.h>
12#include <linux/iommu.h>
12#include <linux/reset.h> 13#include <linux/reset.h>
13 14
15#include <soc/tegra/pmc.h>
16
14#include "dc.h" 17#include "dc.h"
15#include "drm.h" 18#include "drm.h"
16#include "gem.h" 19#include "gem.h"
17 20
21#include <drm/drm_plane_helper.h>
22
18struct tegra_dc_soc_info { 23struct tegra_dc_soc_info {
19 bool supports_interlacing; 24 bool supports_interlacing;
20 bool supports_cursor; 25 bool supports_cursor;
21 bool supports_block_linear; 26 bool supports_block_linear;
22 unsigned int pitch_align; 27 unsigned int pitch_align;
28 bool has_powergate;
23}; 29};
24 30
25struct tegra_plane { 31struct tegra_plane {
@@ -32,6 +38,26 @@ static inline struct tegra_plane *to_tegra_plane(struct drm_plane *plane)
32 return container_of(plane, struct tegra_plane, base); 38 return container_of(plane, struct tegra_plane, base);
33} 39}
34 40
41static void tegra_dc_window_commit(struct tegra_dc *dc, unsigned int index)
42{
43 u32 value = WIN_A_ACT_REQ << index;
44
45 tegra_dc_writel(dc, value << 8, DC_CMD_STATE_CONTROL);
46 tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL);
47}
48
49static void tegra_dc_cursor_commit(struct tegra_dc *dc)
50{
51 tegra_dc_writel(dc, CURSOR_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
52 tegra_dc_writel(dc, CURSOR_ACT_REQ, DC_CMD_STATE_CONTROL);
53}
54
55static void tegra_dc_commit(struct tegra_dc *dc)
56{
57 tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
58 tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
59}
60
35static unsigned int tegra_dc_format(uint32_t format, uint32_t *swap) 61static unsigned int tegra_dc_format(uint32_t format, uint32_t *swap)
36{ 62{
37 /* assume no swapping of fetched data */ 63 /* assume no swapping of fetched data */
@@ -303,17 +329,260 @@ static int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index,
303 break; 329 break;
304 } 330 }
305 331
306 tegra_dc_writel(dc, WIN_A_UPDATE << index, DC_CMD_STATE_CONTROL); 332 tegra_dc_window_commit(dc, index);
307 tegra_dc_writel(dc, WIN_A_ACT_REQ << index, DC_CMD_STATE_CONTROL); 333
334 return 0;
335}
336
337static int tegra_window_plane_disable(struct drm_plane *plane)
338{
339 struct tegra_dc *dc = to_tegra_dc(plane->crtc);
340 struct tegra_plane *p = to_tegra_plane(plane);
341 u32 value;
342
343 if (!plane->crtc)
344 return 0;
345
346 value = WINDOW_A_SELECT << p->index;
347 tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER);
348
349 value = tegra_dc_readl(dc, DC_WIN_WIN_OPTIONS);
350 value &= ~WIN_ENABLE;
351 tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS);
352
353 tegra_dc_window_commit(dc, p->index);
354
355 return 0;
356}
357
358static void tegra_plane_destroy(struct drm_plane *plane)
359{
360 struct tegra_plane *p = to_tegra_plane(plane);
361
362 drm_plane_cleanup(plane);
363 kfree(p);
364}
365
366static const u32 tegra_primary_plane_formats[] = {
367 DRM_FORMAT_XBGR8888,
368 DRM_FORMAT_XRGB8888,
369 DRM_FORMAT_RGB565,
370};
371
372static int tegra_primary_plane_update(struct drm_plane *plane,
373 struct drm_crtc *crtc,
374 struct drm_framebuffer *fb, int crtc_x,
375 int crtc_y, unsigned int crtc_w,
376 unsigned int crtc_h, uint32_t src_x,
377 uint32_t src_y, uint32_t src_w,
378 uint32_t src_h)
379{
380 struct tegra_bo *bo = tegra_fb_get_plane(fb, 0);
381 struct tegra_plane *p = to_tegra_plane(plane);
382 struct tegra_dc *dc = to_tegra_dc(crtc);
383 struct tegra_dc_window window;
384 int err;
385
386 memset(&window, 0, sizeof(window));
387 window.src.x = src_x >> 16;
388 window.src.y = src_y >> 16;
389 window.src.w = src_w >> 16;
390 window.src.h = src_h >> 16;
391 window.dst.x = crtc_x;
392 window.dst.y = crtc_y;
393 window.dst.w = crtc_w;
394 window.dst.h = crtc_h;
395 window.format = tegra_dc_format(fb->pixel_format, &window.swap);
396 window.bits_per_pixel = fb->bits_per_pixel;
397 window.bottom_up = tegra_fb_is_bottom_up(fb);
398
399 err = tegra_fb_get_tiling(fb, &window.tiling);
400 if (err < 0)
401 return err;
402
403 window.base[0] = bo->paddr + fb->offsets[0];
404 window.stride[0] = fb->pitches[0];
405
406 err = tegra_dc_setup_window(dc, p->index, &window);
407 if (err < 0)
408 return err;
409
410 return 0;
411}
412
413static void tegra_primary_plane_destroy(struct drm_plane *plane)
414{
415 tegra_window_plane_disable(plane);
416 tegra_plane_destroy(plane);
417}
418
419static const struct drm_plane_funcs tegra_primary_plane_funcs = {
420 .update_plane = tegra_primary_plane_update,
421 .disable_plane = tegra_window_plane_disable,
422 .destroy = tegra_primary_plane_destroy,
423};
424
425static struct drm_plane *tegra_dc_primary_plane_create(struct drm_device *drm,
426 struct tegra_dc *dc)
427{
428 struct tegra_plane *plane;
429 unsigned int num_formats;
430 const u32 *formats;
431 int err;
432
433 plane = kzalloc(sizeof(*plane), GFP_KERNEL);
434 if (!plane)
435 return ERR_PTR(-ENOMEM);
436
437 num_formats = ARRAY_SIZE(tegra_primary_plane_formats);
438 formats = tegra_primary_plane_formats;
439
440 err = drm_universal_plane_init(drm, &plane->base, 1 << dc->pipe,
441 &tegra_primary_plane_funcs, formats,
442 num_formats, DRM_PLANE_TYPE_PRIMARY);
443 if (err < 0) {
444 kfree(plane);
445 return ERR_PTR(err);
446 }
447
448 return &plane->base;
449}
450
451static const u32 tegra_cursor_plane_formats[] = {
452 DRM_FORMAT_RGBA8888,
453};
454
455static int tegra_cursor_plane_update(struct drm_plane *plane,
456 struct drm_crtc *crtc,
457 struct drm_framebuffer *fb, int crtc_x,
458 int crtc_y, unsigned int crtc_w,
459 unsigned int crtc_h, uint32_t src_x,
460 uint32_t src_y, uint32_t src_w,
461 uint32_t src_h)
462{
463 struct tegra_bo *bo = tegra_fb_get_plane(fb, 0);
464 struct tegra_dc *dc = to_tegra_dc(crtc);
465 u32 value = CURSOR_CLIP_DISPLAY;
466
467 /* scaling not supported for cursor */
468 if ((src_w >> 16 != crtc_w) || (src_h >> 16 != crtc_h))
469 return -EINVAL;
470
471 /* only square cursors supported */
472 if (src_w != src_h)
473 return -EINVAL;
474
475 switch (crtc_w) {
476 case 32:
477 value |= CURSOR_SIZE_32x32;
478 break;
479
480 case 64:
481 value |= CURSOR_SIZE_64x64;
482 break;
483
484 case 128:
485 value |= CURSOR_SIZE_128x128;
486 break;
487
488 case 256:
489 value |= CURSOR_SIZE_256x256;
490 break;
491
492 default:
493 return -EINVAL;
494 }
495
496 value |= (bo->paddr >> 10) & 0x3fffff;
497 tegra_dc_writel(dc, value, DC_DISP_CURSOR_START_ADDR);
498
499#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
500 value = (bo->paddr >> 32) & 0x3;
501 tegra_dc_writel(dc, value, DC_DISP_CURSOR_START_ADDR_HI);
502#endif
503
504 /* enable cursor and set blend mode */
505 value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
506 value |= CURSOR_ENABLE;
507 tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
508
509 value = tegra_dc_readl(dc, DC_DISP_BLEND_CURSOR_CONTROL);
510 value &= ~CURSOR_DST_BLEND_MASK;
511 value &= ~CURSOR_SRC_BLEND_MASK;
512 value |= CURSOR_MODE_NORMAL;
513 value |= CURSOR_DST_BLEND_NEG_K1_TIMES_SRC;
514 value |= CURSOR_SRC_BLEND_K1_TIMES_SRC;
515 value |= CURSOR_ALPHA;
516 tegra_dc_writel(dc, value, DC_DISP_BLEND_CURSOR_CONTROL);
517
518 /* position the cursor */
519 value = (crtc_y & 0x3fff) << 16 | (crtc_x & 0x3fff);
520 tegra_dc_writel(dc, value, DC_DISP_CURSOR_POSITION);
521
522 /* apply changes */
523 tegra_dc_cursor_commit(dc);
524 tegra_dc_commit(dc);
525
526 return 0;
527}
528
529static int tegra_cursor_plane_disable(struct drm_plane *plane)
530{
531 struct tegra_dc *dc = to_tegra_dc(plane->crtc);
532 u32 value;
533
534 if (!plane->crtc)
535 return 0;
536
537 value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
538 value &= ~CURSOR_ENABLE;
539 tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
540
541 tegra_dc_cursor_commit(dc);
542 tegra_dc_commit(dc);
308 543
309 return 0; 544 return 0;
310} 545}
311 546
312static int tegra_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, 547static const struct drm_plane_funcs tegra_cursor_plane_funcs = {
313 struct drm_framebuffer *fb, int crtc_x, 548 .update_plane = tegra_cursor_plane_update,
314 int crtc_y, unsigned int crtc_w, 549 .disable_plane = tegra_cursor_plane_disable,
315 unsigned int crtc_h, uint32_t src_x, 550 .destroy = tegra_plane_destroy,
316 uint32_t src_y, uint32_t src_w, uint32_t src_h) 551};
552
553static struct drm_plane *tegra_dc_cursor_plane_create(struct drm_device *drm,
554 struct tegra_dc *dc)
555{
556 struct tegra_plane *plane;
557 unsigned int num_formats;
558 const u32 *formats;
559 int err;
560
561 plane = kzalloc(sizeof(*plane), GFP_KERNEL);
562 if (!plane)
563 return ERR_PTR(-ENOMEM);
564
565 num_formats = ARRAY_SIZE(tegra_cursor_plane_formats);
566 formats = tegra_cursor_plane_formats;
567
568 err = drm_universal_plane_init(drm, &plane->base, 1 << dc->pipe,
569 &tegra_cursor_plane_funcs, formats,
570 num_formats, DRM_PLANE_TYPE_CURSOR);
571 if (err < 0) {
572 kfree(plane);
573 return ERR_PTR(err);
574 }
575
576 return &plane->base;
577}
578
579static int tegra_overlay_plane_update(struct drm_plane *plane,
580 struct drm_crtc *crtc,
581 struct drm_framebuffer *fb, int crtc_x,
582 int crtc_y, unsigned int crtc_w,
583 unsigned int crtc_h, uint32_t src_x,
584 uint32_t src_y, uint32_t src_w,
585 uint32_t src_h)
317{ 586{
318 struct tegra_plane *p = to_tegra_plane(plane); 587 struct tegra_plane *p = to_tegra_plane(plane);
319 struct tegra_dc *dc = to_tegra_dc(crtc); 588 struct tegra_dc *dc = to_tegra_dc(crtc);
@@ -359,44 +628,19 @@ static int tegra_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
359 return tegra_dc_setup_window(dc, p->index, &window); 628 return tegra_dc_setup_window(dc, p->index, &window);
360} 629}
361 630
362static int tegra_plane_disable(struct drm_plane *plane) 631static void tegra_overlay_plane_destroy(struct drm_plane *plane)
363{ 632{
364 struct tegra_dc *dc = to_tegra_dc(plane->crtc); 633 tegra_window_plane_disable(plane);
365 struct tegra_plane *p = to_tegra_plane(plane); 634 tegra_plane_destroy(plane);
366 unsigned long value;
367
368 if (!plane->crtc)
369 return 0;
370
371 value = WINDOW_A_SELECT << p->index;
372 tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER);
373
374 value = tegra_dc_readl(dc, DC_WIN_WIN_OPTIONS);
375 value &= ~WIN_ENABLE;
376 tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS);
377
378 tegra_dc_writel(dc, WIN_A_UPDATE << p->index, DC_CMD_STATE_CONTROL);
379 tegra_dc_writel(dc, WIN_A_ACT_REQ << p->index, DC_CMD_STATE_CONTROL);
380
381 return 0;
382}
383
384static void tegra_plane_destroy(struct drm_plane *plane)
385{
386 struct tegra_plane *p = to_tegra_plane(plane);
387
388 tegra_plane_disable(plane);
389 drm_plane_cleanup(plane);
390 kfree(p);
391} 635}
392 636
393static const struct drm_plane_funcs tegra_plane_funcs = { 637static const struct drm_plane_funcs tegra_overlay_plane_funcs = {
394 .update_plane = tegra_plane_update, 638 .update_plane = tegra_overlay_plane_update,
395 .disable_plane = tegra_plane_disable, 639 .disable_plane = tegra_window_plane_disable,
396 .destroy = tegra_plane_destroy, 640 .destroy = tegra_overlay_plane_destroy,
397}; 641};
398 642
399static const uint32_t plane_formats[] = { 643static const uint32_t tegra_overlay_plane_formats[] = {
400 DRM_FORMAT_XBGR8888, 644 DRM_FORMAT_XBGR8888,
401 DRM_FORMAT_XRGB8888, 645 DRM_FORMAT_XRGB8888,
402 DRM_FORMAT_RGB565, 646 DRM_FORMAT_RGB565,
@@ -406,27 +650,44 @@ static const uint32_t plane_formats[] = {
406 DRM_FORMAT_YUV422, 650 DRM_FORMAT_YUV422,
407}; 651};
408 652
409static int tegra_dc_add_planes(struct drm_device *drm, struct tegra_dc *dc) 653static struct drm_plane *tegra_dc_overlay_plane_create(struct drm_device *drm,
654 struct tegra_dc *dc,
655 unsigned int index)
410{ 656{
411 unsigned int i; 657 struct tegra_plane *plane;
412 int err = 0; 658 unsigned int num_formats;
659 const u32 *formats;
660 int err;
413 661
414 for (i = 0; i < 2; i++) { 662 plane = kzalloc(sizeof(*plane), GFP_KERNEL);
415 struct tegra_plane *plane; 663 if (!plane)
664 return ERR_PTR(-ENOMEM);
416 665
417 plane = kzalloc(sizeof(*plane), GFP_KERNEL); 666 plane->index = index;
418 if (!plane)
419 return -ENOMEM;
420 667
421 plane->index = 1 + i; 668 num_formats = ARRAY_SIZE(tegra_overlay_plane_formats);
669 formats = tegra_overlay_plane_formats;
422 670
423 err = drm_plane_init(drm, &plane->base, 1 << dc->pipe, 671 err = drm_universal_plane_init(drm, &plane->base, 1 << dc->pipe,
424 &tegra_plane_funcs, plane_formats, 672 &tegra_overlay_plane_funcs, formats,
425 ARRAY_SIZE(plane_formats), false); 673 num_formats, DRM_PLANE_TYPE_OVERLAY);
426 if (err < 0) { 674 if (err < 0) {
427 kfree(plane); 675 kfree(plane);
428 return err; 676 return ERR_PTR(err);
429 } 677 }
678
679 return &plane->base;
680}
681
682static int tegra_dc_add_planes(struct drm_device *drm, struct tegra_dc *dc)
683{
684 struct drm_plane *plane;
685 unsigned int i;
686
687 for (i = 0; i < 2; i++) {
688 plane = tegra_dc_overlay_plane_create(drm, dc, 1 + i);
689 if (IS_ERR(plane))
690 return PTR_ERR(plane);
430 } 691 }
431 692
432 return 0; 693 return 0;
@@ -513,10 +774,8 @@ static int tegra_dc_set_base(struct tegra_dc *dc, int x, int y,
513 tegra_dc_writel(dc, h_offset, DC_WINBUF_ADDR_H_OFFSET); 774 tegra_dc_writel(dc, h_offset, DC_WINBUF_ADDR_H_OFFSET);
514 tegra_dc_writel(dc, v_offset, DC_WINBUF_ADDR_V_OFFSET); 775 tegra_dc_writel(dc, v_offset, DC_WINBUF_ADDR_V_OFFSET);
515 776
516 value = GENERAL_UPDATE | WIN_A_UPDATE;
517 tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL);
518
519 value = GENERAL_ACT_REQ | WIN_A_ACT_REQ; 777 value = GENERAL_ACT_REQ | WIN_A_ACT_REQ;
778 tegra_dc_writel(dc, value << 8, DC_CMD_STATE_CONTROL);
520 tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL); 779 tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL);
521 780
522 return 0; 781 return 0;
@@ -548,109 +807,6 @@ void tegra_dc_disable_vblank(struct tegra_dc *dc)
548 spin_unlock_irqrestore(&dc->lock, flags); 807 spin_unlock_irqrestore(&dc->lock, flags);
549} 808}
550 809
551static int tegra_dc_cursor_set2(struct drm_crtc *crtc, struct drm_file *file,
552 uint32_t handle, uint32_t width,
553 uint32_t height, int32_t hot_x, int32_t hot_y)
554{
555 unsigned long value = CURSOR_CLIP_DISPLAY;
556 struct tegra_dc *dc = to_tegra_dc(crtc);
557 struct drm_gem_object *gem;
558 struct tegra_bo *bo = NULL;
559
560 if (!dc->soc->supports_cursor)
561 return -ENXIO;
562
563 if (width != height)
564 return -EINVAL;
565
566 switch (width) {
567 case 32:
568 value |= CURSOR_SIZE_32x32;
569 break;
570
571 case 64:
572 value |= CURSOR_SIZE_64x64;
573 break;
574
575 case 128:
576 value |= CURSOR_SIZE_128x128;
577
578 case 256:
579 value |= CURSOR_SIZE_256x256;
580 break;
581
582 default:
583 return -EINVAL;
584 }
585
586 if (handle) {
587 gem = drm_gem_object_lookup(crtc->dev, file, handle);
588 if (!gem)
589 return -ENOENT;
590
591 bo = to_tegra_bo(gem);
592 }
593
594 if (bo) {
595 unsigned long addr = (bo->paddr & 0xfffffc00) >> 10;
596#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
597 unsigned long high = (bo->paddr & 0xfffffffc) >> 32;
598#endif
599
600 tegra_dc_writel(dc, value | addr, DC_DISP_CURSOR_START_ADDR);
601
602#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
603 tegra_dc_writel(dc, high, DC_DISP_CURSOR_START_ADDR_HI);
604#endif
605
606 value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
607 value |= CURSOR_ENABLE;
608 tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
609
610 value = tegra_dc_readl(dc, DC_DISP_BLEND_CURSOR_CONTROL);
611 value &= ~CURSOR_DST_BLEND_MASK;
612 value &= ~CURSOR_SRC_BLEND_MASK;
613 value |= CURSOR_MODE_NORMAL;
614 value |= CURSOR_DST_BLEND_NEG_K1_TIMES_SRC;
615 value |= CURSOR_SRC_BLEND_K1_TIMES_SRC;
616 value |= CURSOR_ALPHA;
617 tegra_dc_writel(dc, value, DC_DISP_BLEND_CURSOR_CONTROL);
618 } else {
619 value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
620 value &= ~CURSOR_ENABLE;
621 tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
622 }
623
624 tegra_dc_writel(dc, CURSOR_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
625 tegra_dc_writel(dc, CURSOR_ACT_REQ, DC_CMD_STATE_CONTROL);
626
627 tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
628 tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
629
630 return 0;
631}
632
633static int tegra_dc_cursor_move(struct drm_crtc *crtc, int x, int y)
634{
635 struct tegra_dc *dc = to_tegra_dc(crtc);
636 unsigned long value;
637
638 if (!dc->soc->supports_cursor)
639 return -ENXIO;
640
641 value = ((y & 0x3fff) << 16) | (x & 0x3fff);
642 tegra_dc_writel(dc, value, DC_DISP_CURSOR_POSITION);
643
644 tegra_dc_writel(dc, CURSOR_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
645 tegra_dc_writel(dc, CURSOR_ACT_REQ, DC_CMD_STATE_CONTROL);
646
647 /* XXX: only required on generations earlier than Tegra124? */
648 tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
649 tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
650
651 return 0;
652}
653
654static void tegra_dc_finish_page_flip(struct tegra_dc *dc) 810static void tegra_dc_finish_page_flip(struct tegra_dc *dc)
655{ 811{
656 struct drm_device *drm = dc->base.dev; 812 struct drm_device *drm = dc->base.dev;
@@ -727,8 +883,6 @@ static void tegra_dc_destroy(struct drm_crtc *crtc)
727} 883}
728 884
729static const struct drm_crtc_funcs tegra_crtc_funcs = { 885static const struct drm_crtc_funcs tegra_crtc_funcs = {
730 .cursor_set2 = tegra_dc_cursor_set2,
731 .cursor_move = tegra_dc_cursor_move,
732 .page_flip = tegra_dc_page_flip, 886 .page_flip = tegra_dc_page_flip,
733 .set_config = drm_crtc_helper_set_config, 887 .set_config = drm_crtc_helper_set_config,
734 .destroy = tegra_dc_destroy, 888 .destroy = tegra_dc_destroy,
@@ -736,12 +890,13 @@ static const struct drm_crtc_funcs tegra_crtc_funcs = {
736 890
737static void tegra_crtc_disable(struct drm_crtc *crtc) 891static void tegra_crtc_disable(struct drm_crtc *crtc)
738{ 892{
893 struct tegra_dc *dc = to_tegra_dc(crtc);
739 struct drm_device *drm = crtc->dev; 894 struct drm_device *drm = crtc->dev;
740 struct drm_plane *plane; 895 struct drm_plane *plane;
741 896
742 drm_for_each_legacy_plane(plane, &drm->mode_config.plane_list) { 897 drm_for_each_legacy_plane(plane, &drm->mode_config.plane_list) {
743 if (plane->crtc == crtc) { 898 if (plane->crtc == crtc) {
744 tegra_plane_disable(plane); 899 tegra_window_plane_disable(plane);
745 plane->crtc = NULL; 900 plane->crtc = NULL;
746 901
747 if (plane->fb) { 902 if (plane->fb) {
@@ -752,6 +907,7 @@ static void tegra_crtc_disable(struct drm_crtc *crtc)
752 } 907 }
753 908
754 drm_crtc_vblank_off(crtc); 909 drm_crtc_vblank_off(crtc);
910 tegra_dc_commit(dc);
755} 911}
756 912
757static bool tegra_crtc_mode_fixup(struct drm_crtc *crtc, 913static bool tegra_crtc_mode_fixup(struct drm_crtc *crtc,
@@ -934,15 +1090,9 @@ static void tegra_crtc_prepare(struct drm_crtc *crtc)
934static void tegra_crtc_commit(struct drm_crtc *crtc) 1090static void tegra_crtc_commit(struct drm_crtc *crtc)
935{ 1091{
936 struct tegra_dc *dc = to_tegra_dc(crtc); 1092 struct tegra_dc *dc = to_tegra_dc(crtc);
937 unsigned long value;
938
939 value = GENERAL_UPDATE | WIN_A_UPDATE;
940 tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL);
941
942 value = GENERAL_ACT_REQ | WIN_A_ACT_REQ;
943 tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL);
944 1093
945 drm_crtc_vblank_on(crtc); 1094 drm_crtc_vblank_on(crtc);
1095 tegra_dc_commit(dc);
946} 1096}
947 1097
948static void tegra_crtc_load_lut(struct drm_crtc *crtc) 1098static void tegra_crtc_load_lut(struct drm_crtc *crtc)
@@ -996,7 +1146,7 @@ static int tegra_dc_show_regs(struct seq_file *s, void *data)
996 struct tegra_dc *dc = node->info_ent->data; 1146 struct tegra_dc *dc = node->info_ent->data;
997 1147
998#define DUMP_REG(name) \ 1148#define DUMP_REG(name) \
999 seq_printf(s, "%-40s %#05x %08lx\n", #name, name, \ 1149 seq_printf(s, "%-40s %#05x %08x\n", #name, name, \
1000 tegra_dc_readl(dc, name)) 1150 tegra_dc_readl(dc, name))
1001 1151
1002 DUMP_REG(DC_CMD_GENERAL_INCR_SYNCPT); 1152 DUMP_REG(DC_CMD_GENERAL_INCR_SYNCPT);
@@ -1284,9 +1434,40 @@ static int tegra_dc_init(struct host1x_client *client)
1284 struct drm_device *drm = dev_get_drvdata(client->parent); 1434 struct drm_device *drm = dev_get_drvdata(client->parent);
1285 struct tegra_dc *dc = host1x_client_to_dc(client); 1435 struct tegra_dc *dc = host1x_client_to_dc(client);
1286 struct tegra_drm *tegra = drm->dev_private; 1436 struct tegra_drm *tegra = drm->dev_private;
1437 struct drm_plane *primary = NULL;
1438 struct drm_plane *cursor = NULL;
1287 int err; 1439 int err;
1288 1440
1289 drm_crtc_init(drm, &dc->base, &tegra_crtc_funcs); 1441 if (tegra->domain) {
1442 err = iommu_attach_device(tegra->domain, dc->dev);
1443 if (err < 0) {
1444 dev_err(dc->dev, "failed to attach to domain: %d\n",
1445 err);
1446 return err;
1447 }
1448
1449 dc->domain = tegra->domain;
1450 }
1451
1452 primary = tegra_dc_primary_plane_create(drm, dc);
1453 if (IS_ERR(primary)) {
1454 err = PTR_ERR(primary);
1455 goto cleanup;
1456 }
1457
1458 if (dc->soc->supports_cursor) {
1459 cursor = tegra_dc_cursor_plane_create(drm, dc);
1460 if (IS_ERR(cursor)) {
1461 err = PTR_ERR(cursor);
1462 goto cleanup;
1463 }
1464 }
1465
1466 err = drm_crtc_init_with_planes(drm, &dc->base, primary, cursor,
1467 &tegra_crtc_funcs);
1468 if (err < 0)
1469 goto cleanup;
1470
1290 drm_mode_crtc_set_gamma_size(&dc->base, 256); 1471 drm_mode_crtc_set_gamma_size(&dc->base, 256);
1291 drm_crtc_helper_add(&dc->base, &tegra_crtc_helper_funcs); 1472 drm_crtc_helper_add(&dc->base, &tegra_crtc_helper_funcs);
1292 1473
@@ -1300,12 +1481,12 @@ static int tegra_dc_init(struct host1x_client *client)
1300 err = tegra_dc_rgb_init(drm, dc); 1481 err = tegra_dc_rgb_init(drm, dc);
1301 if (err < 0 && err != -ENODEV) { 1482 if (err < 0 && err != -ENODEV) {
1302 dev_err(dc->dev, "failed to initialize RGB output: %d\n", err); 1483 dev_err(dc->dev, "failed to initialize RGB output: %d\n", err);
1303 return err; 1484 goto cleanup;
1304 } 1485 }
1305 1486
1306 err = tegra_dc_add_planes(drm, dc); 1487 err = tegra_dc_add_planes(drm, dc);
1307 if (err < 0) 1488 if (err < 0)
1308 return err; 1489 goto cleanup;
1309 1490
1310 if (IS_ENABLED(CONFIG_DEBUG_FS)) { 1491 if (IS_ENABLED(CONFIG_DEBUG_FS)) {
1311 err = tegra_dc_debugfs_init(dc, drm->primary); 1492 err = tegra_dc_debugfs_init(dc, drm->primary);
@@ -1318,10 +1499,24 @@ static int tegra_dc_init(struct host1x_client *client)
1318 if (err < 0) { 1499 if (err < 0) {
1319 dev_err(dc->dev, "failed to request IRQ#%u: %d\n", dc->irq, 1500 dev_err(dc->dev, "failed to request IRQ#%u: %d\n", dc->irq,
1320 err); 1501 err);
1321 return err; 1502 goto cleanup;
1322 } 1503 }
1323 1504
1324 return 0; 1505 return 0;
1506
1507cleanup:
1508 if (cursor)
1509 drm_plane_cleanup(cursor);
1510
1511 if (primary)
1512 drm_plane_cleanup(primary);
1513
1514 if (tegra->domain) {
1515 iommu_detach_device(tegra->domain, dc->dev);
1516 dc->domain = NULL;
1517 }
1518
1519 return err;
1325} 1520}
1326 1521
1327static int tegra_dc_exit(struct host1x_client *client) 1522static int tegra_dc_exit(struct host1x_client *client)
@@ -1343,6 +1538,11 @@ static int tegra_dc_exit(struct host1x_client *client)
1343 return err; 1538 return err;
1344 } 1539 }
1345 1540
1541 if (dc->domain) {
1542 iommu_detach_device(dc->domain, dc->dev);
1543 dc->domain = NULL;
1544 }
1545
1346 return 0; 1546 return 0;
1347} 1547}
1348 1548
@@ -1356,6 +1556,7 @@ static const struct tegra_dc_soc_info tegra20_dc_soc_info = {
1356 .supports_cursor = false, 1556 .supports_cursor = false,
1357 .supports_block_linear = false, 1557 .supports_block_linear = false,
1358 .pitch_align = 8, 1558 .pitch_align = 8,
1559 .has_powergate = false,
1359}; 1560};
1360 1561
1361static const struct tegra_dc_soc_info tegra30_dc_soc_info = { 1562static const struct tegra_dc_soc_info tegra30_dc_soc_info = {
@@ -1363,6 +1564,7 @@ static const struct tegra_dc_soc_info tegra30_dc_soc_info = {
1363 .supports_cursor = false, 1564 .supports_cursor = false,
1364 .supports_block_linear = false, 1565 .supports_block_linear = false,
1365 .pitch_align = 8, 1566 .pitch_align = 8,
1567 .has_powergate = false,
1366}; 1568};
1367 1569
1368static const struct tegra_dc_soc_info tegra114_dc_soc_info = { 1570static const struct tegra_dc_soc_info tegra114_dc_soc_info = {
@@ -1370,6 +1572,7 @@ static const struct tegra_dc_soc_info tegra114_dc_soc_info = {
1370 .supports_cursor = false, 1572 .supports_cursor = false,
1371 .supports_block_linear = false, 1573 .supports_block_linear = false,
1372 .pitch_align = 64, 1574 .pitch_align = 64,
1575 .has_powergate = true,
1373}; 1576};
1374 1577
1375static const struct tegra_dc_soc_info tegra124_dc_soc_info = { 1578static const struct tegra_dc_soc_info tegra124_dc_soc_info = {
@@ -1377,6 +1580,7 @@ static const struct tegra_dc_soc_info tegra124_dc_soc_info = {
1377 .supports_cursor = true, 1580 .supports_cursor = true,
1378 .supports_block_linear = true, 1581 .supports_block_linear = true,
1379 .pitch_align = 64, 1582 .pitch_align = 64,
1583 .has_powergate = true,
1380}; 1584};
1381 1585
1382static const struct of_device_id tegra_dc_of_match[] = { 1586static const struct of_device_id tegra_dc_of_match[] = {
@@ -1384,6 +1588,9 @@ static const struct of_device_id tegra_dc_of_match[] = {
1384 .compatible = "nvidia,tegra124-dc", 1588 .compatible = "nvidia,tegra124-dc",
1385 .data = &tegra124_dc_soc_info, 1589 .data = &tegra124_dc_soc_info,
1386 }, { 1590 }, {
1591 .compatible = "nvidia,tegra114-dc",
1592 .data = &tegra114_dc_soc_info,
1593 }, {
1387 .compatible = "nvidia,tegra30-dc", 1594 .compatible = "nvidia,tegra30-dc",
1388 .data = &tegra30_dc_soc_info, 1595 .data = &tegra30_dc_soc_info,
1389 }, { 1596 }, {
@@ -1466,9 +1673,34 @@ static int tegra_dc_probe(struct platform_device *pdev)
1466 return PTR_ERR(dc->rst); 1673 return PTR_ERR(dc->rst);
1467 } 1674 }
1468 1675
1469 err = clk_prepare_enable(dc->clk); 1676 if (dc->soc->has_powergate) {
1470 if (err < 0) 1677 if (dc->pipe == 0)
1471 return err; 1678 dc->powergate = TEGRA_POWERGATE_DIS;
1679 else
1680 dc->powergate = TEGRA_POWERGATE_DISB;
1681
1682 err = tegra_powergate_sequence_power_up(dc->powergate, dc->clk,
1683 dc->rst);
1684 if (err < 0) {
1685 dev_err(&pdev->dev, "failed to power partition: %d\n",
1686 err);
1687 return err;
1688 }
1689 } else {
1690 err = clk_prepare_enable(dc->clk);
1691 if (err < 0) {
1692 dev_err(&pdev->dev, "failed to enable clock: %d\n",
1693 err);
1694 return err;
1695 }
1696
1697 err = reset_control_deassert(dc->rst);
1698 if (err < 0) {
1699 dev_err(&pdev->dev, "failed to deassert reset: %d\n",
1700 err);
1701 return err;
1702 }
1703 }
1472 1704
1473 regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); 1705 regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1474 dc->regs = devm_ioremap_resource(&pdev->dev, regs); 1706 dc->regs = devm_ioremap_resource(&pdev->dev, regs);
@@ -1522,6 +1754,10 @@ static int tegra_dc_remove(struct platform_device *pdev)
1522 } 1754 }
1523 1755
1524 reset_control_assert(dc->rst); 1756 reset_control_assert(dc->rst);
1757
1758 if (dc->soc->has_powergate)
1759 tegra_powergate_power_off(dc->powergate);
1760
1525 clk_disable_unprepare(dc->clk); 1761 clk_disable_unprepare(dc->clk);
1526 1762
1527 return 0; 1763 return 0;