From ca2e58facd0b45c954ea5df0172ea3d06c96a22b Mon Sep 17 00:00:00 2001 From: Shirish S Date: Fri, 6 Jul 2012 15:23:54 +0530 Subject: [PATCH] drm/exynos: add 1280x720 mode to exynos5 fimd this patch adds 1280x720 mode to the fimd panel, the lcd will switch to this mode when HDMI is plugged in and will switch back to default mode when HDMI is plugged out. BUG=chrome-os-partner:10851 TEST=Plugged in/out HDMI cable several times on snow, both in login screen and after login, the resolution switches accordingly Change-Id: I4f02f158dbd9ae5aa1483e780dea00317aab9e1e Signed-off-by: Shirish S Reviewed-on: https://gerrit.chromium.org/gerrit/26848 Reviewed-by: Mandeep Singh Baines Reviewed-by: Sean Paul --- drivers/gpu/drm/exynos/exynos_drm_connector.c | 33 +++++----- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 66 +++++++++++++++---- drivers/gpu/drm/exynos/exynos_mixer.c | 15 ++--- 3 files changed, 77 insertions(+), 37 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_connector.c b/drivers/gpu/drm/exynos/exynos_drm_connector.c index bf791fa0e50d..732c65a244c4 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_connector.c +++ b/drivers/gpu/drm/exynos/exynos_drm_connector.c @@ -122,9 +122,6 @@ static int exynos_drm_connector_get_modes(struct drm_connector *connector) * if get_edid() exists then get_edid() callback of hdmi side * is called to get edid data through i2c interface else * get timing from the FIMD driver(display controller). - * - * P.S. in case of lcd panel, count is always 1 if success - * because lcd panel has only one mode. */ if (display_ops->get_edid) { int ret; @@ -151,25 +148,31 @@ static int exynos_drm_connector_get_modes(struct drm_connector *connector) kfree(connector->display_info.raw_edid); connector->display_info.raw_edid = edid; } else { - struct drm_display_mode *mode = drm_mode_create(connector->dev); + struct drm_display_mode *mode; struct exynos_drm_panel_info *panel; if (display_ops->get_panel) panel = display_ops->get_panel(manager->dev); - else { - drm_mode_destroy(connector->dev, mode); + else return 0; - } - convert_to_display_mode(mode, panel); - connector->display_info.width_mm = mode->width_mm; - connector->display_info.height_mm = mode->height_mm; - - mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; - drm_mode_set_name(mode); - drm_mode_probed_add(connector, mode); + for (count = 0;count < MAX_NR_PANELS;count++) { + if(panel[count].timing.xres == -1 && panel[count].timing.yres == -1) { + DRM_DEBUG_KMS("panel %d count%d\n",panel,count); + break; + } + mode = drm_mode_create(connector->dev); + /* Only the first panel is preferred mode */ + mode->type = count ? DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_USERDEF: + DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; + + convert_to_display_mode(mode, &panel[count]); + connector->display_info.width_mm = mode->width_mm; + connector->display_info.height_mm = mode->height_mm; + drm_mode_set_name(mode); + drm_mode_probed_add(connector, mode); + } - count = 1; } return count; diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 1d814b494c02..1c87d28ae8c7 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -82,11 +82,12 @@ struct fimd_context { struct resource *regs_res; void __iomem *regs; struct fimd_win_data win_data[WINDOWS_NR]; - unsigned int clkdiv; + unsigned int clkdiv[MAX_NR_PANELS]; unsigned int default_win; unsigned long irq_flags; u32 vidcon0; u32 vidcon1; + int idx; bool suspended; struct mutex lock; @@ -113,11 +114,25 @@ static void *fimd_get_panel(struct device *dev) static int fimd_check_timing(struct device *dev, void *timing) { + struct fimd_context *ctx = get_fimd_context(dev); + struct fb_videomode *check_timing = timing; + int i; + DRM_DEBUG_KMS("%s\n", __FILE__); - /* TODO. */ + for (i = 0;i< MAX_NR_PANELS;i++) { + if (ctx->panel[i].timing.xres == -1 && + ctx->panel[i].timing.yres == -1) + break; - return 0; + if (ctx->panel[i].timing.xres == check_timing->xres && + ctx->panel[i].timing.yres == check_timing->yres && + ctx->panel[i].timing.refresh == check_timing->refresh + ) + return 0; + } + + return -EINVAL; } static int fimd_display_power_on(struct device *dev, int mode) @@ -142,6 +157,11 @@ static void fimd_dpms(struct device *subdrv_dev, int mode) struct fimd_context *ctx = get_fimd_context(subdrv_dev); DRM_DEBUG_KMS("%s, %d\n", __FILE__, mode); + /* TODO: + * For Mode Switching, the FIMD need not be turned off, need + * to find another way to DPMS off FIMD + */ + return; mutex_lock(&ctx->lock); @@ -194,7 +214,7 @@ static void fimd_apply(struct device *subdrv_dev) static void fimd_commit(struct device *dev) { struct fimd_context *ctx = get_fimd_context(dev); - struct exynos_drm_panel_info *panel = ctx->panel; + struct exynos_drm_panel_info *panel = &ctx->panel[ctx->idx]; struct fb_videomode *timing = &panel->timing; u32 val; @@ -227,8 +247,8 @@ static void fimd_commit(struct device *dev) val = ctx->vidcon0; val &= ~(VIDCON0_CLKVAL_F_MASK | VIDCON0_CLKDIR); - if (ctx->clkdiv > 1) - val |= VIDCON0_CLKVAL_F(ctx->clkdiv - 1) | VIDCON0_CLKDIR; + if (ctx->clkdiv[ctx->idx] > 1) + val |= VIDCON0_CLKVAL_F(ctx->clkdiv[ctx->idx] - 1) | VIDCON0_CLKDIR; else val &= ~VIDCON0_CLKDIR; /* 1:1 clock */ @@ -317,6 +337,20 @@ static void fimd_win_mode_set(struct device *dev, if (win < 0 || win > WINDOWS_NR) return; + if(win == ctx->default_win) { + for(ctx->idx = 0;ctx->idx < MAX_NR_PANELS;ctx->idx++) { + if (ctx->panel[ctx->idx].timing.xres == -1 && + ctx->panel[ctx->idx].timing.yres == -1) { + DRM_ERROR("Invalid panel parameters"); + ctx->idx = 0; /* Reset to first panel index*/ + break; + } + if (ctx->panel[ctx->idx].timing.xres == overlay->fb_width && + ctx->panel[ctx->idx].timing.yres == overlay->fb_height) + break; + } + } + offset = overlay->fb_x * (overlay->bpp >> 3); offset += overlay->fb_y * overlay->fb_pitch; @@ -562,6 +596,8 @@ static void fimd_win_disable(struct device *dev, int zpos) u32 val; DRM_DEBUG_KMS("%s\n", __FILE__); + if (ctx->suspended) + return; if (win == DEFAULT_ZPOS) win = ctx->default_win; @@ -828,7 +864,7 @@ static int iommu_init(struct platform_device *pdev) platform_set_sysmmu(&pds->dev, &pdev->dev); exynos_drm_common_mapping = s5p_create_iommu_mapping(&pdev->dev, - 0x20000000, SZ_256M, 4, + 0x20000000, SZ_128M, 4, exynos_drm_common_mapping); if (!exynos_drm_common_mapping) { @@ -848,7 +884,7 @@ static int __devinit fimd_probe(struct platform_device *pdev) struct exynos_drm_panel_info *panel; struct resource *res; struct clk *clk_parent; - int win; + int win,i; int ret = -EINVAL; #ifdef CONFIG_EXYNOS_IOMMU @@ -866,7 +902,7 @@ static int __devinit fimd_probe(struct platform_device *pdev) return -EINVAL; } - panel = &pdata->panel; + panel = pdata->panel; if (!panel) { dev_err(dev, "panel is null.\n"); return -EINVAL; @@ -963,11 +999,15 @@ static int __devinit fimd_probe(struct platform_device *pdev) pm_runtime_enable(dev); pm_runtime_get_sync(dev); - ctx->clkdiv = fimd_calc_clkdiv(ctx, &panel->timing); - panel->timing.pixclock = clk_get_rate(ctx->lcd_clk) / ctx->clkdiv; + for (i = 0;i < MAX_NR_PANELS;i++) { + if(panel[i].timing.xres == -1 && panel[i].timing.yres == -1) + break; - DRM_DEBUG_KMS("pixel clock = %d, clkdiv = %d\n", - panel->timing.pixclock, ctx->clkdiv); + ctx->clkdiv[i] = fimd_calc_clkdiv(ctx, &panel[i].timing); + panel[i].timing.pixclock = clk_get_rate(ctx->lcd_clk) / ctx->clkdiv[i]; + DRM_DEBUG_KMS("pixel clock = %d, clkdiv = %d\n for panel[%d]", + panel[i].timing.pixclock, ctx->clkdiv[i],i); + } for (win = 0; win < WINDOWS_NR; win++) fimd_clear_win(ctx, win); diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index 8815e087c3b9..831007f72221 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -601,6 +601,7 @@ static void mixer_graph_buffer(struct mixer_context *ctx, int win) mixer_cfg_scan(ctx, mode_height); mixer_cfg_rgb_fmt(ctx, mode_height); mixer_cfg_layer(ctx, win, true); + mixer_cfg_layer(ctx, MIXER_DEFAULT_WIN, true); mixer_run(ctx); mixer_vsync_set_update(ctx, true); @@ -755,8 +756,10 @@ static void mixer_win_disable(void *ctx, int zpos) spin_unlock_irqrestore(&res->reg_slock, flags); - mixer_win_reset(ctx); - mixer_enable_vblank(ctx, 0); + if (win == MIXER_DEFAULT_WIN) { + mixer_win_reset(ctx); + mixer_enable_vblank(ctx, 0); + } } static struct exynos_mixer_ops mixer_ops = { @@ -826,16 +829,10 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg) if (ctx->event_flags & MXR_EVENT_VSYNC) { DRM_DEBUG_KMS("ctx->event_flags & MXR_EVENT_VSYNC"); - mixer_reg_write(res, MXR_GRAPHIC_WH(0), 0); - mixer_reg_write(res, MXR_GRAPHIC_WH(1), 0); - mixer_reg_write(res, MXR_GRAPHIC_SPAN(0), 0); + mixer_reg_write(res, MXR_GRAPHIC_WH(1), 0); mixer_reg_write(res, MXR_GRAPHIC_SPAN(1), 0); - - mixer_reg_write(res, MXR_GRAPHIC_SXY(0), 0); mixer_reg_write(res, MXR_GRAPHIC_SXY(1), 0); - - mixer_reg_write(res, MXR_GRAPHIC_DXY(0), 0); mixer_reg_write(res, MXR_GRAPHIC_DXY(1), 0); ctx->event_flags &= ~MXR_EVENT_VSYNC; -- 2.20.1