diff --git a/lib/pico-sdk b/lib/pico-sdk index a1438dff1d3..98a542c1a62 160000 --- a/lib/pico-sdk +++ b/lib/pico-sdk @@ -1 +1 @@ -Subproject commit a1438dff1d38bd9c65dbd693f0e5db4b9ae91779 +Subproject commit 98a542c1a62fb549ffb5d66a3e5892b06276b670 diff --git a/ports/rp2/CMakeLists.txt b/ports/rp2/CMakeLists.txt index 5b99b396f4a..17d337be25d 100644 --- a/ports/rp2/CMakeLists.txt +++ b/ports/rp2/CMakeLists.txt @@ -170,7 +170,6 @@ set(MICROPY_SOURCE_PORT pendsv.c rp2_flash.c rp2_pio.c - rp2_psram.c rp2_dma.c uart.c usbd.c @@ -569,6 +568,39 @@ if(DEFINED MICROPY_HW_FLASH_STORAGE_BYTES) ) endif() +# PSRAM (RP2350 only) is brought up by the SDK's hardware_psram library at boot +# (runtime_init). Boards that fit PSRAM set MICROPY_HW_ENABLE_PSRAM and +# MICROPY_HW_PSRAM_CS_PIN in their mpconfigboard.cmake. +# +# Defer to the pico-sdk board header where it configures PSRAM: if it sets a size +# (PICO_PSRAM_SIZE_BYTES, which the SDK exposes as a CMake variable), use the +# header's chip-select and size as-is. main.c asserts the header chip-select +# matches MICROPY_HW_PSRAM_CS_PIN. Otherwise drive the SDK from the downstream +# config: auto-detect the size on the configured chip-select. +# +# MicroPython re-tunes the QMI timing after clock changes (see main.c and +# modmachine.c); flash programming restores it via the SDK's CS1 setup callback. +if(PICO_RP2350 AND MICROPY_HW_ENABLE_PSRAM) + list(APPEND PICO_SDK_COMPONENTS + hardware_psram + ) + target_compile_definitions(${MICROPY_TARGET} PRIVATE + MICROPY_HW_ENABLE_PSRAM=1 + ) + if(DEFINED MICROPY_HW_PSRAM_CS_PIN) + target_compile_definitions(${MICROPY_TARGET} PRIVATE + MICROPY_HW_PSRAM_CS_PIN=${MICROPY_HW_PSRAM_CS_PIN} + ) + endif() + if(NOT PICO_PSRAM_SIZE_BYTES) + # No size configured upstream: auto-detect on the configured chip-select. + target_compile_definitions(${MICROPY_TARGET} PRIVATE + PICO_PSRAM_CS_PIN=${MICROPY_HW_PSRAM_CS_PIN} + PICO_AUTO_DETECT_PSRAM_SIZE=1 + ) + endif() +endif() + # Apply optimisations to performance-critical source code. set_source_files_properties( ${MICROPY_PY_DIR}/map.c @@ -632,11 +664,15 @@ endif() # a linker script modification) until we explicitly add macro calls around the function # defs to move them into RAM. if (NOT MICROPY_BOARD_LINKER_SCRIPT) + # Use the Pico SDK's include-based ("overridable") default linker script, + # supplying only the parts MicroPython needs to change via override paths. if(PICO_RP2040) - set(MICROPY_BOARD_LINKER_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/memmap_mp_rp2040.ld) + pico_add_linker_script_override_path(${MICROPY_TARGET} ${CMAKE_CURRENT_LIST_DIR}/memmap_rp2040) elseif(PICO_RP2350) - set(MICROPY_BOARD_LINKER_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/memmap_mp_rp2350.ld) + pico_add_linker_script_override_path(${MICROPY_TARGET} ${CMAKE_CURRENT_LIST_DIR}/memmap_rp2350) endif() + pico_add_linker_script_override_path(${MICROPY_TARGET} ${CMAKE_CURRENT_LIST_DIR}/memmap_rp2) + set(MICROPY_BOARD_LINKER_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/memmap_mp_rp2.ld) endif() if (PICO_ON_DEVICE AND NOT PICO_NO_FLASH AND NOT PICO_COPY_TO_RAM) diff --git a/ports/rp2/boards/ADAFRUIT_FEATHER_RP2350/mpconfigboard.cmake b/ports/rp2/boards/ADAFRUIT_FEATHER_RP2350/mpconfigboard.cmake index 26db5db5965..3f5bdec039b 100644 --- a/ports/rp2/boards/ADAFRUIT_FEATHER_RP2350/mpconfigboard.cmake +++ b/ports/rp2/boards/ADAFRUIT_FEATHER_RP2350/mpconfigboard.cmake @@ -11,3 +11,7 @@ endif() # To change the gpio count for QFN-80 # set(PICO_NUM_GPIOS 48) + +# 8MB PSRAM on GPIO8. +set(MICROPY_HW_ENABLE_PSRAM 1) +set(MICROPY_HW_PSRAM_CS_PIN 8) diff --git a/ports/rp2/boards/ADAFRUIT_FEATHER_RP2350/mpconfigboard.h b/ports/rp2/boards/ADAFRUIT_FEATHER_RP2350/mpconfigboard.h index d6f950f8cc4..c31e3bedba8 100644 --- a/ports/rp2/boards/ADAFRUIT_FEATHER_RP2350/mpconfigboard.h +++ b/ports/rp2/boards/ADAFRUIT_FEATHER_RP2350/mpconfigboard.h @@ -10,6 +10,4 @@ // Red user LED GPIO7 -// Optional PSRAM on GPIO8 -#define MICROPY_HW_PSRAM_CS_PIN (8) -#define MICROPY_HW_ENABLE_PSRAM (1) +// Optional PSRAM on GPIO8 (enabled in mpconfigboard.cmake) diff --git a/ports/rp2/boards/SPARKFUN_IOTNODE_LORAWAN_RP2350/mpconfigboard.cmake b/ports/rp2/boards/SPARKFUN_IOTNODE_LORAWAN_RP2350/mpconfigboard.cmake index c9c9b1ab1b9..b611c7efebe 100644 --- a/ports/rp2/boards/SPARKFUN_IOTNODE_LORAWAN_RP2350/mpconfigboard.cmake +++ b/ports/rp2/boards/SPARKFUN_IOTNODE_LORAWAN_RP2350/mpconfigboard.cmake @@ -12,3 +12,7 @@ set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py) if(NOT DEFINED MICROPY_HW_FLASH_STORAGE_BYTES) set(MICROPY_HW_FLASH_STORAGE_BYTES 14680064) # 14 * 1024 * 1024 endif() + +# 8MB PSRAM on GPIO0. +set(MICROPY_HW_ENABLE_PSRAM 1) +set(MICROPY_HW_PSRAM_CS_PIN 0) diff --git a/ports/rp2/boards/SPARKFUN_IOTNODE_LORAWAN_RP2350/mpconfigboard.h b/ports/rp2/boards/SPARKFUN_IOTNODE_LORAWAN_RP2350/mpconfigboard.h index b55eac5d8fd..8d38b380d4c 100644 --- a/ports/rp2/boards/SPARKFUN_IOTNODE_LORAWAN_RP2350/mpconfigboard.h +++ b/ports/rp2/boards/SPARKFUN_IOTNODE_LORAWAN_RP2350/mpconfigboard.h @@ -27,6 +27,3 @@ #define MICROPY_HW_UART1_RX (5) #define MICROPY_HW_UART1_CTS (6) #define MICROPY_HW_UART1_RTS (7) - -#define MICROPY_HW_PSRAM_CS_PIN (0) -#define MICROPY_HW_ENABLE_PSRAM (1) diff --git a/ports/rp2/boards/SPARKFUN_IOTREDBOARD_RP2350/mpconfigboard.cmake b/ports/rp2/boards/SPARKFUN_IOTREDBOARD_RP2350/mpconfigboard.cmake index f1dd0021176..816fd51b9f6 100644 --- a/ports/rp2/boards/SPARKFUN_IOTREDBOARD_RP2350/mpconfigboard.cmake +++ b/ports/rp2/boards/SPARKFUN_IOTREDBOARD_RP2350/mpconfigboard.cmake @@ -22,3 +22,7 @@ set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py) if(NOT DEFINED MICROPY_HW_FLASH_STORAGE_BYTES) set(MICROPY_HW_FLASH_STORAGE_BYTES 15204352) # PICO_FLASH_SIZE_BYTES - 1536 * 1024 = 16MB - 1.5MB endif() + +# 8MB PSRAM on GPIO47. +set(MICROPY_HW_ENABLE_PSRAM 1) +set(MICROPY_HW_PSRAM_CS_PIN 47) diff --git a/ports/rp2/boards/SPARKFUN_IOTREDBOARD_RP2350/mpconfigboard.h b/ports/rp2/boards/SPARKFUN_IOTREDBOARD_RP2350/mpconfigboard.h index 767e36c07d0..1818fd626af 100644 --- a/ports/rp2/boards/SPARKFUN_IOTREDBOARD_RP2350/mpconfigboard.h +++ b/ports/rp2/boards/SPARKFUN_IOTREDBOARD_RP2350/mpconfigboard.h @@ -44,9 +44,7 @@ #define MICROPY_HW_SPI1_MOSI (11) #define MICROPY_HW_SPI1_MISO (8) -// PSRAM -#define MICROPY_HW_PSRAM_CS_PIN (47) -#define MICROPY_HW_ENABLE_PSRAM (1) +// PSRAM enabled in mpconfigboard.cmake // #include "enable_cyw43.h" diff --git a/ports/rp2/boards/SPARKFUN_PROMICRO_RP2350/mpconfigboard.cmake b/ports/rp2/boards/SPARKFUN_PROMICRO_RP2350/mpconfigboard.cmake index ab547e9ed93..92b26929ece 100644 --- a/ports/rp2/boards/SPARKFUN_PROMICRO_RP2350/mpconfigboard.cmake +++ b/ports/rp2/boards/SPARKFUN_PROMICRO_RP2350/mpconfigboard.cmake @@ -6,3 +6,7 @@ set(PICO_PLATFORM "rp2350") if(NOT DEFINED MICROPY_HW_FLASH_STORAGE_BYTES) set(MICROPY_HW_FLASH_STORAGE_BYTES 14680064) # 14 * 1024 * 1024 endif() + +# 8MB PSRAM. The chip-select (GPIO19) and size come from the pico-sdk board +# header (sparkfun_promicro_rp2350.h). +set(MICROPY_HW_ENABLE_PSRAM 1) diff --git a/ports/rp2/boards/SPARKFUN_PROMICRO_RP2350/mpconfigboard.h b/ports/rp2/boards/SPARKFUN_PROMICRO_RP2350/mpconfigboard.h index 2ceecfd1cc0..15063782280 100644 --- a/ports/rp2/boards/SPARKFUN_PROMICRO_RP2350/mpconfigboard.h +++ b/ports/rp2/boards/SPARKFUN_PROMICRO_RP2350/mpconfigboard.h @@ -20,6 +20,3 @@ #define MICROPY_HW_SPI0_SCK (22) #define MICROPY_HW_SPI0_MOSI (23) #define MICROPY_HW_SPI0_MISO (20) - -#define MICROPY_HW_PSRAM_CS_PIN (19) -#define MICROPY_HW_ENABLE_PSRAM (1) diff --git a/ports/rp2/boards/SPARKFUN_THINGPLUS_RP2350/mpconfigboard.cmake b/ports/rp2/boards/SPARKFUN_THINGPLUS_RP2350/mpconfigboard.cmake index 1227ff8ac1f..27e9affa374 100644 --- a/ports/rp2/boards/SPARKFUN_THINGPLUS_RP2350/mpconfigboard.cmake +++ b/ports/rp2/boards/SPARKFUN_THINGPLUS_RP2350/mpconfigboard.cmake @@ -17,3 +17,7 @@ set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py) if(NOT DEFINED MICROPY_HW_FLASH_STORAGE_BYTES) set(MICROPY_HW_FLASH_STORAGE_BYTES 14680064) # 14 * 1024 * 1024 endif() + +# 8MB PSRAM. The chip-select (GPIO8) and size come from the pico-sdk board +# header (sparkfun_thingplus_rp2350.h). +set(MICROPY_HW_ENABLE_PSRAM 1) diff --git a/ports/rp2/boards/SPARKFUN_THINGPLUS_RP2350/mpconfigboard.h b/ports/rp2/boards/SPARKFUN_THINGPLUS_RP2350/mpconfigboard.h index e8456c4d0fd..5461da112fa 100644 --- a/ports/rp2/boards/SPARKFUN_THINGPLUS_RP2350/mpconfigboard.h +++ b/ports/rp2/boards/SPARKFUN_THINGPLUS_RP2350/mpconfigboard.h @@ -42,6 +42,3 @@ int mp_hal_is_pin_reserved(int n); #define MICROPY_HW_UART1_RX (5) #define MICROPY_HW_UART1_CTS (6) #define MICROPY_HW_UART1_RTS (7) - -#define MICROPY_HW_PSRAM_CS_PIN (8) -#define MICROPY_HW_ENABLE_PSRAM (1) diff --git a/ports/rp2/boards/SPARKFUN_XRP_CONTROLLER/mpconfigboard.cmake b/ports/rp2/boards/SPARKFUN_XRP_CONTROLLER/mpconfigboard.cmake index 7d1c06aef83..b65c3db1098 100644 --- a/ports/rp2/boards/SPARKFUN_XRP_CONTROLLER/mpconfigboard.cmake +++ b/ports/rp2/boards/SPARKFUN_XRP_CONTROLLER/mpconfigboard.cmake @@ -22,3 +22,7 @@ set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py) if(NOT DEFINED MICROPY_HW_FLASH_STORAGE_BYTES) set(MICROPY_HW_FLASH_STORAGE_BYTES 15204352) # PICO_FLASH_SIZE_BYTES - 1536 * 1024 = 16MB - 1.5MB endif() + +# 8MB PSRAM on GPIO47. +set(MICROPY_HW_ENABLE_PSRAM 1) +set(MICROPY_HW_PSRAM_CS_PIN 47) diff --git a/ports/rp2/boards/SPARKFUN_XRP_CONTROLLER/mpconfigboard.h b/ports/rp2/boards/SPARKFUN_XRP_CONTROLLER/mpconfigboard.h index 164824e85d7..289e707f62a 100644 --- a/ports/rp2/boards/SPARKFUN_XRP_CONTROLLER/mpconfigboard.h +++ b/ports/rp2/boards/SPARKFUN_XRP_CONTROLLER/mpconfigboard.h @@ -46,6 +46,3 @@ int mp_hal_is_pin_reserved(int n); #define MICROPY_HW_UART1_RX (9) #define MICROPY_HW_UART1_CTS (10) #define MICROPY_HW_UART1_RTS (11) - -#define MICROPY_HW_PSRAM_CS_PIN (47) -#define MICROPY_HW_ENABLE_PSRAM (1) diff --git a/ports/rp2/boards/WAVESHARE_RP2350B_CORE/mpconfigboard.cmake b/ports/rp2/boards/WAVESHARE_RP2350B_CORE/mpconfigboard.cmake index 920d5b1711c..a071333fb33 100644 --- a/ports/rp2/boards/WAVESHARE_RP2350B_CORE/mpconfigboard.cmake +++ b/ports/rp2/boards/WAVESHARE_RP2350B_CORE/mpconfigboard.cmake @@ -14,3 +14,7 @@ set(PICO_FLASH_SIZE_BYTES 16777216) if(NOT DEFINED MICROPY_HW_FLASH_STORAGE_BYTES) set(MICROPY_HW_FLASH_STORAGE_BYTES 14680064) # 14 * 1024 * 1024 endif() + +# 8MB PSRAM on GPIO47. +set(MICROPY_HW_ENABLE_PSRAM 1) +set(MICROPY_HW_PSRAM_CS_PIN 47) diff --git a/ports/rp2/boards/WAVESHARE_RP2350B_CORE/mpconfigboard.h b/ports/rp2/boards/WAVESHARE_RP2350B_CORE/mpconfigboard.h index 06efbbfd3d7..8c2c54c23c6 100644 --- a/ports/rp2/boards/WAVESHARE_RP2350B_CORE/mpconfigboard.h +++ b/ports/rp2/boards/WAVESHARE_RP2350B_CORE/mpconfigboard.h @@ -2,8 +2,6 @@ #define MICROPY_HW_BOARD_NAME "Waveshare RP2350B Core" #define PICO_FLASH_SIZE_BYTES (16 * 1024 * 1024) -#define MICROPY_HW_PSRAM_CS_PIN (47) -#define MICROPY_HW_ENABLE_PSRAM (1) // Override machine_uart.c definitions. // See waveshare_rp2350b.h and note that the PICO_DEFAULT_UART configuration diff --git a/ports/rp2/main.c b/ports/rp2/main.c index c67f404f61e..f43c85eee50 100644 --- a/ports/rp2/main.c +++ b/ports/rp2/main.c @@ -48,7 +48,6 @@ #include "mpnetworkport.h" #include "genhdr/mpversion.h" #include "mp_usbd.h" -#include "rp2_psram.h" #include "pico/stdlib.h" #include "pico/binary_info.h" @@ -67,9 +66,22 @@ #endif #include "pico/aon_timer.h" #include "shared/timeutils/timeutils.h" +#if MICROPY_HW_ENABLE_PSRAM +#include "hardware/psram.h" +// When the pico-sdk board header configures the PSRAM chip-select, make sure the +// downstream MicroPython config (MICROPY_HW_PSRAM_CS_PIN) agrees with it. +#if defined(PICO_PSRAM_CS_PIN) && defined(MICROPY_HW_PSRAM_CS_PIN) && (PICO_PSRAM_CS_PIN != MICROPY_HW_PSRAM_CS_PIN) +#error "MICROPY_HW_PSRAM_CS_PIN does not match the board header's PICO_PSRAM_CS_PIN" +#endif +#endif extern uint8_t __StackTop, __StackBottom; extern uint8_t __GcHeapStart, __GcHeapEnd; +#if MICROPY_HW_ENABLE_PSRAM +// Provided by the SDK's PSRAM linker sections: __psram_start__ is ORIGIN(PSRAM) +// (the PSRAM base) and __psram_end__ is the end of any __in_psram data. +extern uint8_t __psram_start__, __psram_end__; +#endif // Embed version info in the binary in machine readable form bi_decl(bi_program_version_string(MICROPY_GIT_TAG)); @@ -99,7 +111,12 @@ int main(int argc, char **argv) { rp2_flash_set_timing(); #if MICROPY_HW_ENABLE_PSRAM - size_t psram_size = psram_init(MICROPY_HW_PSRAM_CS_PIN); + // The SDK's runtime_init brought PSRAM up at the boot clock; re-tune the QMI + // timing now that the system clock has been set to its final value. + if (psram_is_available()) { + psram_configure_params(PICO_DEFAULT_PSRAM_MAX_FREQ, PICO_DEFAULT_PSRAM_MAX_SELECT, PICO_DEFAULT_PSRAM_MIN_DESELECT); + psram_reinitialize(); + } #endif #if MICROPY_HW_ENABLE_UART_REPL @@ -131,12 +148,16 @@ int main(int argc, char **argv) { mp_cstack_init_with_top(&__StackTop, &__StackTop - &__StackBottom); #if MICROPY_HW_ENABLE_PSRAM + size_t psram_size = psram_get_size(); // 0 if PSRAM was not brought up if (psram_size) { + // Use PSRAM from the end of any __in_psram data up to the top of the chip. + void *psram_heap_start = &__psram_end__; + void *psram_heap_end = &__psram_start__ + psram_size; #if MICROPY_GC_SPLIT_HEAP gc_init(&__GcHeapStart, &__GcHeapEnd); - gc_add((void *)PSRAM_BASE, (void *)(PSRAM_BASE + psram_size)); + gc_add(psram_heap_start, psram_heap_end); #else - gc_init((void *)PSRAM_BASE, (void *)(PSRAM_BASE + psram_size)); + gc_init(psram_heap_start, psram_heap_end); #endif } else { gc_init(&__GcHeapStart, &__GcHeapEnd); diff --git a/ports/rp2/memmap_mp_rp2.ld b/ports/rp2/memmap_mp_rp2.ld new file mode 100644 index 00000000000..2b599755ac5 --- /dev/null +++ b/ports/rp2/memmap_mp_rp2.ld @@ -0,0 +1,18 @@ +/* MicroPython linker script for RP2040 and RP2350. + + This uses the Pico SDK's include-based ("overridable") default linker script + (memmap_default.incl) and only overrides the parts MicroPython needs to + change. The per-part overrides live in: + memmap_rp2/ - common to both chips + memmap_rp2040/ - RP2040 only + memmap_rp2350/ - RP2350 only + These directories are added to the linker script search path (ahead of the + SDK's) by pico_add_linker_script_override_path() in CMakeLists.txt. */ + +/* Delete scratch X and expand scratch Y, so all of the C stack lives in a + single 8K scratch region (matches the previous hand-written scripts). */ +SCRATCH_X_LENGTH = 0; +SCRATCH_Y_ORIGIN = SCRATCH_X_ORIGIN_DEFAULT; +SCRATCH_Y_LENGTH = SCRATCH_Y_LENGTH_DEFAULT*2; + +INCLUDE "memmap_default.incl" diff --git a/ports/rp2/memmap_mp_rp2040.ld b/ports/rp2/memmap_mp_rp2040.ld deleted file mode 100644 index 9b925045701..00000000000 --- a/ports/rp2/memmap_mp_rp2040.ld +++ /dev/null @@ -1,270 +0,0 @@ -/* Based on GCC ARM embedded samples. - Defines the following symbols for use by code: - __exidx_start - __exidx_end - __etext - __data_start__ - __preinit_array_start - __preinit_array_end - __init_array_start - __init_array_end - __fini_array_start - __fini_array_end - __data_end__ - __bss_start__ - __bss_end__ - __end__ - end - __HeapLimit - __StackLimit - __StackTop - __stack (== StackTop) -*/ - -MEMORY -{ - FLASH(rx) : ORIGIN = 0x10000000, LENGTH = __micropy_flash_size__ - __micropy_flash_storage_bytes__ - FLASH_FS(rx) : ORIGIN = ORIGIN(FLASH) + LENGTH(FLASH), LENGTH = __micropy_flash_storage_bytes__ - RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 256k - SCRATCH_X(rwx) : ORIGIN = 0x20040000, LENGTH = 0k - SCRATCH_Y(rwx) : ORIGIN = 0x20040000, LENGTH = 8k -} - -ENTRY(_entry_point) - -SECTIONS -{ - /* Second stage bootloader is prepended to the image. It must be 256 bytes big - and checksummed. It is usually built by the boot_stage2 target - in the Raspberry Pi Pico SDK - */ - - .flash_begin : { - __flash_binary_start = .; - } > FLASH - - .boot2 : { - __boot2_start__ = .; - KEEP (*(.boot2)) - __boot2_end__ = .; - } > FLASH - - ASSERT(__boot2_end__ - __boot2_start__ == 256, - "ERROR: Pico second stage bootloader must be 256 bytes in size") - - /* The second stage will always enter the image at the start of .text. - The debugger will use the ELF entry point, which is the _entry_point - symbol if present, otherwise defaults to start of .text. - This can be used to transfer control back to the bootrom on debugger - launches only, to perform proper flash setup. - */ - - .text : { - __logical_binary_start = .; - KEEP (*(.vectors)) - KEEP (*(.binary_info_header)) - __binary_info_header_end = .; - KEEP (*(.reset)) - /* TODO revisit this now memset/memcpy/float in ROM */ - /* bit of a hack right now to exclude all floating point and time critical (e.g. memset, memcpy) code from - * FLASH ... we will include any thing excluded here in .data below by default */ - *(.init) - /* Change for MicroPython... exclude gc.c, parse.c, vm.c from flash */ - *(EXCLUDE_FILE(*libgcc.a: *libc.a: *lib_a-mem*.o *libm.a: *py/gc.c.o *py/vm.c.o *py/parse.c.o) .text*) - *(.fini) - /* Pull all c'tors into .text */ - *crtbegin.o(.ctors) - *crtbegin?.o(.ctors) - *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) - *(SORT(.ctors.*)) - *(.ctors) - /* Followed by destructors */ - *crtbegin.o(.dtors) - *crtbegin?.o(.dtors) - *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) - *(SORT(.dtors.*)) - *(.dtors) - - *(.eh_frame*) - . = ALIGN(4); - } > FLASH - - .rodata : { - *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .rodata*) - . = ALIGN(4); - *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*))) - . = ALIGN(4); - } > FLASH - - .ARM.extab : - { - *(.ARM.extab* .gnu.linkonce.armextab.*) - } > FLASH - - __exidx_start = .; - .ARM.exidx : - { - *(.ARM.exidx* .gnu.linkonce.armexidx.*) - } > FLASH - __exidx_end = .; - - /* Machine inspectable binary information */ - . = ALIGN(4); - __binary_info_start = .; - .binary_info : - { - KEEP(*(.binary_info.keep.*)) - *(.binary_info.*) - } > FLASH - __binary_info_end = .; - . = ALIGN(4); - - /* End of .text-like segments */ - __etext = .; - - .ram_vector_table (COPY): { - *(.ram_vector_table) - } > RAM - - .data : { - __data_start__ = .; - *(vtable) - - *(.time_critical*) - - /* remaining .text and .rodata; i.e. stuff we exclude above because we want it in RAM */ - *(.text*) - . = ALIGN(4); - *(.rodata*) - . = ALIGN(4); - - *(.data*) - - . = ALIGN(4); - *(.after_data.*) - . = ALIGN(4); - /* preinit data */ - PROVIDE_HIDDEN (__mutex_array_start = .); - KEEP(*(SORT(.mutex_array.*))) - KEEP(*(.mutex_array)) - PROVIDE_HIDDEN (__mutex_array_end = .); - - . = ALIGN(4); - /* preinit data */ - PROVIDE_HIDDEN (__preinit_array_start = .); - KEEP(*(SORT(.preinit_array.*))) - KEEP(*(.preinit_array)) - PROVIDE_HIDDEN (__preinit_array_end = .); - - . = ALIGN(4); - /* init data */ - PROVIDE_HIDDEN (__init_array_start = .); - KEEP(*(SORT(.init_array.*))) - KEEP(*(.init_array)) - PROVIDE_HIDDEN (__init_array_end = .); - - . = ALIGN(4); - /* finit data */ - PROVIDE_HIDDEN (__fini_array_start = .); - *(SORT(.fini_array.*)) - *(.fini_array) - PROVIDE_HIDDEN (__fini_array_end = .); - - *(.jcr) - . = ALIGN(4); - /* All data end */ - __data_end__ = .; - } > RAM AT> FLASH - - .uninitialized_data (COPY): { - . = ALIGN(4); - *(.uninitialized_data*) - } > RAM - - /* bss without zero init on startup */ - .uninitialized_bss (NOLOAD): { - . = ALIGN(4); - *(.uninitialized_bss*) - } > RAM - - /* Start and end symbols must be word-aligned */ - .scratch_x : { - __scratch_x_start__ = .; - *(.scratch_x.*) - . = ALIGN(4); - __scratch_x_end__ = .; - } > SCRATCH_X AT > FLASH - __scratch_x_source__ = LOADADDR(.scratch_x); - - .scratch_y : { - __scratch_y_start__ = .; - *(.scratch_y.*) - . = ALIGN(4); - __scratch_y_end__ = .; - } > SCRATCH_Y AT > FLASH - __scratch_y_source__ = LOADADDR(.scratch_y); - - .bss : { - . = ALIGN(4); - __bss_start__ = .; - *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*))) - *(COMMON) - . = ALIGN(4); - __bss_end__ = .; - } > RAM - - .heap (COPY): - { - __end__ = .; - end = __end__; - KEEP(*(.heap*)) - __HeapLimit = .; - } > RAM - - /* .stack*_dummy section doesn't contains any symbols. It is only - * used for linker to calculate size of stack sections, and assign - * values to stack symbols later - * - * stack1 section may be empty/missing if platform_launch_core1 is not used */ - - /* by default we put core 0 stack at the end of scratch Y, so that if core 1 - * stack is not used then all of SCRATCH_X is free. - */ - .stack1_dummy (COPY): - { - KEEP(*(.stack1*)) - } > SCRATCH_X - .stack_dummy (COPY): - { - KEEP(*(.stack*)) - } > SCRATCH_Y - - .flash_end : { - __flash_binary_end = .; - } > FLASH - - /* stack limit is poorly named, but historically is maximum heap ptr */ - __StackLimit = __bss_end__ + __micropy_c_heap_size__; - - /* Define start and end of GC heap */ - __GcHeapStart = __StackLimit; /* after the C heap (sbrk limit) */ - __GcHeapEnd = ORIGIN(RAM) + LENGTH(RAM); - - /* Define memory for the C stack */ - __StackOneTop = ORIGIN(SCRATCH_X) + LENGTH(SCRATCH_X); - __StackTop = ORIGIN(SCRATCH_Y) + LENGTH(SCRATCH_Y); - __StackOneBottom = __StackOneTop - SIZEOF(.stack1_dummy); - __StackBottom = __StackTop - SIZEOF(.stack_dummy); - PROVIDE(__stack = __StackTop); - - /* Check GC heap is at least 32 KB */ - /* This is quarter the minimum RAM suggested for full-featured MicroPython. - * This value accounts for large static buffers included in user C or C++ - * modules, which might significantly reduce the available heap but also - * lower demand for memory at runtime. - */ - ASSERT((__GcHeapEnd - __GcHeapStart) > 32*1024, "GcHeap is too small") - - ASSERT( __binary_info_header_end - __logical_binary_start <= 256, "Binary info must be in first 256 bytes of the binary") - /* todo assert on extra code */ -} diff --git a/ports/rp2/memmap_mp_rp2350.ld b/ports/rp2/memmap_mp_rp2350.ld deleted file mode 100644 index 6af4c48ccf8..00000000000 --- a/ports/rp2/memmap_mp_rp2350.ld +++ /dev/null @@ -1,313 +0,0 @@ -/* Based on GCC ARM embedded samples. - Defines the following symbols for use by code: - __exidx_start - __exidx_end - __etext - __data_start__ - __preinit_array_start - __preinit_array_end - __init_array_start - __init_array_end - __fini_array_start - __fini_array_end - __data_end__ - __bss_start__ - __bss_end__ - __end__ - end - __HeapLimit - __StackLimit - __StackTop - __stack (== StackTop) -*/ - -MEMORY -{ - FLASH(rx) : ORIGIN = 0x10000000, LENGTH = __micropy_flash_size__ - __micropy_flash_storage_bytes__ - FLASH_FS(rx) : ORIGIN = ORIGIN(FLASH) + LENGTH(FLASH), LENGTH = __micropy_flash_storage_bytes__ - RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 512k - SCRATCH_X(rwx) : ORIGIN = 0x20080000, LENGTH = 0k - SCRATCH_Y(rwx) : ORIGIN = 0x20080000, LENGTH = 8k -} - -ENTRY(_entry_point) - -SECTIONS -{ - .flash_begin : { - __flash_binary_start = .; - } > FLASH - - /* The bootrom will enter the image at the point indicated in your - IMAGE_DEF, which is usually the reset handler of your vector table. - - The debugger will use the ELF entry point, which is the _entry_point - symbol, and in our case is *different from the bootrom's entry point.* - This is used to go back through the bootrom on debugger launches only, - to perform the same initial flash setup that would be performed on a - cold boot. - */ - - .text : { - __logical_binary_start = .; - KEEP (*(.vectors)) - KEEP (*(.binary_info_header)) - __binary_info_header_end = .; - KEEP (*(.embedded_block)) - __embedded_block_end = .; - KEEP (*(.reset)) - /* TODO revisit this now memset/memcpy/float in ROM */ - /* bit of a hack right now to exclude all floating point and time critical (e.g. memset, memcpy) code from - * FLASH ... we will include any thing excluded here in .data below by default */ - *(.init) - *libgcc.a:cmse_nonsecure_call.o - /* Change for MicroPython... exclude gc.c, parse.c, vm.c from flash */ - *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a: *py/gc.c.o *py/vm.c.o *py/parse.c.o) .text*) - *(.fini) - /* Pull all c'tors into .text */ - *crtbegin.o(.ctors) - *crtbegin?.o(.ctors) - *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) - *(SORT(.ctors.*)) - *(.ctors) - /* Followed by destructors */ - *crtbegin.o(.dtors) - *crtbegin?.o(.dtors) - *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) - *(SORT(.dtors.*)) - *(.dtors) - - . = ALIGN(4); - /* preinit data */ - PROVIDE_HIDDEN (__preinit_array_start = .); - KEEP(*(SORT(.preinit_array.*))) - KEEP(*(.preinit_array)) - PROVIDE_HIDDEN (__preinit_array_end = .); - - . = ALIGN(4); - /* init data */ - PROVIDE_HIDDEN (__init_array_start = .); - KEEP(*(SORT(.init_array.*))) - KEEP(*(.init_array)) - PROVIDE_HIDDEN (__init_array_end = .); - - . = ALIGN(4); - /* finit data */ - PROVIDE_HIDDEN (__fini_array_start = .); - *(SORT(.fini_array.*)) - *(.fini_array) - PROVIDE_HIDDEN (__fini_array_end = .); - *(.eh_frame*) - . = ALIGN(4); - } > FLASH - - /* Note the boot2 section is optional, and should be discarded if there is - no reference to it *inside* the binary, as it is not called by the - bootrom. (The bootrom performs a simple best-effort XIP setup and - leaves it to the binary to do anything more sophisticated.) However - there is still a size limit of 256 bytes, to ensure the boot2 can be - stored in boot RAM. - - Really this is a "XIP setup function" -- the name boot2 is historic and - refers to its dual-purpose on RP2040, where it also handled vectoring - from the bootrom into the user image. - */ - - .boot2 : { - __boot2_start__ = .; - *(.boot2) - __boot2_end__ = .; - } > FLASH - - ASSERT(__boot2_end__ - __boot2_start__ <= 256, - "ERROR: Pico second stage bootloader must be no more than 256 bytes in size") - - .rodata : { - *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .rodata*) - *(.srodata*) - . = ALIGN(4); - *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*))) - . = ALIGN(4); - } > FLASH - - .ARM.extab : - { - *(.ARM.extab* .gnu.linkonce.armextab.*) - } > FLASH - - __exidx_start = .; - .ARM.exidx : - { - *(.ARM.exidx* .gnu.linkonce.armexidx.*) - } > FLASH - __exidx_end = .; - - /* Machine inspectable binary information */ - . = ALIGN(4); - __binary_info_start = .; - .binary_info : - { - KEEP(*(.binary_info.keep.*)) - *(.binary_info.*) - } > FLASH - __binary_info_end = .; - . = ALIGN(4); - - .ram_vector_table (NOLOAD): { - *(.ram_vector_table) - } > RAM - - .uninitialized_data (NOLOAD): { - . = ALIGN(4); - *(.uninitialized_data*) - } > RAM - - .data : { - __data_start__ = .; - *(vtable) - - *(.time_critical*) - - /* remaining .text and .rodata; i.e. stuff we exclude above because we want it in RAM */ - *(.text*) - . = ALIGN(4); - *(.rodata*) - . = ALIGN(4); - - *(.data*) - *(.sdata*) - - . = ALIGN(4); - *(.after_data.*) - . = ALIGN(4); - /* preinit data */ - PROVIDE_HIDDEN (__mutex_array_start = .); - KEEP(*(SORT(.mutex_array.*))) - KEEP(*(.mutex_array)) - PROVIDE_HIDDEN (__mutex_array_end = .); - - *(.jcr) - . = ALIGN(4); - } > RAM AT> FLASH - - .tdata : { - . = ALIGN(4); - *(.tdata .tdata.* .gnu.linkonce.td.*) - /* All data end */ - __tdata_end = .; - } > RAM AT> FLASH - PROVIDE(__data_end__ = .); - - /* __etext is (for backwards compatibility) the name of the .data init source pointer (...) */ - __etext = LOADADDR(.data); - - .tbss (NOLOAD) : { - . = ALIGN(4); - __bss_start__ = .; - __tls_base = .; - *(.tbss .tbss.* .gnu.linkonce.tb.*) - *(.tcommon) - - __tls_end = .; - } > RAM - - .bss (NOLOAD) : { - . = ALIGN(4); - __tbss_end = .; - - *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*))) - *(COMMON) - PROVIDE(__global_pointer$ = . + 2K); - *(.sbss*) - . = ALIGN(4); - __bss_end__ = .; - } > RAM - - .heap (NOLOAD): - { - __end__ = .; - end = __end__; - KEEP(*(.heap*)) - /* historically on GCC sbrk was growing past __HeapLimit to __StackLimit, however - to be more compatible, we now set __HeapLimit explicitly to where the end of the heap is */ - /* Change for MicroPython: don't include this, it increases reported firmware size. - /* . = ORIGIN(RAM) + LENGTH(RAM); */ - __HeapLimit = .; - } > RAM - - /* Start and end symbols must be word-aligned */ - .scratch_x : { - __scratch_x_start__ = .; - *(.scratch_x.*) - . = ALIGN(4); - __scratch_x_end__ = .; - } > SCRATCH_X AT > FLASH - __scratch_x_source__ = LOADADDR(.scratch_x); - - .scratch_y : { - __scratch_y_start__ = .; - *(.scratch_y.*) - . = ALIGN(4); - __scratch_y_end__ = .; - } > SCRATCH_Y AT > FLASH - __scratch_y_source__ = LOADADDR(.scratch_y); - - /* .stack*_dummy section doesn't contains any symbols. It is only - * used for linker to calculate size of stack sections, and assign - * values to stack symbols later - * - * stack1 section may be empty/missing if platform_launch_core1 is not used */ - - /* by default we put core 0 stack at the end of scratch Y, so that if core 1 - * stack is not used then all of SCRATCH_X is free. - */ - .stack1_dummy (NOLOAD): - { - *(.stack1*) - } > SCRATCH_X - .stack_dummy (NOLOAD): - { - KEEP(*(.stack*)) - } > SCRATCH_Y - - .flash_end : { - KEEP(*(.embedded_end_block*)) - PROVIDE(__flash_binary_end = .); - } > FLASH =0xaa - - /* stack limit is poorly named, but historically is maximum heap ptr */ - __StackLimit = __bss_end__ + __micropy_c_heap_size__; - - /* Define start and end of GC heap */ - __GcHeapStart = __StackLimit; /* after the C heap (sbrk limit) */ - __GcHeapEnd = ORIGIN(RAM) + LENGTH(RAM) - __micropy_extra_stack__; - - /* Define start and end of C stack */ - __StackTop = ORIGIN(SCRATCH_Y) + LENGTH(SCRATCH_Y); - __StackBottom = __GcHeapEnd; - PROVIDE(__stack = __StackTop); - - /* picolibc and LLVM */ - PROVIDE (__heap_start = __end__); - PROVIDE (__heap_end = __HeapLimit); - PROVIDE( __tls_align = MAX(ALIGNOF(.tdata), ALIGNOF(.tbss)) ); - PROVIDE( __tls_size_align = (__tls_size + __tls_align - 1) & ~(__tls_align - 1)); - PROVIDE( __arm32_tls_tcb_offset = MAX(8, __tls_align) ); - - /* llvm-libc */ - PROVIDE (_end = __end__); - PROVIDE (__llvm_libc_heap_limit = __HeapLimit); - - /* Check GC heap is at least 64 KB */ - /* This is half the minimum RAM suggested for full-featured MicroPython. - * This value accounts for large static buffers included in user C or C++ - * modules, which might significantly reduce the available heap but also - * lower demand for memory at runtime. - */ - ASSERT((__GcHeapEnd - __GcHeapStart) > 64*1024, "GcHeap is too small") - - ASSERT( __binary_info_header_end - __logical_binary_start <= 1024, "Binary info must be in first 1024 bytes of the binary") - ASSERT( __embedded_block_end - __logical_binary_start <= 4096, "Embedded block must be in first 4096 bytes of the binary") - - /* todo assert on extra code */ -} diff --git a/ports/rp2/memmap_rp2/default_text_excludes.incl b/ports/rp2/memmap_rp2/default_text_excludes.incl new file mode 100644 index 00000000000..8ebc7c65256 --- /dev/null +++ b/ports/rp2/memmap_rp2/default_text_excludes.incl @@ -0,0 +1,4 @@ +/* Change for MicroPython: additionally exclude gc.c, vm.c and parse.c from + flash, so their .text is placed in RAM (via the default .data section) for + faster execution. Keeps the SDK's default exclusions for libgcc/libc/libm. */ +*(EXCLUDE_FILE(*libgcc.a: *libc.a: *lib*_a-mem*.o *libm.a: *py/gc.c.o *py/vm.c.o *py/parse.c.o) .text*) diff --git a/ports/rp2/memmap_rp2/memory_flash.incl b/ports/rp2/memmap_rp2/memory_flash.incl new file mode 100644 index 00000000000..b1e7f6d4a88 --- /dev/null +++ b/ports/rp2/memmap_rp2/memory_flash.incl @@ -0,0 +1,9 @@ +/* MicroPython flash layout: the FLASH (application) region sits at the base of + flash, with the writable user filesystem (FLASH_FS) carved off the top. The + origin/length below must match the filesystem base computed in rp2_flash.c: + FLASH_FS base = flash_size - flash_storage_bytes */ +MEMORY +{ + FLASH(rx) : ORIGIN = 0x10000000, LENGTH = __micropy_flash_size__ - __micropy_flash_storage_bytes__ + FLASH_FS(rx) : ORIGIN = ORIGIN(FLASH) + LENGTH(FLASH), LENGTH = __micropy_flash_storage_bytes__ +} diff --git a/ports/rp2/memmap_rp2/section_extra_post_scratch.incl b/ports/rp2/memmap_rp2/section_extra_post_scratch.incl new file mode 100644 index 00000000000..899cfa33e64 --- /dev/null +++ b/ports/rp2/memmap_rp2/section_extra_post_scratch.incl @@ -0,0 +1,11 @@ +/* Overrides the following symbols for use by code: + __HeapLimit +*/ + +SECTIONS +{ + /* Change for MicroPython: pin __HeapLimit to the end of the .heap section, + so the SDK doesn't grow it to the top of RAM (which would inflate the + reported firmware size). */ + __HeapLimit = ADDR(.heap) + SIZEOF(.heap); +} diff --git a/ports/rp2/memmap_rp2040/section_extra_post_platform_end.incl b/ports/rp2/memmap_rp2040/section_extra_post_platform_end.incl new file mode 100644 index 00000000000..b7cde4a02f2 --- /dev/null +++ b/ports/rp2/memmap_rp2040/section_extra_post_platform_end.incl @@ -0,0 +1,26 @@ +/* Defines/overrides the following symbols for use by code: + __GcHeapStart, __GcHeapEnd + __StackLimit + __StackBottom +*/ + +SECTIONS +{ + /* Change for MicroPython: __StackLimit is historically the maximum heap + pointer, i.e. the end of the C heap. */ + __StackLimit = __bss_end__ + __micropy_c_heap_size__; + + /* Define start and end of the GC heap. */ + __GcHeapStart = __StackLimit; /* after the C heap (sbrk limit) */ + __GcHeapEnd = ORIGIN(RAM) + LENGTH(RAM); + + /* Change for MicroPython: expand the C stack down to __GcHeapEnd. */ + __StackBottom = __GcHeapEnd; + + /* Check GC heap is at least 32 KB. This is quarter the minimum RAM + suggested for full-featured MicroPython. This value accounts for large + static buffers included in user C or C++ modules, which might + significantly reduce the available heap but also lower demand for memory + at runtime. */ + ASSERT((__GcHeapEnd - __GcHeapStart) > 32*1024, "GcHeap is too small") +} diff --git a/ports/rp2/memmap_rp2350/section_extra_post_platform_end.incl b/ports/rp2/memmap_rp2350/section_extra_post_platform_end.incl new file mode 100644 index 00000000000..ac4d9afa504 --- /dev/null +++ b/ports/rp2/memmap_rp2350/section_extra_post_platform_end.incl @@ -0,0 +1,26 @@ +/* Defines/overrides the following symbols for use by code: + __GcHeapStart, __GcHeapEnd + __StackLimit + __StackBottom +*/ + +SECTIONS +{ + /* Change for MicroPython: __StackLimit is historically the maximum heap + pointer, i.e. the end of the C heap. */ + __StackLimit = __bss_end__ + __micropy_c_heap_size__; + + /* Define start and end of the GC heap. Reserve __micropy_extra_stack__ at + the top of RAM for the C stack. */ + __GcHeapStart = __StackLimit; /* after the C heap (sbrk limit) */ + __GcHeapEnd = ORIGIN(RAM) + LENGTH(RAM) - __micropy_extra_stack__; + + /* Change for MicroPython: expand the C stack down to __GcHeapEnd. */ + __StackBottom = __GcHeapEnd; + + /* Check GC heap is at least 64 KB. This is half the minimum RAM suggested + for full-featured MicroPython. This value accounts for large static + buffers included in user C or C++ modules, which might significantly + reduce the available heap but also lower demand for memory at runtime. */ + ASSERT((__GcHeapEnd - __GcHeapStart) > 64*1024, "GcHeap is too small") +} diff --git a/ports/rp2/modmachine.c b/ports/rp2/modmachine.c index dc064cc1a77..fc711770e29 100644 --- a/ports/rp2/modmachine.c +++ b/ports/rp2/modmachine.c @@ -31,8 +31,10 @@ #include "mp_usbd.h" #include "modmachine.h" #include "uart.h" -#include "rp2_psram.h" #include "rp2_flash.h" +#if MICROPY_HW_ENABLE_PSRAM +#include "hardware/psram.h" +#endif #include "clocks_extra.h" #include "hardware/pll.h" #include "hardware/structs/rosc.h" @@ -133,7 +135,11 @@ static void mp_machine_set_freq(size_t n_args, const mp_obj_t *args) { mp_uart_init(); #endif #if MICROPY_HW_ENABLE_PSRAM - psram_init(MICROPY_HW_PSRAM_CS_PIN); + // Re-tune the PSRAM QMI timing for the new system clock. + if (psram_is_available()) { + psram_configure_params(PICO_DEFAULT_PSRAM_MAX_FREQ, PICO_DEFAULT_PSRAM_MAX_SELECT, PICO_DEFAULT_PSRAM_MIN_DESELECT); + psram_reinitialize(); + } #endif } diff --git a/ports/rp2/rp2_flash.c b/ports/rp2/rp2_flash.c index 4d41d45733c..d030b78866a 100644 --- a/ports/rp2/rp2_flash.c +++ b/ports/rp2/rp2_flash.c @@ -33,7 +33,6 @@ #include "modrp2.h" #include "hardware/flash.h" #include "pico/binary_info.h" -#include "rp2_psram.h" #ifdef PICO_RP2350 #include "hardware/structs/ioqspi.h" #include "hardware/structs/qmi.h" @@ -189,11 +188,10 @@ static uint32_t begin_critical_flash_section(void) { } static void end_critical_flash_section(uint32_t state) { - // The ROM function to program flash will have reset flash and PSRAM timings to defaults + // The ROM function to program flash will have reset the flash timing to + // defaults. (PSRAM timing is restored automatically by the SDK's flash + // routines via the QMI CS1 setup callback registered by psram_reinitialize.) rp2_flash_set_timing_internal(clock_get_hz(clk_sys)); - #if MICROPY_HW_ENABLE_PSRAM - psram_init(MICROPY_HW_PSRAM_CS_PIN); - #endif restore_interrupts(state); if (use_multicore_lockout()) { multicore_lockout_end_blocking(); diff --git a/ports/rp2/rp2_psram.c b/ports/rp2/rp2_psram.c deleted file mode 100644 index 3b212680674..00000000000 --- a/ports/rp2/rp2_psram.c +++ /dev/null @@ -1,201 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2025 Phil Howard - * Mike Bell - * Kirk D. Benell - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "py/mphal.h" - -#if MICROPY_HW_ENABLE_PSRAM - -#include "hardware/structs/ioqspi.h" -#include "hardware/structs/qmi.h" -#include "hardware/structs/xip_ctrl.h" -#include "hardware/clocks.h" -#include "hardware/sync.h" -#include "rp2_psram.h" - -size_t __no_inline_not_in_flash_func(psram_detect)(void) { - int psram_size = 0; - - // Try and read the PSRAM ID via direct_csr. - qmi_hw->direct_csr = 30 << QMI_DIRECT_CSR_CLKDIV_LSB | QMI_DIRECT_CSR_EN_BITS; - - // Need to poll for the cooldown on the last XIP transfer to expire - // (via direct-mode BUSY flag) before it is safe to perform the first - // direct-mode operation - while ((qmi_hw->direct_csr & QMI_DIRECT_CSR_BUSY_BITS) != 0) { - } - - // Exit out of QMI in case we've inited already - qmi_hw->direct_csr |= QMI_DIRECT_CSR_ASSERT_CS1N_BITS; - - // Transmit as quad. - qmi_hw->direct_tx = QMI_DIRECT_TX_OE_BITS | QMI_DIRECT_TX_IWIDTH_VALUE_Q << QMI_DIRECT_TX_IWIDTH_LSB | 0xf5; - - while ((qmi_hw->direct_csr & QMI_DIRECT_CSR_BUSY_BITS) != 0) { - } - - (void)qmi_hw->direct_rx; - - qmi_hw->direct_csr &= ~(QMI_DIRECT_CSR_ASSERT_CS1N_BITS); - - // Read the id - qmi_hw->direct_csr |= QMI_DIRECT_CSR_ASSERT_CS1N_BITS; - uint8_t kgd = 0; - uint8_t eid = 0; - - for (size_t i = 0; i < 7; i++) { - if (i == 0) { - qmi_hw->direct_tx = 0x9f; - } else { - qmi_hw->direct_tx = 0xff; - } - - while ((qmi_hw->direct_csr & QMI_DIRECT_CSR_TXEMPTY_BITS) == 0) { - } - - while ((qmi_hw->direct_csr & QMI_DIRECT_CSR_BUSY_BITS) != 0) { - } - - if (i == 5) { - kgd = qmi_hw->direct_rx; - } else if (i == 6) { - eid = qmi_hw->direct_rx; - } else { - (void)qmi_hw->direct_rx; - } - } - - // Disable direct csr. - qmi_hw->direct_csr &= ~(QMI_DIRECT_CSR_ASSERT_CS1N_BITS | QMI_DIRECT_CSR_EN_BITS); - - if (kgd == 0x5D) { - psram_size = 1024 * 1024; // 1 MiB - uint8_t size_id = eid >> 5; - if (eid == 0x26 || size_id == 2) { - psram_size *= 8; // 8 MiB - } else if (size_id == 0) { - psram_size *= 2; // 2 MiB - } else if (size_id == 1) { - psram_size *= 4; // 4 MiB - } - } - - return psram_size; -} - -size_t __no_inline_not_in_flash_func(psram_init)(uint cs_pin) { - gpio_set_function(cs_pin, GPIO_FUNC_XIP_CS1); - - uint32_t intr_stash = save_and_disable_interrupts(); - - size_t psram_size = psram_detect(); - - if (!psram_size) { - restore_interrupts(intr_stash); - return 0; - } - - // Read clock speed before entering direct mode (flash access is - // unavailable while QMI direct mode is enabled) - const int max_psram_freq = 133000000; - const int clock_hz = clock_get_hz(clk_sys); - - // Enable direct mode, PSRAM CS, clkdiv of 10. - qmi_hw->direct_csr = 10 << QMI_DIRECT_CSR_CLKDIV_LSB | \ - QMI_DIRECT_CSR_EN_BITS | \ - QMI_DIRECT_CSR_AUTO_CS1N_BITS; - while (qmi_hw->direct_csr & QMI_DIRECT_CSR_BUSY_BITS) { - } - - // Enable QPI mode on the PSRAM - const uint CMD_QPI_EN = 0x35; - qmi_hw->direct_tx = QMI_DIRECT_TX_NOPUSH_BITS | CMD_QPI_EN; - - while (qmi_hw->direct_csr & QMI_DIRECT_CSR_BUSY_BITS) { - } - - // Set PSRAM timing for APS6404 - // - // Using an rxdelay equal to the divisor isn't enough when running the APS6404 close to 133MHz. - // So: don't allow running at divisor 1 above 100MHz (because delay of 2 would be too late), - // and add an extra 1 to the rxdelay if the divided clock is > 100MHz (i.e. sys clock > 200MHz). - int divisor = (clock_hz + max_psram_freq - 1) / max_psram_freq; - if (divisor == 1 && clock_hz > 100000000) { - divisor = 2; - } - int rxdelay = divisor; - if (clock_hz / divisor > 100000000) { - rxdelay += 1; - } - - // - Max select must be <= 8us. The value is given in multiples of 64 system clocks. - // - Min deselect must be >= 18ns. The value is given in system clock cycles - ceil(divisor / 2). - const int clock_period_fs = 1000000000000000ll / clock_hz; - const int max_select = (125 * 1000000) / clock_period_fs; // 125 = 8000ns / 64 - const int min_deselect = (18 * 1000000 + (clock_period_fs - 1)) / clock_period_fs - (divisor + 1) / 2; - - qmi_hw->m[1].timing = 1 << QMI_M1_TIMING_COOLDOWN_LSB | - QMI_M1_TIMING_PAGEBREAK_VALUE_1024 << QMI_M1_TIMING_PAGEBREAK_LSB | - max_select << QMI_M1_TIMING_MAX_SELECT_LSB | - min_deselect << QMI_M1_TIMING_MIN_DESELECT_LSB | - rxdelay << QMI_M1_TIMING_RXDELAY_LSB | - divisor << QMI_M1_TIMING_CLKDIV_LSB; - - // Set PSRAM commands and formats - qmi_hw->m[1].rfmt = - QMI_M0_RFMT_PREFIX_WIDTH_VALUE_Q << QMI_M0_RFMT_PREFIX_WIDTH_LSB | \ - QMI_M0_RFMT_ADDR_WIDTH_VALUE_Q << QMI_M0_RFMT_ADDR_WIDTH_LSB | \ - QMI_M0_RFMT_SUFFIX_WIDTH_VALUE_Q << QMI_M0_RFMT_SUFFIX_WIDTH_LSB | \ - QMI_M0_RFMT_DUMMY_WIDTH_VALUE_Q << QMI_M0_RFMT_DUMMY_WIDTH_LSB | \ - QMI_M0_RFMT_DATA_WIDTH_VALUE_Q << QMI_M0_RFMT_DATA_WIDTH_LSB | \ - QMI_M0_RFMT_PREFIX_LEN_VALUE_8 << QMI_M0_RFMT_PREFIX_LEN_LSB | \ - 6 << QMI_M0_RFMT_DUMMY_LEN_LSB; - - qmi_hw->m[1].rcmd = 0xEB; - - qmi_hw->m[1].wfmt = - QMI_M0_WFMT_PREFIX_WIDTH_VALUE_Q << QMI_M0_WFMT_PREFIX_WIDTH_LSB | \ - QMI_M0_WFMT_ADDR_WIDTH_VALUE_Q << QMI_M0_WFMT_ADDR_WIDTH_LSB | \ - QMI_M0_WFMT_SUFFIX_WIDTH_VALUE_Q << QMI_M0_WFMT_SUFFIX_WIDTH_LSB | \ - QMI_M0_WFMT_DUMMY_WIDTH_VALUE_Q << QMI_M0_WFMT_DUMMY_WIDTH_LSB | \ - QMI_M0_WFMT_DATA_WIDTH_VALUE_Q << QMI_M0_WFMT_DATA_WIDTH_LSB | \ - QMI_M0_WFMT_PREFIX_LEN_VALUE_8 << QMI_M0_WFMT_PREFIX_LEN_LSB; - - qmi_hw->m[1].wcmd = 0x38; - - // Disable direct mode - qmi_hw->direct_csr = 0; - - // Enable writes to PSRAM - hw_set_bits(&xip_ctrl_hw->ctrl, XIP_CTRL_WRITABLE_M1_BITS); - - restore_interrupts(intr_stash); - - return psram_size; -} - -#endif diff --git a/ports/rp2/rp2_psram.h b/ports/rp2/rp2_psram.h deleted file mode 100644 index 0eddf634159..00000000000 --- a/ports/rp2/rp2_psram.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2025 Phil Howard - * Mike Bell - * Kirk D. Benell - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "pico/stdlib.h" - -#ifndef MICROPY_INCLUDED_RP2_RP2_PSRAM_H -#define MICROPY_INCLUDED_RP2_RP2_PSRAM_H - -#if MICROPY_HW_ENABLE_PSRAM -#ifndef MICROPY_HW_PSRAM_CS_PIN -#error "MICROPY_HW_ENABLE_PSRAM requires MICROPY_HW_PSRAM_CS_PIN" -#endif - -#define PSRAM_BASE _u(0x11000000) - -extern size_t psram_init(uint cs_pin); -#endif - -#endif