[PATCH 1/3] platform-device driver for MQ11xx graphics chip

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch adds platform_device driver for MQ11xx system-on-chip
graphics chip.  This chip is used in several non-PCI ARM and MIPS
platforms such as the iPAQ H5550.  Two subsequent patches add
support for the framebuffer and USB gadget subdevices.  This patch
adds the toplevel driver to drivers/platform because it does not
provide any specific functionality (e.g., framebuffer) and it not tied
to a named physical bus.  In these platforms, the MQ11xx is tied
directly to the host bus.


Signed-off-by: Jamey Hicks <[email protected]>
Signed-off-by: Andrew Zabolotny <[email protected]>

---
commit d1144b4da9a00634c14dfed3a56f8491749b9f01
tree 66014fccdb508b698e326bbf8158d40161a39226
parent 5f367e62a65136321593c193391a186f56f81b93
author <[email protected]> Tue, 02 Aug 2005 11:24:55 -0400
committer <[email protected]> Tue, 02 Aug 2005 11:24:55 -0400

 arch/arm/Kconfig                               |    2 
 drivers/Kconfig                                |    2 
 drivers/Makefile                               |    2 
 drivers/platform/.tmp_versions/mq11xx_base.mod |    2 
 drivers/platform/Kconfig                       |   23 
 drivers/platform/Makefile                      |    5 
 drivers/platform/mq11xx.h                      |  925 ++++++++++++++++
 drivers/platform/mq11xx_base.c                 | 1390 ++++++++++++++++++++++++
 8 files changed, 2350 insertions(+), 1 deletions(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -764,6 +764,8 @@ source "drivers/usb/Kconfig"
 
 source "drivers/mmc/Kconfig"
 
+source "drivers/platform/Kconfig"
+
 endmenu
 
 source "fs/Kconfig"
diff --git a/drivers/Kconfig b/drivers/Kconfig
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -58,6 +58,8 @@ source "drivers/usb/Kconfig"
 
 source "drivers/mmc/Kconfig"
 
+source "drivers/platform/Kconfig"
+
 source "drivers/infiniband/Kconfig"
 
 source "drivers/sn/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -7,7 +7,7 @@
 
 obj-$(CONFIG_PCI)		+= pci/
 obj-$(CONFIG_PARISC)		+= parisc/
-obj-y				+= video/
+obj-y				+= video/ platform/
 obj-$(CONFIG_ACPI_BOOT)		+= acpi/
 # PnP must come after ACPI since it will eventually need to check if acpi
 # was used and do nothing if so
diff --git a/drivers/platform/.tmp_versions/mq11xx_base.mod b/drivers/platform/.tmp_versions/mq11xx_base.mod
new file mode 100644
--- /dev/null
+++ b/drivers/platform/.tmp_versions/mq11xx_base.mod
@@ -0,0 +1,2 @@
+drivers/platform/mq11xx_base.ko
+drivers/platform/mq11xx_base.o
diff --git a/drivers/platform/Kconfig b/drivers/platform/Kconfig
new file mode 100644
--- /dev/null
+++ b/drivers/platform/Kconfig
@@ -0,0 +1,23 @@
+#
+# Platform devices
+#
+
+menu "Platform devices"
+
+config PLATFORM_MQ11XX
+	tristate "MediaQ 1100/32/68/78/88 SoC support"
+	---help---
+	  MediaQ 1100/32/68/78/88 are system-on-chips that implement a
+	  graphics engine, flat panel controller, USB function controller,
+	  OHCI-compliant USB host controller (1132 only), I2S and SPI
+	  controllers (also 1132 only).
+
+	  This driver implements only the basic support for MediaQ chips;
+	  after you select this option the subdevice drivers will appear
+	  in the respective submenus: MediaQ 1100/32/68/78/88 framebuffer
+	  support, Dell Axim X5 LCD support and so on.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called mq11xx_base.o.
+
+endmenu
diff --git a/drivers/platform/Makefile b/drivers/platform/Makefile
new file mode 100644
--- /dev/null
+++ b/drivers/platform/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for platform device drivers.
+#
+
+obj-$(CONFIG_PLATFORM_MQ11XX)        += mq11xx_base.o
diff --git a/drivers/platform/mq11xx.h b/drivers/platform/mq11xx.h
new file mode 100644
--- /dev/null
+++ b/drivers/platform/mq11xx.h
@@ -0,0 +1,925 @@
+/*
+ * drivers/misc/soc/mq11xx.h
+ *
+ * Copyright (C) 2003 Andrew Zabolotny <[email protected]>
+ * Portions copyright (C) 2003 Keith Packard
+ *
+ * This file contains some definitions for the MediaQ 1100/1132.
+ * These definitions are made public because drivers for
+ * MediaQ subdevices need them.
+ */
+
+#ifndef _PLATFORM_MEDIAQ11XX
+#define _PLATFORM_MEDIAQ11XX
+
+#define MQ11xx_REG_SIZE		(8*1024)
+#define MQ11xx_FB_SIZE		(256*1024)
+#define MQ11xx_NUMIRQS		20
+
+/* MediaQ 1100/1132/1168/1178/1188 subdevices */
+#define MEDIAQ_11XX_FB_DEVICE_ID	0x00000301
+#define MEDIAQ_11XX_FP_DEVICE_ID	0x00000302
+#define MEDIAQ_11XX_UDC_DEVICE_ID	0x00000303
+#define MEDIAQ_11XX_UHC_DEVICE_ID	0x00000304
+#define MEDIAQ_11XX_SPI_DEVICE_ID	0x00000305
+#define MEDIAQ_11XX_I2S_DEVICE_ID	0x00000306
+
+/* Interrupt handling for the MediaQ chip is quite tricky.
+ * The chip has 20 internal interrupt sources (numbered from 0 to 19,
+ * see the constants below) which are demultiplexed to a single output
+ * pin which is usually connected to a single IRQ on the mainboard.
+ * Thus the driver has to multiplex it somehow again into twenty
+ * different IRQs.
+ *
+ * Unfortunately, the mechanisms required for this are missing (as of today)
+ * on all platforms except ARM. Let's hope one day they will be supported on
+ * all platforms; for now no platforms except ARM supports MediaQ interrupts.
+ *
+ * The following contants are IRQ offsets relative to the base IRQ number
+ * (driver allocates a range of IRQs).
+ */
+
+#if defined CONFIG_ARM
+#  define MQ_IRQ_MULTIPLEX
+#endif
+
+#define IRQ_MQ_VSYNC_RISING			0
+#define IRQ_MQ_VSYNC_FALLING			1
+#define IRQ_MQ_VENABLE_RISING			2
+#define IRQ_MQ_VENABLE_FALLING			3
+#define IRQ_MQ_BUS_CYCLE_ABORT			4
+#define IRQ_MQ_GPIO_0				5
+#define IRQ_MQ_GPIO_1				6
+#define IRQ_MQ_GPIO_2				7
+#define IRQ_MQ_COMMAND_FIFO_HALF_EMPTY    	8
+#define IRQ_MQ_COMMAND_FIFO_EMPTY		9
+#define IRQ_MQ_SOURCE_FIFO_HALF_EMPTY		10
+#define IRQ_MQ_SOURCE_FIFO_EMPTY		11
+#define IRQ_MQ_GRAPHICS_ENGINE_IDLE		12
+#define IRQ_MQ_UHC_GLOBAL_SUSPEND_MODE		13
+#define IRQ_MQ_UHC_REMOTE_WAKE_UP		14
+#define IRQ_MQ_UHC				15
+#define IRQ_MQ_UDC				16
+#define IRQ_MQ_I2S				17
+#define IRQ_MQ_SPI				18
+#define IRQ_MQ_UDC_WAKE_UP			19
+
+/* This union uses unnamed structs. This is a gcc extension, but what the
+ * hell, the kernel is not compilable by anything else anyway...
+ */
+struct mediaq11xx_regs {
+	/*
+	 * CPU Interface (CC) Module	    0x000
+	 */
+	union {
+		struct {
+			u32 cpu_control;
+#define MQ_CPU_CONTROL_MIU_READ_REQUEST_GENERATOR_ON	(1 << 0)
+#define MQ_CPU_CONTROL_DISBABLE_FB_READ_CACHE		(1 << 1)
+#define MQ_CPU_CONTROL_ENABLE_CLKRUN			(1 << 3)
+#define MQ_CPU_CONTROL_GPIO_SOURCE_DATA_SELECT		(3 << 4)
+#define MQ_CPU_CONTROL_CPU_INTERFACE_GPIO_DATA		(3 << 6)
+			u32 fifo_status;
+#define MQ_CPU_COMMAND_FIFO(s)				(((s) >> 0) & 0x1f)
+#define MQ_CPU_SOURCE_FIFO(s)				(((s) >> 8) & 0x1f)
+#define MQ_CPU_GE_BUSY					(1 << 16)
+			u32 gpio_control_0;
+			u32 gpio_control_1;
+			u32 cpu_test_mode;
+		};
+		u32 a[6];
+		u8 size[128];
+	} CC;
+	/*
+	 * Memory Interface Unit Controller    0x080
+	 */
+	union {
+		struct {
+			u32	miu_0;
+#define MQ_MIU_ENABLE					(1 << 0)
+#define MQ_MIU_RESET_ENABLE				(1 << 1)
+			u32	miu_1;
+#define MQ_MIU_MEMORY_CLOCK_SOURCE_BUS			(1 << 0)
+#define MQ_MIU_MEMORY_CLOCK_DIVIDER			(7 << 2)
+#define MQ_MIU_MEMORY_CLOCK_DIVIDER_1			(0 << 2)
+#define MQ_MIU_MEMORY_CLOCK_DIVIDER_1_5			(1 << 2)
+#define MQ_MIU_MEMORY_CLOCK_DIVIDER_2			(2 << 2)
+#define MQ_MIU_MEMORY_CLOCK_DIVIDER_2_5			(3 << 2)
+#define MQ_MIU_MEMORY_CLOCK_DIVIDER_3			(4 << 2)
+#define MQ_MIU_MEMORY_CLOCK_DIVIDER_4			(5 << 2)
+#define MQ_MIU_MEMORY_CLOCK_DIVIDER_5			(6 << 2)
+#define MQ_MIU_MEMORY_CLOCK_DIVIDER_6			(7 << 2)
+#define MQ_MIU_DISPLAY_BURST_MASK			(3 << 5)
+#define MQ_MIU_DISPLAY_BURST_COUNT_2			(0 << 5)
+#define MQ_MIU_DISPLAY_BURST_COUNT_4			(1 << 5)
+#define MQ_MIU_DISPLAY_BURST_COUNT_6			(2 << 5)
+#define MQ_MIU_DISPLAY_BURST_COUNT_8			(3 << 5)
+#define MQ_MIU_GRAPHICS_ENGINE_BURST_MASK	    	(3 << 7)
+#define MQ_MIU_GRAPHICS_ENGINE_BURST_COUNT_2	    	(0 << 7)
+#define MQ_MIU_GRAPHICS_ENGINE_BURST_COUNT_4	    	(1 << 7)
+#define MQ_MIU_GRAPHICS_ENGINE_BURST_COUNT_6	    	(2 << 7)
+#define MQ_MIU_GRAPHICS_ENGINE_BURST_COUNT_8	    	(3 << 7)
+#define MQ_MIU_CPU_BURST_MASK				(3 << 9)
+#define MQ_MIU_CPU_BURST_COUNT_2	    		(0 << 9)
+#define MQ_MIU_CPU_BURST_COUNT_4	    		(1 << 9)
+#define MQ_MIU_CPU_BURST_COUNT_6	    		(2 << 9)
+#define MQ_MIU_CPU_BURST_COUNT_8	    		(3 << 9)
+#define MQ_MIU_I2S_BURST_MASK				(3 << 11)
+#define MQ_MIU_I2S_BURST_COUNT_2    			(0 << 11)
+#define MQ_MIU_I2S_BURST_COUNT_4    			(1 << 11)
+#define MQ_MIU_I2S_BURST_COUNT_6    			(2 << 11)
+#define MQ_MIU_I2S_BURST_COUNT_8    			(3 << 11)
+#define MQ_MIU_UDC_BURST_MASK				(3 << 13)
+#define MQ_MIU_UDC_BURST_COUNT_2    			(0 << 13)
+#define MQ_MIU_UDC_BURST_COUNT_4    			(1 << 13)
+#define MQ_MIU_UDC_BURST_COUNT_6    			(2 << 13)
+#define MQ_MIU_UDC_BURST_COUNT_8    			(3 << 13)
+#define MQ_MIU_GCI_FIFO_THRESHOLD			(0xf << 16)
+#define MQ_MIU_GCI_FIFO_THRESHOLD_(v)			((v) << 16)
+#define MQ_MIU_GRAPHICS_ENGINE_SRC_READ_THRESHOLD	(7 << 20)
+#define MQ_MIU_GRAPHICS_ENGINE_SRC_READ_THRESHOLD_(v)	((v) << 20)
+#define MQ_MIU_GRAPHICS_ENGINE_DST_READ_THRESHOLD	(7 << 23)
+#define MQ_MIU_GRAPHICS_ENGINE_DST_READ_THRESHOLD_(v)	((v) << 23)
+#define MQ_MIU_I2S_TRANSMIT_THRESHOLD			(7 << 26)
+#define MQ_MIU_I2S_TRANSMIT_THRESHOLD_(v)    		((v) << 26)
+			u32	miu_test_control;
+			u32	mq1178_unknown1;
+			u32	mq1178_unknown2;
+		};
+		u32 a[8];
+		u8 size[128];
+	} MIU;
+	/*
+	 * Interrupt Controller	    0x100
+	 */
+	union {
+		struct {
+			u32 control;
+#define MQ_INTERRUPT_CONTROL_INTERRUPT_ENABLE		(1 << 0)
+#define MQ_INTERRUPT_CONTROL_INTERRUPT_POLARITY		(1 << 1)
+#define MQ_INTERRUPT_CONTROL_GPIO_0_INTERRUPT_POLARITY	(1 << 2)
+#define MQ_INTERRUPT_CONTROL_GPIO_1_INTERRUPT_POLARITY	(1 << 3)
+#define MQ_INTERRUPT_CONTROL_GPIO_2_INTERRUPT_POLARITY	(1 << 4)
+			u32 interrupt_mask;
+#define MQ_INTERRUPT_MASK_VSYNC_RISING			(1 << 0)
+#define MQ_INTERRUPT_MASK_VSYNC_FALLING			(1 << 1)
+#define MQ_INTERRUPT_MASK_VENABLE_RISING		(1 << 2)
+#define MQ_INTERRUPT_MASK_VENABLE_FALLING		(1 << 3)
+#define MQ_INTERRUPT_MASK_BUS_CYCLE_ABORT		(1 << 4)
+#define MQ_INTERRUPT_MASK_GPIO_0			(1 << 5)
+#define MQ_INTERRUPT_MASK_GPIO_1			(1 << 6)
+#define MQ_INTERRUPT_MASK_GPIO_2			(1 << 7)
+#define MQ_INTERRUPT_MASK_COMMAND_FIFO_HALF_EMPTY    	(1 << 8)
+#define MQ_INTERRUPT_MASK_COMMAND_FIFO_EMPTY		(1 << 9)
+#define MQ_INTERRUPT_MASK_SOURCE_FIFO_HALF_EMPTY	(1 << 10)
+#define MQ_INTERRUPT_MASK_SOURCE_FIFO_EMPTY		(1 << 11)
+#define MQ_INTERRUPT_MASK_GRAPHICS_ENGINE_IDLE		(1 << 12)
+#define MQ_INTERRUPT_MASK_UHC_GLOBAL_SUSPEND_MODE	(1 << 13)
+#define MQ_INTERRUPT_MASK_UHC_REMOTE_WAKE_UP    	(1 << 14)
+#define MQ_INTERRUPT_MASK_UHC				(1 << 15)
+#define MQ_INTERRUPT_MASK_UDC				(1 << 16)
+#define MQ_INTERRUPT_MASK_I2S				(1 << 17)
+#define MQ_INTERRUPT_MASK_SPI				(1 << 18)
+#define MQ_INTERRUPT_MASK_UDC_WAKE_UP			(1 << 19)
+			u32 interrupt_status;
+#define MQ_INTERRUPT_STATUS_VSYNC_RISING		(1 << 0)
+#define MQ_INTERRUPT_STATUS_VSYNC_FALLING		(1 << 1)
+#define MQ_INTERRUPT_STATUS_VENABLE_RISING		(1 << 2)
+#define MQ_INTERRUPT_STATUS_VENABLE_FALLING		(1 << 3)
+#define MQ_INTERRUPT_STATUS_BUS_CYCLE_ABORT		(1 << 4)
+#define MQ_INTERRUPT_STATUS_GPIO_0			(1 << 5)
+#define MQ_INTERRUPT_STATUS_GPIO_1			(1 << 6)
+#define MQ_INTERRUPT_STATUS_GPIO_2			(1 << 7)
+#define MQ_INTERRUPT_STATUS_COMMAND_FIFO_HALF_EMPTY    	(1 << 8)
+#define MQ_INTERRUPT_STATUS_COMMAND_FIFO_EMPTY		(1 << 9)
+#define MQ_INTERRUPT_STATUS_SOURCE_FIFO_HALF_EMPTY	(1 << 10)
+#define MQ_INTERRUPT_STATUS_SOURCE_FIFO_EMPTY		(1 << 11)
+#define MQ_INTERRUPT_STATUS_GRAPHICS_ENGINE_IDLE	(1 << 12)
+#define MQ_INTERRUPT_STATUS_UHC_GLOBAL_SUSPEND_MODE	(1 << 13)
+#define MQ_INTERRUPT_STATUS_UHC_REMOTE_WAKE_UP    	(1 << 14)
+#define MQ_INTERRUPT_STATUS_UHC				(1 << 15)
+#define MQ_INTERRUPT_STATUS_UDC				(1 << 16)
+#define MQ_INTERRUPT_STATUS_I2S				(1 << 17)
+#define MQ_INTERRUPT_STATUS_SPI				(1 << 18)
+#define MQ_INTERRUPT_STATUS_UDC_WAKE_UP			(1 << 19)
+			u32 interrupt_raw_status;
+#define MQ_INTERRUPT_RAWSTATUS_VSYNC			(1 << 0)
+#define MQ_INTERRUPT_RAWSTATUS_VENABLE			(1 << 1)
+#define MQ_INTERRUPT_RAWSTATUS_SCC			(1 << 2)
+#define MQ_INTERRUPT_RAWSTATUS_SPI			(1 << 3)
+#define MQ_INTERRUPT_RAWSTATUS_GPIO_0			(1 << 4)
+#define MQ_INTERRUPT_RAWSTATUS_GPIO_1			(1 << 5)
+#define MQ_INTERRUPT_RAWSTATUS_GPIO_2			(1 << 6)
+#define MQ_INTERRUPT_RAWSTATUS_GRAPHICS_ENGINE_BUSY	(1 << 8)
+#define MQ_INTERRUPT_RAWSTATUS_SOURCE_FIFO_EMPTY	(1 << 9)
+#define MQ_INTERRUPT_RAWSTATUS_SOURCE_FIFO_HALF_EMPTY	(1 << 10)
+#define MQ_INTERRUPT_RAWSTATUS_COMMAND_FIFO_EMPTY	(1 << 11)
+#define MQ_INTERRUPT_RAWSTATUS_COMMAND_FIFO_HALF_EMPTY	(1 << 12)
+#define MQ_INTERRUPT_RAWSTATUS_UHC			(1 << 13)
+#define MQ_INTERRUPT_RAWSTATUS_UHC_GLOBAL_SUSPEND	(1 << 14)
+#define MQ_INTERRUPT_RAWSTATUS_UHC_REMOTE_WAKE_UP	(1 << 15)
+#define MQ_INTERRUPT_RAWSTATUS_UDC			(1 << 16)
+#define MQ_INTERRUPT_RAWSTATUS_UDC_WAKE_UP		(1 << 17)
+		};
+		u32 a[4];
+		u8 size[128];
+	} IC;
+	/*
+	 * Graphics Controller	    0x180
+	 */
+	union {
+		struct {
+			u32 control;
+#define MQ_GC_CONTROL_ENABLE				(1 << 0)
+#define MQ_GC_HORIZONTAL_COUNTER_RESET			(1 << 1)
+#define MQ_GC_VERTICAL_COUNTER_RESET			(1 << 2)
+#define MQ_GC_IMAGE_WINDOW_ENABLE			(1 << 3)
+#define MQ_GC_DEPTH					(0xf << 4)
+#define MQ_GC_DEPTH_PSEUDO_1				(0x0 << 4)
+#define MQ_GC_DEPTH_PSEUDO_2				(0x1 << 4)
+#define MQ_GC_DEPTH_PSEUDO_4				(0x2 << 4)
+#define MQ_GC_DEPTH_PSEUDO_8				(0x3 << 4)
+#define MQ_GC_DEPTH_GRAY_1				(0x8 << 4)
+#define MQ_GC_DEPTH_GRAY_2				(0x9 << 4)
+#define MQ_GC_DEPTH_GRAY_4				(0xa << 4)
+#define MQ_GC_DEPTH_GRAY_8				(0xb << 4)
+#define MQ_GC_DEPTH_TRUE_16				(0xc << 4)
+#define MQ_GC_HARDWARE_CURSOR_ENABLE			(1 << 8)
+#define MQ_GC_DOUBLE_BUFFER_CONTROL			(3 << 10)
+#define MQ_GC_X_SCANNING_DIRECTION			(1 << 12)
+#define MQ_GC_LINE_SCANNING_DIRECTION			(1 << 13)
+#define MQ_GC_HORIZONTAL_DOUBLING			(1 << 14)
+#define MQ_GC_VERTICAL_DOUBLING				(1 << 15)
+#define MQ_GC_GRCLK_SOURCE				(3 << 16)
+#define MQ_GC_GRCLK_SOURCE_BUS				(0 << 16)
+#define MQ_GC_GRCLK_SOURCE_FIRST    			(1 << 16)
+#define MQ_GC_GRCLK_SOURCE_SECON    			(2 << 16)
+#define MQ_GC_GRCLK_SOURCE_THIRD    			(3 << 16)
+#define MQ_GC_ENABLE_TEST_MODE				(1 << 18)
+#define MQ_GC_ENABLE_POLY_SI_TFT			(1 << 19)
+#define MQ_GC_GMCLK_FIRST_DIVISOR			(7 << 20)
+#define MQ_GC_GMCLK_FIRST_DIVISOR_1			(0 << 20)
+#define MQ_GC_GMCLK_FIRST_DIVISOR_1_5			(1 << 20)
+#define MQ_GC_GMCLK_FIRST_DIVISOR_2_5			(2 << 20)
+#define MQ_GC_GMCLK_FIRST_DIVISOR_3_5			(3 << 20)
+#define MQ_GC_GMCLK_FIRST_DIVISOR_4_5			(4 << 20)
+#define MQ_GC_GMCLK_FIRST_DIVISOR_5_5			(5 << 20)
+#define MQ_GC_GMCLK_FIRST_DIVISOR_6_5			(6 << 20)
+#define MQ_GC_GMCLK_SECOND_DIVISOR			(0xf << 24)
+#define MQ_GC_GMCLK_SECOND_DIVISOR_(v)			((v) << 24)
+#define MQ_GC_SHARP_160x160_HR_TFT_ENABLE    		(1 << 31)
+			u32 power_sequencing;
+#define MQ_GC_POWER_UP_INTERVAL				(7 << 0)
+#define MQ_GC_POWER_UP_INTERVAL_1	    		(0 << 0)
+#define MQ_GC_POWER_UP_INTERVAL_2	    		(1 << 0)
+#define MQ_GC_POWER_UP_INTERVAL_4	    		(2 << 0)
+#define MQ_GC_POWER_UP_INTERVAL_8	    		(3 << 0)
+#define MQ_GC_POWER_UP_INTERVAL_16    			(4 << 0)
+#define MQ_GC_POWER_UP_INTERVAL_32    			(5 << 0)
+#define MQ_GC_POWER_UP_INTERVAL_48    			(6 << 0)
+#define MQ_GC_POWER_UP_INTERVAL_64    			(7 << 0)
+#define MQ_GC_FAST_POWER_UP				(1 << 3)
+#define MQ_GC_POWER_DOWN_INTERVAL			(1 << 4)
+#define MQ_GC_POWER_DOWN_INTERVAL_1	    		(0 << 4)
+#define MQ_GC_POWER_DOWN_INTERVAL_2	    		(1 << 4)
+#define MQ_GC_POWER_DOWN_INTERVAL_4	    		(2 << 4)
+#define MQ_GC_POWER_DOWN_INTERVAL_8	    		(3 << 4)
+#define MQ_GC_POWER_DOWN_INTERVAL_16    		(4 << 4)
+#define MQ_GC_POWER_DOWN_INTERVAL_32    		(5 << 4)
+#define MQ_GC_POWER_DOWN_INTERVAL_48    		(6 << 4)
+#define MQ_GC_POWER_DOWN_INTERVAL_64    		(7 << 4)
+#define MQ_GC_FAST_POWER_DOWN				(1 << 7)
+			u32 horizontal_display;
+#define MQ_GC_HORIZONTAL_DISPLAY_TOTAL			(0x7ff << 0)
+#define MQ_GC_HORIZONTAL_DISPLAY_TOTAL_(s)    		((s) << 0)
+#define MQ_GC_HORIZONTAL_DISPLAY_END			(0x7ff << 16)
+#define MQ_GC_HORIZONTAL_DISPLAY_END_(s)    		((s) << 16)
+			u32 vertical_display;
+#define MQ_GC_VERTICAL_DISPLAY_TOTAL			(0x3ff << 0)
+#define MQ_GC_VERTICAL_DISPLAY_TOTAL_(s)		((s) << 0)
+#define MQ_GC_VERTICAL_DISPLAY_END			(0x3ff << 16)
+#define MQ_GC_VERTICAL_DISPLAY_END_(s)			((s) << 16)
+			u32 horizontal_sync;
+#define MQ_GC_HORIZONTAL_SYNC_START			(0x7ff << 0)
+#define MQ_GC_HORIZONTAL_SYNC_START_(s)			((s) << 0)
+#define MQ_GC_HORIZONTAL_SYNC_END			(0x7ff << 16)
+#define MQ_GC_HORIZONTAL_SYNC_END_(s)			((s) << 16)
+			u32 vertical_sync;
+#define MQ_GC_VERTICAL_SYNC_START			(0x3ff << 0)
+#define MQ_GC_VERTICAL_SYNC_START_(s)			((s) << 0)
+#define MQ_GC_VERTICAL_SYNC_END				(0x3ff << 16)
+#define MQ_GC_VERTICAL_SYNC_END_(s)			((s) << 16)
+			u32 horizontal_counter_init;	/* set to 0 */
+			u32 vertical_counter_init;	/* set to 0 */
+			u32 horizontal_window;
+#define MQ_GC_HORIZONTAL_WINDOW_START			(0x7ff << 0)
+#define MQ_GC_HORIZONTAL_WINDOW_START_(s)		((s) << 0)
+#define MQ_GC_HORIZONTAL_WINDOW_WIDTH			(0x7ff << 16)
+#define MQ_GC_HORIZONTAL_WINDOW_WIDTH_(s)		((s) << 16)
+                        u32 vertical_window;
+#define MQ_GC_VERTICAL_WINDOW_START			(0x3ff << 0)
+#define MQ_GC_VERTICAL_WINDOW_START_(s)			((s) << 0)
+#define MQ_GC_VERTICAL_WINDOW_HEIGHT			(0x3ff << 16)
+#define MQ_GC_VERTICAL_WINDOW_HEIGHT_(s)		((s) << 16)
+			u32 reserved_28;
+			u32 line_clock;
+#define MQ_GC_LINE_CLOCK_START				(0x7ff << 0)
+#define MQ_GC_LINE_CLOCK_START_(s)			((s) << 0)
+#define MQ_GC_LINE_CLOCK_END				(0x7ff << 16)
+#define MQ_GC_LINE_CLOCK_END_(s)			((s) << 16)
+			u32 window_start_address;
+			u32 alternate_window_start_address;
+			u32 window_stride;
+			u32 reserved_3c;
+			u32 cursor_position;
+#define MQ_GC_HORIZONTAL_CURSOR_START			(0x7ff << 0)
+#define MQ_GC_HORIZONTAL_CURSOR_START_(s)		((s) << 0)
+#define MQ_GC_VERTICAL_CURSOR_START			(0x3ff << 16)
+#define MQ_GC_VERTICAL_CURSOR_START_(s)			((s) << 16)
+			u32 cursor_start_address;
+#define MQ_GC_CURSOR_START_ADDRESS			(0xff << 0)
+#define MQ_GC_CURSOR_START_ADDRESS_(s)			((s) << 0)
+#define MQ_GC_HORIZONTAL_CURSOR_OFFSET			(0x3f << 16)
+#define MQ_GC_HORIZONTAL_CURSOR_OFFSET_(s)		((s) << 16)
+#define MQ_GC_VERTICAL_CURSOR_OFFSET			(0x3f << 24)
+#define MQ_GC_VERTICAL_CURSOR_OFFSET_(s)		((s) << 24)
+			u32 cursor_foreground;
+			u32 cursor_background;
+			u32 reserved_50_64[6];
+			u32 frame_clock_control;
+#define MQ_GC_FRAME_CLOCK_START				(0x3ff << 0)
+#define MQ_GC_FRAME_CLOCK_START_(s)	    		((s) << 0)
+#define MQ_GC_FRAME_CLOCK_END				(0x3ff << 16)
+#define MQ_GC_FRAME_CLOCK_END_(s)	    		((s) << 16)
+			u32 misc_signals;
+			u32 horizonal_parameter;
+			u32 vertical_parameter;
+			u32 window_line_start_address;
+			u32 cursor_line_start_address;
+		};
+		u32 a[0x20];
+		u8 size[128];
+	} GC;
+	/*
+	 * Graphics Engine			0x200
+	 */
+	union {
+		u32 a[0x14];
+		u8 size[128];
+	} GE;
+	/*
+	 * Synchronous Serial Controller	0x280
+	 */
+	union {
+		u32 a[16];
+		u8 size[128];
+	} SSC;
+	/*
+	 * Serial Peripheral Interface		0x300
+	 */
+	union {
+		struct {
+			u32 control;
+			u32 status;
+			u32 data;
+			u32 time_gap;
+			u32 gpio_mode;
+                        u32 count;
+			u32 fifo_threshold;
+			u32 led_control;
+			u32 blue_gpio_mode;
+		};
+		u32 a[9];
+		u8 size[128];
+	} SPI;
+	/*
+	 * Device Configuration Space		0x380
+	 */
+	union {
+		struct {
+			u32 config_0;
+#define MQ_CONFIG_LITTLE_ENDIAN_ENABLE			(1 << 0)
+#define MQ_CONFIG_BYTE_SWAPPING				(1 << 1)
+			u32 config_1;
+#define MQ_CONFIG_18_OSCILLATOR				(3 << 0)
+#define MQ_CONFIG_18_OSCILLATOR_DISABLED    		(0 << 0)
+#define MQ_CONFIG_18_OSCILLATOR_OSCFO			(1 << 0)
+#define MQ_CONFIG_18_OSCILLATOR_INTERNAL    		(3 << 0)
+#define MQ_CONFIG_CPU_CLOCK_DIVISOR			(1 << 8)
+#define MQ_CONFIG_DTACK_CONTROL				(1 << 9)
+#define MQ_CONFIG_INTERFACE_SYNCHRONIZER_CONTROL    	(1 << 10)
+#define MQ_CONFIG_WRITE_DATA_LATCH    			(1 << 11)
+#define MQ_CONFIG_CPU_TEST_MODE				(1 << 12)
+#define MQ_CONFIG_SOFTWARE_CHIP_RESET			(1 << 16)
+#define MQ_CONFIG_WEAK_PULL_DOWN_FMOD			(1 << 28)
+#define MQ_CONFIG_WEAK_PULL_DOWN_FLCLK			(1 << 29)
+#define MQ_CONFIG_WEAK_PULL_DOWN_PWM0			(1 << 30)
+#define MQ_CONFIG_WEAK_PULL_DOWN_PWM1			(1 << 31)
+                        u32 config_2;
+#define MQ_CONFIG_CC_MODULE_ENABLE			(1 << 0)
+                        u32 config_3;
+#define MQ_CONFIG_BUS_INTERFACE_MODE			(0x7f << 0)
+#define MQ_CONFIG_BUS_INTERFACE_MODE_SH7750    		(0x01 << 0)
+#define MQ_CONFIG_BUS_INTERFACE_MODE_SH7709    		(0x02 << 0)
+#define MQ_CONFIG_BUS_INTERFACE_MODE_VR4111    		(0x04 << 0)
+#define MQ_CONFIG_BUS_INTERFACE_MODE_SA1110    		(0x08 << 0)
+#define MQ_CONFIG_BUS_INTERFACE_MODE_PCI    		(0x20 << 0)
+#define MQ_CONFIG_BUS_INTERFACE_MODE_DRAGONBALL_EZ    	(0x40 << 0)
+			u32 config_4;
+#define MQ_CONFIG_GE_FORCE_BUSY_GLOBAL			(1 << 0)
+#define MQ_CONFIG_GE_FORCE_BUSY_LOCAL			(1 << 1)
+#define MQ_CONFIG_GE_CLOCK_SELECT    			(1 << 2)
+#define MQ_CONFIG_GE_CLOCK_DIVIDER    			(7 << 3)
+#define MQ_CONFIG_GE_CLOCK_DIVIDER_1			(0 << 3)
+#define MQ_CONFIG_GE_CLOCK_DIVIDER_1_5			(1 << 3)
+#define MQ_CONFIG_GE_CLOCK_DIVIDER_2			(2 << 3)
+#define MQ_CONFIG_GE_CLOCK_DIVIDER_2_5			(3 << 3)
+#define MQ_CONFIG_GE_CLOCK_DIVIDER_3			(4 << 3)
+#define MQ_CONFIG_GE_CLOCK_DIVIDER_4			(5 << 3)
+#define MQ_CONFIG_GE_CLOCK_DIVIDER_5			(6 << 3)
+#define MQ_CONFIG_GE_CLOCK_DIVIDER_6			(7 << 3)
+#define MQ_CONFIG_GE_FIFO_RESET				(1 << 6)
+#define MQ_CONFIG_GE_SOURCE_FIFO_RESET			(1 << 7)
+#define MQ_CONFIG_USB_SE0_DETECT    			(1 << 8)
+#define MQ_CONFIG_UHC_DYNAMIC_POWER 	   		(1 << 9)
+#define MQ_CONFIG_USB_COUNTER_SCALE_ENABLE    		(1 << 10)
+#define MQ_CONFIG_UHC_READ_TEST_ENABLE    		(1 << 11)
+#define MQ_CONFIG_UHC_TEST_MODE_DATA    		(0xf << 12)
+#define MQ_CONFIG_UHC_TRANSCEIVER_TEST_ENABLE		(1 << 16)
+#define MQ_CONFIG_UHC_OVER_CURRENT_DETECT  	  	(1 << 17)
+#define MQ_CONFIG_UDC_DYNAMIC_POWER_ENABLE    		(1 << 18)
+#define MQ_CONFIG_UHC_TRANSCEIVER_ENABLE    		(1 << 19)
+#define MQ_CONFIG_UDC_TRANSCEIVER_ENABLE		(1 << 20)
+#define MQ_CONFIG_USB_TEST_VECTOR_GENERATION_ENABLE    	(1 << 21)
+			u32 config_5;
+#define MQ_CONFIG_GE_ENABLE				(1 << 0)
+#define MQ_CONFIG_UHC_CLOCK_ENABLE			(1 << 1)
+#define MQ_CONFIG_UDC_CLOCK_ENABLE   	 		(1 << 2)
+			u32 config_6;
+			u32 config_7;
+			u32 config_8;
+		};
+		u32 a[9];
+		u8 size[128];
+	} DC;
+	/*
+	 * PCI Configuration Header
+	 */
+	union {
+		/* little endian */
+		struct {
+			u16 vendor_id;
+#define MQ_PCI_VENDORID					0x4d51
+                        u16 device_id;
+// This is a wild guess
+#define MQ_PCI_DEVICEID_1100				0x0100
+#define MQ_PCI_DEVICEID_1132				0x0120
+// No confirmation of this IDs yet
+#define MQ_PCI_DEVICEID_1168				0x0168
+// No confirmation of this IDs yet
+#define MQ_PCI_DEVICEID_1178				0x0178
+#define MQ_PCI_DEVICEID_1188				0x0188
+			u16 command;
+			u16 status;
+			u32 revision_class;
+			u8 cache_line_size;
+			u8 latency_timer;
+			u8 header_type;
+			u8 BIST;
+			u32 bar0;
+			u32 bar1;
+			u32 pad0[4];
+			u32 cardbus_cis;
+			u16 subsystem_vendor_id;
+			u16 subsystem_id;
+			u32 expansion_rom;
+			u8 cap_ptr;
+			u8 pad1[3];
+			u8 interrupt_line;
+			u8 interrupt_pin;
+			u8 min_gnt;
+			u8 max_lat;
+			u8 capability_id;
+			u8 next_item_ptr;
+			u16 power_management_capabilities;
+			u16 power_management_control_status;
+			u8 PMCSR_BSE_bridge;
+			u8 data;
+		};
+		u8 size[256];
+	} PCI;
+	/*
+	 * USB Host Controller (0x500)
+	 */
+	union {
+		u32 a[23];
+		u8 size[256];
+	} UHC;
+	/*
+	 * Flat Panel Controller (0x600)
+	 */
+	union {
+		struct {
+			u32 control;
+#define MQ_FP_PANEL_TYPE				(0xf << 0)
+#define MQ_FP_PANEL_TYPE_TFT				(0x0 << 0)
+#define MQ_FP_PANEL_TYPE_STN				(0x4 << 0)
+#define MQ_FP_MONOCHROME_SELECT				(1 << 4)
+#define MQ_FP_FLAT_PANEL_INTERFACE    			(7 << 5)
+#define MQ_FP_FLAT_PANEL_INTERFACE_4_BIT    		(0 << 5)
+#define MQ_FP_FLAT_PANEL_INTERFACE_6_BIT    		(1 << 5)
+#define MQ_FP_FLAT_PANEL_INTERFACE_8_BIT    		(2 << 5)
+#define MQ_FP_FLAT_PANEL_INTERFACE_16_BIT    		(3 << 5)
+#define MQ_FP_DITHER_PATTERN				(3 << 8)
+#define MQ_FP_DITHER_PATTERN_1				(1 << 8)
+#define MQ_FP_DITHER_BASE_COLOR				(7 << 12)
+#define MQ_FP_DITHER_BASE_COLOR_DISABLE			(7 << 12)
+#define MQ_FP_DITHER_BASE_COLOR_3_BITS			(3 << 12)
+#define MQ_FP_DITHER_BASE_COLOR_4_BITS			(4 << 12)
+#define MQ_FP_DITHER_BASE_COLOR_5_BITS			(5 << 12)
+#define MQ_FP_DITHER_BASE_COLOR_6_BITS			(6 << 12)
+#define MQ_FP_ALTERNATE_WINDOW_CONTROL			(1 << 15)
+#define MQ_FP_FRC_CONTROL				(3 << 16)
+#define MQ_FP_FRC_CONTROL_2_LEVEL    			(0 << 16)
+#define MQ_FP_FRC_CONTROL_4_LEVEL    			(1 << 16)
+#define MQ_FP_FRC_CONTROL_8_LEVEL    			(2 << 16)
+#define MQ_FP_FRC_CONTROL_16_LEVEL    			(3 << 16)
+#define MQ_FP_POLY_SI_TFT_ENABLE    			(1 << 19)
+#define MQ_FP_POLY_SI_TFT_FIRST_LINE			(1 << 20)
+#define MQ_FP_POLY_SI_TFT_DISPLAY_DATA_CONTROL		(1 << 21)
+#define MQ_FP_APP_NOTE_SAYS_SET_THIS			(1 << 22)
+			u32 pin_control_1;
+#define MQ_FP_DISABLE_FLAT_PANEL_PINS			(1 << 0)
+#define MQ_FP_DISPLAY_ENABLE				(1 << 2)
+#define MQ_FP_AC_MODULATION_ENABLE    			(1 << 3)
+#define MQ_FP_PWM_CLOCK_ENABLE				(1 << 5)
+#define MQ_FP_TFT_SHIFT_CLOCK_SELECT			(1 << 6)
+#define MQ_FP_SHIFT_CLOCK_MASK				(1 << 7)
+#define MQ_FP_FHSYNC_CONTROL				(1 << 8)
+#define MQ_FP_STN_SHIFT_CLOCK_CONTROL			(1 << 9)
+#define MQ_FP_STN_EXTRA_LP_ENABLE    			(1 << 10)
+#define MQ_FP_TFT_DISPLAY_ENABLE_SELECT			(3 << 12)
+#define MQ_FP_TFT_DISPLAY_ENABLE_SELECT_00    		(0 << 12)
+#define MQ_FP_TFT_DISPLAY_ENABLE_SELECT_01    		(1 << 12)
+#define MQ_FP_TFT_DISPLAY_ENABLE_SELECT_10    		(2 << 12)
+#define MQ_FP_TFT_DISPLAY_ENABLE_SELECT_11    		(3 << 12)
+#define MQ_FP_TFT_HORIZONTAL_SYNC_SELECT    		(3 << 14)
+#define MQ_FP_TFT_HORIZONTAL_SYNC_SELECT_00    		(0 << 14)
+#define MQ_FP_TFT_HORIZONTAL_SYNC_SELECT_01    		(1 << 14)
+#define MQ_FP_TFT_HORIZONTAL_SYNC_SELECT_10    		(2 << 14)
+#define MQ_FP_TFT_HORIZONTAL_SYNC_SELECT_11    		(3 << 14)
+#define MQ_FP_TFT_VERTICAL_SYNC_SELECT    		(3 << 16)
+#define MQ_FP_TFT_VERTICAL_SYNC_SELECT_00    		(0 << 16)
+#define MQ_FP_TFT_VERTICAL_SYNC_SELECT_01    		(1 << 16)
+#define MQ_FP_TFT_VERTICAL_SYNC_SELECT_10    		(2 << 16)
+#define MQ_FP_TFT_VERTICAL_SYNC_SELECT_11    		(3 << 16)
+#define MQ_FP_LINE_CLOCK_CONTROL    			(1 << 18)
+#define MQ_FP_ALTERNATE_LINE_CLOCK_CONTROL    		(1 << 19)
+#define MQ_FP_FMOD_CLOCK_CONTROL    			(1 << 20)
+#define MQ_FP_FMOD_FRAME_INVERSION    			(1 << 21)
+#define MQ_FP_FMOD_FREQUENCY_CONTROL 			(1 << 22)
+#define MQ_FP_FMOD_SYNCHRONOUS_RESET  			(1 << 23)
+#define MQ_FP_SHIFT_CLOCK_DELAY   			(7 << 24)
+#define MQ_FP_EXTENDED_LINE_CLOCK_CONTROL    		(1 << 27)
+			u32 output_control;
+			u32 input_control;
+#define MQ_FP_ENVDD					(1 << 0)
+#define MQ_FP_ENVEE					(1 << 1)
+#define MQ_FP_FD2					(1 << 2)
+#define MQ_FP_FD3					(1 << 3)
+#define MQ_FP_FD4					(1 << 4)
+#define MQ_FP_FD5					(1 << 5)
+#define MQ_FP_FD6					(1 << 6)
+#define MQ_FP_FD7					(1 << 7)
+#define MQ_FP_FD10					(1 << 10)
+#define MQ_FP_FD11					(1 << 11)
+#define MQ_FP_FD12					(1 << 12)
+#define MQ_FP_FD13					(1 << 13)
+#define MQ_FP_FD14					(1 << 14)
+#define MQ_FP_FD15					(1 << 15)
+#define MQ_FP_FD18					(1 << 18)
+#define MQ_FP_FD19					(1 << 19)
+#define MQ_FP_FD20					(1 << 20)
+#define MQ_FP_FD21					(1 << 21)
+#define MQ_FP_FD22					(1 << 22)
+#define MQ_FP_FD23					(1 << 23)
+#define MQ_FP_FSCLK					(1 << 24)
+#define MQ_FP_FDE					(1 << 25)
+#define MQ_FP_FHSYNC					(1 << 26)
+#define MQ_FP_FVSYNC					(1 << 27)
+#define MQ_FP_FMOD					(1 << 28)
+#define MQ_FP_FLCLK					(1 << 29)
+#define MQ_FP_PWM0					(1 << 30)
+#define MQ_FP_PWM1					(1 << 31)
+			u32 stn_panel_control;
+			u32 polarity_control;
+			u32 pin_output_select_0;
+			u32 pin_output_select_1;
+			u32 pin_output_data;
+			u32 pin_input_data;
+			u32 pin_weak_pull_down;
+			u32 additional_pin_output_select;
+			u32 dummy1;
+			u32 dummy2;
+			u32 test_control;
+			u32 pulse_width_mod_control;
+			u32 frc_pattern[32];
+			u32 frc_weight;
+			u32 pwm_clock_selector_c8;
+			u32 pwm_clock_selector_cc;
+			u32 pwm_clock_selector_d0;
+			u32 pwm_clock_selector_d4;
+			u32 frc_weight_d8;
+			u32 frc_weight_dc;
+		};
+		u32 a[0x80];
+		u8 size[512];
+	} FP;
+	/*
+	 * Color Palette (0x800)
+	 */
+	union {
+		struct {
+			u32 palette[256];
+		};
+		u32 a[256];
+		u8 size[1024];
+	} CMAP;
+	/*
+	 * Source FIFO Space (0xc00)
+	 */
+	union {
+                u32 a[256];
+		u8 size[1024];
+	} FIFO;
+	/*
+	 * USB Device Controller (0x1000)
+	 */
+	union {
+		struct {
+			u32 control;
+#define MQ_UDC_SUSPEND_ENABLE				(1 << 0)
+#define MQ_UDC_REMOTEHOST_WAKEUP_ENABLE			(1 << 3)
+#define MQ_UDC_EP2_ISOCHRONOUS				(1 << 5)
+#define MQ_UDC_EP3_ISOCHRONOUS				(1 << 6)
+#define MQ_UDC_WAKEUP_USBHOST				(1 << 8)
+#define MQ_UDC_IEN_SOF					(1 << 16)
+#define MQ_UDC_IEN_EP0_TX				(1 << 17)
+#define MQ_UDC_IEN_EP0_RX				(1 << 18)
+#define MQ_UDC_IEN_EP1_TX				(1 << 19)
+#define MQ_UDC_IEN_EP2_TX_EOT				(1 << 20)
+#define MQ_UDC_IEN_EP3_RX_EOT				(1 << 21)
+#define MQ_UDC_IEN_DMA_TX				(1 << 22)
+#define MQ_UDC_IEN_DMA_RX				(1 << 23)
+#define MQ_UDC_IEN_DMA_RX_EOT				(1 << 24)
+#define MQ_UDC_IEN_GLOBAL_SUSPEND			(1 << 25)
+#define MQ_UDC_IEN_WAKEUP				(1 << 26)
+#define MQ_UDC_IEN_RESET				(1 << 27)
+			u32 address;
+#define MQ_UDC_ADDRESS_MASK				(127)
+			u32 frame_number;
+#define MQ_UDC_FRAME_MASK				(2047)
+#define MQ_UDC_FRAME_CORRUPTED				(1 << 11)
+#define MQ_UDC_FRAME_NEW				(1 << 12)
+#define MQ_UDC_FRAME_MISSING				(1 << 13)
+#define MQ_UDC_EP2_DATA_MISSING				(1 << 14)
+#define MQ_UDC_EP3_DATA_MISSING				(1 << 15)
+			u32 ep0txcontrol;
+#define MQ_UDC_TX_EDT					(1 << 1)
+#define MQ_UDC_STALL					(1 << 2)
+#define MQ_UDC_TX_PID_DATA1				(1 << 3)
+#define MQ_UDC_TX_LAST_ENABLE_SHIFT			(4)
+#define MQ_UDC_TX_LAST_ENABLE_MASK			(15 << MQ_UDC_TX_LAST_ENABLE_SHIFT)
+#define MQ_UDC_TX_LAST_ENABLE(x)  			(((1 << (1 + (((x) - 1) & 3))) - 1) << MQ_UDC_TX_LAST_ENABLE_SHIFT)
+#define MQ_UDC_CLEAR_FIFO				(1 << 8)
+			u32 ep0txstatus;
+#define MQ_UDC_ACK					(1 << 0)
+#define MQ_UDC_ERR					(1 << 1)
+#define MQ_UDC_TIMEOUT					(1 << 2)
+#define MQ_UDC_EOT					(1 << 3)
+#define MQ_UDC_FIFO_OVERRUN				(1 << 6)
+#define MQ_UDC_NAK					(1 << 7)
+#define MQ_UDC_FIFO_SHIFT				(9)
+#define MQ_UDC_FIFO_MASK				(7)
+#define MQ_UDC_FIFO(x)					(((x) >> MQ_UDC_FIFO_SHIFT) & MQ_UDC_FIFO_MASK)
+#define MQ_UDC_FIFO_DEPTH				(4)
+			u32 ep0rxcontrol;
+			/* Most bitmasks shared with txstatus */
+			u32 ep0rxstatus;
+#define MQ_UDC_RX_PID_DATA1				(1 << 4)
+#define MQ_UDC_RX_TOKEN_SETUP				(1 << 5)
+#define MQ_UDC_RX_VALID_BYTES_SHIFT			(12)
+#define MQ_UDC_RX_VALID_BYTES_MASK			(3)
+#define MQ_UDC_RX_VALID_BYTES(x)			(((x) >> MQ_UDC_RX_VALID_BYTES_SHIFT) & MQ_UDC_RX_VALID_BYTES_MASK)
+			u32 ep0rxfifo;
+			u32 ep0txfifo;
+			/* Most bitmasks shared with ep0txcontrol */
+			u32 ep1control;
+#define MQ_UDC_EP_ENABLE				(1 << 0)
+			/* Most bitmasks shared with ep0txstatus */
+			u32 ep1status;
+			u32 ep1fifo;
+			/* Most bitmasks shared with ep0txcontrol */
+			u32 ep2control;
+#define MQ_UDC_FORCE_DATA0				(1 << 3)
+#define MQ_UDC_FIFO_THRESHOLD_SHIFT			(9)
+#define MQ_UDC_FIFO_THRESHOLD_MASK			(7 << MQ_UDC_FIFO_THRESHOLD_SHIFT)
+#define MQ_UDC_FIFO_THRESHOLD(x)			((x) << MQ_UDC_FIFO_THRESHOLD_SHIFT)
+			/* Most bitmasks shared with ep0txstatus */
+			u32 ep2status;
+			/* Most bitmasks shared with ep0rxcontrol */
+			u32 ep3control;
+			/* Most bitmasks shared with ep0rxstatus */
+			u32 ep3status;
+			u32 intstatus;
+#define MQ_UDC_INT_SOF					(1 << 0)
+#define MQ_UDC_INT_EP0_TX				(1 << 1)
+#define MQ_UDC_INT_EP0_RX				(1 << 2)
+#define MQ_UDC_INT_EP1_TX				(1 << 3)
+#define MQ_UDC_INT_EP2_TX_EOT				(1 << 4)
+#define MQ_UDC_INT_EP3_RX_EOT				(1 << 5)
+#define MQ_UDC_INT_DMA_TX				(1 << 6)
+#define MQ_UDC_INT_DMA_RX				(1 << 7)
+#define MQ_UDC_INT_DMA_RX_EOT				(1 << 8)
+#define MQ_UDC_INT_GLOBAL_SUSPEND			(1 << 9)
+#define MQ_UDC_INT_WAKEUP				(1 << 10)
+#define MQ_UDC_INT_RESET				(1 << 11)
+#define MQ_UDC_INT_EP0		(MQ_UDC_INT_EP0_TX | MQ_UDC_INT_EP0_RX)
+#define MQ_UDC_INT_EP1		(MQ_UDC_INT_EP1_TX)
+#define MQ_UDC_INT_EP2		(MQ_UDC_INT_EP2_TX_EOT | MQ_UDC_INT_DMA_TX)
+#define MQ_UDC_INT_EP3		(MQ_UDC_INT_EP3_RX_EOT | MQ_UDC_INT_DMA_RX | \
+				 MQ_UDC_INT_DMA_RX_EOT)
+			u32 testcontrol1;
+			u32 testcontrol2;
+			u32 unused [5];
+			/* This is for endpoint 2 */
+			u32 dmatxcontrol;
+#define MQ_UDC_DMA_ENABLE				(1 << 0)
+#define MQ_UDC_DMA_PINGPONG				(1 << 1)
+#define MQ_UDC_DMA_NUMBUFF_SHIFT			(2)
+#define MQ_UDC_DMA_NUMBUFF_MASK				(3 << MQ_UDC_DMA_NUMBUFF_SHIFT)
+#define MQ_UDC_DMA_NUMBUFF(x)				((x - 1) << MQ_UDC_DMA_NUMBUFF_SHIFT)
+#define MQ_UDC_DMA_BUFF1_OWNER				(1 << 8)
+#define MQ_UDC_DMA_BUFF2_OWNER				(1 << 9)
+#define MQ_UDC_DMA_BUFF1_EOT				(1 << 10)
+#define MQ_UDC_DMA_BUFF2_EOT				(1 << 11)
+			u32 dmatxdesc1;
+#define MQ_UDC_DMA_BUFFER_ADDR_SHIFT			(0)
+#define MQ_UDC_DMA_BUFFER_ADDR_MASK			(32767)
+#define MQ_UDC_DMA_BUFFER_ADDR(x)			(((x) >> 3) << MQ_UDC_DMA_BUFFER_ADDR_SHIFT)
+#define MQ_UDC_DMA_BUFFER_SIZE_SHIFT			(16)
+#define MQ_UDC_DMA_BUFFER_SIZE_MASK			(4095)
+#define MQ_UDC_DMA_BUFFER_SIZE(x)			((x - 1) << MQ_UDC_DMA_BUFFER_SIZE_SHIFT)
+#define MQ_UDC_DMA_BUFFER_LAST				(1 << 28)
+			u32 dmatxdesc2;
+			/* This shares bitmasks with dmatxcontrol, but refers to endpoint 3 */
+			u32 dmarxcontrol;
+#define MQ_UDC_ISO_TRANSFER_END				(1 << 16)
+			u32 dmarxdesc1;
+#define MQ_UDC_DMA_BUFFER_EADDR_SHIFT			(16)
+#define MQ_UDC_DMA_BUFFER_EADDR_MASK			(32767)
+#define MQ_UDC_DMA_BUFFER_EADDR(x)			(((x - 1) >> 3) << MQ_UDC_DMA_BUFFER_EADDR_SHIFT)
+			u32 dmarxdesc2;
+			u32 dmabuff1size;
+			u32 dmabuff2size;
+		};
+		u32 a[19];
+		u8 size[128];
+	} UDC;
+};
+
+/*
+ * Instead of attempting to figure out how to program this device,
+ * just use canned values for the known display types.
+ */
+struct mediaq11xx_init_data {
+	u32 DC[0x6];
+	u32 CC[0x5];
+	u32 MIU[0x7];
+	u32 GC[0x1b];
+	u32 FP[0x80];
+        u32 GE[0x14];
+        u32 SPI[0x9];
+	void (*set_power) (int on);
+};
+
+/* Chip flavour */
+enum
+{
+	CHIP_MEDIAQ_1100,
+	CHIP_MEDIAQ_1132,
+	CHIP_MEDIAQ_1168,
+	CHIP_MEDIAQ_1178,
+	CHIP_MEDIAQ_1188
+};
+
+/* This structure is used by the basic MediaQ SoC driver to allow client
+ * drivers to use its functionality. Rather than doing a bunch of
+ * EXPORT_SYMBOL's we're storing a pointer to this structure in every
+ * device->platform_data, and the device_driver receives it with
+ * every call.
+ */
+struct mediaq11xx_base {
+	/* Memory that is serialized between CPU and gfx engine */
+	u8 *gfxram;
+	/* Memory that is not synchronized between CPU and GE.
+	 * WARNING: NEVER TOUCH MEMORY ALLOCATED WITH THE 'gfx' FLAG
+	 * (SEE BELOW) VIA THE "ram" POINTER!!! SUCH ADDRESSES CAN BE
+	 * BOGUS AND POSSIBLY BELONG TO OTHER PROCESS OR DRIVER!!!
+	 */
+	volatile u8 *ram;
+	/* MediaQ registers */
+	volatile struct mediaq11xx_regs *regs;
+	/* Chip flavour */
+	int chip;
+	/* Chip name (1132, 1178 etc) */
+	const char *chipname;
+	/* The physical address of MediaQ registers */
+	u32 paddr_regs;
+	/* Physical address of serialized & non-serialized RAM */
+	u32 paddr_gfxram, paddr_ram;
+#ifdef MQ_IRQ_MULTIPLEX
+	/* Base IRQ number of our allocated interval of IRQs */
+	int irq_base;
+#endif
+
+	/* Set the MediaQ GPIO to given state. Of course only those GPIOs
+	 * are supported that exist (see MediaQ specs).
+	 */
+	int (*set_GPIO) (struct mediaq11xx_base *zis, int num, int state);
+/* Change GPIO input/output mode */
+#define MQ_GPIO_CHMODE	0x00000010
+/* Disable GPIO pin */
+#define MQ_GPIO_NONE	0x00000000
+/* Enable GPIO input */
+#define MQ_GPIO_IN	0x00000001
+/* Enable GPIO output */
+#define MQ_GPIO_OUT	0x00000002
+/* Output a '0' on the GPIO pin (if OE is set) */
+#define MQ_GPIO_0	0x00000020
+/* Output a '1' on the GPIO pin (if OE is set) */
+#define MQ_GPIO_1	0x00000040
+/* Enable the pullup register (works only for GPIOs 50-53) */
+#define MQ_GPIO_PULLUP	0x00000080
+/* Handy shortcut - set some GPIO pin to output a '0' */
+#define MQ_GPIO_OUT0	(MQ_GPIO_CHMODE | MQ_GPIO_OUT | MQ_GPIO_0)
+/* Handy shortcut - set some GPIO pin to output an '1' */
+#define MQ_GPIO_OUT1	(MQ_GPIO_CHMODE | MQ_GPIO_OUT | MQ_GPIO_1)
+/* Set the MediaQ GPIO to input mode */
+#define MQ_GPIO_INPUT	(MQ_GPIO_CHMODE | MQ_GPIO_IN)
+
+	/* Get the state of a GPIO pin. If pin is in output mode, it
+	 * returns the pin output value; if pin is in input mode it
+	 * reads the logical level on the pin.
+	 */
+	int (*get_GPIO) (struct mediaq11xx_base *zis, int num);
+
+	/* Apply/remove power to a subdevice.
+	 * The base SoC driver keeps a count poweron requests for every
+	 * subdevice; when a specific counter reaches zero the subdevice
+	 * is powered off. For a list of subdev_id's see the MEDIAQ_11XX_XXX
+         * constants in soc-device.h. When all counts for all subdevices
+         * reaches zero, the MediaQ chip is totally powered off.
+	 */
+	void (*set_power) (struct mediaq11xx_base *zis, int subdev_id, int enable);
+
+	/* Query the power on count of a subdevice (0 - off, >0 - on) */
+	int (*get_power) (struct mediaq11xx_base *zis, int subdev_id);
+
+	/* Allocate a portion of MediaQ RAM. The returned pointer is a
+	 * a memory offset from the start of MediaQ RAM; to get a virtual
+	 * address you must add it to either "gfxram" or "ram" pointers.
+	 * If there is not enough free memory, function returns (u32)-1.
+	 * Memory allocated with the 'gfx=1' flag should be always accessed 
+	 * via the 'gfxram' pointer; however the reverse (accessing 'gfx=0'
+	 * memory via the 'gfxram' pointer) is allowed. This is a MediaQ 11xx
+	 * limitation: it doesn't allow access to first 8K of RAM via the
+	 * graphics-engine-unsynchronized window.
+	 */
+	u32 (*alloc) (struct mediaq11xx_base *zis, unsigned bytes, int gfx);
+
+	/* Free a portion of MediaQ RAM, previously allocated by malloc() */
+	void (*free) (struct mediaq11xx_base *zis, u32 addr, unsigned bytes);
+};
+
+/**
+ * Increment the reference counter of the MediaQ base driver module.
+ * You must call this before enumerating MediaQ drivers; otherwise you
+ * can end with a pointer that points to nowhere in the case when driver
+ * is unloaded between mq_driver_enum() and when you use it.
+ */
+extern int mq_driver_get (void);
+
+/**
+ * Decrement mediaq base SoC driver reference counter.
+ */
+extern void mq_driver_put (void);
+
+/**
+ * Query a list of all MediaQ device drivers.
+ * You must lock the driver in memory by calling mq_driver_get() before
+ * calling this function.
+ */
+extern int mq_device_enum (struct mediaq11xx_base **list, int list_size);
+
+#endif  /* _PLATFORM_MEDIAQ11XX */
diff --git a/drivers/platform/mq11xx_base.c b/drivers/platform/mq11xx_base.c
new file mode 100644
--- /dev/null
+++ b/drivers/platform/mq11xx_base.c
@@ -0,0 +1,1390 @@
+/*
+ * System-on-Chip (SoC) driver for MediaQ 1100/1132 chips.
+ *
+ * Copyright (C) 2003 Andrew Zabolotny <[email protected]>
+ * Portions copyright (C) 2003 Keith Packard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/device.h>
+#include <linux/platform.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <asm/io.h>
+
+#include "mq11xx.h"
+
+#ifdef MQ_IRQ_MULTIPLEX
+#  include <asm/irq.h>
+#  include <asm/mach/irq.h>
+#endif
+
+#if 0
+#  define debug(s, args...) printk (KERN_INFO s, ##args)
+#else
+#  define debug(s, args...)
+#endif
+#define debug_func(s, args...) debug ("%s: " s, __FUNCTION__, ##args)
+
+/* Bitmasks for distinguishing resources for different sets of MediaQ chips */
+#define MQ_MASK_1100		(1 << CHIP_MEDIAQ_1100)
+#define MQ_MASK_1132		(1 << CHIP_MEDIAQ_1132)
+#define MQ_MASK_1168		(1 << CHIP_MEDIAQ_1168)
+#define MQ_MASK_1178		(1 << CHIP_MEDIAQ_1178)
+#define MQ_MASK_1188		(1 << CHIP_MEDIAQ_1188)
+#define MQ_MASK_ALL		(MQ_MASK_1100 | MQ_MASK_1132 | MQ_MASK_1168 | \
+				 MQ_MASK_1178 | MQ_MASK_1188)
+
+struct mq11xx_subdevice_id {
+	int id;
+};
+
+struct mq_block
+{
+        struct mq11xx_subdevice_id id;
+	const char *name;
+	unsigned start, end;
+	unsigned mask;
+};
+
+#define MQ_SUBDEVS_COUNT	ARRAY_SIZE(mq_blocks)
+#define MQ_SUBDEVS_REAL_COUNT	(MQ_SUBDEVS_COUNT - 2)
+static const struct mq_block mq_blocks[] = {
+	{
+                /* Graphics Controller */
+		{ MEDIAQ_11XX_FB_DEVICE_ID },
+		"mq11xx_fb",
+		0x100, 0x17f,
+		MQ_MASK_ALL
+	},
+	{
+		/* Graphics Engine -- tied to framebuffer subdevice */
+		{ MEDIAQ_11XX_FB_DEVICE_ID },
+		NULL,
+		0x200, 0x27f,
+		MQ_MASK_ALL
+	},
+	{
+		/* Palette Registers -- tied to framebuffer subdevice */
+		{ MEDIAQ_11XX_FB_DEVICE_ID },
+		NULL,
+		0x800, 0xbff,
+		MQ_MASK_ALL
+	},
+	{
+		/* Flat Panel control interface */
+		{ MEDIAQ_11XX_FP_DEVICE_ID },
+		"mq11xx_lcd",
+		0x600, 0x7ff,
+		MQ_MASK_ALL
+	},
+	{
+		/* USB Function subdevice */
+		{ MEDIAQ_11XX_UDC_DEVICE_ID },
+		"mq11xx_udc",
+		0x1000, 0x107f,
+		MQ_MASK_ALL
+	},
+	{
+		/* USB Host subdevice */
+		{ MEDIAQ_11XX_UHC_DEVICE_ID },
+		"mq11xx_uhc",
+		0x500, 0x5ff,
+		MQ_MASK_1132 | MQ_MASK_1188
+	},
+	{
+		/* Serial Port Interface */
+		{ MEDIAQ_11XX_SPI_DEVICE_ID },
+		"mq11xx_spi",
+		0x300, 0x37f,
+		MQ_MASK_1132
+	},
+	{
+		/* Synchronous Serial Channel (I2S) */
+		{ MEDIAQ_11XX_I2S_DEVICE_ID },
+		"mq11xx_i2s",
+		0x280, 0x2ff,
+		MQ_MASK_1132
+	},
+};
+
+static struct {
+	int id;
+	int chip;
+	const char *name;
+} mq_device_id [] =
+{
+	{ MQ_PCI_DEVICEID_1100, CHIP_MEDIAQ_1100, "1100" },
+	{ MQ_PCI_DEVICEID_1132, CHIP_MEDIAQ_1132, "1132" },
+	{ MQ_PCI_DEVICEID_1168, CHIP_MEDIAQ_1168, "1168" },
+	{ MQ_PCI_DEVICEID_1178, CHIP_MEDIAQ_1178, "1178" },
+	{ MQ_PCI_DEVICEID_1188, CHIP_MEDIAQ_1188, "1188" }
+};
+
+/* Keep free block list no less than this value (minimal slab is 32 bytes) */
+#define MEMBLOCK_MINCOUNT	(32 / sizeof (struct mq_freemem_list))
+/* Align MediaQ memory blocks by this amount (MediaQ DMA limitation) */
+#define MEMBLOCK_ALIGN		64
+
+struct mq_freemem_list {
+	u32 addr;
+	u32 size;
+} __attribute__((packed));
+
+struct mq_data
+{
+	/* The exported parameters */
+	struct mediaq11xx_base base;
+	/* MediaQ initialization register data */
+	struct mediaq11xx_init_data *mq_init;
+	/* Number of subdevices */
+	int ndevices;
+	/* The list of subdevices */
+	struct platform_device *devices;
+	/* MediaQ interrupt number */
+	int irq_nr;
+	/* Count the number of poweron requests to every subdevice */
+	u8 power_on [MQ_SUBDEVS_REAL_COUNT];
+	/* Number of free block descriptors */
+	int nfreeblocks, maxfreeblocks;
+	/* The list of free blocks */
+	struct mq_freemem_list *freelist;
+	/* The lock on the free blocks list */
+	spinlock_t mem_lock;
+	/* The amount of RAM at the beginning of address space that
+	   is not accessible through the unsynced window */
+	int unsynced_ram_skip;
+};
+
+/* Pointer to initialized devices.
+ * This is a bad practice, but if you don't need too much from the
+ * MediaQ device (such as turning on/off a couple of GPIOs) you can
+ * use the mq_get_device (int index) to get a pointer to one of
+ * available MediaQ device structures.
+ */
+#define MAX_MQ11XX_DEVICES	8
+static struct mediaq11xx_base *mq_device_list [MAX_MQ11XX_DEVICES];
+static spinlock_t mq_device_list_lock = SPIN_LOCK_UNLOCKED;
+
+#define to_mq_data(n) container_of(n, struct mq_data, base)
+
+/* For PCI & DragonBall register mapping is as described in the specs sheet;
+ * for other microprocessor buses some addresses are tossed (what a perversion).
+ * Worse than that, on MQ1168 and later, the registers are always as normal.
+ */
+#if defined __arm__
+// || defined NEC41xx || defined HITACHI 77xx
+#define MQ_MASK_REGSET1		(MQ_MASK_1168 | MQ_MASK_1178 | MQ_MASK_1188)
+#define MQ_MASK_REGSET2		(MQ_MASK_1100 | MQ_MASK_1132)
+#else
+#define MQ_MASK_REGSET1		MQ_MASK_ALL
+#define MQ_MASK_REGSET2		0
+#endif
+
+static struct mediaq11xx_init_data mqInitValid = {
+    /* DC */
+    {
+	/* dc00 */		0,
+	/* dc01 */		MQ_MASK_ALL,
+	/* dc02 */		MQ_MASK_ALL,
+	/* dc03 */		0,
+	/* dc04 */		MQ_MASK_ALL,
+	/* dc05 */		MQ_MASK_ALL,
+    },
+    /* CC */
+    {
+	/* cc00 */		MQ_MASK_ALL,
+	/* cc01 */		MQ_MASK_ALL,
+	/* cc02 */		MQ_MASK_ALL,
+	/* cc03 */		MQ_MASK_ALL,
+	/* cc04 */		MQ_MASK_ALL,
+    },
+    /* MIU */
+    {
+	/* mm00 */		MQ_MASK_ALL,
+	/* mm01 */		MQ_MASK_ALL,
+	/* mm02 */		MQ_MASK_ALL,
+	/* mm03 */		MQ_MASK_ALL,
+	/* mm04 */		MQ_MASK_ALL,
+	/* mm05 */		MQ_MASK_1168 | MQ_MASK_1178 | MQ_MASK_1188,
+	/* mm06 */		MQ_MASK_1168 | MQ_MASK_1178 | MQ_MASK_1188,
+    },
+    /* GC */
+    {
+	/* gc00 */		MQ_MASK_ALL,
+	/* gc01 */		MQ_MASK_ALL,
+	/* gc02 */		MQ_MASK_ALL,
+	/* gc03 */		MQ_MASK_ALL,
+	/* gc04 */		MQ_MASK_ALL,
+	/* gc05 */		MQ_MASK_ALL,
+	/* gc06 NOT SET */	0,
+	/* gc07 NOT SET */	0,
+	/* gc08 */		MQ_MASK_ALL,
+	/* gc09 */		MQ_MASK_ALL,
+	/* gc0a */		MQ_MASK_ALL,
+	/* gc0b */		MQ_MASK_ALL,
+	/* gc0c */		MQ_MASK_ALL,
+	/* gc0d */		MQ_MASK_ALL,
+	/* gc0e */		MQ_MASK_ALL,
+	/* gc0f NOT SET */	0,
+	/* gc10 */		MQ_MASK_ALL,
+	/* gc11 */		MQ_MASK_ALL,
+	/* gc12 NOT SET */	0,
+	/* gc13 NOT SET */	0,
+	/* gc14 */		MQ_MASK_ALL,
+	/* gc15 */		MQ_MASK_ALL,
+	/* gc16 */		MQ_MASK_ALL,
+	/* gc17 */		MQ_MASK_ALL,
+	/* gc18 */		MQ_MASK_ALL,
+	/* gc19 */		MQ_MASK_ALL,
+	/* gc1a */		MQ_MASK_ALL,
+    },
+    /* FP */
+    {
+	/* fp00 */		MQ_MASK_ALL,
+	/* fp01 */		MQ_MASK_ALL,
+	/* fp02 */		MQ_MASK_ALL,
+	/* fp03 */		MQ_MASK_ALL,
+	/* fp04 */		MQ_MASK_ALL,
+	/* fp05 */		MQ_MASK_ALL,
+	/* fp06 */		MQ_MASK_ALL,
+	/* fp07 */		MQ_MASK_ALL,
+	/* fp08 */		MQ_MASK_ALL,
+	/* fp09 NOT SET */	0,
+	/* fp0a */		MQ_MASK_ALL,
+	/* fp0b */		MQ_MASK_ALL,
+	/* fp0c */		MQ_MASK_1168 | MQ_MASK_1178 | MQ_MASK_1188,
+	/* fp0d NOT SET */	0,
+	/* fp0e NOT SET */	0,
+	/* fp0f */		MQ_MASK_ALL,
+	/* fp10 */		MQ_MASK_ALL,
+	/* fp11 */		MQ_MASK_ALL,
+	/* fp12 */		MQ_MASK_ALL,
+	/* fp13 */		MQ_MASK_ALL,
+	/* fp14 */		MQ_MASK_ALL,
+	/* fp15 */		MQ_MASK_ALL,
+	/* fp16 */		MQ_MASK_ALL,
+	/* fp17 */		MQ_MASK_ALL,
+	/* fp18 */		MQ_MASK_ALL,
+	/* fp19 */		MQ_MASK_ALL,
+	/* fp1a */		MQ_MASK_ALL,
+	/* fp1b */		MQ_MASK_ALL,
+	/* fp1c */		MQ_MASK_ALL,
+	/* fp1d */		MQ_MASK_ALL,
+	/* fp1e */		MQ_MASK_ALL,
+	/* fp1f */		MQ_MASK_ALL,
+	/* fp20 */		MQ_MASK_REGSET1,
+	/* fp21 */		MQ_MASK_REGSET1,
+	/* fp22 */		MQ_MASK_REGSET1,
+	/* fp23 */		MQ_MASK_REGSET1,
+	/* fp24 */		MQ_MASK_REGSET1,
+	/* fp25 */		MQ_MASK_REGSET1,
+	/* fp26 */		MQ_MASK_REGSET1,
+	/* fp27 */		MQ_MASK_REGSET1,
+	/* fp28 */		MQ_MASK_REGSET1,
+	/* fp29 */		MQ_MASK_REGSET1,
+	/* fp2a */		MQ_MASK_REGSET1,
+	/* fp2b */		MQ_MASK_REGSET1,
+	/* fp2c */		MQ_MASK_REGSET1,
+	/* fp2d */		MQ_MASK_REGSET1,
+	/* fp2e */		MQ_MASK_REGSET1,
+	/* fp2f */		MQ_MASK_REGSET1,
+	/* fp30 */		MQ_MASK_ALL,
+	/* fp31 */		MQ_MASK_ALL,
+	/* fp32 */		MQ_MASK_ALL,
+	/* fp33 */		MQ_MASK_ALL,
+	/* fp34 */		MQ_MASK_ALL,
+	/* fp35 */		MQ_MASK_ALL,
+	/* fp36 */		MQ_MASK_ALL,
+	/* fp37 */		MQ_MASK_ALL,
+	/* fp38 */		MQ_MASK_ALL,
+	/* fp39 */		MQ_MASK_ALL,
+	/* fp3a */		MQ_MASK_ALL,
+	/* fp3b */		MQ_MASK_ALL,
+	/* fp3c */		MQ_MASK_ALL,
+	/* fp3d */		MQ_MASK_ALL,
+	/* fp3e */		MQ_MASK_ALL,
+	/* fp3f */		MQ_MASK_ALL,
+	/* fp40 */		0,
+	/* fp41 */		0,
+	/* fp42 */		0,
+	/* fp43 */		0,
+	/* fp44 */		0,
+	/* fp45 */		0,
+	/* fp46 */		0,
+	/* fp47 */		0,
+	/* fp48 */		0,
+	/* fp49 */		0,
+	/* fp4a */		0,
+	/* fp4b */		0,
+	/* fp4c */		0,
+	/* fp4d */		0,
+	/* fp4e */		0,
+	/* fp4f */		0,
+	/* fp50 */		0,
+	/* fp51 */		0,
+	/* fp52 */		0,
+	/* fp53 */		0,
+	/* fp54 */		0,
+	/* fp55 */		0,
+	/* fp56 */		0,
+	/* fp57 */		0,
+	/* fp58 */		0,
+	/* fp59 */		0,
+	/* fp5a */		0,
+	/* fp5b */		0,
+	/* fp5c */		0,
+	/* fp5d */		0,
+	/* fp5e */		0,
+	/* fp5f */		0,
+	/* fp60 */		0,
+	/* fp61 */		0,
+	/* fp62 */		0,
+	/* fp63 */		0,
+	/* fp64 */		0,
+	/* fp65 */		0,
+	/* fp66 */		0,
+	/* fp67 */		0,
+	/* fp68 */		0,
+	/* fp69 */		0,
+	/* fp6a */		0,
+	/* fp6b */		0,
+	/* fp6c */		0,
+	/* fp6d */		0,
+	/* fp6e */		0,
+	/* fp6f */		0,
+	/* fp70 */		MQ_MASK_REGSET2,
+	/* fp71 */		MQ_MASK_REGSET2,
+	/* fp72 */		MQ_MASK_REGSET2,
+	/* fp73 */		MQ_MASK_REGSET2,
+	/* fp74 */		MQ_MASK_REGSET2,
+	/* fp75 */		MQ_MASK_REGSET2,
+	/* fp76 */		MQ_MASK_REGSET2,
+	/* fp77 */		MQ_MASK_REGSET2,
+    },
+    /* GE */
+    {
+	/* ge00 NOT SET */	0,
+	/* ge01 NOT SET */	0,
+	/* ge02 NOT SET */	0,
+	/* ge03 NOT SET */	0,
+	/* ge04 NOT SET */	0,
+	/* ge05 NOT SET */	0,
+	/* ge06 NOT SET */	0,
+	/* ge07 NOT SET */	0,
+	/* ge08 NOT SET */	0,
+	/* ge09 NOT SET */	0,
+	/* ge0a */		MQ_MASK_ALL,
+	/* ge0b */		MQ_MASK_ALL,
+	/* ge0c NOT SET */      0x0,
+	/* ge0d NOT SET */      0x0,
+	/* ge0e NOT SET */      0x0,
+	/* ge0f NOT SET */      0x0,
+	/* ge10 NOT SET */      0x0,
+	/* ge11 NOT SET */      MQ_MASK_1168 | MQ_MASK_1178 | MQ_MASK_1188,
+	/* ge12 NOT SET */      0x0,
+	/* ge13 NOT SET */      0x0,
+    },
+    /* SPI */
+    {
+      /* sp00 */		MQ_MASK_1132,
+      /* sp01 */		0,
+      /* sp02 NOT SET */	0,
+      /* sp03 NOT SET */	0,
+      /* sp04 */		MQ_MASK_1132,
+      /* sp05 NOT SET */	0,
+      /* sp06 NOT SET */	0,
+      /* sp07 */		MQ_MASK_1132,
+      /* sp08 */		MQ_MASK_1132,
+    },
+};
+
+static int
+mq11xx_loadvals (char *name, int chipmask, volatile u32 *reg,
+		 u32 *src, u32 *valid, int n)
+{
+	int t;
+
+        for (t = 0; t < n; t++){
+		if (valid[t] & chipmask) {
+			int tries;
+			for (tries = 0; tries < 10; tries++) {
+				reg[t] = src[t];
+				if (reg[t] == src[t])
+					break;
+				mdelay (1);
+			}
+			if (tries == 10) {
+				debug ("mq11xx_loadvals %s%02x %08x FAILED (got %08x)\n", name, t, src[t], reg[t]);
+				return -ENODEV;
+			}
+                }
+        }
+	return 0;
+}
+
+static int
+mq11xx_init (struct mq_data *mqdata)
+{
+	int i, chipmask;
+	u16 endian;
+
+	if (mqdata->mq_init->set_power)
+		mqdata->mq_init->set_power(1);
+
+	/* Set up chip endianness - see mq docs for notes on special care
+	   when writing to this register */
+	endian = mqdata->mq_init->DC [0] & 3;
+	endian = endian | (endian << 2);
+	endian = endian | (endian << 4);
+	endian = endian | (endian << 8);
+	*((u16 *)&mqdata->base.regs->DC.config_0) = endian;
+	/* First of all, enable the oscillator clock */
+	mqdata->base.regs->DC.config_1 = mqdata->mq_init->DC [1];
+	/* Wait for oscillator to run - 30ms doesnt suffice */
+	mdelay (100);
+	/* Enable power to CPU Configuration module */
+	mqdata->base.regs->DC.config_2 = mqdata->mq_init->DC [2];
+	mdelay (10);
+	/* Needed for MediaQ 1178/88 on h2200. */
+	mqdata->base.regs->DC.config_8 = 0x86098609;
+	/* Enable the MQ1132 MIU */
+	mqdata->base.regs->MIU.miu_0 |= MQ_MIU_ENABLE;
+	/* Disable the interrupt controller */
+	mqdata->base.regs->IC.control = 0;
+
+	/* See if it's actually a MediaQ chip */
+	if (mqdata->base.regs->PCI.vendor_id != MQ_PCI_VENDORID) {
+unkchip:	printk (KERN_ERR "%s:%d Unknown device ID (%04x:%04x)\n",
+			__FILE__, __LINE__,
+			mqdata->base.regs->PCI.vendor_id,
+			mqdata->base.regs->PCI.device_id);
+		return -ENODEV;
+	}
+
+	for (i = 0; i < ARRAY_SIZE (mq_device_id); i++)
+		if (mqdata->base.regs->PCI.device_id == mq_device_id [i].id) {
+			mqdata->base.chip = mq_device_id [i].chip;
+			mqdata->base.chipname = mq_device_id [i].name;
+			break;
+		}
+
+	if (!mqdata->base.chipname)
+		goto unkchip;
+
+	chipmask = 1 << mqdata->base.chip;
+
+#define INIT_REGS(id) \
+	if (mq11xx_loadvals (#id, chipmask, mqdata->base.regs->id.a, \
+		mqdata->mq_init->id, mqInitValid.id, \
+		ARRAY_SIZE (mqdata->mq_init->id))) \
+		return -ENODEV
+
+	INIT_REGS (DC);
+	INIT_REGS (CC);
+	INIT_REGS (MIU);
+
+	/* XXX Move this stuff to mq1100fb driver some day */
+	INIT_REGS (GC);
+	INIT_REGS (FP);
+	INIT_REGS (GE);
+
+#undef INIT_REGS
+
+	return 0;
+}
+
+static void
+mq_release (struct device *dev)
+{
+}
+
+/* This is kind of ugly and complex... well, this is the way GPIOs are
+ * programmed on MediaQ... what a mess...
+ */
+static int
+mq_set_GPIO (struct mediaq11xx_base *zis, int num, int state)
+{
+	u32 andmask = 0, ormask = 0;
+
+	debug ("mq_set_GPIO (num:%d state:%x)\n", num, state);
+
+	if ((num <= 7) || ((num >= 20) && (num <= 25))) {
+		andmask = 4;
+		if (state & MQ_GPIO_CHMODE) {
+			andmask |= 3;
+			if (state & MQ_GPIO_IN)
+				ormask |= 1;
+			if (state & MQ_GPIO_OUT)
+				ormask |= 2;
+		}
+		if (state & MQ_GPIO_0)
+			andmask |= 8;
+		if (state & MQ_GPIO_1)
+			ormask |= 8;
+		if (num <= 7) {
+			andmask <<= num * 4;
+			ormask <<= num * 4;
+			zis->regs->CC.gpio_control_0 =
+				(zis->regs->CC.gpio_control_0 & ~andmask) | ormask;
+		} else {
+			andmask <<= (num - 18) * 4;
+			ormask <<= (num - 18) * 4;
+			zis->regs->CC.gpio_control_1 =
+				(zis->regs->CC.gpio_control_1 & ~andmask) | ormask;
+		}
+	} else if (num >= 50 && num <= 55) {
+		int shft;
+
+		/* Uhh.... what a mess */
+		if (state & MQ_GPIO_CHMODE) {
+			shft = (num <= 53) ? num - 48 : num - 45;
+			andmask |= 3 << shft;
+			if (state & MQ_GPIO_OUT)
+				ormask |= (1 << (shft * 2));
+			if (state & MQ_GPIO_IN)
+				ormask |= (2 << (shft * 2));
+		}
+
+		if (num == 50)
+			shft = 3;
+		else if (num <= 53)
+			shft = (num - 51);
+		else
+			shft = (num - 38);
+
+		if (state & MQ_GPIO_0)
+			andmask |= (1 << shft);
+		if (state & MQ_GPIO_1)
+			ormask |= (1 << shft);
+		if ((state & MQ_GPIO_PULLUP) && (num <= 53))
+                        ormask |= 0x1000 << (num - 50);
+		zis->regs->SPI.gpio_mode =
+			(zis->regs->SPI.gpio_mode & ~andmask) | ormask;
+	} else if (num >= 60 && num <= 66) {
+		int shft = (num - 60);
+		if (state & MQ_GPIO_0)
+			andmask |= (1 << shft);
+		if (state & MQ_GPIO_1)
+			ormask |= (1 << shft);
+		shft *= 2;
+		if (state & MQ_GPIO_CHMODE) {
+			andmask |= (0x300 << shft);
+			if (state & MQ_GPIO_OUT)
+				ormask |= (0x100 << shft);
+			if (state & MQ_GPIO_IN)
+				ormask |= (0x200 << shft);
+		}
+		zis->regs->SPI.blue_gpio_mode =
+			(zis->regs->SPI.blue_gpio_mode & ~andmask) | ormask;
+	} else
+		return -ENODEV;
+
+	return 0;
+}
+
+static int
+mq_get_GPIO (struct mediaq11xx_base *zis, int num)
+{
+        u32 val;
+
+	if (num <= 7)
+		val = zis->regs->CC.gpio_control_0 & (8 << (num * 4));
+	else if ((num >= 20) && (num <= 25))
+		val = zis->regs->CC.gpio_control_1 & (8 << ((num - 18) * 4));
+	else if (num == 50)
+		val = zis->regs->SPI.gpio_mode & 0x8;
+	else if ((num >= 51) && (num <= 53))
+		val = zis->regs->SPI.gpio_mode & (0x1 << (num - 51));
+	else if ((num >= 54) && (num <= 55))
+		val = zis->regs->SPI.gpio_mode & (0x1 << (num - 38));
+	else if (num >= 60 && num <= 66)
+		val = zis->regs->SPI.blue_gpio_mode & (1 << (num - 60));
+	else
+		val = 0;
+
+	if (val) val = 1;
+
+	return val;
+}
+
+static int
+global_power (struct mq_data *mqdata)
+{
+	int i;
+	for (i = 0; i < sizeof (mqdata->power_on); i++)
+		if (mqdata->power_on [i])
+			return 1;
+	return 0;
+}
+
+static void
+mq_power_on (struct mediaq11xx_base *zis, int subdev_id)
+{
+	/* The device IDs lower 4 bits contains the subdevice index
+	 * (counting from 1). Take care to keep all MEDIAQ_11XX_XXX
+	 * contstants with sequential values in their lower 4 bits!
+	 */
+	unsigned idx = (subdev_id & 0x0f) - 1;
+	struct mq_data *mqdata = to_mq_data (zis);
+
+	debug_func ("subdev:%x curstate:%d\n", subdev_id, mqdata->power_on [idx]);
+
+	/* Check if MediaQ is not totally turned off */
+	if (!global_power (mqdata)) {
+		debug ("-*- Global POWER ON to the MediaQ chip -*-\n");
+		mq11xx_init (mqdata);
+	}
+
+	if (!mqdata->power_on [idx])
+		switch (subdev_id) {
+		case MEDIAQ_11XX_FB_DEVICE_ID:
+			zis->regs->GC.control |= MQ_GC_CONTROL_ENABLE;
+			/* Enable the graphics engine power */
+			zis->regs->DC.config_5 |= MQ_CONFIG_GE_ENABLE;
+			break;
+		case MEDIAQ_11XX_FP_DEVICE_ID:
+			/* Enable flat panel pin outputs */
+			//zis->regs->FP.pin_control_1 &= ~MQ_FP_DISABLE_FLAT_PANEL_PINS;
+			zis->regs->FP.output_control = mqdata->mq_init->FP [2];
+			break;
+		case MEDIAQ_11XX_UDC_DEVICE_ID:
+			/* Enable power to USB function */
+			zis->regs->DC.config_5 |= MQ_CONFIG_UDC_CLOCK_ENABLE;
+			break;
+		case MEDIAQ_11XX_UHC_DEVICE_ID:
+			/* Enable power to USB host */
+			zis->regs->DC.config_5 |= MQ_CONFIG_UHC_CLOCK_ENABLE;
+			break;
+		case MEDIAQ_11XX_SPI_DEVICE_ID:
+		case MEDIAQ_11XX_I2S_DEVICE_ID:
+			/* There's no explicit way to do it */
+			break;
+		}
+	mqdata->power_on [idx]++;
+}
+
+static void
+mq_power_off (struct mediaq11xx_base *zis, int subdev_id)
+{
+	unsigned idx = (subdev_id & 0x0f) - 1;
+	struct mq_data *mqdata = to_mq_data (zis);
+
+	debug_func ("subdev:%x curstate:%d\n", subdev_id, mqdata->power_on [idx]);
+
+	if (!mqdata->power_on [idx]) {
+		printk (KERN_ERR "mq11xx: mismatch power on/off request count for subdevice %x\n",
+			subdev_id);
+		return;
+	}
+
+	switch (subdev_id) {
+	case MEDIAQ_11XX_FB_DEVICE_ID:
+		zis->regs->GC.control &= ~MQ_GC_CONTROL_ENABLE;
+		/* Disable the graphics engine power */
+		zis->regs->DC.config_5 &= ~MQ_CONFIG_GE_ENABLE;
+		break;
+	case MEDIAQ_11XX_FP_DEVICE_ID:
+		/* Disable flat panel pin outputs */
+		zis->regs->FP.output_control = 0;
+		//zis->regs->FP.pin_control_1 |= MQ_FP_DISABLE_FLAT_PANEL_PINS;
+		break;
+	case MEDIAQ_11XX_UDC_DEVICE_ID:
+		/* Disable power to USB function */
+		zis->regs->DC.config_5 &= ~MQ_CONFIG_UDC_CLOCK_ENABLE;
+		break;
+	case MEDIAQ_11XX_UHC_DEVICE_ID:
+		/* Disable power to USB host */
+		zis->regs->DC.config_5 &= ~MQ_CONFIG_UHC_CLOCK_ENABLE;
+		break;
+	case MEDIAQ_11XX_SPI_DEVICE_ID:
+	case MEDIAQ_11XX_I2S_DEVICE_ID:
+		/* There's no explicit way to do it */
+		break;
+	}
+
+	mqdata->power_on [idx]--;
+
+	/* Check if we have to totally power off MediaQ */
+	if (!global_power (mqdata)) {
+		debug ("-*- Global POWER OFF to MediaQ chip -*-\n");
+		/* Disable the MQ1132 MIU */
+		zis->regs->MIU.miu_0 &= ~MQ_MIU_ENABLE;
+		/* Disable power to CPU Configuration module */
+		zis->regs->DC.config_2 &= ~MQ_CONFIG_CC_MODULE_ENABLE;
+		/* Disable the oscillator clock */
+		zis->regs->DC.config_1 &= ~MQ_CONFIG_18_OSCILLATOR;
+
+		if (mqdata->mq_init->set_power)
+			mqdata->mq_init->set_power(0);
+	}
+}
+
+static void
+mq_set_power (struct mediaq11xx_base *zis, int subdev_id, int state)
+{
+	if (state)
+		mq_power_on (zis, subdev_id);
+	else
+		mq_power_off (zis, subdev_id);
+}
+
+static int
+mq_get_power (struct mediaq11xx_base *zis, int subdev_id)
+{
+	unsigned idx = (subdev_id & 0x0f) - 1;
+	struct mq_data *mqdata = to_mq_data (zis);
+	return mqdata->power_on [idx];
+}
+
+/********************************************* On-chip memory management ******/
+
+/**
+ * Since the internal chip RAM may be shared amongst several subdevices
+ * (framebuffer, graphics engine, SPI, UDC and other), we have to implement
+ * a general memory management mechanism to prevent conflicts between drivers
+ * trying to use this resource.
+ *
+ * We could use the "chained free blocks" scheme used in many simple memory
+ * managers, where a { free block size; next free block; } structure is
+ * stuffed directly into the free block itself, to conserve memory. However,
+ * this mechanism is less reliable since it is susceptible to overwrites
+ * past the bounds of an allocated block (because it breaks the free blocks
+ * chain). Of course, a buggy driver is always a bad idea, but we should try
+ * to be as reliable as possible. Thus, the free block chain is kept in kernel
+ * memory (in the device-specific structure), and everything else is done like
+ * in the mentioned scheme.
+ */
+
+static void
+mq_setfreeblocks (struct mq_data *mqdata, int nblocks)
+{
+	void *temp;
+	int newmax;
+
+	/* Increase maximum number of free memory descriptors in power-of-two
+	   steps. This is due to the fact, that Linux allocates memory in
+	   power-of-two chunks, and the minimal chunk (slab) size is 32b.
+	   Allocating anything but power-of-two sized memory blocks is just
+	   a waste of memory. In fact, in most circumstances we have a small
+	   number of free block descriptors. */
+	newmax = (nblocks > 0) ? (1 << fls (nblocks - 1)) : 1;
+	if (likely (newmax < MEMBLOCK_MINCOUNT))
+		newmax = MEMBLOCK_MINCOUNT;
+
+	if (mqdata->maxfreeblocks != newmax) {
+		int nfb = mqdata->nfreeblocks;
+		if (nfb > nblocks) nfb = nblocks;
+		temp = kmalloc (newmax * sizeof (struct mq_freemem_list),
+				GFP_KERNEL);
+		memcpy (temp, mqdata->freelist, nfb * sizeof (struct mq_freemem_list));
+		kfree (mqdata->freelist);
+		mqdata->freelist = temp;
+		mqdata->maxfreeblocks = newmax;
+	}
+
+	mqdata->nfreeblocks = nblocks;
+}
+
+/* Check if memory block is suitable for uses other than graphics. */
+static int mq_suitable_ram (struct mq_data *mqdata, int fbn, unsigned size)
+{
+	int n, delta;
+
+	delta = mqdata->unsynced_ram_skip - mqdata->freelist [fbn].addr;
+	if (delta <= 0)
+		return 1;
+
+	if (mqdata->freelist [fbn].size < size + delta)
+		return 0;
+
+	/* Ok, split the free block into two */
+	n = mqdata->nfreeblocks;
+	mq_setfreeblocks (mqdata, n + 1);
+	mqdata->freelist [n].addr = mqdata->freelist [fbn].addr;
+	mqdata->freelist [n].size = delta;
+	mqdata->freelist [fbn].addr += delta;
+	mqdata->freelist [fbn].size -= delta;
+
+	return 1;
+}
+
+/* Not too optimal (just finds the first free block of equal or larger size
+ * than requested) but usually there are a few blocks in MediaQ RAM anyway...
+ * usually a block of 320x240x2 bytes is eaten by the framebuffer, and we
+ * have just 256k total.
+ */
+static u32
+mq_alloc (struct mediaq11xx_base *zis, unsigned size, int gfx)
+{
+	struct mq_data *mqdata = to_mq_data (zis);
+	int i;
+
+        size = (size + MEMBLOCK_ALIGN - 1) & ~(MEMBLOCK_ALIGN - 1);
+
+        spin_lock (&mqdata->mem_lock);
+
+	for (i = mqdata->nfreeblocks - 1; i >= 0; i--) {
+		if ((mqdata->freelist [i].size >= size) &&
+		    (gfx || mq_suitable_ram (mqdata, i, size))) {
+			u32 addr = mqdata->freelist [i].addr;
+			mqdata->freelist [i].size -= size;
+			if (mqdata->freelist [i].size)
+				mqdata->freelist [i].addr += size;
+			else {
+				memcpy (mqdata->freelist + i, mqdata->freelist + i + 1,
+					(mqdata->nfreeblocks - 1 - i) * sizeof (struct mq_freemem_list));
+				mq_setfreeblocks (mqdata, mqdata->nfreeblocks - 1);
+			}
+			spin_unlock (&mqdata->mem_lock);
+                        return addr;
+		}
+	}
+
+	spin_unlock (&mqdata->mem_lock);
+
+	return (u32)-1;
+}
+
+static void
+mq_free (struct mediaq11xx_base *zis, u32 addr, unsigned size)
+{
+	int i, j;
+	u32 eaddr;
+	struct mq_data *mqdata = to_mq_data (zis);
+
+	size = (size + MEMBLOCK_ALIGN - 1) & ~(MEMBLOCK_ALIGN - 1);
+	eaddr = addr + size;
+
+	spin_lock (&mqdata->mem_lock);
+
+	/* Look for a free block that starts at the end of the block to free */
+	for (i = mqdata->nfreeblocks - 1; i >= 0; i--)
+		if (mqdata->freelist [i].addr == eaddr) {
+			mqdata->freelist [i].size += size;
+			mqdata->freelist [i].addr = addr;
+			/* Now look for a block that ends where we start */
+			for (j = mqdata->nfreeblocks - 1; j >= 0; j--) {
+				if (mqdata->freelist [j].addr + mqdata->freelist [j].size == addr) {
+					/* Ok, concatenate the two free blocks */
+					mqdata->freelist [i].addr = mqdata->freelist [j].addr;
+					mqdata->freelist [i].size += mqdata->freelist [j].size;
+					memcpy (mqdata->freelist + j, mqdata->freelist + j + 1,
+						(mqdata->nfreeblocks - 1 - j) * sizeof (struct mq_freemem_list));
+					mq_setfreeblocks (mqdata, mqdata->nfreeblocks - 1);
+					break;
+				}
+			}
+			spin_unlock (&mqdata->mem_lock);
+			return;
+		}
+
+	for (i = mqdata->nfreeblocks - 1; i >= 0; i--)
+		if (mqdata->freelist [i].addr + mqdata->freelist [i].size == addr) {
+			mqdata->freelist [i].size += size;
+			spin_unlock (&mqdata->mem_lock);
+			return;
+		}
+
+	/* Ok, we have to add a new free block entry */
+	i = mqdata->nfreeblocks;
+	mq_setfreeblocks (mqdata, i + 1);
+	mqdata->freelist [i].addr = addr;
+	mqdata->freelist [i].size = size;
+
+	spin_unlock (&mqdata->mem_lock);
+}
+
+/**************************** IRQ handling using interrupt multiplexing ******/
+
+#ifdef MQ_IRQ_MULTIPLEX
+
+static void
+mq_irq_demux (unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
+{
+	u32 mask, orig_mask;
+	int i, mq_irq, timeout;
+	struct mq_data *mqdata;
+
+	mqdata = desc->data;
+
+	mqdata->base.regs->IC.control &= ~MQ_INTERRUPT_CONTROL_INTERRUPT_ENABLE;
+
+	debug ("mq_irq_demux ENTER\n");
+
+	/* An IRQ is a expensive operation, thus we're handling here
+	 * as much interrupt sources as we can (rather than returning
+	 * from interrupt just to get caught once again). On the other
+	 * hand, we can't process too much of them since some IRQ may be
+	 * continuously triggered. Thus, we'll set an arbitrary upper limit
+	 * on the number of interrupts we can handle at once. Note that,
+	 * for example, if PCMCIA IRQ is connected to MediaQ, this number
+	 * can be very large, e.g. one interrupt for every read sector
+	 * from a memory card.
+	 */
+	timeout = 1024;
+
+	/* Read the IRQ status register */
+	while (timeout-- &&
+	       (mask = orig_mask = mqdata->base.regs->IC.interrupt_status)) {
+		irq = 0;
+		while ((i = ffs (mask))) {
+			irq += i - 1;
+			mq_irq = mqdata->base.irq_base + irq;
+			desc = irq_desc + mq_irq;
+			debug ("mq_irq_demux (irq:%d)\n", mq_irq);
+			desc->handle (mq_irq, desc, regs);
+			mask >>= i;
+		}
+	}
+
+	if (!timeout)
+		printk (KERN_ERR "mq11xx: IRQ continuously triggered, mask %08x\n", mask);
+
+	debug ("mq_irq_demux LEAVE\n");
+
+	mqdata->base.regs->IC.control |= MQ_INTERRUPT_CONTROL_INTERRUPT_ENABLE;
+}
+
+/* Acknowledge, clear _AND_ disable the interrupt. */
+static void
+mq_irq_ack (unsigned int irq)
+{
+	struct mq_data *mqdata = get_irq_chipdata (irq);
+	u32 mask = 1 << (irq - mqdata->base.irq_base);
+	/* Disable the IRQ */
+	mqdata->base.regs->IC.interrupt_mask &= ~mask;
+	/* Acknowledge the IRQ */
+	mqdata->base.regs->IC.interrupt_status = mask;
+}
+
+static void
+mq_irq_mask (unsigned int irq)
+{
+	struct mq_data *mqdata = get_irq_chipdata (irq);
+	u32 mask = 1 << (irq - mqdata->base.irq_base);
+	mqdata->base.regs->IC.interrupt_mask &= ~mask;
+}
+
+static void
+mq_irq_unmask (unsigned int irq)
+{
+	struct mq_data *mqdata = get_irq_chipdata (irq);
+	u32 mask = 1 << (irq - mqdata->base.irq_base);
+	mqdata->base.regs->IC.interrupt_mask |= mask;
+}
+
+static int
+mq_irq_type (unsigned int irq, unsigned int type)
+{
+	struct mq_data *mqdata = get_irq_chipdata (irq);
+	int mask;
+
+	if ((irq < mqdata->base.irq_base + IRQ_MQ_GPIO_0) ||
+	    (irq > mqdata->base.irq_base + IRQ_MQ_GPIO_2))
+		return 0;
+
+	mask = MQ_INTERRUPT_CONTROL_GPIO_0_INTERRUPT_POLARITY <<
+		(irq - mqdata->base.irq_base - IRQ_MQ_GPIO_0);
+
+	if (type & (__IRQT_HIGHLVL | __IRQT_RISEDGE))
+		mqdata->base.regs->IC.control |= mask;
+	else if (type & (__IRQT_LOWLVL | __IRQT_FALEDGE))
+		mqdata->base.regs->IC.control &= ~mask;
+
+	return 0;
+}
+
+static struct irqchip mq_irq_chip = {
+	.ack		= mq_irq_ack,
+	.mask		= mq_irq_mask,
+	.unmask		= mq_irq_unmask,
+	.type		= mq_irq_type,
+};
+
+static int
+mq_irq_init (struct mq_data *mqdata)
+{
+	int i;
+
+	/* Disable all IRQs */
+	mqdata->base.regs->IC.control = 0;
+	mqdata->base.regs->IC.interrupt_mask = 0;
+	/* Clear IRQ status */
+	mqdata->base.regs->IC.interrupt_status = 0xffffffff;
+
+	mqdata->base.irq_base = alloc_irq_space (MQ11xx_NUMIRQS);
+	if (mqdata->base.irq_base < 0) {
+		printk (KERN_ERR "There is no space for %d IRQs in core IRQ table!\n",
+			MQ11xx_NUMIRQS);
+		return -ENOMEM;
+	}
+
+	debug_func ("base IRQ number is %d\n", mqdata->base.irq_base);
+
+	for (i = 0; i < MQ11xx_NUMIRQS; i++) {
+		int irq = mqdata->base.irq_base + i;
+		set_irq_flags (irq, IRQF_VALID);
+		set_irq_chip (irq, &mq_irq_chip);
+		set_irq_handler (irq, do_level_IRQ);
+		set_irq_chipdata (irq, mqdata);
+	}
+
+	i = (mqdata->base.regs->IC.control & MQ_INTERRUPT_CONTROL_INTERRUPT_POLARITY);
+	set_irq_chained_handler (mqdata->irq_nr, mq_irq_demux);
+	set_irq_type (mqdata->irq_nr, i ? IRQT_RISING : IRQT_FALLING);
+	set_irq_data (mqdata->irq_nr, mqdata);
+
+	/* Globally enable IRQs from MediaQ */
+	mqdata->base.regs->IC.control |= MQ_INTERRUPT_CONTROL_INTERRUPT_ENABLE;
+
+	return 0;
+}
+
+static void
+mq_irq_free (struct mq_data *mqdata)
+{
+	/* Disable all IRQs */
+	mqdata->base.regs->IC.control = 0;
+	mqdata->base.regs->IC.interrupt_mask = 0;
+	/* Clear IRQ status */
+	mqdata->base.regs->IC.interrupt_status = 0xffffffff;
+
+	set_irq_handler (mqdata->irq_nr, do_edge_IRQ);
+
+	free_irq_space (mqdata->base.irq_base, MQ11xx_NUMIRQS);
+}
+#endif
+
+int
+mq_device_enum (struct mediaq11xx_base **list, int list_size)
+{
+	int i, j;
+
+	if (!list_size)
+		return 0;
+
+	spin_lock (&mq_device_list_lock);
+	for (i = j = 0; i < MAX_MQ11XX_DEVICES; i++)
+		if (mq_device_list [i]) {
+			list [j++] = mq_device_list [i];
+			if (j >= list_size)
+				break;
+		}
+	spin_unlock (&mq_device_list_lock);
+
+        return j;
+}
+EXPORT_SYMBOL (mq_device_enum);
+
+int
+mq_driver_get (void)
+{
+	return try_module_get (THIS_MODULE) ? 0 : -ENXIO;
+}
+EXPORT_SYMBOL (mq_driver_get);
+
+void
+mq_driver_put (void)
+{
+	module_put (THIS_MODULE);
+}
+EXPORT_SYMBOL (mq_driver_put);
+
+/*
+ * Resources specified in resource table for this driver are:
+ * 0: Synchronous RAM address (physical base + 0 on ARM arch)
+ * 1: Asynchronous RAM address (physical base + 256K+2K on ARM arch)
+ * 2: Registers address (physical base + 256K on ARM arch)
+ * 3: The MediaQ IRQ number
+ *
+ * Also the platform_data field of the device should contain a pointer to
+ * a mq11xx_platform_data structure, which contains the platform-specific
+ * initialization data for MediaQ chip, the name of framebuffer driver
+ * and the name of LCD driver.
+ */
+static int
+mq_initialize (struct device *dev, int num_resources,
+	       struct resource *resource, int instance)
+{
+	int i, j, k, rc, chipmask;
+	struct mq_data *mqdata;
+	struct mediaq11xx_init_data *init_data =
+		(struct mediaq11xx_init_data *)dev->platform_data;
+
+	if (!init_data || num_resources != 4) {
+		printk (KERN_ERR "mq11xx_base: Incorrect platform resources!\n");
+		return -ENODEV;
+	}
+
+	mqdata = kmalloc (sizeof (struct mq_data), GFP_KERNEL);
+	if (!mqdata)
+		return -ENOMEM;
+	memset (mqdata, 0, sizeof (struct mq_data));
+	dev_set_drvdata (dev, mqdata);
+
+#define IOREMAP(v, n, el) \
+	mqdata->base.v = ioremap (resource[n].start, \
+		resource[n].end - resource[n].start + 1); \
+	if (!mqdata->base.v) goto el; \
+	mqdata->base.paddr_##v = resource[n].start;
+
+	IOREMAP (gfxram, 0, err0);
+	IOREMAP (ram, 1, err1);
+	IOREMAP (regs, 2, err2);
+
+#undef IOREMAP
+
+	/* Check how much RAM is accessible through the unsynced window */
+	mqdata->unsynced_ram_skip =
+		(resource [0].end - resource [0].start) -
+		(resource [1].end - resource [1].start);
+	mqdata->base.ram -= mqdata->unsynced_ram_skip;
+	mqdata->base.paddr_ram -= mqdata->unsynced_ram_skip;
+
+	mqdata->ndevices = MQ_SUBDEVS_REAL_COUNT;
+	mqdata->devices = kmalloc (mqdata->ndevices *
+		(sizeof (struct platform_device)), GFP_KERNEL);
+	if (!mqdata->devices)
+		goto err3;
+
+	mqdata->mq_init = init_data;
+	if (mq11xx_init (mqdata)) {
+		printk (KERN_ERR "MediaQ device initialization failed!\n");
+		return -ENODEV;
+	}
+
+	mqdata->irq_nr = resource[3].start;
+	mqdata->base.set_GPIO = mq_set_GPIO;
+	mqdata->base.get_GPIO = mq_get_GPIO;
+	mqdata->base.set_power = mq_set_power;
+	mqdata->base.get_power = mq_get_power;
+	mqdata->base.alloc = mq_alloc;
+	mqdata->base.free = mq_free;
+
+	/* Initialize memory manager */
+	spin_lock_init (&mqdata->mem_lock);
+	mqdata->nfreeblocks = 1;
+	mqdata->maxfreeblocks = MEMBLOCK_MINCOUNT;
+	mqdata->freelist = kmalloc (MEMBLOCK_MINCOUNT * sizeof (struct mq_freemem_list),
+				    GFP_KERNEL);
+	mqdata->freelist [0].addr = 0;
+	mqdata->freelist [0].size = MQ11xx_FB_SIZE;
+
+#if defined MQ_IRQ_MULTIPLEX
+	if ((mqdata->irq_nr != -1) && mq_irq_init (mqdata))
+		goto err4;
+#endif
+
+	for (i = j = 0; j < MQ_SUBDEVS_COUNT; i++) {
+		struct platform_device *sdev = &mqdata->devices[i];
+		const struct mq_block *blk = &mq_blocks[j];
+		struct resource *res;
+		int old_j, k;
+
+		memset (sdev, 0, sizeof (struct platform_device));
+		sdev->id = blk->id.id; /* placeholder id */
+		sdev->name = blk->name;
+		sdev->dev.parent = dev;
+		sdev->dev.release = mq_release;
+		sdev->dev.platform_data = &mqdata->base;
+
+		/* Count number of resources */
+		sdev->num_resources = 2;
+		old_j = j;
+		while (mq_blocks [++j].id.id == sdev->id)
+			/* One resource for _MEM and one for _PLATFORM_VIRTUAL */
+			sdev->num_resources += 2;
+
+		res = kmalloc (sdev->num_resources * sizeof (struct resource), GFP_KERNEL);
+		sdev->resource = res;
+		memset (res, 0, sdev->num_resources * sizeof (struct resource));
+
+		for (j = old_j, k = 0; mq_blocks [j].id.id == sdev->id; j++) {
+			blk = &mq_blocks[j];
+			res[k].start = resource[2].start + blk->start;
+			res[k].end = resource[2].start + blk->end;
+			res[k].parent = &resource[2];
+			res[k++].flags = IORESOURCE_MEM;
+			res[k].start = (unsigned)mqdata->base.regs + blk->start;
+			res[k].end = (unsigned)mqdata->base.regs + blk->end;
+                }
+
+		mqdata->power_on [i] = 1;;
+	}
+
+	/* Second pass */
+	chipmask = 1 << mqdata->base.chip;
+	for (i = j = k = 0; j < MQ_SUBDEVS_COUNT; i++) {
+		struct platform_device *sdev = &mqdata->devices[i];
+                const struct mq_block *blk = &mq_blocks[j];
+
+		while (mq_blocks [++j].id.id == sdev->id)
+			;
+
+		/* Power off all subdevices */
+		mq_power_off (&mqdata->base, sdev->id);
+
+		if (!(blk->mask & chipmask))
+			continue;
+
+		sdev->id = instance;
+		rc = platform_device_register (sdev);
+		if (rc) {
+			printk (KERN_ERR "Failed to register MediaQ subdevice `%s', code %d\n",
+			        blk->name, rc);
+			goto err5;
+		}
+	}
+
+	printk (KERN_INFO "MediaQ %s chip detected, ", mqdata->base.chipname);
+#ifdef MQ_IRQ_MULTIPLEX
+	if (mqdata->base.irq_base)
+		printk ("base IRQ %d\n", mqdata->base.irq_base);
+	else
+		printk ("\n");
+#endif
+
+	spin_lock (&mq_device_list_lock);
+	for (i = 0; i < MAX_MQ11XX_DEVICES; i++)
+		if (!mq_device_list [i]) {
+			mq_device_list [i] = &mqdata->base;
+			break;
+		}
+	spin_unlock (&mq_device_list_lock);
+
+	return 0;
+
+err5:	while (--i >= 0) {
+		platform_device_unregister (&mqdata->devices[i]);
+		kfree (mqdata->devices[i].resource);
+	}
+
+#if defined MQ_IRQ_MULTIPLEX
+	if (mqdata->irq_nr != -1)
+		mq_irq_free (mqdata);
+#endif
+#ifdef MQ_IRQ_MULTIPLEX
+err4:	kfree (mqdata->devices);
+#endif
+err3:	iounmap ((void *)mqdata->base.regs);
+err2:	iounmap ((void *)mqdata->base.ram);
+err1:	iounmap (mqdata->base.gfxram);
+err0:	kfree (mqdata);
+
+	printk (KERN_ERR "MediaQ base SoC driver initialization failed\n");
+
+	return -ENOMEM;
+}
+
+static int
+mq_finalize (struct device *dev)
+{
+	int i;
+	struct mq_data *mqdata = dev_get_drvdata (dev);
+
+	spin_lock (&mq_device_list_lock);
+	for (i = 0; i < MAX_MQ11XX_DEVICES; i++)
+		if (mq_device_list [i] == &mqdata->base) {
+			mq_device_list [i] = NULL;
+			break;
+		}
+	spin_unlock (&mq_device_list_lock);
+
+	for (i = 0; i < mqdata->ndevices; i++) {
+		platform_device_unregister (&mqdata->devices[i]);
+		kfree (mqdata->devices[i].resource);
+	}
+
+#if defined MQ_IRQ_MULTIPLEX
+	if (mqdata->irq_nr != -1)
+		mq_irq_free (mqdata);
+#endif
+
+	kfree (mqdata->devices);
+
+	iounmap ((void *)mqdata->base.regs);
+	iounmap ((void *)mqdata->base.ram);
+	iounmap (mqdata->base.gfxram);
+
+	kfree (mqdata);
+
+	return 0;
+}
+
+/* This is the platform device handler. If MediaQ is connected to a different
+ * bus type (e.g. PCI) a similar device_driver structure should be registered
+ * for that bus. For now this is not implemented.
+ */
+
+static int
+mq_probe (struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device (dev);
+	return mq_initialize (dev, pdev->num_resources, pdev->resource,
+			      pdev->id);
+}
+
+static int
+mq_remove (struct device *dev)
+{
+	return mq_finalize (dev);
+}
+
+static void
+mq_shutdown (struct device *dev)
+{
+	//struct mq_data *mqdata = dev_get_drvdata (dev);
+}
+
+static int
+mq_suspend (struct device *dev, u32 state, u32 level)
+{
+	//struct mq_data *mqdata = dev_get_drvdata (dev);
+	return 0;
+}
+
+static int
+mq_resume (struct device *dev, u32 level)
+{
+	//struct mq_data *mqdata = dev_get_drvdata (dev);
+	return 0;
+}
+
+static struct device_driver mq_device_driver = {
+	.name		= "mq11xx",
+	.bus		= &platform_bus_type,
+
+	.probe		= mq_probe,
+	.remove		= mq_remove,
+	.suspend	= mq_suspend,
+	.resume		= mq_resume,
+	.shutdown	= mq_shutdown,
+};
+
+static int __init
+mq_base_init (void)
+{
+	return driver_register (&mq_device_driver);
+}
+
+static void __exit
+mq_base_exit (void)
+{
+	driver_unregister (&mq_device_driver);
+}
+
+module_init (mq_base_init)
+module_exit (mq_base_exit)
+
+MODULE_AUTHOR("Andrew Zabolotny <[email protected]>");
+MODULE_DESCRIPTION("MediaQ 1100/1132 base SoC support");
+MODULE_LICENSE("GPL");
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]
  Powered by Linux