From c0b90a31efe30987ab4bb21298b410913779e62f Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 15 Jan 2009 15:37:22 +0100 Subject: imxfb: add platform specific init/exit functions Signed-off-by: Sascha Hauer --- drivers/video/imxfb.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers/video/imxfb.c') diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c index d58c68cd456e..629d66f32300 100644 --- a/drivers/video/imxfb.c +++ b/drivers/video/imxfb.c @@ -650,6 +650,12 @@ static int __init imxfb_probe(struct platform_device *pdev) info->fix.smem_start = fbi->screen_dma; } + if (pdata->init) { + ret = pdata->init(fbi->pdev); + if (ret) + goto failed_platform_init; + } + /* * This makes sure that our colour bitfield * descriptors are correctly initialised. @@ -674,6 +680,9 @@ static int __init imxfb_probe(struct platform_device *pdev) failed_register: fb_dealloc_cmap(&info->cmap); failed_cmap: + if (pdata->exit) + pdata->exit(fbi->pdev); +failed_platform_init: if (!pdata->fixed_screen_cpu) dma_free_writecombine(&pdev->dev,fbi->map_size,fbi->map_cpu, fbi->map_dma); @@ -691,6 +700,7 @@ failed_init: static int __devexit imxfb_remove(struct platform_device *pdev) { + struct imx_fb_platform_data *pdata; struct fb_info *info = platform_get_drvdata(pdev); struct imxfb_info *fbi = info->par; struct resource *res; @@ -701,6 +711,10 @@ static int __devexit imxfb_remove(struct platform_device *pdev) unregister_framebuffer(info); + pdata = pdev->dev.platform_data; + if (pdata->exit) + pdata->exit(fbi->pdev); + fb_dealloc_cmap(&info->cmap); kfree(info->pseudo_palette); framebuffer_release(info); -- cgit v1.2.3 From 1512222b105beaff7b7fe11aa4220bcd0088e421 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Mon, 26 Jan 2009 17:31:02 +0100 Subject: imxfb: add 18 bit support v2: As pointed out by Hans J. Koch we have to claim we can do 24bit to make software like X work. We are lucky on i.MX that 18bit support has the necessary gaps in the fields to do so. Signed-off-by: Sascha Hauer --- drivers/video/imxfb.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) (limited to 'drivers/video/imxfb.c') diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c index 629d66f32300..5c61286d7ff5 100644 --- a/drivers/video/imxfb.c +++ b/drivers/video/imxfb.c @@ -14,7 +14,6 @@ * linux-arm-kernel@lists.arm.linux.org.uk */ - #include #include #include @@ -159,6 +158,17 @@ struct imxfb_info { #define MIN_XRES 64 #define MIN_YRES 64 +/* Actually this really is 18bit support, the lowest 2 bits of each colour + * are unused in hardware. We claim to have 24bit support to make software + * like X work, which does not support 18bit. + */ +static struct imxfb_rgb def_rgb_18 = { + .red = {.offset = 16, .length = 8,}, + .green = {.offset = 8, .length = 8,}, + .blue = {.offset = 0, .length = 8,}, + .transp = {.offset = 0, .length = 0,}, +}; + static struct imxfb_rgb def_rgb_16_tft = { .red = {.offset = 11, .length = 5,}, .green = {.offset = 5, .length = 6,}, @@ -286,6 +296,9 @@ static int imxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) pr_debug("var->bits_per_pixel=%d\n", var->bits_per_pixel); switch (var->bits_per_pixel) { + case 32: + rgb = &def_rgb_18; + break; case 16: default: if (readl(fbi->regs + LCDC_PCR) & PCR_TFT) @@ -327,9 +340,7 @@ static int imxfb_set_par(struct fb_info *info) struct imxfb_info *fbi = info->par; struct fb_var_screeninfo *var = &info->var; - pr_debug("set_par\n"); - - if (var->bits_per_pixel == 16) + if (var->bits_per_pixel == 16 || var->bits_per_pixel == 32) info->fix.visual = FB_VISUAL_TRUECOLOR; else if (!fbi->cmap_static) info->fix.visual = FB_VISUAL_PSEUDOCOLOR; -- cgit v1.2.3 From 1d0f98709347c4babac08dd933466674e089f188 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Mon, 26 Jan 2009 17:29:10 +0100 Subject: imxfb: add mx27 support Signed-off-by: Sascha Hauer --- drivers/video/imxfb.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) (limited to 'drivers/video/imxfb.c') diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c index 5c61286d7ff5..9dd27576db71 100644 --- a/drivers/video/imxfb.c +++ b/drivers/video/imxfb.c @@ -43,7 +43,12 @@ #define LCDC_SIZE 0x04 #define SIZE_XMAX(x) ((((x) >> 4) & 0x3f) << 20) + +#ifdef CONFIG_ARCH_MX1 #define SIZE_YMAX(y) ((y) & 0x1ff) +#else +#define SIZE_YMAX(y) ((y) & 0x3ff) +#endif #define LCDC_VPW 0x08 #define VPW_VPW(x) ((x) & 0x3ff) @@ -53,7 +58,12 @@ #define CPOS_CC0 (1<<30) #define CPOS_OP (1<<28) #define CPOS_CXP(x) (((x) & 3ff) << 16) + +#ifdef CONFIG_ARCH_MX1 #define CPOS_CYP(y) ((y) & 0x1ff) +#else +#define CPOS_CYP(y) ((y) & 0x3ff) +#endif #define LCDC_LCWHB 0x10 #define LCWHB_BK_EN (1<<31) @@ -62,9 +72,16 @@ #define LCWHB_BD(x) ((x) & 0xff) #define LCDC_LCHCC 0x14 + +#ifdef CONFIG_ARCH_MX1 #define LCHCC_CUR_COL_R(r) (((r) & 0x1f) << 11) #define LCHCC_CUR_COL_G(g) (((g) & 0x3f) << 5) #define LCHCC_CUR_COL_B(b) ((b) & 0x1f) +#else +#define LCHCC_CUR_COL_R(r) (((r) & 0x3f) << 12) +#define LCHCC_CUR_COL_G(g) (((g) & 0x3f) << 6) +#define LCHCC_CUR_COL_B(b) ((b) & 0x3f) +#endif #define LCDC_PCR 0x18 @@ -91,7 +108,13 @@ /* bit fields in imxfb.h */ #define LCDC_RMCR 0x34 + +#ifdef CONFIG_ARCH_MX1 #define RMCR_LCDC_EN (1<<1) +#else +#define RMCR_LCDC_EN 0 +#endif + #define RMCR_SELF_REF (1<<0) #define LCDC_LCDICR 0x38 @@ -365,10 +388,6 @@ static void imxfb_enable_controller(struct imxfb_info *fbi) { pr_debug("Enabling LCD controller\n"); - /* initialize LCDC */ - writel(readl(fbi->regs + LCDC_RMCR) & ~RMCR_LCDC_EN, - fbi->regs + LCDC_RMCR); /* just to be safe... */ - writel(fbi->screen_dma, fbi->regs + LCDC_SSA); /* physical screen start address */ -- cgit v1.2.3 From 7e8549bcee00d92040904361cb1840c7a5eda615 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Sat, 14 Feb 2009 16:29:38 +0100 Subject: imxfb: Fix margin settings The var->hsync_len, var->right_margin and var->left_margin fields should contain the real values, not the hardware dependent values. Signed-off-by: Sascha Hauer --- drivers/video/imxfb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/video/imxfb.c') diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c index 9dd27576db71..bd1cb75cd14b 100644 --- a/drivers/video/imxfb.c +++ b/drivers/video/imxfb.c @@ -495,9 +495,9 @@ static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *inf info->fix.id, var->lower_margin); #endif - writel(HCR_H_WIDTH(var->hsync_len) | - HCR_H_WAIT_1(var->right_margin) | - HCR_H_WAIT_2(var->left_margin), + writel(HCR_H_WIDTH(var->hsync_len - 1) | + HCR_H_WAIT_1(var->right_margin - 1) | + HCR_H_WAIT_2(var->left_margin - 3), fbi->regs + LCDC_HCR); writel(VCR_V_WIDTH(var->vsync_len) | -- cgit v1.2.3 From f909ef6437a8388e3f1272c67ee29071f930bd6b Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 15 Jan 2009 15:21:00 +0100 Subject: imxfb: add clock support v2: Added change from Martin Fuzzey: pixclock should be in pico seconds instead of MHz. Signed-off-by: Sascha Hauer --- drivers/video/imxfb.c | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) (limited to 'drivers/video/imxfb.c') diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c index bd1cb75cd14b..8f7a2b2c78e7 100644 --- a/drivers/video/imxfb.c +++ b/drivers/video/imxfb.c @@ -26,9 +26,11 @@ #include #include #include +#include #include #include #include +#include #include @@ -141,6 +143,7 @@ struct imxfb_rgb { struct imxfb_info { struct platform_device *pdev; void __iomem *regs; + struct clk *clk; u_int max_bpp; u_int max_xres; @@ -403,6 +406,8 @@ static void imxfb_enable_controller(struct imxfb_info *fbi) writel(RMCR_LCDC_EN, fbi->regs + LCDC_RMCR); + clk_enable(fbi->clk); + if (fbi->backlight_power) fbi->backlight_power(1); if (fbi->lcd_power) @@ -418,6 +423,8 @@ static void imxfb_disable_controller(struct imxfb_info *fbi) if (fbi->lcd_power) fbi->lcd_power(0); + clk_disable(fbi->clk); + writel(0, fbi->regs + LCDC_RMCR); } @@ -461,6 +468,9 @@ static struct fb_ops imxfb_ops = { static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *info) { struct imxfb_info *fbi = info->par; + unsigned int pcr, lcd_clk; + unsigned long long tmp; + pr_debug("var: xres=%d hslen=%d lm=%d rm=%d\n", var->xres, var->hsync_len, var->left_margin, var->right_margin); @@ -507,7 +517,23 @@ static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *inf writel(SIZE_XMAX(var->xres) | SIZE_YMAX(var->yres), fbi->regs + LCDC_SIZE); - writel(fbi->pcr, fbi->regs + LCDC_PCR); + + lcd_clk = clk_get_rate(fbi->clk); + tmp = var->pixclock * (unsigned long long)lcd_clk; + do_div(tmp, 1000000); + if (do_div(tmp, 1000000) > 500000) + tmp++; + pcr = (unsigned int)tmp; + if (--pcr > 0x3F) { + pcr = 0x3F; + printk(KERN_WARNING "Must limit pixel clock to %uHz\n", + lcd_clk / pcr); + } + + /* add sync polarities */ + pcr |= fbi->pcr & ~0x3F; + + writel(pcr, fbi->regs + LCDC_PCR); writel(fbi->pwmr, fbi->regs + LCDC_PWMR); writel(fbi->lscr1, fbi->regs + LCDC_LSCR1); writel(fbi->dmacr, fbi->regs + LCDC_DMACR); @@ -649,6 +675,13 @@ static int __init imxfb_probe(struct platform_device *pdev) goto failed_req; } + fbi->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(fbi->clk)) { + ret = PTR_ERR(fbi->clk);; + dev_err(&pdev->dev, "unable to get clock: %d\n", ret); + goto failed_getclock; + } + fbi->regs = ioremap(res->start, resource_size(res)); if (fbi->regs == NULL) { printk(KERN_ERR"Cannot map frame buffer registers\n"); @@ -717,6 +750,8 @@ failed_platform_init: dma_free_writecombine(&pdev->dev,fbi->map_size,fbi->map_cpu, fbi->map_dma); failed_map: + clk_put(fbi->clk); +failed_getclock: iounmap(fbi->regs); failed_ioremap: release_mem_region(res->start, res->end - res->start); @@ -751,6 +786,9 @@ static int __devexit imxfb_remove(struct platform_device *pdev) iounmap(fbi->regs); release_mem_region(res->start, res->end - res->start + 1); + clk_disable(fbi->clk); + clk_put(fbi->clk); + platform_set_drvdata(pdev, NULL); return 0; -- cgit v1.2.3 From 4d1e4e5a6387aad97590e2da9c6db1350f22f63a Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 26 Mar 2009 12:38:26 +0100 Subject: imxfb: Fix TFT mode We read from the PCR reg to determine whether to use TFT mode or not. This is not possible because it may not have been initialized with the correct value yet. Select it using fbi->pcr instead. Signed-off-by: Sascha Hauer --- drivers/video/imxfb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/video/imxfb.c') diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c index 8f7a2b2c78e7..15a0ee6d8e23 100644 --- a/drivers/video/imxfb.c +++ b/drivers/video/imxfb.c @@ -327,7 +327,7 @@ static int imxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) break; case 16: default: - if (readl(fbi->regs + LCDC_PCR) & PCR_TFT) + if (fbi->pcr & PCR_TFT) rgb = &def_rgb_16_tft; else rgb = &def_rgb_16_stn; -- cgit v1.2.3