diff options
Diffstat (limited to 'drivers/video/imxfb.c')
-rw-r--r-- | drivers/video/imxfb.c | 108 |
1 files changed, 95 insertions, 13 deletions
diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c index d58c68cd456e..15a0ee6d8e23 100644 --- a/drivers/video/imxfb.c +++ b/drivers/video/imxfb.c | |||
@@ -14,7 +14,6 @@ | |||
14 | * linux-arm-kernel@lists.arm.linux.org.uk | 14 | * linux-arm-kernel@lists.arm.linux.org.uk |
15 | */ | 15 | */ |
16 | 16 | ||
17 | |||
18 | #include <linux/module.h> | 17 | #include <linux/module.h> |
19 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
20 | #include <linux/errno.h> | 19 | #include <linux/errno.h> |
@@ -27,9 +26,11 @@ | |||
27 | #include <linux/init.h> | 26 | #include <linux/init.h> |
28 | #include <linux/ioport.h> | 27 | #include <linux/ioport.h> |
29 | #include <linux/cpufreq.h> | 28 | #include <linux/cpufreq.h> |
29 | #include <linux/clk.h> | ||
30 | #include <linux/platform_device.h> | 30 | #include <linux/platform_device.h> |
31 | #include <linux/dma-mapping.h> | 31 | #include <linux/dma-mapping.h> |
32 | #include <linux/io.h> | 32 | #include <linux/io.h> |
33 | #include <linux/math64.h> | ||
33 | 34 | ||
34 | #include <mach/imxfb.h> | 35 | #include <mach/imxfb.h> |
35 | 36 | ||
@@ -44,7 +45,12 @@ | |||
44 | 45 | ||
45 | #define LCDC_SIZE 0x04 | 46 | #define LCDC_SIZE 0x04 |
46 | #define SIZE_XMAX(x) ((((x) >> 4) & 0x3f) << 20) | 47 | #define SIZE_XMAX(x) ((((x) >> 4) & 0x3f) << 20) |
48 | |||
49 | #ifdef CONFIG_ARCH_MX1 | ||
47 | #define SIZE_YMAX(y) ((y) & 0x1ff) | 50 | #define SIZE_YMAX(y) ((y) & 0x1ff) |
51 | #else | ||
52 | #define SIZE_YMAX(y) ((y) & 0x3ff) | ||
53 | #endif | ||
48 | 54 | ||
49 | #define LCDC_VPW 0x08 | 55 | #define LCDC_VPW 0x08 |
50 | #define VPW_VPW(x) ((x) & 0x3ff) | 56 | #define VPW_VPW(x) ((x) & 0x3ff) |
@@ -54,7 +60,12 @@ | |||
54 | #define CPOS_CC0 (1<<30) | 60 | #define CPOS_CC0 (1<<30) |
55 | #define CPOS_OP (1<<28) | 61 | #define CPOS_OP (1<<28) |
56 | #define CPOS_CXP(x) (((x) & 3ff) << 16) | 62 | #define CPOS_CXP(x) (((x) & 3ff) << 16) |
63 | |||
64 | #ifdef CONFIG_ARCH_MX1 | ||
57 | #define CPOS_CYP(y) ((y) & 0x1ff) | 65 | #define CPOS_CYP(y) ((y) & 0x1ff) |
66 | #else | ||
67 | #define CPOS_CYP(y) ((y) & 0x3ff) | ||
68 | #endif | ||
58 | 69 | ||
59 | #define LCDC_LCWHB 0x10 | 70 | #define LCDC_LCWHB 0x10 |
60 | #define LCWHB_BK_EN (1<<31) | 71 | #define LCWHB_BK_EN (1<<31) |
@@ -63,9 +74,16 @@ | |||
63 | #define LCWHB_BD(x) ((x) & 0xff) | 74 | #define LCWHB_BD(x) ((x) & 0xff) |
64 | 75 | ||
65 | #define LCDC_LCHCC 0x14 | 76 | #define LCDC_LCHCC 0x14 |
77 | |||
78 | #ifdef CONFIG_ARCH_MX1 | ||
66 | #define LCHCC_CUR_COL_R(r) (((r) & 0x1f) << 11) | 79 | #define LCHCC_CUR_COL_R(r) (((r) & 0x1f) << 11) |
67 | #define LCHCC_CUR_COL_G(g) (((g) & 0x3f) << 5) | 80 | #define LCHCC_CUR_COL_G(g) (((g) & 0x3f) << 5) |
68 | #define LCHCC_CUR_COL_B(b) ((b) & 0x1f) | 81 | #define LCHCC_CUR_COL_B(b) ((b) & 0x1f) |
82 | #else | ||
83 | #define LCHCC_CUR_COL_R(r) (((r) & 0x3f) << 12) | ||
84 | #define LCHCC_CUR_COL_G(g) (((g) & 0x3f) << 6) | ||
85 | #define LCHCC_CUR_COL_B(b) ((b) & 0x3f) | ||
86 | #endif | ||
69 | 87 | ||
70 | #define LCDC_PCR 0x18 | 88 | #define LCDC_PCR 0x18 |
71 | 89 | ||
@@ -92,7 +110,13 @@ | |||
92 | /* bit fields in imxfb.h */ | 110 | /* bit fields in imxfb.h */ |
93 | 111 | ||
94 | #define LCDC_RMCR 0x34 | 112 | #define LCDC_RMCR 0x34 |
113 | |||
114 | #ifdef CONFIG_ARCH_MX1 | ||
95 | #define RMCR_LCDC_EN (1<<1) | 115 | #define RMCR_LCDC_EN (1<<1) |
116 | #else | ||
117 | #define RMCR_LCDC_EN 0 | ||
118 | #endif | ||
119 | |||
96 | #define RMCR_SELF_REF (1<<0) | 120 | #define RMCR_SELF_REF (1<<0) |
97 | 121 | ||
98 | #define LCDC_LCDICR 0x38 | 122 | #define LCDC_LCDICR 0x38 |
@@ -119,6 +143,7 @@ struct imxfb_rgb { | |||
119 | struct imxfb_info { | 143 | struct imxfb_info { |
120 | struct platform_device *pdev; | 144 | struct platform_device *pdev; |
121 | void __iomem *regs; | 145 | void __iomem *regs; |
146 | struct clk *clk; | ||
122 | 147 | ||
123 | u_int max_bpp; | 148 | u_int max_bpp; |
124 | u_int max_xres; | 149 | u_int max_xres; |
@@ -159,6 +184,17 @@ struct imxfb_info { | |||
159 | #define MIN_XRES 64 | 184 | #define MIN_XRES 64 |
160 | #define MIN_YRES 64 | 185 | #define MIN_YRES 64 |
161 | 186 | ||
187 | /* Actually this really is 18bit support, the lowest 2 bits of each colour | ||
188 | * are unused in hardware. We claim to have 24bit support to make software | ||
189 | * like X work, which does not support 18bit. | ||
190 | */ | ||
191 | static struct imxfb_rgb def_rgb_18 = { | ||
192 | .red = {.offset = 16, .length = 8,}, | ||
193 | .green = {.offset = 8, .length = 8,}, | ||
194 | .blue = {.offset = 0, .length = 8,}, | ||
195 | .transp = {.offset = 0, .length = 0,}, | ||
196 | }; | ||
197 | |||
162 | static struct imxfb_rgb def_rgb_16_tft = { | 198 | static struct imxfb_rgb def_rgb_16_tft = { |
163 | .red = {.offset = 11, .length = 5,}, | 199 | .red = {.offset = 11, .length = 5,}, |
164 | .green = {.offset = 5, .length = 6,}, | 200 | .green = {.offset = 5, .length = 6,}, |
@@ -286,9 +322,12 @@ static int imxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | |||
286 | 322 | ||
287 | pr_debug("var->bits_per_pixel=%d\n", var->bits_per_pixel); | 323 | pr_debug("var->bits_per_pixel=%d\n", var->bits_per_pixel); |
288 | switch (var->bits_per_pixel) { | 324 | switch (var->bits_per_pixel) { |
325 | case 32: | ||
326 | rgb = &def_rgb_18; | ||
327 | break; | ||
289 | case 16: | 328 | case 16: |
290 | default: | 329 | default: |
291 | if (readl(fbi->regs + LCDC_PCR) & PCR_TFT) | 330 | if (fbi->pcr & PCR_TFT) |
292 | rgb = &def_rgb_16_tft; | 331 | rgb = &def_rgb_16_tft; |
293 | else | 332 | else |
294 | rgb = &def_rgb_16_stn; | 333 | rgb = &def_rgb_16_stn; |
@@ -327,9 +366,7 @@ static int imxfb_set_par(struct fb_info *info) | |||
327 | struct imxfb_info *fbi = info->par; | 366 | struct imxfb_info *fbi = info->par; |
328 | struct fb_var_screeninfo *var = &info->var; | 367 | struct fb_var_screeninfo *var = &info->var; |
329 | 368 | ||
330 | pr_debug("set_par\n"); | 369 | if (var->bits_per_pixel == 16 || var->bits_per_pixel == 32) |
331 | |||
332 | if (var->bits_per_pixel == 16) | ||
333 | info->fix.visual = FB_VISUAL_TRUECOLOR; | 370 | info->fix.visual = FB_VISUAL_TRUECOLOR; |
334 | else if (!fbi->cmap_static) | 371 | else if (!fbi->cmap_static) |
335 | info->fix.visual = FB_VISUAL_PSEUDOCOLOR; | 372 | info->fix.visual = FB_VISUAL_PSEUDOCOLOR; |
@@ -354,10 +391,6 @@ static void imxfb_enable_controller(struct imxfb_info *fbi) | |||
354 | { | 391 | { |
355 | pr_debug("Enabling LCD controller\n"); | 392 | pr_debug("Enabling LCD controller\n"); |
356 | 393 | ||
357 | /* initialize LCDC */ | ||
358 | writel(readl(fbi->regs + LCDC_RMCR) & ~RMCR_LCDC_EN, | ||
359 | fbi->regs + LCDC_RMCR); /* just to be safe... */ | ||
360 | |||
361 | writel(fbi->screen_dma, fbi->regs + LCDC_SSA); | 394 | writel(fbi->screen_dma, fbi->regs + LCDC_SSA); |
362 | 395 | ||
363 | /* physical screen start address */ | 396 | /* physical screen start address */ |
@@ -373,6 +406,8 @@ static void imxfb_enable_controller(struct imxfb_info *fbi) | |||
373 | 406 | ||
374 | writel(RMCR_LCDC_EN, fbi->regs + LCDC_RMCR); | 407 | writel(RMCR_LCDC_EN, fbi->regs + LCDC_RMCR); |
375 | 408 | ||
409 | clk_enable(fbi->clk); | ||
410 | |||
376 | if (fbi->backlight_power) | 411 | if (fbi->backlight_power) |
377 | fbi->backlight_power(1); | 412 | fbi->backlight_power(1); |
378 | if (fbi->lcd_power) | 413 | if (fbi->lcd_power) |
@@ -388,6 +423,8 @@ static void imxfb_disable_controller(struct imxfb_info *fbi) | |||
388 | if (fbi->lcd_power) | 423 | if (fbi->lcd_power) |
389 | fbi->lcd_power(0); | 424 | fbi->lcd_power(0); |
390 | 425 | ||
426 | clk_disable(fbi->clk); | ||
427 | |||
391 | writel(0, fbi->regs + LCDC_RMCR); | 428 | writel(0, fbi->regs + LCDC_RMCR); |
392 | } | 429 | } |
393 | 430 | ||
@@ -431,6 +468,9 @@ static struct fb_ops imxfb_ops = { | |||
431 | static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *info) | 468 | static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *info) |
432 | { | 469 | { |
433 | struct imxfb_info *fbi = info->par; | 470 | struct imxfb_info *fbi = info->par; |
471 | unsigned int pcr, lcd_clk; | ||
472 | unsigned long long tmp; | ||
473 | |||
434 | pr_debug("var: xres=%d hslen=%d lm=%d rm=%d\n", | 474 | pr_debug("var: xres=%d hslen=%d lm=%d rm=%d\n", |
435 | var->xres, var->hsync_len, | 475 | var->xres, var->hsync_len, |
436 | var->left_margin, var->right_margin); | 476 | var->left_margin, var->right_margin); |
@@ -465,9 +505,9 @@ static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *inf | |||
465 | info->fix.id, var->lower_margin); | 505 | info->fix.id, var->lower_margin); |
466 | #endif | 506 | #endif |
467 | 507 | ||
468 | writel(HCR_H_WIDTH(var->hsync_len) | | 508 | writel(HCR_H_WIDTH(var->hsync_len - 1) | |
469 | HCR_H_WAIT_1(var->right_margin) | | 509 | HCR_H_WAIT_1(var->right_margin - 1) | |
470 | HCR_H_WAIT_2(var->left_margin), | 510 | HCR_H_WAIT_2(var->left_margin - 3), |
471 | fbi->regs + LCDC_HCR); | 511 | fbi->regs + LCDC_HCR); |
472 | 512 | ||
473 | writel(VCR_V_WIDTH(var->vsync_len) | | 513 | writel(VCR_V_WIDTH(var->vsync_len) | |
@@ -477,7 +517,23 @@ static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *inf | |||
477 | 517 | ||
478 | writel(SIZE_XMAX(var->xres) | SIZE_YMAX(var->yres), | 518 | writel(SIZE_XMAX(var->xres) | SIZE_YMAX(var->yres), |
479 | fbi->regs + LCDC_SIZE); | 519 | fbi->regs + LCDC_SIZE); |
480 | writel(fbi->pcr, fbi->regs + LCDC_PCR); | 520 | |
521 | lcd_clk = clk_get_rate(fbi->clk); | ||
522 | tmp = var->pixclock * (unsigned long long)lcd_clk; | ||
523 | do_div(tmp, 1000000); | ||
524 | if (do_div(tmp, 1000000) > 500000) | ||
525 | tmp++; | ||
526 | pcr = (unsigned int)tmp; | ||
527 | if (--pcr > 0x3F) { | ||
528 | pcr = 0x3F; | ||
529 | printk(KERN_WARNING "Must limit pixel clock to %uHz\n", | ||
530 | lcd_clk / pcr); | ||
531 | } | ||
532 | |||
533 | /* add sync polarities */ | ||
534 | pcr |= fbi->pcr & ~0x3F; | ||
535 | |||
536 | writel(pcr, fbi->regs + LCDC_PCR); | ||
481 | writel(fbi->pwmr, fbi->regs + LCDC_PWMR); | 537 | writel(fbi->pwmr, fbi->regs + LCDC_PWMR); |
482 | writel(fbi->lscr1, fbi->regs + LCDC_LSCR1); | 538 | writel(fbi->lscr1, fbi->regs + LCDC_LSCR1); |
483 | writel(fbi->dmacr, fbi->regs + LCDC_DMACR); | 539 | writel(fbi->dmacr, fbi->regs + LCDC_DMACR); |
@@ -619,6 +675,13 @@ static int __init imxfb_probe(struct platform_device *pdev) | |||
619 | goto failed_req; | 675 | goto failed_req; |
620 | } | 676 | } |
621 | 677 | ||
678 | fbi->clk = clk_get(&pdev->dev, NULL); | ||
679 | if (IS_ERR(fbi->clk)) { | ||
680 | ret = PTR_ERR(fbi->clk);; | ||
681 | dev_err(&pdev->dev, "unable to get clock: %d\n", ret); | ||
682 | goto failed_getclock; | ||
683 | } | ||
684 | |||
622 | fbi->regs = ioremap(res->start, resource_size(res)); | 685 | fbi->regs = ioremap(res->start, resource_size(res)); |
623 | if (fbi->regs == NULL) { | 686 | if (fbi->regs == NULL) { |
624 | printk(KERN_ERR"Cannot map frame buffer registers\n"); | 687 | printk(KERN_ERR"Cannot map frame buffer registers\n"); |
@@ -650,6 +713,12 @@ static int __init imxfb_probe(struct platform_device *pdev) | |||
650 | info->fix.smem_start = fbi->screen_dma; | 713 | info->fix.smem_start = fbi->screen_dma; |
651 | } | 714 | } |
652 | 715 | ||
716 | if (pdata->init) { | ||
717 | ret = pdata->init(fbi->pdev); | ||
718 | if (ret) | ||
719 | goto failed_platform_init; | ||
720 | } | ||
721 | |||
653 | /* | 722 | /* |
654 | * This makes sure that our colour bitfield | 723 | * This makes sure that our colour bitfield |
655 | * descriptors are correctly initialised. | 724 | * descriptors are correctly initialised. |
@@ -674,10 +743,15 @@ static int __init imxfb_probe(struct platform_device *pdev) | |||
674 | failed_register: | 743 | failed_register: |
675 | fb_dealloc_cmap(&info->cmap); | 744 | fb_dealloc_cmap(&info->cmap); |
676 | failed_cmap: | 745 | failed_cmap: |
746 | if (pdata->exit) | ||
747 | pdata->exit(fbi->pdev); | ||
748 | failed_platform_init: | ||
677 | if (!pdata->fixed_screen_cpu) | 749 | if (!pdata->fixed_screen_cpu) |
678 | dma_free_writecombine(&pdev->dev,fbi->map_size,fbi->map_cpu, | 750 | dma_free_writecombine(&pdev->dev,fbi->map_size,fbi->map_cpu, |
679 | fbi->map_dma); | 751 | fbi->map_dma); |
680 | failed_map: | 752 | failed_map: |
753 | clk_put(fbi->clk); | ||
754 | failed_getclock: | ||
681 | iounmap(fbi->regs); | 755 | iounmap(fbi->regs); |
682 | failed_ioremap: | 756 | failed_ioremap: |
683 | release_mem_region(res->start, res->end - res->start); | 757 | release_mem_region(res->start, res->end - res->start); |
@@ -691,6 +765,7 @@ failed_init: | |||
691 | 765 | ||
692 | static int __devexit imxfb_remove(struct platform_device *pdev) | 766 | static int __devexit imxfb_remove(struct platform_device *pdev) |
693 | { | 767 | { |
768 | struct imx_fb_platform_data *pdata; | ||
694 | struct fb_info *info = platform_get_drvdata(pdev); | 769 | struct fb_info *info = platform_get_drvdata(pdev); |
695 | struct imxfb_info *fbi = info->par; | 770 | struct imxfb_info *fbi = info->par; |
696 | struct resource *res; | 771 | struct resource *res; |
@@ -701,12 +776,19 @@ static int __devexit imxfb_remove(struct platform_device *pdev) | |||
701 | 776 | ||
702 | unregister_framebuffer(info); | 777 | unregister_framebuffer(info); |
703 | 778 | ||
779 | pdata = pdev->dev.platform_data; | ||
780 | if (pdata->exit) | ||
781 | pdata->exit(fbi->pdev); | ||
782 | |||
704 | fb_dealloc_cmap(&info->cmap); | 783 | fb_dealloc_cmap(&info->cmap); |
705 | kfree(info->pseudo_palette); | 784 | kfree(info->pseudo_palette); |
706 | framebuffer_release(info); | 785 | framebuffer_release(info); |
707 | 786 | ||
708 | iounmap(fbi->regs); | 787 | iounmap(fbi->regs); |
709 | release_mem_region(res->start, res->end - res->start + 1); | 788 | release_mem_region(res->start, res->end - res->start + 1); |
789 | clk_disable(fbi->clk); | ||
790 | clk_put(fbi->clk); | ||
791 | |||
710 | platform_set_drvdata(pdev, NULL); | 792 | platform_set_drvdata(pdev, NULL); |
711 | 793 | ||
712 | return 0; | 794 | return 0; |