aboutsummaryrefslogtreecommitdiffstats
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 @@
3 * 3 *
4 * Privileged Space Mapping Buffer (PMB) Support. 4 * Privileged Space Mapping Buffer (PMB) Support.
5 * 5 *
6 * Copyright (C) 2005 - 2010 Paul Mundt 6 * Copyright (C) 2005 - 2010 Paul Mundt
7 * 7 * Copyright (C) 2010 Matt Fleming
8 * P1/P2 Section mapping definitions from map32.h, which was:
9 *
10 * Copyright 2003 (c) Lineo Solutions,Inc.
11 * 8 *
12 * This file is subject to the terms and conditions of the GNU General Public 9 * This file is subject to the terms and conditions of the GNU General Public
13 * License. See the file "COPYING" in the main directory of this archive 10 * License. See the file "COPYING" in the main directory of this archive
@@ -280,46 +277,82 @@ static void __pmb_unmap(struct pmb_entry *pmbe)
280} 277}
281 278
282#ifdef CONFIG_PMB_LEGACY 279#ifdef CONFIG_PMB_LEGACY
280static inline unsigned int pmb_ppn_in_range(unsigned long ppn)
281{
282 return ppn >= __MEMORY_START && ppn < __MEMORY_START + __MEMORY_SIZE;
283}
284
283static int pmb_apply_legacy_mappings(void) 285static int pmb_apply_legacy_mappings(void)
284{ 286{
285 int i;
286 unsigned long addr, data;
287 unsigned int applied = 0; 287 unsigned int applied = 0;
288 int i;
288 289
289 for (i = 0; i < PMB_ENTRY_MAX; i++) { 290 pr_info("PMB: Preserving legacy mappings:\n");
290 struct pmb_entry *pmbe;
291 unsigned long vpn, ppn, flags;
292
293 addr = PMB_DATA + (i << PMB_E_SHIFT);
294 data = ctrl_inl(addr);
295 if (!(data & PMB_V))
296 continue;
297 291
298 if (data & PMB_C) { 292 /*
299#if defined(CONFIG_CACHE_WRITETHROUGH) 293 * The following entries are setup by the bootloader.
300 data |= PMB_WT; 294 *
301#elif defined(CONFIG_CACHE_WRITEBACK) 295 * Entry VPN PPN V SZ C UB
302 data &= ~PMB_WT; 296 * --------------------------------------------------------
303#else 297 * 0 0xA0000000 0x00000000 1 64MB 0 0
304 data &= ~(PMB_C | PMB_WT); 298 * 1 0xA4000000 0x04000000 1 16MB 0 0
305#endif 299 * 2 0xA6000000 0x08000000 1 16MB 0 0
306 } 300 * 9 0x88000000 0x48000000 1 128MB 1 1
307 ctrl_outl(data, addr); 301 * 10 0x90000000 0x50000000 1 128MB 1 1
308 302 * 11 0x98000000 0x58000000 1 128MB 1 1
309 ppn = data & PMB_PFN_MASK; 303 * 13 0xA8000000 0x48000000 1 128MB 0 0
304 * 14 0xB0000000 0x50000000 1 128MB 0 0
305 * 15 0xB8000000 0x58000000 1 128MB 0 0
306 *
307 * The only entries the we need are the ones that map the kernel
308 * at the cached and uncached addresses.
309 */
310 for (i = 0; i < PMB_ENTRY_MAX; i++) {
311 unsigned long addr, data;
312 unsigned long addr_val, data_val;
313 unsigned long ppn, vpn;
310 314
311 flags = data & (PMB_C | PMB_WT | PMB_UB); 315 addr = mk_pmb_addr(i);
312 flags |= data & PMB_SZ_MASK; 316 data = mk_pmb_data(i);
313 317
314 addr = PMB_ADDR + (i << PMB_E_SHIFT); 318 addr_val = __raw_readl(addr);
315 data = ctrl_inl(addr); 319 data_val = __raw_readl(data);
316 320
317 vpn = data & PMB_PFN_MASK; 321 /*
322 * Skip over any bogus entries
323 */
324 if (!(data_val & PMB_V) || !(addr_val & PMB_V))
325 continue;
318 326
319 pmbe = pmb_alloc(vpn, ppn, flags, i); 327 ppn = data_val & PMB_PFN_MASK;
320 WARN_ON(IS_ERR(pmbe)); 328 vpn = addr_val & PMB_PFN_MASK;
321 329
322 applied++; 330 /*
331 * Only preserve in-range mappings.
332 */
333 if (pmb_ppn_in_range(ppn)) {
334 unsigned int size;
335 char *sz_str = NULL;
336
337 size = data_val & PMB_SZ_MASK;
338
339 sz_str = (size == PMB_SZ_16M) ? " 16MB":
340 (size == PMB_SZ_64M) ? " 64MB":
341 (size == PMB_SZ_128M) ? "128MB":
342 "512MB";
343
344 pr_info("\t0x%08lx -> 0x%08lx [ %s %scached ]\n",
345 vpn >> PAGE_SHIFT, ppn >> PAGE_SHIFT, sz_str,
346 (data_val & PMB_C) ? "" : "un");
347
348 applied++;
349 } else {
350 /*
351 * Invalidate anything out of bounds.
352 */
353 __raw_writel(addr_val & ~PMB_V, addr);
354 __raw_writel(data_val & ~PMB_V, data);
355 }
323 } 356 }
324 357
325 return (applied == 0); 358 return (applied == 0);
@@ -333,8 +366,9 @@ static inline int pmb_apply_legacy_mappings(void)
333 366
334int __uses_jump_to_uncached pmb_init(void) 367int __uses_jump_to_uncached pmb_init(void)
335{ 368{
336 unsigned int i; 369 int i;
337 unsigned long size, ret; 370 unsigned long addr, data;
371 unsigned long ret;
338 372
339 jump_to_uncached(); 373 jump_to_uncached();
340 374
@@ -352,25 +386,45 @@ int __uses_jump_to_uncached pmb_init(void)
352 } 386 }
353 387
354 /* 388 /*
355 * Insert PMB entries for the P1 and P2 areas so that, after 389 * Sync our software copy of the PMB mappings with those in
356 * we've switched the MMU to 32-bit mode, the semantics of P1 390 * hardware. The mappings in the hardware PMB were either set up
357 * and P2 are the same as in 29-bit mode, e.g. 391 * by the bootloader or very early on by the kernel.
358 *
359 * P1 - provides a cached window onto physical memory
360 * P2 - provides an uncached window onto physical memory
361 */ 392 */
362 size = (unsigned long)__MEMORY_START + __MEMORY_SIZE; 393 for (i = 0; i < PMB_ENTRY_MAX; i++) {
394 struct pmb_entry *pmbe;
395 unsigned long vpn, ppn, flags;
363 396
364 ret = pmb_remap(P1SEG, 0x00000000, size, PMB_C); 397 addr = PMB_DATA + (i << PMB_E_SHIFT);
365 BUG_ON(ret != size); 398 data = ctrl_inl(addr);
399 if (!(data & PMB_V))
400 continue;
366 401
367 ret = pmb_remap(P2SEG, 0x00000000, size, PMB_WT | PMB_UB); 402 if (data & PMB_C) {
368 BUG_ON(ret != size); 403#if defined(CONFIG_CACHE_WRITETHROUGH)
404 data |= PMB_WT;
405#elif defined(CONFIG_CACHE_WRITEBACK)
406 data &= ~PMB_WT;
407#else
408 data &= ~(PMB_C | PMB_WT);
409#endif
410 }
411 ctrl_outl(data, addr);
369 412
370 ctrl_outl(0, PMB_IRMCR); 413 ppn = data & PMB_PFN_MASK;
414
415 flags = data & (PMB_C | PMB_WT | PMB_UB);
416 flags |= data & PMB_SZ_MASK;
371 417
372 /* PMB.SE and UB[7] */ 418 addr = PMB_ADDR + (i << PMB_E_SHIFT);
373 ctrl_outl(PASCR_SE | (1 << 7), PMB_PASCR); 419 data = ctrl_inl(addr);
420
421 vpn = data & PMB_PFN_MASK;
422
423 pmbe = pmb_alloc(vpn, ppn, flags, i);
424 WARN_ON(IS_ERR(pmbe));
425 }
426
427 ctrl_outl(0, PMB_IRMCR);
374 428
375 /* Flush out the TLB */ 429 /* Flush out the TLB */
376 i = ctrl_inl(MMUCR); 430 i = ctrl_inl(MMUCR);