--- pxafb.old.c	2004-05-21 01:17:12.000000000 -0400
+++ pxafb.c	2004-05-21 17:06:16.000000000 -0400
@@ -15,17 +15,11 @@
  *
  *	linux-arm-kernel@lists.arm.linux.org.uk
  *
- *
- * Code Status:
- *
- * 2003/08/29: Joshua Wise <joshua@joshuawise.com>
- *	- Upported to kernel 2.6.
- * 2001/08/03: <cbrake@accelent.com>
- *      - Ported from SA1100 to PXA250
  */
 
 #include <linux/config.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/errno.h>
@@ -35,9 +29,9 @@
 #include <linux/fb.h>
 #include <linux/delay.h>
 #include <linux/init.h>
-#include <linux/notifier.h>
 #include <linux/ioport.h>
 #include <linux/cpufreq.h>
+#define DEBUG 0
 #include <linux/device.h>
 #include <linux/dma-mapping.h>
 #include <linux/lcd.h>
@@ -48,94 +42,47 @@
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 #include <asm/uaccess.h>
+#include <asm/arch/bitfield.h>
+#include <asm/arch/pxafb.h>
 
 /*
- * debugging?
- */
-#define DEBUG 0
-/*
  * Complain if VAR is out of range.
  */
-#define DEBUG_VAR 0
-
-#undef ASSABET_PAL_VIDEO
+#define DEBUG_VAR 1
 
 #include "pxafb.h"
 
-
 void (*pxafb_lcd_power)(int on);
 EXPORT_SYMBOL(pxafb_lcd_power);
 
 void (*pxafb_backlight_power)(int on);
 EXPORT_SYMBOL(pxafb_backlight_power);
 
-void (*pxafb_blank_helper)(int blank);
+void (*pxafb_blank_helper(int blank);
 EXPORT_SYMBOL(pxafb_blank_helper);
 
 extern void (*pxafb_backlight_power)(int on);
 extern void (*pxafb_lcd_power)(int on);
 
-extern unsigned int get_clk_frequency_khz(int info);
-
 /*
- * IMHO this looks wrong.  In 8BPP, length should be 8.
+ * Defining this is OK for consoles but it
+ * causes problems for windowing packages.
  */
-static struct pxafb_rgb rgb_8 = {
-	.red	= { .offset = 0,  .length = 4, },
-	.green	= { .offset = 0,  .length = 4, },
-	.blue	= { .offset = 0,  .length = 4, },
-	.transp	= { .offset = 0,  .length = 0, },
-};
+#undef BLANKING_SET_PALETTE
 
-static struct pxafb_rgb def_rgb_16 = {
-	.red	= { .offset = 11, .length = 5, },
-	.green	= { .offset = 5,  .length = 6, },
-	.blue	= { .offset = 0,  .length = 5, },
-	.transp	= { .offset = 0,  .length = 0, },
-};
+/* Bits which should not be set in machine configuration structures */
+#define LCCR0_INVALID_CONFIG_MASK (LCCR0_OUM|LCCR0_BM|LCCR0_QDM|LCCR0_DIS|LCCR0_EFM|LCCR0_IUM|LCCR0_SFM|LCCR0_LDM|LCCR0_ENB)
+#define LCCR3_INVALID_CONFIG_MASK (LCCR3_HSP|LCCR3_VSP|LCCR3_PCD|LCCR3_BPP)
 
-#ifdef LCD_PIXCLOCK
-static struct pxafb_mach_info pxa_fb_info __initdata = {
-	.pixclock = 	LCD_PIXCLOCK,	/* clock period in ps */
-	.bpp = 		LCD_BPP,
-	.xres = 	LCD_XRES,
-	.yres = 	LCD_YRES,
-	.hsync_len = 	LCD_HORIZONTAL_SYNC_PULSE_WIDTH,
-	.vsync_len = 	LCD_VERTICAL_SYNC_PULSE_WIDTH,
-	.left_margin = 	LCD_BEGIN_OF_LINE_WAIT_COUNT,
-	.upper_margin =	LCD_BEGIN_FRAME_WAIT_COUNT,
-	.right_margin =	LCD_END_OF_LINE_WAIT_COUNT,
-	.lower_margin =	LCD_END_OF_FRAME_WAIT_COUNT,
-	.sync =		LCD_SYNC,
-	.lccr0 =	LCD_LCCR0,
-	.lccr3 =	LCD_LCCR3
-};
-#endif
-
-static struct pxafb_mach_info * 
-pxafb_get_machine_info(void)
-{
-#ifdef CONFIG_LCD_DEVICE
-	struct pxafb_mach_info *inf = NULL;
-	struct lcd_device *lm = lcd_device_get(lcd_device_find("pxafb"));
-	if (lm) {
-		if (lm->get_mach_info)
-			inf = lm->get_mach_info(lm);
-		lcd_device_put(lm);
-		if (inf)
-			return inf;
-	}
-#endif
-#ifdef LCD_PIXCLOCK
-	return &pxa_fb_info;
-#else
-        return NULL;
-#endif
-}
+static void (*pxafb_backlight_power)(int);
+static void (*pxafb_lcd_power)(int);
 
 static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info *);
 static void set_ctrlr_state(struct pxafb_info *fbi, u_int state);
 
+#define PXAFB_OPTIONS_SIZE 256
+static char g_options[PXAFB_OPTIONS_SIZE] __initdata = "";
+
 static inline void pxafb_schedule_work(struct pxafb_info *fbi, u_int state)
 {
 	unsigned long flags;
@@ -161,7 +108,6 @@
 	local_irq_restore(flags);
 }
 
-
 static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf)
 {
 	chan &= 0xffff;
@@ -169,17 +115,34 @@
 	return chan << bf->offset;
 }
 
+/*
+ * Convert bits-per-pixel to a hardware palette PBS value.
+ */
+static inline u_int palette_pbs(struct fb_var_screeninfo *var)
+{
+	int ret = 0;
+	switch (var->bits_per_pixel) {
+	case 4:  ret = 0 << 12;	break;
+	case 8:  ret = 1 << 12; break;
+	case 16: ret = 2 << 12; break;
+	}
+	return ret;
+}
+
 static int
 pxafb_setpalettereg(u_int regno, u_int red, u_int green, u_int blue,
 		       u_int trans, struct fb_info *info)
 {
 	struct pxafb_info *fbi = (struct pxafb_info *)info;
-	unsigned int val, ret = 1;
+	u_int val, ret = 1;
 
 	if (regno < fbi->palette_size) {
-		val = ((red >> 0) & 0xf800);
-		val |= ((green >> 5) & 0x07e0);
-		val |= ((blue >> 11) & 0x001f);
+		val  = ((red   >>  0) & 0xf800);
+		val |= ((green >>  5) & 0x07e0);
+		val |= ((blue  >> 11) & 0x001f);
+
+		if (regno == 0)
+			val |= palette_pbs(&fbi->fb.var);
 
 		fbi->palette_cpu[regno] = val;
 		ret = 0;
@@ -192,12 +155,24 @@
 		   u_int trans, struct fb_info *info)
 {
 	struct pxafb_info *fbi = (struct pxafb_info *)info;
-	u_int val;
+	unsigned int val;
 	int ret = 1;
 
 	/*
+	 * If inverse mode was selected, invert all the colours
+	 * rather than the register number.  The register number
+	 * is what you poke into the framebuffer to produce the
+	 * colour you requested.
+	 */
+	if (fbi->cmap_inverse) {
+		red   = 0xffff - red;
+		green = 0xffff - green;
+		blue  = 0xffff - blue;
+	}
+
+	/*
 	 * If greyscale is true, then we convert the RGB value
-	 * to greyscale no mater what visual we are using.
+	 * to greyscale no matter what visual we are using.
 	 */
 	if (fbi->fb.var.grayscale)
 		red = green = blue = (19595 * red + 38470 * green +
@@ -205,7 +180,6 @@
 
 	switch (fbi->fb.fix.visual) {
 	case FB_VISUAL_TRUECOLOR:
-	case FB_VISUAL_DIRECTCOLOR:
 		/*
 		 * 12 or 16-bit True Colour.  We encode the RGB value
 		 * according to the RGB bitfield information.
@@ -222,6 +196,7 @@
 		}
 		break;
 
+	case FB_VISUAL_STATIC_PSEUDOCOLOR:
 	case FB_VISUAL_PSEUDOCOLOR:
 		ret = pxafb_setpalettereg(regno, red, green, blue, trans, info);
 		break;
@@ -231,16 +206,53 @@
 }
 
 /*
+ *  pxafb_bpp_to_lccr3():
+ *    Convert a bits per pixel value to the correct bit pattern for LCCR3
+ */
+static int pxafb_bpp_to_lccr3(struct fb_var_screeninfo *var)
+{
+        int ret = 0;
+        switch (var->bits_per_pixel) {
+        case 1:  ret = LCCR3_1BPP; break;
+        case 2:  ret = LCCR3_2BPP; break;
+        case 4:  ret = LCCR3_4BPP; break;
+        case 8:  ret = LCCR3_8BPP; break;
+        case 16: ret = LCCR3_16BPP; break;
+        }
+        return ret;
+}
+
+#ifdef CONFIG_CPU_FREQ
+/*
+ *  pxafb_display_dma_period()
+ *    Calculate the minimum period (in picoseconds) between two DMA
+ *    requests for the LCD controller.  If we hit this, it means we're
+ *    doing nothing but LCD DMA.
+ */
+static unsigned int pxafb_display_dma_period(struct fb_var_screeninfo *var)
+{
+       /*
+        * Period = pixclock * bits_per_byte * bytes_per_transfer
+        *              / memory_bits_per_pixel;
+        */
+       return var->pixclock * 8 * 16 / var->bits_per_pixel;
+}
+
+extern unsigned int get_clk_frequency_khz(int info);
+#endif
+
+/*
  *  pxafb_check_var():
+ *    Get the video params out of 'var'. If a value doesn't fit, round it up,
+ *    if it's too big, return -EINVAL.
+ *
  *    Round up in the following order: bits_per_pixel, xres,
  *    yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale,
  *    bitfields, horizontal timing, vertical timing.
  */
-static int
-pxafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+static int pxafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 {
 	struct pxafb_info *fbi = (struct pxafb_info *)info;
-	int rgbidx = 0; // combat bogus warning
 
 	if (var->xres < MIN_XRES)
 		var->xres = MIN_XRES;
@@ -250,69 +262,56 @@
 		var->xres = fbi->max_xres;
 	if (var->yres > fbi->max_yres)
 		var->yres = fbi->max_yres;
-	var->xres_virtual = max(var->xres_virtual, var->xres);
-	var->yres_virtual = max(var->yres_virtual, var->yres);
+	var->xres_virtual =
+		max(var->xres_virtual, var->xres);
+	var->yres_virtual =
+		max(var->yres_virtual, var->yres);
 
-	DPRINTK("var->bits_per_pixel=%d\n", var->bits_per_pixel);
-	switch (var->bits_per_pixel) {
-	case 4:  rgbidx = RGB_8; break;
-	case 8:  rgbidx = RGB_8; break;
-	case 12:
-		/* make sure we are in passive mode */
-		if (!(fbi->lccr0 & LCCR0_PAS))
-			rgbidx = RGB_16;
-		break;
 
-	case 16:
-		/* 
-		 * 16 bits works apparemtly fine in passive mode for those,
-		 * so don't complain
-		 */
-		if (machine_is_lubbock() ||
-		    machine_is_pxa_cerf()) {
-			rgbidx = RGB_16;
-		} else
-			/* make sure we are in active mode */
-			if ((fbi->lccr0 & LCCR0_PAS))
-				rgbidx = RGB_16;
-		break;
-	default:
-		return -EINVAL;
+	DPRINTK("var->bits_per_pixel=%d\n", var->bits_per_pixel);
+        /*
+	 * Setup the RGB parameters for this display.
+	 *
+	 * The pixel packing format is described on page 7-11 of the
+	 * PXA2XX Developer's Manual.
+         */
+	if ( var->bits_per_pixel == 16 ) {
+		var->red.offset   = 11; var->red.length   = 5;
+		var->green.offset = 5;  var->green.length = 6;
+		var->blue.offset  = 0;  var->blue.length  = 5;
+		var->transp.offset = var->transp.length = 0;
+	} else {
+		var->red.offset = var->green.offset = var->blue.offset = var->transp.offset = 0;  
+		var->red.length   = 8;
+		var->green.length = 8;
+		var->blue.length  = 8;
+		var->transp.length = 0;
 	}
-
-	/*
-	 * Copy the RGB parameters for this display
-	 * from the machine specific parameters.
-	 */
-	var->red    = fbi->rgb[rgbidx]->red;
-	var->green  = fbi->rgb[rgbidx]->green;
-	var->blue   = fbi->rgb[rgbidx]->blue;
-	var->transp = fbi->rgb[rgbidx]->transp;
-
-	DPRINTK("RGBT length = %d:%d:%d:%d\n",
-		var->red.length, var->green.length, var->blue.length,
-		var->transp.length);
-
-	DPRINTK("RGBT offset = %d:%d:%d\n",
-		var->red.offset, var->green.offset, var->blue.offset);
+	
+#ifdef CONFIG_CPU_FREQ
+	DPRINTK("dma period = %d ps, clock = %d kHz\n",
+		pxafb_display_dma_period(var),
+		get_clk_frequency_khz(0));
+#endif
 
 	return 0;
 }
 
 static inline void pxafb_set_truecolor(u_int is_true_color)
 {
-	// noop
+	DPRINTK("true_color = %d\n", is_true_color);
+	// do your machine-specific setup if needed
 }
 
 /*
  * pxafb_set_par():
  *	Set the user defined part of the display for the specified console
  */
-static int
-pxafb_set_par(struct fb_info *info)
+static int pxafb_set_par(struct fb_info *info)
 {
 	struct pxafb_info *fbi = (struct pxafb_info *)info;
 	struct fb_var_screeninfo *var = &info->var;
+	unsigned long palette_mem_size;
 
 	DPRINTK("set_par\n");
 
@@ -331,8 +330,16 @@
 
 	fbi->fb.fix.line_length = var->xres_virtual *
 				  var->bits_per_pixel / 8;
-				  
-	/* 
+	fbi->palette_size = var->bits_per_pixel == 8 ? 256 : 16;
+
+	palette_mem_size = fbi->palette_size * sizeof(u16);
+
+	DPRINTK("palette_mem_size = 0x%08lx\n", (u_long) palette_mem_size);
+
+	fbi->palette_cpu = (u16 *)(fbi->map_cpu + PAGE_SIZE - palette_mem_size);
+	fbi->palette_dma = fbi->map_dma + PAGE_SIZE - palette_mem_size;
+
+	/*
 	 * Set (any) board control register to handle new color depth
 	 */
 	pxafb_set_truecolor(fbi->fb.fix.visual == FB_VISUAL_TRUECOLOR);
@@ -342,23 +349,6 @@
 	return 0;
 }
 
-#if 0
-static int
-pxafb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
-		  struct fb_info *info)
-{
-	struct pxafb_info *fbi = (struct pxafb_info *)info;
-
-	/*
-	 * Make sure the user isn't doing something stupid.
-	 */
-	if (!kspc && (fbi->fb.var.bits_per_pixel == 16 || fbi->cmap_static))
-		return -EINVAL;
- 
-	return gen_set_cmap(cmap, kspc, con, info);
-}
-#endif
-
 /*
  * Formal definition of the VESA spec:
  *  On
@@ -388,6 +378,7 @@
  *
  *  This will match the matrox implementation.
  */
+
 /*
  * pxafb_blank():
  *	Blank the display by setting all palette values to zero.  Note, the 
@@ -397,7 +388,9 @@
 static int pxafb_blank(int blank, struct fb_info *info)
 {
 	struct pxafb_info *fbi = (struct pxafb_info *)info;
+#if BLANKING_SET_PALETTE
 	int i;
+#endif
 
 	DPRINTK("pxafb_blank: blank=%d\n", blank);
 
@@ -405,10 +398,13 @@
 	case VESA_POWERDOWN:
 	case VESA_VSYNC_SUSPEND:
 	case VESA_HSYNC_SUSPEND:
+#if BLANKING_SET_PALETTE
+		// This is bad for windowing packages
 		if (fbi->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR ||
 		    fbi->fb.fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
 			for (i = 0; i < fbi->palette_size; i++)
 				pxafb_setpalettereg(i, 0, 0, 0, 0, info);
+#endif
 		pxafb_schedule_work(fbi, C_DISABLE);
 		if (pxafb_blank_helper)
 			pxafb_blank_helper(blank);
@@ -417,9 +413,11 @@
 	case VESA_NO_BLANKING:
 		if (pxafb_blank_helper)
 			pxafb_blank_helper(blank);
+#if BLANKING_SET_PALETTE
 		if (fbi->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR ||
 		    fbi->fb.fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
 			fb_set_cmap(&fbi->fb.cmap, 1, info);
+#endif
 		pxafb_schedule_work(fbi, C_ENABLE);
 	}
 	return 0;
@@ -429,7 +427,6 @@
 	.owner		= THIS_MODULE,
 	.fb_check_var	= pxafb_check_var,
 	.fb_set_par	= pxafb_set_par,
-//	.fb_set_cmap	= pxafb_set_cmap,
 	.fb_setcolreg	= pxafb_setcolreg,
 	.fb_fillrect	= cfb_fillrect,
 	.fb_copyarea	= cfb_copyarea,
@@ -441,32 +438,58 @@
 /*
  * Calculate the PCD value from the clock rate (in picoseconds).
  * We take account of the PPCR clock setting.
+ * From PXA Developer's Manual:
+ *
+ *   PixelClock =      LCLK
+ *                -------------
+ *                2 ( PCD + 1 )
+ *
+ *   PCD =      LCLK
+ *         ------------- - 1
+ *         2(PixelClock)
+ *
+ * Where:
+ *   LCLK = LCD/Memory Clock
+ *   PCD = LCCR3[7:0]
+ *
+ * PixelClock here is in Hz while the pixclock argument given is the
+ * period in picoseconds. Hence PixelClock = 1 / ( pixclock * 10^-12 )
+ *
+ * The function get_lclk_frequency_10khz returns LCLK in units of
+ * 10khz. Calling the result of this function lclk gives us the
+ * following
+ *
+ *    PCD = (lclk * 10^4 ) * ( pixclock * 10^-12 )
+ *          -------------------------------------- - 1
+ *                          2
+ *
+ * Factoring the 10^4 and 10^-12 out gives 10^-8 == 1 / 100000000 as used below.
  */
-static inline unsigned int get_pcd(unsigned int pixclock, unsigned int cpuclock)
+static inline unsigned int get_pcd(unsigned int pixclock)
 {
-	unsigned int pcd;
+	unsigned long long pcd;
 
-	if (pixclock) {
-		pcd = cpuclock / 100 * pixclock;
-		pcd /= 100000000;
-		pcd += 1;	/* make up for integer math truncations */
-	} else {
-		printk(KERN_WARNING "Please convert me to use the PCD calculations\n");
-		pcd = 0;
-	}
-	return pcd;
+	/* FIXME: Need to take into account Double Pixel Clock mode
+         * (DPC) bit? or perhaps set it based on the various clock
+         * speeds */
+	
+	pcd = (unsigned long long)get_lclk_frequency_10khz() * (unsigned long long)pixclock;
+	pcd /= 100000000 * 2;
+	/* no need for this, since we should subtract 1 anyway. they cancel */
+	/* pcd += 1; */ /* make up for integer math truncations */
+	return (unsigned int)pcd;
 }
 
 /*
  * pxafb_activate_var():
  *	Configures LCD Controller based on entries in var parameter.  Settings are      
- *      only written to the controller if changes were made.  
+ *	only written to the controller if changes were made.  
  */
 static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info *fbi)
 {
 	struct pxafb_lcd_reg new_regs;
-	u_int pcd = get_pcd(var->pixclock, get_clk_frequency_khz(0));
 	u_long flags;
+	u_int pcd = get_pcd(var->pixclock);
 
 	DPRINTK("Configuring PXA LCD\n");
 
@@ -481,6 +504,18 @@
 	if (var->xres < 16        || var->xres > 1024)
 		printk(KERN_ERR "%s: invalid xres %d\n",
 			fbi->fb.fix.id, var->xres);
+	switch(var->bits_per_pixel) {
+	case 1:
+	case 2:
+	case 4:
+	case 8:
+	case 16:
+		break;
+	default:
+		printk(KERN_ERR "%s: invalid bit depth %d\n", 
+		       fbi->fb.fix.id, var->bits_per_pixel);
+		break;
+	}
 	if (var->hsync_len < 1    || var->hsync_len > 64)
 		printk(KERN_ERR "%s: invalid hsync_len %d\n",
 			fbi->fb.fix.id, var->hsync_len);
@@ -504,7 +539,10 @@
 			fbi->fb.fix.id, var->lower_margin);
 #endif
 
-	new_regs.lccr0 = fbi->lccr0;
+	new_regs.lccr0 = fbi->lccr0 | 
+		(LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM |
+                 LCCR0_QDM | LCCR0_BM  | LCCR0_OUM);
+	
 	new_regs.lccr1 =
 		LCCR1_DisWdth(var->xres) +
 		LCCR1_HorSnchWdth(var->hsync_len) +
@@ -517,13 +555,17 @@
 		LCCR2_BegFrmDel(var->upper_margin) +
 		LCCR2_EndFrmDel(var->lower_margin);
 
-	new_regs.lccr3 = fbi->lccr3
-		|
+#if defined(CONFIG_ARCH_LOOX600) || defined(CONFIG_ARCH_ADSBITSYX) || defined(CONFIG_ARCH_ADSAGX)
+        new_regs.lccr3 = fbi->lccr3;
+#else
+	new_regs.lccr3 = fbi->lccr3 |
+		pxafb_bpp_to_lccr3(var) |
 		(var->sync & FB_SYNC_HOR_HIGH_ACT ? LCCR3_HorSnchH : LCCR3_HorSnchL) |
 		(var->sync & FB_SYNC_VERT_HIGH_ACT ? LCCR3_VrtSnchH : LCCR3_VrtSnchL);
 
 	if (pcd)
 		new_regs.lccr3 |= LCCR3_PixClkDiv(pcd);
+#endif
 
 	DPRINTK("nlccr0 = 0x%08x\n", new_regs.lccr0);
 	DPRINTK("nlccr1 = 0x%08x\n", new_regs.lccr1);
@@ -542,9 +584,10 @@
 	fbi->dmadesc_fbhigh_dma = fbi->palette_dma - 2*16;
 	fbi->dmadesc_palette_dma = fbi->palette_dma - 1*16;
 
-	#define BYTES_PER_PANEL	((fbi->lccr0 & LCCR0_SDS) ? (var->xres * var->yres * var->bits_per_pixel / 8 / 2) : \
-			                                    (var->xres * var->yres * var->bits_per_pixel / 8))
-	
+	#define BYTES_PER_PANEL ((fbi->lccr0 & LCCR0_SDS) == LCCR0_Dual ? \
+                                (var->xres * var->yres * var->bits_per_pixel / 8 / 2) : \
+                                (var->xres * var->yres * var->bits_per_pixel / 8))
+
 	/* populate descriptors */
 	fbi->dmadesc_fblow_cpu->fdadr = fbi->dmadesc_fblow_dma;
 	fbi->dmadesc_fblow_cpu->fsadr = fbi->screen_dma + BYTES_PER_PANEL;
@@ -573,11 +616,14 @@
 		/* palette shouldn't be loaded in true-color mode */
 		fbi->dmadesc_fbhigh_cpu->fdadr = fbi->dmadesc_fbhigh_dma;
 		fbi->fdadr0 = fbi->dmadesc_fbhigh_dma; /* no pal just fbhigh */
+		/* init it to something, even though we won't be using it */
+		fbi->dmadesc_palette_cpu->fdadr = fbi->dmadesc_palette_dma;
 	}
 
-	DPRINTK("fbi->dmadesc_fblow_cpu = 0x%x\n", (unsigned int)fbi->dmadesc_fblow_cpu);
-	DPRINTK("fbi->dmadesc_fbhigh_cpu = 0x%x\n", (unsigned int)fbi->dmadesc_fbhigh_cpu);
-	DPRINTK("fbi->dmadesc_palette_cpu = 0x%x\n", (unsigned int)fbi->dmadesc_palette_cpu);
+#if 0
+	DPRINTK("fbi->dmadesc_fblow_cpu = 0x%p\n", fbi->dmadesc_fblow_cpu);
+	DPRINTK("fbi->dmadesc_fbhigh_cpu = 0x%p\n", fbi->dmadesc_fbhigh_cpu);
+	DPRINTK("fbi->dmadesc_palette_cpu = 0x%p\n", fbi->dmadesc_palette_cpu);
 	DPRINTK("fbi->dmadesc_fblow_dma = 0x%x\n", fbi->dmadesc_fblow_dma);
 	DPRINTK("fbi->dmadesc_fbhigh_dma = 0x%x\n", fbi->dmadesc_fbhigh_dma);
 	DPRINTK("fbi->dmadesc_palette_dma = 0x%x\n", fbi->dmadesc_palette_dma);
@@ -593,6 +639,7 @@
 	DPRINTK("fbi->dmadesc_fblow_cpu->ldcmd = 0x%x\n", fbi->dmadesc_fblow_cpu->ldcmd);
 	DPRINTK("fbi->dmadesc_fbhigh_cpu->ldcmd = 0x%x\n", fbi->dmadesc_fbhigh_cpu->ldcmd);
 	DPRINTK("fbi->dmadesc_palette_cpu->ldcmd = 0x%x\n", fbi->dmadesc_palette_cpu->ldcmd);
+#endif
 	
 	fbi->reg_lccr0 = new_regs.lccr0;
 	fbi->reg_lccr1 = new_regs.lccr1;
@@ -604,9 +651,9 @@
 	 * Only update the registers if the controller is enabled
 	 * and something has changed.
 	 */
-	if ((LCCR0 != fbi->reg_lccr0)       || (LCCR1 != fbi->reg_lccr1) ||
-	    (LCCR2 != fbi->reg_lccr2)       || (LCCR3 != fbi->reg_lccr3) ||
-	    (FDADR0 != fbi->fdadr0) || (FDADR1 != fbi->fdadr1))
+	if ((LCCR0  != fbi->reg_lccr0) || (LCCR1  != fbi->reg_lccr1) ||
+	    (LCCR2  != fbi->reg_lccr2) || (LCCR3  != fbi->reg_lccr3) ||
+	    (FDADR0 != fbi->fdadr0)    || (FDADR1 != fbi->fdadr1))
 		pxafb_schedule_work(fbi, C_REENABLE);
 
 	return 0;
@@ -618,18 +665,12 @@
  * to ensure that things happen in the right way 100% of time time.
  *	-- rmk
  */
-
-/*
- * FIXME: move LCD power stuff into pxafb_power_up_lcd()
- * Also, I'm expecting that the backlight stuff should
- * be handled differently.
- */
-static inline void __pxafb_backlight_on(struct pxafb_info *fbi, int on)
+static inline void __pxafb_backlight_power(struct pxafb_info *fbi, int on)
 {
 	DPRINTK("backlight o%s\n", on ? "n" : "ff");
 
 #ifdef CONFIG_LCD_DEVICE
-	{ 
+	{
 		struct backlight_device *bl = fbi->bm;
 		if (bl && bl->set_power)
 			bl->set_power(bl, on);
@@ -652,18 +693,13 @@
 #endif
 }
 
-/*
- * FIXME: move LCD power stuf into pxafb_power_down_lcd()
- * Also, I'm expecting that the backlight stuff should
- * be handled differently.
- */
 static inline void __pxafb_lcd_power(struct pxafb_info *fbi, int on)
 {
 	DPRINTK("LCD power o%s\n", on ? "n" : "ff");
 	CKEN |= CKEN16_LCD;
-
+	
 #ifdef CONFIG_LCD_DEVICE
-	{ 
+	{
 		struct lcd_device *lm = fbi->lm;
 		if (lm && lm->set_power)
 			lm->set_power(lm, on);
@@ -675,16 +711,16 @@
 
 static void pxafb_setup_gpio(struct pxafb_info *fbi)
 {
-	unsigned int lccr0;
-
+        unsigned int lccr0 = fbi->lccr0;
+        
 	/*
 	 * setup is based on type of panel supported
-	 */
-
-	lccr0 = fbi->lccr0;
+        */
 
 	/* 4 bit interface */
-	if ((lccr0 & LCCR0_CMS) && (lccr0 & LCCR0_SDS) && !(lccr0 & LCCR0_DPD))
+	if ((lccr0 & LCCR0_CMS) == LCCR0_Mono && 
+	    (lccr0 & LCCR0_SDS) == LCCR0_Sngl && 
+	    (lccr0 & LCCR0_DPD) == LCCR0_4PixMono)
 	{
 		// bits 58-61
 		GPDR1 |= (0xf << 26);
@@ -692,44 +728,59 @@
 
 		// bits 74-77
 		GPDR2 |= (0xf << 10);
-                GAFR2_L = (GAFR2_L & ~(0xff << 20)) | (0xaa << 20);
+		GAFR2_L = (GAFR2_L & ~(0xff << 20)) | (0xaa << 20);
 	}
 
-        /* 8 bit interface */
-        else if (((lccr0 & LCCR0_CMS) && ((lccr0 & LCCR0_SDS) || (lccr0 & LCCR0_DPD))) ||
-                 (!(lccr0 & LCCR0_CMS) && !(lccr0 & LCCR0_PAS) && !(lccr0 & LCCR0_SDS)))
-        {
+	/* 8 bit interface */
+        else if (((lccr0 & LCCR0_CMS) == LCCR0_Mono && 
+		  ((lccr0 & LCCR0_SDS) == LCCR0_Dual || (lccr0 & LCCR0_DPD) == LCCR0_8PixMono)) ||
+                 ((lccr0 & LCCR0_CMS) == LCCR0_Color && 
+		  (lccr0 & LCCR0_PAS) == LCCR0_Pas && (lccr0 & LCCR0_SDS) == LCCR0_Sngl))
+	{
 		// bits 58-65
-                GPDR1 |= (0x3f << 26);
-                GPDR2 |= (0x3);
+		GPDR1 |= (0x3f << 26);
+		GPDR2 |= (0x3);
 
-                GAFR1_U = (GAFR1_U & ~(0xfff << 20)) | (0xaaa << 20);
-                GAFR2_L = (GAFR2_L & ~0xf) | (0xa);
+		GAFR1_U = (GAFR1_U & ~(0xfff << 20)) | (0xaaa << 20);
+		GAFR2_L = (GAFR2_L & ~0xf) | (0xa);
 
-                // bits 74-77
-                GPDR2 |= (0xf << 10);
-                GAFR2_L = (GAFR2_L & ~(0xff << 20)) | (0xaa << 20);
-        }
+		// bits 74-77
+		GPDR2 |= (0xf << 10);
+		GAFR2_L = (GAFR2_L & ~(0xff << 20)) | (0xaa << 20);
+	}
 
-        /* 16 bit interface */
-        else if (!(lccr0 & LCCR0_CMS) && ((lccr0 & LCCR0_SDS) || (lccr0 & LCCR0_PAS)))
-        {
+	/* 16 bit interface */
+	else if ((lccr0 & LCCR0_CMS) == LCCR0_Color && 
+		 ((lccr0 & LCCR0_SDS) == LCCR0_Dual || (lccr0 & LCCR0_PAS) == LCCR0_Act))
+	{
 		// bits 58-77
-                GPDR1 |= (0x3f << 26);
-                GPDR2 |= 0x00003fff;
+		GPDR1 |= (0x3f << 26);
+		GPDR2 |= 0x00003fff;
 
-                GAFR1_U = (GAFR1_U & ~(0xfff << 20)) | (0xaaa << 20);
-                GAFR2_L = (GAFR2_L & 0xf0000000) | 0x0aaaaaaa;
-        }
-	else
-	{
-		printk( KERN_ERR "pxafb_setup_gpio: unable to determine bits per pixel\n");
+		GAFR1_U = (GAFR1_U & ~(0xfff << 20)) | (0xaaa << 20);
+		GAFR2_L = (GAFR2_L & 0xf0000000) | 0x0aaaaaaa;
 	}
+	
+	else {
+	        printk( KERN_ERR "pxafb_setup_gpio: unable to determine bits per pixel\n");
+        }	                                                                                                                                  
 }
 
 static void pxafb_enable_controller(struct pxafb_info *fbi)
 {
 	DPRINTK("Enabling LCD controller\n");
+	DPRINTK("fdadr0 0x%08x\n", (unsigned int) fbi->fdadr0);
+	DPRINTK("fdadr1 0x%08x\n", (unsigned int) fbi->fdadr1);
+	DPRINTK("reg_lccr0 0x%08x\n", (unsigned int) fbi->reg_lccr0);
+	DPRINTK("reg_lccr1 0x%08x\n", (unsigned int) fbi->reg_lccr1);
+	DPRINTK("reg_lccr2 0x%08x\n", (unsigned int) fbi->reg_lccr2);
+	DPRINTK("reg_lccr3 0x%08x\n", (unsigned int) fbi->reg_lccr3);
+
+	/*
+	 * Make sure the mode bits are present in the first palette entry
+	 */
+	//TODO pxafb had: fbi->palette_cpu[0] &= 0xcfff;
+	//TODO pxafb had: fbi->palette_cpu[0] |= palette_pbs(&fbi->fb.var);
 
 	/* Sequence from 11.7.10 */
 	LCCR3 = fbi->reg_lccr3;
@@ -737,18 +788,16 @@
 	LCCR1 = fbi->reg_lccr1;
 	LCCR0 = fbi->reg_lccr0 & ~LCCR0_ENB;
 
-	/* FIXME we used to have LCD power control here */
-
 	FDADR0 = fbi->fdadr0;
 	FDADR1 = fbi->fdadr1;
 	LCCR0 |= LCCR0_ENB;
 
-	DPRINTK("FDADR0 = 0x%08x\n", (unsigned int)FDADR0);
-	DPRINTK("FDADR1 = 0x%08x\n", (unsigned int)FDADR1);
-	DPRINTK("LCCR0 = 0x%08x\n", (unsigned int)LCCR0);
-	DPRINTK("LCCR1 = 0x%08x\n", (unsigned int)LCCR1);
-	DPRINTK("LCCR2 = 0x%08x\n", (unsigned int)LCCR2);
-	DPRINTK("LCCR3 = 0x%08x\n", (unsigned int)LCCR3);
+	DPRINTK("FDADR0 0x%08x\n", (unsigned int) FDADR0);
+	DPRINTK("FDADR1 0x%08x\n", (unsigned int) FDADR1);
+	DPRINTK("LCCR0 0x%08x\n", (unsigned int) LCCR0);
+	DPRINTK("LCCR1 0x%08x\n", (unsigned int) LCCR1);
+	DPRINTK("LCCR2 0x%08x\n", (unsigned int) LCCR2);
+	DPRINTK("LCCR3 0x%08x\n", (unsigned int) LCCR3);
 }
 
 static void pxafb_disable_controller(struct pxafb_info *fbi)
@@ -757,18 +806,15 @@
 
 	DPRINTK("Disabling LCD controller\n");
 
-	/* FIXME add power down GPIO stuff here */
-
 	add_wait_queue(&fbi->ctrlr_wait, &wait);
 	set_current_state(TASK_UNINTERRUPTIBLE);
 
 	LCSR = 0xffffffff;	/* Clear LCD Status Register */
 	LCCR0 &= ~LCCR0_LDM;	/* Enable LCD Disable Done Interrupt */
-	if (0) enable_irq(IRQ_LCD);	/* Enable LCD IRQ */
+	//TODO?enable_irq(IRQ_LCD);  /* Enable LCD IRQ */
 	LCCR0 &= ~LCCR0_ENB;	/* Disable LCD Controller */
 
 	schedule_timeout(20 * HZ / 1000);
-	set_current_state(TASK_RUNNING);
 	remove_wait_queue(&fbi->ctrlr_wait, &wait);
 }
 
@@ -801,9 +847,9 @@
 	down(&fbi->ctrlr_sem);
 
 	old_state = fbi->state;
-	
+
 	/*
-	 * Hack around fbcon initialization.
+	 * Hack around fbcon initialisation.
 	 */
 	if (old_state == C_STARTUP && state == C_REENABLE)
 		state = C_ENABLE;
@@ -828,10 +874,8 @@
 		 * Disable controller
 		 */
 		if (old_state != C_DISABLE) {
-			DPRINTK("Disabling LCD\n");
 			fbi->state = state;
-
-			__pxafb_backlight_on(fbi, 0);
+			__pxafb_backlight_power(fbi, 0);
 			__pxafb_lcd_enable(fbi, 0);
 			__pxafb_lcd_power(fbi, 0);
 			if (old_state != C_DISABLE_CLKCHANGE)
@@ -882,12 +926,11 @@
 		 */
 		if (old_state != C_ENABLE) {
 			fbi->state = C_ENABLE;
-			DPRINTK("Enabling LCD\n");
 			pxafb_setup_gpio(fbi);
 			pxafb_enable_controller(fbi);
 			__pxafb_lcd_power(fbi, 1);
 			__pxafb_lcd_enable(fbi, 1);
-			__pxafb_backlight_on(fbi, 1);
+			__pxafb_backlight_power(fbi, 1);
 		}
 		break;
 	}
@@ -911,13 +954,14 @@
  * CPU clock speed change handler.  We need to adjust the LCD timing
  * parameters when the CPU clock is adjusted by the power management
  * subsystem.
+ *
+ * TODO: Determine why f->new != 10*get_lclk_frequency_10khz()
  */
 static int
-pxafb_freq_transition(struct notifier_block *nb, unsigned long val,
-			 void *data)
+pxafb_freq_transition(struct notifier_block *nb, unsigned long val, void *data)
 {
 	struct pxafb_info *fbi = TO_INF(nb, freq_transition);
-	struct cpufreq_freqs *f = data;
+	//TODO struct cpufreq_freqs *f = data;
 	u_int pcd;
 
 	switch (val) {
@@ -926,7 +970,7 @@
 		break;
 
 	case CPUFREQ_POSTCHANGE:
-		pcd = get_pcd(fbi->fb.var.pixclock, f->new);
+		pcd = get_pcd(fbi->fb.var.pixclock);
 		fbi->reg_lccr3 = (fbi->reg_lccr3 & ~0xff) | LCCR3_PixClkDiv(pcd);
 		set_ctrlr_state(fbi, C_ENABLE_CLKCHANGE);
 		break;
@@ -935,23 +979,30 @@
 }
 
 static int
-pxafb_freq_policy(struct notifier_block *nb, unsigned long val,
-		     void *data)
+pxafb_freq_policy(struct notifier_block *nb, unsigned long val, void *data)
 {
-	/*struct pxafb_info *fbi = TO_INF(nb, freq_policy);
-	struct cpufreq_policy *policy = data;*/
+	struct pxafb_info *fbi = TO_INF(nb, freq_policy);
+	struct fb_var_screeninfo *var = &fbi->fb.var;
+	struct cpufreq_policy *policy = data;
 
 	switch (val) {
 	case CPUFREQ_ADJUST:
 	case CPUFREQ_INCOMPATIBLE:
+		printk(KERN_DEBUG "min dma period: %d ps, "
+			"new clock %d kHz\n", pxafb_display_dma_period(var),
+			policy->max);
+		// TODO: fill in min/max values
 		break;
+#if 0
 	case CPUFREQ_NOTIFY:
+		printk(KERN_ERR "%s: got CPUFREQ_NOTIFY\n", __FUNCTION__);
 		do {} while(0);
 		/* todo: panic if min/max values aren't fulfilled 
 		 * [can't really happen unless there's a bug in the
-		 * CPU policy verififcation process *
+		 * CPU policy verification process *
 		 */
 		break;
+#endif
 	}
 	return 0;
 }
@@ -971,16 +1022,17 @@
 	return 0;
 }
 
-static int pxafb_resume(struct device *dev, u32 level)	
+static int pxafb_resume(struct device *dev, u32 level)
 {
 	struct pxafb_info *fbi = dev_get_drvdata(dev);
+
 	if (level == RESUME_ENABLE)
 		set_ctrlr_state(fbi, C_ENABLE_PM);
 	return 0;
 }
 #else
-#define pxafb_suspend		NULL
-#define pxafb_resume		NULL
+#define pxafb_suspend	NULL
+#define pxafb_resume	NULL
 #endif
 
 /*
@@ -991,62 +1043,59 @@
  *      cache.  Once this area is remapped, all virtual memory
  *      access to the video memory should occur at the new region.
  */
-static int pxafb_map_video_memory(struct pxafb_info *fbi)
+static int __init pxafb_map_video_memory(struct pxafb_info *fbi)
 {
 	u_long palette_mem_size;
-
+	
 	/*
 	 * We reserve one page for the palette, plus the size
 	 * of the framebuffer.
-	 *
-	 * layout of stuff in memory
-	 *
-	 *                fblow descriptor
-	 *                fbhigh descriptor
-	 *                palette descriptor
-	 *                palette
-	 *   page boundary->
-	 *                frame buffer
 	 */
 	fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + PAGE_SIZE);
 	fbi->map_cpu = dma_alloc_coherent(fbi->dev, fbi->map_size,
 					&fbi->map_dma, GFP_KERNEL);
 
 	if (fbi->map_cpu) {
+		/* prevent initial garbage on screen */
+		memset(fbi->map_cpu, 0, fbi->map_size);
 		fbi->fb.screen_base = fbi->map_cpu + PAGE_SIZE;
 		fbi->screen_dma = fbi->map_dma + PAGE_SIZE;
 		fbi->fb.fix.smem_start = fbi->screen_dma;
-
+		
 		fbi->palette_size = fbi->fb.var.bits_per_pixel == 8 ? 256 : 16;
-
+		
 		palette_mem_size = fbi->palette_size * sizeof(u16);
-
 		DPRINTK("palette_mem_size = 0x%08lx\n", (u_long) palette_mem_size);
-
+		
 		fbi->palette_cpu = (u16 *)(fbi->map_cpu + PAGE_SIZE - palette_mem_size);
 		fbi->palette_dma = fbi->map_dma + PAGE_SIZE - palette_mem_size;
-
 	}
 
 	return fbi->map_cpu ? 0 : -ENOMEM;
 }
 
 /* Fake monspecs to fill in fbinfo structure */
-static struct fb_monspecs monspecs = {
+#if 0
+static struct fb_monspecs monspecs __initdata = {
 	30000, 70000, 50, 65, 0	/* Generic */
 };
+#endif
+
 
 
-static struct pxafb_info * pxafb_init_fbinfo(struct pxafb_mach_info *inf)
+static struct pxafb_info * __init pxafb_init_fbinfo(struct device *dev)
 {
 	struct pxafb_info *fbi;
+	void *addr;
+	struct pxafb_mach_info *inf = dev->platform_data;
 
-	fbi = kmalloc(sizeof(struct pxafb_info) + sizeof(u32) * 16,
-		      GFP_KERNEL);
+	/* Alloc the pxafb_info and pseudo_palette in one step */
+	fbi = kmalloc(sizeof(struct pxafb_info) + sizeof(u32) * 17, GFP_KERNEL);
 	if (!fbi)
 		return NULL;
 
-	memset(fbi, 0, sizeof(struct pxafb_info) + sizeof(struct pxafb_info));
+	memset(fbi, 0, sizeof(struct pxafb_info));
+	fbi->dev = dev;
 
 	strcpy(fbi->fb.fix.id, PXA_NAME);
 
@@ -1066,26 +1115,15 @@
 
 	fbi->fb.fbops		= &pxafb_ops;
 	fbi->fb.flags		= FBINFO_FLAG_DEFAULT;
+	fbi->fb.node		= -1;
+#if 0
 	fbi->fb.monspecs	= monspecs;
+#endif
 	fbi->fb.currcon		= -1;
-	fbi->fb.pseudo_palette	= (fbi + 1);
-
-	fbi->rgb[RGB_8]		= &rgb_8;
-	fbi->rgb[RGB_16]	= &def_rgb_16;
-
-	DPRINTK("inf=%p inf->xres=%d inf->yres=%d inf->bpp=%d\n", inf, inf->xres, inf->yres, inf->bpp);
 
-#ifdef YES_I_GET_IT_PLEASE_WHINE_AT_ME	
-	/*
-	 * People just don't seem to get this.  We don't support
-	 * anything but correct entries now, so panic if someone
-	 * does something stupid.
-	 */
-	if (inf->lccr3 & (LCCR3_VrtSnchL|LCCR3_HorSnchL|0xff) ||
-	    inf->pixclock == 0)
-		panic("pxafb error: invalid LCCR3 fields set or zero "
-			"pixclock.");
-#endif
+	addr = fbi;
+	addr = addr + sizeof(struct pxafb_info);
+	fbi->fb.pseudo_palette	= addr;
 
 	fbi->max_xres			= inf->xres;
 	fbi->fb.var.xres		= inf->xres;
@@ -1120,16 +1158,123 @@
 	return fbi;
 }
 
+static int __init pxafb_parse_options(struct device *dev, struct pxafb_mach_info *inf, char *options)
+{
+	/*  
+	*/
+        char *this_opt;
+ 
+        if (!options || !*options)
+                return 0;
+
+	dev_dbg(dev, "options are \"%s\"\n", options ? options : "null");
+
+	/* could be made table driven or similar?... */
+        while ((this_opt = strsep(&options, ",")) != NULL) {
+                if (!strncmp(this_opt, "xres:", 5)) {
+                        inf->xres = simple_strtoul(this_opt+5, NULL, 0);
+			dev_info(dev, "override xres: %d\n", inf->xres);
+                } else if (!strncmp(this_opt, "yres:", 5)) {
+                        inf->yres = simple_strtoul(this_opt+5, NULL, 0);
+			dev_info(dev, "override yres: %d\n", inf->yres);
+                } else if (!strncmp(this_opt, "bpp:", 4)) {
+                        inf->bpp = simple_strtoul(this_opt+4, NULL, 0);
+			dev_info(dev, "override bpp: %d\n", inf->bpp);
+                } else if (!strncmp(this_opt, "pixclock:", 9)) {
+                        inf->pixclock = simple_strtoul(this_opt+9, NULL, 0);
+			dev_info(dev, "override pixclock: %uld\n", inf->pixclock);
+                } else if (!strncmp(this_opt, "left:", 5)) {
+                        inf->left_margin = simple_strtoul(this_opt+5, NULL, 0);
+			dev_info(dev, "override left: %d\n", inf->left_margin);
+                } else if (!strncmp(this_opt, "right:", 6)) {
+                        inf->right_margin = simple_strtoul(this_opt+6, NULL, 0);
+			dev_info(dev, "override right: %d\n", inf->right_margin);
+                } else if (!strncmp(this_opt, "upper:", 6)) {
+                        inf->upper_margin = simple_strtoul(this_opt+6, NULL, 0);
+			dev_info(dev, "override upper: %d\n", inf->upper_margin);
+                } else if (!strncmp(this_opt, "lower:", 6)) {
+                        inf->lower_margin = simple_strtoul(this_opt+6, NULL, 0);
+			dev_info(dev, "override lower: %d\n", inf->lower_margin);
+                } else if (!strncmp(this_opt, "hsynclen:", 9)) {
+                        inf->hsync_len = simple_strtoul(this_opt+9, NULL, 0);
+			dev_info(dev, "override hsynclen: %d\n", inf->hsync_len);
+                } else if (!strncmp(this_opt, "vsynclen:", 9)) {
+                        inf->vsync_len = simple_strtoul(this_opt+9, NULL, 0);
+			dev_info(dev, "override vsynclen: %d\n", inf->vsync_len);
+                } else if (!strncmp(this_opt, "hsync:", 6)) {
+                        if ( simple_strtoul(this_opt+6, NULL, 0) == 0 ) {
+				dev_info(dev, "override hsync: Active Low\n");
+				inf->sync &= ~FB_SYNC_HOR_HIGH_ACT;
+			} else {
+				dev_info(dev, "override hsync: Active High\n");
+				inf->sync |= FB_SYNC_HOR_HIGH_ACT;
+			}
+                } else if (!strncmp(this_opt, "vsync:", 6)) {
+                        if ( simple_strtoul(this_opt+6, NULL, 0) == 0 ) {
+				dev_info(dev, "override vsync: Active Low\n");
+				inf->sync &= ~FB_SYNC_VERT_HIGH_ACT;
+			} else {
+				dev_info(dev, "override vsync: Active High\n");
+				inf->sync |= FB_SYNC_VERT_HIGH_ACT;
+			}
+                } else if (!strncmp(this_opt, "dpc:", 4)) {
+                        if ( simple_strtoul(this_opt+4, NULL, 0) == 0 ) {
+				dev_info(dev, "override double pixel clock: false\n");
+				inf->lccr3 &= ~LCCR3_DPC;
+			} else {
+				dev_info(dev, "override double pixel clock: true\n");
+				inf->lccr3 |= LCCR3_DPC;
+			}
+                } else if (!strncmp(this_opt, "outputen:", 9)) {
+                        if ( simple_strtoul(this_opt+9, NULL, 0) == 0 ) {
+				dev_info(dev, "override output enable: active low\n");
+				inf->lccr3 = ( inf->lccr3 & ~LCCR3_OEP ) | LCCR3_OutEnL;
+			} else {
+				dev_info(dev, "override output enable: active high\n");
+				inf->lccr3 = ( inf->lccr3 & ~LCCR3_OEP ) | LCCR3_OutEnH;
+			}
+                } else if (!strncmp(this_opt, "pixclockpol:", 12)) {
+                        if ( simple_strtoul(this_opt+12, NULL, 0) == 0 ) {
+				dev_info(dev, "override pixel clock polarity: falling edge\n");
+				inf->lccr3 = ( inf->lccr3 & ~LCCR3_PCP ) | LCCR3_PixFlEdg;
+			} else {
+				dev_info(dev, "override pixel clock polarity: rising edge\n");
+				inf->lccr3 = ( inf->lccr3 & ~LCCR3_PCP ) | LCCR3_PixRsEdg;
+			}
+                } else if (!strncmp(this_opt, "color", 5)) {
+			inf->lccr0 = (inf->lccr0 & ~LCCR0_CMS) | LCCR0_Color;
+                } else if (!strncmp(this_opt, "mono", 4)) {
+			inf->lccr0 = (inf->lccr0 & ~LCCR0_CMS) | LCCR0_Mono;
+                } else if (!strncmp(this_opt, "active", 6)) {
+			inf->lccr0 = (inf->lccr0 & ~LCCR0_PAS) | LCCR0_Act;
+                } else if (!strncmp(this_opt, "passive", 7)) {
+			inf->lccr0 = (inf->lccr0 & ~LCCR0_PAS) | LCCR0_Pas;
+                } else if (!strncmp(this_opt, "single", 6)) {
+			inf->lccr0 = (inf->lccr0 & ~LCCR0_SDS) | LCCR0_Sngl;
+                } else if (!strncmp(this_opt, "dual", 4)) {
+			inf->lccr0 = (inf->lccr0 & ~LCCR0_SDS) | LCCR0_Dual;
+                } else if (!strncmp(this_opt, "4pix", 4)) {
+			inf->lccr0 = (inf->lccr0 & ~LCCR0_DPD) | LCCR0_4PixMono;
+                } else if (!strncmp(this_opt, "8pix", 4)) {
+			inf->lccr0 = (inf->lccr0 & ~LCCR0_DPD) | LCCR0_8PixMono;
+		} else {
+			dev_err(dev, "unknown option: %s\n", this_opt);
+			return -EINVAL;
+		}
+        }
+        return 0;
+}
+
 static void pxafb_startup(struct device *dev);
 static struct device *deferred_dev;
-static struct notifier_block notify;
+static struct notifer_block notify;
 
-static int pxafb_notifier_call (struct notifier_block *self, unsigned long a, void *b)
+static int pxafb_notifier_call(struct notifier_block *self, unsigned long a, void *b)
 {
-	notifier_chain_unregister (&lcd_device_chain, self);
-
-	pxafb_startup (deferred_dev);
-
+	notifer_chain_unregister(&lcd_device_chain, self);
+	
+	pxafb_startup(deferred_dev);
+	
 	return NOTIFY_OK;
 }
 
@@ -1142,31 +1287,77 @@
 	notifier_chain_register (&lcd_device_chain, &notify);
 }
 
-static void pxafb_startup(struct device *dev)
+int __init pxafb_probe(struct device *dev)
 {
-	struct pxafb_info *fbi = NULL;
+	struct pxafb_info *fbi;
 	struct pxafb_mach_info *inf;
 	int ret;
 
-	inf = pxafb_get_machine_info ();
+	dev_dbg(dev, "pxafb_probe\n");
+
+	inf = dev->platform_data;
+	ret = -ENOMEM;
+	fbi = NULL;
 	if (!inf)
 		goto failed;
 
-	fbi = pxafb_init_fbinfo(inf);
+	ret = pxafb_parse_options(dev, inf, g_options);
+	if ( ret < 0 )
+		goto failed;
 
-	if (!fbi)
+#ifdef DEBUG_VAR
+        /* Check for various illegal bit-combinations. Currently only
+	 * a warning is given. */
+ 
+        if ( inf->lccr0 & LCCR0_INVALID_CONFIG_MASK )
+                dev_warn(dev, "machine LCCR0 setting contains illegal bits: %08x\n",
+                        inf->lccr0 & LCCR0_INVALID_CONFIG_MASK);
+        if ( inf->lccr3 & LCCR3_INVALID_CONFIG_MASK )
+                dev_warn(dev, "machine LCCR3 setting contains illegal bits: %08x\n",
+                        inf->lccr3 & LCCR3_INVALID_CONFIG_MASK);
+        if ( inf->lccr0 & LCCR0_DPD &&
+             ( ( inf->lccr0 & LCCR0_PAS ) != LCCR0_Pas ||
+               ( inf->lccr0 & LCCR0_SDS ) != LCCR0_Sngl ||
+               ( inf->lccr0 & LCCR0_CMS ) != LCCR0_Mono ) )
+                dev_warn(dev, "Double Pixel Data (DPD) mode is only valid in passive mono"
+			 " single panel mode\n");
+        if ( (inf->lccr0 & LCCR0_PAS) == LCCR0_Act &&
+             ( inf->lccr0 & LCCR0_SDS ) == LCCR0_Dual )
+                dev_warn(dev, "Dual panel only valid in passive mode\n");
+        if ( (inf->lccr0 & LCCR0_PAS ) == LCCR0_Pas &&
+             (inf->upper_margin || inf->lower_margin) )
+                dev_warn(dev, "Upper and lower margins must be 0 in passive mode\n");
+#endif
+
+	dev_dbg(dev, "got a %dx%dx%d LCD\n",inf->xres, inf->yres, inf->bpp);
+	if (inf->xres == 0 || inf->yres == 0 || inf->bpp == 0) {
+		dev_err(dev, "Invalid resolution or bit depth\n");
+		ret = -EINVAL;
 		goto failed;
+	}
+	pxafb_backlight_power = inf->pxafb_backlight_power;
+	pxafb_lcd_power = inf->pxafb_lcd_power;
+	fbi = pxafb_init_fbinfo(dev);
+	if (!fbi) {
+		dev_err(dev, "Failed to initialize framebuffer device\n");
+		ret = -ENOMEM; // only reason for pxafb_init_fbinfo to fail is kmalloc
+		goto failed;
+	}
 
 	/* Initialize video memory */
 	ret = pxafb_map_video_memory(fbi);
-
-	if (ret)
+	if (ret) {
+		dev_err(dev, "Failed to allocate video RAM: %d\n", ret);
+		ret = -ENOMEM;
 		goto failed;
+	}
+	/* enable LCD controller clock */
+	CKEN |= CKEN16_LCD;
 
-	ret = request_irq(IRQ_LCD, pxafb_handle_irq, SA_INTERRUPT,
-			  "LCD", fbi);
+	ret = request_irq(IRQ_LCD, pxafb_handle_irq, SA_INTERRUPT, "LCD", fbi);
 	if (ret) {
-		printk(KERN_ERR "pxafb: failed in request_irq: %d\n", ret);
+		dev_err(dev, "request_irq failed: %d\n", ret);
+		ret = -EBUSY;
 		goto failed;
 	}
 
@@ -1175,18 +1366,19 @@
 	 * descriptors are correctly initialised.
 	 */
 	pxafb_check_var(&fbi->fb.var, &fbi->fb);
-	
-	dev_set_drvdata(dev, fbi);
+	pxafb_set_par(&fbi->fb);
 
-#ifdef CONFIG_LCD_DEVICE
-	fbi->lm = lcd_device_get(lcd_device_find("pxafb"));
-	fbi->bm = backlight_device_get(backlight_device_find("pxafb"));
-#endif
+	dev_set_drvdata(dev, fbi);
 
 	ret = register_framebuffer(&fbi->fb);
-
-	if (ret < 0)
+	if (ret < 0) {
+		dev_err(dev, "Failed to register framebuffer device: %d\n", ret);
 		goto failed;
+	}
+
+#ifdef CONFIG_PM
+	// TODO
+#endif
 
 #ifdef CONFIG_CPU_FREQ
 	fbi->freq_transition.notifier_call = pxafb_freq_transition;
@@ -1195,47 +1387,53 @@
 	cpufreq_register_notifier(&fbi->freq_policy, CPUFREQ_POLICY_NOTIFIER);
 #endif
 
-	/* This driver cannot be unloaded at the moment */
-	try_module_get(THIS_MODULE);	
+	/*
+	 * Ok, now enable the LCD controller
+	 */
+	set_ctrlr_state(fbi, C_ENABLE);
 
-	return;
+	return 0;
 
 failed:
 	dev_set_drvdata(dev, NULL);
 	if (fbi)
 		kfree(fbi);
-	DPRINTK("pxafb: deferring startup\n");
-	pxafb_defer_startup (dev);
-}
-
-static int __init pxafb_probe(struct device *dev)
-{
-	
-	if (!request_mem_region(0x44000000, 0x10000, "LCD"))
-		return -EBUSY;
-
-	pxafb_startup (dev);
-
-	return 0;
+	return ret;
 }
 
 static struct device_driver pxafb_driver = {
-	.name		= "pxa-fb",
+	.name		= "pxafb",
 	.bus		= &platform_bus_type,
 	.probe		= pxafb_probe,
+#ifdef CONFIG_PM
 	.suspend	= pxafb_suspend,
 	.resume		= pxafb_resume,
+#endif
 };
 
-int __init pxafb_init(void)
+int __devinit pxafb_init(void)
 {
 	return driver_register(&pxafb_driver);
 }
 
-
-#ifdef MODULE
+#ifndef MODULE
+int __devinit pxafb_setup(char *options)
+{
+	long opsi = strlen(options);
+	
+	memcpy(g_options, options,
+	       ((opsi + 1) >
+		PXAFB_OPTIONS_SIZE) ? PXAFB_OPTIONS_SIZE : (opsi + 1));
+	g_options[PXAFB_OPTIONS_SIZE - 1] = 0;
+	
+	return 0;
+}
+#else
 module_init(pxafb_init);
+module_param_string(options, g_options, sizeof(g_options), 0);
+MODULE_PARM_DESC(options, "LCD parameters (see Documentation/fb/pxafb.txt)");
 #endif
 
+
 MODULE_DESCRIPTION("loadable framebuffer driver for PXA");
 MODULE_LICENSE("GPL");
