#define CR_AFE (1 << 29)       /* Access flag enable                   */
 #define CR_TE  (1 << 30)       /* Thumb exception enable               */
 
-#ifndef PGTABLE_SIZE
+#if defined(CONFIG_ARMV7_LPAE) && !defined(PGTABLE_SIZE)
+#define PGTABLE_SIZE           (4096 * 5)
+#elif !defined(PGTABLE_SIZE)
 #define PGTABLE_SIZE           (4096 * 4)
 #endif
 
 #define wfi()
 #endif
 
+static inline unsigned long get_cpsr(void)
+{
+       unsigned long cpsr;
+
+       asm volatile("mrs %0, cpsr" : "=r"(cpsr): );
+       return cpsr;
+}
+
+static inline int is_hyp(void)
+{
+#ifdef CONFIG_ARMV7_LPAE
+       /* HYP mode requires LPAE ... */
+       return ((get_cpsr() & 0x1f) == 0x1a);
+#else
+       /* ... so without LPAE support we can optimize all hyp code away */
+       return 0;
+#endif
+}
+
 static inline unsigned int get_cr(void)
 {
        unsigned int val;
-       asm volatile("mrc p15, 0, %0, c1, c0, 0 @ get CR" : "=r" (val) : : "cc");
+
+       if (is_hyp())
+               asm volatile("mrc p15, 4, %0, c1, c0, 0 @ get CR" : "=r" (val)
+                                                                 :
+                                                                 : "cc");
+       else
+               asm volatile("mrc p15, 0, %0, c1, c0, 0 @ get CR" : "=r" (val)
+                                                                 :
+                                                                 : "cc");
        return val;
 }
 
 static inline void set_cr(unsigned int val)
 {
-       asm volatile("mcr p15, 0, %0, c1, c0, 0 @ set CR"
-         : : "r" (val) : "cc");
+       if (is_hyp())
+               asm volatile("mcr p15, 4, %0, c1, c0, 0 @ set CR" :
+                                                                 : "r" (val)
+                                                                 : "cc");
+       else
+               asm volatile("mcr p15, 0, %0, c1, c0, 0 @ set CR" :
+                                                                 : "r" (val)
+                                                                 : "cc");
        isb();
 }
 
        isb();
 }
 
-#ifdef CONFIG_CPU_V7
+#ifdef CONFIG_ARMV7_LPAE
+/* Long-Descriptor Translation Table Level 1/2 Bits */
+#define TTB_SECT_XN_MASK       (1ULL << 54)
+#define TTB_SECT_NG_MASK       (1 << 11)
+#define TTB_SECT_AF            (1 << 10)
+#define TTB_SECT_SH_MASK       (3 << 8)
+#define TTB_SECT_NS_MASK       (1 << 5)
+#define TTB_SECT_AP            (1 << 6)
+/* Note: TTB AP bits are set elsewhere */
+#define TTB_SECT_MAIR(x)       ((x & 0x7) << 2) /* Index into MAIR */
+#define TTB_SECT               (1 << 0)
+#define TTB_PAGETABLE          (3 << 0)
+
+/* TTBCR flags */
+#define TTBCR_EAE              (1 << 31)
+#define TTBCR_T0SZ(x)          ((x) << 0)
+#define TTBCR_T1SZ(x)          ((x) << 16)
+#define TTBCR_USING_TTBR0      (TTBCR_T0SZ(0) | TTBCR_T1SZ(0))
+#define TTBCR_IRGN0_NC         (0 << 8)
+#define TTBCR_IRGN0_WBWA       (1 << 8)
+#define TTBCR_IRGN0_WT         (2 << 8)
+#define TTBCR_IRGN0_WBNWA      (3 << 8)
+#define TTBCR_IRGN0_MASK       (3 << 8)
+#define TTBCR_ORGN0_NC         (0 << 10)
+#define TTBCR_ORGN0_WBWA       (1 << 10)
+#define TTBCR_ORGN0_WT         (2 << 10)
+#define TTBCR_ORGN0_WBNWA      (3 << 10)
+#define TTBCR_ORGN0_MASK       (3 << 10)
+#define TTBCR_SHARED_NON       (0 << 12)
+#define TTBCR_SHARED_OUTER     (2 << 12)
+#define TTBCR_SHARED_INNER     (3 << 12)
+#define TTBCR_EPD0             (0 << 7)
+
+/*
+ * Memory types
+ */
+#define MEMORY_ATTRIBUTES      ((0x00 << (0 * 8)) | (0x88 << (1 * 8)) | \
+                                (0xcc << (2 * 8)) | (0xff << (3 * 8)))
+
+/* options available for data cache on each page */
+enum dcache_option {
+       DCACHE_OFF = TTB_SECT | TTB_SECT_MAIR(0),
+       DCACHE_WRITETHROUGH = TTB_SECT | TTB_SECT_MAIR(1),
+       DCACHE_WRITEBACK = TTB_SECT | TTB_SECT_MAIR(2),
+       DCACHE_WRITEALLOC = TTB_SECT | TTB_SECT_MAIR(3),
+};
+#elif defined(CONFIG_CPU_V7)
 /* Short-Descriptor Translation Table Level 1 Bits */
 #define TTB_SECT_NS_MASK       (1 << 19)
 #define TTB_SECT_NG_MASK       (1 << 17)
 #define TTB_SECT_S_MASK                (1 << 16)
 /* Note: TTB AP bits are set elsewhere */
+#define TTB_SECT_AP            (3 << 10)
 #define TTB_SECT_TEX(x)                ((x & 0x7) << 12)
 #define TTB_SECT_DOMAIN(x)     ((x & 0xf) << 5)
 #define TTB_SECT_XN_MASK       (1 << 4)
        DCACHE_WRITEALLOC = DCACHE_WRITEBACK | TTB_SECT_TEX(1),
 };
 #else
+#define TTB_SECT_AP            (3 << 10)
 /* options available for data cache on each page */
 enum dcache_option {
        DCACHE_OFF = 0x12,
 
 /* Size of an MMU section */
 enum {
-       MMU_SECTION_SHIFT       = 20,
+#ifdef CONFIG_ARMV7_LPAE
+       MMU_SECTION_SHIFT       = 21, /* 2MB */
+#else
+       MMU_SECTION_SHIFT       = 20, /* 1MB */
+#endif
        MMU_SECTION_SIZE        = 1 << MMU_SECTION_SHIFT,
 };
 
 
 
 void set_section_dcache(int section, enum dcache_option option)
 {
+#ifdef CONFIG_ARMV7_LPAE
+       u64 *page_table = (u64 *)gd->arch.tlb_addr;
+       /* Need to set the access flag to not fault */
+       u64 value = TTB_SECT_AP | TTB_SECT_AF;
+#else
        u32 *page_table = (u32 *)gd->arch.tlb_addr;
-       u32 value;
+       u32 value = TTB_SECT_AP;
+#endif
+
+       /* Add the page offset */
+       value |= ((u32)section << MMU_SECTION_SHIFT);
 
-       value = (section << MMU_SECTION_SHIFT) | (3 << 10);
+       /* Add caching bits */
        value |= option;
+
+       /* Set PTE */
        page_table[section] = value;
 }
 
        int     i;
 
        debug("%s: bank: %d\n", __func__, bank);
-       for (i = bd->bi_dram[bank].start >> 20;
-            i < (bd->bi_dram[bank].start >> 20) + (bd->bi_dram[bank].size >> 20);
+       for (i = bd->bi_dram[bank].start >> MMU_SECTION_SHIFT;
+            i < (bd->bi_dram[bank].start >> MMU_SECTION_SHIFT) +
+                (bd->bi_dram[bank].size >> MMU_SECTION_SHIFT);
             i++) {
 #if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH)
                set_section_dcache(i, DCACHE_WRITETHROUGH);
 
        arm_init_before_mmu();
        /* Set up an identity-mapping for all 4GB, rw for everyone */
-       for (i = 0; i < 4096; i++)
+       for (i = 0; i < ((4096ULL * 1024 * 1024) >> MMU_SECTION_SHIFT); i++)
                set_section_dcache(i, DCACHE_OFF);
 
        for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
                dram_bank_mmu_setup(i);
        }
 
-#ifdef CONFIG_CPU_V7
+#ifdef CONFIG_ARMV7_LPAE
+       /* Set up 4 PTE entries pointing to our 4 1GB page tables */
+       for (i = 0; i < 4; i++) {
+               u64 *page_table = (u64 *)(gd->arch.tlb_addr + (4096 * 4));
+               u64 tpt = gd->arch.tlb_addr + (4096 * i);
+               page_table[i] = tpt | TTB_PAGETABLE;
+       }
+
+       reg = TTBCR_EAE;
+#if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH)
+       reg |= TTBCR_ORGN0_WT | TTBCR_IRGN0_WT;
+#elif defined(CONFIG_SYS_ARM_CACHE_WRITEALLOC)
+       reg |= TTBCR_ORGN0_WBWA | TTBCR_IRGN0_WBWA;
+#else
+       reg |= TTBCR_ORGN0_WBNWA | TTBCR_IRGN0_WBNWA;
+#endif
+
+       if (is_hyp()) {
+               /* Set HCTR to enable LPAE */
+               asm volatile("mcr p15, 4, %0, c2, c0, 2"
+                       : : "r" (reg) : "memory");
+               /* Set HTTBR0 */
+               asm volatile("mcrr p15, 4, %0, %1, c2"
+                       :
+                       : "r"(gd->arch.tlb_addr + (4096 * 4)), "r"(0)
+                       : "memory");
+               /* Set HMAIR */
+               asm volatile("mcr p15, 4, %0, c10, c2, 0"
+                       : : "r" (MEMORY_ATTRIBUTES) : "memory");
+       } else {
+               /* Set TTBCR to enable LPAE */
+               asm volatile("mcr p15, 0, %0, c2, c0, 2"
+                       : : "r" (reg) : "memory");
+               /* Set 64-bit TTBR0 */
+               asm volatile("mcrr p15, 0, %0, %1, c2"
+                       :
+                       : "r"(gd->arch.tlb_addr + (4096 * 4)), "r"(0)
+                       : "memory");
+               /* Set MAIR */
+               asm volatile("mcr p15, 0, %0, c10, c2, 0"
+                       : : "r" (MEMORY_ATTRIBUTES) : "memory");
+       }
+#elif defined(CONFIG_CPU_V7)
        /* Set TTBR0 */
        reg = gd->arch.tlb_addr & TTBR0_BASE_ADDR_MASK;
 #if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH)