1 /* $OpenBSD: bcm2711_pcie.c,v 1.7 2021/10/16 17:14:41 kettenis Exp $ */ 2 /* 3 * Copyright (c) 2020 Mark Kettenis <kettenis@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 #include <sys/systm.h> 20 #include <sys/device.h> 21 #include <sys/extent.h> 22 #include <sys/malloc.h> 23 24 #include <machine/intr.h> 25 #include <machine/bus.h> 26 #include <machine/fdt.h> 27 28 #include <dev/pci/pcidevs.h> 29 #include <dev/pci/pcireg.h> 30 #include <dev/pci/pcivar.h> 31 #include <dev/pci/ppbreg.h> 32 33 #include <dev/ofw/openfirm.h> 34 #include <dev/ofw/fdt.h> 35 36 #define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LO 0x400c 37 #define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_HI 0x4010 38 #define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT 0x4070 39 #define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI 0x4080 40 #define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI 0x4084 41 #define PCIE_EXT_CFG_DATA 0x8000 42 #define PCIE_EXT_CFG_INDEX 0x9000 43 #define PCIE_RGR1_SW_INIT_1 0x9210 44 #define PCIE_RGR1_SW_INIT_1_PERST_MASK (1 << 0) 45 #define PCIE_RGR1_SW_INIT_1_INIT_MASK (1 << 1) 46 47 #define HREAD4(sc, reg) \ 48 (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) 49 #define HWRITE4(sc, reg, val) \ 50 bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) 51 52 struct bcmpcie_range { 53 uint32_t flags; 54 uint64_t pci_base; 55 uint64_t phys_base; 56 uint64_t size; 57 }; 58 59 struct bcmpcie_softc { 60 struct device sc_dev; 61 bus_space_tag_t sc_iot; 62 bus_space_handle_t sc_ioh; 63 64 int sc_node; 65 int sc_acells; 66 int sc_scells; 67 int sc_pacells; 68 int sc_pscells; 69 struct bcmpcie_range *sc_ranges; 70 int sc_nranges; 71 72 struct bus_space sc_bus_iot; 73 struct bus_space sc_bus_memt; 74 75 struct machine_pci_chipset sc_pc; 76 int sc_bus; 77 }; 78 79 int bcmpcie_match(struct device *, void *, void *); 80 void bcmpcie_attach(struct device *, struct device *, void *); 81 82 struct cfattach bcmpcie_ca = { 83 sizeof (struct bcmpcie_softc), bcmpcie_match, bcmpcie_attach 84 }; 85 86 struct cfdriver bcmpcie_cd = { 87 NULL, "bcmpcie", DV_DULL 88 }; 89 90 int 91 bcmpcie_match(struct device *parent, void *match, void *aux) 92 { 93 struct fdt_attach_args *faa = aux; 94 95 return OF_is_compatible(faa->fa_node, "brcm,bcm2711-pcie"); 96 } 97 98 void bcmpcie_attach_hook(struct device *, struct device *, 99 struct pcibus_attach_args *); 100 int bcmpcie_bus_maxdevs(void *, int); 101 pcitag_t bcmpcie_make_tag(void *, int, int, int); 102 void bcmpcie_decompose_tag(void *, pcitag_t, int *, int *, int *); 103 int bcmpcie_conf_size(void *, pcitag_t); 104 pcireg_t bcmpcie_conf_read(void *, pcitag_t, int); 105 void bcmpcie_conf_write(void *, pcitag_t, int, pcireg_t); 106 int bcmpcie_probe_device_hook(void *, struct pci_attach_args *); 107 108 int bcmpcie_intr_map(struct pci_attach_args *, pci_intr_handle_t *); 109 const char *bcmpcie_intr_string(void *, pci_intr_handle_t); 110 void *bcmpcie_intr_establish(void *, pci_intr_handle_t, int, 111 struct cpu_info *, int (*)(void *), void *, char *); 112 void bcmpcie_intr_disestablish(void *, void *); 113 114 int bcmpcie_bs_iomap(bus_space_tag_t, bus_addr_t, bus_size_t, int, 115 bus_space_handle_t *); 116 int bcmpcie_bs_memmap(bus_space_tag_t, bus_addr_t, bus_size_t, int, 117 bus_space_handle_t *); 118 119 void 120 bcmpcie_attach(struct device *parent, struct device *self, void *aux) 121 { 122 struct bcmpcie_softc *sc = (struct bcmpcie_softc *)self; 123 struct fdt_attach_args *faa = aux; 124 struct pcibus_attach_args pba; 125 uint32_t *ranges; 126 int i, j, nranges, rangeslen; 127 uint32_t reg; 128 129 if (faa->fa_nreg < 1) { 130 printf(": no registers\n"); 131 return; 132 } 133 134 sc->sc_iot = faa->fa_iot; 135 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 136 faa->fa_reg[0].size, 0, &sc->sc_ioh)) { 137 printf(": can't map registers\n"); 138 return; 139 } 140 141 reg = HREAD4(sc, PCIE_RGR1_SW_INIT_1); 142 if (reg & PCIE_RGR1_SW_INIT_1_INIT_MASK) { 143 printf(": disabled\n"); 144 return; 145 } 146 147 sc->sc_node = faa->fa_node; 148 149 sc->sc_acells = OF_getpropint(sc->sc_node, "#address-cells", 150 faa->fa_acells); 151 sc->sc_scells = OF_getpropint(sc->sc_node, "#size-cells", 152 faa->fa_scells); 153 sc->sc_pacells = faa->fa_acells; 154 sc->sc_pscells = faa->fa_scells; 155 156 rangeslen = OF_getproplen(sc->sc_node, "ranges"); 157 if (rangeslen <= 0 || (rangeslen % sizeof(uint32_t)) || 158 (rangeslen / sizeof(uint32_t)) % (sc->sc_acells + 159 sc->sc_pacells + sc->sc_scells)) { 160 printf(": invalid ranges property\n"); 161 return; 162 } 163 164 ranges = malloc(rangeslen, M_TEMP, M_WAITOK); 165 OF_getpropintarray(sc->sc_node, "ranges", ranges, 166 rangeslen); 167 168 nranges = (rangeslen / sizeof(uint32_t)) / 169 (sc->sc_acells + sc->sc_pacells + sc->sc_scells); 170 sc->sc_ranges = mallocarray(nranges, 171 sizeof(struct bcmpcie_range), M_TEMP, M_WAITOK); 172 sc->sc_nranges = nranges; 173 174 for (i = 0, j = 0; i < sc->sc_nranges; i++) { 175 sc->sc_ranges[i].flags = ranges[j++]; 176 sc->sc_ranges[i].pci_base = ranges[j++]; 177 if (sc->sc_acells - 1 == 2) { 178 sc->sc_ranges[i].pci_base <<= 32; 179 sc->sc_ranges[i].pci_base |= ranges[j++]; 180 } 181 sc->sc_ranges[i].phys_base = ranges[j++]; 182 if (sc->sc_pacells == 2) { 183 sc->sc_ranges[i].phys_base <<= 32; 184 sc->sc_ranges[i].phys_base |= ranges[j++]; 185 } 186 sc->sc_ranges[i].size = ranges[j++]; 187 if (sc->sc_scells == 2) { 188 sc->sc_ranges[i].size <<= 32; 189 sc->sc_ranges[i].size |= ranges[j++]; 190 } 191 } 192 193 free(ranges, M_TEMP, rangeslen); 194 195 /* 196 * Reprogram the outbound window to match the configuration in 197 * the device tree. This is necessary since the EDK2-based 198 * UEFI firmware reprograms the window. 199 */ 200 for (i = 0; i < sc->sc_nranges; i++) { 201 if ((sc->sc_ranges[i].flags & 0x03000000) == 0x02000000) { 202 uint64_t cpu_base = sc->sc_ranges[i].phys_base; 203 uint64_t cpu_limit = sc->sc_ranges[i].phys_base + 204 sc->sc_ranges[i].size - 1; 205 206 HWRITE4(sc, PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LO, 207 sc->sc_ranges[i].pci_base); 208 HWRITE4(sc, PCIE_MISC_CPU_2_PCIE_MEM_WIN0_HI, 209 sc->sc_ranges[i].pci_base >> 32); 210 HWRITE4(sc, PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT, 211 (cpu_base & PPB_MEM_MASK) >> PPB_MEM_SHIFT | 212 (cpu_limit & PPB_MEM_MASK)); 213 HWRITE4(sc, PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI, 214 cpu_base >> 32); 215 HWRITE4(sc, PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI, 216 cpu_limit >> 32); 217 } 218 } 219 220 printf("\n"); 221 222 memcpy(&sc->sc_bus_iot, sc->sc_iot, sizeof(sc->sc_bus_iot)); 223 sc->sc_bus_iot.bus_private = sc; 224 sc->sc_bus_iot._space_map = bcmpcie_bs_iomap; 225 memcpy(&sc->sc_bus_memt, sc->sc_iot, sizeof(sc->sc_bus_memt)); 226 sc->sc_bus_memt.bus_private = sc; 227 sc->sc_bus_memt._space_map = bcmpcie_bs_memmap; 228 229 sc->sc_pc.pc_conf_v = sc; 230 sc->sc_pc.pc_attach_hook = bcmpcie_attach_hook; 231 sc->sc_pc.pc_bus_maxdevs = bcmpcie_bus_maxdevs; 232 sc->sc_pc.pc_make_tag = bcmpcie_make_tag; 233 sc->sc_pc.pc_decompose_tag = bcmpcie_decompose_tag; 234 sc->sc_pc.pc_conf_size = bcmpcie_conf_size; 235 sc->sc_pc.pc_conf_read = bcmpcie_conf_read; 236 sc->sc_pc.pc_conf_write = bcmpcie_conf_write; 237 sc->sc_pc.pc_probe_device_hook = bcmpcie_probe_device_hook; 238 239 sc->sc_pc.pc_intr_v = sc; 240 sc->sc_pc.pc_intr_map = bcmpcie_intr_map; 241 sc->sc_pc.pc_intr_map_msi = _pci_intr_map_msi; 242 sc->sc_pc.pc_intr_map_msix = _pci_intr_map_msix; 243 sc->sc_pc.pc_intr_string = bcmpcie_intr_string; 244 sc->sc_pc.pc_intr_establish = bcmpcie_intr_establish; 245 sc->sc_pc.pc_intr_disestablish = bcmpcie_intr_disestablish; 246 247 memset(&pba, 0, sizeof(pba)); 248 pba.pba_busname = "pci"; 249 pba.pba_iot = &sc->sc_bus_iot; 250 pba.pba_memt = &sc->sc_bus_memt; 251 pba.pba_dmat = faa->fa_dmat; 252 pba.pba_pc = &sc->sc_pc; 253 pba.pba_domain = pci_ndomains++; 254 pba.pba_bus = 0; 255 256 config_found(self, &pba, NULL); 257 } 258 259 void 260 bcmpcie_attach_hook(struct device *parent, struct device *self, 261 struct pcibus_attach_args *pba) 262 { 263 } 264 265 int 266 bcmpcie_bus_maxdevs(void *v, int bus) 267 { 268 struct bcmpcie_softc *sc = v; 269 270 if (bus == sc->sc_bus || bus == sc->sc_bus + 1) 271 return 1; 272 return 32; 273 } 274 275 pcitag_t 276 bcmpcie_make_tag(void *v, int bus, int device, int function) 277 { 278 /* Return ECAM address. */ 279 return ((bus << 20) | (device << 15) | (function << 12)); 280 } 281 282 void 283 bcmpcie_decompose_tag(void *v, pcitag_t tag, int *bp, int *dp, int *fp) 284 { 285 if (bp != NULL) 286 *bp = (tag >> 20) & 0xff; 287 if (dp != NULL) 288 *dp = (tag >> 15) & 0x1f; 289 if (fp != NULL) 290 *fp = (tag >> 12) & 0x7; 291 } 292 293 int 294 bcmpcie_conf_size(void *v, pcitag_t tag) 295 { 296 return PCIE_CONFIG_SPACE_SIZE; 297 } 298 299 pcireg_t 300 bcmpcie_conf_read(void *v, pcitag_t tag, int reg) 301 { 302 struct bcmpcie_softc *sc = v; 303 int bus, dev, fn; 304 305 bcmpcie_decompose_tag(sc, tag, &bus, &dev, &fn); 306 if (bus == 0) { 307 KASSERT(dev == 0); 308 return HREAD4(sc, tag | reg); 309 } 310 311 HWRITE4(sc, PCIE_EXT_CFG_INDEX, tag); 312 return HREAD4(sc, PCIE_EXT_CFG_DATA + reg); 313 } 314 315 void 316 bcmpcie_conf_write(void *v, pcitag_t tag, int reg, pcireg_t data) 317 { 318 struct bcmpcie_softc *sc = v; 319 int bus, dev, fn; 320 321 bcmpcie_decompose_tag(sc, tag, &bus, &dev, &fn); 322 if (bus == 0) { 323 KASSERT(dev == 0); 324 HWRITE4(sc, tag | reg, data); 325 return; 326 } 327 328 HWRITE4(sc, PCIE_EXT_CFG_INDEX, tag); 329 HWRITE4(sc, PCIE_EXT_CFG_DATA + reg, data); 330 } 331 332 int 333 bcmpcie_probe_device_hook(void *v, struct pci_attach_args *pa) 334 { 335 return 0; 336 } 337 338 int 339 bcmpcie_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp) 340 { 341 int pin = pa->pa_rawintrpin; 342 343 if (pin == 0 || pin > PCI_INTERRUPT_PIN_MAX) 344 return -1; 345 346 if (pa->pa_tag == 0) 347 return -1; 348 349 ihp->ih_pc = pa->pa_pc; 350 ihp->ih_tag = pa->pa_intrtag; 351 ihp->ih_intrpin = pa->pa_intrpin; 352 ihp->ih_type = PCI_INTX; 353 354 return 0; 355 } 356 357 const char * 358 bcmpcie_intr_string(void *v, pci_intr_handle_t ih) 359 { 360 switch (ih.ih_type) { 361 case PCI_MSI: 362 return "msi"; 363 case PCI_MSIX: 364 return "msix"; 365 } 366 367 return "intx"; 368 } 369 370 void * 371 bcmpcie_intr_establish(void *v, pci_intr_handle_t ih, int level, 372 struct cpu_info *ci, int (*func)(void *), void *arg, char *name) 373 { 374 struct bcmpcie_softc *sc = v; 375 int bus, dev, fn; 376 uint32_t reg[4]; 377 378 KASSERT(ih.ih_type == PCI_INTX); 379 bcmpcie_decompose_tag(sc, ih.ih_tag, &bus, &dev, &fn); 380 381 reg[0] = bus << 16 | dev << 11 | fn << 8; 382 reg[1] = reg[2] = 0; 383 reg[3] = ih.ih_intrpin; 384 385 return fdt_intr_establish_imap_cpu(sc->sc_node, reg, sizeof(reg), 386 level, ci, func, arg, name); 387 } 388 389 void 390 bcmpcie_intr_disestablish(void *v, void *cookie) 391 { 392 } 393 394 int 395 bcmpcie_bs_iomap(bus_space_tag_t t, bus_addr_t addr, bus_size_t size, 396 int flags, bus_space_handle_t *bshp) 397 { 398 struct bcmpcie_softc *sc = t->bus_private; 399 int i; 400 401 for (i = 0; i < sc->sc_nranges; i++) { 402 uint64_t pci_start = sc->sc_ranges[i].pci_base; 403 uint64_t pci_end = pci_start + sc->sc_ranges[i].size; 404 uint64_t phys_start = sc->sc_ranges[i].phys_base; 405 406 if ((sc->sc_ranges[i].flags & 0x03000000) == 0x01000000 && 407 addr >= pci_start && addr + size <= pci_end) { 408 return bus_space_map(sc->sc_iot, 409 addr - pci_start + phys_start, size, flags, bshp); 410 } 411 } 412 413 return ENXIO; 414 } 415 416 int 417 bcmpcie_bs_memmap(bus_space_tag_t t, bus_addr_t addr, bus_size_t size, 418 int flags, bus_space_handle_t *bshp) 419 { 420 struct bcmpcie_softc *sc = t->bus_private; 421 int i; 422 423 for (i = 0; i < sc->sc_nranges; i++) { 424 uint64_t pci_start = sc->sc_ranges[i].pci_base; 425 uint64_t pci_end = pci_start + sc->sc_ranges[i].size; 426 uint64_t phys_start = sc->sc_ranges[i].phys_base; 427 428 if ((sc->sc_ranges[i].flags & 0x03000000) == 0x02000000 && 429 addr >= pci_start && addr + size <= pci_end) { 430 return bus_space_map(sc->sc_iot, 431 addr - pci_start + phys_start, size, flags, bshp); 432 } 433 } 434 435 return ENXIO; 436 } 437