Skip to content

Commit bc95fc5

Browse files
committed
Documentation improvements. Peer review fixes
1 parent 4377a13 commit bc95fc5

File tree

5 files changed

+151
-16
lines changed

5 files changed

+151
-16
lines changed

docs/Targets.md

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -795,12 +795,43 @@ The PolarFire SoC is a 64-bit RISC-V SoC featuring a five-core CPU cluster (1×
795795
* Low power consumption
796796
* External flash support
797797

798+
### Supported Boot Configurations
799+
800+
Five ready-to-use config templates cover all supported boot mode / storage / memory combinations:
801+
802+
| Configuration | Config File | Boot Mode | Storage | Memory | HSS |
803+
|---------------|-------------|-----------|---------|--------|-----|
804+
| **SDCard** | `polarfire_mpfs250.config` | S-mode (U54 via HSS) | SD Card | DDR | Yes |
805+
| **eMMC** | `polarfire_mpfs250.config` + `DISK_EMMC=1` | S-mode (U54 via HSS) | eMMC | DDR | Yes |
806+
| **QSPI (S-mode)** | `polarfire_mpfs250_qspi.config` | S-mode (U54 via HSS) | MSS or SC QSPI | DDR | Yes |
807+
| **QSPI + L2-LIM** | `polarfire_mpfs250_hss_l2lim.config` | S-mode (U54 via HSS) | SC QSPI | L2-LIM (no DDR) | Yes |
808+
| **M-Mode (no HSS)** | `polarfire_mpfs250_m_qspi.config` | M-mode (E51, no HSS) | SC QSPI | L2 Scratchpad | No |
809+
810+
Key build settings that differ between configurations:
811+
812+
| Setting | SDCard | eMMC | QSPI | L2-LIM | M-Mode |
813+
|---------|--------|------|------|--------|--------|
814+
| `WOLFBOOT_ORIGIN` | `0x80000000` | `0x80000000` | `0x80000000` | `0x08040000` | `0x0A000000` |
815+
| `WOLFBOOT_LOAD_ADDRESS` | `0x8E000000` | `0x8E000000` | `0x8E000000` | `0x08060000` | `0x0A010200` |
816+
| `EXT_FLASH` | 0 | 0 | 1 | 1 | 1 |
817+
| `DISK_SDCARD` | 1 | 0 | 0 | 0 | 0 |
818+
| `DISK_EMMC` | 0 | 1 | 0 | 0 | 0 |
819+
| `MPFS_L2LIM` |||| 1 ||
820+
| `RISCV_MMODE` ||||| 1 |
821+
| Linker script | `mpfs250.ld` | `mpfs250.ld` | `mpfs250.ld` | `mpfs250-hss.ld` | `mpfs250-m.ld` |
822+
| HSS YAML | `mpfs.yaml` | `mpfs.yaml` | `mpfs.yaml` | `mpfs-l2lim.yaml` | N/A |
823+
| `ELF` output | 1 | 1 | 1 | 0 (raw .bin) | 1 |
824+
825+
> **Note:** All configurations require `NO_ASM=1` because the MPFS250 U54/E51 cores lack RISC-V
826+
> crypto extensions (Zknh); wolfBoot uses portable C implementations for all cryptographic operations.
827+
798828
### PolarFire SoC Files
799829

800830
`hal/mpfs250.c` - Hardware abstraction layer (UART, QSPI, SD/eMMC, multi-hart)
801831
`hal/mpfs250.h` - Register definitions and hardware interfaces
802832
`hal/mpfs250.ld` - Linker script for S-mode (HSS-based boot)
803833
`hal/mpfs250-m.ld` - Linker script for M-mode (eNVM + L2 SRAM)
834+
`hal/mpfs250-hss.ld` - Linker script for S-mode (HSS with L2-LIM)
804835
`hal/mpfs.dts` - Device tree source
805836
`hal/mpfs.yaml` - HSS payload generator configuration for use of DDR
806837
`hal/mpfs-l2lim.yaml` - HSS payload generator for the use of L2-LIM
@@ -905,6 +936,63 @@ Notes:
905936
- The MSS QSPI path expects external flash on the MSS QSPI pins; the SC QSPI path is for
906937
fabric-connected flash (design flash) accessed via the System Controller's QSPI instance.
907938
939+
### PolarFire SoC HSS S-Mode with L2-LIM (no DDR)
940+
941+
wolfBoot can run in S-mode via HSS without DDR by targeting the on-chip **L2 Loosely Integrated
942+
Memory (L2-LIM)**. HSS loads wolfBoot from SC QSPI flash into L2-LIM on a U54 application core,
943+
and wolfBoot loads the signed application from SC QSPI into L2-LIM as well. This is useful for
944+
early bring-up or power-constrained scenarios where DDR is not yet initialized.
945+
946+
**Features:**
947+
* S-mode on U54 application core (hart 1), loaded by HSS
948+
* wolfBoot and application both reside in L2-LIM (`0x08000000`, up to 1.5 MB)
949+
* No DDR required
950+
* SC QSPI flash for both wolfBoot payload and signed application image
951+
* Raw binary output (`ELF=0`) required — ELF with debug symbols is too large for L2-LIM
952+
953+
**Relevant files:**
954+
955+
| File | Description |
956+
|------|-------------|
957+
| `config/examples/polarfire_mpfs250_hss_l2lim.config` | HSS S-mode + SC QSPI + L2-LIM |
958+
| `hal/mpfs250-hss.ld` | Linker script for S-mode with L2-LIM |
959+
| `hal/mpfs-l2lim.yaml` | HSS payload generator YAML for L2-LIM load target |
960+
961+
**Build:**
962+
```sh
963+
cp config/examples/polarfire_mpfs250_hss_l2lim.config .config
964+
make clean && make wolfboot.bin
965+
dtc -I dts -O dtb hal/mpfs.dts -o hal/mpfs.dtb
966+
hss-payload-generator -vvv -c ./hal/mpfs-l2lim.yaml wolfboot.bin
967+
```
968+
969+
Flash the HSS payload to the eMMC/SD BIOS partition using HSS `USBDMSC`:
970+
```sh
971+
sudo dd if=wolfboot.bin of=/dev/sdc1 bs=512 && sudo cmp wolfboot.bin /dev/sdc1
972+
```
973+
974+
**Build and sign the test application:**
975+
```sh
976+
make test-app/image_v1_signed.bin
977+
```
978+
979+
**Flash the signed application to QSPI:**
980+
```sh
981+
python3 tools/scripts/mpfs_qspi_prog.py /dev/ttyUSB1 \
982+
test-app/image_v1_signed.bin 0x20000
983+
```
984+
985+
**Notes:**
986+
- `ELF=0` is required: the test-app linker script (`test-app/RISCV64-mpfs250.ld`) places `.init`
987+
(containing `_reset()`) first so the raw binary entry point is at offset 0. The full ELF with
988+
debug symbols exceeds L2-LIM capacity.
989+
- wolfBoot is placed at `0x08040000` (above the HSS L2-LIM resident region) and the application
990+
is loaded at `0x08060000`. The stack resides at the top of the 1.5 MB L2-LIM region.
991+
- HSS must be built and programmed to eNVM separately (see [PolarFire Building Hart Software Services](#polarfire-building-hart-software-services-hss)).
992+
- **LIM instruction fetch caveat:** Ensure `L2_WAY_ENABLE` leaves enough cache ways unallocated
993+
to back the LIM SRAM region. See the M-mode section for a detailed explanation.
994+
- UART output appears on MMUART1 (`/dev/ttyUSB1`), same as other S-mode configurations.
995+
908996
### PolarFire SoC M-Mode (bare-metal eNVM boot)
909997
910998
wolfBoot supports running directly in Machine Mode (M-mode) on PolarFire SoC, replacing the Hart

hal/mpfs250.c

Lines changed: 52 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -902,14 +902,20 @@ int ext_flash_erase(uintptr_t address, int len)
902902
* ============================================================================ */
903903
#if defined(UART_QSPI_PROGRAM) && defined(__WOLFBOOT)
904904

905-
#define QSPI_PROG_CHUNK 256
906-
#define QSPI_PROG_ACK 0x06
905+
#define QSPI_PROG_CHUNK 256
906+
#define QSPI_PROG_ACK 0x06
907+
#define QSPI_RX_TIMEOUT_MS 5000U /* 5 s per byte — aborts if host disappears */
907908

908-
static uint8_t uart_qspi_rx(void)
909+
/* Returns 0-255 on success, -1 on timeout (so the boot path is never deadlocked). */
910+
static int uart_qspi_rx(void)
909911
{
910-
while (!(MMUART_LSR(DEBUG_UART_BASE) & MSS_UART_DR))
911-
;
912-
return MMUART_RBR(DEBUG_UART_BASE);
912+
uint32_t t;
913+
for (t = 0; t < QSPI_RX_TIMEOUT_MS; t++) {
914+
if (MMUART_LSR(DEBUG_UART_BASE) & MSS_UART_DR)
915+
return (int)(uint8_t)MMUART_RBR(DEBUG_UART_BASE);
916+
udelay(1000);
917+
}
918+
return -1; /* timeout */
913919
}
914920

915921
static void uart_qspi_tx(uint8_t c)
@@ -959,11 +965,23 @@ static void qspi_uart_program(void)
959965

960966
/* Receive destination address then data length (4 bytes LE each) */
961967
addr = 0;
962-
for (i = 0; i < 4; i++)
963-
addr |= ((uint32_t)uart_qspi_rx() << (i * 8));
968+
for (i = 0; i < 4; i++) {
969+
int b = uart_qspi_rx();
970+
if (b < 0) {
971+
wolfBoot_printf("QSPI-PROG: RX timeout receiving addr\r\n");
972+
return;
973+
}
974+
addr |= ((uint32_t)(uint8_t)b << (i * 8));
975+
}
964976
size = 0;
965-
for (i = 0; i < 4; i++)
966-
size |= ((uint32_t)uart_qspi_rx() << (i * 8));
977+
for (i = 0; i < 4; i++) {
978+
int b = uart_qspi_rx();
979+
if (b < 0) {
980+
wolfBoot_printf("QSPI-PROG: RX timeout receiving size\r\n");
981+
return;
982+
}
983+
size |= ((uint32_t)(uint8_t)b << (i * 8));
984+
}
967985

968986
wolfBoot_printf("QSPI-PROG: addr=0x%x size=%u bytes\r\n", addr, size);
969987

@@ -972,6 +990,20 @@ static void qspi_uart_program(void)
972990
return;
973991
}
974992

993+
/* Reject writes to unaligned or out-of-partition addresses before any erase */
994+
if ((addr & (FLASH_SECTOR_SIZE - 1U)) != 0U) {
995+
wolfBoot_printf("QSPI-PROG: addr 0x%x not sector-aligned, aborting\r\n", addr);
996+
return;
997+
}
998+
if (!((addr >= WOLFBOOT_PARTITION_BOOT_ADDRESS &&
999+
addr + size <= WOLFBOOT_PARTITION_BOOT_ADDRESS + WOLFBOOT_PARTITION_SIZE) ||
1000+
(addr >= WOLFBOOT_PARTITION_UPDATE_ADDRESS &&
1001+
addr + size <= WOLFBOOT_PARTITION_UPDATE_ADDRESS + WOLFBOOT_PARTITION_SIZE))) {
1002+
wolfBoot_printf("QSPI-PROG: addr 0x%x+%u outside allowed partitions, aborting\r\n",
1003+
addr, size);
1004+
return;
1005+
}
1006+
9751007
/* Erase all required sectors (FLASH_SECTOR_SIZE = 64 KB) */
9761008
n_sectors = (size + FLASH_SECTOR_SIZE - 1) / FLASH_SECTOR_SIZE;
9771009
wolfBoot_printf("QSPI-PROG: Erasing %u sector(s) at 0x%x...\r\n",
@@ -1002,8 +1034,16 @@ static void qspi_uart_program(void)
10021034

10031035
uart_qspi_tx(QSPI_PROG_ACK); /* request next chunk */
10041036

1005-
for (i = 0; i < chunk_len; i++)
1006-
chunk[i] = uart_qspi_rx();
1037+
for (i = 0; i < chunk_len; i++) {
1038+
int b = uart_qspi_rx();
1039+
if (b < 0) {
1040+
wolfBoot_printf("QSPI-PROG: RX timeout at 0x%x+%u\r\n",
1041+
addr + written, i);
1042+
ext_flash_lock();
1043+
return;
1044+
}
1045+
chunk[i] = (uint8_t)b;
1046+
}
10071047

10081048
ret = ext_flash_write(addr + written, chunk, (int)chunk_len);
10091049
if (ret < 0) {

hal/riscv.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,9 +124,16 @@ static inline void riscv_icache_sync(void)
124124
#define SSTATUS_SIE (1UL << 1)
125125
#define SSTATUS_SPIE (1UL << 5)
126126

127-
/* MIP register bits */
127+
/* MIP register bits (mip CSR: pending interrupt flags, written by hardware) */
128128
#define MIP_MSIP (1 << IRQ_M_SOFT)
129129

130+
/* MIE register bits (mie CSR: interrupt enable, always written by software.
131+
* Bit positions match MIP but use these names when targeting the mie register
132+
* to avoid confusing the two CSRs.) */
133+
#define MIE_MSIE (1 << IRQ_M_SOFT)
134+
#define MIE_MTIE (1 << IRQ_M_TIMER)
135+
#define MIE_MEIE (1 << IRQ_M_EXT)
136+
130137
/* SIE register bits */
131138
#define SIE_SSIE (1 << IRQ_S_SOFT)
132139
#define SIE_STIE (1 << IRQ_S_TIMER)

src/boot_riscv_start.S

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ _copy_params:
118118
csrc mstatus, t0
119119
csrw mie, zero
120120
csrw mip, zero
121-
li t0, MIP_MSIP /* wake only on IPI */
121+
li t0, MIE_MSIE /* wake only on IPI */
122122
csrw mie, t0
123123

124124
/* Set up per-hart stack: base + (hartid+1)*STACK_SIZE_PER_HART */

src/sdhci.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@ static volatile int g_mmc_irq_pending = 0;
6666
/* Microsecond delay using hardware timer */
6767
static void udelay(uint32_t us)
6868
{
69-
uint64_t start = hal_get_timer_us();
70-
while ((hal_get_timer_us() - start) < us);
69+
uint64_t end = hal_get_timer_us() + us;
70+
while (hal_get_timer_us() < end);
7171
}
7272

7373
/* ============================================================================

0 commit comments

Comments
 (0)