 drivers/video/Kconfig               |   18 
 drivers/video/Makefile              |    1 
 drivers/video/pxafb.c               |  305 +++++--
 drivers/video/pxafb.h               |   65 +
 drivers/video/pxafb_overlay.c       | 1525 ++++++++++++++++++++++++++++++++++++
 include/asm-arm/arch-pxa/pxa-regs.h |  111 ++
 6 files changed, 1969 insertions(+), 56 deletions(-)

--- linux-2.6.24-rc1.orig/drivers/video/Kconfig
+++ linux-2.6.24-rc1/drivers/video/Kconfig
@@ -1718,6 +1718,24 @@
 
 	  If unsure, say N.
 
+choice
+	prompt "PXA LCD type"
+	depends on FB_PXA
+
+config FB_PXA_LCD_QVGA
+        bool "QVGA(320x240)"
+
+config FB_PXA_LCD_VGA
+        bool "VGA (640x480)"
+
+endchoice
+
+config FB_PXA_OVERLAY
+    tristate "PXA LCD overlay support"
+    depends on FB_PXA
+    ---help---
+        Frame buffer overlay driver for PXA27x
+
 config FB_PXA_PARAMETERS
 	bool "PXA LCD command line parameters"
 	default n
--- linux-2.6.24-rc1.orig/drivers/video/Makefile
+++ linux-2.6.24-rc1/drivers/video/Makefile
@@ -96,6 +96,7 @@
 obj-$(CONFIG_FB_CIRRUS)		  += cirrusfb.o
 obj-$(CONFIG_FB_ASILIANT)	  += asiliantfb.o
 obj-$(CONFIG_FB_PXA)		  += pxafb.o
+obj-$(CONFIG_FB_PXA_OVERLAY)	  += pxafb_overlay.o
 obj-$(CONFIG_FB_W100)		  += w100fb.o
 obj-$(CONFIG_FB_AU1100)		  += au1100fb.o
 obj-$(CONFIG_FB_AU1200)		  += au1200fb.o
--- linux-2.6.24-rc1.orig/drivers/video/pxafb.c
+++ linux-2.6.24-rc1/drivers/video/pxafb.c
@@ -59,17 +59,49 @@
 #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)
 
+wait_queue_head_t fcs_wait_eof;
+int fcs_in_eof;
+static DECLARE_MUTEX(fcs_lcd_sem);
+
 static void (*pxafb_backlight_power)(int);
 static void (*pxafb_lcd_power)(int, struct fb_var_screeninfo *);
 
 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);
+void pxafb_set_ctrlr_state(struct pxafb_info *fbi, u_int state);
 
 #ifdef CONFIG_FB_PXA_PARAMETERS
 #define PXAFB_OPTIONS_SIZE 256
 static char g_options[PXAFB_OPTIONS_SIZE] __devinitdata = "";
 #endif
 
+static struct pxafb_rgb def_rgb_8 = {
+	red:    { offset: 0,  length: 8, },
+	green:  { offset: 0,  length: 8, },
+	blue:   { offset: 0,  length: 8, },
+	transp: { offset: 0,  length: 0, },
+};
+
+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, },
+};
+
+static struct pxafb_rgb def_rgb_18 = {
+	red:    { offset: 12, length: 6, },
+	green:  { offset: 6,  length: 6, },
+	blue:   { offset: 0,  length: 6, },
+	transp: { offset: 0,  length: 0, },
+};
+
+static struct pxafb_rgb def_rgb_24 = {
+	red:    { offset: 16, length: 8, },
+	green:  { offset: 8,  length: 8, },
+	blue:   { offset: 0,  length: 8, },
+	transp: { offset: 0,  length: 0, },
+};
+
 static inline void pxafb_schedule_work(struct pxafb_info *fbi, u_int state)
 {
 	unsigned long flags;
@@ -209,6 +241,10 @@
         case 4:  ret = LCCR3_4BPP; break;
         case 8:  ret = LCCR3_8BPP; break;
         case 16: ret = LCCR3_16BPP; break;
+        case 18: ret = LCCR3_18BPP; break;
+        case 19: ret = LCCR3_19BPP; break;
+        case 24: ret = LCCR3_24BPP; break;
+        case 25: ret = LCCR3_25BPP; break;
         }
         return ret;
 }
@@ -320,18 +356,34 @@
 	 * 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;
-	}
+    	switch (var->bits_per_pixel) {
+    	case 16:
+        	/* 2 pixels per line */
+        	var->red    = def_rgb_16.red;
+        	var->green  = def_rgb_16.green;
+        	var->blue   = def_rgb_16.blue;
+        	var->transp = def_rgb_16.transp;
+        	break;
+    	case 18:
+    	case 19:
+        	var->red    = def_rgb_18.red;
+        	var->green  = def_rgb_18.green;
+        	var->blue   = def_rgb_18.blue;
+        	var->transp = def_rgb_18.transp;
+        	break;
+    	case 24:
+    	case 25:
+        	var->red    = def_rgb_24.red;
+        	var->green  = def_rgb_24.green;
+        	var->blue   = def_rgb_24.blue;
+        	var->transp = def_rgb_24.transp;
+        	break;
+	 default:
+        	var->red    = def_rgb_8.red;
+        	var->green  = def_rgb_8.green;
+        	var->blue   = def_rgb_8.blue;
+        	var->transp = def_rgb_8.transp;
+    }
 
 #ifdef CONFIG_CPU_FREQ
 	pr_debug("pxafb: dma period = %d ps, clock = %d kHz\n",
@@ -345,7 +397,7 @@
 static inline void pxafb_set_truecolor(u_int is_true_color)
 {
 	pr_debug("pxafb: true_color = %d\n", is_true_color);
-	// do your machine-specific setup if needed
+	/* do your machine-specific setup if needed */
 }
 
 /*
@@ -360,7 +412,8 @@
 
 	pr_debug("pxafb: set_par\n");
 
-	if (var->bits_per_pixel == 16)
+    	if (var->bits_per_pixel == 16 || var->bits_per_pixel == 18 ||var->bits_per_pixel == 19
+        || var->bits_per_pixel == 24 || var->bits_per_pixel == 25)
 		fbi->fb.fix.visual = FB_VISUAL_TRUECOLOR;
 	else if (!fbi->cmap_static)
 		fbi->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
@@ -373,12 +426,25 @@
 		fbi->fb.fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
 	}
 
-	fbi->fb.fix.line_length = var->xres_virtual *
-				  var->bits_per_pixel / 8;
-	if (var->bits_per_pixel == 16)
-		fbi->palette_size = 0;
-	else
-		fbi->palette_size = var->bits_per_pixel == 1 ? 4 : 1 << var->bits_per_pixel;
+    	switch (var->bits_per_pixel) {
+    	case 16:
+       	fbi->fb.fix.line_length = var->xres_virtual * 2;
+       	fbi->palette_size = 0;
+        	break;
+    	case 18:
+    	case 19:
+       	fbi->fb.fix.line_length = var->xres_virtual * 3;
+       	fbi->palette_size = 0;
+        	break;
+    	case 24:
+    	case 25:
+        	fbi->fb.fix.line_length = var->xres_virtual * 4;
+        	fbi->palette_size = 0;
+        	break;
+    	default:
+        	fbi->fb.fix.line_length = var->xres_virtual * var->bits_per_pixel / 8;
+        	fbi->palette_size = var->bits_per_pixel == 1 ? 4 : 1 << var->bits_per_pixel;
+    	}
 
 	if ((fbi->lccr4 & LCCR4_PAL_FOR_MASK) == LCCR4_PAL_FOR_0)
 		palette_mem_size = fbi->palette_size * sizeof(u16);
@@ -395,7 +461,8 @@
 	 */
 	pxafb_set_truecolor(fbi->fb.fix.visual == FB_VISUAL_TRUECOLOR);
 
-	if (fbi->fb.var.bits_per_pixel == 16)
+	if (fbi->fb.var.bits_per_pixel == 16 || fbi->fb.var.bits_per_pixel == 18 ||fbi->fb.var.bits_per_pixel == 19
+        || fbi->fb.var.bits_per_pixel == 24 || fbi->fb.var.bits_per_pixel == 25)
 		fb_dealloc_cmap(&fbi->fb.cmap);
 	else
 		fb_alloc_cmap(&fbi->fb.cmap, 1<<fbi->fb.var.bits_per_pixel, 0);
@@ -441,7 +508,7 @@
  * 	16 bpp mode does not really use the palette, so this will not
  *      blank the display in all modes.
  */
-static int pxafb_blank(int blank, struct fb_info *info)
+int pxafb_blank(int blank, struct fb_info *info)
 {
 	struct pxafb_info *fbi = (struct pxafb_info *)info;
 	int i;
@@ -458,19 +525,20 @@
 			for (i = 0; i < fbi->palette_size; i++)
 				pxafb_setpalettereg(i, 0, 0, 0, 0, info);
 
-		pxafb_schedule_work(fbi, C_DISABLE);
-		//TODO if (pxafb_blank_helper) pxafb_blank_helper(blank);
+		pxafb_schedule_work(fbi, C_BLANK);
+		/* TODO if (pxafb_blank_helper) pxafb_blank_helper(blank); */
 		break;
 
 	case FB_BLANK_UNBLANK:
-		//TODO if (pxafb_blank_helper) pxafb_blank_helper(blank);
+		/* TODO if (pxafb_blank_helper) pxafb_blank_helper(blank); */
 		if (fbi->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR ||
 		    fbi->fb.fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
 			fb_set_cmap(&fbi->fb.cmap, info);
-		pxafb_schedule_work(fbi, C_ENABLE);
+		pxafb_schedule_work(fbi, C_UNBLANK);
 	}
 	return 0;
 }
+EXPORT_SYMBOL(pxafb_blank);
 
 static int pxafb_mmap(struct fb_info *info,
 		      struct vm_area_struct *vma)
@@ -606,6 +674,10 @@
 	case 4:
 	case 8:
 	case 16:
+    	case 18:
+    	case 19:
+    	case 24:
+    	case 25:
 		break;
 	default:
 		printk(KERN_ERR "%s: invalid bit depth %d\n",
@@ -637,7 +709,10 @@
 
 	new_regs.lccr0 = fbi->lccr0 |
 		(LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM |
-                 LCCR0_QDM | LCCR0_BM  | LCCR0_OUM);
+#ifdef CONFIG_PXA27x	/* Enable overlay for PXA27x */
+		 LCCR0_OUC | LCCR0_CMDIM | LCCR0_RDSTM |
+#endif
+                 LCCR0_QDM | LCCR0_BM | LCCR0_OUM);
 
 	new_regs.lccr1 =
 		LCCR1_DisWdth(var->xres) +
@@ -696,7 +771,7 @@
 
 	fbi->dmadesc_fbhigh_cpu->fsadr = fbi->screen_dma;
 	fbi->dmadesc_fbhigh_cpu->fidr = 0;
-	fbi->dmadesc_fbhigh_cpu->ldcmd = BYTES_PER_PANEL;
+	fbi->dmadesc_fbhigh_cpu->ldcmd = BYTES_PER_PANEL | LDCMD_EOFINT;
 
 	fbi->dmadesc_palette_cpu->fsadr = fbi->palette_dma;
 	fbi->dmadesc_palette_cpu->fidr  = 0;
@@ -708,7 +783,8 @@
 							sizeof(u32);
 	fbi->dmadesc_palette_cpu->ldcmd |= LDCMD_PAL;
 
-	if (var->bits_per_pixel == 16) {
+	if (var->bits_per_pixel == 16 || var->bits_per_pixel == 18 ||var->bits_per_pixel == 19
+        || var->bits_per_pixel == 24 || var->bits_per_pixel == 25) {
 		/* 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 */
@@ -763,8 +839,8 @@
 }
 
 /*
- * NOTE!  The following functions are purely helpers for set_ctrlr_state.
- * Do not call them directly; set_ctrlr_state does the correct serialisation
+ * NOTE!  The following functions are purely helpers for pxafb_set_ctrlr_state.
+ * Do not call them directly; pxafb_set_ctrlr_state does the correct serialisation
  * to ensure that things happen in the right way 100% of time time.
  *	-- rmk
  */
@@ -786,7 +862,8 @@
 
 static void pxafb_setup_gpio(struct pxafb_info *fbi)
 {
-	int gpio, ldd_bits;
+	int gpio;
+	int ldd_bits = 0;
         unsigned int lccr0 = fbi->lccr0;
 
 	/*
@@ -796,28 +873,56 @@
 	/* 4 bit interface */
 	if ((lccr0 & LCCR0_CMS) == LCCR0_Mono &&
 	    (lccr0 & LCCR0_SDS) == LCCR0_Sngl &&
-	    (lccr0 & LCCR0_DPD) == LCCR0_4PixMono)
+	    (lccr0 & LCCR0_DPD) == LCCR0_4PixMono) {
 		ldd_bits = 4;
-
+	}
 	/* 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))
+		  (lccr0 & LCCR0_PAS) == LCCR0_Pas && (lccr0 & LCCR0_SDS) == LCCR0_Sngl)) {
 		ldd_bits = 8;
-
+	}
 	/* 16 bit interface */
-	else if ((lccr0 & LCCR0_CMS) == LCCR0_Color &&
-		 ((lccr0 & LCCR0_SDS) == LCCR0_Dual || (lccr0 & LCCR0_PAS) == LCCR0_Act))
-		ldd_bits = 16;
+    	else if ((lccr0 & LCCR0_CMS) == LCCR0_Color &&
+         	((lccr0 & LCCR0_SDS) == LCCR0_Dual || (lccr0 & LCCR0_PAS) == LCCR0_Act)) {
+        	switch (fbi->fb.var.bits_per_pixel) {
+        	case 16:
+#ifdef CONFIG_PXA27x
+			/* bits 58-77 */
+            		GPDR1 |= (0x3f << 26);
+            		GPDR2 |= 0x00003fff;
 
+            		GAFR1_U = (GAFR1_U & ~(0xfff << 20)) | (0xaaa << 20);
+            		GAFR2_L = (GAFR2_L & 0xf0000000) | 0x0aaaaaaa;
+#endif
+			ldd_bits = 16;
+            		break;
+        	case 18:
+        	case 19:
+        	case 24:
+        	case 25:
+#ifdef CONFIG_PXA27x
+			/* bits 58-77 and 86, 87 */
+            		GPDR1 |= (0x3f << 26);
+            		GPDR2 |= 0x00c03fff;
+
+            		GAFR1_U = (GAFR1_U & ~(0xfff << 20)) | (0xaaa << 20);
+            		GAFR2_L = (GAFR2_L & 0xf0000000) | 0x0aaaaaaa;
+            		GAFR2_U = (GAFR2_U & 0xffff0fff) | 0xa000;
+#endif
+			ldd_bits = 25;
+            		break;
+        	}
+    	}
 	else {
 	        printk(KERN_ERR "pxafb_setup_gpio: unable to determine bits per pixel\n");
 		return;
         }
 
-	for (gpio = 58; ldd_bits; gpio++, ldd_bits--)
+	for (gpio = 58; ldd_bits > 0; gpio++, ldd_bits--) {
 		pxa_gpio_mode(gpio | GPIO_ALT_FN_2_OUT);
+	}
 	pxa_gpio_mode(GPIO74_LCD_FCLK_MD);
 	pxa_gpio_mode(GPIO75_LCD_LCLK_MD);
 	pxa_gpio_mode(GPIO76_LCD_PCLK_MD);
@@ -837,6 +942,7 @@
 	/* enable LCD controller clock */
 	clk_enable(fbi->clk);
 
+	down(&fcs_lcd_sem);
 	/* Sequence from 11.7.10 */
 	LCCR3 = fbi->reg_lccr3;
 	LCCR2 = fbi->reg_lccr2;
@@ -847,6 +953,8 @@
 	FDADR1 = fbi->fdadr1;
 	LCCR0 |= LCCR0_ENB;
 
+	up(&fcs_lcd_sem);
+
 	pr_debug("FDADR0 0x%08x\n", (unsigned int) FDADR0);
 	pr_debug("FDADR1 0x%08x\n", (unsigned int) FDADR1);
 	pr_debug("LCCR0 0x%08x\n", (unsigned int) LCCR0);
@@ -862,6 +970,7 @@
 
 	pr_debug("pxafb: disabling LCD controller\n");
 
+	down(&fcs_lcd_sem);
 	set_current_state(TASK_UNINTERRUPTIBLE);
 	add_wait_queue(&fbi->ctrlr_wait, &wait);
 
@@ -871,6 +980,7 @@
 
 	schedule_timeout(200 * HZ / 1000);
 	remove_wait_queue(&fbi->ctrlr_wait, &wait);
+	up(&fcs_lcd_sem);
 
 	/* disable LCD controller clock */
 	clk_disable(fbi->clk);
@@ -888,6 +998,11 @@
 		LCCR0 |= LCCR0_LDM;
 		wake_up(&fbi->ctrlr_wait);
 	}
+	if (lcsr & LCSR_EOF && fcs_in_eof) {
+		LCCR0 |= LCCR0_EFM;
+		fcs_in_eof = 0;
+		wake_up(&fcs_wait_eof);
+	}
 
 	LCSR = lcsr;
 	return IRQ_HANDLED;
@@ -898,7 +1013,7 @@
  * sleep when disabling the LCD controller, or if we get two contending
  * processes trying to alter state.
  */
-static void set_ctrlr_state(struct pxafb_info *fbi, u_int state)
+void pxafb_set_ctrlr_state(struct pxafb_info *fbi, u_int state)
 {
 	u_int old_state;
 
@@ -920,7 +1035,9 @@
 		 */
 		if (old_state != C_DISABLE && old_state != C_DISABLE_PM) {
 			fbi->state = state;
-			//TODO __pxafb_lcd_power(fbi, 0);
+			/* TODO __pxafb_lcd_power(fbi, 0); */
+			if(fbi->set_overlay_ctrlr_state)
+				fbi->set_overlay_ctrlr_state(fbi, C_DISABLE);
 			pxafb_disable_controller(fbi);
 		}
 		break;
@@ -934,6 +1051,8 @@
 			fbi->state = state;
 			__pxafb_backlight_power(fbi, 0);
 			__pxafb_lcd_power(fbi, 0);
+			if(fbi->set_overlay_ctrlr_state)
+				fbi->set_overlay_ctrlr_state(fbi, C_DISABLE);
 			if (old_state != C_DISABLE_CLKCHANGE)
 				pxafb_disable_controller(fbi);
 		}
@@ -947,7 +1066,9 @@
 		if (old_state == C_DISABLE_CLKCHANGE) {
 			fbi->state = C_ENABLE;
 			pxafb_enable_controller(fbi);
-			//TODO __pxafb_lcd_power(fbi, 1);
+			/* TODO __pxafb_lcd_power(fbi, 1); */
+			if(fbi->set_overlay_ctrlr_state)
+				fbi->set_overlay_ctrlr_state(fbi, C_ENABLE);
 		}
 		break;
 
@@ -959,9 +1080,13 @@
 		 */
 		if (old_state == C_ENABLE) {
 			__pxafb_lcd_power(fbi, 0);
+			if(fbi->set_overlay_ctrlr_state)
+				fbi->set_overlay_ctrlr_state(fbi, C_DISABLE);
 			pxafb_disable_controller(fbi);
 			pxafb_setup_gpio(fbi);
 			pxafb_enable_controller(fbi);
+			if(fbi->set_overlay_ctrlr_state)
+				fbi->set_overlay_ctrlr_state(fbi, C_ENABLE);
 			__pxafb_lcd_power(fbi, 1);
 		}
 		break;
@@ -987,11 +1112,46 @@
 			pxafb_enable_controller(fbi);
 			__pxafb_lcd_power(fbi, 1);
 			__pxafb_backlight_power(fbi, 1);
+			if(fbi->set_overlay_ctrlr_state)
+				fbi->set_overlay_ctrlr_state(fbi, C_ENABLE);
 		}
 		break;
+
+	case C_BLANK:
+		/*
+		 * Disable controller, blank overlays if exist.
+		 */
+		if ((old_state != C_DISABLE) && (old_state != C_BLANK)) {
+			fbi->state = state;
+			__pxafb_backlight_power(fbi, 0);
+			__pxafb_lcd_power(fbi, 0);
+			if(fbi->set_overlay_ctrlr_state)
+				fbi->set_overlay_ctrlr_state(fbi, C_BLANK);
+			if (old_state != C_DISABLE_CLKCHANGE)
+				pxafb_disable_controller(fbi);
+		}
+		break;
+
+	case C_UNBLANK:
+		/*
+		 * Power up the LCD screen, enable controller, and
+		 * turn on the backlight, unblank overlays if exist.
+		 */
+		if ((old_state != C_ENABLE) && (old_state != C_UNBLANK)) {
+			fbi->state = C_UNBLANK;
+			pxafb_setup_gpio(fbi);
+			pxafb_enable_controller(fbi);
+			__pxafb_lcd_power(fbi, 1);
+			__pxafb_backlight_power(fbi, 1);
+			if(fbi->set_overlay_ctrlr_state)
+				fbi->set_overlay_ctrlr_state(fbi, C_UNBLANK);
+		}
+		break;
+
 	}
 	up(&fbi->ctrlr_sem);
 }
+EXPORT_SYMBOL(pxafb_set_ctrlr_state);
 
 /*
  * Our LCD controller task (which is called when we blank or unblank)
@@ -1003,7 +1163,7 @@
 		container_of(work, struct pxafb_info, task);
 	u_int state = xchg(&fbi->task_state, -1);
 
-	set_ctrlr_state(fbi, state);
+	pxafb_set_ctrlr_state(fbi, state);
 }
 
 #ifdef CONFIG_CPU_FREQ
@@ -1018,19 +1178,29 @@
 pxafb_freq_transition(struct notifier_block *nb, unsigned long val, void *data)
 {
 	struct pxafb_info *fbi = TO_INF(nb, freq_transition);
-	//TODO struct cpufreq_freqs *f = data;
+	/* TODO struct cpufreq_freqs *f = data; */
+	struct cpufreq_freqs *clkinfo;
 	u_int pcd;
+	u_int lccr3;
 
 	switch (val) {
 	case CPUFREQ_PRECHANGE:
-		set_ctrlr_state(fbi, C_DISABLE_CLKCHANGE);
+		pxafb_set_ctrlr_state(fbi, C_DISABLE_CLKCHANGE);
 		break;
 
 	case CPUFREQ_POSTCHANGE:
-		pcd = get_pcd(fbi, fbi->fb.var.pixclock);
+		clkinfo = (struct cpufreq_freqs *)data;
+		/* If leaving a 13kHz state with the LCD sustained */
+		if ((clkinfo->old == 13000))
+			break;
+
+		pcd = get_pcd(fbi->fb.var.pixclock);
+		lccr3 = fbi->reg_lccr3;
 		set_hsync_time(fbi, pcd);
 		fbi->reg_lccr3 = (fbi->reg_lccr3 & ~0xff) | LCCR3_PixClkDiv(pcd);
-		set_ctrlr_state(fbi, C_ENABLE_CLKCHANGE);
+		pxafb_set_ctrlr_state(fbi, C_ENABLE_CLKCHANGE);
+		if (lccr3 != fbi->reg_lccr3 && !((LCCR0 & LCCR0_DIS) || !(LCCR0 & LCCR0_ENB)))
+			LCCR3 = fbi->reg_lccr3;
 		break;
 	}
 	return 0;
@@ -1049,7 +1219,7 @@
 		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
+		/* TODO: fill in min/max values */
 		break;
 #if 0
 	case CPUFREQ_NOTIFY:
@@ -1075,7 +1245,7 @@
 {
 	struct pxafb_info *fbi = platform_get_drvdata(dev);
 
-	set_ctrlr_state(fbi, C_DISABLE_PM);
+	pxafb_set_ctrlr_state(fbi, C_DISABLE_PM);
 	return 0;
 }
 
@@ -1083,7 +1253,11 @@
 {
 	struct pxafb_info *fbi = platform_get_drvdata(dev);
 
-	set_ctrlr_state(fbi, C_ENABLE_PM);
+	pxafb_set_ctrlr_state(fbi, C_ENABLE_PM);
+//RP#ifdef CONFIG_PXA27x
+//RP	LCCR4 |= (1 << 31); /* Disable the PCD Divisor, PCDDIV */
+//RP	LCCR4 |= (5 << 17); /* Undocumented feature */
+//RP#endif
 	return 0;
 }
 #else
@@ -1197,11 +1371,21 @@
 	fbi->task_state			= (u_char)-1;
 
 	for (i = 0; i < inf->num_modes; i++) {
-		smemlen = mode[i].xres * mode[i].yres * mode[i].bpp / 8;
+	     	if (mode[i].bpp <= 16) {       /* 8, 16 bpp */
+	         	smemlen = mode[i].xres * mode[i].yres * mode[i].bpp / 8;
+	     	} else if ( mode[i].bpp > 19 ) { /* 24, 25 bpp */
+	         	smemlen = mode[i].xres * mode[i].yres * 4;
+	     	} else {                          /* 18, 19 bpp */
+	         	/* packed format */
+	         	smemlen = mode[i].xres * mode[i].yres * 3;
+	     	}
+
 		if (smemlen > fbi->fb.fix.smem_len)
 			fbi->fb.fix.smem_len = smemlen;
 	}
 
+	fbi->set_overlay_ctrlr_state	= NULL;
+
 	init_waitqueue_head(&fbi->ctrlr_wait);
 	INIT_WORK(&fbi->task, pxafb_task);
 	init_MUTEX(&fbi->ctrlr_sem);
@@ -1268,6 +1452,10 @@
 				case 4:
 				case 8:
 				case 16:
+                		case 18:
+                		case 19:
+                		case 24:
+                		case 25:
 					inf->modes[0].bpp = bpp;
 					dev_info(dev, "overriding bit depth: %d\n", bpp);
 					break;
@@ -1416,7 +1604,7 @@
 	fbi = pxafb_init_fbinfo(&dev->dev);
 	if (!fbi) {
 		dev_err(&dev->dev, "Failed to initialize framebuffer device\n");
-		ret = -ENOMEM; // only reason for pxafb_init_fbinfo to fail is kmalloc
+		ret = -ENOMEM; /* only reason for pxafb_init_fbinfo to fail is kmalloc */
 		goto failed;
 	}
 
@@ -1451,7 +1639,7 @@
 	}
 
 #ifdef CONFIG_PM
-	// TODO
+	/* TODO */
 #endif
 
 #ifdef CONFIG_CPU_FREQ
@@ -1464,7 +1652,12 @@
 	/*
 	 * Ok, now enable the LCD controller
 	 */
-	set_ctrlr_state(fbi, C_ENABLE);
+	pxafb_set_ctrlr_state(fbi, C_ENABLE);
+//#ifdef CONFIG_PXA27x
+//	LCCR4 |= (1 << 31); /* Disabel the PCD Divisor, PCDDIV */
+//	LCCR4 |= (5 << 17); /* Undocumented feature */
+//#endif
+	init_waitqueue_head(&fcs_wait_eof);
 
 	return 0;
 
--- linux-2.6.24-rc1.orig/drivers/video/pxafb.h
+++ linux-2.6.24-rc1/drivers/video/pxafb.h
@@ -29,6 +29,60 @@
 	unsigned int lccr3;
 };
 
+struct pxafb_rgb {
+	struct fb_bitfield	red;
+	struct fb_bitfield	green;
+	struct fb_bitfield	blue;
+	struct fb_bitfield	transp;
+};
+
+#ifdef CONFIG_PXA27x
+/* PXA Overlay Framebuffer Support */
+struct overlayfb_info
+{
+	struct fb_info	fb;
+
+	struct fb_var_screeninfo old_var;
+
+	struct semaphore mutex;
+	unsigned long	 refcount;
+
+	struct pxafb_info *basefb;
+
+	unsigned long	map_cpu;
+	unsigned long 	screen_cpu;
+	unsigned long	palette_cpu;
+	unsigned long 	map_size;
+	unsigned long   palette_size;
+
+	dma_addr_t 	screen_dma;
+	dma_addr_t	map_dma;
+	dma_addr_t	palette_dma;
+
+	volatile u_char	state;
+
+	/* overlay specific info */
+	unsigned long	xpos;		/* screen position (x, y)*/
+	unsigned long	ypos;
+	unsigned long 	format;
+
+	/* additional */
+	union {
+		struct pxafb_dma_descriptor *dma0;
+		struct pxafb_dma_descriptor *dma1;
+		struct {
+			struct pxafb_dma_descriptor *dma2;
+			struct pxafb_dma_descriptor *dma3;
+			struct pxafb_dma_descriptor *dma4;
+		};
+		struct {
+			struct pxafb_dma_descriptor *dma5_pal;
+			struct pxafb_dma_descriptor *dma5_frame;
+		};
+	};
+};
+#endif
+
 /* PXA LCD DMA descriptor */
 struct pxafb_dma_descriptor {
 	unsigned int fdadr;
@@ -90,6 +144,14 @@
 	wait_queue_head_t	ctrlr_wait;
 	struct work_struct	task;
 
+#ifdef CONFIG_PXA27x
+	/* PXA Overlay Framebuffer Support */
+	struct overlayfb_info  *overlay1fb;
+	struct overlayfb_info  *overlay2fb;
+	struct overlayfb_info  *cursorfb;
+#endif
+	void (*set_overlay_ctrlr_state)(struct pxafb_info *, u_int);
+
 #ifdef CONFIG_CPU_FREQ
 	struct notifier_block	freq_transition;
 	struct notifier_block	freq_policy;
@@ -109,6 +171,9 @@
 #define C_DISABLE_PM		(5)
 #define C_ENABLE_PM		(6)
 #define C_STARTUP		(7)
+#define C_BLANK  		(8)
+#define C_UNBLANK		(9)
+
 
 #define PXA_NAME	"PXA"
 
--- /dev/null
+++ linux-2.6.24-rc1/drivers/video/pxafb_overlay.c
@@ -0,0 +1,1525 @@
+/*
+ *  linux/drivers/video/pxafb_overlay.c
+ *
+ *  Copyright (c) 2004, Intel Corporation
+ *
+ * 	Code Status:
+ * 	2004/10/28: <yan.yin@intel.com>
+ *      - Ported to 2.6 kernel
+ *      - Made overlay driver a loadable module
+ *      - Merged overlay optimized patch
+ * 	2004/03/10: <stanley.cai@intel.com>
+ *      - Fixed Bugs
+ *      - Added workaround for overlay1&2
+ * 	2003/08/27: <yu.tang@intel.com>
+ *      - Added Overlay 1 & Overlay2 & Hardware Cursor support
+ *
+ *
+ * 	This software program is licensed subject to the GNU Lesser General
+ * 	Public License (LGPL). Version 2.1, February 1999, available at
+ * 	http://www.gnu.org/copyleft/lesser.html
+ *
+ * 	Intel PXA27x LCD Controller Frame Buffer Overlay Driver
+ *
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/fb.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/cpufreq.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/arch/bitfield.h>
+#include <asm/arch/pxafb.h>
+#include <asm/arch/pxa-regs.h>
+
+#include "pxafb.h"
+
+/* LCD enhancement : Overlay 1 & 2 & Hardware Cursor */
+
+/*
+ * LCD enhancement : Overlay 1
+ *
+ * Features:
+ * - support 16bpp (No palette)
+ */
+/*
+ * debugging?
+ */
+#define DEBUG 0
+
+#ifdef  DEBUG
+#define dbg(fmt,arg...) printk(KERN_ALERT "%s(): " fmt "\n", __FUNCTION__, ##arg)
+#else
+#define dbg(fmt,arg...)
+#endif
+
+static int overlay1fb_enable(struct fb_info *info);
+static int overlay2fb_enable(struct fb_info *info);
+static int cursorfb_enable(struct fb_info *info);
+
+static int overlay1fb_disable(struct fb_info *info);
+static int overlay2fb_disable(struct fb_info *info);
+static int cursorfb_disable(struct fb_info *info);
+
+static int overlay1fb_blank(int blank, struct fb_info *info);
+static int overlay2fb_blank(int blank, struct fb_info *info);
+static int cursorfb_blank(int blank, struct fb_info *info);
+
+extern void pxafb_set_ctrlr_state(struct pxafb_info *fbi, u_int state);
+extern int pxafb_blank(int blank, struct fb_info *info);
+
+static struct pxafb_rgb def_rgb_18 = {
+	red:    { offset: 12, length: 6, },
+	green:  { offset: 6,  length: 6, },
+	blue:   { offset: 0,  length: 6, },
+	transp: { offset: 0,  length: 0, },
+};
+
+static struct pxafb_rgb def_rgbt_16 = {
+	red:    { offset: 10, length: 5, },
+	green:  { offset: 5,  length: 5, },
+	blue:   { offset: 0,  length: 5, },
+	transp: { offset: 15,  length: 1, },
+};
+
+static struct pxafb_rgb  def_rgbt_19 = {
+	red:    { offset: 12, length: 6, },
+	green:  { offset: 6,  length: 6, },
+	blue:   { offset: 0,  length: 6, },
+	transp: { offset: 18, length: 1, },
+};
+
+static struct pxafb_rgb def_rgbt_24 = {
+	red:    { offset: 16, length: 7, },
+	green:  { offset: 8,  length: 8, },
+	blue:   { offset: 0,  length: 8, },
+	transp: { offset: 0,  length: 0, },
+};
+
+static struct pxafb_rgb def_rgbt_25 = {
+	red:    { offset: 16, length: 8, },
+	green:  { offset: 8,  length: 8, },
+	blue:   { offset: 0,  length: 8, },
+	transp: { offset: 24, length: 1, },
+};
+
+#define CLEAR_LCD_INTR(reg, intr) do {  \
+	reg = (intr);			\
+}while(0)
+
+#define WAIT_FOR_LCD_INTR(reg,intr,timeout) ({	\
+	int __done =0;				\
+	int __t = timeout;			\
+	while (__t) {				\
+		__done = (reg) & (intr);	\
+		if (__done) break;		\
+		mdelay(10);			\
+		__t--;				\
+	}					\
+	if (!__t) dbg("wait " #intr " timeount");\
+	__done;					\
+})
+
+#define DISABLE_OVERLAYS(fbi) do {	 				\
+	if (fbi->overlay1fb && (fbi->overlay1fb->state == C_ENABLE)) {	\
+		overlay1fb_disable((struct fb_info*)fbi->overlay1fb);	\
+	}								\
+	if (fbi->overlay2fb && (fbi->overlay2fb->state == C_ENABLE)) {	\
+		overlay2fb_disable((struct fb_info*)fbi->overlay2fb);	\
+	}								\
+	if (fbi->cursorfb && (fbi->cursorfb->state == C_ENABLE)) {	\
+		cursorfb_disable((struct fb_info*)fbi->cursorfb);	\
+	}								\
+}while(0)
+
+#define ENABLE_OVERLAYS(fbi) do {					\
+	if (fbi->overlay1fb && (fbi->overlay1fb->state == C_DISABLE)) {	\
+		overlay1fb_enable((struct fb_info*)fbi->overlay1fb);	\
+	}								\
+	if (fbi->overlay2fb && (fbi->overlay2fb->state == C_DISABLE)) {	\
+		overlay2fb_enable((struct fb_info*)fbi->overlay2fb);	\
+	}								\
+	if (fbi->cursorfb && (fbi->cursorfb->state == C_DISABLE)) {	\
+		cursorfb_enable((struct fb_info*)fbi->cursorfb);	\
+	}								\
+}while(0)
+
+#define BLANK_OVERLAYS(fbi) do {	 				\
+	if (fbi->overlay1fb && (fbi->overlay1fb->state == C_ENABLE)) {	\
+		overlay1fb_disable((struct fb_info*)fbi->overlay1fb);	\
+		fbi->overlay1fb->state = C_BLANK;			\
+	}								\
+	if (fbi->overlay2fb && (fbi->overlay2fb->state == C_ENABLE)) {	\
+		overlay2fb_disable((struct fb_info*)fbi->overlay2fb);	\
+		fbi->overlay2fb->state = C_BLANK;			\
+	}								\
+	if (fbi->cursorfb && (fbi->cursorfb->state == C_ENABLE)) {	\
+		cursorfb_disable((struct fb_info*)fbi->cursorfb);	\
+		fbi->cursorfb->state = C_BLANK;			\
+	}								\
+}while(0)
+
+#define UNBLANK_OVERLAYS(fbi) do {					\
+	if (fbi->overlay1fb && (fbi->overlay1fb->state == C_BLANK)) { 	\
+		overlay1fb_enable((struct fb_info*)fbi->overlay1fb);	\
+		fbi->overlay1fb->state = C_ENABLE;			\
+	}								\
+	if (fbi->overlay2fb && (fbi->overlay2fb->state == C_BLANK)) {	\
+		overlay2fb_enable((struct fb_info*)fbi->overlay2fb);	\
+		fbi->overlay2fb->state = C_ENABLE;			\
+	}								\
+	if (fbi->cursorfb && (fbi->cursorfb->state == C_BLANK)) {	\
+		cursorfb_enable((struct fb_info*)fbi->cursorfb);	\
+		fbi->cursorfb->state = C_ENABLE;			\
+	}								\
+}while(0)
+
+static int overlay1fb_open(struct fb_info *info, int user)
+{
+	struct overlayfb_info *fbi = (struct overlayfb_info*) info;
+	int ret = 0;
+
+/* If basefb is disable, enable fb. */
+	if (fbi->basefb && fbi->basefb->state != C_ENABLE)
+		pxafb_blank(VESA_NO_BLANKING, (struct fb_info *)(fbi->basefb));
+
+	down(&fbi->mutex);
+
+	if (fbi->refcount)
+		ret = -EACCES;
+	else
+		fbi->refcount ++;
+
+	up(&fbi->mutex);
+
+	/* Initialize the variables in overlay1 framebuffer. */
+	fbi->fb.var.xres = fbi->fb.var.yres = 0;
+	fbi->fb.var.bits_per_pixel = 0;
+
+	return ret;
+}
+
+static int overlay1fb_release(struct fb_info *info, int user)
+{
+	struct overlayfb_info *fbi = (struct overlayfb_info*) info;
+	down(&fbi->mutex);
+
+	if (fbi->refcount)
+		fbi->refcount --;
+
+	up(&fbi->mutex);
+	/* disable overlay when released */
+	overlay1fb_blank(1, info);
+
+	return 0;
+}
+
+static int overlay1fb_map_video_memory(struct fb_info *info)
+{
+	struct overlayfb_info *fbi = (struct overlayfb_info*) info;
+
+	if (fbi->map_cpu)
+		dma_free_writecombine(NULL, fbi->map_size, (void*)fbi->map_cpu,  fbi->map_dma);
+	fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + PAGE_SIZE);
+
+	fbi->map_cpu = (unsigned long)dma_alloc_writecombine(NULL, fbi->map_size,
+					       &fbi->map_dma, GFP_KERNEL );
+
+	if (!fbi->map_cpu) return -ENOMEM;
+
+	fbi->screen_cpu = fbi->map_cpu + PAGE_SIZE;
+	fbi->screen_dma = fbi->map_dma + PAGE_SIZE;
+
+	fbi->fb.fix.smem_start = fbi->screen_dma;
+
+	/* setup dma descriptor */
+	fbi->dma1 = (struct pxafb_dma_descriptor*)
+		(fbi->screen_cpu - sizeof(struct pxafb_dma_descriptor));
+
+	fbi->dma1->fdadr = (fbi->screen_dma - sizeof(struct pxafb_dma_descriptor));
+	fbi->dma1->fsadr = fbi->screen_dma;
+	fbi->dma1->fidr  = 0;
+	fbi->dma1->ldcmd = fbi->fb.fix.smem_len;
+
+	return 0;
+}
+
+static int overlay1fb_enable(struct fb_info *info)
+{
+	struct overlayfb_info *fbi = (struct overlayfb_info*) info;
+	unsigned long bpp1;
+
+	if (!fbi->map_cpu) return -EINVAL;
+
+	switch (fbi->fb.var.bits_per_pixel) {
+	case 16:
+		bpp1 = 0x4;
+		break;
+	case 18:
+		bpp1 = 0x6;
+		break;
+	case 19:
+		bpp1 = 0x8;
+		break;
+	case 24:
+		bpp1 = 0x9;
+		break;
+	case 25:
+		bpp1 = 0xa;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* disable branch/start/end of frame interrupt */
+	LCCR5 |= (LCCR5_IUM1 | LCCR5_BSM1 | LCCR5_EOFM1 | LCCR5_SOFM1);
+
+	if (fbi->state == C_DISABLE || fbi->state == C_BLANK)
+		FDADR1 = (fbi->dma1->fdadr);
+	else
+		FBR1 = fbi->dma1->fdadr | 0x1;
+
+	/* enable overlay 1 window */
+	OVL1C2 = (fbi->ypos << 10) | fbi->xpos;
+	OVL1C1 = OVL1C1_O1EN | (bpp1 << 20) | ((fbi->fb.var.yres-1)<<10) | (fbi->fb.var.xres-1);
+
+	fbi->state = C_ENABLE;
+
+	return 0;
+}
+
+static int overlay1fb_disable(struct fb_info *info)
+{
+	struct overlayfb_info *fbi = (struct overlayfb_info*)info;
+	int done;
+
+	if ((fbi->state == C_DISABLE) || (fbi->state == C_BLANK))
+               return 0;
+
+	fbi->state = C_DISABLE;
+
+	/* clear O1EN */
+	OVL1C1 &= ~OVL1C1_O1EN;
+
+	CLEAR_LCD_INTR(LCSR1, LCSR1_BS1);
+	FBR1 = 0x3;
+	done = WAIT_FOR_LCD_INTR(LCSR1, LCSR1_BS1, 100);
+
+	if (!done) {
+		pr_debug(KERN_INFO "%s: timeout\n", __FUNCTION__);
+		return -1;
+	}
+	return 0;
+}
+
+static int overlay1fb_blank(int blank, struct fb_info *info)
+{
+	struct overlayfb_info *fbi = (struct overlayfb_info*) info;
+	int err=0;
+
+	switch (blank) {
+	case 0:
+		err = overlay1fb_enable(info);
+		if (err) {
+			fbi->state = C_DISABLE;
+			pxafb_set_ctrlr_state(fbi->basefb, C_REENABLE);
+		}
+		break;
+	case 1:
+		err = overlay1fb_disable(info);
+		if (err) {
+			fbi->state = C_DISABLE;
+			pxafb_set_ctrlr_state(fbi->basefb, C_REENABLE);
+		}
+		break;
+	default:
+		break;
+	}
+
+	return err;
+}
+
+static int overlay1fb_check_var( struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	int xpos, ypos;
+	struct overlayfb_info *fbi=(struct overlayfb_info*)info;
+
+	/* must in base frame */
+	xpos = (var->nonstd & 0x3ff);
+	ypos = ((var->nonstd>>10) & 0x3ff);
+
+	if ( (xpos + var->xres) > fbi->basefb->fb.var.xres )
+		return -EINVAL;
+
+	if ( (ypos + var->yres) > fbi->basefb->fb.var.yres )
+		return -EINVAL;
+
+	switch (var->bits_per_pixel) {
+	case 16:
+		if ( var->xres & 0x1 ) {
+			printk("xres should be a multiple of 2 pixels!\n");
+			return -EINVAL;
+		}
+		break;
+	case 18:
+	case 19:
+		if ( var->xres & 0x7 ) {
+			printk("xres should be a multiple of 8 pixels!\n");
+			return -EINVAL;
+		}
+		break;
+	default:
+		break;
+	}
+
+	fbi->old_var=*var;
+
+	var->activate=FB_ACTIVATE_NOW;
+
+	return 0;
+}
+
+
+static int overlay1fb_set_par(struct fb_info *info)
+{
+	int nbytes=0, err=0, pixels_per_line=0;
+
+	struct overlayfb_info *fbi=(struct overlayfb_info*)info;
+	struct fb_var_screeninfo *var = &fbi->fb.var;
+
+	info->flags &= ~FBINFO_MISC_USEREVENT;
+
+	if (fbi->state == C_BLANK)
+		return 0;
+
+	if (fbi->state == C_DISABLE)
+		goto out1;
+
+	/* only xpos & ypos change */
+	if ( (var->xres == fbi->old_var.xres) &&
+		(var->yres == fbi->old_var.yres) &&
+		(var->bits_per_pixel == fbi->old_var.bits_per_pixel) )
+		goto out2;
+
+out1:
+	switch(var->bits_per_pixel) {
+		case 16:
+			/* 2 pixels per line */
+			pixels_per_line = (fbi->fb.var.xres + 0x1) & (~0x1);
+			nbytes = 2;
+
+			var->red    = def_rgbt_16.red;
+			var->green  = def_rgbt_16.green;
+			var->blue   = def_rgbt_16.blue;
+			var->transp = def_rgbt_16.transp;
+
+			break;
+		case 18:
+			/* 8 pixels per line */
+			pixels_per_line = (fbi->fb.var.xres + 0x7 ) & (~0x7);
+			nbytes = 3;
+
+			var->red    = def_rgb_18.red;
+			var->green  = def_rgb_18.green;
+			var->blue   = def_rgb_18.blue;
+			var->transp = def_rgb_18.transp;
+
+			break;
+		case 19:
+			/* 8 pixels per line */
+			pixels_per_line = (fbi->fb.var.xres + 0x7 ) & (~0x7);
+			nbytes = 3;
+
+			var->red    = def_rgbt_19.red;
+			var->green  = def_rgbt_19.green;
+			var->blue   = def_rgbt_19.blue;
+			var->transp = def_rgbt_19.transp;
+
+			break;
+		case 24:
+			pixels_per_line = fbi->fb.var.xres;
+			nbytes = 4;
+
+			var->red    = def_rgbt_24.red;
+			var->green  = def_rgbt_24.green;
+			var->blue   = def_rgbt_24.blue;
+			var->transp = def_rgbt_24.transp;
+
+			break;
+		case 25:
+			pixels_per_line = fbi->fb.var.xres;
+			nbytes = 4;
+
+			var->red    = def_rgbt_25.red;
+			var->green  = def_rgbt_25.green;
+			var->blue   = def_rgbt_25.blue;
+			var->transp = def_rgbt_25.transp;
+
+			break;
+		}
+
+		fbi->fb.fix.line_length = nbytes * pixels_per_line;
+		fbi->fb.fix.smem_len = fbi->fb.fix.line_length * fbi->fb.var.yres;
+
+		err= overlay1fb_map_video_memory((struct fb_info*)fbi);
+
+		if (err)
+			return err;
+
+out2:
+		fbi->xpos = var->nonstd & 0x3ff;
+		fbi->ypos = (var->nonstd>>10) & 0x3ff;
+
+		overlay1fb_enable(info);
+
+		return 0;
+
+}
+
+static struct fb_ops overlay1fb_ops = {
+	.owner			= THIS_MODULE,
+	.fb_open		= overlay1fb_open,
+	.fb_release		= overlay1fb_release,
+	.fb_check_var 		= overlay1fb_check_var,
+	.fb_set_par		= overlay1fb_set_par,
+	.fb_blank		= overlay1fb_blank,
+	.fb_fillrect		= cfb_fillrect,
+	.fb_copyarea		= cfb_copyarea,
+	.fb_imageblit		= cfb_imageblit,
+};
+
+ /*
+ * LCD enhancement : Overlay 2
+ *
+ * Features:
+ * - support planar YCbCr420/YCbCr422/YCbCr444;
+ */
+static int overlay2fb_open(struct fb_info *info, int user)
+{
+	struct overlayfb_info *fbi = (struct overlayfb_info*) info;
+	int ret = 0;
+
+	/* if basefb is disable, enable fb. */
+	if (fbi->basefb && fbi->basefb->state != C_ENABLE)
+		pxafb_blank(VESA_NO_BLANKING, (struct fb_info *)(fbi->basefb));
+
+	down(&fbi->mutex);
+
+	if (fbi->refcount)
+		ret = -EACCES;
+	else
+		fbi->refcount ++;
+
+	up(&fbi->mutex);
+	fbi->fb.var.xres = fbi->fb.var.yres = 0;
+
+	return ret;
+}
+
+static int overlay2fb_release(struct fb_info *info, int user)
+{
+	struct overlayfb_info *fbi = (struct overlayfb_info*) info;
+
+	down(&fbi->mutex);
+
+	if (fbi->refcount)
+		fbi->refcount --;
+
+	up(&fbi->mutex);
+
+	/* disable overlay when released */
+	overlay2fb_blank(1, info);
+
+	return 0;
+}
+
+static int overlay2fb_map_YUV_memory( struct fb_info *info)
+{
+	struct overlayfb_info *fbi = (struct overlayfb_info*) info;
+	unsigned int ylen, cblen, crlen, aylen, acblen, acrlen;
+	unsigned int yoff, cboff, croff;
+	unsigned int xres,yres;
+	unsigned int nbytes;
+
+	ylen = cblen = crlen = aylen = acblen = acrlen = 0;
+	yoff = cboff = croff = 0;
+
+	if (fbi->map_cpu)
+		dma_free_writecombine(NULL, fbi->map_size, (void*)fbi->map_cpu,  fbi->map_dma);
+
+	yres = fbi->fb.var.yres;
+
+	switch(fbi->format) {
+	case 0x4: /* YCbCr 4:2:0 planar */
+		pr_debug("420 planar\n");
+		/* 16 pixels per line */
+		xres = (fbi->fb.var.xres + 0xf) & (~0xf);
+		fbi->fb.fix.line_length = xres;
+
+		nbytes = xres * yres;
+		ylen = nbytes;
+		cblen = crlen = (nbytes/4);
+
+		break;
+	case 0x3: /* YCbCr 4:2:2 planar */
+		/* 8 pixles per line */
+		pr_debug("422 planar\n");
+		xres = (fbi->fb.var.xres + 0x7) & (~0x7);
+		fbi->fb.fix.line_length = xres;
+
+		nbytes = xres * yres;
+		ylen  = nbytes;
+		cblen = crlen = (nbytes/2);
+
+		break;
+	case 0x2: /* YCbCr 4:4:4 planar */
+		/* 4 pixels per line */
+		pr_debug("444 planar\n");
+		xres = (fbi->fb.var.xres + 0x3) & (~0x3);
+		fbi->fb.fix.line_length = xres;
+
+		nbytes = xres * yres;
+		ylen  = cblen = crlen = nbytes;
+		break;
+	}
+
+	/* 16-bytes alignment for DMA */
+	aylen  = (ylen + 0xf) & (~0xf);
+	acblen = (cblen + 0xf) & (~0xf);
+	acrlen = (crlen + 0xf) & (~0xf);
+
+	fbi->fb.fix.smem_len = aylen + acblen + acrlen;
+
+	/* alloc memory */
+
+	fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + PAGE_SIZE);
+	fbi->map_cpu = (unsigned long)dma_alloc_writecombine(NULL, fbi->map_size,
+					       &fbi->map_dma, GFP_KERNEL );
+
+	if (!fbi->map_cpu) return -ENOMEM;
+
+	fbi->screen_cpu = fbi->map_cpu + PAGE_SIZE;
+	fbi->screen_dma = fbi->map_dma + PAGE_SIZE;
+
+	fbi->fb.fix.smem_start = fbi->screen_dma;
+
+	/* setup dma for Planar format */
+	fbi->dma2 = (struct pxafb_dma_descriptor*)
+		(fbi->screen_cpu - sizeof(struct pxafb_dma_descriptor));
+	fbi->dma3 = fbi->dma2 - 1;
+	fbi->dma4 = fbi->dma3 - 1;
+
+	/* offset */
+	yoff = 0;
+	cboff = aylen;
+	croff = cboff + acblen;
+
+	/* Y vector */
+	fbi->dma2->fdadr = (fbi->screen_dma - sizeof(struct pxafb_dma_descriptor));
+	fbi->dma2->fsadr = fbi->screen_dma + yoff;
+	fbi->dma2->fidr  = 0;
+	fbi->dma2->ldcmd = ylen;
+
+	/* Cb vector */
+	fbi->dma3->fdadr = (fbi->dma2->fdadr - sizeof(struct pxafb_dma_descriptor));
+	fbi->dma3->fsadr = (fbi->screen_dma + cboff);
+	fbi->dma3->fidr  = 0;
+	fbi->dma3->ldcmd = cblen;
+
+	/* Cr vector */
+
+	fbi->dma4->fdadr = (fbi->dma3->fdadr - sizeof(struct pxafb_dma_descriptor));
+	fbi->dma4->fsadr = (fbi->screen_dma + croff);
+	fbi->dma4->fidr  = 0;
+	fbi->dma4->ldcmd = crlen;
+
+	/* adjust for user */
+	fbi->fb.var.red.length   = ylen;
+	fbi->fb.var.red.offset   = yoff;
+	fbi->fb.var.green.length = cblen;
+	fbi->fb.var.green.offset = cboff;
+	fbi->fb.var.blue.length  = crlen;
+	fbi->fb.var.blue.offset  = croff;
+
+	return 0;
+};
+
+static int overlay2fb_map_RGB_memory( struct fb_info *info)
+{
+	struct overlayfb_info *fbi = (struct overlayfb_info*) info;
+	struct fb_var_screeninfo *var = &fbi->fb.var;
+	int pixels_per_line=0 , nbytes=0;
+
+	if (fbi->map_cpu)
+		dma_free_writecombine(NULL,  fbi->map_size, (void*)fbi->map_cpu, fbi->map_dma);
+
+	switch(var->bits_per_pixel) {
+	case 16:
+		/* 2 pixels per line */
+		pixels_per_line = (fbi->fb.var.xres + 0x1) & (~0x1);
+		nbytes = 2;
+
+		var->red    = def_rgbt_16.red;
+		var->green  = def_rgbt_16.green;
+		var->blue   = def_rgbt_16.blue;
+		var->transp = def_rgbt_16.transp;
+		break;
+
+	case 18:
+		/* 8 pixels per line */
+		pixels_per_line = (fbi->fb.var.xres + 0x7 ) & (~0x7);
+		nbytes = 3;
+
+		var->red    = def_rgb_18.red;
+		var->green  = def_rgb_18.green;
+		var->blue   = def_rgb_18.blue;
+		var->transp = def_rgb_18.transp;
+
+		break;
+	case 19:
+		/* 8 pixels per line */
+		pixels_per_line = (fbi->fb.var.xres + 0x7 ) & (~0x7);
+		nbytes = 3;
+
+		var->red    = def_rgbt_19.red;
+		var->green  = def_rgbt_19.green;
+		var->blue   = def_rgbt_19.blue;
+		var->transp = def_rgbt_19.transp;
+
+		break;
+	case 24:
+		pixels_per_line = fbi->fb.var.xres;
+		nbytes = 4;
+
+		var->red    = def_rgbt_24.red;
+		var->green  = def_rgbt_24.green;
+		var->blue   = def_rgbt_24.blue;
+		var->transp = def_rgbt_24.transp;
+
+		break;
+
+	case 25:
+		pixels_per_line = fbi->fb.var.xres;
+		nbytes = 4;
+
+		var->red    = def_rgbt_25.red;
+		var->green  = def_rgbt_25.green;
+		var->blue   = def_rgbt_25.blue;
+		var->transp = def_rgbt_25.transp;
+
+		break;
+	}
+
+	fbi->fb.fix.line_length = nbytes * pixels_per_line;
+	fbi->fb.fix.smem_len = fbi->fb.fix.line_length * fbi->fb.var.yres;
+
+	fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + PAGE_SIZE);
+	fbi->map_cpu = (unsigned long)dma_alloc_writecombine(NULL, fbi->map_size,
+					       &fbi->map_dma, GFP_KERNEL );
+
+	if (!fbi->map_cpu) return -ENOMEM;
+
+	fbi->screen_cpu = fbi->map_cpu + PAGE_SIZE;
+	fbi->screen_dma = fbi->map_dma + PAGE_SIZE;
+
+	fbi->fb.fix.smem_start = fbi->screen_dma;
+
+	/* setup dma descriptor */
+	fbi->dma2 = (struct pxafb_dma_descriptor*)
+		(fbi->screen_cpu - sizeof(struct pxafb_dma_descriptor));
+
+	fbi->dma2->fdadr = (fbi->screen_dma - sizeof(struct pxafb_dma_descriptor));
+	fbi->dma2->fsadr = fbi->screen_dma;
+	fbi->dma2->fidr  = 0;
+	fbi->dma2->ldcmd = fbi->fb.fix.smem_len;
+
+	return 0;
+}
+
+static int overlay2fb_enable(struct fb_info *info)
+{
+	struct overlayfb_info *fbi = (struct overlayfb_info*) info;
+	unsigned long bpp2;
+	unsigned int xres, yres;
+
+	if (!fbi->map_cpu) return -EINVAL;
+
+	switch(fbi->fb.var.bits_per_pixel) {
+	case 16:
+		bpp2 = 0x4;
+		break;
+	case 18:
+		bpp2 = 0x6;
+		break;
+	case 19:
+		bpp2 = 0x8;
+		break;
+	case 24:
+		bpp2 = 0x9;
+		break;
+	case 25:
+		bpp2 = 0xa;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+        /* disable branch/start/end of frame interrupt */
+	LCCR5 |= (LCCR5_IUM4 | LCCR5_IUM3 | LCCR5_IUM2 |
+		  LCCR5_BSM4 | LCCR5_BSM3 | LCCR5_BSM2 |
+		  LCCR5_EOFM4 | LCCR5_EOFM3 | LCCR5_EOFM2 |
+		  LCCR5_SOFM4 | LCCR5_SOFM3 | LCCR5_SOFM2);
+
+	if (fbi->format == 0) {
+		/* overlay2 RGB resolution, RGB and YUV have different xres value*/
+		xres = fbi->fb.var.xres;
+		yres = fbi->fb.var.yres;
+
+		OVL2C2 = (fbi->format << 20) | (fbi->ypos << 10) | fbi->xpos;
+		OVL2C1 = OVL2C1_O2EN | (bpp2 << 20) | ((yres-1)<<10) | (xres-1);
+		/* setup RGB DMA */
+		if (fbi->state == C_DISABLE || fbi->state == C_BLANK)
+			FDADR2 = fbi->dma2->fdadr;
+		else
+			FBR2 = fbi->dma2->fdadr | 0x1;
+	} else {
+		/* overlay2 YUV resolution */
+		xres = fbi->fb.fix.line_length;
+		yres = fbi->fb.var.yres;
+
+		OVL2C2 = (fbi->format << 20) | (fbi->ypos << 10) | fbi->xpos;
+		OVL2C1 = OVL2C1_O2EN | (bpp2 << 20) | ((yres-1)<<10) | (xres-1);
+
+		if (fbi->state == C_DISABLE || fbi->state == C_BLANK) {
+			FDADR2 = fbi->dma2->fdadr;
+			FDADR3 = fbi->dma3->fdadr;
+			FDADR4 = fbi->dma4->fdadr;
+		} else {
+			FBR2 = fbi->dma2->fdadr | 0x01;
+			FBR3 = fbi->dma3->fdadr | 0x01;
+			FBR4 = fbi->dma4->fdadr | 0x01;
+		}
+	}
+
+	fbi->state = C_ENABLE;
+	return 0;
+}
+
+static int overlay2fb_disable(struct fb_info *info)
+{
+	struct overlayfb_info *fbi = (struct overlayfb_info*)info;
+	int done;
+
+	if (fbi->state == C_DISABLE)
+		return 0;
+	if (fbi->state == C_BLANK) {
+		fbi->state = C_DISABLE;
+		return 0;
+	}
+
+	fbi->state = C_DISABLE;
+
+	/* clear O2EN */
+	OVL2C1 &= ~OVL2C1_O2EN;
+
+	/* Make overlay2 can't disable/enable
+	 * correctly sometimes.
+	 */
+	CLEAR_LCD_INTR(LCSR1, LCSR1_BS2);
+
+	if (fbi->format == 0)
+		FBR2 = 0x3;
+	else {
+		FBR2 = 0x3;
+		FBR3 = 0x3;
+		FBR4 = 0x3;
+	}
+
+	done = WAIT_FOR_LCD_INTR(LCSR1, LCSR1_BS2, 100);
+
+	if (!done) {
+		pr_debug(KERN_INFO "%s: timeout\n", __FUNCTION__);
+		return -1;
+	}
+	return 0;
+}
+
+static int overlay2fb_blank(int blank, struct fb_info *info)
+{
+	struct overlayfb_info *fbi = (struct overlayfb_info*) info;
+	int err=0;
+
+	switch(blank)
+	{
+	case 0:
+		err = overlay2fb_enable(info);
+		if (err) {
+			fbi->state = C_DISABLE;
+			pxafb_set_ctrlr_state(fbi->basefb, C_REENABLE);
+		}
+		break;
+	case 1:
+		err = overlay2fb_disable(info);
+		if (err) {
+			fbi->state = C_DISABLE;
+			pxafb_set_ctrlr_state(fbi->basefb, C_REENABLE);
+		}
+		break;
+	default:
+		/* reserved */
+		break;
+	}
+
+	return err;
+}
+
+
+static int overlay2fb_check_var( struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	int xpos, ypos, xres, yres;
+	int format;
+	struct overlayfb_info *fbi=(struct overlayfb_info*)info;
+
+	xres=yres=0;
+
+	xpos = (var->nonstd & 0x3ff);
+	ypos = (var->nonstd >> 10) & 0x3ff;
+	format = (var->nonstd >>20) & 0x7;
+
+
+	/* Palnar YCbCr444, YCbCr422, YCbCr420 */
+	if ( (format != 0x4) && (format != 0x3) && (format != 0x2) && (format !=0x0))
+		return -EINVAL;
+
+	/* dummy pixels */
+	switch(format) {
+	case 0x0: /* RGB */
+		xres = var->xres;
+		break;
+	case 0x2: /* 444 */
+		xres = (var->xres + 0x3) & ~(0x3);
+		break;
+	case 0x3: /* 422 */
+		xres = (var->xres + 0x7) & ~(0x7);
+		break;
+	case 0x4: /* 420 */
+		xres = (var->xres + 0xf) & ~(0xf);
+		break;
+	}
+	yres = var->yres;
+
+	if ( (xpos + xres) > fbi->basefb->fb.var.xres )
+		return -EINVAL;
+
+	if ( (ypos + yres) > fbi->basefb->fb.var.yres )
+		return -EINVAL;
+
+	fbi->old_var=*var;
+
+	var->activate=FB_ACTIVATE_NOW;
+
+	return 0;
+
+}
+
+
+/*
+ * overlay2fb_set_var()
+ *
+ * var.nonstd is used as YCbCr format.
+ * var.red/green/blue is used as (Y/Cb/Cr) vector
+ */
+
+static int overlay2fb_set_par(struct fb_info *info)
+{
+	unsigned int xpos, ypos;
+	int format, err;
+
+	struct overlayfb_info *fbi=(struct overlayfb_info*)info;
+	struct fb_var_screeninfo *var = &fbi->fb.var;
+
+	info->flags &= ~FBINFO_MISC_USEREVENT;
+
+	if (fbi->state == C_BLANK)
+		return 0;
+
+	if (fbi->state == C_DISABLE)
+		goto out1;
+
+	if ( (var->xres == fbi->old_var.xres) &&
+		(var->yres == fbi->old_var.yres) &&
+		(var->bits_per_pixel == fbi->old_var.bits_per_pixel) &&
+		(((var->nonstd>>20) & 0x7) == fbi->format) )
+		goto out2;
+
+out1:
+	xpos = var->nonstd & 0x3ff;
+	ypos = (var->nonstd>>10) & 0x3ff;
+	format = (var->nonstd>>20) & 0x7;
+
+
+	fbi->format = format;
+	if ( fbi->format==0 )
+		err = overlay2fb_map_RGB_memory(info);
+	else
+		err = overlay2fb_map_YUV_memory(info);
+
+	if (err) return err;
+
+out2:
+	/* position */
+	fbi->xpos = var->nonstd & 0x3ff;
+	fbi->ypos = (var->nonstd>>10) & 0x3ff;
+
+	overlay2fb_enable(info);
+
+	return 0;
+}
+
+static struct fb_ops overlay2fb_ops = {
+	.owner			= THIS_MODULE,
+	.fb_open		= overlay2fb_open,
+	.fb_release		= overlay2fb_release,
+	.fb_check_var 		= overlay2fb_check_var,
+	.fb_set_par		= overlay2fb_set_par,
+	.fb_blank		= overlay2fb_blank,
+	.fb_fillrect		= cfb_fillrect,
+	.fb_copyarea		= cfb_copyarea,
+	.fb_imageblit		= cfb_imageblit,
+};
+
+/* Hardware cursor */
+
+/* Bulverde Cursor Modes */
+struct cursorfb_mode{
+	int xres;
+	int yres;
+	int bpp;
+};
+
+static struct cursorfb_mode cursorfb_modes[]={
+	{ 32,  32, 2},
+	{ 32,  32, 2},
+	{ 32,  32, 2},
+	{ 64,  64, 2},
+	{ 64,  64, 2},
+	{ 64,  64, 2},
+	{128, 128, 1},
+	{128, 128, 1}
+};
+
+static int cursorfb_enable(struct fb_info *info)
+{
+	struct overlayfb_info *fbi = (struct overlayfb_info*) info;
+
+	if (!fbi->map_cpu) return -EINVAL;
+
+	CCR &= ~CCR_CEN;
+
+	/* set palette format
+	 *
+	 * FIXME: if only cursor uses palette
+	 */
+	LCCR4 = (LCCR4 & (~(0x3<<15))) | (0x1<<15);
+
+	/* disable branch/start/end of frame interrupt */
+	LCCR5 |= (LCCR5_IUM5 | LCCR5_BSM5 | LCCR5_EOFM5 | LCCR5_SOFM5);
+
+	/* load palette and frame data */
+	if (fbi->state == C_DISABLE) {
+		FDADR5 = fbi->dma5_pal->fdadr;
+		udelay(1);
+		FDADR5 = fbi->dma5_frame->fdadr;
+		udelay(1);
+
+	}
+	else {
+		FBR5 = fbi->dma5_pal->fdadr | 0x1;
+		udelay(1);
+		FBR5 = fbi->dma5_frame->fdadr | 0x1;
+		udelay(1);
+	}
+
+	CCR = CCR_CEN | (fbi->ypos << 15) | (fbi->xpos << 5) | (fbi->format);
+
+	fbi->state = C_ENABLE;
+
+	return 0;
+}
+
+static int cursorfb_disable(struct fb_info *info)
+{
+	struct overlayfb_info *fbi = (struct overlayfb_info*)info;
+	int done, ret = 0;
+
+	fbi->state = C_DISABLE;
+
+	done = WAIT_FOR_LCD_INTR(LCSR1, LCSR1_BS5, 100);
+	if (!done) ret = -1;
+
+	CCR &= ~CCR_CEN;
+
+	return ret;
+}
+
+static int cursorfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+		       u_int trans, struct fb_info *info)
+{
+	struct overlayfb_info *fbi = (struct overlayfb_info *)info;
+	u_int val, ret = 1;
+	u_int *pal=(u_int*) fbi->palette_cpu;
+
+	/* 25bit with Transparcy for 16bpp format */
+	if (regno < fbi->palette_size) {
+		val = ((trans << 24)  & 0x1000000);
+		val |= ((red << 16)  & 0x0ff0000);
+		val |= ((green << 8 ) & 0x000ff00);
+		val |= ((blue << 0) & 0x00000ff);
+
+		pal[regno] = val;
+		ret = 0;
+	}
+	return ret;
+}
+
+int cursorfb_blank(int blank, struct fb_info *info)
+{
+	switch(blank)
+	{
+	case 0:
+		cursorfb_enable(info);
+		break;
+	case 1:
+		cursorfb_disable(info);
+		break;
+	default:
+		/* reserved */
+		break;
+	}
+	return 0;
+}
+
+static int cursorfb_check_var( struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	int xpos, ypos, xres, yres;
+	int mode;
+	struct cursorfb_mode *cursor;
+	struct overlayfb_info *fbi=(struct overlayfb_info*)info;
+
+	mode = var->nonstd & 0x7;
+	xpos = (var->nonstd>>5) & 0x3ff;
+	ypos = (var->nonstd>>15) & 0x3ff;
+
+	if (mode>7 || mode <0 )
+		return -EINVAL;
+
+	cursor = cursorfb_modes + mode;
+
+	xres = cursor->xres;
+	yres = cursor->yres;
+
+	if ( (xpos + xres) > fbi->basefb->fb.var.xres )
+		return -EINVAL;
+
+	if ( (ypos + yres) > fbi->basefb->fb.var.yres )
+		return -EINVAL;
+
+	return 0;
+
+}
+
+static int cursorfb_set_par(struct fb_info *info)
+{
+	struct overlayfb_info *fbi = (struct overlayfb_info*) info;
+	struct fb_var_screeninfo *var = &fbi->fb.var;
+	struct cursorfb_mode *cursor;
+	int mode, xpos, ypos;
+	int err;
+
+	info->flags &= ~FBINFO_MISC_USEREVENT;
+
+	mode = var->nonstd & 0x7;
+	xpos = (var->nonstd>>5) & 0x3ff;
+	ypos = (var->nonstd>>15) & 0x3ff;
+
+	if (mode != fbi->format) {
+		cursor = cursorfb_modes + mode;
+
+		/* update "var" info */
+		fbi->fb.var.xres = cursor->xres;
+		fbi->fb.var.yres = cursor->yres;
+		fbi->fb.var.bits_per_pixel = cursor->bpp;
+
+		/* alloc video memory
+		 *
+		 * 4k is engouh for 128x128x1 cursor,
+		 * - 2k for cursor pixels,
+		 * - 2k for palette data, plus 2 dma descriptor
+		 */
+		if (!fbi->map_cpu) {
+			fbi->map_size = PAGE_SIZE;
+			fbi->map_cpu = (unsigned long)dma_alloc_writecombine(NULL, fbi->map_size,
+					       &fbi->map_dma, GFP_KERNEL );
+ 			if (!fbi->map_cpu) return -ENOMEM;
+		}
+
+		cursor = cursorfb_modes + mode;
+
+		/* update overlay & fix "info" */
+		fbi->screen_cpu 	= fbi->map_cpu;
+		fbi->palette_cpu 	= fbi->map_cpu + (PAGE_SIZE/2);
+		fbi->screen_dma  	= fbi->map_dma;
+		fbi->palette_dma 	= fbi->map_dma + (PAGE_SIZE/2);
+
+		fbi->format 		= mode;
+		fbi->palette_size 	= (1<<cursor->bpp);
+		fbi->fb.fix.smem_start 	= fbi->screen_dma;
+		fbi->fb.fix.smem_len 	= cursor->xres * cursor->yres * cursor->bpp / 8;
+		fbi->fb.fix.line_length = cursor->xres * cursor->bpp / 8;
+
+		fbi->dma5_pal     	= (struct pxafb_dma_descriptor*)(fbi->map_cpu + PAGE_SIZE - 16 );
+		fbi->dma5_pal->fdadr 	= (fbi->map_dma + PAGE_SIZE - 16);
+		fbi->dma5_pal->fsadr 	= fbi->palette_dma;
+		fbi->dma5_pal->fidr  	= 0;
+		fbi->dma5_pal->ldcmd 	= (fbi->palette_size<<2) | LDCMD_PAL;
+
+		fbi->dma5_frame   		= (struct pxafb_dma_descriptor*)(fbi->map_cpu + PAGE_SIZE - 32 );
+		fbi->dma5_frame->fdadr 	= (fbi->map_dma + PAGE_SIZE - 32);
+		fbi->dma5_frame->fsadr 	= fbi->screen_dma;
+		fbi->dma5_frame->fidr  	= 0;
+		fbi->dma5_frame->ldcmd 	= fbi->fb.fix.smem_len;
+
+		/* alloc & set default cmap */
+		err = fb_alloc_cmap(&fbi->fb.cmap, fbi->palette_size, 0);
+		if (err) return err;
+		err = fb_set_cmap(&fbi->fb.cmap, info);
+		if (err) return err;
+	}
+
+	/* update overlay info */
+	if ( (xpos != fbi->xpos) || (ypos != fbi->ypos) ) {
+		fbi->xpos = xpos;
+		fbi->ypos = ypos;
+	}
+
+	cursorfb_enable(info);
+	pxafb_set_ctrlr_state(fbi->basefb, C_REENABLE);
+
+	return 0;
+}
+
+static struct fb_ops cursorfb_ops = {
+	.owner			= THIS_MODULE,
+	.fb_check_var		= cursorfb_check_var,
+	.fb_set_par		= cursorfb_set_par,
+	.fb_blank		= cursorfb_blank,
+	.fb_fillrect		= cfb_fillrect,
+	.fb_copyarea		= cfb_copyarea,
+	.fb_imageblit		= cfb_imageblit,
+	.fb_setcolreg		= cursorfb_setcolreg,
+};
+
+static struct overlayfb_info * __init overlay1fb_init_fbinfo(void)
+{
+	struct overlayfb_info *fbi;
+
+	fbi = kmalloc(sizeof(struct overlayfb_info) + sizeof(u16) * 16, GFP_KERNEL);
+	if (!fbi)
+		return NULL;
+
+	memset(fbi, 0, sizeof(struct overlayfb_info) );
+
+	fbi->refcount = 0;
+	init_MUTEX(&fbi->mutex);
+
+	strcpy(fbi->fb.fix.id, "overlay1");
+
+	fbi->fb.fix.type		= FB_TYPE_PACKED_PIXELS;
+	fbi->fb.fix.type_aux		= 0;
+	fbi->fb.fix.xpanstep		= 0;
+	fbi->fb.fix.ypanstep		= 0;
+	fbi->fb.fix.ywrapstep		= 0;
+	fbi->fb.fix.accel		= FB_ACCEL_NONE;
+
+	fbi->fb.var.nonstd		= 0;
+	fbi->fb.var.activate		= FB_ACTIVATE_NOW;
+	fbi->fb.var.height		= -1;
+	fbi->fb.var.width		= -1;
+	fbi->fb.var.accel_flags	= 0;
+	fbi->fb.var.vmode		= FB_VMODE_NONINTERLACED;
+
+
+	fbi->fb.fbops			= &overlay1fb_ops;
+	fbi->fb.flags			= FBINFO_FLAG_DEFAULT;
+	fbi->fb.node			= -1;
+	fbi->fb.pseudo_palette		= NULL;
+
+	fbi->xpos   			= 0;
+	fbi->ypos   			= 0;
+	fbi->format 			= -1;
+	fbi->state 			= C_DISABLE;
+
+	return fbi;
+}
+
+static struct overlayfb_info * __init overlay2fb_init_fbinfo(void)
+{
+	struct overlayfb_info *fbi;
+
+	fbi = kmalloc(sizeof(struct overlayfb_info) + sizeof(u16) * 16, GFP_KERNEL);
+	if (!fbi)
+		return NULL;
+
+	memset(fbi, 0, sizeof(struct overlayfb_info) );
+
+	fbi->refcount = 0;
+	init_MUTEX(&fbi->mutex);
+
+	strcpy(fbi->fb.fix.id, "overlay2");
+
+	fbi->fb.fix.type		= FB_TYPE_PACKED_PIXELS;
+	fbi->fb.fix.type_aux		= 0;
+	fbi->fb.fix.xpanstep		= 0;
+	fbi->fb.fix.ypanstep		= 0;
+	fbi->fb.fix.ywrapstep		= 0;
+	fbi->fb.fix.accel		= FB_ACCEL_NONE;
+
+	fbi->fb.var.nonstd		= 0;
+	fbi->fb.var.activate		= FB_ACTIVATE_NOW;
+	fbi->fb.var.height		= -1;
+	fbi->fb.var.width		= -1;
+	fbi->fb.var.accel_flags		= 0;
+	fbi->fb.var.vmode		= FB_VMODE_NONINTERLACED;
+
+	fbi->fb.fbops			= &overlay2fb_ops;
+	fbi->fb.flags			= FBINFO_FLAG_DEFAULT;
+	fbi->fb.node			= -1;
+	fbi->fb.pseudo_palette		= NULL;
+
+	fbi->xpos   			= 0;
+	fbi->ypos   			= 0;
+	fbi->format 			= -1;
+	fbi->state 			= C_DISABLE;
+
+	return fbi;
+}
+
+static struct overlayfb_info * __init cursorfb_init_fbinfo(void)
+{
+	struct overlayfb_info *fbi;
+
+	fbi = kmalloc(sizeof(struct overlayfb_info) + sizeof(u16) * 16, GFP_KERNEL);
+	if (!fbi)
+		return NULL;
+
+	memset(fbi, 0, sizeof(struct overlayfb_info) );
+
+	fbi->refcount = 0;
+	init_MUTEX(&fbi->mutex);
+
+	strcpy(fbi->fb.fix.id, "cursor");
+
+	fbi->fb.fix.type		= FB_TYPE_PACKED_PIXELS;
+	fbi->fb.fix.type_aux		= 0;
+	fbi->fb.fix.xpanstep		= 0;
+	fbi->fb.fix.ypanstep		= 0;
+	fbi->fb.fix.ywrapstep		= 0;
+	fbi->fb.fix.accel		= FB_ACCEL_NONE;
+
+	fbi->fb.var.nonstd		= 0;
+	fbi->fb.var.activate		= FB_ACTIVATE_NOW;
+	fbi->fb.var.height		= -1;
+	fbi->fb.var.width		= -1;
+	fbi->fb.var.accel_flags		= 0;
+	fbi->fb.var.vmode		= FB_VMODE_NONINTERLACED;
+
+	fbi->fb.fbops			= &cursorfb_ops;
+	fbi->fb.flags			= FBINFO_FLAG_DEFAULT;
+	fbi->fb.node			= -1;
+	fbi->fb.pseudo_palette		= NULL;
+
+
+	fbi->xpos   			= 0;
+	fbi->ypos   			= 0;
+	fbi->format 			= -1;
+	fbi->state 			= C_DISABLE;
+
+	return fbi;
+}
+
+
+void pxa_set_overlay_ctrlr_state(struct pxafb_info *fbi, u_int state)
+{
+	switch (state) {
+	case C_DISABLE:
+			DISABLE_OVERLAYS(fbi);
+			break;
+	case C_ENABLE:
+			ENABLE_OVERLAYS(fbi);
+			break;
+	case C_BLANK:
+			BLANK_OVERLAYS(fbi);
+			break;
+	case C_UNBLANK:
+			UNBLANK_OVERLAYS(fbi);
+			break;
+	default:
+			break;
+	}
+}
+
+static int is_pxafb_device(struct device * dev, void * data)
+{
+	struct platform_device *pdev = container_of(dev, struct platform_device, dev);
+
+	return (strncmp(pdev->name, "pxa2xx-fb", 9) == 0);
+}
+
+static int __devinit pxafb_overlay_init(void)
+{
+	int ret;
+	struct overlayfb_info *overlay1fb, *overlay2fb, *cursorfb;
+	struct pxafb_info *fbi;
+	struct device *dev;
+
+	ret = -1;
+	overlay1fb = overlay2fb = cursorfb = NULL;
+	fbi = NULL;
+
+	dev = bus_find_device(&platform_bus_type, NULL, NULL, is_pxafb_device);
+	if (!dev) {
+		printk(KERN_INFO "Base framebuffer not exists, failed to load overlay driver!\n");
+		return ret;
+	}
+
+	fbi = dev_get_drvdata(dev);
+	if (fbi == NULL) {
+		printk(KERN_INFO "Base framebuffer not initialized, failed to load overlay driver!\n");
+		return ret;
+	}
+
+	/* Overlay 1 windows */
+	overlay1fb = overlay1fb_init_fbinfo();
+
+	if (!overlay1fb) {
+		ret = -ENOMEM;
+		printk("overlay1fb_init_fbinfo failed\n");
+		goto failed;
+	}
+
+	ret = register_framebuffer(&overlay1fb->fb);
+	if (ret < 0)
+		goto failed;
+
+	/* Overlay 2 window */
+	overlay2fb = overlay2fb_init_fbinfo();
+
+	if (!overlay2fb) {
+		ret = -ENOMEM;
+		printk("overlay2fb_init_fbinfo failed\n");
+		goto failed;
+	}
+
+	ret = register_framebuffer(&overlay2fb->fb);
+	if (ret < 0) goto failed;
+
+	/* Hardware cursor window */
+	cursorfb = cursorfb_init_fbinfo();
+
+	if (!cursorfb) {
+		ret = -ENOMEM;
+		printk("cursorfb_init_fbinfo failed\n");
+		goto failed;
+	}
+
+	ret = register_framebuffer(&cursorfb->fb);
+	if (ret < 0) goto failed;
+
+
+	/* set refernce to Overlays  */
+	fbi->overlay1fb  = overlay1fb;
+	fbi->overlay2fb  = overlay2fb;
+	fbi->cursorfb    = cursorfb;
+	fbi->set_overlay_ctrlr_state=pxa_set_overlay_ctrlr_state;
+
+	/* set refernce to BaseFrame */
+	overlay1fb->basefb = fbi;
+	overlay2fb->basefb = fbi;
+	cursorfb->basefb = fbi;
+
+	printk(KERN_INFO "Load PXA Overlay driver successfully!\n");
+
+	return 0;
+
+failed:
+	if (overlay1fb)
+		kfree(overlay1fb);
+	if (overlay2fb)
+		kfree(overlay2fb);
+	if (cursorfb)
+		kfree(cursorfb);
+	printk(KERN_INFO "Load PXA Overlay driver failed!\n");
+	return ret;
+}
+
+static void __exit pxafb_overlay_exit(void)
+{
+	struct pxafb_info *fbi;
+	struct device *dev;
+
+	dev = bus_find_device(&platform_bus_type, NULL, NULL, is_pxafb_device);
+	if (!dev)
+		return;
+
+	fbi = dev_get_drvdata(dev);
+	if (!fbi)
+		return;
+
+	if (fbi->overlay1fb) {
+		unregister_framebuffer(&(fbi->overlay1fb->fb));
+		kfree(fbi->overlay1fb);
+		fbi->overlay1fb  = NULL;
+	}
+
+	if (fbi->overlay2fb) {
+		unregister_framebuffer(&(fbi->overlay2fb->fb));
+		kfree(fbi->overlay2fb);
+		fbi->overlay2fb  = NULL;
+	}
+
+	if (fbi->cursorfb) {
+		unregister_framebuffer(&(fbi->cursorfb->fb));
+		kfree(fbi->cursorfb);
+		fbi->cursorfb  = NULL;
+	}
+
+	fbi->set_overlay_ctrlr_state = NULL;
+
+	printk(KERN_INFO "Unload PXA Overlay driver successfully!\n");
+	return;
+}
+
+
+module_init(pxafb_overlay_init);
+module_exit(pxafb_overlay_exit);
+
+MODULE_DESCRIPTION("Loadable framebuffer overlay driver for PXA");
+MODULE_LICENSE("GPL");
+
--- linux-2.6.24-rc1.orig/include/asm-arm/arch-pxa/pxa-regs.h
+++ linux-2.6.24-rc1/include/asm-arm/arch-pxa/pxa-regs.h
@@ -789,11 +789,18 @@
 #define UDC_INT_PACKETCMP  (0x1)
 
 #define UDCICR_INT(n,intr) (((intr) & 0x03) << (((n) & 0x0F) * 2))
+/* Older defines, do not use. */
 #define UDCICR1_IECC	(1 << 31)	/* IntEn - Configuration Change */
 #define UDCICR1_IESOF	(1 << 30)	/* IntEn - Start of Frame */
 #define UDCICR1_IERU	(1 << 29)	/* IntEn - Resume */
 #define UDCICR1_IESU	(1 << 28)	/* IntEn - Suspend */
 #define UDCICR1_IERS	(1 << 27)	/* IntEn - Reset */
+/* New defines. */
+#define UDCISR1_IRCC	(1 << 31)	/* IntEn - Configuration Change */
+#define UDCISR1_IRSOF	(1 << 30)	/* IntEn - Start of Frame */
+#define UDCISR1_IRRU	(1 << 29)	/* IntEn - Resume */
+#define UDCISR1_IRSU	(1 << 28)	/* IntEn - Suspend */
+#define UDCISR1_IRRS	(1 << 27)	/* IntEn - Reset */
 
 #define UDCISR0         __REG(0x4060000C) /* UDC Interrupt Status Register 0 */
 #define UDCISR1         __REG(0x40600010) /* UDC Interrupt Status Register 1 */
@@ -1827,6 +1834,8 @@
 #define DFBR0		__REG(0x44000020)  /* DMA Channel 0 Frame Branch Register */
 #define DFBR1		__REG(0x44000024)  /* DMA Channel 1 Frame Branch Register */
 #define LCSR		__REG(0x44000038)  /* LCD Controller Status Register */
+#define LCSR0		__REG(0x44000038)  /* LCD Controller Status Register */
+#define LCSR1		__REG(0x44000034)  /* LCD Controller Status Register */
 #define LIIDR		__REG(0x4400003C)  /* LCD Controller Interrupt ID Register */
 #define TMEDRGBR	__REG(0x44000040)  /* TMED RGB Seed Register */
 #define TMEDCR		__REG(0x44000044)  /* TMED Control Register */
@@ -1836,6 +1845,10 @@
 #define LCCR3_4BPP (2 << 24)
 #define LCCR3_8BPP (3 << 24)
 #define LCCR3_16BPP (4 << 24)
+#define LCCR3_18BPP (6 << 24)
+#define LCCR3_19BPP (8 << 24)
+#define LCCR3_24BPP (9 << 24)
+#define LCCR3_25BPP (10<< 24)
 
 #define LCCR3_PDFOR_0 (0 << 30)
 #define LCCR3_PDFOR_1 (1 << 30)
@@ -2010,6 +2023,104 @@
 
 #define LDCMD_PAL	(1 << 26)	/* instructs DMA to load palette buffer */
 
+/* Overlay1 & Overlay2 & Hardware Cursor */
+#define LCSR1_SOF1	(1 << 0)
+#define LCSR1_SOF2	(1 << 1)
+#define LCSR1_SOF3	(1 << 2)
+#define LCSR1_SOF4	(1 << 3)
+#define LCSR1_SOF5	(1 << 4)
+#define LCSR1_SOF6	(1 << 5)
+
+#define LCSR1_EOF1	(1 << 8)
+#define LCSR1_EOF2	(1 << 9)
+#define LCSR1_EOF3	(1 << 10)
+#define LCSR1_EOF4	(1 << 11)
+#define LCSR1_EOF5	(1 << 12)
+#define LCSR1_EOF6	(1 << 13)
+
+#define LCSR1_BS1	(1 << 16)
+#define LCSR1_BS2	(1 << 17)
+#define LCSR1_BS3	(1 << 18)
+#define LCSR1_BS4	(1 << 19)
+#define LCSR1_BS5	(1 << 20)
+#define LCSR1_BS6	(1 << 21)
+
+#define LCSR1_IU2	(1 << 25)
+#define LCSR1_IU3	(1 << 26)
+#define LCSR1_IU4	(1 << 27)
+#define LCSR1_IU5	(1 << 28)
+#define LCSR1_IU6	(1 << 29)
+
+#define LDCMD_SOFINT	(1 << 22)
+#define LDCMD_EOFINT	(1 << 21)
+
+
+#define LCCR5_SOFM1	(1<<0)		/* Start Of Frame Mask for Overlay 1 (channel 1) */
+#define LCCR5_SOFM2	(1<<1)		/* Start Of Frame Mask for Overlay 2 (channel 2) */
+#define LCCR5_SOFM3	(1<<2)		/* Start Of Frame Mask for Overlay 2 (channel 3) */
+#define LCCR5_SOFM4	(1<<3)		/* Start Of Frame Mask for Overlay 2 (channel 4) */
+#define LCCR5_SOFM5	(1<<4)		/* Start Of Frame Mask for cursor (channel 5) */
+#define LCCR5_SOFM6	(1<<5)		/* Start Of Frame Mask for command data (channel 6) */
+
+#define LCCR5_EOFM1	(1<<8)		/* End Of Frame Mask for Overlay 1 (channel 1) */
+#define LCCR5_EOFM2	(1<<9)		/* End Of Frame Mask for Overlay 2 (channel 2) */
+#define LCCR5_EOFM3	(1<<10)		/* End Of Frame Mask for Overlay 2 (channel 3) */
+#define LCCR5_EOFM4	(1<<11)		/* End Of Frame Mask for Overlay 2 (channel 4) */
+#define LCCR5_EOFM5	(1<<12)		/* End Of Frame Mask for cursor (channel 5) */
+#define LCCR5_EOFM6	(1<<13)		/* End Of Frame Mask for command data (channel 6) */
+
+#define LCCR5_BSM1	(1<<16)		/* Branch mask for Overlay 1 (channel 1) */
+#define LCCR5_BSM2	(1<<17)		/* Branch mask for Overlay 2 (channel 2) */
+#define LCCR5_BSM3	(1<<18)		/* Branch mask for Overlay 2 (channel 3) */
+#define LCCR5_BSM4	(1<<19)		/* Branch mask for Overlay 2 (channel 4) */
+#define LCCR5_BSM5	(1<<20)		/* Branch mask for cursor (channel 5) */
+#define LCCR5_BSM6	(1<<21)		/* Branch mask for data command  (channel 6) */
+
+#define LCCR5_IUM1	(1<<24)		/* Input FIFO Underrun Mask for Overlay 1  */
+#define LCCR5_IUM2	(1<<25)		/* Input FIFO Underrun Mask for Overlay 2  */
+#define LCCR5_IUM3	(1<<26)		/* Input FIFO Underrun Mask for Overlay 2  */
+#define LCCR5_IUM4	(1<<27)		/* Input FIFO Underrun Mask for Overlay 2  */
+#define LCCR5_IUM5	(1<<28)		/* Input FIFO Underrun Mask for cursor */
+#define LCCR5_IUM6	(1<<29)		/* Input FIFO Underrun Mask for data command */
+
+#define OVL1C1_O1EN	(1<<31)		/* Enable bit for Overlay 1 */
+#define OVL2C1_O2EN	(1<<31)		/* Enable bit for Overlay 2 */
+#define CCR_CEN		(1<<31)		/* Enable bit for Cursor */
+
+/* LCD registers */
+#define LCCR4		__REG(0x44000010)  /* LCD Controller Control Register 4 */
+#define LCCR5		__REG(0x44000014)  /* LCD Controller Control Register 5 */
+#define FBR0		__REG(0x44000020)  /* DMA Channel 0 Frame Branch Register */
+#define FBR1		__REG(0x44000024)  /* DMA Channel 1 Frame Branch Register */
+#define FBR2		__REG(0x44000028)  /* DMA Channel 2 Frame Branch Register */
+#define FBR3		__REG(0x4400002C)  /* DMA Channel 3 Frame Branch Register */
+#define FBR4		__REG(0x44000030)  /* DMA Channel 4 Frame Branch Register */
+#define FDADR2		__REG(0x44000220)  /* DMA Channel 2 Frame Descriptor Address Register */
+#define FSADR2		__REG(0x44000224)  /* DMA Channel 2 Frame Source Address Register */
+#define FIDR2		__REG(0x44000228)  /* DMA Channel 2 Frame ID Register */
+#define LDCMD2		__REG(0x4400022C)  /* DMA Channel 2 Command Register */
+#define FDADR3		__REG(0x44000230)  /* DMA Channel 3 Frame Descriptor Address Register */
+#define FSADR3		__REG(0x44000234)  /* DMA Channel 3 Frame Source Address Register */
+#define FIDR3		__REG(0x44000238)  /* DMA Channel 3 Frame ID Register */
+#define LDCMD3		__REG(0x4400023C)  /* DMA Channel 3 Command Register */
+#define FDADR4		__REG(0x44000240)  /* DMA Channel 4 Frame Descriptor Address Register */
+#define FSADR4		__REG(0x44000244)  /* DMA Channel 4 Frame Source Address Register */
+#define FIDR4		__REG(0x44000248)  /* DMA Channel 4 Frame ID Register */
+#define LDCMD4		__REG(0x4400024C)  /* DMA Channel 4 Command Register */
+#define FDADR5		__REG(0x44000250)  /* DMA Channel 5 Frame Descriptor Address Register */
+#define FSADR5		__REG(0x44000254)  /* DMA Channel 5 Frame Source Address Register */
+#define FIDR5		__REG(0x44000258)  /* DMA Channel 5 Frame ID Register */
+#define LDCMD5		__REG(0x4400025C)  /* DMA Channel 5 Command Register */
+
+#define OVL1C1		__REG(0x44000050)  /* Overlay 1 Control Register 1 */
+#define OVL1C2		__REG(0x44000060)  /* Overlay 1 Control Register 2 */
+#define OVL2C1		__REG(0x44000070)  /* Overlay 2 Control Register 1 */
+#define OVL2C2		__REG(0x44000080)  /* Overlay 2 Control Register 2 */
+#define CCR		__REG(0x44000090)  /* Cursor Control Register */
+
+#define FBR5		__REG(0x44000110)  /* DMA Channel 5 Frame Branch Register */
+#define FBR6		__REG(0x44000114)  /* DMA Channel 6 Frame Branch Register */
+
 /*
  * Memory controller
  */
