aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/exynos/exynos_drm_fimd.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/exynos/exynos_drm_fimd.c')
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fimd.c143
1 files changed, 79 insertions, 64 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index ca83139cd309..360adf2bba04 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -89,7 +89,7 @@ struct fimd_context {
89 bool suspended; 89 bool suspended;
90 struct mutex lock; 90 struct mutex lock;
91 91
92 struct fb_videomode *timing; 92 struct exynos_drm_panel_info *panel;
93}; 93};
94 94
95static bool fimd_display_is_connected(struct device *dev) 95static bool fimd_display_is_connected(struct device *dev)
@@ -101,13 +101,13 @@ static bool fimd_display_is_connected(struct device *dev)
101 return true; 101 return true;
102} 102}
103 103
104static void *fimd_get_timing(struct device *dev) 104static void *fimd_get_panel(struct device *dev)
105{ 105{
106 struct fimd_context *ctx = get_fimd_context(dev); 106 struct fimd_context *ctx = get_fimd_context(dev);
107 107
108 DRM_DEBUG_KMS("%s\n", __FILE__); 108 DRM_DEBUG_KMS("%s\n", __FILE__);
109 109
110 return ctx->timing; 110 return ctx->panel;
111} 111}
112 112
113static int fimd_check_timing(struct device *dev, void *timing) 113static int fimd_check_timing(struct device *dev, void *timing)
@@ -131,7 +131,7 @@ static int fimd_display_power_on(struct device *dev, int mode)
131static struct exynos_drm_display_ops fimd_display_ops = { 131static struct exynos_drm_display_ops fimd_display_ops = {
132 .type = EXYNOS_DISPLAY_TYPE_LCD, 132 .type = EXYNOS_DISPLAY_TYPE_LCD,
133 .is_connected = fimd_display_is_connected, 133 .is_connected = fimd_display_is_connected,
134 .get_timing = fimd_get_timing, 134 .get_panel = fimd_get_panel,
135 .check_timing = fimd_check_timing, 135 .check_timing = fimd_check_timing,
136 .power_on = fimd_display_power_on, 136 .power_on = fimd_display_power_on,
137}; 137};
@@ -158,7 +158,8 @@ static void fimd_dpms(struct device *subdrv_dev, int mode)
158 case DRM_MODE_DPMS_STANDBY: 158 case DRM_MODE_DPMS_STANDBY:
159 case DRM_MODE_DPMS_SUSPEND: 159 case DRM_MODE_DPMS_SUSPEND:
160 case DRM_MODE_DPMS_OFF: 160 case DRM_MODE_DPMS_OFF:
161 pm_runtime_put_sync(subdrv_dev); 161 if (!ctx->suspended)
162 pm_runtime_put_sync(subdrv_dev);
162 break; 163 break;
163 default: 164 default:
164 DRM_DEBUG_KMS("unspecified mode %d\n", mode); 165 DRM_DEBUG_KMS("unspecified mode %d\n", mode);
@@ -192,7 +193,8 @@ static void fimd_apply(struct device *subdrv_dev)
192static void fimd_commit(struct device *dev) 193static void fimd_commit(struct device *dev)
193{ 194{
194 struct fimd_context *ctx = get_fimd_context(dev); 195 struct fimd_context *ctx = get_fimd_context(dev);
195 struct fb_videomode *timing = ctx->timing; 196 struct exynos_drm_panel_info *panel = ctx->panel;
197 struct fb_videomode *timing = &panel->timing;
196 u32 val; 198 u32 val;
197 199
198 if (ctx->suspended) 200 if (ctx->suspended)
@@ -603,7 +605,12 @@ static void fimd_finish_pageflip(struct drm_device *drm_dev, int crtc)
603 } 605 }
604 606
605 if (is_checked) { 607 if (is_checked) {
606 drm_vblank_put(drm_dev, crtc); 608 /*
609 * call drm_vblank_put only in case that drm_vblank_get was
610 * called.
611 */
612 if (atomic_read(&drm_dev->vblank_refcount[crtc]) > 0)
613 drm_vblank_put(drm_dev, crtc);
607 614
608 /* 615 /*
609 * don't off vblank if vblank_disable_allowed is 1, 616 * don't off vblank if vblank_disable_allowed is 1,
@@ -734,13 +741,53 @@ static void fimd_clear_win(struct fimd_context *ctx, int win)
734 writel(val, ctx->regs + SHADOWCON); 741 writel(val, ctx->regs + SHADOWCON);
735} 742}
736 743
744static int fimd_power_on(struct fimd_context *ctx, bool enable)
745{
746 struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
747 struct device *dev = subdrv->manager.dev;
748
749 DRM_DEBUG_KMS("%s\n", __FILE__);
750
751 if (enable != false && enable != true)
752 return -EINVAL;
753
754 if (enable) {
755 int ret;
756
757 ret = clk_enable(ctx->bus_clk);
758 if (ret < 0)
759 return ret;
760
761 ret = clk_enable(ctx->lcd_clk);
762 if (ret < 0) {
763 clk_disable(ctx->bus_clk);
764 return ret;
765 }
766
767 ctx->suspended = false;
768
769 /* if vblank was enabled status, enable it again. */
770 if (test_and_clear_bit(0, &ctx->irq_flags))
771 fimd_enable_vblank(dev);
772
773 fimd_apply(dev);
774 } else {
775 clk_disable(ctx->lcd_clk);
776 clk_disable(ctx->bus_clk);
777
778 ctx->suspended = true;
779 }
780
781 return 0;
782}
783
737static int __devinit fimd_probe(struct platform_device *pdev) 784static int __devinit fimd_probe(struct platform_device *pdev)
738{ 785{
739 struct device *dev = &pdev->dev; 786 struct device *dev = &pdev->dev;
740 struct fimd_context *ctx; 787 struct fimd_context *ctx;
741 struct exynos_drm_subdrv *subdrv; 788 struct exynos_drm_subdrv *subdrv;
742 struct exynos_drm_fimd_pdata *pdata; 789 struct exynos_drm_fimd_pdata *pdata;
743 struct fb_videomode *timing; 790 struct exynos_drm_panel_info *panel;
744 struct resource *res; 791 struct resource *res;
745 int win; 792 int win;
746 int ret = -EINVAL; 793 int ret = -EINVAL;
@@ -753,9 +800,9 @@ static int __devinit fimd_probe(struct platform_device *pdev)
753 return -EINVAL; 800 return -EINVAL;
754 } 801 }
755 802
756 timing = &pdata->timing; 803 panel = &pdata->panel;
757 if (!timing) { 804 if (!panel) {
758 dev_err(dev, "timing is null.\n"); 805 dev_err(dev, "panel is null.\n");
759 return -EINVAL; 806 return -EINVAL;
760 } 807 }
761 808
@@ -817,16 +864,16 @@ static int __devinit fimd_probe(struct platform_device *pdev)
817 goto err_req_irq; 864 goto err_req_irq;
818 } 865 }
819 866
820 ctx->clkdiv = fimd_calc_clkdiv(ctx, timing); 867 ctx->clkdiv = fimd_calc_clkdiv(ctx, &panel->timing);
821 ctx->vidcon0 = pdata->vidcon0; 868 ctx->vidcon0 = pdata->vidcon0;
822 ctx->vidcon1 = pdata->vidcon1; 869 ctx->vidcon1 = pdata->vidcon1;
823 ctx->default_win = pdata->default_win; 870 ctx->default_win = pdata->default_win;
824 ctx->timing = timing; 871 ctx->panel = panel;
825 872
826 timing->pixclock = clk_get_rate(ctx->lcd_clk) / ctx->clkdiv; 873 panel->timing.pixclock = clk_get_rate(ctx->lcd_clk) / ctx->clkdiv;
827 874
828 DRM_DEBUG_KMS("pixel clock = %d, clkdiv = %d\n", 875 DRM_DEBUG_KMS("pixel clock = %d, clkdiv = %d\n",
829 timing->pixclock, ctx->clkdiv); 876 panel->timing.pixclock, ctx->clkdiv);
830 877
831 subdrv = &ctx->subdrv; 878 subdrv = &ctx->subdrv;
832 879
@@ -911,39 +958,30 @@ out:
911#ifdef CONFIG_PM_SLEEP 958#ifdef CONFIG_PM_SLEEP
912static int fimd_suspend(struct device *dev) 959static int fimd_suspend(struct device *dev)
913{ 960{
914 int ret; 961 struct fimd_context *ctx = get_fimd_context(dev);
915 962
916 if (pm_runtime_suspended(dev)) 963 if (pm_runtime_suspended(dev))
917 return 0; 964 return 0;
918 965
919 ret = pm_runtime_suspend(dev); 966 /*
920 if (ret < 0) 967 * do not use pm_runtime_suspend(). if pm_runtime_suspend() is
921 return ret; 968 * called here, an error would be returned by that interface
922 969 * because the usage_count of pm runtime is more than 1.
923 return 0; 970 */
971 return fimd_power_on(ctx, false);
924} 972}
925 973
926static int fimd_resume(struct device *dev) 974static int fimd_resume(struct device *dev)
927{ 975{
928 int ret; 976 struct fimd_context *ctx = get_fimd_context(dev);
929
930 ret = pm_runtime_resume(dev);
931 if (ret < 0) {
932 DRM_ERROR("failed to resume runtime pm.\n");
933 return ret;
934 }
935
936 pm_runtime_disable(dev);
937
938 ret = pm_runtime_set_active(dev);
939 if (ret < 0) {
940 DRM_ERROR("failed to active runtime pm.\n");
941 pm_runtime_enable(dev);
942 pm_runtime_suspend(dev);
943 return ret;
944 }
945 977
946 pm_runtime_enable(dev); 978 /*
979 * if entered to sleep when lcd panel was on, the usage_count
980 * of pm runtime would still be 1 so in this case, fimd driver
981 * should be on directly not drawing on pm runtime interface.
982 */
983 if (!pm_runtime_suspended(dev))
984 return fimd_power_on(ctx, true);
947 985
948 return 0; 986 return 0;
949} 987}
@@ -956,39 +994,16 @@ static int fimd_runtime_suspend(struct device *dev)
956 994
957 DRM_DEBUG_KMS("%s\n", __FILE__); 995 DRM_DEBUG_KMS("%s\n", __FILE__);
958 996
959 clk_disable(ctx->lcd_clk); 997 return fimd_power_on(ctx, false);
960 clk_disable(ctx->bus_clk);
961
962 ctx->suspended = true;
963 return 0;
964} 998}
965 999
966static int fimd_runtime_resume(struct device *dev) 1000static int fimd_runtime_resume(struct device *dev)
967{ 1001{
968 struct fimd_context *ctx = get_fimd_context(dev); 1002 struct fimd_context *ctx = get_fimd_context(dev);
969 int ret;
970 1003
971 DRM_DEBUG_KMS("%s\n", __FILE__); 1004 DRM_DEBUG_KMS("%s\n", __FILE__);
972 1005
973 ret = clk_enable(ctx->bus_clk); 1006 return fimd_power_on(ctx, true);
974 if (ret < 0)
975 return ret;
976
977 ret = clk_enable(ctx->lcd_clk);
978 if (ret < 0) {
979 clk_disable(ctx->bus_clk);
980 return ret;
981 }
982
983 ctx->suspended = false;
984
985 /* if vblank was enabled status, enable it again. */
986 if (test_and_clear_bit(0, &ctx->irq_flags))
987 fimd_enable_vblank(dev);
988
989 fimd_apply(dev);
990
991 return 0;
992} 1007}
993#endif 1008#endif
994 1009