diff options
author | Andrzej Hajda <a.hajda@samsung.com> | 2013-08-21 10:22:01 -0400 |
---|---|---|
committer | Inki Dae <inki.dae@samsung.com> | 2013-09-05 00:43:44 -0400 |
commit | 111e6055d4e0d35c6a4b6cd37d7bb00a88eaffb4 (patch) | |
tree | c192757baffc958af3e2e10ca9375ae689a4a7bb /drivers/gpu/drm/exynos/exynos_drm_fimd.c | |
parent | 5cc4621a17b1e63738658a93b9a5667c876a22e4 (diff) |
drm/exynos: fimd: replace struct fb_videomode with videomode
The patch replaces all occurrences of struct fb_videomode by
more accurate struct videomode. The change allows to remove
mode conversion function and simplifies clock divider calculation.
Clock configuration is moved to separate function.
Signed-off-by: Andrzej Hajda <a.hajda@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Inki Dae <inki.dae@samsung.com>
Diffstat (limited to 'drivers/gpu/drm/exynos/exynos_drm_fimd.c')
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_fimd.c | 131 |
1 files changed, 65 insertions, 66 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index f8889d28382d..a183ea7dbd55 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/pm_runtime.h> | 21 | #include <linux/pm_runtime.h> |
22 | 22 | ||
23 | #include <video/of_display_timing.h> | 23 | #include <video/of_display_timing.h> |
24 | #include <video/of_videomode.h> | ||
24 | #include <video/samsung_fimd.h> | 25 | #include <video/samsung_fimd.h> |
25 | #include <drm/exynos_drm.h> | 26 | #include <drm/exynos_drm.h> |
26 | 27 | ||
@@ -36,6 +37,8 @@ | |||
36 | * CPU Interface. | 37 | * CPU Interface. |
37 | */ | 38 | */ |
38 | 39 | ||
40 | #define FIMD_DEFAULT_FRAMERATE 60 | ||
41 | |||
39 | /* position control register for hardware window 0, 2 ~ 4.*/ | 42 | /* position control register for hardware window 0, 2 ~ 4.*/ |
40 | #define VIDOSD_A(win) (VIDOSD_BASE + 0x00 + (win) * 16) | 43 | #define VIDOSD_A(win) (VIDOSD_BASE + 0x00 + (win) * 16) |
41 | #define VIDOSD_B(win) (VIDOSD_BASE + 0x04 + (win) * 16) | 44 | #define VIDOSD_B(win) (VIDOSD_BASE + 0x04 + (win) * 16) |
@@ -242,7 +245,7 @@ static void fimd_commit(struct device *dev) | |||
242 | { | 245 | { |
243 | struct fimd_context *ctx = get_fimd_context(dev); | 246 | struct fimd_context *ctx = get_fimd_context(dev); |
244 | struct exynos_drm_panel_info *panel = ctx->panel; | 247 | struct exynos_drm_panel_info *panel = ctx->panel; |
245 | struct fb_videomode *timing = &panel->timing; | 248 | struct videomode *vm = &panel->vm; |
246 | struct fimd_driver_data *driver_data; | 249 | struct fimd_driver_data *driver_data; |
247 | u32 val; | 250 | u32 val; |
248 | 251 | ||
@@ -254,22 +257,22 @@ static void fimd_commit(struct device *dev) | |||
254 | writel(ctx->vidcon1, ctx->regs + driver_data->timing_base + VIDCON1); | 257 | writel(ctx->vidcon1, ctx->regs + driver_data->timing_base + VIDCON1); |
255 | 258 | ||
256 | /* setup vertical timing values. */ | 259 | /* setup vertical timing values. */ |
257 | val = VIDTCON0_VBPD(timing->upper_margin - 1) | | 260 | val = VIDTCON0_VBPD(vm->vback_porch - 1) | |
258 | VIDTCON0_VFPD(timing->lower_margin - 1) | | 261 | VIDTCON0_VFPD(vm->vfront_porch - 1) | |
259 | VIDTCON0_VSPW(timing->vsync_len - 1); | 262 | VIDTCON0_VSPW(vm->vsync_len - 1); |
260 | writel(val, ctx->regs + driver_data->timing_base + VIDTCON0); | 263 | writel(val, ctx->regs + driver_data->timing_base + VIDTCON0); |
261 | 264 | ||
262 | /* setup horizontal timing values. */ | 265 | /* setup horizontal timing values. */ |
263 | val = VIDTCON1_HBPD(timing->left_margin - 1) | | 266 | val = VIDTCON1_HBPD(vm->hback_porch - 1) | |
264 | VIDTCON1_HFPD(timing->right_margin - 1) | | 267 | VIDTCON1_HFPD(vm->hfront_porch - 1) | |
265 | VIDTCON1_HSPW(timing->hsync_len - 1); | 268 | VIDTCON1_HSPW(vm->hsync_len - 1); |
266 | writel(val, ctx->regs + driver_data->timing_base + VIDTCON1); | 269 | writel(val, ctx->regs + driver_data->timing_base + VIDTCON1); |
267 | 270 | ||
268 | /* setup horizontal and vertical display size. */ | 271 | /* setup horizontal and vertical display size. */ |
269 | val = VIDTCON2_LINEVAL(timing->yres - 1) | | 272 | val = VIDTCON2_LINEVAL(vm->vactive - 1) | |
270 | VIDTCON2_HOZVAL(timing->xres - 1) | | 273 | VIDTCON2_HOZVAL(vm->hactive - 1) | |
271 | VIDTCON2_LINEVAL_E(timing->yres - 1) | | 274 | VIDTCON2_LINEVAL_E(vm->vactive - 1) | |
272 | VIDTCON2_HOZVAL_E(timing->xres - 1); | 275 | VIDTCON2_HOZVAL_E(vm->hactive - 1); |
273 | writel(val, ctx->regs + driver_data->timing_base + VIDTCON2); | 276 | writel(val, ctx->regs + driver_data->timing_base + VIDTCON2); |
274 | 277 | ||
275 | /* setup clock source, clock divider, enable dma. */ | 278 | /* setup clock source, clock divider, enable dma. */ |
@@ -750,45 +753,54 @@ static void fimd_subdrv_remove(struct drm_device *drm_dev, struct device *dev) | |||
750 | drm_iommu_detach_device(drm_dev, dev); | 753 | drm_iommu_detach_device(drm_dev, dev); |
751 | } | 754 | } |
752 | 755 | ||
753 | static int fimd_calc_clkdiv(struct fimd_context *ctx, | 756 | static int fimd_configure_clocks(struct fimd_context *ctx, struct device *dev) |
754 | struct fb_videomode *timing) | ||
755 | { | 757 | { |
756 | unsigned long clk = clk_get_rate(ctx->lcd_clk); | 758 | struct videomode *vm = &ctx->panel->vm; |
757 | u32 retrace; | 759 | unsigned long clk; |
758 | u32 clkdiv; | 760 | |
759 | u32 best_framerate = 0; | 761 | ctx->bus_clk = devm_clk_get(dev, "fimd"); |
760 | u32 framerate; | 762 | if (IS_ERR(ctx->bus_clk)) { |
761 | 763 | dev_err(dev, "failed to get bus clock\n"); | |
762 | retrace = timing->left_margin + timing->hsync_len + | 764 | return PTR_ERR(ctx->bus_clk); |
763 | timing->right_margin + timing->xres; | 765 | } |
764 | retrace *= timing->upper_margin + timing->vsync_len + | 766 | |
765 | timing->lower_margin + timing->yres; | 767 | ctx->lcd_clk = devm_clk_get(dev, "sclk_fimd"); |
766 | 768 | if (IS_ERR(ctx->lcd_clk)) { | |
767 | /* default framerate is 60Hz */ | 769 | dev_err(dev, "failed to get lcd clock\n"); |
768 | if (!timing->refresh) | 770 | return PTR_ERR(ctx->lcd_clk); |
769 | timing->refresh = 60; | 771 | } |
770 | 772 | ||
771 | clk /= retrace; | 773 | clk = clk_get_rate(ctx->lcd_clk); |
772 | 774 | if (clk == 0) { | |
773 | for (clkdiv = 1; clkdiv < 0x100; clkdiv++) { | 775 | dev_err(dev, "error getting sclk_fimd clock rate\n"); |
774 | int tmp; | 776 | return -EINVAL; |
775 | 777 | } | |
776 | /* get best framerate */ | 778 | |
777 | framerate = clk / clkdiv; | 779 | if (vm->pixelclock == 0) { |
778 | tmp = timing->refresh - framerate; | 780 | unsigned long c; |
779 | if (tmp < 0) { | 781 | c = vm->hactive + vm->hback_porch + vm->hfront_porch + |
780 | best_framerate = framerate; | 782 | vm->hsync_len; |
781 | continue; | 783 | c *= vm->vactive + vm->vback_porch + vm->vfront_porch + |
782 | } else { | 784 | vm->vsync_len; |
783 | if (!best_framerate) | 785 | vm->pixelclock = c * FIMD_DEFAULT_FRAMERATE; |
784 | best_framerate = framerate; | 786 | if (vm->pixelclock == 0) { |
785 | else if (tmp < (best_framerate - framerate)) | 787 | dev_err(dev, "incorrect display timings\n"); |
786 | best_framerate = framerate; | 788 | return -EINVAL; |
787 | break; | ||
788 | } | 789 | } |
790 | dev_warn(dev, "pixel clock recalculated to %luHz (%dHz frame rate)\n", | ||
791 | vm->pixelclock, FIMD_DEFAULT_FRAMERATE); | ||
792 | } | ||
793 | ctx->clkdiv = DIV_ROUND_UP(clk, vm->pixelclock); | ||
794 | if (ctx->clkdiv > 256) { | ||
795 | dev_warn(dev, "calculated pixel clock divider too high (%u), lowered to 256\n", | ||
796 | ctx->clkdiv); | ||
797 | ctx->clkdiv = 256; | ||
789 | } | 798 | } |
799 | vm->pixelclock = clk / ctx->clkdiv; | ||
800 | DRM_DEBUG_KMS("pixel clock = %lu, clkdiv = %d\n", vm->pixelclock, | ||
801 | ctx->clkdiv); | ||
790 | 802 | ||
791 | return clkdiv; | 803 | return 0; |
792 | } | 804 | } |
793 | 805 | ||
794 | static void fimd_clear_win(struct fimd_context *ctx, int win) | 806 | static void fimd_clear_win(struct fimd_context *ctx, int win) |
@@ -892,14 +904,15 @@ static int fimd_probe(struct platform_device *pdev) | |||
892 | int ret = -EINVAL; | 904 | int ret = -EINVAL; |
893 | 905 | ||
894 | if (dev->of_node) { | 906 | if (dev->of_node) { |
907 | struct videomode *vm; | ||
895 | pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); | 908 | pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); |
896 | if (!pdata) | 909 | if (!pdata) |
897 | return -ENOMEM; | 910 | return -ENOMEM; |
898 | 911 | ||
899 | ret = of_get_fb_videomode(dev->of_node, &pdata->panel.timing, | 912 | vm = &pdata->panel.vm; |
900 | OF_USE_NATIVE_MODE); | 913 | ret = of_get_videomode(dev->of_node, vm, OF_USE_NATIVE_MODE); |
901 | if (ret) { | 914 | if (ret) { |
902 | DRM_ERROR("failed: of_get_fb_videomode() : %d\n", ret); | 915 | DRM_ERROR("failed: of_get_videomode() : %d\n", ret); |
903 | return ret; | 916 | return ret; |
904 | } | 917 | } |
905 | } else { | 918 | } else { |
@@ -920,17 +933,9 @@ static int fimd_probe(struct platform_device *pdev) | |||
920 | if (!ctx) | 933 | if (!ctx) |
921 | return -ENOMEM; | 934 | return -ENOMEM; |
922 | 935 | ||
923 | ctx->bus_clk = devm_clk_get(dev, "fimd"); | 936 | ret = fimd_configure_clocks(ctx, dev); |
924 | if (IS_ERR(ctx->bus_clk)) { | 937 | if (ret) |
925 | dev_err(dev, "failed to get bus clock\n"); | 938 | return ret; |
926 | return PTR_ERR(ctx->bus_clk); | ||
927 | } | ||
928 | |||
929 | ctx->lcd_clk = devm_clk_get(dev, "sclk_fimd"); | ||
930 | if (IS_ERR(ctx->lcd_clk)) { | ||
931 | dev_err(dev, "failed to get lcd clock\n"); | ||
932 | return PTR_ERR(ctx->lcd_clk); | ||
933 | } | ||
934 | 939 | ||
935 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 940 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
936 | 941 | ||
@@ -975,12 +980,6 @@ static int fimd_probe(struct platform_device *pdev) | |||
975 | pm_runtime_enable(dev); | 980 | pm_runtime_enable(dev); |
976 | pm_runtime_get_sync(dev); | 981 | pm_runtime_get_sync(dev); |
977 | 982 | ||
978 | ctx->clkdiv = fimd_calc_clkdiv(ctx, &panel->timing); | ||
979 | panel->timing.pixclock = clk_get_rate(ctx->lcd_clk) / ctx->clkdiv; | ||
980 | |||
981 | DRM_DEBUG_KMS("pixel clock = %d, clkdiv = %d\n", | ||
982 | panel->timing.pixclock, ctx->clkdiv); | ||
983 | |||
984 | for (win = 0; win < WINDOWS_NR; win++) | 983 | for (win = 0; win < WINDOWS_NR; win++) |
985 | fimd_clear_win(ctx, win); | 984 | fimd_clear_win(ctx, win); |
986 | 985 | ||