David Hendricks (dhendrix@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@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@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();