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