diff --git a/ports/stm32/mpu.h b/ports/stm32/mpu.h index c5881d8fde..2541d86bfb 100644 --- a/ports/stm32/mpu.h +++ b/ports/stm32/mpu.h @@ -29,6 +29,9 @@ #if defined(STM32F7) || defined(STM32H7) #define MPU_REGION_ETH (MPU_REGION_NUMBER0) +#define MPU_REGION_QSPI1 (MPU_REGION_NUMBER1) +#define MPU_REGION_QSPI2 (MPU_REGION_NUMBER2) +#define MPU_REGION_QSPI3 (MPU_REGION_NUMBER3) #define MPU_REGION_SDRAM1 (MPU_REGION_NUMBER4) #define MPU_REGION_SDRAM2 (MPU_REGION_NUMBER5) diff --git a/ports/stm32/qspi.c b/ports/stm32/qspi.c index 8c8b9c4940..8ed3a17dd5 100644 --- a/ports/stm32/qspi.c +++ b/ports/stm32/qspi.c @@ -28,11 +28,14 @@ #include "py/mperrno.h" #include "py/mphal.h" +#include "mpu.h" #include "qspi.h" #include "pin_static_af.h" #if defined(MICROPY_HW_QSPIFLASH_SIZE_BITS_LOG2) +#define QSPI_MAP_ADDR (0x90000000) + #ifndef MICROPY_HW_QSPI_PRESCALER #define MICROPY_HW_QSPI_PRESCALER 3 // F_CLK = F_AHB/3 (72MHz when CPU is 216MHz) #endif @@ -49,7 +52,31 @@ #define MICROPY_HW_QSPI_CS_HIGH_CYCLES 2 // nCS stays high for 2 cycles #endif +static inline void qspi_mpu_disable_all(void) { + // Configure MPU to disable access to entire QSPI region, to prevent CPU + // speculative execution from accessing this region and modifying QSPI registers. + mpu_config_start(); + mpu_config_region(MPU_REGION_QSPI1, QSPI_MAP_ADDR, MPU_CONFIG_DISABLE(0x00, MPU_REGION_SIZE_256MB)); + mpu_config_end(); +} + +static inline void qspi_mpu_enable_mapped(void) { + // Configure MPU to allow access to only the valid part of external SPI flash. + // The memory accesses to the mapped QSPI are faster if the MPU is not used + // for the memory-mapped region, so 3 MPU regions are used to disable access + // to everything except the valid address space, using holes in the bottom + // of the regions and nesting them. + // At the moment this is hard-coded to 2MiB of QSPI address space. + mpu_config_start(); + mpu_config_region(MPU_REGION_QSPI1, QSPI_MAP_ADDR, MPU_CONFIG_DISABLE(0x01, MPU_REGION_SIZE_256MB)); + mpu_config_region(MPU_REGION_QSPI2, QSPI_MAP_ADDR, MPU_CONFIG_DISABLE(0x0f, MPU_REGION_SIZE_32MB)); + mpu_config_region(MPU_REGION_QSPI3, QSPI_MAP_ADDR, MPU_CONFIG_DISABLE(0x01, MPU_REGION_SIZE_16MB)); + mpu_config_end(); +} + void qspi_init(void) { + qspi_mpu_disable_all(); + // Configure pins mp_hal_pin_config_alt_static_speed(MICROPY_HW_QSPIFLASH_CS, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_QUADSPI_BK1_NCS); mp_hal_pin_config_alt_static_speed(MICROPY_HW_QSPIFLASH_SCK, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_QUADSPI_CLK); @@ -100,6 +127,8 @@ void qspi_memory_map(void) { | 1 << QUADSPI_CCR_IMODE_Pos // instruction on 1 line | 0xeb << QUADSPI_CCR_INSTRUCTION_Pos // quad read opcode ; + + qspi_mpu_enable_mapped(); } STATIC int qspi_ioctl(void *self_in, uint32_t cmd) {