26
26
27
27
#include <string.h>
28
28
29
+ #include "rp2_psram.h"
29
30
#include "py/mphal.h"
30
31
#include "py/runtime.h"
31
32
#include "extmod/vfs.h"
32
33
#include "modrp2.h"
33
34
#include "hardware/flash.h"
34
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
35
42
36
43
#define BLOCK_SIZE_BYTES (FLASH_SECTOR_SIZE)
37
44
@@ -80,16 +87,75 @@ static bool use_multicore_lockout(void) {
80
87
;
81
88
}
82
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
+
83
132
// Flash erase and write must run with interrupts disabled and the other core suspended,
84
133
// because the XIP bit gets disabled.
85
134
static uint32_t begin_critical_flash_section (void ) {
86
135
if (use_multicore_lockout ()) {
87
136
multicore_lockout_start_blocking ();
88
137
}
89
- return save_and_disable_interrupts ();
138
+ uint32_t state = save_and_disable_interrupts ();
139
+
140
+ #if defined(MICROPY_HW_PSRAM_CS_PIN ) && MICROPY_HW_ENABLE_PSRAM
141
+ // We're about to invalidate the XIP cache, clean it first to commit any dirty writes to PSRAM
142
+ // Use the upper 16k of the maintenance space (0x1bffc000 through 0x1bffffff) to workaround
143
+ // incorrect behaviour of the XIP clean operation, where it also alters the tag of the associated
144
+ // cache line: https://forums.raspberrypi.com/viewtopic.php?t=378249#p2263677
145
+ volatile uint8_t * maintenance_ptr = (volatile uint8_t * )(XIP_SRAM_BASE + (XIP_MAINTENANCE_BASE - XIP_BASE ));
146
+ for (int i = 1 ; i < 16 * 1024 ; i += 8 ) {
147
+ maintenance_ptr [i ] = 0 ;
148
+ }
149
+ #endif
150
+
151
+ return state ;
90
152
}
91
153
92
154
static void end_critical_flash_section (uint32_t state ) {
155
+ rp2_flash_set_timing_internal (clock_get_hz (clk_sys ));
156
+ #if defined(MICROPY_HW_PSRAM_CS_PIN ) && MICROPY_HW_ENABLE_PSRAM
157
+ psram_init (MICROPY_HW_PSRAM_CS_PIN );
158
+ #endif
93
159
restore_interrupts (state );
94
160
if (use_multicore_lockout ()) {
95
161
multicore_lockout_end_blocking ();
@@ -155,11 +221,16 @@ static mp_obj_t rp2_flash_readblocks(size_t n_args, const mp_obj_t *args) {
155
221
}
156
222
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (rp2_flash_readblocks_obj , 3 , 4 , rp2_flash_readblocks ) ;
157
223
224
+ static inline size_t min_size (size_t a , size_t b ) {
225
+ return a < b ? a : b ;
226
+ }
227
+
158
228
static mp_obj_t rp2_flash_writeblocks (size_t n_args , const mp_obj_t * args ) {
159
229
rp2_flash_obj_t * self = MP_OBJ_TO_PTR (args [0 ]);
160
230
uint32_t offset = mp_obj_get_int (args [1 ]) * BLOCK_SIZE_BYTES ;
161
231
mp_buffer_info_t bufinfo ;
162
232
mp_get_buffer_raise (args [2 ], & bufinfo , MP_BUFFER_READ );
233
+
163
234
if (n_args == 3 ) {
164
235
mp_uint_t atomic_state = begin_critical_flash_section ();
165
236
flash_range_erase (self -> flash_base + offset , bufinfo .len );
@@ -169,10 +240,31 @@ static mp_obj_t rp2_flash_writeblocks(size_t n_args, const mp_obj_t *args) {
169
240
} else {
170
241
offset += mp_obj_get_int (args [3 ]);
171
242
}
172
- mp_uint_t atomic_state = begin_critical_flash_section ();
173
- flash_range_program (self -> flash_base + offset , bufinfo .buf , bufinfo .len );
174
- end_critical_flash_section (atomic_state );
175
- mp_event_handle_nowait ();
243
+
244
+ if ((uintptr_t )bufinfo .buf >= SRAM_BASE ) {
245
+ mp_uint_t atomic_state = begin_critical_flash_section ();
246
+ flash_range_program (self -> flash_base + offset , bufinfo .buf , bufinfo .len );
247
+ end_critical_flash_section (atomic_state );
248
+ mp_event_handle_nowait ();
249
+ } else {
250
+ size_t bytes_left = bufinfo .len ;
251
+ size_t bytes_offset = 0 ;
252
+ static uint8_t copy_buffer [BLOCK_SIZE_BYTES ] = {0 };
253
+
254
+ while (bytes_left ) {
255
+ memcpy (copy_buffer , bufinfo .buf + bytes_offset , min_size (bytes_left , BLOCK_SIZE_BYTES ));
256
+ mp_uint_t atomic_state = begin_critical_flash_section ();
257
+ flash_range_program (self -> flash_base + offset + bytes_offset , copy_buffer , min_size (bytes_left , BLOCK_SIZE_BYTES ));
258
+ end_critical_flash_section (atomic_state );
259
+ bytes_offset += BLOCK_SIZE_BYTES ;
260
+ if (bytes_left <= BLOCK_SIZE_BYTES ) {
261
+ break ;
262
+ }
263
+ bytes_left -= BLOCK_SIZE_BYTES ;
264
+ mp_event_handle_nowait ();
265
+ }
266
+ }
267
+
176
268
// TODO check return value
177
269
return mp_const_none ;
178
270
}
@@ -220,3 +312,23 @@ MP_DEFINE_CONST_OBJ_TYPE(
220
312
make_new , rp2_flash_make_new ,
221
313
locals_dict , & rp2_flash_locals_dict
222
314
);
315
+
316
+ // Modify the flash timing. Ensure flash access is suspended while
317
+ // the timings are altered.
318
+ void rp2_flash_set_timing_for_freq (int clock_hz ) {
319
+ if (multicore_lockout_victim_is_initialized (1 - get_core_num ())) {
320
+ multicore_lockout_start_blocking ();
321
+ }
322
+ uint32_t state = save_and_disable_interrupts ();
323
+
324
+ rp2_flash_set_timing_internal (clock_hz );
325
+
326
+ restore_interrupts (state );
327
+ if (multicore_lockout_victim_is_initialized (1 - get_core_num ())) {
328
+ multicore_lockout_end_blocking ();
329
+ }
330
+ }
331
+
332
+ void rp2_flash_set_timing () {
333
+ rp2_flash_set_timing_for_freq (clock_get_hz (clk_sys ));
334
+ }
0 commit comments