From 8ea972838cf3f398b1a2896e645c8c2fb23e2159 Mon Sep 17 00:00:00 2001 From: Vincent Chen Date: Mon, 20 Oct 2025 14:34:05 +0800 Subject: [PATCH] utils: cache: Add SiFive ccache controller SiFive Composable cache is a L3 share cache of the core complex. Add this driver to support the share cache maintenance operations via the MMIO registers. Co-developed-by: Samuel Holland Signed-off-by: Samuel Holland Signed-off-by: Vincent Chen Co-developed-by: Nick Hu Signed-off-by: Nick Hu Reviewed-by: Samuel Holland Reviewed-by: Anup Patel Link: https://lore.kernel.org/r/20251020-cache-upstream-v7-3-69a132447d8a@sifive.com Signed-off-by: Anup Patel --- lib/utils/cache/Kconfig | 8 ++ lib/utils/cache/fdt_sifive_ccache.c | 175 ++++++++++++++++++++++++++++ lib/utils/cache/objects.mk | 3 + platform/generic/configs/defconfig | 1 + 4 files changed, 187 insertions(+) create mode 100644 lib/utils/cache/fdt_sifive_ccache.c diff --git a/lib/utils/cache/Kconfig b/lib/utils/cache/Kconfig index 10602176..1c7abdc9 100644 --- a/lib/utils/cache/Kconfig +++ b/lib/utils/cache/Kconfig @@ -8,6 +8,14 @@ config FDT_CACHE select CACHE default n +if FDT_CACHE + +config FDT_CACHE_SIFIVE_CCACHE + bool "SiFive CCACHE FDT cache driver" + default n + +endif + config CACHE bool "Cache support" default n diff --git a/lib/utils/cache/fdt_sifive_ccache.c b/lib/utils/cache/fdt_sifive_ccache.c new file mode 100644 index 00000000..b641ed16 --- /dev/null +++ b/lib/utils/cache/fdt_sifive_ccache.c @@ -0,0 +1,175 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2025 SiFive Inc. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define CCACHE_CFG_CSR 0 +#define CCACHE_CMD_CSR 0x280 +#define CCACHE_STATUS_CSR 0x288 + +#define CFG_CSR_BANK_MASK 0xff +#define CFG_CSR_WAY_MASK 0xff00 +#define CFG_CSR_WAY_OFFSET 8 +#define CFG_CSR_SET_MASK 0xff0000 +#define CFG_CSR_SET_OFFSET 16 + +#define CMD_CSR_CMD_OFFSET 56 +#define CMD_CSR_BANK_OFFSET 6 + +#define CMD_OPCODE_SETWAY 0x1ULL +#define CMD_OPCODE_OFFSET 0x2ULL + +#define CFLUSH_SETWAY_CLEANINV ((CMD_OPCODE_SETWAY << CMD_OPCODE_OFFSET) | 0x3) + +#define CCACHE_CMD_QLEN 0xff + +#define ccache_mb_b() RISCV_FENCE(rw, o) +#define ccache_mb_a() RISCV_FENCE(o, rw) + +#define CCACHE_ALL_OP_REQ_BATCH_NUM 0x10 +#define CCACHE_ALL_OP_REQ_BATCH_MASK (CCACHE_CMD_QLEN + 1 - CCACHE_ALL_OP_REQ_BATCH_NUM) + +struct sifive_ccache { + struct cache_device dev; + void *addr; + u64 total_lines; +}; + +#define to_ccache(_dev) container_of(_dev, struct sifive_ccache, dev) + +static inline unsigned int sifive_ccache_read_status(void *status_addr) +{ + return readl_relaxed(status_addr); +} + +static inline void sifive_ccache_write_cmd(u64 cmd, void *cmd_csr_addr) +{ +#if __riscv_xlen != 32 + writeq_relaxed(cmd, cmd_csr_addr); +#else + /* + * The cache maintenance request is only generated when the "command" + * field (part of the high word) is written. + */ + writel_relaxed(cmd, cmd_csr_addr); + writel(cmd >> 32, cmd_csr_addr + 4); +#endif +} + +static int sifive_ccache_flush_all(struct cache_device *dev) +{ + struct sifive_ccache *ccache = to_ccache(dev); + void *status_addr = (char *)ccache->addr + CCACHE_STATUS_CSR; + void *cmd_csr_addr = (char *)ccache->addr + CCACHE_CMD_CSR; + u64 total_cnt = ccache->total_lines; + u64 cmd = CFLUSH_SETWAY_CLEANINV << CMD_CSR_CMD_OFFSET; + int loop_cnt = CCACHE_CMD_QLEN & CCACHE_ALL_OP_REQ_BATCH_MASK; + + ccache_mb_b(); +send_cmd: + total_cnt -= loop_cnt; + while (loop_cnt > 0) { + sifive_ccache_write_cmd(cmd + (0 << CMD_CSR_BANK_OFFSET), cmd_csr_addr); + sifive_ccache_write_cmd(cmd + (1 << CMD_CSR_BANK_OFFSET), cmd_csr_addr); + sifive_ccache_write_cmd(cmd + (2 << CMD_CSR_BANK_OFFSET), cmd_csr_addr); + sifive_ccache_write_cmd(cmd + (3 << CMD_CSR_BANK_OFFSET), cmd_csr_addr); + sifive_ccache_write_cmd(cmd + (4 << CMD_CSR_BANK_OFFSET), cmd_csr_addr); + sifive_ccache_write_cmd(cmd + (5 << CMD_CSR_BANK_OFFSET), cmd_csr_addr); + sifive_ccache_write_cmd(cmd + (6 << CMD_CSR_BANK_OFFSET), cmd_csr_addr); + sifive_ccache_write_cmd(cmd + (7 << CMD_CSR_BANK_OFFSET), cmd_csr_addr); + sifive_ccache_write_cmd(cmd + (8 << CMD_CSR_BANK_OFFSET), cmd_csr_addr); + sifive_ccache_write_cmd(cmd + (9 << CMD_CSR_BANK_OFFSET), cmd_csr_addr); + sifive_ccache_write_cmd(cmd + (10 << CMD_CSR_BANK_OFFSET), cmd_csr_addr); + sifive_ccache_write_cmd(cmd + (11 << CMD_CSR_BANK_OFFSET), cmd_csr_addr); + sifive_ccache_write_cmd(cmd + (12 << CMD_CSR_BANK_OFFSET), cmd_csr_addr); + sifive_ccache_write_cmd(cmd + (13 << CMD_CSR_BANK_OFFSET), cmd_csr_addr); + sifive_ccache_write_cmd(cmd + (14 << CMD_CSR_BANK_OFFSET), cmd_csr_addr); + sifive_ccache_write_cmd(cmd + (15 << CMD_CSR_BANK_OFFSET), cmd_csr_addr); + cmd += CCACHE_ALL_OP_REQ_BATCH_NUM << CMD_CSR_BANK_OFFSET; + loop_cnt -= CCACHE_ALL_OP_REQ_BATCH_NUM; + } + if (!total_cnt) + goto done; + + /* Ensure the ccache is able receive more than 16 requests */ + do { + loop_cnt = (CCACHE_CMD_QLEN - sifive_ccache_read_status(status_addr)); + } while (loop_cnt < CCACHE_ALL_OP_REQ_BATCH_NUM); + loop_cnt &= CCACHE_ALL_OP_REQ_BATCH_MASK; + + if (total_cnt < loop_cnt) { + loop_cnt = (total_cnt + CCACHE_ALL_OP_REQ_BATCH_NUM) & CCACHE_ALL_OP_REQ_BATCH_MASK; + cmd -= ((loop_cnt - total_cnt) << CMD_CSR_BANK_OFFSET); + total_cnt = loop_cnt; + } + goto send_cmd; +done: + do {} while (sifive_ccache_read_status(status_addr)); + ccache_mb_a(); + + return 0; +} + +static struct cache_ops sifive_ccache_ops = { + .cache_flush_all = sifive_ccache_flush_all, +}; + +static int sifive_ccache_cold_init(const void *fdt, int nodeoff, const struct fdt_match *match) +{ + struct sifive_ccache *ccache; + struct cache_device *dev; + u64 reg_addr = 0; + u32 config_csr, banks, sets, ways; + int rc; + + /* find the ccache base control address */ + rc = fdt_get_node_addr_size(fdt, nodeoff, 0, ®_addr, NULL); + if (rc < 0 && reg_addr) + return SBI_ENODEV; + + ccache = sbi_zalloc(sizeof(*ccache)); + if (!ccache) + return SBI_ENOMEM; + + dev = &ccache->dev; + dev->ops = &sifive_ccache_ops; + rc = fdt_cache_add(fdt, nodeoff, dev); + if (rc) { + sbi_free(ccache); + return rc; + } + + ccache->addr = (void *)(uintptr_t)reg_addr; + + /* get the info of ccache from config CSR */ + config_csr = readl(ccache->addr + CCACHE_CFG_CSR); + banks = config_csr & CFG_CSR_BANK_MASK; + + sets = (config_csr & CFG_CSR_SET_MASK) >> CFG_CSR_SET_OFFSET; + sets = (1 << sets); + + ways = (config_csr & CFG_CSR_WAY_MASK) >> CFG_CSR_WAY_OFFSET; + + ccache->total_lines = sets * ways * banks; + + return SBI_OK; +} + +static const struct fdt_match sifive_ccache_match[] = { + { .compatible = "sifive,ccache2" }, + {}, +}; + +const struct fdt_driver fdt_sifive_ccache = { + .match_table = sifive_ccache_match, + .init = sifive_ccache_cold_init, +}; diff --git a/lib/utils/cache/objects.mk b/lib/utils/cache/objects.mk index 2fcf9666..a343eb8c 100644 --- a/lib/utils/cache/objects.mk +++ b/lib/utils/cache/objects.mk @@ -7,4 +7,7 @@ libsbiutils-objs-$(CONFIG_FDT_CACHE) += cache/fdt_cache.o libsbiutils-objs-$(CONFIG_FDT_CACHE) += cache/fdt_cache_drivers.carray.o +carray-fdt_cache_drivers-$(CONFIG_FDT_CACHE_SIFIVE_CCACHE) += fdt_sifive_ccache +libsbiutils-objs-$(CONFIG_FDT_CACHE_SIFIVE_CCACHE) += cache/fdt_sifive_ccache.o + libsbiutils-objs-$(CONFIG_CACHE) += cache/cache.o diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig index 6aa51f56..c074518a 100644 --- a/platform/generic/configs/defconfig +++ b/platform/generic/configs/defconfig @@ -11,6 +11,7 @@ CONFIG_PLATFORM_THEAD=y CONFIG_PLATFORM_MIPS_P8700=y CONFIG_PLATFORM_SPACEMIT_K1=y CONFIG_FDT_CACHE=y +CONFIG_FDT_CACHE_SIFIVE_CCACHE=y CONFIG_FDT_CPPC=y CONFIG_FDT_CPPC_RPMI=y CONFIG_FDT_GPIO=y