blob: 8d89a1e5919ca139314361642fae10b01f8c39bf [file] [log] [blame]
Hou Zhiqiangb89e3d92019-04-24 22:33:02 +08001// SPDX-License-Identifier: GPL-2.0+ OR X11
2/*
3 * Copyright 2019 NXP
4 *
5 * PCIe DM U-Boot driver for Freescale PowerPC SoCs
6 * Author: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
7 */
8
9#include <common.h>
10#include <dm.h>
11#include <malloc.h>
12#include <mapmem.h>
13#include <pci.h>
14#include <asm/fsl_pci.h>
15#include <asm/fsl_serdes.h>
Simon Glass401d1c42020-10-30 21:38:53 -060016#include <asm/global_data.h>
Hou Zhiqiangb89e3d92019-04-24 22:33:02 +080017#include <asm/io.h>
Simon Glassc05ed002020-05-10 11:40:11 -060018#include <linux/delay.h>
Hou Zhiqiangb89e3d92019-04-24 22:33:02 +080019#include "pcie_fsl.h"
Simon Glass336d4612020-02-03 07:36:16 -070020#include <dm/device_compat.h>
Hou Zhiqiangb89e3d92019-04-24 22:33:02 +080021
22LIST_HEAD(fsl_pcie_list);
23
24static int fsl_pcie_link_up(struct fsl_pcie *pcie);
25
26static int fsl_pcie_addr_valid(struct fsl_pcie *pcie, pci_dev_t bdf)
27{
28 struct udevice *bus = pcie->bus;
29
30 if (!pcie->enabled)
31 return -ENXIO;
32
Simon Glass8b85dfc2020-12-16 21:20:07 -070033 if (PCI_BUS(bdf) < dev_seq(bus))
Hou Zhiqiangb89e3d92019-04-24 22:33:02 +080034 return -EINVAL;
35
Simon Glass8b85dfc2020-12-16 21:20:07 -070036 if (PCI_BUS(bdf) > dev_seq(bus) && (!fsl_pcie_link_up(pcie) || pcie->mode))
Hou Zhiqiangb89e3d92019-04-24 22:33:02 +080037 return -EINVAL;
38
Simon Glass8b85dfc2020-12-16 21:20:07 -070039 if (PCI_BUS(bdf) == dev_seq(bus) && (PCI_DEV(bdf) > 0 || PCI_FUNC(bdf) > 0))
Hou Zhiqiangb89e3d92019-04-24 22:33:02 +080040 return -EINVAL;
41
Simon Glass8b85dfc2020-12-16 21:20:07 -070042 if (PCI_BUS(bdf) == (dev_seq(bus) + 1) && (PCI_DEV(bdf) > 0))
Hou Zhiqiangb89e3d92019-04-24 22:33:02 +080043 return -EINVAL;
44
45 return 0;
46}
47
Simon Glassc4e72c42020-01-27 08:49:37 -070048static int fsl_pcie_read_config(const struct udevice *bus, pci_dev_t bdf,
Hou Zhiqiangb89e3d92019-04-24 22:33:02 +080049 uint offset, ulong *valuep,
50 enum pci_size_t size)
51{
52 struct fsl_pcie *pcie = dev_get_priv(bus);
53 ccsr_fsl_pci_t *regs = pcie->regs;
54 u32 val;
55
56 if (fsl_pcie_addr_valid(pcie, bdf)) {
57 *valuep = pci_get_ff(size);
58 return 0;
59 }
60
Pali Rohár0d734df2023-05-02 19:53:57 +020061 /* Skip Freescale PCIe controller's PEXCSRBAR register */
62 if (PCI_BUS(bdf) - dev_seq(bus) == 0 &&
63 PCI_DEV(bdf) == 0 && PCI_FUNC(bdf) == 0 &&
64 (offset & ~3) == PCI_BASE_ADDRESS_0) {
65 *valuep = 0;
66 return 0;
67 }
68
Pali Rohárf031f072021-11-26 11:42:47 +010069 val = PCI_CONF1_EXT_ADDRESS(PCI_BUS(bdf) - dev_seq(bus),
70 PCI_DEV(bdf), PCI_FUNC(bdf),
71 offset);
Hou Zhiqiangb89e3d92019-04-24 22:33:02 +080072 out_be32(&regs->cfg_addr, val);
73
74 sync();
75
76 switch (size) {
77 case PCI_SIZE_8:
78 *valuep = in_8((u8 *)&regs->cfg_data + (offset & 3));
79 break;
80 case PCI_SIZE_16:
81 *valuep = in_le16((u16 *)((u8 *)&regs->cfg_data +
82 (offset & 2)));
83 break;
84 case PCI_SIZE_32:
85 *valuep = in_le32(&regs->cfg_data);
86 break;
87 }
88
89 return 0;
90}
91
92static int fsl_pcie_write_config(struct udevice *bus, pci_dev_t bdf,
93 uint offset, ulong value,
94 enum pci_size_t size)
95{
96 struct fsl_pcie *pcie = dev_get_priv(bus);
97 ccsr_fsl_pci_t *regs = pcie->regs;
98 u32 val;
99 u8 val_8;
100 u16 val_16;
101 u32 val_32;
102
103 if (fsl_pcie_addr_valid(pcie, bdf))
104 return 0;
105
Pali Rohár0d734df2023-05-02 19:53:57 +0200106 /* Skip Freescale PCIe controller's PEXCSRBAR register */
107 if (PCI_BUS(bdf) - dev_seq(bus) == 0 &&
108 PCI_DEV(bdf) == 0 && PCI_FUNC(bdf) == 0 &&
109 (offset & ~3) == PCI_BASE_ADDRESS_0)
110 return 0;
111
Pali Rohárf031f072021-11-26 11:42:47 +0100112 val = PCI_CONF1_EXT_ADDRESS(PCI_BUS(bdf) - dev_seq(bus),
113 PCI_DEV(bdf), PCI_FUNC(bdf),
114 offset);
Hou Zhiqiangb89e3d92019-04-24 22:33:02 +0800115 out_be32(&regs->cfg_addr, val);
116
117 sync();
118
119 switch (size) {
120 case PCI_SIZE_8:
121 val_8 = value;
122 out_8((u8 *)&regs->cfg_data + (offset & 3), val_8);
123 break;
124 case PCI_SIZE_16:
125 val_16 = value;
126 out_le16((u16 *)((u8 *)&regs->cfg_data + (offset & 2)), val_16);
127 break;
128 case PCI_SIZE_32:
129 val_32 = value;
130 out_le32(&regs->cfg_data, val_32);
131 break;
132 }
133
134 return 0;
135}
136
137static int fsl_pcie_hose_read_config(struct fsl_pcie *pcie, uint offset,
138 ulong *valuep, enum pci_size_t size)
139{
140 int ret;
141 struct udevice *bus = pcie->bus;
142
Simon Glass8b85dfc2020-12-16 21:20:07 -0700143 ret = fsl_pcie_read_config(bus, PCI_BDF(dev_seq(bus), 0, 0),
Hou Zhiqiangb89e3d92019-04-24 22:33:02 +0800144 offset, valuep, size);
145
146 return ret;
147}
148
149static int fsl_pcie_hose_write_config(struct fsl_pcie *pcie, uint offset,
150 ulong value, enum pci_size_t size)
151{
152 struct udevice *bus = pcie->bus;
153
Simon Glass8b85dfc2020-12-16 21:20:07 -0700154 return fsl_pcie_write_config(bus, PCI_BDF(dev_seq(bus), 0, 0),
Hou Zhiqiangb89e3d92019-04-24 22:33:02 +0800155 offset, value, size);
156}
157
158static int fsl_pcie_hose_read_config_byte(struct fsl_pcie *pcie, uint offset,
159 u8 *valuep)
160{
161 ulong val;
162 int ret;
163
164 ret = fsl_pcie_hose_read_config(pcie, offset, &val, PCI_SIZE_8);
165 *valuep = val;
166
167 return ret;
168}
169
170static int fsl_pcie_hose_read_config_word(struct fsl_pcie *pcie, uint offset,
171 u16 *valuep)
172{
173 ulong val;
174 int ret;
175
176 ret = fsl_pcie_hose_read_config(pcie, offset, &val, PCI_SIZE_16);
177 *valuep = val;
178
179 return ret;
180}
181
182static int fsl_pcie_hose_read_config_dword(struct fsl_pcie *pcie, uint offset,
183 u32 *valuep)
184{
185 ulong val;
186 int ret;
187
188 ret = fsl_pcie_hose_read_config(pcie, offset, &val, PCI_SIZE_32);
189 *valuep = val;
190
191 return ret;
192}
193
194static int fsl_pcie_hose_write_config_byte(struct fsl_pcie *pcie, uint offset,
195 u8 value)
196{
197 return fsl_pcie_hose_write_config(pcie, offset, value, PCI_SIZE_8);
198}
199
200static int fsl_pcie_hose_write_config_word(struct fsl_pcie *pcie, uint offset,
201 u16 value)
202{
203 return fsl_pcie_hose_write_config(pcie, offset, value, PCI_SIZE_16);
204}
205
206static int fsl_pcie_hose_write_config_dword(struct fsl_pcie *pcie, uint offset,
207 u32 value)
208{
209 return fsl_pcie_hose_write_config(pcie, offset, value, PCI_SIZE_32);
210}
211
212static int fsl_pcie_link_up(struct fsl_pcie *pcie)
213{
214 ccsr_fsl_pci_t *regs = pcie->regs;
215 u16 ltssm;
216
217 if (pcie->block_rev >= PEX_IP_BLK_REV_3_0) {
218 ltssm = (in_be32(&regs->pex_csr0)
219 & PEX_CSR0_LTSSM_MASK) >> PEX_CSR0_LTSSM_SHIFT;
220 return ltssm == LTSSM_L0_REV3;
221 }
222
223 fsl_pcie_hose_read_config_word(pcie, PCI_LTSSM, &ltssm);
224
225 return ltssm == LTSSM_L0;
226}
227
228static bool fsl_pcie_is_agent(struct fsl_pcie *pcie)
229{
230 u8 header_type;
231
232 fsl_pcie_hose_read_config_byte(pcie, PCI_HEADER_TYPE, &header_type);
233
234 return (header_type & 0x7f) == PCI_HEADER_TYPE_NORMAL;
235}
236
237static int fsl_pcie_setup_law(struct fsl_pcie *pcie)
238{
239 struct pci_region *io, *mem, *pref;
240
241 pci_get_regions(pcie->bus, &io, &mem, &pref);
242
243 if (mem)
244 set_next_law(mem->phys_start,
245 law_size_bits(mem->size),
246 pcie->law_trgt_if);
247
248 if (io)
249 set_next_law(io->phys_start,
250 law_size_bits(io->size),
251 pcie->law_trgt_if);
252
253 return 0;
254}
255
256static void fsl_pcie_config_ready(struct fsl_pcie *pcie)
257{
258 ccsr_fsl_pci_t *regs = pcie->regs;
259
260 if (pcie->block_rev >= PEX_IP_BLK_REV_3_0) {
261 setbits_be32(&regs->config, FSL_PCIE_V3_CFG_RDY);
262 return;
263 }
264
265 fsl_pcie_hose_write_config_byte(pcie, FSL_PCIE_CFG_RDY, 0x1);
266}
267
268static int fsl_pcie_setup_outbound_win(struct fsl_pcie *pcie, int idx,
269 int type, u64 phys, u64 bus_addr,
270 pci_size_t size)
271{
272 ccsr_fsl_pci_t *regs = pcie->regs;
273 pot_t *po = &regs->pot[idx];
274 u32 war, sz;
275
276 if (idx < 0)
277 return -EINVAL;
278
279 out_be32(&po->powbar, phys >> 12);
280 out_be32(&po->potar, bus_addr >> 12);
281#ifdef CONFIG_SYS_PCI_64BIT
282 out_be32(&po->potear, bus_addr >> 44);
283#else
284 out_be32(&po->potear, 0);
285#endif
286
287 sz = (__ilog2_u64((u64)size) - 1);
288 war = POWAR_EN | sz;
289
290 if (type == PCI_REGION_IO)
291 war |= POWAR_IO_READ | POWAR_IO_WRITE;
292 else
293 war |= POWAR_MEM_READ | POWAR_MEM_WRITE;
294
295 out_be32(&po->powar, war);
296
297 return 0;
298}
299
300static int fsl_pcie_setup_inbound_win(struct fsl_pcie *pcie, int idx,
301 bool pf, u64 phys, u64 bus_addr,
302 pci_size_t size)
303{
304 ccsr_fsl_pci_t *regs = pcie->regs;
305 pit_t *pi = &regs->pit[idx];
306 u32 sz = (__ilog2_u64(size) - 1);
307 u32 flag = PIWAR_LOCAL;
308
309 if (idx < 0)
310 return -EINVAL;
311
312 out_be32(&pi->pitar, phys >> 12);
313 out_be32(&pi->piwbar, bus_addr >> 12);
314
315#ifdef CONFIG_SYS_PCI_64BIT
316 out_be32(&pi->piwbear, bus_addr >> 44);
317#else
318 out_be32(&pi->piwbear, 0);
319#endif
320
Hou Zhiqiangadc983b2019-08-27 10:13:48 +0000321#ifdef CONFIG_SYS_FSL_ERRATUM_A005434
322 flag = 0;
323#endif
Hou Zhiqiangb89e3d92019-04-24 22:33:02 +0800324
325 flag |= PIWAR_EN | PIWAR_READ_SNOOP | PIWAR_WRITE_SNOOP;
326 if (pf)
327 flag |= PIWAR_PF;
328 out_be32(&pi->piwar, flag | sz);
329
330 return 0;
331}
332
333static int fsl_pcie_setup_outbound_wins(struct fsl_pcie *pcie)
334{
335 struct pci_region *io, *mem, *pref;
336 int idx = 1; /* skip 0 */
337
338 pci_get_regions(pcie->bus, &io, &mem, &pref);
339
340 if (io)
341 /* ATU : OUTBOUND : IO */
342 fsl_pcie_setup_outbound_win(pcie, idx++,
343 PCI_REGION_IO,
344 io->phys_start,
345 io->bus_start,
346 io->size);
347
348 if (mem)
349 /* ATU : OUTBOUND : MEM */
350 fsl_pcie_setup_outbound_win(pcie, idx++,
351 PCI_REGION_MEM,
352 mem->phys_start,
353 mem->bus_start,
354 mem->size);
355 return 0;
356}
357
358static int fsl_pcie_setup_inbound_wins(struct fsl_pcie *pcie)
359{
Tom Riniecc8d422022-11-16 13:10:33 -0500360 phys_addr_t phys_start = CFG_SYS_PCI_MEMORY_PHYS;
361 pci_addr_t bus_start = CFG_SYS_PCI_MEMORY_BUS;
Hou Zhiqiangb89e3d92019-04-24 22:33:02 +0800362 u64 sz = min((u64)gd->ram_size, (1ull << 32));
363 pci_size_t pci_sz;
364 int idx;
365
366 if (pcie->block_rev >= PEX_IP_BLK_REV_2_2)
367 idx = 2;
368 else
369 idx = 3;
370
371 pci_sz = 1ull << __ilog2_u64(sz);
372
373 dev_dbg(pcie->bus, "R0 bus_start: %llx phys_start: %llx size: %llx\n",
374 (u64)bus_start, (u64)phys_start, (u64)sz);
375
376 /* if we aren't an exact power of two match, pci_sz is smaller
377 * round it up to the next power of two. We report the actual
378 * size to pci region tracking.
379 */
380 if (pci_sz != sz)
381 sz = 2ull << __ilog2_u64(sz);
382
383 fsl_pcie_setup_inbound_win(pcie, idx--, true,
Tom Riniecc8d422022-11-16 13:10:33 -0500384 CFG_SYS_PCI_MEMORY_PHYS,
385 CFG_SYS_PCI_MEMORY_BUS, sz);
Hou Zhiqiangb89e3d92019-04-24 22:33:02 +0800386#if defined(CONFIG_PHYS_64BIT) && defined(CONFIG_SYS_PCI_64BIT)
387 /*
388 * On 64-bit capable systems, set up a mapping for all of DRAM
389 * in high pci address space.
390 */
391 pci_sz = 1ull << __ilog2_u64(gd->ram_size);
392 /* round up to the next largest power of two */
393 if (gd->ram_size > pci_sz)
394 pci_sz = 1ull << (__ilog2_u64(gd->ram_size) + 1);
395
396 dev_dbg(pcie->bus, "R64 bus_start: %llx phys_start: %llx size: %llx\n",
Tom Riniecc8d422022-11-16 13:10:33 -0500397 (u64)CFG_SYS_PCI64_MEMORY_BUS,
398 (u64)CFG_SYS_PCI_MEMORY_PHYS, (u64)pci_sz);
Hou Zhiqiangb89e3d92019-04-24 22:33:02 +0800399
400 fsl_pcie_setup_inbound_win(pcie, idx--, true,
Tom Riniecc8d422022-11-16 13:10:33 -0500401 CFG_SYS_PCI_MEMORY_PHYS,
402 CFG_SYS_PCI64_MEMORY_BUS, pci_sz);
Hou Zhiqiangb89e3d92019-04-24 22:33:02 +0800403#endif
404
405 return 0;
406}
407
408static int fsl_pcie_init_atmu(struct fsl_pcie *pcie)
409{
410 fsl_pcie_setup_outbound_wins(pcie);
411 fsl_pcie_setup_inbound_wins(pcie);
412
413 return 0;
414}
415
Hou Zhiqiang0205beb2020-10-15 14:54:34 +0800416static void fsl_pcie_dbi_read_only_reg_write_enable(struct fsl_pcie *pcie,
417 bool enable)
418{
419 u32 val;
420
421 fsl_pcie_hose_read_config_dword(pcie, DBI_RO_WR_EN, &val);
422 if (enable)
423 val |= 1;
424 else
425 val &= ~1;
426 fsl_pcie_hose_write_config_dword(pcie, DBI_RO_WR_EN, val);
427}
428
Hou Zhiqiangb89e3d92019-04-24 22:33:02 +0800429static int fsl_pcie_init_port(struct fsl_pcie *pcie)
430{
431 ccsr_fsl_pci_t *regs = pcie->regs;
432 u32 val_32;
433 u16 val_16;
434
435 fsl_pcie_init_atmu(pcie);
436
Hou Zhiqiangadc983b2019-08-27 10:13:48 +0000437#ifdef CONFIG_FSL_PCIE_DISABLE_ASPM
438 val_32 = 0;
439 fsl_pcie_hose_read_config_dword(pcie, PCI_LCR, &val_32);
440 val_32 &= ~0x03;
441 fsl_pcie_hose_write_config_dword(pcie, PCI_LCR, val_32);
442 udelay(1);
443#endif
Hou Zhiqiangb89e3d92019-04-24 22:33:02 +0800444
Hou Zhiqiangadc983b2019-08-27 10:13:48 +0000445#ifdef CONFIG_FSL_PCIE_RESET
446 u16 ltssm;
447 int i;
Hou Zhiqiangb89e3d92019-04-24 22:33:02 +0800448
Hou Zhiqiangadc983b2019-08-27 10:13:48 +0000449 if (pcie->block_rev >= PEX_IP_BLK_REV_3_0) {
450 /* assert PCIe reset */
451 setbits_be32(&regs->pdb_stat, 0x08000000);
452 (void)in_be32(&regs->pdb_stat);
453 udelay(1000);
454 /* clear PCIe reset */
455 clrbits_be32(&regs->pdb_stat, 0x08000000);
456 asm("sync;isync");
457 for (i = 0; i < 100 && !fsl_pcie_link_up(pcie); i++)
458 udelay(1000);
459 } else {
460 fsl_pcie_hose_read_config_word(pcie, PCI_LTSSM, &ltssm);
461 if (ltssm == 1) {
Hou Zhiqiangb89e3d92019-04-24 22:33:02 +0800462 /* assert PCIe reset */
463 setbits_be32(&regs->pdb_stat, 0x08000000);
464 (void)in_be32(&regs->pdb_stat);
Hou Zhiqiangadc983b2019-08-27 10:13:48 +0000465 udelay(100);
Hou Zhiqiangb89e3d92019-04-24 22:33:02 +0800466 /* clear PCIe reset */
467 clrbits_be32(&regs->pdb_stat, 0x08000000);
468 asm("sync;isync");
Hou Zhiqiangadc983b2019-08-27 10:13:48 +0000469 for (i = 0; i < 100 &&
470 !fsl_pcie_link_up(pcie); i++)
Hou Zhiqiangb89e3d92019-04-24 22:33:02 +0800471 udelay(1000);
Hou Zhiqiangb89e3d92019-04-24 22:33:02 +0800472 }
473 }
Hou Zhiqiangadc983b2019-08-27 10:13:48 +0000474#endif
Hou Zhiqiangb89e3d92019-04-24 22:33:02 +0800475
Hou Zhiqiangadc983b2019-08-27 10:13:48 +0000476#ifdef CONFIG_SYS_P4080_ERRATUM_PCIE_A003
477 if (!fsl_pcie_link_up(pcie)) {
Hou Zhiqiangb89e3d92019-04-24 22:33:02 +0800478 serdes_corenet_t *srds_regs;
479
Tom Rini6cc04542022-10-28 20:27:13 -0400480 srds_regs = (void *)CFG_SYS_FSL_CORENET_SERDES_ADDR;
Hou Zhiqiangb89e3d92019-04-24 22:33:02 +0800481 val_32 = in_be32(&srds_regs->srdspccr0);
482
483 if ((val_32 >> 28) == 3) {
484 int i;
485
486 out_be32(&srds_regs->srdspccr0, 2 << 28);
487 setbits_be32(&regs->pdb_stat, 0x08000000);
488 in_be32(&regs->pdb_stat);
489 udelay(100);
490 clrbits_be32(&regs->pdb_stat, 0x08000000);
491 asm("sync;isync");
492 for (i = 0; i < 100 && !fsl_pcie_link_up(pcie); i++)
493 udelay(1000);
494 }
495 }
Hou Zhiqiangadc983b2019-08-27 10:13:48 +0000496#endif
Hou Zhiqiangb89e3d92019-04-24 22:33:02 +0800497
498 /*
499 * The Read-Only Write Enable bit defaults to 1 instead of 0.
500 * Set to 0 to protect the read-only registers.
501 */
Hou Zhiqiangadc983b2019-08-27 10:13:48 +0000502#ifdef CONFIG_SYS_FSL_ERRATUM_A007815
Hou Zhiqiang0205beb2020-10-15 14:54:34 +0800503 fsl_pcie_dbi_read_only_reg_write_enable(pcie, false);
Hou Zhiqiangadc983b2019-08-27 10:13:48 +0000504#endif
Hou Zhiqiangb89e3d92019-04-24 22:33:02 +0800505
506 /*
507 * Enable All Error Interrupts except
508 * - Master abort (pci)
509 * - Master PERR (pci)
510 * - ICCA (PCIe)
511 */
512 out_be32(&regs->peer, ~0x20140);
513
514 /* set URR, FER, NFER (but not CER) */
515 fsl_pcie_hose_read_config_dword(pcie, PCI_DCR, &val_32);
516 val_32 |= 0xf000e;
517 fsl_pcie_hose_write_config_dword(pcie, PCI_DCR, val_32);
518
519 /* Clear all error indications */
520 out_be32(&regs->pme_msg_det, 0xffffffff);
521 out_be32(&regs->pme_msg_int_en, 0xffffffff);
522 out_be32(&regs->pedr, 0xffffffff);
523
524 fsl_pcie_hose_read_config_word(pcie, PCI_DSR, &val_16);
525 if (val_16)
526 fsl_pcie_hose_write_config_word(pcie, PCI_DSR, 0xffff);
527
528 fsl_pcie_hose_read_config_word(pcie, PCI_SEC_STATUS, &val_16);
529 if (val_16)
530 fsl_pcie_hose_write_config_word(pcie, PCI_SEC_STATUS, 0xffff);
531
532 return 0;
533}
534
535static int fsl_pcie_fixup_classcode(struct fsl_pcie *pcie)
536{
Hou Zhiqiangd18d06a2019-08-27 10:13:51 +0000537 u32 classcode_reg;
Hou Zhiqiangb89e3d92019-04-24 22:33:02 +0800538 u32 val;
539
Hou Zhiqiangd18d06a2019-08-27 10:13:51 +0000540 if (pcie->block_rev >= PEX_IP_BLK_REV_3_0) {
541 classcode_reg = PCI_CLASS_REVISION;
Hou Zhiqiang0205beb2020-10-15 14:54:34 +0800542 fsl_pcie_dbi_read_only_reg_write_enable(pcie, true);
Hou Zhiqiangd18d06a2019-08-27 10:13:51 +0000543 } else {
544 classcode_reg = CSR_CLASSCODE;
545 }
546
547 fsl_pcie_hose_read_config_dword(pcie, classcode_reg, &val);
Hou Zhiqiangb89e3d92019-04-24 22:33:02 +0800548 val &= 0xff;
Pali Rohárd7b90402022-02-18 13:18:40 +0100549 val |= PCI_CLASS_BRIDGE_PCI_NORMAL << 8;
Hou Zhiqiangd18d06a2019-08-27 10:13:51 +0000550 fsl_pcie_hose_write_config_dword(pcie, classcode_reg, val);
551
552 if (pcie->block_rev >= PEX_IP_BLK_REV_3_0)
Hou Zhiqiang0205beb2020-10-15 14:54:34 +0800553 fsl_pcie_dbi_read_only_reg_write_enable(pcie, false);
Hou Zhiqiangb89e3d92019-04-24 22:33:02 +0800554
555 return 0;
556}
557
558static int fsl_pcie_init_rc(struct fsl_pcie *pcie)
559{
560 return fsl_pcie_fixup_classcode(pcie);
561}
562
563static int fsl_pcie_init_ep(struct fsl_pcie *pcie)
564{
565 fsl_pcie_config_ready(pcie);
566
567 return 0;
568}
569
570static int fsl_pcie_probe(struct udevice *dev)
571{
572 struct fsl_pcie *pcie = dev_get_priv(dev);
573 ccsr_fsl_pci_t *regs = pcie->regs;
574 u16 val_16;
575
576 pcie->bus = dev;
577 pcie->block_rev = in_be32(&regs->block_rev1);
578
579 list_add(&pcie->list, &fsl_pcie_list);
580 pcie->enabled = is_serdes_configured(PCIE1 + pcie->idx);
581 if (!pcie->enabled) {
582 printf("PCIe%d: %s disabled\n", pcie->idx, dev->name);
583 return 0;
584 }
585
586 fsl_pcie_setup_law(pcie);
587
588 pcie->mode = fsl_pcie_is_agent(pcie);
589
590 fsl_pcie_init_port(pcie);
591
592 printf("PCIe%d: %s ", pcie->idx, dev->name);
593
594 if (pcie->mode) {
595 printf("Endpoint");
596 fsl_pcie_init_ep(pcie);
597 } else {
598 printf("Root Complex");
599 fsl_pcie_init_rc(pcie);
600 }
601
602 if (!fsl_pcie_link_up(pcie)) {
603 printf(": %s\n", pcie->mode ? "undetermined link" : "no link");
604 return 0;
605 }
606
607 fsl_pcie_hose_read_config_word(pcie, PCI_LSR, &val_16);
608 printf(": x%d gen%d\n", (val_16 & 0x3f0) >> 4, (val_16 & 0xf));
609
610 return 0;
611}
612
Simon Glassd1998a92020-12-03 16:55:21 -0700613static int fsl_pcie_of_to_plat(struct udevice *dev)
Hou Zhiqiangb89e3d92019-04-24 22:33:02 +0800614{
615 struct fsl_pcie *pcie = dev_get_priv(dev);
Hou Zhiqiangfbcb2ff2019-08-27 10:13:54 +0000616 struct fsl_pcie_data *info;
Hou Zhiqiangb89e3d92019-04-24 22:33:02 +0800617 int ret;
618
619 pcie->regs = dev_remap_addr(dev);
620 if (!pcie->regs) {
621 pr_err("\"reg\" resource not found\n");
622 return -EINVAL;
623 }
624
625 ret = dev_read_u32(dev, "law_trgt_if", &pcie->law_trgt_if);
626 if (ret < 0) {
627 pr_err("\"law_trgt_if\" not found\n");
628 return ret;
629 }
630
Hou Zhiqiangfbcb2ff2019-08-27 10:13:54 +0000631 info = (struct fsl_pcie_data *)dev_get_driver_data(dev);
632 pcie->info = info;
633 pcie->idx = abs((u32)(dev_read_addr(dev) & info->block_offset_mask) -
634 info->block_offset) / info->stride;
Hou Zhiqiangb89e3d92019-04-24 22:33:02 +0800635
636 return 0;
637}
638
639static const struct dm_pci_ops fsl_pcie_ops = {
640 .read_config = fsl_pcie_read_config,
641 .write_config = fsl_pcie_write_config,
642};
643
Hou Zhiqiangba827362019-08-27 11:04:01 +0000644static struct fsl_pcie_data p1_p2_data = {
645 .block_offset = 0xa000,
646 .block_offset_mask = 0xffff,
647 .stride = 0x1000,
648};
649
Hou Zhiqiang1a928022019-08-27 11:04:25 +0000650static struct fsl_pcie_data p2041_data = {
651 .block_offset = 0x200000,
652 .block_offset_mask = 0x3fffff,
653 .stride = 0x1000,
654};
655
Hou Zhiqiangfbcb2ff2019-08-27 10:13:54 +0000656static struct fsl_pcie_data t2080_data = {
657 .block_offset = 0x240000,
658 .block_offset_mask = 0x3fffff,
659 .stride = 0x10000,
660};
661
Hou Zhiqiangb89e3d92019-04-24 22:33:02 +0800662static const struct udevice_id fsl_pcie_ids[] = {
Pali Rohár95f8dfe2022-04-14 22:52:03 +0200663 { .compatible = "fsl,mpc8548-pcie", .data = (ulong)&p1_p2_data },
Hou Zhiqiangba827362019-08-27 11:04:01 +0000664 { .compatible = "fsl,pcie-p1_p2", .data = (ulong)&p1_p2_data },
Hou Zhiqiang1a928022019-08-27 11:04:25 +0000665 { .compatible = "fsl,pcie-p2041", .data = (ulong)&p2041_data },
Hou Zhiqiang096d5f82019-08-27 11:04:39 +0000666 { .compatible = "fsl,pcie-p3041", .data = (ulong)&p2041_data },
Hou Zhiqiang7b7e4e12019-08-27 11:04:52 +0000667 { .compatible = "fsl,pcie-p4080", .data = (ulong)&p2041_data },
Hou Zhiqiang52744592019-08-27 11:05:02 +0000668 { .compatible = "fsl,pcie-p5040", .data = (ulong)&p2041_data },
Hou Zhiqianga8c79f62019-08-27 11:03:24 +0000669 { .compatible = "fsl,pcie-t102x", .data = (ulong)&t2080_data },
Hou Zhiqiang4392ddb2019-08-27 11:03:44 +0000670 { .compatible = "fsl,pcie-t104x", .data = (ulong)&t2080_data },
Hou Zhiqiangfbcb2ff2019-08-27 10:13:54 +0000671 { .compatible = "fsl,pcie-t2080", .data = (ulong)&t2080_data },
Hou Zhiqiang9acc0382019-08-27 11:03:06 +0000672 { .compatible = "fsl,pcie-t4240", .data = (ulong)&t2080_data },
Hou Zhiqiangb89e3d92019-04-24 22:33:02 +0800673 { }
674};
675
676U_BOOT_DRIVER(fsl_pcie) = {
677 .name = "fsl_pcie",
678 .id = UCLASS_PCI,
679 .of_match = fsl_pcie_ids,
680 .ops = &fsl_pcie_ops,
Simon Glassd1998a92020-12-03 16:55:21 -0700681 .of_to_plat = fsl_pcie_of_to_plat,
Hou Zhiqiangb89e3d92019-04-24 22:33:02 +0800682 .probe = fsl_pcie_probe,
Simon Glass41575d82020-12-03 16:55:17 -0700683 .priv_auto = sizeof(struct fsl_pcie),
Hou Zhiqiangb89e3d92019-04-24 22:33:02 +0800684};