diff --git a/arch/arm/core/aarch32/cortex_a_r/CMakeLists.txt b/arch/arm/core/aarch32/cortex_a_r/CMakeLists.txt index d3337a6753a972..c1cdc7e9c67b89 100644 --- a/arch/arm/core/aarch32/cortex_a_r/CMakeLists.txt +++ b/arch/arm/core/aarch32/cortex_a_r/CMakeLists.txt @@ -17,3 +17,4 @@ zephyr_library_sources( zephyr_library_sources_ifdef(CONFIG_USERSPACE thread.c) zephyr_library_sources_ifdef(CONFIG_SEMIHOST semihost.c) zephyr_library_sources_ifdef(CONFIG_THREAD_LOCAL_STORAGE __aeabi_read_tp.S) +zephyr_library_sources_ifdef(CONFIG_ARCH_CACHE cache.c) diff --git a/arch/arm/core/aarch32/cortex_a_r/cache.c b/arch/arm/core/aarch32/cortex_a_r/cache.c new file mode 100644 index 00000000000000..b9748ef26489d8 --- /dev/null +++ b/arch/arm/core/aarch32/cortex_a_r/cache.c @@ -0,0 +1,210 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Cortex-A/R AArch32 L1-cache maintenance operations. + * + * This module implement the cache API for Cortex-A/R AArch32 cores using CMSIS. + * Only L1-cache maintenance operations is supported. + */ + +#include +#include +#include + +/* Cache Type Register */ +#define CTR_DMINLINE_SHIFT 16 +#define CTR_DMINLINE_MASK BIT_MASK(4) + +static size_t dcache_line_size; + +/** + * @brief Get the smallest D-cache line size. + * + * Get the smallest D-cache line size of all the data and unified caches that + * the processor controls. + */ +size_t arch_dcache_line_size_get(void) +{ + uint32_t val; + uint32_t dminline; + + if (!dcache_line_size) { + val = read_sysreg(ctr); + dminline = (val >> CTR_DMINLINE_SHIFT) & CTR_DMINLINE_MASK; + /* Log2 of the number of words */ + dcache_line_size = 2 << dminline; + } + + return dcache_line_size; +} + +void arch_dcache_enable(void) +{ + uint32_t val; + + arch_dcache_invd_all(); + + val = __get_SCTLR(); + val |= SCTLR_C_Msk; + __DSB(); + __set_SCTLR(val); + __ISB(); +} + +void arch_dcache_disable(void) +{ + uint32_t val; + + val = __get_SCTLR(); + val &= ~SCTLR_C_Msk; + __DSB(); + __set_SCTLR(val); + __ISB(); + + arch_dcache_flush_and_invd_all(); +} + +int arch_dcache_flush_all(void) +{ + L1C_CleanDCacheAll(); + + return 0; +} + +int arch_dcache_invd_all(void) +{ + L1C_InvalidateDCacheAll(); + + return 0; +} + +int arch_dcache_flush_and_invd_all(void) +{ + L1C_CleanInvalidateDCacheAll(); + + return 0; +} + +int arch_dcache_flush_range(void *start_addr, size_t size) +{ + size_t line_size; + uintptr_t addr = (uintptr_t)start_addr; + uintptr_t end_addr = addr + size; + + /* Align address to line size */ + line_size = arch_dcache_line_size_get(); + addr &= ~(line_size - 1); + + while (addr < end_addr) { + L1C_CleanDCacheMVA((void *)addr); + addr += line_size; + } + + return 0; +} + +int arch_dcache_invd_range(void *start_addr, size_t size) +{ + size_t line_size; + uintptr_t addr = (uintptr_t)start_addr; + uintptr_t end_addr = addr + size; + + line_size = arch_dcache_line_size_get(); + + /* + * Clean and invalidate the partial cache lines at both ends of the + * given range to prevent data corruption + */ + if (end_addr & (line_size - 1)) { + end_addr &= ~(line_size - 1); + L1C_CleanInvalidateDCacheMVA((void *)end_addr); + } + + if (addr & (line_size - 1)) { + addr &= ~(line_size - 1); + if (addr == end_addr) { + goto done; + } + L1C_CleanInvalidateDCacheMVA((void *)addr); + addr += line_size; + } + + /* Align address to line size */ + addr &= ~(line_size - 1); + + while (addr < end_addr) { + L1C_InvalidateDCacheMVA((void *)addr); + addr += line_size; + } + +done: + return 0; +} + +int arch_dcache_flush_and_invd_range(void *start_addr, size_t size) +{ + size_t line_size; + uintptr_t addr = (uintptr_t)start_addr; + uintptr_t end_addr = addr + size; + + /* Align address to line size */ + line_size = arch_dcache_line_size_get(); + addr &= ~(line_size - 1); + + while (addr < end_addr) { + L1C_CleanInvalidateDCacheMVA((void *)addr); + addr += line_size; + } + + return 0; +} + +void arch_icache_enable(void) +{ + arch_icache_invd_all(); + __set_SCTLR(__get_SCTLR() | SCTLR_I_Msk); + __ISB(); +} + +void arch_icache_disable(void) +{ + __set_SCTLR(__get_SCTLR() & ~SCTLR_I_Msk); + __ISB(); +} + +int arch_icache_flush_all(void) +{ + return -ENOTSUP; +} + +int arch_icache_invd_all(void) +{ + L1C_InvalidateICacheAll(); + + return 0; +} + +int arch_icache_flush_and_invd_all(void) +{ + return -ENOTSUP; +} + +int arch_icache_flush_range(void *start_addr, size_t size) +{ + return -ENOTSUP; +} + +int arch_icache_invd_range(void *start_addr, size_t size) +{ + return -ENOTSUP; +} + +int arch_icache_flush_and_invd_range(void *start_addr, size_t size) +{ + return -ENOTSUP; +} diff --git a/include/zephyr/arch/arm/aarch32/cortex_a_r/lib_helpers.h b/include/zephyr/arch/arm/aarch32/cortex_a_r/lib_helpers.h index 79d1dabafe32eb..a4e74b0daa42c2 100644 --- a/include/zephyr/arch/arm/aarch32/cortex_a_r/lib_helpers.h +++ b/include/zephyr/arch/arm/aarch32/cortex_a_r/lib_helpers.h @@ -71,6 +71,7 @@ MAKE_REG_HELPER(prlar, 0, 6, 3, 1); MAKE_REG_HELPER(mair0, 0, 10, 2, 0); MAKE_REG_HELPER(vbar, 0, 12, 0, 0); MAKE_REG_HELPER(cntv_ctl, 0, 14, 3, 1); +MAKE_REG_HELPER(ctr, 0, 0, 0, 1); MAKE_REG64_HELPER(ICC_SGI1R, 0, 12); MAKE_REG64_HELPER(cntvct, 1, 14); MAKE_REG64_HELPER(cntv_cval, 3, 14);