| Message ID | 20250708074940.10904-4-nick.hu@sifive.com |
|---|---|
| State | Changes Requested |
| Headers | show |
| Series | Add SiFive TMC0 and SMC0 driver | expand |
On Tue, Jul 8, 2025 at 1:20 PM Nick Hu <nick.hu@sifive.com> wrote: > > From: Vincent Chen <vincent.chen@sifive.com> > > 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 <samuel.holland@sifive.com> > Signed-off-by: Samuel Holland <samuel.holland@sifive.com> > Signed-off-by: Vincent Chen <vincent.chen@sifive.com> > Co-developed-by: Nick Hu <nick.hu@sifive.com> > Signed-off-by: Nick Hu <nick.hu@sifive.com> > Reviewed-by: Samuel Holland <samuel.holland@sifive.com> LGTM. Reviewed-by: Anup Patel <anup@brainfault.org> Regards, Anup > --- > 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..ad7511b5 > --- /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 <libfdt.h> > +#include <sbi/riscv_barrier.h> > +#include <sbi/riscv_io.h> > +#include <sbi/sbi_error.h> > +#include <sbi/sbi_heap.h> > +#include <sbi_utils/cache/fdt_cache.h> > +#include <sbi_utils/fdt/fdt_driver.h> > + > +#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((char *)reg_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 b5a7993d..6b219cfb 100644 > --- a/platform/generic/configs/defconfig > +++ b/platform/generic/configs/defconfig > @@ -8,6 +8,7 @@ CONFIG_PLATFORM_STARFIVE_JH7110=y > CONFIG_PLATFORM_THEAD=y > CONFIG_PLATFORM_MIPS_P8700=y > CONFIG_FDT_CACHE=y > +CONFIG_FDT_CACHE_SIFIVE_CCACHE=y > CONFIG_FDT_CPPC=y > CONFIG_FDT_CPPC_RPMI=y > CONFIG_FDT_GPIO=y > -- > 2.17.1 >
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..ad7511b5 --- /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 <libfdt.h> +#include <sbi/riscv_barrier.h> +#include <sbi/riscv_io.h> +#include <sbi/sbi_error.h> +#include <sbi/sbi_heap.h> +#include <sbi_utils/cache/fdt_cache.h> +#include <sbi_utils/fdt/fdt_driver.h> + +#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((char *)reg_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 b5a7993d..6b219cfb 100644 --- a/platform/generic/configs/defconfig +++ b/platform/generic/configs/defconfig @@ -8,6 +8,7 @@ CONFIG_PLATFORM_STARFIVE_JH7110=y CONFIG_PLATFORM_THEAD=y CONFIG_PLATFORM_MIPS_P8700=y CONFIG_FDT_CACHE=y +CONFIG_FDT_CACHE_SIFIVE_CCACHE=y CONFIG_FDT_CPPC=y CONFIG_FDT_CPPC_RPMI=y CONFIG_FDT_GPIO=y