[ARM] 3848/1: pxafb: Add option of fixing video modes and spitz QVGA mode support

Add the ability to have pxafb use only certain fixed video modes
(selected on a per platform basis). This is useful on production
hardware such as the Zaurus cxx00 models where the valid modes are
known in advance and any other modes could result in hardware damage.

Following this, add support for the cxx00 QVGA mode. Mode information
is passed to the lcd_power call to allowing the panel drivers to
configure the display hardware accordingly (corgi_lcd already contains
the functionality for the cxx00 panel).

This mirrors the setup already used by w100fb.

Signed-off-by: Richard Purdie <rpurdie@rpsys.net>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
diff --git a/arch/arm/mach-pxa/corgi_lcd.c b/arch/arm/mach-pxa/corgi_lcd.c
index 6dbcaf1..d781549 100644
--- a/arch/arm/mach-pxa/corgi_lcd.c
+++ b/arch/arm/mach-pxa/corgi_lcd.c
@@ -431,10 +431,10 @@
 
 #include <asm/arch/pxafb.h>
 
-void spitz_lcd_power(int on)
+void spitz_lcd_power(int on, struct fb_var_screeninfo *var)
 {
 	if (on)
-		lcdtg_hw_init(480);
+		lcdtg_hw_init(var->xres);
 	else
 		lcdtg_suspend();
 }
diff --git a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c
index 5efa847..45fb2c3 100644
--- a/arch/arm/mach-pxa/generic.c
+++ b/arch/arm/mach-pxa/generic.c
@@ -204,13 +204,6 @@
 	}
 };
 
-static struct pxafb_mach_info pxa_fb_info;
-
-void __init set_pxa_fb_info(struct pxafb_mach_info *hard_pxa_fb_info)
-{
-	memcpy(&pxa_fb_info,hard_pxa_fb_info,sizeof(struct pxafb_mach_info));
-}
-
 static struct resource pxafb_resources[] = {
 	[0] = {
 		.start	= 0x44000000,
@@ -230,7 +223,6 @@
 	.name		= "pxa2xx-fb",
 	.id		= -1,
 	.dev		= {
- 		.platform_data	= &pxa_fb_info,
 		.dma_mask	= &fb_dma_mask,
 		.coherent_dma_mask = 0xffffffff,
 	},
@@ -238,6 +230,11 @@
 	.resource	= pxafb_resources,
 };
 
+void __init set_pxa_fb_info(struct pxafb_mach_info *info)
+{
+	pxafb_device.dev.platform_data = info;
+}
+
 void __init set_pxa_fb_parent(struct device *parent_dev)
 {
 	pxafb_device.dev.parent = parent_dev;
diff --git a/arch/arm/mach-pxa/idp.c b/arch/arm/mach-pxa/idp.c
index 6914d22..3e4b0ab 100644
--- a/arch/arm/mach-pxa/idp.c
+++ b/arch/arm/mach-pxa/idp.c
@@ -82,7 +82,7 @@
 	}
 }
 
-static void idp_lcd_power(int on)
+static void idp_lcd_power(int on, struct fb_var_screeninfo *var)
 {
 	if (on) {
 		IDP_CPLD_LCD |= (1<<0);
@@ -99,7 +99,7 @@
 	idp_vlcd(on);
 }
 
-static struct pxafb_mach_info sharp_lm8v31 __initdata = {
+static struct pxafb_mode_info sharp_lm8v31_mode = {
 	.pixclock	= 270000,
 	.xres		= 640,
 	.yres		= 480,
@@ -112,6 +112,11 @@
 	.lower_margin	= 0,
 	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 	.cmap_greyscale	= 0,
+};
+
+static struct pxafb_mach_info sharp_lm8v31 = {
+	.modes          = &sharp_lm8v31_mode,
+	.num_modes      = 1,
 	.cmap_inverse	= 0,
 	.cmap_static	= 0,
 	.lccr0		= LCCR0_SDS,
diff --git a/arch/arm/mach-pxa/lpd270.c b/arch/arm/mach-pxa/lpd270.c
index 12479ae..eff2a91 100644
--- a/arch/arm/mach-pxa/lpd270.c
+++ b/arch/arm/mach-pxa/lpd270.c
@@ -248,7 +248,7 @@
 }
 
 /* 5.7" TFT QVGA (LoLo display number 1) */
-static struct pxafb_mach_info sharp_lq057q3dc02 __initdata = {
+static struct pxafb_mode_info sharp_lq057q3dc02_mode = {
 	.pixclock		= 150000,
 	.xres			= 320,
 	.yres			= 240,
@@ -260,13 +260,18 @@
 	.upper_margin		= 0x08,
 	.lower_margin		= 0x14,
 	.sync			= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+};
+
+static struct pxafb_mach_info sharp_lq057q3dc02 = {
+	.modes			= &sharp_lq057q3dc02_mode,
+	.num_modes		= 1,
 	.lccr0			= 0x07800080,
 	.lccr3			= 0x00400000,
 	.pxafb_backlight_power	= lpd270_backlight_power,
 };
 
 /* 12.1" TFT SVGA (LoLo display number 2) */
-static struct pxafb_mach_info sharp_lq121s1dg31 __initdata = {
+static struct pxafb_mode_info sharp_lq121s1dg31_mode = {
 	.pixclock		= 50000,
 	.xres			= 800,
 	.yres			= 600,
@@ -278,13 +283,18 @@
 	.upper_margin		= 0x14,
 	.lower_margin		= 0x0a,
 	.sync			= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+};
+
+static struct pxafb_mach_info sharp_lq121s1dg31 = {
+	.modes			= &sharp_lq121s1dg31_mode,
+	.num_modes		= 1,
 	.lccr0			= 0x07800080,
 	.lccr3			= 0x00400000,
 	.pxafb_backlight_power	= lpd270_backlight_power,
 };
 
 /* 3.6" TFT QVGA (LoLo display number 3) */
-static struct pxafb_mach_info sharp_lq036q1da01 __initdata = {
+static struct pxafb_mode_info sharp_lq036q1da01_mode = {
 	.pixclock		= 150000,
 	.xres			= 320,
 	.yres			= 240,
@@ -296,13 +306,18 @@
 	.upper_margin		= 0x03,
 	.lower_margin		= 0x03,
 	.sync			= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+};
+
+static struct pxafb_mach_info sharp_lq036q1da01 = {
+	.modes			= &sharp_lq036q1da01_mode,
+	.num_modes		= 1,
 	.lccr0			= 0x07800080,
 	.lccr3			= 0x00400000,
 	.pxafb_backlight_power	= lpd270_backlight_power,
 };
 
 /* 6.4" TFT VGA (LoLo display number 5) */
-static struct pxafb_mach_info sharp_lq64d343 __initdata = {
+static struct pxafb_mode_info sharp_lq64d343_mode = {
 	.pixclock		= 25000,
 	.xres			= 640,
 	.yres			= 480,
@@ -314,13 +329,18 @@
 	.upper_margin		= 0x22,
 	.lower_margin		= 0x00,
 	.sync			= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+};
+
+static struct pxafb_mach_info sharp_lq64d343 = {
+	.modes			= &sharp_lq64d343_mode,
+	.num_modes		= 1,
 	.lccr0			= 0x07800080,
 	.lccr3			= 0x00400000,
 	.pxafb_backlight_power	= lpd270_backlight_power,
 };
 
 /* 10.4" TFT VGA (LoLo display number 7) */
-static struct pxafb_mach_info sharp_lq10d368 __initdata = {
+static struct pxafb_mode_info sharp_lq10d368_mode = {
 	.pixclock		= 25000,
 	.xres			= 640,
 	.yres			= 480,
@@ -332,13 +352,18 @@
 	.upper_margin		= 0x22,
 	.lower_margin		= 0x00,
 	.sync			= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+};
+
+static struct pxafb_mach_info sharp_lq10d368 = {
+	.modes			= &sharp_lq10d368_mode,
+	.num_modes		= 1,
 	.lccr0			= 0x07800080,
 	.lccr3			= 0x00400000,
 	.pxafb_backlight_power	= lpd270_backlight_power,
 };
 
 /* 3.5" TFT QVGA (LoLo display number 8) */
-static struct pxafb_mach_info sharp_lq035q7db02_20 __initdata = {
+static struct pxafb_mode_info sharp_lq035q7db02_20_mode = {
 	.pixclock		= 150000,
 	.xres			= 240,
 	.yres			= 320,
@@ -350,6 +375,11 @@
 	.upper_margin		= 0x05,
 	.lower_margin		= 0x14,
 	.sync			= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+};
+
+static struct pxafb_mach_info sharp_lq035q7db02_20 = {
+	.modes			= &sharp_lq035q7db02_20_mode,
+	.num_modes		= 1,
 	.lccr0			= 0x07800080,
 	.lccr3			= 0x00400000,
 	.pxafb_backlight_power	= lpd270_backlight_power,
diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c
index 83ff5ce..157cf47 100644
--- a/arch/arm/mach-pxa/lubbock.c
+++ b/arch/arm/mach-pxa/lubbock.c
@@ -352,7 +352,7 @@
 	&pxa_ssp,
 };
 
-static struct pxafb_mach_info sharp_lm8v31 __initdata = {
+static struct pxafb_mode_info sharp_lm8v31_mode = {
 	.pixclock	= 270000,
 	.xres		= 640,
 	.yres		= 480,
@@ -365,6 +365,11 @@
 	.lower_margin	= 0,
 	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 	.cmap_greyscale	= 0,
+};
+
+static struct pxafb_mach_info sharp_lm8v31 = {
+	.modes		= &sharp_lm8v31_mode,
+	.num_modes	= 1,
 	.cmap_inverse	= 0,
 	.cmap_static	= 0,
 	.lccr0		= LCCR0_SDS,
diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c
index a7e9b96..7ba0447 100644
--- a/arch/arm/mach-pxa/mainstone.c
+++ b/arch/arm/mach-pxa/mainstone.c
@@ -279,7 +279,7 @@
 	}
 }
 
-static struct pxafb_mach_info toshiba_ltm04c380k __initdata = {
+static struct pxafb_mode_info toshiba_ltm04c380k_mode = {
 	.pixclock		= 50000,
 	.xres			= 640,
 	.yres			= 480,
@@ -291,12 +291,9 @@
 	.upper_margin		= 0,
 	.lower_margin		= 0,
 	.sync			= FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
-	.lccr0			= LCCR0_Act,
-	.lccr3			= LCCR3_PCP,
-	.pxafb_backlight_power	= mainstone_backlight_power,
 };
 
-static struct pxafb_mach_info toshiba_ltm035a776c __initdata = {
+static struct pxafb_mode_info toshiba_ltm035a776c_mode = {
 	.pixclock		= 110000,
 	.xres			= 240,
 	.yres			= 320,
@@ -308,6 +305,10 @@
 	.upper_margin		= 1,
 	.lower_margin		= 10,
 	.sync			= FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
+};
+
+static struct pxafb_mach_info mainstone_pxafb_info = {
+	.num_modes      	= 1,
 	.lccr0			= LCCR0_Act,
 	.lccr3			= LCCR3_PCP,
 	.pxafb_backlight_power	= mainstone_backlight_power,
@@ -448,9 +449,11 @@
 	/* reading Mainstone's "Virtual Configuration Register"
 	   might be handy to select LCD type here */
 	if (0)
-		set_pxa_fb_info(&toshiba_ltm04c380k);
+		mainstone_pxafb_info.modes = &toshiba_ltm04c380k_mode;
 	else
-		set_pxa_fb_info(&toshiba_ltm035a776c);
+		mainstone_pxafb_info.modes = &toshiba_ltm035a776c_mode;
+
+	set_pxa_fb_info(&mainstone_pxafb_info);
 
 	pxa_set_mci_info(&mainstone_mci_platform_data);
 	pxa_set_ficp_info(&mainstone_ficp_platform_data);
diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c
index 6dbff6d..5e8c098 100644
--- a/arch/arm/mach-pxa/poodle.c
+++ b/arch/arm/mach-pxa/poodle.c
@@ -296,27 +296,25 @@
 
 
 /* PXAFB device */
-static struct pxafb_mach_info poodle_fb_info __initdata = {
+static struct pxafb_mode_info poodle_fb_mode = {
 	.pixclock	= 144700,
-
 	.xres		= 320,
 	.yres		= 240,
 	.bpp		= 16,
-
 	.hsync_len	= 7,
 	.left_margin	= 11,
 	.right_margin	= 30,
-
 	.vsync_len	= 2,
 	.upper_margin	= 2,
 	.lower_margin	= 0,
 	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+};
 
+static struct pxafb_mach_info poodle_fb_info = {
+	.modes		= &poodle_fb_mode,
+	.num_modes	= 1,
 	.lccr0		= LCCR0_Act | LCCR0_Sngl | LCCR0_Color,
 	.lccr3		= 0,
-
-	.pxafb_backlight_power	= NULL,
-	.pxafb_lcd_power	= NULL,
 };
 
 static struct platform_device *devices[] __initdata = {
diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c
index 1c32a93..401cdb8 100644
--- a/arch/arm/mach-pxa/spitz.c
+++ b/arch/arm/mach-pxa/spitz.c
@@ -407,21 +407,42 @@
 /*
  * Spitz PXA Framebuffer
  */
-static struct pxafb_mach_info spitz_pxafb_info __initdata = {
-        .pixclock       = 19231,
-        .xres           = 480,
-        .yres           = 640,
-        .bpp            = 16,
-        .hsync_len      = 40,
-        .left_margin    = 46,
-        .right_margin   = 125,
-        .vsync_len      = 3,
-        .upper_margin   = 1,
-        .lower_margin   = 0,
-        .sync           = 0,
-        .lccr0          = LCCR0_Color | LCCR0_Sngl | LCCR0_Act | LCCR0_LDDALT | LCCR0_OUC | LCCR0_CMDIM | LCCR0_RDSTM,
-        .lccr3          = LCCR3_PixRsEdg | LCCR3_OutEnH,
-        .pxafb_lcd_power = spitz_lcd_power,
+
+static struct pxafb_mode_info spitz_pxafb_modes[] = {
+{
+	.pixclock       = 19231,
+	.xres           = 480,
+	.yres           = 640,
+	.bpp            = 16,
+	.hsync_len      = 40,
+	.left_margin    = 46,
+	.right_margin   = 125,
+	.vsync_len      = 3,
+	.upper_margin   = 1,
+	.lower_margin   = 0,
+	.sync           = 0,
+},{
+	.pixclock       = 134617,
+	.xres           = 240,
+	.yres           = 320,
+	.bpp            = 16,
+	.hsync_len      = 20,
+	.left_margin    = 20,
+	.right_margin   = 46,
+	.vsync_len      = 2,
+	.upper_margin   = 1,
+	.lower_margin   = 0,
+	.sync           = 0,
+},
+};
+
+static struct pxafb_mach_info spitz_pxafb_info = {
+	.modes          = &spitz_pxafb_modes[0],
+	.num_modes      = 2,
+	.fixed_modes    = 1,
+	.lccr0          = LCCR0_Color | LCCR0_Sngl | LCCR0_Act | LCCR0_LDDALT | LCCR0_OUC | LCCR0_CMDIM | LCCR0_RDSTM,
+	.lccr3          = LCCR3_PixRsEdg | LCCR3_OutEnH,
+	.pxafb_lcd_power = spitz_lcd_power,
 };
 
 
diff --git a/arch/arm/mach-pxa/trizeps4.c b/arch/arm/mach-pxa/trizeps4.c
index 7c3007d..910571e 100644
--- a/arch/arm/mach-pxa/trizeps4.c
+++ b/arch/arm/mach-pxa/trizeps4.c
@@ -368,7 +368,7 @@
 	}
 };
 
-static struct pxafb_mach_info sharp_lcd __initdata = {
+static struct pxafb_mode_info sharp_lcd_mode = {
     .pixclock		= 78000,
     .xres		= 640,
     .yres		= 480,
@@ -381,6 +381,11 @@
     .lower_margin	= 0,
     .sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
     .cmap_greyscale	= 0,
+};
+
+static struct pxafb_mach_info sharp_lcd = {
+    .modes		= &sharp_lcd_mode,
+    .num_modes	= 1,
     .cmap_inverse	= 0,
     .cmap_static	= 0,
     .lccr0		= LCCR0_Color | LCCR0_Pas | LCCR0_Dual,