*
* Privileged Space Mapping Buffer (PMB) Support.
*
- * Copyright (C) 2005, 2006, 2007 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
static void __set_pmb_entry(unsigned long vpn, unsigned long ppn,
unsigned long flags, int pos)
{
- ctrl_outl(vpn | PMB_V, mk_pmb_addr(pos));
+ __raw_writel(vpn | PMB_V, mk_pmb_addr(pos));
#ifdef CONFIG_CACHE_WRITETHROUGH
/*
flags |= PMB_WT;
#endif
- ctrl_outl(ppn | flags | PMB_V, mk_pmb_data(pos));
+ __raw_writel(ppn | flags | PMB_V, mk_pmb_data(pos));
}
-static void __uses_jump_to_uncached set_pmb_entry(struct pmb_entry *pmbe)
+static void set_pmb_entry(struct pmb_entry *pmbe)
{
jump_to_uncached();
__set_pmb_entry(pmbe->vpn, pmbe->ppn, pmbe->flags, pmbe->entry);
back_to_cached();
}
-static void __uses_jump_to_uncached clear_pmb_entry(struct pmb_entry *pmbe)
+static void clear_pmb_entry(struct pmb_entry *pmbe)
{
unsigned int entry = pmbe->entry;
unsigned long addr;
/* Clear V-bit */
addr = mk_pmb_addr(entry);
- ctrl_outl(ctrl_inl(addr) & ~PMB_V, addr);
+ __raw_writel(__raw_readl(addr) & ~PMB_V, addr);
addr = mk_pmb_data(entry);
- ctrl_outl(ctrl_inl(addr) & ~PMB_V, addr);
+ __raw_writel(__raw_readl(addr) & ~PMB_V, addr);
back_to_cached();
}
} while (pmbe);
}
-#ifdef CONFIG_PMB
-int __uses_jump_to_uncached pmb_init(void)
+#ifdef CONFIG_PMB_LEGACY
+static inline unsigned int pmb_ppn_in_range(unsigned long ppn)
{
- unsigned int i;
- long size, ret;
+ return ppn >= __MEMORY_START && ppn < __MEMORY_START + __MEMORY_SIZE;
+}
- jump_to_uncached();
+static int pmb_apply_legacy_mappings(void)
+{
+ unsigned int applied = 0;
+ int i;
+
+ pr_info("PMB: Preserving legacy mappings:\n");
/*
- * 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.
+ * 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
*
- * P1 - provides a cached window onto physical memory
- * P2 - provides an uncached window onto physical memory
+ * The only entries the we need are the ones that map the kernel
+ * at the cached and uncached addresses.
*/
- size = __MEMORY_START + __MEMORY_SIZE;
-
- ret = pmb_remap(P1SEG, 0x00000000, size, PMB_C);
- BUG_ON(ret != size);
+ for (i = 0; i < PMB_ENTRY_MAX; i++) {
+ unsigned long addr, data;
+ unsigned long addr_val, data_val;
+ unsigned long ppn, vpn;
- ret = pmb_remap(P2SEG, 0x00000000, size, PMB_WT | PMB_UB);
- BUG_ON(ret != size);
+ addr = mk_pmb_addr(i);
+ data = mk_pmb_data(i);
- ctrl_outl(0, PMB_IRMCR);
+ addr_val = __raw_readl(addr);
+ data_val = __raw_readl(data);
- /* PMB.SE and UB[7] */
- ctrl_outl(PASCR_SE | (1 << 7), PMB_PASCR);
+ /*
+ * Skip over any bogus entries
+ */
+ if (!(data_val & PMB_V) || !(addr_val & PMB_V))
+ continue;
- /* Flush out the TLB */
- i = ctrl_inl(MMUCR);
- i |= MMUCR_TI;
- ctrl_outl(i, MMUCR);
+ ppn = data_val & PMB_PFN_MASK;
+ vpn = addr_val & PMB_PFN_MASK;
- back_to_cached();
+ /*
+ * 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 0;
+ return (applied == 0);
}
#else
-int __uses_jump_to_uncached pmb_init(void)
+static inline int pmb_apply_legacy_mappings(void)
+{
+ return 1;
+}
+#endif
+
+int pmb_init(void)
{
int i;
unsigned long addr, data;
+ unsigned long ret;
jump_to_uncached();
+ /*
+ * Attempt to apply the legacy boot mappings if configured. If
+ * this is successful then we simply carry on with those and
+ * don't bother establishing additional memory mappings. Dynamic
+ * device mappings through pmb_remap() can still be bolted on
+ * after this.
+ */
+ ret = pmb_apply_legacy_mappings();
+ if (ret == 0) {
+ back_to_cached();
+ return 0;
+ }
+
+ /*
+ * 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.
+ */
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);
+ data = __raw_readl(addr);
if (!(data & PMB_V))
continue;
data &= ~(PMB_C | PMB_WT);
#endif
}
- ctrl_outl(data, addr);
+ __raw_writel(data, addr);
ppn = data & PMB_PFN_MASK;
flags |= data & PMB_SZ_MASK;
addr = PMB_ADDR + (i << PMB_E_SHIFT);
- data = ctrl_inl(addr);
+ data = __raw_readl(addr);
vpn = data & PMB_PFN_MASK;
WARN_ON(IS_ERR(pmbe));
}
+ __raw_writel(0, PMB_IRMCR);
+
+ /* Flush out the TLB */
+ i = __raw_readl(MMUCR);
+ i |= MMUCR_TI;
+ __raw_writel(i, MMUCR);
+
back_to_cached();
return 0;
}
-#endif /* CONFIG_PMB */
+
+bool __in_29bit_mode(void)
+{
+ return (__raw_readl(PMB_PASCR) & PASCR_SE) == 0;
+}
static int pmb_seq_show(struct seq_file *file, void *iter)
{
unsigned int size;
char *sz_str = NULL;
- addr = ctrl_inl(mk_pmb_addr(i));
- data = ctrl_inl(mk_pmb_data(i));
+ addr = __raw_readl(mk_pmb_addr(i));
+ data = __raw_readl(mk_pmb_data(i));
size = data & PMB_SZ_MASK;
sz_str = (size == PMB_SZ_16M) ? " 16MB":
{
return sysdev_driver_register(&cpu_sysdev_class, &pmb_sysdev_driver);
}
-
subsys_initcall(pmb_sysdev_init);
#endif