Repository navigation
SYSCACHE_ONLY_MODE
What: boot U-Boot entirely from the 24 MB L3 System Cache used as RAM, no DDR init.
Axxia Lionfish (Cortex-A53, Nokia 3x), bsp_u-boot_gen2, branch nokia_3x_images_SYSCACHE_outer_fixed.
Why: Customer had a requirement it is U-Boot toinit memory not SPL before DDR PHY training.
- L1 (per core, ~32K) / L2 (per cluster, ~1–2M) → too small.
- L3 = 24 MB System Cache on the CCN interconnect (codenames DICKENS/SHELLEY)
Branch nokia_3x_images: SPL / ATF(BL31) / U-Boot as separate images (before: SPL+monitor combined). Boot ROM → SPL → ATF → U-Boot → Linux. Offsets (axc6700.h)
Same TBBR BL skeleton (BL1→BL2→BL31→BL33). The difference: BL2/SPL skips DDR and turns the L3 into RAM, so BL31+BL33 run from cache.
Standard
SYSCACHE_ONLY_MODE — SPL jumps to U-Boot at EL3 (runs from L3, inits DDR there);
U-Boot drops to EL2 by loading the Secure Monitor (BL31) on demand and calling it — the
eret is in the monitor, which then returns control to U-Boot now at EL2/NS.
Diffs vs standard:
- BL2 turns the 24 MB L3 into RAM instead of initing DDR; U-Boot is loaded into L3.
-
U-Boot runs at EL3 from L3 and inits DDR there (
init_mem_axxia).start.Senters at EL3 and stays (thearmv8_switch_to_el2instart.Sis underMULTIENTRY, slaves only). -
EL3→EL2 is done by loading BL31 on demand —
switch_to_EL2_non_secure(common/board_f.c:825) reads the Secure Monitor from flash0x300000intoLSM+0x1000, pre-migratesSP_EL2/VBAR_EL2, then calls it (entry(NULL, cfg)). Theeretis in the monitor (TF-A/BL31) binary, not in U-Boot — which is why it is not in the U-Boot source. The monitor erets EL3→EL2/NS and returns to U-Boot (comment "We are now at EL2, non-secure state" right afterentry()). (The board's ownarmv8_switch_to_el2()ataxxia.c:75is dead#if 0.)
Caveat: PSCI is disabled; secondaries come up via spin-table (enable-method = "spin-table",
92c327575a).
The eret back to U-Boot uses no hardcoded address — it reuses the normal AArch64 call
return, i.e. x30 from U-Boot's call into the monitor (the instruction right after the call —
effectively PC+4).
-
U-Boot calls the monitor as an ordinary function —
common/board_f.c:889:entry = (void (*)(void *, void *))(LSM + 0x1000); /* monitor loaded here */ entry(NULL, axxia_configuration); /* compiled to `bl` → x30 = next insn (board_f.c:890) */
-
Monitor entry stashes the caller's LR —
bl31/aarch64/bl31_entrypoint.S:47–49:(also saves SP →ldr x22, =__return_addr_for_el3 str x30, [x22] /* __return_addr_for_el3 = x30 from U-Boot's `bl` */
__sp_addr_for_el3andVBAR_EL3→__vbar3_to_migrate.) -
Monitor sets that as the eret target —
plat/intel/axxia/bl31_plat_setup.c:201:TF-A thenbl33_ep_info.pc = *(uintptr_t*) get_return_addr_for_el3(); /* ELR_EL3 = saved x30 */ bl33_ep_info.spsr = SPSR_64(MODE_EL2, MODE_SP_ELX, 0); /* eret → EL2/NS */
erets tobl33_ep_info.pc→ U-Boot resumes at the instruction right afterentry(...)(board_f.c:890), now at EL2/NS. From U-Boot's viewentry()simply "returned", only the Exception Level changed EL3→EL2.
entered_at is informational only: board_f.c:881 snapshots a label before the call
(asm volatile ("adr %0, .\n" : "=r"(cfg->entered_at))) and the monitor only prints it
("Uboot branched from 0x%lx"). It is not the return path — the real return is x30 above.
Both sides must agree: axxia_configuration_t is declared identically in U-Boot
(board_f.c:814) and ATF (axxia_def.h), and BL31 is linked at TZRAM_BASE = LSM + 0x1000
(platform_def.h) to match where U-Boot copies it. ATF commits: 68fdb6b142 (3 images,
U-Boot-entered comment + entered_at), d23c387a96 (always-on xlat-table print).
-
L3 → FULL —
outer_cache.Ssets HN-F mode FULL (__asm_enable_l3_cache). Modes: OFF / SFONLY / HALF / FULL; 7 HN-F nodes (id 0x20–0x26) on CCN. -
setup_security()— unlock CCN + GPDMA (secure/external boot).secure.c:51 -
set_cluster_coherency(c,1)— add clusters to coherency domain (must precede L3 use).l3_coherency.c:37 -
init_l3()— GPDMA-zero all 24 MB → allocate the lines.spl.c:923 -
mmu_configure(pgt, DISABLE_DCACHE)— page tables Normal, cacheable, Outer Shareable (the crux: outer-share = held/coherent at L3). MMU on, D-cache still off.cache_v8.c(PMD_SECT_OUTER_SHARE) -
pt_walk(...)— prime TLB (RAM, DICKENS, UART, LSM).spl.c:1581 -
enable D-cache —
set_sctlr(|CR_C)(cache AFTER TLB — safe MMU→TLB→cache order). -
load_image_mem(CONFIG_UBOOT_OFFSET)— CPU0 copies U-Boot SPI→addr 0 → lands in L3.spl.c:938 -
flush D$ / invalidate I$ —
.textwritten via D$, fetched via I$. -
jump —
entry=(void*)0x0; (*entry)(NULL,NULL)→ U-Boot runs from L3, no DDR.
PC-relative literal ldr x13,=(DICKENS+0x10) → ldr x13,[pc-0x110] pulled the literal's cache
line Modified; cleanup_before_linux() then cleared C/M bits → dirty line dropped
(lost the DICKENS address). Rule: between disabling and flushing caches, touch only local
(stack) data. Fix: no PC-relative literals in that window + barriers.
a379a81290 3 images · 96e3ab5dbd drop GPDMA, CPU-load · cf06f3dab3 SH→outer + cluster
coherency · 12c9f97fc8 critical cache fix · 1ecab7fd13 working finally.