Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

soc: sifive: ccache: Add StarFive JH7100 support

This adds support for the StarFive JH7100 SoC which also features this
SiFive cache controller.

The JH7100 has non-coherent DMAs but predate the standard RISC-V Zicbom
exension, so instead we need to use this cache controller for
non-standard cache management operations.

Unfortunately the interrupt for uncorrected data is broken on the JH7100
and fires continuously, so add a quirk to not register a handler for it.

Signed-off-by: Emil Renner Berthing <kernel@esmil.dk>
Signed-off-by: Conor Dooley <conor.dooley@microchip.com>

authored by

Emil Renner Berthing and committed by
Conor Dooley
0d5701dc 3d70b985

+60 -2
+60 -2
drivers/cache/sifive_ccache.c
··· 8 8 9 9 #define pr_fmt(fmt) "CCACHE: " fmt 10 10 11 + #include <linux/align.h> 11 12 #include <linux/debugfs.h> 12 13 #include <linux/interrupt.h> 13 14 #include <linux/of_irq.h> 14 15 #include <linux/of_address.h> 15 16 #include <linux/device.h> 16 17 #include <linux/bitfield.h> 18 + #include <asm/cacheflush.h> 17 19 #include <asm/cacheinfo.h> 20 + #include <asm/dma-noncoherent.h> 18 21 #include <soc/sifive/sifive_ccache.h> 19 22 20 23 #define SIFIVE_CCACHE_DIRECCFIX_LOW 0x100 ··· 42 39 #define SIFIVE_CCACHE_CONFIG_SETS_MASK GENMASK_ULL(23, 16) 43 40 #define SIFIVE_CCACHE_CONFIG_BLKS_MASK GENMASK_ULL(31, 24) 44 41 42 + #define SIFIVE_CCACHE_FLUSH64 0x200 43 + #define SIFIVE_CCACHE_FLUSH32 0x240 44 + 45 45 #define SIFIVE_CCACHE_WAYENABLE 0x08 46 46 #define SIFIVE_CCACHE_ECCINJECTERR 0x40 47 47 48 48 #define SIFIVE_CCACHE_MAX_ECCINTR 4 49 + #define SIFIVE_CCACHE_LINE_SIZE 64 49 50 50 51 static void __iomem *ccache_base; 51 52 static int g_irq[SIFIVE_CCACHE_MAX_ECCINTR]; ··· 61 54 DATA_CORR, 62 55 DATA_UNCORR, 63 56 DIR_UNCORR, 57 + }; 58 + 59 + enum { 60 + QUIRK_NONSTANDARD_CACHE_OPS = BIT(0), 61 + QUIRK_BROKEN_DATA_UNCORR = BIT(1), 64 62 }; 65 63 66 64 #ifdef CONFIG_DEBUG_FS ··· 118 106 static const struct of_device_id sifive_ccache_ids[] = { 119 107 { .compatible = "sifive,fu540-c000-ccache" }, 120 108 { .compatible = "sifive,fu740-c000-ccache" }, 109 + { .compatible = "starfive,jh7100-ccache", 110 + .data = (void *)(QUIRK_NONSTANDARD_CACHE_OPS | QUIRK_BROKEN_DATA_UNCORR) }, 121 111 { .compatible = "sifive,ccache0" }, 122 112 { /* end of table */ } 123 113 }; ··· 137 123 return atomic_notifier_chain_unregister(&ccache_err_chain, nb); 138 124 } 139 125 EXPORT_SYMBOL_GPL(unregister_sifive_ccache_error_notifier); 126 + 127 + #ifdef CONFIG_RISCV_NONSTANDARD_CACHE_OPS 128 + static void ccache_flush_range(phys_addr_t start, size_t len) 129 + { 130 + phys_addr_t end = start + len; 131 + phys_addr_t line; 132 + 133 + if (!len) 134 + return; 135 + 136 + mb(); 137 + for (line = ALIGN_DOWN(start, SIFIVE_CCACHE_LINE_SIZE); line < end; 138 + line += SIFIVE_CCACHE_LINE_SIZE) { 139 + #ifdef CONFIG_32BIT 140 + writel(line >> 4, ccache_base + SIFIVE_CCACHE_FLUSH32); 141 + #else 142 + writeq(line, ccache_base + SIFIVE_CCACHE_FLUSH64); 143 + #endif 144 + mb(); 145 + } 146 + } 147 + 148 + static const struct riscv_nonstd_cache_ops ccache_mgmt_ops __initconst = { 149 + .wback = &ccache_flush_range, 150 + .inv = &ccache_flush_range, 151 + .wback_inv = &ccache_flush_range, 152 + }; 153 + #endif /* CONFIG_RISCV_NONSTANDARD_CACHE_OPS */ 140 154 141 155 static int ccache_largest_wayenabled(void) 142 156 { ··· 252 210 struct device_node *np; 253 211 struct resource res; 254 212 int i, rc, intr_num; 213 + const struct of_device_id *match; 214 + unsigned long quirks; 255 215 256 - np = of_find_matching_node(NULL, sifive_ccache_ids); 216 + np = of_find_matching_node_and_match(NULL, sifive_ccache_ids, &match); 257 217 if (!np) 258 218 return -ENODEV; 219 + 220 + quirks = (uintptr_t)match->data; 259 221 260 222 if (of_address_to_resource(np, 0, &res)) { 261 223 rc = -ENODEV; ··· 286 240 287 241 for (i = 0; i < intr_num; i++) { 288 242 g_irq[i] = irq_of_parse_and_map(np, i); 243 + 244 + if (i == DATA_UNCORR && (quirks & QUIRK_BROKEN_DATA_UNCORR)) 245 + continue; 246 + 289 247 rc = request_irq(g_irq[i], ccache_int_handler, 0, "ccache_ecc", 290 248 NULL); 291 249 if (rc) { ··· 298 248 } 299 249 } 300 250 of_node_put(np); 251 + 252 + #ifdef CONFIG_RISCV_NONSTANDARD_CACHE_OPS 253 + if (quirks & QUIRK_NONSTANDARD_CACHE_OPS) { 254 + riscv_cbom_block_size = SIFIVE_CCACHE_LINE_SIZE; 255 + riscv_noncoherent_supported(); 256 + riscv_noncoherent_register_cache_ops(&ccache_mgmt_ops); 257 + } 258 + #endif 301 259 302 260 ccache_config_read(); 303 261 ··· 327 269 return rc; 328 270 } 329 271 330 - device_initcall(sifive_ccache_init); 272 + arch_initcall(sifive_ccache_init);