diff options
Diffstat (limited to 'drivers/video')
80 files changed, 11407 insertions, 799 deletions
diff --git a/drivers/video/68328fb.c b/drivers/video/68328fb.c index 0dda73da8628..7f907fb23b8a 100644 --- a/drivers/video/68328fb.c +++ b/drivers/video/68328fb.c | |||
@@ -60,7 +60,7 @@ static u_long videomemory; | |||
60 | static u_long videomemorysize; | 60 | static u_long videomemorysize; |
61 | 61 | ||
62 | static struct fb_info fb_info; | 62 | static struct fb_info fb_info; |
63 | static u32 mc68x328fb_pseudo_palette[17]; | 63 | static u32 mc68x328fb_pseudo_palette[16]; |
64 | 64 | ||
65 | static struct fb_var_screeninfo mc68x328fb_default __initdata = { | 65 | static struct fb_var_screeninfo mc68x328fb_default __initdata = { |
66 | .red = { 0, 8, 0 }, | 66 | .red = { 0, 8, 0 }, |
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 403dac787ebf..564cc9b51822 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig | |||
@@ -12,6 +12,13 @@ config VGASTATE | |||
12 | tristate | 12 | tristate |
13 | default n | 13 | default n |
14 | 14 | ||
15 | config VIDEO_OUTPUT_CONTROL | ||
16 | tristate "Lowlevel video output switch controls" | ||
17 | default m | ||
18 | help | ||
19 | This framework adds support for low-level control of the video | ||
20 | output switch. | ||
21 | |||
15 | config FB | 22 | config FB |
16 | tristate "Support for frame buffer devices" | 23 | tristate "Support for frame buffer devices" |
17 | ---help--- | 24 | ---help--- |
@@ -812,7 +819,7 @@ config FB_PVR2 | |||
812 | 819 | ||
813 | config FB_EPSON1355 | 820 | config FB_EPSON1355 |
814 | bool "Epson 1355 framebuffer support" | 821 | bool "Epson 1355 framebuffer support" |
815 | depends on (FB = y) && (SUPERH || ARCH_CEIVA) | 822 | depends on (FB = y) && ARCH_CEIVA |
816 | select FB_CFB_FILLRECT | 823 | select FB_CFB_FILLRECT |
817 | select FB_CFB_COPYAREA | 824 | select FB_CFB_COPYAREA |
818 | select FB_CFB_IMAGEBLIT | 825 | select FB_CFB_IMAGEBLIT |
@@ -849,6 +856,16 @@ config FB_INTSRAM | |||
849 | Say Y if you want to map Frame Buffer in internal SRAM. Say N if you want | 856 | Say Y if you want to map Frame Buffer in internal SRAM. Say N if you want |
850 | to let frame buffer in external SDRAM. | 857 | to let frame buffer in external SDRAM. |
851 | 858 | ||
859 | config FB_ATMEL_STN | ||
860 | bool "Use a STN display with AT91/AT32 LCD Controller" | ||
861 | depends on FB_ATMEL && MACH_AT91SAM9261EK | ||
862 | default n | ||
863 | help | ||
864 | Say Y if you want to connect a STN LCD display to the AT91/AT32 LCD | ||
865 | Controller. Say N if you want to connect a TFT. | ||
866 | |||
867 | If unsure, say N. | ||
868 | |||
852 | config FB_NVIDIA | 869 | config FB_NVIDIA |
853 | tristate "nVidia Framebuffer Support" | 870 | tristate "nVidia Framebuffer Support" |
854 | depends on FB && PCI | 871 | depends on FB && PCI |
@@ -1790,19 +1807,20 @@ config FB_IBM_GXT4500 | |||
1790 | adaptor, found on some IBM System P (pSeries) machines. | 1807 | adaptor, found on some IBM System P (pSeries) machines. |
1791 | 1808 | ||
1792 | config FB_PS3 | 1809 | config FB_PS3 |
1793 | bool "PS3 GPU framebuffer driver" | 1810 | tristate "PS3 GPU framebuffer driver" |
1794 | depends on (FB = y) && PS3_PS3AV | 1811 | depends on FB && PS3_PS3AV |
1795 | select FB_SYS_FILLRECT | 1812 | select FB_SYS_FILLRECT |
1796 | select FB_SYS_COPYAREA | 1813 | select FB_SYS_COPYAREA |
1797 | select FB_SYS_IMAGEBLIT | 1814 | select FB_SYS_IMAGEBLIT |
1798 | select FB_SYS_FOPS | 1815 | select FB_SYS_FOPS |
1816 | select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE | ||
1799 | ---help--- | 1817 | ---help--- |
1800 | Include support for the virtual frame buffer in the PS3 platform. | 1818 | Include support for the virtual frame buffer in the PS3 platform. |
1801 | 1819 | ||
1802 | config FB_PS3_DEFAULT_SIZE_M | 1820 | config FB_PS3_DEFAULT_SIZE_M |
1803 | int "PS3 default frame buffer size (in MiB)" | 1821 | int "PS3 default frame buffer size (in MiB)" |
1804 | depends on FB_PS3 | 1822 | depends on FB_PS3 |
1805 | default 18 | 1823 | default 9 |
1806 | ---help--- | 1824 | ---help--- |
1807 | This is the default size (in MiB) of the virtual frame buffer in | 1825 | This is the default size (in MiB) of the virtual frame buffer in |
1808 | the PS3. | 1826 | the PS3. |
@@ -1820,6 +1838,10 @@ config FB_XILINX | |||
1820 | framebuffer. ML300 carries a 640*480 LCD display on the board, | 1838 | framebuffer. ML300 carries a 640*480 LCD display on the board, |
1821 | ML403 uses a standard DB15 VGA connector. | 1839 | ML403 uses a standard DB15 VGA connector. |
1822 | 1840 | ||
1841 | if ARCH_OMAP | ||
1842 | source "drivers/video/omap/Kconfig" | ||
1843 | endif | ||
1844 | |||
1823 | config FB_VIRTUAL | 1845 | config FB_VIRTUAL |
1824 | tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)" | 1846 | tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)" |
1825 | depends on FB | 1847 | depends on FB |
diff --git a/drivers/video/Makefile b/drivers/video/Makefile index bd8b05229500..518933d4905f 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile | |||
@@ -113,6 +113,7 @@ obj-$(CONFIG_FB_IBM_GXT4500) += gxt4500.o | |||
113 | obj-$(CONFIG_FB_PS3) += ps3fb.o | 113 | obj-$(CONFIG_FB_PS3) += ps3fb.o |
114 | obj-$(CONFIG_FB_SM501) += sm501fb.o | 114 | obj-$(CONFIG_FB_SM501) += sm501fb.o |
115 | obj-$(CONFIG_FB_XILINX) += xilinxfb.o | 115 | obj-$(CONFIG_FB_XILINX) += xilinxfb.o |
116 | obj-$(CONFIG_FB_OMAP) += omap/ | ||
116 | 117 | ||
117 | # Platform or fallback drivers go here | 118 | # Platform or fallback drivers go here |
118 | obj-$(CONFIG_FB_VESA) += vesafb.o | 119 | obj-$(CONFIG_FB_VESA) += vesafb.o |
@@ -122,3 +123,6 @@ obj-$(CONFIG_FB_OF) += offb.o | |||
122 | 123 | ||
123 | # the test framebuffer is last | 124 | # the test framebuffer is last |
124 | obj-$(CONFIG_FB_VIRTUAL) += vfb.o | 125 | obj-$(CONFIG_FB_VIRTUAL) += vfb.o |
126 | |||
127 | #video output switch sysfs driver | ||
128 | obj-$(CONFIG_VIDEO_OUTPUT_CONTROL) += output.o | ||
diff --git a/drivers/video/amba-clcd.c b/drivers/video/amba-clcd.c index 6c9dc2e69c82..a7a1c891bfa2 100644 --- a/drivers/video/amba-clcd.c +++ b/drivers/video/amba-clcd.c | |||
@@ -447,13 +447,12 @@ static int clcdfb_probe(struct amba_device *dev, void *id) | |||
447 | goto out; | 447 | goto out; |
448 | } | 448 | } |
449 | 449 | ||
450 | fb = kmalloc(sizeof(struct clcd_fb), GFP_KERNEL); | 450 | fb = kzalloc(sizeof(struct clcd_fb), GFP_KERNEL); |
451 | if (!fb) { | 451 | if (!fb) { |
452 | printk(KERN_INFO "CLCD: could not allocate new clcd_fb struct\n"); | 452 | printk(KERN_INFO "CLCD: could not allocate new clcd_fb struct\n"); |
453 | ret = -ENOMEM; | 453 | ret = -ENOMEM; |
454 | goto free_region; | 454 | goto free_region; |
455 | } | 455 | } |
456 | memset(fb, 0, sizeof(struct clcd_fb)); | ||
457 | 456 | ||
458 | fb->dev = dev; | 457 | fb->dev = dev; |
459 | fb->board = board; | 458 | fb->board = board; |
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c index e1d5bd0c98c4..235b618b4117 100644 --- a/drivers/video/atmel_lcdfb.c +++ b/drivers/video/atmel_lcdfb.c | |||
@@ -79,6 +79,29 @@ static struct fb_fix_screeninfo atmel_lcdfb_fix __initdata = { | |||
79 | .accel = FB_ACCEL_NONE, | 79 | .accel = FB_ACCEL_NONE, |
80 | }; | 80 | }; |
81 | 81 | ||
82 | static unsigned long compute_hozval(unsigned long xres, unsigned long lcdcon2) | ||
83 | { | ||
84 | unsigned long value; | ||
85 | |||
86 | if (!(cpu_is_at91sam9261() || cpu_is_at32ap7000())) | ||
87 | return xres; | ||
88 | |||
89 | value = xres; | ||
90 | if ((lcdcon2 & ATMEL_LCDC_DISTYPE) != ATMEL_LCDC_DISTYPE_TFT) { | ||
91 | /* STN display */ | ||
92 | if ((lcdcon2 & ATMEL_LCDC_DISTYPE) == ATMEL_LCDC_DISTYPE_STNCOLOR) { | ||
93 | value *= 3; | ||
94 | } | ||
95 | if ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_4 | ||
96 | || ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_8 | ||
97 | && (lcdcon2 & ATMEL_LCDC_SCANMOD) == ATMEL_LCDC_SCANMOD_DUAL )) | ||
98 | value = DIV_ROUND_UP(value, 4); | ||
99 | else | ||
100 | value = DIV_ROUND_UP(value, 8); | ||
101 | } | ||
102 | |||
103 | return value; | ||
104 | } | ||
82 | 105 | ||
83 | static void atmel_lcdfb_update_dma(struct fb_info *info, | 106 | static void atmel_lcdfb_update_dma(struct fb_info *info, |
84 | struct fb_var_screeninfo *var) | 107 | struct fb_var_screeninfo *var) |
@@ -181,6 +204,7 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var, | |||
181 | var->xoffset = var->yoffset = 0; | 204 | var->xoffset = var->yoffset = 0; |
182 | 205 | ||
183 | switch (var->bits_per_pixel) { | 206 | switch (var->bits_per_pixel) { |
207 | case 1: | ||
184 | case 2: | 208 | case 2: |
185 | case 4: | 209 | case 4: |
186 | case 8: | 210 | case 8: |
@@ -195,8 +219,11 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var, | |||
195 | var->blue.offset = 10; | 219 | var->blue.offset = 10; |
196 | var->red.length = var->green.length = var->blue.length = 5; | 220 | var->red.length = var->green.length = var->blue.length = 5; |
197 | break; | 221 | break; |
198 | case 24: | ||
199 | case 32: | 222 | case 32: |
223 | var->transp.offset = 24; | ||
224 | var->transp.length = 8; | ||
225 | /* fall through */ | ||
226 | case 24: | ||
200 | var->red.offset = 0; | 227 | var->red.offset = 0; |
201 | var->green.offset = 8; | 228 | var->green.offset = 8; |
202 | var->blue.offset = 16; | 229 | var->blue.offset = 16; |
@@ -228,8 +255,10 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var, | |||
228 | static int atmel_lcdfb_set_par(struct fb_info *info) | 255 | static int atmel_lcdfb_set_par(struct fb_info *info) |
229 | { | 256 | { |
230 | struct atmel_lcdfb_info *sinfo = info->par; | 257 | struct atmel_lcdfb_info *sinfo = info->par; |
258 | unsigned long hozval_linesz; | ||
231 | unsigned long value; | 259 | unsigned long value; |
232 | unsigned long clk_value_khz; | 260 | unsigned long clk_value_khz; |
261 | unsigned long bits_per_line; | ||
233 | 262 | ||
234 | dev_dbg(info->device, "%s:\n", __func__); | 263 | dev_dbg(info->device, "%s:\n", __func__); |
235 | dev_dbg(info->device, " * resolution: %ux%u (%ux%u virtual)\n", | 264 | dev_dbg(info->device, " * resolution: %ux%u (%ux%u virtual)\n", |
@@ -241,12 +270,15 @@ static int atmel_lcdfb_set_par(struct fb_info *info) | |||
241 | 270 | ||
242 | lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0); | 271 | lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0); |
243 | 272 | ||
244 | if (info->var.bits_per_pixel <= 8) | 273 | if (info->var.bits_per_pixel == 1) |
274 | info->fix.visual = FB_VISUAL_MONO01; | ||
275 | else if (info->var.bits_per_pixel <= 8) | ||
245 | info->fix.visual = FB_VISUAL_PSEUDOCOLOR; | 276 | info->fix.visual = FB_VISUAL_PSEUDOCOLOR; |
246 | else | 277 | else |
247 | info->fix.visual = FB_VISUAL_TRUECOLOR; | 278 | info->fix.visual = FB_VISUAL_TRUECOLOR; |
248 | 279 | ||
249 | info->fix.line_length = info->var.xres_virtual * (info->var.bits_per_pixel / 8); | 280 | bits_per_line = info->var.xres_virtual * info->var.bits_per_pixel; |
281 | info->fix.line_length = DIV_ROUND_UP(bits_per_line, 8); | ||
250 | 282 | ||
251 | /* Re-initialize the DMA engine... */ | 283 | /* Re-initialize the DMA engine... */ |
252 | dev_dbg(info->device, " * update DMA engine\n"); | 284 | dev_dbg(info->device, " * update DMA engine\n"); |
@@ -262,18 +294,21 @@ static int atmel_lcdfb_set_par(struct fb_info *info) | |||
262 | /* Set pixel clock */ | 294 | /* Set pixel clock */ |
263 | clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000; | 295 | clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000; |
264 | 296 | ||
265 | value = clk_value_khz / PICOS2KHZ(info->var.pixclock); | 297 | value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(info->var.pixclock)); |
266 | |||
267 | if (clk_value_khz % PICOS2KHZ(info->var.pixclock)) | ||
268 | value++; | ||
269 | 298 | ||
270 | value = (value / 2) - 1; | 299 | value = (value / 2) - 1; |
300 | dev_dbg(info->device, " * programming CLKVAL = 0x%08lx\n", value); | ||
271 | 301 | ||
272 | if (value <= 0) { | 302 | if (value <= 0) { |
273 | dev_notice(info->device, "Bypassing pixel clock divider\n"); | 303 | dev_notice(info->device, "Bypassing pixel clock divider\n"); |
274 | lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS); | 304 | lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS); |
275 | } else | 305 | } else { |
276 | lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, value << ATMEL_LCDC_CLKVAL_OFFSET); | 306 | lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, value << ATMEL_LCDC_CLKVAL_OFFSET); |
307 | info->var.pixclock = KHZ2PICOS(clk_value_khz / (2 * (value + 1))); | ||
308 | dev_dbg(info->device, " updated pixclk: %lu KHz\n", | ||
309 | PICOS2KHZ(info->var.pixclock)); | ||
310 | } | ||
311 | |||
277 | 312 | ||
278 | /* Initialize control register 2 */ | 313 | /* Initialize control register 2 */ |
279 | value = sinfo->default_lcdcon2; | 314 | value = sinfo->default_lcdcon2; |
@@ -311,9 +346,14 @@ static int atmel_lcdfb_set_par(struct fb_info *info) | |||
311 | dev_dbg(info->device, " * LCDTIM2 = %08lx\n", value); | 346 | dev_dbg(info->device, " * LCDTIM2 = %08lx\n", value); |
312 | lcdc_writel(sinfo, ATMEL_LCDC_TIM2, value); | 347 | lcdc_writel(sinfo, ATMEL_LCDC_TIM2, value); |
313 | 348 | ||
349 | /* Horizontal value (aka line size) */ | ||
350 | hozval_linesz = compute_hozval(info->var.xres, | ||
351 | lcdc_readl(sinfo, ATMEL_LCDC_LCDCON2)); | ||
352 | |||
314 | /* Display size */ | 353 | /* Display size */ |
315 | value = (info->var.xres - 1) << ATMEL_LCDC_HOZVAL_OFFSET; | 354 | value = (hozval_linesz - 1) << ATMEL_LCDC_HOZVAL_OFFSET; |
316 | value |= info->var.yres - 1; | 355 | value |= info->var.yres - 1; |
356 | dev_dbg(info->device, " * LCDFRMCFG = %08lx\n", value); | ||
317 | lcdc_writel(sinfo, ATMEL_LCDC_LCDFRMCFG, value); | 357 | lcdc_writel(sinfo, ATMEL_LCDC_LCDFRMCFG, value); |
318 | 358 | ||
319 | /* FIFO Threshold: Use formula from data sheet */ | 359 | /* FIFO Threshold: Use formula from data sheet */ |
@@ -421,6 +461,15 @@ static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red, | |||
421 | ret = 0; | 461 | ret = 0; |
422 | } | 462 | } |
423 | break; | 463 | break; |
464 | |||
465 | case FB_VISUAL_MONO01: | ||
466 | if (regno < 2) { | ||
467 | val = (regno == 0) ? 0x00 : 0x1F; | ||
468 | lcdc_writel(sinfo, ATMEL_LCDC_LUT(regno), val); | ||
469 | ret = 0; | ||
470 | } | ||
471 | break; | ||
472 | |||
424 | } | 473 | } |
425 | 474 | ||
426 | return ret; | 475 | return ret; |
diff --git a/drivers/video/aty/ati_ids.h b/drivers/video/aty/ati_ids.h index 90e7df22f508..685a754991c6 100644 --- a/drivers/video/aty/ati_ids.h +++ b/drivers/video/aty/ati_ids.h | |||
@@ -204,6 +204,7 @@ | |||
204 | #define PCI_CHIP_RV280_5961 0x5961 | 204 | #define PCI_CHIP_RV280_5961 0x5961 |
205 | #define PCI_CHIP_RV280_5962 0x5962 | 205 | #define PCI_CHIP_RV280_5962 0x5962 |
206 | #define PCI_CHIP_RV280_5964 0x5964 | 206 | #define PCI_CHIP_RV280_5964 0x5964 |
207 | #define PCI_CHIP_RS485_5975 0x5975 | ||
207 | #define PCI_CHIP_RV280_5C61 0x5C61 | 208 | #define PCI_CHIP_RV280_5C61 0x5C61 |
208 | #define PCI_CHIP_RV280_5C63 0x5C63 | 209 | #define PCI_CHIP_RV280_5C63 0x5C63 |
209 | #define PCI_CHIP_R423_5D57 0x5D57 | 210 | #define PCI_CHIP_R423_5D57 0x5D57 |
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index d2c68c3d8d76..bc6f0096aa04 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c | |||
@@ -541,7 +541,7 @@ static char ram_off[] __devinitdata = "OFF"; | |||
541 | #endif /* CONFIG_FB_ATY_CT */ | 541 | #endif /* CONFIG_FB_ATY_CT */ |
542 | 542 | ||
543 | 543 | ||
544 | static u32 pseudo_palette[17]; | 544 | static u32 pseudo_palette[16]; |
545 | 545 | ||
546 | #ifdef CONFIG_FB_ATY_GX | 546 | #ifdef CONFIG_FB_ATY_GX |
547 | static char *aty_gx_ram[8] __devinitdata = { | 547 | static char *aty_gx_ram[8] __devinitdata = { |
@@ -2913,10 +2913,6 @@ static int __devinit atyfb_setup_sparc(struct pci_dev *pdev, | |||
2913 | int node, len, i, j, ret; | 2913 | int node, len, i, j, ret; |
2914 | u32 mem, chip_id; | 2914 | u32 mem, chip_id; |
2915 | 2915 | ||
2916 | /* Do not attach when we have a serial console. */ | ||
2917 | if (!con_is_present()) | ||
2918 | return -ENXIO; | ||
2919 | |||
2920 | /* | 2916 | /* |
2921 | * Map memory-mapped registers. | 2917 | * Map memory-mapped registers. |
2922 | */ | 2918 | */ |
@@ -2937,12 +2933,11 @@ static int __devinit atyfb_setup_sparc(struct pci_dev *pdev, | |||
2937 | /* nothing */ ; | 2933 | /* nothing */ ; |
2938 | j = i + 4; | 2934 | j = i + 4; |
2939 | 2935 | ||
2940 | par->mmap_map = kmalloc(j * sizeof(*par->mmap_map), GFP_ATOMIC); | 2936 | par->mmap_map = kcalloc(j, sizeof(*par->mmap_map), GFP_ATOMIC); |
2941 | if (!par->mmap_map) { | 2937 | if (!par->mmap_map) { |
2942 | PRINTKE("atyfb_setup_sparc() can't alloc mmap_map\n"); | 2938 | PRINTKE("atyfb_setup_sparc() can't alloc mmap_map\n"); |
2943 | return -ENOMEM; | 2939 | return -ENOMEM; |
2944 | } | 2940 | } |
2945 | memset(par->mmap_map, 0, j * sizeof(*par->mmap_map)); | ||
2946 | 2941 | ||
2947 | for (i = 0, j = 2; i < 6 && pdev->resource[i].start; i++) { | 2942 | for (i = 0, j = 2; i < 6 && pdev->resource[i].start; i++) { |
2948 | struct resource *rp = &pdev->resource[i]; | 2943 | struct resource *rp = &pdev->resource[i]; |
diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c index 2349e71b0083..47ca62fe7c3e 100644 --- a/drivers/video/aty/radeon_base.c +++ b/drivers/video/aty/radeon_base.c | |||
@@ -153,6 +153,8 @@ static struct pci_device_id radeonfb_pci_table[] = { | |||
153 | /* Mobility 9200 (M9+) */ | 153 | /* Mobility 9200 (M9+) */ |
154 | CHIP_DEF(PCI_CHIP_RV280_5C61, RV280, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), | 154 | CHIP_DEF(PCI_CHIP_RV280_5C61, RV280, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), |
155 | CHIP_DEF(PCI_CHIP_RV280_5C63, RV280, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), | 155 | CHIP_DEF(PCI_CHIP_RV280_5C63, RV280, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), |
156 | /*Mobility Xpress 200 */ | ||
157 | CHIP_DEF(PCI_CHIP_RS485_5975, R300, CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY), | ||
156 | /* 9200 */ | 158 | /* 9200 */ |
157 | CHIP_DEF(PCI_CHIP_RV280_5960, RV280, CHIP_HAS_CRTC2), | 159 | CHIP_DEF(PCI_CHIP_RV280_5960, RV280, CHIP_HAS_CRTC2), |
158 | CHIP_DEF(PCI_CHIP_RV280_5961, RV280, CHIP_HAS_CRTC2), | 160 | CHIP_DEF(PCI_CHIP_RV280_5961, RV280, CHIP_HAS_CRTC2), |
diff --git a/drivers/video/aty/radeonfb.h b/drivers/video/aty/radeonfb.h index 7ebffcdfd1e3..7c922c7b460b 100644 --- a/drivers/video/aty/radeonfb.h +++ b/drivers/video/aty/radeonfb.h | |||
@@ -301,7 +301,7 @@ struct radeonfb_info { | |||
301 | void __iomem *bios_seg; | 301 | void __iomem *bios_seg; |
302 | int fp_bios_start; | 302 | int fp_bios_start; |
303 | 303 | ||
304 | u32 pseudo_palette[17]; | 304 | u32 pseudo_palette[16]; |
305 | struct { u8 red, green, blue, pad; } | 305 | struct { u8 red, green, blue, pad; } |
306 | palette[256]; | 306 | palette[256]; |
307 | 307 | ||
diff --git a/drivers/video/au1200fb.c b/drivers/video/au1200fb.c index dbf4ec3f6d57..03e57ef88378 100644 --- a/drivers/video/au1200fb.c +++ b/drivers/video/au1200fb.c | |||
@@ -1589,11 +1589,10 @@ static int au1200fb_init_fbinfo(struct au1200fb_device *fbdev) | |||
1589 | return -EFAULT; | 1589 | return -EFAULT; |
1590 | } | 1590 | } |
1591 | 1591 | ||
1592 | fbi->pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL); | 1592 | fbi->pseudo_palette = kcalloc(16, sizeof(u32), GFP_KERNEL); |
1593 | if (!fbi->pseudo_palette) { | 1593 | if (!fbi->pseudo_palette) { |
1594 | return -ENOMEM; | 1594 | return -ENOMEM; |
1595 | } | 1595 | } |
1596 | memset(fbi->pseudo_palette, 0, sizeof(u32) * 16); | ||
1597 | 1596 | ||
1598 | if (fb_alloc_cmap(&fbi->cmap, AU1200_LCD_NBR_PALETTE_ENTRIES, 0) < 0) { | 1597 | if (fb_alloc_cmap(&fbi->cmap, AU1200_LCD_NBR_PALETTE_ENTRIES, 0) < 0) { |
1599 | print_err("Fail to allocate colormap (%d entries)", | 1598 | print_err("Fail to allocate colormap (%d entries)", |
diff --git a/drivers/video/backlight/cr_bllcd.c b/drivers/video/backlight/cr_bllcd.c index 5b94567beafd..b7904da51b23 100644 --- a/drivers/video/backlight/cr_bllcd.c +++ b/drivers/video/backlight/cr_bllcd.c | |||
@@ -174,7 +174,7 @@ static int cr_backlight_probe(struct platform_device *pdev) | |||
174 | struct cr_panel *crp; | 174 | struct cr_panel *crp; |
175 | u8 dev_en; | 175 | u8 dev_en; |
176 | 176 | ||
177 | crp = kzalloc(sizeof(crp), GFP_KERNEL); | 177 | crp = kzalloc(sizeof(*crp), GFP_KERNEL); |
178 | if (crp == NULL) | 178 | if (crp == NULL) |
179 | return -ENOMEM; | 179 | return -ENOMEM; |
180 | 180 | ||
diff --git a/drivers/video/clps711xfb.c b/drivers/video/clps711xfb.c index 50b78af0fa24..dea6579941b7 100644 --- a/drivers/video/clps711xfb.c +++ b/drivers/video/clps711xfb.c | |||
@@ -366,11 +366,10 @@ int __init clps711xfb_init(void) | |||
366 | if (fb_get_options("clps711xfb", NULL)) | 366 | if (fb_get_options("clps711xfb", NULL)) |
367 | return -ENODEV; | 367 | return -ENODEV; |
368 | 368 | ||
369 | cfb = kmalloc(sizeof(*cfb), GFP_KERNEL); | 369 | cfb = kzalloc(sizeof(*cfb), GFP_KERNEL); |
370 | if (!cfb) | 370 | if (!cfb) |
371 | goto out; | 371 | goto out; |
372 | 372 | ||
373 | memset(cfb, 0, sizeof(*cfb)); | ||
374 | strcpy(cfb->fix.id, "clps711x"); | 373 | strcpy(cfb->fix.id, "clps711x"); |
375 | 374 | ||
376 | cfb->fbops = &clps7111fb_ops; | 375 | cfb->fbops = &clps7111fb_ops; |
diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig index d3b8a6be2916..49643969f9f8 100644 --- a/drivers/video/console/Kconfig +++ b/drivers/video/console/Kconfig | |||
@@ -118,6 +118,22 @@ config FRAMEBUFFER_CONSOLE | |||
118 | help | 118 | help |
119 | Low-level framebuffer-based console driver. | 119 | Low-level framebuffer-based console driver. |
120 | 120 | ||
121 | config FRAMEBUFFER_CONSOLE_DETECT_PRIMARY | ||
122 | bool "Map the console to the primary display device" | ||
123 | depends on FRAMEBUFFER_CONSOLE | ||
124 | default n | ||
125 | ---help--- | ||
126 | If this option is selected, the framebuffer console will | ||
127 | automatically select the primary display device (if the architecture | ||
128 | supports this feature). Otherwise, the framebuffer console will | ||
129 | always select the first framebuffer driver that is loaded. The latter | ||
130 | is the default behavior. | ||
131 | |||
132 | You can always override the automatic selection of the primary device | ||
133 | by using the fbcon=map: boot option. | ||
134 | |||
135 | If unsure, select n. | ||
136 | |||
121 | config FRAMEBUFFER_CONSOLE_ROTATION | 137 | config FRAMEBUFFER_CONSOLE_ROTATION |
122 | bool "Framebuffer Console Rotation" | 138 | bool "Framebuffer Console Rotation" |
123 | depends on FRAMEBUFFER_CONSOLE | 139 | depends on FRAMEBUFFER_CONSOLE |
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 73813c60d03a..decfdc8eb9cc 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c | |||
@@ -75,6 +75,7 @@ | |||
75 | #include <linux/init.h> | 75 | #include <linux/init.h> |
76 | #include <linux/interrupt.h> | 76 | #include <linux/interrupt.h> |
77 | #include <linux/crc32.h> /* For counting font checksums */ | 77 | #include <linux/crc32.h> /* For counting font checksums */ |
78 | #include <asm/fb.h> | ||
78 | #include <asm/irq.h> | 79 | #include <asm/irq.h> |
79 | #include <asm/system.h> | 80 | #include <asm/system.h> |
80 | #include <asm/uaccess.h> | 81 | #include <asm/uaccess.h> |
@@ -125,6 +126,8 @@ static int first_fb_vc; | |||
125 | static int last_fb_vc = MAX_NR_CONSOLES - 1; | 126 | static int last_fb_vc = MAX_NR_CONSOLES - 1; |
126 | static int fbcon_is_default = 1; | 127 | static int fbcon_is_default = 1; |
127 | static int fbcon_has_exited; | 128 | static int fbcon_has_exited; |
129 | static int primary_device = -1; | ||
130 | static int map_override; | ||
128 | 131 | ||
129 | /* font data */ | 132 | /* font data */ |
130 | static char fontname[40]; | 133 | static char fontname[40]; |
@@ -152,6 +155,7 @@ static int fbcon_set_origin(struct vc_data *); | |||
152 | #define DEFAULT_CURSOR_BLINK_RATE (20) | 155 | #define DEFAULT_CURSOR_BLINK_RATE (20) |
153 | 156 | ||
154 | static int vbl_cursor_cnt; | 157 | static int vbl_cursor_cnt; |
158 | static int fbcon_cursor_noblink; | ||
155 | 159 | ||
156 | #define divides(a, b) ((!(a) || (b)%(a)) ? 0 : 1) | 160 | #define divides(a, b) ((!(a) || (b)%(a)) ? 0 : 1) |
157 | 161 | ||
@@ -188,16 +192,14 @@ static __inline__ void ypan_down(struct vc_data *vc, int count); | |||
188 | static void fbcon_bmove_rec(struct vc_data *vc, struct display *p, int sy, int sx, | 192 | static void fbcon_bmove_rec(struct vc_data *vc, struct display *p, int sy, int sx, |
189 | int dy, int dx, int height, int width, u_int y_break); | 193 | int dy, int dx, int height, int width, u_int y_break); |
190 | static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, | 194 | static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, |
191 | struct vc_data *vc); | 195 | int unit); |
192 | static void fbcon_preset_disp(struct fb_info *info, struct fb_var_screeninfo *var, | ||
193 | int unit); | ||
194 | static void fbcon_redraw_move(struct vc_data *vc, struct display *p, | 196 | static void fbcon_redraw_move(struct vc_data *vc, struct display *p, |
195 | int line, int count, int dy); | 197 | int line, int count, int dy); |
196 | static void fbcon_modechanged(struct fb_info *info); | 198 | static void fbcon_modechanged(struct fb_info *info); |
197 | static void fbcon_set_all_vcs(struct fb_info *info); | 199 | static void fbcon_set_all_vcs(struct fb_info *info); |
198 | static void fbcon_start(void); | 200 | static void fbcon_start(void); |
199 | static void fbcon_exit(void); | 201 | static void fbcon_exit(void); |
200 | static struct class_device *fbcon_class_device; | 202 | static struct device *fbcon_device; |
201 | 203 | ||
202 | #ifdef CONFIG_MAC | 204 | #ifdef CONFIG_MAC |
203 | /* | 205 | /* |
@@ -441,7 +443,8 @@ static void fbcon_add_cursor_timer(struct fb_info *info) | |||
441 | struct fbcon_ops *ops = info->fbcon_par; | 443 | struct fbcon_ops *ops = info->fbcon_par; |
442 | 444 | ||
443 | if ((!info->queue.func || info->queue.func == fb_flashcursor) && | 445 | if ((!info->queue.func || info->queue.func == fb_flashcursor) && |
444 | !(ops->flags & FBCON_FLAGS_CURSOR_TIMER)) { | 446 | !(ops->flags & FBCON_FLAGS_CURSOR_TIMER) && |
447 | !fbcon_cursor_noblink) { | ||
445 | if (!info->queue.func) | 448 | if (!info->queue.func) |
446 | INIT_WORK(&info->queue, fb_flashcursor); | 449 | INIT_WORK(&info->queue, fb_flashcursor); |
447 | 450 | ||
@@ -495,13 +498,17 @@ static int __init fb_console_setup(char *this_opt) | |||
495 | 498 | ||
496 | if (!strncmp(options, "map:", 4)) { | 499 | if (!strncmp(options, "map:", 4)) { |
497 | options += 4; | 500 | options += 4; |
498 | if (*options) | 501 | if (*options) { |
499 | for (i = 0, j = 0; i < MAX_NR_CONSOLES; i++) { | 502 | for (i = 0, j = 0; i < MAX_NR_CONSOLES; i++) { |
500 | if (!options[j]) | 503 | if (!options[j]) |
501 | j = 0; | 504 | j = 0; |
502 | con2fb_map_boot[i] = | 505 | con2fb_map_boot[i] = |
503 | (options[j++]-'0') % FB_MAX; | 506 | (options[j++]-'0') % FB_MAX; |
504 | } | 507 | } |
508 | |||
509 | map_override = 1; | ||
510 | } | ||
511 | |||
505 | return 1; | 512 | return 1; |
506 | } | 513 | } |
507 | 514 | ||
@@ -736,7 +743,9 @@ static int con2fb_acquire_newinfo(struct vc_data *vc, struct fb_info *info, | |||
736 | 743 | ||
737 | if (!err) { | 744 | if (!err) { |
738 | info->fbcon_par = ops; | 745 | info->fbcon_par = ops; |
739 | set_blitting_type(vc, info); | 746 | |
747 | if (vc) | ||
748 | set_blitting_type(vc, info); | ||
740 | } | 749 | } |
741 | 750 | ||
742 | if (err) { | 751 | if (err) { |
@@ -798,11 +807,7 @@ static void con2fb_init_display(struct vc_data *vc, struct fb_info *info, | |||
798 | 807 | ||
799 | ops->flags |= FBCON_FLAGS_INIT; | 808 | ops->flags |= FBCON_FLAGS_INIT; |
800 | ops->graphics = 0; | 809 | ops->graphics = 0; |
801 | 810 | fbcon_set_disp(info, &info->var, unit); | |
802 | if (vc) | ||
803 | fbcon_set_disp(info, &info->var, vc); | ||
804 | else | ||
805 | fbcon_preset_disp(info, &info->var, unit); | ||
806 | 811 | ||
807 | if (show_logo) { | 812 | if (show_logo) { |
808 | struct vc_data *fg_vc = vc_cons[fg_console].d; | 813 | struct vc_data *fg_vc = vc_cons[fg_console].d; |
@@ -1107,6 +1112,9 @@ static void fbcon_init(struct vc_data *vc, int init) | |||
1107 | if (var_to_display(p, &info->var, info)) | 1112 | if (var_to_display(p, &info->var, info)) |
1108 | return; | 1113 | return; |
1109 | 1114 | ||
1115 | if (!info->fbcon_par) | ||
1116 | con2fb_acquire_newinfo(vc, info, vc->vc_num, -1); | ||
1117 | |||
1110 | /* If we are not the first console on this | 1118 | /* If we are not the first console on this |
1111 | fb, copy the font from that console */ | 1119 | fb, copy the font from that console */ |
1112 | t = &fb_display[fg_console]; | 1120 | t = &fb_display[fg_console]; |
@@ -1349,6 +1357,11 @@ static void fbcon_cursor(struct vc_data *vc, int mode) | |||
1349 | if (fbcon_is_inactive(vc, info) || vc->vc_deccm != 1) | 1357 | if (fbcon_is_inactive(vc, info) || vc->vc_deccm != 1) |
1350 | return; | 1358 | return; |
1351 | 1359 | ||
1360 | if (vc->vc_cursor_type & 0x10) | ||
1361 | fbcon_del_cursor_timer(info); | ||
1362 | else | ||
1363 | fbcon_add_cursor_timer(info); | ||
1364 | |||
1352 | ops->cursor_flash = (mode == CM_ERASE) ? 0 : 1; | 1365 | ops->cursor_flash = (mode == CM_ERASE) ? 0 : 1; |
1353 | if (mode & CM_SOFTBACK) { | 1366 | if (mode & CM_SOFTBACK) { |
1354 | mode &= ~CM_SOFTBACK; | 1367 | mode &= ~CM_SOFTBACK; |
@@ -1368,36 +1381,29 @@ static int scrollback_phys_max = 0; | |||
1368 | static int scrollback_max = 0; | 1381 | static int scrollback_max = 0; |
1369 | static int scrollback_current = 0; | 1382 | static int scrollback_current = 0; |
1370 | 1383 | ||
1371 | /* | ||
1372 | * If no vc is existent yet, just set struct display | ||
1373 | */ | ||
1374 | static void fbcon_preset_disp(struct fb_info *info, struct fb_var_screeninfo *var, | ||
1375 | int unit) | ||
1376 | { | ||
1377 | struct display *p = &fb_display[unit]; | ||
1378 | struct display *t = &fb_display[fg_console]; | ||
1379 | |||
1380 | if (var_to_display(p, var, info)) | ||
1381 | return; | ||
1382 | |||
1383 | p->fontdata = t->fontdata; | ||
1384 | p->userfont = t->userfont; | ||
1385 | if (p->userfont) | ||
1386 | REFCOUNT(p->fontdata)++; | ||
1387 | } | ||
1388 | |||
1389 | static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, | 1384 | static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, |
1390 | struct vc_data *vc) | 1385 | int unit) |
1391 | { | 1386 | { |
1392 | struct display *p = &fb_display[vc->vc_num], *t; | 1387 | struct display *p, *t; |
1393 | struct vc_data **default_mode = vc->vc_display_fg; | 1388 | struct vc_data **default_mode, *vc; |
1394 | struct vc_data *svc = *default_mode; | 1389 | struct vc_data *svc; |
1395 | struct fbcon_ops *ops = info->fbcon_par; | 1390 | struct fbcon_ops *ops = info->fbcon_par; |
1396 | int rows, cols, charcnt = 256; | 1391 | int rows, cols, charcnt = 256; |
1397 | 1392 | ||
1393 | p = &fb_display[unit]; | ||
1394 | |||
1398 | if (var_to_display(p, var, info)) | 1395 | if (var_to_display(p, var, info)) |
1399 | return; | 1396 | return; |
1397 | |||
1398 | vc = vc_cons[unit].d; | ||
1399 | |||
1400 | if (!vc) | ||
1401 | return; | ||
1402 | |||
1403 | default_mode = vc->vc_display_fg; | ||
1404 | svc = *default_mode; | ||
1400 | t = &fb_display[svc->vc_num]; | 1405 | t = &fb_display[svc->vc_num]; |
1406 | |||
1401 | if (!vc->vc_font.data) { | 1407 | if (!vc->vc_font.data) { |
1402 | vc->vc_font.data = (void *)(p->fontdata = t->fontdata); | 1408 | vc->vc_font.data = (void *)(p->fontdata = t->fontdata); |
1403 | vc->vc_font.width = (*default_mode)->vc_font.width; | 1409 | vc->vc_font.width = (*default_mode)->vc_font.width; |
@@ -1704,6 +1710,56 @@ static void fbcon_redraw_move(struct vc_data *vc, struct display *p, | |||
1704 | } | 1710 | } |
1705 | } | 1711 | } |
1706 | 1712 | ||
1713 | static void fbcon_redraw_blit(struct vc_data *vc, struct fb_info *info, | ||
1714 | struct display *p, int line, int count, int ycount) | ||
1715 | { | ||
1716 | int offset = ycount * vc->vc_cols; | ||
1717 | unsigned short *d = (unsigned short *) | ||
1718 | (vc->vc_origin + vc->vc_size_row * line); | ||
1719 | unsigned short *s = d + offset; | ||
1720 | struct fbcon_ops *ops = info->fbcon_par; | ||
1721 | |||
1722 | while (count--) { | ||
1723 | unsigned short *start = s; | ||
1724 | unsigned short *le = advance_row(s, 1); | ||
1725 | unsigned short c; | ||
1726 | int x = 0; | ||
1727 | |||
1728 | do { | ||
1729 | c = scr_readw(s); | ||
1730 | |||
1731 | if (c == scr_readw(d)) { | ||
1732 | if (s > start) { | ||
1733 | ops->bmove(vc, info, line + ycount, x, | ||
1734 | line, x, 1, s-start); | ||
1735 | x += s - start + 1; | ||
1736 | start = s + 1; | ||
1737 | } else { | ||
1738 | x++; | ||
1739 | start++; | ||
1740 | } | ||
1741 | } | ||
1742 | |||
1743 | scr_writew(c, d); | ||
1744 | console_conditional_schedule(); | ||
1745 | s++; | ||
1746 | d++; | ||
1747 | } while (s < le); | ||
1748 | if (s > start) | ||
1749 | ops->bmove(vc, info, line + ycount, x, line, x, 1, | ||
1750 | s-start); | ||
1751 | console_conditional_schedule(); | ||
1752 | if (ycount > 0) | ||
1753 | line++; | ||
1754 | else { | ||
1755 | line--; | ||
1756 | /* NOTE: We subtract two lines from these pointers */ | ||
1757 | s -= vc->vc_size_row; | ||
1758 | d -= vc->vc_size_row; | ||
1759 | } | ||
1760 | } | ||
1761 | } | ||
1762 | |||
1707 | static void fbcon_redraw(struct vc_data *vc, struct display *p, | 1763 | static void fbcon_redraw(struct vc_data *vc, struct display *p, |
1708 | int line, int count, int offset) | 1764 | int line, int count, int offset) |
1709 | { | 1765 | { |
@@ -1789,7 +1845,6 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir, | |||
1789 | { | 1845 | { |
1790 | struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; | 1846 | struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; |
1791 | struct display *p = &fb_display[vc->vc_num]; | 1847 | struct display *p = &fb_display[vc->vc_num]; |
1792 | struct fbcon_ops *ops = info->fbcon_par; | ||
1793 | int scroll_partial = info->flags & FBINFO_PARTIAL_PAN_OK; | 1848 | int scroll_partial = info->flags & FBINFO_PARTIAL_PAN_OK; |
1794 | 1849 | ||
1795 | if (fbcon_is_inactive(vc, info)) | 1850 | if (fbcon_is_inactive(vc, info)) |
@@ -1813,10 +1868,15 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir, | |||
1813 | goto redraw_up; | 1868 | goto redraw_up; |
1814 | switch (p->scrollmode) { | 1869 | switch (p->scrollmode) { |
1815 | case SCROLL_MOVE: | 1870 | case SCROLL_MOVE: |
1816 | ops->bmove(vc, info, t + count, 0, t, 0, | 1871 | fbcon_redraw_blit(vc, info, p, t, b - t - count, |
1817 | b - t - count, vc->vc_cols); | 1872 | count); |
1818 | ops->clear(vc, info, b - count, 0, count, | 1873 | fbcon_clear(vc, b - count, 0, count, vc->vc_cols); |
1819 | vc->vc_cols); | 1874 | scr_memsetw((unsigned short *) (vc->vc_origin + |
1875 | vc->vc_size_row * | ||
1876 | (b - count)), | ||
1877 | vc->vc_video_erase_char, | ||
1878 | vc->vc_size_row * count); | ||
1879 | return 1; | ||
1820 | break; | 1880 | break; |
1821 | 1881 | ||
1822 | case SCROLL_WRAP_MOVE: | 1882 | case SCROLL_WRAP_MOVE: |
@@ -1899,9 +1959,15 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir, | |||
1899 | goto redraw_down; | 1959 | goto redraw_down; |
1900 | switch (p->scrollmode) { | 1960 | switch (p->scrollmode) { |
1901 | case SCROLL_MOVE: | 1961 | case SCROLL_MOVE: |
1902 | ops->bmove(vc, info, t, 0, t + count, 0, | 1962 | fbcon_redraw_blit(vc, info, p, b - 1, b - t - count, |
1903 | b - t - count, vc->vc_cols); | 1963 | -count); |
1904 | ops->clear(vc, info, t, 0, count, vc->vc_cols); | 1964 | fbcon_clear(vc, t, 0, count, vc->vc_cols); |
1965 | scr_memsetw((unsigned short *) (vc->vc_origin + | ||
1966 | vc->vc_size_row * | ||
1967 | t), | ||
1968 | vc->vc_video_erase_char, | ||
1969 | vc->vc_size_row * count); | ||
1970 | return 1; | ||
1905 | break; | 1971 | break; |
1906 | 1972 | ||
1907 | case SCROLL_WRAP_MOVE: | 1973 | case SCROLL_WRAP_MOVE: |
@@ -2937,9 +3003,48 @@ static int fbcon_mode_deleted(struct fb_info *info, | |||
2937 | return found; | 3003 | return found; |
2938 | } | 3004 | } |
2939 | 3005 | ||
2940 | static int fbcon_fb_unregistered(int idx) | 3006 | #ifdef CONFIG_VT_HW_CONSOLE_BINDING |
3007 | static int fbcon_unbind(void) | ||
2941 | { | 3008 | { |
2942 | int i; | 3009 | int ret; |
3010 | |||
3011 | ret = unbind_con_driver(&fb_con, first_fb_vc, last_fb_vc, | ||
3012 | fbcon_is_default); | ||
3013 | return ret; | ||
3014 | } | ||
3015 | #else | ||
3016 | static inline int fbcon_unbind(void) | ||
3017 | { | ||
3018 | return -EINVAL; | ||
3019 | } | ||
3020 | #endif /* CONFIG_VT_HW_CONSOLE_BINDING */ | ||
3021 | |||
3022 | static int fbcon_fb_unbind(int idx) | ||
3023 | { | ||
3024 | int i, new_idx = -1, ret = 0; | ||
3025 | |||
3026 | for (i = first_fb_vc; i <= last_fb_vc; i++) { | ||
3027 | if (con2fb_map[i] != idx && | ||
3028 | con2fb_map[i] != -1) { | ||
3029 | new_idx = i; | ||
3030 | break; | ||
3031 | } | ||
3032 | } | ||
3033 | |||
3034 | if (new_idx != -1) { | ||
3035 | for (i = first_fb_vc; i <= last_fb_vc; i++) { | ||
3036 | if (con2fb_map[i] == idx) | ||
3037 | set_con2fb_map(i, new_idx, 0); | ||
3038 | } | ||
3039 | } else | ||
3040 | ret = fbcon_unbind(); | ||
3041 | |||
3042 | return ret; | ||
3043 | } | ||
3044 | |||
3045 | static int fbcon_fb_unregistered(struct fb_info *info) | ||
3046 | { | ||
3047 | int i, idx = info->node; | ||
2943 | 3048 | ||
2944 | for (i = first_fb_vc; i <= last_fb_vc; i++) { | 3049 | for (i = first_fb_vc; i <= last_fb_vc; i++) { |
2945 | if (con2fb_map[i] == idx) | 3050 | if (con2fb_map[i] == idx) |
@@ -2967,12 +3072,48 @@ static int fbcon_fb_unregistered(int idx) | |||
2967 | if (!num_registered_fb) | 3072 | if (!num_registered_fb) |
2968 | unregister_con_driver(&fb_con); | 3073 | unregister_con_driver(&fb_con); |
2969 | 3074 | ||
3075 | |||
3076 | if (primary_device == idx) | ||
3077 | primary_device = -1; | ||
3078 | |||
2970 | return 0; | 3079 | return 0; |
2971 | } | 3080 | } |
2972 | 3081 | ||
2973 | static int fbcon_fb_registered(int idx) | 3082 | #ifdef CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY |
3083 | static void fbcon_select_primary(struct fb_info *info) | ||
2974 | { | 3084 | { |
2975 | int ret = 0, i; | 3085 | if (!map_override && primary_device == -1 && |
3086 | fb_is_primary_device(info)) { | ||
3087 | int i; | ||
3088 | |||
3089 | printk(KERN_INFO "fbcon: %s (fb%i) is primary device\n", | ||
3090 | info->fix.id, info->node); | ||
3091 | primary_device = info->node; | ||
3092 | |||
3093 | for (i = first_fb_vc; i <= last_fb_vc; i++) | ||
3094 | con2fb_map_boot[i] = primary_device; | ||
3095 | |||
3096 | if (con_is_bound(&fb_con)) { | ||
3097 | printk(KERN_INFO "fbcon: Remapping primary device, " | ||
3098 | "fb%i, to tty %i-%i\n", info->node, | ||
3099 | first_fb_vc + 1, last_fb_vc + 1); | ||
3100 | info_idx = primary_device; | ||
3101 | } | ||
3102 | } | ||
3103 | |||
3104 | } | ||
3105 | #else | ||
3106 | static inline void fbcon_select_primary(struct fb_info *info) | ||
3107 | { | ||
3108 | return; | ||
3109 | } | ||
3110 | #endif /* CONFIG_FRAMEBUFFER_DETECT_PRIMARY */ | ||
3111 | |||
3112 | static int fbcon_fb_registered(struct fb_info *info) | ||
3113 | { | ||
3114 | int ret = 0, i, idx = info->node; | ||
3115 | |||
3116 | fbcon_select_primary(info); | ||
2976 | 3117 | ||
2977 | if (info_idx == -1) { | 3118 | if (info_idx == -1) { |
2978 | for (i = first_fb_vc; i <= last_fb_vc; i++) { | 3119 | for (i = first_fb_vc; i <= last_fb_vc; i++) { |
@@ -2986,8 +3127,7 @@ static int fbcon_fb_registered(int idx) | |||
2986 | ret = fbcon_takeover(1); | 3127 | ret = fbcon_takeover(1); |
2987 | } else { | 3128 | } else { |
2988 | for (i = first_fb_vc; i <= last_fb_vc; i++) { | 3129 | for (i = first_fb_vc; i <= last_fb_vc; i++) { |
2989 | if (con2fb_map_boot[i] == idx && | 3130 | if (con2fb_map_boot[i] == idx) |
2990 | con2fb_map[i] == -1) | ||
2991 | set_con2fb_map(i, idx, 0); | 3131 | set_con2fb_map(i, idx, 0); |
2992 | } | 3132 | } |
2993 | } | 3133 | } |
@@ -3034,12 +3174,7 @@ static void fbcon_new_modelist(struct fb_info *info) | |||
3034 | mode = fb_find_nearest_mode(fb_display[i].mode, | 3174 | mode = fb_find_nearest_mode(fb_display[i].mode, |
3035 | &info->modelist); | 3175 | &info->modelist); |
3036 | fb_videomode_to_var(&var, mode); | 3176 | fb_videomode_to_var(&var, mode); |
3037 | 3177 | fbcon_set_disp(info, &var, vc->vc_num); | |
3038 | if (vc) | ||
3039 | fbcon_set_disp(info, &var, vc); | ||
3040 | else | ||
3041 | fbcon_preset_disp(info, &var, i); | ||
3042 | |||
3043 | } | 3178 | } |
3044 | } | 3179 | } |
3045 | 3180 | ||
@@ -3114,11 +3249,14 @@ static int fbcon_event_notify(struct notifier_block *self, | |||
3114 | mode = event->data; | 3249 | mode = event->data; |
3115 | ret = fbcon_mode_deleted(info, mode); | 3250 | ret = fbcon_mode_deleted(info, mode); |
3116 | break; | 3251 | break; |
3252 | case FB_EVENT_FB_UNBIND: | ||
3253 | ret = fbcon_fb_unbind(info->node); | ||
3254 | break; | ||
3117 | case FB_EVENT_FB_REGISTERED: | 3255 | case FB_EVENT_FB_REGISTERED: |
3118 | ret = fbcon_fb_registered(info->node); | 3256 | ret = fbcon_fb_registered(info); |
3119 | break; | 3257 | break; |
3120 | case FB_EVENT_FB_UNREGISTERED: | 3258 | case FB_EVENT_FB_UNREGISTERED: |
3121 | ret = fbcon_fb_unregistered(info->node); | 3259 | ret = fbcon_fb_unregistered(info); |
3122 | break; | 3260 | break; |
3123 | case FB_EVENT_SET_CONSOLE_MAP: | 3261 | case FB_EVENT_SET_CONSOLE_MAP: |
3124 | con2fb = event->data; | 3262 | con2fb = event->data; |
@@ -3179,8 +3317,9 @@ static struct notifier_block fbcon_event_notifier = { | |||
3179 | .notifier_call = fbcon_event_notify, | 3317 | .notifier_call = fbcon_event_notify, |
3180 | }; | 3318 | }; |
3181 | 3319 | ||
3182 | static ssize_t store_rotate(struct class_device *class_device, | 3320 | static ssize_t store_rotate(struct device *device, |
3183 | const char *buf, size_t count) | 3321 | struct device_attribute *attr, const char *buf, |
3322 | size_t count) | ||
3184 | { | 3323 | { |
3185 | struct fb_info *info; | 3324 | struct fb_info *info; |
3186 | int rotate, idx; | 3325 | int rotate, idx; |
@@ -3203,8 +3342,9 @@ err: | |||
3203 | return count; | 3342 | return count; |
3204 | } | 3343 | } |
3205 | 3344 | ||
3206 | static ssize_t store_rotate_all(struct class_device *class_device, | 3345 | static ssize_t store_rotate_all(struct device *device, |
3207 | const char *buf, size_t count) | 3346 | struct device_attribute *attr,const char *buf, |
3347 | size_t count) | ||
3208 | { | 3348 | { |
3209 | struct fb_info *info; | 3349 | struct fb_info *info; |
3210 | int rotate, idx; | 3350 | int rotate, idx; |
@@ -3227,7 +3367,8 @@ err: | |||
3227 | return count; | 3367 | return count; |
3228 | } | 3368 | } |
3229 | 3369 | ||
3230 | static ssize_t show_rotate(struct class_device *class_device, char *buf) | 3370 | static ssize_t show_rotate(struct device *device, |
3371 | struct device_attribute *attr,char *buf) | ||
3231 | { | 3372 | { |
3232 | struct fb_info *info; | 3373 | struct fb_info *info; |
3233 | int rotate = 0, idx; | 3374 | int rotate = 0, idx; |
@@ -3248,20 +3389,86 @@ err: | |||
3248 | return snprintf(buf, PAGE_SIZE, "%d\n", rotate); | 3389 | return snprintf(buf, PAGE_SIZE, "%d\n", rotate); |
3249 | } | 3390 | } |
3250 | 3391 | ||
3251 | static struct class_device_attribute class_device_attrs[] = { | 3392 | static ssize_t show_cursor_blink(struct device *device, |
3393 | struct device_attribute *attr, char *buf) | ||
3394 | { | ||
3395 | struct fb_info *info; | ||
3396 | struct fbcon_ops *ops; | ||
3397 | int idx, blink = -1; | ||
3398 | |||
3399 | if (fbcon_has_exited) | ||
3400 | return 0; | ||
3401 | |||
3402 | acquire_console_sem(); | ||
3403 | idx = con2fb_map[fg_console]; | ||
3404 | |||
3405 | if (idx == -1 || registered_fb[idx] == NULL) | ||
3406 | goto err; | ||
3407 | |||
3408 | info = registered_fb[idx]; | ||
3409 | ops = info->fbcon_par; | ||
3410 | |||
3411 | if (!ops) | ||
3412 | goto err; | ||
3413 | |||
3414 | blink = (ops->flags & FBCON_FLAGS_CURSOR_TIMER) ? 1 : 0; | ||
3415 | err: | ||
3416 | release_console_sem(); | ||
3417 | return snprintf(buf, PAGE_SIZE, "%d\n", blink); | ||
3418 | } | ||
3419 | |||
3420 | static ssize_t store_cursor_blink(struct device *device, | ||
3421 | struct device_attribute *attr, | ||
3422 | const char *buf, size_t count) | ||
3423 | { | ||
3424 | struct fb_info *info; | ||
3425 | int blink, idx; | ||
3426 | char **last = NULL; | ||
3427 | |||
3428 | if (fbcon_has_exited) | ||
3429 | return count; | ||
3430 | |||
3431 | acquire_console_sem(); | ||
3432 | idx = con2fb_map[fg_console]; | ||
3433 | |||
3434 | if (idx == -1 || registered_fb[idx] == NULL) | ||
3435 | goto err; | ||
3436 | |||
3437 | info = registered_fb[idx]; | ||
3438 | |||
3439 | if (!info->fbcon_par) | ||
3440 | goto err; | ||
3441 | |||
3442 | blink = simple_strtoul(buf, last, 0); | ||
3443 | |||
3444 | if (blink) { | ||
3445 | fbcon_cursor_noblink = 0; | ||
3446 | fbcon_add_cursor_timer(info); | ||
3447 | } else { | ||
3448 | fbcon_cursor_noblink = 1; | ||
3449 | fbcon_del_cursor_timer(info); | ||
3450 | } | ||
3451 | |||
3452 | err: | ||
3453 | release_console_sem(); | ||
3454 | return count; | ||
3455 | } | ||
3456 | |||
3457 | static struct device_attribute device_attrs[] = { | ||
3252 | __ATTR(rotate, S_IRUGO|S_IWUSR, show_rotate, store_rotate), | 3458 | __ATTR(rotate, S_IRUGO|S_IWUSR, show_rotate, store_rotate), |
3253 | __ATTR(rotate_all, S_IWUSR, NULL, store_rotate_all), | 3459 | __ATTR(rotate_all, S_IWUSR, NULL, store_rotate_all), |
3460 | __ATTR(cursor_blink, S_IRUGO|S_IWUSR, show_cursor_blink, | ||
3461 | store_cursor_blink), | ||
3254 | }; | 3462 | }; |
3255 | 3463 | ||
3256 | static int fbcon_init_class_device(void) | 3464 | static int fbcon_init_device(void) |
3257 | { | 3465 | { |
3258 | int i, error = 0; | 3466 | int i, error = 0; |
3259 | 3467 | ||
3260 | fbcon_has_sysfs = 1; | 3468 | fbcon_has_sysfs = 1; |
3261 | 3469 | ||
3262 | for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) { | 3470 | for (i = 0; i < ARRAY_SIZE(device_attrs); i++) { |
3263 | error = class_device_create_file(fbcon_class_device, | 3471 | error = device_create_file(fbcon_device, &device_attrs[i]); |
3264 | &class_device_attrs[i]); | ||
3265 | 3472 | ||
3266 | if (error) | 3473 | if (error) |
3267 | break; | 3474 | break; |
@@ -3269,8 +3476,7 @@ static int fbcon_init_class_device(void) | |||
3269 | 3476 | ||
3270 | if (error) { | 3477 | if (error) { |
3271 | while (--i >= 0) | 3478 | while (--i >= 0) |
3272 | class_device_remove_file(fbcon_class_device, | 3479 | device_remove_file(fbcon_device, &device_attrs[i]); |
3273 | &class_device_attrs[i]); | ||
3274 | 3480 | ||
3275 | fbcon_has_sysfs = 0; | 3481 | fbcon_has_sysfs = 0; |
3276 | } | 3482 | } |
@@ -3356,16 +3562,15 @@ static int __init fb_console_init(void) | |||
3356 | 3562 | ||
3357 | acquire_console_sem(); | 3563 | acquire_console_sem(); |
3358 | fb_register_client(&fbcon_event_notifier); | 3564 | fb_register_client(&fbcon_event_notifier); |
3359 | fbcon_class_device = | 3565 | fbcon_device = device_create(fb_class, NULL, MKDEV(0, 0), "fbcon"); |
3360 | class_device_create(fb_class, NULL, MKDEV(0, 0), NULL, "fbcon"); | ||
3361 | 3566 | ||
3362 | if (IS_ERR(fbcon_class_device)) { | 3567 | if (IS_ERR(fbcon_device)) { |
3363 | printk(KERN_WARNING "Unable to create class_device " | 3568 | printk(KERN_WARNING "Unable to create device " |
3364 | "for fbcon; errno = %ld\n", | 3569 | "for fbcon; errno = %ld\n", |
3365 | PTR_ERR(fbcon_class_device)); | 3570 | PTR_ERR(fbcon_device)); |
3366 | fbcon_class_device = NULL; | 3571 | fbcon_device = NULL; |
3367 | } else | 3572 | } else |
3368 | fbcon_init_class_device(); | 3573 | fbcon_init_device(); |
3369 | 3574 | ||
3370 | for (i = 0; i < MAX_NR_CONSOLES; i++) | 3575 | for (i = 0; i < MAX_NR_CONSOLES; i++) |
3371 | con2fb_map[i] = -1; | 3576 | con2fb_map[i] = -1; |
@@ -3379,14 +3584,13 @@ module_init(fb_console_init); | |||
3379 | 3584 | ||
3380 | #ifdef MODULE | 3585 | #ifdef MODULE |
3381 | 3586 | ||
3382 | static void __exit fbcon_deinit_class_device(void) | 3587 | static void __exit fbcon_deinit_device(void) |
3383 | { | 3588 | { |
3384 | int i; | 3589 | int i; |
3385 | 3590 | ||
3386 | if (fbcon_has_sysfs) { | 3591 | if (fbcon_has_sysfs) { |
3387 | for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) | 3592 | for (i = 0; i < ARRAY_SIZE(device_attrs); i++) |
3388 | class_device_remove_file(fbcon_class_device, | 3593 | device_remove_file(fbcon_device, &device_attrs[i]); |
3389 | &class_device_attrs[i]); | ||
3390 | 3594 | ||
3391 | fbcon_has_sysfs = 0; | 3595 | fbcon_has_sysfs = 0; |
3392 | } | 3596 | } |
@@ -3396,8 +3600,8 @@ static void __exit fb_console_exit(void) | |||
3396 | { | 3600 | { |
3397 | acquire_console_sem(); | 3601 | acquire_console_sem(); |
3398 | fb_unregister_client(&fbcon_event_notifier); | 3602 | fb_unregister_client(&fbcon_event_notifier); |
3399 | fbcon_deinit_class_device(); | 3603 | fbcon_deinit_device(); |
3400 | class_device_destroy(fb_class, MKDEV(0, 0)); | 3604 | device_destroy(fb_class, MKDEV(0, 0)); |
3401 | fbcon_exit(); | 3605 | fbcon_exit(); |
3402 | release_console_sem(); | 3606 | release_console_sem(); |
3403 | unregister_con_driver(&fb_con); | 3607 | unregister_con_driver(&fb_con); |
diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index f46fe95f69fb..d18b73aafa0d 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c | |||
@@ -187,7 +187,11 @@ static void vgacon_scrollback_init(int pitch) | |||
187 | } | 187 | } |
188 | } | 188 | } |
189 | 189 | ||
190 | static void vgacon_scrollback_startup(void) | 190 | /* |
191 | * Called only duing init so call of alloc_bootmen is ok. | ||
192 | * Marked __init_refok to silence modpost. | ||
193 | */ | ||
194 | static void __init_refok vgacon_scrollback_startup(void) | ||
191 | { | 195 | { |
192 | vgacon_scrollback = alloc_bootmem(CONFIG_VGACON_SOFT_SCROLLBACK_SIZE | 196 | vgacon_scrollback = alloc_bootmem(CONFIG_VGACON_SOFT_SCROLLBACK_SIZE |
193 | * 1024); | 197 | * 1024); |
diff --git a/drivers/video/controlfb.c b/drivers/video/controlfb.c index 8b762739b1e0..b0be7eac32d8 100644 --- a/drivers/video/controlfb.c +++ b/drivers/video/controlfb.c | |||
@@ -94,7 +94,7 @@ static inline int VAR_MATCH(struct fb_var_screeninfo *x, struct fb_var_screeninf | |||
94 | struct fb_info_control { | 94 | struct fb_info_control { |
95 | struct fb_info info; | 95 | struct fb_info info; |
96 | struct fb_par_control par; | 96 | struct fb_par_control par; |
97 | u32 pseudo_palette[17]; | 97 | u32 pseudo_palette[16]; |
98 | 98 | ||
99 | struct cmap_regs __iomem *cmap_regs; | 99 | struct cmap_regs __iomem *cmap_regs; |
100 | unsigned long cmap_regs_phys; | 100 | unsigned long cmap_regs_phys; |
diff --git a/drivers/video/cyber2000fb.c b/drivers/video/cyber2000fb.c index 7a6eeda5ae9a..30ede6e8830f 100644 --- a/drivers/video/cyber2000fb.c +++ b/drivers/video/cyber2000fb.c | |||
@@ -1221,11 +1221,10 @@ cyberpro_alloc_fb_info(unsigned int id, char *name) | |||
1221 | { | 1221 | { |
1222 | struct cfb_info *cfb; | 1222 | struct cfb_info *cfb; |
1223 | 1223 | ||
1224 | cfb = kmalloc(sizeof(struct cfb_info), GFP_KERNEL); | 1224 | cfb = kzalloc(sizeof(struct cfb_info), GFP_KERNEL); |
1225 | if (!cfb) | 1225 | if (!cfb) |
1226 | return NULL; | 1226 | return NULL; |
1227 | 1227 | ||
1228 | memset(cfb, 0, sizeof(struct cfb_info)); | ||
1229 | 1228 | ||
1230 | cfb->id = id; | 1229 | cfb->id = id; |
1231 | 1230 | ||
diff --git a/drivers/video/cyblafb.c b/drivers/video/cyblafb.c index 94a66c2d2cf5..e23324d10be2 100644 --- a/drivers/video/cyblafb.c +++ b/drivers/video/cyblafb.c | |||
@@ -1068,15 +1068,18 @@ static int cyblafb_setcolreg(unsigned regno, unsigned red, unsigned green, | |||
1068 | out8(0x3C9, green >> 10); | 1068 | out8(0x3C9, green >> 10); |
1069 | out8(0x3C9, blue >> 10); | 1069 | out8(0x3C9, blue >> 10); |
1070 | 1070 | ||
1071 | } else if (bpp == 16) // RGB 565 | 1071 | } else if (regno < 16) { |
1072 | ((u32 *) info->pseudo_palette)[regno] = | 1072 | if (bpp == 16) // RGB 565 |
1073 | (red & 0xF800) | | 1073 | ((u32 *) info->pseudo_palette)[regno] = |
1074 | ((green & 0xFC00) >> 5) | ((blue & 0xF800) >> 11); | 1074 | (red & 0xF800) | |
1075 | else if (bpp == 32) // ARGB 8888 | 1075 | ((green & 0xFC00) >> 5) | |
1076 | ((u32 *) info->pseudo_palette)[regno] = | 1076 | ((blue & 0xF800) >> 11); |
1077 | ((transp & 0xFF00) << 16) | | 1077 | else if (bpp == 32) // ARGB 8888 |
1078 | ((red & 0xFF00) << 8) | | 1078 | ((u32 *) info->pseudo_palette)[regno] = |
1079 | ((green & 0xFF00)) | ((blue & 0xFF00) >> 8); | 1079 | ((transp & 0xFF00) << 16) | |
1080 | ((red & 0xFF00) << 8) | | ||
1081 | ((green & 0xFF00)) | ((blue & 0xFF00) >> 8); | ||
1082 | } | ||
1080 | 1083 | ||
1081 | return 0; | 1084 | return 0; |
1082 | } | 1085 | } |
diff --git a/drivers/video/epson1355fb.c b/drivers/video/epson1355fb.c index ca2c54ce508e..33be46ccb54f 100644 --- a/drivers/video/epson1355fb.c +++ b/drivers/video/epson1355fb.c | |||
@@ -63,23 +63,12 @@ | |||
63 | 63 | ||
64 | struct epson1355_par { | 64 | struct epson1355_par { |
65 | unsigned long reg_addr; | 65 | unsigned long reg_addr; |
66 | u32 pseudo_palette[16]; | ||
66 | }; | 67 | }; |
67 | 68 | ||
68 | /* ------------------------------------------------------------------------- */ | 69 | /* ------------------------------------------------------------------------- */ |
69 | 70 | ||
70 | #ifdef CONFIG_SUPERH | 71 | #if defined(CONFIG_ARM) |
71 | |||
72 | static inline u8 epson1355_read_reg(int index) | ||
73 | { | ||
74 | return ctrl_inb(par.reg_addr + index); | ||
75 | } | ||
76 | |||
77 | static inline void epson1355_write_reg(u8 data, int index) | ||
78 | { | ||
79 | ctrl_outb(data, par.reg_addr + index); | ||
80 | } | ||
81 | |||
82 | #elif defined(CONFIG_ARM) | ||
83 | 72 | ||
84 | # ifdef CONFIG_ARCH_CEIVA | 73 | # ifdef CONFIG_ARCH_CEIVA |
85 | # include <asm/arch/hardware.h> | 74 | # include <asm/arch/hardware.h> |
@@ -289,7 +278,7 @@ static int epson1355fb_blank(int blank_mode, struct fb_info *info) | |||
289 | struct epson1355_par *par = info->par; | 278 | struct epson1355_par *par = info->par; |
290 | 279 | ||
291 | switch (blank_mode) { | 280 | switch (blank_mode) { |
292 | case FB_BLANK_UNBLANKING: | 281 | case FB_BLANK_UNBLANK: |
293 | case FB_BLANK_NORMAL: | 282 | case FB_BLANK_NORMAL: |
294 | lcd_enable(par, 1); | 283 | lcd_enable(par, 1); |
295 | backlight_enable(1); | 284 | backlight_enable(1); |
@@ -635,7 +624,7 @@ int __init epson1355fb_probe(struct platform_device *dev) | |||
635 | goto bail; | 624 | goto bail; |
636 | } | 625 | } |
637 | 626 | ||
638 | info = framebuffer_alloc(sizeof(struct epson1355_par) + sizeof(u32) * 256, &dev->dev); | 627 | info = framebuffer_alloc(sizeof(struct epson1355_par), &dev->dev); |
639 | if (!info) { | 628 | if (!info) { |
640 | rc = -ENOMEM; | 629 | rc = -ENOMEM; |
641 | goto bail; | 630 | goto bail; |
@@ -648,7 +637,7 @@ int __init epson1355fb_probe(struct platform_device *dev) | |||
648 | rc = -ENOMEM; | 637 | rc = -ENOMEM; |
649 | goto bail; | 638 | goto bail; |
650 | } | 639 | } |
651 | info->pseudo_palette = (void *)(default_par + 1); | 640 | info->pseudo_palette = default_par->pseudo_palette; |
652 | 641 | ||
653 | info->screen_base = ioremap(EPSON1355FB_FB_PHYS, EPSON1355FB_FB_LEN); | 642 | info->screen_base = ioremap(EPSON1355FB_FB_PHYS, EPSON1355FB_FB_LEN); |
654 | if (!info->screen_base) { | 643 | if (!info->screen_base) { |
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 38c2e2558f5e..215ac579f901 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c | |||
@@ -33,17 +33,10 @@ | |||
33 | #include <linux/err.h> | 33 | #include <linux/err.h> |
34 | #include <linux/device.h> | 34 | #include <linux/device.h> |
35 | #include <linux/efi.h> | 35 | #include <linux/efi.h> |
36 | #include <linux/fb.h> | ||
36 | 37 | ||
37 | #if defined(__mc68000__) || defined(CONFIG_APUS) | 38 | #include <asm/fb.h> |
38 | #include <asm/setup.h> | ||
39 | #endif | ||
40 | 39 | ||
41 | #include <asm/io.h> | ||
42 | #include <asm/uaccess.h> | ||
43 | #include <asm/page.h> | ||
44 | #include <asm/pgtable.h> | ||
45 | |||
46 | #include <linux/fb.h> | ||
47 | 40 | ||
48 | /* | 41 | /* |
49 | * Frame buffer device initialization and setup routines | 42 | * Frame buffer device initialization and setup routines |
@@ -411,10 +404,146 @@ static void fb_do_show_logo(struct fb_info *info, struct fb_image *image, | |||
411 | } | 404 | } |
412 | } | 405 | } |
413 | 406 | ||
407 | static int fb_show_logo_line(struct fb_info *info, int rotate, | ||
408 | const struct linux_logo *logo, int y, | ||
409 | unsigned int n) | ||
410 | { | ||
411 | u32 *palette = NULL, *saved_pseudo_palette = NULL; | ||
412 | unsigned char *logo_new = NULL, *logo_rotate = NULL; | ||
413 | struct fb_image image; | ||
414 | |||
415 | /* Return if the frame buffer is not mapped or suspended */ | ||
416 | if (logo == NULL || info->state != FBINFO_STATE_RUNNING || | ||
417 | info->flags & FBINFO_MODULE) | ||
418 | return 0; | ||
419 | |||
420 | image.depth = 8; | ||
421 | image.data = logo->data; | ||
422 | |||
423 | if (fb_logo.needs_cmapreset) | ||
424 | fb_set_logocmap(info, logo); | ||
425 | |||
426 | if (fb_logo.needs_truepalette || | ||
427 | fb_logo.needs_directpalette) { | ||
428 | palette = kmalloc(256 * 4, GFP_KERNEL); | ||
429 | if (palette == NULL) | ||
430 | return 0; | ||
431 | |||
432 | if (fb_logo.needs_truepalette) | ||
433 | fb_set_logo_truepalette(info, logo, palette); | ||
434 | else | ||
435 | fb_set_logo_directpalette(info, logo, palette); | ||
436 | |||
437 | saved_pseudo_palette = info->pseudo_palette; | ||
438 | info->pseudo_palette = palette; | ||
439 | } | ||
440 | |||
441 | if (fb_logo.depth <= 4) { | ||
442 | logo_new = kmalloc(logo->width * logo->height, GFP_KERNEL); | ||
443 | if (logo_new == NULL) { | ||
444 | kfree(palette); | ||
445 | if (saved_pseudo_palette) | ||
446 | info->pseudo_palette = saved_pseudo_palette; | ||
447 | return 0; | ||
448 | } | ||
449 | image.data = logo_new; | ||
450 | fb_set_logo(info, logo, logo_new, fb_logo.depth); | ||
451 | } | ||
452 | |||
453 | image.dx = 0; | ||
454 | image.dy = y; | ||
455 | image.width = logo->width; | ||
456 | image.height = logo->height; | ||
457 | |||
458 | if (rotate) { | ||
459 | logo_rotate = kmalloc(logo->width * | ||
460 | logo->height, GFP_KERNEL); | ||
461 | if (logo_rotate) | ||
462 | fb_rotate_logo(info, logo_rotate, &image, rotate); | ||
463 | } | ||
464 | |||
465 | fb_do_show_logo(info, &image, rotate, n); | ||
466 | |||
467 | kfree(palette); | ||
468 | if (saved_pseudo_palette != NULL) | ||
469 | info->pseudo_palette = saved_pseudo_palette; | ||
470 | kfree(logo_new); | ||
471 | kfree(logo_rotate); | ||
472 | return logo->height; | ||
473 | } | ||
474 | |||
475 | |||
476 | #ifdef CONFIG_FB_LOGO_EXTRA | ||
477 | |||
478 | #define FB_LOGO_EX_NUM_MAX 10 | ||
479 | static struct logo_data_extra { | ||
480 | const struct linux_logo *logo; | ||
481 | unsigned int n; | ||
482 | } fb_logo_ex[FB_LOGO_EX_NUM_MAX]; | ||
483 | static unsigned int fb_logo_ex_num; | ||
484 | |||
485 | void fb_append_extra_logo(const struct linux_logo *logo, unsigned int n) | ||
486 | { | ||
487 | if (!n || fb_logo_ex_num == FB_LOGO_EX_NUM_MAX) | ||
488 | return; | ||
489 | |||
490 | fb_logo_ex[fb_logo_ex_num].logo = logo; | ||
491 | fb_logo_ex[fb_logo_ex_num].n = n; | ||
492 | fb_logo_ex_num++; | ||
493 | } | ||
494 | |||
495 | static int fb_prepare_extra_logos(struct fb_info *info, unsigned int height, | ||
496 | unsigned int yres) | ||
497 | { | ||
498 | unsigned int i; | ||
499 | |||
500 | /* FIXME: logo_ex supports only truecolor fb. */ | ||
501 | if (info->fix.visual != FB_VISUAL_TRUECOLOR) | ||
502 | fb_logo_ex_num = 0; | ||
503 | |||
504 | for (i = 0; i < fb_logo_ex_num; i++) { | ||
505 | height += fb_logo_ex[i].logo->height; | ||
506 | if (height > yres) { | ||
507 | height -= fb_logo_ex[i].logo->height; | ||
508 | fb_logo_ex_num = i; | ||
509 | break; | ||
510 | } | ||
511 | } | ||
512 | return height; | ||
513 | } | ||
514 | |||
515 | static int fb_show_extra_logos(struct fb_info *info, int y, int rotate) | ||
516 | { | ||
517 | unsigned int i; | ||
518 | |||
519 | for (i = 0; i < fb_logo_ex_num; i++) | ||
520 | y += fb_show_logo_line(info, rotate, | ||
521 | fb_logo_ex[i].logo, y, fb_logo_ex[i].n); | ||
522 | |||
523 | return y; | ||
524 | } | ||
525 | |||
526 | #else /* !CONFIG_FB_LOGO_EXTRA */ | ||
527 | |||
528 | static inline int fb_prepare_extra_logos(struct fb_info *info, | ||
529 | unsigned int height, | ||
530 | unsigned int yres) | ||
531 | { | ||
532 | return height; | ||
533 | } | ||
534 | |||
535 | static inline int fb_show_extra_logos(struct fb_info *info, int y, int rotate) | ||
536 | { | ||
537 | return y; | ||
538 | } | ||
539 | |||
540 | #endif /* CONFIG_FB_LOGO_EXTRA */ | ||
541 | |||
542 | |||
414 | int fb_prepare_logo(struct fb_info *info, int rotate) | 543 | int fb_prepare_logo(struct fb_info *info, int rotate) |
415 | { | 544 | { |
416 | int depth = fb_get_color_depth(&info->var, &info->fix); | 545 | int depth = fb_get_color_depth(&info->var, &info->fix); |
417 | int yres; | 546 | unsigned int yres; |
418 | 547 | ||
419 | memset(&fb_logo, 0, sizeof(struct logo_data)); | 548 | memset(&fb_logo, 0, sizeof(struct logo_data)); |
420 | 549 | ||
@@ -456,7 +585,7 @@ int fb_prepare_logo(struct fb_info *info, int rotate) | |||
456 | if (!fb_logo.logo) { | 585 | if (!fb_logo.logo) { |
457 | return 0; | 586 | return 0; |
458 | } | 587 | } |
459 | 588 | ||
460 | if (rotate == FB_ROTATE_UR || rotate == FB_ROTATE_UD) | 589 | if (rotate == FB_ROTATE_UR || rotate == FB_ROTATE_UD) |
461 | yres = info->var.yres; | 590 | yres = info->var.yres; |
462 | else | 591 | else |
@@ -473,75 +602,20 @@ int fb_prepare_logo(struct fb_info *info, int rotate) | |||
473 | else if (fb_logo.logo->type == LINUX_LOGO_VGA16) | 602 | else if (fb_logo.logo->type == LINUX_LOGO_VGA16) |
474 | fb_logo.depth = 4; | 603 | fb_logo.depth = 4; |
475 | else | 604 | else |
476 | fb_logo.depth = 1; | 605 | fb_logo.depth = 1; |
477 | return fb_logo.logo->height; | 606 | |
607 | return fb_prepare_extra_logos(info, fb_logo.logo->height, yres); | ||
478 | } | 608 | } |
479 | 609 | ||
480 | int fb_show_logo(struct fb_info *info, int rotate) | 610 | int fb_show_logo(struct fb_info *info, int rotate) |
481 | { | 611 | { |
482 | u32 *palette = NULL, *saved_pseudo_palette = NULL; | 612 | int y; |
483 | unsigned char *logo_new = NULL, *logo_rotate = NULL; | ||
484 | struct fb_image image; | ||
485 | |||
486 | /* Return if the frame buffer is not mapped or suspended */ | ||
487 | if (fb_logo.logo == NULL || info->state != FBINFO_STATE_RUNNING || | ||
488 | info->flags & FBINFO_MODULE) | ||
489 | return 0; | ||
490 | |||
491 | image.depth = 8; | ||
492 | image.data = fb_logo.logo->data; | ||
493 | |||
494 | if (fb_logo.needs_cmapreset) | ||
495 | fb_set_logocmap(info, fb_logo.logo); | ||
496 | |||
497 | if (fb_logo.needs_truepalette || | ||
498 | fb_logo.needs_directpalette) { | ||
499 | palette = kmalloc(256 * 4, GFP_KERNEL); | ||
500 | if (palette == NULL) | ||
501 | return 0; | ||
502 | |||
503 | if (fb_logo.needs_truepalette) | ||
504 | fb_set_logo_truepalette(info, fb_logo.logo, palette); | ||
505 | else | ||
506 | fb_set_logo_directpalette(info, fb_logo.logo, palette); | ||
507 | |||
508 | saved_pseudo_palette = info->pseudo_palette; | ||
509 | info->pseudo_palette = palette; | ||
510 | } | ||
511 | |||
512 | if (fb_logo.depth <= 4) { | ||
513 | logo_new = kmalloc(fb_logo.logo->width * fb_logo.logo->height, | ||
514 | GFP_KERNEL); | ||
515 | if (logo_new == NULL) { | ||
516 | kfree(palette); | ||
517 | if (saved_pseudo_palette) | ||
518 | info->pseudo_palette = saved_pseudo_palette; | ||
519 | return 0; | ||
520 | } | ||
521 | image.data = logo_new; | ||
522 | fb_set_logo(info, fb_logo.logo, logo_new, fb_logo.depth); | ||
523 | } | ||
524 | 613 | ||
525 | image.dx = 0; | 614 | y = fb_show_logo_line(info, rotate, fb_logo.logo, 0, |
526 | image.dy = 0; | 615 | num_online_cpus()); |
527 | image.width = fb_logo.logo->width; | 616 | y = fb_show_extra_logos(info, y, rotate); |
528 | image.height = fb_logo.logo->height; | ||
529 | 617 | ||
530 | if (rotate) { | 618 | return y; |
531 | logo_rotate = kmalloc(fb_logo.logo->width * | ||
532 | fb_logo.logo->height, GFP_KERNEL); | ||
533 | if (logo_rotate) | ||
534 | fb_rotate_logo(info, logo_rotate, &image, rotate); | ||
535 | } | ||
536 | |||
537 | fb_do_show_logo(info, &image, rotate, num_online_cpus()); | ||
538 | |||
539 | kfree(palette); | ||
540 | if (saved_pseudo_palette != NULL) | ||
541 | info->pseudo_palette = saved_pseudo_palette; | ||
542 | kfree(logo_new); | ||
543 | kfree(logo_rotate); | ||
544 | return fb_logo.logo->height; | ||
545 | } | 619 | } |
546 | #else | 620 | #else |
547 | int fb_prepare_logo(struct fb_info *info, int rotate) { return 0; } | 621 | int fb_prepare_logo(struct fb_info *info, int rotate) { return 0; } |
@@ -1155,17 +1229,15 @@ fb_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
1155 | } | 1229 | } |
1156 | #endif | 1230 | #endif |
1157 | 1231 | ||
1158 | static int | 1232 | static int |
1159 | fb_mmap(struct file *file, struct vm_area_struct * vma) | 1233 | fb_mmap(struct file *file, struct vm_area_struct * vma) |
1160 | { | 1234 | { |
1161 | int fbidx = iminor(file->f_path.dentry->d_inode); | 1235 | int fbidx = iminor(file->f_path.dentry->d_inode); |
1162 | struct fb_info *info = registered_fb[fbidx]; | 1236 | struct fb_info *info = registered_fb[fbidx]; |
1163 | struct fb_ops *fb = info->fbops; | 1237 | struct fb_ops *fb = info->fbops; |
1164 | unsigned long off; | 1238 | unsigned long off; |
1165 | #if !defined(__sparc__) || defined(__sparc_v9__) | ||
1166 | unsigned long start; | 1239 | unsigned long start; |
1167 | u32 len; | 1240 | u32 len; |
1168 | #endif | ||
1169 | 1241 | ||
1170 | if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) | 1242 | if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) |
1171 | return -EINVAL; | 1243 | return -EINVAL; |
@@ -1180,12 +1252,6 @@ fb_mmap(struct file *file, struct vm_area_struct * vma) | |||
1180 | return res; | 1252 | return res; |
1181 | } | 1253 | } |
1182 | 1254 | ||
1183 | #if defined(__sparc__) && !defined(__sparc_v9__) | ||
1184 | /* Should never get here, all fb drivers should have their own | ||
1185 | mmap routines */ | ||
1186 | return -EINVAL; | ||
1187 | #else | ||
1188 | /* !sparc32... */ | ||
1189 | lock_kernel(); | 1255 | lock_kernel(); |
1190 | 1256 | ||
1191 | /* frame buffer memory */ | 1257 | /* frame buffer memory */ |
@@ -1209,50 +1275,11 @@ fb_mmap(struct file *file, struct vm_area_struct * vma) | |||
1209 | vma->vm_pgoff = off >> PAGE_SHIFT; | 1275 | vma->vm_pgoff = off >> PAGE_SHIFT; |
1210 | /* This is an IO map - tell maydump to skip this VMA */ | 1276 | /* This is an IO map - tell maydump to skip this VMA */ |
1211 | vma->vm_flags |= VM_IO | VM_RESERVED; | 1277 | vma->vm_flags |= VM_IO | VM_RESERVED; |
1212 | #if defined(__mc68000__) | 1278 | fb_pgprotect(file, vma, off); |
1213 | #if defined(CONFIG_SUN3) | ||
1214 | pgprot_val(vma->vm_page_prot) |= SUN3_PAGE_NOCACHE; | ||
1215 | #elif defined(CONFIG_MMU) | ||
1216 | if (CPU_IS_020_OR_030) | ||
1217 | pgprot_val(vma->vm_page_prot) |= _PAGE_NOCACHE030; | ||
1218 | if (CPU_IS_040_OR_060) { | ||
1219 | pgprot_val(vma->vm_page_prot) &= _CACHEMASK040; | ||
1220 | /* Use no-cache mode, serialized */ | ||
1221 | pgprot_val(vma->vm_page_prot) |= _PAGE_NOCACHE_S; | ||
1222 | } | ||
1223 | #endif | ||
1224 | #elif defined(__powerpc__) | ||
1225 | vma->vm_page_prot = phys_mem_access_prot(file, off >> PAGE_SHIFT, | ||
1226 | vma->vm_end - vma->vm_start, | ||
1227 | vma->vm_page_prot); | ||
1228 | #elif defined(__alpha__) | ||
1229 | /* Caching is off in the I/O space quadrant by design. */ | ||
1230 | #elif defined(__i386__) || defined(__x86_64__) | ||
1231 | if (boot_cpu_data.x86 > 3) | ||
1232 | pgprot_val(vma->vm_page_prot) |= _PAGE_PCD; | ||
1233 | #elif defined(__mips__) || defined(__sparc_v9__) | ||
1234 | vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); | ||
1235 | #elif defined(__hppa__) | ||
1236 | pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE; | ||
1237 | #elif defined(__arm__) || defined(__sh__) || defined(__m32r__) | ||
1238 | vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); | ||
1239 | #elif defined(__avr32__) | ||
1240 | vma->vm_page_prot = __pgprot((pgprot_val(vma->vm_page_prot) | ||
1241 | & ~_PAGE_CACHABLE) | ||
1242 | | (_PAGE_BUFFER | _PAGE_DIRTY)); | ||
1243 | #elif defined(__ia64__) | ||
1244 | if (efi_range_is_wc(vma->vm_start, vma->vm_end - vma->vm_start)) | ||
1245 | vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); | ||
1246 | else | ||
1247 | vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); | ||
1248 | #else | ||
1249 | #warning What do we have to do here?? | ||
1250 | #endif | ||
1251 | if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, | 1279 | if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, |
1252 | vma->vm_end - vma->vm_start, vma->vm_page_prot)) | 1280 | vma->vm_end - vma->vm_start, vma->vm_page_prot)) |
1253 | return -EAGAIN; | 1281 | return -EAGAIN; |
1254 | return 0; | 1282 | return 0; |
1255 | #endif /* !sparc32 */ | ||
1256 | } | 1283 | } |
1257 | 1284 | ||
1258 | static int | 1285 | static int |
@@ -1388,17 +1415,34 @@ register_framebuffer(struct fb_info *fb_info) | |||
1388 | * | 1415 | * |
1389 | * Returns negative errno on error, or zero for success. | 1416 | * Returns negative errno on error, or zero for success. |
1390 | * | 1417 | * |
1418 | * This function will also notify the framebuffer console | ||
1419 | * to release the driver. | ||
1420 | * | ||
1421 | * This is meant to be called within a driver's module_exit() | ||
1422 | * function. If this is called outside module_exit(), ensure | ||
1423 | * that the driver implements fb_open() and fb_release() to | ||
1424 | * check that no processes are using the device. | ||
1391 | */ | 1425 | */ |
1392 | 1426 | ||
1393 | int | 1427 | int |
1394 | unregister_framebuffer(struct fb_info *fb_info) | 1428 | unregister_framebuffer(struct fb_info *fb_info) |
1395 | { | 1429 | { |
1396 | struct fb_event event; | 1430 | struct fb_event event; |
1397 | int i; | 1431 | int i, ret = 0; |
1398 | 1432 | ||
1399 | i = fb_info->node; | 1433 | i = fb_info->node; |
1400 | if (!registered_fb[i]) | 1434 | if (!registered_fb[i]) { |
1401 | return -EINVAL; | 1435 | ret = -EINVAL; |
1436 | goto done; | ||
1437 | } | ||
1438 | |||
1439 | event.info = fb_info; | ||
1440 | ret = fb_notifier_call_chain(FB_EVENT_FB_UNBIND, &event); | ||
1441 | |||
1442 | if (ret) { | ||
1443 | ret = -EINVAL; | ||
1444 | goto done; | ||
1445 | } | ||
1402 | 1446 | ||
1403 | if (fb_info->pixmap.addr && | 1447 | if (fb_info->pixmap.addr && |
1404 | (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT)) | 1448 | (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT)) |
@@ -1410,7 +1454,8 @@ unregister_framebuffer(struct fb_info *fb_info) | |||
1410 | device_destroy(fb_class, MKDEV(FB_MAJOR, i)); | 1454 | device_destroy(fb_class, MKDEV(FB_MAJOR, i)); |
1411 | event.info = fb_info; | 1455 | event.info = fb_info; |
1412 | fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event); | 1456 | fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event); |
1413 | return 0; | 1457 | done: |
1458 | return ret; | ||
1414 | } | 1459 | } |
1415 | 1460 | ||
1416 | /** | 1461 | /** |
diff --git a/drivers/video/fm2fb.c b/drivers/video/fm2fb.c index 70ff55b14596..6c91c61cdb63 100644 --- a/drivers/video/fm2fb.c +++ b/drivers/video/fm2fb.c | |||
@@ -195,13 +195,15 @@ static int fm2fb_blank(int blank, struct fb_info *info) | |||
195 | static int fm2fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, | 195 | static int fm2fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, |
196 | u_int transp, struct fb_info *info) | 196 | u_int transp, struct fb_info *info) |
197 | { | 197 | { |
198 | if (regno > info->cmap.len) | 198 | if (regno < 16) { |
199 | return 1; | 199 | red >>= 8; |
200 | red >>= 8; | 200 | green >>= 8; |
201 | green >>= 8; | 201 | blue >>= 8; |
202 | blue >>= 8; | 202 | |
203 | ((u32*)(info->pseudo_palette))[regno] = (red << 16) | | ||
204 | (green << 8) | blue; | ||
205 | } | ||
203 | 206 | ||
204 | ((u32*)(info->pseudo_palette))[regno] = (red << 16) | (green << 8) | blue; | ||
205 | return 0; | 207 | return 0; |
206 | } | 208 | } |
207 | 209 | ||
@@ -237,7 +239,7 @@ static int __devinit fm2fb_probe(struct zorro_dev *z, | |||
237 | if (!zorro_request_device(z,"fm2fb")) | 239 | if (!zorro_request_device(z,"fm2fb")) |
238 | return -ENXIO; | 240 | return -ENXIO; |
239 | 241 | ||
240 | info = framebuffer_alloc(256 * sizeof(u32), &z->dev); | 242 | info = framebuffer_alloc(16 * sizeof(u32), &z->dev); |
241 | if (!info) { | 243 | if (!info) { |
242 | zorro_release_device(z); | 244 | zorro_release_device(z); |
243 | return -ENOMEM; | 245 | return -ENOMEM; |
diff --git a/drivers/video/gbefb.c b/drivers/video/gbefb.c index bf0e60b5a3b6..b9b572b293d4 100644 --- a/drivers/video/gbefb.c +++ b/drivers/video/gbefb.c | |||
@@ -86,7 +86,7 @@ static int gbe_revision; | |||
86 | 86 | ||
87 | static int ypan, ywrap; | 87 | static int ypan, ywrap; |
88 | 88 | ||
89 | static uint32_t pseudo_palette[256]; | 89 | static uint32_t pseudo_palette[16]; |
90 | 90 | ||
91 | static char *mode_option __initdata = NULL; | 91 | static char *mode_option __initdata = NULL; |
92 | 92 | ||
@@ -854,8 +854,7 @@ static int gbefb_setcolreg(unsigned regno, unsigned red, unsigned green, | |||
854 | green >>= 8; | 854 | green >>= 8; |
855 | blue >>= 8; | 855 | blue >>= 8; |
856 | 856 | ||
857 | switch (info->var.bits_per_pixel) { | 857 | if (info->var.bits_per_pixel <= 8) { |
858 | case 8: | ||
859 | /* wait for the color map FIFO to have a free entry */ | 858 | /* wait for the color map FIFO to have a free entry */ |
860 | for (i = 0; i < 1000 && gbe->cm_fifo >= 63; i++) | 859 | for (i = 0; i < 1000 && gbe->cm_fifo >= 63; i++) |
861 | udelay(10); | 860 | udelay(10); |
@@ -864,23 +863,25 @@ static int gbefb_setcolreg(unsigned regno, unsigned red, unsigned green, | |||
864 | return 1; | 863 | return 1; |
865 | } | 864 | } |
866 | gbe->cmap[regno] = (red << 24) | (green << 16) | (blue << 8); | 865 | gbe->cmap[regno] = (red << 24) | (green << 16) | (blue << 8); |
867 | break; | 866 | } else if (regno < 16) { |
868 | case 15: | 867 | switch (info->var.bits_per_pixel) { |
869 | case 16: | 868 | case 15: |
870 | red >>= 3; | 869 | case 16: |
871 | green >>= 3; | 870 | red >>= 3; |
872 | blue >>= 3; | 871 | green >>= 3; |
873 | pseudo_palette[regno] = | 872 | blue >>= 3; |
874 | (red << info->var.red.offset) | | 873 | pseudo_palette[regno] = |
875 | (green << info->var.green.offset) | | 874 | (red << info->var.red.offset) | |
876 | (blue << info->var.blue.offset); | 875 | (green << info->var.green.offset) | |
877 | break; | 876 | (blue << info->var.blue.offset); |
878 | case 32: | 877 | break; |
879 | pseudo_palette[regno] = | 878 | case 32: |
880 | (red << info->var.red.offset) | | 879 | pseudo_palette[regno] = |
881 | (green << info->var.green.offset) | | 880 | (red << info->var.red.offset) | |
882 | (blue << info->var.blue.offset); | 881 | (green << info->var.green.offset) | |
883 | break; | 882 | (blue << info->var.blue.offset); |
883 | break; | ||
884 | } | ||
884 | } | 885 | } |
885 | 886 | ||
886 | return 0; | 887 | return 0; |
diff --git a/drivers/video/i810/i810.h b/drivers/video/i810/i810.h index 889e4ea5edc1..328ae6c673ec 100644 --- a/drivers/video/i810/i810.h +++ b/drivers/video/i810/i810.h | |||
@@ -266,7 +266,7 @@ struct i810fb_par { | |||
266 | struct i810fb_i2c_chan chan[3]; | 266 | struct i810fb_i2c_chan chan[3]; |
267 | struct mutex open_lock; | 267 | struct mutex open_lock; |
268 | unsigned int use_count; | 268 | unsigned int use_count; |
269 | u32 pseudo_palette[17]; | 269 | u32 pseudo_palette[16]; |
270 | unsigned long mmio_start_phys; | 270 | unsigned long mmio_start_phys; |
271 | u8 __iomem *mmio_start_virtual; | 271 | u8 __iomem *mmio_start_virtual; |
272 | u8 *edid; | 272 | u8 *edid; |
diff --git a/drivers/video/igafb.c b/drivers/video/igafb.c index eb1a4812ad1d..b87ea21d3d78 100644 --- a/drivers/video/igafb.c +++ b/drivers/video/igafb.c | |||
@@ -379,10 +379,6 @@ int __init igafb_init(void) | |||
379 | if (fb_get_options("igafb", NULL)) | 379 | if (fb_get_options("igafb", NULL)) |
380 | return -ENODEV; | 380 | return -ENODEV; |
381 | 381 | ||
382 | /* Do not attach when we have a serial console. */ | ||
383 | if (!con_is_present()) | ||
384 | return -ENXIO; | ||
385 | |||
386 | pdev = pci_get_device(PCI_VENDOR_ID_INTERG, | 382 | pdev = pci_get_device(PCI_VENDOR_ID_INTERG, |
387 | PCI_DEVICE_ID_INTERG_1682, 0); | 383 | PCI_DEVICE_ID_INTERG_1682, 0); |
388 | if (pdev == NULL) { | 384 | if (pdev == NULL) { |
diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h index 80b94c19a9fa..6148300fadd6 100644 --- a/drivers/video/intelfb/intelfb.h +++ b/drivers/video/intelfb/intelfb.h | |||
@@ -302,7 +302,7 @@ struct intelfb_info { | |||
302 | u32 ring_lockup; | 302 | u32 ring_lockup; |
303 | 303 | ||
304 | /* palette */ | 304 | /* palette */ |
305 | u32 pseudo_palette[17]; | 305 | u32 pseudo_palette[16]; |
306 | 306 | ||
307 | /* chip info */ | 307 | /* chip info */ |
308 | int pci_chipset; | 308 | int pci_chipset; |
diff --git a/drivers/video/logo/Kconfig b/drivers/video/logo/Kconfig index 9397bcef3018..9de1c114f809 100644 --- a/drivers/video/logo/Kconfig +++ b/drivers/video/logo/Kconfig | |||
@@ -10,6 +10,11 @@ menuconfig LOGO | |||
10 | 10 | ||
11 | if LOGO | 11 | if LOGO |
12 | 12 | ||
13 | config FB_LOGO_EXTRA | ||
14 | bool | ||
15 | depends on FB=y | ||
16 | default y if SPU_BASE | ||
17 | |||
13 | config LOGO_LINUX_MONO | 18 | config LOGO_LINUX_MONO |
14 | bool "Standard black and white Linux logo" | 19 | bool "Standard black and white Linux logo" |
15 | default y | 20 | default y |
diff --git a/drivers/video/logo/Makefile b/drivers/video/logo/Makefile index b985dfad6c63..a5fc4edf84e6 100644 --- a/drivers/video/logo/Makefile +++ b/drivers/video/logo/Makefile | |||
@@ -14,6 +14,8 @@ obj-$(CONFIG_LOGO_SUPERH_VGA16) += logo_superh_vga16.o | |||
14 | obj-$(CONFIG_LOGO_SUPERH_CLUT224) += logo_superh_clut224.o | 14 | obj-$(CONFIG_LOGO_SUPERH_CLUT224) += logo_superh_clut224.o |
15 | obj-$(CONFIG_LOGO_M32R_CLUT224) += logo_m32r_clut224.o | 15 | obj-$(CONFIG_LOGO_M32R_CLUT224) += logo_m32r_clut224.o |
16 | 16 | ||
17 | obj-$(CONFIG_SPU_BASE) += logo_spe_clut224.o | ||
18 | |||
17 | # How to generate logo's | 19 | # How to generate logo's |
18 | 20 | ||
19 | # Use logo-cfiles to retrieve list of .c files to be built | 21 | # Use logo-cfiles to retrieve list of .c files to be built |
diff --git a/drivers/video/logo/logo.c b/drivers/video/logo/logo.c index 80c03618eb53..2b0f799aa8da 100644 --- a/drivers/video/logo/logo.c +++ b/drivers/video/logo/logo.c | |||
@@ -34,8 +34,11 @@ extern const struct linux_logo logo_superh_vga16; | |||
34 | extern const struct linux_logo logo_superh_clut224; | 34 | extern const struct linux_logo logo_superh_clut224; |
35 | extern const struct linux_logo logo_m32r_clut224; | 35 | extern const struct linux_logo logo_m32r_clut224; |
36 | 36 | ||
37 | 37 | /* logo's are marked __initdata. Use __init_refok to tell | |
38 | const struct linux_logo *fb_find_logo(int depth) | 38 | * modpost that it is intended that this function uses data |
39 | * marked __initdata. | ||
40 | */ | ||
41 | const struct linux_logo * __init_refok fb_find_logo(int depth) | ||
39 | { | 42 | { |
40 | const struct linux_logo *logo = NULL; | 43 | const struct linux_logo *logo = NULL; |
41 | 44 | ||
diff --git a/drivers/video/logo/logo_spe_clut224.ppm b/drivers/video/logo/logo_spe_clut224.ppm new file mode 100644 index 000000000000..d36ad624a79c --- /dev/null +++ b/drivers/video/logo/logo_spe_clut224.ppm | |||
@@ -0,0 +1,283 @@ | |||
1 | P3 | ||
2 | 40 40 | ||
3 | 255 | ||
4 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
5 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
6 | 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 6 6 6 | ||
7 | 15 15 15 21 21 21 19 19 19 14 14 14 6 6 6 2 2 2 | ||
8 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
9 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
10 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
11 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
12 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
13 | 0 0 0 0 0 0 0 0 0 2 2 2 21 21 21 55 55 55 | ||
14 | 56 56 56 54 54 54 53 53 53 60 60 60 56 56 56 25 25 25 | ||
15 | 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
16 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
17 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
18 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
19 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
20 | 0 0 0 0 0 0 2 2 2 27 27 27 62 62 62 17 17 19 | ||
21 | 2 2 6 2 2 6 2 2 6 2 2 6 16 16 18 57 57 57 | ||
22 | 45 45 45 8 8 8 0 0 0 0 0 0 0 0 0 0 0 0 | ||
23 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
24 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
25 | 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 | ||
26 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
27 | 0 0 0 0 0 0 16 16 16 62 62 62 8 8 10 2 2 6 | ||
28 | 2 2 6 2 2 6 2 2 6 12 12 14 67 67 67 16 16 17 | ||
29 | 45 45 45 41 41 41 4 4 4 0 0 0 0 0 0 0 0 0 | ||
30 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
31 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
32 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
33 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
34 | 0 0 0 2 2 2 35 35 35 40 40 40 2 2 6 2 2 6 | ||
35 | 2 2 6 2 2 6 2 2 6 15 15 17 70 70 70 27 27 27 | ||
36 | 3 3 6 62 62 62 20 20 20 0 0 0 0 0 0 0 0 0 | ||
37 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
38 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
39 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
40 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
41 | 0 0 0 4 4 4 58 58 58 12 12 14 2 2 6 2 2 6 | ||
42 | 2 2 6 2 2 6 2 2 6 4 4 7 4 4 7 2 2 6 | ||
43 | 2 2 6 34 34 36 40 40 40 3 3 3 0 0 0 0 0 0 | ||
44 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
45 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
46 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
47 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
48 | 0 0 0 7 7 7 64 64 64 2 2 6 5 5 5 17 17 17 | ||
49 | 3 3 6 2 2 6 2 2 6 15 15 15 21 21 21 7 7 10 | ||
50 | 2 2 6 8 8 10 62 62 62 6 6 6 0 0 0 0 0 0 | ||
51 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
52 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
53 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
54 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
55 | 0 0 0 7 7 7 66 66 66 5 5 8 122 122 122 122 122 122 | ||
56 | 9 9 11 3 3 6 104 96 81 179 179 179 122 122 122 13 13 13 | ||
57 | 2 2 6 2 2 6 67 67 67 10 10 10 0 0 0 0 0 0 | ||
58 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
59 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
60 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
61 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
62 | 0 0 0 7 7 7 65 65 65 41 41 43 152 149 142 192 191 189 | ||
63 | 48 48 49 23 23 24 228 210 210 86 86 86 192 191 189 59 59 61 | ||
64 | 2 2 6 2 2 6 64 64 64 14 14 14 0 0 0 0 0 0 | ||
65 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
66 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
67 | 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 | ||
68 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
69 | 0 0 0 7 7 7 66 66 66 59 59 59 59 59 61 86 86 86 | ||
70 | 99 84 50 78 66 28 152 149 142 5 5 8 122 122 122 104 96 81 | ||
71 | 2 2 6 2 2 6 67 67 67 14 14 14 0 0 0 0 0 0 | ||
72 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
73 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
74 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
75 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
76 | 0 0 0 5 5 5 63 63 63 24 24 24 152 149 142 175 122 13 | ||
77 | 238 184 12 220 170 13 226 181 52 112 86 32 194 165 151 46 46 47 | ||
78 | 2 2 6 2 2 6 65 65 65 17 17 17 0 0 0 0 0 0 | ||
79 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
80 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
81 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
82 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
83 | 0 0 0 5 5 5 59 59 59 21 21 21 175 122 13 231 174 11 | ||
84 | 240 192 13 237 183 61 240 192 13 240 192 13 234 179 16 81 64 9 | ||
85 | 2 2 6 2 2 6 63 63 63 25 25 25 0 0 0 0 0 0 | ||
86 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
87 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
88 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
89 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
90 | 0 0 0 5 5 5 54 54 54 51 48 39 189 138 9 238 184 12 | ||
91 | 240 192 13 240 192 13 240 192 13 215 161 11 207 152 19 81 64 9 | ||
92 | 16 16 18 5 5 8 40 40 40 44 44 44 4 4 4 0 0 0 | ||
93 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
94 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
95 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
96 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
97 | 0 0 0 5 5 5 59 59 59 27 27 27 126 107 64 187 136 12 | ||
98 | 220 170 13 201 147 20 189 138 9 198 154 46 199 182 125 70 70 70 | ||
99 | 27 27 27 104 96 81 12 12 14 70 70 70 16 16 16 0 0 0 | ||
100 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
101 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
102 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
103 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
104 | 0 0 0 17 17 17 70 70 70 12 12 12 168 168 168 174 135 135 | ||
105 | 175 122 13 175 122 13 178 151 83 192 191 189 233 233 233 179 179 179 | ||
106 | 3 3 6 29 29 31 3 3 6 41 41 41 44 44 44 5 5 5 | ||
107 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
108 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
109 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
110 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
111 | 8 8 8 53 53 53 44 44 44 59 59 59 238 238 238 192 191 189 | ||
112 | 192 191 189 192 191 189 221 205 205 240 240 240 253 253 253 253 253 253 | ||
113 | 70 70 70 2 2 6 2 2 6 5 5 8 67 67 67 22 22 22 | ||
114 | 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
115 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
116 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
117 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 | ||
118 | 38 38 38 56 56 56 7 7 9 221 205 205 253 253 253 233 233 233 | ||
119 | 221 205 205 233 233 233 251 251 251 253 253 253 253 253 253 253 253 253 | ||
120 | 192 191 189 2 2 6 2 2 6 2 2 6 25 25 25 64 64 64 | ||
121 | 15 15 15 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
122 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
123 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
124 | 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 27 27 27 | ||
125 | 66 66 66 7 7 9 86 86 86 252 252 252 253 253 253 253 253 253 | ||
126 | 252 252 252 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 | ||
127 | 244 244 244 19 19 21 2 2 6 2 2 6 2 2 6 38 38 38 | ||
128 | 54 54 54 10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 | ||
129 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
130 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
131 | 0 0 0 0 0 0 0 0 0 0 0 0 14 14 14 62 62 62 | ||
132 | 10 10 12 3 3 6 122 122 122 235 235 235 251 251 251 248 248 248 | ||
133 | 235 235 235 248 248 248 252 252 252 246 246 246 233 233 233 237 228 228 | ||
134 | 223 207 207 70 70 70 2 2 6 2 2 6 2 2 6 2 2 6 | ||
135 | 46 46 47 38 38 38 4 4 4 0 0 0 0 0 0 0 0 0 | ||
136 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
137 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
138 | 0 0 0 0 0 0 0 0 0 2 2 2 33 33 33 44 44 44 | ||
139 | 4 4 7 9 9 11 168 168 168 240 240 240 252 252 252 252 252 252 | ||
140 | 246 246 246 253 253 253 253 253 253 251 251 251 245 241 241 233 233 233 | ||
141 | 221 205 205 192 191 189 29 29 31 27 27 27 9 9 12 2 2 6 | ||
142 | 3 3 6 65 65 65 15 15 15 0 0 0 0 0 0 0 0 0 | ||
143 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
144 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
145 | 0 0 0 0 0 0 0 0 0 6 6 6 59 59 59 19 19 21 | ||
146 | 24 24 24 86 86 86 249 249 249 253 253 253 253 253 253 253 253 253 | ||
147 | 253 253 253 228 210 210 241 230 230 253 253 253 253 253 253 253 253 253 | ||
148 | 251 251 251 228 210 210 152 149 142 5 5 8 27 27 27 4 4 7 | ||
149 | 2 2 6 46 46 47 34 34 34 2 2 2 0 0 0 0 0 0 | ||
150 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
151 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
152 | 0 0 0 0 0 0 0 0 0 16 16 16 67 67 67 19 19 21 | ||
153 | 12 12 14 223 207 207 254 20 20 254 20 20 253 127 127 242 223 223 | ||
154 | 254 20 20 253 127 127 254 48 48 242 223 223 254 86 86 254 20 20 | ||
155 | 254 20 20 253 137 137 233 233 233 32 32 32 35 35 35 23 23 24 | ||
156 | 2 2 6 15 15 15 60 60 60 6 6 6 0 0 0 0 0 0 | ||
157 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
158 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
159 | 0 0 0 0 0 0 4 4 4 38 38 38 48 48 49 22 22 22 | ||
160 | 86 86 86 253 253 253 254 20 20 241 230 230 227 216 186 253 137 137 | ||
161 | 253 137 137 253 253 253 253 137 137 253 137 137 254 48 48 253 253 253 | ||
162 | 253 253 253 253 253 253 253 253 253 62 62 62 2 2 6 23 23 24 | ||
163 | 2 2 6 2 2 6 62 62 62 17 17 17 0 0 0 0 0 0 | ||
164 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
165 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
166 | 0 0 0 0 0 0 14 14 14 70 70 70 14 14 14 16 16 18 | ||
167 | 179 179 179 253 253 253 227 216 186 254 48 48 240 219 160 253 127 127 | ||
168 | 254 20 20 253 137 137 254 86 86 231 203 141 254 20 20 254 20 20 | ||
169 | 253 137 137 253 253 253 253 253 253 104 96 81 2 2 6 23 23 24 | ||
170 | 2 2 6 2 2 6 46 46 47 27 27 27 0 0 0 0 0 0 | ||
171 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
172 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
173 | 0 0 0 4 4 4 39 39 39 42 42 43 19 19 21 13 13 13 | ||
174 | 228 210 210 242 223 223 253 253 253 242 223 223 253 127 127 253 127 127 | ||
175 | 253 127 127 253 127 127 253 137 137 253 253 253 254 48 48 253 253 253 | ||
176 | 228 210 210 253 253 253 253 253 253 122 122 122 2 2 6 19 19 19 | ||
177 | 2 2 6 2 2 6 39 39 39 38 38 38 3 3 3 0 0 0 | ||
178 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
179 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
180 | 0 0 0 8 8 8 60 60 60 3 3 6 33 33 33 38 38 38 | ||
181 | 253 137 137 254 86 86 253 137 137 254 86 86 253 137 137 209 197 168 | ||
182 | 253 127 127 253 253 253 253 253 253 253 253 253 253 127 127 254 86 86 | ||
183 | 254 86 86 253 137 137 253 253 253 122 122 122 2 2 6 17 17 17 | ||
184 | 2 2 6 2 2 6 34 34 36 42 42 43 3 3 3 0 0 0 | ||
185 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
186 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
187 | 0 0 0 13 13 13 59 59 59 2 2 6 9 9 12 56 56 56 | ||
188 | 252 252 252 240 219 160 253 137 137 240 219 160 253 253 253 237 228 228 | ||
189 | 254 86 86 253 253 253 253 253 253 253 253 253 253 253 253 242 223 223 | ||
190 | 227 216 186 249 249 249 253 253 253 122 122 122 16 16 17 17 17 17 | ||
191 | 12 12 14 3 3 6 39 39 39 38 38 38 3 3 3 0 0 0 | ||
192 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
193 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 | ||
194 | 5 5 5 22 22 22 104 96 81 187 136 12 207 152 19 51 48 39 | ||
195 | 221 205 205 253 253 253 253 253 253 253 253 253 253 253 253 240 240 240 | ||
196 | 250 247 243 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 | ||
197 | 253 253 253 250 247 243 240 219 160 99 84 50 5 5 8 2 2 6 | ||
198 | 7 7 9 46 46 47 58 58 58 35 35 35 3 3 3 0 0 0 | ||
199 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
200 | 0 0 0 0 0 0 0 0 0 0 0 0 8 8 8 33 33 33 | ||
201 | 58 58 58 86 86 86 170 136 53 239 182 13 246 190 14 220 170 13 | ||
202 | 44 38 29 179 179 179 253 253 253 253 253 253 253 253 253 240 240 240 | ||
203 | 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 | ||
204 | 253 253 253 240 219 160 240 192 13 112 86 32 2 2 6 2 2 6 | ||
205 | 3 3 6 41 33 20 220 170 13 53 53 53 4 4 4 0 0 0 | ||
206 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
207 | 0 0 0 0 0 0 0 0 0 2 2 2 32 32 32 150 116 44 | ||
208 | 215 161 11 215 161 11 228 170 11 245 188 14 246 190 14 246 190 14 | ||
209 | 187 136 12 9 9 11 122 122 122 251 251 251 253 253 253 253 253 253 | ||
210 | 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 | ||
211 | 248 248 248 211 196 135 239 182 13 175 122 13 6 5 6 2 2 6 | ||
212 | 16 14 12 187 136 12 238 184 12 84 78 65 10 10 10 0 0 0 | ||
213 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
214 | 0 0 0 0 0 0 0 0 0 4 4 4 53 53 53 207 152 19 | ||
215 | 242 185 13 245 188 14 246 190 14 246 190 14 246 190 14 246 190 14 | ||
216 | 240 192 13 81 64 9 2 2 6 86 86 86 244 244 244 253 253 253 | ||
217 | 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 | ||
218 | 233 233 233 199 182 125 231 174 11 207 152 19 175 122 13 175 122 13 | ||
219 | 201 147 20 239 182 13 244 187 14 150 116 44 35 35 35 6 6 6 | ||
220 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
221 | 0 0 0 0 0 0 0 0 0 5 5 5 53 53 53 201 147 20 | ||
222 | 242 185 13 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 | ||
223 | 246 190 14 220 170 13 13 11 10 2 2 6 152 149 142 253 253 253 | ||
224 | 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 | ||
225 | 235 235 235 199 182 125 228 170 11 234 177 12 226 168 11 226 168 11 | ||
226 | 234 177 12 246 190 14 246 190 14 234 179 16 126 107 64 36 36 36 | ||
227 | 6 6 6 0 0 0 0 0 0 0 0 0 | ||
228 | 0 0 0 0 0 0 0 0 0 3 3 3 48 48 49 189 142 35 | ||
229 | 242 185 13 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 | ||
230 | 246 190 14 246 190 14 140 112 39 36 36 36 192 191 189 253 253 253 | ||
231 | 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 | ||
232 | 192 191 189 112 86 32 226 168 11 244 187 14 244 187 14 244 187 14 | ||
233 | 245 188 14 246 190 14 246 190 14 246 190 14 242 185 13 150 116 44 | ||
234 | 27 27 27 2 2 2 0 0 0 0 0 0 | ||
235 | 0 0 0 0 0 0 0 0 0 6 6 6 58 58 58 189 142 35 | ||
236 | 239 182 13 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 | ||
237 | 246 190 14 246 190 14 239 188 14 209 197 168 253 253 253 253 253 253 | ||
238 | 253 253 253 253 253 253 253 253 253 253 253 253 252 252 252 168 168 168 | ||
239 | 16 16 18 97 67 8 228 170 11 245 188 14 246 190 14 246 190 14 | ||
240 | 246 190 14 246 190 14 246 190 14 246 190 14 244 187 14 198 154 46 | ||
241 | 35 35 35 3 3 3 0 0 0 0 0 0 | ||
242 | 0 0 0 0 0 0 0 0 0 13 13 13 84 78 65 215 161 11 | ||
243 | 244 187 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 | ||
244 | 246 190 14 246 190 14 238 184 12 187 136 12 168 168 168 244 244 244 | ||
245 | 253 253 253 252 252 252 240 240 240 179 179 179 67 67 67 2 2 6 | ||
246 | 2 2 6 97 67 8 228 170 11 246 190 14 246 190 14 246 190 14 | ||
247 | 246 190 14 246 190 14 245 188 14 234 177 12 189 142 35 86 77 61 | ||
248 | 16 16 16 0 0 0 0 0 0 0 0 0 | ||
249 | 0 0 0 0 0 0 0 0 0 13 13 13 103 92 56 207 152 19 | ||
250 | 228 170 11 234 177 12 239 182 13 242 186 14 245 188 14 246 190 14 | ||
251 | 246 190 14 246 190 14 239 182 13 189 138 9 41 33 20 10 10 12 | ||
252 | 30 30 31 23 23 24 5 5 8 2 2 6 2 2 6 2 2 6 | ||
253 | 4 4 6 112 86 32 215 161 11 245 188 14 246 190 14 245 188 14 | ||
254 | 239 182 13 228 170 11 189 142 35 104 96 81 48 48 49 17 17 17 | ||
255 | 2 2 2 0 0 0 0 0 0 0 0 0 | ||
256 | 0 0 0 0 0 0 0 0 0 5 5 5 39 39 39 103 92 56 | ||
257 | 141 109 44 175 122 13 187 136 12 189 138 9 207 152 19 228 170 11 | ||
258 | 239 182 13 239 182 13 215 161 11 175 122 13 41 33 20 2 2 6 | ||
259 | 15 15 17 20 20 22 20 20 22 20 20 22 20 20 22 8 8 10 | ||
260 | 4 4 6 97 67 8 189 138 9 231 174 11 239 182 13 226 168 11 | ||
261 | 189 138 9 126 107 64 59 59 59 21 21 21 5 5 5 0 0 0 | ||
262 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
263 | 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 17 17 17 | ||
264 | 34 34 34 57 57 57 84 78 65 103 92 56 125 101 41 140 112 39 | ||
265 | 175 122 13 175 122 13 175 122 13 97 67 8 72 67 58 84 78 65 | ||
266 | 60 60 60 56 56 56 56 56 56 56 56 56 57 57 57 65 65 65 | ||
267 | 86 86 86 95 73 34 175 122 13 187 136 12 187 136 12 175 122 13 | ||
268 | 103 92 56 41 41 41 10 10 10 0 0 0 0 0 0 0 0 0 | ||
269 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
270 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
271 | 2 2 2 4 4 4 12 12 12 24 24 24 40 40 40 70 70 70 | ||
272 | 86 77 61 95 73 34 88 72 41 72 67 58 36 36 36 10 10 10 | ||
273 | 5 5 5 5 5 5 5 5 5 4 4 4 5 5 5 6 6 6 | ||
274 | 22 22 22 61 61 59 88 72 41 112 86 32 112 86 32 84 78 65 | ||
275 | 32 32 32 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 | ||
276 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
277 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
278 | 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 10 10 10 | ||
279 | 21 21 21 33 33 33 31 31 31 16 16 16 2 2 2 0 0 0 | ||
280 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
281 | 2 2 2 12 12 12 30 30 31 40 40 40 32 32 32 16 16 16 | ||
282 | 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
283 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
diff --git a/drivers/video/macfb.c b/drivers/video/macfb.c index f7d647dda978..aa8c714d6245 100644 --- a/drivers/video/macfb.c +++ b/drivers/video/macfb.c | |||
@@ -170,7 +170,7 @@ static struct fb_fix_screeninfo macfb_fix = { | |||
170 | }; | 170 | }; |
171 | 171 | ||
172 | static struct fb_info fb_info; | 172 | static struct fb_info fb_info; |
173 | static u32 pseudo_palette[17]; | 173 | static u32 pseudo_palette[16]; |
174 | static int inverse = 0; | 174 | static int inverse = 0; |
175 | static int vidtest = 0; | 175 | static int vidtest = 0; |
176 | 176 | ||
@@ -529,56 +529,63 @@ static int macfb_setcolreg(unsigned regno, unsigned red, unsigned green, | |||
529 | if (regno >= fb_info->cmap.len) | 529 | if (regno >= fb_info->cmap.len) |
530 | return 1; | 530 | return 1; |
531 | 531 | ||
532 | switch (fb_info->var.bits_per_pixel) { | 532 | if (fb_info->var.bits_per_pixel <= 8) { |
533 | case 1: | 533 | switch (fb_info->var.bits_per_pixel) { |
534 | /* We shouldn't get here */ | 534 | case 1: |
535 | break; | 535 | /* We shouldn't get here */ |
536 | case 2: | 536 | break; |
537 | case 4: | 537 | case 2: |
538 | case 8: | 538 | case 4: |
539 | if (macfb_setpalette) | 539 | case 8: |
540 | macfb_setpalette(regno, red, green, blue, fb_info); | 540 | if (macfb_setpalette) |
541 | else | 541 | macfb_setpalette(regno, red, green, blue, |
542 | return 1; | 542 | fb_info); |
543 | break; | 543 | else |
544 | case 16: | 544 | return 1; |
545 | if (fb_info->var.red.offset == 10) { | 545 | break; |
546 | /* 1:5:5:5 */ | 546 | } |
547 | ((u32*) (fb_info->pseudo_palette))[regno] = | 547 | } else if (regno < 16) { |
548 | switch (fb_info->var.bits_per_pixel) { | ||
549 | case 16: | ||
550 | if (fb_info->var.red.offset == 10) { | ||
551 | /* 1:5:5:5 */ | ||
552 | ((u32*) (fb_info->pseudo_palette))[regno] = | ||
548 | ((red & 0xf800) >> 1) | | 553 | ((red & 0xf800) >> 1) | |
549 | ((green & 0xf800) >> 6) | | 554 | ((green & 0xf800) >> 6) | |
550 | ((blue & 0xf800) >> 11) | | 555 | ((blue & 0xf800) >> 11) | |
551 | ((transp != 0) << 15); | 556 | ((transp != 0) << 15); |
552 | } else { | 557 | } else { |
553 | /* 0:5:6:5 */ | 558 | /* 0:5:6:5 */ |
554 | ((u32*) (fb_info->pseudo_palette))[regno] = | 559 | ((u32*) (fb_info->pseudo_palette))[regno] = |
555 | ((red & 0xf800) ) | | 560 | ((red & 0xf800) ) | |
556 | ((green & 0xfc00) >> 5) | | 561 | ((green & 0xfc00) >> 5) | |
557 | ((blue & 0xf800) >> 11); | 562 | ((blue & 0xf800) >> 11); |
563 | } | ||
564 | break; | ||
565 | /* I'm pretty sure that one or the other of these | ||
566 | doesn't exist on 68k Macs */ | ||
567 | case 24: | ||
568 | red >>= 8; | ||
569 | green >>= 8; | ||
570 | blue >>= 8; | ||
571 | ((u32 *)(fb_info->pseudo_palette))[regno] = | ||
572 | (red << fb_info->var.red.offset) | | ||
573 | (green << fb_info->var.green.offset) | | ||
574 | (blue << fb_info->var.blue.offset); | ||
575 | break; | ||
576 | case 32: | ||
577 | red >>= 8; | ||
578 | green >>= 8; | ||
579 | blue >>= 8; | ||
580 | ((u32 *)(fb_info->pseudo_palette))[regno] = | ||
581 | (red << fb_info->var.red.offset) | | ||
582 | (green << fb_info->var.green.offset) | | ||
583 | (blue << fb_info->var.blue.offset); | ||
584 | break; | ||
558 | } | 585 | } |
559 | break; | 586 | } |
560 | /* I'm pretty sure that one or the other of these | 587 | |
561 | doesn't exist on 68k Macs */ | 588 | return 0; |
562 | case 24: | ||
563 | red >>= 8; | ||
564 | green >>= 8; | ||
565 | blue >>= 8; | ||
566 | ((u32 *)(fb_info->pseudo_palette))[regno] = | ||
567 | (red << fb_info->var.red.offset) | | ||
568 | (green << fb_info->var.green.offset) | | ||
569 | (blue << fb_info->var.blue.offset); | ||
570 | break; | ||
571 | case 32: | ||
572 | red >>= 8; | ||
573 | green >>= 8; | ||
574 | blue >>= 8; | ||
575 | ((u32 *)(fb_info->pseudo_palette))[regno] = | ||
576 | (red << fb_info->var.red.offset) | | ||
577 | (green << fb_info->var.green.offset) | | ||
578 | (blue << fb_info->var.blue.offset); | ||
579 | break; | ||
580 | } | ||
581 | return 0; | ||
582 | } | 589 | } |
583 | 590 | ||
584 | static struct fb_ops macfb_ops = { | 591 | static struct fb_ops macfb_ops = { |
diff --git a/drivers/video/macmodes.c b/drivers/video/macmodes.c index ab2149531a04..083f60321ed8 100644 --- a/drivers/video/macmodes.c +++ b/drivers/video/macmodes.c | |||
@@ -369,9 +369,8 @@ EXPORT_SYMBOL(mac_map_monitor_sense); | |||
369 | * | 369 | * |
370 | */ | 370 | */ |
371 | 371 | ||
372 | int __devinit mac_find_mode(struct fb_var_screeninfo *var, | 372 | int mac_find_mode(struct fb_var_screeninfo *var, struct fb_info *info, |
373 | struct fb_info *info, const char *mode_option, | 373 | const char *mode_option, unsigned int default_bpp) |
374 | unsigned int default_bpp) | ||
375 | { | 374 | { |
376 | const struct fb_videomode *db = NULL; | 375 | const struct fb_videomode *db = NULL; |
377 | unsigned int dbsize = 0; | 376 | unsigned int dbsize = 0; |
diff --git a/drivers/video/macmodes.h b/drivers/video/macmodes.h index babeb81f467d..b86ba08aac9e 100644 --- a/drivers/video/macmodes.h +++ b/drivers/video/macmodes.h | |||
@@ -55,10 +55,10 @@ extern int mac_vmode_to_var(int vmode, int cmode, | |||
55 | extern int mac_var_to_vmode(const struct fb_var_screeninfo *var, int *vmode, | 55 | extern int mac_var_to_vmode(const struct fb_var_screeninfo *var, int *vmode, |
56 | int *cmode); | 56 | int *cmode); |
57 | extern int mac_map_monitor_sense(int sense); | 57 | extern int mac_map_monitor_sense(int sense); |
58 | extern int __devinit mac_find_mode(struct fb_var_screeninfo *var, | 58 | extern int mac_find_mode(struct fb_var_screeninfo *var, |
59 | struct fb_info *info, | 59 | struct fb_info *info, |
60 | const char *mode_option, | 60 | const char *mode_option, |
61 | unsigned int default_bpp); | 61 | unsigned int default_bpp); |
62 | 62 | ||
63 | 63 | ||
64 | /* | 64 | /* |
diff --git a/drivers/video/matrox/matroxfb_accel.c b/drivers/video/matrox/matroxfb_accel.c index c57aaadf410c..3660d2673bdc 100644 --- a/drivers/video/matrox/matroxfb_accel.c +++ b/drivers/video/matrox/matroxfb_accel.c | |||
@@ -91,7 +91,6 @@ static inline void matrox_cfb4_pal(u_int32_t* pal) { | |||
91 | for (i = 0; i < 16; i++) { | 91 | for (i = 0; i < 16; i++) { |
92 | pal[i] = i * 0x11111111U; | 92 | pal[i] = i * 0x11111111U; |
93 | } | 93 | } |
94 | pal[i] = 0xFFFFFFFF; | ||
95 | } | 94 | } |
96 | 95 | ||
97 | static inline void matrox_cfb8_pal(u_int32_t* pal) { | 96 | static inline void matrox_cfb8_pal(u_int32_t* pal) { |
@@ -100,7 +99,6 @@ static inline void matrox_cfb8_pal(u_int32_t* pal) { | |||
100 | for (i = 0; i < 16; i++) { | 99 | for (i = 0; i < 16; i++) { |
101 | pal[i] = i * 0x01010101U; | 100 | pal[i] = i * 0x01010101U; |
102 | } | 101 | } |
103 | pal[i] = 0x0F0F0F0F; | ||
104 | } | 102 | } |
105 | 103 | ||
106 | static void matroxfb_copyarea(struct fb_info* info, const struct fb_copyarea* area); | 104 | static void matroxfb_copyarea(struct fb_info* info, const struct fb_copyarea* area); |
@@ -145,13 +143,10 @@ void matrox_cfbX_init(WPMINFO2) { | |||
145 | ACCESS_FBINFO(fbops).fb_imageblit = matroxfb_imageblit; | 143 | ACCESS_FBINFO(fbops).fb_imageblit = matroxfb_imageblit; |
146 | } | 144 | } |
147 | break; | 145 | break; |
148 | case 16: if (ACCESS_FBINFO(fbcon).var.green.length == 5) { | 146 | case 16: if (ACCESS_FBINFO(fbcon).var.green.length == 5) |
149 | maccess = 0xC0000001; | 147 | maccess = 0xC0000001; |
150 | ACCESS_FBINFO(cmap[16]) = 0x7FFF7FFF; | 148 | else |
151 | } else { | ||
152 | maccess = 0x40000001; | 149 | maccess = 0x40000001; |
153 | ACCESS_FBINFO(cmap[16]) = 0xFFFFFFFF; | ||
154 | } | ||
155 | mopmode = M_OPMODE_16BPP; | 150 | mopmode = M_OPMODE_16BPP; |
156 | if (accel) { | 151 | if (accel) { |
157 | ACCESS_FBINFO(fbops).fb_copyarea = matroxfb_copyarea; | 152 | ACCESS_FBINFO(fbops).fb_copyarea = matroxfb_copyarea; |
@@ -161,7 +156,6 @@ void matrox_cfbX_init(WPMINFO2) { | |||
161 | break; | 156 | break; |
162 | case 24: maccess = 0x00000003; | 157 | case 24: maccess = 0x00000003; |
163 | mopmode = M_OPMODE_24BPP; | 158 | mopmode = M_OPMODE_24BPP; |
164 | ACCESS_FBINFO(cmap[16]) = 0xFFFFFFFF; | ||
165 | if (accel) { | 159 | if (accel) { |
166 | ACCESS_FBINFO(fbops).fb_copyarea = matroxfb_copyarea; | 160 | ACCESS_FBINFO(fbops).fb_copyarea = matroxfb_copyarea; |
167 | ACCESS_FBINFO(fbops).fb_fillrect = matroxfb_fillrect; | 161 | ACCESS_FBINFO(fbops).fb_fillrect = matroxfb_fillrect; |
@@ -170,7 +164,6 @@ void matrox_cfbX_init(WPMINFO2) { | |||
170 | break; | 164 | break; |
171 | case 32: maccess = 0x00000002; | 165 | case 32: maccess = 0x00000002; |
172 | mopmode = M_OPMODE_32BPP; | 166 | mopmode = M_OPMODE_32BPP; |
173 | ACCESS_FBINFO(cmap[16]) = 0xFFFFFFFF; | ||
174 | if (accel) { | 167 | if (accel) { |
175 | ACCESS_FBINFO(fbops).fb_copyarea = matroxfb_copyarea; | 168 | ACCESS_FBINFO(fbops).fb_copyarea = matroxfb_copyarea; |
176 | ACCESS_FBINFO(fbops).fb_fillrect = matroxfb_fillrect; | 169 | ACCESS_FBINFO(fbops).fb_fillrect = matroxfb_fillrect; |
diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c index 886e475f22f2..86ca7b179000 100644 --- a/drivers/video/matrox/matroxfb_base.c +++ b/drivers/video/matrox/matroxfb_base.c | |||
@@ -679,6 +679,8 @@ static int matroxfb_setcolreg(unsigned regno, unsigned red, unsigned green, | |||
679 | mga_outb(M_DAC_VAL, blue); | 679 | mga_outb(M_DAC_VAL, blue); |
680 | break; | 680 | break; |
681 | case 16: | 681 | case 16: |
682 | if (regno >= 16) | ||
683 | break; | ||
682 | { | 684 | { |
683 | u_int16_t col = | 685 | u_int16_t col = |
684 | (red << ACCESS_FBINFO(fbcon).var.red.offset) | | 686 | (red << ACCESS_FBINFO(fbcon).var.red.offset) | |
@@ -690,6 +692,8 @@ static int matroxfb_setcolreg(unsigned regno, unsigned red, unsigned green, | |||
690 | break; | 692 | break; |
691 | case 24: | 693 | case 24: |
692 | case 32: | 694 | case 32: |
695 | if (regno >= 16) | ||
696 | break; | ||
693 | ACCESS_FBINFO(cmap[regno]) = | 697 | ACCESS_FBINFO(cmap[regno]) = |
694 | (red << ACCESS_FBINFO(fbcon).var.red.offset) | | 698 | (red << ACCESS_FBINFO(fbcon).var.red.offset) | |
695 | (green << ACCESS_FBINFO(fbcon).var.green.offset) | | 699 | (green << ACCESS_FBINFO(fbcon).var.green.offset) | |
diff --git a/drivers/video/matrox/matroxfb_base.h b/drivers/video/matrox/matroxfb_base.h index 9c25c2f7966b..d59577c8de86 100644 --- a/drivers/video/matrox/matroxfb_base.h +++ b/drivers/video/matrox/matroxfb_base.h | |||
@@ -518,7 +518,7 @@ struct matrox_fb_info { | |||
518 | dll:1; | 518 | dll:1; |
519 | } memory; | 519 | } memory; |
520 | } values; | 520 | } values; |
521 | u_int32_t cmap[17]; | 521 | u_int32_t cmap[16]; |
522 | }; | 522 | }; |
523 | 523 | ||
524 | #define info2minfo(info) container_of(info, struct matrox_fb_info, fbcon) | 524 | #define info2minfo(info) container_of(info, struct matrox_fb_info, fbcon) |
diff --git a/drivers/video/matrox/matroxfb_crtc2.c b/drivers/video/matrox/matroxfb_crtc2.c index 03ae55b168ff..4b3344e03695 100644 --- a/drivers/video/matrox/matroxfb_crtc2.c +++ b/drivers/video/matrox/matroxfb_crtc2.c | |||
@@ -163,11 +163,6 @@ static void matroxfb_dh_disable(struct matroxfb_dh_fb_info* m2info) { | |||
163 | ACCESS_FBINFO(hw).crtc2.ctl = 0x00000004; | 163 | ACCESS_FBINFO(hw).crtc2.ctl = 0x00000004; |
164 | } | 164 | } |
165 | 165 | ||
166 | static void matroxfb_dh_cfbX_init(struct matroxfb_dh_fb_info* m2info) { | ||
167 | /* no acceleration for secondary head... */ | ||
168 | m2info->cmap[16] = 0xFFFFFFFF; | ||
169 | } | ||
170 | |||
171 | static void matroxfb_dh_pan_var(struct matroxfb_dh_fb_info* m2info, | 166 | static void matroxfb_dh_pan_var(struct matroxfb_dh_fb_info* m2info, |
172 | struct fb_var_screeninfo* var) { | 167 | struct fb_var_screeninfo* var) { |
173 | unsigned int pos; | 168 | unsigned int pos; |
@@ -385,7 +380,6 @@ static int matroxfb_dh_set_par(struct fb_info* info) { | |||
385 | } | 380 | } |
386 | } | 381 | } |
387 | up_read(&ACCESS_FBINFO(altout).lock); | 382 | up_read(&ACCESS_FBINFO(altout).lock); |
388 | matroxfb_dh_cfbX_init(m2info); | ||
389 | } | 383 | } |
390 | m2info->initialized = 1; | 384 | m2info->initialized = 1; |
391 | return 0; | 385 | return 0; |
diff --git a/drivers/video/matrox/matroxfb_crtc2.h b/drivers/video/matrox/matroxfb_crtc2.h index 177177609be7..1005582e843e 100644 --- a/drivers/video/matrox/matroxfb_crtc2.h +++ b/drivers/video/matrox/matroxfb_crtc2.h | |||
@@ -28,7 +28,7 @@ struct matroxfb_dh_fb_info { | |||
28 | 28 | ||
29 | unsigned int interlaced:1; | 29 | unsigned int interlaced:1; |
30 | 30 | ||
31 | u_int32_t cmap[17]; | 31 | u_int32_t cmap[16]; |
32 | }; | 32 | }; |
33 | 33 | ||
34 | #endif /* __MATROXFB_CRTC2_H__ */ | 34 | #endif /* __MATROXFB_CRTC2_H__ */ |
diff --git a/drivers/video/matrox/matroxfb_maven.c b/drivers/video/matrox/matroxfb_maven.c index 5d29a26b8cdf..de0d755f9019 100644 --- a/drivers/video/matrox/matroxfb_maven.c +++ b/drivers/video/matrox/matroxfb_maven.c | |||
@@ -273,8 +273,11 @@ static int matroxfb_PLL_mavenclock(const struct matrox_pll_features2* pll, | |||
273 | } | 273 | } |
274 | } | 274 | } |
275 | } | 275 | } |
276 | |||
277 | /* if h2/post/in/feed have not been assigned, return zero (error) */ | ||
276 | if (besth2 < 2) | 278 | if (besth2 < 2) |
277 | return 0; | 279 | return 0; |
280 | |||
278 | dprintk(KERN_ERR "clk: %02X %02X %02X %d %d\n", *in, *feed, *post, fxtal, fwant); | 281 | dprintk(KERN_ERR "clk: %02X %02X %02X %d %d\n", *in, *feed, *post, fxtal, fwant); |
279 | return fxtal * (*feed) / (*in) * ctl->den; | 282 | return fxtal * (*feed) / (*in) * ctl->den; |
280 | } | 283 | } |
@@ -284,7 +287,7 @@ static unsigned int matroxfb_mavenclock(const struct matrox_pll_ctl* ctl, | |||
284 | unsigned int* in, unsigned int* feed, unsigned int* post, | 287 | unsigned int* in, unsigned int* feed, unsigned int* post, |
285 | unsigned int* htotal2) { | 288 | unsigned int* htotal2) { |
286 | unsigned int fvco; | 289 | unsigned int fvco; |
287 | unsigned int p; | 290 | unsigned int uninitialized_var(p); |
288 | 291 | ||
289 | fvco = matroxfb_PLL_mavenclock(&maven1000_pll, ctl, htotal, vtotal, in, feed, &p, htotal2); | 292 | fvco = matroxfb_PLL_mavenclock(&maven1000_pll, ctl, htotal, vtotal, in, feed, &p, htotal2); |
290 | if (!fvco) | 293 | if (!fvco) |
@@ -715,7 +718,9 @@ static int maven_find_exact_clocks(unsigned int ht, unsigned int vt, | |||
715 | m->regs[0x82] = 0x81; | 718 | m->regs[0x82] = 0x81; |
716 | 719 | ||
717 | for (x = 0; x < 8; x++) { | 720 | for (x = 0; x < 8; x++) { |
718 | unsigned int a, b, c, h2; | 721 | unsigned int c; |
722 | unsigned int uninitialized_var(a), uninitialized_var(b), | ||
723 | uninitialized_var(h2); | ||
719 | unsigned int h = ht + 2 + x; | 724 | unsigned int h = ht + 2 + x; |
720 | 725 | ||
721 | if (!matroxfb_mavenclock((m->mode == MATROXFB_OUTPUT_MODE_PAL) ? &maven_PAL : &maven_NTSC, h, vt, &a, &b, &c, &h2)) { | 726 | if (!matroxfb_mavenclock((m->mode == MATROXFB_OUTPUT_MODE_PAL) ? &maven_PAL : &maven_NTSC, h, vt, &a, &b, &c, &h2)) { |
diff --git a/drivers/video/nvidia/nv_hw.c b/drivers/video/nvidia/nv_hw.c index aff11bbf59a7..d1a10549f543 100644 --- a/drivers/video/nvidia/nv_hw.c +++ b/drivers/video/nvidia/nv_hw.c | |||
@@ -150,8 +150,7 @@ static void nvGetClocks(struct nvidia_par *par, unsigned int *MClk, | |||
150 | M = pll & 0xFF; | 150 | M = pll & 0xFF; |
151 | N = (pll >> 8) & 0xFF; | 151 | N = (pll >> 8) & 0xFF; |
152 | if (((par->Chipset & 0xfff0) == 0x0290) || | 152 | if (((par->Chipset & 0xfff0) == 0x0290) || |
153 | ((par->Chipset & 0xfff0) == 0x0390) || | 153 | ((par->Chipset & 0xfff0) == 0x0390)) { |
154 | ((par->Chipset & 0xfff0) == 0x02E0)) { | ||
155 | MB = 1; | 154 | MB = 1; |
156 | NB = 1; | 155 | NB = 1; |
157 | } else { | 156 | } else { |
@@ -161,7 +160,7 @@ static void nvGetClocks(struct nvidia_par *par, unsigned int *MClk, | |||
161 | *MClk = ((N * NB * par->CrystalFreqKHz) / (M * MB)) >> P; | 160 | *MClk = ((N * NB * par->CrystalFreqKHz) / (M * MB)) >> P; |
162 | 161 | ||
163 | pll = NV_RD32(par->PMC, 0x4000); | 162 | pll = NV_RD32(par->PMC, 0x4000); |
164 | P = (pll >> 16) & 0x03; | 163 | P = (pll >> 16) & 0x07; |
165 | pll = NV_RD32(par->PMC, 0x4004); | 164 | pll = NV_RD32(par->PMC, 0x4004); |
166 | M = pll & 0xFF; | 165 | M = pll & 0xFF; |
167 | N = (pll >> 8) & 0xFF; | 166 | N = (pll >> 8) & 0xFF; |
@@ -892,11 +891,17 @@ void NVCalcStateExt(struct nvidia_par *par, | |||
892 | state->general = bpp == 16 ? 0x00101100 : 0x00100100; | 891 | state->general = bpp == 16 ? 0x00101100 : 0x00100100; |
893 | state->repaint1 = hDisplaySize < 1280 ? 0x04 : 0x00; | 892 | state->repaint1 = hDisplaySize < 1280 ? 0x04 : 0x00; |
894 | break; | 893 | break; |
894 | case NV_ARCH_40: | ||
895 | if (!par->FlatPanel) | ||
896 | state->control = NV_RD32(par->PRAMDAC0, 0x0580) & | ||
897 | 0xeffffeff; | ||
898 | /* fallthrough */ | ||
895 | case NV_ARCH_10: | 899 | case NV_ARCH_10: |
896 | case NV_ARCH_20: | 900 | case NV_ARCH_20: |
897 | case NV_ARCH_30: | 901 | case NV_ARCH_30: |
898 | default: | 902 | default: |
899 | if ((par->Chipset & 0xfff0) == 0x0240) { | 903 | if ((par->Chipset & 0xfff0) == 0x0240 || |
904 | (par->Chipset & 0xfff0) == 0x03d0) { | ||
900 | state->arbitration0 = 256; | 905 | state->arbitration0 = 256; |
901 | state->arbitration1 = 0x0480; | 906 | state->arbitration1 = 0x0480; |
902 | } else if (((par->Chipset & 0xffff) == 0x01A0) || | 907 | } else if (((par->Chipset & 0xffff) == 0x01A0) || |
@@ -939,7 +944,7 @@ void NVCalcStateExt(struct nvidia_par *par, | |||
939 | 944 | ||
940 | void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state) | 945 | void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state) |
941 | { | 946 | { |
942 | int i; | 947 | int i, j; |
943 | 948 | ||
944 | NV_WR32(par->PMC, 0x0140, 0x00000000); | 949 | NV_WR32(par->PMC, 0x0140, 0x00000000); |
945 | NV_WR32(par->PMC, 0x0200, 0xFFFF00FF); | 950 | NV_WR32(par->PMC, 0x0200, 0xFFFF00FF); |
@@ -951,7 +956,8 @@ void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state) | |||
951 | NV_WR32(par->PTIMER, 0x0100 * 4, 0xFFFFFFFF); | 956 | NV_WR32(par->PTIMER, 0x0100 * 4, 0xFFFFFFFF); |
952 | 957 | ||
953 | if (par->Architecture == NV_ARCH_04) { | 958 | if (par->Architecture == NV_ARCH_04) { |
954 | NV_WR32(par->PFB, 0x0200, state->config); | 959 | if (state) |
960 | NV_WR32(par->PFB, 0x0200, state->config); | ||
955 | } else if ((par->Architecture < NV_ARCH_40) || | 961 | } else if ((par->Architecture < NV_ARCH_40) || |
956 | (par->Chipset & 0xfff0) == 0x0040) { | 962 | (par->Chipset & 0xfff0) == 0x0040) { |
957 | for (i = 0; i < 8; i++) { | 963 | for (i = 0; i < 8; i++) { |
@@ -964,8 +970,9 @@ void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state) | |||
964 | 970 | ||
965 | if (((par->Chipset & 0xfff0) == 0x0090) || | 971 | if (((par->Chipset & 0xfff0) == 0x0090) || |
966 | ((par->Chipset & 0xfff0) == 0x01D0) || | 972 | ((par->Chipset & 0xfff0) == 0x01D0) || |
967 | ((par->Chipset & 0xfff0) == 0x02E0) || | 973 | ((par->Chipset & 0xfff0) == 0x0290) || |
968 | ((par->Chipset & 0xfff0) == 0x0290)) | 974 | ((par->Chipset & 0xfff0) == 0x0390) || |
975 | ((par->Chipset & 0xfff0) == 0x03D0)) | ||
969 | regions = 15; | 976 | regions = 15; |
970 | for(i = 0; i < regions; i++) { | 977 | for(i = 0; i < regions; i++) { |
971 | NV_WR32(par->PFB, 0x0600 + (i * 0x10), 0); | 978 | NV_WR32(par->PFB, 0x0600 + (i * 0x10), 0); |
@@ -1206,16 +1213,20 @@ void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state) | |||
1206 | NV_WR32(par->PGRAPH, 0x0608, 0xFFFFFFFF); | 1213 | NV_WR32(par->PGRAPH, 0x0608, 0xFFFFFFFF); |
1207 | } else { | 1214 | } else { |
1208 | if (par->Architecture >= NV_ARCH_40) { | 1215 | if (par->Architecture >= NV_ARCH_40) { |
1209 | u32 tmp; | ||
1210 | |||
1211 | NV_WR32(par->PGRAPH, 0x0084, 0x401287c0); | 1216 | NV_WR32(par->PGRAPH, 0x0084, 0x401287c0); |
1212 | NV_WR32(par->PGRAPH, 0x008C, 0x60de8051); | 1217 | NV_WR32(par->PGRAPH, 0x008C, 0x60de8051); |
1213 | NV_WR32(par->PGRAPH, 0x0090, 0x00008000); | 1218 | NV_WR32(par->PGRAPH, 0x0090, 0x00008000); |
1214 | NV_WR32(par->PGRAPH, 0x0610, 0x00be3c5f); | 1219 | NV_WR32(par->PGRAPH, 0x0610, 0x00be3c5f); |
1220 | NV_WR32(par->PGRAPH, 0x0bc4, | ||
1221 | NV_RD32(par->PGRAPH, 0x0bc4) | | ||
1222 | 0x00008000); | ||
1215 | 1223 | ||
1216 | tmp = NV_RD32(par->REGS, 0x1540) & 0xff; | 1224 | j = NV_RD32(par->REGS, 0x1540) & 0xff; |
1217 | for(i = 0; tmp && !(tmp & 1); tmp >>= 1, i++); | 1225 | |
1218 | NV_WR32(par->PGRAPH, 0x5000, i); | 1226 | if (j) { |
1227 | for (i = 0; !(j & 1); j >>= 1, i++); | ||
1228 | NV_WR32(par->PGRAPH, 0x5000, i); | ||
1229 | } | ||
1219 | 1230 | ||
1220 | if ((par->Chipset & 0xfff0) == 0x0040) { | 1231 | if ((par->Chipset & 0xfff0) == 0x0040) { |
1221 | NV_WR32(par->PGRAPH, 0x09b0, | 1232 | NV_WR32(par->PGRAPH, 0x09b0, |
@@ -1250,6 +1261,7 @@ void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state) | |||
1250 | case 0x0160: | 1261 | case 0x0160: |
1251 | case 0x01D0: | 1262 | case 0x01D0: |
1252 | case 0x0240: | 1263 | case 0x0240: |
1264 | case 0x03D0: | ||
1253 | NV_WR32(par->PMC, 0x1700, | 1265 | NV_WR32(par->PMC, 0x1700, |
1254 | NV_RD32(par->PFB, 0x020C)); | 1266 | NV_RD32(par->PFB, 0x020C)); |
1255 | NV_WR32(par->PMC, 0x1704, 0); | 1267 | NV_WR32(par->PMC, 0x1704, 0); |
@@ -1269,7 +1281,6 @@ void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state) | |||
1269 | 0x00000108); | 1281 | 0x00000108); |
1270 | break; | 1282 | break; |
1271 | case 0x0220: | 1283 | case 0x0220: |
1272 | case 0x0230: | ||
1273 | NV_WR32(par->PGRAPH, 0x0860, 0); | 1284 | NV_WR32(par->PGRAPH, 0x0860, 0); |
1274 | NV_WR32(par->PGRAPH, 0x0864, 0); | 1285 | NV_WR32(par->PGRAPH, 0x0864, 0); |
1275 | NV_WR32(par->PRAMDAC, 0x0608, | 1286 | NV_WR32(par->PRAMDAC, 0x0608, |
@@ -1277,8 +1288,8 @@ void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state) | |||
1277 | 0x00100000); | 1288 | 0x00100000); |
1278 | break; | 1289 | break; |
1279 | case 0x0090: | 1290 | case 0x0090: |
1280 | case 0x02E0: | ||
1281 | case 0x0290: | 1291 | case 0x0290: |
1292 | case 0x0390: | ||
1282 | NV_WR32(par->PRAMDAC, 0x0608, | 1293 | NV_WR32(par->PRAMDAC, 0x0608, |
1283 | NV_RD32(par->PRAMDAC, 0x0608) | | 1294 | NV_RD32(par->PRAMDAC, 0x0608) | |
1284 | 0x00100000); | 1295 | 0x00100000); |
@@ -1355,8 +1366,9 @@ void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state) | |||
1355 | } else { | 1366 | } else { |
1356 | if (((par->Chipset & 0xfff0) == 0x0090) || | 1367 | if (((par->Chipset & 0xfff0) == 0x0090) || |
1357 | ((par->Chipset & 0xfff0) == 0x01D0) || | 1368 | ((par->Chipset & 0xfff0) == 0x01D0) || |
1358 | ((par->Chipset & 0xfff0) == 0x02E0) || | 1369 | ((par->Chipset & 0xfff0) == 0x0290) || |
1359 | ((par->Chipset & 0xfff0) == 0x0290)) { | 1370 | ((par->Chipset & 0xfff0) == 0x0390) || |
1371 | ((par->Chipset & 0xfff0) == 0x03D0)) { | ||
1360 | for (i = 0; i < 60; i++) { | 1372 | for (i = 0; i < 60; i++) { |
1361 | NV_WR32(par->PGRAPH, | 1373 | NV_WR32(par->PGRAPH, |
1362 | 0x0D00 + i*4, | 1374 | 0x0D00 + i*4, |
@@ -1407,8 +1419,8 @@ void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state) | |||
1407 | } else { | 1419 | } else { |
1408 | if ((par->Chipset & 0xfff0) == 0x0090 || | 1420 | if ((par->Chipset & 0xfff0) == 0x0090 || |
1409 | (par->Chipset & 0xfff0) == 0x01D0 || | 1421 | (par->Chipset & 0xfff0) == 0x01D0 || |
1410 | (par->Chipset & 0xfff0) == 0x02E0 || | 1422 | (par->Chipset & 0xfff0) == 0x0290 || |
1411 | (par->Chipset & 0xfff0) == 0x0290) { | 1423 | (par->Chipset & 0xfff0) == 0x0390) { |
1412 | NV_WR32(par->PGRAPH, 0x0DF0, | 1424 | NV_WR32(par->PGRAPH, 0x0DF0, |
1413 | NV_RD32(par->PFB, 0x0200)); | 1425 | NV_RD32(par->PFB, 0x0200)); |
1414 | NV_WR32(par->PGRAPH, 0x0DF4, | 1426 | NV_WR32(par->PGRAPH, 0x0DF4, |
@@ -1495,6 +1507,12 @@ void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state) | |||
1495 | NV_WR32(par->PFIFO, 0x0494 * 4, 0x00000001); | 1507 | NV_WR32(par->PFIFO, 0x0494 * 4, 0x00000001); |
1496 | NV_WR32(par->PFIFO, 0x0495 * 4, 0x00000001); | 1508 | NV_WR32(par->PFIFO, 0x0495 * 4, 0x00000001); |
1497 | NV_WR32(par->PFIFO, 0x0140 * 4, 0x00000001); | 1509 | NV_WR32(par->PFIFO, 0x0140 * 4, 0x00000001); |
1510 | |||
1511 | if (!state) { | ||
1512 | par->CurrentState = NULL; | ||
1513 | return; | ||
1514 | } | ||
1515 | |||
1498 | if (par->Architecture >= NV_ARCH_10) { | 1516 | if (par->Architecture >= NV_ARCH_10) { |
1499 | if (par->twoHeads) { | 1517 | if (par->twoHeads) { |
1500 | NV_WR32(par->PCRTC0, 0x0860, state->head); | 1518 | NV_WR32(par->PCRTC0, 0x0860, state->head); |
@@ -1566,6 +1584,9 @@ void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state) | |||
1566 | VGA_WR08(par->PCIO, 0x03D5, state->interlace); | 1584 | VGA_WR08(par->PCIO, 0x03D5, state->interlace); |
1567 | 1585 | ||
1568 | if (!par->FlatPanel) { | 1586 | if (!par->FlatPanel) { |
1587 | if (par->Architecture >= NV_ARCH_40) | ||
1588 | NV_WR32(par->PRAMDAC0, 0x0580, state->control); | ||
1589 | |||
1569 | NV_WR32(par->PRAMDAC0, 0x050C, state->pllsel); | 1590 | NV_WR32(par->PRAMDAC0, 0x050C, state->pllsel); |
1570 | NV_WR32(par->PRAMDAC0, 0x0508, state->vpll); | 1591 | NV_WR32(par->PRAMDAC0, 0x0508, state->vpll); |
1571 | if (par->twoHeads) | 1592 | if (par->twoHeads) |
@@ -1631,6 +1652,9 @@ void NVUnloadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state) { | |||
1631 | state->scale = NV_RD32(par->PRAMDAC, 0x0848); | 1652 | state->scale = NV_RD32(par->PRAMDAC, 0x0848); |
1632 | state->config = NV_RD32(par->PFB, 0x0200); | 1653 | state->config = NV_RD32(par->PFB, 0x0200); |
1633 | 1654 | ||
1655 | if (par->Architecture >= NV_ARCH_40 && !par->FlatPanel) | ||
1656 | state->control = NV_RD32(par->PRAMDAC0, 0x0580); | ||
1657 | |||
1634 | if (par->Architecture >= NV_ARCH_10) { | 1658 | if (par->Architecture >= NV_ARCH_10) { |
1635 | if (par->twoHeads) { | 1659 | if (par->twoHeads) { |
1636 | state->head = NV_RD32(par->PCRTC0, 0x0860); | 1660 | state->head = NV_RD32(par->PCRTC0, 0x0860); |
diff --git a/drivers/video/nvidia/nv_setup.c b/drivers/video/nvidia/nv_setup.c index 707e2c8a13ed..82579d3a9970 100644 --- a/drivers/video/nvidia/nv_setup.c +++ b/drivers/video/nvidia/nv_setup.c | |||
@@ -166,11 +166,13 @@ u8 NVReadDacData(struct nvidia_par *par) | |||
166 | static int NVIsConnected(struct nvidia_par *par, int output) | 166 | static int NVIsConnected(struct nvidia_par *par, int output) |
167 | { | 167 | { |
168 | volatile u32 __iomem *PRAMDAC = par->PRAMDAC0; | 168 | volatile u32 __iomem *PRAMDAC = par->PRAMDAC0; |
169 | u32 reg52C, reg608; | 169 | u32 reg52C, reg608, dac0_reg608 = 0; |
170 | int present; | 170 | int present; |
171 | 171 | ||
172 | if (output) | 172 | if (output) { |
173 | PRAMDAC += 0x800; | 173 | dac0_reg608 = NV_RD32(PRAMDAC, 0x0608); |
174 | PRAMDAC += 0x800; | ||
175 | } | ||
174 | 176 | ||
175 | reg52C = NV_RD32(PRAMDAC, 0x052C); | 177 | reg52C = NV_RD32(PRAMDAC, 0x052C); |
176 | reg608 = NV_RD32(PRAMDAC, 0x0608); | 178 | reg608 = NV_RD32(PRAMDAC, 0x0608); |
@@ -194,8 +196,8 @@ static int NVIsConnected(struct nvidia_par *par, int output) | |||
194 | else | 196 | else |
195 | printk("nvidiafb: CRTC%i analog not found\n", output); | 197 | printk("nvidiafb: CRTC%i analog not found\n", output); |
196 | 198 | ||
197 | NV_WR32(par->PRAMDAC0, 0x0608, NV_RD32(par->PRAMDAC0, 0x0608) & | 199 | if (output) |
198 | 0x0000EFFF); | 200 | NV_WR32(par->PRAMDAC0, 0x0608, dac0_reg608); |
199 | 201 | ||
200 | NV_WR32(PRAMDAC, 0x052C, reg52C); | 202 | NV_WR32(PRAMDAC, 0x052C, reg52C); |
201 | NV_WR32(PRAMDAC, 0x0608, reg608); | 203 | NV_WR32(PRAMDAC, 0x0608, reg608); |
diff --git a/drivers/video/nvidia/nv_type.h b/drivers/video/nvidia/nv_type.h index 38f7cc0a2331..2fdf77ec39fc 100644 --- a/drivers/video/nvidia/nv_type.h +++ b/drivers/video/nvidia/nv_type.h | |||
@@ -86,6 +86,7 @@ typedef struct _riva_hw_state { | |||
86 | u32 timingV; | 86 | u32 timingV; |
87 | u32 displayV; | 87 | u32 displayV; |
88 | u32 crtcSync; | 88 | u32 crtcSync; |
89 | u32 control; | ||
89 | } RIVA_HW_STATE; | 90 | } RIVA_HW_STATE; |
90 | 91 | ||
91 | struct riva_regs { | 92 | struct riva_regs { |
diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c index 41f63658572f..a7fe214f0f77 100644 --- a/drivers/video/nvidia/nvidia.c +++ b/drivers/video/nvidia/nvidia.c | |||
@@ -674,6 +674,7 @@ static int nvidiafb_set_par(struct fb_info *info) | |||
674 | info->fbops->fb_sync = nvidiafb_sync; | 674 | info->fbops->fb_sync = nvidiafb_sync; |
675 | info->pixmap.scan_align = 4; | 675 | info->pixmap.scan_align = 4; |
676 | info->flags &= ~FBINFO_HWACCEL_DISABLED; | 676 | info->flags &= ~FBINFO_HWACCEL_DISABLED; |
677 | info->flags |= FBINFO_READS_FAST; | ||
677 | NVResetGraphics(info); | 678 | NVResetGraphics(info); |
678 | } else { | 679 | } else { |
679 | info->fbops->fb_imageblit = cfb_imageblit; | 680 | info->fbops->fb_imageblit = cfb_imageblit; |
@@ -682,6 +683,7 @@ static int nvidiafb_set_par(struct fb_info *info) | |||
682 | info->fbops->fb_sync = NULL; | 683 | info->fbops->fb_sync = NULL; |
683 | info->pixmap.scan_align = 1; | 684 | info->pixmap.scan_align = 1; |
684 | info->flags |= FBINFO_HWACCEL_DISABLED; | 685 | info->flags |= FBINFO_HWACCEL_DISABLED; |
686 | info->flags &= ~FBINFO_READS_FAST; | ||
685 | } | 687 | } |
686 | 688 | ||
687 | par->cursor_reset = 1; | 689 | par->cursor_reset = 1; |
@@ -1193,7 +1195,8 @@ static u32 __devinit nvidia_get_chipset(struct fb_info *info) | |||
1193 | 1195 | ||
1194 | printk(KERN_INFO PFX "Device ID: %x \n", id); | 1196 | printk(KERN_INFO PFX "Device ID: %x \n", id); |
1195 | 1197 | ||
1196 | if ((id & 0xfff0) == 0x00f0) { | 1198 | if ((id & 0xfff0) == 0x00f0 || |
1199 | (id & 0xfff0) == 0x02e0) { | ||
1197 | /* pci-e */ | 1200 | /* pci-e */ |
1198 | id = NV_RD32(par->REGS, 0x1800); | 1201 | id = NV_RD32(par->REGS, 0x1800); |
1199 | 1202 | ||
@@ -1238,18 +1241,16 @@ static u32 __devinit nvidia_get_arch(struct fb_info *info) | |||
1238 | case 0x0040: /* GeForce 6800 */ | 1241 | case 0x0040: /* GeForce 6800 */ |
1239 | case 0x00C0: /* GeForce 6800 */ | 1242 | case 0x00C0: /* GeForce 6800 */ |
1240 | case 0x0120: /* GeForce 6800 */ | 1243 | case 0x0120: /* GeForce 6800 */ |
1241 | case 0x0130: | ||
1242 | case 0x0140: /* GeForce 6600 */ | 1244 | case 0x0140: /* GeForce 6600 */ |
1243 | case 0x0160: /* GeForce 6200 */ | 1245 | case 0x0160: /* GeForce 6200 */ |
1244 | case 0x01D0: /* GeForce 7200, 7300, 7400 */ | 1246 | case 0x01D0: /* GeForce 7200, 7300, 7400 */ |
1245 | case 0x02E0: /* GeForce 7300 GT */ | ||
1246 | case 0x0090: /* GeForce 7800 */ | 1247 | case 0x0090: /* GeForce 7800 */ |
1247 | case 0x0210: /* GeForce 6800 */ | 1248 | case 0x0210: /* GeForce 6800 */ |
1248 | case 0x0220: /* GeForce 6200 */ | 1249 | case 0x0220: /* GeForce 6200 */ |
1249 | case 0x0230: | ||
1250 | case 0x0240: /* GeForce 6100 */ | 1250 | case 0x0240: /* GeForce 6100 */ |
1251 | case 0x0290: /* GeForce 7900 */ | 1251 | case 0x0290: /* GeForce 7900 */ |
1252 | case 0x0390: /* GeForce 7600 */ | 1252 | case 0x0390: /* GeForce 7600 */ |
1253 | case 0x03D0: | ||
1253 | arch = NV_ARCH_40; | 1254 | arch = NV_ARCH_40; |
1254 | break; | 1255 | break; |
1255 | case 0x0020: /* TNT, TNT2 */ | 1256 | case 0x0020: /* TNT, TNT2 */ |
diff --git a/drivers/video/offb.c b/drivers/video/offb.c index 885b42836cbb..452433d46973 100644 --- a/drivers/video/offb.c +++ b/drivers/video/offb.c | |||
@@ -271,7 +271,7 @@ static void __init offb_init_fb(const char *name, const char *full_name, | |||
271 | return; | 271 | return; |
272 | } | 272 | } |
273 | 273 | ||
274 | size = sizeof(struct fb_info) + sizeof(u32) * 17; | 274 | size = sizeof(struct fb_info) + sizeof(u32) * 16; |
275 | 275 | ||
276 | info = kmalloc(size, GFP_ATOMIC); | 276 | info = kmalloc(size, GFP_ATOMIC); |
277 | 277 | ||
diff --git a/drivers/video/omap/Kconfig b/drivers/video/omap/Kconfig new file mode 100644 index 000000000000..7f4d25b8a184 --- /dev/null +++ b/drivers/video/omap/Kconfig | |||
@@ -0,0 +1,58 @@ | |||
1 | config FB_OMAP | ||
2 | tristate "OMAP frame buffer support (EXPERIMENTAL)" | ||
3 | depends on FB | ||
4 | select FB_CFB_FILLRECT | ||
5 | select FB_CFB_COPYAREA | ||
6 | select FB_CFB_IMAGEBLIT | ||
7 | help | ||
8 | Frame buffer driver for OMAP based boards. | ||
9 | |||
10 | config FB_OMAP_BOOTLOADER_INIT | ||
11 | bool "Check bootloader initializaion" | ||
12 | depends on FB_OMAP | ||
13 | help | ||
14 | Say Y here if you want to enable checking if the bootloader has | ||
15 | already initialized the display controller. In this case the | ||
16 | driver will skip the initialization. | ||
17 | |||
18 | config FB_OMAP_CONSISTENT_DMA_SIZE | ||
19 | int "Consistent DMA memory size (MB)" | ||
20 | depends on FB_OMAP | ||
21 | range 1 14 | ||
22 | default 2 | ||
23 | help | ||
24 | Increase the DMA consistent memory size according to your video | ||
25 | memory needs, for example if you want to use multiple planes. | ||
26 | The size must be 2MB aligned. | ||
27 | If unsure say 1. | ||
28 | |||
29 | config FB_OMAP_DMA_TUNE | ||
30 | bool "Set DMA SDRAM access priority high" | ||
31 | depends on FB_OMAP && ARCH_OMAP1 | ||
32 | help | ||
33 | On systems in which video memory is in system memory | ||
34 | (SDRAM) this will speed up graphics DMA operations. | ||
35 | If you have such a system and want to use rotation | ||
36 | answer yes. Answer no if you have a dedicated video | ||
37 | memory, or don't use any of the accelerated features. | ||
38 | |||
39 | config FB_OMAP_LCDC_EXTERNAL | ||
40 | bool "External LCD controller support" | ||
41 | depends on FB_OMAP | ||
42 | help | ||
43 | Say Y here, if you want to have support for boards with an | ||
44 | external LCD controller connected to the SoSSI/RFBI interface. | ||
45 | |||
46 | config FB_OMAP_LCDC_HWA742 | ||
47 | bool "Epson HWA742 LCD controller support" | ||
48 | depends on FB_OMAP && FB_OMAP_LCDC_EXTERNAL | ||
49 | help | ||
50 | Say Y here if you want to have support for the external | ||
51 | Epson HWA742 LCD controller. | ||
52 | |||
53 | config FB_OMAP_LCDC_BLIZZARD | ||
54 | bool "Epson Blizzard LCD controller support" | ||
55 | depends on FB_OMAP && FB_OMAP_LCDC_EXTERNAL | ||
56 | help | ||
57 | Say Y here if you want to have support for the external | ||
58 | Epson Blizzard LCD controller. | ||
diff --git a/drivers/video/omap/Makefile b/drivers/video/omap/Makefile new file mode 100644 index 000000000000..99da8b6d2c36 --- /dev/null +++ b/drivers/video/omap/Makefile | |||
@@ -0,0 +1,29 @@ | |||
1 | # | ||
2 | # Makefile for the new OMAP framebuffer device driver | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_FB_OMAP) += omapfb.o | ||
6 | |||
7 | objs-yy := omapfb_main.o | ||
8 | |||
9 | objs-y$(CONFIG_ARCH_OMAP1) += lcdc.o | ||
10 | objs-y$(CONFIG_ARCH_OMAP2) += dispc.o | ||
11 | |||
12 | objs-$(CONFIG_ARCH_OMAP1)$(CONFIG_FB_OMAP_LCDC_EXTERNAL) += sossi.o | ||
13 | objs-$(CONFIG_ARCH_OMAP2)$(CONFIG_FB_OMAP_LCDC_EXTERNAL) += rfbi.o | ||
14 | |||
15 | objs-y$(CONFIG_FB_OMAP_LCDC_HWA742) += hwa742.o | ||
16 | objs-y$(CONFIG_FB_OMAP_LCDC_BLIZZARD) += blizzard.o | ||
17 | |||
18 | objs-y$(CONFIG_MACH_OMAP_H4) += lcd_h4.o | ||
19 | objs-y$(CONFIG_MACH_OMAP_H3) += lcd_h3.o | ||
20 | objs-y$(CONFIG_MACH_OMAP_PALMTE) += lcd_palmte.o | ||
21 | objs-y$(CONFIG_MACH_OMAP_PALMTT) += lcd_palmtt.o | ||
22 | objs-y$(CONFIG_MACH_OMAP_PALMZ71) += lcd_palmz71.o | ||
23 | objs-$(CONFIG_ARCH_OMAP16XX)$(CONFIG_MACH_OMAP_INNOVATOR) += lcd_inn1610.o | ||
24 | objs-$(CONFIG_ARCH_OMAP15XX)$(CONFIG_MACH_OMAP_INNOVATOR) += lcd_inn1510.o | ||
25 | objs-y$(CONFIG_MACH_OMAP_OSK) += lcd_osk.o | ||
26 | objs-y$(CONFIG_MACH_SX1) += lcd_sx1.o | ||
27 | |||
28 | omapfb-objs := $(objs-yy) | ||
29 | |||
diff --git a/drivers/video/omap/blizzard.c b/drivers/video/omap/blizzard.c new file mode 100644 index 000000000000..e682940a97a4 --- /dev/null +++ b/drivers/video/omap/blizzard.c | |||
@@ -0,0 +1,1568 @@ | |||
1 | /* | ||
2 | * Epson Blizzard LCD controller driver | ||
3 | * | ||
4 | * Copyright (C) 2004-2005 Nokia Corporation | ||
5 | * Authors: Juha Yrjola <juha.yrjola@nokia.com> | ||
6 | * Imre Deak <imre.deak@nokia.com> | ||
7 | * YUV support: Jussi Laako <jussi.laako@nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License as published by the | ||
11 | * Free Software Foundation; either version 2 of the License, or (at your | ||
12 | * option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License along | ||
20 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
21 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
22 | */ | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/mm.h> | ||
25 | #include <linux/fb.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <linux/clk.h> | ||
28 | |||
29 | #include <asm/arch/dma.h> | ||
30 | #include <asm/arch/omapfb.h> | ||
31 | #include <asm/arch/blizzard.h> | ||
32 | |||
33 | #include "dispc.h" | ||
34 | |||
35 | #define MODULE_NAME "blizzard" | ||
36 | |||
37 | #define BLIZZARD_REV_CODE 0x00 | ||
38 | #define BLIZZARD_CONFIG 0x02 | ||
39 | #define BLIZZARD_PLL_DIV 0x04 | ||
40 | #define BLIZZARD_PLL_LOCK_RANGE 0x06 | ||
41 | #define BLIZZARD_PLL_CLOCK_SYNTH_0 0x08 | ||
42 | #define BLIZZARD_PLL_CLOCK_SYNTH_1 0x0a | ||
43 | #define BLIZZARD_PLL_MODE 0x0c | ||
44 | #define BLIZZARD_CLK_SRC 0x0e | ||
45 | #define BLIZZARD_MEM_BANK0_ACTIVATE 0x10 | ||
46 | #define BLIZZARD_MEM_BANK0_STATUS 0x14 | ||
47 | #define BLIZZARD_HDISP 0x2a | ||
48 | #define BLIZZARD_HNDP 0x2c | ||
49 | #define BLIZZARD_VDISP0 0x2e | ||
50 | #define BLIZZARD_VDISP1 0x30 | ||
51 | #define BLIZZARD_VNDP 0x32 | ||
52 | #define BLIZZARD_HSW 0x34 | ||
53 | #define BLIZZARD_VSW 0x38 | ||
54 | #define BLIZZARD_DISPLAY_MODE 0x68 | ||
55 | #define BLIZZARD_INPUT_WIN_X_START_0 0x6c | ||
56 | #define BLIZZARD_DATA_SOURCE_SELECT 0x8e | ||
57 | #define BLIZZARD_DISP_MEM_DATA_PORT 0x90 | ||
58 | #define BLIZZARD_DISP_MEM_READ_ADDR0 0x92 | ||
59 | #define BLIZZARD_POWER_SAVE 0xE6 | ||
60 | #define BLIZZARD_NDISP_CTRL_STATUS 0xE8 | ||
61 | |||
62 | /* Data source select */ | ||
63 | /* For S1D13745 */ | ||
64 | #define BLIZZARD_SRC_WRITE_LCD_BACKGROUND 0x00 | ||
65 | #define BLIZZARD_SRC_WRITE_LCD_DESTRUCTIVE 0x01 | ||
66 | #define BLIZZARD_SRC_WRITE_OVERLAY_ENABLE 0x04 | ||
67 | #define BLIZZARD_SRC_DISABLE_OVERLAY 0x05 | ||
68 | /* For S1D13744 */ | ||
69 | #define BLIZZARD_SRC_WRITE_LCD 0x00 | ||
70 | #define BLIZZARD_SRC_BLT_LCD 0x06 | ||
71 | |||
72 | #define BLIZZARD_COLOR_RGB565 0x01 | ||
73 | #define BLIZZARD_COLOR_YUV420 0x09 | ||
74 | |||
75 | #define BLIZZARD_VERSION_S1D13745 0x01 /* Hailstorm */ | ||
76 | #define BLIZZARD_VERSION_S1D13744 0x02 /* Blizzard */ | ||
77 | |||
78 | #define BLIZZARD_AUTO_UPDATE_TIME (HZ / 20) | ||
79 | |||
80 | /* Reserve 4 request slots for requests in irq context */ | ||
81 | #define REQ_POOL_SIZE 24 | ||
82 | #define IRQ_REQ_POOL_SIZE 4 | ||
83 | |||
84 | #define REQ_FROM_IRQ_POOL 0x01 | ||
85 | |||
86 | #define REQ_COMPLETE 0 | ||
87 | #define REQ_PENDING 1 | ||
88 | |||
89 | struct blizzard_reg_list { | ||
90 | int start; | ||
91 | int end; | ||
92 | }; | ||
93 | |||
94 | /* These need to be saved / restored separately from the rest. */ | ||
95 | static struct blizzard_reg_list blizzard_pll_regs[] = { | ||
96 | { | ||
97 | .start = 0x04, /* Don't save PLL ctrl (0x0C) */ | ||
98 | .end = 0x0a, | ||
99 | }, | ||
100 | { | ||
101 | .start = 0x0e, /* Clock configuration */ | ||
102 | .end = 0x0e, | ||
103 | }, | ||
104 | }; | ||
105 | |||
106 | static struct blizzard_reg_list blizzard_gen_regs[] = { | ||
107 | { | ||
108 | .start = 0x18, /* SDRAM control */ | ||
109 | .end = 0x20, | ||
110 | }, | ||
111 | { | ||
112 | .start = 0x28, /* LCD Panel configuration */ | ||
113 | .end = 0x5a, /* HSSI interface, TV configuration */ | ||
114 | }, | ||
115 | }; | ||
116 | |||
117 | static u8 blizzard_reg_cache[0x5a / 2]; | ||
118 | |||
119 | struct update_param { | ||
120 | int plane; | ||
121 | int x, y, width, height; | ||
122 | int out_x, out_y; | ||
123 | int out_width, out_height; | ||
124 | int color_mode; | ||
125 | int bpp; | ||
126 | int flags; | ||
127 | }; | ||
128 | |||
129 | struct blizzard_request { | ||
130 | struct list_head entry; | ||
131 | unsigned int flags; | ||
132 | |||
133 | int (*handler)(struct blizzard_request *req); | ||
134 | void (*complete)(void *data); | ||
135 | void *complete_data; | ||
136 | |||
137 | union { | ||
138 | struct update_param update; | ||
139 | struct completion *sync; | ||
140 | } par; | ||
141 | }; | ||
142 | |||
143 | struct plane_info { | ||
144 | unsigned long offset; | ||
145 | int pos_x, pos_y; | ||
146 | int width, height; | ||
147 | int out_width, out_height; | ||
148 | int scr_width; | ||
149 | int color_mode; | ||
150 | int bpp; | ||
151 | }; | ||
152 | |||
153 | struct blizzard_struct { | ||
154 | enum omapfb_update_mode update_mode; | ||
155 | enum omapfb_update_mode update_mode_before_suspend; | ||
156 | |||
157 | struct timer_list auto_update_timer; | ||
158 | int stop_auto_update; | ||
159 | struct omapfb_update_window auto_update_window; | ||
160 | int enabled_planes; | ||
161 | int vid_nonstd_color; | ||
162 | int vid_scaled; | ||
163 | int last_color_mode; | ||
164 | int zoom_on; | ||
165 | int screen_width; | ||
166 | int screen_height; | ||
167 | unsigned te_connected:1; | ||
168 | unsigned vsync_only:1; | ||
169 | |||
170 | struct plane_info plane[OMAPFB_PLANE_NUM]; | ||
171 | |||
172 | struct blizzard_request req_pool[REQ_POOL_SIZE]; | ||
173 | struct list_head pending_req_list; | ||
174 | struct list_head free_req_list; | ||
175 | struct semaphore req_sema; | ||
176 | spinlock_t req_lock; | ||
177 | |||
178 | unsigned long sys_ck_rate; | ||
179 | struct extif_timings reg_timings, lut_timings; | ||
180 | |||
181 | u32 max_transmit_size; | ||
182 | u32 extif_clk_period; | ||
183 | int extif_clk_div; | ||
184 | unsigned long pix_tx_time; | ||
185 | unsigned long line_upd_time; | ||
186 | |||
187 | struct omapfb_device *fbdev; | ||
188 | struct lcd_ctrl_extif *extif; | ||
189 | struct lcd_ctrl *int_ctrl; | ||
190 | |||
191 | void (*power_up)(struct device *dev); | ||
192 | void (*power_down)(struct device *dev); | ||
193 | |||
194 | int version; | ||
195 | } blizzard; | ||
196 | |||
197 | struct lcd_ctrl blizzard_ctrl; | ||
198 | |||
199 | static u8 blizzard_read_reg(u8 reg) | ||
200 | { | ||
201 | u8 data; | ||
202 | |||
203 | blizzard.extif->set_bits_per_cycle(8); | ||
204 | blizzard.extif->write_command(®, 1); | ||
205 | blizzard.extif->read_data(&data, 1); | ||
206 | |||
207 | return data; | ||
208 | } | ||
209 | |||
210 | static void blizzard_write_reg(u8 reg, u8 val) | ||
211 | { | ||
212 | blizzard.extif->set_bits_per_cycle(8); | ||
213 | blizzard.extif->write_command(®, 1); | ||
214 | blizzard.extif->write_data(&val, 1); | ||
215 | } | ||
216 | |||
217 | static void blizzard_restart_sdram(void) | ||
218 | { | ||
219 | unsigned long tmo; | ||
220 | |||
221 | blizzard_write_reg(BLIZZARD_MEM_BANK0_ACTIVATE, 0); | ||
222 | udelay(50); | ||
223 | blizzard_write_reg(BLIZZARD_MEM_BANK0_ACTIVATE, 1); | ||
224 | tmo = jiffies + msecs_to_jiffies(200); | ||
225 | while (!(blizzard_read_reg(BLIZZARD_MEM_BANK0_STATUS) & 0x01)) { | ||
226 | if (time_after(jiffies, tmo)) { | ||
227 | dev_err(blizzard.fbdev->dev, | ||
228 | "s1d1374x: SDRAM not ready"); | ||
229 | break; | ||
230 | } | ||
231 | msleep(1); | ||
232 | } | ||
233 | } | ||
234 | |||
235 | static void blizzard_stop_sdram(void) | ||
236 | { | ||
237 | blizzard_write_reg(BLIZZARD_MEM_BANK0_ACTIVATE, 0); | ||
238 | } | ||
239 | |||
240 | /* Wait until the last window was completely written into the controllers | ||
241 | * SDRAM and we can start transferring the next window. | ||
242 | */ | ||
243 | static void blizzard_wait_line_buffer(void) | ||
244 | { | ||
245 | unsigned long tmo = jiffies + msecs_to_jiffies(30); | ||
246 | |||
247 | while (blizzard_read_reg(BLIZZARD_NDISP_CTRL_STATUS) & (1 << 7)) { | ||
248 | if (time_after(jiffies, tmo)) { | ||
249 | if (printk_ratelimit()) | ||
250 | dev_err(blizzard.fbdev->dev, | ||
251 | "s1d1374x: line buffer not ready\n"); | ||
252 | break; | ||
253 | } | ||
254 | } | ||
255 | } | ||
256 | |||
257 | /* Wait until the YYC color space converter is idle. */ | ||
258 | static void blizzard_wait_yyc(void) | ||
259 | { | ||
260 | unsigned long tmo = jiffies + msecs_to_jiffies(30); | ||
261 | |||
262 | while (blizzard_read_reg(BLIZZARD_NDISP_CTRL_STATUS) & (1 << 4)) { | ||
263 | if (time_after(jiffies, tmo)) { | ||
264 | if (printk_ratelimit()) | ||
265 | dev_err(blizzard.fbdev->dev, | ||
266 | "s1d1374x: YYC not ready\n"); | ||
267 | break; | ||
268 | } | ||
269 | } | ||
270 | } | ||
271 | |||
272 | static void disable_overlay(void) | ||
273 | { | ||
274 | blizzard_write_reg(BLIZZARD_DATA_SOURCE_SELECT, | ||
275 | BLIZZARD_SRC_DISABLE_OVERLAY); | ||
276 | } | ||
277 | |||
278 | static void set_window_regs(int x_start, int y_start, int x_end, int y_end, | ||
279 | int x_out_start, int y_out_start, | ||
280 | int x_out_end, int y_out_end, int color_mode, | ||
281 | int zoom_off, int flags) | ||
282 | { | ||
283 | u8 tmp[18]; | ||
284 | u8 cmd; | ||
285 | |||
286 | x_end--; | ||
287 | y_end--; | ||
288 | tmp[0] = x_start; | ||
289 | tmp[1] = x_start >> 8; | ||
290 | tmp[2] = y_start; | ||
291 | tmp[3] = y_start >> 8; | ||
292 | tmp[4] = x_end; | ||
293 | tmp[5] = x_end >> 8; | ||
294 | tmp[6] = y_end; | ||
295 | tmp[7] = y_end >> 8; | ||
296 | |||
297 | x_out_end--; | ||
298 | y_out_end--; | ||
299 | tmp[8] = x_out_start; | ||
300 | tmp[9] = x_out_start >> 8; | ||
301 | tmp[10] = y_out_start; | ||
302 | tmp[11] = y_out_start >> 8; | ||
303 | tmp[12] = x_out_end; | ||
304 | tmp[13] = x_out_end >> 8; | ||
305 | tmp[14] = y_out_end; | ||
306 | tmp[15] = y_out_end >> 8; | ||
307 | |||
308 | tmp[16] = color_mode; | ||
309 | if (zoom_off && blizzard.version == BLIZZARD_VERSION_S1D13745) | ||
310 | tmp[17] = BLIZZARD_SRC_WRITE_LCD_BACKGROUND; | ||
311 | else if (flags & OMAPFB_FORMAT_FLAG_ENABLE_OVERLAY) | ||
312 | tmp[17] = BLIZZARD_SRC_WRITE_OVERLAY_ENABLE; | ||
313 | else | ||
314 | tmp[17] = blizzard.version == BLIZZARD_VERSION_S1D13744 ? | ||
315 | BLIZZARD_SRC_WRITE_LCD : | ||
316 | BLIZZARD_SRC_WRITE_LCD_DESTRUCTIVE; | ||
317 | |||
318 | blizzard.extif->set_bits_per_cycle(8); | ||
319 | cmd = BLIZZARD_INPUT_WIN_X_START_0; | ||
320 | blizzard.extif->write_command(&cmd, 1); | ||
321 | blizzard.extif->write_data(tmp, 18); | ||
322 | } | ||
323 | |||
324 | static void enable_tearsync(int y, int width, int height, int screen_height, | ||
325 | int out_height, int force_vsync) | ||
326 | { | ||
327 | u8 b; | ||
328 | |||
329 | b = blizzard_read_reg(BLIZZARD_NDISP_CTRL_STATUS); | ||
330 | b |= 1 << 3; | ||
331 | blizzard_write_reg(BLIZZARD_NDISP_CTRL_STATUS, b); | ||
332 | |||
333 | if (likely(blizzard.vsync_only || force_vsync)) { | ||
334 | blizzard.extif->enable_tearsync(1, 0); | ||
335 | return; | ||
336 | } | ||
337 | |||
338 | if (width * blizzard.pix_tx_time < blizzard.line_upd_time) { | ||
339 | blizzard.extif->enable_tearsync(1, 0); | ||
340 | return; | ||
341 | } | ||
342 | |||
343 | if ((width * blizzard.pix_tx_time / 1000) * height < | ||
344 | (y + out_height) * (blizzard.line_upd_time / 1000)) { | ||
345 | blizzard.extif->enable_tearsync(1, 0); | ||
346 | return; | ||
347 | } | ||
348 | |||
349 | blizzard.extif->enable_tearsync(1, y + 1); | ||
350 | } | ||
351 | |||
352 | static void disable_tearsync(void) | ||
353 | { | ||
354 | u8 b; | ||
355 | |||
356 | blizzard.extif->enable_tearsync(0, 0); | ||
357 | b = blizzard_read_reg(BLIZZARD_NDISP_CTRL_STATUS); | ||
358 | b &= ~(1 << 3); | ||
359 | blizzard_write_reg(BLIZZARD_NDISP_CTRL_STATUS, b); | ||
360 | b = blizzard_read_reg(BLIZZARD_NDISP_CTRL_STATUS); | ||
361 | } | ||
362 | |||
363 | static inline void set_extif_timings(const struct extif_timings *t); | ||
364 | |||
365 | static inline struct blizzard_request *alloc_req(void) | ||
366 | { | ||
367 | unsigned long flags; | ||
368 | struct blizzard_request *req; | ||
369 | int req_flags = 0; | ||
370 | |||
371 | if (!in_interrupt()) | ||
372 | down(&blizzard.req_sema); | ||
373 | else | ||
374 | req_flags = REQ_FROM_IRQ_POOL; | ||
375 | |||
376 | spin_lock_irqsave(&blizzard.req_lock, flags); | ||
377 | BUG_ON(list_empty(&blizzard.free_req_list)); | ||
378 | req = list_entry(blizzard.free_req_list.next, | ||
379 | struct blizzard_request, entry); | ||
380 | list_del(&req->entry); | ||
381 | spin_unlock_irqrestore(&blizzard.req_lock, flags); | ||
382 | |||
383 | INIT_LIST_HEAD(&req->entry); | ||
384 | req->flags = req_flags; | ||
385 | |||
386 | return req; | ||
387 | } | ||
388 | |||
389 | static inline void free_req(struct blizzard_request *req) | ||
390 | { | ||
391 | unsigned long flags; | ||
392 | |||
393 | spin_lock_irqsave(&blizzard.req_lock, flags); | ||
394 | |||
395 | list_del(&req->entry); | ||
396 | list_add(&req->entry, &blizzard.free_req_list); | ||
397 | if (!(req->flags & REQ_FROM_IRQ_POOL)) | ||
398 | up(&blizzard.req_sema); | ||
399 | |||
400 | spin_unlock_irqrestore(&blizzard.req_lock, flags); | ||
401 | } | ||
402 | |||
403 | static void process_pending_requests(void) | ||
404 | { | ||
405 | unsigned long flags; | ||
406 | |||
407 | spin_lock_irqsave(&blizzard.req_lock, flags); | ||
408 | |||
409 | while (!list_empty(&blizzard.pending_req_list)) { | ||
410 | struct blizzard_request *req; | ||
411 | void (*complete)(void *); | ||
412 | void *complete_data; | ||
413 | |||
414 | req = list_entry(blizzard.pending_req_list.next, | ||
415 | struct blizzard_request, entry); | ||
416 | spin_unlock_irqrestore(&blizzard.req_lock, flags); | ||
417 | |||
418 | if (req->handler(req) == REQ_PENDING) | ||
419 | return; | ||
420 | |||
421 | complete = req->complete; | ||
422 | complete_data = req->complete_data; | ||
423 | free_req(req); | ||
424 | |||
425 | if (complete) | ||
426 | complete(complete_data); | ||
427 | |||
428 | spin_lock_irqsave(&blizzard.req_lock, flags); | ||
429 | } | ||
430 | |||
431 | spin_unlock_irqrestore(&blizzard.req_lock, flags); | ||
432 | } | ||
433 | |||
434 | static void submit_req_list(struct list_head *head) | ||
435 | { | ||
436 | unsigned long flags; | ||
437 | int process = 1; | ||
438 | |||
439 | spin_lock_irqsave(&blizzard.req_lock, flags); | ||
440 | if (likely(!list_empty(&blizzard.pending_req_list))) | ||
441 | process = 0; | ||
442 | list_splice_init(head, blizzard.pending_req_list.prev); | ||
443 | spin_unlock_irqrestore(&blizzard.req_lock, flags); | ||
444 | |||
445 | if (process) | ||
446 | process_pending_requests(); | ||
447 | } | ||
448 | |||
449 | static void request_complete(void *data) | ||
450 | { | ||
451 | struct blizzard_request *req = (struct blizzard_request *)data; | ||
452 | void (*complete)(void *); | ||
453 | void *complete_data; | ||
454 | |||
455 | complete = req->complete; | ||
456 | complete_data = req->complete_data; | ||
457 | |||
458 | free_req(req); | ||
459 | |||
460 | if (complete) | ||
461 | complete(complete_data); | ||
462 | |||
463 | process_pending_requests(); | ||
464 | } | ||
465 | |||
466 | |||
467 | static int do_full_screen_update(struct blizzard_request *req) | ||
468 | { | ||
469 | int i; | ||
470 | int flags; | ||
471 | |||
472 | for (i = 0; i < 3; i++) { | ||
473 | struct plane_info *p = &blizzard.plane[i]; | ||
474 | if (!(blizzard.enabled_planes & (1 << i))) { | ||
475 | blizzard.int_ctrl->enable_plane(i, 0); | ||
476 | continue; | ||
477 | } | ||
478 | dev_dbg(blizzard.fbdev->dev, "pw %d ph %d\n", | ||
479 | p->width, p->height); | ||
480 | blizzard.int_ctrl->setup_plane(i, | ||
481 | OMAPFB_CHANNEL_OUT_LCD, p->offset, | ||
482 | p->scr_width, p->pos_x, p->pos_y, | ||
483 | p->width, p->height, | ||
484 | p->color_mode); | ||
485 | blizzard.int_ctrl->enable_plane(i, 1); | ||
486 | } | ||
487 | |||
488 | dev_dbg(blizzard.fbdev->dev, "sw %d sh %d\n", | ||
489 | blizzard.screen_width, blizzard.screen_height); | ||
490 | blizzard_wait_line_buffer(); | ||
491 | flags = req->par.update.flags; | ||
492 | if (flags & OMAPFB_FORMAT_FLAG_TEARSYNC) | ||
493 | enable_tearsync(0, blizzard.screen_width, | ||
494 | blizzard.screen_height, | ||
495 | blizzard.screen_height, | ||
496 | blizzard.screen_height, | ||
497 | flags & OMAPFB_FORMAT_FLAG_FORCE_VSYNC); | ||
498 | else | ||
499 | disable_tearsync(); | ||
500 | |||
501 | set_window_regs(0, 0, blizzard.screen_width, blizzard.screen_height, | ||
502 | 0, 0, blizzard.screen_width, blizzard.screen_height, | ||
503 | BLIZZARD_COLOR_RGB565, blizzard.zoom_on, flags); | ||
504 | blizzard.zoom_on = 0; | ||
505 | |||
506 | blizzard.extif->set_bits_per_cycle(16); | ||
507 | /* set_window_regs has left the register index at the right | ||
508 | * place, so no need to set it here. | ||
509 | */ | ||
510 | blizzard.extif->transfer_area(blizzard.screen_width, | ||
511 | blizzard.screen_height, | ||
512 | request_complete, req); | ||
513 | return REQ_PENDING; | ||
514 | } | ||
515 | |||
516 | /* Setup all planes with an overlapping area with the update window. */ | ||
517 | static int do_partial_update(struct blizzard_request *req, int plane, | ||
518 | int x, int y, int w, int h, | ||
519 | int x_out, int y_out, int w_out, int h_out, | ||
520 | int wnd_color_mode, int bpp) | ||
521 | { | ||
522 | int i; | ||
523 | int gx1, gy1, gx2, gy2; | ||
524 | int gx1_out, gy1_out, gx2_out, gy2_out; | ||
525 | int color_mode; | ||
526 | int flags; | ||
527 | int zoom_off; | ||
528 | |||
529 | /* Global coordinates, relative to pixel 0,0 of the LCD */ | ||
530 | gx1 = x + blizzard.plane[plane].pos_x; | ||
531 | gy1 = y + blizzard.plane[plane].pos_y; | ||
532 | gx2 = gx1 + w; | ||
533 | gy2 = gy1 + h; | ||
534 | |||
535 | flags = req->par.update.flags; | ||
536 | if (flags & OMAPFB_FORMAT_FLAG_DOUBLE) { | ||
537 | gx1_out = gx1; | ||
538 | gy1_out = gy1; | ||
539 | gx2_out = gx1 + w * 2; | ||
540 | gy2_out = gy1 + h * 2; | ||
541 | } else { | ||
542 | gx1_out = x_out + blizzard.plane[plane].pos_x; | ||
543 | gy1_out = y_out + blizzard.plane[plane].pos_y; | ||
544 | gx2_out = gx1_out + w_out; | ||
545 | gy2_out = gy1_out + h_out; | ||
546 | } | ||
547 | zoom_off = blizzard.zoom_on && gx1 == 0 && gy1 == 0 && | ||
548 | w == blizzard.screen_width && h == blizzard.screen_height; | ||
549 | blizzard.zoom_on = (!zoom_off && blizzard.zoom_on) || | ||
550 | (w < w_out || h < h_out); | ||
551 | |||
552 | for (i = 0; i < OMAPFB_PLANE_NUM; i++) { | ||
553 | struct plane_info *p = &blizzard.plane[i]; | ||
554 | int px1, py1; | ||
555 | int px2, py2; | ||
556 | int pw, ph; | ||
557 | int pposx, pposy; | ||
558 | unsigned long offset; | ||
559 | |||
560 | if (!(blizzard.enabled_planes & (1 << i)) || | ||
561 | (wnd_color_mode && i != plane)) { | ||
562 | blizzard.int_ctrl->enable_plane(i, 0); | ||
563 | continue; | ||
564 | } | ||
565 | /* Plane coordinates */ | ||
566 | if (i == plane) { | ||
567 | /* Plane in which we are doing the update. | ||
568 | * Local coordinates are the one in the update | ||
569 | * request. | ||
570 | */ | ||
571 | px1 = x; | ||
572 | py1 = y; | ||
573 | px2 = x + w; | ||
574 | py2 = y + h; | ||
575 | pposx = 0; | ||
576 | pposy = 0; | ||
577 | } else { | ||
578 | /* Check if this plane has an overlapping part */ | ||
579 | px1 = gx1 - p->pos_x; | ||
580 | py1 = gy1 - p->pos_y; | ||
581 | px2 = gx2 - p->pos_x; | ||
582 | py2 = gy2 - p->pos_y; | ||
583 | if (px1 >= p->width || py1 >= p->height || | ||
584 | px2 <= 0 || py2 <= 0) { | ||
585 | blizzard.int_ctrl->enable_plane(i, 0); | ||
586 | continue; | ||
587 | } | ||
588 | /* Calculate the coordinates for the overlapping | ||
589 | * part in the plane's local coordinates. | ||
590 | */ | ||
591 | pposx = -px1; | ||
592 | pposy = -py1; | ||
593 | if (px1 < 0) | ||
594 | px1 = 0; | ||
595 | if (py1 < 0) | ||
596 | py1 = 0; | ||
597 | if (px2 > p->width) | ||
598 | px2 = p->width; | ||
599 | if (py2 > p->height) | ||
600 | py2 = p->height; | ||
601 | if (pposx < 0) | ||
602 | pposx = 0; | ||
603 | if (pposy < 0) | ||
604 | pposy = 0; | ||
605 | } | ||
606 | pw = px2 - px1; | ||
607 | ph = py2 - py1; | ||
608 | offset = p->offset + (p->scr_width * py1 + px1) * p->bpp / 8; | ||
609 | if (wnd_color_mode) | ||
610 | /* Window embedded in the plane with a differing | ||
611 | * color mode / bpp. Calculate the number of DMA | ||
612 | * transfer elements in terms of the plane's bpp. | ||
613 | */ | ||
614 | pw = (pw + 1) * bpp / p->bpp; | ||
615 | #ifdef VERBOSE | ||
616 | dev_dbg(blizzard.fbdev->dev, | ||
617 | "plane %d offset %#08lx pposx %d pposy %d " | ||
618 | "px1 %d py1 %d pw %d ph %d\n", | ||
619 | i, offset, pposx, pposy, px1, py1, pw, ph); | ||
620 | #endif | ||
621 | blizzard.int_ctrl->setup_plane(i, | ||
622 | OMAPFB_CHANNEL_OUT_LCD, offset, | ||
623 | p->scr_width, | ||
624 | pposx, pposy, pw, ph, | ||
625 | p->color_mode); | ||
626 | |||
627 | blizzard.int_ctrl->enable_plane(i, 1); | ||
628 | } | ||
629 | |||
630 | switch (wnd_color_mode) { | ||
631 | case OMAPFB_COLOR_YUV420: | ||
632 | color_mode = BLIZZARD_COLOR_YUV420; | ||
633 | /* Currently only the 16 bits/pixel cycle format is | ||
634 | * supported on the external interface. Adjust the number | ||
635 | * of transfer elements per line for 12bpp format. | ||
636 | */ | ||
637 | w = (w + 1) * 3 / 4; | ||
638 | break; | ||
639 | default: | ||
640 | color_mode = BLIZZARD_COLOR_RGB565; | ||
641 | break; | ||
642 | } | ||
643 | |||
644 | blizzard_wait_line_buffer(); | ||
645 | if (blizzard.last_color_mode == BLIZZARD_COLOR_YUV420) | ||
646 | blizzard_wait_yyc(); | ||
647 | blizzard.last_color_mode = color_mode; | ||
648 | if (flags & OMAPFB_FORMAT_FLAG_TEARSYNC) | ||
649 | enable_tearsync(gy1, w, h, | ||
650 | blizzard.screen_height, | ||
651 | h_out, | ||
652 | flags & OMAPFB_FORMAT_FLAG_FORCE_VSYNC); | ||
653 | else | ||
654 | disable_tearsync(); | ||
655 | |||
656 | set_window_regs(gx1, gy1, gx2, gy2, gx1_out, gy1_out, gx2_out, gy2_out, | ||
657 | color_mode, zoom_off, flags); | ||
658 | |||
659 | blizzard.extif->set_bits_per_cycle(16); | ||
660 | /* set_window_regs has left the register index at the right | ||
661 | * place, so no need to set it here. | ||
662 | */ | ||
663 | blizzard.extif->transfer_area(w, h, request_complete, req); | ||
664 | |||
665 | return REQ_PENDING; | ||
666 | } | ||
667 | |||
668 | static int send_frame_handler(struct blizzard_request *req) | ||
669 | { | ||
670 | struct update_param *par = &req->par.update; | ||
671 | int plane = par->plane; | ||
672 | |||
673 | #ifdef VERBOSE | ||
674 | dev_dbg(blizzard.fbdev->dev, | ||
675 | "send_frame: x %d y %d w %d h %d " | ||
676 | "x_out %d y_out %d w_out %d h_out %d " | ||
677 | "color_mode %04x flags %04x planes %01x\n", | ||
678 | par->x, par->y, par->width, par->height, | ||
679 | par->out_x, par->out_y, par->out_width, par->out_height, | ||
680 | par->color_mode, par->flags, blizzard.enabled_planes); | ||
681 | #endif | ||
682 | if (par->flags & OMAPFB_FORMAT_FLAG_DISABLE_OVERLAY) | ||
683 | disable_overlay(); | ||
684 | |||
685 | if ((blizzard.enabled_planes & blizzard.vid_nonstd_color) || | ||
686 | (blizzard.enabled_planes & blizzard.vid_scaled)) | ||
687 | return do_full_screen_update(req); | ||
688 | |||
689 | return do_partial_update(req, plane, par->x, par->y, | ||
690 | par->width, par->height, | ||
691 | par->out_x, par->out_y, | ||
692 | par->out_width, par->out_height, | ||
693 | par->color_mode, par->bpp); | ||
694 | } | ||
695 | |||
696 | static void send_frame_complete(void *data) | ||
697 | { | ||
698 | } | ||
699 | |||
700 | #define ADD_PREQ(_x, _y, _w, _h, _x_out, _y_out, _w_out, _h_out) do { \ | ||
701 | req = alloc_req(); \ | ||
702 | req->handler = send_frame_handler; \ | ||
703 | req->complete = send_frame_complete; \ | ||
704 | req->par.update.plane = plane_idx; \ | ||
705 | req->par.update.x = _x; \ | ||
706 | req->par.update.y = _y; \ | ||
707 | req->par.update.width = _w; \ | ||
708 | req->par.update.height = _h; \ | ||
709 | req->par.update.out_x = _x_out; \ | ||
710 | req->par.update.out_y = _y_out; \ | ||
711 | req->par.update.out_width = _w_out; \ | ||
712 | req->par.update.out_height = _h_out; \ | ||
713 | req->par.update.bpp = bpp; \ | ||
714 | req->par.update.color_mode = color_mode;\ | ||
715 | req->par.update.flags = flags; \ | ||
716 | list_add_tail(&req->entry, req_head); \ | ||
717 | } while(0) | ||
718 | |||
719 | static void create_req_list(int plane_idx, | ||
720 | struct omapfb_update_window *win, | ||
721 | struct list_head *req_head) | ||
722 | { | ||
723 | struct blizzard_request *req; | ||
724 | int x = win->x; | ||
725 | int y = win->y; | ||
726 | int width = win->width; | ||
727 | int height = win->height; | ||
728 | int x_out = win->out_x; | ||
729 | int y_out = win->out_y; | ||
730 | int width_out = win->out_width; | ||
731 | int height_out = win->out_height; | ||
732 | int color_mode; | ||
733 | int bpp; | ||
734 | int flags; | ||
735 | unsigned int ystart = y; | ||
736 | unsigned int yspan = height; | ||
737 | unsigned int ystart_out = y_out; | ||
738 | unsigned int yspan_out = height_out; | ||
739 | |||
740 | flags = win->format & ~OMAPFB_FORMAT_MASK; | ||
741 | color_mode = win->format & OMAPFB_FORMAT_MASK; | ||
742 | switch (color_mode) { | ||
743 | case OMAPFB_COLOR_YUV420: | ||
744 | /* Embedded window with different color mode */ | ||
745 | bpp = 12; | ||
746 | /* X, Y, height must be aligned at 2, width at 4 pixels */ | ||
747 | x &= ~1; | ||
748 | y &= ~1; | ||
749 | height = yspan = height & ~1; | ||
750 | width = width & ~3; | ||
751 | break; | ||
752 | default: | ||
753 | /* Same as the plane color mode */ | ||
754 | bpp = blizzard.plane[plane_idx].bpp; | ||
755 | break; | ||
756 | } | ||
757 | if (width * height * bpp / 8 > blizzard.max_transmit_size) { | ||
758 | yspan = blizzard.max_transmit_size / (width * bpp / 8); | ||
759 | yspan_out = yspan * height_out / height; | ||
760 | ADD_PREQ(x, ystart, width, yspan, x_out, ystart_out, | ||
761 | width_out, yspan_out); | ||
762 | ystart += yspan; | ||
763 | ystart_out += yspan_out; | ||
764 | yspan = height - yspan; | ||
765 | yspan_out = height_out - yspan_out; | ||
766 | flags &= ~OMAPFB_FORMAT_FLAG_TEARSYNC; | ||
767 | } | ||
768 | |||
769 | ADD_PREQ(x, ystart, width, yspan, x_out, ystart_out, | ||
770 | width_out, yspan_out); | ||
771 | } | ||
772 | |||
773 | static void auto_update_complete(void *data) | ||
774 | { | ||
775 | if (!blizzard.stop_auto_update) | ||
776 | mod_timer(&blizzard.auto_update_timer, | ||
777 | jiffies + BLIZZARD_AUTO_UPDATE_TIME); | ||
778 | } | ||
779 | |||
780 | static void blizzard_update_window_auto(unsigned long arg) | ||
781 | { | ||
782 | LIST_HEAD(req_list); | ||
783 | struct blizzard_request *last; | ||
784 | struct omapfb_plane_struct *plane; | ||
785 | |||
786 | plane = blizzard.fbdev->fb_info[0]->par; | ||
787 | create_req_list(plane->idx, | ||
788 | &blizzard.auto_update_window, &req_list); | ||
789 | last = list_entry(req_list.prev, struct blizzard_request, entry); | ||
790 | |||
791 | last->complete = auto_update_complete; | ||
792 | last->complete_data = NULL; | ||
793 | |||
794 | submit_req_list(&req_list); | ||
795 | } | ||
796 | |||
797 | int blizzard_update_window_async(struct fb_info *fbi, | ||
798 | struct omapfb_update_window *win, | ||
799 | void (*complete_callback)(void *arg), | ||
800 | void *complete_callback_data) | ||
801 | { | ||
802 | LIST_HEAD(req_list); | ||
803 | struct blizzard_request *last; | ||
804 | struct omapfb_plane_struct *plane = fbi->par; | ||
805 | |||
806 | if (unlikely(blizzard.update_mode != OMAPFB_MANUAL_UPDATE)) | ||
807 | return -EINVAL; | ||
808 | if (unlikely(!blizzard.te_connected && | ||
809 | (win->format & OMAPFB_FORMAT_FLAG_TEARSYNC))) | ||
810 | return -EINVAL; | ||
811 | |||
812 | create_req_list(plane->idx, win, &req_list); | ||
813 | last = list_entry(req_list.prev, struct blizzard_request, entry); | ||
814 | |||
815 | last->complete = complete_callback; | ||
816 | last->complete_data = (void *)complete_callback_data; | ||
817 | |||
818 | submit_req_list(&req_list); | ||
819 | |||
820 | return 0; | ||
821 | } | ||
822 | EXPORT_SYMBOL(blizzard_update_window_async); | ||
823 | |||
824 | static int update_full_screen(void) | ||
825 | { | ||
826 | return blizzard_update_window_async(blizzard.fbdev->fb_info[0], | ||
827 | &blizzard.auto_update_window, NULL, NULL); | ||
828 | |||
829 | } | ||
830 | |||
831 | static int blizzard_setup_plane(int plane, int channel_out, | ||
832 | unsigned long offset, int screen_width, | ||
833 | int pos_x, int pos_y, int width, int height, | ||
834 | int color_mode) | ||
835 | { | ||
836 | struct plane_info *p; | ||
837 | |||
838 | #ifdef VERBOSE | ||
839 | dev_dbg(blizzard.fbdev->dev, | ||
840 | "plane %d ch_out %d offset %#08lx scr_width %d " | ||
841 | "pos_x %d pos_y %d width %d height %d color_mode %d\n", | ||
842 | plane, channel_out, offset, screen_width, | ||
843 | pos_x, pos_y, width, height, color_mode); | ||
844 | #endif | ||
845 | if ((unsigned)plane > OMAPFB_PLANE_NUM) | ||
846 | return -EINVAL; | ||
847 | p = &blizzard.plane[plane]; | ||
848 | |||
849 | switch (color_mode) { | ||
850 | case OMAPFB_COLOR_YUV422: | ||
851 | case OMAPFB_COLOR_YUY422: | ||
852 | p->bpp = 16; | ||
853 | blizzard.vid_nonstd_color &= ~(1 << plane); | ||
854 | break; | ||
855 | case OMAPFB_COLOR_YUV420: | ||
856 | p->bpp = 12; | ||
857 | blizzard.vid_nonstd_color |= 1 << plane; | ||
858 | break; | ||
859 | case OMAPFB_COLOR_RGB565: | ||
860 | p->bpp = 16; | ||
861 | blizzard.vid_nonstd_color &= ~(1 << plane); | ||
862 | break; | ||
863 | default: | ||
864 | return -EINVAL; | ||
865 | } | ||
866 | |||
867 | p->offset = offset; | ||
868 | p->pos_x = pos_x; | ||
869 | p->pos_y = pos_y; | ||
870 | p->width = width; | ||
871 | p->height = height; | ||
872 | p->scr_width = screen_width; | ||
873 | if (!p->out_width) | ||
874 | p->out_width = width; | ||
875 | if (!p->out_height) | ||
876 | p->out_height = height; | ||
877 | |||
878 | p->color_mode = color_mode; | ||
879 | |||
880 | return 0; | ||
881 | } | ||
882 | |||
883 | static int blizzard_set_scale(int plane, int orig_w, int orig_h, | ||
884 | int out_w, int out_h) | ||
885 | { | ||
886 | struct plane_info *p = &blizzard.plane[plane]; | ||
887 | int r; | ||
888 | |||
889 | dev_dbg(blizzard.fbdev->dev, | ||
890 | "plane %d orig_w %d orig_h %d out_w %d out_h %d\n", | ||
891 | plane, orig_w, orig_h, out_w, out_h); | ||
892 | if ((unsigned)plane > OMAPFB_PLANE_NUM) | ||
893 | return -ENODEV; | ||
894 | |||
895 | r = blizzard.int_ctrl->set_scale(plane, orig_w, orig_h, out_w, out_h); | ||
896 | if (r < 0) | ||
897 | return r; | ||
898 | |||
899 | p->width = orig_w; | ||
900 | p->height = orig_h; | ||
901 | p->out_width = out_w; | ||
902 | p->out_height = out_h; | ||
903 | if (orig_w == out_w && orig_h == out_h) | ||
904 | blizzard.vid_scaled &= ~(1 << plane); | ||
905 | else | ||
906 | blizzard.vid_scaled |= 1 << plane; | ||
907 | |||
908 | return 0; | ||
909 | } | ||
910 | |||
911 | static int blizzard_enable_plane(int plane, int enable) | ||
912 | { | ||
913 | if (enable) | ||
914 | blizzard.enabled_planes |= 1 << plane; | ||
915 | else | ||
916 | blizzard.enabled_planes &= ~(1 << plane); | ||
917 | |||
918 | return 0; | ||
919 | } | ||
920 | |||
921 | static int sync_handler(struct blizzard_request *req) | ||
922 | { | ||
923 | complete(req->par.sync); | ||
924 | return REQ_COMPLETE; | ||
925 | } | ||
926 | |||
927 | static void blizzard_sync(void) | ||
928 | { | ||
929 | LIST_HEAD(req_list); | ||
930 | struct blizzard_request *req; | ||
931 | struct completion comp; | ||
932 | |||
933 | req = alloc_req(); | ||
934 | |||
935 | req->handler = sync_handler; | ||
936 | req->complete = NULL; | ||
937 | init_completion(&comp); | ||
938 | req->par.sync = ∁ | ||
939 | |||
940 | list_add(&req->entry, &req_list); | ||
941 | submit_req_list(&req_list); | ||
942 | |||
943 | wait_for_completion(&comp); | ||
944 | } | ||
945 | |||
946 | |||
947 | static void blizzard_bind_client(struct omapfb_notifier_block *nb) | ||
948 | { | ||
949 | if (blizzard.update_mode == OMAPFB_MANUAL_UPDATE) { | ||
950 | omapfb_notify_clients(blizzard.fbdev, OMAPFB_EVENT_READY); | ||
951 | } | ||
952 | } | ||
953 | |||
954 | static int blizzard_set_update_mode(enum omapfb_update_mode mode) | ||
955 | { | ||
956 | if (unlikely(mode != OMAPFB_MANUAL_UPDATE && | ||
957 | mode != OMAPFB_AUTO_UPDATE && | ||
958 | mode != OMAPFB_UPDATE_DISABLED)) | ||
959 | return -EINVAL; | ||
960 | |||
961 | if (mode == blizzard.update_mode) | ||
962 | return 0; | ||
963 | |||
964 | dev_info(blizzard.fbdev->dev, "s1d1374x: setting update mode to %s\n", | ||
965 | mode == OMAPFB_UPDATE_DISABLED ? "disabled" : | ||
966 | (mode == OMAPFB_AUTO_UPDATE ? "auto" : "manual")); | ||
967 | |||
968 | switch (blizzard.update_mode) { | ||
969 | case OMAPFB_MANUAL_UPDATE: | ||
970 | omapfb_notify_clients(blizzard.fbdev, OMAPFB_EVENT_DISABLED); | ||
971 | break; | ||
972 | case OMAPFB_AUTO_UPDATE: | ||
973 | blizzard.stop_auto_update = 1; | ||
974 | del_timer_sync(&blizzard.auto_update_timer); | ||
975 | break; | ||
976 | case OMAPFB_UPDATE_DISABLED: | ||
977 | break; | ||
978 | } | ||
979 | |||
980 | blizzard.update_mode = mode; | ||
981 | blizzard_sync(); | ||
982 | blizzard.stop_auto_update = 0; | ||
983 | |||
984 | switch (mode) { | ||
985 | case OMAPFB_MANUAL_UPDATE: | ||
986 | omapfb_notify_clients(blizzard.fbdev, OMAPFB_EVENT_READY); | ||
987 | break; | ||
988 | case OMAPFB_AUTO_UPDATE: | ||
989 | blizzard_update_window_auto(0); | ||
990 | break; | ||
991 | case OMAPFB_UPDATE_DISABLED: | ||
992 | break; | ||
993 | } | ||
994 | |||
995 | return 0; | ||
996 | } | ||
997 | |||
998 | static enum omapfb_update_mode blizzard_get_update_mode(void) | ||
999 | { | ||
1000 | return blizzard.update_mode; | ||
1001 | } | ||
1002 | |||
1003 | static inline void set_extif_timings(const struct extif_timings *t) | ||
1004 | { | ||
1005 | blizzard.extif->set_timings(t); | ||
1006 | } | ||
1007 | |||
1008 | static inline unsigned long round_to_extif_ticks(unsigned long ps, int div) | ||
1009 | { | ||
1010 | int bus_tick = blizzard.extif_clk_period * div; | ||
1011 | return (ps + bus_tick - 1) / bus_tick * bus_tick; | ||
1012 | } | ||
1013 | |||
1014 | static int calc_reg_timing(unsigned long sysclk, int div) | ||
1015 | { | ||
1016 | struct extif_timings *t; | ||
1017 | unsigned long systim; | ||
1018 | |||
1019 | /* CSOnTime 0, WEOnTime 2 ns, REOnTime 2 ns, | ||
1020 | * AccessTime 2 ns + 12.2 ns (regs), | ||
1021 | * WEOffTime = WEOnTime + 1 ns, | ||
1022 | * REOffTime = REOnTime + 12 ns (regs), | ||
1023 | * CSOffTime = REOffTime + 1 ns | ||
1024 | * ReadCycle = 2ns + 2*SYSCLK (regs), | ||
1025 | * WriteCycle = 2*SYSCLK + 2 ns, | ||
1026 | * CSPulseWidth = 10 ns */ | ||
1027 | |||
1028 | systim = 1000000000 / (sysclk / 1000); | ||
1029 | dev_dbg(blizzard.fbdev->dev, | ||
1030 | "Blizzard systim %lu ps extif_clk_period %u div %d\n", | ||
1031 | systim, blizzard.extif_clk_period, div); | ||
1032 | |||
1033 | t = &blizzard.reg_timings; | ||
1034 | memset(t, 0, sizeof(*t)); | ||
1035 | |||
1036 | t->clk_div = div; | ||
1037 | |||
1038 | t->cs_on_time = 0; | ||
1039 | t->we_on_time = round_to_extif_ticks(t->cs_on_time + 2000, div); | ||
1040 | t->re_on_time = round_to_extif_ticks(t->cs_on_time + 2000, div); | ||
1041 | t->access_time = round_to_extif_ticks(t->re_on_time + 12200, div); | ||
1042 | t->we_off_time = round_to_extif_ticks(t->we_on_time + 1000, div); | ||
1043 | t->re_off_time = round_to_extif_ticks(t->re_on_time + 13000, div); | ||
1044 | t->cs_off_time = round_to_extif_ticks(t->re_off_time + 1000, div); | ||
1045 | t->we_cycle_time = round_to_extif_ticks(2 * systim + 2000, div); | ||
1046 | if (t->we_cycle_time < t->we_off_time) | ||
1047 | t->we_cycle_time = t->we_off_time; | ||
1048 | t->re_cycle_time = round_to_extif_ticks(2 * systim + 2000, div); | ||
1049 | if (t->re_cycle_time < t->re_off_time) | ||
1050 | t->re_cycle_time = t->re_off_time; | ||
1051 | t->cs_pulse_width = 0; | ||
1052 | |||
1053 | dev_dbg(blizzard.fbdev->dev, "[reg]cson %d csoff %d reon %d reoff %d\n", | ||
1054 | t->cs_on_time, t->cs_off_time, t->re_on_time, t->re_off_time); | ||
1055 | dev_dbg(blizzard.fbdev->dev, "[reg]weon %d weoff %d recyc %d wecyc %d\n", | ||
1056 | t->we_on_time, t->we_off_time, t->re_cycle_time, | ||
1057 | t->we_cycle_time); | ||
1058 | dev_dbg(blizzard.fbdev->dev, "[reg]rdaccess %d cspulse %d\n", | ||
1059 | t->access_time, t->cs_pulse_width); | ||
1060 | |||
1061 | return blizzard.extif->convert_timings(t); | ||
1062 | } | ||
1063 | |||
1064 | static int calc_lut_timing(unsigned long sysclk, int div) | ||
1065 | { | ||
1066 | struct extif_timings *t; | ||
1067 | unsigned long systim; | ||
1068 | |||
1069 | /* CSOnTime 0, WEOnTime 2 ns, REOnTime 2 ns, | ||
1070 | * AccessTime 2 ns + 4 * SYSCLK + 26 (lut), | ||
1071 | * WEOffTime = WEOnTime + 1 ns, | ||
1072 | * REOffTime = REOnTime + 4*SYSCLK + 26 ns (lut), | ||
1073 | * CSOffTime = REOffTime + 1 ns | ||
1074 | * ReadCycle = 2ns + 4*SYSCLK + 26 ns (lut), | ||
1075 | * WriteCycle = 2*SYSCLK + 2 ns, | ||
1076 | * CSPulseWidth = 10 ns */ | ||
1077 | |||
1078 | systim = 1000000000 / (sysclk / 1000); | ||
1079 | dev_dbg(blizzard.fbdev->dev, | ||
1080 | "Blizzard systim %lu ps extif_clk_period %u div %d\n", | ||
1081 | systim, blizzard.extif_clk_period, div); | ||
1082 | |||
1083 | t = &blizzard.lut_timings; | ||
1084 | memset(t, 0, sizeof(*t)); | ||
1085 | |||
1086 | t->clk_div = div; | ||
1087 | |||
1088 | t->cs_on_time = 0; | ||
1089 | t->we_on_time = round_to_extif_ticks(t->cs_on_time + 2000, div); | ||
1090 | t->re_on_time = round_to_extif_ticks(t->cs_on_time + 2000, div); | ||
1091 | t->access_time = round_to_extif_ticks(t->re_on_time + 4 * systim + | ||
1092 | 26000, div); | ||
1093 | t->we_off_time = round_to_extif_ticks(t->we_on_time + 1000, div); | ||
1094 | t->re_off_time = round_to_extif_ticks(t->re_on_time + 4 * systim + | ||
1095 | 26000, div); | ||
1096 | t->cs_off_time = round_to_extif_ticks(t->re_off_time + 1000, div); | ||
1097 | t->we_cycle_time = round_to_extif_ticks(2 * systim + 2000, div); | ||
1098 | if (t->we_cycle_time < t->we_off_time) | ||
1099 | t->we_cycle_time = t->we_off_time; | ||
1100 | t->re_cycle_time = round_to_extif_ticks(2000 + 4 * systim + 26000, div); | ||
1101 | if (t->re_cycle_time < t->re_off_time) | ||
1102 | t->re_cycle_time = t->re_off_time; | ||
1103 | t->cs_pulse_width = 0; | ||
1104 | |||
1105 | dev_dbg(blizzard.fbdev->dev, | ||
1106 | "[lut]cson %d csoff %d reon %d reoff %d\n", | ||
1107 | t->cs_on_time, t->cs_off_time, t->re_on_time, t->re_off_time); | ||
1108 | dev_dbg(blizzard.fbdev->dev, | ||
1109 | "[lut]weon %d weoff %d recyc %d wecyc %d\n", | ||
1110 | t->we_on_time, t->we_off_time, t->re_cycle_time, | ||
1111 | t->we_cycle_time); | ||
1112 | dev_dbg(blizzard.fbdev->dev, "[lut]rdaccess %d cspulse %d\n", | ||
1113 | t->access_time, t->cs_pulse_width); | ||
1114 | |||
1115 | return blizzard.extif->convert_timings(t); | ||
1116 | } | ||
1117 | |||
1118 | static int calc_extif_timings(unsigned long sysclk, int *extif_mem_div) | ||
1119 | { | ||
1120 | int max_clk_div; | ||
1121 | int div; | ||
1122 | |||
1123 | blizzard.extif->get_clk_info(&blizzard.extif_clk_period, &max_clk_div); | ||
1124 | for (div = 1; div <= max_clk_div; div++) { | ||
1125 | if (calc_reg_timing(sysclk, div) == 0) | ||
1126 | break; | ||
1127 | } | ||
1128 | if (div > max_clk_div) { | ||
1129 | dev_dbg(blizzard.fbdev->dev, "reg timing failed\n"); | ||
1130 | goto err; | ||
1131 | } | ||
1132 | *extif_mem_div = div; | ||
1133 | |||
1134 | for (div = 1; div <= max_clk_div; div++) { | ||
1135 | if (calc_lut_timing(sysclk, div) == 0) | ||
1136 | break; | ||
1137 | } | ||
1138 | |||
1139 | if (div > max_clk_div) | ||
1140 | goto err; | ||
1141 | |||
1142 | blizzard.extif_clk_div = div; | ||
1143 | |||
1144 | return 0; | ||
1145 | err: | ||
1146 | dev_err(blizzard.fbdev->dev, "can't setup timings\n"); | ||
1147 | return -1; | ||
1148 | } | ||
1149 | |||
1150 | static void calc_blizzard_clk_rates(unsigned long ext_clk, | ||
1151 | unsigned long *sys_clk, unsigned long *pix_clk) | ||
1152 | { | ||
1153 | int pix_clk_src; | ||
1154 | int sys_div = 0, sys_mul = 0; | ||
1155 | int pix_div; | ||
1156 | |||
1157 | pix_clk_src = blizzard_read_reg(BLIZZARD_CLK_SRC); | ||
1158 | pix_div = ((pix_clk_src >> 3) & 0x1f) + 1; | ||
1159 | if ((pix_clk_src & (0x3 << 1)) == 0) { | ||
1160 | /* Source is the PLL */ | ||
1161 | sys_div = (blizzard_read_reg(BLIZZARD_PLL_DIV) & 0x3f) + 1; | ||
1162 | sys_mul = blizzard_read_reg(BLIZZARD_PLL_CLOCK_SYNTH_0); | ||
1163 | sys_mul |= ((blizzard_read_reg(BLIZZARD_PLL_CLOCK_SYNTH_1) | ||
1164 | & 0x0f) << 11); | ||
1165 | *sys_clk = ext_clk * sys_mul / sys_div; | ||
1166 | } else /* else source is ext clk, or oscillator */ | ||
1167 | *sys_clk = ext_clk; | ||
1168 | |||
1169 | *pix_clk = *sys_clk / pix_div; /* HZ */ | ||
1170 | dev_dbg(blizzard.fbdev->dev, | ||
1171 | "ext_clk %ld pix_src %d pix_div %d sys_div %d sys_mul %d\n", | ||
1172 | ext_clk, pix_clk_src & (0x3 << 1), pix_div, sys_div, sys_mul); | ||
1173 | dev_dbg(blizzard.fbdev->dev, "sys_clk %ld pix_clk %ld\n", | ||
1174 | *sys_clk, *pix_clk); | ||
1175 | } | ||
1176 | |||
1177 | static int setup_tearsync(unsigned long pix_clk, int extif_div) | ||
1178 | { | ||
1179 | int hdisp, vdisp; | ||
1180 | int hndp, vndp; | ||
1181 | int hsw, vsw; | ||
1182 | int hs, vs; | ||
1183 | int hs_pol_inv, vs_pol_inv; | ||
1184 | int use_hsvs, use_ndp; | ||
1185 | u8 b; | ||
1186 | |||
1187 | hsw = blizzard_read_reg(BLIZZARD_HSW); | ||
1188 | vsw = blizzard_read_reg(BLIZZARD_VSW); | ||
1189 | hs_pol_inv = !(hsw & 0x80); | ||
1190 | vs_pol_inv = !(vsw & 0x80); | ||
1191 | hsw = hsw & 0x7f; | ||
1192 | vsw = vsw & 0x3f; | ||
1193 | |||
1194 | hdisp = blizzard_read_reg(BLIZZARD_HDISP) * 8; | ||
1195 | vdisp = blizzard_read_reg(BLIZZARD_VDISP0) + | ||
1196 | ((blizzard_read_reg(BLIZZARD_VDISP1) & 0x3) << 8); | ||
1197 | |||
1198 | hndp = blizzard_read_reg(BLIZZARD_HNDP) & 0x3f; | ||
1199 | vndp = blizzard_read_reg(BLIZZARD_VNDP); | ||
1200 | |||
1201 | /* time to transfer one pixel (16bpp) in ps */ | ||
1202 | blizzard.pix_tx_time = blizzard.reg_timings.we_cycle_time; | ||
1203 | if (blizzard.extif->get_max_tx_rate != NULL) { | ||
1204 | /* The external interface might have a rate limitation, | ||
1205 | * if so, we have to maximize our transfer rate. | ||
1206 | */ | ||
1207 | unsigned long min_tx_time; | ||
1208 | unsigned long max_tx_rate = blizzard.extif->get_max_tx_rate(); | ||
1209 | |||
1210 | dev_dbg(blizzard.fbdev->dev, "max_tx_rate %ld HZ\n", | ||
1211 | max_tx_rate); | ||
1212 | min_tx_time = 1000000000 / (max_tx_rate / 1000); /* ps */ | ||
1213 | if (blizzard.pix_tx_time < min_tx_time) | ||
1214 | blizzard.pix_tx_time = min_tx_time; | ||
1215 | } | ||
1216 | |||
1217 | /* time to update one line in ps */ | ||
1218 | blizzard.line_upd_time = (hdisp + hndp) * 1000000 / (pix_clk / 1000); | ||
1219 | blizzard.line_upd_time *= 1000; | ||
1220 | if (hdisp * blizzard.pix_tx_time > blizzard.line_upd_time) | ||
1221 | /* transfer speed too low, we might have to use both | ||
1222 | * HS and VS */ | ||
1223 | use_hsvs = 1; | ||
1224 | else | ||
1225 | /* decent transfer speed, we'll always use only VS */ | ||
1226 | use_hsvs = 0; | ||
1227 | |||
1228 | if (use_hsvs && (hs_pol_inv || vs_pol_inv)) { | ||
1229 | /* HS or'ed with VS doesn't work, use the active high | ||
1230 | * TE signal based on HNDP / VNDP */ | ||
1231 | use_ndp = 1; | ||
1232 | hs_pol_inv = 0; | ||
1233 | vs_pol_inv = 0; | ||
1234 | hs = hndp; | ||
1235 | vs = vndp; | ||
1236 | } else { | ||
1237 | /* Use HS or'ed with VS as a TE signal if both are needed | ||
1238 | * or VNDP if only vsync is needed. */ | ||
1239 | use_ndp = 0; | ||
1240 | hs = hsw; | ||
1241 | vs = vsw; | ||
1242 | if (!use_hsvs) { | ||
1243 | hs_pol_inv = 0; | ||
1244 | vs_pol_inv = 0; | ||
1245 | } | ||
1246 | } | ||
1247 | |||
1248 | hs = hs * 1000000 / (pix_clk / 1000); /* ps */ | ||
1249 | hs *= 1000; | ||
1250 | |||
1251 | vs = vs * (hdisp + hndp) * 1000000 / (pix_clk / 1000); /* ps */ | ||
1252 | vs *= 1000; | ||
1253 | |||
1254 | if (vs <= hs) | ||
1255 | return -EDOM; | ||
1256 | /* set VS to 120% of HS to minimize VS detection time */ | ||
1257 | vs = hs * 12 / 10; | ||
1258 | /* minimize HS too */ | ||
1259 | if (hs > 10000) | ||
1260 | hs = 10000; | ||
1261 | |||
1262 | b = blizzard_read_reg(BLIZZARD_NDISP_CTRL_STATUS); | ||
1263 | b &= ~0x3; | ||
1264 | b |= use_hsvs ? 1 : 0; | ||
1265 | b |= (use_ndp && use_hsvs) ? 0 : 2; | ||
1266 | blizzard_write_reg(BLIZZARD_NDISP_CTRL_STATUS, b); | ||
1267 | |||
1268 | blizzard.vsync_only = !use_hsvs; | ||
1269 | |||
1270 | dev_dbg(blizzard.fbdev->dev, | ||
1271 | "pix_clk %ld HZ pix_tx_time %ld ps line_upd_time %ld ps\n", | ||
1272 | pix_clk, blizzard.pix_tx_time, blizzard.line_upd_time); | ||
1273 | dev_dbg(blizzard.fbdev->dev, | ||
1274 | "hs %d ps vs %d ps mode %d vsync_only %d\n", | ||
1275 | hs, vs, b & 0x3, !use_hsvs); | ||
1276 | |||
1277 | return blizzard.extif->setup_tearsync(1, hs, vs, | ||
1278 | hs_pol_inv, vs_pol_inv, | ||
1279 | extif_div); | ||
1280 | } | ||
1281 | |||
1282 | static void blizzard_get_caps(int plane, struct omapfb_caps *caps) | ||
1283 | { | ||
1284 | blizzard.int_ctrl->get_caps(plane, caps); | ||
1285 | caps->ctrl |= OMAPFB_CAPS_MANUAL_UPDATE | | ||
1286 | OMAPFB_CAPS_WINDOW_PIXEL_DOUBLE | | ||
1287 | OMAPFB_CAPS_WINDOW_SCALE | | ||
1288 | OMAPFB_CAPS_WINDOW_OVERLAY; | ||
1289 | if (blizzard.te_connected) | ||
1290 | caps->ctrl |= OMAPFB_CAPS_TEARSYNC; | ||
1291 | caps->wnd_color |= (1 << OMAPFB_COLOR_RGB565) | | ||
1292 | (1 << OMAPFB_COLOR_YUV420); | ||
1293 | } | ||
1294 | |||
1295 | static void _save_regs(struct blizzard_reg_list *list, int cnt) | ||
1296 | { | ||
1297 | int i; | ||
1298 | |||
1299 | for (i = 0; i < cnt; i++, list++) { | ||
1300 | int reg; | ||
1301 | for (reg = list->start; reg <= list->end; reg += 2) | ||
1302 | blizzard_reg_cache[reg / 2] = blizzard_read_reg(reg); | ||
1303 | } | ||
1304 | } | ||
1305 | |||
1306 | static void _restore_regs(struct blizzard_reg_list *list, int cnt) | ||
1307 | { | ||
1308 | int i; | ||
1309 | |||
1310 | for (i = 0; i < cnt; i++, list++) { | ||
1311 | int reg; | ||
1312 | for (reg = list->start; reg <= list->end; reg += 2) | ||
1313 | blizzard_write_reg(reg, blizzard_reg_cache[reg / 2]); | ||
1314 | } | ||
1315 | } | ||
1316 | |||
1317 | static void blizzard_save_all_regs(void) | ||
1318 | { | ||
1319 | _save_regs(blizzard_pll_regs, ARRAY_SIZE(blizzard_pll_regs)); | ||
1320 | _save_regs(blizzard_gen_regs, ARRAY_SIZE(blizzard_gen_regs)); | ||
1321 | } | ||
1322 | |||
1323 | static void blizzard_restore_pll_regs(void) | ||
1324 | { | ||
1325 | _restore_regs(blizzard_pll_regs, ARRAY_SIZE(blizzard_pll_regs)); | ||
1326 | } | ||
1327 | |||
1328 | static void blizzard_restore_gen_regs(void) | ||
1329 | { | ||
1330 | _restore_regs(blizzard_gen_regs, ARRAY_SIZE(blizzard_gen_regs)); | ||
1331 | } | ||
1332 | |||
1333 | static void blizzard_suspend(void) | ||
1334 | { | ||
1335 | u32 l; | ||
1336 | unsigned long tmo; | ||
1337 | |||
1338 | if (blizzard.last_color_mode) { | ||
1339 | update_full_screen(); | ||
1340 | blizzard_sync(); | ||
1341 | } | ||
1342 | blizzard.update_mode_before_suspend = blizzard.update_mode; | ||
1343 | /* the following will disable clocks as well */ | ||
1344 | blizzard_set_update_mode(OMAPFB_UPDATE_DISABLED); | ||
1345 | |||
1346 | blizzard_save_all_regs(); | ||
1347 | |||
1348 | blizzard_stop_sdram(); | ||
1349 | |||
1350 | l = blizzard_read_reg(BLIZZARD_POWER_SAVE); | ||
1351 | /* Standby, Sleep. We assume we use an external clock. */ | ||
1352 | l |= 0x03; | ||
1353 | blizzard_write_reg(BLIZZARD_POWER_SAVE, l); | ||
1354 | |||
1355 | tmo = jiffies + msecs_to_jiffies(100); | ||
1356 | while (!(blizzard_read_reg(BLIZZARD_PLL_MODE) & (1 << 1))) { | ||
1357 | if (time_after(jiffies, tmo)) { | ||
1358 | dev_err(blizzard.fbdev->dev, | ||
1359 | "s1d1374x: sleep timeout, stopping PLL manually\n"); | ||
1360 | l = blizzard_read_reg(BLIZZARD_PLL_MODE); | ||
1361 | l &= ~0x03; | ||
1362 | /* Disable PLL, counter function */ | ||
1363 | l |= 0x2; | ||
1364 | blizzard_write_reg(BLIZZARD_PLL_MODE, l); | ||
1365 | break; | ||
1366 | } | ||
1367 | msleep(1); | ||
1368 | } | ||
1369 | |||
1370 | if (blizzard.power_down != NULL) | ||
1371 | blizzard.power_down(blizzard.fbdev->dev); | ||
1372 | } | ||
1373 | |||
1374 | static void blizzard_resume(void) | ||
1375 | { | ||
1376 | u32 l; | ||
1377 | |||
1378 | if (blizzard.power_up != NULL) | ||
1379 | blizzard.power_up(blizzard.fbdev->dev); | ||
1380 | |||
1381 | l = blizzard_read_reg(BLIZZARD_POWER_SAVE); | ||
1382 | /* Standby, Sleep */ | ||
1383 | l &= ~0x03; | ||
1384 | blizzard_write_reg(BLIZZARD_POWER_SAVE, l); | ||
1385 | |||
1386 | blizzard_restore_pll_regs(); | ||
1387 | l = blizzard_read_reg(BLIZZARD_PLL_MODE); | ||
1388 | l &= ~0x03; | ||
1389 | /* Enable PLL, counter function */ | ||
1390 | l |= 0x1; | ||
1391 | blizzard_write_reg(BLIZZARD_PLL_MODE, l); | ||
1392 | |||
1393 | while (!(blizzard_read_reg(BLIZZARD_PLL_DIV) & (1 << 7))) | ||
1394 | msleep(1); | ||
1395 | |||
1396 | blizzard_restart_sdram(); | ||
1397 | |||
1398 | blizzard_restore_gen_regs(); | ||
1399 | |||
1400 | /* Enable display */ | ||
1401 | blizzard_write_reg(BLIZZARD_DISPLAY_MODE, 0x01); | ||
1402 | |||
1403 | /* the following will enable clocks as necessary */ | ||
1404 | blizzard_set_update_mode(blizzard.update_mode_before_suspend); | ||
1405 | |||
1406 | /* Force a background update */ | ||
1407 | blizzard.zoom_on = 1; | ||
1408 | update_full_screen(); | ||
1409 | blizzard_sync(); | ||
1410 | } | ||
1411 | |||
1412 | static int blizzard_init(struct omapfb_device *fbdev, int ext_mode, | ||
1413 | struct omapfb_mem_desc *req_vram) | ||
1414 | { | ||
1415 | int r = 0, i; | ||
1416 | u8 rev, conf; | ||
1417 | unsigned long ext_clk; | ||
1418 | int extif_div; | ||
1419 | unsigned long sys_clk, pix_clk; | ||
1420 | struct omapfb_platform_data *omapfb_conf; | ||
1421 | struct blizzard_platform_data *ctrl_conf; | ||
1422 | |||
1423 | blizzard.fbdev = fbdev; | ||
1424 | |||
1425 | BUG_ON(!fbdev->ext_if || !fbdev->int_ctrl); | ||
1426 | |||
1427 | blizzard.fbdev = fbdev; | ||
1428 | blizzard.extif = fbdev->ext_if; | ||
1429 | blizzard.int_ctrl = fbdev->int_ctrl; | ||
1430 | |||
1431 | omapfb_conf = fbdev->dev->platform_data; | ||
1432 | ctrl_conf = omapfb_conf->ctrl_platform_data; | ||
1433 | if (ctrl_conf == NULL || ctrl_conf->get_clock_rate == NULL) { | ||
1434 | dev_err(fbdev->dev, "s1d1374x: missing platform data\n"); | ||
1435 | r = -ENOENT; | ||
1436 | goto err1; | ||
1437 | } | ||
1438 | |||
1439 | blizzard.power_down = ctrl_conf->power_down; | ||
1440 | blizzard.power_up = ctrl_conf->power_up; | ||
1441 | |||
1442 | spin_lock_init(&blizzard.req_lock); | ||
1443 | |||
1444 | if ((r = blizzard.int_ctrl->init(fbdev, 1, req_vram)) < 0) | ||
1445 | goto err1; | ||
1446 | |||
1447 | if ((r = blizzard.extif->init(fbdev)) < 0) | ||
1448 | goto err2; | ||
1449 | |||
1450 | blizzard_ctrl.set_color_key = blizzard.int_ctrl->set_color_key; | ||
1451 | blizzard_ctrl.get_color_key = blizzard.int_ctrl->get_color_key; | ||
1452 | blizzard_ctrl.setup_mem = blizzard.int_ctrl->setup_mem; | ||
1453 | blizzard_ctrl.mmap = blizzard.int_ctrl->mmap; | ||
1454 | |||
1455 | ext_clk = ctrl_conf->get_clock_rate(fbdev->dev); | ||
1456 | if ((r = calc_extif_timings(ext_clk, &extif_div)) < 0) | ||
1457 | goto err3; | ||
1458 | |||
1459 | set_extif_timings(&blizzard.reg_timings); | ||
1460 | |||
1461 | if (blizzard.power_up != NULL) | ||
1462 | blizzard.power_up(fbdev->dev); | ||
1463 | |||
1464 | calc_blizzard_clk_rates(ext_clk, &sys_clk, &pix_clk); | ||
1465 | |||
1466 | if ((r = calc_extif_timings(sys_clk, &extif_div)) < 0) | ||
1467 | goto err3; | ||
1468 | set_extif_timings(&blizzard.reg_timings); | ||
1469 | |||
1470 | if (!(blizzard_read_reg(BLIZZARD_PLL_DIV) & 0x80)) { | ||
1471 | dev_err(fbdev->dev, | ||
1472 | "controller not initialized by the bootloader\n"); | ||
1473 | r = -ENODEV; | ||
1474 | goto err3; | ||
1475 | } | ||
1476 | |||
1477 | if (ctrl_conf->te_connected) { | ||
1478 | if ((r = setup_tearsync(pix_clk, extif_div)) < 0) | ||
1479 | goto err3; | ||
1480 | blizzard.te_connected = 1; | ||
1481 | } | ||
1482 | |||
1483 | rev = blizzard_read_reg(BLIZZARD_REV_CODE); | ||
1484 | conf = blizzard_read_reg(BLIZZARD_CONFIG); | ||
1485 | |||
1486 | switch (rev & 0xfc) { | ||
1487 | case 0x9c: | ||
1488 | blizzard.version = BLIZZARD_VERSION_S1D13744; | ||
1489 | pr_info("omapfb: s1d13744 LCD controller rev %d " | ||
1490 | "initialized (CNF pins %x)\n", rev & 0x03, conf & 0x07); | ||
1491 | break; | ||
1492 | case 0xa4: | ||
1493 | blizzard.version = BLIZZARD_VERSION_S1D13745; | ||
1494 | pr_info("omapfb: s1d13745 LCD controller rev %d " | ||
1495 | "initialized (CNF pins %x)\n", rev & 0x03, conf & 0x07); | ||
1496 | break; | ||
1497 | default: | ||
1498 | dev_err(fbdev->dev, "invalid s1d1374x revision %02x\n", | ||
1499 | rev); | ||
1500 | r = -ENODEV; | ||
1501 | goto err3; | ||
1502 | } | ||
1503 | |||
1504 | blizzard.max_transmit_size = blizzard.extif->max_transmit_size; | ||
1505 | |||
1506 | blizzard.update_mode = OMAPFB_UPDATE_DISABLED; | ||
1507 | |||
1508 | blizzard.auto_update_window.x = 0; | ||
1509 | blizzard.auto_update_window.y = 0; | ||
1510 | blizzard.auto_update_window.width = fbdev->panel->x_res; | ||
1511 | blizzard.auto_update_window.height = fbdev->panel->y_res; | ||
1512 | blizzard.auto_update_window.out_x = 0; | ||
1513 | blizzard.auto_update_window.out_x = 0; | ||
1514 | blizzard.auto_update_window.out_width = fbdev->panel->x_res; | ||
1515 | blizzard.auto_update_window.out_height = fbdev->panel->y_res; | ||
1516 | blizzard.auto_update_window.format = 0; | ||
1517 | |||
1518 | blizzard.screen_width = fbdev->panel->x_res; | ||
1519 | blizzard.screen_height = fbdev->panel->y_res; | ||
1520 | |||
1521 | init_timer(&blizzard.auto_update_timer); | ||
1522 | blizzard.auto_update_timer.function = blizzard_update_window_auto; | ||
1523 | blizzard.auto_update_timer.data = 0; | ||
1524 | |||
1525 | INIT_LIST_HEAD(&blizzard.free_req_list); | ||
1526 | INIT_LIST_HEAD(&blizzard.pending_req_list); | ||
1527 | for (i = 0; i < ARRAY_SIZE(blizzard.req_pool); i++) | ||
1528 | list_add(&blizzard.req_pool[i].entry, &blizzard.free_req_list); | ||
1529 | BUG_ON(i <= IRQ_REQ_POOL_SIZE); | ||
1530 | sema_init(&blizzard.req_sema, i - IRQ_REQ_POOL_SIZE); | ||
1531 | |||
1532 | return 0; | ||
1533 | err3: | ||
1534 | if (blizzard.power_down != NULL) | ||
1535 | blizzard.power_down(fbdev->dev); | ||
1536 | blizzard.extif->cleanup(); | ||
1537 | err2: | ||
1538 | blizzard.int_ctrl->cleanup(); | ||
1539 | err1: | ||
1540 | return r; | ||
1541 | } | ||
1542 | |||
1543 | static void blizzard_cleanup(void) | ||
1544 | { | ||
1545 | blizzard_set_update_mode(OMAPFB_UPDATE_DISABLED); | ||
1546 | blizzard.extif->cleanup(); | ||
1547 | blizzard.int_ctrl->cleanup(); | ||
1548 | if (blizzard.power_down != NULL) | ||
1549 | blizzard.power_down(blizzard.fbdev->dev); | ||
1550 | } | ||
1551 | |||
1552 | struct lcd_ctrl blizzard_ctrl = { | ||
1553 | .name = "blizzard", | ||
1554 | .init = blizzard_init, | ||
1555 | .cleanup = blizzard_cleanup, | ||
1556 | .bind_client = blizzard_bind_client, | ||
1557 | .get_caps = blizzard_get_caps, | ||
1558 | .set_update_mode = blizzard_set_update_mode, | ||
1559 | .get_update_mode = blizzard_get_update_mode, | ||
1560 | .setup_plane = blizzard_setup_plane, | ||
1561 | .set_scale = blizzard_set_scale, | ||
1562 | .enable_plane = blizzard_enable_plane, | ||
1563 | .update_window = blizzard_update_window_async, | ||
1564 | .sync = blizzard_sync, | ||
1565 | .suspend = blizzard_suspend, | ||
1566 | .resume = blizzard_resume, | ||
1567 | }; | ||
1568 | |||
diff --git a/drivers/video/omap/dispc.c b/drivers/video/omap/dispc.c new file mode 100644 index 000000000000..f4c23434de6f --- /dev/null +++ b/drivers/video/omap/dispc.c | |||
@@ -0,0 +1,1502 @@ | |||
1 | /* | ||
2 | * OMAP2 display controller support | ||
3 | * | ||
4 | * Copyright (C) 2005 Nokia Corporation | ||
5 | * Author: Imre Deak <imre.deak@nokia.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License along | ||
18 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
19 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
20 | */ | ||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/dma-mapping.h> | ||
23 | #include <linux/vmalloc.h> | ||
24 | #include <linux/clk.h> | ||
25 | #include <linux/io.h> | ||
26 | |||
27 | #include <asm/arch/sram.h> | ||
28 | #include <asm/arch/omapfb.h> | ||
29 | #include <asm/arch/board.h> | ||
30 | |||
31 | #include "dispc.h" | ||
32 | |||
33 | #define MODULE_NAME "dispc" | ||
34 | |||
35 | #define DSS_BASE 0x48050000 | ||
36 | #define DSS_SYSCONFIG 0x0010 | ||
37 | |||
38 | #define DISPC_BASE 0x48050400 | ||
39 | |||
40 | /* DISPC common */ | ||
41 | #define DISPC_REVISION 0x0000 | ||
42 | #define DISPC_SYSCONFIG 0x0010 | ||
43 | #define DISPC_SYSSTATUS 0x0014 | ||
44 | #define DISPC_IRQSTATUS 0x0018 | ||
45 | #define DISPC_IRQENABLE 0x001C | ||
46 | #define DISPC_CONTROL 0x0040 | ||
47 | #define DISPC_CONFIG 0x0044 | ||
48 | #define DISPC_CAPABLE 0x0048 | ||
49 | #define DISPC_DEFAULT_COLOR0 0x004C | ||
50 | #define DISPC_DEFAULT_COLOR1 0x0050 | ||
51 | #define DISPC_TRANS_COLOR0 0x0054 | ||
52 | #define DISPC_TRANS_COLOR1 0x0058 | ||
53 | #define DISPC_LINE_STATUS 0x005C | ||
54 | #define DISPC_LINE_NUMBER 0x0060 | ||
55 | #define DISPC_TIMING_H 0x0064 | ||
56 | #define DISPC_TIMING_V 0x0068 | ||
57 | #define DISPC_POL_FREQ 0x006C | ||
58 | #define DISPC_DIVISOR 0x0070 | ||
59 | #define DISPC_SIZE_DIG 0x0078 | ||
60 | #define DISPC_SIZE_LCD 0x007C | ||
61 | |||
62 | #define DISPC_DATA_CYCLE1 0x01D4 | ||
63 | #define DISPC_DATA_CYCLE2 0x01D8 | ||
64 | #define DISPC_DATA_CYCLE3 0x01DC | ||
65 | |||
66 | /* DISPC GFX plane */ | ||
67 | #define DISPC_GFX_BA0 0x0080 | ||
68 | #define DISPC_GFX_BA1 0x0084 | ||
69 | #define DISPC_GFX_POSITION 0x0088 | ||
70 | #define DISPC_GFX_SIZE 0x008C | ||
71 | #define DISPC_GFX_ATTRIBUTES 0x00A0 | ||
72 | #define DISPC_GFX_FIFO_THRESHOLD 0x00A4 | ||
73 | #define DISPC_GFX_FIFO_SIZE_STATUS 0x00A8 | ||
74 | #define DISPC_GFX_ROW_INC 0x00AC | ||
75 | #define DISPC_GFX_PIXEL_INC 0x00B0 | ||
76 | #define DISPC_GFX_WINDOW_SKIP 0x00B4 | ||
77 | #define DISPC_GFX_TABLE_BA 0x00B8 | ||
78 | |||
79 | /* DISPC Video plane 1/2 */ | ||
80 | #define DISPC_VID1_BASE 0x00BC | ||
81 | #define DISPC_VID2_BASE 0x014C | ||
82 | |||
83 | /* Offsets into DISPC_VID1/2_BASE */ | ||
84 | #define DISPC_VID_BA0 0x0000 | ||
85 | #define DISPC_VID_BA1 0x0004 | ||
86 | #define DISPC_VID_POSITION 0x0008 | ||
87 | #define DISPC_VID_SIZE 0x000C | ||
88 | #define DISPC_VID_ATTRIBUTES 0x0010 | ||
89 | #define DISPC_VID_FIFO_THRESHOLD 0x0014 | ||
90 | #define DISPC_VID_FIFO_SIZE_STATUS 0x0018 | ||
91 | #define DISPC_VID_ROW_INC 0x001C | ||
92 | #define DISPC_VID_PIXEL_INC 0x0020 | ||
93 | #define DISPC_VID_FIR 0x0024 | ||
94 | #define DISPC_VID_PICTURE_SIZE 0x0028 | ||
95 | #define DISPC_VID_ACCU0 0x002C | ||
96 | #define DISPC_VID_ACCU1 0x0030 | ||
97 | |||
98 | /* 8 elements in 8 byte increments */ | ||
99 | #define DISPC_VID_FIR_COEF_H0 0x0034 | ||
100 | /* 8 elements in 8 byte increments */ | ||
101 | #define DISPC_VID_FIR_COEF_HV0 0x0038 | ||
102 | /* 5 elements in 4 byte increments */ | ||
103 | #define DISPC_VID_CONV_COEF0 0x0074 | ||
104 | |||
105 | #define DISPC_IRQ_FRAMEMASK 0x0001 | ||
106 | #define DISPC_IRQ_VSYNC 0x0002 | ||
107 | #define DISPC_IRQ_EVSYNC_EVEN 0x0004 | ||
108 | #define DISPC_IRQ_EVSYNC_ODD 0x0008 | ||
109 | #define DISPC_IRQ_ACBIAS_COUNT_STAT 0x0010 | ||
110 | #define DISPC_IRQ_PROG_LINE_NUM 0x0020 | ||
111 | #define DISPC_IRQ_GFX_FIFO_UNDERFLOW 0x0040 | ||
112 | #define DISPC_IRQ_GFX_END_WIN 0x0080 | ||
113 | #define DISPC_IRQ_PAL_GAMMA_MASK 0x0100 | ||
114 | #define DISPC_IRQ_OCP_ERR 0x0200 | ||
115 | #define DISPC_IRQ_VID1_FIFO_UNDERFLOW 0x0400 | ||
116 | #define DISPC_IRQ_VID1_END_WIN 0x0800 | ||
117 | #define DISPC_IRQ_VID2_FIFO_UNDERFLOW 0x1000 | ||
118 | #define DISPC_IRQ_VID2_END_WIN 0x2000 | ||
119 | #define DISPC_IRQ_SYNC_LOST 0x4000 | ||
120 | |||
121 | #define DISPC_IRQ_MASK_ALL 0x7fff | ||
122 | |||
123 | #define DISPC_IRQ_MASK_ERROR (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \ | ||
124 | DISPC_IRQ_VID1_FIFO_UNDERFLOW | \ | ||
125 | DISPC_IRQ_VID2_FIFO_UNDERFLOW | \ | ||
126 | DISPC_IRQ_SYNC_LOST) | ||
127 | |||
128 | #define RFBI_CONTROL 0x48050040 | ||
129 | |||
130 | #define MAX_PALETTE_SIZE (256 * 16) | ||
131 | |||
132 | #define FLD_MASK(pos, len) (((1 << len) - 1) << pos) | ||
133 | |||
134 | #define MOD_REG_FLD(reg, mask, val) \ | ||
135 | dispc_write_reg((reg), (dispc_read_reg(reg) & ~(mask)) | (val)); | ||
136 | |||
137 | #define OMAP2_SRAM_START 0x40200000 | ||
138 | /* Maximum size, in reality this is smaller if SRAM is partially locked. */ | ||
139 | #define OMAP2_SRAM_SIZE 0xa0000 /* 640k */ | ||
140 | |||
141 | /* We support the SDRAM / SRAM types. See OMAPFB_PLANE_MEMTYPE_* in omapfb.h */ | ||
142 | #define DISPC_MEMTYPE_NUM 2 | ||
143 | |||
144 | #define RESMAP_SIZE(_page_cnt) \ | ||
145 | ((_page_cnt + (sizeof(unsigned long) * 8) - 1) / 8) | ||
146 | #define RESMAP_PTR(_res_map, _page_nr) \ | ||
147 | (((_res_map)->map) + (_page_nr) / (sizeof(unsigned long) * 8)) | ||
148 | #define RESMAP_MASK(_page_nr) \ | ||
149 | (1 << ((_page_nr) & (sizeof(unsigned long) * 8 - 1))) | ||
150 | |||
151 | struct resmap { | ||
152 | unsigned long start; | ||
153 | unsigned page_cnt; | ||
154 | unsigned long *map; | ||
155 | }; | ||
156 | |||
157 | static struct { | ||
158 | u32 base; | ||
159 | |||
160 | struct omapfb_mem_desc mem_desc; | ||
161 | struct resmap *res_map[DISPC_MEMTYPE_NUM]; | ||
162 | atomic_t map_count[OMAPFB_PLANE_NUM]; | ||
163 | |||
164 | dma_addr_t palette_paddr; | ||
165 | void *palette_vaddr; | ||
166 | |||
167 | int ext_mode; | ||
168 | |||
169 | unsigned long enabled_irqs; | ||
170 | void (*irq_callback)(void *); | ||
171 | void *irq_callback_data; | ||
172 | struct completion frame_done; | ||
173 | |||
174 | int fir_hinc[OMAPFB_PLANE_NUM]; | ||
175 | int fir_vinc[OMAPFB_PLANE_NUM]; | ||
176 | |||
177 | struct clk *dss_ick, *dss1_fck; | ||
178 | struct clk *dss_54m_fck; | ||
179 | |||
180 | enum omapfb_update_mode update_mode; | ||
181 | struct omapfb_device *fbdev; | ||
182 | |||
183 | struct omapfb_color_key color_key; | ||
184 | } dispc; | ||
185 | |||
186 | static void enable_lcd_clocks(int enable); | ||
187 | |||
188 | static void inline dispc_write_reg(int idx, u32 val) | ||
189 | { | ||
190 | __raw_writel(val, dispc.base + idx); | ||
191 | } | ||
192 | |||
193 | static u32 inline dispc_read_reg(int idx) | ||
194 | { | ||
195 | u32 l = __raw_readl(dispc.base + idx); | ||
196 | return l; | ||
197 | } | ||
198 | |||
199 | /* Select RFBI or bypass mode */ | ||
200 | static void enable_rfbi_mode(int enable) | ||
201 | { | ||
202 | u32 l; | ||
203 | |||
204 | l = dispc_read_reg(DISPC_CONTROL); | ||
205 | /* Enable RFBI, GPIO0/1 */ | ||
206 | l &= ~((1 << 11) | (1 << 15) | (1 << 16)); | ||
207 | l |= enable ? (1 << 11) : 0; | ||
208 | /* RFBI En: GPIO0/1=10 RFBI Dis: GPIO0/1=11 */ | ||
209 | l |= 1 << 15; | ||
210 | l |= enable ? 0 : (1 << 16); | ||
211 | dispc_write_reg(DISPC_CONTROL, l); | ||
212 | |||
213 | /* Set bypass mode in RFBI module */ | ||
214 | l = __raw_readl(io_p2v(RFBI_CONTROL)); | ||
215 | l |= enable ? 0 : (1 << 1); | ||
216 | __raw_writel(l, io_p2v(RFBI_CONTROL)); | ||
217 | } | ||
218 | |||
219 | static void set_lcd_data_lines(int data_lines) | ||
220 | { | ||
221 | u32 l; | ||
222 | int code = 0; | ||
223 | |||
224 | switch (data_lines) { | ||
225 | case 12: | ||
226 | code = 0; | ||
227 | break; | ||
228 | case 16: | ||
229 | code = 1; | ||
230 | break; | ||
231 | case 18: | ||
232 | code = 2; | ||
233 | break; | ||
234 | case 24: | ||
235 | code = 3; | ||
236 | break; | ||
237 | default: | ||
238 | BUG(); | ||
239 | } | ||
240 | |||
241 | l = dispc_read_reg(DISPC_CONTROL); | ||
242 | l &= ~(0x03 << 8); | ||
243 | l |= code << 8; | ||
244 | dispc_write_reg(DISPC_CONTROL, l); | ||
245 | } | ||
246 | |||
247 | static void set_load_mode(int mode) | ||
248 | { | ||
249 | BUG_ON(mode & ~(DISPC_LOAD_CLUT_ONLY | DISPC_LOAD_FRAME_ONLY | | ||
250 | DISPC_LOAD_CLUT_ONCE_FRAME)); | ||
251 | MOD_REG_FLD(DISPC_CONFIG, 0x03 << 1, mode << 1); | ||
252 | } | ||
253 | |||
254 | void omap_dispc_set_lcd_size(int x, int y) | ||
255 | { | ||
256 | BUG_ON((x > (1 << 11)) || (y > (1 << 11))); | ||
257 | enable_lcd_clocks(1); | ||
258 | MOD_REG_FLD(DISPC_SIZE_LCD, FLD_MASK(16, 11) | FLD_MASK(0, 11), | ||
259 | ((y - 1) << 16) | (x - 1)); | ||
260 | enable_lcd_clocks(0); | ||
261 | } | ||
262 | EXPORT_SYMBOL(omap_dispc_set_lcd_size); | ||
263 | |||
264 | void omap_dispc_set_digit_size(int x, int y) | ||
265 | { | ||
266 | BUG_ON((x > (1 << 11)) || (y > (1 << 11))); | ||
267 | enable_lcd_clocks(1); | ||
268 | MOD_REG_FLD(DISPC_SIZE_DIG, FLD_MASK(16, 11) | FLD_MASK(0, 11), | ||
269 | ((y - 1) << 16) | (x - 1)); | ||
270 | enable_lcd_clocks(0); | ||
271 | } | ||
272 | EXPORT_SYMBOL(omap_dispc_set_digit_size); | ||
273 | |||
274 | static void setup_plane_fifo(int plane, int ext_mode) | ||
275 | { | ||
276 | const u32 ftrs_reg[] = { DISPC_GFX_FIFO_THRESHOLD, | ||
277 | DISPC_VID1_BASE + DISPC_VID_FIFO_THRESHOLD, | ||
278 | DISPC_VID2_BASE + DISPC_VID_FIFO_THRESHOLD }; | ||
279 | const u32 fsz_reg[] = { DISPC_GFX_FIFO_SIZE_STATUS, | ||
280 | DISPC_VID1_BASE + DISPC_VID_FIFO_SIZE_STATUS, | ||
281 | DISPC_VID2_BASE + DISPC_VID_FIFO_SIZE_STATUS }; | ||
282 | int low, high; | ||
283 | u32 l; | ||
284 | |||
285 | BUG_ON(plane > 2); | ||
286 | |||
287 | l = dispc_read_reg(fsz_reg[plane]); | ||
288 | l &= FLD_MASK(0, 9); | ||
289 | if (ext_mode) { | ||
290 | low = l * 3 / 4; | ||
291 | high = l; | ||
292 | } else { | ||
293 | low = l / 4; | ||
294 | high = l * 3 / 4; | ||
295 | } | ||
296 | MOD_REG_FLD(ftrs_reg[plane], FLD_MASK(16, 9) | FLD_MASK(0, 9), | ||
297 | (high << 16) | low); | ||
298 | } | ||
299 | |||
300 | void omap_dispc_enable_lcd_out(int enable) | ||
301 | { | ||
302 | enable_lcd_clocks(1); | ||
303 | MOD_REG_FLD(DISPC_CONTROL, 1, enable ? 1 : 0); | ||
304 | enable_lcd_clocks(0); | ||
305 | } | ||
306 | EXPORT_SYMBOL(omap_dispc_enable_lcd_out); | ||
307 | |||
308 | void omap_dispc_enable_digit_out(int enable) | ||
309 | { | ||
310 | enable_lcd_clocks(1); | ||
311 | MOD_REG_FLD(DISPC_CONTROL, 1 << 1, enable ? 1 << 1 : 0); | ||
312 | enable_lcd_clocks(0); | ||
313 | } | ||
314 | EXPORT_SYMBOL(omap_dispc_enable_digit_out); | ||
315 | |||
316 | static inline int _setup_plane(int plane, int channel_out, | ||
317 | u32 paddr, int screen_width, | ||
318 | int pos_x, int pos_y, int width, int height, | ||
319 | int color_mode) | ||
320 | { | ||
321 | const u32 at_reg[] = { DISPC_GFX_ATTRIBUTES, | ||
322 | DISPC_VID1_BASE + DISPC_VID_ATTRIBUTES, | ||
323 | DISPC_VID2_BASE + DISPC_VID_ATTRIBUTES }; | ||
324 | const u32 ba_reg[] = { DISPC_GFX_BA0, DISPC_VID1_BASE + DISPC_VID_BA0, | ||
325 | DISPC_VID2_BASE + DISPC_VID_BA0 }; | ||
326 | const u32 ps_reg[] = { DISPC_GFX_POSITION, | ||
327 | DISPC_VID1_BASE + DISPC_VID_POSITION, | ||
328 | DISPC_VID2_BASE + DISPC_VID_POSITION }; | ||
329 | const u32 sz_reg[] = { DISPC_GFX_SIZE, | ||
330 | DISPC_VID1_BASE + DISPC_VID_PICTURE_SIZE, | ||
331 | DISPC_VID2_BASE + DISPC_VID_PICTURE_SIZE }; | ||
332 | const u32 ri_reg[] = { DISPC_GFX_ROW_INC, | ||
333 | DISPC_VID1_BASE + DISPC_VID_ROW_INC, | ||
334 | DISPC_VID2_BASE + DISPC_VID_ROW_INC }; | ||
335 | const u32 vs_reg[] = { 0, DISPC_VID1_BASE + DISPC_VID_SIZE, | ||
336 | DISPC_VID2_BASE + DISPC_VID_SIZE }; | ||
337 | |||
338 | int chout_shift, burst_shift; | ||
339 | int chout_val; | ||
340 | int color_code; | ||
341 | int bpp; | ||
342 | int cconv_en; | ||
343 | int set_vsize; | ||
344 | u32 l; | ||
345 | |||
346 | #ifdef VERBOSE | ||
347 | dev_dbg(dispc.fbdev->dev, "plane %d channel %d paddr %#08x scr_width %d" | ||
348 | " pos_x %d pos_y %d width %d height %d color_mode %d\n", | ||
349 | plane, channel_out, paddr, screen_width, pos_x, pos_y, | ||
350 | width, height, color_mode); | ||
351 | #endif | ||
352 | |||
353 | set_vsize = 0; | ||
354 | switch (plane) { | ||
355 | case OMAPFB_PLANE_GFX: | ||
356 | burst_shift = 6; | ||
357 | chout_shift = 8; | ||
358 | break; | ||
359 | case OMAPFB_PLANE_VID1: | ||
360 | case OMAPFB_PLANE_VID2: | ||
361 | burst_shift = 14; | ||
362 | chout_shift = 16; | ||
363 | set_vsize = 1; | ||
364 | break; | ||
365 | default: | ||
366 | return -EINVAL; | ||
367 | } | ||
368 | |||
369 | switch (channel_out) { | ||
370 | case OMAPFB_CHANNEL_OUT_LCD: | ||
371 | chout_val = 0; | ||
372 | break; | ||
373 | case OMAPFB_CHANNEL_OUT_DIGIT: | ||
374 | chout_val = 1; | ||
375 | break; | ||
376 | default: | ||
377 | return -EINVAL; | ||
378 | } | ||
379 | |||
380 | cconv_en = 0; | ||
381 | switch (color_mode) { | ||
382 | case OMAPFB_COLOR_RGB565: | ||
383 | color_code = DISPC_RGB_16_BPP; | ||
384 | bpp = 16; | ||
385 | break; | ||
386 | case OMAPFB_COLOR_YUV422: | ||
387 | if (plane == 0) | ||
388 | return -EINVAL; | ||
389 | color_code = DISPC_UYVY_422; | ||
390 | cconv_en = 1; | ||
391 | bpp = 16; | ||
392 | break; | ||
393 | case OMAPFB_COLOR_YUY422: | ||
394 | if (plane == 0) | ||
395 | return -EINVAL; | ||
396 | color_code = DISPC_YUV2_422; | ||
397 | cconv_en = 1; | ||
398 | bpp = 16; | ||
399 | break; | ||
400 | default: | ||
401 | return -EINVAL; | ||
402 | } | ||
403 | |||
404 | l = dispc_read_reg(at_reg[plane]); | ||
405 | |||
406 | l &= ~(0x0f << 1); | ||
407 | l |= color_code << 1; | ||
408 | l &= ~(1 << 9); | ||
409 | l |= cconv_en << 9; | ||
410 | |||
411 | l &= ~(0x03 << burst_shift); | ||
412 | l |= DISPC_BURST_8x32 << burst_shift; | ||
413 | |||
414 | l &= ~(1 << chout_shift); | ||
415 | l |= chout_val << chout_shift; | ||
416 | |||
417 | dispc_write_reg(at_reg[plane], l); | ||
418 | |||
419 | dispc_write_reg(ba_reg[plane], paddr); | ||
420 | MOD_REG_FLD(ps_reg[plane], | ||
421 | FLD_MASK(16, 11) | FLD_MASK(0, 11), (pos_y << 16) | pos_x); | ||
422 | |||
423 | MOD_REG_FLD(sz_reg[plane], FLD_MASK(16, 11) | FLD_MASK(0, 11), | ||
424 | ((height - 1) << 16) | (width - 1)); | ||
425 | |||
426 | if (set_vsize) { | ||
427 | /* Set video size if set_scale hasn't set it */ | ||
428 | if (!dispc.fir_vinc[plane]) | ||
429 | MOD_REG_FLD(vs_reg[plane], | ||
430 | FLD_MASK(16, 11), (height - 1) << 16); | ||
431 | if (!dispc.fir_hinc[plane]) | ||
432 | MOD_REG_FLD(vs_reg[plane], | ||
433 | FLD_MASK(0, 11), width - 1); | ||
434 | } | ||
435 | |||
436 | dispc_write_reg(ri_reg[plane], (screen_width - width) * bpp / 8 + 1); | ||
437 | |||
438 | return height * screen_width * bpp / 8; | ||
439 | } | ||
440 | |||
441 | static int omap_dispc_setup_plane(int plane, int channel_out, | ||
442 | unsigned long offset, | ||
443 | int screen_width, | ||
444 | int pos_x, int pos_y, int width, int height, | ||
445 | int color_mode) | ||
446 | { | ||
447 | u32 paddr; | ||
448 | int r; | ||
449 | |||
450 | if ((unsigned)plane > dispc.mem_desc.region_cnt) | ||
451 | return -EINVAL; | ||
452 | paddr = dispc.mem_desc.region[plane].paddr + offset; | ||
453 | enable_lcd_clocks(1); | ||
454 | r = _setup_plane(plane, channel_out, paddr, | ||
455 | screen_width, | ||
456 | pos_x, pos_y, width, height, color_mode); | ||
457 | enable_lcd_clocks(0); | ||
458 | return r; | ||
459 | } | ||
460 | |||
461 | static void write_firh_reg(int plane, int reg, u32 value) | ||
462 | { | ||
463 | u32 base; | ||
464 | |||
465 | if (plane == 1) | ||
466 | base = DISPC_VID1_BASE + DISPC_VID_FIR_COEF_H0; | ||
467 | else | ||
468 | base = DISPC_VID2_BASE + DISPC_VID_FIR_COEF_H0; | ||
469 | dispc_write_reg(base + reg * 8, value); | ||
470 | } | ||
471 | |||
472 | static void write_firhv_reg(int plane, int reg, u32 value) | ||
473 | { | ||
474 | u32 base; | ||
475 | |||
476 | if (plane == 1) | ||
477 | base = DISPC_VID1_BASE + DISPC_VID_FIR_COEF_HV0; | ||
478 | else | ||
479 | base = DISPC_VID2_BASE + DISPC_VID_FIR_COEF_HV0; | ||
480 | dispc_write_reg(base + reg * 8, value); | ||
481 | } | ||
482 | |||
483 | static void set_upsampling_coef_table(int plane) | ||
484 | { | ||
485 | const u32 coef[][2] = { | ||
486 | { 0x00800000, 0x00800000 }, | ||
487 | { 0x0D7CF800, 0x037B02FF }, | ||
488 | { 0x1E70F5FF, 0x0C6F05FE }, | ||
489 | { 0x335FF5FE, 0x205907FB }, | ||
490 | { 0xF74949F7, 0x00404000 }, | ||
491 | { 0xF55F33FB, 0x075920FE }, | ||
492 | { 0xF5701EFE, 0x056F0CFF }, | ||
493 | { 0xF87C0DFF, 0x027B0300 }, | ||
494 | }; | ||
495 | int i; | ||
496 | |||
497 | for (i = 0; i < 8; i++) { | ||
498 | write_firh_reg(plane, i, coef[i][0]); | ||
499 | write_firhv_reg(plane, i, coef[i][1]); | ||
500 | } | ||
501 | } | ||
502 | |||
503 | static int omap_dispc_set_scale(int plane, | ||
504 | int orig_width, int orig_height, | ||
505 | int out_width, int out_height) | ||
506 | { | ||
507 | const u32 at_reg[] = { 0, DISPC_VID1_BASE + DISPC_VID_ATTRIBUTES, | ||
508 | DISPC_VID2_BASE + DISPC_VID_ATTRIBUTES }; | ||
509 | const u32 vs_reg[] = { 0, DISPC_VID1_BASE + DISPC_VID_SIZE, | ||
510 | DISPC_VID2_BASE + DISPC_VID_SIZE }; | ||
511 | const u32 fir_reg[] = { 0, DISPC_VID1_BASE + DISPC_VID_FIR, | ||
512 | DISPC_VID2_BASE + DISPC_VID_FIR }; | ||
513 | |||
514 | u32 l; | ||
515 | int fir_hinc; | ||
516 | int fir_vinc; | ||
517 | |||
518 | if ((unsigned)plane > OMAPFB_PLANE_NUM) | ||
519 | return -ENODEV; | ||
520 | |||
521 | if (plane == OMAPFB_PLANE_GFX && | ||
522 | (out_width != orig_width || out_height != orig_height)) | ||
523 | return -EINVAL; | ||
524 | |||
525 | enable_lcd_clocks(1); | ||
526 | if (orig_width < out_width) { | ||
527 | /* | ||
528 | * Upsampling. | ||
529 | * Currently you can only scale both dimensions in one way. | ||
530 | */ | ||
531 | if (orig_height > out_height || | ||
532 | orig_width * 8 < out_width || | ||
533 | orig_height * 8 < out_height) { | ||
534 | enable_lcd_clocks(0); | ||
535 | return -EINVAL; | ||
536 | } | ||
537 | set_upsampling_coef_table(plane); | ||
538 | } else if (orig_width > out_width) { | ||
539 | /* Downsampling not yet supported | ||
540 | */ | ||
541 | |||
542 | enable_lcd_clocks(0); | ||
543 | return -EINVAL; | ||
544 | } | ||
545 | if (!orig_width || orig_width == out_width) | ||
546 | fir_hinc = 0; | ||
547 | else | ||
548 | fir_hinc = 1024 * orig_width / out_width; | ||
549 | if (!orig_height || orig_height == out_height) | ||
550 | fir_vinc = 0; | ||
551 | else | ||
552 | fir_vinc = 1024 * orig_height / out_height; | ||
553 | dispc.fir_hinc[plane] = fir_hinc; | ||
554 | dispc.fir_vinc[plane] = fir_vinc; | ||
555 | |||
556 | MOD_REG_FLD(fir_reg[plane], | ||
557 | FLD_MASK(16, 12) | FLD_MASK(0, 12), | ||
558 | ((fir_vinc & 4095) << 16) | | ||
559 | (fir_hinc & 4095)); | ||
560 | |||
561 | dev_dbg(dispc.fbdev->dev, "out_width %d out_height %d orig_width %d " | ||
562 | "orig_height %d fir_hinc %d fir_vinc %d\n", | ||
563 | out_width, out_height, orig_width, orig_height, | ||
564 | fir_hinc, fir_vinc); | ||
565 | |||
566 | MOD_REG_FLD(vs_reg[plane], | ||
567 | FLD_MASK(16, 11) | FLD_MASK(0, 11), | ||
568 | ((out_height - 1) << 16) | (out_width - 1)); | ||
569 | |||
570 | l = dispc_read_reg(at_reg[plane]); | ||
571 | l &= ~(0x03 << 5); | ||
572 | l |= fir_hinc ? (1 << 5) : 0; | ||
573 | l |= fir_vinc ? (1 << 6) : 0; | ||
574 | dispc_write_reg(at_reg[plane], l); | ||
575 | |||
576 | enable_lcd_clocks(0); | ||
577 | return 0; | ||
578 | } | ||
579 | |||
580 | static int omap_dispc_enable_plane(int plane, int enable) | ||
581 | { | ||
582 | const u32 at_reg[] = { DISPC_GFX_ATTRIBUTES, | ||
583 | DISPC_VID1_BASE + DISPC_VID_ATTRIBUTES, | ||
584 | DISPC_VID2_BASE + DISPC_VID_ATTRIBUTES }; | ||
585 | if ((unsigned int)plane > dispc.mem_desc.region_cnt) | ||
586 | return -EINVAL; | ||
587 | |||
588 | enable_lcd_clocks(1); | ||
589 | MOD_REG_FLD(at_reg[plane], 1, enable ? 1 : 0); | ||
590 | enable_lcd_clocks(0); | ||
591 | |||
592 | return 0; | ||
593 | } | ||
594 | |||
595 | static int omap_dispc_set_color_key(struct omapfb_color_key *ck) | ||
596 | { | ||
597 | u32 df_reg, tr_reg; | ||
598 | int shift, val; | ||
599 | |||
600 | switch (ck->channel_out) { | ||
601 | case OMAPFB_CHANNEL_OUT_LCD: | ||
602 | df_reg = DISPC_DEFAULT_COLOR0; | ||
603 | tr_reg = DISPC_TRANS_COLOR0; | ||
604 | shift = 10; | ||
605 | break; | ||
606 | case OMAPFB_CHANNEL_OUT_DIGIT: | ||
607 | df_reg = DISPC_DEFAULT_COLOR1; | ||
608 | tr_reg = DISPC_TRANS_COLOR1; | ||
609 | shift = 12; | ||
610 | break; | ||
611 | default: | ||
612 | return -EINVAL; | ||
613 | } | ||
614 | switch (ck->key_type) { | ||
615 | case OMAPFB_COLOR_KEY_DISABLED: | ||
616 | val = 0; | ||
617 | break; | ||
618 | case OMAPFB_COLOR_KEY_GFX_DST: | ||
619 | val = 1; | ||
620 | break; | ||
621 | case OMAPFB_COLOR_KEY_VID_SRC: | ||
622 | val = 3; | ||
623 | break; | ||
624 | default: | ||
625 | return -EINVAL; | ||
626 | } | ||
627 | enable_lcd_clocks(1); | ||
628 | MOD_REG_FLD(DISPC_CONFIG, FLD_MASK(shift, 2), val << shift); | ||
629 | |||
630 | if (val != 0) | ||
631 | dispc_write_reg(tr_reg, ck->trans_key); | ||
632 | dispc_write_reg(df_reg, ck->background); | ||
633 | enable_lcd_clocks(0); | ||
634 | |||
635 | dispc.color_key = *ck; | ||
636 | |||
637 | return 0; | ||
638 | } | ||
639 | |||
640 | static int omap_dispc_get_color_key(struct omapfb_color_key *ck) | ||
641 | { | ||
642 | *ck = dispc.color_key; | ||
643 | return 0; | ||
644 | } | ||
645 | |||
646 | static void load_palette(void) | ||
647 | { | ||
648 | } | ||
649 | |||
650 | static int omap_dispc_set_update_mode(enum omapfb_update_mode mode) | ||
651 | { | ||
652 | int r = 0; | ||
653 | |||
654 | if (mode != dispc.update_mode) { | ||
655 | switch (mode) { | ||
656 | case OMAPFB_AUTO_UPDATE: | ||
657 | case OMAPFB_MANUAL_UPDATE: | ||
658 | enable_lcd_clocks(1); | ||
659 | omap_dispc_enable_lcd_out(1); | ||
660 | dispc.update_mode = mode; | ||
661 | break; | ||
662 | case OMAPFB_UPDATE_DISABLED: | ||
663 | init_completion(&dispc.frame_done); | ||
664 | omap_dispc_enable_lcd_out(0); | ||
665 | if (!wait_for_completion_timeout(&dispc.frame_done, | ||
666 | msecs_to_jiffies(500))) { | ||
667 | dev_err(dispc.fbdev->dev, | ||
668 | "timeout waiting for FRAME DONE\n"); | ||
669 | } | ||
670 | dispc.update_mode = mode; | ||
671 | enable_lcd_clocks(0); | ||
672 | break; | ||
673 | default: | ||
674 | r = -EINVAL; | ||
675 | } | ||
676 | } | ||
677 | |||
678 | return r; | ||
679 | } | ||
680 | |||
681 | static void omap_dispc_get_caps(int plane, struct omapfb_caps *caps) | ||
682 | { | ||
683 | caps->ctrl |= OMAPFB_CAPS_PLANE_RELOCATE_MEM; | ||
684 | if (plane > 0) | ||
685 | caps->ctrl |= OMAPFB_CAPS_PLANE_SCALE; | ||
686 | caps->plane_color |= (1 << OMAPFB_COLOR_RGB565) | | ||
687 | (1 << OMAPFB_COLOR_YUV422) | | ||
688 | (1 << OMAPFB_COLOR_YUY422); | ||
689 | if (plane == 0) | ||
690 | caps->plane_color |= (1 << OMAPFB_COLOR_CLUT_8BPP) | | ||
691 | (1 << OMAPFB_COLOR_CLUT_4BPP) | | ||
692 | (1 << OMAPFB_COLOR_CLUT_2BPP) | | ||
693 | (1 << OMAPFB_COLOR_CLUT_1BPP) | | ||
694 | (1 << OMAPFB_COLOR_RGB444); | ||
695 | } | ||
696 | |||
697 | static enum omapfb_update_mode omap_dispc_get_update_mode(void) | ||
698 | { | ||
699 | return dispc.update_mode; | ||
700 | } | ||
701 | |||
702 | static void setup_color_conv_coef(void) | ||
703 | { | ||
704 | u32 mask = FLD_MASK(16, 11) | FLD_MASK(0, 11); | ||
705 | int cf1_reg = DISPC_VID1_BASE + DISPC_VID_CONV_COEF0; | ||
706 | int cf2_reg = DISPC_VID2_BASE + DISPC_VID_CONV_COEF0; | ||
707 | int at1_reg = DISPC_VID1_BASE + DISPC_VID_ATTRIBUTES; | ||
708 | int at2_reg = DISPC_VID2_BASE + DISPC_VID_ATTRIBUTES; | ||
709 | const struct color_conv_coef { | ||
710 | int ry, rcr, rcb, gy, gcr, gcb, by, bcr, bcb; | ||
711 | int full_range; | ||
712 | } ctbl_bt601_5 = { | ||
713 | 298, 409, 0, 298, -208, -100, 298, 0, 517, 0, | ||
714 | }; | ||
715 | const struct color_conv_coef *ct; | ||
716 | #define CVAL(x, y) (((x & 2047) << 16) | (y & 2047)) | ||
717 | |||
718 | ct = &ctbl_bt601_5; | ||
719 | |||
720 | MOD_REG_FLD(cf1_reg, mask, CVAL(ct->rcr, ct->ry)); | ||
721 | MOD_REG_FLD(cf1_reg + 4, mask, CVAL(ct->gy, ct->rcb)); | ||
722 | MOD_REG_FLD(cf1_reg + 8, mask, CVAL(ct->gcb, ct->gcr)); | ||
723 | MOD_REG_FLD(cf1_reg + 12, mask, CVAL(ct->bcr, ct->by)); | ||
724 | MOD_REG_FLD(cf1_reg + 16, mask, CVAL(0, ct->bcb)); | ||
725 | |||
726 | MOD_REG_FLD(cf2_reg, mask, CVAL(ct->rcr, ct->ry)); | ||
727 | MOD_REG_FLD(cf2_reg + 4, mask, CVAL(ct->gy, ct->rcb)); | ||
728 | MOD_REG_FLD(cf2_reg + 8, mask, CVAL(ct->gcb, ct->gcr)); | ||
729 | MOD_REG_FLD(cf2_reg + 12, mask, CVAL(ct->bcr, ct->by)); | ||
730 | MOD_REG_FLD(cf2_reg + 16, mask, CVAL(0, ct->bcb)); | ||
731 | #undef CVAL | ||
732 | |||
733 | MOD_REG_FLD(at1_reg, (1 << 11), ct->full_range); | ||
734 | MOD_REG_FLD(at2_reg, (1 << 11), ct->full_range); | ||
735 | } | ||
736 | |||
737 | static void calc_ck_div(int is_tft, int pck, int *lck_div, int *pck_div) | ||
738 | { | ||
739 | unsigned long fck, lck; | ||
740 | |||
741 | *lck_div = 1; | ||
742 | pck = max(1, pck); | ||
743 | fck = clk_get_rate(dispc.dss1_fck); | ||
744 | lck = fck; | ||
745 | *pck_div = (lck + pck - 1) / pck; | ||
746 | if (is_tft) | ||
747 | *pck_div = max(2, *pck_div); | ||
748 | else | ||
749 | *pck_div = max(3, *pck_div); | ||
750 | if (*pck_div > 255) { | ||
751 | *pck_div = 255; | ||
752 | lck = pck * *pck_div; | ||
753 | *lck_div = fck / lck; | ||
754 | BUG_ON(*lck_div < 1); | ||
755 | if (*lck_div > 255) { | ||
756 | *lck_div = 255; | ||
757 | dev_warn(dispc.fbdev->dev, "pixclock %d kHz too low.\n", | ||
758 | pck / 1000); | ||
759 | } | ||
760 | } | ||
761 | } | ||
762 | |||
763 | static void set_lcd_tft_mode(int enable) | ||
764 | { | ||
765 | u32 mask; | ||
766 | |||
767 | mask = 1 << 3; | ||
768 | MOD_REG_FLD(DISPC_CONTROL, mask, enable ? mask : 0); | ||
769 | } | ||
770 | |||
771 | static void set_lcd_timings(void) | ||
772 | { | ||
773 | u32 l; | ||
774 | int lck_div, pck_div; | ||
775 | struct lcd_panel *panel = dispc.fbdev->panel; | ||
776 | int is_tft = panel->config & OMAP_LCDC_PANEL_TFT; | ||
777 | unsigned long fck; | ||
778 | |||
779 | l = dispc_read_reg(DISPC_TIMING_H); | ||
780 | l &= ~(FLD_MASK(0, 6) | FLD_MASK(8, 8) | FLD_MASK(20, 8)); | ||
781 | l |= ( max(1, (min(64, panel->hsw))) - 1 ) << 0; | ||
782 | l |= ( max(1, (min(256, panel->hfp))) - 1 ) << 8; | ||
783 | l |= ( max(1, (min(256, panel->hbp))) - 1 ) << 20; | ||
784 | dispc_write_reg(DISPC_TIMING_H, l); | ||
785 | |||
786 | l = dispc_read_reg(DISPC_TIMING_V); | ||
787 | l &= ~(FLD_MASK(0, 6) | FLD_MASK(8, 8) | FLD_MASK(20, 8)); | ||
788 | l |= ( max(1, (min(64, panel->vsw))) - 1 ) << 0; | ||
789 | l |= ( max(0, (min(255, panel->vfp))) - 0 ) << 8; | ||
790 | l |= ( max(0, (min(255, panel->vbp))) - 0 ) << 20; | ||
791 | dispc_write_reg(DISPC_TIMING_V, l); | ||
792 | |||
793 | l = dispc_read_reg(DISPC_POL_FREQ); | ||
794 | l &= ~FLD_MASK(12, 6); | ||
795 | l |= (panel->config & OMAP_LCDC_SIGNAL_MASK) << 12; | ||
796 | l |= panel->acb & 0xff; | ||
797 | dispc_write_reg(DISPC_POL_FREQ, l); | ||
798 | |||
799 | calc_ck_div(is_tft, panel->pixel_clock * 1000, &lck_div, &pck_div); | ||
800 | |||
801 | l = dispc_read_reg(DISPC_DIVISOR); | ||
802 | l &= ~(FLD_MASK(16, 8) | FLD_MASK(0, 8)); | ||
803 | l |= (lck_div << 16) | (pck_div << 0); | ||
804 | dispc_write_reg(DISPC_DIVISOR, l); | ||
805 | |||
806 | /* update panel info with the exact clock */ | ||
807 | fck = clk_get_rate(dispc.dss1_fck); | ||
808 | panel->pixel_clock = fck / lck_div / pck_div / 1000; | ||
809 | } | ||
810 | |||
811 | int omap_dispc_request_irq(void (*callback)(void *data), void *data) | ||
812 | { | ||
813 | int r = 0; | ||
814 | |||
815 | BUG_ON(callback == NULL); | ||
816 | |||
817 | if (dispc.irq_callback) | ||
818 | r = -EBUSY; | ||
819 | else { | ||
820 | dispc.irq_callback = callback; | ||
821 | dispc.irq_callback_data = data; | ||
822 | } | ||
823 | |||
824 | return r; | ||
825 | } | ||
826 | EXPORT_SYMBOL(omap_dispc_request_irq); | ||
827 | |||
828 | void omap_dispc_enable_irqs(int irq_mask) | ||
829 | { | ||
830 | enable_lcd_clocks(1); | ||
831 | dispc.enabled_irqs = irq_mask; | ||
832 | irq_mask |= DISPC_IRQ_MASK_ERROR; | ||
833 | MOD_REG_FLD(DISPC_IRQENABLE, 0x7fff, irq_mask); | ||
834 | enable_lcd_clocks(0); | ||
835 | } | ||
836 | EXPORT_SYMBOL(omap_dispc_enable_irqs); | ||
837 | |||
838 | void omap_dispc_disable_irqs(int irq_mask) | ||
839 | { | ||
840 | enable_lcd_clocks(1); | ||
841 | dispc.enabled_irqs &= ~irq_mask; | ||
842 | irq_mask &= ~DISPC_IRQ_MASK_ERROR; | ||
843 | MOD_REG_FLD(DISPC_IRQENABLE, 0x7fff, irq_mask); | ||
844 | enable_lcd_clocks(0); | ||
845 | } | ||
846 | EXPORT_SYMBOL(omap_dispc_disable_irqs); | ||
847 | |||
848 | void omap_dispc_free_irq(void) | ||
849 | { | ||
850 | enable_lcd_clocks(1); | ||
851 | omap_dispc_disable_irqs(DISPC_IRQ_MASK_ALL); | ||
852 | dispc.irq_callback = NULL; | ||
853 | dispc.irq_callback_data = NULL; | ||
854 | enable_lcd_clocks(0); | ||
855 | } | ||
856 | EXPORT_SYMBOL(omap_dispc_free_irq); | ||
857 | |||
858 | static irqreturn_t omap_dispc_irq_handler(int irq, void *dev) | ||
859 | { | ||
860 | u32 stat = dispc_read_reg(DISPC_IRQSTATUS); | ||
861 | |||
862 | if (stat & DISPC_IRQ_FRAMEMASK) | ||
863 | complete(&dispc.frame_done); | ||
864 | |||
865 | if (stat & DISPC_IRQ_MASK_ERROR) { | ||
866 | if (printk_ratelimit()) { | ||
867 | dev_err(dispc.fbdev->dev, "irq error status %04x\n", | ||
868 | stat & 0x7fff); | ||
869 | } | ||
870 | } | ||
871 | |||
872 | if ((stat & dispc.enabled_irqs) && dispc.irq_callback) | ||
873 | dispc.irq_callback(dispc.irq_callback_data); | ||
874 | |||
875 | dispc_write_reg(DISPC_IRQSTATUS, stat); | ||
876 | |||
877 | return IRQ_HANDLED; | ||
878 | } | ||
879 | |||
880 | static int get_dss_clocks(void) | ||
881 | { | ||
882 | if (IS_ERR((dispc.dss_ick = clk_get(dispc.fbdev->dev, "dss_ick")))) { | ||
883 | dev_err(dispc.fbdev->dev, "can't get dss_ick"); | ||
884 | return PTR_ERR(dispc.dss_ick); | ||
885 | } | ||
886 | |||
887 | if (IS_ERR((dispc.dss1_fck = clk_get(dispc.fbdev->dev, "dss1_fck")))) { | ||
888 | dev_err(dispc.fbdev->dev, "can't get dss1_fck"); | ||
889 | clk_put(dispc.dss_ick); | ||
890 | return PTR_ERR(dispc.dss1_fck); | ||
891 | } | ||
892 | |||
893 | if (IS_ERR((dispc.dss_54m_fck = | ||
894 | clk_get(dispc.fbdev->dev, "dss_54m_fck")))) { | ||
895 | dev_err(dispc.fbdev->dev, "can't get dss_54m_fck"); | ||
896 | clk_put(dispc.dss_ick); | ||
897 | clk_put(dispc.dss1_fck); | ||
898 | return PTR_ERR(dispc.dss_54m_fck); | ||
899 | } | ||
900 | |||
901 | return 0; | ||
902 | } | ||
903 | |||
904 | static void put_dss_clocks(void) | ||
905 | { | ||
906 | clk_put(dispc.dss_54m_fck); | ||
907 | clk_put(dispc.dss1_fck); | ||
908 | clk_put(dispc.dss_ick); | ||
909 | } | ||
910 | |||
911 | static void enable_lcd_clocks(int enable) | ||
912 | { | ||
913 | if (enable) | ||
914 | clk_enable(dispc.dss1_fck); | ||
915 | else | ||
916 | clk_disable(dispc.dss1_fck); | ||
917 | } | ||
918 | |||
919 | static void enable_interface_clocks(int enable) | ||
920 | { | ||
921 | if (enable) | ||
922 | clk_enable(dispc.dss_ick); | ||
923 | else | ||
924 | clk_disable(dispc.dss_ick); | ||
925 | } | ||
926 | |||
927 | static void enable_digit_clocks(int enable) | ||
928 | { | ||
929 | if (enable) | ||
930 | clk_enable(dispc.dss_54m_fck); | ||
931 | else | ||
932 | clk_disable(dispc.dss_54m_fck); | ||
933 | } | ||
934 | |||
935 | static void omap_dispc_suspend(void) | ||
936 | { | ||
937 | if (dispc.update_mode == OMAPFB_AUTO_UPDATE) { | ||
938 | init_completion(&dispc.frame_done); | ||
939 | omap_dispc_enable_lcd_out(0); | ||
940 | if (!wait_for_completion_timeout(&dispc.frame_done, | ||
941 | msecs_to_jiffies(500))) { | ||
942 | dev_err(dispc.fbdev->dev, | ||
943 | "timeout waiting for FRAME DONE\n"); | ||
944 | } | ||
945 | enable_lcd_clocks(0); | ||
946 | } | ||
947 | } | ||
948 | |||
949 | static void omap_dispc_resume(void) | ||
950 | { | ||
951 | if (dispc.update_mode == OMAPFB_AUTO_UPDATE) { | ||
952 | enable_lcd_clocks(1); | ||
953 | if (!dispc.ext_mode) { | ||
954 | set_lcd_timings(); | ||
955 | load_palette(); | ||
956 | } | ||
957 | omap_dispc_enable_lcd_out(1); | ||
958 | } | ||
959 | } | ||
960 | |||
961 | |||
962 | static int omap_dispc_update_window(struct fb_info *fbi, | ||
963 | struct omapfb_update_window *win, | ||
964 | void (*complete_callback)(void *arg), | ||
965 | void *complete_callback_data) | ||
966 | { | ||
967 | return dispc.update_mode == OMAPFB_UPDATE_DISABLED ? -ENODEV : 0; | ||
968 | } | ||
969 | |||
970 | static int mmap_kern(struct omapfb_mem_region *region) | ||
971 | { | ||
972 | struct vm_struct *kvma; | ||
973 | struct vm_area_struct vma; | ||
974 | pgprot_t pgprot; | ||
975 | unsigned long vaddr; | ||
976 | |||
977 | kvma = get_vm_area(region->size, VM_IOREMAP); | ||
978 | if (kvma == NULL) { | ||
979 | dev_err(dispc.fbdev->dev, "can't get kernel vm area\n"); | ||
980 | return -ENOMEM; | ||
981 | } | ||
982 | vma.vm_mm = &init_mm; | ||
983 | |||
984 | vaddr = (unsigned long)kvma->addr; | ||
985 | |||
986 | pgprot = pgprot_writecombine(pgprot_kernel); | ||
987 | vma.vm_start = vaddr; | ||
988 | vma.vm_end = vaddr + region->size; | ||
989 | if (io_remap_pfn_range(&vma, vaddr, region->paddr >> PAGE_SHIFT, | ||
990 | region->size, pgprot) < 0) { | ||
991 | dev_err(dispc.fbdev->dev, "kernel mmap for FBMEM failed\n"); | ||
992 | return -EAGAIN; | ||
993 | } | ||
994 | region->vaddr = (void *)vaddr; | ||
995 | |||
996 | return 0; | ||
997 | } | ||
998 | |||
999 | static void mmap_user_open(struct vm_area_struct *vma) | ||
1000 | { | ||
1001 | int plane = (int)vma->vm_private_data; | ||
1002 | |||
1003 | atomic_inc(&dispc.map_count[plane]); | ||
1004 | } | ||
1005 | |||
1006 | static void mmap_user_close(struct vm_area_struct *vma) | ||
1007 | { | ||
1008 | int plane = (int)vma->vm_private_data; | ||
1009 | |||
1010 | atomic_dec(&dispc.map_count[plane]); | ||
1011 | } | ||
1012 | |||
1013 | static struct vm_operations_struct mmap_user_ops = { | ||
1014 | .open = mmap_user_open, | ||
1015 | .close = mmap_user_close, | ||
1016 | }; | ||
1017 | |||
1018 | static int omap_dispc_mmap_user(struct fb_info *info, | ||
1019 | struct vm_area_struct *vma) | ||
1020 | { | ||
1021 | struct omapfb_plane_struct *plane = info->par; | ||
1022 | unsigned long off; | ||
1023 | unsigned long start; | ||
1024 | u32 len; | ||
1025 | |||
1026 | if (vma->vm_end - vma->vm_start == 0) | ||
1027 | return 0; | ||
1028 | if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) | ||
1029 | return -EINVAL; | ||
1030 | off = vma->vm_pgoff << PAGE_SHIFT; | ||
1031 | |||
1032 | start = info->fix.smem_start; | ||
1033 | len = info->fix.smem_len; | ||
1034 | if (off >= len) | ||
1035 | return -EINVAL; | ||
1036 | if ((vma->vm_end - vma->vm_start + off) > len) | ||
1037 | return -EINVAL; | ||
1038 | off += start; | ||
1039 | vma->vm_pgoff = off >> PAGE_SHIFT; | ||
1040 | vma->vm_flags |= VM_IO | VM_RESERVED; | ||
1041 | vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); | ||
1042 | vma->vm_ops = &mmap_user_ops; | ||
1043 | vma->vm_private_data = (void *)plane->idx; | ||
1044 | if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, | ||
1045 | vma->vm_end - vma->vm_start, vma->vm_page_prot)) | ||
1046 | return -EAGAIN; | ||
1047 | /* vm_ops.open won't be called for mmap itself. */ | ||
1048 | atomic_inc(&dispc.map_count[plane->idx]); | ||
1049 | return 0; | ||
1050 | } | ||
1051 | |||
1052 | static void unmap_kern(struct omapfb_mem_region *region) | ||
1053 | { | ||
1054 | vunmap(region->vaddr); | ||
1055 | } | ||
1056 | |||
1057 | static int alloc_palette_ram(void) | ||
1058 | { | ||
1059 | dispc.palette_vaddr = dma_alloc_writecombine(dispc.fbdev->dev, | ||
1060 | MAX_PALETTE_SIZE, &dispc.palette_paddr, GFP_KERNEL); | ||
1061 | if (dispc.palette_vaddr == NULL) { | ||
1062 | dev_err(dispc.fbdev->dev, "failed to alloc palette memory\n"); | ||
1063 | return -ENOMEM; | ||
1064 | } | ||
1065 | |||
1066 | return 0; | ||
1067 | } | ||
1068 | |||
1069 | static void free_palette_ram(void) | ||
1070 | { | ||
1071 | dma_free_writecombine(dispc.fbdev->dev, MAX_PALETTE_SIZE, | ||
1072 | dispc.palette_vaddr, dispc.palette_paddr); | ||
1073 | } | ||
1074 | |||
1075 | static int alloc_fbmem(struct omapfb_mem_region *region) | ||
1076 | { | ||
1077 | region->vaddr = dma_alloc_writecombine(dispc.fbdev->dev, | ||
1078 | region->size, ®ion->paddr, GFP_KERNEL); | ||
1079 | |||
1080 | if (region->vaddr == NULL) { | ||
1081 | dev_err(dispc.fbdev->dev, "unable to allocate FB DMA memory\n"); | ||
1082 | return -ENOMEM; | ||
1083 | } | ||
1084 | |||
1085 | return 0; | ||
1086 | } | ||
1087 | |||
1088 | static void free_fbmem(struct omapfb_mem_region *region) | ||
1089 | { | ||
1090 | dma_free_writecombine(dispc.fbdev->dev, region->size, | ||
1091 | region->vaddr, region->paddr); | ||
1092 | } | ||
1093 | |||
1094 | static struct resmap *init_resmap(unsigned long start, size_t size) | ||
1095 | { | ||
1096 | unsigned page_cnt; | ||
1097 | struct resmap *res_map; | ||
1098 | |||
1099 | page_cnt = PAGE_ALIGN(size) / PAGE_SIZE; | ||
1100 | res_map = | ||
1101 | kzalloc(sizeof(struct resmap) + RESMAP_SIZE(page_cnt), GFP_KERNEL); | ||
1102 | if (res_map == NULL) | ||
1103 | return NULL; | ||
1104 | res_map->start = start; | ||
1105 | res_map->page_cnt = page_cnt; | ||
1106 | res_map->map = (unsigned long *)(res_map + 1); | ||
1107 | return res_map; | ||
1108 | } | ||
1109 | |||
1110 | static void cleanup_resmap(struct resmap *res_map) | ||
1111 | { | ||
1112 | kfree(res_map); | ||
1113 | } | ||
1114 | |||
1115 | static inline int resmap_mem_type(unsigned long start) | ||
1116 | { | ||
1117 | if (start >= OMAP2_SRAM_START && | ||
1118 | start < OMAP2_SRAM_START + OMAP2_SRAM_SIZE) | ||
1119 | return OMAPFB_MEMTYPE_SRAM; | ||
1120 | else | ||
1121 | return OMAPFB_MEMTYPE_SDRAM; | ||
1122 | } | ||
1123 | |||
1124 | static inline int resmap_page_reserved(struct resmap *res_map, unsigned page_nr) | ||
1125 | { | ||
1126 | return *RESMAP_PTR(res_map, page_nr) & RESMAP_MASK(page_nr) ? 1 : 0; | ||
1127 | } | ||
1128 | |||
1129 | static inline void resmap_reserve_page(struct resmap *res_map, unsigned page_nr) | ||
1130 | { | ||
1131 | BUG_ON(resmap_page_reserved(res_map, page_nr)); | ||
1132 | *RESMAP_PTR(res_map, page_nr) |= RESMAP_MASK(page_nr); | ||
1133 | } | ||
1134 | |||
1135 | static inline void resmap_free_page(struct resmap *res_map, unsigned page_nr) | ||
1136 | { | ||
1137 | BUG_ON(!resmap_page_reserved(res_map, page_nr)); | ||
1138 | *RESMAP_PTR(res_map, page_nr) &= ~RESMAP_MASK(page_nr); | ||
1139 | } | ||
1140 | |||
1141 | static void resmap_reserve_region(unsigned long start, size_t size) | ||
1142 | { | ||
1143 | |||
1144 | struct resmap *res_map; | ||
1145 | unsigned start_page; | ||
1146 | unsigned end_page; | ||
1147 | int mtype; | ||
1148 | unsigned i; | ||
1149 | |||
1150 | mtype = resmap_mem_type(start); | ||
1151 | res_map = dispc.res_map[mtype]; | ||
1152 | dev_dbg(dispc.fbdev->dev, "reserve mem type %d start %08lx size %d\n", | ||
1153 | mtype, start, size); | ||
1154 | start_page = (start - res_map->start) / PAGE_SIZE; | ||
1155 | end_page = start_page + PAGE_ALIGN(size) / PAGE_SIZE; | ||
1156 | for (i = start_page; i < end_page; i++) | ||
1157 | resmap_reserve_page(res_map, i); | ||
1158 | } | ||
1159 | |||
1160 | static void resmap_free_region(unsigned long start, size_t size) | ||
1161 | { | ||
1162 | struct resmap *res_map; | ||
1163 | unsigned start_page; | ||
1164 | unsigned end_page; | ||
1165 | unsigned i; | ||
1166 | int mtype; | ||
1167 | |||
1168 | mtype = resmap_mem_type(start); | ||
1169 | res_map = dispc.res_map[mtype]; | ||
1170 | dev_dbg(dispc.fbdev->dev, "free mem type %d start %08lx size %d\n", | ||
1171 | mtype, start, size); | ||
1172 | start_page = (start - res_map->start) / PAGE_SIZE; | ||
1173 | end_page = start_page + PAGE_ALIGN(size) / PAGE_SIZE; | ||
1174 | for (i = start_page; i < end_page; i++) | ||
1175 | resmap_free_page(res_map, i); | ||
1176 | } | ||
1177 | |||
1178 | static unsigned long resmap_alloc_region(int mtype, size_t size) | ||
1179 | { | ||
1180 | unsigned i; | ||
1181 | unsigned total; | ||
1182 | unsigned start_page; | ||
1183 | unsigned long start; | ||
1184 | struct resmap *res_map = dispc.res_map[mtype]; | ||
1185 | |||
1186 | BUG_ON(mtype >= DISPC_MEMTYPE_NUM || res_map == NULL || !size); | ||
1187 | |||
1188 | size = PAGE_ALIGN(size) / PAGE_SIZE; | ||
1189 | start_page = 0; | ||
1190 | total = 0; | ||
1191 | for (i = 0; i < res_map->page_cnt; i++) { | ||
1192 | if (resmap_page_reserved(res_map, i)) { | ||
1193 | start_page = i + 1; | ||
1194 | total = 0; | ||
1195 | } else if (++total == size) | ||
1196 | break; | ||
1197 | } | ||
1198 | if (total < size) | ||
1199 | return 0; | ||
1200 | |||
1201 | start = res_map->start + start_page * PAGE_SIZE; | ||
1202 | resmap_reserve_region(start, size * PAGE_SIZE); | ||
1203 | |||
1204 | return start; | ||
1205 | } | ||
1206 | |||
1207 | /* Note that this will only work for user mappings, we don't deal with | ||
1208 | * kernel mappings here, so fbcon will keep using the old region. | ||
1209 | */ | ||
1210 | static int omap_dispc_setup_mem(int plane, size_t size, int mem_type, | ||
1211 | unsigned long *paddr) | ||
1212 | { | ||
1213 | struct omapfb_mem_region *rg; | ||
1214 | unsigned long new_addr = 0; | ||
1215 | |||
1216 | if ((unsigned)plane > dispc.mem_desc.region_cnt) | ||
1217 | return -EINVAL; | ||
1218 | if (mem_type >= DISPC_MEMTYPE_NUM) | ||
1219 | return -EINVAL; | ||
1220 | if (dispc.res_map[mem_type] == NULL) | ||
1221 | return -ENOMEM; | ||
1222 | rg = &dispc.mem_desc.region[plane]; | ||
1223 | if (size == rg->size && mem_type == rg->type) | ||
1224 | return 0; | ||
1225 | if (atomic_read(&dispc.map_count[plane])) | ||
1226 | return -EBUSY; | ||
1227 | if (rg->size != 0) | ||
1228 | resmap_free_region(rg->paddr, rg->size); | ||
1229 | if (size != 0) { | ||
1230 | new_addr = resmap_alloc_region(mem_type, size); | ||
1231 | if (!new_addr) { | ||
1232 | /* Reallocate old region. */ | ||
1233 | resmap_reserve_region(rg->paddr, rg->size); | ||
1234 | return -ENOMEM; | ||
1235 | } | ||
1236 | } | ||
1237 | rg->paddr = new_addr; | ||
1238 | rg->size = size; | ||
1239 | rg->type = mem_type; | ||
1240 | |||
1241 | *paddr = new_addr; | ||
1242 | |||
1243 | return 0; | ||
1244 | } | ||
1245 | |||
1246 | static int setup_fbmem(struct omapfb_mem_desc *req_md) | ||
1247 | { | ||
1248 | struct omapfb_mem_region *rg; | ||
1249 | int i; | ||
1250 | int r; | ||
1251 | unsigned long mem_start[DISPC_MEMTYPE_NUM]; | ||
1252 | unsigned long mem_end[DISPC_MEMTYPE_NUM]; | ||
1253 | |||
1254 | if (!req_md->region_cnt) { | ||
1255 | dev_err(dispc.fbdev->dev, "no memory regions defined\n"); | ||
1256 | return -ENOENT; | ||
1257 | } | ||
1258 | |||
1259 | rg = &req_md->region[0]; | ||
1260 | memset(mem_start, 0xff, sizeof(mem_start)); | ||
1261 | memset(mem_end, 0, sizeof(mem_end)); | ||
1262 | |||
1263 | for (i = 0; i < req_md->region_cnt; i++, rg++) { | ||
1264 | int mtype; | ||
1265 | if (rg->paddr) { | ||
1266 | rg->alloc = 0; | ||
1267 | if (rg->vaddr == NULL) { | ||
1268 | rg->map = 1; | ||
1269 | if ((r = mmap_kern(rg)) < 0) | ||
1270 | return r; | ||
1271 | } | ||
1272 | } else { | ||
1273 | if (rg->type != OMAPFB_MEMTYPE_SDRAM) { | ||
1274 | dev_err(dispc.fbdev->dev, | ||
1275 | "unsupported memory type\n"); | ||
1276 | return -EINVAL; | ||
1277 | } | ||
1278 | rg->alloc = rg->map = 1; | ||
1279 | if ((r = alloc_fbmem(rg)) < 0) | ||
1280 | return r; | ||
1281 | } | ||
1282 | mtype = rg->type; | ||
1283 | |||
1284 | if (rg->paddr < mem_start[mtype]) | ||
1285 | mem_start[mtype] = rg->paddr; | ||
1286 | if (rg->paddr + rg->size > mem_end[mtype]) | ||
1287 | mem_end[mtype] = rg->paddr + rg->size; | ||
1288 | } | ||
1289 | |||
1290 | for (i = 0; i < DISPC_MEMTYPE_NUM; i++) { | ||
1291 | unsigned long start; | ||
1292 | size_t size; | ||
1293 | if (mem_end[i] == 0) | ||
1294 | continue; | ||
1295 | start = mem_start[i]; | ||
1296 | size = mem_end[i] - start; | ||
1297 | dispc.res_map[i] = init_resmap(start, size); | ||
1298 | r = -ENOMEM; | ||
1299 | if (dispc.res_map[i] == NULL) | ||
1300 | goto fail; | ||
1301 | /* Initial state is that everything is reserved. This | ||
1302 | * includes possible holes as well, which will never be | ||
1303 | * freed. | ||
1304 | */ | ||
1305 | resmap_reserve_region(start, size); | ||
1306 | } | ||
1307 | |||
1308 | dispc.mem_desc = *req_md; | ||
1309 | |||
1310 | return 0; | ||
1311 | fail: | ||
1312 | for (i = 0; i < DISPC_MEMTYPE_NUM; i++) { | ||
1313 | if (dispc.res_map[i] != NULL) | ||
1314 | cleanup_resmap(dispc.res_map[i]); | ||
1315 | } | ||
1316 | return r; | ||
1317 | } | ||
1318 | |||
1319 | static void cleanup_fbmem(void) | ||
1320 | { | ||
1321 | struct omapfb_mem_region *rg; | ||
1322 | int i; | ||
1323 | |||
1324 | for (i = 0; i < DISPC_MEMTYPE_NUM; i++) { | ||
1325 | if (dispc.res_map[i] != NULL) | ||
1326 | cleanup_resmap(dispc.res_map[i]); | ||
1327 | } | ||
1328 | rg = &dispc.mem_desc.region[0]; | ||
1329 | for (i = 0; i < dispc.mem_desc.region_cnt; i++, rg++) { | ||
1330 | if (rg->alloc) | ||
1331 | free_fbmem(rg); | ||
1332 | else { | ||
1333 | if (rg->map) | ||
1334 | unmap_kern(rg); | ||
1335 | } | ||
1336 | } | ||
1337 | } | ||
1338 | |||
1339 | static int omap_dispc_init(struct omapfb_device *fbdev, int ext_mode, | ||
1340 | struct omapfb_mem_desc *req_vram) | ||
1341 | { | ||
1342 | int r; | ||
1343 | u32 l; | ||
1344 | struct lcd_panel *panel = fbdev->panel; | ||
1345 | int tmo = 10000; | ||
1346 | int skip_init = 0; | ||
1347 | int i; | ||
1348 | |||
1349 | memset(&dispc, 0, sizeof(dispc)); | ||
1350 | |||
1351 | dispc.base = io_p2v(DISPC_BASE); | ||
1352 | dispc.fbdev = fbdev; | ||
1353 | dispc.ext_mode = ext_mode; | ||
1354 | |||
1355 | init_completion(&dispc.frame_done); | ||
1356 | |||
1357 | if ((r = get_dss_clocks()) < 0) | ||
1358 | return r; | ||
1359 | |||
1360 | enable_interface_clocks(1); | ||
1361 | enable_lcd_clocks(1); | ||
1362 | |||
1363 | #ifdef CONFIG_FB_OMAP_BOOTLOADER_INIT | ||
1364 | l = dispc_read_reg(DISPC_CONTROL); | ||
1365 | /* LCD enabled ? */ | ||
1366 | if (l & 1) { | ||
1367 | pr_info("omapfb: skipping hardware initialization\n"); | ||
1368 | skip_init = 1; | ||
1369 | } | ||
1370 | #endif | ||
1371 | |||
1372 | if (!skip_init) { | ||
1373 | /* Reset monitoring works only w/ the 54M clk */ | ||
1374 | enable_digit_clocks(1); | ||
1375 | |||
1376 | /* Soft reset */ | ||
1377 | MOD_REG_FLD(DISPC_SYSCONFIG, 1 << 1, 1 << 1); | ||
1378 | |||
1379 | while (!(dispc_read_reg(DISPC_SYSSTATUS) & 1)) { | ||
1380 | if (!--tmo) { | ||
1381 | dev_err(dispc.fbdev->dev, "soft reset failed\n"); | ||
1382 | r = -ENODEV; | ||
1383 | enable_digit_clocks(0); | ||
1384 | goto fail1; | ||
1385 | } | ||
1386 | } | ||
1387 | |||
1388 | enable_digit_clocks(0); | ||
1389 | } | ||
1390 | |||
1391 | /* Enable smart idle and autoidle */ | ||
1392 | l = dispc_read_reg(DISPC_CONTROL); | ||
1393 | l &= ~((3 << 12) | (3 << 3)); | ||
1394 | l |= (2 << 12) | (2 << 3) | (1 << 0); | ||
1395 | dispc_write_reg(DISPC_SYSCONFIG, l); | ||
1396 | omap_writel(1 << 0, DSS_BASE + DSS_SYSCONFIG); | ||
1397 | |||
1398 | /* Set functional clock autogating */ | ||
1399 | l = dispc_read_reg(DISPC_CONFIG); | ||
1400 | l |= 1 << 9; | ||
1401 | dispc_write_reg(DISPC_CONFIG, l); | ||
1402 | |||
1403 | l = dispc_read_reg(DISPC_IRQSTATUS); | ||
1404 | dispc_write_reg(l, DISPC_IRQSTATUS); | ||
1405 | |||
1406 | /* Enable those that we handle always */ | ||
1407 | omap_dispc_enable_irqs(DISPC_IRQ_FRAMEMASK); | ||
1408 | |||
1409 | if ((r = request_irq(INT_24XX_DSS_IRQ, omap_dispc_irq_handler, | ||
1410 | 0, MODULE_NAME, fbdev)) < 0) { | ||
1411 | dev_err(dispc.fbdev->dev, "can't get DSS IRQ\n"); | ||
1412 | goto fail1; | ||
1413 | } | ||
1414 | |||
1415 | /* L3 firewall setting: enable access to OCM RAM */ | ||
1416 | __raw_writel(0x402000b0, io_p2v(0x680050a0)); | ||
1417 | |||
1418 | if ((r = alloc_palette_ram()) < 0) | ||
1419 | goto fail2; | ||
1420 | |||
1421 | if ((r = setup_fbmem(req_vram)) < 0) | ||
1422 | goto fail3; | ||
1423 | |||
1424 | if (!skip_init) { | ||
1425 | for (i = 0; i < dispc.mem_desc.region_cnt; i++) { | ||
1426 | memset(dispc.mem_desc.region[i].vaddr, 0, | ||
1427 | dispc.mem_desc.region[i].size); | ||
1428 | } | ||
1429 | |||
1430 | /* Set logic clock to fck, pixel clock to fck/2 for now */ | ||
1431 | MOD_REG_FLD(DISPC_DIVISOR, FLD_MASK(16, 8), 1 << 16); | ||
1432 | MOD_REG_FLD(DISPC_DIVISOR, FLD_MASK(0, 8), 2 << 0); | ||
1433 | |||
1434 | setup_plane_fifo(0, ext_mode); | ||
1435 | setup_plane_fifo(1, ext_mode); | ||
1436 | setup_plane_fifo(2, ext_mode); | ||
1437 | |||
1438 | setup_color_conv_coef(); | ||
1439 | |||
1440 | set_lcd_tft_mode(panel->config & OMAP_LCDC_PANEL_TFT); | ||
1441 | set_load_mode(DISPC_LOAD_FRAME_ONLY); | ||
1442 | |||
1443 | if (!ext_mode) { | ||
1444 | set_lcd_data_lines(panel->data_lines); | ||
1445 | omap_dispc_set_lcd_size(panel->x_res, panel->y_res); | ||
1446 | set_lcd_timings(); | ||
1447 | } else | ||
1448 | set_lcd_data_lines(panel->bpp); | ||
1449 | enable_rfbi_mode(ext_mode); | ||
1450 | } | ||
1451 | |||
1452 | l = dispc_read_reg(DISPC_REVISION); | ||
1453 | pr_info("omapfb: DISPC version %d.%d initialized\n", | ||
1454 | l >> 4 & 0x0f, l & 0x0f); | ||
1455 | enable_lcd_clocks(0); | ||
1456 | |||
1457 | return 0; | ||
1458 | fail3: | ||
1459 | free_palette_ram(); | ||
1460 | fail2: | ||
1461 | free_irq(INT_24XX_DSS_IRQ, fbdev); | ||
1462 | fail1: | ||
1463 | enable_lcd_clocks(0); | ||
1464 | enable_interface_clocks(0); | ||
1465 | put_dss_clocks(); | ||
1466 | |||
1467 | return r; | ||
1468 | } | ||
1469 | |||
1470 | static void omap_dispc_cleanup(void) | ||
1471 | { | ||
1472 | int i; | ||
1473 | |||
1474 | omap_dispc_set_update_mode(OMAPFB_UPDATE_DISABLED); | ||
1475 | /* This will also disable clocks that are on */ | ||
1476 | for (i = 0; i < dispc.mem_desc.region_cnt; i++) | ||
1477 | omap_dispc_enable_plane(i, 0); | ||
1478 | cleanup_fbmem(); | ||
1479 | free_palette_ram(); | ||
1480 | free_irq(INT_24XX_DSS_IRQ, dispc.fbdev); | ||
1481 | enable_interface_clocks(0); | ||
1482 | put_dss_clocks(); | ||
1483 | } | ||
1484 | |||
1485 | const struct lcd_ctrl omap2_int_ctrl = { | ||
1486 | .name = "internal", | ||
1487 | .init = omap_dispc_init, | ||
1488 | .cleanup = omap_dispc_cleanup, | ||
1489 | .get_caps = omap_dispc_get_caps, | ||
1490 | .set_update_mode = omap_dispc_set_update_mode, | ||
1491 | .get_update_mode = omap_dispc_get_update_mode, | ||
1492 | .update_window = omap_dispc_update_window, | ||
1493 | .suspend = omap_dispc_suspend, | ||
1494 | .resume = omap_dispc_resume, | ||
1495 | .setup_plane = omap_dispc_setup_plane, | ||
1496 | .setup_mem = omap_dispc_setup_mem, | ||
1497 | .set_scale = omap_dispc_set_scale, | ||
1498 | .enable_plane = omap_dispc_enable_plane, | ||
1499 | .set_color_key = omap_dispc_set_color_key, | ||
1500 | .get_color_key = omap_dispc_get_color_key, | ||
1501 | .mmap = omap_dispc_mmap_user, | ||
1502 | }; | ||
diff --git a/drivers/video/omap/dispc.h b/drivers/video/omap/dispc.h new file mode 100644 index 000000000000..eb1512b56ce8 --- /dev/null +++ b/drivers/video/omap/dispc.h | |||
@@ -0,0 +1,43 @@ | |||
1 | #ifndef _DISPC_H | ||
2 | #define _DISPC_H | ||
3 | |||
4 | #include <linux/interrupt.h> | ||
5 | |||
6 | #define DISPC_PLANE_GFX 0 | ||
7 | #define DISPC_PLANE_VID1 1 | ||
8 | #define DISPC_PLANE_VID2 2 | ||
9 | |||
10 | #define DISPC_RGB_1_BPP 0x00 | ||
11 | #define DISPC_RGB_2_BPP 0x01 | ||
12 | #define DISPC_RGB_4_BPP 0x02 | ||
13 | #define DISPC_RGB_8_BPP 0x03 | ||
14 | #define DISPC_RGB_12_BPP 0x04 | ||
15 | #define DISPC_RGB_16_BPP 0x06 | ||
16 | #define DISPC_RGB_24_BPP 0x08 | ||
17 | #define DISPC_RGB_24_BPP_UNPACK_32 0x09 | ||
18 | #define DISPC_YUV2_422 0x0a | ||
19 | #define DISPC_UYVY_422 0x0b | ||
20 | |||
21 | #define DISPC_BURST_4x32 0 | ||
22 | #define DISPC_BURST_8x32 1 | ||
23 | #define DISPC_BURST_16x32 2 | ||
24 | |||
25 | #define DISPC_LOAD_CLUT_AND_FRAME 0x00 | ||
26 | #define DISPC_LOAD_CLUT_ONLY 0x01 | ||
27 | #define DISPC_LOAD_FRAME_ONLY 0x02 | ||
28 | #define DISPC_LOAD_CLUT_ONCE_FRAME 0x03 | ||
29 | |||
30 | #define DISPC_TFT_DATA_LINES_12 0 | ||
31 | #define DISPC_TFT_DATA_LINES_16 1 | ||
32 | #define DISPC_TFT_DATA_LINES_18 2 | ||
33 | #define DISPC_TFT_DATA_LINES_24 3 | ||
34 | |||
35 | extern void omap_dispc_set_lcd_size(int width, int height); | ||
36 | |||
37 | extern void omap_dispc_enable_lcd_out(int enable); | ||
38 | extern void omap_dispc_enable_digit_out(int enable); | ||
39 | |||
40 | extern int omap_dispc_request_irq(void (*callback)(void *data), void *data); | ||
41 | extern void omap_dispc_free_irq(void); | ||
42 | |||
43 | #endif | ||
diff --git a/drivers/video/omap/hwa742.c b/drivers/video/omap/hwa742.c new file mode 100644 index 000000000000..dc48e02f215c --- /dev/null +++ b/drivers/video/omap/hwa742.c | |||
@@ -0,0 +1,1077 @@ | |||
1 | /* | ||
2 | * Epson HWA742 LCD controller driver | ||
3 | * | ||
4 | * Copyright (C) 2004-2005 Nokia Corporation | ||
5 | * Authors: Juha Yrjölä <juha.yrjola@nokia.com> | ||
6 | * Imre Deak <imre.deak@nokia.com> | ||
7 | * YUV support: Jussi Laako <jussi.laako@nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License as published by the | ||
11 | * Free Software Foundation; either version 2 of the License, or (at your | ||
12 | * option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License along | ||
20 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
21 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
22 | */ | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/mm.h> | ||
25 | #include <linux/fb.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <linux/clk.h> | ||
28 | |||
29 | #include <asm/arch/dma.h> | ||
30 | #include <asm/arch/omapfb.h> | ||
31 | #include <asm/arch/hwa742.h> | ||
32 | |||
33 | #define HWA742_REV_CODE_REG 0x0 | ||
34 | #define HWA742_CONFIG_REG 0x2 | ||
35 | #define HWA742_PLL_DIV_REG 0x4 | ||
36 | #define HWA742_PLL_0_REG 0x6 | ||
37 | #define HWA742_PLL_1_REG 0x8 | ||
38 | #define HWA742_PLL_2_REG 0xa | ||
39 | #define HWA742_PLL_3_REG 0xc | ||
40 | #define HWA742_PLL_4_REG 0xe | ||
41 | #define HWA742_CLK_SRC_REG 0x12 | ||
42 | #define HWA742_PANEL_TYPE_REG 0x14 | ||
43 | #define HWA742_H_DISP_REG 0x16 | ||
44 | #define HWA742_H_NDP_REG 0x18 | ||
45 | #define HWA742_V_DISP_1_REG 0x1a | ||
46 | #define HWA742_V_DISP_2_REG 0x1c | ||
47 | #define HWA742_V_NDP_REG 0x1e | ||
48 | #define HWA742_HS_W_REG 0x20 | ||
49 | #define HWA742_HP_S_REG 0x22 | ||
50 | #define HWA742_VS_W_REG 0x24 | ||
51 | #define HWA742_VP_S_REG 0x26 | ||
52 | #define HWA742_PCLK_POL_REG 0x28 | ||
53 | #define HWA742_INPUT_MODE_REG 0x2a | ||
54 | #define HWA742_TRANSL_MODE_REG1 0x2e | ||
55 | #define HWA742_DISP_MODE_REG 0x34 | ||
56 | #define HWA742_WINDOW_TYPE 0x36 | ||
57 | #define HWA742_WINDOW_X_START_0 0x38 | ||
58 | #define HWA742_WINDOW_X_START_1 0x3a | ||
59 | #define HWA742_WINDOW_Y_START_0 0x3c | ||
60 | #define HWA742_WINDOW_Y_START_1 0x3e | ||
61 | #define HWA742_WINDOW_X_END_0 0x40 | ||
62 | #define HWA742_WINDOW_X_END_1 0x42 | ||
63 | #define HWA742_WINDOW_Y_END_0 0x44 | ||
64 | #define HWA742_WINDOW_Y_END_1 0x46 | ||
65 | #define HWA742_MEMORY_WRITE_LSB 0x48 | ||
66 | #define HWA742_MEMORY_WRITE_MSB 0x49 | ||
67 | #define HWA742_MEMORY_READ_0 0x4a | ||
68 | #define HWA742_MEMORY_READ_1 0x4c | ||
69 | #define HWA742_MEMORY_READ_2 0x4e | ||
70 | #define HWA742_POWER_SAVE 0x56 | ||
71 | #define HWA742_NDP_CTRL 0x58 | ||
72 | |||
73 | #define HWA742_AUTO_UPDATE_TIME (HZ / 20) | ||
74 | |||
75 | /* Reserve 4 request slots for requests in irq context */ | ||
76 | #define REQ_POOL_SIZE 24 | ||
77 | #define IRQ_REQ_POOL_SIZE 4 | ||
78 | |||
79 | #define REQ_FROM_IRQ_POOL 0x01 | ||
80 | |||
81 | #define REQ_COMPLETE 0 | ||
82 | #define REQ_PENDING 1 | ||
83 | |||
84 | struct update_param { | ||
85 | int x, y, width, height; | ||
86 | int color_mode; | ||
87 | int flags; | ||
88 | }; | ||
89 | |||
90 | struct hwa742_request { | ||
91 | struct list_head entry; | ||
92 | unsigned int flags; | ||
93 | |||
94 | int (*handler)(struct hwa742_request *req); | ||
95 | void (*complete)(void *data); | ||
96 | void *complete_data; | ||
97 | |||
98 | union { | ||
99 | struct update_param update; | ||
100 | struct completion *sync; | ||
101 | } par; | ||
102 | }; | ||
103 | |||
104 | struct { | ||
105 | enum omapfb_update_mode update_mode; | ||
106 | enum omapfb_update_mode update_mode_before_suspend; | ||
107 | |||
108 | struct timer_list auto_update_timer; | ||
109 | int stop_auto_update; | ||
110 | struct omapfb_update_window auto_update_window; | ||
111 | unsigned te_connected:1; | ||
112 | unsigned vsync_only:1; | ||
113 | |||
114 | struct hwa742_request req_pool[REQ_POOL_SIZE]; | ||
115 | struct list_head pending_req_list; | ||
116 | struct list_head free_req_list; | ||
117 | struct semaphore req_sema; | ||
118 | spinlock_t req_lock; | ||
119 | |||
120 | struct extif_timings reg_timings, lut_timings; | ||
121 | |||
122 | int prev_color_mode; | ||
123 | int prev_flags; | ||
124 | int window_type; | ||
125 | |||
126 | u32 max_transmit_size; | ||
127 | u32 extif_clk_period; | ||
128 | unsigned long pix_tx_time; | ||
129 | unsigned long line_upd_time; | ||
130 | |||
131 | |||
132 | struct omapfb_device *fbdev; | ||
133 | struct lcd_ctrl_extif *extif; | ||
134 | struct lcd_ctrl *int_ctrl; | ||
135 | |||
136 | void (*power_up)(struct device *dev); | ||
137 | void (*power_down)(struct device *dev); | ||
138 | } hwa742; | ||
139 | |||
140 | struct lcd_ctrl hwa742_ctrl; | ||
141 | |||
142 | static u8 hwa742_read_reg(u8 reg) | ||
143 | { | ||
144 | u8 data; | ||
145 | |||
146 | hwa742.extif->set_bits_per_cycle(8); | ||
147 | hwa742.extif->write_command(®, 1); | ||
148 | hwa742.extif->read_data(&data, 1); | ||
149 | |||
150 | return data; | ||
151 | } | ||
152 | |||
153 | static void hwa742_write_reg(u8 reg, u8 data) | ||
154 | { | ||
155 | hwa742.extif->set_bits_per_cycle(8); | ||
156 | hwa742.extif->write_command(®, 1); | ||
157 | hwa742.extif->write_data(&data, 1); | ||
158 | } | ||
159 | |||
160 | static void set_window_regs(int x_start, int y_start, int x_end, int y_end) | ||
161 | { | ||
162 | u8 tmp[8]; | ||
163 | u8 cmd; | ||
164 | |||
165 | x_end--; | ||
166 | y_end--; | ||
167 | tmp[0] = x_start; | ||
168 | tmp[1] = x_start >> 8; | ||
169 | tmp[2] = y_start; | ||
170 | tmp[3] = y_start >> 8; | ||
171 | tmp[4] = x_end; | ||
172 | tmp[5] = x_end >> 8; | ||
173 | tmp[6] = y_end; | ||
174 | tmp[7] = y_end >> 8; | ||
175 | |||
176 | hwa742.extif->set_bits_per_cycle(8); | ||
177 | cmd = HWA742_WINDOW_X_START_0; | ||
178 | |||
179 | hwa742.extif->write_command(&cmd, 1); | ||
180 | |||
181 | hwa742.extif->write_data(tmp, 8); | ||
182 | } | ||
183 | |||
184 | static void set_format_regs(int conv, int transl, int flags) | ||
185 | { | ||
186 | if (flags & OMAPFB_FORMAT_FLAG_DOUBLE) { | ||
187 | hwa742.window_type = ((hwa742.window_type & 0xfc) | 0x01); | ||
188 | #ifdef VERBOSE | ||
189 | dev_dbg(hwa742.fbdev->dev, "hwa742: enabled pixel doubling\n"); | ||
190 | #endif | ||
191 | } else { | ||
192 | hwa742.window_type = (hwa742.window_type & 0xfc); | ||
193 | #ifdef VERBOSE | ||
194 | dev_dbg(hwa742.fbdev->dev, "hwa742: disabled pixel doubling\n"); | ||
195 | #endif | ||
196 | } | ||
197 | |||
198 | hwa742_write_reg(HWA742_INPUT_MODE_REG, conv); | ||
199 | hwa742_write_reg(HWA742_TRANSL_MODE_REG1, transl); | ||
200 | hwa742_write_reg(HWA742_WINDOW_TYPE, hwa742.window_type); | ||
201 | } | ||
202 | |||
203 | static void enable_tearsync(int y, int width, int height, int screen_height, | ||
204 | int force_vsync) | ||
205 | { | ||
206 | u8 b; | ||
207 | |||
208 | b = hwa742_read_reg(HWA742_NDP_CTRL); | ||
209 | b |= 1 << 2; | ||
210 | hwa742_write_reg(HWA742_NDP_CTRL, b); | ||
211 | |||
212 | if (likely(hwa742.vsync_only || force_vsync)) { | ||
213 | hwa742.extif->enable_tearsync(1, 0); | ||
214 | return; | ||
215 | } | ||
216 | |||
217 | if (width * hwa742.pix_tx_time < hwa742.line_upd_time) { | ||
218 | hwa742.extif->enable_tearsync(1, 0); | ||
219 | return; | ||
220 | } | ||
221 | |||
222 | if ((width * hwa742.pix_tx_time / 1000) * height < | ||
223 | (y + height) * (hwa742.line_upd_time / 1000)) { | ||
224 | hwa742.extif->enable_tearsync(1, 0); | ||
225 | return; | ||
226 | } | ||
227 | |||
228 | hwa742.extif->enable_tearsync(1, y + 1); | ||
229 | } | ||
230 | |||
231 | static void disable_tearsync(void) | ||
232 | { | ||
233 | u8 b; | ||
234 | |||
235 | hwa742.extif->enable_tearsync(0, 0); | ||
236 | |||
237 | b = hwa742_read_reg(HWA742_NDP_CTRL); | ||
238 | b &= ~(1 << 2); | ||
239 | hwa742_write_reg(HWA742_NDP_CTRL, b); | ||
240 | } | ||
241 | |||
242 | static inline struct hwa742_request *alloc_req(void) | ||
243 | { | ||
244 | unsigned long flags; | ||
245 | struct hwa742_request *req; | ||
246 | int req_flags = 0; | ||
247 | |||
248 | if (!in_interrupt()) | ||
249 | down(&hwa742.req_sema); | ||
250 | else | ||
251 | req_flags = REQ_FROM_IRQ_POOL; | ||
252 | |||
253 | spin_lock_irqsave(&hwa742.req_lock, flags); | ||
254 | BUG_ON(list_empty(&hwa742.free_req_list)); | ||
255 | req = list_entry(hwa742.free_req_list.next, | ||
256 | struct hwa742_request, entry); | ||
257 | list_del(&req->entry); | ||
258 | spin_unlock_irqrestore(&hwa742.req_lock, flags); | ||
259 | |||
260 | INIT_LIST_HEAD(&req->entry); | ||
261 | req->flags = req_flags; | ||
262 | |||
263 | return req; | ||
264 | } | ||
265 | |||
266 | static inline void free_req(struct hwa742_request *req) | ||
267 | { | ||
268 | unsigned long flags; | ||
269 | |||
270 | spin_lock_irqsave(&hwa742.req_lock, flags); | ||
271 | |||
272 | list_del(&req->entry); | ||
273 | list_add(&req->entry, &hwa742.free_req_list); | ||
274 | if (!(req->flags & REQ_FROM_IRQ_POOL)) | ||
275 | up(&hwa742.req_sema); | ||
276 | |||
277 | spin_unlock_irqrestore(&hwa742.req_lock, flags); | ||
278 | } | ||
279 | |||
280 | static void process_pending_requests(void) | ||
281 | { | ||
282 | unsigned long flags; | ||
283 | |||
284 | spin_lock_irqsave(&hwa742.req_lock, flags); | ||
285 | |||
286 | while (!list_empty(&hwa742.pending_req_list)) { | ||
287 | struct hwa742_request *req; | ||
288 | void (*complete)(void *); | ||
289 | void *complete_data; | ||
290 | |||
291 | req = list_entry(hwa742.pending_req_list.next, | ||
292 | struct hwa742_request, entry); | ||
293 | spin_unlock_irqrestore(&hwa742.req_lock, flags); | ||
294 | |||
295 | if (req->handler(req) == REQ_PENDING) | ||
296 | return; | ||
297 | |||
298 | complete = req->complete; | ||
299 | complete_data = req->complete_data; | ||
300 | free_req(req); | ||
301 | |||
302 | if (complete) | ||
303 | complete(complete_data); | ||
304 | |||
305 | spin_lock_irqsave(&hwa742.req_lock, flags); | ||
306 | } | ||
307 | |||
308 | spin_unlock_irqrestore(&hwa742.req_lock, flags); | ||
309 | } | ||
310 | |||
311 | static void submit_req_list(struct list_head *head) | ||
312 | { | ||
313 | unsigned long flags; | ||
314 | int process = 1; | ||
315 | |||
316 | spin_lock_irqsave(&hwa742.req_lock, flags); | ||
317 | if (likely(!list_empty(&hwa742.pending_req_list))) | ||
318 | process = 0; | ||
319 | list_splice_init(head, hwa742.pending_req_list.prev); | ||
320 | spin_unlock_irqrestore(&hwa742.req_lock, flags); | ||
321 | |||
322 | if (process) | ||
323 | process_pending_requests(); | ||
324 | } | ||
325 | |||
326 | static void request_complete(void *data) | ||
327 | { | ||
328 | struct hwa742_request *req = (struct hwa742_request *)data; | ||
329 | void (*complete)(void *); | ||
330 | void *complete_data; | ||
331 | |||
332 | complete = req->complete; | ||
333 | complete_data = req->complete_data; | ||
334 | |||
335 | free_req(req); | ||
336 | |||
337 | if (complete) | ||
338 | complete(complete_data); | ||
339 | |||
340 | process_pending_requests(); | ||
341 | } | ||
342 | |||
343 | static int send_frame_handler(struct hwa742_request *req) | ||
344 | { | ||
345 | struct update_param *par = &req->par.update; | ||
346 | int x = par->x; | ||
347 | int y = par->y; | ||
348 | int w = par->width; | ||
349 | int h = par->height; | ||
350 | int bpp; | ||
351 | int conv, transl; | ||
352 | unsigned long offset; | ||
353 | int color_mode = par->color_mode; | ||
354 | int flags = par->flags; | ||
355 | int scr_width = hwa742.fbdev->panel->x_res; | ||
356 | int scr_height = hwa742.fbdev->panel->y_res; | ||
357 | |||
358 | #ifdef VERBOSE | ||
359 | dev_dbg(hwa742.fbdev->dev, "x %d y %d w %d h %d scr_width %d " | ||
360 | "color_mode %d flags %d\n", | ||
361 | x, y, w, h, scr_width, color_mode, flags); | ||
362 | #endif | ||
363 | |||
364 | switch (color_mode) { | ||
365 | case OMAPFB_COLOR_YUV422: | ||
366 | bpp = 16; | ||
367 | conv = 0x08; | ||
368 | transl = 0x25; | ||
369 | break; | ||
370 | case OMAPFB_COLOR_YUV420: | ||
371 | bpp = 12; | ||
372 | conv = 0x09; | ||
373 | transl = 0x25; | ||
374 | break; | ||
375 | case OMAPFB_COLOR_RGB565: | ||
376 | bpp = 16; | ||
377 | conv = 0x01; | ||
378 | transl = 0x05; | ||
379 | break; | ||
380 | default: | ||
381 | return -EINVAL; | ||
382 | } | ||
383 | |||
384 | if (hwa742.prev_flags != flags || | ||
385 | hwa742.prev_color_mode != color_mode) { | ||
386 | set_format_regs(conv, transl, flags); | ||
387 | hwa742.prev_color_mode = color_mode; | ||
388 | hwa742.prev_flags = flags; | ||
389 | } | ||
390 | flags = req->par.update.flags; | ||
391 | if (flags & OMAPFB_FORMAT_FLAG_TEARSYNC) | ||
392 | enable_tearsync(y, scr_width, h, scr_height, | ||
393 | flags & OMAPFB_FORMAT_FLAG_FORCE_VSYNC); | ||
394 | else | ||
395 | disable_tearsync(); | ||
396 | |||
397 | set_window_regs(x, y, x + w, y + h); | ||
398 | |||
399 | offset = (scr_width * y + x) * bpp / 8; | ||
400 | |||
401 | hwa742.int_ctrl->setup_plane(OMAPFB_PLANE_GFX, | ||
402 | OMAPFB_CHANNEL_OUT_LCD, offset, scr_width, 0, 0, w, h, | ||
403 | color_mode); | ||
404 | |||
405 | hwa742.extif->set_bits_per_cycle(16); | ||
406 | |||
407 | hwa742.int_ctrl->enable_plane(OMAPFB_PLANE_GFX, 1); | ||
408 | hwa742.extif->transfer_area(w, h, request_complete, req); | ||
409 | |||
410 | return REQ_PENDING; | ||
411 | } | ||
412 | |||
413 | static void send_frame_complete(void *data) | ||
414 | { | ||
415 | hwa742.int_ctrl->enable_plane(OMAPFB_PLANE_GFX, 0); | ||
416 | } | ||
417 | |||
418 | #define ADD_PREQ(_x, _y, _w, _h) do { \ | ||
419 | req = alloc_req(); \ | ||
420 | req->handler = send_frame_handler; \ | ||
421 | req->complete = send_frame_complete; \ | ||
422 | req->par.update.x = _x; \ | ||
423 | req->par.update.y = _y; \ | ||
424 | req->par.update.width = _w; \ | ||
425 | req->par.update.height = _h; \ | ||
426 | req->par.update.color_mode = color_mode;\ | ||
427 | req->par.update.flags = flags; \ | ||
428 | list_add_tail(&req->entry, req_head); \ | ||
429 | } while(0) | ||
430 | |||
431 | static void create_req_list(struct omapfb_update_window *win, | ||
432 | struct list_head *req_head) | ||
433 | { | ||
434 | struct hwa742_request *req; | ||
435 | int x = win->x; | ||
436 | int y = win->y; | ||
437 | int width = win->width; | ||
438 | int height = win->height; | ||
439 | int color_mode; | ||
440 | int flags; | ||
441 | |||
442 | flags = win->format & ~OMAPFB_FORMAT_MASK; | ||
443 | color_mode = win->format & OMAPFB_FORMAT_MASK; | ||
444 | |||
445 | if (x & 1) { | ||
446 | ADD_PREQ(x, y, 1, height); | ||
447 | width--; | ||
448 | x++; | ||
449 | flags &= ~OMAPFB_FORMAT_FLAG_TEARSYNC; | ||
450 | } | ||
451 | if (width & ~1) { | ||
452 | unsigned int xspan = width & ~1; | ||
453 | unsigned int ystart = y; | ||
454 | unsigned int yspan = height; | ||
455 | |||
456 | if (xspan * height * 2 > hwa742.max_transmit_size) { | ||
457 | yspan = hwa742.max_transmit_size / (xspan * 2); | ||
458 | ADD_PREQ(x, ystart, xspan, yspan); | ||
459 | ystart += yspan; | ||
460 | yspan = height - yspan; | ||
461 | flags &= ~OMAPFB_FORMAT_FLAG_TEARSYNC; | ||
462 | } | ||
463 | |||
464 | ADD_PREQ(x, ystart, xspan, yspan); | ||
465 | x += xspan; | ||
466 | width -= xspan; | ||
467 | flags &= ~OMAPFB_FORMAT_FLAG_TEARSYNC; | ||
468 | } | ||
469 | if (width) | ||
470 | ADD_PREQ(x, y, 1, height); | ||
471 | } | ||
472 | |||
473 | static void auto_update_complete(void *data) | ||
474 | { | ||
475 | if (!hwa742.stop_auto_update) | ||
476 | mod_timer(&hwa742.auto_update_timer, | ||
477 | jiffies + HWA742_AUTO_UPDATE_TIME); | ||
478 | } | ||
479 | |||
480 | static void hwa742_update_window_auto(unsigned long arg) | ||
481 | { | ||
482 | LIST_HEAD(req_list); | ||
483 | struct hwa742_request *last; | ||
484 | |||
485 | create_req_list(&hwa742.auto_update_window, &req_list); | ||
486 | last = list_entry(req_list.prev, struct hwa742_request, entry); | ||
487 | |||
488 | last->complete = auto_update_complete; | ||
489 | last->complete_data = NULL; | ||
490 | |||
491 | submit_req_list(&req_list); | ||
492 | } | ||
493 | |||
494 | int hwa742_update_window_async(struct fb_info *fbi, | ||
495 | struct omapfb_update_window *win, | ||
496 | void (*complete_callback)(void *arg), | ||
497 | void *complete_callback_data) | ||
498 | { | ||
499 | LIST_HEAD(req_list); | ||
500 | struct hwa742_request *last; | ||
501 | int r = 0; | ||
502 | |||
503 | if (hwa742.update_mode != OMAPFB_MANUAL_UPDATE) { | ||
504 | dev_dbg(hwa742.fbdev->dev, "invalid update mode\n"); | ||
505 | r = -EINVAL; | ||
506 | goto out; | ||
507 | } | ||
508 | if (unlikely(win->format & | ||
509 | ~(0x03 | OMAPFB_FORMAT_FLAG_DOUBLE | | ||
510 | OMAPFB_FORMAT_FLAG_TEARSYNC | OMAPFB_FORMAT_FLAG_FORCE_VSYNC))) { | ||
511 | dev_dbg(hwa742.fbdev->dev, "invalid window flag"); | ||
512 | r = -EINVAL; | ||
513 | goto out; | ||
514 | } | ||
515 | |||
516 | create_req_list(win, &req_list); | ||
517 | last = list_entry(req_list.prev, struct hwa742_request, entry); | ||
518 | |||
519 | last->complete = complete_callback; | ||
520 | last->complete_data = (void *)complete_callback_data; | ||
521 | |||
522 | submit_req_list(&req_list); | ||
523 | |||
524 | out: | ||
525 | return r; | ||
526 | } | ||
527 | EXPORT_SYMBOL(hwa742_update_window_async); | ||
528 | |||
529 | static int hwa742_setup_plane(int plane, int channel_out, | ||
530 | unsigned long offset, int screen_width, | ||
531 | int pos_x, int pos_y, int width, int height, | ||
532 | int color_mode) | ||
533 | { | ||
534 | if (plane != OMAPFB_PLANE_GFX || | ||
535 | channel_out != OMAPFB_CHANNEL_OUT_LCD) | ||
536 | return -EINVAL; | ||
537 | |||
538 | return 0; | ||
539 | } | ||
540 | |||
541 | static int hwa742_enable_plane(int plane, int enable) | ||
542 | { | ||
543 | if (plane != 0) | ||
544 | return -EINVAL; | ||
545 | |||
546 | hwa742.int_ctrl->enable_plane(plane, enable); | ||
547 | |||
548 | return 0; | ||
549 | } | ||
550 | |||
551 | static int sync_handler(struct hwa742_request *req) | ||
552 | { | ||
553 | complete(req->par.sync); | ||
554 | return REQ_COMPLETE; | ||
555 | } | ||
556 | |||
557 | static void hwa742_sync(void) | ||
558 | { | ||
559 | LIST_HEAD(req_list); | ||
560 | struct hwa742_request *req; | ||
561 | struct completion comp; | ||
562 | |||
563 | req = alloc_req(); | ||
564 | |||
565 | req->handler = sync_handler; | ||
566 | req->complete = NULL; | ||
567 | init_completion(&comp); | ||
568 | req->par.sync = ∁ | ||
569 | |||
570 | list_add(&req->entry, &req_list); | ||
571 | submit_req_list(&req_list); | ||
572 | |||
573 | wait_for_completion(&comp); | ||
574 | } | ||
575 | |||
576 | static void hwa742_bind_client(struct omapfb_notifier_block *nb) | ||
577 | { | ||
578 | dev_dbg(hwa742.fbdev->dev, "update_mode %d\n", hwa742.update_mode); | ||
579 | if (hwa742.update_mode == OMAPFB_MANUAL_UPDATE) { | ||
580 | omapfb_notify_clients(hwa742.fbdev, OMAPFB_EVENT_READY); | ||
581 | } | ||
582 | } | ||
583 | |||
584 | static int hwa742_set_update_mode(enum omapfb_update_mode mode) | ||
585 | { | ||
586 | if (mode != OMAPFB_MANUAL_UPDATE && mode != OMAPFB_AUTO_UPDATE && | ||
587 | mode != OMAPFB_UPDATE_DISABLED) | ||
588 | return -EINVAL; | ||
589 | |||
590 | if (mode == hwa742.update_mode) | ||
591 | return 0; | ||
592 | |||
593 | dev_info(hwa742.fbdev->dev, "HWA742: setting update mode to %s\n", | ||
594 | mode == OMAPFB_UPDATE_DISABLED ? "disabled" : | ||
595 | (mode == OMAPFB_AUTO_UPDATE ? "auto" : "manual")); | ||
596 | |||
597 | switch (hwa742.update_mode) { | ||
598 | case OMAPFB_MANUAL_UPDATE: | ||
599 | omapfb_notify_clients(hwa742.fbdev, OMAPFB_EVENT_DISABLED); | ||
600 | break; | ||
601 | case OMAPFB_AUTO_UPDATE: | ||
602 | hwa742.stop_auto_update = 1; | ||
603 | del_timer_sync(&hwa742.auto_update_timer); | ||
604 | break; | ||
605 | case OMAPFB_UPDATE_DISABLED: | ||
606 | break; | ||
607 | } | ||
608 | |||
609 | hwa742.update_mode = mode; | ||
610 | hwa742_sync(); | ||
611 | hwa742.stop_auto_update = 0; | ||
612 | |||
613 | switch (mode) { | ||
614 | case OMAPFB_MANUAL_UPDATE: | ||
615 | omapfb_notify_clients(hwa742.fbdev, OMAPFB_EVENT_READY); | ||
616 | break; | ||
617 | case OMAPFB_AUTO_UPDATE: | ||
618 | hwa742_update_window_auto(0); | ||
619 | break; | ||
620 | case OMAPFB_UPDATE_DISABLED: | ||
621 | break; | ||
622 | } | ||
623 | |||
624 | return 0; | ||
625 | } | ||
626 | |||
627 | static enum omapfb_update_mode hwa742_get_update_mode(void) | ||
628 | { | ||
629 | return hwa742.update_mode; | ||
630 | } | ||
631 | |||
632 | static unsigned long round_to_extif_ticks(unsigned long ps, int div) | ||
633 | { | ||
634 | int bus_tick = hwa742.extif_clk_period * div; | ||
635 | return (ps + bus_tick - 1) / bus_tick * bus_tick; | ||
636 | } | ||
637 | |||
638 | static int calc_reg_timing(unsigned long sysclk, int div) | ||
639 | { | ||
640 | struct extif_timings *t; | ||
641 | unsigned long systim; | ||
642 | |||
643 | /* CSOnTime 0, WEOnTime 2 ns, REOnTime 2 ns, | ||
644 | * AccessTime 2 ns + 12.2 ns (regs), | ||
645 | * WEOffTime = WEOnTime + 1 ns, | ||
646 | * REOffTime = REOnTime + 16 ns (regs), | ||
647 | * CSOffTime = REOffTime + 1 ns | ||
648 | * ReadCycle = 2ns + 2*SYSCLK (regs), | ||
649 | * WriteCycle = 2*SYSCLK + 2 ns, | ||
650 | * CSPulseWidth = 10 ns */ | ||
651 | systim = 1000000000 / (sysclk / 1000); | ||
652 | dev_dbg(hwa742.fbdev->dev, "HWA742 systim %lu ps extif_clk_period %u ps" | ||
653 | "extif_clk_div %d\n", systim, hwa742.extif_clk_period, div); | ||
654 | |||
655 | t = &hwa742.reg_timings; | ||
656 | memset(t, 0, sizeof(*t)); | ||
657 | t->clk_div = div; | ||
658 | t->cs_on_time = 0; | ||
659 | t->we_on_time = round_to_extif_ticks(t->cs_on_time + 2000, div); | ||
660 | t->re_on_time = round_to_extif_ticks(t->cs_on_time + 2000, div); | ||
661 | t->access_time = round_to_extif_ticks(t->re_on_time + 12200, div); | ||
662 | t->we_off_time = round_to_extif_ticks(t->we_on_time + 1000, div); | ||
663 | t->re_off_time = round_to_extif_ticks(t->re_on_time + 16000, div); | ||
664 | t->cs_off_time = round_to_extif_ticks(t->re_off_time + 1000, div); | ||
665 | t->we_cycle_time = round_to_extif_ticks(2 * systim + 2000, div); | ||
666 | if (t->we_cycle_time < t->we_off_time) | ||
667 | t->we_cycle_time = t->we_off_time; | ||
668 | t->re_cycle_time = round_to_extif_ticks(2 * systim + 2000, div); | ||
669 | if (t->re_cycle_time < t->re_off_time) | ||
670 | t->re_cycle_time = t->re_off_time; | ||
671 | t->cs_pulse_width = 0; | ||
672 | |||
673 | dev_dbg(hwa742.fbdev->dev, "[reg]cson %d csoff %d reon %d reoff %d\n", | ||
674 | t->cs_on_time, t->cs_off_time, t->re_on_time, t->re_off_time); | ||
675 | dev_dbg(hwa742.fbdev->dev, "[reg]weon %d weoff %d recyc %d wecyc %d\n", | ||
676 | t->we_on_time, t->we_off_time, t->re_cycle_time, | ||
677 | t->we_cycle_time); | ||
678 | dev_dbg(hwa742.fbdev->dev, "[reg]rdaccess %d cspulse %d\n", | ||
679 | t->access_time, t->cs_pulse_width); | ||
680 | |||
681 | return hwa742.extif->convert_timings(t); | ||
682 | } | ||
683 | |||
684 | static int calc_lut_timing(unsigned long sysclk, int div) | ||
685 | { | ||
686 | struct extif_timings *t; | ||
687 | unsigned long systim; | ||
688 | |||
689 | /* CSOnTime 0, WEOnTime 2 ns, REOnTime 2 ns, | ||
690 | * AccessTime 2 ns + 4 * SYSCLK + 26 (lut), | ||
691 | * WEOffTime = WEOnTime + 1 ns, | ||
692 | * REOffTime = REOnTime + 4*SYSCLK + 26 ns (lut), | ||
693 | * CSOffTime = REOffTime + 1 ns | ||
694 | * ReadCycle = 2ns + 4*SYSCLK + 26 ns (lut), | ||
695 | * WriteCycle = 2*SYSCLK + 2 ns, | ||
696 | * CSPulseWidth = 10 ns | ||
697 | */ | ||
698 | systim = 1000000000 / (sysclk / 1000); | ||
699 | dev_dbg(hwa742.fbdev->dev, "HWA742 systim %lu ps extif_clk_period %u ps" | ||
700 | "extif_clk_div %d\n", systim, hwa742.extif_clk_period, div); | ||
701 | |||
702 | t = &hwa742.lut_timings; | ||
703 | memset(t, 0, sizeof(*t)); | ||
704 | |||
705 | t->clk_div = div; | ||
706 | |||
707 | t->cs_on_time = 0; | ||
708 | t->we_on_time = round_to_extif_ticks(t->cs_on_time + 2000, div); | ||
709 | t->re_on_time = round_to_extif_ticks(t->cs_on_time + 2000, div); | ||
710 | t->access_time = round_to_extif_ticks(t->re_on_time + 4 * systim + | ||
711 | 26000, div); | ||
712 | t->we_off_time = round_to_extif_ticks(t->we_on_time + 1000, div); | ||
713 | t->re_off_time = round_to_extif_ticks(t->re_on_time + 4 * systim + | ||
714 | 26000, div); | ||
715 | t->cs_off_time = round_to_extif_ticks(t->re_off_time + 1000, div); | ||
716 | t->we_cycle_time = round_to_extif_ticks(2 * systim + 2000, div); | ||
717 | if (t->we_cycle_time < t->we_off_time) | ||
718 | t->we_cycle_time = t->we_off_time; | ||
719 | t->re_cycle_time = round_to_extif_ticks(2000 + 4 * systim + 26000, div); | ||
720 | if (t->re_cycle_time < t->re_off_time) | ||
721 | t->re_cycle_time = t->re_off_time; | ||
722 | t->cs_pulse_width = 0; | ||
723 | |||
724 | dev_dbg(hwa742.fbdev->dev, "[lut]cson %d csoff %d reon %d reoff %d\n", | ||
725 | t->cs_on_time, t->cs_off_time, t->re_on_time, t->re_off_time); | ||
726 | dev_dbg(hwa742.fbdev->dev, "[lut]weon %d weoff %d recyc %d wecyc %d\n", | ||
727 | t->we_on_time, t->we_off_time, t->re_cycle_time, | ||
728 | t->we_cycle_time); | ||
729 | dev_dbg(hwa742.fbdev->dev, "[lut]rdaccess %d cspulse %d\n", | ||
730 | t->access_time, t->cs_pulse_width); | ||
731 | |||
732 | return hwa742.extif->convert_timings(t); | ||
733 | } | ||
734 | |||
735 | static int calc_extif_timings(unsigned long sysclk, int *extif_mem_div) | ||
736 | { | ||
737 | int max_clk_div; | ||
738 | int div; | ||
739 | |||
740 | hwa742.extif->get_clk_info(&hwa742.extif_clk_period, &max_clk_div); | ||
741 | for (div = 1; div < max_clk_div; div++) { | ||
742 | if (calc_reg_timing(sysclk, div) == 0) | ||
743 | break; | ||
744 | } | ||
745 | if (div > max_clk_div) | ||
746 | goto err; | ||
747 | |||
748 | *extif_mem_div = div; | ||
749 | |||
750 | for (div = 1; div < max_clk_div; div++) { | ||
751 | if (calc_lut_timing(sysclk, div) == 0) | ||
752 | break; | ||
753 | } | ||
754 | |||
755 | if (div > max_clk_div) | ||
756 | goto err; | ||
757 | |||
758 | return 0; | ||
759 | |||
760 | err: | ||
761 | dev_err(hwa742.fbdev->dev, "can't setup timings\n"); | ||
762 | return -1; | ||
763 | } | ||
764 | |||
765 | static void calc_hwa742_clk_rates(unsigned long ext_clk, | ||
766 | unsigned long *sys_clk, unsigned long *pix_clk) | ||
767 | { | ||
768 | int pix_clk_src; | ||
769 | int sys_div = 0, sys_mul = 0; | ||
770 | int pix_div; | ||
771 | |||
772 | pix_clk_src = hwa742_read_reg(HWA742_CLK_SRC_REG); | ||
773 | pix_div = ((pix_clk_src >> 3) & 0x1f) + 1; | ||
774 | if ((pix_clk_src & (0x3 << 1)) == 0) { | ||
775 | /* Source is the PLL */ | ||
776 | sys_div = (hwa742_read_reg(HWA742_PLL_DIV_REG) & 0x3f) + 1; | ||
777 | sys_mul = (hwa742_read_reg(HWA742_PLL_4_REG) & 0x7f) + 1; | ||
778 | *sys_clk = ext_clk * sys_mul / sys_div; | ||
779 | } else /* else source is ext clk, or oscillator */ | ||
780 | *sys_clk = ext_clk; | ||
781 | |||
782 | *pix_clk = *sys_clk / pix_div; /* HZ */ | ||
783 | dev_dbg(hwa742.fbdev->dev, | ||
784 | "ext_clk %ld pix_src %d pix_div %d sys_div %d sys_mul %d\n", | ||
785 | ext_clk, pix_clk_src & (0x3 << 1), pix_div, sys_div, sys_mul); | ||
786 | dev_dbg(hwa742.fbdev->dev, "sys_clk %ld pix_clk %ld\n", | ||
787 | *sys_clk, *pix_clk); | ||
788 | } | ||
789 | |||
790 | |||
791 | static int setup_tearsync(unsigned long pix_clk, int extif_div) | ||
792 | { | ||
793 | int hdisp, vdisp; | ||
794 | int hndp, vndp; | ||
795 | int hsw, vsw; | ||
796 | int hs, vs; | ||
797 | int hs_pol_inv, vs_pol_inv; | ||
798 | int use_hsvs, use_ndp; | ||
799 | u8 b; | ||
800 | |||
801 | hsw = hwa742_read_reg(HWA742_HS_W_REG); | ||
802 | vsw = hwa742_read_reg(HWA742_VS_W_REG); | ||
803 | hs_pol_inv = !(hsw & 0x80); | ||
804 | vs_pol_inv = !(vsw & 0x80); | ||
805 | hsw = hsw & 0x7f; | ||
806 | vsw = vsw & 0x3f; | ||
807 | |||
808 | hdisp = (hwa742_read_reg(HWA742_H_DISP_REG) & 0x7f) * 8; | ||
809 | vdisp = hwa742_read_reg(HWA742_V_DISP_1_REG) + | ||
810 | ((hwa742_read_reg(HWA742_V_DISP_2_REG) & 0x3) << 8); | ||
811 | |||
812 | hndp = hwa742_read_reg(HWA742_H_NDP_REG) & 0x7f; | ||
813 | vndp = hwa742_read_reg(HWA742_V_NDP_REG); | ||
814 | |||
815 | /* time to transfer one pixel (16bpp) in ps */ | ||
816 | hwa742.pix_tx_time = hwa742.reg_timings.we_cycle_time; | ||
817 | if (hwa742.extif->get_max_tx_rate != NULL) { | ||
818 | /* | ||
819 | * The external interface might have a rate limitation, | ||
820 | * if so, we have to maximize our transfer rate. | ||
821 | */ | ||
822 | unsigned long min_tx_time; | ||
823 | unsigned long max_tx_rate = hwa742.extif->get_max_tx_rate(); | ||
824 | |||
825 | dev_dbg(hwa742.fbdev->dev, "max_tx_rate %ld HZ\n", | ||
826 | max_tx_rate); | ||
827 | min_tx_time = 1000000000 / (max_tx_rate / 1000); /* ps */ | ||
828 | if (hwa742.pix_tx_time < min_tx_time) | ||
829 | hwa742.pix_tx_time = min_tx_time; | ||
830 | } | ||
831 | |||
832 | /* time to update one line in ps */ | ||
833 | hwa742.line_upd_time = (hdisp + hndp) * 1000000 / (pix_clk / 1000); | ||
834 | hwa742.line_upd_time *= 1000; | ||
835 | if (hdisp * hwa742.pix_tx_time > hwa742.line_upd_time) | ||
836 | /* | ||
837 | * transfer speed too low, we might have to use both | ||
838 | * HS and VS | ||
839 | */ | ||
840 | use_hsvs = 1; | ||
841 | else | ||
842 | /* decent transfer speed, we'll always use only VS */ | ||
843 | use_hsvs = 0; | ||
844 | |||
845 | if (use_hsvs && (hs_pol_inv || vs_pol_inv)) { | ||
846 | /* | ||
847 | * HS or'ed with VS doesn't work, use the active high | ||
848 | * TE signal based on HNDP / VNDP | ||
849 | */ | ||
850 | use_ndp = 1; | ||
851 | hs_pol_inv = 0; | ||
852 | vs_pol_inv = 0; | ||
853 | hs = hndp; | ||
854 | vs = vndp; | ||
855 | } else { | ||
856 | /* | ||
857 | * Use HS or'ed with VS as a TE signal if both are needed | ||
858 | * or VNDP if only vsync is needed. | ||
859 | */ | ||
860 | use_ndp = 0; | ||
861 | hs = hsw; | ||
862 | vs = vsw; | ||
863 | if (!use_hsvs) { | ||
864 | hs_pol_inv = 0; | ||
865 | vs_pol_inv = 0; | ||
866 | } | ||
867 | } | ||
868 | |||
869 | hs = hs * 1000000 / (pix_clk / 1000); /* ps */ | ||
870 | hs *= 1000; | ||
871 | |||
872 | vs = vs * (hdisp + hndp) * 1000000 / (pix_clk / 1000); /* ps */ | ||
873 | vs *= 1000; | ||
874 | |||
875 | if (vs <= hs) | ||
876 | return -EDOM; | ||
877 | /* set VS to 120% of HS to minimize VS detection time */ | ||
878 | vs = hs * 12 / 10; | ||
879 | /* minimize HS too */ | ||
880 | hs = 10000; | ||
881 | |||
882 | b = hwa742_read_reg(HWA742_NDP_CTRL); | ||
883 | b &= ~0x3; | ||
884 | b |= use_hsvs ? 1 : 0; | ||
885 | b |= (use_ndp && use_hsvs) ? 0 : 2; | ||
886 | hwa742_write_reg(HWA742_NDP_CTRL, b); | ||
887 | |||
888 | hwa742.vsync_only = !use_hsvs; | ||
889 | |||
890 | dev_dbg(hwa742.fbdev->dev, | ||
891 | "pix_clk %ld HZ pix_tx_time %ld ps line_upd_time %ld ps\n", | ||
892 | pix_clk, hwa742.pix_tx_time, hwa742.line_upd_time); | ||
893 | dev_dbg(hwa742.fbdev->dev, | ||
894 | "hs %d ps vs %d ps mode %d vsync_only %d\n", | ||
895 | hs, vs, (b & 0x3), !use_hsvs); | ||
896 | |||
897 | return hwa742.extif->setup_tearsync(1, hs, vs, | ||
898 | hs_pol_inv, vs_pol_inv, extif_div); | ||
899 | } | ||
900 | |||
901 | static void hwa742_get_caps(int plane, struct omapfb_caps *caps) | ||
902 | { | ||
903 | hwa742.int_ctrl->get_caps(plane, caps); | ||
904 | caps->ctrl |= OMAPFB_CAPS_MANUAL_UPDATE | | ||
905 | OMAPFB_CAPS_WINDOW_PIXEL_DOUBLE; | ||
906 | if (hwa742.te_connected) | ||
907 | caps->ctrl |= OMAPFB_CAPS_TEARSYNC; | ||
908 | caps->wnd_color |= (1 << OMAPFB_COLOR_RGB565) | | ||
909 | (1 << OMAPFB_COLOR_YUV420); | ||
910 | } | ||
911 | |||
912 | static void hwa742_suspend(void) | ||
913 | { | ||
914 | hwa742.update_mode_before_suspend = hwa742.update_mode; | ||
915 | hwa742_set_update_mode(OMAPFB_UPDATE_DISABLED); | ||
916 | /* Enable sleep mode */ | ||
917 | hwa742_write_reg(HWA742_POWER_SAVE, 1 << 1); | ||
918 | if (hwa742.power_down != NULL) | ||
919 | hwa742.power_down(hwa742.fbdev->dev); | ||
920 | } | ||
921 | |||
922 | static void hwa742_resume(void) | ||
923 | { | ||
924 | if (hwa742.power_up != NULL) | ||
925 | hwa742.power_up(hwa742.fbdev->dev); | ||
926 | /* Disable sleep mode */ | ||
927 | hwa742_write_reg(HWA742_POWER_SAVE, 0); | ||
928 | while (1) { | ||
929 | /* Loop until PLL output is stabilized */ | ||
930 | if (hwa742_read_reg(HWA742_PLL_DIV_REG) & (1 << 7)) | ||
931 | break; | ||
932 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
933 | schedule_timeout(msecs_to_jiffies(5)); | ||
934 | } | ||
935 | hwa742_set_update_mode(hwa742.update_mode_before_suspend); | ||
936 | } | ||
937 | |||
938 | static int hwa742_init(struct omapfb_device *fbdev, int ext_mode, | ||
939 | struct omapfb_mem_desc *req_vram) | ||
940 | { | ||
941 | int r = 0, i; | ||
942 | u8 rev, conf; | ||
943 | unsigned long ext_clk; | ||
944 | unsigned long sys_clk, pix_clk; | ||
945 | int extif_mem_div; | ||
946 | struct omapfb_platform_data *omapfb_conf; | ||
947 | struct hwa742_platform_data *ctrl_conf; | ||
948 | |||
949 | BUG_ON(!fbdev->ext_if || !fbdev->int_ctrl); | ||
950 | |||
951 | hwa742.fbdev = fbdev; | ||
952 | hwa742.extif = fbdev->ext_if; | ||
953 | hwa742.int_ctrl = fbdev->int_ctrl; | ||
954 | |||
955 | omapfb_conf = fbdev->dev->platform_data; | ||
956 | ctrl_conf = omapfb_conf->ctrl_platform_data; | ||
957 | |||
958 | if (ctrl_conf == NULL || ctrl_conf->get_clock_rate == NULL) { | ||
959 | dev_err(fbdev->dev, "HWA742: missing platform data\n"); | ||
960 | r = -ENOENT; | ||
961 | goto err1; | ||
962 | } | ||
963 | |||
964 | hwa742.power_down = ctrl_conf->power_down; | ||
965 | hwa742.power_up = ctrl_conf->power_up; | ||
966 | |||
967 | spin_lock_init(&hwa742.req_lock); | ||
968 | |||
969 | if ((r = hwa742.int_ctrl->init(fbdev, 1, req_vram)) < 0) | ||
970 | goto err1; | ||
971 | |||
972 | if ((r = hwa742.extif->init(fbdev)) < 0) | ||
973 | goto err2; | ||
974 | |||
975 | ext_clk = ctrl_conf->get_clock_rate(fbdev->dev); | ||
976 | if ((r = calc_extif_timings(ext_clk, &extif_mem_div)) < 0) | ||
977 | goto err3; | ||
978 | hwa742.extif->set_timings(&hwa742.reg_timings); | ||
979 | if (hwa742.power_up != NULL) | ||
980 | hwa742.power_up(fbdev->dev); | ||
981 | |||
982 | calc_hwa742_clk_rates(ext_clk, &sys_clk, &pix_clk); | ||
983 | if ((r = calc_extif_timings(sys_clk, &extif_mem_div)) < 0) | ||
984 | goto err4; | ||
985 | hwa742.extif->set_timings(&hwa742.reg_timings); | ||
986 | |||
987 | rev = hwa742_read_reg(HWA742_REV_CODE_REG); | ||
988 | if ((rev & 0xfc) != 0x80) { | ||
989 | dev_err(fbdev->dev, "HWA742: invalid revision %02x\n", rev); | ||
990 | r = -ENODEV; | ||
991 | goto err4; | ||
992 | } | ||
993 | |||
994 | |||
995 | if (!(hwa742_read_reg(HWA742_PLL_DIV_REG) & 0x80)) { | ||
996 | dev_err(fbdev->dev, | ||
997 | "HWA742: controller not initialized by the bootloader\n"); | ||
998 | r = -ENODEV; | ||
999 | goto err4; | ||
1000 | } | ||
1001 | |||
1002 | if (ctrl_conf->te_connected) { | ||
1003 | if ((r = setup_tearsync(pix_clk, extif_mem_div)) < 0) { | ||
1004 | dev_err(hwa742.fbdev->dev, | ||
1005 | "HWA742: can't setup tearing synchronization\n"); | ||
1006 | goto err4; | ||
1007 | } | ||
1008 | hwa742.te_connected = 1; | ||
1009 | } | ||
1010 | |||
1011 | hwa742.max_transmit_size = hwa742.extif->max_transmit_size; | ||
1012 | |||
1013 | hwa742.update_mode = OMAPFB_UPDATE_DISABLED; | ||
1014 | |||
1015 | hwa742.auto_update_window.x = 0; | ||
1016 | hwa742.auto_update_window.y = 0; | ||
1017 | hwa742.auto_update_window.width = fbdev->panel->x_res; | ||
1018 | hwa742.auto_update_window.height = fbdev->panel->y_res; | ||
1019 | hwa742.auto_update_window.format = 0; | ||
1020 | |||
1021 | init_timer(&hwa742.auto_update_timer); | ||
1022 | hwa742.auto_update_timer.function = hwa742_update_window_auto; | ||
1023 | hwa742.auto_update_timer.data = 0; | ||
1024 | |||
1025 | hwa742.prev_color_mode = -1; | ||
1026 | hwa742.prev_flags = 0; | ||
1027 | |||
1028 | hwa742.fbdev = fbdev; | ||
1029 | |||
1030 | INIT_LIST_HEAD(&hwa742.free_req_list); | ||
1031 | INIT_LIST_HEAD(&hwa742.pending_req_list); | ||
1032 | for (i = 0; i < ARRAY_SIZE(hwa742.req_pool); i++) | ||
1033 | list_add(&hwa742.req_pool[i].entry, &hwa742.free_req_list); | ||
1034 | BUG_ON(i <= IRQ_REQ_POOL_SIZE); | ||
1035 | sema_init(&hwa742.req_sema, i - IRQ_REQ_POOL_SIZE); | ||
1036 | |||
1037 | conf = hwa742_read_reg(HWA742_CONFIG_REG); | ||
1038 | dev_info(fbdev->dev, ": Epson HWA742 LCD controller rev %d " | ||
1039 | "initialized (CNF pins %x)\n", rev & 0x03, conf & 0x07); | ||
1040 | |||
1041 | return 0; | ||
1042 | err4: | ||
1043 | if (hwa742.power_down != NULL) | ||
1044 | hwa742.power_down(fbdev->dev); | ||
1045 | err3: | ||
1046 | hwa742.extif->cleanup(); | ||
1047 | err2: | ||
1048 | hwa742.int_ctrl->cleanup(); | ||
1049 | err1: | ||
1050 | return r; | ||
1051 | } | ||
1052 | |||
1053 | static void hwa742_cleanup(void) | ||
1054 | { | ||
1055 | hwa742_set_update_mode(OMAPFB_UPDATE_DISABLED); | ||
1056 | hwa742.extif->cleanup(); | ||
1057 | hwa742.int_ctrl->cleanup(); | ||
1058 | if (hwa742.power_down != NULL) | ||
1059 | hwa742.power_down(hwa742.fbdev->dev); | ||
1060 | } | ||
1061 | |||
1062 | struct lcd_ctrl hwa742_ctrl = { | ||
1063 | .name = "hwa742", | ||
1064 | .init = hwa742_init, | ||
1065 | .cleanup = hwa742_cleanup, | ||
1066 | .bind_client = hwa742_bind_client, | ||
1067 | .get_caps = hwa742_get_caps, | ||
1068 | .set_update_mode = hwa742_set_update_mode, | ||
1069 | .get_update_mode = hwa742_get_update_mode, | ||
1070 | .setup_plane = hwa742_setup_plane, | ||
1071 | .enable_plane = hwa742_enable_plane, | ||
1072 | .update_window = hwa742_update_window_async, | ||
1073 | .sync = hwa742_sync, | ||
1074 | .suspend = hwa742_suspend, | ||
1075 | .resume = hwa742_resume, | ||
1076 | }; | ||
1077 | |||
diff --git a/drivers/video/omap/lcd_h3.c b/drivers/video/omap/lcd_h3.c new file mode 100644 index 000000000000..51807b4e26d1 --- /dev/null +++ b/drivers/video/omap/lcd_h3.c | |||
@@ -0,0 +1,141 @@ | |||
1 | /* | ||
2 | * LCD panel support for the TI OMAP H3 board | ||
3 | * | ||
4 | * Copyright (C) 2004 Nokia Corporation | ||
5 | * Author: Imre Deak <imre.deak@nokia.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License along | ||
18 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
19 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
20 | */ | ||
21 | |||
22 | #include <linux/module.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | |||
25 | #include <asm/arch/gpio.h> | ||
26 | #include <asm/arch/tps65010.h> | ||
27 | #include <asm/arch/omapfb.h> | ||
28 | |||
29 | #define MODULE_NAME "omapfb-lcd_h3" | ||
30 | |||
31 | #define pr_err(fmt, args...) printk(KERN_ERR MODULE_NAME ": " fmt, ## args) | ||
32 | |||
33 | static int h3_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev) | ||
34 | { | ||
35 | return 0; | ||
36 | } | ||
37 | |||
38 | static void h3_panel_cleanup(struct lcd_panel *panel) | ||
39 | { | ||
40 | } | ||
41 | |||
42 | static int h3_panel_enable(struct lcd_panel *panel) | ||
43 | { | ||
44 | int r = 0; | ||
45 | |||
46 | /* GPIO1 and GPIO2 of TPS65010 send LCD_ENBKL and LCD_ENVDD signals */ | ||
47 | r = tps65010_set_gpio_out_value(GPIO1, HIGH); | ||
48 | if (!r) | ||
49 | r = tps65010_set_gpio_out_value(GPIO2, HIGH); | ||
50 | if (r) | ||
51 | pr_err("Unable to turn on LCD panel\n"); | ||
52 | |||
53 | return r; | ||
54 | } | ||
55 | |||
56 | static void h3_panel_disable(struct lcd_panel *panel) | ||
57 | { | ||
58 | int r = 0; | ||
59 | |||
60 | /* GPIO1 and GPIO2 of TPS65010 send LCD_ENBKL and LCD_ENVDD signals */ | ||
61 | r = tps65010_set_gpio_out_value(GPIO1, LOW); | ||
62 | if (!r) | ||
63 | tps65010_set_gpio_out_value(GPIO2, LOW); | ||
64 | if (r) | ||
65 | pr_err("Unable to turn off LCD panel\n"); | ||
66 | } | ||
67 | |||
68 | static unsigned long h3_panel_get_caps(struct lcd_panel *panel) | ||
69 | { | ||
70 | return 0; | ||
71 | } | ||
72 | |||
73 | struct lcd_panel h3_panel = { | ||
74 | .name = "h3", | ||
75 | .config = OMAP_LCDC_PANEL_TFT, | ||
76 | |||
77 | .data_lines = 16, | ||
78 | .bpp = 16, | ||
79 | .x_res = 240, | ||
80 | .y_res = 320, | ||
81 | .pixel_clock = 12000, | ||
82 | .hsw = 12, | ||
83 | .hfp = 14, | ||
84 | .hbp = 72 - 12, | ||
85 | .vsw = 1, | ||
86 | .vfp = 1, | ||
87 | .vbp = 0, | ||
88 | .pcd = 0, | ||
89 | |||
90 | .init = h3_panel_init, | ||
91 | .cleanup = h3_panel_cleanup, | ||
92 | .enable = h3_panel_enable, | ||
93 | .disable = h3_panel_disable, | ||
94 | .get_caps = h3_panel_get_caps, | ||
95 | }; | ||
96 | |||
97 | static int h3_panel_probe(struct platform_device *pdev) | ||
98 | { | ||
99 | omapfb_register_panel(&h3_panel); | ||
100 | return 0; | ||
101 | } | ||
102 | |||
103 | static int h3_panel_remove(struct platform_device *pdev) | ||
104 | { | ||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | static int h3_panel_suspend(struct platform_device *pdev, pm_message_t mesg) | ||
109 | { | ||
110 | return 0; | ||
111 | } | ||
112 | |||
113 | static int h3_panel_resume(struct platform_device *pdev) | ||
114 | { | ||
115 | return 0; | ||
116 | } | ||
117 | |||
118 | struct platform_driver h3_panel_driver = { | ||
119 | .probe = h3_panel_probe, | ||
120 | .remove = h3_panel_remove, | ||
121 | .suspend = h3_panel_suspend, | ||
122 | .resume = h3_panel_resume, | ||
123 | .driver = { | ||
124 | .name = "lcd_h3", | ||
125 | .owner = THIS_MODULE, | ||
126 | }, | ||
127 | }; | ||
128 | |||
129 | static int h3_panel_drv_init(void) | ||
130 | { | ||
131 | return platform_driver_register(&h3_panel_driver); | ||
132 | } | ||
133 | |||
134 | static void h3_panel_drv_cleanup(void) | ||
135 | { | ||
136 | platform_driver_unregister(&h3_panel_driver); | ||
137 | } | ||
138 | |||
139 | module_init(h3_panel_drv_init); | ||
140 | module_exit(h3_panel_drv_cleanup); | ||
141 | |||
diff --git a/drivers/video/omap/lcd_h4.c b/drivers/video/omap/lcd_h4.c new file mode 100644 index 000000000000..fd6f0eb16de1 --- /dev/null +++ b/drivers/video/omap/lcd_h4.c | |||
@@ -0,0 +1,117 @@ | |||
1 | /* | ||
2 | * LCD panel support for the TI OMAP H4 board | ||
3 | * | ||
4 | * Copyright (C) 2004 Nokia Corporation | ||
5 | * Author: Imre Deak <imre.deak@nokia.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License along | ||
18 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
19 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
20 | */ | ||
21 | |||
22 | #include <linux/module.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | |||
25 | #include <asm/arch/omapfb.h> | ||
26 | |||
27 | static int h4_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev) | ||
28 | { | ||
29 | return 0; | ||
30 | } | ||
31 | |||
32 | static void h4_panel_cleanup(struct lcd_panel *panel) | ||
33 | { | ||
34 | } | ||
35 | |||
36 | static int h4_panel_enable(struct lcd_panel *panel) | ||
37 | { | ||
38 | return 0; | ||
39 | } | ||
40 | |||
41 | static void h4_panel_disable(struct lcd_panel *panel) | ||
42 | { | ||
43 | } | ||
44 | |||
45 | static unsigned long h4_panel_get_caps(struct lcd_panel *panel) | ||
46 | { | ||
47 | return 0; | ||
48 | } | ||
49 | |||
50 | struct lcd_panel h4_panel = { | ||
51 | .name = "h4", | ||
52 | .config = OMAP_LCDC_PANEL_TFT, | ||
53 | |||
54 | .bpp = 16, | ||
55 | .data_lines = 16, | ||
56 | .x_res = 240, | ||
57 | .y_res = 320, | ||
58 | .pixel_clock = 6250, | ||
59 | .hsw = 15, | ||
60 | .hfp = 15, | ||
61 | .hbp = 60, | ||
62 | .vsw = 1, | ||
63 | .vfp = 1, | ||
64 | .vbp = 1, | ||
65 | |||
66 | .init = h4_panel_init, | ||
67 | .cleanup = h4_panel_cleanup, | ||
68 | .enable = h4_panel_enable, | ||
69 | .disable = h4_panel_disable, | ||
70 | .get_caps = h4_panel_get_caps, | ||
71 | }; | ||
72 | |||
73 | static int h4_panel_probe(struct platform_device *pdev) | ||
74 | { | ||
75 | omapfb_register_panel(&h4_panel); | ||
76 | return 0; | ||
77 | } | ||
78 | |||
79 | static int h4_panel_remove(struct platform_device *pdev) | ||
80 | { | ||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | static int h4_panel_suspend(struct platform_device *pdev, pm_message_t mesg) | ||
85 | { | ||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | static int h4_panel_resume(struct platform_device *pdev) | ||
90 | { | ||
91 | return 0; | ||
92 | } | ||
93 | |||
94 | struct platform_driver h4_panel_driver = { | ||
95 | .probe = h4_panel_probe, | ||
96 | .remove = h4_panel_remove, | ||
97 | .suspend = h4_panel_suspend, | ||
98 | .resume = h4_panel_resume, | ||
99 | .driver = { | ||
100 | .name = "lcd_h4", | ||
101 | .owner = THIS_MODULE, | ||
102 | }, | ||
103 | }; | ||
104 | |||
105 | static int h4_panel_drv_init(void) | ||
106 | { | ||
107 | return platform_driver_register(&h4_panel_driver); | ||
108 | } | ||
109 | |||
110 | static void h4_panel_drv_cleanup(void) | ||
111 | { | ||
112 | platform_driver_unregister(&h4_panel_driver); | ||
113 | } | ||
114 | |||
115 | module_init(h4_panel_drv_init); | ||
116 | module_exit(h4_panel_drv_cleanup); | ||
117 | |||
diff --git a/drivers/video/omap/lcd_inn1510.c b/drivers/video/omap/lcd_inn1510.c new file mode 100644 index 000000000000..551f385861d1 --- /dev/null +++ b/drivers/video/omap/lcd_inn1510.c | |||
@@ -0,0 +1,124 @@ | |||
1 | /* | ||
2 | * LCD panel support for the TI OMAP1510 Innovator board | ||
3 | * | ||
4 | * Copyright (C) 2004 Nokia Corporation | ||
5 | * Author: Imre Deak <imre.deak@nokia.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License along | ||
18 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
19 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
20 | */ | ||
21 | |||
22 | #include <linux/module.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | #include <linux/io.h> | ||
25 | |||
26 | #include <asm/arch/fpga.h> | ||
27 | #include <asm/arch/omapfb.h> | ||
28 | |||
29 | static int innovator1510_panel_init(struct lcd_panel *panel, | ||
30 | struct omapfb_device *fbdev) | ||
31 | { | ||
32 | return 0; | ||
33 | } | ||
34 | |||
35 | static void innovator1510_panel_cleanup(struct lcd_panel *panel) | ||
36 | { | ||
37 | } | ||
38 | |||
39 | static int innovator1510_panel_enable(struct lcd_panel *panel) | ||
40 | { | ||
41 | fpga_write(0x7, OMAP1510_FPGA_LCD_PANEL_CONTROL); | ||
42 | return 0; | ||
43 | } | ||
44 | |||
45 | static void innovator1510_panel_disable(struct lcd_panel *panel) | ||
46 | { | ||
47 | fpga_write(0x0, OMAP1510_FPGA_LCD_PANEL_CONTROL); | ||
48 | } | ||
49 | |||
50 | static unsigned long innovator1510_panel_get_caps(struct lcd_panel *panel) | ||
51 | { | ||
52 | return 0; | ||
53 | } | ||
54 | |||
55 | struct lcd_panel innovator1510_panel = { | ||
56 | .name = "inn1510", | ||
57 | .config = OMAP_LCDC_PANEL_TFT, | ||
58 | |||
59 | .bpp = 16, | ||
60 | .data_lines = 16, | ||
61 | .x_res = 240, | ||
62 | .y_res = 320, | ||
63 | .pixel_clock = 12500, | ||
64 | .hsw = 40, | ||
65 | .hfp = 40, | ||
66 | .hbp = 72, | ||
67 | .vsw = 1, | ||
68 | .vfp = 1, | ||
69 | .vbp = 0, | ||
70 | .pcd = 12, | ||
71 | |||
72 | .init = innovator1510_panel_init, | ||
73 | .cleanup = innovator1510_panel_cleanup, | ||
74 | .enable = innovator1510_panel_enable, | ||
75 | .disable = innovator1510_panel_disable, | ||
76 | .get_caps = innovator1510_panel_get_caps, | ||
77 | }; | ||
78 | |||
79 | static int innovator1510_panel_probe(struct platform_device *pdev) | ||
80 | { | ||
81 | omapfb_register_panel(&innovator1510_panel); | ||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | static int innovator1510_panel_remove(struct platform_device *pdev) | ||
86 | { | ||
87 | return 0; | ||
88 | } | ||
89 | |||
90 | static int innovator1510_panel_suspend(struct platform_device *pdev, | ||
91 | pm_message_t mesg) | ||
92 | { | ||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | static int innovator1510_panel_resume(struct platform_device *pdev) | ||
97 | { | ||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | struct platform_driver innovator1510_panel_driver = { | ||
102 | .probe = innovator1510_panel_probe, | ||
103 | .remove = innovator1510_panel_remove, | ||
104 | .suspend = innovator1510_panel_suspend, | ||
105 | .resume = innovator1510_panel_resume, | ||
106 | .driver = { | ||
107 | .name = "lcd_inn1510", | ||
108 | .owner = THIS_MODULE, | ||
109 | }, | ||
110 | }; | ||
111 | |||
112 | static int innovator1510_panel_drv_init(void) | ||
113 | { | ||
114 | return platform_driver_register(&innovator1510_panel_driver); | ||
115 | } | ||
116 | |||
117 | static void innovator1510_panel_drv_cleanup(void) | ||
118 | { | ||
119 | platform_driver_unregister(&innovator1510_panel_driver); | ||
120 | } | ||
121 | |||
122 | module_init(innovator1510_panel_drv_init); | ||
123 | module_exit(innovator1510_panel_drv_cleanup); | ||
124 | |||
diff --git a/drivers/video/omap/lcd_inn1610.c b/drivers/video/omap/lcd_inn1610.c new file mode 100644 index 000000000000..95604ca43301 --- /dev/null +++ b/drivers/video/omap/lcd_inn1610.c | |||
@@ -0,0 +1,150 @@ | |||
1 | /* | ||
2 | * LCD panel support for the TI OMAP1610 Innovator board | ||
3 | * | ||
4 | * Copyright (C) 2004 Nokia Corporation | ||
5 | * Author: Imre Deak <imre.deak@nokia.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License along | ||
18 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
19 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
20 | */ | ||
21 | |||
22 | #include <linux/module.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | |||
25 | #include <asm/arch/gpio.h> | ||
26 | #include <asm/arch/omapfb.h> | ||
27 | |||
28 | #define MODULE_NAME "omapfb-lcd_h3" | ||
29 | |||
30 | #define pr_err(fmt, args...) printk(KERN_ERR MODULE_NAME ": " fmt, ## args) | ||
31 | |||
32 | static int innovator1610_panel_init(struct lcd_panel *panel, | ||
33 | struct omapfb_device *fbdev) | ||
34 | { | ||
35 | int r = 0; | ||
36 | |||
37 | if (omap_request_gpio(14)) { | ||
38 | pr_err("can't request GPIO 14\n"); | ||
39 | r = -1; | ||
40 | goto exit; | ||
41 | } | ||
42 | if (omap_request_gpio(15)) { | ||
43 | pr_err("can't request GPIO 15\n"); | ||
44 | omap_free_gpio(14); | ||
45 | r = -1; | ||
46 | goto exit; | ||
47 | } | ||
48 | /* configure GPIO(14, 15) as outputs */ | ||
49 | omap_set_gpio_direction(14, 0); | ||
50 | omap_set_gpio_direction(15, 0); | ||
51 | exit: | ||
52 | return r; | ||
53 | } | ||
54 | |||
55 | static void innovator1610_panel_cleanup(struct lcd_panel *panel) | ||
56 | { | ||
57 | omap_free_gpio(15); | ||
58 | omap_free_gpio(14); | ||
59 | } | ||
60 | |||
61 | static int innovator1610_panel_enable(struct lcd_panel *panel) | ||
62 | { | ||
63 | /* set GPIO14 and GPIO15 high */ | ||
64 | omap_set_gpio_dataout(14, 1); | ||
65 | omap_set_gpio_dataout(15, 1); | ||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | static void innovator1610_panel_disable(struct lcd_panel *panel) | ||
70 | { | ||
71 | /* set GPIO13, GPIO14 and GPIO15 low */ | ||
72 | omap_set_gpio_dataout(14, 0); | ||
73 | omap_set_gpio_dataout(15, 0); | ||
74 | } | ||
75 | |||
76 | static unsigned long innovator1610_panel_get_caps(struct lcd_panel *panel) | ||
77 | { | ||
78 | return 0; | ||
79 | } | ||
80 | |||
81 | struct lcd_panel innovator1610_panel = { | ||
82 | .name = "inn1610", | ||
83 | .config = OMAP_LCDC_PANEL_TFT, | ||
84 | |||
85 | .bpp = 16, | ||
86 | .data_lines = 16, | ||
87 | .x_res = 320, | ||
88 | .y_res = 240, | ||
89 | .pixel_clock = 12500, | ||
90 | .hsw = 40, | ||
91 | .hfp = 40, | ||
92 | .hbp = 72, | ||
93 | .vsw = 1, | ||
94 | .vfp = 1, | ||
95 | .vbp = 0, | ||
96 | .pcd = 12, | ||
97 | |||
98 | .init = innovator1610_panel_init, | ||
99 | .cleanup = innovator1610_panel_cleanup, | ||
100 | .enable = innovator1610_panel_enable, | ||
101 | .disable = innovator1610_panel_disable, | ||
102 | .get_caps = innovator1610_panel_get_caps, | ||
103 | }; | ||
104 | |||
105 | static int innovator1610_panel_probe(struct platform_device *pdev) | ||
106 | { | ||
107 | omapfb_register_panel(&innovator1610_panel); | ||
108 | return 0; | ||
109 | } | ||
110 | |||
111 | static int innovator1610_panel_remove(struct platform_device *pdev) | ||
112 | { | ||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | static int innovator1610_panel_suspend(struct platform_device *pdev, | ||
117 | pm_message_t mesg) | ||
118 | { | ||
119 | return 0; | ||
120 | } | ||
121 | |||
122 | static int innovator1610_panel_resume(struct platform_device *pdev) | ||
123 | { | ||
124 | return 0; | ||
125 | } | ||
126 | |||
127 | struct platform_driver innovator1610_panel_driver = { | ||
128 | .probe = innovator1610_panel_probe, | ||
129 | .remove = innovator1610_panel_remove, | ||
130 | .suspend = innovator1610_panel_suspend, | ||
131 | .resume = innovator1610_panel_resume, | ||
132 | .driver = { | ||
133 | .name = "lcd_inn1610", | ||
134 | .owner = THIS_MODULE, | ||
135 | }, | ||
136 | }; | ||
137 | |||
138 | static int innovator1610_panel_drv_init(void) | ||
139 | { | ||
140 | return platform_driver_register(&innovator1610_panel_driver); | ||
141 | } | ||
142 | |||
143 | static void innovator1610_panel_drv_cleanup(void) | ||
144 | { | ||
145 | platform_driver_unregister(&innovator1610_panel_driver); | ||
146 | } | ||
147 | |||
148 | module_init(innovator1610_panel_drv_init); | ||
149 | module_exit(innovator1610_panel_drv_cleanup); | ||
150 | |||
diff --git a/drivers/video/omap/lcd_osk.c b/drivers/video/omap/lcd_osk.c new file mode 100644 index 000000000000..a38038840fd6 --- /dev/null +++ b/drivers/video/omap/lcd_osk.c | |||
@@ -0,0 +1,144 @@ | |||
1 | /* | ||
2 | * LCD panel support for the TI OMAP OSK board | ||
3 | * | ||
4 | * Copyright (C) 2004 Nokia Corporation | ||
5 | * Author: Imre Deak <imre.deak@nokia.com> | ||
6 | * Adapted for OSK by <dirk.behme@de.bosch.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License along | ||
19 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
20 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
21 | */ | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/platform_device.h> | ||
25 | |||
26 | #include <asm/arch/gpio.h> | ||
27 | #include <asm/arch/mux.h> | ||
28 | #include <asm/arch/omapfb.h> | ||
29 | |||
30 | static int osk_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev) | ||
31 | { | ||
32 | return 0; | ||
33 | } | ||
34 | |||
35 | static void osk_panel_cleanup(struct lcd_panel *panel) | ||
36 | { | ||
37 | } | ||
38 | |||
39 | static int osk_panel_enable(struct lcd_panel *panel) | ||
40 | { | ||
41 | /* configure PWL pin */ | ||
42 | omap_cfg_reg(PWL); | ||
43 | |||
44 | /* Enable PWL unit */ | ||
45 | omap_writeb(0x01, OMAP_PWL_CLK_ENABLE); | ||
46 | |||
47 | /* Set PWL level */ | ||
48 | omap_writeb(0xFF, OMAP_PWL_ENABLE); | ||
49 | |||
50 | /* configure GPIO2 as output */ | ||
51 | omap_set_gpio_direction(2, 0); | ||
52 | |||
53 | /* set GPIO2 high */ | ||
54 | omap_set_gpio_dataout(2, 1); | ||
55 | |||
56 | return 0; | ||
57 | } | ||
58 | |||
59 | static void osk_panel_disable(struct lcd_panel *panel) | ||
60 | { | ||
61 | /* Set PWL level to zero */ | ||
62 | omap_writeb(0x00, OMAP_PWL_ENABLE); | ||
63 | |||
64 | /* Disable PWL unit */ | ||
65 | omap_writeb(0x00, OMAP_PWL_CLK_ENABLE); | ||
66 | |||
67 | /* set GPIO2 low */ | ||
68 | omap_set_gpio_dataout(2, 0); | ||
69 | } | ||
70 | |||
71 | static unsigned long osk_panel_get_caps(struct lcd_panel *panel) | ||
72 | { | ||
73 | return 0; | ||
74 | } | ||
75 | |||
76 | struct lcd_panel osk_panel = { | ||
77 | .name = "osk", | ||
78 | .config = OMAP_LCDC_PANEL_TFT, | ||
79 | |||
80 | .bpp = 16, | ||
81 | .data_lines = 16, | ||
82 | .x_res = 240, | ||
83 | .y_res = 320, | ||
84 | .pixel_clock = 12500, | ||
85 | .hsw = 40, | ||
86 | .hfp = 40, | ||
87 | .hbp = 72, | ||
88 | .vsw = 1, | ||
89 | .vfp = 1, | ||
90 | .vbp = 0, | ||
91 | .pcd = 12, | ||
92 | |||
93 | .init = osk_panel_init, | ||
94 | .cleanup = osk_panel_cleanup, | ||
95 | .enable = osk_panel_enable, | ||
96 | .disable = osk_panel_disable, | ||
97 | .get_caps = osk_panel_get_caps, | ||
98 | }; | ||
99 | |||
100 | static int osk_panel_probe(struct platform_device *pdev) | ||
101 | { | ||
102 | omapfb_register_panel(&osk_panel); | ||
103 | return 0; | ||
104 | } | ||
105 | |||
106 | static int osk_panel_remove(struct platform_device *pdev) | ||
107 | { | ||
108 | return 0; | ||
109 | } | ||
110 | |||
111 | static int osk_panel_suspend(struct platform_device *pdev, pm_message_t mesg) | ||
112 | { | ||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | static int osk_panel_resume(struct platform_device *pdev) | ||
117 | { | ||
118 | return 0; | ||
119 | } | ||
120 | |||
121 | struct platform_driver osk_panel_driver = { | ||
122 | .probe = osk_panel_probe, | ||
123 | .remove = osk_panel_remove, | ||
124 | .suspend = osk_panel_suspend, | ||
125 | .resume = osk_panel_resume, | ||
126 | .driver = { | ||
127 | .name = "lcd_osk", | ||
128 | .owner = THIS_MODULE, | ||
129 | }, | ||
130 | }; | ||
131 | |||
132 | static int osk_panel_drv_init(void) | ||
133 | { | ||
134 | return platform_driver_register(&osk_panel_driver); | ||
135 | } | ||
136 | |||
137 | static void osk_panel_drv_cleanup(void) | ||
138 | { | ||
139 | platform_driver_unregister(&osk_panel_driver); | ||
140 | } | ||
141 | |||
142 | module_init(osk_panel_drv_init); | ||
143 | module_exit(osk_panel_drv_cleanup); | ||
144 | |||
diff --git a/drivers/video/omap/lcd_palmte.c b/drivers/video/omap/lcd_palmte.c new file mode 100644 index 000000000000..52bdfdac42c9 --- /dev/null +++ b/drivers/video/omap/lcd_palmte.c | |||
@@ -0,0 +1,123 @@ | |||
1 | /* | ||
2 | * LCD panel support for the Palm Tungsten E | ||
3 | * | ||
4 | * Original version : Romain Goyet <r.goyet@gmail.com> | ||
5 | * Current version : Laurent Gonzalez <palmte.linux@free.fr> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License along | ||
18 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
19 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
20 | */ | ||
21 | |||
22 | #include <linux/module.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | #include <linux/io.h> | ||
25 | |||
26 | #include <asm/arch/fpga.h> | ||
27 | #include <asm/arch/omapfb.h> | ||
28 | |||
29 | static int palmte_panel_init(struct lcd_panel *panel, | ||
30 | struct omapfb_device *fbdev) | ||
31 | { | ||
32 | return 0; | ||
33 | } | ||
34 | |||
35 | static void palmte_panel_cleanup(struct lcd_panel *panel) | ||
36 | { | ||
37 | } | ||
38 | |||
39 | static int palmte_panel_enable(struct lcd_panel *panel) | ||
40 | { | ||
41 | return 0; | ||
42 | } | ||
43 | |||
44 | static void palmte_panel_disable(struct lcd_panel *panel) | ||
45 | { | ||
46 | } | ||
47 | |||
48 | static unsigned long palmte_panel_get_caps(struct lcd_panel *panel) | ||
49 | { | ||
50 | return 0; | ||
51 | } | ||
52 | |||
53 | struct lcd_panel palmte_panel = { | ||
54 | .name = "palmte", | ||
55 | .config = OMAP_LCDC_PANEL_TFT | OMAP_LCDC_INV_VSYNC | | ||
56 | OMAP_LCDC_INV_HSYNC | OMAP_LCDC_HSVS_RISING_EDGE | | ||
57 | OMAP_LCDC_HSVS_OPPOSITE, | ||
58 | |||
59 | .data_lines = 16, | ||
60 | .bpp = 8, | ||
61 | .pixel_clock = 12000, | ||
62 | .x_res = 320, | ||
63 | .y_res = 320, | ||
64 | .hsw = 4, | ||
65 | .hfp = 8, | ||
66 | .hbp = 28, | ||
67 | .vsw = 1, | ||
68 | .vfp = 8, | ||
69 | .vbp = 7, | ||
70 | .pcd = 0, | ||
71 | |||
72 | .init = palmte_panel_init, | ||
73 | .cleanup = palmte_panel_cleanup, | ||
74 | .enable = palmte_panel_enable, | ||
75 | .disable = palmte_panel_disable, | ||
76 | .get_caps = palmte_panel_get_caps, | ||
77 | }; | ||
78 | |||
79 | static int palmte_panel_probe(struct platform_device *pdev) | ||
80 | { | ||
81 | omapfb_register_panel(&palmte_panel); | ||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | static int palmte_panel_remove(struct platform_device *pdev) | ||
86 | { | ||
87 | return 0; | ||
88 | } | ||
89 | |||
90 | static int palmte_panel_suspend(struct platform_device *pdev, pm_message_t mesg) | ||
91 | { | ||
92 | return 0; | ||
93 | } | ||
94 | |||
95 | static int palmte_panel_resume(struct platform_device *pdev) | ||
96 | { | ||
97 | return 0; | ||
98 | } | ||
99 | |||
100 | struct platform_driver palmte_panel_driver = { | ||
101 | .probe = palmte_panel_probe, | ||
102 | .remove = palmte_panel_remove, | ||
103 | .suspend = palmte_panel_suspend, | ||
104 | .resume = palmte_panel_resume, | ||
105 | .driver = { | ||
106 | .name = "lcd_palmte", | ||
107 | .owner = THIS_MODULE, | ||
108 | }, | ||
109 | }; | ||
110 | |||
111 | static int palmte_panel_drv_init(void) | ||
112 | { | ||
113 | return platform_driver_register(&palmte_panel_driver); | ||
114 | } | ||
115 | |||
116 | static void palmte_panel_drv_cleanup(void) | ||
117 | { | ||
118 | platform_driver_unregister(&palmte_panel_driver); | ||
119 | } | ||
120 | |||
121 | module_init(palmte_panel_drv_init); | ||
122 | module_exit(palmte_panel_drv_cleanup); | ||
123 | |||
diff --git a/drivers/video/omap/lcd_palmtt.c b/drivers/video/omap/lcd_palmtt.c new file mode 100644 index 000000000000..4bb349f54356 --- /dev/null +++ b/drivers/video/omap/lcd_palmtt.c | |||
@@ -0,0 +1,127 @@ | |||
1 | /* | ||
2 | * LCD panel support for Palm Tungsten|T | ||
3 | * Current version : Marek Vasut <marek.vasut@gmail.com> | ||
4 | * | ||
5 | * Modified from lcd_inn1510.c | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License along | ||
18 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
19 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
20 | */ | ||
21 | |||
22 | /* | ||
23 | GPIO11 - backlight | ||
24 | GPIO12 - screen blanking | ||
25 | GPIO13 - screen blanking | ||
26 | */ | ||
27 | |||
28 | #include <linux/platform_device.h> | ||
29 | #include <linux/module.h> | ||
30 | #include <linux/io.h> | ||
31 | |||
32 | #include <asm/arch/gpio.h> | ||
33 | #include <asm/arch/omapfb.h> | ||
34 | |||
35 | static int palmtt_panel_init(struct lcd_panel *panel, | ||
36 | struct omapfb_device *fbdev) | ||
37 | { | ||
38 | return 0; | ||
39 | } | ||
40 | |||
41 | static void palmtt_panel_cleanup(struct lcd_panel *panel) | ||
42 | { | ||
43 | } | ||
44 | |||
45 | static int palmtt_panel_enable(struct lcd_panel *panel) | ||
46 | { | ||
47 | return 0; | ||
48 | } | ||
49 | |||
50 | static void palmtt_panel_disable(struct lcd_panel *panel) | ||
51 | { | ||
52 | } | ||
53 | |||
54 | static unsigned long palmtt_panel_get_caps(struct lcd_panel *panel) | ||
55 | { | ||
56 | return OMAPFB_CAPS_SET_BACKLIGHT; | ||
57 | } | ||
58 | |||
59 | struct lcd_panel palmtt_panel = { | ||
60 | .name = "palmtt", | ||
61 | .config = OMAP_LCDC_PANEL_TFT | OMAP_LCDC_INV_VSYNC | | ||
62 | OMAP_LCDC_INV_HSYNC | OMAP_LCDC_HSVS_RISING_EDGE | | ||
63 | OMAP_LCDC_HSVS_OPPOSITE, | ||
64 | .bpp = 16, | ||
65 | .data_lines = 16, | ||
66 | .x_res = 320, | ||
67 | .y_res = 320, | ||
68 | .pixel_clock = 10000, | ||
69 | .hsw = 4, | ||
70 | .hfp = 8, | ||
71 | .hbp = 28, | ||
72 | .vsw = 1, | ||
73 | .vfp = 8, | ||
74 | .vbp = 7, | ||
75 | .pcd = 0, | ||
76 | |||
77 | .init = palmtt_panel_init, | ||
78 | .cleanup = palmtt_panel_cleanup, | ||
79 | .enable = palmtt_panel_enable, | ||
80 | .disable = palmtt_panel_disable, | ||
81 | .get_caps = palmtt_panel_get_caps, | ||
82 | }; | ||
83 | |||
84 | static int palmtt_panel_probe(struct platform_device *pdev) | ||
85 | { | ||
86 | omapfb_register_panel(&palmtt_panel); | ||
87 | return 0; | ||
88 | } | ||
89 | |||
90 | static int palmtt_panel_remove(struct platform_device *pdev) | ||
91 | { | ||
92 | return 0; | ||
93 | } | ||
94 | |||
95 | static int palmtt_panel_suspend(struct platform_device *pdev, pm_message_t mesg) | ||
96 | { | ||
97 | return 0; | ||
98 | } | ||
99 | |||
100 | static int palmtt_panel_resume(struct platform_device *pdev) | ||
101 | { | ||
102 | return 0; | ||
103 | } | ||
104 | |||
105 | struct platform_driver palmtt_panel_driver = { | ||
106 | .probe = palmtt_panel_probe, | ||
107 | .remove = palmtt_panel_remove, | ||
108 | .suspend = palmtt_panel_suspend, | ||
109 | .resume = palmtt_panel_resume, | ||
110 | .driver = { | ||
111 | .name = "lcd_palmtt", | ||
112 | .owner = THIS_MODULE, | ||
113 | }, | ||
114 | }; | ||
115 | |||
116 | static int palmtt_panel_drv_init(void) | ||
117 | { | ||
118 | return platform_driver_register(&palmtt_panel_driver); | ||
119 | } | ||
120 | |||
121 | static void palmtt_panel_drv_cleanup(void) | ||
122 | { | ||
123 | platform_driver_unregister(&palmtt_panel_driver); | ||
124 | } | ||
125 | |||
126 | module_init(palmtt_panel_drv_init); | ||
127 | module_exit(palmtt_panel_drv_cleanup); | ||
diff --git a/drivers/video/omap/lcd_palmz71.c b/drivers/video/omap/lcd_palmz71.c new file mode 100644 index 000000000000..ea6170ddff35 --- /dev/null +++ b/drivers/video/omap/lcd_palmz71.c | |||
@@ -0,0 +1,123 @@ | |||
1 | /* | ||
2 | * LCD panel support for the Palm Zire71 | ||
3 | * | ||
4 | * Original version : Romain Goyet | ||
5 | * Current version : Laurent Gonzalez | ||
6 | * Modified for zire71 : Marek Vasut | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License along | ||
19 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
20 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
21 | */ | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/platform_device.h> | ||
25 | #include <linux/io.h> | ||
26 | |||
27 | #include <asm/arch/omapfb.h> | ||
28 | |||
29 | static int palmz71_panel_init(struct lcd_panel *panel, | ||
30 | struct omapfb_device *fbdev) | ||
31 | { | ||
32 | return 0; | ||
33 | } | ||
34 | |||
35 | static void palmz71_panel_cleanup(struct lcd_panel *panel) | ||
36 | { | ||
37 | |||
38 | } | ||
39 | |||
40 | static int palmz71_panel_enable(struct lcd_panel *panel) | ||
41 | { | ||
42 | return 0; | ||
43 | } | ||
44 | |||
45 | static void palmz71_panel_disable(struct lcd_panel *panel) | ||
46 | { | ||
47 | } | ||
48 | |||
49 | static unsigned long palmz71_panel_get_caps(struct lcd_panel *panel) | ||
50 | { | ||
51 | return OMAPFB_CAPS_SET_BACKLIGHT; | ||
52 | } | ||
53 | |||
54 | struct lcd_panel palmz71_panel = { | ||
55 | .name = "palmz71", | ||
56 | .config = OMAP_LCDC_PANEL_TFT | OMAP_LCDC_INV_VSYNC | | ||
57 | OMAP_LCDC_INV_HSYNC | OMAP_LCDC_HSVS_RISING_EDGE | | ||
58 | OMAP_LCDC_HSVS_OPPOSITE, | ||
59 | .data_lines = 16, | ||
60 | .bpp = 16, | ||
61 | .pixel_clock = 24000, | ||
62 | .x_res = 320, | ||
63 | .y_res = 320, | ||
64 | .hsw = 4, | ||
65 | .hfp = 8, | ||
66 | .hbp = 28, | ||
67 | .vsw = 1, | ||
68 | .vfp = 8, | ||
69 | .vbp = 7, | ||
70 | .pcd = 0, | ||
71 | |||
72 | .init = palmz71_panel_init, | ||
73 | .cleanup = palmz71_panel_cleanup, | ||
74 | .enable = palmz71_panel_enable, | ||
75 | .disable = palmz71_panel_disable, | ||
76 | .get_caps = palmz71_panel_get_caps, | ||
77 | }; | ||
78 | |||
79 | static int palmz71_panel_probe(struct platform_device *pdev) | ||
80 | { | ||
81 | omapfb_register_panel(&palmz71_panel); | ||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | static int palmz71_panel_remove(struct platform_device *pdev) | ||
86 | { | ||
87 | return 0; | ||
88 | } | ||
89 | |||
90 | static int palmz71_panel_suspend(struct platform_device *pdev, | ||
91 | pm_message_t mesg) | ||
92 | { | ||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | static int palmz71_panel_resume(struct platform_device *pdev) | ||
97 | { | ||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | struct platform_driver palmz71_panel_driver = { | ||
102 | .probe = palmz71_panel_probe, | ||
103 | .remove = palmz71_panel_remove, | ||
104 | .suspend = palmz71_panel_suspend, | ||
105 | .resume = palmz71_panel_resume, | ||
106 | .driver = { | ||
107 | .name = "lcd_palmz71", | ||
108 | .owner = THIS_MODULE, | ||
109 | }, | ||
110 | }; | ||
111 | |||
112 | static int palmz71_panel_drv_init(void) | ||
113 | { | ||
114 | return platform_driver_register(&palmz71_panel_driver); | ||
115 | } | ||
116 | |||
117 | static void palmz71_panel_drv_cleanup(void) | ||
118 | { | ||
119 | platform_driver_unregister(&palmz71_panel_driver); | ||
120 | } | ||
121 | |||
122 | module_init(palmz71_panel_drv_init); | ||
123 | module_exit(palmz71_panel_drv_cleanup); | ||
diff --git a/drivers/video/omap/lcd_sx1.c b/drivers/video/omap/lcd_sx1.c new file mode 100644 index 000000000000..c4f306a4e5c9 --- /dev/null +++ b/drivers/video/omap/lcd_sx1.c | |||
@@ -0,0 +1,334 @@ | |||
1 | /* | ||
2 | * LCD panel support for the Siemens SX1 mobile phone | ||
3 | * | ||
4 | * Current version : Vovan888@gmail.com, great help from FCA00000 | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License as published by the | ||
8 | * Free Software Foundation; either version 2 of the License, or (at your | ||
9 | * option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but | ||
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | * General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | #include <linux/module.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/delay.h> | ||
24 | #include <linux/io.h> | ||
25 | |||
26 | #include <asm/arch/gpio.h> | ||
27 | #include <asm/arch/omapfb.h> | ||
28 | #include <asm/arch/mcbsp.h> | ||
29 | #include <asm/arch/mux.h> | ||
30 | |||
31 | /* | ||
32 | * OMAP310 GPIO registers | ||
33 | */ | ||
34 | #define GPIO_DATA_INPUT 0xfffce000 | ||
35 | #define GPIO_DATA_OUTPUT 0xfffce004 | ||
36 | #define GPIO_DIR_CONTROL 0xfffce008 | ||
37 | #define GPIO_INT_CONTROL 0xfffce00c | ||
38 | #define GPIO_INT_MASK 0xfffce010 | ||
39 | #define GPIO_INT_STATUS 0xfffce014 | ||
40 | #define GPIO_PIN_CONTROL 0xfffce018 | ||
41 | |||
42 | |||
43 | #define A_LCD_SSC_RD 3 | ||
44 | #define A_LCD_SSC_SD 7 | ||
45 | #define _A_LCD_RESET 9 | ||
46 | #define _A_LCD_SSC_CS 12 | ||
47 | #define _A_LCD_SSC_A0 13 | ||
48 | |||
49 | #define DSP_REG 0xE1017024 | ||
50 | |||
51 | const unsigned char INIT_1[12] = { | ||
52 | 0x1C, 0x02, 0x88, 0x00, 0x1E, 0xE0, 0x00, 0xDC, 0x00, 0x02, 0x00 | ||
53 | }; | ||
54 | |||
55 | const unsigned char INIT_2[127] = { | ||
56 | 0x15, 0x00, 0x29, 0x00, 0x3E, 0x00, 0x51, 0x00, | ||
57 | 0x65, 0x00, 0x7A, 0x00, 0x8D, 0x00, 0xA1, 0x00, | ||
58 | 0xB6, 0x00, 0xC7, 0x00, 0xD8, 0x00, 0xEB, 0x00, | ||
59 | 0xFB, 0x00, 0x0B, 0x01, 0x1B, 0x01, 0x27, 0x01, | ||
60 | 0x34, 0x01, 0x41, 0x01, 0x4C, 0x01, 0x55, 0x01, | ||
61 | 0x5F, 0x01, 0x68, 0x01, 0x70, 0x01, 0x78, 0x01, | ||
62 | 0x7E, 0x01, 0x86, 0x01, 0x8C, 0x01, 0x94, 0x01, | ||
63 | 0x9B, 0x01, 0xA1, 0x01, 0xA4, 0x01, 0xA9, 0x01, | ||
64 | 0xAD, 0x01, 0xB2, 0x01, 0xB7, 0x01, 0xBC, 0x01, | ||
65 | 0xC0, 0x01, 0xC4, 0x01, 0xC8, 0x01, 0xCB, 0x01, | ||
66 | 0xCF, 0x01, 0xD2, 0x01, 0xD5, 0x01, 0xD8, 0x01, | ||
67 | 0xDB, 0x01, 0xE0, 0x01, 0xE3, 0x01, 0xE6, 0x01, | ||
68 | 0xE8, 0x01, 0xEB, 0x01, 0xEE, 0x01, 0xF1, 0x01, | ||
69 | 0xF3, 0x01, 0xF8, 0x01, 0xF9, 0x01, 0xFC, 0x01, | ||
70 | 0x00, 0x02, 0x03, 0x02, 0x07, 0x02, 0x09, 0x02, | ||
71 | 0x0E, 0x02, 0x13, 0x02, 0x1C, 0x02, 0x00 | ||
72 | }; | ||
73 | |||
74 | const unsigned char INIT_3[15] = { | ||
75 | 0x14, 0x26, 0x33, 0x3D, 0x45, 0x4D, 0x53, 0x59, | ||
76 | 0x5E, 0x63, 0x67, 0x6D, 0x71, 0x78, 0xFF | ||
77 | }; | ||
78 | |||
79 | static void epson_sendbyte(int flag, unsigned char byte) | ||
80 | { | ||
81 | int i, shifter = 0x80; | ||
82 | |||
83 | if (!flag) | ||
84 | omap_set_gpio_dataout(_A_LCD_SSC_A0, 0); | ||
85 | mdelay(2); | ||
86 | omap_set_gpio_dataout(A_LCD_SSC_RD, 1); | ||
87 | |||
88 | omap_set_gpio_dataout(A_LCD_SSC_SD, flag); | ||
89 | |||
90 | OMAP_MCBSP_WRITE(OMAP1510_MCBSP3_BASE, PCR0, 0x2200); | ||
91 | OMAP_MCBSP_WRITE(OMAP1510_MCBSP3_BASE, PCR0, 0x2202); | ||
92 | for (i = 0; i < 8; i++) { | ||
93 | OMAP_MCBSP_WRITE(OMAP1510_MCBSP3_BASE, PCR0, 0x2200); | ||
94 | omap_set_gpio_dataout(A_LCD_SSC_SD, shifter & byte); | ||
95 | OMAP_MCBSP_WRITE(OMAP1510_MCBSP3_BASE, PCR0, 0x2202); | ||
96 | shifter >>= 1; | ||
97 | } | ||
98 | omap_set_gpio_dataout(_A_LCD_SSC_A0, 1); | ||
99 | } | ||
100 | |||
101 | static void init_system(void) | ||
102 | { | ||
103 | omap_mcbsp_request(OMAP_MCBSP3); | ||
104 | omap_mcbsp_stop(OMAP_MCBSP3); | ||
105 | } | ||
106 | |||
107 | static void setup_GPIO(void) | ||
108 | { | ||
109 | /* new wave */ | ||
110 | omap_request_gpio(A_LCD_SSC_RD); | ||
111 | omap_request_gpio(A_LCD_SSC_SD); | ||
112 | omap_request_gpio(_A_LCD_RESET); | ||
113 | omap_request_gpio(_A_LCD_SSC_CS); | ||
114 | omap_request_gpio(_A_LCD_SSC_A0); | ||
115 | |||
116 | /* set all GPIOs to output */ | ||
117 | omap_set_gpio_direction(A_LCD_SSC_RD, 0); | ||
118 | omap_set_gpio_direction(A_LCD_SSC_SD, 0); | ||
119 | omap_set_gpio_direction(_A_LCD_RESET, 0); | ||
120 | omap_set_gpio_direction(_A_LCD_SSC_CS, 0); | ||
121 | omap_set_gpio_direction(_A_LCD_SSC_A0, 0); | ||
122 | |||
123 | /* set GPIO data */ | ||
124 | omap_set_gpio_dataout(A_LCD_SSC_RD, 1); | ||
125 | omap_set_gpio_dataout(A_LCD_SSC_SD, 0); | ||
126 | omap_set_gpio_dataout(_A_LCD_RESET, 0); | ||
127 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 1); | ||
128 | omap_set_gpio_dataout(_A_LCD_SSC_A0, 1); | ||
129 | } | ||
130 | |||
131 | static void display_init(void) | ||
132 | { | ||
133 | int i; | ||
134 | |||
135 | omap_cfg_reg(MCBSP3_CLKX); | ||
136 | |||
137 | mdelay(2); | ||
138 | setup_GPIO(); | ||
139 | mdelay(2); | ||
140 | |||
141 | /* reset LCD */ | ||
142 | omap_set_gpio_dataout(A_LCD_SSC_SD, 1); | ||
143 | epson_sendbyte(0, 0x25); | ||
144 | |||
145 | omap_set_gpio_dataout(_A_LCD_RESET, 0); | ||
146 | mdelay(10); | ||
147 | omap_set_gpio_dataout(_A_LCD_RESET, 1); | ||
148 | |||
149 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 1); | ||
150 | mdelay(2); | ||
151 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 0); | ||
152 | |||
153 | /* init LCD, phase 1 */ | ||
154 | epson_sendbyte(0, 0xCA); | ||
155 | for (i = 0; i < 10; i++) | ||
156 | epson_sendbyte(1, INIT_1[i]); | ||
157 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 1); | ||
158 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 0); | ||
159 | |||
160 | /* init LCD phase 2 */ | ||
161 | epson_sendbyte(0, 0xCB); | ||
162 | for (i = 0; i < 125; i++) | ||
163 | epson_sendbyte(1, INIT_2[i]); | ||
164 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 1); | ||
165 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 0); | ||
166 | |||
167 | /* init LCD phase 2a */ | ||
168 | epson_sendbyte(0, 0xCC); | ||
169 | for (i = 0; i < 14; i++) | ||
170 | epson_sendbyte(1, INIT_3[i]); | ||
171 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 1); | ||
172 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 0); | ||
173 | |||
174 | /* init LCD phase 3 */ | ||
175 | epson_sendbyte(0, 0xBC); | ||
176 | epson_sendbyte(1, 0x08); | ||
177 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 1); | ||
178 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 0); | ||
179 | |||
180 | /* init LCD phase 4 */ | ||
181 | epson_sendbyte(0, 0x07); | ||
182 | epson_sendbyte(1, 0x05); | ||
183 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 1); | ||
184 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 0); | ||
185 | |||
186 | /* init LCD phase 5 */ | ||
187 | epson_sendbyte(0, 0x94); | ||
188 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 1); | ||
189 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 0); | ||
190 | |||
191 | /* init LCD phase 6 */ | ||
192 | epson_sendbyte(0, 0xC6); | ||
193 | epson_sendbyte(1, 0x80); | ||
194 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 1); | ||
195 | mdelay(100); /* used to be 1000 */ | ||
196 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 0); | ||
197 | |||
198 | /* init LCD phase 7 */ | ||
199 | epson_sendbyte(0, 0x16); | ||
200 | epson_sendbyte(1, 0x02); | ||
201 | epson_sendbyte(1, 0x00); | ||
202 | epson_sendbyte(1, 0xB1); | ||
203 | epson_sendbyte(1, 0x00); | ||
204 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 1); | ||
205 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 0); | ||
206 | |||
207 | /* init LCD phase 8 */ | ||
208 | epson_sendbyte(0, 0x76); | ||
209 | epson_sendbyte(1, 0x00); | ||
210 | epson_sendbyte(1, 0x00); | ||
211 | epson_sendbyte(1, 0xDB); | ||
212 | epson_sendbyte(1, 0x00); | ||
213 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 1); | ||
214 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 0); | ||
215 | |||
216 | /* init LCD phase 9 */ | ||
217 | epson_sendbyte(0, 0xAF); | ||
218 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 1); | ||
219 | } | ||
220 | |||
221 | static int sx1_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev) | ||
222 | { | ||
223 | return 0; | ||
224 | } | ||
225 | |||
226 | static void sx1_panel_cleanup(struct lcd_panel *panel) | ||
227 | { | ||
228 | } | ||
229 | |||
230 | static void sx1_panel_disable(struct lcd_panel *panel) | ||
231 | { | ||
232 | printk(KERN_INFO "SX1: LCD panel disable\n"); | ||
233 | sx1_setmmipower(0); | ||
234 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 1); | ||
235 | |||
236 | epson_sendbyte(0, 0x25); | ||
237 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 0); | ||
238 | |||
239 | epson_sendbyte(0, 0xAE); | ||
240 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 1); | ||
241 | mdelay(100); | ||
242 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 0); | ||
243 | |||
244 | epson_sendbyte(0, 0x95); | ||
245 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 1); | ||
246 | } | ||
247 | |||
248 | static int sx1_panel_enable(struct lcd_panel *panel) | ||
249 | { | ||
250 | printk(KERN_INFO "lcd_sx1: LCD panel enable\n"); | ||
251 | init_system(); | ||
252 | display_init(); | ||
253 | |||
254 | sx1_setmmipower(1); | ||
255 | sx1_setbacklight(0x18); | ||
256 | sx1_setkeylight (0x06); | ||
257 | return 0; | ||
258 | } | ||
259 | |||
260 | |||
261 | static unsigned long sx1_panel_get_caps(struct lcd_panel *panel) | ||
262 | { | ||
263 | return 0; | ||
264 | } | ||
265 | |||
266 | struct lcd_panel sx1_panel = { | ||
267 | .name = "sx1", | ||
268 | .config = OMAP_LCDC_PANEL_TFT | OMAP_LCDC_INV_VSYNC | | ||
269 | OMAP_LCDC_INV_HSYNC | OMAP_LCDC_INV_PIX_CLOCK | | ||
270 | OMAP_LCDC_INV_OUTPUT_EN, | ||
271 | |||
272 | .x_res = 176, | ||
273 | .y_res = 220, | ||
274 | .data_lines = 16, | ||
275 | .bpp = 16, | ||
276 | .hsw = 5, | ||
277 | .hfp = 5, | ||
278 | .hbp = 5, | ||
279 | .vsw = 2, | ||
280 | .vfp = 1, | ||
281 | .vbp = 1, | ||
282 | .pixel_clock = 1500, | ||
283 | |||
284 | .init = sx1_panel_init, | ||
285 | .cleanup = sx1_panel_cleanup, | ||
286 | .enable = sx1_panel_enable, | ||
287 | .disable = sx1_panel_disable, | ||
288 | .get_caps = sx1_panel_get_caps, | ||
289 | }; | ||
290 | |||
291 | static int sx1_panel_probe(struct platform_device *pdev) | ||
292 | { | ||
293 | omapfb_register_panel(&sx1_panel); | ||
294 | return 0; | ||
295 | } | ||
296 | |||
297 | static int sx1_panel_remove(struct platform_device *pdev) | ||
298 | { | ||
299 | return 0; | ||
300 | } | ||
301 | |||
302 | static int sx1_panel_suspend(struct platform_device *pdev, pm_message_t mesg) | ||
303 | { | ||
304 | return 0; | ||
305 | } | ||
306 | |||
307 | static int sx1_panel_resume(struct platform_device *pdev) | ||
308 | { | ||
309 | return 0; | ||
310 | } | ||
311 | |||
312 | struct platform_driver sx1_panel_driver = { | ||
313 | .probe = sx1_panel_probe, | ||
314 | .remove = sx1_panel_remove, | ||
315 | .suspend = sx1_panel_suspend, | ||
316 | .resume = sx1_panel_resume, | ||
317 | .driver = { | ||
318 | .name = "lcd_sx1", | ||
319 | .owner = THIS_MODULE, | ||
320 | }, | ||
321 | }; | ||
322 | |||
323 | static int sx1_panel_drv_init(void) | ||
324 | { | ||
325 | return platform_driver_register(&sx1_panel_driver); | ||
326 | } | ||
327 | |||
328 | static void sx1_panel_drv_cleanup(void) | ||
329 | { | ||
330 | platform_driver_unregister(&sx1_panel_driver); | ||
331 | } | ||
332 | |||
333 | module_init(sx1_panel_drv_init); | ||
334 | module_exit(sx1_panel_drv_cleanup); | ||
diff --git a/drivers/video/omap/lcdc.c b/drivers/video/omap/lcdc.c new file mode 100644 index 000000000000..9085188d815e --- /dev/null +++ b/drivers/video/omap/lcdc.c | |||
@@ -0,0 +1,893 @@ | |||
1 | /* | ||
2 | * OMAP1 internal LCD controller | ||
3 | * | ||
4 | * Copyright (C) 2004 Nokia Corporation | ||
5 | * Author: Imre Deak <imre.deak@nokia.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License along | ||
18 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
19 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
20 | */ | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/device.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/spinlock.h> | ||
25 | #include <linux/err.h> | ||
26 | #include <linux/mm.h> | ||
27 | #include <linux/fb.h> | ||
28 | #include <linux/dma-mapping.h> | ||
29 | #include <linux/vmalloc.h> | ||
30 | #include <linux/clk.h> | ||
31 | |||
32 | #include <asm/arch/dma.h> | ||
33 | #include <asm/arch/omapfb.h> | ||
34 | |||
35 | #include <asm/mach-types.h> | ||
36 | |||
37 | #define MODULE_NAME "lcdc" | ||
38 | |||
39 | #define OMAP_LCDC_BASE 0xfffec000 | ||
40 | #define OMAP_LCDC_SIZE 256 | ||
41 | #define OMAP_LCDC_IRQ INT_LCD_CTRL | ||
42 | |||
43 | #define OMAP_LCDC_CONTROL (OMAP_LCDC_BASE + 0x00) | ||
44 | #define OMAP_LCDC_TIMING0 (OMAP_LCDC_BASE + 0x04) | ||
45 | #define OMAP_LCDC_TIMING1 (OMAP_LCDC_BASE + 0x08) | ||
46 | #define OMAP_LCDC_TIMING2 (OMAP_LCDC_BASE + 0x0c) | ||
47 | #define OMAP_LCDC_STATUS (OMAP_LCDC_BASE + 0x10) | ||
48 | #define OMAP_LCDC_SUBPANEL (OMAP_LCDC_BASE + 0x14) | ||
49 | #define OMAP_LCDC_LINE_INT (OMAP_LCDC_BASE + 0x18) | ||
50 | #define OMAP_LCDC_DISPLAY_STATUS (OMAP_LCDC_BASE + 0x1c) | ||
51 | |||
52 | #define OMAP_LCDC_STAT_DONE (1 << 0) | ||
53 | #define OMAP_LCDC_STAT_VSYNC (1 << 1) | ||
54 | #define OMAP_LCDC_STAT_SYNC_LOST (1 << 2) | ||
55 | #define OMAP_LCDC_STAT_ABC (1 << 3) | ||
56 | #define OMAP_LCDC_STAT_LINE_INT (1 << 4) | ||
57 | #define OMAP_LCDC_STAT_FUF (1 << 5) | ||
58 | #define OMAP_LCDC_STAT_LOADED_PALETTE (1 << 6) | ||
59 | |||
60 | #define OMAP_LCDC_CTRL_LCD_EN (1 << 0) | ||
61 | #define OMAP_LCDC_CTRL_LCD_TFT (1 << 7) | ||
62 | #define OMAP_LCDC_CTRL_LINE_IRQ_CLR_SEL (1 << 10) | ||
63 | |||
64 | #define OMAP_LCDC_IRQ_VSYNC (1 << 2) | ||
65 | #define OMAP_LCDC_IRQ_DONE (1 << 3) | ||
66 | #define OMAP_LCDC_IRQ_LOADED_PALETTE (1 << 4) | ||
67 | #define OMAP_LCDC_IRQ_LINE_NIRQ (1 << 5) | ||
68 | #define OMAP_LCDC_IRQ_LINE (1 << 6) | ||
69 | #define OMAP_LCDC_IRQ_MASK (((1 << 5) - 1) << 2) | ||
70 | |||
71 | #define MAX_PALETTE_SIZE PAGE_SIZE | ||
72 | |||
73 | enum lcdc_load_mode { | ||
74 | OMAP_LCDC_LOAD_PALETTE, | ||
75 | OMAP_LCDC_LOAD_FRAME, | ||
76 | OMAP_LCDC_LOAD_PALETTE_AND_FRAME | ||
77 | }; | ||
78 | |||
79 | static struct omap_lcd_controller { | ||
80 | enum omapfb_update_mode update_mode; | ||
81 | int ext_mode; | ||
82 | |||
83 | unsigned long frame_offset; | ||
84 | int screen_width; | ||
85 | int xres; | ||
86 | int yres; | ||
87 | |||
88 | enum omapfb_color_format color_mode; | ||
89 | int bpp; | ||
90 | void *palette_virt; | ||
91 | dma_addr_t palette_phys; | ||
92 | int palette_code; | ||
93 | int palette_size; | ||
94 | |||
95 | unsigned int irq_mask; | ||
96 | struct completion last_frame_complete; | ||
97 | struct completion palette_load_complete; | ||
98 | struct clk *lcd_ck; | ||
99 | struct omapfb_device *fbdev; | ||
100 | |||
101 | void (*dma_callback)(void *data); | ||
102 | void *dma_callback_data; | ||
103 | |||
104 | int fbmem_allocated; | ||
105 | dma_addr_t vram_phys; | ||
106 | void *vram_virt; | ||
107 | unsigned long vram_size; | ||
108 | } lcdc; | ||
109 | |||
110 | static void inline enable_irqs(int mask) | ||
111 | { | ||
112 | lcdc.irq_mask |= mask; | ||
113 | } | ||
114 | |||
115 | static void inline disable_irqs(int mask) | ||
116 | { | ||
117 | lcdc.irq_mask &= ~mask; | ||
118 | } | ||
119 | |||
120 | static void set_load_mode(enum lcdc_load_mode mode) | ||
121 | { | ||
122 | u32 l; | ||
123 | |||
124 | l = omap_readl(OMAP_LCDC_CONTROL); | ||
125 | l &= ~(3 << 20); | ||
126 | switch (mode) { | ||
127 | case OMAP_LCDC_LOAD_PALETTE: | ||
128 | l |= 1 << 20; | ||
129 | break; | ||
130 | case OMAP_LCDC_LOAD_FRAME: | ||
131 | l |= 2 << 20; | ||
132 | break; | ||
133 | case OMAP_LCDC_LOAD_PALETTE_AND_FRAME: | ||
134 | break; | ||
135 | default: | ||
136 | BUG(); | ||
137 | } | ||
138 | omap_writel(l, OMAP_LCDC_CONTROL); | ||
139 | } | ||
140 | |||
141 | static void enable_controller(void) | ||
142 | { | ||
143 | u32 l; | ||
144 | |||
145 | l = omap_readl(OMAP_LCDC_CONTROL); | ||
146 | l |= OMAP_LCDC_CTRL_LCD_EN; | ||
147 | l &= ~OMAP_LCDC_IRQ_MASK; | ||
148 | l |= lcdc.irq_mask | OMAP_LCDC_IRQ_DONE; /* enabled IRQs */ | ||
149 | omap_writel(l, OMAP_LCDC_CONTROL); | ||
150 | } | ||
151 | |||
152 | static void disable_controller_async(void) | ||
153 | { | ||
154 | u32 l; | ||
155 | u32 mask; | ||
156 | |||
157 | l = omap_readl(OMAP_LCDC_CONTROL); | ||
158 | mask = OMAP_LCDC_CTRL_LCD_EN | OMAP_LCDC_IRQ_MASK; | ||
159 | /* | ||
160 | * Preserve the DONE mask, since we still want to get the | ||
161 | * final DONE irq. It will be disabled in the IRQ handler. | ||
162 | */ | ||
163 | mask &= ~OMAP_LCDC_IRQ_DONE; | ||
164 | l &= ~mask; | ||
165 | omap_writel(l, OMAP_LCDC_CONTROL); | ||
166 | } | ||
167 | |||
168 | static void disable_controller(void) | ||
169 | { | ||
170 | init_completion(&lcdc.last_frame_complete); | ||
171 | disable_controller_async(); | ||
172 | if (!wait_for_completion_timeout(&lcdc.last_frame_complete, | ||
173 | msecs_to_jiffies(500))) | ||
174 | dev_err(lcdc.fbdev->dev, "timeout waiting for FRAME DONE\n"); | ||
175 | } | ||
176 | |||
177 | static void reset_controller(u32 status) | ||
178 | { | ||
179 | static unsigned long reset_count; | ||
180 | static unsigned long last_jiffies; | ||
181 | |||
182 | disable_controller_async(); | ||
183 | reset_count++; | ||
184 | if (reset_count == 1 || time_after(jiffies, last_jiffies + HZ)) { | ||
185 | dev_err(lcdc.fbdev->dev, | ||
186 | "resetting (status %#010x,reset count %lu)\n", | ||
187 | status, reset_count); | ||
188 | last_jiffies = jiffies; | ||
189 | } | ||
190 | if (reset_count < 100) { | ||
191 | enable_controller(); | ||
192 | } else { | ||
193 | reset_count = 0; | ||
194 | dev_err(lcdc.fbdev->dev, | ||
195 | "too many reset attempts, giving up.\n"); | ||
196 | } | ||
197 | } | ||
198 | |||
199 | /* | ||
200 | * Configure the LCD DMA according to the current mode specified by parameters | ||
201 | * in lcdc.fbdev and fbdev->var. | ||
202 | */ | ||
203 | static void setup_lcd_dma(void) | ||
204 | { | ||
205 | static const int dma_elem_type[] = { | ||
206 | 0, | ||
207 | OMAP_DMA_DATA_TYPE_S8, | ||
208 | OMAP_DMA_DATA_TYPE_S16, | ||
209 | 0, | ||
210 | OMAP_DMA_DATA_TYPE_S32, | ||
211 | }; | ||
212 | struct omapfb_plane_struct *plane = lcdc.fbdev->fb_info[0]->par; | ||
213 | struct fb_var_screeninfo *var = &lcdc.fbdev->fb_info[0]->var; | ||
214 | unsigned long src; | ||
215 | int esize, xelem, yelem; | ||
216 | |||
217 | src = lcdc.vram_phys + lcdc.frame_offset; | ||
218 | |||
219 | switch (var->rotate) { | ||
220 | case 0: | ||
221 | if (plane->info.mirror || (src & 3) || | ||
222 | lcdc.color_mode == OMAPFB_COLOR_YUV420 || | ||
223 | (lcdc.xres & 1)) | ||
224 | esize = 2; | ||
225 | else | ||
226 | esize = 4; | ||
227 | xelem = lcdc.xres * lcdc.bpp / 8 / esize; | ||
228 | yelem = lcdc.yres; | ||
229 | break; | ||
230 | case 90: | ||
231 | case 180: | ||
232 | case 270: | ||
233 | if (cpu_is_omap15xx()) { | ||
234 | BUG(); | ||
235 | } | ||
236 | esize = 2; | ||
237 | xelem = lcdc.yres * lcdc.bpp / 16; | ||
238 | yelem = lcdc.xres; | ||
239 | break; | ||
240 | default: | ||
241 | BUG(); | ||
242 | return; | ||
243 | } | ||
244 | #ifdef VERBOSE | ||
245 | dev_dbg(lcdc.fbdev->dev, | ||
246 | "setup_dma: src %#010lx esize %d xelem %d yelem %d\n", | ||
247 | src, esize, xelem, yelem); | ||
248 | #endif | ||
249 | omap_set_lcd_dma_b1(src, xelem, yelem, dma_elem_type[esize]); | ||
250 | if (!cpu_is_omap15xx()) { | ||
251 | int bpp = lcdc.bpp; | ||
252 | |||
253 | /* | ||
254 | * YUV support is only for external mode when we have the | ||
255 | * YUV window embedded in a 16bpp frame buffer. | ||
256 | */ | ||
257 | if (lcdc.color_mode == OMAPFB_COLOR_YUV420) | ||
258 | bpp = 16; | ||
259 | /* Set virtual xres elem size */ | ||
260 | omap_set_lcd_dma_b1_vxres( | ||
261 | lcdc.screen_width * bpp / 8 / esize); | ||
262 | /* Setup transformations */ | ||
263 | omap_set_lcd_dma_b1_rotation(var->rotate); | ||
264 | omap_set_lcd_dma_b1_mirror(plane->info.mirror); | ||
265 | } | ||
266 | omap_setup_lcd_dma(); | ||
267 | } | ||
268 | |||
269 | static irqreturn_t lcdc_irq_handler(int irq, void *dev_id) | ||
270 | { | ||
271 | u32 status; | ||
272 | |||
273 | status = omap_readl(OMAP_LCDC_STATUS); | ||
274 | |||
275 | if (status & (OMAP_LCDC_STAT_FUF | OMAP_LCDC_STAT_SYNC_LOST)) | ||
276 | reset_controller(status); | ||
277 | else { | ||
278 | if (status & OMAP_LCDC_STAT_DONE) { | ||
279 | u32 l; | ||
280 | |||
281 | /* | ||
282 | * Disable IRQ_DONE. The status bit will be cleared | ||
283 | * only when the controller is reenabled and we don't | ||
284 | * want to get more interrupts. | ||
285 | */ | ||
286 | l = omap_readl(OMAP_LCDC_CONTROL); | ||
287 | l &= ~OMAP_LCDC_IRQ_DONE; | ||
288 | omap_writel(l, OMAP_LCDC_CONTROL); | ||
289 | complete(&lcdc.last_frame_complete); | ||
290 | } | ||
291 | if (status & OMAP_LCDC_STAT_LOADED_PALETTE) { | ||
292 | disable_controller_async(); | ||
293 | complete(&lcdc.palette_load_complete); | ||
294 | } | ||
295 | } | ||
296 | |||
297 | /* | ||
298 | * Clear these interrupt status bits. | ||
299 | * Sync_lost, FUF bits were cleared by disabling the LCD controller | ||
300 | * LOADED_PALETTE can be cleared this way only in palette only | ||
301 | * load mode. In other load modes it's cleared by disabling the | ||
302 | * controller. | ||
303 | */ | ||
304 | status &= ~(OMAP_LCDC_STAT_VSYNC | | ||
305 | OMAP_LCDC_STAT_LOADED_PALETTE | | ||
306 | OMAP_LCDC_STAT_ABC | | ||
307 | OMAP_LCDC_STAT_LINE_INT); | ||
308 | omap_writel(status, OMAP_LCDC_STATUS); | ||
309 | return IRQ_HANDLED; | ||
310 | } | ||
311 | |||
312 | /* | ||
313 | * Change to a new video mode. We defer this to a later time to avoid any | ||
314 | * flicker and not to mess up the current LCD DMA context. For this we disable | ||
315 | * the LCD controler, which will generate a DONE irq after the last frame has | ||
316 | * been transferred. Then it'll be safe to reconfigure both the LCD controller | ||
317 | * as well as the LCD DMA. | ||
318 | */ | ||
319 | static int omap_lcdc_setup_plane(int plane, int channel_out, | ||
320 | unsigned long offset, int screen_width, | ||
321 | int pos_x, int pos_y, int width, int height, | ||
322 | int color_mode) | ||
323 | { | ||
324 | struct fb_var_screeninfo *var = &lcdc.fbdev->fb_info[0]->var; | ||
325 | struct lcd_panel *panel = lcdc.fbdev->panel; | ||
326 | int rot_x, rot_y; | ||
327 | |||
328 | if (var->rotate == 0) { | ||
329 | rot_x = panel->x_res; | ||
330 | rot_y = panel->y_res; | ||
331 | } else { | ||
332 | rot_x = panel->y_res; | ||
333 | rot_y = panel->x_res; | ||
334 | } | ||
335 | if (plane != 0 || channel_out != 0 || pos_x != 0 || pos_y != 0 || | ||
336 | width > rot_x || height > rot_y) { | ||
337 | #ifdef VERBOSE | ||
338 | dev_dbg(lcdc.fbdev->dev, | ||
339 | "invalid plane params plane %d pos_x %d pos_y %d " | ||
340 | "w %d h %d\n", plane, pos_x, pos_y, width, height); | ||
341 | #endif | ||
342 | return -EINVAL; | ||
343 | } | ||
344 | |||
345 | lcdc.frame_offset = offset; | ||
346 | lcdc.xres = width; | ||
347 | lcdc.yres = height; | ||
348 | lcdc.screen_width = screen_width; | ||
349 | lcdc.color_mode = color_mode; | ||
350 | |||
351 | switch (color_mode) { | ||
352 | case OMAPFB_COLOR_CLUT_8BPP: | ||
353 | lcdc.bpp = 8; | ||
354 | lcdc.palette_code = 0x3000; | ||
355 | lcdc.palette_size = 512; | ||
356 | break; | ||
357 | case OMAPFB_COLOR_RGB565: | ||
358 | lcdc.bpp = 16; | ||
359 | lcdc.palette_code = 0x4000; | ||
360 | lcdc.palette_size = 32; | ||
361 | break; | ||
362 | case OMAPFB_COLOR_RGB444: | ||
363 | lcdc.bpp = 16; | ||
364 | lcdc.palette_code = 0x4000; | ||
365 | lcdc.palette_size = 32; | ||
366 | break; | ||
367 | case OMAPFB_COLOR_YUV420: | ||
368 | if (lcdc.ext_mode) { | ||
369 | lcdc.bpp = 12; | ||
370 | break; | ||
371 | } | ||
372 | /* fallthrough */ | ||
373 | case OMAPFB_COLOR_YUV422: | ||
374 | if (lcdc.ext_mode) { | ||
375 | lcdc.bpp = 16; | ||
376 | break; | ||
377 | } | ||
378 | /* fallthrough */ | ||
379 | default: | ||
380 | /* FIXME: other BPPs. | ||
381 | * bpp1: code 0, size 256 | ||
382 | * bpp2: code 0x1000 size 256 | ||
383 | * bpp4: code 0x2000 size 256 | ||
384 | * bpp12: code 0x4000 size 32 | ||
385 | */ | ||
386 | dev_dbg(lcdc.fbdev->dev, "invalid color mode %d\n", color_mode); | ||
387 | BUG(); | ||
388 | return -1; | ||
389 | } | ||
390 | |||
391 | if (lcdc.ext_mode) { | ||
392 | setup_lcd_dma(); | ||
393 | return 0; | ||
394 | } | ||
395 | |||
396 | if (lcdc.update_mode == OMAPFB_AUTO_UPDATE) { | ||
397 | disable_controller(); | ||
398 | omap_stop_lcd_dma(); | ||
399 | setup_lcd_dma(); | ||
400 | enable_controller(); | ||
401 | } | ||
402 | |||
403 | return 0; | ||
404 | } | ||
405 | |||
406 | static int omap_lcdc_enable_plane(int plane, int enable) | ||
407 | { | ||
408 | dev_dbg(lcdc.fbdev->dev, | ||
409 | "plane %d enable %d update_mode %d ext_mode %d\n", | ||
410 | plane, enable, lcdc.update_mode, lcdc.ext_mode); | ||
411 | if (plane != OMAPFB_PLANE_GFX) | ||
412 | return -EINVAL; | ||
413 | |||
414 | return 0; | ||
415 | } | ||
416 | |||
417 | /* | ||
418 | * Configure the LCD DMA for a palette load operation and do the palette | ||
419 | * downloading synchronously. We don't use the frame+palette load mode of | ||
420 | * the controller, since the palette can always be downloaded seperately. | ||
421 | */ | ||
422 | static void load_palette(void) | ||
423 | { | ||
424 | u16 *palette; | ||
425 | |||
426 | palette = (u16 *)lcdc.palette_virt; | ||
427 | |||
428 | *(u16 *)palette &= 0x0fff; | ||
429 | *(u16 *)palette |= lcdc.palette_code; | ||
430 | |||
431 | omap_set_lcd_dma_b1(lcdc.palette_phys, | ||
432 | lcdc.palette_size / 4 + 1, 1, OMAP_DMA_DATA_TYPE_S32); | ||
433 | |||
434 | omap_set_lcd_dma_single_transfer(1); | ||
435 | omap_setup_lcd_dma(); | ||
436 | |||
437 | init_completion(&lcdc.palette_load_complete); | ||
438 | enable_irqs(OMAP_LCDC_IRQ_LOADED_PALETTE); | ||
439 | set_load_mode(OMAP_LCDC_LOAD_PALETTE); | ||
440 | enable_controller(); | ||
441 | if (!wait_for_completion_timeout(&lcdc.palette_load_complete, | ||
442 | msecs_to_jiffies(500))) | ||
443 | dev_err(lcdc.fbdev->dev, "timeout waiting for FRAME DONE\n"); | ||
444 | /* The controller gets disabled in the irq handler */ | ||
445 | disable_irqs(OMAP_LCDC_IRQ_LOADED_PALETTE); | ||
446 | omap_stop_lcd_dma(); | ||
447 | |||
448 | omap_set_lcd_dma_single_transfer(lcdc.ext_mode); | ||
449 | } | ||
450 | |||
451 | /* Used only in internal controller mode */ | ||
452 | static int omap_lcdc_setcolreg(u_int regno, u16 red, u16 green, u16 blue, | ||
453 | u16 transp, int update_hw_pal) | ||
454 | { | ||
455 | u16 *palette; | ||
456 | |||
457 | if (lcdc.color_mode != OMAPFB_COLOR_CLUT_8BPP || regno > 255) | ||
458 | return -EINVAL; | ||
459 | |||
460 | palette = (u16 *)lcdc.palette_virt; | ||
461 | |||
462 | palette[regno] &= ~0x0fff; | ||
463 | palette[regno] |= ((red >> 12) << 8) | ((green >> 12) << 4 ) | | ||
464 | (blue >> 12); | ||
465 | |||
466 | if (update_hw_pal) { | ||
467 | disable_controller(); | ||
468 | omap_stop_lcd_dma(); | ||
469 | load_palette(); | ||
470 | setup_lcd_dma(); | ||
471 | set_load_mode(OMAP_LCDC_LOAD_FRAME); | ||
472 | enable_controller(); | ||
473 | } | ||
474 | |||
475 | return 0; | ||
476 | } | ||
477 | |||
478 | static void calc_ck_div(int is_tft, int pck, int *pck_div) | ||
479 | { | ||
480 | unsigned long lck; | ||
481 | |||
482 | pck = max(1, pck); | ||
483 | lck = clk_get_rate(lcdc.lcd_ck); | ||
484 | *pck_div = (lck + pck - 1) / pck; | ||
485 | if (is_tft) | ||
486 | *pck_div = max(2, *pck_div); | ||
487 | else | ||
488 | *pck_div = max(3, *pck_div); | ||
489 | if (*pck_div > 255) { | ||
490 | /* FIXME: try to adjust logic clock divider as well */ | ||
491 | *pck_div = 255; | ||
492 | dev_warn(lcdc.fbdev->dev, "pixclock %d kHz too low.\n", | ||
493 | pck / 1000); | ||
494 | } | ||
495 | } | ||
496 | |||
497 | static void inline setup_regs(void) | ||
498 | { | ||
499 | u32 l; | ||
500 | struct lcd_panel *panel = lcdc.fbdev->panel; | ||
501 | int is_tft = panel->config & OMAP_LCDC_PANEL_TFT; | ||
502 | unsigned long lck; | ||
503 | int pcd; | ||
504 | |||
505 | l = omap_readl(OMAP_LCDC_CONTROL); | ||
506 | l &= ~OMAP_LCDC_CTRL_LCD_TFT; | ||
507 | l |= is_tft ? OMAP_LCDC_CTRL_LCD_TFT : 0; | ||
508 | #ifdef CONFIG_MACH_OMAP_PALMTE | ||
509 | /* FIXME:if (machine_is_omap_palmte()) { */ | ||
510 | /* PalmTE uses alternate TFT setting in 8BPP mode */ | ||
511 | l |= (is_tft && panel->bpp == 8) ? 0x810000 : 0; | ||
512 | /* } */ | ||
513 | #endif | ||
514 | omap_writel(l, OMAP_LCDC_CONTROL); | ||
515 | |||
516 | l = omap_readl(OMAP_LCDC_TIMING2); | ||
517 | l &= ~(((1 << 6) - 1) << 20); | ||
518 | l |= (panel->config & OMAP_LCDC_SIGNAL_MASK) << 20; | ||
519 | omap_writel(l, OMAP_LCDC_TIMING2); | ||
520 | |||
521 | l = panel->x_res - 1; | ||
522 | l |= (panel->hsw - 1) << 10; | ||
523 | l |= (panel->hfp - 1) << 16; | ||
524 | l |= (panel->hbp - 1) << 24; | ||
525 | omap_writel(l, OMAP_LCDC_TIMING0); | ||
526 | |||
527 | l = panel->y_res - 1; | ||
528 | l |= (panel->vsw - 1) << 10; | ||
529 | l |= panel->vfp << 16; | ||
530 | l |= panel->vbp << 24; | ||
531 | omap_writel(l, OMAP_LCDC_TIMING1); | ||
532 | |||
533 | l = omap_readl(OMAP_LCDC_TIMING2); | ||
534 | l &= ~0xff; | ||
535 | |||
536 | lck = clk_get_rate(lcdc.lcd_ck); | ||
537 | |||
538 | if (!panel->pcd) | ||
539 | calc_ck_div(is_tft, panel->pixel_clock * 1000, &pcd); | ||
540 | else { | ||
541 | dev_warn(lcdc.fbdev->dev, | ||
542 | "Pixel clock divider value is obsolete.\n" | ||
543 | "Try to set pixel_clock to %lu and pcd to 0 " | ||
544 | "in drivers/video/omap/lcd_%s.c and submit a patch.\n", | ||
545 | lck / panel->pcd / 1000, panel->name); | ||
546 | |||
547 | pcd = panel->pcd; | ||
548 | } | ||
549 | l |= pcd & 0xff; | ||
550 | l |= panel->acb << 8; | ||
551 | omap_writel(l, OMAP_LCDC_TIMING2); | ||
552 | |||
553 | /* update panel info with the exact clock */ | ||
554 | panel->pixel_clock = lck / pcd / 1000; | ||
555 | } | ||
556 | |||
557 | /* | ||
558 | * Configure the LCD controller, download the color palette and start a looped | ||
559 | * DMA transfer of the frame image data. Called only in internal | ||
560 | * controller mode. | ||
561 | */ | ||
562 | static int omap_lcdc_set_update_mode(enum omapfb_update_mode mode) | ||
563 | { | ||
564 | int r = 0; | ||
565 | |||
566 | if (mode != lcdc.update_mode) { | ||
567 | switch (mode) { | ||
568 | case OMAPFB_AUTO_UPDATE: | ||
569 | setup_regs(); | ||
570 | load_palette(); | ||
571 | |||
572 | /* Setup and start LCD DMA */ | ||
573 | setup_lcd_dma(); | ||
574 | |||
575 | set_load_mode(OMAP_LCDC_LOAD_FRAME); | ||
576 | enable_irqs(OMAP_LCDC_IRQ_DONE); | ||
577 | /* This will start the actual DMA transfer */ | ||
578 | enable_controller(); | ||
579 | lcdc.update_mode = mode; | ||
580 | break; | ||
581 | case OMAPFB_UPDATE_DISABLED: | ||
582 | disable_controller(); | ||
583 | omap_stop_lcd_dma(); | ||
584 | lcdc.update_mode = mode; | ||
585 | break; | ||
586 | default: | ||
587 | r = -EINVAL; | ||
588 | } | ||
589 | } | ||
590 | |||
591 | return r; | ||
592 | } | ||
593 | |||
594 | static enum omapfb_update_mode omap_lcdc_get_update_mode(void) | ||
595 | { | ||
596 | return lcdc.update_mode; | ||
597 | } | ||
598 | |||
599 | /* PM code called only in internal controller mode */ | ||
600 | static void omap_lcdc_suspend(void) | ||
601 | { | ||
602 | if (lcdc.update_mode == OMAPFB_AUTO_UPDATE) { | ||
603 | disable_controller(); | ||
604 | omap_stop_lcd_dma(); | ||
605 | } | ||
606 | } | ||
607 | |||
608 | static void omap_lcdc_resume(void) | ||
609 | { | ||
610 | if (lcdc.update_mode == OMAPFB_AUTO_UPDATE) { | ||
611 | setup_regs(); | ||
612 | load_palette(); | ||
613 | setup_lcd_dma(); | ||
614 | set_load_mode(OMAP_LCDC_LOAD_FRAME); | ||
615 | enable_irqs(OMAP_LCDC_IRQ_DONE); | ||
616 | enable_controller(); | ||
617 | } | ||
618 | } | ||
619 | |||
620 | static void omap_lcdc_get_caps(int plane, struct omapfb_caps *caps) | ||
621 | { | ||
622 | return; | ||
623 | } | ||
624 | |||
625 | int omap_lcdc_set_dma_callback(void (*callback)(void *data), void *data) | ||
626 | { | ||
627 | BUG_ON(callback == NULL); | ||
628 | |||
629 | if (lcdc.dma_callback) | ||
630 | return -EBUSY; | ||
631 | else { | ||
632 | lcdc.dma_callback = callback; | ||
633 | lcdc.dma_callback_data = data; | ||
634 | } | ||
635 | return 0; | ||
636 | } | ||
637 | EXPORT_SYMBOL(omap_lcdc_set_dma_callback); | ||
638 | |||
639 | void omap_lcdc_free_dma_callback(void) | ||
640 | { | ||
641 | lcdc.dma_callback = NULL; | ||
642 | } | ||
643 | EXPORT_SYMBOL(omap_lcdc_free_dma_callback); | ||
644 | |||
645 | static void lcdc_dma_handler(u16 status, void *data) | ||
646 | { | ||
647 | if (lcdc.dma_callback) | ||
648 | lcdc.dma_callback(lcdc.dma_callback_data); | ||
649 | } | ||
650 | |||
651 | static int mmap_kern(void) | ||
652 | { | ||
653 | struct vm_struct *kvma; | ||
654 | struct vm_area_struct vma; | ||
655 | pgprot_t pgprot; | ||
656 | unsigned long vaddr; | ||
657 | |||
658 | kvma = get_vm_area(lcdc.vram_size, VM_IOREMAP); | ||
659 | if (kvma == NULL) { | ||
660 | dev_err(lcdc.fbdev->dev, "can't get kernel vm area\n"); | ||
661 | return -ENOMEM; | ||
662 | } | ||
663 | vma.vm_mm = &init_mm; | ||
664 | |||
665 | vaddr = (unsigned long)kvma->addr; | ||
666 | vma.vm_start = vaddr; | ||
667 | vma.vm_end = vaddr + lcdc.vram_size; | ||
668 | |||
669 | pgprot = pgprot_writecombine(pgprot_kernel); | ||
670 | if (io_remap_pfn_range(&vma, vaddr, | ||
671 | lcdc.vram_phys >> PAGE_SHIFT, | ||
672 | lcdc.vram_size, pgprot) < 0) { | ||
673 | dev_err(lcdc.fbdev->dev, "kernel mmap for FB memory failed\n"); | ||
674 | return -EAGAIN; | ||
675 | } | ||
676 | |||
677 | lcdc.vram_virt = (void *)vaddr; | ||
678 | |||
679 | return 0; | ||
680 | } | ||
681 | |||
682 | static void unmap_kern(void) | ||
683 | { | ||
684 | vunmap(lcdc.vram_virt); | ||
685 | } | ||
686 | |||
687 | static int alloc_palette_ram(void) | ||
688 | { | ||
689 | lcdc.palette_virt = dma_alloc_writecombine(lcdc.fbdev->dev, | ||
690 | MAX_PALETTE_SIZE, &lcdc.palette_phys, GFP_KERNEL); | ||
691 | if (lcdc.palette_virt == NULL) { | ||
692 | dev_err(lcdc.fbdev->dev, "failed to alloc palette memory\n"); | ||
693 | return -ENOMEM; | ||
694 | } | ||
695 | memset(lcdc.palette_virt, 0, MAX_PALETTE_SIZE); | ||
696 | |||
697 | return 0; | ||
698 | } | ||
699 | |||
700 | static void free_palette_ram(void) | ||
701 | { | ||
702 | dma_free_writecombine(lcdc.fbdev->dev, MAX_PALETTE_SIZE, | ||
703 | lcdc.palette_virt, lcdc.palette_phys); | ||
704 | } | ||
705 | |||
706 | static int alloc_fbmem(struct omapfb_mem_region *region) | ||
707 | { | ||
708 | int bpp; | ||
709 | int frame_size; | ||
710 | struct lcd_panel *panel = lcdc.fbdev->panel; | ||
711 | |||
712 | bpp = panel->bpp; | ||
713 | if (bpp == 12) | ||
714 | bpp = 16; | ||
715 | frame_size = PAGE_ALIGN(panel->x_res * bpp / 8 * panel->y_res); | ||
716 | if (region->size > frame_size) | ||
717 | frame_size = region->size; | ||
718 | lcdc.vram_size = frame_size; | ||
719 | lcdc.vram_virt = dma_alloc_writecombine(lcdc.fbdev->dev, | ||
720 | lcdc.vram_size, &lcdc.vram_phys, GFP_KERNEL); | ||
721 | if (lcdc.vram_virt == NULL) { | ||
722 | dev_err(lcdc.fbdev->dev, "unable to allocate FB DMA memory\n"); | ||
723 | return -ENOMEM; | ||
724 | } | ||
725 | region->size = frame_size; | ||
726 | region->paddr = lcdc.vram_phys; | ||
727 | region->vaddr = lcdc.vram_virt; | ||
728 | region->alloc = 1; | ||
729 | |||
730 | memset(lcdc.vram_virt, 0, lcdc.vram_size); | ||
731 | |||
732 | return 0; | ||
733 | } | ||
734 | |||
735 | static void free_fbmem(void) | ||
736 | { | ||
737 | dma_free_writecombine(lcdc.fbdev->dev, lcdc.vram_size, | ||
738 | lcdc.vram_virt, lcdc.vram_phys); | ||
739 | } | ||
740 | |||
741 | static int setup_fbmem(struct omapfb_mem_desc *req_md) | ||
742 | { | ||
743 | int r; | ||
744 | |||
745 | if (!req_md->region_cnt) { | ||
746 | dev_err(lcdc.fbdev->dev, "no memory regions defined\n"); | ||
747 | return -EINVAL; | ||
748 | } | ||
749 | |||
750 | if (req_md->region_cnt > 1) { | ||
751 | dev_err(lcdc.fbdev->dev, "only one plane is supported\n"); | ||
752 | req_md->region_cnt = 1; | ||
753 | } | ||
754 | |||
755 | if (req_md->region[0].paddr == 0) { | ||
756 | lcdc.fbmem_allocated = 1; | ||
757 | if ((r = alloc_fbmem(&req_md->region[0])) < 0) | ||
758 | return r; | ||
759 | return 0; | ||
760 | } | ||
761 | |||
762 | lcdc.vram_phys = req_md->region[0].paddr; | ||
763 | lcdc.vram_size = req_md->region[0].size; | ||
764 | |||
765 | if ((r = mmap_kern()) < 0) | ||
766 | return r; | ||
767 | |||
768 | dev_dbg(lcdc.fbdev->dev, "vram at %08x size %08lx mapped to 0x%p\n", | ||
769 | lcdc.vram_phys, lcdc.vram_size, lcdc.vram_virt); | ||
770 | |||
771 | return 0; | ||
772 | } | ||
773 | |||
774 | static void cleanup_fbmem(void) | ||
775 | { | ||
776 | if (lcdc.fbmem_allocated) | ||
777 | free_fbmem(); | ||
778 | else | ||
779 | unmap_kern(); | ||
780 | } | ||
781 | |||
782 | static int omap_lcdc_init(struct omapfb_device *fbdev, int ext_mode, | ||
783 | struct omapfb_mem_desc *req_vram) | ||
784 | { | ||
785 | int r; | ||
786 | u32 l; | ||
787 | int rate; | ||
788 | struct clk *tc_ck; | ||
789 | |||
790 | lcdc.irq_mask = 0; | ||
791 | |||
792 | lcdc.fbdev = fbdev; | ||
793 | lcdc.ext_mode = ext_mode; | ||
794 | |||
795 | l = 0; | ||
796 | omap_writel(l, OMAP_LCDC_CONTROL); | ||
797 | |||
798 | /* FIXME: | ||
799 | * According to errata some platforms have a clock rate limitiation | ||
800 | */ | ||
801 | lcdc.lcd_ck = clk_get(NULL, "lcd_ck"); | ||
802 | if (IS_ERR(lcdc.lcd_ck)) { | ||
803 | dev_err(fbdev->dev, "unable to access LCD clock\n"); | ||
804 | r = PTR_ERR(lcdc.lcd_ck); | ||
805 | goto fail0; | ||
806 | } | ||
807 | |||
808 | tc_ck = clk_get(NULL, "tc_ck"); | ||
809 | if (IS_ERR(tc_ck)) { | ||
810 | dev_err(fbdev->dev, "unable to access TC clock\n"); | ||
811 | r = PTR_ERR(tc_ck); | ||
812 | goto fail1; | ||
813 | } | ||
814 | |||
815 | rate = clk_get_rate(tc_ck); | ||
816 | clk_put(tc_ck); | ||
817 | |||
818 | if (machine_is_ams_delta()) | ||
819 | rate /= 4; | ||
820 | if (machine_is_omap_h3()) | ||
821 | rate /= 3; | ||
822 | r = clk_set_rate(lcdc.lcd_ck, rate); | ||
823 | if (r) { | ||
824 | dev_err(fbdev->dev, "failed to adjust LCD rate\n"); | ||
825 | goto fail1; | ||
826 | } | ||
827 | clk_enable(lcdc.lcd_ck); | ||
828 | |||
829 | r = request_irq(OMAP_LCDC_IRQ, lcdc_irq_handler, 0, MODULE_NAME, fbdev); | ||
830 | if (r) { | ||
831 | dev_err(fbdev->dev, "unable to get IRQ\n"); | ||
832 | goto fail2; | ||
833 | } | ||
834 | |||
835 | r = omap_request_lcd_dma(lcdc_dma_handler, NULL); | ||
836 | if (r) { | ||
837 | dev_err(fbdev->dev, "unable to get LCD DMA\n"); | ||
838 | goto fail3; | ||
839 | } | ||
840 | |||
841 | omap_set_lcd_dma_single_transfer(ext_mode); | ||
842 | omap_set_lcd_dma_ext_controller(ext_mode); | ||
843 | |||
844 | if (!ext_mode) | ||
845 | if ((r = alloc_palette_ram()) < 0) | ||
846 | goto fail4; | ||
847 | |||
848 | if ((r = setup_fbmem(req_vram)) < 0) | ||
849 | goto fail5; | ||
850 | |||
851 | pr_info("omapfb: LCDC initialized\n"); | ||
852 | |||
853 | return 0; | ||
854 | fail5: | ||
855 | if (!ext_mode) | ||
856 | free_palette_ram(); | ||
857 | fail4: | ||
858 | omap_free_lcd_dma(); | ||
859 | fail3: | ||
860 | free_irq(OMAP_LCDC_IRQ, lcdc.fbdev); | ||
861 | fail2: | ||
862 | clk_disable(lcdc.lcd_ck); | ||
863 | fail1: | ||
864 | clk_put(lcdc.lcd_ck); | ||
865 | fail0: | ||
866 | return r; | ||
867 | } | ||
868 | |||
869 | static void omap_lcdc_cleanup(void) | ||
870 | { | ||
871 | if (!lcdc.ext_mode) | ||
872 | free_palette_ram(); | ||
873 | cleanup_fbmem(); | ||
874 | omap_free_lcd_dma(); | ||
875 | free_irq(OMAP_LCDC_IRQ, lcdc.fbdev); | ||
876 | clk_disable(lcdc.lcd_ck); | ||
877 | clk_put(lcdc.lcd_ck); | ||
878 | } | ||
879 | |||
880 | const struct lcd_ctrl omap1_int_ctrl = { | ||
881 | .name = "internal", | ||
882 | .init = omap_lcdc_init, | ||
883 | .cleanup = omap_lcdc_cleanup, | ||
884 | .get_caps = omap_lcdc_get_caps, | ||
885 | .set_update_mode = omap_lcdc_set_update_mode, | ||
886 | .get_update_mode = omap_lcdc_get_update_mode, | ||
887 | .update_window = NULL, | ||
888 | .suspend = omap_lcdc_suspend, | ||
889 | .resume = omap_lcdc_resume, | ||
890 | .setup_plane = omap_lcdc_setup_plane, | ||
891 | .enable_plane = omap_lcdc_enable_plane, | ||
892 | .setcolreg = omap_lcdc_setcolreg, | ||
893 | }; | ||
diff --git a/drivers/video/omap/lcdc.h b/drivers/video/omap/lcdc.h new file mode 100644 index 000000000000..adb731e5314a --- /dev/null +++ b/drivers/video/omap/lcdc.h | |||
@@ -0,0 +1,7 @@ | |||
1 | #ifndef LCDC_H | ||
2 | #define LCDC_H | ||
3 | |||
4 | int omap_lcdc_set_dma_callback(void (*callback)(void *data), void *data); | ||
5 | void omap_lcdc_free_dma_callback(void); | ||
6 | |||
7 | #endif | ||
diff --git a/drivers/video/omap/omapfb_main.c b/drivers/video/omap/omapfb_main.c new file mode 100644 index 000000000000..14d0f7a11145 --- /dev/null +++ b/drivers/video/omap/omapfb_main.c | |||
@@ -0,0 +1,1941 @@ | |||
1 | /* | ||
2 | * Framebuffer driver for TI OMAP boards | ||
3 | * | ||
4 | * Copyright (C) 2004 Nokia Corporation | ||
5 | * Author: Imre Deak <imre.deak@nokia.com> | ||
6 | * | ||
7 | * Acknowledgements: | ||
8 | * Alex McMains <aam@ridgerun.com> - Original driver | ||
9 | * Juha Yrjola <juha.yrjola@nokia.com> - Original driver and improvements | ||
10 | * Dirk Behme <dirk.behme@de.bosch.com> - changes for 2.6 kernel API | ||
11 | * Texas Instruments - H3 support | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify it | ||
14 | * under the terms of the GNU General Public License as published by the | ||
15 | * Free Software Foundation; either version 2 of the License, or (at your | ||
16 | * option) any later version. | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, but | ||
19 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
21 | * General Public License for more details. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License along | ||
24 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
25 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
26 | */ | ||
27 | #include <linux/platform_device.h> | ||
28 | #include <linux/uaccess.h> | ||
29 | |||
30 | #include <asm/mach-types.h> | ||
31 | #include <asm/arch/dma.h> | ||
32 | #include <asm/arch/omapfb.h> | ||
33 | |||
34 | #define MODULE_NAME "omapfb" | ||
35 | |||
36 | static unsigned int def_accel; | ||
37 | static unsigned long def_vram[OMAPFB_PLANE_NUM]; | ||
38 | static int def_vram_cnt; | ||
39 | static unsigned long def_vxres; | ||
40 | static unsigned long def_vyres; | ||
41 | static unsigned int def_rotate; | ||
42 | static unsigned int def_mirror; | ||
43 | |||
44 | #ifdef CONFIG_FB_OMAP_MANUAL_UPDATE | ||
45 | static int manual_update = 1; | ||
46 | #else | ||
47 | static int manual_update; | ||
48 | #endif | ||
49 | |||
50 | static struct platform_device *fbdev_pdev; | ||
51 | static struct lcd_panel *fbdev_panel; | ||
52 | static struct omapfb_device *omapfb_dev; | ||
53 | |||
54 | struct caps_table_struct { | ||
55 | unsigned long flag; | ||
56 | const char *name; | ||
57 | }; | ||
58 | |||
59 | static struct caps_table_struct ctrl_caps[] = { | ||
60 | { OMAPFB_CAPS_MANUAL_UPDATE, "manual update" }, | ||
61 | { OMAPFB_CAPS_TEARSYNC, "tearing synchronization" }, | ||
62 | { OMAPFB_CAPS_PLANE_RELOCATE_MEM, "relocate plane memory" }, | ||
63 | { OMAPFB_CAPS_PLANE_SCALE, "scale plane" }, | ||
64 | { OMAPFB_CAPS_WINDOW_PIXEL_DOUBLE, "pixel double window" }, | ||
65 | { OMAPFB_CAPS_WINDOW_SCALE, "scale window" }, | ||
66 | { OMAPFB_CAPS_WINDOW_OVERLAY, "overlay window" }, | ||
67 | { OMAPFB_CAPS_SET_BACKLIGHT, "backlight setting" }, | ||
68 | }; | ||
69 | |||
70 | static struct caps_table_struct color_caps[] = { | ||
71 | { 1 << OMAPFB_COLOR_RGB565, "RGB565", }, | ||
72 | { 1 << OMAPFB_COLOR_YUV422, "YUV422", }, | ||
73 | { 1 << OMAPFB_COLOR_YUV420, "YUV420", }, | ||
74 | { 1 << OMAPFB_COLOR_CLUT_8BPP, "CLUT8", }, | ||
75 | { 1 << OMAPFB_COLOR_CLUT_4BPP, "CLUT4", }, | ||
76 | { 1 << OMAPFB_COLOR_CLUT_2BPP, "CLUT2", }, | ||
77 | { 1 << OMAPFB_COLOR_CLUT_1BPP, "CLUT1", }, | ||
78 | { 1 << OMAPFB_COLOR_RGB444, "RGB444", }, | ||
79 | { 1 << OMAPFB_COLOR_YUY422, "YUY422", }, | ||
80 | }; | ||
81 | |||
82 | /* | ||
83 | * --------------------------------------------------------------------------- | ||
84 | * LCD panel | ||
85 | * --------------------------------------------------------------------------- | ||
86 | */ | ||
87 | extern struct lcd_ctrl omap1_int_ctrl; | ||
88 | extern struct lcd_ctrl omap2_int_ctrl; | ||
89 | extern struct lcd_ctrl hwa742_ctrl; | ||
90 | extern struct lcd_ctrl blizzard_ctrl; | ||
91 | |||
92 | static struct lcd_ctrl *ctrls[] = { | ||
93 | #ifdef CONFIG_ARCH_OMAP1 | ||
94 | &omap1_int_ctrl, | ||
95 | #else | ||
96 | &omap2_int_ctrl, | ||
97 | #endif | ||
98 | |||
99 | #ifdef CONFIG_FB_OMAP_LCDC_HWA742 | ||
100 | &hwa742_ctrl, | ||
101 | #endif | ||
102 | #ifdef CONFIG_FB_OMAP_LCDC_BLIZZARD | ||
103 | &blizzard_ctrl, | ||
104 | #endif | ||
105 | }; | ||
106 | |||
107 | #ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL | ||
108 | #ifdef CONFIG_ARCH_OMAP1 | ||
109 | extern struct lcd_ctrl_extif omap1_ext_if; | ||
110 | #else | ||
111 | extern struct lcd_ctrl_extif omap2_ext_if; | ||
112 | #endif | ||
113 | #endif | ||
114 | |||
115 | static void omapfb_rqueue_lock(struct omapfb_device *fbdev) | ||
116 | { | ||
117 | mutex_lock(&fbdev->rqueue_mutex); | ||
118 | } | ||
119 | |||
120 | static void omapfb_rqueue_unlock(struct omapfb_device *fbdev) | ||
121 | { | ||
122 | mutex_unlock(&fbdev->rqueue_mutex); | ||
123 | } | ||
124 | |||
125 | /* | ||
126 | * --------------------------------------------------------------------------- | ||
127 | * LCD controller and LCD DMA | ||
128 | * --------------------------------------------------------------------------- | ||
129 | */ | ||
130 | /* Lookup table to map elem size to elem type. */ | ||
131 | static const int dma_elem_type[] = { | ||
132 | 0, | ||
133 | OMAP_DMA_DATA_TYPE_S8, | ||
134 | OMAP_DMA_DATA_TYPE_S16, | ||
135 | 0, | ||
136 | OMAP_DMA_DATA_TYPE_S32, | ||
137 | }; | ||
138 | |||
139 | /* | ||
140 | * Allocate resources needed for LCD controller and LCD DMA operations. Video | ||
141 | * memory is allocated from system memory according to the virtual display | ||
142 | * size, except if a bigger memory size is specified explicitly as a kernel | ||
143 | * parameter. | ||
144 | */ | ||
145 | static int ctrl_init(struct omapfb_device *fbdev) | ||
146 | { | ||
147 | int r; | ||
148 | int i; | ||
149 | |||
150 | /* kernel/module vram parameters override boot tags/board config */ | ||
151 | if (def_vram_cnt) { | ||
152 | for (i = 0; i < def_vram_cnt; i++) | ||
153 | fbdev->mem_desc.region[i].size = | ||
154 | PAGE_ALIGN(def_vram[i]); | ||
155 | fbdev->mem_desc.region_cnt = i; | ||
156 | } else { | ||
157 | struct omapfb_platform_data *conf; | ||
158 | |||
159 | conf = fbdev->dev->platform_data; | ||
160 | fbdev->mem_desc = conf->mem_desc; | ||
161 | } | ||
162 | |||
163 | if (!fbdev->mem_desc.region_cnt) { | ||
164 | struct lcd_panel *panel = fbdev->panel; | ||
165 | int def_size; | ||
166 | int bpp = panel->bpp; | ||
167 | |||
168 | /* 12 bpp is packed in 16 bits */ | ||
169 | if (bpp == 12) | ||
170 | bpp = 16; | ||
171 | def_size = def_vxres * def_vyres * bpp / 8; | ||
172 | fbdev->mem_desc.region_cnt = 1; | ||
173 | fbdev->mem_desc.region[0].size = PAGE_ALIGN(def_size); | ||
174 | } | ||
175 | r = fbdev->ctrl->init(fbdev, 0, &fbdev->mem_desc); | ||
176 | if (r < 0) { | ||
177 | dev_err(fbdev->dev, "controller initialization failed (%d)\n", | ||
178 | r); | ||
179 | return r; | ||
180 | } | ||
181 | |||
182 | #ifdef DEBUG | ||
183 | for (i = 0; i < fbdev->mem_desc.region_cnt; i++) { | ||
184 | dev_dbg(fbdev->dev, "region%d phys %08x virt %p size=%lu\n", | ||
185 | i, | ||
186 | fbdev->mem_desc.region[i].paddr, | ||
187 | fbdev->mem_desc.region[i].vaddr, | ||
188 | fbdev->mem_desc.region[i].size); | ||
189 | } | ||
190 | #endif | ||
191 | return 0; | ||
192 | } | ||
193 | |||
194 | static void ctrl_cleanup(struct omapfb_device *fbdev) | ||
195 | { | ||
196 | fbdev->ctrl->cleanup(); | ||
197 | } | ||
198 | |||
199 | /* Must be called with fbdev->rqueue_mutex held. */ | ||
200 | static int ctrl_change_mode(struct fb_info *fbi) | ||
201 | { | ||
202 | int r; | ||
203 | unsigned long offset; | ||
204 | struct omapfb_plane_struct *plane = fbi->par; | ||
205 | struct omapfb_device *fbdev = plane->fbdev; | ||
206 | struct fb_var_screeninfo *var = &fbi->var; | ||
207 | |||
208 | offset = var->yoffset * fbi->fix.line_length + | ||
209 | var->xoffset * var->bits_per_pixel / 8; | ||
210 | |||
211 | if (fbdev->ctrl->sync) | ||
212 | fbdev->ctrl->sync(); | ||
213 | r = fbdev->ctrl->setup_plane(plane->idx, plane->info.channel_out, | ||
214 | offset, var->xres_virtual, | ||
215 | plane->info.pos_x, plane->info.pos_y, | ||
216 | var->xres, var->yres, plane->color_mode); | ||
217 | if (fbdev->ctrl->set_scale != NULL) | ||
218 | r = fbdev->ctrl->set_scale(plane->idx, | ||
219 | var->xres, var->yres, | ||
220 | plane->info.out_width, | ||
221 | plane->info.out_height); | ||
222 | |||
223 | return r; | ||
224 | } | ||
225 | |||
226 | /* | ||
227 | * --------------------------------------------------------------------------- | ||
228 | * fbdev framework callbacks and the ioctl interface | ||
229 | * --------------------------------------------------------------------------- | ||
230 | */ | ||
231 | /* Called each time the omapfb device is opened */ | ||
232 | static int omapfb_open(struct fb_info *info, int user) | ||
233 | { | ||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | static void omapfb_sync(struct fb_info *info); | ||
238 | |||
239 | /* Called when the omapfb device is closed. We make sure that any pending | ||
240 | * gfx DMA operations are ended, before we return. */ | ||
241 | static int omapfb_release(struct fb_info *info, int user) | ||
242 | { | ||
243 | omapfb_sync(info); | ||
244 | return 0; | ||
245 | } | ||
246 | |||
247 | /* Store a single color palette entry into a pseudo palette or the hardware | ||
248 | * palette if one is available. For now we support only 16bpp and thus store | ||
249 | * the entry only to the pseudo palette. | ||
250 | */ | ||
251 | static int _setcolreg(struct fb_info *info, u_int regno, u_int red, u_int green, | ||
252 | u_int blue, u_int transp, int update_hw_pal) | ||
253 | { | ||
254 | struct omapfb_plane_struct *plane = info->par; | ||
255 | struct omapfb_device *fbdev = plane->fbdev; | ||
256 | struct fb_var_screeninfo *var = &info->var; | ||
257 | int r = 0; | ||
258 | |||
259 | switch (plane->color_mode) { | ||
260 | case OMAPFB_COLOR_YUV422: | ||
261 | case OMAPFB_COLOR_YUV420: | ||
262 | case OMAPFB_COLOR_YUY422: | ||
263 | r = -EINVAL; | ||
264 | break; | ||
265 | case OMAPFB_COLOR_CLUT_8BPP: | ||
266 | case OMAPFB_COLOR_CLUT_4BPP: | ||
267 | case OMAPFB_COLOR_CLUT_2BPP: | ||
268 | case OMAPFB_COLOR_CLUT_1BPP: | ||
269 | if (fbdev->ctrl->setcolreg) | ||
270 | r = fbdev->ctrl->setcolreg(regno, red, green, blue, | ||
271 | transp, update_hw_pal); | ||
272 | /* Fallthrough */ | ||
273 | case OMAPFB_COLOR_RGB565: | ||
274 | case OMAPFB_COLOR_RGB444: | ||
275 | if (r != 0) | ||
276 | break; | ||
277 | |||
278 | if (regno < 0) { | ||
279 | r = -EINVAL; | ||
280 | break; | ||
281 | } | ||
282 | |||
283 | if (regno < 16) { | ||
284 | u16 pal; | ||
285 | pal = ((red >> (16 - var->red.length)) << | ||
286 | var->red.offset) | | ||
287 | ((green >> (16 - var->green.length)) << | ||
288 | var->green.offset) | | ||
289 | (blue >> (16 - var->blue.length)); | ||
290 | ((u32 *)(info->pseudo_palette))[regno] = pal; | ||
291 | } | ||
292 | break; | ||
293 | default: | ||
294 | BUG(); | ||
295 | } | ||
296 | return r; | ||
297 | } | ||
298 | |||
299 | static int omapfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, | ||
300 | u_int transp, struct fb_info *info) | ||
301 | { | ||
302 | return _setcolreg(info, regno, red, green, blue, transp, 1); | ||
303 | } | ||
304 | |||
305 | static int omapfb_setcmap(struct fb_cmap *cmap, struct fb_info *info) | ||
306 | { | ||
307 | int count, index, r; | ||
308 | u16 *red, *green, *blue, *transp; | ||
309 | u16 trans = 0xffff; | ||
310 | |||
311 | red = cmap->red; | ||
312 | green = cmap->green; | ||
313 | blue = cmap->blue; | ||
314 | transp = cmap->transp; | ||
315 | index = cmap->start; | ||
316 | |||
317 | for (count = 0; count < cmap->len; count++) { | ||
318 | if (transp) | ||
319 | trans = *transp++; | ||
320 | r = _setcolreg(info, index++, *red++, *green++, *blue++, trans, | ||
321 | count == cmap->len - 1); | ||
322 | if (r != 0) | ||
323 | return r; | ||
324 | } | ||
325 | |||
326 | return 0; | ||
327 | } | ||
328 | |||
329 | static int omapfb_update_full_screen(struct fb_info *fbi); | ||
330 | |||
331 | static int omapfb_blank(int blank, struct fb_info *fbi) | ||
332 | { | ||
333 | struct omapfb_plane_struct *plane = fbi->par; | ||
334 | struct omapfb_device *fbdev = plane->fbdev; | ||
335 | int do_update = 0; | ||
336 | int r = 0; | ||
337 | |||
338 | omapfb_rqueue_lock(fbdev); | ||
339 | switch (blank) { | ||
340 | case VESA_NO_BLANKING: | ||
341 | if (fbdev->state == OMAPFB_SUSPENDED) { | ||
342 | if (fbdev->ctrl->resume) | ||
343 | fbdev->ctrl->resume(); | ||
344 | fbdev->panel->enable(fbdev->panel); | ||
345 | fbdev->state = OMAPFB_ACTIVE; | ||
346 | if (fbdev->ctrl->get_update_mode() == | ||
347 | OMAPFB_MANUAL_UPDATE) | ||
348 | do_update = 1; | ||
349 | } | ||
350 | break; | ||
351 | case VESA_POWERDOWN: | ||
352 | if (fbdev->state == OMAPFB_ACTIVE) { | ||
353 | fbdev->panel->disable(fbdev->panel); | ||
354 | if (fbdev->ctrl->suspend) | ||
355 | fbdev->ctrl->suspend(); | ||
356 | fbdev->state = OMAPFB_SUSPENDED; | ||
357 | } | ||
358 | break; | ||
359 | default: | ||
360 | r = -EINVAL; | ||
361 | } | ||
362 | omapfb_rqueue_unlock(fbdev); | ||
363 | |||
364 | if (r == 0 && do_update) | ||
365 | r = omapfb_update_full_screen(fbi); | ||
366 | |||
367 | return r; | ||
368 | } | ||
369 | |||
370 | static void omapfb_sync(struct fb_info *fbi) | ||
371 | { | ||
372 | struct omapfb_plane_struct *plane = fbi->par; | ||
373 | struct omapfb_device *fbdev = plane->fbdev; | ||
374 | |||
375 | omapfb_rqueue_lock(fbdev); | ||
376 | if (fbdev->ctrl->sync) | ||
377 | fbdev->ctrl->sync(); | ||
378 | omapfb_rqueue_unlock(fbdev); | ||
379 | } | ||
380 | |||
381 | /* | ||
382 | * Set fb_info.fix fields and also updates fbdev. | ||
383 | * When calling this fb_info.var must be set up already. | ||
384 | */ | ||
385 | static void set_fb_fix(struct fb_info *fbi) | ||
386 | { | ||
387 | struct fb_fix_screeninfo *fix = &fbi->fix; | ||
388 | struct fb_var_screeninfo *var = &fbi->var; | ||
389 | struct omapfb_plane_struct *plane = fbi->par; | ||
390 | struct omapfb_mem_region *rg; | ||
391 | int bpp; | ||
392 | |||
393 | rg = &plane->fbdev->mem_desc.region[plane->idx]; | ||
394 | fbi->screen_base = (char __iomem *)rg->vaddr; | ||
395 | fix->smem_start = rg->paddr; | ||
396 | fix->smem_len = rg->size; | ||
397 | |||
398 | fix->type = FB_TYPE_PACKED_PIXELS; | ||
399 | bpp = var->bits_per_pixel; | ||
400 | if (var->nonstd) | ||
401 | fix->visual = FB_VISUAL_PSEUDOCOLOR; | ||
402 | else switch (var->bits_per_pixel) { | ||
403 | case 16: | ||
404 | case 12: | ||
405 | fix->visual = FB_VISUAL_TRUECOLOR; | ||
406 | /* 12bpp is stored in 16 bits */ | ||
407 | bpp = 16; | ||
408 | break; | ||
409 | case 1: | ||
410 | case 2: | ||
411 | case 4: | ||
412 | case 8: | ||
413 | fix->visual = FB_VISUAL_PSEUDOCOLOR; | ||
414 | break; | ||
415 | } | ||
416 | fix->accel = FB_ACCEL_OMAP1610; | ||
417 | fix->line_length = var->xres_virtual * bpp / 8; | ||
418 | } | ||
419 | |||
420 | static int set_color_mode(struct omapfb_plane_struct *plane, | ||
421 | struct fb_var_screeninfo *var) | ||
422 | { | ||
423 | switch (var->nonstd) { | ||
424 | case 0: | ||
425 | break; | ||
426 | case OMAPFB_COLOR_YUV422: | ||
427 | var->bits_per_pixel = 16; | ||
428 | plane->color_mode = var->nonstd; | ||
429 | return 0; | ||
430 | case OMAPFB_COLOR_YUV420: | ||
431 | var->bits_per_pixel = 12; | ||
432 | plane->color_mode = var->nonstd; | ||
433 | return 0; | ||
434 | case OMAPFB_COLOR_YUY422: | ||
435 | var->bits_per_pixel = 16; | ||
436 | plane->color_mode = var->nonstd; | ||
437 | return 0; | ||
438 | default: | ||
439 | return -EINVAL; | ||
440 | } | ||
441 | |||
442 | switch (var->bits_per_pixel) { | ||
443 | case 1: | ||
444 | plane->color_mode = OMAPFB_COLOR_CLUT_1BPP; | ||
445 | return 0; | ||
446 | case 2: | ||
447 | plane->color_mode = OMAPFB_COLOR_CLUT_2BPP; | ||
448 | return 0; | ||
449 | case 4: | ||
450 | plane->color_mode = OMAPFB_COLOR_CLUT_4BPP; | ||
451 | return 0; | ||
452 | case 8: | ||
453 | plane->color_mode = OMAPFB_COLOR_CLUT_8BPP; | ||
454 | return 0; | ||
455 | case 12: | ||
456 | var->bits_per_pixel = 16; | ||
457 | plane->color_mode = OMAPFB_COLOR_RGB444; | ||
458 | return 0; | ||
459 | case 16: | ||
460 | plane->color_mode = OMAPFB_COLOR_RGB565; | ||
461 | return 0; | ||
462 | default: | ||
463 | return -EINVAL; | ||
464 | } | ||
465 | } | ||
466 | |||
467 | /* | ||
468 | * Check the values in var against our capabilities and in case of out of | ||
469 | * bound values try to adjust them. | ||
470 | */ | ||
471 | static int set_fb_var(struct fb_info *fbi, | ||
472 | struct fb_var_screeninfo *var) | ||
473 | { | ||
474 | int bpp; | ||
475 | unsigned long max_frame_size; | ||
476 | unsigned long line_size; | ||
477 | int xres_min, xres_max; | ||
478 | int yres_min, yres_max; | ||
479 | struct omapfb_plane_struct *plane = fbi->par; | ||
480 | struct omapfb_device *fbdev = plane->fbdev; | ||
481 | struct lcd_panel *panel = fbdev->panel; | ||
482 | |||
483 | if (set_color_mode(plane, var) < 0) | ||
484 | return -EINVAL; | ||
485 | |||
486 | bpp = var->bits_per_pixel; | ||
487 | if (plane->color_mode == OMAPFB_COLOR_RGB444) | ||
488 | bpp = 16; | ||
489 | |||
490 | switch (var->rotate) { | ||
491 | case 0: | ||
492 | case 180: | ||
493 | xres_min = OMAPFB_PLANE_XRES_MIN; | ||
494 | xres_max = panel->x_res; | ||
495 | yres_min = OMAPFB_PLANE_YRES_MIN; | ||
496 | yres_max = panel->y_res; | ||
497 | if (cpu_is_omap15xx()) { | ||
498 | var->xres = panel->x_res; | ||
499 | var->yres = panel->y_res; | ||
500 | } | ||
501 | break; | ||
502 | case 90: | ||
503 | case 270: | ||
504 | xres_min = OMAPFB_PLANE_YRES_MIN; | ||
505 | xres_max = panel->y_res; | ||
506 | yres_min = OMAPFB_PLANE_XRES_MIN; | ||
507 | yres_max = panel->x_res; | ||
508 | if (cpu_is_omap15xx()) { | ||
509 | var->xres = panel->y_res; | ||
510 | var->yres = panel->x_res; | ||
511 | } | ||
512 | break; | ||
513 | default: | ||
514 | return -EINVAL; | ||
515 | } | ||
516 | |||
517 | if (var->xres < xres_min) | ||
518 | var->xres = xres_min; | ||
519 | if (var->yres < yres_min) | ||
520 | var->yres = yres_min; | ||
521 | if (var->xres > xres_max) | ||
522 | var->xres = xres_max; | ||
523 | if (var->yres > yres_max) | ||
524 | var->yres = yres_max; | ||
525 | |||
526 | if (var->xres_virtual < var->xres) | ||
527 | var->xres_virtual = var->xres; | ||
528 | if (var->yres_virtual < var->yres) | ||
529 | var->yres_virtual = var->yres; | ||
530 | max_frame_size = fbdev->mem_desc.region[plane->idx].size; | ||
531 | line_size = var->xres_virtual * bpp / 8; | ||
532 | if (line_size * var->yres_virtual > max_frame_size) { | ||
533 | /* Try to keep yres_virtual first */ | ||
534 | line_size = max_frame_size / var->yres_virtual; | ||
535 | var->xres_virtual = line_size * 8 / bpp; | ||
536 | if (var->xres_virtual < var->xres) { | ||
537 | /* Still doesn't fit. Shrink yres_virtual too */ | ||
538 | var->xres_virtual = var->xres; | ||
539 | line_size = var->xres * bpp / 8; | ||
540 | var->yres_virtual = max_frame_size / line_size; | ||
541 | } | ||
542 | /* Recheck this, as the virtual size changed. */ | ||
543 | if (var->xres_virtual < var->xres) | ||
544 | var->xres = var->xres_virtual; | ||
545 | if (var->yres_virtual < var->yres) | ||
546 | var->yres = var->yres_virtual; | ||
547 | if (var->xres < xres_min || var->yres < yres_min) | ||
548 | return -EINVAL; | ||
549 | } | ||
550 | if (var->xres + var->xoffset > var->xres_virtual) | ||
551 | var->xoffset = var->xres_virtual - var->xres; | ||
552 | if (var->yres + var->yoffset > var->yres_virtual) | ||
553 | var->yoffset = var->yres_virtual - var->yres; | ||
554 | line_size = var->xres * bpp / 8; | ||
555 | |||
556 | if (plane->color_mode == OMAPFB_COLOR_RGB444) { | ||
557 | var->red.offset = 8; var->red.length = 4; | ||
558 | var->red.msb_right = 0; | ||
559 | var->green.offset = 4; var->green.length = 4; | ||
560 | var->green.msb_right = 0; | ||
561 | var->blue.offset = 0; var->blue.length = 4; | ||
562 | var->blue.msb_right = 0; | ||
563 | } else { | ||
564 | var->red.offset = 11; var->red.length = 5; | ||
565 | var->red.msb_right = 0; | ||
566 | var->green.offset = 5; var->green.length = 6; | ||
567 | var->green.msb_right = 0; | ||
568 | var->blue.offset = 0; var->blue.length = 5; | ||
569 | var->blue.msb_right = 0; | ||
570 | } | ||
571 | |||
572 | var->height = -1; | ||
573 | var->width = -1; | ||
574 | var->grayscale = 0; | ||
575 | |||
576 | /* pixclock in ps, the rest in pixclock */ | ||
577 | var->pixclock = 10000000 / (panel->pixel_clock / 100); | ||
578 | var->left_margin = panel->hfp; | ||
579 | var->right_margin = panel->hbp; | ||
580 | var->upper_margin = panel->vfp; | ||
581 | var->lower_margin = panel->vbp; | ||
582 | var->hsync_len = panel->hsw; | ||
583 | var->vsync_len = panel->vsw; | ||
584 | |||
585 | /* TODO: get these from panel->config */ | ||
586 | var->vmode = FB_VMODE_NONINTERLACED; | ||
587 | var->sync = 0; | ||
588 | |||
589 | return 0; | ||
590 | } | ||
591 | |||
592 | |||
593 | /* Set rotation (0, 90, 180, 270 degree), and switch to the new mode. */ | ||
594 | static void omapfb_rotate(struct fb_info *fbi, int rotate) | ||
595 | { | ||
596 | struct omapfb_plane_struct *plane = fbi->par; | ||
597 | struct omapfb_device *fbdev = plane->fbdev; | ||
598 | |||
599 | omapfb_rqueue_lock(fbdev); | ||
600 | if (cpu_is_omap15xx() && rotate != fbi->var.rotate) { | ||
601 | struct fb_var_screeninfo *new_var = &fbdev->new_var; | ||
602 | |||
603 | memcpy(new_var, &fbi->var, sizeof(*new_var)); | ||
604 | new_var->rotate = rotate; | ||
605 | if (set_fb_var(fbi, new_var) == 0 && | ||
606 | memcmp(new_var, &fbi->var, sizeof(*new_var))) { | ||
607 | memcpy(&fbi->var, new_var, sizeof(*new_var)); | ||
608 | ctrl_change_mode(fbi); | ||
609 | } | ||
610 | } | ||
611 | omapfb_rqueue_unlock(fbdev); | ||
612 | } | ||
613 | |||
614 | /* | ||
615 | * Set new x,y offsets in the virtual display for the visible area and switch | ||
616 | * to the new mode. | ||
617 | */ | ||
618 | static int omapfb_pan_display(struct fb_var_screeninfo *var, | ||
619 | struct fb_info *fbi) | ||
620 | { | ||
621 | struct omapfb_plane_struct *plane = fbi->par; | ||
622 | struct omapfb_device *fbdev = plane->fbdev; | ||
623 | int r = 0; | ||
624 | |||
625 | omapfb_rqueue_lock(fbdev); | ||
626 | if (var->xoffset != fbi->var.xoffset || | ||
627 | var->yoffset != fbi->var.yoffset) { | ||
628 | struct fb_var_screeninfo *new_var = &fbdev->new_var; | ||
629 | |||
630 | memcpy(new_var, &fbi->var, sizeof(*new_var)); | ||
631 | new_var->xoffset = var->xoffset; | ||
632 | new_var->yoffset = var->yoffset; | ||
633 | if (set_fb_var(fbi, new_var)) | ||
634 | r = -EINVAL; | ||
635 | else { | ||
636 | memcpy(&fbi->var, new_var, sizeof(*new_var)); | ||
637 | ctrl_change_mode(fbi); | ||
638 | } | ||
639 | } | ||
640 | omapfb_rqueue_unlock(fbdev); | ||
641 | |||
642 | return r; | ||
643 | } | ||
644 | |||
645 | /* Set mirror to vertical axis and switch to the new mode. */ | ||
646 | static int omapfb_mirror(struct fb_info *fbi, int mirror) | ||
647 | { | ||
648 | struct omapfb_plane_struct *plane = fbi->par; | ||
649 | struct omapfb_device *fbdev = plane->fbdev; | ||
650 | int r = 0; | ||
651 | |||
652 | omapfb_rqueue_lock(fbdev); | ||
653 | mirror = mirror ? 1 : 0; | ||
654 | if (cpu_is_omap15xx()) | ||
655 | r = -EINVAL; | ||
656 | else if (mirror != plane->info.mirror) { | ||
657 | plane->info.mirror = mirror; | ||
658 | r = ctrl_change_mode(fbi); | ||
659 | } | ||
660 | omapfb_rqueue_unlock(fbdev); | ||
661 | |||
662 | return r; | ||
663 | } | ||
664 | |||
665 | /* | ||
666 | * Check values in var, try to adjust them in case of out of bound values if | ||
667 | * possible, or return error. | ||
668 | */ | ||
669 | static int omapfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi) | ||
670 | { | ||
671 | struct omapfb_plane_struct *plane = fbi->par; | ||
672 | struct omapfb_device *fbdev = plane->fbdev; | ||
673 | int r; | ||
674 | |||
675 | omapfb_rqueue_lock(fbdev); | ||
676 | if (fbdev->ctrl->sync != NULL) | ||
677 | fbdev->ctrl->sync(); | ||
678 | r = set_fb_var(fbi, var); | ||
679 | omapfb_rqueue_unlock(fbdev); | ||
680 | |||
681 | return r; | ||
682 | } | ||
683 | |||
684 | /* | ||
685 | * Switch to a new mode. The parameters for it has been check already by | ||
686 | * omapfb_check_var. | ||
687 | */ | ||
688 | static int omapfb_set_par(struct fb_info *fbi) | ||
689 | { | ||
690 | struct omapfb_plane_struct *plane = fbi->par; | ||
691 | struct omapfb_device *fbdev = plane->fbdev; | ||
692 | int r = 0; | ||
693 | |||
694 | omapfb_rqueue_lock(fbdev); | ||
695 | set_fb_fix(fbi); | ||
696 | r = ctrl_change_mode(fbi); | ||
697 | omapfb_rqueue_unlock(fbdev); | ||
698 | |||
699 | return r; | ||
700 | } | ||
701 | |||
702 | int omapfb_update_window_async(struct fb_info *fbi, | ||
703 | struct omapfb_update_window *win, | ||
704 | void (*callback)(void *), | ||
705 | void *callback_data) | ||
706 | { | ||
707 | struct omapfb_plane_struct *plane = fbi->par; | ||
708 | struct omapfb_device *fbdev = plane->fbdev; | ||
709 | struct fb_var_screeninfo *var; | ||
710 | |||
711 | var = &fbi->var; | ||
712 | if (win->x >= var->xres || win->y >= var->yres || | ||
713 | win->out_x > var->xres || win->out_y >= var->yres) | ||
714 | return -EINVAL; | ||
715 | |||
716 | if (!fbdev->ctrl->update_window || | ||
717 | fbdev->ctrl->get_update_mode() != OMAPFB_MANUAL_UPDATE) | ||
718 | return -ENODEV; | ||
719 | |||
720 | if (win->x + win->width >= var->xres) | ||
721 | win->width = var->xres - win->x; | ||
722 | if (win->y + win->height >= var->yres) | ||
723 | win->height = var->yres - win->y; | ||
724 | /* The out sizes should be cropped to the LCD size */ | ||
725 | if (win->out_x + win->out_width > fbdev->panel->x_res) | ||
726 | win->out_width = fbdev->panel->x_res - win->out_x; | ||
727 | if (win->out_y + win->out_height > fbdev->panel->y_res) | ||
728 | win->out_height = fbdev->panel->y_res - win->out_y; | ||
729 | if (!win->width || !win->height || !win->out_width || !win->out_height) | ||
730 | return 0; | ||
731 | |||
732 | return fbdev->ctrl->update_window(fbi, win, callback, callback_data); | ||
733 | } | ||
734 | EXPORT_SYMBOL(omapfb_update_window_async); | ||
735 | |||
736 | static int omapfb_update_win(struct fb_info *fbi, | ||
737 | struct omapfb_update_window *win) | ||
738 | { | ||
739 | struct omapfb_plane_struct *plane = fbi->par; | ||
740 | int ret; | ||
741 | |||
742 | omapfb_rqueue_lock(plane->fbdev); | ||
743 | ret = omapfb_update_window_async(fbi, win, NULL, 0); | ||
744 | omapfb_rqueue_unlock(plane->fbdev); | ||
745 | |||
746 | return ret; | ||
747 | } | ||
748 | |||
749 | static int omapfb_update_full_screen(struct fb_info *fbi) | ||
750 | { | ||
751 | struct omapfb_plane_struct *plane = fbi->par; | ||
752 | struct omapfb_device *fbdev = plane->fbdev; | ||
753 | struct omapfb_update_window win; | ||
754 | int r; | ||
755 | |||
756 | if (!fbdev->ctrl->update_window || | ||
757 | fbdev->ctrl->get_update_mode() != OMAPFB_MANUAL_UPDATE) | ||
758 | return -ENODEV; | ||
759 | |||
760 | win.x = 0; | ||
761 | win.y = 0; | ||
762 | win.width = fbi->var.xres; | ||
763 | win.height = fbi->var.yres; | ||
764 | win.out_x = 0; | ||
765 | win.out_y = 0; | ||
766 | win.out_width = fbi->var.xres; | ||
767 | win.out_height = fbi->var.yres; | ||
768 | win.format = 0; | ||
769 | |||
770 | omapfb_rqueue_lock(fbdev); | ||
771 | r = fbdev->ctrl->update_window(fbi, &win, NULL, 0); | ||
772 | omapfb_rqueue_unlock(fbdev); | ||
773 | |||
774 | return r; | ||
775 | } | ||
776 | |||
777 | static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) | ||
778 | { | ||
779 | struct omapfb_plane_struct *plane = fbi->par; | ||
780 | struct omapfb_device *fbdev = plane->fbdev; | ||
781 | struct lcd_panel *panel = fbdev->panel; | ||
782 | struct omapfb_plane_info old_info; | ||
783 | int r = 0; | ||
784 | |||
785 | if (pi->pos_x + pi->out_width > panel->x_res || | ||
786 | pi->pos_y + pi->out_height > panel->y_res) | ||
787 | return -EINVAL; | ||
788 | |||
789 | omapfb_rqueue_lock(fbdev); | ||
790 | if (pi->enabled && !fbdev->mem_desc.region[plane->idx].size) { | ||
791 | /* | ||
792 | * This plane's memory was freed, can't enable it | ||
793 | * until it's reallocated. | ||
794 | */ | ||
795 | r = -EINVAL; | ||
796 | goto out; | ||
797 | } | ||
798 | old_info = plane->info; | ||
799 | plane->info = *pi; | ||
800 | if (pi->enabled) { | ||
801 | r = ctrl_change_mode(fbi); | ||
802 | if (r < 0) { | ||
803 | plane->info = old_info; | ||
804 | goto out; | ||
805 | } | ||
806 | } | ||
807 | r = fbdev->ctrl->enable_plane(plane->idx, pi->enabled); | ||
808 | if (r < 0) { | ||
809 | plane->info = old_info; | ||
810 | goto out; | ||
811 | } | ||
812 | out: | ||
813 | omapfb_rqueue_unlock(fbdev); | ||
814 | return r; | ||
815 | } | ||
816 | |||
817 | static int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) | ||
818 | { | ||
819 | struct omapfb_plane_struct *plane = fbi->par; | ||
820 | |||
821 | *pi = plane->info; | ||
822 | return 0; | ||
823 | } | ||
824 | |||
825 | static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) | ||
826 | { | ||
827 | struct omapfb_plane_struct *plane = fbi->par; | ||
828 | struct omapfb_device *fbdev = plane->fbdev; | ||
829 | struct omapfb_mem_region *rg = &fbdev->mem_desc.region[plane->idx]; | ||
830 | size_t size; | ||
831 | int r = 0; | ||
832 | |||
833 | if (fbdev->ctrl->setup_mem == NULL) | ||
834 | return -ENODEV; | ||
835 | if (mi->type > OMAPFB_MEMTYPE_MAX) | ||
836 | return -EINVAL; | ||
837 | |||
838 | size = PAGE_ALIGN(mi->size); | ||
839 | omapfb_rqueue_lock(fbdev); | ||
840 | if (plane->info.enabled) { | ||
841 | r = -EBUSY; | ||
842 | goto out; | ||
843 | } | ||
844 | if (rg->size != size || rg->type != mi->type) { | ||
845 | struct fb_var_screeninfo *new_var = &fbdev->new_var; | ||
846 | unsigned long old_size = rg->size; | ||
847 | u8 old_type = rg->type; | ||
848 | unsigned long paddr; | ||
849 | |||
850 | rg->size = size; | ||
851 | rg->type = mi->type; | ||
852 | /* | ||
853 | * size == 0 is a special case, for which we | ||
854 | * don't check / adjust the screen parameters. | ||
855 | * This isn't a problem since the plane can't | ||
856 | * be reenabled unless its size is > 0. | ||
857 | */ | ||
858 | if (old_size != size && size) { | ||
859 | if (size) { | ||
860 | memcpy(new_var, &fbi->var, sizeof(*new_var)); | ||
861 | r = set_fb_var(fbi, new_var); | ||
862 | if (r < 0) | ||
863 | goto out; | ||
864 | } | ||
865 | } | ||
866 | |||
867 | if (fbdev->ctrl->sync) | ||
868 | fbdev->ctrl->sync(); | ||
869 | r = fbdev->ctrl->setup_mem(plane->idx, size, mi->type, &paddr); | ||
870 | if (r < 0) { | ||
871 | /* Revert changes. */ | ||
872 | rg->size = old_size; | ||
873 | rg->type = old_type; | ||
874 | goto out; | ||
875 | } | ||
876 | rg->paddr = paddr; | ||
877 | |||
878 | if (old_size != size) { | ||
879 | if (size) { | ||
880 | memcpy(&fbi->var, new_var, sizeof(fbi->var)); | ||
881 | set_fb_fix(fbi); | ||
882 | } else { | ||
883 | /* | ||
884 | * Set these explicitly to indicate that the | ||
885 | * plane memory is dealloce'd, the other | ||
886 | * screen parameters in var / fix are invalid. | ||
887 | */ | ||
888 | fbi->fix.smem_start = 0; | ||
889 | fbi->fix.smem_len = 0; | ||
890 | } | ||
891 | } | ||
892 | } | ||
893 | out: | ||
894 | omapfb_rqueue_unlock(fbdev); | ||
895 | |||
896 | return r; | ||
897 | } | ||
898 | |||
899 | static int omapfb_query_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) | ||
900 | { | ||
901 | struct omapfb_plane_struct *plane = fbi->par; | ||
902 | struct omapfb_device *fbdev = plane->fbdev; | ||
903 | struct omapfb_mem_region *rg; | ||
904 | |||
905 | rg = &fbdev->mem_desc.region[plane->idx]; | ||
906 | memset(mi, 0, sizeof(*mi)); | ||
907 | mi->size = rg->size; | ||
908 | mi->type = rg->type; | ||
909 | |||
910 | return 0; | ||
911 | } | ||
912 | |||
913 | static int omapfb_set_color_key(struct omapfb_device *fbdev, | ||
914 | struct omapfb_color_key *ck) | ||
915 | { | ||
916 | int r; | ||
917 | |||
918 | if (!fbdev->ctrl->set_color_key) | ||
919 | return -ENODEV; | ||
920 | |||
921 | omapfb_rqueue_lock(fbdev); | ||
922 | r = fbdev->ctrl->set_color_key(ck); | ||
923 | omapfb_rqueue_unlock(fbdev); | ||
924 | |||
925 | return r; | ||
926 | } | ||
927 | |||
928 | static int omapfb_get_color_key(struct omapfb_device *fbdev, | ||
929 | struct omapfb_color_key *ck) | ||
930 | { | ||
931 | int r; | ||
932 | |||
933 | if (!fbdev->ctrl->get_color_key) | ||
934 | return -ENODEV; | ||
935 | |||
936 | omapfb_rqueue_lock(fbdev); | ||
937 | r = fbdev->ctrl->get_color_key(ck); | ||
938 | omapfb_rqueue_unlock(fbdev); | ||
939 | |||
940 | return r; | ||
941 | } | ||
942 | |||
943 | static struct blocking_notifier_head omapfb_client_list[OMAPFB_PLANE_NUM]; | ||
944 | static int notifier_inited; | ||
945 | |||
946 | static void omapfb_init_notifier(void) | ||
947 | { | ||
948 | int i; | ||
949 | |||
950 | for (i = 0; i < OMAPFB_PLANE_NUM; i++) | ||
951 | BLOCKING_INIT_NOTIFIER_HEAD(&omapfb_client_list[i]); | ||
952 | } | ||
953 | |||
954 | int omapfb_register_client(struct omapfb_notifier_block *omapfb_nb, | ||
955 | omapfb_notifier_callback_t callback, | ||
956 | void *callback_data) | ||
957 | { | ||
958 | int r; | ||
959 | |||
960 | if ((unsigned)omapfb_nb->plane_idx > OMAPFB_PLANE_NUM) | ||
961 | return -EINVAL; | ||
962 | |||
963 | if (!notifier_inited) { | ||
964 | omapfb_init_notifier(); | ||
965 | notifier_inited = 1; | ||
966 | } | ||
967 | |||
968 | omapfb_nb->nb.notifier_call = (int (*)(struct notifier_block *, | ||
969 | unsigned long, void *))callback; | ||
970 | omapfb_nb->data = callback_data; | ||
971 | r = blocking_notifier_chain_register( | ||
972 | &omapfb_client_list[omapfb_nb->plane_idx], | ||
973 | &omapfb_nb->nb); | ||
974 | if (r) | ||
975 | return r; | ||
976 | if (omapfb_dev != NULL && | ||
977 | omapfb_dev->ctrl && omapfb_dev->ctrl->bind_client) { | ||
978 | omapfb_dev->ctrl->bind_client(omapfb_nb); | ||
979 | } | ||
980 | |||
981 | return 0; | ||
982 | } | ||
983 | EXPORT_SYMBOL(omapfb_register_client); | ||
984 | |||
985 | int omapfb_unregister_client(struct omapfb_notifier_block *omapfb_nb) | ||
986 | { | ||
987 | return blocking_notifier_chain_unregister( | ||
988 | &omapfb_client_list[omapfb_nb->plane_idx], &omapfb_nb->nb); | ||
989 | } | ||
990 | EXPORT_SYMBOL(omapfb_unregister_client); | ||
991 | |||
992 | void omapfb_notify_clients(struct omapfb_device *fbdev, unsigned long event) | ||
993 | { | ||
994 | int i; | ||
995 | |||
996 | if (!notifier_inited) | ||
997 | /* no client registered yet */ | ||
998 | return; | ||
999 | |||
1000 | for (i = 0; i < OMAPFB_PLANE_NUM; i++) | ||
1001 | blocking_notifier_call_chain(&omapfb_client_list[i], event, | ||
1002 | fbdev->fb_info[i]); | ||
1003 | } | ||
1004 | EXPORT_SYMBOL(omapfb_notify_clients); | ||
1005 | |||
1006 | static int omapfb_set_update_mode(struct omapfb_device *fbdev, | ||
1007 | enum omapfb_update_mode mode) | ||
1008 | { | ||
1009 | int r; | ||
1010 | |||
1011 | omapfb_rqueue_lock(fbdev); | ||
1012 | r = fbdev->ctrl->set_update_mode(mode); | ||
1013 | omapfb_rqueue_unlock(fbdev); | ||
1014 | |||
1015 | return r; | ||
1016 | } | ||
1017 | |||
1018 | static enum omapfb_update_mode omapfb_get_update_mode(struct omapfb_device *fbdev) | ||
1019 | { | ||
1020 | int r; | ||
1021 | |||
1022 | omapfb_rqueue_lock(fbdev); | ||
1023 | r = fbdev->ctrl->get_update_mode(); | ||
1024 | omapfb_rqueue_unlock(fbdev); | ||
1025 | |||
1026 | return r; | ||
1027 | } | ||
1028 | |||
1029 | static void omapfb_get_caps(struct omapfb_device *fbdev, int plane, | ||
1030 | struct omapfb_caps *caps) | ||
1031 | { | ||
1032 | memset(caps, 0, sizeof(*caps)); | ||
1033 | fbdev->ctrl->get_caps(plane, caps); | ||
1034 | caps->ctrl |= fbdev->panel->get_caps(fbdev->panel); | ||
1035 | } | ||
1036 | |||
1037 | /* For lcd testing */ | ||
1038 | void omapfb_write_first_pixel(struct omapfb_device *fbdev, u16 pixval) | ||
1039 | { | ||
1040 | omapfb_rqueue_lock(fbdev); | ||
1041 | *(u16 *)fbdev->mem_desc.region[0].vaddr = pixval; | ||
1042 | if (fbdev->ctrl->get_update_mode() == OMAPFB_MANUAL_UPDATE) { | ||
1043 | struct omapfb_update_window win; | ||
1044 | |||
1045 | memset(&win, 0, sizeof(win)); | ||
1046 | win.width = 2; | ||
1047 | win.height = 2; | ||
1048 | win.out_width = 2; | ||
1049 | win.out_height = 2; | ||
1050 | fbdev->ctrl->update_window(fbdev->fb_info[0], &win, NULL, 0); | ||
1051 | } | ||
1052 | omapfb_rqueue_unlock(fbdev); | ||
1053 | } | ||
1054 | EXPORT_SYMBOL(omapfb_write_first_pixel); | ||
1055 | |||
1056 | /* | ||
1057 | * Ioctl interface. Part of the kernel mode frame buffer API is duplicated | ||
1058 | * here to be accessible by user mode code. | ||
1059 | */ | ||
1060 | static int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, | ||
1061 | unsigned long arg) | ||
1062 | { | ||
1063 | struct omapfb_plane_struct *plane = fbi->par; | ||
1064 | struct omapfb_device *fbdev = plane->fbdev; | ||
1065 | struct fb_ops *ops = fbi->fbops; | ||
1066 | union { | ||
1067 | struct omapfb_update_window update_window; | ||
1068 | struct omapfb_plane_info plane_info; | ||
1069 | struct omapfb_mem_info mem_info; | ||
1070 | struct omapfb_color_key color_key; | ||
1071 | enum omapfb_update_mode update_mode; | ||
1072 | struct omapfb_caps caps; | ||
1073 | unsigned int mirror; | ||
1074 | int plane_out; | ||
1075 | int enable_plane; | ||
1076 | } p; | ||
1077 | int r = 0; | ||
1078 | |||
1079 | BUG_ON(!ops); | ||
1080 | switch (cmd) { | ||
1081 | case OMAPFB_MIRROR: | ||
1082 | if (get_user(p.mirror, (int __user *)arg)) | ||
1083 | r = -EFAULT; | ||
1084 | else | ||
1085 | omapfb_mirror(fbi, p.mirror); | ||
1086 | break; | ||
1087 | case OMAPFB_SYNC_GFX: | ||
1088 | omapfb_sync(fbi); | ||
1089 | break; | ||
1090 | case OMAPFB_VSYNC: | ||
1091 | break; | ||
1092 | case OMAPFB_SET_UPDATE_MODE: | ||
1093 | if (get_user(p.update_mode, (int __user *)arg)) | ||
1094 | r = -EFAULT; | ||
1095 | else | ||
1096 | r = omapfb_set_update_mode(fbdev, p.update_mode); | ||
1097 | break; | ||
1098 | case OMAPFB_GET_UPDATE_MODE: | ||
1099 | p.update_mode = omapfb_get_update_mode(fbdev); | ||
1100 | if (put_user(p.update_mode, | ||
1101 | (enum omapfb_update_mode __user *)arg)) | ||
1102 | r = -EFAULT; | ||
1103 | break; | ||
1104 | case OMAPFB_UPDATE_WINDOW_OLD: | ||
1105 | if (copy_from_user(&p.update_window, (void __user *)arg, | ||
1106 | sizeof(struct omapfb_update_window_old))) | ||
1107 | r = -EFAULT; | ||
1108 | else { | ||
1109 | struct omapfb_update_window *u = &p.update_window; | ||
1110 | u->out_x = u->x; | ||
1111 | u->out_y = u->y; | ||
1112 | u->out_width = u->width; | ||
1113 | u->out_height = u->height; | ||
1114 | memset(u->reserved, 0, sizeof(u->reserved)); | ||
1115 | r = omapfb_update_win(fbi, u); | ||
1116 | } | ||
1117 | break; | ||
1118 | case OMAPFB_UPDATE_WINDOW: | ||
1119 | if (copy_from_user(&p.update_window, (void __user *)arg, | ||
1120 | sizeof(p.update_window))) | ||
1121 | r = -EFAULT; | ||
1122 | else | ||
1123 | r = omapfb_update_win(fbi, &p.update_window); | ||
1124 | break; | ||
1125 | case OMAPFB_SETUP_PLANE: | ||
1126 | if (copy_from_user(&p.plane_info, (void __user *)arg, | ||
1127 | sizeof(p.plane_info))) | ||
1128 | r = -EFAULT; | ||
1129 | else | ||
1130 | r = omapfb_setup_plane(fbi, &p.plane_info); | ||
1131 | break; | ||
1132 | case OMAPFB_QUERY_PLANE: | ||
1133 | if ((r = omapfb_query_plane(fbi, &p.plane_info)) < 0) | ||
1134 | break; | ||
1135 | if (copy_to_user((void __user *)arg, &p.plane_info, | ||
1136 | sizeof(p.plane_info))) | ||
1137 | r = -EFAULT; | ||
1138 | break; | ||
1139 | case OMAPFB_SETUP_MEM: | ||
1140 | if (copy_from_user(&p.mem_info, (void __user *)arg, | ||
1141 | sizeof(p.mem_info))) | ||
1142 | r = -EFAULT; | ||
1143 | else | ||
1144 | r = omapfb_setup_mem(fbi, &p.mem_info); | ||
1145 | break; | ||
1146 | case OMAPFB_QUERY_MEM: | ||
1147 | if ((r = omapfb_query_mem(fbi, &p.mem_info)) < 0) | ||
1148 | break; | ||
1149 | if (copy_to_user((void __user *)arg, &p.mem_info, | ||
1150 | sizeof(p.mem_info))) | ||
1151 | r = -EFAULT; | ||
1152 | break; | ||
1153 | case OMAPFB_SET_COLOR_KEY: | ||
1154 | if (copy_from_user(&p.color_key, (void __user *)arg, | ||
1155 | sizeof(p.color_key))) | ||
1156 | r = -EFAULT; | ||
1157 | else | ||
1158 | r = omapfb_set_color_key(fbdev, &p.color_key); | ||
1159 | break; | ||
1160 | case OMAPFB_GET_COLOR_KEY: | ||
1161 | if ((r = omapfb_get_color_key(fbdev, &p.color_key)) < 0) | ||
1162 | break; | ||
1163 | if (copy_to_user((void __user *)arg, &p.color_key, | ||
1164 | sizeof(p.color_key))) | ||
1165 | r = -EFAULT; | ||
1166 | break; | ||
1167 | case OMAPFB_GET_CAPS: | ||
1168 | omapfb_get_caps(fbdev, plane->idx, &p.caps); | ||
1169 | if (copy_to_user((void __user *)arg, &p.caps, sizeof(p.caps))) | ||
1170 | r = -EFAULT; | ||
1171 | break; | ||
1172 | case OMAPFB_LCD_TEST: | ||
1173 | { | ||
1174 | int test_num; | ||
1175 | |||
1176 | if (get_user(test_num, (int __user *)arg)) { | ||
1177 | r = -EFAULT; | ||
1178 | break; | ||
1179 | } | ||
1180 | if (!fbdev->panel->run_test) { | ||
1181 | r = -EINVAL; | ||
1182 | break; | ||
1183 | } | ||
1184 | r = fbdev->panel->run_test(fbdev->panel, test_num); | ||
1185 | break; | ||
1186 | } | ||
1187 | case OMAPFB_CTRL_TEST: | ||
1188 | { | ||
1189 | int test_num; | ||
1190 | |||
1191 | if (get_user(test_num, (int __user *)arg)) { | ||
1192 | r = -EFAULT; | ||
1193 | break; | ||
1194 | } | ||
1195 | if (!fbdev->ctrl->run_test) { | ||
1196 | r = -EINVAL; | ||
1197 | break; | ||
1198 | } | ||
1199 | r = fbdev->ctrl->run_test(test_num); | ||
1200 | break; | ||
1201 | } | ||
1202 | default: | ||
1203 | r = -EINVAL; | ||
1204 | } | ||
1205 | |||
1206 | return r; | ||
1207 | } | ||
1208 | |||
1209 | static int omapfb_mmap(struct fb_info *info, struct vm_area_struct *vma) | ||
1210 | { | ||
1211 | struct omapfb_plane_struct *plane = info->par; | ||
1212 | struct omapfb_device *fbdev = plane->fbdev; | ||
1213 | int r; | ||
1214 | |||
1215 | omapfb_rqueue_lock(fbdev); | ||
1216 | r = fbdev->ctrl->mmap(info, vma); | ||
1217 | omapfb_rqueue_unlock(fbdev); | ||
1218 | |||
1219 | return r; | ||
1220 | } | ||
1221 | |||
1222 | /* | ||
1223 | * Callback table for the frame buffer framework. Some of these pointers | ||
1224 | * will be changed according to the current setting of fb_info->accel_flags. | ||
1225 | */ | ||
1226 | static struct fb_ops omapfb_ops = { | ||
1227 | .owner = THIS_MODULE, | ||
1228 | .fb_open = omapfb_open, | ||
1229 | .fb_release = omapfb_release, | ||
1230 | .fb_setcolreg = omapfb_setcolreg, | ||
1231 | .fb_setcmap = omapfb_setcmap, | ||
1232 | .fb_fillrect = cfb_fillrect, | ||
1233 | .fb_copyarea = cfb_copyarea, | ||
1234 | .fb_imageblit = cfb_imageblit, | ||
1235 | .fb_blank = omapfb_blank, | ||
1236 | .fb_ioctl = omapfb_ioctl, | ||
1237 | .fb_check_var = omapfb_check_var, | ||
1238 | .fb_set_par = omapfb_set_par, | ||
1239 | .fb_rotate = omapfb_rotate, | ||
1240 | .fb_pan_display = omapfb_pan_display, | ||
1241 | }; | ||
1242 | |||
1243 | /* | ||
1244 | * --------------------------------------------------------------------------- | ||
1245 | * Sysfs interface | ||
1246 | * --------------------------------------------------------------------------- | ||
1247 | */ | ||
1248 | /* omapfbX sysfs entries */ | ||
1249 | static ssize_t omapfb_show_caps_num(struct device *dev, | ||
1250 | struct device_attribute *attr, char *buf) | ||
1251 | { | ||
1252 | struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data; | ||
1253 | int plane; | ||
1254 | size_t size; | ||
1255 | struct omapfb_caps caps; | ||
1256 | |||
1257 | plane = 0; | ||
1258 | size = 0; | ||
1259 | while (size < PAGE_SIZE && plane < OMAPFB_PLANE_NUM) { | ||
1260 | omapfb_get_caps(fbdev, plane, &caps); | ||
1261 | size += snprintf(&buf[size], PAGE_SIZE - size, | ||
1262 | "plane#%d %#010x %#010x %#010x\n", | ||
1263 | plane, caps.ctrl, caps.plane_color, caps.wnd_color); | ||
1264 | plane++; | ||
1265 | } | ||
1266 | return size; | ||
1267 | } | ||
1268 | |||
1269 | static ssize_t omapfb_show_caps_text(struct device *dev, | ||
1270 | struct device_attribute *attr, char *buf) | ||
1271 | { | ||
1272 | struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data; | ||
1273 | int i; | ||
1274 | struct omapfb_caps caps; | ||
1275 | int plane; | ||
1276 | size_t size; | ||
1277 | |||
1278 | plane = 0; | ||
1279 | size = 0; | ||
1280 | while (size < PAGE_SIZE && plane < OMAPFB_PLANE_NUM) { | ||
1281 | omapfb_get_caps(fbdev, plane, &caps); | ||
1282 | size += snprintf(&buf[size], PAGE_SIZE - size, | ||
1283 | "plane#%d:\n", plane); | ||
1284 | for (i = 0; i < ARRAY_SIZE(ctrl_caps) && | ||
1285 | size < PAGE_SIZE; i++) { | ||
1286 | if (ctrl_caps[i].flag & caps.ctrl) | ||
1287 | size += snprintf(&buf[size], PAGE_SIZE - size, | ||
1288 | " %s\n", ctrl_caps[i].name); | ||
1289 | } | ||
1290 | size += snprintf(&buf[size], PAGE_SIZE - size, | ||
1291 | " plane colors:\n"); | ||
1292 | for (i = 0; i < ARRAY_SIZE(color_caps) && | ||
1293 | size < PAGE_SIZE; i++) { | ||
1294 | if (color_caps[i].flag & caps.plane_color) | ||
1295 | size += snprintf(&buf[size], PAGE_SIZE - size, | ||
1296 | " %s\n", color_caps[i].name); | ||
1297 | } | ||
1298 | size += snprintf(&buf[size], PAGE_SIZE - size, | ||
1299 | " window colors:\n"); | ||
1300 | for (i = 0; i < ARRAY_SIZE(color_caps) && | ||
1301 | size < PAGE_SIZE; i++) { | ||
1302 | if (color_caps[i].flag & caps.wnd_color) | ||
1303 | size += snprintf(&buf[size], PAGE_SIZE - size, | ||
1304 | " %s\n", color_caps[i].name); | ||
1305 | } | ||
1306 | |||
1307 | plane++; | ||
1308 | } | ||
1309 | return size; | ||
1310 | } | ||
1311 | |||
1312 | static DEVICE_ATTR(caps_num, 0444, omapfb_show_caps_num, NULL); | ||
1313 | static DEVICE_ATTR(caps_text, 0444, omapfb_show_caps_text, NULL); | ||
1314 | |||
1315 | /* panel sysfs entries */ | ||
1316 | static ssize_t omapfb_show_panel_name(struct device *dev, | ||
1317 | struct device_attribute *attr, char *buf) | ||
1318 | { | ||
1319 | struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data; | ||
1320 | |||
1321 | return snprintf(buf, PAGE_SIZE, "%s\n", fbdev->panel->name); | ||
1322 | } | ||
1323 | |||
1324 | static ssize_t omapfb_show_bklight_level(struct device *dev, | ||
1325 | struct device_attribute *attr, | ||
1326 | char *buf) | ||
1327 | { | ||
1328 | struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data; | ||
1329 | int r; | ||
1330 | |||
1331 | if (fbdev->panel->get_bklight_level) { | ||
1332 | r = snprintf(buf, PAGE_SIZE, "%d\n", | ||
1333 | fbdev->panel->get_bklight_level(fbdev->panel)); | ||
1334 | } else | ||
1335 | r = -ENODEV; | ||
1336 | return r; | ||
1337 | } | ||
1338 | |||
1339 | static ssize_t omapfb_store_bklight_level(struct device *dev, | ||
1340 | struct device_attribute *attr, | ||
1341 | const char *buf, size_t size) | ||
1342 | { | ||
1343 | struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data; | ||
1344 | int r; | ||
1345 | |||
1346 | if (fbdev->panel->set_bklight_level) { | ||
1347 | unsigned int level; | ||
1348 | |||
1349 | if (sscanf(buf, "%10d", &level) == 1) { | ||
1350 | r = fbdev->panel->set_bklight_level(fbdev->panel, | ||
1351 | level); | ||
1352 | } else | ||
1353 | r = -EINVAL; | ||
1354 | } else | ||
1355 | r = -ENODEV; | ||
1356 | return r ? r : size; | ||
1357 | } | ||
1358 | |||
1359 | static ssize_t omapfb_show_bklight_max(struct device *dev, | ||
1360 | struct device_attribute *attr, char *buf) | ||
1361 | { | ||
1362 | struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data; | ||
1363 | int r; | ||
1364 | |||
1365 | if (fbdev->panel->get_bklight_level) { | ||
1366 | r = snprintf(buf, PAGE_SIZE, "%d\n", | ||
1367 | fbdev->panel->get_bklight_max(fbdev->panel)); | ||
1368 | } else | ||
1369 | r = -ENODEV; | ||
1370 | return r; | ||
1371 | } | ||
1372 | |||
1373 | static struct device_attribute dev_attr_panel_name = | ||
1374 | __ATTR(name, 0444, omapfb_show_panel_name, NULL); | ||
1375 | static DEVICE_ATTR(backlight_level, 0664, | ||
1376 | omapfb_show_bklight_level, omapfb_store_bklight_level); | ||
1377 | static DEVICE_ATTR(backlight_max, 0444, omapfb_show_bklight_max, NULL); | ||
1378 | |||
1379 | static struct attribute *panel_attrs[] = { | ||
1380 | &dev_attr_panel_name.attr, | ||
1381 | &dev_attr_backlight_level.attr, | ||
1382 | &dev_attr_backlight_max.attr, | ||
1383 | NULL, | ||
1384 | }; | ||
1385 | |||
1386 | static struct attribute_group panel_attr_grp = { | ||
1387 | .name = "panel", | ||
1388 | .attrs = panel_attrs, | ||
1389 | }; | ||
1390 | |||
1391 | /* ctrl sysfs entries */ | ||
1392 | static ssize_t omapfb_show_ctrl_name(struct device *dev, | ||
1393 | struct device_attribute *attr, char *buf) | ||
1394 | { | ||
1395 | struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data; | ||
1396 | |||
1397 | return snprintf(buf, PAGE_SIZE, "%s\n", fbdev->ctrl->name); | ||
1398 | } | ||
1399 | |||
1400 | static struct device_attribute dev_attr_ctrl_name = | ||
1401 | __ATTR(name, 0444, omapfb_show_ctrl_name, NULL); | ||
1402 | |||
1403 | static struct attribute *ctrl_attrs[] = { | ||
1404 | &dev_attr_ctrl_name.attr, | ||
1405 | NULL, | ||
1406 | }; | ||
1407 | |||
1408 | static struct attribute_group ctrl_attr_grp = { | ||
1409 | .name = "ctrl", | ||
1410 | .attrs = ctrl_attrs, | ||
1411 | }; | ||
1412 | |||
1413 | static int omapfb_register_sysfs(struct omapfb_device *fbdev) | ||
1414 | { | ||
1415 | int r; | ||
1416 | |||
1417 | if ((r = device_create_file(fbdev->dev, &dev_attr_caps_num))) | ||
1418 | goto fail0; | ||
1419 | |||
1420 | if ((r = device_create_file(fbdev->dev, &dev_attr_caps_text))) | ||
1421 | goto fail1; | ||
1422 | |||
1423 | if ((r = sysfs_create_group(&fbdev->dev->kobj, &panel_attr_grp))) | ||
1424 | goto fail2; | ||
1425 | |||
1426 | if ((r = sysfs_create_group(&fbdev->dev->kobj, &ctrl_attr_grp))) | ||
1427 | goto fail3; | ||
1428 | |||
1429 | return 0; | ||
1430 | fail3: | ||
1431 | sysfs_remove_group(&fbdev->dev->kobj, &panel_attr_grp); | ||
1432 | fail2: | ||
1433 | device_remove_file(fbdev->dev, &dev_attr_caps_text); | ||
1434 | fail1: | ||
1435 | device_remove_file(fbdev->dev, &dev_attr_caps_num); | ||
1436 | fail0: | ||
1437 | dev_err(fbdev->dev, "unable to register sysfs interface\n"); | ||
1438 | return r; | ||
1439 | } | ||
1440 | |||
1441 | static void omapfb_unregister_sysfs(struct omapfb_device *fbdev) | ||
1442 | { | ||
1443 | sysfs_remove_group(&fbdev->dev->kobj, &ctrl_attr_grp); | ||
1444 | sysfs_remove_group(&fbdev->dev->kobj, &panel_attr_grp); | ||
1445 | device_remove_file(fbdev->dev, &dev_attr_caps_num); | ||
1446 | device_remove_file(fbdev->dev, &dev_attr_caps_text); | ||
1447 | } | ||
1448 | |||
1449 | /* | ||
1450 | * --------------------------------------------------------------------------- | ||
1451 | * LDM callbacks | ||
1452 | * --------------------------------------------------------------------------- | ||
1453 | */ | ||
1454 | /* Initialize system fb_info object and set the default video mode. | ||
1455 | * The frame buffer memory already allocated by lcddma_init | ||
1456 | */ | ||
1457 | static int fbinfo_init(struct omapfb_device *fbdev, struct fb_info *info) | ||
1458 | { | ||
1459 | struct fb_var_screeninfo *var = &info->var; | ||
1460 | struct fb_fix_screeninfo *fix = &info->fix; | ||
1461 | int r = 0; | ||
1462 | |||
1463 | info->fbops = &omapfb_ops; | ||
1464 | info->flags = FBINFO_FLAG_DEFAULT; | ||
1465 | |||
1466 | strncpy(fix->id, MODULE_NAME, sizeof(fix->id)); | ||
1467 | |||
1468 | info->pseudo_palette = fbdev->pseudo_palette; | ||
1469 | |||
1470 | var->accel_flags = def_accel ? FB_ACCELF_TEXT : 0; | ||
1471 | var->xres = def_vxres; | ||
1472 | var->yres = def_vyres; | ||
1473 | var->xres_virtual = def_vxres; | ||
1474 | var->yres_virtual = def_vyres; | ||
1475 | var->rotate = def_rotate; | ||
1476 | var->bits_per_pixel = fbdev->panel->bpp; | ||
1477 | |||
1478 | set_fb_var(info, var); | ||
1479 | set_fb_fix(info); | ||
1480 | |||
1481 | r = fb_alloc_cmap(&info->cmap, 16, 0); | ||
1482 | if (r != 0) | ||
1483 | dev_err(fbdev->dev, "unable to allocate color map memory\n"); | ||
1484 | |||
1485 | return r; | ||
1486 | } | ||
1487 | |||
1488 | /* Release the fb_info object */ | ||
1489 | static void fbinfo_cleanup(struct omapfb_device *fbdev, struct fb_info *fbi) | ||
1490 | { | ||
1491 | fb_dealloc_cmap(&fbi->cmap); | ||
1492 | } | ||
1493 | |||
1494 | static void planes_cleanup(struct omapfb_device *fbdev) | ||
1495 | { | ||
1496 | int i; | ||
1497 | |||
1498 | for (i = 0; i < fbdev->mem_desc.region_cnt; i++) { | ||
1499 | if (fbdev->fb_info[i] == NULL) | ||
1500 | break; | ||
1501 | fbinfo_cleanup(fbdev, fbdev->fb_info[i]); | ||
1502 | framebuffer_release(fbdev->fb_info[i]); | ||
1503 | } | ||
1504 | } | ||
1505 | |||
1506 | static int planes_init(struct omapfb_device *fbdev) | ||
1507 | { | ||
1508 | struct fb_info *fbi; | ||
1509 | int i; | ||
1510 | int r; | ||
1511 | |||
1512 | for (i = 0; i < fbdev->mem_desc.region_cnt; i++) { | ||
1513 | struct omapfb_plane_struct *plane; | ||
1514 | fbi = framebuffer_alloc(sizeof(struct omapfb_plane_struct), | ||
1515 | fbdev->dev); | ||
1516 | if (fbi == NULL) { | ||
1517 | dev_err(fbdev->dev, | ||
1518 | "unable to allocate memory for plane info\n"); | ||
1519 | planes_cleanup(fbdev); | ||
1520 | return -ENOMEM; | ||
1521 | } | ||
1522 | plane = fbi->par; | ||
1523 | plane->idx = i; | ||
1524 | plane->fbdev = fbdev; | ||
1525 | plane->info.mirror = def_mirror; | ||
1526 | fbdev->fb_info[i] = fbi; | ||
1527 | |||
1528 | if ((r = fbinfo_init(fbdev, fbi)) < 0) { | ||
1529 | framebuffer_release(fbi); | ||
1530 | planes_cleanup(fbdev); | ||
1531 | return r; | ||
1532 | } | ||
1533 | plane->info.out_width = fbi->var.xres; | ||
1534 | plane->info.out_height = fbi->var.yres; | ||
1535 | } | ||
1536 | return 0; | ||
1537 | } | ||
1538 | |||
1539 | /* | ||
1540 | * Free driver resources. Can be called to rollback an aborted initialization | ||
1541 | * sequence. | ||
1542 | */ | ||
1543 | static void omapfb_free_resources(struct omapfb_device *fbdev, int state) | ||
1544 | { | ||
1545 | int i; | ||
1546 | |||
1547 | switch (state) { | ||
1548 | case OMAPFB_ACTIVE: | ||
1549 | for (i = 0; i < fbdev->mem_desc.region_cnt; i++) | ||
1550 | unregister_framebuffer(fbdev->fb_info[i]); | ||
1551 | case 7: | ||
1552 | omapfb_unregister_sysfs(fbdev); | ||
1553 | case 6: | ||
1554 | fbdev->panel->disable(fbdev->panel); | ||
1555 | case 5: | ||
1556 | omapfb_set_update_mode(fbdev, OMAPFB_UPDATE_DISABLED); | ||
1557 | case 4: | ||
1558 | planes_cleanup(fbdev); | ||
1559 | case 3: | ||
1560 | ctrl_cleanup(fbdev); | ||
1561 | case 2: | ||
1562 | fbdev->panel->cleanup(fbdev->panel); | ||
1563 | case 1: | ||
1564 | dev_set_drvdata(fbdev->dev, NULL); | ||
1565 | kfree(fbdev); | ||
1566 | case 0: | ||
1567 | /* nothing to free */ | ||
1568 | break; | ||
1569 | default: | ||
1570 | BUG(); | ||
1571 | } | ||
1572 | } | ||
1573 | |||
1574 | static int omapfb_find_ctrl(struct omapfb_device *fbdev) | ||
1575 | { | ||
1576 | struct omapfb_platform_data *conf; | ||
1577 | char name[17]; | ||
1578 | int i; | ||
1579 | |||
1580 | conf = fbdev->dev->platform_data; | ||
1581 | |||
1582 | fbdev->ctrl = NULL; | ||
1583 | |||
1584 | strncpy(name, conf->lcd.ctrl_name, sizeof(name) - 1); | ||
1585 | name[sizeof(name) - 1] = '\0'; | ||
1586 | |||
1587 | if (strcmp(name, "internal") == 0) { | ||
1588 | fbdev->ctrl = fbdev->int_ctrl; | ||
1589 | return 0; | ||
1590 | } | ||
1591 | |||
1592 | for (i = 0; i < ARRAY_SIZE(ctrls); i++) { | ||
1593 | dev_dbg(fbdev->dev, "ctrl %s\n", ctrls[i]->name); | ||
1594 | if (strcmp(ctrls[i]->name, name) == 0) { | ||
1595 | fbdev->ctrl = ctrls[i]; | ||
1596 | break; | ||
1597 | } | ||
1598 | } | ||
1599 | |||
1600 | if (fbdev->ctrl == NULL) { | ||
1601 | dev_dbg(fbdev->dev, "ctrl %s not supported\n", name); | ||
1602 | return -1; | ||
1603 | } | ||
1604 | |||
1605 | return 0; | ||
1606 | } | ||
1607 | |||
1608 | static void check_required_callbacks(struct omapfb_device *fbdev) | ||
1609 | { | ||
1610 | #define _C(x) (fbdev->ctrl->x != NULL) | ||
1611 | #define _P(x) (fbdev->panel->x != NULL) | ||
1612 | BUG_ON(fbdev->ctrl == NULL || fbdev->panel == NULL); | ||
1613 | BUG_ON(!(_C(init) && _C(cleanup) && _C(get_caps) && | ||
1614 | _C(set_update_mode) && _C(setup_plane) && _C(enable_plane) && | ||
1615 | _P(init) && _P(cleanup) && _P(enable) && _P(disable) && | ||
1616 | _P(get_caps))); | ||
1617 | #undef _P | ||
1618 | #undef _C | ||
1619 | } | ||
1620 | |||
1621 | /* | ||
1622 | * Called by LDM binding to probe and attach a new device. | ||
1623 | * Initialization sequence: | ||
1624 | * 1. allocate system omapfb_device structure | ||
1625 | * 2. select controller type according to platform configuration | ||
1626 | * init LCD panel | ||
1627 | * 3. init LCD controller and LCD DMA | ||
1628 | * 4. init system fb_info structure for all planes | ||
1629 | * 5. setup video mode for first plane and enable it | ||
1630 | * 6. enable LCD panel | ||
1631 | * 7. register sysfs attributes | ||
1632 | * OMAPFB_ACTIVE: register system fb_info structure for all planes | ||
1633 | */ | ||
1634 | static int omapfb_do_probe(struct platform_device *pdev, | ||
1635 | struct lcd_panel *panel) | ||
1636 | { | ||
1637 | struct omapfb_device *fbdev = NULL; | ||
1638 | int init_state; | ||
1639 | unsigned long phz, hhz, vhz; | ||
1640 | unsigned long vram; | ||
1641 | int i; | ||
1642 | int r = 0; | ||
1643 | |||
1644 | init_state = 0; | ||
1645 | |||
1646 | if (pdev->num_resources != 0) { | ||
1647 | dev_err(&pdev->dev, "probed for an unknown device\n"); | ||
1648 | r = -ENODEV; | ||
1649 | goto cleanup; | ||
1650 | } | ||
1651 | |||
1652 | if (pdev->dev.platform_data == NULL) { | ||
1653 | dev_err(&pdev->dev, "missing platform data\n"); | ||
1654 | r = -ENOENT; | ||
1655 | goto cleanup; | ||
1656 | } | ||
1657 | |||
1658 | fbdev = kzalloc(sizeof(struct omapfb_device), GFP_KERNEL); | ||
1659 | if (fbdev == NULL) { | ||
1660 | dev_err(&pdev->dev, | ||
1661 | "unable to allocate memory for device info\n"); | ||
1662 | r = -ENOMEM; | ||
1663 | goto cleanup; | ||
1664 | } | ||
1665 | init_state++; | ||
1666 | |||
1667 | fbdev->dev = &pdev->dev; | ||
1668 | fbdev->panel = panel; | ||
1669 | platform_set_drvdata(pdev, fbdev); | ||
1670 | |||
1671 | mutex_init(&fbdev->rqueue_mutex); | ||
1672 | |||
1673 | #ifdef CONFIG_ARCH_OMAP1 | ||
1674 | fbdev->int_ctrl = &omap1_int_ctrl; | ||
1675 | #ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL | ||
1676 | fbdev->ext_if = &omap1_ext_if; | ||
1677 | #endif | ||
1678 | #else /* OMAP2 */ | ||
1679 | fbdev->int_ctrl = &omap2_int_ctrl; | ||
1680 | #ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL | ||
1681 | fbdev->ext_if = &omap2_ext_if; | ||
1682 | #endif | ||
1683 | #endif | ||
1684 | if (omapfb_find_ctrl(fbdev) < 0) { | ||
1685 | dev_err(fbdev->dev, | ||
1686 | "LCD controller not found, board not supported\n"); | ||
1687 | r = -ENODEV; | ||
1688 | goto cleanup; | ||
1689 | } | ||
1690 | |||
1691 | r = fbdev->panel->init(fbdev->panel, fbdev); | ||
1692 | if (r) | ||
1693 | goto cleanup; | ||
1694 | |||
1695 | pr_info("omapfb: configured for panel %s\n", fbdev->panel->name); | ||
1696 | |||
1697 | def_vxres = def_vxres ? : fbdev->panel->x_res; | ||
1698 | def_vyres = def_vyres ? : fbdev->panel->y_res; | ||
1699 | |||
1700 | init_state++; | ||
1701 | |||
1702 | r = ctrl_init(fbdev); | ||
1703 | if (r) | ||
1704 | goto cleanup; | ||
1705 | if (fbdev->ctrl->mmap != NULL) | ||
1706 | omapfb_ops.fb_mmap = omapfb_mmap; | ||
1707 | init_state++; | ||
1708 | |||
1709 | check_required_callbacks(fbdev); | ||
1710 | |||
1711 | r = planes_init(fbdev); | ||
1712 | if (r) | ||
1713 | goto cleanup; | ||
1714 | init_state++; | ||
1715 | |||
1716 | #ifdef CONFIG_FB_OMAP_DMA_TUNE | ||
1717 | /* Set DMA priority for EMIFF access to highest */ | ||
1718 | if (cpu_class_is_omap1()) | ||
1719 | omap_set_dma_priority(0, OMAP_DMA_PORT_EMIFF, 15); | ||
1720 | #endif | ||
1721 | |||
1722 | r = ctrl_change_mode(fbdev->fb_info[0]); | ||
1723 | if (r) { | ||
1724 | dev_err(fbdev->dev, "mode setting failed\n"); | ||
1725 | goto cleanup; | ||
1726 | } | ||
1727 | |||
1728 | /* GFX plane is enabled by default */ | ||
1729 | r = fbdev->ctrl->enable_plane(OMAPFB_PLANE_GFX, 1); | ||
1730 | if (r) | ||
1731 | goto cleanup; | ||
1732 | |||
1733 | omapfb_set_update_mode(fbdev, manual_update ? | ||
1734 | OMAPFB_MANUAL_UPDATE : OMAPFB_AUTO_UPDATE); | ||
1735 | init_state++; | ||
1736 | |||
1737 | r = fbdev->panel->enable(fbdev->panel); | ||
1738 | if (r) | ||
1739 | goto cleanup; | ||
1740 | init_state++; | ||
1741 | |||
1742 | r = omapfb_register_sysfs(fbdev); | ||
1743 | if (r) | ||
1744 | goto cleanup; | ||
1745 | init_state++; | ||
1746 | |||
1747 | vram = 0; | ||
1748 | for (i = 0; i < fbdev->mem_desc.region_cnt; i++) { | ||
1749 | r = register_framebuffer(fbdev->fb_info[i]); | ||
1750 | if (r != 0) { | ||
1751 | dev_err(fbdev->dev, | ||
1752 | "registering framebuffer %d failed\n", i); | ||
1753 | goto cleanup; | ||
1754 | } | ||
1755 | vram += fbdev->mem_desc.region[i].size; | ||
1756 | } | ||
1757 | |||
1758 | fbdev->state = OMAPFB_ACTIVE; | ||
1759 | |||
1760 | panel = fbdev->panel; | ||
1761 | phz = panel->pixel_clock * 1000; | ||
1762 | hhz = phz * 10 / (panel->hfp + panel->x_res + panel->hbp + panel->hsw); | ||
1763 | vhz = hhz / (panel->vfp + panel->y_res + panel->vbp + panel->vsw); | ||
1764 | |||
1765 | omapfb_dev = fbdev; | ||
1766 | |||
1767 | pr_info("omapfb: Framebuffer initialized. Total vram %lu planes %d\n", | ||
1768 | vram, fbdev->mem_desc.region_cnt); | ||
1769 | pr_info("omapfb: Pixclock %lu kHz hfreq %lu.%lu kHz " | ||
1770 | "vfreq %lu.%lu Hz\n", | ||
1771 | phz / 1000, hhz / 10000, hhz % 10, vhz / 10, vhz % 10); | ||
1772 | |||
1773 | return 0; | ||
1774 | |||
1775 | cleanup: | ||
1776 | omapfb_free_resources(fbdev, init_state); | ||
1777 | |||
1778 | return r; | ||
1779 | } | ||
1780 | |||
1781 | static int omapfb_probe(struct platform_device *pdev) | ||
1782 | { | ||
1783 | BUG_ON(fbdev_pdev != NULL); | ||
1784 | |||
1785 | /* Delay actual initialization until the LCD is registered */ | ||
1786 | fbdev_pdev = pdev; | ||
1787 | if (fbdev_panel != NULL) | ||
1788 | omapfb_do_probe(fbdev_pdev, fbdev_panel); | ||
1789 | return 0; | ||
1790 | } | ||
1791 | |||
1792 | void omapfb_register_panel(struct lcd_panel *panel) | ||
1793 | { | ||
1794 | BUG_ON(fbdev_panel != NULL); | ||
1795 | |||
1796 | fbdev_panel = panel; | ||
1797 | if (fbdev_pdev != NULL) | ||
1798 | omapfb_do_probe(fbdev_pdev, fbdev_panel); | ||
1799 | } | ||
1800 | |||
1801 | /* Called when the device is being detached from the driver */ | ||
1802 | static int omapfb_remove(struct platform_device *pdev) | ||
1803 | { | ||
1804 | struct omapfb_device *fbdev = platform_get_drvdata(pdev); | ||
1805 | enum omapfb_state saved_state = fbdev->state; | ||
1806 | |||
1807 | /* FIXME: wait till completion of pending events */ | ||
1808 | |||
1809 | fbdev->state = OMAPFB_DISABLED; | ||
1810 | omapfb_free_resources(fbdev, saved_state); | ||
1811 | |||
1812 | return 0; | ||
1813 | } | ||
1814 | |||
1815 | /* PM suspend */ | ||
1816 | static int omapfb_suspend(struct platform_device *pdev, pm_message_t mesg) | ||
1817 | { | ||
1818 | struct omapfb_device *fbdev = platform_get_drvdata(pdev); | ||
1819 | |||
1820 | omapfb_blank(VESA_POWERDOWN, fbdev->fb_info[0]); | ||
1821 | |||
1822 | return 0; | ||
1823 | } | ||
1824 | |||
1825 | /* PM resume */ | ||
1826 | static int omapfb_resume(struct platform_device *pdev) | ||
1827 | { | ||
1828 | struct omapfb_device *fbdev = platform_get_drvdata(pdev); | ||
1829 | |||
1830 | omapfb_blank(VESA_NO_BLANKING, fbdev->fb_info[0]); | ||
1831 | return 0; | ||
1832 | } | ||
1833 | |||
1834 | static struct platform_driver omapfb_driver = { | ||
1835 | .probe = omapfb_probe, | ||
1836 | .remove = omapfb_remove, | ||
1837 | .suspend = omapfb_suspend, | ||
1838 | .resume = omapfb_resume, | ||
1839 | .driver = { | ||
1840 | .name = MODULE_NAME, | ||
1841 | .owner = THIS_MODULE, | ||
1842 | }, | ||
1843 | }; | ||
1844 | |||
1845 | #ifndef MODULE | ||
1846 | |||
1847 | /* Process kernel command line parameters */ | ||
1848 | static int __init omapfb_setup(char *options) | ||
1849 | { | ||
1850 | char *this_opt = NULL; | ||
1851 | int r = 0; | ||
1852 | |||
1853 | pr_debug("omapfb: options %s\n", options); | ||
1854 | |||
1855 | if (!options || !*options) | ||
1856 | return 0; | ||
1857 | |||
1858 | while (!r && (this_opt = strsep(&options, ",")) != NULL) { | ||
1859 | if (!strncmp(this_opt, "accel", 5)) | ||
1860 | def_accel = 1; | ||
1861 | else if (!strncmp(this_opt, "vram:", 5)) { | ||
1862 | char *suffix; | ||
1863 | unsigned long vram; | ||
1864 | vram = (simple_strtoul(this_opt + 5, &suffix, 0)); | ||
1865 | switch (suffix[0]) { | ||
1866 | case '\0': | ||
1867 | break; | ||
1868 | case 'm': | ||
1869 | case 'M': | ||
1870 | vram *= 1024; | ||
1871 | /* Fall through */ | ||
1872 | case 'k': | ||
1873 | case 'K': | ||
1874 | vram *= 1024; | ||
1875 | break; | ||
1876 | default: | ||
1877 | pr_debug("omapfb: invalid vram suffix %c\n", | ||
1878 | suffix[0]); | ||
1879 | r = -1; | ||
1880 | } | ||
1881 | def_vram[def_vram_cnt++] = vram; | ||
1882 | } | ||
1883 | else if (!strncmp(this_opt, "vxres:", 6)) | ||
1884 | def_vxres = simple_strtoul(this_opt + 6, NULL, 0); | ||
1885 | else if (!strncmp(this_opt, "vyres:", 6)) | ||
1886 | def_vyres = simple_strtoul(this_opt + 6, NULL, 0); | ||
1887 | else if (!strncmp(this_opt, "rotate:", 7)) | ||
1888 | def_rotate = (simple_strtoul(this_opt + 7, NULL, 0)); | ||
1889 | else if (!strncmp(this_opt, "mirror:", 7)) | ||
1890 | def_mirror = (simple_strtoul(this_opt + 7, NULL, 0)); | ||
1891 | else if (!strncmp(this_opt, "manual_update", 13)) | ||
1892 | manual_update = 1; | ||
1893 | else { | ||
1894 | pr_debug("omapfb: invalid option\n"); | ||
1895 | r = -1; | ||
1896 | } | ||
1897 | } | ||
1898 | |||
1899 | return r; | ||
1900 | } | ||
1901 | |||
1902 | #endif | ||
1903 | |||
1904 | /* Register both the driver and the device */ | ||
1905 | static int __init omapfb_init(void) | ||
1906 | { | ||
1907 | #ifndef MODULE | ||
1908 | char *option; | ||
1909 | |||
1910 | if (fb_get_options("omapfb", &option)) | ||
1911 | return -ENODEV; | ||
1912 | omapfb_setup(option); | ||
1913 | #endif | ||
1914 | /* Register the driver with LDM */ | ||
1915 | if (platform_driver_register(&omapfb_driver)) { | ||
1916 | pr_debug("failed to register omapfb driver\n"); | ||
1917 | return -ENODEV; | ||
1918 | } | ||
1919 | |||
1920 | return 0; | ||
1921 | } | ||
1922 | |||
1923 | static void __exit omapfb_cleanup(void) | ||
1924 | { | ||
1925 | platform_driver_unregister(&omapfb_driver); | ||
1926 | } | ||
1927 | |||
1928 | module_param_named(accel, def_accel, uint, 0664); | ||
1929 | module_param_array_named(vram, def_vram, ulong, &def_vram_cnt, 0664); | ||
1930 | module_param_named(vxres, def_vxres, long, 0664); | ||
1931 | module_param_named(vyres, def_vyres, long, 0664); | ||
1932 | module_param_named(rotate, def_rotate, uint, 0664); | ||
1933 | module_param_named(mirror, def_mirror, uint, 0664); | ||
1934 | module_param_named(manual_update, manual_update, bool, 0664); | ||
1935 | |||
1936 | module_init(omapfb_init); | ||
1937 | module_exit(omapfb_cleanup); | ||
1938 | |||
1939 | MODULE_DESCRIPTION("TI OMAP framebuffer driver"); | ||
1940 | MODULE_AUTHOR("Imre Deak <imre.deak@nokia.com>"); | ||
1941 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/omap/rfbi.c b/drivers/video/omap/rfbi.c new file mode 100644 index 000000000000..2b4269813b22 --- /dev/null +++ b/drivers/video/omap/rfbi.c | |||
@@ -0,0 +1,588 @@ | |||
1 | /* | ||
2 | * OMAP2 Remote Frame Buffer Interface support | ||
3 | * | ||
4 | * Copyright (C) 2005 Nokia Corporation | ||
5 | * Author: Juha Yrjölä <juha.yrjola@nokia.com> | ||
6 | * Imre Deak <imre.deak@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License along | ||
19 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
20 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
21 | */ | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/delay.h> | ||
24 | #include <linux/i2c.h> | ||
25 | #include <linux/err.h> | ||
26 | #include <linux/interrupt.h> | ||
27 | #include <linux/clk.h> | ||
28 | #include <linux/io.h> | ||
29 | |||
30 | #include <asm/arch/omapfb.h> | ||
31 | |||
32 | #include "dispc.h" | ||
33 | |||
34 | /* To work around an RFBI transfer rate limitation */ | ||
35 | #define OMAP_RFBI_RATE_LIMIT 1 | ||
36 | |||
37 | #define RFBI_BASE 0x48050800 | ||
38 | #define RFBI_REVISION 0x0000 | ||
39 | #define RFBI_SYSCONFIG 0x0010 | ||
40 | #define RFBI_SYSSTATUS 0x0014 | ||
41 | #define RFBI_CONTROL 0x0040 | ||
42 | #define RFBI_PIXEL_CNT 0x0044 | ||
43 | #define RFBI_LINE_NUMBER 0x0048 | ||
44 | #define RFBI_CMD 0x004c | ||
45 | #define RFBI_PARAM 0x0050 | ||
46 | #define RFBI_DATA 0x0054 | ||
47 | #define RFBI_READ 0x0058 | ||
48 | #define RFBI_STATUS 0x005c | ||
49 | #define RFBI_CONFIG0 0x0060 | ||
50 | #define RFBI_ONOFF_TIME0 0x0064 | ||
51 | #define RFBI_CYCLE_TIME0 0x0068 | ||
52 | #define RFBI_DATA_CYCLE1_0 0x006c | ||
53 | #define RFBI_DATA_CYCLE2_0 0x0070 | ||
54 | #define RFBI_DATA_CYCLE3_0 0x0074 | ||
55 | #define RFBI_VSYNC_WIDTH 0x0090 | ||
56 | #define RFBI_HSYNC_WIDTH 0x0094 | ||
57 | |||
58 | #define DISPC_BASE 0x48050400 | ||
59 | #define DISPC_CONTROL 0x0040 | ||
60 | |||
61 | static struct { | ||
62 | u32 base; | ||
63 | void (*lcdc_callback)(void *data); | ||
64 | void *lcdc_callback_data; | ||
65 | unsigned long l4_khz; | ||
66 | int bits_per_cycle; | ||
67 | struct omapfb_device *fbdev; | ||
68 | struct clk *dss_ick; | ||
69 | struct clk *dss1_fck; | ||
70 | unsigned tearsync_pin_cnt; | ||
71 | unsigned tearsync_mode; | ||
72 | } rfbi; | ||
73 | |||
74 | static inline void rfbi_write_reg(int idx, u32 val) | ||
75 | { | ||
76 | __raw_writel(val, rfbi.base + idx); | ||
77 | } | ||
78 | |||
79 | static inline u32 rfbi_read_reg(int idx) | ||
80 | { | ||
81 | return __raw_readl(rfbi.base + idx); | ||
82 | } | ||
83 | |||
84 | static int rfbi_get_clocks(void) | ||
85 | { | ||
86 | if (IS_ERR((rfbi.dss_ick = clk_get(rfbi.fbdev->dev, "dss_ick")))) { | ||
87 | dev_err(rfbi.fbdev->dev, "can't get dss_ick"); | ||
88 | return PTR_ERR(rfbi.dss_ick); | ||
89 | } | ||
90 | |||
91 | if (IS_ERR((rfbi.dss1_fck = clk_get(rfbi.fbdev->dev, "dss1_fck")))) { | ||
92 | dev_err(rfbi.fbdev->dev, "can't get dss1_fck"); | ||
93 | clk_put(rfbi.dss_ick); | ||
94 | return PTR_ERR(rfbi.dss1_fck); | ||
95 | } | ||
96 | |||
97 | return 0; | ||
98 | } | ||
99 | |||
100 | static void rfbi_put_clocks(void) | ||
101 | { | ||
102 | clk_put(rfbi.dss1_fck); | ||
103 | clk_put(rfbi.dss_ick); | ||
104 | } | ||
105 | |||
106 | static void rfbi_enable_clocks(int enable) | ||
107 | { | ||
108 | if (enable) { | ||
109 | clk_enable(rfbi.dss_ick); | ||
110 | clk_enable(rfbi.dss1_fck); | ||
111 | } else { | ||
112 | clk_disable(rfbi.dss1_fck); | ||
113 | clk_disable(rfbi.dss_ick); | ||
114 | } | ||
115 | } | ||
116 | |||
117 | |||
118 | #ifdef VERBOSE | ||
119 | static void rfbi_print_timings(void) | ||
120 | { | ||
121 | u32 l; | ||
122 | u32 time; | ||
123 | |||
124 | l = rfbi_read_reg(RFBI_CONFIG0); | ||
125 | time = 1000000000 / rfbi.l4_khz; | ||
126 | if (l & (1 << 4)) | ||
127 | time *= 2; | ||
128 | |||
129 | dev_dbg(rfbi.fbdev->dev, "Tick time %u ps\n", time); | ||
130 | l = rfbi_read_reg(RFBI_ONOFF_TIME0); | ||
131 | dev_dbg(rfbi.fbdev->dev, | ||
132 | "CSONTIME %d, CSOFFTIME %d, WEONTIME %d, WEOFFTIME %d, " | ||
133 | "REONTIME %d, REOFFTIME %d\n", | ||
134 | l & 0x0f, (l >> 4) & 0x3f, (l >> 10) & 0x0f, (l >> 14) & 0x3f, | ||
135 | (l >> 20) & 0x0f, (l >> 24) & 0x3f); | ||
136 | |||
137 | l = rfbi_read_reg(RFBI_CYCLE_TIME0); | ||
138 | dev_dbg(rfbi.fbdev->dev, | ||
139 | "WECYCLETIME %d, RECYCLETIME %d, CSPULSEWIDTH %d, " | ||
140 | "ACCESSTIME %d\n", | ||
141 | (l & 0x3f), (l >> 6) & 0x3f, (l >> 12) & 0x3f, | ||
142 | (l >> 22) & 0x3f); | ||
143 | } | ||
144 | #else | ||
145 | static void rfbi_print_timings(void) {} | ||
146 | #endif | ||
147 | |||
148 | static void rfbi_set_timings(const struct extif_timings *t) | ||
149 | { | ||
150 | u32 l; | ||
151 | |||
152 | BUG_ON(!t->converted); | ||
153 | |||
154 | rfbi_enable_clocks(1); | ||
155 | rfbi_write_reg(RFBI_ONOFF_TIME0, t->tim[0]); | ||
156 | rfbi_write_reg(RFBI_CYCLE_TIME0, t->tim[1]); | ||
157 | |||
158 | l = rfbi_read_reg(RFBI_CONFIG0); | ||
159 | l &= ~(1 << 4); | ||
160 | l |= (t->tim[2] ? 1 : 0) << 4; | ||
161 | rfbi_write_reg(RFBI_CONFIG0, l); | ||
162 | |||
163 | rfbi_print_timings(); | ||
164 | rfbi_enable_clocks(0); | ||
165 | } | ||
166 | |||
167 | static void rfbi_get_clk_info(u32 *clk_period, u32 *max_clk_div) | ||
168 | { | ||
169 | *clk_period = 1000000000 / rfbi.l4_khz; | ||
170 | *max_clk_div = 2; | ||
171 | } | ||
172 | |||
173 | static int ps_to_rfbi_ticks(int time, int div) | ||
174 | { | ||
175 | unsigned long tick_ps; | ||
176 | int ret; | ||
177 | |||
178 | /* Calculate in picosecs to yield more exact results */ | ||
179 | tick_ps = 1000000000 / (rfbi.l4_khz) * div; | ||
180 | |||
181 | ret = (time + tick_ps - 1) / tick_ps; | ||
182 | |||
183 | return ret; | ||
184 | } | ||
185 | |||
186 | #ifdef OMAP_RFBI_RATE_LIMIT | ||
187 | static unsigned long rfbi_get_max_tx_rate(void) | ||
188 | { | ||
189 | unsigned long l4_rate, dss1_rate; | ||
190 | int min_l4_ticks = 0; | ||
191 | int i; | ||
192 | |||
193 | /* According to TI this can't be calculated so make the | ||
194 | * adjustments for a couple of known frequencies and warn for | ||
195 | * others. | ||
196 | */ | ||
197 | static const struct { | ||
198 | unsigned long l4_clk; /* HZ */ | ||
199 | unsigned long dss1_clk; /* HZ */ | ||
200 | unsigned long min_l4_ticks; | ||
201 | } ftab[] = { | ||
202 | { 55, 132, 7, }, /* 7.86 MPix/s */ | ||
203 | { 110, 110, 12, }, /* 9.16 MPix/s */ | ||
204 | { 110, 132, 10, }, /* 11 Mpix/s */ | ||
205 | { 120, 120, 10, }, /* 12 Mpix/s */ | ||
206 | { 133, 133, 10, }, /* 13.3 Mpix/s */ | ||
207 | }; | ||
208 | |||
209 | l4_rate = rfbi.l4_khz / 1000; | ||
210 | dss1_rate = clk_get_rate(rfbi.dss1_fck) / 1000000; | ||
211 | |||
212 | for (i = 0; i < ARRAY_SIZE(ftab); i++) { | ||
213 | /* Use a window instead of an exact match, to account | ||
214 | * for different DPLL multiplier / divider pairs. | ||
215 | */ | ||
216 | if (abs(ftab[i].l4_clk - l4_rate) < 3 && | ||
217 | abs(ftab[i].dss1_clk - dss1_rate) < 3) { | ||
218 | min_l4_ticks = ftab[i].min_l4_ticks; | ||
219 | break; | ||
220 | } | ||
221 | } | ||
222 | if (i == ARRAY_SIZE(ftab)) { | ||
223 | /* Can't be sure, return anyway the maximum not | ||
224 | * rate-limited. This might cause a problem only for the | ||
225 | * tearing synchronisation. | ||
226 | */ | ||
227 | dev_err(rfbi.fbdev->dev, | ||
228 | "can't determine maximum RFBI transfer rate\n"); | ||
229 | return rfbi.l4_khz * 1000; | ||
230 | } | ||
231 | return rfbi.l4_khz * 1000 / min_l4_ticks; | ||
232 | } | ||
233 | #else | ||
234 | static int rfbi_get_max_tx_rate(void) | ||
235 | { | ||
236 | return rfbi.l4_khz * 1000; | ||
237 | } | ||
238 | #endif | ||
239 | |||
240 | |||
241 | static int rfbi_convert_timings(struct extif_timings *t) | ||
242 | { | ||
243 | u32 l; | ||
244 | int reon, reoff, weon, weoff, cson, csoff, cs_pulse; | ||
245 | int actim, recyc, wecyc; | ||
246 | int div = t->clk_div; | ||
247 | |||
248 | if (div <= 0 || div > 2) | ||
249 | return -1; | ||
250 | |||
251 | /* Make sure that after conversion it still holds that: | ||
252 | * weoff > weon, reoff > reon, recyc >= reoff, wecyc >= weoff, | ||
253 | * csoff > cson, csoff >= max(weoff, reoff), actim > reon | ||
254 | */ | ||
255 | weon = ps_to_rfbi_ticks(t->we_on_time, div); | ||
256 | weoff = ps_to_rfbi_ticks(t->we_off_time, div); | ||
257 | if (weoff <= weon) | ||
258 | weoff = weon + 1; | ||
259 | if (weon > 0x0f) | ||
260 | return -1; | ||
261 | if (weoff > 0x3f) | ||
262 | return -1; | ||
263 | |||
264 | reon = ps_to_rfbi_ticks(t->re_on_time, div); | ||
265 | reoff = ps_to_rfbi_ticks(t->re_off_time, div); | ||
266 | if (reoff <= reon) | ||
267 | reoff = reon + 1; | ||
268 | if (reon > 0x0f) | ||
269 | return -1; | ||
270 | if (reoff > 0x3f) | ||
271 | return -1; | ||
272 | |||
273 | cson = ps_to_rfbi_ticks(t->cs_on_time, div); | ||
274 | csoff = ps_to_rfbi_ticks(t->cs_off_time, div); | ||
275 | if (csoff <= cson) | ||
276 | csoff = cson + 1; | ||
277 | if (csoff < max(weoff, reoff)) | ||
278 | csoff = max(weoff, reoff); | ||
279 | if (cson > 0x0f) | ||
280 | return -1; | ||
281 | if (csoff > 0x3f) | ||
282 | return -1; | ||
283 | |||
284 | l = cson; | ||
285 | l |= csoff << 4; | ||
286 | l |= weon << 10; | ||
287 | l |= weoff << 14; | ||
288 | l |= reon << 20; | ||
289 | l |= reoff << 24; | ||
290 | |||
291 | t->tim[0] = l; | ||
292 | |||
293 | actim = ps_to_rfbi_ticks(t->access_time, div); | ||
294 | if (actim <= reon) | ||
295 | actim = reon + 1; | ||
296 | if (actim > 0x3f) | ||
297 | return -1; | ||
298 | |||
299 | wecyc = ps_to_rfbi_ticks(t->we_cycle_time, div); | ||
300 | if (wecyc < weoff) | ||
301 | wecyc = weoff; | ||
302 | if (wecyc > 0x3f) | ||
303 | return -1; | ||
304 | |||
305 | recyc = ps_to_rfbi_ticks(t->re_cycle_time, div); | ||
306 | if (recyc < reoff) | ||
307 | recyc = reoff; | ||
308 | if (recyc > 0x3f) | ||
309 | return -1; | ||
310 | |||
311 | cs_pulse = ps_to_rfbi_ticks(t->cs_pulse_width, div); | ||
312 | if (cs_pulse > 0x3f) | ||
313 | return -1; | ||
314 | |||
315 | l = wecyc; | ||
316 | l |= recyc << 6; | ||
317 | l |= cs_pulse << 12; | ||
318 | l |= actim << 22; | ||
319 | |||
320 | t->tim[1] = l; | ||
321 | |||
322 | t->tim[2] = div - 1; | ||
323 | |||
324 | t->converted = 1; | ||
325 | |||
326 | return 0; | ||
327 | } | ||
328 | |||
329 | static int rfbi_setup_tearsync(unsigned pin_cnt, | ||
330 | unsigned hs_pulse_time, unsigned vs_pulse_time, | ||
331 | int hs_pol_inv, int vs_pol_inv, int extif_div) | ||
332 | { | ||
333 | int hs, vs; | ||
334 | int min; | ||
335 | u32 l; | ||
336 | |||
337 | if (pin_cnt != 1 && pin_cnt != 2) | ||
338 | return -EINVAL; | ||
339 | |||
340 | hs = ps_to_rfbi_ticks(hs_pulse_time, 1); | ||
341 | vs = ps_to_rfbi_ticks(vs_pulse_time, 1); | ||
342 | if (hs < 2) | ||
343 | return -EDOM; | ||
344 | if (pin_cnt == 2) | ||
345 | min = 2; | ||
346 | else | ||
347 | min = 4; | ||
348 | if (vs < min) | ||
349 | return -EDOM; | ||
350 | if (vs == hs) | ||
351 | return -EINVAL; | ||
352 | rfbi.tearsync_pin_cnt = pin_cnt; | ||
353 | dev_dbg(rfbi.fbdev->dev, | ||
354 | "setup_tearsync: pins %d hs %d vs %d hs_inv %d vs_inv %d\n", | ||
355 | pin_cnt, hs, vs, hs_pol_inv, vs_pol_inv); | ||
356 | |||
357 | rfbi_enable_clocks(1); | ||
358 | rfbi_write_reg(RFBI_HSYNC_WIDTH, hs); | ||
359 | rfbi_write_reg(RFBI_VSYNC_WIDTH, vs); | ||
360 | |||
361 | l = rfbi_read_reg(RFBI_CONFIG0); | ||
362 | if (hs_pol_inv) | ||
363 | l &= ~(1 << 21); | ||
364 | else | ||
365 | l |= 1 << 21; | ||
366 | if (vs_pol_inv) | ||
367 | l &= ~(1 << 20); | ||
368 | else | ||
369 | l |= 1 << 20; | ||
370 | rfbi_enable_clocks(0); | ||
371 | |||
372 | return 0; | ||
373 | } | ||
374 | |||
375 | static int rfbi_enable_tearsync(int enable, unsigned line) | ||
376 | { | ||
377 | u32 l; | ||
378 | |||
379 | dev_dbg(rfbi.fbdev->dev, "tearsync %d line %d mode %d\n", | ||
380 | enable, line, rfbi.tearsync_mode); | ||
381 | if (line > (1 << 11) - 1) | ||
382 | return -EINVAL; | ||
383 | |||
384 | rfbi_enable_clocks(1); | ||
385 | l = rfbi_read_reg(RFBI_CONFIG0); | ||
386 | l &= ~(0x3 << 2); | ||
387 | if (enable) { | ||
388 | rfbi.tearsync_mode = rfbi.tearsync_pin_cnt; | ||
389 | l |= rfbi.tearsync_mode << 2; | ||
390 | } else | ||
391 | rfbi.tearsync_mode = 0; | ||
392 | rfbi_write_reg(RFBI_CONFIG0, l); | ||
393 | rfbi_write_reg(RFBI_LINE_NUMBER, line); | ||
394 | rfbi_enable_clocks(0); | ||
395 | |||
396 | return 0; | ||
397 | } | ||
398 | |||
399 | static void rfbi_write_command(const void *buf, unsigned int len) | ||
400 | { | ||
401 | rfbi_enable_clocks(1); | ||
402 | if (rfbi.bits_per_cycle == 16) { | ||
403 | const u16 *w = buf; | ||
404 | BUG_ON(len & 1); | ||
405 | for (; len; len -= 2) | ||
406 | rfbi_write_reg(RFBI_CMD, *w++); | ||
407 | } else { | ||
408 | const u8 *b = buf; | ||
409 | BUG_ON(rfbi.bits_per_cycle != 8); | ||
410 | for (; len; len--) | ||
411 | rfbi_write_reg(RFBI_CMD, *b++); | ||
412 | } | ||
413 | rfbi_enable_clocks(0); | ||
414 | } | ||
415 | |||
416 | static void rfbi_read_data(void *buf, unsigned int len) | ||
417 | { | ||
418 | rfbi_enable_clocks(1); | ||
419 | if (rfbi.bits_per_cycle == 16) { | ||
420 | u16 *w = buf; | ||
421 | BUG_ON(len & ~1); | ||
422 | for (; len; len -= 2) { | ||
423 | rfbi_write_reg(RFBI_READ, 0); | ||
424 | *w++ = rfbi_read_reg(RFBI_READ); | ||
425 | } | ||
426 | } else { | ||
427 | u8 *b = buf; | ||
428 | BUG_ON(rfbi.bits_per_cycle != 8); | ||
429 | for (; len; len--) { | ||
430 | rfbi_write_reg(RFBI_READ, 0); | ||
431 | *b++ = rfbi_read_reg(RFBI_READ); | ||
432 | } | ||
433 | } | ||
434 | rfbi_enable_clocks(0); | ||
435 | } | ||
436 | |||
437 | static void rfbi_write_data(const void *buf, unsigned int len) | ||
438 | { | ||
439 | rfbi_enable_clocks(1); | ||
440 | if (rfbi.bits_per_cycle == 16) { | ||
441 | const u16 *w = buf; | ||
442 | BUG_ON(len & 1); | ||
443 | for (; len; len -= 2) | ||
444 | rfbi_write_reg(RFBI_PARAM, *w++); | ||
445 | } else { | ||
446 | const u8 *b = buf; | ||
447 | BUG_ON(rfbi.bits_per_cycle != 8); | ||
448 | for (; len; len--) | ||
449 | rfbi_write_reg(RFBI_PARAM, *b++); | ||
450 | } | ||
451 | rfbi_enable_clocks(0); | ||
452 | } | ||
453 | |||
454 | static void rfbi_transfer_area(int width, int height, | ||
455 | void (callback)(void * data), void *data) | ||
456 | { | ||
457 | u32 w; | ||
458 | |||
459 | BUG_ON(callback == NULL); | ||
460 | |||
461 | rfbi_enable_clocks(1); | ||
462 | omap_dispc_set_lcd_size(width, height); | ||
463 | |||
464 | rfbi.lcdc_callback = callback; | ||
465 | rfbi.lcdc_callback_data = data; | ||
466 | |||
467 | rfbi_write_reg(RFBI_PIXEL_CNT, width * height); | ||
468 | |||
469 | w = rfbi_read_reg(RFBI_CONTROL); | ||
470 | w |= 1; /* enable */ | ||
471 | if (!rfbi.tearsync_mode) | ||
472 | w |= 1 << 4; /* internal trigger, reset by HW */ | ||
473 | rfbi_write_reg(RFBI_CONTROL, w); | ||
474 | |||
475 | omap_dispc_enable_lcd_out(1); | ||
476 | } | ||
477 | |||
478 | static inline void _stop_transfer(void) | ||
479 | { | ||
480 | u32 w; | ||
481 | |||
482 | w = rfbi_read_reg(RFBI_CONTROL); | ||
483 | rfbi_write_reg(RFBI_CONTROL, w & ~(1 << 0)); | ||
484 | rfbi_enable_clocks(0); | ||
485 | } | ||
486 | |||
487 | static void rfbi_dma_callback(void *data) | ||
488 | { | ||
489 | _stop_transfer(); | ||
490 | rfbi.lcdc_callback(rfbi.lcdc_callback_data); | ||
491 | } | ||
492 | |||
493 | static void rfbi_set_bits_per_cycle(int bpc) | ||
494 | { | ||
495 | u32 l; | ||
496 | |||
497 | rfbi_enable_clocks(1); | ||
498 | l = rfbi_read_reg(RFBI_CONFIG0); | ||
499 | l &= ~(0x03 << 0); | ||
500 | |||
501 | switch (bpc) { | ||
502 | case 8: | ||
503 | break; | ||
504 | case 16: | ||
505 | l |= 3; | ||
506 | break; | ||
507 | default: | ||
508 | BUG(); | ||
509 | } | ||
510 | rfbi_write_reg(RFBI_CONFIG0, l); | ||
511 | rfbi.bits_per_cycle = bpc; | ||
512 | rfbi_enable_clocks(0); | ||
513 | } | ||
514 | |||
515 | static int rfbi_init(struct omapfb_device *fbdev) | ||
516 | { | ||
517 | u32 l; | ||
518 | int r; | ||
519 | |||
520 | rfbi.fbdev = fbdev; | ||
521 | rfbi.base = io_p2v(RFBI_BASE); | ||
522 | |||
523 | if ((r = rfbi_get_clocks()) < 0) | ||
524 | return r; | ||
525 | rfbi_enable_clocks(1); | ||
526 | |||
527 | rfbi.l4_khz = clk_get_rate(rfbi.dss_ick) / 1000; | ||
528 | |||
529 | /* Reset */ | ||
530 | rfbi_write_reg(RFBI_SYSCONFIG, 1 << 1); | ||
531 | while (!(rfbi_read_reg(RFBI_SYSSTATUS) & (1 << 0))); | ||
532 | |||
533 | l = rfbi_read_reg(RFBI_SYSCONFIG); | ||
534 | /* Enable autoidle and smart-idle */ | ||
535 | l |= (1 << 0) | (2 << 3); | ||
536 | rfbi_write_reg(RFBI_SYSCONFIG, l); | ||
537 | |||
538 | /* 16-bit interface, ITE trigger mode, 16-bit data */ | ||
539 | l = (0x03 << 0) | (0x00 << 2) | (0x01 << 5) | (0x02 << 7); | ||
540 | l |= (0 << 9) | (1 << 20) | (1 << 21); | ||
541 | rfbi_write_reg(RFBI_CONFIG0, l); | ||
542 | |||
543 | rfbi_write_reg(RFBI_DATA_CYCLE1_0, 0x00000010); | ||
544 | |||
545 | l = rfbi_read_reg(RFBI_CONTROL); | ||
546 | /* Select CS0, clear bypass mode */ | ||
547 | l = (0x01 << 2); | ||
548 | rfbi_write_reg(RFBI_CONTROL, l); | ||
549 | |||
550 | if ((r = omap_dispc_request_irq(rfbi_dma_callback, NULL)) < 0) { | ||
551 | dev_err(fbdev->dev, "can't get DISPC irq\n"); | ||
552 | rfbi_enable_clocks(0); | ||
553 | return r; | ||
554 | } | ||
555 | |||
556 | l = rfbi_read_reg(RFBI_REVISION); | ||
557 | pr_info("omapfb: RFBI version %d.%d initialized\n", | ||
558 | (l >> 4) & 0x0f, l & 0x0f); | ||
559 | |||
560 | rfbi_enable_clocks(0); | ||
561 | |||
562 | return 0; | ||
563 | } | ||
564 | |||
565 | static void rfbi_cleanup(void) | ||
566 | { | ||
567 | omap_dispc_free_irq(); | ||
568 | rfbi_put_clocks(); | ||
569 | } | ||
570 | |||
571 | const struct lcd_ctrl_extif omap2_ext_if = { | ||
572 | .init = rfbi_init, | ||
573 | .cleanup = rfbi_cleanup, | ||
574 | .get_clk_info = rfbi_get_clk_info, | ||
575 | .get_max_tx_rate = rfbi_get_max_tx_rate, | ||
576 | .set_bits_per_cycle = rfbi_set_bits_per_cycle, | ||
577 | .convert_timings = rfbi_convert_timings, | ||
578 | .set_timings = rfbi_set_timings, | ||
579 | .write_command = rfbi_write_command, | ||
580 | .read_data = rfbi_read_data, | ||
581 | .write_data = rfbi_write_data, | ||
582 | .transfer_area = rfbi_transfer_area, | ||
583 | .setup_tearsync = rfbi_setup_tearsync, | ||
584 | .enable_tearsync = rfbi_enable_tearsync, | ||
585 | |||
586 | .max_transmit_size = (u32) ~0, | ||
587 | }; | ||
588 | |||
diff --git a/drivers/video/omap/sossi.c b/drivers/video/omap/sossi.c new file mode 100644 index 000000000000..81dbcf53cf0e --- /dev/null +++ b/drivers/video/omap/sossi.c | |||
@@ -0,0 +1,686 @@ | |||
1 | /* | ||
2 | * OMAP1 Special OptimiSed Screen Interface support | ||
3 | * | ||
4 | * Copyright (C) 2004-2005 Nokia Corporation | ||
5 | * Author: Juha Yrjölä <juha.yrjola@nokia.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License along | ||
18 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
19 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
20 | */ | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/mm.h> | ||
23 | #include <linux/clk.h> | ||
24 | #include <linux/irq.h> | ||
25 | #include <linux/io.h> | ||
26 | |||
27 | #include <asm/arch/dma.h> | ||
28 | #include <asm/arch/omapfb.h> | ||
29 | |||
30 | #include "lcdc.h" | ||
31 | |||
32 | #define MODULE_NAME "omapfb-sossi" | ||
33 | |||
34 | #define OMAP_SOSSI_BASE 0xfffbac00 | ||
35 | #define SOSSI_ID_REG 0x00 | ||
36 | #define SOSSI_INIT1_REG 0x04 | ||
37 | #define SOSSI_INIT2_REG 0x08 | ||
38 | #define SOSSI_INIT3_REG 0x0c | ||
39 | #define SOSSI_FIFO_REG 0x10 | ||
40 | #define SOSSI_REOTABLE_REG 0x14 | ||
41 | #define SOSSI_TEARING_REG 0x18 | ||
42 | #define SOSSI_INIT1B_REG 0x1c | ||
43 | #define SOSSI_FIFOB_REG 0x20 | ||
44 | |||
45 | #define DMA_GSCR 0xfffedc04 | ||
46 | #define DMA_LCD_CCR 0xfffee3c2 | ||
47 | #define DMA_LCD_CTRL 0xfffee3c4 | ||
48 | #define DMA_LCD_LCH_CTRL 0xfffee3ea | ||
49 | |||
50 | #define CONF_SOSSI_RESET_R (1 << 23) | ||
51 | |||
52 | #define RD_ACCESS 0 | ||
53 | #define WR_ACCESS 1 | ||
54 | |||
55 | #define SOSSI_MAX_XMIT_BYTES (512 * 1024) | ||
56 | |||
57 | static struct { | ||
58 | void __iomem *base; | ||
59 | struct clk *fck; | ||
60 | unsigned long fck_hz; | ||
61 | spinlock_t lock; | ||
62 | int bus_pick_count; | ||
63 | int bus_pick_width; | ||
64 | int tearsync_mode; | ||
65 | int tearsync_line; | ||
66 | void (*lcdc_callback)(void *data); | ||
67 | void *lcdc_callback_data; | ||
68 | int vsync_dma_pending; | ||
69 | /* timing for read and write access */ | ||
70 | int clk_div; | ||
71 | u8 clk_tw0[2]; | ||
72 | u8 clk_tw1[2]; | ||
73 | /* | ||
74 | * if last_access is the same as current we don't have to change | ||
75 | * the timings | ||
76 | */ | ||
77 | int last_access; | ||
78 | |||
79 | struct omapfb_device *fbdev; | ||
80 | } sossi; | ||
81 | |||
82 | static inline u32 sossi_read_reg(int reg) | ||
83 | { | ||
84 | return readl(sossi.base + reg); | ||
85 | } | ||
86 | |||
87 | static inline u16 sossi_read_reg16(int reg) | ||
88 | { | ||
89 | return readw(sossi.base + reg); | ||
90 | } | ||
91 | |||
92 | static inline u8 sossi_read_reg8(int reg) | ||
93 | { | ||
94 | return readb(sossi.base + reg); | ||
95 | } | ||
96 | |||
97 | static inline void sossi_write_reg(int reg, u32 value) | ||
98 | { | ||
99 | writel(value, sossi.base + reg); | ||
100 | } | ||
101 | |||
102 | static inline void sossi_write_reg16(int reg, u16 value) | ||
103 | { | ||
104 | writew(value, sossi.base + reg); | ||
105 | } | ||
106 | |||
107 | static inline void sossi_write_reg8(int reg, u8 value) | ||
108 | { | ||
109 | writeb(value, sossi.base + reg); | ||
110 | } | ||
111 | |||
112 | static void sossi_set_bits(int reg, u32 bits) | ||
113 | { | ||
114 | sossi_write_reg(reg, sossi_read_reg(reg) | bits); | ||
115 | } | ||
116 | |||
117 | static void sossi_clear_bits(int reg, u32 bits) | ||
118 | { | ||
119 | sossi_write_reg(reg, sossi_read_reg(reg) & ~bits); | ||
120 | } | ||
121 | |||
122 | #define HZ_TO_PS(x) (1000000000 / (x / 1000)) | ||
123 | |||
124 | static u32 ps_to_sossi_ticks(u32 ps, int div) | ||
125 | { | ||
126 | u32 clk_period = HZ_TO_PS(sossi.fck_hz) * div; | ||
127 | return (clk_period + ps - 1) / clk_period; | ||
128 | } | ||
129 | |||
130 | static int calc_rd_timings(struct extif_timings *t) | ||
131 | { | ||
132 | u32 tw0, tw1; | ||
133 | int reon, reoff, recyc, actim; | ||
134 | int div = t->clk_div; | ||
135 | |||
136 | /* | ||
137 | * Make sure that after conversion it still holds that: | ||
138 | * reoff > reon, recyc >= reoff, actim > reon | ||
139 | */ | ||
140 | reon = ps_to_sossi_ticks(t->re_on_time, div); | ||
141 | /* reon will be exactly one sossi tick */ | ||
142 | if (reon > 1) | ||
143 | return -1; | ||
144 | |||
145 | reoff = ps_to_sossi_ticks(t->re_off_time, div); | ||
146 | |||
147 | if (reoff <= reon) | ||
148 | reoff = reon + 1; | ||
149 | |||
150 | tw0 = reoff - reon; | ||
151 | if (tw0 > 0x10) | ||
152 | return -1; | ||
153 | |||
154 | recyc = ps_to_sossi_ticks(t->re_cycle_time, div); | ||
155 | if (recyc <= reoff) | ||
156 | recyc = reoff + 1; | ||
157 | |||
158 | tw1 = recyc - tw0; | ||
159 | /* values less then 3 result in the SOSSI block resetting itself */ | ||
160 | if (tw1 < 3) | ||
161 | tw1 = 3; | ||
162 | if (tw1 > 0x40) | ||
163 | return -1; | ||
164 | |||
165 | actim = ps_to_sossi_ticks(t->access_time, div); | ||
166 | if (actim < reoff) | ||
167 | actim++; | ||
168 | /* | ||
169 | * access time (data hold time) will be exactly one sossi | ||
170 | * tick | ||
171 | */ | ||
172 | if (actim - reoff > 1) | ||
173 | return -1; | ||
174 | |||
175 | t->tim[0] = tw0 - 1; | ||
176 | t->tim[1] = tw1 - 1; | ||
177 | |||
178 | return 0; | ||
179 | } | ||
180 | |||
181 | static int calc_wr_timings(struct extif_timings *t) | ||
182 | { | ||
183 | u32 tw0, tw1; | ||
184 | int weon, weoff, wecyc; | ||
185 | int div = t->clk_div; | ||
186 | |||
187 | /* | ||
188 | * Make sure that after conversion it still holds that: | ||
189 | * weoff > weon, wecyc >= weoff | ||
190 | */ | ||
191 | weon = ps_to_sossi_ticks(t->we_on_time, div); | ||
192 | /* weon will be exactly one sossi tick */ | ||
193 | if (weon > 1) | ||
194 | return -1; | ||
195 | |||
196 | weoff = ps_to_sossi_ticks(t->we_off_time, div); | ||
197 | if (weoff <= weon) | ||
198 | weoff = weon + 1; | ||
199 | tw0 = weoff - weon; | ||
200 | if (tw0 > 0x10) | ||
201 | return -1; | ||
202 | |||
203 | wecyc = ps_to_sossi_ticks(t->we_cycle_time, div); | ||
204 | if (wecyc <= weoff) | ||
205 | wecyc = weoff + 1; | ||
206 | |||
207 | tw1 = wecyc - tw0; | ||
208 | /* values less then 3 result in the SOSSI block resetting itself */ | ||
209 | if (tw1 < 3) | ||
210 | tw1 = 3; | ||
211 | if (tw1 > 0x40) | ||
212 | return -1; | ||
213 | |||
214 | t->tim[2] = tw0 - 1; | ||
215 | t->tim[3] = tw1 - 1; | ||
216 | |||
217 | return 0; | ||
218 | } | ||
219 | |||
220 | static void _set_timing(int div, int tw0, int tw1) | ||
221 | { | ||
222 | u32 l; | ||
223 | |||
224 | #ifdef VERBOSE | ||
225 | dev_dbg(sossi.fbdev->dev, "Using TW0 = %d, TW1 = %d, div = %d\n", | ||
226 | tw0 + 1, tw1 + 1, div); | ||
227 | #endif | ||
228 | |||
229 | clk_set_rate(sossi.fck, sossi.fck_hz / div); | ||
230 | clk_enable(sossi.fck); | ||
231 | l = sossi_read_reg(SOSSI_INIT1_REG); | ||
232 | l &= ~((0x0f << 20) | (0x3f << 24)); | ||
233 | l |= (tw0 << 20) | (tw1 << 24); | ||
234 | sossi_write_reg(SOSSI_INIT1_REG, l); | ||
235 | clk_disable(sossi.fck); | ||
236 | } | ||
237 | |||
238 | static void _set_bits_per_cycle(int bus_pick_count, int bus_pick_width) | ||
239 | { | ||
240 | u32 l; | ||
241 | |||
242 | l = sossi_read_reg(SOSSI_INIT3_REG); | ||
243 | l &= ~0x3ff; | ||
244 | l |= ((bus_pick_count - 1) << 5) | ((bus_pick_width - 1) & 0x1f); | ||
245 | sossi_write_reg(SOSSI_INIT3_REG, l); | ||
246 | } | ||
247 | |||
248 | static void _set_tearsync_mode(int mode, unsigned line) | ||
249 | { | ||
250 | u32 l; | ||
251 | |||
252 | l = sossi_read_reg(SOSSI_TEARING_REG); | ||
253 | l &= ~(((1 << 11) - 1) << 15); | ||
254 | l |= line << 15; | ||
255 | l &= ~(0x3 << 26); | ||
256 | l |= mode << 26; | ||
257 | sossi_write_reg(SOSSI_TEARING_REG, l); | ||
258 | if (mode) | ||
259 | sossi_set_bits(SOSSI_INIT2_REG, 1 << 6); /* TE logic */ | ||
260 | else | ||
261 | sossi_clear_bits(SOSSI_INIT2_REG, 1 << 6); | ||
262 | } | ||
263 | |||
264 | static inline void set_timing(int access) | ||
265 | { | ||
266 | if (access != sossi.last_access) { | ||
267 | sossi.last_access = access; | ||
268 | _set_timing(sossi.clk_div, | ||
269 | sossi.clk_tw0[access], sossi.clk_tw1[access]); | ||
270 | } | ||
271 | } | ||
272 | |||
273 | static void sossi_start_transfer(void) | ||
274 | { | ||
275 | /* WE */ | ||
276 | sossi_clear_bits(SOSSI_INIT2_REG, 1 << 4); | ||
277 | /* CS active low */ | ||
278 | sossi_clear_bits(SOSSI_INIT1_REG, 1 << 30); | ||
279 | } | ||
280 | |||
281 | static void sossi_stop_transfer(void) | ||
282 | { | ||
283 | /* WE */ | ||
284 | sossi_set_bits(SOSSI_INIT2_REG, 1 << 4); | ||
285 | /* CS active low */ | ||
286 | sossi_set_bits(SOSSI_INIT1_REG, 1 << 30); | ||
287 | } | ||
288 | |||
289 | static void wait_end_of_write(void) | ||
290 | { | ||
291 | /* Before reading we must check if some writings are going on */ | ||
292 | while (!(sossi_read_reg(SOSSI_INIT2_REG) & (1 << 3))); | ||
293 | } | ||
294 | |||
295 | static void send_data(const void *data, unsigned int len) | ||
296 | { | ||
297 | while (len >= 4) { | ||
298 | sossi_write_reg(SOSSI_FIFO_REG, *(const u32 *) data); | ||
299 | len -= 4; | ||
300 | data += 4; | ||
301 | } | ||
302 | while (len >= 2) { | ||
303 | sossi_write_reg16(SOSSI_FIFO_REG, *(const u16 *) data); | ||
304 | len -= 2; | ||
305 | data += 2; | ||
306 | } | ||
307 | while (len) { | ||
308 | sossi_write_reg8(SOSSI_FIFO_REG, *(const u8 *) data); | ||
309 | len--; | ||
310 | data++; | ||
311 | } | ||
312 | } | ||
313 | |||
314 | static void set_cycles(unsigned int len) | ||
315 | { | ||
316 | unsigned long nr_cycles = len / (sossi.bus_pick_width / 8); | ||
317 | |||
318 | BUG_ON((nr_cycles - 1) & ~0x3ffff); | ||
319 | |||
320 | sossi_clear_bits(SOSSI_INIT1_REG, 0x3ffff); | ||
321 | sossi_set_bits(SOSSI_INIT1_REG, (nr_cycles - 1) & 0x3ffff); | ||
322 | } | ||
323 | |||
324 | static int sossi_convert_timings(struct extif_timings *t) | ||
325 | { | ||
326 | int r = 0; | ||
327 | int div = t->clk_div; | ||
328 | |||
329 | t->converted = 0; | ||
330 | |||
331 | if (div <= 0 || div > 8) | ||
332 | return -1; | ||
333 | |||
334 | /* no CS on SOSSI, so ignore cson, csoff, cs_pulsewidth */ | ||
335 | if ((r = calc_rd_timings(t)) < 0) | ||
336 | return r; | ||
337 | |||
338 | if ((r = calc_wr_timings(t)) < 0) | ||
339 | return r; | ||
340 | |||
341 | t->tim[4] = div; | ||
342 | |||
343 | t->converted = 1; | ||
344 | |||
345 | return 0; | ||
346 | } | ||
347 | |||
348 | static void sossi_set_timings(const struct extif_timings *t) | ||
349 | { | ||
350 | BUG_ON(!t->converted); | ||
351 | |||
352 | sossi.clk_tw0[RD_ACCESS] = t->tim[0]; | ||
353 | sossi.clk_tw1[RD_ACCESS] = t->tim[1]; | ||
354 | |||
355 | sossi.clk_tw0[WR_ACCESS] = t->tim[2]; | ||
356 | sossi.clk_tw1[WR_ACCESS] = t->tim[3]; | ||
357 | |||
358 | sossi.clk_div = t->tim[4]; | ||
359 | } | ||
360 | |||
361 | static void sossi_get_clk_info(u32 *clk_period, u32 *max_clk_div) | ||
362 | { | ||
363 | *clk_period = HZ_TO_PS(sossi.fck_hz); | ||
364 | *max_clk_div = 8; | ||
365 | } | ||
366 | |||
367 | static void sossi_set_bits_per_cycle(int bpc) | ||
368 | { | ||
369 | int bus_pick_count, bus_pick_width; | ||
370 | |||
371 | /* | ||
372 | * We set explicitly the the bus_pick_count as well, although | ||
373 | * with remapping/reordering disabled it will be calculated by HW | ||
374 | * as (32 / bus_pick_width). | ||
375 | */ | ||
376 | switch (bpc) { | ||
377 | case 8: | ||
378 | bus_pick_count = 4; | ||
379 | bus_pick_width = 8; | ||
380 | break; | ||
381 | case 16: | ||
382 | bus_pick_count = 2; | ||
383 | bus_pick_width = 16; | ||
384 | break; | ||
385 | default: | ||
386 | BUG(); | ||
387 | return; | ||
388 | } | ||
389 | sossi.bus_pick_width = bus_pick_width; | ||
390 | sossi.bus_pick_count = bus_pick_count; | ||
391 | } | ||
392 | |||
393 | static int sossi_setup_tearsync(unsigned pin_cnt, | ||
394 | unsigned hs_pulse_time, unsigned vs_pulse_time, | ||
395 | int hs_pol_inv, int vs_pol_inv, int div) | ||
396 | { | ||
397 | int hs, vs; | ||
398 | u32 l; | ||
399 | |||
400 | if (pin_cnt != 1 || div < 1 || div > 8) | ||
401 | return -EINVAL; | ||
402 | |||
403 | hs = ps_to_sossi_ticks(hs_pulse_time, div); | ||
404 | vs = ps_to_sossi_ticks(vs_pulse_time, div); | ||
405 | if (vs < 8 || vs <= hs || vs >= (1 << 12)) | ||
406 | return -EDOM; | ||
407 | vs /= 8; | ||
408 | vs--; | ||
409 | if (hs > 8) | ||
410 | hs = 8; | ||
411 | if (hs) | ||
412 | hs--; | ||
413 | |||
414 | dev_dbg(sossi.fbdev->dev, | ||
415 | "setup_tearsync: hs %d vs %d hs_inv %d vs_inv %d\n", | ||
416 | hs, vs, hs_pol_inv, vs_pol_inv); | ||
417 | |||
418 | clk_enable(sossi.fck); | ||
419 | l = sossi_read_reg(SOSSI_TEARING_REG); | ||
420 | l &= ~((1 << 15) - 1); | ||
421 | l |= vs << 3; | ||
422 | l |= hs; | ||
423 | if (hs_pol_inv) | ||
424 | l |= 1 << 29; | ||
425 | else | ||
426 | l &= ~(1 << 29); | ||
427 | if (vs_pol_inv) | ||
428 | l |= 1 << 28; | ||
429 | else | ||
430 | l &= ~(1 << 28); | ||
431 | sossi_write_reg(SOSSI_TEARING_REG, l); | ||
432 | clk_disable(sossi.fck); | ||
433 | |||
434 | return 0; | ||
435 | } | ||
436 | |||
437 | static int sossi_enable_tearsync(int enable, unsigned line) | ||
438 | { | ||
439 | int mode; | ||
440 | |||
441 | dev_dbg(sossi.fbdev->dev, "tearsync %d line %d\n", enable, line); | ||
442 | if (line >= 1 << 11) | ||
443 | return -EINVAL; | ||
444 | if (enable) { | ||
445 | if (line) | ||
446 | mode = 2; /* HS or VS */ | ||
447 | else | ||
448 | mode = 3; /* VS only */ | ||
449 | } else | ||
450 | mode = 0; | ||
451 | sossi.tearsync_line = line; | ||
452 | sossi.tearsync_mode = mode; | ||
453 | |||
454 | return 0; | ||
455 | } | ||
456 | |||
457 | static void sossi_write_command(const void *data, unsigned int len) | ||
458 | { | ||
459 | clk_enable(sossi.fck); | ||
460 | set_timing(WR_ACCESS); | ||
461 | _set_bits_per_cycle(sossi.bus_pick_count, sossi.bus_pick_width); | ||
462 | /* CMD#/DATA */ | ||
463 | sossi_clear_bits(SOSSI_INIT1_REG, 1 << 18); | ||
464 | set_cycles(len); | ||
465 | sossi_start_transfer(); | ||
466 | send_data(data, len); | ||
467 | sossi_stop_transfer(); | ||
468 | wait_end_of_write(); | ||
469 | clk_disable(sossi.fck); | ||
470 | } | ||
471 | |||
472 | static void sossi_write_data(const void *data, unsigned int len) | ||
473 | { | ||
474 | clk_enable(sossi.fck); | ||
475 | set_timing(WR_ACCESS); | ||
476 | _set_bits_per_cycle(sossi.bus_pick_count, sossi.bus_pick_width); | ||
477 | /* CMD#/DATA */ | ||
478 | sossi_set_bits(SOSSI_INIT1_REG, 1 << 18); | ||
479 | set_cycles(len); | ||
480 | sossi_start_transfer(); | ||
481 | send_data(data, len); | ||
482 | sossi_stop_transfer(); | ||
483 | wait_end_of_write(); | ||
484 | clk_disable(sossi.fck); | ||
485 | } | ||
486 | |||
487 | static void sossi_transfer_area(int width, int height, | ||
488 | void (callback)(void *data), void *data) | ||
489 | { | ||
490 | BUG_ON(callback == NULL); | ||
491 | |||
492 | sossi.lcdc_callback = callback; | ||
493 | sossi.lcdc_callback_data = data; | ||
494 | |||
495 | clk_enable(sossi.fck); | ||
496 | set_timing(WR_ACCESS); | ||
497 | _set_bits_per_cycle(sossi.bus_pick_count, sossi.bus_pick_width); | ||
498 | _set_tearsync_mode(sossi.tearsync_mode, sossi.tearsync_line); | ||
499 | /* CMD#/DATA */ | ||
500 | sossi_set_bits(SOSSI_INIT1_REG, 1 << 18); | ||
501 | set_cycles(width * height * sossi.bus_pick_width / 8); | ||
502 | |||
503 | sossi_start_transfer(); | ||
504 | if (sossi.tearsync_mode) { | ||
505 | /* | ||
506 | * Wait for the sync signal and start the transfer only | ||
507 | * then. We can't seem to be able to use HW sync DMA for | ||
508 | * this since LCD DMA shows huge latencies, as if it | ||
509 | * would ignore some of the DMA requests from SoSSI. | ||
510 | */ | ||
511 | unsigned long flags; | ||
512 | |||
513 | spin_lock_irqsave(&sossi.lock, flags); | ||
514 | sossi.vsync_dma_pending++; | ||
515 | spin_unlock_irqrestore(&sossi.lock, flags); | ||
516 | } else | ||
517 | /* Just start the transfer right away. */ | ||
518 | omap_enable_lcd_dma(); | ||
519 | } | ||
520 | |||
521 | static void sossi_dma_callback(void *data) | ||
522 | { | ||
523 | omap_stop_lcd_dma(); | ||
524 | sossi_stop_transfer(); | ||
525 | clk_disable(sossi.fck); | ||
526 | sossi.lcdc_callback(sossi.lcdc_callback_data); | ||
527 | } | ||
528 | |||
529 | static void sossi_read_data(void *data, unsigned int len) | ||
530 | { | ||
531 | clk_enable(sossi.fck); | ||
532 | set_timing(RD_ACCESS); | ||
533 | _set_bits_per_cycle(sossi.bus_pick_count, sossi.bus_pick_width); | ||
534 | /* CMD#/DATA */ | ||
535 | sossi_set_bits(SOSSI_INIT1_REG, 1 << 18); | ||
536 | set_cycles(len); | ||
537 | sossi_start_transfer(); | ||
538 | while (len >= 4) { | ||
539 | *(u32 *) data = sossi_read_reg(SOSSI_FIFO_REG); | ||
540 | len -= 4; | ||
541 | data += 4; | ||
542 | } | ||
543 | while (len >= 2) { | ||
544 | *(u16 *) data = sossi_read_reg16(SOSSI_FIFO_REG); | ||
545 | len -= 2; | ||
546 | data += 2; | ||
547 | } | ||
548 | while (len) { | ||
549 | *(u8 *) data = sossi_read_reg8(SOSSI_FIFO_REG); | ||
550 | len--; | ||
551 | data++; | ||
552 | } | ||
553 | sossi_stop_transfer(); | ||
554 | clk_disable(sossi.fck); | ||
555 | } | ||
556 | |||
557 | static irqreturn_t sossi_match_irq(int irq, void *data) | ||
558 | { | ||
559 | unsigned long flags; | ||
560 | |||
561 | spin_lock_irqsave(&sossi.lock, flags); | ||
562 | if (sossi.vsync_dma_pending) { | ||
563 | sossi.vsync_dma_pending--; | ||
564 | omap_enable_lcd_dma(); | ||
565 | } | ||
566 | spin_unlock_irqrestore(&sossi.lock, flags); | ||
567 | return IRQ_HANDLED; | ||
568 | } | ||
569 | |||
570 | static int sossi_init(struct omapfb_device *fbdev) | ||
571 | { | ||
572 | u32 l, k; | ||
573 | struct clk *fck; | ||
574 | struct clk *dpll1out_ck; | ||
575 | int r; | ||
576 | |||
577 | sossi.base = (void __iomem *)IO_ADDRESS(OMAP_SOSSI_BASE); | ||
578 | sossi.fbdev = fbdev; | ||
579 | spin_lock_init(&sossi.lock); | ||
580 | |||
581 | dpll1out_ck = clk_get(fbdev->dev, "ck_dpll1out"); | ||
582 | if (IS_ERR(dpll1out_ck)) { | ||
583 | dev_err(fbdev->dev, "can't get DPLL1OUT clock\n"); | ||
584 | return PTR_ERR(dpll1out_ck); | ||
585 | } | ||
586 | /* | ||
587 | * We need the parent clock rate, which we might divide further | ||
588 | * depending on the timing requirements of the controller. See | ||
589 | * _set_timings. | ||
590 | */ | ||
591 | sossi.fck_hz = clk_get_rate(dpll1out_ck); | ||
592 | clk_put(dpll1out_ck); | ||
593 | |||
594 | fck = clk_get(fbdev->dev, "ck_sossi"); | ||
595 | if (IS_ERR(fck)) { | ||
596 | dev_err(fbdev->dev, "can't get SoSSI functional clock\n"); | ||
597 | return PTR_ERR(fck); | ||
598 | } | ||
599 | sossi.fck = fck; | ||
600 | |||
601 | /* Reset and enable the SoSSI module */ | ||
602 | l = omap_readl(MOD_CONF_CTRL_1); | ||
603 | l |= CONF_SOSSI_RESET_R; | ||
604 | omap_writel(l, MOD_CONF_CTRL_1); | ||
605 | l &= ~CONF_SOSSI_RESET_R; | ||
606 | omap_writel(l, MOD_CONF_CTRL_1); | ||
607 | |||
608 | clk_enable(sossi.fck); | ||
609 | l = omap_readl(ARM_IDLECT2); | ||
610 | l &= ~(1 << 8); /* DMACK_REQ */ | ||
611 | omap_writel(l, ARM_IDLECT2); | ||
612 | |||
613 | l = sossi_read_reg(SOSSI_INIT2_REG); | ||
614 | /* Enable and reset the SoSSI block */ | ||
615 | l |= (1 << 0) | (1 << 1); | ||
616 | sossi_write_reg(SOSSI_INIT2_REG, l); | ||
617 | /* Take SoSSI out of reset */ | ||
618 | l &= ~(1 << 1); | ||
619 | sossi_write_reg(SOSSI_INIT2_REG, l); | ||
620 | |||
621 | sossi_write_reg(SOSSI_ID_REG, 0); | ||
622 | l = sossi_read_reg(SOSSI_ID_REG); | ||
623 | k = sossi_read_reg(SOSSI_ID_REG); | ||
624 | |||
625 | if (l != 0x55555555 || k != 0xaaaaaaaa) { | ||
626 | dev_err(fbdev->dev, | ||
627 | "invalid SoSSI sync pattern: %08x, %08x\n", l, k); | ||
628 | r = -ENODEV; | ||
629 | goto err; | ||
630 | } | ||
631 | |||
632 | if ((r = omap_lcdc_set_dma_callback(sossi_dma_callback, NULL)) < 0) { | ||
633 | dev_err(fbdev->dev, "can't get LCDC IRQ\n"); | ||
634 | r = -ENODEV; | ||
635 | goto err; | ||
636 | } | ||
637 | |||
638 | l = sossi_read_reg(SOSSI_ID_REG); /* Component code */ | ||
639 | l = sossi_read_reg(SOSSI_ID_REG); | ||
640 | dev_info(fbdev->dev, "SoSSI version %d.%d initialized\n", | ||
641 | l >> 16, l & 0xffff); | ||
642 | |||
643 | l = sossi_read_reg(SOSSI_INIT1_REG); | ||
644 | l |= (1 << 19); /* DMA_MODE */ | ||
645 | l &= ~(1 << 31); /* REORDERING */ | ||
646 | sossi_write_reg(SOSSI_INIT1_REG, l); | ||
647 | |||
648 | if ((r = request_irq(INT_1610_SoSSI_MATCH, sossi_match_irq, | ||
649 | IRQT_FALLING, | ||
650 | "sossi_match", sossi.fbdev->dev)) < 0) { | ||
651 | dev_err(sossi.fbdev->dev, "can't get SoSSI match IRQ\n"); | ||
652 | goto err; | ||
653 | } | ||
654 | |||
655 | clk_disable(sossi.fck); | ||
656 | return 0; | ||
657 | |||
658 | err: | ||
659 | clk_disable(sossi.fck); | ||
660 | clk_put(sossi.fck); | ||
661 | return r; | ||
662 | } | ||
663 | |||
664 | static void sossi_cleanup(void) | ||
665 | { | ||
666 | omap_lcdc_free_dma_callback(); | ||
667 | clk_put(sossi.fck); | ||
668 | } | ||
669 | |||
670 | struct lcd_ctrl_extif omap1_ext_if = { | ||
671 | .init = sossi_init, | ||
672 | .cleanup = sossi_cleanup, | ||
673 | .get_clk_info = sossi_get_clk_info, | ||
674 | .convert_timings = sossi_convert_timings, | ||
675 | .set_timings = sossi_set_timings, | ||
676 | .set_bits_per_cycle = sossi_set_bits_per_cycle, | ||
677 | .setup_tearsync = sossi_setup_tearsync, | ||
678 | .enable_tearsync = sossi_enable_tearsync, | ||
679 | .write_command = sossi_write_command, | ||
680 | .read_data = sossi_read_data, | ||
681 | .write_data = sossi_write_data, | ||
682 | .transfer_area = sossi_transfer_area, | ||
683 | |||
684 | .max_transmit_size = SOSSI_MAX_XMIT_BYTES, | ||
685 | }; | ||
686 | |||
diff --git a/drivers/video/platinumfb.c b/drivers/video/platinumfb.c index e64f8b5d0056..8503e733a172 100644 --- a/drivers/video/platinumfb.c +++ b/drivers/video/platinumfb.c | |||
@@ -52,7 +52,7 @@ struct fb_info_platinum { | |||
52 | struct { | 52 | struct { |
53 | __u8 red, green, blue; | 53 | __u8 red, green, blue; |
54 | } palette[256]; | 54 | } palette[256]; |
55 | u32 pseudo_palette[17]; | 55 | u32 pseudo_palette[16]; |
56 | 56 | ||
57 | volatile struct cmap_regs __iomem *cmap_regs; | 57 | volatile struct cmap_regs __iomem *cmap_regs; |
58 | unsigned long cmap_regs_phys; | 58 | unsigned long cmap_regs_phys; |
diff --git a/drivers/video/pm2fb.c b/drivers/video/pm2fb.c index 0a04483aa3e0..10c0cc6e93fc 100644 --- a/drivers/video/pm2fb.c +++ b/drivers/video/pm2fb.c | |||
@@ -24,7 +24,7 @@ | |||
24 | * License. See the file COPYING in the main directory of this archive for | 24 | * License. See the file COPYING in the main directory of this archive for |
25 | * more details. | 25 | * more details. |
26 | * | 26 | * |
27 | * | 27 | * |
28 | */ | 28 | */ |
29 | 29 | ||
30 | #include <linux/module.h> | 30 | #include <linux/module.h> |
@@ -58,7 +58,7 @@ | |||
58 | #endif | 58 | #endif |
59 | 59 | ||
60 | /* | 60 | /* |
61 | * Driver data | 61 | * Driver data |
62 | */ | 62 | */ |
63 | static char *mode __devinitdata = NULL; | 63 | static char *mode __devinitdata = NULL; |
64 | 64 | ||
@@ -82,12 +82,12 @@ struct pm2fb_par | |||
82 | { | 82 | { |
83 | pm2type_t type; /* Board type */ | 83 | pm2type_t type; /* Board type */ |
84 | unsigned char __iomem *v_regs;/* virtual address of p_regs */ | 84 | unsigned char __iomem *v_regs;/* virtual address of p_regs */ |
85 | u32 memclock; /* memclock */ | 85 | u32 memclock; /* memclock */ |
86 | u32 video; /* video flags before blanking */ | 86 | u32 video; /* video flags before blanking */ |
87 | u32 mem_config; /* MemConfig reg at probe */ | 87 | u32 mem_config; /* MemConfig reg at probe */ |
88 | u32 mem_control; /* MemControl reg at probe */ | 88 | u32 mem_control; /* MemControl reg at probe */ |
89 | u32 boot_address; /* BootAddress reg at probe */ | 89 | u32 boot_address; /* BootAddress reg at probe */ |
90 | u32 palette[16]; | 90 | u32 palette[16]; |
91 | }; | 91 | }; |
92 | 92 | ||
93 | /* | 93 | /* |
@@ -95,12 +95,12 @@ struct pm2fb_par | |||
95 | * if we don't use modedb. | 95 | * if we don't use modedb. |
96 | */ | 96 | */ |
97 | static struct fb_fix_screeninfo pm2fb_fix __devinitdata = { | 97 | static struct fb_fix_screeninfo pm2fb_fix __devinitdata = { |
98 | .id = "", | 98 | .id = "", |
99 | .type = FB_TYPE_PACKED_PIXELS, | 99 | .type = FB_TYPE_PACKED_PIXELS, |
100 | .visual = FB_VISUAL_PSEUDOCOLOR, | 100 | .visual = FB_VISUAL_PSEUDOCOLOR, |
101 | .xpanstep = 1, | 101 | .xpanstep = 1, |
102 | .ypanstep = 1, | 102 | .ypanstep = 1, |
103 | .ywrapstep = 0, | 103 | .ywrapstep = 0, |
104 | .accel = FB_ACCEL_3DLABS_PERMEDIA2, | 104 | .accel = FB_ACCEL_3DLABS_PERMEDIA2, |
105 | }; | 105 | }; |
106 | 106 | ||
@@ -109,26 +109,26 @@ static struct fb_fix_screeninfo pm2fb_fix __devinitdata = { | |||
109 | */ | 109 | */ |
110 | static struct fb_var_screeninfo pm2fb_var __devinitdata = { | 110 | static struct fb_var_screeninfo pm2fb_var __devinitdata = { |
111 | /* "640x480, 8 bpp @ 60 Hz */ | 111 | /* "640x480, 8 bpp @ 60 Hz */ |
112 | .xres = 640, | 112 | .xres = 640, |
113 | .yres = 480, | 113 | .yres = 480, |
114 | .xres_virtual = 640, | 114 | .xres_virtual = 640, |
115 | .yres_virtual = 480, | 115 | .yres_virtual = 480, |
116 | .bits_per_pixel =8, | 116 | .bits_per_pixel = 8, |
117 | .red = {0, 8, 0}, | 117 | .red = {0, 8, 0}, |
118 | .blue = {0, 8, 0}, | 118 | .blue = {0, 8, 0}, |
119 | .green = {0, 8, 0}, | 119 | .green = {0, 8, 0}, |
120 | .activate = FB_ACTIVATE_NOW, | 120 | .activate = FB_ACTIVATE_NOW, |
121 | .height = -1, | 121 | .height = -1, |
122 | .width = -1, | 122 | .width = -1, |
123 | .accel_flags = 0, | 123 | .accel_flags = 0, |
124 | .pixclock = 39721, | 124 | .pixclock = 39721, |
125 | .left_margin = 40, | 125 | .left_margin = 40, |
126 | .right_margin = 24, | 126 | .right_margin = 24, |
127 | .upper_margin = 32, | 127 | .upper_margin = 32, |
128 | .lower_margin = 11, | 128 | .lower_margin = 11, |
129 | .hsync_len = 96, | 129 | .hsync_len = 96, |
130 | .vsync_len = 2, | 130 | .vsync_len = 2, |
131 | .vmode = FB_VMODE_NONINTERLACED | 131 | .vmode = FB_VMODE_NONINTERLACED |
132 | }; | 132 | }; |
133 | 133 | ||
134 | /* | 134 | /* |
@@ -166,7 +166,7 @@ static inline u32 pm2_RDAC_RD(struct pm2fb_par* p, s32 idx) | |||
166 | pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff); | 166 | pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff); |
167 | index = PM2VR_RD_INDEXED_DATA; | 167 | index = PM2VR_RD_INDEXED_DATA; |
168 | break; | 168 | break; |
169 | } | 169 | } |
170 | mb(); | 170 | mb(); |
171 | return pm2_RD(p, index); | 171 | return pm2_RD(p, index); |
172 | } | 172 | } |
@@ -182,7 +182,7 @@ static inline void pm2_RDAC_WR(struct pm2fb_par* p, s32 idx, u32 v) | |||
182 | pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff); | 182 | pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff); |
183 | index = PM2VR_RD_INDEXED_DATA; | 183 | index = PM2VR_RD_INDEXED_DATA; |
184 | break; | 184 | break; |
185 | } | 185 | } |
186 | wmb(); | 186 | wmb(); |
187 | pm2_WR(p, index, v); | 187 | pm2_WR(p, index, v); |
188 | wmb(); | 188 | wmb(); |
@@ -197,7 +197,7 @@ static inline void pm2v_RDAC_WR(struct pm2fb_par* p, s32 idx, u32 v) | |||
197 | } | 197 | } |
198 | 198 | ||
199 | #ifdef CONFIG_FB_PM2_FIFO_DISCONNECT | 199 | #ifdef CONFIG_FB_PM2_FIFO_DISCONNECT |
200 | #define WAIT_FIFO(p,a) | 200 | #define WAIT_FIFO(p, a) |
201 | #else | 201 | #else |
202 | static inline void WAIT_FIFO(struct pm2fb_par* p, u32 a) | 202 | static inline void WAIT_FIFO(struct pm2fb_par* p, u32 a) |
203 | { | 203 | { |
@@ -209,7 +209,7 @@ static inline void WAIT_FIFO(struct pm2fb_par* p, u32 a) | |||
209 | /* | 209 | /* |
210 | * partial products for the supported horizontal resolutions. | 210 | * partial products for the supported horizontal resolutions. |
211 | */ | 211 | */ |
212 | #define PACKPP(p0,p1,p2) (((p2) << 6) | ((p1) << 3) | (p0)) | 212 | #define PACKPP(p0, p1, p2) (((p2) << 6) | ((p1) << 3) | (p0)) |
213 | static const struct { | 213 | static const struct { |
214 | u16 width; | 214 | u16 width; |
215 | u16 pp; | 215 | u16 pp; |
@@ -357,7 +357,7 @@ static void reset_card(struct pm2fb_par* p) | |||
357 | static void reset_config(struct pm2fb_par* p) | 357 | static void reset_config(struct pm2fb_par* p) |
358 | { | 358 | { |
359 | WAIT_FIFO(p, 52); | 359 | WAIT_FIFO(p, 52); |
360 | pm2_WR(p, PM2R_CHIP_CONFIG, pm2_RD(p, PM2R_CHIP_CONFIG)& | 360 | pm2_WR(p, PM2R_CHIP_CONFIG, pm2_RD(p, PM2R_CHIP_CONFIG) & |
361 | ~(PM2F_VGA_ENABLE|PM2F_VGA_FIXED)); | 361 | ~(PM2F_VGA_ENABLE|PM2F_VGA_FIXED)); |
362 | pm2_WR(p, PM2R_BYPASS_WRITE_MASK, ~(0L)); | 362 | pm2_WR(p, PM2R_BYPASS_WRITE_MASK, ~(0L)); |
363 | pm2_WR(p, PM2R_FRAMEBUFFER_WRITE_MASK, ~(0L)); | 363 | pm2_WR(p, PM2R_FRAMEBUFFER_WRITE_MASK, ~(0L)); |
@@ -367,7 +367,7 @@ static void reset_config(struct pm2fb_par* p) | |||
367 | pm2_WR(p, PM2R_RASTERIZER_MODE, 0); | 367 | pm2_WR(p, PM2R_RASTERIZER_MODE, 0); |
368 | pm2_WR(p, PM2R_DELTA_MODE, PM2F_DELTA_ORDER_RGB); | 368 | pm2_WR(p, PM2R_DELTA_MODE, PM2F_DELTA_ORDER_RGB); |
369 | pm2_WR(p, PM2R_LB_READ_FORMAT, 0); | 369 | pm2_WR(p, PM2R_LB_READ_FORMAT, 0); |
370 | pm2_WR(p, PM2R_LB_WRITE_FORMAT, 0); | 370 | pm2_WR(p, PM2R_LB_WRITE_FORMAT, 0); |
371 | pm2_WR(p, PM2R_LB_READ_MODE, 0); | 371 | pm2_WR(p, PM2R_LB_READ_MODE, 0); |
372 | pm2_WR(p, PM2R_LB_SOURCE_OFFSET, 0); | 372 | pm2_WR(p, PM2R_LB_SOURCE_OFFSET, 0); |
373 | pm2_WR(p, PM2R_FB_SOURCE_OFFSET, 0); | 373 | pm2_WR(p, PM2R_FB_SOURCE_OFFSET, 0); |
@@ -535,7 +535,7 @@ static void set_video(struct pm2fb_par* p, u32 video) { | |||
535 | vsync = video; | 535 | vsync = video; |
536 | 536 | ||
537 | DPRINTK("video = 0x%x\n", video); | 537 | DPRINTK("video = 0x%x\n", video); |
538 | 538 | ||
539 | /* | 539 | /* |
540 | * The hardware cursor needs +vsync to recognise vert retrace. | 540 | * The hardware cursor needs +vsync to recognise vert retrace. |
541 | * We may not be using the hardware cursor, but the X Glint | 541 | * We may not be using the hardware cursor, but the X Glint |
@@ -574,9 +574,9 @@ static void set_video(struct pm2fb_par* p, u32 video) { | |||
574 | */ | 574 | */ |
575 | 575 | ||
576 | /** | 576 | /** |
577 | * pm2fb_check_var - Optional function. Validates a var passed in. | 577 | * pm2fb_check_var - Optional function. Validates a var passed in. |
578 | * @var: frame buffer variable screen structure | 578 | * @var: frame buffer variable screen structure |
579 | * @info: frame buffer structure that represents a single frame buffer | 579 | * @info: frame buffer structure that represents a single frame buffer |
580 | * | 580 | * |
581 | * Checks to see if the hardware supports the state requested by | 581 | * Checks to see if the hardware supports the state requested by |
582 | * var passed in. | 582 | * var passed in. |
@@ -615,23 +615,23 @@ static int pm2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | |||
615 | 615 | ||
616 | var->xres = (var->xres + 15) & ~15; /* could sometimes be 8 */ | 616 | var->xres = (var->xres + 15) & ~15; /* could sometimes be 8 */ |
617 | lpitch = var->xres * ((var->bits_per_pixel + 7)>>3); | 617 | lpitch = var->xres * ((var->bits_per_pixel + 7)>>3); |
618 | 618 | ||
619 | if (var->xres < 320 || var->xres > 1600) { | 619 | if (var->xres < 320 || var->xres > 1600) { |
620 | DPRINTK("width not supported: %u\n", var->xres); | 620 | DPRINTK("width not supported: %u\n", var->xres); |
621 | return -EINVAL; | 621 | return -EINVAL; |
622 | } | 622 | } |
623 | 623 | ||
624 | if (var->yres < 200 || var->yres > 1200) { | 624 | if (var->yres < 200 || var->yres > 1200) { |
625 | DPRINTK("height not supported: %u\n", var->yres); | 625 | DPRINTK("height not supported: %u\n", var->yres); |
626 | return -EINVAL; | 626 | return -EINVAL; |
627 | } | 627 | } |
628 | 628 | ||
629 | if (lpitch * var->yres_virtual > info->fix.smem_len) { | 629 | if (lpitch * var->yres_virtual > info->fix.smem_len) { |
630 | DPRINTK("no memory for screen (%ux%ux%u)\n", | 630 | DPRINTK("no memory for screen (%ux%ux%u)\n", |
631 | var->xres, var->yres_virtual, var->bits_per_pixel); | 631 | var->xres, var->yres_virtual, var->bits_per_pixel); |
632 | return -EINVAL; | 632 | return -EINVAL; |
633 | } | 633 | } |
634 | 634 | ||
635 | if (PICOS2KHZ(var->pixclock) > PM2_MAX_PIXCLOCK) { | 635 | if (PICOS2KHZ(var->pixclock) > PM2_MAX_PIXCLOCK) { |
636 | DPRINTK("pixclock too high (%ldKHz)\n", PICOS2KHZ(var->pixclock)); | 636 | DPRINTK("pixclock too high (%ldKHz)\n", PICOS2KHZ(var->pixclock)); |
637 | return -EINVAL; | 637 | return -EINVAL; |
@@ -672,17 +672,17 @@ static int pm2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | |||
672 | break; | 672 | break; |
673 | } | 673 | } |
674 | var->height = var->width = -1; | 674 | var->height = var->width = -1; |
675 | 675 | ||
676 | var->accel_flags = 0; /* Can't mmap if this is on */ | 676 | var->accel_flags = 0; /* Can't mmap if this is on */ |
677 | 677 | ||
678 | DPRINTK("Checking graphics mode at %dx%d depth %d\n", | 678 | DPRINTK("Checking graphics mode at %dx%d depth %d\n", |
679 | var->xres, var->yres, var->bits_per_pixel); | 679 | var->xres, var->yres, var->bits_per_pixel); |
680 | return 0; | 680 | return 0; |
681 | } | 681 | } |
682 | 682 | ||
683 | /** | 683 | /** |
684 | * pm2fb_set_par - Alters the hardware state. | 684 | * pm2fb_set_par - Alters the hardware state. |
685 | * @info: frame buffer structure that represents a single frame buffer | 685 | * @info: frame buffer structure that represents a single frame buffer |
686 | * | 686 | * |
687 | * Using the fb_var_screeninfo in fb_info we set the resolution of the | 687 | * Using the fb_var_screeninfo in fb_info we set the resolution of the |
688 | * this particular framebuffer. | 688 | * this particular framebuffer. |
@@ -709,7 +709,7 @@ static int pm2fb_set_par(struct fb_info *info) | |||
709 | clear_palette(par); | 709 | clear_palette(par); |
710 | if ( par->memclock ) | 710 | if ( par->memclock ) |
711 | set_memclock(par, par->memclock); | 711 | set_memclock(par, par->memclock); |
712 | 712 | ||
713 | width = (info->var.xres_virtual + 7) & ~7; | 713 | width = (info->var.xres_virtual + 7) & ~7; |
714 | height = info->var.yres_virtual; | 714 | height = info->var.yres_virtual; |
715 | depth = (info->var.bits_per_pixel + 7) & ~7; | 715 | depth = (info->var.bits_per_pixel + 7) & ~7; |
@@ -722,7 +722,7 @@ static int pm2fb_set_par(struct fb_info *info) | |||
722 | DPRINTK("pixclock too high (%uKHz)\n", pixclock); | 722 | DPRINTK("pixclock too high (%uKHz)\n", pixclock); |
723 | return -EINVAL; | 723 | return -EINVAL; |
724 | } | 724 | } |
725 | 725 | ||
726 | hsstart = to3264(info->var.right_margin, depth, data64); | 726 | hsstart = to3264(info->var.right_margin, depth, data64); |
727 | hsend = hsstart + to3264(info->var.hsync_len, depth, data64); | 727 | hsend = hsstart + to3264(info->var.hsync_len, depth, data64); |
728 | hbend = hsend + to3264(info->var.left_margin, depth, data64); | 728 | hbend = hsend + to3264(info->var.left_margin, depth, data64); |
@@ -737,7 +737,7 @@ static int pm2fb_set_par(struct fb_info *info) | |||
737 | base = to3264(info->var.yoffset * xres + info->var.xoffset, depth, 1); | 737 | base = to3264(info->var.yoffset * xres + info->var.xoffset, depth, 1); |
738 | if (data64) | 738 | if (data64) |
739 | video |= PM2F_DATA_64_ENABLE; | 739 | video |= PM2F_DATA_64_ENABLE; |
740 | 740 | ||
741 | if (info->var.sync & FB_SYNC_HOR_HIGH_ACT) { | 741 | if (info->var.sync & FB_SYNC_HOR_HIGH_ACT) { |
742 | if (lowhsync) { | 742 | if (lowhsync) { |
743 | DPRINTK("ignoring +hsync, using -hsync.\n"); | 743 | DPRINTK("ignoring +hsync, using -hsync.\n"); |
@@ -778,9 +778,9 @@ static int pm2fb_set_par(struct fb_info *info) | |||
778 | WAIT_FIFO(par, 1); | 778 | WAIT_FIFO(par, 1); |
779 | pm2_WR(par, PM2VR_RD_INDEX_HIGH, 0); | 779 | pm2_WR(par, PM2VR_RD_INDEX_HIGH, 0); |
780 | } | 780 | } |
781 | 781 | ||
782 | set_aperture(par, depth); | 782 | set_aperture(par, depth); |
783 | 783 | ||
784 | mb(); | 784 | mb(); |
785 | WAIT_FIFO(par, 19); | 785 | WAIT_FIFO(par, 19); |
786 | pm2_RDAC_WR(par, PM2I_RD_COLOR_KEY_CONTROL, | 786 | pm2_RDAC_WR(par, PM2I_RD_COLOR_KEY_CONTROL, |
@@ -847,22 +847,22 @@ static int pm2fb_set_par(struct fb_info *info) | |||
847 | set_pixclock(par, pixclock); | 847 | set_pixclock(par, pixclock); |
848 | DPRINTK("Setting graphics mode at %dx%d depth %d\n", | 848 | DPRINTK("Setting graphics mode at %dx%d depth %d\n", |
849 | info->var.xres, info->var.yres, info->var.bits_per_pixel); | 849 | info->var.xres, info->var.yres, info->var.bits_per_pixel); |
850 | return 0; | 850 | return 0; |
851 | } | 851 | } |
852 | 852 | ||
853 | /** | 853 | /** |
854 | * pm2fb_setcolreg - Sets a color register. | 854 | * pm2fb_setcolreg - Sets a color register. |
855 | * @regno: boolean, 0 copy local, 1 get_user() function | 855 | * @regno: boolean, 0 copy local, 1 get_user() function |
856 | * @red: frame buffer colormap structure | 856 | * @red: frame buffer colormap structure |
857 | * @green: The green value which can be up to 16 bits wide | 857 | * @green: The green value which can be up to 16 bits wide |
858 | * @blue: The blue value which can be up to 16 bits wide. | 858 | * @blue: The blue value which can be up to 16 bits wide. |
859 | * @transp: If supported the alpha value which can be up to 16 bits wide. | 859 | * @transp: If supported the alpha value which can be up to 16 bits wide. |
860 | * @info: frame buffer info structure | 860 | * @info: frame buffer info structure |
861 | * | 861 | * |
862 | * Set a single color register. The values supplied have a 16 bit | 862 | * Set a single color register. The values supplied have a 16 bit |
863 | * magnitude which needs to be scaled in this function for the hardware. | 863 | * magnitude which needs to be scaled in this function for the hardware. |
864 | * Pretty much a direct lift from tdfxfb.c. | 864 | * Pretty much a direct lift from tdfxfb.c. |
865 | * | 865 | * |
866 | * Returns negative errno on error, or zero on success. | 866 | * Returns negative errno on error, or zero on success. |
867 | */ | 867 | */ |
868 | static int pm2fb_setcolreg(unsigned regno, unsigned red, unsigned green, | 868 | static int pm2fb_setcolreg(unsigned regno, unsigned red, unsigned green, |
@@ -906,7 +906,7 @@ static int pm2fb_setcolreg(unsigned regno, unsigned red, unsigned green, | |||
906 | * (blue << blue.offset) | (transp << transp.offset) | 906 | * (blue << blue.offset) | (transp << transp.offset) |
907 | * RAMDAC does not exist | 907 | * RAMDAC does not exist |
908 | */ | 908 | */ |
909 | #define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16) | 909 | #define CNVT_TOHW(val, width) ((((val) << (width)) + 0x7FFF -(val)) >> 16) |
910 | switch (info->fix.visual) { | 910 | switch (info->fix.visual) { |
911 | case FB_VISUAL_TRUECOLOR: | 911 | case FB_VISUAL_TRUECOLOR: |
912 | case FB_VISUAL_PSEUDOCOLOR: | 912 | case FB_VISUAL_PSEUDOCOLOR: |
@@ -916,9 +916,9 @@ static int pm2fb_setcolreg(unsigned regno, unsigned red, unsigned green, | |||
916 | transp = CNVT_TOHW(transp, info->var.transp.length); | 916 | transp = CNVT_TOHW(transp, info->var.transp.length); |
917 | break; | 917 | break; |
918 | case FB_VISUAL_DIRECTCOLOR: | 918 | case FB_VISUAL_DIRECTCOLOR: |
919 | /* example here assumes 8 bit DAC. Might be different | 919 | /* example here assumes 8 bit DAC. Might be different |
920 | * for your hardware */ | 920 | * for your hardware */ |
921 | red = CNVT_TOHW(red, 8); | 921 | red = CNVT_TOHW(red, 8); |
922 | green = CNVT_TOHW(green, 8); | 922 | green = CNVT_TOHW(green, 8); |
923 | blue = CNVT_TOHW(blue, 8); | 923 | blue = CNVT_TOHW(blue, 8); |
924 | /* hey, there is bug in transp handling... */ | 924 | /* hey, there is bug in transp handling... */ |
@@ -940,11 +940,11 @@ static int pm2fb_setcolreg(unsigned regno, unsigned red, unsigned green, | |||
940 | 940 | ||
941 | switch (info->var.bits_per_pixel) { | 941 | switch (info->var.bits_per_pixel) { |
942 | case 8: | 942 | case 8: |
943 | break; | 943 | break; |
944 | case 16: | 944 | case 16: |
945 | case 24: | 945 | case 24: |
946 | case 32: | 946 | case 32: |
947 | par->palette[regno] = v; | 947 | par->palette[regno] = v; |
948 | break; | 948 | break; |
949 | } | 949 | } |
950 | return 0; | 950 | return 0; |
@@ -956,15 +956,15 @@ static int pm2fb_setcolreg(unsigned regno, unsigned red, unsigned green, | |||
956 | } | 956 | } |
957 | 957 | ||
958 | /** | 958 | /** |
959 | * pm2fb_pan_display - Pans the display. | 959 | * pm2fb_pan_display - Pans the display. |
960 | * @var: frame buffer variable screen structure | 960 | * @var: frame buffer variable screen structure |
961 | * @info: frame buffer structure that represents a single frame buffer | 961 | * @info: frame buffer structure that represents a single frame buffer |
962 | * | 962 | * |
963 | * Pan (or wrap, depending on the `vmode' field) the display using the | 963 | * Pan (or wrap, depending on the `vmode' field) the display using the |
964 | * `xoffset' and `yoffset' fields of the `var' structure. | 964 | * `xoffset' and `yoffset' fields of the `var' structure. |
965 | * If the values don't fit, return -EINVAL. | 965 | * If the values don't fit, return -EINVAL. |
966 | * | 966 | * |
967 | * Returns negative errno on error, or zero on success. | 967 | * Returns negative errno on error, or zero on success. |
968 | * | 968 | * |
969 | */ | 969 | */ |
970 | static int pm2fb_pan_display(struct fb_var_screeninfo *var, | 970 | static int pm2fb_pan_display(struct fb_var_screeninfo *var, |
@@ -980,24 +980,24 @@ static int pm2fb_pan_display(struct fb_var_screeninfo *var, | |||
980 | depth = (depth > 32) ? 32 : depth; | 980 | depth = (depth > 32) ? 32 : depth; |
981 | base = to3264(var->yoffset * xres + var->xoffset, depth, 1); | 981 | base = to3264(var->yoffset * xres + var->xoffset, depth, 1); |
982 | WAIT_FIFO(p, 1); | 982 | WAIT_FIFO(p, 1); |
983 | pm2_WR(p, PM2R_SCREEN_BASE, base); | 983 | pm2_WR(p, PM2R_SCREEN_BASE, base); |
984 | return 0; | 984 | return 0; |
985 | } | 985 | } |
986 | 986 | ||
987 | /** | 987 | /** |
988 | * pm2fb_blank - Blanks the display. | 988 | * pm2fb_blank - Blanks the display. |
989 | * @blank_mode: the blank mode we want. | 989 | * @blank_mode: the blank mode we want. |
990 | * @info: frame buffer structure that represents a single frame buffer | 990 | * @info: frame buffer structure that represents a single frame buffer |
991 | * | 991 | * |
992 | * Blank the screen if blank_mode != 0, else unblank. Return 0 if | 992 | * Blank the screen if blank_mode != 0, else unblank. Return 0 if |
993 | * blanking succeeded, != 0 if un-/blanking failed due to e.g. a | 993 | * blanking succeeded, != 0 if un-/blanking failed due to e.g. a |
994 | * video mode which doesn't support it. Implements VESA suspend | 994 | * video mode which doesn't support it. Implements VESA suspend |
995 | * and powerdown modes on hardware that supports disabling hsync/vsync: | 995 | * and powerdown modes on hardware that supports disabling hsync/vsync: |
996 | * blank_mode == 2: suspend vsync | 996 | * blank_mode == 2: suspend vsync |
997 | * blank_mode == 3: suspend hsync | 997 | * blank_mode == 3: suspend hsync |
998 | * blank_mode == 4: powerdown | 998 | * blank_mode == 4: powerdown |
999 | * | 999 | * |
1000 | * Returns negative errno on error, or zero on success. | 1000 | * Returns negative errno on error, or zero on success. |
1001 | * | 1001 | * |
1002 | */ | 1002 | */ |
1003 | static int pm2fb_blank(int blank_mode, struct fb_info *info) | 1003 | static int pm2fb_blank(int blank_mode, struct fb_info *info) |
@@ -1071,7 +1071,7 @@ static void pm2fb_block_op(struct fb_info* info, int copy, | |||
1071 | pm2_WR(par, PM2R_RECTANGLE_ORIGIN, (y << 16) | x); | 1071 | pm2_WR(par, PM2R_RECTANGLE_ORIGIN, (y << 16) | x); |
1072 | pm2_WR(par, PM2R_RECTANGLE_SIZE, (h << 16) | w); | 1072 | pm2_WR(par, PM2R_RECTANGLE_SIZE, (h << 16) | w); |
1073 | wmb(); | 1073 | wmb(); |
1074 | pm2_WR(par, PM2R_RENDER,PM2F_RENDER_RECTANGLE | | 1074 | pm2_WR(par, PM2R_RENDER, PM2F_RENDER_RECTANGLE | |
1075 | (x<xsrc ? PM2F_INCREASE_X : 0) | | 1075 | (x<xsrc ? PM2F_INCREASE_X : 0) | |
1076 | (y<ysrc ? PM2F_INCREASE_Y : 0) | | 1076 | (y<ysrc ? PM2F_INCREASE_Y : 0) | |
1077 | (copy ? 0 : PM2F_RENDER_FASTFILL)); | 1077 | (copy ? 0 : PM2F_RENDER_FASTFILL)); |
@@ -1234,7 +1234,7 @@ static int __devinit pm2fb_probe(struct pci_dev *pdev, | |||
1234 | DPRINTK("Adjusting register base for big-endian.\n"); | 1234 | DPRINTK("Adjusting register base for big-endian.\n"); |
1235 | #endif | 1235 | #endif |
1236 | DPRINTK("Register base at 0x%lx\n", pm2fb_fix.mmio_start); | 1236 | DPRINTK("Register base at 0x%lx\n", pm2fb_fix.mmio_start); |
1237 | 1237 | ||
1238 | /* Registers - request region and map it. */ | 1238 | /* Registers - request region and map it. */ |
1239 | if ( !request_mem_region(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len, | 1239 | if ( !request_mem_region(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len, |
1240 | "pm2fb regbase") ) { | 1240 | "pm2fb regbase") ) { |
@@ -1317,17 +1317,17 @@ static int __devinit pm2fb_probe(struct pci_dev *pdev, | |||
1317 | } | 1317 | } |
1318 | 1318 | ||
1319 | info->fbops = &pm2fb_ops; | 1319 | info->fbops = &pm2fb_ops; |
1320 | info->fix = pm2fb_fix; | 1320 | info->fix = pm2fb_fix; |
1321 | info->pseudo_palette = default_par->palette; | 1321 | info->pseudo_palette = default_par->palette; |
1322 | info->flags = FBINFO_DEFAULT | | 1322 | info->flags = FBINFO_DEFAULT | |
1323 | FBINFO_HWACCEL_YPAN | | 1323 | FBINFO_HWACCEL_YPAN | |
1324 | FBINFO_HWACCEL_COPYAREA | | 1324 | FBINFO_HWACCEL_COPYAREA | |
1325 | FBINFO_HWACCEL_FILLRECT; | 1325 | FBINFO_HWACCEL_FILLRECT; |
1326 | 1326 | ||
1327 | if (!mode) | 1327 | if (!mode) |
1328 | mode = "640x480@60"; | 1328 | mode = "640x480@60"; |
1329 | 1329 | ||
1330 | err = fb_find_mode(&info->var, info, mode, NULL, 0, NULL, 8); | 1330 | err = fb_find_mode(&info->var, info, mode, NULL, 0, NULL, 8); |
1331 | if (!err || err == 4) | 1331 | if (!err || err == 4) |
1332 | info->var = pm2fb_var; | 1332 | info->var = pm2fb_var; |
1333 | 1333 | ||
@@ -1348,8 +1348,8 @@ static int __devinit pm2fb_probe(struct pci_dev *pdev, | |||
1348 | return 0; | 1348 | return 0; |
1349 | 1349 | ||
1350 | err_exit_all: | 1350 | err_exit_all: |
1351 | fb_dealloc_cmap(&info->cmap); | 1351 | fb_dealloc_cmap(&info->cmap); |
1352 | err_exit_both: | 1352 | err_exit_both: |
1353 | iounmap(info->screen_base); | 1353 | iounmap(info->screen_base); |
1354 | release_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len); | 1354 | release_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len); |
1355 | err_exit_mmio: | 1355 | err_exit_mmio: |
@@ -1374,7 +1374,7 @@ static void __devexit pm2fb_remove(struct pci_dev *pdev) | |||
1374 | struct pm2fb_par *par = info->par; | 1374 | struct pm2fb_par *par = info->par; |
1375 | 1375 | ||
1376 | unregister_framebuffer(info); | 1376 | unregister_framebuffer(info); |
1377 | 1377 | ||
1378 | iounmap(info->screen_base); | 1378 | iounmap(info->screen_base); |
1379 | release_mem_region(fix->smem_start, fix->smem_len); | 1379 | release_mem_region(fix->smem_start, fix->smem_len); |
1380 | iounmap(par->v_regs); | 1380 | iounmap(par->v_regs); |
@@ -1402,9 +1402,9 @@ static struct pci_device_id pm2fb_id_table[] = { | |||
1402 | 1402 | ||
1403 | static struct pci_driver pm2fb_driver = { | 1403 | static struct pci_driver pm2fb_driver = { |
1404 | .name = "pm2fb", | 1404 | .name = "pm2fb", |
1405 | .id_table = pm2fb_id_table, | 1405 | .id_table = pm2fb_id_table, |
1406 | .probe = pm2fb_probe, | 1406 | .probe = pm2fb_probe, |
1407 | .remove = __devexit_p(pm2fb_remove), | 1407 | .remove = __devexit_p(pm2fb_remove), |
1408 | }; | 1408 | }; |
1409 | 1409 | ||
1410 | MODULE_DEVICE_TABLE(pci, pm2fb_id_table); | 1410 | MODULE_DEVICE_TABLE(pci, pm2fb_id_table); |
@@ -1423,7 +1423,7 @@ static int __init pm2fb_setup(char *options) | |||
1423 | if (!options || !*options) | 1423 | if (!options || !*options) |
1424 | return 0; | 1424 | return 0; |
1425 | 1425 | ||
1426 | while ((this_opt = strsep(&options, ",")) != NULL) { | 1426 | while ((this_opt = strsep(&options, ",")) != NULL) { |
1427 | if (!*this_opt) | 1427 | if (!*this_opt) |
1428 | continue; | 1428 | continue; |
1429 | if(!strcmp(this_opt, "lowhsync")) { | 1429 | if(!strcmp(this_opt, "lowhsync")) { |
diff --git a/drivers/video/pm3fb.c b/drivers/video/pm3fb.c index b52e883f0a52..5b3f54c0918e 100644 --- a/drivers/video/pm3fb.c +++ b/drivers/video/pm3fb.c | |||
@@ -77,7 +77,7 @@ static struct fb_fix_screeninfo pm3fb_fix __devinitdata = { | |||
77 | .xpanstep = 1, | 77 | .xpanstep = 1, |
78 | .ypanstep = 1, | 78 | .ypanstep = 1, |
79 | .ywrapstep = 0, | 79 | .ywrapstep = 0, |
80 | .accel = FB_ACCEL_NONE, | 80 | .accel = FB_ACCEL_3DLABS_PERMEDIA3, |
81 | }; | 81 | }; |
82 | 82 | ||
83 | /* | 83 | /* |
@@ -185,6 +185,238 @@ static inline int pm3fb_shift_bpp(unsigned bpp, int v) | |||
185 | return 0; | 185 | return 0; |
186 | } | 186 | } |
187 | 187 | ||
188 | /* acceleration */ | ||
189 | static int pm3fb_sync(struct fb_info *info) | ||
190 | { | ||
191 | struct pm3_par *par = info->par; | ||
192 | |||
193 | PM3_WAIT(par, 2); | ||
194 | PM3_WRITE_REG(par, PM3FilterMode, PM3FilterModeSync); | ||
195 | PM3_WRITE_REG(par, PM3Sync, 0); | ||
196 | mb(); | ||
197 | do { | ||
198 | while ((PM3_READ_REG(par, PM3OutFIFOWords)) == 0); | ||
199 | rmb(); | ||
200 | } while ((PM3_READ_REG(par, PM3OutputFifo)) != PM3Sync_Tag); | ||
201 | |||
202 | return 0; | ||
203 | } | ||
204 | |||
205 | static void pm3fb_init_engine(struct fb_info *info) | ||
206 | { | ||
207 | struct pm3_par *par = info->par; | ||
208 | const u32 width = (info->var.xres_virtual + 7) & ~7; | ||
209 | |||
210 | PM3_WAIT(par, 50); | ||
211 | PM3_WRITE_REG(par, PM3FilterMode, PM3FilterModeSync); | ||
212 | PM3_WRITE_REG(par, PM3StatisticMode, 0x0); | ||
213 | PM3_WRITE_REG(par, PM3DeltaMode, 0x0); | ||
214 | PM3_WRITE_REG(par, PM3RasterizerMode, 0x0); | ||
215 | PM3_WRITE_REG(par, PM3ScissorMode, 0x0); | ||
216 | PM3_WRITE_REG(par, PM3LineStippleMode, 0x0); | ||
217 | PM3_WRITE_REG(par, PM3AreaStippleMode, 0x0); | ||
218 | PM3_WRITE_REG(par, PM3GIDMode, 0x0); | ||
219 | PM3_WRITE_REG(par, PM3DepthMode, 0x0); | ||
220 | PM3_WRITE_REG(par, PM3StencilMode, 0x0); | ||
221 | PM3_WRITE_REG(par, PM3StencilData, 0x0); | ||
222 | PM3_WRITE_REG(par, PM3ColorDDAMode, 0x0); | ||
223 | PM3_WRITE_REG(par, PM3TextureCoordMode, 0x0); | ||
224 | PM3_WRITE_REG(par, PM3TextureIndexMode0, 0x0); | ||
225 | PM3_WRITE_REG(par, PM3TextureIndexMode1, 0x0); | ||
226 | PM3_WRITE_REG(par, PM3TextureReadMode, 0x0); | ||
227 | PM3_WRITE_REG(par, PM3LUTMode, 0x0); | ||
228 | PM3_WRITE_REG(par, PM3TextureFilterMode, 0x0); | ||
229 | PM3_WRITE_REG(par, PM3TextureCompositeMode, 0x0); | ||
230 | PM3_WRITE_REG(par, PM3TextureApplicationMode, 0x0); | ||
231 | PM3_WRITE_REG(par, PM3TextureCompositeColorMode1, 0x0); | ||
232 | PM3_WRITE_REG(par, PM3TextureCompositeAlphaMode1, 0x0); | ||
233 | PM3_WRITE_REG(par, PM3TextureCompositeColorMode0, 0x0); | ||
234 | PM3_WRITE_REG(par, PM3TextureCompositeAlphaMode0, 0x0); | ||
235 | PM3_WRITE_REG(par, PM3FogMode, 0x0); | ||
236 | PM3_WRITE_REG(par, PM3ChromaTestMode, 0x0); | ||
237 | PM3_WRITE_REG(par, PM3AlphaTestMode, 0x0); | ||
238 | PM3_WRITE_REG(par, PM3AntialiasMode, 0x0); | ||
239 | PM3_WRITE_REG(par, PM3YUVMode, 0x0); | ||
240 | PM3_WRITE_REG(par, PM3AlphaBlendColorMode, 0x0); | ||
241 | PM3_WRITE_REG(par, PM3AlphaBlendAlphaMode, 0x0); | ||
242 | PM3_WRITE_REG(par, PM3DitherMode, 0x0); | ||
243 | PM3_WRITE_REG(par, PM3LogicalOpMode, 0x0); | ||
244 | PM3_WRITE_REG(par, PM3RouterMode, 0x0); | ||
245 | PM3_WRITE_REG(par, PM3Window, 0x0); | ||
246 | |||
247 | PM3_WRITE_REG(par, PM3Config2D, 0x0); | ||
248 | |||
249 | PM3_WRITE_REG(par, PM3SpanColorMask, 0xffffffff); | ||
250 | |||
251 | PM3_WRITE_REG(par, PM3XBias, 0x0); | ||
252 | PM3_WRITE_REG(par, PM3YBias, 0x0); | ||
253 | PM3_WRITE_REG(par, PM3DeltaControl, 0x0); | ||
254 | |||
255 | PM3_WRITE_REG(par, PM3BitMaskPattern, 0xffffffff); | ||
256 | |||
257 | PM3_WRITE_REG(par, PM3FBDestReadEnables, | ||
258 | PM3FBDestReadEnables_E(0xff) | | ||
259 | PM3FBDestReadEnables_R(0xff) | | ||
260 | PM3FBDestReadEnables_ReferenceAlpha(0xff)); | ||
261 | PM3_WRITE_REG(par, PM3FBDestReadBufferAddr0, 0x0); | ||
262 | PM3_WRITE_REG(par, PM3FBDestReadBufferOffset0, 0x0); | ||
263 | PM3_WRITE_REG(par, PM3FBDestReadBufferWidth0, | ||
264 | PM3FBDestReadBufferWidth_Width(width)); | ||
265 | |||
266 | PM3_WRITE_REG(par, PM3FBDestReadMode, | ||
267 | PM3FBDestReadMode_ReadEnable | | ||
268 | PM3FBDestReadMode_Enable0); | ||
269 | PM3_WRITE_REG(par, PM3FBSourceReadBufferAddr, 0x0); | ||
270 | PM3_WRITE_REG(par, PM3FBSourceReadBufferOffset, 0x0); | ||
271 | PM3_WRITE_REG(par, PM3FBSourceReadBufferWidth, | ||
272 | PM3FBSourceReadBufferWidth_Width(width)); | ||
273 | PM3_WRITE_REG(par, PM3FBSourceReadMode, | ||
274 | PM3FBSourceReadMode_Blocking | | ||
275 | PM3FBSourceReadMode_ReadEnable); | ||
276 | |||
277 | PM3_WAIT(par, 2); | ||
278 | { | ||
279 | unsigned long rm = 1; | ||
280 | switch (info->var.bits_per_pixel) { | ||
281 | case 8: | ||
282 | PM3_WRITE_REG(par, PM3PixelSize, | ||
283 | PM3PixelSize_GLOBAL_8BIT); | ||
284 | break; | ||
285 | case 16: | ||
286 | PM3_WRITE_REG(par, PM3PixelSize, | ||
287 | PM3PixelSize_GLOBAL_16BIT); | ||
288 | break; | ||
289 | case 32: | ||
290 | PM3_WRITE_REG(par, PM3PixelSize, | ||
291 | PM3PixelSize_GLOBAL_32BIT); | ||
292 | break; | ||
293 | default: | ||
294 | DPRINTK(1, "Unsupported depth %d\n", | ||
295 | info->var.bits_per_pixel); | ||
296 | break; | ||
297 | } | ||
298 | PM3_WRITE_REG(par, PM3RasterizerMode, rm); | ||
299 | } | ||
300 | |||
301 | PM3_WAIT(par, 20); | ||
302 | PM3_WRITE_REG(par, PM3FBSoftwareWriteMask, 0xffffffff); | ||
303 | PM3_WRITE_REG(par, PM3FBHardwareWriteMask, 0xffffffff); | ||
304 | PM3_WRITE_REG(par, PM3FBWriteMode, | ||
305 | PM3FBWriteMode_WriteEnable | | ||
306 | PM3FBWriteMode_OpaqueSpan | | ||
307 | PM3FBWriteMode_Enable0); | ||
308 | PM3_WRITE_REG(par, PM3FBWriteBufferAddr0, 0x0); | ||
309 | PM3_WRITE_REG(par, PM3FBWriteBufferOffset0, 0x0); | ||
310 | PM3_WRITE_REG(par, PM3FBWriteBufferWidth0, | ||
311 | PM3FBWriteBufferWidth_Width(width)); | ||
312 | |||
313 | PM3_WRITE_REG(par, PM3SizeOfFramebuffer, 0x0); | ||
314 | { | ||
315 | /* size in lines of FB */ | ||
316 | unsigned long sofb = info->screen_size / | ||
317 | info->fix.line_length; | ||
318 | if (sofb > 4095) | ||
319 | PM3_WRITE_REG(par, PM3SizeOfFramebuffer, 4095); | ||
320 | else | ||
321 | PM3_WRITE_REG(par, PM3SizeOfFramebuffer, sofb); | ||
322 | |||
323 | switch (info->var.bits_per_pixel) { | ||
324 | case 8: | ||
325 | PM3_WRITE_REG(par, PM3DitherMode, | ||
326 | (1 << 10) | (2 << 3)); | ||
327 | break; | ||
328 | case 16: | ||
329 | PM3_WRITE_REG(par, PM3DitherMode, | ||
330 | (1 << 10) | (1 << 3)); | ||
331 | break; | ||
332 | case 32: | ||
333 | PM3_WRITE_REG(par, PM3DitherMode, | ||
334 | (1 << 10) | (0 << 3)); | ||
335 | break; | ||
336 | default: | ||
337 | DPRINTK(1, "Unsupported depth %d\n", | ||
338 | info->current_par->depth); | ||
339 | break; | ||
340 | } | ||
341 | } | ||
342 | |||
343 | PM3_WRITE_REG(par, PM3dXDom, 0x0); | ||
344 | PM3_WRITE_REG(par, PM3dXSub, 0x0); | ||
345 | PM3_WRITE_REG(par, PM3dY, (1 << 16)); | ||
346 | PM3_WRITE_REG(par, PM3StartXDom, 0x0); | ||
347 | PM3_WRITE_REG(par, PM3StartXSub, 0x0); | ||
348 | PM3_WRITE_REG(par, PM3StartY, 0x0); | ||
349 | PM3_WRITE_REG(par, PM3Count, 0x0); | ||
350 | |||
351 | /* Disable LocalBuffer. better safe than sorry */ | ||
352 | PM3_WRITE_REG(par, PM3LBDestReadMode, 0x0); | ||
353 | PM3_WRITE_REG(par, PM3LBDestReadEnables, 0x0); | ||
354 | PM3_WRITE_REG(par, PM3LBSourceReadMode, 0x0); | ||
355 | PM3_WRITE_REG(par, PM3LBWriteMode, 0x0); | ||
356 | |||
357 | pm3fb_sync(info); | ||
358 | } | ||
359 | |||
360 | static void pm3fb_fillrect (struct fb_info *info, | ||
361 | const struct fb_fillrect *region) | ||
362 | { | ||
363 | struct pm3_par *par = info->par; | ||
364 | struct fb_fillrect modded; | ||
365 | int vxres, vyres; | ||
366 | u32 color = (info->fix.visual == FB_VISUAL_TRUECOLOR) ? | ||
367 | ((u32*)info->pseudo_palette)[region->color] : region->color; | ||
368 | |||
369 | if (info->state != FBINFO_STATE_RUNNING) | ||
370 | return; | ||
371 | if ((info->flags & FBINFO_HWACCEL_DISABLED) || | ||
372 | region->rop != ROP_COPY ) { | ||
373 | cfb_fillrect(info, region); | ||
374 | return; | ||
375 | } | ||
376 | |||
377 | vxres = info->var.xres_virtual; | ||
378 | vyres = info->var.yres_virtual; | ||
379 | |||
380 | memcpy(&modded, region, sizeof(struct fb_fillrect)); | ||
381 | |||
382 | if(!modded.width || !modded.height || | ||
383 | modded.dx >= vxres || modded.dy >= vyres) | ||
384 | return; | ||
385 | |||
386 | if(modded.dx + modded.width > vxres) | ||
387 | modded.width = vxres - modded.dx; | ||
388 | if(modded.dy + modded.height > vyres) | ||
389 | modded.height = vyres - modded.dy; | ||
390 | |||
391 | if(info->var.bits_per_pixel == 8) | ||
392 | color |= color << 8; | ||
393 | if(info->var.bits_per_pixel <= 16) | ||
394 | color |= color << 16; | ||
395 | |||
396 | PM3_WAIT(par, 4); | ||
397 | |||
398 | PM3_WRITE_REG(par, PM3Config2D, | ||
399 | PM3Config2D_UseConstantSource | | ||
400 | PM3Config2D_ForegroundROPEnable | | ||
401 | (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ | ||
402 | PM3Config2D_FBWriteEnable); | ||
403 | |||
404 | PM3_WRITE_REG(par, PM3ForegroundColor, color); | ||
405 | |||
406 | PM3_WRITE_REG(par, PM3RectanglePosition, | ||
407 | (PM3RectanglePosition_XOffset(modded.dx)) | | ||
408 | (PM3RectanglePosition_YOffset(modded.dy))); | ||
409 | |||
410 | PM3_WRITE_REG(par, PM3Render2D, | ||
411 | PM3Render2D_XPositive | | ||
412 | PM3Render2D_YPositive | | ||
413 | PM3Render2D_Operation_Normal | | ||
414 | PM3Render2D_SpanOperation | | ||
415 | (PM3Render2D_Width(modded.width)) | | ||
416 | (PM3Render2D_Height(modded.height))); | ||
417 | } | ||
418 | /* end of acceleration functions */ | ||
419 | |||
188 | /* write the mode to registers */ | 420 | /* write the mode to registers */ |
189 | static void pm3fb_write_mode(struct fb_info *info) | 421 | static void pm3fb_write_mode(struct fb_info *info) |
190 | { | 422 | { |
@@ -380,8 +612,6 @@ static void pm3fb_write_mode(struct fb_info *info) | |||
380 | /* | 612 | /* |
381 | * hardware independent functions | 613 | * hardware independent functions |
382 | */ | 614 | */ |
383 | int pm3fb_init(void); | ||
384 | |||
385 | static int pm3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | 615 | static int pm3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) |
386 | { | 616 | { |
387 | u32 lpitch; | 617 | u32 lpitch; |
@@ -528,6 +758,7 @@ static int pm3fb_set_par(struct fb_info *info) | |||
528 | pm3fb_clear_colormap(par, 0, 0, 0); | 758 | pm3fb_clear_colormap(par, 0, 0, 0); |
529 | PM3_WRITE_DAC_REG(par, PM3RD_CursorMode, | 759 | PM3_WRITE_DAC_REG(par, PM3RD_CursorMode, |
530 | PM3RD_CursorMode_CURSOR_DISABLE); | 760 | PM3RD_CursorMode_CURSOR_DISABLE); |
761 | pm3fb_init_engine(info); | ||
531 | pm3fb_write_mode(info); | 762 | pm3fb_write_mode(info); |
532 | return 0; | 763 | return 0; |
533 | } | 764 | } |
@@ -675,10 +906,11 @@ static struct fb_ops pm3fb_ops = { | |||
675 | .fb_set_par = pm3fb_set_par, | 906 | .fb_set_par = pm3fb_set_par, |
676 | .fb_setcolreg = pm3fb_setcolreg, | 907 | .fb_setcolreg = pm3fb_setcolreg, |
677 | .fb_pan_display = pm3fb_pan_display, | 908 | .fb_pan_display = pm3fb_pan_display, |
678 | .fb_fillrect = cfb_fillrect, | 909 | .fb_fillrect = pm3fb_fillrect, |
679 | .fb_copyarea = cfb_copyarea, | 910 | .fb_copyarea = cfb_copyarea, |
680 | .fb_imageblit = cfb_imageblit, | 911 | .fb_imageblit = cfb_imageblit, |
681 | .fb_blank = pm3fb_blank, | 912 | .fb_blank = pm3fb_blank, |
913 | .fb_sync = pm3fb_sync, | ||
682 | }; | 914 | }; |
683 | 915 | ||
684 | /* ------------------------------------------------------------------------- */ | 916 | /* ------------------------------------------------------------------------- */ |
@@ -847,7 +1079,8 @@ static int __devinit pm3fb_probe(struct pci_dev *dev, | |||
847 | 1079 | ||
848 | info->fix = pm3fb_fix; | 1080 | info->fix = pm3fb_fix; |
849 | info->pseudo_palette = par->palette; | 1081 | info->pseudo_palette = par->palette; |
850 | info->flags = FBINFO_DEFAULT;/* | FBINFO_HWACCEL_YPAN;*/ | 1082 | info->flags = FBINFO_DEFAULT | |
1083 | FBINFO_HWACCEL_FILLRECT;/* | FBINFO_HWACCEL_YPAN;*/ | ||
851 | 1084 | ||
852 | /* | 1085 | /* |
853 | * This should give a reasonable default video mode. The following is | 1086 | * This should give a reasonable default video mode. The following is |
@@ -935,35 +1168,12 @@ static struct pci_driver pm3fb_driver = { | |||
935 | 1168 | ||
936 | MODULE_DEVICE_TABLE(pci, pm3fb_id_table); | 1169 | MODULE_DEVICE_TABLE(pci, pm3fb_id_table); |
937 | 1170 | ||
938 | #ifndef MODULE | 1171 | static int __init pm3fb_init(void) |
939 | /* | ||
940 | * Setup | ||
941 | */ | ||
942 | |||
943 | /* | ||
944 | * Only necessary if your driver takes special options, | ||
945 | * otherwise we fall back on the generic fb_setup(). | ||
946 | */ | ||
947 | static int __init pm3fb_setup(char *options) | ||
948 | { | 1172 | { |
949 | /* Parse user speficied options (`video=pm3fb:') */ | ||
950 | return 0; | ||
951 | } | ||
952 | #endif /* MODULE */ | ||
953 | |||
954 | int __init pm3fb_init(void) | ||
955 | { | ||
956 | /* | ||
957 | * For kernel boot options (in 'video=pm3fb:<options>' format) | ||
958 | */ | ||
959 | #ifndef MODULE | 1173 | #ifndef MODULE |
960 | char *option = NULL; | 1174 | if (fb_get_options("pm3fb", NULL)) |
961 | |||
962 | if (fb_get_options("pm3fb", &option)) | ||
963 | return -ENODEV; | 1175 | return -ENODEV; |
964 | pm3fb_setup(option); | ||
965 | #endif | 1176 | #endif |
966 | |||
967 | return pci_register_driver(&pm3fb_driver); | 1177 | return pci_register_driver(&pm3fb_driver); |
968 | } | 1178 | } |
969 | 1179 | ||
diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c index 9cf92ba5d6e3..646ec823c168 100644 --- a/drivers/video/ps3fb.c +++ b/drivers/video/ps3fb.c | |||
@@ -27,7 +27,6 @@ | |||
27 | #include <linux/vmalloc.h> | 27 | #include <linux/vmalloc.h> |
28 | #include <linux/delay.h> | 28 | #include <linux/delay.h> |
29 | #include <linux/interrupt.h> | 29 | #include <linux/interrupt.h> |
30 | #include <linux/platform_device.h> | ||
31 | #include <linux/console.h> | 30 | #include <linux/console.h> |
32 | #include <linux/ioctl.h> | 31 | #include <linux/ioctl.h> |
33 | #include <linux/notifier.h> | 32 | #include <linux/notifier.h> |
@@ -46,6 +45,9 @@ | |||
46 | #include <asm/ps3fb.h> | 45 | #include <asm/ps3fb.h> |
47 | #include <asm/ps3.h> | 46 | #include <asm/ps3.h> |
48 | 47 | ||
48 | |||
49 | #define DEVICE_NAME "ps3fb" | ||
50 | |||
49 | #ifdef PS3FB_DEBUG | 51 | #ifdef PS3FB_DEBUG |
50 | #define DPRINTK(fmt, args...) printk("%s: " fmt, __func__ , ##args) | 52 | #define DPRINTK(fmt, args...) printk("%s: " fmt, __func__ , ##args) |
51 | #else | 53 | #else |
@@ -126,7 +128,6 @@ struct gpu_driver_info { | |||
126 | 128 | ||
127 | struct ps3fb_priv { | 129 | struct ps3fb_priv { |
128 | unsigned int irq_no; | 130 | unsigned int irq_no; |
129 | void *dev; | ||
130 | 131 | ||
131 | u64 context_handle, memory_handle; | 132 | u64 context_handle, memory_handle; |
132 | void *xdr_ea; | 133 | void *xdr_ea; |
@@ -171,7 +172,7 @@ static const struct ps3fb_res_table ps3fb_res[] = { | |||
171 | { 0, 0, 0, 0 , 0} }; | 172 | { 0, 0, 0, 0 , 0} }; |
172 | 173 | ||
173 | /* default resolution */ | 174 | /* default resolution */ |
174 | #define GPU_RES_INDEX 0 /* 720 x 480 */ | 175 | #define GPU_RES_INDEX 0 /* 720 x 480 */ |
175 | 176 | ||
176 | static const struct fb_videomode ps3fb_modedb[] = { | 177 | static const struct fb_videomode ps3fb_modedb[] = { |
177 | /* 60 Hz broadcast modes (modes "1" to "5") */ | 178 | /* 60 Hz broadcast modes (modes "1" to "5") */ |
@@ -298,10 +299,9 @@ static const struct fb_videomode ps3fb_modedb[] = { | |||
298 | #define FB_OFF(i) (GPU_OFFSET - VP_OFF(i) % GPU_OFFSET) | 299 | #define FB_OFF(i) (GPU_OFFSET - VP_OFF(i) % GPU_OFFSET) |
299 | 300 | ||
300 | static int ps3fb_mode; | 301 | static int ps3fb_mode; |
301 | module_param(ps3fb_mode, bool, 0); | 302 | module_param(ps3fb_mode, int, 0); |
302 | |||
303 | static char *mode_option __initdata; | ||
304 | 303 | ||
304 | static char *mode_option __devinitdata; | ||
305 | 305 | ||
306 | static int ps3fb_get_res_table(u32 xres, u32 yres) | 306 | static int ps3fb_get_res_table(u32 xres, u32 yres) |
307 | { | 307 | { |
@@ -681,15 +681,15 @@ int ps3fb_wait_for_vsync(u32 crtc) | |||
681 | 681 | ||
682 | EXPORT_SYMBOL_GPL(ps3fb_wait_for_vsync); | 682 | EXPORT_SYMBOL_GPL(ps3fb_wait_for_vsync); |
683 | 683 | ||
684 | void ps3fb_flip_ctl(int on) | 684 | void ps3fb_flip_ctl(int on, void *data) |
685 | { | 685 | { |
686 | struct ps3fb_priv *priv = data; | ||
686 | if (on) | 687 | if (on) |
687 | atomic_dec_if_positive(&ps3fb.ext_flip); | 688 | atomic_dec_if_positive(&priv->ext_flip); |
688 | else | 689 | else |
689 | atomic_inc(&ps3fb.ext_flip); | 690 | atomic_inc(&priv->ext_flip); |
690 | } | 691 | } |
691 | 692 | ||
692 | EXPORT_SYMBOL_GPL(ps3fb_flip_ctl); | ||
693 | 693 | ||
694 | /* | 694 | /* |
695 | * ioctl | 695 | * ioctl |
@@ -812,6 +812,7 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd, | |||
812 | 812 | ||
813 | static int ps3fbd(void *arg) | 813 | static int ps3fbd(void *arg) |
814 | { | 814 | { |
815 | set_freezable(); | ||
815 | while (!kthread_should_stop()) { | 816 | while (!kthread_should_stop()) { |
816 | try_to_freeze(); | 817 | try_to_freeze(); |
817 | set_current_state(TASK_INTERRUPTIBLE); | 818 | set_current_state(TASK_INTERRUPTIBLE); |
@@ -851,37 +852,9 @@ static irqreturn_t ps3fb_vsync_interrupt(int irq, void *ptr) | |||
851 | return IRQ_HANDLED; | 852 | return IRQ_HANDLED; |
852 | } | 853 | } |
853 | 854 | ||
854 | #ifndef MODULE | ||
855 | static int __init ps3fb_setup(char *options) | ||
856 | { | ||
857 | char *this_opt; | ||
858 | int mode = 0; | ||
859 | |||
860 | if (!options || !*options) | ||
861 | return 0; /* no options */ | ||
862 | |||
863 | while ((this_opt = strsep(&options, ",")) != NULL) { | ||
864 | if (!*this_opt) | ||
865 | continue; | ||
866 | if (!strncmp(this_opt, "mode:", 5)) | ||
867 | mode = simple_strtoul(this_opt + 5, NULL, 0); | ||
868 | else | ||
869 | mode_option = this_opt; | ||
870 | } | ||
871 | return mode; | ||
872 | } | ||
873 | #endif /* MODULE */ | ||
874 | |||
875 | /* | ||
876 | * Initialisation | ||
877 | */ | ||
878 | 855 | ||
879 | static void ps3fb_platform_release(struct device *device) | 856 | static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo, |
880 | { | 857 | struct ps3_system_bus_device *dev) |
881 | /* This is called when the reference count goes to zero. */ | ||
882 | } | ||
883 | |||
884 | static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo, void *dev) | ||
885 | { | 858 | { |
886 | int error; | 859 | int error; |
887 | 860 | ||
@@ -897,7 +870,6 @@ static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo, void *dev) | |||
897 | return -EINVAL; | 870 | return -EINVAL; |
898 | } | 871 | } |
899 | 872 | ||
900 | ps3fb.dev = dev; | ||
901 | error = ps3_irq_plug_setup(PS3_BINDING_CPU_ANY, dinfo->irq.irq_outlet, | 873 | error = ps3_irq_plug_setup(PS3_BINDING_CPU_ANY, dinfo->irq.irq_outlet, |
902 | &ps3fb.irq_no); | 874 | &ps3fb.irq_no); |
903 | if (error) { | 875 | if (error) { |
@@ -907,7 +879,7 @@ static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo, void *dev) | |||
907 | } | 879 | } |
908 | 880 | ||
909 | error = request_irq(ps3fb.irq_no, ps3fb_vsync_interrupt, IRQF_DISABLED, | 881 | error = request_irq(ps3fb.irq_no, ps3fb_vsync_interrupt, IRQF_DISABLED, |
910 | "ps3fb vsync", ps3fb.dev); | 882 | DEVICE_NAME, dev); |
911 | if (error) { | 883 | if (error) { |
912 | printk(KERN_ERR "%s: request_irq failed %d\n", __func__, | 884 | printk(KERN_ERR "%s: request_irq failed %d\n", __func__, |
913 | error); | 885 | error); |
@@ -966,16 +938,45 @@ static struct fb_ops ps3fb_ops = { | |||
966 | }; | 938 | }; |
967 | 939 | ||
968 | static struct fb_fix_screeninfo ps3fb_fix __initdata = { | 940 | static struct fb_fix_screeninfo ps3fb_fix __initdata = { |
969 | .id = "PS3 FB", | 941 | .id = DEVICE_NAME, |
970 | .type = FB_TYPE_PACKED_PIXELS, | 942 | .type = FB_TYPE_PACKED_PIXELS, |
971 | .visual = FB_VISUAL_TRUECOLOR, | 943 | .visual = FB_VISUAL_TRUECOLOR, |
972 | .accel = FB_ACCEL_NONE, | 944 | .accel = FB_ACCEL_NONE, |
973 | }; | 945 | }; |
974 | 946 | ||
975 | static int __init ps3fb_probe(struct platform_device *dev) | 947 | static int ps3fb_set_sync(void) |
948 | { | ||
949 | int status; | ||
950 | |||
951 | #ifdef HEAD_A | ||
952 | status = lv1_gpu_context_attribute(0x0, | ||
953 | L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC, | ||
954 | 0, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0); | ||
955 | if (status) { | ||
956 | printk(KERN_ERR "%s: lv1_gpu_context_attribute DISPLAY_SYNC " | ||
957 | "failed: %d\n", __func__, status); | ||
958 | return -1; | ||
959 | } | ||
960 | #endif | ||
961 | #ifdef HEAD_B | ||
962 | status = lv1_gpu_context_attribute(0x0, | ||
963 | L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC, | ||
964 | 1, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0); | ||
965 | |||
966 | if (status) { | ||
967 | printk(KERN_ERR "%s: lv1_gpu_context_attribute DISPLAY_MODE " | ||
968 | "failed: %d\n", __func__, status); | ||
969 | return -1; | ||
970 | } | ||
971 | #endif | ||
972 | return 0; | ||
973 | } | ||
974 | |||
975 | static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) | ||
976 | { | 976 | { |
977 | struct fb_info *info; | 977 | struct fb_info *info; |
978 | int retval = -ENOMEM; | 978 | int retval = -ENOMEM; |
979 | u32 xres, yres; | ||
979 | u64 ddr_lpar = 0; | 980 | u64 ddr_lpar = 0; |
980 | u64 lpar_dma_control = 0; | 981 | u64 lpar_dma_control = 0; |
981 | u64 lpar_driver_info = 0; | 982 | u64 lpar_driver_info = 0; |
@@ -986,6 +987,30 @@ static int __init ps3fb_probe(struct platform_device *dev) | |||
986 | unsigned long offset; | 987 | unsigned long offset; |
987 | struct task_struct *task; | 988 | struct task_struct *task; |
988 | 989 | ||
990 | status = ps3_open_hv_device(dev); | ||
991 | if (status) { | ||
992 | printk(KERN_ERR "%s: ps3_open_hv_device failed\n", __func__); | ||
993 | goto err; | ||
994 | } | ||
995 | |||
996 | if (!ps3fb_mode) | ||
997 | ps3fb_mode = ps3av_get_mode(); | ||
998 | DPRINTK("ps3av_mode:%d\n", ps3fb_mode); | ||
999 | |||
1000 | if (ps3fb_mode > 0 && | ||
1001 | !ps3av_video_mode2res(ps3fb_mode, &xres, &yres)) { | ||
1002 | ps3fb.res_index = ps3fb_get_res_table(xres, yres); | ||
1003 | DPRINTK("res_index:%d\n", ps3fb.res_index); | ||
1004 | } else | ||
1005 | ps3fb.res_index = GPU_RES_INDEX; | ||
1006 | |||
1007 | atomic_set(&ps3fb.f_count, -1); /* fbcon opens ps3fb */ | ||
1008 | atomic_set(&ps3fb.ext_flip, 0); /* for flip with vsync */ | ||
1009 | init_waitqueue_head(&ps3fb.wait_vsync); | ||
1010 | ps3fb.num_frames = 1; | ||
1011 | |||
1012 | ps3fb_set_sync(); | ||
1013 | |||
989 | /* get gpu context handle */ | 1014 | /* get gpu context handle */ |
990 | status = lv1_gpu_memory_allocate(DDR_SIZE, 0, 0, 0, 0, | 1015 | status = lv1_gpu_memory_allocate(DDR_SIZE, 0, 0, 0, 0, |
991 | &ps3fb.memory_handle, &ddr_lpar); | 1016 | &ps3fb.memory_handle, &ddr_lpar); |
@@ -1029,7 +1054,7 @@ static int __init ps3fb_probe(struct platform_device *dev) | |||
1029 | * leakage into userspace | 1054 | * leakage into userspace |
1030 | */ | 1055 | */ |
1031 | memset(ps3fb.xdr_ea, 0, ps3fb_videomemory.size); | 1056 | memset(ps3fb.xdr_ea, 0, ps3fb_videomemory.size); |
1032 | info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev); | 1057 | info = framebuffer_alloc(sizeof(u32) * 16, &dev->core); |
1033 | if (!info) | 1058 | if (!info) |
1034 | goto err_free_irq; | 1059 | goto err_free_irq; |
1035 | 1060 | ||
@@ -1042,7 +1067,7 @@ static int __init ps3fb_probe(struct platform_device *dev) | |||
1042 | info->fix.smem_len = ps3fb_videomemory.size - offset; | 1067 | info->fix.smem_len = ps3fb_videomemory.size - offset; |
1043 | info->pseudo_palette = info->par; | 1068 | info->pseudo_palette = info->par; |
1044 | info->par = NULL; | 1069 | info->par = NULL; |
1045 | info->flags = FBINFO_FLAG_DEFAULT; | 1070 | info->flags = FBINFO_DEFAULT | FBINFO_READS_FAST; |
1046 | 1071 | ||
1047 | retval = fb_alloc_cmap(&info->cmap, 256, 0); | 1072 | retval = fb_alloc_cmap(&info->cmap, 256, 0); |
1048 | if (retval < 0) | 1073 | if (retval < 0) |
@@ -1061,19 +1086,20 @@ static int __init ps3fb_probe(struct platform_device *dev) | |||
1061 | if (retval < 0) | 1086 | if (retval < 0) |
1062 | goto err_fb_dealloc; | 1087 | goto err_fb_dealloc; |
1063 | 1088 | ||
1064 | platform_set_drvdata(dev, info); | 1089 | dev->core.driver_data = info; |
1065 | 1090 | ||
1066 | printk(KERN_INFO | 1091 | printk(KERN_INFO |
1067 | "fb%d: PS3 frame buffer device, using %ld KiB of video memory\n", | 1092 | "fb%d: PS3 frame buffer device, using %ld KiB of video memory\n", |
1068 | info->node, ps3fb_videomemory.size >> 10); | 1093 | info->node, ps3fb_videomemory.size >> 10); |
1069 | 1094 | ||
1070 | task = kthread_run(ps3fbd, info, "ps3fbd"); | 1095 | task = kthread_run(ps3fbd, info, DEVICE_NAME); |
1071 | if (IS_ERR(task)) { | 1096 | if (IS_ERR(task)) { |
1072 | retval = PTR_ERR(task); | 1097 | retval = PTR_ERR(task); |
1073 | goto err_unregister_framebuffer; | 1098 | goto err_unregister_framebuffer; |
1074 | } | 1099 | } |
1075 | 1100 | ||
1076 | ps3fb.task = task; | 1101 | ps3fb.task = task; |
1102 | ps3av_register_flip_ctl(ps3fb_flip_ctl, &ps3fb); | ||
1077 | 1103 | ||
1078 | return 0; | 1104 | return 0; |
1079 | 1105 | ||
@@ -1084,7 +1110,7 @@ err_fb_dealloc: | |||
1084 | err_framebuffer_release: | 1110 | err_framebuffer_release: |
1085 | framebuffer_release(info); | 1111 | framebuffer_release(info); |
1086 | err_free_irq: | 1112 | err_free_irq: |
1087 | free_irq(ps3fb.irq_no, ps3fb.dev); | 1113 | free_irq(ps3fb.irq_no, dev); |
1088 | ps3_irq_plug_destroy(ps3fb.irq_no); | 1114 | ps3_irq_plug_destroy(ps3fb.irq_no); |
1089 | err_iounmap_dinfo: | 1115 | err_iounmap_dinfo: |
1090 | iounmap((u8 __iomem *)ps3fb.dinfo); | 1116 | iounmap((u8 __iomem *)ps3fb.dinfo); |
@@ -1096,26 +1122,30 @@ err: | |||
1096 | return retval; | 1122 | return retval; |
1097 | } | 1123 | } |
1098 | 1124 | ||
1099 | static void ps3fb_shutdown(struct platform_device *dev) | 1125 | static int ps3fb_shutdown(struct ps3_system_bus_device *dev) |
1100 | { | 1126 | { |
1101 | ps3fb_flip_ctl(0); /* flip off */ | 1127 | int status; |
1128 | struct fb_info *info = dev->core.driver_data; | ||
1129 | |||
1130 | DPRINTK(" -> %s:%d\n", __func__, __LINE__); | ||
1131 | |||
1132 | ps3fb_flip_ctl(0, &ps3fb); /* flip off */ | ||
1102 | ps3fb.dinfo->irq.mask = 0; | 1133 | ps3fb.dinfo->irq.mask = 0; |
1103 | free_irq(ps3fb.irq_no, ps3fb.dev); | ||
1104 | ps3_irq_plug_destroy(ps3fb.irq_no); | ||
1105 | iounmap((u8 __iomem *)ps3fb.dinfo); | ||
1106 | } | ||
1107 | 1134 | ||
1108 | void ps3fb_cleanup(void) | 1135 | if (info) { |
1109 | { | 1136 | unregister_framebuffer(info); |
1110 | int status; | 1137 | fb_dealloc_cmap(&info->cmap); |
1138 | framebuffer_release(info); | ||
1139 | } | ||
1111 | 1140 | ||
1141 | ps3av_register_flip_ctl(NULL, NULL); | ||
1112 | if (ps3fb.task) { | 1142 | if (ps3fb.task) { |
1113 | struct task_struct *task = ps3fb.task; | 1143 | struct task_struct *task = ps3fb.task; |
1114 | ps3fb.task = NULL; | 1144 | ps3fb.task = NULL; |
1115 | kthread_stop(task); | 1145 | kthread_stop(task); |
1116 | } | 1146 | } |
1117 | if (ps3fb.irq_no) { | 1147 | if (ps3fb.irq_no) { |
1118 | free_irq(ps3fb.irq_no, ps3fb.dev); | 1148 | free_irq(ps3fb.irq_no, dev); |
1119 | ps3_irq_plug_destroy(ps3fb.irq_no); | 1149 | ps3_irq_plug_destroy(ps3fb.irq_no); |
1120 | } | 1150 | } |
1121 | iounmap((u8 __iomem *)ps3fb.dinfo); | 1151 | iounmap((u8 __iomem *)ps3fb.dinfo); |
@@ -1128,134 +1158,69 @@ void ps3fb_cleanup(void) | |||
1128 | if (status) | 1158 | if (status) |
1129 | DPRINTK("lv1_gpu_memory_free failed: %d\n", status); | 1159 | DPRINTK("lv1_gpu_memory_free failed: %d\n", status); |
1130 | 1160 | ||
1131 | ps3av_dev_close(); | 1161 | ps3_close_hv_device(dev); |
1132 | } | 1162 | DPRINTK(" <- %s:%d\n", __func__, __LINE__); |
1133 | 1163 | ||
1134 | EXPORT_SYMBOL_GPL(ps3fb_cleanup); | ||
1135 | |||
1136 | static int ps3fb_remove(struct platform_device *dev) | ||
1137 | { | ||
1138 | struct fb_info *info = platform_get_drvdata(dev); | ||
1139 | |||
1140 | if (info) { | ||
1141 | unregister_framebuffer(info); | ||
1142 | fb_dealloc_cmap(&info->cmap); | ||
1143 | framebuffer_release(info); | ||
1144 | } | ||
1145 | ps3fb_cleanup(); | ||
1146 | return 0; | 1164 | return 0; |
1147 | } | 1165 | } |
1148 | 1166 | ||
1149 | static struct platform_driver ps3fb_driver = { | 1167 | static struct ps3_system_bus_driver ps3fb_driver = { |
1150 | .probe = ps3fb_probe, | 1168 | .match_id = PS3_MATCH_ID_GRAPHICS, |
1151 | .remove = ps3fb_remove, | 1169 | .core.name = DEVICE_NAME, |
1152 | .shutdown = ps3fb_shutdown, | 1170 | .core.owner = THIS_MODULE, |
1153 | .driver = { .name = "ps3fb" } | 1171 | .probe = ps3fb_probe, |
1154 | }; | 1172 | .remove = ps3fb_shutdown, |
1155 | 1173 | .shutdown = ps3fb_shutdown, | |
1156 | static struct platform_device ps3fb_device = { | ||
1157 | .name = "ps3fb", | ||
1158 | .id = 0, | ||
1159 | .dev = { .release = ps3fb_platform_release } | ||
1160 | }; | 1174 | }; |
1161 | 1175 | ||
1162 | int ps3fb_set_sync(void) | 1176 | static int __init ps3fb_setup(void) |
1163 | { | 1177 | { |
1164 | int status; | 1178 | char *options; |
1165 | 1179 | ||
1166 | #ifdef HEAD_A | 1180 | #ifdef MODULE |
1167 | status = lv1_gpu_context_attribute(0x0, | ||
1168 | L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC, | ||
1169 | 0, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0); | ||
1170 | if (status) { | ||
1171 | printk(KERN_ERR | ||
1172 | "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: %d\n", | ||
1173 | __func__, status); | ||
1174 | return -1; | ||
1175 | } | ||
1176 | #endif | ||
1177 | #ifdef HEAD_B | ||
1178 | status = lv1_gpu_context_attribute(0x0, | ||
1179 | L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC, | ||
1180 | 1, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0); | ||
1181 | |||
1182 | if (status) { | ||
1183 | printk(KERN_ERR | ||
1184 | "%s: lv1_gpu_context_attribute DISPLAY_MODE failed: %d\n", | ||
1185 | __func__, status); | ||
1186 | return -1; | ||
1187 | } | ||
1188 | #endif | ||
1189 | return 0; | 1181 | return 0; |
1190 | } | ||
1191 | |||
1192 | EXPORT_SYMBOL_GPL(ps3fb_set_sync); | ||
1193 | |||
1194 | static int __init ps3fb_init(void) | ||
1195 | { | ||
1196 | int error; | ||
1197 | #ifndef MODULE | ||
1198 | int mode; | ||
1199 | char *option = NULL; | ||
1200 | |||
1201 | if (fb_get_options("ps3fb", &option)) | ||
1202 | goto err; | ||
1203 | #endif | 1182 | #endif |
1204 | 1183 | ||
1205 | if (!ps3fb_videomemory.address) | 1184 | if (fb_get_options(DEVICE_NAME, &options)) |
1206 | goto err; | 1185 | return -ENXIO; |
1207 | |||
1208 | error = ps3av_dev_open(); | ||
1209 | if (error) { | ||
1210 | printk(KERN_ERR "%s: ps3av_dev_open failed\n", __func__); | ||
1211 | goto err; | ||
1212 | } | ||
1213 | 1186 | ||
1214 | ps3fb_mode = ps3av_get_mode(); | 1187 | if (!options || !*options) |
1215 | DPRINTK("ps3av_mode:%d\n", ps3fb_mode); | 1188 | return 0; |
1216 | #ifndef MODULE | ||
1217 | mode = ps3fb_setup(option); /* check boot option */ | ||
1218 | if (mode) | ||
1219 | ps3fb_mode = mode; | ||
1220 | #endif | ||
1221 | if (ps3fb_mode > 0) { | ||
1222 | u32 xres, yres; | ||
1223 | ps3av_video_mode2res(ps3fb_mode, &xres, &yres); | ||
1224 | ps3fb.res_index = ps3fb_get_res_table(xres, yres); | ||
1225 | DPRINTK("res_index:%d\n", ps3fb.res_index); | ||
1226 | } else | ||
1227 | ps3fb.res_index = GPU_RES_INDEX; | ||
1228 | 1189 | ||
1229 | atomic_set(&ps3fb.f_count, -1); /* fbcon opens ps3fb */ | 1190 | while (1) { |
1230 | atomic_set(&ps3fb.ext_flip, 0); /* for flip with vsync */ | 1191 | char *this_opt = strsep(&options, ","); |
1231 | init_waitqueue_head(&ps3fb.wait_vsync); | ||
1232 | ps3fb.num_frames = 1; | ||
1233 | 1192 | ||
1234 | error = platform_driver_register(&ps3fb_driver); | 1193 | if (!this_opt) |
1235 | if (!error) { | 1194 | break; |
1236 | error = platform_device_register(&ps3fb_device); | 1195 | if (!*this_opt) |
1237 | if (error) | 1196 | continue; |
1238 | platform_driver_unregister(&ps3fb_driver); | 1197 | if (!strncmp(this_opt, "mode:", 5)) |
1198 | ps3fb_mode = simple_strtoul(this_opt + 5, NULL, 0); | ||
1199 | else | ||
1200 | mode_option = this_opt; | ||
1239 | } | 1201 | } |
1202 | return 0; | ||
1203 | } | ||
1240 | 1204 | ||
1241 | ps3fb_set_sync(); | 1205 | static int __init ps3fb_init(void) |
1242 | 1206 | { | |
1243 | return error; | 1207 | if (!ps3fb_videomemory.address || ps3fb_setup()) |
1208 | return -ENXIO; | ||
1244 | 1209 | ||
1245 | err: | 1210 | return ps3_system_bus_driver_register(&ps3fb_driver); |
1246 | return -ENXIO; | ||
1247 | } | 1211 | } |
1248 | 1212 | ||
1249 | module_init(ps3fb_init); | ||
1250 | |||
1251 | #ifdef MODULE | ||
1252 | static void __exit ps3fb_exit(void) | 1213 | static void __exit ps3fb_exit(void) |
1253 | { | 1214 | { |
1254 | platform_device_unregister(&ps3fb_device); | 1215 | DPRINTK(" -> %s:%d\n", __func__, __LINE__); |
1255 | platform_driver_unregister(&ps3fb_driver); | 1216 | ps3_system_bus_driver_unregister(&ps3fb_driver); |
1217 | DPRINTK(" <- %s:%d\n", __func__, __LINE__); | ||
1256 | } | 1218 | } |
1257 | 1219 | ||
1220 | module_init(ps3fb_init); | ||
1258 | module_exit(ps3fb_exit); | 1221 | module_exit(ps3fb_exit); |
1259 | 1222 | ||
1260 | MODULE_LICENSE("GPL"); | 1223 | MODULE_LICENSE("GPL"); |
1261 | #endif /* MODULE */ | 1224 | MODULE_DESCRIPTION("PS3 GPU Frame Buffer Driver"); |
1225 | MODULE_AUTHOR("Sony Computer Entertainment Inc."); | ||
1226 | MODULE_ALIAS(PS3_MODULE_ALIAS_GRAPHICS); | ||
diff --git a/drivers/video/pvr2fb.c b/drivers/video/pvr2fb.c index df2909ae704c..f9300266044d 100644 --- a/drivers/video/pvr2fb.c +++ b/drivers/video/pvr2fb.c | |||
@@ -115,11 +115,11 @@ enum { VO_PAL, VO_NTSC, VO_VGA }; | |||
115 | enum { PAL_ARGB1555, PAL_RGB565, PAL_ARGB4444, PAL_ARGB8888 }; | 115 | enum { PAL_ARGB1555, PAL_RGB565, PAL_ARGB4444, PAL_ARGB8888 }; |
116 | 116 | ||
117 | struct pvr2_params { unsigned int val; char *name; }; | 117 | struct pvr2_params { unsigned int val; char *name; }; |
118 | static struct pvr2_params cables[] __initdata = { | 118 | static struct pvr2_params cables[] __devinitdata = { |
119 | { CT_VGA, "VGA" }, { CT_RGB, "RGB" }, { CT_COMPOSITE, "COMPOSITE" }, | 119 | { CT_VGA, "VGA" }, { CT_RGB, "RGB" }, { CT_COMPOSITE, "COMPOSITE" }, |
120 | }; | 120 | }; |
121 | 121 | ||
122 | static struct pvr2_params outputs[] __initdata = { | 122 | static struct pvr2_params outputs[] __devinitdata = { |
123 | { VO_PAL, "PAL" }, { VO_NTSC, "NTSC" }, { VO_VGA, "VGA" }, | 123 | { VO_PAL, "PAL" }, { VO_NTSC, "NTSC" }, { VO_VGA, "VGA" }, |
124 | }; | 124 | }; |
125 | 125 | ||
@@ -147,16 +147,16 @@ static struct pvr2fb_par { | |||
147 | 147 | ||
148 | static struct fb_info *fb_info; | 148 | static struct fb_info *fb_info; |
149 | 149 | ||
150 | static struct fb_fix_screeninfo pvr2_fix __initdata = { | 150 | static struct fb_fix_screeninfo pvr2_fix __devinitdata = { |
151 | .id = "NEC PowerVR2", | 151 | .id = "NEC PowerVR2", |
152 | .type = FB_TYPE_PACKED_PIXELS, | 152 | .type = FB_TYPE_PACKED_PIXELS, |
153 | .visual = FB_VISUAL_TRUECOLOR, | 153 | .visual = FB_VISUAL_TRUECOLOR, |
154 | .ypanstep = 1, | 154 | .ypanstep = 1, |
155 | .ywrapstep = 1, | 155 | .ywrapstep = 1, |
156 | .accel = FB_ACCEL_NONE, | 156 | .accel = FB_ACCEL_NONE, |
157 | }; | 157 | }; |
158 | 158 | ||
159 | static struct fb_var_screeninfo pvr2_var __initdata = { | 159 | static struct fb_var_screeninfo pvr2_var __devinitdata = { |
160 | .xres = 640, | 160 | .xres = 640, |
161 | .yres = 480, | 161 | .yres = 480, |
162 | .xres_virtual = 640, | 162 | .xres_virtual = 640, |
@@ -195,10 +195,6 @@ static unsigned int shdma = PVR2_CASCADE_CHAN; | |||
195 | static unsigned int pvr2dma = ONCHIP_NR_DMA_CHANNELS; | 195 | static unsigned int pvr2dma = ONCHIP_NR_DMA_CHANNELS; |
196 | #endif | 196 | #endif |
197 | 197 | ||
198 | /* Interface used by the world */ | ||
199 | |||
200 | int pvr2fb_setup(char*); | ||
201 | |||
202 | static int pvr2fb_setcolreg(unsigned int regno, unsigned int red, unsigned int green, unsigned int blue, | 198 | static int pvr2fb_setcolreg(unsigned int regno, unsigned int red, unsigned int green, unsigned int blue, |
203 | unsigned int transp, struct fb_info *info); | 199 | unsigned int transp, struct fb_info *info); |
204 | static int pvr2fb_blank(int blank, struct fb_info *info); | 200 | static int pvr2fb_blank(int blank, struct fb_info *info); |
@@ -227,12 +223,12 @@ static struct fb_ops pvr2fb_ops = { | |||
227 | #ifdef CONFIG_SH_DMA | 223 | #ifdef CONFIG_SH_DMA |
228 | .fb_write = pvr2fb_write, | 224 | .fb_write = pvr2fb_write, |
229 | #endif | 225 | #endif |
230 | .fb_fillrect = cfb_fillrect, | 226 | .fb_fillrect = cfb_fillrect, |
231 | .fb_copyarea = cfb_copyarea, | 227 | .fb_copyarea = cfb_copyarea, |
232 | .fb_imageblit = cfb_imageblit, | 228 | .fb_imageblit = cfb_imageblit, |
233 | }; | 229 | }; |
234 | 230 | ||
235 | static struct fb_videomode pvr2_modedb[] __initdata = { | 231 | static struct fb_videomode pvr2_modedb[] __devinitdata = { |
236 | /* | 232 | /* |
237 | * Broadcast video modes (PAL and NTSC). I'm unfamiliar with | 233 | * Broadcast video modes (PAL and NTSC). I'm unfamiliar with |
238 | * PAL-M and PAL-N, but from what I've read both modes parallel PAL and | 234 | * PAL-M and PAL-N, but from what I've read both modes parallel PAL and |
@@ -252,7 +248,7 @@ static struct fb_videomode pvr2_modedb[] __initdata = { | |||
252 | /* 640x480 @ 60hz (VGA) */ | 248 | /* 640x480 @ 60hz (VGA) */ |
253 | "vga_640x480", 60, 640, 480, VGA_CLK, 38, 33, 0, 18, 146, 26, | 249 | "vga_640x480", 60, 640, 480, VGA_CLK, 38, 33, 0, 18, 146, 26, |
254 | 0, FB_VMODE_YWRAP | 250 | 0, FB_VMODE_YWRAP |
255 | }, | 251 | }, |
256 | }; | 252 | }; |
257 | 253 | ||
258 | #define NUM_TOTAL_MODES ARRAY_SIZE(pvr2_modedb) | 254 | #define NUM_TOTAL_MODES ARRAY_SIZE(pvr2_modedb) |
@@ -262,7 +258,7 @@ static struct fb_videomode pvr2_modedb[] __initdata = { | |||
262 | #define DEFMODE_VGA 2 | 258 | #define DEFMODE_VGA 2 |
263 | 259 | ||
264 | static int defmode = DEFMODE_NTSC; | 260 | static int defmode = DEFMODE_NTSC; |
265 | static char *mode_option __initdata = NULL; | 261 | static char *mode_option __devinitdata = NULL; |
266 | 262 | ||
267 | static inline void pvr2fb_set_pal_type(unsigned int type) | 263 | static inline void pvr2fb_set_pal_type(unsigned int type) |
268 | { | 264 | { |
@@ -293,7 +289,7 @@ static void set_color_bitfields(struct fb_var_screeninfo *var) | |||
293 | { | 289 | { |
294 | switch (var->bits_per_pixel) { | 290 | switch (var->bits_per_pixel) { |
295 | case 16: /* RGB 565 */ | 291 | case 16: /* RGB 565 */ |
296 | pvr2fb_set_pal_type(PAL_RGB565); | 292 | pvr2fb_set_pal_type(PAL_RGB565); |
297 | var->red.offset = 11; var->red.length = 5; | 293 | var->red.offset = 11; var->red.length = 5; |
298 | var->green.offset = 5; var->green.length = 6; | 294 | var->green.offset = 5; var->green.length = 6; |
299 | var->blue.offset = 0; var->blue.length = 5; | 295 | var->blue.offset = 0; var->blue.length = 5; |
@@ -306,7 +302,7 @@ static void set_color_bitfields(struct fb_var_screeninfo *var) | |||
306 | var->transp.offset = 0; var->transp.length = 0; | 302 | var->transp.offset = 0; var->transp.length = 0; |
307 | break; | 303 | break; |
308 | case 32: /* ARGB 8888 */ | 304 | case 32: /* ARGB 8888 */ |
309 | pvr2fb_set_pal_type(PAL_ARGB8888); | 305 | pvr2fb_set_pal_type(PAL_ARGB8888); |
310 | var->red.offset = 16; var->red.length = 8; | 306 | var->red.offset = 16; var->red.length = 8; |
311 | var->green.offset = 8; var->green.length = 8; | 307 | var->green.offset = 8; var->green.length = 8; |
312 | var->blue.offset = 0; var->blue.length = 8; | 308 | var->blue.offset = 0; var->blue.length = 8; |
@@ -337,24 +333,25 @@ static int pvr2fb_setcolreg(unsigned int regno, unsigned int red, | |||
337 | ((blue & 0xf800) >> 11); | 333 | ((blue & 0xf800) >> 11); |
338 | 334 | ||
339 | pvr2fb_set_pal_entry(par, regno, tmp); | 335 | pvr2fb_set_pal_entry(par, regno, tmp); |
340 | ((u16*)(info->pseudo_palette))[regno] = tmp; | ||
341 | break; | 336 | break; |
342 | case 24: /* RGB 888 */ | 337 | case 24: /* RGB 888 */ |
343 | red >>= 8; green >>= 8; blue >>= 8; | 338 | red >>= 8; green >>= 8; blue >>= 8; |
344 | ((u32*)(info->pseudo_palette))[regno] = (red << 16) | (green << 8) | blue; | 339 | tmp = (red << 16) | (green << 8) | blue; |
345 | break; | 340 | break; |
346 | case 32: /* ARGB 8888 */ | 341 | case 32: /* ARGB 8888 */ |
347 | red >>= 8; green >>= 8; blue >>= 8; | 342 | red >>= 8; green >>= 8; blue >>= 8; |
348 | tmp = (transp << 24) | (red << 16) | (green << 8) | blue; | 343 | tmp = (transp << 24) | (red << 16) | (green << 8) | blue; |
349 | 344 | ||
350 | pvr2fb_set_pal_entry(par, regno, tmp); | 345 | pvr2fb_set_pal_entry(par, regno, tmp); |
351 | ((u32*)(info->pseudo_palette))[regno] = tmp; | ||
352 | break; | 346 | break; |
353 | default: | 347 | default: |
354 | pr_debug("Invalid bit depth %d?!?\n", info->var.bits_per_pixel); | 348 | pr_debug("Invalid bit depth %d?!?\n", info->var.bits_per_pixel); |
355 | return 1; | 349 | return 1; |
356 | } | 350 | } |
357 | 351 | ||
352 | if (regno < 16) | ||
353 | ((u32*)(info->pseudo_palette))[regno] = tmp; | ||
354 | |||
358 | return 0; | 355 | return 0; |
359 | } | 356 | } |
360 | 357 | ||
@@ -379,13 +376,13 @@ static int pvr2fb_set_par(struct fb_info *info) | |||
379 | var->vmode &= FB_VMODE_MASK; | 376 | var->vmode &= FB_VMODE_MASK; |
380 | if (var->vmode & FB_VMODE_INTERLACED && video_output != VO_VGA) | 377 | if (var->vmode & FB_VMODE_INTERLACED && video_output != VO_VGA) |
381 | par->is_interlaced = 1; | 378 | par->is_interlaced = 1; |
382 | /* | 379 | /* |
383 | * XXX: Need to be more creative with this (i.e. allow doublecan for | 380 | * XXX: Need to be more creative with this (i.e. allow doublecan for |
384 | * PAL/NTSC output). | 381 | * PAL/NTSC output). |
385 | */ | 382 | */ |
386 | if (var->vmode & FB_VMODE_DOUBLE && video_output == VO_VGA) | 383 | if (var->vmode & FB_VMODE_DOUBLE && video_output == VO_VGA) |
387 | par->is_doublescan = 1; | 384 | par->is_doublescan = 1; |
388 | 385 | ||
389 | par->hsync_total = var->left_margin + var->xres + var->right_margin + | 386 | par->hsync_total = var->left_margin + var->xres + var->right_margin + |
390 | var->hsync_len; | 387 | var->hsync_len; |
391 | par->vsync_total = var->upper_margin + var->yres + var->lower_margin + | 388 | par->vsync_total = var->upper_margin + var->yres + var->lower_margin + |
@@ -408,7 +405,7 @@ static int pvr2fb_set_par(struct fb_info *info) | |||
408 | } else { | 405 | } else { |
409 | /* VGA mode */ | 406 | /* VGA mode */ |
410 | /* XXX: What else needs to be checked? */ | 407 | /* XXX: What else needs to be checked? */ |
411 | /* | 408 | /* |
412 | * XXX: We have a little freedom in VGA modes, what ranges | 409 | * XXX: We have a little freedom in VGA modes, what ranges |
413 | * should be here (i.e. hsync/vsync totals, etc.)? | 410 | * should be here (i.e. hsync/vsync totals, etc.)? |
414 | */ | 411 | */ |
@@ -419,8 +416,8 @@ static int pvr2fb_set_par(struct fb_info *info) | |||
419 | /* Calculate the remainding offsets */ | 416 | /* Calculate the remainding offsets */ |
420 | par->diwstart_h = par->borderstart_h + var->left_margin; | 417 | par->diwstart_h = par->borderstart_h + var->left_margin; |
421 | par->diwstart_v = par->borderstart_v + var->upper_margin; | 418 | par->diwstart_v = par->borderstart_v + var->upper_margin; |
422 | par->borderstop_h = par->diwstart_h + var->xres + | 419 | par->borderstop_h = par->diwstart_h + var->xres + |
423 | var->right_margin; | 420 | var->right_margin; |
424 | par->borderstop_v = par->diwstart_v + var->yres + | 421 | par->borderstop_v = par->diwstart_v + var->yres + |
425 | var->lower_margin; | 422 | var->lower_margin; |
426 | 423 | ||
@@ -465,12 +462,12 @@ static int pvr2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | |||
465 | set_color_bitfields(var); | 462 | set_color_bitfields(var); |
466 | 463 | ||
467 | if (var->vmode & FB_VMODE_YWRAP) { | 464 | if (var->vmode & FB_VMODE_YWRAP) { |
468 | if (var->xoffset || var->yoffset < 0 || | 465 | if (var->xoffset || var->yoffset < 0 || |
469 | var->yoffset >= var->yres_virtual) { | 466 | var->yoffset >= var->yres_virtual) { |
470 | var->xoffset = var->yoffset = 0; | 467 | var->xoffset = var->yoffset = 0; |
471 | } else { | 468 | } else { |
472 | if (var->xoffset > var->xres_virtual - var->xres || | 469 | if (var->xoffset > var->xres_virtual - var->xres || |
473 | var->yoffset > var->yres_virtual - var->yres || | 470 | var->yoffset > var->yres_virtual - var->yres || |
474 | var->xoffset < 0 || var->yoffset < 0) | 471 | var->xoffset < 0 || var->yoffset < 0) |
475 | var->xoffset = var->yoffset = 0; | 472 | var->xoffset = var->yoffset = 0; |
476 | } | 473 | } |
@@ -478,7 +475,7 @@ static int pvr2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | |||
478 | var->xoffset = var->yoffset = 0; | 475 | var->xoffset = var->yoffset = 0; |
479 | } | 476 | } |
480 | 477 | ||
481 | /* | 478 | /* |
482 | * XXX: Need to be more creative with this (i.e. allow doublecan for | 479 | * XXX: Need to be more creative with this (i.e. allow doublecan for |
483 | * PAL/NTSC output). | 480 | * PAL/NTSC output). |
484 | */ | 481 | */ |
@@ -507,7 +504,7 @@ static int pvr2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | |||
507 | var->vsync_len = par->borderstop_v + | 504 | var->vsync_len = par->borderstop_v + |
508 | (par->vsync_total - par->borderstop_v); | 505 | (par->vsync_total - par->borderstop_v); |
509 | } | 506 | } |
510 | 507 | ||
511 | hsync_total = var->left_margin + var->xres + var->right_margin + | 508 | hsync_total = var->left_margin + var->xres + var->right_margin + |
512 | var->hsync_len; | 509 | var->hsync_len; |
513 | vtotal = var->upper_margin + var->yres + var->lower_margin + | 510 | vtotal = var->upper_margin + var->yres + var->lower_margin + |
@@ -531,7 +528,7 @@ static int pvr2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | |||
531 | } | 528 | } |
532 | } | 529 | } |
533 | } | 530 | } |
534 | 531 | ||
535 | /* Check memory sizes */ | 532 | /* Check memory sizes */ |
536 | line_length = get_line_length(var->xres_virtual, var->bits_per_pixel); | 533 | line_length = get_line_length(var->xres_virtual, var->bits_per_pixel); |
537 | if (line_length * var->yres_virtual > info->fix.smem_len) | 534 | if (line_length * var->yres_virtual > info->fix.smem_len) |
@@ -552,7 +549,7 @@ static void pvr2_update_display(struct fb_info *info) | |||
552 | DISP_DIWADDRS); | 549 | DISP_DIWADDRS); |
553 | } | 550 | } |
554 | 551 | ||
555 | /* | 552 | /* |
556 | * Initialize the video mode. Currently, the 16bpp and 24bpp modes aren't | 553 | * Initialize the video mode. Currently, the 16bpp and 24bpp modes aren't |
557 | * very stable. It's probably due to the fact that a lot of the 2D video | 554 | * very stable. It's probably due to the fact that a lot of the 2D video |
558 | * registers are still undocumented. | 555 | * registers are still undocumented. |
@@ -592,18 +589,18 @@ static void pvr2_init_display(struct fb_info *info) | |||
592 | /* display window start position */ | 589 | /* display window start position */ |
593 | fb_writel(par->diwstart_h, DISP_DIWHSTRT); | 590 | fb_writel(par->diwstart_h, DISP_DIWHSTRT); |
594 | fb_writel((par->diwstart_v << 16) | par->diwstart_v, DISP_DIWVSTRT); | 591 | fb_writel((par->diwstart_v << 16) | par->diwstart_v, DISP_DIWVSTRT); |
595 | 592 | ||
596 | /* misc. settings */ | 593 | /* misc. settings */ |
597 | fb_writel((0x16 << 16) | par->is_lowres, DISP_DIWCONF); | 594 | fb_writel((0x16 << 16) | par->is_lowres, DISP_DIWCONF); |
598 | 595 | ||
599 | /* clock doubler (for VGA), scan doubler, display enable */ | 596 | /* clock doubler (for VGA), scan doubler, display enable */ |
600 | fb_writel(((video_output == VO_VGA) << 23) | | 597 | fb_writel(((video_output == VO_VGA) << 23) | |
601 | (par->is_doublescan << 1) | 1, DISP_DIWMODE); | 598 | (par->is_doublescan << 1) | 1, DISP_DIWMODE); |
602 | 599 | ||
603 | /* bits per pixel */ | 600 | /* bits per pixel */ |
604 | fb_writel(fb_readl(DISP_DIWMODE) | (--bytesperpixel << 2), DISP_DIWMODE); | 601 | fb_writel(fb_readl(DISP_DIWMODE) | (--bytesperpixel << 2), DISP_DIWMODE); |
605 | 602 | ||
606 | /* video enable, color sync, interlace, | 603 | /* video enable, color sync, interlace, |
607 | * hsync and vsync polarity (currently unused) */ | 604 | * hsync and vsync polarity (currently unused) */ |
608 | fb_writel(0x100 | ((par->is_interlaced /*|4*/) << 4), DISP_SYNCCONF); | 605 | fb_writel(0x100 | ((par->is_interlaced /*|4*/) << 4), DISP_SYNCCONF); |
609 | } | 606 | } |
@@ -657,7 +654,7 @@ static irqreturn_t pvr2fb_interrupt(int irq, void *dev_id) | |||
657 | static int pvr2_init_cable(void) | 654 | static int pvr2_init_cable(void) |
658 | { | 655 | { |
659 | if (cable_type < 0) { | 656 | if (cable_type < 0) { |
660 | fb_writel((fb_readl(PCTRA) & 0xfff0ffff) | 0x000a0000, | 657 | fb_writel((fb_readl(PCTRA) & 0xfff0ffff) | 0x000a0000, |
661 | PCTRA); | 658 | PCTRA); |
662 | cable_type = (fb_readw(PDTRA) >> 8) & 3; | 659 | cable_type = (fb_readw(PDTRA) >> 8) & 3; |
663 | } | 660 | } |
@@ -687,7 +684,7 @@ static ssize_t pvr2fb_write(struct fb_info *info, const char *buf, | |||
687 | pages = kmalloc(nr_pages * sizeof(struct page *), GFP_KERNEL); | 684 | pages = kmalloc(nr_pages * sizeof(struct page *), GFP_KERNEL); |
688 | if (!pages) | 685 | if (!pages) |
689 | return -ENOMEM; | 686 | return -ENOMEM; |
690 | 687 | ||
691 | down_read(¤t->mm->mmap_sem); | 688 | down_read(¤t->mm->mmap_sem); |
692 | ret = get_user_pages(current, current->mm, (unsigned long)buf, | 689 | ret = get_user_pages(current, current->mm, (unsigned long)buf, |
693 | nr_pages, WRITE, 0, pages, NULL); | 690 | nr_pages, WRITE, 0, pages, NULL); |
@@ -700,7 +697,7 @@ static ssize_t pvr2fb_write(struct fb_info *info, const char *buf, | |||
700 | } | 697 | } |
701 | 698 | ||
702 | dma_configure_channel(shdma, 0x12c1); | 699 | dma_configure_channel(shdma, 0x12c1); |
703 | 700 | ||
704 | dst = (unsigned long)fb_info->screen_base + *ppos; | 701 | dst = (unsigned long)fb_info->screen_base + *ppos; |
705 | start = (unsigned long)page_address(pages[0]); | 702 | start = (unsigned long)page_address(pages[0]); |
706 | end = (unsigned long)page_address(pages[nr_pages]); | 703 | end = (unsigned long)page_address(pages[nr_pages]); |
@@ -744,7 +741,7 @@ out_unmap: | |||
744 | kfree(pages); | 741 | kfree(pages); |
745 | 742 | ||
746 | return ret; | 743 | return ret; |
747 | } | 744 | } |
748 | #endif /* CONFIG_SH_DMA */ | 745 | #endif /* CONFIG_SH_DMA */ |
749 | 746 | ||
750 | /** | 747 | /** |
@@ -765,21 +762,21 @@ out_unmap: | |||
765 | * in for flexibility anyways. Who knows, maybe someone has tv-out on a | 762 | * in for flexibility anyways. Who knows, maybe someone has tv-out on a |
766 | * PCI-based version of these things ;-) | 763 | * PCI-based version of these things ;-) |
767 | */ | 764 | */ |
768 | static int __init pvr2fb_common_init(void) | 765 | static int __devinit pvr2fb_common_init(void) |
769 | { | 766 | { |
770 | struct pvr2fb_par *par = currentpar; | 767 | struct pvr2fb_par *par = currentpar; |
771 | unsigned long modememused, rev; | 768 | unsigned long modememused, rev; |
772 | 769 | ||
773 | fb_info->screen_base = ioremap_nocache(pvr2_fix.smem_start, | 770 | fb_info->screen_base = ioremap_nocache(pvr2_fix.smem_start, |
774 | pvr2_fix.smem_len); | 771 | pvr2_fix.smem_len); |
775 | 772 | ||
776 | if (!fb_info->screen_base) { | 773 | if (!fb_info->screen_base) { |
777 | printk(KERN_ERR "pvr2fb: Failed to remap smem space\n"); | 774 | printk(KERN_ERR "pvr2fb: Failed to remap smem space\n"); |
778 | goto out_err; | 775 | goto out_err; |
779 | } | 776 | } |
780 | 777 | ||
781 | par->mmio_base = (unsigned long)ioremap_nocache(pvr2_fix.mmio_start, | 778 | par->mmio_base = (unsigned long)ioremap_nocache(pvr2_fix.mmio_start, |
782 | pvr2_fix.mmio_len); | 779 | pvr2_fix.mmio_len); |
783 | if (!par->mmio_base) { | 780 | if (!par->mmio_base) { |
784 | printk(KERN_ERR "pvr2fb: Failed to remap mmio space\n"); | 781 | printk(KERN_ERR "pvr2fb: Failed to remap mmio space\n"); |
785 | goto out_err; | 782 | goto out_err; |
@@ -820,7 +817,7 @@ static int __init pvr2fb_common_init(void) | |||
820 | printk("fb%d: %s (rev %ld.%ld) frame buffer device, using %ldk/%ldk of video memory\n", | 817 | printk("fb%d: %s (rev %ld.%ld) frame buffer device, using %ldk/%ldk of video memory\n", |
821 | fb_info->node, fb_info->fix.id, (rev >> 4) & 0x0f, rev & 0x0f, | 818 | fb_info->node, fb_info->fix.id, (rev >> 4) & 0x0f, rev & 0x0f, |
822 | modememused >> 10, (unsigned long)(fb_info->fix.smem_len >> 10)); | 819 | modememused >> 10, (unsigned long)(fb_info->fix.smem_len >> 10)); |
823 | printk("fb%d: Mode %dx%d-%d pitch = %ld cable: %s video output: %s\n", | 820 | printk("fb%d: Mode %dx%d-%d pitch = %ld cable: %s video output: %s\n", |
824 | fb_info->node, fb_info->var.xres, fb_info->var.yres, | 821 | fb_info->node, fb_info->var.xres, fb_info->var.yres, |
825 | fb_info->var.bits_per_pixel, | 822 | fb_info->var.bits_per_pixel, |
826 | get_line_length(fb_info->var.xres, fb_info->var.bits_per_pixel), | 823 | get_line_length(fb_info->var.xres, fb_info->var.bits_per_pixel), |
@@ -878,8 +875,8 @@ static int __init pvr2fb_dc_init(void) | |||
878 | video_output = VO_NTSC; | 875 | video_output = VO_NTSC; |
879 | } | 876 | } |
880 | } | 877 | } |
881 | 878 | ||
882 | /* | 879 | /* |
883 | * Nothing exciting about the DC PVR2 .. only a measly 8MiB. | 880 | * Nothing exciting about the DC PVR2 .. only a measly 8MiB. |
884 | */ | 881 | */ |
885 | pvr2_fix.smem_start = 0xa5000000; /* RAM starts here */ | 882 | pvr2_fix.smem_start = 0xa5000000; /* RAM starts here */ |
@@ -903,7 +900,7 @@ static int __init pvr2fb_dc_init(void) | |||
903 | return pvr2fb_common_init(); | 900 | return pvr2fb_common_init(); |
904 | } | 901 | } |
905 | 902 | ||
906 | static void pvr2fb_dc_exit(void) | 903 | static void __exit pvr2fb_dc_exit(void) |
907 | { | 904 | { |
908 | if (fb_info->screen_base) { | 905 | if (fb_info->screen_base) { |
909 | iounmap(fb_info->screen_base); | 906 | iounmap(fb_info->screen_base); |
@@ -987,13 +984,13 @@ static int __init pvr2fb_pci_init(void) | |||
987 | return pci_register_driver(&pvr2fb_pci_driver); | 984 | return pci_register_driver(&pvr2fb_pci_driver); |
988 | } | 985 | } |
989 | 986 | ||
990 | static void pvr2fb_pci_exit(void) | 987 | static void __exit pvr2fb_pci_exit(void) |
991 | { | 988 | { |
992 | pci_unregister_driver(&pvr2fb_pci_driver); | 989 | pci_unregister_driver(&pvr2fb_pci_driver); |
993 | } | 990 | } |
994 | #endif /* CONFIG_PCI */ | 991 | #endif /* CONFIG_PCI */ |
995 | 992 | ||
996 | static int __init pvr2_get_param(const struct pvr2_params *p, const char *s, | 993 | static int __devinit pvr2_get_param(const struct pvr2_params *p, const char *s, |
997 | int val, int size) | 994 | int val, int size) |
998 | { | 995 | { |
999 | int i; | 996 | int i; |
@@ -1021,7 +1018,7 @@ static int __init pvr2_get_param(const struct pvr2_params *p, const char *s, | |||
1021 | */ | 1018 | */ |
1022 | 1019 | ||
1023 | #ifndef MODULE | 1020 | #ifndef MODULE |
1024 | int __init pvr2fb_setup(char *options) | 1021 | static int __init pvr2fb_setup(char *options) |
1025 | { | 1022 | { |
1026 | char *this_opt; | 1023 | char *this_opt; |
1027 | char cable_arg[80]; | 1024 | char cable_arg[80]; |
@@ -1061,7 +1058,7 @@ static struct pvr2_board { | |||
1061 | int (*init)(void); | 1058 | int (*init)(void); |
1062 | void (*exit)(void); | 1059 | void (*exit)(void); |
1063 | char name[16]; | 1060 | char name[16]; |
1064 | } board_list[] = { | 1061 | } board_driver[] = { |
1065 | #ifdef CONFIG_SH_DREAMCAST | 1062 | #ifdef CONFIG_SH_DREAMCAST |
1066 | { pvr2fb_dc_init, pvr2fb_dc_exit, "Sega DC PVR2" }, | 1063 | { pvr2fb_dc_init, pvr2fb_dc_exit, "Sega DC PVR2" }, |
1067 | #endif | 1064 | #endif |
@@ -1071,7 +1068,7 @@ static struct pvr2_board { | |||
1071 | { 0, }, | 1068 | { 0, }, |
1072 | }; | 1069 | }; |
1073 | 1070 | ||
1074 | int __init pvr2fb_init(void) | 1071 | static int __init pvr2fb_init(void) |
1075 | { | 1072 | { |
1076 | int i, ret = -ENODEV; | 1073 | int i, ret = -ENODEV; |
1077 | int size; | 1074 | int size; |
@@ -1085,18 +1082,17 @@ int __init pvr2fb_init(void) | |||
1085 | #endif | 1082 | #endif |
1086 | size = sizeof(struct fb_info) + sizeof(struct pvr2fb_par) + 16 * sizeof(u32); | 1083 | size = sizeof(struct fb_info) + sizeof(struct pvr2fb_par) + 16 * sizeof(u32); |
1087 | 1084 | ||
1088 | fb_info = kmalloc(size, GFP_KERNEL); | 1085 | fb_info = kzalloc(size, GFP_KERNEL); |
1089 | if (!fb_info) { | 1086 | if (!fb_info) { |
1090 | printk(KERN_ERR "Failed to allocate memory for fb_info\n"); | 1087 | printk(KERN_ERR "Failed to allocate memory for fb_info\n"); |
1091 | return -ENOMEM; | 1088 | return -ENOMEM; |
1092 | } | 1089 | } |
1093 | 1090 | ||
1094 | memset(fb_info, 0, size); | ||
1095 | 1091 | ||
1096 | currentpar = (struct pvr2fb_par *)(fb_info + 1); | 1092 | currentpar = (struct pvr2fb_par *)(fb_info + 1); |
1097 | 1093 | ||
1098 | for (i = 0; i < ARRAY_SIZE(board_list); i++) { | 1094 | for (i = 0; i < ARRAY_SIZE(board_driver); i++) { |
1099 | struct pvr2_board *pvr_board = board_list + i; | 1095 | struct pvr2_board *pvr_board = board_driver + i; |
1100 | 1096 | ||
1101 | if (!pvr_board->init) | 1097 | if (!pvr_board->init) |
1102 | continue; | 1098 | continue; |
@@ -1118,13 +1114,13 @@ static void __exit pvr2fb_exit(void) | |||
1118 | { | 1114 | { |
1119 | int i; | 1115 | int i; |
1120 | 1116 | ||
1121 | for (i = 0; i < ARRAY_SIZE(board_list); i++) { | 1117 | for (i = 0; i < ARRAY_SIZE(board_driver); i++) { |
1122 | struct pvr2_board *pvr_board = board_list + i; | 1118 | struct pvr2_board *pvr_board = board_driver + i; |
1123 | 1119 | ||
1124 | if (pvr_board->exit) | 1120 | if (pvr_board->exit) |
1125 | pvr_board->exit(); | 1121 | pvr_board->exit(); |
1126 | } | 1122 | } |
1127 | 1123 | ||
1128 | #ifdef CONFIG_SH_STORE_QUEUES | 1124 | #ifdef CONFIG_SH_STORE_QUEUES |
1129 | sq_unmap(pvr2fb_map); | 1125 | sq_unmap(pvr2fb_map); |
1130 | #endif | 1126 | #endif |
@@ -1139,4 +1135,3 @@ module_exit(pvr2fb_exit); | |||
1139 | MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>, M. R. Brown <mrbrown@0xd6.org>"); | 1135 | MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>, M. R. Brown <mrbrown@0xd6.org>"); |
1140 | MODULE_DESCRIPTION("Framebuffer driver for NEC PowerVR 2 based graphics boards"); | 1136 | MODULE_DESCRIPTION("Framebuffer driver for NEC PowerVR 2 based graphics boards"); |
1141 | MODULE_LICENSE("GPL"); | 1137 | MODULE_LICENSE("GPL"); |
1142 | |||
diff --git a/drivers/video/q40fb.c b/drivers/video/q40fb.c index 48536c3e58a4..4beac1df617b 100644 --- a/drivers/video/q40fb.c +++ b/drivers/video/q40fb.c | |||
@@ -95,7 +95,7 @@ static int __init q40fb_probe(struct platform_device *dev) | |||
95 | /* mapped in q40/config.c */ | 95 | /* mapped in q40/config.c */ |
96 | q40fb_fix.smem_start = Q40_PHYS_SCREEN_ADDR; | 96 | q40fb_fix.smem_start = Q40_PHYS_SCREEN_ADDR; |
97 | 97 | ||
98 | info = framebuffer_alloc(sizeof(u32) * 256, &dev->dev); | 98 | info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev); |
99 | if (!info) | 99 | if (!info) |
100 | return -ENOMEM; | 100 | return -ENOMEM; |
101 | 101 | ||
diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c index d251174d8baa..5c47968e7f21 100644 --- a/drivers/video/riva/fbdev.c +++ b/drivers/video/riva/fbdev.c | |||
@@ -2146,7 +2146,7 @@ static void __devexit rivafb_remove(struct pci_dev *pd) | |||
2146 | * ------------------------------------------------------------------------- */ | 2146 | * ------------------------------------------------------------------------- */ |
2147 | 2147 | ||
2148 | #ifndef MODULE | 2148 | #ifndef MODULE |
2149 | static int __init rivafb_setup(char *options) | 2149 | static int __devinit rivafb_setup(char *options) |
2150 | { | 2150 | { |
2151 | char *this_opt; | 2151 | char *this_opt; |
2152 | 2152 | ||
diff --git a/drivers/video/riva/riva_hw.c b/drivers/video/riva/riva_hw.c index 70bfd78eca81..13307703a9f0 100644 --- a/drivers/video/riva/riva_hw.c +++ b/drivers/video/riva/riva_hw.c | |||
@@ -1223,6 +1223,8 @@ static int CalcVClock | |||
1223 | } | 1223 | } |
1224 | } | 1224 | } |
1225 | } | 1225 | } |
1226 | |||
1227 | /* non-zero: M/N/P/clock values assigned. zero: error (not set) */ | ||
1226 | return (DeltaOld != 0xFFFFFFFF); | 1228 | return (DeltaOld != 0xFFFFFFFF); |
1227 | } | 1229 | } |
1228 | /* | 1230 | /* |
@@ -1240,7 +1242,10 @@ int CalcStateExt | |||
1240 | int dotClock | 1242 | int dotClock |
1241 | ) | 1243 | ) |
1242 | { | 1244 | { |
1243 | int pixelDepth, VClk, m, n, p; | 1245 | int pixelDepth; |
1246 | int uninitialized_var(VClk),uninitialized_var(m), | ||
1247 | uninitialized_var(n), uninitialized_var(p); | ||
1248 | |||
1244 | /* | 1249 | /* |
1245 | * Save mode parameters. | 1250 | * Save mode parameters. |
1246 | */ | 1251 | */ |
diff --git a/drivers/video/savage/savagefb_driver.c b/drivers/video/savage/savagefb_driver.c index 3d7507ad55f6..b855f4a34afe 100644 --- a/drivers/video/savage/savagefb_driver.c +++ b/drivers/video/savage/savagefb_driver.c | |||
@@ -2174,11 +2174,10 @@ static int __devinit savage_init_fb_info(struct fb_info *info, | |||
2174 | 2174 | ||
2175 | #if defined(CONFIG_FB_SAVAGE_ACCEL) | 2175 | #if defined(CONFIG_FB_SAVAGE_ACCEL) |
2176 | /* FIFO size + padding for commands */ | 2176 | /* FIFO size + padding for commands */ |
2177 | info->pixmap.addr = kmalloc(8*1024, GFP_KERNEL); | 2177 | info->pixmap.addr = kcalloc(8, 1024, GFP_KERNEL); |
2178 | 2178 | ||
2179 | err = -ENOMEM; | 2179 | err = -ENOMEM; |
2180 | if (info->pixmap.addr) { | 2180 | if (info->pixmap.addr) { |
2181 | memset(info->pixmap.addr, 0, 8*1024); | ||
2182 | info->pixmap.size = 8*1024; | 2181 | info->pixmap.size = 8*1024; |
2183 | info->pixmap.scan_align = 4; | 2182 | info->pixmap.scan_align = 4; |
2184 | info->pixmap.buf_align = 4; | 2183 | info->pixmap.buf_align = 4; |
diff --git a/drivers/video/sgivwfb.c b/drivers/video/sgivwfb.c index ebb6756aea08..4fb16240c04d 100644 --- a/drivers/video/sgivwfb.c +++ b/drivers/video/sgivwfb.c | |||
@@ -752,7 +752,7 @@ static int __init sgivwfb_probe(struct platform_device *dev) | |||
752 | struct fb_info *info; | 752 | struct fb_info *info; |
753 | char *monitor; | 753 | char *monitor; |
754 | 754 | ||
755 | info = framebuffer_alloc(sizeof(struct sgivw_par) + sizeof(u32) * 256, &dev->dev); | 755 | info = framebuffer_alloc(sizeof(struct sgivw_par) + sizeof(u32) * 16, &dev->dev); |
756 | if (!info) | 756 | if (!info) |
757 | return -ENOMEM; | 757 | return -ENOMEM; |
758 | par = info->par; | 758 | par = info->par; |
diff --git a/drivers/video/sis/sis.h b/drivers/video/sis/sis.h index d5e2d9c27847..d53bf6945f0c 100644 --- a/drivers/video/sis/sis.h +++ b/drivers/video/sis/sis.h | |||
@@ -479,7 +479,7 @@ struct sis_video_info { | |||
479 | struct fb_var_screeninfo default_var; | 479 | struct fb_var_screeninfo default_var; |
480 | 480 | ||
481 | struct fb_fix_screeninfo sisfb_fix; | 481 | struct fb_fix_screeninfo sisfb_fix; |
482 | u32 pseudo_palette[17]; | 482 | u32 pseudo_palette[16]; |
483 | 483 | ||
484 | struct sisfb_monitor { | 484 | struct sisfb_monitor { |
485 | u16 hmin; | 485 | u16 hmin; |
diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c index 93d07ef85276..e8ccace01252 100644 --- a/drivers/video/sis/sis_main.c +++ b/drivers/video/sis/sis_main.c | |||
@@ -1405,12 +1405,18 @@ sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, | |||
1405 | } | 1405 | } |
1406 | break; | 1406 | break; |
1407 | case 16: | 1407 | case 16: |
1408 | if (regno >= 16) | ||
1409 | break; | ||
1410 | |||
1408 | ((u32 *)(info->pseudo_palette))[regno] = | 1411 | ((u32 *)(info->pseudo_palette))[regno] = |
1409 | (red & 0xf800) | | 1412 | (red & 0xf800) | |
1410 | ((green & 0xfc00) >> 5) | | 1413 | ((green & 0xfc00) >> 5) | |
1411 | ((blue & 0xf800) >> 11); | 1414 | ((blue & 0xf800) >> 11); |
1412 | break; | 1415 | break; |
1413 | case 32: | 1416 | case 32: |
1417 | if (regno >= 16) | ||
1418 | break; | ||
1419 | |||
1414 | red >>= 8; | 1420 | red >>= 8; |
1415 | green >>= 8; | 1421 | green >>= 8; |
1416 | blue >>= 8; | 1422 | blue >>= 8; |
diff --git a/drivers/video/tgafb.c b/drivers/video/tgafb.c index 5c0dab628099..89facb73edfc 100644 --- a/drivers/video/tgafb.c +++ b/drivers/video/tgafb.c | |||
@@ -1634,7 +1634,7 @@ tgafb_register(struct device *dev) | |||
1634 | FBINFO_HWACCEL_IMAGEBLIT | FBINFO_HWACCEL_FILLRECT; | 1634 | FBINFO_HWACCEL_IMAGEBLIT | FBINFO_HWACCEL_FILLRECT; |
1635 | info->fbops = &tgafb_ops; | 1635 | info->fbops = &tgafb_ops; |
1636 | info->screen_base = par->tga_fb_base; | 1636 | info->screen_base = par->tga_fb_base; |
1637 | info->pseudo_palette = (void *)(par + 1); | 1637 | info->pseudo_palette = par->palette; |
1638 | 1638 | ||
1639 | /* This should give a reasonable default video mode. */ | 1639 | /* This should give a reasonable default video mode. */ |
1640 | if (tga_bus_pci) { | 1640 | if (tga_bus_pci) { |
diff --git a/drivers/video/tridentfb.c b/drivers/video/tridentfb.c index 55e8aa450bfa..c699864b6f4a 100644 --- a/drivers/video/tridentfb.c +++ b/drivers/video/tridentfb.c | |||
@@ -976,7 +976,7 @@ static int tridentfb_setcolreg(unsigned regno, unsigned red, unsigned green, | |||
976 | return 1; | 976 | return 1; |
977 | 977 | ||
978 | 978 | ||
979 | if (bpp==8) { | 979 | if (bpp == 8) { |
980 | t_outb(0xFF,0x3C6); | 980 | t_outb(0xFF,0x3C6); |
981 | t_outb(regno,0x3C8); | 981 | t_outb(regno,0x3C8); |
982 | 982 | ||
@@ -984,19 +984,21 @@ static int tridentfb_setcolreg(unsigned regno, unsigned red, unsigned green, | |||
984 | t_outb(green>>10,0x3C9); | 984 | t_outb(green>>10,0x3C9); |
985 | t_outb(blue>>10,0x3C9); | 985 | t_outb(blue>>10,0x3C9); |
986 | 986 | ||
987 | } else if (bpp == 16) { /* RGB 565 */ | 987 | } else if (regno < 16) { |
988 | u32 col; | 988 | if (bpp == 16) { /* RGB 565 */ |
989 | 989 | u32 col; | |
990 | col = (red & 0xF800) | ((green & 0xFC00) >> 5) | | 990 | |
991 | ((blue & 0xF800) >> 11); | 991 | col = (red & 0xF800) | ((green & 0xFC00) >> 5) | |
992 | col |= col << 16; | 992 | ((blue & 0xF800) >> 11); |
993 | ((u32 *)(info->pseudo_palette))[regno] = col; | 993 | col |= col << 16; |
994 | } else if (bpp == 32) /* ARGB 8888 */ | 994 | ((u32 *)(info->pseudo_palette))[regno] = col; |
995 | ((u32*)info->pseudo_palette)[regno] = | 995 | } else if (bpp == 32) /* ARGB 8888 */ |
996 | ((transp & 0xFF00) <<16) | | 996 | ((u32*)info->pseudo_palette)[regno] = |
997 | ((red & 0xFF00) << 8) | | 997 | ((transp & 0xFF00) <<16) | |
998 | ((green & 0xFF00)) | | 998 | ((red & 0xFF00) << 8) | |
999 | ((blue & 0xFF00)>>8); | 999 | ((green & 0xFF00)) | |
1000 | ((blue & 0xFF00)>>8); | ||
1001 | } | ||
1000 | 1002 | ||
1001 | // debug("exit\n"); | 1003 | // debug("exit\n"); |
1002 | return 0; | 1004 | return 0; |
diff --git a/drivers/video/tx3912fb.c b/drivers/video/tx3912fb.c index 07389ba01eff..e6f7c78da68b 100644 --- a/drivers/video/tx3912fb.c +++ b/drivers/video/tx3912fb.c | |||
@@ -291,7 +291,7 @@ int __init tx3912fb_init(void) | |||
291 | fb_info.fbops = &tx3912fb_ops; | 291 | fb_info.fbops = &tx3912fb_ops; |
292 | fb_info.var = tx3912fb_var; | 292 | fb_info.var = tx3912fb_var; |
293 | fb_info.fix = tx3912fb_fix; | 293 | fb_info.fix = tx3912fb_fix; |
294 | fb_info.pseudo_palette = pseudo_palette; | 294 | fb_info.pseudo_palette = cfb8; |
295 | fb_info.flags = FBINFO_DEFAULT; | 295 | fb_info.flags = FBINFO_DEFAULT; |
296 | 296 | ||
297 | /* Clear the framebuffer */ | 297 | /* Clear the framebuffer */ |
diff --git a/drivers/video/valkyriefb.c b/drivers/video/valkyriefb.c index ad66f070acb8..7b0cef9ca8f9 100644 --- a/drivers/video/valkyriefb.c +++ b/drivers/video/valkyriefb.c | |||
@@ -356,10 +356,9 @@ int __init valkyriefb_init(void) | |||
356 | } | 356 | } |
357 | #endif /* ppc (!CONFIG_MAC) */ | 357 | #endif /* ppc (!CONFIG_MAC) */ |
358 | 358 | ||
359 | p = kmalloc(sizeof(*p), GFP_ATOMIC); | 359 | p = kzalloc(sizeof(*p), GFP_ATOMIC); |
360 | if (p == 0) | 360 | if (p == 0) |
361 | return -ENOMEM; | 361 | return -ENOMEM; |
362 | memset(p, 0, sizeof(*p)); | ||
363 | 362 | ||
364 | /* Map in frame buffer and registers */ | 363 | /* Map in frame buffer and registers */ |
365 | if (!request_mem_region(frame_buffer_phys, 0x100000, "valkyriefb")) { | 364 | if (!request_mem_region(frame_buffer_phys, 0x100000, "valkyriefb")) { |
diff --git a/drivers/video/vt8623fb.c b/drivers/video/vt8623fb.c index 30c0b948852b..4c3a63308df1 100644 --- a/drivers/video/vt8623fb.c +++ b/drivers/video/vt8623fb.c | |||
@@ -68,26 +68,26 @@ static const struct svga_pll vt8623_pll = {2, 127, 2, 7, 0, 3, | |||
68 | 68 | ||
69 | /* CRT timing register sets */ | 69 | /* CRT timing register sets */ |
70 | 70 | ||
71 | struct vga_regset vt8623_h_total_regs[] = {{0x00, 0, 7}, {0x36, 3, 3}, VGA_REGSET_END}; | 71 | static struct vga_regset vt8623_h_total_regs[] = {{0x00, 0, 7}, {0x36, 3, 3}, VGA_REGSET_END}; |
72 | struct vga_regset vt8623_h_display_regs[] = {{0x01, 0, 7}, VGA_REGSET_END}; | 72 | static struct vga_regset vt8623_h_display_regs[] = {{0x01, 0, 7}, VGA_REGSET_END}; |
73 | struct vga_regset vt8623_h_blank_start_regs[] = {{0x02, 0, 7}, VGA_REGSET_END}; | 73 | static struct vga_regset vt8623_h_blank_start_regs[] = {{0x02, 0, 7}, VGA_REGSET_END}; |
74 | struct vga_regset vt8623_h_blank_end_regs[] = {{0x03, 0, 4}, {0x05, 7, 7}, {0x33, 5, 5}, VGA_REGSET_END}; | 74 | static struct vga_regset vt8623_h_blank_end_regs[] = {{0x03, 0, 4}, {0x05, 7, 7}, {0x33, 5, 5}, VGA_REGSET_END}; |
75 | struct vga_regset vt8623_h_sync_start_regs[] = {{0x04, 0, 7}, {0x33, 4, 4}, VGA_REGSET_END}; | 75 | static struct vga_regset vt8623_h_sync_start_regs[] = {{0x04, 0, 7}, {0x33, 4, 4}, VGA_REGSET_END}; |
76 | struct vga_regset vt8623_h_sync_end_regs[] = {{0x05, 0, 4}, VGA_REGSET_END}; | 76 | static struct vga_regset vt8623_h_sync_end_regs[] = {{0x05, 0, 4}, VGA_REGSET_END}; |
77 | 77 | ||
78 | struct vga_regset vt8623_v_total_regs[] = {{0x06, 0, 7}, {0x07, 0, 0}, {0x07, 5, 5}, {0x35, 0, 0}, VGA_REGSET_END}; | 78 | static struct vga_regset vt8623_v_total_regs[] = {{0x06, 0, 7}, {0x07, 0, 0}, {0x07, 5, 5}, {0x35, 0, 0}, VGA_REGSET_END}; |
79 | struct vga_regset vt8623_v_display_regs[] = {{0x12, 0, 7}, {0x07, 1, 1}, {0x07, 6, 6}, {0x35, 2, 2}, VGA_REGSET_END}; | 79 | static struct vga_regset vt8623_v_display_regs[] = {{0x12, 0, 7}, {0x07, 1, 1}, {0x07, 6, 6}, {0x35, 2, 2}, VGA_REGSET_END}; |
80 | struct vga_regset vt8623_v_blank_start_regs[] = {{0x15, 0, 7}, {0x07, 3, 3}, {0x09, 5, 5}, {0x35, 3, 3}, VGA_REGSET_END}; | 80 | static struct vga_regset vt8623_v_blank_start_regs[] = {{0x15, 0, 7}, {0x07, 3, 3}, {0x09, 5, 5}, {0x35, 3, 3}, VGA_REGSET_END}; |
81 | struct vga_regset vt8623_v_blank_end_regs[] = {{0x16, 0, 7}, VGA_REGSET_END}; | 81 | static struct vga_regset vt8623_v_blank_end_regs[] = {{0x16, 0, 7}, VGA_REGSET_END}; |
82 | struct vga_regset vt8623_v_sync_start_regs[] = {{0x10, 0, 7}, {0x07, 2, 2}, {0x07, 7, 7}, {0x35, 1, 1}, VGA_REGSET_END}; | 82 | static struct vga_regset vt8623_v_sync_start_regs[] = {{0x10, 0, 7}, {0x07, 2, 2}, {0x07, 7, 7}, {0x35, 1, 1}, VGA_REGSET_END}; |
83 | struct vga_regset vt8623_v_sync_end_regs[] = {{0x11, 0, 3}, VGA_REGSET_END}; | 83 | static struct vga_regset vt8623_v_sync_end_regs[] = {{0x11, 0, 3}, VGA_REGSET_END}; |
84 | 84 | ||
85 | struct vga_regset vt8623_offset_regs[] = {{0x13, 0, 7}, {0x35, 5, 7}, VGA_REGSET_END}; | 85 | static struct vga_regset vt8623_offset_regs[] = {{0x13, 0, 7}, {0x35, 5, 7}, VGA_REGSET_END}; |
86 | struct vga_regset vt8623_line_compare_regs[] = {{0x18, 0, 7}, {0x07, 4, 4}, {0x09, 6, 6}, {0x33, 0, 2}, {0x35, 4, 4}, VGA_REGSET_END}; | 86 | static struct vga_regset vt8623_line_compare_regs[] = {{0x18, 0, 7}, {0x07, 4, 4}, {0x09, 6, 6}, {0x33, 0, 2}, {0x35, 4, 4}, VGA_REGSET_END}; |
87 | struct vga_regset vt8623_fetch_count_regs[] = {{0x1C, 0, 7}, {0x1D, 0, 1}, VGA_REGSET_END}; | 87 | static struct vga_regset vt8623_fetch_count_regs[] = {{0x1C, 0, 7}, {0x1D, 0, 1}, VGA_REGSET_END}; |
88 | struct vga_regset vt8623_start_address_regs[] = {{0x0d, 0, 7}, {0x0c, 0, 7}, {0x34, 0, 7}, {0x48, 0, 1}, VGA_REGSET_END}; | 88 | static struct vga_regset vt8623_start_address_regs[] = {{0x0d, 0, 7}, {0x0c, 0, 7}, {0x34, 0, 7}, {0x48, 0, 1}, VGA_REGSET_END}; |
89 | 89 | ||
90 | struct svga_timing_regs vt8623_timing_regs = { | 90 | static struct svga_timing_regs vt8623_timing_regs = { |
91 | vt8623_h_total_regs, vt8623_h_display_regs, vt8623_h_blank_start_regs, | 91 | vt8623_h_total_regs, vt8623_h_display_regs, vt8623_h_blank_start_regs, |
92 | vt8623_h_blank_end_regs, vt8623_h_sync_start_regs, vt8623_h_sync_end_regs, | 92 | vt8623_h_blank_end_regs, vt8623_h_sync_start_regs, vt8623_h_sync_end_regs, |
93 | vt8623_v_total_regs, vt8623_v_display_regs, vt8623_v_blank_start_regs, | 93 | vt8623_v_total_regs, vt8623_v_display_regs, vt8623_v_blank_start_regs, |
@@ -903,7 +903,7 @@ static void __exit vt8623fb_cleanup(void) | |||
903 | 903 | ||
904 | /* Driver Initialisation */ | 904 | /* Driver Initialisation */ |
905 | 905 | ||
906 | int __init vt8623fb_init(void) | 906 | static int __init vt8623fb_init(void) |
907 | { | 907 | { |
908 | 908 | ||
909 | #ifndef MODULE | 909 | #ifndef MODULE |