[coreboot] Patch set updated for coreboot: f310fd0 armv7/exynos/snow: set up caches properly
David Hendricks (dhendrix@chromium.org)
gerrit at coreboot.org
Sat Mar 16 04:44:56 CET 2013
David Hendricks (dhendrix at chromium.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/2729
-gerrit
commit f310fd07028a0f6011dd3834786eab74a80409ca
Author: David Hendricks <dhendrix at chromium.org>
Date: Thu Mar 14 15:24:57 2013 -0700
armv7/exynos/snow: set up caches properly
** do not submit **
This (hopefully) sets up caches more carefully than we were doing
before. This patch needs a bit more testing before going in.
TODO:
- Clean up. Most of this is now done in a generic manner in
bootblock_simple, so a lot of earlier code can go away.
- Set cache policy and enable caches.
- Replace imported cache routines with BSD-licensed version?
Change-Id: I7390981190e3213f4e1431f8e56746545c5cc7c9
Signed-off-by: David Hendricks <dhendrix at chromium.org>
---
src/arch/armv7/bootblock_simple.c | 245 ++++++++++++++++++++++++++++++
src/arch/armv7/include/system.h | 16 ++
src/arch/armv7/lib/Makefile.inc | 1 +
src/arch/armv7/lib/cache-cp15.c | 3 +-
src/arch/armv7/lib/cache_v7.c | 2 +-
src/cpu/samsung/exynos5250/Makefile.inc | 1 -
src/cpu/samsung/exynos5250/bootblock.c | 30 ++++
src/cpu/samsung/exynos5250/exynos_cache.c | 8 +-
src/mainboard/google/snow/ramstage.c | 15 --
src/mainboard/google/snow/romstage.c | 45 +++---
10 files changed, 317 insertions(+), 49 deletions(-)
diff --git a/src/arch/armv7/bootblock_simple.c b/src/arch/armv7/bootblock_simple.c
index 0132b87..364209f 100644
--- a/src/arch/armv7/bootblock_simple.c
+++ b/src/arch/armv7/bootblock_simple.c
@@ -24,9 +24,245 @@
#include <arch/stages.h>
#include <cbfs.h>
#include <console/console.h>
+#include <lib.h>
+#include <system.h>
#include "stages.c"
+/*
+ * Set/clear program flow prediction and return the previous state.
+ */
+static int config_branch_prediction(int set_cr_z)
+{
+ unsigned int cr;
+
+ /* System Control Register: 11th bit Z Branch prediction enable */
+ cr = get_cr();
+ set_cr(set_cr_z ? cr | CR_Z : cr & ~CR_Z);
+
+ return cr & CR_Z;
+}
+
+#if 0
+/* Cache and MMU init */
+static void armv7_invalidate_caches(void)
+{
+ unsigned int cr;
+
+ /*
+ * From Cortex-A Series Programmers guide (Example 15-3):
+ * 1. Disable MMU
+ * 2. Disable L1 caches (example disables i-cache then d-cache)
+ * 3. Invalidate L1 caches (same order)
+ * 4. Invalidate TLB
+ *
+ * L2 cache setup will be done by SoC-specific code. MMU setup
+ * needs to be done after DRAM init in board-specific code.
+ */
+
+ /* Disable MMU */
+ cr = get_cr();
+ cr &= ~CR_M;
+ set_cr(cr);
+
+ /* Disable L1 caches */
+ icache_disable();
+ dcache_disable();
+
+ /* Invalidate caches */
+ invalidate_icache_all();
+ invalidate_dcache_all();
+
+ /* Invalidate TLB */
+ v7_inval_tlb();
+}
+#endif
+
+static inline uint32_t read_clidr(void)
+{
+ uint32_t val = 0;
+ asm volatile ("mrc p15, 1, %0, c0, c0, 1" : "=r" (val));
+ return val;
+}
+
+static inline uint32_t read_ccsidr(void)
+{
+ uint32_t val = 0;
+ asm volatile ("mrc p15, 1, %0, c0, c0, 0" : "=r" (val));
+ return val;
+}
+
+static inline uint32_t read_csselr(void)
+{
+ uint32_t val = 0;
+ asm volatile ("mrc p15, 2, %0, c0, c0, 0" : "=r" (val));
+ return val;
+}
+
+/* Write to Cache Size Selection Register (CSSELR) */
+static inline void write_csselr(uint32_t val)
+{
+ /*
+ * Bits [3:1] - Cache level + 1 (0b000 = L1, 0b110 = L7, 0b111 is rsvd)
+ * Bit 0 - 0 = data or unified cache, 1 = instruction cache
+ */
+ asm volatile ("mcr p15, 2, %0, c0, c0, 0" : : "r" (val));
+ /* Note: Do an ISB if doing CCSIDR after this */
+}
+
+/* Instruction cache invalidate all by PoU */
+static inline void iciallu(void)
+{
+ asm volatile ("mcr p15, 0, %0, c7, c5, 0" : : "r" (0));
+}
+
+/* Data cache invalidate all by set/way */
+static inline void dcisw(uint32_t val)
+{
+ asm volatile ("mcr p15, 0, %0, c7, c6, 0" : : "r" (val));
+}
+
+static void clear_icache(unsigned int level)
+{
+ uint32_t ccselr;
+
+ ccselr = (level << 1) | 1;
+ write_csselr(&ccselr);
+
+ /* icache can be entirely invalidated with one operation.
+ * Note: If branch predictors are architecturally-visible, ICIALLU
+ * also performs a BPIALL operation (B2-1283 in arch manual)
+ */
+ iciallu();
+ isb();
+}
+
+#ifndef __mask
+# define __mask(high, low) ((1UL << (high)) + \
+ (((1UL << (high)) - 1) - ((1UL << (low)) - 1)))
+#endif
+
+static void clear_dcache(unsigned int level)
+{
+ uint32_t ccsidr, ccselr;
+ unsigned int associativity, num_sets, linesize;
+ unsigned int set, way;
+
+ ccselr = level << 1;
+ write_csselr(&ccselr);
+ isb(); /* ISB to sync the change to the CCSIDR */
+
+ /*
+ * dcache must be invalidated by set/way for portability since virtual
+ * memory mapping is SoC-defined. The number of sets and associativity
+ * is given by CCSIDR. We'll use DCISW to invalidate the dcache.
+ */
+ read_ccsidr(&ccsidr);
+ /* FIXME: Round to the nearest power-of-2 (if necessary) */
+ num_sets = ((ccsidr & __mask(27, 13)) >> 13) + 1;
+ associativity = ((ccsidr & __mask(12, 3)) >> 3) + 1;
+ linesize = 2 << ((ccsidr & 0x7) + 2);
+
+ /*
+ * Set/way operations require an interesting bit packing. See section
+ * B4-35 in the ARMv7 Architecture Reference Manual:
+ *
+ * A: Log2(associativity)
+ * B: L+S
+ * L: Log2(linesize)
+ * S: Log2(num_sets)
+ *
+ * The bits are packed as follows:
+ * 31 31-A B-1 L-1 4 3 2 1 0
+ * |---|-------------|--------|-------|-|-|-|-|
+ * |Way| zeros | Set | zeros |level|0|
+ * |---|-------------|--------|-------|-|-|-|-|
+ */
+ for (way = 0; way < assoc; way++) {
+ for (set = 0; set < num_sets; set++) {
+ uint32_t val = 0;
+ val |= way << (32 - log2(associativity));
+ val |= set << log2(linesize);
+ val |= level << 1;
+ dcisw(val);
+ }
+ }
+
+}
+
+static void armv7_disable_and_flush_caches(void)
+{
+ uint32_t sctlr, clidr, ccsidr;
+ unsigned int associatvity, num_sets;
+ int level;
+
+ /*
+ * From Cortex-A Series Programmers guide (Example 15-3):
+ * 1. Disable MMU
+ * 2. Disable L1 caches (example disables i-cache then d-cache)
+ * 3. Invalidate L1 caches (same order)
+ * 4. Invalidate TLB
+ *
+ * L2 cache setup will be done by SoC-specific code. MMU setup
+ * needs to be done after DRAM init in board-specific code.
+ */
+
+ /* Globally disable MMU, caches, and branch prediction (these should
+ * be disabled by default on reset) */
+ sctlr = get_cr();
+ sctlr &= ~(CR_M | CR_C | CR_Z | CR_I);
+ set_cr(sctlr);
+
+ /* Invalidate branch predictor */
+ /* bpiall(); */
+
+ /*
+ * Iterate thru each eache identified in CLIDR and invalidate.
+ */
+ clidr = get_clidr();
+ for (level = 0; level < 7; level++) {
+ unsigned int ctype = (clidr >> (level * 3)) & 0x7;
+ switch(ctype) {
+ case 0x0:
+ /* no cache */
+ break;
+ case 0x1:
+ /* icache only */
+ clear_icache(level);
+ break;
+ case 0x2:
+ /* dcache only */
+ clear_dcache(level);
+ break;
+ case 0x3:
+ /* separate icache and dcache */
+ clear_icache(level);
+ clear_dcache(level);
+ break;
+ case 0x4:
+ /* unified cache (FIXME: same as dcache only?) */
+ clear_dcache(level);
+ default:
+ /* reserved */
+ break;
+ }
+ }
+
+#if 0
+ /* Disable L1 caches */
+ icache_disable();
+ dcache_disable();
+
+ /* Invalidate caches */
+ invalidate_icache_all();
+ invalidate_dcache_all();
+#endif
+
+ /* Invalidate TLB */
+// v7_inval_tlb();
+ /* dtlbiall(); */
+}
+
static int boot_cpu(void)
{
/*
@@ -42,6 +278,15 @@ void main(void)
const char *stage_name = "fallback/romstage";
void *entry;
+ armv7_invalidate_caches();
+
+ /*
+ * Branch prediction enable happens after cache invalidation. (doesn't need to?)
+ * Note: If booting from USB, we need to disable branch prediction
+ * before copying from USB into RAM (FIXME: why?)
+ */
+ config_branch_prediction(1);
+
if (boot_cpu()) {
bootblock_cpu_init();
bootblock_mainboard_init();
diff --git a/src/arch/armv7/include/system.h b/src/arch/armv7/include/system.h
index 053df8d..9a694ba 100644
--- a/src/arch/armv7/include/system.h
+++ b/src/arch/armv7/include/system.h
@@ -64,6 +64,20 @@ static inline void set_cr(unsigned int val)
isb();
}
+static inline unsigned int get_acr(void)
+{
+ unsigned int val;
+ asm("mrc p15, 0, %0, c1, c0, 1 @ get ACR" : "=r" (val) : : "cc");
+ return val;
+}
+
+static inline void set_acr(unsigned int val)
+{
+ asm volatile("mcr p15, 0, %0, c1, c0, 1 @ set ACR"
+ : : "r" (val) : "cc");
+ isb();
+}
+
/* options available for data cache on each page */
enum dcache_option {
DCACHE_OFF,
@@ -97,6 +111,8 @@ void mmu_page_table_flush(unsigned long start, unsigned long stop);
void mmu_setup(unsigned long start, unsigned long size);
+void v7_inval_tlb(void);
+
void arm_init_before_mmu(void);
/*
diff --git a/src/arch/armv7/lib/Makefile.inc b/src/arch/armv7/lib/Makefile.inc
index 508f776..75e6752 100644
--- a/src/arch/armv7/lib/Makefile.inc
+++ b/src/arch/armv7/lib/Makefile.inc
@@ -14,6 +14,7 @@ ramstage-y += div0.c
#ramstage-y += memcpy.S
#ramstage-y += memset.S
ramstage-y += syslib.c
+ramstage-y += cache-cp15.c
ramstage-y += cache_v7.c
#FIXME(dhendrix): should this be a config option?
diff --git a/src/arch/armv7/lib/cache-cp15.c b/src/arch/armv7/lib/cache-cp15.c
index e08ea57..32f3c79 100644
--- a/src/arch/armv7/lib/cache-cp15.c
+++ b/src/arch/armv7/lib/cache-cp15.c
@@ -123,8 +123,7 @@ inline void mmu_setup(unsigned long start, unsigned long size_mb)
int i;
u32 reg;
- arm_init_before_mmu();
-
+// arm_init_before_mmu();
/* Set up an identity-mapping for all 4GB, rw for everyone */
for (i = 0; i < 4096; i++)
set_section_dcache(i, DCACHE_OFF);
diff --git a/src/arch/armv7/lib/cache_v7.c b/src/arch/armv7/lib/cache_v7.c
index 31072c7..1764351 100644
--- a/src/arch/armv7/lib/cache_v7.c
+++ b/src/arch/armv7/lib/cache_v7.c
@@ -226,7 +226,7 @@ static void v7_dcache_maint_range(u32 start, u32 stop, u32 range_op)
}
/* Invalidate TLB */
-static void v7_inval_tlb(void)
+void v7_inval_tlb(void)
{
/* Invalidate entire unified TLB */
asm volatile ("mcr p15, 0, %0, c8, c7, 0" : : "r" (0));
diff --git a/src/cpu/samsung/exynos5250/Makefile.inc b/src/cpu/samsung/exynos5250/Makefile.inc
index 2774b12..961b719 100644
--- a/src/cpu/samsung/exynos5250/Makefile.inc
+++ b/src/cpu/samsung/exynos5250/Makefile.inc
@@ -30,7 +30,6 @@ ramstage-y += power.c
ramstage-y += soc.c
ramstage-$(CONFIG_CONSOLE_SERIAL_UART) += uart.c
ramstage-y += cpu.c
-ramstage-y += exynos_cache.c
#ramstage-$(CONFIG_SATA_AHCI) += sata.c
diff --git a/src/cpu/samsung/exynos5250/bootblock.c b/src/cpu/samsung/exynos5250/bootblock.c
index 949468f..74817f4 100644
--- a/src/cpu/samsung/exynos5250/bootblock.c
+++ b/src/cpu/samsung/exynos5250/bootblock.c
@@ -17,7 +17,37 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <armv7.h>
+
+/*
+ * cortex_a15_cache_init - Initialize caches for Cortex-A15
+ * L1 cache features:
+ * - 32KB 2-way set associative icache, fixed 64-byte line length.
+ * - 32KB 2-way set associative dcache, fixed 64-byte line length.
+ *
+ * L2 cache features:
+ * - Unified, 16-way set associative, fixed 64-byte line length
+ * - Configurable for 512KB, 1M, 2M, or 4MB sizes (SoC-dependent)
+ *
+ * FIXME: move this elsewhere
+ */
+static void cortex_a15_cache_init(uint32_t dram_start, uint32_t dram_size)
+{
+ /* Disable caches */
+ /* Clean and invalidate caches */
+ /* Set L1 cache parameters */
+ /* Enable L1 cache */
+ /* Set L2 cache parameters */
+ /* Enable L2 cache */
+}
+
void bootblock_cpu_init(void);
void bootblock_cpu_init(void)
{
+ cortex_a15_cache_init();
+
+ /* Enable L2 cache */
+ /* FIXME: maybe do this in romstage along with the other cache
+ * init functions? */
+// v7_outer_cache_enable();
}
diff --git a/src/cpu/samsung/exynos5250/exynos_cache.c b/src/cpu/samsung/exynos5250/exynos_cache.c
index 7f4effe..87eded5 100644
--- a/src/cpu/samsung/exynos5250/exynos_cache.c
+++ b/src/cpu/samsung/exynos5250/exynos_cache.c
@@ -34,15 +34,11 @@ enum l2_cache_params {
};
-/* FIXME(dhendrix): maybe move this to a romstage-specific file? */
-#ifdef __PRE_RAM__
void enable_caches(void)
{
- /* Enable D-cache. I-cache is already enabled in start.S */
- /* can't use it anyway -- it has dependencies we have to fix. */
- //dcache_enable();
+ icache_enable(CONFIG_SYS_SDRAM_BASE, CONFIG_DRAM_SIZE_MB);
+ dcache_enable(CONFIG_SYS_SDRAM_BASE, CONFIG_DRAM_SIZE_MB);
}
-#endif
/*
* Set L2 cache parameters
diff --git a/src/mainboard/google/snow/ramstage.c b/src/mainboard/google/snow/ramstage.c
index e4d53cf..687f9b1 100644
--- a/src/mainboard/google/snow/ramstage.c
+++ b/src/mainboard/google/snow/ramstage.c
@@ -23,22 +23,10 @@
#include <cpu/samsung/exynos5250/clk.h>
#include <cpu/samsung/exynos5250/power.h>
-#include <system.h> /* FIXME: for testing cache */
-static void cp_delay(void)
-{
- volatile int i;
-
- /* copro seems to need some delay between reading and writing */
- for (i = 0; i < 100; i++)
- nop();
- asm volatile("" : : : "memory");
-}
-
static inline uint32_t read_clidr(void)
{
uint32_t val = 0;
asm volatile ("mrc p15, 1, %0, c0, c0, 1" : "=r" (val));
- isb();
return val;
}
@@ -46,7 +34,6 @@ static inline uint32_t read_ccsidr(void)
{
uint32_t val = 0;
asm volatile ("mrc p15, 1, %0, c0, c0, 0" : "=r" (val));
- isb();
return val;
}
@@ -54,7 +41,6 @@ static inline uint32_t read_csselr(void)
{
uint32_t val = 0;
asm volatile ("mrc p15, 2, %0, c0, c0, 0" : "=r" (val));
- isb();
return val;
}
@@ -66,7 +52,6 @@ static inline void write_csselr(uint32_t val)
* Bit 0 - 0 = data or unified cache, 1 = instruction cache
*/
asm volatile ("mcr p15, 2, %0, c0, c0, 0" : : "r" (val));
- isb();
}
#ifndef __mask
diff --git a/src/mainboard/google/snow/romstage.c b/src/mainboard/google/snow/romstage.c
index ea2feec..3b14d91 100644
--- a/src/mainboard/google/snow/romstage.c
+++ b/src/mainboard/google/snow/romstage.c
@@ -20,6 +20,7 @@
#include <types.h>
#include <system.h>
+#include <armv7.h>
#include <cache.h>
#include <cbfs.h>
#include <common.h>
@@ -52,20 +53,6 @@ static int board_wakeup_permitted(void)
}
#endif
-/*
- * Set/clear program flow prediction and return the previous state.
- */
-static int config_branch_prediction(int set_cr_z)
-{
- unsigned int cr;
-
- /* System Control Register: 11th bit Z Branch prediction enable */
- cr = get_cr();
- set_cr(set_cr_z ? cr | CR_Z : cr & ~CR_Z);
-
- return cr & CR_Z;
-}
-
static void initialize_s5p_mshc(void)
{
/* MMC0: Fixed, 8 bit mode, connected with GPIO. */
@@ -94,13 +81,16 @@ void main(void)
struct arm_clk_ratios *arm_ratios;
int ret;
void *entry;
-
- /* FIXME: if we boot from USB, we need to disable branch prediction
- * before copying from USB into RAM */
- config_branch_prediction(1);
+ unsigned int cr;
clock_set_rate(PERIPH_ID_SPI1, 50000000); /* set spi clock to 50Mhz */
+ /*
+ * FIXME: Do necessary I2C init so low-level PMIC code doesn't need to.
+ * Also, we should only call power_init() on cold boot.
+ */
+ power_init();
+
/* Clock must be initialized before console_init, otherwise you may need
* to re-initialize serial console drivers again. */
mem = get_mem_timings();
@@ -109,12 +99,6 @@ void main(void)
console_init();
- /*
- * FIXME: Do necessary I2C init so low-level PMIC code doesn't need to.
- * Also, we should only call power_init() on cold boot.
- */
- power_init();
-
if (!mem) {
printk(BIOS_CRIT, "Unable to auto-detect memory timings\n");
while(1);
@@ -132,8 +116,21 @@ void main(void)
while(1);
}
+ /* Set up MMU and caches */
mmu_setup(CONFIG_SYS_SDRAM_BASE, CONFIG_DRAM_SIZE_MB);
+ /* Enable D-side prefetch */
+ cr = get_acr();
+ cr |= (1 << 2);
+ set_acr(cr);
+ CP15DSB;
+ CP15ISB;
+
+ /* FIXME: these functions take because the "generic" cache_enable()
+ * tries to call mmu_setup if mmu has not already been enabled */
+ icache_enable(CONFIG_SYS_SDRAM_BASE, CONFIG_DRAM_SIZE_MB);
+ dcache_enable(CONFIG_SYS_SDRAM_BASE, CONFIG_DRAM_SIZE_MB);
+
initialize_s5p_mshc();
graphics();
More information about the coreboot
mailing list