[PATCH 3/3] lib: utils/cache: Add SiFive Extensible Cache (EC) driver
Anup Patel
anup at brainfault.org
Mon Dec 8 03:02:37 PST 2025
On Fri, Nov 14, 2025 at 8:46 AM Nick Hu <nick.hu at sifive.com> wrote:
>
> Add support for SiFive Extensible Cache (EC) controller with multi-slice
> architecture. The driver implements cache maintenance operations through
> MMIO register interface.
>
> Co-developed-by: Vincent Chen <vincent.chen at sifive.com>
> Signed-off-by: Vincent Chen <vincent.chen at sifive.com>
> Co-developed-by: Samuel Holland <samuel.holland at sifive.com>
> Signed-off-by: Samuel Holland <samuel.holland at sifive.com>
> Co-developed-by: Yong-Xuan Wang <yongxuan.wang at sifive.com>
> Signed-off-by: Yong-Xuan Wang <yongxuan.wang at sifive.com>
> Signed-off-by: Nick Hu <nick.hu at sifive.com>
LGTM.
Reviewed-by: Anup Patel <anup at brainfault.org>
Applied this patch to the riscv/opensbi repo.
Thanks,
Anup
> ---
> lib/utils/cache/Kconfig | 4 +
> lib/utils/cache/fdt_sifive_ec.c | 194 +++++++++++++++++++++++++++++++++++++
> lib/utils/cache/objects.mk | 3 +
> platform/generic/configs/defconfig | 1 +
> 4 files changed, 202 insertions(+)
>
> diff --git a/lib/utils/cache/Kconfig b/lib/utils/cache/Kconfig
> index e28262fa2e81328460c8ee9a34b841454d03d776..be7d57c37d2477e60fb793d42bd6cf2cd830b846 100644
> --- a/lib/utils/cache/Kconfig
> +++ b/lib/utils/cache/Kconfig
> @@ -14,6 +14,10 @@ config FDT_CACHE_SIFIVE_CCACHE
> bool "SiFive CCACHE FDT cache driver"
> default n
>
> +config FDT_CACHE_SIFIVE_EC
> + bool "SiFive EC FDT cache driver"
> + default n
> +
> config FDT_CACHE_SIFIVE_PL2
> bool "SiFive PL2 FDT cache driver"
> default n
> diff --git a/lib/utils/cache/fdt_sifive_ec.c b/lib/utils/cache/fdt_sifive_ec.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..53ef6edb24aee316652cbaf83fd34c7c159aba59
> --- /dev/null
> +++ b/lib/utils/cache/fdt_sifive_ec.c
> @@ -0,0 +1,194 @@
> +/*
> + * SPDX-License-Identifier: BSD-2-Clause
> + *
> + * Copyright (c) 2025 SiFive Inc.
> + */
> +
> +#include <libfdt.h>
> +#include <sbi/riscv_io.h>
> +#include <sbi/sbi_heap.h>
> +#include <sbi/sbi_platform.h>
> +#include <sbi_utils/cache/fdt_cache.h>
> +#include <sbi_utils/fdt/fdt_driver.h>
> +
> +#define SIFIVE_EC_FEATURE_DISABLE_OFF 0x100UL
> +#define SIFIVE_EC_FLUSH_CMD_OFF 0x800UL
> +#define SIFIVE_EC_FLUSH_STATUS_OFF 0x808UL
> +#define SIFIVE_EC_FLUSH_ADDR_OFF 0x810UL
> +#define SIFIVE_EC_MODE_CTRL 0xa00UL
> +
> +#define SIFIVE_EC_FLUSH_COMPLETION_MASK BIT(0)
> +
> +#define SIFIVE_EC_CLEANINV_ALL_CMD 0x3
> +
> +#define SIFIVE_EC_FEATURE_DISABLE_VAL 0
> +
> +struct sifive_ec_quirks {
> + bool two_mode;
> + char *reg_name;
> +};
> +
> +struct sifive_ec_slice {
> + void *addr;
> + bool last_slice;
> +};
> +
> +struct sifive_ec {
> + struct cache_device dev;
> + struct sifive_ec_slice *slices;
> +};
> +
> +#define to_ec(_dev) container_of(_dev, struct sifive_ec, dev)
> +
> +static int sifive_ec_flush_all(struct cache_device *dev)
> +{
> + struct sifive_ec *ec_dev = to_ec(dev);
> + struct sifive_ec_slice *slices = ec_dev->slices;
> + u32 cmd = SIFIVE_EC_CLEANINV_ALL_CMD, i = 0;
> + void *addr;
> +
> + do {
> + addr = slices[i].addr;
> +
> + writel((int)-1, addr + SIFIVE_EC_FLUSH_ADDR_OFF);
> + writel((int)-1, addr + SIFIVE_EC_FLUSH_ADDR_OFF + sizeof(u32));
> + writel(cmd, addr + SIFIVE_EC_FLUSH_CMD_OFF);
> + } while (!slices[i++].last_slice);
> +
> + i = 0;
> + do {
> + addr = slices[i].addr;
> + do {} while (!(readl(addr + SIFIVE_EC_FLUSH_STATUS_OFF) &
> + SIFIVE_EC_FLUSH_COMPLETION_MASK));
> + } while (!slices[i++].last_slice);
> +
> + return 0;
> +}
> +
> +int sifive_ec_warm_init(struct cache_device *dev)
> +{
> + struct sifive_ec *ec_dev = to_ec(dev);
> + struct sifive_ec_slice *slices = ec_dev->slices;
> + struct sbi_domain *dom = sbi_domain_thishart_ptr();
> + int i = 0;
> +
> + if (dom->boot_hartid == current_hartid()) {
> + do {
> + writel(SIFIVE_EC_FEATURE_DISABLE_VAL,
> + slices[i].addr + SIFIVE_EC_FEATURE_DISABLE_OFF);
> + } while (!slices[i++].last_slice);
> + }
> +
> + return SBI_OK;
> +}
> +
> +static struct cache_ops sifive_ec_ops = {
> + .warm_init = sifive_ec_warm_init,
> + .cache_flush_all = sifive_ec_flush_all,
> +};
> +
> +static int sifive_ec_slices_cold_init(const void *fdt, int nodeoff, struct sifive_ec_slice *slices,
> + const struct sifive_ec_quirks *quirks)
> +{
> + int rc, subnode, slice_idx = -1;
> + u64 reg_addr, size, start_addr = -1, end_addr = 0;
> +
> + fdt_for_each_subnode(subnode, fdt, nodeoff) {
> + rc = fdt_get_node_addr_size_by_name(fdt, subnode, quirks->reg_name, ®_addr,
> + &size);
> + if (rc < 0)
> + return SBI_ENODEV;
> +
> + if (reg_addr < start_addr)
> + start_addr = reg_addr;
> +
> + if (reg_addr + size > end_addr)
> + end_addr = reg_addr + size;
> +
> + slices[++slice_idx].addr = (void *)(uintptr_t)reg_addr;
> + }
> + slices[slice_idx].last_slice = true;
> +
> + /* Only enable the pmp to protect the EC m-mode region when it support two mode */
> + if (quirks->two_mode) {
> + rc = sbi_domain_root_add_memrange((unsigned long)start_addr,
> + (unsigned long)(end_addr - start_addr),
> + BIT(12),
> + (SBI_DOMAIN_MEMREGION_MMIO |
> + SBI_DOMAIN_MEMREGION_M_READABLE |
> + SBI_DOMAIN_MEMREGION_M_WRITABLE));
> + if (rc)
> + return rc;
> + }
> +
> + return SBI_OK;
> +}
> +
> +static int sifive_ec_cold_init(const void *fdt, int nodeoff, const struct fdt_match *match)
> +{
> + const struct sifive_ec_quirks *quirks = match->data;
> + struct sifive_ec_slice *slices;
> + struct sifive_ec *ec_dev;
> + struct cache_device *dev;
> + int subnode, rc = SBI_ENOMEM;
> + u32 slice_count = 0;
> +
> + /* Count the number of slices */
> + fdt_for_each_subnode(subnode, fdt, nodeoff)
> + slice_count++;
> +
> + /* Need at least one slice */
> + if (!slice_count)
> + return SBI_EINVAL;
> +
> + ec_dev = sbi_zalloc(sizeof(*ec_dev));
> + if (!ec_dev)
> + return SBI_ENOMEM;
> +
> + slices = sbi_zalloc(slice_count * sizeof(*slices));
> + if (!slices)
> + goto free_ec;
> +
> + rc = sifive_ec_slices_cold_init(fdt, nodeoff, slices, quirks);
> + if (rc)
> + goto free_slice;
> +
> + dev = &ec_dev->dev;
> + dev->ops = &sifive_ec_ops;
> + rc = fdt_cache_add(fdt, nodeoff, dev);
> + if (rc)
> + goto free_slice;
> +
> + ec_dev->slices = slices;
> +
> + return SBI_OK;
> +
> +free_slice:
> + sbi_free(slices);
> +free_ec:
> + sbi_free(ec_dev);
> + return rc;
> +}
> +
> +static const struct sifive_ec_quirks sifive_extensiblecache0_quirks = {
> + .two_mode = false,
> + .reg_name = "control",
> +};
> +
> +static const struct sifive_ec_quirks sifive_extensiblecache4_quirks = {
> + .two_mode = true,
> + .reg_name = "m_mode",
> +};
> +
> +static const struct fdt_match sifive_ec_match[] = {
> + { .compatible = "sifive,extensiblecache4", .data = &sifive_extensiblecache4_quirks },
> + { .compatible = "sifive,extensiblecache3", .data = &sifive_extensiblecache0_quirks },
> + { .compatible = "sifive,extensiblecache2", .data = &sifive_extensiblecache0_quirks },
> + { .compatible = "sifive,extensiblecache0", .data = &sifive_extensiblecache0_quirks },
> + {},
> +};
> +
> +struct fdt_driver fdt_sifive_ec = {
> + .match_table = sifive_ec_match,
> + .init = sifive_ec_cold_init,
> +};
> diff --git a/lib/utils/cache/objects.mk b/lib/utils/cache/objects.mk
> index 37d250d1001bc647e3ae05304b2278e5dc608cae..aa76adc2e3bc5efbaa32b4ead9849d8b62bb7747 100644
> --- a/lib/utils/cache/objects.mk
> +++ b/lib/utils/cache/objects.mk
> @@ -14,4 +14,7 @@ libsbiutils-objs-$(CONFIG_FDT_CACHE_SIFIVE_CCACHE) += cache/fdt_sifive_ccache.o
> carray-fdt_cache_drivers-$(CONFIG_FDT_CACHE_SIFIVE_PL2) += fdt_sifive_pl2
> libsbiutils-objs-$(CONFIG_FDT_CACHE_SIFIVE_PL2) += cache/fdt_sifive_pl2.o
>
> +carray-fdt_cache_drivers-$(CONFIG_FDT_CACHE_SIFIVE_EC) += fdt_sifive_ec
> +libsbiutils-objs-$(CONFIG_FDT_CACHE_SIFIVE_EC) += cache/fdt_sifive_ec.o
> +
> libsbiutils-objs-$(CONFIG_CACHE) += cache/cache.o
> diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig
> index 1bb14c78b9f0fc98493961023703a1ed2a24eea8..d0e2ec26bd60ad9394f631dd4d2870f5f2b90fd0 100644
> --- a/platform/generic/configs/defconfig
> +++ b/platform/generic/configs/defconfig
> @@ -13,6 +13,7 @@ CONFIG_PLATFORM_MIPS_P8700=y
> CONFIG_PLATFORM_SPACEMIT_K1=y
> CONFIG_FDT_CACHE=y
> CONFIG_FDT_CACHE_SIFIVE_CCACHE=y
> +CONFIG_FDT_CACHE_SIFIVE_EC=y
> CONFIG_FDT_CACHE_SIFIVE_PL2=y
> CONFIG_FDT_CPPC=y
> CONFIG_FDT_CPPC_RPMI=y
>
> --
> 2.34.1
>
>
> --
> opensbi mailing list
> opensbi at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/opensbi
More information about the opensbi
mailing list