1 /*        $NetBSD: bcm2838_pcie.c,v 1.10 2025/01/03 13:04:02 skrll Exp $ */
2 
3 /*-
4  * Copyright (c) 2020 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Michael van Elst
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: bcm2838_pcie.c,v 1.10 2025/01/03 13:04:02 skrll Exp $");
34 
35 #include <sys/param.h>
36 #include <sys/device.h>
37 
38 #include <dev/pci/pcireg.h>
39 #include <dev/pci/pcivar.h>
40 #include <dev/pci/pciconf.h>
41 
42 #include <dev/fdt/fdtvar.h>
43 
44 #include <arch/arm/pci/pci_msi_machdep.h>
45 #include <arch/arm/broadcom/bcm2838_pcie.h>
46 
47 #include <arch/evbarm/rpi/vcprop.h>
48 #include <dev/pci/pcidevs.h>
49 
50 #define PHYS_HI_RELO                    __BIT(31)
51 #define PHYS_HI_PREFETCH      __BIT(30)
52 #define PHYS_HI_ALIASED                 __BIT(29)
53 #define PHYS_HI_SPACE                   __BITS(25,24)
54 #define  PHYS_HI_SPACE_CFG    0
55 #define  PHYS_HI_SPACE_IO     1
56 #define  PHYS_HI_SPACE_MEM32  2
57 #define  PHYS_HI_SPACE_MEM64  3
58 
59 #define CFG_OFFSET(b,d,f,r) ((b) << 16 | (d) << 1 | (f) << 8 | (r))
60 
61 struct bcmstb_busspace {
62           struct bus_space    bst;
63           int                           (*map)(void *, bus_addr_t, bus_size_t,
64                                             int, bus_space_handle_t *);
65           int                           flags;
66           struct {
67                     bus_addr_t          bpci;
68                     bus_addr_t          bbus;
69                     bus_size_t          size;
70           }                             ranges[4];
71           size_t                        nranges;
72 };
73 
74 struct bcmstb_softc {
75           bus_space_tag_t               sc_bst;
76           bus_space_handle_t  sc_bsh;
77           bus_dma_tag_t                 sc_dmat;
78 
79           kmutex_t            sc_lock;
80           const char *                  sc_name;
81 
82           int                           sc_phandle;
83 
84           uint32_t            sc_bus_min;
85           uint32_t            sc_bus_max;
86 
87           struct arm32_pci_chipset      sc_pc;
88 
89           struct bcmstb_busspace        sc_io;
90           struct bcmstb_busspace        sc_mem;
91 
92           int                           sc_pci_flags;
93 };
94 
95 static void         bcmstb_attach(device_t, struct bcmstb_softc *);
96 static int          bcmstb_config(struct bcmstb_softc *);
97 static int          bcmstb_setup(struct bcmstb_softc *);
98 static void         bcmstb_attach_hook(device_t, device_t, struct pcibus_attach_args *);
99 static int          bcmstb_bus_maxdevs(void *, int);
100 static pcitag_t bcmstb_make_tag(void *, int, int, int);
101 static void         bcmstb_decompose_tag(void *, pcitag_t, int *, int *, int *);
102 static u_int        bcmstb_get_segment(void *);
103 static pcireg_t bcmstb_conf_read(void *, pcitag_t, int);
104 static void         bcmstb_conf_write(void *, pcitag_t, int, pcireg_t);
105 static int          bcmstb_conf_hook(void *, int, int, int, pcireg_t);
106 static void         bcmstb_conf_interrupt(void *, int, int, int, int, int *);
107 
108 static int                              bcmstb_intr_map(const struct pci_attach_args *, pci_intr_handle_t *);
109 static const char             *bcmstb_intr_string(void *, pci_intr_handle_t, char *, size_t);
110 static const struct evcnt     *bcmstb_intr_evcnt(void *, pci_intr_handle_t);
111 static int                              bcmstb_intr_setattr(void *, pci_intr_handle_t *, int, uint64_t);
112 static void                             *bcmstb_intr_establish(void *, pci_intr_handle_t, int,
113                                             int (*)(void *), void *, const char *);
114 static void                             bcmstb_intr_disestablish(void *, void *);
115 static int                              bcmstb_bus_space_map(void *, bus_addr_t,
116                                             bus_size_t, int, bus_space_handle_t *);
117 
118 struct bcm2838pcie_softc {
119           device_t            sc_dev;
120           struct bcmstb_softc sc_bcmstb;
121 };
122 
123 static int bcm2838pcie_match(device_t, cfdata_t, void *);
124 static void bcm2838pcie_attach(device_t, device_t, void *);
125 
126 CFATTACH_DECL_NEW(bcm2838pcie_fdt, sizeof(struct bcm2838pcie_softc),
127     bcm2838pcie_match, bcm2838pcie_attach, NULL, NULL);
128 
129 
130 static inline void
stb_write(struct bcmstb_softc * sc,int r,uint32_t v)131 stb_write(struct bcmstb_softc *sc, int r, uint32_t v)
132 {
133           bus_space_write_4(sc->sc_bst, sc->sc_bsh, r, v);
134 }
135 
136 static inline uint32_t
stb_read(struct bcmstb_softc * sc,int r)137 stb_read(struct bcmstb_softc *sc, int r)
138 {
139           uint32_t v;
140 
141           v = bus_space_read_4(sc->sc_bst, sc->sc_bsh, r);
142 
143           return v;
144 }
145 static inline void
stb_setbits(struct bcmstb_softc * sc,int r,uint32_t clr,uint32_t set)146 stb_setbits(struct bcmstb_softc *sc, int r, uint32_t clr, uint32_t set)
147 {
148           uint32_t w;
149 
150           w = stb_read(sc, r);
151           w = (w & ~clr) | set;
152           stb_write(sc, r, w);
153 }
154 #define STBWRITE(sc, r, v)    stb_write((sc), (r), (v))
155 #define STBREAD(sc, r)                  stb_read((sc), (r))
156 #define STBRMW(sc, r, c, s)   stb_setbits((sc), (r), (c), (s))
157 
158 static const struct device_compatible_entry compat_data[] = {
159           { .compat = "brcm,pci-plat-dev" },
160           { .compat = "brcm,bcm2711-pcie" },
161           DEVICE_COMPAT_EOL
162 };
163 
164 /* ARGSUSED */
165 static int
bcm2838pcie_match(device_t parent,cfdata_t match,void * aux)166 bcm2838pcie_match(device_t parent, cfdata_t match, void *aux)
167 {
168           struct fdt_attach_args * const faa = aux;
169 
170           return of_compatible_match(faa->faa_phandle, compat_data);
171 }
172 
173 static void
bcm2838pcie_attach(device_t parent,device_t self,void * aux)174 bcm2838pcie_attach(device_t parent, device_t self, void *aux)
175 {
176           struct bcm2838pcie_softc *sc = device_private(self);
177           struct fdt_attach_args * const faa = aux;
178           bus_addr_t addr;
179           bus_size_t size;
180           bus_dma_tag_t dmat;
181           bus_space_tag_t bst;
182           bus_space_handle_t bsh;
183           int error;
184 
185           sc->sc_dev = self;
186 
187           mutex_init(&sc->sc_bcmstb.sc_lock, MUTEX_DEFAULT, IPL_HIGH);
188 
189           error = fdtbus_get_reg(faa->faa_phandle, 0, &addr, &size);
190           if (error) {
191                     aprint_error_dev(sc->sc_dev, ": couldn't get registers\n");
192                     return;
193           }
194 
195           // bst = faa->faa_bst;
196           extern struct bus_space arm_generic_bs_tag;
197           bst = &arm_generic_bs_tag;
198 
199           if (bus_space_map(faa->faa_bst, addr, size, 0, &bsh)) {
200                     aprint_error_dev(sc->sc_dev, ": unable to map device\n");
201                     return;
202           }
203 
204           /* RPI4 limits PCIe DMA to the first 3GB */
205           error = bus_dmatag_subregion(faa->faa_dmat, 0, 0xbfffffff,
206                     &dmat, BUS_DMA_WAITOK);
207 
208           if (error == EOPNOTSUPP) {
209                     /* assume default DMA tag is fine */
210                     dmat = faa->faa_dmat;
211           } else if (error) {
212                     aprint_error_dev(sc->sc_dev, ": unable to subregion DMA\n");
213                     bus_space_unmap(faa->faa_bst, bsh, size);
214                     return;
215           }
216 
217           aprint_naive("\n");
218           aprint_normal(": Broadcom PCIE Host Controller\n");
219 
220           if (error == 0)
221                     aprint_normal_dev(sc->sc_dev, "Using 3GB DMA subregion\n");
222 
223           sc->sc_bcmstb.sc_bst = bst;
224           sc->sc_bcmstb.sc_bsh = bsh;
225           sc->sc_bcmstb.sc_dmat = dmat;
226           sc->sc_bcmstb.sc_name = device_xname(sc->sc_dev);
227           sc->sc_bcmstb.sc_phandle = faa->faa_phandle;
228 
229           bcmstb_attach(sc->sc_dev, &sc->sc_bcmstb);
230 }
231 
232 static void
bcmstb_attach(device_t self,struct bcmstb_softc * sc)233 bcmstb_attach(device_t self, struct bcmstb_softc *sc)
234 {
235           struct arm32_pci_chipset *pc;
236           struct pcibus_attach_args pba;
237           int error;
238 
239           // fdtbus_register_interrupt_controller(self, OF_child(sc->sc_phandle),
240           //           &bcmstb_intrfuncs);
241 
242           pc = &sc->sc_pc;
243 
244           pc->pc_conf_v = (void *)sc;
245           pc->pc_attach_hook = bcmstb_attach_hook;
246           pc->pc_bus_maxdevs = bcmstb_bus_maxdevs;
247           pc->pc_make_tag = bcmstb_make_tag;
248           pc->pc_decompose_tag = bcmstb_decompose_tag;
249           pc->pc_get_segment = bcmstb_get_segment;
250           pc->pc_conf_read = bcmstb_conf_read;
251           pc->pc_conf_write = bcmstb_conf_write;
252           pc->pc_conf_hook = bcmstb_conf_hook;
253           pc->pc_conf_interrupt = bcmstb_conf_interrupt;
254 
255           pc->pc_intr_v = (void *)sc;
256           pc->pc_intr_map = bcmstb_intr_map;
257           pc->pc_intr_string = bcmstb_intr_string;
258           pc->pc_intr_evcnt = bcmstb_intr_evcnt;
259           pc->pc_intr_setattr = bcmstb_intr_setattr;
260           pc->pc_intr_establish = bcmstb_intr_establish;
261           pc->pc_intr_disestablish = bcmstb_intr_disestablish;
262 
263           /* XXX bus-range */
264           sc->sc_bus_min = 0x00;
265           sc->sc_bus_max = 0x01;
266 
267           error = bcmstb_config(sc);
268           if (error) {
269                     aprint_error_dev(self, "configuration failed: %d\n", error);
270                     return;
271           }
272 
273           memset(&pba, 0, sizeof(pba));
274           pba.pba_flags = sc->sc_pci_flags;
275           pba.pba_iot = &sc->sc_io.bst;
276           pba.pba_memt = &sc->sc_mem.bst;
277           pba.pba_dmat = sc->sc_dmat;
278 #ifdef _PCI_HAVE_DMA64
279           pba.pba_dmat64 = sc->sc_dmat;
280 #endif
281           pba.pba_pc = pc;
282           pba.pba_bus = sc->sc_bus_min;
283 
284           config_found(self, &pba, pcibusprint,
285               CFARGS(.devhandle = device_handle(self)));
286 }
287 
288 static void
bcmstb_makespace(struct bcmstb_softc * sc,struct bcmstb_busspace * bs,int flags)289 bcmstb_makespace(struct bcmstb_softc *sc, struct bcmstb_busspace *bs, int flags)
290 {
291           bs->bst = *sc->sc_bst;
292           bs->bst.bs_cookie = bs;
293           bs->map = bs->bst.bs_map;
294           bs->bst.bs_map = bcmstb_bus_space_map;
295           bs->flags = flags;
296 }
297 
298 static int
bcmstb_addrange(struct bcmstb_busspace * bs,bus_addr_t pci,bus_addr_t bus,bus_size_t sz)299 bcmstb_addrange(struct bcmstb_busspace *bs, bus_addr_t pci, bus_addr_t bus, bus_size_t sz)
300 {
301           if (bs->nranges >= __arraycount(bs->ranges))
302                     return -1;
303 
304           bs->ranges[bs->nranges].bpci = pci;
305           bs->ranges[bs->nranges].bbus = bus;
306           bs->ranges[bs->nranges].size = sz;
307           ++bs->nranges;
308 
309           return 0;
310 }
311 
312 static int
bcmstb_config(struct bcmstb_softc * sc)313 bcmstb_config(struct bcmstb_softc *sc)
314 {
315           const u_int *ranges;
316           int len, type, error;
317           struct pciconf_resources *pcires;
318           uint32_t phys_hi;
319           uint64_t bus_phys, cpu_phys, size;
320 
321           bcmstb_makespace(sc, &sc->sc_io, PCI_FLAGS_IO_OKAY);
322           bcmstb_makespace(sc, &sc->sc_mem, PCI_FLAGS_MEM_OKAY);
323 
324           ranges = fdtbus_get_prop(sc->sc_phandle, "ranges", &len);
325           if (ranges == NULL) {
326                     aprint_error("%s: missing 'ranges' property\n", sc->sc_name);
327                     return ENXIO;
328           }
329 
330           pcires = pciconf_resource_init();
331 
332           while (len >= 28) {
333                     phys_hi = be32toh(ranges[0]);
334                     bus_phys = ((uint64_t)be32toh(ranges[1])) << 32 | be32toh(ranges[2]);
335                     cpu_phys = ((uint64_t)be32toh(ranges[3])) << 32 | be32toh(ranges[4]);
336                     size     = ((uint64_t)be32toh(ranges[5])) << 32 | be32toh(ranges[6]);
337 
338                     len -= 28;
339                     ranges += 7;
340 
341                     switch (__SHIFTOUT(phys_hi, PHYS_HI_SPACE)) {
342                     case PHYS_HI_SPACE_IO:
343                               if (bcmstb_addrange(&sc->sc_io, bus_phys, cpu_phys, size)) {
344                                         aprint_error("%s: too many IO ranges\n", sc->sc_name);
345                                         continue;
346                               }
347                               type = PCICONF_RESOURCE_IO;
348 
349                               aprint_verbose("%s: IO: 0x%" PRIx64 "+0x%" PRIx64 "@0x%" PRIx64 "\n",
350                                   sc->sc_name,
351                                   bus_phys, size, cpu_phys);
352 
353                               error = pciconf_resource_add(pcires, type, bus_phys, size);
354                               if (error == 0)
355                                         sc->sc_pci_flags |= PCI_FLAGS_IO_OKAY;
356                               break;
357                     case PHYS_HI_SPACE_MEM64:
358                               /* FALLTHROUGH */
359                     case PHYS_HI_SPACE_MEM32:
360                               if (bcmstb_addrange(&sc->sc_mem, bus_phys, cpu_phys, size)) {
361                                         aprint_error("%s: too many mem ranges\n", sc->sc_name);
362                                         continue;
363                               }
364                               if ((phys_hi & PHYS_HI_PREFETCH) != 0 ||
365                                   __SHIFTOUT(phys_hi, PHYS_HI_SPACE) == PHYS_HI_SPACE_MEM64) {
366                                         type = PCICONF_RESOURCE_PREFETCHABLE_MEM;
367                               } else {
368                                         type = PCICONF_RESOURCE_MEM;
369                               }
370 
371                               aprint_verbose("%s: MMIO (%d-bit%s): 0x%" PRIx64 "+0x%" PRIx64 "@0x%" PRIx64 "\n",
372                                   sc->sc_name,
373                                   __SHIFTOUT(phys_hi, PHYS_HI_SPACE) == PHYS_HI_SPACE_MEM64 ? 64 : 32,
374                                   type == PCICONF_RESOURCE_PREFETCHABLE_MEM ? " prefetchable" : "",
375                                   bus_phys, size, cpu_phys);
376 
377                               error = pciconf_resource_add(pcires, type, bus_phys, size);
378                               if (error == 0)
379                                         sc->sc_pci_flags |= PCI_FLAGS_MEM_OKAY;
380                               break;
381                     default:
382                               break;
383                     }
384           }
385 
386           error = bcmstb_setup(sc);
387           if (error)
388                     return error;
389 
390           error = pci_configure_bus(&sc->sc_pc, pcires, sc->sc_bus_min, 64);
391           pciconf_resource_fini(pcires);
392 
393           return error;
394 }
395 
396 static void
bcmstb_setwin(struct bcmstb_softc * sc,int win,uint64_t pa,uint64_t ca,uint64_t sz)397 bcmstb_setwin(struct bcmstb_softc *sc, int win, uint64_t pa, uint64_t ca,
398     uint64_t sz)
399 {
400           uint32_t base, limit;
401 
402           STBWRITE(sc, PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LO(win), pa);
403           STBWRITE(sc, PCIE_MISC_CPU_2_PCIE_MEM_WIN0_HI(win), pa >> 32);
404 
405           base = (ca >> 20) & 0xfff;
406           limit = ((ca + sz - 1) >> 20) & 0xfff;
407 
408           STBRMW(sc, PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT(win),
409               PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_BASE
410               | PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_LIMIT,
411               __SHIFTIN(base, PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_BASE)
412               | __SHIFTIN(limit, PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_LIMIT));
413 
414           base = (ca >> 32) & 0xff;
415           limit = ((ca + sz - 1) >> 32) & 0xff;
416 
417           STBRMW(sc, PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI(win),
418               PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI_BASE,
419               __SHIFTIN(base, PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI_BASE));
420 
421           STBRMW(sc, PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI(win),
422               PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI_LIMIT,
423               __SHIFTIN(base, PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI_LIMIT));
424 }
425 
426 static int
bcmstb_encode_size(int bits)427 bcmstb_encode_size(int bits)
428 {
429           /* 4K .. 32K */
430           if (bits >= 12 && bits <= 15)
431                     return 28 + (bits - 12);
432 
433           /* 64K .. 32G */
434           if (bits >= 16 && bits <= 35)
435                     return 1 + (bits - 16);
436 
437           /* invalid */
438           return 0;
439 }
440 
441 static int
bcmstb_setup(struct bcmstb_softc * sc)442 bcmstb_setup(struct bcmstb_softc *sc)
443 {
444           struct bcmstb_busspace * const bs = &sc->sc_mem;
445           uint32_t w, m;
446           uint64_t ad;
447           int t, i, sz;
448 
449           /* Reset */
450           STBRMW(sc, PCIE_RGR1_SW_INIT_1, 0, PCIE_RGR1_SW_INIT_1_INIT);
451           delay(200);
452           STBRMW(sc, PCIE_RGR1_SW_INIT_1, PCIE_RGR1_SW_INIT_1_INIT, 0);
453 
454           /* Clear IDDQ */
455           STBRMW(sc, PCIE_MISC_HARD_PCIE_HARD_DEBUG,
456               PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ, 0);
457           w = STBREAD(sc, PCIE_MISC_HARD_PCIE_HARD_DEBUG);
458 
459           delay(100);
460 
461           w = STBREAD(sc, PCIE_MISC_REVISION);
462           printf("RootBridge Revision %x\n",
463               (u_int)__SHIFTOUT(w, PCIE_MISC_REVISION_MAJMIN));
464 
465           STBRMW(sc, PCIE_MISC_MISC_CTRL,
466               PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE, /* 128B */
467               PCIE_MISC_MISC_CTRL_SCB_ACCESS_EN
468               | PCIE_MISC_MISC_CTRL_CFG_READ_UR_MODE);
469 
470           /*
471            * XXX Inbound window for RPI4 is 3GB, should be parsed
472            * from dma-ranges attribute
473            */
474           ad = 0;
475           sz = bcmstb_encode_size(32);
476 
477           w = (__SHIFTIN(ad, PCIE_MISC_RC_BARx_CONFIG_LO_MATCH_ADDRESS)
478                & PCIE_MISC_RC_BARx_CONFIG_LO_MATCH_ADDRESS)
479               | __SHIFTIN(sz, PCIE_MISC_RC_BARx_CONFIG_LO_SIZE);
480           STBWRITE(sc, PCIE_MISC_RC_BAR2_CONFIG_LO, w);
481           STBWRITE(sc, PCIE_MISC_RC_BAR2_CONFIG_HI, ad >> 32);
482 
483           STBRMW(sc, PCIE_MISC_MISC_CTRL,
484               PCIE_MISC_MISC_CTRL_SCB0_SIZE,
485               __SHIFTIN(sz, PCIE_MISC_MISC_CTRL_SCB0_SIZE));
486 
487           /* disable PCIe->GISB window */
488           STBWRITE(sc, PCIE_MISC_RC_BAR1_CONFIG_LO, 0);
489           STBWRITE(sc, PCIE_MISC_RC_BAR1_CONFIG_HI, 0);
490           /* disable PCIe->SCB window */
491           STBWRITE(sc, PCIE_MISC_RC_BAR3_CONFIG_LO, 0);
492           STBWRITE(sc, PCIE_MISC_RC_BAR3_CONFIG_HI, 0);
493 
494           for (i=0; i<bs->nranges; ++i) {
495                     bcmstb_setwin(sc, i,
496                         bs->ranges[i].bpci,
497                         bs->ranges[i].bbus,
498                         bs->ranges[i].size);
499           }
500 
501           STBWRITE(sc, PCIE_INTR2_MASK_CLR, ~0);
502           STBWRITE(sc, PCIE_INTR2_MASK_SET, ~0);
503 
504           /* Release PERST */
505           STBRMW(sc, PCIE_RGR1_SW_INIT_1, PCIE_RGR1_SW_INIT_1_PERST, 0);
506 
507           t = 100;
508           m = PCIE_MISC_PCIE_STATUS_PCIE_PHYLINKUP
509             | PCIE_MISC_PCIE_STATUS_PCIE_DL_ACTIVE;
510           do {
511                     w = STBREAD(sc, PCIE_MISC_PCIE_STATUS);
512                     delay(1000);
513                     --t;
514           } while ((w & m) != m && t > 0);
515           if ((w & m) != m) {
516                     printf("PCIe link not ready\n");
517                     return 1;
518           }
519 
520           m = PCIE_MISC_PCIE_STATUS_PCIE_PORT;
521           if ((w & m) != m) {
522                     printf("PCIe link not in RC mode\n");
523                     return 1;
524           }
525 
526           /* advertise L0 and L1s capability */
527           STBRMW(sc, PCIE_RC_CFG_PRIV1_LINK_CAPABILITY,
528               PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_ASPM_SUPPORT,
529               __SHIFTIN(0x3, PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_ASPM_SUPPORT));
530 
531           /* present as PCIe->PCIe bridge */
532           STBRMW(sc, PCIE_RC_CFG_PRIV1_ID_VAL3,
533               PCIE_RC_CFG_PRIV1_ID_VAL3_CLASS_CODE,
534               __SHIFTIN(0x60400, PCIE_RC_CFG_PRIV1_ID_VAL3_CLASS_CODE));
535 
536           /* XXX enable SSC */
537 
538           /* clear endian mode == little endian */
539           STBRMW(sc, PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1,
540               PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1_ENDIAN_MODE_BAR2,
541               0);
542 
543           /* Gate clock with CLKREQ# */
544           STBRMW(sc, PCIE_MISC_HARD_PCIE_HARD_DEBUG,
545               0,
546               PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ);
547 
548           return 0;
549 }
550 
551 static void
bcmstb_attach_hook(device_t parent,device_t self,struct pcibus_attach_args * pba)552 bcmstb_attach_hook(device_t parent, device_t self,
553     struct pcibus_attach_args *pba)
554 {
555 }
556 
557 static int
bcmstb_bus_maxdevs(void * v,int bus)558 bcmstb_bus_maxdevs(void *v, int bus)
559 {
560           // struct bcmstb_softc *sc = v;
561 
562           return 1;
563 }
564 
565 static pcitag_t
bcmstb_make_tag(void * v,int bus,int device,int function)566 bcmstb_make_tag(void *v, int bus, int device, int function)
567 {
568           return (bus << 20) | (device << 15) | (function << 12);
569 }
570 
571 static void
bcmstb_decompose_tag(void * v,pcitag_t tag,int * bp,int * dp,int * fp)572 bcmstb_decompose_tag(void *v, pcitag_t tag, int *bp, int *dp, int *fp)
573 {
574           if (bp != NULL)
575                     *bp = (tag >> 20) & 0xff;
576           if (dp != NULL)
577                     *dp = (tag >> 15) & 0x1f;
578           if (fp != NULL)
579                     *fp = (tag >> 12) & 0x7;
580 }
581 
582 static u_int
bcmstb_get_segment(void * v)583 bcmstb_get_segment(void *v)
584 {
585           // struct bcmstb_softc *sc = v;
586 
587           return 1;
588 }
589 
590 static pcireg_t
bcmstb_conf_read(void * v,pcitag_t tag,int offset)591 bcmstb_conf_read(void *v, pcitag_t tag, int offset)
592 {
593           struct bcmstb_softc *sc = v;
594           int bus, dev, fn;
595           uint32_t idx, reg;
596           pcireg_t data;
597 
598           if (offset < 0 || offset > 4092)
599                     return (pcireg_t) -1;
600 
601           bcmstb_decompose_tag(v, tag, &bus, &dev, &fn);
602 
603           if (bus < 2 && dev > 0)
604                     return (pcireg_t) -1;
605 
606           idx = __SHIFTIN(bus, PCIE_EXT_CFG_INDEX_BUSNUM)
607               | __SHIFTIN(dev, PCIE_EXT_CFG_INDEX_SLOT)
608               | __SHIFTIN(fn, PCIE_EXT_CFG_INDEX_FUNC);
609 
610           reg = bus > 0 ? PCIE_EXT_CFG_DATA + offset : offset;
611 
612           mutex_enter(&sc->sc_lock);
613           STBWRITE(sc, PCIE_EXT_CFG_INDEX, idx);
614           data = STBREAD(sc, reg);
615           mutex_exit(&sc->sc_lock);
616 
617           return data;
618 }
619 
620 static void
bcmstb_conf_write(void * v,pcitag_t tag,int offset,pcireg_t data)621 bcmstb_conf_write(void *v, pcitag_t tag, int offset, pcireg_t data)
622 {
623           struct bcmstb_softc *sc = v;
624           int bus, dev, fn;
625           uint32_t idx, reg;
626 
627           if (offset < 0 || offset > 4092)
628                     return;
629 
630           bcmstb_decompose_tag(v, tag, &bus, &dev, &fn);
631 
632           if (bus < 2 && dev > 0)
633                     return;
634 
635           idx = __SHIFTIN(bus, PCIE_EXT_CFG_INDEX_BUSNUM)
636               | __SHIFTIN(dev, PCIE_EXT_CFG_INDEX_SLOT)
637               | __SHIFTIN(fn, PCIE_EXT_CFG_INDEX_FUNC);
638 
639           reg = bus > 0 ? PCIE_EXT_CFG_DATA + offset : offset;
640 
641           mutex_enter(&sc->sc_lock);
642           STBWRITE(sc, PCIE_EXT_CFG_INDEX, idx);
643           STBWRITE(sc, reg, data);
644           mutex_exit(&sc->sc_lock);
645 }
646 
647 static int
bcmstb_conf_hook(void * v,int bus,int dev,int fn,pcireg_t id)648 bcmstb_conf_hook(void *v, int bus, int dev, int fn, pcireg_t id)
649 {
650           /*
651            * Newer RPi4 lacks the VL805 EEPROM, so the
652            * firmware needs to be loaded after a reset.
653            * Trigger the GPU to do this.
654            */
655 
656           if (bus == 1 && dev == 0 && fn == 0 &&
657               PCI_VENDOR(id) == PCI_VENDOR_VIATECH &&
658               PCI_PRODUCT(id) == PCI_PRODUCT_VIATECH_VL805_XHCI) {
659 
660                     uint32_t idx;
661                     idx = __SHIFTIN(bus, PCIE_EXT_CFG_INDEX_BUSNUM)
662                         | __SHIFTIN(dev, PCIE_EXT_CFG_INDEX_SLOT)
663                         | __SHIFTIN(fn, PCIE_EXT_CFG_INDEX_FUNC);
664 
665                     rpi_notify_xhci_reset(idx);
666           }
667 
668           return PCI_CONF_DEFAULT;
669 }
670 
671 static void
bcmstb_conf_interrupt(void * v,int bus,int dev,int ipin,int swiz,int * ilinep)672 bcmstb_conf_interrupt(void *v, int bus, int dev, int ipin, int swiz, int *ilinep)
673 {
674 }
675 
676 static int
bcmstb_intr_map(const struct pci_attach_args * pa,pci_intr_handle_t * ih)677 bcmstb_intr_map(const struct pci_attach_args *pa, pci_intr_handle_t *ih)
678 {
679           struct bcmstb_softc *sc = pa->pa_pc->pc_intr_v;
680           u_int addr_cells, interrupt_cells;
681           const u_int *imap, *imask;
682           int imaplen, imasklen;
683           u_int match[4];
684           int index, off;
685 
686           if (pa->pa_intrpin == 0)
687                     return EINVAL;
688 
689           imap = fdtbus_get_prop(sc->sc_phandle, "interrupt-map", &imaplen);
690           imask = fdtbus_get_prop(sc->sc_phandle, "interrupt-map-mask",
691               &imasklen);
692           if (imap == NULL || imask == NULL || imasklen != 16)
693                     return EINVAL;
694 
695           off = CFG_OFFSET(pa->pa_bus, pa->pa_device, pa->pa_function, 0);
696 
697           /* Convert attach args to specifier */
698           match[0] = htobe32(off) & imask[0];
699           match[1] = htobe32(0) & imask[1];
700           match[2] = htobe32(0) & imask[2];
701           match[3] = htobe32(pa->pa_intrpin) & imask[3];
702 
703           index = 0;
704           while (imaplen >= 20) {
705                     const int map_ihandle = fdtbus_get_phandle_from_native(be32toh(imap[4]));
706                     if (of_getprop_uint32(map_ihandle, "#address-cells", &addr_cells))
707                               addr_cells = 2;
708                     if (of_getprop_uint32(map_ihandle, "#interrupt-cells", &interrupt_cells))
709                               interrupt_cells = 0;
710                     if (imaplen < (addr_cells + interrupt_cells) * 4)
711                               return ENXIO;
712 
713                     if ((imap[0] & imask[0]) == match[0] &&
714                         (imap[1] & imask[1]) == match[1] &&
715                         (imap[2] & imask[2]) == match[2] &&
716                         (imap[3] & imask[3]) == match[3]) {
717                               *ih = index;
718                               return 0;
719                     }
720 
721                     imap += (5 + addr_cells + interrupt_cells);
722                     imaplen -= (5 + addr_cells + interrupt_cells) * 4;
723                     index++;
724           }
725 
726           return EINVAL;
727 }
728 
729 static const u_int *
bcmstb_find_intr(struct bcmstb_softc * sc,pci_intr_handle_t ih,int * pihandle)730 bcmstb_find_intr(struct bcmstb_softc *sc, pci_intr_handle_t ih, int *pihandle)
731 {
732           u_int addr_cells, int_cells;
733           u_int iaddr_cells, iint_cells;
734           int imaplen, index;
735           const u_int *imap;
736           int intc;
737 
738           imap = fdtbus_get_prop(sc->sc_phandle, "interrupt-map", &imaplen);
739           if (imap == NULL)
740                     return NULL;
741           imaplen /= 4;
742 
743           if (of_getprop_uint32(sc->sc_phandle, "#address-cells", &addr_cells))
744                     return NULL;
745 
746           if (of_getprop_uint32(sc->sc_phandle, "#interrupt-cells", &int_cells))
747                     return NULL;
748 
749           index = 0;
750           while (imaplen >= int_cells + addr_cells + 1) {
751 
752                     intc = fdtbus_get_phandle_from_native(be32toh(imap[int_cells + addr_cells]));
753                     if (of_getprop_uint32(intc, "#interrupt-cells", &iint_cells))
754                               break;
755 
756                     if (of_getprop_uint32(intc, "#address-cells", &iaddr_cells))
757                               iaddr_cells = 0;
758 
759                     imap += addr_cells + int_cells + 1;
760                     imaplen -= addr_cells + int_cells + 1;
761 
762                     if (imaplen < iint_cells + iaddr_cells)
763                               break;
764 
765                     /* XXX, should really match child */
766                     if (index == ih) {
767                               *pihandle = intc;
768                               return imap;
769                     }
770 
771                     imap += iaddr_cells + iint_cells;
772                     imaplen -= iaddr_cells + iint_cells;
773                     index++;
774           }
775 
776           return NULL;
777 }
778 
779 static const char *
bcmstb_intr_string(void * v,pci_intr_handle_t ih,char * buf,size_t len)780 bcmstb_intr_string(void *v, pci_intr_handle_t ih, char *buf, size_t len)
781 {
782           struct bcmstb_softc *sc = v;
783           const int irq = __SHIFTOUT(ih, ARM_PCI_INTR_IRQ);
784           const int vec = __SHIFTOUT(ih, ARM_PCI_INTR_MSI_VEC);
785           const u_int *specifier;
786           int ihandle;
787 
788           if (ih & ARM_PCI_INTR_MSIX) {
789                     snprintf(buf, len, "irq %d (MSI-X vec %d)", irq, vec);
790           } else if (ih & ARM_PCI_INTR_MSI) {
791                     snprintf(buf, len, "irq %d (MSI vec %d)", irq, vec);
792           } else {
793                     specifier = bcmstb_find_intr(sc, ih & ARM_PCI_INTR_IRQ, &ihandle);
794                     if (specifier == NULL)
795                               return NULL;
796                     if (!fdtbus_intr_str_raw(ihandle, specifier, buf, len))
797                               return NULL;
798           }
799 
800           return buf;
801 }
802 
803 static const struct evcnt *
bcmstb_intr_evcnt(void * v,pci_intr_handle_t ih)804 bcmstb_intr_evcnt(void *v, pci_intr_handle_t ih)
805 {
806           return NULL;
807 }
808 
809 static int
bcmstb_intr_setattr(void * v,pci_intr_handle_t * ih,int attr,uint64_t data)810 bcmstb_intr_setattr(void *v, pci_intr_handle_t *ih, int attr, uint64_t data)
811 {
812           switch (attr) {
813           default:
814                     return ENODEV;
815           }
816 }
817 
818 static void *
bcmstb_intr_establish(void * v,pci_intr_handle_t ih,int ipl,int (* callback)(void *),void * arg,const char * xname)819 bcmstb_intr_establish(void *v, pci_intr_handle_t ih, int ipl,
820     int (*callback)(void *), void *arg, const char *xname)
821 {
822           struct bcmstb_softc *sc = v;
823           const int flags = (ih & ARM_PCI_INTR_MPSAFE) ? FDT_INTR_MPSAFE : 0;
824           const u_int *specifier;
825           int ihandle;
826 
827           if ((ih & (ARM_PCI_INTR_MSI | ARM_PCI_INTR_MSIX)) != 0) {
828 //                  return arm_pci_msi_intr_establish(&sc->sc_pc, ih, ipl,
829 //                                                            callback, arg, xname);
830                     return NULL;
831           }
832 
833           /* should search for PCI device */
834           specifier = bcmstb_find_intr(sc, ih & ARM_PCI_INTR_IRQ, &ihandle);
835           if (specifier == NULL)
836                     return NULL;
837 
838           return fdtbus_intr_establish_raw(ihandle, specifier, ipl, flags,
839                                                    callback, arg, xname);
840 }
841 
842 static void
bcmstb_intr_disestablish(void * v,void * vih)843 bcmstb_intr_disestablish(void *v, void *vih)
844 {
845           struct bcmstb_softc *sc = v;
846 
847           fdtbus_intr_disestablish(sc->sc_phandle, vih);
848 }
849 
850 static int
bcmstb_bus_space_map(void * t,bus_addr_t bpa,bus_size_t size,int flag,bus_space_handle_t * bshp)851 bcmstb_bus_space_map(void *t, bus_addr_t bpa, bus_size_t size, int flag,
852     bus_space_handle_t *bshp)
853 {
854           struct bcmstb_busspace * const bs = t;
855 
856 //        if ((bs->flags & PCI_FLAGS_IO_OKAY) != 0) {
857                     /* Force strongly ordered mapping for all I/O space */
858                     flag = BUS_SPACE_MAP_NONPOSTED;
859 //        }
860 
861           for (size_t i = 0; i < bs->nranges; i++) {
862                     const bus_addr_t rmin = bs->ranges[i].bpci;
863                     const bus_addr_t rmax = bs->ranges[i].bpci - 1 + bs->ranges[i].size;
864                     if ((bpa >= rmin) && ((bpa - 1 + size) <= rmax)) {
865                               const bus_addr_t pa = bs->ranges[i].bbus + (bpa - rmin);
866 
867                               return bs->map(t, pa, size, flag, bshp);
868                     }
869           }
870 
871           return ERANGE;
872 }
873