rp2040

RP2040 Programming without SDK
Log | Files | Refs

commit f54b95e177d885028b09e1ab7ce368f6db3240c5
parent e99f7a9bb0e1fe65bb38f0061b2e2c6fb81b7299
Author: Matsuda Kenji <info@mtkn.jp>
Date:   Mon,  3 Apr 2023 18:45:31 +0900

trying to compile original code from sdk

Diffstat:
MMakefile | 4++--
Mboot2/boot2_w25q.S | 215+++++++++++++++++++++++++++++++++++++++++++++----------------------------------
2 files changed, 126 insertions(+), 93 deletions(-)

diff --git a/Makefile b/Makefile @@ -30,8 +30,8 @@ start.o: start.s # ./bincrc boot2/bs2_default.bin boot2/boot2_crc.S boot2_crc.o: boot2/boot2_crc.S $(AS) $(ASFLAGS) -o boot2_crc.o boot2/boot2_crc.S -boot2/boot2_crc.S: boot2/boot2.S bincrc - $(AS) $(ASFLAGS) -o boot2/boot2.o boot2/boot2.S +boot2/boot2_crc.S: boot2/boot2_w25q.S bincrc + $(AS) $(ASFLAGS) -o boot2/boot2.o boot2/boot2_w25q.S $(OBJCOPY) -O binary boot2/boot2.o boot2/boot2.bin ./bincrc boot2/boot2.bin boot2/boot2_crc.S diff --git a/boot2/boot2_w25q.S b/boot2/boot2_w25q.S @@ -1,15 +1,6 @@ -#define PICO_FLASH_SPI_CLKDIV 4 -#define FRAME_FORMAT 0x2 -#define CMD_READ 0xeb -#define MODE_CONTINUOUS_READ 0xa0 -#define ADDR_L 8 -#define WAIT_CYCLES 4 - -#define CMD_WRITE_ENABLE 0x06 -#define CMD_READ_STATUS 0x05 -#define CMD_READ_STATUS2 0x35 -#define CMD_WRITE_STATUS 0x01 -#define SREG_DATA 0x02 // Enable quad-SPI mode +.equ XIP_SSI_BASE, 0x18000000 +.equ PADS_QSPI_BASE, 0x40020000 +.equ PPB_BASE, 0xe0000000 .syntax unified .cpu cortex-m0plus @@ -24,82 +15,82 @@ _stage2_boot: push {lr} ldr r3, =PADS_QSPI_BASE - movs r0, #(2 << PADS_QSPI_GPIO_QSPI_SCLK_DRIVE_LSB | PADS_QSPI_GPIO_QSPI_SCLK_SLEWFAST_BITS) - str r0, [r3, #PADS_QSPI_GPIO_QSPI_SCLK_OFFSET] - ldr r0, [r3, #PADS_QSPI_GPIO_QSPI_SD0_OFFSET] - movs r1, #PADS_QSPI_GPIO_QSPI_SD0_SCHMITT_BITS + movs r0, #(2 << 4 | 1) + str r0, [r3, #0x4] + ldr r0, [r3, #0x8] + movs r1, #2 bics r0, r1 - str r0, [r3, #PADS_QSPI_GPIO_QSPI_SD0_OFFSET] - str r0, [r3, #PADS_QSPI_GPIO_QSPI_SD1_OFFSET] - str r0, [r3, #PADS_QSPI_GPIO_QSPI_SD2_OFFSET] - str r0, [r3, #PADS_QSPI_GPIO_QSPI_SD3_OFFSET] + str r0, [r3, #0x8] + str r0, [r3, #0xc] + str r0, [r3, #0x10] + str r0, [r3, #0x14] ldr r3, =XIP_SSI_BASE // Disable SSI to allow further config movs r1, #0 - str r1, [r3, #SSI_SSIENR_OFFSET] + str r1, [r3, #0x8] // Set baud rate - movs r1, #PICO_FLASH_SPI_CLKDIV - str r1, [r3, #SSI_BAUDR_OFFSET] + movs r1, #4 + str r1, [r3, #0x14] - // Set 1-cycle sample delay. If PICO_FLASH_SPI_CLKDIV == 2 then this means, + // Set 1-cycle sample delay. If 4 == 2 then this means, // if the flash launches data on SCLK posedge, we capture it at the time that // the next SCLK posedge is launched. This is shortly before that posedge // arrives at the flash, so data hold time should be ok. For - // PICO_FLASH_SPI_CLKDIV > 2 this pretty much has no effect. + // 4 > 2 this pretty much has no effect. movs r1, #1 - movs r2, #SSI_RX_SAMPLE_DLY_OFFSET // == 0xf0 so need 8 bits of offset significance + ldr r2, =0xf0 // == 0xf0 so need 8 bits of offset significance str r1, [r3, r2] // On QSPI parts we usually need a 01h SR-write command to enable QSPI mode // (i.e. turn WPn and HOLDn into IO2/IO3) -#ifdef PROGRAM_STATUS_REG program_sregs: -#define CTRL0_SPI_TXRX \ - (7 << SSI_CTRLR0_DFS_32_LSB) | /* 8 bits per data frame */ \ - (SSI_CTRLR0_TMOD_VALUE_TX_AND_RX << SSI_CTRLR0_TMOD_LSB) + movs r1, #7 + lsls r1, r1, #16 + movs r2, #0 + lsls r2, r2, #8 + adds r1, r1, r2 - ldr r1, =(CTRL0_SPI_TXRX) - str r1, [r3, #SSI_CTRLR0_OFFSET] + str r1, [r3, #0] // Enable SSI and select slave 0 movs r1, #1 - str r1, [r3, #SSI_SSIENR_OFFSET] + str r1, [r3, #0x8] // Check whether SR needs updating - movs r0, #CMD_READ_STATUS2 + movs r0, #0x35 bl read_flash_sreg - movs r2, #SREG_DATA + movs r2, #0x02 cmp r0, r2 beq skip_sreg_programming // Send write enable command - movs r1, #CMD_WRITE_ENABLE - str r1, [r3, #SSI_DR0_OFFSET] + movs r1, #0x06 + str r1, [r3, #0x60] // Poll for completion and discard RX bl wait_ssi_ready - ldr r1, [r3, #SSI_DR0_OFFSET] + ldr r1, [r3, #0x60] // Send status write command followed by data bytes - movs r1, #CMD_WRITE_STATUS - str r1, [r3, #SSI_DR0_OFFSET] + movs r1, #0x01 + str r1, [r3, #0x60] movs r0, #0 - str r0, [r3, #SSI_DR0_OFFSET] - str r2, [r3, #SSI_DR0_OFFSET] + str r0, [r3, #0x60] + str r2, [r3, #0x60] bl wait_ssi_ready - ldr r1, [r3, #SSI_DR0_OFFSET] - ldr r1, [r3, #SSI_DR0_OFFSET] - ldr r1, [r3, #SSI_DR0_OFFSET] + ldr r1, [r3, #0x60] + ldr r1, [r3, #0x60] + ldr r1, [r3, #0x60] // Poll status register for write completion 1: - movs r0, #CMD_READ_STATUS + movs r0, #0x05 bl read_flash_sreg movs r1, #1 tst r0, r1 @@ -109,8 +100,7 @@ skip_sreg_programming: // Disable SSI again so that it can be reconfigured movs r1, #0 - str r1, [r3, #SSI_SSIENR_OFFSET] -#endif + str r1, [r3, #0x8] // Currently the flash expects an 8 bit serial command prefix on every // transfer, which is a waste of cycles. Perform a dummy Fast Read Quad I/O @@ -119,38 +109,40 @@ skip_sreg_programming: // of the read, the important part is the mode bits. dummy_read: -#define CTRLR0_ENTER_XIP \ - (FRAME_FORMAT /* Quad I/O mode */ \ - << SSI_CTRLR0_SPI_FRF_LSB) | \ - (31 << SSI_CTRLR0_DFS_32_LSB) | /* 32 data bits */ \ - (SSI_CTRLR0_TMOD_VALUE_EEPROM_READ /* Send INST/ADDR, Receive Data */ \ - << SSI_CTRLR0_TMOD_LSB) + movs r1, #0x2 + lsls r1, r1, #21 + movs r2, #31 + lsls r2, r2, #16 + adds r1, r1, r2 + movs r2, #3 + lsls r2, r2, #8 + adds r1, r1, r2 - ldr r1, =(CTRLR0_ENTER_XIP) - str r1, [r3, #SSI_CTRLR0_OFFSET] + str r1, [r3, #0x0] movs r1, #0x0 // NDF=0 (single 32b read) - str r1, [r3, #SSI_CTRLR1_OFFSET] - -#define SPI_CTRLR0_ENTER_XIP \ - (ADDR_L << SSI_SPI_CTRLR0_ADDR_L_LSB) | /* Address + mode bits */ \ - (WAIT_CYCLES << SSI_SPI_CTRLR0_WAIT_CYCLES_LSB) | /* Hi-Z dummy clocks following address + mode */ \ - (SSI_SPI_CTRLR0_INST_L_VALUE_8B \ - << SSI_SPI_CTRLR0_INST_L_LSB) | /* 8-bit instruction */ \ - (SSI_SPI_CTRLR0_TRANS_TYPE_VALUE_1C2A /* Send Command in serial mode then address in Quad I/O mode */ \ - << SSI_SPI_CTRLR0_TRANS_TYPE_LSB) - - ldr r1, =(SPI_CTRLR0_ENTER_XIP) - ldr r0, =(XIP_SSI_BASE + SSI_SPI_CTRLR0_OFFSET) // SPI_CTRL0 Register + str r1, [r3, #0x4] + + movs r1, #8 + lsls r1, r1, #2 + movs r2, #4 + lsls r2, r2, #11 + adds r1, r1, r2 + movs r2, #2 + lsls r2, r2, #8 + adds r1, r1, r2 + adds r1, #1 + + ldr r0, =(XIP_SSI_BASE + 0xf4) // SPI_CTRL0 Register str r1, [r0] movs r1, #1 // Re-enable SSI - str r1, [r3, #SSI_SSIENR_OFFSET] + str r1, [r3, #0x8] - movs r1, #CMD_READ - str r1, [r3, #SSI_DR0_OFFSET] // Push SPI command into TX FIFO - movs r1, #MODE_CONTINUOUS_READ // 32-bit: 24 address bits (we don't care, so 0) and M[7:4]=1010 - str r1, [r3, #SSI_DR0_OFFSET] // Push Address into TX FIFO - this will trigger the transaction + movs r1, #0xeb + str r1, [r3, #0x60] // Push SPI command into TX FIFO + movs r1, #0xa0 // 32-bit: 24 address bits (we don't care, so 0) and M[7:4]=1010 + str r1, [r3, #0x60] // Push Address into TX FIFO - this will trigger the transaction // Poll for completion bl wait_ssi_ready @@ -160,41 +152,82 @@ dummy_read: // into QSPI transfers of this form. movs r1, #0 - str r1, [r3, #SSI_SSIENR_OFFSET] // Disable SSI (and clear FIFO) to allow further config + str r1, [r3, #0x8] // Disable SSI (and clear FIFO) to allow further config // Note that the INST_L field is used to select what XIP data gets pushed into // the TX FIFO: // INST_L_0_BITS {ADDR[23:0],XIP_CMD[7:0]} Load "mode bits" into XIP_CMD // Anything else {XIP_CMD[7:0],ADDR[23:0]} Load SPI command into XIP_CMD configure_ssi: -#define SPI_CTRLR0_XIP \ - (MODE_CONTINUOUS_READ /* Mode bits to keep flash in continuous read mode */ \ - << SSI_SPI_CTRLR0_XIP_CMD_LSB) | \ - (ADDR_L << SSI_SPI_CTRLR0_ADDR_L_LSB) | /* Total number of address + mode bits */ \ - (WAIT_CYCLES << SSI_SPI_CTRLR0_WAIT_CYCLES_LSB) | /* Hi-Z dummy clocks following address + mode */ \ - (SSI_SPI_CTRLR0_INST_L_VALUE_NONE /* Do not send a command, instead send XIP_CMD as mode bits after address */ \ - << SSI_SPI_CTRLR0_INST_L_LSB) | \ - (SSI_SPI_CTRLR0_TRANS_TYPE_VALUE_2C2A /* Send Address in Quad I/O mode (and Command but that is zero bits long) */ \ - << SSI_SPI_CTRLR0_TRANS_TYPE_LSB) + movs r1, #0xa0 + lsls r1, r1, #24 + movs r2, #8 + lsls r2, #2 + adds r1, r1, r2 + movs r2, #4 + lsls r2, r2, #11 + adds r1, r1, r2 + movs r2, #0 + lsls r2, r2, #8 + adds r1, r1, r2 + adds r1, #2 ldr r1, =(SPI_CTRLR0_XIP) - ldr r0, =(XIP_SSI_BASE + SSI_SPI_CTRLR0_OFFSET) + ldr r0, =(XIP_SSI_BASE + 0xf4) str r1, [r0] movs r1, #1 - str r1, [r3, #SSI_SSIENR_OFFSET] // Re-enable SSI + str r1, [r3, #0x8] // Re-enable SSI // Bus accesses to the XIP window will now be transparently serviced by the // external flash on cache miss. We are ready to run code from flash. // Pull in standard exit routine -#include "boot2_helpers/exit_from_boot2.S" +check_return: + pop {r0} + cmp r0, #0 + beq vector_into_flash + bx r0 +vector_into_flash: + ldr r0, =XIP_BASE + ldr r1, =0x100 + adds r0, r0, r1 + ldr r1, =PPB_BASE + ldr r2, =0xed08 + adds r1, r1, r2 + str r0, [r1] + ldmia r0, {r0, r1} + msr msp, r0 + bx r1 + +wait_ssi_ready: + push {r0, r1, lr} + + // Command is complete when there is nothing left to send + // (TX FIFO empty) and SSI is no longer busy (CSn deasserted) +1: + ldr r1, [r3, #0x28] + movs r0, #4 + tst r1, r0 + beq 1b + movs r0, #1 + tst r1, r0 + bne 1b + + pop {r0, r1, pc} + +read_flash_sreg: + push {r1, lr} + str r0, [r3, #0x60] + // Dummy byte: + str r0, [r3, #0x60] + + bl wait_ssi_ready + // Discard first byte and combine the next two + ldr r0, [r3, #0x60] + ldr r0, [r3, #0x60] -// Common functions -#include "boot2_helpers/wait_ssi_ready.S" -#ifdef PROGRAM_STATUS_REG -#include "boot2_helpers/read_flash_sreg.S" -#endif + pop {r1, pc} .global literals literals: