3434#include "modrp2.h"
3535#include "hardware/flash.h"
3636#include "pico/binary_info.h"
37+ #ifdef PICO_RP2350
38+ #include "hardware/structs/ioqspi.h"
39+ #include "hardware/structs/qmi.h"
40+ #else
41+ #include "hardware/structs/ssi.h"
42+ #endif
3743
3844#define BLOCK_SIZE_BYTES (FLASH_SECTOR_SIZE)
3945
@@ -91,6 +97,48 @@ static bool use_multicore_lockout(void) {
9197 ;
9298}
9399
100+ // Function to set the flash divisor to the correct divisor, assumes interrupts disabled
101+ // and core1 locked out if relevant.
102+ static void __no_inline_not_in_flash_func (rp2_flash_set_timing_internal )(int clock_hz ) {
103+
104+ // Use the minimum divisor assuming a 133MHz flash.
105+ const int max_flash_freq = 133000000 ;
106+ int divisor = (clock_hz + max_flash_freq - 1 ) / max_flash_freq ;
107+
108+ #if PICO_RP2350
109+ // Make sure flash is deselected - QMI doesn't appear to have a busy flag(!)
110+ while ((ioqspi_hw -> io [1 ].status & IO_QSPI_GPIO_QSPI_SS_STATUS_OUTTOPAD_BITS ) != IO_QSPI_GPIO_QSPI_SS_STATUS_OUTTOPAD_BITS ) {
111+ ;
112+ }
113+
114+ // RX delay equal to the divisor means sampling at the same time as the next falling edge of SCK after the
115+ // falling edge that generated the data. This is pretty tight at 133MHz but seems to work with the Winbond flash chips.
116+ const int rxdelay = divisor ;
117+ qmi_hw -> m [0 ].timing = (1 << QMI_M0_TIMING_COOLDOWN_LSB ) |
118+ rxdelay << QMI_M1_TIMING_RXDELAY_LSB |
119+ divisor << QMI_M1_TIMING_CLKDIV_LSB ;
120+
121+ // Force a read through XIP to ensure the timing is applied
122+ volatile uint32_t * ptr = (volatile uint32_t * )0x14000000 ;
123+ (void )* ptr ;
124+ #else
125+ // RP2040 SSI hardware only supports even divisors
126+ if (divisor & 1 ) {
127+ divisor += 1 ;
128+ }
129+
130+ // Wait for SSI not busy
131+ while (ssi_hw -> sr & SSI_SR_BUSY_BITS ) {
132+ ;
133+ }
134+
135+ // Disable, set the new divisor, and re-enable
136+ hw_clear_bits (& ssi_hw -> ssienr , SSI_SSIENR_SSI_EN_BITS );
137+ ssi_hw -> baudr = divisor ;
138+ hw_set_bits (& ssi_hw -> ssienr , SSI_SSIENR_SSI_EN_BITS );
139+ #endif
140+ }
141+
94142// Flash erase and write must run with interrupts disabled and the other core suspended,
95143// because the XIP bit gets disabled.
96144static uint32_t begin_critical_flash_section (void ) {
@@ -114,6 +162,7 @@ static void end_critical_flash_section(uint32_t state) {
114162 #if defined(MICROPY_HW_PSRAM_CS_PIN ) && MICROPY_HW_ENABLE_PSRAM
115163 psram_init (MICROPY_HW_PSRAM_CS_PIN );
116164 #endif
165+ rp2_flash_set_timing_internal (clock_get_hz (clk_sys ));
117166 restore_interrupts (state );
118167 if (use_multicore_lockout ()) {
119168 multicore_lockout_end_blocking ();
@@ -299,3 +348,23 @@ mp_obj_t mp_vfs_rom_ioctl(size_t n_args, const mp_obj_t *args) {
299348 }
300349}
301350#endif
351+
352+ // Modify the flash timing. Ensure flash access is suspended while
353+ // the timings are altered.
354+ void rp2_flash_set_timing_for_freq (int clock_hz ) {
355+ if (multicore_lockout_victim_is_initialized (1 - get_core_num ())) {
356+ multicore_lockout_start_blocking ();
357+ }
358+ uint32_t state = save_and_disable_interrupts ();
359+
360+ rp2_flash_set_timing_internal (clock_hz );
361+
362+ restore_interrupts (state );
363+ if (multicore_lockout_victim_is_initialized (1 - get_core_num ())) {
364+ multicore_lockout_end_blocking ();
365+ }
366+ }
367+
368+ void rp2_flash_set_timing () {
369+ rp2_flash_set_timing_for_freq (clock_get_hz (clk_sys ));
370+ }
0 commit comments