33
33
#include "modrp2.h"
34
34
#include "hardware/flash.h"
35
35
#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
36
42
37
43
#define BLOCK_SIZE_BYTES (FLASH_SECTOR_SIZE)
38
44
@@ -81,6 +87,48 @@ static bool use_multicore_lockout(void) {
81
87
;
82
88
}
83
89
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
+
84
132
// Flash erase and write must run with interrupts disabled and the other core suspended,
85
133
// because the XIP bit gets disabled.
86
134
static uint32_t begin_critical_flash_section (void ) {
@@ -104,6 +152,7 @@ static void end_critical_flash_section(uint32_t state) {
104
152
#if defined(MICROPY_HW_PSRAM_CS_PIN ) && MICROPY_HW_ENABLE_PSRAM
105
153
psram_init (MICROPY_HW_PSRAM_CS_PIN );
106
154
#endif
155
+ rp2_flash_set_timing_internal (clock_get_hz (clk_sys ));
107
156
restore_interrupts (state );
108
157
if (use_multicore_lockout ()) {
109
158
multicore_lockout_end_blocking ();
@@ -260,3 +309,23 @@ MP_DEFINE_CONST_OBJ_TYPE(
260
309
make_new , rp2_flash_make_new ,
261
310
locals_dict , & rp2_flash_locals_dict
262
311
);
312
+
313
+ // Modify the flash timing. Ensure flash access is suspended while
314
+ // the timings are altered.
315
+ void rp2_flash_set_timing_for_freq (int clock_hz ) {
316
+ if (multicore_lockout_victim_is_initialized (1 - get_core_num ())) {
317
+ multicore_lockout_start_blocking ();
318
+ }
319
+ uint32_t state = save_and_disable_interrupts ();
320
+
321
+ rp2_flash_set_timing_internal (clock_hz );
322
+
323
+ restore_interrupts (state );
324
+ if (multicore_lockout_victim_is_initialized (1 - get_core_num ())) {
325
+ multicore_lockout_end_blocking ();
326
+ }
327
+ }
328
+
329
+ void rp2_flash_set_timing () {
330
+ rp2_flash_set_timing_for_freq (clock_get_hz (clk_sys ));
331
+ }
0 commit comments