diff options
| author | Nick Hu <nick.hu@sifive.com> | 2025-11-14 11:22:46 +0800 |
|---|---|---|
| committer | Anup Patel <anup@brainfault.org> | 2025-12-08 10:01:05 +0530 |
| commit | ec51e91eaa4e55e6babe0b37387645e75f7ded61 (patch) | |
| tree | e02edce7ec8f599df4beed17b943a748cdf346ac /lib/utils/cache | |
| parent | 35aece218a1da347e7c276a18c4ccdbda32ebec9 (diff) | |
| download | opensbi-ec51e91eaa4e55e6babe0b37387645e75f7ded61.zip opensbi-ec51e91eaa4e55e6babe0b37387645e75f7ded61.tar.gz opensbi-ec51e91eaa4e55e6babe0b37387645e75f7ded61.tar.bz2 | |
lib: utils/cache: Add SiFive PL2 controller
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@sifive.com>
Signed-off-by: Eric Lin <eric.lin@sifive.com>
Co-developed-by: Zong Li <zong.li@sifive.com>
Signed-off-by: Zong Li <zong.li@sifive.com>
Co-developed-by: Vincent Chen <vincent.chen@sifive.com>
Signed-off-by: Vincent Chen <vincent.chen@sifive.com>
Co-developed-by: Samuel Holland <samuel.holland@sifive.com>
Signed-off-by: Samuel Holland <samuel.holland@sifive.com>
Signed-off-by: Nick Hu <nick.hu@sifive.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Link: https://lore.kernel.org/r/20251114-sifive-cache-drivers-v1-2-8423a721924c@sifive.com
Signed-off-by: Anup Patel <anup@brainfault.org>
Diffstat (limited to 'lib/utils/cache')
| -rw-r--r-- | lib/utils/cache/Kconfig | 4 | ||||
| -rw-r--r-- | lib/utils/cache/fdt_sifive_pl2.c | 139 | ||||
| -rw-r--r-- | lib/utils/cache/objects.mk | 3 |
3 files changed, 146 insertions, 0 deletions
diff --git a/lib/utils/cache/Kconfig b/lib/utils/cache/Kconfig index 1c7abdc..e28262f 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 0000000..8069e96 --- /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)); +#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, ®_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 6829a96..37d250d 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 |
