$(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  $@
 
 /* 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
  */
        ((__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 */
 
 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;
        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.
 
  * 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
 
 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;
 
        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
          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
 
 
 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
 
        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
        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
        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.
 
--- /dev/null
+/*
+ * 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);