11.2Sskrll/* $NetBSD: fu540_ccache.c,v 1.2 2024/01/14 07:13:15 skrll Exp $ */ 21.1Sskrll 31.1Sskrll/*- 41.1Sskrll * Copyright (c) 2023 The NetBSD Foundation, Inc. 51.1Sskrll * All rights reserved. 61.1Sskrll * 71.1Sskrll * This code is derived from software contributed to The NetBSD Foundation 81.1Sskrll * by Nick Hudson 91.1Sskrll * 101.1Sskrll * Redistribution and use in source and binary forms, with or without 111.1Sskrll * modification, are permitted provided that the following conditions 121.1Sskrll * are met: 131.1Sskrll * 1. Redistributions of source code must retain the above copyright 141.1Sskrll * notice, this list of conditions and the following disclaimer. 151.1Sskrll * 2. Redistributions in binary form must reproduce the above copyright 161.1Sskrll * notice, this list of conditions and the following disclaimer in the 171.1Sskrll * documentation and/or other materials provided with the distribution. 181.1Sskrll * 191.1Sskrll * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 201.1Sskrll * ``AS IS'' AND ANY EXPRESS OR IMPLinIED WARRANTIES, INCLUDING, BUT NOT LIMITED 211.1Sskrll * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 221.1Sskrll * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 231.1Sskrll * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 241.1Sskrll * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 251.1Sskrll * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 261.1Sskrll * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 271.1Sskrll * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 281.1Sskrll * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 291.1Sskrll * POSSIBILITY OF SUCH DAMAGE. 301.1Sskrll */ 311.1Sskrll 321.1Sskrll#include <sys/cdefs.h> 331.2Sskrll__KERNEL_RCSID(0, "$NetBSD: fu540_ccache.c,v 1.2 2024/01/14 07:13:15 skrll Exp $"); 341.1Sskrll 351.1Sskrll#include <sys/param.h> 361.1Sskrll 371.1Sskrll#include <sys/bus.h> 381.1Sskrll 391.1Sskrll#include <dev/fdt/fdtvar.h> 401.1Sskrll 411.1Sskrll#include <machine/cpufunc.h> 421.1Sskrll 431.1Sskrll#define CCACHE_CONFIG 0x0000 441.1Sskrll#define CCACHE_CONFIG_BANKS_MASK __BITS( 7, 0) 451.1Sskrll#define CCACHE_CONFIG_WAYS_MASK __BITS(15, 8) 461.1Sskrll#define CCACHE_CONFIG_LGSETS_MASK __BITS(23, 16) 471.1Sskrll#define CCACHE_CONFIG_LGBLOCKBYTES_MASK __BITS(31, 24) 481.1Sskrll#define CCACHE_WAYENABLE 0x0008 491.1Sskrll 501.1Sskrll#define CCACHE_ECCINJECTERROR 0x0040 511.1Sskrll 521.1Sskrll#define CCACHE_DIRECCFIX_LOW 0x0100 531.1Sskrll#define CCACHE_DIRECCFIX_HIGH 0x0104 541.1Sskrll#define CCACHE_DIRECCFIX_COUNT 0x0108 551.1Sskrll 561.1Sskrll#define CCACHE_DIRECCFAIL_LOW 0x0120 571.1Sskrll#define CCACHE_DIRECCFAIL_HIGH 0x0124 581.1Sskrll#define CCACHE_DIRECCFAIL_COUNT 0x0128 591.1Sskrll 601.1Sskrll#define CCACHE_DATECCFIX_LOW 0x0140 611.1Sskrll#define CCACHE_DATECCFIX_HIGH 0x0144 621.1Sskrll#define CCACHE_DATECCFIX_COUNT 0x0148 631.1Sskrll 641.1Sskrll#define CCACHE_DATECCFAIL_LOW 0x0160 651.1Sskrll#define CCACHE_DATECCFAIL_HIGH 0x0164 661.1Sskrll#define CCACHE_DATECCFAIL_COUNT 0x0168 671.1Sskrll 681.1Sskrll#define CCACHE_FLUSH64 0x0200 691.1Sskrll#define CCACHE_FLUSH32 0x0250 701.1Sskrll 711.1Sskrll#define CCACHE_MAX_ECCINTR 4 721.1Sskrll 731.1Sskrll#define CCACHE_FLUSH64_LINE_LEN 64 741.1Sskrll 751.1Sskrllstatic const struct device_compatible_entry compat_data[] = { 761.1Sskrll { .compat = "sifive,fu540-c000-ccache" }, 771.1Sskrll { .compat = "sifive,fu740-c000-ccache" }, 781.2Sskrll { .compat = "starfive,jh7100-ccache" }, 791.2Sskrll { .compat = "starfive,jh7110-ccache" }, 801.2Sskrll { .compat = "starfive,ccache0" }, 811.1Sskrll DEVICE_COMPAT_EOL 821.1Sskrll}; 831.1Sskrll 841.1Sskrllstruct fu540_ccache_softc { 851.1Sskrll device_t sc_dev; 861.1Sskrll bus_space_tag_t sc_bst; 871.1Sskrll bus_space_handle_t sc_bsh; 881.1Sskrll 891.1Sskrll uint32_t sc_line_size; 901.1Sskrll uint32_t sc_size; 911.1Sskrll uint32_t sc_sets; 921.1Sskrll uint32_t sc_level; 931.1Sskrll}; 941.1Sskrll 951.1Sskrll 961.1Sskrllstatic struct fu540_ccache_softc *fu540_ccache_sc; 971.1Sskrll 981.1Sskrll#define RD4(sc, reg) \ 991.1Sskrll bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) 1001.1Sskrll#define WR4(sc, reg, val) \ 1011.1Sskrll bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) 1021.1Sskrll#define WR8(sc, reg, val) \ 1031.1Sskrll bus_space_write_8((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) 1041.1Sskrll 1051.1Sskrll 1061.1Sskrllstatic void 1071.1Sskrllfu540_ccache_cache_wbinv_range(vaddr_t va, paddr_t pa, psize_t len) 1081.1Sskrll{ 1091.1Sskrll struct fu540_ccache_softc * const sc = fu540_ccache_sc; 1101.1Sskrll 1111.1Sskrll KASSERT(powerof2(sc->sc_line_size)); 1121.1Sskrll KASSERT(len != 0); 1131.1Sskrll 1141.1Sskrll const paddr_t spa = rounddown2(pa, sc->sc_line_size); 1151.1Sskrll const paddr_t epa = roundup2(pa + len, sc->sc_line_size); 1161.1Sskrll 1171.1Sskrll asm volatile ("fence iorw,iorw" ::: "memory"); 1181.1Sskrll 1191.1Sskrll for (paddr_t fpa = spa; fpa < epa; fpa += sc->sc_line_size) { 1201.1Sskrll#ifdef _LP64 1211.1Sskrll WR8(sc, CCACHE_FLUSH64, fpa); 1221.1Sskrll#else 1231.1Sskrll WR4(sc, CCACHE_FLUSH32, fpa >> 4); 1241.1Sskrll#endif 1251.1Sskrll asm volatile ("fence iorw,iorw" ::: "memory"); 1261.1Sskrll } 1271.1Sskrll} 1281.1Sskrll 1291.1Sskrll 1301.1Sskrllstatic int 1311.1Sskrllfu540_ccache_match(device_t parent, cfdata_t cf, void *aux) 1321.1Sskrll{ 1331.1Sskrll struct fdt_attach_args * const faa = aux; 1341.1Sskrll 1351.1Sskrll return of_compatible_match(faa->faa_phandle, compat_data); 1361.1Sskrll} 1371.1Sskrll 1381.1Sskrllstatic void 1391.1Sskrllfu540_ccache_attach(device_t parent, device_t self, void *aux) 1401.1Sskrll{ 1411.1Sskrll struct fu540_ccache_softc * const sc = device_private(self); 1421.1Sskrll const struct fdt_attach_args * const faa = aux; 1431.1Sskrll const int phandle = faa->faa_phandle; 1441.1Sskrll bus_addr_t addr; 1451.1Sskrll bus_size_t size; 1461.1Sskrll 1471.1Sskrll int error; 1481.1Sskrll error = fdtbus_get_reg(phandle, 0, &addr, &size); 1491.1Sskrll if (error) { 1501.1Sskrll aprint_error(": couldn't get registers\n"); 1511.1Sskrll return; 1521.1Sskrll } 1531.1Sskrll 1541.1Sskrll sc->sc_dev = self; 1551.1Sskrll sc->sc_bst = faa->faa_bst; 1561.1Sskrll 1571.1Sskrll error = bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh); 1581.1Sskrll if (error) { 1591.1Sskrll aprint_error(": couldn't map registers\n"); 1601.1Sskrll return; 1611.1Sskrll } 1621.1Sskrll 1631.1Sskrll int ret; 1641.1Sskrll ret = of_getprop_uint32(phandle, "cache-block-size", 1651.1Sskrll &sc->sc_line_size); 1661.1Sskrll if (ret < 0) { 1671.1Sskrll aprint_error(": can't get cache-block-size\n"); 1681.1Sskrll return; 1691.1Sskrll } 1701.1Sskrll 1711.1Sskrll ret = of_getprop_uint32(phandle, "cache-level", 1721.1Sskrll &sc->sc_level); 1731.1Sskrll if (ret < 0) { 1741.1Sskrll aprint_error(": can't get cache-level\n"); 1751.1Sskrll return; 1761.1Sskrll } 1771.1Sskrll 1781.1Sskrll ret = of_getprop_uint32(phandle, "cache-sets", 1791.1Sskrll &sc->sc_sets); 1801.1Sskrll if (ret < 0) { 1811.1Sskrll aprint_error(": can't get cache-sets\n"); 1821.1Sskrll return; 1831.1Sskrll } 1841.1Sskrll ret = of_getprop_uint32(phandle, "cache-size", 1851.1Sskrll &sc->sc_size); 1861.1Sskrll if (ret < 0) { 1871.1Sskrll aprint_error(": can't get cache-size\n"); 1881.1Sskrll return; 1891.1Sskrll } 1901.1Sskrll 1911.1Sskrll if (!of_hasprop(phandle, "cache-unified")) { 1921.1Sskrll aprint_error(": can't get cache-unified\n"); 1931.1Sskrll return; 1941.1Sskrll } 1951.1Sskrll 1961.1Sskrll uint32_t ways = sc->sc_size / (sc->sc_sets * sc->sc_line_size); 1971.1Sskrll 1981.1Sskrll aprint_naive("\n"); 1991.1Sskrll aprint_normal(": L%u cache controller. %u KiB/%uB %u-way (%u set).\n", 2001.1Sskrll sc->sc_level, sc->sc_size / 1024, sc->sc_line_size, ways, 2011.1Sskrll sc->sc_sets); 2021.1Sskrll 2031.1Sskrll uint32_t l2config = RD4(sc, CCACHE_CONFIG); 2041.1Sskrll 2051.1Sskrll aprint_debug_dev(self, "l2config %#10" PRIx32 "\n", 2061.1Sskrll l2config); 2071.1Sskrll aprint_verbose_dev(self, "No. of banks %4" __PRIuBIT "\n", 2081.1Sskrll __SHIFTOUT(l2config, CCACHE_CONFIG_BANKS_MASK)); 2091.1Sskrll aprint_verbose_dev(self, "No. of ways per bank %4" __PRIuBIT "\n", 2101.1Sskrll __SHIFTOUT(l2config, CCACHE_CONFIG_WAYS_MASK)); 2111.1Sskrll aprint_verbose_dev(self, "Sets per bank %4lu\n", 2121.1Sskrll 1UL << __SHIFTOUT(l2config, CCACHE_CONFIG_LGSETS_MASK)); 2131.1Sskrll aprint_verbose_dev(self, "Bytes per cache block %4lu\n", 2141.1Sskrll 1UL << __SHIFTOUT(l2config, CCACHE_CONFIG_LGBLOCKBYTES_MASK)); 2151.1Sskrll 2161.1Sskrll uint32_t l2wayenable = RD4(sc, CCACHE_WAYENABLE); 2171.1Sskrll 2181.1Sskrll aprint_verbose_dev(self, "Largest way enabled %4" PRIu32 "\n", 2191.1Sskrll l2wayenable); 2201.1Sskrll 2211.1Sskrll fu540_ccache_sc = sc; 2221.1Sskrll 2231.1Sskrll cpu_sdcache_wbinv_range = fu540_ccache_cache_wbinv_range; 2241.1Sskrll cpu_sdcache_inv_range = fu540_ccache_cache_wbinv_range; 2251.1Sskrll cpu_sdcache_wb_range = fu540_ccache_cache_wbinv_range; 2261.1Sskrll} 2271.1Sskrll 2281.1SskrllCFATTACH_DECL_NEW(fu540_ccache, sizeof(struct fu540_ccache_softc), 2291.1Sskrll fu540_ccache_match, fu540_ccache_attach, NULL, NULL); 230