diff options
Diffstat (limited to 'drivers/gpu/drm/exynos/exynos7_drm_decon.c')
-rw-r--r-- | drivers/gpu/drm/exynos/exynos7_drm_decon.c | 173 |
1 files changed, 34 insertions, 139 deletions
diff --git a/drivers/gpu/drm/exynos/exynos7_drm_decon.c b/drivers/gpu/drm/exynos/exynos7_drm_decon.c index 6714e5b193ea..362532afd1a5 100644 --- a/drivers/gpu/drm/exynos/exynos7_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos7_drm_decon.c | |||
@@ -89,8 +89,9 @@ static void decon_wait_for_vblank(struct exynos_drm_crtc *crtc) | |||
89 | DRM_DEBUG_KMS("vblank wait timed out.\n"); | 89 | DRM_DEBUG_KMS("vblank wait timed out.\n"); |
90 | } | 90 | } |
91 | 91 | ||
92 | static void decon_clear_channel(struct decon_context *ctx) | 92 | static void decon_clear_channels(struct exynos_drm_crtc *crtc) |
93 | { | 93 | { |
94 | struct decon_context *ctx = crtc->ctx; | ||
94 | unsigned int win, ch_enabled = 0; | 95 | unsigned int win, ch_enabled = 0; |
95 | 96 | ||
96 | DRM_DEBUG_KMS("%s\n", __FILE__); | 97 | DRM_DEBUG_KMS("%s\n", __FILE__); |
@@ -120,27 +121,16 @@ static int decon_ctx_initialize(struct decon_context *ctx, | |||
120 | struct drm_device *drm_dev) | 121 | struct drm_device *drm_dev) |
121 | { | 122 | { |
122 | struct exynos_drm_private *priv = drm_dev->dev_private; | 123 | struct exynos_drm_private *priv = drm_dev->dev_private; |
124 | int ret; | ||
123 | 125 | ||
124 | ctx->drm_dev = drm_dev; | 126 | ctx->drm_dev = drm_dev; |
125 | ctx->pipe = priv->pipe++; | 127 | ctx->pipe = priv->pipe++; |
126 | 128 | ||
127 | /* attach this sub driver to iommu mapping if supported. */ | 129 | ret = drm_iommu_attach_device_if_possible(ctx->crtc, drm_dev, ctx->dev); |
128 | if (is_drm_iommu_supported(ctx->drm_dev)) { | 130 | if (ret) |
129 | int ret; | 131 | priv->pipe--; |
130 | |||
131 | /* | ||
132 | * If any channel is already active, iommu will throw | ||
133 | * a PAGE FAULT when enabled. So clear any channel if enabled. | ||
134 | */ | ||
135 | decon_clear_channel(ctx); | ||
136 | ret = drm_iommu_attach_device(ctx->drm_dev, ctx->dev); | ||
137 | if (ret) { | ||
138 | DRM_ERROR("drm_iommu_attach failed.\n"); | ||
139 | return ret; | ||
140 | } | ||
141 | } | ||
142 | 132 | ||
143 | return 0; | 133 | return ret; |
144 | } | 134 | } |
145 | 135 | ||
146 | static void decon_ctx_remove(struct decon_context *ctx) | 136 | static void decon_ctx_remove(struct decon_context *ctx) |
@@ -175,7 +165,7 @@ static bool decon_mode_fixup(struct exynos_drm_crtc *crtc, | |||
175 | static void decon_commit(struct exynos_drm_crtc *crtc) | 165 | static void decon_commit(struct exynos_drm_crtc *crtc) |
176 | { | 166 | { |
177 | struct decon_context *ctx = crtc->ctx; | 167 | struct decon_context *ctx = crtc->ctx; |
178 | struct drm_display_mode *mode = &crtc->base.mode; | 168 | struct drm_display_mode *mode = &crtc->base.state->adjusted_mode; |
179 | u32 val, clkdiv; | 169 | u32 val, clkdiv; |
180 | 170 | ||
181 | if (ctx->suspended) | 171 | if (ctx->suspended) |
@@ -395,7 +385,7 @@ static void decon_shadow_protect_win(struct decon_context *ctx, | |||
395 | static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) | 385 | static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) |
396 | { | 386 | { |
397 | struct decon_context *ctx = crtc->ctx; | 387 | struct decon_context *ctx = crtc->ctx; |
398 | struct drm_display_mode *mode = &crtc->base.mode; | 388 | struct drm_display_mode *mode = &crtc->base.state->adjusted_mode; |
399 | struct exynos_drm_plane *plane; | 389 | struct exynos_drm_plane *plane; |
400 | int padding; | 390 | int padding; |
401 | unsigned long val, alpha; | 391 | unsigned long val, alpha; |
@@ -410,11 +400,8 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) | |||
410 | 400 | ||
411 | plane = &ctx->planes[win]; | 401 | plane = &ctx->planes[win]; |
412 | 402 | ||
413 | /* If suspended, enable this on resume */ | 403 | if (ctx->suspended) |
414 | if (ctx->suspended) { | ||
415 | plane->resume = true; | ||
416 | return; | 404 | return; |
417 | } | ||
418 | 405 | ||
419 | /* | 406 | /* |
420 | * SHADOWCON/PRTCON register is used for enabling timing. | 407 | * SHADOWCON/PRTCON register is used for enabling timing. |
@@ -506,8 +493,6 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) | |||
506 | val = readl(ctx->regs + DECON_UPDATE); | 493 | val = readl(ctx->regs + DECON_UPDATE); |
507 | val |= DECON_UPDATE_STANDALONE_F; | 494 | val |= DECON_UPDATE_STANDALONE_F; |
508 | writel(val, ctx->regs + DECON_UPDATE); | 495 | writel(val, ctx->regs + DECON_UPDATE); |
509 | |||
510 | plane->enabled = true; | ||
511 | } | 496 | } |
512 | 497 | ||
513 | static void decon_win_disable(struct exynos_drm_crtc *crtc, unsigned int win) | 498 | static void decon_win_disable(struct exynos_drm_crtc *crtc, unsigned int win) |
@@ -521,11 +506,8 @@ static void decon_win_disable(struct exynos_drm_crtc *crtc, unsigned int win) | |||
521 | 506 | ||
522 | plane = &ctx->planes[win]; | 507 | plane = &ctx->planes[win]; |
523 | 508 | ||
524 | if (ctx->suspended) { | 509 | if (ctx->suspended) |
525 | /* do not resume this window*/ | ||
526 | plane->resume = false; | ||
527 | return; | 510 | return; |
528 | } | ||
529 | 511 | ||
530 | /* protect windows */ | 512 | /* protect windows */ |
531 | decon_shadow_protect_win(ctx, win, true); | 513 | decon_shadow_protect_win(ctx, win, true); |
@@ -541,49 +523,6 @@ static void decon_win_disable(struct exynos_drm_crtc *crtc, unsigned int win) | |||
541 | val = readl(ctx->regs + DECON_UPDATE); | 523 | val = readl(ctx->regs + DECON_UPDATE); |
542 | val |= DECON_UPDATE_STANDALONE_F; | 524 | val |= DECON_UPDATE_STANDALONE_F; |
543 | writel(val, ctx->regs + DECON_UPDATE); | 525 | writel(val, ctx->regs + DECON_UPDATE); |
544 | |||
545 | plane->enabled = false; | ||
546 | } | ||
547 | |||
548 | static void decon_window_suspend(struct decon_context *ctx) | ||
549 | { | ||
550 | struct exynos_drm_plane *plane; | ||
551 | int i; | ||
552 | |||
553 | for (i = 0; i < WINDOWS_NR; i++) { | ||
554 | plane = &ctx->planes[i]; | ||
555 | plane->resume = plane->enabled; | ||
556 | if (plane->enabled) | ||
557 | decon_win_disable(ctx->crtc, i); | ||
558 | } | ||
559 | } | ||
560 | |||
561 | static void decon_window_resume(struct decon_context *ctx) | ||
562 | { | ||
563 | struct exynos_drm_plane *plane; | ||
564 | int i; | ||
565 | |||
566 | for (i = 0; i < WINDOWS_NR; i++) { | ||
567 | plane = &ctx->planes[i]; | ||
568 | plane->enabled = plane->resume; | ||
569 | plane->resume = false; | ||
570 | } | ||
571 | } | ||
572 | |||
573 | static void decon_apply(struct decon_context *ctx) | ||
574 | { | ||
575 | struct exynos_drm_plane *plane; | ||
576 | int i; | ||
577 | |||
578 | for (i = 0; i < WINDOWS_NR; i++) { | ||
579 | plane = &ctx->planes[i]; | ||
580 | if (plane->enabled) | ||
581 | decon_win_commit(ctx->crtc, i); | ||
582 | else | ||
583 | decon_win_disable(ctx->crtc, i); | ||
584 | } | ||
585 | |||
586 | decon_commit(ctx->crtc); | ||
587 | } | 526 | } |
588 | 527 | ||
589 | static void decon_init(struct decon_context *ctx) | 528 | static void decon_init(struct decon_context *ctx) |
@@ -603,12 +542,13 @@ static void decon_init(struct decon_context *ctx) | |||
603 | writel(VIDCON1_VCLK_HOLD, ctx->regs + VIDCON1(0)); | 542 | writel(VIDCON1_VCLK_HOLD, ctx->regs + VIDCON1(0)); |
604 | } | 543 | } |
605 | 544 | ||
606 | static int decon_poweron(struct decon_context *ctx) | 545 | static void decon_enable(struct exynos_drm_crtc *crtc) |
607 | { | 546 | { |
547 | struct decon_context *ctx = crtc->ctx; | ||
608 | int ret; | 548 | int ret; |
609 | 549 | ||
610 | if (!ctx->suspended) | 550 | if (!ctx->suspended) |
611 | return 0; | 551 | return; |
612 | 552 | ||
613 | ctx->suspended = false; | 553 | ctx->suspended = false; |
614 | 554 | ||
@@ -617,68 +557,51 @@ static int decon_poweron(struct decon_context *ctx) | |||
617 | ret = clk_prepare_enable(ctx->pclk); | 557 | ret = clk_prepare_enable(ctx->pclk); |
618 | if (ret < 0) { | 558 | if (ret < 0) { |
619 | DRM_ERROR("Failed to prepare_enable the pclk [%d]\n", ret); | 559 | DRM_ERROR("Failed to prepare_enable the pclk [%d]\n", ret); |
620 | goto pclk_err; | 560 | return; |
621 | } | 561 | } |
622 | 562 | ||
623 | ret = clk_prepare_enable(ctx->aclk); | 563 | ret = clk_prepare_enable(ctx->aclk); |
624 | if (ret < 0) { | 564 | if (ret < 0) { |
625 | DRM_ERROR("Failed to prepare_enable the aclk [%d]\n", ret); | 565 | DRM_ERROR("Failed to prepare_enable the aclk [%d]\n", ret); |
626 | goto aclk_err; | 566 | return; |
627 | } | 567 | } |
628 | 568 | ||
629 | ret = clk_prepare_enable(ctx->eclk); | 569 | ret = clk_prepare_enable(ctx->eclk); |
630 | if (ret < 0) { | 570 | if (ret < 0) { |
631 | DRM_ERROR("Failed to prepare_enable the eclk [%d]\n", ret); | 571 | DRM_ERROR("Failed to prepare_enable the eclk [%d]\n", ret); |
632 | goto eclk_err; | 572 | return; |
633 | } | 573 | } |
634 | 574 | ||
635 | ret = clk_prepare_enable(ctx->vclk); | 575 | ret = clk_prepare_enable(ctx->vclk); |
636 | if (ret < 0) { | 576 | if (ret < 0) { |
637 | DRM_ERROR("Failed to prepare_enable the vclk [%d]\n", ret); | 577 | DRM_ERROR("Failed to prepare_enable the vclk [%d]\n", ret); |
638 | goto vclk_err; | 578 | return; |
639 | } | 579 | } |
640 | 580 | ||
641 | decon_init(ctx); | 581 | decon_init(ctx); |
642 | 582 | ||
643 | /* if vblank was enabled status, enable it again. */ | 583 | /* if vblank was enabled status, enable it again. */ |
644 | if (test_and_clear_bit(0, &ctx->irq_flags)) { | 584 | if (test_and_clear_bit(0, &ctx->irq_flags)) |
645 | ret = decon_enable_vblank(ctx->crtc); | 585 | decon_enable_vblank(ctx->crtc); |
646 | if (ret) { | ||
647 | DRM_ERROR("Failed to re-enable vblank [%d]\n", ret); | ||
648 | goto err; | ||
649 | } | ||
650 | } | ||
651 | |||
652 | decon_window_resume(ctx); | ||
653 | |||
654 | decon_apply(ctx); | ||
655 | 586 | ||
656 | return 0; | 587 | decon_commit(ctx->crtc); |
657 | |||
658 | err: | ||
659 | clk_disable_unprepare(ctx->vclk); | ||
660 | vclk_err: | ||
661 | clk_disable_unprepare(ctx->eclk); | ||
662 | eclk_err: | ||
663 | clk_disable_unprepare(ctx->aclk); | ||
664 | aclk_err: | ||
665 | clk_disable_unprepare(ctx->pclk); | ||
666 | pclk_err: | ||
667 | ctx->suspended = true; | ||
668 | return ret; | ||
669 | } | 588 | } |
670 | 589 | ||
671 | static int decon_poweroff(struct decon_context *ctx) | 590 | static void decon_disable(struct exynos_drm_crtc *crtc) |
672 | { | 591 | { |
592 | struct decon_context *ctx = crtc->ctx; | ||
593 | int i; | ||
594 | |||
673 | if (ctx->suspended) | 595 | if (ctx->suspended) |
674 | return 0; | 596 | return; |
675 | 597 | ||
676 | /* | 598 | /* |
677 | * We need to make sure that all windows are disabled before we | 599 | * We need to make sure that all windows are disabled before we |
678 | * suspend that connector. Otherwise we might try to scan from | 600 | * suspend that connector. Otherwise we might try to scan from |
679 | * a destroyed buffer later. | 601 | * a destroyed buffer later. |
680 | */ | 602 | */ |
681 | decon_window_suspend(ctx); | 603 | for (i = 0; i < WINDOWS_NR; i++) |
604 | decon_win_disable(crtc, i); | ||
682 | 605 | ||
683 | clk_disable_unprepare(ctx->vclk); | 606 | clk_disable_unprepare(ctx->vclk); |
684 | clk_disable_unprepare(ctx->eclk); | 607 | clk_disable_unprepare(ctx->eclk); |
@@ -688,30 +611,11 @@ static int decon_poweroff(struct decon_context *ctx) | |||
688 | pm_runtime_put_sync(ctx->dev); | 611 | pm_runtime_put_sync(ctx->dev); |
689 | 612 | ||
690 | ctx->suspended = true; | 613 | ctx->suspended = true; |
691 | return 0; | ||
692 | } | ||
693 | |||
694 | static void decon_dpms(struct exynos_drm_crtc *crtc, int mode) | ||
695 | { | ||
696 | DRM_DEBUG_KMS("%s, %d\n", __FILE__, mode); | ||
697 | |||
698 | switch (mode) { | ||
699 | case DRM_MODE_DPMS_ON: | ||
700 | decon_poweron(crtc->ctx); | ||
701 | break; | ||
702 | case DRM_MODE_DPMS_STANDBY: | ||
703 | case DRM_MODE_DPMS_SUSPEND: | ||
704 | case DRM_MODE_DPMS_OFF: | ||
705 | decon_poweroff(crtc->ctx); | ||
706 | break; | ||
707 | default: | ||
708 | DRM_DEBUG_KMS("unspecified mode %d\n", mode); | ||
709 | break; | ||
710 | } | ||
711 | } | 614 | } |
712 | 615 | ||
713 | static const struct exynos_drm_crtc_ops decon_crtc_ops = { | 616 | static const struct exynos_drm_crtc_ops decon_crtc_ops = { |
714 | .dpms = decon_dpms, | 617 | .enable = decon_enable, |
618 | .disable = decon_disable, | ||
715 | .mode_fixup = decon_mode_fixup, | 619 | .mode_fixup = decon_mode_fixup, |
716 | .commit = decon_commit, | 620 | .commit = decon_commit, |
717 | .enable_vblank = decon_enable_vblank, | 621 | .enable_vblank = decon_enable_vblank, |
@@ -719,6 +623,7 @@ static const struct exynos_drm_crtc_ops decon_crtc_ops = { | |||
719 | .wait_for_vblank = decon_wait_for_vblank, | 623 | .wait_for_vblank = decon_wait_for_vblank, |
720 | .win_commit = decon_win_commit, | 624 | .win_commit = decon_win_commit, |
721 | .win_disable = decon_win_disable, | 625 | .win_disable = decon_win_disable, |
626 | .clear_channels = decon_clear_channels, | ||
722 | }; | 627 | }; |
723 | 628 | ||
724 | 629 | ||
@@ -796,7 +701,7 @@ static void decon_unbind(struct device *dev, struct device *master, | |||
796 | { | 701 | { |
797 | struct decon_context *ctx = dev_get_drvdata(dev); | 702 | struct decon_context *ctx = dev_get_drvdata(dev); |
798 | 703 | ||
799 | decon_dpms(ctx->crtc, DRM_MODE_DPMS_OFF); | 704 | decon_disable(ctx->crtc); |
800 | 705 | ||
801 | if (ctx->display) | 706 | if (ctx->display) |
802 | exynos_dpi_remove(ctx->display); | 707 | exynos_dpi_remove(ctx->display); |
@@ -824,11 +729,6 @@ static int decon_probe(struct platform_device *pdev) | |||
824 | if (!ctx) | 729 | if (!ctx) |
825 | return -ENOMEM; | 730 | return -ENOMEM; |
826 | 731 | ||
827 | ret = exynos_drm_component_add(dev, EXYNOS_DEVICE_TYPE_CRTC, | ||
828 | EXYNOS_DISPLAY_TYPE_LCD); | ||
829 | if (ret) | ||
830 | return ret; | ||
831 | |||
832 | ctx->dev = dev; | 732 | ctx->dev = dev; |
833 | ctx->suspended = true; | 733 | ctx->suspended = true; |
834 | 734 | ||
@@ -838,10 +738,8 @@ static int decon_probe(struct platform_device *pdev) | |||
838 | of_node_put(i80_if_timings); | 738 | of_node_put(i80_if_timings); |
839 | 739 | ||
840 | ctx->regs = of_iomap(dev->of_node, 0); | 740 | ctx->regs = of_iomap(dev->of_node, 0); |
841 | if (!ctx->regs) { | 741 | if (!ctx->regs) |
842 | ret = -ENOMEM; | 742 | return -ENOMEM; |
843 | goto err_del_component; | ||
844 | } | ||
845 | 743 | ||
846 | ctx->pclk = devm_clk_get(dev, "pclk_decon0"); | 744 | ctx->pclk = devm_clk_get(dev, "pclk_decon0"); |
847 | if (IS_ERR(ctx->pclk)) { | 745 | if (IS_ERR(ctx->pclk)) { |
@@ -911,8 +809,6 @@ err_disable_pm_runtime: | |||
911 | err_iounmap: | 809 | err_iounmap: |
912 | iounmap(ctx->regs); | 810 | iounmap(ctx->regs); |
913 | 811 | ||
914 | err_del_component: | ||
915 | exynos_drm_component_del(dev, EXYNOS_DEVICE_TYPE_CRTC); | ||
916 | return ret; | 812 | return ret; |
917 | } | 813 | } |
918 | 814 | ||
@@ -925,7 +821,6 @@ static int decon_remove(struct platform_device *pdev) | |||
925 | iounmap(ctx->regs); | 821 | iounmap(ctx->regs); |
926 | 822 | ||
927 | component_del(&pdev->dev, &decon_component_ops); | 823 | component_del(&pdev->dev, &decon_component_ops); |
928 | exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC); | ||
929 | 824 | ||
930 | return 0; | 825 | return 0; |
931 | } | 826 | } |