1 1.4 rkujawa /* $NetBSD: pcix.c,v 1.4 2026/09/28 20:41:01 rkujawa Exp $ */ 2 1.1 rkujawa 3 1.1 rkujawa /* 4 1.1 rkujawa * Copyright (c) 2012, 2014, 2024, 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 1.1 rkujawa * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 1.1 rkujawa * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 1.1 rkujawa * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 1.1 rkujawa * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 1.1 rkujawa * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 1.1 rkujawa * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 1.1 rkujawa * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 1.1 rkujawa * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 1.1 rkujawa * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 1.1 rkujawa */ 30 1.1 rkujawa 31 1.1 rkujawa /* 32 1.1 rkujawa * IBM PLB-PCIX host bridge, as found on the 440GP/440SPe/460EX 33 1.1 rkujawa * 34 1.1 rkujawa * XXX The bridge addresses are currently straight from 460EX include 35 1.1 rkujawa */ 36 1.1 rkujawa 37 1.1 rkujawa #include <sys/cdefs.h> 38 1.4 rkujawa __KERNEL_RCSID(0, "$NetBSD: pcix.c,v 1.4 2026/09/28 20:41:01 rkujawa Exp $"); 39 1.1 rkujawa 40 1.1 rkujawa #ifdef _KERNEL_OPT 41 1.1 rkujawa #include "opt_pci.h" 42 1.1 rkujawa #endif 43 1.1 rkujawa 44 1.1 rkujawa #include <sys/param.h> 45 1.1 rkujawa #include <sys/systm.h> 46 1.1 rkujawa #include <sys/device.h> 47 1.1 rkujawa #include <sys/extent.h> 48 1.1 rkujawa #include <sys/bus.h> 49 1.1 rkujawa 50 1.1 rkujawa #include <dev/pci/pcivar.h> 51 1.1 rkujawa #include <dev/pci/pcireg.h> 52 1.1 rkujawa #include <dev/pci/pciconf.h> 53 1.1 rkujawa 54 1.1 rkujawa #include <powerpc/ibm4xx/amcc460ex.h> 55 1.1 rkujawa #include <powerpc/ibm4xx/cpu.h> 56 1.1 rkujawa #include <powerpc/ibm4xx/spr.h> 57 1.1 rkujawa #include <powerpc/ibm4xx/dev/plbvar.h> 58 1.1 rkujawa #include <powerpc/ibm4xx/pci_machdep.h> 59 1.1 rkujawa #include <powerpc/pci_machdep.h> 60 1.1 rkujawa 61 1.1 rkujawa /* Internal register offsets (relative to the internal register base) */ 62 1.1 rkujawa #define PCIX0_POM0LAL 0x68 63 1.1 rkujawa #define PCIX0_POM0LAH 0x6c 64 1.1 rkujawa #define PCIX0_POM0SA 0x70 65 1.1 rkujawa #define PCIX0_POM0PCIAL 0x74 66 1.1 rkujawa #define PCIX0_POM0PCIAH 0x78 67 1.1 rkujawa #define PCIX0_POM1LAL 0x7c 68 1.1 rkujawa #define PCIX0_POM1LAH 0x80 69 1.1 rkujawa #define PCIX0_POM1SA 0x84 70 1.2 rkujawa #define PCIX0_POM1PCIAL 0x88 71 1.2 rkujawa #define PCIX0_POM1PCIAH 0x8c 72 1.1 rkujawa #define PCIX0_POM2SA 0x90 73 1.1 rkujawa #define PCIX0_PIM0SAL 0x98 74 1.1 rkujawa #define PCIX0_PIM0LAL 0x9c 75 1.1 rkujawa #define PCIX0_PIM0LAH 0xa0 76 1.1 rkujawa #define PCIX0_PIM1SA 0xa4 77 1.1 rkujawa #define PCIX0_PIM1LAL 0xa8 78 1.1 rkujawa #define PCIX0_PIM1LAH 0xac 79 1.1 rkujawa #define PCIX0_PIM2SAL 0xb0 80 1.1 rkujawa #define PCIX0_PIM0SAH 0xf8 81 1.1 rkujawa 82 1.3 rkujawa #define PIM_SA_ENABLE 0x1 83 1.3 rkujawa #define PIM_SA_PREFETCH 0x2 /* inbound read prefetch (bit 1) */ 84 1.3 rkujawa 85 1.1 rkujawa #define PCIC_CFGADDR 0 86 1.1 rkujawa #define PCIC_CFGDATA 4 87 1.1 rkujawa 88 1.1 rkujawa static int pcix_match(device_t, cfdata_t, void *); 89 1.1 rkujawa static void pcix_attach(device_t, device_t, void *); 90 1.1 rkujawa static int pcix_print(void *, const char *); 91 1.1 rkujawa 92 1.1 rkujawa CFATTACH_DECL_NEW(pcix, 0, pcix_match, pcix_attach, NULL, NULL); 93 1.1 rkujawa 94 1.1 rkujawa static pcireg_t pcix_conf_read(void *, pcitag_t, int); 95 1.1 rkujawa static void pcix_conf_write(void *, pcitag_t, int, pcireg_t); 96 1.1 rkujawa static void pcix_attach_hook(device_t, device_t, 97 1.1 rkujawa struct pcibus_attach_args *); 98 1.1 rkujawa static int pcix_conf_hook(void *, int, int, int, pcireg_t); 99 1.1 rkujawa 100 1.1 rkujawa /* CFGADDR/CFGDATA pair */ 101 1.1 rkujawa static struct powerpc_bus_space pcix_cfg_tag = { 102 1.1 rkujawa _BUS_SPACE_LITTLE_ENDIAN | _BUS_SPACE_MEM_TYPE, 103 1.1 rkujawa 0x00000000, /* offset */ 104 1.1 rkujawa AMCC460EX_PCIX0_CFG_PLBA, /* extent base */ 105 1.1 rkujawa AMCC460EX_PCIX0_CFG_PLBA + 8, /* extent limit */ 106 1.1 rkujawa }; 107 1.1 rkujawa 108 1.1 rkujawa /* Internal (window) registers */ 109 1.1 rkujawa static struct powerpc_bus_space pcix_reg_tag = { 110 1.1 rkujawa _BUS_SPACE_LITTLE_ENDIAN | _BUS_SPACE_MEM_TYPE, 111 1.1 rkujawa 0x00000000, 112 1.1 rkujawa AMCC460EX_PCIX0_REGS_PLBA, 113 1.1 rkujawa AMCC460EX_PCIX0_REGS_PLBA + 0x100, 114 1.1 rkujawa }; 115 1.1 rkujawa 116 1.1 rkujawa /* PCI I/O: bus 0x0000-0xffff -> PLB I/O window */ 117 1.1 rkujawa static struct powerpc_bus_space pcix_io_tag = { 118 1.1 rkujawa _BUS_SPACE_LITTLE_ENDIAN | _BUS_SPACE_IO_TYPE, 119 1.1 rkujawa AMCC460EX_PCIX0_IO_PLBA, /* offset */ 120 1.1 rkujawa 0x00000000, /* extent base */ 121 1.1 rkujawa 0x00010000, /* extent limit */ 122 1.1 rkujawa }; 123 1.1 rkujawa 124 1.2 rkujawa /* 125 1.2 rkujawa * PCI memory: bus addr = low 32 bits of PLB addr. 126 1.2 rkujawa */ 127 1.1 rkujawa static struct powerpc_bus_space pcix_mem_tag = { 128 1.1 rkujawa _BUS_SPACE_LITTLE_ENDIAN | _BUS_SPACE_MEM_TYPE, 129 1.1 rkujawa 0x00000000, 130 1.1 rkujawa AMCC460EX_PCIX0_MEM_BASE, 131 1.2 rkujawa AMCC460EX_PCIX0_PMEM_BASE + AMCC460EX_PCIX0_PMEM_SIZE, 132 1.1 rkujawa }; 133 1.1 rkujawa 134 1.1 rkujawa static bus_space_handle_t pcix_cfg_ioh; 135 1.1 rkujawa static bus_space_handle_t pcix_reg_ioh; 136 1.1 rkujawa 137 1.1 rkujawa static struct genppc_pci_chipset pcix_chipset = { 138 1.1 rkujawa .pc_conf_v = NULL, 139 1.1 rkujawa .pc_attach_hook = pcix_attach_hook, 140 1.1 rkujawa .pc_bus_maxdevs = ibm4xx_pci_bus_maxdevs, 141 1.1 rkujawa .pc_make_tag = ibm4xx_pci_make_tag, 142 1.1 rkujawa .pc_conf_read = pcix_conf_read, 143 1.1 rkujawa .pc_conf_write = pcix_conf_write, 144 1.1 rkujawa 145 1.1 rkujawa .pc_intr_v = &pcix_chipset, 146 1.1 rkujawa .pc_intr_map = genppc_pci_intr_map, 147 1.1 rkujawa .pc_intr_string = genppc_pci_intr_string, 148 1.1 rkujawa .pc_intr_evcnt = genppc_pci_intr_evcnt, 149 1.1 rkujawa .pc_intr_establish = genppc_pci_intr_establish, 150 1.1 rkujawa .pc_intr_disestablish = genppc_pci_intr_disestablish, 151 1.1 rkujawa .pc_intr_setattr = ibm4xx_pci_intr_setattr, 152 1.1 rkujawa .pc_intr_type = genppc_pci_intr_type, 153 1.1 rkujawa .pc_intr_alloc = genppc_pci_intr_alloc, 154 1.1 rkujawa .pc_intr_release = genppc_pci_intr_release, 155 1.1 rkujawa .pc_intx_alloc = genppc_pci_intx_alloc, 156 1.1 rkujawa 157 1.1 rkujawa .pc_msi_v = &pcix_chipset, 158 1.1 rkujawa GENPPC_PCI_MSI_INITIALIZER, 159 1.1 rkujawa 160 1.1 rkujawa .pc_msix_v = &pcix_chipset, 161 1.1 rkujawa GENPPC_PCI_MSIX_INITIALIZER, 162 1.1 rkujawa 163 1.1 rkujawa .pc_conf_interrupt = ibm4xx_pci_conf_interrupt, 164 1.1 rkujawa .pc_decompose_tag = ibm4xx_pci_decompose_tag, 165 1.1 rkujawa .pc_conf_hook = pcix_conf_hook, 166 1.1 rkujawa }; 167 1.1 rkujawa 168 1.1 rkujawa static void 169 1.1 rkujawa pcix_attach_hook(device_t parent, device_t self, 170 1.1 rkujawa struct pcibus_attach_args *pba) 171 1.1 rkujawa { 172 1.1 rkujawa } 173 1.1 rkujawa 174 1.1 rkujawa static int 175 1.1 rkujawa pcix_conf_hook(void *v, int bus, int dev, int func, pcireg_t id) 176 1.1 rkujawa { 177 1.1 rkujawa 178 1.1 rkujawa return PCI_CONF_DEFAULT; 179 1.1 rkujawa } 180 1.1 rkujawa 181 1.2 rkujawa /* 182 1.2 rkujawa * Translate the tag 183 1.2 rkujawa */ 184 1.2 rkujawa static uint32_t 185 1.2 rkujawa pcix_cfg_addr(pcitag_t tag, int reg) 186 1.2 rkujawa { 187 1.2 rkujawa uint32_t addr = (tag & 0x00ffff00) | (reg & 0xfc); 188 1.2 rkujawa 189 1.2 rkujawa if (tag & 0x00ff0000) /* bus number != 0 -> Type 1 */ 190 1.2 rkujawa addr |= 1; 191 1.2 rkujawa return addr; 192 1.2 rkujawa } 193 1.2 rkujawa 194 1.1 rkujawa static pcireg_t 195 1.1 rkujawa pcix_conf_read(void *v, pcitag_t tag, int reg) 196 1.1 rkujawa { 197 1.1 rkujawa pcireg_t data; 198 1.1 rkujawa 199 1.1 rkujawa if ((unsigned int)reg >= PCI_CONF_SIZE) 200 1.1 rkujawa return (pcireg_t) -1; 201 1.1 rkujawa 202 1.1 rkujawa bus_space_write_4(&pcix_cfg_tag, pcix_cfg_ioh, PCIC_CFGADDR, 203 1.2 rkujawa pcix_cfg_addr(tag, reg)); 204 1.1 rkujawa data = bus_space_read_4(&pcix_cfg_tag, pcix_cfg_ioh, PCIC_CFGDATA); 205 1.1 rkujawa bus_space_write_4(&pcix_cfg_tag, pcix_cfg_ioh, PCIC_CFGADDR, 0); 206 1.1 rkujawa return data; 207 1.1 rkujawa } 208 1.1 rkujawa 209 1.1 rkujawa static void 210 1.1 rkujawa pcix_conf_write(void *v, pcitag_t tag, int reg, pcireg_t data) 211 1.1 rkujawa { 212 1.1 rkujawa 213 1.1 rkujawa if ((unsigned int)reg >= PCI_CONF_SIZE) 214 1.1 rkujawa return; 215 1.1 rkujawa 216 1.1 rkujawa bus_space_write_4(&pcix_cfg_tag, pcix_cfg_ioh, PCIC_CFGADDR, 217 1.2 rkujawa pcix_cfg_addr(tag, reg)); 218 1.1 rkujawa bus_space_write_4(&pcix_cfg_tag, pcix_cfg_ioh, PCIC_CFGDATA, data); 219 1.1 rkujawa bus_space_write_4(&pcix_cfg_tag, pcix_cfg_ioh, PCIC_CFGADDR, 0); 220 1.1 rkujawa } 221 1.1 rkujawa 222 1.1 rkujawa #define PCIX_REG_WRITE(reg, val) \ 223 1.1 rkujawa bus_space_write_4(&pcix_reg_tag, pcix_reg_ioh, (reg), (val)) 224 1.1 rkujawa 225 1.1 rkujawa static void 226 1.1 rkujawa pcix_setup_windows(void) 227 1.1 rkujawa { 228 1.1 rkujawa 229 1.1 rkujawa /* POM0: PLB -> PCI memory, 128MB */ 230 1.1 rkujawa PCIX_REG_WRITE(PCIX0_POM0SA, 0); /* disable while */ 231 1.1 rkujawa PCIX_REG_WRITE(PCIX0_POM0LAL, AMCC460EX_PCIX0_MEM_BASE); 232 1.1 rkujawa PCIX_REG_WRITE(PCIX0_POM0LAH, AMCC460EX_PCIX0_MEM_PLBA_H); 233 1.1 rkujawa PCIX_REG_WRITE(PCIX0_POM0PCIAL, AMCC460EX_PCIX0_MEM_BASE); 234 1.1 rkujawa PCIX_REG_WRITE(PCIX0_POM0PCIAH, 0); 235 1.1 rkujawa PCIX_REG_WRITE(PCIX0_POM0SA, ~(0x08000000 - 1) | 1); 236 1.1 rkujawa 237 1.2 rkujawa /* POM1: PLB -> PCI prefetchable memory, identity mapped, 256MB */ 238 1.2 rkujawa PCIX_REG_WRITE(PCIX0_POM1SA, 0); /* disable while */ 239 1.2 rkujawa PCIX_REG_WRITE(PCIX0_POM1LAL, AMCC460EX_PCIX0_PMEM_BASE); 240 1.2 rkujawa PCIX_REG_WRITE(PCIX0_POM1LAH, AMCC460EX_PCIX0_PMEM_PLBA_H); 241 1.2 rkujawa PCIX_REG_WRITE(PCIX0_POM1PCIAL, AMCC460EX_PCIX0_PMEM_BASE); 242 1.2 rkujawa PCIX_REG_WRITE(PCIX0_POM1PCIAH, 0); 243 1.2 rkujawa PCIX_REG_WRITE(PCIX0_POM1SA, ~(AMCC460EX_PCIX0_PMEM_SIZE - 1) | 1); 244 1.2 rkujawa 245 1.2 rkujawa /* POM2 unused */ 246 1.1 rkujawa PCIX_REG_WRITE(PCIX0_POM2SA, 0); 247 1.1 rkujawa 248 1.1 rkujawa /* PIM0: PCI 0 -> PLB 0, 2GB (covers all of RAM) */ 249 1.1 rkujawa PCIX_REG_WRITE(PCIX0_PIM0SAL, 0); /* disable while */ 250 1.1 rkujawa PCIX_REG_WRITE(PCIX0_PIM0LAL, 0); 251 1.1 rkujawa PCIX_REG_WRITE(PCIX0_PIM0LAH, 0); 252 1.1 rkujawa PCIX_REG_WRITE(PCIX0_PIM0SAH, 0xffffffff); 253 1.3 rkujawa /* 254 1.3 rkujawa * Enable inbound read prefetch 255 1.3 rkujawa */ 256 1.3 rkujawa PCIX_REG_WRITE(PCIX0_PIM0SAL, 257 1.3 rkujawa ~(0x80000000U - 1) | PIM_SA_ENABLE | PIM_SA_PREFETCH); 258 1.1 rkujawa 259 1.1 rkujawa /* PIM1/PIM2 unused */ 260 1.1 rkujawa PCIX_REG_WRITE(PCIX0_PIM1SA, 0); 261 1.1 rkujawa PCIX_REG_WRITE(PCIX0_PIM2SAL, 0); 262 1.1 rkujawa } 263 1.1 rkujawa 264 1.1 rkujawa static int 265 1.1 rkujawa pcix_match(device_t parent, cfdata_t cf, void *aux) 266 1.1 rkujawa { 267 1.1 rkujawa struct plb_attach_args *paa = aux; 268 1.1 rkujawa 269 1.1 rkujawa if (strcmp(paa->plb_name, cf->cf_name) != 0) 270 1.1 rkujawa return 0; 271 1.1 rkujawa 272 1.1 rkujawa return 1; 273 1.1 rkujawa } 274 1.1 rkujawa 275 1.1 rkujawa static void 276 1.1 rkujawa pcix_attach(device_t parent, device_t self, void *aux) 277 1.1 rkujawa { 278 1.1 rkujawa struct plb_attach_args *paa = aux; 279 1.1 rkujawa struct pcibus_attach_args pba; 280 1.1 rkujawa pci_chipset_tag_t pc = &pcix_chipset; 281 1.1 rkujawa 282 1.1 rkujawa aprint_normal(": PLB-PCIX host bridge\n"); 283 1.1 rkujawa 284 1.1 rkujawa if (bus_space_init(&pcix_cfg_tag, "pcixcfg", NULL, 0) || 285 1.1 rkujawa bus_space_map(&pcix_cfg_tag, AMCC460EX_PCIX0_CFG_PLBA, 8, 0, 286 1.1 rkujawa &pcix_cfg_ioh)) 287 1.1 rkujawa panic("pcix_attach: can't map config registers"); 288 1.1 rkujawa if (bus_space_init(&pcix_reg_tag, "pcixreg", NULL, 0) || 289 1.1 rkujawa bus_space_map(&pcix_reg_tag, AMCC460EX_PCIX0_REGS_PLBA, 0x100, 0, 290 1.1 rkujawa &pcix_reg_ioh)) 291 1.1 rkujawa panic("pcix_attach: can't map bridge registers"); 292 1.1 rkujawa if (bus_space_init(&pcix_io_tag, "pcixio", NULL, 0)) 293 1.1 rkujawa panic("pcix_attach: can't init IO tag"); 294 1.1 rkujawa if (bus_space_init(&pcix_mem_tag, "pcixmem", NULL, 0)) 295 1.1 rkujawa panic("pcix_attach: can't init MEM tag"); 296 1.1 rkujawa 297 1.1 rkujawa pcix_setup_windows(); 298 1.1 rkujawa 299 1.1 rkujawa #ifdef PCI_NETBSD_CONFIGURE 300 1.1 rkujawa struct pciconf_resources *pcires = pciconf_resource_init(); 301 1.1 rkujawa 302 1.1 rkujawa pciconf_resource_add(pcires, PCICONF_RESOURCE_IO, 303 1.1 rkujawa 0x1000, 0x10000 - 0x1000); 304 1.1 rkujawa pciconf_resource_add(pcires, PCICONF_RESOURCE_MEM, 305 1.1 rkujawa AMCC460EX_PCIX0_MEM_BASE, AMCC460EX_PCIX0_MEM_SIZE); 306 1.2 rkujawa pciconf_resource_add(pcires, PCICONF_RESOURCE_PREFETCHABLE_MEM, 307 1.4 rkujawa AMCC460EX_PCIX0_PMEM_BASE, AMCC460EX_PCIX0_PMEM_MAP); 308 1.4 rkujawa 309 1.4 rkujawa aprint_verbose_dev(self, "mem 0x%08x-0x%08x, prefetchable mem " 310 1.4 rkujawa "0x%08x-0x%08x\n", 311 1.4 rkujawa AMCC460EX_PCIX0_MEM_BASE, 312 1.4 rkujawa AMCC460EX_PCIX0_MEM_BASE + AMCC460EX_PCIX0_MEM_SIZE - 1, 313 1.4 rkujawa AMCC460EX_PCIX0_PMEM_BASE, 314 1.4 rkujawa AMCC460EX_PCIX0_PMEM_BASE + AMCC460EX_PCIX0_PMEM_MAP - 1); 315 1.1 rkujawa 316 1.1 rkujawa pci_configure_bus(pc, pcires, 0, 32); 317 1.1 rkujawa pciconf_resource_fini(pcires); 318 1.1 rkujawa #endif 319 1.1 rkujawa 320 1.1 rkujawa pba.pba_iot = &pcix_io_tag; 321 1.1 rkujawa pba.pba_memt = &pcix_mem_tag; 322 1.1 rkujawa pba.pba_dmat = paa->plb_dmat; 323 1.1 rkujawa pba.pba_dmat64 = NULL; 324 1.1 rkujawa pba.pba_pc = pc; 325 1.1 rkujawa pba.pba_bus = 0; 326 1.1 rkujawa pba.pba_bridgetag = NULL; 327 1.1 rkujawa pba.pba_flags = PCI_FLAGS_MEM_OKAY | PCI_FLAGS_IO_OKAY; 328 1.1 rkujawa config_found(self, &pba, pcix_print, CFARGS_NONE); 329 1.1 rkujawa } 330 1.1 rkujawa 331 1.1 rkujawa static int 332 1.1 rkujawa pcix_print(void *aux, const char *p) 333 1.1 rkujawa { 334 1.1 rkujawa 335 1.1 rkujawa if (p == NULL) 336 1.1 rkujawa return UNCONF; 337 1.1 rkujawa return QUIET; 338 1.1 rkujawa } 339