Skip to content

Commit 92c28e5

Browse files
committed
Merge branch '15620' into sfe_rp2350_beta_06
2 parents a4ab847 + 14b3505 commit 92c28e5

File tree

8 files changed

+358
-5
lines changed

8 files changed

+358
-5
lines changed

ports/rp2/CMakeLists.txt

+6
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,12 @@ set(MICROPY_SOURCE_PORT
173173
${CMAKE_BINARY_DIR}/pins_${MICROPY_BOARD}.c
174174
)
175175

176+
if(PICO_RP2350)
177+
list(APPEND MICROPY_SOURCE_PORT
178+
rp2_psram.c
179+
)
180+
endif()
181+
176182
set(MICROPY_SOURCE_QSTR
177183
${MICROPY_SOURCE_PY}
178184
${MICROPY_DIR}/shared/readline/readline.c

ports/rp2/main.c

+23
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626

2727
#include <stdio.h>
2828

29+
#include "rp2_psram.h"
30+
#include "rp2_flash.h"
2931
#include "py/compile.h"
3032
#include "py/cstack.h"
3133
#include "py/runtime.h"
@@ -93,6 +95,13 @@ int main(int argc, char **argv) {
9395
// Hook for setting up anything that needs to be super early in the bootup process.
9496
MICROPY_BOARD_STARTUP();
9597

98+
// Set the flash divisor to an appropriate value
99+
rp2_flash_set_timing();
100+
101+
#if defined(MICROPY_HW_PSRAM_CS_PIN) && MICROPY_HW_ENABLE_PSRAM
102+
size_t psram_size = psram_init(MICROPY_HW_PSRAM_CS_PIN);
103+
#endif
104+
96105
#if MICROPY_HW_ENABLE_UART_REPL
97106
bi_decl(bi_program_feature("UART REPL"))
98107
setup_default_uart();
@@ -120,7 +129,21 @@ int main(int argc, char **argv) {
120129

121130
// Initialise stack extents and GC heap.
122131
mp_cstack_init_with_top(&__StackTop, &__StackTop - &__StackBottom);
132+
133+
#if defined(MICROPY_HW_PSRAM_CS_PIN) && MICROPY_HW_ENABLE_PSRAM
134+
if (psram_size) {
135+
#if MICROPY_GC_SPLIT_HEAP
136+
gc_init(&__GcHeapStart, &__GcHeapEnd);
137+
gc_add((void *)PSRAM_LOCATION, (void *)(PSRAM_LOCATION + psram_size));
138+
#else
139+
gc_init((void *)PSRAM_LOCATION, (void *)(PSRAM_LOCATION + psram_size));
140+
#endif
141+
} else {
142+
gc_init(&__GcHeapStart, &__GcHeapEnd);
143+
}
144+
#else
123145
gc_init(&__GcHeapStart, &__GcHeapEnd);
146+
#endif
124147

125148
#if MICROPY_PY_LWIP
126149
// lwIP doesn't allow to reinitialise itself by subsequent calls to this function

ports/rp2/modmachine.c

+16
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
#include "mp_usbd.h"
3232
#include "modmachine.h"
3333
#include "uart.h"
34+
#include "rp2_psram.h"
35+
#include "rp2_flash.h"
3436
#include "clocks_extra.h"
3537
#include "hardware/pll.h"
3638
#include "hardware/structs/rosc.h"
@@ -94,6 +96,11 @@ static mp_obj_t mp_machine_get_freq(void) {
9496

9597
static void mp_machine_set_freq(size_t n_args, const mp_obj_t *args) {
9698
mp_int_t freq = mp_obj_get_int(args[0]);
99+
100+
// If necessary, increase the flash divider before increasing the clock speed
101+
const int old_freq = clock_get_hz(clk_sys);
102+
rp2_flash_set_timing_for_freq(MAX(freq, old_freq));
103+
97104
if (!set_sys_clock_khz(freq / 1000, false)) {
98105
mp_raise_ValueError(MP_ERROR_TEXT("cannot change frequency"));
99106
}
@@ -111,10 +118,19 @@ static void mp_machine_set_freq(size_t n_args, const mp_obj_t *args) {
111118
}
112119
}
113120
}
121+
122+
// If clock speed was reduced, maybe we can reduce the flash divider
123+
if (freq < old_freq) {
124+
rp2_flash_set_timing_for_freq(freq);
125+
}
126+
114127
#if MICROPY_HW_ENABLE_UART_REPL
115128
setup_default_uart();
116129
mp_uart_init();
117130
#endif
131+
#if defined(MICROPY_HW_PSRAM_CS_PIN) && MICROPY_HW_ENABLE_PSRAM
132+
psram_init(MICROPY_HW_PSRAM_CS_PIN);
133+
#endif
118134
}
119135

120136
static void mp_machine_idle(void) {

ports/rp2/mpconfigport.h

+12
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,20 @@
7171
#define MICROPY_CONFIG_ROM_LEVEL (MICROPY_CONFIG_ROM_LEVEL_EXTRA_FEATURES)
7272
#endif
7373

74+
#ifndef MICROPY_HW_ENABLE_PSRAM
75+
#define MICROPY_HW_ENABLE_PSRAM (0)
76+
#endif
77+
7478
// Memory allocation policies
79+
#if MICROPY_HW_ENABLE_PSRAM
80+
#define MICROPY_GC_STACK_ENTRY_TYPE uint32_t
81+
#define MICROPY_ALLOC_GC_STACK_SIZE (1024) // Avoid slowdown when GC stack overflow causes a full sweep of PSRAM-backed heap
82+
#else
7583
#define MICROPY_GC_STACK_ENTRY_TYPE uint16_t
84+
#endif
85+
#ifndef MICROPY_GC_SPLIT_HEAP
86+
#define MICROPY_GC_SPLIT_HEAP MICROPY_HW_ENABLE_PSRAM // whether PSRAM is added to or replaces the heap
87+
#endif
7688
#define MICROPY_ALLOC_PATH_MAX (128)
7789
#define MICROPY_QSTR_BYTES_IN_HASH (1)
7890

ports/rp2/rp2_flash.c

+117-5
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,19 @@
2626

2727
#include <string.h>
2828

29+
#include "rp2_psram.h"
2930
#include "py/mphal.h"
3031
#include "py/runtime.h"
3132
#include "extmod/vfs.h"
3233
#include "modrp2.h"
3334
#include "hardware/flash.h"
3435
#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
3542

3643
#define BLOCK_SIZE_BYTES (FLASH_SECTOR_SIZE)
3744

@@ -70,16 +77,75 @@ bi_decl(bi_block_device(
7077
BINARY_INFO_BLOCK_DEV_FLAG_WRITE |
7178
BINARY_INFO_BLOCK_DEV_FLAG_PT_UNKNOWN));
7279

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+
73122
// Flash erase and write must run with interrupts disabled and the other core suspended,
74123
// because the XIP bit gets disabled.
75124
static uint32_t begin_critical_flash_section(void) {
76125
if (multicore_lockout_victim_is_initialized(1 - get_core_num())) {
77126
multicore_lockout_start_blocking();
78127
}
79-
return save_and_disable_interrupts();
128+
uint32_t state = save_and_disable_interrupts();
129+
130+
#if defined(MICROPY_HW_PSRAM_CS_PIN) && MICROPY_HW_ENABLE_PSRAM
131+
// We're about to invalidate the XIP cache, clean it first to commit any dirty writes to PSRAM
132+
// Use the upper 16k of the maintenance space (0x1bffc000 through 0x1bffffff) to workaround
133+
// incorrect behaviour of the XIP clean operation, where it also alters the tag of the associated
134+
// cache line: https://forums.raspberrypi.com/viewtopic.php?t=378249#p2263677
135+
volatile uint8_t *maintenance_ptr = (volatile uint8_t *)(XIP_SRAM_BASE + (XIP_MAINTENANCE_BASE - XIP_BASE));
136+
for (int i = 1; i < 16 * 1024; i += 8) {
137+
maintenance_ptr[i] = 0;
138+
}
139+
#endif
140+
141+
return state;
80142
}
81143

82144
static void end_critical_flash_section(uint32_t state) {
145+
rp2_flash_set_timing_internal(clock_get_hz(clk_sys));
146+
#if defined(MICROPY_HW_PSRAM_CS_PIN) && MICROPY_HW_ENABLE_PSRAM
147+
psram_init(MICROPY_HW_PSRAM_CS_PIN);
148+
#endif
83149
restore_interrupts(state);
84150
if (multicore_lockout_victim_is_initialized(1 - get_core_num())) {
85151
multicore_lockout_end_blocking();
@@ -145,11 +211,16 @@ static mp_obj_t rp2_flash_readblocks(size_t n_args, const mp_obj_t *args) {
145211
}
146212
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(rp2_flash_readblocks_obj, 3, 4, rp2_flash_readblocks);
147213

214+
static inline size_t min_size(size_t a, size_t b) {
215+
return a < b ? a : b;
216+
}
217+
148218
static mp_obj_t rp2_flash_writeblocks(size_t n_args, const mp_obj_t *args) {
149219
rp2_flash_obj_t *self = MP_OBJ_TO_PTR(args[0]);
150220
uint32_t offset = mp_obj_get_int(args[1]) * BLOCK_SIZE_BYTES;
151221
mp_buffer_info_t bufinfo;
152222
mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_READ);
223+
153224
if (n_args == 3) {
154225
mp_uint_t atomic_state = begin_critical_flash_section();
155226
flash_range_erase(self->flash_base + offset, bufinfo.len);
@@ -159,10 +230,31 @@ static mp_obj_t rp2_flash_writeblocks(size_t n_args, const mp_obj_t *args) {
159230
} else {
160231
offset += mp_obj_get_int(args[3]);
161232
}
162-
mp_uint_t atomic_state = begin_critical_flash_section();
163-
flash_range_program(self->flash_base + offset, bufinfo.buf, bufinfo.len);
164-
end_critical_flash_section(atomic_state);
165-
mp_event_handle_nowait();
233+
234+
if ((uintptr_t)bufinfo.buf >= SRAM_BASE) {
235+
mp_uint_t atomic_state = begin_critical_flash_section();
236+
flash_range_program(self->flash_base + offset, bufinfo.buf, bufinfo.len);
237+
end_critical_flash_section(atomic_state);
238+
mp_event_handle_nowait();
239+
} else {
240+
size_t bytes_left = bufinfo.len;
241+
size_t bytes_offset = 0;
242+
static uint8_t copy_buffer[BLOCK_SIZE_BYTES] = {0};
243+
244+
while (bytes_left) {
245+
memcpy(copy_buffer, bufinfo.buf + bytes_offset, min_size(bytes_left, BLOCK_SIZE_BYTES));
246+
mp_uint_t atomic_state = begin_critical_flash_section();
247+
flash_range_program(self->flash_base + offset + bytes_offset, copy_buffer, min_size(bytes_left, BLOCK_SIZE_BYTES));
248+
end_critical_flash_section(atomic_state);
249+
bytes_offset += BLOCK_SIZE_BYTES;
250+
if (bytes_left <= BLOCK_SIZE_BYTES) {
251+
break;
252+
}
253+
bytes_left -= BLOCK_SIZE_BYTES;
254+
mp_event_handle_nowait();
255+
}
256+
}
257+
166258
// TODO check return value
167259
return mp_const_none;
168260
}
@@ -210,3 +302,23 @@ MP_DEFINE_CONST_OBJ_TYPE(
210302
make_new, rp2_flash_make_new,
211303
locals_dict, &rp2_flash_locals_dict
212304
);
305+
306+
// Modify the flash timing. Ensure flash access is suspended while
307+
// the timings are altered.
308+
void rp2_flash_set_timing_for_freq(int clock_hz) {
309+
if (multicore_lockout_victim_is_initialized(1 - get_core_num())) {
310+
multicore_lockout_start_blocking();
311+
}
312+
uint32_t state = save_and_disable_interrupts();
313+
314+
rp2_flash_set_timing_internal(clock_hz);
315+
316+
restore_interrupts(state);
317+
if (multicore_lockout_victim_is_initialized(1 - get_core_num())) {
318+
multicore_lockout_end_blocking();
319+
}
320+
}
321+
322+
void rp2_flash_set_timing() {
323+
rp2_flash_set_timing_for_freq(clock_get_hz(clk_sys));
324+
}

ports/rp2/rp2_flash.h

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#ifndef MICROPY_INCLUDED_RP2_MACHINE_FLASH_H
2+
#define MICROPY_INCLUDED_RP2_MACHINE_FLASH_H
3+
4+
extern void rp2_flash_set_timing_for_freq(int clock_hz);
5+
extern void rp2_flash_set_timing();
6+
7+
#endif

0 commit comments

Comments
 (0)