|
33 | 33 | #include "modrp2.h"
|
34 | 34 | #include "hardware/flash.h"
|
35 | 35 | #include "pico/binary_info.h"
|
| 36 | +#include "rp2_psram.h" |
36 | 37 |
|
37 | 38 | #define BLOCK_SIZE_BYTES (FLASH_SECTOR_SIZE)
|
38 | 39 |
|
| 40 | +// Size of buffer for flash writes from PSRAM, since they are mutually exclusive |
| 41 | +#define COPY_BUFFER_SIZE_BYTES (FLASH_PAGE_SIZE) |
| 42 | + |
39 | 43 | static_assert(MICROPY_HW_ROMFS_BYTES % 4096 == 0, "ROMFS size must be a multiple of 4K");
|
40 | 44 | static_assert(MICROPY_HW_FLASH_STORAGE_BYTES % 4096 == 0, "Flash storage size must be a multiple of 4K");
|
41 | 45 |
|
@@ -96,10 +100,27 @@ static uint32_t begin_critical_flash_section(void) {
|
96 | 100 | if (use_multicore_lockout()) {
|
97 | 101 | multicore_lockout_start_blocking();
|
98 | 102 | }
|
99 |
| - return save_and_disable_interrupts(); |
| 103 | + uint32_t state = save_and_disable_interrupts(); |
| 104 | + |
| 105 | + #if MICROPY_HW_ENABLE_PSRAM |
| 106 | + // We're about to invalidate the XIP cache, clean it first to commit any dirty writes to PSRAM |
| 107 | + // Use the upper 16k of the maintenance space (0x1bffc000 through 0x1bffffff) to workaround |
| 108 | + // incorrect behaviour of the XIP clean operation, where it also alters the tag of the associated |
| 109 | + // cache line: https://forums.raspberrypi.com/viewtopic.php?t=378249#p2263677 |
| 110 | + volatile uint8_t *maintenance_ptr = (volatile uint8_t *)(XIP_SRAM_BASE + (XIP_MAINTENANCE_BASE - XIP_BASE)); |
| 111 | + for (int i = 1; i < 16 * 1024; i += 8) { |
| 112 | + maintenance_ptr[i] = 0; |
| 113 | + } |
| 114 | + #endif |
| 115 | + |
| 116 | + return state; |
100 | 117 | }
|
101 | 118 |
|
102 | 119 | static void end_critical_flash_section(uint32_t state) {
|
| 120 | + #if MICROPY_HW_ENABLE_PSRAM |
| 121 | + // The ROM function to program flash will reset PSRAM timings to defaults |
| 122 | + psram_init(MICROPY_HW_PSRAM_CS_PIN); |
| 123 | + #endif |
103 | 124 | restore_interrupts(state);
|
104 | 125 | if (use_multicore_lockout()) {
|
105 | 126 | multicore_lockout_end_blocking();
|
@@ -192,10 +213,43 @@ static mp_obj_t rp2_flash_writeblocks(size_t n_args, const mp_obj_t *args) {
|
192 | 213 | } else {
|
193 | 214 | offset += mp_obj_get_int(args[3]);
|
194 | 215 | }
|
195 |
| - mp_uint_t atomic_state = begin_critical_flash_section(); |
196 |
| - flash_range_program(self->flash_base + offset, bufinfo.buf, bufinfo.len); |
197 |
| - end_critical_flash_section(atomic_state); |
198 |
| - mp_event_handle_nowait(); |
| 216 | + |
| 217 | + // If copying from SRAM, can write direct to flash. |
| 218 | + // If copying from PSRAM/flash, use an SRAM buffer and write in chunks. |
| 219 | + #if MICROPY_HW_ENABLE_PSRAM |
| 220 | + bool write_direct = (uintptr_t)bufinfo.buf >= SRAM_BASE; |
| 221 | + #else |
| 222 | + bool write_direct = true; |
| 223 | + #endif |
| 224 | + |
| 225 | + if (write_direct) { |
| 226 | + // If copying from SRAM, write direct |
| 227 | + mp_uint_t atomic_state = begin_critical_flash_section(); |
| 228 | + flash_range_program(self->flash_base + offset, bufinfo.buf, bufinfo.len); |
| 229 | + end_critical_flash_section(atomic_state); |
| 230 | + mp_event_handle_nowait(); |
| 231 | + } |
| 232 | + #if MICROPY_HW_ENABLE_PSRAM |
| 233 | + else { |
| 234 | + size_t bytes_left = bufinfo.len; |
| 235 | + size_t bytes_offset = 0; |
| 236 | + static uint8_t copy_buffer[COPY_BUFFER_SIZE_BYTES] = {0}; |
| 237 | + |
| 238 | + while (bytes_left) { |
| 239 | + memcpy(copy_buffer, bufinfo.buf + bytes_offset, MIN(bytes_left, COPY_BUFFER_SIZE_BYTES)); |
| 240 | + mp_uint_t atomic_state = begin_critical_flash_section(); |
| 241 | + flash_range_program(self->flash_base + offset + bytes_offset, copy_buffer, MIN(bytes_left, COPY_BUFFER_SIZE_BYTES)); |
| 242 | + end_critical_flash_section(atomic_state); |
| 243 | + bytes_offset += COPY_BUFFER_SIZE_BYTES; |
| 244 | + if (bytes_left <= COPY_BUFFER_SIZE_BYTES) { |
| 245 | + break; |
| 246 | + } |
| 247 | + bytes_left -= COPY_BUFFER_SIZE_BYTES; |
| 248 | + mp_event_handle_nowait(); |
| 249 | + } |
| 250 | + } |
| 251 | + #endif |
| 252 | + |
199 | 253 | // TODO check return value
|
200 | 254 | return mp_const_none;
|
201 | 255 | }
|
|
0 commit comments