diff options
Diffstat (limited to 'arch/arm/cpu')
-rw-r--r-- | arch/arm/cpu/armv7m/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/cpu/armv7m/cache.c | 23 | ||||
-rw-r--r-- | arch/arm/cpu/armv7m/cpu.c | 19 | ||||
-rw-r--r-- | arch/arm/cpu/armv7m/mpu.c | 82 | ||||
-rw-r--r-- | arch/arm/cpu/armv8/cache.S | 24 | ||||
-rw-r--r-- | arch/arm/cpu/armv8/cache_v8.c | 2 | ||||
-rw-r--r-- | arch/arm/cpu/armv8/generic_timer.c | 2 |
7 files changed, 151 insertions, 3 deletions
diff --git a/arch/arm/cpu/armv7m/Makefile b/arch/arm/cpu/armv7m/Makefile index 93c9085219..257fc7faf3 100644 --- a/arch/arm/cpu/armv7m/Makefile +++ b/arch/arm/cpu/armv7m/Makefile @@ -6,5 +6,5 @@ # extra-y := start.o -obj-y += cpu.o cache.o +obj-y += cpu.o cache.o mpu.o obj-$(CONFIG_SYS_ARCH_TIMER) += systick-timer.o diff --git a/arch/arm/cpu/armv7m/cache.c b/arch/arm/cpu/armv7m/cache.c index 162cfe3928..e8f86420cf 100644 --- a/arch/arm/cpu/armv7m/cache.c +++ b/arch/arm/cpu/armv7m/cache.c @@ -253,6 +253,21 @@ void flush_dcache_range(unsigned long start, unsigned long stop) return; } } +void flush_dcache_all(void) +{ + if (action_dcache_all(FLUSH_SET_WAY)) { + printf("ERR: D-cache not flushed\n"); + return; + } +} + +void invalidate_dcache_all(void) +{ + if (action_dcache_all(INVALIDATE_SET_WAY)) { + printf("ERR: D-cache not invalidated\n"); + return; + } +} #else void dcache_enable(void) { @@ -268,6 +283,14 @@ int dcache_status(void) { return 0; } + +void flush_dcache_all(void) +{ +} + +void invalidate_dcache_all(void) +{ +} #endif #ifndef CONFIG_SYS_ICACHE_OFF diff --git a/arch/arm/cpu/armv7m/cpu.c b/arch/arm/cpu/armv7m/cpu.c index 58cde9391f..a424babde5 100644 --- a/arch/arm/cpu/armv7m/cpu.c +++ b/arch/arm/cpu/armv7m/cpu.c @@ -18,6 +18,25 @@ */ int cleanup_before_linux(void) { + /* + * this function is called just before we call linux + * it prepares the processor for linux + * + * disable interrupt and turn off caches etc ... + */ + disable_interrupts(); + /* + * turn off D-cache + * dcache_disable() in turn flushes the d-cache + * MPU is still enabled & can't be disabled as the u-boot + * code might be running in sdram which by default is not + * executable area. + */ + dcache_disable(); + /* invalidate to make sure no cache line gets dirty between + * dcache flushing and disabling dcache */ + invalidate_dcache_all(); + return 0; } diff --git a/arch/arm/cpu/armv7m/mpu.c b/arch/arm/cpu/armv7m/mpu.c new file mode 100644 index 0000000000..31a243b49a --- /dev/null +++ b/arch/arm/cpu/armv7m/mpu.c @@ -0,0 +1,82 @@ +/* + * (C) Copyright 2017 + * Vikas Manocha, ST Micoelectronics, vikas.manocha@st.com. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <linux/bitops.h> +#include <asm/armv7m.h> +#include <asm/armv7m_mpu.h> +#include <asm/io.h> + +#define V7M_MPU_CTRL_ENABLE (1 << 0) +#define V7M_MPU_CTRL_DISABLE (0 << 0) +#define V7M_MPU_CTRL_HFNMIENA (1 << 1) +#define VALID_REGION (1 << 4) + +#define ENABLE_REGION (1 << 0) + +#define AP_SHIFT 24 +#define XN_SHIFT 28 +#define TEX_SHIFT 19 +#define S_SHIFT 18 +#define C_SHIFT 17 +#define B_SHIFT 16 +#define REGION_SIZE_SHIFT 1 + +#define CACHEABLE (1 << C_SHIFT) +#define BUFFERABLE (1 << B_SHIFT) +#define SHAREABLE (1 << S_SHIFT) + +void disable_mpu(void) +{ + writel(0, &V7M_MPU->ctrl); +} + +void enable_mpu(void) +{ + writel(V7M_MPU_CTRL_ENABLE | V7M_MPU_CTRL_HFNMIENA, &V7M_MPU->ctrl); + + /* Make sure new mpu config is effective for next memory access */ + dsb(); + isb(); /* Make sure instruction stream sees it */ +} + +void mpu_config(struct mpu_region_config *reg_config) +{ + uint32_t attr; + + switch (reg_config->mr_attr) { + case STRONG_ORDER: + attr = SHAREABLE; + break; + case SHARED_WRITE_BUFFERED: + attr = BUFFERABLE; + break; + case O_I_WT_NO_WR_ALLOC: + attr = CACHEABLE; + break; + case O_I_WB_NO_WR_ALLOC: + attr = CACHEABLE | BUFFERABLE; + break; + case O_I_NON_CACHEABLE: + attr = 1 << TEX_SHIFT; + break; + case O_I_WB_RD_WR_ALLOC: + attr = (1 << TEX_SHIFT) | CACHEABLE | BUFFERABLE; + break; + case DEVICE_NON_SHARED: + attr = (2 << TEX_SHIFT) | BUFFERABLE; + default: + attr = 0; /* strongly ordered */ + break; + }; + + writel(reg_config->start_addr | VALID_REGION | reg_config->region_no, + &V7M_MPU->rbar); + + writel(reg_config->xn << XN_SHIFT | reg_config->ap << AP_SHIFT | attr + | reg_config->reg_size << REGION_SIZE_SHIFT | ENABLE_REGION + , &V7M_MPU->rasr); +} diff --git a/arch/arm/cpu/armv8/cache.S b/arch/arm/cpu/armv8/cache.S index f1deaa7230..7cba308ee7 100644 --- a/arch/arm/cpu/armv8/cache.S +++ b/arch/arm/cpu/armv8/cache.S @@ -138,6 +138,30 @@ ENTRY(__asm_flush_dcache_range) dsb sy ret ENDPROC(__asm_flush_dcache_range) +/* + * void __asm_invalidate_dcache_range(start, end) + * + * invalidate data cache in the range + * + * x0: start address + * x1: end address + */ +ENTRY(__asm_invalidate_dcache_range) + mrs x3, ctr_el0 + ubfm x3, x3, #16, #19 + mov x2, #4 + lsl x2, x2, x3 /* cache line size */ + + /* x2 <- minimal cache line size in cache system */ + sub x3, x2, #1 + bic x0, x0, x3 +1: dc ivac, x0 /* invalidate data or unified cache */ + add x0, x0, x2 + cmp x0, x1 + b.lo 1b + dsb sy + ret +ENDPROC(__asm_invalidate_dcache_range) /* * void __asm_invalidate_icache_all(void) diff --git a/arch/arm/cpu/armv8/cache_v8.c b/arch/arm/cpu/armv8/cache_v8.c index bd1c3e0335..adc7e1746f 100644 --- a/arch/arm/cpu/armv8/cache_v8.c +++ b/arch/arm/cpu/armv8/cache_v8.c @@ -446,7 +446,7 @@ inline void flush_dcache_all(void) */ void invalidate_dcache_range(unsigned long start, unsigned long stop) { - __asm_flush_dcache_range(start, stop); + __asm_invalidate_dcache_range(start, stop); } /* diff --git a/arch/arm/cpu/armv8/generic_timer.c b/arch/arm/cpu/armv8/generic_timer.c index cd92b2c761..a2dda333fe 100644 --- a/arch/arm/cpu/armv8/generic_timer.c +++ b/arch/arm/cpu/armv8/generic_timer.c @@ -43,7 +43,7 @@ unsigned long timer_read_counter(void) return cntpct; } -unsigned long long get_ticks(void) +uint64_t get_ticks(void) { unsigned long ticks = timer_read_counter(); |