fu540_ccache.c revision 1.1
1/*	$NetBSD: fu540_ccache.c,v 1.1 2024/01/13 17:01:58 skrll Exp $	*/
2
3/*-
4 * Copyright (c) 2023 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Nick Hudson
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLinIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include <sys/cdefs.h>
33__KERNEL_RCSID(0, "$NetBSD: fu540_ccache.c,v 1.1 2024/01/13 17:01:58 skrll Exp $");
34
35#include <sys/param.h>
36
37#include <sys/bus.h>
38
39#include <dev/fdt/fdtvar.h>
40
41#include <machine/cpufunc.h>
42
43#define CCACHE_CONFIG			0x0000
44#define  CCACHE_CONFIG_BANKS_MASK		__BITS( 7,  0)
45#define  CCACHE_CONFIG_WAYS_MASK		__BITS(15,  8)
46#define  CCACHE_CONFIG_LGSETS_MASK		__BITS(23, 16)
47#define  CCACHE_CONFIG_LGBLOCKBYTES_MASK	__BITS(31, 24)
48#define CCACHE_WAYENABLE		0x0008
49
50#define CCACHE_ECCINJECTERROR		0x0040
51
52#define CCACHE_DIRECCFIX_LOW		0x0100
53#define CCACHE_DIRECCFIX_HIGH		0x0104
54#define CCACHE_DIRECCFIX_COUNT 		0x0108
55
56#define CCACHE_DIRECCFAIL_LOW		0x0120
57#define CCACHE_DIRECCFAIL_HIGH	 	0x0124
58#define CCACHE_DIRECCFAIL_COUNT 	0x0128
59
60#define CCACHE_DATECCFIX_LOW		0x0140
61#define CCACHE_DATECCFIX_HIGH		0x0144
62#define CCACHE_DATECCFIX_COUNT		0x0148
63
64#define CCACHE_DATECCFAIL_LOW		0x0160
65#define CCACHE_DATECCFAIL_HIGH		0x0164
66#define CCACHE_DATECCFAIL_COUNT		0x0168
67
68#define CCACHE_FLUSH64			0x0200
69#define CCACHE_FLUSH32			0x0250
70
71#define CCACHE_MAX_ECCINTR		4
72
73#define CCACHE_FLUSH64_LINE_LEN		64
74
75static const struct device_compatible_entry compat_data[] = {
76	{ .compat = "sifive,fu540-c000-ccache" },
77	{ .compat = "sifive,fu740-c000-ccache" },
78	DEVICE_COMPAT_EOL
79};
80
81struct fu540_ccache_softc {
82	device_t		 sc_dev;
83	bus_space_tag_t		 sc_bst;
84	bus_space_handle_t	 sc_bsh;
85
86	uint32_t		 sc_line_size;
87	uint32_t		 sc_size;
88	uint32_t		 sc_sets;
89	uint32_t		 sc_level;
90};
91
92
93static struct fu540_ccache_softc *fu540_ccache_sc;
94
95#define RD4(sc, reg) \
96	bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
97#define	WR4(sc, reg, val) \
98	bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
99#define	WR8(sc, reg, val)						\
100	bus_space_write_8((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
101
102
103static void
104fu540_ccache_cache_wbinv_range(vaddr_t va, paddr_t pa, psize_t len)
105{
106	struct fu540_ccache_softc * const sc = fu540_ccache_sc;
107
108	KASSERT(powerof2(sc->sc_line_size));
109	KASSERT(len != 0);
110
111	const paddr_t spa = rounddown2(pa, sc->sc_line_size);
112	const paddr_t epa = roundup2(pa + len, sc->sc_line_size);
113
114	asm volatile ("fence iorw,iorw" ::: "memory");
115
116	for (paddr_t fpa = spa; fpa < epa; fpa += sc->sc_line_size) {
117#ifdef _LP64
118		WR8(sc, CCACHE_FLUSH64, fpa);
119#else
120		WR4(sc, CCACHE_FLUSH32, fpa >> 4);
121#endif
122		asm volatile ("fence iorw,iorw" ::: "memory");
123	}
124}
125
126
127static int
128fu540_ccache_match(device_t parent, cfdata_t cf, void *aux)
129{
130	struct fdt_attach_args * const faa = aux;
131
132	return of_compatible_match(faa->faa_phandle, compat_data);
133}
134
135static void
136fu540_ccache_attach(device_t parent, device_t self, void *aux)
137{
138	struct fu540_ccache_softc * const sc = device_private(self);
139	const struct fdt_attach_args * const faa = aux;
140	const int phandle = faa->faa_phandle;
141	bus_addr_t addr;
142	bus_size_t size;
143
144	int error;
145	error = fdtbus_get_reg(phandle, 0, &addr, &size);
146	if (error) {
147		aprint_error(": couldn't get registers\n");
148		return;
149	}
150
151	sc->sc_dev = self;
152	sc->sc_bst = faa->faa_bst;
153
154	error = bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh);
155	if (error) {
156		aprint_error(": couldn't map registers\n");
157		return;
158	}
159
160	int ret;
161	ret = of_getprop_uint32(phandle, "cache-block-size",
162	    &sc->sc_line_size);
163	if (ret < 0) {
164		aprint_error(": can't get cache-block-size\n");
165		return;
166	}
167
168	ret = of_getprop_uint32(phandle, "cache-level",
169	    &sc->sc_level);
170	if (ret < 0) {
171		aprint_error(": can't get cache-level\n");
172		return;
173	}
174
175	ret = of_getprop_uint32(phandle, "cache-sets",
176	    &sc->sc_sets);
177	if (ret < 0) {
178		aprint_error(": can't get cache-sets\n");
179		return;
180	}
181	ret = of_getprop_uint32(phandle, "cache-size",
182	    &sc->sc_size);
183	if (ret < 0) {
184		aprint_error(": can't get cache-size\n");
185		return;
186	}
187
188	if (!of_hasprop(phandle, "cache-unified")) {
189		aprint_error(": can't get cache-unified\n");
190		return;
191	}
192
193	uint32_t ways = sc->sc_size / (sc->sc_sets * sc->sc_line_size);
194
195	aprint_naive("\n");
196	aprint_normal(": L%u cache controller. %u KiB/%uB %u-way (%u set).\n",
197	    sc->sc_level, sc->sc_size / 1024, sc->sc_line_size, ways,
198	    sc->sc_sets);
199
200	uint32_t l2config = RD4(sc, CCACHE_CONFIG);
201
202	aprint_debug_dev(self,   "l2config        %#10" PRIx32 "\n",
203	    l2config);
204	aprint_verbose_dev(self, "No. of banks          %4" __PRIuBIT "\n",
205	    __SHIFTOUT(l2config, CCACHE_CONFIG_BANKS_MASK));
206	aprint_verbose_dev(self, "No. of ways per bank  %4" __PRIuBIT "\n",
207	    __SHIFTOUT(l2config, CCACHE_CONFIG_WAYS_MASK));
208	aprint_verbose_dev(self, "Sets per bank         %4lu\n",
209	    1UL << __SHIFTOUT(l2config, CCACHE_CONFIG_LGSETS_MASK));
210	aprint_verbose_dev(self, "Bytes per cache block %4lu\n",
211	    1UL << __SHIFTOUT(l2config, CCACHE_CONFIG_LGBLOCKBYTES_MASK));
212
213	uint32_t l2wayenable = RD4(sc, CCACHE_WAYENABLE);
214
215	aprint_verbose_dev(self, "Largest way enabled   %4" PRIu32 "\n",
216	    l2wayenable);
217
218	fu540_ccache_sc = sc;
219
220	cpu_sdcache_wbinv_range = fu540_ccache_cache_wbinv_range;
221	cpu_sdcache_inv_range = fu540_ccache_cache_wbinv_range;
222	cpu_sdcache_wb_range = fu540_ccache_cache_wbinv_range;
223}
224
225CFATTACH_DECL_NEW(fu540_ccache, sizeof(struct fu540_ccache_softc),
226	fu540_ccache_match, fu540_ccache_attach, NULL, NULL);
227