Move vector table to beginning of flash image (#10)
* Move vector table to beginning of flash image. Modify a boot2 to use the table. * Move binary info header up between ELF entry and reset handler * Extract common routines from boot2_w25q080 into helper files * Non-default boot2s: use common routines, make callable as void(*)(void) * BSD3 headers on boot2 files (people might want to use them elsewhere) * Promote binary info header to its own section, + comment/readability changes * Fix scope of asminclude path (fixes user custom boot2 definitions) * Rename symbol, clarify comment
This commit is contained in:
parent
5e5776b9c0
commit
732b53271f
@ -24,7 +24,10 @@ function(pico_define_boot_stage2 NAME SOURCES)
|
||||
target_link_options(${NAME} PRIVATE "--specs=nosys.specs")
|
||||
target_link_options(${NAME} PRIVATE "-nostartfiles")
|
||||
endif ()
|
||||
|
||||
|
||||
# boot2_helpers include dir
|
||||
target_include_directories(${NAME} PRIVATE ${PICO_BOOT_STAGE2_DIR}/asminclude)
|
||||
|
||||
target_link_libraries(${NAME} hardware_regs)
|
||||
target_link_options(${NAME} PRIVATE "LINKER:--script=${PICO_BOOT_STAGE2_DIR}/boot_stage2.ld")
|
||||
set_target_properties(${NAME} PROPERTIES LINK_DEPENDS ${PICO_BOOT_STAGE2_DIR}/boot_stage2.ld)
|
||||
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef _BOOT2_HELPER_EXIT_FROM_BOOT2
|
||||
#define _BOOT2_HELPER_EXIT_FROM_BOOT2
|
||||
|
||||
#include "hardware/regs/m0plus.h"
|
||||
|
||||
// If entered from the bootrom, lr (which we earlier pushed) will be 0,
|
||||
// and we vector through the table at the start of the main flash image.
|
||||
// Any regular function call will have a nonzero value for lr.
|
||||
check_return:
|
||||
pop {r0}
|
||||
cmp r0, #0
|
||||
beq vector_into_flash
|
||||
bx r0
|
||||
vector_into_flash:
|
||||
ldr r0, =(XIP_BASE + 0x100)
|
||||
ldr r1, =(PPB_BASE + M0PLUS_VTOR_OFFSET)
|
||||
str r0, [r1]
|
||||
ldmia r0, {r0, r1}
|
||||
msr msp, r0
|
||||
bx r1
|
||||
|
||||
#endif
|
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef _BOOT2_HELPER_READ_FLASH_SREG
|
||||
#define _BOOT2_HELPER_READ_FLASH_SREG
|
||||
|
||||
#include "boot2_helpers/wait_ssi_ready.S"
|
||||
|
||||
// Pass status read cmd into r0.
|
||||
// Returns status value in r0.
|
||||
.global read_flash_sreg
|
||||
.type read_flash_sreg,%function
|
||||
.thumb_func
|
||||
read_flash_sreg:
|
||||
push {r1, lr}
|
||||
str r0, [r3, #SSI_DR0_OFFSET]
|
||||
// Dummy byte:
|
||||
str r0, [r3, #SSI_DR0_OFFSET]
|
||||
|
||||
bl wait_ssi_ready
|
||||
// Discard first byte and combine the next two
|
||||
ldr r0, [r3, #SSI_DR0_OFFSET]
|
||||
ldr r0, [r3, #SSI_DR0_OFFSET]
|
||||
|
||||
pop {r1, pc}
|
||||
|
||||
#endif
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef _BOOT2_HELPER_WAIT_SSI_READY
|
||||
#define _BOOT2_HELPER_WAIT_SSI_READY
|
||||
|
||||
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, #SSI_SR_OFFSET]
|
||||
movs r0, #SSI_SR_TFE_BITS
|
||||
tst r1, r0
|
||||
beq 1b
|
||||
movs r0, #SSI_SR_BUSY_BITS
|
||||
tst r1, r0
|
||||
bne 1b
|
||||
|
||||
pop {r0, r1, pc}
|
||||
|
||||
#endif
|
@ -1,6 +1,7 @@
|
||||
// ----------------------------------------------------------------------------
|
||||
// Second stage boot code
|
||||
// Copyright (c) 2019 Raspberry Pi (Trading) Ltd.
|
||||
// Copyright (c) 2019-2021 Raspberry Pi (Trading) Ltd.
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
//
|
||||
// Device: Anything which responds to 03h serial read command
|
||||
//
|
||||
@ -17,7 +18,7 @@
|
||||
|
||||
#include "pico/asm_helper.S"
|
||||
#include "hardware/regs/addressmap.h"
|
||||
#include "ssi.h"
|
||||
#include "hardware/regs/ssi.h"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Config section
|
||||
@ -92,58 +93,8 @@ _stage2_boot:
|
||||
// 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.
|
||||
|
||||
soft_reset:
|
||||
// Jump to exit point provided in lr. Bootrom will pass null, in which
|
||||
// case we use default exit target at a 256 byte offset into XIP region
|
||||
// (immediately after this second stage's flash location)
|
||||
pop {r0}
|
||||
cmp r0, #0
|
||||
bne 1f
|
||||
ldr r0, =(XIP_BASE + 0x101)
|
||||
1:
|
||||
bx r0
|
||||
|
||||
// Common functions
|
||||
|
||||
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, #SSI_SR_OFFSET]
|
||||
mov r0, #SSI_SR_TFE_BITS
|
||||
tst r1, r0
|
||||
beq 1b
|
||||
mov r0, #SSI_SR_BUSY_BITS
|
||||
tst r1, r0
|
||||
bne 1b
|
||||
|
||||
pop {r0, r1, pc}
|
||||
|
||||
#ifdef PROGRAM_STATUS_REG
|
||||
// Pass status read cmd into r0.
|
||||
// Returns status value in r0.
|
||||
.global read_flash_sreg
|
||||
.type read_flash_sreg,%function
|
||||
.thumb_func
|
||||
read_flash_sreg:
|
||||
push {r1, lr}
|
||||
str r0, [r3, #SSI_DR0_OFFSET]
|
||||
// Dummy byte:
|
||||
str r0, [r3, #SSI_DR0_OFFSET]
|
||||
|
||||
bl wait_ssi_ready
|
||||
// Discard first byte and combine the next two
|
||||
ldr r0, [r3, #SSI_DR0_OFFSET]
|
||||
ldr r0, [r3, #SSI_DR0_OFFSET]
|
||||
|
||||
pop {r1, pc}
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Literal Table
|
||||
// ----------------------------------------------------------------------------
|
||||
// Pull in standard exit routine
|
||||
#include "boot2_helpers/exit_from_boot2.S"
|
||||
|
||||
.global literals
|
||||
literals:
|
||||
|
@ -1,6 +1,6 @@
|
||||
// ----------------------------------------------------------------------------
|
||||
// Second stage boot code
|
||||
// Copyright (c) 2019 Raspberry Pi (Trading) Ltd.
|
||||
// Copyright (c) 2019-2021 Raspberry Pi (Trading) Ltd.
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
//
|
||||
// Device: ISSI IS25LP080D
|
||||
// Based on W25Q080 code: main difference is the QE bit being in
|
||||
@ -29,7 +29,7 @@
|
||||
|
||||
#include "pico/asm_helper.S"
|
||||
#include "hardware/regs/addressmap.h"
|
||||
#include "ssi.h"
|
||||
#include "hardware/regs/ssi.h"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Config section
|
||||
@ -89,16 +89,17 @@
|
||||
.type _stage2_boot,%function
|
||||
.thumb_func
|
||||
_stage2_boot:
|
||||
push {lr}
|
||||
|
||||
ldr r5, =XIP_SSI_BASE // Use as base address where possible
|
||||
ldr r3, =XIP_SSI_BASE // Use as base address where possible
|
||||
|
||||
// Disable SSI to allow further config
|
||||
mov r1, #0
|
||||
str r1, [r5, #SSI_SSIENR_OFFSET]
|
||||
str r1, [r3, #SSI_SSIENR_OFFSET]
|
||||
|
||||
// Set baud rate
|
||||
mov r1, #PICO_FLASH_SPI_CLKDIV
|
||||
str r1, [r5, #SSI_BAUDR_OFFSET]
|
||||
str r1, [r3, #SSI_BAUDR_OFFSET]
|
||||
|
||||
// On QSPI parts we usually need a 01h SR-write command to enable QSPI mode
|
||||
// (i.e. turn WPn and HOLDn into IO2/IO3)
|
||||
@ -109,11 +110,11 @@ program_sregs:
|
||||
(SSI_CTRLR0_TMOD_VALUE_TX_AND_RX << SSI_CTRLR0_TMOD_LSB)
|
||||
|
||||
ldr r1, =(CTRL0_SPI_TXRX)
|
||||
str r1, [r5, #SSI_CTRLR0_OFFSET]
|
||||
str r1, [r3, #SSI_CTRLR0_OFFSET]
|
||||
|
||||
// Enable SSI and select slave 0
|
||||
mov r1, #1
|
||||
str r1, [r5, #SSI_SSIENR_OFFSET]
|
||||
str r1, [r3, #SSI_SSIENR_OFFSET]
|
||||
|
||||
// Check whether SR needs updating
|
||||
ldr r0, =CMD_READ_STATUS
|
||||
@ -124,21 +125,21 @@ program_sregs:
|
||||
|
||||
// Send write enable command
|
||||
mov r1, #CMD_WRITE_ENABLE
|
||||
str r1, [r5, #SSI_DR0_OFFSET]
|
||||
str r1, [r3, #SSI_DR0_OFFSET]
|
||||
|
||||
// Poll for completion and discard RX
|
||||
bl wait_ssi_ready
|
||||
ldr r1, [r5, #SSI_DR0_OFFSET]
|
||||
ldr r1, [r3, #SSI_DR0_OFFSET]
|
||||
|
||||
// Send status write command followed by data bytes
|
||||
mov r1, #CMD_WRITE_STATUS
|
||||
str r1, [r5, #SSI_DR0_OFFSET]
|
||||
str r1, [r3, #SSI_DR0_OFFSET]
|
||||
mov r0, #0
|
||||
str r2, [r5, #SSI_DR0_OFFSET]
|
||||
str r2, [r3, #SSI_DR0_OFFSET]
|
||||
|
||||
bl wait_ssi_ready
|
||||
ldr r1, [r5, #SSI_DR0_OFFSET]
|
||||
ldr r1, [r5, #SSI_DR0_OFFSET]
|
||||
ldr r1, [r3, #SSI_DR0_OFFSET]
|
||||
ldr r1, [r3, #SSI_DR0_OFFSET]
|
||||
|
||||
// Poll status register for write completion
|
||||
1:
|
||||
@ -152,12 +153,12 @@ skip_sreg_programming:
|
||||
|
||||
// Send a 0xA3 high-performance-mode instruction
|
||||
// ldr r1, =0xa3
|
||||
// str r1, [r5, #SSI_DR0_OFFSET]
|
||||
// str r1, [r3, #SSI_DR0_OFFSET]
|
||||
// bl wait_ssi_ready
|
||||
|
||||
// Disable SSI again so that it can be reconfigured
|
||||
mov r1, #0
|
||||
str r1, [r5, #SSI_SSIENR_OFFSET]
|
||||
str r1, [r3, #SSI_SSIENR_OFFSET]
|
||||
#endif
|
||||
|
||||
|
||||
@ -179,10 +180,10 @@ dummy_read:
|
||||
<< SSI_CTRLR0_TMOD_LSB)
|
||||
|
||||
ldr r1, =(CTRLR0_ENTER_XIP)
|
||||
str r1, [r5, #SSI_CTRLR0_OFFSET]
|
||||
str r1, [r3, #SSI_CTRLR0_OFFSET]
|
||||
|
||||
mov r1, #0x0 // NDF=0 (single 32b read)
|
||||
str r1, [r5, #SSI_CTRLR1_OFFSET]
|
||||
str r1, [r3, #SSI_CTRLR1_OFFSET]
|
||||
|
||||
#define SPI_CTRLR0_ENTER_XIP \
|
||||
(ADDR_L << SSI_SPI_CTRLR0_ADDR_L_LSB) | /* Address + mode bits */ \
|
||||
@ -197,12 +198,12 @@ dummy_read:
|
||||
str r1, [r0]
|
||||
|
||||
mov r1, #1 // Re-enable SSI
|
||||
str r1, [r5, #SSI_SSIENR_OFFSET]
|
||||
str r1, [r3, #SSI_SSIENR_OFFSET]
|
||||
|
||||
mov r1, #CMD_READ
|
||||
str r1, [r5, #SSI_DR0_OFFSET] // Push SPI command into TX FIFO
|
||||
str r1, [r3, #SSI_DR0_OFFSET] // Push SPI command into TX FIFO
|
||||
mov r1, #MODE_CONTINUOUS_READ // 32-bit: 24 address bits (we don't care, so 0) and M[7:4]=1010
|
||||
str r1, [r5, #SSI_DR0_OFFSET] // Push Address into TX FIFO - this will trigger the transaction
|
||||
str r1, [r3, #SSI_DR0_OFFSET] // Push Address into TX FIFO - this will trigger the transaction
|
||||
|
||||
// Poll for completion
|
||||
bl wait_ssi_ready
|
||||
@ -218,7 +219,7 @@ dummy_read:
|
||||
// to 4'b0000).
|
||||
|
||||
mov r1, #0
|
||||
str r1, [r5, #SSI_SSIENR_OFFSET] // Disable SSI (and clear FIFO) to allow further config
|
||||
str r1, [r3, #SSI_SSIENR_OFFSET] // 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:
|
||||
@ -240,58 +241,20 @@ configure_ssi:
|
||||
str r1, [r0]
|
||||
|
||||
mov r1, #1
|
||||
str r1, [r5, #SSI_SSIENR_OFFSET] // Re-enable SSI
|
||||
str r1, [r3, #SSI_SSIENR_OFFSET] // Re-enable SSI
|
||||
|
||||
// We are now in XIP mode, with all transactions using Dual I/O and only
|
||||
// needing to send 24-bit addresses (plus mode bits) for each read transaction.
|
||||
|
||||
soft_reset:
|
||||
// Just jump to start of image after this 256-byte boot stage2 (with thumb bit set)
|
||||
ldr r0, =(XIP_BASE + 256 + 1)
|
||||
bx r0
|
||||
// Pull in standard exit routine
|
||||
#include "boot2_helpers/exit_from_boot2.S"
|
||||
|
||||
// Common functions
|
||||
|
||||
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, [r5, #SSI_SR_OFFSET]
|
||||
mov r0, #SSI_SR_TFE_BITS
|
||||
tst r1, r0
|
||||
beq 1b
|
||||
mov r0, #SSI_SR_BUSY_BITS
|
||||
tst r1, r0
|
||||
bne 1b
|
||||
|
||||
pop {r0, r1, pc}
|
||||
|
||||
#include "boot2_helpers/wait_ssi_ready.S"
|
||||
#ifdef PROGRAM_STATUS_REG
|
||||
// Pass status read cmd into r0.
|
||||
// Returns status value in r0.
|
||||
.global read_flash_sreg
|
||||
.type read_flash_sreg,%function
|
||||
.thumb_func
|
||||
read_flash_sreg:
|
||||
push {r1, lr}
|
||||
str r0, [r5, #SSI_DR0_OFFSET]
|
||||
// Dummy byte:
|
||||
str r0, [r5, #SSI_DR0_OFFSET]
|
||||
|
||||
bl wait_ssi_ready
|
||||
// Discard first byte and combine the next two
|
||||
ldr r0, [r5, #SSI_DR0_OFFSET]
|
||||
ldr r0, [r5, #SSI_DR0_OFFSET]
|
||||
|
||||
pop {r1, pc}
|
||||
#include "boot2_helpers/read_flash_sreg.S"
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Literal Table
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
.global literals
|
||||
literals:
|
||||
.ltorg
|
||||
|
@ -1,3 +1,9 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
// Stub second stage which calls into USB bootcode, with parameters.
|
||||
// USB boot takes two parameters:
|
||||
// - A GPIO mask for activity LED -- if mask is 0, don't touch GPIOs at all
|
||||
|
@ -1,6 +1,7 @@
|
||||
// ----------------------------------------------------------------------------
|
||||
// Second stage boot code
|
||||
// Copyright (c) 2019 Raspberry Pi (Trading) Ltd.
|
||||
// Copyright (c) 2019-2021 Raspberry Pi (Trading) Ltd.
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
//
|
||||
// Device: Winbond W25Q080
|
||||
// Also supports W25Q16JV (which has some different SR instructions)
|
||||
@ -270,59 +271,15 @@ configure_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.
|
||||
|
||||
soft_reset:
|
||||
// Jump to exit point provided in lr. Bootrom will pass null, in which
|
||||
// case we use default exit target at a 256 byte offset into XIP region
|
||||
// (immediately after this second stage's flash location)
|
||||
pop {r0}
|
||||
cmp r0, #0
|
||||
bne 1f
|
||||
ldr r0, =(XIP_BASE + 0x101)
|
||||
1:
|
||||
bx r0
|
||||
// Pull in standard exit routine
|
||||
#include "boot2_helpers/exit_from_boot2.S"
|
||||
|
||||
// Common functions
|
||||
|
||||
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, #SSI_SR_OFFSET]
|
||||
movs r0, #SSI_SR_TFE_BITS
|
||||
tst r1, r0
|
||||
beq 1b
|
||||
movs r0, #SSI_SR_BUSY_BITS
|
||||
tst r1, r0
|
||||
bne 1b
|
||||
|
||||
pop {r0, r1, pc}
|
||||
|
||||
#include "boot2_helpers/wait_ssi_ready.S"
|
||||
#ifdef PROGRAM_STATUS_REG
|
||||
// Pass status read cmd into r0.
|
||||
// Returns status value in r0.
|
||||
.global read_flash_sreg
|
||||
.type read_flash_sreg,%function
|
||||
.thumb_func
|
||||
read_flash_sreg:
|
||||
push {r1, lr}
|
||||
str r0, [r3, #SSI_DR0_OFFSET]
|
||||
// Dummy byte:
|
||||
str r0, [r3, #SSI_DR0_OFFSET]
|
||||
|
||||
bl wait_ssi_ready
|
||||
// Discard first byte and combine the next two
|
||||
ldr r0, [r3, #SSI_DR0_OFFSET]
|
||||
ldr r0, [r3, #SSI_DR0_OFFSET]
|
||||
|
||||
pop {r1, pc}
|
||||
#include "boot2_helpers/read_flash_sreg.S"
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Literal Table
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
.global literals
|
||||
literals:
|
||||
.ltorg
|
||||
|
@ -1,26 +1,7 @@
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// .d8888b. 888 .d8888b. 888
|
||||
// d88P Y88b 888 d88P Y88b 888
|
||||
// 888 888 Y88b. 888
|
||||
// .d88P 88888b. .d88888 "Y888b. 888888 8888b. .d88b. .d88b.
|
||||
// .od888P" 888 "88b d88" 888 "Y88b. 888 "88b d88P"88b d8P Y8b
|
||||
// d88P" 888 888 888 888 "888 888 .d888888 888 888 88888888
|
||||
// 888" 888 888 Y88b 888 Y88b d88P Y88b. 888 888 Y88b 888 Y8b.
|
||||
// 888888888 888 888 "Y88888 "Y8888P" "Y888 "Y888888 "Y88888 "Y8888
|
||||
// 888
|
||||
// Y8b d88P
|
||||
// "Y88P"
|
||||
// 888888b. 888 .d8888b. 888
|
||||
// 888 "88b 888 d88P Y88b 888
|
||||
// 888 .88P 888 888 888 888
|
||||
// 8888888K. .d88b. .d88b. 888888 888 .d88b. .d88888 .d88b.
|
||||
// 888 "Y88b d88""88b d88""88b 888 888 d88""88b d88" 888 d8P Y8b
|
||||
// 888 888 888 888 888 888 888 888 888 888 888 888 888 88888888
|
||||
// 888 d88P Y88..88P Y88..88P Y88b. Y88b d88P Y88..88P Y88b 888 Y8b.
|
||||
// 8888888P" "Y88P" "Y88P" "Y888 "Y8888P" "Y88P" "Y88888 "Y8888
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Second stage boot code
|
||||
// Copyright (c) 2019-2021 Raspberry Pi (Trading) Ltd.
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
//
|
||||
// Device: Winbond W25X10CL
|
||||
//
|
||||
@ -51,7 +32,7 @@
|
||||
|
||||
#include "pico/asm_helper.S"
|
||||
#include "hardware/regs/addressmap.h"
|
||||
#include "ssi.h"
|
||||
#include "hardware/regs/ssi.h"
|
||||
|
||||
// The serial flash interface will run at clk_sys/PICO_FLASH_SPI_CLKDIV.
|
||||
// This must be an even number.
|
||||
@ -101,19 +82,19 @@
|
||||
.type _stage2_boot,%function
|
||||
.thumb_func
|
||||
_stage2_boot:
|
||||
|
||||
ldr r5, =XIP_SSI_BASE // Use as base address where possible
|
||||
push {lr}
|
||||
ldr r3, =XIP_SSI_BASE // Use as base address where possible
|
||||
|
||||
// We are primarily interested in setting up Flash for DSPI XIP w/ continuous read
|
||||
|
||||
mov r1, #0
|
||||
str r1, [r5, #SSI_SSIENR_OFFSET] // Disable SSI to allow further config
|
||||
str r1, [r3, #SSI_SSIENR_OFFSET] // Disable SSI to allow further config
|
||||
|
||||
// The Boot ROM sets a very conservative SPI clock frequency to be sure it can
|
||||
// read the initial 256 bytes from any device. Here we can be more aggressive.
|
||||
|
||||
mov r1, #PICO_FLASH_SPI_CLKDIV
|
||||
str r1, [r5, #SSI_BAUDR_OFFSET] // Set SSI Clock
|
||||
str r1, [r3, #SSI_BAUDR_OFFSET] // Set SSI Clock
|
||||
|
||||
// First we need to send the initial command to get us in to Fast Read Dual I/O
|
||||
// mode. As this transaction requires a command, we can't send it in XIP mode.
|
||||
@ -133,10 +114,10 @@ _stage2_boot:
|
||||
<< SSI_CTRLR0_TMOD_LSB)
|
||||
|
||||
ldr r1, =(CTRLR0_ENTER_XIP)
|
||||
str r1, [r5, #SSI_CTRLR0_OFFSET]
|
||||
str r1, [r3, #SSI_CTRLR0_OFFSET]
|
||||
|
||||
mov r1, #0x0 // NDF=0 (single 32b read)
|
||||
str r1, [r5, #SSI_CTRLR1_OFFSET]
|
||||
str r1, [r3, #SSI_CTRLR1_OFFSET]
|
||||
|
||||
#define SPI_CTRLR0_ENTER_XIP \
|
||||
(7 << SSI_SPI_CTRLR0_ADDR_L_LSB) | /* Send 28 bits (24 address + 4 mode) */ \
|
||||
@ -151,19 +132,19 @@ _stage2_boot:
|
||||
str r1, [r0]
|
||||
|
||||
mov r1, #1 // Re-enable SSI
|
||||
str r1, [r5, #SSI_SSIENR_OFFSET]
|
||||
str r1, [r3, #SSI_SSIENR_OFFSET]
|
||||
|
||||
mov r1, #W25X10CL_CMD_READ_DATA_FAST_DUAL_IO // 8b command = 0xBB
|
||||
str r1, [r5, #SSI_DR0_OFFSET] // Push SPI command into TX FIFO
|
||||
str r1, [r3, #SSI_DR0_OFFSET] // Push SPI command into TX FIFO
|
||||
mov r1, #0x0000002 // 28-bit Address for dummy read = 0x000000 + 0x2 Mode bits to set M[5:4]=10
|
||||
str r1, [r5, #SSI_DR0_OFFSET] // Push Address into TX FIFO - this will trigger the transaction
|
||||
str r1, [r3, #SSI_DR0_OFFSET] // Push Address into TX FIFO - this will trigger the transaction
|
||||
|
||||
// Now we wait for the read transaction to complete by monitoring the SSI
|
||||
// status register and checking for the "RX FIFO Not Empty" flag to assert.
|
||||
|
||||
mov r1, #SSI_SR_RFNE_BITS
|
||||
00:
|
||||
ldr r0, [r5, #SSI_SR_OFFSET] // Read status register
|
||||
ldr r0, [r3, #SSI_SR_OFFSET] // Read status register
|
||||
tst r0, r1 // RFNE status flag set?
|
||||
beq 00b // If not then wait
|
||||
|
||||
@ -178,7 +159,7 @@ _stage2_boot:
|
||||
// to 4'b0000).
|
||||
|
||||
mov r1, #0
|
||||
str r1, [r5, #SSI_SSIENR_OFFSET] // Disable SSI (and clear FIFO) to allow further config
|
||||
str r1, [r3, #SSI_SSIENR_OFFSET] // 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:
|
||||
@ -200,20 +181,16 @@ _stage2_boot:
|
||||
str r1, [r0]
|
||||
|
||||
mov r1, #1
|
||||
str r1, [r5, #SSI_SSIENR_OFFSET] // Re-enable SSI
|
||||
str r1, [r3, #SSI_SSIENR_OFFSET] // Re-enable SSI
|
||||
|
||||
// We are now in XIP mode, with all transactions using Dual I/O and only
|
||||
// needing to send 24-bit addresses (plus mode bits) for each read transaction.
|
||||
|
||||
soft_reset:
|
||||
// Just jump to start of image after this 256-byte boot stage2 (with thumb bit set)
|
||||
ldr r0, =(XIP_BASE + 256 + 1)
|
||||
bx r0
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Literal Table
|
||||
// ----------------------------------------------------------------------------
|
||||
// Pull in standard exit routine
|
||||
#include "boot2_helpers/exit_from_boot2.S"
|
||||
|
||||
.global literals
|
||||
literals:
|
||||
.ltorg
|
||||
|
||||
.end
|
||||
|
@ -144,40 +144,61 @@ __unhandled_user_irq:
|
||||
unhandled_user_irq_num_in_r0:
|
||||
bkpt #0
|
||||
|
||||
.section .reset, "ax"
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// This is the beginning of the image, which is entered from stage2 or bootrom USB MSD watchdog reboot
|
||||
.section .binary_info_header, "a"
|
||||
|
||||
// note if we are NO_FLASH then start: below is currently identical anyway, so save 4 bytes
|
||||
#if !PICO_NO_FLASH
|
||||
// We simply install our own vector table and redirect through it
|
||||
ldr r0, =__vectors
|
||||
b __vector_entry
|
||||
// Header must be in first 256 bytes of main image (i.e. excluding flash boot2).
|
||||
// For flash builds we put it immediately after vector table; for NO_FLASH the
|
||||
// vectors are at a +0x100 offset because the bootrom enters RAM images directly
|
||||
// at their lowest address, so we put the header in the VTOR alignment hole.
|
||||
|
||||
#if !PICO_NO_BINARY_INFO
|
||||
binary_info_header:
|
||||
.word BINARY_INFO_MARKER_START
|
||||
.word __binary_info_start
|
||||
.word __binary_info_end
|
||||
.word data_cpy_table // we may need to decode pointers that are in RAM at runtime.
|
||||
.word BINARY_INFO_MARKER_END
|
||||
#endif
|
||||
|
||||
// ELF entry point generally called when we load an ELF via debugger
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
.section .reset, "ax"
|
||||
|
||||
// On flash builds, the vector table comes first in the image (conventional).
|
||||
// On NO_FLASH builds, the reset handler section comes first, as the entry
|
||||
// point is at offset 0 (fixed due to bootrom), and VTOR is highly-aligned.
|
||||
// Image is entered in various ways:
|
||||
//
|
||||
// - NO_FLASH builds are entered from beginning by UF2 bootloader
|
||||
//
|
||||
// - Flash builds vector through the table into _reset_handler from boot2
|
||||
//
|
||||
// - Either type can be entered via _entry_point by the debugger, and flash builds
|
||||
// must then be sent back round the boot sequence to properly initialise flash
|
||||
|
||||
// ELF entry point:
|
||||
.type _entry_point,%function
|
||||
.thumb_func
|
||||
.global _entry_point
|
||||
_entry_point:
|
||||
|
||||
#if PICO_NO_FLASH
|
||||
// non flash
|
||||
// Vector through our own table (SP, VTOR will not have been set up at
|
||||
// this point). Same path for debugger entry and bootloader entry.
|
||||
ldr r0, =__vectors
|
||||
#else
|
||||
// todo clear watchdog?
|
||||
// When using flash, we install and use the ROM vector table to go thru regular bootrom/stage2 flash sequence
|
||||
// Debugger tried to run code after loading, so SSI is in 03h-only mode.
|
||||
// Go back through bootrom + boot2 to properly initialise flash.
|
||||
movs r0, #0
|
||||
#endif
|
||||
|
||||
__vector_entry:
|
||||
ldr r1, =(PPB_BASE + M0PLUS_CPUID_OFFSET)
|
||||
str r0, [r1, #8]
|
||||
ldr r1, =(PPB_BASE + M0PLUS_VTOR_OFFSET)
|
||||
str r0, [r1]
|
||||
ldmia r0!, {r1, r2}
|
||||
msr msp, r1
|
||||
bx r2
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Reset handler:
|
||||
// - initialises .data
|
||||
// - clears .bss
|
||||
@ -188,11 +209,12 @@ __vector_entry:
|
||||
.type _reset_handler,%function
|
||||
.thumb_func
|
||||
_reset_handler:
|
||||
// Hang all cores except core 0
|
||||
// Only core 0 should run the C runtime startup code; core 1 is normally
|
||||
// sleeping in the bootrom at this point but check to be sure
|
||||
ldr r0, =(SIO_BASE + SIO_CPUID_OFFSET)
|
||||
ldr r0, [r0]
|
||||
cmp r0, #0
|
||||
bne wait_for_vector
|
||||
bne hold_non_core0_in_bootrom
|
||||
|
||||
adr r4, data_cpy_table
|
||||
|
||||
@ -243,15 +265,6 @@ data_cpy:
|
||||
blo data_cpy_loop
|
||||
bx lr
|
||||
|
||||
#if !PICO_NO_BINARY_INFO
|
||||
binary_info_header:
|
||||
.word BINARY_INFO_MARKER_START
|
||||
.word __binary_info_start
|
||||
.word __binary_info_end
|
||||
.word data_cpy_table // we may need to decode pointers that are in RAM at runtime.
|
||||
.word BINARY_INFO_MARKER_END
|
||||
#endif
|
||||
|
||||
.align 2
|
||||
data_cpy_table:
|
||||
#if PICO_COPY_TO_RAM
|
||||
@ -284,11 +297,12 @@ runtime_init:
|
||||
bx lr
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// In case core 1's VTOR has already been moved into flash, we need to handle
|
||||
// core 1 reset. However, we do so by just jumping back into bootrom version of
|
||||
// wait_for_vector
|
||||
// If core 1 somehow gets into crt0 due to a spectacular VTOR mishap, we need to
|
||||
// catch it and send back to the sleep-and-launch code in the bootrom. Shouldn't
|
||||
// happen (it should sleep in the ROM until given an entry point via the
|
||||
// cross-core FIFOs) but it's good to be defensive.
|
||||
|
||||
wait_for_vector:
|
||||
hold_non_core0_in_bootrom:
|
||||
ldr r0, = 'W' | ('V' << 8)
|
||||
bl rom_func_lookup
|
||||
bx r0
|
||||
@ -312,4 +326,4 @@ __get_current_exception:
|
||||
.section .heap
|
||||
.align 2
|
||||
.equ HeapSize, PICO_HEAP_SIZE
|
||||
.space HeapSize
|
||||
.space HeapSize
|
||||
|
@ -59,12 +59,11 @@ SECTIONS
|
||||
*/
|
||||
|
||||
.text : {
|
||||
__reset_start = .;
|
||||
KEEP (*(.reset))
|
||||
. = ALIGN(256);
|
||||
__reset_end = .;
|
||||
ASSERT(__reset_end - __reset_start == 256, "ERROR: reset section should only be 256 bytes");
|
||||
__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 */
|
||||
@ -246,6 +245,8 @@ SECTIONS
|
||||
|
||||
/* Check if data + heap + stack exceeds RAM limit */
|
||||
ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed")
|
||||
|
||||
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 */
|
||||
}
|
||||
|
||||
|
@ -59,12 +59,11 @@ SECTIONS
|
||||
*/
|
||||
|
||||
.flashtext : {
|
||||
__reset_start = .;
|
||||
KEEP (*(.reset))
|
||||
. = ALIGN(256);
|
||||
__reset_end = .;
|
||||
ASSERT(__reset_end - __reset_start == 256, "ERROR: reset section should only be 256 bytes");
|
||||
__logical_binary_start = .;
|
||||
KEEP (*(.vectors))
|
||||
KEEP (*(.binary_info_header))
|
||||
__binary_info_header_end = .;
|
||||
KEEP (*(.reset))
|
||||
}
|
||||
|
||||
.rodata : {
|
||||
@ -247,6 +246,8 @@ SECTIONS
|
||||
|
||||
/* Check if data + heap + stack exceeds RAM limit */
|
||||
ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed")
|
||||
|
||||
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 */
|
||||
}
|
||||
|
||||
|
@ -59,12 +59,11 @@ SECTIONS
|
||||
*/
|
||||
|
||||
.text : {
|
||||
__reset_start = .;
|
||||
KEEP (*(.reset))
|
||||
. = ALIGN(256);
|
||||
__reset_end = .;
|
||||
ASSERT(__reset_end - __reset_start == 256, "ERROR: reset section should only be 256 bytes");
|
||||
__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 */
|
||||
@ -246,6 +245,8 @@ SECTIONS
|
||||
|
||||
/* Check if data + heap + stack exceeds RAM limit */
|
||||
ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed")
|
||||
|
||||
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 */
|
||||
}
|
||||
|
||||
|
@ -32,19 +32,21 @@ ENTRY(_entry_point)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
/* Watchdog reboot into RAM (via USB MSD will enter) 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.
|
||||
/* Note in NO_FLASH builds the entry point for both the bootrom, and debugger
|
||||
entry (ELF entry point), are *first* in the image, and the vector table
|
||||
follows immediately afterward. This is because the bootrom enters RAM
|
||||
binaries directly at their lowest address (preferring main RAM over XIP
|
||||
cache-as-SRAM if both are used).
|
||||
*/
|
||||
|
||||
.text : {
|
||||
__reset_start = .;
|
||||
__logical_binary_start = .;
|
||||
__reset_start = .;
|
||||
KEEP (*(.reset))
|
||||
/* reset should come first */
|
||||
KEEP (*(.reset))
|
||||
. = ALIGN(256);
|
||||
__reset_end = .;
|
||||
ASSERT(__reset_end - __reset_start == 256, "ERROR: reset section should only be 256 bytes");
|
||||
KEEP (*(.binary_info_header))
|
||||
__binary_info_header_end = .;
|
||||
. = ALIGN(256);
|
||||
KEEP (*(.vectors))
|
||||
*(.time_critical*)
|
||||
*(.text*)
|
||||
@ -208,6 +210,8 @@ SECTIONS
|
||||
|
||||
/* Check if data + heap + stack exceeds RAM limit */
|
||||
ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed")
|
||||
|
||||
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 */
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user