X-Git-Url: https://git.kernelconcepts.de/?a=blobdiff_plain;f=drivers%2Fvideo%2Ffbdev%2Fmxsfb.c;h=5e5901403e5b62c47bf53a2bf87a0da6f2de1cbc;hb=8f2e795b08180b9a9e9ea88cddd5110e01406b5e;hp=accf48a2cce43e16d8ebeea80807df2b32c9cc76;hpb=e055a6e20a9105551295da164c31179b82c6227e;p=karo-tx-linux.git diff --git a/drivers/video/fbdev/mxsfb.c b/drivers/video/fbdev/mxsfb.c index accf48a2cce4..5e5901403e5b 100644 --- a/drivers/video/fbdev/mxsfb.c +++ b/drivers/video/fbdev/mxsfb.c @@ -4,7 +4,7 @@ * This code is based on: * Author: Vitaly Wool * - * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008-2014 Freescale Semiconductor, Inc. All Rights Reserved. * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. * * This program is free software; you can redistribute it and/or @@ -171,7 +171,9 @@ struct mxsfb_devdata { struct mxsfb_info { struct fb_info fb_info; struct platform_device *pdev; - struct clk *clk; + struct clk *clk_pix; + struct clk *clk_axi; + bool clk_axi_enabled; void __iomem *base; /* registers */ unsigned allocated_size; int enabled; @@ -208,6 +210,26 @@ static const struct mxsfb_devdata mxsfb_devdata[] = { #define to_imxfb_host(x) (container_of(x, struct mxsfb_info, fb_info)) +/* enable lcdif axi clock */ +static inline void clk_enable_axi(struct mxsfb_info *host) +{ + if (!host->clk_axi_enabled && host && + host->clk_axi && !IS_ERR(host->clk_axi)) { + clk_prepare_enable(host->clk_axi); + host->clk_axi_enabled = true; + } +} + +/* disable lcdif axi clock */ +static inline void clk_disable_axi(struct mxsfb_info *host) +{ + if (host->clk_axi_enabled && host && + host->clk_axi && !IS_ERR(host->clk_axi)) { + clk_disable_unprepare(host->clk_axi); + host->clk_axi_enabled = false; + } +} + /* mask and shift depends on architecture */ static inline u32 set_hsync_pulse_width(struct mxsfb_info *host, unsigned val) { @@ -331,8 +353,13 @@ static void mxsfb_enable_controller(struct fb_info *fb_info) } } - clk_prepare_enable(host->clk); - clk_set_rate(host->clk, PICOS2KHZ(fb_info->var.pixclock) * 1000U); + clk_enable_axi(host); + + clk_prepare_enable(host->clk_pix); + clk_set_rate(host->clk_pix, PICOS2KHZ(fb_info->var.pixclock) * 1000U); + + /* Clean soft reset and clock gate bit if it was enabled */ + writel(CTRL_SFTRST | CTRL_CLKGATE, host->base + LCDC_CTRL + REG_CLR); /* if it was disabled, re-enable the mode again */ writel(CTRL_DOTCLK_MODE, host->base + LCDC_CTRL + REG_SET); @@ -342,6 +369,7 @@ static void mxsfb_enable_controller(struct fb_info *fb_info) reg |= VDCTRL4_SYNC_SIGNALS_ON; writel(reg, host->base + LCDC_VDCTRL4); + writel(CTRL_MASTER, host->base + LCDC_CTRL + REG_SET); writel(CTRL_RUN, host->base + LCDC_CTRL + REG_SET); host->enabled = 1; @@ -356,6 +384,7 @@ static void mxsfb_disable_controller(struct fb_info *fb_info) dev_dbg(&host->pdev->dev, "%s\n", __func__); + clk_enable_axi(host); /* * Even if we disable the controller here, it will still continue * until its FIFOs are running out of data @@ -370,10 +399,12 @@ static void mxsfb_disable_controller(struct fb_info *fb_info) loop--; } + writel(CTRL_MASTER, host->base + LCDC_CTRL + REG_CLR); + reg = readl(host->base + LCDC_VDCTRL4); writel(reg & ~VDCTRL4_SYNC_SIGNALS_ON, host->base + LCDC_VDCTRL4); - clk_disable_unprepare(host->clk); + clk_disable_unprepare(host->clk_pix); host->enabled = 0; @@ -392,6 +423,8 @@ static int mxsfb_set_par(struct fb_info *fb_info) int line_size, fb_size; int reenable = 0; + clk_enable_axi(host); + line_size = fb_info->var.xres * (fb_info->var.bits_per_pixel >> 3); fb_size = fb_info->var.yres_virtual * line_size; @@ -550,11 +583,14 @@ static int mxsfb_blank(int blank, struct fb_info *fb_info) case FB_BLANK_NORMAL: if (host->enabled) mxsfb_disable_controller(fb_info); + + clk_disable_axi(host); break; case FB_BLANK_UNBLANK: if (!host->enabled) mxsfb_enable_controller(fb_info); + mxsfb_set_par(&host->fb_info); break; } return 0; @@ -569,6 +605,8 @@ static int mxsfb_pan_display(struct fb_var_screeninfo *var, if (var->xoffset != 0) return -EINVAL; + clk_enable_axi(host); + offset = fb_info->fix.line_length * var->yoffset; /* update on next VSYNC */ @@ -600,6 +638,8 @@ static int mxsfb_restore_mode(struct mxsfb_info *host, int bits_per_pixel, ofs; u32 transfer_count, vdctrl0, vdctrl2, vdctrl3, vdctrl4, ctrl; + clk_enable_axi(host); + /* Only restore the mode when the controller is running */ ctrl = readl(host->base + LCDC_CTRL); if (!(ctrl & CTRL_RUN)) @@ -675,7 +715,7 @@ static int mxsfb_restore_mode(struct mxsfb_info *host, line_count = fb_info->fix.smem_len / fb_info->fix.line_length; fb_info->fix.ypanstep = 1; - clk_prepare_enable(host->clk); + clk_prepare_enable(host->clk_pix); host->enabled = 1; return 0; @@ -861,9 +901,15 @@ static int mxsfb_probe(struct platform_device *pdev) host->devdata = &mxsfb_devdata[pdev->id_entry->driver_data]; - host->clk = devm_clk_get(&host->pdev->dev, NULL); - if (IS_ERR(host->clk)) { - ret = PTR_ERR(host->clk); + host->clk_pix = devm_clk_get(&host->pdev->dev, "pix"); + if (IS_ERR(host->clk_pix)) { + ret = PTR_ERR(host->clk_pix); + goto fb_release; + } + + host->clk_axi = devm_clk_get(&host->pdev->dev, "axi"); + if (IS_ERR(host->clk_axi)) { + ret = PTR_ERR(host->clk_axi); goto fb_release; } @@ -907,7 +953,7 @@ static int mxsfb_probe(struct platform_device *pdev) fb_destroy: if (host->enabled) - clk_disable_unprepare(host->clk); + clk_disable_unprepare(host->clk_pix); fb_release: framebuffer_release(fb_info); @@ -935,11 +981,14 @@ static void mxsfb_shutdown(struct platform_device *pdev) struct fb_info *fb_info = platform_get_drvdata(pdev); struct mxsfb_info *host = to_imxfb_host(fb_info); + clk_enable_axi(host); /* * Force stop the LCD controller as keeping it running during reboot * might interfere with the BootROM's boot mode pads sampling. */ writel(CTRL_RUN, host->base + LCDC_CTRL + REG_CLR); + writel(CTRL_MASTER, host->base + LCDC_CTRL + REG_CLR); + clk_disable_axi(host); } static struct platform_driver mxsfb_driver = {