diff options
author | Robby Cai <R63905@freescale.com> | 2013-08-22 14:35:09 +0800 |
---|---|---|
committer | Jason Liu <r64343@freescale.com> | 2013-10-30 09:55:02 +0800 |
commit | 2b2df2753f6dfb6345e1eb3124f18d6d4dd9e08e (patch) | |
tree | a289c54bb50066c9e3909bb58fb47c6f818d04cd | |
parent | 48a9dddc8f9fd9a28f28d7f9172a8f0262ebe079 (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.txt | 7 | ||||
-rw-r--r-- | arch/arm/mach-imx/clk-imx6sl.c | 6 | ||||
-rw-r--r-- | drivers/video/Kconfig | 2 | ||||
-rw-r--r-- | drivers/video/mxsfb.c | 63 |
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 = <®_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 = { |