[PATCH 2/3] lib: utils/cache: Add SiFive PL2 controller

Anup Patel anup at brainfault.org
Mon Dec 8 03:02:32 PST 2025


On Fri, Nov 14, 2025 at 8:46 AM Nick Hu <nick.hu at sifive.com> wrote:
>
> SiFive Private L2(PL2) cache is a private cache owned by each hart. Add
> this driver to support private cache flush operations via the MMIO
> registers.
>
> Co-developed-by: Eric Lin <eric.lin at sifive.com>
> Signed-off-by: Eric Lin <eric.lin at sifive.com>
> Co-developed-by: Zong Li <zong.li at sifive.com>
> Signed-off-by: Zong Li <zong.li at sifive.com>
> 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>
> Signed-off-by: Nick Hu <nick.hu at sifive.com>
> ---
>  lib/utils/cache/Kconfig            |   4 ++
>  lib/utils/cache/fdt_sifive_pl2.c   | 139 +++++++++++++++++++++++++++++++++++++
>  lib/utils/cache/objects.mk         |   3 +
>  platform/generic/configs/defconfig |   1 +
>  4 files changed, 147 insertions(+)
>
> diff --git a/lib/utils/cache/Kconfig b/lib/utils/cache/Kconfig
> index 1c7abdc9ad93319569807b4e25623cac871c6ce3..e28262fa2e81328460c8ee9a34b841454d03d776 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_PL2
> +       bool "SiFive PL2 FDT cache driver"
> +       default n
> +
>  endif
>
>  config CACHE
> diff --git a/lib/utils/cache/fdt_sifive_pl2.c b/lib/utils/cache/fdt_sifive_pl2.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..afe5d6796dbf3504604642643b49cbb4ccc858c6
> --- /dev/null
> +++ b/lib/utils/cache/fdt_sifive_pl2.c
> @@ -0,0 +1,139 @@
> +/*
> + * SPDX-License-Identifier: BSD-2-Clause
> + *
> + * Copyright (c) 2025 SiFive Inc.
> + */
> +
> +#include <libfdt.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 FLUSH64_CMD_TARGET_ALL         (0x2 << 3)
> +#define FLUSH64_CMD_TYPE_FLUSH         0x3ULL
> +
> +#define SIFIVE_PL2CACHE_CMD_QLEN       0xff
> +
> +#define SIFIVE_PL2CACHE_FLUSH64_OFF    0x200ULL
> +#define SIFIVE_PL2CACHE_STATUS_OFF     0x208ULL
> +#define SIFIVE_PL2CACHE_CONFIG1_OFF    0x1000ULL
> +#define SIFIVE_PL2CACHE_CONFIG0_OFF    0x1008ULL
> +
> +#define FLUSH64_CMD_POS                        56
> +#define REGIONCLOCKDISABLE_MASK                BIT(3)
> +
> +#define CONFIG0_ACCEPT_DIRTY_DATA_ENABLE       BIT(24)
> +
> +struct sifive_pl2_quirks {
> +       bool no_dirty_fill;
> +};
> +
> +struct sifive_pl2 {
> +       struct cache_device dev;
> +       void *addr;
> +       bool no_dirty_fill;
> +};
> +
> +#define to_pl2(_dev) container_of(_dev, struct sifive_pl2, dev)
> +
> +static int sifive_pl2_flush_all(struct cache_device *dev)
> +{
> +       struct sifive_pl2 *pl2_dev = to_pl2(dev);
> +       char *addr = pl2_dev->addr;
> +       u64 cmd = (FLUSH64_CMD_TARGET_ALL | FLUSH64_CMD_TYPE_FLUSH) << FLUSH64_CMD_POS;
> +       u32 config0;
> +
> +       /*
> +        * While flushing pl2 cache, a speculative load might causes a dirty line pull into PL2. It
> +        * will cause the SiFive SMC0 refuse to enter the power gating. Disable the
> +        * ACCEPT_DIRTY_DATA_ENABLE to avoid the issue.
> +        */
> +       if (pl2_dev->no_dirty_fill) {
> +               config0 = readl((void *)addr + SIFIVE_PL2CACHE_CONFIG0_OFF);
> +               config0 &= ~CONFIG0_ACCEPT_DIRTY_DATA_ENABLE;
> +               writel(config0, (void *)addr + SIFIVE_PL2CACHE_CONFIG0_OFF);
> +       }
> +
> +#if __riscv_xlen != 32
> +       writeq(cmd, addr + SIFIVE_PL2CACHE_FLUSH64_OFF);
> +#else
> +       writel((u32)cmd, addr + SIFIVE_PL2CACHE_FLUSH64_OFF);
> +       writel((u32)cmd >> 32, addr + SIFIVE_PL2CACHE_FLUSH64_OFF + sizeof(u32));

This does not compile on RV32. I will fix it at the time of merging.

> +#endif
> +       do {} while (readl(addr + SIFIVE_PL2CACHE_STATUS_OFF) & SIFIVE_PL2CACHE_CMD_QLEN);
> +
> +       return 0;
> +}
> +
> +static int sifive_pl2_warm_init(struct cache_device *dev)
> +{
> +       struct sifive_pl2 *pl2_dev = to_pl2(dev);
> +       char *addr = pl2_dev->addr;
> +       u32 val;
> +
> +       /* Enabling the clock gating */
> +       val = readl(addr + SIFIVE_PL2CACHE_CONFIG1_OFF);
> +       val &= (~REGIONCLOCKDISABLE_MASK);
> +       writel(val, addr + SIFIVE_PL2CACHE_CONFIG1_OFF);
> +
> +       return 0;
> +}
> +
> +static struct cache_ops sifive_pl2_ops = {
> +       .warm_init = sifive_pl2_warm_init,
> +       .cache_flush_all = sifive_pl2_flush_all,
> +};
> +
> +static int sifive_pl2_cold_init(const void *fdt, int nodeoff, const struct fdt_match *match)
> +{
> +       const struct sifive_pl2_quirks *quirk = match->data;
> +       struct sifive_pl2 *pl2_dev;
> +       struct cache_device *dev;
> +       u64 reg_addr;
> +       int rc;
> +
> +       /* find the pl2 control base address */
> +       rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &reg_addr, NULL);
> +       if (rc < 0 && reg_addr)
> +               return SBI_ENODEV;
> +
> +       pl2_dev = sbi_zalloc(sizeof(*pl2_dev));
> +       if (!pl2_dev)
> +               return SBI_ENOMEM;
> +
> +       dev = &pl2_dev->dev;
> +       dev->ops = &sifive_pl2_ops;
> +       dev->cpu_private = true;
> +
> +       rc = fdt_cache_add(fdt, nodeoff, dev);
> +       if (rc)
> +               return rc;
> +
> +       pl2_dev->addr = (void *)(uintptr_t)reg_addr;
> +       if (quirk)
> +               pl2_dev->no_dirty_fill = quirk->no_dirty_fill;
> +
> +       return 0;
> +}
> +
> +static const struct sifive_pl2_quirks pl2cache2_quirks = {
> +       .no_dirty_fill = true,
> +};
> +
> +static const struct sifive_pl2_quirks pl2cache0_quirks = {
> +       .no_dirty_fill = false,
> +};
> +
> +static const struct fdt_match sifive_pl2_match[] = {
> +       { .compatible = "sifive,pl2cache2", .data = &pl2cache2_quirks },
> +       { .compatible = "sifive,pl2cache1", .data = &pl2cache0_quirks },
> +       { .compatible = "sifive,pl2cache0", .data = &pl2cache0_quirks },
> +       {},
> +};
> +
> +struct fdt_driver fdt_sifive_pl2 = {
> +       .match_table = sifive_pl2_match,
> +       .init = sifive_pl2_cold_init,
> +};
> diff --git a/lib/utils/cache/objects.mk b/lib/utils/cache/objects.mk
> index 6829a966784732127d93180b3eb46ed24de5bc7d..37d250d1001bc647e3ae05304b2278e5dc608cae 100644
> --- a/lib/utils/cache/objects.mk
> +++ b/lib/utils/cache/objects.mk
> @@ -11,4 +11,7 @@ libsbiutils-objs-$(CONFIG_FDT_CACHE) += cache/fdt_cmo_helper.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
>
> +carray-fdt_cache_drivers-$(CONFIG_FDT_CACHE_SIFIVE_PL2) += fdt_sifive_pl2
> +libsbiutils-objs-$(CONFIG_FDT_CACHE_SIFIVE_PL2) += cache/fdt_sifive_pl2.o
> +
>  libsbiutils-objs-$(CONFIG_CACHE) += cache/cache.o
> diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig
> index 3896b0e03268ad3520a3d1586b652e38c0b54ceb..1bb14c78b9f0fc98493961023703a1ed2a24eea8 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_PL2=y
>  CONFIG_FDT_CPPC=y
>  CONFIG_FDT_CPPC_RPMI=y
>  CONFIG_FDT_GPIO=y
>
> --
> 2.34.1
>
>
> --
> opensbi mailing list
> opensbi at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/opensbi

Otherwise, LGTM.

Reviewed-by: Anup Patel <anup at brainfault.org>

Applied this patch to the riscv/opensbi repo.

Thanks,
Anup



More information about the opensbi mailing list