From 518580ac82b891915d95c2df46bfa3fafdf96a7e Mon Sep 17 00:00:00 2001 From: Henrik Lindblom Date: Sat, 12 Apr 2025 08:57:51 +0300 Subject: [PATCH 1/3] cache: stm32: add cortex-m33 peripheral driver STM32 Cortex-M33, such as the L5/H5/U5 series, have a cache peripheral for instruction and data caches, which are not present in the C-M33 architecture spec. The driver defaults to direct mapped cache as it uses less power than the alternative set associative mapping [1]. This has also been the default in stm32 soc initialization code for chips that have the ICACHE peripheral, which makes it the safest choice for backward compatibility. The exception to the rule is STM32L5, which has the n-way cache mode selected in SOC code. [1]: https://en.wikipedia.org/wiki/Cache_placement_policies Signed-off-by: Henrik Lindblom --- drivers/cache/CMakeLists.txt | 1 + drivers/cache/Kconfig | 1 + drivers/cache/Kconfig.stm32 | 24 +++++ drivers/cache/cache_stm32.c | 182 +++++++++++++++++++++++++++++++++++ 4 files changed, 208 insertions(+) create mode 100644 drivers/cache/Kconfig.stm32 create mode 100644 drivers/cache/cache_stm32.c diff --git a/drivers/cache/CMakeLists.txt b/drivers/cache/CMakeLists.txt index 74c3b983026f..51a1940c1731 100644 --- a/drivers/cache/CMakeLists.txt +++ b/drivers/cache/CMakeLists.txt @@ -10,3 +10,4 @@ zephyr_library_sources_ifdef(CONFIG_CACHE_ANDES cache_andes.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE cache_handlers.c) zephyr_library_sources_ifdef(CONFIG_CACHE_NRF_CACHE cache_nrf.c) zephyr_library_sources_ifdef(CONFIG_CACHE_NXP_XCACHE cache_nxp_xcache.c) +zephyr_library_sources_ifdef(CONFIG_CACHE_STM32 cache_stm32.c) diff --git a/drivers/cache/Kconfig b/drivers/cache/Kconfig index 8bae7f352024..eb8dfae76ca7 100644 --- a/drivers/cache/Kconfig +++ b/drivers/cache/Kconfig @@ -22,5 +22,6 @@ source "drivers/cache/Kconfig.aspeed" source "drivers/cache/Kconfig.nrf" source "drivers/cache/Kconfig.andes" source "drivers/cache/Kconfig.nxp_xcache" +source "drivers/cache/Kconfig.stm32" endif # CACHE diff --git a/drivers/cache/Kconfig.stm32 b/drivers/cache/Kconfig.stm32 new file mode 100644 index 000000000000..6d468f98548d --- /dev/null +++ b/drivers/cache/Kconfig.stm32 @@ -0,0 +1,24 @@ +# Copyright (c) 2025 Henrik Lindblom +# SPDX-License-Identifier: Apache-2.0 + +menuconfig CACHE_STM32 + bool "STM32 cache driver" + select CACHE_HAS_DRIVER + depends on CACHE_MANAGEMENT + help + Enable support for the STM32 ICACHE / DCACHE peripheral present in some STM32 chips. + +if CACHE_STM32 + +# "default n" for L5 is legacy - could be removed? +config CACHE_STM32_ICACHE_DIRECT_MAPPING + bool "Use 1-way associative mapping for ICACHE" + default n if SOC_SERIES_STM32L5X + default y + help + Use ICACHE in direct mapping (1-way associative) mode instead of the default n-way + associative cache mode. + + This option reduces power consumption but slightly reduces cache's performance. + +endif # CACHE_STM32 diff --git a/drivers/cache/cache_stm32.c b/drivers/cache/cache_stm32.c new file mode 100644 index 000000000000..8dc07c1a2c65 --- /dev/null +++ b/drivers/cache/cache_stm32.c @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2025 Henrik Lindblom + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(cache_stm32, CONFIG_CACHE_LOG_LEVEL); + +#ifdef CONFIG_DCACHE + +void cache_data_enable(void) +{ + LL_DCACHE_Enable(DCACHE1); +#if defined(DCACHE2) + LL_DCACHE_Enable(DCACHE2); +#endif +} + +void cache_data_disable(void) +{ + cache_data_flush_all(); + + while (LL_DCACHE_IsActiveFlag_BUSYCMD(DCACHE1)) { + } + + LL_DCACHE_Disable(DCACHE1); + LL_DCACHE_ClearFlag_BSYEND(DCACHE1); + +#if defined(DCACHE2) + while (LL_DCACHE_IsActiveFlag_BUSYCMD(DCACHE2)) { + } + + LL_DCACHE_Disable(DCACHE2); + LL_DCACHE_ClearFlag_BSYEND(DCACHE2); +#endif +} + +static int cache_data_manage_range(void *addr, size_t size, uint32_t command) +{ + /* + * This is a simple approach to invalidate the range. The address might be in either DCACHE1 + * or DCACHE2 (if present). The cache invalidation algorithm checks the TAG memory for the + * specified address range so there's little harm in just checking both caches. + */ + uint32_t start = (uint32_t)addr; + uint32_t end; + + if (u32_add_overflow(start, size, &end)) { + return -EOVERFLOW; + } + + LL_DCACHE_SetStartAddress(DCACHE1, start); + LL_DCACHE_SetEndAddress(DCACHE1, end); + LL_DCACHE_SetCommand(DCACHE1, command); + LL_DCACHE_StartCommand(DCACHE1); +#if defined(DCACHE2) + LL_DCACHE_SetStartAddress(DCACHE2, start); + LL_DCACHE_SetEndAddress(DCACHE2, end); + LL_DCACHE_SetCommand(DCACHE2, command); + LL_DCACHE_StartCommand(DCACHE2); +#endif + return 0; +} + +int cache_data_flush_range(void *addr, size_t size) +{ + return cache_data_manage_range(addr, size, LL_DCACHE_COMMAND_CLEAN_BY_ADDR); +} + +int cache_data_invd_range(void *addr, size_t size) +{ + return cache_data_manage_range(addr, size, LL_DCACHE_COMMAND_INVALIDATE_BY_ADDR); +} + +int cache_data_flush_and_invd_range(void *addr, size_t size) +{ + return cache_data_manage_range(addr, size, LL_DCACHE_COMMAND_CLEAN_INVALIDATE_BY_ADDR); +} + +int cache_data_flush_all(void) +{ + return cache_data_flush_range(0, UINT32_MAX); +} + +int cache_data_invd_all(void) +{ + LL_DCACHE_Invalidate(DCACHE1); +#if defined(DCACHE2) + LL_DCACHE_Invalidate(DCACHE2); +#endif + return 0; +} + +int cache_data_flush_and_invd_all(void) +{ + return cache_data_flush_and_invd_range(0, UINT32_MAX); +} + +#endif /* CONFIG_DCACHE */ + +static inline void wait_for_icache(void) +{ + while (LL_ICACHE_IsActiveFlag_BUSY()) { + } + + /* Clear BSYEND to avoid an extra interrupt if somebody enables them. */ + LL_ICACHE_ClearFlag_BSYEND(); +} + +void cache_instr_enable(void) +{ + if (IS_ENABLED(CONFIG_CACHE_STM32_ICACHE_DIRECT_MAPPING)) { + LL_ICACHE_SetMode(LL_ICACHE_1WAY); + } + + /* + * Need to wait until any pending cache invalidation operations finish. This is recommended + * in the reference manual to ensure execution timing determinism. + */ + wait_for_icache(); + LL_ICACHE_Enable(); +} + +void cache_instr_disable(void) +{ + LL_ICACHE_Disable(); + + while (LL_ICACHE_IsEnabled()) { + /** + * Wait until the ICACHE is disabled (CR.EN=0), at which point + * all requests bypass the cache and are forwarded directly + * from the ICACHE slave port to the ICACHE master port(s). + * + * The cache invalidation will start once disabled, but we allow + * it to proceed in the background since it doesn't need to be + * complete for requests to bypass the ICACHE. + */ + } +} + +int cache_instr_flush_all(void) +{ + return -ENOTSUP; +} + +int cache_instr_invd_all(void) +{ + LL_ICACHE_Invalidate(); + return 0; +} + +int cache_instr_flush_and_invd_all(void) +{ + return -ENOTSUP; +} + +int cache_instr_flush_range(void *addr, size_t size) +{ + ARG_UNUSED(addr); + ARG_UNUSED(size); + return -ENOTSUP; +} + +int cache_instr_invd_range(void *addr, size_t size) +{ + ARG_UNUSED(addr); + ARG_UNUSED(size); + return -ENOTSUP; +} + +int cache_instr_flush_and_invd_range(void *addr, size_t size) +{ + ARG_UNUSED(addr); + ARG_UNUSED(size); + return -ENOTSUP; +} From 6c63cab2b48d601942aeef689fb07f3ad5c51fa3 Mon Sep 17 00:00:00 2001 From: Henrik Lindblom Date: Tue, 15 Apr 2025 11:20:11 +0300 Subject: [PATCH 2/3] soc: stm32: use cache peripheral driver Use the Zephyr cache API in soc initialization code instead of calling the HAL directly. The change does not modify the pre-existing cache settings, just changes the path they are enabled. Signed-off-by: Henrik Lindblom --- soc/st/stm32/Kconfig.defconfig | 3 +++ soc/st/stm32/stm32h5x/Kconfig.defconfig | 13 ++++++++++++ soc/st/stm32/stm32h5x/soc.c | 6 ++---- soc/st/stm32/stm32l5x/Kconfig.defconfig | 10 +++++++++ soc/st/stm32/stm32l5x/soc.c | 7 ++---- soc/st/stm32/stm32u5x/Kconfig.defconfig | 13 ++++++++++++ soc/st/stm32/stm32u5x/power.c | 25 +++------------------- soc/st/stm32/stm32u5x/soc.c | 6 ++---- soc/st/stm32/stm32wbax/Kconfig.defconfig | 10 +++++++++ soc/st/stm32/stm32wbax/power.c | 27 ++++-------------------- soc/st/stm32/stm32wbax/soc.c | 6 ++---- 11 files changed, 64 insertions(+), 62 deletions(-) diff --git a/soc/st/stm32/Kconfig.defconfig b/soc/st/stm32/Kconfig.defconfig index b34e0c775beb..1cf916d1611e 100644 --- a/soc/st/stm32/Kconfig.defconfig +++ b/soc/st/stm32/Kconfig.defconfig @@ -11,6 +11,9 @@ if SOC_FAMILY_STM32 # can override the defaults given here rsource "*/Kconfig.defconfig" +config CACHE_STM32 + default y if EXTERNAL_CACHE + config CLOCK_CONTROL default y diff --git a/soc/st/stm32/stm32h5x/Kconfig.defconfig b/soc/st/stm32/stm32h5x/Kconfig.defconfig index f8167440f336..d3eb43e42860 100644 --- a/soc/st/stm32/stm32h5x/Kconfig.defconfig +++ b/soc/st/stm32/stm32h5x/Kconfig.defconfig @@ -7,6 +7,19 @@ if SOC_SERIES_STM32H5X rsource "Kconfig.defconfig.stm32h5*" +config ICACHE + default y + +config DCACHE + default y if !SOC_STM32H503XX + +config CACHE_MANAGEMENT + default y + +choice CACHE_TYPE + default EXTERNAL_CACHE +endchoice + config ROM_START_OFFSET default 0x400 if BOOTLOADER_MCUBOOT diff --git a/soc/st/stm32/stm32h5x/soc.c b/soc/st/stm32/stm32h5x/soc.c index c4735c78c795..5ae4618b707d 100644 --- a/soc/st/stm32/stm32h5x/soc.c +++ b/soc/st/stm32/stm32h5x/soc.c @@ -11,9 +11,9 @@ #include #include +#include #include #include -#include #include #include @@ -29,9 +29,7 @@ extern void stm32_power_init(void); */ void soc_early_init_hook(void) { - /* Enable instruction cache in 1-way (direct mapped cache) */ - LL_ICACHE_SetMode(LL_ICACHE_1WAY); - LL_ICACHE_Enable(); + sys_cache_instr_enable(); /* Update CMSIS SystemCoreClock variable (HCLK) */ /* At reset, system core clock is set to 32 MHz from HSI with a HSIDIV = 2 */ diff --git a/soc/st/stm32/stm32l5x/Kconfig.defconfig b/soc/st/stm32/stm32l5x/Kconfig.defconfig index 2c8607c9b79e..77ba04cece93 100644 --- a/soc/st/stm32/stm32l5x/Kconfig.defconfig +++ b/soc/st/stm32/stm32l5x/Kconfig.defconfig @@ -7,6 +7,16 @@ if SOC_SERIES_STM32L5X rsource "Kconfig.defconfig.stm32l5*" +config ICACHE + default y + +config CACHE_MANAGEMENT + default y + +choice CACHE_TYPE + default EXTERNAL_CACHE +endchoice + config ROM_START_OFFSET default 0x400 if BOOTLOADER_MCUBOOT diff --git a/soc/st/stm32/stm32l5x/soc.c b/soc/st/stm32/stm32l5x/soc.c index 4c52d30bd01e..d8aed0383a69 100644 --- a/soc/st/stm32/stm32l5x/soc.c +++ b/soc/st/stm32/stm32l5x/soc.c @@ -11,9 +11,9 @@ #include #include +#include #include #include -#include #include #include @@ -29,10 +29,7 @@ extern void stm32_power_init(void); */ void soc_early_init_hook(void) { - /* Enable ICACHE */ - while (LL_ICACHE_IsActiveFlag_BUSY()) { - } - LL_ICACHE_Enable(); + sys_cache_instr_enable(); /* Update CMSIS SystemCoreClock variable (HCLK) */ /* At reset, system core clock is set to 4 MHz from MSI */ diff --git a/soc/st/stm32/stm32u5x/Kconfig.defconfig b/soc/st/stm32/stm32u5x/Kconfig.defconfig index 61771d8951eb..55a18e69ad0f 100644 --- a/soc/st/stm32/stm32u5x/Kconfig.defconfig +++ b/soc/st/stm32/stm32u5x/Kconfig.defconfig @@ -10,6 +10,19 @@ rsource "Kconfig.defconfig.stm32u5*" config ROM_START_OFFSET default 0x400 if BOOTLOADER_MCUBOOT +config ICACHE + default y + +config DCACHE + default y + +config CACHE_MANAGEMENT + default y + +choice CACHE_TYPE + default EXTERNAL_CACHE +endchoice + if STM32_STOP3_LP_MODE config COUNTER diff --git a/soc/st/stm32/stm32u5x/power.c b/soc/st/stm32/stm32u5x/power.c index 22f12dc57bbd..7ee343948832 100644 --- a/soc/st/stm32/stm32u5x/power.c +++ b/soc/st/stm32/stm32u5x/power.c @@ -4,6 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ #include +#include #include #include #include @@ -12,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -35,22 +35,6 @@ static void pwr_stop3_isr(const struct device *dev) /* Clear all wake-up flags */ LL_PWR_ClearFlag_WU(); } - -static void disable_cache(void) -{ - /* Disabling ICACHE */ - LL_ICACHE_Disable(); - while (LL_ICACHE_IsEnabled() == 1U) { - } - - /* Wait until ICACHE_SR.BUSYF is cleared */ - while (LL_ICACHE_IsActiveFlag_BUSY() == 1U) { - } - - /* Wait until ICACHE_SR.BSYENDF is set */ - while (LL_ICACHE_IsActiveFlag_BSYEND() == 0U) { - } -} #endif void set_mode_stop(uint8_t substate_id) @@ -82,7 +66,7 @@ void set_mode_stop(uint8_t substate_id) LL_PWR_ClearFlag_SB(); LL_PWR_ClearFlag_WU(); - disable_cache(); + sys_cache_instr_disable(); LL_PWR_SetPowerMode(LL_PWR_STOP3_MODE); break; @@ -135,10 +119,7 @@ void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) } else if (substate_id == 4) { stm32_clock_control_standby_exit(); - LL_ICACHE_SetMode(LL_ICACHE_1WAY); - LL_ICACHE_Enable(); - while (LL_ICACHE_IsEnabled() == 0U) { - } + sys_cache_instr_enable(); LL_LPM_DisableSleepOnExit(); LL_LPM_EnableSleep(); diff --git a/soc/st/stm32/stm32u5x/soc.c b/soc/st/stm32/stm32u5x/soc.c index 131279dabae4..5263db29c376 100644 --- a/soc/st/stm32/stm32u5x/soc.c +++ b/soc/st/stm32/stm32u5x/soc.c @@ -10,10 +10,10 @@ */ #include +#include #include #include #include -#include #include #include @@ -29,9 +29,7 @@ extern void stm32_power_init(void); */ void soc_early_init_hook(void) { - /* Enable instruction cache in 1-way (direct mapped cache) */ - LL_ICACHE_SetMode(LL_ICACHE_1WAY); - LL_ICACHE_Enable(); + sys_cache_instr_enable(); /* Update CMSIS SystemCoreClock variable (HCLK) */ /* At reset, system core clock is set to 4 MHz from MSIS */ diff --git a/soc/st/stm32/stm32wbax/Kconfig.defconfig b/soc/st/stm32/stm32wbax/Kconfig.defconfig index 88e41074518d..498292d79ce8 100644 --- a/soc/st/stm32/stm32wbax/Kconfig.defconfig +++ b/soc/st/stm32/stm32wbax/Kconfig.defconfig @@ -7,6 +7,16 @@ if SOC_SERIES_STM32WBAX rsource "Kconfig.defconfig.stm32wba*" +config ICACHE + default y + +config CACHE_MANAGEMENT + default y + +choice CACHE_TYPE + default EXTERNAL_CACHE +endchoice + config STM32_LPTIM_TIMER default y if PM diff --git a/soc/st/stm32/stm32wbax/power.c b/soc/st/stm32/stm32wbax/power.c index 6fc6e424b85a..43fcd67b6124 100644 --- a/soc/st/stm32/stm32wbax/power.c +++ b/soc/st/stm32/stm32wbax/power.c @@ -4,6 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ #include +#include #include #include #include @@ -13,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -28,22 +28,6 @@ LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); void stm32_power_init(void); -static void disable_cache(void) -{ - /* Disabling ICACHE */ - LL_ICACHE_Disable(); - while (LL_ICACHE_IsEnabled() == 1U) { - } - - /* Wait until ICACHE_SR.BUSYF is cleared */ - while (LL_ICACHE_IsActiveFlag_BUSY() == 1U) { - } - - /* Wait until ICACHE_SR.BSYENDF is set */ - while (LL_ICACHE_IsActiveFlag_BSYEND() == 0U) { - } -} - static void set_mode_stop(uint8_t substate_id) { @@ -53,7 +37,7 @@ static void set_mode_stop(uint8_t substate_id) /* Erratum 2.2.15: * Disabling ICACHE is required before entering stop mode */ - disable_cache(); + sys_cache_instr_disable(); #ifdef CONFIG_BT_STM32WBA scm_setwaitstates(LP); @@ -108,7 +92,7 @@ static void set_mode_suspend_to_ram(void) LL_PWR_ClearFlag_WU(); LL_RCC_ClearResetFlags(); - disable_cache(); + sys_cache_instr_disable(); /* Select standby mode */ LL_PWR_SetPowerMode(LL_PWR_MODE_STANDBY); @@ -161,10 +145,7 @@ void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) /* Erratum 2.2.15: * Enable ICACHE when exiting stop mode */ - LL_ICACHE_SetMode(LL_ICACHE_1WAY); - LL_ICACHE_Enable(); - while (LL_ICACHE_IsEnabled() == 0U) { - } + sys_cache_instr_enable(); LL_LPM_DisableSleepOnExit(); LL_LPM_EnableSleep(); diff --git a/soc/st/stm32/stm32wbax/soc.c b/soc/st/stm32/stm32wbax/soc.c index 9e49f8be955c..fb54c5b53030 100644 --- a/soc/st/stm32/stm32wbax/soc.c +++ b/soc/st/stm32/stm32wbax/soc.c @@ -11,10 +11,10 @@ #include #include +#include #include #include #include -#include #include #include #include @@ -31,9 +31,7 @@ LOG_MODULE_REGISTER(soc); */ void stm32wba_init(void) { - /* Enable instruction cache in 1-way (direct mapped cache) */ - LL_ICACHE_SetMode(LL_ICACHE_1WAY); - LL_ICACHE_Enable(); + sys_cache_instr_enable(); #ifdef CONFIG_STM32_FLASH_PREFETCH __HAL_FLASH_PREFETCH_BUFFER_ENABLE(); #endif From fa373e9702042b8e137bb5d470e9dcb7f66e754c Mon Sep 17 00:00:00 2001 From: Henrik Lindblom Date: Wed, 16 Apr 2025 15:28:53 +0300 Subject: [PATCH 3/3] drivers: stm32: use cache peripheral driver Use cache API for disabling and enabling ICACHE. The driver handles waiting for ongoing cache invalidation. Signed-off-by: Henrik Lindblom --- drivers/flash/flash_stm32l5x.c | 156 ++++------------------ drivers/flash/flash_stm32wbax.c | 154 +++------------------ drivers/hwinfo/hwinfo_stm32.c | 6 +- drivers/sensor/st/stm32_temp/stm32_temp.c | 6 +- drivers/sensor/st/stm32_vref/stm32_vref.c | 6 +- 5 files changed, 53 insertions(+), 275 deletions(-) diff --git a/drivers/flash/flash_stm32l5x.c b/drivers/flash/flash_stm32l5x.c index e085ac3fd819..1db7f0c4a917 100644 --- a/drivers/flash/flash_stm32l5x.c +++ b/drivers/flash/flash_stm32l5x.c @@ -11,6 +11,7 @@ LOG_MODULE_REGISTER(LOG_DOMAIN); #include #include +#include #include #include #include @@ -34,89 +35,6 @@ LOG_MODULE_REGISTER(LOG_DOMAIN); #define BANK2_OFFSET (KB(STM32_SERIES_MAX_FLASH) / 2) -#define ICACHE_DISABLE_TIMEOUT_VALUE 1U /* 1ms */ -#define ICACHE_INVALIDATE_TIMEOUT_VALUE 1U /* 1ms */ - -static int stm32_icache_disable(void) -{ - int status = 0; - uint32_t tickstart; - - LOG_DBG("I-cache Disable"); - /* Clear BSYENDF flag first and then disable the instruction cache - * that starts a cache invalidation procedure - */ - CLEAR_BIT(ICACHE->FCR, ICACHE_FCR_CBSYENDF); - - LL_ICACHE_Disable(); - - /* Get tick */ - tickstart = k_uptime_get_32(); - - /* Wait for instruction cache to get disabled */ - while (LL_ICACHE_IsEnabled()) { - if ((k_uptime_get_32() - tickstart) > - ICACHE_DISABLE_TIMEOUT_VALUE) { - /* New check to avoid false timeout detection in case - * of preemption. - */ - if (LL_ICACHE_IsEnabled()) { - status = -ETIMEDOUT; - break; - } - } - } - - return status; -} - -static void stm32_icache_enable(void) -{ - LOG_DBG("I-cache Enable"); - LL_ICACHE_Enable(); -} - -static int icache_wait_for_invalidate_complete(void) -{ - int status = -EIO; - uint32_t tickstart; - - /* Check if ongoing invalidation operation */ - if (LL_ICACHE_IsActiveFlag_BUSY()) { - /* Get tick */ - tickstart = k_uptime_get_32(); - - /* Wait for end of cache invalidation */ - while (!LL_ICACHE_IsActiveFlag_BSYEND()) { - if ((k_uptime_get_32() - tickstart) > - ICACHE_INVALIDATE_TIMEOUT_VALUE) { - break; - } - } - } - - /* Clear any pending flags */ - if (LL_ICACHE_IsActiveFlag_BSYEND()) { - LOG_DBG("I-cache Invalidation complete"); - - LL_ICACHE_ClearFlag_BSYEND(); - status = 0; - } else { - LOG_ERR("I-cache Invalidation timeout"); - - status = -ETIMEDOUT; - } - - if (LL_ICACHE_IsActiveFlag_ERR()) { - LOG_ERR("I-cache error"); - - LL_ICACHE_ClearFlag_ERR(); - status = -EIO; - } - - return status; -} - /* Macro to check if the flash is Dual bank or not */ #if defined(CONFIG_SOC_SERIES_STM32H5X) #define stm32_flash_has_2_banks(flash_device) true @@ -302,19 +220,16 @@ int flash_stm32_block_erase_loop(const struct device *dev, { unsigned int address = offset; int rc = 0; - bool icache_enabled = LL_ICACHE_IsEnabled(); - if (icache_enabled) { - /* Disable icache, this will start the invalidation procedure. - * All changes(erase/write) to flash memory should happen when - * i-cache is disabled. A write to flash performed without - * disabling i-cache will set ERRF error flag in SR register. - */ - rc = stm32_icache_disable(); - if (rc != 0) { - return rc; - } - } + /* Disable icache, this will start the invalidation procedure. + * All changes(erase/write) to flash memory should happen when + * i-cache is disabled. A write to flash performed without + * disabling i-cache will set ERRF error flag in SR register. + */ + + bool cache_enabled = LL_ICACHE_IsEnabled(); + + sys_cache_instr_disable(); for (; address <= offset + len - 1 ; address += FLASH_PAGE_SIZE) { rc = erase_page(dev, address); @@ -323,16 +238,8 @@ int flash_stm32_block_erase_loop(const struct device *dev, } } - if (icache_enabled) { - /* Since i-cache was disabled, this would start the - * invalidation procedure, so wait for completion. - */ - rc = icache_wait_for_invalidate_complete(); - - /* I-cache should be enabled only after the - * invalidation is complete. - */ - stm32_icache_enable(); + if (cache_enabled) { + sys_cache_instr_enable(); } return rc; @@ -342,19 +249,16 @@ int flash_stm32_write_range(const struct device *dev, unsigned int offset, const void *data, unsigned int len) { int i, rc = 0; - bool icache_enabled = LL_ICACHE_IsEnabled(); - if (icache_enabled) { - /* Disable icache, this will start the invalidation procedure. - * All changes(erase/write) to flash memory should happen when - * i-cache is disabled. A write to flash performed without - * disabling i-cache will set ERRF error flag in SR register. - */ - rc = stm32_icache_disable(); - if (rc != 0) { - return rc; - } - } + /* Disable icache, this will start the invalidation procedure. + * All changes(erase/write) to flash memory should happen when + * i-cache is disabled. A write to flash performed without + * disabling i-cache will set ERRF error flag in SR register. + */ + + bool cache_enabled = LL_ICACHE_IsEnabled(); + + sys_cache_instr_disable(); for (i = 0; i < len; i += FLASH_STM32_WRITE_BLOCK_SIZE) { rc = write_nwords(dev, offset + i, ((const uint32_t *) data + (i>>2)), @@ -364,22 +268,8 @@ int flash_stm32_write_range(const struct device *dev, unsigned int offset, } } - if (icache_enabled) { - int rc2; - - /* Since i-cache was disabled, this would start the - * invalidation procedure, so wait for completion. - */ - rc2 = icache_wait_for_invalidate_complete(); - - if (!rc) { - rc = rc2; - } - - /* I-cache should be enabled only after the - * invalidation is complete. - */ - stm32_icache_enable(); + if (cache_enabled) { + sys_cache_instr_enable(); } return rc; diff --git a/drivers/flash/flash_stm32wbax.c b/drivers/flash/flash_stm32wbax.c index d7abb3ff928d..0065b36cee5a 100644 --- a/drivers/flash/flash_stm32wbax.c +++ b/drivers/flash/flash_stm32wbax.c @@ -11,6 +11,7 @@ LOG_MODULE_REGISTER(LOG_DOMAIN); #include #include +#include #include #include #include @@ -35,89 +36,6 @@ LOG_MODULE_REGISTER(LOG_DOMAIN); #define BANK2_OFFSET (KB(STM32_SERIES_MAX_FLASH) / 2) -#define ICACHE_DISABLE_TIMEOUT_VALUE 1U /* 1ms */ -#define ICACHE_INVALIDATE_TIMEOUT_VALUE 1U /* 1ms */ - -static int stm32_icache_disable(void) -{ - int status = 0; - uint32_t tickstart; - - LOG_DBG("I-cache Disable"); - /* Clear BSYENDF flag first and then disable the instruction cache - * that starts a cache invalidation procedure - */ - CLEAR_BIT(ICACHE->FCR, ICACHE_FCR_CBSYENDF); - - LL_ICACHE_Disable(); - - /* Get tick */ - tickstart = k_uptime_get_32(); - - /* Wait for instruction cache to get disabled */ - while (LL_ICACHE_IsEnabled()) { - if ((k_uptime_get_32() - tickstart) > - ICACHE_DISABLE_TIMEOUT_VALUE) { - /* New check to avoid false timeout detection in case - * of preemption. - */ - if (LL_ICACHE_IsEnabled()) { - status = -ETIMEDOUT; - break; - } - } - } - - return status; -} - -static void stm32_icache_enable(void) -{ - LOG_DBG("I-cache Enable"); - LL_ICACHE_Enable(); -} - -static int icache_wait_for_invalidate_complete(void) -{ - int status = -EIO; - uint32_t tickstart; - - /* Check if ongoing invalidation operation */ - if (LL_ICACHE_IsActiveFlag_BUSY()) { - /* Get tick */ - tickstart = k_uptime_get_32(); - - /* Wait for end of cache invalidation */ - while (!LL_ICACHE_IsActiveFlag_BSYEND()) { - if ((k_uptime_get_32() - tickstart) > - ICACHE_INVALIDATE_TIMEOUT_VALUE) { - break; - } - } - } - - /* Clear any pending flags */ - if (LL_ICACHE_IsActiveFlag_BSYEND()) { - LOG_DBG("I-cache Invalidation complete"); - - LL_ICACHE_ClearFlag_BSYEND(); - status = 0; - } else { - LOG_ERR("I-cache Invalidation timeout"); - - status = -ETIMEDOUT; - } - - if (LL_ICACHE_IsActiveFlag_ERR()) { - LOG_ERR("I-cache error"); - - LL_ICACHE_ClearFlag_ERR(); - status = -EIO; - } - - return status; -} - /* * offset and len must be aligned on write-block-size for write, * positive and not beyond end of flash @@ -272,19 +190,15 @@ int flash_stm32_block_erase_loop(const struct device *dev, { unsigned int address = offset; int rc = 0; - bool icache_enabled = LL_ICACHE_IsEnabled(); - if (icache_enabled) { - /* Disable icache, this will start the invalidation procedure. - * All changes(erase/write) to flash memory should happen when - * i-cache is disabled. A write to flash performed without - * disabling i-cache will set ERRF error flag in SR register. - */ - rc = stm32_icache_disable(); - if (rc != 0) { - return rc; - } - } + /* Disable icache, this will start the invalidation procedure. + * All changes(erase/write) to flash memory should happen when + * i-cache is disabled. A write to flash performed without + * disabling i-cache will set ERRF error flag in SR register. + */ + bool cache_enabled = LL_ICACHE_IsEnabled(); + + sys_cache_instr_disable(); for (; address <= offset + len - 1 ; address += FLASH_PAGE_SIZE) { rc = erase_page(dev, address); @@ -293,16 +207,8 @@ int flash_stm32_block_erase_loop(const struct device *dev, } } - if (icache_enabled) { - /* Since i-cache was disabled, this would start the - * invalidation procedure, so wait for completion. - */ - rc = icache_wait_for_invalidate_complete(); - - /* I-cache should be enabled only after the - * invalidation is complete. - */ - stm32_icache_enable(); + if (cache_enabled) { + sys_cache_instr_enable(); } return rc; @@ -312,19 +218,15 @@ int flash_stm32_write_range(const struct device *dev, unsigned int offset, const void *data, unsigned int len) { int i, rc = 0; - bool icache_enabled = LL_ICACHE_IsEnabled(); - if (icache_enabled) { - /* Disable icache, this will start the invalidation procedure. - * All changes(erase/write) to flash memory should happen when - * i-cache is disabled. A write to flash performed without - * disabling i-cache will set ERRF error flag in SR register. - */ - rc = stm32_icache_disable(); - if (rc != 0) { - return rc; - } - } + /* Disable icache, this will start the invalidation procedure. + * All changes(erase/write) to flash memory should happen when + * i-cache is disabled. A write to flash performed without + * disabling i-cache will set ERRF error flag in SR register. + */ + bool cache_enabled = LL_ICACHE_IsEnabled(); + + sys_cache_instr_disable(); for (i = 0; i < len; i += 16) { rc = write_qword(dev, offset + i, ((const uint32_t *) data + (i>>2))); @@ -333,22 +235,8 @@ int flash_stm32_write_range(const struct device *dev, unsigned int offset, } } - if (icache_enabled) { - int rc2; - - /* Since i-cache was disabled, this would start the - * invalidation procedure, so wait for completion. - */ - rc2 = icache_wait_for_invalidate_complete(); - - if (!rc) { - rc = rc2; - } - - /* I-cache should be enabled only after the - * invalidation is complete. - */ - stm32_icache_enable(); + if (cache_enabled) { + sys_cache_instr_enable(); } return rc; diff --git a/drivers/hwinfo/hwinfo_stm32.c b/drivers/hwinfo/hwinfo_stm32.c index 1af82ec1c3c1..264b7eb11db7 100644 --- a/drivers/hwinfo/hwinfo_stm32.c +++ b/drivers/hwinfo/hwinfo_stm32.c @@ -8,7 +8,7 @@ #include #include #if defined(CONFIG_SOC_SERIES_STM32H5X) -#include +#include #endif /* CONFIG_SOC_SERIES_STM32H5X */ #include #include @@ -39,7 +39,7 @@ ssize_t z_impl_hwinfo_get_device_id(uint8_t *buffer, size_t length) struct stm32_uid dev_id; #if defined(CONFIG_SOC_SERIES_STM32H5X) - LL_ICACHE_Disable(); + sys_cache_instr_disable(); #endif /* CONFIG_SOC_SERIES_STM32H5X */ dev_id.id[0] = sys_cpu_to_be32(STM32_UID_WORD_2); @@ -47,7 +47,7 @@ ssize_t z_impl_hwinfo_get_device_id(uint8_t *buffer, size_t length) dev_id.id[2] = sys_cpu_to_be32(STM32_UID_WORD_0); #if defined(CONFIG_SOC_SERIES_STM32H5X) - LL_ICACHE_Enable(); + sys_cache_instr_enable(); #endif /* CONFIG_SOC_SERIES_STM32H5X */ if (length > sizeof(dev_id.id)) { diff --git a/drivers/sensor/st/stm32_temp/stm32_temp.c b/drivers/sensor/st/stm32_temp/stm32_temp.c index f6d70c96f590..d306caafb9e5 100644 --- a/drivers/sensor/st/stm32_temp/stm32_temp.c +++ b/drivers/sensor/st/stm32_temp/stm32_temp.c @@ -13,7 +13,7 @@ #include #include #if defined(CONFIG_SOC_SERIES_STM32H5X) -#include +#include #endif /* CONFIG_SOC_SERIES_STM32H5X */ LOG_MODULE_REGISTER(stm32_temp, CONFIG_SENSOR_LOG_LEVEL); @@ -105,7 +105,7 @@ static void read_calibration_data(const struct stm32_temp_config *cfg, * This is required on STM32H5, where the manufacturing flash must be * accessed in non-cacheable mode - otherwise, a bus error occurs. */ - LL_ICACHE_Disable(); + sys_cache_instr_disable(); #endif /* CONFIG_SOC_SERIES_STM32H5X */ calib_data[0] = fetch_mfg_data(cfg->ts_cal1_addr); @@ -116,7 +116,7 @@ static void read_calibration_data(const struct stm32_temp_config *cfg, #if defined(CONFIG_SOC_SERIES_STM32H5X) /* Re-enable the ICACHE (unconditonally - it should always be turned on) */ - LL_ICACHE_Enable(); + sys_cache_instr_enable(); #endif /* CONFIG_SOC_SERIES_STM32H5X */ } #endif /* HAS_CALIBRATION */ diff --git a/drivers/sensor/st/stm32_vref/stm32_vref.c b/drivers/sensor/st/stm32_vref/stm32_vref.c index 95148e45d6cb..2f2c847ea0b4 100644 --- a/drivers/sensor/st/stm32_vref/stm32_vref.c +++ b/drivers/sensor/st/stm32_vref/stm32_vref.c @@ -14,7 +14,7 @@ #include #include #if defined(CONFIG_SOC_SERIES_STM32H5X) -#include +#include #endif /* CONFIG_SOC_SERIES_STM32H5X */ LOG_MODULE_REGISTER(stm32_vref, CONFIG_SENSOR_LOG_LEVEL); @@ -103,14 +103,14 @@ static int stm32_vref_channel_get(const struct device *dev, enum sensor_channel * STM32H5X: accesses to flash RO region must be done with caching disabled. */ #if defined(CONFIG_SOC_SERIES_STM32H5X) - LL_ICACHE_Disable(); + sys_cache_instr_disable(); #endif /* CONFIG_SOC_SERIES_STM32H5X */ /* Calculate VREF+ using VREFINT bandgap voltage and calibration data */ vref = (cfg->cal_mv * ((*cfg->cal_addr) >> cfg->cal_shift)) / data->raw; #if defined(CONFIG_SOC_SERIES_STM32H5X) - LL_ICACHE_Enable(); + sys_cache_instr_enable(); #endif /* CONFIG_SOC_SERIES_STM32H5X */ return sensor_value_from_milli(val, vref);