34
34
#include "hardware/flash.h"
35
35
#include "pico/binary_info.h"
36
36
#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
37
43
38
44
#define BLOCK_SIZE_BYTES (FLASH_SECTOR_SIZE)
39
45
@@ -94,6 +100,48 @@ static bool use_multicore_lockout(void) {
94
100
;
95
101
}
96
102
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
+
97
145
// Flash erase and write must run with interrupts disabled and the other core suspended,
98
146
// because the XIP bit gets disabled.
99
147
static uint32_t begin_critical_flash_section (void ) {
@@ -117,8 +165,9 @@ static uint32_t begin_critical_flash_section(void) {
117
165
}
118
166
119
167
static 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 ));
120
170
#if MICROPY_HW_ENABLE_PSRAM
121
- // The ROM function to program flash will reset PSRAM timings to defaults
122
171
psram_init (MICROPY_HW_PSRAM_CS_PIN );
123
172
#endif
124
173
restore_interrupts (state );
@@ -313,3 +362,23 @@ mp_obj_t mp_vfs_rom_ioctl(size_t n_args, const mp_obj_t *args) {
313
362
}
314
363
}
315
364
#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 () {
383
+ rp2_flash_set_timing_for_freq (clock_get_hz (clk_sys ));
384
+ }
0 commit comments