Linux-2.6.12-rc2

Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.

Let it rip!
diff --git a/arch/arm/mach-integrator/Kconfig b/arch/arm/mach-integrator/Kconfig
new file mode 100644
index 0000000..df97d16
--- /dev/null
+++ b/arch/arm/mach-integrator/Kconfig
@@ -0,0 +1,33 @@
+if ARCH_INTEGRATOR
+
+menu "Integrator Options"
+
+config ARCH_INTEGRATOR_AP
+	bool "Support Integrator/AP and Integrator/PP2 platforms"
+	help
+	  Include support for the ARM(R) Integrator/AP and
+	  Integrator/PP2 platforms.
+
+config ARCH_INTEGRATOR_CP
+	bool "Support Integrator/CP platform"
+	select ARCH_CINTEGRATOR
+	help
+	  Include support for the ARM(R) Integrator CP platform.
+
+config ARCH_CINTEGRATOR
+	bool
+
+config INTEGRATOR_IMPD1
+	tristate "Include support for Integrator/IM-PD1"
+	depends on ARCH_INTEGRATOR_AP
+	help
+	  The IM-PD1 is an add-on logic module for the Integrator which
+	  allows ARM(R) Ltd PrimeCells to be developed and evaluated.
+	  The IM-PD1 can be found on the Integrator/PP2 platform.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called impd1.
+
+endmenu
+
+endif
diff --git a/arch/arm/mach-integrator/Makefile b/arch/arm/mach-integrator/Makefile
new file mode 100644
index 0000000..158daaf
--- /dev/null
+++ b/arch/arm/mach-integrator/Makefile
@@ -0,0 +1,14 @@
+#
+# Makefile for the linux kernel.
+#
+
+# Object file lists.
+
+obj-y					:= clock.o core.o lm.o time.o
+obj-$(CONFIG_ARCH_INTEGRATOR_AP)	+= integrator_ap.o
+obj-$(CONFIG_ARCH_INTEGRATOR_CP)	+= integrator_cp.o
+
+obj-$(CONFIG_LEDS)			+= leds.o
+obj-$(CONFIG_PCI)			+= pci_v3.o pci.o
+obj-$(CONFIG_CPU_FREQ_INTEGRATOR)	+= cpu.o
+obj-$(CONFIG_INTEGRATOR_IMPD1)		+= impd1.o
diff --git a/arch/arm/mach-integrator/Makefile.boot b/arch/arm/mach-integrator/Makefile.boot
new file mode 100644
index 0000000..c7e75ac
--- /dev/null
+++ b/arch/arm/mach-integrator/Makefile.boot
@@ -0,0 +1,4 @@
+   zreladdr-y	:= 0x00008000
+params_phys-y	:= 0x00000100
+initrd_phys-y	:= 0x00800000
+
diff --git a/arch/arm/mach-integrator/clock.c b/arch/arm/mach-integrator/clock.c
new file mode 100644
index 0000000..5620059
--- /dev/null
+++ b/arch/arm/mach-integrator/clock.c
@@ -0,0 +1,141 @@
+/*
+ *  linux/arch/arm/mach-integrator/clock.c
+ *
+ *  Copyright (C) 2004 ARM Limited.
+ *  Written by Deep Blue Solutions Limited.
+ *
+ * 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/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+
+#include <asm/semaphore.h>
+#include <asm/hardware/clock.h>
+#include <asm/hardware/icst525.h>
+
+#include "clock.h"
+
+static LIST_HEAD(clocks);
+static DECLARE_MUTEX(clocks_sem);
+
+struct clk *clk_get(struct device *dev, const char *id)
+{
+	struct clk *p, *clk = ERR_PTR(-ENOENT);
+
+	down(&clocks_sem);
+	list_for_each_entry(p, &clocks, node) {
+		if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) {
+			clk = p;
+			break;
+		}
+	}
+	up(&clocks_sem);
+
+	return clk;
+}
+EXPORT_SYMBOL(clk_get);
+
+void clk_put(struct clk *clk)
+{
+	module_put(clk->owner);
+}
+EXPORT_SYMBOL(clk_put);
+
+int clk_enable(struct clk *clk)
+{
+	return 0;
+}
+EXPORT_SYMBOL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+}
+EXPORT_SYMBOL(clk_disable);
+
+int clk_use(struct clk *clk)
+{
+	return 0;
+}
+EXPORT_SYMBOL(clk_use);
+
+void clk_unuse(struct clk *clk)
+{
+}
+EXPORT_SYMBOL(clk_unuse);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+	return clk->rate;
+}
+EXPORT_SYMBOL(clk_get_rate);
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+	struct icst525_vco vco;
+
+	vco = icst525_khz_to_vco(clk->params, rate / 1000);
+	return icst525_khz(clk->params, vco) * 1000;
+}
+EXPORT_SYMBOL(clk_round_rate);
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	int ret = -EIO;
+	if (clk->setvco) {
+		struct icst525_vco vco;
+
+		vco = icst525_khz_to_vco(clk->params, rate / 1000);
+		clk->rate = icst525_khz(clk->params, vco) * 1000;
+
+		printk("Clock %s: setting VCO reg params: S=%d R=%d V=%d\n",
+			clk->name, vco.s, vco.r, vco.v);
+
+		clk->setvco(clk, vco);
+		ret = 0;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(clk_set_rate);
+
+/*
+ * These are fixed clocks.
+ */
+static struct clk kmi_clk = {
+	.name	= "KMIREFCLK",
+	.rate	= 24000000,
+};
+
+static struct clk uart_clk = {
+	.name	= "UARTCLK",
+	.rate	= 14745600,
+};
+
+int clk_register(struct clk *clk)
+{
+	down(&clocks_sem);
+	list_add(&clk->node, &clocks);
+	up(&clocks_sem);
+	return 0;
+}
+EXPORT_SYMBOL(clk_register);
+
+void clk_unregister(struct clk *clk)
+{
+	down(&clocks_sem);
+	list_del(&clk->node);
+	up(&clocks_sem);
+}
+EXPORT_SYMBOL(clk_unregister);
+
+static int __init clk_init(void)
+{
+	clk_register(&kmi_clk);
+	clk_register(&uart_clk);
+	return 0;
+}
+arch_initcall(clk_init);
diff --git a/arch/arm/mach-integrator/clock.h b/arch/arm/mach-integrator/clock.h
new file mode 100644
index 0000000..09e6328
--- /dev/null
+++ b/arch/arm/mach-integrator/clock.h
@@ -0,0 +1,25 @@
+/*
+ *  linux/arch/arm/mach-integrator/clock.h
+ *
+ *  Copyright (C) 2004 ARM Limited.
+ *  Written by Deep Blue Solutions Limited.
+ *
+ * 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.
+ */
+struct module;
+struct icst525_params;
+
+struct clk {
+	struct list_head	node;
+	unsigned long		rate;
+	struct module		*owner;
+	const char		*name;
+	const struct icst525_params *params;
+	void			*data;
+	void			(*setvco)(struct clk *, struct icst525_vco vco);
+};
+
+int clk_register(struct clk *clk);
+void clk_unregister(struct clk *clk);
diff --git a/arch/arm/mach-integrator/common.h b/arch/arm/mach-integrator/common.h
new file mode 100644
index 0000000..609c49d
--- /dev/null
+++ b/arch/arm/mach-integrator/common.h
@@ -0,0 +1,2 @@
+extern void integrator_time_init(unsigned long, unsigned int);
+extern unsigned long integrator_gettimeoffset(void);
diff --git a/arch/arm/mach-integrator/core.c b/arch/arm/mach-integrator/core.c
new file mode 100644
index 0000000..86c50c3
--- /dev/null
+++ b/arch/arm/mach-integrator/core.c
@@ -0,0 +1,271 @@
+/*
+ *  linux/arch/arm/mach-integrator/core.c
+ *
+ *  Copyright (C) 2000-2003 Deep Blue Solutions Ltd
+ *
+ * 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/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/hardware/amba.h>
+#include <asm/arch/cm.h>
+#include <asm/system.h>
+#include <asm/leds.h>
+#include <asm/mach/time.h>
+
+#include "common.h"
+
+static struct amba_device rtc_device = {
+	.dev		= {
+		.bus_id	= "mb:15",
+	},
+	.res		= {
+		.start	= INTEGRATOR_RTC_BASE,
+		.end	= INTEGRATOR_RTC_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	.irq		= { IRQ_RTCINT, NO_IRQ },
+	.periphid	= 0x00041030,
+};
+
+static struct amba_device uart0_device = {
+	.dev		= {
+		.bus_id	= "mb:16",
+	},
+	.res		= {
+		.start	= INTEGRATOR_UART0_BASE,
+		.end	= INTEGRATOR_UART0_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	.irq		= { IRQ_UARTINT0, NO_IRQ },
+	.periphid	= 0x0041010,
+};
+
+static struct amba_device uart1_device = {
+	.dev		= {
+		.bus_id	= "mb:17",
+	},
+	.res		= {
+		.start	= INTEGRATOR_UART1_BASE,
+		.end	= INTEGRATOR_UART1_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	.irq		= { IRQ_UARTINT1, NO_IRQ },
+	.periphid	= 0x0041010,
+};
+
+static struct amba_device kmi0_device = {
+	.dev		= {
+		.bus_id	= "mb:18",
+	},
+	.res		= {
+		.start	= KMI0_BASE,
+		.end	= KMI0_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	.irq		= { IRQ_KMIINT0, NO_IRQ },
+	.periphid	= 0x00041050,
+};
+
+static struct amba_device kmi1_device = {
+	.dev		= {
+		.bus_id	= "mb:19",
+	},
+	.res		= {
+		.start	= KMI1_BASE,
+		.end	= KMI1_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	.irq		= { IRQ_KMIINT1, NO_IRQ },
+	.periphid	= 0x00041050,
+};
+
+static struct amba_device *amba_devs[] __initdata = {
+	&rtc_device,
+	&uart0_device,
+	&uart1_device,
+	&kmi0_device,
+	&kmi1_device,
+};
+
+static int __init integrator_init(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
+		struct amba_device *d = amba_devs[i];
+		amba_device_register(d, &iomem_resource);
+	}
+
+	return 0;
+}
+
+arch_initcall(integrator_init);
+
+#define CM_CTRL	IO_ADDRESS(INTEGRATOR_HDR_BASE) + INTEGRATOR_HDR_CTRL_OFFSET
+
+static DEFINE_SPINLOCK(cm_lock);
+
+/**
+ * cm_control - update the CM_CTRL register.
+ * @mask: bits to change
+ * @set: bits to set
+ */
+void cm_control(u32 mask, u32 set)
+{
+	unsigned long flags;
+	u32 val;
+
+	spin_lock_irqsave(&cm_lock, flags);
+	val = readl(CM_CTRL) & ~mask;
+	writel(val | set, CM_CTRL);
+	spin_unlock_irqrestore(&cm_lock, flags);
+}
+
+EXPORT_SYMBOL(cm_control);
+
+/*
+ * Where is the timer (VA)?
+ */
+#define TIMER0_VA_BASE (IO_ADDRESS(INTEGRATOR_CT_BASE)+0x00000000)
+#define TIMER1_VA_BASE (IO_ADDRESS(INTEGRATOR_CT_BASE)+0x00000100)
+#define TIMER2_VA_BASE (IO_ADDRESS(INTEGRATOR_CT_BASE)+0x00000200)
+#define VA_IC_BASE     IO_ADDRESS(INTEGRATOR_IC_BASE) 
+
+/*
+ * How long is the timer interval?
+ */
+#define TIMER_INTERVAL	(TICKS_PER_uSEC * mSEC_10)
+#if TIMER_INTERVAL >= 0x100000
+#define TICKS2USECS(x)	(256 * (x) / TICKS_PER_uSEC)
+#elif TIMER_INTERVAL >= 0x10000
+#define TICKS2USECS(x)	(16 * (x) / TICKS_PER_uSEC)
+#else
+#define TICKS2USECS(x)	((x) / TICKS_PER_uSEC)
+#endif
+
+/*
+ * What does it look like?
+ */
+typedef struct TimerStruct {
+	unsigned long TimerLoad;
+	unsigned long TimerValue;
+	unsigned long TimerControl;
+	unsigned long TimerClear;
+} TimerStruct_t;
+
+static unsigned long timer_reload;
+
+/*
+ * Returns number of ms since last clock interrupt.  Note that interrupts
+ * will have been disabled by do_gettimeoffset()
+ */
+unsigned long integrator_gettimeoffset(void)
+{
+	volatile TimerStruct_t *timer1 = (TimerStruct_t *)TIMER1_VA_BASE;
+	unsigned long ticks1, ticks2, status;
+
+	/*
+	 * Get the current number of ticks.  Note that there is a race
+	 * condition between us reading the timer and checking for
+	 * an interrupt.  We get around this by ensuring that the
+	 * counter has not reloaded between our two reads.
+	 */
+	ticks2 = timer1->TimerValue & 0xffff;
+	do {
+		ticks1 = ticks2;
+		status = __raw_readl(VA_IC_BASE + IRQ_RAW_STATUS);
+		ticks2 = timer1->TimerValue & 0xffff;
+	} while (ticks2 > ticks1);
+
+	/*
+	 * Number of ticks since last interrupt.
+	 */
+	ticks1 = timer_reload - ticks2;
+
+	/*
+	 * Interrupt pending?  If so, we've reloaded once already.
+	 */
+	if (status & (1 << IRQ_TIMERINT1))
+		ticks1 += timer_reload;
+
+	/*
+	 * Convert the ticks to usecs
+	 */
+	return TICKS2USECS(ticks1);
+}
+
+/*
+ * IRQ handler for the timer
+ */
+static irqreturn_t
+integrator_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	volatile TimerStruct_t *timer1 = (volatile TimerStruct_t *)TIMER1_VA_BASE;
+
+	write_seqlock(&xtime_lock);
+
+	// ...clear the interrupt
+	timer1->TimerClear = 1;
+
+	timer_tick(regs);
+
+	write_sequnlock(&xtime_lock);
+
+	return IRQ_HANDLED;
+}
+
+static struct irqaction integrator_timer_irq = {
+	.name		= "Integrator Timer Tick",
+	.flags		= SA_INTERRUPT,
+	.handler	= integrator_timer_interrupt
+};
+
+/*
+ * Set up timer interrupt, and return the current time in seconds.
+ */
+void __init integrator_time_init(unsigned long reload, unsigned int ctrl)
+{
+	volatile TimerStruct_t *timer0 = (volatile TimerStruct_t *)TIMER0_VA_BASE;
+	volatile TimerStruct_t *timer1 = (volatile TimerStruct_t *)TIMER1_VA_BASE;
+	volatile TimerStruct_t *timer2 = (volatile TimerStruct_t *)TIMER2_VA_BASE;
+	unsigned int timer_ctrl = 0x80 | 0x40;	/* periodic */
+
+	timer_reload = reload;
+	timer_ctrl |= ctrl;
+
+	if (timer_reload > 0x100000) {
+		timer_reload >>= 8;
+		timer_ctrl |= 0x08; /* /256 */
+	} else if (timer_reload > 0x010000) {
+		timer_reload >>= 4;
+		timer_ctrl |= 0x04; /* /16 */
+	}
+
+	/*
+	 * Initialise to a known state (all timers off)
+	 */
+	timer0->TimerControl = 0;
+	timer1->TimerControl = 0;
+	timer2->TimerControl = 0;
+
+	timer1->TimerLoad    = timer_reload;
+	timer1->TimerValue   = timer_reload;
+	timer1->TimerControl = timer_ctrl;
+
+	/* 
+	 * Make irqs happen for the system timer
+	 */
+	setup_irq(IRQ_TIMERINT1, &integrator_timer_irq);
+}
diff --git a/arch/arm/mach-integrator/cpu.c b/arch/arm/mach-integrator/cpu.c
new file mode 100644
index 0000000..71c58bff
--- /dev/null
+++ b/arch/arm/mach-integrator/cpu.c
@@ -0,0 +1,221 @@
+/*
+ *  linux/arch/arm/mach-integrator/cpu.c
+ *
+ *  Copyright (C) 2001-2002 Deep Blue Solutions Ltd.
+ *
+ *  $Id: cpu.c,v 1.6 2002/07/18 13:58:51 rmk Exp $
+ *
+ * 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.
+ *
+ * CPU support functions
+ */
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/cpufreq.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/init.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/mach-types.h>
+#include <asm/hardware/icst525.h>
+
+static struct cpufreq_driver integrator_driver;
+
+#define CM_ID  	(IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_ID_OFFSET)
+#define CM_OSC	(IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_OSC_OFFSET)
+#define CM_STAT (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_STAT_OFFSET)
+#define CM_LOCK (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_LOCK_OFFSET)
+
+static const struct icst525_params lclk_params = {
+	.ref		= 24000,
+	.vco_max	= 320000,
+	.vd_min		= 8,
+	.vd_max		= 132,
+	.rd_min		= 24,
+	.rd_max		= 24,
+};
+
+static const struct icst525_params cclk_params = {
+	.ref		= 24000,
+	.vco_max	= 320000,
+	.vd_min		= 12,
+	.vd_max		= 160,
+	.rd_min		= 24,
+	.rd_max		= 24,
+};
+
+/*
+ * Validate the speed policy.
+ */
+static int integrator_verify_policy(struct cpufreq_policy *policy)
+{
+	struct icst525_vco vco;
+
+	cpufreq_verify_within_limits(policy, 
+				     policy->cpuinfo.min_freq, 
+				     policy->cpuinfo.max_freq);
+
+	vco = icst525_khz_to_vco(&cclk_params, policy->max);
+	policy->max = icst525_khz(&cclk_params, vco);
+
+	vco = icst525_khz_to_vco(&cclk_params, policy->min);
+	policy->min = icst525_khz(&cclk_params, vco);
+
+	cpufreq_verify_within_limits(policy, 
+				     policy->cpuinfo.min_freq, 
+				     policy->cpuinfo.max_freq);
+
+	return 0;
+}
+
+
+static int integrator_set_target(struct cpufreq_policy *policy,
+				 unsigned int target_freq,
+				 unsigned int relation)
+{
+	cpumask_t cpus_allowed;
+	int cpu = policy->cpu;
+	struct icst525_vco vco;
+	struct cpufreq_freqs freqs;
+	u_int cm_osc;
+
+	/*
+	 * Save this threads cpus_allowed mask.
+	 */
+	cpus_allowed = current->cpus_allowed;
+
+	/*
+	 * Bind to the specified CPU.  When this call returns,
+	 * we should be running on the right CPU.
+	 */
+	set_cpus_allowed(current, cpumask_of_cpu(cpu));
+	BUG_ON(cpu != smp_processor_id());
+
+	/* get current setting */
+	cm_osc = __raw_readl(CM_OSC);
+
+	if (machine_is_integrator()) {
+		vco.s = (cm_osc >> 8) & 7;
+	} else if (machine_is_cintegrator()) {
+		vco.s = 1;
+	}
+	vco.v = cm_osc & 255;
+	vco.r = 22;
+	freqs.old = icst525_khz(&cclk_params, vco);
+
+	/* icst525_khz_to_vco rounds down -- so we need the next
+	 * larger freq in case of CPUFREQ_RELATION_L.
+	 */
+	if (relation == CPUFREQ_RELATION_L)
+		target_freq += 999;
+	if (target_freq > policy->max)
+		target_freq = policy->max;
+	vco = icst525_khz_to_vco(&cclk_params, target_freq);
+	freqs.new = icst525_khz(&cclk_params, vco);
+
+	freqs.cpu = policy->cpu;
+
+	if (freqs.old == freqs.new) {
+		set_cpus_allowed(current, cpus_allowed);
+		return 0;
+	}
+
+	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+	cm_osc = __raw_readl(CM_OSC);
+
+	if (machine_is_integrator()) {
+		cm_osc &= 0xfffff800;
+		cm_osc |= vco.s << 8;
+	} else if (machine_is_cintegrator()) {
+		cm_osc &= 0xffffff00;
+	}
+	cm_osc |= vco.v;
+
+	__raw_writel(0xa05f, CM_LOCK);
+	__raw_writel(cm_osc, CM_OSC);
+	__raw_writel(0, CM_LOCK);
+
+	/*
+	 * Restore the CPUs allowed mask.
+	 */
+	set_cpus_allowed(current, cpus_allowed);
+
+	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+	return 0;
+}
+
+static unsigned int integrator_get(unsigned int cpu)
+{
+	cpumask_t cpus_allowed;
+	unsigned int current_freq;
+	u_int cm_osc;
+	struct icst525_vco vco;
+
+	cpus_allowed = current->cpus_allowed;
+
+	set_cpus_allowed(current, cpumask_of_cpu(cpu));
+	BUG_ON(cpu != smp_processor_id());
+
+	/* detect memory etc. */
+	cm_osc = __raw_readl(CM_OSC);
+
+	if (machine_is_integrator()) {
+		vco.s = (cm_osc >> 8) & 7;
+	} else if (machine_is_cintegrator()) {
+		vco.s = 1;
+	}
+	vco.v = cm_osc & 255;
+	vco.r = 22;
+
+	current_freq = icst525_khz(&cclk_params, vco); /* current freq */
+
+	set_cpus_allowed(current, cpus_allowed);
+
+	return current_freq;
+}
+
+static int integrator_cpufreq_init(struct cpufreq_policy *policy)
+{
+
+	/* set default policy and cpuinfo */
+	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+	policy->cpuinfo.max_freq = 160000;
+	policy->cpuinfo.min_freq = 12000;
+	policy->cpuinfo.transition_latency = 1000000; /* 1 ms, assumed */
+	policy->cur = policy->min = policy->max = integrator_get(policy->cpu);
+
+	return 0;
+}
+
+static struct cpufreq_driver integrator_driver = {
+	.verify		= integrator_verify_policy,
+	.target		= integrator_set_target,
+	.get		= integrator_get,
+	.init		= integrator_cpufreq_init,
+	.name		= "integrator",
+};
+
+static int __init integrator_cpu_init(void)
+{
+	return cpufreq_register_driver(&integrator_driver);
+}
+
+static void __exit integrator_cpu_exit(void)
+{
+	cpufreq_unregister_driver(&integrator_driver);
+}
+
+MODULE_AUTHOR ("Russell M. King");
+MODULE_DESCRIPTION ("cpufreq driver for ARM Integrator CPUs");
+MODULE_LICENSE ("GPL");
+
+module_init(integrator_cpu_init);
+module_exit(integrator_cpu_exit);
diff --git a/arch/arm/mach-integrator/dma.c b/arch/arm/mach-integrator/dma.c
new file mode 100644
index 0000000..aae6f23
--- /dev/null
+++ b/arch/arm/mach-integrator/dma.c
@@ -0,0 +1,35 @@
+/*
+ *  linux/arch/arm/mach-integrator/dma.c
+ *
+ *  Copyright (C) 1999 ARM Limited
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <linux/slab.h>
+#include <linux/mman.h>
+#include <linux/init.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+
+#include <asm/mach/dma.h>
+
+void __init arch_dma_init(dma_t *dma)
+{
+}
diff --git a/arch/arm/mach-integrator/impd1.c b/arch/arm/mach-integrator/impd1.c
new file mode 100644
index 0000000..c3c2f17
--- /dev/null
+++ b/arch/arm/mach-integrator/impd1.c
@@ -0,0 +1,475 @@
+/*
+ *  linux/arch/arm/mach-integrator/impd1.c
+ *
+ *  Copyright (C) 2003 Deep Blue Solutions Ltd, All Rights Reserved.
+ *
+ * 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.
+ *
+ *  This file provides the core support for the IM-PD1 module.
+ *
+ * Module / boot parameters.
+ *   lmid=n   impd1.lmid=n - set the logic module position in stack to 'n'
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+
+#include <asm/io.h>
+#include <asm/hardware/icst525.h>
+#include <asm/hardware/amba.h>
+#include <asm/hardware/amba_clcd.h>
+#include <asm/arch/lm.h>
+#include <asm/arch/impd1.h>
+#include <asm/sizes.h>
+
+#include "clock.h"
+
+static int module_id;
+
+module_param_named(lmid, module_id, int, 0444);
+MODULE_PARM_DESC(lmid, "logic module stack position");
+
+struct impd1_module {
+	void __iomem	*base;
+	struct clk	vcos[2];
+};
+
+static const struct icst525_params impd1_vco_params = {
+	.ref		= 24000,	/* 24 MHz */
+	.vco_max	= 200000,	/* 200 MHz */
+	.vd_min		= 12,
+	.vd_max		= 519,
+	.rd_min		= 3,
+	.rd_max		= 120,
+};
+
+static void impd1_setvco(struct clk *clk, struct icst525_vco vco)
+{
+	struct impd1_module *impd1 = clk->data;
+	int vconr = clk - impd1->vcos;
+	u32 val;
+
+	val = vco.v | (vco.r << 9) | (vco.s << 16);
+
+	writel(0xa05f, impd1->base + IMPD1_LOCK);
+	switch (vconr) {
+	case 0:
+		writel(val, impd1->base + IMPD1_OSC1);
+		break;
+	case 1:
+		writel(val, impd1->base + IMPD1_OSC2);
+		break;
+	}
+	writel(0, impd1->base + IMPD1_LOCK);
+
+#if DEBUG
+	vco.v = val & 0x1ff;
+	vco.r = (val >> 9) & 0x7f;
+	vco.s = (val >> 16) & 7;
+
+	pr_debug("IM-PD1: VCO%d clock is %ld kHz\n",
+		 vconr, icst525_khz(&impd1_vco_params, vco));
+#endif
+}
+
+void impd1_tweak_control(struct device *dev, u32 mask, u32 val)
+{
+	struct impd1_module *impd1 = dev_get_drvdata(dev);
+	u32 cur;
+
+	val &= mask;
+	cur = readl(impd1->base + IMPD1_CTRL) & ~mask;
+	writel(cur | val, impd1->base + IMPD1_CTRL);
+}
+
+EXPORT_SYMBOL(impd1_tweak_control);
+
+/*
+ * CLCD support
+ */
+#define PANEL		PROSPECTOR
+
+#define LTM10C209		1
+#define PROSPECTOR		2
+#define SVGA			3
+#define VGA			4
+
+#if PANEL == VGA
+#define PANELTYPE	vga
+static struct clcd_panel vga = {
+	.mode		= {
+		.name		= "VGA",
+		.refresh	= 60,
+		.xres		= 640,
+		.yres		= 480,
+		.pixclock	= 39721,
+		.left_margin	= 40,
+		.right_margin	= 24,
+		.upper_margin	= 32,
+		.lower_margin	= 11,
+		.hsync_len	= 96,
+		.vsync_len	= 2,
+		.sync		= 0,
+		.vmode		= FB_VMODE_NONINTERLACED,
+	},
+	.width		= -1,
+	.height		= -1,
+	.tim2		= TIM2_BCD | TIM2_IPC,
+	.cntl		= CNTL_LCDTFT | CNTL_LCDVCOMP(1),
+	.connector	= IMPD1_CTRL_DISP_VGA,
+	.bpp		= 16,
+	.grayscale	= 0,
+};
+
+#elif PANEL == SVGA
+#define PANELTYPE	svga
+static struct clcd_panel svga = {
+	.mode		= {
+		.name		= "SVGA",
+		.refresh	= 0,
+		.xres		= 800,
+		.yres		= 600,
+		.pixclock	= 27778,
+		.left_margin	= 20,
+		.right_margin	= 20,
+		.upper_margin	= 5,
+		.lower_margin	= 5,
+		.hsync_len	= 164,
+		.vsync_len	= 62,
+		.sync		= 0,
+		.vmode		= FB_VMODE_NONINTERLACED,
+	},
+	.width		= -1,
+	.height		= -1,
+	.tim2		= TIM2_BCD,
+	.cntl		= CNTL_LCDTFT | CNTL_LCDVCOMP(1),
+	.connector	= IMPD1_CTRL_DISP_VGA,
+	.bpp		= 16,
+	.grayscale	= 0,
+};
+
+#elif PANEL == PROSPECTOR
+#define PANELTYPE	prospector
+static struct clcd_panel prospector = {
+	.mode		= {
+		.name		= "PROSPECTOR",
+		.refresh	= 0,
+		.xres		= 640,
+		.yres		= 480,
+		.pixclock	= 40000,
+		.left_margin	= 33,
+		.right_margin	= 64,
+		.upper_margin	= 36,
+		.lower_margin	= 7,
+		.hsync_len	= 64,
+		.vsync_len	= 25,
+		.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+		.vmode		= FB_VMODE_NONINTERLACED,
+	},
+	.width		= -1,
+	.height		= -1,
+	.tim2		= TIM2_BCD,
+	.cntl		= CNTL_LCDTFT | CNTL_LCDVCOMP(1),
+	.fixedtimings	= 1,
+	.connector	= IMPD1_CTRL_DISP_LCD,
+	.bpp		= 16,
+	.grayscale	= 0,
+};
+
+#elif PANEL == LTM10C209
+#define PANELTYPE	ltm10c209
+/*
+ * Untested.
+ */
+static struct clcd_panel ltm10c209 = {
+	.mode		= {
+		.name		= "LTM10C209",
+		.refresh	= 0,
+		.xres		= 640,
+		.yres		= 480,
+		.pixclock	= 40000,
+		.left_margin	= 20,
+		.right_margin	= 20,
+		.upper_margin	= 19,
+		.lower_margin	= 19,
+		.hsync_len	= 20,
+		.vsync_len	= 10,
+		.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+		.vmode		= FB_VMODE_NONINTERLACED,
+	},
+	.width		= -1,
+	.height		= -1,
+	.tim2		= TIM2_BCD,
+	.cntl		= CNTL_LCDTFT | CNTL_LCDVCOMP(1),
+	.fixedtimings	= 1,
+	.connector	= IMPD1_CTRL_DISP_LCD,
+	.bpp		= 16,
+	.grayscale	= 0,
+};
+#endif
+
+/*
+ * Disable all display connectors on the interface module.
+ */
+static void impd1fb_clcd_disable(struct clcd_fb *fb)
+{
+	impd1_tweak_control(fb->dev->dev.parent, IMPD1_CTRL_DISP_MASK, 0);
+}
+
+/*
+ * Enable the relevant connector on the interface module.
+ */
+static void impd1fb_clcd_enable(struct clcd_fb *fb)
+{
+	impd1_tweak_control(fb->dev->dev.parent, IMPD1_CTRL_DISP_MASK,
+			fb->panel->connector | IMPD1_CTRL_DISP_ENABLE);
+}
+
+static int impd1fb_clcd_setup(struct clcd_fb *fb)
+{
+	unsigned long framebase = fb->dev->res.start + 0x01000000;
+	unsigned long framesize = SZ_1M;
+	int ret = 0;
+
+	fb->panel = &PANELTYPE;
+
+	if (!request_mem_region(framebase, framesize, "clcd framebuffer")) {
+		printk(KERN_ERR "IM-PD1: unable to reserve framebuffer\n");
+		return -EBUSY;
+	}
+
+	fb->fb.screen_base = ioremap(framebase, framesize);
+	if (!fb->fb.screen_base) {
+		printk(KERN_ERR "IM-PD1: unable to map framebuffer\n");
+		ret = -ENOMEM;
+		goto free_buffer;
+	}
+
+	fb->fb.fix.smem_start	= framebase;
+	fb->fb.fix.smem_len	= framesize;
+
+	return 0;
+
+ free_buffer:
+	release_mem_region(framebase, framesize);
+	return ret;
+}
+
+static int impd1fb_clcd_mmap(struct clcd_fb *fb, struct vm_area_struct *vma)
+{
+	unsigned long start, size;
+
+	start = vma->vm_pgoff + (fb->fb.fix.smem_start >> PAGE_SHIFT);
+	size = vma->vm_end - vma->vm_start;
+
+	return remap_pfn_range(vma, vma->vm_start, start, size,
+			       vma->vm_page_prot);
+}
+
+static void impd1fb_clcd_remove(struct clcd_fb *fb)
+{
+	iounmap(fb->fb.screen_base);
+	release_mem_region(fb->fb.fix.smem_start, fb->fb.fix.smem_len);
+}
+
+static struct clcd_board impd1_clcd_data = {
+	.name		= "IM-PD/1",
+	.check		= clcdfb_check,
+	.decode		= clcdfb_decode,
+	.disable	= impd1fb_clcd_disable,
+	.enable		= impd1fb_clcd_enable,
+	.setup		= impd1fb_clcd_setup,
+	.mmap		= impd1fb_clcd_mmap,
+	.remove		= impd1fb_clcd_remove,
+};
+
+struct impd1_device {
+	unsigned long	offset;
+	unsigned int	irq[2];
+	unsigned int	id;
+	void		*platform_data;
+};
+
+static struct impd1_device impd1_devs[] = {
+	{
+		.offset	= 0x03000000,
+		.id	= 0x00041190,
+	}, {
+		.offset	= 0x00100000,
+		.irq	= { 1 },
+		.id	= 0x00141011,
+	}, {
+		.offset	= 0x00200000,
+		.irq	= { 2 },
+		.id	= 0x00141011,
+	}, {
+		.offset	= 0x00300000,
+		.irq	= { 3 },
+		.id	= 0x00041022,
+	}, {
+		.offset	= 0x00400000,
+		.irq	= { 4 },
+		.id	= 0x00041061,
+	}, {
+		.offset	= 0x00500000,
+		.irq	= { 5 },
+		.id	= 0x00041061,
+	}, {
+		.offset	= 0x00600000,
+		.irq	= { 6 },
+		.id	= 0x00041130,
+	}, {
+		.offset	= 0x00700000,
+		.irq	= { 7, 8 },
+		.id	= 0x00041181,
+	}, {
+		.offset	= 0x00800000,
+		.irq	= { 9 },
+		.id	= 0x00041041,
+	}, {
+		.offset	= 0x01000000,
+		.irq	= { 11 },
+		.id	= 0x00041110,
+		.platform_data = &impd1_clcd_data,
+	}
+};
+
+static const char *impd1_vconames[2] = {
+	"CLCDCLK",
+	"AUXVCO2",
+};
+
+static int impd1_probe(struct lm_device *dev)
+{
+	struct impd1_module *impd1;
+	int i, ret;
+
+	if (dev->id != module_id)
+		return -EINVAL;
+
+	if (!request_mem_region(dev->resource.start, SZ_4K, "LM registers"))
+		return -EBUSY;
+
+	impd1 = kmalloc(sizeof(struct impd1_module), GFP_KERNEL);
+	if (!impd1) {
+		ret = -ENOMEM;
+		goto release_lm;
+	}
+	memset(impd1, 0, sizeof(struct impd1_module));
+
+	impd1->base = ioremap(dev->resource.start, SZ_4K);
+	if (!impd1->base) {
+		ret = -ENOMEM;
+		goto free_impd1;
+	}
+
+	lm_set_drvdata(dev, impd1);
+
+	printk("IM-PD1 found at 0x%08lx\n", dev->resource.start);
+
+	for (i = 0; i < ARRAY_SIZE(impd1->vcos); i++) {
+		impd1->vcos[i].owner = THIS_MODULE,
+		impd1->vcos[i].name = impd1_vconames[i],
+		impd1->vcos[i].params = &impd1_vco_params,
+		impd1->vcos[i].data = impd1,
+		impd1->vcos[i].setvco = impd1_setvco;
+
+		clk_register(&impd1->vcos[i]);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(impd1_devs); i++) {
+		struct impd1_device *idev = impd1_devs + i;
+		struct amba_device *d;
+		unsigned long pc_base;
+
+		pc_base = dev->resource.start + idev->offset;
+
+		d = kmalloc(sizeof(struct amba_device), GFP_KERNEL);
+		if (!d)
+			continue;
+
+		memset(d, 0, sizeof(struct amba_device));
+
+		snprintf(d->dev.bus_id, sizeof(d->dev.bus_id),
+			 "lm%x:%5.5lx", dev->id, idev->offset >> 12);
+
+		d->dev.parent	= &dev->dev;
+		d->res.start	= dev->resource.start + idev->offset;
+		d->res.end	= d->res.start + SZ_4K - 1;
+		d->res.flags	= IORESOURCE_MEM;
+		d->irq[0]	= dev->irq;
+		d->irq[1]	= dev->irq;
+		d->periphid	= idev->id;
+		d->dev.platform_data = idev->platform_data;
+
+		ret = amba_device_register(d, &dev->resource);
+		if (ret) {
+			printk("unable to register device %s: %d\n",
+				d->dev.bus_id, ret);
+			kfree(d);
+		}
+	}
+
+	return 0;
+
+ free_impd1:
+	if (impd1 && impd1->base)
+		iounmap(impd1->base);
+	if (impd1)
+		kfree(impd1);
+ release_lm:
+	release_mem_region(dev->resource.start, SZ_4K);
+	return ret;
+}
+
+static void impd1_remove(struct lm_device *dev)
+{
+	struct impd1_module *impd1 = lm_get_drvdata(dev);
+	struct list_head *l, *n;
+	int i;
+
+	list_for_each_safe(l, n, &dev->dev.children) {
+		struct device *d = list_to_dev(l);
+
+		device_unregister(d);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(impd1->vcos); i++)
+		clk_unregister(&impd1->vcos[i]);
+
+	lm_set_drvdata(dev, NULL);
+
+	iounmap(impd1->base);
+	kfree(impd1);
+	release_mem_region(dev->resource.start, SZ_4K);
+}
+
+static struct lm_driver impd1_driver = {
+	.drv = {
+		.name	= "impd1",
+	},
+	.probe		= impd1_probe,
+	.remove		= impd1_remove,
+};
+
+static int __init impd1_init(void)
+{
+	return lm_driver_register(&impd1_driver);
+}
+
+static void __exit impd1_exit(void)
+{
+	lm_driver_unregister(&impd1_driver);
+}
+
+module_init(impd1_init);
+module_exit(impd1_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Integrator/IM-PD1 logic module core driver");
+MODULE_AUTHOR("Deep Blue Solutions Ltd");
diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c
new file mode 100644
index 0000000..91ba9fd
--- /dev/null
+++ b/arch/arm/mach-integrator/integrator_ap.c
@@ -0,0 +1,302 @@
+/*
+ *  linux/arch/arm/mach-integrator/integrator_ap.c
+ *
+ *  Copyright (C) 2000-2003 Deep Blue Solutions Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/sysdev.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/hardware/amba.h>
+#include <asm/hardware/amba_kmi.h>
+
+#include <asm/arch/lm.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/flash.h>
+#include <asm/mach/irq.h>
+#include <asm/mach/map.h>
+#include <asm/mach/time.h>
+
+#include "common.h"
+
+/* 
+ * All IO addresses are mapped onto VA 0xFFFx.xxxx, where x.xxxx
+ * is the (PA >> 12).
+ *
+ * Setup a VA for the Integrator interrupt controller (for header #0,
+ * just for now).
+ */
+#define VA_IC_BASE	IO_ADDRESS(INTEGRATOR_IC_BASE) 
+#define VA_SC_BASE	IO_ADDRESS(INTEGRATOR_SC_BASE)
+#define VA_EBI_BASE	IO_ADDRESS(INTEGRATOR_EBI_BASE)
+#define VA_CMIC_BASE	IO_ADDRESS(INTEGRATOR_HDR_BASE) + INTEGRATOR_HDR_IC_OFFSET
+
+/*
+ * Logical      Physical
+ * e8000000	40000000	PCI memory		PHYS_PCI_MEM_BASE	(max 512M)
+ * ec000000	61000000	PCI config space	PHYS_PCI_CONFIG_BASE	(max 16M)
+ * ed000000	62000000	PCI V3 regs		PHYS_PCI_V3_BASE	(max 64k)
+ * ee000000	60000000	PCI IO			PHYS_PCI_IO_BASE	(max 16M)
+ * ef000000			Cache flush
+ * f1000000	10000000	Core module registers
+ * f1100000	11000000	System controller registers
+ * f1200000	12000000	EBI registers
+ * f1300000	13000000	Counter/Timer
+ * f1400000	14000000	Interrupt controller
+ * f1600000	16000000	UART 0
+ * f1700000	17000000	UART 1
+ * f1a00000	1a000000	Debug LEDs
+ * f1b00000	1b000000	GPIO
+ */
+
+static struct map_desc ap_io_desc[] __initdata = {
+ { IO_ADDRESS(INTEGRATOR_HDR_BASE),   INTEGRATOR_HDR_BASE,   SZ_4K,  MT_DEVICE },
+ { IO_ADDRESS(INTEGRATOR_SC_BASE),    INTEGRATOR_SC_BASE,    SZ_4K,  MT_DEVICE },
+ { IO_ADDRESS(INTEGRATOR_EBI_BASE),   INTEGRATOR_EBI_BASE,   SZ_4K,  MT_DEVICE },
+ { IO_ADDRESS(INTEGRATOR_CT_BASE),    INTEGRATOR_CT_BASE,    SZ_4K,  MT_DEVICE },
+ { IO_ADDRESS(INTEGRATOR_IC_BASE),    INTEGRATOR_IC_BASE,    SZ_4K,  MT_DEVICE },
+ { IO_ADDRESS(INTEGRATOR_UART0_BASE), INTEGRATOR_UART0_BASE, SZ_4K,  MT_DEVICE },
+ { IO_ADDRESS(INTEGRATOR_UART1_BASE), INTEGRATOR_UART1_BASE, SZ_4K,  MT_DEVICE },
+ { IO_ADDRESS(INTEGRATOR_DBG_BASE),   INTEGRATOR_DBG_BASE,   SZ_4K,  MT_DEVICE },
+ { IO_ADDRESS(INTEGRATOR_GPIO_BASE),  INTEGRATOR_GPIO_BASE,  SZ_4K,  MT_DEVICE },
+ { PCI_MEMORY_VADDR,                  PHYS_PCI_MEM_BASE,     SZ_16M, MT_DEVICE },
+ { PCI_CONFIG_VADDR,                  PHYS_PCI_CONFIG_BASE,  SZ_16M, MT_DEVICE },
+ { PCI_V3_VADDR,                      PHYS_PCI_V3_BASE,      SZ_64K, MT_DEVICE },
+ { PCI_IO_VADDR,                      PHYS_PCI_IO_BASE,      SZ_64K, MT_DEVICE }
+};
+
+static void __init ap_map_io(void)
+{
+	iotable_init(ap_io_desc, ARRAY_SIZE(ap_io_desc));
+}
+
+#define INTEGRATOR_SC_VALID_INT	0x003fffff
+
+static void sc_mask_irq(unsigned int irq)
+{
+	writel(1 << irq, VA_IC_BASE + IRQ_ENABLE_CLEAR);
+}
+
+static void sc_unmask_irq(unsigned int irq)
+{
+	writel(1 << irq, VA_IC_BASE + IRQ_ENABLE_SET);
+}
+
+static struct irqchip sc_chip = {
+	.ack	= sc_mask_irq,
+	.mask	= sc_mask_irq,
+	.unmask = sc_unmask_irq,
+};
+
+static void __init ap_init_irq(void)
+{
+	unsigned int i;
+
+	/* Disable all interrupts initially. */
+	/* Do the core module ones */
+	writel(-1, VA_CMIC_BASE + IRQ_ENABLE_CLEAR);
+
+	/* do the header card stuff next */
+	writel(-1, VA_IC_BASE + IRQ_ENABLE_CLEAR);
+	writel(-1, VA_IC_BASE + FIQ_ENABLE_CLEAR);
+
+	for (i = 0; i < NR_IRQS; i++) {
+		if (((1 << i) & INTEGRATOR_SC_VALID_INT) != 0) {
+			set_irq_chip(i, &sc_chip);
+			set_irq_handler(i, do_level_IRQ);
+			set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
+		}
+	}
+}
+
+#ifdef CONFIG_PM
+static unsigned long ic_irq_enable;
+
+static int irq_suspend(struct sys_device *dev, pm_message_t state)
+{
+	ic_irq_enable = readl(VA_IC_BASE + IRQ_ENABLE);
+	return 0;
+}
+
+static int irq_resume(struct sys_device *dev)
+{
+	/* disable all irq sources */
+	writel(-1, VA_CMIC_BASE + IRQ_ENABLE_CLEAR);
+	writel(-1, VA_IC_BASE + IRQ_ENABLE_CLEAR);
+	writel(-1, VA_IC_BASE + FIQ_ENABLE_CLEAR);
+
+	writel(ic_irq_enable, VA_IC_BASE + IRQ_ENABLE_SET);
+	return 0;
+}
+#else
+#define irq_suspend NULL
+#define irq_resume NULL
+#endif
+
+static struct sysdev_class irq_class = {
+	set_kset_name("irq"),
+	.suspend	= irq_suspend,
+	.resume		= irq_resume,
+};
+
+static struct sys_device irq_device = {
+	.id	= 0,
+	.cls	= &irq_class,
+};
+
+static int __init irq_init_sysfs(void)
+{
+	int ret = sysdev_class_register(&irq_class);
+	if (ret == 0)
+		ret = sysdev_register(&irq_device);
+	return ret;
+}
+
+device_initcall(irq_init_sysfs);
+
+/*
+ * Flash handling.
+ */
+#define SC_CTRLC (VA_SC_BASE + INTEGRATOR_SC_CTRLC_OFFSET)
+#define SC_CTRLS (VA_SC_BASE + INTEGRATOR_SC_CTRLS_OFFSET)
+#define EBI_CSR1 (VA_EBI_BASE + INTEGRATOR_EBI_CSR1_OFFSET)
+#define EBI_LOCK (VA_EBI_BASE + INTEGRATOR_EBI_LOCK_OFFSET)
+
+static int ap_flash_init(void)
+{
+	u32 tmp;
+
+	writel(INTEGRATOR_SC_CTRL_nFLVPPEN | INTEGRATOR_SC_CTRL_nFLWP, SC_CTRLC);
+
+	tmp = readl(EBI_CSR1) | INTEGRATOR_EBI_WRITE_ENABLE;
+	writel(tmp, EBI_CSR1);
+
+	if (!(readl(EBI_CSR1) & INTEGRATOR_EBI_WRITE_ENABLE)) {
+		writel(0xa05f, EBI_LOCK);
+		writel(tmp, EBI_CSR1);
+		writel(0, EBI_LOCK);
+	}
+	return 0;
+}
+
+static void ap_flash_exit(void)
+{
+	u32 tmp;
+
+	writel(INTEGRATOR_SC_CTRL_nFLVPPEN | INTEGRATOR_SC_CTRL_nFLWP, SC_CTRLC);
+
+	tmp = readl(EBI_CSR1) & ~INTEGRATOR_EBI_WRITE_ENABLE;
+	writel(tmp, EBI_CSR1);
+
+	if (readl(EBI_CSR1) & INTEGRATOR_EBI_WRITE_ENABLE) {
+		writel(0xa05f, EBI_LOCK);
+		writel(tmp, EBI_CSR1);
+		writel(0, EBI_LOCK);
+	}
+}
+
+static void ap_flash_set_vpp(int on)
+{
+	unsigned long reg = on ? SC_CTRLS : SC_CTRLC;
+
+	writel(INTEGRATOR_SC_CTRL_nFLVPPEN, reg);
+}
+
+static struct flash_platform_data ap_flash_data = {
+	.map_name	= "cfi_probe",
+	.width		= 4,
+	.init		= ap_flash_init,
+	.exit		= ap_flash_exit,
+	.set_vpp	= ap_flash_set_vpp,
+};
+
+static struct resource cfi_flash_resource = {
+	.start		= INTEGRATOR_FLASH_BASE,
+	.end		= INTEGRATOR_FLASH_BASE + INTEGRATOR_FLASH_SIZE - 1,
+	.flags		= IORESOURCE_MEM,
+};
+
+static struct platform_device cfi_flash_device = {
+	.name		= "armflash",
+	.id		= 0,
+	.dev		= {
+		.platform_data	= &ap_flash_data,
+	},
+	.num_resources	= 1,
+	.resource	= &cfi_flash_resource,
+};
+
+static void __init ap_init(void)
+{
+	unsigned long sc_dec;
+	int i;
+
+	platform_device_register(&cfi_flash_device);
+
+	sc_dec = readl(VA_SC_BASE + INTEGRATOR_SC_DEC_OFFSET);
+	for (i = 0; i < 4; i++) {
+		struct lm_device *lmdev;
+
+		if ((sc_dec & (16 << i)) == 0)
+			continue;
+
+		lmdev = kmalloc(sizeof(struct lm_device), GFP_KERNEL);
+		if (!lmdev)
+			continue;
+
+		memset(lmdev, 0, sizeof(struct lm_device));
+
+		lmdev->resource.start = 0xc0000000 + 0x10000000 * i;
+		lmdev->resource.end = lmdev->resource.start + 0x0fffffff;
+		lmdev->resource.flags = IORESOURCE_MEM;
+		lmdev->irq = IRQ_AP_EXPINT0 + i;
+		lmdev->id = i;
+
+		lm_device_register(lmdev);
+	}
+}
+
+static void __init ap_init_timer(void)
+{
+	integrator_time_init(1000000 * TICKS_PER_uSEC / HZ, 0);
+}
+
+static struct sys_timer ap_timer = {
+	.init		= ap_init_timer,
+	.offset		= integrator_gettimeoffset,
+};
+
+MACHINE_START(INTEGRATOR, "ARM-Integrator")
+	MAINTAINER("ARM Ltd/Deep Blue Solutions Ltd")
+	BOOT_MEM(0x00000000, 0x16000000, 0xf1600000)
+	BOOT_PARAMS(0x00000100)
+	MAPIO(ap_map_io)
+	INITIRQ(ap_init_irq)
+	.timer		= &ap_timer,
+	INIT_MACHINE(ap_init)
+MACHINE_END
diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c
new file mode 100644
index 0000000..68e15c3
--- /dev/null
+++ b/arch/arm/mach-integrator/integrator_cp.c
@@ -0,0 +1,528 @@
+/*
+ *  linux/arch/arm/mach-integrator/integrator_cp.c
+ *
+ *  Copyright (C) 2003 Deep Blue Solutions Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/sysdev.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/hardware/amba.h>
+#include <asm/hardware/amba_kmi.h>
+#include <asm/hardware/amba_clcd.h>
+#include <asm/hardware/icst525.h>
+
+#include <asm/arch/cm.h>
+#include <asm/arch/lm.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/flash.h>
+#include <asm/mach/irq.h>
+#include <asm/mach/mmc.h>
+#include <asm/mach/map.h>
+#include <asm/mach/time.h>
+
+#include "common.h"
+#include "clock.h"
+
+#define INTCP_PA_MMC_BASE		0x1c000000
+#define INTCP_PA_AACI_BASE		0x1d000000
+
+#define INTCP_PA_FLASH_BASE		0x24000000
+#define INTCP_FLASH_SIZE		SZ_32M
+
+#define INTCP_PA_CLCD_BASE		0xc0000000
+
+#define INTCP_VA_CIC_BASE		0xf1000040
+#define INTCP_VA_PIC_BASE		0xf1400000
+#define INTCP_VA_SIC_BASE		0xfca00000
+
+#define INTCP_PA_ETH_BASE		0xc8000000
+#define INTCP_ETH_SIZE			0x10
+
+#define INTCP_VA_CTRL_BASE		0xfcb00000
+#define INTCP_FLASHPROG			0x04
+#define CINTEGRATOR_FLASHPROG_FLVPPEN	(1 << 0)
+#define CINTEGRATOR_FLASHPROG_FLWREN	(1 << 1)
+
+/*
+ * Logical      Physical
+ * f1000000	10000000	Core module registers
+ * f1100000	11000000	System controller registers
+ * f1200000	12000000	EBI registers
+ * f1300000	13000000	Counter/Timer
+ * f1400000	14000000	Interrupt controller
+ * f1600000	16000000	UART 0
+ * f1700000	17000000	UART 1
+ * f1a00000	1a000000	Debug LEDs
+ * f1b00000	1b000000	GPIO
+ */
+
+static struct map_desc intcp_io_desc[] __initdata = {
+ { IO_ADDRESS(INTEGRATOR_HDR_BASE),   INTEGRATOR_HDR_BASE,   SZ_4K,  MT_DEVICE },
+ { IO_ADDRESS(INTEGRATOR_SC_BASE),    INTEGRATOR_SC_BASE,    SZ_4K,  MT_DEVICE },
+ { IO_ADDRESS(INTEGRATOR_EBI_BASE),   INTEGRATOR_EBI_BASE,   SZ_4K,  MT_DEVICE },
+ { IO_ADDRESS(INTEGRATOR_CT_BASE),    INTEGRATOR_CT_BASE,    SZ_4K,  MT_DEVICE },
+ { IO_ADDRESS(INTEGRATOR_IC_BASE),    INTEGRATOR_IC_BASE,    SZ_4K,  MT_DEVICE },
+ { IO_ADDRESS(INTEGRATOR_UART0_BASE), INTEGRATOR_UART0_BASE, SZ_4K,  MT_DEVICE },
+ { IO_ADDRESS(INTEGRATOR_UART1_BASE), INTEGRATOR_UART1_BASE, SZ_4K,  MT_DEVICE },
+ { IO_ADDRESS(INTEGRATOR_DBG_BASE),   INTEGRATOR_DBG_BASE,   SZ_4K,  MT_DEVICE },
+ { IO_ADDRESS(INTEGRATOR_GPIO_BASE),  INTEGRATOR_GPIO_BASE,  SZ_4K,  MT_DEVICE },
+ { 0xfc900000, 0xc9000000, SZ_4K, MT_DEVICE },
+ { 0xfca00000, 0xca000000, SZ_4K, MT_DEVICE },
+ { 0xfcb00000, 0xcb000000, SZ_4K, MT_DEVICE },
+};
+
+static void __init intcp_map_io(void)
+{
+	iotable_init(intcp_io_desc, ARRAY_SIZE(intcp_io_desc));
+}
+
+#define cic_writel	__raw_writel
+#define cic_readl	__raw_readl
+#define pic_writel	__raw_writel
+#define pic_readl	__raw_readl
+#define sic_writel	__raw_writel
+#define sic_readl	__raw_readl
+
+static void cic_mask_irq(unsigned int irq)
+{
+	irq -= IRQ_CIC_START;
+	cic_writel(1 << irq, INTCP_VA_CIC_BASE + IRQ_ENABLE_CLEAR);
+}
+
+static void cic_unmask_irq(unsigned int irq)
+{
+	irq -= IRQ_CIC_START;
+	cic_writel(1 << irq, INTCP_VA_CIC_BASE + IRQ_ENABLE_SET);
+}
+
+static struct irqchip cic_chip = {
+	.ack	= cic_mask_irq,
+	.mask	= cic_mask_irq,
+	.unmask	= cic_unmask_irq,
+};
+
+static void pic_mask_irq(unsigned int irq)
+{
+	irq -= IRQ_PIC_START;
+	pic_writel(1 << irq, INTCP_VA_PIC_BASE + IRQ_ENABLE_CLEAR);
+}
+
+static void pic_unmask_irq(unsigned int irq)
+{
+	irq -= IRQ_PIC_START;
+	pic_writel(1 << irq, INTCP_VA_PIC_BASE + IRQ_ENABLE_SET);
+}
+
+static struct irqchip pic_chip = {
+	.ack	= pic_mask_irq,
+	.mask	= pic_mask_irq,
+	.unmask = pic_unmask_irq,
+};
+
+static void sic_mask_irq(unsigned int irq)
+{
+	irq -= IRQ_SIC_START;
+	sic_writel(1 << irq, INTCP_VA_SIC_BASE + IRQ_ENABLE_CLEAR);
+}
+
+static void sic_unmask_irq(unsigned int irq)
+{
+	irq -= IRQ_SIC_START;
+	sic_writel(1 << irq, INTCP_VA_SIC_BASE + IRQ_ENABLE_SET);
+}
+
+static struct irqchip sic_chip = {
+	.ack	= sic_mask_irq,
+	.mask	= sic_mask_irq,
+	.unmask	= sic_unmask_irq,
+};
+
+static void
+sic_handle_irq(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
+{
+	unsigned long status = sic_readl(INTCP_VA_SIC_BASE + IRQ_STATUS);
+
+	if (status == 0) {
+		do_bad_IRQ(irq, desc, regs);
+		return;
+	}
+
+	do {
+		irq = ffs(status) - 1;
+		status &= ~(1 << irq);
+
+		irq += IRQ_SIC_START;
+
+		desc = irq_desc + irq;
+		desc->handle(irq, desc, regs);
+	} while (status);
+}
+
+static void __init intcp_init_irq(void)
+{
+	unsigned int i;
+
+	/*
+	 * Disable all interrupt sources
+	 */
+	pic_writel(0xffffffff, INTCP_VA_PIC_BASE + IRQ_ENABLE_CLEAR);
+	pic_writel(0xffffffff, INTCP_VA_PIC_BASE + FIQ_ENABLE_CLEAR);
+
+	for (i = IRQ_PIC_START; i <= IRQ_PIC_END; i++) {
+		if (i == 11)
+			i = 22;
+		if (i == IRQ_CP_CPPLDINT)
+			i++;
+		if (i == 29)
+			break;
+		set_irq_chip(i, &pic_chip);
+		set_irq_handler(i, do_level_IRQ);
+		set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
+	}
+
+	cic_writel(0xffffffff, INTCP_VA_CIC_BASE + IRQ_ENABLE_CLEAR);
+	cic_writel(0xffffffff, INTCP_VA_CIC_BASE + FIQ_ENABLE_CLEAR);
+
+	for (i = IRQ_CIC_START; i <= IRQ_CIC_END; i++) {
+		set_irq_chip(i, &cic_chip);
+		set_irq_handler(i, do_level_IRQ);
+		set_irq_flags(i, IRQF_VALID);
+	}
+
+	sic_writel(0x00000fff, INTCP_VA_SIC_BASE + IRQ_ENABLE_CLEAR);
+	sic_writel(0x00000fff, INTCP_VA_SIC_BASE + FIQ_ENABLE_CLEAR);
+
+	for (i = IRQ_SIC_START; i <= IRQ_SIC_END; i++) {
+		set_irq_chip(i, &sic_chip);
+		set_irq_handler(i, do_level_IRQ);
+		set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
+	}
+
+	set_irq_handler(IRQ_CP_CPPLDINT, sic_handle_irq);
+	pic_unmask_irq(IRQ_CP_CPPLDINT);
+}
+
+/*
+ * Clock handling
+ */
+#define CM_LOCK (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_LOCK_OFFSET)
+#define CM_AUXOSC (IO_ADDRESS(INTEGRATOR_HDR_BASE)+0x1c)
+
+static const struct icst525_params cp_auxvco_params = {
+	.ref		= 24000,
+	.vco_max	= 320000,
+	.vd_min 	= 8,
+	.vd_max 	= 263,
+	.rd_min 	= 3,
+	.rd_max 	= 65,
+};
+
+static void cp_auxvco_set(struct clk *clk, struct icst525_vco vco)
+{
+	u32 val;
+
+	val = readl(CM_AUXOSC) & ~0x7ffff;
+	val |= vco.v | (vco.r << 9) | (vco.s << 16);
+
+	writel(0xa05f, CM_LOCK);
+	writel(val, CM_AUXOSC);
+	writel(0, CM_LOCK);
+}
+
+static struct clk cp_clcd_clk = {
+	.name	= "CLCDCLK",
+	.params	= &cp_auxvco_params,
+	.setvco = cp_auxvco_set,
+};
+
+static struct clk cp_mmci_clk = {
+	.name	= "MCLK",
+	.rate	= 14745600,
+};
+
+/*
+ * Flash handling.
+ */
+static int intcp_flash_init(void)
+{
+	u32 val;
+
+	val = readl(INTCP_VA_CTRL_BASE + INTCP_FLASHPROG);
+	val |= CINTEGRATOR_FLASHPROG_FLWREN;
+	writel(val, INTCP_VA_CTRL_BASE + INTCP_FLASHPROG);
+
+	return 0;
+}
+
+static void intcp_flash_exit(void)
+{
+	u32 val;
+
+	val = readl(INTCP_VA_CTRL_BASE + INTCP_FLASHPROG);
+	val &= ~(CINTEGRATOR_FLASHPROG_FLVPPEN|CINTEGRATOR_FLASHPROG_FLWREN);
+	writel(val, INTCP_VA_CTRL_BASE + INTCP_FLASHPROG);
+}
+
+static void intcp_flash_set_vpp(int on)
+{
+	u32 val;
+
+	val = readl(INTCP_VA_CTRL_BASE + INTCP_FLASHPROG);
+	if (on)
+		val |= CINTEGRATOR_FLASHPROG_FLVPPEN;
+	else
+		val &= ~CINTEGRATOR_FLASHPROG_FLVPPEN;
+	writel(val, INTCP_VA_CTRL_BASE + INTCP_FLASHPROG);
+}
+
+static struct flash_platform_data intcp_flash_data = {
+	.map_name	= "cfi_probe",
+	.width		= 4,
+	.init		= intcp_flash_init,
+	.exit		= intcp_flash_exit,
+	.set_vpp	= intcp_flash_set_vpp,
+};
+
+static struct resource intcp_flash_resource = {
+	.start		= INTCP_PA_FLASH_BASE,
+	.end		= INTCP_PA_FLASH_BASE + INTCP_FLASH_SIZE - 1,
+	.flags		= IORESOURCE_MEM,
+};
+
+static struct platform_device intcp_flash_device = {
+	.name		= "armflash",
+	.id		= 0,
+	.dev		= {
+		.platform_data	= &intcp_flash_data,
+	},
+	.num_resources	= 1,
+	.resource	= &intcp_flash_resource,
+};
+
+static struct resource smc91x_resources[] = {
+	[0] = {
+		.start	= INTCP_PA_ETH_BASE,
+		.end	= INTCP_PA_ETH_BASE + INTCP_ETH_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= IRQ_CP_ETHINT,
+		.end	= IRQ_CP_ETHINT,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device smc91x_device = {
+	.name		= "smc91x",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(smc91x_resources),
+	.resource	= smc91x_resources,
+};
+
+static struct platform_device *intcp_devs[] __initdata = {
+	&intcp_flash_device,
+	&smc91x_device,
+};
+
+/*
+ * It seems that the card insertion interrupt remains active after
+ * we've acknowledged it.  We therefore ignore the interrupt, and
+ * rely on reading it from the SIC.  This also means that we must
+ * clear the latched interrupt.
+ */
+static unsigned int mmc_status(struct device *dev)
+{
+	unsigned int status = readl(0xfca00004);
+	writel(8, 0xfcb00008);
+
+	return status & 8;
+}
+
+static struct mmc_platform_data mmc_data = {
+	.ocr_mask	= MMC_VDD_32_33|MMC_VDD_33_34,
+	.status		= mmc_status,
+};
+
+static struct amba_device mmc_device = {
+	.dev		= {
+		.bus_id	= "mb:1c",
+		.platform_data = &mmc_data,
+	},
+	.res		= {
+		.start	= INTCP_PA_MMC_BASE,
+		.end	= INTCP_PA_MMC_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	.irq		= { IRQ_CP_MMCIINT0, IRQ_CP_MMCIINT1 },
+	.periphid	= 0,
+};
+
+static struct amba_device aaci_device = {
+	.dev		= {
+		.bus_id	= "mb:1d",
+	},
+	.res		= {
+		.start	= INTCP_PA_AACI_BASE,
+		.end	= INTCP_PA_AACI_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	.irq		= { IRQ_CP_AACIINT, NO_IRQ },
+	.periphid	= 0,
+};
+
+
+/*
+ * CLCD support
+ */
+static struct clcd_panel vga = {
+	.mode		= {
+		.name		= "VGA",
+		.refresh	= 60,
+		.xres		= 640,
+		.yres		= 480,
+		.pixclock	= 39721,
+		.left_margin	= 40,
+		.right_margin	= 24,
+		.upper_margin	= 32,
+		.lower_margin	= 11,
+		.hsync_len	= 96,
+		.vsync_len	= 2,
+		.sync		= 0,
+		.vmode		= FB_VMODE_NONINTERLACED,
+	},
+	.width		= -1,
+	.height		= -1,
+	.tim2		= TIM2_BCD | TIM2_IPC,
+	.cntl		= CNTL_LCDTFT | CNTL_LCDVCOMP(1),
+	.bpp		= 16,
+	.grayscale	= 0,
+};
+
+/*
+ * Ensure VGA is selected.
+ */
+static void cp_clcd_enable(struct clcd_fb *fb)
+{
+	cm_control(CM_CTRL_LCDMUXSEL_MASK, CM_CTRL_LCDMUXSEL_VGA);
+}
+
+static unsigned long framesize = SZ_1M;
+
+static int cp_clcd_setup(struct clcd_fb *fb)
+{
+	dma_addr_t dma;
+
+	fb->panel = &vga;
+
+	fb->fb.screen_base = dma_alloc_writecombine(&fb->dev->dev, framesize,
+						    &dma, GFP_KERNEL);
+	if (!fb->fb.screen_base) {
+		printk(KERN_ERR "CLCD: unable to map framebuffer\n");
+		return -ENOMEM;
+	}
+
+	fb->fb.fix.smem_start	= dma;
+	fb->fb.fix.smem_len	= framesize;
+
+	return 0;
+}
+
+static int cp_clcd_mmap(struct clcd_fb *fb, struct vm_area_struct *vma)
+{
+	return dma_mmap_writecombine(&fb->dev->dev, vma,
+				     fb->fb.screen_base,
+				     fb->fb.fix.smem_start,
+				     fb->fb.fix.smem_len);
+}
+
+static void cp_clcd_remove(struct clcd_fb *fb)
+{
+	dma_free_writecombine(&fb->dev->dev, fb->fb.fix.smem_len,
+			      fb->fb.screen_base, fb->fb.fix.smem_start);
+}
+
+static struct clcd_board clcd_data = {
+	.name		= "Integrator/CP",
+	.check		= clcdfb_check,
+	.decode		= clcdfb_decode,
+	.enable		= cp_clcd_enable,
+	.setup		= cp_clcd_setup,
+	.mmap		= cp_clcd_mmap,
+	.remove		= cp_clcd_remove,
+};
+
+static struct amba_device clcd_device = {
+	.dev		= {
+		.bus_id	= "mb:c0",
+		.coherent_dma_mask = ~0,
+		.platform_data = &clcd_data,
+	},
+	.res		= {
+		.start	= INTCP_PA_CLCD_BASE,
+		.end	= INTCP_PA_CLCD_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	.dma_mask	= ~0,
+	.irq		= { IRQ_CP_CLCDCINT, NO_IRQ },
+	.periphid	= 0,
+};
+
+static struct amba_device *amba_devs[] __initdata = {
+	&mmc_device,
+	&aaci_device,
+	&clcd_device,
+};
+
+static void __init intcp_init(void)
+{
+	int i;
+
+	clk_register(&cp_clcd_clk);
+	clk_register(&cp_mmci_clk);
+
+	platform_add_devices(intcp_devs, ARRAY_SIZE(intcp_devs));
+
+	for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
+		struct amba_device *d = amba_devs[i];
+		amba_device_register(d, &iomem_resource);
+	}
+}
+
+#define TIMER_CTRL_IE	(1 << 5)			/* Interrupt Enable */
+
+static void __init intcp_timer_init(void)
+{
+	integrator_time_init(1000000 / HZ, TIMER_CTRL_IE);
+}
+
+static struct sys_timer cp_timer = {
+	.init		= intcp_timer_init,
+	.offset		= integrator_gettimeoffset,
+};
+
+MACHINE_START(CINTEGRATOR, "ARM-IntegratorCP")
+	MAINTAINER("ARM Ltd/Deep Blue Solutions Ltd")
+	BOOT_MEM(0x00000000, 0x16000000, 0xf1600000)
+	BOOT_PARAMS(0x00000100)
+	MAPIO(intcp_map_io)
+	INITIRQ(intcp_init_irq)
+	.timer		= &cp_timer,
+	INIT_MACHINE(intcp_init)
+MACHINE_END
diff --git a/arch/arm/mach-integrator/leds.c b/arch/arm/mach-integrator/leds.c
new file mode 100644
index 0000000..9d182b7
--- /dev/null
+++ b/arch/arm/mach-integrator/leds.c
@@ -0,0 +1,88 @@
+/*
+ *  linux/arch/arm/mach-integrator/leds.c
+ *
+ *  Integrator/AP and Integrator/CP LED control routines
+ *
+ *  Copyright (C) 1999 ARM Limited
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/leds.h>
+#include <asm/system.h>
+#include <asm/mach-types.h>
+#include <asm/arch/cm.h>
+
+static int saved_leds;
+
+static void integrator_leds_event(led_event_t ledevt)
+{
+	unsigned long flags;
+	const unsigned int dbg_base = IO_ADDRESS(INTEGRATOR_DBG_BASE);
+	unsigned int update_alpha_leds;
+	
+	// yup, change the LEDs
+	local_irq_save(flags);
+	update_alpha_leds = 0;
+
+	switch(ledevt) {
+	case led_idle_start:
+		cm_control(CM_CTRL_LED, 0);
+		break;
+
+	case led_idle_end:
+		cm_control(CM_CTRL_LED, CM_CTRL_LED);
+		break;
+
+	case led_timer:
+		saved_leds ^= GREEN_LED;
+		update_alpha_leds = 1;
+		break;
+
+	case led_red_on:
+		saved_leds |= RED_LED;
+		update_alpha_leds = 1;
+		break;
+
+	case led_red_off:
+		saved_leds &= ~RED_LED;
+		update_alpha_leds = 1;
+		break;
+
+	default:
+		break;
+	}
+
+	if (update_alpha_leds) {
+		while (__raw_readl(dbg_base + INTEGRATOR_DBG_ALPHA_OFFSET) & 1);
+		__raw_writel(saved_leds, dbg_base + INTEGRATOR_DBG_LEDS_OFFSET);
+	}
+	local_irq_restore(flags);
+}
+
+static int __init leds_init(void)
+{
+	if (machine_is_integrator() || machine_is_cintegrator())
+		leds_event = integrator_leds_event;
+
+	return 0;
+}
+
+__initcall(leds_init);
diff --git a/arch/arm/mach-integrator/lm.c b/arch/arm/mach-integrator/lm.c
new file mode 100644
index 0000000..c5f19d1
--- /dev/null
+++ b/arch/arm/mach-integrator/lm.c
@@ -0,0 +1,96 @@
+/*
+ *  linux/arch/arm/mach-integrator/lm.c
+ *
+ *  Copyright (C) 2003 Deep Blue Solutions Ltd, All Rights Reserved.
+ *
+ * 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/init.h>
+#include <linux/device.h>
+
+#include <asm/arch/lm.h>
+
+#define to_lm_device(d)	container_of(d, struct lm_device, dev)
+#define to_lm_driver(d)	container_of(d, struct lm_driver, drv)
+
+static int lm_match(struct device *dev, struct device_driver *drv)
+{
+	return 1;
+}
+
+static struct bus_type lm_bustype = {
+	.name		= "logicmodule",
+	.match		= lm_match,
+//	.suspend	= lm_suspend,
+//	.resume		= lm_resume,
+};
+
+static int __init lm_init(void)
+{
+	return bus_register(&lm_bustype);
+}
+
+postcore_initcall(lm_init);
+
+static int lm_bus_probe(struct device *dev)
+{
+	struct lm_device *lmdev = to_lm_device(dev);
+	struct lm_driver *lmdrv = to_lm_driver(dev->driver);
+
+	return lmdrv->probe(lmdev);
+}
+
+static int lm_bus_remove(struct device *dev)
+{
+	struct lm_device *lmdev = to_lm_device(dev);
+	struct lm_driver *lmdrv = to_lm_driver(dev->driver);
+
+	lmdrv->remove(lmdev);
+	return 0;
+}
+
+int lm_driver_register(struct lm_driver *drv)
+{
+	drv->drv.bus = &lm_bustype;
+	drv->drv.probe = lm_bus_probe;
+	drv->drv.remove = lm_bus_remove;
+
+	return driver_register(&drv->drv);
+}
+
+void lm_driver_unregister(struct lm_driver *drv)
+{
+	driver_unregister(&drv->drv);
+}
+
+static void lm_device_release(struct device *dev)
+{
+	struct lm_device *d = to_lm_device(dev);
+
+	kfree(d);
+}
+
+int lm_device_register(struct lm_device *dev)
+{
+	int ret;
+
+	dev->dev.release = lm_device_release;
+	dev->dev.bus = &lm_bustype;
+
+	snprintf(dev->dev.bus_id, sizeof(dev->dev.bus_id), "lm%d", dev->id);
+	dev->resource.name = dev->dev.bus_id;
+
+	ret = request_resource(&iomem_resource, &dev->resource);
+	if (ret == 0) {
+		ret = device_register(&dev->dev);
+		if (ret)
+			release_resource(&dev->resource);
+	}
+	return ret;
+}
+
+EXPORT_SYMBOL(lm_driver_register);
+EXPORT_SYMBOL(lm_driver_unregister);
diff --git a/arch/arm/mach-integrator/pci.c b/arch/arm/mach-integrator/pci.c
new file mode 100644
index 0000000..394ec92
--- /dev/null
+++ b/arch/arm/mach-integrator/pci.c
@@ -0,0 +1,132 @@
+/*
+ *  linux/arch/arm/mach-integrator/pci-integrator.c
+ *
+ *  Copyright (C) 1999 ARM Limited
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *
+ *  PCI functions for Integrator
+ */
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/ptrace.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/mach/pci.h>
+#include <asm/mach-types.h>
+
+/* 
+ * A small note about bridges and interrupts.  The DECchip 21050 (and
+ * later) adheres to the PCI-PCI bridge specification.  This says that
+ * the interrupts on the other side of a bridge are swizzled in the
+ * following manner:
+ *
+ * Dev    Interrupt   Interrupt 
+ *        Pin on      Pin on 
+ *        Device      Connector
+ *
+ *   4    A           A
+ *        B           B
+ *        C           C
+ *        D           D
+ * 
+ *   5    A           B
+ *        B           C
+ *        C           D
+ *        D           A
+ *
+ *   6    A           C
+ *        B           D
+ *        C           A
+ *        D           B
+ *
+ *   7    A           D
+ *        B           A
+ *        C           B
+ *        D           C
+ *
+ * Where A = pin 1, B = pin 2 and so on and pin=0 = default = A.
+ * Thus, each swizzle is ((pin-1) + (device#-4)) % 4
+ *
+ * The following code swizzles for exactly one bridge.  
+ */
+static inline int bridge_swizzle(int pin, unsigned int slot) 
+{
+	return (pin + slot) & 3;
+}
+
+/*
+ * This routine handles multiple bridges.
+ */
+static u8 __init integrator_swizzle(struct pci_dev *dev, u8 *pinp)
+{
+	int pin = *pinp;
+
+	if (pin == 0)
+		pin = 1;
+
+	pin -= 1;
+	while (dev->bus->self) {
+		pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn));
+		/*
+		 * move up the chain of bridges, swizzling as we go.
+		 */
+		dev = dev->bus->self;
+	}
+	*pinp = pin + 1;
+
+	return PCI_SLOT(dev->devfn);
+}
+
+static int irq_tab[4] __initdata = {
+	IRQ_AP_PCIINT0,	IRQ_AP_PCIINT1,	IRQ_AP_PCIINT2,	IRQ_AP_PCIINT3
+};
+
+/*
+ * map the specified device/slot/pin to an IRQ.  This works out such
+ * that slot 9 pin 1 is INT0, pin 2 is INT1, and slot 10 pin 1 is INT1.
+ */
+static int __init integrator_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+	int intnr = ((slot - 9) + (pin - 1)) & 3;
+
+	return irq_tab[intnr];
+}
+
+extern void pci_v3_init(void *);
+
+static struct hw_pci integrator_pci __initdata = {
+	.swizzle		= integrator_swizzle,
+	.map_irq		= integrator_map_irq,
+	.setup			= pci_v3_setup,
+	.nr_controllers		= 1,
+	.scan			= pci_v3_scan_bus,
+	.preinit		= pci_v3_preinit,
+	.postinit		= pci_v3_postinit,
+};
+
+static int __init integrator_pci_init(void)
+{
+	if (machine_is_integrator())
+		pci_common_init(&integrator_pci);
+	return 0;
+}
+
+subsys_initcall(integrator_pci_init);
diff --git a/arch/arm/mach-integrator/pci_v3.c b/arch/arm/mach-integrator/pci_v3.c
new file mode 100644
index 0000000..229a63a
--- /dev/null
+++ b/arch/arm/mach-integrator/pci_v3.c
@@ -0,0 +1,604 @@
+/*
+ *  linux/arch/arm/mach-integrator/pci_v3.c
+ *
+ *  PCI functions for V3 host PCI bridge
+ *
+ *  Copyright (C) 1999 ARM Limited
+ *  Copyright (C) 2000-2001 Deep Blue Solutions Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/init.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/mach/pci.h>
+
+#include <asm/hardware/pci_v3.h>
+
+/*
+ * The V3 PCI interface chip in Integrator provides several windows from
+ * local bus memory into the PCI memory areas.   Unfortunately, there
+ * are not really enough windows for our usage, therefore we reuse 
+ * one of the windows for access to PCI configuration space.  The
+ * memory map is as follows:
+ * 
+ * Local Bus Memory         Usage
+ * 
+ * 40000000 - 4FFFFFFF      PCI memory.  256M non-prefetchable
+ * 50000000 - 5FFFFFFF      PCI memory.  256M prefetchable
+ * 60000000 - 60FFFFFF      PCI IO.  16M
+ * 61000000 - 61FFFFFF      PCI Configuration. 16M
+ * 
+ * There are three V3 windows, each described by a pair of V3 registers.
+ * These are LB_BASE0/LB_MAP0, LB_BASE1/LB_MAP1 and LB_BASE2/LB_MAP2.
+ * Base0 and Base1 can be used for any type of PCI memory access.   Base2
+ * can be used either for PCI I/O or for I20 accesses.  By default, uHAL
+ * uses this only for PCI IO space.
+ * 
+ * Normally these spaces are mapped using the following base registers:
+ * 
+ * Usage Local Bus Memory         Base/Map registers used
+ * 
+ * Mem   40000000 - 4FFFFFFF      LB_BASE0/LB_MAP0
+ * Mem   50000000 - 5FFFFFFF      LB_BASE1/LB_MAP1
+ * IO    60000000 - 60FFFFFF      LB_BASE2/LB_MAP2
+ * Cfg   61000000 - 61FFFFFF
+ * 
+ * This means that I20 and PCI configuration space accesses will fail.
+ * When PCI configuration accesses are needed (via the uHAL PCI 
+ * configuration space primitives) we must remap the spaces as follows:
+ * 
+ * Usage Local Bus Memory         Base/Map registers used
+ * 
+ * Mem   40000000 - 4FFFFFFF      LB_BASE0/LB_MAP0
+ * Mem   50000000 - 5FFFFFFF      LB_BASE0/LB_MAP0
+ * IO    60000000 - 60FFFFFF      LB_BASE2/LB_MAP2
+ * Cfg   61000000 - 61FFFFFF      LB_BASE1/LB_MAP1
+ * 
+ * To make this work, the code depends on overlapping windows working.
+ * The V3 chip translates an address by checking its range within 
+ * each of the BASE/MAP pairs in turn (in ascending register number
+ * order).  It will use the first matching pair.   So, for example,
+ * if the same address is mapped by both LB_BASE0/LB_MAP0 and
+ * LB_BASE1/LB_MAP1, the V3 will use the translation from 
+ * LB_BASE0/LB_MAP0.
+ * 
+ * To allow PCI Configuration space access, the code enlarges the
+ * window mapped by LB_BASE0/LB_MAP0 from 256M to 512M.  This occludes
+ * the windows currently mapped by LB_BASE1/LB_MAP1 so that it can
+ * be remapped for use by configuration cycles.
+ * 
+ * At the end of the PCI Configuration space accesses, 
+ * LB_BASE1/LB_MAP1 is reset to map PCI Memory.  Finally the window
+ * mapped by LB_BASE0/LB_MAP0 is reduced in size from 512M to 256M to
+ * reveal the now restored LB_BASE1/LB_MAP1 window.
+ * 
+ * NOTE: We do not set up I2O mapping.  I suspect that this is only
+ * for an intelligent (target) device.  Using I2O disables most of
+ * the mappings into PCI memory.
+ */
+
+// V3 access routines
+#define v3_writeb(o,v) __raw_writeb(v, PCI_V3_VADDR + (unsigned int)(o))
+#define v3_readb(o)    (__raw_readb(PCI_V3_VADDR + (unsigned int)(o)))
+
+#define v3_writew(o,v) __raw_writew(v, PCI_V3_VADDR + (unsigned int)(o))
+#define v3_readw(o)    (__raw_readw(PCI_V3_VADDR + (unsigned int)(o)))
+
+#define v3_writel(o,v) __raw_writel(v, PCI_V3_VADDR + (unsigned int)(o))
+#define v3_readl(o)    (__raw_readl(PCI_V3_VADDR + (unsigned int)(o)))
+
+/*============================================================================
+ *
+ * routine:	uHALir_PCIMakeConfigAddress()
+ *
+ * parameters:	bus = which bus
+ *              device = which device
+ *              function = which function
+ *		offset = configuration space register we are interested in
+ *
+ * description:	this routine will generate a platform dependent config
+ *		address.
+ *
+ * calls:	none
+ *
+ * returns:	configuration address to play on the PCI bus
+ *
+ * To generate the appropriate PCI configuration cycles in the PCI 
+ * configuration address space, you present the V3 with the following pattern 
+ * (which is very nearly a type 1 (except that the lower two bits are 00 and
+ * not 01).   In order for this mapping to work you need to set up one of
+ * the local to PCI aperatures to 16Mbytes in length translating to
+ * PCI configuration space starting at 0x0000.0000.
+ *
+ * PCI configuration cycles look like this:
+ *
+ * Type 0:
+ *
+ *  3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 
+ *  3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | | |D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|0|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ *	31:11	Device select bit.
+ * 	10:8	Function number
+ * 	 7:2	Register number
+ *
+ * Type 1:
+ *
+ *  3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 
+ *  3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | | | | | | | | | | |B|B|B|B|B|B|B|B|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|1|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ *	31:24	reserved
+ *	23:16	bus number (8 bits = 128 possible buses)
+ *	15:11	Device number (5 bits)
+ *	10:8	function number
+ *	 7:2	register number
+ *  
+ */
+static DEFINE_SPINLOCK(v3_lock);
+
+#define PCI_BUS_NONMEM_START	0x00000000
+#define PCI_BUS_NONMEM_SIZE	SZ_256M
+
+#define PCI_BUS_PREMEM_START	PCI_BUS_NONMEM_START + PCI_BUS_NONMEM_SIZE
+#define PCI_BUS_PREMEM_SIZE	SZ_256M
+
+#if PCI_BUS_NONMEM_START & 0x000fffff
+#error PCI_BUS_NONMEM_START must be megabyte aligned
+#endif
+#if PCI_BUS_PREMEM_START & 0x000fffff
+#error PCI_BUS_PREMEM_START must be megabyte aligned
+#endif
+
+#undef V3_LB_BASE_PREFETCH
+#define V3_LB_BASE_PREFETCH 0
+
+static unsigned long v3_open_config_window(struct pci_bus *bus,
+					   unsigned int devfn, int offset)
+{
+	unsigned int address, mapaddress, busnr;
+
+	busnr = bus->number;
+
+	/*
+	 * Trap out illegal values
+	 */
+	if (offset > 255)
+		BUG();
+	if (busnr > 255)
+		BUG();
+	if (devfn > 255)
+		BUG();
+
+	if (busnr == 0) {
+		int slot = PCI_SLOT(devfn);
+
+		/*
+		 * local bus segment so need a type 0 config cycle
+		 *
+		 * build the PCI configuration "address" with one-hot in
+		 * A31-A11
+		 *
+		 * mapaddress:
+		 *  3:1 = config cycle (101)
+		 *  0   = PCI A1 & A0 are 0 (0)
+		 */
+		address = PCI_FUNC(devfn) << 8;
+		mapaddress = V3_LB_MAP_TYPE_CONFIG;
+
+		if (slot > 12)
+			/*
+			 * high order bits are handled by the MAP register
+			 */
+			mapaddress |= 1 << (slot - 5);
+		else
+			/*
+			 * low order bits handled directly in the address
+			 */
+			address |= 1 << (slot + 11);
+	} else {
+        	/*
+		 * not the local bus segment so need a type 1 config cycle
+		 *
+		 * address:
+		 *  23:16 = bus number
+		 *  15:11 = slot number (7:3 of devfn)
+		 *  10:8  = func number (2:0 of devfn)
+		 *
+		 * mapaddress:
+		 *  3:1 = config cycle (101)
+		 *  0   = PCI A1 & A0 from host bus (1)
+		 */
+		mapaddress = V3_LB_MAP_TYPE_CONFIG | V3_LB_MAP_AD_LOW_EN;
+		address = (busnr << 16) | (devfn << 8);
+	}
+
+	/*
+	 * Set up base0 to see all 512Mbytes of memory space (not
+	 * prefetchable), this frees up base1 for re-use by
+	 * configuration memory
+	 */
+	v3_writel(V3_LB_BASE0, v3_addr_to_lb_base(PHYS_PCI_MEM_BASE) |
+			V3_LB_BASE_ADR_SIZE_512MB | V3_LB_BASE_ENABLE);
+
+	/*
+	 * Set up base1/map1 to point into configuration space.
+	 */
+	v3_writel(V3_LB_BASE1, v3_addr_to_lb_base(PHYS_PCI_CONFIG_BASE) |
+			V3_LB_BASE_ADR_SIZE_16MB | V3_LB_BASE_ENABLE);
+	v3_writew(V3_LB_MAP1, mapaddress);
+
+	return PCI_CONFIG_VADDR + address + offset;
+}
+
+static void v3_close_config_window(void)
+{
+	/*
+	 * Reassign base1 for use by prefetchable PCI memory
+	 */
+	v3_writel(V3_LB_BASE1, v3_addr_to_lb_base(PHYS_PCI_MEM_BASE + SZ_256M) |
+			V3_LB_BASE_ADR_SIZE_256MB | V3_LB_BASE_PREFETCH |
+			V3_LB_BASE_ENABLE);
+	v3_writew(V3_LB_MAP1, v3_addr_to_lb_map(PCI_BUS_PREMEM_START) |
+			V3_LB_MAP_TYPE_MEM_MULTIPLE);
+
+	/*
+	 * And shrink base0 back to a 256M window (NOTE: MAP0 already correct)
+	 */
+	v3_writel(V3_LB_BASE0, v3_addr_to_lb_base(PHYS_PCI_MEM_BASE) |
+			V3_LB_BASE_ADR_SIZE_256MB | V3_LB_BASE_ENABLE);
+}
+
+static int v3_read_config(struct pci_bus *bus, unsigned int devfn, int where,
+			  int size, u32 *val)
+{
+	unsigned long addr;
+	unsigned long flags;
+	u32 v;
+
+	spin_lock_irqsave(&v3_lock, flags);
+	addr = v3_open_config_window(bus, devfn, where);
+
+	switch (size) {
+	case 1:
+		v = __raw_readb(addr);
+		break;
+
+	case 2:
+		v = __raw_readw(addr);
+		break;
+
+	default:
+		v = __raw_readl(addr);
+		break;
+	}
+
+	v3_close_config_window();
+	spin_unlock_irqrestore(&v3_lock, flags);
+
+	*val = v;
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int v3_write_config(struct pci_bus *bus, unsigned int devfn, int where,
+			   int size, u32 val)
+{
+	unsigned long addr;
+	unsigned long flags;
+
+	spin_lock_irqsave(&v3_lock, flags);
+	addr = v3_open_config_window(bus, devfn, where);
+
+	switch (size) {
+	case 1:
+		__raw_writeb((u8)val, addr);
+		__raw_readb(addr);
+		break;
+
+	case 2:
+		__raw_writew((u16)val, addr);
+		__raw_readw(addr);
+		break;
+
+	case 4:
+		__raw_writel(val, addr);
+		__raw_readl(addr);
+		break;
+	}
+
+	v3_close_config_window();
+	spin_unlock_irqrestore(&v3_lock, flags);
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops pci_v3_ops = {
+	.read	= v3_read_config,
+	.write	= v3_write_config,
+};
+
+static struct resource non_mem = {
+	.name	= "PCI non-prefetchable",
+	.start	= PHYS_PCI_MEM_BASE + PCI_BUS_NONMEM_START,
+	.end	= PHYS_PCI_MEM_BASE + PCI_BUS_NONMEM_START + PCI_BUS_NONMEM_SIZE - 1,
+	.flags	= IORESOURCE_MEM,
+};
+
+static struct resource pre_mem = {
+	.name	= "PCI prefetchable",
+	.start	= PHYS_PCI_MEM_BASE + PCI_BUS_PREMEM_START,
+	.end	= PHYS_PCI_MEM_BASE + PCI_BUS_PREMEM_START + PCI_BUS_PREMEM_SIZE - 1,
+	.flags	= IORESOURCE_MEM | IORESOURCE_PREFETCH,
+};
+
+static int __init pci_v3_setup_resources(struct resource **resource)
+{
+	if (request_resource(&iomem_resource, &non_mem)) {
+		printk(KERN_ERR "PCI: unable to allocate non-prefetchable "
+		       "memory region\n");
+		return -EBUSY;
+	}
+	if (request_resource(&iomem_resource, &pre_mem)) {
+		release_resource(&non_mem);
+		printk(KERN_ERR "PCI: unable to allocate prefetchable "
+		       "memory region\n");
+		return -EBUSY;
+	}
+
+	/*
+	 * bus->resource[0] is the IO resource for this bus
+	 * bus->resource[1] is the mem resource for this bus
+	 * bus->resource[2] is the prefetch mem resource for this bus
+	 */
+	resource[0] = &ioport_resource;
+	resource[1] = &non_mem;
+	resource[2] = &pre_mem;
+
+	return 1;
+}
+
+/*
+ * These don't seem to be implemented on the Integrator I have, which
+ * means I can't get additional information on the reason for the pm2fb
+ * problems.  I suppose I'll just have to mind-meld with the machine. ;)
+ */
+#define SC_PCI     (IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_PCIENABLE_OFFSET)
+#define SC_LBFADDR (IO_ADDRESS(INTEGRATOR_SC_BASE) + 0x20)
+#define SC_LBFCODE (IO_ADDRESS(INTEGRATOR_SC_BASE) + 0x24)
+
+static int
+v3_pci_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
+{
+	unsigned long pc = instruction_pointer(regs);
+	unsigned long instr = *(unsigned long *)pc;
+#if 0
+	char buf[128];
+
+	sprintf(buf, "V3 fault: addr 0x%08lx, FSR 0x%03x, PC 0x%08lx [%08lx] LBFADDR=%08x LBFCODE=%02x ISTAT=%02x\n",
+		addr, fsr, pc, instr, __raw_readl(SC_LBFADDR), __raw_readl(SC_LBFCODE) & 255,
+		v3_readb(V3_LB_ISTAT));
+	printk(KERN_DEBUG "%s", buf);
+	printascii(buf);
+#endif
+
+	v3_writeb(V3_LB_ISTAT, 0);
+	__raw_writel(3, SC_PCI);
+
+	/*
+	 * If the instruction being executed was a read,
+	 * make it look like it read all-ones.
+	 */
+	if ((instr & 0x0c100000) == 0x04100000) {
+		int reg = (instr >> 12) & 15;
+		unsigned long val;
+
+		if (instr & 0x00400000)
+			val = 255;
+		else
+			val = -1;
+
+		regs->uregs[reg] = val;
+		regs->ARM_pc += 4;
+		return 0;
+	}
+
+	if ((instr & 0x0e100090) == 0x00100090) {
+		int reg = (instr >> 12) & 15;
+
+		regs->uregs[reg] = -1;
+		regs->ARM_pc += 4;
+		return 0;
+	}
+
+	return 1;
+}
+
+static irqreturn_t v3_irq(int irq, void *devid, struct pt_regs *regs)
+{
+#ifdef CONFIG_DEBUG_LL
+	unsigned long pc = instruction_pointer(regs);
+	unsigned long instr = *(unsigned long *)pc;
+	char buf[128];
+
+	sprintf(buf, "V3 int %d: pc=0x%08lx [%08lx] LBFADDR=%08x LBFCODE=%02x ISTAT=%02x\n", irq,
+		pc, instr, __raw_readl(SC_LBFADDR), __raw_readl(SC_LBFCODE) & 255,
+		v3_readb(V3_LB_ISTAT));
+	printascii(buf);
+#endif
+
+	v3_writew(V3_PCI_STAT, 0xf000);
+	v3_writeb(V3_LB_ISTAT, 0);
+	__raw_writel(3, SC_PCI);
+
+#ifdef CONFIG_DEBUG_LL
+	/*
+	 * If the instruction being executed was a read,
+	 * make it look like it read all-ones.
+	 */
+	if ((instr & 0x0c100000) == 0x04100000) {
+		int reg = (instr >> 16) & 15;
+		sprintf(buf, "   reg%d = %08lx\n", reg, regs->uregs[reg]);
+		printascii(buf);
+	}
+#endif
+	return IRQ_HANDLED;
+}
+
+int __init pci_v3_setup(int nr, struct pci_sys_data *sys)
+{
+	int ret = 0;
+
+	if (nr == 0) {
+		sys->mem_offset = PHYS_PCI_MEM_BASE;
+		ret = pci_v3_setup_resources(sys->resource);
+	}
+
+	return ret;
+}
+
+struct pci_bus *pci_v3_scan_bus(int nr, struct pci_sys_data *sys)
+{
+	return pci_scan_bus(sys->busnr, &pci_v3_ops, sys);
+}
+
+/*
+ * V3_LB_BASE? - local bus address
+ * V3_LB_MAP?  - pci bus address
+ */
+void __init pci_v3_preinit(void)
+{
+	unsigned long flags;
+	unsigned int temp;
+	int ret;
+
+	/*
+	 * Hook in our fault handler for PCI errors
+	 */
+	hook_fault_code(4, v3_pci_fault, SIGBUS, "external abort on linefetch");
+	hook_fault_code(6, v3_pci_fault, SIGBUS, "external abort on linefetch");
+	hook_fault_code(8, v3_pci_fault, SIGBUS, "external abort on non-linefetch");
+	hook_fault_code(10, v3_pci_fault, SIGBUS, "external abort on non-linefetch");
+
+	spin_lock_irqsave(&v3_lock, flags);
+
+	/*
+	 * Unlock V3 registers, but only if they were previously locked.
+	 */
+	if (v3_readw(V3_SYSTEM) & V3_SYSTEM_M_LOCK)
+		v3_writew(V3_SYSTEM, 0xa05f);
+
+	/*
+	 * Setup window 0 - PCI non-prefetchable memory
+	 *  Local: 0x40000000 Bus: 0x00000000 Size: 256MB
+	 */
+	v3_writel(V3_LB_BASE0, v3_addr_to_lb_base(PHYS_PCI_MEM_BASE) |
+			V3_LB_BASE_ADR_SIZE_256MB | V3_LB_BASE_ENABLE);
+	v3_writew(V3_LB_MAP0, v3_addr_to_lb_map(PCI_BUS_NONMEM_START) |
+			V3_LB_MAP_TYPE_MEM);
+
+	/*
+	 * Setup window 1 - PCI prefetchable memory
+	 *  Local: 0x50000000 Bus: 0x10000000 Size: 256MB
+	 */
+	v3_writel(V3_LB_BASE1, v3_addr_to_lb_base(PHYS_PCI_MEM_BASE + SZ_256M) |
+			V3_LB_BASE_ADR_SIZE_256MB | V3_LB_BASE_PREFETCH |
+			V3_LB_BASE_ENABLE);
+	v3_writew(V3_LB_MAP1, v3_addr_to_lb_map(PCI_BUS_PREMEM_START) |
+			V3_LB_MAP_TYPE_MEM_MULTIPLE);
+
+	/*
+	 * Setup window 2 - PCI IO
+	 */
+	v3_writel(V3_LB_BASE2, v3_addr_to_lb_base2(PHYS_PCI_IO_BASE) |
+			V3_LB_BASE_ENABLE);
+	v3_writew(V3_LB_MAP2, v3_addr_to_lb_map2(0));
+
+	/*
+	 * Disable PCI to host IO cycles
+	 */
+	temp = v3_readw(V3_PCI_CFG) & ~V3_PCI_CFG_M_I2O_EN;
+	temp |= V3_PCI_CFG_M_IO_REG_DIS | V3_PCI_CFG_M_IO_DIS;
+	v3_writew(V3_PCI_CFG, temp);
+
+	printk(KERN_DEBUG "FIFO_CFG: %04x  FIFO_PRIO: %04x\n",
+		v3_readw(V3_FIFO_CFG), v3_readw(V3_FIFO_PRIORITY));
+
+	/*
+	 * Set the V3 FIFO such that writes have higher priority than
+	 * reads, and local bus write causes local bus read fifo flush.
+	 * Same for PCI.
+	 */
+	v3_writew(V3_FIFO_PRIORITY, 0x0a0a);
+
+	/*
+	 * Re-lock the system register.
+	 */
+	temp = v3_readw(V3_SYSTEM) | V3_SYSTEM_M_LOCK;
+	v3_writew(V3_SYSTEM, temp);
+
+	/*
+	 * Clear any error conditions, and enable write errors.
+	 */
+	v3_writeb(V3_LB_ISTAT, 0);
+	v3_writew(V3_LB_CFG, v3_readw(V3_LB_CFG) | (1 << 10));
+	v3_writeb(V3_LB_IMASK, 0x28);
+	__raw_writel(3, SC_PCI);
+
+	/*
+	 * Grab the PCI error interrupt.
+	 */
+	ret = request_irq(IRQ_AP_V3INT, v3_irq, 0, "V3", NULL);
+	if (ret)
+		printk(KERN_ERR "PCI: unable to grab PCI error "
+		       "interrupt: %d\n", ret);
+
+	spin_unlock_irqrestore(&v3_lock, flags);
+}
+
+void __init pci_v3_postinit(void)
+{
+	unsigned int pci_cmd;
+
+	pci_cmd = PCI_COMMAND_MEMORY |
+		  PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE;
+
+	v3_writew(V3_PCI_CMD, pci_cmd);
+
+	v3_writeb(V3_LB_ISTAT, ~0x40);
+	v3_writeb(V3_LB_IMASK, 0x68);
+
+#if 0
+	ret = request_irq(IRQ_AP_LBUSTIMEOUT, lb_timeout, 0, "bus timeout", NULL);
+	if (ret)
+		printk(KERN_ERR "PCI: unable to grab local bus timeout "
+		       "interrupt: %d\n", ret);
+#endif
+}
diff --git a/arch/arm/mach-integrator/time.c b/arch/arm/mach-integrator/time.c
new file mode 100644
index 0000000..20729de
--- /dev/null
+++ b/arch/arm/mach-integrator/time.c
@@ -0,0 +1,213 @@
+/*
+ *  linux/arch/arm/mach-integrator/time.c
+ *
+ *  Copyright (C) 2000-2001 Deep Blue Solutions Ltd.
+ *
+ * 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/time.h>
+#include <linux/mc146818rtc.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/device.h>
+
+#include <asm/hardware/amba.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/rtc.h>
+
+#include <asm/mach/time.h>
+
+#define RTC_DR		(0)
+#define RTC_MR		(4)
+#define RTC_STAT	(8)
+#define RTC_EOI		(8)
+#define RTC_LR		(12)
+#define RTC_CR		(16)
+#define RTC_CR_MIE	(1 << 0)
+
+extern int (*set_rtc)(void);
+static void __iomem *rtc_base;
+
+static int integrator_set_rtc(void)
+{
+	__raw_writel(xtime.tv_sec, rtc_base + RTC_LR);
+	return 1;
+}
+
+static void rtc_read_alarm(struct rtc_wkalrm *alrm)
+{
+	rtc_time_to_tm(readl(rtc_base + RTC_MR), &alrm->time);
+}
+
+static int rtc_set_alarm(struct rtc_wkalrm *alrm)
+{
+	unsigned long time;
+	int ret;
+
+	ret = rtc_tm_to_time(&alrm->time, &time);
+	if (ret == 0)
+		writel(time, rtc_base + RTC_MR);
+	return ret;
+}
+
+static void rtc_read_time(struct rtc_time *tm)
+{
+	rtc_time_to_tm(readl(rtc_base + RTC_DR), tm);
+}
+
+/*
+ * Set the RTC time.  Unfortunately, we can't accurately set
+ * the point at which the counter updates.
+ *
+ * Also, since RTC_LR is transferred to RTC_CR on next rising
+ * edge of the 1Hz clock, we must write the time one second
+ * in advance.
+ */
+static int rtc_set_time(struct rtc_time *tm)
+{
+	unsigned long time;
+	int ret;
+
+	ret = rtc_tm_to_time(tm, &time);
+	if (ret == 0)
+		writel(time + 1, rtc_base + RTC_LR);
+
+	return ret;
+}
+
+static struct rtc_ops rtc_ops = {
+	.owner		= THIS_MODULE,
+	.read_time	= rtc_read_time,
+	.set_time	= rtc_set_time,
+	.read_alarm	= rtc_read_alarm,
+	.set_alarm	= rtc_set_alarm,
+};
+
+static irqreturn_t rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	writel(0, rtc_base + RTC_EOI);
+	return IRQ_HANDLED;
+}
+
+static int rtc_probe(struct amba_device *dev, void *id)
+{
+	int ret;
+
+	if (rtc_base)
+		return -EBUSY;
+
+	ret = amba_request_regions(dev, NULL);
+	if (ret)
+		goto out;
+
+	rtc_base = ioremap(dev->res.start, SZ_4K);
+	if (!rtc_base) {
+		ret = -ENOMEM;
+		goto res_out;
+	}
+
+	__raw_writel(0, rtc_base + RTC_CR);
+	__raw_writel(0, rtc_base + RTC_EOI);
+
+	xtime.tv_sec = __raw_readl(rtc_base + RTC_DR);
+
+	ret = request_irq(dev->irq[0], rtc_interrupt, SA_INTERRUPT,
+			  "rtc-pl030", dev);
+	if (ret)
+		goto map_out;
+
+	ret = register_rtc(&rtc_ops);
+	if (ret)
+		goto irq_out;
+
+	set_rtc = integrator_set_rtc;
+	return 0;
+
+ irq_out:
+	free_irq(dev->irq[0], dev);
+ map_out:
+	iounmap(rtc_base);
+	rtc_base = NULL;
+ res_out:
+	amba_release_regions(dev);
+ out:
+	return ret;
+}
+
+static int rtc_remove(struct amba_device *dev)
+{
+	set_rtc = NULL;
+
+	writel(0, rtc_base + RTC_CR);
+
+	free_irq(dev->irq[0], dev);
+	unregister_rtc(&rtc_ops);
+
+	iounmap(rtc_base);
+	rtc_base = NULL;
+	amba_release_regions(dev);
+
+	return 0;
+}
+
+static struct timespec rtc_delta;
+
+static int rtc_suspend(struct amba_device *dev, pm_message_t state)
+{
+	struct timespec rtc;
+
+	rtc.tv_sec = readl(rtc_base + RTC_DR);
+	rtc.tv_nsec = 0;
+	save_time_delta(&rtc_delta, &rtc);
+
+	return 0;
+}
+
+static int rtc_resume(struct amba_device *dev)
+{
+	struct timespec rtc;
+
+	rtc.tv_sec = readl(rtc_base + RTC_DR);
+	rtc.tv_nsec = 0;
+	restore_time_delta(&rtc_delta, &rtc);
+
+	return 0;
+}
+
+static struct amba_id rtc_ids[] = {
+	{
+		.id	= 0x00041030,
+		.mask	= 0x000fffff,
+	},
+	{ 0, 0 },
+};
+
+static struct amba_driver rtc_driver = {
+	.drv		= {
+		.name	= "rtc-pl030",
+	},
+	.probe		= rtc_probe,
+	.remove		= rtc_remove,
+	.suspend	= rtc_suspend,
+	.resume		= rtc_resume,
+	.id_table	= rtc_ids,
+};
+
+static int __init integrator_rtc_init(void)
+{
+	return amba_driver_register(&rtc_driver);
+}
+
+static void __exit integrator_rtc_exit(void)
+{
+	amba_driver_unregister(&rtc_driver);
+}
+
+module_init(integrator_rtc_init);
+module_exit(integrator_rtc_exit);