Skip to content

Commit

Permalink
Merge pull request #9783 from dhalbert/rp2350-nvm-write-flush-cache
Browse files Browse the repository at this point in the history
RP2350: need cache flush in microcontroller.nvm
  • Loading branch information
dhalbert authored Nov 2, 2024
2 parents e0256be + 3abd122 commit 24a8927
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 13 deletions.
7 changes: 7 additions & 0 deletions ports/raspberrypi/common-hal/nvm/ByteArray.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "py/runtime.h"
#include "src/rp2_common/hardware_flash/include/hardware/flash.h"
#include "shared-bindings/microcontroller/__init__.h"
#include "supervisor/internal_flash.h"

extern uint32_t __flash_binary_start;
static const uint32_t flash_binary_start = (uint32_t)&__flash_binary_start;
Expand All @@ -28,14 +29,18 @@ static void write_page(uint32_t page_addr, uint32_t offset, uint32_t len, uint8_
if (offset == 0 && len == FLASH_PAGE_SIZE) {
// disable interrupts to prevent core hang on rp2040
common_hal_mcu_disable_interrupts();
supervisor_flash_pre_write();
flash_range_program(RMV_OFFSET(page_addr), bytes, FLASH_PAGE_SIZE);
supervisor_flash_post_write();
common_hal_mcu_enable_interrupts();
} else {
uint8_t buffer[FLASH_PAGE_SIZE];
memcpy(buffer, (uint8_t *)page_addr, FLASH_PAGE_SIZE);
memcpy(buffer + offset, bytes, len);
common_hal_mcu_disable_interrupts();
supervisor_flash_pre_write();
flash_range_program(RMV_OFFSET(page_addr), buffer, FLASH_PAGE_SIZE);
supervisor_flash_post_write();
common_hal_mcu_enable_interrupts();
}

Expand All @@ -57,8 +62,10 @@ static void erase_and_write_sector(uint32_t address, uint32_t len, uint8_t *byte
memcpy(buffer + address, bytes, len);
// disable interrupts to prevent core hang on rp2040
common_hal_mcu_disable_interrupts();
supervisor_flash_pre_write();
flash_range_erase(RMV_OFFSET(CIRCUITPY_INTERNAL_NVM_START_ADDR), FLASH_SECTOR_SIZE);
flash_range_program(RMV_OFFSET(CIRCUITPY_INTERNAL_NVM_START_ADDR), buffer, FLASH_SECTOR_SIZE);
supervisor_flash_post_write();
common_hal_mcu_enable_interrupts();
}

Expand Down
33 changes: 20 additions & 13 deletions ports/raspberrypi/supervisor/internal_flash.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,30 +46,37 @@ static uint32_t m1_rfmt;
static uint32_t m1_timing;
#endif

static void save_psram_settings(void) {
static void __no_inline_not_in_flash_func(save_psram_settings)(void) {
#ifdef PICO_RP2350
// We're about to invalidate the XIP cache, clean it first to commit any dirty writes to PSRAM
volatile uint8_t *maintenance_ptr = (uint8_t *)XIP_MAINTENANCE_BASE;
for (int i = 1; i < 16 * 1024; i += 8) {
// Background info: https://forums.raspberrypi.com/viewtopic.php?t=378249
maintenance_ptr[i] = 0; // Clean
__compiler_memory_barrier();
maintenance_ptr[i - 1] = 0; // Explicitly invalidate
__compiler_memory_barrier();
// From https://forums.raspberrypi.com/viewtopic.php?t=378249#p2263677
// Perform clean-by-set/way on all lines
for (uint32_t i = 0; i < 2048; ++i) {
// Use the upper 16k of the maintenance space (0x1bffc000 through 0x1bffffff):
*(volatile uint8_t *)(XIP_SRAM_BASE + (XIP_MAINTENANCE_BASE - XIP_BASE) + i * 8u + 0x1u) = 0;
}

m1_timing = qmi_hw->m[1].timing;
m1_rfmt = qmi_hw->m[1].rfmt;
#endif
}

static void restore_psram_settings(void) {
static void __no_inline_not_in_flash_func(restore_psram_settings)(void) {
#ifdef PICO_RP2350
qmi_hw->m[1].timing = m1_timing;
qmi_hw->m[1].rfmt = m1_rfmt;
__compiler_memory_barrier();
#endif
}

void supervisor_flash_pre_write(void) {
save_psram_settings();
}

void supervisor_flash_post_write(void) {
restore_psram_settings();
}

void supervisor_flash_init(void) {
bi_decl_if_func_used(bi_block_device(
BINARY_INFO_MAKE_TAG('C', 'P'),
Expand All @@ -84,9 +91,9 @@ void supervisor_flash_init(void) {
// Read the RDID register to get the flash capacity.
uint8_t cmd[] = {0x9f, 0, 0, 0};
uint8_t data[4];
save_psram_settings();
supervisor_flash_pre_write();
flash_do_cmd(cmd, data, 4);
restore_psram_settings();
supervisor_flash_post_write();
uint8_t power_of_two = FLASH_DEFAULT_POWER_OF_TWO;
// Flash must be at least 2MB (1 << 21) because we use the first 1MB for the
// CircuitPython core. We validate the range because Adesto Tech flash chips
Expand Down Expand Up @@ -116,10 +123,10 @@ void port_internal_flash_flush(void) {
#if CIRCUITPY_AUDIOCORE
uint32_t channel_mask = audio_dma_pause_all();
#endif
save_psram_settings();
supervisor_flash_pre_write();
flash_range_erase(CIRCUITPY_CIRCUITPY_DRIVE_START_ADDR + _cache_lba, SECTOR_SIZE);
flash_range_program(CIRCUITPY_CIRCUITPY_DRIVE_START_ADDR + _cache_lba, _cache, SECTOR_SIZE);
restore_psram_settings();
supervisor_flash_post_write();
_cache_lba = NO_CACHE;
#if CIRCUITPY_AUDIOCORE
audio_dma_unpause_mask(channel_mask);
Expand Down
4 changes: 4 additions & 0 deletions ports/raspberrypi/supervisor/internal_flash.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@

#include "mpconfigport.h"

// These must be called before and after doing a low-level flash write.
void supervisor_flash_pre_write(void);
void supervisor_flash_post_write(void);

// #define INTERNAL_FLASH_PART1_NUM_BLOCKS (CIRCUITPY_INTERNAL_FLASH_FILESYSTEM_SIZE / FILESYSTEM_BLOCK_SIZE)

// #define INTERNAL_FLASH_SYSTICK_MASK (0x1ff) // 512ms
Expand Down

0 comments on commit 24a8927

Please sign in to comment.