diff --git a/src/rp2040/boot_stage2/boot2_at25sf128a.S b/src/rp2040/boot_stage2/boot2_at25sf128a.S index 72f751ed9..dcab0e197 100644 --- a/src/rp2040/boot_stage2/boot2_at25sf128a.S +++ b/src/rp2040/boot_stage2/boot2_at25sf128a.S @@ -80,6 +80,7 @@ #define CMD_READ_STATUS2 0x35 #define CMD_WRITE_STATUS 0x01 #define CMD_WRITE_STATUS2 0x31 +#define CMD_RELEASE_POWERDOWN 0xAB #define SREG_DATA 0x02 // Enable quad-SPI mode // ---------------------------------------------------------------------------- @@ -147,10 +148,20 @@ program_sregs: ldr r1, =(CTRL0_SPI_TXRX) str r1, [r3, #SSI_CTRLR0_OFFSET] - // Enable SSI and select slave 0 + // Enable SSI and select slave 0 movs r1, #1 str r1, [r3, #SSI_SSIENR_OFFSET] +#if PICO_BOOT_STAGE2_FLASH_RELEASE_POWERDOWN + // Send release power-down command, discard RX + movs r1, #CMD_RELEASE_POWERDOWN + str r1, [r3, #SSI_DR0_OFFSET] + + // Poll for completion and discard RX + bl wait_ssi_ready + ldr r1, [r3, #SSI_DR0_OFFSET] +#endif + // Check whether SR needs updating movs r0, #CMD_READ_STATUS2 bl read_flash_sreg diff --git a/src/rp2040/boot_stage2/boot2_generic_03h.S b/src/rp2040/boot_stage2/boot2_generic_03h.S index effef930b..047fae7b7 100644 --- a/src/rp2040/boot_stage2/boot2_generic_03h.S +++ b/src/rp2040/boot_stage2/boot2_generic_03h.S @@ -36,6 +36,7 @@ pico_default_asm_setup #endif #define CMD_READ 0x03 +#define CMD_RELEASE_POWERDOWN 0xAB // Value is number of address bits divided by 4 #define ADDR_L 6 @@ -92,6 +93,16 @@ regular_func _stage2_boot movs r1, #1 str r1, [r3, #SSI_SSIENR_OFFSET] +#if PICO_BOOT_STAGE2_FLASH_RELEASE_POWERDOWN + // Send release power-down command, discard RX + movs r1, #CMD_RELEASE_POWERDOWN + str r1, [r3, #SSI_DR0_OFFSET] + + // Poll for completion and discard RX + bl wait_ssi_ready + ldr r1, [r3, #SSI_DR0_OFFSET] +#endif + // We are now in XIP mode. Any bus accesses to the XIP address window will be // translated by the SSI into 03h read commands to the external flash (if cache is missed), // and the data will be returned to the bus. @@ -99,6 +110,11 @@ regular_func _stage2_boot // Pull in standard exit routine #include "boot2_helpers/exit_from_boot2.S" +#if PICO_BOOT_STAGE2_FLASH_RELEASE_POWERDOWN +// Common functions +#include "boot2_helpers/wait_ssi_ready.S" +#endif + .global literals literals: .ltorg diff --git a/src/rp2040/boot_stage2/boot2_is25lp080.S b/src/rp2040/boot_stage2/boot2_is25lp080.S index fda0f992f..e1a4e4429 100644 --- a/src/rp2040/boot_stage2/boot2_is25lp080.S +++ b/src/rp2040/boot_stage2/boot2_is25lp080.S @@ -74,6 +74,7 @@ #define CMD_WRITE_ENABLE 0x06 #define CMD_READ_STATUS 0x05 #define CMD_WRITE_STATUS 0x01 +#define CMD_RELEASE_POWERDOWN 0xAB #define SREG_DATA 0x40 // Enable quad-SPI mode // ---------------------------------------------------------------------------- @@ -114,10 +115,20 @@ program_sregs: ldr r1, =(CTRL0_SPI_TXRX) str r1, [r3, #SSI_CTRLR0_OFFSET] - // Enable SSI and select slave 0 + // Enable SSI and select slave 0 movs r1, #1 str r1, [r3, #SSI_SSIENR_OFFSET] +#if PICO_BOOT_STAGE2_FLASH_RELEASE_POWERDOWN + // Send release power-down command, discard RX + movs r1, #CMD_RELEASE_POWERDOWN + str r1, [r3, #SSI_DR0_OFFSET] + + // Poll for completion and discard RX + bl wait_ssi_ready + ldr r1, [r3, #SSI_DR0_OFFSET] +#endif + // Check whether SR needs updating ldr r0, =CMD_READ_STATUS bl read_flash_sreg diff --git a/src/rp2040/boot_stage2/boot2_w25q080.S b/src/rp2040/boot_stage2/boot2_w25q080.S index c35fb81fa..2ccec85a1 100644 --- a/src/rp2040/boot_stage2/boot2_w25q080.S +++ b/src/rp2040/boot_stage2/boot2_w25q080.S @@ -80,6 +80,7 @@ #define CMD_READ_STATUS 0x05 #define CMD_READ_STATUS2 0x35 #define CMD_WRITE_STATUS 0x01 +#define CMD_RELEASE_POWERDOWN 0xAB #define SREG_DATA 0x02 // Enable quad-SPI mode // ---------------------------------------------------------------------------- @@ -147,10 +148,20 @@ program_sregs: ldr r1, =(CTRL0_SPI_TXRX) str r1, [r3, #SSI_CTRLR0_OFFSET] - // Enable SSI and select slave 0 + // Enable SSI and select slave 0 movs r1, #1 str r1, [r3, #SSI_SSIENR_OFFSET] +#if PICO_BOOT_STAGE2_FLASH_RELEASE_POWERDOWN + // Send release power-down command, discard RX + movs r1, #CMD_RELEASE_POWERDOWN + str r1, [r3, #SSI_DR0_OFFSET] + + // Poll for completion and discard RX + bl wait_ssi_ready + ldr r1, [r3, #SSI_DR0_OFFSET] +#endif + // Check whether SR needs updating movs r0, #CMD_READ_STATUS2 bl read_flash_sreg diff --git a/src/rp2040/boot_stage2/include/boot_stage2/config.h b/src/rp2040/boot_stage2/include/boot_stage2/config.h index ba9bb1f8b..c9ef5730f 100644 --- a/src/rp2040/boot_stage2/include/boot_stage2/config.h +++ b/src/rp2040/boot_stage2/include/boot_stage2/config.h @@ -11,6 +11,11 @@ #include "pico.h" +// PICO_CONFIG: PICO_BOOT_STAGE2_FLASH_RELEASE_POWERDOWN, Release the flash device from power-down state during boot stage 2, type=bool, default=0, group=boot_stage2 +#ifndef PICO_BOOT_STAGE2_FLASH_RELEASE_POWERDOWN +#define PICO_BOOT_STAGE2_FLASH_RELEASE_POWERDOWN 0 +#endif + // PICO_CONFIG: PICO_BUILD_BOOT_STAGE2_NAME, Name of the boot stage 2 if selected in the build system, group=boot_stage2 #ifdef PICO_BUILD_BOOT_STAGE2_NAME #define _BOOT_STAGE2_SELECTED diff --git a/src/rp2350/boot_stage2/boot2_generic_03h.S b/src/rp2350/boot_stage2/boot2_generic_03h.S index 4e14a4c7b..44c9eec9b 100644 --- a/src/rp2350/boot_stage2/boot2_generic_03h.S +++ b/src/rp2350/boot_stage2/boot2_generic_03h.S @@ -47,6 +47,7 @@ #endif #define CMD_READ 0x03 +#define CMD_RELEASE_POWERDOWN 0xAB // ---------------------------------------------------------------------------- // Register initialisation values -- same in Arm/RISC-V code. @@ -60,6 +61,15 @@ // CLKDIV and RXDELAY, and no constraints on CS max assertion, CS min // deassertion, or page boundary burst breaks. +// Need to use direct serial mode to send SR commands. Choose a +// conservative direct-mode divisor (5 MHz at 150 MHz clk_sys) +// since the XIP-mode divisor may be unsafe without an RX delay. +#define INIT_DIRECT_CSR (\ + 30 << QMI_DIRECT_CSR_CLKDIV_LSB | \ + QMI_DIRECT_CSR_EN_BITS | \ + QMI_DIRECT_CSR_AUTO_CS0N_BITS | \ +0) + #define INIT_M0_TIMING (\ 1 << QMI_M0_TIMING_COOLDOWN_LSB |\ PICO_FLASH_SPI_RXDELAY << QMI_M0_TIMING_RXDELAY_LSB |\ @@ -100,6 +110,27 @@ regular_func _stage2_boot sw a0, QMI_M0_RCMD_OFFSET(a3) li a0, INIT_M0_RFMT sw a0, QMI_M0_RFMT_OFFSET(a3) + +#if PICO_BOOT_STAGE2_FLASH_RELEASE_POWERDOWN + // Need to use direct serial mode to send commands. + li a1, INIT_DIRECT_CSR + sw a1, QMI_DIRECT_CSR_OFFSET(a3) + // Wait for cooldown on last XIP transfer to expire, by polling BUSY +1: + lw a1, QMI_DIRECT_CSR_OFFSET(a3) + andi a1, a1, QMI_DIRECT_CSR_BUSY_BITS + bnez a1, 1b + + // Send release power-down command, discard RX + li a0, CMD_RELEASE_POWERDOWN + sw a0, QMI_DIRECT_TX_OFFSET(a3) + jal wait_qmi_ready + lw a0, QMI_DIRECT_RX_OFFSET(a3) + + // Disable direct mode + andi a1, a1, ~QMI_DIRECT_CSR_EN_BITS + sw a1, QMI_DIRECT_CSR_OFFSET(a3) +#endif #else push {lr} ldr r3, =XIP_QMI_BASE @@ -109,11 +140,37 @@ regular_func _stage2_boot str r0, [r3, #QMI_M0_RCMD_OFFSET] ldr r0, =INIT_M0_RFMT str r0, [r3, #QMI_M0_RFMT_OFFSET] + +#if PICO_BOOT_STAGE2_FLASH_RELEASE_POWERDOWN + // Need to use direct serial mode to send commands. + ldr r1, =INIT_DIRECT_CSR + str r1, [r3, #QMI_DIRECT_CSR_OFFSET] + // Wait for cooldown on last XIP transfer to expire, by polling BUSY +1: + ldr r0, [r3, #QMI_DIRECT_CSR_OFFSET] + tst r0, #QMI_DIRECT_CSR_BUSY_BITS + bne 1b + + // Send release power-down command, discard RX + movs r0, #CMD_RELEASE_POWERDOWN + str r0, [r3, #QMI_DIRECT_TX_OFFSET] + bl wait_qmi_ready + ldr r0, [r3, #QMI_DIRECT_RX_OFFSET] + + // Disable direct mode + bics r1, #QMI_DIRECT_CSR_EN_BITS + str r1, [r3, #QMI_DIRECT_CSR_OFFSET] +#endif #endif // Pull in standard exit routine #include "boot2_helpers/exit_from_boot2.S" +#if PICO_BOOT_STAGE2_FLASH_RELEASE_POWERDOWN +// Common functions +#include "boot2_helpers/wait_qmi_ready.S" +#endif + #ifndef __riscv .global literals literals: diff --git a/src/rp2350/boot_stage2/boot2_w25q080.S b/src/rp2350/boot_stage2/boot2_w25q080.S index 9d37e5f5a..4ab1aca7f 100644 --- a/src/rp2350/boot_stage2/boot2_w25q080.S +++ b/src/rp2350/boot_stage2/boot2_w25q080.S @@ -85,6 +85,7 @@ #define CMD_READ_STATUS 0x05 #define CMD_READ_STATUS2 0x35 #define CMD_WRITE_STATUS 0x01 +#define CMD_RELEASE_POWERDOWN 0xAB #define SREG_DATA 0x02 // Enable quad-SPI mode // ---------------------------------------------------------------------------- @@ -176,6 +177,14 @@ program_sregs: lw a1, QMI_DIRECT_CSR_OFFSET(a3) andi a1, a1, QMI_DIRECT_CSR_BUSY_BITS bnez a1, 1b + +#if PICO_BOOT_STAGE2_FLASH_RELEASE_POWERDOWN + // Send release power-down command, discard RX + li a0, CMD_RELEASE_POWERDOWN + sw a0, QMI_DIRECT_TX_OFFSET(a3) + jal wait_qmi_ready + lw a0, QMI_DIRECT_RX_OFFSET(a3) +#endif // Check whether SR needs updating li a0, CMD_READ_STATUS2 @@ -268,6 +277,14 @@ program_sregs: ldr r0, [r3, #QMI_DIRECT_CSR_OFFSET] tst r0, #QMI_DIRECT_CSR_BUSY_BITS bne 1b + +#if PICO_BOOT_STAGE2_FLASH_RELEASE_POWERDOWN + // Send release power-down command, discard RX + movs r0, #CMD_RELEASE_POWERDOWN + str r0, [r3, #QMI_DIRECT_TX_OFFSET] + bl wait_qmi_ready + ldr r0, [r3, #QMI_DIRECT_RX_OFFSET] +#endif // Check whether SR needs updating movs r0, #CMD_READ_STATUS2 diff --git a/src/rp2350/boot_stage2/include/boot_stage2/config.h b/src/rp2350/boot_stage2/include/boot_stage2/config.h index 61f9b9b53..408a72f9b 100644 --- a/src/rp2350/boot_stage2/include/boot_stage2/config.h +++ b/src/rp2350/boot_stage2/include/boot_stage2/config.h @@ -11,6 +11,11 @@ #include "pico/config.h" +// PICO_CONFIG: PICO_BOOT_STAGE2_FLASH_RELEASE_POWERDOWN, Release the flash device from power-down state during boot stage 2, type=bool, default=0, group=boot_stage2 +#ifndef PICO_BOOT_STAGE2_FLASH_RELEASE_POWERDOWN +#define PICO_BOOT_STAGE2_FLASH_RELEASE_POWERDOWN 0 +#endif + // PICO_CONFIG: PICO_BUILD_BOOT_STAGE2_NAME, Name of the boot stage 2 if selected in the build system, group=boot_stage2 #ifdef PICO_BUILD_BOOT_STAGE2_NAME #define _BOOT_STAGE2_SELECTED