From 9ce3fca4cb3d5c04b2a434c2629207e7bac6cf99 Mon Sep 17 00:00:00 2001 From: Marcin Bukat Date: Wed, 7 Oct 2026 08:01:21 +0200 Subject: [PATCH] rk27xx: no whole-cache invalidate at run time commit_discard_idcache() invalidated both cache ways at run time, at every codec and plugin load and every USB connect. With the cache on, the CPU crashed in the poll loop when that loop started a cache line of its own; with the cache off around it, since 0e1952a4d1, code fetched again afterwards could come back wrong. On a Samsung YP-CP3 a build with a few changes elsewhere took an undefined instruction exception in the USB interrupt handler at every boot into USB mode, always at the same instruction, wherever the linker put it. The same build with only the invalidate at USB connect replaced by a nop booted and worked. The original firmware invalidates the ways only once, at power-on with the cache off, as crt0.S does, and after that only single lines. None is needed at run time: the cache is unified and write-through, so what the CPU writes, code included, is in memory and in any cached copy, and every DMA into memory - SD reads, USB receives, recording - discards the lines of its own buffer first. NAND is read by the CPU. So commit_discard_idcache(), and commit_discard_dcache() with it, now do nothing. Tested on a YP-CP3, with the build that crashed: it boots into USB mode, copies files with matching checksums, plays several formats, runs plugins (fft with playback, bubbles), and records. Co-Authored-By: Claude Opus 5.5 Change-Id: I14301a0c05736e28e53a3365c838f4a4a73052b3 --- firmware/target/arm/rk27xx/system-rk27xx.c | 35 ++++++---------------- 1 file changed, 9 insertions(+), 26 deletions(-) diff --git a/firmware/target/arm/rk27xx/system-rk27xx.c b/firmware/target/arm/rk27xx/system-rk27xx.c index 0d4a521cf8..8ca7d3d25f 100644 --- a/firmware/target/arm/rk27xx/system-rk27xx.c +++ b/firmware/target/arm/rk27xx/system-rk27xx.c @@ -184,34 +184,17 @@ void udelay(unsigned usecs) ); } -static void cache_invalidate_way(int way) -{ - /* Issue invalidata way command to the cache controler */ - CACHEOP = ((way<<31)|0x2); - - /* wait for invalidate process to complete */ - while (CACHEOP & 0x03); -} - +/* No whole-cache invalidate at run time, as in the original firmware: it + * invalidates the ways once, at power-on with the cache off (crt0.S), and + * after that only single lines. Invalidating the ways while running from + * cached SDRAM crashed depending on where code happened to lie - with the + * cache on in the poll loop, and with it off later, as code was fetched + * again. None is needed: the cache is unified and write-through, so what + * the CPU writes, code included, is in memory and in any cached copy, and + * every DMA into memory discards the lines of its own buffer first + * (commit_discard_dcache_range()). */ void commit_discard_idcache(void) { - int old_irq = disable_irq_save(); - unsigned long devid = DEVID; - - /* Invalidate with the cache off, as crt0 does. This code runs from - * cached SDRAM: invalidating the ways while fetching through them fails - * when the poll loop starts on a cache line of its own, depending on - * where the linker happened to put it. The cache is write-through, so - * nothing is lost by turning it off. */ - DEVID = devid & ~(1UL << 31); - - cache_invalidate_way(0); - - cache_invalidate_way(1); - - DEVID = devid; - - restore_irq(old_irq); } void commit_discard_dcache (void) __attribute__((alias("commit_discard_idcache")));