diff --git a/src/rp2350/boot_stage2/boot2_generic_03h.S b/src/rp2350/boot_stage2/boot2_generic_03h.S index 4e14a4c7b..f7a836f11 100644 --- a/src/rp2350/boot_stage2/boot2_generic_03h.S +++ b/src/rp2350/boot_stage2/boot2_generic_03h.S @@ -46,6 +46,7 @@ #error "RX delay greater than maximum" #endif +#define CMD_RELEASE_POWERDOWN 0xAB #define CMD_READ 0x03 // ---------------------------------------------------------------------------- @@ -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,25 @@ regular_func _stage2_boot sw a0, QMI_M0_RCMD_OFFSET(a3) li a0, INIT_M0_RFMT sw a0, QMI_M0_RFMT_OFFSET(a3) + + // 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) #else push {lr} ldr r3, =XIP_QMI_BASE @@ -109,11 +138,33 @@ regular_func _stage2_boot str r0, [r3, #QMI_M0_RCMD_OFFSET] ldr r0, =INIT_M0_RFMT str r0, [r3, #QMI_M0_RFMT_OFFSET] + + // 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 // Pull in standard exit routine #include "boot2_helpers/exit_from_boot2.S" +// Common functions +#include "boot2_helpers/wait_qmi_ready.S" + #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..71da8a1cb 100644 --- a/src/rp2350/boot_stage2/boot2_w25q080.S +++ b/src/rp2350/boot_stage2/boot2_w25q080.S @@ -81,6 +81,7 @@ // A better solution is to use a volatile SR write if your device supports it. #define PROGRAM_STATUS_REG +#define CMD_RELEASE_POWERDOWN 0xAB #define CMD_WRITE_ENABLE 0x06 #define CMD_READ_STATUS 0x05 #define CMD_READ_STATUS2 0x35 @@ -176,6 +177,12 @@ program_sregs: 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) // Check whether SR needs updating li a0, CMD_READ_STATUS2 @@ -268,6 +275,12 @@ program_sregs: 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] // Check whether SR needs updating movs r0, #CMD_READ_STATUS2