1296936Smmel/*-
2296936Smmel * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org>
3296936Smmel * All rights reserved.
4296936Smmel *
5296936Smmel * Redistribution and use in source and binary forms, with or without
6296936Smmel * modification, are permitted provided that the following conditions
7296936Smmel * are met:
8296936Smmel * 1. Redistributions of source code must retain the above copyright
9296936Smmel *    notice, this list of conditions and the following disclaimer.
10296936Smmel * 2. Redistributions in binary form must reproduce the above copyright
11296936Smmel *    notice, this list of conditions and the following disclaimer in the
12296936Smmel *    documentation and/or other materials provided with the distribution.
13296936Smmel *
14296936Smmel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15296936Smmel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16296936Smmel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17296936Smmel * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18296936Smmel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19296936Smmel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20296936Smmel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21296936Smmel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22296936Smmel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23296936Smmel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24296936Smmel * SUCH DAMAGE.
25296936Smmel */
26296936Smmel
27296936Smmel#include <sys/cdefs.h>
28296936Smmel__FBSDID("$FreeBSD: releng/11.0/sys/arm/nvidia/tegra_pcie.c 298627 2016-04-26 11:53:37Z br $");
29296936Smmel
30296936Smmel/*
31296936Smmel * Nvidia Integrated PCI/PCI-Express controller driver.
32296936Smmel */
33296936Smmel
34296936Smmel#include <sys/param.h>
35296936Smmel#include <sys/systm.h>
36296936Smmel#include <sys/kernel.h>
37296936Smmel#include <sys/lock.h>
38296936Smmel#include <sys/malloc.h>
39296936Smmel#include <sys/module.h>
40296936Smmel#include <sys/mutex.h>
41296936Smmel#include <sys/queue.h>
42296936Smmel#include <sys/bus.h>
43296936Smmel#include <sys/rman.h>
44296936Smmel#include <sys/endian.h>
45298627Sbr#include <sys/devmap.h>
46296936Smmel
47296936Smmel#include <machine/intr.h>
48296936Smmel
49296936Smmel#include <vm/vm.h>
50296936Smmel#include <vm/pmap.h>
51296936Smmel
52296936Smmel#include <dev/extres/clk/clk.h>
53296936Smmel#include <dev/extres/hwreset/hwreset.h>
54296936Smmel#include <dev/extres/phy/phy.h>
55296936Smmel#include <dev/extres/regulator/regulator.h>
56296936Smmel#include <dev/fdt/fdt_common.h>
57296936Smmel#include <dev/ofw/ofw_bus.h>
58296936Smmel#include <dev/ofw/ofw_bus_subr.h>
59296936Smmel#include <dev/ofw/ofw_pci.h>
60296936Smmel#include <dev/pci/pcivar.h>
61296936Smmel#include <dev/pci/pcireg.h>
62296936Smmel#include <dev/pci/pcib_private.h>
63296936Smmel
64296936Smmel#include <machine/resource.h>
65296936Smmel#include <machine/bus.h>
66296936Smmel
67296936Smmel#include "ofw_bus_if.h"
68296936Smmel#include "pcib_if.h"
69296936Smmel
70296936Smmel#include <arm/nvidia/tegra_pmc.h>
71296936Smmel
72296936Smmel/* --- Move to ofw_pci.c/.h ----------------------- */
73296936Smmel
74296936Smmelstruct tegra_pci_range {
75296936Smmel	/* parsed phys.hi */
76296936Smmel	int 		nonrelocatable;
77296936Smmel	int		prefetchable;
78296936Smmel	int		aliased;
79296936Smmel	int		space_code;	/* In native format (not shifted)*/
80296936Smmel	int		bus;
81296936Smmel	int		device;
82296936Smmel	int		function;
83296936Smmel	int		reg;
84296936Smmel	pci_addr_t	pci_addr;	/* PCI Address */
85296936Smmel	bus_addr_t	host_addr;	/* Host bus address*/
86296936Smmel	bus_size_t	size;		/* Range size */
87296936Smmel};
88296936Smmel
89296936Smmelstatic int
90296936Smmeltegra_pci_get_ranges(phandle_t node,  struct tegra_pci_range **ranges)
91296936Smmel{
92296936Smmel	int host_address_cells, pci_address_cells, size_cells;
93296936Smmel	cell_t *base_ranges;
94296936Smmel	ssize_t nbase_ranges;
95296936Smmel	int nranges;
96296936Smmel	int i, j, k;
97296936Smmel	uint32_t flags;
98296936Smmel	uint64_t tmp;
99296936Smmel
100296936Smmel	host_address_cells = 1;
101296936Smmel	pci_address_cells = 3;
102296936Smmel	size_cells = 2;
103296936Smmel	OF_getencprop(OF_parent(node), "#address-cells", &host_address_cells,
104296936Smmel	    sizeof(host_address_cells));
105296936Smmel	OF_getencprop(node, "#address-cells", &pci_address_cells,
106296936Smmel	    sizeof(pci_address_cells));
107296936Smmel	OF_getencprop(node, "#size-cells", &size_cells, sizeof(size_cells));
108296936Smmel
109296936Smmel	nbase_ranges = OF_getproplen(node, "ranges");
110296936Smmel	if (nbase_ranges <= 0)
111296936Smmel		return (-1);
112296936Smmel	nranges = nbase_ranges / sizeof(cell_t) /
113296936Smmel	    (pci_address_cells + host_address_cells + size_cells);
114296936Smmel
115296936Smmel	*ranges = malloc(nranges * sizeof(struct tegra_pci_range),
116296936Smmel	    M_DEVBUF, M_WAITOK);
117296936Smmel	base_ranges = malloc(nbase_ranges, M_DEVBUF, M_WAITOK);
118296936Smmel	OF_getencprop(node, "ranges", base_ranges, nbase_ranges);
119296936Smmel
120296936Smmel	for (i = 0, j = 0; i < nranges; i++) {
121296936Smmel		flags =  base_ranges[j++];
122296936Smmel		(*ranges)[i].nonrelocatable =
123296936Smmel		   flags & OFW_PCI_PHYS_HI_NONRELOCATABLE ? 1 : 0;
124296936Smmel		(*ranges)[i].prefetchable =
125296936Smmel		   flags & OFW_PCI_PHYS_HI_PREFETCHABLE ? 1 : 0;
126296936Smmel		(*ranges)[i].aliased =
127296936Smmel		   flags & OFW_PCI_PHYS_HI_ALIASED ? 1 : 0;
128296936Smmel		(*ranges)[i].space_code = flags & OFW_PCI_PHYS_HI_SPACEMASK;
129296936Smmel		(*ranges)[i].bus = OFW_PCI_PHYS_HI_BUS(flags);
130296936Smmel		(*ranges)[i].device = OFW_PCI_PHYS_HI_DEVICE(flags);
131296936Smmel		(*ranges)[i].function = OFW_PCI_PHYS_HI_FUNCTION(flags);
132296936Smmel		(*ranges)[i].reg = flags & OFW_PCI_PHYS_HI_REGISTERMASK;
133296936Smmel
134296936Smmel		tmp = 0;
135296936Smmel		for (k = 0; k < pci_address_cells - 1; k++) {
136296936Smmel			tmp <<= 32;
137296936Smmel			tmp |= base_ranges[j++];
138296936Smmel		}
139296936Smmel		(*ranges)[i].pci_addr = (pci_addr_t)tmp;
140296936Smmel
141296936Smmel		tmp = 0;
142296936Smmel		for (k = 0; k < host_address_cells; k++) {
143296936Smmel			tmp <<= 32;
144296936Smmel			tmp |= base_ranges[j++];
145296936Smmel		}
146296936Smmel		(*ranges)[i].host_addr = (bus_addr_t)tmp;
147296936Smmel		tmp = 0;
148296936Smmel
149296936Smmel		for (k = 0; k < size_cells; k++) {
150296936Smmel			tmp <<= 32;
151296936Smmel			tmp |= base_ranges[j++];
152296936Smmel		}
153296936Smmel		(*ranges)[i].size = (bus_size_t)tmp;
154296936Smmel	}
155296936Smmel
156296936Smmel	free(base_ranges, M_DEVBUF);
157296936Smmel	return (nranges);
158296936Smmel}
159296936Smmel
160296936Smmel/* -------------------------------------------------------------------------- */
161296936Smmel#define	AFI_AXI_BAR0_SZ				0x000
162296936Smmel#define	AFI_AXI_BAR1_SZ				0x004
163296936Smmel#define	AFI_AXI_BAR2_SZ				0x008
164296936Smmel#define	AFI_AXI_BAR3_SZ				0x00c
165296936Smmel#define	AFI_AXI_BAR4_SZ				0x010
166296936Smmel#define	AFI_AXI_BAR5_SZ				0x014
167296936Smmel#define	AFI_AXI_BAR0_START			0x018
168296936Smmel#define	AFI_AXI_BAR1_START			0x01c
169296936Smmel#define	AFI_AXI_BAR2_START			0x020
170296936Smmel#define	AFI_AXI_BAR3_START			0x024
171296936Smmel#define	AFI_AXI_BAR4_START			0x028
172296936Smmel#define	AFI_AXI_BAR5_START			0x02c
173296936Smmel#define	AFI_FPCI_BAR0				0x030
174296936Smmel#define	AFI_FPCI_BAR1				0x034
175296936Smmel#define	AFI_FPCI_BAR2				0x038
176296936Smmel#define	AFI_FPCI_BAR3				0x03c
177296936Smmel#define	AFI_FPCI_BAR4				0x040
178296936Smmel#define	AFI_FPCI_BAR5				0x044
179296936Smmel#define	AFI_MSI_BAR_SZ				0x060
180296936Smmel#define	AFI_MSI_FPCI_BAR_ST			0x064
181296936Smmel#define	AFI_MSI_AXI_BAR_ST			0x068
182296936Smmel
183296936Smmel
184296936Smmel#define	AFI_AXI_BAR6_SZ				0x134
185296936Smmel#define	AFI_AXI_BAR7_SZ				0x138
186296936Smmel#define	AFI_AXI_BAR8_SZ				0x13c
187296936Smmel#define	AFI_AXI_BAR6_START			0x140
188296936Smmel#define	AFI_AXI_BAR7_START			0x144
189296936Smmel#define	AFI_AXI_BAR8_START			0x148
190296936Smmel#define	AFI_FPCI_BAR6				0x14c
191296936Smmel#define	AFI_FPCI_BAR7				0x150
192296936Smmel#define	AFI_FPCI_BAR8				0x154
193296936Smmel
194296936Smmel#define	AFI_CONFIGURATION			0x0ac
195296936Smmel#define	 AFI_CONFIGURATION_EN_FPCI			(1 << 0)
196296936Smmel
197296936Smmel#define	AFI_FPCI_ERROR_MASKS			0x0b0
198296936Smmel#define	AFI_INTR_MASK				0x0b4
199296936Smmel#define	 AFI_INTR_MASK_MSI_MASK				(1 << 8)
200296936Smmel#define	 AFI_INTR_MASK_INT_MASK				(1 << 0)
201296936Smmel
202296936Smmel#define	AFI_INTR_CODE				0x0b8
203296936Smmel#define	 AFI_INTR_CODE_MASK				0xf
204296936Smmel#define	 AFI_INTR_CODE_INT_CODE_INI_SLVERR		1
205296936Smmel#define	 AFI_INTR_CODE_INT_CODE_INI_DECERR		2
206296936Smmel#define	 AFI_INTR_CODE_INT_CODE_TGT_SLVERR		3
207296936Smmel#define	 AFI_INTR_CODE_INT_CODE_TGT_DECERR		4
208296936Smmel#define	 AFI_INTR_CODE_INT_CODE_TGT_WRERR		5
209296936Smmel#define	 AFI_INTR_CODE_INT_CODE_SM_MSG			6
210296936Smmel#define	 AFI_INTR_CODE_INT_CODE_DFPCI_DECERR		7
211296936Smmel#define	 AFI_INTR_CODE_INT_CODE_AXI_DECERR		8
212296936Smmel#define	 AFI_INTR_CODE_INT_CODE_FPCI_TIMEOUT		9
213296936Smmel#define	 AFI_INTR_CODE_INT_CODE_PE_PRSNT_SENSE		10
214296936Smmel#define	 AFI_INTR_CODE_INT_CODE_PE_CLKREQ_SENSE		11
215296936Smmel#define	 AFI_INTR_CODE_INT_CODE_CLKCLAMP_SENSE		12
216296936Smmel#define	 AFI_INTR_CODE_INT_CODE_RDY4PD_SENSE		13
217296936Smmel#define	 AFI_INTR_CODE_INT_CODE_P2P_ERROR		14
218296936Smmel
219296936Smmel
220296936Smmel#define	AFI_INTR_SIGNATURE			0x0bc
221296936Smmel#define	AFI_UPPER_FPCI_ADDRESS			0x0c0
222296936Smmel#define	AFI_SM_INTR_ENABLE			0x0c4
223296936Smmel#define	 AFI_SM_INTR_RP_DEASSERT			(1 << 14)
224296936Smmel#define	 AFI_SM_INTR_RP_ASSERT				(1 << 13)
225296936Smmel#define	 AFI_SM_INTR_HOTPLUG				(1 << 12)
226296936Smmel#define	 AFI_SM_INTR_PME				(1 << 11)
227296936Smmel#define	 AFI_SM_INTR_FATAL_ERROR			(1 << 10)
228296936Smmel#define	 AFI_SM_INTR_UNCORR_ERROR			(1 <<  9)
229296936Smmel#define	 AFI_SM_INTR_CORR_ERROR				(1 <<  8)
230296936Smmel#define	 AFI_SM_INTR_INTD_DEASSERT			(1 <<  7)
231296936Smmel#define	 AFI_SM_INTR_INTC_DEASSERT			(1 <<  6)
232296936Smmel#define	 AFI_SM_INTR_INTB_DEASSERT			(1 <<  5)
233296936Smmel#define	 AFI_SM_INTR_INTA_DEASSERT			(1 <<  4)
234296936Smmel#define	 AFI_SM_INTR_INTD_ASSERT			(1 <<  3)
235296936Smmel#define	 AFI_SM_INTR_INTC_ASSERT			(1 <<  2)
236296936Smmel#define	 AFI_SM_INTR_INTB_ASSERT			(1 <<  1)
237296936Smmel#define	 AFI_SM_INTR_INTA_ASSERT			(1 <<  0)
238296936Smmel
239296936Smmel#define	AFI_AFI_INTR_ENABLE			0x0c8
240296936Smmel#define	 AFI_AFI_INTR_ENABLE_CODE(code)			(1 << (code))
241296936Smmel
242296936Smmel#define	AFI_PCIE_CONFIG				0x0f8
243296936Smmel#define	 AFI_PCIE_CONFIG_PCIE_DISABLE(x)		(1 << ((x) + 1))
244296936Smmel#define	 AFI_PCIE_CONFIG_PCIE_DISABLE_ALL		0x6
245296936Smmel#define	 AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_MASK	(0xf << 20)
246296936Smmel#define	 AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_XBAR2_1	(0x0 << 20)
247296936Smmel#define	 AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_XBAR4_1	(0x1 << 20)
248296936Smmel
249296936Smmel#define	AFI_FUSE				0x104
250296936Smmel#define	 AFI_FUSE_PCIE_T0_GEN2_DIS			(1 << 2)
251296936Smmel
252296936Smmel#define	AFI_PEX0_CTRL				0x110
253296936Smmel#define	AFI_PEX1_CTRL				0x118
254296936Smmel#define	AFI_PEX2_CTRL				0x128
255296936Smmel#define	 AFI_PEX_CTRL_OVERRIDE_EN			(1 << 4)
256296936Smmel#define	 AFI_PEX_CTRL_REFCLK_EN				(1 << 3)
257296936Smmel#define	 AFI_PEX_CTRL_CLKREQ_EN				(1 << 1)
258296936Smmel#define	 AFI_PEX_CTRL_RST_L				(1 << 0)
259296936Smmel
260296936Smmel#define	AFI_AXI_BAR6_SZ				0x134
261296936Smmel#define	AFI_AXI_BAR7_SZ				0x138
262296936Smmel#define	AFI_AXI_BAR8_SZ				0x13c
263296936Smmel#define	AFI_AXI_BAR6_START			0x140
264296936Smmel#define	AFI_AXI_BAR7_START			0x144
265296936Smmel#define	AFI_AXI_BAR8_START			0x148
266296936Smmel#define	AFI_FPCI_BAR6				0x14c
267296936Smmel#define	AFI_FPCI_BAR7				0x150
268296936Smmel#define	AFI_FPCI_BAR8				0x154
269296936Smmel#define	AFI_PLLE_CONTROL			0x160
270296936Smmel#define	 AFI_PLLE_CONTROL_BYPASS_PADS2PLLE_CONTROL	(1 << 9)
271296936Smmel#define	 AFI_PLLE_CONTROL_BYPASS_PCIE2PLLE_CONTROL	(1 << 8)
272296936Smmel#define	 AFI_PLLE_CONTROL_PADS2PLLE_CONTROL_EN		(1 << 1)
273296936Smmel#define	 AFI_PLLE_CONTROL_PCIE2PLLE_CONTROL_EN		(1 << 0)
274296936Smmel
275296936Smmel#define	AFI_PEXBIAS_CTRL			0x168
276296936Smmel
277296936Smmel/* FPCI Address space */
278296936Smmel#define	FPCI_MAP_IO			0xfdfc000000ULL
279296936Smmel#define	FPCI_MAP_TYPE0_CONFIG		0xfdfc000000ULL
280296936Smmel#define	FPCI_MAP_TYPE1_CONFIG		0xfdff000000ULL
281296936Smmel#define	FPCI_MAP_EXT_TYPE0_CONFIG	0xfe00000000ULL
282296936Smmel#define	FPCI_MAP_EXT_TYPE1_CONFIG	0xfe10000000ULL
283296936Smmel
284296936Smmel/* Configuration space */
285296936Smmel#define	RP_VEND_XP	0x00000F00
286296936Smmel#define	 RP_VEND_XP_DL_UP	(1 << 30)
287296936Smmel
288296936Smmel#define	RP_PRIV_MISC	0x00000FE0
289296936Smmel#define	 RP_PRIV_MISC_PRSNT_MAP_EP_PRSNT (0xE << 0)
290296936Smmel#define	 RP_PRIV_MISC_PRSNT_MAP_EP_ABSNT (0xF << 0)
291296936Smmel
292296936Smmel#define	RP_LINK_CONTROL_STATUS			0x00000090
293296936Smmel#define	 RP_LINK_CONTROL_STATUS_DL_LINK_ACTIVE	0x20000000
294296936Smmel#define	 RP_LINK_CONTROL_STATUS_LINKSTAT_MASK	0x3fff0000
295296936Smmel
296296936Smmel#define	TEGRA_PCIE_LINKUP_TIMEOUT	200
297296936Smmel
298296936Smmel#define	DEBUG
299296936Smmel#ifdef DEBUG
300296936Smmel#define	debugf(fmt, args...) do { printf(fmt,##args); } while (0)
301296936Smmel#else
302296936Smmel#define	debugf(fmt, args...)
303296936Smmel#endif
304296936Smmel
305296936Smmel/*
306296936Smmel * Configuration space format:
307296936Smmel *    [27:24] extended register
308296936Smmel *    [23:16] bus
309296936Smmel *    [15:11] slot (device)
310296936Smmel *    [10: 8] function
311296936Smmel *    [ 7: 0] register
312296936Smmel */
313296936Smmel#define	PCI_CFG_EXT_REG(reg)	((((reg) >> 8) & 0x0f) << 24)
314296936Smmel#define	PCI_CFG_BUS(bus)	(((bus) & 0xff) << 16)
315296936Smmel#define	PCI_CFG_DEV(dev)	(((dev) & 0x1f) << 11)
316296936Smmel#define	PCI_CFG_FUN(fun)	(((fun) & 0x07) << 8)
317296936Smmel#define	PCI_CFG_BASE_REG(reg)	((reg)  & 0xff)
318296936Smmel
319296936Smmel#define	PADS_WR4(_sc, _r, _v)	bus_write_4((_sc)-pads_mem_res, (_r), (_v))
320296936Smmel#define	PADS_RD4(_sc, _r)	bus_read_4((_sc)->pads_mem_res, (_r))
321296936Smmel#define	AFI_WR4(_sc, _r, _v)	bus_write_4((_sc)->afi_mem_res, (_r), (_v))
322296936Smmel#define	AFI_RD4(_sc, _r)	bus_read_4((_sc)->afi_mem_res, (_r))
323296936Smmel
324296936Smmelstatic struct {
325296936Smmel	bus_size_t	axi_start;
326296936Smmel	bus_size_t	fpci_start;
327296936Smmel	bus_size_t	size;
328296936Smmel} bars[] = {
329296936Smmel    {AFI_AXI_BAR0_START, AFI_FPCI_BAR0, AFI_AXI_BAR0_SZ},	/* BAR 0 */
330296936Smmel    {AFI_AXI_BAR1_START, AFI_FPCI_BAR1, AFI_AXI_BAR1_SZ},	/* BAR 1 */
331296936Smmel    {AFI_AXI_BAR2_START, AFI_FPCI_BAR2, AFI_AXI_BAR2_SZ},	/* BAR 2 */
332296936Smmel    {AFI_AXI_BAR3_START, AFI_FPCI_BAR3, AFI_AXI_BAR3_SZ},	/* BAR 3 */
333296936Smmel    {AFI_AXI_BAR4_START, AFI_FPCI_BAR4, AFI_AXI_BAR4_SZ},	/* BAR 4 */
334296936Smmel    {AFI_AXI_BAR5_START, AFI_FPCI_BAR5, AFI_AXI_BAR5_SZ},	/* BAR 5 */
335296936Smmel    {AFI_AXI_BAR6_START, AFI_FPCI_BAR6, AFI_AXI_BAR6_SZ},	/* BAR 6 */
336296936Smmel    {AFI_AXI_BAR7_START, AFI_FPCI_BAR7, AFI_AXI_BAR7_SZ},	/* BAR 7 */
337296936Smmel    {AFI_AXI_BAR8_START, AFI_FPCI_BAR8, AFI_AXI_BAR8_SZ},	/* BAR 8 */
338296936Smmel    {AFI_MSI_AXI_BAR_ST, AFI_MSI_FPCI_BAR_ST, AFI_MSI_BAR_SZ},	/* MSI 9 */
339296936Smmel};
340296936Smmel
341296936Smmel/* Compatible devices. */
342296936Smmelstatic struct ofw_compat_data compat_data[] = {
343296936Smmel	{"nvidia,tegra124-pcie",	1},
344296936Smmel	{NULL,		 		0},
345296936Smmel};
346296936Smmel
347296936Smmelstruct tegra_pcib_port {
348296936Smmel	int		enabled;
349296936Smmel	int 		port_idx;		/* chip port index */
350296936Smmel	int		num_lanes;		/* number of lanes */
351296936Smmel	bus_size_t	afi_pex_ctrl;		/* offset of afi_pex_ctrl */
352296936Smmel
353296936Smmel	/* Config space properties. */
354296936Smmel	bus_addr_t	rp_base_addr;		/* PA of config window */
355296936Smmel	bus_size_t	rp_size;		/* size of config window */
356296936Smmel	bus_space_handle_t cfg_handle;		/* handle of config window */
357296936Smmel};
358296936Smmel
359296936Smmel#define	TEGRA_PCIB_MAX_PORTS	3
360296936Smmelstruct tegra_pcib_softc {
361296936Smmel	device_t		dev;
362296936Smmel	struct mtx		mtx;
363296936Smmel	struct ofw_bus_iinfo	pci_iinfo;
364296936Smmel	struct rman		pref_mem_rman;
365296936Smmel	struct rman		mem_rman;
366296936Smmel	struct rman		io_rman;
367296936Smmel	struct resource		*pads_mem_res;
368296936Smmel	struct resource		*afi_mem_res;
369296936Smmel	struct resource		*cfg_mem_res;
370296936Smmel	struct resource 	*irq_res;
371296936Smmel	struct resource 	*msi_irq_res;
372296936Smmel	void			*intr_cookie;
373296936Smmel	void			*msi_intr_cookie;
374296936Smmel
375296936Smmel	struct tegra_pci_range	mem_range;
376296936Smmel	struct tegra_pci_range	pref_mem_range;
377296936Smmel	struct tegra_pci_range	io_range;
378296936Smmel
379296936Smmel	phy_t			phy;
380296936Smmel	clk_t			clk_pex;
381296936Smmel	clk_t			clk_afi;
382296936Smmel	clk_t			clk_pll_e;
383296936Smmel	clk_t			clk_cml;
384296936Smmel	hwreset_t			hwreset_pex;
385296936Smmel	hwreset_t			hwreset_afi;
386296936Smmel	hwreset_t			hwreset_pcie_x;
387296936Smmel	regulator_t		supply_avddio_pex;
388296936Smmel	regulator_t		supply_dvddio_pex;
389296936Smmel	regulator_t		supply_avdd_pex_pll;
390296936Smmel	regulator_t		supply_hvdd_pex;
391296936Smmel	regulator_t		supply_hvdd_pex_pll_e;
392296936Smmel	regulator_t		supply_vddio_pex_ctl;
393296936Smmel	regulator_t		supply_avdd_pll_erefe;
394296936Smmel
395296936Smmel	int			busnr;		/* host bridge bus number */
396296936Smmel	uint32_t		msi_bitmap;
397296936Smmel	bus_addr_t		cfg_base_addr;	/* base address of config */
398296936Smmel	bus_size_t		cfg_cur_offs; 	/* currently mapped window */
399296936Smmel	bus_space_handle_t 	cfg_handle;	/* handle of config window */
400296936Smmel	bus_space_tag_t 	bus_tag;	/* tag of config window */
401296936Smmel	int			lanes_cfg;
402296936Smmel	int			num_ports;
403296936Smmel	struct tegra_pcib_port *ports[TEGRA_PCIB_MAX_PORTS];
404296936Smmel};
405296936Smmel
406296936Smmel/* ------------------------------------------------------------------------- */
407296936Smmel/*
408296936Smmel * Resource manager
409296936Smmel */
410296936Smmelstatic int
411296936Smmeltegra_pcib_rman_init(struct tegra_pcib_softc *sc)
412296936Smmel{
413296936Smmel	int err;
414296936Smmel	char buf[64];
415296936Smmel
416296936Smmel	/* Memory management. */
417296936Smmel	sc->pref_mem_rman.rm_type = RMAN_ARRAY;
418296936Smmel	snprintf(buf, sizeof(buf), "%s prefetchable memory space",
419296936Smmel	    device_get_nameunit(sc->dev));
420296936Smmel	sc->pref_mem_rman.rm_descr = strdup(buf, M_DEVBUF);
421296936Smmel	err = rman_init(&sc->pref_mem_rman);
422296936Smmel	if (err)
423296936Smmel		return (err);
424296936Smmel
425296936Smmel	sc->mem_rman.rm_type = RMAN_ARRAY;
426296936Smmel	snprintf(buf, sizeof(buf), "%s non prefetchable memory space",
427296936Smmel	    device_get_nameunit(sc->dev));
428296936Smmel	sc->mem_rman.rm_descr = strdup(buf, M_DEVBUF);
429296936Smmel	err = rman_init(&sc->mem_rman);
430296936Smmel	if (err)
431296936Smmel		return (err);
432296936Smmel
433296936Smmel	sc->io_rman.rm_type = RMAN_ARRAY;
434296936Smmel	snprintf(buf, sizeof(buf), "%s I/O space",
435296936Smmel	    device_get_nameunit(sc->dev));
436296936Smmel	sc->io_rman.rm_descr = strdup(buf, M_DEVBUF);
437296936Smmel	err = rman_init(&sc->io_rman);
438296936Smmel	if (err) {
439296936Smmel		rman_fini(&sc->mem_rman);
440296936Smmel		return (err);
441296936Smmel	}
442296936Smmel
443296936Smmel	err = rman_manage_region(&sc->pref_mem_rman,
444296936Smmel	    sc->pref_mem_range.host_addr,
445296936Smmel	    sc->pref_mem_range.host_addr + sc->pref_mem_range.size - 1);
446296936Smmel	if (err)
447296936Smmel		goto error;
448296936Smmel	err = rman_manage_region(&sc->mem_rman,
449296936Smmel	    sc->mem_range.host_addr,
450296936Smmel	    sc->mem_range.host_addr + sc->mem_range.size - 1);
451296936Smmel	if (err)
452296936Smmel		goto error;
453296936Smmel	err = rman_manage_region(&sc->io_rman,
454296936Smmel	    sc->io_range.pci_addr,
455296936Smmel	    sc->io_range.pci_addr + sc->io_range.size - 1);
456296936Smmel	if (err)
457296936Smmel		goto error;
458296936Smmel	return (0);
459296936Smmel
460296936Smmelerror:
461296936Smmel	rman_fini(&sc->pref_mem_rman);
462296936Smmel	rman_fini(&sc->mem_rman);
463296936Smmel	rman_fini(&sc->io_rman);
464296936Smmel	return (err);
465296936Smmel}
466296936Smmel
467296936Smmelstatic struct rman *
468296936Smmeltegra_pcib_rman(struct tegra_pcib_softc *sc, int type, u_int flags)
469296936Smmel{
470296936Smmel
471296936Smmel	switch (type) {
472296936Smmel	case SYS_RES_IOPORT:
473296936Smmel		return (&sc->io_rman);
474296936Smmel	case SYS_RES_MEMORY:
475296936Smmel		if (flags & RF_PREFETCHABLE)
476296936Smmel			return (&sc->pref_mem_rman);
477296936Smmel		else
478296936Smmel			return (&sc->mem_rman);
479296936Smmel	default:
480296936Smmel		break;
481296936Smmel	}
482296936Smmel
483296936Smmel	return (NULL);
484296936Smmel}
485296936Smmel
486296936Smmelstatic struct resource *
487296936Smmeltegra_pcib_alloc_resource(device_t dev, device_t child, int type, int *rid,
488296936Smmel    rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
489296936Smmel{
490296936Smmel	struct tegra_pcib_softc *sc;
491296936Smmel	struct rman *rm;
492296936Smmel	struct resource *res;
493296936Smmel
494297011Smmel	debugf("%s: enter %d start %#jx end %#jx count %#jx\n", __func__,
495296936Smmel	    type, start, end, count);
496296936Smmel	sc = device_get_softc(dev);
497296936Smmel
498296936Smmel#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
499296936Smmel	if (type ==  PCI_RES_BUS) {
500296936Smmel		  return (pci_domain_alloc_bus(0, child, rid, start, end, count,
501296936Smmel					       flags));
502296936Smmel	}
503296936Smmel#endif
504296936Smmel
505296936Smmel	rm = tegra_pcib_rman(sc, type, flags);
506296936Smmel
507296936Smmel	if (rm == NULL) {
508296936Smmel		res = BUS_ALLOC_RESOURCE(device_get_parent(dev), dev,
509296936Smmel		    type, rid, start, end, count, flags);
510296936Smmel
511296936Smmel		return (res);
512296936Smmel	}
513296936Smmel
514296936Smmel	if (bootverbose) {
515296936Smmel		device_printf(dev,
516297011Smmel		    "rman_reserve_resource: start=%#jx, end=%#jx, count=%#jx\n",
517296936Smmel		    start, end, count);
518296936Smmel	}
519296936Smmel
520296936Smmel	res = rman_reserve_resource(rm, start, end, count, flags, child);
521296936Smmel	if (res == NULL)
522296936Smmel		goto fail;
523296936Smmel	rman_set_rid(res, *rid);
524296936Smmel	if (flags & RF_ACTIVE) {
525296936Smmel		if (bus_activate_resource(child, type, *rid, res)) {
526296936Smmel			rman_release_resource(res);
527296936Smmel			goto fail;
528296936Smmel		}
529296936Smmel	}
530296936Smmel	return (res);
531296936Smmel
532296936Smmelfail:
533296936Smmel	if (bootverbose) {
534296936Smmel		device_printf(dev, "%s FAIL: type=%d, rid=%d, "
535297011Smmel		    "start=%016jx, end=%016jx, count=%016jx, flags=%x\n",
536296936Smmel		    __func__, type, *rid, start, end, count, flags);
537296936Smmel	}
538296936Smmel
539296936Smmel	return (NULL);
540296936Smmel}
541296936Smmel
542296936Smmelstatic int
543296936Smmeltegra_pcib_release_resource(device_t dev, device_t child, int type, int rid,
544296936Smmel    struct resource *res)
545296936Smmel{
546296936Smmel	struct tegra_pcib_softc *sc;
547296936Smmel	struct rman *rm;
548296936Smmel
549296936Smmel	sc = device_get_softc(dev);
550296936Smmel	debugf("%s: %d rid %x\n",  __func__, type, rid);
551296936Smmel
552296936Smmel#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
553296936Smmel	if (type == PCI_RES_BUS)
554296936Smmel		return (pci_domain_release_bus(0, child, rid, res));
555296936Smmel#endif
556296936Smmel
557296936Smmel	rm = tegra_pcib_rman(sc, type, rman_get_flags(res));
558296936Smmel	if (rm != NULL) {
559296936Smmel		KASSERT(rman_is_region_manager(res, rm), ("rman mismatch"));
560296936Smmel		rman_release_resource(res);
561296936Smmel	}
562296936Smmel
563296936Smmel	return (bus_generic_release_resource(dev, child, type, rid, res));
564296936Smmel}
565296936Smmel
566296936Smmelstatic int
567296936Smmeltegra_pcib_adjust_resource(device_t dev, device_t child, int type,
568297011Smmel			    struct resource *res, rman_res_t start, rman_res_t end)
569296936Smmel{
570296936Smmel	struct tegra_pcib_softc *sc;
571296936Smmel	struct rman *rm;
572296936Smmel
573296936Smmel	sc = device_get_softc(dev);
574297011Smmel	debugf("%s: %d start %jx end %jx \n", __func__, type, start, end);
575296936Smmel
576296936Smmel#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
577296936Smmel	if (type == PCI_RES_BUS)
578296936Smmel		return (pci_domain_adjust_bus(0, child, res, start, end));
579296936Smmel#endif
580296936Smmel
581296936Smmel	rm = tegra_pcib_rman(sc, type, rman_get_flags(res));
582296936Smmel	if (rm != NULL)
583296936Smmel		return (rman_adjust_resource(res, start, end));
584296936Smmel	return (bus_generic_adjust_resource(dev, child, type, res, start, end));
585296936Smmel}
586296936Smmelextern bus_space_tag_t fdtbus_bs_tag;
587296936Smmelstatic int
588296936Smmeltegra_pcib_pcie_activate_resource(device_t dev, device_t child, int type,
589296936Smmel    int rid, struct resource *r)
590296936Smmel{
591296936Smmel	struct tegra_pcib_softc *sc;
592296936Smmel	vm_offset_t start;
593296936Smmel	void *p;
594296936Smmel	int rv;
595296936Smmel
596296936Smmel	sc = device_get_softc(dev);
597296936Smmel	rv = rman_activate_resource(r);
598296936Smmel	if (rv != 0)
599296936Smmel		return (rv);
600296936Smmel	switch(type) {
601296936Smmel	case SYS_RES_IOPORT:
602296936Smmel		start = rman_get_start(r) + sc->io_range.host_addr;
603296936Smmel		break;
604296936Smmel	default:
605296936Smmel		start = rman_get_start(r);
606296936Smmel		rman_get_start(r);
607296936Smmel		break;
608296936Smmel	}
609296936Smmel
610296936Smmel	if (bootverbose)
611297011Smmel		printf("%s: start %zx, len %jd\n", __func__, start,
612296936Smmel			rman_get_size(r));
613296936Smmel
614296936Smmel	p = pmap_mapdev(start, (vm_size_t)rman_get_size(r));
615296936Smmel	rman_set_virtual(r, p);
616296936Smmel	rman_set_bustag(r, fdtbus_bs_tag);
617296936Smmel	rman_set_bushandle(r, (u_long)p);
618296936Smmel	return (0);
619296936Smmel}
620296936Smmel
621296936Smmel/* ------------------------------------------------------------------------- */
622296936Smmel/*
623296936Smmel * IVARs
624296936Smmel */
625296936Smmelstatic int
626296936Smmeltegra_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
627296936Smmel{
628296936Smmel	struct tegra_pcib_softc *sc = device_get_softc(dev);
629296936Smmel
630296936Smmel	switch (which) {
631296936Smmel	case PCIB_IVAR_BUS:
632296936Smmel		*result = sc->busnr;
633296936Smmel		return (0);
634296936Smmel	case PCIB_IVAR_DOMAIN:
635296936Smmel		*result = device_get_unit(dev);
636296936Smmel		return (0);
637296936Smmel	}
638296936Smmel
639296936Smmel	return (ENOENT);
640296936Smmel}
641296936Smmel
642296936Smmelstatic int
643296936Smmeltegra_pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
644296936Smmel{
645296936Smmel	struct tegra_pcib_softc *sc = device_get_softc(dev);
646296936Smmel
647296936Smmel	switch (which) {
648296936Smmel	case PCIB_IVAR_BUS:
649296936Smmel		sc->busnr = value;
650296936Smmel		return (0);
651296936Smmel	}
652296936Smmel
653296936Smmel	return (ENOENT);
654296936Smmel}
655296936Smmel
656296936Smmelstatic int
657296936Smmeltegra_pcib_maxslots(device_t dev)
658296936Smmel{
659296936Smmel	return (16);
660296936Smmel}
661296936Smmel
662296936Smmel
663296936Smmelstatic int
664296936Smmeltegra_pcib_route_interrupt(device_t bus, device_t dev, int pin)
665296936Smmel{
666296936Smmel	struct tegra_pcib_softc *sc;
667296936Smmel
668296936Smmel	sc = device_get_softc(bus);
669297011Smmel	device_printf(bus, "route pin %d for device %d.%d to %ju\n",
670296936Smmel		      pin, pci_get_slot(dev), pci_get_function(dev),
671296936Smmel		      rman_get_start(sc->irq_res));
672296936Smmel
673296936Smmel	return (rman_get_start(sc->irq_res));
674296936Smmel}
675296936Smmel
676296936Smmelstatic int
677296936Smmeltegra_pcbib_map_cfg(struct tegra_pcib_softc *sc, u_int bus, u_int slot,
678296936Smmel    u_int func, u_int reg)
679296936Smmel{
680296936Smmel	bus_size_t offs;
681296936Smmel	int rv;
682296936Smmel
683296936Smmel	offs = sc->cfg_base_addr;
684296936Smmel	offs |= PCI_CFG_BUS(bus) | PCI_CFG_DEV(slot) | PCI_CFG_FUN(func) |
685296936Smmel	    PCI_CFG_EXT_REG(reg);
686296936Smmel	if ((sc->cfg_handle != 0) && (sc->cfg_cur_offs == offs))
687296936Smmel		return (0);
688296936Smmel	if (sc->cfg_handle != 0)
689296936Smmel		bus_space_unmap(sc->bus_tag, sc->cfg_handle, 0x800);
690296936Smmel
691296936Smmel	rv = bus_space_map(sc->bus_tag, offs, 0x800, 0, &sc->cfg_handle);
692296936Smmel	if (rv != 0)
693296936Smmel		device_printf(sc->dev, "Cannot map config space\n");
694296936Smmel	else
695296936Smmel		sc->cfg_cur_offs = offs;
696296936Smmel	return (rv);
697296936Smmel}
698296936Smmel
699296936Smmelstatic uint32_t
700296936Smmeltegra_pcib_read_config(device_t dev, u_int bus, u_int slot, u_int func,
701296936Smmel    u_int reg, int bytes)
702296936Smmel{
703296936Smmel	struct tegra_pcib_softc *sc;
704296936Smmel	bus_space_handle_t hndl;
705296936Smmel	uint32_t off;
706296936Smmel	uint32_t val;
707296936Smmel	int rv, i;
708296936Smmel
709296936Smmel	sc = device_get_softc(dev);
710296936Smmel	if (bus == 0) {
711296936Smmel		if (func != 0)
712296936Smmel			return (0xFFFFFFFF);
713296936Smmel		for (i = 0; i < TEGRA_PCIB_MAX_PORTS; i++) {
714296936Smmel			if ((sc->ports[i] != NULL) &&
715296936Smmel			    (sc->ports[i]->port_idx == slot)) {
716296936Smmel				hndl = sc->ports[i]->cfg_handle;
717296936Smmel				off = reg & 0xFFF;
718296936Smmel				break;
719296936Smmel			}
720296936Smmel		}
721296936Smmel		if (i >= TEGRA_PCIB_MAX_PORTS)
722296936Smmel			return (0xFFFFFFFF);
723296936Smmel	} else {
724296936Smmel		rv = tegra_pcbib_map_cfg(sc, bus, slot, func, reg);
725296936Smmel		if (rv != 0)
726296936Smmel			return (0xFFFFFFFF);
727296936Smmel		hndl = sc->cfg_handle;
728296936Smmel		off = PCI_CFG_BASE_REG(reg);
729296936Smmel	}
730296936Smmel
731296936Smmel	val = bus_space_read_4(sc->bus_tag, hndl, off & ~3);
732296936Smmel	switch (bytes) {
733296936Smmel	case 4:
734296936Smmel		break;
735296936Smmel	case 2:
736296936Smmel		if (off & 3)
737296936Smmel			val >>= 16;
738296936Smmel		val &= 0xffff;
739296936Smmel		break;
740296936Smmel	case 1:
741296936Smmel		val >>= ((off & 3) << 3);
742296936Smmel		val &= 0xff;
743296936Smmel		break;
744296936Smmel	}
745296936Smmel	return val;
746296936Smmel}
747296936Smmel
748296936Smmelstatic void
749296936Smmeltegra_pcib_write_config(device_t dev, u_int bus, u_int slot, u_int func,
750296936Smmel    u_int reg, uint32_t val, int bytes)
751296936Smmel{
752296936Smmel	struct tegra_pcib_softc *sc;
753296936Smmel	bus_space_handle_t hndl;
754296936Smmel	uint32_t off;
755296936Smmel	uint32_t val2;
756296936Smmel	int rv, i;
757296936Smmel
758296936Smmel	sc = device_get_softc(dev);
759296936Smmel	if (bus == 0) {
760296936Smmel		if (func != 0)
761296936Smmel			return;
762296936Smmel		for (i = 0; i < TEGRA_PCIB_MAX_PORTS; i++) {
763296936Smmel			if ((sc->ports[i] != NULL) &&
764296936Smmel			    (sc->ports[i]->port_idx == slot)) {
765296936Smmel				hndl = sc->ports[i]->cfg_handle;
766296936Smmel				off = reg & 0xFFF;
767296936Smmel				break;
768296936Smmel			}
769296936Smmel		}
770296936Smmel		if (i >= TEGRA_PCIB_MAX_PORTS)
771296936Smmel			return;
772296936Smmel	} else {
773296936Smmel		rv = tegra_pcbib_map_cfg(sc, bus, slot, func, reg);
774296936Smmel		if (rv != 0)
775296936Smmel			return;
776296936Smmel		hndl = sc->cfg_handle;
777296936Smmel		off = PCI_CFG_BASE_REG(reg);
778296936Smmel	}
779296936Smmel
780296936Smmel	switch (bytes) {
781296936Smmel	case 4:
782296936Smmel		bus_space_write_4(sc->bus_tag, hndl, off, val);
783296936Smmel		break;
784296936Smmel	case 2:
785296936Smmel		val2 = bus_space_read_4(sc->bus_tag, hndl, off & ~3);
786296936Smmel		val2 &= ~(0xffff << ((off & 3) << 3));
787296936Smmel		val2 |= ((val & 0xffff) << ((off & 3) << 3));
788296936Smmel		bus_space_write_4(sc->bus_tag, hndl, off & ~3, val2);
789296936Smmel		break;
790296936Smmel	case 1:
791296936Smmel		val2 = bus_space_read_4(sc->bus_tag, hndl, off & ~3);
792296936Smmel		val2 &= ~(0xff << ((off & 3) << 3));
793296936Smmel		val2 |= ((val & 0xff) << ((off & 3) << 3));
794296936Smmel		bus_space_write_4(sc->bus_tag, hndl, off & ~3, val2);
795296936Smmel		break;
796296936Smmel	}
797296936Smmel}
798296936Smmel
799296936Smmelstatic int tegra_pci_intr(void *arg)
800296936Smmel{
801296936Smmel	struct tegra_pcib_softc *sc = arg;
802296936Smmel	uint32_t code, signature;
803296936Smmel
804296936Smmel	code = bus_read_4(sc->afi_mem_res, AFI_INTR_CODE) & AFI_INTR_CODE_MASK;
805296936Smmel	signature = bus_read_4(sc->afi_mem_res, AFI_INTR_SIGNATURE);
806296936Smmel	bus_write_4(sc->afi_mem_res, AFI_INTR_CODE, 0);
807296936Smmel	if (code == AFI_INTR_CODE_INT_CODE_SM_MSG)
808296936Smmel		return(FILTER_STRAY);
809296936Smmel
810296936Smmel	printf("tegra_pci_intr: code %x sig %x\n", code, signature);
811296936Smmel	return (FILTER_HANDLED);
812296936Smmel}
813296936Smmel
814296936Smmel#if defined(TEGRA_PCI_MSI)
815296936Smmelstatic int
816296936Smmeltegra_pcib_map_msi(device_t dev, device_t child, int irq, uint64_t *addr,
817296936Smmel    uint32_t *data)
818296936Smmel{
819296936Smmel	struct tegra_pcib_softc *sc;
820296936Smmel
821296936Smmel	sc = device_get_softc(dev);
822296936Smmel	irq = irq - MSI_IRQ;
823296936Smmel
824296936Smmel	/* validate parameters */
825296936Smmel	if (isclr(&sc->msi_bitmap, irq)) {
826296936Smmel		device_printf(dev, "invalid MSI 0x%x\n", irq);
827296936Smmel		return (EINVAL);
828296936Smmel	}
829296936Smmel
830296936Smmel	tegra_msi_data(irq, addr, data);
831296936Smmel
832296936Smmel	debugf("%s: irq: %d addr: %jx data: %x\n",
833296936Smmel	    __func__, irq, *addr, *data);
834296936Smmel
835296936Smmel	return (0);
836296936Smmel}
837296936Smmel
838296936Smmelstatic int
839296936Smmeltegra_pcib_alloc_msi(device_t dev, device_t child, int count,
840296936Smmel    int maxcount __unused, int *irqs)
841296936Smmel{
842296936Smmel	struct tegra_pcib_softc *sc;
843296936Smmel	u_int start = 0, i;
844296936Smmel
845296936Smmel	if (powerof2(count) == 0 || count > MSI_IRQ_NUM)
846296936Smmel		return (EINVAL);
847296936Smmel
848296936Smmel	sc = device_get_softc(dev);
849296936Smmel	mtx_lock(&sc->mtx);
850296936Smmel
851296936Smmel	for (start = 0; (start + count) < MSI_IRQ_NUM; start++) {
852296936Smmel		for (i = start; i < start + count; i++) {
853296936Smmel			if (isset(&sc->msi_bitmap, i))
854296936Smmel				break;
855296936Smmel		}
856296936Smmel		if (i == start + count)
857296936Smmel			break;
858296936Smmel	}
859296936Smmel
860296936Smmel	if ((start + count) == MSI_IRQ_NUM) {
861296936Smmel		mtx_unlock(&sc->mtx);
862296936Smmel		return (ENXIO);
863296936Smmel	}
864296936Smmel
865296936Smmel	for (i = start; i < start + count; i++) {
866296936Smmel		setbit(&sc->msi_bitmap, i);
867296936Smmel		irqs[i] = MSI_IRQ + i;
868296936Smmel	}
869296936Smmel	debugf("%s: start: %x count: %x\n", __func__, start, count);
870296936Smmel
871296936Smmel	mtx_unlock(&sc->mtx);
872296936Smmel	return (0);
873296936Smmel}
874296936Smmel
875296936Smmelstatic int
876296936Smmeltegra_pcib_release_msi(device_t dev, device_t child, int count, int *irqs)
877296936Smmel{
878296936Smmel	struct tegra_pcib_softc *sc;
879296936Smmel	u_int i;
880296936Smmel
881296936Smmel	sc = device_get_softc(dev);
882296936Smmel	mtx_lock(&sc->mtx);
883296936Smmel
884296936Smmel	for (i = 0; i < count; i++)
885296936Smmel		clrbit(&sc->msi_bitmap, irqs[i] - MSI_IRQ);
886296936Smmel
887296936Smmel	mtx_unlock(&sc->mtx);
888296936Smmel	return (0);
889296936Smmel}
890296936Smmel#endif
891296936Smmel
892296936Smmelstatic bus_size_t
893296936Smmeltegra_pcib_pex_ctrl(struct tegra_pcib_softc *sc, int port)
894296936Smmel{
895296936Smmel	if (port >= TEGRA_PCIB_MAX_PORTS)
896296936Smmel		panic("invalid port number: %d\n", port);
897296936Smmel
898296936Smmel	if (port == 0)
899296936Smmel		return (AFI_PEX0_CTRL);
900296936Smmel	else if (port == 1)
901296936Smmel		return (AFI_PEX1_CTRL);
902296936Smmel	else if (port == 2)
903296936Smmel		return (AFI_PEX2_CTRL);
904296936Smmel	else
905296936Smmel		panic("invalid port number: %d\n", port);
906296936Smmel}
907296936Smmel
908296936Smmelstatic int
909296936Smmeltegra_pcib_enable_fdt_resources(struct tegra_pcib_softc *sc)
910296936Smmel{
911296936Smmel	int rv;
912296936Smmel
913296936Smmel	rv = hwreset_assert(sc->hwreset_pcie_x);
914296936Smmel	if (rv != 0) {
915296936Smmel		device_printf(sc->dev, "Cannot assert 'pcie_x' reset\n");
916296936Smmel		return (rv);
917296936Smmel	}
918296936Smmel	rv = hwreset_assert(sc->hwreset_afi);
919296936Smmel	if (rv != 0) {
920296936Smmel		device_printf(sc->dev, "Cannot assert  'afi' reset\n");
921296936Smmel		return (rv);
922296936Smmel	}
923296936Smmel	rv = hwreset_assert(sc->hwreset_pex);
924296936Smmel	if (rv != 0) {
925296936Smmel		device_printf(sc->dev, "Cannot assert  'pex' reset\n");
926296936Smmel		return (rv);
927296936Smmel	}
928296936Smmel
929296936Smmel	tegra_powergate_power_off(TEGRA_POWERGATE_PCX);
930296936Smmel
931296936Smmel	/* Power supplies. */
932296936Smmel	rv = regulator_enable(sc->supply_avddio_pex);
933296936Smmel	if (rv != 0) {
934296936Smmel		device_printf(sc->dev,
935296936Smmel		    "Cannot enable 'avddio_pex' regulator\n");
936296936Smmel		return (rv);
937296936Smmel	}
938296936Smmel	rv = regulator_enable(sc->supply_dvddio_pex);
939296936Smmel	if (rv != 0) {
940296936Smmel		device_printf(sc->dev,
941296936Smmel		    "Cannot enable 'dvddio_pex' regulator\n");
942296936Smmel		return (rv);
943296936Smmel	}
944296936Smmel	rv = regulator_enable(sc->supply_avdd_pex_pll);
945296936Smmel	if (rv != 0) {
946296936Smmel		device_printf(sc->dev,
947296936Smmel		    "Cannot enable 'avdd-pex-pll' regulator\n");
948296936Smmel		return (rv);
949296936Smmel	}
950296936Smmel
951296936Smmel	rv = regulator_enable(sc->supply_hvdd_pex);
952296936Smmel	if (rv != 0) {
953296936Smmel		device_printf(sc->dev,
954296936Smmel		    "Cannot enable 'hvdd-pex-supply' regulator\n");
955296936Smmel		return (rv);
956296936Smmel	}
957296936Smmel	rv = regulator_enable(sc->supply_hvdd_pex_pll_e);
958296936Smmel	if (rv != 0) {
959296936Smmel		device_printf(sc->dev,
960296936Smmel		    "Cannot enable 'hvdd-pex-pll-e-supply' regulator\n");
961296936Smmel		return (rv);
962296936Smmel	}
963296936Smmel	rv = regulator_enable(sc->supply_vddio_pex_ctl);
964296936Smmel	if (rv != 0) {
965296936Smmel		device_printf(sc->dev,
966296936Smmel		    "Cannot enable 'vddio-pex-ctl' regulator\n");
967296936Smmel		return (rv);
968296936Smmel	}
969296936Smmel	rv = regulator_enable(sc->supply_avdd_pll_erefe);
970296936Smmel	if (rv != 0) {
971296936Smmel		device_printf(sc->dev,
972296936Smmel		    "Cannot enable 'avdd-pll-erefe-supply' regulator\n");
973296936Smmel		return (rv);
974296936Smmel	}
975296936Smmel
976296936Smmel	rv = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_PCX,
977296936Smmel	    sc->clk_pex, sc->hwreset_pex);
978296936Smmel	if (rv != 0) {
979296936Smmel		device_printf(sc->dev, "Cannot enable 'PCX' powergate\n");
980296936Smmel		return (rv);
981296936Smmel	}
982296936Smmel
983296936Smmel	rv = hwreset_deassert(sc->hwreset_afi);
984296936Smmel	if (rv != 0) {
985296936Smmel		device_printf(sc->dev, "Cannot unreset 'afi' reset\n");
986296936Smmel		return (rv);
987296936Smmel	}
988296936Smmel
989296936Smmel	rv = clk_enable(sc->clk_afi);
990296936Smmel	if (rv != 0) {
991296936Smmel		device_printf(sc->dev, "Cannot enable 'afi' clock\n");
992296936Smmel		return (rv);
993296936Smmel	}
994296936Smmel
995296936Smmel	rv = clk_enable(sc->clk_cml);
996296936Smmel	if (rv != 0) {
997296936Smmel		device_printf(sc->dev, "Cannot enable 'cml' clock\n");
998296936Smmel		return (rv);
999296936Smmel	}
1000296936Smmel
1001296936Smmel	rv = clk_enable(sc->clk_pll_e);
1002296936Smmel	if (rv != 0) {
1003296936Smmel		device_printf(sc->dev, "Cannot enable 'pll_e' clock\n");
1004296936Smmel		return (rv);
1005296936Smmel	}
1006296936Smmel	return (0);
1007296936Smmel}
1008296936Smmel
1009296936Smmelstatic struct tegra_pcib_port *
1010296936Smmeltegra_pcib_parse_port(struct tegra_pcib_softc *sc, phandle_t node)
1011296936Smmel{
1012296936Smmel	struct tegra_pcib_port *port;
1013296936Smmel	uint32_t tmp[5];
1014296936Smmel	char tmpstr[6];
1015296936Smmel	int rv;
1016296936Smmel
1017296936Smmel	port = malloc(sizeof(struct tegra_pcib_port), M_DEVBUF, M_WAITOK);
1018296936Smmel
1019296936Smmel	rv = OF_getprop(node, "status", tmpstr, sizeof(tmpstr));
1020296936Smmel	if (rv <= 0 || strcmp(tmpstr, "okay") == 0 ||
1021296936Smmel	   strcmp(tmpstr, "ok") == 0)
1022296936Smmel		port->enabled = 1;
1023296936Smmel	else
1024296936Smmel		port->enabled = 0;
1025296936Smmel
1026296936Smmel	rv = OF_getencprop(node, "assigned-addresses", tmp, sizeof(tmp));
1027296936Smmel	if (rv != sizeof(tmp)) {
1028296936Smmel		device_printf(sc->dev, "Cannot parse assigned-address: %d\n",
1029296936Smmel		    rv);
1030296936Smmel		goto fail;
1031296936Smmel	}
1032296936Smmel	port->rp_base_addr = tmp[2];
1033296936Smmel	port->rp_size = tmp[4];
1034296936Smmel	port->port_idx = OFW_PCI_PHYS_HI_DEVICE(tmp[0]) - 1;
1035296936Smmel	if (port->port_idx >= TEGRA_PCIB_MAX_PORTS) {
1036296936Smmel		device_printf(sc->dev, "Invalid port index: %d\n",
1037296936Smmel		    port->port_idx);
1038296936Smmel		goto fail;
1039296936Smmel	}
1040296936Smmel	/* XXX - TODO:
1041296936Smmel	 * Implement proper function for parsing pci "reg" property:
1042296936Smmel	 *  - it have PCI bus format
1043296936Smmel	 *  - its relative to matching "assigned-addresses"
1044296936Smmel	 */
1045296936Smmel	rv = OF_getencprop(node, "reg", tmp, sizeof(tmp));
1046296936Smmel	if (rv != sizeof(tmp)) {
1047296936Smmel		device_printf(sc->dev, "Cannot parse reg: %d\n", rv);
1048296936Smmel		goto fail;
1049296936Smmel	}
1050296936Smmel	port->rp_base_addr += tmp[2];
1051296936Smmel
1052296936Smmel	rv = OF_getencprop(node, "nvidia,num-lanes", &port->num_lanes,
1053296936Smmel	    sizeof(port->num_lanes));
1054296936Smmel	if (rv != sizeof(port->num_lanes)) {
1055296936Smmel		device_printf(sc->dev, "Cannot parse nvidia,num-lanes: %d\n",
1056296936Smmel		    rv);
1057296936Smmel		goto fail;
1058296936Smmel	}
1059296936Smmel	if (port->num_lanes > 4) {
1060296936Smmel		device_printf(sc->dev, "Invalid nvidia,num-lanes: %d\n",
1061296936Smmel		    port->num_lanes);
1062296936Smmel		goto fail;
1063296936Smmel	}
1064296936Smmel
1065296936Smmel	port->afi_pex_ctrl = tegra_pcib_pex_ctrl(sc, port->port_idx);
1066296936Smmel	sc->lanes_cfg |= port->num_lanes << (4 * port->port_idx);
1067296936Smmel
1068296936Smmel	return (port);
1069296936Smmelfail:
1070296936Smmel	free(port, M_DEVBUF);
1071296936Smmel	return (NULL);
1072296936Smmel}
1073296936Smmel
1074296936Smmel
1075296936Smmelstatic int
1076296936Smmeltegra_pcib_parse_fdt_resources(struct tegra_pcib_softc *sc, phandle_t node)
1077296936Smmel{
1078296936Smmel	phandle_t child;
1079296936Smmel	struct tegra_pcib_port *port;
1080296936Smmel	int rv;
1081296936Smmel
1082296936Smmel	/* Power supplies. */
1083296936Smmel	rv = regulator_get_by_ofw_property(sc->dev, "avddio-pex-supply",
1084296936Smmel	    &sc->supply_avddio_pex);
1085296936Smmel	if (rv != 0) {
1086296936Smmel		device_printf(sc->dev,
1087296936Smmel		    "Cannot get 'avddio-pex' regulator\n");
1088296936Smmel		return (ENXIO);
1089296936Smmel	}
1090296936Smmel	rv = regulator_get_by_ofw_property(sc->dev, "dvddio-pex-supply",
1091296936Smmel	     &sc->supply_dvddio_pex);
1092296936Smmel	if (rv != 0) {
1093296936Smmel		device_printf(sc->dev,
1094296936Smmel		    "Cannot get 'dvddio-pex' regulator\n");
1095296936Smmel		return (ENXIO);
1096296936Smmel	}
1097296936Smmel	rv = regulator_get_by_ofw_property(sc->dev, "avdd-pex-pll-supply",
1098296936Smmel	     &sc->supply_avdd_pex_pll);
1099296936Smmel	if (rv != 0) {
1100296936Smmel		device_printf(sc->dev,
1101296936Smmel		    "Cannot get 'avdd-pex-pll' regulator\n");
1102296936Smmel		return (ENXIO);
1103296936Smmel	}
1104296936Smmel	rv = regulator_get_by_ofw_property(sc->dev, "hvdd-pex-supply",
1105296936Smmel	     &sc->supply_hvdd_pex);
1106296936Smmel	if (rv != 0) {
1107296936Smmel		device_printf(sc->dev,
1108296936Smmel		    "Cannot get 'hvdd-pex' regulator\n");
1109296936Smmel		return (ENXIO);
1110296936Smmel	}
1111296936Smmel	rv = regulator_get_by_ofw_property(sc->dev, "hvdd-pex-pll-e-supply",
1112296936Smmel	     &sc->supply_hvdd_pex_pll_e);
1113296936Smmel	if (rv != 0) {
1114296936Smmel		device_printf(sc->dev,
1115296936Smmel		    "Cannot get 'hvdd-pex-pll-e' regulator\n");
1116296936Smmel		return (ENXIO);
1117296936Smmel	}
1118296936Smmel	rv = regulator_get_by_ofw_property(sc->dev, "vddio-pex-ctl-supply",
1119296936Smmel	    &sc->supply_vddio_pex_ctl);
1120296936Smmel	if (rv != 0) {
1121296936Smmel		device_printf(sc->dev,
1122296936Smmel		    "Cannot get 'vddio-pex-ctl' regulator\n");
1123296936Smmel		return (ENXIO);
1124296936Smmel	}
1125296936Smmel	rv = regulator_get_by_ofw_property(sc->dev, "avdd-pll-erefe-supply",
1126296936Smmel	     &sc->supply_avdd_pll_erefe);
1127296936Smmel	if (rv != 0) {
1128296936Smmel		device_printf(sc->dev,
1129296936Smmel		    "Cannot get 'avdd-pll-erefe' regulator\n");
1130296936Smmel		return (ENXIO);
1131296936Smmel	}
1132296936Smmel
1133296936Smmel	/* Resets. */
1134296936Smmel	rv = hwreset_get_by_ofw_name(sc->dev, "pex", &sc->hwreset_pex);
1135296936Smmel	if (rv != 0) {
1136296936Smmel		device_printf(sc->dev, "Cannot get 'pex' reset\n");
1137296936Smmel		return (ENXIO);
1138296936Smmel	}
1139296936Smmel	rv = hwreset_get_by_ofw_name(sc->dev, "afi", &sc->hwreset_afi);
1140296936Smmel	if (rv != 0) {
1141296936Smmel		device_printf(sc->dev, "Cannot get 'afi' reset\n");
1142296936Smmel		return (ENXIO);
1143296936Smmel	}
1144296936Smmel	rv = hwreset_get_by_ofw_name(sc->dev, "pcie_x", &sc->hwreset_pcie_x);
1145296936Smmel	if (rv != 0) {
1146296936Smmel		device_printf(sc->dev, "Cannot get 'pcie_x' reset\n");
1147296936Smmel		return (ENXIO);
1148296936Smmel	}
1149296936Smmel
1150296936Smmel	/* Clocks. */
1151296936Smmel	rv = clk_get_by_ofw_name(sc->dev, "pex", &sc->clk_pex);
1152296936Smmel	if (rv != 0) {
1153296936Smmel		device_printf(sc->dev, "Cannot get 'pex' clock\n");
1154296936Smmel		return (ENXIO);
1155296936Smmel	}
1156296936Smmel	rv = clk_get_by_ofw_name(sc->dev, "afi", &sc->clk_afi);
1157296936Smmel	if (rv != 0) {
1158296936Smmel		device_printf(sc->dev, "Cannot get 'afi' clock\n");
1159296936Smmel		return (ENXIO);
1160296936Smmel	}
1161296936Smmel	rv = clk_get_by_ofw_name(sc->dev, "pll_e", &sc->clk_pll_e);
1162296936Smmel	if (rv != 0) {
1163296936Smmel		device_printf(sc->dev, "Cannot get 'pll_e' clock\n");
1164296936Smmel		return (ENXIO);
1165296936Smmel	}
1166296936Smmel	rv = clk_get_by_ofw_name(sc->dev, "cml", &sc->clk_cml);
1167296936Smmel	if (rv != 0) {
1168296936Smmel		device_printf(sc->dev, "Cannot get 'cml' clock\n");
1169296936Smmel		return (ENXIO);
1170296936Smmel	}
1171296936Smmel
1172296936Smmel	/* Phy. */
1173296936Smmel	rv = phy_get_by_ofw_name(sc->dev, "pcie", &sc->phy);
1174296936Smmel	if (rv != 0) {
1175296936Smmel		device_printf(sc->dev, "Cannot get 'pcie' phy\n");
1176296936Smmel		return (ENXIO);
1177296936Smmel	}
1178296936Smmel
1179296936Smmel	/* Ports */
1180296936Smmel	sc->num_ports = 0;
1181296936Smmel	for (child = OF_child(node); child != 0; child = OF_peer(child)) {
1182296936Smmel		port = tegra_pcib_parse_port(sc, child);
1183296936Smmel		if (port == NULL) {
1184296936Smmel			device_printf(sc->dev, "Cannot parse PCIe port node\n");
1185296936Smmel			return (ENXIO);
1186296936Smmel		}
1187296936Smmel		sc->ports[sc->num_ports++] = port;
1188296936Smmel	}
1189296936Smmel
1190296936Smmel	return (0);
1191296936Smmel}
1192296936Smmel
1193296936Smmelstatic int
1194296936Smmeltegra_pcib_decode_ranges(struct tegra_pcib_softc *sc,
1195296936Smmel    struct tegra_pci_range *ranges, int nranges)
1196296936Smmel{
1197296936Smmel	int i;
1198296936Smmel
1199296936Smmel	for (i = 2; i < nranges; i++) {
1200296936Smmel		if (ranges[i].space_code == OFW_PCI_PHYS_HI_SPACE_IO) {
1201296936Smmel			if (sc->io_range.size != 0) {
1202296936Smmel				device_printf(sc->dev,
1203296936Smmel				    "Duplicated IO range found in DT\n");
1204296936Smmel				return (ENXIO);
1205296936Smmel			}
1206296936Smmel			sc->io_range = ranges[i];
1207296936Smmel		}
1208296936Smmel		if ((ranges[i].space_code == OFW_PCI_PHYS_HI_SPACE_MEM32) &&
1209296936Smmel		    !ranges[i].prefetchable) {
1210296936Smmel			if (sc->mem_range.size != 0) {
1211296936Smmel				device_printf(sc->dev,
1212296936Smmel				    "Duplicated memory range found in DT\n");
1213296936Smmel				return (ENXIO);
1214296936Smmel			}
1215296936Smmel			sc->mem_range = ranges[i];
1216296936Smmel		}
1217296936Smmel		if ((ranges[i].space_code == OFW_PCI_PHYS_HI_SPACE_MEM32) &&
1218296936Smmel		    ranges[i].prefetchable) {
1219296936Smmel			if (sc->pref_mem_range.size != 0) {
1220296936Smmel				device_printf(sc->dev,
1221296936Smmel				    "Duplicated memory range found in DT\n");
1222296936Smmel				return (ENXIO);
1223296936Smmel			}
1224296936Smmel			sc->pref_mem_range = ranges[i];
1225296936Smmel		}
1226296936Smmel	}
1227296936Smmel	if ((sc->io_range.size == 0) || (sc->mem_range.size == 0)
1228296936Smmel	    || (sc->pref_mem_range.size == 0)) {
1229296936Smmel		device_printf(sc->dev,
1230296936Smmel		    " Not all required ranges are found in DT\n");
1231296936Smmel		return (ENXIO);
1232296936Smmel	}
1233296936Smmel	return (0);
1234296936Smmel}
1235296936Smmel
1236296936Smmel/*
1237296936Smmel * Hardware config.
1238296936Smmel */
1239296936Smmelstatic int
1240296936Smmeltegra_pcib_wait_for_link(struct tegra_pcib_softc *sc,
1241296936Smmel    struct tegra_pcib_port *port)
1242296936Smmel{
1243296936Smmel	uint32_t reg;
1244296936Smmel	int i;
1245296936Smmel
1246296936Smmel
1247296936Smmel	/* Setup link detection. */
1248296936Smmel	reg = tegra_pcib_read_config(sc->dev, 0, port->port_idx, 0,
1249296936Smmel	    RP_PRIV_MISC, 4);
1250296936Smmel	reg &= ~RP_PRIV_MISC_PRSNT_MAP_EP_ABSNT;
1251296936Smmel	reg |= RP_PRIV_MISC_PRSNT_MAP_EP_PRSNT;
1252296936Smmel	tegra_pcib_write_config(sc->dev, 0, port->port_idx, 0,
1253296936Smmel	    RP_PRIV_MISC, reg, 4);
1254296936Smmel
1255296936Smmel	for (i = TEGRA_PCIE_LINKUP_TIMEOUT; i > 0; i--) {
1256296936Smmel		reg = tegra_pcib_read_config(sc->dev, 0, port->port_idx, 0,
1257296936Smmel		    RP_VEND_XP, 4);
1258296936Smmel		if (reg & RP_VEND_XP_DL_UP)
1259296936Smmel				break;
1260296936Smmel
1261296936Smmel	}
1262296936Smmel	if (i <= 0)
1263296936Smmel		return (ETIMEDOUT);
1264296936Smmel
1265296936Smmel	for (i = TEGRA_PCIE_LINKUP_TIMEOUT; i > 0; i--) {
1266296936Smmel		reg = tegra_pcib_read_config(sc->dev, 0, port->port_idx, 0,
1267296936Smmel		    RP_LINK_CONTROL_STATUS, 4);
1268296936Smmel		if (reg & RP_LINK_CONTROL_STATUS_DL_LINK_ACTIVE)
1269296936Smmel				break;
1270296936Smmel
1271296936Smmel	}
1272296936Smmel	if (i <= 0)
1273296936Smmel		return (ETIMEDOUT);
1274296936Smmel	return (0);
1275296936Smmel}
1276296936Smmel
1277296936Smmelstatic void
1278296936Smmeltegra_pcib_port_enable(struct tegra_pcib_softc *sc, int port_num)
1279296936Smmel{
1280296936Smmel	struct tegra_pcib_port *port;
1281296936Smmel	uint32_t reg;
1282296936Smmel	int rv;
1283296936Smmel
1284296936Smmel	port = sc->ports[port_num];
1285296936Smmel
1286296936Smmel	/* Put port to reset. */
1287296936Smmel	reg = AFI_RD4(sc, port->afi_pex_ctrl);
1288296936Smmel	reg &= ~AFI_PEX_CTRL_RST_L;
1289296936Smmel	AFI_WR4(sc, port->afi_pex_ctrl, reg);
1290296936Smmel	AFI_RD4(sc, port->afi_pex_ctrl);
1291296936Smmel	DELAY(10);
1292296936Smmel
1293296936Smmel	/* Enable clocks. */
1294296936Smmel	reg |= AFI_PEX_CTRL_REFCLK_EN;
1295296936Smmel	reg |= AFI_PEX_CTRL_CLKREQ_EN;
1296296936Smmel	reg |= AFI_PEX_CTRL_OVERRIDE_EN;
1297296936Smmel	AFI_WR4(sc, port->afi_pex_ctrl, reg);
1298296936Smmel	AFI_RD4(sc, port->afi_pex_ctrl);
1299296936Smmel	DELAY(100);
1300296936Smmel
1301296936Smmel	/* Release reset. */
1302296936Smmel	reg |= AFI_PEX_CTRL_RST_L;
1303296936Smmel	AFI_WR4(sc, port->afi_pex_ctrl, reg);
1304296936Smmel
1305296936Smmel	rv = tegra_pcib_wait_for_link(sc, port);
1306296936Smmel	if (bootverbose)
1307296936Smmel		device_printf(sc->dev, " port %d (%d lane%s): Link is %s\n",
1308296936Smmel			 port->port_idx, port->num_lanes,
1309296936Smmel			 port->num_lanes > 1 ? "s": "",
1310296936Smmel			 rv == 0 ? "up": "down");
1311296936Smmel}
1312296936Smmel
1313296936Smmel
1314296936Smmelstatic void
1315296936Smmeltegra_pcib_port_disable(struct tegra_pcib_softc *sc, uint32_t port_num)
1316296936Smmel{
1317296936Smmel	struct tegra_pcib_port *port;
1318296936Smmel	uint32_t reg;
1319296936Smmel
1320296936Smmel	port = sc->ports[port_num];
1321296936Smmel
1322296936Smmel	/* Put port to reset. */
1323296936Smmel	reg = AFI_RD4(sc, port->afi_pex_ctrl);
1324296936Smmel	reg &= ~AFI_PEX_CTRL_RST_L;
1325296936Smmel	AFI_WR4(sc, port->afi_pex_ctrl, reg);
1326296936Smmel	AFI_RD4(sc, port->afi_pex_ctrl);
1327296936Smmel	DELAY(10);
1328296936Smmel
1329296936Smmel	/* Disable clocks. */
1330296936Smmel	reg &= ~AFI_PEX_CTRL_CLKREQ_EN;
1331296936Smmel	reg &= ~AFI_PEX_CTRL_REFCLK_EN;
1332296936Smmel	AFI_WR4(sc, port->afi_pex_ctrl, reg);
1333296936Smmel
1334296936Smmel	if (bootverbose)
1335296936Smmel		device_printf(sc->dev, " port %d (%d lane%s): Disabled\n",
1336296936Smmel			 port->port_idx, port->num_lanes,
1337296936Smmel			 port->num_lanes > 1 ? "s": "");
1338296936Smmel}
1339296936Smmel
1340296936Smmelstatic void
1341296936Smmeltegra_pcib_set_bar(struct tegra_pcib_softc *sc, int bar, uint32_t axi,
1342296936Smmel    uint64_t fpci, uint32_t size, int is_memory)
1343296936Smmel{
1344296936Smmel	uint32_t fpci_reg;
1345296936Smmel	uint32_t axi_reg;
1346296936Smmel	uint32_t size_reg;
1347296936Smmel
1348296936Smmel	axi_reg = axi & ~0xFFF;
1349296936Smmel	size_reg = size >> 12;
1350296936Smmel	fpci_reg = (uint32_t)(fpci >> 8) & ~0xF;
1351296936Smmel	fpci_reg |= is_memory ? 0x1 : 0x0;
1352296936Smmel	AFI_WR4(sc, bars[bar].axi_start, axi_reg);
1353296936Smmel	AFI_WR4(sc, bars[bar].size, size_reg);
1354296936Smmel	AFI_WR4(sc, bars[bar].fpci_start, fpci_reg);
1355296936Smmel}
1356296936Smmel
1357296936Smmelstatic int
1358296936Smmeltegra_pcib_enable(struct tegra_pcib_softc *sc, uint32_t port)
1359296936Smmel{
1360296936Smmel	int rv;
1361296936Smmel	int i;
1362296936Smmel	uint32_t reg;
1363296936Smmel
1364296936Smmel	rv = tegra_pcib_enable_fdt_resources(sc);
1365296936Smmel	if (rv != 0) {
1366296936Smmel		device_printf(sc->dev, "Cannot enable FDT resources\n");
1367296936Smmel		return (rv);
1368296936Smmel	}
1369296936Smmel	/* Enable PLLE control. */
1370296936Smmel	reg = AFI_RD4(sc, AFI_PLLE_CONTROL);
1371296936Smmel	reg &= ~AFI_PLLE_CONTROL_BYPASS_PADS2PLLE_CONTROL;
1372296936Smmel	reg |= AFI_PLLE_CONTROL_PADS2PLLE_CONTROL_EN;
1373296936Smmel	AFI_WR4(sc, AFI_PLLE_CONTROL, reg);
1374296936Smmel
1375296936Smmel	/* Set bias pad. */
1376296936Smmel	AFI_WR4(sc, AFI_PEXBIAS_CTRL, 0);
1377296936Smmel
1378296936Smmel	/* Configure mode and ports. */
1379296936Smmel	reg = AFI_RD4(sc, AFI_PCIE_CONFIG);
1380296936Smmel	reg &= ~AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_MASK;
1381296936Smmel	if (sc->lanes_cfg == 0x14) {
1382296936Smmel		if (bootverbose)
1383296936Smmel			device_printf(sc->dev,
1384296936Smmel			    "Using x1,x4 configuration\n");
1385296936Smmel		reg |= AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_XBAR4_1;
1386296936Smmel	} else if (sc->lanes_cfg == 0x12) {
1387296936Smmel		if (bootverbose)
1388296936Smmel			device_printf(sc->dev,
1389296936Smmel			    "Using x1,x2 configuration\n");
1390296936Smmel		reg |= AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_XBAR2_1;
1391296936Smmel	} else {
1392296936Smmel		device_printf(sc->dev,
1393296936Smmel		    "Unsupported lanes configuration: 0x%X\n", sc->lanes_cfg);
1394296936Smmel	}
1395296936Smmel	reg |= AFI_PCIE_CONFIG_PCIE_DISABLE_ALL;
1396296936Smmel	for (i = 0; i < TEGRA_PCIB_MAX_PORTS; i++) {
1397296936Smmel		if ((sc->ports[i] != NULL))
1398296936Smmel			reg &=
1399296936Smmel			 ~AFI_PCIE_CONFIG_PCIE_DISABLE(sc->ports[i]->port_idx);
1400296936Smmel	}
1401296936Smmel	AFI_WR4(sc, AFI_PCIE_CONFIG, reg);
1402296936Smmel
1403296936Smmel	/* Enable Gen2 support. */
1404296936Smmel	reg = AFI_RD4(sc, AFI_FUSE);
1405296936Smmel	reg &= ~AFI_FUSE_PCIE_T0_GEN2_DIS;
1406296936Smmel	AFI_WR4(sc, AFI_FUSE, reg);
1407296936Smmel
1408296936Smmel	/* Enable PCIe phy. */
1409296936Smmel	rv = phy_enable(sc->dev, sc->phy);
1410296936Smmel	if (rv != 0) {
1411296936Smmel		device_printf(sc->dev, "Cannot enable phy\n");
1412296936Smmel		return (rv);
1413296936Smmel	}
1414296936Smmel
1415296936Smmel	rv = hwreset_deassert(sc->hwreset_pcie_x);
1416296936Smmel	if (rv != 0) {
1417296936Smmel		device_printf(sc->dev, "Cannot unreset  'pci_x' reset\n");
1418296936Smmel		return (rv);
1419296936Smmel	}
1420296936Smmel
1421296936Smmel	/* Enable config space. */
1422296936Smmel	reg = AFI_RD4(sc, AFI_CONFIGURATION);
1423296936Smmel	reg |= AFI_CONFIGURATION_EN_FPCI;
1424296936Smmel	AFI_WR4(sc, AFI_CONFIGURATION, reg);
1425296936Smmel
1426296936Smmel	/* Enable AFI errors. */
1427296936Smmel	reg = 0;
1428296936Smmel	reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_INI_SLVERR);
1429296936Smmel	reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_INI_DECERR);
1430296936Smmel	reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_TGT_SLVERR);
1431296936Smmel	reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_TGT_DECERR);
1432296936Smmel	reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_TGT_WRERR);
1433296936Smmel	reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_SM_MSG);
1434296936Smmel	reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_DFPCI_DECERR);
1435296936Smmel	reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_AXI_DECERR);
1436296936Smmel	reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_FPCI_TIMEOUT);
1437296936Smmel	reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_PE_PRSNT_SENSE);
1438296936Smmel	reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_PE_CLKREQ_SENSE);
1439296936Smmel	reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_CLKCLAMP_SENSE);
1440296936Smmel	reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_RDY4PD_SENSE);
1441296936Smmel	reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_P2P_ERROR);
1442296936Smmel	AFI_WR4(sc, AFI_AFI_INTR_ENABLE, reg);
1443296936Smmel	AFI_WR4(sc, AFI_SM_INTR_ENABLE, 0xffffffff);
1444296936Smmel
1445296936Smmel	/* Enable INT, disable MSI. */
1446296936Smmel	AFI_WR4(sc, AFI_INTR_MASK, AFI_INTR_MASK_INT_MASK);
1447296936Smmel
1448296936Smmel	/* Mask all FPCI errors. */
1449296936Smmel	AFI_WR4(sc, AFI_FPCI_ERROR_MASKS, 0);
1450296936Smmel
1451296936Smmel	/* Setup AFI translation windows. */
1452296936Smmel	/* BAR 0 - type 1 extended configuration. */
1453296936Smmel	tegra_pcib_set_bar(sc, 0, rman_get_start(sc->cfg_mem_res),
1454296936Smmel	   FPCI_MAP_EXT_TYPE1_CONFIG, rman_get_size(sc->cfg_mem_res), 0);
1455296936Smmel
1456296936Smmel	/* BAR 1 - downstream I/O. */
1457296936Smmel	tegra_pcib_set_bar(sc, 1, sc->io_range.host_addr, FPCI_MAP_IO,
1458296936Smmel	    sc->io_range.size, 0);
1459296936Smmel
1460296936Smmel	/* BAR 2 - downstream prefetchable memory 1:1. */
1461296936Smmel	tegra_pcib_set_bar(sc, 2, sc->pref_mem_range.host_addr,
1462296936Smmel	    sc->pref_mem_range.host_addr, sc->pref_mem_range.size, 1);
1463296936Smmel
1464296936Smmel	/* BAR 3 - downstream not prefetchable memory 1:1 .*/
1465296936Smmel	tegra_pcib_set_bar(sc, 3, sc->mem_range.host_addr,
1466296936Smmel	    sc->mem_range.host_addr, sc->mem_range.size, 1);
1467296936Smmel
1468296936Smmel	/* BAR 3-8 clear. */
1469296936Smmel	tegra_pcib_set_bar(sc, 4, 0, 0, 0, 0);
1470296936Smmel	tegra_pcib_set_bar(sc, 5, 0, 0, 0, 0);
1471296936Smmel	tegra_pcib_set_bar(sc, 6, 0, 0, 0, 0);
1472296936Smmel	tegra_pcib_set_bar(sc, 7, 0, 0, 0, 0);
1473296936Smmel	tegra_pcib_set_bar(sc, 8, 0, 0, 0, 0);
1474296936Smmel
1475296936Smmel	/* MSI BAR - clear. */
1476296936Smmel	tegra_pcib_set_bar(sc, 9, 0, 0, 0, 0);
1477296936Smmel	return(0);
1478296936Smmel}
1479296936Smmel
1480296936Smmelstatic int
1481296936Smmeltegra_pcib_probe(device_t dev)
1482296936Smmel{
1483296936Smmel	if (!ofw_bus_status_okay(dev))
1484296936Smmel		return (ENXIO);
1485296936Smmel
1486296936Smmel	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data != 0) {
1487296936Smmel		device_set_desc(dev, "Nvidia Integrated PCI/PCI-E Controller");
1488296936Smmel		return (BUS_PROBE_DEFAULT);
1489296936Smmel	}
1490296936Smmel	return (ENXIO);
1491296936Smmel}
1492296936Smmel
1493296936Smmelstatic int
1494296936Smmeltegra_pcib_attach(device_t dev)
1495296936Smmel{
1496296936Smmel	struct tegra_pcib_softc *sc;
1497296936Smmel	phandle_t node;
1498296936Smmel	uint32_t unit;
1499296936Smmel	int rv;
1500296936Smmel	int rid;
1501296936Smmel	int nranges;
1502296936Smmel	struct tegra_pci_range *ranges;
1503296936Smmel	struct tegra_pcib_port *port;
1504296936Smmel	int i;
1505296936Smmel
1506296936Smmel	sc = device_get_softc(dev);
1507296936Smmel	sc->dev = dev;
1508296936Smmel	unit = fdt_get_unit(dev);
1509296936Smmel	mtx_init(&sc->mtx, "msi_mtx", NULL, MTX_DEF);
1510296936Smmel
1511296936Smmel
1512296936Smmel	node = ofw_bus_get_node(dev);
1513296936Smmel
1514296936Smmel	rv = tegra_pcib_parse_fdt_resources(sc, node);
1515296936Smmel	if (rv != 0) {
1516296936Smmel		device_printf(dev, "Cannot get FDT resources\n");
1517296936Smmel		return (rv);
1518296936Smmel	}
1519296936Smmel
1520296936Smmel	nranges = tegra_pci_get_ranges(node, &ranges);
1521296936Smmel	if (nranges != 5) {
1522296936Smmel		device_printf(sc->dev, "Unexpected number of ranges: %d\n",
1523296936Smmel		    nranges);
1524296936Smmel		rv = ENXIO;
1525296936Smmel		goto out;
1526296936Smmel	}
1527296936Smmel
1528296936Smmel	/* Allocate bus_space resources. */
1529296936Smmel	rid = 0;
1530296936Smmel	sc->pads_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
1531296936Smmel	    RF_ACTIVE);
1532296936Smmel	if (sc->pads_mem_res == NULL) {
1533296936Smmel		device_printf(dev, "Cannot allocate PADS register\n");
1534296936Smmel		rv = ENXIO;
1535296936Smmel		goto out;
1536296936Smmel	}
1537296936Smmel	/*
1538296936Smmel	 * XXX - FIXME
1539296936Smmel	 * tag for config space is not filled when RF_ALLOCATED flag is used.
1540296936Smmel	 */
1541296936Smmel	sc->bus_tag = rman_get_bustag(sc->pads_mem_res);
1542296936Smmel
1543296936Smmel	rid = 1;
1544296936Smmel	sc->afi_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
1545296936Smmel	    RF_ACTIVE);
1546296936Smmel	if (sc->afi_mem_res == NULL) {
1547296936Smmel		device_printf(dev, "Cannot allocate AFI register\n");
1548296936Smmel		rv = ENXIO;
1549296936Smmel		goto out;
1550296936Smmel	}
1551296936Smmel
1552296936Smmel	rid = 2;
1553296936Smmel	sc->cfg_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
1554296936Smmel	    RF_ALLOCATED);
1555296936Smmel	if (sc->cfg_mem_res == NULL) {
1556296936Smmel		device_printf(dev, "Cannot allocate config space memory\n");
1557296936Smmel		rv = ENXIO;
1558296936Smmel		goto out;
1559296936Smmel	}
1560296936Smmel	sc->cfg_base_addr = rman_get_start(sc->cfg_mem_res);
1561296936Smmel
1562296936Smmel
1563296936Smmel	/* Map RP slots */
1564296936Smmel	for (i = 0; i < TEGRA_PCIB_MAX_PORTS; i++) {
1565296936Smmel		if (sc->ports[i] == NULL)
1566296936Smmel			continue;
1567296936Smmel		port = sc->ports[i];
1568296936Smmel		rv = bus_space_map(sc->bus_tag, port->rp_base_addr,
1569296936Smmel		    port->rp_size, 0, &port->cfg_handle);
1570296936Smmel		if (rv != 0) {
1571296936Smmel			device_printf(sc->dev, "Cannot allocate memory for "
1572296936Smmel			    "port: %d\n", i);
1573296936Smmel			rv = ENXIO;
1574296936Smmel			goto out;
1575296936Smmel		}
1576296936Smmel	}
1577296936Smmel
1578296936Smmel	/*
1579296936Smmel	 * Get PCI interrupt info.
1580296936Smmel	 */
1581296936Smmel	ofw_bus_setup_iinfo(node, &sc->pci_iinfo, sizeof(pcell_t));
1582296936Smmel	rid = 0;
1583296936Smmel	sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
1584296936Smmel	    RF_ACTIVE | RF_SHAREABLE);
1585296936Smmel	if (sc->irq_res == NULL) {
1586296936Smmel		device_printf(dev, "Cannot allocate IRQ resources\n");
1587296936Smmel		rv = ENXIO;
1588296936Smmel		goto out;
1589296936Smmel	}
1590296936Smmel
1591296936Smmel	rid = 1;
1592296936Smmel	sc->msi_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
1593296936Smmel	    RF_ACTIVE);
1594296936Smmel	if (sc->irq_res == NULL) {
1595296936Smmel		device_printf(dev, "Cannot allocate MSI IRQ resources\n");
1596296936Smmel		rv = ENXIO;
1597296936Smmel		goto out;
1598296936Smmel	}
1599296936Smmel
1600296936Smmel	if (bus_setup_intr(dev, sc->irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
1601296936Smmel			   tegra_pci_intr, NULL, sc, &sc->intr_cookie)) {
1602296936Smmel		device_printf(dev, "cannot setup interrupt handler\n");
1603296936Smmel		rv = ENXIO;
1604296936Smmel		goto out;
1605296936Smmel	}
1606296936Smmel
1607296936Smmel	/* Memory management. */
1608296936Smmel	rv = tegra_pcib_decode_ranges(sc, ranges, nranges);
1609296936Smmel	if (rv != 0)
1610296936Smmel		goto out;
1611296936Smmel
1612296936Smmel	rv = tegra_pcib_rman_init(sc);
1613296936Smmel	if (rv != 0)
1614296936Smmel		goto out;
1615296936Smmel	free(ranges, M_DEVBUF);
1616296936Smmel	ranges = NULL;
1617296936Smmel
1618296936Smmel	/*
1619296936Smmel	 * Enable PCIE device.
1620296936Smmel	 */
1621296936Smmel	rv = tegra_pcib_enable(sc, unit);
1622296936Smmel	if (rv != 0)
1623296936Smmel		goto out;
1624296936Smmel	for (i = 0; i < TEGRA_PCIB_MAX_PORTS; i++) {
1625296936Smmel		if (sc->ports[i] == NULL)
1626296936Smmel			continue;
1627296936Smmel		if (sc->ports[i]->enabled)
1628296936Smmel			tegra_pcib_port_enable(sc, i);
1629296936Smmel		else
1630296936Smmel			tegra_pcib_port_disable(sc, i);
1631296936Smmel	}
1632296936Smmel
1633296936Smmel	device_add_child(dev, "pci", -1);
1634296936Smmel
1635296936Smmel	return (bus_generic_attach(dev));
1636296936Smmel
1637296936Smmelout:
1638296936Smmel	if (ranges != NULL)
1639296936Smmel		free(ranges, M_DEVBUF);
1640296936Smmel
1641296936Smmel	return (rv);
1642296936Smmel}
1643296936Smmel
1644296936Smmel
1645296936Smmelstatic device_method_t tegra_pcib_methods[] = {
1646296936Smmel	/* Device interface */
1647296936Smmel	DEVMETHOD(device_probe,			tegra_pcib_probe),
1648296936Smmel	DEVMETHOD(device_attach,		tegra_pcib_attach),
1649296936Smmel
1650296936Smmel	/* Bus interface */
1651296936Smmel	DEVMETHOD(bus_read_ivar,		tegra_pcib_read_ivar),
1652296936Smmel	DEVMETHOD(bus_write_ivar,		tegra_pcib_write_ivar),
1653296936Smmel	DEVMETHOD(bus_alloc_resource,		tegra_pcib_alloc_resource),
1654296936Smmel	DEVMETHOD(bus_adjust_resource,		tegra_pcib_adjust_resource),
1655296936Smmel	DEVMETHOD(bus_release_resource,		tegra_pcib_release_resource),
1656296936Smmel	DEVMETHOD(bus_activate_resource,	tegra_pcib_pcie_activate_resource),
1657296936Smmel	DEVMETHOD(bus_deactivate_resource,	bus_generic_deactivate_resource),
1658296936Smmel	DEVMETHOD(bus_setup_intr,		bus_generic_setup_intr),
1659296936Smmel	DEVMETHOD(bus_teardown_intr,		bus_generic_teardown_intr),
1660296936Smmel
1661296936Smmel	/* pcib interface */
1662296936Smmel	DEVMETHOD(pcib_maxslots,		tegra_pcib_maxslots),
1663296936Smmel	DEVMETHOD(pcib_read_config,		tegra_pcib_read_config),
1664296936Smmel	DEVMETHOD(pcib_write_config,		tegra_pcib_write_config),
1665296936Smmel	DEVMETHOD(pcib_route_interrupt,		tegra_pcib_route_interrupt),
1666296936Smmel
1667296936Smmel#if defined(TEGRA_PCI_MSI)
1668296936Smmel	DEVMETHOD(pcib_alloc_msi,		tegra_pcib_alloc_msi),
1669296936Smmel	DEVMETHOD(pcib_release_msi,		tegra_pcib_release_msi),
1670296936Smmel	DEVMETHOD(pcib_map_msi,			tegra_pcib_map_msi),
1671296936Smmel#endif
1672296936Smmel
1673296936Smmel	/* OFW bus interface */
1674296936Smmel	DEVMETHOD(ofw_bus_get_compat,		ofw_bus_gen_get_compat),
1675296936Smmel	DEVMETHOD(ofw_bus_get_model,		ofw_bus_gen_get_model),
1676296936Smmel	DEVMETHOD(ofw_bus_get_name,		ofw_bus_gen_get_name),
1677296936Smmel	DEVMETHOD(ofw_bus_get_node,		ofw_bus_gen_get_node),
1678296936Smmel	DEVMETHOD(ofw_bus_get_type,		ofw_bus_gen_get_type),
1679296936Smmel
1680296936Smmel	DEVMETHOD_END
1681296936Smmel};
1682296936Smmel
1683296936Smmelstatic driver_t tegra_pcib_driver = {
1684296936Smmel	"pcib",
1685296936Smmel	tegra_pcib_methods,
1686296936Smmel	sizeof(struct tegra_pcib_softc),
1687296936Smmel};
1688296936Smmel
1689296936Smmeldevclass_t pcib_devclass;
1690296936Smmel
1691298627SbrDRIVER_MODULE(pcib, simplebus, tegra_pcib_driver, pcib_devclass, 0, 0);
1692