xref: /freebsd/sys/arm/broadcom/bcm2835/bcm2838_pci.c (revision 82d4dc0621c92e3c05a86013eec35afbdec057a5)
1eed8b80fSAndrew Turner /*-
2eed8b80fSAndrew Turner  * SPDX-License-Identifier: ISC
3eed8b80fSAndrew Turner  *
4eed8b80fSAndrew Turner  * Copyright (c) 2020 Dr Robert Harvey Crowston <crowston@protonmail.com>
5eed8b80fSAndrew Turner  *
6eed8b80fSAndrew Turner  * Permission to use, copy, modify, and distribute this software for any
7eed8b80fSAndrew Turner  * purpose with or without fee is hereby granted, provided that the above
8eed8b80fSAndrew Turner  * copyright notice and this permission notice appear in all copies.
9eed8b80fSAndrew Turner  *
10eed8b80fSAndrew Turner  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11eed8b80fSAndrew Turner  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12eed8b80fSAndrew Turner  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13eed8b80fSAndrew Turner  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14eed8b80fSAndrew Turner  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15eed8b80fSAndrew Turner  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16eed8b80fSAndrew Turner  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17eed8b80fSAndrew Turner  *
18eed8b80fSAndrew Turner  *
19eed8b80fSAndrew Turner  * $FreeBSD$
20eed8b80fSAndrew Turner  *
21eed8b80fSAndrew Turner  */
22eed8b80fSAndrew Turner 
23eed8b80fSAndrew Turner /*
24eed8b80fSAndrew Turner  * BCM2838-compatible PCI-express controller.
25eed8b80fSAndrew Turner  *
26eed8b80fSAndrew Turner  * Broadcom likes to give the same chip lots of different names. The name of
27eed8b80fSAndrew Turner  * this driver is taken from the Raspberry Pi 4 Broadcom 2838 chip.
28eed8b80fSAndrew Turner  */
29eed8b80fSAndrew Turner 
30eed8b80fSAndrew Turner #include <sys/cdefs.h>
31eed8b80fSAndrew Turner __FBSDID("$FreeBSD$");
32eed8b80fSAndrew Turner 
33eed8b80fSAndrew Turner #include <sys/param.h>
34eed8b80fSAndrew Turner #include <sys/systm.h>
35eed8b80fSAndrew Turner #include <sys/endian.h>
36eed8b80fSAndrew Turner #include <sys/kernel.h>
37eed8b80fSAndrew Turner #include <sys/module.h>
38eed8b80fSAndrew Turner #include <sys/bus.h>
39eed8b80fSAndrew Turner #include <sys/proc.h>
40eed8b80fSAndrew Turner #include <sys/rman.h>
41eed8b80fSAndrew Turner #include <sys/intr.h>
42eed8b80fSAndrew Turner #include <sys/mutex.h>
43eed8b80fSAndrew Turner 
44eed8b80fSAndrew Turner #include <dev/ofw/openfirm.h>
45eed8b80fSAndrew Turner #include <dev/ofw/ofw_bus.h>
46eed8b80fSAndrew Turner #include <dev/ofw/ofw_bus_subr.h>
47eed8b80fSAndrew Turner 
48eed8b80fSAndrew Turner #include <dev/pci/pci_host_generic.h>
49eed8b80fSAndrew Turner #include <dev/pci/pci_host_generic_fdt.h>
50eed8b80fSAndrew Turner #include <dev/pci/pcivar.h>
51eed8b80fSAndrew Turner #include <dev/pci/pcireg.h>
52eed8b80fSAndrew Turner #include <dev/pci/pcib_private.h>
53eed8b80fSAndrew Turner 
54eed8b80fSAndrew Turner #include <machine/bus.h>
55eed8b80fSAndrew Turner #include <machine/intr.h>
56eed8b80fSAndrew Turner 
57eed8b80fSAndrew Turner #include "pcib_if.h"
58eed8b80fSAndrew Turner #include "msi_if.h"
59eed8b80fSAndrew Turner 
60eed8b80fSAndrew Turner #define PCI_ID_VAL3		0x43c
61eed8b80fSAndrew Turner #define CLASS_SHIFT		0x10
62eed8b80fSAndrew Turner #define SUBCLASS_SHIFT		0x8
63eed8b80fSAndrew Turner 
64eed8b80fSAndrew Turner #define REG_CONTROLLER_HW_REV			0x406c
65eed8b80fSAndrew Turner #define REG_BRIDGE_CTRL				0x9210
66eed8b80fSAndrew Turner #define BRIDGE_DISABLE_FLAG	0x1
67eed8b80fSAndrew Turner #define BRIDGE_RESET_FLAG	0x2
68eed8b80fSAndrew Turner #define REG_BRIDGE_SERDES_MODE			0x4204
69ac89220bSMike Karels #define REG_DMA_CONFIG				0x4008
70ac89220bSMike Karels #define REG_DMA_WINDOW_LOW			0x4034
71ac89220bSMike Karels #define REG_DMA_WINDOW_HIGH			0x4038
72ac89220bSMike Karels #define REG_DMA_WINDOW_1			0x403c
73eed8b80fSAndrew Turner #define REG_BRIDGE_GISB_WINDOW			0x402c
74eed8b80fSAndrew Turner #define REG_BRIDGE_STATE			0x4068
75eed8b80fSAndrew Turner #define REG_BRIDGE_LINK_STATE			0x00bc
76ac89220bSMike Karels #define REG_BUS_WINDOW_LOW			0x400c
77ac89220bSMike Karels #define REG_BUS_WINDOW_HIGH			0x4010
78ac89220bSMike Karels #define REG_CPU_WINDOW_LOW			0x4070
79ac89220bSMike Karels #define REG_CPU_WINDOW_START_HIGH		0x4080
80ac89220bSMike Karels #define REG_CPU_WINDOW_END_HIGH			0x4084
81eed8b80fSAndrew Turner 
82eed8b80fSAndrew Turner #define REG_MSI_ADDR_LOW			0x4044
83eed8b80fSAndrew Turner #define REG_MSI_ADDR_HIGH			0x4048
84eed8b80fSAndrew Turner #define REG_MSI_CONFIG				0x404c
85eed8b80fSAndrew Turner #define REG_MSI_CLR				0x4508
86eed8b80fSAndrew Turner #define REG_MSI_MASK_CLR			0x4514
87eed8b80fSAndrew Turner #define REG_MSI_RAISED				0x4500
88eed8b80fSAndrew Turner #define REG_MSI_EOI				0x4060
89eed8b80fSAndrew Turner #define NUM_MSI			32
90eed8b80fSAndrew Turner 
91eed8b80fSAndrew Turner #define REG_EP_CONFIG_CHOICE			0x9000
92eed8b80fSAndrew Turner #define REG_EP_CONFIG_DATA			0x8000
93eed8b80fSAndrew Turner 
94eed8b80fSAndrew Turner /*
95ac89220bSMike Karels  * The system memory controller can address up to 16 GiB of physical memory
96ac89220bSMike Karels  * (although at time of writing the largest memory size available for purchase
97ac89220bSMike Karels  * is 8 GiB). However, the system DMA controller is capable of accessing only a
98ac89220bSMike Karels  * limited portion of the address space. Worse, the PCI-e controller has further
99ac89220bSMike Karels  * constraints for DMA, and those limitations are not wholly clear to the
100ac89220bSMike Karels  * author. NetBSD and Linux allow DMA on the lower 3 GiB of the physical memory,
101ac89220bSMike Karels  * but experimentation shows DMA performed above 960 MiB results in data
102ac89220bSMike Karels  * corruption with this driver. The limit of 960 MiB is taken from OpenBSD, but
103ac89220bSMike Karels  * apparently that value was chosen for satisfying a constraint of an unrelated
104ac89220bSMike Karels  * peripheral.
105ac89220bSMike Karels  *
106ac89220bSMike Karels  * Whatever the true maximum address, 960 MiB works.
107eed8b80fSAndrew Turner  */
108ac89220bSMike Karels #define DMA_HIGH_LIMIT			0x3c000000
109ac89220bSMike Karels #define MAX_MEMORY_LOG2			0x21
110ac89220bSMike Karels #define REG_VALUE_DMA_WINDOW_LOW	(MAX_MEMORY_LOG2 - 0xf)
111ac89220bSMike Karels #define REG_VALUE_DMA_WINDOW_HIGH	0x0
112ac89220bSMike Karels #define DMA_WINDOW_ENABLE		0x3000
113ac89220bSMike Karels #define REG_VALUE_DMA_WINDOW_CONFIG	\
114ac89220bSMike Karels     (((MAX_MEMORY_LOG2 - 0xf) << 0x1b) | DMA_WINDOW_ENABLE)
115ac89220bSMike Karels 
116eed8b80fSAndrew Turner #define REG_VALUE_MSI_CONFIG	0xffe06540
117eed8b80fSAndrew Turner 
118eed8b80fSAndrew Turner struct bcm_pcib_irqsrc {
119eed8b80fSAndrew Turner 	struct intr_irqsrc	isrc;
120eed8b80fSAndrew Turner 	u_int			irq;
121eed8b80fSAndrew Turner 	bool			allocated;
122eed8b80fSAndrew Turner };
123eed8b80fSAndrew Turner 
124eed8b80fSAndrew Turner struct bcm_pcib_softc {
125eed8b80fSAndrew Turner 	struct generic_pcie_fdt_softc	base;
126eed8b80fSAndrew Turner 	device_t			dev;
127ac89220bSMike Karels 	bus_dma_tag_t			dmat;
128eed8b80fSAndrew Turner 	struct mtx			config_mtx;
129eed8b80fSAndrew Turner 	struct mtx			msi_mtx;
130eed8b80fSAndrew Turner 	struct resource 		*msi_irq_res;
131eed8b80fSAndrew Turner 	void				*msi_intr_cookie;
132eed8b80fSAndrew Turner 	struct bcm_pcib_irqsrc		*msi_isrcs;
133eed8b80fSAndrew Turner 	pci_addr_t			msi_addr;
134eed8b80fSAndrew Turner };
135eed8b80fSAndrew Turner 
136eed8b80fSAndrew Turner static struct ofw_compat_data compat_data[] = {
137eed8b80fSAndrew Turner 	{"brcm,bcm2711-pcie",			1},
138eed8b80fSAndrew Turner 	{"brcm,bcm7211-pcie",			1},
139eed8b80fSAndrew Turner 	{"brcm,bcm7445-pcie",			1},
140eed8b80fSAndrew Turner 	{NULL,					0}
141eed8b80fSAndrew Turner };
142eed8b80fSAndrew Turner 
143eed8b80fSAndrew Turner static int
144eed8b80fSAndrew Turner bcm_pcib_probe(device_t dev)
145eed8b80fSAndrew Turner {
146eed8b80fSAndrew Turner 
147eed8b80fSAndrew Turner 	if (!ofw_bus_status_okay(dev))
148eed8b80fSAndrew Turner 		return (ENXIO);
149eed8b80fSAndrew Turner 
150eed8b80fSAndrew Turner 	if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data)
151eed8b80fSAndrew Turner 		return (ENXIO);
152eed8b80fSAndrew Turner 
153eed8b80fSAndrew Turner 	device_set_desc(dev,
154eed8b80fSAndrew Turner 	    "BCM2838-compatible PCI-express controller");
155eed8b80fSAndrew Turner 	return (BUS_PROBE_DEFAULT);
156eed8b80fSAndrew Turner }
157eed8b80fSAndrew Turner 
158ac89220bSMike Karels static bus_dma_tag_t
159ac89220bSMike Karels bcm_pcib_get_dma_tag(device_t dev, device_t child)
160ac89220bSMike Karels {
161ac89220bSMike Karels 	struct bcm_pcib_softc *sc;
162ac89220bSMike Karels 
163ac89220bSMike Karels 	sc = device_get_softc(dev);
164ac89220bSMike Karels 	return (sc->dmat);
165ac89220bSMike Karels }
166ac89220bSMike Karels 
167eed8b80fSAndrew Turner static void
168eed8b80fSAndrew Turner bcm_pcib_set_reg(struct bcm_pcib_softc *sc, uint32_t reg, uint32_t val)
169eed8b80fSAndrew Turner {
170eed8b80fSAndrew Turner 
171eed8b80fSAndrew Turner 	bus_space_write_4(sc->base.base.bst, sc->base.base.bsh, reg,
172eed8b80fSAndrew Turner 	    htole32(val));
173eed8b80fSAndrew Turner }
174eed8b80fSAndrew Turner 
175eed8b80fSAndrew Turner static uint32_t
176eed8b80fSAndrew Turner bcm_pcib_read_reg(struct bcm_pcib_softc *sc, uint32_t reg)
177eed8b80fSAndrew Turner {
178eed8b80fSAndrew Turner 
179eed8b80fSAndrew Turner 	return (le32toh(bus_space_read_4(sc->base.base.bst, sc->base.base.bsh,
180eed8b80fSAndrew Turner 	    reg)));
181eed8b80fSAndrew Turner }
182eed8b80fSAndrew Turner 
183eed8b80fSAndrew Turner static void
184eed8b80fSAndrew Turner bcm_pcib_reset_controller(struct bcm_pcib_softc *sc)
185eed8b80fSAndrew Turner {
186eed8b80fSAndrew Turner 	uint32_t val;
187eed8b80fSAndrew Turner 
188eed8b80fSAndrew Turner 	val = bcm_pcib_read_reg(sc, REG_BRIDGE_CTRL);
189eed8b80fSAndrew Turner 	val = val | BRIDGE_RESET_FLAG | BRIDGE_DISABLE_FLAG;
190eed8b80fSAndrew Turner 	bcm_pcib_set_reg(sc, REG_BRIDGE_CTRL, val);
191eed8b80fSAndrew Turner 
192eed8b80fSAndrew Turner 	DELAY(100);
193eed8b80fSAndrew Turner 
194eed8b80fSAndrew Turner 	val = bcm_pcib_read_reg(sc, REG_BRIDGE_CTRL);
195eed8b80fSAndrew Turner 	val = val & ~BRIDGE_RESET_FLAG;
196eed8b80fSAndrew Turner 	bcm_pcib_set_reg(sc, REG_BRIDGE_CTRL, val);
197eed8b80fSAndrew Turner 
198eed8b80fSAndrew Turner 	DELAY(100);
199eed8b80fSAndrew Turner 
200eed8b80fSAndrew Turner 	bcm_pcib_set_reg(sc, REG_BRIDGE_SERDES_MODE, 0);
201eed8b80fSAndrew Turner 
202eed8b80fSAndrew Turner 	DELAY(100);
203eed8b80fSAndrew Turner }
204eed8b80fSAndrew Turner 
205eed8b80fSAndrew Turner static void
206eed8b80fSAndrew Turner bcm_pcib_enable_controller(struct bcm_pcib_softc *sc)
207eed8b80fSAndrew Turner {
208eed8b80fSAndrew Turner 	uint32_t val;
209eed8b80fSAndrew Turner 
210eed8b80fSAndrew Turner 	val = bcm_pcib_read_reg(sc, REG_BRIDGE_CTRL);
211eed8b80fSAndrew Turner 	val = val & ~BRIDGE_DISABLE_FLAG;
212eed8b80fSAndrew Turner 	bcm_pcib_set_reg(sc, REG_BRIDGE_CTRL, val);
213eed8b80fSAndrew Turner 
214eed8b80fSAndrew Turner 	DELAY(100);
215eed8b80fSAndrew Turner }
216eed8b80fSAndrew Turner 
217eed8b80fSAndrew Turner static int
218eed8b80fSAndrew Turner bcm_pcib_check_ranges(device_t dev)
219eed8b80fSAndrew Turner {
220eed8b80fSAndrew Turner 	struct bcm_pcib_softc *sc;
221eed8b80fSAndrew Turner 	struct pcie_range *ranges;
222eed8b80fSAndrew Turner 	int error = 0, i;
223eed8b80fSAndrew Turner 
224eed8b80fSAndrew Turner 	sc = device_get_softc(dev);
225eed8b80fSAndrew Turner 	ranges = &sc->base.base.ranges[0];
226eed8b80fSAndrew Turner 
227eed8b80fSAndrew Turner 	/* The first range needs to be non-zero. */
228eed8b80fSAndrew Turner 	if (ranges[0].size == 0) {
229eed8b80fSAndrew Turner 		device_printf(dev, "error: first outbound memory range "
230eed8b80fSAndrew Turner 		    "(pci addr: 0x%jx, cpu addr: 0x%jx) has zero size.\n",
231eed8b80fSAndrew Turner 		    ranges[0].pci_base, ranges[0].phys_base);
232eed8b80fSAndrew Turner 		error = ENXIO;
233eed8b80fSAndrew Turner 	}
234eed8b80fSAndrew Turner 
235eed8b80fSAndrew Turner 	/*
236eed8b80fSAndrew Turner 	 * The controller can actually handle three distinct ranges, but we
237eed8b80fSAndrew Turner 	 * only implement support for one.
238eed8b80fSAndrew Turner 	 */
239eed8b80fSAndrew Turner 	for (i = 1; (bootverbose || error) && i < MAX_RANGES_TUPLES; ++i) {
240eed8b80fSAndrew Turner 		if (ranges[i].size > 0)
241eed8b80fSAndrew Turner 			device_printf(dev,
242eed8b80fSAndrew Turner 			    "note: outbound memory range %d (pci addr: 0x%jx, "
243eed8b80fSAndrew Turner 			    "cpu addr: 0x%jx, size: 0x%jx) will be ignored.\n",
244eed8b80fSAndrew Turner 			    i, ranges[i].pci_base, ranges[i].phys_base,
245eed8b80fSAndrew Turner 			    ranges[i].size);
246eed8b80fSAndrew Turner 	}
247eed8b80fSAndrew Turner 
248eed8b80fSAndrew Turner 	return (error);
249eed8b80fSAndrew Turner }
250eed8b80fSAndrew Turner 
251eed8b80fSAndrew Turner static const char *
252eed8b80fSAndrew Turner bcm_pcib_link_state_string(uint32_t mode)
253eed8b80fSAndrew Turner {
254eed8b80fSAndrew Turner 
255eed8b80fSAndrew Turner 	switch(mode & PCIEM_LINK_STA_SPEED) {
256eed8b80fSAndrew Turner 	case 0:
257eed8b80fSAndrew Turner 		return ("not up");
258eed8b80fSAndrew Turner 	case 1:
259eed8b80fSAndrew Turner 		return ("2.5 GT/s");
260eed8b80fSAndrew Turner 	case 2:
261eed8b80fSAndrew Turner 		return ("5.0 GT/s");
262eed8b80fSAndrew Turner 	case 4:
263eed8b80fSAndrew Turner 		return ("8.0 GT/s");
264eed8b80fSAndrew Turner 	default:
265eed8b80fSAndrew Turner 		return ("unknown");
266eed8b80fSAndrew Turner 	}
267eed8b80fSAndrew Turner }
268eed8b80fSAndrew Turner 
269eed8b80fSAndrew Turner static bus_addr_t
270eed8b80fSAndrew Turner bcm_get_offset_and_prepare_config(struct bcm_pcib_softc *sc, u_int bus,
271eed8b80fSAndrew Turner     u_int slot, u_int func, u_int reg)
272eed8b80fSAndrew Turner {
273eed8b80fSAndrew Turner 	/*
274eed8b80fSAndrew Turner 	 * Config for an end point is only available through a narrow window for
275eed8b80fSAndrew Turner 	 * one end point at a time. We first tell the controller which end point
276eed8b80fSAndrew Turner 	 * we want, then access it through the window.
277eed8b80fSAndrew Turner 	 */
278eed8b80fSAndrew Turner 	uint32_t func_index;
279eed8b80fSAndrew Turner 
280eed8b80fSAndrew Turner 	if (bus == 0 && slot == 0 && func == 0)
281eed8b80fSAndrew Turner 		/*
282eed8b80fSAndrew Turner 		 * Special case for root device; its config is always available
283eed8b80fSAndrew Turner 		 * through the zero-offset.
284eed8b80fSAndrew Turner 		 */
285eed8b80fSAndrew Turner 		return (reg);
286eed8b80fSAndrew Turner 
287eed8b80fSAndrew Turner 	/* Tell the controller to show us the config in question. */
288eed8b80fSAndrew Turner 	func_index = PCIE_ADDR_OFFSET(bus, slot, func, 0);
289eed8b80fSAndrew Turner 	bcm_pcib_set_reg(sc, REG_EP_CONFIG_CHOICE, func_index);
290eed8b80fSAndrew Turner 
291eed8b80fSAndrew Turner 	return (REG_EP_CONFIG_DATA + reg);
292eed8b80fSAndrew Turner }
293eed8b80fSAndrew Turner 
294eed8b80fSAndrew Turner static bool
295eed8b80fSAndrew Turner bcm_pcib_is_valid_quad(struct bcm_pcib_softc *sc, u_int bus, u_int slot,
296eed8b80fSAndrew Turner     u_int func, u_int reg)
297eed8b80fSAndrew Turner {
298eed8b80fSAndrew Turner 
299eed8b80fSAndrew Turner 	if ((bus < sc->base.base.bus_start) || (bus > sc->base.base.bus_end))
300eed8b80fSAndrew Turner 		return (false);
301eed8b80fSAndrew Turner 	if ((slot > PCI_SLOTMAX) || (func > PCI_FUNCMAX) || (reg > PCIE_REGMAX))
302eed8b80fSAndrew Turner 		return (false);
303eed8b80fSAndrew Turner 
304eed8b80fSAndrew Turner 	if (bus == 0 && slot == 0 && func == 0)
305eed8b80fSAndrew Turner 		return (true);
306eed8b80fSAndrew Turner 	if (bus == 0)
307eed8b80fSAndrew Turner 		/*
308eed8b80fSAndrew Turner 		 * Probing other slots and funcs on bus 0 will lock up the
309eed8b80fSAndrew Turner 		 * memory controller.
310eed8b80fSAndrew Turner 		 */
311eed8b80fSAndrew Turner 		return (false);
312eed8b80fSAndrew Turner 
313eed8b80fSAndrew Turner 	return (true);
314eed8b80fSAndrew Turner }
315eed8b80fSAndrew Turner 
316eed8b80fSAndrew Turner static uint32_t
317eed8b80fSAndrew Turner bcm_pcib_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg,
318eed8b80fSAndrew Turner     int bytes)
319eed8b80fSAndrew Turner {
320eed8b80fSAndrew Turner 	struct bcm_pcib_softc *sc;
321eed8b80fSAndrew Turner 	bus_space_handle_t h;
322eed8b80fSAndrew Turner 	bus_space_tag_t	t;
323eed8b80fSAndrew Turner 	bus_addr_t offset;
324eed8b80fSAndrew Turner 	uint32_t data;
325eed8b80fSAndrew Turner 
326eed8b80fSAndrew Turner 	sc = device_get_softc(dev);
327eed8b80fSAndrew Turner 	if (!bcm_pcib_is_valid_quad(sc, bus, slot, func, reg))
328eed8b80fSAndrew Turner 		return (~0U);
329eed8b80fSAndrew Turner 
330eed8b80fSAndrew Turner 	mtx_lock(&sc->config_mtx);
331eed8b80fSAndrew Turner 	offset = bcm_get_offset_and_prepare_config(sc, bus, slot, func, reg);
332eed8b80fSAndrew Turner 
333eed8b80fSAndrew Turner 	t = sc->base.base.bst;
334eed8b80fSAndrew Turner 	h = sc->base.base.bsh;
335eed8b80fSAndrew Turner 
336eed8b80fSAndrew Turner 	switch (bytes) {
337eed8b80fSAndrew Turner 	case 1:
338eed8b80fSAndrew Turner 		data = bus_space_read_1(t, h, offset);
339eed8b80fSAndrew Turner 		break;
340eed8b80fSAndrew Turner 	case 2:
341eed8b80fSAndrew Turner 		data = le16toh(bus_space_read_2(t, h, offset));
342eed8b80fSAndrew Turner 		break;
343eed8b80fSAndrew Turner 	case 4:
344eed8b80fSAndrew Turner 		data = le32toh(bus_space_read_4(t, h, offset));
345eed8b80fSAndrew Turner 		break;
346eed8b80fSAndrew Turner 	default:
347eed8b80fSAndrew Turner 		data = ~0U;
348eed8b80fSAndrew Turner 		break;
349eed8b80fSAndrew Turner 	}
350eed8b80fSAndrew Turner 
351eed8b80fSAndrew Turner 	mtx_unlock(&sc->config_mtx);
352eed8b80fSAndrew Turner 	return (data);
353eed8b80fSAndrew Turner }
354eed8b80fSAndrew Turner 
355eed8b80fSAndrew Turner static void
356eed8b80fSAndrew Turner bcm_pcib_write_config(device_t dev, u_int bus, u_int slot,
357eed8b80fSAndrew Turner     u_int func, u_int reg, uint32_t val, int bytes)
358eed8b80fSAndrew Turner {
359eed8b80fSAndrew Turner 	struct bcm_pcib_softc *sc;
360eed8b80fSAndrew Turner 	bus_space_handle_t h;
361eed8b80fSAndrew Turner 	bus_space_tag_t	t;
362eed8b80fSAndrew Turner 	uint32_t offset;
363eed8b80fSAndrew Turner 
364eed8b80fSAndrew Turner 	sc = device_get_softc(dev);
365eed8b80fSAndrew Turner 	if (!bcm_pcib_is_valid_quad(sc, bus, slot, func, reg))
366eed8b80fSAndrew Turner 		return;
367eed8b80fSAndrew Turner 
368eed8b80fSAndrew Turner 	mtx_lock(&sc->config_mtx);
369eed8b80fSAndrew Turner 	offset = bcm_get_offset_and_prepare_config(sc, bus, slot, func, reg);
370eed8b80fSAndrew Turner 
371eed8b80fSAndrew Turner 	t = sc->base.base.bst;
372eed8b80fSAndrew Turner 	h = sc->base.base.bsh;
373eed8b80fSAndrew Turner 
374eed8b80fSAndrew Turner 	switch (bytes) {
375eed8b80fSAndrew Turner 	case 1:
376eed8b80fSAndrew Turner 		bus_space_write_1(t, h, offset, val);
377eed8b80fSAndrew Turner 		break;
378eed8b80fSAndrew Turner 	case 2:
379eed8b80fSAndrew Turner 		bus_space_write_2(t, h, offset, htole16(val));
380eed8b80fSAndrew Turner 		break;
381eed8b80fSAndrew Turner 	case 4:
382eed8b80fSAndrew Turner 		bus_space_write_4(t, h, offset, htole32(val));
383eed8b80fSAndrew Turner 		break;
384eed8b80fSAndrew Turner 	default:
385eed8b80fSAndrew Turner 		break;
386eed8b80fSAndrew Turner 	}
387eed8b80fSAndrew Turner 
388eed8b80fSAndrew Turner 	mtx_unlock(&sc->config_mtx);
389eed8b80fSAndrew Turner }
390eed8b80fSAndrew Turner 
391eed8b80fSAndrew Turner static void
392eed8b80fSAndrew Turner bcm_pcib_msi_intr_process(struct bcm_pcib_softc *sc, uint32_t interrupt_bitmap,
393eed8b80fSAndrew Turner     struct trapframe *tf)
394eed8b80fSAndrew Turner {
395eed8b80fSAndrew Turner 	struct bcm_pcib_irqsrc *irqsrc;
396eed8b80fSAndrew Turner 	uint32_t bit, irq;
397eed8b80fSAndrew Turner 
398eed8b80fSAndrew Turner 	while ((bit = ffs(interrupt_bitmap))) {
399eed8b80fSAndrew Turner 		irq = bit - 1;
400eed8b80fSAndrew Turner 
401eed8b80fSAndrew Turner 		/* Acknowledge interrupt. */
402eed8b80fSAndrew Turner 		bcm_pcib_set_reg(sc, REG_MSI_CLR, 1 << irq);
403eed8b80fSAndrew Turner 
404eed8b80fSAndrew Turner 		/* Send EOI. */
405eed8b80fSAndrew Turner 		bcm_pcib_set_reg(sc, REG_MSI_EOI, 1);
406eed8b80fSAndrew Turner 
407eed8b80fSAndrew Turner 		/* Despatch to handler. */
408eed8b80fSAndrew Turner 		irqsrc = &sc->msi_isrcs[irq];
409eed8b80fSAndrew Turner 		if (intr_isrc_dispatch(&irqsrc->isrc, tf))
410eed8b80fSAndrew Turner 			device_printf(sc->dev,
411eed8b80fSAndrew Turner 			    "note: unexpected interrupt (%d) triggered.\n",
412eed8b80fSAndrew Turner 			    irq);
413eed8b80fSAndrew Turner 
414eed8b80fSAndrew Turner 		/* Done with this interrupt. */
415eed8b80fSAndrew Turner 		interrupt_bitmap = interrupt_bitmap & ~(1 << irq);
416eed8b80fSAndrew Turner 	}
417eed8b80fSAndrew Turner }
418eed8b80fSAndrew Turner 
419eed8b80fSAndrew Turner static int
420eed8b80fSAndrew Turner bcm_pcib_msi_intr(void *arg)
421eed8b80fSAndrew Turner {
422eed8b80fSAndrew Turner 	struct bcm_pcib_softc *sc;
423eed8b80fSAndrew Turner 	struct trapframe *tf;
424eed8b80fSAndrew Turner 	uint32_t interrupt_bitmap;
425eed8b80fSAndrew Turner 
426eed8b80fSAndrew Turner 	sc = (struct bcm_pcib_softc *) arg;
427eed8b80fSAndrew Turner 	tf = curthread->td_intr_frame;
428eed8b80fSAndrew Turner 
429eed8b80fSAndrew Turner 	while ((interrupt_bitmap = bcm_pcib_read_reg(sc, REG_MSI_RAISED)))
430eed8b80fSAndrew Turner 		bcm_pcib_msi_intr_process(sc, interrupt_bitmap, tf);
431eed8b80fSAndrew Turner 
432eed8b80fSAndrew Turner 	return (FILTER_HANDLED);
433eed8b80fSAndrew Turner }
434eed8b80fSAndrew Turner 
435eed8b80fSAndrew Turner static int
436eed8b80fSAndrew Turner bcm_pcib_alloc_msi(device_t dev, device_t child, int count, int maxcount,
437eed8b80fSAndrew Turner     device_t *pic, struct intr_irqsrc **srcs)
438eed8b80fSAndrew Turner {
439eed8b80fSAndrew Turner 	struct bcm_pcib_softc *sc;
440eed8b80fSAndrew Turner 	int first_int, i;
441eed8b80fSAndrew Turner 
442eed8b80fSAndrew Turner 	sc = device_get_softc(dev);
443eed8b80fSAndrew Turner 	mtx_lock(&sc->msi_mtx);
444eed8b80fSAndrew Turner 
445eed8b80fSAndrew Turner 	/* Find a continguous region of free message-signalled interrupts. */
446eed8b80fSAndrew Turner 	for (first_int = 0; first_int + count < NUM_MSI; ) {
447eed8b80fSAndrew Turner 		for (i = first_int; i < first_int + count; ++i) {
448eed8b80fSAndrew Turner 			if (sc->msi_isrcs[i].allocated)
449eed8b80fSAndrew Turner 				goto next;
450eed8b80fSAndrew Turner 		}
451eed8b80fSAndrew Turner 		goto found;
452eed8b80fSAndrew Turner next:
453eed8b80fSAndrew Turner 		first_int = i + 1;
454eed8b80fSAndrew Turner 	}
455eed8b80fSAndrew Turner 
456eed8b80fSAndrew Turner 	/* No appropriate region available. */
457eed8b80fSAndrew Turner 	mtx_unlock(&sc->msi_mtx);
458eed8b80fSAndrew Turner 	device_printf(dev, "warning: failed to allocate %d MSI messages.\n",
459eed8b80fSAndrew Turner 	    count);
460eed8b80fSAndrew Turner 	return (ENXIO);
461eed8b80fSAndrew Turner 
462eed8b80fSAndrew Turner found:
463eed8b80fSAndrew Turner 	/* Mark the messages as in use. */
464eed8b80fSAndrew Turner 	for (i = 0; i < count; ++i) {
465eed8b80fSAndrew Turner 		sc->msi_isrcs[i + first_int].allocated = true;
466eed8b80fSAndrew Turner 		srcs[i] = &(sc->msi_isrcs[i + first_int].isrc);
467eed8b80fSAndrew Turner 	}
468eed8b80fSAndrew Turner 
469eed8b80fSAndrew Turner 	mtx_unlock(&sc->msi_mtx);
470eed8b80fSAndrew Turner 	*pic = device_get_parent(dev);
471eed8b80fSAndrew Turner 
472eed8b80fSAndrew Turner 	return (0);
473eed8b80fSAndrew Turner }
474eed8b80fSAndrew Turner 
475eed8b80fSAndrew Turner static int
476eed8b80fSAndrew Turner bcm_pcib_map_msi(device_t dev, device_t child, struct intr_irqsrc *isrc,
477eed8b80fSAndrew Turner     uint64_t *addr, uint32_t *data)
478eed8b80fSAndrew Turner {
479eed8b80fSAndrew Turner 	struct bcm_pcib_softc *sc;
480eed8b80fSAndrew Turner 	struct bcm_pcib_irqsrc *msi_msg;
481eed8b80fSAndrew Turner 
482eed8b80fSAndrew Turner 	sc = device_get_softc(dev);
483eed8b80fSAndrew Turner 	msi_msg = (struct bcm_pcib_irqsrc *) isrc;
484eed8b80fSAndrew Turner 
485eed8b80fSAndrew Turner 	*addr = sc->msi_addr;
486eed8b80fSAndrew Turner 	*data = (REG_VALUE_MSI_CONFIG & 0xffff) | msi_msg->irq;
487eed8b80fSAndrew Turner 	return (0);
488eed8b80fSAndrew Turner }
489eed8b80fSAndrew Turner 
490eed8b80fSAndrew Turner static int
491eed8b80fSAndrew Turner bcm_pcib_release_msi(device_t dev, device_t child, int count,
492eed8b80fSAndrew Turner     struct intr_irqsrc **isrc)
493eed8b80fSAndrew Turner {
494eed8b80fSAndrew Turner 	struct bcm_pcib_softc *sc;
495eed8b80fSAndrew Turner 	struct bcm_pcib_irqsrc *msi_isrc;
496eed8b80fSAndrew Turner 	int i;
497eed8b80fSAndrew Turner 
498eed8b80fSAndrew Turner 	sc = device_get_softc(dev);
499eed8b80fSAndrew Turner 	mtx_lock(&sc->msi_mtx);
500eed8b80fSAndrew Turner 
501eed8b80fSAndrew Turner 	for (i = 0; i < count; i++) {
502eed8b80fSAndrew Turner 		msi_isrc = (struct bcm_pcib_irqsrc *) isrc[i];
503eed8b80fSAndrew Turner 		msi_isrc->allocated = false;
504eed8b80fSAndrew Turner 	}
505eed8b80fSAndrew Turner 
506eed8b80fSAndrew Turner 	mtx_unlock(&sc->msi_mtx);
507eed8b80fSAndrew Turner 	return (0);
508eed8b80fSAndrew Turner }
509eed8b80fSAndrew Turner 
510eed8b80fSAndrew Turner static int
511eed8b80fSAndrew Turner bcm_pcib_msi_attach(device_t dev)
512eed8b80fSAndrew Turner {
513eed8b80fSAndrew Turner 	struct bcm_pcib_softc *sc;
514eed8b80fSAndrew Turner 	phandle_t node, xref;
515eed8b80fSAndrew Turner 	char const *bcm_name;
516eed8b80fSAndrew Turner 	int i, rid;
517eed8b80fSAndrew Turner 
518eed8b80fSAndrew Turner 	sc = device_get_softc(dev);
519eed8b80fSAndrew Turner 	sc->msi_addr = 0xffffffffc;
520eed8b80fSAndrew Turner 
521eed8b80fSAndrew Turner 	/* Clear any pending interrupts. */
522eed8b80fSAndrew Turner 	bcm_pcib_set_reg(sc, REG_MSI_CLR, 0xffffffff);
523eed8b80fSAndrew Turner 
524eed8b80fSAndrew Turner 	rid = 1;
525eed8b80fSAndrew Turner 	sc->msi_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
526eed8b80fSAndrew Turner 	    RF_ACTIVE);
527eed8b80fSAndrew Turner 	if (sc->msi_irq_res == NULL) {
528eed8b80fSAndrew Turner 		device_printf(dev, "could not allocate MSI irq resource.\n");
529eed8b80fSAndrew Turner 		return (ENXIO);
530eed8b80fSAndrew Turner 	}
531eed8b80fSAndrew Turner 
532eed8b80fSAndrew Turner 	sc->msi_isrcs = malloc(sizeof(*sc->msi_isrcs) * NUM_MSI, M_DEVBUF,
533eed8b80fSAndrew Turner 	    M_WAITOK | M_ZERO);
534eed8b80fSAndrew Turner 
535eed8b80fSAndrew Turner 	int error = bus_setup_intr(dev, sc->msi_irq_res, INTR_TYPE_BIO |
536eed8b80fSAndrew Turner 	    INTR_MPSAFE, bcm_pcib_msi_intr, NULL, sc, &sc->msi_intr_cookie);
537eed8b80fSAndrew Turner 	if (error) {
538eed8b80fSAndrew Turner 		device_printf(dev, "error: failed to setup MSI handler.\n");
539eed8b80fSAndrew Turner 		return (ENXIO);
540eed8b80fSAndrew Turner 	}
541eed8b80fSAndrew Turner 
542eed8b80fSAndrew Turner 	bcm_name = device_get_nameunit(dev);
543eed8b80fSAndrew Turner 	for (i = 0; i < NUM_MSI; i++) {
544eed8b80fSAndrew Turner 		sc->msi_isrcs[i].irq = i;
545eed8b80fSAndrew Turner 		error = intr_isrc_register(&sc->msi_isrcs[i].isrc, dev, 0,
546eed8b80fSAndrew Turner 		    "%s,%u", bcm_name, i);
547eed8b80fSAndrew Turner 		if (error) {
548eed8b80fSAndrew Turner 			device_printf(dev,
549eed8b80fSAndrew Turner 			"error: failed to register interrupt %d.\n", i);
550eed8b80fSAndrew Turner 			return (ENXIO);
551eed8b80fSAndrew Turner 		}
552eed8b80fSAndrew Turner 	}
553eed8b80fSAndrew Turner 
554eed8b80fSAndrew Turner 	node = ofw_bus_get_node(dev);
555eed8b80fSAndrew Turner 	xref = OF_xref_from_node(node);
556eed8b80fSAndrew Turner 	OF_device_register_xref(xref, dev);
557eed8b80fSAndrew Turner 
558eed8b80fSAndrew Turner 	error = intr_msi_register(dev, xref);
559eed8b80fSAndrew Turner 	if (error)
560eed8b80fSAndrew Turner 		return (ENXIO);
561eed8b80fSAndrew Turner 
562eed8b80fSAndrew Turner 	mtx_init(&sc->msi_mtx, "bcm_pcib: msi_mtx", NULL, MTX_DEF);
563eed8b80fSAndrew Turner 
564eed8b80fSAndrew Turner 	bcm_pcib_set_reg(sc, REG_MSI_MASK_CLR, 0xffffffff);
565eed8b80fSAndrew Turner 	bcm_pcib_set_reg(sc, REG_MSI_ADDR_LOW, (sc->msi_addr & 0xffffffff) | 1);
566eed8b80fSAndrew Turner 	bcm_pcib_set_reg(sc, REG_MSI_ADDR_HIGH, (sc->msi_addr >> 32));
567eed8b80fSAndrew Turner 	bcm_pcib_set_reg(sc, REG_MSI_CONFIG, REG_VALUE_MSI_CONFIG);
568eed8b80fSAndrew Turner 
569eed8b80fSAndrew Turner 	return (0);
570eed8b80fSAndrew Turner }
571eed8b80fSAndrew Turner 
572eed8b80fSAndrew Turner static void
573eed8b80fSAndrew Turner bcm_pcib_relocate_bridge_window(device_t dev)
574eed8b80fSAndrew Turner {
575eed8b80fSAndrew Turner 	/*
576eed8b80fSAndrew Turner 	 * In principle an out-of-bounds bridge window could be automatically
577eed8b80fSAndrew Turner 	 * adjusted at resource-activation time to lie within the bus address
578eed8b80fSAndrew Turner 	 * space by pcib_grow_window(), but that is not possible because the
579eed8b80fSAndrew Turner 	 * out-of-bounds resource allocation fails at allocation time. Instead,
580eed8b80fSAndrew Turner 	 * we will just fix up the window on the controller here, before it is
581eed8b80fSAndrew Turner 	 * re-discovered by pcib_probe_windows().
582eed8b80fSAndrew Turner 	 */
583eed8b80fSAndrew Turner 
584eed8b80fSAndrew Turner 	struct bcm_pcib_softc *sc;
585eed8b80fSAndrew Turner 	pci_addr_t base, size, new_base, new_limit;
586eed8b80fSAndrew Turner 	uint16_t val;
587eed8b80fSAndrew Turner 
588eed8b80fSAndrew Turner 	sc = device_get_softc(dev);
589eed8b80fSAndrew Turner 
590eed8b80fSAndrew Turner 	val = bcm_pcib_read_config(dev, 0, 0, 0, PCIR_MEMBASE_1, 2);
591eed8b80fSAndrew Turner 	base = PCI_PPBMEMBASE(0, val);
592eed8b80fSAndrew Turner 
593eed8b80fSAndrew Turner 	val = bcm_pcib_read_config(dev, 0, 0, 0, PCIR_MEMLIMIT_1, 2);
594eed8b80fSAndrew Turner 	size = PCI_PPBMEMLIMIT(0, val) - base;
595eed8b80fSAndrew Turner 
596eed8b80fSAndrew Turner 	new_base = sc->base.base.ranges[0].pci_base;
597eed8b80fSAndrew Turner 	val = (uint16_t) (new_base >> 16);
598eed8b80fSAndrew Turner 	bcm_pcib_write_config(dev, 0, 0, 0, PCIR_MEMBASE_1, val, 2);
599eed8b80fSAndrew Turner 
600eed8b80fSAndrew Turner 	new_limit = new_base + size;
601eed8b80fSAndrew Turner 	val = (uint16_t) (new_limit >> 16);
602eed8b80fSAndrew Turner 	bcm_pcib_write_config(dev, 0, 0, 0, PCIR_MEMLIMIT_1, val, 2);
603eed8b80fSAndrew Turner }
604eed8b80fSAndrew Turner 
605eed8b80fSAndrew Turner static uint32_t
606eed8b80fSAndrew Turner encode_cpu_window_low(pci_addr_t phys_base, bus_size_t size)
607eed8b80fSAndrew Turner {
608eed8b80fSAndrew Turner 
609eed8b80fSAndrew Turner 	return (((phys_base >> 0x10) & 0xfff0) |
610eed8b80fSAndrew Turner 	    ((phys_base + size - 1) & 0xfff00000));
611eed8b80fSAndrew Turner }
612eed8b80fSAndrew Turner 
613eed8b80fSAndrew Turner static uint32_t
614eed8b80fSAndrew Turner encode_cpu_window_start_high(pci_addr_t phys_base)
615eed8b80fSAndrew Turner {
616eed8b80fSAndrew Turner 
617eed8b80fSAndrew Turner 	return ((phys_base >> 0x20) & 0xff);
618eed8b80fSAndrew Turner }
619eed8b80fSAndrew Turner 
620eed8b80fSAndrew Turner static uint32_t
621eed8b80fSAndrew Turner encode_cpu_window_end_high(pci_addr_t phys_base, bus_size_t size)
622eed8b80fSAndrew Turner {
623eed8b80fSAndrew Turner 
624eed8b80fSAndrew Turner 	return (((phys_base + size - 1) >> 0x20) & 0xff);
625eed8b80fSAndrew Turner }
626eed8b80fSAndrew Turner 
627eed8b80fSAndrew Turner static int
628eed8b80fSAndrew Turner bcm_pcib_attach(device_t dev)
629eed8b80fSAndrew Turner {
630eed8b80fSAndrew Turner 	struct bcm_pcib_softc *sc;
631eed8b80fSAndrew Turner 	pci_addr_t phys_base, pci_base;
632eed8b80fSAndrew Turner 	bus_size_t size;
633eed8b80fSAndrew Turner 	uint32_t hardware_rev, bridge_state, link_state;
634eed8b80fSAndrew Turner 	int error, tries;
635eed8b80fSAndrew Turner 
636eed8b80fSAndrew Turner 	sc = device_get_softc(dev);
637eed8b80fSAndrew Turner 	sc->dev = dev;
638eed8b80fSAndrew Turner 
639ac89220bSMike Karels 	/*
640ac89220bSMike Karels 	 * This tag will be used in preference to the one created in
641ac89220bSMike Karels 	 * pci_host_generic.c.
642ac89220bSMike Karels 	 */
643ac89220bSMike Karels 	error = bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */
644ac89220bSMike Karels 	    1, 0,				/* alignment, bounds */
645ac89220bSMike Karels 	    DMA_HIGH_LIMIT,			/* lowaddr */
646ac89220bSMike Karels 	    BUS_SPACE_MAXADDR,			/* highaddr */
647ac89220bSMike Karels 	    NULL, NULL,				/* filter, filterarg */
648ac89220bSMike Karels 	    DMA_HIGH_LIMIT,			/* maxsize */
649ac89220bSMike Karels 	    BUS_SPACE_UNRESTRICTED,		/* nsegments */
650ac89220bSMike Karels 	    DMA_HIGH_LIMIT,			/* maxsegsize */
651ac89220bSMike Karels 	    0, 					/* flags */
652ac89220bSMike Karels 	    NULL, NULL,				/* lockfunc, lockarg */
653ac89220bSMike Karels 	    &sc->dmat);
654ac89220bSMike Karels 	if (error)
655ac89220bSMike Karels 		return (error);
656ac89220bSMike Karels 
657eed8b80fSAndrew Turner 	error = pci_host_generic_setup_fdt(dev);
658eed8b80fSAndrew Turner 	if (error)
659eed8b80fSAndrew Turner 		return (error);
660eed8b80fSAndrew Turner 
661eed8b80fSAndrew Turner 	error = bcm_pcib_check_ranges(dev);
662eed8b80fSAndrew Turner 	if (error)
663eed8b80fSAndrew Turner 		return (error);
664eed8b80fSAndrew Turner 
665eed8b80fSAndrew Turner 	mtx_init(&sc->config_mtx, "bcm_pcib: config_mtx", NULL, MTX_DEF);
666eed8b80fSAndrew Turner 
667eed8b80fSAndrew Turner 	bcm_pcib_reset_controller(sc);
668eed8b80fSAndrew Turner 
669eed8b80fSAndrew Turner 	hardware_rev = bcm_pcib_read_reg(sc, REG_CONTROLLER_HW_REV) & 0xffff;
670eed8b80fSAndrew Turner 	device_printf(dev, "hardware identifies as revision 0x%x.\n",
671eed8b80fSAndrew Turner 	    hardware_rev);
672eed8b80fSAndrew Turner 
673eed8b80fSAndrew Turner 	/*
674eed8b80fSAndrew Turner 	 * Set PCI->CPU memory window. This encodes the inbound window showing
675ac89220bSMike Karels 	 * the system memory to the controller.
676eed8b80fSAndrew Turner 	 */
677ac89220bSMike Karels 	bcm_pcib_set_reg(sc, REG_DMA_WINDOW_LOW, REG_VALUE_DMA_WINDOW_LOW);
678ac89220bSMike Karels 	bcm_pcib_set_reg(sc, REG_DMA_WINDOW_HIGH, REG_VALUE_DMA_WINDOW_HIGH);
679ac89220bSMike Karels 	bcm_pcib_set_reg(sc, REG_DMA_CONFIG, REG_VALUE_DMA_WINDOW_CONFIG);
680ac89220bSMike Karels 
681eed8b80fSAndrew Turner 	bcm_pcib_set_reg(sc, REG_BRIDGE_GISB_WINDOW, 0);
682ac89220bSMike Karels 	bcm_pcib_set_reg(sc, REG_DMA_WINDOW_1, 0);
683eed8b80fSAndrew Turner 
684eed8b80fSAndrew Turner 	bcm_pcib_enable_controller(sc);
685eed8b80fSAndrew Turner 
686eed8b80fSAndrew Turner 	/* Wait for controller to start. */
687eed8b80fSAndrew Turner 	for(tries = 0; ; ++tries) {
688eed8b80fSAndrew Turner 		bridge_state = bcm_pcib_read_reg(sc, REG_BRIDGE_STATE);
689eed8b80fSAndrew Turner 
690eed8b80fSAndrew Turner 		if ((bridge_state & 0x30) == 0x30)
691eed8b80fSAndrew Turner 			/* Controller ready. */
692eed8b80fSAndrew Turner 			break;
693eed8b80fSAndrew Turner 
694eed8b80fSAndrew Turner 		if (tries > 100) {
695eed8b80fSAndrew Turner 			device_printf(dev,
696eed8b80fSAndrew Turner 			    "error: controller failed to start.\n");
697eed8b80fSAndrew Turner 			return (ENXIO);
698eed8b80fSAndrew Turner 		}
699eed8b80fSAndrew Turner 
700eed8b80fSAndrew Turner 		DELAY(1000);
701eed8b80fSAndrew Turner 	}
702eed8b80fSAndrew Turner 
703eed8b80fSAndrew Turner 	link_state = bcm_pcib_read_reg(sc, REG_BRIDGE_LINK_STATE) >> 0x10;
704eed8b80fSAndrew Turner 	if (!link_state) {
705eed8b80fSAndrew Turner 		device_printf(dev, "error: controller started but link is not "
706eed8b80fSAndrew Turner 		    "up.\n");
707eed8b80fSAndrew Turner 		return (ENXIO);
708eed8b80fSAndrew Turner 	}
709eed8b80fSAndrew Turner 	if (bootverbose)
710eed8b80fSAndrew Turner 		device_printf(dev, "note: reported link speed is %s.\n",
711eed8b80fSAndrew Turner 		    bcm_pcib_link_state_string(link_state));
712eed8b80fSAndrew Turner 
713eed8b80fSAndrew Turner 	/*
714eed8b80fSAndrew Turner 	 * Set the CPU->PCI memory window. The map in this direction is not 1:1.
715eed8b80fSAndrew Turner 	 * Addresses seen by the CPU need to be adjusted to make sense to the
716eed8b80fSAndrew Turner 	 * controller as they pass through the window.
717eed8b80fSAndrew Turner 	 */
718eed8b80fSAndrew Turner 	pci_base  = sc->base.base.ranges[0].pci_base;
719eed8b80fSAndrew Turner 	phys_base = sc->base.base.ranges[0].phys_base;
720eed8b80fSAndrew Turner 	size      = sc->base.base.ranges[0].size;
721eed8b80fSAndrew Turner 
722ac89220bSMike Karels 	bcm_pcib_set_reg(sc, REG_BUS_WINDOW_LOW, pci_base & 0xffffffff);
723ac89220bSMike Karels 	bcm_pcib_set_reg(sc, REG_BUS_WINDOW_HIGH, pci_base >> 32);
724eed8b80fSAndrew Turner 
725ac89220bSMike Karels 	bcm_pcib_set_reg(sc, REG_CPU_WINDOW_LOW,
726eed8b80fSAndrew Turner 	    encode_cpu_window_low(phys_base, size));
727ac89220bSMike Karels 	bcm_pcib_set_reg(sc, REG_CPU_WINDOW_START_HIGH,
728eed8b80fSAndrew Turner 	    encode_cpu_window_start_high(phys_base));
729ac89220bSMike Karels 	bcm_pcib_set_reg(sc, REG_CPU_WINDOW_END_HIGH,
730eed8b80fSAndrew Turner 	    encode_cpu_window_end_high(phys_base, size));
731eed8b80fSAndrew Turner 
732eed8b80fSAndrew Turner 	/*
733eed8b80fSAndrew Turner 	 * The controller starts up declaring itself an endpoint; readvertise it
734eed8b80fSAndrew Turner 	 * as a bridge.
735eed8b80fSAndrew Turner 	 */
736eed8b80fSAndrew Turner 	bcm_pcib_set_reg(sc, PCI_ID_VAL3,
737eed8b80fSAndrew Turner 	    PCIC_BRIDGE << CLASS_SHIFT | PCIS_BRIDGE_PCI << SUBCLASS_SHIFT);
738eed8b80fSAndrew Turner 
739eed8b80fSAndrew Turner 	bcm_pcib_set_reg(sc, REG_BRIDGE_SERDES_MODE, 0x2);
740eed8b80fSAndrew Turner 	DELAY(100);
741eed8b80fSAndrew Turner 
742eed8b80fSAndrew Turner 	bcm_pcib_relocate_bridge_window(dev);
743eed8b80fSAndrew Turner 
744eed8b80fSAndrew Turner 	/* Configure interrupts. */
745eed8b80fSAndrew Turner 	error = bcm_pcib_msi_attach(dev);
746eed8b80fSAndrew Turner 	if (error)
747eed8b80fSAndrew Turner 		return (error);
748eed8b80fSAndrew Turner 
749eed8b80fSAndrew Turner 	/* Done. */
750eed8b80fSAndrew Turner 	device_add_child(dev, "pci", -1);
751eed8b80fSAndrew Turner 	return (bus_generic_attach(dev));
752eed8b80fSAndrew Turner }
753eed8b80fSAndrew Turner 
754eed8b80fSAndrew Turner /*
755eed8b80fSAndrew Turner  * Device method table.
756eed8b80fSAndrew Turner  */
757eed8b80fSAndrew Turner static device_method_t bcm_pcib_methods[] = {
758ac89220bSMike Karels 	/* Bus interface. */
759ac89220bSMike Karels 	DEVMETHOD(bus_get_dma_tag,		bcm_pcib_get_dma_tag),
760ac89220bSMike Karels 
761eed8b80fSAndrew Turner 	/* Device interface. */
762eed8b80fSAndrew Turner 	DEVMETHOD(device_probe,			bcm_pcib_probe),
763eed8b80fSAndrew Turner 	DEVMETHOD(device_attach,		bcm_pcib_attach),
764eed8b80fSAndrew Turner 
765eed8b80fSAndrew Turner 	/* PCIB interface. */
766eed8b80fSAndrew Turner 	DEVMETHOD(pcib_read_config,		bcm_pcib_read_config),
767eed8b80fSAndrew Turner 	DEVMETHOD(pcib_write_config,		bcm_pcib_write_config),
768eed8b80fSAndrew Turner 
769eed8b80fSAndrew Turner 	/* MSI interface. */
770eed8b80fSAndrew Turner 	DEVMETHOD(msi_alloc_msi,		bcm_pcib_alloc_msi),
771eed8b80fSAndrew Turner 	DEVMETHOD(msi_release_msi,		bcm_pcib_release_msi),
772eed8b80fSAndrew Turner 	DEVMETHOD(msi_map_msi,			bcm_pcib_map_msi),
773eed8b80fSAndrew Turner 
774eed8b80fSAndrew Turner 	DEVMETHOD_END
775eed8b80fSAndrew Turner };
776eed8b80fSAndrew Turner 
777eed8b80fSAndrew Turner DEFINE_CLASS_1(pcib, bcm_pcib_driver, bcm_pcib_methods,
778eed8b80fSAndrew Turner     sizeof(struct bcm_pcib_softc), generic_pcie_fdt_driver);
779eed8b80fSAndrew Turner 
780*82d4dc06SJohn Baldwin DRIVER_MODULE(bcm_pcib, simplebus, bcm_pcib_driver, 0, 0);
781ac89220bSMike Karels 
782