Skip to content

Commit 24a8927

Browse files
authored
Merge pull request #9783 from dhalbert/rp2350-nvm-write-flush-cache
RP2350: need cache flush in microcontroller.nvm
2 parents e0256be + 3abd122 commit 24a8927

File tree

3 files changed

+31
-13
lines changed

3 files changed

+31
-13
lines changed

ports/raspberrypi/common-hal/nvm/ByteArray.c

+7
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "py/runtime.h"
1313
#include "src/rp2_common/hardware_flash/include/hardware/flash.h"
1414
#include "shared-bindings/microcontroller/__init__.h"
15+
#include "supervisor/internal_flash.h"
1516

1617
extern uint32_t __flash_binary_start;
1718
static const uint32_t flash_binary_start = (uint32_t)&__flash_binary_start;
@@ -28,14 +29,18 @@ static void write_page(uint32_t page_addr, uint32_t offset, uint32_t len, uint8_
2829
if (offset == 0 && len == FLASH_PAGE_SIZE) {
2930
// disable interrupts to prevent core hang on rp2040
3031
common_hal_mcu_disable_interrupts();
32+
supervisor_flash_pre_write();
3133
flash_range_program(RMV_OFFSET(page_addr), bytes, FLASH_PAGE_SIZE);
34+
supervisor_flash_post_write();
3235
common_hal_mcu_enable_interrupts();
3336
} else {
3437
uint8_t buffer[FLASH_PAGE_SIZE];
3538
memcpy(buffer, (uint8_t *)page_addr, FLASH_PAGE_SIZE);
3639
memcpy(buffer + offset, bytes, len);
3740
common_hal_mcu_disable_interrupts();
41+
supervisor_flash_pre_write();
3842
flash_range_program(RMV_OFFSET(page_addr), buffer, FLASH_PAGE_SIZE);
43+
supervisor_flash_post_write();
3944
common_hal_mcu_enable_interrupts();
4045
}
4146

@@ -57,8 +62,10 @@ static void erase_and_write_sector(uint32_t address, uint32_t len, uint8_t *byte
5762
memcpy(buffer + address, bytes, len);
5863
// disable interrupts to prevent core hang on rp2040
5964
common_hal_mcu_disable_interrupts();
65+
supervisor_flash_pre_write();
6066
flash_range_erase(RMV_OFFSET(CIRCUITPY_INTERNAL_NVM_START_ADDR), FLASH_SECTOR_SIZE);
6167
flash_range_program(RMV_OFFSET(CIRCUITPY_INTERNAL_NVM_START_ADDR), buffer, FLASH_SECTOR_SIZE);
68+
supervisor_flash_post_write();
6269
common_hal_mcu_enable_interrupts();
6370
}
6471

ports/raspberrypi/supervisor/internal_flash.c

+20-13
Original file line numberDiff line numberDiff line change
@@ -46,30 +46,37 @@ static uint32_t m1_rfmt;
4646
static uint32_t m1_timing;
4747
#endif
4848

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

6159
m1_timing = qmi_hw->m[1].timing;
6260
m1_rfmt = qmi_hw->m[1].rfmt;
6361
#endif
6462
}
6563

66-
static void restore_psram_settings(void) {
64+
static void __no_inline_not_in_flash_func(restore_psram_settings)(void) {
6765
#ifdef PICO_RP2350
6866
qmi_hw->m[1].timing = m1_timing;
6967
qmi_hw->m[1].rfmt = m1_rfmt;
68+
__compiler_memory_barrier();
7069
#endif
7170
}
7271

72+
void supervisor_flash_pre_write(void) {
73+
save_psram_settings();
74+
}
75+
76+
void supervisor_flash_post_write(void) {
77+
restore_psram_settings();
78+
}
79+
7380
void supervisor_flash_init(void) {
7481
bi_decl_if_func_used(bi_block_device(
7582
BINARY_INFO_MAKE_TAG('C', 'P'),
@@ -84,9 +91,9 @@ void supervisor_flash_init(void) {
8491
// Read the RDID register to get the flash capacity.
8592
uint8_t cmd[] = {0x9f, 0, 0, 0};
8693
uint8_t data[4];
87-
save_psram_settings();
94+
supervisor_flash_pre_write();
8895
flash_do_cmd(cmd, data, 4);
89-
restore_psram_settings();
96+
supervisor_flash_post_write();
9097
uint8_t power_of_two = FLASH_DEFAULT_POWER_OF_TWO;
9198
// Flash must be at least 2MB (1 << 21) because we use the first 1MB for the
9299
// CircuitPython core. We validate the range because Adesto Tech flash chips
@@ -116,10 +123,10 @@ void port_internal_flash_flush(void) {
116123
#if CIRCUITPY_AUDIOCORE
117124
uint32_t channel_mask = audio_dma_pause_all();
118125
#endif
119-
save_psram_settings();
126+
supervisor_flash_pre_write();
120127
flash_range_erase(CIRCUITPY_CIRCUITPY_DRIVE_START_ADDR + _cache_lba, SECTOR_SIZE);
121128
flash_range_program(CIRCUITPY_CIRCUITPY_DRIVE_START_ADDR + _cache_lba, _cache, SECTOR_SIZE);
122-
restore_psram_settings();
129+
supervisor_flash_post_write();
123130
_cache_lba = NO_CACHE;
124131
#if CIRCUITPY_AUDIOCORE
125132
audio_dma_unpause_mask(channel_mask);

ports/raspberrypi/supervisor/internal_flash.h

+4
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99

1010
#include "mpconfigport.h"
1111

12+
// These must be called before and after doing a low-level flash write.
13+
void supervisor_flash_pre_write(void);
14+
void supervisor_flash_post_write(void);
15+
1216
// #define INTERNAL_FLASH_PART1_NUM_BLOCKS (CIRCUITPY_INTERNAL_FLASH_FILESYSTEM_SIZE / FILESYSTEM_BLOCK_SIZE)
1317

1418
// #define INTERNAL_FLASH_SYSTICK_MASK (0x1ff) // 512ms

0 commit comments

Comments
 (0)