2626
2727#include <string.h>
2828
29+ #include "rp2_psram.h"
2930#include "py/mphal.h"
3031#include "py/runtime.h"
3132#include "extmod/vfs.h"
3233#include "modrp2.h"
3334#include "hardware/flash.h"
3435#include "pico/binary_info.h"
36+ #ifdef PICO_RP2350
37+ #include "hardware/structs/ioqspi.h"
38+ #include "hardware/structs/qmi.h"
39+ #else
40+ #include "hardware/structs/ssi.h"
41+ #endif
3542
3643#define BLOCK_SIZE_BYTES (FLASH_SECTOR_SIZE)
3744
@@ -80,16 +87,75 @@ static bool use_multicore_lockout(void) {
8087 ;
8188}
8289
90+ // Function to set the flash divisor to the correct divisor, assumes interrupts disabled
91+ // and core1 locked out if relevant.
92+ static void __no_inline_not_in_flash_func (rp2_flash_set_timing_internal )(int clock_hz ) {
93+
94+ // Use the minimum divisor assuming a 133MHz flash.
95+ const int max_flash_freq = 133000000 ;
96+ int divisor = (clock_hz + max_flash_freq - 1 ) / max_flash_freq ;
97+
98+ #if PICO_RP2350
99+ // Make sure flash is deselected - QMI doesn't appear to have a busy flag(!)
100+ while ((ioqspi_hw -> io [1 ].status & IO_QSPI_GPIO_QSPI_SS_STATUS_OUTTOPAD_BITS ) != IO_QSPI_GPIO_QSPI_SS_STATUS_OUTTOPAD_BITS ) {
101+ ;
102+ }
103+
104+ // RX delay equal to the divisor means sampling at the same time as the next falling edge of SCK after the
105+ // falling edge that generated the data. This is pretty tight at 133MHz but seems to work with the Winbond flash chips.
106+ const int rxdelay = divisor ;
107+ qmi_hw -> m [0 ].timing = (1 << QMI_M0_TIMING_COOLDOWN_LSB ) |
108+ rxdelay << QMI_M1_TIMING_RXDELAY_LSB |
109+ divisor << QMI_M1_TIMING_CLKDIV_LSB ;
110+
111+ // Force a read through XIP to ensure the timing is applied
112+ volatile uint32_t * ptr = (volatile uint32_t * )0x14000000 ;
113+ (void )* ptr ;
114+ #else
115+ // RP2040 SSI hardware only supports even divisors
116+ if (divisor & 1 ) {
117+ divisor += 1 ;
118+ }
119+
120+ // Wait for SSI not busy
121+ while (ssi_hw -> sr & SSI_SR_BUSY_BITS ) {
122+ ;
123+ }
124+
125+ // Disable, set the new divisor, and re-enable
126+ hw_clear_bits (& ssi_hw -> ssienr , SSI_SSIENR_SSI_EN_BITS );
127+ ssi_hw -> baudr = divisor ;
128+ hw_set_bits (& ssi_hw -> ssienr , SSI_SSIENR_SSI_EN_BITS );
129+ #endif
130+ }
131+
83132// Flash erase and write must run with interrupts disabled and the other core suspended,
84133// because the XIP bit gets disabled.
85134static uint32_t begin_critical_flash_section (void ) {
86135 if (use_multicore_lockout ()) {
87136 multicore_lockout_start_blocking ();
88137 }
89- return save_and_disable_interrupts ();
138+ uint32_t state = save_and_disable_interrupts ();
139+
140+ #if defined(MICROPY_HW_PSRAM_CS_PIN ) && MICROPY_HW_ENABLE_PSRAM
141+ // We're about to invalidate the XIP cache, clean it first to commit any dirty writes to PSRAM
142+ // Use the upper 16k of the maintenance space (0x1bffc000 through 0x1bffffff) to workaround
143+ // incorrect behaviour of the XIP clean operation, where it also alters the tag of the associated
144+ // cache line: https://forums.raspberrypi.com/viewtopic.php?t=378249#p2263677
145+ volatile uint8_t * maintenance_ptr = (volatile uint8_t * )(XIP_SRAM_BASE + (XIP_MAINTENANCE_BASE - XIP_BASE ));
146+ for (int i = 1 ; i < 16 * 1024 ; i += 8 ) {
147+ maintenance_ptr [i ] = 0 ;
148+ }
149+ #endif
150+
151+ return state ;
90152}
91153
92154static void end_critical_flash_section (uint32_t state ) {
155+ rp2_flash_set_timing_internal (clock_get_hz (clk_sys ));
156+ #if defined(MICROPY_HW_PSRAM_CS_PIN ) && MICROPY_HW_ENABLE_PSRAM
157+ psram_init (MICROPY_HW_PSRAM_CS_PIN );
158+ #endif
93159 restore_interrupts (state );
94160 if (use_multicore_lockout ()) {
95161 multicore_lockout_end_blocking ();
@@ -155,11 +221,16 @@ static mp_obj_t rp2_flash_readblocks(size_t n_args, const mp_obj_t *args) {
155221}
156222static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (rp2_flash_readblocks_obj , 3 , 4 , rp2_flash_readblocks ) ;
157223
224+ static inline size_t min_size (size_t a , size_t b ) {
225+ return a < b ? a : b ;
226+ }
227+
158228static mp_obj_t rp2_flash_writeblocks (size_t n_args , const mp_obj_t * args ) {
159229 rp2_flash_obj_t * self = MP_OBJ_TO_PTR (args [0 ]);
160230 uint32_t offset = mp_obj_get_int (args [1 ]) * BLOCK_SIZE_BYTES ;
161231 mp_buffer_info_t bufinfo ;
162232 mp_get_buffer_raise (args [2 ], & bufinfo , MP_BUFFER_READ );
233+
163234 if (n_args == 3 ) {
164235 mp_uint_t atomic_state = begin_critical_flash_section ();
165236 flash_range_erase (self -> flash_base + offset , bufinfo .len );
@@ -169,10 +240,31 @@ static mp_obj_t rp2_flash_writeblocks(size_t n_args, const mp_obj_t *args) {
169240 } else {
170241 offset += mp_obj_get_int (args [3 ]);
171242 }
172- mp_uint_t atomic_state = begin_critical_flash_section ();
173- flash_range_program (self -> flash_base + offset , bufinfo .buf , bufinfo .len );
174- end_critical_flash_section (atomic_state );
175- mp_event_handle_nowait ();
243+
244+ if ((uintptr_t )bufinfo .buf >= SRAM_BASE ) {
245+ mp_uint_t atomic_state = begin_critical_flash_section ();
246+ flash_range_program (self -> flash_base + offset , bufinfo .buf , bufinfo .len );
247+ end_critical_flash_section (atomic_state );
248+ mp_event_handle_nowait ();
249+ } else {
250+ size_t bytes_left = bufinfo .len ;
251+ size_t bytes_offset = 0 ;
252+ static uint8_t copy_buffer [BLOCK_SIZE_BYTES ] = {0 };
253+
254+ while (bytes_left ) {
255+ memcpy (copy_buffer , bufinfo .buf + bytes_offset , min_size (bytes_left , BLOCK_SIZE_BYTES ));
256+ mp_uint_t atomic_state = begin_critical_flash_section ();
257+ flash_range_program (self -> flash_base + offset + bytes_offset , copy_buffer , min_size (bytes_left , BLOCK_SIZE_BYTES ));
258+ end_critical_flash_section (atomic_state );
259+ bytes_offset += BLOCK_SIZE_BYTES ;
260+ if (bytes_left <= BLOCK_SIZE_BYTES ) {
261+ break ;
262+ }
263+ bytes_left -= BLOCK_SIZE_BYTES ;
264+ mp_event_handle_nowait ();
265+ }
266+ }
267+
176268 // TODO check return value
177269 return mp_const_none ;
178270}
@@ -220,3 +312,23 @@ MP_DEFINE_CONST_OBJ_TYPE(
220312 make_new , rp2_flash_make_new ,
221313 locals_dict , & rp2_flash_locals_dict
222314 );
315+
316+ // Modify the flash timing. Ensure flash access is suspended while
317+ // the timings are altered.
318+ void rp2_flash_set_timing_for_freq (int clock_hz ) {
319+ if (multicore_lockout_victim_is_initialized (1 - get_core_num ())) {
320+ multicore_lockout_start_blocking ();
321+ }
322+ uint32_t state = save_and_disable_interrupts ();
323+
324+ rp2_flash_set_timing_internal (clock_hz );
325+
326+ restore_interrupts (state );
327+ if (multicore_lockout_victim_is_initialized (1 - get_core_num ())) {
328+ multicore_lockout_end_blocking ();
329+ }
330+ }
331+
332+ void rp2_flash_set_timing () {
333+ rp2_flash_set_timing_for_freq (clock_get_hz (clk_sys ));
334+ }
0 commit comments