|
3 | 3 | * HAL for the Raspberry Pi Compute Module 4 (CM4): Broadcom BCM2711, |
4 | 4 | * quad-core Cortex-A72 (ARMv8-A). |
5 | 5 | * |
6 | | - * The VideoCore GPU firmware loads wolfBoot (as kernel8.img) to 0x80000 and |
7 | | - * releases the A72 cores; wolfBoot verifies the appended signed payload and |
8 | | - * boots it from RAM. hal_flash_* are no-ops (no in-place flash in this mode). |
9 | | - * Optional eMMC/SD A/B via the generic SDHCI driver is at the end of the file. |
| 6 | + * The VideoCore GPU firmware loads wolfBoot (an ARM64 kernel8.img carrying the |
| 7 | + * Linux image header) to 0x200000 and enters it at EL2; wolfBoot verifies the |
| 8 | + * signed payload and boots it from RAM, or from eMMC/SD A/B via the generic |
| 9 | + * SDHCI driver (at the end of this file). hal_flash_* are no-ops (no in-place |
| 10 | + * flash in this mode). |
10 | 11 | * |
11 | 12 | * Copyright (C) 2026 wolfSSL Inc. |
12 | 13 | * |
|
42 | 43 | /* Fixed addresses (provided by the linker script) */ |
43 | 44 | extern void *kernel_addr, *update_addr, *dts_addr; |
44 | 45 |
|
45 | | -#if defined(HAVE_FIPS) |
| 46 | +/* Enable the identity MMU + caches when the build does more than the trivial |
| 47 | + * RAM-boot: FIPS (unaligned/SIMD in the module), or the disk path (optimized |
| 48 | + * code + SDHCI block-buffer memcpy fault on MMU-off Device memory). Normal |
| 49 | + * cacheable memory permits those accesses and speeds up crypto/disk reads. */ |
| 50 | +#if (defined(HAVE_FIPS) || defined(DISK_SDCARD) || defined(DISK_EMMC)) \ |
| 51 | + && defined(__aarch64__) |
| 52 | +#define CM4_USE_MMU |
| 53 | +#endif |
| 54 | + |
| 55 | +#if defined(CM4_USE_MMU) |
46 | 56 | void cm4_mmu_enable(void); /* defined below; called from hal_init */ |
47 | 57 | void cm4_mmu_disable(void); /* defined below; called from hal_prepare_boot */ |
48 | 58 | #endif |
49 | 59 |
|
50 | 60 | #if defined(DEBUG_UART) |
| 61 | +/* Console UART select. On this bench CM4 the debug cable on GPIO14/15 is the |
| 62 | + * BCM2711 mini-UART (AUX, Linux ttyS0), so that is the default. Boards where |
| 63 | + * dtoverlay=disable-bt actually routes the PL011 onto GPIO14/15 can build with |
| 64 | + * CM4_UART_PL011 to use the PL011 (0xFE201000) instead. */ |
| 65 | +#if defined(CM4_UART_PL011) |
51 | 66 | static void uart_tx(char c) |
52 | 67 | { |
53 | 68 | while (*UART0_FR & 0x20) /* TXFF: wait while FIFO full */ |
54 | 69 | ; |
55 | | - *UART0_DR = c; |
56 | | -} |
57 | | - |
58 | | -void uart_write(const char* buf, uint32_t sz) |
59 | | -{ |
60 | | - while (sz-- > 0 && *buf) |
61 | | - uart_tx(*buf++); |
| 70 | + *UART0_DR = (unsigned int)(unsigned char)c; |
62 | 71 | } |
63 | 72 |
|
64 | 73 | void uart_init(void) |
65 | 74 | { |
66 | | - /* The VideoCore firmware has already routed the PL011 to GPIO14/15 |
67 | | - * (dtoverlay=disable-bt) and set init_uart_clock=48MHz. Program the PL011 |
68 | | - * for 115200 8N1 directly, without the VideoCore mailbox (a mailbox poll |
69 | | - * that never returns post-handoff would hang before any output). |
70 | | - * 48MHz UARTCLK: BAUDDIV = 48e6/(16*115200) = 26.04 -> IBRD 26, FBRD 3. */ |
| 75 | + /* Program the PL011 for 115200 8N1 assuming a 48MHz UARTCLK |
| 76 | + * (init_uart_clock=48000000): BAUDDIV = 48e6/(16*115200) -> IBRD 26 FBRD 3. */ |
71 | 77 | *UART0_CR = 0; |
72 | 78 | *UART0_ICR = 0x7FF; |
73 | 79 | *UART0_IBRD = 26; |
74 | 80 | *UART0_FBRD = 3; |
75 | 81 | *UART0_LCRH = (1 << 4) | (1 << 5) | (1 << 6); /* FIFO, 8-bit */ |
76 | 82 | *UART0_CR = (1 << 0) | (1 << 8) | (1 << 9); /* enable UART, TX, RX */ |
77 | 83 | } |
| 84 | +#else /* mini-UART (default) */ |
| 85 | +static void uart_tx(char c) |
| 86 | +{ |
| 87 | + while ((*MU_LSR & MU_LSR_TXFF_EMPTY) == 0) /* wait until TX can accept */ |
| 88 | + ; |
| 89 | + *MU_IO = (unsigned int)(unsigned char)c; |
| 90 | +} |
| 91 | + |
| 92 | +void uart_init(void) |
| 93 | +{ |
| 94 | + /* The firmware has already enabled the mini-UART at a stable baud |
| 95 | + * (enable_uart=1 fixes core_freq), so - like the Linux 8250 console with |
| 96 | + * "skip-init" - wolfBoot inherits that setup and just writes AUX_MU_IO. |
| 97 | + * Reprogramming the baud here is unnecessary (and error-prone: the mini-UART |
| 98 | + * clock is core_freq-derived, not a fixed rate). */ |
| 99 | +} |
| 100 | +#endif /* CM4_UART_PL011 */ |
| 101 | + |
| 102 | +void uart_write(const char* buf, uint32_t sz) |
| 103 | +{ |
| 104 | + while (sz-- > 0 && *buf) |
| 105 | + uart_tx(*buf++); |
| 106 | +} |
78 | 107 | #endif /* DEBUG_UART */ |
79 | 108 |
|
80 | 109 | void* hal_get_primary_address(void) |
@@ -134,18 +163,19 @@ void hal_init(void) |
134 | 163 | wolfBoot_printf("wolfBoot CM4 (BCM2711 Cortex-A72) hal_init, EL%d\n", |
135 | 164 | (int)((el >> 2) & 0x3)); |
136 | 165 | #endif |
137 | | -#if defined(HAVE_FIPS) |
138 | | - /* Bring up Normal cacheable memory before the FIPS POST, which uses |
139 | | - * unaligned / SIMD accesses that the MMU-off Device memory rejects. */ |
| 166 | +#if defined(CM4_USE_MMU) |
| 167 | + /* Bring up Normal cacheable memory before any code that uses unaligned / |
| 168 | + * SIMD accesses (FIPS module, optimized disk path) which the MMU-off |
| 169 | + * Device memory rejects. */ |
140 | 170 | cm4_mmu_enable(); |
141 | 171 | #endif |
142 | 172 | } |
143 | 173 |
|
144 | 174 | void hal_prepare_boot(void) |
145 | 175 | { |
146 | | -#if defined(HAVE_FIPS) |
147 | | - /* Undo cm4_mmu_enable() before handoff: flush the app out of the D-cache |
148 | | - * and return to the MMU-off state the application expects. */ |
| 176 | +#if defined(CM4_USE_MMU) |
| 177 | + /* Undo cm4_mmu_enable() before handoff: flush the loaded image out of the |
| 178 | + * D-cache and return to the MMU-off state the application expects. */ |
149 | 179 | cm4_mmu_disable(); |
150 | 180 | #endif |
151 | 181 | } |
@@ -173,13 +203,16 @@ void* _sbrk(int incr) |
173 | 203 | brk += incr; |
174 | 204 | return (void*)prev; |
175 | 205 | } |
| 206 | +#endif /* HAVE_FIPS */ |
176 | 207 |
|
| 208 | +#if defined(CM4_USE_MMU) |
177 | 209 | /* Minimal identity-mapped MMU + caches for the CM4. wolfBoot's simple startup |
178 | 210 | * runs with the MMU off, so all memory is Device-nGnRnE, which faults on the |
179 | | - * unaligned / 128-bit SIMD accesses the FIPS module and newlib printf perform. |
180 | | - * Mapping DDR as Normal (cacheable) permits those accesses and speeds up the |
181 | | - * crypto; the peripheral region (incl. 0xFE000000) stays Device. |
182 | | - * Four 1GB block descriptors cover the 32-bit VA space at translation level 1. */ |
| 211 | + * unaligned / 128-bit SIMD accesses that the FIPS module, newlib printf, and |
| 212 | + * the optimized disk/SDHCI code paths perform. Mapping DDR as Normal |
| 213 | + * (cacheable) permits those accesses and speeds up crypto/disk reads; the |
| 214 | + * peripheral region (incl. 0xFE000000) stays Device. Four 1GB block |
| 215 | + * descriptors cover the 32-bit VA space at translation level 1. */ |
183 | 216 | #define MMU_BLOCK_NORMAL 0x0000000000000701ULL /* block, AttrIdx0, AF, SH inner */ |
184 | 217 | #define MMU_BLOCK_DEVICE 0x0000000000000405ULL /* block, AttrIdx1, AF, SH none */ |
185 | 218 |
|
@@ -275,7 +308,7 @@ void cm4_mmu_disable(void) |
275 | 308 | __asm__ volatile("dsb sy"); |
276 | 309 | __asm__ volatile("isb"); |
277 | 310 | } |
278 | | -#endif /* HAVE_FIPS */ |
| 311 | +#endif /* CM4_USE_MMU */ |
279 | 312 |
|
280 | 313 | #if defined(DEBUG) && defined(DEBUG_UART) |
281 | 314 | /* CM4 bring-up diagnostic: exception handler invoked from cm4_vectors in |
@@ -371,9 +404,9 @@ int RAMFUNCTION hal_flash_erase(uintptr_t address, int len) |
371 | 404 | /* BCM2711 EMMC2 platform glue for the generic SDHCI driver (src/sdhci.c). |
372 | 405 | * EMMC2 is a standard SDHCI v3.0 Arasan block at 0xFE340000. The driver uses |
373 | 406 | * Cadence-style SRS offsets (0x200 + std); translate them to the standard |
374 | | - * Arasan layout, mirroring the ZynqMP path in hal/zynq.c. NOTE: not yet |
375 | | - * hardware-validated; clock/caps/card-detect quirks may be required once |
376 | | - * validated on hardware. */ |
| 407 | + * Arasan layout, mirroring the ZynqMP path in hal/zynq.c. The GPU firmware has |
| 408 | + * already configured the EMMC2 clock/pinmux, so only a controller soft reset is |
| 409 | + * needed here (hardware-validated on CM4 eMMC). */ |
377 | 410 | #include "sdhci.h" |
378 | 411 |
|
379 | 412 | uint32_t sdhci_reg_read(uint32_t offset) |
|
0 commit comments