Merge branches 'at91', 'ep93xx', 'errata', 'footbridge', 'fncpy', 'gemini', 'irqdata', 'pm', 'sh', 'smp', 'spear', 'ux500' and 'via' into devel
diff --git a/Documentation/arm/SH-Mobile/Makefile b/Documentation/arm/SH-Mobile/Makefile
new file mode 100644
index 0000000..8771d83
--- /dev/null
+++ b/Documentation/arm/SH-Mobile/Makefile
@@ -0,0 +1,8 @@
+BIN := vrl4
+
+.PHONY: all
+all: $(BIN)
+
+.PHONY: clean
+clean:
+	rm -f *.o $(BIN)
diff --git a/Documentation/arm/SH-Mobile/vrl4.c b/Documentation/arm/SH-Mobile/vrl4.c
new file mode 100644
index 0000000..e8a1913
--- /dev/null
+++ b/Documentation/arm/SH-Mobile/vrl4.c
@@ -0,0 +1,169 @@
+/*
+ * vrl4 format generator
+ *
+ * Copyright (C) 2010 Simon Horman
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+/*
+ * usage: vrl4 < zImage > out
+ *	  dd if=out of=/dev/sdx bs=512 seek=1 # Write the image to sector 1
+ *
+ * Reads a zImage from stdin and writes a vrl4 image to stdout.
+ * In practice this means writing a padded vrl4 header to stdout followed
+ * by the zImage.
+ *
+ * The padding places the zImage at ALIGN bytes into the output.
+ * The vrl4 uses ALIGN + START_BASE as the start_address.
+ * This is where the mask ROM will jump to after verifying the header.
+ *
+ * The header sets copy_size to min(sizeof(zImage), MAX_BOOT_PROG_LEN) + ALIGN.
+ * That is, the mask ROM will load the padded header (ALIGN bytes)
+ * And then MAX_BOOT_PROG_LEN bytes of the image, or the entire image,
+ * whichever is smaller.
+ *
+ * The zImage is not modified in any way.
+ */
+
+#define _BSD_SOURCE
+#include <endian.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <errno.h>
+
+struct hdr {
+	uint32_t magic1;
+	uint32_t reserved1;
+	uint32_t magic2;
+	uint32_t reserved2;
+	uint16_t copy_size;
+	uint16_t boot_options;
+	uint32_t reserved3;
+	uint32_t start_address;
+	uint32_t reserved4;
+	uint32_t reserved5;
+	char     reserved6[308];
+};
+
+#define DECLARE_HDR(h)					\
+	struct hdr (h) = {				\
+		.magic1 =	htole32(0xea000000),	\
+		.reserved1 =	htole32(0x56),		\
+		.magic2 =	htole32(0xe59ff008),	\
+		.reserved3 =	htole16(0x1) }
+
+/* Align to 512 bytes, the MMCIF sector size */
+#define ALIGN_BITS	9
+#define ALIGN		(1 << ALIGN_BITS)
+
+#define START_BASE	0xe55b0000
+
+/*
+ * With an alignment of 512 the header uses the first sector.
+ * There is a 128 sector (64kbyte) limit on the data loaded by the mask ROM.
+ * So there are 127 sectors left for the boot programme. But in practice
+ * Only a small portion of a zImage is needed, 16 sectors should be more
+ * than enough.
+ *
+ * Note that this sets how much of the zImage is copied by the mask ROM.
+ * The entire zImage is present after the header and is loaded
+ * by the code in the boot program (which is the first portion of the zImage).
+ */
+#define	MAX_BOOT_PROG_LEN (16 * 512)
+
+#define ROUND_UP(x)	((x + ALIGN - 1) & ~(ALIGN - 1))
+
+ssize_t do_read(int fd, void *buf, size_t count)
+{
+	size_t offset = 0;
+	ssize_t l;
+
+	while (offset < count) {
+		l = read(fd, buf + offset, count - offset);
+		if (!l)
+			break;
+		if (l < 0) {
+			if (errno == EAGAIN || errno == EWOULDBLOCK)
+				continue;
+			perror("read");
+			return -1;
+		}
+		offset += l;
+	}
+
+	return offset;
+}
+
+ssize_t do_write(int fd, const void *buf, size_t count)
+{
+	size_t offset = 0;
+	ssize_t l;
+
+	while (offset < count) {
+		l = write(fd, buf + offset, count - offset);
+		if (l < 0) {
+			if (errno == EAGAIN || errno == EWOULDBLOCK)
+				continue;
+			perror("write");
+			return -1;
+		}
+		offset += l;
+	}
+
+	return offset;
+}
+
+ssize_t write_zero(int fd, size_t len)
+{
+	size_t i = len;
+
+	while (i--) {
+		const char x = 0;
+		if (do_write(fd, &x, 1) < 0)
+			return -1;
+	}
+
+	return len;
+}
+
+int main(void)
+{
+	DECLARE_HDR(hdr);
+	char boot_program[MAX_BOOT_PROG_LEN];
+	size_t aligned_hdr_len, alligned_prog_len;
+	ssize_t prog_len;
+
+	prog_len = do_read(0, boot_program, sizeof(boot_program));
+	if (prog_len <= 0)
+		return -1;
+
+	aligned_hdr_len = ROUND_UP(sizeof(hdr));
+	hdr.start_address = htole32(START_BASE + aligned_hdr_len);
+	alligned_prog_len = ROUND_UP(prog_len);
+	hdr.copy_size = htole16(aligned_hdr_len + alligned_prog_len);
+
+	if (do_write(1, &hdr, sizeof(hdr)) < 0)
+		return -1;
+	if (write_zero(1, aligned_hdr_len - sizeof(hdr)) < 0)
+		return -1;
+
+	if (do_write(1, boot_program, prog_len) < 0)
+		return 1;
+
+	/* Write out the rest of the kernel */
+	while (1) {
+		prog_len = do_read(0, boot_program, sizeof(boot_program));
+		if (prog_len < 0)
+			return 1;
+		if (prog_len == 0)
+			break;
+		if (do_write(1, boot_program, prog_len) < 0)
+			return 1;
+	}
+
+	return 0;
+}
diff --git a/Documentation/arm/SH-Mobile/zboot-rom-mmcif.txt b/Documentation/arm/SH-Mobile/zboot-rom-mmcif.txt
new file mode 100644
index 0000000..efff8ae
--- /dev/null
+++ b/Documentation/arm/SH-Mobile/zboot-rom-mmcif.txt
@@ -0,0 +1,29 @@
+ROM-able zImage boot from MMC
+-----------------------------
+
+An ROM-able zImage compiled with ZBOOT_ROM_MMCIF may be written to MMC and
+SuperH Mobile ARM will to boot directly from the MMCIF hardware block.
+
+This is achieved by the mask ROM loading the first portion of the image into
+MERAM and then jumping to it. This portion contains loader code which
+copies the entire image to SDRAM and jumps to it. From there the zImage
+boot code proceeds as normal, uncompressing the image into its final
+location and then jumping to it.
+
+This code has been tested on an AP4EB board using the developer 1A eMMC
+boot mode which is configured using the following jumper settings.
+The board used for testing required a patched mask ROM in order for
+this mode to function.
+
+   8 7 6 5 4 3 2 1
+   x|x|x|x|x| |x|
+S4 -+-+-+-+-+-+-+-
+    | | | | |x| |x on
+
+The zImage must be written to the MMC card at sector 1 (512 bytes) in
+vrl4 format. A utility vrl4 is supplied to accomplish this.
+
+e.g.
+	vrl4 < zImage | dd of=/dev/sdX bs=512 seek=1
+
+A dual-voltage MMC 4.0 card was used for testing.
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 166efa2..38bf684 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -346,7 +346,7 @@
 	bool "FootBridge"
 	select CPU_SA110
 	select FOOTBRIDGE
-	select ARCH_USES_GETTIMEOFFSET
+	select GENERIC_CLOCKEVENTS
 	help
 	  Support for systems based on the DC21285 companion chip
 	  ("FootBridge"), such as the Simtec CATS and the Rebel NetWinder.
@@ -875,6 +875,16 @@
 	help
 	  Support for ST's SPEAr platform (SPEAr3xx, SPEAr6xx and SPEAr13xx).
 
+config ARCH_VT8500
+	bool "VIA/WonderMedia 85xx"
+	select CPU_ARM926T
+	select GENERIC_GPIO
+	select ARCH_HAS_CPUFREQ
+	select GENERIC_CLOCKEVENTS
+	select ARCH_REQUIRE_GPIOLIB
+	select HAVE_PWM
+	help
+	  Support for VIA/WonderMedia VT8500/WM85xx System-on-Chip.
 endchoice
 
 #
@@ -1007,6 +1017,8 @@
 
 source "arch/arm/mach-vexpress/Kconfig"
 
+source "arch/arm/mach-vt8500/Kconfig"
+
 source "arch/arm/mach-w90x900/Kconfig"
 
 # Definitions to make life easier
@@ -1202,6 +1214,28 @@
 	  This has the same effect as the cache sync operation: store buffer
 	  drain and waiting for all buffers empty.
 
+config ARM_ERRATA_754322
+	bool "ARM errata: possible faulty MMU translations following an ASID switch"
+	depends on CPU_V7
+	help
+	  This option enables the workaround for the 754322 Cortex-A9 (r2p*,
+	  r3p*) erratum. A speculative memory access may cause a page table walk
+	  which starts prior to an ASID switch but completes afterwards. This
+	  can populate the micro-TLB with a stale entry which may be hit with
+	  the new ASID. This workaround places two dsb instructions in the mm
+	  switching code so that no page table walks can cross the ASID switch.
+
+config ARM_ERRATA_754327
+	bool "ARM errata: no automatic Store Buffer drain"
+	depends on CPU_V7 && SMP
+	help
+	  This option enables the workaround for the 754327 Cortex-A9 (prior to
+	  r2p0) erratum. The Store Buffer does not have any automatic draining
+	  mechanism and therefore a livelock may occur if an external agent
+	  continuously polls a memory location waiting to observe an update.
+	  This workaround defines cpu_relax() as smp_mb(), preventing correctly
+	  written polling loops from denying visibility of updates to memory.
+
 endmenu
 
 source "arch/arm/common/Kconfig"
@@ -1644,6 +1678,18 @@
 	  Say Y here if you intend to execute your compressed kernel image
 	  (zImage) directly from ROM or flash.  If unsure, say N.
 
+config ZBOOT_ROM_MMCIF
+	bool "Include MMCIF loader in zImage (EXPERIMENTAL)"
+	depends on ZBOOT_ROM && ARCH_SH7372 && EXPERIMENTAL
+	help
+	  Say Y here to include experimental MMCIF loading code in the
+	  ROM-able zImage. With this enabled it is possible to write the
+	  the ROM-able zImage kernel image to an MMC card and boot the
+	  kernel straight from the reset vector. At reset the processor
+	  Mask ROM will load the first part of the the ROM-able zImage
+	  which in turn loads the rest the kernel image to RAM using the
+	  MMCIF hardware block.
+
 config CMDLINE
 	string "Default kernel command string"
 	default ""
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 6f7b292..cd56c91 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -190,6 +190,7 @@
 machine-$(CONFIG_ARCH_U8500)		:= ux500
 machine-$(CONFIG_ARCH_VERSATILE)	:= versatile
 machine-$(CONFIG_ARCH_VEXPRESS)		:= vexpress
+machine-$(CONFIG_ARCH_VT8500)		:= vt8500
 machine-$(CONFIG_ARCH_W90X900)		:= w90x900
 machine-$(CONFIG_ARCH_NUC93X)		:= nuc93x
 machine-$(CONFIG_FOOTBRIDGE)		:= footbridge
diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile
index 0a8f748..5f3a161 100644
--- a/arch/arm/boot/compressed/Makefile
+++ b/arch/arm/boot/compressed/Makefile
@@ -4,9 +4,20 @@
 # create a compressed vmlinuz image from the original vmlinux
 #
 
+OBJS		=
+
+# Ensure that mmcif loader code appears early in the image
+# to minimise that number of bocks that have to be read in
+# order to load it.
+ifeq ($(CONFIG_ZBOOT_ROM_MMCIF),y)
+ifeq ($(CONFIG_ARCH_SH7372),y)
+OBJS		+= mmcif-sh7372.o
+endif
+endif
+
 AFLAGS_head.o += -DTEXT_OFFSET=$(TEXT_OFFSET)
 HEAD	= head.o
-OBJS	= misc.o decompress.o
+OBJS	+= misc.o decompress.o
 FONTC	= $(srctree)/drivers/video/console/font_acorn_8x8.c
 
 #
@@ -29,6 +40,10 @@
 OBJS		+= head-sa1100.o
 endif
 
+ifeq ($(CONFIG_ARCH_VT8500),y)
+OBJS		+= head-vt8500.o
+endif
+
 ifeq ($(CONFIG_CPU_XSCALE),y)
 OBJS		+= head-xscale.o
 endif
diff --git a/arch/arm/boot/compressed/head-shmobile.S b/arch/arm/boot/compressed/head-shmobile.S
index 30973b7..c943d2e 100644
--- a/arch/arm/boot/compressed/head-shmobile.S
+++ b/arch/arm/boot/compressed/head-shmobile.S
@@ -25,6 +25,36 @@
 	/* load board-specific initialization code */
 #include <mach/zboot.h>
 
+#ifdef CONFIG_ZBOOT_ROM_MMCIF
+	/* Load image from MMC */
+	adr	sp, __tmp_stack + 128
+	ldr	r0, __image_start
+	ldr	r1, __image_end
+	subs	r1, r1, r0
+	ldr	r0, __load_base
+	bl	mmcif_loader
+
+	/* Jump to loaded code */
+	ldr	r0, __loaded
+	ldr	r1, __image_start
+	sub	r0, r0, r1
+	ldr	r1, __load_base
+	add	pc, r0, r1
+
+__image_start:
+	.long	_start
+__image_end:
+	.long	_got_end
+__load_base:
+	.long	CONFIG_MEMORY_START + 0x02000000 @ Load at 32Mb into SDRAM
+__loaded:
+	.long	__continue
+	.align
+__tmp_stack:
+	.space	128
+__continue:
+#endif /* CONFIG_ZBOOT_ROM_MMCIF */
+
 	b	1f
 __atags:@ tag #1
 	.long	12			@ tag->hdr.size = tag_size(tag_core);
diff --git a/arch/arm/boot/compressed/head-vt8500.S b/arch/arm/boot/compressed/head-vt8500.S
new file mode 100644
index 0000000..1dc1e21
--- /dev/null
+++ b/arch/arm/boot/compressed/head-vt8500.S
@@ -0,0 +1,46 @@
+/*
+ * linux/arch/arm/boot/compressed/head-vt8500.S
+ *
+ * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
+ *
+ * VIA VT8500 specific tweaks. This is merged into head.S by the linker.
+ *
+ */
+
+#include <linux/linkage.h>
+#include <asm/mach-types.h>
+
+		.section        ".start", "ax"
+
+__VT8500_start:
+	@ Compare the SCC ID register against a list of known values
+	ldr	r1, .SCCID
+	ldr	r3, [r1]
+
+	@ VT8500 override
+	ldr	r4, .VT8500SCC
+	cmp	r3, r4
+	ldreq	r7, .ID_BV07
+	beq	.Lendvt8500
+
+	@ WM8505 override
+	ldr	r4, .WM8505SCC
+	cmp	r3, r4
+	ldreq	r7, .ID_8505
+	beq	.Lendvt8500
+
+	@ Otherwise, leave the bootloader's machine id untouched
+
+.SCCID:
+	.word	0xd8120000
+.VT8500SCC:
+	.word	0x34000102
+.WM8505SCC:
+	.word	0x34260103
+
+.ID_BV07:
+	.word	MACH_TYPE_BV07
+.ID_8505:
+	.word	MACH_TYPE_WM8505_7IN_NETBOOK
+
+.Lendvt8500:
diff --git a/arch/arm/boot/compressed/mmcif-sh7372.c b/arch/arm/boot/compressed/mmcif-sh7372.c
new file mode 100644
index 0000000..e6180af
--- /dev/null
+++ b/arch/arm/boot/compressed/mmcif-sh7372.c
@@ -0,0 +1,87 @@
+/*
+ * sh7372 MMCIF loader
+ *
+ * Copyright (C) 2010 Magnus Damm
+ * Copyright (C) 2010 Simon Horman
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/mmc/sh_mmcif.h>
+#include <mach/mmcif.h>
+
+#define MMCIF_BASE      (void __iomem *)0xe6bd0000
+
+#define PORT84CR	(void __iomem *)0xe6050054
+#define PORT85CR	(void __iomem *)0xe6050055
+#define PORT86CR	(void __iomem *)0xe6050056
+#define PORT87CR	(void __iomem *)0xe6050057
+#define PORT88CR	(void __iomem *)0xe6050058
+#define PORT89CR	(void __iomem *)0xe6050059
+#define PORT90CR	(void __iomem *)0xe605005a
+#define PORT91CR	(void __iomem *)0xe605005b
+#define PORT92CR	(void __iomem *)0xe605005c
+#define PORT99CR	(void __iomem *)0xe6050063
+
+#define SMSTPCR3	(void __iomem *)0xe615013c
+
+/* SH7372 specific MMCIF loader
+ *
+ * loads the zImage from an MMC card starting from block 1.
+ *
+ * The image must be start with a vrl4 header and
+ * the zImage must start at offset 512 of the image. That is,
+ * at block 2 (=byte 1024) on the media
+ *
+ * Use the following line to write the vrl4 formated zImage
+ * to an MMC card
+ * # dd if=vrl4.out of=/dev/sdx bs=512 seek=1
+ */
+asmlinkage void mmcif_loader(unsigned char *buf, unsigned long len)
+{
+	mmcif_init_progress();
+	mmcif_update_progress(MMCIF_PROGRESS_ENTER);
+
+	/* Initialise MMC
+	 * registers: PORT84CR-PORT92CR
+	 *            (MMCD0_0-MMCD0_7,MMCCMD0 Control)
+	 * value: 0x04 - select function 4
+	 */
+	 __raw_writeb(0x04, PORT84CR);
+	 __raw_writeb(0x04, PORT85CR);
+	 __raw_writeb(0x04, PORT86CR);
+	 __raw_writeb(0x04, PORT87CR);
+	 __raw_writeb(0x04, PORT88CR);
+	 __raw_writeb(0x04, PORT89CR);
+	 __raw_writeb(0x04, PORT90CR);
+	 __raw_writeb(0x04, PORT91CR);
+	 __raw_writeb(0x04, PORT92CR);
+
+	/* Initialise MMC
+	 * registers: PORT99CR (MMCCLK0 Control)
+	 * value: 0x10 | 0x04 - enable output | select function 4
+	 */
+	__raw_writeb(0x14, PORT99CR);
+
+	/* Enable clock to MMC hardware block */
+	__raw_writel(__raw_readl(SMSTPCR3) & ~(1 << 12), SMSTPCR3);
+
+	mmcif_update_progress(MMCIF_PROGRESS_INIT);
+
+	/* setup MMCIF hardware */
+	sh_mmcif_boot_init(MMCIF_BASE);
+
+	mmcif_update_progress(MMCIF_PROGRESS_LOAD);
+
+	/* load kernel via MMCIF interface */
+	sh_mmcif_boot_do_read(MMCIF_BASE, 2, /* Kernel is at block 2 */
+			      (len + SH_MMCIF_BBS - 1) / SH_MMCIF_BBS, buf);
+
+
+	/* Disable clock to MMC hardware block */
+	__raw_writel(__raw_readl(SMSTPCR3) & (1 << 12), SMSTPCR3);
+
+	mmcif_update_progress(MMCIF_PROGRESS_DONE);
+}
diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h
index 3acd8fa..18a5664 100644
--- a/arch/arm/include/asm/cacheflush.h
+++ b/arch/arm/include/asm/cacheflush.h
@@ -12,7 +12,7 @@
 
 #include <linux/mm.h>
 
-#include <asm/glue.h>
+#include <asm/glue-cache.h>
 #include <asm/shmparam.h>
 #include <asm/cachetype.h>
 #include <asm/outercache.h>
@@ -20,123 +20,6 @@
 #define CACHE_COLOUR(vaddr)	((vaddr & (SHMLBA - 1)) >> PAGE_SHIFT)
 
 /*
- *	Cache Model
- *	===========
- */
-#undef _CACHE
-#undef MULTI_CACHE
-
-#if defined(CONFIG_CPU_CACHE_V3)
-# ifdef _CACHE
-#  define MULTI_CACHE 1
-# else
-#  define _CACHE v3
-# endif
-#endif
-
-#if defined(CONFIG_CPU_CACHE_V4)
-# ifdef _CACHE
-#  define MULTI_CACHE 1
-# else
-#  define _CACHE v4
-# endif
-#endif
-
-#if defined(CONFIG_CPU_ARM920T) || defined(CONFIG_CPU_ARM922T) || \
-    defined(CONFIG_CPU_ARM925T) || defined(CONFIG_CPU_ARM1020) || \
-    defined(CONFIG_CPU_ARM1026)
-# define MULTI_CACHE 1
-#endif
-
-#if defined(CONFIG_CPU_FA526)
-# ifdef _CACHE
-#  define MULTI_CACHE 1
-# else
-#  define _CACHE fa
-# endif
-#endif
-
-#if defined(CONFIG_CPU_ARM926T)
-# ifdef _CACHE
-#  define MULTI_CACHE 1
-# else
-#  define _CACHE arm926
-# endif
-#endif
-
-#if defined(CONFIG_CPU_ARM940T)
-# ifdef _CACHE
-#  define MULTI_CACHE 1
-# else
-#  define _CACHE arm940
-# endif
-#endif
-
-#if defined(CONFIG_CPU_ARM946E)
-# ifdef _CACHE
-#  define MULTI_CACHE 1
-# else
-#  define _CACHE arm946
-# endif
-#endif
-
-#if defined(CONFIG_CPU_CACHE_V4WB)
-# ifdef _CACHE
-#  define MULTI_CACHE 1
-# else
-#  define _CACHE v4wb
-# endif
-#endif
-
-#if defined(CONFIG_CPU_XSCALE)
-# ifdef _CACHE
-#  define MULTI_CACHE 1
-# else
-#  define _CACHE xscale
-# endif
-#endif
-
-#if defined(CONFIG_CPU_XSC3)
-# ifdef _CACHE
-#  define MULTI_CACHE 1
-# else
-#  define _CACHE xsc3
-# endif
-#endif
-
-#if defined(CONFIG_CPU_MOHAWK)
-# ifdef _CACHE
-#  define MULTI_CACHE 1
-# else
-#  define _CACHE mohawk
-# endif
-#endif
-
-#if defined(CONFIG_CPU_FEROCEON)
-# define MULTI_CACHE 1
-#endif
-
-#if defined(CONFIG_CPU_V6)
-//# ifdef _CACHE
-#  define MULTI_CACHE 1
-//# else
-//#  define _CACHE v6
-//# endif
-#endif
-
-#if defined(CONFIG_CPU_V7)
-//# ifdef _CACHE
-#  define MULTI_CACHE 1
-//# else
-//#  define _CACHE v7
-//# endif
-#endif
-
-#if !defined(_CACHE) && !defined(MULTI_CACHE)
-#error Unknown cache maintainence model
-#endif
-
-/*
  * This flag is used to indicate that the page pointed to by a pte is clean
  * and does not require cleaning before returning it to the user.
  */
@@ -249,19 +132,11 @@
  * visible to the CPU.
  */
 #define dmac_map_area			cpu_cache.dma_map_area
-#define dmac_unmap_area		cpu_cache.dma_unmap_area
+#define dmac_unmap_area			cpu_cache.dma_unmap_area
 #define dmac_flush_range		cpu_cache.dma_flush_range
 
 #else
 
-#define __cpuc_flush_icache_all		__glue(_CACHE,_flush_icache_all)
-#define __cpuc_flush_kern_all		__glue(_CACHE,_flush_kern_cache_all)
-#define __cpuc_flush_user_all		__glue(_CACHE,_flush_user_cache_all)
-#define __cpuc_flush_user_range		__glue(_CACHE,_flush_user_cache_range)
-#define __cpuc_coherent_kern_range	__glue(_CACHE,_coherent_kern_range)
-#define __cpuc_coherent_user_range	__glue(_CACHE,_coherent_user_range)
-#define __cpuc_flush_dcache_area	__glue(_CACHE,_flush_kern_dcache_area)
-
 extern void __cpuc_flush_icache_all(void);
 extern void __cpuc_flush_kern_all(void);
 extern void __cpuc_flush_user_all(void);
@@ -276,10 +151,6 @@
  * is visible to DMA, or data written by DMA to system memory is
  * visible to the CPU.
  */
-#define dmac_map_area			__glue(_CACHE,_dma_map_area)
-#define dmac_unmap_area		__glue(_CACHE,_dma_unmap_area)
-#define dmac_flush_range		__glue(_CACHE,_dma_flush_range)
-
 extern void dmac_map_area(const void *, size_t, int);
 extern void dmac_unmap_area(const void *, size_t, int);
 extern void dmac_flush_range(const void *, const void *);
diff --git a/arch/arm/include/asm/cpu-multi32.h b/arch/arm/include/asm/cpu-multi32.h
deleted file mode 100644
index e2b5b0b..0000000
--- a/arch/arm/include/asm/cpu-multi32.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- *  arch/arm/include/asm/cpu-multi32.h
- *
- *  Copyright (C) 2000 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 <asm/page.h>
-
-struct mm_struct;
-
-/*
- * Don't change this structure - ASM code
- * relies on it.
- */
-extern struct processor {
-	/* MISC
-	 * get data abort address/flags
-	 */
-	void (*_data_abort)(unsigned long pc);
-	/*
-	 * Retrieve prefetch fault address
-	 */
-	unsigned long (*_prefetch_abort)(unsigned long lr);
-	/*
-	 * Set up any processor specifics
-	 */
-	void (*_proc_init)(void);
-	/*
-	 * Disable any processor specifics
-	 */
-	void (*_proc_fin)(void);
-	/*
-	 * Special stuff for a reset
-	 */
-	void (*reset)(unsigned long addr) __attribute__((noreturn));
-	/*
-	 * Idle the processor
-	 */
-	int (*_do_idle)(void);
-	/*
-	 * Processor architecture specific
-	 */
-	/*
-	 * clean a virtual address range from the
-	 * D-cache without flushing the cache.
-	 */
-	void (*dcache_clean_area)(void *addr, int size);
-
-	/*
-	 * Set the page table
-	 */
-	void (*switch_mm)(unsigned long pgd_phys, struct mm_struct *mm);
-	/*
-	 * Set a possibly extended PTE.  Non-extended PTEs should
-	 * ignore 'ext'.
-	 */
-	void (*set_pte_ext)(pte_t *ptep, pte_t pte, unsigned int ext);
-} processor;
-
-#define cpu_proc_init()			processor._proc_init()
-#define cpu_proc_fin()			processor._proc_fin()
-#define cpu_reset(addr)			processor.reset(addr)
-#define cpu_do_idle()			processor._do_idle()
-#define cpu_dcache_clean_area(addr,sz)	processor.dcache_clean_area(addr,sz)
-#define cpu_set_pte_ext(ptep,pte,ext)	processor.set_pte_ext(ptep,pte,ext)
-#define cpu_do_switch_mm(pgd,mm)	processor.switch_mm(pgd,mm)
diff --git a/arch/arm/include/asm/cpu-single.h b/arch/arm/include/asm/cpu-single.h
deleted file mode 100644
index f073a6d2a..0000000
--- a/arch/arm/include/asm/cpu-single.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- *  arch/arm/include/asm/cpu-single.h
- *
- *  Copyright (C) 2000 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.
- */
-/*
- * Single CPU
- */
-#ifdef __STDC__
-#define __catify_fn(name,x)	name##x
-#else
-#define __catify_fn(name,x)	name/**/x
-#endif
-#define __cpu_fn(name,x)	__catify_fn(name,x)
-
-/*
- * If we are supporting multiple CPUs, then we must use a table of
- * function pointers for this lot.  Otherwise, we can optimise the
- * table away.
- */
-#define cpu_proc_init			__cpu_fn(CPU_NAME,_proc_init)
-#define cpu_proc_fin			__cpu_fn(CPU_NAME,_proc_fin)
-#define cpu_reset			__cpu_fn(CPU_NAME,_reset)
-#define cpu_do_idle			__cpu_fn(CPU_NAME,_do_idle)
-#define cpu_dcache_clean_area		__cpu_fn(CPU_NAME,_dcache_clean_area)
-#define cpu_do_switch_mm		__cpu_fn(CPU_NAME,_switch_mm)
-#define cpu_set_pte_ext			__cpu_fn(CPU_NAME,_set_pte_ext)
-
-#include <asm/page.h>
-
-struct mm_struct;
-
-/* declare all the functions as extern */
-extern void cpu_proc_init(void);
-extern void cpu_proc_fin(void);
-extern int cpu_do_idle(void);
-extern void cpu_dcache_clean_area(void *, int);
-extern void cpu_do_switch_mm(unsigned long pgd_phys, struct mm_struct *mm);
-extern void cpu_set_pte_ext(pte_t *ptep, pte_t pte, unsigned int ext);
-extern void cpu_reset(unsigned long addr) __attribute__((noreturn));
diff --git a/arch/arm/include/asm/fncpy.h b/arch/arm/include/asm/fncpy.h
new file mode 100644
index 0000000..de53547
--- /dev/null
+++ b/arch/arm/include/asm/fncpy.h
@@ -0,0 +1,94 @@
+/*
+ * arch/arm/include/asm/fncpy.h - helper macros for function body copying
+ *
+ * Copyright (C) 2011 Linaro 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.
+ *
+ * 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
+ */
+
+/*
+ * These macros are intended for use when there is a need to copy a low-level
+ * function body into special memory.
+ *
+ * For example, when reconfiguring the SDRAM controller, the code doing the
+ * reconfiguration may need to run from SRAM.
+ *
+ * NOTE: that the copied function body must be entirely self-contained and
+ * position-independent in order for this to work properly.
+ *
+ * NOTE: in order for embedded literals and data to get referenced correctly,
+ * the alignment of functions must be preserved when copying.  To ensure this,
+ * the source and destination addresses for fncpy() must be aligned to a
+ * multiple of 8 bytes: you will be get a BUG() if this condition is not met.
+ * You will typically need a ".align 3" directive in the assembler where the
+ * function to be copied is defined, and ensure that your allocator for the
+ * destination buffer returns 8-byte-aligned pointers.
+ *
+ * Typical usage example:
+ *
+ * extern int f(args);
+ * extern uint32_t size_of_f;
+ * int (*copied_f)(args);
+ * void *sram_buffer;
+ *
+ * copied_f = fncpy(sram_buffer, &f, size_of_f);
+ *
+ * ... later, call the function: ...
+ *
+ * copied_f(args);
+ *
+ * The size of the function to be copied can't be determined from C:
+ * this must be determined by other means, such as adding assmbler directives
+ * in the file where f is defined.
+ */
+
+#ifndef __ASM_FNCPY_H
+#define __ASM_FNCPY_H
+
+#include <linux/types.h>
+#include <linux/string.h>
+
+#include <asm/bug.h>
+#include <asm/cacheflush.h>
+
+/*
+ * Minimum alignment requirement for the source and destination addresses
+ * for function copying.
+ */
+#define FNCPY_ALIGN 8
+
+#define fncpy(dest_buf, funcp, size) ({					\
+	uintptr_t __funcp_address;					\
+	typeof(funcp) __result;						\
+									\
+	asm("" : "=r" (__funcp_address) : "0" (funcp));			\
+									\
+	/*								\
+	 * Ensure alignment of source and destination addresses,	\
+	 * disregarding the function's Thumb bit:			\
+	 */								\
+	BUG_ON((uintptr_t)(dest_buf) & (FNCPY_ALIGN - 1) ||		\
+		(__funcp_address & ~(uintptr_t)1 & (FNCPY_ALIGN - 1)));	\
+									\
+	memcpy(dest_buf, (void const *)(__funcp_address & ~1), size);	\
+	flush_icache_range((unsigned long)(dest_buf),			\
+		(unsigned long)(dest_buf) + (size));			\
+									\
+	asm("" : "=r" (__result)					\
+		: "0" ((uintptr_t)(dest_buf) | (__funcp_address & 1)));	\
+									\
+	__result;							\
+})
+
+#endif /* !__ASM_FNCPY_H */
diff --git a/arch/arm/include/asm/glue-cache.h b/arch/arm/include/asm/glue-cache.h
new file mode 100644
index 0000000..0591d350
--- /dev/null
+++ b/arch/arm/include/asm/glue-cache.h
@@ -0,0 +1,146 @@
+/*
+ *  arch/arm/include/asm/glue-cache.h
+ *
+ *  Copyright (C) 1999-2002 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.
+ */
+#ifndef ASM_GLUE_CACHE_H
+#define ASM_GLUE_CACHE_H
+
+#include <asm/glue.h>
+
+/*
+ *	Cache Model
+ *	===========
+ */
+#undef _CACHE
+#undef MULTI_CACHE
+
+#if defined(CONFIG_CPU_CACHE_V3)
+# ifdef _CACHE
+#  define MULTI_CACHE 1
+# else
+#  define _CACHE v3
+# endif
+#endif
+
+#if defined(CONFIG_CPU_CACHE_V4)
+# ifdef _CACHE
+#  define MULTI_CACHE 1
+# else
+#  define _CACHE v4
+# endif
+#endif
+
+#if defined(CONFIG_CPU_ARM920T) || defined(CONFIG_CPU_ARM922T) || \
+    defined(CONFIG_CPU_ARM925T) || defined(CONFIG_CPU_ARM1020) || \
+    defined(CONFIG_CPU_ARM1026)
+# define MULTI_CACHE 1
+#endif
+
+#if defined(CONFIG_CPU_FA526)
+# ifdef _CACHE
+#  define MULTI_CACHE 1
+# else
+#  define _CACHE fa
+# endif
+#endif
+
+#if defined(CONFIG_CPU_ARM926T)
+# ifdef _CACHE
+#  define MULTI_CACHE 1
+# else
+#  define _CACHE arm926
+# endif
+#endif
+
+#if defined(CONFIG_CPU_ARM940T)
+# ifdef _CACHE
+#  define MULTI_CACHE 1
+# else
+#  define _CACHE arm940
+# endif
+#endif
+
+#if defined(CONFIG_CPU_ARM946E)
+# ifdef _CACHE
+#  define MULTI_CACHE 1
+# else
+#  define _CACHE arm946
+# endif
+#endif
+
+#if defined(CONFIG_CPU_CACHE_V4WB)
+# ifdef _CACHE
+#  define MULTI_CACHE 1
+# else
+#  define _CACHE v4wb
+# endif
+#endif
+
+#if defined(CONFIG_CPU_XSCALE)
+# ifdef _CACHE
+#  define MULTI_CACHE 1
+# else
+#  define _CACHE xscale
+# endif
+#endif
+
+#if defined(CONFIG_CPU_XSC3)
+# ifdef _CACHE
+#  define MULTI_CACHE 1
+# else
+#  define _CACHE xsc3
+# endif
+#endif
+
+#if defined(CONFIG_CPU_MOHAWK)
+# ifdef _CACHE
+#  define MULTI_CACHE 1
+# else
+#  define _CACHE mohawk
+# endif
+#endif
+
+#if defined(CONFIG_CPU_FEROCEON)
+# define MULTI_CACHE 1
+#endif
+
+#if defined(CONFIG_CPU_V6)
+//# ifdef _CACHE
+#  define MULTI_CACHE 1
+//# else
+//#  define _CACHE v6
+//# endif
+#endif
+
+#if defined(CONFIG_CPU_V7)
+//# ifdef _CACHE
+#  define MULTI_CACHE 1
+//# else
+//#  define _CACHE v7
+//# endif
+#endif
+
+#if !defined(_CACHE) && !defined(MULTI_CACHE)
+#error Unknown cache maintainence model
+#endif
+
+#ifndef MULTI_CACHE
+#define __cpuc_flush_icache_all		__glue(_CACHE,_flush_icache_all)
+#define __cpuc_flush_kern_all		__glue(_CACHE,_flush_kern_cache_all)
+#define __cpuc_flush_user_all		__glue(_CACHE,_flush_user_cache_all)
+#define __cpuc_flush_user_range		__glue(_CACHE,_flush_user_cache_range)
+#define __cpuc_coherent_kern_range	__glue(_CACHE,_coherent_kern_range)
+#define __cpuc_coherent_user_range	__glue(_CACHE,_coherent_user_range)
+#define __cpuc_flush_dcache_area	__glue(_CACHE,_flush_kern_dcache_area)
+
+#define dmac_map_area			__glue(_CACHE,_dma_map_area)
+#define dmac_unmap_area			__glue(_CACHE,_dma_unmap_area)
+#define dmac_flush_range		__glue(_CACHE,_dma_flush_range)
+#endif
+
+#endif
diff --git a/arch/arm/include/asm/glue-df.h b/arch/arm/include/asm/glue-df.h
new file mode 100644
index 0000000..354d571
--- /dev/null
+++ b/arch/arm/include/asm/glue-df.h
@@ -0,0 +1,110 @@
+/*
+ *  arch/arm/include/asm/glue-df.h
+ *
+ *  Copyright (C) 1997-1999 Russell King
+ *  Copyright (C) 2000-2002 Deep Blue Solutions Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef ASM_GLUE_DF_H
+#define ASM_GLUE_DF_H
+
+#include <asm/glue.h>
+
+/*
+ *	Data Abort Model
+ *	================
+ *
+ *	We have the following to choose from:
+ *	  arm6          - ARM6 style
+ *	  arm7		- ARM7 style
+ *	  v4_early	- ARMv4 without Thumb early abort handler
+ *	  v4t_late	- ARMv4 with Thumb late abort handler
+ *	  v4t_early	- ARMv4 with Thumb early abort handler
+ *	  v5tej_early	- ARMv5 with Thumb and Java early abort handler
+ *	  xscale	- ARMv5 with Thumb with Xscale extensions
+ *	  v6_early	- ARMv6 generic early abort handler
+ *	  v7_early	- ARMv7 generic early abort handler
+ */
+#undef CPU_DABORT_HANDLER
+#undef MULTI_DABORT
+
+#if defined(CONFIG_CPU_ARM610)
+# ifdef CPU_DABORT_HANDLER
+#  define MULTI_DABORT 1
+# else
+#  define CPU_DABORT_HANDLER cpu_arm6_data_abort
+# endif
+#endif
+
+#if defined(CONFIG_CPU_ARM710)
+# ifdef CPU_DABORT_HANDLER
+#  define MULTI_DABORT 1
+# else
+#  define CPU_DABORT_HANDLER cpu_arm7_data_abort
+# endif
+#endif
+
+#ifdef CONFIG_CPU_ABRT_LV4T
+# ifdef CPU_DABORT_HANDLER
+#  define MULTI_DABORT 1
+# else
+#  define CPU_DABORT_HANDLER v4t_late_abort
+# endif
+#endif
+
+#ifdef CONFIG_CPU_ABRT_EV4
+# ifdef CPU_DABORT_HANDLER
+#  define MULTI_DABORT 1
+# else
+#  define CPU_DABORT_HANDLER v4_early_abort
+# endif
+#endif
+
+#ifdef CONFIG_CPU_ABRT_EV4T
+# ifdef CPU_DABORT_HANDLER
+#  define MULTI_DABORT 1
+# else
+#  define CPU_DABORT_HANDLER v4t_early_abort
+# endif
+#endif
+
+#ifdef CONFIG_CPU_ABRT_EV5TJ
+# ifdef CPU_DABORT_HANDLER
+#  define MULTI_DABORT 1
+# else
+#  define CPU_DABORT_HANDLER v5tj_early_abort
+# endif
+#endif
+
+#ifdef CONFIG_CPU_ABRT_EV5T
+# ifdef CPU_DABORT_HANDLER
+#  define MULTI_DABORT 1
+# else
+#  define CPU_DABORT_HANDLER v5t_early_abort
+# endif
+#endif
+
+#ifdef CONFIG_CPU_ABRT_EV6
+# ifdef CPU_DABORT_HANDLER
+#  define MULTI_DABORT 1
+# else
+#  define CPU_DABORT_HANDLER v6_early_abort
+# endif
+#endif
+
+#ifdef CONFIG_CPU_ABRT_EV7
+# ifdef CPU_DABORT_HANDLER
+#  define MULTI_DABORT 1
+# else
+#  define CPU_DABORT_HANDLER v7_early_abort
+# endif
+#endif
+
+#ifndef CPU_DABORT_HANDLER
+#error Unknown data abort handler type
+#endif
+
+#endif
diff --git a/arch/arm/include/asm/glue-pf.h b/arch/arm/include/asm/glue-pf.h
new file mode 100644
index 0000000..d385f37
--- /dev/null
+++ b/arch/arm/include/asm/glue-pf.h
@@ -0,0 +1,57 @@
+/*
+ *  arch/arm/include/asm/glue-pf.h
+ *
+ *  Copyright (C) 1997-1999 Russell King
+ *  Copyright (C) 2000-2002 Deep Blue Solutions Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef ASM_GLUE_PF_H
+#define ASM_GLUE_PF_H
+
+#include <asm/glue.h>
+
+/*
+ *	Prefetch Abort Model
+ *	================
+ *
+ *	We have the following to choose from:
+ *	  legacy	- no IFSR, no IFAR
+ *	  v6		- ARMv6: IFSR, no IFAR
+ *	  v7		- ARMv7: IFSR and IFAR
+ */
+
+#undef CPU_PABORT_HANDLER
+#undef MULTI_PABORT
+
+#ifdef CONFIG_CPU_PABRT_LEGACY
+# ifdef CPU_PABORT_HANDLER
+#  define MULTI_PABORT 1
+# else
+#  define CPU_PABORT_HANDLER legacy_pabort
+# endif
+#endif
+
+#ifdef CONFIG_CPU_PABRT_V6
+# ifdef CPU_PABORT_HANDLER
+#  define MULTI_PABORT 1
+# else
+#  define CPU_PABORT_HANDLER v6_pabort
+# endif
+#endif
+
+#ifdef CONFIG_CPU_PABRT_V7
+# ifdef CPU_PABORT_HANDLER
+#  define MULTI_PABORT 1
+# else
+#  define CPU_PABORT_HANDLER v7_pabort
+# endif
+#endif
+
+#ifndef CPU_PABORT_HANDLER
+#error Unknown prefetch abort handler type
+#endif
+
+#endif
diff --git a/arch/arm/include/asm/glue-proc.h b/arch/arm/include/asm/glue-proc.h
new file mode 100644
index 0000000..6469521
--- /dev/null
+++ b/arch/arm/include/asm/glue-proc.h
@@ -0,0 +1,264 @@
+/*
+ *  arch/arm/include/asm/glue-proc.h
+ *
+ *  Copyright (C) 1997-1999 Russell King
+ *  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 version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef ASM_GLUE_PROC_H
+#define ASM_GLUE_PROC_H
+
+#include <asm/glue.h>
+
+/*
+ * Work out if we need multiple CPU support
+ */
+#undef MULTI_CPU
+#undef CPU_NAME
+
+/*
+ * CPU_NAME - the prefix for CPU related functions
+ */
+
+#ifdef CONFIG_CPU_ARM610
+# ifdef CPU_NAME
+#  undef  MULTI_CPU
+#  define MULTI_CPU
+# else
+#  define CPU_NAME cpu_arm6
+# endif
+#endif
+
+#ifdef CONFIG_CPU_ARM7TDMI
+# ifdef CPU_NAME
+#  undef  MULTI_CPU
+#  define MULTI_CPU
+# else
+#  define CPU_NAME cpu_arm7tdmi
+# endif
+#endif
+
+#ifdef CONFIG_CPU_ARM710
+# ifdef CPU_NAME
+#  undef  MULTI_CPU
+#  define MULTI_CPU
+# else
+#  define CPU_NAME cpu_arm7
+# endif
+#endif
+
+#ifdef CONFIG_CPU_ARM720T
+# ifdef CPU_NAME
+#  undef  MULTI_CPU
+#  define MULTI_CPU
+# else
+#  define CPU_NAME cpu_arm720
+# endif
+#endif
+
+#ifdef CONFIG_CPU_ARM740T
+# ifdef CPU_NAME
+#  undef  MULTI_CPU
+#  define MULTI_CPU
+# else
+#  define CPU_NAME cpu_arm740
+# endif
+#endif
+
+#ifdef CONFIG_CPU_ARM9TDMI
+# ifdef CPU_NAME
+#  undef  MULTI_CPU
+#  define MULTI_CPU
+# else
+#  define CPU_NAME cpu_arm9tdmi
+# endif
+#endif
+
+#ifdef CONFIG_CPU_ARM920T
+# ifdef CPU_NAME
+#  undef  MULTI_CPU
+#  define MULTI_CPU
+# else
+#  define CPU_NAME cpu_arm920
+# endif
+#endif
+
+#ifdef CONFIG_CPU_ARM922T
+# ifdef CPU_NAME
+#  undef  MULTI_CPU
+#  define MULTI_CPU
+# else
+#  define CPU_NAME cpu_arm922
+# endif
+#endif
+
+#ifdef CONFIG_CPU_FA526
+# ifdef CPU_NAME
+#  undef  MULTI_CPU
+#  define MULTI_CPU
+# else
+#  define CPU_NAME cpu_fa526
+# endif
+#endif
+
+#ifdef CONFIG_CPU_ARM925T
+# ifdef CPU_NAME
+#  undef  MULTI_CPU
+#  define MULTI_CPU
+# else
+#  define CPU_NAME cpu_arm925
+# endif
+#endif
+
+#ifdef CONFIG_CPU_ARM926T
+# ifdef CPU_NAME
+#  undef  MULTI_CPU
+#  define MULTI_CPU
+# else
+#  define CPU_NAME cpu_arm926
+# endif
+#endif
+
+#ifdef CONFIG_CPU_ARM940T
+# ifdef CPU_NAME
+#  undef  MULTI_CPU
+#  define MULTI_CPU
+# else
+#  define CPU_NAME cpu_arm940
+# endif
+#endif
+
+#ifdef CONFIG_CPU_ARM946E
+# ifdef CPU_NAME
+#  undef  MULTI_CPU
+#  define MULTI_CPU
+# else
+#  define CPU_NAME cpu_arm946
+# endif
+#endif
+
+#ifdef CONFIG_CPU_SA110
+# ifdef CPU_NAME
+#  undef  MULTI_CPU
+#  define MULTI_CPU
+# else
+#  define CPU_NAME cpu_sa110
+# endif
+#endif
+
+#ifdef CONFIG_CPU_SA1100
+# ifdef CPU_NAME
+#  undef  MULTI_CPU
+#  define MULTI_CPU
+# else
+#  define CPU_NAME cpu_sa1100
+# endif
+#endif
+
+#ifdef CONFIG_CPU_ARM1020
+# ifdef CPU_NAME
+#  undef  MULTI_CPU
+#  define MULTI_CPU
+# else
+#  define CPU_NAME cpu_arm1020
+# endif
+#endif
+
+#ifdef CONFIG_CPU_ARM1020E
+# ifdef CPU_NAME
+#  undef  MULTI_CPU
+#  define MULTI_CPU
+# else
+#  define CPU_NAME cpu_arm1020e
+# endif
+#endif
+
+#ifdef CONFIG_CPU_ARM1022
+# ifdef CPU_NAME
+#  undef  MULTI_CPU
+#  define MULTI_CPU
+# else
+#  define CPU_NAME cpu_arm1022
+# endif
+#endif
+
+#ifdef CONFIG_CPU_ARM1026
+# ifdef CPU_NAME
+#  undef  MULTI_CPU
+#  define MULTI_CPU
+# else
+#  define CPU_NAME cpu_arm1026
+# endif
+#endif
+
+#ifdef CONFIG_CPU_XSCALE
+# ifdef CPU_NAME
+#  undef  MULTI_CPU
+#  define MULTI_CPU
+# else
+#  define CPU_NAME cpu_xscale
+# endif
+#endif
+
+#ifdef CONFIG_CPU_XSC3
+# ifdef CPU_NAME
+#  undef  MULTI_CPU
+#  define MULTI_CPU
+# else
+#  define CPU_NAME cpu_xsc3
+# endif
+#endif
+
+#ifdef CONFIG_CPU_MOHAWK
+# ifdef CPU_NAME
+#  undef  MULTI_CPU
+#  define MULTI_CPU
+# else
+#  define CPU_NAME cpu_mohawk
+# endif
+#endif
+
+#ifdef CONFIG_CPU_FEROCEON
+# ifdef CPU_NAME
+#  undef  MULTI_CPU
+#  define MULTI_CPU
+# else
+#  define CPU_NAME cpu_feroceon
+# endif
+#endif
+
+#ifdef CONFIG_CPU_V6
+# ifdef CPU_NAME
+#  undef  MULTI_CPU
+#  define MULTI_CPU
+# else
+#  define CPU_NAME cpu_v6
+# endif
+#endif
+
+#ifdef CONFIG_CPU_V7
+# ifdef CPU_NAME
+#  undef  MULTI_CPU
+#  define MULTI_CPU
+# else
+#  define CPU_NAME cpu_v7
+# endif
+#endif
+
+#ifndef MULTI_CPU
+#define cpu_proc_init			__glue(CPU_NAME,_proc_init)
+#define cpu_proc_fin			__glue(CPU_NAME,_proc_fin)
+#define cpu_reset			__glue(CPU_NAME,_reset)
+#define cpu_do_idle			__glue(CPU_NAME,_do_idle)
+#define cpu_dcache_clean_area		__glue(CPU_NAME,_dcache_clean_area)
+#define cpu_do_switch_mm		__glue(CPU_NAME,_switch_mm)
+#define cpu_set_pte_ext			__glue(CPU_NAME,_set_pte_ext)
+#define cpu_suspend_size		__glue(CPU_NAME,_suspend_size)
+#define cpu_do_suspend			__glue(CPU_NAME,_do_suspend)
+#define cpu_do_resume			__glue(CPU_NAME,_do_resume)
+#endif
+
+#endif
diff --git a/arch/arm/include/asm/glue.h b/arch/arm/include/asm/glue.h
index 234a3fc..0ec35d1 100644
--- a/arch/arm/include/asm/glue.h
+++ b/arch/arm/include/asm/glue.h
@@ -15,7 +15,6 @@
  */
 #ifdef __KERNEL__
 
-
 #ifdef __STDC__
 #define ____glue(name,fn)	name##fn
 #else
@@ -23,141 +22,4 @@
 #endif
 #define __glue(name,fn)		____glue(name,fn)
 
-
-
-/*
- *	Data Abort Model
- *	================
- *
- *	We have the following to choose from:
- *	  arm6          - ARM6 style
- *	  arm7		- ARM7 style
- *	  v4_early	- ARMv4 without Thumb early abort handler
- *	  v4t_late	- ARMv4 with Thumb late abort handler
- *	  v4t_early	- ARMv4 with Thumb early abort handler
- *	  v5tej_early	- ARMv5 with Thumb and Java early abort handler
- *	  xscale	- ARMv5 with Thumb with Xscale extensions
- *	  v6_early	- ARMv6 generic early abort handler
- *	  v7_early	- ARMv7 generic early abort handler
- */
-#undef CPU_DABORT_HANDLER
-#undef MULTI_DABORT
-
-#if defined(CONFIG_CPU_ARM610)
-# ifdef CPU_DABORT_HANDLER
-#  define MULTI_DABORT 1
-# else
-#  define CPU_DABORT_HANDLER cpu_arm6_data_abort
-# endif
-#endif
-
-#if defined(CONFIG_CPU_ARM710)
-# ifdef CPU_DABORT_HANDLER
-#  define MULTI_DABORT 1
-# else
-#  define CPU_DABORT_HANDLER cpu_arm7_data_abort
-# endif
-#endif
-
-#ifdef CONFIG_CPU_ABRT_LV4T
-# ifdef CPU_DABORT_HANDLER
-#  define MULTI_DABORT 1
-# else
-#  define CPU_DABORT_HANDLER v4t_late_abort
-# endif
-#endif
-
-#ifdef CONFIG_CPU_ABRT_EV4
-# ifdef CPU_DABORT_HANDLER
-#  define MULTI_DABORT 1
-# else
-#  define CPU_DABORT_HANDLER v4_early_abort
-# endif
-#endif
-
-#ifdef CONFIG_CPU_ABRT_EV4T
-# ifdef CPU_DABORT_HANDLER
-#  define MULTI_DABORT 1
-# else
-#  define CPU_DABORT_HANDLER v4t_early_abort
-# endif
-#endif
-
-#ifdef CONFIG_CPU_ABRT_EV5TJ
-# ifdef CPU_DABORT_HANDLER
-#  define MULTI_DABORT 1
-# else
-#  define CPU_DABORT_HANDLER v5tj_early_abort
-# endif
-#endif
-
-#ifdef CONFIG_CPU_ABRT_EV5T
-# ifdef CPU_DABORT_HANDLER
-#  define MULTI_DABORT 1
-# else
-#  define CPU_DABORT_HANDLER v5t_early_abort
-# endif
-#endif
-
-#ifdef CONFIG_CPU_ABRT_EV6
-# ifdef CPU_DABORT_HANDLER
-#  define MULTI_DABORT 1
-# else
-#  define CPU_DABORT_HANDLER v6_early_abort
-# endif
-#endif
-
-#ifdef CONFIG_CPU_ABRT_EV7
-# ifdef CPU_DABORT_HANDLER
-#  define MULTI_DABORT 1
-# else
-#  define CPU_DABORT_HANDLER v7_early_abort
-# endif
-#endif
-
-#ifndef CPU_DABORT_HANDLER
-#error Unknown data abort handler type
-#endif
-
-/*
- *	Prefetch Abort Model
- *	================
- *
- *	We have the following to choose from:
- *	  legacy	- no IFSR, no IFAR
- *	  v6		- ARMv6: IFSR, no IFAR
- *	  v7		- ARMv7: IFSR and IFAR
- */
-
-#undef CPU_PABORT_HANDLER
-#undef MULTI_PABORT
-
-#ifdef CONFIG_CPU_PABRT_LEGACY
-# ifdef CPU_PABORT_HANDLER
-#  define MULTI_PABORT 1
-# else
-#  define CPU_PABORT_HANDLER legacy_pabort
-# endif
-#endif
-
-#ifdef CONFIG_CPU_PABRT_V6
-# ifdef CPU_PABORT_HANDLER
-#  define MULTI_PABORT 1
-# else
-#  define CPU_PABORT_HANDLER v6_pabort
-# endif
-#endif
-
-#ifdef CONFIG_CPU_PABRT_V7
-# ifdef CPU_PABORT_HANDLER
-#  define MULTI_PABORT 1
-# else
-#  define CPU_PABORT_HANDLER v7_pabort
-# endif
-#endif
-
-#ifndef CPU_PABORT_HANDLER
-#error Unknown prefetch abort handler type
-#endif
-
 #endif
diff --git a/arch/arm/include/asm/proc-fns.h b/arch/arm/include/asm/proc-fns.h
index 8fdae9b..8ec535e 100644
--- a/arch/arm/include/asm/proc-fns.h
+++ b/arch/arm/include/asm/proc-fns.h
@@ -13,250 +13,86 @@
 
 #ifdef __KERNEL__
 
-
-/*
- * Work out if we need multiple CPU support
- */
-#undef MULTI_CPU
-#undef CPU_NAME
-
-/*
- * CPU_NAME - the prefix for CPU related functions
- */
-
-#ifdef CONFIG_CPU_ARM610
-# ifdef CPU_NAME
-#  undef  MULTI_CPU
-#  define MULTI_CPU
-# else
-#  define CPU_NAME cpu_arm6
-# endif
-#endif
-
-#ifdef CONFIG_CPU_ARM7TDMI
-# ifdef CPU_NAME
-#  undef  MULTI_CPU
-#  define MULTI_CPU
-# else
-#  define CPU_NAME cpu_arm7tdmi
-# endif
-#endif
-
-#ifdef CONFIG_CPU_ARM710
-# ifdef CPU_NAME
-#  undef  MULTI_CPU
-#  define MULTI_CPU
-# else
-#  define CPU_NAME cpu_arm7
-# endif
-#endif
-
-#ifdef CONFIG_CPU_ARM720T
-# ifdef CPU_NAME
-#  undef  MULTI_CPU
-#  define MULTI_CPU
-# else
-#  define CPU_NAME cpu_arm720
-# endif
-#endif
-
-#ifdef CONFIG_CPU_ARM740T
-# ifdef CPU_NAME
-#  undef  MULTI_CPU
-#  define MULTI_CPU
-# else
-#  define CPU_NAME cpu_arm740
-# endif
-#endif
-
-#ifdef CONFIG_CPU_ARM9TDMI
-# ifdef CPU_NAME
-#  undef  MULTI_CPU
-#  define MULTI_CPU
-# else
-#  define CPU_NAME cpu_arm9tdmi
-# endif
-#endif
-
-#ifdef CONFIG_CPU_ARM920T
-# ifdef CPU_NAME
-#  undef  MULTI_CPU
-#  define MULTI_CPU
-# else
-#  define CPU_NAME cpu_arm920
-# endif
-#endif
-
-#ifdef CONFIG_CPU_ARM922T
-# ifdef CPU_NAME
-#  undef  MULTI_CPU
-#  define MULTI_CPU
-# else
-#  define CPU_NAME cpu_arm922
-# endif
-#endif
-
-#ifdef CONFIG_CPU_FA526
-# ifdef CPU_NAME
-#  undef  MULTI_CPU
-#  define MULTI_CPU
-# else
-#  define CPU_NAME cpu_fa526
-# endif
-#endif
-
-#ifdef CONFIG_CPU_ARM925T
-# ifdef CPU_NAME
-#  undef  MULTI_CPU
-#  define MULTI_CPU
-# else
-#  define CPU_NAME cpu_arm925
-# endif
-#endif
-
-#ifdef CONFIG_CPU_ARM926T
-# ifdef CPU_NAME
-#  undef  MULTI_CPU
-#  define MULTI_CPU
-# else
-#  define CPU_NAME cpu_arm926
-# endif
-#endif
-
-#ifdef CONFIG_CPU_ARM940T
-# ifdef CPU_NAME
-#  undef  MULTI_CPU
-#  define MULTI_CPU
-# else
-#  define CPU_NAME cpu_arm940
-# endif
-#endif
-
-#ifdef CONFIG_CPU_ARM946E
-# ifdef CPU_NAME
-#  undef  MULTI_CPU
-#  define MULTI_CPU
-# else
-#  define CPU_NAME cpu_arm946
-# endif
-#endif
-
-#ifdef CONFIG_CPU_SA110
-# ifdef CPU_NAME
-#  undef  MULTI_CPU
-#  define MULTI_CPU
-# else
-#  define CPU_NAME cpu_sa110
-# endif
-#endif
-
-#ifdef CONFIG_CPU_SA1100
-# ifdef CPU_NAME
-#  undef  MULTI_CPU
-#  define MULTI_CPU
-# else
-#  define CPU_NAME cpu_sa1100
-# endif
-#endif
-
-#ifdef CONFIG_CPU_ARM1020
-# ifdef CPU_NAME
-#  undef  MULTI_CPU
-#  define MULTI_CPU
-# else
-#  define CPU_NAME cpu_arm1020
-# endif
-#endif
-
-#ifdef CONFIG_CPU_ARM1020E
-# ifdef CPU_NAME
-#  undef  MULTI_CPU
-#  define MULTI_CPU
-# else
-#  define CPU_NAME cpu_arm1020e
-# endif
-#endif
-
-#ifdef CONFIG_CPU_ARM1022
-# ifdef CPU_NAME
-#  undef  MULTI_CPU
-#  define MULTI_CPU
-# else
-#  define CPU_NAME cpu_arm1022
-# endif
-#endif
-
-#ifdef CONFIG_CPU_ARM1026
-# ifdef CPU_NAME
-#  undef  MULTI_CPU
-#  define MULTI_CPU
-# else
-#  define CPU_NAME cpu_arm1026
-# endif
-#endif
-
-#ifdef CONFIG_CPU_XSCALE
-# ifdef CPU_NAME
-#  undef  MULTI_CPU
-#  define MULTI_CPU
-# else
-#  define CPU_NAME cpu_xscale
-# endif
-#endif
-
-#ifdef CONFIG_CPU_XSC3
-# ifdef CPU_NAME
-#  undef  MULTI_CPU
-#  define MULTI_CPU
-# else
-#  define CPU_NAME cpu_xsc3
-# endif
-#endif
-
-#ifdef CONFIG_CPU_MOHAWK
-# ifdef CPU_NAME
-#  undef  MULTI_CPU
-#  define MULTI_CPU
-# else
-#  define CPU_NAME cpu_mohawk
-# endif
-#endif
-
-#ifdef CONFIG_CPU_FEROCEON
-# ifdef CPU_NAME
-#  undef  MULTI_CPU
-#  define MULTI_CPU
-# else
-#  define CPU_NAME cpu_feroceon
-# endif
-#endif
-
-#ifdef CONFIG_CPU_V6
-# ifdef CPU_NAME
-#  undef  MULTI_CPU
-#  define MULTI_CPU
-# else
-#  define CPU_NAME cpu_v6
-# endif
-#endif
-
-#ifdef CONFIG_CPU_V7
-# ifdef CPU_NAME
-#  undef  MULTI_CPU
-#  define MULTI_CPU
-# else
-#  define CPU_NAME cpu_v7
-# endif
-#endif
+#include <asm/glue-proc.h>
+#include <asm/page.h>
 
 #ifndef __ASSEMBLY__
 
+struct mm_struct;
+
+/*
+ * Don't change this structure - ASM code relies on it.
+ */
+extern struct processor {
+	/* MISC
+	 * get data abort address/flags
+	 */
+	void (*_data_abort)(unsigned long pc);
+	/*
+	 * Retrieve prefetch fault address
+	 */
+	unsigned long (*_prefetch_abort)(unsigned long lr);
+	/*
+	 * Set up any processor specifics
+	 */
+	void (*_proc_init)(void);
+	/*
+	 * Disable any processor specifics
+	 */
+	void (*_proc_fin)(void);
+	/*
+	 * Special stuff for a reset
+	 */
+	void (*reset)(unsigned long addr) __attribute__((noreturn));
+	/*
+	 * Idle the processor
+	 */
+	int (*_do_idle)(void);
+	/*
+	 * Processor architecture specific
+	 */
+	/*
+	 * clean a virtual address range from the
+	 * D-cache without flushing the cache.
+	 */
+	void (*dcache_clean_area)(void *addr, int size);
+
+	/*
+	 * Set the page table
+	 */
+	void (*switch_mm)(unsigned long pgd_phys, struct mm_struct *mm);
+	/*
+	 * Set a possibly extended PTE.  Non-extended PTEs should
+	 * ignore 'ext'.
+	 */
+	void (*set_pte_ext)(pte_t *ptep, pte_t pte, unsigned int ext);
+
+	/* Suspend/resume */
+	unsigned int suspend_size;
+	void (*do_suspend)(void *);
+	void (*do_resume)(void *);
+} processor;
+
 #ifndef MULTI_CPU
-#include <asm/cpu-single.h>
+extern void cpu_proc_init(void);
+extern void cpu_proc_fin(void);
+extern int cpu_do_idle(void);
+extern void cpu_dcache_clean_area(void *, int);
+extern void cpu_do_switch_mm(unsigned long pgd_phys, struct mm_struct *mm);
+extern void cpu_set_pte_ext(pte_t *ptep, pte_t pte, unsigned int ext);
+extern void cpu_reset(unsigned long addr) __attribute__((noreturn));
 #else
-#include <asm/cpu-multi32.h>
+#define cpu_proc_init()			processor._proc_init()
+#define cpu_proc_fin()			processor._proc_fin()
+#define cpu_reset(addr)			processor.reset(addr)
+#define cpu_do_idle()			processor._do_idle()
+#define cpu_dcache_clean_area(addr,sz)	processor.dcache_clean_area(addr,sz)
+#define cpu_set_pte_ext(ptep,pte,ext)	processor.set_pte_ext(ptep,pte,ext)
+#define cpu_do_switch_mm(pgd,mm)	processor.switch_mm(pgd,mm)
 #endif
 
+extern void cpu_resume(void);
+
 #include <asm/memory.h>
 
 #ifdef CONFIG_MMU
diff --git a/arch/arm/include/asm/processor.h b/arch/arm/include/asm/processor.h
index 67357ba..7a1f03c 100644
--- a/arch/arm/include/asm/processor.h
+++ b/arch/arm/include/asm/processor.h
@@ -95,7 +95,7 @@
 
 unsigned long get_wchan(struct task_struct *p);
 
-#if __LINUX_ARM_ARCH__ == 6
+#if __LINUX_ARM_ARCH__ == 6 || defined(CONFIG_ARM_ERRATA_754327)
 #define cpu_relax()			smp_mb()
 #else
 #define cpu_relax()			barrier()
diff --git a/arch/arm/include/asm/smp_scu.h b/arch/arm/include/asm/smp_scu.h
index 2376835..4eb6d00 100644
--- a/arch/arm/include/asm/smp_scu.h
+++ b/arch/arm/include/asm/smp_scu.h
@@ -1,7 +1,14 @@
 #ifndef __ASMARM_ARCH_SCU_H
 #define __ASMARM_ARCH_SCU_H
 
+#define SCU_PM_NORMAL	0
+#define SCU_PM_DORMANT	2
+#define SCU_PM_POWEROFF	3
+
+#ifndef __ASSEMBLER__
 unsigned int scu_get_core_count(void __iomem *);
 void scu_enable(void __iomem *);
+int scu_power_mode(void __iomem *, unsigned int);
+#endif
 
 #endif
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index 185ee82..74554f1 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -29,6 +29,7 @@
 obj-$(CONFIG_ARTHUR)		+= arthur.o
 obj-$(CONFIG_ISA_DMA)		+= dma-isa.o
 obj-$(CONFIG_PCI)		+= bios32.o isa.o
+obj-$(CONFIG_PM)		+= sleep.o
 obj-$(CONFIG_HAVE_SCHED_CLOCK)	+= sched_clock.o
 obj-$(CONFIG_SMP)		+= smp.o smp_tlb.o
 obj-$(CONFIG_HAVE_ARM_SCU)	+= smp_scu.o
diff --git a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c
index 82da661..927522c 100644
--- a/arch/arm/kernel/asm-offsets.c
+++ b/arch/arm/kernel/asm-offsets.c
@@ -13,6 +13,9 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/dma-mapping.h>
+#include <asm/cacheflush.h>
+#include <asm/glue-df.h>
+#include <asm/glue-pf.h>
 #include <asm/mach/arch.h>
 #include <asm/thread_info.h>
 #include <asm/memory.h>
@@ -114,6 +117,14 @@
 #ifdef MULTI_PABORT
   DEFINE(PROCESSOR_PABT_FUNC,	offsetof(struct processor, _prefetch_abort));
 #endif
+#ifdef MULTI_CPU
+  DEFINE(CPU_SLEEP_SIZE,	offsetof(struct processor, suspend_size));
+  DEFINE(CPU_DO_SUSPEND,	offsetof(struct processor, do_suspend));
+  DEFINE(CPU_DO_RESUME,		offsetof(struct processor, do_resume));
+#endif
+#ifdef MULTI_CACHE
+  DEFINE(CACHE_FLUSH_KERN_ALL,	offsetof(struct cpu_cache_fns, flush_kern_all));
+#endif
   BLANK();
   DEFINE(DMA_BIDIRECTIONAL,	DMA_BIDIRECTIONAL);
   DEFINE(DMA_TO_DEVICE,		DMA_TO_DEVICE);
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 2b46fea..e8d8856 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -16,7 +16,8 @@
  */
 
 #include <asm/memory.h>
-#include <asm/glue.h>
+#include <asm/glue-df.h>
+#include <asm/glue-pf.h>
 #include <asm/vfpmacros.h>
 #include <mach/entry-macro.S>
 #include <asm/thread_notify.h>
diff --git a/arch/arm/kernel/sleep.S b/arch/arm/kernel/sleep.S
new file mode 100644
index 0000000..bfad698
--- /dev/null
+++ b/arch/arm/kernel/sleep.S
@@ -0,0 +1,134 @@
+#include <linux/linkage.h>
+#include <linux/threads.h>
+#include <asm/asm-offsets.h>
+#include <asm/assembler.h>
+#include <asm/glue-cache.h>
+#include <asm/glue-proc.h>
+#include <asm/system.h>
+	.text
+
+/*
+ * Save CPU state for a suspend
+ *  r1 = v:p offset
+ *  r3 = virtual return function
+ * Note: sp is decremented to allocate space for CPU state on stack
+ * r0-r3,r9,r10,lr corrupted
+ */
+ENTRY(cpu_suspend)
+	mov	r9, lr
+#ifdef MULTI_CPU
+	ldr	r10, =processor
+	mov	r2, sp			@ current virtual SP
+	ldr	r0, [r10, #CPU_SLEEP_SIZE] @ size of CPU sleep state
+	ldr	ip, [r10, #CPU_DO_RESUME] @ virtual resume function
+	sub	sp, sp, r0		@ allocate CPU state on stack
+	mov	r0, sp			@ save pointer
+	add	ip, ip, r1		@ convert resume fn to phys
+	stmfd	sp!, {r1, r2, r3, ip}	@ save v:p, virt SP, retfn, phys resume fn
+	ldr	r3, =sleep_save_sp
+	add	r2, sp, r1		@ convert SP to phys
+#ifdef CONFIG_SMP
+	ALT_SMP(mrc p15, 0, lr, c0, c0, 5)
+	ALT_UP(mov lr, #0)
+	and	lr, lr, #15
+	str	r2, [r3, lr, lsl #2]	@ save phys SP
+#else
+	str	r2, [r3]		@ save phys SP
+#endif
+	mov	lr, pc
+	ldr	pc, [r10, #CPU_DO_SUSPEND] @ save CPU state
+#else
+	mov	r2, sp			@ current virtual SP
+	ldr	r0, =cpu_suspend_size
+	sub	sp, sp, r0		@ allocate CPU state on stack
+	mov	r0, sp			@ save pointer
+	stmfd	sp!, {r1, r2, r3}	@ save v:p, virt SP, return fn
+	ldr	r3, =sleep_save_sp
+	add	r2, sp, r1		@ convert SP to phys
+#ifdef CONFIG_SMP
+	ALT_SMP(mrc p15, 0, lr, c0, c0, 5)
+	ALT_UP(mov lr, #0)
+	and	lr, lr, #15
+	str	r2, [r3, lr, lsl #2]	@ save phys SP
+#else
+	str	r2, [r3]		@ save phys SP
+#endif
+	bl	cpu_do_suspend
+#endif
+
+	@ flush data cache
+#ifdef MULTI_CACHE
+	ldr	r10, =cpu_cache
+	mov	lr, r9
+	ldr	pc, [r10, #CACHE_FLUSH_KERN_ALL]
+#else
+	mov	lr, r9
+	b	__cpuc_flush_kern_all
+#endif
+ENDPROC(cpu_suspend)
+	.ltorg
+
+/*
+ * r0 = control register value
+ * r1 = v:p offset (preserved by cpu_do_resume)
+ * r2 = phys page table base
+ * r3 = L1 section flags
+ */
+ENTRY(cpu_resume_mmu)
+	adr	r4, cpu_resume_turn_mmu_on
+	mov	r4, r4, lsr #20
+	orr	r3, r3, r4, lsl #20
+	ldr	r5, [r2, r4, lsl #2]	@ save old mapping
+	str	r3, [r2, r4, lsl #2]	@ setup 1:1 mapping for mmu code
+	sub	r2, r2, r1
+	ldr	r3, =cpu_resume_after_mmu
+	bic	r1, r0, #CR_C		@ ensure D-cache is disabled
+	b	cpu_resume_turn_mmu_on
+ENDPROC(cpu_resume_mmu)
+	.ltorg
+	.align	5
+cpu_resume_turn_mmu_on:
+	mcr	p15, 0, r1, c1, c0, 0	@ turn on MMU, I-cache, etc
+	mrc	p15, 0, r1, c0, c0, 0	@ read id reg
+	mov	r1, r1
+	mov	r1, r1
+	mov	pc, r3			@ jump to virtual address
+ENDPROC(cpu_resume_turn_mmu_on)
+cpu_resume_after_mmu:
+	str	r5, [r2, r4, lsl #2]	@ restore old mapping
+	mcr	p15, 0, r0, c1, c0, 0	@ turn on D-cache
+	mov	pc, lr
+ENDPROC(cpu_resume_after_mmu)
+
+/*
+ * Note: Yes, part of the following code is located into the .data section.
+ *       This is to allow sleep_save_sp to be accessed with a relative load
+ *       while we can't rely on any MMU translation.  We could have put
+ *       sleep_save_sp in the .text section as well, but some setups might
+ *       insist on it to be truly read-only.
+ */
+	.data
+	.align
+ENTRY(cpu_resume)
+#ifdef CONFIG_SMP
+	adr	r0, sleep_save_sp
+	ALT_SMP(mrc p15, 0, r1, c0, c0, 5)
+	ALT_UP(mov r1, #0)
+	and	r1, r1, #15
+	ldr	r0, [r0, r1, lsl #2]	@ stack phys addr
+#else
+	ldr	r0, sleep_save_sp	@ stack phys addr
+#endif
+	msr	cpsr_c, #PSR_I_BIT | PSR_F_BIT | SVC_MODE @ set SVC, irqs off
+#ifdef MULTI_CPU
+	ldmia	r0!, {r1, sp, lr, pc}	@ load v:p, stack, return fn, resume fn
+#else
+	ldmia	r0!, {r1, sp, lr}	@ load v:p, stack, return fn
+	b	cpu_do_resume
+#endif
+ENDPROC(cpu_resume)
+
+sleep_save_sp:
+	.rept	CONFIG_NR_CPUS
+	.long	0				@ preserve stack phys ptr here
+	.endr
diff --git a/arch/arm/kernel/smp_scu.c b/arch/arm/kernel/smp_scu.c
index 9ab4149..a1e757c 100644
--- a/arch/arm/kernel/smp_scu.c
+++ b/arch/arm/kernel/smp_scu.c
@@ -50,3 +50,26 @@
 	 */
 	flush_cache_all();
 }
+
+/*
+ * Set the executing CPUs power mode as defined.  This will be in
+ * preparation for it executing a WFI instruction.
+ *
+ * This function must be called with preemption disabled, and as it
+ * has the side effect of disabling coherency, caches must have been
+ * flushed.  Interrupts must also have been disabled.
+ */
+int scu_power_mode(void __iomem *scu_base, unsigned int mode)
+{
+	unsigned int val;
+	int cpu = smp_processor_id();
+
+	if (mode > 3 || mode == 1 || cpu > 3)
+		return -EINVAL;
+
+	val = __raw_readb(scu_base + SCU_CPU_STATUS + cpu) & ~0x03;
+	val |= mode;
+	__raw_writeb(val, scu_base + SCU_CPU_STATUS + cpu);
+
+	return 0;
+}
diff --git a/arch/arm/mach-at91/board-snapper9260.c b/arch/arm/mach-at91/board-snapper9260.c
index 0a99b3c..17f7d9b 100644
--- a/arch/arm/mach-at91/board-snapper9260.c
+++ b/arch/arm/mach-at91/board-snapper9260.c
@@ -153,6 +153,7 @@
 	{
 		/* RTC */
 		I2C_BOARD_INFO("isl1208", 0x6f),
+		.irq = gpio_to_irq(AT91_PIN_PA31),
 	},
 };
 
diff --git a/arch/arm/mach-at91/include/mach/gpio.h b/arch/arm/mach-at91/include/mach/gpio.h
index bfdd8ab..ddeb645 100644
--- a/arch/arm/mach-at91/include/mach/gpio.h
+++ b/arch/arm/mach-at91/include/mach/gpio.h
@@ -220,15 +220,8 @@
 #define gpio_set_value	__gpio_set_value
 #define gpio_cansleep	__gpio_cansleep
 
-static inline int gpio_to_irq(unsigned gpio)
-{
-	return gpio;
-}
-
-static inline int irq_to_gpio(unsigned irq)
-{
-	return irq;
-}
+#define gpio_to_irq(gpio) (gpio)
+#define irq_to_gpio(irq)  (irq)
 
 #endif	/* __ASSEMBLY__ */
 
diff --git a/arch/arm/mach-ep93xx/edb93xx.c b/arch/arm/mach-ep93xx/edb93xx.c
index 4b04316..9969bb1 100644
--- a/arch/arm/mach-ep93xx/edb93xx.c
+++ b/arch/arm/mach-ep93xx/edb93xx.c
@@ -30,8 +30,13 @@
 #include <linux/gpio.h>
 #include <linux/i2c.h>
 #include <linux/i2c-gpio.h>
+#include <linux/spi/spi.h>
+
+#include <sound/cs4271.h>
 
 #include <mach/hardware.h>
+#include <mach/fb.h>
+#include <mach/ep93xx_spi.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -93,6 +98,83 @@
 
 
 /*************************************************************************
+ * EDB93xx SPI peripheral handling
+ *************************************************************************/
+static struct cs4271_platform_data edb93xx_cs4271_data = {
+	.gpio_nreset	= -EINVAL,	/* filled in later */
+};
+
+static int edb93xx_cs4271_hw_setup(struct spi_device *spi)
+{
+	return gpio_request_one(EP93XX_GPIO_LINE_EGPIO6,
+				GPIOF_OUT_INIT_HIGH, spi->modalias);
+}
+
+static void edb93xx_cs4271_hw_cleanup(struct spi_device *spi)
+{
+	gpio_free(EP93XX_GPIO_LINE_EGPIO6);
+}
+
+static void edb93xx_cs4271_hw_cs_control(struct spi_device *spi, int value)
+{
+	gpio_set_value(EP93XX_GPIO_LINE_EGPIO6, value);
+}
+
+static struct ep93xx_spi_chip_ops edb93xx_cs4271_hw = {
+	.setup		= edb93xx_cs4271_hw_setup,
+	.cleanup	= edb93xx_cs4271_hw_cleanup,
+	.cs_control	= edb93xx_cs4271_hw_cs_control,
+};
+
+static struct spi_board_info edb93xx_spi_board_info[] __initdata = {
+	{
+		.modalias		= "cs4271",
+		.platform_data		= &edb93xx_cs4271_data,
+		.controller_data	= &edb93xx_cs4271_hw,
+		.max_speed_hz		= 6000000,
+		.bus_num		= 0,
+		.chip_select		= 0,
+		.mode			= SPI_MODE_3,
+	},
+};
+
+static struct ep93xx_spi_info edb93xx_spi_info __initdata = {
+	.num_chipselect	= ARRAY_SIZE(edb93xx_spi_board_info),
+};
+
+static void __init edb93xx_register_spi(void)
+{
+	if (machine_is_edb9301() || machine_is_edb9302())
+		edb93xx_cs4271_data.gpio_nreset = EP93XX_GPIO_LINE_EGPIO1;
+	else if (machine_is_edb9302a() || machine_is_edb9307a())
+		edb93xx_cs4271_data.gpio_nreset = EP93XX_GPIO_LINE_H(2);
+	else if (machine_is_edb9315a())
+		edb93xx_cs4271_data.gpio_nreset = EP93XX_GPIO_LINE_EGPIO14;
+
+	ep93xx_register_spi(&edb93xx_spi_info, edb93xx_spi_board_info,
+			    ARRAY_SIZE(edb93xx_spi_board_info));
+}
+
+
+/*************************************************************************
+ * EDB93xx I2S
+ *************************************************************************/
+static int __init edb93xx_has_audio(void)
+{
+	return (machine_is_edb9301() || machine_is_edb9302() ||
+		machine_is_edb9302a() || machine_is_edb9307a() ||
+		machine_is_edb9315a());
+}
+
+static void __init edb93xx_register_i2s(void)
+{
+	if (edb93xx_has_audio()) {
+		ep93xx_register_i2s();
+	}
+}
+
+
+/*************************************************************************
  * EDB93xx pwm
  *************************************************************************/
 static void __init edb93xx_register_pwm(void)
@@ -111,13 +193,47 @@
 }
 
 
+/*************************************************************************
+ * EDB93xx framebuffer
+ *************************************************************************/
+static struct ep93xxfb_mach_info __initdata edb93xxfb_info = {
+	.num_modes	= EP93XXFB_USE_MODEDB,
+	.bpp		= 16,
+	.flags		= 0,
+};
+
+static int __init edb93xx_has_fb(void)
+{
+	/* These platforms have an ep93xx with video capability */
+	return machine_is_edb9307() || machine_is_edb9307a() ||
+	       machine_is_edb9312() || machine_is_edb9315() ||
+	       machine_is_edb9315a();
+}
+
+static void __init edb93xx_register_fb(void)
+{
+	if (!edb93xx_has_fb())
+		return;
+
+	if (machine_is_edb9307a() || machine_is_edb9315a())
+		edb93xxfb_info.flags |= EP93XXFB_USE_SDCSN0;
+	else
+		edb93xxfb_info.flags |= EP93XXFB_USE_SDCSN3;
+
+	ep93xx_register_fb(&edb93xxfb_info);
+}
+
+
 static void __init edb93xx_init_machine(void)
 {
 	ep93xx_init_devices();
 	edb93xx_register_flash();
 	ep93xx_register_eth(&edb93xx_eth_data, 1);
 	edb93xx_register_i2c();
+	edb93xx_register_spi();
+	edb93xx_register_i2s();
 	edb93xx_register_pwm();
+	edb93xx_register_fb();
 }
 
 
diff --git a/arch/arm/mach-ep93xx/gpio.c b/arch/arm/mach-ep93xx/gpio.c
index bec34b8..a889fa7 100644
--- a/arch/arm/mach-ep93xx/gpio.c
+++ b/arch/arm/mach-ep93xx/gpio.c
@@ -61,7 +61,7 @@
 	gpio_int_unmasked[line >> 3] &= ~(1 << (line & 7));
 }
 
-void ep93xx_gpio_int_debounce(unsigned int irq, int enable)
+static void ep93xx_gpio_int_debounce(unsigned int irq, bool enable)
 {
 	int line = irq_to_gpio(irq);
 	int port = line >> 3;
@@ -75,7 +75,6 @@
 	__raw_writeb(gpio_int_debounce[port],
 		EP93XX_GPIO_REG(int_debounce_register_offset[port]));
 }
-EXPORT_SYMBOL(ep93xx_gpio_int_debounce);
 
 static void ep93xx_gpio_ab_irq_handler(unsigned int irq, struct irq_desc *desc)
 {
@@ -335,6 +334,20 @@
 	local_irq_restore(flags);
 }
 
+static int ep93xx_gpio_set_debounce(struct gpio_chip *chip,
+				    unsigned offset, unsigned debounce)
+{
+	int gpio = chip->base + offset;
+	int irq = gpio_to_irq(gpio);
+
+	if (irq < 0)
+		return -EINVAL;
+
+	ep93xx_gpio_int_debounce(irq, debounce ? true : false);
+
+	return 0;
+}
+
 static void ep93xx_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
 {
 	struct ep93xx_gpio_chip *ep93xx_chip = to_ep93xx_gpio_chip(chip);
@@ -434,6 +447,18 @@
 				 EP93XX_SYSCON_DEVCFG_GONIDE |
 				 EP93XX_SYSCON_DEVCFG_HONIDE);
 
-	for (i = 0; i < ARRAY_SIZE(ep93xx_gpio_banks); i++)
-		gpiochip_add(&ep93xx_gpio_banks[i].chip);
+	for (i = 0; i < ARRAY_SIZE(ep93xx_gpio_banks); i++) {
+		struct gpio_chip *chip = &ep93xx_gpio_banks[i].chip;
+
+		/*
+		 * Ports A, B, and F support input debouncing when
+		 * used as interrupts.
+		 */
+		if (!strcmp(chip->label, "A") ||
+		    !strcmp(chip->label, "B") ||
+		    !strcmp(chip->label, "F"))
+			chip->set_debounce = ep93xx_gpio_set_debounce;
+
+		gpiochip_add(chip);
+	}
 }
diff --git a/arch/arm/mach-ep93xx/include/mach/gpio.h b/arch/arm/mach-ep93xx/include/mach/gpio.h
index c991b14..c57152c 100644
--- a/arch/arm/mach-ep93xx/include/mach/gpio.h
+++ b/arch/arm/mach-ep93xx/include/mach/gpio.h
@@ -99,8 +99,6 @@
 /* maximum value for irq capable line identifiers */
 #define EP93XX_GPIO_LINE_MAX_IRQ	EP93XX_GPIO_LINE_F(7)
 
-extern void ep93xx_gpio_int_debounce(unsigned int irq, int enable);
-
 /* new generic GPIO API - see Documentation/gpio.txt */
 
 #include <asm-generic/gpio.h>
diff --git a/arch/arm/mach-footbridge/dc21285-timer.c b/arch/arm/mach-footbridge/dc21285-timer.c
index bc5e83f..a921fe9 100644
--- a/arch/arm/mach-footbridge/dc21285-timer.c
+++ b/arch/arm/mach-footbridge/dc21285-timer.c
@@ -4,10 +4,11 @@
  *  Copyright (C) 1998 Russell King.
  *  Copyright (C) 1998 Phil Blundell
  */
+#include <linux/clockchips.h>
+#include <linux/clocksource.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
-#include <linux/spinlock.h>
 
 #include <asm/irq.h>
 
@@ -16,32 +17,76 @@
 
 #include "common.h"
 
-/*
- * Footbridge timer 1 support.
- */
-static unsigned long timer1_latch;
-
-static unsigned long timer1_gettimeoffset (void)
+static cycle_t cksrc_dc21285_read(struct clocksource *cs)
 {
-	unsigned long value = timer1_latch - *CSR_TIMER1_VALUE;
-
-	return ((tick_nsec / 1000) * value) / timer1_latch;
+	return cs->mask - *CSR_TIMER2_VALUE;
 }
 
-static irqreturn_t
-timer1_interrupt(int irq, void *dev_id)
+static int cksrc_dc21285_enable(struct clocksource *cs)
 {
+	*CSR_TIMER2_LOAD = cs->mask;
+	*CSR_TIMER2_CLR = 0;
+	*CSR_TIMER2_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_DIV16;
+	return 0;
+}
+
+static int cksrc_dc21285_disable(struct clocksource *cs)
+{
+	*CSR_TIMER2_CNTL = 0;
+}
+
+static struct clocksource cksrc_dc21285 = {
+	.name		= "dc21285_timer2",
+	.rating		= 200,
+	.read		= cksrc_dc21285_read,
+	.enable		= cksrc_dc21285_enable,
+	.disable	= cksrc_dc21285_disable,
+	.mask		= CLOCKSOURCE_MASK(24),
+	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static void ckevt_dc21285_set_mode(enum clock_event_mode mode,
+	struct clock_event_device *c)
+{
+	switch (mode) {
+	case CLOCK_EVT_MODE_RESUME:
+	case CLOCK_EVT_MODE_PERIODIC:
+		*CSR_TIMER1_CLR = 0;
+		*CSR_TIMER1_LOAD = (mem_fclk_21285 + 8 * HZ) / (16 * HZ);
+		*CSR_TIMER1_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_AUTORELOAD |
+				   TIMER_CNTL_DIV16;
+		break;
+
+	default:
+		*CSR_TIMER1_CNTL = 0;
+		break;
+	}
+}
+
+static struct clock_event_device ckevt_dc21285 = {
+	.name		= "dc21285_timer1",
+	.features	= CLOCK_EVT_FEAT_PERIODIC,
+	.rating		= 200,
+	.irq		= IRQ_TIMER1,
+	.set_mode	= ckevt_dc21285_set_mode,
+};
+
+static irqreturn_t timer1_interrupt(int irq, void *dev_id)
+{
+	struct clock_event_device *ce = dev_id;
+
 	*CSR_TIMER1_CLR = 0;
 
-	timer_tick();
+	ce->event_handler(ce);
 
 	return IRQ_HANDLED;
 }
 
 static struct irqaction footbridge_timer_irq = {
-	.name		= "Timer1 timer tick",
+	.name		= "dc21285_timer1",
 	.handler	= timer1_interrupt,
 	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
+	.dev_id		= &ckevt_dc21285,
 };
 
 /*
@@ -49,16 +94,19 @@
  */
 static void __init footbridge_timer_init(void)
 {
-	timer1_latch = (mem_fclk_21285 + 8 * HZ) / (16 * HZ);
+	struct clock_event_device *ce = &ckevt_dc21285;
 
-	*CSR_TIMER1_CLR  = 0;
-	*CSR_TIMER1_LOAD = timer1_latch;
-	*CSR_TIMER1_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_AUTORELOAD | TIMER_CNTL_DIV16;
+	clocksource_register_hz(&cksrc_dc21285, (mem_fclk_21285 + 8) / 16);
 
-	setup_irq(IRQ_TIMER1, &footbridge_timer_irq);
+	setup_irq(ce->irq, &footbridge_timer_irq);
+
+	clockevents_calc_mult_shift(ce, mem_fclk_21285, 5);
+	ce->max_delta_ns = clockevent_delta2ns(0xffffff, ce);
+	ce->min_delta_ns = clockevent_delta2ns(0x000004, ce);
+
+	clockevents_register_device(ce);
 }
 
 struct sys_timer footbridge_timer = {
 	.init		= footbridge_timer_init,
-	.offset		= timer1_gettimeoffset,
 };
diff --git a/arch/arm/mach-footbridge/isa-timer.c b/arch/arm/mach-footbridge/isa-timer.c
index f488fa2..441c6ce 100644
--- a/arch/arm/mach-footbridge/isa-timer.c
+++ b/arch/arm/mach-footbridge/isa-timer.c
@@ -4,10 +4,13 @@
  *  Copyright (C) 1998 Russell King.
  *  Copyright (C) 1998 Phil Blundell
  */
+#include <linux/clockchips.h>
+#include <linux/clocksource.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/io.h>
+#include <linux/timex.h>
 
 #include <asm/irq.h>
 
@@ -15,77 +18,115 @@
 
 #include "common.h"
 
-/*
- * ISA timer tick support
- */
-#define mSEC_10_from_14 ((14318180 + 100) / 200)
+#define PIT_MODE	0x43
+#define PIT_CH0		0x40
 
-static unsigned long isa_gettimeoffset(void)
+#define PIT_LATCH	((PIT_TICK_RATE + HZ / 2) / HZ)
+
+static cycle_t pit_read(struct clocksource *cs)
 {
+	unsigned long flags;
+	static int old_count;
+	static u32 old_jifs;
 	int count;
+	u32 jifs;
 
-	static int count_p = (mSEC_10_from_14/6);    /* for the first call after boot */
-	static unsigned long jiffies_p = 0;
+	raw_local_irq_save(flags);
 
-	/*
-	 * cache volatile jiffies temporarily; we have IRQs turned off. 
-	 */
-	unsigned long jiffies_t;
+	jifs = jiffies;
+	outb_p(0x00, PIT_MODE);		/* latch the count */
+	count = inb_p(PIT_CH0);		/* read the latched count */
+	count |= inb_p(PIT_CH0) << 8;
 
-	/* timer count may underflow right here */
-	outb_p(0x00, 0x43);	/* latch the count ASAP */
+	if (count > old_count && jifs == old_jifs)
+		count = old_count;
 
-	count = inb_p(0x40);	/* read the latched count */
+	old_count = count;
+	old_jifs = jifs;
 
-	/*
-	 * We do this guaranteed double memory access instead of a _p 
-	 * postfix in the previous port access. Wheee, hackady hack
-	 */
- 	jiffies_t = jiffies;
+	raw_local_irq_restore(flags);
 
-	count |= inb_p(0x40) << 8;
+	count = (PIT_LATCH - 1) - count;
 
-	/* Detect timer underflows.  If we haven't had a timer tick since 
-	   the last time we were called, and time is apparently going
-	   backwards, the counter must have wrapped during this routine. */
-	if ((jiffies_t == jiffies_p) && (count > count_p))
-		count -= (mSEC_10_from_14/6);
-	else
-		jiffies_p = jiffies_t;
-
-	count_p = count;
-
-	count = (((mSEC_10_from_14/6)-1) - count) * (tick_nsec / 1000);
-	count = (count + (mSEC_10_from_14/6)/2) / (mSEC_10_from_14/6);
-
-	return count;
+	return (cycle_t)(jifs * PIT_LATCH) + count;
 }
 
-static irqreturn_t
-isa_timer_interrupt(int irq, void *dev_id)
+static struct clocksource pit_cs = {
+	.name		= "pit",
+	.rating		= 110,
+	.read		= pit_read,
+	.mask		= CLOCKSOURCE_MASK(32),
+};
+
+static void pit_set_mode(enum clock_event_mode mode,
+	struct clock_event_device *evt)
 {
-	timer_tick();
+	unsigned long flags;
+
+	raw_local_irq_save(flags);
+
+	switch (mode) {
+	case CLOCK_EVT_MODE_PERIODIC:
+		outb_p(0x34, PIT_MODE);
+		outb_p(PIT_LATCH & 0xff, PIT_CH0);
+		outb_p(PIT_LATCH >> 8, PIT_CH0);
+		break;
+
+	case CLOCK_EVT_MODE_SHUTDOWN:
+	case CLOCK_EVT_MODE_UNUSED:
+		outb_p(0x30, PIT_MODE);
+		outb_p(0, PIT_CH0);
+		outb_p(0, PIT_CH0);
+		break;
+
+	case CLOCK_EVT_MODE_ONESHOT:
+	case CLOCK_EVT_MODE_RESUME:
+		break;
+	}
+	local_irq_restore(flags);
+}
+
+static int pit_set_next_event(unsigned long delta,
+	struct clock_event_device *evt)
+{
+	return 0;
+}
+
+static struct clock_event_device pit_ce = {
+	.name		= "pit",
+	.features	= CLOCK_EVT_FEAT_PERIODIC,
+	.set_mode	= pit_set_mode,
+	.set_next_event	= pit_set_next_event,
+	.shift		= 32,
+};
+
+static irqreturn_t pit_timer_interrupt(int irq, void *dev_id)
+{
+	struct clock_event_device *ce = dev_id;
+	ce->event_handler(ce);
 	return IRQ_HANDLED;
 }
 
-static struct irqaction isa_timer_irq = {
-	.name		= "ISA timer tick",
-	.handler	= isa_timer_interrupt,
+static struct irqaction pit_timer_irq = {
+	.name		= "pit",
+	.handler	= pit_timer_interrupt,
 	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
+	.dev_id		= &pit_ce,
 };
 
 static void __init isa_timer_init(void)
 {
-	/* enable PIT timer */
-	/* set for periodic (4) and LSB/MSB write (0x30) */
-	outb(0x34, 0x43);
-	outb((mSEC_10_from_14/6) & 0xFF, 0x40);
-	outb((mSEC_10_from_14/6) >> 8, 0x40);
+	pit_ce.cpumask = cpumask_of(smp_processor_id());
+	pit_ce.mult = div_sc(PIT_TICK_RATE, NSEC_PER_SEC, pit_ce.shift);
+	pit_ce.max_delta_ns = clockevent_delta2ns(0x7fff, &pit_ce);
+	pit_ce.min_delta_ns = clockevent_delta2ns(0x000f, &pit_ce);
 
-	setup_irq(IRQ_ISA_TIMER, &isa_timer_irq);
+	clocksource_register_hz(&pit_cs, PIT_TICK_RATE);
+
+	setup_irq(pit_ce.irq, &pit_timer_irq);
+	clockevents_register_device(&pit_ce);
 }
 
 struct sys_timer isa_timer = {
 	.init		= isa_timer_init,
-	.offset		= isa_gettimeoffset,
 };
diff --git a/arch/arm/mach-gemini/board-nas4220b.c b/arch/arm/mach-gemini/board-nas4220b.c
index 2ba096d..0cf7a07 100644
--- a/arch/arm/mach-gemini/board-nas4220b.c
+++ b/arch/arm/mach-gemini/board-nas4220b.c
@@ -98,6 +98,7 @@
 	platform_register_pflash(SZ_16M, NULL, 0);
 	platform_device_register(&ib4220b_led_device);
 	platform_device_register(&ib4220b_key_device);
+	platform_register_rtc();
 }
 
 MACHINE_START(NAS4220B, "Raidsonic NAS IB-4220-B")
diff --git a/arch/arm/mach-gemini/board-rut1xx.c b/arch/arm/mach-gemini/board-rut1xx.c
index a9a0d8b..4fa09af 100644
--- a/arch/arm/mach-gemini/board-rut1xx.c
+++ b/arch/arm/mach-gemini/board-rut1xx.c
@@ -82,6 +82,7 @@
 	platform_register_pflash(SZ_8M, NULL, 0);
 	platform_device_register(&rut1xx_leds);
 	platform_device_register(&rut1xx_keys_device);
+	platform_register_rtc();
 }
 
 MACHINE_START(RUT100, "Teltonika RUT100")
diff --git a/arch/arm/mach-gemini/board-wbd111.c b/arch/arm/mach-gemini/board-wbd111.c
index 8b88d50..af7b68a 100644
--- a/arch/arm/mach-gemini/board-wbd111.c
+++ b/arch/arm/mach-gemini/board-wbd111.c
@@ -130,6 +130,7 @@
 				 wbd111_num_partitions);
 	platform_device_register(&wbd111_leds_device);
 	platform_device_register(&wbd111_keys_device);
+	platform_register_rtc();
 }
 
 MACHINE_START(WBD111, "Wiliboard WBD-111")
diff --git a/arch/arm/mach-gemini/board-wbd222.c b/arch/arm/mach-gemini/board-wbd222.c
index 1eebcec..99e5bbe 100644
--- a/arch/arm/mach-gemini/board-wbd222.c
+++ b/arch/arm/mach-gemini/board-wbd222.c
@@ -130,6 +130,7 @@
 		wbd222_num_partitions);
 	platform_device_register(&wbd222_leds_device);
 	platform_device_register(&wbd222_keys_device);
+	platform_register_rtc();
 }
 
 MACHINE_START(WBD222, "Wiliboard WBD-222")
diff --git a/arch/arm/mach-gemini/common.h b/arch/arm/mach-gemini/common.h
index 9392834..7670c39 100644
--- a/arch/arm/mach-gemini/common.h
+++ b/arch/arm/mach-gemini/common.h
@@ -18,6 +18,7 @@
 extern void gemini_init_irq(void);
 extern void gemini_timer_init(void);
 extern void gemini_gpio_init(void);
+extern void platform_register_rtc(void);
 
 /* Common platform devices registration functions */
 extern int platform_register_uart(void);
diff --git a/arch/arm/mach-gemini/devices.c b/arch/arm/mach-gemini/devices.c
index 6b52525..5cff298 100644
--- a/arch/arm/mach-gemini/devices.c
+++ b/arch/arm/mach-gemini/devices.c
@@ -90,3 +90,29 @@
 
 	return platform_device_register(&pflash_device);
 }
+
+static struct resource gemini_rtc_resources[] = {
+	[0] = {
+		.start  = GEMINI_RTC_BASE,
+		.end    = GEMINI_RTC_BASE + 0x24,
+		.flags  = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start  = IRQ_RTC,
+		.end    = IRQ_RTC,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device gemini_rtc_device = {
+	.name		= "rtc-gemini",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(gemini_rtc_resources),
+	.resource	= gemini_rtc_resources,
+};
+
+int __init platform_register_rtc(void)
+{
+	return platform_device_register(&gemini_rtc_device);
+}
+
diff --git a/arch/arm/mach-mxs/gpio.c b/arch/arm/mach-mxs/gpio.c
index cb0c0e8..61991e4 100644
--- a/arch/arm/mach-mxs/gpio.c
+++ b/arch/arm/mach-mxs/gpio.c
@@ -68,29 +68,29 @@
 	}
 }
 
-static void mxs_gpio_ack_irq(u32 irq)
+static void mxs_gpio_ack_irq(struct irq_data *d)
 {
-	u32 gpio = irq_to_gpio(irq);
+	u32 gpio = irq_to_gpio(d->irq);
 	clear_gpio_irqstatus(&mxs_gpio_ports[gpio / 32], gpio & 0x1f);
 }
 
-static void mxs_gpio_mask_irq(u32 irq)
+static void mxs_gpio_mask_irq(struct irq_data *d)
 {
-	u32 gpio = irq_to_gpio(irq);
+	u32 gpio = irq_to_gpio(d->irq);
 	set_gpio_irqenable(&mxs_gpio_ports[gpio / 32], gpio & 0x1f, 0);
 }
 
-static void mxs_gpio_unmask_irq(u32 irq)
+static void mxs_gpio_unmask_irq(struct irq_data *d)
 {
-	u32 gpio = irq_to_gpio(irq);
+	u32 gpio = irq_to_gpio(d->irq);
 	set_gpio_irqenable(&mxs_gpio_ports[gpio / 32], gpio & 0x1f, 1);
 }
 
 static int mxs_gpio_get(struct gpio_chip *chip, unsigned offset);
 
-static int mxs_gpio_set_irq_type(u32 irq, u32 type)
+static int mxs_gpio_set_irq_type(struct irq_data *d, unsigned int type)
 {
-	u32 gpio = irq_to_gpio(irq);
+	u32 gpio = irq_to_gpio(d->irq);
 	u32 pin_mask = 1 << (gpio & 31);
 	struct mxs_gpio_port *port = &mxs_gpio_ports[gpio / 32];
 	void __iomem *pin_addr;
@@ -160,9 +160,9 @@
  * @param  enable       enable as wake-up if equal to non-zero
  * @return       This function returns 0 on success.
  */
-static int mxs_gpio_set_wake_irq(u32 irq, u32 enable)
+static int mxs_gpio_set_wake_irq(struct irq_data *d, unsigned int enable)
 {
-	u32 gpio = irq_to_gpio(irq);
+	u32 gpio = irq_to_gpio(d->irq);
 	u32 gpio_idx = gpio & 0x1f;
 	struct mxs_gpio_port *port = &mxs_gpio_ports[gpio / 32];
 
@@ -182,11 +182,11 @@
 }
 
 static struct irq_chip gpio_irq_chip = {
-	.ack = mxs_gpio_ack_irq,
-	.mask = mxs_gpio_mask_irq,
-	.unmask = mxs_gpio_unmask_irq,
-	.set_type = mxs_gpio_set_irq_type,
-	.set_wake = mxs_gpio_set_wake_irq,
+	.irq_ack = mxs_gpio_ack_irq,
+	.irq_mask = mxs_gpio_mask_irq,
+	.irq_unmask = mxs_gpio_unmask_irq,
+	.irq_set_type = mxs_gpio_set_irq_type,
+	.irq_set_wake = mxs_gpio_set_wake_irq,
 };
 
 static void mxs_set_gpio_direction(struct gpio_chip *chip, unsigned offset,
diff --git a/arch/arm/mach-mxs/icoll.c b/arch/arm/mach-mxs/icoll.c
index 5dd43ba..0f4c120 100644
--- a/arch/arm/mach-mxs/icoll.c
+++ b/arch/arm/mach-mxs/icoll.c
@@ -34,7 +34,7 @@
 
 static void __iomem *icoll_base = MXS_IO_ADDRESS(MXS_ICOLL_BASE_ADDR);
 
-static void icoll_ack_irq(unsigned int irq)
+static void icoll_ack_irq(struct irq_data *d)
 {
 	/*
 	 * The Interrupt Collector is able to prioritize irqs.
@@ -45,22 +45,22 @@
 			icoll_base + HW_ICOLL_LEVELACK);
 }
 
-static void icoll_mask_irq(unsigned int irq)
+static void icoll_mask_irq(struct irq_data *d)
 {
 	__raw_writel(BM_ICOLL_INTERRUPTn_ENABLE,
-			icoll_base + HW_ICOLL_INTERRUPTn_CLR(irq));
+			icoll_base + HW_ICOLL_INTERRUPTn_CLR(d->irq));
 }
 
-static void icoll_unmask_irq(unsigned int irq)
+static void icoll_unmask_irq(struct irq_data *d)
 {
 	__raw_writel(BM_ICOLL_INTERRUPTn_ENABLE,
-			icoll_base + HW_ICOLL_INTERRUPTn_SET(irq));
+			icoll_base + HW_ICOLL_INTERRUPTn_SET(d->irq));
 }
 
 static struct irq_chip mxs_icoll_chip = {
-	.ack = icoll_ack_irq,
-	.mask = icoll_mask_irq,
-	.unmask = icoll_unmask_irq,
+	.irq_ack = icoll_ack_irq,
+	.irq_mask = icoll_mask_irq,
+	.irq_unmask = icoll_unmask_irq,
 };
 
 void __init icoll_init_irq(void)
diff --git a/arch/arm/mach-omap1/pm.h b/arch/arm/mach-omap1/pm.h
index 56a6479..cd926dc 100644
--- a/arch/arm/mach-omap1/pm.h
+++ b/arch/arm/mach-omap1/pm.h
@@ -123,9 +123,9 @@
 extern void omap1_pm_idle(void);
 extern void omap1_pm_suspend(void);
 
-extern void omap7xx_cpu_suspend(unsigned short, unsigned short);
-extern void omap1510_cpu_suspend(unsigned short, unsigned short);
-extern void omap1610_cpu_suspend(unsigned short, unsigned short);
+extern void omap7xx_cpu_suspend(unsigned long, unsigned long);
+extern void omap1510_cpu_suspend(unsigned long, unsigned long);
+extern void omap1610_cpu_suspend(unsigned long, unsigned long);
 extern void omap7xx_idle_loop_suspend(void);
 extern void omap1510_idle_loop_suspend(void);
 extern void omap1610_idle_loop_suspend(void);
diff --git a/arch/arm/mach-omap1/sleep.S b/arch/arm/mach-omap1/sleep.S
index ef771ce8..c875bdc 100644
--- a/arch/arm/mach-omap1/sleep.S
+++ b/arch/arm/mach-omap1/sleep.S
@@ -58,6 +58,7 @@
  */
 
 #if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
+	.align	3
 ENTRY(omap7xx_cpu_suspend)
 
 	@ save registers on stack
@@ -137,6 +138,7 @@
 #endif /* CONFIG_ARCH_OMAP730 || CONFIG_ARCH_OMAP850 */
 
 #ifdef CONFIG_ARCH_OMAP15XX
+	.align	3
 ENTRY(omap1510_cpu_suspend)
 
 	@ save registers on stack
@@ -211,6 +213,7 @@
 #endif /* CONFIG_ARCH_OMAP15XX */
 
 #if defined(CONFIG_ARCH_OMAP16XX)
+	.align	3
 ENTRY(omap1610_cpu_suspend)
 
 	@ save registers on stack
diff --git a/arch/arm/mach-omap1/sram.S b/arch/arm/mach-omap1/sram.S
index 7724e52..692587d 100644
--- a/arch/arm/mach-omap1/sram.S
+++ b/arch/arm/mach-omap1/sram.S
@@ -18,6 +18,7 @@
 /*
  * Reprograms ULPD and CKCTL.
  */
+	.align	3
 ENTRY(omap1_sram_reprogram_clock)
 	stmfd	sp!, {r0 - r12, lr}		@ save registers on stack
 
diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h
index 1c1b0ab..39580e6 100644
--- a/arch/arm/mach-omap2/pm.h
+++ b/arch/arm/mach-omap2/pm.h
@@ -92,7 +92,7 @@
 extern void omap24xx_cpu_suspend(u32 dll_ctrl, void __iomem *sdrc_dlla_ctrl,
 					void __iomem *sdrc_power);
 extern void omap34xx_cpu_suspend(u32 *addr, int save_state);
-extern void save_secure_ram_context(u32 *addr);
+extern int save_secure_ram_context(u32 *addr);
 extern void omap3_save_scratchpad_contents(void);
 
 extern unsigned int omap24xx_idle_loop_suspend_sz;
diff --git a/arch/arm/mach-omap2/sleep24xx.S b/arch/arm/mach-omap2/sleep24xx.S
index c7780cc..b5071a4 100644
--- a/arch/arm/mach-omap2/sleep24xx.S
+++ b/arch/arm/mach-omap2/sleep24xx.S
@@ -47,6 +47,7 @@
  * Note: This code get's copied to internal SRAM at boot. When the OMAP
  *	 wakes up it continues execution at the point it went to sleep.
  */
+	.align	3
 ENTRY(omap24xx_idle_loop_suspend)
 	stmfd	sp!, {r0, lr}		@ save registers on stack
 	mov	r0, #0			@ clear for mcr setup
@@ -82,6 +83,7 @@
  * The DLL load value is not kept in RETENTION or OFF.	It needs to be restored
  * at wake
  */
+	.align	3
 ENTRY(omap24xx_cpu_suspend)
 	stmfd	sp!, {r0 - r12, lr}	@ save registers on stack
 	mov	r3, #0x0		@ clear for mcr call
diff --git a/arch/arm/mach-omap2/sleep34xx.S b/arch/arm/mach-omap2/sleep34xx.S
index 98d8232..951a0be 100644
--- a/arch/arm/mach-omap2/sleep34xx.S
+++ b/arch/arm/mach-omap2/sleep34xx.S
@@ -118,6 +118,7 @@
 
 	.text
 /* Function to call rom code to save secure ram context */
+	.align	3
 ENTRY(save_secure_ram_context)
 	stmfd	sp!, {r1-r12, lr}	@ save registers on stack
 	adr	r3, api_params		@ r3 points to parameters
@@ -169,6 +170,7 @@
  *   depending on the low power mode (non-OFF vs OFF modes),
  *   cf. 'Resume path for xxx mode' comments.
  */
+	.align	3
 ENTRY(omap34xx_cpu_suspend)
 	stmfd	sp!, {r0-r12, lr}	@ save registers on stack
 
diff --git a/arch/arm/mach-omap2/sram242x.S b/arch/arm/mach-omap2/sram242x.S
index 055310c..ff9b9db 100644
--- a/arch/arm/mach-omap2/sram242x.S
+++ b/arch/arm/mach-omap2/sram242x.S
@@ -39,6 +39,7 @@
 
 	.text
 
+	.align	3
 ENTRY(omap242x_sram_ddr_init)
 	stmfd	sp!, {r0 - r12, lr}	@ save registers on stack
 
@@ -143,6 +144,7 @@
  * r0 = [PRCM_FULL | PRCM_HALF] r1 = SDRC_DLLA_CTRL value r2 = [DDR | SDR]
  * PRCM_FULL = 2, PRCM_HALF = 1, DDR = 1, SDR = 0
  */
+	.align	3
 ENTRY(omap242x_sram_reprogram_sdrc)
 	stmfd	sp!, {r0 - r10, lr}	@ save registers on stack
 	mov	r3, #0x0		@ clear for mrc call
@@ -238,6 +240,7 @@
 /*
  * Set dividers and pll. Also recalculate DLL value for DDR and unlock mode.
  */
+	.align	3
 ENTRY(omap242x_sram_set_prcm)
 	stmfd	sp!, {r0-r12, lr}	@ regs to stack
 	adr	r4, pbegin		@ addr of preload start
diff --git a/arch/arm/mach-omap2/sram243x.S b/arch/arm/mach-omap2/sram243x.S
index f900758..7673020 100644
--- a/arch/arm/mach-omap2/sram243x.S
+++ b/arch/arm/mach-omap2/sram243x.S
@@ -39,6 +39,7 @@
 
 	.text
 
+	.align	3
 ENTRY(omap243x_sram_ddr_init)
 	stmfd	sp!, {r0 - r12, lr}	@ save registers on stack
 
@@ -143,6 +144,7 @@
  * r0 = [PRCM_FULL | PRCM_HALF] r1 = SDRC_DLLA_CTRL value r2 = [DDR | SDR]
  * PRCM_FULL = 2, PRCM_HALF = 1, DDR = 1, SDR = 0
  */
+	.align	3
 ENTRY(omap243x_sram_reprogram_sdrc)
 	stmfd	sp!, {r0 - r10, lr}	@ save registers on stack
 	mov	r3, #0x0		@ clear for mrc call
@@ -238,6 +240,7 @@
 /*
  * Set dividers and pll. Also recalculate DLL value for DDR and unlock mode.
  */
+	.align	3
 ENTRY(omap243x_sram_set_prcm)
 	stmfd	sp!, {r0-r12, lr}	@ regs to stack
 	adr	r4, pbegin		@ addr of preload start
diff --git a/arch/arm/mach-omap2/sram34xx.S b/arch/arm/mach-omap2/sram34xx.S
index 7f893a2..25011ca 100644
--- a/arch/arm/mach-omap2/sram34xx.S
+++ b/arch/arm/mach-omap2/sram34xx.S
@@ -111,6 +111,7 @@
  * since it will cause the ARM MMU to attempt to walk the page tables.
  * These crashes may be intermittent.
  */
+	.align	3
 ENTRY(omap3_sram_configure_core_dpll)
 	stmfd	sp!, {r1-r12, lr}	@ store regs to stack
 
diff --git a/arch/arm/mach-pxa/include/mach/pm.h b/arch/arm/mach-pxa/include/mach/pm.h
index fd8360c..f15afe0 100644
--- a/arch/arm/mach-pxa/include/mach/pm.h
+++ b/arch/arm/mach-pxa/include/mach/pm.h
@@ -22,9 +22,8 @@
 extern struct pxa_cpu_pm_fns *pxa_cpu_pm_fns;
 
 /* sleep.S */
-extern void pxa25x_cpu_suspend(unsigned int);
-extern void pxa27x_cpu_suspend(unsigned int);
-extern void pxa_cpu_resume(void);
+extern void pxa25x_cpu_suspend(unsigned int, long);
+extern void pxa27x_cpu_suspend(unsigned int, long);
 
 extern int pxa_pm_enter(suspend_state_t state);
 extern int pxa_pm_prepare(void);
diff --git a/arch/arm/mach-pxa/palmz72.c b/arch/arm/mach-pxa/palmz72.c
index 7bf4017..3010193 100644
--- a/arch/arm/mach-pxa/palmz72.c
+++ b/arch/arm/mach-pxa/palmz72.c
@@ -212,7 +212,7 @@
 static int palmz72_pm_suspend(struct sys_device *dev, pm_message_t msg)
 {
 	/* setup the resume_info struct for the original bootloader */
-	palmz72_resume_info.resume_addr = (u32) pxa_cpu_resume;
+	palmz72_resume_info.resume_addr = (u32) cpu_resume;
 
 	/* Storing memory touched by ROM */
 	store_ptr = *PALMZ72_SAVE_DWORD;
diff --git a/arch/arm/mach-pxa/pm.c b/arch/arm/mach-pxa/pm.c
index 1807c9a..51e1583 100644
--- a/arch/arm/mach-pxa/pm.c
+++ b/arch/arm/mach-pxa/pm.c
@@ -67,11 +67,6 @@
 
 EXPORT_SYMBOL_GPL(pxa_pm_enter);
 
-unsigned long sleep_phys_sp(void *sp)
-{
-	return virt_to_phys(sp);
-}
-
 static int pxa_pm_valid(suspend_state_t state)
 {
 	if (pxa_cpu_pm_fns)
diff --git a/arch/arm/mach-pxa/pxa25x.c b/arch/arm/mach-pxa/pxa25x.c
index b166b1d..6bde595 100644
--- a/arch/arm/mach-pxa/pxa25x.c
+++ b/arch/arm/mach-pxa/pxa25x.c
@@ -244,7 +244,7 @@
 
 	switch (state) {
 	case PM_SUSPEND_MEM:
-		pxa25x_cpu_suspend(PWRMODE_SLEEP);
+		pxa25x_cpu_suspend(PWRMODE_SLEEP, PLAT_PHYS_OFFSET - PAGE_OFFSET);
 		break;
 	}
 }
@@ -252,7 +252,7 @@
 static int pxa25x_cpu_pm_prepare(void)
 {
 	/* set resume return address */
-	PSPR = virt_to_phys(pxa_cpu_resume);
+	PSPR = virt_to_phys(cpu_resume);
 	return 0;
 }
 
diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c
index 987301f..28b11be 100644
--- a/arch/arm/mach-pxa/pxa27x.c
+++ b/arch/arm/mach-pxa/pxa27x.c
@@ -300,7 +300,7 @@
 		pxa_cpu_standby();
 		break;
 	case PM_SUSPEND_MEM:
-		pxa27x_cpu_suspend(pwrmode);
+		pxa27x_cpu_suspend(pwrmode, PLAT_PHYS_OFFSET - PAGE_OFFSET);
 		break;
 	}
 }
@@ -313,7 +313,7 @@
 static int pxa27x_cpu_pm_prepare(void)
 {
 	/* set resume return address */
-	PSPR = virt_to_phys(pxa_cpu_resume);
+	PSPR = virt_to_phys(cpu_resume);
 	return 0;
 }
 
diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c
index a7a19e1..1230343 100644
--- a/arch/arm/mach-pxa/pxa3xx.c
+++ b/arch/arm/mach-pxa/pxa3xx.c
@@ -142,8 +142,7 @@
 	volatile unsigned long *p = (volatile void *)0xc0000000;
 	unsigned long saved_data = *p;
 
-	extern void pxa3xx_cpu_suspend(void);
-	extern void pxa3xx_cpu_resume(void);
+	extern void pxa3xx_cpu_suspend(long);
 
 	/* resuming from D2 requires the HSIO2/BOOT/TPM clocks enabled */
 	CKENA |= (1 << CKEN_BOOT) | (1 << CKEN_TPM);
@@ -161,9 +160,9 @@
 	PSPR = 0x5c014000;
 
 	/* overwrite with the resume address */
-	*p = virt_to_phys(pxa3xx_cpu_resume);
+	*p = virt_to_phys(cpu_resume);
 
-	pxa3xx_cpu_suspend();
+	pxa3xx_cpu_suspend(PLAT_PHYS_OFFSET - PAGE_OFFSET);
 
 	*p = saved_data;
 
diff --git a/arch/arm/mach-pxa/sleep.S b/arch/arm/mach-pxa/sleep.S
index c551da8..6f53688 100644
--- a/arch/arm/mach-pxa/sleep.S
+++ b/arch/arm/mach-pxa/sleep.S
@@ -22,133 +22,26 @@
 
 		.text
 
-pxa_cpu_save_cp:
-	@ get coprocessor registers
-	mrc	p14, 0, r3, c6, c0, 0		@ clock configuration, for turbo mode
-	mrc	p15, 0, r4, c15, c1, 0		@ CP access reg
-	mrc	p15, 0, r5, c13, c0, 0		@ PID
-	mrc 	p15, 0, r6, c3, c0, 0		@ domain ID
-	mrc 	p15, 0, r7, c2, c0, 0		@ translation table base addr
-	mrc	p15, 0, r8, c1, c1, 0           @ auxiliary control reg
-	mrc 	p15, 0, r9, c1, c0, 0		@ control reg
-
-	bic	r3, r3, #2			@ clear frequency change bit
-
-	@ store them plus current virtual stack ptr on stack
-	mov	r10, sp
-	stmfd	sp!, {r3 - r10}
-
-	mov	pc, lr
-
-pxa_cpu_save_sp:
-	@ preserve phys address of stack
-	mov	r0, sp
-	str	lr, [sp, #-4]!
-	bl	sleep_phys_sp
-	ldr	r1, =sleep_save_sp
-	str	r0, [r1]
-	ldr	pc, [sp], #4
-
 #ifdef CONFIG_PXA3xx
 /*
  * pxa3xx_cpu_suspend() - forces CPU into sleep state (S2D3C4)
  *
- * NOTE:  unfortunately, pxa_cpu_save_cp can not be reused here since
- * the auxiliary control register address is different between pxa3xx
- * and pxa{25x,27x}
+ * r0 = v:p offset
  */
-
 ENTRY(pxa3xx_cpu_suspend)
 
 #ifndef CONFIG_IWMMXT
 	mra	r2, r3, acc0
 #endif
 	stmfd	sp!, {r2 - r12, lr}	@ save registers on stack
-
-	mrc	p14, 0, r3, c6, c0, 0		@ clock configuration, for turbo mode
-	mrc	p15, 0, r4, c15, c1, 0		@ CP access reg
-	mrc	p15, 0, r5, c13, c0, 0		@ PID
-	mrc 	p15, 0, r6, c3, c0, 0		@ domain ID
-	mrc 	p15, 0, r7, c2, c0, 0		@ translation table base addr
-	mrc	p15, 0, r8, c1, c0, 1           @ auxiliary control reg
-	mrc 	p15, 0, r9, c1, c0, 0		@ control reg
-
-	bic	r3, r3, #2			@ clear frequency change bit
-
-	@ store them plus current virtual stack ptr on stack
-	mov	r10, sp
-	stmfd	sp!, {r3 - r10}
-
-	@ store physical address of stack pointer
-	mov	r0, sp
-	bl	sleep_phys_sp
-	ldr	r1, =sleep_save_sp
-	str	r0, [r1]
-
-	@ clean data cache
-	bl	xsc3_flush_kern_cache_all
+	mov	r1, r0
+	ldr	r3, =pxa_cpu_resume	@ resume function
+	bl	cpu_suspend
 
 	mov	r0, #0x06		@ S2D3C4 mode
 	mcr	p14, 0, r0, c7, c0, 0	@ enter sleep
 
 20:	b	20b			@ waiting for sleep
-
-	.data
-	.align 5
-/*
- * pxa3xx_cpu_resume
- */
-
-ENTRY(pxa3xx_cpu_resume)
-
-	mov	r0, #PSR_I_BIT | PSR_F_BIT | SVC_MODE	@ set SVC, irqs off
-	msr	cpsr_c, r0
-
-	ldr	r0, sleep_save_sp		@ stack phys addr
-	ldmfd	r0, {r3 - r9, sp}		@ CP regs + virt stack ptr
-
-	mov	r1, #0
-	mcr	p15, 0, r1, c7, c7, 0		@ invalidate I & D caches, BTB
-	mcr	p15, 0, r1, c7, c10, 4		@ drain write (&fill) buffer
-	mcr	p15, 0, r1, c7, c5, 4		@ flush prefetch buffer
-	mcr	p15, 0, r1, c8, c7, 0   	@ invalidate I & D TLBs
-
-	mcr	p14, 0, r3, c6, c0, 0		@ clock configuration, turbo mode.
-	mcr	p15, 0, r4, c15, c1, 0		@ CP access reg
-	mcr	p15, 0, r5, c13, c0, 0		@ PID
-	mcr 	p15, 0, r6, c3, c0, 0		@ domain ID
-	mcr 	p15, 0, r7, c2, c0, 0		@ translation table base addr
-	mcr	p15, 0, r8, c1, c0, 1           @ auxiliary control reg
-
-	@ temporarily map resume_turn_on_mmu into the page table,
-	@ otherwise prefetch abort occurs after MMU is turned on
-	mov	r1, r7
-	bic	r1, r1, #0x00ff
-	bic	r1, r1, #0x3f00
-	ldr	r2, =0x542e
-
-	adr	r3, resume_turn_on_mmu
-	mov	r3, r3, lsr #20
-	orr	r4, r2, r3, lsl #20
-	ldr	r5, [r1, r3, lsl #2]
-	str     r4, [r1, r3, lsl #2]
-
-	@ Mapping page table address in the page table
-	mov	r6, r1, lsr #20
-	orr	r7, r2, r6, lsl #20
-	ldr	r8, [r1, r6, lsl #2]
-	str	r7, [r1, r6, lsl #2]
-
-	ldr	r2, =pxa3xx_resume_after_mmu	@ absolute virtual address
-	b	resume_turn_on_mmu		@ cache align execution
-
-	.text
-pxa3xx_resume_after_mmu:
-	/* restore the temporary mapping */
-	str	r5, [r1, r3, lsl #2]
-	str	r8, [r1, r6, lsl #2]
-	b	resume_after_mmu
-
 #endif /* CONFIG_PXA3xx */
 
 #ifdef CONFIG_PXA27x
@@ -158,28 +51,23 @@
  * Forces CPU into sleep state.
  *
  * r0 = value for PWRMODE M field for desired sleep state
+ * r1 = v:p offset
  */
-
 ENTRY(pxa27x_cpu_suspend)
 
 #ifndef CONFIG_IWMMXT
 	mra	r2, r3, acc0
 #endif
 	stmfd	sp!, {r2 - r12, lr}		@ save registers on stack
-
-	bl	pxa_cpu_save_cp
-
-	mov	r5, r0				@ save sleep mode
-	bl	pxa_cpu_save_sp
-
-	@ clean data cache
-	bl	xscale_flush_kern_cache_all
+	mov	r4, r0				@ save sleep mode
+	ldr	r3, =pxa_cpu_resume		@ resume function
+	bl	cpu_suspend
 
 	@ Put the processor to sleep
 	@ (also workaround for sighting 28071)
 
 	@ prepare value for sleep mode
-	mov	r1, r5				@ sleep mode
+	mov	r1, r4				@ sleep mode
 
 	@ prepare pointer to physical address 0 (virtual mapping in generic.c)
 	mov	r2, #UNCACHED_PHYS_0
@@ -216,21 +104,16 @@
  * Forces CPU into sleep state.
  *
  * r0 = value for PWRMODE M field for desired sleep state
+ * r1 = v:p offset
  */
 
 ENTRY(pxa25x_cpu_suspend)
 	stmfd	sp!, {r2 - r12, lr}		@ save registers on stack
-
-	bl	pxa_cpu_save_cp
-
-	mov	r5, r0				@ save sleep mode
-	bl	pxa_cpu_save_sp
-
-	@ clean data cache
-	bl	xscale_flush_kern_cache_all
-
+	mov	r4, r0				@ save sleep mode
+	ldr	r3, =pxa_cpu_resume		@ resume function
+	bl	cpu_suspend
 	@ prepare value for sleep mode
-	mov	r1, r5				@ sleep mode
+	mov	r1, r4				@ sleep mode
 
 	@ prepare pointer to physical address 0 (virtual mapping in generic.c)
 	mov	r2, #UNCACHED_PHYS_0
@@ -317,53 +200,9 @@
  * pxa_cpu_resume()
  *
  * entry point from bootloader into kernel during resume
- *
- * Note: Yes, part of the following code is located into the .data section.
- *       This is to allow sleep_save_sp to be accessed with a relative load
- *       while we can't rely on any MMU translation.  We could have put
- *       sleep_save_sp in the .text section as well, but some setups might
- *       insist on it to be truly read-only.
  */
-
-	.data
 	.align 5
-ENTRY(pxa_cpu_resume)
-	mov	r0, #PSR_I_BIT | PSR_F_BIT | SVC_MODE	@ set SVC, irqs off
-	msr	cpsr_c, r0
-
-	ldr	r0, sleep_save_sp		@ stack phys addr
-	ldr	r2, =resume_after_mmu		@ its absolute virtual address
-	ldmfd	r0, {r3 - r9, sp}		@ CP regs + virt stack ptr
-
-	mov	r1, #0
-	mcr	p15, 0, r1, c8, c7, 0   	@ invalidate I & D TLBs
-	mcr	p15, 0, r1, c7, c7, 0		@ invalidate I & D caches, BTB
-
-	mcr	p14, 0, r3, c6, c0, 0		@ clock configuration, turbo mode.
-	mcr	p15, 0, r4, c15, c1, 0		@ CP access reg
-	mcr	p15, 0, r5, c13, c0, 0		@ PID
-	mcr 	p15, 0, r6, c3, c0, 0		@ domain ID
-	mcr 	p15, 0, r7, c2, c0, 0		@ translation table base addr
-	mcr	p15, 0, r8, c1, c1, 0           @ auxiliary control reg
-	b	resume_turn_on_mmu		@ cache align execution
-
-	.align 5
-resume_turn_on_mmu:
-	mcr 	p15, 0, r9, c1, c0, 0		@ turn on MMU, caches, etc.
-
-	@ Let us ensure we jump to resume_after_mmu only when the mcr above
-	@ actually took effect.  They call it the "cpwait" operation.
-	mrc	p15, 0, r0, c2, c0, 0		@ queue a dependency on CP15
-	sub	pc, r2, r0, lsr #32		@ jump to virtual addr
-	nop
-	nop
-	nop
-
-sleep_save_sp:
-	.word	0				@ preserve stack phys ptr here
-
-	.text
-resume_after_mmu:
+pxa_cpu_resume:
 	ldmfd	sp!, {r2, r3}
 #ifndef CONFIG_IWMMXT
 	mar	acc0, r2, r3
diff --git a/arch/arm/mach-pxa/zeus.c b/arch/arm/mach-pxa/zeus.c
index f4b053b..b92aa3b 100644
--- a/arch/arm/mach-pxa/zeus.c
+++ b/arch/arm/mach-pxa/zeus.c
@@ -676,7 +676,7 @@
 static void zeus_power_off(void)
 {
 	local_irq_disable();
-	pxa27x_cpu_suspend(PWRMODE_DEEPSLEEP);
+	pxa27x_cpu_suspend(PWRMODE_DEEPSLEEP, PLAT_PHYS_OFFSET - PAGE_OFFSET);
 }
 #else
 #define zeus_power_off   NULL
diff --git a/arch/arm/mach-s3c64xx/sleep.S b/arch/arm/mach-s3c64xx/sleep.S
index b2ef443..afe5a76 100644
--- a/arch/arm/mach-s3c64xx/sleep.S
+++ b/arch/arm/mach-s3c64xx/sleep.S
@@ -32,25 +32,13 @@
 	 * code after resume.
 	 *
 	 * entry:
-	 *	r0 = pointer to the save block
+	 *	r1 = v:p offset
 	*/
 
 ENTRY(s3c_cpu_save)
 	stmfd	sp!, { r4 - r12, lr }
-
-	mrc	p15, 0, r4, c13, c0, 0	@ FCSE/PID
-	mrc	p15, 0, r5, c3, c0, 0	@ Domain ID
-	mrc	p15, 0, r6, c2, c0, 0	@ Translation Table BASE0
-	mrc	p15, 0, r7, c2, c0, 1	@ Translation Table BASE1
-	mrc	p15, 0, r8, c2, c0, 2	@ Translation Table Control
-	mrc	p15, 0, r9, c1, c0, 0	@ Control register
-	mrc	p15, 0, r10, c1, c0, 1	@ Auxiliary control register
-	mrc	p15, 0, r11, c1, c0, 2	@ Co-processor access controls
-
-	stmia	r0, { r4 - r13 }	@ Save CP registers and SP
-
-	@@ save our state to ram
-	bl	s3c_pm_cb_flushcache
+	ldr	r3, =resume_with_mmu
+	bl	cpu_suspend
 
 	@@ call final suspend code
 	ldr	r0, =pm_cpu_sleep
@@ -61,18 +49,6 @@
 resume_with_mmu:
 	ldmfd	sp!, { r4 - r12, pc }	@ return, from sp from s3c_cpu_save
 
-	.data
-
-	/* the next bit is code, but it requires easy access to the
-	 * s3c_sleep_save_phys data before the MMU is switched on, so
-	 * we store the code that needs this variable in the .data where
-	 * the value can be written to (the .text segment is RO).
-	*/
-
-	.global	s3c_sleep_save_phys
-s3c_sleep_save_phys:
-	.word	0
-
 	/* Sleep magic, the word before the resume entry point so that the
 	 * bootloader can check for a resumeable image. */
 
@@ -110,35 +86,4 @@
 	orr	r0, r0, #1 << 15			@ GPN15
 	str	r0, [ r3, #S3C64XX_GPNDAT ]
 #endif
-
-	/* __v6_setup from arch/arm/mm/proc-v6.S, ensure that the caches
-	 * are thoroughly cleaned just in case the bootloader didn't do it
-	 * for us. */
-	mov	r0, #0
-	mcr	p15, 0, r0, c7, c14, 0		@ clean+invalidate D cache
-	mcr	p15, 0, r0, c7, c5, 0		@ invalidate I cache
-	mcr	p15, 0, r0, c7, c15, 0		@ clean+invalidate cache
-	mcr	p15, 0, r0, c7, c10, 4		@ drain write buffer
-	@@mcr	p15, 0, r0, c8, c7, 0		@ invalidate I + D TLBs
-	@@mcr	p15, 0, r0, c7, c7, 0		@ Invalidate I + D caches
-
-	ldr	r0, s3c_sleep_save_phys
-	ldmia	r0, { r4 - r13 }
-
-	mcr	p15, 0, r4, c13, c0, 0	@ FCSE/PID
-	mcr	p15, 0, r5, c3, c0, 0	@ Domain ID
-	mcr	p15, 0, r6, c2, c0, 0	@ Translation Table BASE0
-	mcr	p15, 0, r7, c2, c0, 1	@ Translation Table BASE1
-	mcr	p15, 0, r8, c2, c0, 2	@ Translation Table Control
-	mcr	p15, 0, r10, c1, c0, 1	@ Auxiliary control register
-
-	mov	r0, #0			@ restore copro access controls
-	mcr	p15, 0, r11, c1, c0, 2	@ Co-processor access controls
-	mcr 	p15, 0, r0, c7, c5, 4
-
-	ldr	r2, =resume_with_mmu
-	mcr	p15, 0, r9, c1, c0, 0		/* turn mmu back on */
-	nop
-	mov	pc, r2				/* jump back */
-
-	.end
+	b	cpu_resume
diff --git a/arch/arm/mach-s5pv210/sleep.S b/arch/arm/mach-s5pv210/sleep.S
index d4d222b..a3d6494 100644
--- a/arch/arm/mach-s5pv210/sleep.S
+++ b/arch/arm/mach-s5pv210/sleep.S
@@ -35,50 +35,24 @@
 	/* s3c_cpu_save
 	 *
 	 * entry:
-	 *	r0 = save address (virtual addr of s3c_sleep_save_phys)
+	 *	r1 = v:p offset
 	*/
 
 ENTRY(s3c_cpu_save)
 
 	stmfd	sp!, { r3 - r12, lr }
-
-	mrc	p15, 0, r4, c13, c0, 0	@ FCSE/PID
-	mrc	p15, 0, r5, c3, c0, 0	@ Domain ID
-	mrc	p15, 0, r6, c2, c0, 0	@ Translation Table BASE0
-	mrc	p15, 0, r7, c2, c0, 1	@ Translation Table BASE1
-	mrc	p15, 0, r8, c2, c0, 2	@ Translation Table Control
-	mrc	p15, 0, r9, c1, c0, 0	@ Control register
-	mrc	p15, 0, r10, c1, c0, 1	@ Auxiliary control register
-	mrc	p15, 0, r11, c1, c0, 2	@ Co-processor access controls
-	mrc	p15, 0, r12, c10, c2, 0	@ Read PRRR
-	mrc	p15, 0, r3, c10, c2, 1	@ READ NMRR
-
-	stmia	r0, { r3 - r13 }
-
-	bl	s3c_pm_cb_flushcache
+	ldr	r3, =resume_with_mmu
+	bl	cpu_suspend
 
 	ldr	r0, =pm_cpu_sleep
 	ldr	r0, [ r0 ]
 	mov	pc, r0
 
 resume_with_mmu:
-	/*
-	 * After MMU is turned on, restore the previous MMU table.
-	 */
-	ldr	r9 , =(PAGE_OFFSET - PHYS_OFFSET)
-	add	r4, r4, r9
-	str	r12, [r4]
-
 	ldmfd	sp!, { r3 - r12, pc }
 
 	.ltorg
 
-	.data
-
-	.global	s3c_sleep_save_phys
-s3c_sleep_save_phys:
-	.word	0
-
 	/* sleep magic, to allow the bootloader to check for an valid
 	 * image to resume to. Must be the first word before the
 	 * s3c_cpu_resume entry.
@@ -96,75 +70,4 @@
 	*/
 
 ENTRY(s3c_cpu_resume)
-	mov	r0, #PSR_I_BIT | PSR_F_BIT | SVC_MODE
-	msr	cpsr_c, r0
-
-	mov	r1, #0
-	mcr	p15, 0, r1, c8, c7, 0		@ invalidate TLBs
-	mcr	p15, 0, r1, c7, c5, 0		@ invalidate I Cache
-
-	ldr	r0, s3c_sleep_save_phys		@ address of restore block
-	ldmia	r0, { r3 - r13 }
-
-	mcr	p15, 0, r4, c13, c0, 0		@ FCSE/PID
-	mcr	p15, 0, r5, c3, c0, 0		@ Domain ID
-
-	mcr	p15, 0, r8, c2, c0, 2		@ Translation Table Control
-	mcr	p15, 0, r7, c2, c0, 1		@ Translation Table BASE1
-	mcr	p15, 0, r6, c2, c0, 0		@ Translation Table BASE0
-
-	mcr	p15, 0, r10, c1, c0, 1		@ Auxiliary control register
-
-	mov	r0, #0
-	mcr	p15, 0, r0, c8, c7, 0		@ Invalidate I & D TLB
-
-	mov	r0, #0				@ restore copro access
-	mcr	p15, 0, r11, c1, c0, 2		@ Co-processor access
-	mcr 	p15, 0, r0, c7, c5, 4
-
-	mcr	p15, 0, r12, c10, c2, 0		@ write PRRR
-	mcr	p15, 0, r3, c10, c2, 1		@ write NMRR
-
-	/*
-	 * In Cortex-A8, when MMU is turned on, the pipeline is flushed.
-	 * And there are no valid entries in the MMU table at this point.
-	 * So before turning on the MMU, the MMU entry for the DRAM address
-	 * range is added. After the MMU is turned on, the other entries
-	 * in the MMU table will be restored.
-	*/
-
-	/* r6 = Translation Table BASE0 */
-	mov	r4, r6
-	mov	r4, r4, LSR #14
-	mov	r4, r4, LSL #14
-
-	/* Load address for adding to MMU table list */
-	ldr	r11, =0xE010F000		@ INFORM0 reg.
-	ldr	r10, [r11, #0]
-	mov	r10, r10, LSR #18
-	bic	r10, r10, #0x3
-	orr	r4, r4, r10
-
-	/* Calculate MMU table entry */
-	mov 	r10, r10, LSL #18
-	ldr	r5, =0x40E
-	orr	r10, r10, r5
-
-	/* Back up originally data */
-	ldr	r12, [r4]
-
-	/* Add calculated MMU table entry into MMU table list */
-	str	r10, [r4]
-
-	ldr	r2, =resume_with_mmu
-	mcr	p15, 0, r9, c1, c0, 0		@ turn on MMU, etc
-
-	nop
-	nop
-	nop
-	nop
-	nop					@ second-to-last before mmu
-
-	mov	pc, r2				@ go back to virtual address
-
-	.ltorg
+	b	cpu_resume
diff --git a/arch/arm/mach-sa1100/pm.c b/arch/arm/mach-sa1100/pm.c
index ab9fc44..c4661aa 100644
--- a/arch/arm/mach-sa1100/pm.c
+++ b/arch/arm/mach-sa1100/pm.c
@@ -32,8 +32,7 @@
 #include <asm/system.h>
 #include <asm/mach/time.h>
 
-extern void sa1100_cpu_suspend(void);
-extern void sa1100_cpu_resume(void);
+extern void sa1100_cpu_suspend(long);
 
 #define SAVE(x)		sleep_save[SLEEP_SAVE_##x] = x
 #define RESTORE(x)	x = sleep_save[SLEEP_SAVE_##x]
@@ -73,10 +72,10 @@
 	RCSR = RCSR_HWR | RCSR_SWR | RCSR_WDR | RCSR_SMR;
 
 	/* set resume return address */
-	PSPR = virt_to_phys(sa1100_cpu_resume);
+	PSPR = virt_to_phys(cpu_resume);
 
 	/* go zzz */
-	sa1100_cpu_suspend();
+	sa1100_cpu_suspend(PLAT_PHYS_OFFSET - PAGE_OFFSET);
 
 	cpu_init();
 
@@ -115,11 +114,6 @@
 	return 0;
 }
 
-unsigned long sleep_phys_sp(void *sp)
-{
-	return virt_to_phys(sp);
-}
-
 static const struct platform_suspend_ops sa11x0_pm_ops = {
 	.enter		= sa11x0_pm_enter,
 	.valid		= suspend_valid_only_mem,
diff --git a/arch/arm/mach-sa1100/sleep.S b/arch/arm/mach-sa1100/sleep.S
index 80f31ba..04f2a61 100644
--- a/arch/arm/mach-sa1100/sleep.S
+++ b/arch/arm/mach-sa1100/sleep.S
@@ -20,12 +20,7 @@
 #include <asm/assembler.h>
 #include <mach/hardware.h>
 
-
-
 		.text
-
-
-
 /*
  * sa1100_cpu_suspend()
  *
@@ -34,27 +29,10 @@
  */
 
 ENTRY(sa1100_cpu_suspend)
-
 	stmfd	sp!, {r4 - r12, lr}		@ save registers on stack
-
-	@ get coprocessor registers
-	mrc 	p15, 0, r4, c3, c0, 0		@ domain ID
-	mrc 	p15, 0, r5, c2, c0, 0		@ translation table base addr
-	mrc	p15, 0, r6, c13, c0, 0		@ PID
-	mrc 	p15, 0, r7, c1, c0, 0		@ control reg
-
-	@ store them plus current virtual stack ptr on stack
-	mov	r8, sp
-	stmfd	sp!, {r4 - r8}
-
-	@ preserve phys address of stack
-	mov	r0, sp
-	bl	sleep_phys_sp
-	ldr	r1, =sleep_save_sp
-	str	r0, [r1]
-
-	@ clean data cache and invalidate WB
-	bl	v4wb_flush_kern_cache_all
+	mov	r1, r0
+	ldr	r3, =sa1100_cpu_resume		@ return function
+	bl	cpu_suspend
 
 	@ disable clock switching
 	mcr	p15, 0, r1, c15, c2, 2
@@ -166,50 +144,8 @@
  * cpu_sa1100_resume()
  *
  * entry point from bootloader into kernel during resume
- *
- * Note: Yes, part of the following code is located into the .data section.
- *       This is to allow sleep_save_sp to be accessed with a relative load
- *       while we can't rely on any MMU translation.  We could have put
- *       sleep_save_sp in the .text section as well, but some setups might
- *       insist on it to be truly read-only.
  */
-
-	.data
 	.align 5
-ENTRY(sa1100_cpu_resume)
-	mov	r0, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
-	msr	cpsr_c, r0			@ set SVC, irqs off
-
-	ldr	r0, sleep_save_sp		@ stack phys addr
-	ldr	r2, =resume_after_mmu		@ its absolute virtual address
-	ldmfd	r0, {r4 - r7, sp}		@ CP regs + virt stack ptr
-
-	mov	r1, #0
-	mcr	p15, 0, r1, c8, c7, 0   	@ flush I+D TLBs
-	mcr	p15, 0, r1, c7, c7, 0		@ flush I&D cache
-	mcr	p15, 0, r1, c9, c0, 0		@ invalidate RB
-	mcr	p15, 0, r1, c9, c0, 5		@ allow user space to use RB
-
-	mcr	p15, 0, r4, c3, c0, 0		@ domain ID
-	mcr	p15, 0, r5, c2, c0, 0		@ translation table base addr
-	mcr	p15, 0, r6, c13, c0, 0		@ PID
-	b	resume_turn_on_mmu		@ cache align execution
-
-	.align 5
-resume_turn_on_mmu:
-	mcr 	p15, 0, r7, c1, c0, 0		@ turn on MMU, caches, etc.
-	nop
-	mov	pc, r2				@ jump to virtual addr
-	nop
-	nop
-	nop
-
-sleep_save_sp:
-	.word	0				@ preserve stack phys ptr here
-
-	.text
-resume_after_mmu:
+sa1100_cpu_resume:
 	mcr	p15, 0, r1, c15, c1, 2		@ enable clock switching
 	ldmfd	sp!, {r4 - r12, pc}		@ return to caller
-
-
diff --git a/arch/arm/mach-shmobile/include/mach/mmcif-ap4eb.h b/arch/arm/mach-shmobile/include/mach/mmcif-ap4eb.h
new file mode 100644
index 0000000..a8d02be
--- /dev/null
+++ b/arch/arm/mach-shmobile/include/mach/mmcif-ap4eb.h
@@ -0,0 +1,29 @@
+#ifndef MMCIF_AP4EB_H
+#define MMCIF_AP4EB_H
+
+#define PORT185CR      (void __iomem *)0xe60520b9
+#define PORT186CR      (void __iomem *)0xe60520ba
+#define PORT187CR      (void __iomem *)0xe60520bb
+#define PORT188CR      (void __iomem *)0xe60520bc
+
+#define PORTR191_160DR (void __iomem *)0xe6056014
+
+static inline void mmcif_init_progress(void)
+{
+       /* Initialise LEDS1-4
+        * registers: PORT185CR-PORT188CR (LED1-LED4 Control)
+        * value:     0x10 - enable output
+        */
+       __raw_writeb(0x10, PORT185CR);
+       __raw_writeb(0x10, PORT186CR);
+       __raw_writeb(0x10, PORT187CR);
+       __raw_writeb(0x10, PORT188CR);
+}
+
+static inline void mmcif_update_progress(int n)
+{
+	__raw_writel((__raw_readl(PORTR191_160DR) & ~(0xf << 25)) |
+		     (1 << (25 + n)), PORTR191_160DR);
+}
+
+#endif /* MMCIF_AP4EB_H */
diff --git a/arch/arm/mach-shmobile/include/mach/mmcif-mackerel.h b/arch/arm/mach-shmobile/include/mach/mmcif-mackerel.h
new file mode 100644
index 0000000..4b4f694
--- /dev/null
+++ b/arch/arm/mach-shmobile/include/mach/mmcif-mackerel.h
@@ -0,0 +1,39 @@
+#ifndef MMCIF_MACKEREL_H
+#define MMCIF_MACKEREL_H
+
+#define PORT0CR      (void __iomem *)0xe6051000
+#define PORT1CR      (void __iomem *)0xe6051001
+#define PORT2CR      (void __iomem *)0xe6051002
+#define PORT159CR    (void __iomem *)0xe605009f
+
+#define PORTR031_000DR (void __iomem *)0xe6055000
+#define PORTL159_128DR (void __iomem *)0xe6054010
+
+static inline void mmcif_init_progress(void)
+{
+       /* Initialise LEDS0-3
+        * registers: PORT0CR-PORT2CR,PORT159CR (LED0-LED3 Control)
+        * value:     0x10 - enable output
+        */
+       __raw_writeb(0x10, PORT0CR);
+       __raw_writeb(0x10, PORT1CR);
+       __raw_writeb(0x10, PORT2CR);
+       __raw_writeb(0x10, PORT159CR);
+}
+
+static inline void mmcif_update_progress(int n)
+{
+	unsigned a = 0, b = 0;
+
+	if (n < 3)
+		a = 1 << n;
+	else
+		b = 1 << 31;
+
+	__raw_writel((__raw_readl(PORTR031_000DR) & ~0x7) | a,
+		     PORTR031_000DR);
+	__raw_writel((__raw_readl(PORTL159_128DR) & ~(1 << 31)) | b,
+		     PORTL159_128DR);
+}
+
+#endif /* MMCIF_MACKEREL_H */
diff --git a/arch/arm/mach-shmobile/include/mach/mmcif.h b/arch/arm/mach-shmobile/include/mach/mmcif.h
new file mode 100644
index 0000000..f4dc327
--- /dev/null
+++ b/arch/arm/mach-shmobile/include/mach/mmcif.h
@@ -0,0 +1,18 @@
+#ifndef MMCIF_H
+#define MMCIF_H
+
+/**************************************************
+ *
+ *		board specific settings
+ *
+ **************************************************/
+
+#ifdef CONFIG_MACH_AP4EVB
+#include "mach/mmcif-ap4eb.h"
+#elif CONFIG_MACH_MACKEREL
+#include "mach/mmcif-mackerel.h"
+#else
+#error "unsupported board."
+#endif
+
+#endif /* MMCIF_H */
diff --git a/arch/arm/mach-ux500/Kconfig b/arch/arm/mach-ux500/Kconfig
index 247caa3..203b986 100644
--- a/arch/arm/mach-ux500/Kconfig
+++ b/arch/arm/mach-ux500/Kconfig
@@ -6,6 +6,7 @@
 	select ARM_GIC
 	select HAS_MTU
 	select NOMADIK_GPIO
+	select ARM_ERRATA_753970
 
 menu "Ux500 SoC"
 
diff --git a/arch/arm/mach-vt8500/Kconfig b/arch/arm/mach-vt8500/Kconfig
new file mode 100644
index 0000000..2c20a34
--- /dev/null
+++ b/arch/arm/mach-vt8500/Kconfig
@@ -0,0 +1,73 @@
+if ARCH_VT8500
+
+config VTWM_VERSION_VT8500
+	bool
+
+config VTWM_VERSION_WM8505
+	bool
+
+config MACH_BV07
+	bool "Benign BV07-8500 Mini Netbook"
+	depends on ARCH_VT8500
+	select VTWM_VERSION_VT8500
+	help
+	  Add support for the inexpensive 7-inch netbooks sold by many
+	  Chinese distributors under various names. Note that there are
+	  many hardware implementations in identical exterior, make sure
+	  that yours is indeed based on a VIA VT8500 chip.
+
+config MACH_WM8505_7IN_NETBOOK
+	bool "WM8505 7-inch generic netbook"
+	depends on ARCH_VT8500
+	select VTWM_VERSION_WM8505
+	help
+	  Add support for the inexpensive 7-inch netbooks sold by many
+	  Chinese distributors under various names. Note that there are
+	  many hardware implementations in identical exterior, make sure
+	  that yours is indeed based on a WonderMedia WM8505 chip.
+
+comment "LCD panel size"
+
+config WMT_PANEL_800X480
+	bool "7-inch with 800x480 resolution"
+	depends on (FB_VT8500 || FB_WM8505)
+	default y
+	help
+	  These are found in most of the netbooks in generic cases, as
+	  well as in Eken M001 tablets and possibly elsewhere.
+
+	  To select this panel at runtime, say y here and append
+	  'panel=800x480' to your kernel command line. Otherwise, the
+	  largest one available will be used.
+
+config WMT_PANEL_800X600
+	bool "8-inch with 800x600 resolution"
+	depends on (FB_VT8500 || FB_WM8505)
+	help
+	  These are found in Eken M003 tablets and possibly elsewhere.
+
+	  To select this panel at runtime, say y here and append
+	  'panel=800x600' to your kernel command line. Otherwise, the
+	  largest one available will be used.
+
+config WMT_PANEL_1024X576
+	bool "10-inch with 1024x576 resolution"
+	depends on (FB_VT8500 || FB_WM8505)
+	help
+	  These are found in CherryPal netbooks and possibly elsewhere.
+
+	  To select this panel at runtime, say y here and append
+	  'panel=1024x576' to your kernel command line. Otherwise, the
+	  largest one available will be used.
+
+config WMT_PANEL_1024X600
+	bool "10-inch with 1024x600 resolution"
+	depends on (FB_VT8500 || FB_WM8505)
+	help
+	  These are found in Eken M006 tablets and possibly elsewhere.
+
+	  To select this panel at runtime, say y here and append
+	  'panel=1024x600' to your kernel command line. Otherwise, the
+	  largest one available will be used.
+
+endif
diff --git a/arch/arm/mach-vt8500/Makefile b/arch/arm/mach-vt8500/Makefile
new file mode 100644
index 0000000..81aedb7
--- /dev/null
+++ b/arch/arm/mach-vt8500/Makefile
@@ -0,0 +1,9 @@
+obj-y += devices.o gpio.o irq.o timer.o
+
+obj-$(CONFIG_VTWM_VERSION_VT8500) += devices-vt8500.o
+obj-$(CONFIG_VTWM_VERSION_WM8505) += devices-wm8505.o
+
+obj-$(CONFIG_MACH_BV07) += bv07.o
+obj-$(CONFIG_MACH_WM8505_7IN_NETBOOK) += wm8505_7in.o
+
+obj-$(CONFIG_HAVE_PWM) += pwm.o
diff --git a/arch/arm/mach-vt8500/Makefile.boot b/arch/arm/mach-vt8500/Makefile.boot
new file mode 100644
index 0000000..a8acc4e
--- /dev/null
+++ b/arch/arm/mach-vt8500/Makefile.boot
@@ -0,0 +1,3 @@
+   zreladdr-y	:= 0x00008000
+params_phys-y	:= 0x00000100
+initrd_phys-y	:= 0x01000000
diff --git a/arch/arm/mach-vt8500/bv07.c b/arch/arm/mach-vt8500/bv07.c
new file mode 100644
index 0000000..94a261d
--- /dev/null
+++ b/arch/arm/mach-vt8500/bv07.c
@@ -0,0 +1,77 @@
+/*
+ *  arch/arm/mach-vt8500/bv07.c
+ *
+ *  Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
+ *
+ * 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/io.h>
+#include <linux/pm.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#include "devices.h"
+
+static void __iomem *pmc_hiber;
+
+static struct platform_device *devices[] __initdata = {
+	&vt8500_device_uart0,
+	&vt8500_device_lcdc,
+	&vt8500_device_ehci,
+	&vt8500_device_ge_rops,
+	&vt8500_device_pwm,
+	&vt8500_device_pwmbl,
+	&vt8500_device_rtc,
+};
+
+static void vt8500_power_off(void)
+{
+	local_irq_disable();
+	writew(5, pmc_hiber);
+	asm("mcr%? p15, 0, %0, c7, c0, 4" : : "r" (0));
+}
+
+void __init bv07_init(void)
+{
+#ifdef CONFIG_FB_VT8500
+	void __iomem *gpio_mux_reg = ioremap(wmt_gpio_base + 0x200, 4);
+	if (gpio_mux_reg) {
+		writel(readl(gpio_mux_reg) | 1, gpio_mux_reg);
+		iounmap(gpio_mux_reg);
+	} else {
+		printk(KERN_ERR "Could not remap the GPIO mux register, display may not work properly!\n");
+	}
+#endif
+	pmc_hiber = ioremap(wmt_pmc_base + 0x12, 2);
+	if (pmc_hiber)
+		pm_power_off = &vt8500_power_off;
+	else
+		printk(KERN_ERR "PMC Hibernation register could not be remapped, not enabling power off!\n");
+
+	vt8500_set_resources();
+	platform_add_devices(devices, ARRAY_SIZE(devices));
+	vt8500_gpio_init();
+}
+
+MACHINE_START(BV07, "Benign BV07 Mini Netbook")
+	.boot_params	= 0x00000100,
+	.reserve	= vt8500_reserve_mem,
+	.map_io		= vt8500_map_io,
+	.init_irq	= vt8500_init_irq,
+	.timer		= &vt8500_timer,
+	.init_machine	= bv07_init,
+MACHINE_END
diff --git a/arch/arm/mach-vt8500/devices-vt8500.c b/arch/arm/mach-vt8500/devices-vt8500.c
new file mode 100644
index 0000000..19519ae
--- /dev/null
+++ b/arch/arm/mach-vt8500/devices-vt8500.c
@@ -0,0 +1,91 @@
+/* linux/arch/arm/mach-vt8500/devices-vt8500.c
+ *
+ * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/platform_device.h>
+
+#include <mach/vt8500_regs.h>
+#include <mach/vt8500_irqs.h>
+#include <mach/i8042.h>
+#include "devices.h"
+
+void __init vt8500_set_resources(void)
+{
+	struct resource tmp[3];
+
+	tmp[0] = wmt_mmio_res(VT8500_LCDC_BASE, SZ_1K);
+	tmp[1] = wmt_irq_res(IRQ_LCDC);
+	wmt_res_add(&vt8500_device_lcdc, tmp, 2);
+
+	tmp[0] = wmt_mmio_res(VT8500_UART0_BASE, 0x1040);
+	tmp[1] = wmt_irq_res(IRQ_UART0);
+	wmt_res_add(&vt8500_device_uart0, tmp, 2);
+
+	tmp[0] = wmt_mmio_res(VT8500_UART1_BASE, 0x1040);
+	tmp[1] = wmt_irq_res(IRQ_UART1);
+	wmt_res_add(&vt8500_device_uart1, tmp, 2);
+
+	tmp[0] = wmt_mmio_res(VT8500_UART2_BASE, 0x1040);
+	tmp[1] = wmt_irq_res(IRQ_UART2);
+	wmt_res_add(&vt8500_device_uart2, tmp, 2);
+
+	tmp[0] = wmt_mmio_res(VT8500_UART3_BASE, 0x1040);
+	tmp[1] = wmt_irq_res(IRQ_UART3);
+	wmt_res_add(&vt8500_device_uart3, tmp, 2);
+
+	tmp[0] = wmt_mmio_res(VT8500_EHCI_BASE, SZ_512);
+	tmp[1] = wmt_irq_res(IRQ_EHCI);
+	wmt_res_add(&vt8500_device_ehci, tmp, 2);
+
+	tmp[0] = wmt_mmio_res(VT8500_GEGEA_BASE, SZ_256);
+	wmt_res_add(&vt8500_device_ge_rops, tmp, 1);
+
+	tmp[0] = wmt_mmio_res(VT8500_PWM_BASE, 0x44);
+	wmt_res_add(&vt8500_device_pwm, tmp, 1);
+
+	tmp[0] = wmt_mmio_res(VT8500_RTC_BASE, 0x2c);
+	tmp[1] = wmt_irq_res(IRQ_RTC);
+	tmp[2] = wmt_irq_res(IRQ_RTCSM);
+	wmt_res_add(&vt8500_device_rtc, tmp, 3);
+}
+
+static void __init vt8500_set_externs(void)
+{
+	/* Non-resource-aware stuff */
+	wmt_ic_base = VT8500_IC_BASE;
+	wmt_gpio_base = VT8500_GPIO_BASE;
+	wmt_pmc_base = VT8500_PMC_BASE;
+	wmt_i8042_base = VT8500_PS2_BASE;
+
+	wmt_nr_irqs = VT8500_NR_IRQS;
+	wmt_timer_irq = IRQ_PMCOS0;
+	wmt_gpio_ext_irq[0] = IRQ_EXT0;
+	wmt_gpio_ext_irq[1] = IRQ_EXT1;
+	wmt_gpio_ext_irq[2] = IRQ_EXT2;
+	wmt_gpio_ext_irq[3] = IRQ_EXT3;
+	wmt_gpio_ext_irq[4] = IRQ_EXT4;
+	wmt_gpio_ext_irq[5] = IRQ_EXT5;
+	wmt_gpio_ext_irq[6] = IRQ_EXT6;
+	wmt_gpio_ext_irq[7] = IRQ_EXT7;
+	wmt_i8042_kbd_irq = IRQ_PS2KBD;
+	wmt_i8042_aux_irq = IRQ_PS2MOUSE;
+}
+
+void __init vt8500_map_io(void)
+{
+	iotable_init(wmt_io_desc, ARRAY_SIZE(wmt_io_desc));
+
+	/* Should be done before interrupts and timers are initialized */
+	vt8500_set_externs();
+}
diff --git a/arch/arm/mach-vt8500/devices-wm8505.c b/arch/arm/mach-vt8500/devices-wm8505.c
new file mode 100644
index 0000000..db4594e
--- /dev/null
+++ b/arch/arm/mach-vt8500/devices-wm8505.c
@@ -0,0 +1,99 @@
+/* linux/arch/arm/mach-vt8500/devices-wm8505.c
+ *
+ * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/platform_device.h>
+
+#include <mach/wm8505_regs.h>
+#include <mach/wm8505_irqs.h>
+#include <mach/i8042.h>
+#include "devices.h"
+
+void __init wm8505_set_resources(void)
+{
+	struct resource tmp[3];
+
+	tmp[0] = wmt_mmio_res(WM8505_GOVR_BASE, SZ_512);
+	wmt_res_add(&vt8500_device_wm8505_fb, tmp, 1);
+
+	tmp[0] = wmt_mmio_res(WM8505_UART0_BASE, 0x1040);
+	tmp[1] = wmt_irq_res(IRQ_UART0);
+	wmt_res_add(&vt8500_device_uart0, tmp, 2);
+
+	tmp[0] = wmt_mmio_res(WM8505_UART1_BASE, 0x1040);
+	tmp[1] = wmt_irq_res(IRQ_UART1);
+	wmt_res_add(&vt8500_device_uart1, tmp, 2);
+
+	tmp[0] = wmt_mmio_res(WM8505_UART2_BASE, 0x1040);
+	tmp[1] = wmt_irq_res(IRQ_UART2);
+	wmt_res_add(&vt8500_device_uart2, tmp, 2);
+
+	tmp[0] = wmt_mmio_res(WM8505_UART3_BASE, 0x1040);
+	tmp[1] = wmt_irq_res(IRQ_UART3);
+	wmt_res_add(&vt8500_device_uart3, tmp, 2);
+
+	tmp[0] = wmt_mmio_res(WM8505_UART4_BASE, 0x1040);
+	tmp[1] = wmt_irq_res(IRQ_UART4);
+	wmt_res_add(&vt8500_device_uart4, tmp, 2);
+
+	tmp[0] = wmt_mmio_res(WM8505_UART5_BASE, 0x1040);
+	tmp[1] = wmt_irq_res(IRQ_UART5);
+	wmt_res_add(&vt8500_device_uart5, tmp, 2);
+
+	tmp[0] = wmt_mmio_res(WM8505_EHCI_BASE, SZ_512);
+	tmp[1] = wmt_irq_res(IRQ_EHCI);
+	wmt_res_add(&vt8500_device_ehci, tmp, 2);
+
+	tmp[0] = wmt_mmio_res(WM8505_GEGEA_BASE, SZ_256);
+	wmt_res_add(&vt8500_device_ge_rops, tmp, 1);
+
+	tmp[0] = wmt_mmio_res(WM8505_PWM_BASE, 0x44);
+	wmt_res_add(&vt8500_device_pwm, tmp, 1);
+
+	tmp[0] = wmt_mmio_res(WM8505_RTC_BASE, 0x2c);
+	tmp[1] = wmt_irq_res(IRQ_RTC);
+	tmp[2] = wmt_irq_res(IRQ_RTCSM);
+	wmt_res_add(&vt8500_device_rtc, tmp, 3);
+}
+
+static void __init wm8505_set_externs(void)
+{
+	/* Non-resource-aware stuff */
+	wmt_ic_base = WM8505_IC_BASE;
+	wmt_sic_base = WM8505_SIC_BASE;
+	wmt_gpio_base = WM8505_GPIO_BASE;
+	wmt_pmc_base = WM8505_PMC_BASE;
+	wmt_i8042_base = WM8505_PS2_BASE;
+
+	wmt_nr_irqs = WM8505_NR_IRQS;
+	wmt_timer_irq = IRQ_PMCOS0;
+	wmt_gpio_ext_irq[0] = IRQ_EXT0;
+	wmt_gpio_ext_irq[1] = IRQ_EXT1;
+	wmt_gpio_ext_irq[2] = IRQ_EXT2;
+	wmt_gpio_ext_irq[3] = IRQ_EXT3;
+	wmt_gpio_ext_irq[4] = IRQ_EXT4;
+	wmt_gpio_ext_irq[5] = IRQ_EXT5;
+	wmt_gpio_ext_irq[6] = IRQ_EXT6;
+	wmt_gpio_ext_irq[7] = IRQ_EXT7;
+	wmt_i8042_kbd_irq = IRQ_PS2KBD;
+	wmt_i8042_aux_irq = IRQ_PS2MOUSE;
+}
+
+void __init wm8505_map_io(void)
+{
+	iotable_init(wmt_io_desc, ARRAY_SIZE(wmt_io_desc));
+
+	/* Should be done before interrupts and timers are initialized */
+	wm8505_set_externs();
+}
diff --git a/arch/arm/mach-vt8500/devices.c b/arch/arm/mach-vt8500/devices.c
new file mode 100644
index 0000000..1fcdc36
--- /dev/null
+++ b/arch/arm/mach-vt8500/devices.c
@@ -0,0 +1,270 @@
+/* linux/arch/arm/mach-vt8500/devices.c
+ *
+ * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/pwm_backlight.h>
+#include <linux/memblock.h>
+
+#include <asm/mach/arch.h>
+
+#include <mach/vt8500fb.h>
+#include <mach/i8042.h>
+#include "devices.h"
+
+/* These can't use resources currently */
+unsigned long wmt_ic_base __initdata;
+unsigned long wmt_sic_base __initdata;
+unsigned long wmt_gpio_base __initdata;
+unsigned long wmt_pmc_base __initdata;
+unsigned long wmt_i8042_base __initdata;
+
+int wmt_nr_irqs __initdata;
+int wmt_timer_irq __initdata;
+int wmt_gpio_ext_irq[8] __initdata;
+
+/* Should remain accessible after init.
+ * i8042 driver desperately calls for attention...
+ */
+int wmt_i8042_kbd_irq;
+int wmt_i8042_aux_irq;
+
+static u64 fb_dma_mask = DMA_BIT_MASK(32);
+
+struct platform_device vt8500_device_lcdc = {
+	.name           = "vt8500-lcd",
+	.id             = 0,
+	.dev		= {
+		.dma_mask	= &fb_dma_mask,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+	},
+};
+
+struct platform_device vt8500_device_wm8505_fb = {
+	.name           = "wm8505-fb",
+	.id             = 0,
+};
+
+/* Smallest to largest */
+static struct vt8500fb_platform_data panels[] = {
+#ifdef CONFIG_WMT_PANEL_800X480
+{
+	.xres_virtual	= 800,
+	.yres_virtual	= 480 * 2,
+	.mode		= {
+		.name		= "800x480",
+		.xres		= 800,
+		.yres		= 480,
+		.left_margin	= 88,
+		.right_margin	= 40,
+		.upper_margin	= 32,
+		.lower_margin	= 11,
+		.hsync_len	= 0,
+		.vsync_len	= 1,
+		.vmode		= FB_VMODE_NONINTERLACED,
+	},
+},
+#endif
+#ifdef CONFIG_WMT_PANEL_800X600
+{
+	.xres_virtual	= 800,
+	.yres_virtual	= 600 * 2,
+	.mode		= {
+		.name		= "800x600",
+		.xres		= 800,
+		.yres		= 600,
+		.left_margin	= 88,
+		.right_margin	= 40,
+		.upper_margin	= 32,
+		.lower_margin	= 11,
+		.hsync_len	= 0,
+		.vsync_len	= 1,
+		.vmode		= FB_VMODE_NONINTERLACED,
+	},
+},
+#endif
+#ifdef CONFIG_WMT_PANEL_1024X576
+{
+	.xres_virtual	= 1024,
+	.yres_virtual	= 576 * 2,
+	.mode		= {
+		.name		= "1024x576",
+		.xres		= 1024,
+		.yres		= 576,
+		.left_margin	= 40,
+		.right_margin	= 24,
+		.upper_margin	= 32,
+		.lower_margin	= 11,
+		.hsync_len	= 96,
+		.vsync_len	= 2,
+		.vmode		= FB_VMODE_NONINTERLACED,
+	},
+},
+#endif
+#ifdef CONFIG_WMT_PANEL_1024X600
+{
+	.xres_virtual	= 1024,
+	.yres_virtual	= 600 * 2,
+	.mode		= {
+		.name		= "1024x600",
+		.xres		= 1024,
+		.yres		= 600,
+		.left_margin	= 66,
+		.right_margin	= 2,
+		.upper_margin	= 19,
+		.lower_margin	= 1,
+		.hsync_len	= 23,
+		.vsync_len	= 8,
+		.vmode		= FB_VMODE_NONINTERLACED,
+	},
+},
+#endif
+};
+
+static int current_panel_idx __initdata = ARRAY_SIZE(panels) - 1;
+
+static int __init panel_setup(char *str)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(panels); i++) {
+		if (strcmp(panels[i].mode.name, str) == 0) {
+			current_panel_idx = i;
+			break;
+		}
+	}
+	return 0;
+}
+
+early_param("panel", panel_setup);
+
+static inline void preallocate_fb(struct vt8500fb_platform_data *p,
+				  unsigned long align) {
+	p->video_mem_len = (p->xres_virtual * p->yres_virtual * 4) >>
+			(p->bpp > 16 ? 0 : (p->bpp > 8 ? 1 :
+					(8 / p->bpp) + 1));
+	p->video_mem_phys = (unsigned long)memblock_alloc(p->video_mem_len,
+							  align);
+	p->video_mem_virt = phys_to_virt(p->video_mem_phys);
+}
+
+struct platform_device vt8500_device_uart0 = {
+	.name		= "vt8500_serial",
+	.id		= 0,
+};
+
+struct platform_device vt8500_device_uart1 = {
+	.name		= "vt8500_serial",
+	.id		= 1,
+};
+
+struct platform_device vt8500_device_uart2 = {
+	.name		= "vt8500_serial",
+	.id		= 2,
+};
+
+struct platform_device vt8500_device_uart3 = {
+	.name		= "vt8500_serial",
+	.id		= 3,
+};
+
+struct platform_device vt8500_device_uart4 = {
+	.name		= "vt8500_serial",
+	.id		= 4,
+};
+
+struct platform_device vt8500_device_uart5 = {
+	.name		= "vt8500_serial",
+	.id		= 5,
+};
+
+static u64 ehci_dma_mask = DMA_BIT_MASK(32);
+
+struct platform_device vt8500_device_ehci = {
+	.name		= "vt8500-ehci",
+	.id		= 0,
+	.dev		= {
+		.dma_mask	= &ehci_dma_mask,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+	},
+};
+
+struct platform_device vt8500_device_ge_rops = {
+	.name		= "wmt_ge_rops",
+	.id		= -1,
+};
+
+struct platform_device vt8500_device_pwm = {
+	.name		= "vt8500-pwm",
+	.id		= 0,
+};
+
+static struct platform_pwm_backlight_data vt8500_pwmbl_data = {
+	.pwm_id		= 0,
+	.max_brightness	= 128,
+	.dft_brightness = 70,
+	.pwm_period_ns	= 250000, /* revisit when clocks are implemented */
+};
+
+struct platform_device vt8500_device_pwmbl = {
+	.name		= "pwm-backlight",
+	.id		= 0,
+	.dev		= {
+		.platform_data = &vt8500_pwmbl_data,
+	},
+};
+
+struct platform_device vt8500_device_rtc = {
+	.name		= "vt8500-rtc",
+	.id		= 0,
+};
+
+struct map_desc wmt_io_desc[] __initdata = {
+	/* SoC MMIO registers */
+	[0] = {
+		.virtual	= 0xf8000000,
+		.pfn		= __phys_to_pfn(0xd8000000),
+		.length		= 0x00390000, /* max of all chip variants */
+		.type		= MT_DEVICE
+	},
+	/* PCI I/O space, numbers tied to those in <mach/io.h> */
+	[1] = {
+		.virtual	= 0xf0000000,
+		.pfn		= __phys_to_pfn(0xc0000000),
+		.length		= SZ_64K,
+		.type		= MT_DEVICE
+	},
+};
+
+void __init vt8500_reserve_mem(void)
+{
+#ifdef CONFIG_FB_VT8500
+	panels[current_panel_idx].bpp = 16; /* Always use RGB565 */
+	preallocate_fb(&panels[current_panel_idx], SZ_4M);
+	vt8500_device_lcdc.dev.platform_data = &panels[current_panel_idx];
+#endif
+}
+
+void __init wm8505_reserve_mem(void)
+{
+#if defined CONFIG_FB_WM8505
+	panels[current_panel_idx].bpp = 32; /* Always use RGB888 */
+	preallocate_fb(&panels[current_panel_idx], 32);
+	vt8500_device_wm8505_fb.dev.platform_data = &panels[current_panel_idx];
+#endif
+}
diff --git a/arch/arm/mach-vt8500/devices.h b/arch/arm/mach-vt8500/devices.h
new file mode 100644
index 0000000..188d4e1
--- /dev/null
+++ b/arch/arm/mach-vt8500/devices.h
@@ -0,0 +1,88 @@
+/* linux/arch/arm/mach-vt8500/devices.h
+ *
+ * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __ARCH_ARM_MACH_VT8500_DEVICES_H
+#define __ARCH_ARM_MACH_VT8500_DEVICES_H
+
+#include <linux/platform_device.h>
+#include <asm/mach/map.h>
+
+void __init vt8500_init_irq(void);
+void __init wm8505_init_irq(void);
+void __init vt8500_map_io(void);
+void __init wm8505_map_io(void);
+void __init vt8500_reserve_mem(void);
+void __init wm8505_reserve_mem(void);
+void __init vt8500_gpio_init(void);
+void __init vt8500_set_resources(void);
+void __init wm8505_set_resources(void);
+
+extern unsigned long wmt_ic_base __initdata;
+extern unsigned long wmt_sic_base __initdata;
+extern unsigned long wmt_gpio_base __initdata;
+extern unsigned long wmt_pmc_base __initdata;
+
+extern int wmt_nr_irqs __initdata;
+extern int wmt_timer_irq __initdata;
+extern int wmt_gpio_ext_irq[8] __initdata;
+
+extern struct map_desc wmt_io_desc[2] __initdata;
+
+static inline struct resource wmt_mmio_res(u32 start, u32 size)
+{
+	struct resource tmp = {
+		.flags = IORESOURCE_MEM,
+		.start = start,
+		.end = start + size - 1,
+	};
+
+	return tmp;
+}
+
+static inline struct resource wmt_irq_res(int irq)
+{
+	struct resource tmp = {
+		.flags = IORESOURCE_IRQ,
+		.start = irq,
+		.end = irq,
+	};
+
+	return tmp;
+}
+
+static inline void wmt_res_add(struct platform_device *pdev,
+			       const struct resource *res, unsigned int num)
+{
+	if (unlikely(platform_device_add_resources(pdev, res, num)))
+		pr_err("Failed to assign resources\n");
+}
+
+extern struct sys_timer vt8500_timer;
+
+extern struct platform_device vt8500_device_uart0;
+extern struct platform_device vt8500_device_uart1;
+extern struct platform_device vt8500_device_uart2;
+extern struct platform_device vt8500_device_uart3;
+extern struct platform_device vt8500_device_uart4;
+extern struct platform_device vt8500_device_uart5;
+
+extern struct platform_device vt8500_device_lcdc;
+extern struct platform_device vt8500_device_wm8505_fb;
+extern struct platform_device vt8500_device_ehci;
+extern struct platform_device vt8500_device_ge_rops;
+extern struct platform_device vt8500_device_pwm;
+extern struct platform_device vt8500_device_pwmbl;
+extern struct platform_device vt8500_device_rtc;
+#endif
diff --git a/arch/arm/mach-vt8500/gpio.c b/arch/arm/mach-vt8500/gpio.c
new file mode 100644
index 0000000..2bcc0ec
--- /dev/null
+++ b/arch/arm/mach-vt8500/gpio.c
@@ -0,0 +1,240 @@
+/* linux/arch/arm/mach-vt8500/gpio.c
+ *
+ * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+
+#include "devices.h"
+
+#define to_vt8500(__chip) container_of(__chip, struct vt8500_gpio_chip, chip)
+
+#define ENABLE_REGS	0x0
+#define DIRECTION_REGS	0x20
+#define OUTVALUE_REGS	0x40
+#define INVALUE_REGS	0x60
+
+#define EXT_REGOFF	0x1c
+
+static void __iomem *regbase;
+
+struct vt8500_gpio_chip {
+	struct gpio_chip	chip;
+	unsigned int		shift;
+	unsigned int		regoff;
+};
+
+static int gpio_to_irq_map[8];
+
+static int vt8500_muxed_gpio_request(struct gpio_chip *chip,
+				     unsigned offset)
+{
+	struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
+	unsigned val = readl(regbase + ENABLE_REGS + vt8500_chip->regoff);
+
+	val |= (1 << vt8500_chip->shift << offset);
+	writel(val, regbase + ENABLE_REGS + vt8500_chip->regoff);
+
+	return 0;
+}
+
+static void vt8500_muxed_gpio_free(struct gpio_chip *chip,
+				   unsigned offset)
+{
+	struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
+	unsigned val = readl(regbase + ENABLE_REGS + vt8500_chip->regoff);
+
+	val &= ~(1 << vt8500_chip->shift << offset);
+	writel(val, regbase + ENABLE_REGS + vt8500_chip->regoff);
+}
+
+static int vt8500_muxed_gpio_direction_input(struct gpio_chip *chip,
+				       unsigned offset)
+{
+	struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
+	unsigned val = readl(regbase + DIRECTION_REGS + vt8500_chip->regoff);
+
+	val &= ~(1 << vt8500_chip->shift << offset);
+	writel(val, regbase + DIRECTION_REGS + vt8500_chip->regoff);
+
+	return 0;
+}
+
+static int vt8500_muxed_gpio_direction_output(struct gpio_chip *chip,
+					unsigned offset, int value)
+{
+	struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
+	unsigned val = readl(regbase + DIRECTION_REGS + vt8500_chip->regoff);
+
+	val |= (1 << vt8500_chip->shift << offset);
+	writel(val, regbase + DIRECTION_REGS + vt8500_chip->regoff);
+
+	if (value) {
+		val = readl(regbase + OUTVALUE_REGS + vt8500_chip->regoff);
+		val |= (1 << vt8500_chip->shift << offset);
+		writel(val, regbase + OUTVALUE_REGS + vt8500_chip->regoff);
+	}
+	return 0;
+}
+
+static int vt8500_muxed_gpio_get_value(struct gpio_chip *chip,
+				       unsigned offset)
+{
+	struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
+
+	return (readl(regbase + INVALUE_REGS + vt8500_chip->regoff)
+		>> vt8500_chip->shift >> offset) & 1;
+}
+
+static void vt8500_muxed_gpio_set_value(struct gpio_chip *chip,
+					unsigned offset, int value)
+{
+	struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
+	unsigned val = readl(regbase + INVALUE_REGS + vt8500_chip->regoff);
+
+	if (value)
+		val |= (1 << vt8500_chip->shift << offset);
+	else
+		val &= ~(1 << vt8500_chip->shift << offset);
+
+	writel(val, regbase + INVALUE_REGS + vt8500_chip->regoff);
+}
+
+#define VT8500_GPIO_BANK(__name, __shift, __off, __base, __num)		\
+{									\
+	.chip = {							\
+		.label			= __name,			\
+		.request		= vt8500_muxed_gpio_request,	\
+		.free			= vt8500_muxed_gpio_free,	\
+		.direction_input  = vt8500_muxed_gpio_direction_input,	\
+		.direction_output = vt8500_muxed_gpio_direction_output,	\
+		.get			= vt8500_muxed_gpio_get_value,	\
+		.set			= vt8500_muxed_gpio_set_value,	\
+		.can_sleep		= 0,				\
+		.base			= __base,			\
+		.ngpio			= __num,			\
+	},								\
+	.shift		= __shift,					\
+	.regoff		= __off,					\
+}
+
+static struct vt8500_gpio_chip vt8500_muxed_gpios[] = {
+	VT8500_GPIO_BANK("uart0",	0,	0x0,	8,	4),
+	VT8500_GPIO_BANK("uart1",	4,	0x0,	12,	4),
+	VT8500_GPIO_BANK("spi0",	8,	0x0,	16,	4),
+	VT8500_GPIO_BANK("spi1",	12,	0x0,	20,	4),
+	VT8500_GPIO_BANK("spi2",	16,	0x0,	24,	4),
+	VT8500_GPIO_BANK("pwmout",	24,	0x0,	28,	2),
+
+	VT8500_GPIO_BANK("sdmmc",	0,	0x4,	30,	11),
+	VT8500_GPIO_BANK("ms",		16,	0x4,	41,	7),
+	VT8500_GPIO_BANK("i2c0",	24,	0x4,	48,	2),
+	VT8500_GPIO_BANK("i2c1",	26,	0x4,	50,	2),
+
+	VT8500_GPIO_BANK("mii",		0,	0x8,	52,	20),
+	VT8500_GPIO_BANK("see",		20,	0x8,	72,	4),
+	VT8500_GPIO_BANK("ide",		24,	0x8,	76,	7),
+
+	VT8500_GPIO_BANK("ccir",	0,	0xc,	83,	19),
+
+	VT8500_GPIO_BANK("ts",		8,	0x10,	102,	11),
+
+	VT8500_GPIO_BANK("lcd",		0,	0x14,	113,	23),
+};
+
+static int vt8500_gpio_direction_input(struct gpio_chip *chip,
+				       unsigned offset)
+{
+	unsigned val = readl(regbase + DIRECTION_REGS + EXT_REGOFF);
+
+	val &= ~(1 << offset);
+	writel(val, regbase + DIRECTION_REGS + EXT_REGOFF);
+	return 0;
+}
+
+static int vt8500_gpio_direction_output(struct gpio_chip *chip,
+					unsigned offset, int value)
+{
+	unsigned val = readl(regbase + DIRECTION_REGS + EXT_REGOFF);
+
+	val |= (1 << offset);
+	writel(val, regbase + DIRECTION_REGS + EXT_REGOFF);
+
+	if (value) {
+		val = readl(regbase + OUTVALUE_REGS + EXT_REGOFF);
+		val |= (1 << offset);
+		writel(val, regbase + OUTVALUE_REGS + EXT_REGOFF);
+	}
+	return 0;
+}
+
+static int vt8500_gpio_get_value(struct gpio_chip *chip,
+				       unsigned offset)
+{
+	return (readl(regbase + INVALUE_REGS + EXT_REGOFF) >> offset) & 1;
+}
+
+static void vt8500_gpio_set_value(struct gpio_chip *chip,
+					unsigned offset, int value)
+{
+	unsigned val = readl(regbase + OUTVALUE_REGS + EXT_REGOFF);
+
+	if (value)
+		val |= (1 << offset);
+	else
+		val &= ~(1 << offset);
+
+	writel(val, regbase + OUTVALUE_REGS + EXT_REGOFF);
+}
+
+static int vt8500_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+	if (offset > 7)
+		return -EINVAL;
+
+	return gpio_to_irq_map[offset];
+}
+
+static struct gpio_chip vt8500_external_gpios = {
+	.label			= "extgpio",
+	.direction_input	= vt8500_gpio_direction_input,
+	.direction_output	= vt8500_gpio_direction_output,
+	.get			= vt8500_gpio_get_value,
+	.set			= vt8500_gpio_set_value,
+	.to_irq			= vt8500_gpio_to_irq,
+	.can_sleep		= 0,
+	.base			= 0,
+	.ngpio			= 8,
+};
+
+void __init vt8500_gpio_init(void)
+{
+	int i;
+
+	for (i = 0; i < 8; i++)
+		gpio_to_irq_map[i] = wmt_gpio_ext_irq[i];
+
+	regbase = ioremap(wmt_gpio_base, SZ_64K);
+	if (!regbase) {
+		printk(KERN_ERR "Failed to map MMIO registers for GPIO\n");
+		return;
+	}
+
+	gpiochip_add(&vt8500_external_gpios);
+
+	for (i = 0; i < ARRAY_SIZE(vt8500_muxed_gpios); i++)
+		gpiochip_add(&vt8500_muxed_gpios[i].chip);
+}
diff --git a/arch/arm/mach-vt8500/include/mach/debug-macro.S b/arch/arm/mach-vt8500/include/mach/debug-macro.S
new file mode 100644
index 0000000..f119162
--- /dev/null
+++ b/arch/arm/mach-vt8500/include/mach/debug-macro.S
@@ -0,0 +1,31 @@
+/*
+ * arch/arm/mach-vt8500/include/mach/debug-macro.S
+ *
+ *  Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
+ *
+ * Debugging macro include header
+ *
+ * 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.
+ *
+*/
+
+	.macro	addruart, rp, rv
+	mov	\rp,      #0x00200000
+	orr	\rv, \rp, #0xf8000000
+	orr	\rp, \rp, #0xd8000000
+	.endm
+
+	.macro	senduart,rd,rx
+	strb	\rd, [\rx, #0]
+	.endm
+
+	.macro	busyuart,rd,rx
+1001:	ldr	\rd, [\rx, #0x1c]
+	ands	\rd, \rd, #0x2
+	bne	1001b
+	.endm
+
+	.macro	waituart,rd,rx
+	.endm
diff --git a/arch/arm/mach-vt8500/include/mach/entry-macro.S b/arch/arm/mach-vt8500/include/mach/entry-macro.S
new file mode 100644
index 0000000..92684c7
--- /dev/null
+++ b/arch/arm/mach-vt8500/include/mach/entry-macro.S
@@ -0,0 +1,32 @@
+/*
+ * arch/arm/mach-vt8500/include/mach/entry-macro.S
+ *
+ * Low-level IRQ helper macros for VIA VT8500
+ *
+ * This file is licensed under  the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+	.macro	disable_fiq
+	.endm
+
+	.macro  get_irqnr_preamble, base, tmp
+	@ physical 0xd8140000 is virtual 0xf8140000
+	mov	\base, #0xf8000000
+	orr	\base, \base, #0x00140000
+	.endm
+
+	.macro  arch_ret_to_user, tmp1, tmp2
+	.endm
+
+	.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
+	ldr	\irqnr, [\base]
+	cmp	\irqnr, #63 @ may be false positive, check interrupt status
+	bne	1001f
+	ldr	\irqstat, [\base, #0x84]
+	ands	\irqstat, #0x80000000
+	moveq	\irqnr, #0
+1001:
+	.endm
+
diff --git a/arch/arm/mach-vt8500/include/mach/gpio.h b/arch/arm/mach-vt8500/include/mach/gpio.h
new file mode 100644
index 0000000..94ff276
--- /dev/null
+++ b/arch/arm/mach-vt8500/include/mach/gpio.h
@@ -0,0 +1,6 @@
+#include <asm-generic/gpio.h>
+
+#define gpio_get_value	__gpio_get_value
+#define gpio_set_value	__gpio_set_value
+#define gpio_cansleep	__gpio_cansleep
+#define gpio_to_irq	__gpio_to_irq
diff --git a/arch/arm/mach-vt8500/include/mach/hardware.h b/arch/arm/mach-vt8500/include/mach/hardware.h
new file mode 100644
index 0000000..db4163f
--- /dev/null
+++ b/arch/arm/mach-vt8500/include/mach/hardware.h
@@ -0,0 +1,12 @@
+/* arch/arm/mach-vt8500/include/mach/hardware.h
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
diff --git a/arch/arm/mach-vt8500/include/mach/i8042.h b/arch/arm/mach-vt8500/include/mach/i8042.h
new file mode 100644
index 0000000..cd7143c
--- /dev/null
+++ b/arch/arm/mach-vt8500/include/mach/i8042.h
@@ -0,0 +1,18 @@
+/* arch/arm/mach-vt8500/include/mach/i8042.h
+ *
+ * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+extern unsigned long wmt_i8042_base __initdata;
+extern int wmt_i8042_kbd_irq;
+extern int wmt_i8042_aux_irq;
diff --git a/arch/arm/mach-vt8500/include/mach/io.h b/arch/arm/mach-vt8500/include/mach/io.h
new file mode 100644
index 0000000..9077239
--- /dev/null
+++ b/arch/arm/mach-vt8500/include/mach/io.h
@@ -0,0 +1,28 @@
+/*
+ *  arch/arm/mach-vt8500/include/mach/io.h
+ *
+ *  Copyright (C) 2010 Alexey Charkov
+ *
+ * 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_ARM_ARCH_IO_H
+#define __ASM_ARM_ARCH_IO_H
+
+#define IO_SPACE_LIMIT 0xffff
+
+#define __io(a)		__typesafe_io((a) + 0xf0000000)
+#define __mem_pci(a)	(a)
+
+#endif
diff --git a/arch/arm/mach-vt8500/include/mach/irqs.h b/arch/arm/mach-vt8500/include/mach/irqs.h
new file mode 100644
index 0000000..a129fd1
--- /dev/null
+++ b/arch/arm/mach-vt8500/include/mach/irqs.h
@@ -0,0 +1,22 @@
+/*
+ *  arch/arm/mach-vt8500/include/mach/irqs.h
+ *
+ *  Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
+ *
+ * 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
+ */
+
+/* This value is just to make the core happy, never used otherwise */
+#define NR_IRQS 128
diff --git a/arch/arm/mach-vt8500/include/mach/memory.h b/arch/arm/mach-vt8500/include/mach/memory.h
new file mode 100644
index 0000000..175f914
--- /dev/null
+++ b/arch/arm/mach-vt8500/include/mach/memory.h
@@ -0,0 +1,28 @@
+/*
+ *  arch/arm/mach-vt8500/include/mach/memory.h
+ *
+ *  Copyright (C) 2003 ARM Limited
+ *
+ * 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_MEMORY_H
+#define __ASM_ARCH_MEMORY_H
+
+/*
+ * Physical DRAM offset.
+ */
+#define PHYS_OFFSET	UL(0x00000000)
+
+#endif
diff --git a/arch/arm/mach-vt8500/include/mach/system.h b/arch/arm/mach-vt8500/include/mach/system.h
new file mode 100644
index 0000000..d6c757e
--- /dev/null
+++ b/arch/arm/mach-vt8500/include/mach/system.h
@@ -0,0 +1,18 @@
+/*
+ * arch/arm/mach-vt8500/include/mach/system.h
+ *
+ */
+#include <asm/io.h>
+
+/* PM Software Reset request register */
+#define VT8500_PMSR_VIRT	0xf8130060
+
+static inline void arch_idle(void)
+{
+	cpu_do_idle();
+}
+
+static inline void arch_reset(char mode, const char *cmd)
+{
+	writel(1, VT8500_PMSR_VIRT);
+}
diff --git a/arch/arm/mach-vt8500/include/mach/timex.h b/arch/arm/mach-vt8500/include/mach/timex.h
new file mode 100644
index 0000000..8487e4c
--- /dev/null
+++ b/arch/arm/mach-vt8500/include/mach/timex.h
@@ -0,0 +1,26 @@
+/*
+ *  arch/arm/mach-vt8500/include/mach/timex.h
+ *
+ *  Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
+ *
+ * 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 MACH_TIMEX_H
+#define MACH_TIMEX_H
+
+#define CLOCK_TICK_RATE		(3000000)
+
+#endif /* MACH_TIMEX_H */
diff --git a/arch/arm/mach-vt8500/include/mach/uncompress.h b/arch/arm/mach-vt8500/include/mach/uncompress.h
new file mode 100644
index 0000000..bb9e2d2
--- /dev/null
+++ b/arch/arm/mach-vt8500/include/mach/uncompress.h
@@ -0,0 +1,37 @@
+/* arch/arm/mach-vt8500/include/mach/uncompress.h
+ *
+ * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
+ *
+ * Based on arch/arm/mach-dove/include/mach/uncompress.h
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#define UART0_PHYS 0xd8200000
+#include <asm/io.h>
+
+static void putc(const char c)
+{
+	while (readb(UART0_PHYS + 0x1c) & 0x2)
+		/* Tx busy, wait and poll */;
+
+	writeb(c, UART0_PHYS);
+}
+
+static void flush(void)
+{
+}
+
+/*
+ * nothing to do
+ */
+#define arch_decomp_setup()
+#define arch_decomp_wdog()
diff --git a/arch/arm/mach-vt8500/include/mach/vmalloc.h b/arch/arm/mach-vt8500/include/mach/vmalloc.h
new file mode 100644
index 0000000..4642290
--- /dev/null
+++ b/arch/arm/mach-vt8500/include/mach/vmalloc.h
@@ -0,0 +1,20 @@
+/*
+ *  arch/arm/mach-vt8500/include/mach/vmalloc.h
+ *
+ *  Copyright (C) 2000 Russell King.
+ *
+ * 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
+ */
+#define VMALLOC_END	0xd0000000UL
diff --git a/arch/arm/mach-vt8500/include/mach/vt8500_irqs.h b/arch/arm/mach-vt8500/include/mach/vt8500_irqs.h
new file mode 100644
index 0000000..ecfee91
--- /dev/null
+++ b/arch/arm/mach-vt8500/include/mach/vt8500_irqs.h
@@ -0,0 +1,88 @@
+/*
+ *  arch/arm/mach-vt8500/include/mach/vt8500_irqs.h
+ *
+ *  Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
+ *
+ * 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
+ */
+
+/* VT8500 Interrupt Sources */
+
+#define IRQ_JPEGENC	0	/* JPEG Encoder */
+#define IRQ_JPEGDEC	1	/* JPEG Decoder */
+				/* Reserved */
+#define IRQ_PATA	3	/* PATA Controller */
+				/* Reserved */
+#define IRQ_DMA		5	/* DMA Controller */
+#define IRQ_EXT0	6	/* External Interrupt 0 */
+#define IRQ_EXT1	7	/* External Interrupt 1 */
+#define IRQ_GE		8	/* Graphic Engine */
+#define IRQ_GOV		9	/* Graphic Overlay Engine */
+#define IRQ_ETHER	10	/* Ethernet MAC */
+#define IRQ_MPEGTS	11	/* Transport Stream Interface */
+#define IRQ_LCDC	12	/* LCD Controller */
+#define IRQ_EXT2	13	/* External Interrupt 2 */
+#define IRQ_EXT3	14	/* External Interrupt 3 */
+#define IRQ_EXT4	15	/* External Interrupt 4 */
+#define IRQ_CIPHER	16	/* Cipher */
+#define IRQ_VPP		17	/* Video Post-Processor */
+#define IRQ_I2C1	18	/* I2C 1 */
+#define IRQ_I2C0	19	/* I2C 0 */
+#define IRQ_SDMMC	20	/* SD/MMC Controller */
+#define IRQ_SDMMC_DMA	21	/* SD/MMC Controller DMA */
+#define IRQ_PMC_WU	22	/* Power Management Controller Wakeup */
+				/* Reserved */
+#define IRQ_SPI0	24	/* SPI 0 */
+#define IRQ_SPI1	25	/* SPI 1 */
+#define IRQ_SPI2	26	/* SPI 2 */
+#define IRQ_LCDDF	27	/* LCD Data Formatter */
+#define IRQ_NAND	28	/* NAND Flash Controller */
+#define IRQ_NAND_DMA	29	/* NAND Flash Controller DMA */
+#define IRQ_MS		30	/* MemoryStick Controller */
+#define IRQ_MS_DMA	31	/* MemoryStick Controller DMA */
+#define IRQ_UART0	32	/* UART 0 */
+#define IRQ_UART1	33	/* UART 1 */
+#define IRQ_I2S		34	/* I2S */
+#define IRQ_PCM		35	/* PCM */
+#define IRQ_PMCOS0	36	/* PMC OS Timer 0 */
+#define IRQ_PMCOS1	37	/* PMC OS Timer 1 */
+#define IRQ_PMCOS2	38	/* PMC OS Timer 2 */
+#define IRQ_PMCOS3	39	/* PMC OS Timer 3 */
+#define IRQ_VPU		40	/* Video Processing Unit */
+#define IRQ_VID		41	/* Video Digital Input Interface */
+#define IRQ_AC97	42	/* AC97 Interface */
+#define IRQ_EHCI	43	/* USB */
+#define IRQ_NOR		44	/* NOR Flash Controller */
+#define IRQ_PS2MOUSE	45	/* PS/2 Mouse */
+#define IRQ_PS2KBD	46	/* PS/2 Keyboard */
+#define IRQ_UART2	47	/* UART 2 */
+#define IRQ_RTC		48	/* RTC Interrupt */
+#define IRQ_RTCSM	49	/* RTC Second/Minute Update Interrupt */
+#define IRQ_UART3	50	/* UART 3 */
+#define IRQ_ADC		51	/* ADC */
+#define IRQ_EXT5	52	/* External Interrupt 5 */
+#define IRQ_EXT6	53	/* External Interrupt 6 */
+#define IRQ_EXT7	54	/* External Interrupt 7 */
+#define IRQ_CIR		55	/* CIR */
+#define IRQ_DMA0	56	/* DMA Channel 0 */
+#define IRQ_DMA1	57	/* DMA Channel 1 */
+#define IRQ_DMA2	58	/* DMA Channel 2 */
+#define IRQ_DMA3	59	/* DMA Channel 3 */
+#define IRQ_DMA4	60	/* DMA Channel 4 */
+#define IRQ_DMA5	61	/* DMA Channel 5 */
+#define IRQ_DMA6	62	/* DMA Channel 6 */
+#define IRQ_DMA7	63	/* DMA Channel 7 */
+
+#define VT8500_NR_IRQS		64
diff --git a/arch/arm/mach-vt8500/include/mach/vt8500_regs.h b/arch/arm/mach-vt8500/include/mach/vt8500_regs.h
new file mode 100644
index 0000000..29c63ec
--- /dev/null
+++ b/arch/arm/mach-vt8500/include/mach/vt8500_regs.h
@@ -0,0 +1,79 @@
+/*
+ *  arch/arm/mach-vt8500/include/mach/vt8500_regs.h
+ *
+ *  Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
+ *
+ * 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_ARM_ARCH_VT8500_REGS_H
+#define __ASM_ARM_ARCH_VT8500_REGS_H
+
+/* VT8500 Registers Map */
+
+#define VT8500_REGS_START_PHYS	0xd8000000	/* Start of MMIO registers */
+#define VT8500_REGS_START_VIRT	0xf8000000	/* Virtual mapping start */
+
+#define VT8500_DDR_BASE		0xd8000000	/* 1k	DDR/DDR2 Memory
+							Controller */
+#define VT8500_DMA_BASE		0xd8001000	/* 1k	DMA Controller */
+#define VT8500_SFLASH_BASE	0xd8002000	/* 1k	Serial Flash Memory
+							Controller */
+#define VT8500_ETHER_BASE	0xd8004000	/* 1k	Ethernet MAC 0 */
+#define VT8500_CIPHER_BASE	0xd8006000	/* 4k	Cipher */
+#define VT8500_USB_BASE		0xd8007800	/* 2k	USB OTG */
+# define VT8500_EHCI_BASE	0xd8007900	/*	EHCI */
+# define VT8500_UHCI_BASE	0xd8007b01	/*	UHCI */
+#define VT8500_PATA_BASE	0xd8008000	/* 512	PATA */
+#define VT8500_PS2_BASE		0xd8008800	/* 1k	PS/2 */
+#define VT8500_NAND_BASE	0xd8009000	/* 1k	NAND Controller */
+#define VT8500_NOR_BASE		0xd8009400	/* 1k	NOR Controller */
+#define VT8500_SDMMC_BASE	0xd800a000	/* 1k	SD/MMC Controller */
+#define VT8500_MS_BASE		0xd800b000	/* 1k	MS/MSPRO Controller */
+#define VT8500_LCDC_BASE	0xd800e400	/* 1k	LCD Controller */
+#define VT8500_VPU_BASE		0xd8050000	/* 256	VPU */
+#define VT8500_GOV_BASE		0xd8050300	/* 256	GOV */
+#define VT8500_GEGEA_BASE	0xd8050400	/* 768	GE/GE Alpha Mixing */
+#define VT8500_LCDF_BASE	0xd8050900	/* 256	LCD Formatter */
+#define VT8500_VID_BASE		0xd8050a00	/* 256	VID */
+#define VT8500_VPP_BASE		0xd8050b00	/* 256	VPP */
+#define VT8500_TSBK_BASE	0xd80f4000	/* 4k	TSBK */
+#define VT8500_JPEGDEC_BASE	0xd80fe000	/* 4k	JPEG Decoder */
+#define VT8500_JPEGENC_BASE	0xd80ff000	/* 4k	JPEG Encoder */
+#define VT8500_RTC_BASE		0xd8100000	/* 64k	RTC */
+#define VT8500_GPIO_BASE	0xd8110000	/* 64k	GPIO Configuration */
+#define VT8500_SCC_BASE		0xd8120000	/* 64k	System Configuration*/
+#define VT8500_PMC_BASE		0xd8130000	/* 64k	PMC Configuration */
+#define VT8500_IC_BASE		0xd8140000	/* 64k	Interrupt Controller*/
+#define VT8500_UART0_BASE	0xd8200000	/* 64k	UART 0 */
+#define VT8500_UART2_BASE	0xd8210000	/* 64k	UART 2 */
+#define VT8500_PWM_BASE		0xd8220000	/* 64k	PWM Configuration */
+#define VT8500_SPI0_BASE	0xd8240000	/* 64k	SPI 0 */
+#define VT8500_SPI1_BASE	0xd8250000	/* 64k	SPI 1 */
+#define VT8500_CIR_BASE		0xd8270000	/* 64k	CIR */
+#define VT8500_I2C0_BASE	0xd8280000	/* 64k	I2C 0 */
+#define VT8500_AC97_BASE	0xd8290000	/* 64k	AC97 */
+#define VT8500_SPI2_BASE	0xd82a0000	/* 64k	SPI 2 */
+#define VT8500_UART1_BASE	0xd82b0000	/* 64k	UART 1 */
+#define VT8500_UART3_BASE	0xd82c0000	/* 64k	UART 3 */
+#define VT8500_PCM_BASE		0xd82d0000	/* 64k	PCM */
+#define VT8500_I2C1_BASE	0xd8320000	/* 64k	I2C 1 */
+#define VT8500_I2S_BASE		0xd8330000	/* 64k	I2S */
+#define VT8500_ADC_BASE		0xd8340000	/* 64k	ADC */
+
+#define VT8500_REGS_END_PHYS	0xd834ffff	/* End of MMIO registers */
+#define VT8500_REGS_LENGTH	(VT8500_REGS_END_PHYS \
+				- VT8500_REGS_START_PHYS + 1)
+
+#endif
diff --git a/arch/arm/mach-vt8500/include/mach/vt8500fb.h b/arch/arm/mach-vt8500/include/mach/vt8500fb.h
new file mode 100644
index 0000000..7f399c3
--- /dev/null
+++ b/arch/arm/mach-vt8500/include/mach/vt8500fb.h
@@ -0,0 +1,31 @@
+/*
+ *  VT8500/WM8505 Frame Buffer platform data definitions
+ *
+ *  Copyright (C) 2010 Ed Spiridonov <edo.rus@gmail.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+
+#ifndef _VT8500FB_H
+#define _VT8500FB_H
+
+#include <linux/fb.h>
+
+struct vt8500fb_platform_data {
+	struct fb_videomode	mode;
+	u32			xres_virtual;
+	u32			yres_virtual;
+	u32			bpp;
+	unsigned long		video_mem_phys;
+	void			*video_mem_virt;
+	unsigned long		video_mem_len;
+};
+
+#endif /* _VT8500FB_H */
diff --git a/arch/arm/mach-vt8500/include/mach/wm8505_irqs.h b/arch/arm/mach-vt8500/include/mach/wm8505_irqs.h
new file mode 100644
index 0000000..6128627
--- /dev/null
+++ b/arch/arm/mach-vt8500/include/mach/wm8505_irqs.h
@@ -0,0 +1,115 @@
+/*
+ *  arch/arm/mach-vt8500/include/mach/wm8505_irqs.h
+ *
+ *  Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
+ *
+ * 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
+ */
+
+/* WM8505 Interrupt Sources */
+
+#define IRQ_UHCI	0	/* UHC FS (UHCI?) */
+#define IRQ_EHCI	1	/* UHC HS */
+#define IRQ_UDCDMA	2	/* UDC DMA */
+				/* Reserved */
+#define IRQ_PS2MOUSE	4	/* PS/2 Mouse */
+#define IRQ_UDC		5	/* UDC */
+#define IRQ_EXT0	6	/* External Interrupt 0 */
+#define IRQ_EXT1	7	/* External Interrupt 1 */
+#define IRQ_KEYPAD	8	/* Keypad */
+#define IRQ_DMA		9	/* DMA Controller */
+#define IRQ_ETHER	10	/* Ethernet MAC */
+				/* Reserved */
+				/* Reserved */
+#define IRQ_EXT2	13	/* External Interrupt 2 */
+#define IRQ_EXT3	14	/* External Interrupt 3 */
+#define IRQ_EXT4	15	/* External Interrupt 4 */
+#define IRQ_APB		16	/* APB Bridge */
+#define IRQ_DMA0	17	/* DMA Channel 0 */
+#define IRQ_I2C1	18	/* I2C 1 */
+#define IRQ_I2C0	19	/* I2C 0 */
+#define IRQ_SDMMC	20	/* SD/MMC Controller */
+#define IRQ_SDMMC_DMA	21	/* SD/MMC Controller DMA */
+#define IRQ_PMC_WU	22	/* Power Management Controller Wakeup */
+#define IRQ_PS2KBD	23	/* PS/2 Keyboard */
+#define IRQ_SPI0	24	/* SPI 0 */
+#define IRQ_SPI1	25	/* SPI 1 */
+#define IRQ_SPI2	26	/* SPI 2 */
+#define IRQ_DMA1	27	/* DMA Channel 1 */
+#define IRQ_NAND	28	/* NAND Flash Controller */
+#define IRQ_NAND_DMA	29	/* NAND Flash Controller DMA */
+#define IRQ_UART5	30	/* UART 5 */
+#define IRQ_UART4	31	/* UART 4 */
+#define IRQ_UART0	32	/* UART 0 */
+#define IRQ_UART1	33	/* UART 1 */
+#define IRQ_DMA2	34	/* DMA Channel 2 */
+#define IRQ_I2S		35	/* I2S */
+#define IRQ_PMCOS0	36	/* PMC OS Timer 0 */
+#define IRQ_PMCOS1	37	/* PMC OS Timer 1 */
+#define IRQ_PMCOS2	38	/* PMC OS Timer 2 */
+#define IRQ_PMCOS3	39	/* PMC OS Timer 3 */
+#define IRQ_DMA3	40	/* DMA Channel 3 */
+#define IRQ_DMA4	41	/* DMA Channel 4 */
+#define IRQ_AC97	42	/* AC97 Interface */
+				/* Reserved */
+#define IRQ_NOR		44	/* NOR Flash Controller */
+#define IRQ_DMA5	45	/* DMA Channel 5 */
+#define IRQ_DMA6	46	/* DMA Channel 6 */
+#define IRQ_UART2	47	/* UART 2 */
+#define IRQ_RTC		48	/* RTC Interrupt */
+#define IRQ_RTCSM	49	/* RTC Second/Minute Update Interrupt */
+#define IRQ_UART3	50	/* UART 3 */
+#define IRQ_DMA7	51	/* DMA Channel 7 */
+#define IRQ_EXT5	52	/* External Interrupt 5 */
+#define IRQ_EXT6	53	/* External Interrupt 6 */
+#define IRQ_EXT7	54	/* External Interrupt 7 */
+#define IRQ_CIR		55	/* CIR */
+#define IRQ_SIC0	56	/* SIC IRQ0 */
+#define IRQ_SIC1	57	/* SIC IRQ1 */
+#define IRQ_SIC2	58	/* SIC IRQ2 */
+#define IRQ_SIC3	59	/* SIC IRQ3 */
+#define IRQ_SIC4	60	/* SIC IRQ4 */
+#define IRQ_SIC5	61	/* SIC IRQ5 */
+#define IRQ_SIC6	62	/* SIC IRQ6 */
+#define IRQ_SIC7	63	/* SIC IRQ7 */
+				/* Reserved */
+#define IRQ_JPEGDEC	65	/* JPEG Decoder */
+#define IRQ_SAE		66	/* SAE (?) */
+				/* Reserved */
+#define IRQ_VPU		79	/* Video Processing Unit */
+#define IRQ_VPP		80	/* Video Post-Processor */
+#define IRQ_VID		81	/* Video Digital Input Interface */
+#define IRQ_SPU		82	/* SPU (?) */
+#define IRQ_PIP		83	/* PIP Error */
+#define IRQ_GE		84	/* Graphic Engine */
+#define IRQ_GOV		85	/* Graphic Overlay Engine */
+#define IRQ_DVO		86	/* Digital Video Output */
+				/* Reserved */
+#define IRQ_DMA8	92	/* DMA Channel 8 */
+#define IRQ_DMA9	93	/* DMA Channel 9 */
+#define IRQ_DMA10	94	/* DMA Channel 10 */
+#define IRQ_DMA11	95	/* DMA Channel 11 */
+#define IRQ_DMA12	96	/* DMA Channel 12 */
+#define IRQ_DMA13	97	/* DMA Channel 13 */
+#define IRQ_DMA14	98	/* DMA Channel 14 */
+#define IRQ_DMA15	99	/* DMA Channel 15 */
+				/* Reserved */
+#define IRQ_GOVW	111	/* GOVW (?) */
+#define IRQ_GOVRSDSCD	112	/* GOVR SDSCD (?) */
+#define IRQ_GOVRSDMIF	113	/* GOVR SDMIF (?) */
+#define IRQ_GOVRHDSCD	114	/* GOVR HDSCD (?) */
+#define IRQ_GOVRHDMIF	115	/* GOVR HDMIF (?) */
+
+#define WM8505_NR_IRQS		116
diff --git a/arch/arm/mach-vt8500/include/mach/wm8505_regs.h b/arch/arm/mach-vt8500/include/mach/wm8505_regs.h
new file mode 100644
index 0000000..df15509
--- /dev/null
+++ b/arch/arm/mach-vt8500/include/mach/wm8505_regs.h
@@ -0,0 +1,78 @@
+/*
+ *  arch/arm/mach-vt8500/include/mach/wm8505_regs.h
+ *
+ *  Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
+ *
+ * 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_ARM_ARCH_WM8505_REGS_H
+#define __ASM_ARM_ARCH_WM8505_REGS_H
+
+/* WM8505 Registers Map */
+
+#define WM8505_REGS_START_PHYS	0xd8000000	/* Start of MMIO registers */
+#define WM8505_REGS_START_VIRT	0xf8000000	/* Virtual mapping start */
+
+#define WM8505_DDR_BASE		0xd8000400	/* 1k	DDR/DDR2 Memory
+							Controller */
+#define WM8505_DMA_BASE		0xd8001800	/* 1k	DMA Controller */
+#define WM8505_VDMA_BASE	0xd8001c00	/* 1k	VDMA */
+#define WM8505_SFLASH_BASE	0xd8002000	/* 1k	Serial Flash Memory
+							Controller */
+#define WM8505_ETHER_BASE	0xd8004000	/* 1k	Ethernet MAC 0 */
+#define WM8505_CIPHER_BASE	0xd8006000	/* 4k	Cipher */
+#define WM8505_USB_BASE		0xd8007000	/* 2k	USB 2.0 Host */
+# define WM8505_EHCI_BASE	0xd8007100	/*	EHCI */
+# define WM8505_UHCI_BASE	0xd8007301	/*	UHCI */
+#define WM8505_PS2_BASE		0xd8008800	/* 1k	PS/2 */
+#define WM8505_NAND_BASE	0xd8009000	/* 1k	NAND Controller */
+#define WM8505_NOR_BASE		0xd8009400	/* 1k	NOR Controller */
+#define WM8505_SDMMC_BASE	0xd800a000	/* 1k	SD/MMC Controller */
+#define WM8505_VPU_BASE		0xd8050000	/* 256	VPU */
+#define WM8505_GOV_BASE		0xd8050300	/* 256	GOV */
+#define WM8505_GEGEA_BASE	0xd8050400	/* 768	GE/GE Alpha Mixing */
+#define WM8505_GOVR_BASE	0xd8050800	/* 512	GOVR (frambuffer) */
+#define WM8505_VID_BASE		0xd8050a00	/* 256	VID */
+#define WM8505_SCL_BASE		0xd8050d00	/* 256	SCL */
+#define WM8505_VPP_BASE		0xd8050f00	/* 256	VPP */
+#define WM8505_JPEGDEC_BASE	0xd80fe000	/* 4k	JPEG Decoder */
+#define WM8505_RTC_BASE		0xd8100000	/* 64k	RTC */
+#define WM8505_GPIO_BASE	0xd8110000	/* 64k	GPIO Configuration */
+#define WM8505_SCC_BASE		0xd8120000	/* 64k	System Configuration*/
+#define WM8505_PMC_BASE		0xd8130000	/* 64k	PMC Configuration */
+#define WM8505_IC_BASE		0xd8140000	/* 64k	Interrupt Controller*/
+#define WM8505_SIC_BASE		0xd8150000	/* 64k	Secondary IC */
+#define WM8505_UART0_BASE	0xd8200000	/* 64k	UART 0 */
+#define WM8505_UART2_BASE	0xd8210000	/* 64k	UART 2 */
+#define WM8505_PWM_BASE		0xd8220000	/* 64k	PWM Configuration */
+#define WM8505_SPI0_BASE	0xd8240000	/* 64k	SPI 0 */
+#define WM8505_SPI1_BASE	0xd8250000	/* 64k	SPI 1 */
+#define WM8505_KEYPAD_BASE	0xd8260000	/* 64k	Keypad control */
+#define WM8505_CIR_BASE		0xd8270000	/* 64k	CIR */
+#define WM8505_I2C0_BASE	0xd8280000	/* 64k	I2C 0 */
+#define WM8505_AC97_BASE	0xd8290000	/* 64k	AC97 */
+#define WM8505_SPI2_BASE	0xd82a0000	/* 64k	SPI 2 */
+#define WM8505_UART1_BASE	0xd82b0000	/* 64k	UART 1 */
+#define WM8505_UART3_BASE	0xd82c0000	/* 64k	UART 3 */
+#define WM8505_I2C1_BASE	0xd8320000	/* 64k	I2C 1 */
+#define WM8505_I2S_BASE		0xd8330000	/* 64k	I2S */
+#define WM8505_UART4_BASE	0xd8370000	/* 64k	UART 4 */
+#define WM8505_UART5_BASE	0xd8380000	/* 64k	UART 5 */
+
+#define WM8505_REGS_END_PHYS	0xd838ffff	/* End of MMIO registers */
+#define WM8505_REGS_LENGTH	(WM8505_REGS_END_PHYS \
+				- WM8505_REGS_START_PHYS + 1)
+
+#endif
diff --git a/arch/arm/mach-vt8500/irq.c b/arch/arm/mach-vt8500/irq.c
new file mode 100644
index 0000000..5f4ddde
--- /dev/null
+++ b/arch/arm/mach-vt8500/irq.c
@@ -0,0 +1,177 @@
+/*
+ *  arch/arm/mach-vt8500/irq.c
+ *
+ *  Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
+ *
+ * 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/io.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+
+#include <asm/irq.h>
+
+#include "devices.h"
+
+#define VT8500_IC_DCTR		0x40		/* Destination control
+						register, 64*u8 */
+#define VT8500_INT_ENABLE	(1 << 3)
+#define VT8500_TRIGGER_HIGH	(0 << 4)
+#define VT8500_TRIGGER_RISING	(1 << 4)
+#define VT8500_TRIGGER_FALLING	(2 << 4)
+#define VT8500_EDGE		( VT8500_TRIGGER_RISING \
+				| VT8500_TRIGGER_FALLING)
+#define VT8500_IC_STATUS	0x80		/* Interrupt status, 2*u32 */
+
+static void __iomem *ic_regbase;
+static void __iomem *sic_regbase;
+
+static void vt8500_irq_mask(unsigned int irq)
+{
+	void __iomem *base = ic_regbase;
+	u8 edge;
+
+	if (irq >= 64) {
+		base = sic_regbase;
+		irq -= 64;
+	}
+	edge = readb(base + VT8500_IC_DCTR + irq) & VT8500_EDGE;
+	if (edge) {
+		void __iomem *stat_reg = base + VT8500_IC_STATUS
+						+ (irq < 32 ? 0 : 4);
+		unsigned status = readl(stat_reg);
+
+		status |= (1 << (irq & 0x1f));
+		writel(status, stat_reg);
+	} else {
+		u8 dctr = readb(base + VT8500_IC_DCTR + irq);
+
+		dctr &= ~VT8500_INT_ENABLE;
+		writeb(dctr, base + VT8500_IC_DCTR + irq);
+	}
+}
+
+static void vt8500_irq_unmask(unsigned int irq)
+{
+	void __iomem *base = ic_regbase;
+	u8 dctr;
+
+	if (irq >= 64) {
+		base = sic_regbase;
+		irq -= 64;
+	}
+	dctr = readb(base + VT8500_IC_DCTR + irq);
+	dctr |= VT8500_INT_ENABLE;
+	writeb(dctr, base + VT8500_IC_DCTR + irq);
+}
+
+static int vt8500_irq_set_type(unsigned int irq, unsigned int flow_type)
+{
+	void __iomem *base = ic_regbase;
+	unsigned int orig_irq = irq;
+	u8 dctr;
+
+	if (irq >= 64) {
+		base = sic_regbase;
+		irq -= 64;
+	}
+
+	dctr = readb(base + VT8500_IC_DCTR + irq);
+	dctr &= ~VT8500_EDGE;
+
+	switch (flow_type) {
+	case IRQF_TRIGGER_LOW:
+		return -EINVAL;
+	case IRQF_TRIGGER_HIGH:
+		dctr |= VT8500_TRIGGER_HIGH;
+		irq_desc[orig_irq].handle_irq = handle_level_irq;
+		break;
+	case IRQF_TRIGGER_FALLING:
+		dctr |= VT8500_TRIGGER_FALLING;
+		irq_desc[orig_irq].handle_irq = handle_edge_irq;
+		break;
+	case IRQF_TRIGGER_RISING:
+		dctr |= VT8500_TRIGGER_RISING;
+		irq_desc[orig_irq].handle_irq = handle_edge_irq;
+		break;
+	}
+	writeb(dctr, base + VT8500_IC_DCTR + irq);
+
+	return 0;
+}
+
+static struct irq_chip vt8500_irq_chip = {
+	.name      = "vt8500",
+	.ack       = vt8500_irq_mask,
+	.mask      = vt8500_irq_mask,
+	.unmask    = vt8500_irq_unmask,
+	.set_type  = vt8500_irq_set_type,
+};
+
+void __init vt8500_init_irq(void)
+{
+	unsigned int i;
+
+	ic_regbase = ioremap(wmt_ic_base, SZ_64K);
+
+	if (ic_regbase) {
+		/* Enable rotating priority for IRQ */
+		writel((1 << 6), ic_regbase + 0x20);
+		writel(0, ic_regbase + 0x24);
+
+		for (i = 0; i < wmt_nr_irqs; i++) {
+			/* Disable all interrupts and route them to IRQ */
+			writeb(0x00, ic_regbase + VT8500_IC_DCTR + i);
+
+			set_irq_chip(i, &vt8500_irq_chip);
+			set_irq_handler(i, handle_level_irq);
+			set_irq_flags(i, IRQF_VALID);
+		}
+	} else {
+		printk(KERN_ERR "Unable to remap the Interrupt Controller registers, not enabling IRQs!\n");
+	}
+}
+
+void __init wm8505_init_irq(void)
+{
+	unsigned int i;
+
+	ic_regbase = ioremap(wmt_ic_base, SZ_64K);
+	sic_regbase = ioremap(wmt_sic_base, SZ_64K);
+
+	if (ic_regbase && sic_regbase) {
+		/* Enable rotating priority for IRQ */
+		writel((1 << 6), ic_regbase + 0x20);
+		writel(0, ic_regbase + 0x24);
+		writel((1 << 6), sic_regbase + 0x20);
+		writel(0, sic_regbase + 0x24);
+
+		for (i = 0; i < wmt_nr_irqs; i++) {
+			/* Disable all interrupts and route them to IRQ */
+			if (i < 64)
+				writeb(0x00, ic_regbase + VT8500_IC_DCTR + i);
+			else
+				writeb(0x00, sic_regbase + VT8500_IC_DCTR
+								+ i - 64);
+
+			set_irq_chip(i, &vt8500_irq_chip);
+			set_irq_handler(i, handle_level_irq);
+			set_irq_flags(i, IRQF_VALID);
+		}
+	} else {
+		printk(KERN_ERR "Unable to remap the Interrupt Controller registers, not enabling IRQs!\n");
+	}
+}
diff --git a/arch/arm/mach-vt8500/pwm.c b/arch/arm/mach-vt8500/pwm.c
new file mode 100644
index 0000000..8ad825e
--- /dev/null
+++ b/arch/arm/mach-vt8500/pwm.c
@@ -0,0 +1,265 @@
+/*
+ * arch/arm/mach-vt8500/pwm.c
+ *
+ *  Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/pwm.h>
+#include <linux/delay.h>
+
+#include <asm/div64.h>
+
+#define VT8500_NR_PWMS 4
+
+static DEFINE_MUTEX(pwm_lock);
+static LIST_HEAD(pwm_list);
+
+struct pwm_device {
+	struct list_head	node;
+	struct platform_device	*pdev;
+
+	const char	*label;
+
+	void __iomem	*regbase;
+
+	unsigned int	use_count;
+	unsigned int	pwm_id;
+};
+
+#define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t)
+static inline void pwm_busy_wait(void __iomem *reg, u8 bitmask)
+{
+	int loops = msecs_to_loops(10);
+	while ((readb(reg) & bitmask) && --loops)
+		cpu_relax();
+
+	if (unlikely(!loops))
+		pr_warning("Waiting for status bits 0x%x to clear timed out\n",
+			   bitmask);
+}
+
+int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
+{
+	unsigned long long c;
+	unsigned long period_cycles, prescale, pv, dc;
+
+	if (pwm == NULL || period_ns == 0 || duty_ns > period_ns)
+		return -EINVAL;
+
+	c = 25000000/2; /* wild guess --- need to implement clocks */
+	c = c * period_ns;
+	do_div(c, 1000000000);
+	period_cycles = c;
+
+	if (period_cycles < 1)
+		period_cycles = 1;
+	prescale = (period_cycles - 1) / 4096;
+	pv = period_cycles / (prescale + 1) - 1;
+	if (pv > 4095)
+		pv = 4095;
+
+	if (prescale > 1023)
+		return -EINVAL;
+
+	c = (unsigned long long)pv * duty_ns;
+	do_div(c, period_ns);
+	dc = c;
+
+	pwm_busy_wait(pwm->regbase + 0x40 + pwm->pwm_id, (1 << 1));
+	writel(prescale, pwm->regbase + 0x4 + (pwm->pwm_id << 4));
+
+	pwm_busy_wait(pwm->regbase + 0x40 + pwm->pwm_id, (1 << 2));
+	writel(pv, pwm->regbase + 0x8 + (pwm->pwm_id << 4));
+
+	pwm_busy_wait(pwm->regbase + 0x40 + pwm->pwm_id, (1 << 3));
+	writel(dc, pwm->regbase + 0xc + (pwm->pwm_id << 4));
+
+	return 0;
+}
+EXPORT_SYMBOL(pwm_config);
+
+int pwm_enable(struct pwm_device *pwm)
+{
+	pwm_busy_wait(pwm->regbase + 0x40 + pwm->pwm_id, (1 << 0));
+	writel(5, pwm->regbase + (pwm->pwm_id << 4));
+	return 0;
+}
+EXPORT_SYMBOL(pwm_enable);
+
+void pwm_disable(struct pwm_device *pwm)
+{
+	pwm_busy_wait(pwm->regbase + 0x40 + pwm->pwm_id, (1 << 0));
+	writel(0, pwm->regbase + (pwm->pwm_id << 4));
+}
+EXPORT_SYMBOL(pwm_disable);
+
+struct pwm_device *pwm_request(int pwm_id, const char *label)
+{
+	struct pwm_device *pwm;
+	int found = 0;
+
+	mutex_lock(&pwm_lock);
+
+	list_for_each_entry(pwm, &pwm_list, node) {
+		if (pwm->pwm_id == pwm_id) {
+			found = 1;
+			break;
+		}
+	}
+
+	if (found) {
+		if (pwm->use_count == 0) {
+			pwm->use_count++;
+			pwm->label = label;
+		} else {
+			pwm = ERR_PTR(-EBUSY);
+		}
+	} else {
+		pwm = ERR_PTR(-ENOENT);
+	}
+
+	mutex_unlock(&pwm_lock);
+	return pwm;
+}
+EXPORT_SYMBOL(pwm_request);
+
+void pwm_free(struct pwm_device *pwm)
+{
+	mutex_lock(&pwm_lock);
+
+	if (pwm->use_count) {
+		pwm->use_count--;
+		pwm->label = NULL;
+	} else {
+		pr_warning("PWM device already freed\n");
+	}
+
+	mutex_unlock(&pwm_lock);
+}
+EXPORT_SYMBOL(pwm_free);
+
+static inline void __add_pwm(struct pwm_device *pwm)
+{
+	mutex_lock(&pwm_lock);
+	list_add_tail(&pwm->node, &pwm_list);
+	mutex_unlock(&pwm_lock);
+}
+
+static int __devinit pwm_probe(struct platform_device *pdev)
+{
+	struct pwm_device *pwms;
+	struct resource *r;
+	int ret = 0;
+	int i;
+
+	pwms = kzalloc(sizeof(struct pwm_device) * VT8500_NR_PWMS, GFP_KERNEL);
+	if (pwms == NULL) {
+		dev_err(&pdev->dev, "failed to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < VT8500_NR_PWMS; i++) {
+		pwms[i].use_count = 0;
+		pwms[i].pwm_id = i;
+		pwms[i].pdev = pdev;
+	}
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (r == NULL) {
+		dev_err(&pdev->dev, "no memory resource defined\n");
+		ret = -ENODEV;
+		goto err_free;
+	}
+
+	r = request_mem_region(r->start, resource_size(r), pdev->name);
+	if (r == NULL) {
+		dev_err(&pdev->dev, "failed to request memory resource\n");
+		ret = -EBUSY;
+		goto err_free;
+	}
+
+	pwms[0].regbase = ioremap(r->start, resource_size(r));
+	if (pwms[0].regbase == NULL) {
+		dev_err(&pdev->dev, "failed to ioremap() registers\n");
+		ret = -ENODEV;
+		goto err_free_mem;
+	}
+
+	for (i = 1; i < VT8500_NR_PWMS; i++)
+		pwms[i].regbase = pwms[0].regbase;
+
+	for (i = 0; i < VT8500_NR_PWMS; i++)
+		__add_pwm(&pwms[i]);
+
+	platform_set_drvdata(pdev, pwms);
+	return 0;
+
+err_free_mem:
+	release_mem_region(r->start, resource_size(r));
+err_free:
+	kfree(pwms);
+	return ret;
+}
+
+static int __devexit pwm_remove(struct platform_device *pdev)
+{
+	struct pwm_device *pwms;
+	struct resource *r;
+	int i;
+
+	pwms = platform_get_drvdata(pdev);
+	if (pwms == NULL)
+		return -ENODEV;
+
+	mutex_lock(&pwm_lock);
+
+	for (i = 0; i < VT8500_NR_PWMS; i++)
+		list_del(&pwms[i].node);
+	mutex_unlock(&pwm_lock);
+
+	iounmap(pwms[0].regbase);
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	release_mem_region(r->start, resource_size(r));
+
+	kfree(pwms);
+	return 0;
+}
+
+static struct platform_driver pwm_driver = {
+	.driver		= {
+		.name	= "vt8500-pwm",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= pwm_probe,
+	.remove		= __devexit_p(pwm_remove),
+};
+
+static int __init pwm_init(void)
+{
+	return platform_driver_register(&pwm_driver);
+}
+arch_initcall(pwm_init);
+
+static void __exit pwm_exit(void)
+{
+	platform_driver_unregister(&pwm_driver);
+}
+module_exit(pwm_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-vt8500/timer.c b/arch/arm/mach-vt8500/timer.c
new file mode 100644
index 0000000..d5376c5
--- /dev/null
+++ b/arch/arm/mach-vt8500/timer.c
@@ -0,0 +1,155 @@
+/*
+ *  arch/arm/mach-vt8500/timer.c
+ *
+ *  Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
+ *
+ * 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/io.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <linux/delay.h>
+
+#include <asm/mach/time.h>
+
+#include "devices.h"
+
+#define VT8500_TIMER_OFFSET	0x0100
+#define TIMER_MATCH_VAL		0x0000
+#define TIMER_COUNT_VAL		0x0010
+#define TIMER_STATUS_VAL	0x0014
+#define TIMER_IER_VAL		0x001c		/* interrupt enable */
+#define TIMER_CTRL_VAL		0x0020
+#define TIMER_AS_VAL		0x0024		/* access status */
+#define TIMER_COUNT_R_ACTIVE	(1 << 5)	/* not ready for read */
+#define TIMER_COUNT_W_ACTIVE	(1 << 4)	/* not ready for write */
+#define TIMER_MATCH_W_ACTIVE	(1 << 0)	/* not ready for write */
+#define VT8500_TIMER_HZ		3000000
+
+#define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t)
+
+static void __iomem *regbase;
+
+static cycle_t vt8500_timer_read(struct clocksource *cs)
+{
+	int loops = msecs_to_loops(10);
+	writel(3, regbase + TIMER_CTRL_VAL);
+	while ((readl((regbase + TIMER_AS_VAL)) & TIMER_COUNT_R_ACTIVE)
+						&& --loops)
+		cpu_relax();
+	return readl(regbase + TIMER_COUNT_VAL);
+}
+
+struct clocksource clocksource = {
+	.name           = "vt8500_timer",
+	.rating         = 200,
+	.read           = vt8500_timer_read,
+	.mask           = CLOCKSOURCE_MASK(32),
+	.flags          = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static int vt8500_timer_set_next_event(unsigned long cycles,
+				    struct clock_event_device *evt)
+{
+	int loops = msecs_to_loops(10);
+	cycle_t alarm = clocksource.read(&clocksource) + cycles;
+	while ((readl(regbase + TIMER_AS_VAL) & TIMER_MATCH_W_ACTIVE)
+						&& --loops)
+		cpu_relax();
+	writel((unsigned long)alarm, regbase + TIMER_MATCH_VAL);
+
+	if ((signed)(alarm - clocksource.read(&clocksource)) <= 16)
+		return -ETIME;
+
+	writel(1, regbase + TIMER_IER_VAL);
+
+	return 0;
+}
+
+static void vt8500_timer_set_mode(enum clock_event_mode mode,
+			      struct clock_event_device *evt)
+{
+	switch (mode) {
+	case CLOCK_EVT_MODE_RESUME:
+	case CLOCK_EVT_MODE_PERIODIC:
+		break;
+	case CLOCK_EVT_MODE_ONESHOT:
+	case CLOCK_EVT_MODE_UNUSED:
+	case CLOCK_EVT_MODE_SHUTDOWN:
+		writel(readl(regbase + TIMER_CTRL_VAL) | 1,
+			regbase + TIMER_CTRL_VAL);
+		writel(0, regbase + TIMER_IER_VAL);
+		break;
+	}
+}
+
+struct clock_event_device clockevent = {
+	.name           = "vt8500_timer",
+	.features       = CLOCK_EVT_FEAT_ONESHOT,
+	.rating         = 200,
+	.set_next_event = vt8500_timer_set_next_event,
+	.set_mode       = vt8500_timer_set_mode,
+};
+
+static irqreturn_t vt8500_timer_interrupt(int irq, void *dev_id)
+{
+	struct clock_event_device *evt = dev_id;
+	writel(0xf, regbase + TIMER_STATUS_VAL);
+	evt->event_handler(evt);
+
+	return IRQ_HANDLED;
+}
+
+struct irqaction irq = {
+	.name    = "vt8500_timer",
+	.flags   = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
+	.handler = vt8500_timer_interrupt,
+	.dev_id  = &clockevent,
+};
+
+static void __init vt8500_timer_init(void)
+{
+	regbase = ioremap(wmt_pmc_base + VT8500_TIMER_OFFSET, 0x28);
+	if (!regbase)
+		printk(KERN_ERR "vt8500_timer_init: failed to map MMIO registers\n");
+
+	writel(1, regbase + TIMER_CTRL_VAL);
+	writel(0xf, regbase + TIMER_STATUS_VAL);
+	writel(~0, regbase + TIMER_MATCH_VAL);
+
+	if (clocksource_register_hz(&clocksource, VT8500_TIMER_HZ))
+		printk(KERN_ERR "vt8500_timer_init: clocksource_register failed for %s\n",
+					clocksource.name);
+
+	clockevents_calc_mult_shift(&clockevent, VT8500_TIMER_HZ, 4);
+
+	/* copy-pasted from mach-msm; no idea */
+	clockevent.max_delta_ns =
+		clockevent_delta2ns(0xf0000000, &clockevent);
+	clockevent.min_delta_ns = clockevent_delta2ns(4, &clockevent);
+	clockevent.cpumask = cpumask_of(0);
+
+	if (setup_irq(wmt_timer_irq, &irq))
+		printk(KERN_ERR "vt8500_timer_init: setup_irq failed for %s\n",
+					clockevent.name);
+	clockevents_register_device(&clockevent);
+}
+
+struct sys_timer vt8500_timer = {
+	.init = vt8500_timer_init
+};
diff --git a/arch/arm/mach-vt8500/wm8505_7in.c b/arch/arm/mach-vt8500/wm8505_7in.c
new file mode 100644
index 0000000..e73aadb
--- /dev/null
+++ b/arch/arm/mach-vt8500/wm8505_7in.c
@@ -0,0 +1,77 @@
+/*
+ *  arch/arm/mach-vt8500/wm8505_7in.c
+ *
+ *  Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
+ *
+ * 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/io.h>
+#include <linux/pm.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#include "devices.h"
+
+static void __iomem *pmc_hiber;
+
+static struct platform_device *devices[] __initdata = {
+	&vt8500_device_uart0,
+	&vt8500_device_ehci,
+	&vt8500_device_wm8505_fb,
+	&vt8500_device_ge_rops,
+	&vt8500_device_pwm,
+	&vt8500_device_pwmbl,
+	&vt8500_device_rtc,
+};
+
+static void vt8500_power_off(void)
+{
+	local_irq_disable();
+	writew(5, pmc_hiber);
+	asm("mcr%? p15, 0, %0, c7, c0, 4" : : "r" (0));
+}
+
+void __init wm8505_7in_init(void)
+{
+#ifdef CONFIG_FB_WM8505
+	void __iomem *gpio_mux_reg = ioremap(wmt_gpio_base + 0x200, 4);
+	if (gpio_mux_reg) {
+		writel(readl(gpio_mux_reg) | 0x80000000, gpio_mux_reg);
+		iounmap(gpio_mux_reg);
+	} else {
+		printk(KERN_ERR "Could not remap the GPIO mux register, display may not work properly!\n");
+	}
+#endif
+	pmc_hiber = ioremap(wmt_pmc_base + 0x12, 2);
+	if (pmc_hiber)
+		pm_power_off = &vt8500_power_off;
+	else
+		printk(KERN_ERR "PMC Hibernation register could not be remapped, not enabling power off!\n");
+
+	wm8505_set_resources();
+	platform_add_devices(devices, ARRAY_SIZE(devices));
+	vt8500_gpio_init();
+}
+
+MACHINE_START(WM8505_7IN_NETBOOK, "WM8505 7-inch generic netbook")
+	.boot_params	= 0x00000100,
+	.reserve	= wm8505_reserve_mem,
+	.map_io		= wm8505_map_io,
+	.init_irq	= wm8505_init_irq,
+	.timer		= &vt8500_timer,
+	.init_machine	= wm8505_7in_init,
+MACHINE_END
diff --git a/arch/arm/mm/proc-arm1020.S b/arch/arm/mm/proc-arm1020.S
index bcf748d..226e3d8 100644
--- a/arch/arm/mm/proc-arm1020.S
+++ b/arch/arm/mm/proc-arm1020.S
@@ -493,6 +493,9 @@
 	.word	cpu_arm1020_dcache_clean_area
 	.word	cpu_arm1020_switch_mm
 	.word	cpu_arm1020_set_pte_ext
+	.word	0
+	.word	0
+	.word	0
 	.size	arm1020_processor_functions, . - arm1020_processor_functions
 
 	.section ".rodata"
diff --git a/arch/arm/mm/proc-arm1020e.S b/arch/arm/mm/proc-arm1020e.S
index ab7ec26..86d9c2c 100644
--- a/arch/arm/mm/proc-arm1020e.S
+++ b/arch/arm/mm/proc-arm1020e.S
@@ -474,6 +474,9 @@
 	.word	cpu_arm1020e_dcache_clean_area
 	.word	cpu_arm1020e_switch_mm
 	.word	cpu_arm1020e_set_pte_ext
+	.word	0
+	.word	0
+	.word	0
 	.size	arm1020e_processor_functions, . - arm1020e_processor_functions
 
 	.section ".rodata"
diff --git a/arch/arm/mm/proc-arm1022.S b/arch/arm/mm/proc-arm1022.S
index 831c5e5..83d3dd3 100644
--- a/arch/arm/mm/proc-arm1022.S
+++ b/arch/arm/mm/proc-arm1022.S
@@ -457,6 +457,9 @@
 	.word	cpu_arm1022_dcache_clean_area
 	.word	cpu_arm1022_switch_mm
 	.word	cpu_arm1022_set_pte_ext
+	.word	0
+	.word	0
+	.word	0
 	.size	arm1022_processor_functions, . - arm1022_processor_functions
 
 	.section ".rodata"
diff --git a/arch/arm/mm/proc-arm1026.S b/arch/arm/mm/proc-arm1026.S
index e3f7e9a..686043e 100644
--- a/arch/arm/mm/proc-arm1026.S
+++ b/arch/arm/mm/proc-arm1026.S
@@ -452,6 +452,9 @@
 	.word	cpu_arm1026_dcache_clean_area
 	.word	cpu_arm1026_switch_mm
 	.word	cpu_arm1026_set_pte_ext
+	.word	0
+	.word	0
+	.word	0
 	.size	arm1026_processor_functions, . - arm1026_processor_functions
 
 	.section .rodata
diff --git a/arch/arm/mm/proc-arm6_7.S b/arch/arm/mm/proc-arm6_7.S
index 6a7be18..5f79dc4 100644
--- a/arch/arm/mm/proc-arm6_7.S
+++ b/arch/arm/mm/proc-arm6_7.S
@@ -284,6 +284,9 @@
 		.word	cpu_arm6_dcache_clean_area
 		.word	cpu_arm6_switch_mm
 		.word	cpu_arm6_set_pte_ext
+		.word	0
+		.word	0
+		.word	0
 		.size	arm6_processor_functions, . - arm6_processor_functions
 
 /*
@@ -301,6 +304,9 @@
 		.word	cpu_arm7_dcache_clean_area
 		.word	cpu_arm7_switch_mm
 		.word	cpu_arm7_set_pte_ext
+		.word	0
+		.word	0
+		.word	0
 		.size	arm7_processor_functions, . - arm7_processor_functions
 
 		.section ".rodata"
diff --git a/arch/arm/mm/proc-arm720.S b/arch/arm/mm/proc-arm720.S
index c285395..665266d 100644
--- a/arch/arm/mm/proc-arm720.S
+++ b/arch/arm/mm/proc-arm720.S
@@ -185,6 +185,9 @@
 		.word	cpu_arm720_dcache_clean_area
 		.word	cpu_arm720_switch_mm
 		.word	cpu_arm720_set_pte_ext
+		.word	0
+		.word	0
+		.word	0
 		.size	arm720_processor_functions, . - arm720_processor_functions
 
 		.section ".rodata"
diff --git a/arch/arm/mm/proc-arm740.S b/arch/arm/mm/proc-arm740.S
index 38b27dc..6f9d12e 100644
--- a/arch/arm/mm/proc-arm740.S
+++ b/arch/arm/mm/proc-arm740.S
@@ -130,6 +130,9 @@
 	.word	cpu_arm740_dcache_clean_area
 	.word	cpu_arm740_switch_mm
 	.word	0			@ cpu_*_set_pte
+	.word	0
+	.word	0
+	.word	0
 	.size	arm740_processor_functions, . - arm740_processor_functions
 
 	.section ".rodata"
diff --git a/arch/arm/mm/proc-arm7tdmi.S b/arch/arm/mm/proc-arm7tdmi.S
index 0c9786d..e4c165c 100644
--- a/arch/arm/mm/proc-arm7tdmi.S
+++ b/arch/arm/mm/proc-arm7tdmi.S
@@ -70,6 +70,9 @@
 		.word	cpu_arm7tdmi_dcache_clean_area
 		.word	cpu_arm7tdmi_switch_mm
 		.word	0		@ cpu_*_set_pte
+		.word	0
+		.word	0
+		.word	0
 		.size	arm7tdmi_processor_functions, . - arm7tdmi_processor_functions
 
 		.section ".rodata"
diff --git a/arch/arm/mm/proc-arm920.S b/arch/arm/mm/proc-arm920.S
index 6109f27..219980e 100644
--- a/arch/arm/mm/proc-arm920.S
+++ b/arch/arm/mm/proc-arm920.S
@@ -387,6 +387,40 @@
 #endif
 	mov	pc, lr
 
+/* Suspend/resume support: taken from arch/arm/plat-s3c24xx/sleep.S */
+.globl	cpu_arm920_suspend_size
+.equ	cpu_arm920_suspend_size, 4 * 3
+#ifdef CONFIG_PM
+ENTRY(cpu_arm920_do_suspend)
+	stmfd	sp!, {r4 - r7, lr}
+	mrc	p15, 0, r4, c13, c0, 0	@ PID
+	mrc	p15, 0, r5, c3, c0, 0	@ Domain ID
+	mrc	p15, 0, r6, c2, c0, 0	@ TTB address
+	mrc	p15, 0, r7, c1, c0, 0	@ Control register
+	stmia	r0, {r4 - r7}
+	ldmfd	sp!, {r4 - r7, pc}
+ENDPROC(cpu_arm920_do_suspend)
+
+ENTRY(cpu_arm920_do_resume)
+	mov	ip, #0
+	mcr	p15, 0, ip, c8, c7, 0	@ invalidate I+D TLBs
+	mcr	p15, 0, ip, c7, c7, 0	@ invalidate I+D caches
+	ldmia	r0, {r4 - r7}
+	mcr	p15, 0, r4, c13, c0, 0	@ PID
+	mcr	p15, 0, r5, c3, c0, 0	@ Domain ID
+	mcr	p15, 0, r6, c2, c0, 0	@ TTB address
+	mov	r0, r7			@ control register
+	mov	r2, r6, lsr #14		@ get TTB0 base
+	mov	r2, r2, lsl #14
+	ldr	r3, =PMD_TYPE_SECT | PMD_SECT_BUFFERABLE | \
+		     PMD_SECT_CACHEABLE | PMD_BIT4 | PMD_SECT_AP_WRITE
+	b	cpu_resume_mmu
+ENDPROC(cpu_arm920_do_resume)
+#else
+#define cpu_arm920_do_suspend	0
+#define cpu_arm920_do_resume	0
+#endif
+
 	__CPUINIT
 
 	.type	__arm920_setup, #function
@@ -432,6 +466,9 @@
 	.word	cpu_arm920_dcache_clean_area
 	.word	cpu_arm920_switch_mm
 	.word	cpu_arm920_set_pte_ext
+	.word	cpu_arm920_suspend_size
+	.word	cpu_arm920_do_suspend
+	.word	cpu_arm920_do_resume
 	.size	arm920_processor_functions, . - arm920_processor_functions
 
 	.section ".rodata"
diff --git a/arch/arm/mm/proc-arm922.S b/arch/arm/mm/proc-arm922.S
index bb2f0f4..36154b1 100644
--- a/arch/arm/mm/proc-arm922.S
+++ b/arch/arm/mm/proc-arm922.S
@@ -436,6 +436,9 @@
 	.word	cpu_arm922_dcache_clean_area
 	.word	cpu_arm922_switch_mm
 	.word	cpu_arm922_set_pte_ext
+	.word	0
+	.word	0
+	.word	0
 	.size	arm922_processor_functions, . - arm922_processor_functions
 
 	.section ".rodata"
diff --git a/arch/arm/mm/proc-arm925.S b/arch/arm/mm/proc-arm925.S
index c13e01a..89c5e000 100644
--- a/arch/arm/mm/proc-arm925.S
+++ b/arch/arm/mm/proc-arm925.S
@@ -503,6 +503,9 @@
 	.word	cpu_arm925_dcache_clean_area
 	.word	cpu_arm925_switch_mm
 	.word	cpu_arm925_set_pte_ext
+	.word	0
+	.word	0
+	.word	0
 	.size	arm925_processor_functions, . - arm925_processor_functions
 
 	.section ".rodata"
diff --git a/arch/arm/mm/proc-arm926.S b/arch/arm/mm/proc-arm926.S
index 42eb431..6a4bdb2 100644
--- a/arch/arm/mm/proc-arm926.S
+++ b/arch/arm/mm/proc-arm926.S
@@ -401,6 +401,40 @@
 #endif
 	mov	pc, lr
 
+/* Suspend/resume support: taken from arch/arm/plat-s3c24xx/sleep.S */
+.globl	cpu_arm926_suspend_size
+.equ	cpu_arm926_suspend_size, 4 * 3
+#ifdef CONFIG_PM
+ENTRY(cpu_arm926_do_suspend)
+	stmfd	sp!, {r4 - r7, lr}
+	mrc	p15, 0, r4, c13, c0, 0	@ PID
+	mrc	p15, 0, r5, c3, c0, 0	@ Domain ID
+	mrc	p15, 0, r6, c2, c0, 0	@ TTB address
+	mrc	p15, 0, r7, c1, c0, 0	@ Control register
+	stmia	r0, {r4 - r7}
+	ldmfd	sp!, {r4 - r7, pc}
+ENDPROC(cpu_arm926_do_suspend)
+
+ENTRY(cpu_arm926_do_resume)
+	mov	ip, #0
+	mcr	p15, 0, ip, c8, c7, 0	@ invalidate I+D TLBs
+	mcr	p15, 0, ip, c7, c7, 0	@ invalidate I+D caches
+	ldmia	r0, {r4 - r7}
+	mcr	p15, 0, r4, c13, c0, 0	@ PID
+	mcr	p15, 0, r5, c3, c0, 0	@ Domain ID
+	mcr	p15, 0, r6, c2, c0, 0	@ TTB address
+	mov	r0, r7			@ control register
+	mov	r2, r6, lsr #14		@ get TTB0 base
+	mov	r2, r2, lsl #14
+	ldr	r3, =PMD_TYPE_SECT | PMD_SECT_BUFFERABLE | \
+		     PMD_SECT_CACHEABLE | PMD_BIT4 | PMD_SECT_AP_WRITE
+	b	cpu_resume_mmu
+ENDPROC(cpu_arm926_do_resume)
+#else
+#define cpu_arm926_do_suspend	0
+#define cpu_arm926_do_resume	0
+#endif
+
 	__CPUINIT
 
 	.type	__arm926_setup, #function
@@ -456,6 +490,9 @@
 	.word	cpu_arm926_dcache_clean_area
 	.word	cpu_arm926_switch_mm
 	.word	cpu_arm926_set_pte_ext
+	.word	cpu_arm926_suspend_size
+	.word	cpu_arm926_do_suspend
+	.word	cpu_arm926_do_resume
 	.size	arm926_processor_functions, . - arm926_processor_functions
 
 	.section ".rodata"
diff --git a/arch/arm/mm/proc-arm940.S b/arch/arm/mm/proc-arm940.S
index 7b11cdb..26aea3f 100644
--- a/arch/arm/mm/proc-arm940.S
+++ b/arch/arm/mm/proc-arm940.S
@@ -363,6 +363,9 @@
 	.word	cpu_arm940_dcache_clean_area
 	.word	cpu_arm940_switch_mm
 	.word	0		@ cpu_*_set_pte
+	.word	0
+	.word	0
+	.word	0
 	.size	arm940_processor_functions, . - arm940_processor_functions
 
 	.section ".rodata"
diff --git a/arch/arm/mm/proc-arm946.S b/arch/arm/mm/proc-arm946.S
index 1a5bbf08..8063345 100644
--- a/arch/arm/mm/proc-arm946.S
+++ b/arch/arm/mm/proc-arm946.S
@@ -419,6 +419,9 @@
 	.word	cpu_arm946_dcache_clean_area
 	.word	cpu_arm946_switch_mm
 	.word	0		@ cpu_*_set_pte
+	.word	0
+	.word	0
+	.word	0
 	.size	arm946_processor_functions, . - arm946_processor_functions
 
 	.section ".rodata"
diff --git a/arch/arm/mm/proc-arm9tdmi.S b/arch/arm/mm/proc-arm9tdmi.S
index db67e31..7b7ebd4 100644
--- a/arch/arm/mm/proc-arm9tdmi.S
+++ b/arch/arm/mm/proc-arm9tdmi.S
@@ -70,6 +70,9 @@
 		.word	cpu_arm9tdmi_dcache_clean_area
 		.word	cpu_arm9tdmi_switch_mm
 		.word	0		@ cpu_*_set_pte
+		.word	0
+		.word	0
+		.word	0
 		.size	arm9tdmi_processor_functions, . - arm9tdmi_processor_functions
 
 		.section ".rodata"
diff --git a/arch/arm/mm/proc-fa526.S b/arch/arm/mm/proc-fa526.S
index 7c9ad62..fc2a4ae 100644
--- a/arch/arm/mm/proc-fa526.S
+++ b/arch/arm/mm/proc-fa526.S
@@ -195,6 +195,9 @@
 	.word	cpu_fa526_dcache_clean_area
 	.word	cpu_fa526_switch_mm
 	.word	cpu_fa526_set_pte_ext
+	.word	0
+	.word	0
+	.word	0
 	.size	fa526_processor_functions, . - fa526_processor_functions
 
 	.section ".rodata"
diff --git a/arch/arm/mm/proc-feroceon.S b/arch/arm/mm/proc-feroceon.S
index b4597ed..d3883ee 100644
--- a/arch/arm/mm/proc-feroceon.S
+++ b/arch/arm/mm/proc-feroceon.S
@@ -554,6 +554,9 @@
 	.word	cpu_feroceon_dcache_clean_area
 	.word	cpu_feroceon_switch_mm
 	.word	cpu_feroceon_set_pte_ext
+	.word	0
+	.word	0
+	.word	0
 	.size	feroceon_processor_functions, . - feroceon_processor_functions
 
 	.section ".rodata"
diff --git a/arch/arm/mm/proc-mohawk.S b/arch/arm/mm/proc-mohawk.S
index 4458ee6..9d4f2ae 100644
--- a/arch/arm/mm/proc-mohawk.S
+++ b/arch/arm/mm/proc-mohawk.S
@@ -388,6 +388,9 @@
 	.word	cpu_mohawk_dcache_clean_area
 	.word	cpu_mohawk_switch_mm
 	.word	cpu_mohawk_set_pte_ext
+	.word	0
+	.word	0
+	.word	0
 	.size	mohawk_processor_functions, . - mohawk_processor_functions
 
 	.section ".rodata"
diff --git a/arch/arm/mm/proc-sa110.S b/arch/arm/mm/proc-sa110.S
index 5aa8d59..46f09ed 100644
--- a/arch/arm/mm/proc-sa110.S
+++ b/arch/arm/mm/proc-sa110.S
@@ -203,6 +203,9 @@
 	.word	cpu_sa110_dcache_clean_area
 	.word	cpu_sa110_switch_mm
 	.word	cpu_sa110_set_pte_ext
+	.word	0
+	.word	0
+	.word	0
 	.size	sa110_processor_functions, . - sa110_processor_functions
 
 	.section ".rodata"
diff --git a/arch/arm/mm/proc-sa1100.S b/arch/arm/mm/proc-sa1100.S
index 2ac4e6f..74483d1 100644
--- a/arch/arm/mm/proc-sa1100.S
+++ b/arch/arm/mm/proc-sa1100.S
@@ -169,6 +169,42 @@
 #endif
 	mov	pc, lr
 
+.globl	cpu_sa1100_suspend_size
+.equ	cpu_sa1100_suspend_size, 4*4
+#ifdef CONFIG_PM
+ENTRY(cpu_sa1100_do_suspend)
+	stmfd	sp!, {r4 - r7, lr}
+	mrc	p15, 0, r4, c3, c0, 0		@ domain ID
+	mrc	p15, 0, r5, c2, c0, 0		@ translation table base addr
+	mrc	p15, 0, r6, c13, c0, 0		@ PID
+	mrc	p15, 0, r7, c1, c0, 0		@ control reg
+	stmia	r0, {r4 - r7}			@ store cp regs
+	ldmfd	sp!, {r4 - r7, pc}
+ENDPROC(cpu_sa1100_do_suspend)
+
+ENTRY(cpu_sa1100_do_resume)
+	ldmia	r0, {r4 - r7}			@ load cp regs
+	mov	r1, #0
+	mcr	p15, 0, r1, c8, c7, 0		@ flush I+D TLBs
+	mcr	p15, 0, r1, c7, c7, 0		@ flush I&D cache
+	mcr	p15, 0, r1, c9, c0, 0		@ invalidate RB
+	mcr	p15, 0, r1, c9, c0, 5		@ allow user space to use RB
+
+	mcr	p15, 0, r4, c3, c0, 0		@ domain ID
+	mcr	p15, 0, r5, c2, c0, 0		@ translation table base addr
+	mcr	p15, 0, r6, c13, c0, 0		@ PID
+	mov	r0, r7				@ control register
+	mov	r2, r5, lsr #14			@ get TTB0 base
+	mov	r2, r2, lsl #14
+	ldr	r3, =PMD_TYPE_SECT | PMD_SECT_BUFFERABLE | \
+		     PMD_SECT_CACHEABLE | PMD_SECT_AP_WRITE
+	b	cpu_resume_mmu
+ENDPROC(cpu_sa1100_do_resume)
+#else
+#define cpu_sa1100_do_suspend	0
+#define cpu_sa1100_do_resume	0
+#endif
+
 	__CPUINIT
 
 	.type	__sa1100_setup, #function
@@ -218,6 +254,9 @@
 	.word	cpu_sa1100_dcache_clean_area
 	.word	cpu_sa1100_switch_mm
 	.word	cpu_sa1100_set_pte_ext
+	.word	cpu_sa1100_suspend_size
+	.word	cpu_sa1100_do_suspend
+	.word	cpu_sa1100_do_resume
 	.size	sa1100_processor_functions, . - sa1100_processor_functions
 
 	.section ".rodata"
diff --git a/arch/arm/mm/proc-v6.S b/arch/arm/mm/proc-v6.S
index 59a7e1f..832b6bd 100644
--- a/arch/arm/mm/proc-v6.S
+++ b/arch/arm/mm/proc-v6.S
@@ -121,6 +121,53 @@
 #endif
 	mov	pc, lr
 
+/* Suspend/resume support: taken from arch/arm/mach-s3c64xx/sleep.S */
+.globl	cpu_v6_suspend_size
+.equ	cpu_v6_suspend_size, 4 * 8
+#ifdef CONFIG_PM
+ENTRY(cpu_v6_do_suspend)
+	stmfd	sp!, {r4 - r11, lr}
+	mrc	p15, 0, r4, c13, c0, 0	@ FCSE/PID
+	mrc	p15, 0, r5, c13, c0, 1	@ Context ID
+	mrc	p15, 0, r6, c3, c0, 0	@ Domain ID
+	mrc	p15, 0, r7, c2, c0, 0	@ Translation table base 0
+	mrc	p15, 0, r8, c2, c0, 1	@ Translation table base 1
+	mrc	p15, 0, r9, c1, c0, 1	@ auxillary control register
+	mrc	p15, 0, r10, c1, c0, 2	@ co-processor access control
+	mrc	p15, 0, r11, c1, c0, 0	@ control register
+	stmia	r0, {r4 - r11}
+	ldmfd	sp!, {r4- r11, pc}
+ENDPROC(cpu_v6_do_suspend)
+
+ENTRY(cpu_v6_do_resume)
+	mov	ip, #0
+	mcr	p15, 0, ip, c7, c14, 0	@ clean+invalidate D cache
+	mcr	p15, 0, ip, c7, c5, 0	@ invalidate I cache
+	mcr	p15, 0, ip, c7, c15, 0	@ clean+invalidate cache
+	mcr	p15, 0, ip, c7, c10, 4	@ drain write buffer
+	ldmia	r0, {r4 - r11}
+	mcr	p15, 0, r4, c13, c0, 0	@ FCSE/PID
+	mcr	p15, 0, r5, c13, c0, 1	@ Context ID
+	mcr	p15, 0, r6, c3, c0, 0	@ Domain ID
+	mcr	p15, 0, r7, c2, c0, 0	@ Translation table base 0
+	mcr	p15, 0, r8, c2, c0, 1	@ Translation table base 1
+	mcr	p15, 0, r9, c1, c0, 1	@ auxillary control register
+	mcr	p15, 0, r10, c1, c0, 2	@ co-processor access control
+	mcr	p15, 0, ip, c2, c0, 2	@ TTB control register
+	mcr	p15, 0, ip, c7, c5, 4	@ ISB
+	mov	r0, r11			@ control register
+	mov	r2, r7, lsr #14		@ get TTB0 base
+	mov	r2, r2, lsl #14
+	ldr	r3, cpu_resume_l1_flags
+	b	cpu_resume_mmu
+ENDPROC(cpu_v6_do_resume)
+cpu_resume_l1_flags:
+	ALT_SMP(.long PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_FLAGS_SMP)
+	ALT_UP(.long  PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_FLAGS_UP)
+#else
+#define cpu_v6_do_suspend 0
+#define cpu_v6_do_resume 0
+#endif
 
 
 	.type	cpu_v6_name, #object
@@ -206,6 +253,9 @@
 	.word	cpu_v6_dcache_clean_area
 	.word	cpu_v6_switch_mm
 	.word	cpu_v6_set_pte_ext
+	.word	cpu_v6_suspend_size
+	.word	cpu_v6_do_suspend
+	.word	cpu_v6_do_resume
 	.size	v6_processor_functions, . - v6_processor_functions
 
 	.section ".rodata"
diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S
index 8e33562..262fa88 100644
--- a/arch/arm/mm/proc-v7.S
+++ b/arch/arm/mm/proc-v7.S
@@ -108,10 +108,16 @@
 #ifdef CONFIG_ARM_ERRATA_430973
 	mcr	p15, 0, r2, c7, c5, 6		@ flush BTAC/BTB
 #endif
+#ifdef CONFIG_ARM_ERRATA_754322
+	dsb
+#endif
 	mcr	p15, 0, r2, c13, c0, 1		@ set reserved context ID
 	isb
 1:	mcr	p15, 0, r0, c2, c0, 0		@ set TTB 0
 	isb
+#ifdef CONFIG_ARM_ERRATA_754322
+	dsb
+#endif
 	mcr	p15, 0, r1, c13, c0, 1		@ set context ID
 	isb
 #endif
@@ -171,6 +177,87 @@
 	.ascii	"ARMv7 Processor"
 	.align
 
+	/*
+	 * Memory region attributes with SCTLR.TRE=1
+	 *
+	 *   n = TEX[0],C,B
+	 *   TR = PRRR[2n+1:2n]		- memory type
+	 *   IR = NMRR[2n+1:2n]		- inner cacheable property
+	 *   OR = NMRR[2n+17:2n+16]	- outer cacheable property
+	 *
+	 *			n	TR	IR	OR
+	 *   UNCACHED		000	00
+	 *   BUFFERABLE		001	10	00	00
+	 *   WRITETHROUGH	010	10	10	10
+	 *   WRITEBACK		011	10	11	11
+	 *   reserved		110
+	 *   WRITEALLOC		111	10	01	01
+	 *   DEV_SHARED		100	01
+	 *   DEV_NONSHARED	100	01
+	 *   DEV_WC		001	10
+	 *   DEV_CACHED		011	10
+	 *
+	 * Other attributes:
+	 *
+	 *   DS0 = PRRR[16] = 0		- device shareable property
+	 *   DS1 = PRRR[17] = 1		- device shareable property
+	 *   NS0 = PRRR[18] = 0		- normal shareable property
+	 *   NS1 = PRRR[19] = 1		- normal shareable property
+	 *   NOS = PRRR[24+n] = 1	- not outer shareable
+	 */
+.equ	PRRR,	0xff0a81a8
+.equ	NMRR,	0x40e040e0
+
+/* Suspend/resume support: derived from arch/arm/mach-s5pv210/sleep.S */
+.globl	cpu_v7_suspend_size
+.equ	cpu_v7_suspend_size, 4 * 8
+#ifdef CONFIG_PM
+ENTRY(cpu_v7_do_suspend)
+	stmfd	sp!, {r4 - r11, lr}
+	mrc	p15, 0, r4, c13, c0, 0	@ FCSE/PID
+	mrc	p15, 0, r5, c13, c0, 1	@ Context ID
+	mrc	p15, 0, r6, c3, c0, 0	@ Domain ID
+	mrc	p15, 0, r7, c2, c0, 0	@ TTB 0
+	mrc	p15, 0, r8, c2, c0, 1	@ TTB 1
+	mrc	p15, 0, r9, c1, c0, 0	@ Control register
+	mrc	p15, 0, r10, c1, c0, 1	@ Auxiliary control register
+	mrc	p15, 0, r11, c1, c0, 2	@ Co-processor access control
+	stmia	r0, {r4 - r11}
+	ldmfd	sp!, {r4 - r11, pc}
+ENDPROC(cpu_v7_do_suspend)
+
+ENTRY(cpu_v7_do_resume)
+	mov	ip, #0
+	mcr	p15, 0, ip, c8, c7, 0	@ invalidate TLBs
+	mcr	p15, 0, ip, c7, c5, 0	@ invalidate I cache
+	ldmia	r0, {r4 - r11}
+	mcr	p15, 0, r4, c13, c0, 0	@ FCSE/PID
+	mcr	p15, 0, r5, c13, c0, 1	@ Context ID
+	mcr	p15, 0, r6, c3, c0, 0	@ Domain ID
+	mcr	p15, 0, r7, c2, c0, 0	@ TTB 0
+	mcr	p15, 0, r8, c2, c0, 1	@ TTB 1
+	mcr	p15, 0, ip, c2, c0, 2	@ TTB control register
+	mcr	p15, 0, r10, c1, c0, 1	@ Auxillary control register
+	mcr	p15, 0, r11, c1, c0, 2	@ Co-processor access control
+	ldr	r4, =PRRR		@ PRRR
+	ldr	r5, =NMRR		@ NMRR
+	mcr	p15, 0, r4, c10, c2, 0	@ write PRRR
+	mcr	p15, 0, r5, c10, c2, 1	@ write NMRR
+	isb
+	mov	r0, r9			@ control register
+	mov	r2, r7, lsr #14		@ get TTB0 base
+	mov	r2, r2, lsl #14
+	ldr	r3, cpu_resume_l1_flags
+	b	cpu_resume_mmu
+ENDPROC(cpu_v7_do_resume)
+cpu_resume_l1_flags:
+	ALT_SMP(.long PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_FLAGS_SMP)
+	ALT_UP(.long  PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_FLAGS_UP)
+#else
+#define cpu_v7_do_suspend	0
+#define cpu_v7_do_resume	0
+#endif
+
 	__CPUINIT
 
 /*
@@ -282,36 +369,8 @@
 	ALT_SMP(orr	r4, r4, #TTB_FLAGS_SMP)
 	ALT_UP(orr	r4, r4, #TTB_FLAGS_UP)
 	mcr	p15, 0, r4, c2, c0, 1		@ load TTB1
-	/*
-	 * Memory region attributes with SCTLR.TRE=1
-	 *
-	 *   n = TEX[0],C,B
-	 *   TR = PRRR[2n+1:2n]		- memory type
-	 *   IR = NMRR[2n+1:2n]		- inner cacheable property
-	 *   OR = NMRR[2n+17:2n+16]	- outer cacheable property
-	 *
-	 *			n	TR	IR	OR
-	 *   UNCACHED		000	00
-	 *   BUFFERABLE		001	10	00	00
-	 *   WRITETHROUGH	010	10	10	10
-	 *   WRITEBACK		011	10	11	11
-	 *   reserved		110
-	 *   WRITEALLOC		111	10	01	01
-	 *   DEV_SHARED		100	01
-	 *   DEV_NONSHARED	100	01
-	 *   DEV_WC		001	10
-	 *   DEV_CACHED		011	10
-	 *
-	 * Other attributes:
-	 *
-	 *   DS0 = PRRR[16] = 0		- device shareable property
-	 *   DS1 = PRRR[17] = 1		- device shareable property
-	 *   NS0 = PRRR[18] = 0		- normal shareable property
-	 *   NS1 = PRRR[19] = 1		- normal shareable property
-	 *   NOS = PRRR[24+n] = 1	- not outer shareable
-	 */
-	ldr	r5, =0xff0a81a8			@ PRRR
-	ldr	r6, =0x40e040e0			@ NMRR
+	ldr	r5, =PRRR			@ PRRR
+	ldr	r6, =NMRR			@ NMRR
 	mcr	p15, 0, r5, c10, c2, 0		@ write PRRR
 	mcr	p15, 0, r6, c10, c2, 1		@ write NMRR
 #endif
@@ -357,6 +416,9 @@
 	.word	cpu_v7_dcache_clean_area
 	.word	cpu_v7_switch_mm
 	.word	cpu_v7_set_pte_ext
+	.word	0
+	.word	0
+	.word	0
 	.size	v7_processor_functions, . - v7_processor_functions
 
 	.section ".rodata"
diff --git a/arch/arm/mm/proc-xsc3.S b/arch/arm/mm/proc-xsc3.S
index ec26355..63d8b20 100644
--- a/arch/arm/mm/proc-xsc3.S
+++ b/arch/arm/mm/proc-xsc3.S
@@ -413,9 +413,52 @@
 	mov	pc, lr
 
 	.ltorg
-
 	.align
 
+.globl	cpu_xsc3_suspend_size
+.equ	cpu_xsc3_suspend_size, 4 * 8
+#ifdef CONFIG_PM
+ENTRY(cpu_xsc3_do_suspend)
+	stmfd	sp!, {r4 - r10, lr}
+	mrc	p14, 0, r4, c6, c0, 0	@ clock configuration, for turbo mode
+	mrc	p15, 0, r5, c15, c1, 0	@ CP access reg
+	mrc	p15, 0, r6, c13, c0, 0	@ PID
+	mrc 	p15, 0, r7, c3, c0, 0	@ domain ID
+	mrc 	p15, 0, r8, c2, c0, 0	@ translation table base addr
+	mrc	p15, 0, r9, c1, c0, 1	@ auxiliary control reg
+	mrc 	p15, 0, r10, c1, c0, 0	@ control reg
+	bic	r4, r4, #2		@ clear frequency change bit
+	stmia	r0, {r1, r4 - r10}	@ store v:p offset + cp regs
+	ldmia	sp!, {r4 - r10, pc}
+ENDPROC(cpu_xsc3_do_suspend)
+
+ENTRY(cpu_xsc3_do_resume)
+	ldmia	r0, {r1, r4 - r10}	@ load v:p offset + cp regs
+	mov	ip, #0
+	mcr	p15, 0, ip, c7, c7, 0	@ invalidate I & D caches, BTB
+	mcr	p15, 0, ip, c7, c10, 4	@ drain write (&fill) buffer
+	mcr	p15, 0, ip, c7, c5, 4	@ flush prefetch buffer
+	mcr	p15, 0, ip, c8, c7, 0	@ invalidate I & D TLBs
+	mcr	p14, 0, r4, c6, c0, 0	@ clock configuration, turbo mode.
+	mcr	p15, 0, r5, c15, c1, 0	@ CP access reg
+	mcr	p15, 0, r6, c13, c0, 0	@ PID
+	mcr	p15, 0, r7, c3, c0, 0	@ domain ID
+	mcr	p15, 0, r8, c2, c0, 0	@ translation table base addr
+	mcr	p15, 0, r9, c1, c0, 1	@ auxiliary control reg
+
+	@ temporarily map resume_turn_on_mmu into the page table,
+	@ otherwise prefetch abort occurs after MMU is turned on
+	mov	r0, r10			@ control register
+	mov	r2, r8, lsr #14		@ get TTB0 base
+	mov	r2, r2, lsl #14
+	ldr	r3, =0x542e		@ section flags
+	b	cpu_resume_mmu
+ENDPROC(cpu_xsc3_do_resume)
+#else
+#define cpu_xsc3_do_suspend	0
+#define cpu_xsc3_do_resume	0
+#endif
+
 	__CPUINIT
 
 	.type	__xsc3_setup, #function
@@ -476,6 +519,9 @@
 	.word	cpu_xsc3_dcache_clean_area
 	.word	cpu_xsc3_switch_mm
 	.word	cpu_xsc3_set_pte_ext
+	.word	cpu_xsc3_suspend_size
+	.word	cpu_xsc3_do_suspend
+	.word	cpu_xsc3_do_resume
 	.size	xsc3_processor_functions, . - xsc3_processor_functions
 
 	.section ".rodata"
diff --git a/arch/arm/mm/proc-xscale.S b/arch/arm/mm/proc-xscale.S
index 5a37c5e..086038c 100644
--- a/arch/arm/mm/proc-xscale.S
+++ b/arch/arm/mm/proc-xscale.S
@@ -513,11 +513,49 @@
 	xscale_set_pte_ext_epilogue
 	mov	pc, lr
 
-
 	.ltorg
-
 	.align
 
+.globl	cpu_xscale_suspend_size
+.equ	cpu_xscale_suspend_size, 4 * 7
+#ifdef CONFIG_PM
+ENTRY(cpu_xscale_do_suspend)
+	stmfd	sp!, {r4 - r10, lr}
+	mrc	p14, 0, r4, c6, c0, 0	@ clock configuration, for turbo mode
+	mrc	p15, 0, r5, c15, c1, 0	@ CP access reg
+	mrc	p15, 0, r6, c13, c0, 0	@ PID
+	mrc	p15, 0, r7, c3, c0, 0	@ domain ID
+	mrc	p15, 0, r8, c2, c0, 0	@ translation table base addr
+	mrc	p15, 0, r9, c1, c1, 0	@ auxiliary control reg
+	mrc	p15, 0, r10, c1, c0, 0	@ control reg
+	bic	r4, r4, #2		@ clear frequency change bit
+	stmia	r0, {r4 - r10}		@ store cp regs
+	ldmfd	sp!, {r4 - r10, pc}
+ENDPROC(cpu_xscale_do_suspend)
+
+ENTRY(cpu_xscale_do_resume)
+	ldmia	r0, {r4 - r10}		@ load cp regs
+	mov	ip, #0
+	mcr	p15, 0, ip, c8, c7, 0	@ invalidate I & D TLBs
+	mcr	p15, 0, ip, c7, c7, 0	@ invalidate I & D caches, BTB
+	mcr	p14, 0, r4, c6, c0, 0	@ clock configuration, turbo mode.
+	mcr	p15, 0, r5, c15, c1, 0	@ CP access reg
+	mcr	p15, 0, r6, c13, c0, 0	@ PID
+	mcr	p15, 0, r7, c3, c0, 0	@ domain ID
+	mcr	p15, 0, r8, c2, c0, 0	@ translation table base addr
+	mcr	p15, 0, r9, c1, c1, 0	@ auxiliary control reg
+	mov	r0, r10			@ control register
+	mov	r2, r8, lsr #14		@ get TTB0 base
+	mov	r2, r2, lsl #14
+	ldr	r3, =PMD_TYPE_SECT | PMD_SECT_BUFFERABLE | \
+		     PMD_SECT_CACHEABLE | PMD_SECT_AP_WRITE
+	b	cpu_resume_mmu
+ENDPROC(cpu_xscale_do_resume)
+#else
+#define cpu_xscale_do_suspend	0
+#define cpu_xscale_do_resume	0
+#endif
+
 	__CPUINIT
 
 	.type	__xscale_setup, #function
@@ -565,6 +603,9 @@
 	.word	cpu_xscale_dcache_clean_area
 	.word	cpu_xscale_switch_mm
 	.word	cpu_xscale_set_pte_ext
+	.word	cpu_xscale_suspend_size
+	.word	cpu_xscale_do_suspend
+	.word	cpu_xscale_do_resume
 	.size	xscale_processor_functions, . - xscale_processor_functions
 
 	.section ".rodata"
diff --git a/arch/arm/plat-omap/include/plat/sram.h b/arch/arm/plat-omap/include/plat/sram.h
index 9967d5e..f500fc3 100644
--- a/arch/arm/plat-omap/include/plat/sram.h
+++ b/arch/arm/plat-omap/include/plat/sram.h
@@ -12,7 +12,19 @@
 #define __ARCH_ARM_OMAP_SRAM_H
 
 #ifndef __ASSEMBLY__
-extern void * omap_sram_push(void * start, unsigned long size);
+#include <asm/fncpy.h>
+
+extern void *omap_sram_push_address(unsigned long size);
+
+/* Macro to push a function to the internal SRAM, using the fncpy API */
+#define omap_sram_push(funcp, size) ({				\
+	typeof(&(funcp)) _res = NULL;				\
+	void *_sram_address = omap_sram_push_address(size);	\
+	if (_sram_address)					\
+		_res = fncpy(_sram_address, &(funcp), size);	\
+	_res;							\
+})
+
 extern void omap_sram_reprogram_clock(u32 dpllctl, u32 ckctl);
 
 extern void omap2_sram_ddr_init(u32 *slow_dll_ctrl, u32 fast_dll_ctrl,
diff --git a/arch/arm/plat-omap/sram.c b/arch/arm/plat-omap/sram.c
index e26e504..68fcc7d 100644
--- a/arch/arm/plat-omap/sram.c
+++ b/arch/arm/plat-omap/sram.c
@@ -242,7 +242,14 @@
 	       omap_sram_size - SRAM_BOOTLOADER_SZ);
 }
 
-void * omap_sram_push(void * start, unsigned long size)
+/*
+ * Memory allocator for SRAM: calculates the new ceiling address
+ * for pushing a function using the fncpy API.
+ *
+ * Note that fncpy requires the returned address to be aligned
+ * to an 8-byte boundary.
+ */
+void *omap_sram_push_address(unsigned long size)
 {
 	if (size > (omap_sram_ceil - (omap_sram_base + SRAM_BOOTLOADER_SZ))) {
 		printk(KERN_ERR "Not enough space in SRAM\n");
@@ -250,10 +257,7 @@
 	}
 
 	omap_sram_ceil -= size;
-	omap_sram_ceil = ROUND_DOWN(omap_sram_ceil, sizeof(void *));
-	memcpy((void *)omap_sram_ceil, start, size);
-	flush_icache_range((unsigned long)omap_sram_ceil,
-		(unsigned long)(omap_sram_ceil + size));
+	omap_sram_ceil = ROUND_DOWN(omap_sram_ceil, FNCPY_ALIGN);
 
 	return (void *)omap_sram_ceil;
 }
diff --git a/arch/arm/plat-s3c24xx/sleep.S b/arch/arm/plat-s3c24xx/sleep.S
index e73e3b6e..fd7032f 100644
--- a/arch/arm/plat-s3c24xx/sleep.S
+++ b/arch/arm/plat-s3c24xx/sleep.S
@@ -44,23 +44,13 @@
 	/* s3c_cpu_save
 	 *
 	 * entry:
-	 *	r0 = save address (virtual addr of s3c_sleep_save_phys)
+	 *	r1 = v:p offset
 	*/
 
 ENTRY(s3c_cpu_save)
 	stmfd	sp!, { r4 - r12, lr }
-
-	@@ store co-processor registers
-
-	mrc	p15, 0, r4, c13, c0, 0	@ PID
-	mrc	p15, 0, r5, c3, c0, 0	@ Domain ID
-	mrc	p15, 0, r6, c2, c0, 0	@ translation table base address
-	mrc	p15, 0, r7, c1, c0, 0	@ control register
-
-	stmia	r0, { r4 - r13 }
-
-	@@ write our state back to RAM
-	bl	s3c_pm_cb_flushcache
+	ldr	r3, =resume_with_mmu
+	bl	cpu_suspend
 
 	@@ jump to final code to send system to sleep
 	ldr	r0, =pm_cpu_sleep
@@ -76,20 +66,6 @@
 
 	.ltorg
 
-	@@ the next bits sit in the .data segment, even though they
-	@@ happen to be code... the s3c_sleep_save_phys needs to be
-	@@ accessed by the resume code before it can restore the MMU.
-	@@ This means that the variable has to be close enough for the
-	@@ code to read it... since the .text segment needs to be RO,
-	@@ the data segment can be the only place to put this code.
-
-	.data
-
-	.global	s3c_sleep_save_phys
-s3c_sleep_save_phys:
-	.word	0
-
-
 	/* sleep magic, to allow the bootloader to check for an valid
 	 * image to resume to. Must be the first word before the
 	 * s3c_cpu_resume entry.
@@ -100,10 +76,6 @@
 	/* s3c_cpu_resume
 	 *
 	 * resume code entry for bootloader to call
-	 *
-	 * we must put this code here in the data segment as we have no
-	 * other way of restoring the stack pointer after sleep, and we
-	 * must not write to the code segment (code is read-only)
 	*/
 
 ENTRY(s3c_cpu_resume)
@@ -134,25 +106,4 @@
 	beq	1001b
 #endif /* CONFIG_DEBUG_RESUME */
 
-	mov	r1, #0
-	mcr	p15, 0, r1, c8, c7, 0		@@ invalidate I & D TLBs
-	mcr	p15, 0, r1, c7, c7, 0		@@ invalidate I & D caches
-
-	ldr	r0, s3c_sleep_save_phys		@ address of restore block
-	ldmia	r0, { r4 - r13 }
-
-	mcr	p15, 0, r4, c13, c0, 0		@ PID
-	mcr	p15, 0, r5, c3, c0, 0		@ Domain ID
-	mcr	p15, 0, r6, c2, c0, 0		@ translation table base
-
-#ifdef CONFIG_DEBUG_RESUME
-	mov	r3, #'R'
-	strb	r3, [ r2, #S3C2410_UTXH ]
-#endif
-
-	ldr	r2, =resume_with_mmu
-	mcr	p15, 0, r7, c1, c0, 0		@ turn on MMU, etc
-	nop					@ second-to-last before mmu
-	mov	pc, r2				@ go back to virtual address
-
-	.ltorg
+	b	cpu_resume
diff --git a/arch/arm/plat-samsung/include/plat/pm.h b/arch/arm/plat-samsung/include/plat/pm.h
index 30518cc..937cc2a 100644
--- a/arch/arm/plat-samsung/include/plat/pm.h
+++ b/arch/arm/plat-samsung/include/plat/pm.h
@@ -52,13 +52,11 @@
 
 /* from sleep.S */
 
-extern int  s3c_cpu_save(unsigned long *saveblk);
+extern int  s3c_cpu_save(unsigned long *saveblk, long);
 extern void s3c_cpu_resume(void);
 
 extern void s3c2410_cpu_suspend(void);
 
-extern unsigned long s3c_sleep_save_phys;
-
 /* sleep save info */
 
 /**
@@ -181,13 +179,5 @@
  */
 extern void s3c_pm_save_gpios(void);
 
-/**
- * s3c_pm_cb_flushcache - callback for assembly code
- *
- * Callback to issue flush_cache_all() as this call is
- * not a directly callable object.
- */
-extern void s3c_pm_cb_flushcache(void);
-
 extern void s3c_pm_save_core(void);
 extern void s3c_pm_restore_core(void);
diff --git a/arch/arm/plat-samsung/pm.c b/arch/arm/plat-samsung/pm.c
index 02d531f..d5b58d3 100644
--- a/arch/arm/plat-samsung/pm.c
+++ b/arch/arm/plat-samsung/pm.c
@@ -241,8 +241,6 @@
 
 static int s3c_pm_enter(suspend_state_t state)
 {
-	static unsigned long regs_save[16];
-
 	/* ensure the debug is initialised (if enabled) */
 
 	s3c_pm_debug_init();
@@ -266,12 +264,6 @@
 		return -EINVAL;
 	}
 
-	/* store the physical address of the register recovery block */
-
-	s3c_sleep_save_phys = virt_to_phys(regs_save);
-
-	S3C_PMDBG("s3c_sleep_save_phys=0x%08lx\n", s3c_sleep_save_phys);
-
 	/* save all necessary core registers not covered by the drivers */
 
 	s3c_pm_save_gpios();
@@ -305,7 +297,7 @@
 	 * we resume as it saves its own register state and restores it
 	 * during the resume.  */
 
-	s3c_cpu_save(regs_save);
+	s3c_cpu_save(0, PLAT_PHYS_OFFSET - PAGE_OFFSET);
 
 	/* restore the cpu state using the kernel's cpu init code. */
 
@@ -336,12 +328,6 @@
 	return 0;
 }
 
-/* callback from assembly code */
-void s3c_pm_cb_flushcache(void)
-{
-	flush_cache_all();
-}
-
 static int s3c_pm_prepare(void)
 {
 	/* prepare check area if configured */