From: Conor Dooley <conor@kernel.org> To: conor@kernel.org, arnd@arndb.de, palmer@dabbelt.com, prabhakar.csengg@gmail.com Cc: Conor Dooley <conor.dooley@microchip.com>, ajones@ventanamicro.com, aou@eecs.berkeley.edu, apatel@ventanamicro.com, atishp@rivosinc.com, biju.das.jz@bp.renesas.com, devicetree@vger.kernel.org, geert@linux-m68k.org, guoren@kernel.org, hch@infradead.org, heiko@sntech.de, jszhang@kernel.org, krzysztof.kozlowski+dt@linaro.org, linux-kernel@vger.kernel.org, linux-renesas-soc@vger.kernel.org, linux-riscv@lists.infradead.org, magnus.damm@gmail.com, nathan@kernel.org, paul.walmsley@sifive.com, philipp.tomsich@vrull.eu, prabhakar.mahadev-lad.rj@bp.renesas.com, robh+dt@kernel.org, samuel@sholland.org, soc@kernel.org Subject: [RFC v5.1 8/9] soc: renesas: Add L2 cache management for RZ/Five SoC Date: Tue, 3 Jan 2023 21:04:00 +0000 [thread overview] Message-ID: <20230103210400.3500626-9-conor@kernel.org> (raw) In-Reply-To: <Y62nOqzyuUKqYDpq@spud> From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com> I/O Coherence Port (IOCP) provides an AXI interface for connecting external non-caching masters, such as DMA controllers. The accesses from IOCP are coherent with D-Caches and L2 Cache. IOCP is a specification option and is disabled on the Renesas RZ/Five SoC due to this reason IP blocks using DMA will fail. The Andes AX45MP core has a Programmable Physical Memory Attributes (PMA) block that allows dynamic adjustment of memory attributes in the runtime. It contains a configurable amount of PMA entries implemented as CSR registers to control the attributes of memory locations in interest. Below are the memory attributes supported: * Device, Non-bufferable * Device, bufferable * Memory, Non-cacheable, Non-bufferable * Memory, Non-cacheable, Bufferable * Memory, Write-back, No-allocate * Memory, Write-back, Read-allocate * Memory, Write-back, Write-allocate * Memory, Write-back, Read and Write-allocate More info about PMA (section 10.3): Link: http://www.andestech.com/wp-content/uploads/AX45MP-1C-Rev.-5.0.0-Datasheet.pdf As a workaround for SoCs with IOCP disabled CMO needs to be handled by software. Firstly OpenSBI configures the memory region as "Memory, Non-cacheable, Bufferable" and passes this region as a global shared dma pool as a DT node. With DMA_GLOBAL_POOL enabled all DMA allocations happen from this region and synchronization callbacks are implemented to synchronize when doing DMA transactions. Example PMA region passes as a DT node from OpenSBI: reserved-memory { #address-cells = <2>; #size-cells = <2>; ranges; pma_resv0@58000000 { compatible = "shared-dma-pool"; reg = <0x0 0x58000000 0x0 0x08000000>; no-map; linux,dma-default; }; }; Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com> [Conor: moved the driver to drivers/cache] Signed-off-by: Conor Dooley <conor.dooley@microchip.com> --- arch/riscv/include/asm/errata_list.h | 28 ++- drivers/cache/Kconfig | 9 + drivers/cache/Makefile | 2 + drivers/cache/ax45mp_cache.c | 253 +++++++++++++++++++++++++++ drivers/soc/renesas/Kconfig | 4 + 5 files changed, 290 insertions(+), 6 deletions(-) create mode 100644 drivers/cache/ax45mp_cache.c diff --git a/arch/riscv/include/asm/errata_list.h b/arch/riscv/include/asm/errata_list.h index 48e899a8e7a9..7636b83c1ecb 100644 --- a/arch/riscv/include/asm/errata_list.h +++ b/arch/riscv/include/asm/errata_list.h @@ -125,8 +125,8 @@ asm volatile(ALTERNATIVE( \ #define THEAD_SYNC_S ".long 0x0190000b" #define ALT_CMO_OP(_op, _start, _size, _cachesize, _dir, _ops) \ -asm volatile(ALTERNATIVE_2( \ - __nops(6), \ +asm volatile(ALTERNATIVE_3( \ + __nops(14), \ "mv a0, %1\n\t" \ "j 2f\n\t" \ "3:\n\t" \ @@ -134,7 +134,7 @@ asm volatile(ALTERNATIVE_2( \ "add a0, a0, %0\n\t" \ "2:\n\t" \ "bltu a0, %2, 3b\n\t" \ - "nop", 0, CPUFEATURE_ZICBOM, CONFIG_RISCV_ISA_ZICBOM, \ + __nops(9), 0, CPUFEATURE_ZICBOM, CONFIG_RISCV_ISA_ZICBOM, \ "mv a0, %1\n\t" \ "j 2f\n\t" \ "3:\n\t" \ @@ -142,8 +142,24 @@ asm volatile(ALTERNATIVE_2( \ "add a0, a0, %0\n\t" \ "2:\n\t" \ "bltu a0, %2, 3b\n\t" \ - THEAD_SYNC_S, THEAD_VENDOR_ID, \ - ERRATA_THEAD_CMO, CONFIG_ERRATA_THEAD_CMO) \ + THEAD_SYNC_S "\n\t" \ + __nops(8), THEAD_VENDOR_ID, \ + ERRATA_THEAD_CMO, CONFIG_ERRATA_THEAD_CMO, \ + "addi sp,sp,-16\n\t" \ + "sd s0,0(sp)\n\t" \ + "sd ra,8(sp)\n\t" \ + "addi s0,sp,16\n\t" \ + "mv a4,%6\n\t" \ + "mv a3,%5\n\t" \ + "mv a2,%4\n\t" \ + "mv a1,%3\n\t" \ + "mv a0,%0\n\t" \ + "call cmo_patchfunc\n\t" \ + "ld ra,8(sp)\n\t" \ + "ld s0,0(sp)\n\t" \ + "addi sp,sp,16\n\t", \ + ANDESTECH_VENDOR_ID, ERRATA_ANDESTECH_NO_IOCP, \ + CONFIG_ERRATA_ANDES_CMO) \ : : "r"(_cachesize), \ "r"((unsigned long)(_start) & ~((_cachesize) - 1UL)), \ "r"((unsigned long)(_start) + (_size)), \ @@ -151,7 +167,7 @@ asm volatile(ALTERNATIVE_2( \ "r"((unsigned long)(_size)), \ "r"((unsigned long)(_dir)), \ "r"((unsigned long)(_ops)) \ - : "a0") + : "a0", "a1", "a2", "a3", "a4", "memory") #define THEAD_C9XX_RV_IRQ_PMU 17 #define THEAD_C9XX_CSR_SCOUNTEROF 0x5c5 diff --git a/drivers/cache/Kconfig b/drivers/cache/Kconfig index bc852f005c10..e3309a668d1b 100644 --- a/drivers/cache/Kconfig +++ b/drivers/cache/Kconfig @@ -6,6 +6,15 @@ menuconfig CACHE_CONTROLLER if CACHE_CONTROLLER +config AX45MP_L2_CACHE + bool "Andes Technology AX45MP L2 Cache controller" + depends on RISCV + depends on RISCV_SBI + default y + help + Support for the L2 cache controller on Andes Technology AX45MP + platforms. + config SIFIVE_CCACHE bool "Sifive Composable Cache controller" depends on RISCV diff --git a/drivers/cache/Makefile b/drivers/cache/Makefile index 1f5dc339bf82..f175d16d8611 100644 --- a/drivers/cache/Makefile +++ b/drivers/cache/Makefile @@ -1,3 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_AX45MP_L2_CACHE) += ax45mp_cache.o obj-$(CONFIG_SIFIVE_CCACHE) += sifive_ccache.o diff --git a/drivers/cache/ax45mp_cache.c b/drivers/cache/ax45mp_cache.c new file mode 100644 index 000000000000..a488b85b9eea --- /dev/null +++ b/drivers/cache/ax45mp_cache.c @@ -0,0 +1,253 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * non-coherent cache functions for Andes AX45MP + * + * Copyright (C) 2022 Renesas Electronics Corp. + */ + +#include <linux/cacheflush.h> +#include <linux/cacheinfo.h> +#include <linux/dma-direction.h> +#include <linux/of_address.h> +#include <linux/of_platform.h> + +#include <asm/cacheflush.h> +#include <asm/sbi.h> + +/* L2 cache registers */ +#define AX45MP_L2C_REG_CTL_OFFSET 0x8 + +#define AX45MP_L2C_REG_C0_CMD_OFFSET 0x40 +#define AX45MP_L2C_REG_C0_ACC_OFFSET 0x48 +#define AX45MP_L2C_REG_STATUS_OFFSET 0x80 + +/* D-cache operation */ +#define AX45MP_CCTL_L1D_VA_INVAL 0 +#define AX45MP_CCTL_L1D_VA_WB 1 + +/* L2 CCTL status */ +#define AX45MP_CCTL_L2_STATUS_IDLE 0 + +/* L2 CCTL status cores mask */ +#define AX45MP_CCTL_L2_STATUS_C0_MASK 0xf + +/* L2 cache operation */ +#define AX45MP_CCTL_L2_PA_INVAL 0x8 +#define AX45MP_CCTL_L2_PA_WB 0x9 + +#define AX45MP_L2C_REG_PER_CORE_OFFSET 0x10 +#define AX45MP_CCTL_L2_STATUS_PER_CORE_OFFSET 4 + +#define AX45MP_L2C_REG_CN_CMD_OFFSET(n) \ + (AX45MP_L2C_REG_C0_CMD_OFFSET + ((n) * AX45MP_L2C_REG_PER_CORE_OFFSET)) +#define AX45MP_L2C_REG_CN_ACC_OFFSET(n) \ + (AX45MP_L2C_REG_C0_ACC_OFFSET + ((n) * AX45MP_L2C_REG_PER_CORE_OFFSET)) +#define AX45MP_CCTL_L2_STATUS_CN_MASK(n) \ + (AX45MP_CCTL_L2_STATUS_C0_MASK << ((n) * AX45MP_CCTL_L2_STATUS_PER_CORE_OFFSET)) + +#define AX45MP_CCTL_REG_UCCTLBEGINADDR_NUM 0x80b +#define AX45MP_CCTL_REG_UCCTLCOMMAND_NUM 0x80c + +#define AX45MP_CACHE_LINE_SIZE 64 + +struct ax45mp_priv { + void __iomem *l2c_base; + u32 ax45mp_cache_line_size; +}; + +static struct ax45mp_priv *ax45mp_priv; +static struct riscv_cache_maint_ops ax45mp_cmos; + +/* L2 Cache operations */ +static inline uint32_t ax45mp_cpu_l2c_get_cctl_status(void) +{ + return readl(ax45mp_priv->l2c_base + AX45MP_L2C_REG_STATUS_OFFSET); +} + +/* + * Software trigger CCTL operation (cache maintenance operations) by writing + * to ucctlcommand and ucctlbeginaddr registers and write-back an L2 cache + * entry. + */ +static void ax45mp_cpu_dcache_wb_range(void *start, void *end, int line_size) +{ + void __iomem *base = ax45mp_priv->l2c_base; + int mhartid = smp_processor_id(); + unsigned long pa; + + while (end > start) { + csr_write(AX45MP_CCTL_REG_UCCTLBEGINADDR_NUM, start); + csr_write(AX45MP_CCTL_REG_UCCTLCOMMAND_NUM, AX45MP_CCTL_L1D_VA_WB); + + pa = virt_to_phys(start); + writel(pa, base + AX45MP_L2C_REG_CN_ACC_OFFSET(mhartid)); + writel(AX45MP_CCTL_L2_PA_WB, + base + AX45MP_L2C_REG_CN_CMD_OFFSET(mhartid)); + while ((ax45mp_cpu_l2c_get_cctl_status() & + AX45MP_CCTL_L2_STATUS_CN_MASK(mhartid)) != + AX45MP_CCTL_L2_STATUS_IDLE) + ; + + start += line_size; + } +} + +/* + * Software trigger CCTL operation by writing to ucctlcommand and ucctlbeginaddr + * registers and invalidate the L2 cache entry. + */ +static void ax45mp_cpu_dcache_inval_range(void *start, void *end, int line_size) +{ + void __iomem *base = ax45mp_priv->l2c_base; + int mhartid = smp_processor_id(); + unsigned long pa; + + while (end > start) { + csr_write(AX45MP_CCTL_REG_UCCTLBEGINADDR_NUM, start); + csr_write(AX45MP_CCTL_REG_UCCTLCOMMAND_NUM, AX45MP_CCTL_L1D_VA_INVAL); + + pa = virt_to_phys(start); + writel(pa, base + AX45MP_L2C_REG_CN_ACC_OFFSET(mhartid)); + writel(AX45MP_CCTL_L2_PA_INVAL, + base + AX45MP_L2C_REG_CN_CMD_OFFSET(mhartid)); + while ((ax45mp_cpu_l2c_get_cctl_status() & + AX45MP_CCTL_L2_STATUS_CN_MASK(mhartid)) != + AX45MP_CCTL_L2_STATUS_IDLE) + ; + + start += line_size; + } +} + +static void ax45mp_cpu_dma_inval_range(void *vaddr, size_t size) +{ + char cache_buf[2][AX45MP_CACHE_LINE_SIZE]; + unsigned long start = (unsigned long)vaddr; + unsigned long end = start + size; + unsigned long old_start = start; + unsigned long old_end = end; + unsigned long line_size; + unsigned long flags; + + if (unlikely(start == end)) + return; + + line_size = ax45mp_priv->ax45mp_cache_line_size; + + memset(&cache_buf, 0x0, sizeof(cache_buf)); + start = start & (~(line_size - 1)); + end = ((end + line_size - 1) & (~(line_size - 1))); + + local_irq_save(flags); + if (unlikely(start != old_start)) + memcpy(&cache_buf[0][0], (void *)start, line_size); + + if (unlikely(end != old_end)) + memcpy(&cache_buf[1][0], (void *)(old_end & (~(line_size - 1))), line_size); + + ax45mp_cpu_dcache_inval_range(vaddr, (void *)end, line_size); + + if (unlikely(start != old_start)) + memcpy((void *)start, &cache_buf[0][0], (old_start & (line_size - 1))); + + local_irq_restore(flags); +} + +static void ax45mp_cpu_dma_wb_range(void *vaddr, size_t size) +{ + unsigned long start = (unsigned long)vaddr; + unsigned long end = start + size; + unsigned long line_size; + unsigned long flags; + + line_size = ax45mp_priv->ax45mp_cache_line_size; + local_irq_save(flags); + start = start & (~(line_size - 1)); + ax45mp_cpu_dcache_wb_range(vaddr, (void *)end, line_size); + local_irq_restore(flags); +} + +static void ax45mp_no_iocp_cmo(unsigned int cache_size, void *vaddr, size_t size, int dir, int ops) +{ + if (ops == NON_COHERENT_DMA_PREP) + return; + + if (ops == NON_COHERENT_SYNC_DMA_FOR_DEVICE) { + switch (dir) { + case DMA_FROM_DEVICE: + ax45mp_cpu_dma_inval_range(vaddr, size); + break; + case DMA_TO_DEVICE: + case DMA_BIDIRECTIONAL: + ax45mp_cpu_dma_wb_range(vaddr, size); + break; + default: + break; + } + return; + } + + /* op == NON_COHERENT_SYNC_DMA_FOR_CPU */ + if (dir == DMA_BIDIRECTIONAL || dir == DMA_FROM_DEVICE) + ax45mp_cpu_dma_inval_range(vaddr, size); +} + +static void ax45mp_configure_l2_cache(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct device *dev = &pdev->dev; + int ret; + + ret = of_property_read_u32(np, "cache-line-size", &ax45mp_priv->ax45mp_cache_line_size); + if (ret) { + dev_err(dev, "Failed to get cache-line-size, defaulting to 64 bytes\n"); + ax45mp_priv->ax45mp_cache_line_size = AX45MP_CACHE_LINE_SIZE; + } + + if (ax45mp_priv->ax45mp_cache_line_size != AX45MP_CACHE_LINE_SIZE) { + dev_err(dev, "Expected cache-line-size to be 64 bytes (found:%u). Defaulting to 64 bytes\n", + ax45mp_priv->ax45mp_cache_line_size); + ax45mp_priv->ax45mp_cache_line_size = AX45MP_CACHE_LINE_SIZE; + } +} + +static int ax45mp_l2c_probe(struct platform_device *pdev) +{ + ax45mp_priv = devm_kzalloc(&pdev->dev, sizeof(*ax45mp_priv), GFP_KERNEL); + if (!ax45mp_priv) + return -ENOMEM; + + ax45mp_priv->l2c_base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(ax45mp_priv->l2c_base)) + return PTR_ERR(ax45mp_priv->l2c_base); + + ax45mp_configure_l2_cache(pdev); + + ax45mp_cmos.cmo_patchfunc = ax45mp_no_iocp_cmo; + riscv_set_cache_maint_ops(&ax45mp_cmos); + + return 0; +} + +static const struct of_device_id ax45mp_cache_ids[] = { + { .compatible = "andestech,ax45mp-cache" }, + { /* sentinel */ } +}; + +static struct platform_driver ax45mp_l2c_driver = { + .driver = { + .name = "ax45mp-l2c", + .of_match_table = ax45mp_cache_ids, + }, + .probe = ax45mp_l2c_probe, +}; + +static int __init ax45mp_cache_init(void) +{ + return platform_driver_register(&ax45mp_l2c_driver); +} +arch_initcall(ax45mp_cache_init); + +MODULE_AUTHOR("Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>"); +MODULE_DESCRIPTION("Andes AX45MP L2 cache driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/soc/renesas/Kconfig b/drivers/soc/renesas/Kconfig index 660498252ec5..c3475c084685 100644 --- a/drivers/soc/renesas/Kconfig +++ b/drivers/soc/renesas/Kconfig @@ -340,6 +340,10 @@ if RISCV config ARCH_R9A07G043 bool "RISC-V Platform support for RZ/Five" select ARCH_RZG2L + select AX45MP_L2_CACHE + select DMA_GLOBAL_POOL + select ERRATA_ANDES + select ERRATA_ANDES_CMO help This enables support for the Renesas RZ/Five SoC. -- 2.39.0
WARNING: multiple messages have this Message-ID (diff)
From: Conor Dooley <conor@kernel.org> To: conor@kernel.org, arnd@arndb.de, palmer@dabbelt.com, prabhakar.csengg@gmail.com Cc: Conor Dooley <conor.dooley@microchip.com>, ajones@ventanamicro.com, aou@eecs.berkeley.edu, apatel@ventanamicro.com, atishp@rivosinc.com, biju.das.jz@bp.renesas.com, devicetree@vger.kernel.org, geert@linux-m68k.org, guoren@kernel.org, hch@infradead.org, heiko@sntech.de, jszhang@kernel.org, krzysztof.kozlowski+dt@linaro.org, linux-kernel@vger.kernel.org, linux-renesas-soc@vger.kernel.org, linux-riscv@lists.infradead.org, magnus.damm@gmail.com, nathan@kernel.org, paul.walmsley@sifive.com, philipp.tomsich@vrull.eu, prabhakar.mahadev-lad.rj@bp.renesas.com, robh+dt@kernel.org, samuel@sholland.org, soc@kernel.org Subject: [RFC v5.1 8/9] soc: renesas: Add L2 cache management for RZ/Five SoC Date: Tue, 3 Jan 2023 21:04:00 +0000 [thread overview] Message-ID: <20230103210400.3500626-9-conor@kernel.org> (raw) In-Reply-To: <Y62nOqzyuUKqYDpq@spud> From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com> I/O Coherence Port (IOCP) provides an AXI interface for connecting external non-caching masters, such as DMA controllers. The accesses from IOCP are coherent with D-Caches and L2 Cache. IOCP is a specification option and is disabled on the Renesas RZ/Five SoC due to this reason IP blocks using DMA will fail. The Andes AX45MP core has a Programmable Physical Memory Attributes (PMA) block that allows dynamic adjustment of memory attributes in the runtime. It contains a configurable amount of PMA entries implemented as CSR registers to control the attributes of memory locations in interest. Below are the memory attributes supported: * Device, Non-bufferable * Device, bufferable * Memory, Non-cacheable, Non-bufferable * Memory, Non-cacheable, Bufferable * Memory, Write-back, No-allocate * Memory, Write-back, Read-allocate * Memory, Write-back, Write-allocate * Memory, Write-back, Read and Write-allocate More info about PMA (section 10.3): Link: http://www.andestech.com/wp-content/uploads/AX45MP-1C-Rev.-5.0.0-Datasheet.pdf As a workaround for SoCs with IOCP disabled CMO needs to be handled by software. Firstly OpenSBI configures the memory region as "Memory, Non-cacheable, Bufferable" and passes this region as a global shared dma pool as a DT node. With DMA_GLOBAL_POOL enabled all DMA allocations happen from this region and synchronization callbacks are implemented to synchronize when doing DMA transactions. Example PMA region passes as a DT node from OpenSBI: reserved-memory { #address-cells = <2>; #size-cells = <2>; ranges; pma_resv0@58000000 { compatible = "shared-dma-pool"; reg = <0x0 0x58000000 0x0 0x08000000>; no-map; linux,dma-default; }; }; Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com> [Conor: moved the driver to drivers/cache] Signed-off-by: Conor Dooley <conor.dooley@microchip.com> --- arch/riscv/include/asm/errata_list.h | 28 ++- drivers/cache/Kconfig | 9 + drivers/cache/Makefile | 2 + drivers/cache/ax45mp_cache.c | 253 +++++++++++++++++++++++++++ drivers/soc/renesas/Kconfig | 4 + 5 files changed, 290 insertions(+), 6 deletions(-) create mode 100644 drivers/cache/ax45mp_cache.c diff --git a/arch/riscv/include/asm/errata_list.h b/arch/riscv/include/asm/errata_list.h index 48e899a8e7a9..7636b83c1ecb 100644 --- a/arch/riscv/include/asm/errata_list.h +++ b/arch/riscv/include/asm/errata_list.h @@ -125,8 +125,8 @@ asm volatile(ALTERNATIVE( \ #define THEAD_SYNC_S ".long 0x0190000b" #define ALT_CMO_OP(_op, _start, _size, _cachesize, _dir, _ops) \ -asm volatile(ALTERNATIVE_2( \ - __nops(6), \ +asm volatile(ALTERNATIVE_3( \ + __nops(14), \ "mv a0, %1\n\t" \ "j 2f\n\t" \ "3:\n\t" \ @@ -134,7 +134,7 @@ asm volatile(ALTERNATIVE_2( \ "add a0, a0, %0\n\t" \ "2:\n\t" \ "bltu a0, %2, 3b\n\t" \ - "nop", 0, CPUFEATURE_ZICBOM, CONFIG_RISCV_ISA_ZICBOM, \ + __nops(9), 0, CPUFEATURE_ZICBOM, CONFIG_RISCV_ISA_ZICBOM, \ "mv a0, %1\n\t" \ "j 2f\n\t" \ "3:\n\t" \ @@ -142,8 +142,24 @@ asm volatile(ALTERNATIVE_2( \ "add a0, a0, %0\n\t" \ "2:\n\t" \ "bltu a0, %2, 3b\n\t" \ - THEAD_SYNC_S, THEAD_VENDOR_ID, \ - ERRATA_THEAD_CMO, CONFIG_ERRATA_THEAD_CMO) \ + THEAD_SYNC_S "\n\t" \ + __nops(8), THEAD_VENDOR_ID, \ + ERRATA_THEAD_CMO, CONFIG_ERRATA_THEAD_CMO, \ + "addi sp,sp,-16\n\t" \ + "sd s0,0(sp)\n\t" \ + "sd ra,8(sp)\n\t" \ + "addi s0,sp,16\n\t" \ + "mv a4,%6\n\t" \ + "mv a3,%5\n\t" \ + "mv a2,%4\n\t" \ + "mv a1,%3\n\t" \ + "mv a0,%0\n\t" \ + "call cmo_patchfunc\n\t" \ + "ld ra,8(sp)\n\t" \ + "ld s0,0(sp)\n\t" \ + "addi sp,sp,16\n\t", \ + ANDESTECH_VENDOR_ID, ERRATA_ANDESTECH_NO_IOCP, \ + CONFIG_ERRATA_ANDES_CMO) \ : : "r"(_cachesize), \ "r"((unsigned long)(_start) & ~((_cachesize) - 1UL)), \ "r"((unsigned long)(_start) + (_size)), \ @@ -151,7 +167,7 @@ asm volatile(ALTERNATIVE_2( \ "r"((unsigned long)(_size)), \ "r"((unsigned long)(_dir)), \ "r"((unsigned long)(_ops)) \ - : "a0") + : "a0", "a1", "a2", "a3", "a4", "memory") #define THEAD_C9XX_RV_IRQ_PMU 17 #define THEAD_C9XX_CSR_SCOUNTEROF 0x5c5 diff --git a/drivers/cache/Kconfig b/drivers/cache/Kconfig index bc852f005c10..e3309a668d1b 100644 --- a/drivers/cache/Kconfig +++ b/drivers/cache/Kconfig @@ -6,6 +6,15 @@ menuconfig CACHE_CONTROLLER if CACHE_CONTROLLER +config AX45MP_L2_CACHE + bool "Andes Technology AX45MP L2 Cache controller" + depends on RISCV + depends on RISCV_SBI + default y + help + Support for the L2 cache controller on Andes Technology AX45MP + platforms. + config SIFIVE_CCACHE bool "Sifive Composable Cache controller" depends on RISCV diff --git a/drivers/cache/Makefile b/drivers/cache/Makefile index 1f5dc339bf82..f175d16d8611 100644 --- a/drivers/cache/Makefile +++ b/drivers/cache/Makefile @@ -1,3 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_AX45MP_L2_CACHE) += ax45mp_cache.o obj-$(CONFIG_SIFIVE_CCACHE) += sifive_ccache.o diff --git a/drivers/cache/ax45mp_cache.c b/drivers/cache/ax45mp_cache.c new file mode 100644 index 000000000000..a488b85b9eea --- /dev/null +++ b/drivers/cache/ax45mp_cache.c @@ -0,0 +1,253 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * non-coherent cache functions for Andes AX45MP + * + * Copyright (C) 2022 Renesas Electronics Corp. + */ + +#include <linux/cacheflush.h> +#include <linux/cacheinfo.h> +#include <linux/dma-direction.h> +#include <linux/of_address.h> +#include <linux/of_platform.h> + +#include <asm/cacheflush.h> +#include <asm/sbi.h> + +/* L2 cache registers */ +#define AX45MP_L2C_REG_CTL_OFFSET 0x8 + +#define AX45MP_L2C_REG_C0_CMD_OFFSET 0x40 +#define AX45MP_L2C_REG_C0_ACC_OFFSET 0x48 +#define AX45MP_L2C_REG_STATUS_OFFSET 0x80 + +/* D-cache operation */ +#define AX45MP_CCTL_L1D_VA_INVAL 0 +#define AX45MP_CCTL_L1D_VA_WB 1 + +/* L2 CCTL status */ +#define AX45MP_CCTL_L2_STATUS_IDLE 0 + +/* L2 CCTL status cores mask */ +#define AX45MP_CCTL_L2_STATUS_C0_MASK 0xf + +/* L2 cache operation */ +#define AX45MP_CCTL_L2_PA_INVAL 0x8 +#define AX45MP_CCTL_L2_PA_WB 0x9 + +#define AX45MP_L2C_REG_PER_CORE_OFFSET 0x10 +#define AX45MP_CCTL_L2_STATUS_PER_CORE_OFFSET 4 + +#define AX45MP_L2C_REG_CN_CMD_OFFSET(n) \ + (AX45MP_L2C_REG_C0_CMD_OFFSET + ((n) * AX45MP_L2C_REG_PER_CORE_OFFSET)) +#define AX45MP_L2C_REG_CN_ACC_OFFSET(n) \ + (AX45MP_L2C_REG_C0_ACC_OFFSET + ((n) * AX45MP_L2C_REG_PER_CORE_OFFSET)) +#define AX45MP_CCTL_L2_STATUS_CN_MASK(n) \ + (AX45MP_CCTL_L2_STATUS_C0_MASK << ((n) * AX45MP_CCTL_L2_STATUS_PER_CORE_OFFSET)) + +#define AX45MP_CCTL_REG_UCCTLBEGINADDR_NUM 0x80b +#define AX45MP_CCTL_REG_UCCTLCOMMAND_NUM 0x80c + +#define AX45MP_CACHE_LINE_SIZE 64 + +struct ax45mp_priv { + void __iomem *l2c_base; + u32 ax45mp_cache_line_size; +}; + +static struct ax45mp_priv *ax45mp_priv; +static struct riscv_cache_maint_ops ax45mp_cmos; + +/* L2 Cache operations */ +static inline uint32_t ax45mp_cpu_l2c_get_cctl_status(void) +{ + return readl(ax45mp_priv->l2c_base + AX45MP_L2C_REG_STATUS_OFFSET); +} + +/* + * Software trigger CCTL operation (cache maintenance operations) by writing + * to ucctlcommand and ucctlbeginaddr registers and write-back an L2 cache + * entry. + */ +static void ax45mp_cpu_dcache_wb_range(void *start, void *end, int line_size) +{ + void __iomem *base = ax45mp_priv->l2c_base; + int mhartid = smp_processor_id(); + unsigned long pa; + + while (end > start) { + csr_write(AX45MP_CCTL_REG_UCCTLBEGINADDR_NUM, start); + csr_write(AX45MP_CCTL_REG_UCCTLCOMMAND_NUM, AX45MP_CCTL_L1D_VA_WB); + + pa = virt_to_phys(start); + writel(pa, base + AX45MP_L2C_REG_CN_ACC_OFFSET(mhartid)); + writel(AX45MP_CCTL_L2_PA_WB, + base + AX45MP_L2C_REG_CN_CMD_OFFSET(mhartid)); + while ((ax45mp_cpu_l2c_get_cctl_status() & + AX45MP_CCTL_L2_STATUS_CN_MASK(mhartid)) != + AX45MP_CCTL_L2_STATUS_IDLE) + ; + + start += line_size; + } +} + +/* + * Software trigger CCTL operation by writing to ucctlcommand and ucctlbeginaddr + * registers and invalidate the L2 cache entry. + */ +static void ax45mp_cpu_dcache_inval_range(void *start, void *end, int line_size) +{ + void __iomem *base = ax45mp_priv->l2c_base; + int mhartid = smp_processor_id(); + unsigned long pa; + + while (end > start) { + csr_write(AX45MP_CCTL_REG_UCCTLBEGINADDR_NUM, start); + csr_write(AX45MP_CCTL_REG_UCCTLCOMMAND_NUM, AX45MP_CCTL_L1D_VA_INVAL); + + pa = virt_to_phys(start); + writel(pa, base + AX45MP_L2C_REG_CN_ACC_OFFSET(mhartid)); + writel(AX45MP_CCTL_L2_PA_INVAL, + base + AX45MP_L2C_REG_CN_CMD_OFFSET(mhartid)); + while ((ax45mp_cpu_l2c_get_cctl_status() & + AX45MP_CCTL_L2_STATUS_CN_MASK(mhartid)) != + AX45MP_CCTL_L2_STATUS_IDLE) + ; + + start += line_size; + } +} + +static void ax45mp_cpu_dma_inval_range(void *vaddr, size_t size) +{ + char cache_buf[2][AX45MP_CACHE_LINE_SIZE]; + unsigned long start = (unsigned long)vaddr; + unsigned long end = start + size; + unsigned long old_start = start; + unsigned long old_end = end; + unsigned long line_size; + unsigned long flags; + + if (unlikely(start == end)) + return; + + line_size = ax45mp_priv->ax45mp_cache_line_size; + + memset(&cache_buf, 0x0, sizeof(cache_buf)); + start = start & (~(line_size - 1)); + end = ((end + line_size - 1) & (~(line_size - 1))); + + local_irq_save(flags); + if (unlikely(start != old_start)) + memcpy(&cache_buf[0][0], (void *)start, line_size); + + if (unlikely(end != old_end)) + memcpy(&cache_buf[1][0], (void *)(old_end & (~(line_size - 1))), line_size); + + ax45mp_cpu_dcache_inval_range(vaddr, (void *)end, line_size); + + if (unlikely(start != old_start)) + memcpy((void *)start, &cache_buf[0][0], (old_start & (line_size - 1))); + + local_irq_restore(flags); +} + +static void ax45mp_cpu_dma_wb_range(void *vaddr, size_t size) +{ + unsigned long start = (unsigned long)vaddr; + unsigned long end = start + size; + unsigned long line_size; + unsigned long flags; + + line_size = ax45mp_priv->ax45mp_cache_line_size; + local_irq_save(flags); + start = start & (~(line_size - 1)); + ax45mp_cpu_dcache_wb_range(vaddr, (void *)end, line_size); + local_irq_restore(flags); +} + +static void ax45mp_no_iocp_cmo(unsigned int cache_size, void *vaddr, size_t size, int dir, int ops) +{ + if (ops == NON_COHERENT_DMA_PREP) + return; + + if (ops == NON_COHERENT_SYNC_DMA_FOR_DEVICE) { + switch (dir) { + case DMA_FROM_DEVICE: + ax45mp_cpu_dma_inval_range(vaddr, size); + break; + case DMA_TO_DEVICE: + case DMA_BIDIRECTIONAL: + ax45mp_cpu_dma_wb_range(vaddr, size); + break; + default: + break; + } + return; + } + + /* op == NON_COHERENT_SYNC_DMA_FOR_CPU */ + if (dir == DMA_BIDIRECTIONAL || dir == DMA_FROM_DEVICE) + ax45mp_cpu_dma_inval_range(vaddr, size); +} + +static void ax45mp_configure_l2_cache(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct device *dev = &pdev->dev; + int ret; + + ret = of_property_read_u32(np, "cache-line-size", &ax45mp_priv->ax45mp_cache_line_size); + if (ret) { + dev_err(dev, "Failed to get cache-line-size, defaulting to 64 bytes\n"); + ax45mp_priv->ax45mp_cache_line_size = AX45MP_CACHE_LINE_SIZE; + } + + if (ax45mp_priv->ax45mp_cache_line_size != AX45MP_CACHE_LINE_SIZE) { + dev_err(dev, "Expected cache-line-size to be 64 bytes (found:%u). Defaulting to 64 bytes\n", + ax45mp_priv->ax45mp_cache_line_size); + ax45mp_priv->ax45mp_cache_line_size = AX45MP_CACHE_LINE_SIZE; + } +} + +static int ax45mp_l2c_probe(struct platform_device *pdev) +{ + ax45mp_priv = devm_kzalloc(&pdev->dev, sizeof(*ax45mp_priv), GFP_KERNEL); + if (!ax45mp_priv) + return -ENOMEM; + + ax45mp_priv->l2c_base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(ax45mp_priv->l2c_base)) + return PTR_ERR(ax45mp_priv->l2c_base); + + ax45mp_configure_l2_cache(pdev); + + ax45mp_cmos.cmo_patchfunc = ax45mp_no_iocp_cmo; + riscv_set_cache_maint_ops(&ax45mp_cmos); + + return 0; +} + +static const struct of_device_id ax45mp_cache_ids[] = { + { .compatible = "andestech,ax45mp-cache" }, + { /* sentinel */ } +}; + +static struct platform_driver ax45mp_l2c_driver = { + .driver = { + .name = "ax45mp-l2c", + .of_match_table = ax45mp_cache_ids, + }, + .probe = ax45mp_l2c_probe, +}; + +static int __init ax45mp_cache_init(void) +{ + return platform_driver_register(&ax45mp_l2c_driver); +} +arch_initcall(ax45mp_cache_init); + +MODULE_AUTHOR("Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>"); +MODULE_DESCRIPTION("Andes AX45MP L2 cache driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/soc/renesas/Kconfig b/drivers/soc/renesas/Kconfig index 660498252ec5..c3475c084685 100644 --- a/drivers/soc/renesas/Kconfig +++ b/drivers/soc/renesas/Kconfig @@ -340,6 +340,10 @@ if RISCV config ARCH_R9A07G043 bool "RISC-V Platform support for RZ/Five" select ARCH_RZG2L + select AX45MP_L2_CACHE + select DMA_GLOBAL_POOL + select ERRATA_ANDES + select ERRATA_ANDES_CMO help This enables support for the Renesas RZ/Five SoC. -- 2.39.0 _______________________________________________ linux-riscv mailing list linux-riscv@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-riscv
next prev parent reply other threads:[~2023-01-03 21:05 UTC|newest] Thread overview: 132+ messages / expand[flat|nested] mbox.gz Atom feed top 2022-12-12 11:54 [PATCH v5 0/6] AX45MP: Add support to non-coherent DMA Prabhakar 2022-12-12 11:54 ` Prabhakar 2022-12-12 11:55 ` [PATCH v5 1/6] riscv: asm: alternative-macros: Introduce ALTERNATIVE_3() macro Prabhakar 2022-12-12 11:55 ` Prabhakar 2022-12-12 12:32 ` Heiko Stuebner 2022-12-12 12:32 ` Heiko Stuebner 2022-12-13 17:21 ` Geert Uytterhoeven 2022-12-13 17:21 ` Geert Uytterhoeven 2022-12-13 17:49 ` Lad, Prabhakar 2022-12-13 17:49 ` Lad, Prabhakar 2022-12-14 14:34 ` Andrew Jones 2022-12-14 14:34 ` Andrew Jones 2022-12-17 21:41 ` Conor Dooley 2022-12-17 21:41 ` Conor Dooley 2022-12-19 11:15 ` Lad, Prabhakar 2022-12-19 11:15 ` Lad, Prabhakar 2022-12-19 16:22 ` Conor Dooley 2022-12-19 16:22 ` Conor Dooley 2022-12-19 16:24 ` Lad, Prabhakar 2022-12-19 16:24 ` Lad, Prabhakar 2022-12-12 11:55 ` [PATCH v5 2/6] riscv: asm: vendorid_list: Add Andes Technology to the vendors list Prabhakar 2022-12-12 11:55 ` Prabhakar 2022-12-12 11:55 ` [PATCH v5 3/6] riscv: errata: Add Andes alternative ports Prabhakar 2022-12-12 11:55 ` Prabhakar 2022-12-17 21:19 ` Conor Dooley 2022-12-17 21:19 ` Conor Dooley 2022-12-19 11:19 ` Lad, Prabhakar 2022-12-19 11:19 ` Lad, Prabhakar 2022-12-19 16:20 ` Conor Dooley 2022-12-19 16:20 ` Conor Dooley 2022-12-21 0:31 ` Lad, Prabhakar 2022-12-21 0:31 ` Lad, Prabhakar 2022-12-12 11:55 ` [PATCH v5 4/6] riscv: mm: dma-noncoherent: Pass direction and operation to ALT_CMO_OP() Prabhakar 2022-12-12 11:55 ` Prabhakar 2022-12-13 17:14 ` Geert Uytterhoeven 2022-12-13 17:14 ` Geert Uytterhoeven 2022-12-13 17:57 ` Lad, Prabhakar 2022-12-13 17:57 ` Lad, Prabhakar 2022-12-17 20:52 ` Conor Dooley 2022-12-17 20:52 ` Conor Dooley 2022-12-19 11:21 ` Lad, Prabhakar 2022-12-19 11:21 ` Lad, Prabhakar 2022-12-12 11:55 ` [PATCH v5 5/6] dt-bindings: cache: r9a07g043f-l2-cache: Add DT binding documentation for L2 cache controller Prabhakar 2022-12-12 11:55 ` Prabhakar 2022-12-12 17:28 ` Rob Herring 2022-12-12 17:28 ` Rob Herring 2022-12-12 11:55 ` [PATCH v5 6/6] soc: renesas: Add L2 cache management for RZ/Five SoC Prabhakar 2022-12-12 11:55 ` Prabhakar 2022-12-15 10:34 ` Geert Uytterhoeven 2022-12-15 10:34 ` Geert Uytterhoeven 2022-12-15 11:03 ` Lad, Prabhakar 2022-12-15 11:03 ` Lad, Prabhakar 2022-12-15 11:10 ` Geert Uytterhoeven 2022-12-15 11:10 ` Geert Uytterhoeven 2022-12-15 17:46 ` Lad, Prabhakar 2022-12-15 17:46 ` Lad, Prabhakar 2022-12-15 19:54 ` Conor Dooley 2022-12-15 19:54 ` Conor Dooley 2022-12-15 20:17 ` Geert Uytterhoeven 2022-12-15 20:17 ` Geert Uytterhoeven 2022-12-15 20:32 ` Conor Dooley 2022-12-15 20:32 ` Conor Dooley 2022-12-15 21:40 ` Palmer Dabbelt 2022-12-15 21:40 ` Palmer Dabbelt 2022-12-16 7:02 ` Christoph Hellwig 2022-12-16 7:02 ` Christoph Hellwig 2022-12-16 16:32 ` Palmer Dabbelt 2022-12-16 16:32 ` Palmer Dabbelt 2022-12-16 20:04 ` Arnd Bergmann 2022-12-16 20:04 ` Arnd Bergmann 2022-12-17 22:52 ` Conor Dooley 2022-12-17 22:52 ` Conor Dooley 2022-12-19 12:43 ` Lad, Prabhakar 2022-12-19 12:43 ` Lad, Prabhakar 2022-12-19 16:08 ` Conor Dooley 2022-12-19 16:08 ` Conor Dooley 2022-12-29 14:05 ` Arnd Bergmann 2022-12-29 14:05 ` Arnd Bergmann 2022-12-29 14:42 ` Conor Dooley 2022-12-29 14:42 ` Conor Dooley 2023-01-03 21:03 ` [RFC v5.1 0/9] Generic function based cache management operations (was Re: [PATCH v5 6/6] soc: renesas: Add L2 cache management for RZ/Five SoC) Conor Dooley 2023-01-03 21:03 ` Conor Dooley 2023-01-03 21:03 ` [RFC v5.1 1/9] riscv: asm: alternative-macros: Introduce ALTERNATIVE_3() macro Conor Dooley 2023-01-03 21:03 ` Conor Dooley 2023-01-03 21:03 ` [RFC v5.1 2/9] riscv: asm: vendorid_list: Add Andes Technology to the vendors list Conor Dooley 2023-01-03 21:03 ` Conor Dooley 2023-01-03 21:03 ` [RFC v5.1 3/9] riscv: errata: Add Andes alternative ports Conor Dooley 2023-01-03 21:03 ` Conor Dooley 2023-01-03 21:03 ` [RFC v5.1 4/9] riscv: mm: dma-noncoherent: Pass direction and operation to ALT_CMO_OP() Conor Dooley 2023-01-03 21:03 ` Conor Dooley 2023-01-03 21:03 ` [RFC v5.1 5/9] dt-bindings: cache: r9a07g043f-l2-cache: Add DT binding documentation for L2 cache controller Conor Dooley 2023-01-03 21:03 ` Conor Dooley 2023-01-03 21:03 ` [RFC v5.1 6/9] cache,soc: Move SiFive CCache driver & create drivers/cache Conor Dooley 2023-01-03 21:03 ` Conor Dooley 2023-01-04 9:50 ` Ben Dooks 2023-01-04 9:50 ` Ben Dooks 2023-01-04 10:18 ` Conor Dooley 2023-01-04 10:18 ` Conor Dooley 2023-01-03 21:03 ` [RFC v5.1 7/9] RISC-V: create a function based cache management interface Conor Dooley 2023-01-03 21:03 ` Conor Dooley 2023-01-03 21:04 ` Conor Dooley [this message] 2023-01-03 21:04 ` [RFC v5.1 8/9] soc: renesas: Add L2 cache management for RZ/Five SoC Conor Dooley 2023-01-03 21:04 ` [RFC v5.1 9/9] [DON'T APPLY] cache: sifive-ccache: add cache flushing capability Conor Dooley 2023-01-03 21:04 ` Conor Dooley 2023-01-03 21:25 ` Palmer Dabbelt 2023-01-03 21:25 ` Palmer Dabbelt 2023-01-03 21:28 ` Arnd Bergmann 2023-01-03 21:28 ` Arnd Bergmann 2023-01-04 0:00 ` Conor Dooley 2023-01-04 0:00 ` Conor Dooley 2023-01-04 8:17 ` Arnd Bergmann 2023-01-04 8:17 ` Arnd Bergmann 2023-01-04 9:23 ` Conor Dooley 2023-01-04 9:23 ` Conor Dooley 2023-01-04 10:19 ` Arnd Bergmann 2023-01-04 10:19 ` Arnd Bergmann 2023-01-04 11:56 ` Conor Dooley 2023-01-04 11:56 ` Conor Dooley 2023-01-04 12:18 ` Arnd Bergmann 2023-01-04 12:18 ` Arnd Bergmann 2023-01-04 13:20 ` Conor Dooley 2023-01-04 13:20 ` Conor Dooley 2023-01-04 14:15 ` Arnd Bergmann 2023-01-04 14:15 ` Arnd Bergmann 2023-01-04 9:45 ` Ben Dooks 2023-01-04 9:45 ` Ben Dooks 2023-01-04 9:57 ` Conor Dooley 2023-01-04 9:57 ` Conor Dooley 2022-12-17 21:35 ` [PATCH v5 6/6] soc: renesas: Add L2 cache management for RZ/Five SoC Conor Dooley 2022-12-17 21:35 ` Conor Dooley 2022-12-28 3:16 ` Samuel Holland 2022-12-28 3:16 ` Samuel Holland
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20230103210400.3500626-9-conor@kernel.org \ --to=conor@kernel.org \ --cc=ajones@ventanamicro.com \ --cc=aou@eecs.berkeley.edu \ --cc=apatel@ventanamicro.com \ --cc=arnd@arndb.de \ --cc=atishp@rivosinc.com \ --cc=biju.das.jz@bp.renesas.com \ --cc=conor.dooley@microchip.com \ --cc=devicetree@vger.kernel.org \ --cc=geert@linux-m68k.org \ --cc=guoren@kernel.org \ --cc=hch@infradead.org \ --cc=heiko@sntech.de \ --cc=jszhang@kernel.org \ --cc=krzysztof.kozlowski+dt@linaro.org \ --cc=linux-kernel@vger.kernel.org \ --cc=linux-renesas-soc@vger.kernel.org \ --cc=linux-riscv@lists.infradead.org \ --cc=magnus.damm@gmail.com \ --cc=nathan@kernel.org \ --cc=palmer@dabbelt.com \ --cc=paul.walmsley@sifive.com \ --cc=philipp.tomsich@vrull.eu \ --cc=prabhakar.csengg@gmail.com \ --cc=prabhakar.mahadev-lad.rj@bp.renesas.com \ --cc=robh+dt@kernel.org \ --cc=samuel@sholland.org \ --cc=soc@kernel.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.