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 | |
| 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>
| -rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_connector.c | 33 | ||||
| -rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_fimd.c | 131 | ||||
| -rw-r--r-- | include/drm/exynos_drm.h | 3 |
3 files changed, 70 insertions, 97 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_connector.c b/drivers/gpu/drm/exynos/exynos_drm_connector.c index de7c7b294d2c..e082efb2fece 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_connector.c +++ b/drivers/gpu/drm/exynos/exynos_drm_connector.c | |||
| @@ -29,35 +29,6 @@ struct exynos_drm_connector { | |||
| 29 | uint32_t dpms; | 29 | uint32_t dpms; |
| 30 | }; | 30 | }; |
| 31 | 31 | ||
| 32 | /* convert exynos_video_timings to drm_display_mode */ | ||
| 33 | static inline void | ||
| 34 | convert_to_display_mode(struct drm_display_mode *mode, | ||
| 35 | struct exynos_drm_panel_info *panel) | ||
| 36 | { | ||
| 37 | struct fb_videomode *timing = &panel->timing; | ||
| 38 | |||
| 39 | mode->clock = timing->pixclock / 1000; | ||
| 40 | mode->vrefresh = timing->refresh; | ||
| 41 | |||
| 42 | mode->hdisplay = timing->xres; | ||
| 43 | mode->hsync_start = mode->hdisplay + timing->right_margin; | ||
| 44 | mode->hsync_end = mode->hsync_start + timing->hsync_len; | ||
| 45 | mode->htotal = mode->hsync_end + timing->left_margin; | ||
| 46 | |||
| 47 | mode->vdisplay = timing->yres; | ||
| 48 | mode->vsync_start = mode->vdisplay + timing->lower_margin; | ||
| 49 | mode->vsync_end = mode->vsync_start + timing->vsync_len; | ||
| 50 | mode->vtotal = mode->vsync_end + timing->upper_margin; | ||
| 51 | mode->width_mm = panel->width_mm; | ||
| 52 | mode->height_mm = panel->height_mm; | ||
| 53 | |||
| 54 | if (timing->vmode & FB_VMODE_INTERLACED) | ||
| 55 | mode->flags |= DRM_MODE_FLAG_INTERLACE; | ||
| 56 | |||
| 57 | if (timing->vmode & FB_VMODE_DOUBLE) | ||
| 58 | mode->flags |= DRM_MODE_FLAG_DBLSCAN; | ||
| 59 | } | ||
| 60 | |||
| 61 | static int exynos_drm_connector_get_modes(struct drm_connector *connector) | 32 | static int exynos_drm_connector_get_modes(struct drm_connector *connector) |
| 62 | { | 33 | { |
| 63 | struct exynos_drm_connector *exynos_connector = | 34 | struct exynos_drm_connector *exynos_connector = |
| @@ -112,7 +83,9 @@ static int exynos_drm_connector_get_modes(struct drm_connector *connector) | |||
| 112 | return 0; | 83 | return 0; |
| 113 | } | 84 | } |
| 114 | 85 | ||
| 115 | convert_to_display_mode(mode, panel); | 86 | drm_display_mode_from_videomode(&panel->vm, mode); |
| 87 | mode->width_mm = panel->width_mm; | ||
| 88 | mode->height_mm = panel->height_mm; | ||
| 116 | connector->display_info.width_mm = mode->width_mm; | 89 | connector->display_info.width_mm = mode->width_mm; |
| 117 | connector->display_info.height_mm = mode->height_mm; | 90 | connector->display_info.height_mm = mode->height_mm; |
| 118 | 91 | ||
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 | ||
diff --git a/include/drm/exynos_drm.h b/include/drm/exynos_drm.h index d6aeaf3c6d6c..cb65fa14acfc 100644 --- a/include/drm/exynos_drm.h +++ b/include/drm/exynos_drm.h | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #define _EXYNOS_DRM_H_ | 15 | #define _EXYNOS_DRM_H_ |
| 16 | 16 | ||
| 17 | #include <uapi/drm/exynos_drm.h> | 17 | #include <uapi/drm/exynos_drm.h> |
| 18 | #include <video/videomode.h> | ||
| 18 | 19 | ||
| 19 | /** | 20 | /** |
| 20 | * A structure for lcd panel information. | 21 | * A structure for lcd panel information. |
| @@ -24,7 +25,7 @@ | |||
| 24 | * @height_mm: physical size of lcd height. | 25 | * @height_mm: physical size of lcd height. |
| 25 | */ | 26 | */ |
| 26 | struct exynos_drm_panel_info { | 27 | struct exynos_drm_panel_info { |
| 27 | struct fb_videomode timing; | 28 | struct videomode vm; |
| 28 | u32 width_mm; | 29 | u32 width_mm; |
| 29 | u32 height_mm; | 30 | u32 height_mm; |
| 30 | }; | 31 | }; |
