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

jamey_at_crl.dec.com
Date: 08/02/05

  • Next message: Ingo Molnar: "Re: [patch] remove sys_set_zone_reclaim()"
    To: linux-kernel@vger.kernel.org
    Date:	Tue,  2 Aug 2005 15:20:41 -0400 (EDT)
    
    

    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 <jamey@handhelds.org>
    Signed-off-by: Andrew Zabolotny <anpaza@mail.ru>

    ---
    commit d1144b4da9a00634c14dfed3a56f8491749b9f01
    tree 66014fccdb508b698e326bbf8158d40161a39226
    parent 5f367e62a65136321593c193391a186f56f81b93
    author <jamey@lspace.crl.dec.com> Tue, 02 Aug 2005 11:24:55 -0400
    committer <jamey@lspace.crl.dec.com> 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 <anpaza@mail.ru>
    + * 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 <anpaza@mail.ru>
    + * 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 ***;
    + * 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 <anpaza@mail.ru>");
    +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 majordomo@vger.kernel.org
    More majordomo info at  http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at  http://www.tux.org/lkml/
    

  • Next message: Ingo Molnar: "Re: [patch] remove sys_set_zone_reclaim()"