aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/68328fb.c2
-rw-r--r--drivers/video/Kconfig30
-rw-r--r--drivers/video/Makefile4
-rw-r--r--drivers/video/amba-clcd.c3
-rw-r--r--drivers/video/atmel_lcdfb.c67
-rw-r--r--drivers/video/aty/ati_ids.h1
-rw-r--r--drivers/video/aty/atyfb_base.c9
-rw-r--r--drivers/video/aty/radeon_base.c2
-rw-r--r--drivers/video/aty/radeonfb.h2
-rw-r--r--drivers/video/au1200fb.c3
-rw-r--r--drivers/video/backlight/cr_bllcd.c2
-rw-r--r--drivers/video/clps711xfb.c3
-rw-r--r--drivers/video/console/Kconfig16
-rw-r--r--drivers/video/console/fbcon.c366
-rw-r--r--drivers/video/console/vgacon.c6
-rw-r--r--drivers/video/controlfb.c2
-rw-r--r--drivers/video/cyber2000fb.c3
-rw-r--r--drivers/video/cyblafb.c21
-rw-r--r--drivers/video/epson1355fb.c21
-rw-r--r--drivers/video/fbmem.c299
-rw-r--r--drivers/video/fm2fb.c16
-rw-r--r--drivers/video/gbefb.c41
-rw-r--r--drivers/video/i810/i810.h2
-rw-r--r--drivers/video/igafb.c4
-rw-r--r--drivers/video/intelfb/intelfb.h2
-rw-r--r--drivers/video/logo/Kconfig5
-rw-r--r--drivers/video/logo/Makefile2
-rw-r--r--drivers/video/logo/logo.c7
-rw-r--r--drivers/video/logo/logo_spe_clut224.ppm283
-rw-r--r--drivers/video/macfb.c93
-rw-r--r--drivers/video/macmodes.c5
-rw-r--r--drivers/video/macmodes.h8
-rw-r--r--drivers/video/matrox/matroxfb_accel.c11
-rw-r--r--drivers/video/matrox/matroxfb_base.c4
-rw-r--r--drivers/video/matrox/matroxfb_base.h2
-rw-r--r--drivers/video/matrox/matroxfb_crtc2.c6
-rw-r--r--drivers/video/matrox/matroxfb_crtc2.h2
-rw-r--r--drivers/video/matrox/matroxfb_maven.c9
-rw-r--r--drivers/video/nvidia/nv_hw.c62
-rw-r--r--drivers/video/nvidia/nv_setup.c12
-rw-r--r--drivers/video/nvidia/nv_type.h1
-rw-r--r--drivers/video/nvidia/nvidia.c9
-rw-r--r--drivers/video/offb.c2
-rw-r--r--drivers/video/omap/Kconfig58
-rw-r--r--drivers/video/omap/Makefile29
-rw-r--r--drivers/video/omap/blizzard.c1568
-rw-r--r--drivers/video/omap/dispc.c1502
-rw-r--r--drivers/video/omap/dispc.h43
-rw-r--r--drivers/video/omap/hwa742.c1077
-rw-r--r--drivers/video/omap/lcd_h3.c141
-rw-r--r--drivers/video/omap/lcd_h4.c117
-rw-r--r--drivers/video/omap/lcd_inn1510.c124
-rw-r--r--drivers/video/omap/lcd_inn1610.c150
-rw-r--r--drivers/video/omap/lcd_osk.c144
-rw-r--r--drivers/video/omap/lcd_palmte.c123
-rw-r--r--drivers/video/omap/lcd_palmtt.c127
-rw-r--r--drivers/video/omap/lcd_palmz71.c123
-rw-r--r--drivers/video/omap/lcd_sx1.c334
-rw-r--r--drivers/video/omap/lcdc.c893
-rw-r--r--drivers/video/omap/lcdc.h7
-rw-r--r--drivers/video/omap/omapfb_main.c1941
-rw-r--r--drivers/video/omap/rfbi.c588
-rw-r--r--drivers/video/omap/sossi.c686
-rw-r--r--drivers/video/platinumfb.c2
-rw-r--r--drivers/video/pm2fb.c202
-rw-r--r--drivers/video/pm3fb.c270
-rw-r--r--drivers/video/ps3fb.c293
-rw-r--r--drivers/video/pvr2fb.c111
-rw-r--r--drivers/video/q40fb.c2
-rw-r--r--drivers/video/riva/fbdev.c2
-rw-r--r--drivers/video/riva/riva_hw.c7
-rw-r--r--drivers/video/savage/savagefb_driver.c3
-rw-r--r--drivers/video/sgivwfb.c2
-rw-r--r--drivers/video/sis/sis.h2
-rw-r--r--drivers/video/sis/sis_main.c6
-rw-r--r--drivers/video/tgafb.c2
-rw-r--r--drivers/video/tridentfb.c30
-rw-r--r--drivers/video/tx3912fb.c2
-rw-r--r--drivers/video/valkyriefb.c3
-rw-r--r--drivers/video/vt8623fb.c42
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;
60static u_long videomemorysize; 60static u_long videomemorysize;
61 61
62static struct fb_info fb_info; 62static struct fb_info fb_info;
63static u32 mc68x328fb_pseudo_palette[17]; 63static u32 mc68x328fb_pseudo_palette[16];
64 64
65static struct fb_var_screeninfo mc68x328fb_default __initdata = { 65static 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
15config 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
15config FB 22config 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
813config FB_EPSON1355 820config 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
859config 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
852config FB_NVIDIA 869config 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
1792config FB_PS3 1809config 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
1802config FB_PS3_DEFAULT_SIZE_M 1820config 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
1841if ARCH_OMAP
1842 source "drivers/video/omap/Kconfig"
1843endif
1844
1823config FB_VIRTUAL 1845config 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
113obj-$(CONFIG_FB_PS3) += ps3fb.o 113obj-$(CONFIG_FB_PS3) += ps3fb.o
114obj-$(CONFIG_FB_SM501) += sm501fb.o 114obj-$(CONFIG_FB_SM501) += sm501fb.o
115obj-$(CONFIG_FB_XILINX) += xilinxfb.o 115obj-$(CONFIG_FB_XILINX) += xilinxfb.o
116obj-$(CONFIG_FB_OMAP) += omap/
116 117
117# Platform or fallback drivers go here 118# Platform or fallback drivers go here
118obj-$(CONFIG_FB_VESA) += vesafb.o 119obj-$(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
124obj-$(CONFIG_FB_VIRTUAL) += vfb.o 125obj-$(CONFIG_FB_VIRTUAL) += vfb.o
126
127#video output switch sysfs driver
128obj-$(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
82static 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
83static void atmel_lcdfb_update_dma(struct fb_info *info, 106static 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,
228static int atmel_lcdfb_set_par(struct fb_info *info) 255static 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
544static u32 pseudo_palette[17]; 544static u32 pseudo_palette[16];
545 545
546#ifdef CONFIG_FB_ATY_GX 546#ifdef CONFIG_FB_ATY_GX
547static char *aty_gx_ram[8] __devinitdata = { 547static 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
121config 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
121config FRAMEBUFFER_CONSOLE_ROTATION 137config 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;
125static int last_fb_vc = MAX_NR_CONSOLES - 1; 126static int last_fb_vc = MAX_NR_CONSOLES - 1;
126static int fbcon_is_default = 1; 127static int fbcon_is_default = 1;
127static int fbcon_has_exited; 128static int fbcon_has_exited;
129static int primary_device = -1;
130static int map_override;
128 131
129/* font data */ 132/* font data */
130static char fontname[40]; 133static 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
154static int vbl_cursor_cnt; 157static int vbl_cursor_cnt;
158static 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);
188static void fbcon_bmove_rec(struct vc_data *vc, struct display *p, int sy, int sx, 192static 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);
190static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, 194static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
191 struct vc_data *vc); 195 int unit);
192static void fbcon_preset_disp(struct fb_info *info, struct fb_var_screeninfo *var,
193 int unit);
194static void fbcon_redraw_move(struct vc_data *vc, struct display *p, 196static 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);
196static void fbcon_modechanged(struct fb_info *info); 198static void fbcon_modechanged(struct fb_info *info);
197static void fbcon_set_all_vcs(struct fb_info *info); 199static void fbcon_set_all_vcs(struct fb_info *info);
198static void fbcon_start(void); 200static void fbcon_start(void);
199static void fbcon_exit(void); 201static void fbcon_exit(void);
200static struct class_device *fbcon_class_device; 202static 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;
1368static int scrollback_max = 0; 1381static int scrollback_max = 0;
1369static int scrollback_current = 0; 1382static int scrollback_current = 0;
1370 1383
1371/*
1372 * If no vc is existent yet, just set struct display
1373 */
1374static 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
1389static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, 1384static 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
1713static 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
1707static void fbcon_redraw(struct vc_data *vc, struct display *p, 1763static 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
2940static int fbcon_fb_unregistered(int idx) 3006#ifdef CONFIG_VT_HW_CONSOLE_BINDING
3007static 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
3016static inline int fbcon_unbind(void)
3017{
3018 return -EINVAL;
3019}
3020#endif /* CONFIG_VT_HW_CONSOLE_BINDING */
3021
3022static 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
3045static 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
2973static int fbcon_fb_registered(int idx) 3082#ifdef CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY
3083static 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
3106static inline void fbcon_select_primary(struct fb_info *info)
3107{
3108 return;
3109}
3110#endif /* CONFIG_FRAMEBUFFER_DETECT_PRIMARY */
3111
3112static 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
3182static ssize_t store_rotate(struct class_device *class_device, 3320static 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
3206static ssize_t store_rotate_all(struct class_device *class_device, 3345static 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
3230static ssize_t show_rotate(struct class_device *class_device, char *buf) 3370static 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
3251static struct class_device_attribute class_device_attrs[] = { 3392static 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;
3415err:
3416 release_console_sem();
3417 return snprintf(buf, PAGE_SIZE, "%d\n", blink);
3418}
3419
3420static 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
3452err:
3453 release_console_sem();
3454 return count;
3455}
3456
3457static 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
3256static int fbcon_init_class_device(void) 3464static 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
3382static void __exit fbcon_deinit_class_device(void) 3587static 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
190static 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 */
194static 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
94struct fb_info_control { 94struct 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
64struct epson1355_par { 64struct 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
72static inline u8 epson1355_read_reg(int index)
73{
74 return ctrl_inb(par.reg_addr + index);
75}
76
77static 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
407static 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
479static struct logo_data_extra {
480 const struct linux_logo *logo;
481 unsigned int n;
482} fb_logo_ex[FB_LOGO_EX_NUM_MAX];
483static unsigned int fb_logo_ex_num;
484
485void 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
495static 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
515static 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
528static inline int fb_prepare_extra_logos(struct fb_info *info,
529 unsigned int height,
530 unsigned int yres)
531{
532 return height;
533}
534
535static 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
414int fb_prepare_logo(struct fb_info *info, int rotate) 543int 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
480int fb_show_logo(struct fb_info *info, int rotate) 610int 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
547int fb_prepare_logo(struct fb_info *info, int rotate) { return 0; } 621int 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
1158static int 1232static int
1159fb_mmap(struct file *file, struct vm_area_struct * vma) 1233fb_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
1258static int 1285static 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
1393int 1427int
1394unregister_framebuffer(struct fb_info *fb_info) 1428unregister_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; 1457done:
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)
195static int fm2fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, 195static 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
87static int ypan, ywrap; 87static int ypan, ywrap;
88 88
89static uint32_t pseudo_palette[256]; 89static uint32_t pseudo_palette[16];
90 90
91static char *mode_option __initdata = NULL; 91static 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
11if LOGO 11if LOGO
12 12
13config FB_LOGO_EXTRA
14 bool
15 depends on FB=y
16 default y if SPU_BASE
17
13config LOGO_LINUX_MONO 18config 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
14obj-$(CONFIG_LOGO_SUPERH_CLUT224) += logo_superh_clut224.o 14obj-$(CONFIG_LOGO_SUPERH_CLUT224) += logo_superh_clut224.o
15obj-$(CONFIG_LOGO_M32R_CLUT224) += logo_m32r_clut224.o 15obj-$(CONFIG_LOGO_M32R_CLUT224) += logo_m32r_clut224.o
16 16
17obj-$(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;
34extern const struct linux_logo logo_superh_clut224; 34extern const struct linux_logo logo_superh_clut224;
35extern const struct linux_logo logo_m32r_clut224; 35extern const struct linux_logo logo_m32r_clut224;
36 36
37 37/* logo's are marked __initdata. Use __init_refok to tell
38const struct linux_logo *fb_find_logo(int depth) 38 * modpost that it is intended that this function uses data
39 * marked __initdata.
40 */
41const 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 @@
1P3
240 40
3255
40 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
50 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
60 0 0 0 0 0 0 0 0 0 0 0 2 2 2 6 6 6
715 15 15 21 21 21 19 19 19 14 14 14 6 6 6 2 2 2
80 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
90 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
100 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
120 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
130 0 0 0 0 0 0 0 0 2 2 2 21 21 21 55 55 55
1456 56 56 54 54 54 53 53 53 60 60 60 56 56 56 25 25 25
156 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
160 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
170 0 0 0 0 0 0 0 0 0 0 0
180 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
190 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
200 0 0 0 0 0 2 2 2 27 27 27 62 62 62 17 17 19
212 2 6 2 2 6 2 2 6 2 2 6 16 16 18 57 57 57
2245 45 45 8 8 8 0 0 0 0 0 0 0 0 0 0 0 0
230 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
240 0 0 0 0 0 0 0 0 0 0 0
250 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0
260 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
270 0 0 0 0 0 16 16 16 62 62 62 8 8 10 2 2 6
282 2 6 2 2 6 2 2 6 12 12 14 67 67 67 16 16 17
2945 45 45 41 41 41 4 4 4 0 0 0 0 0 0 0 0 0
300 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
310 0 0 0 0 0 0 0 0 0 0 0
320 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
330 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
340 0 0 2 2 2 35 35 35 40 40 40 2 2 6 2 2 6
352 2 6 2 2 6 2 2 6 15 15 17 70 70 70 27 27 27
363 3 6 62 62 62 20 20 20 0 0 0 0 0 0 0 0 0
370 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
380 0 0 0 0 0 0 0 0 0 0 0
390 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
400 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
410 0 0 4 4 4 58 58 58 12 12 14 2 2 6 2 2 6
422 2 6 2 2 6 2 2 6 4 4 7 4 4 7 2 2 6
432 2 6 34 34 36 40 40 40 3 3 3 0 0 0 0 0 0
440 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
450 0 0 0 0 0 0 0 0 0 0 0
460 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
470 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
480 0 0 7 7 7 64 64 64 2 2 6 5 5 5 17 17 17
493 3 6 2 2 6 2 2 6 15 15 15 21 21 21 7 7 10
502 2 6 8 8 10 62 62 62 6 6 6 0 0 0 0 0 0
510 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
520 0 0 0 0 0 0 0 0 0 0 0
530 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
540 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
550 0 0 7 7 7 66 66 66 5 5 8 122 122 122 122 122 122
569 9 11 3 3 6 104 96 81 179 179 179 122 122 122 13 13 13
572 2 6 2 2 6 67 67 67 10 10 10 0 0 0 0 0 0
580 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
590 0 0 0 0 0 0 0 0 0 0 0
600 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
610 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
620 0 0 7 7 7 65 65 65 41 41 43 152 149 142 192 191 189
6348 48 49 23 23 24 228 210 210 86 86 86 192 191 189 59 59 61
642 2 6 2 2 6 64 64 64 14 14 14 0 0 0 0 0 0
650 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
660 0 0 0 0 0 0 0 0 0 0 0
670 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0
680 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
690 0 0 7 7 7 66 66 66 59 59 59 59 59 61 86 86 86
7099 84 50 78 66 28 152 149 142 5 5 8 122 122 122 104 96 81
712 2 6 2 2 6 67 67 67 14 14 14 0 0 0 0 0 0
720 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
730 0 0 0 0 0 0 0 0 0 0 0
740 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
750 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
760 0 0 5 5 5 63 63 63 24 24 24 152 149 142 175 122 13
77238 184 12 220 170 13 226 181 52 112 86 32 194 165 151 46 46 47
782 2 6 2 2 6 65 65 65 17 17 17 0 0 0 0 0 0
790 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
800 0 0 0 0 0 0 0 0 0 0 0
810 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
820 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
830 0 0 5 5 5 59 59 59 21 21 21 175 122 13 231 174 11
84240 192 13 237 183 61 240 192 13 240 192 13 234 179 16 81 64 9
852 2 6 2 2 6 63 63 63 25 25 25 0 0 0 0 0 0
860 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
870 0 0 0 0 0 0 0 0 0 0 0
880 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
890 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
900 0 0 5 5 5 54 54 54 51 48 39 189 138 9 238 184 12
91240 192 13 240 192 13 240 192 13 215 161 11 207 152 19 81 64 9
9216 16 18 5 5 8 40 40 40 44 44 44 4 4 4 0 0 0
930 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
940 0 0 0 0 0 0 0 0 0 0 0
950 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
960 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
970 0 0 5 5 5 59 59 59 27 27 27 126 107 64 187 136 12
98220 170 13 201 147 20 189 138 9 198 154 46 199 182 125 70 70 70
9927 27 27 104 96 81 12 12 14 70 70 70 16 16 16 0 0 0
1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1010 0 0 0 0 0 0 0 0 0 0 0
1020 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1030 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1040 0 0 17 17 17 70 70 70 12 12 12 168 168 168 174 135 135
105175 122 13 175 122 13 178 151 83 192 191 189 233 233 233 179 179 179
1063 3 6 29 29 31 3 3 6 41 41 41 44 44 44 5 5 5
1070 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1080 0 0 0 0 0 0 0 0 0 0 0
1090 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1100 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1118 8 8 53 53 53 44 44 44 59 59 59 238 238 238 192 191 189
112192 191 189 192 191 189 221 205 205 240 240 240 253 253 253 253 253 253
11370 70 70 2 2 6 2 2 6 5 5 8 67 67 67 22 22 22
1142 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1150 0 0 0 0 0 0 0 0 0 0 0
1160 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1170 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5
11838 38 38 56 56 56 7 7 9 221 205 205 253 253 253 233 233 233
119221 205 205 233 233 233 251 251 251 253 253 253 253 253 253 253 253 253
120192 191 189 2 2 6 2 2 6 2 2 6 25 25 25 64 64 64
12115 15 15 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1220 0 0 0 0 0 0 0 0 0 0 0
1230 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1240 0 0 0 0 0 0 0 0 0 0 0 2 2 2 27 27 27
12566 66 66 7 7 9 86 86 86 252 252 252 253 253 253 253 253 253
126252 252 252 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
127244 244 244 19 19 21 2 2 6 2 2 6 2 2 6 38 38 38
12854 54 54 10 10 10 0 0 0 0 0 0 0 0 0 0 0 0
1290 0 0 0 0 0 0 0 0 0 0 0
1300 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1310 0 0 0 0 0 0 0 0 0 0 0 14 14 14 62 62 62
13210 10 12 3 3 6 122 122 122 235 235 235 251 251 251 248 248 248
133235 235 235 248 248 248 252 252 252 246 246 246 233 233 233 237 228 228
134223 207 207 70 70 70 2 2 6 2 2 6 2 2 6 2 2 6
13546 46 47 38 38 38 4 4 4 0 0 0 0 0 0 0 0 0
1360 0 0 0 0 0 0 0 0 0 0 0
1370 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1380 0 0 0 0 0 0 0 0 2 2 2 33 33 33 44 44 44
1394 4 7 9 9 11 168 168 168 240 240 240 252 252 252 252 252 252
140246 246 246 253 253 253 253 253 253 251 251 251 245 241 241 233 233 233
141221 205 205 192 191 189 29 29 31 27 27 27 9 9 12 2 2 6
1423 3 6 65 65 65 15 15 15 0 0 0 0 0 0 0 0 0
1430 0 0 0 0 0 0 0 0 0 0 0
1440 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1450 0 0 0 0 0 0 0 0 6 6 6 59 59 59 19 19 21
14624 24 24 86 86 86 249 249 249 253 253 253 253 253 253 253 253 253
147253 253 253 228 210 210 241 230 230 253 253 253 253 253 253 253 253 253
148251 251 251 228 210 210 152 149 142 5 5 8 27 27 27 4 4 7
1492 2 6 46 46 47 34 34 34 2 2 2 0 0 0 0 0 0
1500 0 0 0 0 0 0 0 0 0 0 0
1510 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1520 0 0 0 0 0 0 0 0 16 16 16 67 67 67 19 19 21
15312 12 14 223 207 207 254 20 20 254 20 20 253 127 127 242 223 223
154254 20 20 253 127 127 254 48 48 242 223 223 254 86 86 254 20 20
155254 20 20 253 137 137 233 233 233 32 32 32 35 35 35 23 23 24
1562 2 6 15 15 15 60 60 60 6 6 6 0 0 0 0 0 0
1570 0 0 0 0 0 0 0 0 0 0 0
1580 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1590 0 0 0 0 0 4 4 4 38 38 38 48 48 49 22 22 22
16086 86 86 253 253 253 254 20 20 241 230 230 227 216 186 253 137 137
161253 137 137 253 253 253 253 137 137 253 137 137 254 48 48 253 253 253
162253 253 253 253 253 253 253 253 253 62 62 62 2 2 6 23 23 24
1632 2 6 2 2 6 62 62 62 17 17 17 0 0 0 0 0 0
1640 0 0 0 0 0 0 0 0 0 0 0
1650 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1660 0 0 0 0 0 14 14 14 70 70 70 14 14 14 16 16 18
167179 179 179 253 253 253 227 216 186 254 48 48 240 219 160 253 127 127
168254 20 20 253 137 137 254 86 86 231 203 141 254 20 20 254 20 20
169253 137 137 253 253 253 253 253 253 104 96 81 2 2 6 23 23 24
1702 2 6 2 2 6 46 46 47 27 27 27 0 0 0 0 0 0
1710 0 0 0 0 0 0 0 0 0 0 0
1720 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1730 0 0 4 4 4 39 39 39 42 42 43 19 19 21 13 13 13
174228 210 210 242 223 223 253 253 253 242 223 223 253 127 127 253 127 127
175253 127 127 253 127 127 253 137 137 253 253 253 254 48 48 253 253 253
176228 210 210 253 253 253 253 253 253 122 122 122 2 2 6 19 19 19
1772 2 6 2 2 6 39 39 39 38 38 38 3 3 3 0 0 0
1780 0 0 0 0 0 0 0 0 0 0 0
1790 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1800 0 0 8 8 8 60 60 60 3 3 6 33 33 33 38 38 38
181253 137 137 254 86 86 253 137 137 254 86 86 253 137 137 209 197 168
182253 127 127 253 253 253 253 253 253 253 253 253 253 127 127 254 86 86
183254 86 86 253 137 137 253 253 253 122 122 122 2 2 6 17 17 17
1842 2 6 2 2 6 34 34 36 42 42 43 3 3 3 0 0 0
1850 0 0 0 0 0 0 0 0 0 0 0
1860 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1870 0 0 13 13 13 59 59 59 2 2 6 9 9 12 56 56 56
188252 252 252 240 219 160 253 137 137 240 219 160 253 253 253 237 228 228
189254 86 86 253 253 253 253 253 253 253 253 253 253 253 253 242 223 223
190227 216 186 249 249 249 253 253 253 122 122 122 16 16 17 17 17 17
19112 12 14 3 3 6 39 39 39 38 38 38 3 3 3 0 0 0
1920 0 0 0 0 0 0 0 0 0 0 0
1930 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2
1945 5 5 22 22 22 104 96 81 187 136 12 207 152 19 51 48 39
195221 205 205 253 253 253 253 253 253 253 253 253 253 253 253 240 240 240
196250 247 243 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
197253 253 253 250 247 243 240 219 160 99 84 50 5 5 8 2 2 6
1987 7 9 46 46 47 58 58 58 35 35 35 3 3 3 0 0 0
1990 0 0 0 0 0 0 0 0 0 0 0
2000 0 0 0 0 0 0 0 0 0 0 0 8 8 8 33 33 33
20158 58 58 86 86 86 170 136 53 239 182 13 246 190 14 220 170 13
20244 38 29 179 179 179 253 253 253 253 253 253 253 253 253 240 240 240
203253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
204253 253 253 240 219 160 240 192 13 112 86 32 2 2 6 2 2 6
2053 3 6 41 33 20 220 170 13 53 53 53 4 4 4 0 0 0
2060 0 0 0 0 0 0 0 0 0 0 0
2070 0 0 0 0 0 0 0 0 2 2 2 32 32 32 150 116 44
208215 161 11 215 161 11 228 170 11 245 188 14 246 190 14 246 190 14
209187 136 12 9 9 11 122 122 122 251 251 251 253 253 253 253 253 253
210253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
211248 248 248 211 196 135 239 182 13 175 122 13 6 5 6 2 2 6
21216 14 12 187 136 12 238 184 12 84 78 65 10 10 10 0 0 0
2130 0 0 0 0 0 0 0 0 0 0 0
2140 0 0 0 0 0 0 0 0 4 4 4 53 53 53 207 152 19
215242 185 13 245 188 14 246 190 14 246 190 14 246 190 14 246 190 14
216240 192 13 81 64 9 2 2 6 86 86 86 244 244 244 253 253 253
217253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
218233 233 233 199 182 125 231 174 11 207 152 19 175 122 13 175 122 13
219201 147 20 239 182 13 244 187 14 150 116 44 35 35 35 6 6 6
2200 0 0 0 0 0 0 0 0 0 0 0
2210 0 0 0 0 0 0 0 0 5 5 5 53 53 53 201 147 20
222242 185 13 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14
223246 190 14 220 170 13 13 11 10 2 2 6 152 149 142 253 253 253
224253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
225235 235 235 199 182 125 228 170 11 234 177 12 226 168 11 226 168 11
226234 177 12 246 190 14 246 190 14 234 179 16 126 107 64 36 36 36
2276 6 6 0 0 0 0 0 0 0 0 0
2280 0 0 0 0 0 0 0 0 3 3 3 48 48 49 189 142 35
229242 185 13 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14
230246 190 14 246 190 14 140 112 39 36 36 36 192 191 189 253 253 253
231253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
232192 191 189 112 86 32 226 168 11 244 187 14 244 187 14 244 187 14
233245 188 14 246 190 14 246 190 14 246 190 14 242 185 13 150 116 44
23427 27 27 2 2 2 0 0 0 0 0 0
2350 0 0 0 0 0 0 0 0 6 6 6 58 58 58 189 142 35
236239 182 13 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14
237246 190 14 246 190 14 239 188 14 209 197 168 253 253 253 253 253 253
238253 253 253 253 253 253 253 253 253 253 253 253 252 252 252 168 168 168
23916 16 18 97 67 8 228 170 11 245 188 14 246 190 14 246 190 14
240246 190 14 246 190 14 246 190 14 246 190 14 244 187 14 198 154 46
24135 35 35 3 3 3 0 0 0 0 0 0
2420 0 0 0 0 0 0 0 0 13 13 13 84 78 65 215 161 11
243244 187 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14
244246 190 14 246 190 14 238 184 12 187 136 12 168 168 168 244 244 244
245253 253 253 252 252 252 240 240 240 179 179 179 67 67 67 2 2 6
2462 2 6 97 67 8 228 170 11 246 190 14 246 190 14 246 190 14
247246 190 14 246 190 14 245 188 14 234 177 12 189 142 35 86 77 61
24816 16 16 0 0 0 0 0 0 0 0 0
2490 0 0 0 0 0 0 0 0 13 13 13 103 92 56 207 152 19
250228 170 11 234 177 12 239 182 13 242 186 14 245 188 14 246 190 14
251246 190 14 246 190 14 239 182 13 189 138 9 41 33 20 10 10 12
25230 30 31 23 23 24 5 5 8 2 2 6 2 2 6 2 2 6
2534 4 6 112 86 32 215 161 11 245 188 14 246 190 14 245 188 14
254239 182 13 228 170 11 189 142 35 104 96 81 48 48 49 17 17 17
2552 2 2 0 0 0 0 0 0 0 0 0
2560 0 0 0 0 0 0 0 0 5 5 5 39 39 39 103 92 56
257141 109 44 175 122 13 187 136 12 189 138 9 207 152 19 228 170 11
258239 182 13 239 182 13 215 161 11 175 122 13 41 33 20 2 2 6
25915 15 17 20 20 22 20 20 22 20 20 22 20 20 22 8 8 10
2604 4 6 97 67 8 189 138 9 231 174 11 239 182 13 226 168 11
261189 138 9 126 107 64 59 59 59 21 21 21 5 5 5 0 0 0
2620 0 0 0 0 0 0 0 0 0 0 0
2630 0 0 0 0 0 0 0 0 0 0 0 5 5 5 17 17 17
26434 34 34 57 57 57 84 78 65 103 92 56 125 101 41 140 112 39
265175 122 13 175 122 13 175 122 13 97 67 8 72 67 58 84 78 65
26660 60 60 56 56 56 56 56 56 56 56 56 57 57 57 65 65 65
26786 86 86 95 73 34 175 122 13 187 136 12 187 136 12 175 122 13
268103 92 56 41 41 41 10 10 10 0 0 0 0 0 0 0 0 0
2690 0 0 0 0 0 0 0 0 0 0 0
2700 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2712 2 2 4 4 4 12 12 12 24 24 24 40 40 40 70 70 70
27286 77 61 95 73 34 88 72 41 72 67 58 36 36 36 10 10 10
2735 5 5 5 5 5 5 5 5 4 4 4 5 5 5 6 6 6
27422 22 22 61 61 59 88 72 41 112 86 32 112 86 32 84 78 65
27532 32 32 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0
2760 0 0 0 0 0 0 0 0 0 0 0
2770 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2780 0 0 0 0 0 0 0 0 0 0 0 3 3 3 10 10 10
27921 21 21 33 33 33 31 31 31 16 16 16 2 2 2 0 0 0
2800 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2812 2 2 12 12 12 30 30 31 40 40 40 32 32 32 16 16 16
2822 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2830 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
172static struct fb_info fb_info; 172static struct fb_info fb_info;
173static u32 pseudo_palette[17]; 173static u32 pseudo_palette[16];
174static int inverse = 0; 174static int inverse = 0;
175static int vidtest = 0; 175static 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
584static struct fb_ops macfb_ops = { 591static 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
372int __devinit mac_find_mode(struct fb_var_screeninfo *var, 372int 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,
55extern int mac_var_to_vmode(const struct fb_var_screeninfo *var, int *vmode, 55extern int mac_var_to_vmode(const struct fb_var_screeninfo *var, int *vmode,
56 int *cmode); 56 int *cmode);
57extern int mac_map_monitor_sense(int sense); 57extern int mac_map_monitor_sense(int sense);
58extern int __devinit mac_find_mode(struct fb_var_screeninfo *var, 58extern 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
97static inline void matrox_cfb8_pal(u_int32_t* pal) { 96static 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
106static void matroxfb_copyarea(struct fb_info* info, const struct fb_copyarea* area); 104static 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
166static void matroxfb_dh_cfbX_init(struct matroxfb_dh_fb_info* m2info) {
167 /* no acceleration for secondary head... */
168 m2info->cmap[16] = 0xFFFFFFFF;
169}
170
171static void matroxfb_dh_pan_var(struct matroxfb_dh_fb_info* m2info, 166static 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
940void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state) 945void 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)
166static int NVIsConnected(struct nvidia_par *par, int output) 166static 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
91struct riva_regs { 92struct 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 @@
1config 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
10config 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
18config 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
29config 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
39config 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
46config 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
53config 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
5obj-$(CONFIG_FB_OMAP) += omapfb.o
6
7objs-yy := omapfb_main.o
8
9objs-y$(CONFIG_ARCH_OMAP1) += lcdc.o
10objs-y$(CONFIG_ARCH_OMAP2) += dispc.o
11
12objs-$(CONFIG_ARCH_OMAP1)$(CONFIG_FB_OMAP_LCDC_EXTERNAL) += sossi.o
13objs-$(CONFIG_ARCH_OMAP2)$(CONFIG_FB_OMAP_LCDC_EXTERNAL) += rfbi.o
14
15objs-y$(CONFIG_FB_OMAP_LCDC_HWA742) += hwa742.o
16objs-y$(CONFIG_FB_OMAP_LCDC_BLIZZARD) += blizzard.o
17
18objs-y$(CONFIG_MACH_OMAP_H4) += lcd_h4.o
19objs-y$(CONFIG_MACH_OMAP_H3) += lcd_h3.o
20objs-y$(CONFIG_MACH_OMAP_PALMTE) += lcd_palmte.o
21objs-y$(CONFIG_MACH_OMAP_PALMTT) += lcd_palmtt.o
22objs-y$(CONFIG_MACH_OMAP_PALMZ71) += lcd_palmz71.o
23objs-$(CONFIG_ARCH_OMAP16XX)$(CONFIG_MACH_OMAP_INNOVATOR) += lcd_inn1610.o
24objs-$(CONFIG_ARCH_OMAP15XX)$(CONFIG_MACH_OMAP_INNOVATOR) += lcd_inn1510.o
25objs-y$(CONFIG_MACH_OMAP_OSK) += lcd_osk.o
26objs-y$(CONFIG_MACH_SX1) += lcd_sx1.o
27
28omapfb-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
89struct blizzard_reg_list {
90 int start;
91 int end;
92};
93
94/* These need to be saved / restored separately from the rest. */
95static 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
106static 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
117static u8 blizzard_reg_cache[0x5a / 2];
118
119struct 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
129struct 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
143struct 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
153struct 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
197struct lcd_ctrl blizzard_ctrl;
198
199static u8 blizzard_read_reg(u8 reg)
200{
201 u8 data;
202
203 blizzard.extif->set_bits_per_cycle(8);
204 blizzard.extif->write_command(&reg, 1);
205 blizzard.extif->read_data(&data, 1);
206
207 return data;
208}
209
210static void blizzard_write_reg(u8 reg, u8 val)
211{
212 blizzard.extif->set_bits_per_cycle(8);
213 blizzard.extif->write_command(&reg, 1);
214 blizzard.extif->write_data(&val, 1);
215}
216
217static 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
235static 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 */
243static 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. */
258static 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
272static void disable_overlay(void)
273{
274 blizzard_write_reg(BLIZZARD_DATA_SOURCE_SELECT,
275 BLIZZARD_SRC_DISABLE_OVERLAY);
276}
277
278static 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
324static 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
352static 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
363static inline void set_extif_timings(const struct extif_timings *t);
364
365static 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
389static 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
403static 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
434static 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
449static 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
467static 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. */
517static 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
668static 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
696static 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
719static 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
773static 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
780static 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
797int 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}
822EXPORT_SYMBOL(blizzard_update_window_async);
823
824static 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
831static 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
883static 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
911static 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
921static int sync_handler(struct blizzard_request *req)
922{
923 complete(req->par.sync);
924 return REQ_COMPLETE;
925}
926
927static 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 = &comp;
939
940 list_add(&req->entry, &req_list);
941 submit_req_list(&req_list);
942
943 wait_for_completion(&comp);
944}
945
946
947static 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
954static 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
998static enum omapfb_update_mode blizzard_get_update_mode(void)
999{
1000 return blizzard.update_mode;
1001}
1002
1003static inline void set_extif_timings(const struct extif_timings *t)
1004{
1005 blizzard.extif->set_timings(t);
1006}
1007
1008static 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
1014static 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
1064static 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
1118static 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;
1145err:
1146 dev_err(blizzard.fbdev->dev, "can't setup timings\n");
1147 return -1;
1148}
1149
1150static 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
1177static 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
1282static 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
1295static 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
1306static 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
1317static 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
1323static void blizzard_restore_pll_regs(void)
1324{
1325 _restore_regs(blizzard_pll_regs, ARRAY_SIZE(blizzard_pll_regs));
1326}
1327
1328static void blizzard_restore_gen_regs(void)
1329{
1330 _restore_regs(blizzard_gen_regs, ARRAY_SIZE(blizzard_gen_regs));
1331}
1332
1333static 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
1374static 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
1412static 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;
1533err3:
1534 if (blizzard.power_down != NULL)
1535 blizzard.power_down(fbdev->dev);
1536 blizzard.extif->cleanup();
1537err2:
1538 blizzard.int_ctrl->cleanup();
1539err1:
1540 return r;
1541}
1542
1543static 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
1552struct 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
151struct resmap {
152 unsigned long start;
153 unsigned page_cnt;
154 unsigned long *map;
155};
156
157static 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
186static void enable_lcd_clocks(int enable);
187
188static void inline dispc_write_reg(int idx, u32 val)
189{
190 __raw_writel(val, dispc.base + idx);
191}
192
193static 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 */
200static 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
219static 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
247static 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
254void 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}
262EXPORT_SYMBOL(omap_dispc_set_lcd_size);
263
264void 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}
272EXPORT_SYMBOL(omap_dispc_set_digit_size);
273
274static 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
300void 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}
306EXPORT_SYMBOL(omap_dispc_enable_lcd_out);
307
308void 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}
314EXPORT_SYMBOL(omap_dispc_enable_digit_out);
315
316static 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
441static 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
461static 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
472static 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
483static 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
503static 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
580static 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
595static 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
640static int omap_dispc_get_color_key(struct omapfb_color_key *ck)
641{
642 *ck = dispc.color_key;
643 return 0;
644}
645
646static void load_palette(void)
647{
648}
649
650static 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
681static 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
697static enum omapfb_update_mode omap_dispc_get_update_mode(void)
698{
699 return dispc.update_mode;
700}
701
702static 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
737static 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
763static 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
771static 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
811int 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}
826EXPORT_SYMBOL(omap_dispc_request_irq);
827
828void 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}
836EXPORT_SYMBOL(omap_dispc_enable_irqs);
837
838void 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}
846EXPORT_SYMBOL(omap_dispc_disable_irqs);
847
848void 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}
856EXPORT_SYMBOL(omap_dispc_free_irq);
857
858static 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
880static 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
904static 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
911static 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
919static 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
927static 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
935static 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
949static 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
962static 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
970static 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
999static 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
1006static 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
1013static struct vm_operations_struct mmap_user_ops = {
1014 .open = mmap_user_open,
1015 .close = mmap_user_close,
1016};
1017
1018static 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
1052static void unmap_kern(struct omapfb_mem_region *region)
1053{
1054 vunmap(region->vaddr);
1055}
1056
1057static 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
1069static 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
1075static int alloc_fbmem(struct omapfb_mem_region *region)
1076{
1077 region->vaddr = dma_alloc_writecombine(dispc.fbdev->dev,
1078 region->size, &region->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
1088static 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
1094static 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
1110static void cleanup_resmap(struct resmap *res_map)
1111{
1112 kfree(res_map);
1113}
1114
1115static 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
1124static 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
1129static 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
1135static 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
1141static 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
1160static 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
1178static 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 */
1210static 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
1246static 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;
1311fail:
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
1319static 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
1339static 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;
1458fail3:
1459 free_palette_ram();
1460fail2:
1461 free_irq(INT_24XX_DSS_IRQ, fbdev);
1462fail1:
1463 enable_lcd_clocks(0);
1464 enable_interface_clocks(0);
1465 put_dss_clocks();
1466
1467 return r;
1468}
1469
1470static 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
1485const 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
35extern void omap_dispc_set_lcd_size(int width, int height);
36
37extern void omap_dispc_enable_lcd_out(int enable);
38extern void omap_dispc_enable_digit_out(int enable);
39
40extern int omap_dispc_request_irq(void (*callback)(void *data), void *data);
41extern 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
84struct update_param {
85 int x, y, width, height;
86 int color_mode;
87 int flags;
88};
89
90struct 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
104struct {
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
140struct lcd_ctrl hwa742_ctrl;
141
142static u8 hwa742_read_reg(u8 reg)
143{
144 u8 data;
145
146 hwa742.extif->set_bits_per_cycle(8);
147 hwa742.extif->write_command(&reg, 1);
148 hwa742.extif->read_data(&data, 1);
149
150 return data;
151}
152
153static void hwa742_write_reg(u8 reg, u8 data)
154{
155 hwa742.extif->set_bits_per_cycle(8);
156 hwa742.extif->write_command(&reg, 1);
157 hwa742.extif->write_data(&data, 1);
158}
159
160static 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
184static 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
203static 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
231static 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
242static 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
266static 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
280static 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
311static 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
326static 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
343static 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
413static 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
431static 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
473static 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
480static 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
494int 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
524out:
525 return r;
526}
527EXPORT_SYMBOL(hwa742_update_window_async);
528
529static 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
541static 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
551static int sync_handler(struct hwa742_request *req)
552{
553 complete(req->par.sync);
554 return REQ_COMPLETE;
555}
556
557static 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 = &comp;
569
570 list_add(&req->entry, &req_list);
571 submit_req_list(&req_list);
572
573 wait_for_completion(&comp);
574}
575
576static 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
584static 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
627static enum omapfb_update_mode hwa742_get_update_mode(void)
628{
629 return hwa742.update_mode;
630}
631
632static 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
638static 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
684static 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
735static 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
760err:
761 dev_err(hwa742.fbdev->dev, "can't setup timings\n");
762 return -1;
763}
764
765static 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
791static 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
901static 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
912static 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
922static 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
938static 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;
1042err4:
1043 if (hwa742.power_down != NULL)
1044 hwa742.power_down(fbdev->dev);
1045err3:
1046 hwa742.extif->cleanup();
1047err2:
1048 hwa742.int_ctrl->cleanup();
1049err1:
1050 return r;
1051}
1052
1053static 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
1062struct 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
33static int h3_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev)
34{
35 return 0;
36}
37
38static void h3_panel_cleanup(struct lcd_panel *panel)
39{
40}
41
42static 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
56static 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
68static unsigned long h3_panel_get_caps(struct lcd_panel *panel)
69{
70 return 0;
71}
72
73struct 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
97static int h3_panel_probe(struct platform_device *pdev)
98{
99 omapfb_register_panel(&h3_panel);
100 return 0;
101}
102
103static int h3_panel_remove(struct platform_device *pdev)
104{
105 return 0;
106}
107
108static int h3_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
109{
110 return 0;
111}
112
113static int h3_panel_resume(struct platform_device *pdev)
114{
115 return 0;
116}
117
118struct 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
129static int h3_panel_drv_init(void)
130{
131 return platform_driver_register(&h3_panel_driver);
132}
133
134static void h3_panel_drv_cleanup(void)
135{
136 platform_driver_unregister(&h3_panel_driver);
137}
138
139module_init(h3_panel_drv_init);
140module_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
27static int h4_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev)
28{
29 return 0;
30}
31
32static void h4_panel_cleanup(struct lcd_panel *panel)
33{
34}
35
36static int h4_panel_enable(struct lcd_panel *panel)
37{
38 return 0;
39}
40
41static void h4_panel_disable(struct lcd_panel *panel)
42{
43}
44
45static unsigned long h4_panel_get_caps(struct lcd_panel *panel)
46{
47 return 0;
48}
49
50struct 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
73static int h4_panel_probe(struct platform_device *pdev)
74{
75 omapfb_register_panel(&h4_panel);
76 return 0;
77}
78
79static int h4_panel_remove(struct platform_device *pdev)
80{
81 return 0;
82}
83
84static int h4_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
85{
86 return 0;
87}
88
89static int h4_panel_resume(struct platform_device *pdev)
90{
91 return 0;
92}
93
94struct 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
105static int h4_panel_drv_init(void)
106{
107 return platform_driver_register(&h4_panel_driver);
108}
109
110static void h4_panel_drv_cleanup(void)
111{
112 platform_driver_unregister(&h4_panel_driver);
113}
114
115module_init(h4_panel_drv_init);
116module_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
29static int innovator1510_panel_init(struct lcd_panel *panel,
30 struct omapfb_device *fbdev)
31{
32 return 0;
33}
34
35static void innovator1510_panel_cleanup(struct lcd_panel *panel)
36{
37}
38
39static int innovator1510_panel_enable(struct lcd_panel *panel)
40{
41 fpga_write(0x7, OMAP1510_FPGA_LCD_PANEL_CONTROL);
42 return 0;
43}
44
45static void innovator1510_panel_disable(struct lcd_panel *panel)
46{
47 fpga_write(0x0, OMAP1510_FPGA_LCD_PANEL_CONTROL);
48}
49
50static unsigned long innovator1510_panel_get_caps(struct lcd_panel *panel)
51{
52 return 0;
53}
54
55struct 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
79static int innovator1510_panel_probe(struct platform_device *pdev)
80{
81 omapfb_register_panel(&innovator1510_panel);
82 return 0;
83}
84
85static int innovator1510_panel_remove(struct platform_device *pdev)
86{
87 return 0;
88}
89
90static int innovator1510_panel_suspend(struct platform_device *pdev,
91 pm_message_t mesg)
92{
93 return 0;
94}
95
96static int innovator1510_panel_resume(struct platform_device *pdev)
97{
98 return 0;
99}
100
101struct 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
112static int innovator1510_panel_drv_init(void)
113{
114 return platform_driver_register(&innovator1510_panel_driver);
115}
116
117static void innovator1510_panel_drv_cleanup(void)
118{
119 platform_driver_unregister(&innovator1510_panel_driver);
120}
121
122module_init(innovator1510_panel_drv_init);
123module_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
32static 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);
51exit:
52 return r;
53}
54
55static void innovator1610_panel_cleanup(struct lcd_panel *panel)
56{
57 omap_free_gpio(15);
58 omap_free_gpio(14);
59}
60
61static 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
69static 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
76static unsigned long innovator1610_panel_get_caps(struct lcd_panel *panel)
77{
78 return 0;
79}
80
81struct 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
105static int innovator1610_panel_probe(struct platform_device *pdev)
106{
107 omapfb_register_panel(&innovator1610_panel);
108 return 0;
109}
110
111static int innovator1610_panel_remove(struct platform_device *pdev)
112{
113 return 0;
114}
115
116static int innovator1610_panel_suspend(struct platform_device *pdev,
117 pm_message_t mesg)
118{
119 return 0;
120}
121
122static int innovator1610_panel_resume(struct platform_device *pdev)
123{
124 return 0;
125}
126
127struct 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
138static int innovator1610_panel_drv_init(void)
139{
140 return platform_driver_register(&innovator1610_panel_driver);
141}
142
143static void innovator1610_panel_drv_cleanup(void)
144{
145 platform_driver_unregister(&innovator1610_panel_driver);
146}
147
148module_init(innovator1610_panel_drv_init);
149module_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
30static int osk_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev)
31{
32 return 0;
33}
34
35static void osk_panel_cleanup(struct lcd_panel *panel)
36{
37}
38
39static 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
59static 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
71static unsigned long osk_panel_get_caps(struct lcd_panel *panel)
72{
73 return 0;
74}
75
76struct 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
100static int osk_panel_probe(struct platform_device *pdev)
101{
102 omapfb_register_panel(&osk_panel);
103 return 0;
104}
105
106static int osk_panel_remove(struct platform_device *pdev)
107{
108 return 0;
109}
110
111static int osk_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
112{
113 return 0;
114}
115
116static int osk_panel_resume(struct platform_device *pdev)
117{
118 return 0;
119}
120
121struct 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
132static int osk_panel_drv_init(void)
133{
134 return platform_driver_register(&osk_panel_driver);
135}
136
137static void osk_panel_drv_cleanup(void)
138{
139 platform_driver_unregister(&osk_panel_driver);
140}
141
142module_init(osk_panel_drv_init);
143module_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
29static int palmte_panel_init(struct lcd_panel *panel,
30 struct omapfb_device *fbdev)
31{
32 return 0;
33}
34
35static void palmte_panel_cleanup(struct lcd_panel *panel)
36{
37}
38
39static int palmte_panel_enable(struct lcd_panel *panel)
40{
41 return 0;
42}
43
44static void palmte_panel_disable(struct lcd_panel *panel)
45{
46}
47
48static unsigned long palmte_panel_get_caps(struct lcd_panel *panel)
49{
50 return 0;
51}
52
53struct 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
79static int palmte_panel_probe(struct platform_device *pdev)
80{
81 omapfb_register_panel(&palmte_panel);
82 return 0;
83}
84
85static int palmte_panel_remove(struct platform_device *pdev)
86{
87 return 0;
88}
89
90static int palmte_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
91{
92 return 0;
93}
94
95static int palmte_panel_resume(struct platform_device *pdev)
96{
97 return 0;
98}
99
100struct 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
111static int palmte_panel_drv_init(void)
112{
113 return platform_driver_register(&palmte_panel_driver);
114}
115
116static void palmte_panel_drv_cleanup(void)
117{
118 platform_driver_unregister(&palmte_panel_driver);
119}
120
121module_init(palmte_panel_drv_init);
122module_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/*
23GPIO11 - backlight
24GPIO12 - screen blanking
25GPIO13 - 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
35static int palmtt_panel_init(struct lcd_panel *panel,
36 struct omapfb_device *fbdev)
37{
38 return 0;
39}
40
41static void palmtt_panel_cleanup(struct lcd_panel *panel)
42{
43}
44
45static int palmtt_panel_enable(struct lcd_panel *panel)
46{
47 return 0;
48}
49
50static void palmtt_panel_disable(struct lcd_panel *panel)
51{
52}
53
54static unsigned long palmtt_panel_get_caps(struct lcd_panel *panel)
55{
56 return OMAPFB_CAPS_SET_BACKLIGHT;
57}
58
59struct 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
84static int palmtt_panel_probe(struct platform_device *pdev)
85{
86 omapfb_register_panel(&palmtt_panel);
87 return 0;
88}
89
90static int palmtt_panel_remove(struct platform_device *pdev)
91{
92 return 0;
93}
94
95static int palmtt_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
96{
97 return 0;
98}
99
100static int palmtt_panel_resume(struct platform_device *pdev)
101{
102 return 0;
103}
104
105struct 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
116static int palmtt_panel_drv_init(void)
117{
118 return platform_driver_register(&palmtt_panel_driver);
119}
120
121static void palmtt_panel_drv_cleanup(void)
122{
123 platform_driver_unregister(&palmtt_panel_driver);
124}
125
126module_init(palmtt_panel_drv_init);
127module_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
29static int palmz71_panel_init(struct lcd_panel *panel,
30 struct omapfb_device *fbdev)
31{
32 return 0;
33}
34
35static void palmz71_panel_cleanup(struct lcd_panel *panel)
36{
37
38}
39
40static int palmz71_panel_enable(struct lcd_panel *panel)
41{
42 return 0;
43}
44
45static void palmz71_panel_disable(struct lcd_panel *panel)
46{
47}
48
49static unsigned long palmz71_panel_get_caps(struct lcd_panel *panel)
50{
51 return OMAPFB_CAPS_SET_BACKLIGHT;
52}
53
54struct 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
79static int palmz71_panel_probe(struct platform_device *pdev)
80{
81 omapfb_register_panel(&palmz71_panel);
82 return 0;
83}
84
85static int palmz71_panel_remove(struct platform_device *pdev)
86{
87 return 0;
88}
89
90static int palmz71_panel_suspend(struct platform_device *pdev,
91 pm_message_t mesg)
92{
93 return 0;
94}
95
96static int palmz71_panel_resume(struct platform_device *pdev)
97{
98 return 0;
99}
100
101struct 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
112static int palmz71_panel_drv_init(void)
113{
114 return platform_driver_register(&palmz71_panel_driver);
115}
116
117static void palmz71_panel_drv_cleanup(void)
118{
119 platform_driver_unregister(&palmz71_panel_driver);
120}
121
122module_init(palmz71_panel_drv_init);
123module_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
51const unsigned char INIT_1[12] = {
52 0x1C, 0x02, 0x88, 0x00, 0x1E, 0xE0, 0x00, 0xDC, 0x00, 0x02, 0x00
53};
54
55const 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
74const unsigned char INIT_3[15] = {
75 0x14, 0x26, 0x33, 0x3D, 0x45, 0x4D, 0x53, 0x59,
76 0x5E, 0x63, 0x67, 0x6D, 0x71, 0x78, 0xFF
77};
78
79static 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
101static void init_system(void)
102{
103 omap_mcbsp_request(OMAP_MCBSP3);
104 omap_mcbsp_stop(OMAP_MCBSP3);
105}
106
107static 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
131static 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
221static int sx1_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev)
222{
223 return 0;
224}
225
226static void sx1_panel_cleanup(struct lcd_panel *panel)
227{
228}
229
230static 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
248static 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
261static unsigned long sx1_panel_get_caps(struct lcd_panel *panel)
262{
263 return 0;
264}
265
266struct 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
291static int sx1_panel_probe(struct platform_device *pdev)
292{
293 omapfb_register_panel(&sx1_panel);
294 return 0;
295}
296
297static int sx1_panel_remove(struct platform_device *pdev)
298{
299 return 0;
300}
301
302static int sx1_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
303{
304 return 0;
305}
306
307static int sx1_panel_resume(struct platform_device *pdev)
308{
309 return 0;
310}
311
312struct 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
323static int sx1_panel_drv_init(void)
324{
325 return platform_driver_register(&sx1_panel_driver);
326}
327
328static void sx1_panel_drv_cleanup(void)
329{
330 platform_driver_unregister(&sx1_panel_driver);
331}
332
333module_init(sx1_panel_drv_init);
334module_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
73enum lcdc_load_mode {
74 OMAP_LCDC_LOAD_PALETTE,
75 OMAP_LCDC_LOAD_FRAME,
76 OMAP_LCDC_LOAD_PALETTE_AND_FRAME
77};
78
79static 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
110static void inline enable_irqs(int mask)
111{
112 lcdc.irq_mask |= mask;
113}
114
115static void inline disable_irqs(int mask)
116{
117 lcdc.irq_mask &= ~mask;
118}
119
120static 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
141static 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
152static 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
168static 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
177static 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 */
203static 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
269static 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 */
319static 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
406static 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 */
422static 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 */
452static 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
478static 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
497static 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 */
562static 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
594static 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 */
600static 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
608static 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
620static void omap_lcdc_get_caps(int plane, struct omapfb_caps *caps)
621{
622 return;
623}
624
625int 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}
637EXPORT_SYMBOL(omap_lcdc_set_dma_callback);
638
639void omap_lcdc_free_dma_callback(void)
640{
641 lcdc.dma_callback = NULL;
642}
643EXPORT_SYMBOL(omap_lcdc_free_dma_callback);
644
645static void lcdc_dma_handler(u16 status, void *data)
646{
647 if (lcdc.dma_callback)
648 lcdc.dma_callback(lcdc.dma_callback_data);
649}
650
651static 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
682static void unmap_kern(void)
683{
684 vunmap(lcdc.vram_virt);
685}
686
687static 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
700static 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
706static 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
735static void free_fbmem(void)
736{
737 dma_free_writecombine(lcdc.fbdev->dev, lcdc.vram_size,
738 lcdc.vram_virt, lcdc.vram_phys);
739}
740
741static 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
774static void cleanup_fbmem(void)
775{
776 if (lcdc.fbmem_allocated)
777 free_fbmem();
778 else
779 unmap_kern();
780}
781
782static 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;
854fail5:
855 if (!ext_mode)
856 free_palette_ram();
857fail4:
858 omap_free_lcd_dma();
859fail3:
860 free_irq(OMAP_LCDC_IRQ, lcdc.fbdev);
861fail2:
862 clk_disable(lcdc.lcd_ck);
863fail1:
864 clk_put(lcdc.lcd_ck);
865fail0:
866 return r;
867}
868
869static 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
880const 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
4int omap_lcdc_set_dma_callback(void (*callback)(void *data), void *data);
5void 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
36static unsigned int def_accel;
37static unsigned long def_vram[OMAPFB_PLANE_NUM];
38static int def_vram_cnt;
39static unsigned long def_vxres;
40static unsigned long def_vyres;
41static unsigned int def_rotate;
42static unsigned int def_mirror;
43
44#ifdef CONFIG_FB_OMAP_MANUAL_UPDATE
45static int manual_update = 1;
46#else
47static int manual_update;
48#endif
49
50static struct platform_device *fbdev_pdev;
51static struct lcd_panel *fbdev_panel;
52static struct omapfb_device *omapfb_dev;
53
54struct caps_table_struct {
55 unsigned long flag;
56 const char *name;
57};
58
59static 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
70static 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 */
87extern struct lcd_ctrl omap1_int_ctrl;
88extern struct lcd_ctrl omap2_int_ctrl;
89extern struct lcd_ctrl hwa742_ctrl;
90extern struct lcd_ctrl blizzard_ctrl;
91
92static 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
109extern struct lcd_ctrl_extif omap1_ext_if;
110#else
111extern struct lcd_ctrl_extif omap2_ext_if;
112#endif
113#endif
114
115static void omapfb_rqueue_lock(struct omapfb_device *fbdev)
116{
117 mutex_lock(&fbdev->rqueue_mutex);
118}
119
120static 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. */
131static 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 */
145static 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
194static void ctrl_cleanup(struct omapfb_device *fbdev)
195{
196 fbdev->ctrl->cleanup();
197}
198
199/* Must be called with fbdev->rqueue_mutex held. */
200static 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 */
232static int omapfb_open(struct fb_info *info, int user)
233{
234 return 0;
235}
236
237static 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. */
241static 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 */
251static 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
299static 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
305static 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
329static int omapfb_update_full_screen(struct fb_info *fbi);
330
331static 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
370static 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 */
385static 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
420static 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 */
471static 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. */
594static 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 */
618static 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. */
646static 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 */
669static 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 */
688static 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
702int 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}
734EXPORT_SYMBOL(omapfb_update_window_async);
735
736static 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
749static 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
777static 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 }
812out:
813 omapfb_rqueue_unlock(fbdev);
814 return r;
815}
816
817static 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
825static 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 }
893out:
894 omapfb_rqueue_unlock(fbdev);
895
896 return r;
897}
898
899static 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
913static 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
928static 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
943static struct blocking_notifier_head omapfb_client_list[OMAPFB_PLANE_NUM];
944static int notifier_inited;
945
946static 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
954int 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}
983EXPORT_SYMBOL(omapfb_register_client);
984
985int 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}
990EXPORT_SYMBOL(omapfb_unregister_client);
991
992void 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}
1004EXPORT_SYMBOL(omapfb_notify_clients);
1005
1006static 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
1018static 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
1029static 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 */
1038void 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}
1054EXPORT_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 */
1060static 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
1209static 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 */
1226static 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 */
1249static 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
1269static 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
1312static DEVICE_ATTR(caps_num, 0444, omapfb_show_caps_num, NULL);
1313static DEVICE_ATTR(caps_text, 0444, omapfb_show_caps_text, NULL);
1314
1315/* panel sysfs entries */
1316static 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
1324static 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
1339static 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
1359static 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
1373static struct device_attribute dev_attr_panel_name =
1374 __ATTR(name, 0444, omapfb_show_panel_name, NULL);
1375static DEVICE_ATTR(backlight_level, 0664,
1376 omapfb_show_bklight_level, omapfb_store_bklight_level);
1377static DEVICE_ATTR(backlight_max, 0444, omapfb_show_bklight_max, NULL);
1378
1379static 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
1386static struct attribute_group panel_attr_grp = {
1387 .name = "panel",
1388 .attrs = panel_attrs,
1389};
1390
1391/* ctrl sysfs entries */
1392static 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
1400static struct device_attribute dev_attr_ctrl_name =
1401 __ATTR(name, 0444, omapfb_show_ctrl_name, NULL);
1402
1403static struct attribute *ctrl_attrs[] = {
1404 &dev_attr_ctrl_name.attr,
1405 NULL,
1406};
1407
1408static struct attribute_group ctrl_attr_grp = {
1409 .name = "ctrl",
1410 .attrs = ctrl_attrs,
1411};
1412
1413static 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;
1430fail3:
1431 sysfs_remove_group(&fbdev->dev->kobj, &panel_attr_grp);
1432fail2:
1433 device_remove_file(fbdev->dev, &dev_attr_caps_text);
1434fail1:
1435 device_remove_file(fbdev->dev, &dev_attr_caps_num);
1436fail0:
1437 dev_err(fbdev->dev, "unable to register sysfs interface\n");
1438 return r;
1439}
1440
1441static 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 */
1457static 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 */
1489static void fbinfo_cleanup(struct omapfb_device *fbdev, struct fb_info *fbi)
1490{
1491 fb_dealloc_cmap(&fbi->cmap);
1492}
1493
1494static 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
1506static 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 */
1543static 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
1574static 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
1608static 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 */
1634static 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
1775cleanup:
1776 omapfb_free_resources(fbdev, init_state);
1777
1778 return r;
1779}
1780
1781static 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
1792void 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 */
1802static 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 */
1816static 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 */
1826static 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
1834static 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 */
1848static 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 */
1905static 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
1923static void __exit omapfb_cleanup(void)
1924{
1925 platform_driver_unregister(&omapfb_driver);
1926}
1927
1928module_param_named(accel, def_accel, uint, 0664);
1929module_param_array_named(vram, def_vram, ulong, &def_vram_cnt, 0664);
1930module_param_named(vxres, def_vxres, long, 0664);
1931module_param_named(vyres, def_vyres, long, 0664);
1932module_param_named(rotate, def_rotate, uint, 0664);
1933module_param_named(mirror, def_mirror, uint, 0664);
1934module_param_named(manual_update, manual_update, bool, 0664);
1935
1936module_init(omapfb_init);
1937module_exit(omapfb_cleanup);
1938
1939MODULE_DESCRIPTION("TI OMAP framebuffer driver");
1940MODULE_AUTHOR("Imre Deak <imre.deak@nokia.com>");
1941MODULE_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
61static 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
74static inline void rfbi_write_reg(int idx, u32 val)
75{
76 __raw_writel(val, rfbi.base + idx);
77}
78
79static inline u32 rfbi_read_reg(int idx)
80{
81 return __raw_readl(rfbi.base + idx);
82}
83
84static 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
100static void rfbi_put_clocks(void)
101{
102 clk_put(rfbi.dss1_fck);
103 clk_put(rfbi.dss_ick);
104}
105
106static 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
119static 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
145static void rfbi_print_timings(void) {}
146#endif
147
148static 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
167static 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
173static 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
187static 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
234static int rfbi_get_max_tx_rate(void)
235{
236 return rfbi.l4_khz * 1000;
237}
238#endif
239
240
241static 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
329static 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
375static 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
399static 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
416static 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
437static 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
454static 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
478static 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
487static void rfbi_dma_callback(void *data)
488{
489 _stop_transfer();
490 rfbi.lcdc_callback(rfbi.lcdc_callback_data);
491}
492
493static 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
515static 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
565static void rfbi_cleanup(void)
566{
567 omap_dispc_free_irq();
568 rfbi_put_clocks();
569}
570
571const 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
57static 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
82static inline u32 sossi_read_reg(int reg)
83{
84 return readl(sossi.base + reg);
85}
86
87static inline u16 sossi_read_reg16(int reg)
88{
89 return readw(sossi.base + reg);
90}
91
92static inline u8 sossi_read_reg8(int reg)
93{
94 return readb(sossi.base + reg);
95}
96
97static inline void sossi_write_reg(int reg, u32 value)
98{
99 writel(value, sossi.base + reg);
100}
101
102static inline void sossi_write_reg16(int reg, u16 value)
103{
104 writew(value, sossi.base + reg);
105}
106
107static inline void sossi_write_reg8(int reg, u8 value)
108{
109 writeb(value, sossi.base + reg);
110}
111
112static void sossi_set_bits(int reg, u32 bits)
113{
114 sossi_write_reg(reg, sossi_read_reg(reg) | bits);
115}
116
117static 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
124static 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
130static 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
181static 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
220static 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
238static 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
248static 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
264static 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
273static 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
281static 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
289static 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
295static 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
314static 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
324static 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
348static 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
361static 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
367static 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
393static 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
437static 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
457static 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
472static 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
487static 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
521static 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
529static 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
557static 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
570static 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
658err:
659 clk_disable(sossi.fck);
660 clk_put(sossi.fck);
661 return r;
662}
663
664static void sossi_cleanup(void)
665{
666 omap_lcdc_free_dma_callback();
667 clk_put(sossi.fck);
668}
669
670struct 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 */
63static char *mode __devinitdata = NULL; 63static 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 */
97static struct fb_fix_screeninfo pm2fb_fix __devinitdata = { 97static 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 */
110static struct fb_var_screeninfo pm2fb_var __devinitdata = { 110static 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
202static inline void WAIT_FIFO(struct pm2fb_par* p, u32 a) 202static 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))
213static const struct { 213static 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)
357static void reset_config(struct pm2fb_par* p) 357static 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 */
868static int pm2fb_setcolreg(unsigned regno, unsigned red, unsigned green, 868static 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 */
970static int pm2fb_pan_display(struct fb_var_screeninfo *var, 970static 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 */
1003static int pm2fb_blank(int blank_mode, struct fb_info *info) 1003static 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
1403static struct pci_driver pm2fb_driver = { 1403static 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
1410MODULE_DEVICE_TABLE(pci, pm2fb_id_table); 1410MODULE_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 */
189static 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
205static 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
360static 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 */
189static void pm3fb_write_mode(struct fb_info *info) 421static 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 */
383int pm3fb_init(void);
384
385static int pm3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) 615static 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
936MODULE_DEVICE_TABLE(pci, pm3fb_id_table); 1169MODULE_DEVICE_TABLE(pci, pm3fb_id_table);
937 1170
938#ifndef MODULE 1171static 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 */
947static int __init pm3fb_setup(char *options)
948{ 1172{
949 /* Parse user speficied options (`video=pm3fb:') */
950 return 0;
951}
952#endif /* MODULE */
953
954int __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
127struct ps3fb_priv { 129struct 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
176static const struct fb_videomode ps3fb_modedb[] = { 177static 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
300static int ps3fb_mode; 301static int ps3fb_mode;
301module_param(ps3fb_mode, bool, 0); 302module_param(ps3fb_mode, int, 0);
302
303static char *mode_option __initdata;
304 303
304static char *mode_option __devinitdata;
305 305
306static int ps3fb_get_res_table(u32 xres, u32 yres) 306static int ps3fb_get_res_table(u32 xres, u32 yres)
307{ 307{
@@ -681,15 +681,15 @@ int ps3fb_wait_for_vsync(u32 crtc)
681 681
682EXPORT_SYMBOL_GPL(ps3fb_wait_for_vsync); 682EXPORT_SYMBOL_GPL(ps3fb_wait_for_vsync);
683 683
684void ps3fb_flip_ctl(int on) 684void 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
692EXPORT_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
813static int ps3fbd(void *arg) 813static 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
855static 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
879static void ps3fb_platform_release(struct device *device) 856static 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
884static 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
968static struct fb_fix_screeninfo ps3fb_fix __initdata = { 940static 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
975static int __init ps3fb_probe(struct platform_device *dev) 947static 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
975static 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:
1084err_framebuffer_release: 1110err_framebuffer_release:
1085 framebuffer_release(info); 1111 framebuffer_release(info);
1086err_free_irq: 1112err_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);
1089err_iounmap_dinfo: 1115err_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
1099static void ps3fb_shutdown(struct platform_device *dev) 1125static 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
1108void 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
1134EXPORT_SYMBOL_GPL(ps3fb_cleanup);
1135
1136static 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
1149static struct platform_driver ps3fb_driver = { 1167static 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,
1156static struct platform_device ps3fb_device = {
1157 .name = "ps3fb",
1158 .id = 0,
1159 .dev = { .release = ps3fb_platform_release }
1160}; 1174};
1161 1175
1162int ps3fb_set_sync(void) 1176static 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
1192EXPORT_SYMBOL_GPL(ps3fb_set_sync);
1193
1194static 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(); 1205static int __init ps3fb_init(void)
1242 1206{
1243 return error; 1207 if (!ps3fb_videomemory.address || ps3fb_setup())
1208 return -ENXIO;
1244 1209
1245err: 1210 return ps3_system_bus_driver_register(&ps3fb_driver);
1246 return -ENXIO;
1247} 1211}
1248 1212
1249module_init(ps3fb_init);
1250
1251#ifdef MODULE
1252static void __exit ps3fb_exit(void) 1213static 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
1220module_init(ps3fb_init);
1258module_exit(ps3fb_exit); 1221module_exit(ps3fb_exit);
1259 1222
1260MODULE_LICENSE("GPL"); 1223MODULE_LICENSE("GPL");
1261#endif /* MODULE */ 1224MODULE_DESCRIPTION("PS3 GPU Frame Buffer Driver");
1225MODULE_AUTHOR("Sony Computer Entertainment Inc.");
1226MODULE_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 };
115enum { PAL_ARGB1555, PAL_RGB565, PAL_ARGB4444, PAL_ARGB8888 }; 115enum { PAL_ARGB1555, PAL_RGB565, PAL_ARGB4444, PAL_ARGB8888 };
116 116
117struct pvr2_params { unsigned int val; char *name; }; 117struct pvr2_params { unsigned int val; char *name; };
118static struct pvr2_params cables[] __initdata = { 118static 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
122static struct pvr2_params outputs[] __initdata = { 122static 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
148static struct fb_info *fb_info; 148static struct fb_info *fb_info;
149 149
150static struct fb_fix_screeninfo pvr2_fix __initdata = { 150static 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
159static struct fb_var_screeninfo pvr2_var __initdata = { 159static 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;
195static unsigned int pvr2dma = ONCHIP_NR_DMA_CHANNELS; 195static unsigned int pvr2dma = ONCHIP_NR_DMA_CHANNELS;
196#endif 196#endif
197 197
198/* Interface used by the world */
199
200int pvr2fb_setup(char*);
201
202static int pvr2fb_setcolreg(unsigned int regno, unsigned int red, unsigned int green, unsigned int blue, 198static 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);
204static int pvr2fb_blank(int blank, struct fb_info *info); 200static 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
235static struct fb_videomode pvr2_modedb[] __initdata = { 231static 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
264static int defmode = DEFMODE_NTSC; 260static int defmode = DEFMODE_NTSC;
265static char *mode_option __initdata = NULL; 261static char *mode_option __devinitdata = NULL;
266 262
267static inline void pvr2fb_set_pal_type(unsigned int type) 263static 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)
657static int pvr2_init_cable(void) 654static 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(&current->mm->mmap_sem); 688 down_read(&current->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 */
768static int __init pvr2fb_common_init(void) 765static 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
906static void pvr2fb_dc_exit(void) 903static 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
990static void pvr2fb_pci_exit(void) 987static 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
996static int __init pvr2_get_param(const struct pvr2_params *p, const char *s, 993static 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
1024int __init pvr2fb_setup(char *options) 1021static 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
1074int __init pvr2fb_init(void) 1071static 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);
1139MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>, M. R. Brown <mrbrown@0xd6.org>"); 1135MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>, M. R. Brown <mrbrown@0xd6.org>");
1140MODULE_DESCRIPTION("Framebuffer driver for NEC PowerVR 2 based graphics boards"); 1136MODULE_DESCRIPTION("Framebuffer driver for NEC PowerVR 2 based graphics boards");
1141MODULE_LICENSE("GPL"); 1137MODULE_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
2149static int __init rivafb_setup(char *options) 2149static 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
71struct vga_regset vt8623_h_total_regs[] = {{0x00, 0, 7}, {0x36, 3, 3}, VGA_REGSET_END}; 71static struct vga_regset vt8623_h_total_regs[] = {{0x00, 0, 7}, {0x36, 3, 3}, VGA_REGSET_END};
72struct vga_regset vt8623_h_display_regs[] = {{0x01, 0, 7}, VGA_REGSET_END}; 72static struct vga_regset vt8623_h_display_regs[] = {{0x01, 0, 7}, VGA_REGSET_END};
73struct vga_regset vt8623_h_blank_start_regs[] = {{0x02, 0, 7}, VGA_REGSET_END}; 73static struct vga_regset vt8623_h_blank_start_regs[] = {{0x02, 0, 7}, VGA_REGSET_END};
74struct vga_regset vt8623_h_blank_end_regs[] = {{0x03, 0, 4}, {0x05, 7, 7}, {0x33, 5, 5}, VGA_REGSET_END}; 74static struct vga_regset vt8623_h_blank_end_regs[] = {{0x03, 0, 4}, {0x05, 7, 7}, {0x33, 5, 5}, VGA_REGSET_END};
75struct vga_regset vt8623_h_sync_start_regs[] = {{0x04, 0, 7}, {0x33, 4, 4}, VGA_REGSET_END}; 75static struct vga_regset vt8623_h_sync_start_regs[] = {{0x04, 0, 7}, {0x33, 4, 4}, VGA_REGSET_END};
76struct vga_regset vt8623_h_sync_end_regs[] = {{0x05, 0, 4}, VGA_REGSET_END}; 76static struct vga_regset vt8623_h_sync_end_regs[] = {{0x05, 0, 4}, VGA_REGSET_END};
77 77
78struct vga_regset vt8623_v_total_regs[] = {{0x06, 0, 7}, {0x07, 0, 0}, {0x07, 5, 5}, {0x35, 0, 0}, VGA_REGSET_END}; 78static struct vga_regset vt8623_v_total_regs[] = {{0x06, 0, 7}, {0x07, 0, 0}, {0x07, 5, 5}, {0x35, 0, 0}, VGA_REGSET_END};
79struct vga_regset vt8623_v_display_regs[] = {{0x12, 0, 7}, {0x07, 1, 1}, {0x07, 6, 6}, {0x35, 2, 2}, VGA_REGSET_END}; 79static struct vga_regset vt8623_v_display_regs[] = {{0x12, 0, 7}, {0x07, 1, 1}, {0x07, 6, 6}, {0x35, 2, 2}, VGA_REGSET_END};
80struct vga_regset vt8623_v_blank_start_regs[] = {{0x15, 0, 7}, {0x07, 3, 3}, {0x09, 5, 5}, {0x35, 3, 3}, VGA_REGSET_END}; 80static struct vga_regset vt8623_v_blank_start_regs[] = {{0x15, 0, 7}, {0x07, 3, 3}, {0x09, 5, 5}, {0x35, 3, 3}, VGA_REGSET_END};
81struct vga_regset vt8623_v_blank_end_regs[] = {{0x16, 0, 7}, VGA_REGSET_END}; 81static struct vga_regset vt8623_v_blank_end_regs[] = {{0x16, 0, 7}, VGA_REGSET_END};
82struct vga_regset vt8623_v_sync_start_regs[] = {{0x10, 0, 7}, {0x07, 2, 2}, {0x07, 7, 7}, {0x35, 1, 1}, VGA_REGSET_END}; 82static struct vga_regset vt8623_v_sync_start_regs[] = {{0x10, 0, 7}, {0x07, 2, 2}, {0x07, 7, 7}, {0x35, 1, 1}, VGA_REGSET_END};
83struct vga_regset vt8623_v_sync_end_regs[] = {{0x11, 0, 3}, VGA_REGSET_END}; 83static struct vga_regset vt8623_v_sync_end_regs[] = {{0x11, 0, 3}, VGA_REGSET_END};
84 84
85struct vga_regset vt8623_offset_regs[] = {{0x13, 0, 7}, {0x35, 5, 7}, VGA_REGSET_END}; 85static struct vga_regset vt8623_offset_regs[] = {{0x13, 0, 7}, {0x35, 5, 7}, VGA_REGSET_END};
86struct vga_regset vt8623_line_compare_regs[] = {{0x18, 0, 7}, {0x07, 4, 4}, {0x09, 6, 6}, {0x33, 0, 2}, {0x35, 4, 4}, VGA_REGSET_END}; 86static 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};
87struct vga_regset vt8623_fetch_count_regs[] = {{0x1C, 0, 7}, {0x1D, 0, 1}, VGA_REGSET_END}; 87static struct vga_regset vt8623_fetch_count_regs[] = {{0x1C, 0, 7}, {0x1D, 0, 1}, VGA_REGSET_END};
88struct vga_regset vt8623_start_address_regs[] = {{0x0d, 0, 7}, {0x0c, 0, 7}, {0x34, 0, 7}, {0x48, 0, 1}, VGA_REGSET_END}; 88static struct vga_regset vt8623_start_address_regs[] = {{0x0d, 0, 7}, {0x0c, 0, 7}, {0x34, 0, 7}, {0x48, 0, 1}, VGA_REGSET_END};
89 89
90struct svga_timing_regs vt8623_timing_regs = { 90static 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
906int __init vt8623fb_init(void) 906static int __init vt8623fb_init(void)
907{ 907{
908 908
909#ifndef MODULE 909#ifndef MODULE