From 8ad68bbf7a06cdd77c170be792418488dbb65da4 Mon Sep 17 00:00:00 2001
From: Catalin Marinas <catalin.marinas@arm.com>
Date: Mon, 31 Oct 2005 14:25:02 +0000
Subject: [ARM] Add support for ARM RealView board

Support for RealView EB.

Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/Kconfig                     |   9 +
 arch/arm/Makefile                    |   1 +
 arch/arm/mach-realview/Kconfig       |  11 +
 arch/arm/mach-realview/Makefile      |   6 +
 arch/arm/mach-realview/Makefile.boot |   4 +
 arch/arm/mach-realview/clock.c       | 145 +++++++++
 arch/arm/mach-realview/clock.h       |  25 ++
 arch/arm/mach-realview/core.c        | 605 +++++++++++++++++++++++++++++++++++
 arch/arm/mach-realview/core.h        | 118 +++++++
 arch/arm/mach-realview/realview_eb.c | 142 ++++++++
 arch/arm/mm/Kconfig                  |   6 +-
 11 files changed, 1069 insertions(+), 3 deletions(-)
 create mode 100644 arch/arm/mach-realview/Kconfig
 create mode 100644 arch/arm/mach-realview/Makefile
 create mode 100644 arch/arm/mach-realview/Makefile.boot
 create mode 100644 arch/arm/mach-realview/clock.c
 create mode 100644 arch/arm/mach-realview/clock.h
 create mode 100644 arch/arm/mach-realview/core.c
 create mode 100644 arch/arm/mach-realview/core.h
 create mode 100644 arch/arm/mach-realview/realview_eb.c

(limited to 'arch')

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 682367bd0f..dc6d8342e5 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -194,6 +194,13 @@ config ARCH_VERSATILE
 	help
 	  This enables support for ARM Ltd Versatile board.
 
+config ARCH_REALVIEW
+	bool "RealView"
+	select ARM_AMBA
+	select ICST307
+	help
+	  This enables support for ARM Ltd RealView boards.
+
 config ARCH_IMX
 	bool "IMX"
 
@@ -244,6 +251,8 @@ source "arch/arm/mach-versatile/Kconfig"
 
 source "arch/arm/mach-aaec2000/Kconfig"
 
+source "arch/arm/mach-realview/Kconfig"
+
 # Definitions to make life easier
 config ARCH_ACORN
 	bool
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 64cf480b0b..d80749ae2a 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -99,6 +99,7 @@ textaddr-$(CONFIG_ARCH_FORTUNET)   := 0xc0008000
  machine-$(CONFIG_ARCH_IMX)	   := imx
  machine-$(CONFIG_ARCH_H720X)	   := h720x
  machine-$(CONFIG_ARCH_AAEC2000)   := aaec2000
+ machine-$(CONFIG_ARCH_REALVIEW)   := realview
 
 ifeq ($(CONFIG_ARCH_EBSA110),y)
 # This is what happens if you forget the IOCS16 line.
diff --git a/arch/arm/mach-realview/Kconfig b/arch/arm/mach-realview/Kconfig
new file mode 100644
index 0000000000..4b63dc9eab
--- /dev/null
+++ b/arch/arm/mach-realview/Kconfig
@@ -0,0 +1,11 @@
+menu "RealView platform type"
+	depends on ARCH_REALVIEW
+
+config MACH_REALVIEW_EB
+	bool "Support RealView/EB platform"
+	default n
+	select ARM_GIC
+	help
+	  Include support for the ARM(R) RealView Emulation Baseboard platform.
+
+endmenu
diff --git a/arch/arm/mach-realview/Makefile b/arch/arm/mach-realview/Makefile
new file mode 100644
index 0000000000..8d37ea1605
--- /dev/null
+++ b/arch/arm/mach-realview/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the linux kernel.
+#
+
+obj-y					:= core.o clock.o
+obj-$(CONFIG_MACH_REALVIEW_EB)		+= realview_eb.o
diff --git a/arch/arm/mach-realview/Makefile.boot b/arch/arm/mach-realview/Makefile.boot
new file mode 100644
index 0000000000..c7e75acfe6
--- /dev/null
+++ b/arch/arm/mach-realview/Makefile.boot
@@ -0,0 +1,4 @@
+   zreladdr-y	:= 0x00008000
+params_phys-y	:= 0x00000100
+initrd_phys-y	:= 0x00800000
+
diff --git a/arch/arm/mach-realview/clock.c b/arch/arm/mach-realview/clock.c
new file mode 100644
index 0000000000..002635c97b
--- /dev/null
+++ b/arch/arm/mach-realview/clock.c
@@ -0,0 +1,145 @@
+/*
+ *  linux/arch/arm/mach-realview/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/icst307.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)
+{
+	return rate;
+}
+EXPORT_SYMBOL(clk_round_rate);
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	int ret = -EIO;
+
+	if (clk->setvco) {
+		struct icst307_vco vco;
+
+		vco = icst307_khz_to_vco(clk->params, rate / 1000);
+		clk->rate = icst307_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 ret;
+}
+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	= 24000000,
+};
+
+static struct clk mmci_clk = {
+	.name	= "MCLK",
+	.rate	= 33000000,
+};
+
+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);
+	clk_register(&mmci_clk);
+	return 0;
+}
+arch_initcall(clk_init);
diff --git a/arch/arm/mach-realview/clock.h b/arch/arm/mach-realview/clock.h
new file mode 100644
index 0000000000..dadba695e1
--- /dev/null
+++ b/arch/arm/mach-realview/clock.h
@@ -0,0 +1,25 @@
+/*
+ *  linux/arch/arm/mach-realview/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 icst307_params;
+
+struct clk {
+	struct list_head	node;
+	unsigned long		rate;
+	struct module		*owner;
+	const char		*name;
+	const struct icst307_params *params;
+	void			*data;
+	void			(*setvco)(struct clk *, struct icst307_vco vco);
+};
+
+int clk_register(struct clk *clk);
+void clk_unregister(struct clk *clk);
diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c
new file mode 100644
index 0000000000..4f98f13ad3
--- /dev/null
+++ b/arch/arm/mach-realview/core.c
@@ -0,0 +1,605 @@
+/*
+ *  linux/arch/arm/mach-realview/core.c
+ *
+ *  Copyright (C) 1999 - 2003 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/config.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/sysdev.h>
+#include <linux/interrupt.h>
+
+#include <asm/system.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/leds.h>
+#include <asm/mach-types.h>
+#include <asm/hardware/amba.h>
+#include <asm/hardware/amba_clcd.h>
+#include <asm/hardware/arm_timer.h>
+#include <asm/hardware/icst307.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/flash.h>
+#include <asm/mach/irq.h>
+#include <asm/mach/time.h>
+#include <asm/mach/map.h>
+#include <asm/mach/mmc.h>
+
+#include <asm/hardware/gic.h>
+
+#include "core.h"
+#include "clock.h"
+
+#define REALVIEW_REFCOUNTER	(__io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_24MHz_OFFSET)
+
+/*
+ * This is the RealView sched_clock implementation.  This has
+ * a resolution of 41.7ns, and a maximum value of about 179s.
+ */
+unsigned long long sched_clock(void)
+{
+	unsigned long long v;
+
+	v = (unsigned long long)readl(REALVIEW_REFCOUNTER) * 125;
+	do_div(v, 3);
+
+	return v;
+}
+
+
+#define REALVIEW_FLASHCTRL    (__io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_FLASH_OFFSET)
+
+static int realview_flash_init(void)
+{
+	u32 val;
+
+	val = __raw_readl(REALVIEW_FLASHCTRL);
+	val &= ~REALVIEW_FLASHPROG_FLVPPEN;
+	__raw_writel(val, REALVIEW_FLASHCTRL);
+
+	return 0;
+}
+
+static void realview_flash_exit(void)
+{
+	u32 val;
+
+	val = __raw_readl(REALVIEW_FLASHCTRL);
+	val &= ~REALVIEW_FLASHPROG_FLVPPEN;
+	__raw_writel(val, REALVIEW_FLASHCTRL);
+}
+
+static void realview_flash_set_vpp(int on)
+{
+	u32 val;
+
+	val = __raw_readl(REALVIEW_FLASHCTRL);
+	if (on)
+		val |= REALVIEW_FLASHPROG_FLVPPEN;
+	else
+		val &= ~REALVIEW_FLASHPROG_FLVPPEN;
+	__raw_writel(val, REALVIEW_FLASHCTRL);
+}
+
+static struct flash_platform_data realview_flash_data = {
+	.map_name		= "cfi_probe",
+	.width			= 4,
+	.init			= realview_flash_init,
+	.exit			= realview_flash_exit,
+	.set_vpp		= realview_flash_set_vpp,
+};
+
+static struct resource realview_flash_resource = {
+	.start			= REALVIEW_FLASH_BASE,
+	.end			= REALVIEW_FLASH_BASE + REALVIEW_FLASH_SIZE,
+	.flags			= IORESOURCE_MEM,
+};
+
+struct platform_device realview_flash_device = {
+	.name			= "armflash",
+	.id			= 0,
+	.dev			= {
+		.platform_data	= &realview_flash_data,
+	},
+	.num_resources		= 1,
+	.resource		= &realview_flash_resource,
+};
+
+static struct resource realview_smc91x_resources[] = {
+	[0] = {
+		.start		= REALVIEW_ETH_BASE,
+		.end		= REALVIEW_ETH_BASE + SZ_64K - 1,
+		.flags		= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start		= IRQ_ETH,
+		.end		= IRQ_ETH,
+		.flags		= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device realview_smc91x_device = {
+	.name		= "smc91x",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(realview_smc91x_resources),
+	.resource	= realview_smc91x_resources,
+};
+
+#define REALVIEW_SYSMCI	(__io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_MCI_OFFSET)
+
+static unsigned int realview_mmc_status(struct device *dev)
+{
+	struct amba_device *adev = container_of(dev, struct amba_device, dev);
+	u32 mask;
+
+	if (adev->res.start == REALVIEW_MMCI0_BASE)
+		mask = 1;
+	else
+		mask = 2;
+
+	return readl(REALVIEW_SYSMCI) & mask;
+}
+
+struct mmc_platform_data realview_mmc0_plat_data = {
+	.ocr_mask	= MMC_VDD_32_33|MMC_VDD_33_34,
+	.status		= realview_mmc_status,
+};
+
+struct mmc_platform_data realview_mmc1_plat_data = {
+	.ocr_mask	= MMC_VDD_32_33|MMC_VDD_33_34,
+	.status		= realview_mmc_status,
+};
+
+/*
+ * Clock handling
+ */
+static const struct icst307_params realview_oscvco_params = {
+	.ref		= 24000,
+	.vco_max	= 200000,
+	.vd_min		= 4 + 8,
+	.vd_max		= 511 + 8,
+	.rd_min		= 1 + 2,
+	.rd_max		= 127 + 2,
+};
+
+static void realview_oscvco_set(struct clk *clk, struct icst307_vco vco)
+{
+	void __iomem *sys_lock = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_LOCK_OFFSET;
+	void __iomem *sys_osc = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_OSC1_OFFSET;
+	u32 val;
+
+	val = readl(sys_osc) & ~0x7ffff;
+	val |= vco.v | (vco.r << 9) | (vco.s << 16);
+
+	writel(0xa05f, sys_lock);
+	writel(val, sys_osc);
+	writel(0, sys_lock);
+}
+
+struct clk realview_clcd_clk = {
+	.name	= "CLCDCLK",
+	.params	= &realview_oscvco_params,
+	.setvco = realview_oscvco_set,
+};
+
+/*
+ * CLCD support.
+ */
+#define SYS_CLCD_MODE_MASK	(3 << 0)
+#define SYS_CLCD_MODE_888	(0 << 0)
+#define SYS_CLCD_MODE_5551	(1 << 0)
+#define SYS_CLCD_MODE_565_RLSB	(2 << 0)
+#define SYS_CLCD_MODE_565_BLSB	(3 << 0)
+#define SYS_CLCD_NLCDIOON	(1 << 2)
+#define SYS_CLCD_VDDPOSSWITCH	(1 << 3)
+#define SYS_CLCD_PWR3V5SWITCH	(1 << 4)
+#define SYS_CLCD_ID_MASK	(0x1f << 8)
+#define SYS_CLCD_ID_SANYO_3_8	(0x00 << 8)
+#define SYS_CLCD_ID_UNKNOWN_8_4	(0x01 << 8)
+#define SYS_CLCD_ID_EPSON_2_2	(0x02 << 8)
+#define SYS_CLCD_ID_SANYO_2_5	(0x07 << 8)
+#define SYS_CLCD_ID_VGA		(0x1f << 8)
+
+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,
+};
+
+static struct clcd_panel sanyo_3_8_in = {
+	.mode		= {
+		.name		= "Sanyo QVGA",
+		.refresh	= 116,
+		.xres		= 320,
+		.yres		= 240,
+		.pixclock	= 100000,
+		.left_margin	= 6,
+		.right_margin	= 6,
+		.upper_margin	= 5,
+		.lower_margin	= 5,
+		.hsync_len	= 6,
+		.vsync_len	= 6,
+		.sync		= 0,
+		.vmode		= FB_VMODE_NONINTERLACED,
+	},
+	.width		= -1,
+	.height		= -1,
+	.tim2		= TIM2_BCD,
+	.cntl		= CNTL_LCDTFT | CNTL_LCDVCOMP(1),
+	.bpp		= 16,
+};
+
+static struct clcd_panel sanyo_2_5_in = {
+	.mode		= {
+		.name		= "Sanyo QVGA Portrait",
+		.refresh	= 116,
+		.xres		= 240,
+		.yres		= 320,
+		.pixclock	= 100000,
+		.left_margin	= 20,
+		.right_margin	= 10,
+		.upper_margin	= 2,
+		.lower_margin	= 2,
+		.hsync_len	= 10,
+		.vsync_len	= 2,
+		.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+		.vmode		= FB_VMODE_NONINTERLACED,
+	},
+	.width		= -1,
+	.height		= -1,
+	.tim2		= TIM2_IVS | TIM2_IHS | TIM2_IPC,
+	.cntl		= CNTL_LCDTFT | CNTL_LCDVCOMP(1),
+	.bpp		= 16,
+};
+
+static struct clcd_panel epson_2_2_in = {
+	.mode		= {
+		.name		= "Epson QCIF",
+		.refresh	= 390,
+		.xres		= 176,
+		.yres		= 220,
+		.pixclock	= 62500,
+		.left_margin	= 3,
+		.right_margin	= 2,
+		.upper_margin	= 1,
+		.lower_margin	= 0,
+		.hsync_len	= 3,
+		.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,
+};
+
+/*
+ * Detect which LCD panel is connected, and return the appropriate
+ * clcd_panel structure.  Note: we do not have any information on
+ * the required timings for the 8.4in panel, so we presently assume
+ * VGA timings.
+ */
+static struct clcd_panel *realview_clcd_panel(void)
+{
+	void __iomem *sys_clcd = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_CLCD_OFFSET;
+	struct clcd_panel *panel = &vga;
+	u32 val;
+
+	val = readl(sys_clcd) & SYS_CLCD_ID_MASK;
+	if (val == SYS_CLCD_ID_SANYO_3_8)
+		panel = &sanyo_3_8_in;
+	else if (val == SYS_CLCD_ID_SANYO_2_5)
+		panel = &sanyo_2_5_in;
+	else if (val == SYS_CLCD_ID_EPSON_2_2)
+		panel = &epson_2_2_in;
+	else if (val == SYS_CLCD_ID_VGA)
+		panel = &vga;
+	else {
+		printk(KERN_ERR "CLCD: unknown LCD panel ID 0x%08x, using VGA\n",
+			val);
+		panel = &vga;
+	}
+
+	return panel;
+}
+
+/*
+ * Disable all display connectors on the interface module.
+ */
+static void realview_clcd_disable(struct clcd_fb *fb)
+{
+	void __iomem *sys_clcd = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_CLCD_OFFSET;
+	u32 val;
+
+	val = readl(sys_clcd);
+	val &= ~SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH;
+	writel(val, sys_clcd);
+}
+
+/*
+ * Enable the relevant connector on the interface module.
+ */
+static void realview_clcd_enable(struct clcd_fb *fb)
+{
+	void __iomem *sys_clcd = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_CLCD_OFFSET;
+	u32 val;
+
+	val = readl(sys_clcd);
+	val &= ~SYS_CLCD_MODE_MASK;
+
+	switch (fb->fb.var.green.length) {
+	case 5:
+		val |= SYS_CLCD_MODE_5551;
+		break;
+	case 6:
+		val |= SYS_CLCD_MODE_565_RLSB;
+		break;
+	case 8:
+		val |= SYS_CLCD_MODE_888;
+		break;
+	}
+
+	/*
+	 * Set the MUX
+	 */
+	writel(val, sys_clcd);
+
+	/*
+	 * And now enable the PSUs
+	 */
+	val |= SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH;
+	writel(val, sys_clcd);
+}
+
+static unsigned long framesize = SZ_1M;
+
+static int realview_clcd_setup(struct clcd_fb *fb)
+{
+	dma_addr_t dma;
+
+	fb->panel		= realview_clcd_panel();
+
+	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 realview_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 realview_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);
+}
+
+struct clcd_board clcd_plat_data = {
+	.name		= "RealView",
+	.check		= clcdfb_check,
+	.decode		= clcdfb_decode,
+	.disable	= realview_clcd_disable,
+	.enable		= realview_clcd_enable,
+	.setup		= realview_clcd_setup,
+	.mmap		= realview_clcd_mmap,
+	.remove		= realview_clcd_remove,
+};
+
+#ifdef CONFIG_LEDS
+#define VA_LEDS_BASE (__io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_LED_OFFSET)
+
+void realview_leds_event(led_event_t ledevt)
+{
+	unsigned long flags;
+	u32 val;
+
+	local_irq_save(flags);
+	val = readl(VA_LEDS_BASE);
+
+	switch (ledevt) {
+	case led_idle_start:
+		val = val & ~REALVIEW_SYS_LED0;
+		break;
+
+	case led_idle_end:
+		val = val | REALVIEW_SYS_LED0;
+		break;
+
+	case led_timer:
+		val = val ^ REALVIEW_SYS_LED1;
+		break;
+
+	case led_halted:
+		val = 0;
+		break;
+
+	default:
+		break;
+	}
+
+	writel(val, VA_LEDS_BASE);
+	local_irq_restore(flags);
+}
+#endif	/* CONFIG_LEDS */
+
+/*
+ * Where is the timer (VA)?
+ */
+#define TIMER0_VA_BASE		 __io_address(REALVIEW_TIMER0_1_BASE)
+#define TIMER1_VA_BASE		(__io_address(REALVIEW_TIMER0_1_BASE) + 0x20)
+#define TIMER2_VA_BASE		 __io_address(REALVIEW_TIMER2_3_BASE)
+#define TIMER3_VA_BASE		(__io_address(REALVIEW_TIMER2_3_BASE) + 0x20)
+
+/*
+ * How long is the timer interval?
+ */
+#define TIMER_INTERVAL	(TICKS_PER_uSEC * mSEC_10)
+#if TIMER_INTERVAL >= 0x100000
+#define TIMER_RELOAD	(TIMER_INTERVAL >> 8)
+#define TIMER_DIVISOR	(TIMER_CTRL_DIV256)
+#define TICKS2USECS(x)	(256 * (x) / TICKS_PER_uSEC)
+#elif TIMER_INTERVAL >= 0x10000
+#define TIMER_RELOAD	(TIMER_INTERVAL >> 4)		/* Divide by 16 */
+#define TIMER_DIVISOR	(TIMER_CTRL_DIV16)
+#define TICKS2USECS(x)	(16 * (x) / TICKS_PER_uSEC)
+#else
+#define TIMER_RELOAD	(TIMER_INTERVAL)
+#define TIMER_DIVISOR	(TIMER_CTRL_DIV1)
+#define TICKS2USECS(x)	((x) / TICKS_PER_uSEC)
+#endif
+
+/*
+ * Returns number of ms since last clock interrupt.  Note that interrupts
+ * will have been disabled by do_gettimeoffset()
+ */
+static unsigned long realview_gettimeoffset(void)
+{
+	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 = readl(TIMER0_VA_BASE + TIMER_VALUE) & 0xffff;
+	do {
+		ticks1 = ticks2;
+		status = __raw_readl(__io_address(REALVIEW_GIC_DIST_BASE + GIC_DIST_PENDING_SET)
+				     + ((IRQ_TIMERINT0_1 >> 5) << 2));
+		ticks2 = readl(TIMER0_VA_BASE + TIMER_VALUE) & 0xffff;
+	} while (ticks2 > ticks1);
+
+	/*
+	 * Number of ticks since last interrupt.
+	 */
+	ticks1 = TIMER_RELOAD - ticks2;
+
+	/*
+	 * Interrupt pending?  If so, we've reloaded once already.
+	 *
+	 * FIXME: Need to check this is effectively timer 0 that expires
+	 */
+	if (status & IRQMASK_TIMERINT0_1)
+		ticks1 += TIMER_RELOAD;
+
+	/*
+	 * Convert the ticks to usecs
+	 */
+	return TICKS2USECS(ticks1);
+}
+
+/*
+ * IRQ handler for the timer
+ */
+static irqreturn_t realview_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	write_seqlock(&xtime_lock);
+
+	// ...clear the interrupt
+	writel(1, TIMER0_VA_BASE + TIMER_INTCLR);
+
+	timer_tick(regs);
+
+	write_sequnlock(&xtime_lock);
+
+	return IRQ_HANDLED;
+}
+
+static struct irqaction realview_timer_irq = {
+	.name		= "RealView Timer Tick",
+	.flags		= SA_INTERRUPT | SA_TIMER,
+	.handler	= realview_timer_interrupt,
+};
+
+/*
+ * Set up timer interrupt, and return the current time in seconds.
+ */
+static void __init realview_timer_init(void)
+{
+	u32 val;
+
+	/* 
+	 * set clock frequency: 
+	 *	REALVIEW_REFCLK is 32KHz
+	 *	REALVIEW_TIMCLK is 1MHz
+	 */
+	val = readl(__io_address(REALVIEW_SCTL_BASE));
+	writel((REALVIEW_TIMCLK << REALVIEW_TIMER1_EnSel) |
+	       (REALVIEW_TIMCLK << REALVIEW_TIMER2_EnSel) | 
+	       (REALVIEW_TIMCLK << REALVIEW_TIMER3_EnSel) |
+	       (REALVIEW_TIMCLK << REALVIEW_TIMER4_EnSel) | val,
+	       __io_address(REALVIEW_SCTL_BASE));
+
+	/*
+	 * Initialise to a known state (all timers off)
+	 */
+	writel(0, TIMER0_VA_BASE + TIMER_CTRL);
+	writel(0, TIMER1_VA_BASE + TIMER_CTRL);
+	writel(0, TIMER2_VA_BASE + TIMER_CTRL);
+	writel(0, TIMER3_VA_BASE + TIMER_CTRL);
+
+	writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_LOAD);
+	writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_VALUE);
+	writel(TIMER_DIVISOR | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC |
+	       TIMER_CTRL_IE, TIMER0_VA_BASE + TIMER_CTRL);
+
+	/* 
+	 * Make irqs happen for the system timer
+	 */
+	setup_irq(IRQ_TIMERINT0_1, &realview_timer_irq);
+}
+
+struct sys_timer realview_timer = {
+	.init		= realview_timer_init,
+	.offset		= realview_gettimeoffset,
+};
diff --git a/arch/arm/mach-realview/core.h b/arch/arm/mach-realview/core.h
new file mode 100644
index 0000000000..575599db74
--- /dev/null
+++ b/arch/arm/mach-realview/core.h
@@ -0,0 +1,118 @@
+/*
+ *  linux/arch/arm/mach-realview/core.h
+ *
+ *  Copyright (C) 2004 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
+ */
+
+#ifndef __ASM_ARCH_REALVIEW_H
+#define __ASM_ARCH_REALVIEW_H
+
+#include <asm/hardware/amba.h>
+#include <asm/io.h>
+
+#define __io_address(n)		__io(IO_ADDRESS(n))
+
+extern struct sys_timer realview_timer;
+
+#define AMBA_DEVICE(name,busid,base,plat)			\
+static struct amba_device name##_device = {			\
+	.dev		= {					\
+		.coherent_dma_mask = ~0,			\
+		.bus_id	= busid,				\
+		.platform_data = plat,				\
+	},							\
+	.res		= {					\
+		.start	= REALVIEW_##base##_BASE,		\
+		.end	= (REALVIEW_##base##_BASE) + SZ_4K - 1,\
+		.flags	= IORESOURCE_MEM,			\
+	},							\
+	.dma_mask	= ~0,					\
+	.irq		= base##_IRQ,				\
+	/* .dma		= base##_DMA,*/				\
+}
+
+/*
+ * These devices are connected via the core APB bridge
+ */
+#define GPIO2_IRQ	{ IRQ_GPIOINT2, NO_IRQ }
+#define GPIO2_DMA	{ 0, 0 }
+#define GPIO3_IRQ	{ IRQ_GPIOINT3, NO_IRQ }
+#define GPIO3_DMA	{ 0, 0 }
+
+#define AACI_IRQ	{ IRQ_AACI, NO_IRQ }
+#define AACI_DMA	{ 0x80, 0x81 }
+#define MMCI0_IRQ	{ IRQ_MMCI0A,IRQ_MMCI0B }
+#define MMCI0_DMA	{ 0x84, 0 }
+#define KMI0_IRQ	{ IRQ_KMI0, NO_IRQ }
+#define KMI0_DMA	{ 0, 0 }
+#define KMI1_IRQ	{ IRQ_KMI1, NO_IRQ }
+#define KMI1_DMA	{ 0, 0 }
+
+/*
+ * These devices are connected directly to the multi-layer AHB switch
+ */
+#define SMC_IRQ		{ NO_IRQ, NO_IRQ }
+#define SMC_DMA		{ 0, 0 }
+#define MPMC_IRQ	{ NO_IRQ, NO_IRQ }
+#define MPMC_DMA	{ 0, 0 }
+#define CLCD_IRQ	{ IRQ_CLCDINT, NO_IRQ }
+#define CLCD_DMA	{ 0, 0 }
+#define DMAC_IRQ	{ IRQ_DMAINT, NO_IRQ }
+#define DMAC_DMA	{ 0, 0 }
+
+/*
+ * These devices are connected via the core APB bridge
+ */
+#define SCTL_IRQ	{ NO_IRQ, NO_IRQ }
+#define SCTL_DMA	{ 0, 0 }
+#define WATCHDOG_IRQ	{ IRQ_WDOGINT, NO_IRQ }
+#define WATCHDOG_DMA	{ 0, 0 }
+#define GPIO0_IRQ	{ IRQ_GPIOINT0, NO_IRQ }
+#define GPIO0_DMA	{ 0, 0 }
+#define GPIO1_IRQ	{ IRQ_GPIOINT1, NO_IRQ }
+#define GPIO1_DMA	{ 0, 0 }
+#define RTC_IRQ		{ IRQ_RTCINT, NO_IRQ }
+#define RTC_DMA		{ 0, 0 }
+
+/*
+ * These devices are connected via the DMA APB bridge
+ */
+#define SCI_IRQ		{ IRQ_SCIINT, NO_IRQ }
+#define SCI_DMA		{ 7, 6 }
+#define UART0_IRQ	{ IRQ_UARTINT0, NO_IRQ }
+#define UART0_DMA	{ 15, 14 }
+#define UART1_IRQ	{ IRQ_UARTINT1, NO_IRQ }
+#define UART1_DMA	{ 13, 12 }
+#define UART2_IRQ	{ IRQ_UARTINT2, NO_IRQ }
+#define UART2_DMA	{ 11, 10 }
+#define UART3_IRQ	{ IRQ_UART3, NO_IRQ }
+#define UART3_DMA	{ 0x86, 0x87 }
+#define SSP_IRQ		{ IRQ_SSPINT, NO_IRQ }
+#define SSP_DMA		{ 9, 8 }
+
+
+extern struct platform_device realview_flash_device;
+extern struct platform_device realview_smc91x_device;
+extern struct mmc_platform_data realview_mmc0_plat_data;
+extern struct mmc_platform_data realview_mmc1_plat_data;
+extern struct clk realview_clcd_clk;
+extern struct clcd_board clcd_plat_data;
+
+extern void realview_leds_event(led_event_t ledevt);
+
+#endif
diff --git a/arch/arm/mach-realview/realview_eb.c b/arch/arm/mach-realview/realview_eb.c
new file mode 100644
index 0000000000..1279feeecf
--- /dev/null
+++ b/arch/arm/mach-realview/realview_eb.c
@@ -0,0 +1,142 @@
+/*
+ *  linux/arch/arm/mach-realview/realview_eb.c
+ *
+ *  Copyright (C) 2004 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/config.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/sysdev.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/leds.h>
+#include <asm/mach-types.h>
+#include <asm/hardware/gic.h>
+#include <asm/hardware/amba.h>
+#include <asm/hardware/icst307.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/mmc.h>
+
+#include <asm/arch/irqs.h>
+
+#include "core.h"
+#include "clock.h"
+
+static struct map_desc realview_eb_io_desc[] __initdata = {
+ { IO_ADDRESS(REALVIEW_SYS_BASE),	REALVIEW_SYS_BASE,	SZ_4K,	MT_DEVICE },
+ { IO_ADDRESS(REALVIEW_GIC_CPU_BASE),	REALVIEW_GIC_CPU_BASE,	SZ_4K,	MT_DEVICE },
+ { IO_ADDRESS(REALVIEW_GIC_DIST_BASE),	REALVIEW_GIC_DIST_BASE,	SZ_4K,	MT_DEVICE },
+ { IO_ADDRESS(REALVIEW_SCTL_BASE),	REALVIEW_SCTL_BASE,	SZ_4K,	MT_DEVICE },
+ { IO_ADDRESS(REALVIEW_TIMER0_1_BASE),	REALVIEW_TIMER0_1_BASE,	SZ_4K,	MT_DEVICE },
+ { IO_ADDRESS(REALVIEW_TIMER2_3_BASE),	REALVIEW_TIMER2_3_BASE,	SZ_4K,	MT_DEVICE },
+#ifdef CONFIG_DEBUG_LL
+ { IO_ADDRESS(REALVIEW_UART0_BASE),	REALVIEW_UART0_BASE,	SZ_4K,	MT_DEVICE },
+#endif
+};
+
+static void __init realview_eb_map_io(void)
+{
+	iotable_init(realview_eb_io_desc, ARRAY_SIZE(realview_eb_io_desc));
+}
+
+/* FPGA Primecells */
+AMBA_DEVICE(aaci,  "fpga:04", AACI,     NULL);
+AMBA_DEVICE(mmc0,  "fpga:05", MMCI0,    &realview_mmc0_plat_data);
+AMBA_DEVICE(kmi0,  "fpga:06", KMI0,     NULL);
+AMBA_DEVICE(kmi1,  "fpga:07", KMI1,     NULL);
+AMBA_DEVICE(uart3, "fpga:09", UART3,    NULL);
+
+/* DevChip Primecells */
+AMBA_DEVICE(smc,   "dev:00",  SMC,      NULL);
+AMBA_DEVICE(clcd,  "dev:20",  CLCD,     &clcd_plat_data);
+AMBA_DEVICE(dmac,  "dev:30",  DMAC,     NULL);
+AMBA_DEVICE(sctl,  "dev:e0",  SCTL,     NULL);
+AMBA_DEVICE(wdog,  "dev:e1",  WATCHDOG, NULL);
+AMBA_DEVICE(gpio0, "dev:e4",  GPIO0,    NULL);
+AMBA_DEVICE(gpio1, "dev:e5",  GPIO1,    NULL);
+AMBA_DEVICE(gpio2, "dev:e6",  GPIO2,    NULL);
+AMBA_DEVICE(rtc,   "dev:e8",  RTC,      NULL);
+AMBA_DEVICE(sci0,  "dev:f0",  SCI,      NULL);
+AMBA_DEVICE(uart0, "dev:f1",  UART0,    NULL);
+AMBA_DEVICE(uart1, "dev:f2",  UART1,    NULL);
+AMBA_DEVICE(uart2, "dev:f3",  UART2,    NULL);
+AMBA_DEVICE(ssp0,  "dev:f4",  SSP,      NULL);
+
+static struct amba_device *amba_devs[] __initdata = {
+	&dmac_device,
+	&uart0_device,
+	&uart1_device,
+	&uart2_device,
+	&uart3_device,
+	&smc_device,
+	&clcd_device,
+	&sctl_device,
+	&wdog_device,
+	&gpio0_device,
+	&gpio1_device,
+	&gpio2_device,
+	&rtc_device,
+	&sci0_device,
+	&ssp0_device,
+	&aaci_device,
+	&mmc0_device,
+	&kmi0_device,
+	&kmi1_device,
+};
+
+static void __init gic_init_irq(void)
+{
+	gic_dist_init(__io_address(REALVIEW_GIC_DIST_BASE));
+	gic_cpu_init(__io_address(REALVIEW_GIC_CPU_BASE));
+}
+
+static void __init realview_eb_init(void)
+{
+	int i;
+
+	clk_register(&realview_clcd_clk);
+
+	platform_device_register(&realview_flash_device);
+	platform_device_register(&realview_smc91x_device);
+
+	for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
+		struct amba_device *d = amba_devs[i];
+		amba_device_register(d, &iomem_resource);
+	}
+
+#ifdef CONFIG_LEDS
+	leds_event = realview_leds_event;
+#endif
+}
+
+MACHINE_START(REALVIEW_EB, "ARM-RealView EB")
+	/* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
+	.phys_ram	= 0x00000000,
+	.phys_io	= REALVIEW_UART0_BASE,
+	.io_pg_offst	= (IO_ADDRESS(REALVIEW_UART0_BASE) >> 18) & 0xfffc,
+	.boot_params	= 0x00000100,
+	.map_io		= realview_eb_map_io,
+	.init_irq	= gic_init_irq,
+	.timer		= &realview_timer,
+	.init_machine	= realview_eb_init,
+MACHINE_END
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index c54e04c995..5568403e98 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -120,8 +120,8 @@ config CPU_ARM925T
 
 # ARM926T
 config CPU_ARM926T
-	bool "Support ARM926T processor" if ARCH_INTEGRATOR
-	depends on ARCH_INTEGRATOR || ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX
+	bool "Support ARM926T processor"
+	depends on ARCH_INTEGRATOR || ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || MACH_REALVIEW_EB
 	default y if ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX
 	select CPU_32v5
 	select CPU_ABRT_EV5TJ
@@ -242,7 +242,7 @@ config CPU_XSCALE
 # ARMv6
 config CPU_V6
 	bool "Support ARM V6 processor"
-	depends on ARCH_INTEGRATOR
+	depends on ARCH_INTEGRATOR || MACH_REALVIEW_EB
 	select CPU_32v6
 	select CPU_ABRT_EV6
 	select CPU_CACHE_V6
-- 
cgit v1.2.2


From 1be7228da280252167150346dcec4e7c50a79eb4 Mon Sep 17 00:00:00 2001
From: Russell King <rmk@dyn-67.arm.linux.org.uk>
Date: Mon, 31 Oct 2005 16:57:06 +0000
Subject: [ARM] Fixup platform device.h includes for realview board

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-realview/core.c        | 2 +-
 arch/arm/mach-realview/realview_eb.c | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

(limited to 'arch')

diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c
index 4f98f13ad3..482eb512eb 100644
--- a/arch/arm/mach-realview/core.c
+++ b/arch/arm/mach-realview/core.c
@@ -20,7 +20,7 @@
  */
 #include <linux/config.h>
 #include <linux/init.h>
-#include <linux/device.h>
+#include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
 #include <linux/sysdev.h>
 #include <linux/interrupt.h>
diff --git a/arch/arm/mach-realview/realview_eb.c b/arch/arm/mach-realview/realview_eb.c
index 1279feeecf..01b264be50 100644
--- a/arch/arm/mach-realview/realview_eb.c
+++ b/arch/arm/mach-realview/realview_eb.c
@@ -21,7 +21,7 @@
 
 #include <linux/config.h>
 #include <linux/init.h>
-#include <linux/device.h>
+#include <linux/platform_device.h>
 #include <linux/sysdev.h>
 
 #include <asm/hardware.h>
-- 
cgit v1.2.2


From 37bb30e86bc2e48d9affb25f6ce9eb3d8e65b2ac Mon Sep 17 00:00:00 2001
From: Russell King <rmk@dyn-67.arm.linux.org.uk>
Date: Mon, 31 Oct 2005 17:14:57 +0000
Subject: [ARM] Convert EBSA110 network driver to a platform driver

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-ebsa110/core.c | 26 +++++++++++++++++++++++++-
 1 file changed, 25 insertions(+), 1 deletion(-)

(limited to 'arch')

diff --git a/arch/arm/mach-ebsa110/core.c b/arch/arm/mach-ebsa110/core.c
index 15261646dc..ed4614983a 100644
--- a/arch/arm/mach-ebsa110/core.c
+++ b/arch/arm/mach-ebsa110/core.c
@@ -251,9 +251,33 @@ static struct platform_device serial_device = {
 	},
 };
 
+static struct resource am79c961_resources[] = {
+	{
+		.start		= 0x220,
+		.end		= 0x238,
+		.flags		= IORESOURCE_IO,
+	}, {
+		.start		= IRQ_EBSA110_ETHERNET,
+		.end		= IRQ_EBSA110_ETHERNET,
+		.flags		= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device am79c961_device = {
+	.name			= "am79c961",
+	.id			= -1,
+	.num_resources		= ARRAY_SIZE(am79c961_resources),
+	.resource		= am79c961_resources,
+};
+
+static struct platform_device *ebsa110_devices[] = {
+	&serial_device,
+	&am79c961_device,
+};
+
 static int __init ebsa110_init(void)
 {
-	return platform_device_register(&serial_device);
+	return platform_add_devices(ebsa110_devices, ARRAY_SIZE(ebsa110_devices));
 }
 
 arch_initcall(ebsa110_init);
-- 
cgit v1.2.2


From a6f1063b388cfd48a598cc7971eae1f83ebc8ba4 Mon Sep 17 00:00:00 2001
From: Lennert Buytenhek <buytenh@wantstofly.org>
Date: Tue, 1 Nov 2005 19:44:24 +0000
Subject: [ARM] 3062/1: map in various enp2611 peripherals for the ixp2000
 netdev driver

Patch from Lennert Buytenhek

The enp2611 version of the ixp2000 netdev driver needs to be able to
access a number of on-board peripherals.  ioremap() is not suitable
for this, as that will cause XCB=000 mappings to be done, which will
make the cpu susceptible to crashing on ixp2400 erratum #66.  Properly
aligned iotable mappings with MT_IXP2000_DEVICE will cause section
mappings with XCB=101 to be done, which is safe.

Signed-off-by: Lennert Buytenhek <buytenh@wantstofly.org>
Signed-off-by: Deepak Saxena <dsaxena@plexity.net>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-ixp2000/enp2611.c | 31 ++++++++++++++++++++++++++++++-
 1 file changed, 30 insertions(+), 1 deletion(-)

(limited to 'arch')

diff --git a/arch/arm/mach-ixp2000/enp2611.c b/arch/arm/mach-ixp2000/enp2611.c
index 9aa54de447..b91fe7c80f 100644
--- a/arch/arm/mach-ixp2000/enp2611.c
+++ b/arch/arm/mach-ixp2000/enp2611.c
@@ -63,6 +63,35 @@ static struct sys_timer enp2611_timer = {
 };
 
 
+/*************************************************************************
+ * ENP-2611 I/O
+ *************************************************************************/
+static struct map_desc enp2611_io_desc[] __initdata = {
+	{
+		.virtual	= ENP2611_CALEB_VIRT_BASE,
+		.physical	= ENP2611_CALEB_PHYS_BASE,
+		.length		= ENP2611_CALEB_SIZE,
+		.type		= MT_IXP2000_DEVICE
+	}, {
+		.virtual	= ENP2611_PM3386_0_VIRT_BASE,
+		.physical	= ENP2611_PM3386_0_PHYS_BASE,
+		.length		= ENP2611_PM3386_0_SIZE,
+		.type		= MT_IXP2000_DEVICE
+	}, {
+		.virtual	= ENP2611_PM3386_1_VIRT_BASE,
+		.physical	= ENP2611_PM3386_1_PHYS_BASE,
+		.length		= ENP2611_PM3386_1_SIZE,
+		.type		= MT_IXP2000_DEVICE
+	}
+};
+
+void __init enp2611_map_io(void)
+{
+	ixp2000_map_io();
+	iotable_init(enp2611_io_desc, ARRAY_SIZE(enp2611_io_desc));
+}
+
+
 /*************************************************************************
  * ENP-2611 PCI
  *************************************************************************/
@@ -229,7 +258,7 @@ MACHINE_START(ENP2611, "Radisys ENP-2611 PCI network processor board")
 	.phys_io	= IXP2000_UART_PHYS_BASE,
 	.io_pg_offst	= ((IXP2000_UART_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
-	.map_io		= ixp2000_map_io,
+	.map_io		= enp2611_map_io,
 	.init_irq	= ixp2000_init_irq,
 	.timer		= &enp2611_timer,
 	.init_machine	= enp2611_init_machine,
-- 
cgit v1.2.2


From e9b72e43d96a1ea2be0f513c78f16743a835d252 Mon Sep 17 00:00:00 2001
From: Lennert Buytenhek <buytenh@wantstofly.org>
Date: Tue, 1 Nov 2005 19:44:26 +0000
Subject: [ARM] 3064/1: start using ixp2000_reg_wrb

Patch from Lennert Buytenhek

Switch the users of ixp2000_reg_write that depend on writes being
flushed out of the write buffer by the time that function returns
over to ixp2000_reg_wrb.

When using XCB=101, writes to the same functional unit are still
guaranteed to complete in order, so we only need to protect against:
- reordering of writes to different functional units
- masking an interrupt and then reenabling the IRQ bit in CPSR

Signed-off-by: Lennert Buytenhek <buytenh@wantstofly.org>
Signed-off-by: Deepak Saxena <dsaxena@plexity.net>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-ixp2000/core.c     | 30 +++++++++++++++---------------
 arch/arm/mach-ixp2000/ixdp2x00.c |  4 ++--
 arch/arm/mach-ixp2000/ixdp2x01.c |  8 ++++----
 arch/arm/mach-ixp2000/pci.c      |  6 +++---
 4 files changed, 24 insertions(+), 24 deletions(-)

(limited to 'arch')

diff --git a/arch/arm/mach-ixp2000/core.c b/arch/arm/mach-ixp2000/core.c
index 01c393c504..69c6cf81a4 100644
--- a/arch/arm/mach-ixp2000/core.c
+++ b/arch/arm/mach-ixp2000/core.c
@@ -62,7 +62,7 @@ void ixp2000_acquire_slowport(struct slowport_cfg *new_cfg, struct slowport_cfg
 	ixp2000_reg_write(IXP2000_SLOWPORT_WTC2, new_cfg->WTC);
 	ixp2000_reg_write(IXP2000_SLOWPORT_RTC2, new_cfg->RTC);
 	ixp2000_reg_write(IXP2000_SLOWPORT_PCR, new_cfg->PCR);
-	ixp2000_reg_write(IXP2000_SLOWPORT_ADC, new_cfg->ADC);
+	ixp2000_reg_wrb(IXP2000_SLOWPORT_ADC, new_cfg->ADC);
 }
 
 void ixp2000_release_slowport(struct slowport_cfg *old_cfg)
@@ -71,7 +71,7 @@ void ixp2000_release_slowport(struct slowport_cfg *old_cfg)
 	ixp2000_reg_write(IXP2000_SLOWPORT_WTC2, old_cfg->WTC);
 	ixp2000_reg_write(IXP2000_SLOWPORT_RTC2, old_cfg->RTC);
 	ixp2000_reg_write(IXP2000_SLOWPORT_PCR, old_cfg->PCR);
-	ixp2000_reg_write(IXP2000_SLOWPORT_ADC, old_cfg->ADC);
+	ixp2000_reg_wrb(IXP2000_SLOWPORT_ADC, old_cfg->ADC);
 
 	spin_unlock_irqrestore(&ixp2000_slowport_lock, 
 					ixp2000_slowport_irq_flags);
@@ -145,7 +145,7 @@ void __init ixp2000_map_io(void)
 	iotable_init(ixp2000_io_desc, ARRAY_SIZE(ixp2000_io_desc));
 
 	/* Set slowport to 8-bit mode.  */
-	ixp2000_reg_write(IXP2000_SLOWPORT_FRM, 1);
+	ixp2000_reg_wrb(IXP2000_SLOWPORT_FRM, 1);
 }
 
 
@@ -209,7 +209,7 @@ static int ixp2000_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 	write_seqlock(&xtime_lock);
 
 	/* clear timer 1 */
-	ixp2000_reg_write(IXP2000_T1_CLR, 1);
+	ixp2000_reg_wrb(IXP2000_T1_CLR, 1);
 
 	while ((next_jiffy_time - *missing_jiffy_timer_csr) > ticks_per_jiffy) {
 		timer_tick(regs);
@@ -252,12 +252,12 @@ void __init ixp2000_init_time(unsigned long tick_rate)
 
 		ixp2000_reg_write(IXP2000_T4_CLR, 0);
 		ixp2000_reg_write(IXP2000_T4_CLD, -1);
-		ixp2000_reg_write(IXP2000_T4_CTL, (1 << 7));
+		ixp2000_reg_wrb(IXP2000_T4_CTL, (1 << 7));
 		missing_jiffy_timer_csr = IXP2000_T4_CSR;
 	} else {
 		ixp2000_reg_write(IXP2000_T2_CLR, 0);
 		ixp2000_reg_write(IXP2000_T2_CLD, -1);
-		ixp2000_reg_write(IXP2000_T2_CTL, (1 << 7));
+		ixp2000_reg_wrb(IXP2000_T2_CTL, (1 << 7));
 		missing_jiffy_timer_csr = IXP2000_T2_CSR;
 	}
  	next_jiffy_time = 0xffffffff;
@@ -279,7 +279,7 @@ static void update_gpio_int_csrs(void)
 	ixp2000_reg_write(IXP2000_GPIO_FEDR, GPIO_IRQ_falling_edge);
 	ixp2000_reg_write(IXP2000_GPIO_REDR, GPIO_IRQ_rising_edge);
 	ixp2000_reg_write(IXP2000_GPIO_LSLR, GPIO_IRQ_level_low);
-	ixp2000_reg_write(IXP2000_GPIO_LSHR, GPIO_IRQ_level_high);
+	ixp2000_reg_wrb(IXP2000_GPIO_LSHR, GPIO_IRQ_level_high);
 }
 
 void gpio_line_config(int line, int direction)
@@ -297,9 +297,9 @@ void gpio_line_config(int line, int direction)
 		GPIO_IRQ_level_high &= ~(1 << line);
 		update_gpio_int_csrs();
 
-		ixp2000_reg_write(IXP2000_GPIO_PDSR, 1 << line);
+		ixp2000_reg_wrb(IXP2000_GPIO_PDSR, 1 << line);
 	} else if (direction == GPIO_IN) {
-		ixp2000_reg_write(IXP2000_GPIO_PDCR, 1 << line);
+		ixp2000_reg_wrb(IXP2000_GPIO_PDCR, 1 << line);
 	}
 	local_irq_restore(flags);
 }
@@ -365,12 +365,12 @@ static void ixp2000_GPIO_irq_mask_ack(unsigned int irq)
 
 	ixp2000_reg_write(IXP2000_GPIO_EDSR, (1 << (irq - IRQ_IXP2000_GPIO0)));
 	ixp2000_reg_write(IXP2000_GPIO_LDSR, (1 << (irq - IRQ_IXP2000_GPIO0)));
-	ixp2000_reg_write(IXP2000_GPIO_INST, (1 << (irq - IRQ_IXP2000_GPIO0)));
+	ixp2000_reg_wrb(IXP2000_GPIO_INST, (1 << (irq - IRQ_IXP2000_GPIO0)));
 }
 
 static void ixp2000_GPIO_irq_mask(unsigned int irq)
 {
-	ixp2000_reg_write(IXP2000_GPIO_INCR, (1 << (irq - IRQ_IXP2000_GPIO0)));
+	ixp2000_reg_wrb(IXP2000_GPIO_INCR, (1 << (irq - IRQ_IXP2000_GPIO0)));
 }
 
 static void ixp2000_GPIO_irq_unmask(unsigned int irq)
@@ -389,9 +389,9 @@ static void ixp2000_pci_irq_mask(unsigned int irq)
 {
 	unsigned long temp = *IXP2000_PCI_XSCALE_INT_ENABLE;
 	if (irq == IRQ_IXP2000_PCIA)
-		ixp2000_reg_write(IXP2000_PCI_XSCALE_INT_ENABLE, (temp & ~(1 << 26)));
+		ixp2000_reg_wrb(IXP2000_PCI_XSCALE_INT_ENABLE, (temp & ~(1 << 26)));
 	else if (irq == IRQ_IXP2000_PCIB)
-		ixp2000_reg_write(IXP2000_PCI_XSCALE_INT_ENABLE, (temp & ~(1 << 27)));
+		ixp2000_reg_wrb(IXP2000_PCI_XSCALE_INT_ENABLE, (temp & ~(1 << 27)));
 }
 
 static void ixp2000_pci_irq_unmask(unsigned int irq)
@@ -411,7 +411,7 @@ static struct irqchip ixp2000_pci_irq_chip = {
 
 static void ixp2000_irq_mask(unsigned int irq)
 {
-	ixp2000_reg_write(IXP2000_IRQ_ENABLE_CLR, (1 << irq));
+	ixp2000_reg_wrb(IXP2000_IRQ_ENABLE_CLR, (1 << irq));
 }
 
 static void ixp2000_irq_unmask(unsigned int irq)
@@ -443,7 +443,7 @@ void __init ixp2000_init_irq(void)
 	ixp2000_reg_write(IXP2000_GPIO_INCR, -1);
 
 	/* clear PCI interrupt sources */
-	ixp2000_reg_write(IXP2000_PCI_XSCALE_INT_ENABLE, 0);
+	ixp2000_reg_wrb(IXP2000_PCI_XSCALE_INT_ENABLE, 0);
 
 	/*
 	 * Certain bits in the IRQ status register of the 
diff --git a/arch/arm/mach-ixp2000/ixdp2x00.c b/arch/arm/mach-ixp2000/ixdp2x00.c
index 8b4a839b62..00af934dea 100644
--- a/arch/arm/mach-ixp2000/ixdp2x00.c
+++ b/arch/arm/mach-ixp2000/ixdp2x00.c
@@ -81,7 +81,7 @@ static void ixdp2x00_irq_mask(unsigned int irq)
 
 	dummy = *board_irq_mask;
 	dummy |=  IXP2000_BOARD_IRQ_MASK(irq);
-	ixp2000_reg_write(board_irq_mask, dummy);
+	ixp2000_reg_wrb(board_irq_mask, dummy);
 
 #ifdef CONFIG_ARCH_IXDP2400
 	if (machine_is_ixdp2400())
@@ -101,7 +101,7 @@ static void ixdp2x00_irq_unmask(unsigned int irq)
 
 	dummy = *board_irq_mask;
 	dummy &=  ~IXP2000_BOARD_IRQ_MASK(irq);
-	ixp2000_reg_write(board_irq_mask, dummy);
+	ixp2000_reg_wrb(board_irq_mask, dummy);
 
 	if (machine_is_ixdp2400()) 
 		ixp2000_release_slowport(&old_cfg);
diff --git a/arch/arm/mach-ixp2000/ixdp2x01.c b/arch/arm/mach-ixp2000/ixdp2x01.c
index fee1d7b735..dfaaa2d281 100644
--- a/arch/arm/mach-ixp2000/ixdp2x01.c
+++ b/arch/arm/mach-ixp2000/ixdp2x01.c
@@ -51,7 +51,7 @@
  *************************************************************************/
 static void ixdp2x01_irq_mask(unsigned int irq)
 {
-	ixp2000_reg_write(IXDP2X01_INT_MASK_SET_REG,
+	ixp2000_reg_wrb(IXDP2X01_INT_MASK_SET_REG,
 				IXP2000_BOARD_IRQ_MASK(irq));
 }
 
@@ -114,7 +114,7 @@ void __init ixdp2x01_init_irq(void)
 
 	/* Mask all interrupts from CPLD, disable simulation */
 	ixp2000_reg_write(IXDP2X01_INT_MASK_SET_REG, 0xffffffff);
-	ixp2000_reg_write(IXDP2X01_INT_SIM_REG, 0);
+	ixp2000_reg_wrb(IXDP2X01_INT_SIM_REG, 0);
 
 	for (irq = NR_IXP2000_IRQS; irq < NR_IXDP2X01_IRQS; irq++) {
 		if (irq & valid_irq_mask) {
@@ -316,7 +316,7 @@ static struct flash_platform_data ixdp2x01_flash_platform_data = {
 
 static unsigned long ixdp2x01_flash_bank_setup(unsigned long ofs)
 {
-	ixp2000_reg_write(IXDP2X01_CPLD_FLASH_REG,
+	ixp2000_reg_wrb(IXDP2X01_CPLD_FLASH_REG,
 		((ofs >> IXDP2X01_FLASH_WINDOW_BITS) | IXDP2X01_CPLD_FLASH_INTERN));
 	return (ofs & IXDP2X01_FLASH_WINDOW_MASK);
 }
@@ -363,7 +363,7 @@ static struct platform_device *ixdp2x01_devices[] __initdata = {
 
 static void __init ixdp2x01_init_machine(void)
 {
-	ixp2000_reg_write(IXDP2X01_CPLD_FLASH_REG,
+	ixp2000_reg_wrb(IXDP2X01_CPLD_FLASH_REG,
 		(IXDP2X01_CPLD_FLASH_BANK_MASK | IXDP2X01_CPLD_FLASH_INTERN));
 	
 	ixdp2x01_flash_data.nr_banks =
diff --git a/arch/arm/mach-ixp2000/pci.c b/arch/arm/mach-ixp2000/pci.c
index 522205acb3..d4bf1e1c00 100644
--- a/arch/arm/mach-ixp2000/pci.c
+++ b/arch/arm/mach-ixp2000/pci.c
@@ -148,7 +148,7 @@ int ixp2000_pci_abort_handler(unsigned long addr, unsigned int fsr, struct pt_re
 	local_irq_save(flags);
 	temp = *(IXP2000_PCI_CONTROL);
 	if (temp & ((1 << 8) | (1 << 5))) {
-		ixp2000_reg_write(IXP2000_PCI_CONTROL, temp);
+		ixp2000_reg_wrb(IXP2000_PCI_CONTROL, temp);
 	}
 
 	temp = *(IXP2000_PCI_CMDSTAT);
@@ -178,8 +178,8 @@ clear_master_aborts(void)
 
 	local_irq_save(flags);
 	temp = *(IXP2000_PCI_CONTROL);
-	if (temp & ((1 << 8) | (1 << 5))) {	
-		ixp2000_reg_write(IXP2000_PCI_CONTROL, temp);
+	if (temp & ((1 << 8) | (1 << 5))) {
+		ixp2000_reg_wrb(IXP2000_PCI_CONTROL, temp);
 	}
 
 	temp = *(IXP2000_PCI_CMDSTAT);
-- 
cgit v1.2.2


From fa87cedd4e89ea29bda622d5cd6dbf19a915fc40 Mon Sep 17 00:00:00 2001
From: Lennert Buytenhek <buytenh@wantstofly.org>
Date: Tue, 1 Nov 2005 19:44:27 +0000
Subject: [ARM] 3065/1: ixp2000 typo and whitespace fixes

Patch from Lennert Buytenhek

Misc ixp2000 typo and whitespace fixes.

Signed-off-by: Lennert Buytenhek <buytenh@wantstofly.org>
Signed-off-by: Deepak Saxena <dsaxena@plexity.net>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-ixp2000/core.c     | 3 +--
 arch/arm/mach-ixp2000/ixdp2x01.c | 1 -
 2 files changed, 1 insertion(+), 3 deletions(-)

(limited to 'arch')

diff --git a/arch/arm/mach-ixp2000/core.c b/arch/arm/mach-ixp2000/core.c
index 69c6cf81a4..c93a98b2a3 100644
--- a/arch/arm/mach-ixp2000/core.c
+++ b/arch/arm/mach-ixp2000/core.c
@@ -1,5 +1,5 @@
 /*
- * arch/arm/mach-ixp2000/common.c
+ * arch/arm/mach-ixp2000/core.c
  *
  * Common routines used by all IXP2400/2800 based platforms.
  *
@@ -49,7 +49,6 @@ static unsigned long ixp2000_slowport_irq_flags;
  *************************************************************************/
 void ixp2000_acquire_slowport(struct slowport_cfg *new_cfg, struct slowport_cfg *old_cfg)
 {
-
 	spin_lock_irqsave(&ixp2000_slowport_lock, ixp2000_slowport_irq_flags);
 
 	old_cfg->CCR = *IXP2000_SLOWPORT_CCR;
diff --git a/arch/arm/mach-ixp2000/ixdp2x01.c b/arch/arm/mach-ixp2000/ixdp2x01.c
index dfaaa2d281..a4e507c8a1 100644
--- a/arch/arm/mach-ixp2000/ixdp2x01.c
+++ b/arch/arm/mach-ixp2000/ixdp2x01.c
@@ -299,7 +299,6 @@ struct hw_pci ixdp2x01_pci __initdata = {
 
 int __init ixdp2x01_pci_init(void)
 {
-
 	pci_common_init(&ixdp2x01_pci);
 	return 0;
 }
-- 
cgit v1.2.2


From e838ffc2e5c9afa81451cf21dcd3f3246e2adcd2 Mon Sep 17 00:00:00 2001
From: Ben Dooks <ben-linux@fluff.org>
Date: Tue, 1 Nov 2005 19:44:28 +0000
Subject: [ARM] 3071/1: RX3715 - add lcd/fb platform setup

Patch from Ben Dooks

Platform data for the LCD/framebuffer driver for
the RX3715 LCD panel.

Signed-off-by: Ben Dooks <ben-linux@fluff.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-s3c2410/mach-rx3715.c | 70 ++++++++++++++++++++++++++++++++++---
 1 file changed, 66 insertions(+), 4 deletions(-)

(limited to 'arch')

diff --git a/arch/arm/mach-s3c2410/mach-rx3715.c b/arch/arm/mach-s3c2410/mach-rx3715.c
index 22d9e070fd..7ff8e4d574 100644
--- a/arch/arm/mach-s3c2410/mach-rx3715.c
+++ b/arch/arm/mach-s3c2410/mach-rx3715.c
@@ -17,6 +17,7 @@
  *	10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA
  *	14-Mar-2005 BJD  Fixed __iomem warnings
  *	20-Sep-2005 BJD  Added static to non-exported items
+ *	31-Oct-2005 BJD  Added LCD setup for framebuffer
 */
 
 #include <linux/kernel.h>
@@ -42,6 +43,9 @@
 
 #include <asm/arch/regs-serial.h>
 #include <asm/arch/regs-gpio.h>
+#include <asm/arch/regs-lcd.h>
+
+#include <asm/arch/fb.h>
 
 #include "clock.h"
 #include "devs.h"
@@ -96,6 +100,66 @@ static struct s3c2410_uartcfg rx3715_uartcfgs[] = {
 	}
 };
 
+/* framebuffer lcd controller information */
+
+static struct s3c2410fb_mach_info rx3715_lcdcfg __initdata = {
+	.regs	= {
+		.lcdcon1 =	S3C2410_LCDCON1_TFT16BPP | \
+				S3C2410_LCDCON1_TFT | \
+				S3C2410_LCDCON1_CLKVAL(0x0C),
+
+		.lcdcon2 =	S3C2410_LCDCON2_VBPD(5) | \
+				S3C2410_LCDCON2_LINEVAL(319) | \
+				S3C2410_LCDCON2_VFPD(6) | \
+				S3C2410_LCDCON2_VSPW(2),
+
+		.lcdcon3 =	S3C2410_LCDCON3_HBPD(35) | \
+				S3C2410_LCDCON3_HOZVAL(239) | \
+				S3C2410_LCDCON3_HFPD(35),
+
+		.lcdcon4 =	S3C2410_LCDCON4_MVAL(0) | \
+				S3C2410_LCDCON4_HSPW(7),
+
+		.lcdcon5 =	S3C2410_LCDCON5_INVVLINE |
+				S3C2410_LCDCON5_FRM565 |
+				S3C2410_LCDCON5_HWSWP,
+	},
+
+	.lpcsel =	0xf82,
+
+	.gpccon =	0xaa955699,
+	.gpccon_mask =	0xffc003cc,
+	.gpcup =	0x0000ffff,
+	.gpcup_mask =	0xffffffff,
+
+	.gpdcon =	0xaa95aaa1,
+	.gpdcon_mask =	0xffc0fff0,
+	.gpdup =	0x0000faff,
+	.gpdup_mask =	0xffffffff,
+
+	.fixed_syncs =	1,
+	.width  =	240,
+	.height =	320,
+
+	.xres	= {
+		.min =		240,
+		.max =		240,
+		.defval =	240,
+	},
+
+	.yres	= {
+		.max =		320,
+		.min =		320,
+		.defval	=	320,
+	},
+
+	.bpp	= {
+		.min =		16,
+		.max =		16,
+		.defval =	16,
+	},
+};
+
 static struct platform_device *rx3715_devices[] __initdata = {
 	&s3c_device_usb,
 	&s3c_device_lcd,
@@ -122,14 +186,12 @@ static void __init rx3715_init_irq(void)
 	s3c24xx_init_irq();
 }
 
-#ifdef CONFIG_PM
 static void __init rx3715_init_machine(void)
 {
 	s3c2410_pm_init();
+	s3c24xx_fb_set_platdata(&rx3715_lcdcfg);
 }
-#else
-#define rx3715_init_machine NULL
-#endif
+
 
 MACHINE_START(RX3715, "IPAQ-RX3715")
 	/* Maintainer: Ben Dooks <ben@fluff.org> */
-- 
cgit v1.2.2


From 85eb226c446a017996859093cbfb5d3ae2c2117a Mon Sep 17 00:00:00 2001
From: David Brownell <david-b@pacbell.net>
Date: Tue, 1 Nov 2005 19:44:30 +0000
Subject: [ARM] 3078/1: lubbock platform updates, mostly mmc detection

Patch from David Brownell

Lubbock updates:

  * Provide an address for the SMC91x chip that doesn't generate
    a boot-time warning (matching the EEPROM).

  * Update MMC support to (a) detect card insert/remove, and
    (b) report the readonly switch setting for SD cards.

Previously, MMC/SD cards had to be present at boot time else they
couldn't be detected.

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-pxa/lubbock.c | 63 ++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 60 insertions(+), 3 deletions(-)

(limited to 'arch')

diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c
index beccf455f7..689f31349b 100644
--- a/arch/arm/mach-pxa/lubbock.c
+++ b/arch/arm/mach-pxa/lubbock.c
@@ -175,7 +175,7 @@ static struct platform_device sa1111_device = {
 static struct resource smc91x_resources[] = {
 	[0] = {
 		.name	= "smc91x-regs",
-		.start	= 0x0c000000,
+		.start	= 0x0c000c00,
 		.end	= 0x0c0fffff,
 		.flags	= IORESOURCE_MEM,
 	},
@@ -224,18 +224,75 @@ static struct pxafb_mach_info sharp_lm8v31 __initdata = {
 	.lccr3		= LCCR3_PCP | LCCR3_Acb(255),
 };
 
-static int lubbock_mci_init(struct device *dev, irqreturn_t (*lubbock_detect_int)(int, void *, struct pt_regs *), void *data)
+#define	MMC_POLL_RATE		msecs_to_jiffies(1000)
+
+static void lubbock_mmc_poll(unsigned long);
+static irqreturn_t (*mmc_detect_int)(int, void *, struct pt_regs *);
+
+static struct timer_list mmc_timer = {
+	.function	= lubbock_mmc_poll,
+};
+
+static void lubbock_mmc_poll(unsigned long data)
+{
+	unsigned long flags;
+
+	/* clear any previous irq state, then ... */
+	local_irq_save(flags);
+	LUB_IRQ_SET_CLR &= ~(1 << 0);
+	local_irq_restore(flags);
+
+	/* poll until mmc/sd card is removed */
+	if (LUB_IRQ_SET_CLR & (1 << 0))
+		mod_timer(&mmc_timer, jiffies + MMC_POLL_RATE);
+	else {
+		(void) mmc_detect_int(LUBBOCK_SD_IRQ, (void *)data, NULL);
+		enable_irq(LUBBOCK_SD_IRQ);
+	}
+}
+
+static irqreturn_t lubbock_detect_int(int irq, void *data, struct pt_regs *regs)
+{
+	/* IRQ is level triggered; disable, and poll for removal */
+	disable_irq(irq);
+	mod_timer(&mmc_timer, jiffies + MMC_POLL_RATE);
+
+	return mmc_detect_int(irq, data, regs);
+}
+
+static int lubbock_mci_init(struct device *dev,
+		irqreturn_t (*detect_int)(int, void *, struct pt_regs *),
+		void *data)
 {
 	/* setup GPIO for PXA25x MMC controller	*/
 	pxa_gpio_mode(GPIO6_MMCCLK_MD);
 	pxa_gpio_mode(GPIO8_MMCCS0_MD);
 
-	return 0;
+	/* detect card insert/eject */
+	mmc_detect_int = detect_int;
+	init_timer(&mmc_timer);
+	mmc_timer.data = (unsigned long) data;
+	return request_irq(LUBBOCK_SD_IRQ, lubbock_detect_int,
+			SA_SAMPLE_RANDOM, "lubbock-sd-detect", data);
+}
+
+static int lubbock_mci_get_ro(struct device *dev)
+{
+	return (LUB_MISC_RD & (1 << 2)) != 0;
+}
+
+static void lubbock_mci_exit(struct device *dev, void *data)
+{
+	free_irq(LUBBOCK_SD_IRQ, data);
+	del_timer_sync(&mmc_timer);
 }
 
 static struct pxamci_platform_data lubbock_mci_platform_data = {
 	.ocr_mask	= MMC_VDD_32_33|MMC_VDD_33_34,
+	.detect_delay	= 1,
 	.init 		= lubbock_mci_init,
+	.get_ro		= lubbock_mci_get_ro,
+	.exit 		= lubbock_mci_exit,
 };
 
 static void lubbock_irda_transceiver_mode(struct device *dev, int mode)
-- 
cgit v1.2.2


From a0c6fdb987860e6c7f9b8e57439ca2703f462578 Mon Sep 17 00:00:00 2001
From: Nicolas Pitre <nico@cam.org>
Date: Tue, 1 Nov 2005 19:52:22 +0000
Subject: [ARM] 2946/2: split --arch_clear_user() out of lib/uaccess.S

Patch from Nicolas Pitre

Required for future enhancement patches.

Signed-off-by: Nicolas Pitre <nico@cam.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/lib/Makefile     |  5 +++--
 arch/arm/lib/clear_user.S | 52 +++++++++++++++++++++++++++++++++++++++++++++++
 arch/arm/lib/uaccess.S    | 38 ----------------------------------
 3 files changed, 55 insertions(+), 40 deletions(-)
 create mode 100644 arch/arm/lib/clear_user.S

(limited to 'arch')

diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile
index 71e5b99e51..d3d9b21eb7 100644
--- a/arch/arm/lib/Makefile
+++ b/arch/arm/lib/Makefile
@@ -9,8 +9,9 @@ lib-y		:= backtrace.o changebit.o csumipv6.o csumpartial.o   \
 		   copy_page.o delay.o findbit.o memchr.o memcpy.o    \
 		   memset.o memzero.o setbit.o strncpy_from_user.o    \
 		   strnlen_user.o strchr.o strrchr.o testchangebit.o  \
-		   testclearbit.o testsetbit.o uaccess.o getuser.o    \
-		   putuser.o ashldi3.o ashrdi3.o lshrdi3.o muldi3.o   \
+		   testclearbit.o testsetbit.o uaccess.o              \
+		   getuser.o putuser.o clear_user.o                   \
+		   ashldi3.o ashrdi3.o lshrdi3.o muldi3.o             \
 		   ucmpdi2.o lib1funcs.o div64.o sha1.o               \
 		   io-readsb.o io-writesb.o io-readsl.o io-writesl.o
 
diff --git a/arch/arm/lib/clear_user.S b/arch/arm/lib/clear_user.S
new file mode 100644
index 0000000000..7ff9f831b3
--- /dev/null
+++ b/arch/arm/lib/clear_user.S
@@ -0,0 +1,52 @@
+/*
+ *  linux/arch/arm/lib/clear_user.S
+ *
+ *  Copyright (C) 1995, 1996,1997,1998 Russell King
+ *
+ * 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/linkage.h>
+#include <asm/assembler.h>
+
+		.text
+
+/* Prototype: int __arch_clear_user(void *addr, size_t sz)
+ * Purpose  : clear some user memory
+ * Params   : addr - user memory address to clear
+ *          : sz   - number of bytes to clear
+ * Returns  : number of bytes NOT cleared
+ */
+ENTRY(__arch_clear_user)
+		stmfd	sp!, {r1, lr}
+		mov	r2, #0
+		cmp	r1, #4
+		blt	2f
+		ands	ip, r0, #3
+		beq	1f
+		cmp	ip, #2
+USER(		strbt	r2, [r0], #1)
+USER(		strlebt	r2, [r0], #1)
+USER(		strltbt	r2, [r0], #1)
+		rsb	ip, ip, #4
+		sub	r1, r1, ip		@  7  6  5  4  3  2  1
+1:		subs	r1, r1, #8		@ -1 -2 -3 -4 -5 -6 -7
+USER(		strplt	r2, [r0], #4)
+USER(		strplt	r2, [r0], #4)
+		bpl	1b
+		adds	r1, r1, #4		@  3  2  1  0 -1 -2 -3
+USER(		strplt	r2, [r0], #4)
+2:		tst	r1, #2			@ 1x 1x 0x 0x 1x 1x 0x
+USER(		strnebt	r2, [r0], #1)
+USER(		strnebt	r2, [r0], #1)
+		tst	r1, #1			@ x1 x0 x1 x0 x1 x0 x1
+USER(		strnebt	r2, [r0], #1)
+		mov	r0, #0
+		LOADREGS(fd,sp!, {r1, pc})
+
+		.section .fixup,"ax"
+		.align	0
+9001:		LOADREGS(fd,sp!, {r0, pc})
+		.previous
+
diff --git a/arch/arm/lib/uaccess.S b/arch/arm/lib/uaccess.S
index d3ed0636c0..c28449157b 100644
--- a/arch/arm/lib/uaccess.S
+++ b/arch/arm/lib/uaccess.S
@@ -657,41 +657,3 @@ USER(		ldrgtbt	r3, [r1], #1)			@ May fault
 		LOADREGS(fd,sp!, {r4 - r7, pc})
 		.previous
 
-/* Prototype: int __arch_clear_user(void *addr, size_t sz)
- * Purpose  : clear some user memory
- * Params   : addr - user memory address to clear
- *          : sz   - number of bytes to clear
- * Returns  : number of bytes NOT cleared
- */
-ENTRY(__arch_clear_user)
-		stmfd	sp!, {r1, lr}
-		mov	r2, #0
-		cmp	r1, #4
-		blt	2f
-		ands	ip, r0, #3
-		beq	1f
-		cmp	ip, #2
-USER(		strbt	r2, [r0], #1)
-USER(		strlebt	r2, [r0], #1)
-USER(		strltbt	r2, [r0], #1)
-		rsb	ip, ip, #4
-		sub	r1, r1, ip		@  7  6  5  4  3  2  1
-1:		subs	r1, r1, #8		@ -1 -2 -3 -4 -5 -6 -7
-USER(		strplt	r2, [r0], #4)
-USER(		strplt	r2, [r0], #4)
-		bpl	1b
-		adds	r1, r1, #4		@  3  2  1  0 -1 -2 -3
-USER(		strplt	r2, [r0], #4)
-2:		tst	r1, #2			@ 1x 1x 0x 0x 1x 1x 0x
-USER(		strnebt	r2, [r0], #1)
-USER(		strnebt	r2, [r0], #1)
-		tst	r1, #1			@ x1 x0 x1 x0 x1 x0 x1
-USER(		strnebt	r2, [r0], #1)
-		mov	r0, #0
-		LOADREGS(fd,sp!, {r1, pc})
-
-		.section .fixup,"ax"
-		.align	0
-9001:		LOADREGS(fd,sp!, {r0, pc})
-		.previous
-
-- 
cgit v1.2.2


From 7549423000fc38d39a8b81c601dea0332c113a42 Mon Sep 17 00:00:00 2001
From: Nicolas Pitre <nico@cam.org>
Date: Tue, 1 Nov 2005 19:52:23 +0000
Subject: [ARM] 2947/1: copy template with new memcpy/memmove

Patch from Nicolas Pitre

This patch provides a new implementation for optimized memory copy
functions on ARM.  It is made of two levels: a template that consists of
the core copy code and separate files that define macros to be used with
the core code depending on the type of copy needed. This allows for best
performances while sharing the same core for implementing memcpy(),
copy_from_user() and copy_to_user() for instance.

Two reasons for this work:

1) the current copy_to_user/copy_from_user implementation assumes no
   task switch will ever occur in the middle of each copied page making
   it completely unsafe with CONFIG_PREEMPT=y.

2) current copy implementations are measurably suboptimal and optimizing
   different implementations separately is a pain and more opportunities
   for bugs.

The reason for (1) is the fact that copy inside user pages are performed
with the ldm instruction which has no mean for testing user protections
and could possibly race with process preemption bypassing the COW mechanism
for example.  This is a longstanding issue that we said ought to be fixed
for about two years now.  The solution is to substitute those ldm insns
with a series of ldrt or strt insns to enforce user memory protection.
At least on StrongARM and XScale cores the ldm is not faster than the
equivalent ldr/str insns with a warm i-cache so there is no measurable
performance degradation with that change. The fact that the copy code is
a template makes it pretty easy to reuse the same core code as for memcpy
and benefit from the same performance optimizations.

Now (2) is best demonstrated with actual throughput measurements.
First, here is a summary of memcopy tests performed on a StrongARM core:

	PTR alignment	buffer size	kernel version	this version
	------------------------------------------------------------
	  aligned	     32		 59.73		107.43
	unaligned	     32		 61.31		 74.72
	  aligned	    100		132.47		136.15
	unaligned	    100	    	103.84		123.76
	  aligned	   4096		130.67		130.80
	unaligned	   4096	    	130.68		130.64
	  aligned	1048576		 68.03		68.18
	unaligned	1048576		 68.03		68.18

The buffer size is in bytes and the measured speed in MB/s.  The copy
was performed repeatedly with given buffer and throughput averaged over
3 seconds.

Here we can see that the current kernel version has a higher entry cost
that shows up with small buffers.  As buffer size grows both implementation
converge to the same throughput.

Now here's the exact same test performed on an XScale core (PXA255):

	PTR alignment	buffer size	kernel version	this version
	------------------------------------------------------------
	  aligned	     32		 46.99		 77.58
	unaligned	     32		 53.61		 59.59
	  aligned	    100		107.19		136.59
	unaligned	    100		 83.61		 97.58
	  aligned	   4096		129.13		129.98
	unaligned	   4096		128.36		128.53
	  aligned	1048576		 53.76		 59.41
	unaligned	1048576		 33.67		 56.96

Again we can see the entry setup cost being higher for the current kernel
before getting to the main copy loop.  Then throughput results converge
as long as the buffer remains in the cache. Then the 1MB case shows more
differences probably due to better pld placement and/or less instruction
interlocks in this proposed implementation.

Disclaimer: The PXA system was running with slower clocks than the
StrongARM system so trying to infer any conclusion by comparing those
separate sets of results side by side would be completely inappropriate.

So...  What this patch does is to replace both memcpy and memmove with
an implementation based on the provided copy code template.  The memmove
code is kept separate since it is used only if the memory areas involved
do overlap in which case the code is a transposition of the template but
with the copy occurring in the opposite direction (trying to fit that
mode into the template turned it into a mess not worth it for memmove
alone).  And obviously both memcpy and memmove were tested with all kinds
of pointer alignments and buffer sizes to exercise all code paths for
correctness.

The next patch will provide the now trivial replacement implementation
copy_to_user and copy_from_user.

Signed-off-by: Nicolas Pitre <nico@cam.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/lib/Makefile        |   5 +-
 arch/arm/lib/copy_template.S | 255 +++++++++++++++++++++++++++
 arch/arm/lib/memcpy.S        | 410 ++++---------------------------------------
 arch/arm/lib/memmove.S       | 206 ++++++++++++++++++++++
 4 files changed, 502 insertions(+), 374 deletions(-)
 create mode 100644 arch/arm/lib/copy_template.S
 create mode 100644 arch/arm/lib/memmove.S

(limited to 'arch')

diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile
index d3d9b21eb7..8f9770f1af 100644
--- a/arch/arm/lib/Makefile
+++ b/arch/arm/lib/Makefile
@@ -7,8 +7,9 @@
 lib-y		:= backtrace.o changebit.o csumipv6.o csumpartial.o   \
 		   csumpartialcopy.o csumpartialcopyuser.o clearbit.o \
 		   copy_page.o delay.o findbit.o memchr.o memcpy.o    \
-		   memset.o memzero.o setbit.o strncpy_from_user.o    \
-		   strnlen_user.o strchr.o strrchr.o testchangebit.o  \
+		   memmove.o memset.o memzero.o setbit.o              \
+		   strncpy_from_user.o strnlen_user.o                 \
+		   strchr.o strrchr.o testchangebit.o                 \
 		   testclearbit.o testsetbit.o uaccess.o              \
 		   getuser.o putuser.o clear_user.o                   \
 		   ashldi3.o ashrdi3.o lshrdi3.o muldi3.o             \
diff --git a/arch/arm/lib/copy_template.S b/arch/arm/lib/copy_template.S
new file mode 100644
index 0000000000..838e435e49
--- /dev/null
+++ b/arch/arm/lib/copy_template.S
@@ -0,0 +1,255 @@
+/*
+ *  linux/arch/arm/lib/copy_template.s
+ *
+ *  Code template for optimized memory copy functions
+ *
+ *  Author:	Nicolas Pitre
+ *  Created:	Sep 28, 2005
+ *  Copyright:	MontaVista Software, Inc.
+ *
+ *  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 can be used to enable code to cacheline align the source pointer.
+ * Experiments on tested architectures (StrongARM and XScale) didn't show
+ * this a worthwhile thing to do.  That might be different in the future.
+ */
+//#define CALGN(code...)	code
+#define CALGN(code...)
+
+/*
+ * Theory of operation
+ * -------------------
+ *
+ * This file provides the core code for a forward memory copy used in
+ * the implementation of memcopy(), copy_to_user() and copy_from_user().
+ *
+ * The including file must define the following accessor macros
+ * according to the need of the given function:
+ *
+ * ldr1w ptr reg abort
+ *
+ *	This loads one word from 'ptr', stores it in 'reg' and increments
+ *	'ptr' to the next word. The 'abort' argument is used for fixup tables.
+ *
+ * ldr4w ptr reg1 reg2 reg3 reg4 abort
+ * ldr8w ptr, reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
+ *
+ *	This loads four or eight words starting from 'ptr', stores them
+ *	in provided registers and increments 'ptr' past those words.
+ *	The'abort' argument is used for fixup tables.
+ *
+ * ldr1b ptr reg cond abort
+ *
+ *	Similar to ldr1w, but it loads a byte and increments 'ptr' one byte.
+ *	It also must apply the condition code if provided, otherwise the
+ *	"al" condition is assumed by default.
+ *
+ * str1w ptr reg abort
+ * str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
+ * str1b ptr reg cond abort
+ *
+ *	Same as their ldr* counterparts, but data is stored to 'ptr' location
+ *	rather than being loaded.
+ *
+ * enter reg1 reg2
+ *
+ *	Preserve the provided registers on the stack plus any additional
+ *	data as needed by the implementation including this code. Called
+ *	upon code entry.
+ *
+ * exit reg1 reg2
+ *
+ *	Restore registers with the values previously saved with the
+ *	'preserv' macro. Called upon code termination.
+ */
+
+
+		enter	r4, lr
+
+		subs	r2, r2, #4
+		blt	8f
+		ands	ip, r0, #3
+	PLD(	pld	[r1, #0]		)
+		bne	9f
+		ands	ip, r1, #3
+		bne	10f
+
+1:		subs	r2, r2, #(28)
+		stmfd	sp!, {r5 - r8}
+		blt	5f
+
+	CALGN(	ands	ip, r1, #31		)
+	CALGN(	rsb	r3, ip, #32		)
+	CALGN(	sbcnes	r4, r3, r2		)  @ C is always set here
+	CALGN(	bcs	2f			)
+	CALGN(	adr	r4, 6f			)
+	CALGN(	subs	r2, r2, r3		)  @ C gets set
+	CALGN(	add	pc, r4, ip		)
+
+	PLD(	pld	[r1, #0]		)
+2:	PLD(	subs	r2, r2, #96		)
+	PLD(	pld	[r1, #28]		)
+	PLD(	blt	4f			)
+	PLD(	pld	[r1, #60]		)
+	PLD(	pld	[r1, #92]		)
+
+3:	PLD(	pld	[r1, #124]		)
+4:		ldr8w	r1, r3, r4, r5, r6, r7, r8, ip, lr, abort=20f
+		subs	r2, r2, #32
+		str8w	r0, r3, r4, r5, r6, r7, r8, ip, lr, abort=20f
+		bge	3b
+	PLD(	cmn	r2, #96			)
+	PLD(	bge	4b			)
+
+5:		ands	ip, r2, #28
+		rsb	ip, ip, #32
+		addne	pc, pc, ip		@ C is always clear here
+		b	7f
+6:		nop
+		ldr1w	r1, r3, abort=20f
+		ldr1w	r1, r4, abort=20f
+		ldr1w	r1, r5, abort=20f
+		ldr1w	r1, r6, abort=20f
+		ldr1w	r1, r7, abort=20f
+		ldr1w	r1, r8, abort=20f
+		ldr1w	r1, lr, abort=20f
+
+		add	pc, pc, ip
+		nop
+		nop
+		str1w	r0, r3, abort=20f
+		str1w	r0, r4, abort=20f
+		str1w	r0, r5, abort=20f
+		str1w	r0, r6, abort=20f
+		str1w	r0, r7, abort=20f
+		str1w	r0, r8, abort=20f
+		str1w	r0, lr, abort=20f
+
+	CALGN(	bcs	2b			)
+
+7:		ldmfd	sp!, {r5 - r8}
+
+8:		movs	r2, r2, lsl #31
+		ldr1b	r1, r3, ne, abort=21f
+		ldr1b	r1, r4, cs, abort=21f
+		ldr1b	r1, ip, cs, abort=21f
+		str1b	r0, r3, ne, abort=21f
+		str1b	r0, r4, cs, abort=21f
+		str1b	r0, ip, cs, abort=21f
+
+		exit	r4, pc
+
+9:		rsb	ip, ip, #4
+		cmp	ip, #2
+		ldr1b	r1, r3, gt, abort=21f
+		ldr1b	r1, r4, ge, abort=21f
+		ldr1b	r1, lr, abort=21f
+		str1b	r0, r3, gt, abort=21f
+		str1b	r0, r4, ge, abort=21f
+		subs	r2, r2, ip
+		str1b	r0, lr, abort=21f
+		blt	8b
+		ands	ip, r1, #3
+		beq	1b
+
+10:		bic	r1, r1, #3
+		cmp	ip, #2
+		ldr1w	r1, lr, abort=21f
+		beq	17f
+		bgt	18f
+
+
+		.macro	forward_copy_shift pull push
+
+		subs	r2, r2, #28
+		blt	14f
+
+	CALGN(	ands	ip, r1, #31		)
+	CALGN(	rsb	ip, ip, #32		)
+	CALGN(	sbcnes	r4, ip, r2		)  @ C is always set here
+	CALGN(	subcc	r2, r2, ip		)
+	CALGN(	bcc	15f			)
+
+11:		stmfd	sp!, {r5 - r9}
+
+	PLD(	pld	[r1, #0]		)
+	PLD(	subs	r2, r2, #96		)
+	PLD(	pld	[r1, #28]		)
+	PLD(	blt	13f			)
+	PLD(	pld	[r1, #60]		)
+	PLD(	pld	[r1, #92]		)
+
+12:	PLD(	pld	[r1, #124]		)
+13:		ldr4w	r1, r4, r5, r6, r7, abort=19f
+		mov	r3, lr, pull #\pull
+		subs	r2, r2, #32
+		ldr4w	r1, r8, r9, ip, lr, abort=19f
+		orr	r3, r3, r4, push #\push
+		mov	r4, r4, pull #\pull
+		orr	r4, r4, r5, push #\push
+		mov	r5, r5, pull #\pull
+		orr	r5, r5, r6, push #\push
+		mov	r6, r6, pull #\pull
+		orr	r6, r6, r7, push #\push
+		mov	r7, r7, pull #\pull
+		orr	r7, r7, r8, push #\push
+		mov	r8, r8, pull #\pull
+		orr	r8, r8, r9, push #\push
+		mov	r9, r9, pull #\pull
+		orr	r9, r9, ip, push #\push
+		mov	ip, ip, pull #\pull
+		orr	ip, ip, lr, push #\push
+		str8w	r0, r3, r4, r5, r6, r7, r8, r9, ip, , abort=19f
+		bge	12b
+	PLD(	cmn	r2, #96			)
+	PLD(	bge	13b			)
+
+		ldmfd	sp!, {r5 - r9}
+
+14:		ands	ip, r2, #28
+		beq	16f
+
+15:		mov	r3, lr, pull #\pull
+		ldr1w	r1, lr, abort=21f
+		subs	ip, ip, #4
+		orr	r3, r3, lr, push #\push
+		str1w	r0, r3, abort=21f
+		bgt	15b
+	CALGN(	cmp	r2, #0			)
+	CALGN(	bge	11b			)
+
+16:		sub	r1, r1, #(\push / 8)
+		b	8b
+
+		.endm
+
+
+		forward_copy_shift	pull=8	push=24
+
+17:		forward_copy_shift	pull=16	push=16
+
+18:		forward_copy_shift	pull=24	push=8
+
+
+/*
+ * Abort preanble and completion macros.
+ * If a fixup handler is required then those macros must surround it.
+ * It is assumed that the fixup code will handle the private part of
+ * the exit macro.
+ */
+
+	.macro	copy_abort_preamble
+19:	ldmfd	sp!, {r5 - r9}
+	b	21f
+20:	ldmfd	sp!, {r5 - r8}
+21:
+	.endm
+
+	.macro	copy_abort_end
+	ldmfd	sp!, {r4, pc}
+	.endm
+
diff --git a/arch/arm/lib/memcpy.S b/arch/arm/lib/memcpy.S
index f5a593ceb8..7e71d6708a 100644
--- a/arch/arm/lib/memcpy.S
+++ b/arch/arm/lib/memcpy.S
@@ -1,393 +1,59 @@
 /*
  *  linux/arch/arm/lib/memcpy.S
  *
- *  Copyright (C) 1995-1999 Russell King
+ *  Author:	Nicolas Pitre
+ *  Created:	Sep 28, 2005
+ *  Copyright:	MontaVista Software, Inc.
  *
- * 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.
- *
- *  ASM optimised string functions
+ *  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/linkage.h>
 #include <asm/assembler.h>
 
-		.text
-
-#define ENTER	\
-		mov	ip,sp	;\
-		stmfd	sp!,{r0,r4-r9,fp,ip,lr,pc}	;\
-		sub	fp,ip,#4
-
-#define EXIT	\
-		LOADREGS(ea, fp, {r0, r4 - r9, fp, sp, pc})
-
-#define EXITEQ	\
-		LOADREGS(eqea, fp, {r0, r4 - r9, fp, sp, pc})
-
-/*
- * Prototype: void memcpy(void *to,const void *from,unsigned long n);
- */
-ENTRY(memcpy)
-ENTRY(memmove)
-		ENTER
-		cmp	r1, r0
-		bcc	23f
-		subs	r2, r2, #4
-		blt	6f
-	PLD(	pld	[r1, #0]		)
-		ands	ip, r0, #3
-		bne	7f
-		ands	ip, r1, #3
-		bne	8f
+	.macro ldr1w ptr reg abort
+	ldr \reg, [\ptr], #4
+	.endm
 
-1:		subs	r2, r2, #8
-		blt	5f
-		subs	r2, r2, #20
-		blt	4f
-	PLD(	pld	[r1, #28]		)
-	PLD(	subs	r2, r2, #64		)
-	PLD(	blt	3f			)
-2:	PLD(	pld	[r1, #60]		)
-	PLD(	pld	[r1, #92]		)
-		ldmia	r1!, {r3 - r9, ip}
-		subs	r2, r2, #32
-		stmgeia	r0!, {r3 - r9, ip}
-		ldmgeia	r1!, {r3 - r9, ip}
-		subges	r2, r2, #32
-		stmia	r0!, {r3 - r9, ip}
-		bge	2b
-3:	PLD(	ldmia	r1!, {r3 - r9, ip}	)
-	PLD(	adds	r2, r2, #32		)
-	PLD(	stmgeia	r0!, {r3 - r9, ip}	)
-	PLD(	ldmgeia	r1!, {r3 - r9, ip}	)
-	PLD(	subges	r2, r2, #32		)
-	PLD(	stmia	r0!, {r3 - r9, ip}	)
-4:		cmn	r2, #16
-		ldmgeia	r1!, {r3 - r6}
-		subge	r2, r2, #16
-		stmgeia	r0!, {r3 - r6}
-		adds	r2, r2, #20
-		ldmgeia	r1!, {r3 - r5}
-		subge	r2, r2, #12
-		stmgeia	r0!, {r3 - r5}
-5:		adds	r2, r2, #8
-		blt	6f
-		subs	r2, r2, #4
-		ldrlt	r3, [r1], #4
-		ldmgeia	r1!, {r4, r5}
-		subge	r2, r2, #4
-		strlt	r3, [r0], #4
-		stmgeia	r0!, {r4, r5}
+	.macro ldr4w ptr reg1 reg2 reg3 reg4 abort
+	ldmia \ptr!, {\reg1, \reg2, \reg3, \reg4}
+	.endm
 
-6:		adds	r2, r2, #4
-		EXITEQ
-		cmp	r2, #2
-		ldrb	r3, [r1], #1
-		ldrgeb	r4, [r1], #1
-		ldrgtb	r5, [r1], #1
-		strb	r3, [r0], #1
-		strgeb	r4, [r0], #1
-		strgtb	r5, [r0], #1
-		EXIT
+	.macro ldr8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
+	ldmia \ptr!, {\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8}
+	.endm
 
-7:		rsb	ip, ip, #4
-		cmp	ip, #2
-		ldrb	r3, [r1], #1
-		ldrgeb	r4, [r1], #1
-		ldrgtb	r5, [r1], #1
-		strb	r3, [r0], #1
-		strgeb	r4, [r0], #1
-		strgtb	r5, [r0], #1
-		subs	r2, r2, ip
-		blt	6b
-		ands	ip, r1, #3
-		beq	1b
+	.macro ldr1b ptr reg cond=al abort
+	ldr\cond\()b \reg, [\ptr], #1
+	.endm
 
-8:		bic	r1, r1, #3
-		ldr	r7, [r1], #4
-		cmp	ip, #2
-		bgt	18f
-		beq	13f
-		cmp	r2, #12
-		blt	11f
-	PLD(	pld	[r1, #12]		)
-		sub	r2, r2, #12
-	PLD(	subs	r2, r2, #32		)
-	PLD(	blt	10f			)
-	PLD(	pld	[r1, #28]		)
-9:	PLD(	pld	[r1, #44]		)
-10:		mov	r3, r7, pull #8
-		ldmia	r1!, {r4 - r7}
-		subs	r2, r2, #16
-		orr	r3, r3, r4, push #24
-		mov	r4, r4, pull #8
-		orr	r4, r4, r5, push #24
-		mov	r5, r5, pull #8
-		orr	r5, r5, r6, push #24
-		mov	r6, r6, pull #8
-		orr	r6, r6, r7, push #24
-		stmia	r0!, {r3 - r6}
-		bge	9b
-	PLD(	cmn	r2, #32			)
-	PLD(	bge	10b			)
-	PLD(	add	r2, r2, #32		)
-		adds	r2, r2, #12
-		blt	12f
-11:		mov	r3, r7, pull #8
-		ldr	r7, [r1], #4
-		subs	r2, r2, #4
-		orr	r3, r3, r7, push #24
-		str	r3, [r0], #4
-		bge	11b
-12:		sub	r1, r1, #3
-		b	6b
+	.macro str1w ptr reg abort
+	str \reg, [\ptr], #4
+	.endm
 
-13:		cmp	r2, #12
-		blt	16f
-	PLD(	pld	[r1, #12]		)
-		sub	r2, r2, #12
-	PLD(	subs	r2, r2, #32		)
-	PLD(	blt	15f			)
-	PLD(	pld	[r1, #28]		)
-14:	PLD(	pld	[r1, #44]		)
-15:		mov	r3, r7, pull #16
-		ldmia	r1!, {r4 - r7}
-		subs	r2, r2, #16
-		orr	r3, r3, r4, push #16
-		mov	r4, r4, pull #16
-		orr	r4, r4, r5, push #16
-		mov	r5, r5, pull #16
-		orr	r5, r5, r6, push #16
-		mov	r6, r6, pull #16
-		orr	r6, r6, r7, push #16
-		stmia	r0!, {r3 - r6}
-		bge	14b
-	PLD(	cmn	r2, #32			)
-	PLD(	bge	15b			)
-	PLD(	add	r2, r2, #32		)
-		adds	r2, r2, #12
-		blt	17f
-16:		mov	r3, r7, pull #16
-		ldr	r7, [r1], #4
-		subs	r2, r2, #4
-		orr	r3, r3, r7, push #16
-		str	r3, [r0], #4
-		bge	16b
-17:		sub	r1, r1, #2
-		b	6b
+	.macro str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
+	stmia \ptr!, {\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8}
+	.endm
 
-18:		cmp	r2, #12
-		blt	21f
-	PLD(	pld	[r1, #12]		)
-		sub	r2, r2, #12
-	PLD(	subs	r2, r2, #32		)
-	PLD(	blt	20f			)
-	PLD(	pld	[r1, #28]		)
-19:	PLD(	pld	[r1, #44]		)
-20:		mov	r3, r7, pull #24
-		ldmia	r1!, {r4 - r7}
-		subs	r2, r2, #16
-		orr	r3, r3, r4, push #8
-		mov	r4, r4, pull #24
-		orr	r4, r4, r5, push #8
-		mov	r5, r5, pull #24
-		orr	r5, r5, r6, push #8
-		mov	r6, r6, pull #24
-		orr	r6, r6, r7, push #8
-		stmia	r0!, {r3 - r6}
-		bge	19b
-	PLD(	cmn	r2, #32			)
-	PLD(	bge	20b			)
-	PLD(	add	r2, r2, #32		)
-		adds	r2, r2, #12
-		blt	22f
-21:		mov	r3, r7, pull #24
-		ldr	r7, [r1], #4
-		subs	r2, r2, #4
-		orr	r3, r3, r7, push #8
-		str	r3, [r0], #4
-		bge	21b
-22:		sub	r1, r1, #1
-		b	6b
+	.macro str1b ptr reg cond=al abort
+	str\cond\()b \reg, [\ptr], #1
+	.endm
 
+	.macro enter reg1 reg2
+	stmdb sp!, {r0, \reg1, \reg2}
+	.endm
 
-23:		add	r1, r1, r2
-		add	r0, r0, r2
-		subs	r2, r2, #4
-		blt	29f
-	PLD(	pld	[r1, #-4]		)
-		ands	ip, r0, #3
-		bne	30f
-		ands	ip, r1, #3
-		bne	31f
+	.macro exit reg1 reg2
+	ldmfd sp!, {r0, \reg1, \reg2}
+	.endm
 
-24:		subs	r2, r2, #8
-		blt	28f
-		subs	r2, r2, #20
-		blt	27f
-	PLD(	pld	[r1, #-32]		)
-	PLD(	subs	r2, r2, #64		)
-	PLD(	blt	26f			)
-25:	PLD(	pld	[r1, #-64]		)
-	PLD(	pld	[r1, #-96]		)
-		ldmdb	r1!, {r3 - r9, ip}
-		subs	r2, r2, #32
-		stmgedb	r0!, {r3 - r9, ip}
-		ldmgedb	r1!, {r3 - r9, ip}
-		subges	r2, r2, #32
-		stmdb	r0!, {r3 - r9, ip}
-		bge	25b
-26:	PLD(	ldmdb	r1!, {r3 - r9, ip}	)
-	PLD(	adds	r2, r2, #32		)
-	PLD(	stmgedb	r0!, {r3 - r9, ip}	)
-	PLD(	ldmgedb	r1!, {r3 - r9, ip}	)
-	PLD(	subges	r2, r2, #32		)
-	PLD(	stmdb	r0!, {r3 - r9, ip}	)
-27:		cmn	r2, #16
-		ldmgedb	r1!, {r3 - r6}
-		subge	r2, r2, #16
-		stmgedb	r0!, {r3 - r6}
-		adds	r2, r2, #20
-		ldmgedb	r1!, {r3 - r5}
-		subge	r2, r2, #12
-		stmgedb	r0!, {r3 - r5}
-28:		adds	r2, r2, #8
-		blt	29f
-		subs	r2, r2, #4
-		ldrlt	r3, [r1, #-4]!
-		ldmgedb	r1!, {r4, r5}
-		subge	r2, r2, #4
-		strlt	r3, [r0, #-4]!
-		stmgedb	r0!, {r4, r5}
+	.text
 
-29:		adds	r2, r2, #4
-		EXITEQ
-		cmp	r2, #2
-		ldrb	r3, [r1, #-1]!
-		ldrgeb	r4, [r1, #-1]!
-		ldrgtb	r5, [r1, #-1]!
-		strb	r3, [r0, #-1]!
-		strgeb	r4, [r0, #-1]!
-		strgtb	r5, [r0, #-1]!
-		EXIT
+/* Prototype: void *memcpy(void *dest, const void *src, size_t n); */
 
-30:		cmp	ip, #2
-		ldrb	r3, [r1, #-1]!
-		ldrgeb	r4, [r1, #-1]!
-		ldrgtb	r5, [r1, #-1]!
-		strb	r3, [r0, #-1]!
-		strgeb	r4, [r0, #-1]!
-		strgtb	r5, [r0, #-1]!
-		subs	r2, r2, ip
-		blt	29b
-		ands	ip, r1, #3
-		beq	24b
-
-31:		bic	r1, r1, #3
-		ldr	r3, [r1], #0
-		cmp	ip, #2
-		blt	41f
-		beq	36f
-		cmp	r2, #12
-		blt	34f
-	PLD(	pld	[r1, #-16]		)
-		sub	r2, r2, #12
-	PLD(	subs	r2, r2, #32		)
-	PLD(	blt	33f			)
-	PLD(	pld	[r1, #-32]		)
-32:	PLD(	pld	[r1, #-48]		)
-33:		mov	r7, r3, push #8
-		ldmdb	r1!, {r3, r4, r5, r6}
-		subs	r2, r2, #16
-		orr	r7, r7, r6, pull #24
-		mov	r6, r6, push #8
-		orr	r6, r6, r5, pull #24
-		mov	r5, r5, push #8
-		orr	r5, r5, r4, pull #24
-		mov	r4, r4, push #8
-		orr	r4, r4, r3, pull #24
-		stmdb	r0!, {r4, r5, r6, r7}
-		bge	32b
-	PLD(	cmn	r2, #32			)
-	PLD(	bge	33b			)
-	PLD(	add	r2, r2, #32		)
-		adds	r2, r2, #12
-		blt	35f
-34:		mov	ip, r3, push #8
-		ldr	r3, [r1, #-4]!
-		subs	r2, r2, #4
-		orr	ip, ip, r3, pull #24
-		str	ip, [r0, #-4]!
-		bge	34b
-35:		add	r1, r1, #3
-		b	29b
-
-36:		cmp	r2, #12
-		blt	39f
-	PLD(	pld	[r1, #-16]		)
-		sub	r2, r2, #12
-	PLD(	subs	r2, r2, #32		)
-	PLD(	blt	38f			)
-	PLD(	pld	[r1, #-32]		)
-37:	PLD(	pld	[r1, #-48]		)
-38:		mov	r7, r3, push #16
-		ldmdb	r1!, {r3, r4, r5, r6}
-		subs	r2, r2, #16
-		orr	r7, r7, r6, pull #16
-		mov	r6, r6, push #16
-		orr	r6, r6, r5, pull #16
-		mov	r5, r5, push #16
-		orr	r5, r5, r4, pull #16
-		mov	r4, r4, push #16
-		orr	r4, r4, r3, pull #16
-		stmdb	r0!, {r4, r5, r6, r7}
-		bge	37b
-	PLD(	cmn	r2, #32			)
-	PLD(	bge	38b			)
-	PLD(	add	r2, r2, #32		)
-		adds	r2, r2, #12
-		blt	40f
-39:		mov	ip, r3, push #16
-		ldr	r3, [r1, #-4]!
-		subs	r2, r2, #4
-		orr	ip, ip, r3, pull #16
-		str	ip, [r0, #-4]!
-		bge	39b
-40:		add	r1, r1, #2
-		b	29b
+ENTRY(memcpy)
 
-41:		cmp	r2, #12
-		blt	44f
-	PLD(	pld	[r1, #-16]		)
-		sub	r2, r2, #12
-	PLD(	subs	r2, r2, #32		)
-	PLD(	blt	43f			)
-	PLD(	pld	[r1, #-32]		)
-42:	PLD(	pld	[r1, #-48]		)
-43:		mov	r7, r3, push #24
-		ldmdb	r1!, {r3, r4, r5, r6}
-		subs	r2, r2, #16
-		orr	r7, r7, r6, pull #8
-		mov	r6, r6, push #24
-		orr	r6, r6, r5, pull #8
-		mov	r5, r5, push #24
-		orr	r5, r5, r4, pull #8
-		mov	r4, r4, push #24
-		orr	r4, r4, r3, pull #8
-		stmdb	r0!, {r4, r5, r6, r7}
-		bge	42b
-	PLD(	cmn	r2, #32			)
-	PLD(	bge	43b			)
-	PLD(	add	r2, r2, #32		)
-		adds	r2, r2, #12
-		blt	45f
-44:		mov	ip, r3, push #24
-		ldr	r3, [r1, #-4]!
-		subs	r2, r2, #4
-		orr	ip, ip, r3, pull #8
-		str	ip, [r0, #-4]!
-		bge	44b
-45:		add	r1, r1, #1
-		b	29b
+#include "copy_template.S"
 
diff --git a/arch/arm/lib/memmove.S b/arch/arm/lib/memmove.S
new file mode 100644
index 0000000000..ef7fddc14a
--- /dev/null
+++ b/arch/arm/lib/memmove.S
@@ -0,0 +1,206 @@
+/*
+ *  linux/arch/arm/lib/memmove.S
+ *
+ *  Author:	Nicolas Pitre
+ *  Created:	Sep 28, 2005
+ *  Copyright:	(C) MontaVista Software Inc.
+ *
+ *  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/linkage.h>
+#include <asm/assembler.h>
+
+/*
+ * This can be used to enable code to cacheline align the source pointer.
+ * Experiments on tested architectures (StrongARM and XScale) didn't show
+ * this a worthwhile thing to do.  That might be different in the future.
+ */
+//#define CALGN(code...)        code
+#define CALGN(code...)
+
+		.text
+
+/*
+ * Prototype: void *memmove(void *dest, const void *src, size_t n);
+ *
+ * Note:
+ *
+ * If the memory regions don't overlap, we simply branch to memcpy which is
+ * normally a bit faster. Otherwise the copy is done going downwards.  This
+ * is a transposition of the code from copy_template.S but with the copy
+ * occurring in the opposite direction.
+ */
+
+ENTRY(memmove)
+
+		subs	ip, r0, r1
+		cmphi	r2, ip
+		bls	memcpy
+
+		stmfd	sp!, {r0, r4, lr}
+		add	r1, r1, r2
+		add	r0, r0, r2
+		subs	r2, r2, #4
+		blt	8f
+		ands	ip, r0, #3
+	PLD(	pld	[r1, #-4]		)
+		bne	9f
+		ands	ip, r1, #3
+		bne	10f
+
+1:		subs	r2, r2, #(28)
+		stmfd	sp!, {r5 - r8}
+		blt	5f
+
+	CALGN(	ands	ip, r1, #31		)
+	CALGN(	sbcnes	r4, ip, r2		)  @ C is always set here
+	CALGN(	bcs	2f			)
+	CALGN(	adr	r4, 6f			)
+	CALGN(	subs	r2, r2, ip		)  @ C is set here
+	CALGN(	add	pc, r4, ip		)
+
+	PLD(	pld	[r1, #-4]		)
+2:	PLD(	subs	r2, r2, #96		)
+	PLD(	pld	[r1, #-32]		)
+	PLD(	blt	4f			)
+	PLD(	pld	[r1, #-64]		)
+	PLD(	pld	[r1, #-96]		)
+
+3:	PLD(	pld	[r1, #-128]		)
+4:		ldmdb	r1!, {r3, r4, r5, r6, r7, r8, ip, lr}
+		subs	r2, r2, #32
+		stmdb	r0!, {r3, r4, r5, r6, r7, r8, ip, lr}
+		bge	3b
+	PLD(	cmn	r2, #96			)
+	PLD(	bge	4b			)
+
+5:		ands	ip, r2, #28
+		rsb	ip, ip, #32
+		addne	pc, pc, ip		@ C is always clear here
+		b	7f
+6:		nop
+		ldr	r3, [r1, #-4]!
+		ldr	r4, [r1, #-4]!
+		ldr	r5, [r1, #-4]!
+		ldr	r6, [r1, #-4]!
+		ldr	r7, [r1, #-4]!
+		ldr	r8, [r1, #-4]!
+		ldr	lr, [r1, #-4]!
+
+		add	pc, pc, ip
+		nop
+		nop
+		str	r3, [r0, #-4]!
+		str	r4, [r0, #-4]!
+		str	r5, [r0, #-4]!
+		str	r6, [r0, #-4]!
+		str	r7, [r0, #-4]!
+		str	r8, [r0, #-4]!
+		str	lr, [r0, #-4]!
+
+	CALGN(	bcs	2b			)
+
+7:		ldmfd	sp!, {r5 - r8}
+
+8:		movs	r2, r2, lsl #31
+		ldrneb	r3, [r1, #-1]!
+		ldrcsb	r4, [r1, #-1]!
+		ldrcsb	ip, [r1, #-1]
+		strneb	r3, [r0, #-1]!
+		strcsb	r4, [r0, #-1]!
+		strcsb	ip, [r0, #-1]
+		ldmfd	sp!, {r0, r4, pc}
+
+9:		cmp	ip, #2
+		ldrgtb	r3, [r1, #-1]!
+		ldrgeb	r4, [r1, #-1]!
+		ldrb	lr, [r1, #-1]!
+		strgtb	r3, [r0, #-1]!
+		strgeb	r4, [r0, #-1]!
+		subs	r2, r2, ip
+		strb	lr, [r0, #-1]!
+		blt	8b
+		ands	ip, r1, #3
+		beq	1b
+
+10:		bic	r1, r1, #3
+		cmp	ip, #2
+		ldr	r3, [r1, #0]
+		beq	17f
+		blt	18f
+
+
+		.macro	backward_copy_shift push pull
+
+		subs	r2, r2, #28
+		blt	14f
+
+	CALGN(	ands	ip, r1, #31		)
+	CALGN(	rsb	ip, ip, #32		)
+	CALGN(	sbcnes	r4, ip, r2		)  @ C is always set here
+	CALGN(	subcc	r2, r2, ip		)
+	CALGN(	bcc	15f			)
+
+11:		stmfd	sp!, {r5 - r9}
+
+	PLD(	pld	[r1, #-4]		)
+	PLD(	subs	r2, r2, #96		)
+	PLD(	pld	[r1, #-32]		)
+	PLD(	blt	13f			)
+	PLD(	pld	[r1, #-64]		)
+	PLD(	pld	[r1, #-96]		)
+
+12:	PLD(	pld	[r1, #-128]		)
+13:		ldmdb   r1!, {r7, r8, r9, ip}
+		mov     lr, r3, push #\push
+		subs    r2, r2, #32
+		ldmdb   r1!, {r3, r4, r5, r6}
+		orr     lr, lr, ip, pull #\pull
+		mov     ip, ip, push #\push
+		orr     ip, ip, r9, pull #\pull
+		mov     r9, r9, push #\push
+		orr     r9, r9, r8, pull #\pull
+		mov     r8, r8, push #\push
+		orr     r8, r8, r7, pull #\pull
+		mov     r7, r7, push #\push
+		orr     r7, r7, r6, pull #\pull
+		mov     r6, r6, push #\push
+		orr     r6, r6, r5, pull #\pull
+		mov     r5, r5, push #\push
+		orr     r5, r5, r4, pull #\pull
+		mov     r4, r4, push #\push
+		orr     r4, r4, r3, pull #\pull
+		stmdb   r0!, {r4 - r9, ip, lr}
+		bge	12b
+	PLD(	cmn	r2, #96			)
+	PLD(	bge	13b			)
+
+		ldmfd	sp!, {r5 - r9}
+
+14:		ands	ip, r2, #28
+		beq	16f
+
+15:		mov     lr, r3, push #\push
+		ldr	r3, [r1, #-4]!
+		subs	ip, ip, #4
+		orr	lr, lr, r3, pull #\pull
+		str	lr, [r0, #-4]!
+		bgt	15b
+	CALGN(	cmp	r2, #0			)
+	CALGN(	bge	11b			)
+
+16:		add	r1, r1, #(\pull / 8)
+		b	8b
+
+		.endm
+
+
+		backward_copy_shift	push=8	pull=24
+
+17:		backward_copy_shift	push=16	pull=16
+
+18:		backward_copy_shift	push=24	pull=8
+
-- 
cgit v1.2.2


From fadab0943d1c5b652a66858bb99b204fedaad96b Mon Sep 17 00:00:00 2001
From: Nicolas Pitre <nico@cam.org>
Date: Tue, 1 Nov 2005 19:52:24 +0000
Subject: [ARM] 2948/1: new preemption safe copy_{to|from}_user implementation

Patch from Nicolas Pitre

This patch provides a preemption safe implementation of copy_to_user
and copy_from_user based on the copy template also used for memcpy.
It is enabled unconditionally when CONFIG_PREEMPT=y.  Otherwise if the
configured architecture is not ARMv3 then it is enabled as well as it
gives better performances at least on StrongARM and XScale cores.  If
ARMv3 is not too affected or if it doesn't matter too much then
uaccess.S could be removed altogether.

Signed-off-by: Nicolas Pitre <nico@cam.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/lib/Makefile         |  16 ++++++-
 arch/arm/lib/copy_from_user.S | 101 ++++++++++++++++++++++++++++++++++++++++++
 arch/arm/lib/copy_to_user.S   | 101 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 216 insertions(+), 2 deletions(-)
 create mode 100644 arch/arm/lib/copy_from_user.S
 create mode 100644 arch/arm/lib/copy_to_user.S

(limited to 'arch')

diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile
index 8f9770f1af..391f3ab3ff 100644
--- a/arch/arm/lib/Makefile
+++ b/arch/arm/lib/Makefile
@@ -9,13 +9,25 @@ lib-y		:= backtrace.o changebit.o csumipv6.o csumpartial.o   \
 		   copy_page.o delay.o findbit.o memchr.o memcpy.o    \
 		   memmove.o memset.o memzero.o setbit.o              \
 		   strncpy_from_user.o strnlen_user.o                 \
-		   strchr.o strrchr.o testchangebit.o                 \
-		   testclearbit.o testsetbit.o uaccess.o              \
+		   strchr.o strrchr.o                                 \
+		   testchangebit.o testclearbit.o testsetbit.o        \
 		   getuser.o putuser.o clear_user.o                   \
 		   ashldi3.o ashrdi3.o lshrdi3.o muldi3.o             \
 		   ucmpdi2.o lib1funcs.o div64.o sha1.o               \
 		   io-readsb.o io-writesb.o io-readsl.o io-writesl.o
 
+# the code in uaccess.S is not preemption safe and
+# probably faster on ARMv3 only
+ifeq ($CONFIG_PREEMPT,y)
+  lib-y	+= copy_from_user.o copy_to_user.o
+else
+ifneq ($(CONFIG_CPU_32v3),y)
+  lib-y	+= copy_from_user.o copy_to_user.o
+else
+  lib-y	+= uaccess.o
+endif
+endif
+
 ifeq ($(CONFIG_CPU_32v3),y)
   lib-y	+= io-readsw-armv3.o io-writesw-armv3.o
 else
diff --git a/arch/arm/lib/copy_from_user.S b/arch/arm/lib/copy_from_user.S
new file mode 100644
index 0000000000..7497393a0e
--- /dev/null
+++ b/arch/arm/lib/copy_from_user.S
@@ -0,0 +1,101 @@
+/*
+ *  linux/arch/arm/lib/copy_from_user.S
+ *
+ *  Author:	Nicolas Pitre
+ *  Created:	Sep 29, 2005
+ *  Copyright:	MontaVista Software, Inc.
+ *
+ *  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/linkage.h>
+#include <asm/assembler.h>
+
+/*
+ * Prototype:
+ *
+ *	size_t __arch_copy_from_user(void *to, const void *from, size_t n)
+ *
+ * Purpose:
+ *
+ *	copy a block to kernel memory from user memory
+ *
+ * Params:
+ *
+ *	to = kernel memory
+ *	from = user memory
+ *	n = number of bytes to copy
+ *
+ * Return value:
+ *
+ *	Number of bytes NOT copied.
+ */
+
+	.macro ldr1w ptr reg abort
+100:	ldrt \reg, [\ptr], #4
+	.section __ex_table, "a"
+	.long 100b, \abort
+	.previous
+	.endm
+
+	.macro ldr4w ptr reg1 reg2 reg3 reg4 abort
+	ldr1w \ptr, \reg1, \abort
+	ldr1w \ptr, \reg2, \abort
+	ldr1w \ptr, \reg3, \abort
+	ldr1w \ptr, \reg4, \abort
+	.endm
+
+	.macro ldr8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
+	ldr4w \ptr, \reg1, \reg2, \reg3, \reg4, \abort
+	ldr4w \ptr, \reg5, \reg6, \reg7, \reg8, \abort
+	.endm
+
+	.macro ldr1b ptr reg cond=al abort
+100:	ldr\cond\()bt \reg, [\ptr], #1
+	.section __ex_table, "a"
+	.long 100b, \abort
+	.previous
+	.endm
+
+	.macro str1w ptr reg abort
+	str \reg, [\ptr], #4
+	.endm
+
+	.macro str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
+	stmia \ptr!, {\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8}
+	.endm
+
+	.macro str1b ptr reg cond=al abort
+	str\cond\()b \reg, [\ptr], #1
+	.endm
+
+	.macro enter reg1 reg2
+	mov	r3, #0
+	stmdb	sp!, {r0, r2, r3, \reg1, \reg2}
+	.endm
+
+	.macro exit reg1 reg2
+	add	sp, sp, #8
+	ldmfd	sp!, {r0, \reg1, \reg2}
+	.endm
+
+	.text
+
+ENTRY(__arch_copy_from_user)
+
+#include "copy_template.S"
+
+	.section .fixup,"ax"
+	.align 0
+	copy_abort_preamble
+	ldmfd	sp!, {r1, r2}
+	sub	r3, r0, r1
+	rsb	r1, r3, r2
+	str	r1, [sp]
+	bl	__memzero
+	ldr	r0, [sp], #4
+	copy_abort_end
+	.previous
+
diff --git a/arch/arm/lib/copy_to_user.S b/arch/arm/lib/copy_to_user.S
new file mode 100644
index 0000000000..4a6d8ea140
--- /dev/null
+++ b/arch/arm/lib/copy_to_user.S
@@ -0,0 +1,101 @@
+/*
+ *  linux/arch/arm/lib/copy_to_user.S
+ *
+ *  Author:	Nicolas Pitre
+ *  Created:	Sep 29, 2005
+ *  Copyright:	MontaVista Software, Inc.
+ *
+ *  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/linkage.h>
+#include <asm/assembler.h>
+
+/*
+ * Prototype:
+ *
+ *	size_t __arch_copy_to_user(void *to, const void *from, size_t n)
+ *
+ * Purpose:
+ *
+ *	copy a block to user memory from kernel memory
+ *
+ * Params:
+ *
+ *	to = user memory
+ *	from = kernel memory
+ *	n = number of bytes to copy
+ *
+ * Return value:
+ *
+ *	Number of bytes NOT copied.
+ */
+
+	.macro ldr1w ptr reg abort
+	ldr \reg, [\ptr], #4
+	.endm
+
+	.macro ldr4w ptr reg1 reg2 reg3 reg4 abort
+	ldmia \ptr!, {\reg1, \reg2, \reg3, \reg4}
+	.endm
+
+	.macro ldr8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
+	ldmia \ptr!, {\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8}
+	.endm
+
+	.macro ldr1b ptr reg cond=al abort
+	ldr\cond\()b \reg, [\ptr], #1
+	.endm
+
+	.macro str1w ptr reg abort
+100:	strt \reg, [\ptr], #4
+	.section __ex_table, "a"
+	.long 100b, \abort
+	.previous
+	.endm
+
+	.macro str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
+	str1w \ptr, \reg1, \abort
+	str1w \ptr, \reg2, \abort
+	str1w \ptr, \reg3, \abort
+	str1w \ptr, \reg4, \abort
+	str1w \ptr, \reg5, \abort
+	str1w \ptr, \reg6, \abort
+	str1w \ptr, \reg7, \abort
+	str1w \ptr, \reg8, \abort
+	.endm
+
+	.macro str1b ptr reg cond=al abort
+100:	str\cond\()bt \reg, [\ptr], #1
+	.section __ex_table, "a"
+	.long 100b, \abort
+	.previous
+	.endm
+
+	.macro enter reg1 reg2
+	mov	r3, #0
+	stmdb	sp!, {r0, r2, r3, \reg1, \reg2}
+	.endm
+
+	.macro exit reg1 reg2
+	add	sp, sp, #8
+	ldmfd	sp!, {r0, \reg1, \reg2}
+	.endm
+
+	.text
+
+ENTRY(__arch_copy_to_user)
+
+#include "copy_template.S"
+
+	.section .fixup,"ax"
+	.align 0
+	copy_abort_preamble
+	ldmfd	sp!, {r1, r2, r3}
+	sub	r0, r0, r1
+	rsb	r0, r0, r2
+	copy_abort_end
+	.previous
+
-- 
cgit v1.2.2


From d01e8897fcf597f62d84f626fdced8d94c70deaf Mon Sep 17 00:00:00 2001
From: Lennert Buytenhek <buytenh@wantstofly.org>
Date: Tue, 1 Nov 2005 19:53:50 +0000
Subject: [ARM] 3052/1: add ixp2000 microcode loader

Patch from Lennert Buytenhek

This patch adds a microcode loader for the ixp2000 architecture.

The ixp2000 is an xscale-based CPU with a number of additional small
CPUs ('microengines') on die that can be programmed to do various
things.  Depending on the ixp2000 model, there are between 2 and 16
microengines.

This code provides an API that allows configuring the microengines,
loading code into them, and starting and stopping them and reading
out a number of status registers, and is used by the microengine
network driver that was recently announced to netdev.

Signed-off-by: Lennert Buytenhek <buytenh@wantstofly.org>
Signed-off-by: Deepak Saxena <dsaxena@plexity.net>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mach-ixp2000/Makefile  |   2 +-
 arch/arm/mach-ixp2000/uengine.c | 474 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 475 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm/mach-ixp2000/uengine.c

(limited to 'arch')

diff --git a/arch/arm/mach-ixp2000/Makefile b/arch/arm/mach-ixp2000/Makefile
index 1e6139d42a..9621aeb61f 100644
--- a/arch/arm/mach-ixp2000/Makefile
+++ b/arch/arm/mach-ixp2000/Makefile
@@ -1,7 +1,7 @@
 #
 # Makefile for the linux kernel.
 #
-obj-y			:= core.o pci.o
+obj-y			:= core.o pci.o uengine.o
 obj-m			:=
 obj-n			:=
 obj-			:=
diff --git a/arch/arm/mach-ixp2000/uengine.c b/arch/arm/mach-ixp2000/uengine.c
new file mode 100644
index 0000000000..43e234349d
--- /dev/null
+++ b/arch/arm/mach-ixp2000/uengine.c
@@ -0,0 +1,474 @@
+/*
+ * Generic library functions for the microengines found on the Intel
+ * IXP2000 series of network processors.
+ *
+ * Copyright (C) 2004, 2005 Lennert Buytenhek <buytenh@wantstofly.org>
+ * Dedicated to Marija Kulikova.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <asm/hardware.h>
+#include <asm/arch/ixp2000-regs.h>
+#include <asm/arch/uengine.h>
+#include <asm/io.h>
+
+#define USTORE_ADDRESS			0x000
+#define USTORE_DATA_LOWER		0x004
+#define USTORE_DATA_UPPER		0x008
+#define CTX_ENABLES			0x018
+#define CC_ENABLE			0x01c
+#define CSR_CTX_POINTER			0x020
+#define INDIRECT_CTX_STS		0x040
+#define ACTIVE_CTX_STS			0x044
+#define INDIRECT_CTX_SIG_EVENTS		0x048
+#define INDIRECT_CTX_WAKEUP_EVENTS	0x050
+#define NN_PUT				0x080
+#define NN_GET				0x084
+#define TIMESTAMP_LOW			0x0c0
+#define TIMESTAMP_HIGH			0x0c4
+#define T_INDEX_BYTE_INDEX		0x0f4
+#define LOCAL_CSR_STATUS		0x180
+
+u32 ixp2000_uengine_mask;
+
+static void *ixp2000_uengine_csr_area(int uengine)
+{
+	return ((void *)IXP2000_UENGINE_CSR_VIRT_BASE) + (uengine << 10);
+}
+
+/*
+ * LOCAL_CSR_STATUS=1 after a read or write to a microengine's CSR
+ * space means that the microengine we tried to access was also trying
+ * to access its own CSR space on the same clock cycle as we did.  When
+ * this happens, we lose the arbitration process by default, and the
+ * read or write we tried to do was not actually performed, so we try
+ * again until it succeeds.
+ */
+u32 ixp2000_uengine_csr_read(int uengine, int offset)
+{
+	void *uebase;
+	u32 *local_csr_status;
+	u32 *reg;
+	u32 value;
+
+	uebase = ixp2000_uengine_csr_area(uengine);
+
+	local_csr_status = (u32 *)(uebase + LOCAL_CSR_STATUS);
+	reg = (u32 *)(uebase + offset);
+	do {
+		value = ixp2000_reg_read(reg);
+	} while (ixp2000_reg_read(local_csr_status) & 1);
+
+	return value;
+}
+EXPORT_SYMBOL(ixp2000_uengine_csr_read);
+
+void ixp2000_uengine_csr_write(int uengine, int offset, u32 value)
+{
+	void *uebase;
+	u32 *local_csr_status;
+	u32 *reg;
+
+	uebase = ixp2000_uengine_csr_area(uengine);
+
+	local_csr_status = (u32 *)(uebase + LOCAL_CSR_STATUS);
+	reg = (u32 *)(uebase + offset);
+	do {
+		ixp2000_reg_write(reg, value);
+	} while (ixp2000_reg_read(local_csr_status) & 1);
+}
+EXPORT_SYMBOL(ixp2000_uengine_csr_write);
+
+void ixp2000_uengine_reset(u32 uengine_mask)
+{
+	ixp2000_reg_write(IXP2000_RESET1, uengine_mask & ixp2000_uengine_mask);
+	ixp2000_reg_write(IXP2000_RESET1, 0);
+}
+EXPORT_SYMBOL(ixp2000_uengine_reset);
+
+void ixp2000_uengine_set_mode(int uengine, u32 mode)
+{
+	/*
+	 * CTL_STR_PAR_EN: unconditionally enable parity checking on
+	 * control store.
+	 */
+	mode |= 0x10000000;
+	ixp2000_uengine_csr_write(uengine, CTX_ENABLES, mode);
+
+	/*
+	 * Enable updating of condition codes.
+	 */
+	ixp2000_uengine_csr_write(uengine, CC_ENABLE, 0x00002000);
+
+	/*
+	 * Initialise other per-microengine registers.
+	 */
+	ixp2000_uengine_csr_write(uengine, NN_PUT, 0x00);
+	ixp2000_uengine_csr_write(uengine, NN_GET, 0x00);
+	ixp2000_uengine_csr_write(uengine, T_INDEX_BYTE_INDEX, 0);
+}
+EXPORT_SYMBOL(ixp2000_uengine_set_mode);
+
+static int make_even_parity(u32 x)
+{
+	return hweight32(x) & 1;
+}
+
+static void ustore_write(int uengine, u64 insn)
+{
+	/*
+	 * Generate even parity for top and bottom 20 bits.
+	 */
+	insn |= (u64)make_even_parity((insn >> 20) & 0x000fffff) << 41;
+	insn |= (u64)make_even_parity(insn & 0x000fffff) << 40;
+
+	/*
+	 * Write to microstore.  The second write auto-increments
+	 * the USTORE_ADDRESS index register.
+	 */
+	ixp2000_uengine_csr_write(uengine, USTORE_DATA_LOWER, (u32)insn);
+	ixp2000_uengine_csr_write(uengine, USTORE_DATA_UPPER, (u32)(insn >> 32));
+}
+
+void ixp2000_uengine_load_microcode(int uengine, u8 *ucode, int insns)
+{
+	int i;
+
+	/*
+	 * Start writing to microstore at address 0.
+	 */
+	ixp2000_uengine_csr_write(uengine, USTORE_ADDRESS, 0x80000000);
+	for (i = 0; i < insns; i++) {
+		u64 insn;
+
+		insn = (((u64)ucode[0]) << 32) |
+			(((u64)ucode[1]) << 24) |
+			(((u64)ucode[2]) << 16) |
+			(((u64)ucode[3]) << 8) |
+			((u64)ucode[4]);
+		ucode += 5;
+
+		ustore_write(uengine, insn);
+	}
+
+	/*
+ 	 * Pad with a few NOPs at the end (to avoid the microengine
+	 * aborting as it prefetches beyond the last instruction), unless
+	 * we run off the end of the instruction store first, at which
+	 * point the address register will wrap back to zero.
+	 */
+	for (i = 0; i < 4; i++) {
+		u32 addr;
+
+		addr = ixp2000_uengine_csr_read(uengine, USTORE_ADDRESS);
+		if (addr == 0x80000000)
+			break;
+		ustore_write(uengine, 0xf0000c0300ULL);
+	}
+
+	/*
+	 * End programming.
+	 */
+	ixp2000_uengine_csr_write(uengine, USTORE_ADDRESS, 0x00000000);
+}
+EXPORT_SYMBOL(ixp2000_uengine_load_microcode);
+
+void ixp2000_uengine_init_context(int uengine, int context, int pc)
+{
+	/*
+	 * Select the right context for indirect access.
+	 */
+	ixp2000_uengine_csr_write(uengine, CSR_CTX_POINTER, context);
+
+	/*
+	 * Initialise signal masks to immediately go to Ready state.
+	 */
+	ixp2000_uengine_csr_write(uengine, INDIRECT_CTX_SIG_EVENTS, 1);
+	ixp2000_uengine_csr_write(uengine, INDIRECT_CTX_WAKEUP_EVENTS, 1);
+
+	/*
+	 * Set program counter.
+	 */
+	ixp2000_uengine_csr_write(uengine, INDIRECT_CTX_STS, pc);
+}
+EXPORT_SYMBOL(ixp2000_uengine_init_context);
+
+void ixp2000_uengine_start_contexts(int uengine, u8 ctx_mask)
+{
+	u32 mask;
+
+	/*
+	 * Enable the specified context to go to Executing state.
+	 */
+	mask = ixp2000_uengine_csr_read(uengine, CTX_ENABLES);
+	mask |= ctx_mask << 8;
+	ixp2000_uengine_csr_write(uengine, CTX_ENABLES, mask);
+}
+EXPORT_SYMBOL(ixp2000_uengine_start_contexts);
+
+void ixp2000_uengine_stop_contexts(int uengine, u8 ctx_mask)
+{
+	u32 mask;
+
+	/*
+	 * Disable the Ready->Executing transition.  Note that this
+	 * does not stop the context until it voluntarily yields.
+	 */
+	mask = ixp2000_uengine_csr_read(uengine, CTX_ENABLES);
+	mask &= ~(ctx_mask << 8);
+	ixp2000_uengine_csr_write(uengine, CTX_ENABLES, mask);
+}
+EXPORT_SYMBOL(ixp2000_uengine_stop_contexts);
+
+static int check_ixp_type(struct ixp2000_uengine_code *c)
+{
+	u32 product_id;
+	u32 rev;
+
+	product_id = ixp2000_reg_read(IXP2000_PRODUCT_ID);
+	if (((product_id >> 16) & 0x1f) != 0)
+		return 0;
+
+	switch ((product_id >> 8) & 0xff) {
+	case 0:		/* IXP2800 */
+		if (!(c->cpu_model_bitmask & 4))
+			return 0;
+		break;
+
+	case 1:		/* IXP2850 */
+		if (!(c->cpu_model_bitmask & 8))
+			return 0;
+		break;
+
+	case 2:		/* IXP2400 */
+		if (!(c->cpu_model_bitmask & 2))
+			return 0;
+		break;
+
+	default:
+		return 0;
+	}
+
+	rev = product_id & 0xff;
+	if (rev < c->cpu_min_revision || rev > c->cpu_max_revision)
+		return 0;
+
+	return 1;
+}
+
+static void generate_ucode(u8 *ucode, u32 *gpr_a, u32 *gpr_b)
+{
+	int offset;
+	int i;
+
+	offset = 0;
+
+	for (i = 0; i < 128; i++) {
+		u8 b3;
+		u8 b2;
+		u8 b1;
+		u8 b0;
+
+		b3 = (gpr_a[i] >> 24) & 0xff;
+		b2 = (gpr_a[i] >> 16) & 0xff;
+		b1 = (gpr_a[i] >> 8) & 0xff;
+		b0 = gpr_a[i] & 0xff;
+
+		// immed[@ai, (b1 << 8) | b0]
+		// 11110000 0000VVVV VVVV11VV VVVVVV00 1IIIIIII
+		ucode[offset++] = 0xf0;
+		ucode[offset++] = (b1 >> 4);
+		ucode[offset++] = (b1 << 4) | 0x0c | (b0 >> 6);
+		ucode[offset++] = (b0 << 2);
+		ucode[offset++] = 0x80 | i;
+
+		// immed_w1[@ai, (b3 << 8) | b2]
+		// 11110100 0100VVVV VVVV11VV VVVVVV00 1IIIIIII
+		ucode[offset++] = 0xf4;
+		ucode[offset++] = 0x40 | (b3 >> 4);
+		ucode[offset++] = (b3 << 4) | 0x0c | (b2 >> 6);
+		ucode[offset++] = (b2 << 2);
+		ucode[offset++] = 0x80 | i;
+	}
+
+	for (i = 0; i < 128; i++) {
+		u8 b3;
+		u8 b2;
+		u8 b1;
+		u8 b0;
+
+		b3 = (gpr_b[i] >> 24) & 0xff;
+		b2 = (gpr_b[i] >> 16) & 0xff;
+		b1 = (gpr_b[i] >> 8) & 0xff;
+		b0 = gpr_b[i] & 0xff;
+
+		// immed[@bi, (b1 << 8) | b0]
+		// 11110000 0000VVVV VVVV001I IIIIII11 VVVVVVVV
+		ucode[offset++] = 0xf0;
+		ucode[offset++] = (b1 >> 4);
+		ucode[offset++] = (b1 << 4) | 0x02 | (i >> 6);
+		ucode[offset++] = (i << 2) | 0x03;
+		ucode[offset++] = b0;
+
+		// immed_w1[@bi, (b3 << 8) | b2]
+		// 11110100 0100VVVV VVVV001I IIIIII11 VVVVVVVV
+		ucode[offset++] = 0xf4;
+		ucode[offset++] = 0x40 | (b3 >> 4);
+		ucode[offset++] = (b3 << 4) | 0x02 | (i >> 6);
+		ucode[offset++] = (i << 2) | 0x03;
+		ucode[offset++] = b2;
+	}
+
+	// ctx_arb[kill]
+	ucode[offset++] = 0xe0;
+	ucode[offset++] = 0x00;
+	ucode[offset++] = 0x01;
+	ucode[offset++] = 0x00;
+	ucode[offset++] = 0x00;
+}
+
+static int set_initial_registers(int uengine, struct ixp2000_uengine_code *c)
+{
+	int per_ctx_regs;
+	u32 *gpr_a;
+	u32 *gpr_b;
+	u8 *ucode;
+	int i;
+
+	gpr_a = kmalloc(128 * sizeof(u32), GFP_KERNEL);
+	gpr_b = kmalloc(128 * sizeof(u32), GFP_KERNEL);
+	ucode = kmalloc(513 * 5, GFP_KERNEL);
+	if (gpr_a == NULL || gpr_b == NULL || ucode == NULL) {
+		kfree(ucode);
+		kfree(gpr_b);
+		kfree(gpr_a);
+		return 1;
+	}
+
+	per_ctx_regs = 16;
+	if (c->uengine_parameters & IXP2000_UENGINE_4_CONTEXTS)
+		per_ctx_regs = 32;
+
+	memset(gpr_a, 0, sizeof(gpr_a));
+	memset(gpr_b, 0, sizeof(gpr_b));
+	for (i = 0; i < 256; i++) {
+		struct ixp2000_reg_value *r = c->initial_reg_values + i;
+		u32 *bank;
+		int inc;
+		int j;
+
+		if (r->reg == -1)
+			break;
+
+		bank = (r->reg & 0x400) ? gpr_b : gpr_a;
+		inc = (r->reg & 0x80) ? 128 : per_ctx_regs;
+
+		j = r->reg & 0x7f;
+		while (j < 128) {
+			bank[j] = r->value;
+			j += inc;
+		}
+	}
+
+	generate_ucode(ucode, gpr_a, gpr_b);
+	ixp2000_uengine_load_microcode(uengine, ucode, 513);
+	ixp2000_uengine_init_context(uengine, 0, 0);
+	ixp2000_uengine_start_contexts(uengine, 0x01);
+	for (i = 0; i < 100; i++) {
+		u32 status;
+
+		status = ixp2000_uengine_csr_read(uengine, ACTIVE_CTX_STS);
+		if (!(status & 0x80000000))
+			break;
+	}
+	ixp2000_uengine_stop_contexts(uengine, 0x01);
+
+	kfree(ucode);
+	kfree(gpr_b);
+	kfree(gpr_a);
+
+	return !!(i == 100);
+}
+
+int ixp2000_uengine_load(int uengine, struct ixp2000_uengine_code *c)
+{
+	int ctx;
+
+	if (!check_ixp_type(c))
+		return 1;
+
+	if (!(ixp2000_uengine_mask & (1 << uengine)))
+		return 1;
+
+	ixp2000_uengine_reset(1 << uengine);
+	ixp2000_uengine_set_mode(uengine, c->uengine_parameters);
+	if (set_initial_registers(uengine, c))
+		return 1;
+	ixp2000_uengine_load_microcode(uengine, c->insns, c->num_insns);
+
+	for (ctx = 0; ctx < 8; ctx++)
+		ixp2000_uengine_init_context(uengine, ctx, 0);
+
+	return 0;
+}
+EXPORT_SYMBOL(ixp2000_uengine_load);
+
+
+static int __init ixp2000_uengine_init(void)
+{
+	int uengine;
+	u32 value;
+
+	/*
+	 * Determine number of microengines present.
+	 */
+	switch ((ixp2000_reg_read(IXP2000_PRODUCT_ID) >> 8) & 0x1fff) {
+	case 0:		/* IXP2800 */
+	case 1:		/* IXP2850 */
+		ixp2000_uengine_mask = 0x00ff00ff;
+		break;
+
+	case 2:		/* IXP2400 */
+		ixp2000_uengine_mask = 0x000f000f;
+		break;
+
+	default:
+		printk(KERN_INFO "Detected unknown IXP2000 model (%.8x)\n",
+			(unsigned int)ixp2000_reg_read(IXP2000_PRODUCT_ID));
+		ixp2000_uengine_mask = 0x00000000;
+		break;
+	}
+
+	/*
+	 * Reset microengines.
+	 */
+	ixp2000_reg_write(IXP2000_RESET1, ixp2000_uengine_mask);
+	ixp2000_reg_write(IXP2000_RESET1, 0);
+
+	/*
+	 * Synchronise timestamp counters across all microengines.
+	 */
+	value = ixp2000_reg_read(IXP2000_MISC_CONTROL);
+	ixp2000_reg_write(IXP2000_MISC_CONTROL, value & ~0x80);
+	for (uengine = 0; uengine < 32; uengine++) {
+		if (ixp2000_uengine_mask & (1 << uengine)) {
+			ixp2000_uengine_csr_write(uengine, TIMESTAMP_LOW, 0);
+			ixp2000_uengine_csr_write(uengine, TIMESTAMP_HIGH, 0);
+		}
+	}
+	ixp2000_reg_write(IXP2000_MISC_CONTROL, value | 0x80);
+
+	return 0;
+}
+
+subsys_initcall(ixp2000_uengine_init);
-- 
cgit v1.2.2


From 73ee723e4c6d179c2e9496cc4caf160a18d95603 Mon Sep 17 00:00:00 2001
From: Deepak Saxena <dsaxena@plexity.net>
Date: Tue, 1 Nov 2005 22:32:12 +0000
Subject: [ARM] 3081/1: Remove GTWX5715 from ixp4xx_defconfig

Patch from Deepak Saxena

CONFIG_MACH_GTWX5715 hardcodes the machine type in head-xscale.S so we
can no longer boot on any other machine types. The proper fix would be
to remove the hardcoding, but that machine is an off-the-shelf system
and most users won't have access to the bootloader. :(

Signed-off-by: Deepak Saxena <dsaxena@plexity.net>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/configs/ixp4xx_defconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'arch')

diff --git a/arch/arm/configs/ixp4xx_defconfig b/arch/arm/configs/ixp4xx_defconfig
index c279e41ed1..f74c926beb 100644
--- a/arch/arm/configs/ixp4xx_defconfig
+++ b/arch/arm/configs/ixp4xx_defconfig
@@ -104,7 +104,7 @@ CONFIG_ARCH_IXCDP1100=y
 CONFIG_ARCH_PRPMC1100=y
 CONFIG_ARCH_IXDP4XX=y
 CONFIG_CPU_IXP46X=y
-CONFIG_MACH_GTWX5715=y
+# CONFIG_MACH_GTWX5715 is not set
 
 #
 # IXP4xx Options
-- 
cgit v1.2.2