fu540_ccache.c revision 1.1
11.1Sskrll/* $NetBSD: fu540_ccache.c,v 1.1 2024/01/13 17:01:58 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.1Sskrll__KERNEL_RCSID(0, "$NetBSD: fu540_ccache.c,v 1.1 2024/01/13 17:01:58 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.1Sskrll DEVICE_COMPAT_EOL 791.1Sskrll}; 801.1Sskrll 811.1Sskrllstruct fu540_ccache_softc { 821.1Sskrll device_t sc_dev; 831.1Sskrll bus_space_tag_t sc_bst; 841.1Sskrll bus_space_handle_t sc_bsh; 851.1Sskrll 861.1Sskrll uint32_t sc_line_size; 871.1Sskrll uint32_t sc_size; 881.1Sskrll uint32_t sc_sets; 891.1Sskrll uint32_t sc_level; 901.1Sskrll}; 911.1Sskrll 921.1Sskrll 931.1Sskrllstatic struct fu540_ccache_softc *fu540_ccache_sc; 941.1Sskrll 951.1Sskrll#define RD4(sc, reg) \ 961.1Sskrll bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) 971.1Sskrll#define WR4(sc, reg, val) \ 981.1Sskrll bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) 991.1Sskrll#define WR8(sc, reg, val) \ 1001.1Sskrll bus_space_write_8((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) 1011.1Sskrll 1021.1Sskrll 1031.1Sskrllstatic void 1041.1Sskrllfu540_ccache_cache_wbinv_range(vaddr_t va, paddr_t pa, psize_t len) 1051.1Sskrll{ 1061.1Sskrll struct fu540_ccache_softc * const sc = fu540_ccache_sc; 1071.1Sskrll 1081.1Sskrll KASSERT(powerof2(sc->sc_line_size)); 1091.1Sskrll KASSERT(len != 0); 1101.1Sskrll 1111.1Sskrll const paddr_t spa = rounddown2(pa, sc->sc_line_size); 1121.1Sskrll const paddr_t epa = roundup2(pa + len, sc->sc_line_size); 1131.1Sskrll 1141.1Sskrll asm volatile ("fence iorw,iorw" ::: "memory"); 1151.1Sskrll 1161.1Sskrll for (paddr_t fpa = spa; fpa < epa; fpa += sc->sc_line_size) { 1171.1Sskrll#ifdef _LP64 1181.1Sskrll WR8(sc, CCACHE_FLUSH64, fpa); 1191.1Sskrll#else 1201.1Sskrll WR4(sc, CCACHE_FLUSH32, fpa >> 4); 1211.1Sskrll#endif 1221.1Sskrll asm volatile ("fence iorw,iorw" ::: "memory"); 1231.1Sskrll } 1241.1Sskrll} 1251.1Sskrll 1261.1Sskrll 1271.1Sskrllstatic int 1281.1Sskrllfu540_ccache_match(device_t parent, cfdata_t cf, void *aux) 1291.1Sskrll{ 1301.1Sskrll struct fdt_attach_args * const faa = aux; 1311.1Sskrll 1321.1Sskrll return of_compatible_match(faa->faa_phandle, compat_data); 1331.1Sskrll} 1341.1Sskrll 1351.1Sskrllstatic void 1361.1Sskrllfu540_ccache_attach(device_t parent, device_t self, void *aux) 1371.1Sskrll{ 1381.1Sskrll struct fu540_ccache_softc * const sc = device_private(self); 1391.1Sskrll const struct fdt_attach_args * const faa = aux; 1401.1Sskrll const int phandle = faa->faa_phandle; 1411.1Sskrll bus_addr_t addr; 1421.1Sskrll bus_size_t size; 1431.1Sskrll 1441.1Sskrll int error; 1451.1Sskrll error = fdtbus_get_reg(phandle, 0, &addr, &size); 1461.1Sskrll if (error) { 1471.1Sskrll aprint_error(": couldn't get registers\n"); 1481.1Sskrll return; 1491.1Sskrll } 1501.1Sskrll 1511.1Sskrll sc->sc_dev = self; 1521.1Sskrll sc->sc_bst = faa->faa_bst; 1531.1Sskrll 1541.1Sskrll error = bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh); 1551.1Sskrll if (error) { 1561.1Sskrll aprint_error(": couldn't map registers\n"); 1571.1Sskrll return; 1581.1Sskrll } 1591.1Sskrll 1601.1Sskrll int ret; 1611.1Sskrll ret = of_getprop_uint32(phandle, "cache-block-size", 1621.1Sskrll &sc->sc_line_size); 1631.1Sskrll if (ret < 0) { 1641.1Sskrll aprint_error(": can't get cache-block-size\n"); 1651.1Sskrll return; 1661.1Sskrll } 1671.1Sskrll 1681.1Sskrll ret = of_getprop_uint32(phandle, "cache-level", 1691.1Sskrll &sc->sc_level); 1701.1Sskrll if (ret < 0) { 1711.1Sskrll aprint_error(": can't get cache-level\n"); 1721.1Sskrll return; 1731.1Sskrll } 1741.1Sskrll 1751.1Sskrll ret = of_getprop_uint32(phandle, "cache-sets", 1761.1Sskrll &sc->sc_sets); 1771.1Sskrll if (ret < 0) { 1781.1Sskrll aprint_error(": can't get cache-sets\n"); 1791.1Sskrll return; 1801.1Sskrll } 1811.1Sskrll ret = of_getprop_uint32(phandle, "cache-size", 1821.1Sskrll &sc->sc_size); 1831.1Sskrll if (ret < 0) { 1841.1Sskrll aprint_error(": can't get cache-size\n"); 1851.1Sskrll return; 1861.1Sskrll } 1871.1Sskrll 1881.1Sskrll if (!of_hasprop(phandle, "cache-unified")) { 1891.1Sskrll aprint_error(": can't get cache-unified\n"); 1901.1Sskrll return; 1911.1Sskrll } 1921.1Sskrll 1931.1Sskrll uint32_t ways = sc->sc_size / (sc->sc_sets * sc->sc_line_size); 1941.1Sskrll 1951.1Sskrll aprint_naive("\n"); 1961.1Sskrll aprint_normal(": L%u cache controller. %u KiB/%uB %u-way (%u set).\n", 1971.1Sskrll sc->sc_level, sc->sc_size / 1024, sc->sc_line_size, ways, 1981.1Sskrll sc->sc_sets); 1991.1Sskrll 2001.1Sskrll uint32_t l2config = RD4(sc, CCACHE_CONFIG); 2011.1Sskrll 2021.1Sskrll aprint_debug_dev(self, "l2config %#10" PRIx32 "\n", 2031.1Sskrll l2config); 2041.1Sskrll aprint_verbose_dev(self, "No. of banks %4" __PRIuBIT "\n", 2051.1Sskrll __SHIFTOUT(l2config, CCACHE_CONFIG_BANKS_MASK)); 2061.1Sskrll aprint_verbose_dev(self, "No. of ways per bank %4" __PRIuBIT "\n", 2071.1Sskrll __SHIFTOUT(l2config, CCACHE_CONFIG_WAYS_MASK)); 2081.1Sskrll aprint_verbose_dev(self, "Sets per bank %4lu\n", 2091.1Sskrll 1UL << __SHIFTOUT(l2config, CCACHE_CONFIG_LGSETS_MASK)); 2101.1Sskrll aprint_verbose_dev(self, "Bytes per cache block %4lu\n", 2111.1Sskrll 1UL << __SHIFTOUT(l2config, CCACHE_CONFIG_LGBLOCKBYTES_MASK)); 2121.1Sskrll 2131.1Sskrll uint32_t l2wayenable = RD4(sc, CCACHE_WAYENABLE); 2141.1Sskrll 2151.1Sskrll aprint_verbose_dev(self, "Largest way enabled %4" PRIu32 "\n", 2161.1Sskrll l2wayenable); 2171.1Sskrll 2181.1Sskrll fu540_ccache_sc = sc; 2191.1Sskrll 2201.1Sskrll cpu_sdcache_wbinv_range = fu540_ccache_cache_wbinv_range; 2211.1Sskrll cpu_sdcache_inv_range = fu540_ccache_cache_wbinv_range; 2221.1Sskrll cpu_sdcache_wb_range = fu540_ccache_cache_wbinv_range; 2231.1Sskrll} 2241.1Sskrll 2251.1SskrllCFATTACH_DECL_NEW(fu540_ccache, sizeof(struct fu540_ccache_softc), 2261.1Sskrll fu540_ccache_match, fu540_ccache_attach, NULL, NULL); 227