bool "Support SH7786 processor"
        select CPU_SH4A
        select CPU_SHX3
+       select CPU_HAS_PTEAEX
        select ARCH_SPARSEMEM_ENABLE
        select SYS_SUPPORTS_NUMA
 
 
 config CPU_HAS_PTEA
        bool
 
+config CPU_HAS_PTEAEX
+       bool
+
 config CPU_HAS_DSP
        bool
 
 
 #define CPU_HAS_LLSC           0x0040  /* movli.l/movco.l */
 #define CPU_HAS_L2_CACHE       0x0080  /* Secondary cache / URAM */
 #define CPU_HAS_OP32           0x0100  /* 32-bit instruction support */
+#define CPU_HAS_PTEAEX         0x0200  /* PTE ASID Extension support */
 
 #endif /* __ASM_SH_CPU_FEATURES_H */
 
  *    (a) TLB cache version (or round, cycle whatever expression you like)
  *    (b) ASID (Address Space IDentifier)
  */
+#ifdef CONFIG_CPU_HAS_PTEAEX
+#define MMU_CONTEXT_ASID_MASK          0x0000ffff
+#else
 #define MMU_CONTEXT_ASID_MASK          0x000000ff
-#define MMU_CONTEXT_VERSION_MASK       0xffffff00
-#define MMU_CONTEXT_FIRST_VERSION      0x00000100
-#define NO_CONTEXT                     0UL
+#endif
 
-/* ASID is 8-bit value, so it can't be 0x100 */
-#define MMU_NO_ASID                    0x100
+#define MMU_CONTEXT_VERSION_MASK       (~0UL & ~MMU_CONTEXT_ASID_MASK)
+#define MMU_CONTEXT_FIRST_VERSION      (MMU_CONTEXT_ASID_MASK + 1)
+
+/* Impossible ASID value, to differentiate from NO_CONTEXT. */
+#define MMU_NO_ASID                    MMU_CONTEXT_FIRST_VERSION
+#define NO_CONTEXT                     0UL
 
 #define asid_cache(cpu)                (cpu_data[cpu].asid_cache)
 
 
        /* Do nothing */
 }
 
+#ifdef CONFIG_CPU_HAS_PTEAEX
+static inline void set_asid(unsigned long asid)
+{
+       __raw_writel(asid, MMU_PTEAEX);
+}
+
+static inline unsigned long get_asid(void)
+{
+       return __raw_readl(MMU_PTEAEX) & MMU_CONTEXT_ASID_MASK;
+}
+#else
 static inline void set_asid(unsigned long asid)
 {
        unsigned long __dummy;
        asid &= MMU_CONTEXT_ASID_MASK;
        return asid;
 }
+#endif /* CONFIG_CPU_HAS_PTEAEX */
 
 /* MMU_TTB is used for optimizing the fault handling. */
 static inline void set_TTB(pgd_t *pgd)
 
 #define MMU_PTEL       0xFF000004      /* Page table entry register LOW */
 #define MMU_TTB                0xFF000008      /* Translation table base register */
 #define MMU_TEA                0xFF00000C      /* TLB Exception Address */
-#define MMU_PTEA       0xFF000034      /* Page table entry assistance register */
+#define MMU_PTEA       0xFF000034      /* PTE assistance register */
+#define MMU_PTEAEX     0xFF00007C      /* PTE ASID extension register */
 
 #define MMUCR          0xFF000010      /* MMU Control Register */
 
-#define MMU_ITLB_ADDRESS_ARRAY 0xF2000000
 #define MMU_UTLB_ADDRESS_ARRAY 0xF6000000
+#define MMU_UTLB_ADDRESS_ARRAY2        0xF6800000
 #define MMU_PAGE_ASSOC_BIT     0x80
 
 #define MMUCR_TI               (1<<2)
 
-#ifdef CONFIG_X2TLB
-#define MMUCR_ME               (1 << 7)
-#else
-#define MMUCR_ME               (0)
-#endif
-
 #if defined(CONFIG_32BIT) && defined(CONFIG_CPU_SUBTYPE_ST40)
 #define MMUCR_SE               (1 << 4)
 #else
 #define MMUCR_SE               (0)
 #endif
 
+#ifdef CONFIG_CPU_HAS_PTEAEX
+#define MMUCR_AEX              (1 << 6)
+#else
+#define MMUCR_AEX              (0)
+#endif
+
+#ifdef CONFIG_X2TLB
+#define MMUCR_ME               (1 << 7)
+#else
+#define MMUCR_ME               (0)
+#endif
+
 #ifdef CONFIG_SH_STORE_QUEUES
 #define MMUCR_SQMD             (1 << 9)
 #else
 #endif
 
 #define MMU_NTLB_ENTRIES       64
-#define MMU_CONTROL_INIT       (0x05|MMUCR_SQMD|MMUCR_ME|MMUCR_SE)
-
-#define MMU_ITLB_DATA_ARRAY    0xF3000000
-#define MMU_UTLB_DATA_ARRAY    0xF7000000
-
-#define MMU_UTLB_ENTRIES          64
-#define MMU_U_ENTRY_SHIFT          8
-#define MMU_UTLB_VALID         0x100
-#define MMU_ITLB_ENTRIES           4
-#define MMU_I_ENTRY_SHIFT          8
-#define MMU_ITLB_VALID         0x100
+#define MMU_CONTROL_INIT       (0x05|MMUCR_SQMD|MMUCR_ME|MMUCR_SE|MMUCR_AEX)
 
 #define TRA    0xff000020
 #define EXPEVT 0xff000024
 
                boot_cpu_data.icache.ways = 4;
                boot_cpu_data.dcache.ways = 4;
                boot_cpu_data.flags |= CPU_HAS_FPU | CPU_HAS_PERF_COUNTER |
-                       CPU_HAS_LLSC;
+                       CPU_HAS_LLSC | CPU_HAS_PTEAEX;
                break;
        case 0x3008:
                boot_cpu_data.icache.ways = 4;
 
 /* Symbolic CPU flags, keep in sync with asm/cpu-features.h */
 static const char *cpu_flags[] = {
        "none", "fpu", "p2flush", "mmuassoc", "dsp", "perfctr",
-       "ptea", "llsc", "l2", "op32", NULL
+       "ptea", "llsc", "l2", "op32", "pteaex", NULL
 };
 
 static void show_cpuflags(struct seq_file *m, struct sh_cpuinfo *c)
 
 endif
 
 ifdef CONFIG_MMU
-obj-$(CONFIG_CPU_SH3)  += tlb-sh3.o
-obj-$(CONFIG_CPU_SH4)  += tlb-sh4.o
+tlb-$(CONFIG_CPU_SH3)          := tlb-sh3.o
+tlb-$(CONFIG_CPU_SH4)          := tlb-sh4.o
+tlb-$(CONFIG_CPU_HAS_PTEAEX)   := tlb-pteaex.o
+obj-y                          += $(tlb-y)
 ifndef CONFIG_CACHE_OFF
 obj-$(CONFIG_CPU_SH4)          += pg-sh4.o
 obj-$(CONFIG_SH7705_CACHE_32KB)        += pg-sh7705.o
 
--- /dev/null
+/*
+ * arch/sh/mm/tlb-pteaex.c
+ *
+ * TLB operations for SH-X3 CPUs featuring PTE ASID Extensions.
+ *
+ * Copyright (C) 2009 Paul Mundt
+ *
+ * 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/kernel.h>
+#include <linux/mm.h>
+#include <linux/io.h>
+#include <asm/system.h>
+#include <asm/mmu_context.h>
+#include <asm/cacheflush.h>
+
+void update_mmu_cache(struct vm_area_struct * vma,
+                     unsigned long address, pte_t pte)
+{
+       unsigned long flags;
+       unsigned long pteval;
+       unsigned long vpn;
+
+       /* Ptrace may call this routine. */
+       if (vma && current->active_mm != vma->vm_mm)
+               return;
+
+#ifndef CONFIG_CACHE_OFF
+       {
+               unsigned long pfn = pte_pfn(pte);
+
+               if (pfn_valid(pfn)) {
+                       struct page *page = pfn_to_page(pfn);
+
+                       if (!test_bit(PG_mapped, &page->flags)) {
+                               unsigned long phys = pte_val(pte) & PTE_PHYS_MASK;
+                               __flush_wback_region((void *)P1SEGADDR(phys),
+                                                    PAGE_SIZE);
+                               __set_bit(PG_mapped, &page->flags);
+                       }
+               }
+       }
+#endif
+
+       local_irq_save(flags);
+
+       /* Set PTEH register */
+       vpn = address & MMU_VPN_MASK;
+       __raw_writel(vpn, MMU_PTEH);
+
+       /* Set PTEAEX */
+       __raw_writel(get_asid(), MMU_PTEAEX);
+
+       pteval = pte.pte_low;
+
+       /* Set PTEA register */
+#ifdef CONFIG_X2TLB
+       /*
+        * For the extended mode TLB this is trivial, only the ESZ and
+        * EPR bits need to be written out to PTEA, with the remainder of
+        * the protection bits (with the exception of the compat-mode SZ
+        * and PR bits, which are cleared) being written out in PTEL.
+        */
+       __raw_writel(pte.pte_high, MMU_PTEA);
+#else
+       /* TODO: make this look less hacky */
+       __raw_writel(((pteval >> 28) & 0xe) | (pteval & 0x1), MMU_PTEA);
+#endif
+
+       /* Set PTEL register */
+       pteval &= _PAGE_FLAGS_HARDWARE_MASK; /* drop software flags */
+#ifdef CONFIG_CACHE_WRITETHROUGH
+       pteval |= _PAGE_WT;
+#endif
+       /* conveniently, we want all the software flags to be 0 anyway */
+       __raw_writel(pteval, MMU_PTEL);
+
+       /* Load the TLB */
+       asm volatile("ldtlb": /* no output */ : /* no input */ : "memory");
+       local_irq_restore(flags);
+}
+
+/*
+ * While SH-X2 extended TLB mode splits out the memory-mapped I/UTLB
+ * data arrays, SH-X3 cores with PTEAEX split out the memory-mapped
+ * address arrays. In compat mode the second array is inaccessible, while
+ * in extended mode, the legacy 8-bit ASID field in address array 1 has
+ * undefined behaviour.
+ */
+void __uses_jump_to_uncached local_flush_tlb_one(unsigned long asid,
+                                                unsigned long page)
+{
+       jump_to_uncached();
+       __raw_writel(page, MMU_UTLB_ADDRESS_ARRAY | MMU_PAGE_ASSOC_BIT);
+       __raw_writel(asid, MMU_UTLB_ADDRESS_ARRAY2 | MMU_PAGE_ASSOC_BIT);
+       back_to_cached();
+}