#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ibm4xx_460ex_l2.c,v 1.1 2026/06/19 18:55:23 rkujawa Exp $");
#include "opt_ppc4xx.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/intr.h>
#define _POWERPC_BUS_DMA_PRIVATE
#include <sys/bus.h>
#include <powerpc/ibm4xx/cpu.h>
#include <powerpc/ibm4xx/amcc460ex.h>
#include <powerpc/ibm4xx/ibm4xx_460ex_l2.h>
#define L2_LINE_SIZE 32
#define L2_WAYS 4
#define L2_SIZE (256 * 1024)
#define L2_INDEX_SPAN (L2_SIZE / L2_WAYS)
bool ibm4xx_460ex_l2_enabled = false;
uint32_t ibm4xx_460ex_l2_cfg;
static inline uint32_t
ibm4xx_460ex_l2_addr(bus_addr_t pa)
{
return (uint32_t)pa & 0xfffffff0;
}
static void
ibm4xx_460ex_l2_invalidate(bus_dma_tag_t t, bus_dmamap_t map,
bus_addr_t offset, bus_size_t len)
{
const bus_dma_segment_t *ds = map->dm_segs;
int s;
if (len == 0)
return;
s = splhigh();
if (len >= L2_INDEX_SPAN) {
mtdcr(DCR_L2C0_ADDR, 0);
mtdcr(DCR_L2C0_CMD, L2C_CMD_HCC);
while ((mfdcr(DCR_L2C0_SR) & L2C_SR_CC) == 0)
;
__asm volatile ("msync" ::: "memory");
splx(s);
return;
}
while (offset >= ds->ds_len) {
offset -= ds->ds_len;
ds++;
}
for (; len > 0; ds++, offset = 0) {
bus_size_t seglen = ds->ds_len - offset;
bus_addr_t addr = BUS_MEM_TO_PHYS(t, ds->ds_addr) + offset;
bus_addr_t lineoff, epa;
if (seglen > len)
seglen = len;
len -= seglen;
KASSERT(ds < &map->dm_segs[map->dm_nsegs]);
lineoff = addr & (L2_LINE_SIZE - 1);
seglen += lineoff;
addr -= lineoff;
for (epa = addr + seglen; addr < epa; addr += L2_LINE_SIZE) {
mtdcr(DCR_L2C0_ADDR, ibm4xx_460ex_l2_addr(addr));
mtdcr(DCR_L2C0_CMD, L2C_CMD_INV);
while ((mfdcr(DCR_L2C0_SR) & L2C_SR_CC) == 0)
;
}
}
__asm volatile ("msync" ::: "memory");
splx(s);
}
static void
ibm4xx_460ex_l2_dmamap_sync(bus_dma_tag_t t, bus_dmamap_t map,
bus_addr_t offset, bus_size_t len, int ops)
{
if (ibm4xx_460ex_l2_enabled && (ops & BUS_DMASYNC_POSTREAD) != 0)
ibm4xx_460ex_l2_invalidate(t, map, offset, len);
_bus_dmamap_sync(t, map, offset, len, ops);
}
struct powerpc_bus_dma_tag ibm4xx_460ex_l2_bus_dma_tag = {
0, 0,
_bus_dmamap_create,
_bus_dmamap_destroy,
_bus_dmamap_load,
_bus_dmamap_load_mbuf,
_bus_dmamap_load_uio,
_bus_dmamap_load_raw,
_bus_dmamap_unload,
ibm4xx_460ex_l2_dmamap_sync,
_bus_dmamem_alloc,
_bus_dmamem_free,
_bus_dmamem_map,
_bus_dmamem_unmap,
_bus_dmamem_mmap,
_bus_dma_phys_to_bus_mem_generic,
_bus_dma_bus_mem_to_phys_generic,
};
bus_dma_tag_t
ibm4xx_460ex_l2_dmatag(void)
{
return &ibm4xx_460ex_l2_bus_dma_tag;
}
void
ibm4xx_460ex_l2cache_enable(u_int memsize)
{
uint32_t snpsz;
u_int code;
mtdcr(DCR_SRAM0_SB0CR, 0);
mtdcr(DCR_SRAM0_SB1CR, 0);
mtdcr(DCR_SRAM0_SB2CR, 0);
mtdcr(DCR_SRAM0_SB3CR, 0);
mtdcr(DCR_L2C0_CFG, L2C_CFG_RDBW | L2C_CFG_L2M | L2C_CFG_SS_256KB);
mtdcr(DCR_L2C0_ADDR, 0);
mtdcr(DCR_L2C0_CMD, L2C_CMD_HCC);
while ((mfdcr(DCR_L2C0_SR) & L2C_SR_CC) == 0)
;
mtdcr(DCR_L2C0_CMD, L2C_CMD_CCP);
while ((mfdcr(DCR_L2C0_SR) & L2C_SR_CC) == 0)
;
mtdcr(DCR_L2C0_CMD, L2C_CMD_CTE);
while ((mfdcr(DCR_L2C0_SR) & L2C_SR_CC) == 0)
;
__asm volatile ("msync" ::: "memory");
snpsz = 0x100000;
code = 0;
while (snpsz < memsize) {
snpsz <<= 1;
code++;
}
mtdcr(DCR_L2C0_SNP0, (code << L2C_SNP_SSR_SHIFT) | L2C_SNP_ESR);
mtdcr(DCR_L2C0_SNP1, 0);
mtdcr(DCR_L2C0_CFG, L2C_CFG_RDBW | L2C_CFG_L2M | L2C_CFG_SS_256KB |
L2C_CFG_FRAN | L2C_CFG_SNPCI | L2C_CFG_ICU | L2C_CFG_DCU);
__asm volatile ("msync" ::: "memory");
ibm4xx_460ex_l2_cfg = mfdcr(DCR_L2C0_CFG);
if (ibm4xx_460ex_l2_cfg & L2C_CFG_L2M)
ibm4xx_460ex_l2_enabled = true;
}