diff options
author | Robby Cai <R63905@freescale.com> | 2013-08-22 02:35:09 -0400 |
---|---|---|
committer | Nitin Garg <nitin.garg@freescale.com> | 2014-04-16 09:01:27 -0400 |
commit | 423273b4437f3df3201856afa93fd93e87d44c67 (patch) | |
tree | 77a8d420848a2d7102cd42bdb7be98c9567db92b /drivers/video | |
parent | d8a07074df2009874fdad284b8ceedb7244a8a18 (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>
Diffstat (limited to 'drivers/video')
-rw-r--r-- | drivers/video/Kconfig | 2 | ||||
-rw-r--r-- | drivers/video/mxsfb.c | 63 |
2 files changed, 53 insertions, 12 deletions
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 | |||
2424 | 2424 | ||
2425 | config FB_MXS | 2425 | config FB_MXS |
2426 | tristate "MXS LCD framebuffer support" | 2426 | tristate "MXS LCD framebuffer support" |
2427 | depends on FB && ARCH_MXS | 2427 | depends on FB && (ARCH_MXS || ARCH_MXC) |
2428 | select FB_CFB_FILLRECT | 2428 | select FB_CFB_FILLRECT |
2429 | select FB_CFB_COPYAREA | 2429 | select FB_CFB_COPYAREA |
2430 | select FB_CFB_IMAGEBLIT | 2430 | 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 @@ | |||
4 | * This code is based on: | 4 | * This code is based on: |
5 | * Author: Vitaly Wool <vital@embeddedalley.com> | 5 | * Author: Vitaly Wool <vital@embeddedalley.com> |
6 | * | 6 | * |
7 | * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. | 7 | * Copyright 2008-2013 Freescale Semiconductor, Inc. All Rights Reserved. |
8 | * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. | 8 | * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or | 10 | * This program is free software; you can redistribute it and/or |
@@ -171,7 +171,9 @@ struct mxsfb_devdata { | |||
171 | struct mxsfb_info { | 171 | struct mxsfb_info { |
172 | struct fb_info fb_info; | 172 | struct fb_info fb_info; |
173 | struct platform_device *pdev; | 173 | struct platform_device *pdev; |
174 | struct clk *clk; | 174 | struct clk *clk_pix; |
175 | struct clk *clk_axi; | ||
176 | bool clk_axi_enabled; | ||
175 | void __iomem *base; /* registers */ | 177 | void __iomem *base; /* registers */ |
176 | unsigned allocated_size; | 178 | unsigned allocated_size; |
177 | int enabled; | 179 | int enabled; |
@@ -208,6 +210,26 @@ static const struct mxsfb_devdata mxsfb_devdata[] = { | |||
208 | 210 | ||
209 | #define to_imxfb_host(x) (container_of(x, struct mxsfb_info, fb_info)) | 211 | #define to_imxfb_host(x) (container_of(x, struct mxsfb_info, fb_info)) |
210 | 212 | ||
213 | /* enable lcdif axi clock */ | ||
214 | static inline void clk_enable_axi(struct mxsfb_info *host) | ||
215 | { | ||
216 | if (!host->clk_axi_enabled && host && | ||
217 | host->clk_axi && !IS_ERR(host->clk_axi)) { | ||
218 | clk_prepare_enable(host->clk_axi); | ||
219 | host->clk_axi_enabled = true; | ||
220 | } | ||
221 | } | ||
222 | |||
223 | /* disable lcdif axi clock */ | ||
224 | static inline void clk_disable_axi(struct mxsfb_info *host) | ||
225 | { | ||
226 | if (host->clk_axi_enabled && host && | ||
227 | host->clk_axi && !IS_ERR(host->clk_axi)) { | ||
228 | clk_disable_unprepare(host->clk_axi); | ||
229 | host->clk_axi_enabled = false; | ||
230 | } | ||
231 | } | ||
232 | |||
211 | /* mask and shift depends on architecture */ | 233 | /* mask and shift depends on architecture */ |
212 | static inline u32 set_hsync_pulse_width(struct mxsfb_info *host, unsigned val) | 234 | static inline u32 set_hsync_pulse_width(struct mxsfb_info *host, unsigned val) |
213 | { | 235 | { |
@@ -352,8 +374,10 @@ static void mxsfb_enable_controller(struct fb_info *fb_info) | |||
352 | } | 374 | } |
353 | } | 375 | } |
354 | 376 | ||
355 | clk_prepare_enable(host->clk); | 377 | clk_enable_axi(host); |
356 | clk_set_rate(host->clk, PICOS2KHZ(fb_info->var.pixclock) * 1000U); | 378 | |
379 | clk_prepare_enable(host->clk_pix); | ||
380 | clk_set_rate(host->clk_pix, PICOS2KHZ(fb_info->var.pixclock) * 1000U); | ||
357 | 381 | ||
358 | /* if it was disabled, re-enable the mode again */ | 382 | /* if it was disabled, re-enable the mode again */ |
359 | writel(CTRL_DOTCLK_MODE, host->base + LCDC_CTRL + REG_SET); | 383 | writel(CTRL_DOTCLK_MODE, host->base + LCDC_CTRL + REG_SET); |
@@ -377,6 +401,7 @@ static void mxsfb_disable_controller(struct fb_info *fb_info) | |||
377 | 401 | ||
378 | dev_dbg(&host->pdev->dev, "%s\n", __func__); | 402 | dev_dbg(&host->pdev->dev, "%s\n", __func__); |
379 | 403 | ||
404 | clk_enable_axi(host); | ||
380 | /* | 405 | /* |
381 | * Even if we disable the controller here, it will still continue | 406 | * Even if we disable the controller here, it will still continue |
382 | * until its FIFOs are running out of data | 407 | * until its FIFOs are running out of data |
@@ -394,7 +419,7 @@ static void mxsfb_disable_controller(struct fb_info *fb_info) | |||
394 | reg = readl(host->base + LCDC_VDCTRL4); | 419 | reg = readl(host->base + LCDC_VDCTRL4); |
395 | writel(reg & ~VDCTRL4_SYNC_SIGNALS_ON, host->base + LCDC_VDCTRL4); | 420 | writel(reg & ~VDCTRL4_SYNC_SIGNALS_ON, host->base + LCDC_VDCTRL4); |
396 | 421 | ||
397 | clk_disable_unprepare(host->clk); | 422 | clk_disable_unprepare(host->clk_pix); |
398 | 423 | ||
399 | host->enabled = 0; | 424 | host->enabled = 0; |
400 | 425 | ||
@@ -413,6 +438,8 @@ static int mxsfb_set_par(struct fb_info *fb_info) | |||
413 | int line_size, fb_size; | 438 | int line_size, fb_size; |
414 | int reenable = 0; | 439 | int reenable = 0; |
415 | 440 | ||
441 | clk_enable_axi(host); | ||
442 | |||
416 | line_size = fb_info->var.xres * (fb_info->var.bits_per_pixel >> 3); | 443 | line_size = fb_info->var.xres * (fb_info->var.bits_per_pixel >> 3); |
417 | fb_size = fb_info->var.yres_virtual * line_size; | 444 | fb_size = fb_info->var.yres_virtual * line_size; |
418 | 445 | ||
@@ -576,6 +603,8 @@ static int mxsfb_blank(int blank, struct fb_info *fb_info) | |||
576 | case FB_BLANK_NORMAL: | 603 | case FB_BLANK_NORMAL: |
577 | if (host->enabled) | 604 | if (host->enabled) |
578 | mxsfb_disable_controller(fb_info); | 605 | mxsfb_disable_controller(fb_info); |
606 | |||
607 | clk_disable_axi(host); | ||
579 | break; | 608 | break; |
580 | 609 | ||
581 | case FB_BLANK_UNBLANK: | 610 | case FB_BLANK_UNBLANK: |
@@ -595,6 +624,8 @@ static int mxsfb_pan_display(struct fb_var_screeninfo *var, | |||
595 | if (var->xoffset != 0) | 624 | if (var->xoffset != 0) |
596 | return -EINVAL; | 625 | return -EINVAL; |
597 | 626 | ||
627 | clk_enable_axi(host); | ||
628 | |||
598 | offset = fb_info->fix.line_length * var->yoffset; | 629 | offset = fb_info->fix.line_length * var->yoffset; |
599 | 630 | ||
600 | /* update on next VSYNC */ | 631 | /* update on next VSYNC */ |
@@ -626,6 +657,8 @@ static int mxsfb_restore_mode(struct mxsfb_info *host) | |||
626 | u32 transfer_count, vdctrl0, vdctrl2, vdctrl3, vdctrl4, ctrl; | 657 | u32 transfer_count, vdctrl0, vdctrl2, vdctrl3, vdctrl4, ctrl; |
627 | struct fb_videomode vmode; | 658 | struct fb_videomode vmode; |
628 | 659 | ||
660 | clk_enable_axi(host); | ||
661 | |||
629 | /* Only restore the mode when the controller is running */ | 662 | /* Only restore the mode when the controller is running */ |
630 | ctrl = readl(host->base + LCDC_CTRL); | 663 | ctrl = readl(host->base + LCDC_CTRL); |
631 | if (!(ctrl & CTRL_RUN)) | 664 | if (!(ctrl & CTRL_RUN)) |
@@ -654,7 +687,7 @@ static int mxsfb_restore_mode(struct mxsfb_info *host) | |||
654 | 687 | ||
655 | fb_info->var.bits_per_pixel = bits_per_pixel; | 688 | fb_info->var.bits_per_pixel = bits_per_pixel; |
656 | 689 | ||
657 | vmode.pixclock = KHZ2PICOS(clk_get_rate(host->clk) / 1000U); | 690 | vmode.pixclock = KHZ2PICOS(clk_get_rate(host->clk_pix) / 1000U); |
658 | vmode.hsync_len = get_hsync_pulse_width(host, vdctrl2); | 691 | vmode.hsync_len = get_hsync_pulse_width(host, vdctrl2); |
659 | vmode.left_margin = GET_HOR_WAIT_CNT(vdctrl3) - vmode.hsync_len; | 692 | vmode.left_margin = GET_HOR_WAIT_CNT(vdctrl3) - vmode.hsync_len; |
660 | vmode.right_margin = VDCTRL2_GET_HSYNC_PERIOD(vdctrl2) - vmode.hsync_len - | 693 | vmode.right_margin = VDCTRL2_GET_HSYNC_PERIOD(vdctrl2) - vmode.hsync_len - |
@@ -701,7 +734,7 @@ static int mxsfb_restore_mode(struct mxsfb_info *host) | |||
701 | line_count = fb_info->fix.smem_len / fb_info->fix.line_length; | 734 | line_count = fb_info->fix.smem_len / fb_info->fix.line_length; |
702 | fb_info->fix.ypanstep = 1; | 735 | fb_info->fix.ypanstep = 1; |
703 | 736 | ||
704 | clk_prepare_enable(host->clk); | 737 | clk_prepare_enable(host->clk_pix); |
705 | host->enabled = 1; | 738 | host->enabled = 1; |
706 | 739 | ||
707 | return 0; | 740 | return 0; |
@@ -915,9 +948,15 @@ static int mxsfb_probe(struct platform_device *pdev) | |||
915 | goto fb_release; | 948 | goto fb_release; |
916 | } | 949 | } |
917 | 950 | ||
918 | host->clk = devm_clk_get(&host->pdev->dev, NULL); | 951 | host->clk_pix = devm_clk_get(&host->pdev->dev, "pix"); |
919 | if (IS_ERR(host->clk)) { | 952 | if (IS_ERR(host->clk_pix)) { |
920 | ret = PTR_ERR(host->clk); | 953 | ret = PTR_ERR(host->clk_pix); |
954 | goto fb_release; | ||
955 | } | ||
956 | |||
957 | host->clk_axi = devm_clk_get(&host->pdev->dev, "axi"); | ||
958 | if (IS_ERR(host->clk_axi)) { | ||
959 | ret = PTR_ERR(host->clk_axi); | ||
921 | goto fb_release; | 960 | goto fb_release; |
922 | } | 961 | } |
923 | 962 | ||
@@ -965,7 +1004,7 @@ static int mxsfb_probe(struct platform_device *pdev) | |||
965 | 1004 | ||
966 | fb_destroy: | 1005 | fb_destroy: |
967 | if (host->enabled) | 1006 | if (host->enabled) |
968 | clk_disable_unprepare(host->clk); | 1007 | clk_disable_unprepare(host->clk_pix); |
969 | fb_destroy_modelist(&fb_info->modelist); | 1008 | fb_destroy_modelist(&fb_info->modelist); |
970 | fb_release: | 1009 | fb_release: |
971 | framebuffer_release(fb_info); | 1010 | framebuffer_release(fb_info); |
@@ -996,11 +1035,13 @@ static void mxsfb_shutdown(struct platform_device *pdev) | |||
996 | struct fb_info *fb_info = platform_get_drvdata(pdev); | 1035 | struct fb_info *fb_info = platform_get_drvdata(pdev); |
997 | struct mxsfb_info *host = to_imxfb_host(fb_info); | 1036 | struct mxsfb_info *host = to_imxfb_host(fb_info); |
998 | 1037 | ||
1038 | clk_enable_axi(host); | ||
999 | /* | 1039 | /* |
1000 | * Force stop the LCD controller as keeping it running during reboot | 1040 | * Force stop the LCD controller as keeping it running during reboot |
1001 | * might interfere with the BootROM's boot mode pads sampling. | 1041 | * might interfere with the BootROM's boot mode pads sampling. |
1002 | */ | 1042 | */ |
1003 | writel(CTRL_RUN, host->base + LCDC_CTRL + REG_CLR); | 1043 | writel(CTRL_RUN, host->base + LCDC_CTRL + REG_CLR); |
1044 | clk_disable_axi(host); | ||
1004 | } | 1045 | } |
1005 | 1046 | ||
1006 | static struct platform_driver mxsfb_driver = { | 1047 | static struct platform_driver mxsfb_driver = { |