1 /* $OpenBSD: aplpcie.c,v 1.1 2021/02/26 11:09:23 kettenis Exp $ */ 2 /* 3 * Copyright (c) 2021 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 32 #include <dev/ofw/openfirm.h> 33 #include <dev/ofw/ofw_misc.h> 34 #include <dev/ofw/fdt.h> 35 36 /* 37 * This driver is based on preliminary device tree bindings and will 38 * almost certainly need changes once the official bindings land in 39 * mainline Linux. Support for these preliminary bindings will be 40 * dropped as soon as official bindings are available. 41 * 42 * The driver assumes that the hardware has been (almost) completely 43 * initialized by U-Boot. More code will be needed to support 44 * alternate boot paths. 45 */ 46 47 #define PCIE_MSI_CTRL 0x0124 48 #define PCIE_MSI_CTRL_ENABLE (1 << 0) 49 #define PCIE_MSI_CTRL_32 (5 << 4) 50 #define PCIE_MSI_REMAP 0x0128 51 #define PCIE_MSI_DOORBELL 0x0168 52 53 #define HREAD4(sc, reg) \ 54 (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) 55 #define HWRITE4(sc, reg, val) \ 56 bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) 57 58 struct aplpcie_range { 59 uint32_t flags; 60 uint64_t pci_base; 61 uint64_t phys_base; 62 uint64_t size; 63 }; 64 65 struct aplpcie_softc { 66 struct device sc_dev; 67 bus_space_tag_t sc_iot; 68 bus_space_handle_t sc_ioh; 69 bus_space_handle_t sc_port_ioh[3]; 70 bus_dma_tag_t sc_dmat; 71 72 int sc_node; 73 int sc_acells; 74 int sc_scells; 75 int sc_pacells; 76 int sc_pscells; 77 struct aplpcie_range *sc_ranges; 78 int sc_nranges; 79 80 struct bus_space sc_bus_iot; 81 struct bus_space sc_bus_memt; 82 83 struct arm64_pci_chipset sc_pc; 84 struct extent *sc_busex; 85 struct extent *sc_memex; 86 struct extent *sc_pmemex; 87 struct extent *sc_ioex; 88 int sc_bus; 89 90 int sc_msi; 91 bus_addr_t sc_msi_doorbell; 92 }; 93 94 int aplpcie_match(struct device *, void *, void *); 95 void aplpcie_attach(struct device *, struct device *, void *); 96 97 struct cfattach aplpcie_ca = { 98 sizeof (struct aplpcie_softc), aplpcie_match, aplpcie_attach 99 }; 100 101 struct cfdriver aplpcie_cd = { 102 NULL, "aplpcie", DV_DULL 103 }; 104 105 int 106 aplpcie_match(struct device *parent, void *match, void *aux) 107 { 108 struct fdt_attach_args *faa = aux; 109 110 return OF_is_compatible(faa->fa_node, "apple,pcie-m1"); 111 } 112 113 void aplpcie_attach_hook(struct device *, struct device *, 114 struct pcibus_attach_args *); 115 int aplpcie_bus_maxdevs(void *, int); 116 pcitag_t aplpcie_make_tag(void *, int, int, int); 117 void aplpcie_decompose_tag(void *, pcitag_t, int *, int *, int *); 118 int aplpcie_conf_size(void *, pcitag_t); 119 pcireg_t aplpcie_conf_read(void *, pcitag_t, int); 120 void aplpcie_conf_write(void *, pcitag_t, int, pcireg_t); 121 int aplpcie_probe_device_hook(void *, struct pci_attach_args *); 122 123 int aplpcie_intr_map(struct pci_attach_args *, pci_intr_handle_t *); 124 const char *aplpcie_intr_string(void *, pci_intr_handle_t); 125 void *aplpcie_intr_establish(void *, pci_intr_handle_t, int, 126 struct cpu_info *, int (*)(void *), void *, char *); 127 void aplpcie_intr_disestablish(void *, void *); 128 129 int aplpcie_bs_iomap(bus_space_tag_t, bus_addr_t, bus_size_t, int, 130 bus_space_handle_t *); 131 int aplpcie_bs_memmap(bus_space_tag_t, bus_addr_t, bus_size_t, int, 132 bus_space_handle_t *); 133 134 void 135 aplpcie_attach(struct device *parent, struct device *self, void *aux) 136 { 137 struct aplpcie_softc *sc = (struct aplpcie_softc *)self; 138 struct fdt_attach_args *faa = aux; 139 struct pcibus_attach_args pba; 140 uint32_t *ranges; 141 int i, j, nranges, rangeslen; 142 uint32_t bus_range[2]; 143 144 if (faa->fa_nreg < 6) { 145 printf(": no registers\n"); 146 return; 147 } 148 149 sc->sc_iot = faa->fa_iot; 150 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 151 faa->fa_reg[0].size, 0, &sc->sc_ioh)) { 152 printf(": can't map registers\n"); 153 return; 154 } 155 156 for (i = 3; i < 6; i++) { 157 if (bus_space_map(sc->sc_iot, faa->fa_reg[i].addr, 158 faa->fa_reg[i].size, 0, &sc->sc_port_ioh[i - 3])) { 159 printf(": can't map registers\n"); 160 return; 161 } 162 } 163 164 sc->sc_dmat = faa->fa_dmat; 165 sc->sc_node = faa->fa_node; 166 printf("\n"); 167 168 sc->sc_msi_doorbell = 169 OF_getpropint64(sc->sc_node, "msi-doorbell", 0xffff000ULL); 170 171 /* 172 * Set things up such that we can share the 32 available MSIs 173 * across all ports. 174 */ 175 for (i = 0; i < 3; i++) { 176 bus_space_write_4(sc->sc_iot, sc->sc_port_ioh[i], 177 PCIE_MSI_CTRL, PCIE_MSI_CTRL_32 | PCIE_MSI_CTRL_ENABLE); 178 bus_space_write_4(sc->sc_iot, sc->sc_port_ioh[i], 179 PCIE_MSI_REMAP, 0); 180 bus_space_write_4(sc->sc_iot, sc->sc_port_ioh[i], 181 PCIE_MSI_DOORBELL, sc->sc_msi_doorbell); 182 } 183 sc->sc_msi = 0; 184 185 sc->sc_acells = OF_getpropint(sc->sc_node, "#address-cells", 186 faa->fa_acells); 187 sc->sc_scells = OF_getpropint(sc->sc_node, "#size-cells", 188 faa->fa_scells); 189 sc->sc_pacells = faa->fa_acells; 190 sc->sc_pscells = faa->fa_scells; 191 192 rangeslen = OF_getproplen(sc->sc_node, "ranges"); 193 if (rangeslen <= 0 || (rangeslen % sizeof(uint32_t)) || 194 (rangeslen / sizeof(uint32_t)) % (sc->sc_acells + 195 sc->sc_pacells + sc->sc_scells)) { 196 printf(": invalid ranges property\n"); 197 return; 198 } 199 200 ranges = malloc(rangeslen, M_TEMP, M_WAITOK); 201 OF_getpropintarray(sc->sc_node, "ranges", ranges, 202 rangeslen); 203 204 nranges = (rangeslen / sizeof(uint32_t)) / 205 (sc->sc_acells + sc->sc_pacells + sc->sc_scells); 206 sc->sc_ranges = mallocarray(nranges, 207 sizeof(struct aplpcie_range), M_TEMP, M_WAITOK); 208 sc->sc_nranges = nranges; 209 210 for (i = 0, j = 0; i < sc->sc_nranges; i++) { 211 sc->sc_ranges[i].flags = ranges[j++]; 212 sc->sc_ranges[i].pci_base = ranges[j++]; 213 if (sc->sc_acells - 1 == 2) { 214 sc->sc_ranges[i].pci_base <<= 32; 215 sc->sc_ranges[i].pci_base |= ranges[j++]; 216 } 217 sc->sc_ranges[i].phys_base = ranges[j++]; 218 if (sc->sc_pacells == 2) { 219 sc->sc_ranges[i].phys_base <<= 32; 220 sc->sc_ranges[i].phys_base |= ranges[j++]; 221 } 222 sc->sc_ranges[i].size = ranges[j++]; 223 if (sc->sc_scells == 2) { 224 sc->sc_ranges[i].size <<= 32; 225 sc->sc_ranges[i].size |= ranges[j++]; 226 } 227 } 228 229 free(ranges, M_TEMP, rangeslen); 230 231 /* Create extents for our address spaces. */ 232 sc->sc_busex = extent_create("pcibus", 0, 255, 233 M_DEVBUF, NULL, 0, EX_WAITOK | EX_FILLED); 234 sc->sc_memex = extent_create("pcimem", 0, (u_long)-1, 235 M_DEVBUF, NULL, 0, EX_WAITOK | EX_FILLED); 236 sc->sc_pmemex = extent_create("pcipmem", 0, (u_long)-1, 237 M_DEVBUF, NULL, 0, EX_WAITOK | EX_FILLED); 238 sc->sc_ioex = extent_create("pciio", 0, 0xffffffff, 239 M_DEVBUF, NULL, 0, EX_WAITOK | EX_FILLED); 240 for (i = 0; i < sc->sc_nranges; i++) { 241 if ((sc->sc_ranges[i].flags & 0x03000000) == 0x01000000) { 242 extent_free(sc->sc_ioex, sc->sc_ranges[i].pci_base, 243 sc->sc_ranges[i].size, EX_WAITOK); 244 } 245 if ((sc->sc_ranges[i].flags & 0x03000000) == 0x02000000) { 246 extent_free(sc->sc_memex, sc->sc_ranges[i].pci_base, 247 sc->sc_ranges[i].size, EX_WAITOK); 248 } 249 if ((sc->sc_ranges[i].flags & 0x03000000) == 0x03000000) { 250 extent_free(sc->sc_pmemex, sc->sc_ranges[i].pci_base, 251 sc->sc_ranges[i].size, EX_WAITOK); 252 } 253 } 254 255 /* Set up bus range. */ 256 if (OF_getpropintarray(sc->sc_node, "bus-range", bus_range, 257 sizeof(bus_range)) != sizeof(bus_range) || 258 bus_range[0] >= 32 || bus_range[1] >= 32) { 259 bus_range[0] = 0; 260 bus_range[1] = 31; 261 } 262 sc->sc_bus = bus_range[0]; 263 extent_free(sc->sc_busex, bus_range[0], 264 bus_range[1] - bus_range[0] + 1, EX_WAITOK); 265 266 memcpy(&sc->sc_bus_iot, sc->sc_iot, sizeof(sc->sc_bus_iot)); 267 sc->sc_bus_iot.bus_private = sc; 268 sc->sc_bus_iot._space_map = aplpcie_bs_iomap; 269 memcpy(&sc->sc_bus_memt, sc->sc_iot, sizeof(sc->sc_bus_memt)); 270 sc->sc_bus_memt.bus_private = sc; 271 sc->sc_bus_memt._space_map = aplpcie_bs_memmap; 272 273 sc->sc_pc.pc_conf_v = sc; 274 sc->sc_pc.pc_attach_hook = aplpcie_attach_hook; 275 sc->sc_pc.pc_bus_maxdevs = aplpcie_bus_maxdevs; 276 sc->sc_pc.pc_make_tag = aplpcie_make_tag; 277 sc->sc_pc.pc_decompose_tag = aplpcie_decompose_tag; 278 sc->sc_pc.pc_conf_size = aplpcie_conf_size; 279 sc->sc_pc.pc_conf_read = aplpcie_conf_read; 280 sc->sc_pc.pc_conf_write = aplpcie_conf_write; 281 sc->sc_pc.pc_probe_device_hook = aplpcie_probe_device_hook; 282 283 sc->sc_pc.pc_intr_v = sc; 284 sc->sc_pc.pc_intr_map = aplpcie_intr_map; 285 sc->sc_pc.pc_intr_map_msi = _pci_intr_map_msi; 286 sc->sc_pc.pc_intr_map_msix = _pci_intr_map_msix; 287 sc->sc_pc.pc_intr_string = aplpcie_intr_string; 288 sc->sc_pc.pc_intr_establish = aplpcie_intr_establish; 289 sc->sc_pc.pc_intr_disestablish = aplpcie_intr_disestablish; 290 291 memset(&pba, 0, sizeof(pba)); 292 pba.pba_busname = "pci"; 293 pba.pba_iot = &sc->sc_bus_iot; 294 pba.pba_memt = &sc->sc_bus_memt; 295 pba.pba_dmat = sc->sc_dmat; 296 pba.pba_pc = &sc->sc_pc; 297 pba.pba_busex = sc->sc_busex; 298 pba.pba_memex = sc->sc_memex; 299 pba.pba_pmemex = sc->sc_pmemex; 300 pba.pba_ioex = sc->sc_ioex; 301 pba.pba_domain = pci_ndomains++; 302 pba.pba_bus = sc->sc_bus; 303 pba.pba_flags |= PCI_FLAGS_MSI_ENABLED; 304 305 config_found(self, &pba, NULL); 306 } 307 308 void 309 aplpcie_attach_hook(struct device *parent, struct device *self, 310 struct pcibus_attach_args *pba) 311 { 312 } 313 314 int 315 aplpcie_bus_maxdevs(void *v, int bus) 316 { 317 return 32; 318 } 319 320 pcitag_t 321 aplpcie_make_tag(void *v, int bus, int device, int function) 322 { 323 /* Return ECAM address. */ 324 return ((bus << 20) | (device << 15) | (function << 12)); 325 } 326 327 void 328 aplpcie_decompose_tag(void *v, pcitag_t tag, int *bp, int *dp, int *fp) 329 { 330 if (bp != NULL) 331 *bp = (tag >> 20) & 0xff; 332 if (dp != NULL) 333 *dp = (tag >> 15) & 0x1f; 334 if (fp != NULL) 335 *fp = (tag >> 12) & 0x7; 336 } 337 338 int 339 aplpcie_conf_size(void *v, pcitag_t tag) 340 { 341 return PCIE_CONFIG_SPACE_SIZE; 342 } 343 344 pcireg_t 345 aplpcie_conf_read(void *v, pcitag_t tag, int reg) 346 { 347 struct aplpcie_softc *sc = v; 348 349 return HREAD4(sc, tag | reg); 350 } 351 352 void 353 aplpcie_conf_write(void *v, pcitag_t tag, int reg, pcireg_t data) 354 { 355 struct aplpcie_softc *sc = v; 356 357 HWRITE4(sc, tag | reg, data); 358 } 359 360 int 361 aplpcie_probe_device_hook(void *v, struct pci_attach_args *pa) 362 { 363 struct aplpcie_softc *sc = v; 364 uint16_t rid; 365 366 rid = pci_requester_id(pa->pa_pc, pa->pa_tag); 367 pa->pa_dmat = iommu_device_map_pci(sc->sc_node, rid, pa->pa_dmat); 368 369 return 0; 370 } 371 372 int 373 aplpcie_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp) 374 { 375 int pin = pa->pa_rawintrpin; 376 377 if (pin == 0 || pin > PCI_INTERRUPT_PIN_MAX) 378 return -1; 379 380 if (pa->pa_tag == 0) 381 return -1; 382 383 ihp->ih_pc = pa->pa_pc; 384 ihp->ih_tag = pa->pa_intrtag; 385 ihp->ih_intrpin = pa->pa_intrpin; 386 ihp->ih_type = PCI_INTX; 387 388 return 0; 389 } 390 391 const char * 392 aplpcie_intr_string(void *v, pci_intr_handle_t ih) 393 { 394 switch (ih.ih_type) { 395 case PCI_MSI: 396 return "msi"; 397 case PCI_MSIX: 398 return "msix"; 399 } 400 401 return "intx"; 402 } 403 404 void * 405 aplpcie_intr_establish(void *v, pci_intr_handle_t ih, int level, 406 struct cpu_info *ci, int (*func)(void *), void *arg, char *name) 407 { 408 struct aplpcie_softc *sc = v; 409 void *cookie; 410 411 KASSERT(ih.ih_type != PCI_NONE); 412 413 if (ih.ih_type != PCI_INTX) { 414 uint64_t addr, data; 415 416 data = sc->sc_msi++; 417 addr = sc->sc_msi_doorbell; 418 cookie = fdt_intr_establish_idx_cpu(sc->sc_node, 3 + data, 419 level, ci, func, arg, (void *)name); 420 if (cookie == NULL) 421 return NULL; 422 423 if (ih.ih_type == PCI_MSIX) { 424 pci_msix_enable(ih.ih_pc, ih.ih_tag, 425 &sc->sc_bus_memt, ih.ih_intrpin, addr, data); 426 } else 427 pci_msi_enable(ih.ih_pc, ih.ih_tag, addr, data); 428 } else { 429 int bus, dev, fn; 430 uint32_t reg[4]; 431 432 aplpcie_decompose_tag(sc, ih.ih_tag, &bus, &dev, &fn); 433 434 reg[0] = bus << 16 | dev << 11 | fn << 8; 435 reg[1] = reg[2] = 0; 436 reg[3] = ih.ih_intrpin; 437 438 cookie = fdt_intr_establish_imap_cpu(sc->sc_node, reg, 439 sizeof(reg), level, ci, func, arg, name); 440 } 441 442 return cookie; 443 } 444 445 void 446 aplpcie_intr_disestablish(void *v, void *cookie) 447 { 448 } 449 450 int 451 aplpcie_bs_iomap(bus_space_tag_t t, bus_addr_t addr, bus_size_t size, 452 int flags, bus_space_handle_t *bshp) 453 { 454 struct aplpcie_softc *sc = t->bus_private; 455 int i; 456 457 for (i = 0; i < sc->sc_nranges; i++) { 458 uint64_t pci_start = sc->sc_ranges[i].pci_base; 459 uint64_t pci_end = pci_start + sc->sc_ranges[i].size; 460 uint64_t phys_start = sc->sc_ranges[i].phys_base; 461 462 if ((sc->sc_ranges[i].flags & 0x03000000) == 0x01000000 && 463 addr >= pci_start && addr + size <= pci_end) { 464 return bus_space_map(sc->sc_iot, 465 addr - pci_start + phys_start, size, flags, bshp); 466 } 467 } 468 469 return ENXIO; 470 } 471 472 int 473 aplpcie_bs_memmap(bus_space_tag_t t, bus_addr_t addr, bus_size_t size, 474 int flags, bus_space_handle_t *bshp) 475 { 476 struct aplpcie_softc *sc = t->bus_private; 477 int i; 478 479 flags |= BUS_SPACE_MAP_POSTED; 480 481 for (i = 0; i < sc->sc_nranges; i++) { 482 uint64_t pci_start = sc->sc_ranges[i].pci_base; 483 uint64_t pci_end = pci_start + sc->sc_ranges[i].size; 484 uint64_t phys_start = sc->sc_ranges[i].phys_base; 485 486 if ((sc->sc_ranges[i].flags & 0x02000000) == 0x02000000 && 487 addr >= pci_start && addr + size <= pci_end) { 488 return bus_space_map(sc->sc_iot, 489 addr - pci_start + phys_start, size, flags, bshp); 490 } 491 } 492 493 return ENXIO; 494 } 495