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