Commit c8e482cf72929228b06adf82a0772ed060eb77c2
Committed by
Larisa Grigore
1 parent
b3d4a0d4bd
Exists in
smarc_8mq_lf_v2020.04
and in
4 other branches
s32v234pcie: Bring in fix for link reset recovery
Enable EP ignoring ERR009852 Signed-off-by: Heinz Wrobel <Heinz.Wrobel@freescale.com> Signed-off-by: Aurelian Floricica <b43657@freescale.com> Signed-off-by: Costin Carabas <costin.carabas@nxp.com> Signed-off-by: Stefan-Gabriel Mirea <stefan-gabriel.mirea@nxp.com> Signed-off-by: Larisa Grigore <larisa.grigore@nxp.com>
Showing 7 changed files with 664 additions and 186 deletions Side-by-side Diff
arch/arm/cpu/armv8/s32v234/Makefile
arch/arm/cpu/armv8/s32v234/gicsupport.c
1 | +// SPDX-License-Identifier: GPL-2.0+ | |
2 | +/* | |
3 | + * (C) Copyright 2016,2020 NXP | |
4 | + * Heinz Wrobel <Heinz.Wrobel@nxp.com> | |
5 | + * | |
6 | + * Basic GIC support to permit dealing with interrupt handlers in ARMv8. | |
7 | + * This code is currently only tested on S32V234, but should be generic | |
8 | + * enough to be placed outside a CPU specific directory at some point. | |
9 | + * We ignore SGI/PPI because that is done in gic_64.S. | |
10 | + * | |
11 | + * Some of this code is taken from sources developed by <Jay.Tu@nxp.com> | |
12 | + */ | |
13 | + | |
14 | +#include <common.h> | |
15 | +#include <linux/compiler.h> | |
16 | +#include <asm/io.h> | |
17 | +#include <asm/gicsupport.h> | |
18 | +#include <asm/gic.h> | |
19 | +#include <asm/proc-armv/system.h> | |
20 | + | |
21 | +#define GICD_INVALID_IRQ (-1) | |
22 | + | |
23 | +#define GICD_ICENABLERn_CLEAR_MASK (0xffffffff) | |
24 | + | |
25 | +#define HWIRQ_BIT(irq) BIT((irq) & 0x1f) | |
26 | +#define HWIRQ_BANK(irq) (((irq) >> 5) * sizeof(u32)) | |
27 | + | |
28 | +#define HWIRQ_BANK_2BITS(irq) (((irq) >> 4) * sizeof(u32)) | |
29 | + | |
30 | +#define GICD_INT_DEF_TARGET (0x01) | |
31 | +#define GICD_INT_DEF_TARGET_X4 ((GICD_INT_DEF_TARGET << 24) |\ | |
32 | + (GICD_INT_DEF_TARGET << 16) |\ | |
33 | + (GICD_INT_DEF_TARGET << 8) |\ | |
34 | + GICD_INT_DEF_TARGET) | |
35 | + | |
36 | +#define GICD_INT_DEF_PRI (0xa0) | |
37 | +#define GICD_INT_DEF_PRI_X4 ((GICD_INT_DEF_PRI << 24) |\ | |
38 | + (GICD_INT_DEF_PRI << 16) |\ | |
39 | + (GICD_INT_DEF_PRI << 8) |\ | |
40 | + GICD_INT_DEF_PRI) | |
41 | + | |
42 | +#define GICD_TYPER_SPIS(typer) ((((typer) & 0x1f) + 1) * 32) | |
43 | +#define GICD_CTLR_ENABLE_G1A BIT(1) | |
44 | +#define GICD_CTLR_ENABLE_G1 BIT(0) | |
45 | +#define GICR_PROPBASER_IDBITS_MASK (0x1f) | |
46 | +#define GICC_PMR_PRIORITY (0xff) | |
47 | + | |
48 | +#define GICD_ICFGR_MASK (0x3) | |
49 | +#define GICD_ICFGR_IRQ_SHIFT(irq) (((irq) & 0x0f) * 2) | |
50 | +#define GICD_ICFGR_IRQ_MASK(irq) (GICD_ICFGR_MASK << \ | |
51 | + GICD_ICFGR_IRQ_SHIFT(irq)) | |
52 | +#define GICD_ICFGR_IRQ_TYPE(type, irq) ((type & GICD_ICFGR_MASK) << \ | |
53 | + GICD_ICFGR_IRQ_SHIFT(irq)) | |
54 | + | |
55 | +#define GIC_SUPPORTED_HANDLERS (16) | |
56 | + | |
57 | +#define GIC_GROUP_IRQ (1022) | |
58 | +#define GIC_SPURIOUS_IRQ (1023) | |
59 | + | |
60 | +/* A performance implementation would use an indexed table. | |
61 | + * U-Boot has a need for a small footprint, so we do a simple search | |
62 | + * and only support a few handlers concurrently. | |
63 | + */ | |
64 | +static struct | |
65 | +{ | |
66 | + int irq; | |
67 | + void (*handler)(struct pt_regs *pt_regs, unsigned int esr); | |
68 | + const char *name; | |
69 | + int type; | |
70 | + u32 count; | |
71 | +} inthandlers[GIC_SUPPORTED_HANDLERS]; | |
72 | + | |
73 | +static u32 count_spurious; | |
74 | +static bool pre_init_done, full_init_done; | |
75 | + | |
76 | +static void interrupt_handler_init(void) | |
77 | +{ | |
78 | + /* We need to decouple this init from the generic | |
79 | + * interrupt_init() function because interrupt handlers | |
80 | + * may be preregistered by code before the GIC init has | |
81 | + * happened! PCIe support is a good example for this. | |
82 | + */ | |
83 | + int i; | |
84 | + | |
85 | + if (!pre_init_done) { | |
86 | + pre_init_done = 1; | |
87 | + /* Make sure that we do not have any active handlers */ | |
88 | + for (i = 0; i < ARRAY_SIZE(inthandlers); i++) { | |
89 | + inthandlers[i].irq = GICD_INVALID_IRQ; | |
90 | + inthandlers[i].count = 0; | |
91 | + } | |
92 | + count_spurious = 0; | |
93 | + } | |
94 | +} | |
95 | + | |
96 | +/* Function to support handlers. Benign to call before GIC init */ | |
97 | +static void gic_unmask_irq(unsigned int irq) | |
98 | +{ | |
99 | + u32 mask; | |
100 | + | |
101 | + if (full_init_done) { | |
102 | + mask = HWIRQ_BIT(irq); | |
103 | + writel(mask, | |
104 | + GICD_BASE + GICD_ISENABLERn + HWIRQ_BANK(irq)); | |
105 | + } | |
106 | +} | |
107 | + | |
108 | +/* Function to support handlers. Benign to call before GIC init */ | |
109 | +static void gic_mask_irq(unsigned int irq) | |
110 | +{ | |
111 | + u32 mask = HWIRQ_BIT(irq); | |
112 | + | |
113 | + writel(mask, GICD_BASE + GICD_ICENABLERn + HWIRQ_BANK(irq)); | |
114 | +} | |
115 | + | |
116 | +/* Function to support handlers. Benign to call before GIC init */ | |
117 | +static void gic_set_type(unsigned int irq, int type) | |
118 | +{ | |
119 | + u32 icfgr; | |
120 | + | |
121 | + if (full_init_done) { | |
122 | + icfgr = readl(GICD_BASE + GICD_ICFGR + | |
123 | + HWIRQ_BANK_2BITS(irq)); | |
124 | + icfgr &= ~GICD_ICFGR_IRQ_MASK(irq); | |
125 | + icfgr |= GICD_ICFGR_IRQ_TYPE(type, irq); | |
126 | + writel(icfgr, | |
127 | + GICD_BASE + GICD_ICFGR + HWIRQ_BANK_2BITS(irq)); | |
128 | + } | |
129 | +} | |
130 | + | |
131 | +static void gic_dist_init(unsigned long base) | |
132 | +{ | |
133 | + unsigned int gic_irqs, i; | |
134 | + u32 ctlr = readl(base + GICD_CTLR); | |
135 | + | |
136 | + /* We turn off the GIC while we mess with it. | |
137 | + * The original init has happened in gic_64.S! | |
138 | + */ | |
139 | + writel(ctlr & ~(GICD_CTLR_ENABLE_G1A | GICD_CTLR_ENABLE_G1), | |
140 | + base + GICD_CTLR); | |
141 | + | |
142 | + gic_irqs = GICD_TYPER_SPIS(readl(base + GICD_TYPER)); | |
143 | + | |
144 | + /* | |
145 | + * Set all global interrupts to be level triggered, active low. | |
146 | + */ | |
147 | + for (i = 32; i < gic_irqs; i += 16) | |
148 | + writel(0, base + GICD_ICFGR + i / 4); | |
149 | + | |
150 | + /* | |
151 | + * Set all global interrupts to this CPU only. | |
152 | + */ | |
153 | + for (i = 32; i < gic_irqs; i += 4) | |
154 | + writel(GICD_INT_DEF_TARGET_X4, base + GICD_ITARGETSRn + i); | |
155 | + | |
156 | + /* | |
157 | + * Set priority on all global interrupts. | |
158 | + */ | |
159 | + | |
160 | + for (i = 32; i < gic_irqs; i += 4) | |
161 | + writel(GICD_INT_DEF_PRI_X4, base + GICD_IPRIORITYRn + i); | |
162 | + | |
163 | + /* | |
164 | + * Disable all interrupts. Leave the PPI and SGIs alone | |
165 | + * as these enables are banked registers. | |
166 | + */ | |
167 | + for (i = 32; i < gic_irqs; i += 32) | |
168 | + writel(GICD_ICENABLERn_CLEAR_MASK, | |
169 | + base + GICD_ICENABLERn + i / 8); | |
170 | + | |
171 | + writel(ctlr, base + GICD_CTLR); | |
172 | +} | |
173 | + | |
174 | +static void gic_cpu_clean(unsigned long dist_base, unsigned long cpu_base) | |
175 | +{ | |
176 | + /* Initially we need to make sure that we do not have any | |
177 | + * left over requests that could cause a mess during | |
178 | + * initialization. This happens during sloppy SMP init in | |
179 | + * lowlevel.S and should be FIXED. *sigh* | |
180 | + */ | |
181 | + writel(GICD_ICENABLERn_CLEAR_MASK, dist_base + GICD_ICENABLERn); | |
182 | +} | |
183 | + | |
184 | +static void gic_cpu_init(unsigned long dist_base, unsigned long cpu_base) | |
185 | +{ | |
186 | + /* Accept just about anything */ | |
187 | + writel(GICC_PMR_PRIORITY, cpu_base + GICC_PMR); | |
188 | + | |
189 | + /* gic_64.S doesn't set the recommended AckCtl value. We do */ | |
190 | + writel(0x1e3, cpu_base + GICC_CTLR); | |
191 | +} | |
192 | + | |
193 | +/* Public function to support handlers. Benign to call before GIC init */ | |
194 | +int gic_irq_status(unsigned int irq) | |
195 | +{ | |
196 | + u32 mask = HWIRQ_BIT(irq); | |
197 | + u32 v = readl(GICD_BASE + GICD_ISPENDRn + HWIRQ_BANK(irq)); | |
198 | + | |
199 | + return !!(v & mask); | |
200 | +} | |
201 | + | |
202 | +int gic_register_handler(int irq, | |
203 | + void (*handler)(struct pt_regs *pt_regs, | |
204 | + unsigned int esr), int type, | |
205 | + const char *name) | |
206 | +{ | |
207 | + int i; | |
208 | + | |
209 | + interrupt_handler_init(); | |
210 | + | |
211 | + if (full_init_done) | |
212 | + gic_mask_irq(irq); | |
213 | + | |
214 | + for (i = 0; i < ARRAY_SIZE(inthandlers); i++) { | |
215 | + if (inthandlers[i].irq < 0) { | |
216 | + inthandlers[i].handler = handler; | |
217 | + inthandlers[i].name = name; | |
218 | + inthandlers[i].type = type; | |
219 | + | |
220 | + /* Done last to avoid race condition */ | |
221 | + inthandlers[i].irq = irq; | |
222 | + | |
223 | + if (full_init_done) { | |
224 | + gic_set_type(irq, type); | |
225 | + gic_unmask_irq(irq); | |
226 | + } | |
227 | + break; | |
228 | + } | |
229 | + } | |
230 | + | |
231 | + return i >= ARRAY_SIZE(inthandlers) ? 0 : 1; | |
232 | +} | |
233 | + | |
234 | +int interrupt_init(void) | |
235 | +{ | |
236 | + int i; | |
237 | + | |
238 | + interrupt_handler_init(); | |
239 | + | |
240 | + gic_cpu_clean(GICD_BASE, GICC_BASE); | |
241 | + | |
242 | + gic_dist_init(GICD_BASE); | |
243 | + | |
244 | + /* U-Boot runs with a single CPU only */ | |
245 | + gic_cpu_init(GICD_BASE, GICC_BASE); | |
246 | + | |
247 | + full_init_done = 1; | |
248 | + | |
249 | + /* Now that we have set up the GIC, we need to start up | |
250 | + * any preregistered handlers. | |
251 | + */ | |
252 | + for (i = 0; i < ARRAY_SIZE(inthandlers); i++) { | |
253 | + int irq = inthandlers[i].irq; | |
254 | + | |
255 | + if (irq >= 0) { | |
256 | + gic_set_type(irq, inthandlers[i].type); | |
257 | + gic_unmask_irq(irq); | |
258 | + } | |
259 | + } | |
260 | + | |
261 | + return 0; | |
262 | +} | |
263 | + | |
264 | +void enable_interrupts(void) | |
265 | +{ | |
266 | + local_irq_enable(); | |
267 | +} | |
268 | + | |
269 | +int disable_interrupts(void) | |
270 | +{ | |
271 | + int flags; | |
272 | + | |
273 | + local_irq_save(flags); | |
274 | + | |
275 | + return flags; | |
276 | +} | |
277 | + | |
278 | +void do_irq(struct pt_regs *pt_regs, unsigned int esr) | |
279 | +{ | |
280 | + int i, group = 0; | |
281 | + u32 thisirq = readl(GICC_BASE + GICC_IAR); | |
282 | + | |
283 | + if (thisirq == GIC_GROUP_IRQ) { | |
284 | + /* Group 1 interrupt! */ | |
285 | + group = 1; | |
286 | + thisirq = readl(GICC_BASE + GICC_AIAR); | |
287 | + } | |
288 | + | |
289 | + if (thisirq == GIC_SPURIOUS_IRQ) { | |
290 | + count_spurious++; | |
291 | + return; | |
292 | + } | |
293 | + | |
294 | + for (i = 0; i < ARRAY_SIZE(inthandlers); i++) { | |
295 | + if (inthandlers[i].irq == thisirq) { | |
296 | + inthandlers[i].count++; | |
297 | + inthandlers[i].handler(pt_regs, esr); | |
298 | + | |
299 | + break; | |
300 | + } | |
301 | + } | |
302 | + | |
303 | + if (group) | |
304 | + writel(thisirq, GICC_BASE + GICC_AEOIR); | |
305 | + else | |
306 | + writel(thisirq, GICC_BASE + GICC_EOIR); | |
307 | + | |
308 | + if (i >= ARRAY_SIZE(inthandlers)) { | |
309 | + printf("\"Irq\" handler, esr 0x%08x for GIC irq %d, group %d\n", | |
310 | + esr, thisirq, group); | |
311 | + show_regs(pt_regs); | |
312 | + panic("Resetting CPU ...\n"); | |
313 | + } | |
314 | +} | |
315 | + | |
316 | +#if defined(CONFIG_CMD_IRQ) | |
317 | +int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) | |
318 | +{ | |
319 | + int i; | |
320 | + | |
321 | + printf("GIC support is enabled for GIC @ 0x%08x\n", GICD_BASE); | |
322 | + printf("Spurious: %d\n", count_spurious); | |
323 | + for (i = 0; i < ARRAY_SIZE(inthandlers); i++) { | |
324 | + if (inthandlers[i].irq >= 0) { | |
325 | + printf("%20s(%d): %d\n", inthandlers[i].name, | |
326 | + inthandlers[i].irq, | |
327 | + inthandlers[i].count); | |
328 | + } | |
329 | + } | |
330 | + | |
331 | + return 0; | |
332 | +} | |
333 | +#endif |
arch/arm/include/asm/gicsupport.h
1 | +/* SPDX-License-Identifier: GPL-2.0+ */ | |
2 | +/* | |
3 | + * Copyright 2016 NXP | |
4 | + * | |
5 | + */ | |
6 | + /* Functions declared in arch/arm/cpu/armv8/s32/gicsupport.c */ | |
7 | +int gic_irq_status(unsigned int irq); | |
8 | +int gic_register_handler(int irq, | |
9 | + void (*handler)(struct pt_regs *pt_regs, | |
10 | + unsigned int esr), | |
11 | + int type, const char *name); |
arch/arm/lib/interrupts_64.c
1 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | 2 | /* |
3 | 3 | * (C) Copyright 2013 |
4 | + * Copyright 2016,2020 NXP | |
4 | 5 | * David Feng <fenghua@phytium.com.cn> |
5 | 6 | */ |
6 | 7 | |
7 | 8 | |
8 | 9 | |
9 | 10 | |
... | ... | @@ -11,21 +12,28 @@ |
11 | 12 | |
12 | 13 | DECLARE_GLOBAL_DATA_PTR; |
13 | 14 | |
14 | -int interrupt_init(void) | |
15 | +int __interrupt_init(void) | |
15 | 16 | { |
16 | 17 | return 0; |
17 | 18 | } |
18 | 19 | |
19 | -void enable_interrupts(void) | |
20 | +void __enable_interrupts(void) | |
20 | 21 | { |
21 | 22 | return; |
22 | 23 | } |
23 | 24 | |
24 | -int disable_interrupts(void) | |
25 | +int __disable_interrupts(void) | |
25 | 26 | { |
26 | 27 | return 0; |
27 | 28 | } |
28 | 29 | |
30 | +int interrupt_init(void) | |
31 | + __attribute__((weak, alias("__interrupt_init"))); | |
32 | +void enable_interrupts(void) | |
33 | + __attribute__((weak, alias("__enable_interrupts"))); | |
34 | +int disable_interrupts(void) | |
35 | + __attribute__((weak, alias("__disable_interrupts"))); | |
36 | + | |
29 | 37 | static void show_efi_loaded_images(struct pt_regs *regs) |
30 | 38 | { |
31 | 39 | efi_print_image_infos((void *)regs->elr); |
32 | 40 | |
... | ... | @@ -120,9 +128,9 @@ |
120 | 128 | } |
121 | 129 | |
122 | 130 | /* |
123 | - * do_irq handles the Irq exception. | |
131 | + * __do_irq handles the Irq exception. | |
124 | 132 | */ |
125 | -void do_irq(struct pt_regs *pt_regs, unsigned int esr) | |
133 | +void __do_irq(struct pt_regs *pt_regs, unsigned int esr) | |
126 | 134 | { |
127 | 135 | efi_restore_gd(); |
128 | 136 | printf("\"Irq\" handler, esr 0x%08x\n", esr); |
129 | 137 | |
... | ... | @@ -132,9 +140,9 @@ |
132 | 140 | } |
133 | 141 | |
134 | 142 | /* |
135 | - * do_fiq handles the Fiq exception. | |
143 | + * __do_fiq handles the Fiq exception. | |
136 | 144 | */ |
137 | -void do_fiq(struct pt_regs *pt_regs, unsigned int esr) | |
145 | +void __do_fiq(struct pt_regs *pt_regs, unsigned int esr) | |
138 | 146 | { |
139 | 147 | efi_restore_gd(); |
140 | 148 | printf("\"Fiq\" handler, esr 0x%08x\n", esr); |
... | ... | @@ -142,6 +150,11 @@ |
142 | 150 | show_efi_loaded_images(pt_regs); |
143 | 151 | panic("Resetting CPU ...\n"); |
144 | 152 | } |
153 | + | |
154 | +void do_irq(struct pt_regs *pt_regs, unsigned int esr) | |
155 | + __attribute__((weak, alias("__do_irq"))); | |
156 | +void do_fiq(struct pt_regs *pt_regs, unsigned int esr) | |
157 | + __attribute__((weak, alias("__do_fiq"))); | |
145 | 158 | |
146 | 159 | /* |
147 | 160 | * do_error handles the Error exception. |
drivers/pci/pcie_s32v2xx.c
... | ... | @@ -2,8 +2,9 @@ |
2 | 2 | /* |
3 | 3 | * Freescale S32V234 PCI Express Root-Complex driver |
4 | 4 | * |
5 | - * Copyright (C) 2013 Marek Vasut <marex@denx.de> | |
6 | - * Copyright 2020 NXP | |
5 | + * Copyright (C) 2016 Heinz Wrobel <heinz.wrobel@nxp.com> | |
6 | + * Copyright (C) 2015 Aurelian Voicu <aurelian.voicu@nxp.com> | |
7 | + * Copyright (C) 2016,2020 NXP | |
7 | 8 | * |
8 | 9 | * Based on upstream iMX U-Boot driver: |
9 | 10 | * pcie_imx.c: Marek Vasut <marex@denx.de> |
... | ... | @@ -19,6 +20,7 @@ |
19 | 20 | #include <asm/arch/mc_me_regs.h> |
20 | 21 | #include <asm/arch/mc_cgm_regs.h> |
21 | 22 | #include <asm/io.h> |
23 | +#include <asm/gicsupport.h> | |
22 | 24 | #include <linux/sizes.h> |
23 | 25 | |
24 | 26 | #define PCI_ACCESS_READ 0 |
25 | 27 | |
26 | 28 | |
... | ... | @@ -82,30 +84,32 @@ |
82 | 84 | #define PCIE_ATU_FUNC(x) (((x) & 0x7) << 16) |
83 | 85 | #define PCIE_ATU_UPPER_TARGET 0x91C |
84 | 86 | |
85 | -#ifdef CONFIG_PCIE_EP_MODE | |
87 | +/* The following defines are used for EP mode only */ | |
86 | 88 | #define MSI_REGION 0x72FB0000 |
87 | -#define PCI_BASE_ADDR 0x72000000 | |
88 | -#define PCI_BASE_DBI 0x72FFC000 | |
89 | -#define MSI_REGION_NR 3 | |
90 | -#define NR_REGIONS 4 | |
91 | -#define PCI_REGION_MEM 0x00000000 /* PCI mem space */ | |
92 | -#define PCI_REGION_IO 0x00000001 /* PCI IO space */ | |
93 | -#define PCI_WIDTH_32b 0x00000000 /* 32-bit BAR */ | |
94 | -#define PCI_WIDTH_64b 0x00000004 /* 64-bit BAR */ | |
95 | -#define PCI_REGION_PREFETCH 0x00000008 /* prefetch PCI mem */ | |
96 | -#define PCI_REGION_NON_PREFETCH 0x00000000 /* non-prefetch PCI mem */ | |
97 | -#define PCIE_BAR0_SIZE SZ_1M /* 1MB */ | |
98 | -#define PCIE_BAR1_SIZE 0 | |
99 | -#define PCIE_BAR2_SIZE SZ_1M /* 1MB */ | |
100 | -#define PCIE_BAR3_SIZE 0 /* 256B Fixed sizing */ | |
101 | -#define PCIE_BAR4_SIZE 0 /* 4K Fixed sizing */ | |
102 | -#define PCIE_BAR5_SIZE 0 /* 64K Fixed sizing */ | |
89 | +#define PCI_BASE_ADDR 0x72000000 | |
90 | +#define PCI_BASE_DBI 0x72FFC000 | |
91 | +#define MSI_REGION_NR 3 | |
92 | +#define NR_REGIONS 4 | |
93 | +#define PCI_REGION_MEM 0x00000000 /* PCI mem space */ | |
94 | +#define PCI_REGION_IO 0x00000001 /* PCI IO space */ | |
95 | +#define PCI_WIDTH_32b 0x00000000 /* 32-bit BAR */ | |
96 | +#define PCI_WIDTH_64b 0x00000004 /* 64-bit BAR */ | |
97 | +#define PCI_REGION_PREFETCH 0x00000008 /* prefetch PCI mem */ | |
98 | +#define PCI_REGION_NON_PREFETCH 0x00000000 /* non-prefetch PCI mem */ | |
99 | +#define PCIE_BAR0_SIZE SZ_1M /* 1MB */ | |
100 | +#define PCIE_BAR1_SIZE 0 | |
101 | +#define PCIE_BAR2_SIZE SZ_1M /* 1MB */ | |
102 | +#define PCIE_BAR3_SIZE 0 | |
103 | +#define PCIE_BAR4_SIZE 0 | |
104 | +#define PCIE_BAR5_SIZE 0 | |
105 | +#define PCIE_ROM_SIZE 0 | |
103 | 106 | #define PCIE_BAR0_EN_DIS 1 |
104 | 107 | #define PCIE_BAR1_EN_DIS 0 |
105 | 108 | #define PCIE_BAR2_EN_DIS 1 |
106 | 109 | #define PCIE_BAR3_EN_DIS 1 |
107 | 110 | #define PCIE_BAR4_EN_DIS 1 |
108 | 111 | #define PCIE_BAR5_EN_DIS 1 |
112 | +#define PCIE_ROM_EN_DIS 0 | |
109 | 113 | #define PCIE_BAR0_INIT (PCI_REGION_MEM | PCI_WIDTH_32b | \ |
110 | 114 | PCI_REGION_NON_PREFETCH) |
111 | 115 | #define PCIE_BAR1_INIT (PCI_REGION_MEM | PCI_WIDTH_32b | \ |
112 | 116 | |
... | ... | @@ -116,10 +120,24 @@ |
116 | 120 | PCI_REGION_NON_PREFETCH) |
117 | 121 | #define PCIE_BAR4_INIT 0 |
118 | 122 | #define PCIE_BAR5_INIT 0 |
119 | -#endif | |
123 | +#define PCIE_ROM_INIT 0 | |
124 | + | |
125 | +/* To do proper EP support, we need to have interrupt driven handlers | |
126 | + * to keep our EP configuration in proper shape. | |
127 | + */ | |
128 | +#define PCIE_INTERRUPT_link_req_rst_not 135 | |
129 | + | |
130 | +/* Global variables */ | |
131 | +static int ignoreERR009852; | |
132 | + | |
120 | 133 | /* |
121 | 134 | * PHY access functions |
122 | 135 | */ |
136 | + /* FIX: The RM does not document any of this. How should it be | |
137 | + * possible to understand any of the PHY handling if it is a hard | |
138 | + * requirement. Do we have to reinstate PHY docs in the manual? | |
139 | + * If so, what parts? | |
140 | + */ | |
123 | 141 | static int pcie_phy_poll_ack(void __iomem *dbi_base, int exp_val) |
124 | 142 | { |
125 | 143 | u32 val; |
126 | 144 | |
... | ... | @@ -293,10 +311,147 @@ |
293 | 311 | return 0; |
294 | 312 | } |
295 | 313 | |
314 | +static void s32v234_pcie_set_bar(int baroffset, int enable, unsigned int size, | |
315 | + unsigned int init) | |
316 | +{ | |
317 | + char __iomem *dbi_base = (char __iomem *)S32V234_DBI_ADDR; | |
318 | + u32 mask = (enable) ? ((size - 1) & ~1) : 0; | |
319 | + | |
320 | + /* According to the RM, you have to enable the BAR before you | |
321 | + * can modify the mask value. While it appears that this may | |
322 | + * be ok in a single write anyway, we play it safe. | |
323 | + */ | |
324 | + writel(1, dbi_base + 0x1000 + baroffset); | |
325 | + | |
326 | + writel(enable | mask, dbi_base + 0x1000 + baroffset); | |
327 | + writel(init, dbi_base + baroffset); | |
328 | +} | |
329 | + | |
330 | +static void set_non_sticky_config_regs(void) | |
331 | +{ | |
332 | + const int socmask_info = readl(SIUL2_MIDR1) & 0x000000ff; | |
333 | + const struct src *src_regs = (struct src *)SRC_SOC_BASE_ADDR; | |
334 | + const int ep_mode = (readl(&src_regs->gpr5) & 0x0000001c) == 0; | |
335 | + | |
336 | + /* We need this function because the PCIe IP loses some | |
337 | + * configuration values when it loses the link. | |
338 | + * THIS FUNCTION MUST BE INTERRUPT SAFE, so we don't use | |
339 | + * external complex functions. | |
340 | + */ | |
341 | + if (!ep_mode) { | |
342 | + /* Set the CLASS_REV of RC CFG header to PCI_CLASS_BRIDGE_PCI */ | |
343 | + setbits_le32(S32V234_DBI_ADDR + PCI_CLASS_REVISION, | |
344 | + PCI_CLASS_BRIDGE_PCI << 16); | |
345 | + | |
346 | + /* CMD reg:I/O space, MEM space, and Bus Master Enable */ | |
347 | + setbits_le32(S32V234_DBI_ADDR | PCI_COMMAND, | |
348 | + PCI_COMMAND_IO | PCI_COMMAND_MEMORY | | |
349 | + PCI_COMMAND_MASTER); | |
350 | + | |
351 | + /* Region #0 is used for Outbound CFG space access. */ | |
352 | + writel(0, S32V234_DBI_ADDR + PCIE_ATU_VIEWPORT); | |
353 | + writel(S32V234_ROOT_ADDR, | |
354 | + S32V234_DBI_ADDR + PCIE_ATU_LOWER_BASE); | |
355 | + writel(0, S32V234_DBI_ADDR + PCIE_ATU_UPPER_BASE); | |
356 | + writel(S32V234_ROOT_ADDR + S32V234_ROOT_SIZE, | |
357 | + S32V234_DBI_ADDR + PCIE_ATU_LIMIT); | |
358 | + writel(0, S32V234_DBI_ADDR + PCIE_ATU_LOWER_TARGET); | |
359 | + writel(0, S32V234_DBI_ADDR + PCIE_ATU_UPPER_TARGET); | |
360 | + writel(PCIE_ATU_TYPE_CFG0, S32V234_DBI_ADDR + PCIE_ATU_CR1); | |
361 | + writel(PCIE_ATU_ENABLE, S32V234_DBI_ADDR + PCIE_ATU_CR2); | |
362 | + } else { | |
363 | + /* Set the CLASS_REV of RC CFG header to something that | |
364 | + * makes sense for this SoC by itself. For a product, | |
365 | + * the class setting should be board/product specific, | |
366 | + * so we'd technically need a CONFIG_PCIE_CLASS as part | |
367 | + * of the board configuration. | |
368 | + */ | |
369 | + setbits_le32(S32V234_DBI_ADDR + PCI_CLASS_REVISION, | |
370 | + (PCI_BASE_CLASS_PROCESSOR << 24) | | |
371 | + (0x80 /* other */ << 16)); | |
372 | + | |
373 | + /* Preconfigure the BAR registers, so that the RC can | |
374 | + * enumerate us properly and assign address spaces. | |
375 | + * Mask registers are W only! | |
376 | + */ | |
377 | + if (!ignoreERR009852 && socmask_info == 0x00) { | |
378 | + /* Erratum ERR009852 requires us to avoid | |
379 | + * any memory access from the RC! We solve this | |
380 | + * by disabling all BARs and ROM access | |
381 | + */ | |
382 | + s32v234_pcie_set_bar(PCI_BASE_ADDRESS_0, 0, 0, 0); | |
383 | + s32v234_pcie_set_bar(PCI_BASE_ADDRESS_1, 0, 0, 0); | |
384 | + s32v234_pcie_set_bar(PCI_BASE_ADDRESS_2, 0, 0, 0); | |
385 | + s32v234_pcie_set_bar(PCI_BASE_ADDRESS_3, 0, 0, 0); | |
386 | + s32v234_pcie_set_bar(PCI_BASE_ADDRESS_4, 0, 0, 0); | |
387 | + s32v234_pcie_set_bar(PCI_BASE_ADDRESS_5, 0, 0, 0); | |
388 | + s32v234_pcie_set_bar(PCI_ROM_ADDRESS, 0, 0, 0); | |
389 | + } else { | |
390 | + s32v234_pcie_set_bar(PCI_BASE_ADDRESS_0, | |
391 | + PCIE_BAR0_EN_DIS, PCIE_BAR0_SIZE, | |
392 | + PCIE_BAR0_INIT); | |
393 | + s32v234_pcie_set_bar(PCI_BASE_ADDRESS_1, | |
394 | + PCIE_BAR1_EN_DIS, PCIE_BAR1_SIZE, | |
395 | + PCIE_BAR1_INIT); | |
396 | + s32v234_pcie_set_bar(PCI_BASE_ADDRESS_2, | |
397 | + PCIE_BAR2_EN_DIS, PCIE_BAR2_SIZE, | |
398 | + PCIE_BAR2_INIT); | |
399 | + s32v234_pcie_set_bar(PCI_BASE_ADDRESS_3, | |
400 | + PCIE_BAR3_EN_DIS, PCIE_BAR3_SIZE, | |
401 | + PCIE_BAR3_INIT); | |
402 | + s32v234_pcie_set_bar(PCI_BASE_ADDRESS_4, | |
403 | + PCIE_BAR4_EN_DIS, PCIE_BAR4_SIZE, | |
404 | + PCIE_BAR4_INIT); | |
405 | + s32v234_pcie_set_bar(PCI_BASE_ADDRESS_5, | |
406 | + PCIE_BAR5_EN_DIS, PCIE_BAR5_SIZE, | |
407 | + PCIE_BAR5_INIT); | |
408 | + s32v234_pcie_set_bar(PCI_ROM_ADDRESS, | |
409 | + PCIE_ROM_EN_DIS, PCIE_ROM_SIZE, | |
410 | + PCIE_ROM_INIT); | |
411 | + | |
412 | + /* Region #0 is used for Inbound Mem | |
413 | + * space access on BAR2. | |
414 | + */ | |
415 | + writel(0x80000000, | |
416 | + S32V234_DBI_ADDR + PCIE_ATU_VIEWPORT); | |
417 | + writel(0xcff00000, | |
418 | + S32V234_DBI_ADDR + PCIE_ATU_LOWER_TARGET); | |
419 | + writel(0, S32V234_DBI_ADDR + PCIE_ATU_UPPER_TARGET); | |
420 | + writel(PCIE_ATU_TYPE_MEM, | |
421 | + S32V234_DBI_ADDR + PCIE_ATU_CR1); | |
422 | + writel(0xC0000200, S32V234_DBI_ADDR + PCIE_ATU_CR2); | |
423 | + | |
424 | + /* CMD reg:I/O space, MEM space, Bus Master Enable */ | |
425 | + setbits_le32(S32V234_DBI_ADDR | PCI_COMMAND, | |
426 | + PCI_COMMAND_IO | PCI_COMMAND_MEMORY | | |
427 | + PCI_COMMAND_MASTER); | |
428 | + } | |
429 | + } | |
430 | +} | |
431 | + | |
432 | +static void inthandler_pcie_link_req_rst_not(struct pt_regs *pt_regs, | |
433 | + unsigned int esr) | |
434 | +{ | |
435 | + const struct src *src_regs = (struct src *)SRC_SOC_BASE_ADDR; | |
436 | + | |
437 | + /* Clear link_req_rst_not interrupt signal */ | |
438 | + clrsetbits_le32(&src_regs->pcie_config0, 0x00000001, 0x00000001); | |
439 | + | |
440 | + /* Once we get this interrupt, the link came down and all the | |
441 | + * non sticky registers in our configuration space got reset. | |
442 | + * We reestablish the register values now and finally | |
443 | + * permit configuration transactions | |
444 | + */ | |
445 | + set_non_sticky_config_regs(); | |
446 | + | |
447 | + /* Accept inbound configuration requests now */ | |
448 | + clrsetbits_le32(&src_regs->gpr11, 0x00400000, 0x00400000); | |
449 | +} | |
450 | + | |
296 | 451 | /* |
297 | 452 | * iATU region setup |
298 | 453 | */ |
299 | -static int s32v234_pcie_regions_setup(void) | |
454 | +static int s32v234_pcie_regions_setup(const int ep_mode) | |
300 | 455 | { |
301 | 456 | /* |
302 | 457 | * S32V234 defines 16MB in the AXI address map for PCIe. |
303 | 458 | |
304 | 459 | |
305 | 460 | |
306 | 461 | |
307 | 462 | |
308 | 463 | |
309 | 464 | |
310 | 465 | |
311 | 466 | |
... | ... | @@ -310,107 +465,74 @@ |
310 | 465 | * 0x01F0_0000 --- 0x01FF_FFFF 1MB Cfg + Registers |
311 | 466 | */ |
312 | 467 | |
313 | - /* CMD reg:I/O space, MEM space, and Bus Master Enable */ | |
314 | - setbits_le32(S32V234_DBI_ADDR | PCI_COMMAND, | |
315 | - PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); | |
316 | -#ifndef CONFIG_PCIE_EP_MODE | |
317 | - /* Set the CLASS_REV of RC CFG header to PCI_CLASS_BRIDGE_PCI */ | |
318 | - setbits_le32(S32V234_DBI_ADDR + PCI_CLASS_REVISION, | |
319 | - PCI_CLASS_BRIDGE_PCI << 16); | |
320 | -#else | |
321 | - /* Set the CLASS_REV of RC CFG header to PCI_CLASS_MEMORY_RAM */ | |
322 | - setbits_le32(S32V234_DBI_ADDR + PCI_CLASS_REVISION, | |
323 | - PCI_CLASS_MEMORY_RAM << 16); | |
324 | - /* 1MB 32bit none-prefetchable memory on BAR0 */ | |
325 | - writel(PCIE_BAR0_INIT, S32V234_DBI_ADDR + PCI_BASE_ADDRESS_0); | |
326 | -#if PCIE_BAR0_EN_DIS | |
327 | - writel((PCIE_BAR0_EN_DIS | (PCIE_BAR0_SIZE - 1)), | |
328 | - S32V234_DBI_ADDR + (1 << 12) + PCI_BASE_ADDRESS_0); | |
329 | -#else | |
330 | - writel((PCIE_BAR0_EN_DIS & (PCIE_BAR0_SIZE - 1)), | |
331 | - S32V234_DBI_ADDR + (1 << 12) + PCI_BASE_ADDRESS_0); | |
332 | -#endif | |
468 | + /* We set up the ID for all Rev 1.x chips */ | |
469 | + if (get_siul2_midr1_major() == 0x00) { | |
470 | + /* | |
471 | + * Vendor ID is Freescale (now NXP): 0x1957 | |
472 | + * Device ID is split as follows | |
473 | + * Family 15:12, Device 11:6, Personality 5:0 | |
474 | + * S32V is in the automotive family: 0100 | |
475 | + * S32V is the first auto device with PCIe: 000000 | |
476 | + * S32V does not have export controlled cryptography: 00001 | |
477 | + */ | |
478 | + printf("Setting PCIE Vendor and Device ID\n"); | |
479 | + writel((0x4001 << 16) | 0x1957, | |
480 | + S32V234_DBI_ADDR + PCI_VENDOR_ID); | |
481 | + } | |
333 | 482 | |
334 | - /* None used BAR1 */ | |
335 | - writel(PCIE_BAR1_INIT, S32V234_DBI_ADDR + PCI_BASE_ADDRESS_1); | |
336 | -#if PCIE_BAR1_EN_DIS | |
337 | - writel((PCIE_BAR1_EN_DIS | (PCIE_BAR1_SIZE - 1)), | |
338 | - S32V234_DBI_ADDR + (1 << 12) + PCI_BASE_ADDRESS_1); | |
339 | -#else | |
340 | - writel((PCIE_BAR1_EN_DIS & (PCIE_BAR1_SIZE - 1)), | |
341 | - S32V234_DBI_ADDR + (1 << 12) + PCI_BASE_ADDRESS_1); | |
483 | +#if defined(CONFIG_PCIE_SUBSYSTEM_VENDOR_ID) && \ | |
484 | + defined(CONFIG_PCIE_SUBSYSTEM_ID) | |
485 | + writel((CONFIG_PCIE_SUBSYSTEM_ID << 16) | | |
486 | + CONFIG_PCIE_SUBSYSTEM_VENDOR_ID, | |
487 | + S32V234_DBI_ADDR + PCI_SUBSYSTEM_VENDOR_ID); | |
342 | 488 | #endif |
343 | 489 | |
344 | - /* 64KB 32bit none-prefetchable memory on BAR2 */ | |
345 | - writel(PCIE_BAR2_INIT, S32V234_DBI_ADDR + PCI_BASE_ADDRESS_2); | |
346 | -#if PCIE_BAR2_EN_DIS | |
347 | - writel((PCIE_BAR2_EN_DIS | (PCIE_BAR2_SIZE - 1)), | |
348 | - S32V234_DBI_ADDR + (1 << 12) + PCI_BASE_ADDRESS_2); | |
349 | -#else | |
350 | - writel((PCIE_BAR2_EN_DIS & (PCIE_BAR2_SIZE - 1)), | |
351 | - S32V234_DBI_ADDR + (1 << 12) + PCI_BASE_ADDRESS_2); | |
352 | -#endif | |
490 | + ignoreERR009852 = env_get("ignoreERR009852") ? true : false; | |
353 | 491 | |
354 | - /* Default size BAR3 */ | |
355 | - writel(PCIE_BAR3_INIT, S32V234_DBI_ADDR + PCI_BASE_ADDRESS_3); | |
356 | -#if PCIE_BAR3_EN_DIS | |
357 | - writel((PCIE_BAR3_EN_DIS | (PCIE_BAR3_SIZE - 1)), | |
358 | - S32V234_DBI_ADDR + (1 << 12) + PCI_BASE_ADDRESS_3); | |
359 | -#else | |
360 | - writel((PCIE_BAR3_EN_DIS & (PCIE_BAR3_SIZE - 1)), | |
361 | - S32V234_DBI_ADDR + (1 << 12) + PCI_BASE_ADDRESS_3); | |
362 | -#endif | |
492 | + set_non_sticky_config_regs(); | |
363 | 493 | |
364 | - /* Default size BAR4 */ | |
365 | - writel(PCIE_BAR4_INIT, S32V234_DBI_ADDR + PCI_BASE_ADDRESS_4); | |
366 | -#if PCIE_BAR4_EN_DIS | |
367 | - writel((PCIE_BAR4_EN_DIS | (PCIE_BAR4_SIZE - 1)), | |
368 | - S32V234_DBI_ADDR + (1 << 12) + PCI_BASE_ADDRESS_4); | |
369 | -#else | |
370 | - writel((PCIE_BAR4_EN_DIS & (PCIE_BAR4_SIZE - 1)), | |
371 | - S32V234_DBI_ADDR + (1 << 12) + PCI_BASE_ADDRESS_4); | |
372 | -#endif | |
494 | + if (ep_mode) { | |
495 | + struct src *src_regs = (struct src *)SRC_SOC_BASE_ADDR; | |
373 | 496 | |
374 | - /* Default size BAR5 */ | |
375 | - writel(PCIE_BAR5_INIT, S32V234_DBI_ADDR + PCI_BASE_ADDRESS_5); | |
376 | -#if PCIE_BAR5_EN_DIS | |
377 | - writel((PCIE_BAR5_EN_DIS | (PCIE_BAR5_SIZE - 1)), | |
378 | - S32V234_DBI_ADDR + (1 << 12) + PCI_BASE_ADDRESS_5); | |
379 | -#else | |
380 | - writel((PCIE_BAR5_EN_DIS & (PCIE_BAR5_SIZE - 1)), | |
381 | - S32V234_DBI_ADDR + (1 << 12) + PCI_BASE_ADDRESS_5); | |
382 | -#endif | |
383 | -#endif /* CONFIG_PCIE_EP_MODE */ | |
497 | + if (ignoreERR009852) | |
498 | + printf("\n Ignoring errata ERR009852\n"); | |
384 | 499 | |
385 | -#ifndef CONFIG_PCIE_EP_MODE | |
386 | - /* Region #0 is used for Outbound CFG space access. */ | |
387 | - writel(0, S32V234_DBI_ADDR + PCIE_ATU_VIEWPORT); | |
388 | - writel(S32V234_ROOT_ADDR, S32V234_DBI_ADDR + PCIE_ATU_LOWER_BASE); | |
389 | - writel(0, S32V234_DBI_ADDR + PCIE_ATU_UPPER_BASE); | |
390 | - writel(S32V234_ROOT_ADDR + S32V234_ROOT_SIZE, | |
391 | - S32V234_DBI_ADDR + PCIE_ATU_LIMIT); | |
392 | - writel(0, S32V234_DBI_ADDR + PCIE_ATU_LOWER_TARGET); | |
393 | - writel(0, S32V234_DBI_ADDR + PCIE_ATU_UPPER_TARGET); | |
394 | - writel(PCIE_ATU_TYPE_CFG0, S32V234_DBI_ADDR + PCIE_ATU_CR1); | |
395 | - writel(PCIE_ATU_ENABLE, S32V234_DBI_ADDR + PCIE_ATU_CR2); | |
396 | -#else | |
397 | - /* Region #0 is used for Inbound Mem space access on BAR2. */ | |
398 | - writel(0x80000000, S32V234_DBI_ADDR + PCIE_ATU_VIEWPORT); | |
399 | - writel(0xcff00000, S32V234_DBI_ADDR + PCIE_ATU_LOWER_TARGET); | |
400 | - writel(0, S32V234_DBI_ADDR + PCIE_ATU_UPPER_TARGET); | |
401 | - writel(PCIE_ATU_TYPE_MEM, S32V234_DBI_ADDR + PCIE_ATU_CR1); | |
402 | - writel(0xC0000200, S32V234_DBI_ADDR + PCIE_ATU_CR2); | |
403 | -#endif | |
500 | + /* Ensure that if the link comes down we do not react | |
501 | + * to config accesses anymore until we have reconfigured | |
502 | + * ourselves properly! A link down event unfortunately | |
503 | + * clears non-sticky registers. | |
504 | + * Note that we permit automatic link training. This | |
505 | + * puts the responsibility on us to reconfigure and | |
506 | + * set PCIE_CFG_READY again if the link comes down. | |
507 | + */ | |
508 | + clrsetbits_le32(&src_regs->gpr10, 0x40000000, 0x40000000); | |
509 | + | |
510 | + /* Assume the link is up and reset the link down event, | |
511 | + * so that we can properly try to set PCIE_CFG_READY. | |
512 | + */ | |
513 | + clrsetbits_le32(&src_regs->pcie_config0, 0x00000001, | |
514 | + 0x00000001); | |
515 | + | |
516 | + /* Ensure that we can fix up our configuration again | |
517 | + * if the link came down! | |
518 | + */ | |
519 | + gic_register_handler(PCIE_INTERRUPT_link_req_rst_not, | |
520 | + inthandler_pcie_link_req_rst_not, | |
521 | + 0, "PCIE_INTERRUPT_link_req_rst_not"); | |
522 | + | |
523 | + /* Accept inbound configuration requests now */ | |
524 | + clrsetbits_le32(&src_regs->gpr11, 0x00400000, 0x00400000); | |
525 | + } | |
526 | + | |
404 | 527 | return 0; |
405 | 528 | } |
406 | 529 | |
407 | -#ifndef CONFIG_PCIE_EP_MODE | |
408 | 530 | /* |
409 | 531 | * PCI Express accessors |
410 | 532 | */ |
411 | -static u32 get_bus_address(pci_dev_t d, int where) | |
533 | +static u8 *get_bus_address(pci_dev_t d, int where) | |
412 | 534 | { |
413 | - u32 va_address; | |
535 | + u8 *va_address; | |
414 | 536 | |
415 | 537 | /* Reconfigure Region #0 */ |
416 | 538 | writel(0, S32V234_DBI_ADDR + PCIE_ATU_VIEWPORT); |
417 | 539 | |
... | ... | @@ -421,10 +543,10 @@ |
421 | 543 | writel(PCIE_ATU_TYPE_CFG1, S32V234_DBI_ADDR + PCIE_ATU_CR1); |
422 | 544 | |
423 | 545 | if (PCI_BUS(d) == 0) { |
424 | - va_address = S32V234_DBI_ADDR; | |
546 | + va_address = (u8 *)S32V234_DBI_ADDR; | |
425 | 547 | } else { |
426 | 548 | writel(d << 8, S32V234_DBI_ADDR + PCIE_ATU_LOWER_TARGET); |
427 | - va_address = S32V234_IO_ADDR + SZ_16M - SZ_1M; | |
549 | + va_address = (u8 *)(S32V234_IO_ADDR + SZ_16M - SZ_1M); | |
428 | 550 | } |
429 | 551 | |
430 | 552 | va_address += (where & ~0x3); |
... | ... | @@ -444,7 +566,7 @@ |
444 | 566 | static int s32v234_pcie_read_config(struct pci_controller *hose, pci_dev_t d, |
445 | 567 | int where, u32 *val) |
446 | 568 | { |
447 | - u32 va_address; | |
569 | + u8 *va_address; | |
448 | 570 | int ret; |
449 | 571 | |
450 | 572 | ret = s32v234_pcie_addr_valid(d); |
... | ... | @@ -463,7 +585,7 @@ |
463 | 585 | static int s32v234_pcie_write_config(struct pci_controller *hose, pci_dev_t d, |
464 | 586 | int where, u32 val) |
465 | 587 | { |
466 | - u32 va_address = 0; | |
588 | + void *va_address = 0; | |
467 | 589 | int ret; |
468 | 590 | |
469 | 591 | ret = s32v234_pcie_addr_valid(d); |
470 | 592 | |
471 | 593 | |
472 | 594 | |
473 | 595 | |
474 | 596 | |
... | ... | @@ -475,31 +597,21 @@ |
475 | 597 | |
476 | 598 | return 0; |
477 | 599 | } |
478 | -#endif /* CONFIG_PCIE_EP_MODE */ | |
479 | 600 | |
480 | -static int s32v234_pcie_init_phy(void) | |
601 | +static int s32v234_pcie_init_phy(const int ep_mode) | |
481 | 602 | { |
482 | 603 | struct src *src_regs = (struct src *)SRC_SOC_BASE_ADDR; |
483 | 604 | |
484 | 605 | clrbits_le32(&src_regs->gpr5, SRC_GPR5_PCIE_APP_LTSSM_ENABLE); |
485 | 606 | |
486 | -#ifndef CONFIG_PCIE_EP_MODE | |
487 | 607 | clrsetbits_le32(&src_regs->gpr5, |
488 | - SRC_GPR5_PCIE_DEVICE_TYPE_MASK, | |
489 | - SRC_GPR5_PCIE_DEVICE_TYPE_RC); | |
490 | -#else | |
608 | + SRC_GPR5_PCIE_PHY_LOS_LEVEL_MASK, | |
609 | + SRC_GPR5_PCIE_PHY_LOS_LEVEL_9); | |
491 | 610 | clrsetbits_le32(&src_regs->gpr5, |
492 | - SRC_GPR5_PCIE_DEVICE_TYPE_MASK, | |
493 | - SRC_GPR5_PCIE_DEVICE_TYPE_EP); | |
494 | -#endif | |
495 | - clrsetbits_le32(&src_regs->gpr5, | |
496 | - SRC_GPR5_PCIE_PHY_LOS_LEVEL_MASK, | |
497 | - SRC_GPR5_PCIE_PHY_LOS_LEVEL_9); | |
498 | - clrsetbits_le32(&src_regs->gpr5, | |
499 | - SRC_GPR5_PCIE_PHY_RX0_EQ_MASK, | |
500 | - SRC_GPR5_PCIE_PHY_RX0_EQ_2); | |
611 | + SRC_GPR5_PCIE_PHY_RX0_EQ_MASK, | |
612 | + SRC_GPR5_PCIE_PHY_RX0_EQ_2); | |
501 | 613 | |
502 | - writel((0x0 << SRC_GPR6_PCIE_PCS_TX_DEEMPH_GEN1_OFFSET) | | |
614 | + writel((0x0 << SRC_GPR6_PCIE_PCS_TX_DEEMPH_GEN1_OFFSET) | | |
503 | 615 | (0x0 << SRC_GPR6_PCIE_PCS_TX_DEEMPH_GEN2_3P5DB_OFFSET) | |
504 | 616 | (20 << SRC_GPR6_PCIE_PCS_TX_DEEMPH_GEN2_6DB_OFFSET) | |
505 | 617 | (127 << SRC_GPR6_PCIE_PCS_TX_SWING_FULL_OFFSET) | |
506 | 618 | |
507 | 619 | |
508 | 620 | |
509 | 621 | |
... | ... | @@ -520,28 +632,24 @@ |
520 | 632 | return 0; |
521 | 633 | } |
522 | 634 | |
523 | -static int s32v_pcie_link_up(void) | |
635 | +static int s32v_pcie_link_up(const int ep_mode) | |
524 | 636 | { |
525 | 637 | struct src *src_regs = (struct src *)SRC_SOC_BASE_ADDR; |
526 | 638 | |
527 | 639 | u32 tmp; |
528 | 640 | int count = 0; |
529 | 641 | |
530 | - s32v234_pcie_init_phy(); | |
642 | + s32v234_pcie_init_phy(ep_mode); | |
531 | 643 | s32v234_pcie_deassert_core_reset(); |
532 | - s32v234_pcie_regions_setup(); | |
644 | + s32v234_pcie_regions_setup(ep_mode); | |
533 | 645 | |
534 | -#ifdef CONFIG_PCIE_EP_MODE | |
535 | - writel(readl(&src_regs->gpr11) | 0x00400000, &src_regs->gpr11); | |
536 | -#endif | |
537 | - | |
538 | 646 | /* |
539 | 647 | * FIXME: Force the PCIe RC to Gen1 operation |
540 | 648 | * The RC must be forced into Gen1 mode before bringing the link |
541 | 649 | * up, otherwise no downstream devices are detected. After the |
542 | 650 | * link is up, a managed Gen1->Gen2 transition can be initiated. |
543 | 651 | */ |
544 | - printf("\n Forcing PCIe RC to Gen1 operation"); | |
652 | + printf("\nForcing PCIe to Gen1 operation\n"); | |
545 | 653 | |
546 | 654 | tmp = readl(S32V234_DBI_ADDR + 0x7c); |
547 | 655 | tmp &= ~0xf; |
548 | 656 | |
549 | 657 | |
550 | 658 | |
551 | 659 | |
552 | 660 | |
553 | 661 | |
554 | 662 | |
555 | 663 | |
556 | 664 | |
557 | 665 | |
558 | 666 | |
559 | 667 | |
560 | 668 | |
... | ... | @@ -566,57 +674,67 @@ |
566 | 674 | return 0; |
567 | 675 | } |
568 | 676 | |
569 | -void s32v234_pcie_init(void) | |
677 | +void s32v234_pcie_init(const int ep_mode) | |
570 | 678 | { |
571 | -#ifndef CONFIG_PCIE_EP_MODE | |
572 | 679 | /* Static instance of the controller. */ |
573 | 680 | static struct pci_controller pcc; |
574 | 681 | struct pci_controller *hose = &pcc; |
575 | -#endif | |
576 | 682 | int ret; |
683 | + struct src *src_regs = (struct src *)SRC_SOC_BASE_ADDR; | |
577 | 684 | |
578 | -#ifndef CONFIG_PCIE_EP_MODE | |
579 | - memset(&pcc, 0, sizeof(pcc)); | |
685 | + /* Set device type */ | |
686 | + clrsetbits_le32(&src_regs->gpr5, | |
687 | + SRC_GPR5_PCIE_DEVICE_TYPE_MASK, | |
688 | + (ep_mode) ? SRC_GPR5_PCIE_DEVICE_TYPE_EP : | |
689 | + SRC_GPR5_PCIE_DEVICE_TYPE_RC); | |
580 | 690 | |
581 | - /* PCI I/O space */ | |
582 | - pci_set_region(&hose->regions[0], | |
583 | - S32V234_IO_ADDR, S32V234_IO_ADDR, | |
584 | - S32V234_IO_SIZE, PCI_REGION_IO); | |
691 | + if (!ep_mode) { | |
692 | + memset(&pcc, 0, sizeof(pcc)); | |
585 | 693 | |
586 | - /* PCI memory space */ | |
587 | - pci_set_region(&hose->regions[1], | |
588 | - S32V234_MEM_ADDR, S32V234_MEM_ADDR, | |
589 | - S32V234_MEM_SIZE, PCI_REGION_MEM); | |
694 | + /* PCI I/O space */ | |
695 | + pci_set_region(&hose->regions[0], | |
696 | + S32V234_IO_ADDR, S32V234_IO_ADDR, | |
697 | + S32V234_IO_SIZE, PCI_REGION_IO); | |
590 | 698 | |
591 | - /* System memory space */ | |
592 | - /* For now, allocating only 1024MB from address 0x80000000 */ | |
699 | + /* PCI memory space */ | |
700 | + pci_set_region(&hose->regions[1], | |
701 | + S32V234_MEM_ADDR, S32V234_MEM_ADDR, | |
702 | + S32V234_MEM_SIZE, PCI_REGION_MEM); | |
593 | 703 | |
594 | - pci_set_region(&hose->regions[2], | |
595 | - MMDC0_ARB_BASE_ADDR, MMDC0_ARB_BASE_ADDR, | |
596 | - 0x3FFFFFFF, PCI_REGION_MEM | PCI_REGION_SYS_MEMORY); | |
704 | + /* System memory space */ | |
705 | + pci_set_region(&hose->regions[2], | |
706 | + MMDC0_ARB_BASE_ADDR, MMDC0_ARB_BASE_ADDR, | |
707 | + 0x3FFFFFFF, | |
708 | + PCI_REGION_MEM | PCI_REGION_SYS_MEMORY); | |
597 | 709 | |
598 | - hose->region_count = 3; | |
710 | + hose->region_count = 3; | |
599 | 711 | |
600 | - pci_set_ops(hose, | |
601 | - pci_hose_read_config_byte_via_dword, | |
602 | - pci_hose_read_config_word_via_dword, | |
603 | - s32v234_pcie_read_config, | |
604 | - pci_hose_write_config_byte_via_dword, | |
605 | - pci_hose_write_config_word_via_dword, | |
606 | - s32v234_pcie_write_config); | |
607 | -#endif | |
712 | + pci_set_ops(hose, | |
713 | + pci_hose_read_config_byte_via_dword, | |
714 | + pci_hose_read_config_word_via_dword, | |
715 | + s32v234_pcie_read_config, | |
716 | + pci_hose_write_config_byte_via_dword, | |
717 | + pci_hose_write_config_word_via_dword, | |
718 | + s32v234_pcie_write_config); | |
719 | + } | |
720 | + | |
608 | 721 | /* Start the controller. */ |
609 | - ret = s32v_pcie_link_up(); | |
610 | -#ifndef CONFIG_PCIE_EP_MODE | |
611 | - if (!ret) { | |
612 | - pci_register_hose(hose); | |
613 | - hose->last_busno = pci_hose_scan(hose); | |
722 | + ret = s32v_pcie_link_up(ep_mode); | |
723 | + | |
724 | + if (!ep_mode) { | |
725 | + if (!ret) { | |
726 | + pci_register_hose(hose); | |
727 | + hose->last_busno = pci_hose_scan(hose); | |
728 | + } | |
614 | 729 | } |
615 | -#endif | |
616 | 730 | } |
617 | 731 | |
618 | 732 | void pci_init_board(void) |
619 | 733 | { |
620 | - s32v234_pcie_init(); | |
734 | +#ifdef CONFIG_PCIE_EP_MODE | |
735 | + s32v234_pcie_init(1); | |
736 | +#else | |
737 | + s32v234_pcie_init(0); | |
738 | +#endif | |
621 | 739 | } |
include/configs/s32v234pcie.h