3434#include  "hardware/flash.h" 
3535#include  "pico/binary_info.h" 
3636#include  "rp2_psram.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
@@ -94,6 +100,48 @@ static bool use_multicore_lockout(void) {
94100    ;
95101}
96102
103+ // Function to set the flash divisor to the correct divisor, assumes interrupts disabled 
104+ // and core1 locked out if relevant. 
105+ static  void  __no_inline_not_in_flash_func (rp2_flash_set_timing_internal )(int  clock_hz ) {
106+ 
107+     // Use the minimum divisor assuming a 133MHz flash. 
108+     const  int  max_flash_freq  =  133000000 ;
109+     int  divisor  =  (clock_hz  +  max_flash_freq  -  1 ) / max_flash_freq ;
110+ 
111+     #if  PICO_RP2350 
112+     // Make sure flash is deselected - QMI doesn't appear to have a busy flag(!) 
113+     while  ((ioqspi_hw -> io [1 ].status  &  IO_QSPI_GPIO_QSPI_SS_STATUS_OUTTOPAD_BITS ) !=  IO_QSPI_GPIO_QSPI_SS_STATUS_OUTTOPAD_BITS ) {
114+         ;
115+     }
116+ 
117+     // RX delay equal to the divisor means sampling at the same time as the next falling edge of SCK after the 
118+     // falling edge that generated the data.  This is pretty tight at 133MHz but seems to work with the Winbond flash chips. 
119+     const  int  rxdelay  =  divisor ;
120+     qmi_hw -> m [0 ].timing  =  (1  << QMI_M0_TIMING_COOLDOWN_LSB ) |
121+         rxdelay  << QMI_M1_TIMING_RXDELAY_LSB  |
122+         divisor  << QMI_M1_TIMING_CLKDIV_LSB ;
123+ 
124+     // Force a read through XIP to ensure the timing is applied 
125+     volatile  uint32_t  * ptr  =  (volatile  uint32_t  * )0x14000000 ;
126+     (void )* ptr ;
127+     #else 
128+     // RP2040 SSI hardware only supports even divisors 
129+     if  (divisor  &  1 ) {
130+         divisor  +=  1 ;
131+     }
132+ 
133+     // Wait for SSI not busy 
134+     while  (ssi_hw -> sr  &  SSI_SR_BUSY_BITS ) {
135+         ;
136+     }
137+ 
138+     // Disable, set the new divisor, and re-enable 
139+     hw_clear_bits (& ssi_hw -> ssienr , SSI_SSIENR_SSI_EN_BITS );
140+     ssi_hw -> baudr  =  divisor ;
141+     hw_set_bits (& ssi_hw -> ssienr , SSI_SSIENR_SSI_EN_BITS );
142+     #endif 
143+ }
144+ 
97145// Flash erase and write must run with interrupts disabled and the other core suspended, 
98146// because the XIP bit gets disabled. 
99147static  uint32_t  begin_critical_flash_section (void ) {
@@ -117,8 +165,9 @@ static uint32_t begin_critical_flash_section(void) {
117165}
118166
119167static  void  end_critical_flash_section (uint32_t  state ) {
168+     // The ROM function to program flash will have reset flash and PSRAM timings to defaults 
169+     rp2_flash_set_timing_internal (clock_get_hz (clk_sys ));
120170    #if  MICROPY_HW_ENABLE_PSRAM 
121-     // The ROM function to program flash will reset PSRAM timings to defaults 
122171    psram_init (MICROPY_HW_PSRAM_CS_PIN );
123172    #endif 
124173    restore_interrupts (state );
@@ -313,3 +362,23 @@ mp_obj_t mp_vfs_rom_ioctl(size_t n_args, const mp_obj_t *args) {
313362    }
314363}
315364#endif 
365+ 
366+ // Modify the flash timing.  Ensure flash access is suspended while 
367+ // the timings are altered. 
368+ void  rp2_flash_set_timing_for_freq (int  clock_hz ) {
369+     if  (multicore_lockout_victim_is_initialized (1  -  get_core_num ())) {
370+         multicore_lockout_start_blocking ();
371+     }
372+     uint32_t  state  =  save_and_disable_interrupts ();
373+ 
374+     rp2_flash_set_timing_internal (clock_hz );
375+ 
376+     restore_interrupts (state );
377+     if  (multicore_lockout_victim_is_initialized (1  -  get_core_num ())) {
378+         multicore_lockout_end_blocking ();
379+     }
380+ }
381+ 
382+ void  rp2_flash_set_timing (void ) {
383+     rp2_flash_set_timing_for_freq (clock_get_hz (clk_sys ));
384+ }
0 commit comments