Commit 2fa3b4c4 authored by Liu Ying's avatar Liu Ying Committed by Tomi Valkeinen

video: mxsfb: Make sure axi clock is enabled when accessing registers

The LCDIF engines embedded in i.MX6sl and i.MX6sx SoCs need the axi clock
as the engine's system clock.  The clock should be enabled when accessing
LCDIF registers, otherwise the kernel would hang up.  We should also keep
the clock enabled when the engine is being active to scan out frames from
memory.  This patch makes sure the axi clock is enabled when accessing
registers so that the kernel hang up issue can be fixed.
Reported-by: default avatarPeter Chen <peter.chen@freescale.com>
Tested-by: default avatarPeter Chen <peter.chen@freescale.com>
Cc: <stable@vger.kernel.org> # 3.19+
Signed-off-by: default avatarLiu Ying <Ying.Liu@freescale.com>
Signed-off-by: default avatarTomi Valkeinen <tomi.valkeinen@ti.com>
parent a7c42990
...@@ -316,6 +316,18 @@ static int mxsfb_check_var(struct fb_var_screeninfo *var, ...@@ -316,6 +316,18 @@ static int mxsfb_check_var(struct fb_var_screeninfo *var,
return 0; return 0;
} }
static inline void mxsfb_enable_axi_clk(struct mxsfb_info *host)
{
if (host->clk_axi)
clk_prepare_enable(host->clk_axi);
}
static inline void mxsfb_disable_axi_clk(struct mxsfb_info *host)
{
if (host->clk_axi)
clk_disable_unprepare(host->clk_axi);
}
static void mxsfb_enable_controller(struct fb_info *fb_info) static void mxsfb_enable_controller(struct fb_info *fb_info)
{ {
struct mxsfb_info *host = to_imxfb_host(fb_info); struct mxsfb_info *host = to_imxfb_host(fb_info);
...@@ -333,14 +345,13 @@ static void mxsfb_enable_controller(struct fb_info *fb_info) ...@@ -333,14 +345,13 @@ static void mxsfb_enable_controller(struct fb_info *fb_info)
} }
} }
if (host->clk_axi)
clk_prepare_enable(host->clk_axi);
if (host->clk_disp_axi) if (host->clk_disp_axi)
clk_prepare_enable(host->clk_disp_axi); clk_prepare_enable(host->clk_disp_axi);
clk_prepare_enable(host->clk); clk_prepare_enable(host->clk);
clk_set_rate(host->clk, PICOS2KHZ(fb_info->var.pixclock) * 1000U); clk_set_rate(host->clk, PICOS2KHZ(fb_info->var.pixclock) * 1000U);
mxsfb_enable_axi_clk(host);
/* if it was disabled, re-enable the mode again */ /* if it was disabled, re-enable the mode again */
writel(CTRL_DOTCLK_MODE, host->base + LCDC_CTRL + REG_SET); writel(CTRL_DOTCLK_MODE, host->base + LCDC_CTRL + REG_SET);
...@@ -380,11 +391,11 @@ static void mxsfb_disable_controller(struct fb_info *fb_info) ...@@ -380,11 +391,11 @@ static void mxsfb_disable_controller(struct fb_info *fb_info)
reg = readl(host->base + LCDC_VDCTRL4); reg = readl(host->base + LCDC_VDCTRL4);
writel(reg & ~VDCTRL4_SYNC_SIGNALS_ON, host->base + LCDC_VDCTRL4); writel(reg & ~VDCTRL4_SYNC_SIGNALS_ON, host->base + LCDC_VDCTRL4);
mxsfb_disable_axi_clk(host);
clk_disable_unprepare(host->clk); clk_disable_unprepare(host->clk);
if (host->clk_disp_axi) if (host->clk_disp_axi)
clk_disable_unprepare(host->clk_disp_axi); clk_disable_unprepare(host->clk_disp_axi);
if (host->clk_axi)
clk_disable_unprepare(host->clk_axi);
host->enabled = 0; host->enabled = 0;
...@@ -421,6 +432,8 @@ static int mxsfb_set_par(struct fb_info *fb_info) ...@@ -421,6 +432,8 @@ static int mxsfb_set_par(struct fb_info *fb_info)
mxsfb_disable_controller(fb_info); mxsfb_disable_controller(fb_info);
} }
mxsfb_enable_axi_clk(host);
/* clear the FIFOs */ /* clear the FIFOs */
writel(CTRL1_FIFO_CLEAR, host->base + LCDC_CTRL1 + REG_SET); writel(CTRL1_FIFO_CLEAR, host->base + LCDC_CTRL1 + REG_SET);
...@@ -438,6 +451,7 @@ static int mxsfb_set_par(struct fb_info *fb_info) ...@@ -438,6 +451,7 @@ static int mxsfb_set_par(struct fb_info *fb_info)
ctrl |= CTRL_SET_WORD_LENGTH(3); ctrl |= CTRL_SET_WORD_LENGTH(3);
switch (host->ld_intf_width) { switch (host->ld_intf_width) {
case STMLCDIF_8BIT: case STMLCDIF_8BIT:
mxsfb_disable_axi_clk(host);
dev_err(&host->pdev->dev, dev_err(&host->pdev->dev,
"Unsupported LCD bus width mapping\n"); "Unsupported LCD bus width mapping\n");
return -EINVAL; return -EINVAL;
...@@ -451,6 +465,7 @@ static int mxsfb_set_par(struct fb_info *fb_info) ...@@ -451,6 +465,7 @@ static int mxsfb_set_par(struct fb_info *fb_info)
writel(CTRL1_SET_BYTE_PACKAGING(0x7), host->base + LCDC_CTRL1); writel(CTRL1_SET_BYTE_PACKAGING(0x7), host->base + LCDC_CTRL1);
break; break;
default: default:
mxsfb_disable_axi_clk(host);
dev_err(&host->pdev->dev, "Unhandled color depth of %u\n", dev_err(&host->pdev->dev, "Unhandled color depth of %u\n",
fb_info->var.bits_per_pixel); fb_info->var.bits_per_pixel);
return -EINVAL; return -EINVAL;
...@@ -504,6 +519,8 @@ static int mxsfb_set_par(struct fb_info *fb_info) ...@@ -504,6 +519,8 @@ static int mxsfb_set_par(struct fb_info *fb_info)
fb_info->fix.line_length * fb_info->var.yoffset, fb_info->fix.line_length * fb_info->var.yoffset,
host->base + host->devdata->next_buf); host->base + host->devdata->next_buf);
mxsfb_disable_axi_clk(host);
if (reenable) if (reenable)
mxsfb_enable_controller(fb_info); mxsfb_enable_controller(fb_info);
...@@ -582,10 +599,14 @@ static int mxsfb_pan_display(struct fb_var_screeninfo *var, ...@@ -582,10 +599,14 @@ static int mxsfb_pan_display(struct fb_var_screeninfo *var,
offset = fb_info->fix.line_length * var->yoffset; offset = fb_info->fix.line_length * var->yoffset;
mxsfb_enable_axi_clk(host);
/* update on next VSYNC */ /* update on next VSYNC */
writel(fb_info->fix.smem_start + offset, writel(fb_info->fix.smem_start + offset,
host->base + host->devdata->next_buf); host->base + host->devdata->next_buf);
mxsfb_disable_axi_clk(host);
return 0; return 0;
} }
...@@ -608,13 +629,17 @@ static int mxsfb_restore_mode(struct mxsfb_info *host, ...@@ -608,13 +629,17 @@ static int mxsfb_restore_mode(struct mxsfb_info *host,
unsigned line_count; unsigned line_count;
unsigned period; unsigned period;
unsigned long pa, fbsize; unsigned long pa, fbsize;
int bits_per_pixel, ofs; int bits_per_pixel, ofs, ret = 0;
u32 transfer_count, vdctrl0, vdctrl2, vdctrl3, vdctrl4, ctrl; u32 transfer_count, vdctrl0, vdctrl2, vdctrl3, vdctrl4, ctrl;
mxsfb_enable_axi_clk(host);
/* Only restore the mode when the controller is running */ /* Only restore the mode when the controller is running */
ctrl = readl(host->base + LCDC_CTRL); ctrl = readl(host->base + LCDC_CTRL);
if (!(ctrl & CTRL_RUN)) if (!(ctrl & CTRL_RUN)) {
return -EINVAL; ret = -EINVAL;
goto err;
}
vdctrl0 = readl(host->base + LCDC_VDCTRL0); vdctrl0 = readl(host->base + LCDC_VDCTRL0);
vdctrl2 = readl(host->base + LCDC_VDCTRL2); vdctrl2 = readl(host->base + LCDC_VDCTRL2);
...@@ -635,7 +660,8 @@ static int mxsfb_restore_mode(struct mxsfb_info *host, ...@@ -635,7 +660,8 @@ static int mxsfb_restore_mode(struct mxsfb_info *host,
break; break;
case 1: case 1:
default: default:
return -EINVAL; ret = -EINVAL;
goto err;
} }
fb_info->var.bits_per_pixel = bits_per_pixel; fb_info->var.bits_per_pixel = bits_per_pixel;
...@@ -673,10 +699,14 @@ static int mxsfb_restore_mode(struct mxsfb_info *host, ...@@ -673,10 +699,14 @@ static int mxsfb_restore_mode(struct mxsfb_info *host,
pa = readl(host->base + host->devdata->cur_buf); pa = readl(host->base + host->devdata->cur_buf);
fbsize = fb_info->fix.line_length * vmode->yres; fbsize = fb_info->fix.line_length * vmode->yres;
if (pa < fb_info->fix.smem_start) if (pa < fb_info->fix.smem_start) {
return -EINVAL; ret = -EINVAL;
if (pa + fbsize > fb_info->fix.smem_start + fb_info->fix.smem_len) goto err;
return -EINVAL; }
if (pa + fbsize > fb_info->fix.smem_start + fb_info->fix.smem_len) {
ret = -EINVAL;
goto err;
}
ofs = pa - fb_info->fix.smem_start; ofs = pa - fb_info->fix.smem_start;
if (ofs) { if (ofs) {
memmove(fb_info->screen_base, fb_info->screen_base + ofs, fbsize); memmove(fb_info->screen_base, fb_info->screen_base + ofs, fbsize);
...@@ -689,7 +719,11 @@ static int mxsfb_restore_mode(struct mxsfb_info *host, ...@@ -689,7 +719,11 @@ static int mxsfb_restore_mode(struct mxsfb_info *host,
clk_prepare_enable(host->clk); clk_prepare_enable(host->clk);
host->enabled = 1; host->enabled = 1;
return 0; err:
if (ret)
mxsfb_disable_axi_clk(host);
return ret;
} }
static int mxsfb_init_fbinfo_dt(struct mxsfb_info *host, static int mxsfb_init_fbinfo_dt(struct mxsfb_info *host,
...@@ -915,7 +949,9 @@ static int mxsfb_probe(struct platform_device *pdev) ...@@ -915,7 +949,9 @@ static int mxsfb_probe(struct platform_device *pdev)
} }
if (!host->enabled) { if (!host->enabled) {
mxsfb_enable_axi_clk(host);
writel(0, host->base + LCDC_CTRL); writel(0, host->base + LCDC_CTRL);
mxsfb_disable_axi_clk(host);
mxsfb_set_par(fb_info); mxsfb_set_par(fb_info);
mxsfb_enable_controller(fb_info); mxsfb_enable_controller(fb_info);
} }
...@@ -954,11 +990,15 @@ static void mxsfb_shutdown(struct platform_device *pdev) ...@@ -954,11 +990,15 @@ static void mxsfb_shutdown(struct platform_device *pdev)
struct fb_info *fb_info = platform_get_drvdata(pdev); struct fb_info *fb_info = platform_get_drvdata(pdev);
struct mxsfb_info *host = to_imxfb_host(fb_info); struct mxsfb_info *host = to_imxfb_host(fb_info);
mxsfb_enable_axi_clk(host);
/* /*
* Force stop the LCD controller as keeping it running during reboot * Force stop the LCD controller as keeping it running during reboot
* might interfere with the BootROM's boot mode pads sampling. * might interfere with the BootROM's boot mode pads sampling.
*/ */
writel(CTRL_RUN, host->base + LCDC_CTRL + REG_CLR); writel(CTRL_RUN, host->base + LCDC_CTRL + REG_CLR);
mxsfb_disable_axi_clk(host);
} }
static struct platform_driver mxsfb_driver = { static struct platform_driver mxsfb_driver = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment