diff --git a/firmware/SOURCES b/firmware/SOURCES index 7b8991cf3e..bbe7f06f31 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES @@ -608,6 +608,8 @@ target/arm/mmu-arm.S # elif ARM_ARCH == 6 target/arm/bits-armv6.S target/arm/mmu-armv6.S +# elif ARM_ARCH == 7 && ARM_PROFILE == ARM_PROFILE_MICRO +target/arm/cpucache-armv7m.c # endif #if defined(CPU_ARM_CLASSIC) diff --git a/firmware/target/arm/cpucache-armv7m.c b/firmware/target/arm/cpucache-armv7m.c new file mode 100644 index 0000000000..c05c3e0d2b --- /dev/null +++ b/firmware/target/arm/cpucache-armv7m.c @@ -0,0 +1,112 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2025 Aidan MacDonald + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "cpucache-armv7m.h" +#include "cortex-m/cache.h" + +/* + * The target must define DCACHE_WAYS and DCACHE_SETS to the number + * of sets/ways in the L1 data cache. DCACHE_LINESIZE should be set + * to the writeback granule size. + * + * If you have multiple levels of caches (L2 or higher) then you'll + * probably need to change things here to handle it properly. + */ + +#define DCACHE_WAYSHIFT \ + (DCACHE_WAYS <= 1 ? 0 : __builtin_clzl(DCACHE_WAYS - 1)) + +static inline void full_dcache_op(volatile uint32_t *cache_reg) +{ + arm_dsb(); + + for (uint32_t way = 0; way < DCACHE_WAYS; ++way) + { + uint32_t arg = way << DCACHE_WAYSHIFT; + + for (uint32_t set = 0; set < DCACHE_SETS; ++set) + { + *cache_reg = arg; + arg += DCACHE_LINESIZE; + } + } + + arm_dsb(); +} + +static inline void range_dcache_op(const void *base, unsigned int size, + volatile uint32_t *cache_reg) +{ + arm_dsb(); + + uint32_t addr = (uint32_t)base; + uint32_t endaddr = addr + size; + + while (addr < endaddr) + { + *cache_reg = addr; + addr += DCACHE_LINESIZE; + } + + arm_dsb(); +} + +void commit_dcache(void) +{ + full_dcache_op(®_CACHE_DCCSW); +} + +void commit_discard_dcache(void) +{ + full_dcache_op(®_CACHE_DCCISW); +} + +void commit_discard_idcache(void) +{ + full_dcache_op(®_CACHE_DCCISW); + + REG_CACHE_ICIALLU = 0; + + arm_isb(); +} + +void __discard_idcache(void) +{ + full_dcache_op(®_CACHE_DCISW); + + REG_CACHE_ICIALLU = 0; + + arm_isb(); +} + +void commit_discard_dcache_range(const void *base, unsigned int size) +{ + range_dcache_op(base, size, ®_CACHE_DCCIMVAC); +} + +void commit_dcache_range(const void *base, unsigned int size) +{ + range_dcache_op(base, size, ®_CACHE_DCCMVAC); +} + +void discard_dcache_range(const void *base, unsigned int size) +{ + range_dcache_op(base, size, ®_CACHE_DCIMVAC); +} diff --git a/firmware/target/arm/cpucache-armv7m.h b/firmware/target/arm/cpucache-armv7m.h new file mode 100644 index 0000000000..1fcca7e8f6 --- /dev/null +++ b/firmware/target/arm/cpucache-armv7m.h @@ -0,0 +1,34 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2025 Aidan MacDonald + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#ifndef CPUCACHE_ARMV7M_H +#define CPUCACHE_ARMV7M_H + +#include "cpucache-arm.h" +#include "cpu.h" + +#define arm_dsb() asm volatile("dsb" ::: "memory") +#define arm_isb() asm volatile("isb" ::: "memory") + +/* Discard entire icache and dcache, generally only used + * when first enabling the caches. */ +void __discard_idcache(void); + +#endif /* CPUCACHE_ARMV7M_H */