/* SPDX-License-Identifier: GPL-2.0+ */ /* * cache_va.c - cache maintenance by virtual address, the operations * the manual prescribes for boot handoff: clean to point of * coherency (dc cvac), invalidate (dc ivac), and clean and * invalidate (dc civac), plus icache invalidate by VA to the point * of unification (ic ivau). by VA beats by set and way when the * address range is known, the manual's own guidance, set and way * only for the full flush cases in cache.S. * * Copyright (C) 2026 Bradley Morgan */ #include #include #define CACHE_LINE_SHIFT 6 /* 64 byte lines on cortex-a class */ #define CACHE_LINE_SIZE (1 << CACHE_LINE_SHIFT) void tb_clean_dcache_range(uintptr_t start, size_t len) { uintptr_t line = start & ~(uintptr_t)(CACHE_LINE_SIZE - 1); uintptr_t end = start + len; while (line < end) { asm volatile("dc cvac, %0" :: "r" (line) : "memory"); line += CACHE_LINE_SIZE; } asm volatile("dsb sy" ::: "memory"); } void tb_inval_dcache_range(uintptr_t start, size_t len) { uintptr_t line = start & ~(uintptr_t)(CACHE_LINE_SIZE - 1); uintptr_t end = start + len; while (line < end) { asm volatile("dc ivac, %0" :: "r" (line) : "memory"); line += CACHE_LINE_SIZE; } asm volatile("dsb sy" ::: "memory"); } void tb_clean_inval_dcache_range(uintptr_t start, size_t len) { uintptr_t line = start & ~(uintptr_t)(CACHE_LINE_SIZE - 1); uintptr_t end = start + len; while (line < end) { asm volatile("dc civac, %0" :: "r" (line) : "memory"); line += CACHE_LINE_SIZE; } asm volatile("dsb sy" ::: "memory"); } void tb_inval_icache_range(uintptr_t start, size_t len) { uintptr_t line = start & ~(uintptr_t)(CACHE_LINE_SIZE - 1); uintptr_t end = start + len; while (line < end) { asm volatile("ic ivau, %0" :: "r" (line) : "memory"); line += CACHE_LINE_SIZE; } asm volatile( "dsb ish\n" "isb\n" ::: "memory"); }