Joshua Yeong wrote: > Add StarFive Starlink cache management driver for > JH8100 SoC. This driver enables RISC-V > non-standard cache operation on JH8100 that does > not support Zicbom extension instructions. > > Signed-off-by: Joshua Yeong <joshua.yeong@xxxxxxxxxxxxxxxx> > --- > drivers/cache/Kconfig | 9 ++ > drivers/cache/Makefile | 5 +- > drivers/cache/starfive_starlink_cache.c | 135 ++++++++++++++++++++++++ > 3 files changed, 147 insertions(+), 2 deletions(-) > create mode 100644 drivers/cache/starfive_starlink_cache.c > > diff --git a/drivers/cache/Kconfig b/drivers/cache/Kconfig > index 9345ce4976d7..9181cd391f53 100644 > --- a/drivers/cache/Kconfig > +++ b/drivers/cache/Kconfig > @@ -14,4 +14,13 @@ config SIFIVE_CCACHE > help > Support for the composable cache controller on SiFive platforms. > > +config STARFIVE_STARLINK_CACHE > + bool "StarFive StarLink Cache controller" > + depends on RISCV > + depends on ARCH_STARFIVE > + select RISCV_DMA_NONCOHERENT > + select RISCV_NONSTANDARD_CACHE_OPS > + help > + Support for the StarLink cache controller on StarFive platforms. This is a bit misleading. The JH71x0s don't have this. It's only on the JH8100 so far, and hopefully later SoCs will just implement RISC-V standards for this. So maybe something like "Support for the StarLink cache controller on the StarFive JH8100 SoC." > + > endmenu > diff --git a/drivers/cache/Makefile b/drivers/cache/Makefile > index 7657cff3bd6c..55c5e851034d 100644 > --- a/drivers/cache/Makefile > +++ b/drivers/cache/Makefile > @@ -1,4 +1,5 @@ > # SPDX-License-Identifier: GPL-2.0 > > -obj-$(CONFIG_AX45MP_L2_CACHE) += ax45mp_cache.o > -obj-$(CONFIG_SIFIVE_CCACHE) += sifive_ccache.o > +obj-$(CONFIG_AX45MP_L2_CACHE) += ax45mp_cache.o > +obj-$(CONFIG_SIFIVE_CCACHE) += sifive_ccache.o > +obj-$(CONFIG_STARFIVE_STARLINK_CACHE) += starfive_starlink_cache.o > diff --git a/drivers/cache/starfive_starlink_cache.c b/drivers/cache/starfive_starlink_cache.c > new file mode 100644 > index 000000000000..2f1fa6a923ee > --- /dev/null > +++ b/drivers/cache/starfive_starlink_cache.c > @@ -0,0 +1,135 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Cache Management Operations for StarFive's Starlink cache controller > + * > + * Copyright (C) 2024 Shanghai StarFive Technology Co., Ltd. > + * > + * Author: Joshua Yeong <joshua.yeong@xxxxxxxxxxxxxxxx> > + */ > + > +#include <linux/bitfield.h> > +#include <linux/cacheflush.h> > +#include <linux/iopoll.h> > +#include <linux/of_address.h> > + > +#include <asm/dma-noncoherent.h> > + > +#define STARLINK_CACHE_FLUSH_START_ADDR 0x0 > +#define STARLINK_CACHE_FLUSH_END_ADDR 0x8 > +#define STARLINK_CACHE_FLUSH_CTL 0x10 > +#define STARLINK_CACHE_ALIGN 0x40 > + > +#define STARLINK_CACHE_ADDRESS_RANGE_MASK GENMASK(39, 0) > +#define STARLINK_CACHE_FLUSH_CTL_MODE_MASK GENMASK(2, 1) > +#define STARLINK_CACHE_FLUSH_CTL_ENABLE_MASK BIT(0) > + > +#define STARLINK_CACHE_FLUSH_CTL_CLEAN_INVALIDATE 0 > +#define STARLINK_CACHE_FLUSH_CTL_MAKE_INVALIDATE 1 > +#define STARLINK_CACHE_FLUSH_CTL_CLEAN_SHARED 2 > +#define STARLINK_CACHE_FLUSH_POLL_DELAY_US 1 > +#define STARLINK_CACHE_FLUSH_TIMEOUT_US 5000000 > + > +struct starlink_cache_priv { > + void __iomem *base_addr; > +}; > + > +static struct starlink_cache_priv starlink_cache_priv; This could just be static void __iomem *starlink_cache_base; > + > +static void starlink_cache_flush_complete(void) > +{ > + volatile void __iomem *ctl = starlink_cache_priv.base_addr + > + STARLINK_CACHE_FLUSH_CTL; > + u64 v; > + int ret; > + > + ret = readq_poll_timeout_atomic(ctl, v, !(v & STARLINK_CACHE_FLUSH_CTL_ENABLE_MASK), > + STARLINK_CACHE_FLUSH_POLL_DELAY_US, > + STARLINK_CACHE_FLUSH_TIMEOUT_US); > + if (ret) > + WARN(1, "StarFive Starlink cache flush operation timeout\n"); > +} > + > +static void starlink_cache_dma_cache_wback(phys_addr_t paddr, unsigned long size) > +{ > + writeq(FIELD_PREP(STARLINK_CACHE_ADDRESS_RANGE_MASK, paddr), > + starlink_cache_priv.base_addr + STARLINK_CACHE_FLUSH_START_ADDR); > + writeq(FIELD_PREP(STARLINK_CACHE_ADDRESS_RANGE_MASK, paddr + size), > + starlink_cache_priv.base_addr + STARLINK_CACHE_FLUSH_END_ADDR); > + > + mb(); > + writeq(FIELD_PREP(STARLINK_CACHE_FLUSH_CTL_MODE_MASK, > + STARLINK_CACHE_FLUSH_CTL_CLEAN_SHARED), > + starlink_cache_priv.base_addr + STARLINK_CACHE_FLUSH_CTL); > + > + starlink_cache_flush_complete(); > +} > + > +static void starlink_cache_dma_cache_invalidate(phys_addr_t paddr, unsigned long size) > +{ > + writeq(FIELD_PREP(STARLINK_CACHE_ADDRESS_RANGE_MASK, paddr), > + starlink_cache_priv.base_addr + STARLINK_CACHE_FLUSH_START_ADDR); > + writeq(FIELD_PREP(STARLINK_CACHE_ADDRESS_RANGE_MASK, paddr + size), > + starlink_cache_priv.base_addr + STARLINK_CACHE_FLUSH_END_ADDR); > + > + mb(); > + writeq(FIELD_PREP(STARLINK_CACHE_FLUSH_CTL_MODE_MASK, > + STARLINK_CACHE_FLUSH_CTL_MAKE_INVALIDATE), > + starlink_cache_priv.base_addr + STARLINK_CACHE_FLUSH_CTL); > + > + starlink_cache_flush_complete(); > +} > + > +static void starlink_cache_dma_cache_wback_inv(phys_addr_t paddr, unsigned long size) > +{ > + writeq(FIELD_PREP(STARLINK_CACHE_ADDRESS_RANGE_MASK, paddr), > + starlink_cache_priv.base_addr + STARLINK_CACHE_FLUSH_START_ADDR); > + writeq(FIELD_PREP(STARLINK_CACHE_ADDRESS_RANGE_MASK, paddr + size), > + starlink_cache_priv.base_addr + STARLINK_CACHE_FLUSH_END_ADDR); > + > + mb(); > + writeq(FIELD_PREP(STARLINK_CACHE_FLUSH_CTL_MODE_MASK, > + STARLINK_CACHE_FLUSH_CTL_CLEAN_INVALIDATE), > + starlink_cache_priv.base_addr + STARLINK_CACHE_FLUSH_CTL); > + > + starlink_cache_flush_complete(); > +} > + > +static const struct riscv_nonstd_cache_ops starlink_cache_ops = { > + .wback = &starlink_cache_dma_cache_wback, > + .inv = &starlink_cache_dma_cache_invalidate, > + .wback_inv = &starlink_cache_dma_cache_wback_inv, > +}; > + > +static const struct of_device_id starlink_cache_ids[] = { > + { .compatible = "starfive,jh8100-starlink-cache" }, > + { /* sentinel */ } > +}; > + > +static int __init starlink_cache_init(void) > +{ > + struct device_node *np; > + u32 block_size = 0; You return early if of_property_read_u32() fails, so this doesn't need to be initialized. > + int ret; > + > + np = of_find_matching_node(NULL, starlink_cache_ids); > + if (!of_device_is_available(np)) > + return -ENODEV; > + > + ret = of_property_read_u32(np, "cache-block-size", &block_size); > + if (ret) > + return ret; > + > + if (block_size % STARLINK_CACHE_ALIGN) > + return -EINVAL; > + > + starlink_cache_priv.base_addr = of_iomap(np, 0); > + if (!starlink_cache_priv.base_addr) > + return -ENOMEM; > + > + riscv_cbom_block_size = block_size; > + riscv_noncoherent_supported(); > + riscv_noncoherent_register_cache_ops(&starlink_cache_ops); > + > + return 0; > +} > +early_initcall(starlink_cache_init); The sifive driver gets away with arch_initcall() here. Any particular reason you need this earlier? > -- > 2.25.1 > > > _______________________________________________ > linux-riscv mailing list > linux-riscv@xxxxxxxxxxxxxxxxxxx > http://lists.infradead.org/mailman/listinfo/linux-riscv