Implements proper support for different stage2 bootloaders (#80)

Co-authored-by: Felix "xq" Queißner <git@random-projects.net>
wch-ch32v003
Felix Queißner 1 year ago committed by GitHub
parent 6f201f7f4c
commit 2a0c0ff281
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -5,3 +5,11 @@ HAL and register definitions for the RP2040.
== What version of Zig to use
0.11.0
== Supported devices ==
- Raspberry Pi Pico
- (*experimental*) Waveshare RP2040-Plus (4M Flash)
- (*experimental*) Waveshare RP2040-Plus (16M Flash)
- (*experimental*) Waveshare RP2040-ETH Mini
- (*experimental*) Waveshare RP2040-Matrix

@ -1,43 +1,121 @@
const std = @import("std");
const Builder = std.build.Builder;
const Pkg = std.build.Pkg;
const Build = std.Build;
const comptimePrint = std.fmt.comptimePrint;
const LazyPath = std.build.LazyPath;
const microzig = @import("microzig");
pub const chips = @import("src/chips.zig");
pub const boards = @import("src/boards.zig");
const linkerscript_path = root() ++ "rp2040.ld";
const build_root = root();
pub const BuildOptions = struct {
optimize: std.builtin.OptimizeMode,
const linkerscript_path = build_root ++ "/rp2040.ld";
pub const BootROM = union(enum) {
artifact: *std.build.CompileStep, // provide a custom startup code
blob: std.build.LazyPath, // just include a binary blob
// Pre-shipped ones:
at25sf128a,
generic_03h,
is25lp080,
w25q080,
w25x10cl,
// Use the old stage2 bootloader vendored with MicroZig till 2023-09-13
legacy,
};
pub const PicoExecutableOptions = struct {
name: []const u8,
source_file: LazyPath,
source_file: std.Build.LazyPath,
optimize: std.builtin.OptimizeMode = .Debug,
board: boards.Board = boards.raspberry_pi_pico,
bootrom: ?BootROM = null,
};
pub fn addPiPicoExecutable(
builder: *Builder,
pub const addPiPicoExecutable = addExecutable; // Deprecated, use addExecutable!
pub const Stage2Bootloader = struct {
bin: std.Build.LazyPath,
elf: ?std.Build.LazyPath,
};
pub fn getBootrom(b: *Build, rom: BootROM) Stage2Bootloader {
const rom_exe = switch (rom) {
.artifact => |artifact| artifact,
.blob => |blob| return Stage2Bootloader{
.bin = blob,
.elf = null,
},
else => blk: {
var target = chips.rp2040.cpu.target;
target.abi = .eabi;
const rom_path = b.pathFromRoot(b.fmt("{s}/src/bootroms/{s}.S", .{ build_root, @tagName(rom) }));
const rom_exe = b.addExecutable(.{
.name = b.fmt("stage2-{s}", .{@tagName(rom)}),
.optimize = .ReleaseSmall,
.target = target,
.root_source_file = null,
});
rom_exe.linkage = .static;
// rom_exe.pie = false;
// rom_exe.force_pic = false;
rom_exe.setLinkerScript(.{ .path = build_root ++ "/src/bootroms/shared/stage2.ld" });
rom_exe.addAssemblyFile(.{ .path = rom_path });
break :blk rom_exe;
},
};
const rom_objcopy = b.addObjCopy(rom_exe.getEmittedBin(), .{
.basename = b.fmt("{s}.bin", .{@tagName(rom)}),
.format = .bin,
});
return Stage2Bootloader{
.bin = rom_objcopy.getOutput(),
.elf = rom_exe.getEmittedBin(),
};
}
pub fn addExecutable(
b: *Build,
opts: PicoExecutableOptions,
) *microzig.EmbeddedExecutable {
return microzig.addEmbeddedExecutable(builder, .{
var exe = microzig.addEmbeddedExecutable(b, .{
.name = opts.name,
.source_file = opts.source_file,
.backing = .{ .board = boards.raspberry_pi_pico },
.backing = .{ .board = opts.board.inner },
.optimize = opts.optimize,
.linkerscript_source_file = .{ .path = linkerscript_path },
});
const i: *std.Build.CompileStep = exe.inner;
const bootrom_file = getBootrom(b, opts.bootrom orelse opts.board.bootrom);
// HACK: Inject the file as a dependency to MicroZig.board
i.modules.get("microzig").?.dependencies.get("board").?.dependencies.put(
"bootloader",
b.createModule(.{
.source_file = bootrom_file.bin,
}),
) catch @panic("oom");
bootrom_file.bin.addStepDependencies(&i.step);
return exe;
}
// this build script is mostly for testing and verification of this
// package. In an attempt to modularize -- designing for a case where a
// project requires multiple HALs, it accepts microzig as a param
pub fn build(b: *Builder) !void {
pub fn build(b: *Build) !void {
const optimize = b.standardOptimizeOption(.{});
const args_dep = b.dependency("args", .{});
@ -57,15 +135,40 @@ pub fn build(b: *Builder) !void {
const test_step = b.step("test", "run unit tests");
test_step.dependOn(&b.addRunArtifact(pio_tests).step);
const flash_tool = b.addExecutable(.{
.name = "rp2040-flash",
.optimize = .Debug,
.target = .{},
.root_source_file = .{ .path = "tools/rp2040-flash.zig" },
});
flash_tool.addModule("args", args_mod);
{
const flash_tool = b.addExecutable(.{
.name = "rp2040-flash",
.optimize = .Debug,
.target = .{},
.root_source_file = .{ .path = "tools/rp2040-flash.zig" },
});
flash_tool.addModule("args", args_mod);
b.installArtifact(flash_tool);
b.installArtifact(flash_tool);
}
// Install all bootroms for debugging and CI
inline for (comptime std.enums.values(std.meta.Tag(BootROM))) |rom| {
if (rom == .artifact or rom == .blob) {
continue;
}
if (rom == .is25lp080) {
// TODO: https://github.com/ZigEmbeddedGroup/raspberrypi-rp2040/issues/79
// is25lp080.o:(text+0x16): has non-ABS relocation R_ARM_THM_CALL against symbol 'read_flash_sreg'
continue;
}
const files = getBootrom(b, rom);
if (files.elf) |elf| {
b.getInstallStep().dependOn(
&b.addInstallFileWithDir(elf, .{ .custom = "stage2" }, b.fmt("{s}.elf", .{@tagName(rom)})).step,
);
}
b.getInstallStep().dependOn(
&b.addInstallFileWithDir(files.bin, .{ .custom = "stage2" }, b.fmt("{s}.bin", .{@tagName(rom)})).step,
);
}
}
fn root() []const u8 {
@ -89,12 +192,12 @@ pub const Examples = struct {
ws2812: *microzig.EmbeddedExecutable,
random: *microzig.EmbeddedExecutable,
pub fn init(b: *Builder, optimize: std.builtin.OptimizeMode) Examples {
pub fn init(b: *Build, optimize: std.builtin.OptimizeMode) Examples {
var ret: Examples = undefined;
inline for (@typeInfo(Examples).Struct.fields) |field| {
const path = comptime root() ++ "examples/" ++ field.name ++ ".zig";
@field(ret, field.name) = addPiPicoExecutable(b, .{
@field(ret, field.name) = addExecutable(b, .{
.name = field.name,
.source_file = .{ .path = path },
.optimize = optimize,
@ -104,9 +207,11 @@ pub const Examples = struct {
return ret;
}
pub fn install(examples: *Examples, b: *Builder) void {
pub fn install(examples: *Examples, b: *Build) void {
inline for (@typeInfo(Examples).Struct.fields) |field| {
b.installArtifact(@field(examples, field.name).inner);
b.getInstallStep().dependOn(
&b.addInstallFileWithDir(@field(examples, field.name).inner.getEmittedBin(), .{ .custom = "firmware" }, field.name ++ ".elf").step,
);
}
}
};

@ -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,
};
// https://www.raspberrypi.com/products/raspberry-pi-pico/
pub const raspberry_pi_pico = Board{
.inner = .{
.name = "Raspberry Pi Pico",
.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,
};
pub const raspberry_pi_pico = microzig.Board{
.name = "Raspberry Pi Pico",
.source = .{ .path = board_path },
.chip = chips.rp2040,
// 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,809 @@
/**
* Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
// =============================================================================
// Register block : SSI
// Version : 1
// Bus type : apb
// Description : DW_apb_ssi has the following features:
// * APB interface Allows for easy integration into a
// DesignWare Synthesizable Components for AMBA 2
// implementation.
// * APB3 and APB4 protocol support.
// * Scalable APB data bus width Supports APB data bus widths
// of 8, 16, and 32 bits.
// * Serial-master or serial-slave operation Enables serial
// communication with serial-master or serial-slave peripheral
// devices.
// * Programmable Dual/Quad/Octal SPI support in Master Mode.
// * Dual Data Rate (DDR) and Read Data Strobe (RDS) Support -
// Enables the DW_apb_ssi master to perform operations with the
// device in DDR and RDS modes when working in Dual/Quad/Octal
// mode of operation.
// * Data Mask Support - Enables the DW_apb_ssi to selectively
// update the bytes in the device. This feature is applicable
// only in enhanced SPI modes.
// * eXecute-In-Place (XIP) support - Enables the DW_apb_ssi
// master to behave as a memory mapped I/O and fetches the data
// from the device based on the APB read request. This feature
// is applicable only in enhanced SPI modes.
// * DMA Controller Interface Enables the DW_apb_ssi to
// interface to a DMA controller over the bus using a
// handshaking interface for transfer requests.
// * Independent masking of interrupts Master collision,
// transmit FIFO overflow, transmit FIFO empty, receive FIFO
// full, receive FIFO underflow, and receive FIFO overflow
// interrupts can all be masked independently.
// * Multi-master contention detection Informs the processor
// of multiple serial-master accesses on the serial bus.
// * Bypass of meta-stability flip-flops for synchronous clocks
// When the APB clock (pclk) and the DW_apb_ssi serial clock
// (ssi_clk) are synchronous, meta-stable flip-flops are not
// used when transferring control signals across these clock
// domains.
// * Programmable delay on the sample time of the received
// serial data bit (rxd); enables programmable control of
// routing delays resulting in higher serial data-bit rates.
// * Programmable features:
// - Serial interface operation Choice of Motorola SPI, Texas
// Instruments Synchronous Serial Protocol or National
// Semiconductor Microwire.
// - Clock bit-rate Dynamic control of the serial bit rate of
// the data transfer; used in only serial-master mode of
// operation.
// - Data Item size (4 to 32 bits) Item size of each data
// transfer under the control of the programmer.
// * Configured features:
// - FIFO depth 16 words deep. The FIFO width is fixed at 32
// bits.
// - 1 slave select output.
// - Hardware slave-select Dedicated hardware slave-select
// line.
// - Combined interrupt line - one combined interrupt line from
// the DW_apb_ssi to the interrupt controller.
// - Interrupt polarity active high interrupt lines.
// - Serial clock polarity low serial-clock polarity directly
// after reset.
// - Serial clock phase capture on first edge of serial-clock
// directly after reset.
// =============================================================================
#ifndef HARDWARE_REGS_SSI_DEFINED
#define HARDWARE_REGS_SSI_DEFINED
// =============================================================================
// Register : SSI_CTRLR0
// Description : Control register 0
#define SSI_CTRLR0_OFFSET _u(0x00000000)
#define SSI_CTRLR0_BITS _u(0x017fffff)
#define SSI_CTRLR0_RESET _u(0x00000000)
// -----------------------------------------------------------------------------
// Field : SSI_CTRLR0_SSTE
// Description : Slave select toggle enable
#define SSI_CTRLR0_SSTE_RESET _u(0x0)
#define SSI_CTRLR0_SSTE_BITS _u(0x01000000)
#define SSI_CTRLR0_SSTE_MSB _u(24)
#define SSI_CTRLR0_SSTE_LSB _u(24)
#define SSI_CTRLR0_SSTE_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : SSI_CTRLR0_SPI_FRF
// Description : SPI frame format
// 0x0 -> Standard 1-bit SPI frame format; 1 bit per SCK,
// full-duplex
// 0x1 -> Dual-SPI frame format; two bits per SCK, half-duplex
// 0x2 -> Quad-SPI frame format; four bits per SCK, half-duplex
#define SSI_CTRLR0_SPI_FRF_RESET _u(0x0)
#define SSI_CTRLR0_SPI_FRF_BITS _u(0x00600000)
#define SSI_CTRLR0_SPI_FRF_MSB _u(22)
#define SSI_CTRLR0_SPI_FRF_LSB _u(21)
#define SSI_CTRLR0_SPI_FRF_ACCESS "RW"
#define SSI_CTRLR0_SPI_FRF_VALUE_STD _u(0x0)
#define SSI_CTRLR0_SPI_FRF_VALUE_DUAL _u(0x1)
#define SSI_CTRLR0_SPI_FRF_VALUE_QUAD _u(0x2)
// -----------------------------------------------------------------------------
// Field : SSI_CTRLR0_DFS_32
// Description : Data frame size in 32b transfer mode
// Value of n -> n+1 clocks per frame.
#define SSI_CTRLR0_DFS_32_RESET _u(0x00)
#define SSI_CTRLR0_DFS_32_BITS _u(0x001f0000)
#define SSI_CTRLR0_DFS_32_MSB _u(20)
#define SSI_CTRLR0_DFS_32_LSB _u(16)
#define SSI_CTRLR0_DFS_32_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : SSI_CTRLR0_CFS
// Description : Control frame size
// Value of n -> n+1 clocks per frame.
#define SSI_CTRLR0_CFS_RESET _u(0x0)
#define SSI_CTRLR0_CFS_BITS _u(0x0000f000)
#define SSI_CTRLR0_CFS_MSB _u(15)
#define SSI_CTRLR0_CFS_LSB _u(12)
#define SSI_CTRLR0_CFS_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : SSI_CTRLR0_SRL
// Description : Shift register loop (test mode)
#define SSI_CTRLR0_SRL_RESET _u(0x0)
#define SSI_CTRLR0_SRL_BITS _u(0x00000800)
#define SSI_CTRLR0_SRL_MSB _u(11)
#define SSI_CTRLR0_SRL_LSB _u(11)
#define SSI_CTRLR0_SRL_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : SSI_CTRLR0_SLV_OE
// Description : Slave output enable
#define SSI_CTRLR0_SLV_OE_RESET _u(0x0)
#define SSI_CTRLR0_SLV_OE_BITS _u(0x00000400)
#define SSI_CTRLR0_SLV_OE_MSB _u(10)
#define SSI_CTRLR0_SLV_OE_LSB _u(10)
#define SSI_CTRLR0_SLV_OE_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : SSI_CTRLR0_TMOD
// Description : Transfer mode
// 0x0 -> Both transmit and receive
// 0x1 -> Transmit only (not for FRF == 0, standard SPI mode)
// 0x2 -> Receive only (not for FRF == 0, standard SPI mode)
// 0x3 -> EEPROM read mode (TX then RX; RX starts after control
// data TX'd)
#define SSI_CTRLR0_TMOD_RESET _u(0x0)
#define SSI_CTRLR0_TMOD_BITS _u(0x00000300)
#define SSI_CTRLR0_TMOD_MSB _u(9)
#define SSI_CTRLR0_TMOD_LSB _u(8)
#define SSI_CTRLR0_TMOD_ACCESS "RW"
#define SSI_CTRLR0_TMOD_VALUE_TX_AND_RX _u(0x0)
#define SSI_CTRLR0_TMOD_VALUE_TX_ONLY _u(0x1)
#define SSI_CTRLR0_TMOD_VALUE_RX_ONLY _u(0x2)
#define SSI_CTRLR0_TMOD_VALUE_EEPROM_READ _u(0x3)
// -----------------------------------------------------------------------------
// Field : SSI_CTRLR0_SCPOL
// Description : Serial clock polarity
#define SSI_CTRLR0_SCPOL_RESET _u(0x0)
#define SSI_CTRLR0_SCPOL_BITS _u(0x00000080)
#define SSI_CTRLR0_SCPOL_MSB _u(7)
#define SSI_CTRLR0_SCPOL_LSB _u(7)
#define SSI_CTRLR0_SCPOL_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : SSI_CTRLR0_SCPH
// Description : Serial clock phase
#define SSI_CTRLR0_SCPH_RESET _u(0x0)
#define SSI_CTRLR0_SCPH_BITS _u(0x00000040)
#define SSI_CTRLR0_SCPH_MSB _u(6)
#define SSI_CTRLR0_SCPH_LSB _u(6)
#define SSI_CTRLR0_SCPH_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : SSI_CTRLR0_FRF
// Description : Frame format
#define SSI_CTRLR0_FRF_RESET _u(0x0)
#define SSI_CTRLR0_FRF_BITS _u(0x00000030)
#define SSI_CTRLR0_FRF_MSB _u(5)
#define SSI_CTRLR0_FRF_LSB _u(4)
#define SSI_CTRLR0_FRF_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : SSI_CTRLR0_DFS
// Description : Data frame size
#define SSI_CTRLR0_DFS_RESET _u(0x0)
#define SSI_CTRLR0_DFS_BITS _u(0x0000000f)
#define SSI_CTRLR0_DFS_MSB _u(3)
#define SSI_CTRLR0_DFS_LSB _u(0)
#define SSI_CTRLR0_DFS_ACCESS "RW"
// =============================================================================
// Register : SSI_CTRLR1
// Description : Master Control register 1
#define SSI_CTRLR1_OFFSET _u(0x00000004)
#define SSI_CTRLR1_BITS _u(0x0000ffff)
#define SSI_CTRLR1_RESET _u(0x00000000)
// -----------------------------------------------------------------------------
// Field : SSI_CTRLR1_NDF
// Description : Number of data frames
#define SSI_CTRLR1_NDF_RESET _u(0x0000)
#define SSI_CTRLR1_NDF_BITS _u(0x0000ffff)
#define SSI_CTRLR1_NDF_MSB _u(15)
#define SSI_CTRLR1_NDF_LSB _u(0)
#define SSI_CTRLR1_NDF_ACCESS "RW"
// =============================================================================
// Register : SSI_SSIENR
// Description : SSI Enable
#define SSI_SSIENR_OFFSET _u(0x00000008)
#define SSI_SSIENR_BITS _u(0x00000001)
#define SSI_SSIENR_RESET _u(0x00000000)
// -----------------------------------------------------------------------------
// Field : SSI_SSIENR_SSI_EN
// Description : SSI enable
#define SSI_SSIENR_SSI_EN_RESET _u(0x0)
#define SSI_SSIENR_SSI_EN_BITS _u(0x00000001)
#define SSI_SSIENR_SSI_EN_MSB _u(0)
#define SSI_SSIENR_SSI_EN_LSB _u(0)
#define SSI_SSIENR_SSI_EN_ACCESS "RW"
// =============================================================================
// Register : SSI_MWCR
// Description : Microwire Control
#define SSI_MWCR_OFFSET _u(0x0000000c)
#define SSI_MWCR_BITS _u(0x00000007)
#define SSI_MWCR_RESET _u(0x00000000)
// -----------------------------------------------------------------------------
// Field : SSI_MWCR_MHS
// Description : Microwire handshaking
#define SSI_MWCR_MHS_RESET _u(0x0)
#define SSI_MWCR_MHS_BITS _u(0x00000004)
#define SSI_MWCR_MHS_MSB _u(2)
#define SSI_MWCR_MHS_LSB _u(2)
#define SSI_MWCR_MHS_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : SSI_MWCR_MDD
// Description : Microwire control
#define SSI_MWCR_MDD_RESET _u(0x0)
#define SSI_MWCR_MDD_BITS _u(0x00000002)
#define SSI_MWCR_MDD_MSB _u(1)
#define SSI_MWCR_MDD_LSB _u(1)
#define SSI_MWCR_MDD_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : SSI_MWCR_MWMOD
// Description : Microwire transfer mode
#define SSI_MWCR_MWMOD_RESET _u(0x0)
#define SSI_MWCR_MWMOD_BITS _u(0x00000001)
#define SSI_MWCR_MWMOD_MSB _u(0)
#define SSI_MWCR_MWMOD_LSB _u(0)
#define SSI_MWCR_MWMOD_ACCESS "RW"
// =============================================================================
// Register : SSI_SER
// Description : Slave enable
// For each bit:
// 0 -> slave not selected
// 1 -> slave selected
#define SSI_SER_OFFSET _u(0x00000010)
#define SSI_SER_BITS _u(0x00000001)
#define SSI_SER_RESET _u(0x00000000)
#define SSI_SER_MSB _u(0)
#define SSI_SER_LSB _u(0)
#define SSI_SER_ACCESS "RW"
// =============================================================================
// Register : SSI_BAUDR
// Description : Baud rate
#define SSI_BAUDR_OFFSET _u(0x00000014)
#define SSI_BAUDR_BITS _u(0x0000ffff)
#define SSI_BAUDR_RESET _u(0x00000000)
// -----------------------------------------------------------------------------
// Field : SSI_BAUDR_SCKDV
// Description : SSI clock divider
#define SSI_BAUDR_SCKDV_RESET _u(0x0000)
#define SSI_BAUDR_SCKDV_BITS _u(0x0000ffff)
#define SSI_BAUDR_SCKDV_MSB _u(15)
#define SSI_BAUDR_SCKDV_LSB _u(0)
#define SSI_BAUDR_SCKDV_ACCESS "RW"
// =============================================================================
// Register : SSI_TXFTLR
// Description : TX FIFO threshold level
#define SSI_TXFTLR_OFFSET _u(0x00000018)
#define SSI_TXFTLR_BITS _u(0x000000ff)
#define SSI_TXFTLR_RESET _u(0x00000000)
// -----------------------------------------------------------------------------
// Field : SSI_TXFTLR_TFT
// Description : Transmit FIFO threshold
#define SSI_TXFTLR_TFT_RESET _u(0x00)
#define SSI_TXFTLR_TFT_BITS _u(0x000000ff)
#define SSI_TXFTLR_TFT_MSB _u(7)
#define SSI_TXFTLR_TFT_LSB _u(0)
#define SSI_TXFTLR_TFT_ACCESS "RW"
// =============================================================================
// Register : SSI_RXFTLR
// Description : RX FIFO threshold level
#define SSI_RXFTLR_OFFSET _u(0x0000001c)
#define SSI_RXFTLR_BITS _u(0x000000ff)
#define SSI_RXFTLR_RESET _u(0x00000000)
// -----------------------------------------------------------------------------
// Field : SSI_RXFTLR_RFT
// Description : Receive FIFO threshold
#define SSI_RXFTLR_RFT_RESET _u(0x00)
#define SSI_RXFTLR_RFT_BITS _u(0x000000ff)
#define SSI_RXFTLR_RFT_MSB _u(7)
#define SSI_RXFTLR_RFT_LSB _u(0)
#define SSI_RXFTLR_RFT_ACCESS "RW"
// =============================================================================
// Register : SSI_TXFLR
// Description : TX FIFO level
#define SSI_TXFLR_OFFSET _u(0x00000020)
#define SSI_TXFLR_BITS _u(0x000000ff)
#define SSI_TXFLR_RESET _u(0x00000000)
// -----------------------------------------------------------------------------
// Field : SSI_TXFLR_TFTFL
// Description : Transmit FIFO level
#define SSI_TXFLR_TFTFL_RESET _u(0x00)
#define SSI_TXFLR_TFTFL_BITS _u(0x000000ff)
#define SSI_TXFLR_TFTFL_MSB _u(7)
#define SSI_TXFLR_TFTFL_LSB _u(0)
#define SSI_TXFLR_TFTFL_ACCESS "RO"
// =============================================================================
// Register : SSI_RXFLR
// Description : RX FIFO level
#define SSI_RXFLR_OFFSET _u(0x00000024)
#define SSI_RXFLR_BITS _u(0x000000ff)
#define SSI_RXFLR_RESET _u(0x00000000)
// -----------------------------------------------------------------------------
// Field : SSI_RXFLR_RXTFL
// Description : Receive FIFO level
#define SSI_RXFLR_RXTFL_RESET _u(0x00)
#define SSI_RXFLR_RXTFL_BITS _u(0x000000ff)
#define SSI_RXFLR_RXTFL_MSB _u(7)
#define SSI_RXFLR_RXTFL_LSB _u(0)
#define SSI_RXFLR_RXTFL_ACCESS "RO"
// =============================================================================
// Register : SSI_SR
// Description : Status register
#define SSI_SR_OFFSET _u(0x00000028)
#define SSI_SR_BITS _u(0x0000007f)
#define SSI_SR_RESET _u(0x00000000)
// -----------------------------------------------------------------------------
// Field : SSI_SR_DCOL
// Description : Data collision error
#define SSI_SR_DCOL_RESET _u(0x0)
#define SSI_SR_DCOL_BITS _u(0x00000040)
#define SSI_SR_DCOL_MSB _u(6)
#define SSI_SR_DCOL_LSB _u(6)
#define SSI_SR_DCOL_ACCESS "RO"
// -----------------------------------------------------------------------------
// Field : SSI_SR_TXE
// Description : Transmission error
#define SSI_SR_TXE_RESET _u(0x0)
#define SSI_SR_TXE_BITS _u(0x00000020)
#define SSI_SR_TXE_MSB _u(5)
#define SSI_SR_TXE_LSB _u(5)
#define SSI_SR_TXE_ACCESS "RO"
// -----------------------------------------------------------------------------
// Field : SSI_SR_RFF
// Description : Receive FIFO full
#define SSI_SR_RFF_RESET _u(0x0)
#define SSI_SR_RFF_BITS _u(0x00000010)
#define SSI_SR_RFF_MSB _u(4)
#define SSI_SR_RFF_LSB _u(4)
#define SSI_SR_RFF_ACCESS "RO"
// -----------------------------------------------------------------------------
// Field : SSI_SR_RFNE
// Description : Receive FIFO not empty
#define SSI_SR_RFNE_RESET _u(0x0)
#define SSI_SR_RFNE_BITS _u(0x00000008)
#define SSI_SR_RFNE_MSB _u(3)
#define SSI_SR_RFNE_LSB _u(3)
#define SSI_SR_RFNE_ACCESS "RO"
// -----------------------------------------------------------------------------
// Field : SSI_SR_TFE
// Description : Transmit FIFO empty
#define SSI_SR_TFE_RESET _u(0x0)
#define SSI_SR_TFE_BITS _u(0x00000004)
#define SSI_SR_TFE_MSB _u(2)
#define SSI_SR_TFE_LSB _u(2)
#define SSI_SR_TFE_ACCESS "RO"
// -----------------------------------------------------------------------------
// Field : SSI_SR_TFNF
// Description : Transmit FIFO not full
#define SSI_SR_TFNF_RESET _u(0x0)
#define SSI_SR_TFNF_BITS _u(0x00000002)
#define SSI_SR_TFNF_MSB _u(1)
#define SSI_SR_TFNF_LSB _u(1)
#define SSI_SR_TFNF_ACCESS "RO"
// -----------------------------------------------------------------------------
// Field : SSI_SR_BUSY
// Description : SSI busy flag
#define SSI_SR_BUSY_RESET _u(0x0)
#define SSI_SR_BUSY_BITS _u(0x00000001)
#define SSI_SR_BUSY_MSB _u(0)
#define SSI_SR_BUSY_LSB _u(0)
#define SSI_SR_BUSY_ACCESS "RO"
// =============================================================================
// Register : SSI_IMR
// Description : Interrupt mask
#define SSI_IMR_OFFSET _u(0x0000002c)
#define SSI_IMR_BITS _u(0x0000003f)
#define SSI_IMR_RESET _u(0x00000000)
// -----------------------------------------------------------------------------
// Field : SSI_IMR_MSTIM
// Description : Multi-master contention interrupt mask
#define SSI_IMR_MSTIM_RESET _u(0x0)
#define SSI_IMR_MSTIM_BITS _u(0x00000020)
#define SSI_IMR_MSTIM_MSB _u(5)
#define SSI_IMR_MSTIM_LSB _u(5)
#define SSI_IMR_MSTIM_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : SSI_IMR_RXFIM
// Description : Receive FIFO full interrupt mask
#define SSI_IMR_RXFIM_RESET _u(0x0)
#define SSI_IMR_RXFIM_BITS _u(0x00000010)
#define SSI_IMR_RXFIM_MSB _u(4)
#define SSI_IMR_RXFIM_LSB _u(4)
#define SSI_IMR_RXFIM_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : SSI_IMR_RXOIM
// Description : Receive FIFO overflow interrupt mask
#define SSI_IMR_RXOIM_RESET _u(0x0)
#define SSI_IMR_RXOIM_BITS _u(0x00000008)
#define SSI_IMR_RXOIM_MSB _u(3)
#define SSI_IMR_RXOIM_LSB _u(3)
#define SSI_IMR_RXOIM_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : SSI_IMR_RXUIM
// Description : Receive FIFO underflow interrupt mask
#define SSI_IMR_RXUIM_RESET _u(0x0)
#define SSI_IMR_RXUIM_BITS _u(0x00000004)
#define SSI_IMR_RXUIM_MSB _u(2)
#define SSI_IMR_RXUIM_LSB _u(2)
#define SSI_IMR_RXUIM_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : SSI_IMR_TXOIM
// Description : Transmit FIFO overflow interrupt mask
#define SSI_IMR_TXOIM_RESET _u(0x0)
#define SSI_IMR_TXOIM_BITS _u(0x00000002)
#define SSI_IMR_TXOIM_MSB _u(1)
#define SSI_IMR_TXOIM_LSB _u(1)
#define SSI_IMR_TXOIM_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : SSI_IMR_TXEIM
// Description : Transmit FIFO empty interrupt mask
#define SSI_IMR_TXEIM_RESET _u(0x0)
#define SSI_IMR_TXEIM_BITS _u(0x00000001)
#define SSI_IMR_TXEIM_MSB _u(0)
#define SSI_IMR_TXEIM_LSB _u(0)
#define SSI_IMR_TXEIM_ACCESS "RW"
// =============================================================================
// Register : SSI_ISR
// Description : Interrupt status
#define SSI_ISR_OFFSET _u(0x00000030)
#define SSI_ISR_BITS _u(0x0000003f)
#define SSI_ISR_RESET _u(0x00000000)
// -----------------------------------------------------------------------------
// Field : SSI_ISR_MSTIS
// Description : Multi-master contention interrupt status
#define SSI_ISR_MSTIS_RESET _u(0x0)
#define SSI_ISR_MSTIS_BITS _u(0x00000020)
#define SSI_ISR_MSTIS_MSB _u(5)
#define SSI_ISR_MSTIS_LSB _u(5)
#define SSI_ISR_MSTIS_ACCESS "RO"
// -----------------------------------------------------------------------------
// Field : SSI_ISR_RXFIS
// Description : Receive FIFO full interrupt status
#define SSI_ISR_RXFIS_RESET _u(0x0)
#define SSI_ISR_RXFIS_BITS _u(0x00000010)
#define SSI_ISR_RXFIS_MSB _u(4)
#define SSI_ISR_RXFIS_LSB _u(4)
#define SSI_ISR_RXFIS_ACCESS "RO"
// -----------------------------------------------------------------------------
// Field : SSI_ISR_RXOIS
// Description : Receive FIFO overflow interrupt status
#define SSI_ISR_RXOIS_RESET _u(0x0)
#define SSI_ISR_RXOIS_BITS _u(0x00000008)
#define SSI_ISR_RXOIS_MSB _u(3)
#define SSI_ISR_RXOIS_LSB _u(3)
#define SSI_ISR_RXOIS_ACCESS "RO"
// -----------------------------------------------------------------------------
// Field : SSI_ISR_RXUIS
// Description : Receive FIFO underflow interrupt status
#define SSI_ISR_RXUIS_RESET _u(0x0)
#define SSI_ISR_RXUIS_BITS _u(0x00000004)
#define SSI_ISR_RXUIS_MSB _u(2)
#define SSI_ISR_RXUIS_LSB _u(2)
#define SSI_ISR_RXUIS_ACCESS "RO"
// -----------------------------------------------------------------------------
// Field : SSI_ISR_TXOIS
// Description : Transmit FIFO overflow interrupt status
#define SSI_ISR_TXOIS_RESET _u(0x0)
#define SSI_ISR_TXOIS_BITS _u(0x00000002)
#define SSI_ISR_TXOIS_MSB _u(1)
#define SSI_ISR_TXOIS_LSB _u(1)
#define SSI_ISR_TXOIS_ACCESS "RO"
// -----------------------------------------------------------------------------
// Field : SSI_ISR_TXEIS
// Description : Transmit FIFO empty interrupt status
#define SSI_ISR_TXEIS_RESET _u(0x0)
#define SSI_ISR_TXEIS_BITS _u(0x00000001)
#define SSI_ISR_TXEIS_MSB _u(0)
#define SSI_ISR_TXEIS_LSB _u(0)
#define SSI_ISR_TXEIS_ACCESS "RO"
// =============================================================================
// Register : SSI_RISR
// Description : Raw interrupt status
#define SSI_RISR_OFFSET _u(0x00000034)
#define SSI_RISR_BITS _u(0x0000003f)
#define SSI_RISR_RESET _u(0x00000000)
// -----------------------------------------------------------------------------
// Field : SSI_RISR_MSTIR
// Description : Multi-master contention raw interrupt status
#define SSI_RISR_MSTIR_RESET _u(0x0)
#define SSI_RISR_MSTIR_BITS _u(0x00000020)
#define SSI_RISR_MSTIR_MSB _u(5)
#define SSI_RISR_MSTIR_LSB _u(5)
#define SSI_RISR_MSTIR_ACCESS "RO"
// -----------------------------------------------------------------------------
// Field : SSI_RISR_RXFIR
// Description : Receive FIFO full raw interrupt status
#define SSI_RISR_RXFIR_RESET _u(0x0)
#define SSI_RISR_RXFIR_BITS _u(0x00000010)
#define SSI_RISR_RXFIR_MSB _u(4)
#define SSI_RISR_RXFIR_LSB _u(4)
#define SSI_RISR_RXFIR_ACCESS "RO"
// -----------------------------------------------------------------------------
// Field : SSI_RISR_RXOIR
// Description : Receive FIFO overflow raw interrupt status
#define SSI_RISR_RXOIR_RESET _u(0x0)
#define SSI_RISR_RXOIR_BITS _u(0x00000008)
#define SSI_RISR_RXOIR_MSB _u(3)
#define SSI_RISR_RXOIR_LSB _u(3)
#define SSI_RISR_RXOIR_ACCESS "RO"
// -----------------------------------------------------------------------------
// Field : SSI_RISR_RXUIR
// Description : Receive FIFO underflow raw interrupt status
#define SSI_RISR_RXUIR_RESET _u(0x0)
#define SSI_RISR_RXUIR_BITS _u(0x00000004)
#define SSI_RISR_RXUIR_MSB _u(2)
#define SSI_RISR_RXUIR_LSB _u(2)
#define SSI_RISR_RXUIR_ACCESS "RO"
// -----------------------------------------------------------------------------
// Field : SSI_RISR_TXOIR
// Description : Transmit FIFO overflow raw interrupt status
#define SSI_RISR_TXOIR_RESET _u(0x0)
#define SSI_RISR_TXOIR_BITS _u(0x00000002)
#define SSI_RISR_TXOIR_MSB _u(1)
#define SSI_RISR_TXOIR_LSB _u(1)
#define SSI_RISR_TXOIR_ACCESS "RO"
// -----------------------------------------------------------------------------
// Field : SSI_RISR_TXEIR
// Description : Transmit FIFO empty raw interrupt status
#define SSI_RISR_TXEIR_RESET _u(0x0)
#define SSI_RISR_TXEIR_BITS _u(0x00000001)
#define SSI_RISR_TXEIR_MSB _u(0)
#define SSI_RISR_TXEIR_LSB _u(0)
#define SSI_RISR_TXEIR_ACCESS "RO"
// =============================================================================
// Register : SSI_TXOICR
// Description : TX FIFO overflow interrupt clear
// Clear-on-read transmit FIFO overflow interrupt
#define SSI_TXOICR_OFFSET _u(0x00000038)
#define SSI_TXOICR_BITS _u(0x00000001)
#define SSI_TXOICR_RESET _u(0x00000000)
#define SSI_TXOICR_MSB _u(0)
#define SSI_TXOICR_LSB _u(0)
#define SSI_TXOICR_ACCESS "RO"
// =============================================================================
// Register : SSI_RXOICR
// Description : RX FIFO overflow interrupt clear
// Clear-on-read receive FIFO overflow interrupt
#define SSI_RXOICR_OFFSET _u(0x0000003c)
#define SSI_RXOICR_BITS _u(0x00000001)
#define SSI_RXOICR_RESET _u(0x00000000)
#define SSI_RXOICR_MSB _u(0)
#define SSI_RXOICR_LSB _u(0)
#define SSI_RXOICR_ACCESS "RO"
// =============================================================================
// Register : SSI_RXUICR
// Description : RX FIFO underflow interrupt clear
// Clear-on-read receive FIFO underflow interrupt
#define SSI_RXUICR_OFFSET _u(0x00000040)
#define SSI_RXUICR_BITS _u(0x00000001)
#define SSI_RXUICR_RESET _u(0x00000000)
#define SSI_RXUICR_MSB _u(0)
#define SSI_RXUICR_LSB _u(0)
#define SSI_RXUICR_ACCESS "RO"
// =============================================================================
// Register : SSI_MSTICR
// Description : Multi-master interrupt clear
// Clear-on-read multi-master contention interrupt
#define SSI_MSTICR_OFFSET _u(0x00000044)
#define SSI_MSTICR_BITS _u(0x00000001)
#define SSI_MSTICR_RESET _u(0x00000000)
#define SSI_MSTICR_MSB _u(0)
#define SSI_MSTICR_LSB _u(0)
#define SSI_MSTICR_ACCESS "RO"
// =============================================================================
// Register : SSI_ICR
// Description : Interrupt clear
// Clear-on-read all active interrupts
#define SSI_ICR_OFFSET _u(0x00000048)
#define SSI_ICR_BITS _u(0x00000001)
#define SSI_ICR_RESET _u(0x00000000)
#define SSI_ICR_MSB _u(0)
#define SSI_ICR_LSB _u(0)
#define SSI_ICR_ACCESS "RO"
// =============================================================================
// Register : SSI_DMACR
// Description : DMA control
#define SSI_DMACR_OFFSET _u(0x0000004c)
#define SSI_DMACR_BITS _u(0x00000003)
#define SSI_DMACR_RESET _u(0x00000000)
// -----------------------------------------------------------------------------
// Field : SSI_DMACR_TDMAE
// Description : Transmit DMA enable
#define SSI_DMACR_TDMAE_RESET _u(0x0)
#define SSI_DMACR_TDMAE_BITS _u(0x00000002)
#define SSI_DMACR_TDMAE_MSB _u(1)
#define SSI_DMACR_TDMAE_LSB _u(1)
#define SSI_DMACR_TDMAE_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : SSI_DMACR_RDMAE
// Description : Receive DMA enable
#define SSI_DMACR_RDMAE_RESET _u(0x0)
#define SSI_DMACR_RDMAE_BITS _u(0x00000001)
#define SSI_DMACR_RDMAE_MSB _u(0)
#define SSI_DMACR_RDMAE_LSB _u(0)
#define SSI_DMACR_RDMAE_ACCESS "RW"
// =============================================================================
// Register : SSI_DMATDLR
// Description : DMA TX data level
#define SSI_DMATDLR_OFFSET _u(0x00000050)
#define SSI_DMATDLR_BITS _u(0x000000ff)
#define SSI_DMATDLR_RESET _u(0x00000000)
// -----------------------------------------------------------------------------
// Field : SSI_DMATDLR_DMATDL
// Description : Transmit data watermark level
#define SSI_DMATDLR_DMATDL_RESET _u(0x00)
#define SSI_DMATDLR_DMATDL_BITS _u(0x000000ff)
#define SSI_DMATDLR_DMATDL_MSB _u(7)
#define SSI_DMATDLR_DMATDL_LSB _u(0)
#define SSI_DMATDLR_DMATDL_ACCESS "RW"
// =============================================================================
// Register : SSI_DMARDLR
// Description : DMA RX data level
#define SSI_DMARDLR_OFFSET _u(0x00000054)
#define SSI_DMARDLR_BITS _u(0x000000ff)
#define SSI_DMARDLR_RESET _u(0x00000000)
// -----------------------------------------------------------------------------
// Field : SSI_DMARDLR_DMARDL
// Description : Receive data watermark level (DMARDLR+1)
#define SSI_DMARDLR_DMARDL_RESET _u(0x00)
#define SSI_DMARDLR_DMARDL_BITS _u(0x000000ff)
#define SSI_DMARDLR_DMARDL_MSB _u(7)
#define SSI_DMARDLR_DMARDL_LSB _u(0)
#define SSI_DMARDLR_DMARDL_ACCESS "RW"
// =============================================================================
// Register : SSI_IDR
// Description : Identification register
#define SSI_IDR_OFFSET _u(0x00000058)
#define SSI_IDR_BITS _u(0xffffffff)
#define SSI_IDR_RESET _u(0x51535049)
// -----------------------------------------------------------------------------
// Field : SSI_IDR_IDCODE
// Description : Peripheral dentification code
#define SSI_IDR_IDCODE_RESET _u(0x51535049)
#define SSI_IDR_IDCODE_BITS _u(0xffffffff)
#define SSI_IDR_IDCODE_MSB _u(31)
#define SSI_IDR_IDCODE_LSB _u(0)
#define SSI_IDR_IDCODE_ACCESS "RO"
// =============================================================================
// Register : SSI_SSI_VERSION_ID
// Description : Version ID
#define SSI_SSI_VERSION_ID_OFFSET _u(0x0000005c)
#define SSI_SSI_VERSION_ID_BITS _u(0xffffffff)
#define SSI_SSI_VERSION_ID_RESET _u(0x3430312a)
// -----------------------------------------------------------------------------
// Field : SSI_SSI_VERSION_ID_SSI_COMP_VERSION
// Description : SNPS component version (format X.YY)
#define SSI_SSI_VERSION_ID_SSI_COMP_VERSION_RESET _u(0x3430312a)
#define SSI_SSI_VERSION_ID_SSI_COMP_VERSION_BITS _u(0xffffffff)
#define SSI_SSI_VERSION_ID_SSI_COMP_VERSION_MSB _u(31)
#define SSI_SSI_VERSION_ID_SSI_COMP_VERSION_LSB _u(0)
#define SSI_SSI_VERSION_ID_SSI_COMP_VERSION_ACCESS "RO"
// =============================================================================
// Register : SSI_DR0
// Description : Data Register 0 (of 36)
#define SSI_DR0_OFFSET _u(0x00000060)
#define SSI_DR0_BITS _u(0xffffffff)
#define SSI_DR0_RESET _u(0x00000000)
// -----------------------------------------------------------------------------
// Field : SSI_DR0_DR
// Description : First data register of 36
#define SSI_DR0_DR_RESET _u(0x00000000)
#define SSI_DR0_DR_BITS _u(0xffffffff)
#define SSI_DR0_DR_MSB _u(31)
#define SSI_DR0_DR_LSB _u(0)
#define SSI_DR0_DR_ACCESS "RW"
// =============================================================================
// Register : SSI_RX_SAMPLE_DLY
// Description : RX sample delay
#define SSI_RX_SAMPLE_DLY_OFFSET _u(0x000000f0)
#define SSI_RX_SAMPLE_DLY_BITS _u(0x000000ff)
#define SSI_RX_SAMPLE_DLY_RESET _u(0x00000000)
// -----------------------------------------------------------------------------
// Field : SSI_RX_SAMPLE_DLY_RSD
// Description : RXD sample delay (in SCLK cycles)
#define SSI_RX_SAMPLE_DLY_RSD_RESET _u(0x00)
#define SSI_RX_SAMPLE_DLY_RSD_BITS _u(0x000000ff)
#define SSI_RX_SAMPLE_DLY_RSD_MSB _u(7)
#define SSI_RX_SAMPLE_DLY_RSD_LSB _u(0)
#define SSI_RX_SAMPLE_DLY_RSD_ACCESS "RW"
// =============================================================================
// Register : SSI_SPI_CTRLR0
// Description : SPI control
#define SSI_SPI_CTRLR0_OFFSET _u(0x000000f4)
#define SSI_SPI_CTRLR0_BITS _u(0xff07fb3f)
#define SSI_SPI_CTRLR0_RESET _u(0x03000000)
// -----------------------------------------------------------------------------
// Field : SSI_SPI_CTRLR0_XIP_CMD
// Description : SPI Command to send in XIP mode (INST_L = 8-bit) or to append
// to Address (INST_L = 0-bit)
#define SSI_SPI_CTRLR0_XIP_CMD_RESET _u(0x03)
#define SSI_SPI_CTRLR0_XIP_CMD_BITS _u(0xff000000)
#define SSI_SPI_CTRLR0_XIP_CMD_MSB _u(31)
#define SSI_SPI_CTRLR0_XIP_CMD_LSB _u(24)
#define SSI_SPI_CTRLR0_XIP_CMD_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : SSI_SPI_CTRLR0_SPI_RXDS_EN
// Description : Read data strobe enable
#define SSI_SPI_CTRLR0_SPI_RXDS_EN_RESET _u(0x0)
#define SSI_SPI_CTRLR0_SPI_RXDS_EN_BITS _u(0x00040000)
#define SSI_SPI_CTRLR0_SPI_RXDS_EN_MSB _u(18)
#define SSI_SPI_CTRLR0_SPI_RXDS_EN_LSB _u(18)
#define SSI_SPI_CTRLR0_SPI_RXDS_EN_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : SSI_SPI_CTRLR0_INST_DDR_EN
// Description : Instruction DDR transfer enable
#define SSI_SPI_CTRLR0_INST_DDR_EN_RESET _u(0x0)
#define SSI_SPI_CTRLR0_INST_DDR_EN_BITS _u(0x00020000)
#define SSI_SPI_CTRLR0_INST_DDR_EN_MSB _u(17)
#define SSI_SPI_CTRLR0_INST_DDR_EN_LSB _u(17)
#define SSI_SPI_CTRLR0_INST_DDR_EN_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : SSI_SPI_CTRLR0_SPI_DDR_EN
// Description : SPI DDR transfer enable
#define SSI_SPI_CTRLR0_SPI_DDR_EN_RESET _u(0x0)
#define SSI_SPI_CTRLR0_SPI_DDR_EN_BITS _u(0x00010000)
#define SSI_SPI_CTRLR0_SPI_DDR_EN_MSB _u(16)
#define SSI_SPI_CTRLR0_SPI_DDR_EN_LSB _u(16)
#define SSI_SPI_CTRLR0_SPI_DDR_EN_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : SSI_SPI_CTRLR0_WAIT_CYCLES
// Description : Wait cycles between control frame transmit and data reception
// (in SCLK cycles)
#define SSI_SPI_CTRLR0_WAIT_CYCLES_RESET _u(0x00)
#define SSI_SPI_CTRLR0_WAIT_CYCLES_BITS _u(0x0000f800)
#define SSI_SPI_CTRLR0_WAIT_CYCLES_MSB _u(15)
#define SSI_SPI_CTRLR0_WAIT_CYCLES_LSB _u(11)
#define SSI_SPI_CTRLR0_WAIT_CYCLES_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : SSI_SPI_CTRLR0_INST_L
// Description : Instruction length (0/4/8/16b)
// 0x0 -> No instruction
// 0x1 -> 4-bit instruction
// 0x2 -> 8-bit instruction
// 0x3 -> 16-bit instruction
#define SSI_SPI_CTRLR0_INST_L_RESET _u(0x0)
#define SSI_SPI_CTRLR0_INST_L_BITS _u(0x00000300)
#define SSI_SPI_CTRLR0_INST_L_MSB _u(9)
#define SSI_SPI_CTRLR0_INST_L_LSB _u(8)
#define SSI_SPI_CTRLR0_INST_L_ACCESS "RW"
#define SSI_SPI_CTRLR0_INST_L_VALUE_NONE _u(0x0)
#define SSI_SPI_CTRLR0_INST_L_VALUE_4B _u(0x1)
#define SSI_SPI_CTRLR0_INST_L_VALUE_8B _u(0x2)
#define SSI_SPI_CTRLR0_INST_L_VALUE_16B _u(0x3)
// -----------------------------------------------------------------------------
// Field : SSI_SPI_CTRLR0_ADDR_L
// Description : Address length (0b-60b in 4b increments)
#define SSI_SPI_CTRLR0_ADDR_L_RESET _u(0x0)
#define SSI_SPI_CTRLR0_ADDR_L_BITS _u(0x0000003c)
#define SSI_SPI_CTRLR0_ADDR_L_MSB _u(5)
#define SSI_SPI_CTRLR0_ADDR_L_LSB _u(2)
#define SSI_SPI_CTRLR0_ADDR_L_ACCESS "RW"
// -----------------------------------------------------------------------------
// Field : SSI_SPI_CTRLR0_TRANS_TYPE
// Description : Address and instruction transfer format
// 0x0 -> Command and address both in standard SPI frame format
// 0x1 -> Command in standard SPI format, address in format
// specified by FRF
// 0x2 -> Command and address both in format specified by FRF
// (e.g. Dual-SPI)
#define SSI_SPI_CTRLR0_TRANS_TYPE_RESET _u(0x0)
#define SSI_SPI_CTRLR0_TRANS_TYPE_BITS _u(0x00000003)
#define SSI_SPI_CTRLR0_TRANS_TYPE_MSB _u(1)
#define SSI_SPI_CTRLR0_TRANS_TYPE_LSB _u(0)
#define SSI_SPI_CTRLR0_TRANS_TYPE_ACCESS "RW"
#define SSI_SPI_CTRLR0_TRANS_TYPE_VALUE_1C1A _u(0x0)
#define SSI_SPI_CTRLR0_TRANS_TYPE_VALUE_1C2A _u(0x1)
#define SSI_SPI_CTRLR0_TRANS_TYPE_VALUE_2C2A _u(0x2)
// =============================================================================
// Register : SSI_TXD_DRIVE_EDGE
// Description : TX drive edge
#define SSI_TXD_DRIVE_EDGE_OFFSET _u(0x000000f8)
#define SSI_TXD_DRIVE_EDGE_BITS _u(0x000000ff)
#define SSI_TXD_DRIVE_EDGE_RESET _u(0x00000000)
// -----------------------------------------------------------------------------
// Field : SSI_TXD_DRIVE_EDGE_TDE
// Description : TXD drive edge
#define SSI_TXD_DRIVE_EDGE_TDE_RESET _u(0x00)
#define SSI_TXD_DRIVE_EDGE_TDE_BITS _u(0x000000ff)
#define SSI_TXD_DRIVE_EDGE_TDE_MSB _u(7)
#define SSI_TXD_DRIVE_EDGE_TDE_LSB _u(0)
#define SSI_TXD_DRIVE_EDGE_TDE_ACCESS "RW"
// =============================================================================
#endif // HARDWARE_REGS_SSI_DEFINED

@ -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…
Cancel
Save