Skip to content

Commit 709355b

Browse files
authored
treewide: Add SPI write support and flashing utility (#45)
* hw/bootrom: Add `ebreak` on return, some cleanup * sw: Add SD and NOR flash write support and flashing utility * target/xilinx: Add QSPI and NOR flash boot support on Genesys2 * sw/boot: Clean up VCU128 NOR flash device tree entry * util: Increase OpenOCD adapter speed to 8 kHz * sw: Fix various `-Wpedantic` warnings, some cleanup * nonfree: Integrate new internal CI setup * docs: Document changes
1 parent 44fb98a commit 709355b

30 files changed

Lines changed: 2220 additions & 1852 deletions

cheshire.mk

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ chs-clean-deps:
6161
######################
6262

6363
CHS_NONFREE_REMOTE ?= git@iis-git.ee.ethz.ch:pulp-restricted/cheshire-nonfree.git
64-
CHS_NONFREE_COMMIT ?= fd3526f
64+
CHS_NONFREE_COMMIT ?= 99e58ec
6565

6666
CHS_PHONY += chs-nonfree-init
6767
chs-nonfree-init:

docs/tg/xilinx.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ The second command only ensures correctness of the partition layout; it moves th
130130

131131
Insert your SD card and reset into boot mode 1. You should see a `Hello World!` UART output.
132132

133-
### Boot from onboard flash (`vcu128` only)
133+
### Boot from onboard flash
134134

135135
Build a GPT disk image for your desired binary as explained above, then flash it to your board's flash. For `helloworld`:
136136

@@ -179,4 +179,5 @@ Flash your image to an SD card or SPI flash as described in the preceding sectio
179179
( P )
180180
( ))))))))))
181181
```
182+
182183
You should then boot through OpenSBI, U-Boot, and Linux until you are dropped into a shell.

docs/um/sw.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ The boot ROM supports four builtin boot modes chosen from by the `boot_mode_i` p
5151
| `0b10` | EEPROM (24FC1025) | I2C |
5252

5353

54+
Should a program invoked by the boot ROM return, the boot ROM will attempt to yield control to an external debugger if present, such as GDB, using the `ebreak` instruction.
55+
5456
#### Passive Preload
5557

5658
The *passive preload* boot mode expects code to be preloaded to an executable location and an entry point to be written to `scratch[1:0]`. After preloading, execution is launched when `scratch[2][0]` is set to 1. Unlike for autonomous boot modes, BMPs can directly be preloaded into DRAM and have no size restriction.
@@ -63,7 +65,6 @@ The JTAG and serial link interfaces can preload programs by directly accessing t
6365
| `0x12` (Write) | 64b address, 64b length | RX `ACK`, TX write data, RX `EOT` |
6466
| `0x13` (Exec) | 64b address | RX `ACK`, execution, RX `ACK`, RX return |
6567

66-
6768
#### Autonomous Boot
6869

6970
The *autonomous* boot modes load a BMP of at most 48 KiB from their boot medium into SPM, then execute it. The boot medium can either be GPT-formatted or contain raw code. If no GPT header is found, raw code execution starts from sector 0 of the boot medium.
@@ -76,7 +77,11 @@ BMPs that run from SPM and fit into the alotted size can be compiled into raw im
7677
make sw/tests/helloworld.(rom|gpt).(bin|memh)
7778
```
7879

79-
The boot ROM is *not* reentrant; when an invoked BMP returns, the system will halt and not reboot.
80+
These images then can be copied onto a bootable disk. For convenience, we also provide a BMP that can flash images preloaded into DRAM to selected devices (`sw/boot/flash.spm.elf`). This BMP can be invoked through OpenOCD using the following script (see BMP and script for details):
81+
82+
```
83+
util/flash_disk.sh <board_or_adapter> <disk_type_idx> <image>
84+
```
8085

8186
### Zero-Stage Loader
8287

hw/bootrom/cheshire_bootrom.S

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,10 +119,11 @@ _boot:
119119
// If main returns, we end up here
120120
.global _exit
121121
_exit:
122-
// Save the return value to scratch register 2 and wait forever
122+
// Save the return value to scratch register 2, try `ebreak`, then wait forever
123123
slli a0, a0, 1
124124
ori a0, a0, 1
125125
la t0, __base_regs
126126
sw a0, 8(t0) // regs.SCRATCH[2]
127+
ebreak
127128
1: wfi
128129
j 1b

hw/bootrom/cheshire_bootrom.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,12 @@
44
//
55
// Nicole Narr <narrn@student.ethz.ch>
66
// Christopher Reinwardt <creinwar@student.ethz.ch>
7-
// Paul Scheffler <paulsc@student.ethz.ch>
7+
// Paul Scheffler <paulsc@iis.ee.ethz.ch>
88

99
#include <stdint.h>
1010
#include "util.h"
1111
#include "params.h"
1212
#include "regs/cheshire.h"
13-
#include "regs/serial_link.h"
1413
#include "spi_host_regs.h"
1514
#include "dif/clint.h"
1615
#include "hal/i2c_24fc1025.h"

hw/bootrom/cheshire_bootrom.sv

Lines changed: 1748 additions & 1748 deletions
Large diffs are not rendered by default.

sw/boot/cheshire.genesys2.dts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,22 @@
77
/include/ "cheshire.dtsi"
88

99
&spi {
10-
boot-with = <0>;
10+
// Choose NOR in "boot-with", as it is only considered if `mmc` probe fails.
11+
// Thus, we boot from MMC (SD) if available and NOR flash otherwise.
12+
boot-with = <1>;
1113
mmc@0 {
1214
compatible = "mmc-spi-slot";
1315
reg = <0>; // CS
1416
spi-max-frequency = <25000000>;
1517
voltage-ranges = <3300 3300>;
1618
disable-wp;
1719
};
20+
nor@1 {
21+
compatible = "s25fl256s1", "jedec,spi-nor";
22+
reg = <1>; // CS
23+
spi-max-frequency = <25000000>;
24+
disable-wp;
25+
};
1826
};
1927

2028
&soc {

sw/boot/cheshire.vcu128.dts

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,10 @@
99
&spi {
1010
boot-with = <1>;
1111
nor@1 {
12-
#address-cells = <0x1>;
13-
#size-cells = <0x1>;
1412
// Note : u-boot does not find mt25qu02g
1513
compatible = "mt25qu02g", "jedec,spi-nor";
1614
reg = <0x1>; // CS
1715
spi-max-frequency = <25000000>;
18-
spi-rx-bus-width = <0x1>;
19-
spi-tx-bus-width = <0x1>;
2016
disable-wp;
21-
partition@0 {
22-
label = "all";
23-
reg = <0x0 0x6000000>; // 96 MB
24-
read-only;
25-
};
2617
};
2718
};

sw/boot/flash.c

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// Copyright 2023 ETH Zurich and University of Bologna.
2+
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3+
// SPDX-License-Identifier: Apache-2.0
4+
//
5+
// Paul Scheffler <paulsc@iis.ee.ethz.ch>
6+
//
7+
// Boot disk flasher for Cheshire; writes a contiguous disk segment to a boot target disk.
8+
// This program can be preloaded and invoked repeatedly to write multiple segments.
9+
10+
#include <stdint.h>
11+
#include "util.h"
12+
#include "params.h"
13+
#include "regs/cheshire.h"
14+
#include "spi_host_regs.h"
15+
#include "dif/clint.h"
16+
#include "hal/i2c_24fc1025.h"
17+
#include "hal/spi_s25fs512s.h"
18+
#include "hal/spi_sdcard.h"
19+
#include "hal/uart_debug.h"
20+
#include "gpt.h"
21+
#include "printf.h"
22+
23+
int flash_spi_sdcard(uint64_t core_freq, uint64_t rtc_freq, void *img_base, uint64_t sector,
24+
uint64_t len) {
25+
// Initialize device handle
26+
spi_sdcard_t device = {
27+
.spi_freq = 24 * 1000 * 1000, // 24MHz (maximum is 25MHz)
28+
.csid = 0,
29+
.csid_dummy = SPI_HOST_PARAM_NUM_C_S - 1 // Last physical CS is designated dummy
30+
};
31+
CHECK_CALL(spi_sdcard_init(&device, core_freq))
32+
// Wait for device to be initialized (1ms, round up extra tick to be sure)
33+
clint_spin_until((1000 * rtc_freq) / (1000 * 1000) + 1);
34+
// Write sectors: we have 512 512B blocks per 256KiB sector, so a 9b left shift
35+
return spi_sdcard_write_blocks(&device, img_base, sector << 9, len << 9, 1);
36+
}
37+
38+
int flash_spi_s25fs512s(uint64_t core_freq, uint64_t rtc_freq, void *img_base, uint64_t sector,
39+
uint64_t len) {
40+
// Initialize device handle
41+
spi_s25fs512s_t device = {
42+
.spi_freq = MIN(40 * 1000 * 1000, core_freq / 4), // Up to quarter core freq or 40MHz
43+
.csid = 1};
44+
CHECK_CALL(spi_s25fs512s_init(&device, core_freq))
45+
// Wait for device to be initialized (t_PU = 300us, round up extra tick to be sure)
46+
clint_spin_until((350 * rtc_freq) / (1000 * 1000) + 1);
47+
// Write sectors of 256 KiB directly
48+
return spi_s25fs512s_single_flash(&device, img_base, sector, len);
49+
}
50+
51+
int flash_i2c_24fc1025(uint64_t core_freq, void *img_base) {
52+
// Initialize device handle
53+
dif_i2c_t i2c;
54+
CHECK_CALL(i2c_24fc1025_init(&i2c, core_freq))
55+
// Write half of a single 256 KiB sector (entire capacity)
56+
return i2c_24fc1025_write(&i2c, img_base, 0, 128 * 1024);
57+
}
58+
59+
int main() {
60+
int ret;
61+
// Read reference frequency and compute core frequency
62+
uint32_t rtc_freq = *reg32(&__base_regs, CHESHIRE_RTC_FREQ_REG_OFFSET);
63+
uint64_t core_freq = clint_get_core_freq(rtc_freq, 2500);
64+
// Get arguments from scratch registers
65+
volatile uint32_t *scratch = reg32(&__base_regs, CHESHIRE_SCRATCH_0_REG_OFFSET);
66+
uint64_t target = scratch[0];
67+
void *img_base = (void *)(uintptr_t)scratch[1];
68+
uint64_t sector = scratch[2];
69+
uint64_t len = scratch[3];
70+
// Flash chosen disk
71+
printf("[FLASH] Write buffer at 0x%x of length %d to target %d, sector %d ... ", img_base, len,
72+
target, sector);
73+
switch (target) {
74+
case 1: {
75+
ret = flash_spi_sdcard(core_freq, rtc_freq, img_base, sector, len);
76+
break;
77+
}
78+
case 2: {
79+
ret = flash_spi_s25fs512s(core_freq, rtc_freq, img_base, sector, len);
80+
break;
81+
}
82+
case 3: {
83+
ret = flash_i2c_24fc1025(core_freq, img_base);
84+
break;
85+
}
86+
default: {
87+
ret = -1;
88+
break;
89+
}
90+
}
91+
if (ret)
92+
printf("ERROR (%d)\r\n", ret);
93+
else
94+
printf("OK\r\n");
95+
return ret;
96+
}

sw/include/dif/dma.h

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,18 @@
99
#include "regs/idma.h"
1010
#include "params.h"
1111

12-
#define DMA_SRC_ADDR(BASE) ((void *)BASE + IDMA_REG64_2D_SRC_ADDR_LOW_REG_OFFSET)
13-
#define DMA_DST_ADDR(BASE) ((void *)BASE + IDMA_REG64_2D_DST_ADDR_LOW_REG_OFFSET)
14-
#define DMA_NUMBYTES_ADDR(BASE) ((void *)BASE + IDMA_REG64_2D_LENGTH_LOW_REG_OFFSET)
15-
#define DMA_CONF_ADDR(BASE) ((void *)BASE + IDMA_REG64_2D_CONF_REG_OFFSET)
16-
#define DMA_STATUS_ADDR(BASE) ((void *)BASE + IDMA_REG64_2D_STATUS_0_REG_OFFSET)
17-
#define DMA_NEXTID_ADDR(BASE) ((void *)BASE + IDMA_REG64_2D_NEXT_ID_0_REG_OFFSET)
18-
#define DMA_DONE_ADDR(BASE) ((void *)BASE + IDMA_REG64_2D_DONE_ID_0_REG_OFFSET)
19-
#define DMA_SRC_STRIDE_ADDR(BASE) ((void *)BASE + IDMA_REG64_2D_SRC_STRIDE_2_LOW_REG_OFFSET)
20-
#define DMA_DST_STRIDE_ADDR(BASE) ((void *)BASE + IDMA_REG64_2D_DST_STRIDE_2_LOW_REG_OFFSET)
21-
#define DMA_NUM_REPS_ADDR(BASE) ((void *)BASE + IDMA_REG64_2D_REPS_2_LOW_REG_OFFSET)
12+
#define DMA_SRC_ADDR(BASE) (void *)((uint8_t *)BASE + IDMA_REG64_2D_SRC_ADDR_LOW_REG_OFFSET)
13+
#define DMA_DST_ADDR(BASE) (void *)((uint8_t *)BASE + IDMA_REG64_2D_DST_ADDR_LOW_REG_OFFSET)
14+
#define DMA_NUMBYTES_ADDR(BASE) (void *)((uint8_t *)BASE + IDMA_REG64_2D_LENGTH_LOW_REG_OFFSET)
15+
#define DMA_CONF_ADDR(BASE) (void *)((uint8_t *)BASE + IDMA_REG64_2D_CONF_REG_OFFSET)
16+
#define DMA_STATUS_ADDR(BASE) (void *)((uint8_t *)BASE + IDMA_REG64_2D_STATUS_0_REG_OFFSET)
17+
#define DMA_NEXTID_ADDR(BASE) (void *)((uint8_t *)BASE + IDMA_REG64_2D_NEXT_ID_0_REG_OFFSET)
18+
#define DMA_DONE_ADDR(BASE) (void *)((uint8_t *)BASE + IDMA_REG64_2D_DONE_ID_0_REG_OFFSET)
19+
#define DMA_SRC_STRIDE_ADDR(BASE) \
20+
(void *)((uint8_t *)BASE + IDMA_REG64_2D_SRC_STRIDE_2_LOW_REG_OFFSET)
21+
#define DMA_DST_STRIDE_ADDR(BASE) \
22+
(void *)((uint8_t *)BASE + IDMA_REG64_2D_DST_STRIDE_2_LOW_REG_OFFSET)
23+
#define DMA_NUM_REPS_ADDR(BASE) (void *)((uint8_t *)BASE + IDMA_REG64_2D_REPS_2_LOW_REG_OFFSET)
2224
#define DMA_CONF_DECOUPLE_AW 0
2325
#define DMA_CONF_DECOUPLE_RW 0
2426

@@ -120,6 +122,6 @@
120122
return *(NAME##_dma_status_ptr()); \
121123
}
122124

123-
X(sys, &__base_dma);
125+
X(sys, &__base_dma)
124126

125127
#undef X

0 commit comments

Comments
 (0)