diff --git a/arch/arm/kernel/smp_scu.c b/arch/arm/kernel/smp_scu.c
index d3831f616ee9..9ab4149bd983 100644
--- a/arch/arm/kernel/smp_scu.c
+++ b/arch/arm/kernel/smp_scu.c
@@ -37,6 +37,10 @@ void __init scu_enable(void __iomem *scu_base)
 	u32 scu_ctrl;
 
 	scu_ctrl = __raw_readl(scu_base + SCU_CTRL);
+	/* already enabled? */
+	if (scu_ctrl & 1)
+		return;
+
 	scu_ctrl |= 1;
 	__raw_writel(scu_ctrl, scu_base + SCU_CTRL);
 
diff --git a/arch/arm/mach-realview/Kconfig b/arch/arm/mach-realview/Kconfig
index dfc9b0bc6eb2..c48e1f2c3349 100644
--- a/arch/arm/mach-realview/Kconfig
+++ b/arch/arm/mach-realview/Kconfig
@@ -70,6 +70,8 @@ config MACH_REALVIEW_PBX
 	bool "Support RealView/PBX platform"
 	select ARM_GIC
 	select HAVE_PATA_PLATFORM
+	select ARCH_SPARSEMEM_ENABLE if CPU_V7 && !HIGH_PHYS_OFFSET
+	select ZONE_DMA if SPARSEMEM
 	help
 	  Include support for the ARM(R) RealView PBX platform.
 
@@ -82,6 +84,7 @@ config REALVIEW_HIGH_PHYS_OFFSET
 	  0x70000000, 256MB of which being mirrored at 0x00000000. If
 	  the board supports 512MB of RAM, this option allows the
 	  memory to be accessed contiguously at the high physical
-	  offset.
+	  offset. On the PBX board, disabling this option allows 1GB of
+	  RAM to be used with SPARSEMEM.
 
 endmenu
diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c
index a2083b60e3fb..9f293438e020 100644
--- a/arch/arm/mach-realview/core.c
+++ b/arch/arm/mach-realview/core.c
@@ -59,6 +59,25 @@
 /* used by entry-macro.S and platsmp.c */
 void __iomem *gic_cpu_base_addr;
 
+#ifdef CONFIG_ZONE_DMA
+/*
+ * Adjust the zones if there are restrictions for DMA access.
+ */
+void __init realview_adjust_zones(int node, unsigned long *size,
+				  unsigned long *hole)
+{
+	unsigned long dma_size = SZ_256M >> PAGE_SHIFT;
+
+	if (!machine_is_realview_pbx() || node || (size[0] <= dma_size))
+		return;
+
+	size[ZONE_NORMAL] = size[0] - dma_size;
+	size[ZONE_DMA] = dma_size;
+	hole[ZONE_NORMAL] = hole[0];
+	hole[ZONE_DMA] = 0;
+}
+#endif
+
 /*
  * This is the RealView sched_clock implementation.  This has
  * a resolution of 41.7ns, and a maximum value of about 179s.
@@ -543,7 +562,7 @@ static int realview_clcd_setup(struct clcd_fb *fb)
 	fb->panel		= realview_clcd_panel();
 
 	fb->fb.screen_base = dma_alloc_writecombine(&fb->dev->dev, framesize,
-						    &dma, GFP_KERNEL);
+						    &dma, GFP_KERNEL | GFP_DMA);
 	if (!fb->fb.screen_base) {
 		printk(KERN_ERR "CLCD: unable to map framebuffer\n");
 		return -ENOMEM;
@@ -788,3 +807,24 @@ void __init realview_timer_init(unsigned int timer_irq)
 	realview_clocksource_init();
 	realview_clockevents_init(timer_irq);
 }
+
+/*
+ * Setup the memory banks.
+ */
+void realview_fixup(struct machine_desc *mdesc, struct tag *tags, char **from,
+		    struct meminfo *meminfo)
+{
+	/*
+	 * Most RealView platforms have 512MB contiguous RAM at 0x70000000.
+	 * Half of this is mirrored at 0.
+	 */
+#ifdef CONFIG_REALVIEW_HIGH_PHYS_OFFSET
+	meminfo->bank[0].start = 0x70000000;
+	meminfo->bank[0].size = SZ_512M;
+	meminfo->nr_banks = 1;
+#else
+	meminfo->bank[0].start = 0;
+	meminfo->bank[0].size = SZ_256M;
+	meminfo->nr_banks = 1;
+#endif
+}
diff --git a/arch/arm/mach-realview/core.h b/arch/arm/mach-realview/core.h
index 699671fa6e0b..781bca68a9fa 100644
--- a/arch/arm/mach-realview/core.h
+++ b/arch/arm/mach-realview/core.h
@@ -25,6 +25,7 @@
 #include <linux/amba/bus.h>
 #include <linux/io.h>
 
+#include <asm/setup.h>
 #include <asm/leds.h>
 
 #define AMBA_DEVICE(name,busid,base,plat)			\
@@ -44,6 +45,8 @@ static struct amba_device name##_device = {			\
 	/* .dma		= base##_DMA,*/				\
 }
 
+struct machine_desc;
+
 extern struct platform_device realview_flash_device;
 extern struct platform_device realview_cf_device;
 extern struct platform_device realview_i2c_device;
@@ -61,5 +64,8 @@ extern void realview_timer_init(unsigned int timer_irq);
 extern int realview_flash_register(struct resource *res, u32 num);
 extern int realview_eth_register(const char *name, struct resource *res);
 extern int realview_usb_register(struct resource *res);
+extern void realview_fixup(struct machine_desc *mdesc, struct tag *tags,
+			   char **from, struct meminfo *meminfo);
 extern void (*realview_reset)(char);
+
 #endif
diff --git a/arch/arm/mach-realview/include/mach/memory.h b/arch/arm/mach-realview/include/mach/memory.h
index 293c30025e7e..2417bbcf97fd 100644
--- a/arch/arm/mach-realview/include/mach/memory.h
+++ b/arch/arm/mach-realview/include/mach/memory.h
@@ -29,4 +29,53 @@
 #define PHYS_OFFSET		UL(0x00000000)
 #endif
 
+#if !defined(__ASSEMBLY__) && defined(CONFIG_ZONE_DMA)
+extern void realview_adjust_zones(int node, unsigned long *size,
+				  unsigned long *hole);
+#define arch_adjust_zones(node, size, hole) \
+	realview_adjust_zones(node, size, hole)
+
+#define ISA_DMA_THRESHOLD	(PHYS_OFFSET + SZ_256M - 1)
+#define MAX_DMA_ADDRESS		(PAGE_OFFSET + SZ_256M)
+#endif
+
+#ifdef CONFIG_SPARSEMEM
+
+/*
+ * Sparsemem definitions for RealView PBX.
+ *
+ * The RealView PBX board has another block of 512MB of RAM at 0x20000000,
+ * however only the block at 0x70000000 (or the 256MB mirror at 0x00000000)
+ * may be used for DMA.
+ *
+ * The macros below define a section size of 256MB and a non-linear virtual to
+ * physical mapping:
+ *
+ * 256MB @ 0x00000000 -> PAGE_OFFSET
+ * 512MB @ 0x20000000 -> PAGE_OFFSET + 0x10000000
+ * 256MB @ 0x80000000 -> PAGE_OFFSET + 0x30000000
+ */
+#ifdef CONFIG_REALVIEW_HIGH_PHYS_OFFSET
+#error "SPARSEMEM not available with REALVIEW_HIGH_PHYS_OFFSET"
+#endif
+
+#define MAX_PHYSMEM_BITS	32
+#define SECTION_SIZE_BITS	28
+
+/* bank page offsets */
+#define PAGE_OFFSET1	(PAGE_OFFSET + 0x10000000)
+#define PAGE_OFFSET2	(PAGE_OFFSET + 0x30000000)
+
+#define __phys_to_virt(phys)						\
+	((phys) >= 0x80000000 ?	(phys) - 0x80000000 + PAGE_OFFSET2 :	\
+	 (phys) >= 0x20000000 ?	(phys) - 0x20000000 + PAGE_OFFSET1 :	\
+	 (phys) + PAGE_OFFSET)
+
+#define __virt_to_phys(virt)						\
+	 ((virt) >= PAGE_OFFSET2 ? (virt) - PAGE_OFFSET2 + 0x80000000 :	\
+	  (virt) >= PAGE_OFFSET1 ? (virt) - PAGE_OFFSET1 + 0x20000000 :	\
+	  (virt) - PAGE_OFFSET)
+
+#endif	/* CONFIG_SPARSEMEM */
+
 #endif
diff --git a/arch/arm/mach-realview/platsmp.c b/arch/arm/mach-realview/platsmp.c
index a88458b4799d..009265818d55 100644
--- a/arch/arm/mach-realview/platsmp.c
+++ b/arch/arm/mach-realview/platsmp.c
@@ -146,11 +146,8 @@ static void __init poke_milo(void)
 	 * register. The BootMonitor waits for this register to become
 	 * non-zero.
 	 */
-#define REALVIEW_SYS_FLAGSS_OFFSET 0x30
-#define REALVIEW_SYS_FLAGSC_OFFSET 0x34
 	__raw_writel(BSYM(virt_to_phys(realview_secondary_startup)),
-		     __io_address(REALVIEW_SYS_BASE) +
-		     REALVIEW_SYS_FLAGSS_OFFSET);
+		     __io_address(REALVIEW_SYS_FLAGSSET));
 
 	mb();
 }
diff --git a/arch/arm/mach-realview/realview_eb.c b/arch/arm/mach-realview/realview_eb.c
index 1d65e64ae571..917f8ca3abff 100644
--- a/arch/arm/mach-realview/realview_eb.c
+++ b/arch/arm/mach-realview/realview_eb.c
@@ -415,6 +415,7 @@ MACHINE_START(REALVIEW_EB, "ARM-RealView EB")
 	.phys_io	= REALVIEW_EB_UART0_BASE,
 	.io_pg_offst	= (IO_ADDRESS(REALVIEW_EB_UART0_BASE) >> 18) & 0xfffc,
 	.boot_params	= PHYS_OFFSET + 0x00000100,
+	.fixup		= realview_fixup,
 	.map_io		= realview_eb_map_io,
 	.init_irq	= gic_init_irq,
 	.timer		= &realview_eb_timer,
diff --git a/arch/arm/mach-realview/realview_pb1176.c b/arch/arm/mach-realview/realview_pb1176.c
index a6ba147692c1..7fb726d5f8b9 100644
--- a/arch/arm/mach-realview/realview_pb1176.c
+++ b/arch/arm/mach-realview/realview_pb1176.c
@@ -300,6 +300,18 @@ static void realview_pb1176_reset(char mode)
 	__raw_writel(REALVIEW_PB1176_SYS_LOCKVAL_RSTCTL, hdr_ctrl);
 }
 
+static void realview_pb1176_fixup(struct machine_desc *mdesc,
+				  struct tag *tags, char **from,
+				  struct meminfo *meminfo)
+{
+	/*
+	 * RealView PB1176 only has 128MB of RAM mapped at 0.
+	 */
+	meminfo->bank[0].start = 0;
+	meminfo->bank[0].size = SZ_128M;
+	meminfo->nr_banks = 1;
+}
+
 static void __init realview_pb1176_init(void)
 {
 	int i;
@@ -331,6 +343,7 @@ MACHINE_START(REALVIEW_PB1176, "ARM-RealView PB1176")
 	.phys_io	= REALVIEW_PB1176_UART0_BASE,
 	.io_pg_offst	= (IO_ADDRESS(REALVIEW_PB1176_UART0_BASE) >> 18) & 0xfffc,
 	.boot_params	= PHYS_OFFSET + 0x00000100,
+	.fixup		= realview_pb1176_fixup,
 	.map_io		= realview_pb1176_map_io,
 	.init_irq	= gic_init_irq,
 	.timer		= &realview_pb1176_timer,
diff --git a/arch/arm/mach-realview/realview_pb11mp.c b/arch/arm/mach-realview/realview_pb11mp.c
index 070d284ce96e..9bbbfc05f225 100644
--- a/arch/arm/mach-realview/realview_pb11mp.c
+++ b/arch/arm/mach-realview/realview_pb11mp.c
@@ -347,6 +347,7 @@ MACHINE_START(REALVIEW_PB11MP, "ARM-RealView PB11MPCore")
 	.phys_io	= REALVIEW_PB11MP_UART0_BASE,
 	.io_pg_offst	= (IO_ADDRESS(REALVIEW_PB11MP_UART0_BASE) >> 18) & 0xfffc,
 	.boot_params	= PHYS_OFFSET + 0x00000100,
+	.fixup		= realview_fixup,
 	.map_io		= realview_pb11mp_map_io,
 	.init_irq	= gic_init_irq,
 	.timer		= &realview_pb11mp_timer,
diff --git a/arch/arm/mach-realview/realview_pba8.c b/arch/arm/mach-realview/realview_pba8.c
index 941beb2b9709..fe861e96c566 100644
--- a/arch/arm/mach-realview/realview_pba8.c
+++ b/arch/arm/mach-realview/realview_pba8.c
@@ -298,6 +298,7 @@ MACHINE_START(REALVIEW_PBA8, "ARM-RealView PB-A8")
 	.phys_io	= REALVIEW_PBA8_UART0_BASE,
 	.io_pg_offst	= (IO_ADDRESS(REALVIEW_PBA8_UART0_BASE) >> 18) & 0xfffc,
 	.boot_params	= PHYS_OFFSET + 0x00000100,
+	.fixup		= realview_fixup,
 	.map_io		= realview_pba8_map_io,
 	.init_irq	= gic_init_irq,
 	.timer		= &realview_pba8_timer,
diff --git a/arch/arm/mach-realview/realview_pbx.c b/arch/arm/mach-realview/realview_pbx.c
index 7e4bc6cdca52..ec39488e2b42 100644
--- a/arch/arm/mach-realview/realview_pbx.c
+++ b/arch/arm/mach-realview/realview_pbx.c
@@ -304,6 +304,26 @@ static struct sys_timer realview_pbx_timer = {
 	.init		= realview_pbx_timer_init,
 };
 
+static void realview_pbx_fixup(struct machine_desc *mdesc, struct tag *tags,
+			       char **from, struct meminfo *meminfo)
+{
+#ifdef CONFIG_SPARSEMEM
+	/*
+	 * Memory configuration with SPARSEMEM enabled on RealView PBX (see
+	 * asm/mach/memory.h for more information).
+	 */
+	meminfo->bank[0].start = 0;
+	meminfo->bank[0].size = SZ_256M;
+	meminfo->bank[1].start = 0x20000000;
+	meminfo->bank[1].size = SZ_512M;
+	meminfo->bank[2].start = 0x80000000;
+	meminfo->bank[2].size = SZ_256M;
+	meminfo->nr_banks = 3;
+#else
+	realview_fixup(mdesc, tags, from, meminfo);
+#endif
+}
+
 static void __init realview_pbx_init(void)
 {
 	int i;
@@ -345,6 +365,7 @@ MACHINE_START(REALVIEW_PBX, "ARM-RealView PBX")
 	.phys_io	= REALVIEW_PBX_UART0_BASE,
 	.io_pg_offst	= (IO_ADDRESS(REALVIEW_PBX_UART0_BASE) >> 18) & 0xfffc,
 	.boot_params	= PHYS_OFFSET + 0x00000100,
+	.fixup		= realview_pbx_fixup,
 	.map_io		= realview_pbx_map_io,
 	.init_irq	= gic_init_irq,
 	.timer		= &realview_pbx_timer,
diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S
index eeeed01ee44a..3a285218fd15 100644
--- a/arch/arm/mm/proc-v7.S
+++ b/arch/arm/mm/proc-v7.S
@@ -186,9 +186,10 @@ cpu_v7_name:
  */
 __v7_setup:
 #ifdef CONFIG_SMP
-	mrc	p15, 0, r0, c1, c0, 1		@ Enable SMP/nAMP mode and
-	orr	r0, r0, #(1 << 6) | (1 << 0)	@ TLB ops broadcasting
-	mcr	p15, 0, r0, c1, c0, 1
+	mrc	p15, 0, r0, c1, c0, 1
+	tst	r0, #(1 << 6)			@ SMP/nAMP mode enabled?
+	orreq	r0, r0, #(1 << 6) | (1 << 0)	@ Enable SMP/nAMP mode and
+	mcreq	p15, 0, r0, c1, c0, 1		@ TLB ops broadcasting
 #endif
 	adr	r12, __v7_setup_stack		@ the local stack
 	stmia	r12, {r0-r5, r7, r9, r11, lr}