lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Wed, 10 Sep 2008 10:07:35 +0200
From:	Rodolfo Giometti <giometti@...eenne.com>
To:	linux-arm@...r.kernel.org
Cc:	Eric Miao <eric.miao@...vell.com>,
	Russell King <linux@....linux.org.uk>,
	linux-kernel@...r.kernel.org, Rodolfo Giometti <giometti@...ux.it>
Subject: [PATCH 1/2] pxafb: frame buffer overlay support for PXA27x.

From: Rodolfo Giometti <giometti@...ux.it>

Signed-off-by: Rodolfo Giometti <giometti@...ux.it>
---
 arch/arm/mach-pxa/include/mach/regs-lcd.h |   39 +
 drivers/video/Kconfig                     |    6 +
 drivers/video/Makefile                    |    1 +
 drivers/video/pxafb.c                     |   75 ++-
 drivers/video/pxafb.h                     |   74 ++
 drivers/video/pxafb_overlay.c             | 1476 +++++++++++++++++++++++++++++
 6 files changed, 1654 insertions(+), 17 deletions(-)
 create mode 100644 drivers/video/pxafb_overlay.c

diff --git a/arch/arm/mach-pxa/include/mach/regs-lcd.h b/arch/arm/mach-pxa/include/mach/regs-lcd.h
index c689c4e..7439bfb 100644
--- a/arch/arm/mach-pxa/include/mach/regs-lcd.h
+++ b/arch/arm/mach-pxa/include/mach/regs-lcd.h
@@ -14,10 +14,21 @@
 #define LCCR5		(0x014)	/* LCD Controller Control Register 5 */
 #define DFBR0		(0x020)	/* DMA Channel 0 Frame Branch Register */
 #define DFBR1		(0x024)	/* DMA Channel 1 Frame Branch Register */
+#define DFBR2		(0x028)	/* DMA Channel 2 Frame Branch Register */
+#define DFBR3		(0x02C)	/* DMA Channel 3 Frame Branch Register */
+#define DFBR4		(0x030)	/* DMA Channel 4 Frame Branch Register */
+#define DFBR5		(0x110)	/* DMA Channel 5 Frame Branch Register */
+#define DFBR6		(0x114)	/* DMA Channel 6 Frame Branch Register */
+#define LCSR1		(0x034)	/* LCD Controller Status Register 1 */
 #define LCSR		(0x038)	/* LCD Controller Status Register */
 #define LIIDR		(0x03C)	/* LCD Controller Interrupt ID Register */
 #define TMEDRGBR	(0x040)	/* TMED RGB Seed Register */
 #define TMEDCR		(0x044)	/* TMED Control Register */
+#define OVL1C1		(0x050)	/* Overlay 1 Control Register 1 */
+#define OVL1C2		(0x060)	/* Overlay 1 Control Register 2 */
+#define OVL2C1		(0x070)	/* Overlay 2 Control Register 1 */
+#define OVL2C2		(0x080)	/* Overlay 2 Control Register 2 */
+#define CCR		(0x090)	/* Cursor Control Register */
 
 #define CMDCR		(0x100)	/* Command Control Register */
 #define PRSR		(0x104)	/* Panel Read Status Register */
@@ -52,6 +63,21 @@
 #define FSADR1		(0x214)	/* DMA Channel 1 Frame Source Address Register */
 #define FIDR1		(0x218)	/* DMA Channel 1 Frame ID Register */
 #define LDCMD1		(0x21C)	/* DMA Channel 1 Command Register */
+#define FDADR2		(0x220)	/* DMA Channel 2 Frame Descriptor Address Register */
+#define FSADR2		(0x224)	/* DMA Channel 2 Frame Source Address Register */
+#define FIDR2		(0x228)	/* DMA Channel 2 Frame ID Register */
+#define FDADR3		(0x230)	/* DMA Channel 3 Frame Descriptor Address Register */
+#define FSADR3		(0x234)	/* DMA Channel 3 Frame Source Address Register */
+#define FIDR3		(0x238)	/* DMA Channel 3 Frame ID Register */
+#define LDCMD3		(0x23C)	/* DMA Channel 3 Command Register */
+#define FDADR4		(0x240)	/* DMA Channel 4 Frame Descriptor Address Register */
+#define FSADR4		(0x244)	/* DMA Channel 4 Frame Source Address Register */
+#define FIDR4		(0x248)	/* DMA Channel 4 Frame ID Register */
+#define LDCMD4		(0x24C)	/* DMA Channel 4 Command Register */
+#define FDADR5		(0x250)	/* DMA Channel 5 Frame Descriptor Address Register */
+#define FSADR5		(0x254)	/* DMA Channel 5 Frame Source Address Register */
+#define FIDR5		(0x258)	/* DMA Channel 5 Frame ID Register */
+#define LDCMD5		(0x25C)	/* DMA Channel 5 Command Register */
 #define FDADR6		(0x260) /* DMA Channel 6 Frame Descriptor Address Register */
 #define FSADR6		(0x264) /* DMA Channel 6 Frame Source Address Register */
 #define FIDR6		(0x268) /* DMA Channel 6 Frame ID Register */
@@ -143,6 +169,10 @@
 #define LCCR5_EOFM(x)	(1 << ((x) + 7))  /* end of frame mask */
 #define LCCR5_SOFM(x)	(1 << ((x) + 0))  /* start of frame mask */
 
+#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 */
+
 #define LCSR_LDD	(1 << 0)	/* LCD Disable Done */
 #define LCSR_SOF	(1 << 1)	/* Start of frame */
 #define LCSR_BER	(1 << 2)	/* Bus error */
@@ -159,6 +189,15 @@
 
 #define LDCMD_PAL	(1 << 26)	/* instructs DMA to load palette buffer */
 
+/* Overlay1 & Overlay2 & Hardware Cursor */
+#define LCSR1_SOF(x)	(1 << ((x) + 0))  /* start of frame */
+#define LCSR1_EOF(x)	(1 << ((x) + 7))  /* end of frame */
+#define LCSR1_BS(x)	(1 << ((x) + 15)) /* branch status */
+#define LCSR1_IU(x)	(1 << ((x) + 23)) /* input FIFO underrun */
+
+#define LDCMD_SOFINT	(1 << 22)
+#define LDCMD_EOFINT	(1 << 21)
+
 /* smartpanel related */
 #define PRSR_DATA(x)	((x) & 0xff)	/* Panel Data */
 #define PRSR_A0		(1 << 8)	/* Read Data Source */
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 70d135e..5d5c8c8 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -1802,6 +1802,12 @@ config FB_PXA_SMARTPANEL
 	default n
 	depends on FB_PXA
 
+config FB_PXA_OVERLAY
+	bool "PXA LCD overlay support"
+	depends on FB_PXA && PXA27x
+	---help---
+	  Frame buffer overlay driver for PXA27x
+
 config FB_PXA_PARAMETERS
 	bool "PXA LCD command line parameters"
 	default n
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index a6b5529..4968776 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -97,6 +97,7 @@ obj-$(CONFIG_FB_GBE)              += gbefb.o
 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
diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c
index 9720449..c17a6f3 100644
--- a/drivers/video/pxafb.c
+++ b/drivers/video/pxafb.c
@@ -74,19 +74,6 @@ 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);
-
-static inline unsigned long
-lcd_readl(struct pxafb_info *fbi, unsigned int off)
-{
-	return __raw_readl(fbi->mmio_base + off);
-}
-
-static inline void
-lcd_writel(struct pxafb_info *fbi, unsigned int off, unsigned long val)
-{
-	__raw_writel(val, fbi->mmio_base + off);
-}
 
 static inline void pxafb_schedule_work(struct pxafb_info *fbi, u_int state)
 {
@@ -488,7 +475,7 @@ static int pxafb_blank(int blank, struct fb_info *info)
 			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_BLANK);
 		/* TODO if (pxafb_blank_helper) pxafb_blank_helper(blank); */
 		break;
 
@@ -497,7 +484,7 @@ static int pxafb_blank(int blank, struct fb_info *info)
 		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;
 }
@@ -928,6 +915,9 @@ static int pxafb_activate_var(struct fb_var_screeninfo *var,
 
 	fbi->reg_lccr0 = fbi->lccr0 |
 		(LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM |
+#ifdef CONFIG_FB_PXA_OVERLAY
+		 LCCR0_OUC | LCCR0_CMDIM | LCCR0_RDSTM |
+#endif
 		 LCCR0_QDM | LCCR0_BM  | LCCR0_OUM);
 
 	fbi->reg_lccr3 |= pxafb_bpp_to_lccr3(var);
@@ -936,7 +926,8 @@ static int pxafb_activate_var(struct fb_var_screeninfo *var,
 
 	if ((fbi->lccr0 & LCCR0_SDS) == LCCR0_Dual) {
 		nbytes = nbytes / 2;
-		setup_frame_dma(fbi, DMA_LOWER, PAL_NONE, nbytes, nbytes);
+		setup_frame_dma(fbi, DMA_LOWER, PAL_NONE, nbytes,
+					nbytes | LDCMD_EOFINT);
 	}
 
 	if ((var->bits_per_pixel >= 16) || (fbi->lccr0 & LCCR0_LCDT))
@@ -1116,7 +1107,7 @@ static irqreturn_t pxafb_handle_irq(int irq, void *dev_id)
  * 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;
 
@@ -1139,6 +1130,8 @@ static void set_ctrlr_state(struct pxafb_info *fbi, u_int state)
 		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;
@@ -1152,6 +1145,8 @@ static void set_ctrlr_state(struct pxafb_info *fbi, u_int state)
 			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);
 		}
@@ -1166,6 +1161,8 @@ static void set_ctrlr_state(struct pxafb_info *fbi, u_int state)
 			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;
 
@@ -1177,9 +1174,13 @@ static void set_ctrlr_state(struct pxafb_info *fbi, u_int state)
 		 */
 		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;
@@ -1205,8 +1206,42 @@ static void set_ctrlr_state(struct pxafb_info *fbi, u_int state)
 			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;
+
 	}
 	mutex_unlock(&fbi->ctrlr_lock);
 }
@@ -1362,6 +1397,8 @@ static void pxafb_decode_mode_info(struct pxafb_info *fbi,
 		if (smemlen > fbi->fb.fix.smem_len)
 			fbi->fb.fix.smem_len = smemlen;
 	}
+
+	fbi->set_overlay_ctrlr_state = NULL;
 }
 
 static void pxafb_decode_mach_info(struct pxafb_info *fbi,
@@ -1839,6 +1876,10 @@ static int __devinit pxafb_probe(struct platform_device *dev)
 				CPUFREQ_POLICY_NOTIFIER);
 #endif
 
+#ifdef CONFIG_FB_PXA_OVERLAY
+	pxafb_overlay_probe(&dev->dev);
+#endif
+
 	/*
 	 * Ok, now enable the LCD controller
 	 */
diff --git a/drivers/video/pxafb.h b/drivers/video/pxafb.h
index 31541b8..16b12f4 100644
--- a/drivers/video/pxafb.h
+++ b/drivers/video/pxafb.h
@@ -61,6 +61,56 @@ struct pxafb_dma_buff {
 	struct pxafb_dma_descriptor dma_desc[DMA_MAX];
 };
 
+#ifdef CONFIG_FB_PXA_OVERLAY
+struct overlayfb_info
+{
+	struct fb_info		fb;
+
+	struct fb_var_screeninfo old_var;
+
+	atomic_t		refcount;
+
+	u_char *		map_cpu;
+	u_char *		screen_cpu;
+	u_int *			palette_cpu;
+	unsigned long		map_size;
+	unsigned long		palette_size;
+	ssize_t			video_offset;
+
+	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;
+		};
+	};
+};
+
+#define o1_to_basefb(d)		container_of(d, struct pxafb_info, overlay1fb)
+#define o2_to_basefb(d)		container_of(d, struct pxafb_info, overlay2fb)
+#define cu_to_basefb(d)		container_of(d, struct pxafb_info, cursorfb)
+
+extern void pxafb_overlay_probe(struct device *dev);
+#endif
+
 struct pxafb_info {
 	struct fb_info		fb;
 	struct device		*dev;
@@ -120,6 +170,13 @@ struct pxafb_info {
 	struct task_struct	*smart_thread;
 #endif
 
+#ifdef CONFIG_FB_PXA_OVERLAY
+	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;
@@ -139,6 +196,11 @@ struct pxafb_info {
 #define C_DISABLE_PM		(5)
 #define C_ENABLE_PM		(6)
 #define C_STARTUP		(7)
+#define C_BLANK  		(8)
+#define C_UNBLANK		(9)
+
+extern void set_ctrlr_state(struct pxafb_info *fbi, u_int state);
+
 
 #define PXA_NAME	"PXA"
 
@@ -148,4 +210,16 @@ struct pxafb_info {
 #define MIN_XRES	64
 #define MIN_YRES	64
 
+static inline unsigned long
+lcd_readl(struct pxafb_info *fbi, unsigned int off)
+{
+	return __raw_readl(fbi->mmio_base + off);
+}
+
+static inline void
+lcd_writel(struct pxafb_info *fbi, unsigned int off, unsigned long val)
+{
+	__raw_writel(val, fbi->mmio_base + off);
+}
+
 #endif /* __PXAFB_H__ */
diff --git a/drivers/video/pxafb_overlay.c b/drivers/video/pxafb_overlay.c
new file mode 100644
index 0000000..25935b5
--- /dev/null
+++ b/drivers/video/pxafb_overlay.c
@@ -0,0 +1,1476 @@
+/*
+ *  linux/drivers/video/pxafb_overlay.c
+ *
+ *  Copyright (c) 2004, Intel Corporation
+ *
+ * 	Code Status:
+ * 	2008/07/21: Rodolfo Giometti <giometti@...ux.it>
+ * 	- Ported to 2.6.26 kernel
+ * 	2004/10/28: <yan.yin@...el.com>
+ *      - Ported to 2.6 kernel
+ *      - Made overlay driver a loadable module
+ *      - Merged overlay optimized patch
+ * 	2004/03/10: <stanley.cai@...el.com>
+ *      - Fixed Bugs
+ *      - Added workaround for overlay1&2
+ * 	2003/08/27: <yu.tang@...el.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 <linux/io.h>
+#include <linux/uaccess.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.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)
+ */
+
+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);
+
+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(bfi, reg, intr, timeout) ({		\
+	int __done = 0;						\
+	int __t = timeout;					\
+	while (__t) {						\
+		__done = lcd_readl(bfi, reg) & (intr);		\
+		if (__done)					\
+			break;					\
+		mdelay(10);					\
+		__t--;						\
+	}							\
+	if (!__t)						\
+		dev_info(bfi->dev, "wait " #intr " timeount");	\
+	__done;							\
+})
+
+#define DISABLE_OVERLAYS(fbi) do {	 				\
+	if (fbi->overlay1fb.state == C_ENABLE)				\
+		overlay1fb_disable((struct fb_info *) &fbi->overlay1fb);\
+	if (fbi->overlay2fb.state == C_ENABLE)				\
+		overlay2fb_disable((struct fb_info *) &fbi->overlay2fb);\
+	if (fbi->cursorfb.state == C_ENABLE)				\
+		cursorfb_disable((struct fb_info *) &fbi->cursorfb);	\
+} while (0)
+
+#define ENABLE_OVERLAYS(fbi) do {					\
+	if (fbi->overlay1fb.state == C_DISABLE)				\
+		overlay1fb_enable((struct fb_info *) &fbi->overlay1fb);	\
+	if (fbi->overlay2fb.state == C_DISABLE)				\
+		overlay2fb_enable((struct fb_info *) &fbi->overlay2fb);	\
+	if (fbi->cursorfb.state == C_DISABLE)				\
+		cursorfb_enable((struct fb_info *) &fbi->cursorfb);	\
+} while (0)
+
+#define BLANK_OVERLAYS(fbi) do {	 				\
+	if (fbi->overlay1fb.state == C_ENABLE) {			\
+		overlay1fb_disable((struct fb_info *) &fbi->overlay1fb);\
+		fbi->overlay1fb.state = C_BLANK;			\
+	}								\
+	if (fbi->overlay2fb.state == C_ENABLE) {			\
+		overlay2fb_disable((struct fb_info *) &fbi->overlay2fb);\
+		fbi->overlay2fb.state = C_BLANK;			\
+	}								\
+	if (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.state == C_BLANK) {				\
+		overlay1fb_enable((struct fb_info *) &fbi->overlay1fb);	\
+		fbi->overlay1fb.state = C_ENABLE;			\
+	}								\
+	if (fbi->overlay2fb.state == C_BLANK) {				\
+		overlay2fb_enable((struct fb_info *) &fbi->overlay2fb);	\
+		fbi->overlay2fb.state = C_ENABLE;			\
+	}								\
+	if (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 (!atomic_dec_and_test(&fbi->refcount)) {
+		atomic_inc(&fbi->refcount);
+		return -EACCES;
+	}
+
+	/* If basefb is disable, enable fb */
+	if (o1_to_basefb(fbi)->state != C_ENABLE)
+		o1_to_basefb(fbi)->fb.fbops->fb_blank(VESA_NO_BLANKING,
+				(struct fb_info *) o1_to_basefb(fbi));
+
+	/* 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;
+
+	/* Disable overlay when released */
+	overlay1fb_blank(1, info);
+
+	atomic_inc(&fbi->refcount);
+
+	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(o1_to_basefb(fbi)->dev, fbi->map_size,
+					(void *) fbi->map_cpu, fbi->map_dma);
+	fbi->video_offset = PAGE_ALIGN(sizeof(struct pxafb_dma_descriptor));
+	fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + fbi->video_offset);
+	fbi->map_cpu = dma_alloc_writecombine(o1_to_basefb(fbi)->dev,
+						fbi->map_size, &fbi->map_dma,
+						GFP_KERNEL);
+	if (!fbi->map_cpu)
+		return -ENOMEM;
+
+	/* Prevent initial garbage on screen */
+	memset(fbi->map_cpu, 0, fbi->map_size);
+	fbi->fb.screen_base = fbi->map_cpu + fbi->video_offset;
+	fbi->screen_cpu = fbi->map_cpu + fbi->video_offset;
+	fbi->screen_dma = fbi->map_dma + fbi->video_offset;
+
+	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;
+	unsigned int lccr5;
+
+	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 = lcd_readl(o1_to_basefb(fbi), LCCR5);
+	lcd_writel(o1_to_basefb(fbi), LCCR5,
+				lccr5 | LCCR5_IUM(1) | LCCR5_BSM(1)
+					| LCCR5_EOFM(1) | LCCR5_SOFM(1));
+
+	if (fbi->state == C_DISABLE || fbi->state == C_BLANK)
+		lcd_writel(o1_to_basefb(fbi), FDADR1, fbi->dma1->fdadr);
+	else
+		lcd_writel(o1_to_basefb(fbi), DFBR1, fbi->dma1->fdadr | 0x1);
+
+	/* Enable overlay 1 window */
+	lcd_writel(o1_to_basefb(fbi), OVL1C2,
+				(fbi->ypos << 10) | fbi->xpos);;
+	lcd_writel(o1_to_basefb(fbi), 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;
+	unsigned int ovl1c1;
+
+	if ((fbi->state == C_DISABLE) || (fbi->state == C_BLANK))
+		return 0;
+
+	fbi->state = C_DISABLE;
+
+	/* Clear O1EN */
+	ovl1c1 = lcd_readl(o1_to_basefb(fbi), OVL1C1);
+	lcd_writel(o1_to_basefb(fbi), OVL1C1, ovl1c1 & ~OVL1C1_O1EN);
+
+	lcd_writel(o1_to_basefb(fbi), LCSR1, LCSR1_BS(1));
+	lcd_writel(o1_to_basefb(fbi), DFBR1, 0x3);
+	done = WAIT_FOR_LCD_INTR(o1_to_basefb(fbi), LCSR1, LCSR1_BS(1), 100);
+
+	if (!done) {
+		dev_info(o1_to_basefb(fbi)->dev, "%s: timeout\n", __func__);
+		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(o1_to_basefb(fbi), C_REENABLE);
+		}
+		break;
+	case 1:
+		err = overlay1fb_disable(info);
+		if (err) {
+			fbi->state = C_DISABLE;
+			set_ctrlr_state(o1_to_basefb(fbi), C_REENABLE);
+		}
+		break;
+	}
+
+	return err;
+}
+
+static int overlay1fb_check_var(struct fb_var_screeninfo *var,
+						struct fb_info *info)
+{
+	struct overlayfb_info *fbi = (struct overlayfb_info *) info;
+	int xpos, ypos;
+
+	/* Must in base frame */
+	xpos = var->nonstd & 0x3ff;
+	ypos = (var->nonstd>>10) & 0x3ff;
+
+	if ((xpos + var->xres) > o1_to_basefb(fbi)->fb.var.xres)
+		return -EINVAL;
+
+	if ((ypos + var->yres) > o1_to_basefb(fbi)->fb.var.yres)
+		return -EINVAL;
+
+	switch (var->bits_per_pixel) {
+	case 16:
+		if (var->xres & 0x1) {
+			dev_err(o1_to_basefb(fbi)->dev,
+				"xres should be a multiple of 2 pixels!\n");
+			return -EINVAL;
+		}
+		break;
+	case 18:
+	case 19:
+		if (var->xres & 0x7) {
+			dev_err(o1_to_basefb(fbi)->dev,
+				"xres should be a multiple of 8 pixels!\n");
+			return -EINVAL;
+		}
+		break;
+	}
+
+	fbi->old_var = *var;
+
+	var->activate = FB_ACTIVATE_NOW;
+
+	return 0;
+}
+
+static int overlay1fb_set_par(struct fb_info *info)
+{
+	struct overlayfb_info *fbi = (struct overlayfb_info *) info;
+	struct fb_var_screeninfo *var = &fbi->fb.var;
+	int nbytes = 0, err = 0, pixels_per_line = 0;
+
+	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(info);
+	if (err)
+		return err;
+
+out2:
+	fbi->xpos = var->nonstd & 0x3ff;
+	fbi->ypos = (var->nonstd>>10) & 0x3ff;
+
+	overlay1fb_enable(info);
+
+	return 0;
+}
+
+static int overlay1fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+	struct overlayfb_info *fbi = (struct overlayfb_info *) info;
+	unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
+
+	if (off < info->fix.smem_len) {
+		vma->vm_pgoff += fbi->video_offset / PAGE_SIZE;
+		return dma_mmap_writecombine(o1_to_basefb(fbi)->dev, vma,
+					     fbi->map_cpu, fbi->map_dma,
+					     fbi->map_size);
+	}
+	return -EINVAL;
+}
+
+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,
+	.fb_mmap		= overlay1fb_mmap,
+};
+
+/*
+ * 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;
+
+	if (!atomic_dec_and_test(&fbi->refcount)) {
+		atomic_inc(&fbi->refcount);
+		return -EACCES;
+	}
+
+	/* If basefb is disable, enable fb */
+	if (o2_to_basefb(fbi)->state != C_ENABLE)
+		o2_to_basefb(fbi)->fb.fbops->fb_blank(VESA_NO_BLANKING,
+				(struct fb_info *) o2_to_basefb(fbi));
+
+	fbi->fb.var.xres = fbi->fb.var.yres = 0;
+
+	return 0;
+}
+
+static int overlay2fb_release(struct fb_info *info, int user)
+{
+	struct overlayfb_info *fbi = (struct overlayfb_info *) info;
+
+	/* Disable overlay when released */
+	overlay2fb_blank(1, info);
+
+	atomic_inc(&fbi->refcount);
+
+	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(o2_to_basefb(fbi)->dev, fbi->map_size,
+					fbi->map_cpu, fbi->map_dma);
+
+	yres = fbi->fb.var.yres;
+
+	switch (fbi->format) {
+	case 0x4: /* YCbCr 4:2:0 planar */
+		dev_dbg(o2_to_basefb(fbi)->dev, "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 */
+		dev_dbg(o2_to_basefb(fbi)->dev, "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 */
+		dev_dbg(o2_to_basefb(fbi)->dev, "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->video_offset = PAGE_ALIGN(sizeof(struct pxafb_dma_descriptor));
+	fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + fbi->video_offset);
+	fbi->map_cpu = dma_alloc_writecombine(o2_to_basefb(fbi)->dev,
+						fbi->map_size, &fbi->map_dma,
+						GFP_KERNEL);
+	if (!fbi->map_cpu)
+		return -ENOMEM;
+
+	/* Prevent initial garbage on screen */
+	memset(fbi->map_cpu, 0, fbi->map_size);
+	fbi->fb.screen_base = fbi->map_cpu + fbi->video_offset;
+	fbi->screen_cpu = fbi->map_cpu + fbi->video_offset;
+	fbi->screen_dma = fbi->map_dma + fbi->video_offset;
+
+	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(o2_to_basefb(fbi)->dev, fbi->map_size,
+					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->video_offset = PAGE_ALIGN(sizeof(struct pxafb_dma_descriptor));
+	fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + fbi->video_offset);
+	fbi->map_cpu = dma_alloc_writecombine(o2_to_basefb(fbi)->dev,
+						fbi->map_size, &fbi->map_dma,
+						GFP_KERNEL);
+	if (!fbi->map_cpu)
+		return -ENOMEM;
+
+	/* Prevent initial garbage on screen */
+	memset(fbi->map_cpu, 0, fbi->map_size);
+	fbi->fb.screen_base = fbi->map_cpu + fbi->video_offset;
+	fbi->screen_cpu = fbi->map_cpu + fbi->video_offset;
+	fbi->screen_dma = fbi->map_dma + fbi->video_offset;
+
+	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;
+	unsigned int lccr5;
+
+	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 = lcd_readl(o2_to_basefb(fbi), LCCR5);
+	lcd_writel(o2_to_basefb(fbi), LCCR5, lccr5
+			| LCCR5_IUM(4) | LCCR5_IUM(3) | LCCR5_IUM(2)
+			| LCCR5_BSM(4) | LCCR5_BSM(3) | LCCR5_BSM(2)
+			| LCCR5_EOFM(4) | LCCR5_EOFM(3) | LCCR5_EOFM(2)
+			| LCCR5_SOFM(4) | LCCR5_SOFM(3) | LCCR5_SOFM(2));
+
+	if (fbi->format == 0) {
+		/* Overlay2 RGB resolution, RGB and YUV have different
+		 * xres value
+		 */
+		xres = fbi->fb.var.xres;
+		yres = fbi->fb.var.yres;
+
+		lcd_writel(o2_to_basefb(fbi), OVL2C2,
+			(fbi->format << 20) | (fbi->ypos << 10) | fbi->xpos);
+		lcd_writel(o2_to_basefb(fbi), OVL2C1,
+			OVL2C1_O2EN | (bpp2 << 20) | ((yres-1)<<10) | (xres-1));
+
+		/* Setup RGB DMA */
+		if (fbi->state == C_DISABLE || fbi->state == C_BLANK)
+			lcd_writel(o2_to_basefb(fbi), FDADR2,
+						fbi->dma2->fdadr);
+		else
+			lcd_writel(o2_to_basefb(fbi), DFBR2,
+						fbi->dma2->fdadr | 0x1);
+	} else {
+		/* Overlay2 YUV resolution */
+		xres = fbi->fb.fix.line_length;
+		yres = fbi->fb.var.yres;
+
+		lcd_writel(o2_to_basefb(fbi), OVL2C2,
+			(fbi->format << 20) | (fbi->ypos << 10) | fbi->xpos);
+		lcd_writel(o2_to_basefb(fbi), OVL2C1,
+			OVL2C1_O2EN | (bpp2 << 20) | ((yres-1)<<10) | (xres-1));
+
+		if (fbi->state == C_DISABLE || fbi->state == C_BLANK) {
+			lcd_writel(o2_to_basefb(fbi), FDADR2,
+						fbi->dma2->fdadr);
+			lcd_writel(o2_to_basefb(fbi), FDADR3,
+						fbi->dma3->fdadr);
+			lcd_writel(o2_to_basefb(fbi), FDADR4,
+						fbi->dma4->fdadr);
+		} else {
+			lcd_writel(o2_to_basefb(fbi), DFBR2,
+						fbi->dma2->fdadr | 0x01);
+			lcd_writel(o2_to_basefb(fbi), DFBR3,
+						fbi->dma3->fdadr | 0x01);
+			lcd_writel(o2_to_basefb(fbi), DFBR4,
+						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;
+	unsigned int ovl2c1;
+	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 = lcd_readl(o2_to_basefb(fbi), OVL2C1);
+	lcd_writel(o2_to_basefb(fbi), OVL2C1, ovl2c1 & ~OVL2C1_O2EN);
+
+	/* Make overlay2 can't disable/enable correctly sometimes */
+	lcd_writel(o2_to_basefb(fbi), LCSR1, LCSR1_BS(2));
+
+	if (fbi->format == 0)
+		lcd_writel(o2_to_basefb(fbi), DFBR2, 0x3);
+	else {
+		lcd_writel(o2_to_basefb(fbi), DFBR2, 0x3);
+		lcd_writel(o2_to_basefb(fbi), DFBR3, 0x3);
+		lcd_writel(o2_to_basefb(fbi), DFBR4, 0x3);
+	}
+
+	done = WAIT_FOR_LCD_INTR(o2_to_basefb(fbi), LCSR1, LCSR1_BS(2), 100);
+	if (!done) {
+		dev_info(o2_to_basefb(fbi)->dev, "%s: timeout\n", __func__);
+		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(o2_to_basefb(fbi), C_REENABLE);
+		}
+		break;
+	case 1:
+		err = overlay2fb_disable(info);
+		if (err) {
+			fbi->state = C_DISABLE;
+			set_ctrlr_state(o2_to_basefb(fbi), C_REENABLE);
+		}
+		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) > o2_to_basefb(fbi)->fb.var.xres)
+		return -EINVAL;
+
+	if ((ypos + yres) > o2_to_basefb(fbi)->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 int overlay2fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+	struct overlayfb_info *fbi = (struct overlayfb_info *) info;
+	unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
+
+	if (off < info->fix.smem_len) {
+		vma->vm_pgoff += fbi->video_offset / PAGE_SIZE;
+		return dma_mmap_writecombine(o2_to_basefb(fbi)->dev, vma,
+					     fbi->map_cpu, fbi->map_dma,
+					     fbi->map_size);
+	}
+	return -EINVAL;
+}
+
+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,
+	.fb_mmap		= overlay2fb_mmap,
+};
+
+/* 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;
+	unsigned int ccr, lccr4, lccr5;
+
+	if (!fbi->map_cpu)
+		return -EINVAL;
+
+	ccr = lcd_readl(cu_to_basefb(fbi), CCR);
+	lcd_writel(cu_to_basefb(fbi), CCR, ccr & ~CCR_CEN);
+
+	/* Set palette format
+	 *
+	 * FIXME: if only cursor uses palette
+	 */
+	lccr4 = lcd_readl(cu_to_basefb(fbi), LCCR4);
+	lcd_writel(cu_to_basefb(fbi), LCCR4,
+			(lccr4 & (~(0x3 << 15))) | (0x1 << 15));
+
+	/* Disable branch/start/end of frame interrupt */
+	lccr5 = lcd_readl(cu_to_basefb(fbi), LCCR5);
+	lcd_writel(cu_to_basefb(fbi), LCCR5,
+				lccr5 | LCCR5_IUM(5) | LCCR5_BSM(5)
+					| LCCR5_EOFM(5) | LCCR5_SOFM(5));
+
+	/* Load palette and frame data */
+	if (fbi->state == C_DISABLE) {
+		lcd_writel(cu_to_basefb(fbi), FDADR5,
+					fbi->dma5_pal->fdadr);
+		udelay(1);
+		lcd_writel(cu_to_basefb(fbi), FDADR5,
+					fbi->dma5_frame->fdadr);
+		udelay(1);
+
+	} else {
+		lcd_writel(cu_to_basefb(fbi), DFBR5,
+					fbi->dma5_pal->fdadr | 0x1);
+		udelay(1);
+		lcd_writel(cu_to_basefb(fbi), DFBR5,
+					fbi->dma5_frame->fdadr | 0x1);
+		udelay(1);
+	}
+
+	lcd_writel(cu_to_basefb(fbi), 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;
+	unsigned int ccr;
+	int done, ret = 0;
+
+	fbi->state = C_DISABLE;
+
+	done = WAIT_FOR_LCD_INTR(cu_to_basefb(fbi), LCSR1, LCSR1_BS(5), 100);
+	if (!done)
+		ret = -1;
+
+	ccr = lcd_readl(cu_to_basefb(fbi), CCR);
+	lcd_writel(cu_to_basefb(fbi), CCR, 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 = 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;
+	}
+
+	return 0;
+}
+
+static int cursorfb_check_var(struct fb_var_screeninfo *var,
+						struct fb_info *info)
+{
+	struct overlayfb_info *fbi = (struct overlayfb_info *) info;
+	int xpos, ypos, xres, yres;
+	int mode;
+	struct cursorfb_mode *cursor;
+
+	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) > cu_to_basefb(fbi)->fb.var.xres)
+		return -EINVAL;
+
+	if ((ypos + yres) > cu_to_basefb(fbi)->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 = 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 	= (u_int *)
+						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(cu_to_basefb(fbi), 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 void __init overlay1fb_init_fbinfo(struct overlayfb_info *fbi)
+{
+	memset(fbi, 0, sizeof(struct overlayfb_info));
+
+	atomic_set(&fbi->refcount, 1);
+	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;
+}
+
+static void __init overlay2fb_init_fbinfo(struct overlayfb_info *fbi)
+{
+	memset(fbi, 0, sizeof(struct overlayfb_info));
+
+	atomic_set(&fbi->refcount, 1);
+	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;
+}
+
+static void __init cursorfb_init_fbinfo(struct overlayfb_info *fbi)
+{
+	memset(fbi, 0, sizeof(struct overlayfb_info));
+
+	atomic_set(&fbi->refcount, 1);
+	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;
+}
+
+
+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;
+	}
+}
+
+void __init pxafb_overlay_probe(struct device *dev)
+{
+	struct pxafb_info *fbi;
+	int ret;
+
+	dev_dbg(dev, "pxafb_overlay_probe\n");
+
+	fbi = dev_get_drvdata(dev);
+	if (!fbi) {
+		dev_err(dev, "base framebuffer not initialized, "
+				"failed to load overlay driver!\n");
+		return;
+	}
+
+	/* Overlay 1 windows */
+	overlay1fb_init_fbinfo(&fbi->overlay1fb);
+	ret = register_framebuffer(&fbi->overlay1fb.fb);
+	if (ret < 0) {
+		dev_err(dev, "unable to register overlay 1 windows\n");
+		goto error_o1;
+	}
+
+	/* Overlay 2 window */
+	overlay2fb_init_fbinfo(&fbi->overlay2fb);
+	ret = register_framebuffer(&fbi->overlay2fb.fb);
+	if (ret < 0) {
+		dev_err(dev, "unable to register overlay 2 windows\n");
+		goto error_o2;
+	}
+
+	/* Hardware cursor window */
+	cursorfb_init_fbinfo(&fbi->cursorfb);
+	ret = register_framebuffer(&fbi->cursorfb.fb);
+	if (ret < 0) {
+		dev_err(dev, "unable to register hardware cursor windows\n");
+		goto error_cu;
+	}
+
+	fbi->set_overlay_ctrlr_state = pxa_set_overlay_ctrlr_state;
+
+	dev_info(dev, "PXA overlay driver enabled\n");
+
+	return;
+
+error_cu:
+	unregister_framebuffer(&fbi->overlay2fb.fb);
+error_o2:
+	unregister_framebuffer(&fbi->overlay1fb.fb);
+error_o1:
+	dev_info(dev, "PXA overlay driver failed\n");
+
+	return;
+}
+EXPORT_SYMBOL(pxafb_overlay_probe);
-- 
1.5.4.3

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ