summaryrefslogtreecommitdiffstats
path: root/arch/sh/mm/pmb.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sh/mm/pmb.c')
-rw-r--r--arch/sh/mm/pmb.c156
1 files changed, 105 insertions, 51 deletions
diff --git a/arch/sh/mm/pmb.c b/arch/sh/mm/pmb.c
index 8f7dbf183fb0..b796b6c021b4 100644
--- a/arch/sh/mm/pmb.c
+++ b/arch/sh/mm/pmb.c
@@ -3,11 +3,8 @@
*
* Privileged Space Mapping Buffer (PMB) Support.
*
- * Copyright (C) 2005 - 2010 Paul Mundt
- *
- * P1/P2 Section mapping definitions from map32.h, which was:
- *
- * Copyright 2003 (c) Lineo Solutions,Inc.
+ * Copyright (C) 2005 - 2010 Paul Mundt
+ * Copyright (C) 2010 Matt Fleming
*
* 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
@@ -280,46 +277,82 @@ static void __pmb_unmap(struct pmb_entry *pmbe)
}
#ifdef CONFIG_PMB_LEGACY
+static inline unsigned int pmb_ppn_in_range(unsigned long ppn)
+{
+ return ppn >= __MEMORY_START && ppn < __MEMORY_START + __MEMORY_SIZE;
+}
+
static int pmb_apply_legacy_mappings(void)
{
- int i;
- unsigned long addr, data;
unsigned int applied = 0;
+ int i;
- for (i = 0; i < PMB_ENTRY_MAX; i++) {
- struct pmb_entry *pmbe;
- unsigned long vpn, ppn, flags;
-
- addr = PMB_DATA + (i << PMB_E_SHIFT);
- data = ctrl_inl(addr);
- if (!(data & PMB_V))
- continue;
+ pr_info("PMB: Preserving legacy mappings:\n");
- if (data & PMB_C) {
-#if defined(CONFIG_CACHE_WRITETHROUGH)
- data |= PMB_WT;
-#elif defined(CONFIG_CACHE_WRITEBACK)
- data &= ~PMB_WT;
-#else
- data &= ~(PMB_C | PMB_WT);
-#endif
- }
- ctrl_outl(data, addr);
-
- ppn = data & PMB_PFN_MASK;
+ /*
+ * The following entries are setup by the bootloader.
+ *
+ * Entry VPN PPN V SZ C UB
+ * --------------------------------------------------------
+ * 0 0xA0000000 0x00000000 1 64MB 0 0
+ * 1 0xA4000000 0x04000000 1 16MB 0 0
+ * 2 0xA6000000 0x08000000 1 16MB 0 0
+ * 9 0x88000000 0x48000000 1 128MB 1 1
+ * 10 0x90000000 0x50000000 1 128MB 1 1
+ * 11 0x98000000 0x58000000 1 128MB 1 1
+ * 13 0xA8000000 0x48000000 1 128MB 0 0
+ * 14 0xB0000000 0x50000000 1 128MB 0 0
+ * 15 0xB8000000 0x58000000 1 128MB 0 0
+ *
+ * The only entries the we need are the ones that map the kernel
+ * at the cached and uncached addresses.
+ */
+ for (i = 0; i < PMB_ENTRY_MAX; i++) {
+ unsigned long addr, data;
+ unsigned long addr_val, data_val;
+ unsigned long ppn, vpn;
- flags = data & (PMB_C | PMB_WT | PMB_UB);
- flags |= data & PMB_SZ_MASK;
+ addr = mk_pmb_addr(i);
+ data = mk_pmb_data(i);
- addr = PMB_ADDR + (i << PMB_E_SHIFT);
- data = ctrl_inl(addr);
+ addr_val = __raw_readl(addr);
+ data_val = __raw_readl(data);
- vpn = data & PMB_PFN_MASK;
+ /*
+ * Skip over any bogus entries
+ */
+ if (!(data_val & PMB_V) || !(addr_val & PMB_V))
+ continue;
- pmbe = pmb_alloc(vpn, ppn, flags, i);
- WARN_ON(IS_ERR(pmbe));
+ ppn = data_val & PMB_PFN_MASK;
+ vpn = addr_val & PMB_PFN_MASK;
- applied++;
+ /*
+ * Only preserve in-range mappings.
+ */
+ if (pmb_ppn_in_range(ppn)) {
+ unsigned int size;
+ char *sz_str = NULL;
+
+ size = data_val & PMB_SZ_MASK;
+
+ sz_str = (size == PMB_SZ_16M) ? " 16MB":
+ (size == PMB_SZ_64M) ? " 64MB":
+ (size == PMB_SZ_128M) ? "128MB":
+ "512MB";
+
+ pr_info("\t0x%08lx -> 0x%08lx [ %s %scached ]\n",
+ vpn >> PAGE_SHIFT, ppn >> PAGE_SHIFT, sz_str,
+ (data_val & PMB_C) ? "" : "un");
+
+ applied++;
+ } else {
+ /*
+ * Invalidate anything out of bounds.
+ */
+ __raw_writel(addr_val & ~PMB_V, addr);
+ __raw_writel(data_val & ~PMB_V, data);
+ }
}
return (applied == 0);
@@ -333,8 +366,9 @@ static inline int pmb_apply_legacy_mappings(void)
int __uses_jump_to_uncached pmb_init(void)
{
- unsigned int i;
- unsigned long size, ret;
+ int i;
+ unsigned long addr, data;
+ unsigned long ret;
jump_to_uncached();
@@ -352,25 +386,45 @@ int __uses_jump_to_uncached pmb_init(void)
}
/*
- * Insert PMB entries for the P1 and P2 areas so that, after
- * we've switched the MMU to 32-bit mode, the semantics of P1
- * and P2 are the same as in 29-bit mode, e.g.
- *
- * P1 - provides a cached window onto physical memory
- * P2 - provides an uncached window onto physical memory
+ * Sync our software copy of the PMB mappings with those in
+ * hardware. The mappings in the hardware PMB were either set up
+ * by the bootloader or very early on by the kernel.
*/
- size = (unsigned long)__MEMORY_START + __MEMORY_SIZE;
+ for (i = 0; i < PMB_ENTRY_MAX; i++) {
+ struct pmb_entry *pmbe;
+ unsigned long vpn, ppn, flags;
- ret = pmb_remap(P1SEG, 0x00000000, size, PMB_C);
- BUG_ON(ret != size);
+ addr = PMB_DATA + (i << PMB_E_SHIFT);
+ data = ctrl_inl(addr);
+ if (!(data & PMB_V))
+ continue;
- ret = pmb_remap(P2SEG, 0x00000000, size, PMB_WT | PMB_UB);
- BUG_ON(ret != size);
+ if (data & PMB_C) {
+#if defined(CONFIG_CACHE_WRITETHROUGH)
+ data |= PMB_WT;
+#elif defined(CONFIG_CACHE_WRITEBACK)
+ data &= ~PMB_WT;
+#else
+ data &= ~(PMB_C | PMB_WT);
+#endif
+ }
+ ctrl_outl(data, addr);
- ctrl_outl(0, PMB_IRMCR);
+ ppn = data & PMB_PFN_MASK;
+
+ flags = data & (PMB_C | PMB_WT | PMB_UB);
+ flags |= data & PMB_SZ_MASK;
- /* PMB.SE and UB[7] */
- ctrl_outl(PASCR_SE | (1 << 7), PMB_PASCR);
+ addr = PMB_ADDR + (i << PMB_E_SHIFT);
+ data = ctrl_inl(addr);
+
+ vpn = data & PMB_PFN_MASK;
+
+ pmbe = pmb_alloc(vpn, ppn, flags, i);
+ WARN_ON(IS_ERR(pmbe));
+ }
+
+ ctrl_outl(0, PMB_IRMCR);
/* Flush out the TLB */
i = ctrl_inl(MMUCR);