Skip to content

Commit be904b4

Browse files
committed
Move flash example out of rp2040_only and refactor
1 parent 457c4b0 commit be904b4

6 files changed

Lines changed: 52 additions & 73 deletions

File tree

examples/raspberrypi/rp2xxx/build.zig

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ pub fn build(b: *std.Build) void {
1717
const specific_examples: []const Example = &.{
1818
// RaspberryPi Boards:
1919
.{ .target = raspberrypi.pico, .name = "pico_board_blinky", .file = "src/board_blinky.zig" },
20-
.{ .target = raspberrypi.pico, .name = "pico_flash-program", .file = "src/rp2040_only/flash_program.zig" },
2120
.{ .target = raspberrypi.pico, .name = "pico_random", .file = "src/rp2040_only/random.zig" },
2221
.{ .target = raspberrypi.pico, .name = "pico_rtc", .file = "src/rp2040_only/rtc.zig" },
2322
.{ .target = raspberrypi.pico, .name = "pico_multicore", .file = "src/blinky_core1.zig" },
@@ -35,7 +34,6 @@ pub fn build(b: *std.Build) void {
3534
.{ .target = raspberrypi.pico2_arm, .name = "pico2_arm_freertos-multitask-demo", .file = "src/freertos/multitask_demo.zig" },
3635

3736
.{ .target = raspberrypi.pico_flashless, .name = "pico_flashless_blinky", .file = "src/blinky.zig" },
38-
.{ .target = raspberrypi.pico_flashless, .name = "pico_flashless_flash-program", .file = "src/rp2040_only/flash_program.zig" },
3937

4038
.{ .target = raspberrypi.pico2_arm_flashless, .name = "pico2_arm_flashless_blinky", .file = "src/blinky.zig" },
4139
.{ .target = raspberrypi.pico2_riscv_flashless, .name = "pico2_riscv_flashless_blinky", .file = "src/blinky.zig" },
@@ -108,6 +106,7 @@ pub fn build(b: *std.Build) void {
108106
.{ .name = "net-tcp_client", .file = "src/net/tcp_client.zig" },
109107
.{ .name = "net-tcp_server", .file = "src/net/tcp_server.zig" },
110108
.{ .name = "board-id", .file = "src/board_id.zig" },
109+
.{ .name = "flash-program", .file = "src/flash_program.zig" },
111110
};
112111

113112
var available_examples: std.array_list.Managed(Example) = .init(b.allocator);

examples/raspberrypi/rp2xxx/src/rp2040_only/flash_program.zig renamed to examples/raspberrypi/rp2xxx/src/flash_program.zig

File renamed without changes.

port/raspberrypi/rp2xxx/build.zig

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,8 +202,6 @@ pub fn init(dep: *std.Build.Dependency) Self {
202202
.name = "RaspberryPi Pico (ram image)",
203203
.url = "https://www.raspberrypi.com/products/raspberry-pi-pico/",
204204
.root_source_file = b.path("src/boards/raspberry_pi_pico.zig"),
205-
// needed by the flash hal
206-
.imports = rp2040_bootrom_imports,
207205
},
208206
}),
209207
.pico2_arm = chip_rp2350_arm.derive(.{

port/raspberrypi/rp2xxx/src/boards/raspberry_pi_pico.zig

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,13 @@ const microzig = @import("microzig");
44
const hal = microzig.hal;
55
const pins = hal.pins;
66

7-
pub const bootrom = @import("shared/rp2040_bootrom.zig");
8-
9-
comptime {
10-
_ = bootrom;
11-
}
12-
137
pub const pin_config = pins.GlobalConfiguration{
148
.GPIO25 = .{
159
.name = "led",
1610
.function = .SIO,
1711
},
1812
};
13+
14+
comptime {
15+
_ = @import("shared/rp2040_bootrom.zig");
16+
}

port/raspberrypi/rp2xxx/src/boards/shared/rp2040_bootrom.zig

Lines changed: 29 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,40 +4,41 @@ const chip = microzig.hal.compatibility.chip;
44

55
comptime {
66
if (chip == .RP2040 and !microzig.config.ram_image) {
7-
_ = bootloader_data;
7+
_ = BootromData.bootloader_data;
88
}
99
}
1010

11-
/// Raw stage2 bootrom
12-
pub const stage2_rom: []align(2) const u8 = @embedFile("bootloader");
11+
const BootromData = struct {
12+
fn prepare_boot_sector(comptime stage2_rom: []const u8) [256]u8 {
13+
@setEvalBranchQuota(10_000);
1314

14-
pub export const bootloader_data: [256]u8 linksection(".boot2") = blk: {
15-
@setEvalBranchQuota(10_000);
15+
var bootrom: [256]u8 = @splat(0xFF);
16+
@memcpy(bootrom[0..stage2_rom.len], stage2_rom);
1617

17-
var bootrom: [256]u8 = @splat(0xFF);
18-
@memcpy(bootrom[0..stage2_rom.len], stage2_rom);
18+
// 2.8.1.3.1. Checksum
19+
// The last four bytes of the image loaded from flash (which we hope is a valid flash second stage) are a CRC32 checksum
20+
// of the first 252 bytes. The parameters of the checksum are:
21+
// • Polynomial: 0x04c11db7
22+
// • Input reflection: no
23+
// • Output reflection: no
24+
// • Initial value: 0xffffffff
25+
// • Final XOR: 0x00000000
26+
// • Checksum value appears as little-endian integer at end of image
27+
// The Bootrom makes 128 attempts of approximately 4ms each for a total of approximately 0.5 seconds before giving up
28+
// and dropping into USB code to load and checksum the second stage with varying SPI parameters. If it sees a checksum
29+
// pass it will immediately jump into the 252-byte payload which contains the flash second stage.
30+
const Hash = std.hash.crc.Crc(u32, .{
31+
.polynomial = 0x04c11db7,
32+
.initial = 0xffffffff,
33+
.reflect_input = false,
34+
.reflect_output = false,
35+
.xor_output = 0x00000000,
36+
});
1937

20-
// 2.8.1.3.1. Checksum
21-
// The last four bytes of the image loaded from flash (which we hope is a valid flash second stage) are a CRC32 checksum
22-
// of the first 252 bytes. The parameters of the checksum are:
23-
// • Polynomial: 0x04c11db7
24-
// • Input reflection: no
25-
// • Output reflection: no
26-
// • Initial value: 0xffffffff
27-
// • Final XOR: 0x00000000
28-
// • Checksum value appears as little-endian integer at end of image
29-
// The Bootrom makes 128 attempts of approximately 4ms each for a total of approximately 0.5 seconds before giving up
30-
// and dropping into USB code to load and checksum the second stage with varying SPI parameters. If it sees a checksum
31-
// pass it will immediately jump into the 252-byte payload which contains the flash second stage.
32-
const Hash = std.hash.crc.Crc(u32, .{
33-
.polynomial = 0x04c11db7,
34-
.initial = 0xffffffff,
35-
.reflect_input = false,
36-
.reflect_output = false,
37-
.xor_output = 0x00000000,
38-
});
38+
std.mem.writeInt(u32, bootrom[252..256], Hash.hash(bootrom[0..252]), .little);
3939

40-
std.mem.writeInt(u32, bootrom[252..256], Hash.hash(bootrom[0..252]), .little);
40+
return bootrom;
41+
}
4142

42-
break :blk bootrom;
43+
export const bootloader_data: [256]u8 linksection(".boot2") = prepare_boot_sector(@embedFile("bootloader"));
4344
};

port/raspberrypi/rp2xxx/src/hal/flash.zig

Lines changed: 18 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -15,38 +15,23 @@ pub const PAGE_SIZE = 256;
1515
pub const SECTOR_SIZE = 4096;
1616
pub const BLOCK_SIZE = 65536;
1717

18-
/// Bus reads to a 16MB memory window start at this address
18+
/// Bus reads to a 16MB memory window start at this address.
1919
pub const XIP_BASE = 0x10000000;
2020

21-
/// After the bootrom enters the user application, it contains also a copy of
22-
/// the flash XIP setup function.
21+
/// After the bootrom enters the user application, a copy of the flash XIP
22+
/// setup function is found here on RP2350.
2323
pub const BOOTRAM_BASE = 0x400e0000;
2424

25-
/// Flash code related to the second stage boot loader
26-
pub const boot2 = if (!microzig.config.ram_image) struct {
27-
/// Size of the second stage bootloader in words
25+
/// Infrastructure for reentering XIP mode after exiting for programming.
26+
pub const boot2 = if (!microzig.config.ram_image and compatibility.arch == .arm) struct {
2827
const BOOT2_SIZE_WORDS = 64;
2928

30-
/// Buffer for the second stage bootloader
31-
///
32-
/// The only job of the second stage bootloader is to configure the SSI and
33-
/// the external flash for the best possible execute-in-place (XIP)
34-
/// performance. Until the SSI is correctly configured for the attached
35-
/// flash device, it's not possible to access flash via the XIP address
36-
/// window, i.e., we have to copy the bootloader into sram before calling
37-
/// `rom.flash_exit_xip`. This is required if we want to erase and/or write
38-
/// to flash.
39-
///
40-
/// At the end we can then just make a subroutine call to copyout, to
41-
/// configure the SSI and flash. The second stage bootloader will return to
42-
/// the calling function if a return address is provided in `lr`.
4329
var copyout: [BOOT2_SIZE_WORDS]u32 = undefined;
4430
var copyout_valid: bool = false;
4531

46-
/// Copy the 2nd stage bootloader into memory
47-
///
48-
/// This is required by `_range_erase` and `_range_program` so we can later
49-
/// setup XIP via the second stage bootloader.
32+
/// Copies the XIP setup function into RAM:
33+
/// - On RP2040 this *is* the second stage bootloader
34+
/// - On RP2350 it is found at BOOTRAM_BASE.
5035
pub export fn flash_init() linksection(".ram_text") void {
5136
if (copyout_valid) return;
5237
const bootloader = @as([*]u32, @ptrFromInt(switch (compatibility.chip) {
@@ -61,25 +46,23 @@ pub const boot2 = if (!microzig.config.ram_image) struct {
6146
copyout_valid = true;
6247
}
6348

64-
/// Configure the SSI and the external flash for XIP by calling the second
65-
/// stage bootloader that was copied out to `copyout`.
49+
/// Configure the SSI and the external flash for XIP using the XIP setup
50+
/// function that was copied out to `copyout`.
6651
pub export fn flash_enable_xip() linksection(".ram_text") void {
67-
const f: *const fn () callconv(.c) void = @ptrCast(&copyout);
68-
f();
52+
53+
// Calling boot2 as a function works because it accepts a return vector in
54+
// LR (and doesn't trash r4-r7). Bootrom passes NULL in LR, instructing
55+
// boot2 to enter flash vector table's reset handler.
56+
@as(*const fn () callconv(.c) void, @ptrFromInt(@intFromPtr(&copyout) + 1))();
6957
}
7058
} else struct {
7159
// no op
7260
pub inline fn flash_init() linksection(".ram_text") void {}
7361

74-
/// Configure the SSI and the external flash for XIP by calling the second
75-
/// stage bootloader embedded into RAM.
62+
// Fallback. This is a very slow XIP configuration, but is very widely
63+
// supported.
7664
pub inline fn flash_enable_xip() linksection(".ram_text") void {
77-
if (compatibility.chip == .RP2040 and @hasDecl(microzig.board, "bootrom")) {
78-
const f: *const fn () callconv(.c) void = @ptrCast(microzig.board.bootrom.stage2_rom.ptr);
79-
f();
80-
} else {
81-
rom.flash_enter_cmd_xip();
82-
}
65+
rom.flash_enter_cmd_xip();
8366
}
8467
};
8568

0 commit comments

Comments
 (0)