diff -Nur linux-2.6.16/drivers/video/Kconfig linux-2.6.16-pxa27x-ovl/drivers/video/Kconfig
--- linux-2.6.16/drivers/video/Kconfig	2006-03-20 05:53:29.000000000 +0000
+++ linux-2.6.16-pxa27x-ovl/drivers/video/Kconfig	2006-04-16 20:13:09.000000000 +0000
@@ -1387,6 +1387,12 @@
 
 	  <file:Documentation/fb/pxafb.txt> describes the available parameters.
 
+config FB_PXA_OVERLAY
+    	tristate "PXA LCD overlay support"
+    	depends on FB_PXA
+    	---help---
+        	Frame buffer overlay driver for PXA27x
+
 config FB_W100
 	tristate "W100 frame buffer support"
 	depends on FB && PXA_SHARPSL
diff -Nur linux-2.6.16/drivers/video/Makefile linux-2.6.16-pxa27x-ovl/drivers/video/Makefile
--- linux-2.6.16/drivers/video/Makefile	2006-03-20 05:53:29.000000000 +0000
+++ linux-2.6.16-pxa27x-ovl/drivers/video/Makefile	2006-04-16 20:13:17.000000000 +0000
@@ -99,6 +99,8 @@
 obj-$(CONFIG_FB_VESA)             += vesafb.o
 obj-$(CONFIG_FB_VGA16)            += vga16fb.o vgastate.o
 obj-$(CONFIG_FB_OF)               += offb.o
+obj-$(CONFIG_FB_PXA_OVERLAY)	  += pxafb_overlay.o 
+
 
 # the test framebuffer is last
 obj-$(CONFIG_FB_VIRTUAL)          += vfb.o
diff -Nur linux-2.6.16/drivers/video/pxafb.c linux-2.6.16-pxa27x-ovl/drivers/video/pxafb.c
--- linux-2.6.16/drivers/video/pxafb.c	2006-04-18 02:06:50.000000000 +0000
+++ linux-2.6.16-pxa27x-ovl/drivers/video/pxafb.c	2006-04-17 18:36:56.000000000 +0000
@@ -62,8 +62,9 @@
 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);
+int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info *);
+void set_ctrlr_state(struct pxafb_info *fbi, u_int state);
+extern int pxafb_overlay_init(void);
 
 #ifdef CONFIG_FB_PXA_PARAMETERS
 #define PXAFB_OPTIONS_SIZE 256
@@ -364,7 +365,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;
@@ -381,7 +382,8 @@
 			for (i = 0; i < fbi->palette_size; i++)
 				pxafb_setpalettereg(i, 0, 0, 0, 0, info);
 
-		pxafb_schedule_work(fbi, C_DISABLE);
+		//pxafb_schedule_work(fbi, C_DISABLE);
+		pxafb_schedule_work(fbi, C_BLANK);
 		//TODO if (pxafb_blank_helper) pxafb_blank_helper(blank);
 		break;
 
@@ -390,11 +392,14 @@
 		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_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)
 {
@@ -750,16 +755,45 @@
 	/* enable LCD controller clock */
 	pxa_set_cken(CKEN16_LCD, 1);
 
-	/* Sequence from 11.7.10 */
+#ifdef CONFIG_PXA27x_E17
+	/* FIXME:PXA27X E17: Overlay1 is not enabled intermittently after re-enabling LCD. */
+
+	OVL1C2 = 0;
+	OVL1C1 = 0;
+	OVL2C2 = 0;
+	OVL2C1 = 0;
+	CCR    = 0;
+
+	LCCR3 = fbi->reg_lccr3;
+	LCCR2 = fbi->reg_lccr2;
+	LCCR1 = fbi->reg_lccr1;
+	LCCR0 = fbi->reg_lccr0 & ~LCCR0_ENB;
+
+	LCCR0 |= LCCR0_ENB;
+	LCCR0 |= LCCR0_DIS;
+
 	LCCR3 = fbi->reg_lccr3;
 	LCCR2 = fbi->reg_lccr2;
 	LCCR1 = fbi->reg_lccr1;
 	LCCR0 = fbi->reg_lccr0 & ~LCCR0_ENB;
 
+	LCCR0 |= LCCR0_ENB;
+
 	FDADR0 = fbi->fdadr0;
 	FDADR1 = fbi->fdadr1;
+
 	LCCR0 |= LCCR0_ENB;
+#else
+	/* Sequence from 11.7.10 */
+	LCCR3 = fbi->reg_lccr3;
+	LCCR2 = fbi->reg_lccr2;
+	LCCR1 = fbi->reg_lccr1;
+	LCCR0 = fbi->reg_lccr0 & ~LCCR0_ENB;
 
+	FDADR0 = fbi->fdadr0;
+	FDADR1 = fbi->fdadr1;
+	LCCR0 |= LCCR0_ENB;
+#endif
 	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);
@@ -810,7 +844,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 set_ctrlr_state(struct pxafb_info *fbi, u_int state)
 {
 	u_int old_state;
 
@@ -833,6 +867,8 @@
 		if (old_state != C_DISABLE && old_state != C_DISABLE_PM) {
 			fbi->state = state;
 			//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;
@@ -846,6 +882,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);
 		}
@@ -860,6 +898,8 @@
 			fbi->state = C_ENABLE;
 			pxafb_enable_controller(fbi);
 			//TODO __pxafb_lcd_power(fbi, 1);
+			if(fbi->set_overlay_ctrlr_state)
+				fbi->set_overlay_ctrlr_state(fbi, C_ENABLE);
 		}
 		break;
 
@@ -870,9 +910,13 @@
 		 * registers.
 		 */
 		if (old_state == C_ENABLE) {
+			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);
 		}
 		break;
 
@@ -897,12 +941,47 @@
 			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
+		 */
+		if (old_state != C_BLANK) {
+			fbi->state = C_DISABLE;
+			__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.
+		 */
+		if (old_state != C_UNBLANK) {
+			fbi->state = C_ENABLE;
+			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(set_ctrlr_state);
+
 /*
  * Our LCD controller task (which is called when we blank or unblank)
  * via keventd.
@@ -1389,6 +1468,7 @@
 #endif
 	.driver		= {
 		.name	= "pxa2xx-fb",
+		.bus	= &platform_bus_type,
 	},
 };
 
diff -Nur linux-2.6.16/drivers/video/pxafb.h linux-2.6.16-pxa27x-ovl/drivers/video/pxafb.h
--- linux-2.6.16/drivers/video/pxafb.h	2006-03-20 05:53:29.000000000 +0000
+++ linux-2.6.16-pxa27x-ovl/drivers/video/pxafb.h	2006-04-16 20:13:45.000000000 +0000
@@ -29,6 +29,117 @@
 	unsigned int lccr3;
 };
 
+struct pxafb_rgb {
+	struct fb_bitfield	red;
+	struct fb_bitfield	green;
+	struct fb_bitfield	blue;
+	struct fb_bitfield	transp;
+};
+
+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, },
+};
+
+#ifdef CONFIG_PXA27x
+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, },
+};
+
+
+/* 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;
@@ -91,6 +202,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;
+	void (*set_overlay_ctrlr_state)(struct pxafb_info *, u_int);
+#endif
+
 #ifdef CONFIG_CPU_FREQ
 	struct notifier_block	freq_transition;
 	struct notifier_block	freq_policy;
@@ -110,6 +229,8 @@
 #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"
 
@@ -119,4 +240,10 @@
 #define MIN_XRES	64
 #define MIN_YRES	64
 
+#ifdef CONFIG_PXA27x
+#define CONFIG_PXA27x_E17
+#define CONFIG_PXA27x_E25
+//#define CONFIG_PXA27x_OV2_FASTBUS_WORKAROUND
+#endif
+
 #endif /* __PXAFB_H__ */
diff -Nur linux-2.6.16/drivers/video/pxafb_overlay.c linux-2.6.16-pxa27x-ovl/drivers/video/pxafb_overlay.c
--- linux-2.6.16/drivers/video/pxafb_overlay.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16-pxa27x-ovl/drivers/video/pxafb_overlay.c	2006-04-18 01:47:46.000000000 +0000
@@ -0,0 +1,1688 @@
+/*
+ *  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/config.h>
+#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 1
+
+#ifdef  DEBUG
+#define dbg(fmt,arg...) printk(KERN_ALERT "%s(): " fmt "\n", __FUNCTION__, ##arg)
+#define DPRINTK(fmt, args...)	printk(KERN_DEBUG "pxafb_overlay: " fmt, ## args)
+#else
+#define dbg(fmt,arg...)
+#define DPRINTK(fmt, args...)
+#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 set_ctrlr_state(struct pxafb_info *fbi, u_int state);
+extern int pxafb_blank(int blank, struct fb_info *info);
+
+#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)	\
+	    && fbi->overlay1fb->refcount) {				\
+		overlay1fb_disable((struct fb_info*)fbi->overlay1fb);	\
+	}								\
+	if (fbi->overlay2fb && (fbi->overlay2fb->state == C_ENABLE)	\
+	    && fbi->overlay2fb->refcount) {				\
+		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) 	\
+	    && fbi->overlay1fb->refcount) {				\
+		overlay1fb_enable((struct fb_info*)fbi->overlay1fb);	\
+	}								\
+	if (fbi->overlay2fb && (fbi->overlay2fb->state == C_DISABLE)	\
+	    && fbi->overlay2fb->refcount) {				\
+		overlay2fb_unblank_workaroundYUV420((struct fb_info*)fbi->overlay2fb);	\
+		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)	\
+	    && fbi->overlay1fb->refcount) {				\
+		overlay1fb_disable((struct fb_info*)fbi->overlay1fb);	\
+		fbi->overlay1fb->state = C_BLANK;			\
+	}								\
+	if (fbi->overlay2fb && (fbi->overlay2fb->state == C_ENABLE)	\
+	    && fbi->overlay2fb->refcount) {				\
+		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) 	\
+	    && fbi->overlay1fb->refcount) {				\
+		overlay1fb_enable((struct fb_info*)fbi->overlay1fb);	\
+		fbi->overlay1fb->state = C_ENABLE;			\
+	}								\
+	if (fbi->overlay2fb && (fbi->overlay2fb->state == C_BLANK)	\
+	    && fbi->overlay2fb->refcount) {				\
+		overlay2fb_unblank_workaroundYUV420((struct fb_info*)fbi->overlay2fb);	\
+		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(FB_BLANK_UNBLANK, (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) {
+		DPRINTK(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;
+			set_ctrlr_state(fbi->basefb, C_REENABLE);
+		}
+		break;
+	case 1:
+		err = overlay1fb_disable(info);
+		if (err) {
+			fbi->state = C_DISABLE;
+			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(FB_BLANK_UNBLANK, (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 */
+		DPRINTK("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 */
+		DPRINTK("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 */
+		DPRINTK("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:
+		DPRINTK("16bpp\n");
+		/* 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:
+		DPRINTK("18bpp\n");
+		/* 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:
+		DPRINTK("19bpp\n");
+		/* 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:
+		DPRINTK("24bpp\n");
+		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:
+		DPRINTK("25bpp\n");
+		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;
+}
+
+#ifdef CONFIG_PXA27x_E25
+/* set xpos, ypos, PPL and LP to 0 */
+static int overlay2fb_YUV420_workaround(struct fb_info *info)
+{
+	struct overlayfb_info *fbi = (struct overlayfb_info*)info;
+	struct pxafb_dma_descriptor *dma; 
+	u32 map_dma, map_cpu;
+	int done, ret=0;
+
+	map_cpu = (u32)dma_alloc_writecombine(NULL, PAGE_SIZE, &map_dma, GFP_KERNEL );
+	
+	if (!map_cpu) return -1;
+
+	dma = (struct pxafb_dma_descriptor*)((map_cpu + PAGE_SIZE) - sizeof(struct pxafb_dma_descriptor));
+	dma->fdadr = map_dma + PAGE_SIZE - sizeof(struct pxafb_dma_descriptor);
+	dma->fsadr = map_dma;
+	dma->fidr  = 0;
+	dma->ldcmd = LDCMD_EOFINT | 128;
+
+	/* step 2.a - enable overlay 2 with RGB mode
+         *
+         * - (xpos,ypos) = (0,0); 
+	 * - 64 pixels, 16bpp 
+	 */
+	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);
+	OVL2C2 = 0;
+	OVL2C1 = OVL2C1_O2EN | 0x04 <<20 | (63);
+
+	CLEAR_LCD_INTR(LCSR1, LCSR1_EOF2);
+	if (fbi->state == C_DISABLE || fbi->state == C_BLANK)
+		FDADR2 = dma->fdadr;
+	else
+		FBR2 = dma->fdadr | 0x1;
+
+	/* step 2.b - run at least 1 frame with overlay 2 */
+	done = WAIT_FOR_LCD_INTR(LCSR1, LCSR1_EOF2, 100);
+	if (!done) goto err;
+
+	/* step 2.c - disable overlay 2 */
+	OVL2C1 &= ~OVL2C1_O2EN;
+
+	CLEAR_LCD_INTR(LCSR1, LCSR1_BS2);
+	FBR2 = 0x3;
+
+	done = WAIT_FOR_LCD_INTR(LCSR1, LCSR1_BS2, 100);
+	if (!done) goto err;
+
+	/* step 2.d - Wait for base EOF interrupts */
+	CLEAR_LCD_INTR(LCSR0, LCSR_EOF);
+	done = WAIT_FOR_LCD_INTR(LCSR0, LCSR_EOF, 100);
+
+	goto out;
+err:
+	ret = -1;
+out:
+	/* free buffer allocated */
+	dma_free_writecombine(NULL, PAGE_SIZE, (void*)map_cpu,  map_dma);
+
+	fbi->state == C_DISABLE;
+	return ret;
+}
+
+static void overlay2fb_unblank_workaroundYUV420(struct fb_info *info)
+{
+	struct overlayfb_info *fbi=(struct overlayfb_info*)info;
+	int format = fbi->format;
+	
+	if ( (format == 0x4) && (fbi->state == C_BLANK) )
+		overlay2fb_YUV420_workaround(info);
+}
+#else
+static void overlay2fb_unblank_workaroundYUV420(struct fb_info *info) {}
+#endif
+
+#ifdef CONFIG_PXA27x_OV2_FASTBUS_WORKAROUND
+/* workaround for overlay2 fast bus issue */
+static int fastbus_set = 0;
+
+static void overlay2fb_set_fastbus( void )
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+	if ( fastbus_set ) {
+		__asm__ __volatile__ ("\n\
+                    mrc p14, 0, r0, c6, c0, 0    \n\
+                    orr r0, r0, #0x8              \n\
+                    mcr p14, 0, r0, c6, c0, 0    \n\
+                    mrc p14, 0, r0, c6, c0, 0    \n\
+                    mov r0, r0                   \n\
+                    nop                          \n\
+                    nop" : : : "r0" );
+	}
+	local_irq_restore(flags);
+}
+
+static void overlay2fb_clear_fastbus( void )
+{
+	unsigned int cclkcfg;
+	unsigned int unused;
+	unsigned int flags;
+
+	local_irq_save(flags);
+	__asm__ __volatile__("\
+                mrc p14, 0, %0, c6, c0, 0          \n\
+                nop                                \n\
+                nop                                \n\
+              "
+	      : "=r" (cclkcfg));
+	printk("cclkcfg = 0x%08x\n", cclkcfg);
+
+	fastbus_set = 0;
+	/* If fast bus bit is set, clear it and set a flag */
+	if ( cclkcfg | 0x8 ) {
+		cclkcfg &= ~(0x8);
+		__asm__ __volatile__ ( "\n\
+                      mcr p14, 0, %1, c6, c0, 0    \n\
+                      nop                          \n\
+                      nop                          \n\
+                    " : "=&r" (unused) : "r" (cclkcfg) );
+
+		fastbus_set = 1;
+	}
+	local_irq_restore(flags);
+}
+#endif
+
+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);
+#ifdef	CONFIG_PXA27x_E25
+		/* FIXME PXA27x E25 */
+		if (fbi->format == 4){
+			/* FIXME */
+			/* Wait util fifo emtpy */
+			CLEAR_LCD_INTR(LCSR1, LCSR1_IU2);
+			WAIT_FOR_LCD_INTR(LCSR1, LCSR1_IU2, 100);
+		}
+#endif
+		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;
+
+/* This sentence was lost in opt.patch. 
+ * That 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) {
+		DPRINTK(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;
+			set_ctrlr_state(fbi->basefb, C_REENABLE);
+		}
+		break;
+	case 1:
+		err = overlay2fb_disable(info);
+		if (err) {
+			fbi->state = C_DISABLE;
+			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:
+#ifdef	CONFIG_PXA27x_E25
+	/* FIXME PXA27x E25 */
+	if (C_ENABLE == fbi->state)
+		overlay2fb_disable(info);
+	
+	if ((format == 0x4 ) &&
+	    ((fbi->state == C_DISABLE) || (fbi->format != format)) )
+		overlay2fb_YUV420_workaround(info);
+#endif
+
+	/* 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);
+	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;
+	}
+}
+
+struct callback_data_t{
+	char  *name;
+	struct device *dev;
+};
+
+
+static int find_dev(struct device *dev, void *callback_data)
+{
+	int found=0;
+	struct callback_data_t * data=(struct callback_data_t *) callback_data;
+	
+	found = (strncmp(dev->kobj.name, data->name, KOBJ_NAME_LEN) == 0);
+	if(found == 1){
+		data->dev = dev;
+	}
+
+	return found;
+}
+struct device*  find_bus_device(struct bus_type *bus, char *name)
+{
+	struct callback_data_t callback_data;
+	
+	callback_data.name = name;
+	callback_data.dev = NULL;
+	bus_for_each_dev(bus, NULL, &callback_data, find_dev);
+	return callback_data.dev;
+}
+
+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=find_bus_device(&platform_bus_type, "pxa2xx-fb");
+	if(dev == NULL){	
+		printk(KERN_INFO "Base framebuffer not exists, failed to load overlay driver!\n");
+		return ret;
+	}
+
+	fbi = dev_get_drvdata(dev);
+/* 
+static inline void * dev_get_drvdata (struct device *dev)
+{
+	return dev->driver_data;
+}
+*/
+	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=find_bus_device(&platform_bus_type, "pxa2xx-fb");
+	if(dev ==NULL){	
+		return ;
+	}
+	
+	fbi = dev_get_drvdata(dev);
+	if(fbi ==NULL ){
+		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");
+
diff -Nur linux-2.6.16/include/asm-arm/arch-pxa/pxafb_overlay.h linux-2.6.16-pxa27x-ovl/include/asm-arm/arch-pxa/pxafb_overlay.h
--- linux-2.6.16/include/asm-arm/arch-pxa/pxafb_overlay.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16-pxa27x-ovl/include/asm-arm/arch-pxa/pxafb_overlay.h	2006-04-17 20:30:32.000000000 +0000
@@ -0,0 +1,11 @@
+#ifndef __PXAFB_OVERLAY_H__
+#define __PXAFB_OVERLAY_H__
+
+#define PIX_FMT_RGB		0
+#define PIX_FMT_YCbCr444	2
+#define PIX_FMT_YCbCr422	3
+#define PIX_FMT_YCbCr420	4
+
+#define PXA_OVL_SETUP(fmt, xpos, ypos) (((fmt & 7) << 20) | ((ypos & 0x3ff) << 10) | ((xpos & 0x3ff)))
+
+#endif
diff -Nur linux-2.6.16/include/asm-arm/arch-pxa/pxa-regs.h linux-2.6.16-pxa27x-ovl/include/asm-arm/arch-pxa/pxa-regs.h
--- linux-2.6.16/include/asm-arm/arch-pxa/pxa-regs.h	2006-03-20 05:53:29.000000000 +0000
+++ linux-2.6.16-pxa27x-ovl/include/asm-arm/arch-pxa/pxa-regs.h	2006-04-16 20:12:59.000000000 +0000
@@ -1830,6 +1830,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 */
@@ -1839,6 +1841,10 @@
 #define LCCR3_4BPP (2 << 24)
 #define LCCR3_8BPP (3 << 24)
 #define LCCR3_16BPP (4 << 24)
+#define LCCR3_18BPP (6 << 24)       	/* packed pixel format */
+#define LCCR3_19BPP (8 << 24)       	/* packed pixel format */
+#define LCCR3_24BPP (9 << 24) 
+#define LCCR3_25BPP (10<< 24)
 
 #define FDADR0		__REG(0x44000200)  /* DMA Channel 0 Frame Descriptor Address Register */
 #define FSADR0		__REG(0x44000204)  /* DMA Channel 0 Frame Source Address Register */
@@ -1989,19 +1995,105 @@
 
 #define LDCMD_PAL	(1 << 26)	/* instructs DMA to load palette buffer */
 
-#define LCSR_LDD	(1 << 0)	/* LCD Disable Done */
-#define LCSR_SOF	(1 << 1)	/* Start of frame */
-#define LCSR_BER	(1 << 2)	/* Bus error */
-#define LCSR_ABC	(1 << 3)	/* AC Bias count */
-#define LCSR_IUL	(1 << 4)	/* input FIFO underrun Lower panel */
-#define LCSR_IUU	(1 << 5)	/* input FIFO underrun Upper panel */
-#define LCSR_OU		(1 << 6)	/* output FIFO underrun */
-#define LCSR_QD		(1 << 7)	/* quick disable */
-#define LCSR_EOF	(1 << 8)	/* end of frame */
-#define LCSR_BS		(1 << 9)	/* branch status */
-#define LCSR_SINT	(1 << 10)	/* subsequent interrupt */
+/* 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 CMDCR		__REG(0x44000100)  /* Command Control Register */
+#define PRSR		__REG(0x44000104)  /* Panel Read Status Register */
+#define LCDBSCNTR	__REG(0x48000054)  /* LCD Buffer Strength Control Register */
 
-#define LDCMD_PAL	(1 << 26)	/* instructs DMA to load palette buffer */
+#define FBR5		__REG(0x44000110)  /* DMA Channel 5 Frame Branch Register */
+#define FBR6		__REG(0x44000114)  /* DMA Channel 6 Frame Branch Register */
 
 /*
  * Memory controller

