Implements proper support for different stage2 bootloaders (#80)
Co-authored-by: Felix "xq" Queißner <git@random-projects.net>wch-ch32v003
parent
6f201f7f4c
commit
2a0c0ff281
@ -1,15 +1,69 @@
|
||||
const std = @import("std");
|
||||
const microzig = @import("microzig");
|
||||
const rp2040 = @import("../build.zig");
|
||||
const chips = @import("chips.zig");
|
||||
|
||||
fn root_dir() []const u8 {
|
||||
return std.fs.path.dirname(@src().file) orelse ".";
|
||||
}
|
||||
|
||||
const board_path = std.fmt.comptimePrint("{s}/boards/raspberry_pi_pico.zig", .{root_dir()});
|
||||
fn board_path(comptime path: []const u8) std.Build.LazyPath {
|
||||
return .{
|
||||
.path = std.fmt.comptimePrint("{s}/boards/{s}", .{ root_dir(), path }),
|
||||
};
|
||||
}
|
||||
|
||||
pub const Board = struct {
|
||||
inner: microzig.Board,
|
||||
bootrom: rp2040.BootROM,
|
||||
};
|
||||
|
||||
pub const raspberry_pi_pico = microzig.Board{
|
||||
// https://www.raspberrypi.com/products/raspberry-pi-pico/
|
||||
pub const raspberry_pi_pico = Board{
|
||||
.inner = .{
|
||||
.name = "Raspberry Pi Pico",
|
||||
.source = .{ .path = board_path },
|
||||
.source = board_path("raspberry_pi_pico.zig"),
|
||||
.chip = chips.rp2040,
|
||||
},
|
||||
.bootrom = .w25q080,
|
||||
};
|
||||
|
||||
// https://www.waveshare.com/rp2040-plus.htm
|
||||
pub const waveshare_rp2040_plus_4m = Board{
|
||||
.inner = .{
|
||||
.name = "Waveshare RP2040-Plus (4M Flash)",
|
||||
.source = board_path("waveshare_rp2040_plus_4m.zig"),
|
||||
.chip = chips.rp2040,
|
||||
},
|
||||
.bootrom = .w25q080,
|
||||
};
|
||||
|
||||
// https://www.waveshare.com/rp2040-plus.htm
|
||||
pub const waveshare_rp2040_plus_16m = Board{
|
||||
.inner = .{
|
||||
.name = "Waveshare RP2040-Plus (16M Flash)",
|
||||
.source = board_path("waveshare_rp2040_plus_16m.zig"),
|
||||
.chip = chips.rp2040,
|
||||
},
|
||||
.bootrom = .w25q080,
|
||||
};
|
||||
|
||||
// https://www.waveshare.com/rp2040-eth.htm
|
||||
pub const waveshare_rp2040_eth = Board{
|
||||
.inner = .{
|
||||
.name = "Waveshare RP2040-ETH Mini",
|
||||
.source = board_path("waveshare_rp2040_eth.zig"),
|
||||
.chip = chips.rp2040,
|
||||
},
|
||||
.bootrom = .w25q080,
|
||||
};
|
||||
|
||||
// https://www.waveshare.com/rp2040-matrix.htm
|
||||
pub const waveshare_rp2040_matrix = Board{
|
||||
.inner = .{
|
||||
.name = "Waveshare RP2040-Matrix",
|
||||
.source = board_path("waveshare_rp2040_matrix.zig"),
|
||||
.chip = chips.rp2040,
|
||||
},
|
||||
.bootrom = .w25q080,
|
||||
};
|
||||
|
@ -1,38 +1,5 @@
|
||||
pub const xosc_freq = 12_000_000;
|
||||
|
||||
// TODO: improve interface so that user can use a custom implementation and
|
||||
// automatically checksum it.
|
||||
pub export const _BOOT2: [256]u8 linksection(".boot2") = [_]u8{
|
||||
0x00, 0xb5, 0x32, 0x4b, 0x21, 0x20, 0x58, 0x60,
|
||||
0x98, 0x68, 0x02, 0x21, 0x88, 0x43, 0x98, 0x60,
|
||||
0xd8, 0x60, 0x18, 0x61, 0x58, 0x61, 0x2e, 0x4b,
|
||||
0x00, 0x21, 0x99, 0x60, 0x02, 0x21, 0x59, 0x61,
|
||||
0x01, 0x21, 0xf0, 0x22, 0x99, 0x50, 0x2b, 0x49,
|
||||
0x19, 0x60, 0x01, 0x21, 0x99, 0x60, 0x35, 0x20,
|
||||
0x00, 0xf0, 0x44, 0xf8, 0x02, 0x22, 0x90, 0x42,
|
||||
0x14, 0xd0, 0x06, 0x21, 0x19, 0x66, 0x00, 0xf0,
|
||||
0x34, 0xf8, 0x19, 0x6e, 0x01, 0x21, 0x19, 0x66,
|
||||
0x00, 0x20, 0x18, 0x66, 0x1a, 0x66, 0x00, 0xf0,
|
||||
0x2c, 0xf8, 0x19, 0x6e, 0x19, 0x6e, 0x19, 0x6e,
|
||||
0x05, 0x20, 0x00, 0xf0, 0x2f, 0xf8, 0x01, 0x21,
|
||||
0x08, 0x42, 0xf9, 0xd1, 0x00, 0x21, 0x99, 0x60,
|
||||
0x1b, 0x49, 0x19, 0x60, 0x00, 0x21, 0x59, 0x60,
|
||||
0x1a, 0x49, 0x1b, 0x48, 0x01, 0x60, 0x01, 0x21,
|
||||
0x99, 0x60, 0xeb, 0x21, 0x19, 0x66, 0xa0, 0x21,
|
||||
0x19, 0x66, 0x00, 0xf0, 0x12, 0xf8, 0x00, 0x21,
|
||||
0x99, 0x60, 0x16, 0x49, 0x14, 0x48, 0x01, 0x60,
|
||||
0x01, 0x21, 0x99, 0x60, 0x01, 0xbc, 0x00, 0x28,
|
||||
0x00, 0xd0, 0x00, 0x47, 0x12, 0x48, 0x13, 0x49,
|
||||
0x08, 0x60, 0x03, 0xc8, 0x80, 0xf3, 0x08, 0x88,
|
||||
0x08, 0x47, 0x03, 0xb5, 0x99, 0x6a, 0x04, 0x20,
|
||||
0x01, 0x42, 0xfb, 0xd0, 0x01, 0x20, 0x01, 0x42,
|
||||
0xf8, 0xd1, 0x03, 0xbd, 0x02, 0xb5, 0x18, 0x66,
|
||||
0x18, 0x66, 0xff, 0xf7, 0xf2, 0xff, 0x18, 0x6e,
|
||||
0x18, 0x6e, 0x02, 0xbd, 0x00, 0x00, 0x02, 0x40,
|
||||
0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0x00,
|
||||
0x00, 0x03, 0x5f, 0x00, 0x21, 0x22, 0x00, 0x00,
|
||||
0xf4, 0x00, 0x00, 0x18, 0x22, 0x20, 0x00, 0xa0,
|
||||
0x00, 0x01, 0x00, 0x10, 0x08, 0xed, 0x00, 0xe0,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x74, 0xb2, 0x4e, 0x7a,
|
||||
};
|
||||
comptime {
|
||||
_ = @import("shared/bootrom.zig");
|
||||
}
|
||||
|
@ -0,0 +1,41 @@
|
||||
const std = @import("std");
|
||||
|
||||
comptime {
|
||||
_ = stage2_bootloader;
|
||||
}
|
||||
|
||||
export const stage2_bootloader: [256]u8 linksection(".boot2") = prepareBootSector(
|
||||
@embedFile("bootloader"),
|
||||
);
|
||||
|
||||
/// Create a new
|
||||
fn prepareBootSector(comptime stage2_rom: []const u8) [256]u8 {
|
||||
@setEvalBranchQuota(10_000);
|
||||
|
||||
var bootrom: [256]u8 = .{0xFF} ** 256;
|
||||
@memcpy(bootrom[0..stage2_rom.len], stage2_rom);
|
||||
|
||||
// 2.8.1.3.1. Checksum
|
||||
// The last four bytes of the image loaded from flash (which we hope is a valid flash second stage) are a CRC32 checksum
|
||||
// of the first 252 bytes. The parameters of the checksum are:
|
||||
// • Polynomial: 0x04c11db7
|
||||
// • Input reflection: no
|
||||
// • Output reflection: no
|
||||
// • Initial value: 0xffffffff
|
||||
// • Final XOR: 0x00000000
|
||||
// • Checksum value appears as little-endian integer at end of image
|
||||
// The Bootrom makes 128 attempts of approximately 4ms each for a total of approximately 0.5 seconds before giving up
|
||||
// and dropping into USB code to load and checksum the second stage with varying SPI parameters. If it sees a checksum
|
||||
// pass it will immediately jump into the 252-byte payload which contains the flash second stage.
|
||||
const Hash = std.hash.crc.Crc(u32, .{
|
||||
.polynomial = 0x04c11db7,
|
||||
.initial = 0xffffffff,
|
||||
.reflect_input = false,
|
||||
.reflect_output = false,
|
||||
.xor_output = 0x00000000,
|
||||
});
|
||||
|
||||
std.mem.writeIntLittle(u32, bootrom[252..256], Hash.hash(bootrom[0..252]));
|
||||
|
||||
return bootrom;
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
pub const xosc_freq = 12_000_000;
|
||||
|
||||
comptime {
|
||||
_ = @import("shared/bootrom.zig");
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
pub const xosc_freq = 12_000_000;
|
||||
|
||||
comptime {
|
||||
_ = @import("shared/bootrom.zig");
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
pub const xosc_freq = 12_000_000;
|
||||
|
||||
comptime {
|
||||
_ = @import("shared/bootrom.zig");
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
pub const xosc_freq = 12_000_000;
|
||||
|
||||
comptime {
|
||||
_ = @import("shared/bootrom.zig");
|
||||
}
|
@ -0,0 +1,278 @@
|
||||
// ----------------------------------------------------------------------------
|
||||
// Second stage boot code
|
||||
// Copyright (c) 2019-2021 Raspberry Pi (Trading) Ltd.
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
//
|
||||
// Device: Adesto AT25SF128A
|
||||
// Based on W25Q080 code: main difference is the QE bit is being set
|
||||
// via command 0x31
|
||||
//
|
||||
// Description: Configures AT25SF128A to run in Quad I/O continuous read XIP mode
|
||||
//
|
||||
// Details: * Check status register 2 to determine if QSPI mode is enabled,
|
||||
// and perform an SR2 programming cycle if necessary.
|
||||
// * Use SSI to perform a dummy 0xEB read command, with the mode
|
||||
// continuation bits set, so that the flash will not require
|
||||
// 0xEB instruction prefix on subsequent reads.
|
||||
// * Configure SSI to write address, mode bits, but no instruction.
|
||||
// SSI + flash are now jointly in a state where continuous reads
|
||||
// can take place.
|
||||
// * Jump to exit pointer passed in via lr. Bootrom passes null,
|
||||
// in which case this code uses a default 256 byte flash offset
|
||||
//
|
||||
// Building: * This code must be position-independent, and use stack only
|
||||
// * The code will be padded to a size of 256 bytes, including a
|
||||
// 4-byte checksum. Therefore code size cannot exceed 252 bytes.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include "shared/asm_helper.S"
|
||||
#include "shared/regs.h"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Config section
|
||||
// ----------------------------------------------------------------------------
|
||||
// It should be possible to support most flash devices by modifying this section
|
||||
|
||||
// The serial flash interface will run at clk_sys/PICO_FLASH_SPI_CLKDIV.
|
||||
// This must be a positive, even integer.
|
||||
// The bootrom is very conservative with SPI frequency, but here we should be
|
||||
// as aggressive as possible.
|
||||
|
||||
#ifndef PICO_FLASH_SPI_CLKDIV
|
||||
#define PICO_FLASH_SPI_CLKDIV 4
|
||||
#endif
|
||||
#if PICO_FLASH_SPI_CLKDIV & 1
|
||||
#error PICO_FLASH_SPI_CLKDIV must be even
|
||||
#endif
|
||||
|
||||
// Define interface width: single/dual/quad IO
|
||||
#define FRAME_FORMAT SSI_CTRLR0_SPI_FRF_VALUE_QUAD
|
||||
|
||||
// For W25Q080 this is the "Read data fast quad IO" instruction:
|
||||
#define CMD_READ 0xeb
|
||||
|
||||
// "Mode bits" are 8 special bits sent immediately after
|
||||
// the address bits in a "Read Data Fast Quad I/O" command sequence.
|
||||
// On W25Q080, the four LSBs are don't care, and if MSBs == 0xa, the
|
||||
// next read does not require the 0xeb instruction prefix.
|
||||
#define MODE_CONTINUOUS_READ 0x20
|
||||
|
||||
// The number of address + mode bits, divided by 4 (always 4, not function of
|
||||
// interface width).
|
||||
#define ADDR_L 8
|
||||
|
||||
// How many clocks of Hi-Z following the mode bits. For W25Q080, 4 dummy cycles
|
||||
// are required.
|
||||
#define WAIT_CYCLES 4
|
||||
|
||||
// If defined, we will read status reg, compare to SREG_DATA, and overwrite
|
||||
// with our value if the SR doesn't match.
|
||||
// We do a two-byte write to SR1 (01h cmd) rather than a one-byte write to
|
||||
// SR2 (31h cmd) as the latter command isn't supported by WX25Q080.
|
||||
// This isn't great because it will remove block protections.
|
||||
// A better solution is to use a volatile SR write if your device supports it.
|
||||
#define PROGRAM_STATUS_REG
|
||||
|
||||
#define CMD_WRITE_ENABLE 0x06
|
||||
#define CMD_READ_STATUS 0x05
|
||||
#define CMD_READ_STATUS2 0x35
|
||||
#define CMD_WRITE_STATUS 0x01
|
||||
#define CMD_WRITE_STATUS2 0x31
|
||||
#define SREG_DATA 0x02 // Enable quad-SPI mode
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Start of 2nd Stage Boot Code
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
pico_default_asm_setup
|
||||
|
||||
.section .text
|
||||
|
||||
// The exit point is passed in lr. If entered from bootrom, this will be the
|
||||
// flash address immediately following this second stage (0x10000100).
|
||||
// Otherwise it will be a return address -- second stage being called as a
|
||||
// function by user code, after copying out of XIP region. r3 holds SSI base,
|
||||
// r0...2 used as temporaries. Other GPRs not used.
|
||||
regular_func _stage2_boot
|
||||
push {lr}
|
||||
|
||||
// Set pad configuration:
|
||||
// - SCLK 8mA drive, no slew limiting
|
||||
// - SDx disable input Schmitt to reduce delay
|
||||
|
||||
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
|
||||
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]
|
||||
|
||||
ldr r3, =XIP_SSI_BASE
|
||||
|
||||
// Disable SSI to allow further config
|
||||
movs r1, #0
|
||||
str r1, [r3, #SSI_SSIENR_OFFSET]
|
||||
|
||||
// Set baud rate
|
||||
movs r1, #PICO_FLASH_SPI_CLKDIV
|
||||
str r1, [r3, #SSI_BAUDR_OFFSET]
|
||||
|
||||
// Set 1-cycle sample delay. If PICO_FLASH_SPI_CLKDIV == 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.
|
||||
|
||||
movs r1, #1
|
||||
movs r2, #SSI_RX_SAMPLE_DLY_OFFSET // == 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)
|
||||
|
||||
ldr r1, =(CTRL0_SPI_TXRX)
|
||||
str r1, [r3, #SSI_CTRLR0_OFFSET]
|
||||
|
||||
// Enable SSI and select slave 0
|
||||
movs r1, #1
|
||||
str r1, [r3, #SSI_SSIENR_OFFSET]
|
||||
|
||||
// Check whether SR needs updating
|
||||
movs r0, #CMD_READ_STATUS2
|
||||
bl read_flash_sreg
|
||||
movs r2, #SREG_DATA
|
||||
cmp r0, r2
|
||||
beq skip_sreg_programming
|
||||
|
||||
// Send write enable command
|
||||
movs r1, #CMD_WRITE_ENABLE
|
||||
str r1, [r3, #SSI_DR0_OFFSET]
|
||||
|
||||
// Poll for completion and discard RX
|
||||
bl wait_ssi_ready
|
||||
ldr r1, [r3, #SSI_DR0_OFFSET]
|
||||
|
||||
// Send status write command followed by data bytes
|
||||
movs r1, #CMD_WRITE_STATUS2
|
||||
str r1, [r3, #SSI_DR0_OFFSET]
|
||||
str r2, [r3, #SSI_DR0_OFFSET]
|
||||
|
||||
bl wait_ssi_ready
|
||||
ldr r1, [r3, #SSI_DR0_OFFSET]
|
||||
ldr r1, [r3, #SSI_DR0_OFFSET]
|
||||
ldr r1, [r3, #SSI_DR0_OFFSET]
|
||||
|
||||
// Poll status register for write completion
|
||||
1:
|
||||
movs r0, #CMD_READ_STATUS
|
||||
bl read_flash_sreg
|
||||
movs r1, #1
|
||||
tst r0, r1
|
||||
bne 1b
|
||||
|
||||
skip_sreg_programming:
|
||||
|
||||
// Disable SSI again so that it can be reconfigured
|
||||
movs r1, #0
|
||||
str r1, [r3, #SSI_SSIENR_OFFSET]
|
||||
#endif
|
||||
|
||||
// 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
|
||||
// command, with mode bits set such that the flash will not expect a serial
|
||||
// command prefix on *subsequent* transfers. We don't care about the results
|
||||
// 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)
|
||||
|
||||
ldr r1, =(CTRLR0_ENTER_XIP)
|
||||
str r1, [r3, #SSI_CTRLR0_OFFSET]
|
||||
|
||||
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, [r0]
|
||||
|
||||
movs r1, #1 // Re-enable SSI
|
||||
str r1, [r3, #SSI_SSIENR_OFFSET]
|
||||
|
||||
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
|
||||
|
||||
// Poll for completion
|
||||
bl wait_ssi_ready
|
||||
|
||||
// The flash is in a state where we can blast addresses in parallel, and get
|
||||
// parallel data back. Now configure the SSI to translate XIP bus accesses
|
||||
// into QSPI transfers of this form.
|
||||
|
||||
movs r1, #0
|
||||
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:
|
||||
// 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)
|
||||
|
||||
ldr r1, =(SPI_CTRLR0_XIP)
|
||||
ldr r0, =(XIP_SSI_BASE + SSI_SPI_CTRLR0_OFFSET)
|
||||
str r1, [r0]
|
||||
|
||||
movs r1, #1
|
||||
str r1, [r3, #SSI_SSIENR_OFFSET] // 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 "shared/exit_from_boot2.S"
|
||||
|
||||
// Common functions
|
||||
#include "shared/wait_ssi_ready.S"
|
||||
#ifdef PROGRAM_STATUS_REG
|
||||
#include "shared/read_flash_sreg.S"
|
||||
#endif
|
||||
|
||||
.global literals
|
||||
literals:
|
||||
.ltorg
|
||||
|
||||
.end
|
@ -0,0 +1,98 @@
|
||||
// ----------------------------------------------------------------------------
|
||||
// Second stage boot code
|
||||
// Copyright (c) 2019-2021 Raspberry Pi (Trading) Ltd.
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
//
|
||||
// Device: Anything which responds to 03h serial read command
|
||||
//
|
||||
// Details: * Configure SSI to translate each APB read into a 03h command
|
||||
// * 8 command clocks, 24 address clocks and 32 data clocks
|
||||
// * This enables you to boot from almost anything: you can pretty
|
||||
// much solder a potato to your PCB, or a piece of cheese
|
||||
// * The tradeoff is performance around 3x worse than QSPI XIP
|
||||
//
|
||||
// Building: * This code must be position-independent, and use stack only
|
||||
// * The code will be padded to a size of 256 bytes, including a
|
||||
// 4-byte checksum. Therefore code size cannot exceed 252 bytes.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include "shared/asm_helper.S"
|
||||
#include "shared/regs.h"
|
||||
|
||||
pico_default_asm_setup
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Config section
|
||||
// ----------------------------------------------------------------------------
|
||||
// It should be possible to support most flash devices by modifying this section
|
||||
|
||||
// The serial flash interface will run at clk_sys/PICO_FLASH_SPI_CLKDIV.
|
||||
// This must be a positive, even integer.
|
||||
// The bootrom is very conservative with SPI frequency, but here we should be
|
||||
// as aggressive as possible.
|
||||
#ifndef PICO_FLASH_SPI_CLKDIV
|
||||
#define PICO_FLASH_SPI_CLKDIV 4
|
||||
#endif
|
||||
|
||||
#define CMD_READ 0x03
|
||||
|
||||
// Value is number of address bits divided by 4
|
||||
#define ADDR_L 6
|
||||
|
||||
#define CTRLR0_XIP \
|
||||
(SSI_CTRLR0_SPI_FRF_VALUE_STD << SSI_CTRLR0_SPI_FRF_LSB) | /* Standard 1-bit SPI serial frames */ \
|
||||
(31 << SSI_CTRLR0_DFS_32_LSB) | /* 32 clocks per data frame */ \
|
||||
(SSI_CTRLR0_TMOD_VALUE_EEPROM_READ << SSI_CTRLR0_TMOD_LSB) /* Send instr + addr, receive data */
|
||||
|
||||
#define SPI_CTRLR0_XIP \
|
||||
(CMD_READ << SSI_SPI_CTRLR0_XIP_CMD_LSB) | /* Value of instruction prefix */ \
|
||||
(ADDR_L << SSI_SPI_CTRLR0_ADDR_L_LSB) | /* Total number of address + mode bits */ \
|
||||
(2 << SSI_SPI_CTRLR0_INST_L_LSB) | /* 8 bit command prefix (field value is bits divided by 4) */ \
|
||||
(SSI_SPI_CTRLR0_TRANS_TYPE_VALUE_1C1A << SSI_SPI_CTRLR0_TRANS_TYPE_LSB) /* command and address both in serial format */
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Start of 2nd Stage Boot Code
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
.section .text
|
||||
|
||||
regular_func _stage2_boot
|
||||
push {lr}
|
||||
|
||||
ldr r3, =XIP_SSI_BASE // Use as base address where possible
|
||||
|
||||
// Disable SSI to allow further config
|
||||
movs r1, #0
|
||||
str r1, [r3, #SSI_SSIENR_OFFSET]
|
||||
|
||||
// Set baud rate
|
||||
movs r1, #PICO_FLASH_SPI_CLKDIV
|
||||
str r1, [r3, #SSI_BAUDR_OFFSET]
|
||||
|
||||
ldr r1, =(CTRLR0_XIP)
|
||||
str r1, [r3, #SSI_CTRLR0_OFFSET]
|
||||
|
||||
ldr r1, =(SPI_CTRLR0_XIP)
|
||||
ldr r0, =(XIP_SSI_BASE + SSI_SPI_CTRLR0_OFFSET)
|
||||
str r1, [r0]
|
||||
|
||||
// NDF=0 (single 32b read)
|
||||
movs r1, #0x0
|
||||
str r1, [r3, #SSI_CTRLR1_OFFSET]
|
||||
|
||||
// Re-enable SSI
|
||||
movs r1, #1
|
||||
str r1, [r3, #SSI_SSIENR_OFFSET]
|
||||
|
||||
// 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.
|
||||
|
||||
// Pull in standard exit routine
|
||||
#include "shared/exit_from_boot2.S"
|
||||
|
||||
.global literals
|
||||
literals:
|
||||
.ltorg
|
||||
|
||||
.end
|
@ -0,0 +1,256 @@
|
||||
// ----------------------------------------------------------------------------
|
||||
// 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
|
||||
// SR1 instead of SR2.
|
||||
//
|
||||
// Description: Configures IS25LP080D to run in Quad I/O continuous read XIP mode
|
||||
//
|
||||
// Details: * Check status register to determine if QSPI mode is enabled,
|
||||
// and perform an SR programming cycle if necessary.
|
||||
// * Use SSI to perform a dummy 0xEB read command, with the mode
|
||||
// continuation bits set, so that the flash will not require
|
||||
// 0xEB instruction prefix on subsequent reads.
|
||||
// * Configure SSI to write address, mode bits, but no instruction.
|
||||
// SSI + flash are now jointly in a state where continuous reads
|
||||
// can take place.
|
||||
// * Set VTOR = 0x10000100 (user vector table immediately after
|
||||
// this boot2 image).
|
||||
// * Read stack pointer (MSP) and reset vector from the flash
|
||||
// vector table; set SP and jump, as though the processor had
|
||||
// booted directly from flash.
|
||||
//
|
||||
// Building: * This code must be linked to run at 0x20027f00
|
||||
// * The code will be padded to a size of 256 bytes, including a
|
||||
// 4-byte checksum. Therefore code size cannot exceed 252 bytes.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include "shared/asm_helper.S"
|
||||
#include "shared/regs.h"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Config section
|
||||
// ----------------------------------------------------------------------------
|
||||
// It should be possible to support most flash devices by modifying this section
|
||||
|
||||
// The serial flash interface will run at clk_sys/PICO_FLASH_SPI_CLKDIV.
|
||||
// This must be a positive, even integer.
|
||||
// The bootrom is very conservative with SPI frequency, but here we should be
|
||||
// as aggressive as possible.
|
||||
#ifndef PICO_FLASH_SPI_CLKDIV
|
||||
#define PICO_FLASH_SPI_CLKDIV 4
|
||||
#endif
|
||||
|
||||
|
||||
// Define interface width: single/dual/quad IO
|
||||
#define FRAME_FORMAT SSI_CTRLR0_SPI_FRF_VALUE_QUAD
|
||||
|
||||
// For W25Q080 this is the "Read data fast quad IO" instruction:
|
||||
#define CMD_READ 0xeb
|
||||
|
||||
// "Mode bits" are 8 special bits sent immediately after
|
||||
// the address bits in a "Read Data Fast Quad I/O" command sequence.
|
||||
// On W25Q080, the four LSBs are don't care, and if MSBs == 0xa, the
|
||||
// next read does not require the 0xeb instruction prefix.
|
||||
#define MODE_CONTINUOUS_READ 0xa0
|
||||
|
||||
// The number of address + mode bits, divided by 4 (always 4, not function of
|
||||
// interface width).
|
||||
#define ADDR_L 8
|
||||
|
||||
// How many clocks of Hi-Z following the mode bits. For W25Q080, 4 dummy cycles
|
||||
// are required.
|
||||
#define WAIT_CYCLES 4
|
||||
|
||||
// If defined, we will read status reg, compare to SREG_DATA, and overwrite
|
||||
// with our value if the SR doesn't match.
|
||||
// This isn't great because it will remove block protections.
|
||||
// A better solution is to use a volatile SR write if your device supports it.
|
||||
#define PROGRAM_STATUS_REG
|
||||
|
||||
#define CMD_WRITE_ENABLE 0x06
|
||||
#define CMD_READ_STATUS 0x05
|
||||
#define CMD_WRITE_STATUS 0x01
|
||||
#define SREG_DATA 0x40 // Enable quad-SPI mode
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Start of 2nd Stage Boot Code
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
pico_default_asm_setup
|
||||
|
||||
.section text
|
||||
regular_func _stage2_boot
|
||||
push {lr}
|
||||
|
||||
ldr r3, =XIP_SSI_BASE // Use as base address where possible
|
||||
|
||||
// Disable SSI to allow further config
|
||||
movs r1, #0
|
||||
str r1, [r3, #SSI_SSIENR_OFFSET]
|
||||
|
||||
// Set baud rate
|
||||
movs r1, #PICO_FLASH_SPI_CLKDIV
|
||||
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)
|
||||
#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)
|
||||
|
||||
ldr r1, =(CTRL0_SPI_TXRX)
|
||||
str r1, [r3, #SSI_CTRLR0_OFFSET]
|
||||
|
||||
// Enable SSI and select slave 0
|
||||
movs r1, #1
|
||||
str r1, [r3, #SSI_SSIENR_OFFSET]
|
||||
|
||||
// Check whether SR needs updating
|
||||
ldr r0, =CMD_READ_STATUS
|
||||
bl read_flash_sreg
|
||||
ldr r2, =SREG_DATA
|
||||
cmp r0, r2
|
||||
beq skip_sreg_programming
|
||||
|
||||
// Send write enable command
|
||||
movs r1, #CMD_WRITE_ENABLE
|
||||
str r1, [r3, #SSI_DR0_OFFSET]
|
||||
|
||||
// Poll for completion and discard RX
|
||||
bl wait_ssi_ready
|
||||
ldr r1, [r3, #SSI_DR0_OFFSET]
|
||||
|
||||
// Send status write command followed by data bytes
|
||||
movs r1, #CMD_WRITE_STATUS
|
||||
str r1, [r3, #SSI_DR0_OFFSET]
|
||||
movs r0, #0
|
||||
str r2, [r3, #SSI_DR0_OFFSET]
|
||||
|
||||
bl wait_ssi_ready
|
||||
ldr r1, [r3, #SSI_DR0_OFFSET]
|
||||
ldr r1, [r3, #SSI_DR0_OFFSET]
|
||||
|
||||
// Poll status register for write completion
|
||||
1:
|
||||
ldr r0, =CMD_READ_STATUS
|
||||
bl read_flash_sreg
|
||||
movs r1, #1
|
||||
tst r0, r1
|
||||
bne 1b
|
||||
|
||||
skip_sreg_programming:
|
||||
|
||||
// Send a 0xA3 high-performance-mode instruction
|
||||
// ldr r1, =0xa3
|
||||
// str r1, [r3, #SSI_DR0_OFFSET]
|
||||
// bl wait_ssi_ready
|
||||
|
||||
// Disable SSI again so that it can be reconfigured
|
||||
movs r1, #0
|
||||
str r1, [r3, #SSI_SSIENR_OFFSET]
|
||||
#endif
|
||||
|
||||
|
||||
// First we need to send the initial command to get us in to Fast Read Quad I/O
|
||||
// mode. As this transaction requires a command, we can't send it in XIP mode.
|
||||
// To enter Continuous Read mode as well we need to append 4'b0010 to the address
|
||||
// bits and then add a further 4 don't care bits. We will construct this by
|
||||
// specifying a 28-bit address, with the least significant bits being 4'b0010.
|
||||
// This is just a dummy transaction so we'll perform a read from address zero
|
||||
// and then discard what comes back. All we really care about is that at the
|
||||
// end of the transaction, the flash device is in Continuous Read mode
|
||||
// and from then on will only expect to receive addresses.
|
||||
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)
|
||||
|
||||
ldr r1, =(CTRLR0_ENTER_XIP)
|
||||
str r1, [r3, #SSI_CTRLR0_OFFSET]
|
||||
|
||||
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, [r0]
|
||||
|
||||
movs r1, #1 // Re-enable SSI
|
||||
str r1, [r3, #SSI_SSIENR_OFFSET]
|
||||
|
||||
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
|
||||
|
||||
// Poll for completion
|
||||
bl wait_ssi_ready
|
||||
|
||||
// At this point CN# will be deasserted and the SPI clock will not be running.
|
||||
// The Winbond WX25X10CL device will be in continuous read, dual I/O mode and
|
||||
// only expecting address bits after the next CN# assertion. So long as we
|
||||
// send 4'b0010 (and 4 more dummy HiZ bits) after every subsequent 24b address
|
||||
// then the Winbond device will remain in continuous read mode. This is the
|
||||
// ideal mode for Execute-In-Place.
|
||||
// (If we want to exit continuous read mode then we will need to switch back
|
||||
// to APM mode and generate a 28-bit address phase with the extra nibble set
|
||||
// to 4'b0000).
|
||||
|
||||
movs r1, #0
|
||||
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:
|
||||
// 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)
|
||||
|
||||
ldr r1, =(SPI_CTRLR0_XIP)
|
||||
ldr r0, =(XIP_SSI_BASE + SSI_SPI_CTRLR0_OFFSET)
|
||||
str r1, [r0]
|
||||
|
||||
movs r1, #1
|
||||
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.
|
||||
|
||||
// Pull in standard exit routine
|
||||
#include "shared/exit_from_boot2.S"
|
||||
|
||||
// Common functions
|
||||
#include "shared/wait_ssi_ready.S"
|
||||
#ifdef PROGRAM_STATUS_REG
|
||||
#include "shared/read_flash_sreg.S"
|
||||
#endif
|
||||
|
||||
.global literals
|
||||
literals:
|
||||
.ltorg
|
||||
|
||||
.end
|
@ -0,0 +1,26 @@
|
||||
|
||||
// This is the legacy blob we used to ship in
|
||||
// src/boards/raspberry_pi_pico.zig
|
||||
// Now it's generic over all boards we have.
|
||||
|
||||
.text
|
||||
.global _stage2_boot
|
||||
_stage2_boot:
|
||||
.byte 0x00, 0xb5, 0x32, 0x4b, 0x21, 0x20, 0x58, 0x60, 0x98, 0x68, 0x02, 0x21, 0x88, 0x43, 0x98, 0x60
|
||||
.byte 0xd8, 0x60, 0x18, 0x61, 0x58, 0x61, 0x2e, 0x4b, 0x00, 0x21, 0x99, 0x60, 0x02, 0x21, 0x59, 0x61
|
||||
.byte 0x01, 0x21, 0xf0, 0x22, 0x99, 0x50, 0x2b, 0x49, 0x19, 0x60, 0x01, 0x21, 0x99, 0x60, 0x35, 0x20
|
||||
.byte 0x00, 0xf0, 0x44, 0xf8, 0x02, 0x22, 0x90, 0x42, 0x14, 0xd0, 0x06, 0x21, 0x19, 0x66, 0x00, 0xf0
|
||||
.byte 0x34, 0xf8, 0x19, 0x6e, 0x01, 0x21, 0x19, 0x66, 0x00, 0x20, 0x18, 0x66, 0x1a, 0x66, 0x00, 0xf0
|
||||
.byte 0x2c, 0xf8, 0x19, 0x6e, 0x19, 0x6e, 0x19, 0x6e, 0x05, 0x20, 0x00, 0xf0, 0x2f, 0xf8, 0x01, 0x21
|
||||
.byte 0x08, 0x42, 0xf9, 0xd1, 0x00, 0x21, 0x99, 0x60, 0x1b, 0x49, 0x19, 0x60, 0x00, 0x21, 0x59, 0x60
|
||||
.byte 0x1a, 0x49, 0x1b, 0x48, 0x01, 0x60, 0x01, 0x21, 0x99, 0x60, 0xeb, 0x21, 0x19, 0x66, 0xa0, 0x21
|
||||
.byte 0x19, 0x66, 0x00, 0xf0, 0x12, 0xf8, 0x00, 0x21, 0x99, 0x60, 0x16, 0x49, 0x14, 0x48, 0x01, 0x60
|
||||
.byte 0x01, 0x21, 0x99, 0x60, 0x01, 0xbc, 0x00, 0x28, 0x00, 0xd0, 0x00, 0x47, 0x12, 0x48, 0x13, 0x49
|
||||
.byte 0x08, 0x60, 0x03, 0xc8, 0x80, 0xf3, 0x08, 0x88, 0x08, 0x47, 0x03, 0xb5, 0x99, 0x6a, 0x04, 0x20
|
||||
.byte 0x01, 0x42, 0xfb, 0xd0, 0x01, 0x20, 0x01, 0x42, 0xf8, 0xd1, 0x03, 0xbd, 0x02, 0xb5, 0x18, 0x66
|
||||
.byte 0x18, 0x66, 0xff, 0xf7, 0xf2, 0xff, 0x18, 0x6e, 0x18, 0x6e, 0x02, 0xbd, 0x00, 0x00, 0x02, 0x40
|
||||
.byte 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0x00, 0x00, 0x03, 0x5f, 0x00, 0x21, 0x22, 0x00, 0x00
|
||||
.byte 0xf4, 0x00, 0x00, 0x18, 0x22, 0x20, 0x00, 0xa0, 0x00, 0x01, 0x00, 0x10, 0x08, 0xed, 0x00, 0xe0
|
||||
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0xb2, 0x4e, 0x7a
|
||||
|
||||
// last four bytes are checksum, also computed by microzig when embedding the bootrom.
|
@ -0,0 +1,73 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
#ifndef _ADDRESSMAP_H_
|
||||
#define _ADDRESSMAP_H_
|
||||
|
||||
|
||||
// Register address offsets for atomic RMW aliases
|
||||
#define REG_ALIAS_RW_BITS (0x0u << 12u)
|
||||
#define REG_ALIAS_XOR_BITS (0x1u << 12u)
|
||||
#define REG_ALIAS_SET_BITS (0x2u << 12u)
|
||||
#define REG_ALIAS_CLR_BITS (0x3u << 12u)
|
||||
|
||||
#define ROM_BASE _u(0x00000000)
|
||||
#define XIP_BASE _u(0x10000000)
|
||||
#define XIP_MAIN_BASE _u(0x10000000)
|
||||
#define XIP_NOALLOC_BASE _u(0x11000000)
|
||||
#define XIP_NOCACHE_BASE _u(0x12000000)
|
||||
#define XIP_NOCACHE_NOALLOC_BASE _u(0x13000000)
|
||||
#define XIP_CTRL_BASE _u(0x14000000)
|
||||
#define XIP_SRAM_BASE _u(0x15000000)
|
||||
#define XIP_SRAM_END _u(0x15004000)
|
||||
#define XIP_SSI_BASE _u(0x18000000)
|
||||
#define SRAM_BASE _u(0x20000000)
|
||||
#define SRAM_STRIPED_BASE _u(0x20000000)
|
||||
#define SRAM_STRIPED_END _u(0x20040000)
|
||||
#define SRAM4_BASE _u(0x20040000)
|
||||
#define SRAM5_BASE _u(0x20041000)
|
||||
#define SRAM_END _u(0x20042000)
|
||||
#define SRAM0_BASE _u(0x21000000)
|
||||
#define SRAM1_BASE _u(0x21010000)
|
||||
#define SRAM2_BASE _u(0x21020000)
|
||||
#define SRAM3_BASE _u(0x21030000)
|
||||
#define SYSINFO_BASE _u(0x40000000)
|
||||
#define SYSCFG_BASE _u(0x40004000)
|
||||
#define CLOCKS_BASE _u(0x40008000)
|
||||
#define RESETS_BASE _u(0x4000c000)
|
||||
#define PSM_BASE _u(0x40010000)
|
||||
#define IO_BANK0_BASE _u(0x40014000)
|
||||
#define IO_QSPI_BASE _u(0x40018000)
|
||||
#define PADS_BANK0_BASE _u(0x4001c000)
|
||||
#define PADS_QSPI_BASE _u(0x40020000)
|
||||
#define XOSC_BASE _u(0x40024000)
|
||||
#define PLL_SYS_BASE _u(0x40028000)
|
||||
#define PLL_USB_BASE _u(0x4002c000)
|
||||
#define BUSCTRL_BASE _u(0x40030000)
|
||||
#define UART0_BASE _u(0x40034000)
|
||||
#define UART1_BASE _u(0x40038000)
|
||||
#define SPI0_BASE _u(0x4003c000)
|
||||
#define SPI1_BASE _u(0x40040000)
|
||||
#define I2C0_BASE _u(0x40044000)
|
||||
#define I2C1_BASE _u(0x40048000)
|
||||
#define ADC_BASE _u(0x4004c000)
|
||||
#define PWM_BASE _u(0x40050000)
|
||||
#define TIMER_BASE _u(0x40054000)
|
||||
#define WATCHDOG_BASE _u(0x40058000)
|
||||
#define RTC_BASE _u(0x4005c000)
|
||||
#define ROSC_BASE _u(0x40060000)
|
||||
#define VREG_AND_CHIP_RESET_BASE _u(0x40064000)
|
||||
#define TBMAN_BASE _u(0x4006c000)
|
||||
#define DMA_BASE _u(0x50000000)
|
||||
#define USBCTRL_DPRAM_BASE _u(0x50100000)
|
||||
#define USBCTRL_BASE _u(0x50100000)
|
||||
#define USBCTRL_REGS_BASE _u(0x50110000)
|
||||
#define PIO0_BASE _u(0x50200000)
|
||||
#define PIO1_BASE _u(0x50300000)
|
||||
#define XIP_AUX_BASE _u(0x50400000)
|
||||
#define SIO_BASE _u(0xd0000000)
|
||||
#define PPB_BASE _u(0xe0000000)
|
||||
|
||||
#endif // _ADDRESSMAP_H_
|
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include "regs.h"
|
||||
|
||||
# note we don't do this by default in this file for backwards comaptibility with user code
|
||||
# that may include this file, but not use unified syntax. Note that this macro does equivalent
|
||||
# setup to the pico_default_asm macro for inline assembly in C code.
|
||||
.macro pico_default_asm_setup
|
||||
.syntax unified
|
||||
.cpu cortex-m0plus
|
||||
.thumb
|
||||
.endm
|
||||
|
||||
// do not put align in here as it is used mid function sometimes
|
||||
.macro regular_func x
|
||||
.global \x
|
||||
.type \x,%function
|
||||
.thumb_func
|
||||
\x:
|
||||
.endm
|
||||
|
||||
.macro regular_func_with_section x
|
||||
.section .text.\x
|
||||
regular_func \x
|
||||
.endm
|
||||
|
||||
// do not put align in here as it is used mid function sometimes
|
||||
.macro wrapper_func x
|
||||
regular_func WRAPPER_FUNC_NAME(\x)
|
||||
.endm
|
||||
|
||||
.macro __pre_init func, priority_string
|
||||
.section .preinit_array.\priority_string
|
||||
.align 2
|
||||
.word \func
|
||||
.endm
|
||||
|
@ -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 "regs.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
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,454 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
// =============================================================================
|
||||
// Register block : PADS_QSPI
|
||||
// Version : 1
|
||||
// Bus type : apb
|
||||
// Description : None
|
||||
// =============================================================================
|
||||
#ifndef HARDWARE_REGS_PADS_QSPI_DEFINED
|
||||
#define HARDWARE_REGS_PADS_QSPI_DEFINED
|
||||
// =============================================================================
|
||||
// Register : PADS_QSPI_VOLTAGE_SELECT
|
||||
// Description : Voltage select. Per bank control
|
||||
// 0x0 -> Set voltage to 3.3V (DVDD >= 2V5)
|
||||
// 0x1 -> Set voltage to 1.8V (DVDD <= 1V8)
|
||||
#define PADS_QSPI_VOLTAGE_SELECT_OFFSET _u(0x00000000)
|
||||
#define PADS_QSPI_VOLTAGE_SELECT_BITS _u(0x00000001)
|
||||
#define PADS_QSPI_VOLTAGE_SELECT_RESET _u(0x00000000)
|
||||
#define PADS_QSPI_VOLTAGE_SELECT_MSB _u(0)
|
||||
#define PADS_QSPI_VOLTAGE_SELECT_LSB _u(0)
|
||||
#define PADS_QSPI_VOLTAGE_SELECT_ACCESS "RW"
|
||||
#define PADS_QSPI_VOLTAGE_SELECT_VALUE_3V3 _u(0x0)
|
||||
#define PADS_QSPI_VOLTAGE_SELECT_VALUE_1V8 _u(0x1)
|
||||
// =============================================================================
|
||||
// Register : PADS_QSPI_GPIO_QSPI_SCLK
|
||||
// Description : Pad control register
|
||||
#define PADS_QSPI_GPIO_QSPI_SCLK_OFFSET _u(0x00000004)
|
||||
#define PADS_QSPI_GPIO_QSPI_SCLK_BITS _u(0x000000ff)
|
||||
#define PADS_QSPI_GPIO_QSPI_SCLK_RESET _u(0x00000056)
|
||||
// -----------------------------------------------------------------------------
|
||||
// Field : PADS_QSPI_GPIO_QSPI_SCLK_OD
|
||||
// Description : Output disable. Has priority over output enable from
|
||||
// peripherals
|
||||
#define PADS_QSPI_GPIO_QSPI_SCLK_OD_RESET _u(0x0)
|
||||
#define PADS_QSPI_GPIO_QSPI_SCLK_OD_BITS _u(0x00000080)
|
||||
#define PADS_QSPI_GPIO_QSPI_SCLK_OD_MSB _u(7)
|
||||
#define PADS_QSPI_GPIO_QSPI_SCLK_OD_LSB _u(7)
|
||||
#define PADS_QSPI_GPIO_QSPI_SCLK_OD_ACCESS "RW"
|
||||
// -----------------------------------------------------------------------------
|
||||
// Field : PADS_QSPI_GPIO_QSPI_SCLK_IE
|
||||
// Description : Input enable
|
||||
#define PADS_QSPI_GPIO_QSPI_SCLK_IE_RESET _u(0x1)
|
||||
#define PADS_QSPI_GPIO_QSPI_SCLK_IE_BITS _u(0x00000040)
|
||||
#define PADS_QSPI_GPIO_QSPI_SCLK_IE_MSB _u(6)
|
||||
#define PADS_QSPI_GPIO_QSPI_SCLK_IE_LSB _u(6)
|
||||
#define PADS_QSPI_GPIO_QSPI_SCLK_IE_ACCESS "RW"
|
||||
// -----------------------------------------------------------------------------
|
||||
// Field : PADS_QSPI_GPIO_QSPI_SCLK_DRIVE
|
||||
// Description : Drive strength.
|
||||
// 0x0 -> 2mA
|
||||
// 0x1 -> 4mA
|
||||
// 0x2 -> 8mA
|
||||
// 0x3 -> 12mA
|
||||
#define PADS_QSPI_GPIO_QSPI_SCLK_DRIVE_RESET _u(0x1)
|
||||
#define PADS_QSPI_GPIO_QSPI_SCLK_DRIVE_BITS _u(0x00000030)
|
||||
#define PADS_QSPI_GPIO_QSPI_SCLK_DRIVE_MSB _u(5)
|
||||
#define PADS_QSPI_GPIO_QSPI_SCLK_DRIVE_LSB _u(4)
|
||||
#define PADS_QSPI_GPIO_QSPI_SCLK_DRIVE_ACCESS "RW"
|
||||
#define PADS_QSPI_GPIO_QSPI_SCLK_DRIVE_VALUE_2MA _u(0x0)
|
||||
#define PADS_QSPI_GPIO_QSPI_SCLK_DRIVE_VALUE_4MA _u(0x1)
|
||||
#define PADS_QSPI_GPIO_QSPI_SCLK_DRIVE_VALUE_8MA _u(0x2)
|
||||
#define PADS_QSPI_GPIO_QSPI_SCLK_DRIVE_VALUE_12MA _u(0x3)
|
||||
// -----------------------------------------------------------------------------
|
||||
// Field : PADS_QSPI_GPIO_QSPI_SCLK_PUE
|
||||
// Description : Pull up enable
|
||||
#define PADS_QSPI_GPIO_QSPI_SCLK_PUE_RESET _u(0x0)
|
||||
#define PADS_QSPI_GPIO_QSPI_SCLK_PUE_BITS _u(0x00000008)
|
||||
#define PADS_QSPI_GPIO_QSPI_SCLK_PUE_MSB _u(3)
|
||||
#define PADS_QSPI_GPIO_QSPI_SCLK_PUE_LSB _u(3)
|
||||
#define PADS_QSPI_GPIO_QSPI_SCLK_PUE_ACCESS "RW"
|
||||
// -----------------------------------------------------------------------------
|
||||
// Field : PADS_QSPI_GPIO_QSPI_SCLK_PDE
|
||||
// Description : Pull down enable
|
||||
#define PADS_QSPI_GPIO_QSPI_SCLK_PDE_RESET _u(0x1)
|
||||
#define PADS_QSPI_GPIO_QSPI_SCLK_PDE_BITS _u(0x00000004)
|
||||
#define PADS_QSPI_GPIO_QSPI_SCLK_PDE_MSB _u(2)
|
||||
#define PADS_QSPI_GPIO_QSPI_SCLK_PDE_LSB _u(2)
|
||||
#define PADS_QSPI_GPIO_QSPI_SCLK_PDE_ACCESS "RW"
|
||||
// -----------------------------------------------------------------------------
|
||||
// Field : PADS_QSPI_GPIO_QSPI_SCLK_SCHMITT
|
||||
// Description : Enable schmitt trigger
|
||||
#define PADS_QSPI_GPIO_QSPI_SCLK_SCHMITT_RESET _u(0x1)
|
||||
#define PADS_QSPI_GPIO_QSPI_SCLK_SCHMITT_BITS _u(0x00000002)
|
||||
#define PADS_QSPI_GPIO_QSPI_SCLK_SCHMITT_MSB _u(1)
|
||||
#define PADS_QSPI_GPIO_QSPI_SCLK_SCHMITT_LSB _u(1)
|
||||
#define PADS_QSPI_GPIO_QSPI_SCLK_SCHMITT_ACCESS "RW"
|
||||
// -----------------------------------------------------------------------------
|
||||
// Field : PADS_QSPI_GPIO_QSPI_SCLK_SLEWFAST
|
||||
// Description : Slew rate control. 1 = Fast, 0 = Slow
|
||||
#define PADS_QSPI_GPIO_QSPI_SCLK_SLEWFAST_RESET _u(0x0)
|
||||
#define PADS_QSPI_GPIO_QSPI_SCLK_SLEWFAST_BITS _u(0x00000001)
|
||||
#define PADS_QSPI_GPIO_QSPI_SCLK_SLEWFAST_MSB _u(0)
|
||||
#define PADS_QSPI_GPIO_QSPI_SCLK_SLEWFAST_LSB _u(0)
|
||||
#define PADS_QSPI_GPIO_QSPI_SCLK_SLEWFAST_ACCESS "RW"
|
||||
// =============================================================================
|
||||
// Register : PADS_QSPI_GPIO_QSPI_SD0
|
||||
// Description : Pad control register
|
||||
#define PADS_QSPI_GPIO_QSPI_SD0_OFFSET _u(0x00000008)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD0_BITS _u(0x000000ff)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD0_RESET _u(0x00000052)
|
||||
// -----------------------------------------------------------------------------
|
||||
// Field : PADS_QSPI_GPIO_QSPI_SD0_OD
|
||||
// Description : Output disable. Has priority over output enable from
|
||||
// peripherals
|
||||
#define PADS_QSPI_GPIO_QSPI_SD0_OD_RESET _u(0x0)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD0_OD_BITS _u(0x00000080)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD0_OD_MSB _u(7)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD0_OD_LSB _u(7)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD0_OD_ACCESS "RW"
|
||||
// -----------------------------------------------------------------------------
|
||||
// Field : PADS_QSPI_GPIO_QSPI_SD0_IE
|
||||
// Description : Input enable
|
||||
#define PADS_QSPI_GPIO_QSPI_SD0_IE_RESET _u(0x1)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD0_IE_BITS _u(0x00000040)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD0_IE_MSB _u(6)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD0_IE_LSB _u(6)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD0_IE_ACCESS "RW"
|
||||
// -----------------------------------------------------------------------------
|
||||
// Field : PADS_QSPI_GPIO_QSPI_SD0_DRIVE
|
||||
// Description : Drive strength.
|
||||
// 0x0 -> 2mA
|
||||
// 0x1 -> 4mA
|
||||
// 0x2 -> 8mA
|
||||
// 0x3 -> 12mA
|
||||
#define PADS_QSPI_GPIO_QSPI_SD0_DRIVE_RESET _u(0x1)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD0_DRIVE_BITS _u(0x00000030)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD0_DRIVE_MSB _u(5)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD0_DRIVE_LSB _u(4)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD0_DRIVE_ACCESS "RW"
|
||||
#define PADS_QSPI_GPIO_QSPI_SD0_DRIVE_VALUE_2MA _u(0x0)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD0_DRIVE_VALUE_4MA _u(0x1)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD0_DRIVE_VALUE_8MA _u(0x2)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD0_DRIVE_VALUE_12MA _u(0x3)
|
||||
// -----------------------------------------------------------------------------
|
||||
// Field : PADS_QSPI_GPIO_QSPI_SD0_PUE
|
||||
// Description : Pull up enable
|
||||
#define PADS_QSPI_GPIO_QSPI_SD0_PUE_RESET _u(0x0)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD0_PUE_BITS _u(0x00000008)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD0_PUE_MSB _u(3)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD0_PUE_LSB _u(3)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD0_PUE_ACCESS "RW"
|
||||
// -----------------------------------------------------------------------------
|
||||
// Field : PADS_QSPI_GPIO_QSPI_SD0_PDE
|
||||
// Description : Pull down enable
|
||||
#define PADS_QSPI_GPIO_QSPI_SD0_PDE_RESET _u(0x0)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD0_PDE_BITS _u(0x00000004)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD0_PDE_MSB _u(2)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD0_PDE_LSB _u(2)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD0_PDE_ACCESS "RW"
|
||||
// -----------------------------------------------------------------------------
|
||||
// Field : PADS_QSPI_GPIO_QSPI_SD0_SCHMITT
|
||||
// Description : Enable schmitt trigger
|
||||
#define PADS_QSPI_GPIO_QSPI_SD0_SCHMITT_RESET _u(0x1)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD0_SCHMITT_BITS _u(0x00000002)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD0_SCHMITT_MSB _u(1)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD0_SCHMITT_LSB _u(1)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD0_SCHMITT_ACCESS "RW"
|
||||
// -----------------------------------------------------------------------------
|
||||
// Field : PADS_QSPI_GPIO_QSPI_SD0_SLEWFAST
|
||||
// Description : Slew rate control. 1 = Fast, 0 = Slow
|
||||
#define PADS_QSPI_GPIO_QSPI_SD0_SLEWFAST_RESET _u(0x0)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD0_SLEWFAST_BITS _u(0x00000001)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD0_SLEWFAST_MSB _u(0)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD0_SLEWFAST_LSB _u(0)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD0_SLEWFAST_ACCESS "RW"
|
||||
// =============================================================================
|
||||
// Register : PADS_QSPI_GPIO_QSPI_SD1
|
||||
// Description : Pad control register
|
||||
#define PADS_QSPI_GPIO_QSPI_SD1_OFFSET _u(0x0000000c)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD1_BITS _u(0x000000ff)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD1_RESET _u(0x00000052)
|
||||
// -----------------------------------------------------------------------------
|
||||
// Field : PADS_QSPI_GPIO_QSPI_SD1_OD
|
||||
// Description : Output disable. Has priority over output enable from
|
||||
// peripherals
|
||||
#define PADS_QSPI_GPIO_QSPI_SD1_OD_RESET _u(0x0)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD1_OD_BITS _u(0x00000080)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD1_OD_MSB _u(7)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD1_OD_LSB _u(7)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD1_OD_ACCESS "RW"
|
||||
// -----------------------------------------------------------------------------
|
||||
// Field : PADS_QSPI_GPIO_QSPI_SD1_IE
|
||||
// Description : Input enable
|
||||
#define PADS_QSPI_GPIO_QSPI_SD1_IE_RESET _u(0x1)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD1_IE_BITS _u(0x00000040)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD1_IE_MSB _u(6)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD1_IE_LSB _u(6)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD1_IE_ACCESS "RW"
|
||||
// -----------------------------------------------------------------------------
|
||||
// Field : PADS_QSPI_GPIO_QSPI_SD1_DRIVE
|
||||
// Description : Drive strength.
|
||||
// 0x0 -> 2mA
|
||||
// 0x1 -> 4mA
|
||||
// 0x2 -> 8mA
|
||||
// 0x3 -> 12mA
|
||||
#define PADS_QSPI_GPIO_QSPI_SD1_DRIVE_RESET _u(0x1)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD1_DRIVE_BITS _u(0x00000030)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD1_DRIVE_MSB _u(5)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD1_DRIVE_LSB _u(4)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD1_DRIVE_ACCESS "RW"
|
||||
#define PADS_QSPI_GPIO_QSPI_SD1_DRIVE_VALUE_2MA _u(0x0)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD1_DRIVE_VALUE_4MA _u(0x1)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD1_DRIVE_VALUE_8MA _u(0x2)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD1_DRIVE_VALUE_12MA _u(0x3)
|
||||
// -----------------------------------------------------------------------------
|
||||
// Field : PADS_QSPI_GPIO_QSPI_SD1_PUE
|
||||
// Description : Pull up enable
|
||||
#define PADS_QSPI_GPIO_QSPI_SD1_PUE_RESET _u(0x0)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD1_PUE_BITS _u(0x00000008)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD1_PUE_MSB _u(3)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD1_PUE_LSB _u(3)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD1_PUE_ACCESS "RW"
|
||||
// -----------------------------------------------------------------------------
|
||||
// Field : PADS_QSPI_GPIO_QSPI_SD1_PDE
|
||||
// Description : Pull down enable
|
||||
#define PADS_QSPI_GPIO_QSPI_SD1_PDE_RESET _u(0x0)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD1_PDE_BITS _u(0x00000004)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD1_PDE_MSB _u(2)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD1_PDE_LSB _u(2)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD1_PDE_ACCESS "RW"
|
||||
// -----------------------------------------------------------------------------
|
||||
// Field : PADS_QSPI_GPIO_QSPI_SD1_SCHMITT
|
||||
// Description : Enable schmitt trigger
|
||||
#define PADS_QSPI_GPIO_QSPI_SD1_SCHMITT_RESET _u(0x1)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD1_SCHMITT_BITS _u(0x00000002)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD1_SCHMITT_MSB _u(1)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD1_SCHMITT_LSB _u(1)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD1_SCHMITT_ACCESS "RW"
|
||||
// -----------------------------------------------------------------------------
|
||||
// Field : PADS_QSPI_GPIO_QSPI_SD1_SLEWFAST
|
||||
// Description : Slew rate control. 1 = Fast, 0 = Slow
|
||||
#define PADS_QSPI_GPIO_QSPI_SD1_SLEWFAST_RESET _u(0x0)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD1_SLEWFAST_BITS _u(0x00000001)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD1_SLEWFAST_MSB _u(0)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD1_SLEWFAST_LSB _u(0)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD1_SLEWFAST_ACCESS "RW"
|
||||
// =============================================================================
|
||||
// Register : PADS_QSPI_GPIO_QSPI_SD2
|
||||
// Description : Pad control register
|
||||
#define PADS_QSPI_GPIO_QSPI_SD2_OFFSET _u(0x00000010)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD2_BITS _u(0x000000ff)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD2_RESET _u(0x00000052)
|
||||
// -----------------------------------------------------------------------------
|
||||
// Field : PADS_QSPI_GPIO_QSPI_SD2_OD
|
||||
// Description : Output disable. Has priority over output enable from
|
||||
// peripherals
|
||||
#define PADS_QSPI_GPIO_QSPI_SD2_OD_RESET _u(0x0)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD2_OD_BITS _u(0x00000080)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD2_OD_MSB _u(7)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD2_OD_LSB _u(7)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD2_OD_ACCESS "RW"
|
||||
// -----------------------------------------------------------------------------
|
||||
// Field : PADS_QSPI_GPIO_QSPI_SD2_IE
|
||||
// Description : Input enable
|
||||
#define PADS_QSPI_GPIO_QSPI_SD2_IE_RESET _u(0x1)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD2_IE_BITS _u(0x00000040)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD2_IE_MSB _u(6)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD2_IE_LSB _u(6)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD2_IE_ACCESS "RW"
|
||||
// -----------------------------------------------------------------------------
|
||||
// Field : PADS_QSPI_GPIO_QSPI_SD2_DRIVE
|
||||
// Description : Drive strength.
|
||||
// 0x0 -> 2mA
|
||||
// 0x1 -> 4mA
|
||||
// 0x2 -> 8mA
|
||||
// 0x3 -> 12mA
|
||||
#define PADS_QSPI_GPIO_QSPI_SD2_DRIVE_RESET _u(0x1)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD2_DRIVE_BITS _u(0x00000030)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD2_DRIVE_MSB _u(5)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD2_DRIVE_LSB _u(4)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD2_DRIVE_ACCESS "RW"
|
||||
#define PADS_QSPI_GPIO_QSPI_SD2_DRIVE_VALUE_2MA _u(0x0)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD2_DRIVE_VALUE_4MA _u(0x1)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD2_DRIVE_VALUE_8MA _u(0x2)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD2_DRIVE_VALUE_12MA _u(0x3)
|
||||
// -----------------------------------------------------------------------------
|
||||
// Field : PADS_QSPI_GPIO_QSPI_SD2_PUE
|
||||
// Description : Pull up enable
|
||||
#define PADS_QSPI_GPIO_QSPI_SD2_PUE_RESET _u(0x0)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD2_PUE_BITS _u(0x00000008)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD2_PUE_MSB _u(3)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD2_PUE_LSB _u(3)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD2_PUE_ACCESS "RW"
|
||||
// -----------------------------------------------------------------------------
|
||||
// Field : PADS_QSPI_GPIO_QSPI_SD2_PDE
|
||||
// Description : Pull down enable
|
||||
#define PADS_QSPI_GPIO_QSPI_SD2_PDE_RESET _u(0x0)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD2_PDE_BITS _u(0x00000004)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD2_PDE_MSB _u(2)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD2_PDE_LSB _u(2)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD2_PDE_ACCESS "RW"
|
||||
// -----------------------------------------------------------------------------
|
||||
// Field : PADS_QSPI_GPIO_QSPI_SD2_SCHMITT
|
||||
// Description : Enable schmitt trigger
|
||||
#define PADS_QSPI_GPIO_QSPI_SD2_SCHMITT_RESET _u(0x1)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD2_SCHMITT_BITS _u(0x00000002)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD2_SCHMITT_MSB _u(1)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD2_SCHMITT_LSB _u(1)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD2_SCHMITT_ACCESS "RW"
|
||||
// -----------------------------------------------------------------------------
|
||||
// Field : PADS_QSPI_GPIO_QSPI_SD2_SLEWFAST
|
||||
// Description : Slew rate control. 1 = Fast, 0 = Slow
|
||||
#define PADS_QSPI_GPIO_QSPI_SD2_SLEWFAST_RESET _u(0x0)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD2_SLEWFAST_BITS _u(0x00000001)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD2_SLEWFAST_MSB _u(0)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD2_SLEWFAST_LSB _u(0)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD2_SLEWFAST_ACCESS "RW"
|
||||
// =============================================================================
|
||||
// Register : PADS_QSPI_GPIO_QSPI_SD3
|
||||
// Description : Pad control register
|
||||
#define PADS_QSPI_GPIO_QSPI_SD3_OFFSET _u(0x00000014)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD3_BITS _u(0x000000ff)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD3_RESET _u(0x00000052)
|
||||
// -----------------------------------------------------------------------------
|
||||
// Field : PADS_QSPI_GPIO_QSPI_SD3_OD
|
||||
// Description : Output disable. Has priority over output enable from
|
||||
// peripherals
|
||||
#define PADS_QSPI_GPIO_QSPI_SD3_OD_RESET _u(0x0)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD3_OD_BITS _u(0x00000080)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD3_OD_MSB _u(7)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD3_OD_LSB _u(7)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD3_OD_ACCESS "RW"
|
||||
// -----------------------------------------------------------------------------
|
||||
// Field : PADS_QSPI_GPIO_QSPI_SD3_IE
|
||||
// Description : Input enable
|
||||
#define PADS_QSPI_GPIO_QSPI_SD3_IE_RESET _u(0x1)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD3_IE_BITS _u(0x00000040)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD3_IE_MSB _u(6)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD3_IE_LSB _u(6)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD3_IE_ACCESS "RW"
|
||||
// -----------------------------------------------------------------------------
|
||||
// Field : PADS_QSPI_GPIO_QSPI_SD3_DRIVE
|
||||
// Description : Drive strength.
|
||||
// 0x0 -> 2mA
|
||||
// 0x1 -> 4mA
|
||||
// 0x2 -> 8mA
|
||||
// 0x3 -> 12mA
|
||||
#define PADS_QSPI_GPIO_QSPI_SD3_DRIVE_RESET _u(0x1)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD3_DRIVE_BITS _u(0x00000030)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD3_DRIVE_MSB _u(5)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD3_DRIVE_LSB _u(4)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD3_DRIVE_ACCESS "RW"
|
||||
#define PADS_QSPI_GPIO_QSPI_SD3_DRIVE_VALUE_2MA _u(0x0)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD3_DRIVE_VALUE_4MA _u(0x1)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD3_DRIVE_VALUE_8MA _u(0x2)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD3_DRIVE_VALUE_12MA _u(0x3)
|
||||
// -----------------------------------------------------------------------------
|
||||
// Field : PADS_QSPI_GPIO_QSPI_SD3_PUE
|
||||
// Description : Pull up enable
|
||||
#define PADS_QSPI_GPIO_QSPI_SD3_PUE_RESET _u(0x0)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD3_PUE_BITS _u(0x00000008)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD3_PUE_MSB _u(3)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD3_PUE_LSB _u(3)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD3_PUE_ACCESS "RW"
|
||||
// -----------------------------------------------------------------------------
|
||||
// Field : PADS_QSPI_GPIO_QSPI_SD3_PDE
|
||||
// Description : Pull down enable
|
||||
#define PADS_QSPI_GPIO_QSPI_SD3_PDE_RESET _u(0x0)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD3_PDE_BITS _u(0x00000004)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD3_PDE_MSB _u(2)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD3_PDE_LSB _u(2)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD3_PDE_ACCESS "RW"
|
||||
// -----------------------------------------------------------------------------
|
||||
// Field : PADS_QSPI_GPIO_QSPI_SD3_SCHMITT
|
||||
// Description : Enable schmitt trigger
|
||||
#define PADS_QSPI_GPIO_QSPI_SD3_SCHMITT_RESET _u(0x1)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD3_SCHMITT_BITS _u(0x00000002)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD3_SCHMITT_MSB _u(1)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD3_SCHMITT_LSB _u(1)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD3_SCHMITT_ACCESS "RW"
|
||||
// -----------------------------------------------------------------------------
|
||||
// Field : PADS_QSPI_GPIO_QSPI_SD3_SLEWFAST
|
||||
// Description : Slew rate control. 1 = Fast, 0 = Slow
|
||||
#define PADS_QSPI_GPIO_QSPI_SD3_SLEWFAST_RESET _u(0x0)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD3_SLEWFAST_BITS _u(0x00000001)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD3_SLEWFAST_MSB _u(0)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD3_SLEWFAST_LSB _u(0)
|
||||
#define PADS_QSPI_GPIO_QSPI_SD3_SLEWFAST_ACCESS "RW"
|
||||
// =============================================================================
|
||||
// Register : PADS_QSPI_GPIO_QSPI_SS
|
||||
// Description : Pad control register
|
||||
#define PADS_QSPI_GPIO_QSPI_SS_OFFSET _u(0x00000018)
|
||||
#define PADS_QSPI_GPIO_QSPI_SS_BITS _u(0x000000ff)
|
||||
#define PADS_QSPI_GPIO_QSPI_SS_RESET _u(0x0000005a)
|
||||
// -----------------------------------------------------------------------------
|
||||
// Field : PADS_QSPI_GPIO_QSPI_SS_OD
|
||||
// Description : Output disable. Has priority over output enable from
|
||||
// peripherals
|
||||
#define PADS_QSPI_GPIO_QSPI_SS_OD_RESET _u(0x0)
|
||||
#define PADS_QSPI_GPIO_QSPI_SS_OD_BITS _u(0x00000080)
|
||||
#define PADS_QSPI_GPIO_QSPI_SS_OD_MSB _u(7)
|
||||
#define PADS_QSPI_GPIO_QSPI_SS_OD_LSB _u(7)
|
||||
#define PADS_QSPI_GPIO_QSPI_SS_OD_ACCESS "RW"
|
||||
// -----------------------------------------------------------------------------
|
||||
// Field : PADS_QSPI_GPIO_QSPI_SS_IE
|
||||
// Description : Input enable
|
||||
#define PADS_QSPI_GPIO_QSPI_SS_IE_RESET _u(0x1)
|
||||
#define PADS_QSPI_GPIO_QSPI_SS_IE_BITS _u(0x00000040)
|
||||
#define PADS_QSPI_GPIO_QSPI_SS_IE_MSB _u(6)
|
||||
#define PADS_QSPI_GPIO_QSPI_SS_IE_LSB _u(6)
|
||||
#define PADS_QSPI_GPIO_QSPI_SS_IE_ACCESS "RW"
|
||||
// -----------------------------------------------------------------------------
|
||||
// Field : PADS_QSPI_GPIO_QSPI_SS_DRIVE
|
||||
// Description : Drive strength.
|
||||
// 0x0 -> 2mA
|
||||
// 0x1 -> 4mA
|
||||
// 0x2 -> 8mA
|
||||
// 0x3 -> 12mA
|
||||
#define PADS_QSPI_GPIO_QSPI_SS_DRIVE_RESET _u(0x1)
|
||||
#define PADS_QSPI_GPIO_QSPI_SS_DRIVE_BITS _u(0x00000030)
|
||||
#define PADS_QSPI_GPIO_QSPI_SS_DRIVE_MSB _u(5)
|
||||
#define PADS_QSPI_GPIO_QSPI_SS_DRIVE_LSB _u(4)
|
||||
#define PADS_QSPI_GPIO_QSPI_SS_DRIVE_ACCESS "RW"
|
||||
#define PADS_QSPI_GPIO_QSPI_SS_DRIVE_VALUE_2MA _u(0x0)
|
||||
#define PADS_QSPI_GPIO_QSPI_SS_DRIVE_VALUE_4MA _u(0x1)
|
||||
#define PADS_QSPI_GPIO_QSPI_SS_DRIVE_VALUE_8MA _u(0x2)
|
||||
#define PADS_QSPI_GPIO_QSPI_SS_DRIVE_VALUE_12MA _u(0x3)
|
||||
// -----------------------------------------------------------------------------
|
||||
// Field : PADS_QSPI_GPIO_QSPI_SS_PUE
|
||||
// Description : Pull up enable
|
||||
#define PADS_QSPI_GPIO_QSPI_SS_PUE_RESET _u(0x1)
|
||||
#define PADS_QSPI_GPIO_QSPI_SS_PUE_BITS _u(0x00000008)
|
||||
#define PADS_QSPI_GPIO_QSPI_SS_PUE_MSB _u(3)
|
||||
#define PADS_QSPI_GPIO_QSPI_SS_PUE_LSB _u(3)
|
||||
#define PADS_QSPI_GPIO_QSPI_SS_PUE_ACCESS "RW"
|
||||
// -----------------------------------------------------------------------------
|
||||
// Field : PADS_QSPI_GPIO_QSPI_SS_PDE
|
||||
// Description : Pull down enable
|
||||
#define PADS_QSPI_GPIO_QSPI_SS_PDE_RESET _u(0x0)
|
||||
#define PADS_QSPI_GPIO_QSPI_SS_PDE_BITS _u(0x00000004)
|
||||
#define PADS_QSPI_GPIO_QSPI_SS_PDE_MSB _u(2)
|
||||
#define PADS_QSPI_GPIO_QSPI_SS_PDE_LSB _u(2)
|
||||
#define PADS_QSPI_GPIO_QSPI_SS_PDE_ACCESS "RW"
|
||||
// -----------------------------------------------------------------------------
|
||||
// Field : PADS_QSPI_GPIO_QSPI_SS_SCHMITT
|
||||
// Description : Enable schmitt trigger
|
||||
#define PADS_QSPI_GPIO_QSPI_SS_SCHMITT_RESET _u(0x1)
|
||||
#define PADS_QSPI_GPIO_QSPI_SS_SCHMITT_BITS _u(0x00000002)
|
||||
#define PADS_QSPI_GPIO_QSPI_SS_SCHMITT_MSB _u(1)
|
||||
#define PADS_QSPI_GPIO_QSPI_SS_SCHMITT_LSB _u(1)
|
||||
#define PADS_QSPI_GPIO_QSPI_SS_SCHMITT_ACCESS "RW"
|
||||
// -----------------------------------------------------------------------------
|
||||
// Field : PADS_QSPI_GPIO_QSPI_SS_SLEWFAST
|
||||
// Description : Slew rate control. 1 = Fast, 0 = Slow
|
||||
#define PADS_QSPI_GPIO_QSPI_SS_SLEWFAST_RESET _u(0x0)
|
||||
#define PADS_QSPI_GPIO_QSPI_SS_SLEWFAST_BITS _u(0x00000001)
|
||||
#define PADS_QSPI_GPIO_QSPI_SS_SLEWFAST_MSB _u(0)
|
||||
#define PADS_QSPI_GPIO_QSPI_SS_SLEWFAST_LSB _u(0)
|
||||
#define PADS_QSPI_GPIO_QSPI_SS_SLEWFAST_ACCESS "RW"
|
||||
// =============================================================================
|
||||
#endif // HARDWARE_REGS_PADS_QSPI_DEFINED
|
@ -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 "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,11 @@
|
||||
#ifndef RP2040_STAGE2_REGS_H
|
||||
#define RP2040_STAGE2_REGS_H
|
||||
|
||||
#define _u(x) x ## u
|
||||
|
||||
#include "ssi.h"
|
||||
#include "pads_qspi.h"
|
||||
#include "addressmap.h"
|
||||
#include "m0plus.h"
|
||||
|
||||
#endif // RP2040_STAGE2_REGS_H
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Target CPU: ARM Cortex-M0+
|
||||
* Target Chip: RP2040
|
||||
*/
|
||||
|
||||
ENTRY(_stage2_boot);
|
||||
|
||||
MEMORY
|
||||
{
|
||||
flash0 (rx!w) : ORIGIN = 0x10000000, LENGTH = 0x00200000
|
||||
ram0 (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00040000
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.text : {
|
||||
KEEP (*(.text))
|
||||
*(.rodata*)
|
||||
} > flash0
|
||||
|
||||
.ARM.exidx : {
|
||||
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
|
||||
} >flash0
|
||||
|
||||
|
||||
.data :
|
||||
{
|
||||
*(.data*)
|
||||
*(.bss*)
|
||||
} > ram0 /* AT> flash0 */
|
||||
}
|
@ -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
|
@ -0,0 +1,280 @@
|
||||
// ----------------------------------------------------------------------------
|
||||
// Second stage boot code
|
||||
// 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)
|
||||
// Also supports AT25SF081
|
||||
// Also supports S25FL132K0
|
||||
//
|
||||
// Description: Configures W25Q080 to run in Quad I/O continuous read XIP mode
|
||||
//
|
||||
// Details: * Check status register 2 to determine if QSPI mode is enabled,
|
||||
// and perform an SR2 programming cycle if necessary.
|
||||
// * Use SSI to perform a dummy 0xEB read command, with the mode
|
||||
// continuation bits set, so that the flash will not require
|
||||
// 0xEB instruction prefix on subsequent reads.
|
||||
// * Configure SSI to write address, mode bits, but no instruction.
|
||||
// SSI + flash are now jointly in a state where continuous reads
|
||||
// can take place.
|
||||
// * Jump to exit pointer passed in via lr. Bootrom passes null,
|
||||
// in which case this code uses a default 256 byte flash offset
|
||||
//
|
||||
// Building: * This code must be position-independent, and use stack only
|
||||
// * The code will be padded to a size of 256 bytes, including a
|
||||
// 4-byte checksum. Therefore code size cannot exceed 252 bytes.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include "shared/asm_helper.S"
|
||||
#include "shared/regs.h"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Config section
|
||||
// ----------------------------------------------------------------------------
|
||||
// It should be possible to support most flash devices by modifying this section
|
||||
|
||||
// The serial flash interface will run at clk_sys/PICO_FLASH_SPI_CLKDIV.
|
||||
// This must be a positive, even integer.
|
||||
// The bootrom is very conservative with SPI frequency, but here we should be
|
||||
// as aggressive as possible.
|
||||
|
||||
#ifndef PICO_FLASH_SPI_CLKDIV
|
||||
#define PICO_FLASH_SPI_CLKDIV 4
|
||||
#endif
|
||||
#if PICO_FLASH_SPI_CLKDIV & 1
|
||||
#error PICO_FLASH_SPI_CLKDIV must be even
|
||||
#endif
|
||||
|
||||
// Define interface width: single/dual/quad IO
|
||||
#define FRAME_FORMAT SSI_CTRLR0_SPI_FRF_VALUE_QUAD
|
||||
|
||||
// For W25Q080 this is the "Read data fast quad IO" instruction:
|
||||
#define CMD_READ 0xeb
|
||||
|
||||
// "Mode bits" are 8 special bits sent immediately after
|
||||
// the address bits in a "Read Data Fast Quad I/O" command sequence.
|
||||
// On W25Q080, the four LSBs are don't care, and if MSBs == 0xa, the
|
||||
// next read does not require the 0xeb instruction prefix.
|
||||
#define MODE_CONTINUOUS_READ 0xa0
|
||||
|
||||
// The number of address + mode bits, divided by 4 (always 4, not function of
|
||||
// interface width).
|
||||
#define ADDR_L 8
|
||||
|
||||
// How many clocks of Hi-Z following the mode bits. For W25Q080, 4 dummy cycles
|
||||
// are required.
|
||||
#define WAIT_CYCLES 4
|
||||
|
||||
// If defined, we will read status reg, compare to SREG_DATA, and overwrite
|
||||
// with our value if the SR doesn't match.
|
||||
// We do a two-byte write to SR1 (01h cmd) rather than a one-byte write to
|
||||
// SR2 (31h cmd) as the latter command isn't supported by WX25Q080.
|
||||
// This isn't great because it will remove block protections.
|
||||
// A better solution is to use a volatile SR write if your device supports it.
|
||||
#define PROGRAM_STATUS_REG
|
||||
|
||||
#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
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Start of 2nd Stage Boot Code
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
pico_default_asm_setup
|
||||
|
||||
.section .text
|
||||
|
||||
// The exit point is passed in lr. If entered from bootrom, this will be the
|
||||
// flash address immediately following this second stage (0x10000100).
|
||||
// Otherwise it will be a return address -- second stage being called as a
|
||||
// function by user code, after copying out of XIP region. r3 holds SSI base,
|
||||
// r0...2 used as temporaries. Other GPRs not used.
|
||||
regular_func _stage2_boot
|
||||
push {lr}
|
||||
|
||||
// Set pad configuration:
|
||||
// - SCLK 8mA drive, no slew limiting
|
||||
// - SDx disable input Schmitt to reduce delay
|
||||
|
||||
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
|
||||
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]
|
||||
|
||||
ldr r3, =XIP_SSI_BASE
|
||||
|
||||
// Disable SSI to allow further config
|
||||
movs r1, #0
|
||||
str r1, [r3, #SSI_SSIENR_OFFSET]
|
||||
|
||||
// Set baud rate
|
||||
movs r1, #PICO_FLASH_SPI_CLKDIV
|
||||
str r1, [r3, #SSI_BAUDR_OFFSET]
|
||||
|
||||
// Set 1-cycle sample delay. If PICO_FLASH_SPI_CLKDIV == 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.
|
||||
|
||||
movs r1, #1
|
||||
movs r2, #SSI_RX_SAMPLE_DLY_OFFSET // == 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)
|
||||
|
||||
ldr r1, =(CTRL0_SPI_TXRX)
|
||||
str r1, [r3, #SSI_CTRLR0_OFFSET]
|
||||
|
||||
// Enable SSI and select slave 0
|
||||
movs r1, #1
|
||||
str r1, [r3, #SSI_SSIENR_OFFSET]
|
||||
|
||||
// Check whether SR needs updating
|
||||
movs r0, #CMD_READ_STATUS2
|
||||
bl read_flash_sreg
|
||||
movs r2, #SREG_DATA
|
||||
cmp r0, r2
|
||||
beq skip_sreg_programming
|
||||
|
||||
// Send write enable command
|
||||
movs r1, #CMD_WRITE_ENABLE
|
||||
str r1, [r3, #SSI_DR0_OFFSET]
|
||||
|
||||
// Poll for completion and discard RX
|
||||
bl wait_ssi_ready
|
||||
ldr r1, [r3, #SSI_DR0_OFFSET]
|
||||
|
||||
// Send status write command followed by data bytes
|
||||
movs r1, #CMD_WRITE_STATUS
|
||||
str r1, [r3, #SSI_DR0_OFFSET]
|
||||
movs r0, #0
|
||||
str r0, [r3, #SSI_DR0_OFFSET]
|
||||
str r2, [r3, #SSI_DR0_OFFSET]
|
||||
|
||||
bl wait_ssi_ready
|
||||
ldr r1, [r3, #SSI_DR0_OFFSET]
|
||||
ldr r1, [r3, #SSI_DR0_OFFSET]
|
||||
ldr r1, [r3, #SSI_DR0_OFFSET]
|
||||
|
||||
// Poll status register for write completion
|
||||
1:
|
||||
movs r0, #CMD_READ_STATUS
|
||||
bl read_flash_sreg
|
||||
movs r1, #1
|
||||
tst r0, r1
|
||||
bne 1b
|
||||
|
||||
skip_sreg_programming:
|
||||
|
||||
// Disable SSI again so that it can be reconfigured
|
||||
movs r1, #0
|
||||
str r1, [r3, #SSI_SSIENR_OFFSET]
|
||||
#endif
|
||||
|
||||
// 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
|
||||
// command, with mode bits set such that the flash will not expect a serial
|
||||
// command prefix on *subsequent* transfers. We don't care about the results
|
||||
// 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)
|
||||
|
||||
ldr r1, =(CTRLR0_ENTER_XIP)
|
||||
str r1, [r3, #SSI_CTRLR0_OFFSET]
|
||||
|
||||
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, [r0]
|
||||
|
||||
movs r1, #1 // Re-enable SSI
|
||||
str r1, [r3, #SSI_SSIENR_OFFSET]
|
||||
|
||||
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
|
||||
|
||||
// Poll for completion
|
||||
bl wait_ssi_ready
|
||||
|
||||
// The flash is in a state where we can blast addresses in parallel, and get
|
||||
// parallel data back. Now configure the SSI to translate XIP bus accesses
|
||||
// into QSPI transfers of this form.
|
||||
|
||||
movs r1, #0
|
||||
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:
|
||||
// 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)
|
||||
|
||||
ldr r1, =(SPI_CTRLR0_XIP)
|
||||
ldr r0, =(XIP_SSI_BASE + SSI_SPI_CTRLR0_OFFSET)
|
||||
str r1, [r0]
|
||||
|
||||
movs r1, #1
|
||||
str r1, [r3, #SSI_SSIENR_OFFSET] // 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 "shared/exit_from_boot2.S"
|
||||
|
||||
// Common functions
|
||||
#include "shared/wait_ssi_ready.S"
|
||||
#ifdef PROGRAM_STATUS_REG
|
||||
#include "shared/read_flash_sreg.S"
|
||||
#endif
|
||||
|
||||
.global literals
|
||||
literals:
|
||||
.ltorg
|
||||
|
||||
.end
|
@ -0,0 +1,191 @@
|
||||
// ----------------------------------------------------------------------------
|
||||
// Second stage boot code
|
||||
// Copyright (c) 2019-2021 Raspberry Pi (Trading) Ltd.
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
//
|
||||
// Device: Winbond W25X10CL
|
||||
//
|
||||
// Description: Configures W25X10CL to run in Dual I/O continuous read XIP mode
|
||||
//
|
||||
// Details: * Disable SSI
|
||||
// * Configure SSI to generate 8b command + 28b address + 2 wait,
|
||||
// with address and data using dual SPI mode
|
||||
// * Enable SSI
|
||||
// * Generate dummy read with command = 0xBB, top 24b of address
|
||||
// of 0x000000 followed by M[7:0]=0010zzzz (with the HiZ being
|
||||
// generated by 2 wait cycles). This leaves the W25X10CL in
|
||||
// continuous read mode
|
||||
// * Disable SSI
|
||||
// * Configure SSI to generate 0b command + 28b address + 2 wait,
|
||||
// with the extra 4 bits of address LSB being 0x2 to keep the
|
||||
// W25X10CL in continuous read mode forever
|
||||
// * Enable SSI
|
||||
// * Set VTOR = 0x10000100
|
||||
// * Read MSP reset vector from 0x10000100 and write to MSP (this
|
||||
// will also enable XIP mode in the SSI wrapper)
|
||||
// * Read PC reset vector from 0x10000104 and jump to it
|
||||
//
|
||||
// Building: * This code must be linked to run at 0x20000000
|
||||
// * The code will be padded to a size of 256 bytes, including a
|
||||
// 4-byte checksum. Therefore code size cannot exceed 252 bytes.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include "shared/asm_helper.S"
|
||||
#include "shared/regs.h"
|
||||
|
||||
// The serial flash interface will run at clk_sys/PICO_FLASH_SPI_CLKDIV.
|
||||
// This must be an even number.
|
||||
#ifndef PICO_FLASH_SPI_CLKDIV
|
||||
#define PICO_FLASH_SPI_CLKDIV 4
|
||||
#endif
|
||||
|
||||
pico_default_asm_setup
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// The "System Control Block" is a set of internal Cortex-M0+ control registers
|
||||
// that are memory mapped and accessed like any other H/W register. They have
|
||||
// fixed addresses in the address map of every Cortex-M0+ system.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
.equ SCB_VTOR, 0xE000ED08 // RW Vector Table Offset Register
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Winbond W25X10CL Supported Commands
|
||||
// Taken from "w25x10cl_reg_021714.pdf"
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
.equ W25X10CL_CMD_READ_DATA_FAST_DUAL_IO, 0xbb
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Winbond W25X10CL "Mode bits" are 8 special bits sent immediately after
|
||||
// the address bits in a "Read Data Fast Dual I/O" command sequence.
|
||||
// Of M[7:4], they say M[7:6] are reserved (set to zero), and bits M[3:0]
|
||||
// are don't care (we HiZ). Only M[5:4] are used, and they must be set
|
||||
// to M[5:4] = 2'b10 to enable continuous read mode.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
.equ W25X10CL_MODE_CONTINUOUS_READ, 0x20
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Start of 2nd Stage Boot Code
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
.org 0
|
||||
|
||||
.section .text
|
||||
|
||||
// This code will get copied to 0x20000000 and then executed
|
||||
|
||||
regular_func _stage2_boot
|
||||
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
|
||||
|
||||
movs r1, #0
|
||||
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.
|
||||
|
||||
movs r1, #PICO_FLASH_SPI_CLKDIV
|
||||
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.
|
||||
// To enter Continuous Read mode as well we need to append 4'b0010 to the address
|
||||
// bits and then add a further 4 don't care bits. We will construct this by
|
||||
// specifying a 28-bit address, with the least significant bits being 4'b0010.
|
||||
// This is just a dummy transaction so we'll perform a read from address zero
|
||||
// and then discard what comes back. All we really care about is that at the
|
||||
// end of the transaction, the Winbond W25X10CL device is in Continuous Read mode
|
||||
// and from then on will only expect to receive addresses.
|
||||
|
||||
#define CTRLR0_ENTER_XIP \
|
||||
(SSI_CTRLR0_SPI_FRF_VALUE_DUAL /* Dual 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)
|
||||
|
||||
ldr r1, =(CTRLR0_ENTER_XIP)
|
||||
str r1, [r3, #SSI_CTRLR0_OFFSET]
|
||||
|
||||
movs r1, #0x0 // NDF=0 (single 32b read)
|
||||
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) */ \
|
||||
(2 << SSI_SPI_CTRLR0_WAIT_CYCLES_LSB) | /* Hi-Z the other 4 mode bits (2 cycles @ dual I/O = 4 bits) */ \
|
||||
(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 Dual 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, [r0]
|
||||
|
||||
movs r1, #1 // Re-enable SSI
|
||||
str r1, [r3, #SSI_SSIENR_OFFSET]
|
||||
|
||||
movs r1, #W25X10CL_CMD_READ_DATA_FAST_DUAL_IO // 8b command = 0xBB
|
||||
str r1, [r3, #SSI_DR0_OFFSET] // Push SPI command into TX FIFO
|
||||
movs r1, #0x0000002 // 28-bit Address for dummy read = 0x000000 + 0x2 Mode bits to set M[5:4]=10
|
||||
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.
|
||||
|
||||
movs r1, #SSI_SR_RFNE_BITS
|
||||
00:
|
||||
ldr r0, [r3, #SSI_SR_OFFSET] // Read status register
|
||||
tst r0, r1 // RFNE status flag set?
|
||||
beq 00b // If not then wait
|
||||
|
||||
// At this point CN# will be deasserted and the SPI clock will not be running.
|
||||
// The Winbond WX25X10CL device will be in continuous read, dual I/O mode and
|
||||
// only expecting address bits after the next CN# assertion. So long as we
|
||||
// send 4'b0010 (and 4 more dummy HiZ bits) after every subsequent 24b address
|
||||
// then the Winbond device will remain in continuous read mode. This is the
|
||||
// ideal mode for Execute-In-Place.
|
||||
// (If we want to exit continuous read mode then we will need to switch back
|
||||
// to APM mode and generate a 28-bit address phase with the extra nibble set
|
||||
// to 4'b0000).
|
||||
|
||||
movs r1, #0
|
||||
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:
|
||||
// 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
|
||||
|
||||
#define SPI_CTRLR0_XIP \
|
||||
(W25X10CL_MODE_CONTINUOUS_READ /* Mode bits to keep Winbond in continuous read mode */ \
|
||||
<< SSI_SPI_CTRLR0_XIP_CMD_LSB) | \
|
||||
(7 << SSI_SPI_CTRLR0_ADDR_L_LSB) | /* Send 28 bits (24 address + 4 mode) */ \
|
||||
(2 << SSI_SPI_CTRLR0_WAIT_CYCLES_LSB) | /* Hi-Z the other 4 mode bits (2 cycles @ dual I/O = 4 bits) */ \
|
||||
(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 Dual I/O mode (and Command but that is zero bits long) */ \
|
||||
<< SSI_SPI_CTRLR0_TRANS_TYPE_LSB)
|
||||
|
||||
ldr r1, =(SPI_CTRLR0_XIP)
|
||||
ldr r0, =(XIP_SSI_BASE + SSI_SPI_CTRLR0_OFFSET)
|
||||
str r1, [r0]
|
||||
|
||||
movs r1, #1
|
||||
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.
|
||||
|
||||
// Pull in standard exit routine
|
||||
#include "shared/exit_from_boot2.S"
|
||||
|
||||
.global literals
|
||||
literals:
|
||||
.ltorg
|
||||
|
||||
.end
|
Loading…
Reference in New Issue