summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/include/mach/pci.h
blob: e5eac3ad564088f93c4ee32098d17a87c0bf2a9d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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
115
116
117
118
119
120
121
122
123
124
125
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
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
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
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
/*
 *  arch/arm/mach-tegra/include/mach/pci.h
 *
 *  Header file containing constants for the tegra PCIe driver.
 *
 * Copyright (c) 2008-2009, NVIDIA Corporation.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

#ifndef __MACH_TEGRA_PCI_H

#include <linux/pci.h>
#include <mach/platform.h>

#include "nvrm_drf.h"
#include "ap20/dev_ap_pcie2_root_port.h"
#include "ap20/dev_ap_pcie2_pads.h"
#include "ap20/arafi.h"

extern void __iomem * volatile pci_tegra_regs;

/*
 * AXI address map for the PCIe aperture.  AP20, defines 1GB in the AXI
 *  address map for PCIe.
 *
 *  That address space is split into different regions, with sizes and
 *  offsets as follows. Exepct for the Register space, SW is free to slice the
 *  regions as it chooces.
 *
 *  The split below seems to work fine for now.
 *
 *  0x8000_0000 to 0x80ff_ffff - Register space          16MB.
 *  0x8100_0000 to 0x81ff_ffff - Config space            16MB.
 *  0x8200_0000 to 0x82ff_ffff - Extended config space   16MB.
 *  0x8300_0000 to 0x83ff_ffff - Downstream IO space
 *   ... Will be filled with other BARS like MSI/upstream IO etc.
 *  0x9000_0000 to 0x9fff_ffff - non-prefetchable memory aperture
 *  0xa000_0000 to 0xbfff_ffff - Prefetchable memory aperture
 *
 *  Config and Extended config sizes are choosen to support
 *  maximum of 256 devices,
 *  which is good enough for all the AP20 use cases.
 * */

#define PCIE_REGS_SIZE			0x01000000UL
#define PCIE_CONFIG_OFFSET		PCIE_REGS_SIZE
#define PCIE_CONFIG_SIZE		0x01000000UL
#define PCIE_EXTENDED_CONFIG_OFFSET	(PCIE_CONFIG_SIZE + PCIE_CONFIG_OFFSET)
#define PCIE_EXTENDED_CONFIG_SIZE	0x01000000UL
#define PCIE_DOWNSTREAM_IO_OFFSET	(PCIE_EXTENDED_CONFIG_SIZE + \
					PCIE_EXTENDED_CONFIG_OFFSET)
#define PCIE_DOWNSTREAM_IO_SIZE		0x00100000UL

#define PCIE_NON_PREFETCH_MEMORY_OFFSET	0x10000000UL
#define PCIE_NON_PREFETCH_MEMORY_SIZE	0x10000000UL
#define PCIE_PREFETCH_MEMORY_OFFSET	(PCIE_NON_PREFETCH_MEMORY_OFFSET + \
					PCIE_NON_PREFETCH_MEMORY_SIZE)
#define PCIE_PREFETCH_MEMORY_SIZE	0x20000000UL

/* PCIe registers can be classified into 4 regions.
 *
 * 1. AFI registers - AFI is a wrapper between PCIE and ARM AXI bus. These
 * registers define the address translation registers, interrupt registers and
 * some configuration (a.k.a CYA) registers.
 * 2. PAD registers - PAD control registers which are inside the PCIE CORE.
 * 3. Configuration 0 and Configuration 1 registers - These registers are PCIe
 * configuration registers of Root port 0 and root port 1.
 *
 * Check the PcieRegType enumeration for the list of Registers banks inside the
 * PCIE aperture.
 *
 * */
#define NV_PCIE_AXI_AFI_REGS_OFSET	0x3800UL
#define NV_PCIE_AXI_PADS_OFSET		0x3000UL
#define NV_PCIE_AXI_RP_T0C0_OFFSET	0x0000UL
#define NV_PCIE_AXI_RP_T0C1_OFFSET	0x1000UL

/* During the boot only registers/config and extended config apertures are
 * mapped. Rest are mapped on demand by the PCI device drivers.
 */
#define PCI_TEGRA_IOMAPPED_REG_APERTURE_SIZE	\
	(PCIE_REGS_SIZE + PCIE_CONFIG_SIZE + PCIE_EXTENDED_CONFIG_SIZE)

/*
 *  PCI address map for memory mapped devices. Still using 32-bit aperture.
 *
 *  1GB for the system memory.
 *  Everything mapped as cpu physical = pci
 *
 */
#define FPCI_SYSTEM_MEMORY_OFFSET           0x0UL
#define FPCI_SYSTEM_MEMORY_SIZE             0x40000000UL
#define FPCI_NON_PREFETCH_MEMORY_OFFSET     0x90000000UL
#define FPCI_NON_PREFETCH_MEMORY_SIZE       PCIE_NON_PREFETCH_MEMORY_SIZE
#define FPCI_PREFETCH_MEMORY_OFFSET         (FPCI_NON_PREFETCH_MEMORY_OFFSET+ \
						FPCI_NON_PREFETCH_MEMORY_SIZE)
#define FPCI_PREFETCH_MEMORY_SIZE           0x40000000UL




/* PCIE DRF macros to read and write PRI registers */

/** NVPCIE_DRF_DEF - define a new register value.

	@param d register domain (hardware block)
	@param r register name
	@param f register field
	@param c defined value for the field
 */
#define NVPCIE_DRF_DEF(d,r,f,c) \
	((NV_PROJ__PCIE2_##d##_##r##_##f##_##c)  \
	<< NV_FIELD_SHIFT(NV_PROJ__PCIE2_##d##_##r##_##f))

/** NVPCIE_DRF_NUM - define a new register value.

	@param d register domain (hardware block)
	@param r register name
	@param f register field
	@param n numeric value for the field
 */
#define NVPCIE_DRF_NUM(d,r,f,n) \
	(((n)& NV_FIELD_MASK(NV_PROJ__PCIE2_##d##_##r##_##f)) << \
	NV_FIELD_SHIFT(NV_PROJ__PCIE2_##d##_##r##_##f))

/** NVPCIE_DRF_VAL - read a field from a register.

	@param d register domain (hardware block)
	@param r register name
	@param f register field
	@param v register value
 */
#define NVPCIE_DRF_VAL(d,r,f,v) \
	(((v)>> NV_FIELD_SHIFT(NV_PROJ__PCIE2_##d##_##r##_##f)) & \
        NV_FIELD_MASK(NV_PROJ__PCIE2_##d##_##r##_##f))

/** NVPCIE_FLD_SET_DRF_NUM - modify a register field.

	@param d register domain (hardware block)
	@param r register name
	@param f register field
	@param n numeric field value
	@param v register value
 */
#define NVPCIE_FLD_SET_DRF_NUM(d,r,f,n,v) \
	((v & ~NV_FIELD_SHIFTMASK(NV_PROJ__PCIE2_##d##_##r##_##f)) | \
	NVPCIE_DRF_NUM(d,r,f,n))

/** NVPCIE_FLD_SET_DRF_DEF - modify a register field.

	@param d register domain (hardware block)
	@param r register name
	@param f register field
	@param c defined field value
	@param v register value
 */
#define NVPCIE_FLD_SET_DRF_DEF(d,r,f,c,v) \
    (((v) & ~NV_FIELD_SHIFTMASK(NV_PROJ__PCIE2_##d##_##r##_##f)) | \
        NVPCIE_DRF_DEF(d,r,f,c))

/** NVPCIE_RESETVAL - get the reset value for a register.

	@param d register domain (hardware block)
	@param r register name
 */
#define NVPCIE_RESETVAL(d,r)    (d##_##r##_0_RESET_VAL)

/* Register access inline functions */

static inline void pci_tegra_afi_writel(u32 value,unsigned long offset)
{
	writel(value, offset + NV_PCIE_AXI_AFI_REGS_OFSET + pci_tegra_regs);
}

static inline void pci_tegra_rp_writel(u32 value, unsigned long offset, int rp)
{
	BUG_ON(rp != 0 && rp != 1);

	if (rp == 0) offset += NV_PCIE_AXI_RP_T0C0_OFFSET;
	if (rp == 1) offset += NV_PCIE_AXI_RP_T0C1_OFFSET;

	writel(value, offset + pci_tegra_regs);
}

static inline void pci_tegra_rp_writew(u16 value, unsigned long offset, int rp)
{
	u32 reg;

	BUG_ON(rp != 0 && rp != 1);

	if (rp == 0) offset += NV_PCIE_AXI_RP_T0C0_OFFSET;
	if (rp == 1) offset += NV_PCIE_AXI_RP_T0C1_OFFSET;

	reg = readl((offset & ~0x3) + pci_tegra_regs);
	reg &= ~(0xffff << ((offset & 0x3) * 8));
	reg |= (u32)value << ((offset & 0x3) * 8);
	writel(reg, (offset & ~0x3) + pci_tegra_regs);
}

static inline void pci_tegra_rp_writeb(u8 value, unsigned long offset, int rp)
{
	u32 reg;

	BUG_ON(rp != 0 && rp != 1);

	if (rp == 0) offset += NV_PCIE_AXI_RP_T0C0_OFFSET;
	if (rp == 1) offset += NV_PCIE_AXI_RP_T0C1_OFFSET;

	reg = readl((offset & ~0x3) + pci_tegra_regs);
	reg &= ~(0xff << ((offset & 0x3) * 8));
	reg |= (u32)value << ((offset & 0x3) * 8);
	writel(reg, (offset & ~0x3) + pci_tegra_regs);
}

static inline void pci_tegra_pads_writel(u32 value, unsigned long offset)
{
	writel(value, offset + NV_PCIE_AXI_PADS_OFSET + pci_tegra_regs);
}

static inline u32 pci_tegra_afi_readl(unsigned long offset)
{
	return readl(offset + NV_PCIE_AXI_AFI_REGS_OFSET + pci_tegra_regs);
}

static inline u32 pci_tegra_rp_readl(unsigned long offset, int rp)
{
	BUG_ON(rp != 0 && rp != 1);

	if (rp == 0) offset += NV_PCIE_AXI_RP_T0C0_OFFSET;
	if (rp == 1) offset += NV_PCIE_AXI_RP_T0C1_OFFSET;

	return readl(offset + pci_tegra_regs);
}

static inline u16 pci_tegra_rp_readw(unsigned long offset, int rp)
{
	u32 val;

	BUG_ON(rp != 0 && rp != 1);

	if (rp == 0) offset += NV_PCIE_AXI_RP_T0C0_OFFSET;
	if (rp == 1) offset += NV_PCIE_AXI_RP_T0C1_OFFSET;

	val = readl((offset & ~0x3) + pci_tegra_regs);
	val >>=  8 * (offset & 3);
	val &= 0xffff;

	return (u16)val;
}

static inline u8 pci_tegra_rp_readb(unsigned long offset, int rp)
{
	u32 val;

	BUG_ON(rp != 0 && rp != 1);

	if (rp == 0) offset += NV_PCIE_AXI_RP_T0C0_OFFSET;
	if (rp == 1) offset += NV_PCIE_AXI_RP_T0C1_OFFSET;

	val = readl((offset & ~0x3) + pci_tegra_regs);
	val >>=  8 * (offset & 3);
	val &= 0xff;

	return (u8)val;
}

static inline u32 pci_tegra_pads_reedl(unsigned long offset)
{
	return readl(offset + NV_PCIE_AXI_PADS_OFSET + pci_tegra_regs);
}

static inline bool pci_tegra_is_rp(u32 bus_number, int *rp)
{
	if (bus_number == pci_tegra_rp_readb(PCI_PRIMARY_BUS, 0)) {
		*rp = 0;
		return true;
	} else if (bus_number == pci_tegra_rp_readb(PCI_PRIMARY_BUS, 1)) {
		*rp = 1;
		return true;
	} else
		return false;
}

/*
 *	Given the bus number, devfn and the offset this API returns the mapped
 *	address of the config space.
 */
static inline void __iomem *pci_tegra_config_addr(u8 bus_number,
	u32 devfn, u32 where)
{
	void *addr;
	u32 function;
	u32 device;

	function = PCI_FUNC(devfn);
	device = PCI_SLOT(devfn);

	addr = pci_tegra_regs;
	addr += (where < 256) ? PCIE_CONFIG_OFFSET
		   : PCIE_EXTENDED_CONFIG_OFFSET;
	addr += bus_number << 16;
	addr += device << 11;
	addr += function << 8;
	addr += where;
	return addr;
}

void pci_tegra_enumerate(void);

#endif