sh: Support fixed 32-bit PMB mappings from bootloader.
authorYoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
Tue, 10 Mar 2009 06:49:54 +0000 (15:49 +0900)
committerPaul Mundt <lethal@linux-sh.org>
Tue, 10 Mar 2009 06:49:54 +0000 (15:49 +0900)
This provides a method for supporting fixed PMB mappings inherited from
the bootloader, as an alternative to the dynamic PMB mapping currently
used by the kernel. In the future these methods will be combined.

P1/P2 area is handled like a regular 29-bit physical address, and local
bus device are assigned P3 area addresses.

Signed-off-by: Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
arch/sh/boot/Makefile
arch/sh/include/asm/addrspace.h
arch/sh/include/asm/io.h
arch/sh/include/asm/page.h
arch/sh/kernel/vmlinux_32.lds.S
arch/sh/mm/Kconfig
arch/sh/mm/Makefile_32
arch/sh/mm/ioremap_32.c
arch/sh/mm/pmb-fixed.c [new file with mode: 0644]

index c16ccd4..95483d1 100644 (file)
@@ -33,20 +33,24 @@ $(obj)/zImage: $(obj)/compressed/vmlinux FORCE
 $(obj)/compressed/vmlinux: FORCE
        $(Q)$(MAKE) $(build)=$(obj)/compressed $@
 
-ifeq ($(CONFIG_32BIT),y)
-KERNEL_LOAD    := $(shell /bin/bash -c 'printf "0x%08x" \
-                    $$[$(CONFIG_PAGE_OFFSET)  + \
-                       $(CONFIG_ZERO_PAGE_OFFSET)]')
-else
+KERNEL_MEMORY := 0x00000000
+ifeq ($(CONFIG_PMB_FIXED),y)
+KERNEL_MEMORY := $(shell /bin/bash -c 'printf "0x%08x" \
+                    $$[$(CONFIG_MEMORY_START) & 0x1fffffff]')
+endif
+ifeq ($(CONFIG_29BIT),y)
+KERNEL_MEMORY := $(shell /bin/bash -c 'printf "0x%08x" \
+                    $$[$(CONFIG_MEMORY_START)]')
+endif
+
 KERNEL_LOAD    := $(shell /bin/bash -c 'printf "0x%08x" \
                     $$[$(CONFIG_PAGE_OFFSET)  + \
-                       $(CONFIG_MEMORY_START) + \
+                       $(KERNEL_MEMORY) + \
                        $(CONFIG_ZERO_PAGE_OFFSET)]')
-endif
 
 KERNEL_ENTRY   := $(shell /bin/bash -c 'printf "0x%08x" \
                     $$[$(CONFIG_PAGE_OFFSET)  + \
-                       $(CONFIG_MEMORY_START) + \
+                       $(KERNEL_MEMORY) + \
                        $(CONFIG_ZERO_PAGE_OFFSET) + $(CONFIG_ENTRY_OFFSET)]')
 
 quiet_cmd_uimage = UIMAGE  $@
index 36736c7..80d4081 100644 (file)
@@ -31,7 +31,7 @@
 /* Returns the physical address of a PnSEG (n=1,2) address   */
 #define PHYSADDR(a)    (((unsigned long)(a)) & 0x1fffffff)
 
-#ifdef CONFIG_29BIT
+#if defined(CONFIG_29BIT) || defined(CONFIG_PMB_FIXED)
 /*
  * Map an address to a certain privileged segment
  */
@@ -43,7 +43,7 @@
        ((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) | P3SEG))
 #define P4SEGADDR(a)   \
        ((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) | P4SEG))
-#endif /* 29BIT */
+#endif /* 29BIT || PMB_FIXED */
 #endif /* P1SEG */
 
 /* Check if an address can be reached in 29 bits */
index 61f6dae..0454f8d 100644 (file)
@@ -238,7 +238,7 @@ extern void onchip_unmap(unsigned long vaddr);
 static inline void __iomem *
 __ioremap_mode(unsigned long offset, unsigned long size, unsigned long flags)
 {
-#ifdef CONFIG_SUPERH32
+#if defined(CONFIG_SUPERH32) && !defined(CONFIG_PMB_FIXED)
        unsigned long last_addr = offset + size - 1;
 #endif
        void __iomem *ret;
@@ -247,7 +247,7 @@ __ioremap_mode(unsigned long offset, unsigned long size, unsigned long flags)
        if (ret)
                return ret;
 
-#ifdef CONFIG_SUPERH32
+#if defined(CONFIG_SUPERH32) && !defined(CONFIG_PMB_FIXED)
        /*
         * For P1 and P2 space this is trivial, as everything is already
         * mapped. Uncached access for P1 addresses are done through P2.
index 5871d78..9c6d21e 100644 (file)
@@ -129,7 +129,12 @@ typedef struct page *pgtable_t;
  * is not visible (it is part of the PMB mapping) and so needs to be
  * added or subtracted as required.
  */
-#ifdef CONFIG_32BIT
+#if defined(CONFIG_PMB_FIXED)
+/* phys = virt - PAGE_OFFSET - (__MEMORY_START & 0xe0000000) */
+#define PMB_OFFSET     (PAGE_OFFSET - PXSEG(__MEMORY_START))
+#define __pa(x)        ((unsigned long)(x) - PMB_OFFSET)
+#define __va(x)        ((void *)((unsigned long)(x) + PMB_OFFSET))
+#elif defined(CONFIG_32BIT)
 #define __pa(x)        ((unsigned long)(x)-PAGE_OFFSET+__MEMORY_START)
 #define __va(x)        ((void *)((unsigned long)(x)+PAGE_OFFSET-__MEMORY_START))
 #else
index 7b4b82b..d0b2a71 100644 (file)
@@ -15,7 +15,10 @@ OUTPUT_ARCH(sh)
 ENTRY(_start)
 SECTIONS
 {
-#ifdef CONFIG_32BIT
+#ifdef CONFIG_PMB_FIXED
+       . = CONFIG_PAGE_OFFSET + (CONFIG_MEMORY_START & 0x1fffffff) +
+           CONFIG_ZERO_PAGE_OFFSET;
+#elif defined(CONFIG_32BIT)
        . = CONFIG_PAGE_OFFSET + CONFIG_ZERO_PAGE_OFFSET;
 #else
        . = CONFIG_PAGE_OFFSET + CONFIG_MEMORY_START + CONFIG_ZERO_PAGE_OFFSET;
index 555ec97..10c2435 100644 (file)
@@ -57,7 +57,7 @@ config 32BIT
        bool
        default y if CPU_SH5
 
-config PMB
+config PMB_ENABLE
        bool "Support 32-bit physical addressing through PMB"
        depends on MMU && EXPERIMENTAL && (CPU_SUBTYPE_SH7780 || CPU_SUBTYPE_SH7785)
        select 32BIT
@@ -67,6 +67,33 @@ config PMB
          32-bits through the SH-4A PMB. If this is not set, legacy
          29-bit physical addressing will be used.
 
+choice
+       prompt "PMB handling type"
+       depends on PMB_ENABLE
+       default PMB_FIXED
+
+config PMB
+       bool "PMB"
+       depends on MMU && EXPERIMENTAL && (CPU_SUBTYPE_SH7780 || CPU_SUBTYPE_SH7785)
+       select 32BIT
+       help
+         If you say Y here, physical addressing will be extended to
+         32-bits through the SH-4A PMB. If this is not set, legacy
+         29-bit physical addressing will be used.
+
+config PMB_FIXED
+       bool "fixed PMB"
+       depends on MMU && EXPERIMENTAL && (CPU_SUBTYPE_SH7780 || \
+                                          CPU_SUBTYPE_SH7785)
+       select 32BIT
+       help
+         If this option is enabled, fixed PMB mappings are inherited
+         from the boot loader, and the kernel does not attempt dynamic
+         management. This is the closest to legacy 29-bit physical mode,
+         and allows systems to support up to 512MiB of system memory.
+
+endchoice
+
 config X2TLB
        bool "Enable extended TLB mode"
        depends on (CPU_SHX2 || CPU_SHX3) && MMU && EXPERIMENTAL
index cb2f3f2..469ff16 100644 (file)
@@ -35,6 +35,7 @@ endif
 
 obj-$(CONFIG_HUGETLB_PAGE)     += hugetlbpage.o
 obj-$(CONFIG_PMB)              += pmb.o
+obj-$(CONFIG_PMB_FIXED)                += pmb-fixed.o
 obj-$(CONFIG_NUMA)             += numa.o
 
 EXTRA_CFLAGS += -Werror
index 8dc7702..60cc486 100644 (file)
@@ -59,11 +59,13 @@ void __iomem *__ioremap(unsigned long phys_addr, unsigned long size,
        if (is_pci_memaddr(phys_addr) && is_pci_memaddr(last_addr))
                return (void __iomem *)phys_addr;
 
+#if !defined(CONFIG_PMB_FIXED)
        /*
         * Don't allow anybody to remap normal RAM that we're using..
         */
        if (phys_addr < virt_to_phys(high_memory))
                return NULL;
+#endif
 
        /*
         * Mappings have to be page-aligned
@@ -81,7 +83,7 @@ void __iomem *__ioremap(unsigned long phys_addr, unsigned long size,
        area->phys_addr = phys_addr;
        orig_addr = addr = (unsigned long)area->addr;
 
-#ifdef CONFIG_32BIT
+#ifdef CONFIG_PMB
        /*
         * First try to remap through the PMB once a valid VMA has been
         * established. Smaller allocations (or the rest of the size
@@ -122,7 +124,7 @@ void __iounmap(void __iomem *addr)
        if (seg < P3SEG || vaddr >= P3_ADDR_MAX || is_pci_memaddr(vaddr))
                return;
 
-#ifdef CONFIG_32BIT
+#ifdef CONFIG_PMB
        /*
         * Purge any PMB entries that may have been established for this
         * mapping, then proceed with conventional VMA teardown.
diff --git a/arch/sh/mm/pmb-fixed.c b/arch/sh/mm/pmb-fixed.c
new file mode 100644 (file)
index 0000000..43c8eac
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * arch/sh/mm/fixed_pmb.c
+ *
+ * Copyright (C) 2009  Renesas Solutions Corp.
+ *
+ * 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/init.h>
+#include <linux/mm.h>
+#include <linux/io.h>
+#include <asm/mmu.h>
+#include <asm/mmu_context.h>
+
+static int __uses_jump_to_uncached fixed_pmb_init(void)
+{
+       int i;
+       unsigned long addr, data;
+
+       jump_to_uncached();
+
+       for (i = 0; i < PMB_ENTRY_MAX; i++) {
+               addr = PMB_DATA + (i << PMB_E_SHIFT);
+               data = ctrl_inl(addr);
+               if (!(data & PMB_V))
+                       continue;
+
+               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);
+       }
+
+       back_to_cached();
+
+       return 0;
+}
+arch_initcall(fixed_pmb_init);