aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSean Paul <seanpaul@chromium.org>2014-01-30 16:19:20 -0500
committerInki Dae <daeinki@gmail.com>2014-03-23 11:36:34 -0400
commita968e72771ea19aaedeeaa4ac9d8339186c302e3 (patch)
treec5206e556af52a5996a3ed10542463e05d5e0eab
parent4b4052699ae4e913c4d2b965061f10eec122e558 (diff)
drm/exynos: Use mode_set to configure fimd
This patch uses the mode passed into mode_set to configure fimd instead of directly using the panel from context. This will allow us to move the exynos_drm_display implementation out of fimd, where it doesn't belong. Signed-off-by: Sean Paul <seanpaul@chromium.org> Signed-off-by: Inki Dae <inki.dae@samsung.com>
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fimd.c143
1 files changed, 74 insertions, 69 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index dc8c5e4aa235..53d92fec665b 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -112,8 +112,8 @@ struct fimd_context {
112 struct clk *bus_clk; 112 struct clk *bus_clk;
113 struct clk *lcd_clk; 113 struct clk *lcd_clk;
114 void __iomem *regs; 114 void __iomem *regs;
115 struct drm_display_mode mode;
115 struct fimd_win_data win_data[WINDOWS_NR]; 116 struct fimd_win_data win_data[WINDOWS_NR];
116 unsigned int clkdiv;
117 unsigned int default_win; 117 unsigned int default_win;
118 unsigned long irq_flags; 118 unsigned long irq_flags;
119 u32 vidcon0; 119 u32 vidcon0;
@@ -221,38 +221,82 @@ static void fimd_mgr_remove(struct exynos_drm_manager *mgr)
221 drm_iommu_detach_device(ctx->drm_dev, ctx->dev); 221 drm_iommu_detach_device(ctx->drm_dev, ctx->dev);
222} 222}
223 223
224static u32 fimd_calc_clkdiv(struct fimd_context *ctx,
225 const struct drm_display_mode *mode)
226{
227 unsigned long ideal_clk = mode->htotal * mode->vtotal * mode->vrefresh;
228 u32 clkdiv;
229
230 /* Find the clock divider value that gets us closest to ideal_clk */
231 clkdiv = DIV_ROUND_UP(clk_get_rate(ctx->lcd_clk), ideal_clk);
232
233 return (clkdiv < 0x100) ? clkdiv : 0xff;
234}
235
236static bool fimd_mode_fixup(struct exynos_drm_manager *mgr,
237 const struct drm_display_mode *mode,
238 struct drm_display_mode *adjusted_mode)
239{
240 if (adjusted_mode->vrefresh == 0)
241 adjusted_mode->vrefresh = FIMD_DEFAULT_FRAMERATE;
242
243 return true;
244}
245
246static void fimd_mode_set(struct exynos_drm_manager *mgr,
247 const struct drm_display_mode *in_mode)
248{
249 struct fimd_context *ctx = mgr->ctx;
250
251 drm_mode_copy(&ctx->mode, in_mode);
252}
253
224static void fimd_commit(struct exynos_drm_manager *mgr) 254static void fimd_commit(struct exynos_drm_manager *mgr)
225{ 255{
226 struct fimd_context *ctx = mgr->ctx; 256 struct fimd_context *ctx = mgr->ctx;
227 struct exynos_drm_panel_info *panel = &ctx->panel; 257 struct drm_display_mode *mode = &ctx->mode;
228 struct videomode *vm = &panel->vm;
229 struct fimd_driver_data *driver_data; 258 struct fimd_driver_data *driver_data;
230 u32 val; 259 u32 val, clkdiv;
260 int hblank, vblank, vsync_len, vbpd, vfpd, hsync_len, hbpd, hfpd;
231 261
232 driver_data = ctx->driver_data; 262 driver_data = ctx->driver_data;
233 if (ctx->suspended) 263 if (ctx->suspended)
234 return; 264 return;
235 265
266 /* nothing to do if we haven't set the mode yet */
267 if (mode->htotal == 0 || mode->vtotal == 0)
268 return;
269
236 /* setup polarity values from machine code. */ 270 /* setup polarity values from machine code. */
237 writel(ctx->vidcon1, ctx->regs + driver_data->timing_base + VIDCON1); 271 writel(ctx->vidcon1, ctx->regs + driver_data->timing_base + VIDCON1);
238 272
239 /* setup vertical timing values. */ 273 /* setup vertical timing values. */
240 val = VIDTCON0_VBPD(vm->vback_porch - 1) | 274 vblank = mode->crtc_vblank_end - mode->crtc_vblank_start;
241 VIDTCON0_VFPD(vm->vfront_porch - 1) | 275 vsync_len = mode->crtc_vsync_end - mode->crtc_vsync_start;
242 VIDTCON0_VSPW(vm->vsync_len - 1); 276 vbpd = (vblank - vsync_len) / 2;
277 vfpd = vblank - vsync_len - vbpd;
278
279 val = VIDTCON0_VBPD(vbpd - 1) |
280 VIDTCON0_VFPD(vfpd - 1) |
281 VIDTCON0_VSPW(vsync_len - 1);
243 writel(val, ctx->regs + driver_data->timing_base + VIDTCON0); 282 writel(val, ctx->regs + driver_data->timing_base + VIDTCON0);
244 283
245 /* setup horizontal timing values. */ 284 /* setup horizontal timing values. */
246 val = VIDTCON1_HBPD(vm->hback_porch - 1) | 285 hblank = mode->crtc_hblank_end - mode->crtc_hblank_start;
247 VIDTCON1_HFPD(vm->hfront_porch - 1) | 286 hsync_len = mode->crtc_hsync_end - mode->crtc_hsync_start;
248 VIDTCON1_HSPW(vm->hsync_len - 1); 287 hbpd = (hblank - hsync_len) / 2;
288 hfpd = hblank - hsync_len - hbpd;
289
290 val = VIDTCON1_HBPD(hbpd - 1) |
291 VIDTCON1_HFPD(hfpd - 1) |
292 VIDTCON1_HSPW(hsync_len - 1);
249 writel(val, ctx->regs + driver_data->timing_base + VIDTCON1); 293 writel(val, ctx->regs + driver_data->timing_base + VIDTCON1);
250 294
251 /* setup horizontal and vertical display size. */ 295 /* setup horizontal and vertical display size. */
252 val = VIDTCON2_LINEVAL(vm->vactive - 1) | 296 val = VIDTCON2_LINEVAL(mode->vdisplay - 1) |
253 VIDTCON2_HOZVAL(vm->hactive - 1) | 297 VIDTCON2_HOZVAL(mode->hdisplay - 1) |
254 VIDTCON2_LINEVAL_E(vm->vactive - 1) | 298 VIDTCON2_LINEVAL_E(mode->vdisplay - 1) |
255 VIDTCON2_HOZVAL_E(vm->hactive - 1); 299 VIDTCON2_HOZVAL_E(mode->hdisplay - 1);
256 writel(val, ctx->regs + driver_data->timing_base + VIDTCON2); 300 writel(val, ctx->regs + driver_data->timing_base + VIDTCON2);
257 301
258 /* setup clock source, clock divider, enable dma. */ 302 /* setup clock source, clock divider, enable dma. */
@@ -264,8 +308,9 @@ static void fimd_commit(struct exynos_drm_manager *mgr)
264 val |= VIDCON0_CLKSEL_LCD; 308 val |= VIDCON0_CLKSEL_LCD;
265 } 309 }
266 310
267 if (ctx->clkdiv > 1) 311 clkdiv = fimd_calc_clkdiv(ctx, mode);
268 val |= VIDCON0_CLKVAL_F(ctx->clkdiv - 1) | VIDCON0_CLKDIR; 312 if (clkdiv > 1)
313 val |= VIDCON0_CLKVAL_F(clkdiv - 1) | VIDCON0_CLKDIR;
269 else 314 else
270 val &= ~VIDCON0_CLKDIR; /* 1:1 clock */ 315 val &= ~VIDCON0_CLKDIR; /* 1:1 clock */
271 316
@@ -683,6 +728,8 @@ static struct exynos_drm_manager_ops fimd_manager_ops = {
683 .initialize = fimd_mgr_initialize, 728 .initialize = fimd_mgr_initialize,
684 .remove = fimd_mgr_remove, 729 .remove = fimd_mgr_remove,
685 .dpms = fimd_dpms, 730 .dpms = fimd_dpms,
731 .mode_fixup = fimd_mode_fixup,
732 .mode_set = fimd_mode_set,
686 .commit = fimd_commit, 733 .commit = fimd_commit,
687 .enable_vblank = fimd_enable_vblank, 734 .enable_vblank = fimd_enable_vblank,
688 .disable_vblank = fimd_disable_vblank, 735 .disable_vblank = fimd_disable_vblank,
@@ -724,56 +771,6 @@ out:
724 return IRQ_HANDLED; 771 return IRQ_HANDLED;
725} 772}
726 773
727static int fimd_configure_clocks(struct fimd_context *ctx, struct device *dev)
728{
729 struct videomode *vm = &ctx->panel.vm;
730 unsigned long clk;
731
732 ctx->bus_clk = devm_clk_get(dev, "fimd");
733 if (IS_ERR(ctx->bus_clk)) {
734 dev_err(dev, "failed to get bus clock\n");
735 return PTR_ERR(ctx->bus_clk);
736 }
737
738 ctx->lcd_clk = devm_clk_get(dev, "sclk_fimd");
739 if (IS_ERR(ctx->lcd_clk)) {
740 dev_err(dev, "failed to get lcd clock\n");
741 return PTR_ERR(ctx->lcd_clk);
742 }
743
744 clk = clk_get_rate(ctx->lcd_clk);
745 if (clk == 0) {
746 dev_err(dev, "error getting sclk_fimd clock rate\n");
747 return -EINVAL;
748 }
749
750 if (vm->pixelclock == 0) {
751 unsigned long c;
752 c = vm->hactive + vm->hback_porch + vm->hfront_porch +
753 vm->hsync_len;
754 c *= vm->vactive + vm->vback_porch + vm->vfront_porch +
755 vm->vsync_len;
756 vm->pixelclock = c * FIMD_DEFAULT_FRAMERATE;
757 if (vm->pixelclock == 0) {
758 dev_err(dev, "incorrect display timings\n");
759 return -EINVAL;
760 }
761 dev_warn(dev, "pixel clock recalculated to %luHz (%dHz frame rate)\n",
762 vm->pixelclock, FIMD_DEFAULT_FRAMERATE);
763 }
764 ctx->clkdiv = DIV_ROUND_UP(clk, vm->pixelclock);
765 if (ctx->clkdiv > 256) {
766 dev_warn(dev, "calculated pixel clock divider too high (%u), lowered to 256\n",
767 ctx->clkdiv);
768 ctx->clkdiv = 256;
769 }
770 vm->pixelclock = clk / ctx->clkdiv;
771 DRM_DEBUG_KMS("pixel clock = %lu, clkdiv = %d\n", vm->pixelclock,
772 ctx->clkdiv);
773
774 return 0;
775}
776
777static void fimd_clear_win(struct fimd_context *ctx, int win) 774static void fimd_clear_win(struct fimd_context *ctx, int win)
778{ 775{
779 writel(0, ctx->regs + WINCON(win)); 776 writel(0, ctx->regs + WINCON(win));
@@ -926,9 +923,17 @@ static int fimd_probe(struct platform_device *pdev)
926 if (ret) 923 if (ret)
927 return ret; 924 return ret;
928 925
929 ret = fimd_configure_clocks(ctx, dev); 926 ctx->bus_clk = devm_clk_get(dev, "fimd");
930 if (ret) 927 if (IS_ERR(ctx->bus_clk)) {
931 return ret; 928 dev_err(dev, "failed to get bus clock\n");
929 return PTR_ERR(ctx->bus_clk);
930 }
931
932 ctx->lcd_clk = devm_clk_get(dev, "sclk_fimd");
933 if (IS_ERR(ctx->lcd_clk)) {
934 dev_err(dev, "failed to get lcd clock\n");
935 return PTR_ERR(ctx->lcd_clk);
936 }
932 937
933 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 938 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
934 939