summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobby Cai <R63905@freescale.com>2013-08-22 14:35:09 +0800
committerJason Liu <r64343@freescale.com>2013-10-30 09:55:02 +0800
commit2b2df2753f6dfb6345e1eb3124f18d6d4dd9e08e (patch)
treea289c54bb50066c9e3909bb58fb47c6f818d04cd
parent48a9dddc8f9fd9a28f28d7f9172a8f0262ebe079 (diff)
ENGR00275031-1 mx6sl fb: support lcdif framebuffer on 3.10
re-use the upstreaming mxsfb.c code. - add the lcdif axi clock for register and dram access - set the lcdif pix's parent as pll5_video to get most accurate pix clock - add binding doc for lcdif dts Signed-off-by: Robby Cai <R63905@freescale.com>
-rw-r--r--Documentation/devicetree/bindings/fb/mxsfb.txt7
-rw-r--r--arch/arm/mach-imx/clk-imx6sl.c6
-rw-r--r--drivers/video/Kconfig2
-rw-r--r--drivers/video/mxsfb.c63
4 files changed, 66 insertions, 12 deletions
diff --git a/Documentation/devicetree/bindings/fb/mxsfb.txt b/Documentation/devicetree/bindings/fb/mxsfb.txt
index 96ec5179c8a0..db41376d503e 100644
--- a/Documentation/devicetree/bindings/fb/mxsfb.txt
+++ b/Documentation/devicetree/bindings/fb/mxsfb.txt
@@ -3,6 +3,9 @@
Required properties:
- compatible: Should be "fsl,<chip>-lcdif". Supported chips include
imx23 and imx28.
+- pinctrl-names: Should be "default"
+- pinctrl-0: pinctrl setting for lcd
+- lcd-supply: lcd power supply, usually via GPIO
- reg: Address and length of the register set for lcdif
- interrupts: Should contain lcdif interrupts
- display : phandle to display node (see below for details)
@@ -22,6 +25,10 @@ lcdif@80030000 {
compatible = "fsl,imx28-lcdif";
reg = <0x80030000 2000>;
interrupts = <38 86>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&lcdif_24bit_pins_a
+ &lcdif_pins_evk>;
+ lcd-supply = <&reg_lcd_3v3>;
display: display {
bits-per-pixel = <32>;
diff --git a/arch/arm/mach-imx/clk-imx6sl.c b/arch/arm/mach-imx/clk-imx6sl.c
index 4c367f4711fc..b634990362ab 100644
--- a/arch/arm/mach-imx/clk-imx6sl.c
+++ b/arch/arm/mach-imx/clk-imx6sl.c
@@ -280,5 +280,11 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node)
WARN_ON(!base);
irq = irq_of_parse_and_map(np, 0);
mxc_timer_init(base, irq);
+
+ /* Initialize Video PLLs to valid frequency (650MHz). */
+ clk_set_rate(clks[IMX6SL_CLK_PLL5_VIDEO_DIV], 650000000);
+ /* set PLL5 video as lcdif pix parent clock */
+ clk_set_parent(clks[IMX6SL_CLK_LCDIF_PIX_SEL],
+ clks[IMX6SL_CLK_PLL5_VIDEO_DIV]);
}
CLK_OF_DECLARE(imx6sl, "fsl,imx6sl-ccm", imx6sl_clocks_init);
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 120811cbc063..722208120c84 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -2424,7 +2424,7 @@ config FB_JZ4740
config FB_MXS
tristate "MXS LCD framebuffer support"
- depends on FB && ARCH_MXS
+ depends on FB && (ARCH_MXS || ARCH_MXC)
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
diff --git a/drivers/video/mxsfb.c b/drivers/video/mxsfb.c
index 21223d475b39..5e94efeaa1d2 100644
--- a/drivers/video/mxsfb.c
+++ b/drivers/video/mxsfb.c
@@ -4,7 +4,7 @@
* This code is based on:
* Author: Vitaly Wool <vital@embeddedalley.com>
*
- * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008-2013 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)
{
@@ -352,8 +374,10 @@ 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);
/* if it was disabled, re-enable the mode again */
writel(CTRL_DOTCLK_MODE, host->base + LCDC_CTRL + REG_SET);
@@ -377,6 +401,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
@@ -394,7 +419,7 @@ static void mxsfb_disable_controller(struct fb_info *fb_info)
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;
@@ -413,6 +438,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;
@@ -576,6 +603,8 @@ 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:
@@ -595,6 +624,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 */
@@ -626,6 +657,8 @@ static int mxsfb_restore_mode(struct mxsfb_info *host)
u32 transfer_count, vdctrl0, vdctrl2, vdctrl3, vdctrl4, ctrl;
struct fb_videomode vmode;
+ clk_enable_axi(host);
+
/* Only restore the mode when the controller is running */
ctrl = readl(host->base + LCDC_CTRL);
if (!(ctrl & CTRL_RUN))
@@ -654,7 +687,7 @@ static int mxsfb_restore_mode(struct mxsfb_info *host)
fb_info->var.bits_per_pixel = bits_per_pixel;
- vmode.pixclock = KHZ2PICOS(clk_get_rate(host->clk) / 1000U);
+ vmode.pixclock = KHZ2PICOS(clk_get_rate(host->clk_pix) / 1000U);
vmode.hsync_len = get_hsync_pulse_width(host, vdctrl2);
vmode.left_margin = GET_HOR_WAIT_CNT(vdctrl3) - vmode.hsync_len;
vmode.right_margin = VDCTRL2_GET_HSYNC_PERIOD(vdctrl2) - vmode.hsync_len -
@@ -701,7 +734,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;
@@ -915,9 +948,15 @@ static int mxsfb_probe(struct platform_device *pdev)
goto fb_release;
}
- 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;
}
@@ -965,7 +1004,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_destroy_modelist(&fb_info->modelist);
fb_release:
framebuffer_release(fb_info);
@@ -996,11 +1035,13 @@ 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);
+ clk_disable_axi(host);
}
static struct platform_driver mxsfb_driver = {