Blame view

drivers/pci/pci_tegra.c 28.2 KB
83d290c56   Tom Rini   SPDX: Convert all...
1
  // SPDX-License-Identifier: GPL-2.0
f315828b0   Thierry Reding   pci: tegra: Add T...
2
3
4
5
6
7
8
9
  /*
   * Copyright (c) 2010, CompuLab, Ltd.
   * Author: Mike Rapoport <mike@compulab.co.il>
   *
   * Based on NVIDIA PCIe driver
   * Copyright (c) 2008-2009, NVIDIA Corporation.
   *
   * Copyright (c) 2013-2014, NVIDIA Corporation.
f315828b0   Thierry Reding   pci: tegra: Add T...
10
   */
f315828b0   Thierry Reding   pci: tegra: Add T...
11
12
13
  #define pr_fmt(fmt) "tegra-pcie: " fmt
  
  #include <common.h>
bbc5b36b2   Stephen Warren   pci: tegra: port ...
14
  #include <clk.h>
e81ca8845   Simon Glass   dm: tegra: pci: C...
15
  #include <dm.h>
f315828b0   Thierry Reding   pci: tegra: Add T...
16
  #include <errno.h>
f315828b0   Thierry Reding   pci: tegra: Add T...
17
18
  #include <malloc.h>
  #include <pci.h>
355560d58   Marcel Ziswiler   pci: tegra: intro...
19
  #include <pci_tegra.h>
bbc5b36b2   Stephen Warren   pci: tegra: port ...
20
21
  #include <power-domain.h>
  #include <reset.h>
f315828b0   Thierry Reding   pci: tegra: Add T...
22
23
24
  
  #include <asm/io.h>
  #include <asm/gpio.h>
68f008113   Simon Glass   dm: tegra: pci: C...
25
  #include <linux/ioport.h>
bbc5b36b2   Stephen Warren   pci: tegra: port ...
26
27
28
  #include <linux/list.h>
  
  #ifndef CONFIG_TEGRA186
f315828b0   Thierry Reding   pci: tegra: Add T...
29
30
31
  #include <asm/arch/clock.h>
  #include <asm/arch/powergate.h>
  #include <asm/arch-tegra/xusb-padctl.h>
f315828b0   Thierry Reding   pci: tegra: Add T...
32
  #include <dt-bindings/pinctrl/pinctrl-tegra-xusb.h>
bbc5b36b2   Stephen Warren   pci: tegra: port ...
33
34
35
36
37
38
39
40
41
42
  #endif
  
  /*
   * FIXME: TODO: This driver contains a number of ifdef CONFIG_TEGRA186 that
   * should not be present. These are needed because newer Tegra SoCs support
   * only the standard clock/reset APIs, whereas older Tegra SoCs support only
   * a custom Tegra-specific API. ASAP the older Tegra SoCs' code should be
   * fixed to implement the standard APIs, and all drivers converted to solely
   * use the new standard APIs, with no ifdefs.
   */
f315828b0   Thierry Reding   pci: tegra: Add T...
43

f315828b0   Thierry Reding   pci: tegra: Add T...
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
  #define AFI_AXI_BAR0_SZ	0x00
  #define AFI_AXI_BAR1_SZ	0x04
  #define AFI_AXI_BAR2_SZ	0x08
  #define AFI_AXI_BAR3_SZ	0x0c
  #define AFI_AXI_BAR4_SZ	0x10
  #define AFI_AXI_BAR5_SZ	0x14
  
  #define AFI_AXI_BAR0_START	0x18
  #define AFI_AXI_BAR1_START	0x1c
  #define AFI_AXI_BAR2_START	0x20
  #define AFI_AXI_BAR3_START	0x24
  #define AFI_AXI_BAR4_START	0x28
  #define AFI_AXI_BAR5_START	0x2c
  
  #define AFI_FPCI_BAR0	0x30
  #define AFI_FPCI_BAR1	0x34
  #define AFI_FPCI_BAR2	0x38
  #define AFI_FPCI_BAR3	0x3c
  #define AFI_FPCI_BAR4	0x40
  #define AFI_FPCI_BAR5	0x44
  
  #define AFI_CACHE_BAR0_SZ	0x48
  #define AFI_CACHE_BAR0_ST	0x4c
  #define AFI_CACHE_BAR1_SZ	0x50
  #define AFI_CACHE_BAR1_ST	0x54
  
  #define AFI_MSI_BAR_SZ		0x60
  #define AFI_MSI_FPCI_BAR_ST	0x64
  #define AFI_MSI_AXI_BAR_ST	0x68
  
  #define AFI_CONFIGURATION		0xac
  #define  AFI_CONFIGURATION_EN_FPCI	(1 << 0)
  
  #define AFI_FPCI_ERROR_MASKS	0xb0
  
  #define AFI_INTR_MASK		0xb4
  #define  AFI_INTR_MASK_INT_MASK	(1 << 0)
  #define  AFI_INTR_MASK_MSI_MASK	(1 << 8)
  
  #define AFI_SM_INTR_ENABLE	0xc4
  #define  AFI_SM_INTR_INTA_ASSERT	(1 << 0)
  #define  AFI_SM_INTR_INTB_ASSERT	(1 << 1)
  #define  AFI_SM_INTR_INTC_ASSERT	(1 << 2)
  #define  AFI_SM_INTR_INTD_ASSERT	(1 << 3)
  #define  AFI_SM_INTR_INTA_DEASSERT	(1 << 4)
  #define  AFI_SM_INTR_INTB_DEASSERT	(1 << 5)
  #define  AFI_SM_INTR_INTC_DEASSERT	(1 << 6)
  #define  AFI_SM_INTR_INTD_DEASSERT	(1 << 7)
  
  #define AFI_AFI_INTR_ENABLE		0xc8
  #define  AFI_INTR_EN_INI_SLVERR		(1 << 0)
  #define  AFI_INTR_EN_INI_DECERR		(1 << 1)
  #define  AFI_INTR_EN_TGT_SLVERR		(1 << 2)
  #define  AFI_INTR_EN_TGT_DECERR		(1 << 3)
  #define  AFI_INTR_EN_TGT_WRERR		(1 << 4)
  #define  AFI_INTR_EN_DFPCI_DECERR	(1 << 5)
  #define  AFI_INTR_EN_AXI_DECERR		(1 << 6)
  #define  AFI_INTR_EN_FPCI_TIMEOUT	(1 << 7)
  #define  AFI_INTR_EN_PRSNT_SENSE	(1 << 8)
  
  #define AFI_PCIE_CONFIG					0x0f8
  #define  AFI_PCIE_CONFIG_PCIE_DISABLE(x)		(1 << ((x) + 1))
  #define  AFI_PCIE_CONFIG_PCIE_DISABLE_ALL		0xe
  #define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_MASK	(0xf << 20)
  #define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_SINGLE	(0x0 << 20)
  #define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_420	(0x0 << 20)
  #define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X2_X1	(0x0 << 20)
  #define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_DUAL	(0x1 << 20)
  #define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_222	(0x1 << 20)
  #define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X4_X1	(0x1 << 20)
  #define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_411	(0x2 << 20)
bbc5b36b2   Stephen Warren   pci: tegra: port ...
115
116
117
  #define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_401	(0x0 << 20)
  #define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_211	(0x1 << 20)
  #define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_111	(0x2 << 20)
f315828b0   Thierry Reding   pci: tegra: Add T...
118
119
120
121
122
123
124
  
  #define AFI_FUSE			0x104
  #define  AFI_FUSE_PCIE_T0_GEN2_DIS	(1 << 2)
  
  #define AFI_PEX0_CTRL			0x110
  #define AFI_PEX1_CTRL			0x118
  #define AFI_PEX2_CTRL			0x128
bbc5b36b2   Stephen Warren   pci: tegra: port ...
125
  #define AFI_PEX2_CTRL_T186		0x19c
f315828b0   Thierry Reding   pci: tegra: Add T...
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
  #define  AFI_PEX_CTRL_RST		(1 << 0)
  #define  AFI_PEX_CTRL_CLKREQ_EN		(1 << 1)
  #define  AFI_PEX_CTRL_REFCLK_EN		(1 << 3)
  #define  AFI_PEX_CTRL_OVERRIDE_EN	(1 << 4)
  
  #define AFI_PLLE_CONTROL		0x160
  #define  AFI_PLLE_CONTROL_BYPASS_PADS2PLLE_CONTROL (1 << 9)
  #define  AFI_PLLE_CONTROL_PADS2PLLE_CONTROL_EN (1 << 1)
  
  #define AFI_PEXBIAS_CTRL_0		0x168
  
  #define PADS_CTL_SEL		0x0000009C
  
  #define PADS_CTL		0x000000A0
  #define  PADS_CTL_IDDQ_1L	(1 <<  0)
  #define  PADS_CTL_TX_DATA_EN_1L	(1 <<  6)
  #define  PADS_CTL_RX_DATA_EN_1L	(1 << 10)
  
  #define PADS_PLL_CTL_TEGRA20			0x000000B8
  #define PADS_PLL_CTL_TEGRA30			0x000000B4
  #define  PADS_PLL_CTL_RST_B4SM			(0x1 <<  1)
  #define  PADS_PLL_CTL_LOCKDET			(0x1 <<  8)
  #define  PADS_PLL_CTL_REFCLK_MASK		(0x3 << 16)
  #define  PADS_PLL_CTL_REFCLK_INTERNAL_CML	(0x0 << 16)
  #define  PADS_PLL_CTL_REFCLK_INTERNAL_CMOS	(0x1 << 16)
  #define  PADS_PLL_CTL_REFCLK_EXTERNAL		(0x2 << 16)
  #define  PADS_PLL_CTL_TXCLKREF_MASK		(0x1 << 20)
  #define  PADS_PLL_CTL_TXCLKREF_DIV10		(0x0 << 20)
  #define  PADS_PLL_CTL_TXCLKREF_DIV5		(0x1 << 20)
  #define  PADS_PLL_CTL_TXCLKREF_BUF_EN		(0x1 << 22)
  
  #define PADS_REFCLK_CFG0			0x000000C8
  #define PADS_REFCLK_CFG1			0x000000CC
  
  /*
   * Fields in PADS_REFCLK_CFG*. Those registers form an array of 16-bit
   * entries, one entry per PCIe port. These field definitions and desired
   * values aren't in the TRM, but do come from NVIDIA.
   */
  #define PADS_REFCLK_CFG_TERM_SHIFT		2  /* 6:2 */
  #define PADS_REFCLK_CFG_E_TERM_SHIFT		7
  #define PADS_REFCLK_CFG_PREDI_SHIFT		8  /* 11:8 */
  #define PADS_REFCLK_CFG_DRVI_SHIFT		12 /* 15:12 */
f315828b0   Thierry Reding   pci: tegra: Add T...
169
170
  #define RP_VEND_XP	0x00000F00
  #define  RP_VEND_XP_DL_UP	(1 << 30)
514e19138   Stephen Warren   pci: tegra: imple...
171
172
  #define RP_VEND_CTL2				0x00000FA8
  #define  RP_VEND_CTL2_PCA_ENABLE		(1 << 7)
f315828b0   Thierry Reding   pci: tegra: Add T...
173
174
175
176
177
178
179
  #define RP_PRIV_MISC	0x00000FE0
  #define  RP_PRIV_MISC_PRSNT_MAP_EP_PRSNT (0xE << 0)
  #define  RP_PRIV_MISC_PRSNT_MAP_EP_ABSNT (0xF << 0)
  
  #define RP_LINK_CONTROL_STATUS			0x00000090
  #define  RP_LINK_CONTROL_STATUS_DL_LINK_ACTIVE	0x20000000
  #define  RP_LINK_CONTROL_STATUS_LINKSTAT_MASK	0x3fff0000
e81ca8845   Simon Glass   dm: tegra: pci: C...
180
181
182
183
184
  enum tegra_pci_id {
  	TEGRA20_PCIE,
  	TEGRA30_PCIE,
  	TEGRA124_PCIE,
  	TEGRA210_PCIE,
bbc5b36b2   Stephen Warren   pci: tegra: port ...
185
  	TEGRA186_PCIE,
e81ca8845   Simon Glass   dm: tegra: pci: C...
186
  };
f315828b0   Thierry Reding   pci: tegra: Add T...
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
  
  struct tegra_pcie_port {
  	struct tegra_pcie *pcie;
  
  	struct fdt_resource regs;
  	unsigned int num_lanes;
  	unsigned int index;
  
  	struct list_head list;
  };
  
  struct tegra_pcie_soc {
  	unsigned int num_ports;
  	unsigned long pads_pll_ctl;
  	unsigned long tx_ref_sel;
bbc5b36b2   Stephen Warren   pci: tegra: port ...
202
  	unsigned long afi_pex2_ctrl;
3cfc6be4a   Stephen Warren   pci: tegra: corre...
203
204
  	u32 pads_refclk_cfg0;
  	u32 pads_refclk_cfg1;
f315828b0   Thierry Reding   pci: tegra: Add T...
205
206
207
208
  	bool has_pex_clkreq_en;
  	bool has_pex_bias_ctrl;
  	bool has_cml_clk;
  	bool has_gen2;
514e19138   Stephen Warren   pci: tegra: imple...
209
  	bool force_pca_enable;
f315828b0   Thierry Reding   pci: tegra: Add T...
210
211
212
  };
  
  struct tegra_pcie {
68f008113   Simon Glass   dm: tegra: pci: C...
213
214
215
  	struct resource pads;
  	struct resource afi;
  	struct resource cs;
f315828b0   Thierry Reding   pci: tegra: Add T...
216

f315828b0   Thierry Reding   pci: tegra: Add T...
217
218
219
220
  	struct list_head ports;
  	unsigned long xbar;
  
  	const struct tegra_pcie_soc *soc;
bbc5b36b2   Stephen Warren   pci: tegra: port ...
221
222
223
224
225
226
227
228
229
  
  #ifdef CONFIG_TEGRA186
  	struct clk clk_afi;
  	struct clk clk_pex;
  	struct reset_ctl reset_afi;
  	struct reset_ctl reset_pex;
  	struct reset_ctl reset_pcie_x;
  	struct power_domain pwrdom;
  #else
f315828b0   Thierry Reding   pci: tegra: Add T...
230
  	struct tegra_xusb_phy *phy;
bbc5b36b2   Stephen Warren   pci: tegra: port ...
231
  #endif
f315828b0   Thierry Reding   pci: tegra: Add T...
232
  };
f315828b0   Thierry Reding   pci: tegra: Add T...
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
  static void afi_writel(struct tegra_pcie *pcie, unsigned long value,
  		       unsigned long offset)
  {
  	writel(value, pcie->afi.start + offset);
  }
  
  static unsigned long afi_readl(struct tegra_pcie *pcie, unsigned long offset)
  {
  	return readl(pcie->afi.start + offset);
  }
  
  static void pads_writel(struct tegra_pcie *pcie, unsigned long value,
  			unsigned long offset)
  {
  	writel(value, pcie->pads.start + offset);
  }
bbc5b36b2   Stephen Warren   pci: tegra: port ...
249
  #ifndef CONFIG_TEGRA186
f315828b0   Thierry Reding   pci: tegra: Add T...
250
251
252
253
  static unsigned long pads_readl(struct tegra_pcie *pcie, unsigned long offset)
  {
  	return readl(pcie->pads.start + offset);
  }
bbc5b36b2   Stephen Warren   pci: tegra: port ...
254
  #endif
f315828b0   Thierry Reding   pci: tegra: Add T...
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
  
  static unsigned long rp_readl(struct tegra_pcie_port *port,
  			      unsigned long offset)
  {
  	return readl(port->regs.start + offset);
  }
  
  static void rp_writel(struct tegra_pcie_port *port, unsigned long value,
  		      unsigned long offset)
  {
  	writel(value, port->regs.start + offset);
  }
  
  static unsigned long tegra_pcie_conf_offset(pci_dev_t bdf, int where)
  {
  	return ((where & 0xf00) << 16) | (PCI_BUS(bdf) << 16) |
  	       (PCI_DEV(bdf) << 11) | (PCI_FUNC(bdf) << 8) |
  	       (where & 0xfc);
  }
  
  static int tegra_pcie_conf_address(struct tegra_pcie *pcie, pci_dev_t bdf,
  				   int where, unsigned long *address)
  {
  	unsigned int bus = PCI_BUS(bdf);
  
  	if (bus == 0) {
  		unsigned int dev = PCI_DEV(bdf);
  		struct tegra_pcie_port *port;
  
  		list_for_each_entry(port, &pcie->ports, list) {
  			if (port->index + 1 == dev) {
  				*address = port->regs.start + (where & ~3);
  				return 0;
  			}
  		}
f5c6db84e   Stephen Warren   pci: tegra: fix D...
290
  		return -EFAULT;
f315828b0   Thierry Reding   pci: tegra: Add T...
291
  	} else {
f5c6db84e   Stephen Warren   pci: tegra: fix D...
292
293
294
295
296
  #ifdef CONFIG_TEGRA20
  		unsigned int dev = PCI_DEV(bdf);
  		if (dev != 0)
  			return -EFAULT;
  #endif
f315828b0   Thierry Reding   pci: tegra: Add T...
297
298
299
  		*address = pcie->cs.start + tegra_pcie_conf_offset(bdf, where);
  		return 0;
  	}
f315828b0   Thierry Reding   pci: tegra: Add T...
300
  }
c4e72c4ad   Simon Glass   dm: pci: Update t...
301
  static int pci_tegra_read_config(const struct udevice *bus, pci_dev_t bdf,
e81ca8845   Simon Glass   dm: tegra: pci: C...
302
303
  				 uint offset, ulong *valuep,
  				 enum pci_size_t size)
f315828b0   Thierry Reding   pci: tegra: Add T...
304
  {
e81ca8845   Simon Glass   dm: tegra: pci: C...
305
306
  	struct tegra_pcie *pcie = dev_get_priv(bus);
  	unsigned long address, value;
f315828b0   Thierry Reding   pci: tegra: Add T...
307
  	int err;
e81ca8845   Simon Glass   dm: tegra: pci: C...
308
  	err = tegra_pcie_conf_address(pcie, bdf, offset, &address);
f315828b0   Thierry Reding   pci: tegra: Add T...
309
  	if (err < 0) {
e81ca8845   Simon Glass   dm: tegra: pci: C...
310
311
  		value = 0xffffffff;
  		goto done;
f315828b0   Thierry Reding   pci: tegra: Add T...
312
  	}
e81ca8845   Simon Glass   dm: tegra: pci: C...
313
  	value = readl(address);
f315828b0   Thierry Reding   pci: tegra: Add T...
314

f5c6db84e   Stephen Warren   pci: tegra: fix D...
315
  #ifdef CONFIG_TEGRA20
f315828b0   Thierry Reding   pci: tegra: Add T...
316
317
  	/* fixup root port class */
  	if (PCI_BUS(bdf) == 0) {
f5c6db84e   Stephen Warren   pci: tegra: fix D...
318
  		if ((offset & ~3) == PCI_CLASS_REVISION) {
e81ca8845   Simon Glass   dm: tegra: pci: C...
319
320
  			value &= ~0x00ff0000;
  			value |= PCI_CLASS_BRIDGE_PCI << 16;
f315828b0   Thierry Reding   pci: tegra: Add T...
321
322
  		}
  	}
f5c6db84e   Stephen Warren   pci: tegra: fix D...
323
  #endif
f315828b0   Thierry Reding   pci: tegra: Add T...
324

e81ca8845   Simon Glass   dm: tegra: pci: C...
325
326
  done:
  	*valuep = pci_conv_32_to_size(value, offset, size);
f315828b0   Thierry Reding   pci: tegra: Add T...
327
328
  	return 0;
  }
e81ca8845   Simon Glass   dm: tegra: pci: C...
329
330
331
  static int pci_tegra_write_config(struct udevice *bus, pci_dev_t bdf,
  				  uint offset, ulong value,
  				  enum pci_size_t size)
f315828b0   Thierry Reding   pci: tegra: Add T...
332
  {
e81ca8845   Simon Glass   dm: tegra: pci: C...
333
  	struct tegra_pcie *pcie = dev_get_priv(bus);
f315828b0   Thierry Reding   pci: tegra: Add T...
334
  	unsigned long address;
e81ca8845   Simon Glass   dm: tegra: pci: C...
335
  	ulong old;
f315828b0   Thierry Reding   pci: tegra: Add T...
336
  	int err;
e81ca8845   Simon Glass   dm: tegra: pci: C...
337
  	err = tegra_pcie_conf_address(pcie, bdf, offset, &address);
f315828b0   Thierry Reding   pci: tegra: Add T...
338
  	if (err < 0)
e81ca8845   Simon Glass   dm: tegra: pci: C...
339
  		return 0;
f315828b0   Thierry Reding   pci: tegra: Add T...
340

e81ca8845   Simon Glass   dm: tegra: pci: C...
341
342
  	old = readl(address);
  	value = pci_conv_size_to_32(old, value, offset, size);
f315828b0   Thierry Reding   pci: tegra: Add T...
343
344
345
346
  	writel(value, address);
  
  	return 0;
  }
68f008113   Simon Glass   dm: tegra: pci: C...
347
  static int tegra_pcie_port_parse_dt(ofnode node, struct tegra_pcie_port *port)
f315828b0   Thierry Reding   pci: tegra: Add T...
348
349
350
  {
  	const u32 *addr;
  	int len;
68f008113   Simon Glass   dm: tegra: pci: C...
351
  	addr = ofnode_get_property(node, "assigned-addresses", &len);
f315828b0   Thierry Reding   pci: tegra: Add T...
352
  	if (!addr) {
9b643e312   Masahiro Yamada   treewide: replace...
353
  		pr_err("property \"assigned-addresses\" not found");
f315828b0   Thierry Reding   pci: tegra: Add T...
354
355
356
357
358
359
360
361
  		return -FDT_ERR_NOTFOUND;
  	}
  
  	port->regs.start = fdt32_to_cpu(addr[2]);
  	port->regs.end = port->regs.start + fdt32_to_cpu(addr[4]);
  
  	return 0;
  }
68f008113   Simon Glass   dm: tegra: pci: C...
362
  static int tegra_pcie_get_xbar_config(ofnode node, u32 lanes,
e81ca8845   Simon Glass   dm: tegra: pci: C...
363
  				      enum tegra_pci_id id, unsigned long *xbar)
f315828b0   Thierry Reding   pci: tegra: Add T...
364
  {
f315828b0   Thierry Reding   pci: tegra: Add T...
365
  	switch (id) {
e81ca8845   Simon Glass   dm: tegra: pci: C...
366
  	case TEGRA20_PCIE:
f315828b0   Thierry Reding   pci: tegra: Add T...
367
368
369
370
371
372
373
374
375
376
377
378
379
380
  		switch (lanes) {
  		case 0x00000004:
  			debug("single-mode configuration
  ");
  			*xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_SINGLE;
  			return 0;
  
  		case 0x00000202:
  			debug("dual-mode configuration
  ");
  			*xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_DUAL;
  			return 0;
  		}
  		break;
e81ca8845   Simon Glass   dm: tegra: pci: C...
381
  	case TEGRA30_PCIE:
f315828b0   Thierry Reding   pci: tegra: Add T...
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
  		switch (lanes) {
  		case 0x00000204:
  			debug("4x1, 2x1 configuration
  ");
  			*xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_420;
  			return 0;
  
  		case 0x00020202:
  			debug("2x3 configuration
  ");
  			*xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_222;
  			return 0;
  
  		case 0x00010104:
  			debug("4x1, 1x2 configuration
  ");
  			*xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_411;
  			return 0;
  		}
  		break;
e81ca8845   Simon Glass   dm: tegra: pci: C...
402
403
  	case TEGRA124_PCIE:
  	case TEGRA210_PCIE:
f315828b0   Thierry Reding   pci: tegra: Add T...
404
405
406
407
408
409
410
411
412
413
414
415
416
417
  		switch (lanes) {
  		case 0x0000104:
  			debug("4x1, 1x1 configuration
  ");
  			*xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X4_X1;
  			return 0;
  
  		case 0x0000102:
  			debug("2x1, 1x1 configuration
  ");
  			*xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X2_X1;
  			return 0;
  		}
  		break;
bbc5b36b2   Stephen Warren   pci: tegra: port ...
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
  	case TEGRA186_PCIE:
  		switch (lanes) {
  		case 0x0010004:
  			debug("x4 x1 configuration
  ");
  			*xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_401;
  			return 0;
  
  		case 0x0010102:
  			debug("x2 x1 x1 configuration
  ");
  			*xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_211;
  			return 0;
  
  		case 0x0010101:
  			debug("x1 x1 x1 configuration
  ");
  			*xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_111;
  			return 0;
  		}
  		break;
f315828b0   Thierry Reding   pci: tegra: Add T...
439
440
441
442
443
444
  	default:
  		break;
  	}
  
  	return -FDT_ERR_NOTFOUND;
  }
68f008113   Simon Glass   dm: tegra: pci: C...
445
  static int tegra_pcie_parse_port_info(ofnode node, uint *index, uint *lanes)
f315828b0   Thierry Reding   pci: tegra: Add T...
446
  {
a62e84d7b   Bin Meng   fdt: Add several ...
447
  	struct fdt_pci_addr addr;
f315828b0   Thierry Reding   pci: tegra: Add T...
448
  	int err;
68f008113   Simon Glass   dm: tegra: pci: C...
449
  	err = ofnode_read_u32_default(node, "nvidia,num-lanes", -1);
f315828b0   Thierry Reding   pci: tegra: Add T...
450
  	if (err < 0) {
9b643e312   Masahiro Yamada   treewide: replace...
451
  		pr_err("failed to parse \"nvidia,num-lanes\" property");
f315828b0   Thierry Reding   pci: tegra: Add T...
452
453
454
455
  		return err;
  	}
  
  	*lanes = err;
68f008113   Simon Glass   dm: tegra: pci: C...
456
  	err = ofnode_read_pci_addr(node, 0, "reg", &addr);
f315828b0   Thierry Reding   pci: tegra: Add T...
457
  	if (err < 0) {
9b643e312   Masahiro Yamada   treewide: replace...
458
  		pr_err("failed to parse \"reg\" property");
f315828b0   Thierry Reding   pci: tegra: Add T...
459
460
  		return err;
  	}
053b86e6d   Sjoerd Simons   pci: tegra: Fix p...
461
  	*index = PCI_DEV(addr.phys_hi) - 1;
f315828b0   Thierry Reding   pci: tegra: Add T...
462
463
464
  
  	return 0;
  }
e81ca8845   Simon Glass   dm: tegra: pci: C...
465
466
467
468
  int __weak tegra_pcie_board_init(void)
  {
  	return 0;
  }
68f008113   Simon Glass   dm: tegra: pci: C...
469
  static int tegra_pcie_parse_dt(struct udevice *dev, enum tegra_pci_id id,
f315828b0   Thierry Reding   pci: tegra: Add T...
470
471
  			       struct tegra_pcie *pcie)
  {
68f008113   Simon Glass   dm: tegra: pci: C...
472
  	ofnode subnode;
f315828b0   Thierry Reding   pci: tegra: Add T...
473
  	u32 lanes = 0;
68f008113   Simon Glass   dm: tegra: pci: C...
474
  	int err;
f315828b0   Thierry Reding   pci: tegra: Add T...
475

68f008113   Simon Glass   dm: tegra: pci: C...
476
  	err = dev_read_resource(dev, 0, &pcie->pads);
f315828b0   Thierry Reding   pci: tegra: Add T...
477
  	if (err < 0) {
9b643e312   Masahiro Yamada   treewide: replace...
478
  		pr_err("resource \"pads\" not found");
f315828b0   Thierry Reding   pci: tegra: Add T...
479
480
  		return err;
  	}
68f008113   Simon Glass   dm: tegra: pci: C...
481
  	err = dev_read_resource(dev, 1, &pcie->afi);
f315828b0   Thierry Reding   pci: tegra: Add T...
482
  	if (err < 0) {
9b643e312   Masahiro Yamada   treewide: replace...
483
  		pr_err("resource \"afi\" not found");
f315828b0   Thierry Reding   pci: tegra: Add T...
484
485
  		return err;
  	}
68f008113   Simon Glass   dm: tegra: pci: C...
486
  	err = dev_read_resource(dev, 2, &pcie->cs);
f315828b0   Thierry Reding   pci: tegra: Add T...
487
  	if (err < 0) {
9b643e312   Masahiro Yamada   treewide: replace...
488
  		pr_err("resource \"cs\" not found");
f315828b0   Thierry Reding   pci: tegra: Add T...
489
490
  		return err;
  	}
dfa71e9fc   Simon Glass   tegra: Report err...
491
492
  	err = tegra_pcie_board_init();
  	if (err < 0) {
9b643e312   Masahiro Yamada   treewide: replace...
493
  		pr_err("tegra_pcie_board_init() failed: err=%d", err);
dfa71e9fc   Simon Glass   tegra: Report err...
494
495
  		return err;
  	}
e81ca8845   Simon Glass   dm: tegra: pci: C...
496

bbc5b36b2   Stephen Warren   pci: tegra: port ...
497
  #ifndef CONFIG_TEGRA186
f315828b0   Thierry Reding   pci: tegra: Add T...
498
499
500
501
  	pcie->phy = tegra_xusb_phy_get(TEGRA_XUSB_PADCTL_PCIE);
  	if (pcie->phy) {
  		err = tegra_xusb_phy_prepare(pcie->phy);
  		if (err < 0) {
9b643e312   Masahiro Yamada   treewide: replace...
502
  			pr_err("failed to prepare PHY: %d", err);
f315828b0   Thierry Reding   pci: tegra: Add T...
503
504
505
  			return err;
  		}
  	}
bbc5b36b2   Stephen Warren   pci: tegra: port ...
506
  #endif
f315828b0   Thierry Reding   pci: tegra: Add T...
507

68f008113   Simon Glass   dm: tegra: pci: C...
508
  	dev_for_each_subnode(subnode, dev) {
f315828b0   Thierry Reding   pci: tegra: Add T...
509
510
  		unsigned int index = 0, num_lanes = 0;
  		struct tegra_pcie_port *port;
68f008113   Simon Glass   dm: tegra: pci: C...
511
  		err = tegra_pcie_parse_port_info(subnode, &index, &num_lanes);
f315828b0   Thierry Reding   pci: tegra: Add T...
512
  		if (err < 0) {
9b643e312   Masahiro Yamada   treewide: replace...
513
  			pr_err("failed to obtain root port info");
f315828b0   Thierry Reding   pci: tegra: Add T...
514
515
516
517
  			continue;
  		}
  
  		lanes |= num_lanes << (index << 3);
68f008113   Simon Glass   dm: tegra: pci: C...
518
  		if (!ofnode_is_available(subnode))
f315828b0   Thierry Reding   pci: tegra: Add T...
519
520
521
522
523
524
525
526
527
  			continue;
  
  		port = malloc(sizeof(*port));
  		if (!port)
  			continue;
  
  		memset(port, 0, sizeof(*port));
  		port->num_lanes = num_lanes;
  		port->index = index;
68f008113   Simon Glass   dm: tegra: pci: C...
528
  		err = tegra_pcie_port_parse_dt(subnode, port);
f315828b0   Thierry Reding   pci: tegra: Add T...
529
530
531
532
533
534
535
536
  		if (err < 0) {
  			free(port);
  			continue;
  		}
  
  		list_add_tail(&port->list, &pcie->ports);
  		port->pcie = pcie;
  	}
68f008113   Simon Glass   dm: tegra: pci: C...
537
538
  	err = tegra_pcie_get_xbar_config(dev_ofnode(dev), lanes, id,
  					 &pcie->xbar);
f315828b0   Thierry Reding   pci: tegra: Add T...
539
  	if (err < 0) {
9b643e312   Masahiro Yamada   treewide: replace...
540
  		pr_err("invalid lane configuration");
f315828b0   Thierry Reding   pci: tegra: Add T...
541
542
543
544
545
  		return err;
  	}
  
  	return 0;
  }
bbc5b36b2   Stephen Warren   pci: tegra: port ...
546
547
548
549
550
551
552
  #ifdef CONFIG_TEGRA186
  static int tegra_pcie_power_on(struct tegra_pcie *pcie)
  {
  	int ret;
  
  	ret = power_domain_on(&pcie->pwrdom);
  	if (ret) {
9b643e312   Masahiro Yamada   treewide: replace...
553
554
  		pr_err("power_domain_on() failed: %d
  ", ret);
bbc5b36b2   Stephen Warren   pci: tegra: port ...
555
556
557
558
559
  		return ret;
  	}
  
  	ret = clk_enable(&pcie->clk_afi);
  	if (ret) {
9b643e312   Masahiro Yamada   treewide: replace...
560
561
  		pr_err("clk_enable(afi) failed: %d
  ", ret);
bbc5b36b2   Stephen Warren   pci: tegra: port ...
562
563
564
565
566
  		return ret;
  	}
  
  	ret = clk_enable(&pcie->clk_pex);
  	if (ret) {
9b643e312   Masahiro Yamada   treewide: replace...
567
568
  		pr_err("clk_enable(pex) failed: %d
  ", ret);
bbc5b36b2   Stephen Warren   pci: tegra: port ...
569
570
571
572
573
  		return ret;
  	}
  
  	ret = reset_deassert(&pcie->reset_afi);
  	if (ret) {
9b643e312   Masahiro Yamada   treewide: replace...
574
575
  		pr_err("reset_deassert(afi) failed: %d
  ", ret);
bbc5b36b2   Stephen Warren   pci: tegra: port ...
576
577
578
579
580
  		return ret;
  	}
  
  	ret = reset_deassert(&pcie->reset_pex);
  	if (ret) {
9b643e312   Masahiro Yamada   treewide: replace...
581
582
  		pr_err("reset_deassert(pex) failed: %d
  ", ret);
bbc5b36b2   Stephen Warren   pci: tegra: port ...
583
584
585
586
587
588
  		return ret;
  	}
  
  	return 0;
  }
  #else
f315828b0   Thierry Reding   pci: tegra: Add T...
589
590
591
592
593
594
595
596
597
598
599
600
601
  static int tegra_pcie_power_on(struct tegra_pcie *pcie)
  {
  	const struct tegra_pcie_soc *soc = pcie->soc;
  	unsigned long value;
  	int err;
  
  	/* reset PCIEXCLK logic, AFI controller and PCIe controller */
  	reset_set_enable(PERIPH_ID_PCIEXCLK, 1);
  	reset_set_enable(PERIPH_ID_AFI, 1);
  	reset_set_enable(PERIPH_ID_PCIE, 1);
  
  	err = tegra_powergate_power_off(TEGRA_POWERGATE_PCIE);
  	if (err < 0) {
9b643e312   Masahiro Yamada   treewide: replace...
602
  		pr_err("failed to power off PCIe partition: %d", err);
f315828b0   Thierry Reding   pci: tegra: Add T...
603
604
  		return err;
  	}
f315828b0   Thierry Reding   pci: tegra: Add T...
605
606
607
  	err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_PCIE,
  						PERIPH_ID_PCIE);
  	if (err < 0) {
9b643e312   Masahiro Yamada   treewide: replace...
608
  		pr_err("failed to power up PCIe partition: %d", err);
f315828b0   Thierry Reding   pci: tegra: Add T...
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
  		return err;
  	}
  
  	/* take AFI controller out of reset */
  	reset_set_enable(PERIPH_ID_AFI, 0);
  
  	/* enable AFI clock */
  	clock_enable(PERIPH_ID_AFI);
  
  	if (soc->has_cml_clk) {
  		/* enable CML clock */
  		value = readl(NV_PA_CLK_RST_BASE + 0x48c);
  		value |= (1 << 0);
  		value &= ~(1 << 1);
  		writel(value, NV_PA_CLK_RST_BASE + 0x48c);
  	}
  
  	err = tegra_plle_enable();
  	if (err < 0) {
9b643e312   Masahiro Yamada   treewide: replace...
628
629
  		pr_err("failed to enable PLLE: %d
  ", err);
f315828b0   Thierry Reding   pci: tegra: Add T...
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
  		return err;
  	}
  
  	return 0;
  }
  
  static int tegra_pcie_pll_wait(struct tegra_pcie *pcie, unsigned long timeout)
  {
  	const struct tegra_pcie_soc *soc = pcie->soc;
  	unsigned long start = get_timer(0);
  	u32 value;
  
  	while (get_timer(start) < timeout) {
  		value = pads_readl(pcie, soc->pads_pll_ctl);
  		if (value & PADS_PLL_CTL_LOCKDET)
  			return 0;
  	}
  
  	return -ETIMEDOUT;
  }
  
  static int tegra_pcie_phy_enable(struct tegra_pcie *pcie)
  {
  	const struct tegra_pcie_soc *soc = pcie->soc;
  	u32 value;
  	int err;
  
  	/* initialize internal PHY, enable up to 16 PCIe lanes */
  	pads_writel(pcie, 0, PADS_CTL_SEL);
  
  	/* override IDDQ to 1 on all 4 lanes */
  	value = pads_readl(pcie, PADS_CTL);
  	value |= PADS_CTL_IDDQ_1L;
  	pads_writel(pcie, value, PADS_CTL);
  
  	/*
  	 * Set up PHY PLL inputs select PLLE output as refclock, set TX
  	 * ref sel to div10 (not div5).
  	 */
  	value = pads_readl(pcie, soc->pads_pll_ctl);
  	value &= ~(PADS_PLL_CTL_REFCLK_MASK | PADS_PLL_CTL_TXCLKREF_MASK);
  	value |= PADS_PLL_CTL_REFCLK_INTERNAL_CML | soc->tx_ref_sel;
  	pads_writel(pcie, value, soc->pads_pll_ctl);
  
  	/* reset PLL */
  	value = pads_readl(pcie, soc->pads_pll_ctl);
  	value &= ~PADS_PLL_CTL_RST_B4SM;
  	pads_writel(pcie, value, soc->pads_pll_ctl);
  
  	udelay(20);
  
  	/* take PLL out of reset */
  	value = pads_readl(pcie, soc->pads_pll_ctl);
  	value |= PADS_PLL_CTL_RST_B4SM;
  	pads_writel(pcie, value, soc->pads_pll_ctl);
f315828b0   Thierry Reding   pci: tegra: Add T...
685
686
687
  	/* wait for the PLL to lock */
  	err = tegra_pcie_pll_wait(pcie, 500);
  	if (err < 0) {
9b643e312   Masahiro Yamada   treewide: replace...
688
  		pr_err("PLL failed to lock: %d", err);
f315828b0   Thierry Reding   pci: tegra: Add T...
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
  		return err;
  	}
  
  	/* turn off IDDQ override */
  	value = pads_readl(pcie, PADS_CTL);
  	value &= ~PADS_CTL_IDDQ_1L;
  	pads_writel(pcie, value, PADS_CTL);
  
  	/* enable TX/RX data */
  	value = pads_readl(pcie, PADS_CTL);
  	value |= PADS_CTL_TX_DATA_EN_1L | PADS_CTL_RX_DATA_EN_1L;
  	pads_writel(pcie, value, PADS_CTL);
  
  	return 0;
  }
bbc5b36b2   Stephen Warren   pci: tegra: port ...
704
  #endif
f315828b0   Thierry Reding   pci: tegra: Add T...
705
706
707
708
709
710
711
  
  static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
  {
  	const struct tegra_pcie_soc *soc = pcie->soc;
  	struct tegra_pcie_port *port;
  	u32 value;
  	int err;
bbc5b36b2   Stephen Warren   pci: tegra: port ...
712
713
714
  #ifdef CONFIG_TEGRA186
  	{
  #else
f315828b0   Thierry Reding   pci: tegra: Add T...
715
  	if (pcie->phy) {
bbc5b36b2   Stephen Warren   pci: tegra: port ...
716
  #endif
f315828b0   Thierry Reding   pci: tegra: Add T...
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
  		value = afi_readl(pcie, AFI_PLLE_CONTROL);
  		value &= ~AFI_PLLE_CONTROL_BYPASS_PADS2PLLE_CONTROL;
  		value |= AFI_PLLE_CONTROL_PADS2PLLE_CONTROL_EN;
  		afi_writel(pcie, value, AFI_PLLE_CONTROL);
  	}
  
  	if (soc->has_pex_bias_ctrl)
  		afi_writel(pcie, 0, AFI_PEXBIAS_CTRL_0);
  
  	value = afi_readl(pcie, AFI_PCIE_CONFIG);
  	value &= ~AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_MASK;
  	value |= AFI_PCIE_CONFIG_PCIE_DISABLE_ALL | pcie->xbar;
  
  	list_for_each_entry(port, &pcie->ports, list)
  		value &= ~AFI_PCIE_CONFIG_PCIE_DISABLE(port->index);
  
  	afi_writel(pcie, value, AFI_PCIE_CONFIG);
  
  	value = afi_readl(pcie, AFI_FUSE);
  
  	if (soc->has_gen2)
  		value &= ~AFI_FUSE_PCIE_T0_GEN2_DIS;
  	else
  		value |= AFI_FUSE_PCIE_T0_GEN2_DIS;
  
  	afi_writel(pcie, value, AFI_FUSE);
bbc5b36b2   Stephen Warren   pci: tegra: port ...
743
  #ifndef CONFIG_TEGRA186
f315828b0   Thierry Reding   pci: tegra: Add T...
744
745
746
747
748
749
  	if (pcie->phy)
  		err = tegra_xusb_phy_enable(pcie->phy);
  	else
  		err = tegra_pcie_phy_enable(pcie);
  
  	if (err < 0) {
9b643e312   Masahiro Yamada   treewide: replace...
750
751
  		pr_err("failed to power on PHY: %d
  ", err);
f315828b0   Thierry Reding   pci: tegra: Add T...
752
753
  		return err;
  	}
bbc5b36b2   Stephen Warren   pci: tegra: port ...
754
  #endif
f315828b0   Thierry Reding   pci: tegra: Add T...
755
756
  
  	/* take the PCIEXCLK logic out of reset */
bbc5b36b2   Stephen Warren   pci: tegra: port ...
757
758
759
  #ifdef CONFIG_TEGRA186
  	err = reset_deassert(&pcie->reset_pcie_x);
  	if (err) {
9b643e312   Masahiro Yamada   treewide: replace...
760
761
  		pr_err("reset_deassert(pcie_x) failed: %d
  ", err);
bbc5b36b2   Stephen Warren   pci: tegra: port ...
762
763
764
  		return err;
  	}
  #else
f315828b0   Thierry Reding   pci: tegra: Add T...
765
  	reset_set_enable(PERIPH_ID_PCIEXCLK, 0);
bbc5b36b2   Stephen Warren   pci: tegra: port ...
766
  #endif
f315828b0   Thierry Reding   pci: tegra: Add T...
767
768
769
770
771
772
773
774
775
776
777
778
779
780
  
  	/* finally enable PCIe */
  	value = afi_readl(pcie, AFI_CONFIGURATION);
  	value |= AFI_CONFIGURATION_EN_FPCI;
  	afi_writel(pcie, value, AFI_CONFIGURATION);
  
  	/* disable all interrupts */
  	afi_writel(pcie, 0, AFI_AFI_INTR_ENABLE);
  	afi_writel(pcie, 0, AFI_SM_INTR_ENABLE);
  	afi_writel(pcie, 0, AFI_INTR_MASK);
  	afi_writel(pcie, 0, AFI_FPCI_ERROR_MASKS);
  
  	return 0;
  }
e81ca8845   Simon Glass   dm: tegra: pci: C...
781
  static int tegra_pcie_setup_translations(struct udevice *bus)
f315828b0   Thierry Reding   pci: tegra: Add T...
782
  {
e81ca8845   Simon Glass   dm: tegra: pci: C...
783
  	struct tegra_pcie *pcie = dev_get_priv(bus);
f315828b0   Thierry Reding   pci: tegra: Add T...
784
  	unsigned long fpci, axi, size;
e81ca8845   Simon Glass   dm: tegra: pci: C...
785
786
  	struct pci_region *io, *mem, *pref;
  	int count;
f315828b0   Thierry Reding   pci: tegra: Add T...
787
788
789
  
  	/* BAR 0: type 1 extended configuration space */
  	fpci = 0xfe100000;
68f008113   Simon Glass   dm: tegra: pci: C...
790
  	size = resource_size(&pcie->cs);
f315828b0   Thierry Reding   pci: tegra: Add T...
791
792
793
794
795
  	axi = pcie->cs.start;
  
  	afi_writel(pcie, axi, AFI_AXI_BAR0_START);
  	afi_writel(pcie, size >> 12, AFI_AXI_BAR0_SZ);
  	afi_writel(pcie, fpci, AFI_FPCI_BAR0);
e81ca8845   Simon Glass   dm: tegra: pci: C...
796
797
798
  	count = pci_get_regions(bus, &io, &mem, &pref);
  	if (count != 3)
  		return -EINVAL;
f315828b0   Thierry Reding   pci: tegra: Add T...
799
800
  	/* BAR 1: downstream I/O */
  	fpci = 0xfdfc0000;
e81ca8845   Simon Glass   dm: tegra: pci: C...
801
802
  	size = io->size;
  	axi = io->phys_start;
f315828b0   Thierry Reding   pci: tegra: Add T...
803
804
805
806
807
808
  
  	afi_writel(pcie, axi, AFI_AXI_BAR1_START);
  	afi_writel(pcie, size >> 12, AFI_AXI_BAR1_SZ);
  	afi_writel(pcie, fpci, AFI_FPCI_BAR1);
  
  	/* BAR 2: prefetchable memory */
e81ca8845   Simon Glass   dm: tegra: pci: C...
809
810
811
  	fpci = (((pref->phys_start >> 12) & 0x0fffffff) << 4) | 0x1;
  	size = pref->size;
  	axi = pref->phys_start;
f315828b0   Thierry Reding   pci: tegra: Add T...
812
813
814
815
816
817
  
  	afi_writel(pcie, axi, AFI_AXI_BAR2_START);
  	afi_writel(pcie, size >> 12, AFI_AXI_BAR2_SZ);
  	afi_writel(pcie, fpci, AFI_FPCI_BAR2);
  
  	/* BAR 3: non-prefetchable memory */
e81ca8845   Simon Glass   dm: tegra: pci: C...
818
819
820
  	fpci = (((mem->phys_start >> 12) & 0x0fffffff) << 4) | 0x1;
  	size = mem->size;
  	axi = mem->phys_start;
f315828b0   Thierry Reding   pci: tegra: Add T...
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
  
  	afi_writel(pcie, axi, AFI_AXI_BAR3_START);
  	afi_writel(pcie, size >> 12, AFI_AXI_BAR3_SZ);
  	afi_writel(pcie, fpci, AFI_FPCI_BAR3);
  
  	/* NULL out the remaining BARs as they are not used */
  	afi_writel(pcie, 0, AFI_AXI_BAR4_START);
  	afi_writel(pcie, 0, AFI_AXI_BAR4_SZ);
  	afi_writel(pcie, 0, AFI_FPCI_BAR4);
  
  	afi_writel(pcie, 0, AFI_AXI_BAR5_START);
  	afi_writel(pcie, 0, AFI_AXI_BAR5_SZ);
  	afi_writel(pcie, 0, AFI_FPCI_BAR5);
  
  	/* map all upstream transactions as uncached */
  	afi_writel(pcie, NV_PA_SDRAM_BASE, AFI_CACHE_BAR0_ST);
  	afi_writel(pcie, 0, AFI_CACHE_BAR0_SZ);
  	afi_writel(pcie, 0, AFI_CACHE_BAR1_ST);
  	afi_writel(pcie, 0, AFI_CACHE_BAR1_SZ);
  
  	/* MSI translations are setup only when needed */
  	afi_writel(pcie, 0, AFI_MSI_FPCI_BAR_ST);
  	afi_writel(pcie, 0, AFI_MSI_BAR_SZ);
  	afi_writel(pcie, 0, AFI_MSI_AXI_BAR_ST);
  	afi_writel(pcie, 0, AFI_MSI_BAR_SZ);
e81ca8845   Simon Glass   dm: tegra: pci: C...
846
847
  
  	return 0;
f315828b0   Thierry Reding   pci: tegra: Add T...
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
  }
  
  static unsigned long tegra_pcie_port_get_pex_ctrl(struct tegra_pcie_port *port)
  {
  	unsigned long ret = 0;
  
  	switch (port->index) {
  	case 0:
  		ret = AFI_PEX0_CTRL;
  		break;
  
  	case 1:
  		ret = AFI_PEX1_CTRL;
  		break;
  
  	case 2:
bbc5b36b2   Stephen Warren   pci: tegra: port ...
864
  		ret = port->pcie->soc->afi_pex2_ctrl;
f315828b0   Thierry Reding   pci: tegra: Add T...
865
866
867
868
869
  		break;
  	}
  
  	return ret;
  }
355560d58   Marcel Ziswiler   pci: tegra: intro...
870
  void tegra_pcie_port_reset(struct tegra_pcie_port *port)
f315828b0   Thierry Reding   pci: tegra: Add T...
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
  {
  	unsigned long ctrl = tegra_pcie_port_get_pex_ctrl(port);
  	unsigned long value;
  
  	/* pulse reset signel */
  	value = afi_readl(port->pcie, ctrl);
  	value &= ~AFI_PEX_CTRL_RST;
  	afi_writel(port->pcie, value, ctrl);
  
  	udelay(2000);
  
  	value = afi_readl(port->pcie, ctrl);
  	value |= AFI_PEX_CTRL_RST;
  	afi_writel(port->pcie, value, ctrl);
  }
355560d58   Marcel Ziswiler   pci: tegra: intro...
886
887
888
889
890
891
892
893
894
  int tegra_pcie_port_index_of_port(struct tegra_pcie_port *port)
  {
  	return port->index;
  }
  
  void __weak tegra_pcie_board_port_reset(struct tegra_pcie_port *port)
  {
  	tegra_pcie_port_reset(port);
  }
f315828b0   Thierry Reding   pci: tegra: Add T...
895
896
  static void tegra_pcie_port_enable(struct tegra_pcie_port *port)
  {
f39a6a327   Stephen Warren   pci: tegra: actua...
897
898
  	struct tegra_pcie *pcie = port->pcie;
  	const struct tegra_pcie_soc *soc = pcie->soc;
f315828b0   Thierry Reding   pci: tegra: Add T...
899
900
901
902
  	unsigned long ctrl = tegra_pcie_port_get_pex_ctrl(port);
  	unsigned long value;
  
  	/* enable reference clock */
f39a6a327   Stephen Warren   pci: tegra: actua...
903
  	value = afi_readl(pcie, ctrl);
f315828b0   Thierry Reding   pci: tegra: Add T...
904
  	value |= AFI_PEX_CTRL_REFCLK_EN;
f39a6a327   Stephen Warren   pci: tegra: actua...
905
  	if (pcie->soc->has_pex_clkreq_en)
f315828b0   Thierry Reding   pci: tegra: Add T...
906
907
908
  		value |= AFI_PEX_CTRL_CLKREQ_EN;
  
  	value |= AFI_PEX_CTRL_OVERRIDE_EN;
f39a6a327   Stephen Warren   pci: tegra: actua...
909
  	afi_writel(pcie, value, ctrl);
f315828b0   Thierry Reding   pci: tegra: Add T...
910

355560d58   Marcel Ziswiler   pci: tegra: intro...
911
  	tegra_pcie_board_port_reset(port);
514e19138   Stephen Warren   pci: tegra: imple...
912
913
914
915
916
917
  
  	if (soc->force_pca_enable) {
  		value = rp_readl(port, RP_VEND_CTL2);
  		value |= RP_VEND_CTL2_PCA_ENABLE;
  		rp_writel(port, value, RP_VEND_CTL2);
  	}
f39a6a327   Stephen Warren   pci: tegra: actua...
918
919
920
921
922
  
  	/* configure the reference clock driver */
  	pads_writel(pcie, soc->pads_refclk_cfg0, PADS_REFCLK_CFG0);
  	if (soc->num_ports > 2)
  		pads_writel(pcie, soc->pads_refclk_cfg1, PADS_REFCLK_CFG1);
f315828b0   Thierry Reding   pci: tegra: Add T...
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
  }
  
  static bool tegra_pcie_port_check_link(struct tegra_pcie_port *port)
  {
  	unsigned int retries = 3;
  	unsigned long value;
  
  	value = rp_readl(port, RP_PRIV_MISC);
  	value &= ~RP_PRIV_MISC_PRSNT_MAP_EP_ABSNT;
  	value |= RP_PRIV_MISC_PRSNT_MAP_EP_PRSNT;
  	rp_writel(port, value, RP_PRIV_MISC);
  
  	do {
  		unsigned int timeout = 200;
  
  		do {
  			value = rp_readl(port, RP_VEND_XP);
  			if (value & RP_VEND_XP_DL_UP)
  				break;
  
  			udelay(2000);
  		} while (--timeout);
  
  		if (!timeout) {
  			debug("link %u down, retrying
  ", port->index);
  			goto retry;
  		}
  
  		timeout = 200;
  
  		do {
  			value = rp_readl(port, RP_LINK_CONTROL_STATUS);
  			if (value & RP_LINK_CONTROL_STATUS_DL_LINK_ACTIVE)
  				return true;
  
  			udelay(2000);
  		} while (--timeout);
  
  retry:
355560d58   Marcel Ziswiler   pci: tegra: intro...
963
  		tegra_pcie_board_port_reset(port);
f315828b0   Thierry Reding   pci: tegra: Add T...
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
  	} while (--retries);
  
  	return false;
  }
  
  static void tegra_pcie_port_disable(struct tegra_pcie_port *port)
  {
  	unsigned long ctrl = tegra_pcie_port_get_pex_ctrl(port);
  	unsigned long value;
  
  	/* assert port reset */
  	value = afi_readl(port->pcie, ctrl);
  	value &= ~AFI_PEX_CTRL_RST;
  	afi_writel(port->pcie, value, ctrl);
  
  	/* disable reference clock */
  	value = afi_readl(port->pcie, ctrl);
  	value &= ~AFI_PEX_CTRL_REFCLK_EN;
  	afi_writel(port->pcie, value, ctrl);
  }
  
  static void tegra_pcie_port_free(struct tegra_pcie_port *port)
  {
  	list_del(&port->list);
  	free(port);
  }
  
  static int tegra_pcie_enable(struct tegra_pcie *pcie)
  {
  	struct tegra_pcie_port *port, *tmp;
  
  	list_for_each_entry_safe(port, tmp, &pcie->ports, list) {
  		debug("probing port %u, using %u lanes
  ", port->index,
  		      port->num_lanes);
  
  		tegra_pcie_port_enable(port);
  
  		if (tegra_pcie_port_check_link(port))
  			continue;
  
  		debug("link %u down, ignoring
  ", port->index);
  
  		tegra_pcie_port_disable(port);
  		tegra_pcie_port_free(port);
  	}
  
  	return 0;
  }
e81ca8845   Simon Glass   dm: tegra: pci: C...
1014
1015
1016
1017
1018
  static const struct tegra_pcie_soc pci_tegra_soc[] = {
  	[TEGRA20_PCIE] = {
  		.num_ports = 2,
  		.pads_pll_ctl = PADS_PLL_CTL_TEGRA20,
  		.tx_ref_sel = PADS_PLL_CTL_TXCLKREF_DIV10,
3cfc6be4a   Stephen Warren   pci: tegra: corre...
1019
  		.pads_refclk_cfg0 = 0xfa5cfa5c,
e81ca8845   Simon Glass   dm: tegra: pci: C...
1020
1021
1022
1023
1024
1025
1026
1027
1028
  		.has_pex_clkreq_en = false,
  		.has_pex_bias_ctrl = false,
  		.has_cml_clk = false,
  		.has_gen2 = false,
  	},
  	[TEGRA30_PCIE] = {
  		.num_ports = 3,
  		.pads_pll_ctl = PADS_PLL_CTL_TEGRA30,
  		.tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN,
bbc5b36b2   Stephen Warren   pci: tegra: port ...
1029
  		.afi_pex2_ctrl = AFI_PEX2_CTRL,
3cfc6be4a   Stephen Warren   pci: tegra: corre...
1030
1031
  		.pads_refclk_cfg0 = 0xfa5cfa5c,
  		.pads_refclk_cfg1 = 0xfa5cfa5c,
e81ca8845   Simon Glass   dm: tegra: pci: C...
1032
1033
1034
1035
1036
1037
1038
1039
1040
  		.has_pex_clkreq_en = true,
  		.has_pex_bias_ctrl = true,
  		.has_cml_clk = true,
  		.has_gen2 = false,
  	},
  	[TEGRA124_PCIE] = {
  		.num_ports = 2,
  		.pads_pll_ctl = PADS_PLL_CTL_TEGRA30,
  		.tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN,
3cfc6be4a   Stephen Warren   pci: tegra: corre...
1041
  		.pads_refclk_cfg0 = 0x44ac44ac,
e81ca8845   Simon Glass   dm: tegra: pci: C...
1042
1043
1044
1045
1046
1047
1048
1049
1050
  		.has_pex_clkreq_en = true,
  		.has_pex_bias_ctrl = true,
  		.has_cml_clk = true,
  		.has_gen2 = true,
  	},
  	[TEGRA210_PCIE] = {
  		.num_ports = 2,
  		.pads_pll_ctl = PADS_PLL_CTL_TEGRA30,
  		.tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN,
3cfc6be4a   Stephen Warren   pci: tegra: corre...
1051
  		.pads_refclk_cfg0 = 0x90b890b8,
e81ca8845   Simon Glass   dm: tegra: pci: C...
1052
1053
1054
1055
1056
  		.has_pex_clkreq_en = true,
  		.has_pex_bias_ctrl = true,
  		.has_cml_clk = true,
  		.has_gen2 = true,
  		.force_pca_enable = true,
bbc5b36b2   Stephen Warren   pci: tegra: port ...
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
  	},
  	[TEGRA186_PCIE] = {
  		.num_ports = 3,
  		.afi_pex2_ctrl = AFI_PEX2_CTRL_T186,
  		.pads_refclk_cfg0 = 0x80b880b8,
  		.pads_refclk_cfg1 = 0x000480b8,
  		.has_pex_clkreq_en = true,
  		.has_pex_bias_ctrl = true,
  		.has_gen2 = true,
  	},
d9eda6c44   Stephen Warren   pci: tegra: add/e...
1067
  };
e81ca8845   Simon Glass   dm: tegra: pci: C...
1068
  static int pci_tegra_ofdata_to_platdata(struct udevice *dev)
f315828b0   Thierry Reding   pci: tegra: Add T...
1069
  {
e81ca8845   Simon Glass   dm: tegra: pci: C...
1070
1071
  	struct tegra_pcie *pcie = dev_get_priv(dev);
  	enum tegra_pci_id id;
f315828b0   Thierry Reding   pci: tegra: Add T...
1072

e81ca8845   Simon Glass   dm: tegra: pci: C...
1073
1074
  	id = dev_get_driver_data(dev);
  	pcie->soc = &pci_tegra_soc[id];
f315828b0   Thierry Reding   pci: tegra: Add T...
1075

e81ca8845   Simon Glass   dm: tegra: pci: C...
1076
  	INIT_LIST_HEAD(&pcie->ports);
f315828b0   Thierry Reding   pci: tegra: Add T...
1077

68f008113   Simon Glass   dm: tegra: pci: C...
1078
  	if (tegra_pcie_parse_dt(dev, id, pcie))
e81ca8845   Simon Glass   dm: tegra: pci: C...
1079
  		return -EINVAL;
f315828b0   Thierry Reding   pci: tegra: Add T...
1080

e81ca8845   Simon Glass   dm: tegra: pci: C...
1081
1082
  	return 0;
  }
f315828b0   Thierry Reding   pci: tegra: Add T...
1083

e81ca8845   Simon Glass   dm: tegra: pci: C...
1084
1085
1086
1087
  static int pci_tegra_probe(struct udevice *dev)
  {
  	struct tegra_pcie *pcie = dev_get_priv(dev);
  	int err;
f315828b0   Thierry Reding   pci: tegra: Add T...
1088

bbc5b36b2   Stephen Warren   pci: tegra: port ...
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
  #ifdef CONFIG_TEGRA186
  	err = clk_get_by_name(dev, "afi", &pcie->clk_afi);
  	if (err) {
  		debug("clk_get_by_name(afi) failed: %d
  ", err);
  		return err;
  	}
  
  	err = clk_get_by_name(dev, "pex", &pcie->clk_pex);
  	if (err) {
  		debug("clk_get_by_name(pex) failed: %d
  ", err);
  		return err;
  	}
  
  	err = reset_get_by_name(dev, "afi", &pcie->reset_afi);
  	if (err) {
  		debug("reset_get_by_name(afi) failed: %d
  ", err);
  		return err;
  	}
  
  	err = reset_get_by_name(dev, "pex", &pcie->reset_pex);
  	if (err) {
  		debug("reset_get_by_name(pex) failed: %d
  ", err);
  		return err;
  	}
  
  	err = reset_get_by_name(dev, "pcie_x", &pcie->reset_pcie_x);
  	if (err) {
  		debug("reset_get_by_name(pcie_x) failed: %d
  ", err);
  		return err;
  	}
  
  	err = power_domain_get(dev, &pcie->pwrdom);
  	if (err) {
  		debug("power_domain_get() failed: %d
  ", err);
  		return err;
  	}
  #endif
e81ca8845   Simon Glass   dm: tegra: pci: C...
1132
1133
  	err = tegra_pcie_power_on(pcie);
  	if (err < 0) {
9b643e312   Masahiro Yamada   treewide: replace...
1134
  		pr_err("failed to power on");
e81ca8845   Simon Glass   dm: tegra: pci: C...
1135
1136
  		return err;
  	}
f315828b0   Thierry Reding   pci: tegra: Add T...
1137

e81ca8845   Simon Glass   dm: tegra: pci: C...
1138
1139
  	err = tegra_pcie_enable_controller(pcie);
  	if (err < 0) {
9b643e312   Masahiro Yamada   treewide: replace...
1140
  		pr_err("failed to enable controller");
e81ca8845   Simon Glass   dm: tegra: pci: C...
1141
1142
  		return err;
  	}
f315828b0   Thierry Reding   pci: tegra: Add T...
1143

e81ca8845   Simon Glass   dm: tegra: pci: C...
1144
1145
  	err = tegra_pcie_setup_translations(dev);
  	if (err < 0) {
9b643e312   Masahiro Yamada   treewide: replace...
1146
  		pr_err("failed to decode ranges");
e81ca8845   Simon Glass   dm: tegra: pci: C...
1147
1148
  		return err;
  	}
f315828b0   Thierry Reding   pci: tegra: Add T...
1149

e81ca8845   Simon Glass   dm: tegra: pci: C...
1150
1151
  	err = tegra_pcie_enable(pcie);
  	if (err < 0) {
9b643e312   Masahiro Yamada   treewide: replace...
1152
  		pr_err("failed to enable PCIe");
e81ca8845   Simon Glass   dm: tegra: pci: C...
1153
  		return err;
f315828b0   Thierry Reding   pci: tegra: Add T...
1154
1155
1156
1157
  	}
  
  	return 0;
  }
e81ca8845   Simon Glass   dm: tegra: pci: C...
1158
1159
1160
1161
  static const struct dm_pci_ops pci_tegra_ops = {
  	.read_config	= pci_tegra_read_config,
  	.write_config	= pci_tegra_write_config,
  };
f315828b0   Thierry Reding   pci: tegra: Add T...
1162

e81ca8845   Simon Glass   dm: tegra: pci: C...
1163
1164
1165
1166
1167
  static const struct udevice_id pci_tegra_ids[] = {
  	{ .compatible = "nvidia,tegra20-pcie", .data = TEGRA20_PCIE },
  	{ .compatible = "nvidia,tegra30-pcie", .data = TEGRA30_PCIE },
  	{ .compatible = "nvidia,tegra124-pcie", .data = TEGRA124_PCIE },
  	{ .compatible = "nvidia,tegra210-pcie", .data = TEGRA210_PCIE },
bbc5b36b2   Stephen Warren   pci: tegra: port ...
1168
  	{ .compatible = "nvidia,tegra186-pcie", .data = TEGRA186_PCIE },
e81ca8845   Simon Glass   dm: tegra: pci: C...
1169
1170
  	{ }
  };
a02e26354   Stephen Warren   pci: tegra: call ...
1171

e81ca8845   Simon Glass   dm: tegra: pci: C...
1172
1173
1174
1175
1176
1177
1178
1179
1180
  U_BOOT_DRIVER(pci_tegra) = {
  	.name	= "pci_tegra",
  	.id	= UCLASS_PCI,
  	.of_match = pci_tegra_ids,
  	.ops	= &pci_tegra_ops,
  	.ofdata_to_platdata = pci_tegra_ofdata_to_platdata,
  	.probe	= pci_tegra_probe,
  	.priv_auto_alloc_size = sizeof(struct tegra_pcie),
  };