mpc86xx: set the DDR BATs after calculating true DDR size
authorTimur Tabi <timur@freescale.com>
Mon, 29 Mar 2010 17:51:07 +0000 (12:51 -0500)
committerKumar Gala <galak@kernel.crashing.org>
Tue, 30 Mar 2010 15:50:22 +0000 (10:50 -0500)
After determining how much DDR is actually in the system, set DBAT0 and
IBAT0 accordingly.  This ensures that the CPU won't attempt to access
(via speculation) addresses outside of actual memory.

On 86xx systems, DBAT0 and IBAT0 (the BATs for DDR) are initialized to 2GB
and kept that way.  If the system has less than 2GB of memory (typical for
an MPC8610 HPCD), the CPU may attempt to access this memory during
speculation.  The zlib code is notorious for generating such memory reads,
and indeed on the MPC8610, uncompressing the Linux kernel causes a machine
check (without this patch).

Currently we are limited to power of two sized DDR since we only use a
single bat.  If a non-power of two size is used that is less than
CONFIG_MAX_MEM_MAPPED u-boot will crash.

Signed-off-by: Timur Tabi <timur@freescale.com>
Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
board/freescale/mpc8610hpcd/mpc8610hpcd.c
board/freescale/mpc8641hpcn/mpc8641hpcn.c
cpu/mpc86xx/cpu.c
cpu/mpc86xx/cpu_init.c
include/asm-ppc/mmu.h
include/configs/MPC8610HPCD.h
include/configs/MPC8641HPCN.h
include/mpc86xx.h

index 784a2ed686d28979cef48b8db52ad58e8eecd6ee..ab5f800453b6043a42ee86df90ec8b5502a3994c 100644 (file)
@@ -127,6 +127,8 @@ initdram(int board_type)
        dram_size = fixed_sdram();
 #endif
 
+       setup_ddr_bat(dram_size);
+
        puts(" DDR: ");
        return dram_size;
 }
index c521527d890b4a27264dfbfdf73ac9f718bb0e3b..443c9fd8ec4f036695f77f920d3fd170d19b8fe1 100644 (file)
@@ -74,6 +74,8 @@ initdram(int board_type)
        dram_size = fixed_sdram();
 #endif
 
+       setup_ddr_bat(dram_size);
+
        puts("    DDR: ");
        return dram_size;
 }
index f7e012db573cc0f795291f32dd3b2b9fae0c89c3..188757587f5272ed246cdf55e7bebf63b209c7a8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2006,2009 Freescale Semiconductor, Inc.
+ * Copyright 2006,2009-2010 Freescale Semiconductor, Inc.
  * Jeff Brown
  * Srikanth Srinivasan (srikanth.srinivasan@freescale.com)
  *
@@ -197,3 +197,37 @@ void mpc86xx_reginfo(void)
        printf("\tBR7\t0x%08X\tOR7\t0x%08X \n", in_be32(&lbc->br7), in_be32(&lbc->or7));
 
 }
+
+/*
+ * Set the DDR BATs to reflect the actual size of DDR.
+ *
+ * dram_size is the actual size of DDR, in bytes
+ *
+ * Note: we assume that CONFIG_MAX_MEM_MAPPED is 2G or smaller as we only
+ * are using a single BAT to cover DDR.
+ *
+ * If this is not true, (e.g. CONFIG_MAX_MEM_MAPPED is 2GB but HID0_XBSEN
+ * is not defined) then we might have a situation where U-Boot will attempt
+ * to relocated itself outside of the region mapped by DBAT0.
+ * This will cause a machine check.
+ *
+ * Currently we are limited to power of two sized DDR since we only use a
+ * single bat.  If a non-power of two size is used that is less than
+ * CONFIG_MAX_MEM_MAPPED u-boot will crash.
+ *
+ */
+void setup_ddr_bat(phys_addr_t dram_size)
+{
+       unsigned long batu, bl;
+
+       bl = TO_BATU_BL(min(dram_size, CONFIG_MAX_MEM_MAPPED));
+
+       if (BATU_SIZE(bl) != dram_size) {
+               u64 sz = (u64)dram_size - BATU_SIZE(bl);
+               print_size(sz, " left unmapped\n");
+       }
+
+       batu = bl | BATU_VS | BATU_VP;
+       write_bat(DBAT0, batu, CONFIG_SYS_DBAT0L);
+       write_bat(IBAT0, batu, CONFIG_SYS_IBAT0L);
+}
index 5a78a9cdc7458a769f39be1d0efd284b41cb0062..b4f047d85d071707289958cb35d84848a255967b 100644 (file)
@@ -138,8 +138,12 @@ int cpu_init_r(void)
 /* Set up BAT registers */
 void setup_bats(void)
 {
+#if defined(CONFIG_SYS_DBAT0U) && defined(CONFIG_SYS_DBAT0L)
        write_bat(DBAT0, CONFIG_SYS_DBAT0U, CONFIG_SYS_DBAT0L);
+#endif
+#if defined(CONFIG_SYS_IBAT0U) && defined(CONFIG_SYS_IBAT0L)
        write_bat(IBAT0, CONFIG_SYS_IBAT0U, CONFIG_SYS_IBAT0L);
+#endif
        write_bat(DBAT1, CONFIG_SYS_DBAT1U, CONFIG_SYS_DBAT1L);
        write_bat(IBAT1, CONFIG_SYS_IBAT1U, CONFIG_SYS_IBAT1L);
        write_bat(DBAT2, CONFIG_SYS_DBAT2U, CONFIG_SYS_DBAT2L);
index fd1024947d94e58e3725f4505198a142fd357e3f..ce7f0810051d67daea5b2a26eeba282c34b71f59 100644 (file)
@@ -213,7 +213,11 @@ extern void print_bats(void);
 #define BATL_PADDR(x) ((phys_addr_t)((x & 0xfffe0000)          \
                                     | ((x & 0x0e00ULL) << 24)  \
                                     | ((x & 0x04ULL) << 30)))
-#define BATU_SIZE(x) (1UL << (fls((x & BATU_BL_MAX) >> 2) + 17))
+#define BATU_SIZE(x) (1ULL << (fls((x & BATU_BL_MAX) >> 2) + 17))
+
+/* bytes into BATU_BL */
+#define TO_BATU_BL(x) \
+       (u32)((((1ull << __ilog2_u64((u64)x)) / (128 * 1024)) - 1) * 4)
 
 /* Used to set up SDR1 register */
 #define HASH_TABLE_SIZE_64K    0x00010000
index 1d2d659239f24851bbb92272e750907e8f8f3aa7..fed441eb37c4914ea6a92b896ef845b2811a47a8 100644 (file)
  * BAT0                2G      Cacheable, non-guarded
  * 0x0000_0000 2G      DDR
  */
-#define CONFIG_SYS_DBAT0L      (BATL_PP_RW | BATL_MEMCOHERENCE)
-#define CONFIG_SYS_DBAT0U      (BATU_BL_2G | BATU_VS | BATU_VP)
-#define CONFIG_SYS_IBAT0L      (BATL_PP_RW | BATL_MEMCOHERENCE )
-#define CONFIG_SYS_IBAT0U      CONFIG_SYS_DBAT0U
+#define CONFIG_SYS_DBAT0L      (BATL_PP_RW)
+#define CONFIG_SYS_IBAT0L      (BATL_PP_RW)
 
 /*
  * BAT1                1G      Cache-inhibited, guarded
index 12a8f603900f85a4407518075ffa410aba06e4c8..94e4d243e86903ff5e74ae7208ad7b7157759ee7 100644 (file)
@@ -482,9 +482,7 @@ extern unsigned long get_board_sys_clk(unsigned long dummy);
  * BAT0                DDR
  */
 #define CONFIG_SYS_DBAT0L      (BATL_PP_RW | BATL_MEMCOHERENCE)
-#define CONFIG_SYS_DBAT0U      (BATU_BL_2G | BATU_VS | BATU_VP)
-#define CONFIG_SYS_IBAT0L      (BATL_PP_RW | BATL_MEMCOHERENCE )
-#define CONFIG_SYS_IBAT0U      CONFIG_SYS_DBAT0U
+#define CONFIG_SYS_IBAT0L      (BATL_PP_RW | BATL_MEMCOHERENCE)
 
 /*
  * BAT1                LBC (PIXIS/CF)
index c6f30f9fd5a7dc91250712e7529f47d817f9c74b..eb85d60cad1bfa3688d70adbaa446a44e0497b6c 100644 (file)
@@ -83,5 +83,7 @@ static __inline__ unsigned long get_l2cr (void)
    return l2cr_val;
 }
 
+void setup_ddr_bat(phys_addr_t dram_size);
+
 #endif  /* _ASMLANGUAGE */
 #endif /* __MPC86xx_H__ */