[PATCH 4/6] cache: andes-l2: Add writeback-invalidate operation
Leo Yu-Chi Liang
ycliang at andestech.com
Thu Mar 19 09:37:11 CET 2026
Add a wbinval operation to the cache uclass that performs
writeback-invalidate without the disable/enable cycle that the
existing disable path uses. This is needed for flush_dcache_all()
to properly flush both L1 and L2 caches.
Implement andes_l2_wbinval_all() in the Andes L2 cache driver
which issues the L2_WBINVAL_ALL command while keeping the cache
enabled.
Update flush_dcache_all() in the Andes cache code to also call
L2 wbinval when CONFIG_ANDES_L2_CACHE is enabled.
Signed-off-by: Leo Yu-Chi Liang <ycliang at andestech.com>
---
arch/riscv/cpu/andes/cache.c | 4 ++++
drivers/cache/cache-andes-l2.c | 24 ++++++++++++++++++++++++
drivers/cache/cache-uclass.c | 10 ++++++++++
include/cache.h | 16 ++++++++++++++++
4 files changed, 54 insertions(+)
diff --git a/arch/riscv/cpu/andes/cache.c b/arch/riscv/cpu/andes/cache.c
index bb57498d75a..3b325d77954 100644
--- a/arch/riscv/cpu/andes/cache.c
+++ b/arch/riscv/cpu/andes/cache.c
@@ -44,6 +44,10 @@ static void cache_ops(int (*ops)(struct udevice *dev))
void flush_dcache_all(void)
{
csr_write(CSR_UCCTLCOMMAND, CCTL_L1D_WBINVAL_ALL);
+
+#ifdef CONFIG_ANDES_L2_CACHE
+ cache_ops(cache_wbinval);
+#endif
}
void flush_dcache_range(unsigned long start, unsigned long end)
diff --git a/drivers/cache/cache-andes-l2.c b/drivers/cache/cache-andes-l2.c
index 45a4f216b07..5ceccf609e5 100644
--- a/drivers/cache/cache-andes-l2.c
+++ b/drivers/cache/cache-andes-l2.c
@@ -91,6 +91,29 @@ static int andes_l2_enable(struct udevice *dev)
return 0;
}
+static int andes_l2_wbinval_all(struct udevice *dev)
+{
+ struct andes_l2_plat *plat = dev_get_plat(dev);
+ volatile struct l2cache *regs = plat->regs;
+ u8 hart = gd->arch.boot_hart;
+
+ void __iomem *cctlcmd = (void __iomem *)CCTL_CMD_REG(regs, hart);
+ void __iomem *cctlstatus = (void __iomem *)CCTL_STATUS_REG(regs, hart);
+
+ if ((regs) && (readl(®s->control) & L2_ENABLE)) {
+ writel(L2_WBINVAL_ALL, cctlcmd);
+
+ while ((readl(cctlstatus) & CCTL_STATUS_MSK(hart))) {
+ if ((readl(cctlstatus) & CCTL_STATUS_ILLEGAL(hart))) {
+ printf("L2 flush illegal! hanging...");
+ hang();
+ }
+ }
+ }
+
+ return 0;
+}
+
static int andes_l2_disable(struct udevice *dev)
{
struct andes_l2_plat *plat = dev_get_plat(dev);
@@ -192,6 +215,7 @@ static const struct udevice_id andes_l2_cache_ids[] = {
static const struct cache_ops andes_l2_cache_ops = {
.enable = andes_l2_enable,
.disable = andes_l2_disable,
+ .wbinval = andes_l2_wbinval_all,
};
U_BOOT_DRIVER(andes_l2_cache) = {
diff --git a/drivers/cache/cache-uclass.c b/drivers/cache/cache-uclass.c
index 300e7bc86e1..8e77c9e2f4e 100644
--- a/drivers/cache/cache-uclass.c
+++ b/drivers/cache/cache-uclass.c
@@ -38,6 +38,16 @@ int cache_disable(struct udevice *dev)
return ops->disable(dev);
}
+int cache_wbinval(struct udevice *dev)
+{
+ struct cache_ops *ops = cache_get_ops(dev);
+
+ if (!ops->wbinval)
+ return -ENOSYS;
+
+ return ops->wbinval(dev);
+}
+
UCLASS_DRIVER(cache) = {
.id = UCLASS_CACHE,
.name = "cache",
diff --git a/include/cache.h b/include/cache.h
index 296ae3c8b48..45b27ab989c 100644
--- a/include/cache.h
+++ b/include/cache.h
@@ -42,6 +42,14 @@ struct cache_ops {
* @return 0 if OK, -ve on error
*/
int (*disable)(struct udevice *dev);
+
+ /**
+ * wbinval() - Writeback and invalidate cache
+ *
+ * @dev: Device to check (UCLASS_CACHE)
+ * @return 0 if OK, -ve on error
+ */
+ int (*wbinval)(struct udevice *dev);
};
#define cache_get_ops(dev) ((struct cache_ops *)(dev)->driver->ops)
@@ -70,4 +78,12 @@ int cache_enable(struct udevice *dev);
* Return: 0 if OK, -ve on error
*/
int cache_disable(struct udevice *dev);
+
+/**
+ * cache_wbinval() - Writeback and invalidate cache
+ *
+ * @dev: Device to check (UCLASS_CACHE)
+ * Return: 0 if OK, -ve on error
+ */
+int cache_wbinval(struct udevice *dev);
#endif
--
2.34.1
More information about the U-Boot
mailing list