mtk_pcie.c revision 298059
1297717Ssgalabov/*-
2297717Ssgalabov * Copyright (c) 2016 Stanislav Galabov.
3297717Ssgalabov *
4297717Ssgalabov * Redistribution and use in source and binary forms, with or without
5297717Ssgalabov * modification, are permitted provided that the following conditions
6297717Ssgalabov * are met:
7297717Ssgalabov * 1. Redistributions of source code must retain the above copyright
8297717Ssgalabov *    notice, this list of conditions and the following disclaimer.
9297717Ssgalabov * 2. Redistributions in binary form must reproduce the above copyright
10297717Ssgalabov *    notice, this list of conditions and the following disclaimer in the
11297717Ssgalabov *    documentation and/or other materials provided with the distribution.
12297717Ssgalabov *
13297717Ssgalabov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14297717Ssgalabov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15297717Ssgalabov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16297717Ssgalabov * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17297717Ssgalabov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18297717Ssgalabov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19297717Ssgalabov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20297717Ssgalabov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21297717Ssgalabov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22297717Ssgalabov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23297717Ssgalabov * SUCH DAMAGE.
24297717Ssgalabov */
25297717Ssgalabov#include <sys/cdefs.h>
26297717Ssgalabov__FBSDID("$FreeBSD: head/sys/mips/mediatek/mtk_pcie.c 298059 2016-04-15 15:24:42Z sgalabov $");
27297717Ssgalabov
28297717Ssgalabov#include <sys/param.h>
29297717Ssgalabov#include <sys/systm.h>
30297717Ssgalabov
31297717Ssgalabov#include <sys/bus.h>
32297717Ssgalabov#include <sys/interrupt.h>
33297717Ssgalabov#include <sys/malloc.h>
34297717Ssgalabov#include <sys/kernel.h>
35297717Ssgalabov#include <sys/module.h>
36297717Ssgalabov#include <sys/rman.h>
37297717Ssgalabov#include <sys/lock.h>
38297717Ssgalabov#include <sys/mutex.h>
39297717Ssgalabov#include <sys/endian.h>
40297717Ssgalabov
41297717Ssgalabov#include <vm/vm.h>
42297717Ssgalabov#include <vm/pmap.h>
43297717Ssgalabov#include <vm/vm_extern.h>
44297717Ssgalabov
45297717Ssgalabov#include <machine/bus.h>
46297717Ssgalabov#include <machine/cpu.h>
47297717Ssgalabov#include <machine/intr.h>
48297717Ssgalabov#include <machine/pmap.h>
49297717Ssgalabov
50297717Ssgalabov#include <dev/pci/pcivar.h>
51297717Ssgalabov#include <dev/pci/pcireg.h>
52297717Ssgalabov
53297717Ssgalabov#include <dev/pci/pcib_private.h>
54297717Ssgalabov
55297717Ssgalabov#include <dev/fdt/fdt_common.h>
56297717Ssgalabov#include <dev/fdt/fdt_clock.h>
57297717Ssgalabov#include <dev/ofw/openfirm.h>
58297717Ssgalabov#include <dev/ofw/ofw_bus.h>
59297717Ssgalabov#include <dev/ofw/ofw_bus_subr.h>
60297717Ssgalabov
61297717Ssgalabov#include <mips/mediatek/mtk_pcie.h>
62297717Ssgalabov#include <mips/mediatek/mtk_soc.h>
63297717Ssgalabov#include <mips/mediatek/mtk_sysctl.h>
64297717Ssgalabov#include <mips/mediatek/fdt_reset.h>
65297717Ssgalabov
66297850Ssgalabov#include "ofw_bus_if.h"
67297717Ssgalabov#include "pcib_if.h"
68297717Ssgalabov#include "pic_if.h"
69297717Ssgalabov
70297717Ssgalabov/*
71297717Ssgalabov * Note: We only support PCIe at the moment.
72297717Ssgalabov * Most SoCs in the Ralink/Mediatek family that we target actually don't
73297717Ssgalabov * support PCI anyway, with the notable exceptions being RT3662/RT3883, which
74297717Ssgalabov * support both PCI and PCIe. If there exists a board based on one of them
75297717Ssgalabov * which is of interest in the future it shouldn't be too hard to enable PCI
76297717Ssgalabov * support for it.
77297717Ssgalabov */
78297717Ssgalabov
79297717Ssgalabov/* Chip specific function declarations */
80297717Ssgalabovstatic int  mtk_pcie_phy_init(device_t);
81297717Ssgalabovstatic int  mtk_pcie_phy_start(device_t);
82297717Ssgalabovstatic int  mtk_pcie_phy_stop(device_t);
83297717Ssgalabovstatic int  mtk_pcie_phy_mt7621_init(device_t);
84297717Ssgalabovstatic int  mtk_pcie_phy_mt7628_init(device_t);
85297717Ssgalabovstatic int  mtk_pcie_phy_mt7620_init(device_t);
86297717Ssgalabovstatic int  mtk_pcie_phy_rt3883_init(device_t);
87297717Ssgalabovstatic void mtk_pcie_phy_setup_slots(device_t);
88297717Ssgalabov
89297717Ssgalabov/* Generic declarations */
90297717Ssgalabovstruct mtx mtk_pci_mtx;
91297717SsgalabovMTX_SYSINIT(mtk_pci_mtx, &mtk_pci_mtx, "MTK PCIe mutex", MTX_SPIN);
92297717Ssgalabov
93297717Ssgalabovstatic int mtk_pci_intr(void *);
94297717Ssgalabov
95297717Ssgalabovstatic struct mtk_pci_softc *mt_sc = NULL;
96297717Ssgalabov
97297717Ssgalabovstruct mtk_pci_range {
98297717Ssgalabov	u_long	base;
99297717Ssgalabov	u_long	len;
100297717Ssgalabov};
101297717Ssgalabov
102298059Ssgalabov#define FDT_RANGES_CELLS	((1 + 2 + 3) * 2)
103297717Ssgalabov
104297717Ssgalabovstatic void
105297717Ssgalabovmtk_pci_range_dump(struct mtk_pci_range *range)
106297717Ssgalabov{
107297717Ssgalabov#ifdef DEBUG
108297717Ssgalabov	printf("\n");
109297717Ssgalabov	printf("  base = 0x%08lx\n", range->base);
110297717Ssgalabov	printf("  len  = 0x%08lx\n", range->len);
111297717Ssgalabov#endif
112297717Ssgalabov}
113297717Ssgalabov
114297717Ssgalabovstatic int
115297717Ssgalabovmtk_pci_ranges_decode(phandle_t node, struct mtk_pci_range *io_space,
116297717Ssgalabov    struct mtk_pci_range *mem_space)
117297717Ssgalabov{
118297717Ssgalabov	struct mtk_pci_range *pci_space;
119297717Ssgalabov	pcell_t ranges[FDT_RANGES_CELLS];
120298059Ssgalabov	pcell_t addr_cells, size_cells, par_addr_cells;
121297717Ssgalabov	pcell_t *rangesptr;
122297717Ssgalabov	pcell_t cell0, cell1, cell2;
123298059Ssgalabov	int tuple_size, tuples, i, rv, len;
124297717Ssgalabov
125297717Ssgalabov	/*
126297717Ssgalabov	 * Retrieve 'ranges' property.
127297717Ssgalabov	 */
128298059Ssgalabov	if ((fdt_addrsize_cells(node, &addr_cells, &size_cells)) != 0)
129297717Ssgalabov		return (EINVAL);
130298059Ssgalabov	if (addr_cells != 3 || size_cells != 2)
131298059Ssgalabov		return (ERANGE);
132297717Ssgalabov
133298059Ssgalabov	par_addr_cells = fdt_parent_addr_cells(node);
134298059Ssgalabov	if (par_addr_cells != 1)
135298059Ssgalabov		return (ERANGE);
136298059Ssgalabov
137297717Ssgalabov	len = OF_getproplen(node, "ranges");
138298059Ssgalabov	if (len > sizeof(ranges))
139297717Ssgalabov		return (ENOMEM);
140297717Ssgalabov
141298059Ssgalabov	if (OF_getprop(node, "ranges", ranges, sizeof(ranges)) <= 0)
142297717Ssgalabov		return (EINVAL);
143297717Ssgalabov
144298059Ssgalabov	tuple_size = sizeof(pcell_t) * (addr_cells + par_addr_cells +
145298059Ssgalabov	    size_cells);
146298059Ssgalabov	tuples = len / tuple_size;
147297717Ssgalabov
148297717Ssgalabov	/*
149297717Ssgalabov	 * Initialize the ranges so that we don't have to worry about
150297717Ssgalabov	 * having them all defined in the FDT. In particular, it is
151297717Ssgalabov	 * perfectly fine not to want I/O space on PCI busses.
152297717Ssgalabov	 */
153297717Ssgalabov	bzero(io_space, sizeof(*io_space));
154297717Ssgalabov	bzero(mem_space, sizeof(*mem_space));
155297717Ssgalabov
156297717Ssgalabov	rangesptr = &ranges[0];
157297717Ssgalabov	for (i = 0; i < tuples; i++) {
158297717Ssgalabov		cell0 = fdt_data_get((void *)rangesptr, 1);
159297717Ssgalabov		rangesptr++;
160297717Ssgalabov		cell1 = fdt_data_get((void *)rangesptr, 1);
161297717Ssgalabov		rangesptr++;
162297717Ssgalabov		cell2 = fdt_data_get((void *)rangesptr, 1);
163297717Ssgalabov		rangesptr++;
164297717Ssgalabov
165298059Ssgalabov		if (cell0 & 0x02000000) {
166297717Ssgalabov			pci_space = mem_space;
167298059Ssgalabov		} else if (cell0 & 0x01000000) {
168297717Ssgalabov			pci_space = io_space;
169297717Ssgalabov		} else {
170297717Ssgalabov			rv = ERANGE;
171297717Ssgalabov			goto out;
172297717Ssgalabov		}
173297717Ssgalabov
174298059Ssgalabov		pci_space->base = fdt_data_get((void *)rangesptr,
175298059Ssgalabov		    par_addr_cells);
176298059Ssgalabov		rangesptr += par_addr_cells;
177298059Ssgalabov
178298059Ssgalabov		pci_space->len = fdt_data_get((void *)rangesptr, size_cells);
179298059Ssgalabov		rangesptr += size_cells;
180297717Ssgalabov	}
181297717Ssgalabov
182297717Ssgalabov	rv = 0;
183297717Ssgalabovout:
184297717Ssgalabov	return (rv);
185297717Ssgalabov}
186297717Ssgalabov
187297717Ssgalabovstatic int
188297717Ssgalabovmtk_pci_ranges(phandle_t node, struct mtk_pci_range *io_space,
189297717Ssgalabov    struct mtk_pci_range *mem_space)
190297717Ssgalabov{
191297717Ssgalabov	int err;
192297717Ssgalabov
193297717Ssgalabov	if ((err = mtk_pci_ranges_decode(node, io_space, mem_space)) != 0) {
194297717Ssgalabov		return (err);
195297717Ssgalabov	}
196297717Ssgalabov
197297717Ssgalabov	mtk_pci_range_dump(io_space);
198297717Ssgalabov	mtk_pci_range_dump(mem_space);
199297717Ssgalabov
200297717Ssgalabov	return (0);
201297717Ssgalabov}
202297717Ssgalabov
203297717Ssgalabovstatic struct ofw_compat_data compat_data[] = {
204297717Ssgalabov	{ "ralink,rt3662-pcie",		MTK_SOC_RT3883 },
205297717Ssgalabov	{ "ralink,rt3883-pcie",		MTK_SOC_RT3883 },
206297717Ssgalabov	{ "ralink,mt7620a-pcie",	MTK_SOC_MT7620A },
207297717Ssgalabov	{ "ralink,mt7621-pcie",		MTK_SOC_MT7621 },
208298059Ssgalabov	{ "mediatek,mt7621-pci",	MTK_SOC_MT7621 },
209297717Ssgalabov	{ "ralink,mt7628-pcie",		MTK_SOC_MT7628 },
210297717Ssgalabov	{ "ralink,mt7688-pcie",		MTK_SOC_MT7628 },
211297717Ssgalabov	{ NULL,				MTK_SOC_UNKNOWN }
212297717Ssgalabov};
213297717Ssgalabov
214297717Ssgalabovstatic int
215297717Ssgalabovmtk_pci_probe(device_t dev)
216297717Ssgalabov{
217297717Ssgalabov	struct mtk_pci_softc *sc = device_get_softc(dev);
218297717Ssgalabov
219297717Ssgalabov	if (!ofw_bus_status_okay(dev))
220297717Ssgalabov		return (ENXIO);
221297717Ssgalabov
222297717Ssgalabov	sc->socid = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
223297717Ssgalabov	if (sc->socid == MTK_SOC_UNKNOWN)
224297717Ssgalabov		return (ENXIO);
225297717Ssgalabov
226297717Ssgalabov	device_set_desc(dev, "MTK PCIe Controller");
227297717Ssgalabov
228297717Ssgalabov	return (0);
229297717Ssgalabov}
230297717Ssgalabov
231297717Ssgalabovstatic int
232297717Ssgalabovmtk_pci_attach(device_t dev)
233297717Ssgalabov{
234297717Ssgalabov	struct mtk_pci_softc *sc = device_get_softc(dev);
235297717Ssgalabov	struct mtk_pci_range io_space, mem_space;
236297717Ssgalabov	phandle_t node;
237297717Ssgalabov	intptr_t xref;
238297717Ssgalabov	int i, rid;
239297717Ssgalabov
240297717Ssgalabov	sc->sc_dev = dev;
241297717Ssgalabov	mt_sc = sc;
242297717Ssgalabov	sc->addr_mask = 0xffffffff;
243297717Ssgalabov
244297717Ssgalabov	/* Request our memory */
245297717Ssgalabov	rid = 0;
246297717Ssgalabov	sc->pci_res[0] = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
247297717Ssgalabov			    RF_ACTIVE);
248297717Ssgalabov	if (sc->pci_res[0] == NULL) {
249297717Ssgalabov		device_printf(dev, "could not allocate memory resource\n");
250297717Ssgalabov		return (ENXIO);
251297717Ssgalabov	}
252297717Ssgalabov
253297717Ssgalabov	/* See how many interrupts we need */
254297717Ssgalabov	if (sc->socid == MTK_SOC_MT7621)
255297717Ssgalabov		sc->sc_num_irq = 3;
256297717Ssgalabov	else {
257297717Ssgalabov		sc->sc_num_irq = 1;
258297717Ssgalabov		sc->pci_res[2] = sc->pci_res[3] = NULL;
259297717Ssgalabov		sc->pci_intrhand[1] = sc->pci_intrhand[2] = NULL;
260297717Ssgalabov	}
261297717Ssgalabov
262297717Ssgalabov	/* Request our interrupts */
263297717Ssgalabov	for (i = 1; i <= sc->sc_num_irq ; i++) {
264297717Ssgalabov		rid = i - 1;
265297717Ssgalabov		sc->pci_res[i] = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
266297717Ssgalabov				     RF_ACTIVE);
267297717Ssgalabov		if (sc->pci_res[i] == NULL) {
268297717Ssgalabov			device_printf(dev, "could not allocate interrupt "
269297717Ssgalabov			    "resource %d\n", rid);
270297717Ssgalabov			goto cleanup_res;
271297717Ssgalabov		}
272297717Ssgalabov	}
273297717Ssgalabov
274297717Ssgalabov	/* Parse our PCI 'ranges' property */
275297717Ssgalabov	node = ofw_bus_get_node(dev);
276297717Ssgalabov	xref = OF_xref_from_node(node);
277297717Ssgalabov	if (mtk_pci_ranges(node, &io_space, &mem_space)) {
278297717Ssgalabov		device_printf(dev, "could not retrieve 'ranges' data\n");
279297717Ssgalabov		goto cleanup_res;
280297717Ssgalabov	}
281297717Ssgalabov
282297717Ssgalabov	/* Memory, I/O and IRQ resource limits */
283297717Ssgalabov	sc->sc_io_base = io_space.base;
284297717Ssgalabov	sc->sc_io_size = io_space.len;
285297717Ssgalabov	sc->sc_mem_base = mem_space.base;
286297717Ssgalabov	sc->sc_mem_size = mem_space.len;
287297717Ssgalabov	sc->sc_irq_start = MTK_PCIE0_IRQ;
288297717Ssgalabov	sc->sc_irq_end = MTK_PCIE2_IRQ;
289297717Ssgalabov
290297717Ssgalabov	/* Init resource managers for memory, I/O and IRQ */
291297717Ssgalabov	sc->sc_mem_rman.rm_type = RMAN_ARRAY;
292297717Ssgalabov	sc->sc_mem_rman.rm_descr = "mtk pcie memory window";
293297717Ssgalabov	if (rman_init(&sc->sc_mem_rman) != 0 ||
294297717Ssgalabov	    rman_manage_region(&sc->sc_mem_rman, sc->sc_mem_base,
295297717Ssgalabov	    sc->sc_mem_base + sc->sc_mem_size - 1) != 0) {
296297717Ssgalabov		device_printf(dev, "failed to setup memory rman\n");
297297717Ssgalabov		goto cleanup_res;
298297717Ssgalabov	}
299297717Ssgalabov
300297717Ssgalabov	sc->sc_io_rman.rm_type = RMAN_ARRAY;
301297717Ssgalabov	sc->sc_io_rman.rm_descr = "mtk pcie io window";
302297717Ssgalabov	if (rman_init(&sc->sc_io_rman) != 0 ||
303297717Ssgalabov	    rman_manage_region(&sc->sc_io_rman, sc->sc_io_base,
304297717Ssgalabov	    sc->sc_io_base + sc->sc_io_size - 1) != 0) {
305297717Ssgalabov		device_printf(dev, "failed to setup io rman\n");
306297717Ssgalabov		goto cleanup_res;
307297717Ssgalabov	}
308297717Ssgalabov
309297717Ssgalabov	sc->sc_irq_rman.rm_type = RMAN_ARRAY;
310297717Ssgalabov	sc->sc_irq_rman.rm_descr = "mtk pcie irqs";
311297717Ssgalabov	if (rman_init(&sc->sc_irq_rman) != 0 ||
312297717Ssgalabov	    rman_manage_region(&sc->sc_irq_rman, sc->sc_irq_start,
313297717Ssgalabov	    sc->sc_irq_end) != 0) {
314297717Ssgalabov		device_printf(dev, "failed to setup irq rman\n");
315297717Ssgalabov		goto cleanup_res;
316297717Ssgalabov	}
317297717Ssgalabov
318297717Ssgalabov	/* Do SoC-specific PCIe initialization */
319297717Ssgalabov	if (mtk_pcie_phy_init(dev)) {
320297717Ssgalabov		device_printf(dev, "pcie phy init failed\n");
321297717Ssgalabov		goto cleanup_rman;
322297717Ssgalabov	}
323297717Ssgalabov
324297717Ssgalabov	/* Register ourselves as an interrupt controller */
325297717Ssgalabov	if (intr_pic_register(dev, xref) != 0) {
326297717Ssgalabov		device_printf(dev, "could not register PIC\n");
327297717Ssgalabov		goto cleanup_rman;
328297717Ssgalabov	}
329297717Ssgalabov
330297717Ssgalabov	/* Set up our interrupt handler */
331297717Ssgalabov	for (i = 1; i <= sc->sc_num_irq; i++) {
332297717Ssgalabov		sc->pci_intrhand[i - 1] = NULL;
333297717Ssgalabov		if (bus_setup_intr(dev, sc->pci_res[i], INTR_TYPE_MISC,
334297717Ssgalabov		    mtk_pci_intr, NULL, sc, &sc->pci_intrhand[i - 1])) {
335297717Ssgalabov			device_printf(dev, "could not setup intr handler %d\n",
336297717Ssgalabov			    i);
337297717Ssgalabov			goto cleanup;
338297717Ssgalabov		}
339297717Ssgalabov	}
340297717Ssgalabov
341297717Ssgalabov	/* Attach our PCI child so bus enumeration can start */
342297717Ssgalabov	if (device_add_child(dev, "pci", -1) == NULL) {
343297717Ssgalabov		device_printf(dev, "could not attach pci bus\n");
344297717Ssgalabov		goto cleanup;
345297717Ssgalabov	}
346297717Ssgalabov
347297717Ssgalabov	/* And finally, attach ourselves to the bus */
348297717Ssgalabov	if (bus_generic_attach(dev)) {
349297717Ssgalabov		device_printf(dev, "could not attach to bus\n");
350297717Ssgalabov		goto cleanup;
351297717Ssgalabov	}
352297717Ssgalabov
353297717Ssgalabov	return (0);
354297717Ssgalabov
355297717Ssgalabovcleanup:
356297717Ssgalabov#ifdef notyet
357297717Ssgalabov	intr_pic_unregister(dev, xref);
358297717Ssgalabov#endif
359297717Ssgalabov	for (i = 1; i <= sc->sc_num_irq; i++) {
360297717Ssgalabov		if (sc->pci_intrhand[i - 1] != NULL)
361297717Ssgalabov			bus_teardown_intr(dev, sc->pci_res[i],
362297717Ssgalabov			    sc->pci_intrhand[i - 1]);
363297717Ssgalabov	}
364297717Ssgalabovcleanup_rman:
365297717Ssgalabov	mtk_pcie_phy_stop(dev);
366297717Ssgalabov	rman_fini(&sc->sc_irq_rman);
367297717Ssgalabov	rman_fini(&sc->sc_io_rman);
368297717Ssgalabov	rman_fini(&sc->sc_mem_rman);
369297717Ssgalabovcleanup_res:
370297717Ssgalabov	mt_sc = NULL;
371297717Ssgalabov	if (sc->pci_res[0] != NULL)
372297717Ssgalabov		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->pci_res[0]);
373297717Ssgalabov	if (sc->pci_res[1] != NULL)
374297717Ssgalabov		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->pci_res[1]);
375297717Ssgalabov	if (sc->pci_res[2] != NULL)
376297717Ssgalabov		bus_release_resource(dev, SYS_RES_IRQ, 1, sc->pci_res[2]);
377297717Ssgalabov	if (sc->pci_res[3] != NULL)
378297717Ssgalabov		bus_release_resource(dev, SYS_RES_IRQ, 2, sc->pci_res[3]);
379297717Ssgalabov	return (ENXIO);
380297717Ssgalabov}
381297717Ssgalabov
382297717Ssgalabovstatic int
383297717Ssgalabovmtk_pci_read_ivar(device_t dev, device_t child, int which,
384297717Ssgalabov	uintptr_t *result)
385297717Ssgalabov{
386297717Ssgalabov	struct mtk_pci_softc *sc = device_get_softc(dev);
387297717Ssgalabov
388297717Ssgalabov	switch (which) {
389297717Ssgalabov	case PCIB_IVAR_DOMAIN:
390297717Ssgalabov		*result = device_get_unit(dev);
391297717Ssgalabov		return (0);
392297717Ssgalabov	case PCIB_IVAR_BUS:
393297717Ssgalabov		*result = sc->sc_busno;
394297717Ssgalabov		return (0);
395297717Ssgalabov	}
396297717Ssgalabov
397297717Ssgalabov	return (ENOENT);
398297717Ssgalabov}
399297717Ssgalabov
400297717Ssgalabovstatic int
401297717Ssgalabovmtk_pci_write_ivar(device_t dev, device_t child, int which,
402297717Ssgalabov	uintptr_t result)
403297717Ssgalabov{
404297717Ssgalabov	struct mtk_pci_softc *sc = device_get_softc(dev);
405297717Ssgalabov
406297717Ssgalabov	switch (which) {
407297717Ssgalabov	case PCIB_IVAR_BUS:
408297717Ssgalabov		sc->sc_busno = result;
409297717Ssgalabov		return (0);
410297717Ssgalabov	}
411297717Ssgalabov
412297717Ssgalabov	return (ENOENT);
413297717Ssgalabov}
414297717Ssgalabov
415297717Ssgalabovstatic struct resource *
416297717Ssgalabovmtk_pci_alloc_resource(device_t bus, device_t child, int type, int *rid,
417297717Ssgalabov	rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
418297717Ssgalabov{
419297717Ssgalabov	struct mtk_pci_softc *sc = device_get_softc(bus);
420297717Ssgalabov	struct resource *rv;
421297717Ssgalabov	struct rman *rm;
422297717Ssgalabov
423297717Ssgalabov	switch (type) {
424297850Ssgalabov	case PCI_RES_BUS:
425297850Ssgalabov		return pci_domain_alloc_bus(0, child, rid, start, end, count,
426297850Ssgalabov					    flags);
427297717Ssgalabov	case SYS_RES_IRQ:
428297717Ssgalabov		rm = &sc->sc_irq_rman;
429297717Ssgalabov		break;
430297717Ssgalabov	case SYS_RES_IOPORT:
431297717Ssgalabov		rm = &sc->sc_io_rman;
432297717Ssgalabov		break;
433297717Ssgalabov	case SYS_RES_MEMORY:
434297717Ssgalabov		rm = &sc->sc_mem_rman;
435297717Ssgalabov		break;
436297717Ssgalabov	default:
437297717Ssgalabov		return (NULL);
438297717Ssgalabov	}
439297717Ssgalabov
440297717Ssgalabov	rv = rman_reserve_resource(rm, start, end, count, flags, child);
441297717Ssgalabov
442297717Ssgalabov	if (rv == NULL)
443297717Ssgalabov		return (NULL);
444297717Ssgalabov
445297717Ssgalabov	rman_set_rid(rv, *rid);
446297717Ssgalabov
447297717Ssgalabov	if ((flags & RF_ACTIVE) && type != SYS_RES_IRQ) {
448297717Ssgalabov		if (bus_activate_resource(child, type, *rid, rv)) {
449297717Ssgalabov			rman_release_resource(rv);
450297717Ssgalabov			return (NULL);
451297717Ssgalabov		}
452297717Ssgalabov	}
453297717Ssgalabov
454297717Ssgalabov	return (rv);
455297717Ssgalabov}
456297717Ssgalabov
457297850Ssgalabovstatic int
458297850Ssgalabovmtk_pci_release_resource(device_t bus, device_t child, int type, int rid,
459297850Ssgalabov    struct resource *res)
460297850Ssgalabov{
461297850Ssgalabov
462297850Ssgalabov	if (type == PCI_RES_BUS)
463297850Ssgalabov		return (pci_domain_release_bus(0, child, rid, res));
464297850Ssgalabov
465297850Ssgalabov	return (bus_generic_release_resource(bus, child, type, rid, res));
466297850Ssgalabov}
467297850Ssgalabov
468297850Ssgalabovstatic int
469297850Ssgalabovmtk_pci_adjust_resource(device_t bus, device_t child, int type,
470297850Ssgalabov    struct resource *res, rman_res_t start, rman_res_t end)
471297850Ssgalabov{
472297850Ssgalabov	struct mtk_pci_softc *sc = device_get_softc(bus);
473297850Ssgalabov	struct rman *rm;
474297850Ssgalabov
475297850Ssgalabov	switch (type) {
476297850Ssgalabov	case PCI_RES_BUS:
477297850Ssgalabov		return pci_domain_adjust_bus(0, child, res, start, end);
478297850Ssgalabov	case SYS_RES_IRQ:
479297850Ssgalabov		rm = &sc->sc_irq_rman;
480297850Ssgalabov		break;
481297850Ssgalabov	case SYS_RES_IOPORT:
482297850Ssgalabov		rm = &sc->sc_io_rman;
483297850Ssgalabov		break;
484297850Ssgalabov	case SYS_RES_MEMORY:
485297850Ssgalabov		rm = &sc->sc_mem_rman;
486297850Ssgalabov		break;
487297850Ssgalabov	default:
488297850Ssgalabov		rm = NULL;
489297850Ssgalabov		break;
490297850Ssgalabov	}
491297850Ssgalabov
492297850Ssgalabov	if (rm != NULL)
493297850Ssgalabov		return (rman_adjust_resource(res, start, end));
494297850Ssgalabov
495297850Ssgalabov	return (bus_generic_adjust_resource(bus, child, type, res, start, end));
496297850Ssgalabov}
497297850Ssgalabov
498297717Ssgalabovstatic inline int
499297717Ssgalabovmtk_idx_to_irq(int idx)
500297717Ssgalabov{
501297717Ssgalabov
502297717Ssgalabov	return ((idx == 0) ? MTK_PCIE0_IRQ :
503297717Ssgalabov		(idx == 1) ? MTK_PCIE1_IRQ :
504297717Ssgalabov		(idx == 2) ? MTK_PCIE2_IRQ : -1);
505297717Ssgalabov}
506297717Ssgalabov
507297717Ssgalabovstatic inline int
508297717Ssgalabovmtk_irq_to_idx(int irq)
509297717Ssgalabov{
510297717Ssgalabov
511297717Ssgalabov	return ((irq == MTK_PCIE0_IRQ) ? 0 :
512297717Ssgalabov		(irq == MTK_PCIE1_IRQ) ? 1 :
513297717Ssgalabov		(irq == MTK_PCIE2_IRQ) ? 2 : -1);
514297717Ssgalabov}
515297717Ssgalabov
516297717Ssgalabovstatic void
517297717Ssgalabovmtk_pci_mask_irq(void *source)
518297717Ssgalabov{
519297717Ssgalabov	MT_WRITE32(mt_sc, MTK_PCI_PCIENA,
520297717Ssgalabov		MT_READ32(mt_sc, MTK_PCI_PCIENA) & ~(1<<((int)source)));
521297717Ssgalabov}
522297717Ssgalabov
523297717Ssgalabovstatic void
524297717Ssgalabovmtk_pci_unmask_irq(void *source)
525297717Ssgalabov{
526297717Ssgalabov
527297717Ssgalabov	MT_WRITE32(mt_sc, MTK_PCI_PCIENA,
528297717Ssgalabov		MT_READ32(mt_sc, MTK_PCI_PCIENA) | (1<<((int)source)));
529297717Ssgalabov}
530297717Ssgalabov
531297717Ssgalabovstatic int
532297717Ssgalabovmtk_pci_setup_intr(device_t bus, device_t child, struct resource *ires,
533297717Ssgalabov	int flags, driver_filter_t *filt, driver_intr_t *handler,
534297717Ssgalabov	void *arg, void **cookiep)
535297717Ssgalabov{
536297717Ssgalabov	struct mtk_pci_softc *sc = device_get_softc(bus);
537297717Ssgalabov	struct intr_event *event;
538297717Ssgalabov	int irq, error, irqidx;
539297717Ssgalabov
540297717Ssgalabov	irq = rman_get_start(ires);
541297717Ssgalabov
542297717Ssgalabov	if (irq < sc->sc_irq_start || irq > sc->sc_irq_end)
543297717Ssgalabov		return (EINVAL);
544297717Ssgalabov
545297717Ssgalabov	irqidx = irq - sc->sc_irq_start;
546297717Ssgalabov
547297717Ssgalabov	event = sc->sc_eventstab[irqidx];
548297717Ssgalabov	if (event == NULL) {
549297717Ssgalabov		error = intr_event_create(&event, (void *)irq, 0, irq,
550297717Ssgalabov		    mtk_pci_mask_irq, mtk_pci_unmask_irq, NULL, NULL,
551297717Ssgalabov		    "pci intr%d:", irq);
552297717Ssgalabov
553297717Ssgalabov		if (error == 0) {
554297717Ssgalabov			sc->sc_eventstab[irqidx] = event;
555297717Ssgalabov		}
556297717Ssgalabov		else {
557297717Ssgalabov			return (error);
558297717Ssgalabov		}
559297717Ssgalabov	}
560297717Ssgalabov
561297717Ssgalabov	intr_event_add_handler(event, device_get_nameunit(child), filt,
562297717Ssgalabov		handler, arg, intr_priority(flags), flags, cookiep);
563297717Ssgalabov
564297717Ssgalabov	mtk_pci_unmask_irq((void*)irq);
565297717Ssgalabov
566297717Ssgalabov	return (0);
567297717Ssgalabov}
568297717Ssgalabov
569297717Ssgalabovstatic int
570297717Ssgalabovmtk_pci_teardown_intr(device_t dev, device_t child, struct resource *ires,
571297717Ssgalabov	void *cookie)
572297717Ssgalabov{
573297717Ssgalabov	struct mtk_pci_softc *sc = device_get_softc(dev);
574297717Ssgalabov	int irq, result, irqidx;
575297717Ssgalabov
576297717Ssgalabov	irq = rman_get_start(ires);
577297717Ssgalabov	if (irq < sc->sc_irq_start || irq > sc->sc_irq_end)
578297717Ssgalabov		return (EINVAL);
579297717Ssgalabov
580297717Ssgalabov	irqidx = irq - sc->sc_irq_start;
581297717Ssgalabov	if (sc->sc_eventstab[irqidx] == NULL)
582297717Ssgalabov		panic("Trying to teardown unoccupied IRQ");
583297717Ssgalabov
584297717Ssgalabov	mtk_pci_mask_irq((void*)irq);
585297717Ssgalabov
586297717Ssgalabov	result = intr_event_remove_handler(cookie);
587297717Ssgalabov	if (!result)
588297717Ssgalabov		sc->sc_eventstab[irqidx] = NULL;
589297717Ssgalabov
590297717Ssgalabov
591297717Ssgalabov	return (result);
592297717Ssgalabov}
593297717Ssgalabov
594297717Ssgalabovstatic inline uint32_t
595297717Ssgalabovmtk_pci_make_addr(int bus, int slot, int func, int reg)
596297717Ssgalabov{
597297717Ssgalabov	uint32_t addr;
598297717Ssgalabov
599297717Ssgalabov	addr = ((((reg & 0xf00) >> 8) << 24) | (bus << 16) | (slot << 11) |
600297717Ssgalabov		(func << 8) | (reg & 0xfc) | (1 << 31));
601297717Ssgalabov
602297717Ssgalabov	return (addr);
603297717Ssgalabov}
604297717Ssgalabov
605297717Ssgalabovstatic int
606297717Ssgalabovmtk_pci_maxslots(device_t dev)
607297717Ssgalabov{
608297717Ssgalabov
609297717Ssgalabov	return (PCI_SLOTMAX);
610297717Ssgalabov}
611297717Ssgalabov
612297717Ssgalabovstatic inline int
613297717Ssgalabovmtk_pci_slot_has_link(device_t dev, int slot)
614297717Ssgalabov{
615297717Ssgalabov	struct mtk_pci_softc *sc = device_get_softc(dev);
616297717Ssgalabov
617297717Ssgalabov	return !!(sc->pcie_link_status & (1<<slot));
618297717Ssgalabov}
619297717Ssgalabov
620297717Ssgalabovstatic uint32_t
621297717Ssgalabovmtk_pci_read_config(device_t dev, u_int bus, u_int slot, u_int func,
622297717Ssgalabov	u_int reg, int bytes)
623297717Ssgalabov{
624297717Ssgalabov	struct mtk_pci_softc *sc = device_get_softc(dev);
625297717Ssgalabov	uint32_t addr = 0, data = 0;
626297717Ssgalabov
627297717Ssgalabov	/* Return ~0U if slot has no link */
628297717Ssgalabov	if (bus == 0 && mtk_pci_slot_has_link(dev, slot) == 0) {
629297717Ssgalabov		return (~0U);
630297717Ssgalabov	}
631297717Ssgalabov
632297717Ssgalabov	mtx_lock_spin(&mtk_pci_mtx);
633297717Ssgalabov	addr = mtk_pci_make_addr(bus, slot, func, (reg & ~3)) & sc->addr_mask;
634297717Ssgalabov	MT_WRITE32(sc, MTK_PCI_CFGADDR, addr);
635297717Ssgalabov	switch (bytes % 4) {
636297717Ssgalabov	case 0:
637297717Ssgalabov		data = MT_READ32(sc, MTK_PCI_CFGDATA);
638297717Ssgalabov		break;
639297717Ssgalabov	case 1:
640297717Ssgalabov		data = MT_READ8(sc, MTK_PCI_CFGDATA + (reg & 0x3));
641297717Ssgalabov		break;
642297717Ssgalabov	case 2:
643297717Ssgalabov		data = MT_READ16(sc, MTK_PCI_CFGDATA + (reg & 0x3));
644297717Ssgalabov		break;
645297717Ssgalabov	default:
646297717Ssgalabov		panic("%s(): Wrong number of bytes (%d) requested!\n",
647297717Ssgalabov			__FUNCTION__, bytes % 4);
648297717Ssgalabov	}
649297717Ssgalabov	mtx_unlock_spin(&mtk_pci_mtx);
650297717Ssgalabov
651297717Ssgalabov	return (data);
652297717Ssgalabov}
653297717Ssgalabov
654297717Ssgalabovstatic void
655297717Ssgalabovmtk_pci_write_config(device_t dev, u_int bus, u_int slot, u_int func,
656297717Ssgalabov	u_int reg, uint32_t val, int bytes)
657297717Ssgalabov{
658297717Ssgalabov	struct mtk_pci_softc *sc = device_get_softc(dev);
659297717Ssgalabov	uint32_t addr = 0, data = val;
660297717Ssgalabov
661297717Ssgalabov	/* Do not write if slot has no link */
662297717Ssgalabov	if (bus == 0 && mtk_pci_slot_has_link(dev, slot) == 0)
663297717Ssgalabov		return;
664297717Ssgalabov
665297717Ssgalabov	mtx_lock_spin(&mtk_pci_mtx);
666297717Ssgalabov	addr = mtk_pci_make_addr(bus, slot, func, (reg & ~3)) & sc->addr_mask;
667297717Ssgalabov	MT_WRITE32(sc, MTK_PCI_CFGADDR, addr);
668297717Ssgalabov	switch (bytes % 4) {
669297717Ssgalabov	case 0:
670297717Ssgalabov		MT_WRITE32(sc, MTK_PCI_CFGDATA, data);
671297717Ssgalabov		break;
672297717Ssgalabov	case 1:
673297717Ssgalabov		MT_WRITE8(sc, MTK_PCI_CFGDATA + (reg & 0x3), data);
674297717Ssgalabov		break;
675297717Ssgalabov	case 2:
676297717Ssgalabov		MT_WRITE16(sc, MTK_PCI_CFGDATA + (reg & 0x3), data);
677297717Ssgalabov		break;
678297717Ssgalabov	default:
679297717Ssgalabov		panic("%s(): Wrong number of bytes (%d) requested!\n",
680297717Ssgalabov			__FUNCTION__, bytes % 4);
681297717Ssgalabov	}
682297717Ssgalabov	mtx_unlock_spin(&mtk_pci_mtx);
683297717Ssgalabov}
684297717Ssgalabov
685297717Ssgalabovstatic int
686297717Ssgalabovmtk_pci_route_interrupt(device_t pcib, device_t device, int pin)
687297717Ssgalabov{
688297717Ssgalabov	int bus, sl, dev;
689297717Ssgalabov
690297717Ssgalabov	bus = pci_get_bus(device);
691297717Ssgalabov	sl = pci_get_slot(device);
692297717Ssgalabov	dev = pci_get_device(device);
693297717Ssgalabov
694297717Ssgalabov	if (bus != 0)
695297717Ssgalabov		panic("Unexpected bus number %d\n", bus);
696297717Ssgalabov
697297717Ssgalabov	/* PCIe only */
698297717Ssgalabov	switch (sl) {
699297717Ssgalabov	case 0: return MTK_PCIE0_IRQ;
700297717Ssgalabov	case 1: return MTK_PCIE0_IRQ + 1;
701297717Ssgalabov	case 2: return MTK_PCIE0_IRQ + 2;
702297717Ssgalabov	default: return (-1);
703297717Ssgalabov	}
704297717Ssgalabov
705297717Ssgalabov	return (-1);
706297717Ssgalabov}
707297717Ssgalabov
708297717Ssgalabovstatic device_method_t mtk_pci_methods[] = {
709297717Ssgalabov	/* Device interface */
710297717Ssgalabov	DEVMETHOD(device_probe,		mtk_pci_probe),
711297717Ssgalabov	DEVMETHOD(device_attach,	mtk_pci_attach),
712297717Ssgalabov	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
713297717Ssgalabov	DEVMETHOD(device_suspend,	bus_generic_suspend),
714297717Ssgalabov	DEVMETHOD(device_resume,	bus_generic_resume),
715297717Ssgalabov
716297717Ssgalabov	/* Bus interface */
717297717Ssgalabov	DEVMETHOD(bus_read_ivar,	mtk_pci_read_ivar),
718297717Ssgalabov	DEVMETHOD(bus_write_ivar,	mtk_pci_write_ivar),
719297717Ssgalabov	DEVMETHOD(bus_alloc_resource,	mtk_pci_alloc_resource),
720297850Ssgalabov	DEVMETHOD(bus_release_resource,	mtk_pci_release_resource),
721297850Ssgalabov	DEVMETHOD(bus_adjust_resource,	mtk_pci_adjust_resource),
722297717Ssgalabov	DEVMETHOD(bus_activate_resource,   bus_generic_activate_resource),
723297717Ssgalabov	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
724297717Ssgalabov	DEVMETHOD(bus_setup_intr,	mtk_pci_setup_intr),
725297717Ssgalabov	DEVMETHOD(bus_teardown_intr,	mtk_pci_teardown_intr),
726297717Ssgalabov
727297717Ssgalabov	/* pcib interface */
728297717Ssgalabov	DEVMETHOD(pcib_maxslots,	mtk_pci_maxslots),
729297717Ssgalabov	DEVMETHOD(pcib_read_config,	mtk_pci_read_config),
730297717Ssgalabov	DEVMETHOD(pcib_write_config,	mtk_pci_write_config),
731297717Ssgalabov	DEVMETHOD(pcib_route_interrupt,	mtk_pci_route_interrupt),
732297717Ssgalabov
733297850Ssgalabov	/* OFW bus interface */
734297850Ssgalabov	DEVMETHOD(ofw_bus_get_compat,	ofw_bus_gen_get_compat),
735297850Ssgalabov	DEVMETHOD(ofw_bus_get_model,	ofw_bus_gen_get_model),
736297850Ssgalabov	DEVMETHOD(ofw_bus_get_name,	ofw_bus_gen_get_name),
737297850Ssgalabov	DEVMETHOD(ofw_bus_get_node,	ofw_bus_gen_get_node),
738297850Ssgalabov	DEVMETHOD(ofw_bus_get_type,	ofw_bus_gen_get_type),
739297850Ssgalabov
740297717Ssgalabov	DEVMETHOD_END
741297717Ssgalabov};
742297717Ssgalabov
743297717Ssgalabovstatic driver_t mtk_pci_driver = {
744297717Ssgalabov	"pcib",
745297717Ssgalabov	mtk_pci_methods,
746297717Ssgalabov	sizeof(struct mtk_pci_softc),
747297717Ssgalabov};
748297717Ssgalabov
749297717Ssgalabovstatic devclass_t mtk_pci_devclass;
750297717Ssgalabov
751297717SsgalabovDRIVER_MODULE(mtk_pci, simplebus, mtk_pci_driver, mtk_pci_devclass, 0, 0);
752297717Ssgalabov
753297717Ssgalabov/* Our interrupt handler */
754297717Ssgalabovstatic int
755297717Ssgalabovmtk_pci_intr(void *arg)
756297717Ssgalabov{
757297717Ssgalabov	struct mtk_pci_softc *sc = arg;
758297717Ssgalabov	struct intr_event *event;
759297717Ssgalabov	uint32_t reg, irq, irqidx;
760297717Ssgalabov
761297717Ssgalabov	reg = MT_READ32(sc, MTK_PCI_PCIINT);
762297717Ssgalabov
763297717Ssgalabov	for (irq = sc->sc_irq_start; irq <= sc->sc_irq_end; irq++) {
764297717Ssgalabov		if (reg & (1u<<irq)) {
765297717Ssgalabov			irqidx = irq - sc->sc_irq_start;
766297717Ssgalabov			event = sc->sc_eventstab[irqidx];
767297717Ssgalabov			if (!event || TAILQ_EMPTY(&event->ie_handlers)) {
768297717Ssgalabov				if (irq != 0)
769297717Ssgalabov					printf("Stray PCI IRQ %d\n", irq);
770297717Ssgalabov				continue;
771297717Ssgalabov			}
772297717Ssgalabov
773297717Ssgalabov			intr_event_handle(event, NULL);
774297717Ssgalabov		}
775297717Ssgalabov	}
776297717Ssgalabov
777297717Ssgalabov	return (FILTER_HANDLED);
778297717Ssgalabov}
779297717Ssgalabov
780297717Ssgalabov/* PCIe SoC-specific initialization */
781297717Ssgalabovstatic int
782297717Ssgalabovmtk_pcie_phy_init(device_t dev)
783297717Ssgalabov{
784297717Ssgalabov	struct mtk_pci_softc *sc;
785297717Ssgalabov
786297717Ssgalabov	/* Get our softc */
787297717Ssgalabov	sc = device_get_softc(dev);
788297717Ssgalabov
789297717Ssgalabov	/* We don't know how many slots we have yet */
790297717Ssgalabov	sc->num_slots = 0;
791297717Ssgalabov
792297717Ssgalabov	/* Handle SoC specific PCIe init */
793297717Ssgalabov	switch (sc->socid) {
794297717Ssgalabov	case MTK_SOC_MT7628: /* Fallthrough */
795297717Ssgalabov	case MTK_SOC_MT7688:
796297717Ssgalabov		if (mtk_pcie_phy_mt7628_init(dev))
797297717Ssgalabov			return (ENXIO);
798297717Ssgalabov		break;
799297717Ssgalabov	case MTK_SOC_MT7621:
800297717Ssgalabov		if (mtk_pcie_phy_mt7621_init(dev))
801297717Ssgalabov			return (ENXIO);
802297717Ssgalabov		break;
803297717Ssgalabov	case MTK_SOC_MT7620A:
804297717Ssgalabov		if (mtk_pcie_phy_mt7620_init(dev))
805297717Ssgalabov			return (ENXIO);
806297717Ssgalabov		break;
807297717Ssgalabov	case MTK_SOC_RT3662: /* Fallthrough */
808297717Ssgalabov	case MTK_SOC_RT3883:
809297717Ssgalabov		if (mtk_pcie_phy_rt3883_init(dev))
810297717Ssgalabov			return (ENXIO);
811297717Ssgalabov		break;
812297717Ssgalabov	default:
813297717Ssgalabov		device_printf(dev, "unsupported device %x\n", sc->socid);
814297717Ssgalabov		return (ENXIO);
815297717Ssgalabov	}
816297717Ssgalabov
817297717Ssgalabov	/*
818297717Ssgalabov	 * If we were successful so far go and set up the PCIe slots, so we
819297717Ssgalabov	 * may allocate mem/io/irq resources and enumerate busses later.
820297717Ssgalabov	 */
821297717Ssgalabov	mtk_pcie_phy_setup_slots(dev);
822297717Ssgalabov
823297717Ssgalabov	return (0);
824297717Ssgalabov}
825297717Ssgalabov
826297717Ssgalabovstatic int
827297717Ssgalabovmtk_pcie_phy_start(device_t dev)
828297717Ssgalabov{
829297717Ssgalabov	struct mtk_pci_softc *sc = device_get_softc(dev);
830297717Ssgalabov
831297717Ssgalabov	if (sc->socid == MTK_SOC_MT7621 &&
832297717Ssgalabov	    (mtk_sysctl_get(SYSCTL_REVID) & SYSCTL_REVID_MASK) !=
833297717Ssgalabov	    SYSCTL_MT7621_REV_E) {
834297717Ssgalabov		if (fdt_reset_assert_all(dev))
835297717Ssgalabov			return (ENXIO);
836297717Ssgalabov	} else {
837297717Ssgalabov		if (fdt_reset_deassert_all(dev))
838297717Ssgalabov			return (ENXIO);
839297717Ssgalabov	}
840297717Ssgalabov
841297717Ssgalabov	if (fdt_clock_enable_all(dev))
842297717Ssgalabov		return (ENXIO);
843297717Ssgalabov
844297717Ssgalabov	return (0);
845297717Ssgalabov}
846297717Ssgalabov
847297717Ssgalabovstatic int
848297717Ssgalabovmtk_pcie_phy_stop(device_t dev)
849297717Ssgalabov{
850297717Ssgalabov	struct mtk_pci_softc *sc = device_get_softc(dev);
851297717Ssgalabov
852297717Ssgalabov	if (sc->socid == MTK_SOC_MT7621 &&
853297717Ssgalabov	    (mtk_sysctl_get(SYSCTL_REVID) & SYSCTL_REVID_MASK) !=
854297717Ssgalabov	    SYSCTL_MT7621_REV_E) {
855297717Ssgalabov		if (fdt_reset_deassert_all(dev))
856297717Ssgalabov			return (ENXIO);
857297717Ssgalabov	} else {
858297717Ssgalabov		if (fdt_reset_assert_all(dev))
859297717Ssgalabov			return (ENXIO);
860297717Ssgalabov	}
861297717Ssgalabov
862297717Ssgalabov	if (fdt_clock_disable_all(dev))
863297717Ssgalabov		return (ENXIO);
864297717Ssgalabov
865297717Ssgalabov	return (0);
866297717Ssgalabov}
867297717Ssgalabov
868297717Ssgalabov#define mtk_pcie_phy_set(_sc, _reg, _s, _n, _v)			\
869297717Ssgalabov	MT_WRITE32((_sc), (_reg), ((MT_READ32((_sc), (_reg)) &	\
870297717Ssgalabov	    (~(((1ull << (_n)) - 1) << (_s)))) | ((_v) << (_s))))
871297717Ssgalabov
872297717Ssgalabovstatic void
873297717Ssgalabovmtk_pcie_phy_mt7621_bypass_pipe_rst(struct mtk_pci_softc *sc, uint32_t off)
874297717Ssgalabov{
875297717Ssgalabov
876297717Ssgalabov	mtk_pcie_phy_set(sc, off + 0x002c, 12, 1, 1);
877297717Ssgalabov	mtk_pcie_phy_set(sc, off + 0x002c,  4, 1, 1);
878297717Ssgalabov	mtk_pcie_phy_set(sc, off + 0x012c, 12, 1, 1);
879297717Ssgalabov	mtk_pcie_phy_set(sc, off + 0x012c,  4, 1, 1);
880297717Ssgalabov	mtk_pcie_phy_set(sc, off + 0x102c, 12, 1, 1);
881297717Ssgalabov	mtk_pcie_phy_set(sc, off + 0x102c,  4, 1, 1);
882297717Ssgalabov}
883297717Ssgalabov
884297717Ssgalabovstatic void
885297717Ssgalabovmtk_pcie_phy_mt7621_setup_ssc(struct mtk_pci_softc *sc, uint32_t off)
886297717Ssgalabov{
887297717Ssgalabov	uint32_t xtal_sel;
888297717Ssgalabov
889297717Ssgalabov	xtal_sel = mtk_sysctl_get(SYSCTL_SYSCFG) >> 6;
890297717Ssgalabov	xtal_sel &= 0x7;
891297717Ssgalabov
892297717Ssgalabov	mtk_pcie_phy_set(sc, off + 0x400, 8, 1, 1);
893297717Ssgalabov	mtk_pcie_phy_set(sc, off + 0x400, 9, 2, 0);
894297717Ssgalabov	mtk_pcie_phy_set(sc, off + 0x000, 4, 1, 1);
895297717Ssgalabov	mtk_pcie_phy_set(sc, off + 0x100, 4, 1, 1);
896297717Ssgalabov	mtk_pcie_phy_set(sc, off + 0x000, 5, 1, 0);
897297717Ssgalabov	mtk_pcie_phy_set(sc, off + 0x100, 5, 1, 0);
898297717Ssgalabov
899297717Ssgalabov	if (xtal_sel <= 5 && xtal_sel >= 3) {
900297717Ssgalabov		mtk_pcie_phy_set(sc, off + 0x490,  6,  2, 1);
901297717Ssgalabov		mtk_pcie_phy_set(sc, off + 0x4a8,  0, 12, 0x1a);
902297717Ssgalabov		mtk_pcie_phy_set(sc, off + 0x4a8, 16, 12, 0x1a);
903297717Ssgalabov	} else {
904297717Ssgalabov		mtk_pcie_phy_set(sc, off + 0x490,  6,  2, 0);
905297717Ssgalabov		if (xtal_sel >= 6) {
906297717Ssgalabov			mtk_pcie_phy_set(sc, off + 0x4bc,  4,  2, 0x01);
907297717Ssgalabov			mtk_pcie_phy_set(sc, off + 0x49c,  0, 31, 0x18000000);
908297717Ssgalabov			mtk_pcie_phy_set(sc, off + 0x4a4,  0, 16, 0x18d);
909297717Ssgalabov			mtk_pcie_phy_set(sc, off + 0x4a8,  0, 12, 0x4a);
910297717Ssgalabov			mtk_pcie_phy_set(sc, off + 0x4a8, 16, 12, 0x4a);
911297717Ssgalabov			mtk_pcie_phy_set(sc, off + 0x4a8,  0, 12, 0x11);
912297717Ssgalabov			mtk_pcie_phy_set(sc, off + 0x4a8, 16, 12, 0x11);
913297717Ssgalabov		} else {
914297717Ssgalabov			mtk_pcie_phy_set(sc, off + 0x4a8,  0, 12, 0x1a);
915297717Ssgalabov			mtk_pcie_phy_set(sc, off + 0x4a8, 16, 12, 0x1a);
916297717Ssgalabov		}
917297717Ssgalabov	}
918297717Ssgalabov
919297717Ssgalabov	mtk_pcie_phy_set(sc, off + 0x4a0,  5, 1, 1);
920297717Ssgalabov	mtk_pcie_phy_set(sc, off + 0x490, 22, 2, 2);
921297717Ssgalabov	mtk_pcie_phy_set(sc, off + 0x490, 18, 4, 6);
922297717Ssgalabov	mtk_pcie_phy_set(sc, off + 0x490, 12, 4, 2);
923297717Ssgalabov	mtk_pcie_phy_set(sc, off + 0x490,  8, 4, 1);
924297717Ssgalabov	mtk_pcie_phy_set(sc, off + 0x4ac, 16, 3, 0);
925297717Ssgalabov	mtk_pcie_phy_set(sc, off + 0x490,  1, 3, 2);
926297717Ssgalabov
927297717Ssgalabov	if (xtal_sel <= 5 && xtal_sel >= 3) {
928297717Ssgalabov		mtk_pcie_phy_set(sc, off + 0x414, 6, 2, 1);
929297717Ssgalabov		mtk_pcie_phy_set(sc, off + 0x414, 5, 1, 1);
930297717Ssgalabov	}
931297717Ssgalabov
932297717Ssgalabov	mtk_pcie_phy_set(sc, off + 0x414, 28, 2, 1);
933297717Ssgalabov	mtk_pcie_phy_set(sc, off + 0x040, 17, 4, 7);
934297717Ssgalabov	mtk_pcie_phy_set(sc, off + 0x040, 16, 1, 1);
935297717Ssgalabov	mtk_pcie_phy_set(sc, off + 0x140, 17, 4, 7);
936297717Ssgalabov	mtk_pcie_phy_set(sc, off + 0x140, 16, 1, 1);
937297717Ssgalabov
938297717Ssgalabov	mtk_pcie_phy_set(sc, off + 0x000,  5, 1, 1);
939297717Ssgalabov	mtk_pcie_phy_set(sc, off + 0x100,  5, 1, 1);
940297717Ssgalabov	mtk_pcie_phy_set(sc, off + 0x000,  4, 1, 0);
941297717Ssgalabov	mtk_pcie_phy_set(sc, off + 0x100,  4, 1, 0);
942297717Ssgalabov}
943297717Ssgalabov
944297717Ssgalabov/* XXX: ugly, we need to fix this at some point */
945297717Ssgalabov#define MT7621_GPIO_CTRL0	*((volatile uint32_t *)0xbe000600)
946297717Ssgalabov#define MT7621_GPIO_DATA0	*((volatile uint32_t *)0xbe000620)
947297717Ssgalabov
948297717Ssgalabov#define mtk_gpio_clr_set(_reg, _clr, _set)		\
949297717Ssgalabov	do {						\
950297717Ssgalabov		(_reg) = ((_reg) & (_clr)) | (_set);	\
951297717Ssgalabov	} while (0)
952297717Ssgalabov
953297717Ssgalabovstatic int
954297717Ssgalabovmtk_pcie_phy_mt7621_init(device_t dev)
955297717Ssgalabov{
956297717Ssgalabov	struct mtk_pci_softc *sc = device_get_softc(dev);
957297717Ssgalabov
958297717Ssgalabov	/* First off, stop the PHY */
959297717Ssgalabov	if (mtk_pcie_phy_stop(dev))
960297717Ssgalabov		return (ENXIO);
961297717Ssgalabov
962297717Ssgalabov	/* PCIe resets are GPIO pins */
963297717Ssgalabov	mtk_sysctl_clr_set(SYSCTL_GPIOMODE, MT7621_PERST_GPIO_MODE |
964297717Ssgalabov	    MT7621_UARTL3_GPIO_MODE, MT7621_PERST_GPIO | MT7621_UARTL3_GPIO);
965297717Ssgalabov
966297717Ssgalabov	/* Set GPIO pins as outputs */
967297717Ssgalabov	mtk_gpio_clr_set(MT7621_GPIO_CTRL0, 0, MT7621_PCIE_RST);
968297717Ssgalabov
969297717Ssgalabov	/* Assert resets to PCIe devices */
970297717Ssgalabov	mtk_gpio_clr_set(MT7621_GPIO_DATA0, MT7621_PCIE_RST, 0);
971297717Ssgalabov
972297717Ssgalabov	/* Give everything a chance to sink in */
973297717Ssgalabov	DELAY(100000);
974297717Ssgalabov
975297717Ssgalabov	/* Now start the PHY again */
976297717Ssgalabov	if (mtk_pcie_phy_start(dev))
977297717Ssgalabov		return (ENXIO);
978297717Ssgalabov
979297717Ssgalabov	/* Wait for things to settle */
980297717Ssgalabov	DELAY(100000);
981297717Ssgalabov
982297717Ssgalabov	/* Only apply below to REV-E hardware */
983297717Ssgalabov	if ((mtk_sysctl_get(SYSCTL_REVID) & SYSCTL_REVID_MASK) ==
984297717Ssgalabov	    SYSCTL_MT7621_REV_E)
985297717Ssgalabov		mtk_pcie_phy_mt7621_bypass_pipe_rst(sc, 0x9000);
986297717Ssgalabov
987297717Ssgalabov	/* Setup PCIe ports 0 and 1 */
988297717Ssgalabov	mtk_pcie_phy_mt7621_setup_ssc(sc, 0x9000);
989297717Ssgalabov	/* Setup PCIe port 2 */
990297717Ssgalabov	mtk_pcie_phy_mt7621_setup_ssc(sc, 0xa000);
991297717Ssgalabov
992297717Ssgalabov	/* Deassert resets to PCIe devices */
993297717Ssgalabov	mtk_gpio_clr_set(MT7621_GPIO_DATA0, 0, MT7621_PCIE_RST);
994297717Ssgalabov
995297717Ssgalabov	/* Set number of slots supported */
996297717Ssgalabov	sc->num_slots = 3;
997297717Ssgalabov
998297717Ssgalabov	/* Give it a chance to sink in */
999297717Ssgalabov	DELAY(100000);
1000297717Ssgalabov
1001297717Ssgalabov	return (0);
1002297717Ssgalabov}
1003297717Ssgalabov
1004297717Ssgalabovstatic void
1005297717Ssgalabovmtk_pcie_phy_mt7628_setup(struct mtk_pci_softc *sc, uint32_t off)
1006297717Ssgalabov{
1007297717Ssgalabov	uint32_t xtal_sel;
1008297717Ssgalabov
1009297717Ssgalabov	xtal_sel = mtk_sysctl_get(SYSCTL_SYSCFG) >> 6;
1010297717Ssgalabov	xtal_sel &= 0x1;
1011297717Ssgalabov
1012297717Ssgalabov	mtk_pcie_phy_set(sc, off + 0x400,  8, 1, 1);
1013297717Ssgalabov	mtk_pcie_phy_set(sc, off + 0x400,  9, 2, 0);
1014297717Ssgalabov	mtk_pcie_phy_set(sc, off + 0x000,  4, 1, 1);
1015297717Ssgalabov	mtk_pcie_phy_set(sc, off + 0x000,  5, 1, 0);
1016297717Ssgalabov	mtk_pcie_phy_set(sc, off + 0x4ac, 16, 3, 3);
1017297717Ssgalabov
1018297717Ssgalabov	if (xtal_sel == 1) {
1019297717Ssgalabov		mtk_pcie_phy_set(sc, off + 0x4bc, 24,  8, 0x7d);
1020297717Ssgalabov		mtk_pcie_phy_set(sc, off + 0x490, 12,  4, 0x08);
1021297717Ssgalabov		mtk_pcie_phy_set(sc, off + 0x490,  6,  2, 0x01);
1022297717Ssgalabov		mtk_pcie_phy_set(sc, off + 0x4c0,  0, 32, 0x1f400000);
1023297717Ssgalabov		mtk_pcie_phy_set(sc, off + 0x4a4,  0, 16, 0x013d);
1024297717Ssgalabov		mtk_pcie_phy_set(sc, off + 0x4a8, 16, 16, 0x74);
1025297717Ssgalabov		mtk_pcie_phy_set(sc, off + 0x4a8,  0, 16, 0x74);
1026297717Ssgalabov	} else {
1027297717Ssgalabov		mtk_pcie_phy_set(sc, off + 0x4bc, 24,  8, 0x64);
1028297717Ssgalabov		mtk_pcie_phy_set(sc, off + 0x490, 12,  4, 0x0a);
1029297717Ssgalabov		mtk_pcie_phy_set(sc, off + 0x490,  6,  2, 0x00);
1030297717Ssgalabov		mtk_pcie_phy_set(sc, off + 0x4c0,  0, 32, 0x19000000);
1031297717Ssgalabov		mtk_pcie_phy_set(sc, off + 0x4a4,  0, 16, 0x018d);
1032297717Ssgalabov		mtk_pcie_phy_set(sc, off + 0x4a8, 16, 16, 0x4a);
1033297717Ssgalabov		mtk_pcie_phy_set(sc, off + 0x4a8,  0, 16, 0x4a);
1034297717Ssgalabov	}
1035297717Ssgalabov
1036297717Ssgalabov	mtk_pcie_phy_set(sc, off + 0x498, 0, 8, 5);
1037297717Ssgalabov	mtk_pcie_phy_set(sc, off + 0x000, 5, 1, 1);
1038297717Ssgalabov	mtk_pcie_phy_set(sc, off + 0x000, 4, 1, 0);
1039297717Ssgalabov}
1040297717Ssgalabov
1041297717Ssgalabovstatic int
1042297717Ssgalabovmtk_pcie_phy_mt7628_init(device_t dev)
1043297717Ssgalabov{
1044297717Ssgalabov	struct mtk_pci_softc *sc = device_get_softc(dev);
1045297717Ssgalabov
1046297717Ssgalabov	/* Set PCIe reset to normal mode */
1047297717Ssgalabov	mtk_sysctl_clr_set(SYSCTL_GPIOMODE, MT7628_PERST_GPIO_MODE,
1048297717Ssgalabov	    MT7628_PERST);
1049297717Ssgalabov
1050297717Ssgalabov	/* Start the PHY */
1051297717Ssgalabov	if (mtk_pcie_phy_start(dev))
1052297717Ssgalabov		return (ENXIO);
1053297717Ssgalabov
1054297717Ssgalabov	/* Give it a chance to sink in */
1055297717Ssgalabov	DELAY(100000);
1056297717Ssgalabov
1057297717Ssgalabov	/* Setup the PHY */
1058297717Ssgalabov	mtk_pcie_phy_mt7628_setup(sc, 0x9000);
1059297717Ssgalabov
1060297717Ssgalabov	/* Deassert PCIe device reset */
1061297717Ssgalabov	MT_CLR_SET32(sc, MTK_PCI_PCICFG, MTK_PCI_RESET, 0);
1062297717Ssgalabov
1063297717Ssgalabov	/* Set number of slots supported */
1064297717Ssgalabov	sc->num_slots = 1;
1065297717Ssgalabov
1066297717Ssgalabov	return (0);
1067297717Ssgalabov}
1068297717Ssgalabov
1069297717Ssgalabovstatic int
1070297717Ssgalabovmtk_pcie_phy_mt7620_wait_busy(struct mtk_pci_softc *sc)
1071297717Ssgalabov{
1072297717Ssgalabov	uint32_t reg_value, retry;
1073297717Ssgalabov
1074297717Ssgalabov	reg_value = retry = 0;
1075297717Ssgalabov
1076297717Ssgalabov	while (retry++ < MT7620_MAX_RETRIES) {
1077297717Ssgalabov		reg_value = MT_READ32(sc, MT7620_PCIE_PHY_CFG);
1078297717Ssgalabov		if (reg_value & PHY_BUSY)
1079297717Ssgalabov			DELAY(100000);
1080297717Ssgalabov		else
1081297717Ssgalabov			break;
1082297717Ssgalabov	}
1083297717Ssgalabov
1084297717Ssgalabov	if (retry >= MT7620_MAX_RETRIES)
1085297717Ssgalabov		return (ENXIO);
1086297717Ssgalabov
1087297717Ssgalabov	return (0);
1088297717Ssgalabov}
1089297717Ssgalabov
1090297717Ssgalabovstatic int
1091297717Ssgalabovmtk_pcie_phy_mt7620_set(struct mtk_pci_softc *sc, uint32_t reg,
1092297717Ssgalabov    uint32_t val)
1093297717Ssgalabov{
1094297717Ssgalabov	uint32_t reg_val;
1095297717Ssgalabov
1096297717Ssgalabov	if (mtk_pcie_phy_mt7620_wait_busy(sc))
1097297717Ssgalabov		return (ENXIO);
1098297717Ssgalabov
1099297717Ssgalabov	reg_val = PHY_MODE_WRITE | ((reg & 0xff) << PHY_ADDR_OFFSET) |
1100297717Ssgalabov	    (val & 0xff);
1101297717Ssgalabov	MT_WRITE32(sc, MT7620_PCIE_PHY_CFG, reg_val);
1102297717Ssgalabov	DELAY(1000);
1103297717Ssgalabov
1104297717Ssgalabov	if (mtk_pcie_phy_mt7620_wait_busy(sc))
1105297717Ssgalabov		return (ENXIO);
1106297717Ssgalabov
1107297717Ssgalabov	return (0);
1108297717Ssgalabov}
1109297717Ssgalabov
1110297717Ssgalabovstatic int
1111297717Ssgalabovmtk_pcie_phy_mt7620_init(device_t dev)
1112297717Ssgalabov{
1113297717Ssgalabov	struct mtk_pci_softc *sc = device_get_softc(dev);
1114297717Ssgalabov
1115297717Ssgalabov	/*
1116297717Ssgalabov	 * The below sets the PCIe PHY to bypass the PCIe DLL and enables
1117297717Ssgalabov	 * "elastic buffer control", whatever that may be...
1118297717Ssgalabov	 */
1119297717Ssgalabov	if (mtk_pcie_phy_mt7620_set(sc, 0x00, 0x80) ||
1120297717Ssgalabov	    mtk_pcie_phy_mt7620_set(sc, 0x01, 0x04) ||
1121297717Ssgalabov	    mtk_pcie_phy_mt7620_set(sc, 0x68, 0x84))
1122297717Ssgalabov		return (ENXIO);
1123297717Ssgalabov
1124297717Ssgalabov	/* Stop PCIe */
1125297717Ssgalabov	if (mtk_pcie_phy_stop(dev))
1126297717Ssgalabov		return (ENXIO);
1127297717Ssgalabov
1128297717Ssgalabov	/* Restore PPLL to a sane state before going on */
1129297717Ssgalabov	mtk_sysctl_clr_set(MT7620_PPLL_DRV, LC_CKDRVPD, PDRV_SW_SET);
1130297717Ssgalabov
1131297717Ssgalabov	/* No PCIe on the MT7620N */
1132297717Ssgalabov	if (!(mtk_sysctl_get(SYSCTL_REVID) & MT7620_PKG_BGA)) {
1133297717Ssgalabov		device_printf(dev, "PCIe disabled for MT7620N\n");
1134297717Ssgalabov		mtk_sysctl_clr_set(MT7620_PPLL_CFG0, 0, PPLL_SW_SET);
1135297717Ssgalabov		mtk_sysctl_clr_set(MT7620_PPLL_CFG1, 0, PPLL_PD);
1136297717Ssgalabov		return (ENXIO);
1137297717Ssgalabov	}
1138297717Ssgalabov
1139297717Ssgalabov	/* PCIe device reset pin is in normal mode */
1140297717Ssgalabov	mtk_sysctl_clr_set(SYSCTL_GPIOMODE, MT7620_PERST_GPIO_MODE,
1141297717Ssgalabov	    MT7620_PERST);
1142297717Ssgalabov
1143297717Ssgalabov	/* Enable PCIe now */
1144297717Ssgalabov	if (mtk_pcie_phy_start(dev))
1145297717Ssgalabov		return (ENXIO);
1146297717Ssgalabov
1147297717Ssgalabov	/* Give it a chance to sink in */
1148297717Ssgalabov	DELAY(100000);
1149297717Ssgalabov
1150297717Ssgalabov	/* If PLL is not locked - bail */
1151297717Ssgalabov	if (!(mtk_sysctl_get(MT7620_PPLL_CFG1) & PPLL_LOCKED)) {
1152297717Ssgalabov		device_printf(dev, "no PPLL not lock\n");
1153297717Ssgalabov		mtk_pcie_phy_stop(dev);
1154297717Ssgalabov		return (ENXIO);
1155297717Ssgalabov	}
1156297717Ssgalabov
1157297717Ssgalabov	/* Configure PCIe PLL */
1158297717Ssgalabov	mtk_sysctl_clr_set(MT7620_PPLL_DRV, LC_CKDRVOHZ | LC_CKDRVHZ,
1159297717Ssgalabov	    LC_CKDRVPD | PDRV_SW_SET);
1160297717Ssgalabov
1161297717Ssgalabov	/* and give it a chance to settle */
1162297717Ssgalabov	DELAY(100000);
1163297717Ssgalabov
1164297717Ssgalabov	/* Deassert PCIe device reset */
1165297717Ssgalabov	MT_CLR_SET32(sc, MTK_PCI_PCICFG, MTK_PCI_RESET, 0);
1166297717Ssgalabov
1167297717Ssgalabov	/* MT7620 supports one PCIe slot */
1168297717Ssgalabov	sc->num_slots = 1;
1169297717Ssgalabov
1170297717Ssgalabov	return (0);
1171297717Ssgalabov}
1172297717Ssgalabov
1173297717Ssgalabovstatic int
1174297717Ssgalabovmtk_pcie_phy_rt3883_init(device_t dev)
1175297717Ssgalabov{
1176297717Ssgalabov	struct mtk_pci_softc *sc = device_get_softc(dev);
1177297717Ssgalabov
1178297717Ssgalabov	/* Enable PCI host mode and PCIe RC mode */
1179297717Ssgalabov	mtk_sysctl_clr_set(SYSCTL_SYSCFG1, 0, RT3883_PCI_HOST_MODE |
1180297717Ssgalabov	    RT3883_PCIE_RC_MODE);
1181297717Ssgalabov
1182297717Ssgalabov	/* Enable PCIe PHY */
1183297717Ssgalabov	if (mtk_pcie_phy_start(dev))
1184297717Ssgalabov		return (ENXIO);
1185297717Ssgalabov
1186297717Ssgalabov	/* Disable PCI, we only support PCIe for now */
1187297717Ssgalabov	mtk_sysctl_clr_set(SYSCTL_RSTCTRL, 0, RT3883_PCI_RST);
1188297717Ssgalabov	mtk_sysctl_clr_set(SYSCTL_CLKCFG1, RT3883_PCI_CLK, 0);
1189297717Ssgalabov
1190297717Ssgalabov	/* Give things a chance to sink in */
1191297717Ssgalabov	DELAY(500000);
1192297717Ssgalabov
1193297717Ssgalabov	/* Set PCIe port number to 0 and lift PCIe reset */
1194297717Ssgalabov	MT_WRITE32(sc, MTK_PCI_PCICFG, 0);
1195297717Ssgalabov
1196297717Ssgalabov	/* Configure PCI Arbiter */
1197297717Ssgalabov	MT_WRITE32(sc, MTK_PCI_ARBCTL, 0x79);
1198297717Ssgalabov
1199297717Ssgalabov	/* We have a single PCIe slot */
1200297717Ssgalabov	sc->num_slots = 1;
1201297717Ssgalabov
1202297717Ssgalabov	return (0);
1203297717Ssgalabov}
1204297717Ssgalabov
1205297717Ssgalabovstatic void
1206297717Ssgalabovmtk_pcie_phy_setup_slots(device_t dev)
1207297717Ssgalabov{
1208297717Ssgalabov	struct mtk_pci_softc *sc = device_get_softc(dev);
1209297717Ssgalabov	uint32_t bar0_val, val;
1210297717Ssgalabov	int i;
1211297717Ssgalabov
1212297717Ssgalabov	/* Disable all PCIe interrupts */
1213297717Ssgalabov	MT_WRITE32(sc, MTK_PCI_PCIENA, 0);
1214297717Ssgalabov
1215297717Ssgalabov	/* Default bar0_val is 64M, enabled */
1216297717Ssgalabov	bar0_val = 0x03FF0001;
1217297717Ssgalabov
1218297717Ssgalabov	/* But we override it to 2G, enabled for some SoCs */
1219297717Ssgalabov	if (sc->socid == MTK_SOC_MT7620A || sc->socid == MTK_SOC_MT7628 ||
1220297717Ssgalabov	    sc->socid == MTK_SOC_MT7688 || sc->socid == MTK_SOC_MT7621)
1221297717Ssgalabov		bar0_val = 0x7FFF0001;
1222297717Ssgalabov
1223297717Ssgalabov	/* We still don't know which slots have linked up */
1224297717Ssgalabov	sc->pcie_link_status = 0;
1225297717Ssgalabov
1226297717Ssgalabov	/* XXX: I am not sure if this delay is really necessary */
1227297717Ssgalabov	DELAY(500000);
1228297717Ssgalabov
1229297717Ssgalabov	/*
1230297717Ssgalabov	 * See which slots have links and mark them.
1231297717Ssgalabov	 * Set up all slots' BARs and make them look like PCIe bridges.
1232297717Ssgalabov	 */
1233297717Ssgalabov	for (i = 0; i < sc->num_slots; i++) {
1234297717Ssgalabov		/* If slot has link - mark it */
1235297717Ssgalabov		if (MT_READ32(sc, MTK_PCIE_STATUS(i)) & 1)
1236297717Ssgalabov			sc->pcie_link_status |= (1<<i);
1237297850Ssgalabov		else
1238297850Ssgalabov			continue;
1239297717Ssgalabov
1240297717Ssgalabov		/* Generic slot configuration follows */
1241297717Ssgalabov
1242297717Ssgalabov		/* We enable BAR0 */
1243297717Ssgalabov		MT_WRITE32(sc, MTK_PCIE_BAR0SETUP(i), bar0_val);
1244297717Ssgalabov		/* and disable BAR1 */
1245297717Ssgalabov		MT_WRITE32(sc, MTK_PCIE_BAR1SETUP(i), 0);
1246297717Ssgalabov		/* Internal memory base has no offset */
1247297717Ssgalabov		MT_WRITE32(sc, MTK_PCIE_IMBASEBAR0(i), 0);
1248297717Ssgalabov		/* We're a PCIe bridge */
1249297717Ssgalabov		MT_WRITE32(sc, MTK_PCIE_CLASS(i), 0x06040001);
1250297717Ssgalabov
1251297717Ssgalabov		val = mtk_pci_read_config(dev, 0, i, 0, 0x4, 4);
1252297717Ssgalabov		mtk_pci_write_config(dev, 0, i, 0, 0x4, val | 0x4, 4);
1253297717Ssgalabov		val = mtk_pci_read_config(dev, 0, i, 0, 0x70c, 4);
1254297717Ssgalabov		val &= ~(0xff << 8);
1255297717Ssgalabov		val |= (0x50 << 8);
1256297850Ssgalabov		mtk_pci_write_config(dev, 0, i, 0, 0x70c, val, 4);
1257297850Ssgalabov
1258297850Ssgalabov		mtk_pci_write_config(dev, 0, i, 0, PCIR_IOBASEL_1, 0xff, 1);
1259297850Ssgalabov		mtk_pci_write_config(dev, 0, i, 0, PCIR_IOBASEH_1, 0xffff, 2);
1260297850Ssgalabov		mtk_pci_write_config(dev, 0, i, 0, PCIR_IOLIMITL_1, 0, 1);
1261297850Ssgalabov		mtk_pci_write_config(dev, 0, i, 0, PCIR_IOLIMITH_1, 0, 2);
1262297850Ssgalabov		mtk_pci_write_config(dev, 0, i, 0, PCIR_MEMBASE_1, 0xffff, 2);
1263297850Ssgalabov		mtk_pci_write_config(dev, 0, i, 0, PCIR_MEMLIMIT_1, 0, 2);
1264297850Ssgalabov		mtk_pci_write_config(dev, 0, i, 0, PCIR_PMBASEL_1, 0xffff, 2);
1265297850Ssgalabov		mtk_pci_write_config(dev, 0, i, 0, PCIR_PMBASEH_1, 0xffffffff,
1266297850Ssgalabov		    4);
1267297850Ssgalabov		mtk_pci_write_config(dev, 0, i, 0, PCIR_PMLIMITL_1, 0, 2);
1268297850Ssgalabov		mtk_pci_write_config(dev, 0, i, 0, PCIR_PMLIMITH_1, 0, 4);
1269297717Ssgalabov	}
1270297717Ssgalabov}
1271