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