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
@@ -71,6 +77,48 @@ bi_decl(bi_block_device(
71
77
BINARY_INFO_BLOCK_DEV_FLAG_WRITE |
72
78
BINARY_INFO_BLOCK_DEV_FLAG_PT_UNKNOWN ));
73
79
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
+
74
122
// Flash erase and write must run with interrupts disabled and the other core suspended,
75
123
// because the XIP bit gets disabled.
76
124
static uint32_t begin_critical_flash_section (void ) {
@@ -94,6 +142,7 @@ static void end_critical_flash_section(uint32_t state) {
94
142
#if defined(MICROPY_HW_PSRAM_CS_PIN ) && MICROPY_HW_ENABLE_PSRAM
95
143
psram_init (MICROPY_HW_PSRAM_CS_PIN );
96
144
#endif
145
+ rp2_flash_set_timing_internal (clock_get_hz (clk_sys ));
97
146
restore_interrupts (state );
98
147
if (multicore_lockout_victim_is_initialized (1 - get_core_num ())) {
99
148
multicore_lockout_end_blocking ();
@@ -250,3 +299,23 @@ MP_DEFINE_CONST_OBJ_TYPE(
250
299
make_new , rp2_flash_make_new ,
251
300
locals_dict , & rp2_flash_locals_dict
252
301
);
302
+
303
+ // Modify the flash timing. Ensure flash access is suspended while
304
+ // the timings are altered.
305
+ void rp2_flash_set_timing_for_freq (int clock_hz ) {
306
+ if (multicore_lockout_victim_is_initialized (1 - get_core_num ())) {
307
+ multicore_lockout_start_blocking ();
308
+ }
309
+ uint32_t state = save_and_disable_interrupts ();
310
+
311
+ rp2_flash_set_timing_internal (clock_hz );
312
+
313
+ restore_interrupts (state );
314
+ if (multicore_lockout_victim_is_initialized (1 - get_core_num ())) {
315
+ multicore_lockout_end_blocking ();
316
+ }
317
+ }
318
+
319
+ void rp2_flash_set_timing () {
320
+ rp2_flash_set_timing_for_freq (clock_get_hz (clk_sys ));
321
+ }
0 commit comments