Index: firmware/target/arm/system-pp502x.c =================================================================== --- firmware/target/arm/system-pp502x.c (revision 31026) +++ firmware/target/arm/system-pp502x.c (working copy) @@ -209,6 +209,15 @@ GPIOL_INT_EN = 0; } +/* FIXME: The following bug may not be present on all PP502x variants. + * The workaround code wastes time and energy when the bug is not present. */ + +/* When the cache is flushed or flushed and invalidated, cache lines + * which are not marked as valid can cause memory corruption. Therefore, + * all cache lines must be marked as valid before calling these functions. + * This is accomplished via code that runs after cache initialization and + * invalidation. */ + void ICODE_ATTR cpucache_commit(void) { if (CACHE_CTL & CACHE_CTL_ENABLE) @@ -224,9 +233,23 @@ { if (CACHE_CTL & CACHE_CTL_ENABLE) { + /* Interrupts between the flush and rewriting of cache + * status words could cause memory corruption. */ + register int istat = disable_interrupt_save(IRQ_FIQ_STATUS); + CACHE_OPERATION |= CACHE_OP_FLUSH | CACHE_OP_INVALIDATE; while ((CACHE_CTL & CACHE_CTL_BUSY) != 0); nop; nop; nop; nop; + + /* Point all cache status words past end of RAM, + * and make them valid, but not dirty. */ + register volatile unsigned long *p; + for (p = &CACHE_STATUS_BASE; + p < (&CACHE_STATUS_BASE) + 512*16/sizeof(*p); + p += 16/sizeof(*p)) + *p = ((8*0x100000) >> 11) | 0x800000; + + restore_interrupt(istat); } } void cpucache_invalidate(void) __attribute__((alias("cpucache_commit_discard"))); @@ -257,6 +280,13 @@ /* enable cache */ CACHE_CTL |= CACHE_CTL_INIT | CACHE_CTL_ENABLE | CACHE_CTL_RUN; nop; nop; nop; nop; + + /* Ensure all cache lines are valid for the next flush. Since this + * can run from cached RAM, rewriting of cache status words may not + * be safe and the cache is filled instead by reading. */ + register volatile char *p; + for (p = (volatile char *)0; p < (volatile char *)0x2000; p += 0x10) + (void)*p; } #endif /* BOOTLOADER || HAVE_BOOTLOADER_USB_MODE */