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