diff options
Diffstat (limited to 'arch/sh/mm')
-rw-r--r-- | arch/sh/mm/pmb.c | 156 |
1 files changed, 105 insertions, 51 deletions
diff --git a/arch/sh/mm/pmb.c b/arch/sh/mm/pmb.c index 8f7dbf183fb..b796b6c021b 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); |