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
@@ -70,16 +77,75 @@ bi_decl(bi_block_device(
7077 BINARY_INFO_BLOCK_DEV_FLAG_WRITE |
7178 BINARY_INFO_BLOCK_DEV_FLAG_PT_UNKNOWN ));
7279
80+ // Function to set the flash divisor to the correct divisor, assumes interrupts disabled
81+ // and core1 locked out if relevant.
82+ static void __no_inline_not_in_flash_func (rp2_flash_set_timing_internal )(int clock_hz ) {
83+
84+ // Use the minimum divisor assuming a 133MHz flash.
85+ const int max_flash_freq = 133000000 ;
86+ int divisor = (clock_hz + max_flash_freq - 1 ) / max_flash_freq ;
87+
88+ #if PICO_RP2350
89+ // Make sure flash is deselected - QMI doesn't appear to have a busy flag(!)
90+ while ((ioqspi_hw -> io [1 ].status & IO_QSPI_GPIO_QSPI_SS_STATUS_OUTTOPAD_BITS ) != IO_QSPI_GPIO_QSPI_SS_STATUS_OUTTOPAD_BITS ) {
91+ ;
92+ }
93+
94+ // RX delay equal to the divisor means sampling at the same time as the next falling edge of SCK after the
95+ // falling edge that generated the data. This is pretty tight at 133MHz but seems to work with the Winbond flash chips.
96+ const int rxdelay = divisor ;
97+ qmi_hw -> m [0 ].timing = (1 << QMI_M0_TIMING_COOLDOWN_LSB ) |
98+ rxdelay << QMI_M1_TIMING_RXDELAY_LSB |
99+ divisor << QMI_M1_TIMING_CLKDIV_LSB ;
100+
101+ // Force a read through XIP to ensure the timing is applied
102+ volatile uint32_t * ptr = (volatile uint32_t * )0x14000000 ;
103+ (void )* ptr ;
104+ #else
105+ // RP2040 SSI hardware only supports even divisors
106+ if (divisor & 1 ) {
107+ divisor += 1 ;
108+ }
109+
110+ // Wait for SSI not busy
111+ while (ssi_hw -> sr & SSI_SR_BUSY_BITS ) {
112+ ;
113+ }
114+
115+ // Disable, set the new divisor, and re-enable
116+ hw_clear_bits (& ssi_hw -> ssienr , SSI_SSIENR_SSI_EN_BITS );
117+ ssi_hw -> baudr = divisor ;
118+ hw_set_bits (& ssi_hw -> ssienr , SSI_SSIENR_SSI_EN_BITS );
119+ #endif
120+ }
121+
73122// Flash erase and write must run with interrupts disabled and the other core suspended,
74123// because the XIP bit gets disabled.
75124static uint32_t begin_critical_flash_section (void ) {
76125 if (multicore_lockout_victim_is_initialized (1 - get_core_num ())) {
77126 multicore_lockout_start_blocking ();
78127 }
79- return save_and_disable_interrupts ();
128+ uint32_t state = save_and_disable_interrupts ();
129+
130+ #if defined(MICROPY_HW_PSRAM_CS_PIN ) && MICROPY_HW_ENABLE_PSRAM
131+ // We're about to invalidate the XIP cache, clean it first to commit any dirty writes to PSRAM
132+ // Use the upper 16k of the maintenance space (0x1bffc000 through 0x1bffffff) to workaround
133+ // incorrect behaviour of the XIP clean operation, where it also alters the tag of the associated
134+ // cache line: https://forums.raspberrypi.com/viewtopic.php?t=378249#p2263677
135+ volatile uint8_t * maintenance_ptr = (volatile uint8_t * )(XIP_SRAM_BASE + (XIP_MAINTENANCE_BASE - XIP_BASE ));
136+ for (int i = 1 ; i < 16 * 1024 ; i += 8 ) {
137+ maintenance_ptr [i ] = 0 ;
138+ }
139+ #endif
140+
141+ return state ;
80142}
81143
82144static void end_critical_flash_section (uint32_t state ) {
145+ rp2_flash_set_timing_internal (clock_get_hz (clk_sys ));
146+ #if defined(MICROPY_HW_PSRAM_CS_PIN ) && MICROPY_HW_ENABLE_PSRAM
147+ psram_init (MICROPY_HW_PSRAM_CS_PIN );
148+ #endif
83149 restore_interrupts (state );
84150 if (multicore_lockout_victim_is_initialized (1 - get_core_num ())) {
85151 multicore_lockout_end_blocking ();
@@ -145,11 +211,16 @@ static mp_obj_t rp2_flash_readblocks(size_t n_args, const mp_obj_t *args) {
145211}
146212static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (rp2_flash_readblocks_obj , 3 , 4 , rp2_flash_readblocks ) ;
147213
214+ static inline size_t min_size (size_t a , size_t b ) {
215+ return a < b ? a : b ;
216+ }
217+
148218static mp_obj_t rp2_flash_writeblocks (size_t n_args , const mp_obj_t * args ) {
149219 rp2_flash_obj_t * self = MP_OBJ_TO_PTR (args [0 ]);
150220 uint32_t offset = mp_obj_get_int (args [1 ]) * BLOCK_SIZE_BYTES ;
151221 mp_buffer_info_t bufinfo ;
152222 mp_get_buffer_raise (args [2 ], & bufinfo , MP_BUFFER_READ );
223+
153224 if (n_args == 3 ) {
154225 mp_uint_t atomic_state = begin_critical_flash_section ();
155226 flash_range_erase (self -> flash_base + offset , bufinfo .len );
@@ -159,10 +230,31 @@ static mp_obj_t rp2_flash_writeblocks(size_t n_args, const mp_obj_t *args) {
159230 } else {
160231 offset += mp_obj_get_int (args [3 ]);
161232 }
162- mp_uint_t atomic_state = begin_critical_flash_section ();
163- flash_range_program (self -> flash_base + offset , bufinfo .buf , bufinfo .len );
164- end_critical_flash_section (atomic_state );
165- mp_event_handle_nowait ();
233+
234+ if ((uintptr_t )bufinfo .buf >= SRAM_BASE ) {
235+ mp_uint_t atomic_state = begin_critical_flash_section ();
236+ flash_range_program (self -> flash_base + offset , bufinfo .buf , bufinfo .len );
237+ end_critical_flash_section (atomic_state );
238+ mp_event_handle_nowait ();
239+ } else {
240+ size_t bytes_left = bufinfo .len ;
241+ size_t bytes_offset = 0 ;
242+ static uint8_t copy_buffer [BLOCK_SIZE_BYTES ] = {0 };
243+
244+ while (bytes_left ) {
245+ memcpy (copy_buffer , bufinfo .buf + bytes_offset , min_size (bytes_left , BLOCK_SIZE_BYTES ));
246+ mp_uint_t atomic_state = begin_critical_flash_section ();
247+ flash_range_program (self -> flash_base + offset + bytes_offset , copy_buffer , min_size (bytes_left , BLOCK_SIZE_BYTES ));
248+ end_critical_flash_section (atomic_state );
249+ bytes_offset += BLOCK_SIZE_BYTES ;
250+ if (bytes_left <= BLOCK_SIZE_BYTES ) {
251+ break ;
252+ }
253+ bytes_left -= BLOCK_SIZE_BYTES ;
254+ mp_event_handle_nowait ();
255+ }
256+ }
257+
166258 // TODO check return value
167259 return mp_const_none ;
168260}
@@ -210,3 +302,23 @@ MP_DEFINE_CONST_OBJ_TYPE(
210302 make_new , rp2_flash_make_new ,
211303 locals_dict , & rp2_flash_locals_dict
212304 );
305+
306+ // Modify the flash timing. Ensure flash access is suspended while
307+ // the timings are altered.
308+ void rp2_flash_set_timing_for_freq (int clock_hz ) {
309+ if (multicore_lockout_victim_is_initialized (1 - get_core_num ())) {
310+ multicore_lockout_start_blocking ();
311+ }
312+ uint32_t state = save_and_disable_interrupts ();
313+
314+ rp2_flash_set_timing_internal (clock_hz );
315+
316+ restore_interrupts (state );
317+ if (multicore_lockout_victim_is_initialized (1 - get_core_num ())) {
318+ multicore_lockout_end_blocking ();
319+ }
320+ }
321+
322+ void rp2_flash_set_timing () {
323+ rp2_flash_set_timing_for_freq (clock_get_hz (clk_sys ));
324+ }
0 commit comments