All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Antonino A. Daplas" <adaplas@gmail.com>
To: Andrew Morton <akpm@osdl.org>,
	Linux Fbdev development list
	<linux-fbdev-devel@lists.sourceforge.net>
Subject: [PATCH 5/5] au1200fb: Alchemy Au1200 framebuffer driver
Date: Thu, 23 Feb 2006 20:07:09 +0800	[thread overview]
Message-ID: <43FDA56D.30902@gmail.com> (raw)

From: Ralf Baechle <ralf@linux-mips.org>

Add support for Alchemy Au1200 framebuffer driver

Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Signed-off-by: Antonino Daplas <adaplas@pol.net>
---

 drivers/video/Kconfig    |   11 
 drivers/video/Makefile   |    1 
 drivers/video/au1200fb.c | 3844 ++++++++++++++++++++++++++++++++++++++++++++++
 drivers/video/au1200fb.h |  572 +++++++
 4 files changed, 4428 insertions(+), 0 deletions(-)

diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 87384d3..e6a02d6 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -1216,6 +1216,17 @@ config FB_AU1100
 	bool "Au1100 LCD Driver"
 	depends on (FB = y) && EXPERIMENTAL && PCI && MIPS && MIPS_PB1100=y
 
+config FB_AU1200
+	bool "Au1200 LCD Driver"
+	depends on FB && MIPS && SOC_AU1200
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	help
+	  This is the framebuffer driver for the AMD Au1200 SOC.  It can drive
+	  various panels and CRTs by passing in kernel cmd line option
+	  au1200fb:panel=<name>.
+
 source "drivers/video/geode/Kconfig"
 
 config FB_FFB
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index aa434e7..cb90218 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -86,6 +86,7 @@ obj-$(CONFIG_FB_ASILIANT)	  += asiliantf
 obj-$(CONFIG_FB_PXA)		  += pxafb.o
 obj-$(CONFIG_FB_W100)		  += w100fb.o
 obj-$(CONFIG_FB_AU1100)		  += au1100fb.o
+obj-$(CONFIG_FB_AU1200)		  += au1200fb.o
 obj-$(CONFIG_FB_PMAG_AA)	  += pmag-aa-fb.o
 obj-$(CONFIG_FB_PMAG_BA)	  += pmag-ba-fb.o
 obj-$(CONFIG_FB_PMAGB_B)	  += pmagb-b-fb.o
diff --git a/drivers/video/au1200fb.c b/drivers/video/au1200fb.c
new file mode 100644
index 0000000..b367de3
--- /dev/null
+++ b/drivers/video/au1200fb.c
@@ -0,0 +1,3844 @@
+/*
+ * BRIEF MODULE DESCRIPTION
+ *	Au1200 LCD Driver.
+ *
+ * Copyright 2004-2005 AMD
+ * Author: AMD
+ *
+ * Based on:
+ * linux/drivers/video/skeletonfb.c -- Skeleton for a frame buffer device
+ *  Created 28 Dec 1997 by Geert Uytterhoeven
+ *
+ *  This program is free software; you can redistribute	 it and/or modify it
+ *  under  the terms of	 the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the	License, or (at your
+ *  option) any later version.
+ *
+ *  THIS  SOFTWARE  IS PROVIDED	  ``AS	IS'' AND   ANY	EXPRESS OR IMPLIED
+ *  WARRANTIES,	  INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO	EVENT  SHALL   THE AUTHOR  BE	 LIABLE FOR ANY	  DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED	  TO, PROCUREMENT OF  SUBSTITUTE GOODS	OR SERVICES; LOSS OF
+ *  USE, DATA,	OR PROFITS; OR	BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN	 CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the  GNU General Public License along
+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ctype.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/mach-au1x00/au1000.h>
+#include "au1200fb.h"
+
+#ifdef CONFIG_PM
+#include <asm/mach-au1x00/au1xxx_pm.h>
+#endif
+
+#ifndef CONFIG_FB_AU1200_DEVS
+#define CONFIG_FB_AU1200_DEVS 4
+#endif
+
+#define DRIVER_NAME "au1200fb"
+#define DRIVER_DESC "LCD controller driver for AU1200 processors"
+
+#define DEBUG 1
+
+#define print_err(f, arg...) printk(KERN_ERR DRIVER_NAME ": " f "\n", ## arg)
+#define print_warn(f, arg...) printk(KERN_WARNING DRIVER_NAME ": " f "\n", ## arg)
+#define print_info(f, arg...) printk(KERN_INFO DRIVER_NAME ": " f "\n", ## arg)
+
+#if DEBUG
+#define print_dbg(f, arg...) printk(KERN_DEBUG __FILE__ ": " f "\n", ## arg)
+#else
+#define print_dbg(f, arg...) do {} while (0)
+#endif
+
+
+#define AU1200_LCD_FB_IOCTL 0x46FF
+
+#define AU1200_LCD_SET_SCREEN 1
+#define AU1200_LCD_GET_SCREEN 2
+#define AU1200_LCD_SET_WINDOW 3
+#define AU1200_LCD_GET_WINDOW 4
+#define AU1200_LCD_SET_PANEL  5
+#define AU1200_LCD_GET_PANEL  6
+
+#define SCREEN_SIZE		    (1<< 1)
+#define SCREEN_BACKCOLOR    (1<< 2)
+#define SCREEN_BRIGHTNESS   (1<< 3)
+#define SCREEN_COLORKEY     (1<< 4)
+#define SCREEN_MASK         (1<< 5)
+
+struct au1200_lcd_global_regs_t {
+	unsigned int flags;
+	unsigned int xsize;
+	unsigned int ysize;
+	unsigned int backcolor;
+	unsigned int brightness;
+	unsigned int colorkey;
+	unsigned int mask;
+	unsigned int panel_choice;
+	char panel_desc[80];
+
+};
+
+#define WIN_POSITION            (1<< 0)
+#define WIN_ALPHA_COLOR         (1<< 1)
+#define WIN_ALPHA_MODE          (1<< 2)
+#define WIN_PRIORITY            (1<< 3)
+#define WIN_CHANNEL             (1<< 4)
+#define WIN_BUFFER_FORMAT       (1<< 5)
+#define WIN_COLOR_ORDER         (1<< 6)
+#define WIN_PIXEL_ORDER         (1<< 7)
+#define WIN_SIZE                (1<< 8)
+#define WIN_COLORKEY_MODE       (1<< 9)
+#define WIN_DOUBLE_BUFFER_MODE  (1<< 10)
+#define WIN_RAM_ARRAY_MODE      (1<< 11)
+#define WIN_BUFFER_SCALE        (1<< 12)
+#define WIN_ENABLE	            (1<< 13)
+
+struct au1200_lcd_window_regs_t {
+	unsigned int flags;
+	unsigned int xpos;
+	unsigned int ypos;
+	unsigned int alpha_color;
+	unsigned int alpha_mode;
+	unsigned int priority;
+	unsigned int channel;
+	unsigned int buffer_format;
+	unsigned int color_order;
+	unsigned int pixel_order;
+	unsigned int xsize;
+	unsigned int ysize;
+	unsigned int colorkey_mode;
+	unsigned int double_buffer_mode;
+	unsigned int ram_array_mode;
+	unsigned int xscale;
+	unsigned int yscale;
+	unsigned int enable;
+};
+
+
+struct au1200_lcd_iodata_t {
+	unsigned int subcmd;
+	struct au1200_lcd_global_regs_t global;
+	struct au1200_lcd_window_regs_t window;
+};
+
+#if defined(__BIG_ENDIAN)
+#define LCD_CONTROL_DEFAULT_PO LCD_CONTROL_PO_11
+#else
+#define LCD_CONTROL_DEFAULT_PO LCD_CONTROL_PO_00
+#endif
+#define LCD_CONTROL_DEFAULT_SBPPF LCD_CONTROL_SBPPF_565
+
+/* Private, per-framebuffer management information (independent of the panel itself) */
+struct au1200fb_device {
+	struct fb_info fb_info;			/* FB driver info record */
+
+	int					plane;
+	unsigned char* 		fb_mem;		/* FrameBuffer memory map */
+	unsigned int		fb_len;
+	dma_addr_t    		fb_phys;
+};
+
+static struct au1200fb_device _au1200fb_devices[CONFIG_FB_AU1200_DEVS];
+/********************************************************************/
+
+/* LCD controller restrictions */
+#define AU1200_LCD_MAX_XRES	1280
+#define AU1200_LCD_MAX_YRES	1024
+#define AU1200_LCD_MAX_BPP	32
+#define AU1200_LCD_MAX_CLK	96000000 /* fixme: this needs to go away ? */
+#define AU1200_LCD_NBR_PALETTE_ENTRIES 256
+
+/* Default number of visible screen buffer to allocate */
+#define AU1200FB_NBR_VIDEO_BUFFERS 1
+
+/********************************************************************/
+
+static struct au1200_lcd *lcd = (struct au1200_lcd *) AU1200_LCD_ADDR;
+static int window_index = 2; /* default is zero */
+static int panel_index = 2; /* default is zero */
+static struct window_settings *win;
+static struct panel_settings *panel;
+static int noblanking = 1;
+static int nohwcursor = 0;
+
+struct window_settings {
+	unsigned char name[64];
+	uint32 mode_backcolor;
+	uint32 mode_colorkey;
+	uint32 mode_colorkeymsk;
+	struct {
+		int xres;
+		int yres;
+		int xpos;
+		int ypos;
+		uint32 mode_winctrl1; /* winctrl1[FRM,CCO,PO,PIPE] */
+		uint32 mode_winenable;
+	} w[4];
+};
+
+#if defined(__BIG_ENDIAN)
+#define LCD_WINCTRL1_PO_16BPP LCD_WINCTRL1_PO_00
+#else
+#define LCD_WINCTRL1_PO_16BPP LCD_WINCTRL1_PO_01
+#endif
+
+extern int board_au1200fb_panel_init (void);
+extern int board_au1200fb_panel_shutdown (void);
+
+#ifdef CONFIG_PM
+int au1200fb_pm_callback(au1xxx_power_dev_t *dev,
+		au1xxx_request_t request, void *data);
+au1xxx_power_dev_t *LCD_pm_dev;
+#endif
+
+/*
+ * Default window configurations
+ */
+static struct window_settings windows[] = {
+	{ /* Index 0 */
+		"0-FS gfx, 1-video, 2-ovly gfx, 3-ovly gfx",
+		/* mode_backcolor	*/ 0x006600ff,
+		/* mode_colorkey,msk*/ 0, 0,
+		{
+			{
+			/* xres, yres, xpos, ypos */ 0, 0, 0, 0,
+			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
+				LCD_WINCTRL1_PO_16BPP,
+			/* mode_winenable*/ LCD_WINENABLE_WEN0,
+			},
+			{
+			/* xres, yres, xpos, ypos */ 100, 100, 100, 100,
+			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
+				LCD_WINCTRL1_PO_16BPP |
+				LCD_WINCTRL1_PIPE,
+			/* mode_winenable*/ LCD_WINENABLE_WEN1,
+			},
+			{
+			/* xres, yres, xpos, ypos */ 0, 0, 0, 0,
+			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
+				LCD_WINCTRL1_PO_16BPP,
+			/* mode_winenable*/ 0,
+			},
+			{
+			/* xres, yres, xpos, ypos */ 0, 0, 0, 0,
+			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
+				LCD_WINCTRL1_PO_16BPP |
+				LCD_WINCTRL1_PIPE,
+			/* mode_winenable*/ 0,
+			},
+		},
+	},
+
+	{ /* Index 1 */
+		"0-FS gfx, 1-video, 2-ovly gfx, 3-ovly gfx",
+		/* mode_backcolor	*/ 0x006600ff,
+		/* mode_colorkey,msk*/ 0, 0,
+		{
+			{
+			/* xres, yres, xpos, ypos */ 320, 240, 5, 5,
+			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_24BPP |
+				LCD_WINCTRL1_PO_00,
+			/* mode_winenable*/ LCD_WINENABLE_WEN0,
+			},
+			{
+			/* xres, yres, xpos, ypos */ 0, 0, 0, 0,
+			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565
+				| LCD_WINCTRL1_PO_16BPP,
+			/* mode_winenable*/ 0,
+			},
+			{
+			/* xres, yres, xpos, ypos */ 100, 100, 0, 0,
+			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
+				LCD_WINCTRL1_PO_16BPP |
+				LCD_WINCTRL1_PIPE,
+			/* mode_winenable*/ 0/*LCD_WINENABLE_WEN2*/,
+			},
+			{
+			/* xres, yres, xpos, ypos */ 200, 25, 0, 0,
+			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
+				LCD_WINCTRL1_PO_16BPP |
+				LCD_WINCTRL1_PIPE,
+			/* mode_winenable*/ 0,
+			},
+		},
+	},
+	{ /* Index 2 */
+		"0-FS gfx, 1-video, 2-ovly gfx, 3-ovly gfx",
+		/* mode_backcolor	*/ 0x006600ff,
+		/* mode_colorkey,msk*/ 0, 0,
+		{
+			{
+			/* xres, yres, xpos, ypos */ 0, 0, 0, 0,
+			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
+				LCD_WINCTRL1_PO_16BPP,
+			/* mode_winenable*/ LCD_WINENABLE_WEN0,
+			},
+			{
+			/* xres, yres, xpos, ypos */ 0, 0, 0, 0,
+			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
+				LCD_WINCTRL1_PO_16BPP,
+			/* mode_winenable*/ 0,
+			},
+			{
+			/* xres, yres, xpos, ypos */ 0, 0, 0, 0,
+			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_32BPP |
+				LCD_WINCTRL1_PO_00|LCD_WINCTRL1_PIPE,
+			/* mode_winenable*/ 0/*LCD_WINENABLE_WEN2*/,
+			},
+			{
+			/* xres, yres, xpos, ypos */ 0, 0, 0, 0,
+			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
+				LCD_WINCTRL1_PO_16BPP |
+				LCD_WINCTRL1_PIPE,
+			/* mode_winenable*/ 0,
+			},
+		},
+	},
+	/* Need VGA 640 @ 24bpp, @ 32bpp */
+	/* Need VGA 800 @ 24bpp, @ 32bpp */
+	/* Need VGA 1024 @ 24bpp, @ 32bpp */
+};
+
+/*
+ * Controller configurations for various panels.
+ */
+
+struct panel_settings
+{
+	const char name[25];		/* Full name <vendor>_<model> */
+
+	struct 	fb_monspecs monspecs; 	/* FB monitor specs */
+
+	/* panel timings */
+	uint32 mode_screen;
+	uint32 mode_horztiming;
+	uint32 mode_verttiming;
+	uint32 mode_clkcontrol;
+	uint32 mode_pwmdiv;
+	uint32 mode_pwmhi;
+	uint32 mode_outmask;
+	uint32 mode_fifoctrl;
+	uint32 mode_toyclksrc;
+	uint32 mode_backlight;
+	uint32 mode_auxpll;
+	int (*device_init)(void);
+	int (*device_shutdown)(void);
+#define Xres min_xres
+#define Yres min_yres
+	u32	min_xres;		/* Minimum horizontal resolution */
+	u32	max_xres;		/* Maximum horizontal resolution */
+	u32 	min_yres;		/* Minimum vertical resolution */
+	u32 	max_yres;		/* Maximum vertical resolution */
+};
+
+/********************************************************************/
+/* fixme: Maybe a modedb for the CRT ? otherwise panels should be as-is */
+
+/* List of panels known to work with the AU1200 LCD controller.
+ * To add a new panel, enter the same specifications as the
+ * Generic_TFT one, and MAKE SURE that it doesn't conflicts
+ * with the controller restrictions. Restrictions are:
+ *
+ * STN color panels: max_bpp <= 12
+ * STN mono panels: max_bpp <= 4
+ * TFT panels: max_bpp <= 16
+ * max_xres <= 800
+ * max_yres <= 600
+ */
+static struct panel_settings known_lcd_panels[] =
+{
+	[0] = { /* QVGA 320x240 H:33.3kHz V:110Hz */
+		.name = "QVGA_320x240",
+		.monspecs = {
+			.modedb = NULL,
+			.modedb_len = 0,
+			.hfmin = 30000,
+			.hfmax = 70000,
+			.vfmin = 60,
+			.vfmax = 60,
+			.dclkmin = 6000000,
+			.dclkmax = 28000000,
+			.input = FB_DISP_RGB,
+		},
+		.mode_screen		= LCD_SCREEN_SX_N(320) |
+			LCD_SCREEN_SY_N(240),
+		.mode_horztiming	= 0x00c4623b,
+		.mode_verttiming	= 0x00502814,
+		.mode_clkcontrol	= 0x00020002, /* /4=24Mhz */
+		.mode_pwmdiv		= 0x00000000,
+		.mode_pwmhi		= 0x00000000,
+		.mode_outmask	= 0x00FFFFFF,
+		.mode_fifoctrl	= 0x2f2f2f2f,
+		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
+		.mode_backlight	= 0x00000000,
+		.mode_auxpll		= 8, /* 96MHz AUXPLL */
+		.device_init		= NULL,
+		.device_shutdown	= NULL,
+		320, 320,
+		240, 240,
+	},
+
+	[1] = { /* VGA 640x480 H:30.3kHz V:58Hz */
+		.name = "VGA_640x480",
+		.monspecs = {
+			.modedb = NULL,
+			.modedb_len = 0,
+			.hfmin = 30000,
+			.hfmax = 70000,
+			.vfmin = 60,
+			.vfmax = 60,
+			.dclkmin = 6000000,
+			.dclkmax = 28000000,
+			.input = FB_DISP_RGB,
+		},
+		.mode_screen		= 0x13f9df80,
+		.mode_horztiming	= 0x003c5859,
+		.mode_verttiming	= 0x00741201,
+		.mode_clkcontrol	= 0x00020001, /* /4=24Mhz */
+		.mode_pwmdiv		= 0x00000000,
+		.mode_pwmhi		= 0x00000000,
+		.mode_outmask	= 0x00FFFFFF,
+		.mode_fifoctrl	= 0x2f2f2f2f,
+		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
+		.mode_backlight	= 0x00000000,
+		.mode_auxpll		= 8, /* 96MHz AUXPLL */
+		.device_init		= NULL,
+		.device_shutdown	= NULL,
+		640, 480,
+		640, 480,
+	},
+
+	[2] = { /* SVGA 800x600 H:46.1kHz V:69Hz */
+		.name = "SVGA_800x600",
+		.monspecs = {
+			.modedb = NULL,
+			.modedb_len = 0,
+			.hfmin = 30000,
+			.hfmax = 70000,
+			.vfmin = 60,
+			.vfmax = 60,
+			.dclkmin = 6000000,
+			.dclkmax = 28000000,
+			.input = FB_DISP_RGB,
+		},
+		.mode_screen		= 0x18fa5780,
+		.mode_horztiming	= 0x00dc7e77,
+		.mode_verttiming	= 0x00584805,
+		.mode_clkcontrol	= 0x00020000, /* /2=48Mhz */
+		.mode_pwmdiv		= 0x00000000,
+		.mode_pwmhi		= 0x00000000,
+		.mode_outmask	= 0x00FFFFFF,
+		.mode_fifoctrl	= 0x2f2f2f2f,
+		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
+		.mode_backlight	= 0x00000000,
+		.mode_auxpll		= 8, /* 96MHz AUXPLL */
+		.device_init		= NULL,
+		.device_shutdown	= NULL,
+		800, 800,
+		600, 600,
+	},
+
+	[3] = { /* XVGA 1024x768 H:56.2kHz V:70Hz */
+		.name = "XVGA_1024x768",
+		.monspecs = {
+			.modedb = NULL,
+			.modedb_len = 0,
+			.hfmin = 30000,
+			.hfmax = 70000,
+			.vfmin = 60,
+			.vfmax = 60,
+			.dclkmin = 6000000,
+			.dclkmax = 28000000,
+			.input = FB_DISP_RGB,
+		},
+		.mode_screen		= 0x1ffaff80,
+		.mode_horztiming	= 0x007d0e57,
+		.mode_verttiming	= 0x00740a01,
+		.mode_clkcontrol	= 0x000A0000, /* /1 */
+		.mode_pwmdiv		= 0x00000000,
+		.mode_pwmhi		= 0x00000000,
+		.mode_outmask	= 0x00FFFFFF,
+		.mode_fifoctrl	= 0x2f2f2f2f,
+		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
+		.mode_backlight	= 0x00000000,
+		.mode_auxpll		= 6, /* 72MHz AUXPLL */
+		.device_init		= NULL,
+		.device_shutdown	= NULL,
+		1024, 1024,
+		768, 768,
+	},
+
+	[4] = { /* XVGA XVGA 1280x1024 H:68.5kHz V:65Hz */
+		.name = "XVGA_1280x1024",
+		.monspecs = {
+			.modedb = NULL,
+			.modedb_len = 0,
+			.hfmin = 30000,
+			.hfmax = 70000,
+			.vfmin = 60,
+			.vfmax = 60,
+			.dclkmin = 6000000,
+			.dclkmax = 28000000,
+			.input = FB_DISP_RGB,
+		},
+		.mode_screen		= 0x27fbff80,
+		.mode_horztiming	= 0x00cdb2c7,
+		.mode_verttiming	= 0x00600002,
+		.mode_clkcontrol	= 0x000A0000, /* /1 */
+		.mode_pwmdiv		= 0x00000000,
+		.mode_pwmhi		= 0x00000000,
+		.mode_outmask	= 0x00FFFFFF,
+		.mode_fifoctrl	= 0x2f2f2f2f,
+		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
+		.mode_backlight	= 0x00000000,
+		.mode_auxpll		= 10, /* 120MHz AUXPLL */
+		.device_init		= NULL,
+		.device_shutdown	= NULL,
+		1280, 1280,
+		1024, 1024,
+	},
+
+	[5] = { /* Samsung 1024x768 TFT */
+		.name = "Samsung_1024x768_TFT",
+		.monspecs = {
+			.modedb = NULL,
+			.modedb_len = 0,
+			.hfmin = 30000,
+			.hfmax = 70000,
+			.vfmin = 60,
+			.vfmax = 60,
+			.dclkmin = 6000000,
+			.dclkmax = 28000000,
+			.input = FB_DISP_RGB,
+		},
+		.mode_screen		= 0x1ffaff80,
+		.mode_horztiming	= 0x018cc677,
+		.mode_verttiming	= 0x00241217,
+		.mode_clkcontrol	= 0x00000000, /* SCB 0x1 /4=24Mhz */
+		.mode_pwmdiv		= 0x8000063f, /* SCB 0x0 */
+		.mode_pwmhi		= 0x03400000, /* SCB 0x0 */
+		.mode_outmask	= 0x00FFFFFF,
+		.mode_fifoctrl	= 0x2f2f2f2f,
+		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
+		.mode_backlight	= 0x00000000,
+		.mode_auxpll		= 8, /* 96MHz AUXPLL */
+		.device_init		= board_au1200fb_panel_init,
+		.device_shutdown	= board_au1200fb_panel_shutdown,
+		1024, 1024,
+		768, 768,
+	},
+
+	[6] = { /* Toshiba 640x480 TFT */
+		.name = "Toshiba_640x480_TFT",
+		.monspecs = {
+			.modedb = NULL,
+			.modedb_len = 0,
+			.hfmin = 30000,
+			.hfmax = 70000,
+			.vfmin = 60,
+			.vfmax = 60,
+			.dclkmin = 6000000,
+			.dclkmax = 28000000,
+			.input = FB_DISP_RGB,
+		},
+		.mode_screen		= LCD_SCREEN_SX_N(640) |
+			LCD_SCREEN_SY_N(480),
+		.mode_horztiming	= LCD_HORZTIMING_HPW_N(96) |
+			LCD_HORZTIMING_HND1_N(13) | LCD_HORZTIMING_HND2_N(51),
+		.mode_verttiming	= LCD_VERTTIMING_VPW_N(2) |
+			LCD_VERTTIMING_VND1_N(11) | LCD_VERTTIMING_VND2_N(32),
+		.mode_clkcontrol	= 0x00000000, /* /4=24Mhz */
+		.mode_pwmdiv		= 0x8000063f,
+		.mode_pwmhi		= 0x03400000,
+		.mode_outmask	= 0x00fcfcfc,
+		.mode_fifoctrl	= 0x2f2f2f2f,
+		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
+		.mode_backlight	= 0x00000000,
+		.mode_auxpll		= 8, /* 96MHz AUXPLL */
+		.device_init		= board_au1200fb_panel_init,
+		.device_shutdown	= board_au1200fb_panel_shutdown,
+		640, 480,
+		640, 480,
+	},
+
+	[7] = { /* Sharp 320x240 TFT */
+		.name = "Sharp_320x240_TFT",
+		.monspecs = {
+			.modedb = NULL,
+			.modedb_len = 0,
+			.hfmin = 12500,
+			.hfmax = 20000,
+			.vfmin = 38,
+			.vfmax = 81,
+			.dclkmin = 4500000,
+			.dclkmax = 6800000,
+			.input = FB_DISP_RGB,
+		},
+		.mode_screen		= LCD_SCREEN_SX_N(320) |
+			LCD_SCREEN_SY_N(240),
+		.mode_horztiming	= LCD_HORZTIMING_HPW_N(60) |
+			LCD_HORZTIMING_HND1_N(13) | LCD_HORZTIMING_HND2_N(2),
+		.mode_verttiming	= LCD_VERTTIMING_VPW_N(2) |
+			LCD_VERTTIMING_VND1_N(2) | LCD_VERTTIMING_VND2_N(5),
+		.mode_clkcontrol	= LCD_CLKCONTROL_PCD_N(7), /*16=6Mhz*/
+		.mode_pwmdiv		= 0x8000063f,
+		.mode_pwmhi		= 0x03400000,
+		.mode_outmask	= 0x00fcfcfc,
+		.mode_fifoctrl	= 0x2f2f2f2f,
+		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
+		.mode_backlight	= 0x00000000,
+		.mode_auxpll		= 8, /* 96MHz AUXPLL */
+		.device_init		= board_au1200fb_panel_init,
+		.device_shutdown	= board_au1200fb_panel_shutdown,
+		320, 320,
+		240, 240,
+	},
+
+	[8] = { /* Toppoly TD070WGCB2 7" 856x480 TFT */
+		.name = "Toppoly_TD070WGCB2",
+		.monspecs = {
+			.modedb = NULL,
+			.modedb_len = 0,
+			.hfmin = 30000,
+			.hfmax = 70000,
+			.vfmin = 60,
+			.vfmax = 60,
+			.dclkmin = 6000000,
+			.dclkmax = 28000000,
+			.input = FB_DISP_RGB,
+		},
+		.mode_screen		= LCD_SCREEN_SX_N(856) |
+			LCD_SCREEN_SY_N(480),
+		.mode_horztiming	= LCD_HORZTIMING_HND2_N(43) |
+			LCD_HORZTIMING_HND1_N(43) | LCD_HORZTIMING_HPW_N(114),
+		.mode_verttiming	= LCD_VERTTIMING_VND2_N(20) |
+			LCD_VERTTIMING_VND1_N(21) | LCD_VERTTIMING_VPW_N(4),
+		.mode_clkcontrol	= 0x00020001, /* /4=24Mhz */
+		.mode_pwmdiv		= 0x8000063f,
+		.mode_pwmhi		= 0x03400000,
+		.mode_outmask	= 0x00fcfcfc,
+		.mode_fifoctrl	= 0x2f2f2f2f,
+		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
+		.mode_backlight	= 0x00000000,
+		.mode_auxpll		= 8, /* 96MHz AUXPLL */
+		.device_init		= board_au1200fb_panel_init,
+		.device_shutdown	= board_au1200fb_panel_shutdown,
+		856, 856,
+		480, 480,
+	},
+};
+
+#define NUM_PANELS (ARRAY_SIZE(known_lcd_panels))
+
+/********************************************************************/
+
+#ifdef CONFIG_PM
+static int set_brightness(unsigned int brightness)
+{
+	unsigned int hi1, divider;
+
+	/* limit brightness pwm duty to >= 30/1600 */
+	if (brightness < 30) {
+		brightness = 30;
+	}
+	divider = (lcd->pwmdiv & 0x3FFFF) + 1;
+	hi1 = (lcd->pwmhi >> 16) + 1;
+	hi1 = (((brightness & 0xFF) + 1) * divider >> 8);
+	lcd->pwmhi &= 0xFFFF;
+	lcd->pwmhi |= (hi1 << 16);
+
+	return brightness;
+}
+#endif /* CONFIG_PM */
+
+static int winbpp (unsigned int winctrl1)
+{
+	int bits = 0;
+
+	/* how many bits are needed for each pixel format */
+	switch (winctrl1 & LCD_WINCTRL1_FRM) {
+	case LCD_WINCTRL1_FRM_1BPP:
+		bits = 1;
+		break;
+	case LCD_WINCTRL1_FRM_2BPP:
+		bits = 2;
+		break;
+	case LCD_WINCTRL1_FRM_4BPP:
+		bits = 4;
+		break;
+	case LCD_WINCTRL1_FRM_8BPP:
+		bits = 8;
+		break;
+	case LCD_WINCTRL1_FRM_12BPP:
+	case LCD_WINCTRL1_FRM_16BPP655:
+	case LCD_WINCTRL1_FRM_16BPP565:
+	case LCD_WINCTRL1_FRM_16BPP556:
+	case LCD_WINCTRL1_FRM_16BPPI1555:
+	case LCD_WINCTRL1_FRM_16BPPI5551:
+	case LCD_WINCTRL1_FRM_16BPPA1555:
+	case LCD_WINCTRL1_FRM_16BPPA5551:
+		bits = 16;
+		break;
+	case LCD_WINCTRL1_FRM_24BPP:
+	case LCD_WINCTRL1_FRM_32BPP:
+		bits = 32;
+		break;
+	}
+
+	return bits;
+}
+
+static int fbinfo2index (struct fb_info *fb_info)
+{
+	int i;
+
+	for (i = 0; i < CONFIG_FB_AU1200_DEVS; ++i) {
+		if (fb_info == (struct fb_info *)(&_au1200fb_devices[i].fb_info))
+			return i;
+	}
+	printk("au1200fb: ERROR: fbinfo2index failed!\n");
+	return -1;
+}
+
+static int au1200_setlocation (struct au1200fb_device *fbdev, int plane,
+	int xpos, int ypos)
+{
+	uint32 winctrl0, winctrl1, winenable, fb_offset = 0;
+	int xsz, ysz;
+
+	/* FIX!!! NOT CHECKING FOR COMPLETE OFFSCREEN YET */
+
+	winctrl0 = lcd->window[plane].winctrl0;
+	winctrl1 = lcd->window[plane].winctrl1;
+	winctrl0 &= (LCD_WINCTRL0_A | LCD_WINCTRL0_AEN);
+	winctrl1 &= ~(LCD_WINCTRL1_SZX | LCD_WINCTRL1_SZY);
+
+	/* Check for off-screen adjustments */
+	xsz = win->w[plane].xres;
+	ysz = win->w[plane].yres;
+	if ((xpos + win->w[plane].xres) > panel->Xres) {
+		/* Off-screen to the right */
+		xsz = panel->Xres - xpos; /* off by 1 ??? */
+		/*printk("off screen right\n");*/
+	}
+
+	if ((ypos + win->w[plane].yres) > panel->Yres) {
+		/* Off-screen to the bottom */
+		ysz = panel->Yres - ypos; /* off by 1 ??? */
+		/*printk("off screen bottom\n");*/
+	}
+
+	if (xpos < 0) {
+		/* Off-screen to the left */
+		xsz = win->w[plane].xres + xpos;
+		fb_offset += (((0 - xpos) * winbpp(lcd->window[plane].winctrl1))/8);
+		xpos = 0;
+		/*printk("off screen left\n");*/
+	}
+
+	if (ypos < 0) {
+		/* Off-screen to the top */
+		ysz = win->w[plane].yres + ypos;
+		/* fixme: fb_offset += ((0-ypos)*fb_pars[plane].line_length); */
+		ypos = 0;
+		/*printk("off screen top\n");*/
+	}
+
+	/* record settings */
+	win->w[plane].xpos = xpos;
+	win->w[plane].ypos = ypos;
+
+	xsz -= 1;
+	ysz -= 1;
+	winctrl0 |= (xpos << 21);
+	winctrl0 |= (ypos << 10);
+	winctrl1 |= (xsz << 11);
+	winctrl1 |= (ysz << 0);
+
+	/* Disable the window while making changes, then restore WINEN */
+	winenable = lcd->winenable & (1 << plane);
+	au_sync();
+	lcd->winenable &= ~(1 << plane);
+	lcd->window[plane].winctrl0 = winctrl0;
+	lcd->window[plane].winctrl1 = winctrl1;
+	lcd->window[plane].winbuf0 =
+	lcd->window[plane].winbuf1 = fbdev->fb_phys;
+	lcd->window[plane].winbufctrl = 0; /* select winbuf0 */
+	lcd->winenable |= winenable;
+	au_sync();
+
+	return 0;
+}
+
+static void au1200_setpanel (struct panel_settings *newpanel)
+{
+	/*
+	 * Perform global setup/init of LCD controller
+	 */
+	uint32 winenable;
+
+	/* Make sure all windows disabled */
+	winenable = lcd->winenable;
+	lcd->winenable = 0;
+	au_sync();
+	/*
+	 * Ensure everything is disabled before reconfiguring
+	 */
+	if (lcd->screen & LCD_SCREEN_SEN) {
+		/* Wait for vertical sync period */
+		lcd->intstatus = LCD_INT_SS;
+		while ((lcd->intstatus & LCD_INT_SS) == 0) {
+			au_sync();
+		}
+
+		lcd->screen &= ~LCD_SCREEN_SEN;	/*disable the controller*/
+
+		do {
+			lcd->intstatus = lcd->intstatus; /*clear interrupts*/
+			au_sync();
+		/*wait for controller to shut down*/
+		} while ((lcd->intstatus & LCD_INT_SD) == 0);
+
+		/* Call shutdown of current panel (if up) */
+		/* this must occur last, because if an external clock is driving
+		    the controller, the clock cannot be turned off before first
+			shutting down the controller.
+		 */
+		if (panel->device_shutdown != NULL)
+			panel->device_shutdown();
+	}
+
+	/* Newpanel == NULL indicates a shutdown operation only */
+	if (newpanel == NULL)
+		return;
+
+	panel = newpanel;
+
+	printk("Panel(%s), %dx%d\n", panel->name, panel->Xres, panel->Yres);
+
+	/*
+	 * Setup clocking if internal LCD clock source (assumes sys_auxpll valid)
+	 */
+	if (!(panel->mode_clkcontrol & LCD_CLKCONTROL_EXT))
+	{
+		uint32 sys_clksrc;
+		au_writel(panel->mode_auxpll, SYS_AUXPLL);
+		sys_clksrc = au_readl(SYS_CLKSRC) & ~0x0000001f;
+		sys_clksrc |= panel->mode_toyclksrc;
+		au_writel(sys_clksrc, SYS_CLKSRC);
+	}
+
+	/*
+	 * Configure panel timings
+	 */
+	lcd->screen = panel->mode_screen;
+	lcd->horztiming = panel->mode_horztiming;
+	lcd->verttiming = panel->mode_verttiming;
+	lcd->clkcontrol = panel->mode_clkcontrol;
+	lcd->pwmdiv = panel->mode_pwmdiv;
+	lcd->pwmhi = panel->mode_pwmhi;
+	lcd->outmask = panel->mode_outmask;
+	lcd->fifoctrl = panel->mode_fifoctrl;
+	au_sync();
+
+	/* fixme: Check window settings to make sure still valid
+	 * for new geometry */
+#if 0
+	au1200_setlocation(fbdev, 0, win->w[0].xpos, win->w[0].ypos);
+	au1200_setlocation(fbdev, 1, win->w[1].xpos, win->w[1].ypos);
+	au1200_setlocation(fbdev, 2, win->w[2].xpos, win->w[2].ypos);
+	au1200_setlocation(fbdev, 3, win->w[3].xpos, win->w[3].ypos);
+#endif
+	lcd->winenable = winenable;
+
+	/*
+	 * Re-enable screen now that it is configured
+	 */
+	lcd->screen |= LCD_SCREEN_SEN;
+	au_sync();
+
+	/* Call init of panel */
+	if (panel->device_init != NULL) panel->device_init();
+
+	/* FIX!!!! not appropriate on panel change!!! Global setup/init */
+	lcd->intenable = 0;
+	lcd->intstatus = ~0;
+	lcd->backcolor = win->mode_backcolor;
+
+	/* Setup Color Key - FIX!!! */
+	lcd->colorkey = win->mode_colorkey;
+	lcd->colorkeymsk = win->mode_colorkeymsk;
+
+	/* Setup HWCursor - FIX!!! Need to support this eventually */
+	lcd->hwc.cursorctrl = 0;
+	lcd->hwc.cursorpos = 0;
+	lcd->hwc.cursorcolor0 = 0;
+	lcd->hwc.cursorcolor1 = 0;
+	lcd->hwc.cursorcolor2 = 0;
+	lcd->hwc.cursorcolor3 = 0;
+
+
+#if 0
+#define D(X) printk("%25s: %08X\n", #X, X)
+	D(lcd->screen);
+	D(lcd->horztiming);
+	D(lcd->verttiming);
+	D(lcd->clkcontrol);
+	D(lcd->pwmdiv);
+	D(lcd->pwmhi);
+	D(lcd->outmask);
+	D(lcd->fifoctrl);
+	D(lcd->window[0].winctrl0);
+	D(lcd->window[0].winctrl1);
+	D(lcd->window[0].winctrl2);
+	D(lcd->window[0].winbuf0);
+	D(lcd->window[0].winbuf1);
+	D(lcd->window[0].winbufctrl);
+	D(lcd->window[1].winctrl0);
+	D(lcd->window[1].winctrl1);
+	D(lcd->window[1].winctrl2);
+	D(lcd->window[1].winbuf0);
+	D(lcd->window[1].winbuf1);
+	D(lcd->window[1].winbufctrl);
+	D(lcd->window[2].winctrl0);
+	D(lcd->window[2].winctrl1);
+	D(lcd->window[2].winctrl2);
+	D(lcd->window[2].winbuf0);
+	D(lcd->window[2].winbuf1);
+	D(lcd->window[2].winbufctrl);
+	D(lcd->window[3].winctrl0);
+	D(lcd->window[3].winctrl1);
+	D(lcd->window[3].winctrl2);
+	D(lcd->window[3].winbuf0);
+	D(lcd->window[3].winbuf1);
+	D(lcd->window[3].winbufctrl);
+	D(lcd->winenable);
+	D(lcd->intenable);
+	D(lcd->intstatus);
+	D(lcd->backcolor);
+	D(lcd->winenable);
+	D(lcd->colorkey);
+    D(lcd->colorkeymsk);
+	D(lcd->hwc.cursorctrl);
+	D(lcd->hwc.cursorpos);
+	D(lcd->hwc.cursorcolor0);
+	D(lcd->hwc.cursorcolor1);
+	D(lcd->hwc.cursorcolor2);
+	D(lcd->hwc.cursorcolor3);
+#endif
+}
+
+static void au1200_setmode(struct au1200fb_device *fbdev)
+{
+	int plane = fbdev->plane;
+	/* Window/plane setup */
+	lcd->window[plane].winctrl1 = ( 0
+		| LCD_WINCTRL1_PRI_N(plane)
+		| win->w[plane].mode_winctrl1 /* FRM,CCO,PO,PIPE */
+		) ;
+
+	au1200_setlocation(fbdev, plane, win->w[plane].xpos, win->w[plane].ypos);
+
+	lcd->window[plane].winctrl2 = ( 0
+		| LCD_WINCTRL2_CKMODE_00
+		| LCD_WINCTRL2_DBM
+		| LCD_WINCTRL2_BX_N( fbdev->fb_info.fix.line_length)
+		| LCD_WINCTRL2_SCX_1
+		| LCD_WINCTRL2_SCY_1
+		) ;
+	lcd->winenable |= win->w[plane].mode_winenable;
+	au_sync();
+}
+
+
+/* Inline helpers */
+
+/*#define panel_is_dual(panel)  ((panel->mode_screen & LCD_SCREEN_PT) == LCD_SCREEN_PT_010)*/
+/*#define panel_is_active(panel)((panel->mode_screen & LCD_SCREEN_PT) == LCD_SCREEN_PT_010)*/
+
+#define panel_is_color(panel) ((panel->mode_screen & LCD_SCREEN_PT) <= LCD_SCREEN_PT_CDSTN)
+
+/* Bitfields format supported by the controller. */
+static struct fb_bitfield rgb_bitfields[][4] = {
+  	/*     Red, 	   Green, 	 Blue, 	     Transp   */
+	[LCD_WINCTRL1_FRM_16BPP655 >> 25] =
+		{ { 10, 6, 0 }, { 5, 5, 0 }, { 0, 5, 0 }, { 0, 0, 0 } },
+
+	[LCD_WINCTRL1_FRM_16BPP565 >> 25] =
+		{ { 11, 5, 0 }, { 5, 6, 0 }, { 0, 5, 0 }, { 0, 0, 0 } },
+
+	[LCD_WINCTRL1_FRM_16BPP556 >> 25] =
+		{ { 11, 5, 0 }, { 6, 5, 0 }, { 0, 6, 0 }, { 0, 0, 0 } },
+
+	[LCD_WINCTRL1_FRM_16BPPI1555 >> 25] =
+		{ { 10, 5, 0 }, { 5, 5, 0 }, { 0, 5, 0 }, { 0, 0, 0 } },
+
+	[LCD_WINCTRL1_FRM_16BPPI5551 >> 25] =
+		{ { 11, 5, 0 }, { 6, 5, 0 }, { 1, 5, 0 }, { 0, 0, 0 } },
+
+	[LCD_WINCTRL1_FRM_16BPPA1555 >> 25] =
+		{ { 10, 5, 0 }, { 5, 5, 0 }, { 0, 5, 0 }, { 15, 1, 0 } },
+
+	[LCD_WINCTRL1_FRM_16BPPA5551 >> 25] =
+		{ { 11, 5, 0 }, { 6, 5, 0 }, { 1, 5, 0 }, { 0, 1, 0 } },
+
+	[LCD_WINCTRL1_FRM_24BPP >> 25] =
+		{ { 16, 8, 0 }, { 8, 8, 0 }, { 0, 8, 0 }, { 0, 0, 0 } },
+
+	[LCD_WINCTRL1_FRM_32BPP >> 25] =
+		{ { 16, 8, 0 }, { 8, 8, 0 }, { 0, 8, 0 }, { 24, 0, 0 } },
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* Helpers */
+
+static void au1200fb_update_fbinfo(struct fb_info *fbi)
+{
+	/* FIX!!!! This also needs to take the window pixel format into account!!! */
+
+	/* Update var-dependent FB info */
+	if (panel_is_color(panel)) {
+		if (fbi->var.bits_per_pixel <= 8) {
+			/* palettized */
+			fbi->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+			fbi->fix.line_length = fbi->var.xres_virtual /
+				(8/fbi->var.bits_per_pixel);
+		} else {
+			/* non-palettized */
+			fbi->fix.visual = FB_VISUAL_TRUECOLOR;
+			fbi->fix.line_length = fbi->var.xres_virtual * (fbi->var.bits_per_pixel / 8);
+		}
+	} else {
+		/* mono FIX!!! mono 8 and 4 bits */
+		fbi->fix.visual = FB_VISUAL_MONO10;
+		fbi->fix.line_length = fbi->var.xres_virtual / 8;
+	}
+
+	fbi->screen_size = fbi->fix.line_length * fbi->var.yres_virtual;
+	print_dbg("line length: %d\n", fbi->fix.line_length);
+	print_dbg("bits_per_pixel: %d\n", fbi->var.bits_per_pixel);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* AU1200 framebuffer driver */
+
+/* fb_check_var
+ * Validate var settings with hardware restrictions and modify it if necessary
+ */
+static int au1200fb_fb_check_var(struct fb_var_screeninfo *var,
+	struct fb_info *fbi)
+{
+	struct au1200fb_device *fbdev = (struct au1200fb_device *)fbi;
+	u32 pixclock;
+	int screen_size, plane;
+
+	plane = fbdev->plane;
+
+	/* Make sure that the mode respect all LCD controller and
+	 * panel restrictions. */
+	var->xres = win->w[plane].xres;
+	var->yres = win->w[plane].yres;
+
+	/* No need for virtual resolution support */
+	var->xres_virtual = var->xres;
+	var->yres_virtual = var->yres;
+
+	var->bits_per_pixel = winbpp(win->w[plane].mode_winctrl1);
+
+	screen_size = var->xres_virtual * var->yres_virtual;
+	if (var->bits_per_pixel > 8) screen_size *= (var->bits_per_pixel / 8);
+	else screen_size /= (8/var->bits_per_pixel);
+
+	if (fbdev->fb_len < screen_size)
+		return -EINVAL; /* Virtual screen is to big, abort */
+
+	/* FIX!!!! what are the implicaitons of ignoring this for windows ??? */
+	/* The max LCD clock is fixed to 48MHz (value of AUX_CLK). The pixel
+	 * clock can only be obtain by dividing this value by an even integer.
+	 * Fallback to a slower pixel clock if necessary. */
+	pixclock = max((u32)(PICOS2KHZ(var->pixclock) * 1000), fbi->monspecs.dclkmin);
+	pixclock = min(pixclock, min(fbi->monspecs.dclkmax, (u32)AU1200_LCD_MAX_CLK/2));
+
+	if (AU1200_LCD_MAX_CLK % pixclock) {
+		int diff = AU1200_LCD_MAX_CLK % pixclock;
+		pixclock -= diff;
+	}
+
+	var->pixclock = KHZ2PICOS(pixclock/1000);
+#if 0
+	if (!panel_is_active(panel)) {
+		int pcd = AU1200_LCD_MAX_CLK / (pixclock * 2) - 1;
+
+		if (!panel_is_color(panel)
+			&& (panel->control_base & LCD_CONTROL_MPI) && (pcd < 3)) {
+			/* STN 8bit mono panel support is up to 6MHz pixclock */
+			var->pixclock = KHZ2PICOS(6000);
+		} else if (!pcd) {
+			/* Other STN panel support is up to 12MHz  */
+			var->pixclock = KHZ2PICOS(12000);
+		}
+	}
+#endif
+	/* Set bitfield accordingly */
+	switch (var->bits_per_pixel) {
+		case 16:
+		{
+			/* 16bpp True color.
+			 * These must be set to MATCH WINCTRL[FORM] */
+			int idx;
+			idx = (win->w[0].mode_winctrl1 & LCD_WINCTRL1_FRM) >> 25;
+			var->red    = rgb_bitfields[idx][0];
+			var->green  = rgb_bitfields[idx][1];
+			var->blue   = rgb_bitfields[idx][2];
+			var->transp = rgb_bitfields[idx][3];
+			break;
+		}
+
+		case 32:
+		{
+			/* 32bpp True color.
+			 * These must be set to MATCH WINCTRL[FORM] */
+			int idx;
+			idx = (win->w[0].mode_winctrl1 & LCD_WINCTRL1_FRM) >> 25;
+			var->red    = rgb_bitfields[idx][0];
+			var->green  = rgb_bitfields[idx][1];
+			var->blue   = rgb_bitfields[idx][2];
+			var->transp = rgb_bitfields[idx][3];
+			break;
+		}
+		default:
+			print_dbg("Unsupported depth %dbpp", var->bits_per_pixel);
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* fb_set_par
+ * Set hardware with var settings. This will enable the controller with a
+ * specific mode, normally validated with the fb_check_var method
+ */
+static int au1200fb_fb_set_par(struct fb_info *fbi)
+{
+	struct au1200fb_device *fbdev = (struct au1200fb_device *)fbi;
+
+	au1200fb_update_fbinfo(fbi);
+	au1200_setmode(fbdev);
+
+	return 0;
+}
+
+/* fb_setcolreg
+ * Set color in LCD palette.
+ */
+static int au1200fb_fb_setcolreg(unsigned regno, unsigned red, unsigned green,
+	unsigned blue, unsigned transp, struct fb_info *fbi)
+{
+	volatile u32 *palette = lcd->palette;
+	u32 value;
+
+	if (regno > (AU1200_LCD_NBR_PALETTE_ENTRIES - 1))
+		return -EINVAL;
+
+	if (fbi->var.grayscale) {
+		/* Convert color to grayscale */
+		red = green = blue =
+			(19595 * red + 38470 * green + 7471 * blue) >> 16;
+	}
+
+	if (fbi->fix.visual == FB_VISUAL_TRUECOLOR) {
+		/* Place color in the pseudopalette */
+		if (regno > 16)
+			return -EINVAL;
+
+		palette = (u32*) fbi->pseudo_palette;
+
+		red   >>= (16 - fbi->var.red.length);
+		green >>= (16 - fbi->var.green.length);
+		blue  >>= (16 - fbi->var.blue.length);
+
+		value = (red   << fbi->var.red.offset) 	|
+			(green << fbi->var.green.offset)|
+			(blue  << fbi->var.blue.offset);
+		value &= 0xFFFF;
+
+	} else if (1 /*FIX!!! panel_is_active(fbdev->panel)*/) {
+		/* COLOR TFT PALLETTIZED (use RGB 565) */
+		value = (red & 0xF800)|((green >> 5) &
+				0x07E0)|((blue >> 11) & 0x001F);
+		value &= 0xFFFF;
+
+	} else if (0 /*panel_is_color(fbdev->panel)*/) {
+		/* COLOR STN MODE */
+		value = 0x1234;
+		value &= 0xFFF;
+	} else {
+		/* MONOCHROME MODE */
+		value = (green >> 12) & 0x000F;
+		value &= 0xF;
+	}
+
+	palette[regno] = value;
+
+	return 0;
+}
+
+/* fb_blank
+ * Blank the screen. Depending on the mode, the screen will be
+ * activated with the backlight color, or desactivated
+ */
+static int au1200fb_fb_blank(int blank_mode, struct fb_info *fbi)
+{
+	/* Short-circuit screen blanking */
+	if (noblanking)
+		return 0;
+
+	switch (blank_mode) {
+
+	case FB_BLANK_UNBLANK:
+	case FB_BLANK_NORMAL:
+		/* printk("turn on panel\n"); */
+		au1200_setpanel(panel);
+		break;
+	case FB_BLANK_VSYNC_SUSPEND:
+	case FB_BLANK_HSYNC_SUSPEND:
+	case FB_BLANK_POWERDOWN:
+		/* printk("turn off panel\n"); */
+		au1200_setpanel(NULL);
+		break;
+	default:
+		break;
+
+	}
+
+	/* FB_BLANK_NORMAL is a soft blank */
+	return (blank_mode == FB_BLANK_NORMAL) ? -EINVAL : 0;
+}
+
+/* fb_mmap
+ * Map video memory in user space. We don't use the generic fb_mmap
+ * method mainly to allow the use of the TLB streaming flag (CCA=6)
+ */
+static int au1200fb_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+
+{
+	unsigned int len;
+	unsigned long start=0, off;
+	struct au1200fb_device *fbdev = (struct au1200fb_device *) info;
+
+#ifdef CONFIG_PM
+	au1xxx_pm_access(LCD_pm_dev);
+#endif
+
+	if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) {
+		return -EINVAL;
+	}
+
+	start = fbdev->fb_phys & PAGE_MASK;
+	len = PAGE_ALIGN((start & ~PAGE_MASK) + fbdev->fb_len);
+
+	off = vma->vm_pgoff << PAGE_SHIFT;
+
+	if ((vma->vm_end - vma->vm_start + off) > len) {
+		return -EINVAL;
+	}
+
+	off += start;
+	vma->vm_pgoff = off >> PAGE_SHIFT;
+
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+	pgprot_val(vma->vm_page_prot) |= _CACHE_MASK; /* CCA=7 */
+
+	vma->vm_flags |= VM_IO;
+
+	return io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
+				  vma->vm_end - vma->vm_start,
+				  vma->vm_page_prot);
+
+	return 0;
+}
+
+static void set_global(u_int cmd, struct au1200_lcd_global_regs_t *pdata)
+{
+
+	unsigned int hi1, divider;
+
+	/* SCREEN_SIZE: user cannot reset size, must switch panel choice */
+
+	if (pdata->flags & SCREEN_BACKCOLOR)
+		lcd->backcolor = pdata->backcolor;
+
+	if (pdata->flags & SCREEN_BRIGHTNESS) {
+
+		// limit brightness pwm duty to >= 30/1600
+		if (pdata->brightness < 30) {
+			pdata->brightness = 30;
+		}
+		divider = (lcd->pwmdiv & 0x3FFFF) + 1;
+		hi1 = (lcd->pwmhi >> 16) + 1;
+		hi1 = (((pdata->brightness & 0xFF)+1) * divider >> 8);
+		lcd->pwmhi &= 0xFFFF;
+		lcd->pwmhi |= (hi1 << 16);
+	}
+
+	if (pdata->flags & SCREEN_COLORKEY)
+		lcd->colorkey = pdata->colorkey;
+
+	if (pdata->flags & SCREEN_MASK)
+		lcd->colorkeymsk = pdata->mask;
+	au_sync();
+}
+
+static void get_global(u_int cmd, struct au1200_lcd_global_regs_t *pdata)
+{
+	unsigned int hi1, divider;
+
+	pdata->xsize = ((lcd->screen & LCD_SCREEN_SX) >> 19) + 1;
+	pdata->ysize = ((lcd->screen & LCD_SCREEN_SY) >> 8) + 1;
+
+	pdata->backcolor = lcd->backcolor;
+	pdata->colorkey = lcd->colorkey;
+	pdata->mask = lcd->colorkeymsk;
+
+	// brightness
+	hi1 = (lcd->pwmhi >> 16) + 1;
+	divider = (lcd->pwmdiv & 0x3FFFF) + 1;
+	pdata->brightness = ((hi1 << 8) / divider) - 1;
+	au_sync();
+}
+
+static void set_window(unsigned int plane,
+	struct au1200_lcd_window_regs_t *pdata)
+{
+	unsigned int val, bpp;
+
+	/* Window control register 0 */
+	if (pdata->flags & WIN_POSITION) {
+		val = lcd->window[plane].winctrl0 & ~(LCD_WINCTRL0_OX |
+				LCD_WINCTRL0_OY);
+		val |= ((pdata->xpos << 21) & LCD_WINCTRL0_OX);
+		val |= ((pdata->ypos << 10) & LCD_WINCTRL0_OY);
+		lcd->window[plane].winctrl0 = val;
+	}
+	if (pdata->flags & WIN_ALPHA_COLOR) {
+		val = lcd->window[plane].winctrl0 & ~(LCD_WINCTRL0_A);
+		val |= ((pdata->alpha_color << 2) & LCD_WINCTRL0_A);
+		lcd->window[plane].winctrl0 = val;
+	}
+	if (pdata->flags & WIN_ALPHA_MODE) {
+		val = lcd->window[plane].winctrl0 & ~(LCD_WINCTRL0_AEN);
+		val |= ((pdata->alpha_mode << 1) & LCD_WINCTRL0_AEN);
+		lcd->window[plane].winctrl0 = val;
+	}
+
+	/* Window control register 1 */
+	if (pdata->flags & WIN_PRIORITY) {
+		val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_PRI);
+		val |= ((pdata->priority << 30) & LCD_WINCTRL1_PRI);
+		lcd->window[plane].winctrl1 = val;
+	}
+	if (pdata->flags & WIN_CHANNEL) {
+		val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_PIPE);
+		val |= ((pdata->channel << 29) & LCD_WINCTRL1_PIPE);
+		lcd->window[plane].winctrl1 = val;
+	}
+	if (pdata->flags & WIN_BUFFER_FORMAT) {
+		val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_FRM);
+		val |= ((pdata->buffer_format << 25) & LCD_WINCTRL1_FRM);
+		lcd->window[plane].winctrl1 = val;
+	}
+	if (pdata->flags & WIN_COLOR_ORDER) {
+		val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_CCO);
+		val |= ((pdata->color_order << 24) & LCD_WINCTRL1_CCO);
+		lcd->window[plane].winctrl1 = val;
+	}
+	if (pdata->flags & WIN_PIXEL_ORDER) {
+		val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_PO);
+		val |= ((pdata->pixel_order << 22) & LCD_WINCTRL1_PO);
+		lcd->window[plane].winctrl1 = val;
+	}
+	if (pdata->flags & WIN_SIZE) {
+		val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_SZX |
+				LCD_WINCTRL1_SZY);
+		val |= (((pdata->xsize << 11) - 1) & LCD_WINCTRL1_SZX);
+		val |= (((pdata->ysize) - 1) & LCD_WINCTRL1_SZY);
+		lcd->window[plane].winctrl1 = val;
+		/* program buffer line width */
+		bpp = winbpp(val) / 8;
+		val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_BX);
+		val |= (((pdata->xsize * bpp) << 8) & LCD_WINCTRL2_BX);
+		lcd->window[plane].winctrl2 = val;
+	}
+
+	/* Window control register 2 */
+	if (pdata->flags & WIN_COLORKEY_MODE) {
+		val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_CKMODE);
+		val |= ((pdata->colorkey_mode << 24) & LCD_WINCTRL2_CKMODE);
+		lcd->window[plane].winctrl2 = val;
+	}
+	if (pdata->flags & WIN_DOUBLE_BUFFER_MODE) {
+		val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_DBM);
+		val |= ((pdata->double_buffer_mode << 23) & LCD_WINCTRL2_DBM);
+		lcd->window[plane].winctrl2 = val;
+	}
+	if (pdata->flags & WIN_RAM_ARRAY_MODE) {
+		val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_RAM);
+		val |= ((pdata->ram_array_mode << 21) & LCD_WINCTRL2_RAM);
+		lcd->window[plane].winctrl2 = val;
+	}
+
+	/* Buffer line width programmed with WIN_SIZE */
+
+	if (pdata->flags & WIN_BUFFER_SCALE) {
+		val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_SCX |
+				LCD_WINCTRL2_SCY);
+		val |= ((pdata->xsize << 11) & LCD_WINCTRL2_SCX);
+		val |= ((pdata->ysize) & LCD_WINCTRL2_SCY);
+		lcd->window[plane].winctrl2 = val;
+	}
+
+	if (pdata->flags & WIN_ENABLE) {
+		val = lcd->winenable;
+		val &= ~(1<<plane);
+		val |= (pdata->enable & 1) << plane;
+		lcd->winenable = val;
+	}
+	au_sync();
+}
+
+static void get_window(unsigned int plane,
+	struct au1200_lcd_window_regs_t *pdata)
+{
+	/* Window control register 0 */
+	pdata->xpos = (lcd->window[plane].winctrl0 & LCD_WINCTRL0_OX) >> 21;
+	pdata->ypos = (lcd->window[plane].winctrl0 & LCD_WINCTRL0_OY) >> 10;
+	pdata->alpha_color = (lcd->window[plane].winctrl0 & LCD_WINCTRL0_A) >> 2;
+	pdata->alpha_mode = (lcd->window[plane].winctrl0 & LCD_WINCTRL0_AEN) >> 1;
+
+	/* Window control register 1 */
+	pdata->priority = (lcd->window[plane].winctrl1& LCD_WINCTRL1_PRI) >> 30;
+	pdata->channel = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_PIPE) >> 29;
+	pdata->buffer_format = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_FRM) >> 25;
+	pdata->color_order = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_CCO) >> 24;
+	pdata->pixel_order = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_PO) >> 22;
+	pdata->xsize = ((lcd->window[plane].winctrl1 & LCD_WINCTRL1_SZX) >> 11) + 1;
+	pdata->ysize = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_SZY) + 1;
+
+	/* Window control register 2 */
+	pdata->colorkey_mode = (lcd->window[plane].winctrl2 & LCD_WINCTRL2_CKMODE) >> 24;
+	pdata->double_buffer_mode = (lcd->window[plane].winctrl2 & LCD_WINCTRL2_DBM) >> 23;
+	pdata->ram_array_mode = (lcd->window[plane].winctrl2 & LCD_WINCTRL2_RAM) >> 21;
+
+	pdata->enable = (lcd->winenable >> plane) & 1;
+	au_sync();
+}
+
+static int au1200fb_ioctl(struct fb_info *info, unsigned int cmd,
+                          unsigned long arg)
+{
+	int plane;
+	int val;
+
+#ifdef CONFIG_PM
+	au1xxx_pm_access(LCD_pm_dev);
+#endif
+
+	plane = fbinfo2index(info);
+	print_dbg("au1200fb: ioctl %d on plane %d\n", cmd, plane);
+
+	if (cmd == AU1200_LCD_FB_IOCTL) {
+		struct au1200_lcd_iodata_t iodata;
+
+		if (copy_from_user(&iodata, (void __user *) arg, sizeof(iodata)))
+			return -EFAULT;
+
+		print_dbg("FB IOCTL called\n");
+
+		switch (iodata.subcmd) {
+		case AU1200_LCD_SET_SCREEN:
+			print_dbg("AU1200_LCD_SET_SCREEN\n");
+			set_global(cmd, &iodata.global);
+			break;
+
+		case AU1200_LCD_GET_SCREEN:
+			print_dbg("AU1200_LCD_GET_SCREEN\n");
+			get_global(cmd, &iodata.global);
+			break;
+
+		case AU1200_LCD_SET_WINDOW:
+			print_dbg("AU1200_LCD_SET_WINDOW\n");
+			set_window(plane, &iodata.window);
+			break;
+
+		case AU1200_LCD_GET_WINDOW:
+			print_dbg("AU1200_LCD_GET_WINDOW\n");
+			get_window(plane, &iodata.window);
+			break;
+
+		case AU1200_LCD_SET_PANEL:
+			print_dbg("AU1200_LCD_SET_PANEL\n");
+			if ((iodata.global.panel_choice >= 0) &&
+					(iodata.global.panel_choice <
+					 NUM_PANELS))
+			{
+				struct panel_settings *newpanel;
+				panel_index = iodata.global.panel_choice;
+				newpanel = &known_lcd_panels[panel_index];
+				au1200_setpanel(newpanel);
+			}
+			break;
+
+		case AU1200_LCD_GET_PANEL:
+			print_dbg("AU1200_LCD_GET_PANEL\n");
+			iodata.global.panel_choice = panel_index;
+			break;
+
+		default:
+			return -EINVAL;
+		}
+
+		val = copy_to_user((void __user *) arg, &iodata, sizeof(iodata));
+		if (val) {
+			print_dbg("error: could not copy %d bytes\n", val);
+			return -EFAULT;
+		}
+	}
+
+	return 0;
+}
+
+
+static struct fb_ops au1200fb_fb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_check_var	= au1200fb_fb_check_var,
+	.fb_set_par	= au1200fb_fb_set_par,
+	.fb_setcolreg	= au1200fb_fb_setcolreg,
+	.fb_blank	= au1200fb_fb_blank,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_sync	= NULL,
+	.fb_ioctl	= au1200fb_ioctl,
+	.fb_mmap	= au1200fb_fb_mmap,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static irqreturn_t au1200fb_handle_irq(int irq, void* dev_id, struct pt_regs *regs)
+{
+	/* Nothing to do for now, just clear any pending interrupt */
+	lcd->intstatus = lcd->intstatus;
+	au_sync();
+
+	return IRQ_HANDLED;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* AU1200 LCD device probe helpers */
+
+static int au1200fb_init_fbinfo(struct au1200fb_device *fbdev)
+{
+	struct fb_info *fbi = &fbdev->fb_info;
+	int bpp;
+
+	memset(fbi, 0, sizeof(struct fb_info));
+	fbi->fbops = &au1200fb_fb_ops;
+
+	bpp = winbpp(win->w[fbdev->plane].mode_winctrl1);
+
+	/* Copy monitor specs from panel data */
+	/* fixme: we're setting up LCD controller windows, so these dont give a
+	damn as to what the monitor specs are (the panel itself does, but that
+	isnt done here...so maybe need a generic catchall monitor setting??? */
+	memcpy(&fbi->monspecs, &panel->monspecs, sizeof(struct fb_monspecs));
+
+	/* We first try the user mode passed in argument. If that failed,
+	 * or if no one has been specified, we default to the first mode of the
+	 * panel list. Note that after this call, var data will be set */
+	if (!fb_find_mode(&fbi->var,
+			  fbi,
+			  NULL, /* drv_info.opt_mode, */
+			  fbi->monspecs.modedb,
+			  fbi->monspecs.modedb_len,
+			  fbi->monspecs.modedb,
+			  bpp)) {
+
+		print_err("Cannot find valid mode for panel %s", panel->name);
+		return -EFAULT;
+	}
+
+	fbi->pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL);
+	if (!fbi->pseudo_palette) {
+		return -ENOMEM;
+	}
+	memset(fbi->pseudo_palette, 0, sizeof(u32) * 16);
+
+	if (fb_alloc_cmap(&fbi->cmap, AU1200_LCD_NBR_PALETTE_ENTRIES, 0) < 0) {
+		print_err("Fail to allocate colormap (%d entries)",
+			   AU1200_LCD_NBR_PALETTE_ENTRIES);
+		kfree(fbi->pseudo_palette);
+		return -EFAULT;
+	}
+
+	strncpy(fbi->fix.id, "AU1200", sizeof(fbi->fix.id));
+	fbi->fix.smem_start = fbdev->fb_phys;
+	fbi->fix.smem_len = fbdev->fb_len;
+	fbi->fix.type = FB_TYPE_PACKED_PIXELS;
+	fbi->fix.xpanstep = 0;
+	fbi->fix.ypanstep = 0;
+	fbi->fix.mmio_start = 0;
+	fbi->fix.mmio_len = 0;
+	fbi->fix.accel = FB_ACCEL_NONE;
+
+	fbi->screen_base = (char __iomem *) fbdev->fb_mem;
+
+	au1200fb_update_fbinfo(fbi);
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* AU1200 LCD controller device driver */
+
+static int au1200fb_drv_probe(struct device *dev)
+{
+	struct au1200fb_device *fbdev;
+	unsigned long page;
+	int bpp, plane, ret;
+
+	if (!dev)
+		return -EINVAL;
+
+	for (plane = 0; plane < CONFIG_FB_AU1200_DEVS; ++plane) {
+		bpp = winbpp(win->w[plane].mode_winctrl1);
+		if (win->w[plane].xres == 0)
+			win->w[plane].xres = panel->Xres;
+		if (win->w[plane].yres == 0)
+			win->w[plane].yres = panel->Yres;
+
+		fbdev = &_au1200fb_devices[plane];
+		memset(fbdev, 0, sizeof(struct au1200fb_device));
+		fbdev->plane = plane;
+
+		/* Allocate the framebuffer to the maximum screen size */
+		fbdev->fb_len = (win->w[plane].xres * win->w[plane].yres * bpp) / 8;
+
+		fbdev->fb_mem = dma_alloc_noncoherent(dev,
+				PAGE_ALIGN(fbdev->fb_len),
+				&fbdev->fb_phys, GFP_KERNEL);
+		if (!fbdev->fb_mem) {
+			print_err("fail to allocate frambuffer (size: %dK))",
+				  fbdev->fb_len / 1024);
+			return -ENOMEM;
+		}
+
+		/*
+		 * Set page reserved so that mmap will work. This is necessary
+		 * since we'll be remapping normal memory.
+		 */
+		for (page = (unsigned long)fbdev->fb_phys;
+		     page < PAGE_ALIGN((unsigned long)fbdev->fb_phys +
+			     fbdev->fb_len);
+		     page += PAGE_SIZE) {
+			SetPageReserved(pfn_to_page(page >> PAGE_SHIFT)); /* LCD DMA is NOT coherent on Au1200 */
+		}
+		print_dbg("Framebuffer memory map at %p", fbdev->fb_mem);
+		print_dbg("phys=0x%08x, size=%dK", fbdev->fb_phys, fbdev->fb_len / 1024);
+
+		/* Init FB data */
+		if ((ret = au1200fb_init_fbinfo(fbdev)) < 0)
+			goto failed;
+
+		/* Register new framebuffer */
+		if ((ret = register_framebuffer(&fbdev->fb_info)) < 0) {
+			print_err("cannot register new framebuffer");
+			goto failed;
+		}
+
+		au1200fb_fb_set_par(&fbdev->fb_info);
+
+#if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO)
+		if (plane == 0)
+			if (fb_prepare_logo(&fbdev->fb_info, FB_ROTATE_UR)) {
+				/* Start display and show logo on boot */
+				fb_set_cmap(&fbdev->fb_info.cmap,
+						&fbdev->fb_info);
+
+				fb_show_logo(&fbdev->fb_info, FB_ROTATE_UR);
+			}
+#endif
+	}
+
+	/* Now hook interrupt too */
+	if ((ret = request_irq(AU1200_LCD_INT, au1200fb_handle_irq,
+		 	  SA_INTERRUPT | SA_SHIRQ, "lcd", (void *)dev)) < 0) {
+		print_err("fail to request interrupt line %d (err: %d)",
+			  AU1200_LCD_INT, ret);
+		goto failed;
+	}
+
+	return 0;
+
+failed:
+	/* NOTE: This only does the current plane/window that failed; others are still active */
+	if (fbdev->fb_mem)
+		dma_free_noncoherent(dev, PAGE_ALIGN(fbdev->fb_len),
+				fbdev->fb_mem, fbdev->fb_phys);
+	if (fbdev->fb_info.cmap.len != 0)
+		fb_dealloc_cmap(&fbdev->fb_info.cmap);
+	if (fbdev->fb_info.pseudo_palette)
+		kfree(fbdev->fb_info.pseudo_palette);
+	if (plane == 0)
+		free_irq(AU1200_LCD_INT, (void*)dev);
+	return ret;
+}
+
+static int au1200fb_drv_remove(struct device *dev)
+{
+	struct au1200fb_device *fbdev;
+	int plane;
+
+	if (!dev)
+		return -ENODEV;
+
+	/* Turn off the panel */
+	au1200_setpanel(NULL);
+
+	for (plane = 0; plane < CONFIG_FB_AU1200_DEVS; ++plane)
+	{
+		fbdev = &_au1200fb_devices[plane];
+
+		/* Clean up all probe data */
+		unregister_framebuffer(&fbdev->fb_info);
+		if (fbdev->fb_mem)
+			dma_free_noncoherent(dev, PAGE_ALIGN(fbdev->fb_len),
+					fbdev->fb_mem, fbdev->fb_phys);
+		if (fbdev->fb_info.cmap.len != 0)
+			fb_dealloc_cmap(&fbdev->fb_info.cmap);
+		if (fbdev->fb_info.pseudo_palette)
+			kfree(fbdev->fb_info.pseudo_palette);
+	}
+
+	free_irq(AU1200_LCD_INT, (void *)dev);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int au1200fb_drv_suspend(struct device *dev, u32 state, u32 level)
+{
+	/* TODO */
+	return 0;
+}
+
+static int au1200fb_drv_resume(struct device *dev, u32 level)
+{
+	/* TODO */
+	return 0;
+}
+#endif /* CONFIG_PM */
+
+static struct device_driver au1200fb_driver = {
+	.name		= "au1200-lcd",
+	.bus		= &platform_bus_type,
+	.probe		= au1200fb_drv_probe,
+	.remove		= au1200fb_drv_remove,
+#ifdef CONFIG_PM
+	.suspend	= au1200fb_drv_suspend,
+	.resume		= au1200fb_drv_resume,
+#endif
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* Kernel driver */
+
+static void au1200fb_setup(void)
+{
+	char* options = NULL;
+	char* this_opt;
+	int num_panels = ARRAY_SIZE(known_lcd_panels);
+	int panel_idx = -1;
+
+	fb_get_options(DRIVER_NAME, &options);
+
+	if (options) {
+		while ((this_opt = strsep(&options,",")) != NULL) {
+			/* Panel option - can be panel name,
+			 * "bs" for board-switch, or number/index */
+			if (!strncmp(this_opt, "panel:", 6)) {
+				int i;
+				long int li;
+				char *endptr;
+				this_opt += 6;
+				/* First check for index, which allows
+				 * to short circuit this mess */
+				li = simple_strtol(this_opt, &endptr, 0);
+				if (*endptr == '\0') {
+					panel_idx = (int)li;
+				}
+				else if (strcmp(this_opt, "bs") == 0) {
+					extern int board_au1200fb_panel(void);
+					panel_idx = board_au1200fb_panel();
+				}
+
+				else
+				for (i = 0; i < num_panels; i++) {
+					if (!strcmp(this_opt, known_lcd_panels[i].name)) {
+						panel_idx = i;
+						break;
+					}
+				}
+
+				if ((panel_idx < 0) || (panel_idx >= num_panels)) {
+						print_warn("Panel %s not supported!", this_opt);
+				}
+				else
+					panel_index = panel_idx;
+			}
+
+			else if (strncmp(this_opt, "nohwcursor", 10) == 0) {
+				nohwcursor = 1;
+			}
+
+			/* Unsupported option */
+			else {
+				print_warn("Unsupported option \"%s\"", this_opt);
+			}
+		}
+	}
+}
+
+#ifdef CONFIG_PM
+static int au1200fb_pm_callback(au1xxx_power_dev_t *dev,
+		au1xxx_request_t request, void *data) {
+	int retval = -1;
+	unsigned int d = 0;
+	unsigned int brightness = 0;
+
+	if (request == AU1XXX_PM_SLEEP) {
+		board_au1200fb_panel_shutdown();
+	}
+	else if (request == AU1XXX_PM_WAKEUP) {
+		if(dev->prev_state == SLEEP_STATE)
+		{
+			int plane;
+			au1200_setpanel(panel);
+			for (plane = 0; plane < CONFIG_FB_AU1200_DEVS; ++plane) 	{
+				struct au1200fb_device *fbdev;
+				fbdev = &_au1200fb_devices[plane];
+				au1200fb_fb_set_par(&fbdev->fb_info);
+			}
+		}
+
+		d = *((unsigned int*)data);
+		if(d <=10) brightness = 26;
+		else if(d<=20) brightness = 51;
+		else if(d<=30) brightness = 77;
+		else if(d<=40) brightness = 102;
+		else if(d<=50) brightness = 128;
+		else if(d<=60) brightness = 153;
+		else if(d<=70) brightness = 179;
+		else if(d<=80) brightness = 204;
+		else if(d<=90) brightness = 230;
+		else brightness = 255;
+		set_brightness(brightness);
+	} else if (request == AU1XXX_PM_GETSTATUS) {
+		return dev->cur_state;
+	} else if (request == AU1XXX_PM_ACCESS) {
+		if (dev->cur_state != SLEEP_STATE)
+			return retval;
+		else {
+			au1200_setpanel(panel);
+		}
+	} else if (request == AU1XXX_PM_IDLE) {
+	} else if (request == AU1XXX_PM_CLEANUP) {
+	}
+
+	return retval;
+}
+#endif
+
+static int __init au1200fb_init(void)
+{
+	print_info("" DRIVER_DESC "");
+
+	/* Setup driver with options */
+	au1200fb_setup();
+
+	/* Point to the panel selected */
+	panel = &known_lcd_panels[panel_index];
+	win = &windows[window_index];
+
+	printk(DRIVER_NAME ": Panel %d %s\n", panel_index, panel->name);
+	printk(DRIVER_NAME ": Win %d %s\n", window_index, win->name);
+
+	/* Kickstart the panel, the framebuffers/windows come soon enough */
+	au1200_setpanel(panel);
+
+	#ifdef CONFIG_PM
+	LCD_pm_dev = new_au1xxx_power_device("LCD", &au1200fb_pm_callback, NULL);
+	if ( LCD_pm_dev == NULL)
+		printk(KERN_INFO "Unable to create a power management device entry for the au1200fb.\n");
+	else
+		printk(KERN_INFO "Power management device entry for the au1200fb loaded.\n");
+	#endif
+
+	return driver_register(&au1200fb_driver);
+}
+
+static void __exit au1200fb_cleanup(void)
+{
+	driver_unregister(&au1200fb_driver);
+}
+
+module_init(au1200fb_init);
+module_exit(au1200fb_cleanup);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+/*
+ * BRIEF MODULE DESCRIPTION
+ *	Au1200 LCD Driver.
+ *
+ * Copyright 2004-2005 AMD
+ * Author: AMD
+ *
+ * Based on:
+ * linux/drivers/video/skeletonfb.c -- Skeleton for a frame buffer device
+ *  Created 28 Dec 1997 by Geert Uytterhoeven
+ *
+ *  This program is free software; you can redistribute	 it and/or modify it
+ *  under  the terms of	 the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the	License, or (at your
+ *  option) any later version.
+ *
+ *  THIS  SOFTWARE  IS PROVIDED	  ``AS	IS'' AND   ANY	EXPRESS OR IMPLIED
+ *  WARRANTIES,	  INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO	EVENT  SHALL   THE AUTHOR  BE	 LIABLE FOR ANY	  DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED	  TO, PROCUREMENT OF  SUBSTITUTE GOODS	OR SERVICES; LOSS OF
+ *  USE, DATA,	OR PROFITS; OR	BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN	 CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the  GNU General Public License along
+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ctype.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/mach-au1x00/au1000.h>
+#include "au1200fb.h"
+
+#ifdef CONFIG_PM
+#include <asm/mach-au1x00/au1xxx_pm.h>
+#endif
+
+#ifndef CONFIG_FB_AU1200_DEVS
+#define CONFIG_FB_AU1200_DEVS 4
+#endif
+
+#define DRIVER_NAME "au1200fb"
+#define DRIVER_DESC "LCD controller driver for AU1200 processors"
+
+#define DEBUG 1
+
+#define print_err(f, arg...) printk(KERN_ERR DRIVER_NAME ": " f "\n", ## arg)
+#define print_warn(f, arg...) printk(KERN_WARNING DRIVER_NAME ": " f "\n", ## arg)
+#define print_info(f, arg...) printk(KERN_INFO DRIVER_NAME ": " f "\n", ## arg)
+
+#if DEBUG
+#define print_dbg(f, arg...) printk(KERN_DEBUG __FILE__ ": " f "\n", ## arg)
+#else
+#define print_dbg(f, arg...) do {} while (0)
+#endif
+
+
+#define AU1200_LCD_FB_IOCTL 0x46FF
+
+#define AU1200_LCD_SET_SCREEN 1
+#define AU1200_LCD_GET_SCREEN 2
+#define AU1200_LCD_SET_WINDOW 3
+#define AU1200_LCD_GET_WINDOW 4
+#define AU1200_LCD_SET_PANEL  5
+#define AU1200_LCD_GET_PANEL  6
+
+#define SCREEN_SIZE		    (1<< 1)
+#define SCREEN_BACKCOLOR    (1<< 2)
+#define SCREEN_BRIGHTNESS   (1<< 3)
+#define SCREEN_COLORKEY     (1<< 4)
+#define SCREEN_MASK         (1<< 5)
+
+struct au1200_lcd_global_regs_t {
+	unsigned int flags;
+	unsigned int xsize;
+	unsigned int ysize;
+	unsigned int backcolor;
+	unsigned int brightness;
+	unsigned int colorkey;
+	unsigned int mask;
+	unsigned int panel_choice;
+	char panel_desc[80];
+
+};
+
+#define WIN_POSITION            (1<< 0)
+#define WIN_ALPHA_COLOR         (1<< 1)
+#define WIN_ALPHA_MODE          (1<< 2)
+#define WIN_PRIORITY            (1<< 3)
+#define WIN_CHANNEL             (1<< 4)
+#define WIN_BUFFER_FORMAT       (1<< 5)
+#define WIN_COLOR_ORDER         (1<< 6)
+#define WIN_PIXEL_ORDER         (1<< 7)
+#define WIN_SIZE                (1<< 8)
+#define WIN_COLORKEY_MODE       (1<< 9)
+#define WIN_DOUBLE_BUFFER_MODE  (1<< 10)
+#define WIN_RAM_ARRAY_MODE      (1<< 11)
+#define WIN_BUFFER_SCALE        (1<< 12)
+#define WIN_ENABLE	            (1<< 13)
+
+struct au1200_lcd_window_regs_t {
+	unsigned int flags;
+	unsigned int xpos;
+	unsigned int ypos;
+	unsigned int alpha_color;
+	unsigned int alpha_mode;
+	unsigned int priority;
+	unsigned int channel;
+	unsigned int buffer_format;
+	unsigned int color_order;
+	unsigned int pixel_order;
+	unsigned int xsize;
+	unsigned int ysize;
+	unsigned int colorkey_mode;
+	unsigned int double_buffer_mode;
+	unsigned int ram_array_mode;
+	unsigned int xscale;
+	unsigned int yscale;
+	unsigned int enable;
+};
+
+
+struct au1200_lcd_iodata_t {
+	unsigned int subcmd;
+	struct au1200_lcd_global_regs_t global;
+	struct au1200_lcd_window_regs_t window;
+};
+
+#if defined(__BIG_ENDIAN)
+#define LCD_CONTROL_DEFAULT_PO LCD_CONTROL_PO_11
+#else
+#define LCD_CONTROL_DEFAULT_PO LCD_CONTROL_PO_00
+#endif
+#define LCD_CONTROL_DEFAULT_SBPPF LCD_CONTROL_SBPPF_565
+
+/* Private, per-framebuffer management information (independent of the panel itself) */
+struct au1200fb_device {
+	struct fb_info fb_info;			/* FB driver info record */
+
+	int					plane;
+	unsigned char* 		fb_mem;		/* FrameBuffer memory map */
+	unsigned int		fb_len;
+	dma_addr_t    		fb_phys;
+};
+
+static struct au1200fb_device _au1200fb_devices[CONFIG_FB_AU1200_DEVS];
+/********************************************************************/
+
+/* LCD controller restrictions */
+#define AU1200_LCD_MAX_XRES	1280
+#define AU1200_LCD_MAX_YRES	1024
+#define AU1200_LCD_MAX_BPP	32
+#define AU1200_LCD_MAX_CLK	96000000 /* fixme: this needs to go away ? */
+#define AU1200_LCD_NBR_PALETTE_ENTRIES 256
+
+/* Default number of visible screen buffer to allocate */
+#define AU1200FB_NBR_VIDEO_BUFFERS 1
+
+/********************************************************************/
+
+static struct au1200_lcd *lcd = (struct au1200_lcd *) AU1200_LCD_ADDR;
+static int window_index = 2; /* default is zero */
+static int panel_index = 2; /* default is zero */
+static struct window_settings *win;
+static struct panel_settings *panel;
+static int noblanking = 1;
+static int nohwcursor = 0;
+
+struct window_settings {
+	unsigned char name[64];
+	uint32 mode_backcolor;
+	uint32 mode_colorkey;
+	uint32 mode_colorkeymsk;
+	struct {
+		int xres;
+		int yres;
+		int xpos;
+		int ypos;
+		uint32 mode_winctrl1; /* winctrl1[FRM,CCO,PO,PIPE] */
+		uint32 mode_winenable;
+	} w[4];
+};
+
+#if defined(__BIG_ENDIAN)
+#define LCD_WINCTRL1_PO_16BPP LCD_WINCTRL1_PO_00
+#else
+#define LCD_WINCTRL1_PO_16BPP LCD_WINCTRL1_PO_01
+#endif
+
+extern int board_au1200fb_panel_init (void);
+extern int board_au1200fb_panel_shutdown (void);
+
+#ifdef CONFIG_PM
+int au1200fb_pm_callback(au1xxx_power_dev_t *dev,
+		au1xxx_request_t request, void *data);
+au1xxx_power_dev_t *LCD_pm_dev;
+#endif
+
+/*
+ * Default window configurations
+ */
+static struct window_settings windows[] = {
+	{ /* Index 0 */
+		"0-FS gfx, 1-video, 2-ovly gfx, 3-ovly gfx",
+		/* mode_backcolor	*/ 0x006600ff,
+		/* mode_colorkey,msk*/ 0, 0,
+		{
+			{
+			/* xres, yres, xpos, ypos */ 0, 0, 0, 0,
+			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
+				LCD_WINCTRL1_PO_16BPP,
+			/* mode_winenable*/ LCD_WINENABLE_WEN0,
+			},
+			{
+			/* xres, yres, xpos, ypos */ 100, 100, 100, 100,
+			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
+				LCD_WINCTRL1_PO_16BPP |
+				LCD_WINCTRL1_PIPE,
+			/* mode_winenable*/ LCD_WINENABLE_WEN1,
+			},
+			{
+			/* xres, yres, xpos, ypos */ 0, 0, 0, 0,
+			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
+				LCD_WINCTRL1_PO_16BPP,
+			/* mode_winenable*/ 0,
+			},
+			{
+			/* xres, yres, xpos, ypos */ 0, 0, 0, 0,
+			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
+				LCD_WINCTRL1_PO_16BPP |
+				LCD_WINCTRL1_PIPE,
+			/* mode_winenable*/ 0,
+			},
+		},
+	},
+
+	{ /* Index 1 */
+		"0-FS gfx, 1-video, 2-ovly gfx, 3-ovly gfx",
+		/* mode_backcolor	*/ 0x006600ff,
+		/* mode_colorkey,msk*/ 0, 0,
+		{
+			{
+			/* xres, yres, xpos, ypos */ 320, 240, 5, 5,
+			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_24BPP |
+				LCD_WINCTRL1_PO_00,
+			/* mode_winenable*/ LCD_WINENABLE_WEN0,
+			},
+			{
+			/* xres, yres, xpos, ypos */ 0, 0, 0, 0,
+			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565
+				| LCD_WINCTRL1_PO_16BPP,
+			/* mode_winenable*/ 0,
+			},
+			{
+			/* xres, yres, xpos, ypos */ 100, 100, 0, 0,
+			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
+				LCD_WINCTRL1_PO_16BPP |
+				LCD_WINCTRL1_PIPE,
+			/* mode_winenable*/ 0/*LCD_WINENABLE_WEN2*/,
+			},
+			{
+			/* xres, yres, xpos, ypos */ 200, 25, 0, 0,
+			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
+				LCD_WINCTRL1_PO_16BPP |
+				LCD_WINCTRL1_PIPE,
+			/* mode_winenable*/ 0,
+			},
+		},
+	},
+	{ /* Index 2 */
+		"0-FS gfx, 1-video, 2-ovly gfx, 3-ovly gfx",
+		/* mode_backcolor	*/ 0x006600ff,
+		/* mode_colorkey,msk*/ 0, 0,
+		{
+			{
+			/* xres, yres, xpos, ypos */ 0, 0, 0, 0,
+			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
+				LCD_WINCTRL1_PO_16BPP,
+			/* mode_winenable*/ LCD_WINENABLE_WEN0,
+			},
+			{
+			/* xres, yres, xpos, ypos */ 0, 0, 0, 0,
+			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
+				LCD_WINCTRL1_PO_16BPP,
+			/* mode_winenable*/ 0,
+			},
+			{
+			/* xres, yres, xpos, ypos */ 0, 0, 0, 0,
+			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_32BPP |
+				LCD_WINCTRL1_PO_00|LCD_WINCTRL1_PIPE,
+			/* mode_winenable*/ 0/*LCD_WINENABLE_WEN2*/,
+			},
+			{
+			/* xres, yres, xpos, ypos */ 0, 0, 0, 0,
+			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
+				LCD_WINCTRL1_PO_16BPP |
+				LCD_WINCTRL1_PIPE,
+			/* mode_winenable*/ 0,
+			},
+		},
+	},
+	/* Need VGA 640 @ 24bpp, @ 32bpp */
+	/* Need VGA 800 @ 24bpp, @ 32bpp */
+	/* Need VGA 1024 @ 24bpp, @ 32bpp */
+};
+
+/*
+ * Controller configurations for various panels.
+ */
+
+struct panel_settings
+{
+	const char name[25];		/* Full name <vendor>_<model> */
+
+	struct 	fb_monspecs monspecs; 	/* FB monitor specs */
+
+	/* panel timings */
+	uint32 mode_screen;
+	uint32 mode_horztiming;
+	uint32 mode_verttiming;
+	uint32 mode_clkcontrol;
+	uint32 mode_pwmdiv;
+	uint32 mode_pwmhi;
+	uint32 mode_outmask;
+	uint32 mode_fifoctrl;
+	uint32 mode_toyclksrc;
+	uint32 mode_backlight;
+	uint32 mode_auxpll;
+	int (*device_init)(void);
+	int (*device_shutdown)(void);
+#define Xres min_xres
+#define Yres min_yres
+	u32	min_xres;		/* Minimum horizontal resolution */
+	u32	max_xres;		/* Maximum horizontal resolution */
+	u32 	min_yres;		/* Minimum vertical resolution */
+	u32 	max_yres;		/* Maximum vertical resolution */
+};
+
+/********************************************************************/
+/* fixme: Maybe a modedb for the CRT ? otherwise panels should be as-is */
+
+/* List of panels known to work with the AU1200 LCD controller.
+ * To add a new panel, enter the same specifications as the
+ * Generic_TFT one, and MAKE SURE that it doesn't conflicts
+ * with the controller restrictions. Restrictions are:
+ *
+ * STN color panels: max_bpp <= 12
+ * STN mono panels: max_bpp <= 4
+ * TFT panels: max_bpp <= 16
+ * max_xres <= 800
+ * max_yres <= 600
+ */
+static struct panel_settings known_lcd_panels[] =
+{
+	[0] = { /* QVGA 320x240 H:33.3kHz V:110Hz */
+		.name = "QVGA_320x240",
+		.monspecs = {
+			.modedb = NULL,
+			.modedb_len = 0,
+			.hfmin = 30000,
+			.hfmax = 70000,
+			.vfmin = 60,
+			.vfmax = 60,
+			.dclkmin = 6000000,
+			.dclkmax = 28000000,
+			.input = FB_DISP_RGB,
+		},
+		.mode_screen		= LCD_SCREEN_SX_N(320) |
+			LCD_SCREEN_SY_N(240),
+		.mode_horztiming	= 0x00c4623b,
+		.mode_verttiming	= 0x00502814,
+		.mode_clkcontrol	= 0x00020002, /* /4=24Mhz */
+		.mode_pwmdiv		= 0x00000000,
+		.mode_pwmhi		= 0x00000000,
+		.mode_outmask	= 0x00FFFFFF,
+		.mode_fifoctrl	= 0x2f2f2f2f,
+		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
+		.mode_backlight	= 0x00000000,
+		.mode_auxpll		= 8, /* 96MHz AUXPLL */
+		.device_init		= NULL,
+		.device_shutdown	= NULL,
+		320, 320,
+		240, 240,
+	},
+
+	[1] = { /* VGA 640x480 H:30.3kHz V:58Hz */
+		.name = "VGA_640x480",
+		.monspecs = {
+			.modedb = NULL,
+			.modedb_len = 0,
+			.hfmin = 30000,
+			.hfmax = 70000,
+			.vfmin = 60,
+			.vfmax = 60,
+			.dclkmin = 6000000,
+			.dclkmax = 28000000,
+			.input = FB_DISP_RGB,
+		},
+		.mode_screen		= 0x13f9df80,
+		.mode_horztiming	= 0x003c5859,
+		.mode_verttiming	= 0x00741201,
+		.mode_clkcontrol	= 0x00020001, /* /4=24Mhz */
+		.mode_pwmdiv		= 0x00000000,
+		.mode_pwmhi		= 0x00000000,
+		.mode_outmask	= 0x00FFFFFF,
+		.mode_fifoctrl	= 0x2f2f2f2f,
+		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
+		.mode_backlight	= 0x00000000,
+		.mode_auxpll		= 8, /* 96MHz AUXPLL */
+		.device_init		= NULL,
+		.device_shutdown	= NULL,
+		640, 480,
+		640, 480,
+	},
+
+	[2] = { /* SVGA 800x600 H:46.1kHz V:69Hz */
+		.name = "SVGA_800x600",
+		.monspecs = {
+			.modedb = NULL,
+			.modedb_len = 0,
+			.hfmin = 30000,
+			.hfmax = 70000,
+			.vfmin = 60,
+			.vfmax = 60,
+			.dclkmin = 6000000,
+			.dclkmax = 28000000,
+			.input = FB_DISP_RGB,
+		},
+		.mode_screen		= 0x18fa5780,
+		.mode_horztiming	= 0x00dc7e77,
+		.mode_verttiming	= 0x00584805,
+		.mode_clkcontrol	= 0x00020000, /* /2=48Mhz */
+		.mode_pwmdiv		= 0x00000000,
+		.mode_pwmhi		= 0x00000000,
+		.mode_outmask	= 0x00FFFFFF,
+		.mode_fifoctrl	= 0x2f2f2f2f,
+		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
+		.mode_backlight	= 0x00000000,
+		.mode_auxpll		= 8, /* 96MHz AUXPLL */
+		.device_init		= NULL,
+		.device_shutdown	= NULL,
+		800, 800,
+		600, 600,
+	},
+
+	[3] = { /* XVGA 1024x768 H:56.2kHz V:70Hz */
+		.name = "XVGA_1024x768",
+		.monspecs = {
+			.modedb = NULL,
+			.modedb_len = 0,
+			.hfmin = 30000,
+			.hfmax = 70000,
+			.vfmin = 60,
+			.vfmax = 60,
+			.dclkmin = 6000000,
+			.dclkmax = 28000000,
+			.input = FB_DISP_RGB,
+		},
+		.mode_screen		= 0x1ffaff80,
+		.mode_horztiming	= 0x007d0e57,
+		.mode_verttiming	= 0x00740a01,
+		.mode_clkcontrol	= 0x000A0000, /* /1 */
+		.mode_pwmdiv		= 0x00000000,
+		.mode_pwmhi		= 0x00000000,
+		.mode_outmask	= 0x00FFFFFF,
+		.mode_fifoctrl	= 0x2f2f2f2f,
+		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
+		.mode_backlight	= 0x00000000,
+		.mode_auxpll		= 6, /* 72MHz AUXPLL */
+		.device_init		= NULL,
+		.device_shutdown	= NULL,
+		1024, 1024,
+		768, 768,
+	},
+
+	[4] = { /* XVGA XVGA 1280x1024 H:68.5kHz V:65Hz */
+		.name = "XVGA_1280x1024",
+		.monspecs = {
+			.modedb = NULL,
+			.modedb_len = 0,
+			.hfmin = 30000,
+			.hfmax = 70000,
+			.vfmin = 60,
+			.vfmax = 60,
+			.dclkmin = 6000000,
+			.dclkmax = 28000000,
+			.input = FB_DISP_RGB,
+		},
+		.mode_screen		= 0x27fbff80,
+		.mode_horztiming	= 0x00cdb2c7,
+		.mode_verttiming	= 0x00600002,
+		.mode_clkcontrol	= 0x000A0000, /* /1 */
+		.mode_pwmdiv		= 0x00000000,
+		.mode_pwmhi		= 0x00000000,
+		.mode_outmask	= 0x00FFFFFF,
+		.mode_fifoctrl	= 0x2f2f2f2f,
+		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
+		.mode_backlight	= 0x00000000,
+		.mode_auxpll		= 10, /* 120MHz AUXPLL */
+		.device_init		= NULL,
+		.device_shutdown	= NULL,
+		1280, 1280,
+		1024, 1024,
+	},
+
+	[5] = { /* Samsung 1024x768 TFT */
+		.name = "Samsung_1024x768_TFT",
+		.monspecs = {
+			.modedb = NULL,
+			.modedb_len = 0,
+			.hfmin = 30000,
+			.hfmax = 70000,
+			.vfmin = 60,
+			.vfmax = 60,
+			.dclkmin = 6000000,
+			.dclkmax = 28000000,
+			.input = FB_DISP_RGB,
+		},
+		.mode_screen		= 0x1ffaff80,
+		.mode_horztiming	= 0x018cc677,
+		.mode_verttiming	= 0x00241217,
+		.mode_clkcontrol	= 0x00000000, /* SCB 0x1 /4=24Mhz */
+		.mode_pwmdiv		= 0x8000063f, /* SCB 0x0 */
+		.mode_pwmhi		= 0x03400000, /* SCB 0x0 */
+		.mode_outmask	= 0x00FFFFFF,
+		.mode_fifoctrl	= 0x2f2f2f2f,
+		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
+		.mode_backlight	= 0x00000000,
+		.mode_auxpll		= 8, /* 96MHz AUXPLL */
+		.device_init		= board_au1200fb_panel_init,
+		.device_shutdown	= board_au1200fb_panel_shutdown,
+		1024, 1024,
+		768, 768,
+	},
+
+	[6] = { /* Toshiba 640x480 TFT */
+		.name = "Toshiba_640x480_TFT",
+		.monspecs = {
+			.modedb = NULL,
+			.modedb_len = 0,
+			.hfmin = 30000,
+			.hfmax = 70000,
+			.vfmin = 60,
+			.vfmax = 60,
+			.dclkmin = 6000000,
+			.dclkmax = 28000000,
+			.input = FB_DISP_RGB,
+		},
+		.mode_screen		= LCD_SCREEN_SX_N(640) |
+			LCD_SCREEN_SY_N(480),
+		.mode_horztiming	= LCD_HORZTIMING_HPW_N(96) |
+			LCD_HORZTIMING_HND1_N(13) | LCD_HORZTIMING_HND2_N(51),
+		.mode_verttiming	= LCD_VERTTIMING_VPW_N(2) |
+			LCD_VERTTIMING_VND1_N(11) | LCD_VERTTIMING_VND2_N(32),
+		.mode_clkcontrol	= 0x00000000, /* /4=24Mhz */
+		.mode_pwmdiv		= 0x8000063f,
+		.mode_pwmhi		= 0x03400000,
+		.mode_outmask	= 0x00fcfcfc,
+		.mode_fifoctrl	= 0x2f2f2f2f,
+		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
+		.mode_backlight	= 0x00000000,
+		.mode_auxpll		= 8, /* 96MHz AUXPLL */
+		.device_init		= board_au1200fb_panel_init,
+		.device_shutdown	= board_au1200fb_panel_shutdown,
+		640, 480,
+		640, 480,
+	},
+
+	[7] = { /* Sharp 320x240 TFT */
+		.name = "Sharp_320x240_TFT",
+		.monspecs = {
+			.modedb = NULL,
+			.modedb_len = 0,
+			.hfmin = 12500,
+			.hfmax = 20000,
+			.vfmin = 38,
+			.vfmax = 81,
+			.dclkmin = 4500000,
+			.dclkmax = 6800000,
+			.input = FB_DISP_RGB,
+		},
+		.mode_screen		= LCD_SCREEN_SX_N(320) |
+			LCD_SCREEN_SY_N(240),
+		.mode_horztiming	= LCD_HORZTIMING_HPW_N(60) |
+			LCD_HORZTIMING_HND1_N(13) | LCD_HORZTIMING_HND2_N(2),
+		.mode_verttiming	= LCD_VERTTIMING_VPW_N(2) |
+			LCD_VERTTIMING_VND1_N(2) | LCD_VERTTIMING_VND2_N(5),
+		.mode_clkcontrol	= LCD_CLKCONTROL_PCD_N(7), /*16=6Mhz*/
+		.mode_pwmdiv		= 0x8000063f,
+		.mode_pwmhi		= 0x03400000,
+		.mode_outmask	= 0x00fcfcfc,
+		.mode_fifoctrl	= 0x2f2f2f2f,
+		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
+		.mode_backlight	= 0x00000000,
+		.mode_auxpll		= 8, /* 96MHz AUXPLL */
+		.device_init		= board_au1200fb_panel_init,
+		.device_shutdown	= board_au1200fb_panel_shutdown,
+		320, 320,
+		240, 240,
+	},
+
+	[8] = { /* Toppoly TD070WGCB2 7" 856x480 TFT */
+		.name = "Toppoly_TD070WGCB2",
+		.monspecs = {
+			.modedb = NULL,
+			.modedb_len = 0,
+			.hfmin = 30000,
+			.hfmax = 70000,
+			.vfmin = 60,
+			.vfmax = 60,
+			.dclkmin = 6000000,
+			.dclkmax = 28000000,
+			.input = FB_DISP_RGB,
+		},
+		.mode_screen		= LCD_SCREEN_SX_N(856) |
+			LCD_SCREEN_SY_N(480),
+		.mode_horztiming	= LCD_HORZTIMING_HND2_N(43) |
+			LCD_HORZTIMING_HND1_N(43) | LCD_HORZTIMING_HPW_N(114),
+		.mode_verttiming	= LCD_VERTTIMING_VND2_N(20) |
+			LCD_VERTTIMING_VND1_N(21) | LCD_VERTTIMING_VPW_N(4),
+		.mode_clkcontrol	= 0x00020001, /* /4=24Mhz */
+		.mode_pwmdiv		= 0x8000063f,
+		.mode_pwmhi		= 0x03400000,
+		.mode_outmask	= 0x00fcfcfc,
+		.mode_fifoctrl	= 0x2f2f2f2f,
+		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
+		.mode_backlight	= 0x00000000,
+		.mode_auxpll		= 8, /* 96MHz AUXPLL */
+		.device_init		= board_au1200fb_panel_init,
+		.device_shutdown	= board_au1200fb_panel_shutdown,
+		856, 856,
+		480, 480,
+	},
+};
+
+#define NUM_PANELS (ARRAY_SIZE(known_lcd_panels))
+
+/********************************************************************/
+
+#ifdef CONFIG_PM
+static int set_brightness(unsigned int brightness)
+{
+	unsigned int hi1, divider;
+
+	/* limit brightness pwm duty to >= 30/1600 */
+	if (brightness < 30) {
+		brightness = 30;
+	}
+	divider = (lcd->pwmdiv & 0x3FFFF) + 1;
+	hi1 = (lcd->pwmhi >> 16) + 1;
+	hi1 = (((brightness & 0xFF) + 1) * divider >> 8);
+	lcd->pwmhi &= 0xFFFF;
+	lcd->pwmhi |= (hi1 << 16);
+
+	return brightness;
+}
+#endif /* CONFIG_PM */
+
+static int winbpp (unsigned int winctrl1)
+{
+	int bits = 0;
+
+	/* how many bits are needed for each pixel format */
+	switch (winctrl1 & LCD_WINCTRL1_FRM) {
+	case LCD_WINCTRL1_FRM_1BPP:
+		bits = 1;
+		break;
+	case LCD_WINCTRL1_FRM_2BPP:
+		bits = 2;
+		break;
+	case LCD_WINCTRL1_FRM_4BPP:
+		bits = 4;
+		break;
+	case LCD_WINCTRL1_FRM_8BPP:
+		bits = 8;
+		break;
+	case LCD_WINCTRL1_FRM_12BPP:
+	case LCD_WINCTRL1_FRM_16BPP655:
+	case LCD_WINCTRL1_FRM_16BPP565:
+	case LCD_WINCTRL1_FRM_16BPP556:
+	case LCD_WINCTRL1_FRM_16BPPI1555:
+	case LCD_WINCTRL1_FRM_16BPPI5551:
+	case LCD_WINCTRL1_FRM_16BPPA1555:
+	case LCD_WINCTRL1_FRM_16BPPA5551:
+		bits = 16;
+		break;
+	case LCD_WINCTRL1_FRM_24BPP:
+	case LCD_WINCTRL1_FRM_32BPP:
+		bits = 32;
+		break;
+	}
+
+	return bits;
+}
+
+static int fbinfo2index (struct fb_info *fb_info)
+{
+	int i;
+
+	for (i = 0; i < CONFIG_FB_AU1200_DEVS; ++i) {
+		if (fb_info == (struct fb_info *)(&_au1200fb_devices[i].fb_info))
+			return i;
+	}
+	printk("au1200fb: ERROR: fbinfo2index failed!\n");
+	return -1;
+}
+
+static int au1200_setlocation (struct au1200fb_device *fbdev, int plane,
+	int xpos, int ypos)
+{
+	uint32 winctrl0, winctrl1, winenable, fb_offset = 0;
+	int xsz, ysz;
+
+	/* FIX!!! NOT CHECKING FOR COMPLETE OFFSCREEN YET */
+
+	winctrl0 = lcd->window[plane].winctrl0;
+	winctrl1 = lcd->window[plane].winctrl1;
+	winctrl0 &= (LCD_WINCTRL0_A | LCD_WINCTRL0_AEN);
+	winctrl1 &= ~(LCD_WINCTRL1_SZX | LCD_WINCTRL1_SZY);
+
+	/* Check for off-screen adjustments */
+	xsz = win->w[plane].xres;
+	ysz = win->w[plane].yres;
+	if ((xpos + win->w[plane].xres) > panel->Xres) {
+		/* Off-screen to the right */
+		xsz = panel->Xres - xpos; /* off by 1 ??? */
+		/*printk("off screen right\n");*/
+	}
+
+	if ((ypos + win->w[plane].yres) > panel->Yres) {
+		/* Off-screen to the bottom */
+		ysz = panel->Yres - ypos; /* off by 1 ??? */
+		/*printk("off screen bottom\n");*/
+	}
+
+	if (xpos < 0) {
+		/* Off-screen to the left */
+		xsz = win->w[plane].xres + xpos;
+		fb_offset += (((0 - xpos) * winbpp(lcd->window[plane].winctrl1))/8);
+		xpos = 0;
+		/*printk("off screen left\n");*/
+	}
+
+	if (ypos < 0) {
+		/* Off-screen to the top */
+		ysz = win->w[plane].yres + ypos;
+		/* fixme: fb_offset += ((0-ypos)*fb_pars[plane].line_length); */
+		ypos = 0;
+		/*printk("off screen top\n");*/
+	}
+
+	/* record settings */
+	win->w[plane].xpos = xpos;
+	win->w[plane].ypos = ypos;
+
+	xsz -= 1;
+	ysz -= 1;
+	winctrl0 |= (xpos << 21);
+	winctrl0 |= (ypos << 10);
+	winctrl1 |= (xsz << 11);
+	winctrl1 |= (ysz << 0);
+
+	/* Disable the window while making changes, then restore WINEN */
+	winenable = lcd->winenable & (1 << plane);
+	au_sync();
+	lcd->winenable &= ~(1 << plane);
+	lcd->window[plane].winctrl0 = winctrl0;
+	lcd->window[plane].winctrl1 = winctrl1;
+	lcd->window[plane].winbuf0 =
+	lcd->window[plane].winbuf1 = fbdev->fb_phys;
+	lcd->window[plane].winbufctrl = 0; /* select winbuf0 */
+	lcd->winenable |= winenable;
+	au_sync();
+
+	return 0;
+}
+
+static void au1200_setpanel (struct panel_settings *newpanel)
+{
+	/*
+	 * Perform global setup/init of LCD controller
+	 */
+	uint32 winenable;
+
+	/* Make sure all windows disabled */
+	winenable = lcd->winenable;
+	lcd->winenable = 0;
+	au_sync();
+	/*
+	 * Ensure everything is disabled before reconfiguring
+	 */
+	if (lcd->screen & LCD_SCREEN_SEN) {
+		/* Wait for vertical sync period */
+		lcd->intstatus = LCD_INT_SS;
+		while ((lcd->intstatus & LCD_INT_SS) == 0) {
+			au_sync();
+		}
+
+		lcd->screen &= ~LCD_SCREEN_SEN;	/*disable the controller*/
+
+		do {
+			lcd->intstatus = lcd->intstatus; /*clear interrupts*/
+			au_sync();
+		/*wait for controller to shut down*/
+		} while ((lcd->intstatus & LCD_INT_SD) == 0);
+
+		/* Call shutdown of current panel (if up) */
+		/* this must occur last, because if an external clock is driving
+		    the controller, the clock cannot be turned off before first
+			shutting down the controller.
+		 */
+		if (panel->device_shutdown != NULL)
+			panel->device_shutdown();
+	}
+
+	/* Newpanel == NULL indicates a shutdown operation only */
+	if (newpanel == NULL)
+		return;
+
+	panel = newpanel;
+
+	printk("Panel(%s), %dx%d\n", panel->name, panel->Xres, panel->Yres);
+
+	/*
+	 * Setup clocking if internal LCD clock source (assumes sys_auxpll valid)
+	 */
+	if (!(panel->mode_clkcontrol & LCD_CLKCONTROL_EXT))
+	{
+		uint32 sys_clksrc;
+		au_writel(panel->mode_auxpll, SYS_AUXPLL);
+		sys_clksrc = au_readl(SYS_CLKSRC) & ~0x0000001f;
+		sys_clksrc |= panel->mode_toyclksrc;
+		au_writel(sys_clksrc, SYS_CLKSRC);
+	}
+
+	/*
+	 * Configure panel timings
+	 */
+	lcd->screen = panel->mode_screen;
+	lcd->horztiming = panel->mode_horztiming;
+	lcd->verttiming = panel->mode_verttiming;
+	lcd->clkcontrol = panel->mode_clkcontrol;
+	lcd->pwmdiv = panel->mode_pwmdiv;
+	lcd->pwmhi = panel->mode_pwmhi;
+	lcd->outmask = panel->mode_outmask;
+	lcd->fifoctrl = panel->mode_fifoctrl;
+	au_sync();
+
+	/* fixme: Check window settings to make sure still valid
+	 * for new geometry */
+#if 0
+	au1200_setlocation(fbdev, 0, win->w[0].xpos, win->w[0].ypos);
+	au1200_setlocation(fbdev, 1, win->w[1].xpos, win->w[1].ypos);
+	au1200_setlocation(fbdev, 2, win->w[2].xpos, win->w[2].ypos);
+	au1200_setlocation(fbdev, 3, win->w[3].xpos, win->w[3].ypos);
+#endif
+	lcd->winenable = winenable;
+
+	/*
+	 * Re-enable screen now that it is configured
+	 */
+	lcd->screen |= LCD_SCREEN_SEN;
+	au_sync();
+
+	/* Call init of panel */
+	if (panel->device_init != NULL) panel->device_init();
+
+	/* FIX!!!! not appropriate on panel change!!! Global setup/init */
+	lcd->intenable = 0;
+	lcd->intstatus = ~0;
+	lcd->backcolor = win->mode_backcolor;
+
+	/* Setup Color Key - FIX!!! */
+	lcd->colorkey = win->mode_colorkey;
+	lcd->colorkeymsk = win->mode_colorkeymsk;
+
+	/* Setup HWCursor - FIX!!! Need to support this eventually */
+	lcd->hwc.cursorctrl = 0;
+	lcd->hwc.cursorpos = 0;
+	lcd->hwc.cursorcolor0 = 0;
+	lcd->hwc.cursorcolor1 = 0;
+	lcd->hwc.cursorcolor2 = 0;
+	lcd->hwc.cursorcolor3 = 0;
+
+
+#if 0
+#define D(X) printk("%25s: %08X\n", #X, X)
+	D(lcd->screen);
+	D(lcd->horztiming);
+	D(lcd->verttiming);
+	D(lcd->clkcontrol);
+	D(lcd->pwmdiv);
+	D(lcd->pwmhi);
+	D(lcd->outmask);
+	D(lcd->fifoctrl);
+	D(lcd->window[0].winctrl0);
+	D(lcd->window[0].winctrl1);
+	D(lcd->window[0].winctrl2);
+	D(lcd->window[0].winbuf0);
+	D(lcd->window[0].winbuf1);
+	D(lcd->window[0].winbufctrl);
+	D(lcd->window[1].winctrl0);
+	D(lcd->window[1].winctrl1);
+	D(lcd->window[1].winctrl2);
+	D(lcd->window[1].winbuf0);
+	D(lcd->window[1].winbuf1);
+	D(lcd->window[1].winbufctrl);
+	D(lcd->window[2].winctrl0);
+	D(lcd->window[2].winctrl1);
+	D(lcd->window[2].winctrl2);
+	D(lcd->window[2].winbuf0);
+	D(lcd->window[2].winbuf1);
+	D(lcd->window[2].winbufctrl);
+	D(lcd->window[3].winctrl0);
+	D(lcd->window[3].winctrl1);
+	D(lcd->window[3].winctrl2);
+	D(lcd->window[3].winbuf0);
+	D(lcd->window[3].winbuf1);
+	D(lcd->window[3].winbufctrl);
+	D(lcd->winenable);
+	D(lcd->intenable);
+	D(lcd->intstatus);
+	D(lcd->backcolor);
+	D(lcd->winenable);
+	D(lcd->colorkey);
+    D(lcd->colorkeymsk);
+	D(lcd->hwc.cursorctrl);
+	D(lcd->hwc.cursorpos);
+	D(lcd->hwc.cursorcolor0);
+	D(lcd->hwc.cursorcolor1);
+	D(lcd->hwc.cursorcolor2);
+	D(lcd->hwc.cursorcolor3);
+#endif
+}
+
+static void au1200_setmode(struct au1200fb_device *fbdev)
+{
+	int plane = fbdev->plane;
+	/* Window/plane setup */
+	lcd->window[plane].winctrl1 = ( 0
+		| LCD_WINCTRL1_PRI_N(plane)
+		| win->w[plane].mode_winctrl1 /* FRM,CCO,PO,PIPE */
+		) ;
+
+	au1200_setlocation(fbdev, plane, win->w[plane].xpos, win->w[plane].ypos);
+
+	lcd->window[plane].winctrl2 = ( 0
+		| LCD_WINCTRL2_CKMODE_00
+		| LCD_WINCTRL2_DBM
+		| LCD_WINCTRL2_BX_N( fbdev->fb_info.fix.line_length)
+		| LCD_WINCTRL2_SCX_1
+		| LCD_WINCTRL2_SCY_1
+		) ;
+	lcd->winenable |= win->w[plane].mode_winenable;
+	au_sync();
+}
+
+
+/* Inline helpers */
+
+/*#define panel_is_dual(panel)  ((panel->mode_screen & LCD_SCREEN_PT) == LCD_SCREEN_PT_010)*/
+/*#define panel_is_active(panel)((panel->mode_screen & LCD_SCREEN_PT) == LCD_SCREEN_PT_010)*/
+
+#define panel_is_color(panel) ((panel->mode_screen & LCD_SCREEN_PT) <= LCD_SCREEN_PT_CDSTN)
+
+/* Bitfields format supported by the controller. */
+static struct fb_bitfield rgb_bitfields[][4] = {
+  	/*     Red, 	   Green, 	 Blue, 	     Transp   */
+	[LCD_WINCTRL1_FRM_16BPP655 >> 25] =
+		{ { 10, 6, 0 }, { 5, 5, 0 }, { 0, 5, 0 }, { 0, 0, 0 } },
+
+	[LCD_WINCTRL1_FRM_16BPP565 >> 25] =
+		{ { 11, 5, 0 }, { 5, 6, 0 }, { 0, 5, 0 }, { 0, 0, 0 } },
+
+	[LCD_WINCTRL1_FRM_16BPP556 >> 25] =
+		{ { 11, 5, 0 }, { 6, 5, 0 }, { 0, 6, 0 }, { 0, 0, 0 } },
+
+	[LCD_WINCTRL1_FRM_16BPPI1555 >> 25] =
+		{ { 10, 5, 0 }, { 5, 5, 0 }, { 0, 5, 0 }, { 0, 0, 0 } },
+
+	[LCD_WINCTRL1_FRM_16BPPI5551 >> 25] =
+		{ { 11, 5, 0 }, { 6, 5, 0 }, { 1, 5, 0 }, { 0, 0, 0 } },
+
+	[LCD_WINCTRL1_FRM_16BPPA1555 >> 25] =
+		{ { 10, 5, 0 }, { 5, 5, 0 }, { 0, 5, 0 }, { 15, 1, 0 } },
+
+	[LCD_WINCTRL1_FRM_16BPPA5551 >> 25] =
+		{ { 11, 5, 0 }, { 6, 5, 0 }, { 1, 5, 0 }, { 0, 1, 0 } },
+
+	[LCD_WINCTRL1_FRM_24BPP >> 25] =
+		{ { 16, 8, 0 }, { 8, 8, 0 }, { 0, 8, 0 }, { 0, 0, 0 } },
+
+	[LCD_WINCTRL1_FRM_32BPP >> 25] =
+		{ { 16, 8, 0 }, { 8, 8, 0 }, { 0, 8, 0 }, { 24, 0, 0 } },
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* Helpers */
+
+static void au1200fb_update_fbinfo(struct fb_info *fbi)
+{
+	/* FIX!!!! This also needs to take the window pixel format into account!!! */
+
+	/* Update var-dependent FB info */
+	if (panel_is_color(panel)) {
+		if (fbi->var.bits_per_pixel <= 8) {
+			/* palettized */
+			fbi->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+			fbi->fix.line_length = fbi->var.xres_virtual /
+				(8/fbi->var.bits_per_pixel);
+		} else {
+			/* non-palettized */
+			fbi->fix.visual = FB_VISUAL_TRUECOLOR;
+			fbi->fix.line_length = fbi->var.xres_virtual * (fbi->var.bits_per_pixel / 8);
+		}
+	} else {
+		/* mono FIX!!! mono 8 and 4 bits */
+		fbi->fix.visual = FB_VISUAL_MONO10;
+		fbi->fix.line_length = fbi->var.xres_virtual / 8;
+	}
+
+	fbi->screen_size = fbi->fix.line_length * fbi->var.yres_virtual;
+	print_dbg("line length: %d\n", fbi->fix.line_length);
+	print_dbg("bits_per_pixel: %d\n", fbi->var.bits_per_pixel);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* AU1200 framebuffer driver */
+
+/* fb_check_var
+ * Validate var settings with hardware restrictions and modify it if necessary
+ */
+static int au1200fb_fb_check_var(struct fb_var_screeninfo *var,
+	struct fb_info *fbi)
+{
+	struct au1200fb_device *fbdev = (struct au1200fb_device *)fbi;
+	u32 pixclock;
+	int screen_size, plane;
+
+	plane = fbdev->plane;
+
+	/* Make sure that the mode respect all LCD controller and
+	 * panel restrictions. */
+	var->xres = win->w[plane].xres;
+	var->yres = win->w[plane].yres;
+
+	/* No need for virtual resolution support */
+	var->xres_virtual = var->xres;
+	var->yres_virtual = var->yres;
+
+	var->bits_per_pixel = winbpp(win->w[plane].mode_winctrl1);
+
+	screen_size = var->xres_virtual * var->yres_virtual;
+	if (var->bits_per_pixel > 8) screen_size *= (var->bits_per_pixel / 8);
+	else screen_size /= (8/var->bits_per_pixel);
+
+	if (fbdev->fb_len < screen_size)
+		return -EINVAL; /* Virtual screen is to big, abort */
+
+	/* FIX!!!! what are the implicaitons of ignoring this for windows ??? */
+	/* The max LCD clock is fixed to 48MHz (value of AUX_CLK). The pixel
+	 * clock can only be obtain by dividing this value by an even integer.
+	 * Fallback to a slower pixel clock if necessary. */
+	pixclock = max((u32)(PICOS2KHZ(var->pixclock) * 1000), fbi->monspecs.dclkmin);
+	pixclock = min(pixclock, min(fbi->monspecs.dclkmax, (u32)AU1200_LCD_MAX_CLK/2));
+
+	if (AU1200_LCD_MAX_CLK % pixclock) {
+		int diff = AU1200_LCD_MAX_CLK % pixclock;
+		pixclock -= diff;
+	}
+
+	var->pixclock = KHZ2PICOS(pixclock/1000);
+#if 0
+	if (!panel_is_active(panel)) {
+		int pcd = AU1200_LCD_MAX_CLK / (pixclock * 2) - 1;
+
+		if (!panel_is_color(panel)
+			&& (panel->control_base & LCD_CONTROL_MPI) && (pcd < 3)) {
+			/* STN 8bit mono panel support is up to 6MHz pixclock */
+			var->pixclock = KHZ2PICOS(6000);
+		} else if (!pcd) {
+			/* Other STN panel support is up to 12MHz  */
+			var->pixclock = KHZ2PICOS(12000);
+		}
+	}
+#endif
+	/* Set bitfield accordingly */
+	switch (var->bits_per_pixel) {
+		case 16:
+		{
+			/* 16bpp True color.
+			 * These must be set to MATCH WINCTRL[FORM] */
+			int idx;
+			idx = (win->w[0].mode_winctrl1 & LCD_WINCTRL1_FRM) >> 25;
+			var->red    = rgb_bitfields[idx][0];
+			var->green  = rgb_bitfields[idx][1];
+			var->blue   = rgb_bitfields[idx][2];
+			var->transp = rgb_bitfields[idx][3];
+			break;
+		}
+
+		case 32:
+		{
+			/* 32bpp True color.
+			 * These must be set to MATCH WINCTRL[FORM] */
+			int idx;
+			idx = (win->w[0].mode_winctrl1 & LCD_WINCTRL1_FRM) >> 25;
+			var->red    = rgb_bitfields[idx][0];
+			var->green  = rgb_bitfields[idx][1];
+			var->blue   = rgb_bitfields[idx][2];
+			var->transp = rgb_bitfields[idx][3];
+			break;
+		}
+		default:
+			print_dbg("Unsupported depth %dbpp", var->bits_per_pixel);
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* fb_set_par
+ * Set hardware with var settings. This will enable the controller with a
+ * specific mode, normally validated with the fb_check_var method
+ */
+static int au1200fb_fb_set_par(struct fb_info *fbi)
+{
+	struct au1200fb_device *fbdev = (struct au1200fb_device *)fbi;
+
+	au1200fb_update_fbinfo(fbi);
+	au1200_setmode(fbdev);
+
+	return 0;
+}
+
+/* fb_setcolreg
+ * Set color in LCD palette.
+ */
+static int au1200fb_fb_setcolreg(unsigned regno, unsigned red, unsigned green,
+	unsigned blue, unsigned transp, struct fb_info *fbi)
+{
+	volatile u32 *palette = lcd->palette;
+	u32 value;
+
+	if (regno > (AU1200_LCD_NBR_PALETTE_ENTRIES - 1))
+		return -EINVAL;
+
+	if (fbi->var.grayscale) {
+		/* Convert color to grayscale */
+		red = green = blue =
+			(19595 * red + 38470 * green + 7471 * blue) >> 16;
+	}
+
+	if (fbi->fix.visual == FB_VISUAL_TRUECOLOR) {
+		/* Place color in the pseudopalette */
+		if (regno > 16)
+			return -EINVAL;
+
+		palette = (u32*) fbi->pseudo_palette;
+
+		red   >>= (16 - fbi->var.red.length);
+		green >>= (16 - fbi->var.green.length);
+		blue  >>= (16 - fbi->var.blue.length);
+
+		value = (red   << fbi->var.red.offset) 	|
+			(green << fbi->var.green.offset)|
+			(blue  << fbi->var.blue.offset);
+		value &= 0xFFFF;
+
+	} else if (1 /*FIX!!! panel_is_active(fbdev->panel)*/) {
+		/* COLOR TFT PALLETTIZED (use RGB 565) */
+		value = (red & 0xF800)|((green >> 5) &
+				0x07E0)|((blue >> 11) & 0x001F);
+		value &= 0xFFFF;
+
+	} else if (0 /*panel_is_color(fbdev->panel)*/) {
+		/* COLOR STN MODE */
+		value = 0x1234;
+		value &= 0xFFF;
+	} else {
+		/* MONOCHROME MODE */
+		value = (green >> 12) & 0x000F;
+		value &= 0xF;
+	}
+
+	palette[regno] = value;
+
+	return 0;
+}
+
+/* fb_blank
+ * Blank the screen. Depending on the mode, the screen will be
+ * activated with the backlight color, or desactivated
+ */
+static int au1200fb_fb_blank(int blank_mode, struct fb_info *fbi)
+{
+	/* Short-circuit screen blanking */
+	if (noblanking)
+		return 0;
+
+	switch (blank_mode) {
+
+	case FB_BLANK_UNBLANK:
+	case FB_BLANK_NORMAL:
+		/* printk("turn on panel\n"); */
+		au1200_setpanel(panel);
+		break;
+	case FB_BLANK_VSYNC_SUSPEND:
+	case FB_BLANK_HSYNC_SUSPEND:
+	case FB_BLANK_POWERDOWN:
+		/* printk("turn off panel\n"); */
+		au1200_setpanel(NULL);
+		break;
+	default:
+		break;
+
+	}
+
+	/* FB_BLANK_NORMAL is a soft blank */
+	return (blank_mode == FB_BLANK_NORMAL) ? -EINVAL : 0;
+}
+
+/* fb_mmap
+ * Map video memory in user space. We don't use the generic fb_mmap
+ * method mainly to allow the use of the TLB streaming flag (CCA=6)
+ */
+static int au1200fb_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+
+{
+	unsigned int len;
+	unsigned long start=0, off;
+	struct au1200fb_device *fbdev = (struct au1200fb_device *) info;
+
+#ifdef CONFIG_PM
+	au1xxx_pm_access(LCD_pm_dev);
+#endif
+
+	if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) {
+		return -EINVAL;
+	}
+
+	start = fbdev->fb_phys & PAGE_MASK;
+	len = PAGE_ALIGN((start & ~PAGE_MASK) + fbdev->fb_len);
+
+	off = vma->vm_pgoff << PAGE_SHIFT;
+
+	if ((vma->vm_end - vma->vm_start + off) > len) {
+		return -EINVAL;
+	}
+
+	off += start;
+	vma->vm_pgoff = off >> PAGE_SHIFT;
+
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+	pgprot_val(vma->vm_page_prot) |= _CACHE_MASK; /* CCA=7 */
+
+	vma->vm_flags |= VM_IO;
+
+	return io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
+				  vma->vm_end - vma->vm_start,
+				  vma->vm_page_prot);
+
+	return 0;
+}
+
+static void set_global(u_int cmd, struct au1200_lcd_global_regs_t *pdata)
+{
+
+	unsigned int hi1, divider;
+
+	/* SCREEN_SIZE: user cannot reset size, must switch panel choice */
+
+	if (pdata->flags & SCREEN_BACKCOLOR)
+		lcd->backcolor = pdata->backcolor;
+
+	if (pdata->flags & SCREEN_BRIGHTNESS) {
+
+		// limit brightness pwm duty to >= 30/1600
+		if (pdata->brightness < 30) {
+			pdata->brightness = 30;
+		}
+		divider = (lcd->pwmdiv & 0x3FFFF) + 1;
+		hi1 = (lcd->pwmhi >> 16) + 1;
+		hi1 = (((pdata->brightness & 0xFF)+1) * divider >> 8);
+		lcd->pwmhi &= 0xFFFF;
+		lcd->pwmhi |= (hi1 << 16);
+	}
+
+	if (pdata->flags & SCREEN_COLORKEY)
+		lcd->colorkey = pdata->colorkey;
+
+	if (pdata->flags & SCREEN_MASK)
+		lcd->colorkeymsk = pdata->mask;
+	au_sync();
+}
+
+static void get_global(u_int cmd, struct au1200_lcd_global_regs_t *pdata)
+{
+	unsigned int hi1, divider;
+
+	pdata->xsize = ((lcd->screen & LCD_SCREEN_SX) >> 19) + 1;
+	pdata->ysize = ((lcd->screen & LCD_SCREEN_SY) >> 8) + 1;
+
+	pdata->backcolor = lcd->backcolor;
+	pdata->colorkey = lcd->colorkey;
+	pdata->mask = lcd->colorkeymsk;
+
+	// brightness
+	hi1 = (lcd->pwmhi >> 16) + 1;
+	divider = (lcd->pwmdiv & 0x3FFFF) + 1;
+	pdata->brightness = ((hi1 << 8) / divider) - 1;
+	au_sync();
+}
+
+static void set_window(unsigned int plane,
+	struct au1200_lcd_window_regs_t *pdata)
+{
+	unsigned int val, bpp;
+
+	/* Window control register 0 */
+	if (pdata->flags & WIN_POSITION) {
+		val = lcd->window[plane].winctrl0 & ~(LCD_WINCTRL0_OX |
+				LCD_WINCTRL0_OY);
+		val |= ((pdata->xpos << 21) & LCD_WINCTRL0_OX);
+		val |= ((pdata->ypos << 10) & LCD_WINCTRL0_OY);
+		lcd->window[plane].winctrl0 = val;
+	}
+	if (pdata->flags & WIN_ALPHA_COLOR) {
+		val = lcd->window[plane].winctrl0 & ~(LCD_WINCTRL0_A);
+		val |= ((pdata->alpha_color << 2) & LCD_WINCTRL0_A);
+		lcd->window[plane].winctrl0 = val;
+	}
+	if (pdata->flags & WIN_ALPHA_MODE) {
+		val = lcd->window[plane].winctrl0 & ~(LCD_WINCTRL0_AEN);
+		val |= ((pdata->alpha_mode << 1) & LCD_WINCTRL0_AEN);
+		lcd->window[plane].winctrl0 = val;
+	}
+
+	/* Window control register 1 */
+	if (pdata->flags & WIN_PRIORITY) {
+		val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_PRI);
+		val |= ((pdata->priority << 30) & LCD_WINCTRL1_PRI);
+		lcd->window[plane].winctrl1 = val;
+	}
+	if (pdata->flags & WIN_CHANNEL) {
+		val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_PIPE);
+		val |= ((pdata->channel << 29) & LCD_WINCTRL1_PIPE);
+		lcd->window[plane].winctrl1 = val;
+	}
+	if (pdata->flags & WIN_BUFFER_FORMAT) {
+		val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_FRM);
+		val |= ((pdata->buffer_format << 25) & LCD_WINCTRL1_FRM);
+		lcd->window[plane].winctrl1 = val;
+	}
+	if (pdata->flags & WIN_COLOR_ORDER) {
+		val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_CCO);
+		val |= ((pdata->color_order << 24) & LCD_WINCTRL1_CCO);
+		lcd->window[plane].winctrl1 = val;
+	}
+	if (pdata->flags & WIN_PIXEL_ORDER) {
+		val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_PO);
+		val |= ((pdata->pixel_order << 22) & LCD_WINCTRL1_PO);
+		lcd->window[plane].winctrl1 = val;
+	}
+	if (pdata->flags & WIN_SIZE) {
+		val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_SZX |
+				LCD_WINCTRL1_SZY);
+		val |= (((pdata->xsize << 11) - 1) & LCD_WINCTRL1_SZX);
+		val |= (((pdata->ysize) - 1) & LCD_WINCTRL1_SZY);
+		lcd->window[plane].winctrl1 = val;
+		/* program buffer line width */
+		bpp = winbpp(val) / 8;
+		val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_BX);
+		val |= (((pdata->xsize * bpp) << 8) & LCD_WINCTRL2_BX);
+		lcd->window[plane].winctrl2 = val;
+	}
+
+	/* Window control register 2 */
+	if (pdata->flags & WIN_COLORKEY_MODE) {
+		val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_CKMODE);
+		val |= ((pdata->colorkey_mode << 24) & LCD_WINCTRL2_CKMODE);
+		lcd->window[plane].winctrl2 = val;
+	}
+	if (pdata->flags & WIN_DOUBLE_BUFFER_MODE) {
+		val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_DBM);
+		val |= ((pdata->double_buffer_mode << 23) & LCD_WINCTRL2_DBM);
+		lcd->window[plane].winctrl2 = val;
+	}
+	if (pdata->flags & WIN_RAM_ARRAY_MODE) {
+		val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_RAM);
+		val |= ((pdata->ram_array_mode << 21) & LCD_WINCTRL2_RAM);
+		lcd->window[plane].winctrl2 = val;
+	}
+
+	/* Buffer line width programmed with WIN_SIZE */
+
+	if (pdata->flags & WIN_BUFFER_SCALE) {
+		val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_SCX |
+				LCD_WINCTRL2_SCY);
+		val |= ((pdata->xsize << 11) & LCD_WINCTRL2_SCX);
+		val |= ((pdata->ysize) & LCD_WINCTRL2_SCY);
+		lcd->window[plane].winctrl2 = val;
+	}
+
+	if (pdata->flags & WIN_ENABLE) {
+		val = lcd->winenable;
+		val &= ~(1<<plane);
+		val |= (pdata->enable & 1) << plane;
+		lcd->winenable = val;
+	}
+	au_sync();
+}
+
+static void get_window(unsigned int plane,
+	struct au1200_lcd_window_regs_t *pdata)
+{
+	/* Window control register 0 */
+	pdata->xpos = (lcd->window[plane].winctrl0 & LCD_WINCTRL0_OX) >> 21;
+	pdata->ypos = (lcd->window[plane].winctrl0 & LCD_WINCTRL0_OY) >> 10;
+	pdata->alpha_color = (lcd->window[plane].winctrl0 & LCD_WINCTRL0_A) >> 2;
+	pdata->alpha_mode = (lcd->window[plane].winctrl0 & LCD_WINCTRL0_AEN) >> 1;
+
+	/* Window control register 1 */
+	pdata->priority = (lcd->window[plane].winctrl1& LCD_WINCTRL1_PRI) >> 30;
+	pdata->channel = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_PIPE) >> 29;
+	pdata->buffer_format = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_FRM) >> 25;
+	pdata->color_order = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_CCO) >> 24;
+	pdata->pixel_order = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_PO) >> 22;
+	pdata->xsize = ((lcd->window[plane].winctrl1 & LCD_WINCTRL1_SZX) >> 11) + 1;
+	pdata->ysize = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_SZY) + 1;
+
+	/* Window control register 2 */
+	pdata->colorkey_mode = (lcd->window[plane].winctrl2 & LCD_WINCTRL2_CKMODE) >> 24;
+	pdata->double_buffer_mode = (lcd->window[plane].winctrl2 & LCD_WINCTRL2_DBM) >> 23;
+	pdata->ram_array_mode = (lcd->window[plane].winctrl2 & LCD_WINCTRL2_RAM) >> 21;
+
+	pdata->enable = (lcd->winenable >> plane) & 1;
+	au_sync();
+}
+
+static int au1200fb_ioctl(struct fb_info *info, unsigned int cmd,
+                          unsigned long arg)
+{
+	int plane;
+	int val;
+
+#ifdef CONFIG_PM
+	au1xxx_pm_access(LCD_pm_dev);
+#endif
+
+	plane = fbinfo2index(info);
+	print_dbg("au1200fb: ioctl %d on plane %d\n", cmd, plane);
+
+	if (cmd == AU1200_LCD_FB_IOCTL) {
+		struct au1200_lcd_iodata_t iodata;
+
+		if (copy_from_user(&iodata, (void __user *) arg, sizeof(iodata)))
+			return -EFAULT;
+
+		print_dbg("FB IOCTL called\n");
+
+		switch (iodata.subcmd) {
+		case AU1200_LCD_SET_SCREEN:
+			print_dbg("AU1200_LCD_SET_SCREEN\n");
+			set_global(cmd, &iodata.global);
+			break;
+
+		case AU1200_LCD_GET_SCREEN:
+			print_dbg("AU1200_LCD_GET_SCREEN\n");
+			get_global(cmd, &iodata.global);
+			break;
+
+		case AU1200_LCD_SET_WINDOW:
+			print_dbg("AU1200_LCD_SET_WINDOW\n");
+			set_window(plane, &iodata.window);
+			break;
+
+		case AU1200_LCD_GET_WINDOW:
+			print_dbg("AU1200_LCD_GET_WINDOW\n");
+			get_window(plane, &iodata.window);
+			break;
+
+		case AU1200_LCD_SET_PANEL:
+			print_dbg("AU1200_LCD_SET_PANEL\n");
+			if ((iodata.global.panel_choice >= 0) &&
+					(iodata.global.panel_choice <
+					 NUM_PANELS))
+			{
+				struct panel_settings *newpanel;
+				panel_index = iodata.global.panel_choice;
+				newpanel = &known_lcd_panels[panel_index];
+				au1200_setpanel(newpanel);
+			}
+			break;
+
+		case AU1200_LCD_GET_PANEL:
+			print_dbg("AU1200_LCD_GET_PANEL\n");
+			iodata.global.panel_choice = panel_index;
+			break;
+
+		default:
+			return -EINVAL;
+		}
+
+		val = copy_to_user((void __user *) arg, &iodata, sizeof(iodata));
+		if (val) {
+			print_dbg("error: could not copy %d bytes\n", val);
+			return -EFAULT;
+		}
+	}
+
+	return 0;
+}
+
+
+static struct fb_ops au1200fb_fb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_check_var	= au1200fb_fb_check_var,
+	.fb_set_par	= au1200fb_fb_set_par,
+	.fb_setcolreg	= au1200fb_fb_setcolreg,
+	.fb_blank	= au1200fb_fb_blank,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_sync	= NULL,
+	.fb_ioctl	= au1200fb_ioctl,
+	.fb_mmap	= au1200fb_fb_mmap,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static irqreturn_t au1200fb_handle_irq(int irq, void* dev_id, struct pt_regs *regs)
+{
+	/* Nothing to do for now, just clear any pending interrupt */
+	lcd->intstatus = lcd->intstatus;
+	au_sync();
+
+	return IRQ_HANDLED;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* AU1200 LCD device probe helpers */
+
+static int au1200fb_init_fbinfo(struct au1200fb_device *fbdev)
+{
+	struct fb_info *fbi = &fbdev->fb_info;
+	int bpp;
+
+	memset(fbi, 0, sizeof(struct fb_info));
+	fbi->fbops = &au1200fb_fb_ops;
+
+	bpp = winbpp(win->w[fbdev->plane].mode_winctrl1);
+
+	/* Copy monitor specs from panel data */
+	/* fixme: we're setting up LCD controller windows, so these dont give a
+	damn as to what the monitor specs are (the panel itself does, but that
+	isnt done here...so maybe need a generic catchall monitor setting??? */
+	memcpy(&fbi->monspecs, &panel->monspecs, sizeof(struct fb_monspecs));
+
+	/* We first try the user mode passed in argument. If that failed,
+	 * or if no one has been specified, we default to the first mode of the
+	 * panel list. Note that after this call, var data will be set */
+	if (!fb_find_mode(&fbi->var,
+			  fbi,
+			  NULL, /* drv_info.opt_mode, */
+			  fbi->monspecs.modedb,
+			  fbi->monspecs.modedb_len,
+			  fbi->monspecs.modedb,
+			  bpp)) {
+
+		print_err("Cannot find valid mode for panel %s", panel->name);
+		return -EFAULT;
+	}
+
+	fbi->pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL);
+	if (!fbi->pseudo_palette) {
+		return -ENOMEM;
+	}
+	memset(fbi->pseudo_palette, 0, sizeof(u32) * 16);
+
+	if (fb_alloc_cmap(&fbi->cmap, AU1200_LCD_NBR_PALETTE_ENTRIES, 0) < 0) {
+		print_err("Fail to allocate colormap (%d entries)",
+			   AU1200_LCD_NBR_PALETTE_ENTRIES);
+		kfree(fbi->pseudo_palette);
+		return -EFAULT;
+	}
+
+	strncpy(fbi->fix.id, "AU1200", sizeof(fbi->fix.id));
+	fbi->fix.smem_start = fbdev->fb_phys;
+	fbi->fix.smem_len = fbdev->fb_len;
+	fbi->fix.type = FB_TYPE_PACKED_PIXELS;
+	fbi->fix.xpanstep = 0;
+	fbi->fix.ypanstep = 0;
+	fbi->fix.mmio_start = 0;
+	fbi->fix.mmio_len = 0;
+	fbi->fix.accel = FB_ACCEL_NONE;
+
+	fbi->screen_base = (char __iomem *) fbdev->fb_mem;
+
+	au1200fb_update_fbinfo(fbi);
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* AU1200 LCD controller device driver */
+
+static int au1200fb_drv_probe(struct device *dev)
+{
+	struct au1200fb_device *fbdev;
+	unsigned long page;
+	int bpp, plane, ret;
+
+	if (!dev)
+		return -EINVAL;
+
+	for (plane = 0; plane < CONFIG_FB_AU1200_DEVS; ++plane) {
+		bpp = winbpp(win->w[plane].mode_winctrl1);
+		if (win->w[plane].xres == 0)
+			win->w[plane].xres = panel->Xres;
+		if (win->w[plane].yres == 0)
+			win->w[plane].yres = panel->Yres;
+
+		fbdev = &_au1200fb_devices[plane];
+		memset(fbdev, 0, sizeof(struct au1200fb_device));
+		fbdev->plane = plane;
+
+		/* Allocate the framebuffer to the maximum screen size */
+		fbdev->fb_len = (win->w[plane].xres * win->w[plane].yres * bpp) / 8;
+
+		fbdev->fb_mem = dma_alloc_noncoherent(dev,
+				PAGE_ALIGN(fbdev->fb_len),
+				&fbdev->fb_phys, GFP_KERNEL);
+		if (!fbdev->fb_mem) {
+			print_err("fail to allocate frambuffer (size: %dK))",
+				  fbdev->fb_len / 1024);
+			return -ENOMEM;
+		}
+
+		/*
+		 * Set page reserved so that mmap will work. This is necessary
+		 * since we'll be remapping normal memory.
+		 */
+		for (page = (unsigned long)fbdev->fb_phys;
+		     page < PAGE_ALIGN((unsigned long)fbdev->fb_phys +
+			     fbdev->fb_len);
+		     page += PAGE_SIZE) {
+			SetPageReserved(pfn_to_page(page >> PAGE_SHIFT)); /* LCD DMA is NOT coherent on Au1200 */
+		}
+		print_dbg("Framebuffer memory map at %p", fbdev->fb_mem);
+		print_dbg("phys=0x%08x, size=%dK", fbdev->fb_phys, fbdev->fb_len / 1024);
+
+		/* Init FB data */
+		if ((ret = au1200fb_init_fbinfo(fbdev)) < 0)
+			goto failed;
+
+		/* Register new framebuffer */
+		if ((ret = register_framebuffer(&fbdev->fb_info)) < 0) {
+			print_err("cannot register new framebuffer");
+			goto failed;
+		}
+
+		au1200fb_fb_set_par(&fbdev->fb_info);
+
+#if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO)
+		if (plane == 0)
+			if (fb_prepare_logo(&fbdev->fb_info, FB_ROTATE_UR)) {
+				/* Start display and show logo on boot */
+				fb_set_cmap(&fbdev->fb_info.cmap,
+						&fbdev->fb_info);
+
+				fb_show_logo(&fbdev->fb_info, FB_ROTATE_UR);
+			}
+#endif
+	}
+
+	/* Now hook interrupt too */
+	if ((ret = request_irq(AU1200_LCD_INT, au1200fb_handle_irq,
+		 	  SA_INTERRUPT | SA_SHIRQ, "lcd", (void *)dev)) < 0) {
+		print_err("fail to request interrupt line %d (err: %d)",
+			  AU1200_LCD_INT, ret);
+		goto failed;
+	}
+
+	return 0;
+
+failed:
+	/* NOTE: This only does the current plane/window that failed; others are still active */
+	if (fbdev->fb_mem)
+		dma_free_noncoherent(dev, PAGE_ALIGN(fbdev->fb_len),
+				fbdev->fb_mem, fbdev->fb_phys);
+	if (fbdev->fb_info.cmap.len != 0)
+		fb_dealloc_cmap(&fbdev->fb_info.cmap);
+	if (fbdev->fb_info.pseudo_palette)
+		kfree(fbdev->fb_info.pseudo_palette);
+	if (plane == 0)
+		free_irq(AU1200_LCD_INT, (void*)dev);
+	return ret;
+}
+
+static int au1200fb_drv_remove(struct device *dev)
+{
+	struct au1200fb_device *fbdev;
+	int plane;
+
+	if (!dev)
+		return -ENODEV;
+
+	/* Turn off the panel */
+	au1200_setpanel(NULL);
+
+	for (plane = 0; plane < CONFIG_FB_AU1200_DEVS; ++plane)
+	{
+		fbdev = &_au1200fb_devices[plane];
+
+		/* Clean up all probe data */
+		unregister_framebuffer(&fbdev->fb_info);
+		if (fbdev->fb_mem)
+			dma_free_noncoherent(dev, PAGE_ALIGN(fbdev->fb_len),
+					fbdev->fb_mem, fbdev->fb_phys);
+		if (fbdev->fb_info.cmap.len != 0)
+			fb_dealloc_cmap(&fbdev->fb_info.cmap);
+		if (fbdev->fb_info.pseudo_palette)
+			kfree(fbdev->fb_info.pseudo_palette);
+	}
+
+	free_irq(AU1200_LCD_INT, (void *)dev);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int au1200fb_drv_suspend(struct device *dev, u32 state, u32 level)
+{
+	/* TODO */
+	return 0;
+}
+
+static int au1200fb_drv_resume(struct device *dev, u32 level)
+{
+	/* TODO */
+	return 0;
+}
+#endif /* CONFIG_PM */
+
+static struct device_driver au1200fb_driver = {
+	.name		= "au1200-lcd",
+	.bus		= &platform_bus_type,
+	.probe		= au1200fb_drv_probe,
+	.remove		= au1200fb_drv_remove,
+#ifdef CONFIG_PM
+	.suspend	= au1200fb_drv_suspend,
+	.resume		= au1200fb_drv_resume,
+#endif
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* Kernel driver */
+
+static void au1200fb_setup(void)
+{
+	char* options = NULL;
+	char* this_opt;
+	int num_panels = ARRAY_SIZE(known_lcd_panels);
+	int panel_idx = -1;
+
+	fb_get_options(DRIVER_NAME, &options);
+
+	if (options) {
+		while ((this_opt = strsep(&options,",")) != NULL) {
+			/* Panel option - can be panel name,
+			 * "bs" for board-switch, or number/index */
+			if (!strncmp(this_opt, "panel:", 6)) {
+				int i;
+				long int li;
+				char *endptr;
+				this_opt += 6;
+				/* First check for index, which allows
+				 * to short circuit this mess */
+				li = simple_strtol(this_opt, &endptr, 0);
+				if (*endptr == '\0') {
+					panel_idx = (int)li;
+				}
+				else if (strcmp(this_opt, "bs") == 0) {
+					extern int board_au1200fb_panel(void);
+					panel_idx = board_au1200fb_panel();
+				}
+
+				else
+				for (i = 0; i < num_panels; i++) {
+					if (!strcmp(this_opt, known_lcd_panels[i].name)) {
+						panel_idx = i;
+						break;
+					}
+				}
+
+				if ((panel_idx < 0) || (panel_idx >= num_panels)) {
+						print_warn("Panel %s not supported!", this_opt);
+				}
+				else
+					panel_index = panel_idx;
+			}
+
+			else if (strncmp(this_opt, "nohwcursor", 10) == 0) {
+				nohwcursor = 1;
+			}
+
+			/* Unsupported option */
+			else {
+				print_warn("Unsupported option \"%s\"", this_opt);
+			}
+		}
+	}
+}
+
+#ifdef CONFIG_PM
+static int au1200fb_pm_callback(au1xxx_power_dev_t *dev,
+		au1xxx_request_t request, void *data) {
+	int retval = -1;
+	unsigned int d = 0;
+	unsigned int brightness = 0;
+
+	if (request == AU1XXX_PM_SLEEP) {
+		board_au1200fb_panel_shutdown();
+	}
+	else if (request == AU1XXX_PM_WAKEUP) {
+		if(dev->prev_state == SLEEP_STATE)
+		{
+			int plane;
+			au1200_setpanel(panel);
+			for (plane = 0; plane < CONFIG_FB_AU1200_DEVS; ++plane) 	{
+				struct au1200fb_device *fbdev;
+				fbdev = &_au1200fb_devices[plane];
+				au1200fb_fb_set_par(&fbdev->fb_info);
+			}
+		}
+
+		d = *((unsigned int*)data);
+		if(d <=10) brightness = 26;
+		else if(d<=20) brightness = 51;
+		else if(d<=30) brightness = 77;
+		else if(d<=40) brightness = 102;
+		else if(d<=50) brightness = 128;
+		else if(d<=60) brightness = 153;
+		else if(d<=70) brightness = 179;
+		else if(d<=80) brightness = 204;
+		else if(d<=90) brightness = 230;
+		else brightness = 255;
+		set_brightness(brightness);
+	} else if (request == AU1XXX_PM_GETSTATUS) {
+		return dev->cur_state;
+	} else if (request == AU1XXX_PM_ACCESS) {
+		if (dev->cur_state != SLEEP_STATE)
+			return retval;
+		else {
+			au1200_setpanel(panel);
+		}
+	} else if (request == AU1XXX_PM_IDLE) {
+	} else if (request == AU1XXX_PM_CLEANUP) {
+	}
+
+	return retval;
+}
+#endif
+
+static int __init au1200fb_init(void)
+{
+	print_info("" DRIVER_DESC "");
+
+	/* Setup driver with options */
+	au1200fb_setup();
+
+	/* Point to the panel selected */
+	panel = &known_lcd_panels[panel_index];
+	win = &windows[window_index];
+
+	printk(DRIVER_NAME ": Panel %d %s\n", panel_index, panel->name);
+	printk(DRIVER_NAME ": Win %d %s\n", window_index, win->name);
+
+	/* Kickstart the panel, the framebuffers/windows come soon enough */
+	au1200_setpanel(panel);
+
+	#ifdef CONFIG_PM
+	LCD_pm_dev = new_au1xxx_power_device("LCD", &au1200fb_pm_callback, NULL);
+	if ( LCD_pm_dev == NULL)
+		printk(KERN_INFO "Unable to create a power management device entry for the au1200fb.\n");
+	else
+		printk(KERN_INFO "Power management device entry for the au1200fb loaded.\n");
+	#endif
+
+	return driver_register(&au1200fb_driver);
+}
+
+static void __exit au1200fb_cleanup(void)
+{
+	driver_unregister(&au1200fb_driver);
+}
+
+module_init(au1200fb_init);
+module_exit(au1200fb_cleanup);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/au1200fb.h b/drivers/video/au1200fb.h
new file mode 100644
index 0000000..e267271
--- /dev/null
+++ b/drivers/video/au1200fb.h
@@ -0,0 +1,572 @@
+/*
+ * BRIEF MODULE DESCRIPTION
+ *	Hardware definitions for the Au1200 LCD controller
+ *
+ * Copyright 2004 AMD
+ * Author:	AMD
+ *
+ *  This program is free software; you can redistribute	 it and/or modify it
+ *  under  the terms of	 the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the	License, or (at your
+ *  option) any later version.
+ *
+ *  THIS  SOFTWARE  IS PROVIDED	  ``AS	IS'' AND   ANY	EXPRESS OR IMPLIED
+ *  WARRANTIES,	  INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO	EVENT  SHALL   THE AUTHOR  BE	 LIABLE FOR ANY	  DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED	  TO, PROCUREMENT OF  SUBSTITUTE GOODS	OR SERVICES; LOSS OF
+ *  USE, DATA,	OR PROFITS; OR	BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN	 CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the  GNU General Public License along
+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _AU1200LCD_H
+#define _AU1200LCD_H
+
+/********************************************************************/
+#define AU1200_LCD_ADDR		0xB5000000
+
+#define uint8 unsigned char
+#define uint32 unsigned int
+
+struct au1200_lcd {
+	volatile uint32	reserved0;
+	volatile uint32	screen;
+	volatile uint32	backcolor;
+	volatile uint32	horztiming;
+	volatile uint32	verttiming;
+	volatile uint32	clkcontrol;
+	volatile uint32	pwmdiv;
+	volatile uint32	pwmhi;
+	volatile uint32	reserved1;
+	volatile uint32	winenable;
+	volatile uint32	colorkey;
+	volatile uint32	colorkeymsk;
+	struct
+	{
+		volatile uint32	cursorctrl;
+		volatile uint32	cursorpos;
+		volatile uint32	cursorcolor0;
+		volatile uint32	cursorcolor1;
+		volatile uint32	cursorcolor2;
+		uint32	cursorcolor3;
+	} hwc;
+	volatile uint32	intstatus;
+	volatile uint32	intenable;
+	volatile uint32	outmask;
+	volatile uint32	fifoctrl;
+	uint32	reserved2[(0x0100-0x0058)/4];
+	struct
+	{
+		volatile uint32	winctrl0;
+		volatile uint32	winctrl1;
+		volatile uint32	winctrl2;
+		volatile uint32	winbuf0;
+		volatile uint32	winbuf1;
+		volatile uint32	winbufctrl;
+		uint32	winreserved0;
+		uint32	winreserved1;
+	} window[4];
+
+	uint32	reserved3[(0x0400-0x0180)/4];
+
+	volatile uint32	palette[(0x0800-0x0400)/4];
+
+	volatile uint8	cursorpattern[256];
+};
+
+/* lcd_screen */
+#define LCD_SCREEN_SEN		(1<<31)
+#define LCD_SCREEN_SX		(0x07FF<<19)
+#define LCD_SCREEN_SY		(0x07FF<< 8)
+#define LCD_SCREEN_SWP		(1<<7)
+#define LCD_SCREEN_SWD		(1<<6)
+#define LCD_SCREEN_PT		(7<<0)
+#define LCD_SCREEN_PT_TFT	(0<<0)
+#define LCD_SCREEN_SX_N(WIDTH)	((WIDTH-1)<<19)
+#define LCD_SCREEN_SY_N(HEIGHT)	((HEIGHT-1)<<8)
+#define LCD_SCREEN_PT_CSTN	(1<<0)
+#define LCD_SCREEN_PT_CDSTN	(2<<0)
+#define LCD_SCREEN_PT_M8STN	(3<<0)
+#define LCD_SCREEN_PT_M4STN	(4<<0)
+
+/* lcd_backcolor */
+#define LCD_BACKCOLOR_SBGR		(0xFF<<16)
+#define LCD_BACKCOLOR_SBGG		(0xFF<<8)
+#define LCD_BACKCOLOR_SBGB		(0xFF<<0)
+#define LCD_BACKCOLOR_SBGR_N(N)	((N)<<16)
+#define LCD_BACKCOLOR_SBGG_N(N)	((N)<<8)
+#define LCD_BACKCOLOR_SBGB_N(N)	((N)<<0)
+
+/* lcd_winenable */
+#define LCD_WINENABLE_WEN3		(1<<3)
+#define LCD_WINENABLE_WEN2		(1<<2)
+#define LCD_WINENABLE_WEN1		(1<<1)
+#define LCD_WINENABLE_WEN0		(1<<0)
+
+/* lcd_colorkey */
+#define LCD_COLORKEY_CKR		(0xFF<<16)
+#define LCD_COLORKEY_CKG		(0xFF<<8)
+#define LCD_COLORKEY_CKB		(0xFF<<0)
+#define LCD_COLORKEY_CKR_N(N)	((N)<<16)
+#define LCD_COLORKEY_CKG_N(N)	((N)<<8)
+#define LCD_COLORKEY_CKB_N(N)	((N)<<0)
+
+/* lcd_colorkeymsk */
+#define LCD_COLORKEYMSK_CKMR		(0xFF<<16)
+#define LCD_COLORKEYMSK_CKMG		(0xFF<<8)
+#define LCD_COLORKEYMSK_CKMB		(0xFF<<0)
+#define LCD_COLORKEYMSK_CKMR_N(N)	((N)<<16)
+#define LCD_COLORKEYMSK_CKMG_N(N)	((N)<<8)
+#define LCD_COLORKEYMSK_CKMB_N(N)	((N)<<0)
+
+/* lcd windows control 0 */
+#define LCD_WINCTRL0_OX		(0x07FF<<21)
+#define LCD_WINCTRL0_OY		(0x07FF<<10)
+#define LCD_WINCTRL0_A		(0x00FF<<2)
+#define LCD_WINCTRL0_AEN	(1<<1)
+#define LCD_WINCTRL0_OX_N(N) ((N)<<21)
+#define LCD_WINCTRL0_OY_N(N) ((N)<<10)
+#define LCD_WINCTRL0_A_N(N) ((N)<<2)
+
+/* lcd windows control 1 */
+#define LCD_WINCTRL1_PRI	(3<<30)
+#define LCD_WINCTRL1_PIPE	(1<<29)
+#define LCD_WINCTRL1_FRM	(0xF<<25)
+#define LCD_WINCTRL1_CCO	(1<<24)
+#define LCD_WINCTRL1_PO		(3<<22)
+#define LCD_WINCTRL1_SZX	(0x07FF<<11)
+#define LCD_WINCTRL1_SZY	(0x07FF<<0)
+#define LCD_WINCTRL1_FRM_1BPP	(0<<25)
+#define LCD_WINCTRL1_FRM_2BPP	(1<<25)
+#define LCD_WINCTRL1_FRM_4BPP	(2<<25)
+#define LCD_WINCTRL1_FRM_8BPP	(3<<25)
+#define LCD_WINCTRL1_FRM_12BPP	(4<<25)
+#define LCD_WINCTRL1_FRM_16BPP655	(5<<25)
+#define LCD_WINCTRL1_FRM_16BPP565	(6<<25)
+#define LCD_WINCTRL1_FRM_16BPP556	(7<<25)
+#define LCD_WINCTRL1_FRM_16BPPI1555	(8<<25)
+#define LCD_WINCTRL1_FRM_16BPPI5551	(9<<25)
+#define LCD_WINCTRL1_FRM_16BPPA1555	(10<<25)
+#define LCD_WINCTRL1_FRM_16BPPA5551	(11<<25)
+#define LCD_WINCTRL1_FRM_24BPP		(12<<25)
+#define LCD_WINCTRL1_FRM_32BPP		(13<<25)
+#define LCD_WINCTRL1_PRI_N(N)	((N)<<30)
+#define LCD_WINCTRL1_PO_00		(0<<22)
+#define LCD_WINCTRL1_PO_01		(1<<22)
+#define LCD_WINCTRL1_PO_10		(2<<22)
+#define LCD_WINCTRL1_PO_11		(3<<22)
+#define LCD_WINCTRL1_SZX_N(N)	((N-1)<<11)
+#define LCD_WINCTRL1_SZY_N(N)	((N-1)<<0)
+
+/* lcd windows control 2 */
+#define LCD_WINCTRL2_CKMODE		(3<<24)
+#define LCD_WINCTRL2_DBM		(1<<23)
+#define LCD_WINCTRL2_RAM		(3<<21)
+#define LCD_WINCTRL2_BX			(0x1FFF<<8)
+#define LCD_WINCTRL2_SCX		(0xF<<4)
+#define LCD_WINCTRL2_SCY		(0xF<<0)
+#define LCD_WINCTRL2_CKMODE_00		(0<<24)
+#define LCD_WINCTRL2_CKMODE_01		(1<<24)
+#define LCD_WINCTRL2_CKMODE_10		(2<<24)
+#define LCD_WINCTRL2_CKMODE_11		(3<<24)
+#define LCD_WINCTRL2_RAM_NONE		(0<<21)
+#define LCD_WINCTRL2_RAM_PALETTE	(1<<21)
+#define LCD_WINCTRL2_RAM_GAMMA		(2<<21)
+#define LCD_WINCTRL2_RAM_BUFFER		(3<<21)
+#define LCD_WINCTRL2_BX_N(N)	((N)<<8)
+#define LCD_WINCTRL2_SCX_1		(0<<4)
+#define LCD_WINCTRL2_SCX_2		(1<<4)
+#define LCD_WINCTRL2_SCX_4		(2<<4)
+#define LCD_WINCTRL2_SCY_1		(0<<0)
+#define LCD_WINCTRL2_SCY_2		(1<<0)
+#define LCD_WINCTRL2_SCY_4		(2<<0)
+
+/* lcd windows buffer control */
+#define LCD_WINBUFCTRL_DB		(1<<1)
+#define LCD_WINBUFCTRL_DBN		(1<<0)
+
+/* lcd_intstatus, lcd_intenable */
+#define LCD_INT_IFO				(0xF<<14)
+#define LCD_INT_IFU				(0xF<<10)
+#define LCD_INT_OFO				(1<<9)
+#define LCD_INT_OFU				(1<<8)
+#define LCD_INT_WAIT			(1<<3)
+#define LCD_INT_SD				(1<<2)
+#define LCD_INT_SA				(1<<1)
+#define LCD_INT_SS				(1<<0)
+
+/* lcd_horztiming */
+#define LCD_HORZTIMING_HND2		(0x1FF<<18)
+#define LCD_HORZTIMING_HND1		(0x1FF<<9)
+#define LCD_HORZTIMING_HPW		(0x1FF<<0)
+#define LCD_HORZTIMING_HND2_N(N)(((N)-1)<<18)
+#define LCD_HORZTIMING_HND1_N(N)(((N)-1)<<9)
+#define LCD_HORZTIMING_HPW_N(N)	(((N)-1)<<0)
+
+/* lcd_verttiming */
+#define LCD_VERTTIMING_VND2		(0x1FF<<18)
+#define LCD_VERTTIMING_VND1		(0x1FF<<9)
+#define LCD_VERTTIMING_VPW		(0x1FF<<0)
+#define LCD_VERTTIMING_VND2_N(N)(((N)-1)<<18)
+#define LCD_VERTTIMING_VND1_N(N)(((N)-1)<<9)
+#define LCD_VERTTIMING_VPW_N(N)	(((N)-1)<<0)
+
+/* lcd_clkcontrol */
+#define LCD_CLKCONTROL_EXT		(1<<22)
+#define LCD_CLKCONTROL_DELAY	(3<<20)
+#define LCD_CLKCONTROL_CDD		(1<<19)
+#define LCD_CLKCONTROL_IB		(1<<18)
+#define LCD_CLKCONTROL_IC		(1<<17)
+#define LCD_CLKCONTROL_IH		(1<<16)
+#define LCD_CLKCONTROL_IV		(1<<15)
+#define LCD_CLKCONTROL_BF		(0x1F<<10)
+#define LCD_CLKCONTROL_PCD		(0x3FF<<0)
+#define LCD_CLKCONTROL_BF_N(N)	(((N)-1)<<10)
+#define LCD_CLKCONTROL_PCD_N(N)	((N)<<0)
+
+/* lcd_pwmdiv */
+#define LCD_PWMDIV_EN			(1<<31)
+#define LCD_PWMDIV_PWMDIV		(0x1FFFF<<0)
+#define LCD_PWMDIV_PWMDIV_N(N)	((N)<<0)
+
+/* lcd_pwmhi */
+#define LCD_PWMHI_PWMHI1		(0xFFFF<<16)
+#define LCD_PWMHI_PWMHI0		(0xFFFF<<0)
+#define LCD_PWMHI_PWMHI1_N(N)	((N)<<16)
+#define LCD_PWMHI_PWMHI0_N(N)	((N)<<0)
+
+/* lcd_hwccon */
+#define LCD_HWCCON_EN			(1<<0)
+
+/* lcd_cursorpos */
+#define LCD_CURSORPOS_HWCXOFF		(0x1F<<27)
+#define LCD_CURSORPOS_HWCXPOS		(0x07FF<<16)
+#define LCD_CURSORPOS_HWCYOFF		(0x1F<<11)
+#define LCD_CURSORPOS_HWCYPOS		(0x07FF<<0)
+#define LCD_CURSORPOS_HWCXOFF_N(N)	((N)<<27)
+#define LCD_CURSORPOS_HWCXPOS_N(N)	((N)<<16)
+#define LCD_CURSORPOS_HWCYOFF_N(N)	((N)<<11)
+#define LCD_CURSORPOS_HWCYPOS_N(N)	((N)<<0)
+
+/* lcd_cursorcolor */
+#define LCD_CURSORCOLOR_HWCA		(0xFF<<24)
+#define LCD_CURSORCOLOR_HWCR		(0xFF<<16)
+#define LCD_CURSORCOLOR_HWCG		(0xFF<<8)
+#define LCD_CURSORCOLOR_HWCB		(0xFF<<0)
+#define LCD_CURSORCOLOR_HWCA_N(N)	((N)<<24)
+#define LCD_CURSORCOLOR_HWCR_N(N)	((N)<<16)
+#define LCD_CURSORCOLOR_HWCG_N(N)	((N)<<8)
+#define LCD_CURSORCOLOR_HWCB_N(N)	((N)<<0)
+
+/* lcd_fifoctrl */
+#define LCD_FIFOCTRL_F3IF		(1<<29)
+#define LCD_FIFOCTRL_F3REQ		(0x1F<<24)
+#define LCD_FIFOCTRL_F2IF		(1<<29)
+#define LCD_FIFOCTRL_F2REQ		(0x1F<<16)
+#define LCD_FIFOCTRL_F1IF		(1<<29)
+#define LCD_FIFOCTRL_F1REQ		(0x1F<<8)
+#define LCD_FIFOCTRL_F0IF		(1<<29)
+#define LCD_FIFOCTRL_F0REQ		(0x1F<<0)
+#define LCD_FIFOCTRL_F3REQ_N(N)	((N-1)<<24)
+#define LCD_FIFOCTRL_F2REQ_N(N)	((N-1)<<16)
+#define LCD_FIFOCTRL_F1REQ_N(N)	((N-1)<<8)
+#define LCD_FIFOCTRL_F0REQ_N(N)	((N-1)<<0)
+
+/* lcd_outmask */
+#define LCD_OUTMASK_MASK		(0x00FFFFFF)
+
+/********************************************************************/
+#endif /* _AU1200LCD_H */
+/*
+ * BRIEF MODULE DESCRIPTION
+ *	Hardware definitions for the Au1200 LCD controller
+ *
+ * Copyright 2004 AMD
+ * Author:	AMD
+ *
+ *  This program is free software; you can redistribute	 it and/or modify it
+ *  under  the terms of	 the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the	License, or (at your
+ *  option) any later version.
+ *
+ *  THIS  SOFTWARE  IS PROVIDED	  ``AS	IS'' AND   ANY	EXPRESS OR IMPLIED
+ *  WARRANTIES,	  INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO	EVENT  SHALL   THE AUTHOR  BE	 LIABLE FOR ANY	  DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED	  TO, PROCUREMENT OF  SUBSTITUTE GOODS	OR SERVICES; LOSS OF
+ *  USE, DATA,	OR PROFITS; OR	BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN	 CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the  GNU General Public License along
+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _AU1200LCD_H
+#define _AU1200LCD_H
+
+/********************************************************************/
+#define AU1200_LCD_ADDR		0xB5000000
+
+#define uint8 unsigned char
+#define uint32 unsigned int
+
+struct au1200_lcd {
+	volatile uint32	reserved0;
+	volatile uint32	screen;
+	volatile uint32	backcolor;
+	volatile uint32	horztiming;
+	volatile uint32	verttiming;
+	volatile uint32	clkcontrol;
+	volatile uint32	pwmdiv;
+	volatile uint32	pwmhi;
+	volatile uint32	reserved1;
+	volatile uint32	winenable;
+	volatile uint32	colorkey;
+	volatile uint32	colorkeymsk;
+	struct
+	{
+		volatile uint32	cursorctrl;
+		volatile uint32	cursorpos;
+		volatile uint32	cursorcolor0;
+		volatile uint32	cursorcolor1;
+		volatile uint32	cursorcolor2;
+		uint32	cursorcolor3;
+	} hwc;
+	volatile uint32	intstatus;
+	volatile uint32	intenable;
+	volatile uint32	outmask;
+	volatile uint32	fifoctrl;
+	uint32	reserved2[(0x0100-0x0058)/4];
+	struct
+	{
+		volatile uint32	winctrl0;
+		volatile uint32	winctrl1;
+		volatile uint32	winctrl2;
+		volatile uint32	winbuf0;
+		volatile uint32	winbuf1;
+		volatile uint32	winbufctrl;
+		uint32	winreserved0;
+		uint32	winreserved1;
+	} window[4];
+
+	uint32	reserved3[(0x0400-0x0180)/4];
+
+	volatile uint32	palette[(0x0800-0x0400)/4];
+
+	volatile uint8	cursorpattern[256];
+};
+
+/* lcd_screen */
+#define LCD_SCREEN_SEN		(1<<31)
+#define LCD_SCREEN_SX		(0x07FF<<19)
+#define LCD_SCREEN_SY		(0x07FF<< 8)
+#define LCD_SCREEN_SWP		(1<<7)
+#define LCD_SCREEN_SWD		(1<<6)
+#define LCD_SCREEN_PT		(7<<0)
+#define LCD_SCREEN_PT_TFT	(0<<0)
+#define LCD_SCREEN_SX_N(WIDTH)	((WIDTH-1)<<19)
+#define LCD_SCREEN_SY_N(HEIGHT)	((HEIGHT-1)<<8)
+#define LCD_SCREEN_PT_CSTN	(1<<0)
+#define LCD_SCREEN_PT_CDSTN	(2<<0)
+#define LCD_SCREEN_PT_M8STN	(3<<0)
+#define LCD_SCREEN_PT_M4STN	(4<<0)
+
+/* lcd_backcolor */
+#define LCD_BACKCOLOR_SBGR		(0xFF<<16)
+#define LCD_BACKCOLOR_SBGG		(0xFF<<8)
+#define LCD_BACKCOLOR_SBGB		(0xFF<<0)
+#define LCD_BACKCOLOR_SBGR_N(N)	((N)<<16)
+#define LCD_BACKCOLOR_SBGG_N(N)	((N)<<8)
+#define LCD_BACKCOLOR_SBGB_N(N)	((N)<<0)
+
+/* lcd_winenable */
+#define LCD_WINENABLE_WEN3		(1<<3)
+#define LCD_WINENABLE_WEN2		(1<<2)
+#define LCD_WINENABLE_WEN1		(1<<1)
+#define LCD_WINENABLE_WEN0		(1<<0)
+
+/* lcd_colorkey */
+#define LCD_COLORKEY_CKR		(0xFF<<16)
+#define LCD_COLORKEY_CKG		(0xFF<<8)
+#define LCD_COLORKEY_CKB		(0xFF<<0)
+#define LCD_COLORKEY_CKR_N(N)	((N)<<16)
+#define LCD_COLORKEY_CKG_N(N)	((N)<<8)
+#define LCD_COLORKEY_CKB_N(N)	((N)<<0)
+
+/* lcd_colorkeymsk */
+#define LCD_COLORKEYMSK_CKMR		(0xFF<<16)
+#define LCD_COLORKEYMSK_CKMG		(0xFF<<8)
+#define LCD_COLORKEYMSK_CKMB		(0xFF<<0)
+#define LCD_COLORKEYMSK_CKMR_N(N)	((N)<<16)
+#define LCD_COLORKEYMSK_CKMG_N(N)	((N)<<8)
+#define LCD_COLORKEYMSK_CKMB_N(N)	((N)<<0)
+
+/* lcd windows control 0 */
+#define LCD_WINCTRL0_OX		(0x07FF<<21)
+#define LCD_WINCTRL0_OY		(0x07FF<<10)
+#define LCD_WINCTRL0_A		(0x00FF<<2)
+#define LCD_WINCTRL0_AEN	(1<<1)
+#define LCD_WINCTRL0_OX_N(N) ((N)<<21)
+#define LCD_WINCTRL0_OY_N(N) ((N)<<10)
+#define LCD_WINCTRL0_A_N(N) ((N)<<2)
+
+/* lcd windows control 1 */
+#define LCD_WINCTRL1_PRI	(3<<30)
+#define LCD_WINCTRL1_PIPE	(1<<29)
+#define LCD_WINCTRL1_FRM	(0xF<<25)
+#define LCD_WINCTRL1_CCO	(1<<24)
+#define LCD_WINCTRL1_PO		(3<<22)
+#define LCD_WINCTRL1_SZX	(0x07FF<<11)
+#define LCD_WINCTRL1_SZY	(0x07FF<<0)
+#define LCD_WINCTRL1_FRM_1BPP	(0<<25)
+#define LCD_WINCTRL1_FRM_2BPP	(1<<25)
+#define LCD_WINCTRL1_FRM_4BPP	(2<<25)
+#define LCD_WINCTRL1_FRM_8BPP	(3<<25)
+#define LCD_WINCTRL1_FRM_12BPP	(4<<25)
+#define LCD_WINCTRL1_FRM_16BPP655	(5<<25)
+#define LCD_WINCTRL1_FRM_16BPP565	(6<<25)
+#define LCD_WINCTRL1_FRM_16BPP556	(7<<25)
+#define LCD_WINCTRL1_FRM_16BPPI1555	(8<<25)
+#define LCD_WINCTRL1_FRM_16BPPI5551	(9<<25)
+#define LCD_WINCTRL1_FRM_16BPPA1555	(10<<25)
+#define LCD_WINCTRL1_FRM_16BPPA5551	(11<<25)
+#define LCD_WINCTRL1_FRM_24BPP		(12<<25)
+#define LCD_WINCTRL1_FRM_32BPP		(13<<25)
+#define LCD_WINCTRL1_PRI_N(N)	((N)<<30)
+#define LCD_WINCTRL1_PO_00		(0<<22)
+#define LCD_WINCTRL1_PO_01		(1<<22)
+#define LCD_WINCTRL1_PO_10		(2<<22)
+#define LCD_WINCTRL1_PO_11		(3<<22)
+#define LCD_WINCTRL1_SZX_N(N)	((N-1)<<11)
+#define LCD_WINCTRL1_SZY_N(N)	((N-1)<<0)
+
+/* lcd windows control 2 */
+#define LCD_WINCTRL2_CKMODE		(3<<24)
+#define LCD_WINCTRL2_DBM		(1<<23)
+#define LCD_WINCTRL2_RAM		(3<<21)
+#define LCD_WINCTRL2_BX			(0x1FFF<<8)
+#define LCD_WINCTRL2_SCX		(0xF<<4)
+#define LCD_WINCTRL2_SCY		(0xF<<0)
+#define LCD_WINCTRL2_CKMODE_00		(0<<24)
+#define LCD_WINCTRL2_CKMODE_01		(1<<24)
+#define LCD_WINCTRL2_CKMODE_10		(2<<24)
+#define LCD_WINCTRL2_CKMODE_11		(3<<24)
+#define LCD_WINCTRL2_RAM_NONE		(0<<21)
+#define LCD_WINCTRL2_RAM_PALETTE	(1<<21)
+#define LCD_WINCTRL2_RAM_GAMMA		(2<<21)
+#define LCD_WINCTRL2_RAM_BUFFER		(3<<21)
+#define LCD_WINCTRL2_BX_N(N)	((N)<<8)
+#define LCD_WINCTRL2_SCX_1		(0<<4)
+#define LCD_WINCTRL2_SCX_2		(1<<4)
+#define LCD_WINCTRL2_SCX_4		(2<<4)
+#define LCD_WINCTRL2_SCY_1		(0<<0)
+#define LCD_WINCTRL2_SCY_2		(1<<0)
+#define LCD_WINCTRL2_SCY_4		(2<<0)
+
+/* lcd windows buffer control */
+#define LCD_WINBUFCTRL_DB		(1<<1)
+#define LCD_WINBUFCTRL_DBN		(1<<0)
+
+/* lcd_intstatus, lcd_intenable */
+#define LCD_INT_IFO				(0xF<<14)
+#define LCD_INT_IFU				(0xF<<10)
+#define LCD_INT_OFO				(1<<9)
+#define LCD_INT_OFU				(1<<8)
+#define LCD_INT_WAIT			(1<<3)
+#define LCD_INT_SD				(1<<2)
+#define LCD_INT_SA				(1<<1)
+#define LCD_INT_SS				(1<<0)
+
+/* lcd_horztiming */
+#define LCD_HORZTIMING_HND2		(0x1FF<<18)
+#define LCD_HORZTIMING_HND1		(0x1FF<<9)
+#define LCD_HORZTIMING_HPW		(0x1FF<<0)
+#define LCD_HORZTIMING_HND2_N(N)(((N)-1)<<18)
+#define LCD_HORZTIMING_HND1_N(N)(((N)-1)<<9)
+#define LCD_HORZTIMING_HPW_N(N)	(((N)-1)<<0)
+
+/* lcd_verttiming */
+#define LCD_VERTTIMING_VND2		(0x1FF<<18)
+#define LCD_VERTTIMING_VND1		(0x1FF<<9)
+#define LCD_VERTTIMING_VPW		(0x1FF<<0)
+#define LCD_VERTTIMING_VND2_N(N)(((N)-1)<<18)
+#define LCD_VERTTIMING_VND1_N(N)(((N)-1)<<9)
+#define LCD_VERTTIMING_VPW_N(N)	(((N)-1)<<0)
+
+/* lcd_clkcontrol */
+#define LCD_CLKCONTROL_EXT		(1<<22)
+#define LCD_CLKCONTROL_DELAY	(3<<20)
+#define LCD_CLKCONTROL_CDD		(1<<19)
+#define LCD_CLKCONTROL_IB		(1<<18)
+#define LCD_CLKCONTROL_IC		(1<<17)
+#define LCD_CLKCONTROL_IH		(1<<16)
+#define LCD_CLKCONTROL_IV		(1<<15)
+#define LCD_CLKCONTROL_BF		(0x1F<<10)
+#define LCD_CLKCONTROL_PCD		(0x3FF<<0)
+#define LCD_CLKCONTROL_BF_N(N)	(((N)-1)<<10)
+#define LCD_CLKCONTROL_PCD_N(N)	((N)<<0)
+
+/* lcd_pwmdiv */
+#define LCD_PWMDIV_EN			(1<<31)
+#define LCD_PWMDIV_PWMDIV		(0x1FFFF<<0)
+#define LCD_PWMDIV_PWMDIV_N(N)	((N)<<0)
+
+/* lcd_pwmhi */
+#define LCD_PWMHI_PWMHI1		(0xFFFF<<16)
+#define LCD_PWMHI_PWMHI0		(0xFFFF<<0)
+#define LCD_PWMHI_PWMHI1_N(N)	((N)<<16)
+#define LCD_PWMHI_PWMHI0_N(N)	((N)<<0)
+
+/* lcd_hwccon */
+#define LCD_HWCCON_EN			(1<<0)
+
+/* lcd_cursorpos */
+#define LCD_CURSORPOS_HWCXOFF		(0x1F<<27)
+#define LCD_CURSORPOS_HWCXPOS		(0x07FF<<16)
+#define LCD_CURSORPOS_HWCYOFF		(0x1F<<11)
+#define LCD_CURSORPOS_HWCYPOS		(0x07FF<<0)
+#define LCD_CURSORPOS_HWCXOFF_N(N)	((N)<<27)
+#define LCD_CURSORPOS_HWCXPOS_N(N)	((N)<<16)
+#define LCD_CURSORPOS_HWCYOFF_N(N)	((N)<<11)
+#define LCD_CURSORPOS_HWCYPOS_N(N)	((N)<<0)
+
+/* lcd_cursorcolor */
+#define LCD_CURSORCOLOR_HWCA		(0xFF<<24)
+#define LCD_CURSORCOLOR_HWCR		(0xFF<<16)
+#define LCD_CURSORCOLOR_HWCG		(0xFF<<8)
+#define LCD_CURSORCOLOR_HWCB		(0xFF<<0)
+#define LCD_CURSORCOLOR_HWCA_N(N)	((N)<<24)
+#define LCD_CURSORCOLOR_HWCR_N(N)	((N)<<16)
+#define LCD_CURSORCOLOR_HWCG_N(N)	((N)<<8)
+#define LCD_CURSORCOLOR_HWCB_N(N)	((N)<<0)
+
+/* lcd_fifoctrl */
+#define LCD_FIFOCTRL_F3IF		(1<<29)
+#define LCD_FIFOCTRL_F3REQ		(0x1F<<24)
+#define LCD_FIFOCTRL_F2IF		(1<<29)
+#define LCD_FIFOCTRL_F2REQ		(0x1F<<16)
+#define LCD_FIFOCTRL_F1IF		(1<<29)
+#define LCD_FIFOCTRL_F1REQ		(0x1F<<8)
+#define LCD_FIFOCTRL_F0IF		(1<<29)
+#define LCD_FIFOCTRL_F0REQ		(0x1F<<0)
+#define LCD_FIFOCTRL_F3REQ_N(N)	((N-1)<<24)
+#define LCD_FIFOCTRL_F2REQ_N(N)	((N-1)<<16)
+#define LCD_FIFOCTRL_F1REQ_N(N)	((N-1)<<8)
+#define LCD_FIFOCTRL_F0REQ_N(N)	((N-1)<<0)
+
+/* lcd_outmask */
+#define LCD_OUTMASK_MASK		(0x00FFFFFF)
+
+/********************************************************************/
+#endif /* _AU1200LCD_H */



-------------------------------------------------------
This SF.Net email is sponsored by xPML, a groundbreaking scripting language
that extends applications into web and mobile media. Attend the live webcast
and join the prime developer group breaking into this new coding territory!
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=110944&bid=241720&dat=121642

                 reply	other threads:[~2006-02-24 18:45 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=43FDA56D.30902@gmail.com \
    --to=adaplas@gmail.com \
    --cc=akpm@osdl.org \
    --cc=linux-fbdev-devel@lists.sourceforge.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.