arch/arm/stm32h5: map OTP, RO and EDATA flash non-cacheable.

The OTP, read-only (UID, flash size, package) and high-cycle data (EDATA)
flash areas only accept 16/32-bit accesses and return a bus error
otherwise (RM0481 Table 77).  The manual requires the MPU to disable local
cacheability for them (RM0481 7.3.2); with the ICACHE enabled and no such
region, reading them raises a precise bus error.

Until now this was worked around piecemeal: the driver disabled the
ICACHE around stm32_get_uniqueid() and the OTP and EDATA word reads, and
nucleo-h563zi mapped the 4 KB OTP/RO area non-cacheable in its board
code.  Other reads, for example stm32_otp_read() or an application
reading the OTP on another board, still raised a precise bus error when
the ICACHE was enabled.

Map 0x08fff000-0x09017fff, which covers the three contiguous areas, as
Normal non-cacheable and execute-never with a single MPU region before
the ICACHE is enabled.  STM32_ICACHE now selects ARM_MPU so that
stm32_mpuinitialize() has reset and enabled the MPU by then.

Remove the nucleo-h563zi OTP region in the same commit: the Armv8-M MPU
faults on an address that matches more than one region, so keeping both
would make OTP and UID reads fault on that board.

Assisted-by: Claude:claude-sonnet-5-5
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Ricardo Maurizio Paul <ricardopaul@geotab.com>
This commit is contained in:
Ricardo Maurizio Paul 2026-10-05 14:43:32 +02:00 • committed by Alan C. Assis
parent 6c3e9ad7b1
commit 3ff85acb4b
7 changed files with 34 additions and 67 deletions

View file

@ -324,6 +324,12 @@ config STM32_ICACHE
bool "ICACHE"
default n
depends on STM32_HAVE_ICACHE
select ARM_MPU
---help---
Enable the instruction cache (ICACHE) on the C-AHB bus. The OTP,
read-only and high-cycle data flash areas cannot be cached
(RM0481 7.3.2), so this option selects ARM_MPU and maps them
non-cacheable.
config STM32_DCACHE1
depends on STM32_HAVE_DCACHE1

View file

@ -34,6 +34,7 @@
#include <stdint.h>
#include "arm_internal.h"
#include "mpu.h"
#include "stm32.h"
/****************************************************************************
@ -43,6 +44,15 @@
#define STM32_ICACHE_INTERRUPT (defined(CONFIG_STM32_ICACHE_INV_INT) ||\
defined(CONFIG_STM32_ICACHE_ERR_INT))
/* The OTP (0x08fff000), read-only (0x08fff800, UID) and EDATA
* (0x09000000-0x09017fff) flash areas only accept 16/32-bit accesses
* (RM0481 Table 77) and must be mapped non-cacheable (RM0481 7.3.2). They
* are contiguous, so one MPU region covers them.
*/
#define STM32_ICACHE_NC_BASE 0x08fff000
#define STM32_ICACHE_NC_END 0x09018000
/****************************************************************************
* Private Types
****************************************************************************/
@ -238,12 +248,30 @@ static void stm32_icache_setup_region(struct stm32_icache_region region)
}
#endif
static void stm32_icache_mpu_setup(void)
{
/* Non-cacheable, execute-never. stm32_mpuinitialize() enabled the MPU. */
DEBUGASSERT((getreg32(MPU_CTRL) & MPU_CTRL_ENABLE) != 0);
mpu_configure_region(STM32_ICACHE_NC_BASE,
STM32_ICACHE_NC_END - STM32_ICACHE_NC_BASE,
MPU_RBAR_XN | MPU_RBAR_AP_RWRW | MPU_RBAR_SH_NO,
MPU_RLAR_NONCACHEABLE);
}
void stm32_icache_initialize(void)
{
#ifdef CONFIG_STM32_ICACHE_DIRECT
uint32_t regval;
#endif
/* The flash areas that cannot be cached must be excluded before the
* ICACHE is enabled.
*/
stm32_icache_mpu_setup();
/* Set associativity */
#ifdef CONFIG_STM32_ICACHE_DIRECT

View file

@ -52,10 +52,6 @@ if(CONFIG_STM32_USBFS_HOST)
list(APPEND SRCS stm32_usb.c)
endif()
if(CONFIG_ARM_MPU)
list(APPEND SRCS stm32_mpu.c)
endif()
target_sources(board PRIVATE ${SRCS})
set_property(GLOBAL PROPERTY LD_SCRIPT "${NUTTX_BOARD_DIR}/scripts/flash.ld")

View file

@ -58,10 +58,6 @@ ifeq ($(CONFIG_STM32_USBFS_HOST),y)
CSRCS += stm32_usb.c
endif
ifeq ($(CONFIG_ARM_MPU),y)
CSRCS += stm32_mpu.c
endif
DEPPATH += --dep-path board
VPATH += :board
CFLAGS += ${INCDIR_PREFIX}$(TOPDIR)$(DELIM)arch$(DELIM)$(CONFIG_ARCH)$(DELIM)src$(DELIM)board$(DELIM)board

View file

@ -115,18 +115,6 @@
int stm32_bringup(void);
/****************************************************************************
* Name: stm32_mpu_configure_otp
*
* Description:
* Initialize MPU and configure the OTP flash region.
*
****************************************************************************/
#if defined(CONFIG_ARM_MPU) && defined(CONFIG_STM32_ICACHE)
void stm32_mpu_configure_otp(void);
#endif
#ifdef CONFIG_STM32_SPI
/****************************************************************************
* Name: stm32_spiregister

View file

@ -53,12 +53,6 @@
void stm32_board_initialize(void)
{
#if defined(CONFIG_ARM_MPU) && defined(CONFIG_STM32_ICACHE)
/* Configure OTP MPU region. */
stm32_mpu_configure_otp();
#endif
#ifdef CONFIG_ARCH_LEDS
/* Configure on-board LEDs if LED support has been selected. */

View file

@ -1,41 +0,0 @@
/****************************************************************************
* boards/arm/stm32h5/nucleo-h563zi/src/stm32_mpu.c
*
* SPDX-License-Identifier: Apache-2.0
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <debug.h>
#include <errno.h>
#include <nuttx/arch.h>
#include "hardware/stm32_memorymap.h"
#include "mpu.h"
#include "stm32_mpuinit.h"
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: stm32_mpu_configure_otp
*
* Description:
* Configure the OTP flash region as non-cacheable, non-executable, non-
* shareable, and read-only.
*
****************************************************************************/
void stm32_mpu_configure_otp(void)
{
mpu_configure_region(STM32_OTP_BASE, 4096,
MPU_RBAR_XN | MPU_RBAR_SH_NO | MPU_RBAR_AP_RORO,
MPU_RLAR_NONCACHEABLE);
}