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