xref: /openbsd-src/sys/arch/arm64/dev/aplpcie.c (revision 56d02c00c34befa82f36a0070f336a6b39010607)
1*56d02c00Skettenis /*	$OpenBSD: aplpcie.c,v 1.19 2024/02/03 10:37:25 kettenis Exp $	*/
2ac95a80cSkettenis /*
3ac95a80cSkettenis  * Copyright (c) 2021 Mark Kettenis <kettenis@openbsd.org>
4ac95a80cSkettenis  *
5ac95a80cSkettenis  * Permission to use, copy, modify, and distribute this software for any
6ac95a80cSkettenis  * purpose with or without fee is hereby granted, provided that the above
7ac95a80cSkettenis  * copyright notice and this permission notice appear in all copies.
8ac95a80cSkettenis  *
9ac95a80cSkettenis  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10ac95a80cSkettenis  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11ac95a80cSkettenis  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12ac95a80cSkettenis  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13ac95a80cSkettenis  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14ac95a80cSkettenis  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15ac95a80cSkettenis  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16ac95a80cSkettenis  */
17ac95a80cSkettenis 
18ac95a80cSkettenis #include <sys/param.h>
19ac95a80cSkettenis #include <sys/systm.h>
20ac95a80cSkettenis #include <sys/device.h>
21ac95a80cSkettenis #include <sys/extent.h>
22ac95a80cSkettenis #include <sys/malloc.h>
23ac95a80cSkettenis 
24ac95a80cSkettenis #include <machine/intr.h>
25ac95a80cSkettenis #include <machine/bus.h>
26ac95a80cSkettenis #include <machine/fdt.h>
27ac95a80cSkettenis 
28ac95a80cSkettenis #include <dev/pci/pcidevs.h>
29ac95a80cSkettenis #include <dev/pci/pcireg.h>
30ac95a80cSkettenis #include <dev/pci/pcivar.h>
31ac95a80cSkettenis 
32ac95a80cSkettenis #include <dev/ofw/openfirm.h>
3386f87525Skettenis #include <dev/ofw/ofw_gpio.h>
34ac95a80cSkettenis #include <dev/ofw/ofw_misc.h>
35036514a8Skettenis #include <dev/ofw/ofw_pinctrl.h>
369a869755Skettenis #include <dev/ofw/ofw_power.h>
37ac95a80cSkettenis #include <dev/ofw/fdt.h>
38ac95a80cSkettenis 
392a3a2a65Skettenis #define PCIE_RC_PHY_BASE(port)		(0x84000 + (port) * 0x4000)
402a3a2a65Skettenis #define PCIE_RC_PHY_SIZE		0x4000
412a3a2a65Skettenis 
422a3a2a65Skettenis #define PCIE_PHY_LANE_CONF		0x0000
432a3a2a65Skettenis #define  PCIE_PHY_LANE_CONF_REFCLK0REQ	(1 << 0)
442a3a2a65Skettenis #define  PCIE_PHY_LANE_CONF_REFCLK1REQ	(1 << 1)
452a3a2a65Skettenis #define  PCIE_PHY_LANE_CONF_REFCLK0ACK	(1 << 2)
462a3a2a65Skettenis #define  PCIE_PHY_LANE_CONF_REFCLK1ACK	(1 << 3)
472a3a2a65Skettenis #define  PCIE_PHY_LANE_CONF_REFCLK0EN	(1 << 9)
482a3a2a65Skettenis #define  PCIE_PHY_LANE_CONF_REFCLK1EN	(1 << 10)
492a3a2a65Skettenis #define  PCIE_PHY_LANE_CONF_REFCLK0CGEN	(1 << 30)
502a3a2a65Skettenis #define  PCIE_PHY_LANE_CONF_REFCLK1CGEN	(1U << 31)
512a3a2a65Skettenis #define PCIE_PHY_LANE_CTRL		0x0004
522a3a2a65Skettenis #define  PCIE_PHY_LANE_CTRL_CFGACC	(1 << 15)
53ac95a80cSkettenis 
5486f87525Skettenis #define PCIE_PORT_LTSSM_CTRL		0x0080
5586f87525Skettenis #define  PCIE_PORT_LTSSM_CTRL_START	(1 << 0)
5686f87525Skettenis #define PCIE_PORT_MSI_CTRL		0x0124
5786f87525Skettenis #define  PCIE_PORT_MSI_CTRL_ENABLE	(1 << 0)
5886f87525Skettenis #define  PCIE_PORT_MSI_CTRL_32		(5 << 4)
5986f87525Skettenis #define PCIE_PORT_MSI_REMAP		0x0128
6086f87525Skettenis #define PCIE_PORT_MSI_DOORBELL		0x0168
6186f87525Skettenis #define PCIE_PORT_LINK_STAT		0x0208
6286f87525Skettenis #define  PCIE_PORT_LINK_STAT_UP		(1 << 0)
6386f87525Skettenis #define PCIE_PORT_APPCLK		0x0800
6486f87525Skettenis #define  PCIE_PORT_APPCLK_EN		(1 << 0)
6586f87525Skettenis #define  PCIE_PORT_APPCLK_CGDIS		(1 << 8)
6686f87525Skettenis #define PCIE_PORT_STAT			0x0804
6786f87525Skettenis #define  PCIE_PORT_STAT_READY		(1 << 0)
6886f87525Skettenis #define PCIE_PORT_REFCLK		0x0810
6986f87525Skettenis #define  PCIE_PORT_REFCLK_EN		(1 << 0)
7086f87525Skettenis #define  PCIE_PORT_REFCLK_CGDIS		(1 << 8)
7186f87525Skettenis #define PCIE_PORT_PERST			0x0814
7286f87525Skettenis #define  PCIE_PORT_PERST_DIS		(1 << 0)
73ce211e92Skettenis #define PCIE_PORT_RID2SID(idx)		(0x0828 + (idx) * 4)
74ce211e92Skettenis #define  PCIE_PORT_RID2SID_VALID	(1U << 31)
75ce211e92Skettenis #define  PCIE_PORT_RID2SID_SID_SHIFT	16
76ce211e92Skettenis #define  PCIE_PORT_RID2SID_RID_MASK	0x0000ffff
770d546792Skettenis #define  PCIE_PORT_MAX_RID2SID		64
78ac95a80cSkettenis 
792a3a2a65Skettenis #define PCIE_T6020_PORT_MSI_DOORBELL_LO	0x016c
802a3a2a65Skettenis #define PCIE_T6020_PORT_MSI_DOORBELL_HI	0x0170
812a3a2a65Skettenis #define PCIE_T6020_PORT_PERST		0x082c
820d546792Skettenis #define PCIE_T6020_PORT_RID2SID(idx)	(0x3000 + (idx) * 4)
830d546792Skettenis #define  PCIE_T6020_PORT_MAX_RID2SID	512
842a3a2a65Skettenis #define PCIE_T6020_PORT_MSI_MAP(idx)	(0x3800 + (idx) * 4)
852a3a2a65Skettenis #define  PCIE_T6020_PORT_MSI_MAP_ENABLE	(1U << 31)
862a3a2a65Skettenis 
87ac95a80cSkettenis #define HREAD4(sc, reg)							\
88ac95a80cSkettenis     (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
89ac95a80cSkettenis #define HWRITE4(sc, reg, val)						\
90ac95a80cSkettenis     bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
91ac95a80cSkettenis 
9286f87525Skettenis #define RREAD4(sc, reg)						\
9386f87525Skettenis     (bus_space_read_4((sc)->sc_iot, (sc)->sc_rc_ioh, (reg)))
9486f87525Skettenis #define RWRITE4(sc, reg, val)					\
9586f87525Skettenis     bus_space_write_4((sc)->sc_iot, (sc)->sc_rc_ioh, (reg), (val))
9686f87525Skettenis #define RSET4(sc, reg, bits)				\
9786f87525Skettenis     RWRITE4((sc), (reg), RREAD4((sc), (reg)) | (bits))
9886f87525Skettenis #define RCLR4(sc, reg, bits)				\
9986f87525Skettenis     RWRITE4((sc), (reg), RREAD4((sc), (reg)) & ~(bits))
10086f87525Skettenis 
1012a3a2a65Skettenis #define LREAD4(sc, port, reg)					\
1022a3a2a65Skettenis     (bus_space_read_4((sc)->sc_iot, (sc)->sc_phy_ioh[port], (reg)))
1032a3a2a65Skettenis #define LWRITE4(sc, port, reg, val)				\
1042a3a2a65Skettenis     bus_space_write_4((sc)->sc_iot, (sc)->sc_phy_ioh[port], (reg), (val))
1052a3a2a65Skettenis #define LSET4(sc, port, reg, bits)			\
1062a3a2a65Skettenis     LWRITE4((sc), (port), (reg), LREAD4((sc), (port), (reg)) | (bits))
1072a3a2a65Skettenis #define LCLR4(sc, port, reg, bits)			\
1082a3a2a65Skettenis     LWRITE4((sc), (port), (reg), LREAD4((sc), (port), (reg)) & ~(bits))
1092a3a2a65Skettenis 
11086f87525Skettenis #define PREAD4(sc, port, reg)						\
11186f87525Skettenis     (bus_space_read_4((sc)->sc_iot, (sc)->sc_port_ioh[(port)], (reg)))
11286f87525Skettenis #define PWRITE4(sc, port, reg, val)					\
11386f87525Skettenis     bus_space_write_4((sc)->sc_iot, (sc)->sc_port_ioh[(port)], (reg), (val))
11486f87525Skettenis #define PSET4(sc, port, reg, bits)				\
11586f87525Skettenis     PWRITE4((sc), (port), (reg), PREAD4((sc), (port), (reg)) | (bits))
11686f87525Skettenis #define PCLR4(sc, port, reg, bits)				\
11786f87525Skettenis     PWRITE4((sc), (port), (reg), PREAD4((sc), (port), (reg)) & ~(bits))
11886f87525Skettenis 
119ac95a80cSkettenis struct aplpcie_range {
120ac95a80cSkettenis 	uint32_t		flags;
121ac95a80cSkettenis 	uint64_t		pci_base;
122ac95a80cSkettenis 	uint64_t		phys_base;
123ac95a80cSkettenis 	uint64_t		size;
124ac95a80cSkettenis };
125ac95a80cSkettenis 
12686f87525Skettenis #define APLPCIE_MAX_PORTS	4
12786f87525Skettenis 
128ac95a80cSkettenis struct aplpcie_softc {
129ac95a80cSkettenis 	struct device		sc_dev;
130ac95a80cSkettenis 	bus_space_tag_t		sc_iot;
131ac95a80cSkettenis 	bus_space_handle_t	sc_ioh;
13286f87525Skettenis 	bus_space_handle_t	sc_rc_ioh;
1332a3a2a65Skettenis 	bus_space_handle_t	sc_phy_ioh[APLPCIE_MAX_PORTS];
1342a3a2a65Skettenis 	bus_size_t		sc_phy_ios[APLPCIE_MAX_PORTS];
13586f87525Skettenis 	bus_space_handle_t	sc_port_ioh[APLPCIE_MAX_PORTS];
13686f87525Skettenis 	bus_size_t		sc_port_ios[APLPCIE_MAX_PORTS];
137ac95a80cSkettenis 	bus_dma_tag_t		sc_dmat;
138ac95a80cSkettenis 
139ac95a80cSkettenis 	int			sc_node;
140ac95a80cSkettenis 	int			sc_acells;
141ac95a80cSkettenis 	int			sc_scells;
142ac95a80cSkettenis 	int			sc_pacells;
143ac95a80cSkettenis 	int			sc_pscells;
144ac95a80cSkettenis 	struct aplpcie_range	*sc_ranges;
145ac95a80cSkettenis 	int			sc_nranges;
146ac95a80cSkettenis 
147ac95a80cSkettenis 	struct bus_space	sc_bus_iot;
148ac95a80cSkettenis 	struct bus_space	sc_bus_memt;
149ac95a80cSkettenis 
1502b0be198Skettenis 	struct machine_pci_chipset sc_pc;
151ac95a80cSkettenis 	struct extent		*sc_busex;
152ac95a80cSkettenis 	struct extent		*sc_memex;
153ac95a80cSkettenis 	struct extent		*sc_pmemex;
154ac95a80cSkettenis 	struct extent		*sc_ioex;
155ac95a80cSkettenis 	int			sc_bus;
156ac95a80cSkettenis 
157ac95a80cSkettenis 	int			sc_msi;
158ac95a80cSkettenis 	bus_addr_t		sc_msi_doorbell;
15996995178Skettenis 	uint32_t		sc_msi_range[6];
16096995178Skettenis 	int			sc_msi_rangelen;
1615641a7faSkettenis 	struct interrupt_controller sc_msi_ic;
162ac95a80cSkettenis };
163ac95a80cSkettenis 
164ac95a80cSkettenis int	aplpcie_match(struct device *, void *, void *);
165ac95a80cSkettenis void	aplpcie_attach(struct device *, struct device *, void *);
166ac95a80cSkettenis 
167471aeecfSnaddy const struct cfattach	aplpcie_ca = {
168ac95a80cSkettenis 	sizeof (struct aplpcie_softc), aplpcie_match, aplpcie_attach
169ac95a80cSkettenis };
170ac95a80cSkettenis 
171ac95a80cSkettenis struct cfdriver aplpcie_cd = {
172ac95a80cSkettenis 	NULL, "aplpcie", DV_DULL
173ac95a80cSkettenis };
174ac95a80cSkettenis 
175ac95a80cSkettenis int
aplpcie_match(struct device * parent,void * match,void * aux)176ac95a80cSkettenis aplpcie_match(struct device *parent, void *match, void *aux)
177ac95a80cSkettenis {
178ac95a80cSkettenis 	struct fdt_attach_args *faa = aux;
179ac95a80cSkettenis 
1802a3a2a65Skettenis 	return OF_is_compatible(faa->fa_node, "apple,pcie") ||
1812a3a2a65Skettenis 	    OF_is_compatible(faa->fa_node, "apple,t6020-pcie");
182ac95a80cSkettenis }
183ac95a80cSkettenis 
18486f87525Skettenis void	aplpcie_init_port(struct aplpcie_softc *, int);
1852a3a2a65Skettenis void	aplpcie_t6020_init_port(struct aplpcie_softc *, int);
18686f87525Skettenis 
187ac95a80cSkettenis void	aplpcie_attach_hook(struct device *, struct device *,
188ac95a80cSkettenis 	    struct pcibus_attach_args *);
189ac95a80cSkettenis int	aplpcie_bus_maxdevs(void *, int);
190ac95a80cSkettenis pcitag_t aplpcie_make_tag(void *, int, int, int);
191ac95a80cSkettenis void	aplpcie_decompose_tag(void *, pcitag_t, int *, int *, int *);
192ac95a80cSkettenis int	aplpcie_conf_size(void *, pcitag_t);
193ac95a80cSkettenis pcireg_t aplpcie_conf_read(void *, pcitag_t, int);
194ac95a80cSkettenis void	aplpcie_conf_write(void *, pcitag_t, int, pcireg_t);
195ac95a80cSkettenis int	aplpcie_probe_device_hook(void *, struct pci_attach_args *);
196ac95a80cSkettenis 
197ac95a80cSkettenis int	aplpcie_intr_map(struct pci_attach_args *, pci_intr_handle_t *);
198ac95a80cSkettenis const char *aplpcie_intr_string(void *, pci_intr_handle_t);
199ac95a80cSkettenis void	*aplpcie_intr_establish(void *, pci_intr_handle_t, int,
200ac95a80cSkettenis 	    struct cpu_info *, int (*)(void *), void *, char *);
201ac95a80cSkettenis void	aplpcie_intr_disestablish(void *, void *);
202ac95a80cSkettenis 
203ac95a80cSkettenis int	aplpcie_bs_iomap(bus_space_tag_t, bus_addr_t, bus_size_t, int,
204ac95a80cSkettenis 	    bus_space_handle_t *);
205ac95a80cSkettenis int	aplpcie_bs_memmap(bus_space_tag_t, bus_addr_t, bus_size_t, int,
206ac95a80cSkettenis 	    bus_space_handle_t *);
207ac95a80cSkettenis 
2085641a7faSkettenis void	*aplpcie_intr_establish_msi(void *, uint64_t *, uint64_t *,
2095641a7faSkettenis 	    int, struct cpu_info *, int (*)(void *), void *, char *);
2105641a7faSkettenis void	aplpcie_intr_disestablish_msi(void *);
2115641a7faSkettenis 
212ac95a80cSkettenis void
aplpcie_attach(struct device * parent,struct device * self,void * aux)213ac95a80cSkettenis aplpcie_attach(struct device *parent, struct device *self, void *aux)
214ac95a80cSkettenis {
215ac95a80cSkettenis 	struct aplpcie_softc *sc = (struct aplpcie_softc *)self;
216ac95a80cSkettenis 	struct fdt_attach_args *faa = aux;
217ac95a80cSkettenis 	struct pcibus_attach_args pba;
218ac95a80cSkettenis 	uint32_t *ranges;
219ac95a80cSkettenis 	int i, j, nranges, rangeslen;
220ac95a80cSkettenis 	uint32_t bus_range[2];
2215641a7faSkettenis 	char name[32];
22286f87525Skettenis 	int idx, node, port;
223ac95a80cSkettenis 
224ac95a80cSkettenis 	sc->sc_iot = faa->fa_iot;
2255641a7faSkettenis 
2265641a7faSkettenis 	idx = OF_getindex(faa->fa_node, "config", "reg-names");
2275641a7faSkettenis 	if (idx < 0 || idx >= faa->fa_nreg ||
22855406a37Skettenis 	    bus_space_map(sc->sc_iot, faa->fa_reg[idx].addr,
22955406a37Skettenis 	    faa->fa_reg[idx].size, 0, &sc->sc_ioh)) {
230ac95a80cSkettenis 		printf(": can't map registers\n");
231ac95a80cSkettenis 		return;
232ac95a80cSkettenis 	}
233ac95a80cSkettenis 
23486f87525Skettenis 	idx = OF_getindex(faa->fa_node, "rc", "reg-names");
23586f87525Skettenis 	if (idx < 0 || idx >= faa->fa_nreg ||
2365641a7faSkettenis 	    bus_space_map(sc->sc_iot, faa->fa_reg[idx].addr,
23786f87525Skettenis 	    faa->fa_reg[idx].size, 0, &sc->sc_rc_ioh)) {
238ac95a80cSkettenis 		printf(": can't map registers\n");
239ac95a80cSkettenis 		return;
240ac95a80cSkettenis 	}
24186f87525Skettenis 
24286f87525Skettenis 	for (port = 0; port < APLPCIE_MAX_PORTS; port++) {
24386f87525Skettenis 		snprintf(name, sizeof(name), "port%d", port);
24486f87525Skettenis 		idx = OF_getindex(faa->fa_node, name, "reg-names");
24586f87525Skettenis 		if (idx < 0)
24686f87525Skettenis 			continue;
24786f87525Skettenis 		if (idx > faa->fa_nreg ||
24886f87525Skettenis 		    bus_space_map(sc->sc_iot, faa->fa_reg[idx].addr,
24986f87525Skettenis 		    faa->fa_reg[idx].size, 0, &sc->sc_port_ioh[port])) {
25086f87525Skettenis 			printf(": can't map registers\n");
25186f87525Skettenis 			return;
25286f87525Skettenis 		}
25386f87525Skettenis 		sc->sc_port_ios[port] = faa->fa_reg[idx].size;
2542a3a2a65Skettenis 
2552a3a2a65Skettenis 		snprintf(name, sizeof(name), "phy%d", port);
2562a3a2a65Skettenis 		idx = OF_getindex(faa->fa_node, name, "reg-names");
2572a3a2a65Skettenis 		if (idx < 0) {
2582a3a2a65Skettenis 			bus_space_subregion(sc->sc_iot, sc->sc_rc_ioh,
2592a3a2a65Skettenis 			    PCIE_RC_PHY_BASE(port), PCIE_RC_PHY_SIZE,
2602a3a2a65Skettenis 			    &sc->sc_phy_ioh[port]);
2612a3a2a65Skettenis 			continue;
2622a3a2a65Skettenis 		}
2632a3a2a65Skettenis 		if (idx > faa->fa_nreg ||
2642a3a2a65Skettenis 		    bus_space_map(sc->sc_iot, faa->fa_reg[idx].addr,
2652a3a2a65Skettenis 		    faa->fa_reg[idx].size, 0, &sc->sc_phy_ioh[port])) {
2662a3a2a65Skettenis 			printf(": can't map registers\n");
2672a3a2a65Skettenis 			return;
2682a3a2a65Skettenis 		}
2692a3a2a65Skettenis 		sc->sc_phy_ios[port] = faa->fa_reg[idx].size;
270ac95a80cSkettenis 	}
271ac95a80cSkettenis 
272ac95a80cSkettenis 	sc->sc_dmat = faa->fa_dmat;
273ac95a80cSkettenis 	sc->sc_node = faa->fa_node;
274ac95a80cSkettenis 
2759a869755Skettenis 	power_domain_enable(sc->sc_node);
276036514a8Skettenis 	pinctrl_byname(sc->sc_node, "default");
277036514a8Skettenis 
278ac95a80cSkettenis 	sc->sc_msi_doorbell =
279ac95a80cSkettenis 	    OF_getpropint64(sc->sc_node, "msi-doorbell", 0xffff000ULL);
28096995178Skettenis 	sc->sc_msi_rangelen = OF_getpropintarray(sc->sc_node, "msi-ranges",
28196995178Skettenis 	    sc->sc_msi_range, sizeof(sc->sc_msi_range));
28296995178Skettenis 	if (sc->sc_msi_rangelen <= 0 ||
28396995178Skettenis 	    (sc->sc_msi_rangelen % sizeof(uint32_t)) ||
28496995178Skettenis 	    (sc->sc_msi_rangelen / sizeof(uint32_t)) < 5 ||
28596995178Skettenis 	    (sc->sc_msi_rangelen / sizeof(uint32_t) > 6)) {
2865641a7faSkettenis 		printf(": invalid msi-ranges property\n");
2875641a7faSkettenis 		return;
2885641a7faSkettenis 	}
289ac95a80cSkettenis 
2902a3a2a65Skettenis 	if (OF_is_compatible(sc->sc_node, "apple,t6020-pcie")) {
2912a3a2a65Skettenis 		for (node = OF_child(sc->sc_node); node; node = OF_peer(node))
2922a3a2a65Skettenis 			aplpcie_t6020_init_port(sc, node);
2932a3a2a65Skettenis 	} else {
29486f87525Skettenis 		for (node = OF_child(sc->sc_node); node; node = OF_peer(node))
29586f87525Skettenis 			aplpcie_init_port(sc, node);
2962a3a2a65Skettenis 	}
29786f87525Skettenis 
298ac95a80cSkettenis 	/*
29986f87525Skettenis 	 * Must wait at least 100ms after link training completes
30086f87525Skettenis 	 * before sending a configuration request to a device
30186f87525Skettenis 	 * immediately below a port.
302ac95a80cSkettenis 	 */
30386f87525Skettenis 	delay(100000);
304ac95a80cSkettenis 
305ac95a80cSkettenis 	sc->sc_acells = OF_getpropint(sc->sc_node, "#address-cells",
306ac95a80cSkettenis 	    faa->fa_acells);
307ac95a80cSkettenis 	sc->sc_scells = OF_getpropint(sc->sc_node, "#size-cells",
308ac95a80cSkettenis 	    faa->fa_scells);
309ac95a80cSkettenis 	sc->sc_pacells = faa->fa_acells;
310ac95a80cSkettenis 	sc->sc_pscells = faa->fa_scells;
311ac95a80cSkettenis 
312ac95a80cSkettenis 	rangeslen = OF_getproplen(sc->sc_node, "ranges");
313ac95a80cSkettenis 	if (rangeslen <= 0 || (rangeslen % sizeof(uint32_t)) ||
314ac95a80cSkettenis 	     (rangeslen / sizeof(uint32_t)) % (sc->sc_acells +
315ac95a80cSkettenis 	     sc->sc_pacells + sc->sc_scells)) {
316ac95a80cSkettenis 		printf(": invalid ranges property\n");
317ac95a80cSkettenis 		return;
318ac95a80cSkettenis 	}
319ac95a80cSkettenis 
320ac95a80cSkettenis 	ranges = malloc(rangeslen, M_TEMP, M_WAITOK);
321ac95a80cSkettenis 	OF_getpropintarray(sc->sc_node, "ranges", ranges,
322ac95a80cSkettenis 	    rangeslen);
323ac95a80cSkettenis 
324ac95a80cSkettenis 	nranges = (rangeslen / sizeof(uint32_t)) /
325ac95a80cSkettenis 	    (sc->sc_acells + sc->sc_pacells + sc->sc_scells);
326ac95a80cSkettenis 	sc->sc_ranges = mallocarray(nranges,
327ac95a80cSkettenis 	    sizeof(struct aplpcie_range), M_TEMP, M_WAITOK);
328ac95a80cSkettenis 	sc->sc_nranges = nranges;
329ac95a80cSkettenis 
330ac95a80cSkettenis 	for (i = 0, j = 0; i < sc->sc_nranges; i++) {
331ac95a80cSkettenis 		sc->sc_ranges[i].flags = ranges[j++];
332ac95a80cSkettenis 		sc->sc_ranges[i].pci_base = ranges[j++];
333ac95a80cSkettenis 		if (sc->sc_acells - 1 == 2) {
334ac95a80cSkettenis 			sc->sc_ranges[i].pci_base <<= 32;
335ac95a80cSkettenis 			sc->sc_ranges[i].pci_base |= ranges[j++];
336ac95a80cSkettenis 		}
337ac95a80cSkettenis 		sc->sc_ranges[i].phys_base = ranges[j++];
338ac95a80cSkettenis 		if (sc->sc_pacells == 2) {
339ac95a80cSkettenis 			sc->sc_ranges[i].phys_base <<= 32;
340ac95a80cSkettenis 			sc->sc_ranges[i].phys_base |= ranges[j++];
341ac95a80cSkettenis 		}
342ac95a80cSkettenis 		sc->sc_ranges[i].size = ranges[j++];
343ac95a80cSkettenis 		if (sc->sc_scells == 2) {
344ac95a80cSkettenis 			sc->sc_ranges[i].size <<= 32;
345ac95a80cSkettenis 			sc->sc_ranges[i].size |= ranges[j++];
346ac95a80cSkettenis 		}
347ac95a80cSkettenis 	}
348ac95a80cSkettenis 
349ac95a80cSkettenis 	free(ranges, M_TEMP, rangeslen);
350ac95a80cSkettenis 
3515641a7faSkettenis 	printf("\n");
3525641a7faSkettenis 
353ac95a80cSkettenis 	/* Create extents for our address spaces. */
354ac95a80cSkettenis 	sc->sc_busex = extent_create("pcibus", 0, 255,
355ac95a80cSkettenis 	    M_DEVBUF, NULL, 0, EX_WAITOK | EX_FILLED);
356ac95a80cSkettenis 	sc->sc_memex = extent_create("pcimem", 0, (u_long)-1,
357ac95a80cSkettenis 	    M_DEVBUF, NULL, 0, EX_WAITOK | EX_FILLED);
358ac95a80cSkettenis 	sc->sc_pmemex = extent_create("pcipmem", 0, (u_long)-1,
359ac95a80cSkettenis 	    M_DEVBUF, NULL, 0, EX_WAITOK | EX_FILLED);
360ac95a80cSkettenis 	sc->sc_ioex = extent_create("pciio", 0, 0xffffffff,
361ac95a80cSkettenis 	    M_DEVBUF, NULL, 0, EX_WAITOK | EX_FILLED);
362ac95a80cSkettenis 	for (i = 0; i < sc->sc_nranges; i++) {
363ac95a80cSkettenis 		if ((sc->sc_ranges[i].flags & 0x03000000) == 0x01000000) {
364ac95a80cSkettenis 			extent_free(sc->sc_ioex, sc->sc_ranges[i].pci_base,
365ac95a80cSkettenis 			    sc->sc_ranges[i].size, EX_WAITOK);
366ac95a80cSkettenis 		}
367ac95a80cSkettenis 		if ((sc->sc_ranges[i].flags & 0x03000000) == 0x02000000) {
368ac95a80cSkettenis 			extent_free(sc->sc_memex, sc->sc_ranges[i].pci_base,
369ac95a80cSkettenis 			    sc->sc_ranges[i].size, EX_WAITOK);
370ac95a80cSkettenis 		}
371ac95a80cSkettenis 		if ((sc->sc_ranges[i].flags & 0x03000000) == 0x03000000) {
372ac95a80cSkettenis 			extent_free(sc->sc_pmemex, sc->sc_ranges[i].pci_base,
373ac95a80cSkettenis 			    sc->sc_ranges[i].size, EX_WAITOK);
374ac95a80cSkettenis 		}
375ac95a80cSkettenis 	}
376ac95a80cSkettenis 
377ac95a80cSkettenis 	/* Set up bus range. */
378ac95a80cSkettenis 	if (OF_getpropintarray(sc->sc_node, "bus-range", bus_range,
379ac95a80cSkettenis 	    sizeof(bus_range)) != sizeof(bus_range) ||
380ac95a80cSkettenis 	    bus_range[0] >= 32 || bus_range[1] >= 32) {
381ac95a80cSkettenis 		bus_range[0] = 0;
382ac95a80cSkettenis 		bus_range[1] = 31;
383ac95a80cSkettenis 	}
384ac95a80cSkettenis 	sc->sc_bus = bus_range[0];
385ac95a80cSkettenis 	extent_free(sc->sc_busex, bus_range[0],
386ac95a80cSkettenis 	    bus_range[1] - bus_range[0] + 1, EX_WAITOK);
387ac95a80cSkettenis 
388ac95a80cSkettenis 	memcpy(&sc->sc_bus_iot, sc->sc_iot, sizeof(sc->sc_bus_iot));
389ac95a80cSkettenis 	sc->sc_bus_iot.bus_private = sc;
390ac95a80cSkettenis 	sc->sc_bus_iot._space_map = aplpcie_bs_iomap;
391ac95a80cSkettenis 	memcpy(&sc->sc_bus_memt, sc->sc_iot, sizeof(sc->sc_bus_memt));
392ac95a80cSkettenis 	sc->sc_bus_memt.bus_private = sc;
393ac95a80cSkettenis 	sc->sc_bus_memt._space_map = aplpcie_bs_memmap;
394ac95a80cSkettenis 
395ac95a80cSkettenis 	sc->sc_pc.pc_conf_v = sc;
396ac95a80cSkettenis 	sc->sc_pc.pc_attach_hook = aplpcie_attach_hook;
397ac95a80cSkettenis 	sc->sc_pc.pc_bus_maxdevs = aplpcie_bus_maxdevs;
398ac95a80cSkettenis 	sc->sc_pc.pc_make_tag = aplpcie_make_tag;
399ac95a80cSkettenis 	sc->sc_pc.pc_decompose_tag = aplpcie_decompose_tag;
400ac95a80cSkettenis 	sc->sc_pc.pc_conf_size = aplpcie_conf_size;
401ac95a80cSkettenis 	sc->sc_pc.pc_conf_read = aplpcie_conf_read;
402ac95a80cSkettenis 	sc->sc_pc.pc_conf_write = aplpcie_conf_write;
403ac95a80cSkettenis 	sc->sc_pc.pc_probe_device_hook = aplpcie_probe_device_hook;
404ac95a80cSkettenis 
405ac95a80cSkettenis 	sc->sc_pc.pc_intr_v = sc;
406ac95a80cSkettenis 	sc->sc_pc.pc_intr_map = aplpcie_intr_map;
407ac95a80cSkettenis 	sc->sc_pc.pc_intr_map_msi = _pci_intr_map_msi;
408*56d02c00Skettenis 	sc->sc_pc.pc_intr_map_msivec = _pci_intr_map_msivec;
409ac95a80cSkettenis 	sc->sc_pc.pc_intr_map_msix = _pci_intr_map_msix;
410ac95a80cSkettenis 	sc->sc_pc.pc_intr_string = aplpcie_intr_string;
411ac95a80cSkettenis 	sc->sc_pc.pc_intr_establish = aplpcie_intr_establish;
412ac95a80cSkettenis 	sc->sc_pc.pc_intr_disestablish = aplpcie_intr_disestablish;
413ac95a80cSkettenis 
414ac95a80cSkettenis 	memset(&pba, 0, sizeof(pba));
415ac95a80cSkettenis 	pba.pba_busname = "pci";
416ac95a80cSkettenis 	pba.pba_iot = &sc->sc_bus_iot;
417ac95a80cSkettenis 	pba.pba_memt = &sc->sc_bus_memt;
418ac95a80cSkettenis 	pba.pba_dmat = sc->sc_dmat;
419ac95a80cSkettenis 	pba.pba_pc = &sc->sc_pc;
420ac95a80cSkettenis 	pba.pba_busex = sc->sc_busex;
421ac95a80cSkettenis 	pba.pba_memex = sc->sc_memex;
422ac95a80cSkettenis 	pba.pba_pmemex = sc->sc_pmemex;
423ac95a80cSkettenis 	pba.pba_ioex = sc->sc_ioex;
424ac95a80cSkettenis 	pba.pba_domain = pci_ndomains++;
425ac95a80cSkettenis 	pba.pba_bus = sc->sc_bus;
426ac95a80cSkettenis 	pba.pba_flags |= PCI_FLAGS_MSI_ENABLED;
427ac95a80cSkettenis 
4285641a7faSkettenis 	sc->sc_msi_ic.ic_node = sc->sc_node;
4295641a7faSkettenis 	sc->sc_msi_ic.ic_cookie = sc;
4305641a7faSkettenis 	sc->sc_msi_ic.ic_establish_msi = aplpcie_intr_establish_msi;
4315641a7faSkettenis 	sc->sc_msi_ic.ic_disestablish = aplpcie_intr_disestablish_msi;
4325641a7faSkettenis 	sc->sc_msi_ic.ic_barrier = intr_barrier;
4335641a7faSkettenis 	fdt_intr_register(&sc->sc_msi_ic);
4345641a7faSkettenis 
43521e68981Skettenis 	pci_dopm = 1;
43621e68981Skettenis 
437ac95a80cSkettenis 	config_found(self, &pba, NULL);
438ac95a80cSkettenis }
439ac95a80cSkettenis 
440ac95a80cSkettenis void
aplpcie_init_port(struct aplpcie_softc * sc,int node)44186f87525Skettenis aplpcie_init_port(struct aplpcie_softc *sc, int node)
44286f87525Skettenis {
44378972d8eSkettenis 	char status[32];
44486f87525Skettenis 	uint32_t reg[5];
44589945389Skettenis 	uint32_t *pwren_gpio;
44686f87525Skettenis 	uint32_t *reset_gpio;
44789945389Skettenis 	int pwren_gpiolen, reset_gpiolen;
44886f87525Skettenis 	uint32_t stat;
449ce211e92Skettenis 	int idx, port, timo;
45086f87525Skettenis 
45178972d8eSkettenis 	if (OF_getprop(node, "status", status, sizeof(status)) > 0 &&
45278972d8eSkettenis 	    strcmp(status, "disabled") == 0)
45378972d8eSkettenis 		return;
45478972d8eSkettenis 
45586f87525Skettenis 	if (OF_getpropintarray(node, "reg", reg, sizeof(reg)) != sizeof(reg))
45686f87525Skettenis 		return;
45786f87525Skettenis 
45886f87525Skettenis 	port = reg[0] >> 11;
45986f87525Skettenis 	if (port >= APLPCIE_MAX_PORTS || sc->sc_port_ios[port] == 0)
46086f87525Skettenis 		return;
46186f87525Skettenis 
46289945389Skettenis 	pwren_gpiolen = OF_getproplen(node, "pwren-gpios");
46386f87525Skettenis 	reset_gpiolen = OF_getproplen(node, "reset-gpios");
46486f87525Skettenis 	if (reset_gpiolen <= 0)
46586f87525Skettenis 		return;
46686f87525Skettenis 
46786f87525Skettenis 	/*
46886f87525Skettenis 	 * Set things up such that we can share the 32 available MSIs
46986f87525Skettenis 	 * across all ports.
47086f87525Skettenis 	 */
47186f87525Skettenis 	PWRITE4(sc, port, PCIE_PORT_MSI_CTRL,
47286f87525Skettenis 	    PCIE_PORT_MSI_CTRL_32 | PCIE_PORT_MSI_CTRL_ENABLE);
47386f87525Skettenis 	PWRITE4(sc, port, PCIE_PORT_MSI_REMAP, 0);
47486f87525Skettenis 	PWRITE4(sc, port, PCIE_PORT_MSI_DOORBELL, sc->sc_msi_doorbell);
47586f87525Skettenis 
476ce211e92Skettenis 	/*
477ce211e92Skettenis 	 * Clear stream ID mappings.
478ce211e92Skettenis 	 */
4790d546792Skettenis 	for (idx = 0; idx < PCIE_PORT_MAX_RID2SID; idx++)
480ce211e92Skettenis 		PWRITE4(sc, port, PCIE_PORT_RID2SID(idx), 0);
481ce211e92Skettenis 
48286f87525Skettenis 	/* Check if the link is already up. */
48386f87525Skettenis 	stat = PREAD4(sc, port, PCIE_PORT_LINK_STAT);
48486f87525Skettenis 	if (stat & PCIE_PORT_LINK_STAT_UP)
48586f87525Skettenis 		return;
48686f87525Skettenis 
48786f87525Skettenis 	PSET4(sc, port, PCIE_PORT_APPCLK, PCIE_PORT_APPCLK_EN);
48886f87525Skettenis 
48986f87525Skettenis 	/* Assert PERST#. */
49086f87525Skettenis 	reset_gpio = malloc(reset_gpiolen, M_TEMP, M_WAITOK);
49186f87525Skettenis 	OF_getpropintarray(node, "reset-gpios", reset_gpio, reset_gpiolen);
49286f87525Skettenis 	gpio_controller_config_pin(reset_gpio, GPIO_CONFIG_OUTPUT);
49386f87525Skettenis 	gpio_controller_set_pin(reset_gpio, 1);
49486f87525Skettenis 
49589945389Skettenis 	/* Power up the device if necessary. */
49689945389Skettenis 	if (pwren_gpiolen > 0) {
49789945389Skettenis 		pwren_gpio = malloc(pwren_gpiolen, M_TEMP, M_WAITOK);
49889945389Skettenis 		OF_getpropintarray(node, "pwren-gpios",
49989945389Skettenis 		    pwren_gpio, pwren_gpiolen);
50089945389Skettenis 		gpio_controller_config_pin(pwren_gpio, GPIO_CONFIG_OUTPUT);
50189945389Skettenis 		gpio_controller_set_pin(pwren_gpio, 1);
50289945389Skettenis 		free(pwren_gpio, M_TEMP, pwren_gpiolen);
50389945389Skettenis 	}
50489945389Skettenis 
50586f87525Skettenis 	/* Setup Refclk. */
5062a3a2a65Skettenis 	LSET4(sc, port, PCIE_PHY_LANE_CTRL, PCIE_PHY_LANE_CTRL_CFGACC);
5072a3a2a65Skettenis 	LSET4(sc, port, PCIE_PHY_LANE_CONF, PCIE_PHY_LANE_CONF_REFCLK0REQ);
50886f87525Skettenis 	for (timo = 500; timo > 0; timo--) {
5092a3a2a65Skettenis 		stat = LREAD4(sc, port, PCIE_PHY_LANE_CONF);
5102a3a2a65Skettenis 		if (stat & PCIE_PHY_LANE_CONF_REFCLK0ACK)
51186f87525Skettenis 			break;
51286f87525Skettenis 		delay(100);
51386f87525Skettenis 	}
5142a3a2a65Skettenis 	LSET4(sc, port, PCIE_PHY_LANE_CONF, PCIE_PHY_LANE_CONF_REFCLK1REQ);
51586f87525Skettenis 	for (timo = 500; timo > 0; timo--) {
5162a3a2a65Skettenis 		stat = LREAD4(sc, port, PCIE_PHY_LANE_CONF);
5172a3a2a65Skettenis 		if (stat & PCIE_PHY_LANE_CONF_REFCLK1ACK)
51886f87525Skettenis 			break;
51986f87525Skettenis 		delay(100);
52086f87525Skettenis 	}
5212a3a2a65Skettenis 	LCLR4(sc, port, PCIE_PHY_LANE_CTRL, PCIE_PHY_LANE_CTRL_CFGACC);
5222a3a2a65Skettenis 	LSET4(sc, port, PCIE_PHY_LANE_CONF,
5232a3a2a65Skettenis 	    PCIE_PHY_LANE_CONF_REFCLK0EN | PCIE_PHY_LANE_CONF_REFCLK1EN);
52486f87525Skettenis 	PSET4(sc, port, PCIE_PORT_REFCLK, PCIE_PORT_REFCLK_EN);
52586f87525Skettenis 
52686f87525Skettenis 	/*
52786f87525Skettenis 	 * PERST# must remain asserted for at least 100us after the
52889945389Skettenis 	 * reference clock becomes stable.  But also has to remain
52989945389Skettenis 	 * active at least 100ms after power up.
53086f87525Skettenis 	 */
53189945389Skettenis 	if (pwren_gpiolen > 0)
53289945389Skettenis 		delay(100000);
53389945389Skettenis 	else
53486f87525Skettenis 		delay(100);
53586f87525Skettenis 
53686f87525Skettenis 	/* Deassert PERST#. */
53786f87525Skettenis 	PSET4(sc, port, PCIE_PORT_PERST, PCIE_PORT_PERST_DIS);
53886f87525Skettenis 	gpio_controller_set_pin(reset_gpio, 0);
53986f87525Skettenis 	free(reset_gpio, M_TEMP, reset_gpiolen);
54086f87525Skettenis 
54186f87525Skettenis 	for (timo = 2500; timo > 0; timo--) {
54286f87525Skettenis 		stat = PREAD4(sc, port, PCIE_PORT_STAT);
54386f87525Skettenis 		if (stat & PCIE_PORT_STAT_READY)
54486f87525Skettenis 			break;
54586f87525Skettenis 		delay(100);
54686f87525Skettenis 	}
54786f87525Skettenis 	if ((stat & PCIE_PORT_STAT_READY) == 0)
54886f87525Skettenis 		return;
54986f87525Skettenis 
55086f87525Skettenis 	PCLR4(sc, port, PCIE_PORT_REFCLK, PCIE_PORT_REFCLK_CGDIS);
55186f87525Skettenis 	PCLR4(sc, port, PCIE_PORT_APPCLK, PCIE_PORT_APPCLK_CGDIS);
55286f87525Skettenis 
55386f87525Skettenis 	/* Bring up the link. */
55486f87525Skettenis 	PWRITE4(sc, port, PCIE_PORT_LTSSM_CTRL, PCIE_PORT_LTSSM_CTRL_START);
55586f87525Skettenis 	for (timo = 1000; timo > 0; timo--) {
55686f87525Skettenis 		stat = PREAD4(sc, port, PCIE_PORT_LINK_STAT);
55786f87525Skettenis 		if (stat & PCIE_PORT_LINK_STAT_UP)
55886f87525Skettenis 			break;
55986f87525Skettenis 		delay(100);
56086f87525Skettenis 	}
56186f87525Skettenis }
56286f87525Skettenis 
56386f87525Skettenis void
aplpcie_t6020_init_port(struct aplpcie_softc * sc,int node)5642a3a2a65Skettenis aplpcie_t6020_init_port(struct aplpcie_softc *sc, int node)
5652a3a2a65Skettenis {
5662a3a2a65Skettenis 	char status[32];
5672a3a2a65Skettenis 	uint32_t reg[5];
5682a3a2a65Skettenis 	uint32_t *pwren_gpio;
5692a3a2a65Skettenis 	uint32_t *reset_gpio;
5702a3a2a65Skettenis 	int pwren_gpiolen, reset_gpiolen;
5712a3a2a65Skettenis 	uint32_t stat;
5720d546792Skettenis 	int idx, msi, port, timo;
5732a3a2a65Skettenis 
5742a3a2a65Skettenis 	if (OF_getprop(node, "status", status, sizeof(status)) > 0 &&
5752a3a2a65Skettenis 	    strcmp(status, "disabled") == 0)
5762a3a2a65Skettenis 		return;
5772a3a2a65Skettenis 
5782a3a2a65Skettenis 	if (OF_getpropintarray(node, "reg", reg, sizeof(reg)) != sizeof(reg))
5792a3a2a65Skettenis 		return;
5802a3a2a65Skettenis 
5812a3a2a65Skettenis 	port = reg[0] >> 11;
5822a3a2a65Skettenis 	if (port >= APLPCIE_MAX_PORTS || sc->sc_port_ios[port] == 0)
5832a3a2a65Skettenis 		return;
5842a3a2a65Skettenis 
5852a3a2a65Skettenis 	pwren_gpiolen = OF_getproplen(node, "pwren-gpios");
5862a3a2a65Skettenis 	reset_gpiolen = OF_getproplen(node, "reset-gpios");
5872a3a2a65Skettenis 	if (reset_gpiolen <= 0)
5882a3a2a65Skettenis 		return;
5892a3a2a65Skettenis 
5902a3a2a65Skettenis 	/*
5912a3a2a65Skettenis 	 * Set things up such that we can share the 32 available MSIs
5922a3a2a65Skettenis 	 * across all ports.
5932a3a2a65Skettenis 	 */
5942a3a2a65Skettenis 	PWRITE4(sc, port, PCIE_PORT_MSI_CTRL, PCIE_PORT_MSI_CTRL_ENABLE);
5952a3a2a65Skettenis 	for (msi = 0; msi < 32; msi++)
5962a3a2a65Skettenis 		PWRITE4(sc, port, PCIE_T6020_PORT_MSI_MAP(msi),
5972a3a2a65Skettenis 		    msi | PCIE_T6020_PORT_MSI_MAP_ENABLE);
5982a3a2a65Skettenis 	PWRITE4(sc, port, PCIE_T6020_PORT_MSI_DOORBELL_LO,
5992a3a2a65Skettenis 	    sc->sc_msi_doorbell);
6002a3a2a65Skettenis 	PWRITE4(sc, port, PCIE_T6020_PORT_MSI_DOORBELL_HI,
6012a3a2a65Skettenis 	    sc->sc_msi_doorbell >> 32);
6022a3a2a65Skettenis 
6030d546792Skettenis 	/*
6040d546792Skettenis 	 * Clear stream ID mappings.
6050d546792Skettenis 	 */
6060d546792Skettenis 	for (idx = 0; idx < PCIE_T6020_PORT_MAX_RID2SID; idx++)
6070d546792Skettenis 		PWRITE4(sc, port, PCIE_T6020_PORT_RID2SID(idx), 0);
6080d546792Skettenis 
6092a3a2a65Skettenis 	/* Check if the link is already up. */
6102a3a2a65Skettenis 	stat = PREAD4(sc, port, PCIE_PORT_LINK_STAT);
6112a3a2a65Skettenis 	if (stat & PCIE_PORT_LINK_STAT_UP)
6122a3a2a65Skettenis 		return;
6132a3a2a65Skettenis 
6142a3a2a65Skettenis 	PSET4(sc, port, PCIE_PORT_APPCLK, PCIE_PORT_APPCLK_EN);
6152a3a2a65Skettenis 
6162a3a2a65Skettenis 	/* Assert PERST#. */
6172a3a2a65Skettenis 	reset_gpio = malloc(reset_gpiolen, M_TEMP, M_WAITOK);
6182a3a2a65Skettenis 	OF_getpropintarray(node, "reset-gpios", reset_gpio, reset_gpiolen);
6192a3a2a65Skettenis 	gpio_controller_config_pin(reset_gpio, GPIO_CONFIG_OUTPUT);
6202a3a2a65Skettenis 	gpio_controller_set_pin(reset_gpio, 1);
6212a3a2a65Skettenis 
6222a3a2a65Skettenis 	/* Power up the device if necessary. */
6232a3a2a65Skettenis 	if (pwren_gpiolen > 0) {
6242a3a2a65Skettenis 		pwren_gpio = malloc(pwren_gpiolen, M_TEMP, M_WAITOK);
6252a3a2a65Skettenis 		OF_getpropintarray(node, "pwren-gpios",
6262a3a2a65Skettenis 		    pwren_gpio, pwren_gpiolen);
6272a3a2a65Skettenis 		gpio_controller_config_pin(pwren_gpio, GPIO_CONFIG_OUTPUT);
6282a3a2a65Skettenis 		gpio_controller_set_pin(pwren_gpio, 1);
6292a3a2a65Skettenis 		free(pwren_gpio, M_TEMP, pwren_gpiolen);
6302a3a2a65Skettenis 	}
6312a3a2a65Skettenis 
6322a3a2a65Skettenis 	/* Setup Refclk. */
6332a3a2a65Skettenis 	LSET4(sc, port, PCIE_PHY_LANE_CONF, PCIE_PHY_LANE_CONF_REFCLK0REQ);
6342a3a2a65Skettenis 	for (timo = 500; timo > 0; timo--) {
6352a3a2a65Skettenis 		stat = LREAD4(sc, port, PCIE_PHY_LANE_CONF);
6362a3a2a65Skettenis 		if (stat & PCIE_PHY_LANE_CONF_REFCLK0ACK)
6372a3a2a65Skettenis 			break;
6382a3a2a65Skettenis 		delay(100);
6392a3a2a65Skettenis 	}
6402a3a2a65Skettenis 	LSET4(sc, port, PCIE_PHY_LANE_CONF, PCIE_PHY_LANE_CONF_REFCLK1REQ);
6412a3a2a65Skettenis 	for (timo = 500; timo > 0; timo--) {
6422a3a2a65Skettenis 		stat = LREAD4(sc, port, PCIE_PHY_LANE_CONF);
6432a3a2a65Skettenis 		if (stat & PCIE_PHY_LANE_CONF_REFCLK1ACK)
6442a3a2a65Skettenis 			break;
6452a3a2a65Skettenis 		delay(100);
6462a3a2a65Skettenis 	}
6472a3a2a65Skettenis 	LSET4(sc, port, PCIE_PHY_LANE_CONF,
6482a3a2a65Skettenis 	    PCIE_PHY_LANE_CONF_REFCLK0EN | PCIE_PHY_LANE_CONF_REFCLK1EN);
6492a3a2a65Skettenis 
6502a3a2a65Skettenis 	/*
6512a3a2a65Skettenis 	 * PERST# must remain asserted for at least 100us after the
6522a3a2a65Skettenis 	 * reference clock becomes stable.  But also has to remain
6532a3a2a65Skettenis 	 * active at least 100ms after power up.
6542a3a2a65Skettenis 	 */
6552a3a2a65Skettenis 	if (pwren_gpiolen > 0)
6562a3a2a65Skettenis 		delay(100000);
6572a3a2a65Skettenis 	else
6582a3a2a65Skettenis 		delay(100);
6592a3a2a65Skettenis 
6602a3a2a65Skettenis 	/* Deassert PERST#. */
6612a3a2a65Skettenis 	PSET4(sc, port, PCIE_T6020_PORT_PERST, PCIE_PORT_PERST_DIS);
6622a3a2a65Skettenis 	gpio_controller_set_pin(reset_gpio, 0);
6632a3a2a65Skettenis 	free(reset_gpio, M_TEMP, reset_gpiolen);
6642a3a2a65Skettenis 
6652a3a2a65Skettenis 	for (timo = 2500; timo > 0; timo--) {
6662a3a2a65Skettenis 		stat = PREAD4(sc, port, PCIE_PORT_STAT);
6672a3a2a65Skettenis 		if (stat & PCIE_PORT_STAT_READY)
6682a3a2a65Skettenis 			break;
6692a3a2a65Skettenis 		delay(100);
6702a3a2a65Skettenis 	}
6712a3a2a65Skettenis 	if ((stat & PCIE_PORT_STAT_READY) == 0)
6722a3a2a65Skettenis 		return;
6732a3a2a65Skettenis 
6742a3a2a65Skettenis 	LSET4(sc, port, PCIE_PHY_LANE_CONF,
6752a3a2a65Skettenis 	    PCIE_PHY_LANE_CONF_REFCLK0CGEN | PCIE_PHY_LANE_CONF_REFCLK1CGEN);
6762a3a2a65Skettenis 	PCLR4(sc, port, PCIE_PORT_APPCLK, PCIE_PORT_APPCLK_CGDIS);
6772a3a2a65Skettenis 
6782a3a2a65Skettenis 	/* Bring up the link. */
6792a3a2a65Skettenis 	PWRITE4(sc, port, PCIE_PORT_LTSSM_CTRL, PCIE_PORT_LTSSM_CTRL_START);
6802a3a2a65Skettenis 	for (timo = 1000; timo > 0; timo--) {
6812a3a2a65Skettenis 		stat = PREAD4(sc, port, PCIE_PORT_LINK_STAT);
6822a3a2a65Skettenis 		if (stat & PCIE_PORT_LINK_STAT_UP)
6832a3a2a65Skettenis 			break;
6842a3a2a65Skettenis 		delay(100);
6852a3a2a65Skettenis 	}
6862a3a2a65Skettenis }
6872a3a2a65Skettenis 
6882a3a2a65Skettenis void
aplpcie_attach_hook(struct device * parent,struct device * self,struct pcibus_attach_args * pba)689ac95a80cSkettenis aplpcie_attach_hook(struct device *parent, struct device *self,
690ac95a80cSkettenis     struct pcibus_attach_args *pba)
691ac95a80cSkettenis {
692ac95a80cSkettenis }
693ac95a80cSkettenis 
694ac95a80cSkettenis int
aplpcie_bus_maxdevs(void * v,int bus)695ac95a80cSkettenis aplpcie_bus_maxdevs(void *v, int bus)
696ac95a80cSkettenis {
697ac95a80cSkettenis 	return 32;
698ac95a80cSkettenis }
699ac95a80cSkettenis 
700ad1c997dSkettenis int
aplpcie_find_node(int node,int bus,int device,int function)701ad1c997dSkettenis aplpcie_find_node(int node, int bus, int device, int function)
702ad1c997dSkettenis {
703ad1c997dSkettenis 	uint32_t reg[5];
704ad1c997dSkettenis 	uint32_t phys_hi;
705ad1c997dSkettenis 	int child;
706ad1c997dSkettenis 
707ad1c997dSkettenis 	phys_hi = ((bus << 16) | (device << 11) | (function << 8));
708ad1c997dSkettenis 
709ad1c997dSkettenis 	for (child = OF_child(node); child; child = OF_peer(child)) {
710ad1c997dSkettenis 		if (OF_getpropintarray(child, "reg",
711ad1c997dSkettenis 		    reg, sizeof(reg)) != sizeof(reg))
712ad1c997dSkettenis 			continue;
713ad1c997dSkettenis 
714ad1c997dSkettenis 		if (reg[0] == phys_hi)
715ad1c997dSkettenis 			return child;
716ad1c997dSkettenis 
717ad1c997dSkettenis 		node = aplpcie_find_node(child, bus, device, function);
718ad1c997dSkettenis 		if (node)
719ad1c997dSkettenis 			return node;
720ad1c997dSkettenis 	}
721ad1c997dSkettenis 
722ad1c997dSkettenis 	return 0;
723ad1c997dSkettenis }
724ad1c997dSkettenis 
725ac95a80cSkettenis pcitag_t
aplpcie_make_tag(void * v,int bus,int device,int function)726ac95a80cSkettenis aplpcie_make_tag(void *v, int bus, int device, int function)
727ac95a80cSkettenis {
728ad1c997dSkettenis 	struct aplpcie_softc *sc = v;
729ad1c997dSkettenis 	int node;
730ad1c997dSkettenis 
731ad1c997dSkettenis 	node = aplpcie_find_node(sc->sc_node, bus, device, function);
732ad1c997dSkettenis 	return (((pcitag_t)node << 32) |
733ad1c997dSkettenis 	    (bus << 20) | (device << 15) | (function << 12));
734ac95a80cSkettenis }
735ac95a80cSkettenis 
736ac95a80cSkettenis void
aplpcie_decompose_tag(void * v,pcitag_t tag,int * bp,int * dp,int * fp)737ac95a80cSkettenis aplpcie_decompose_tag(void *v, pcitag_t tag, int *bp, int *dp, int *fp)
738ac95a80cSkettenis {
739ac95a80cSkettenis 	if (bp != NULL)
740ac95a80cSkettenis 		*bp = (tag >> 20) & 0xff;
741ac95a80cSkettenis 	if (dp != NULL)
742ac95a80cSkettenis 		*dp = (tag >> 15) & 0x1f;
743ac95a80cSkettenis 	if (fp != NULL)
744ac95a80cSkettenis 		*fp = (tag >> 12) & 0x7;
745ac95a80cSkettenis }
746ac95a80cSkettenis 
747ac95a80cSkettenis int
aplpcie_conf_size(void * v,pcitag_t tag)748ac95a80cSkettenis aplpcie_conf_size(void *v, pcitag_t tag)
749ac95a80cSkettenis {
750ac95a80cSkettenis 	return PCIE_CONFIG_SPACE_SIZE;
751ac95a80cSkettenis }
752ac95a80cSkettenis 
753ac95a80cSkettenis pcireg_t
aplpcie_conf_read(void * v,pcitag_t tag,int reg)754ac95a80cSkettenis aplpcie_conf_read(void *v, pcitag_t tag, int reg)
755ac95a80cSkettenis {
756ac95a80cSkettenis 	struct aplpcie_softc *sc = v;
757ac95a80cSkettenis 
758ad1c997dSkettenis 	tag = PCITAG_OFFSET(tag);
759ac95a80cSkettenis 	return HREAD4(sc, tag | reg);
760ac95a80cSkettenis }
761ac95a80cSkettenis 
762ac95a80cSkettenis void
aplpcie_conf_write(void * v,pcitag_t tag,int reg,pcireg_t data)763ac95a80cSkettenis aplpcie_conf_write(void *v, pcitag_t tag, int reg, pcireg_t data)
764ac95a80cSkettenis {
765ac95a80cSkettenis 	struct aplpcie_softc *sc = v;
766ac95a80cSkettenis 
767ad1c997dSkettenis 	tag = PCITAG_OFFSET(tag);
768ac95a80cSkettenis 	HWRITE4(sc, tag | reg, data);
769ac95a80cSkettenis }
770ac95a80cSkettenis 
771ac95a80cSkettenis int
aplpcie_find_port(struct aplpcie_softc * sc,int bus)772ce211e92Skettenis aplpcie_find_port(struct aplpcie_softc *sc, int bus)
773ce211e92Skettenis {
774ce211e92Skettenis 	uint32_t bus_range[2];
775ce211e92Skettenis 	uint32_t reg[5];
776ce211e92Skettenis 	int node;
777ce211e92Skettenis 
778ce211e92Skettenis 	for (node = OF_child(sc->sc_node); node; node = OF_peer(node)) {
779ce211e92Skettenis 		/* Check if bus is in the range for this node. */
780ce211e92Skettenis 		if (OF_getpropintarray(node, "bus-range", bus_range,
781ce211e92Skettenis 		    sizeof(bus_range)) != sizeof(bus_range))
782ce211e92Skettenis 			continue;
783ce211e92Skettenis 		if (bus < bus_range[0] || bus > bus_range[1])
784ce211e92Skettenis 			continue;
785ce211e92Skettenis 
786ce211e92Skettenis 		if (OF_getpropintarray(node, "reg", reg,
787ce211e92Skettenis 		    sizeof(reg)) != sizeof(reg))
788ce211e92Skettenis 			continue;
789ce211e92Skettenis 		return reg[0] >> 11;
790ce211e92Skettenis 	}
791ce211e92Skettenis 
792ce211e92Skettenis 	return -1;
793ce211e92Skettenis }
794ce211e92Skettenis 
795ce211e92Skettenis int
aplpcie_map_rid(struct aplpcie_softc * sc,int port,uint16_t rid,uint32_t sid)7960d546792Skettenis aplpcie_map_rid(struct aplpcie_softc *sc, int port, uint16_t rid, uint32_t sid)
7970d546792Skettenis {
7980d546792Skettenis 	uint32_t reg;
7990d546792Skettenis 	int idx;
8000d546792Skettenis 
8010d546792Skettenis 	for (idx = 0; idx < PCIE_PORT_MAX_RID2SID; idx++) {
8020d546792Skettenis 		reg = PREAD4(sc, port, PCIE_PORT_RID2SID(idx));
8030d546792Skettenis 
8040d546792Skettenis 		/* If already mapped, we're done. */
8050d546792Skettenis 		if ((reg & PCIE_PORT_RID2SID_RID_MASK) == rid)
8060d546792Skettenis 			return 0;
8070d546792Skettenis 
8080d546792Skettenis 		/* Is this an empty slot? */
8090d546792Skettenis 		if (reg & PCIE_PORT_RID2SID_VALID)
8100d546792Skettenis 			continue;
8110d546792Skettenis 
8120d546792Skettenis 		/* Map using this slot. */
8130d546792Skettenis 		reg = (sid << PCIE_PORT_RID2SID_SID_SHIFT) | rid |
8140d546792Skettenis 		    PCIE_PORT_RID2SID_VALID;
8150d546792Skettenis 		PWRITE4(sc, port, PCIE_PORT_RID2SID(idx), reg);
8160d546792Skettenis 
8170d546792Skettenis 		/* Read back to check the slot is implemented. */
8180d546792Skettenis 		if (PREAD4(sc, port, PCIE_PORT_RID2SID(idx)) != reg)
8190d546792Skettenis 			return ENODEV;
8200d546792Skettenis 		return 0;
8210d546792Skettenis 	}
8220d546792Skettenis 
8230d546792Skettenis 	return ENODEV;
8240d546792Skettenis }
8250d546792Skettenis 
8260d546792Skettenis int
aplpcie_t6020_map_rid(struct aplpcie_softc * sc,int port,uint16_t rid,uint32_t sid)8270d546792Skettenis aplpcie_t6020_map_rid(struct aplpcie_softc *sc, int port, uint16_t rid,
8280d546792Skettenis     uint32_t sid)
8290d546792Skettenis {
8300d546792Skettenis 	uint32_t reg;
8310d546792Skettenis 	int idx;
8320d546792Skettenis 
8330d546792Skettenis 	for (idx = 0; idx < PCIE_T6020_PORT_MAX_RID2SID; idx++) {
8340d546792Skettenis 		reg = PREAD4(sc, port, PCIE_T6020_PORT_RID2SID(idx));
8350d546792Skettenis 
8360d546792Skettenis 		/* If already mapped, we're done. */
8370d546792Skettenis 		if ((reg & PCIE_PORT_RID2SID_RID_MASK) == rid)
8380d546792Skettenis 			return 0;
8390d546792Skettenis 
8400d546792Skettenis 		/* Is this an empty slot? */
8410d546792Skettenis 		if (reg & PCIE_PORT_RID2SID_VALID)
8420d546792Skettenis 			continue;
8430d546792Skettenis 
8440d546792Skettenis 		/* Map using this slot. */
8450d546792Skettenis 		reg = (sid << PCIE_PORT_RID2SID_SID_SHIFT) | rid |
8460d546792Skettenis 		    PCIE_PORT_RID2SID_VALID;
8470d546792Skettenis 		PWRITE4(sc, port, PCIE_T6020_PORT_RID2SID(idx), reg);
8480d546792Skettenis 
8490d546792Skettenis 		/* Read back to check the slot is implemented. */
8500d546792Skettenis 		if (PREAD4(sc, port, PCIE_T6020_PORT_RID2SID(idx)) != reg)
8510d546792Skettenis 			return ENODEV;
8520d546792Skettenis 		return 0;
8530d546792Skettenis 	}
8540d546792Skettenis 
8550d546792Skettenis 	return ENODEV;
8560d546792Skettenis }
8570d546792Skettenis 
8580d546792Skettenis int
aplpcie_probe_device_hook(void * v,struct pci_attach_args * pa)859ac95a80cSkettenis aplpcie_probe_device_hook(void *v, struct pci_attach_args *pa)
860ac95a80cSkettenis {
861ac95a80cSkettenis 	struct aplpcie_softc *sc = v;
8620d546792Skettenis 	uint32_t phandle, sid;
863ac95a80cSkettenis 	uint16_t rid;
8640d546792Skettenis 	int error, port;
865ac95a80cSkettenis 
866ac95a80cSkettenis 	rid = pci_requester_id(pa->pa_pc, pa->pa_tag);
867ac95a80cSkettenis 	pa->pa_dmat = iommu_device_map_pci(sc->sc_node, rid, pa->pa_dmat);
868ce211e92Skettenis 	if (iommu_device_lookup_pci(sc->sc_node, rid, &phandle, &sid))
869ce211e92Skettenis 		return 0;
870ac95a80cSkettenis 
871ce211e92Skettenis 	/*
872ce211e92Skettenis 	 * Create a stream ID mapping for this device.  The mappings
873ce211e92Skettenis 	 * are per-port so we first need to find the port for this
874ce211e92Skettenis 	 * device.  Then we find a free mapping slot to enter the
875ce211e92Skettenis 	 * mapping.  If we run out of mappings, we print a warning; as
876ce211e92Skettenis 	 * long as the device doesn't do DMA, it will still work.
877ce211e92Skettenis 	 */
878ce211e92Skettenis 
879ce211e92Skettenis 	port = aplpcie_find_port(sc, pa->pa_bus);
880ce211e92Skettenis 	if (port == -1)
881ce211e92Skettenis 		return EINVAL;
882ce211e92Skettenis 
8830d546792Skettenis 	if (OF_is_compatible(sc->sc_node, "apple,t6020-pcie"))
8840d546792Skettenis 		error = aplpcie_t6020_map_rid(sc, port, rid, sid);
8850d546792Skettenis 	else
8860d546792Skettenis 		error = aplpcie_map_rid(sc, port, rid, sid);
8870d546792Skettenis 	if (error) {
888ce211e92Skettenis 		printf("%s: out of stream ID mapping slots\n",
889ce211e92Skettenis 		    sc->sc_dev.dv_xname);
8900d546792Skettenis 	}
8910d546792Skettenis 
8920d546792Skettenis 	/*
8930d546792Skettenis 	 * Not all PCI devices do DMA, so don't return an error if we
8940d546792Skettenis 	 * ran out of stream ID mapping slots.
8950d546792Skettenis 	 */
896ac95a80cSkettenis 	return 0;
897ac95a80cSkettenis }
898ac95a80cSkettenis 
899ac95a80cSkettenis int
aplpcie_intr_map(struct pci_attach_args * pa,pci_intr_handle_t * ihp)900ac95a80cSkettenis aplpcie_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp)
901ac95a80cSkettenis {
902ac95a80cSkettenis 	int pin = pa->pa_rawintrpin;
903ac95a80cSkettenis 
904ac95a80cSkettenis 	if (pin == 0 || pin > PCI_INTERRUPT_PIN_MAX)
905ac95a80cSkettenis 		return -1;
906ac95a80cSkettenis 
907ac95a80cSkettenis 	if (pa->pa_tag == 0)
908ac95a80cSkettenis 		return -1;
909ac95a80cSkettenis 
910ac95a80cSkettenis 	ihp->ih_pc = pa->pa_pc;
911ac95a80cSkettenis 	ihp->ih_tag = pa->pa_intrtag;
912ac95a80cSkettenis 	ihp->ih_intrpin = pa->pa_intrpin;
913ac95a80cSkettenis 	ihp->ih_type = PCI_INTX;
914ac95a80cSkettenis 
915ac95a80cSkettenis 	return 0;
916ac95a80cSkettenis }
917ac95a80cSkettenis 
918ac95a80cSkettenis const char *
aplpcie_intr_string(void * v,pci_intr_handle_t ih)919ac95a80cSkettenis aplpcie_intr_string(void *v, pci_intr_handle_t ih)
920ac95a80cSkettenis {
921ac95a80cSkettenis 	switch (ih.ih_type) {
922ac95a80cSkettenis 	case PCI_MSI:
923ac95a80cSkettenis 		return "msi";
924ac95a80cSkettenis 	case PCI_MSIX:
925ac95a80cSkettenis 		return "msix";
926ac95a80cSkettenis 	}
927ac95a80cSkettenis 
928ac95a80cSkettenis 	return "intx";
929ac95a80cSkettenis }
930ac95a80cSkettenis 
931ac95a80cSkettenis void *
aplpcie_intr_establish(void * v,pci_intr_handle_t ih,int level,struct cpu_info * ci,int (* func)(void *),void * arg,char * name)932ac95a80cSkettenis aplpcie_intr_establish(void *v, pci_intr_handle_t ih, int level,
933ac95a80cSkettenis     struct cpu_info *ci, int (*func)(void *), void *arg, char *name)
934ac95a80cSkettenis {
935ac95a80cSkettenis 	struct aplpcie_softc *sc = v;
936ac95a80cSkettenis 	void *cookie;
937ac95a80cSkettenis 
938ac95a80cSkettenis 	KASSERT(ih.ih_type != PCI_NONE);
939ac95a80cSkettenis 
940ac95a80cSkettenis 	if (ih.ih_type != PCI_INTX) {
941ac95a80cSkettenis 		uint64_t addr, data;
942ac95a80cSkettenis 
943*56d02c00Skettenis 		addr = data = 0;
9445641a7faSkettenis 		cookie = fdt_intr_establish_msi_cpu(sc->sc_node, &addr,
9455641a7faSkettenis 		    &data, level, ci, func, arg, name);
946ac95a80cSkettenis 		if (cookie == NULL)
947ac95a80cSkettenis 			return NULL;
948ac95a80cSkettenis 
949ac95a80cSkettenis 		if (ih.ih_type == PCI_MSIX) {
950ac95a80cSkettenis 			pci_msix_enable(ih.ih_pc, ih.ih_tag,
951ac95a80cSkettenis 			    &sc->sc_bus_memt, ih.ih_intrpin, addr, data);
952ac95a80cSkettenis 		} else
953ac95a80cSkettenis 			pci_msi_enable(ih.ih_pc, ih.ih_tag, addr, data);
954ac95a80cSkettenis 	} else {
955ac95a80cSkettenis 		int bus, dev, fn;
956ac95a80cSkettenis 		uint32_t reg[4];
957ac95a80cSkettenis 
958ac95a80cSkettenis 		aplpcie_decompose_tag(sc, ih.ih_tag, &bus, &dev, &fn);
959ac95a80cSkettenis 
960ac95a80cSkettenis 		reg[0] = bus << 16 | dev << 11 | fn << 8;
961ac95a80cSkettenis 		reg[1] = reg[2] = 0;
962ac95a80cSkettenis 		reg[3] = ih.ih_intrpin;
963ac95a80cSkettenis 
964ac95a80cSkettenis 		cookie = fdt_intr_establish_imap_cpu(sc->sc_node, reg,
965ac95a80cSkettenis 		    sizeof(reg), level, ci, func, arg, name);
966ac95a80cSkettenis 	}
967ac95a80cSkettenis 
968ac95a80cSkettenis 	return cookie;
969ac95a80cSkettenis }
970ac95a80cSkettenis 
971ac95a80cSkettenis void
aplpcie_intr_disestablish(void * v,void * cookie)972ac95a80cSkettenis aplpcie_intr_disestablish(void *v, void *cookie)
973ac95a80cSkettenis {
974ac95a80cSkettenis }
975ac95a80cSkettenis 
9765641a7faSkettenis void *
aplpcie_intr_establish_msi(void * cookie,uint64_t * addr,uint64_t * data,int level,struct cpu_info * ci,int (* func)(void *),void * arg,char * name)9775641a7faSkettenis aplpcie_intr_establish_msi(void *cookie, uint64_t *addr, uint64_t *data,
9785641a7faSkettenis     int level, struct cpu_info *ci, int (*func)(void *), void *arg, char *name)
9795641a7faSkettenis {
9805641a7faSkettenis 	struct aplpcie_softc *sc = cookie;
98196995178Skettenis 	uint32_t cells[4];
98296995178Skettenis 	int ncells;
9835641a7faSkettenis 
98496995178Skettenis 	ncells = sc->sc_msi_rangelen / sizeof(uint32_t);
98596995178Skettenis 	if (sc->sc_msi >= sc->sc_msi_range[ncells - 1])
9865641a7faSkettenis 		return NULL;
9875641a7faSkettenis 
9885641a7faSkettenis 	*addr = sc->sc_msi_doorbell;
9895641a7faSkettenis 	*data = sc->sc_msi++;
9905641a7faSkettenis 
99196995178Skettenis 	memcpy(cells, &sc->sc_msi_range[1], sizeof(cells));
99296995178Skettenis 	cells[ncells - 4] += *data;
9935641a7faSkettenis 
9945641a7faSkettenis 	return fdt_intr_parent_establish(&sc->sc_msi_ic, cells,
9955641a7faSkettenis 	    level, ci, func, arg, name);
9965641a7faSkettenis }
9975641a7faSkettenis 
9985641a7faSkettenis void
aplpcie_intr_disestablish_msi(void * cookie)9995641a7faSkettenis aplpcie_intr_disestablish_msi(void *cookie)
10005641a7faSkettenis {
10015641a7faSkettenis 	fdt_intr_parent_disestablish(cookie);
10025641a7faSkettenis }
10035641a7faSkettenis 
1004ac95a80cSkettenis int
aplpcie_bs_iomap(bus_space_tag_t t,bus_addr_t addr,bus_size_t size,int flags,bus_space_handle_t * bshp)1005ac95a80cSkettenis aplpcie_bs_iomap(bus_space_tag_t t, bus_addr_t addr, bus_size_t size,
1006ac95a80cSkettenis     int flags, bus_space_handle_t *bshp)
1007ac95a80cSkettenis {
1008ac95a80cSkettenis 	struct aplpcie_softc *sc = t->bus_private;
1009ac95a80cSkettenis 	int i;
1010ac95a80cSkettenis 
1011ac95a80cSkettenis 	for (i = 0; i < sc->sc_nranges; i++) {
1012ac95a80cSkettenis 		uint64_t pci_start = sc->sc_ranges[i].pci_base;
1013ac95a80cSkettenis 		uint64_t pci_end = pci_start + sc->sc_ranges[i].size;
1014ac95a80cSkettenis 		uint64_t phys_start = sc->sc_ranges[i].phys_base;
1015ac95a80cSkettenis 
1016ac95a80cSkettenis 		if ((sc->sc_ranges[i].flags & 0x03000000) == 0x01000000 &&
1017ac95a80cSkettenis 		    addr >= pci_start && addr + size <= pci_end) {
1018ac95a80cSkettenis 			return bus_space_map(sc->sc_iot,
1019ac95a80cSkettenis 			    addr - pci_start + phys_start, size, flags, bshp);
1020ac95a80cSkettenis 		}
1021ac95a80cSkettenis 	}
1022ac95a80cSkettenis 
1023ac95a80cSkettenis 	return ENXIO;
1024ac95a80cSkettenis }
1025ac95a80cSkettenis 
1026ac95a80cSkettenis int
aplpcie_bs_memmap(bus_space_tag_t t,bus_addr_t addr,bus_size_t size,int flags,bus_space_handle_t * bshp)1027ac95a80cSkettenis aplpcie_bs_memmap(bus_space_tag_t t, bus_addr_t addr, bus_size_t size,
1028ac95a80cSkettenis     int flags, bus_space_handle_t *bshp)
1029ac95a80cSkettenis {
1030ac95a80cSkettenis 	struct aplpcie_softc *sc = t->bus_private;
1031ac95a80cSkettenis 	int i;
1032ac95a80cSkettenis 
1033ac95a80cSkettenis 	flags |= BUS_SPACE_MAP_POSTED;
1034ac95a80cSkettenis 
1035ac95a80cSkettenis 	for (i = 0; i < sc->sc_nranges; i++) {
1036ac95a80cSkettenis 		uint64_t pci_start = sc->sc_ranges[i].pci_base;
1037ac95a80cSkettenis 		uint64_t pci_end = pci_start + sc->sc_ranges[i].size;
1038ac95a80cSkettenis 		uint64_t phys_start = sc->sc_ranges[i].phys_base;
1039ac95a80cSkettenis 
1040ac95a80cSkettenis 		if ((sc->sc_ranges[i].flags & 0x02000000) == 0x02000000 &&
1041ac95a80cSkettenis 		    addr >= pci_start && addr + size <= pci_end) {
1042ac95a80cSkettenis 			return bus_space_map(sc->sc_iot,
1043ac95a80cSkettenis 			    addr - pci_start + phys_start, size, flags, bshp);
1044ac95a80cSkettenis 		}
1045ac95a80cSkettenis 	}
1046ac95a80cSkettenis 
1047ac95a80cSkettenis 	return ENXIO;
1048ac95a80cSkettenis }
1049