ibm4xx_460ex_l2.c revision 1.1 1 1.1 rkujawa /* $NetBSD: ibm4xx_460ex_l2.c,v 1.1 2026/06/19 18:55:23 rkujawa Exp $ */
2 1.1 rkujawa
3 1.1 rkujawa /*
4 1.1 rkujawa * Copyright (c) 2026 The NetBSD Foundation, Inc.
5 1.1 rkujawa * All rights reserved.
6 1.1 rkujawa *
7 1.1 rkujawa * This code is derived from software contributed to The NetBSD Foundation
8 1.1 rkujawa * by Radoslaw Kujawa.
9 1.1 rkujawa *
10 1.1 rkujawa * Redistribution and use in source and binary forms, with or without
11 1.1 rkujawa * modification, are permitted provided that the following conditions
12 1.1 rkujawa * are met:
13 1.1 rkujawa * 1. Redistributions of source code must retain the above copyright
14 1.1 rkujawa * notice, this list of conditions and the following disclaimer.
15 1.1 rkujawa * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 rkujawa * notice, this list of conditions and the following disclaimer in the
17 1.1 rkujawa * documentation and/or other materials provided with the distribution.
18 1.1 rkujawa *
19 1.1 rkujawa * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 1.1 rkujawa * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.1 rkujawa * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.1 rkujawa * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 1.1 rkujawa * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 1.1 rkujawa * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 1.1 rkujawa * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.1 rkujawa * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.1 rkujawa * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.1 rkujawa * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.1 rkujawa * POSSIBILITY OF SUCH DAMAGE.
30 1.1 rkujawa */
31 1.1 rkujawa
32 1.1 rkujawa /*
33 1.1 rkujawa * AMCC PPC460EX on-chip 256KB L2 cache support
34 1.1 rkujawa */
35 1.1 rkujawa
36 1.1 rkujawa #include <sys/cdefs.h>
37 1.1 rkujawa __KERNEL_RCSID(0, "$NetBSD: ibm4xx_460ex_l2.c,v 1.1 2026/06/19 18:55:23 rkujawa Exp $");
38 1.1 rkujawa
39 1.1 rkujawa #include "opt_ppc4xx.h"
40 1.1 rkujawa
41 1.1 rkujawa #include <sys/param.h>
42 1.1 rkujawa #include <sys/systm.h>
43 1.1 rkujawa #include <sys/intr.h>
44 1.1 rkujawa
45 1.1 rkujawa #define _POWERPC_BUS_DMA_PRIVATE
46 1.1 rkujawa #include <sys/bus.h>
47 1.1 rkujawa
48 1.1 rkujawa #include <powerpc/ibm4xx/cpu.h>
49 1.1 rkujawa #include <powerpc/ibm4xx/amcc460ex.h>
50 1.1 rkujawa #include <powerpc/ibm4xx/ibm4xx_460ex_l2.h>
51 1.1 rkujawa
52 1.1 rkujawa #define L2_LINE_SIZE 32
53 1.1 rkujawa #define L2_WAYS 4
54 1.1 rkujawa #define L2_SIZE (256 * 1024)
55 1.1 rkujawa #define L2_INDEX_SPAN (L2_SIZE / L2_WAYS) /* 64KB */
56 1.1 rkujawa
57 1.1 rkujawa bool ibm4xx_460ex_l2_enabled = false;
58 1.1 rkujawa uint32_t ibm4xx_460ex_l2_cfg;
59 1.1 rkujawa
60 1.1 rkujawa /*
61 1.1 rkujawa * Build the L2C0_ADDR val for an invalidate command
62 1.1 rkujawa */
63 1.1 rkujawa static inline uint32_t
64 1.1 rkujawa ibm4xx_460ex_l2_addr(bus_addr_t pa)
65 1.1 rkujawa {
66 1.1 rkujawa return (uint32_t)pa & 0xfffffff0;
67 1.1 rkujawa }
68 1.1 rkujawa
69 1.1 rkujawa /*
70 1.1 rkujawa * Invalidate the L2 lines backing the (offset, offset+len) window
71 1.1 rkujawa */
72 1.1 rkujawa static void
73 1.1 rkujawa ibm4xx_460ex_l2_invalidate(bus_dma_tag_t t, bus_dmamap_t map,
74 1.1 rkujawa bus_addr_t offset, bus_size_t len)
75 1.1 rkujawa {
76 1.1 rkujawa const bus_dma_segment_t *ds = map->dm_segs;
77 1.1 rkujawa int s;
78 1.1 rkujawa
79 1.1 rkujawa if (len == 0)
80 1.1 rkujawa return;
81 1.1 rkujawa
82 1.1 rkujawa s = splhigh();
83 1.1 rkujawa
84 1.1 rkujawa if (len >= L2_INDEX_SPAN) {
85 1.1 rkujawa /* Window sweeps every index: one whole-cache invalidate. */
86 1.1 rkujawa mtdcr(DCR_L2C0_ADDR, 0);
87 1.1 rkujawa mtdcr(DCR_L2C0_CMD, L2C_CMD_HCC);
88 1.1 rkujawa while ((mfdcr(DCR_L2C0_SR) & L2C_SR_CC) == 0)
89 1.1 rkujawa ;
90 1.1 rkujawa __asm volatile ("msync" ::: "memory");
91 1.1 rkujawa splx(s);
92 1.1 rkujawa return;
93 1.1 rkujawa }
94 1.1 rkujawa
95 1.1 rkujawa /* Skip leading amount. */
96 1.1 rkujawa while (offset >= ds->ds_len) {
97 1.1 rkujawa offset -= ds->ds_len;
98 1.1 rkujawa ds++;
99 1.1 rkujawa }
100 1.1 rkujawa for (; len > 0; ds++, offset = 0) {
101 1.1 rkujawa bus_size_t seglen = ds->ds_len - offset;
102 1.1 rkujawa bus_addr_t addr = BUS_MEM_TO_PHYS(t, ds->ds_addr) + offset;
103 1.1 rkujawa bus_addr_t lineoff, epa;
104 1.1 rkujawa
105 1.1 rkujawa if (seglen > len)
106 1.1 rkujawa seglen = len;
107 1.1 rkujawa len -= seglen;
108 1.1 rkujawa KASSERT(ds < &map->dm_segs[map->dm_nsegs]);
109 1.1 rkujawa
110 1.1 rkujawa /* Realign to cache-line boundaries. */
111 1.1 rkujawa lineoff = addr & (L2_LINE_SIZE - 1);
112 1.1 rkujawa seglen += lineoff;
113 1.1 rkujawa addr -= lineoff;
114 1.1 rkujawa
115 1.1 rkujawa for (epa = addr + seglen; addr < epa; addr += L2_LINE_SIZE) {
116 1.1 rkujawa mtdcr(DCR_L2C0_ADDR, ibm4xx_460ex_l2_addr(addr));
117 1.1 rkujawa mtdcr(DCR_L2C0_CMD, L2C_CMD_INV);
118 1.1 rkujawa while ((mfdcr(DCR_L2C0_SR) & L2C_SR_CC) == 0)
119 1.1 rkujawa ;
120 1.1 rkujawa }
121 1.1 rkujawa }
122 1.1 rkujawa __asm volatile ("msync" ::: "memory");
123 1.1 rkujawa splx(s);
124 1.1 rkujawa }
125 1.1 rkujawa
126 1.1 rkujawa /*
127 1.1 rkujawa * Private bus_dma sync for the USB controllers.
128 1.1 rkujawa */
129 1.1 rkujawa static void
130 1.1 rkujawa ibm4xx_460ex_l2_dmamap_sync(bus_dma_tag_t t, bus_dmamap_t map,
131 1.1 rkujawa bus_addr_t offset, bus_size_t len, int ops)
132 1.1 rkujawa {
133 1.1 rkujawa if (ibm4xx_460ex_l2_enabled && (ops & BUS_DMASYNC_POSTREAD) != 0)
134 1.1 rkujawa ibm4xx_460ex_l2_invalidate(t, map, offset, len);
135 1.1 rkujawa _bus_dmamap_sync(t, map, offset, len, ops);
136 1.1 rkujawa }
137 1.1 rkujawa
138 1.1 rkujawa /*
139 1.1 rkujawa * A clone of ibm4xx_default_bus_dma_tag sync overriden
140 1.1 rkujawa */
141 1.1 rkujawa struct powerpc_bus_dma_tag ibm4xx_460ex_l2_bus_dma_tag = {
142 1.1 rkujawa 0, 0,
143 1.1 rkujawa _bus_dmamap_create,
144 1.1 rkujawa _bus_dmamap_destroy,
145 1.1 rkujawa _bus_dmamap_load,
146 1.1 rkujawa _bus_dmamap_load_mbuf,
147 1.1 rkujawa _bus_dmamap_load_uio,
148 1.1 rkujawa _bus_dmamap_load_raw,
149 1.1 rkujawa _bus_dmamap_unload,
150 1.1 rkujawa ibm4xx_460ex_l2_dmamap_sync,
151 1.1 rkujawa _bus_dmamem_alloc,
152 1.1 rkujawa _bus_dmamem_free,
153 1.1 rkujawa _bus_dmamem_map,
154 1.1 rkujawa _bus_dmamem_unmap,
155 1.1 rkujawa _bus_dmamem_mmap,
156 1.1 rkujawa _bus_dma_phys_to_bus_mem_generic,
157 1.1 rkujawa _bus_dma_bus_mem_to_phys_generic,
158 1.1 rkujawa };
159 1.1 rkujawa
160 1.1 rkujawa bus_dma_tag_t
161 1.1 rkujawa ibm4xx_460ex_l2_dmatag(void)
162 1.1 rkujawa {
163 1.1 rkujawa return &ibm4xx_460ex_l2_bus_dma_tag;
164 1.1 rkujawa }
165 1.1 rkujawa
166 1.1 rkujawa void
167 1.1 rkujawa ibm4xx_460ex_l2cache_enable(u_int memsize)
168 1.1 rkujawa {
169 1.1 rkujawa uint32_t snpsz;
170 1.1 rkujawa u_int code;
171 1.1 rkujawa
172 1.1 rkujawa /* Hand the SRAM0 data arrays back from the SRAM controller. */
173 1.1 rkujawa mtdcr(DCR_SRAM0_SB0CR, 0);
174 1.1 rkujawa mtdcr(DCR_SRAM0_SB1CR, 0);
175 1.1 rkujawa mtdcr(DCR_SRAM0_SB2CR, 0);
176 1.1 rkujawa mtdcr(DCR_SRAM0_SB3CR, 0);
177 1.1 rkujawa
178 1.1 rkujawa /* RDBW is required; switch the array into L2 mode. */
179 1.1 rkujawa mtdcr(DCR_L2C0_CFG, L2C_CFG_RDBW | L2C_CFG_L2M | L2C_CFG_SS_256KB);
180 1.1 rkujawa
181 1.1 rkujawa /* Reset the tag array with the hardware clear command. */
182 1.1 rkujawa mtdcr(DCR_L2C0_ADDR, 0);
183 1.1 rkujawa mtdcr(DCR_L2C0_CMD, L2C_CMD_HCC);
184 1.1 rkujawa while ((mfdcr(DCR_L2C0_SR) & L2C_SR_CC) == 0)
185 1.1 rkujawa ;
186 1.1 rkujawa /* Clear any latched cache- and tag-parity errors. */
187 1.1 rkujawa mtdcr(DCR_L2C0_CMD, L2C_CMD_CCP);
188 1.1 rkujawa while ((mfdcr(DCR_L2C0_SR) & L2C_SR_CC) == 0)
189 1.1 rkujawa ;
190 1.1 rkujawa mtdcr(DCR_L2C0_CMD, L2C_CMD_CTE);
191 1.1 rkujawa while ((mfdcr(DCR_L2C0_SR) & L2C_SR_CC) == 0)
192 1.1 rkujawa ;
193 1.1 rkujawa __asm volatile ("msync" ::: "memory");
194 1.1 rkujawa
195 1.1 rkujawa /*
196 1.1 rkujawa * Program snoop region 0 to cover all of DRAM on the LL segment!
197 1.1 rkujawa */
198 1.1 rkujawa snpsz = 0x100000; /* 1MB, the smallest snoop region */
199 1.1 rkujawa code = 0;
200 1.1 rkujawa while (snpsz < memsize) {
201 1.1 rkujawa snpsz <<= 1;
202 1.1 rkujawa code++;
203 1.1 rkujawa }
204 1.1 rkujawa mtdcr(DCR_L2C0_SNP0, (code << L2C_SNP_SSR_SHIFT) | L2C_SNP_ESR);
205 1.1 rkujawa mtdcr(DCR_L2C0_SNP1, 0);
206 1.1 rkujawa
207 1.1 rkujawa /* Enable instruction- and data-side L2 caching. */
208 1.1 rkujawa mtdcr(DCR_L2C0_CFG, L2C_CFG_RDBW | L2C_CFG_L2M | L2C_CFG_SS_256KB |
209 1.1 rkujawa L2C_CFG_FRAN | L2C_CFG_SNPCI | L2C_CFG_ICU | L2C_CFG_DCU);
210 1.1 rkujawa __asm volatile ("msync" ::: "memory");
211 1.1 rkujawa
212 1.1 rkujawa /* Read back so the caller can confirm what actually stuck. */
213 1.1 rkujawa ibm4xx_460ex_l2_cfg = mfdcr(DCR_L2C0_CFG);
214 1.1 rkujawa if (ibm4xx_460ex_l2_cfg & L2C_CFG_L2M)
215 1.1 rkujawa ibm4xx_460ex_l2_enabled = true;
216 1.1 rkujawa }
217 1.1 rkujawa
218