[ARM] pxa: PXA3xx base support

Signed-off-by: eric miao <eric.y.miao@gmail.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig
index 5ebec6d..e895188 100644
--- a/arch/arm/mach-pxa/Kconfig
+++ b/arch/arm/mach-pxa/Kconfig
@@ -1,6 +1,24 @@
 if ARCH_PXA
 
-menu "Intel PXA2xx Implementations"
+menu "Intel PXA2xx/PXA3xx Implementations"
+
+if PXA3xx
+
+menu "Supported PXA3xx Processor Variants"
+
+config CPU_PXA300
+	bool "PXA300 (codename Monahans-L)"
+
+config CPU_PXA310
+	bool "PXA310 (codename Monahans-LV)"
+	select CPU_PXA300
+
+config CPU_PXA320
+	bool "PXA320 (codename Monahans-P)"
+
+endmenu
+
+endif
 
 choice
 	prompt "Select target board"
@@ -41,6 +59,10 @@
 	bool "CompuLab EM-x270 platform"
 	select PXA27x
 
+config MACH_ZYLONITE
+	bool "PXA3xx Development Platform"
+	select PXA3xx
+
 endchoice
 
 if PXA_SHARPSL
@@ -130,6 +152,11 @@
 	help
 	  Select code specific to PXA27x variants
 
+config PXA3xx
+	bool
+	help
+	  Select code specific to PXA3xx variants
+
 config PXA_SHARP_C7xx
 	bool
 	select PXA_SSP
diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile
index 8970928..bfdd0c5 100644
--- a/arch/arm/mach-pxa/Makefile
+++ b/arch/arm/mach-pxa/Makefile
@@ -6,6 +6,9 @@
 obj-y				+= clock.o generic.o irq.o dma.o time.o
 obj-$(CONFIG_PXA25x)		+= pxa25x.o
 obj-$(CONFIG_PXA27x)		+= pxa27x.o
+obj-$(CONFIG_PXA3xx)		+= pxa3xx.o mfp.o
+obj-$(CONFIG_CPU_PXA300)	+= pxa300.o
+obj-$(CONFIG_CPU_PXA320)	+= pxa320.o
 
 # Specific board support
 obj-$(CONFIG_ARCH_LUBBOCK)	+= lubbock.o
@@ -20,6 +23,12 @@
 obj-$(CONFIG_MACH_TOSA)		+= tosa.o
 obj-$(CONFIG_MACH_EM_X270)	+= em-x270.o
 
+ifeq ($(CONFIG_MACH_ZYLONITE),y)
+  obj-y				+= zylonite.o
+  obj-$(CONFIG_CPU_PXA300)	+= zylonite_pxa300.o
+  obj-$(CONFIG_CPU_PXA320)	+= zylonite_pxa320.o
+endif
+
 # Support for blinky lights
 led-y := leds.o
 led-$(CONFIG_ARCH_LUBBOCK)	+= leds-lubbock.o
diff --git a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c
index eed95eaf..2263a84 100644
--- a/arch/arm/mach-pxa/generic.c
+++ b/arch/arm/mach-pxa/generic.c
@@ -51,8 +51,10 @@
 {
 	if (cpu_is_pxa21x() || cpu_is_pxa25x())
 		return pxa25x_get_clk_frequency_khz(info);
-	else
+	else if (cpu_is_pxa27x())
 		return pxa27x_get_clk_frequency_khz(info);
+	else
+		return pxa3xx_get_clk_frequency_khz(info);
 }
 EXPORT_SYMBOL(get_clk_frequency_khz);
 
@@ -63,8 +65,10 @@
 {
 	if (cpu_is_pxa21x() || cpu_is_pxa25x())
 		return pxa25x_get_memclk_frequency_10khz();
-	else
+	else if (cpu_is_pxa27x())
 		return pxa27x_get_memclk_frequency_10khz();
+	else
+		return pxa3xx_get_memclk_frequency_10khz();
 }
 EXPORT_SYMBOL(get_memclk_frequency_10khz);
 
diff --git a/arch/arm/mach-pxa/generic.h b/arch/arm/mach-pxa/generic.h
index 2c4fe61..b30f240 100644
--- a/arch/arm/mach-pxa/generic.h
+++ b/arch/arm/mach-pxa/generic.h
@@ -18,6 +18,7 @@
 extern void __init pxa_init_irq_set_wake(int (*set_wake)(unsigned int, unsigned int));
 extern void __init pxa25x_init_irq(void);
 extern void __init pxa27x_init_irq(void);
+extern void __init pxa3xx_init_irq(void);
 extern void __init pxa_map_io(void);
 
 extern unsigned int get_clk_frequency_khz(int info);
@@ -44,3 +45,10 @@
 #define pxa27x_get_memclk_frequency_10khz()	(0)
 #endif
 
+#ifdef CONFIG_PXA3xx
+extern unsigned pxa3xx_get_clk_frequency_khz(int);
+extern unsigned pxa3xx_get_memclk_frequency_10khz(void);
+#else
+#define pxa3xx_get_clk_frequency_khz(x)		(0)
+#define pxa3xx_get_memclk_frequency_10khz()	(0)
+#endif
diff --git a/arch/arm/mach-pxa/irq.c b/arch/arm/mach-pxa/irq.c
index 294cc67..07acb45 100644
--- a/arch/arm/mach-pxa/irq.c
+++ b/arch/arm/mach-pxa/irq.c
@@ -65,7 +65,7 @@
 	}
 }
 
-#ifdef CONFIG_PXA27x
+#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx)
 
 /*
  * This is for the second set of internal IRQs as found on the PXA27x.
diff --git a/arch/arm/mach-pxa/mfp.c b/arch/arm/mach-pxa/mfp.c
new file mode 100644
index 0000000..5cd3cad
--- /dev/null
+++ b/arch/arm/mach-pxa/mfp.c
@@ -0,0 +1,235 @@
+/*
+ * linux/arch/arm/mach-pxa/mfp.c
+ *
+ * PXA3xx Multi-Function Pin Support
+ *
+ * Copyright (C) 2007 Marvell Internation Ltd.
+ *
+ * 2007-08-21: eric miao <eric.y.miao@gmail.com>
+ *             initial version
+ *
+ *  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/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+
+#include <asm/hardware.h>
+#include <asm/arch/mfp.h>
+
+/* mfp_spin_lock is used to ensure that MFP register configuration
+ * (most likely a read-modify-write operation) is atomic, and that
+ * mfp_table[] is consistent
+ */
+static DEFINE_SPINLOCK(mfp_spin_lock);
+
+static void __iomem *mfpr_mmio_base = (void __iomem *)&__REG(MFPR_BASE);
+static struct pxa3xx_mfp_pin mfp_table[MFP_PIN_MAX];
+
+#define mfpr_readl(off)			\
+	__raw_readl(mfpr_mmio_base + (off))
+
+#define mfpr_writel(off, val)		\
+	__raw_writel(val, mfpr_mmio_base + (off))
+
+/*
+ * perform a read-back of any MFPR register to make sure the
+ * previous writings are finished
+ */
+#define mfpr_sync()	(void)__raw_readl(mfpr_mmio_base + 0)
+
+static inline void __mfp_config(int pin, unsigned long val)
+{
+	unsigned long off = mfp_table[pin].mfpr_off;
+
+	mfp_table[pin].mfpr_val = val;
+	mfpr_writel(off, val);
+}
+
+void pxa3xx_mfp_config(mfp_cfg_t *mfp_cfgs, int num)
+{
+	int i, pin;
+	unsigned long val, flags;
+	mfp_cfg_t *mfp_cfg = mfp_cfgs;
+
+	spin_lock_irqsave(&mfp_spin_lock, flags);
+
+	for (i = 0; i < num; i++, mfp_cfg++) {
+		pin = MFP_CFG_PIN(*mfp_cfg);
+		val = MFP_CFG_VAL(*mfp_cfg);
+
+		BUG_ON(pin >= MFP_PIN_MAX);
+
+		__mfp_config(pin, val);
+	}
+
+	mfpr_sync();
+	spin_unlock_irqrestore(&mfp_spin_lock, flags);
+}
+
+unsigned long pxa3xx_mfp_read(int mfp)
+{
+	unsigned long val, flags;
+
+	BUG_ON(mfp >= MFP_PIN_MAX);
+
+	spin_lock_irqsave(&mfp_spin_lock, flags);
+	val = mfpr_readl(mfp_table[mfp].mfpr_off);
+	spin_unlock_irqrestore(&mfp_spin_lock, flags);
+
+	return val;
+}
+
+void pxa3xx_mfp_write(int mfp, unsigned long val)
+{
+	unsigned long flags;
+
+	BUG_ON(mfp >= MFP_PIN_MAX);
+
+	spin_lock_irqsave(&mfp_spin_lock, flags);
+	mfpr_writel(mfp_table[mfp].mfpr_off, val);
+	mfpr_sync();
+	spin_unlock_irqrestore(&mfp_spin_lock, flags);
+}
+
+void pxa3xx_mfp_set_afds(int mfp, int af, int ds)
+{
+	uint32_t mfpr_off, mfpr_val;
+	unsigned long flags;
+
+	BUG_ON(mfp >= MFP_PIN_MAX);
+
+	spin_lock_irqsave(&mfp_spin_lock, flags);
+	mfpr_off = mfp_table[mfp].mfpr_off;
+
+	mfpr_val = mfpr_readl(mfpr_off);
+	mfpr_val &= ~(MFPR_AF_MASK | MFPR_DRV_MASK);
+	mfpr_val |= (((af & 0x7) << MFPR_ALT_OFFSET) |
+		     ((ds & 0x7) << MFPR_DRV_OFFSET));
+
+	mfpr_writel(mfpr_off, mfpr_val);
+	mfpr_sync();
+
+	spin_unlock_irqrestore(&mfp_spin_lock, flags);
+}
+
+void pxa3xx_mfp_set_rdh(int mfp, int rdh)
+{
+	uint32_t mfpr_off, mfpr_val;
+	unsigned long flags;
+
+	BUG_ON(mfp >= MFP_PIN_MAX);
+
+	spin_lock_irqsave(&mfp_spin_lock, flags);
+
+	mfpr_off = mfp_table[mfp].mfpr_off;
+
+	mfpr_val = mfpr_readl(mfpr_off);
+	mfpr_val &= ~MFPR_RDH_MASK;
+
+	if (likely(rdh))
+		mfpr_val |= (1u << MFPR_SS_OFFSET);
+
+	mfpr_writel(mfpr_off, mfpr_val);
+	mfpr_sync();
+
+	spin_unlock_irqrestore(&mfp_spin_lock, flags);
+}
+
+void pxa3xx_mfp_set_lpm(int mfp, int lpm)
+{
+	uint32_t mfpr_off, mfpr_val;
+	unsigned long flags;
+
+	BUG_ON(mfp >= MFP_PIN_MAX);
+
+	spin_lock_irqsave(&mfp_spin_lock, flags);
+
+	mfpr_off = mfp_table[mfp].mfpr_off;
+	mfpr_val = mfpr_readl(mfpr_off);
+	mfpr_val &= ~MFPR_LPM_MASK;
+
+	if (lpm & 0x1) mfpr_val |= 1u << MFPR_SON_OFFSET;
+	if (lpm & 0x2) mfpr_val |= 1u << MFPR_SD_OFFSET;
+	if (lpm & 0x4) mfpr_val |= 1u << MFPR_PU_OFFSET;
+	if (lpm & 0x8) mfpr_val |= 1u << MFPR_PD_OFFSET;
+	if (lpm &0x10) mfpr_val |= 1u << MFPR_PS_OFFSET;
+
+	mfpr_writel(mfpr_off, mfpr_val);
+	mfpr_sync();
+
+	spin_unlock_irqrestore(&mfp_spin_lock, flags);
+}
+
+void pxa3xx_mfp_set_pull(int mfp, int pull)
+{
+	uint32_t mfpr_off, mfpr_val;
+	unsigned long flags;
+
+	BUG_ON(mfp >= MFP_PIN_MAX);
+
+	spin_lock_irqsave(&mfp_spin_lock, flags);
+
+	mfpr_off = mfp_table[mfp].mfpr_off;
+	mfpr_val = mfpr_readl(mfpr_off);
+	mfpr_val &= ~MFPR_PULL_MASK;
+	mfpr_val |= ((pull & 0x7u) << MFPR_PD_OFFSET);
+
+	mfpr_writel(mfpr_off, mfpr_val);
+	mfpr_sync();
+
+	spin_unlock_irqrestore(&mfp_spin_lock, flags);
+}
+
+void pxa3xx_mfp_set_edge(int mfp, int edge)
+{
+	uint32_t mfpr_off, mfpr_val;
+	unsigned long flags;
+
+	BUG_ON(mfp >= MFP_PIN_MAX);
+
+	spin_lock_irqsave(&mfp_spin_lock, flags);
+
+	mfpr_off = mfp_table[mfp].mfpr_off;
+	mfpr_val = mfpr_readl(mfpr_off);
+
+	mfpr_val &= ~MFPR_EDGE_MASK;
+	mfpr_val |= (edge & 0x3u) << MFPR_ERE_OFFSET;
+	mfpr_val |= (!edge & 0x1) << MFPR_EC_OFFSET;
+
+	mfpr_writel(mfpr_off, mfpr_val);
+	mfpr_sync();
+
+	spin_unlock_irqrestore(&mfp_spin_lock, flags);
+}
+
+void __init pxa3xx_mfp_init_addr(struct pxa3xx_mfp_addr_map *map)
+{
+	struct pxa3xx_mfp_addr_map *p;
+	unsigned long offset, flags;
+	int i;
+
+	spin_lock_irqsave(&mfp_spin_lock, flags);
+
+	for (p = map; p->start != MFP_PIN_INVALID; p++) {
+		offset = p->offset;
+		i = p->start;
+
+		do {
+			mfp_table[i].mfpr_off = offset;
+			mfp_table[i].mfpr_val = 0;
+			offset += 4; i++;
+		} while ((i <= p->end) && (p->end != -1));
+	}
+
+	spin_unlock_irqrestore(&mfp_spin_lock, flags);
+}
+
+void __init pxa3xx_init_mfp(void)
+{
+	memset(mfp_table, 0, sizeof(mfp_table));
+}
diff --git a/arch/arm/mach-pxa/pxa300.c b/arch/arm/mach-pxa/pxa300.c
new file mode 100644
index 0000000..5363b13
--- /dev/null
+++ b/arch/arm/mach-pxa/pxa300.c
@@ -0,0 +1,93 @@
+/*
+ * linux/arch/arm/mach-pxa/pxa300.c
+ *
+ * Code specific to PXA300/PXA310
+ *
+ * Copyright (C) 2007 Marvell Internation Ltd.
+ *
+ * 2007-08-21: eric miao <eric.y.miao@gmail.com>
+ *             initial version
+ *
+ * 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/kernel.h>
+
+#include <asm/hardware.h>
+#include <asm/arch/mfp-pxa300.h>
+
+static struct pxa3xx_mfp_addr_map pxa300_mfp_addr_map[] __initdata = {
+
+	MFP_ADDR_X(GPIO0,   GPIO2,   0x00b4),
+	MFP_ADDR_X(GPIO3,   GPIO26,  0x027c),
+	MFP_ADDR_X(GPIO27,  GPIO127, 0x0400),
+	MFP_ADDR_X(GPIO0_2, GPIO6_2, 0x02ec),
+
+	MFP_ADDR(nBE0, 0x0204),
+	MFP_ADDR(nBE1, 0x0208),
+
+	MFP_ADDR(nLUA, 0x0244),
+	MFP_ADDR(nLLA, 0x0254),
+
+	MFP_ADDR(DF_CLE_nOE, 0x0240),
+	MFP_ADDR(DF_nRE_nOE, 0x0200),
+	MFP_ADDR(DF_ALE_nWE, 0x020C),
+	MFP_ADDR(DF_INT_RnB, 0x00C8),
+	MFP_ADDR(DF_nCS0, 0x0248),
+	MFP_ADDR(DF_nCS1, 0x0278),
+	MFP_ADDR(DF_nWE, 0x00CC),
+
+	MFP_ADDR(DF_ADDR0, 0x0210),
+	MFP_ADDR(DF_ADDR1, 0x0214),
+	MFP_ADDR(DF_ADDR2, 0x0218),
+	MFP_ADDR(DF_ADDR3, 0x021C),
+
+	MFP_ADDR(DF_IO0, 0x0220),
+	MFP_ADDR(DF_IO1, 0x0228),
+	MFP_ADDR(DF_IO2, 0x0230),
+	MFP_ADDR(DF_IO3, 0x0238),
+	MFP_ADDR(DF_IO4, 0x0258),
+	MFP_ADDR(DF_IO5, 0x0260),
+	MFP_ADDR(DF_IO6, 0x0268),
+	MFP_ADDR(DF_IO7, 0x0270),
+	MFP_ADDR(DF_IO8, 0x0224),
+	MFP_ADDR(DF_IO9, 0x022C),
+	MFP_ADDR(DF_IO10, 0x0234),
+	MFP_ADDR(DF_IO11, 0x023C),
+	MFP_ADDR(DF_IO12, 0x025C),
+	MFP_ADDR(DF_IO13, 0x0264),
+	MFP_ADDR(DF_IO14, 0x026C),
+	MFP_ADDR(DF_IO15, 0x0274),
+
+	MFP_ADDR_END,
+};
+
+/* override pxa300 MFP register addresses */
+static struct pxa3xx_mfp_addr_map pxa310_mfp_addr_map[] __initdata = {
+	MFP_ADDR_X(GPIO30,  GPIO98,   0x0418),
+	MFP_ADDR_X(GPIO7_2, GPIO12_2, 0x052C),
+
+	MFP_ADDR(ULPI_STP, 0x040C),
+	MFP_ADDR(ULPI_NXT, 0x0410),
+	MFP_ADDR(ULPI_DIR, 0x0414),
+
+	MFP_ADDR_END,
+};
+
+static int __init pxa300_init(void)
+{
+	if (cpu_is_pxa300() || cpu_is_pxa310()) {
+		pxa3xx_init_mfp();
+		pxa3xx_mfp_init_addr(pxa300_mfp_addr_map);
+	}
+
+	if (cpu_is_pxa310())
+		pxa3xx_mfp_init_addr(pxa310_mfp_addr_map);
+
+	return 0;
+}
+
+core_initcall(pxa300_init);
diff --git a/arch/arm/mach-pxa/pxa320.c b/arch/arm/mach-pxa/pxa320.c
new file mode 100644
index 0000000..cd9eba5
--- /dev/null
+++ b/arch/arm/mach-pxa/pxa320.c
@@ -0,0 +1,88 @@
+/*
+ * linux/arch/arm/mach-pxa/pxa320.c
+ *
+ * Code specific to PXA320
+ *
+ * Copyright (C) 2007 Marvell Internation Ltd.
+ *
+ * 2007-08-21: eric miao <eric.y.miao@gmail.com>
+ *             initial version
+ *
+ * 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/kernel.h>
+
+#include <asm/hardware.h>
+#include <asm/arch/mfp.h>
+#include <asm/arch/mfp-pxa320.h>
+
+static struct pxa3xx_mfp_addr_map pxa320_mfp_addr_map[] __initdata = {
+
+	MFP_ADDR_X(GPIO0,  GPIO4,   0x0124),
+	MFP_ADDR_X(GPIO5,  GPIO26,  0x028C),
+	MFP_ADDR_X(GPIO27, GPIO62,  0x0400),
+	MFP_ADDR_X(GPIO63, GPIO73,  0x04B4),
+	MFP_ADDR_X(GPIO74, GPIO98,  0x04F0),
+	MFP_ADDR_X(GPIO99, GPIO127, 0x0600),
+	MFP_ADDR_X(GPIO0_2,  GPIO5_2,   0x0674),
+	MFP_ADDR_X(GPIO6_2,  GPIO13_2,  0x0494),
+	MFP_ADDR_X(GPIO14_2, GPIO17_2, 0x04E0),
+
+	MFP_ADDR(nXCVREN, 0x0138),
+	MFP_ADDR(DF_CLE_nOE, 0x0204),
+	MFP_ADDR(DF_nADV1_ALE, 0x0208),
+	MFP_ADDR(DF_SCLK_S, 0x020C),
+	MFP_ADDR(DF_SCLK_E, 0x0210),
+	MFP_ADDR(nBE0, 0x0214),
+	MFP_ADDR(nBE1, 0x0218),
+	MFP_ADDR(DF_nADV2_ALE, 0x021C),
+	MFP_ADDR(DF_INT_RnB, 0x0220),
+	MFP_ADDR(DF_nCS0, 0x0224),
+	MFP_ADDR(DF_nCS1, 0x0228),
+	MFP_ADDR(DF_nWE, 0x022C),
+	MFP_ADDR(DF_nRE_nOE, 0x0230),
+	MFP_ADDR(nLUA, 0x0234),
+	MFP_ADDR(nLLA, 0x0238),
+	MFP_ADDR(DF_ADDR0, 0x023C),
+	MFP_ADDR(DF_ADDR1, 0x0240),
+	MFP_ADDR(DF_ADDR2, 0x0244),
+	MFP_ADDR(DF_ADDR3, 0x0248),
+	MFP_ADDR(DF_IO0, 0x024C),
+	MFP_ADDR(DF_IO8, 0x0250),
+	MFP_ADDR(DF_IO1, 0x0254),
+	MFP_ADDR(DF_IO9, 0x0258),
+	MFP_ADDR(DF_IO2, 0x025C),
+	MFP_ADDR(DF_IO10, 0x0260),
+	MFP_ADDR(DF_IO3, 0x0264),
+	MFP_ADDR(DF_IO11, 0x0268),
+	MFP_ADDR(DF_IO4, 0x026C),
+	MFP_ADDR(DF_IO12, 0x0270),
+	MFP_ADDR(DF_IO5, 0x0274),
+	MFP_ADDR(DF_IO13, 0x0278),
+	MFP_ADDR(DF_IO6, 0x027C),
+	MFP_ADDR(DF_IO14, 0x0280),
+	MFP_ADDR(DF_IO7, 0x0284),
+	MFP_ADDR(DF_IO15, 0x0288),
+
+	MFP_ADDR_END,
+};
+
+static void __init pxa320_init_mfp(void)
+{
+	pxa3xx_init_mfp();
+	pxa3xx_mfp_init_addr(pxa320_mfp_addr_map);
+}
+
+static int __init pxa320_init(void)
+{
+	if (cpu_is_pxa320())
+		pxa320_init_mfp();
+
+	return 0;
+}
+
+core_initcall(pxa320_init);
diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c
new file mode 100644
index 0000000..39f0de8
--- /dev/null
+++ b/arch/arm/mach-pxa/pxa3xx.c
@@ -0,0 +1,216 @@
+/*
+ * linux/arch/arm/mach-pxa/pxa3xx.c
+ *
+ * code specific to pxa3xx aka Monahans
+ *
+ * Copyright (C) 2006 Marvell International Ltd.
+ *
+ * 2007-09-02: eric miao <eric.y.miao@gmail.com>
+ *             initial version
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/pm.h>
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+
+#include <asm/hardware.h>
+#include <asm/arch/pxa3xx-regs.h>
+#include <asm/arch/ohci.h>
+#include <asm/arch/pm.h>
+#include <asm/arch/dma.h>
+#include <asm/arch/ssp.h>
+
+#include "generic.h"
+#include "devices.h"
+#include "clock.h"
+
+/* Crystal clock: 13MHz */
+#define BASE_CLK	13000000
+
+/* Ring Oscillator Clock: 60MHz */
+#define RO_CLK		60000000
+
+#define ACCR_D0CS	(1 << 26)
+
+/* crystal frequency to static memory controller multiplier (SMCFS) */
+static unsigned char smcfs_mult[8] = { 6, 0, 8, 0, 0, 16, };
+
+/* crystal frequency to HSIO bus frequency multiplier (HSS) */
+static unsigned char hss_mult[4] = { 8, 12, 16, 0 };
+
+/*
+ * Get the clock frequency as reflected by CCSR and the turbo flag.
+ * We assume these values have been applied via a fcs.
+ * If info is not 0 we also display the current settings.
+ */
+unsigned int pxa3xx_get_clk_frequency_khz(int info)
+{
+	unsigned long acsr, xclkcfg;
+	unsigned int t, xl, xn, hss, ro, XL, XN, CLK, HSS;
+
+	/* Read XCLKCFG register turbo bit */
+	__asm__ __volatile__("mrc\tp14, 0, %0, c6, c0, 0" : "=r"(xclkcfg));
+	t = xclkcfg & 0x1;
+
+	acsr = ACSR;
+
+	xl  = acsr & 0x1f;
+	xn  = (acsr >> 8) & 0x7;
+	hss = (acsr >> 14) & 0x3;
+
+	XL = xl * BASE_CLK;
+	XN = xn * XL;
+
+	ro = acsr & ACCR_D0CS;
+
+	CLK = (ro) ? RO_CLK : ((t) ? XN : XL);
+	HSS = (ro) ? RO_CLK : hss_mult[hss] * BASE_CLK;
+
+	if (info) {
+		pr_info("RO Mode clock: %d.%02dMHz (%sactive)\n",
+			RO_CLK / 1000000, (RO_CLK % 1000000) / 10000,
+			(ro) ? "" : "in");
+		pr_info("Run Mode clock: %d.%02dMHz (*%d)\n",
+			XL / 1000000, (XL % 1000000) / 10000, xl);
+		pr_info("Turbo Mode clock: %d.%02dMHz (*%d, %sactive)\n",
+			XN / 1000000, (XN % 1000000) / 10000, xn,
+			(t) ? "" : "in");
+		pr_info("HSIO bus clock: %d.%02dMHz\n",
+			HSS / 1000000, (HSS % 1000000) / 10000);
+	}
+
+	return CLK;
+}
+
+/*
+ * Return the current static memory controller clock frequency
+ * in units of 10kHz
+ */
+unsigned int pxa3xx_get_memclk_frequency_10khz(void)
+{
+	unsigned long acsr;
+	unsigned int smcfs, clk = 0;
+
+	acsr = ACSR;
+
+	smcfs = (acsr >> 23) & 0x7;
+	clk = (acsr & ACCR_D0CS) ? RO_CLK : smcfs_mult[smcfs] * BASE_CLK;
+
+	return (clk / 10000);
+}
+
+/*
+ * Return the current HSIO bus clock frequency
+ */
+static unsigned long clk_pxa3xx_hsio_getrate(struct clk *clk)
+{
+	unsigned long acsr;
+	unsigned int hss, hsio_clk;
+
+	acsr = ACSR;
+
+	hss = (acsr >> 14) & 0x3;
+	hsio_clk = (acsr & ACCR_D0CS) ? RO_CLK : hss_mult[hss] * BASE_CLK;
+
+	return hsio_clk;
+}
+
+static void clk_pxa3xx_cken_enable(struct clk *clk)
+{
+	unsigned long mask = 1ul << (clk->cken & 0x1f);
+
+	local_irq_disable();
+
+	if (clk->cken < 32)
+		CKENA |= mask;
+	else
+		CKENB |= mask;
+
+	local_irq_enable();
+}
+
+static void clk_pxa3xx_cken_disable(struct clk *clk)
+{
+	unsigned long mask = 1ul << (clk->cken & 0x1f);
+
+	local_irq_disable();
+
+	if (clk->cken < 32)
+		CKENA &= ~mask;
+	else
+		CKENB &= ~mask;
+
+	local_irq_enable();
+}
+
+static const struct clkops clk_pxa3xx_hsio_ops = {
+	.enable		= clk_pxa3xx_cken_enable,
+	.disable	= clk_pxa3xx_cken_disable,
+	.getrate	= clk_pxa3xx_hsio_getrate,
+};
+
+static struct clk pxa3xx_clks[] = {
+	INIT_CK("LCDCLK", LCD,    &clk_pxa3xx_hsio_ops, &pxa_device_fb.dev),
+	INIT_CK("CAMCLK", CAMERA, &clk_pxa3xx_hsio_ops, NULL),
+
+	INIT_CKEN("UARTCLK", FFUART, 14857000, 1, &pxa_device_ffuart.dev),
+	INIT_CKEN("UARTCLK", BTUART, 14857000, 1, &pxa_device_btuart.dev),
+	INIT_CKEN("UARTCLK", STUART, 14857000, 1, NULL),
+
+	INIT_CKEN("I2CCLK",  I2C,  32842000, 0, &pxa_device_i2c.dev),
+	INIT_CKEN("UDCCLK",  UDC,  48000000, 5, &pxa_device_udc.dev),
+};
+
+void __init pxa3xx_init_irq(void)
+{
+	/* enable CP6 access */
+	u32 value;
+	__asm__ __volatile__("mrc p15, 0, %0, c15, c1, 0\n": "=r"(value));
+	value |= (1 << 6);
+	__asm__ __volatile__("mcr p15, 0, %0, c15, c1, 0\n": :"r"(value));
+
+	pxa_init_irq_low();
+	pxa_init_irq_high();
+	pxa_init_irq_gpio(128);
+}
+
+/*
+ * device registration specific to PXA3xx.
+ */
+
+static struct platform_device *devices[] __initdata = {
+	&pxa_device_mci,
+	&pxa_device_udc,
+	&pxa_device_fb,
+	&pxa_device_ffuart,
+	&pxa_device_btuart,
+	&pxa_device_stuart,
+	&pxa_device_i2c,
+	&pxa_device_i2s,
+	&pxa_device_ficp,
+	&pxa_device_rtc,
+};
+
+static int __init pxa3xx_init(void)
+{
+	int ret = 0;
+
+	if (cpu_is_pxa3xx()) {
+		clks_register(pxa3xx_clks, ARRAY_SIZE(pxa3xx_clks));
+
+		if ((ret = pxa_init_dma(32)))
+			return ret;
+
+		return platform_add_devices(devices, ARRAY_SIZE(devices));
+	}
+	return 0;
+}
+
+subsys_initcall(pxa3xx_init);
diff --git a/arch/arm/mach-pxa/zylonite.c b/arch/arm/mach-pxa/zylonite.c
new file mode 100644
index 0000000..3f18d76
--- /dev/null
+++ b/arch/arm/mach-pxa/zylonite.c
@@ -0,0 +1,184 @@
+/*
+ * linux/arch/arm/mach-pxa/zylonite.c
+ *
+ * Support for the PXA3xx Development Platform (aka Zylonite)
+ *
+ * Copyright (C) 2006 Marvell International Ltd.
+ *
+ * 2007-09-04: eric miao <eric.y.miao@gmail.com>
+ *             rewrite to align with latest kernel
+ *
+ * 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/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/hardware.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/pxafb.h>
+#include <asm/arch/zylonite.h>
+
+#include "generic.h"
+
+int gpio_backlight;
+int gpio_eth_irq;
+
+int lcd_id;
+int lcd_orientation;
+
+static struct resource smc91x_resources[] = {
+	[0] = {
+		.start	= ZYLONITE_ETH_PHYS + 0x300,
+		.end	= ZYLONITE_ETH_PHYS + 0xfffff,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= -1,	/* for run-time assignment */
+		.end	= -1,
+		.flags	= IORESOURCE_IRQ,
+	}
+};
+
+static struct platform_device smc91x_device = {
+	.name		= "smc91x",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(smc91x_resources),
+	.resource	= smc91x_resources,
+};
+
+#if defined(CONFIG_FB_PXA) || (CONFIG_FB_PXA_MODULES)
+static void zylonite_backlight_power(int on)
+{
+	gpio_set_value(gpio_backlight, on);
+}
+
+static struct pxafb_mode_info toshiba_ltm035a776c_mode = {
+	.pixclock		= 110000,
+	.xres			= 240,
+	.yres			= 320,
+	.bpp			= 16,
+	.hsync_len		= 4,
+	.left_margin		= 6,
+	.right_margin		= 4,
+	.vsync_len		= 2,
+	.upper_margin		= 2,
+	.lower_margin		= 3,
+	.sync			= FB_SYNC_VERT_HIGH_ACT,
+};
+
+static struct pxafb_mode_info toshiba_ltm04c380k_mode = {
+	.pixclock		= 50000,
+	.xres			= 640,
+	.yres			= 480,
+	.bpp			= 16,
+	.hsync_len		= 1,
+	.left_margin		= 0x9f,
+	.right_margin		= 1,
+	.vsync_len		= 44,
+	.upper_margin		= 0,
+	.lower_margin		= 0,
+	.sync			= FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
+};
+
+static struct pxafb_mach_info zylonite_toshiba_lcd_info = {
+	.num_modes      	= 1,
+	.lccr0			= LCCR0_Act,
+	.lccr3			= LCCR3_PCP,
+	.pxafb_backlight_power	= zylonite_backlight_power,
+};
+
+static struct pxafb_mode_info sharp_ls037_modes[] = {
+	[0] = {
+		.pixclock	= 158000,
+		.xres		= 240,
+		.yres		= 320,
+		.bpp		= 16,
+		.hsync_len	= 4,
+		.left_margin	= 39,
+		.right_margin	= 39,
+		.vsync_len	= 1,
+		.upper_margin	= 2,
+		.lower_margin	= 3,
+		.sync		= 0,
+	},
+	[1] = {
+		.pixclock	= 39700,
+		.xres		= 480,
+		.yres		= 640,
+		.bpp		= 16,
+		.hsync_len	= 8,
+		.left_margin	= 81,
+		.right_margin	= 81,
+		.vsync_len	= 1,
+		.upper_margin	= 2,
+		.lower_margin	= 7,
+		.sync		= 0,
+	},
+};
+
+static struct pxafb_mach_info zylonite_sharp_lcd_info = {
+	.modes			= sharp_ls037_modes,
+	.num_modes		= 2,
+	.lccr0			= LCCR0_Act,
+	.lccr3			= LCCR3_PCP | LCCR3_HSP | LCCR3_VSP,
+	.pxafb_backlight_power	= zylonite_backlight_power,
+};
+
+static void __init zylonite_init_lcd(void)
+{
+	/* backlight GPIO: output, default on */
+	gpio_direction_output(gpio_backlight, 1);
+
+	if (lcd_id & 0x20) {
+		set_pxa_fb_info(&zylonite_sharp_lcd_info);
+		return;
+	}
+
+	/* legacy LCD panels, it would be handy here if LCD panel type can
+	 * be decided at run-time
+	 */
+	if (1)
+		zylonite_toshiba_lcd_info.modes = &toshiba_ltm035a776c_mode;
+	else
+		zylonite_toshiba_lcd_info.modes = &toshiba_ltm04c380k_mode;
+
+	set_pxa_fb_info(&zylonite_toshiba_lcd_info);
+}
+#else
+static inline void zylonite_init_lcd(void) {}
+#endif
+
+static void __init zylonite_init(void)
+{
+	/* board-processor specific initialization */
+	zylonite_pxa300_init();
+	zylonite_pxa320_init();
+
+	/*
+	 * Note: We depend that the bootloader set
+	 * the correct value to MSC register for SMC91x.
+	 */
+	smc91x_resources[1].start = gpio_to_irq(gpio_eth_irq);
+	smc91x_resources[1].end   = gpio_to_irq(gpio_eth_irq);
+	platform_device_register(&smc91x_device);
+
+	zylonite_init_lcd();
+}
+
+MACHINE_START(ZYLONITE, "PXA3xx Platform Development Kit (aka Zylonite)")
+	.phys_io	= 0x40000000,
+	.boot_params	= 0xa0000100,
+	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
+	.map_io		= pxa_map_io,
+	.init_irq	= pxa3xx_init_irq,
+	.timer		= &pxa_timer,
+	.init_machine	= zylonite_init,
+MACHINE_END
diff --git a/arch/arm/mach-pxa/zylonite_pxa300.c b/arch/arm/mach-pxa/zylonite_pxa300.c
new file mode 100644
index 0000000..b5fbd2f
--- /dev/null
+++ b/arch/arm/mach-pxa/zylonite_pxa300.c
@@ -0,0 +1,188 @@
+/*
+ * linux/arch/arm/mach-pxa/zylonite_pxa300.c
+ *
+ * PXA300/PXA310 specific support code for the
+ * PXA3xx Development Platform (aka Zylonite)
+ *
+ * Copyright (C) 2007 Marvell Internation Ltd.
+ * 2007-08-21: eric miao <eric.y.miao@gmail.com>
+ *             initial version
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+
+#include <asm/gpio.h>
+#include <asm/arch/mfp-pxa300.h>
+#include <asm/arch/zylonite.h>
+
+#define ARRAY_AND_SIZE(x)	(x), ARRAY_SIZE(x)
+
+/* PXA300/PXA310 common configurations */
+static mfp_cfg_t common_mfp_cfg[] __initdata = {
+	/* LCD */
+	GPIO54_LCD_LDD_0,
+	GPIO55_LCD_LDD_1,
+	GPIO56_LCD_LDD_2,
+	GPIO57_LCD_LDD_3,
+	GPIO58_LCD_LDD_4,
+	GPIO59_LCD_LDD_5,
+	GPIO60_LCD_LDD_6,
+	GPIO61_LCD_LDD_7,
+	GPIO62_LCD_LDD_8,
+	GPIO63_LCD_LDD_9,
+	GPIO64_LCD_LDD_10,
+	GPIO65_LCD_LDD_11,
+	GPIO66_LCD_LDD_12,
+	GPIO67_LCD_LDD_13,
+	GPIO68_LCD_LDD_14,
+	GPIO69_LCD_LDD_15,
+	GPIO70_LCD_LDD_16,
+	GPIO71_LCD_LDD_17,
+	GPIO72_LCD_FCLK,
+	GPIO73_LCD_LCLK,
+	GPIO74_LCD_PCLK,
+	GPIO75_LCD_BIAS,
+	GPIO76_LCD_VSYNC,
+	GPIO127_LCD_CS_N,
+
+	/* BTUART */
+	GPIO111_UART2_RTS,
+	GPIO112_UART2_RXD,
+	GPIO113_UART2_TXD,
+	GPIO114_UART2_CTS,
+
+	/* STUART */
+	GPIO109_UART3_TXD,
+	GPIO110_UART3_RXD,
+
+	/* AC97 */
+	GPIO23_AC97_nACRESET,
+	GPIO24_AC97_SYSCLK,
+	GPIO29_AC97_BITCLK,
+	GPIO25_AC97_SDATA_IN_0,
+	GPIO27_AC97_SDATA_OUT,
+	GPIO28_AC97_SYNC,
+
+	/* Keypad */
+	GPIO107_KP_DKIN_0,
+	GPIO108_KP_DKIN_1,
+	GPIO115_KP_MKIN_0,
+	GPIO116_KP_MKIN_1,
+	GPIO117_KP_MKIN_2,
+	GPIO118_KP_MKIN_3,
+	GPIO119_KP_MKIN_4,
+	GPIO120_KP_MKIN_5,
+	GPIO2_2_KP_MKIN_6,
+	GPIO3_2_KP_MKIN_7,
+	GPIO121_KP_MKOUT_0,
+	GPIO122_KP_MKOUT_1,
+	GPIO123_KP_MKOUT_2,
+	GPIO124_KP_MKOUT_3,
+	GPIO125_KP_MKOUT_4,
+	GPIO4_2_KP_MKOUT_5,
+	GPIO5_2_KP_MKOUT_6,
+	GPIO6_2_KP_MKOUT_7,
+};
+
+static mfp_cfg_t pxa300_mfp_cfg[] __initdata = {
+	/* FFUART */
+	GPIO30_UART1_RXD,
+	GPIO31_UART1_TXD,
+	GPIO32_UART1_CTS,
+	GPIO37_UART1_RTS,
+	GPIO33_UART1_DCD,
+	GPIO34_UART1_DSR,
+	GPIO35_UART1_RI,
+	GPIO36_UART1_DTR,
+
+	/* Ethernet */
+	GPIO2_nCS3,
+	GPIO99_GPIO,
+};
+
+static mfp_cfg_t pxa310_mfp_cfg[] __initdata = {
+	/* FFUART */
+	GPIO99_UART1_RXD,
+	GPIO100_UART1_TXD,
+	GPIO101_UART1_CTS,
+	GPIO106_UART1_RTS,
+
+	/* Ethernet */
+	GPIO2_nCS3,
+	GPIO102_GPIO,
+};
+
+#define NUM_LCD_DETECT_PINS	7
+
+static int lcd_detect_pins[] __initdata = {
+	MFP_PIN_GPIO71,	/* LCD_LDD_17 - ORIENT */
+	MFP_PIN_GPIO70, /* LCD_LDD_16 - LCDID[5] */
+	MFP_PIN_GPIO75, /* LCD_BIAS   - LCDID[4] */
+	MFP_PIN_GPIO73, /* LCD_LCLK   - LCDID[3] */
+	MFP_PIN_GPIO72, /* LCD_FCLK   - LCDID[2] */
+	MFP_PIN_GPIO127,/* LCD_CS_N   - LCDID[1] */
+	MFP_PIN_GPIO76, /* LCD_VSYNC  - LCDID[0] */
+};
+
+static void __init zylonite_detect_lcd_panel(void)
+{
+	unsigned long mfpr_save[NUM_LCD_DETECT_PINS];
+	int i, gpio, id = 0;
+
+	/* save the original MFP settings of these pins and configure
+	 * them as GPIO Input, DS01X, Pull Neither, Edge Clear
+	 */
+	for (i = 0; i < NUM_LCD_DETECT_PINS; i++) {
+		mfpr_save[i] = pxa3xx_mfp_read(lcd_detect_pins[i]);
+		pxa3xx_mfp_write(lcd_detect_pins[i], 0x8440);
+	}
+
+	for (i = 0; i < NUM_LCD_DETECT_PINS; i++) {
+		id = id << 1;
+		gpio = mfp_to_gpio(lcd_detect_pins[i]);
+		gpio_direction_input(gpio);
+
+		if (gpio_get_value(gpio))
+			id = id | 0x1;
+	}
+
+	/* lcd id, flush out bit 1 */
+	lcd_id = id & 0x3d;
+
+	/* lcd orientation, portrait or landscape */
+	lcd_orientation = (id >> 6) & 0x1;
+
+	/* restore the original MFP settings */
+	for (i = 0; i < NUM_LCD_DETECT_PINS; i++)
+		pxa3xx_mfp_write(lcd_detect_pins[i], mfpr_save[i]);
+}
+
+void __init zylonite_pxa300_init(void)
+{
+	if (cpu_is_pxa300() || cpu_is_pxa310()) {
+		/* initialize MFP */
+		pxa3xx_mfp_config(ARRAY_AND_SIZE(common_mfp_cfg));
+
+		/* detect LCD panel */
+		zylonite_detect_lcd_panel();
+
+		/* GPIO pin assignment */
+		gpio_backlight = mfp_to_gpio(MFP_PIN_GPIO20);
+	}
+
+	if (cpu_is_pxa300()) {
+		pxa3xx_mfp_config(ARRAY_AND_SIZE(pxa300_mfp_cfg));
+		gpio_eth_irq = mfp_to_gpio(MFP_PIN_GPIO99);
+	}
+
+	if (cpu_is_pxa310()) {
+		pxa3xx_mfp_config(ARRAY_AND_SIZE(pxa310_mfp_cfg));
+		gpio_eth_irq = mfp_to_gpio(MFP_PIN_GPIO102);
+	}
+}
diff --git a/arch/arm/mach-pxa/zylonite_pxa320.c b/arch/arm/mach-pxa/zylonite_pxa320.c
new file mode 100644
index 0000000..63cb36b
--- /dev/null
+++ b/arch/arm/mach-pxa/zylonite_pxa320.c
@@ -0,0 +1,173 @@
+/*
+ * linux/arch/arm/mach-pxa/zylonite_pxa320.c
+ *
+ * PXA320 specific support code for the
+ * PXA3xx Development Platform (aka Zylonite)
+ *
+ * Copyright (C) 2007 Marvell Internation Ltd.
+ * 2007-08-21: eric miao <eric.y.miao@gmail.com>
+ *             initial version
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/mfp-pxa320.h>
+#include <asm/arch/zylonite.h>
+
+#define ARRAY_AND_SIZE(x)	(x), ARRAY_SIZE(x)
+
+static mfp_cfg_t mfp_cfg[] __initdata = {
+	/* LCD */
+	GPIO6_2_LCD_LDD_0,
+	GPIO7_2_LCD_LDD_1,
+	GPIO8_2_LCD_LDD_2,
+	GPIO9_2_LCD_LDD_3,
+	GPIO10_2_LCD_LDD_4,
+	GPIO11_2_LCD_LDD_5,
+	GPIO12_2_LCD_LDD_6,
+	GPIO13_2_LCD_LDD_7,
+	GPIO63_LCD_LDD_8,
+	GPIO64_LCD_LDD_9,
+	GPIO65_LCD_LDD_10,
+	GPIO66_LCD_LDD_11,
+	GPIO67_LCD_LDD_12,
+	GPIO68_LCD_LDD_13,
+	GPIO69_LCD_LDD_14,
+	GPIO70_LCD_LDD_15,
+	GPIO71_LCD_LDD_16,
+	GPIO72_LCD_LDD_17,
+	GPIO73_LCD_CS_N,
+	GPIO74_LCD_VSYNC,
+	GPIO14_2_LCD_FCLK,
+	GPIO15_2_LCD_LCLK,
+	GPIO16_2_LCD_PCLK,
+	GPIO17_2_LCD_BIAS,
+
+	/* FFUART */
+	GPIO41_UART1_RXD,
+	GPIO42_UART1_TXD,
+	GPIO43_UART1_CTS,
+	GPIO44_UART1_DCD,
+	GPIO45_UART1_DSR,
+	GPIO46_UART1_RI,
+	GPIO47_UART1_DTR,
+	GPIO48_UART1_RTS,
+
+	/* AC97 */
+	GPIO34_AC97_SYSCLK,
+	GPIO35_AC97_SDATA_IN_0,
+	GPIO37_AC97_SDATA_OUT,
+	GPIO38_AC97_SYNC,
+	GPIO39_AC97_BITCLK,
+	GPIO40_AC97_nACRESET,
+
+	/* I2C */
+	GPIO32_I2C_SCL,
+	GPIO33_I2C_SDA,
+
+	/* Keypad */
+	GPIO105_KP_DKIN_0,
+	GPIO106_KP_DKIN_1,
+	GPIO113_KP_MKIN_0,
+	GPIO114_KP_MKIN_1,
+	GPIO115_KP_MKIN_2,
+	GPIO116_KP_MKIN_3,
+	GPIO117_KP_MKIN_4,
+	GPIO118_KP_MKIN_5,
+	GPIO119_KP_MKIN_6,
+	GPIO120_KP_MKIN_7,
+	GPIO121_KP_MKOUT_0,
+	GPIO122_KP_MKOUT_1,
+	GPIO123_KP_MKOUT_2,
+	GPIO124_KP_MKOUT_3,
+	GPIO125_KP_MKOUT_4,
+	GPIO126_KP_MKOUT_5,
+	GPIO127_KP_MKOUT_6,
+	GPIO5_2_KP_MKOUT_7,
+
+	/* Ethernet */
+	GPIO4_nCS3,
+	GPIO90_GPIO,
+};
+
+#define NUM_LCD_DETECT_PINS	7
+
+static int lcd_detect_pins[] __initdata = {
+	MFP_PIN_GPIO72,   /* LCD_LDD_17 - ORIENT */
+	MFP_PIN_GPIO71,   /* LCD_LDD_16 - LCDID[5] */
+	MFP_PIN_GPIO17_2, /* LCD_BIAS   - LCDID[4] */
+	MFP_PIN_GPIO15_2, /* LCD_LCLK   - LCDID[3] */
+	MFP_PIN_GPIO14_2, /* LCD_FCLK   - LCDID[2] */
+	MFP_PIN_GPIO73,   /* LCD_CS_N   - LCDID[1] */
+	MFP_PIN_GPIO74,   /* LCD_VSYNC  - LCDID[0] */
+	/*
+	 * set the MFP_PIN_GPIO 14/15/17 to alternate function other than
+	 * GPIO to avoid input level confliction with 14_2, 15_2, 17_2
+	 */
+	MFP_PIN_GPIO14,
+	MFP_PIN_GPIO15,
+	MFP_PIN_GPIO17,
+};
+
+static int lcd_detect_mfpr[] __initdata = {
+	/* AF0, DS 1X, Pull Neither, Edge Clear */
+	0x8440, 0x8440, 0x8440, 0x8440, 0x8440, 0x8440, 0x8440,
+	0xc442, /* Backlight, Pull-Up, AF2 */
+	0x8445, /* AF5 */
+	0x8445, /* AF5 */
+};
+
+static void __init zylonite_detect_lcd_panel(void)
+{
+	unsigned long mfpr_save[ARRAY_SIZE(lcd_detect_pins)];
+	int i, gpio, id = 0;
+
+	/* save the original MFP settings of these pins and configure them
+	 * as GPIO Input, DS01X, Pull Neither, Edge Clear
+	 */
+	for (i = 0; i < ARRAY_SIZE(lcd_detect_pins); i++) {
+		mfpr_save[i] = pxa3xx_mfp_read(lcd_detect_pins[i]);
+		pxa3xx_mfp_write(lcd_detect_pins[i], lcd_detect_mfpr[i]);
+	}
+
+	for (i = 0; i < NUM_LCD_DETECT_PINS; i++) {
+		id = id << 1;
+		gpio = mfp_to_gpio(lcd_detect_pins[i]);
+		gpio_direction_input(gpio);
+
+		if (gpio_get_value(gpio))
+			id = id | 0x1;
+	}
+
+	/* lcd id, flush out bit 1 */
+	lcd_id = id & 0x3d;
+
+	/* lcd orientation, portrait or landscape */
+	lcd_orientation = (id >> 6) & 0x1;
+
+	/* restore the original MFP settings */
+	for (i = 0; i < ARRAY_SIZE(lcd_detect_pins); i++)
+		pxa3xx_mfp_write(lcd_detect_pins[i], mfpr_save[i]);
+}
+
+void __init zylonite_pxa320_init(void)
+{
+	if (cpu_is_pxa320()) {
+		/* initialize MFP */
+		pxa3xx_mfp_config(ARRAY_AND_SIZE(mfp_cfg));
+
+		/* detect LCD panel */
+		zylonite_detect_lcd_panel();
+
+		/* GPIO pin assignment */
+		gpio_backlight	= mfp_to_gpio(MFP_PIN_GPIO14);
+		gpio_eth_irq	= mfp_to_gpio(MFP_PIN_GPIO9);
+	}
+}