blob: b061b31cae59434af8109e9823d1839bed93f4c1 [file] [log] [blame]
Hou Zhiqiang25ff98c2019-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>
16#include <asm/io.h>
Simon Glassdbd79542020-05-10 11:40:11 -060017#include <linux/delay.h>
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +080018#include "pcie_fsl.h"
Simon Glass9bc15642020-02-03 07:36:16 -070019#include <dm/device_compat.h>
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +080020
21LIST_HEAD(fsl_pcie_list);
22
23static int fsl_pcie_link_up(struct fsl_pcie *pcie);
24
25static int fsl_pcie_addr_valid(struct fsl_pcie *pcie, pci_dev_t bdf)
26{
27 struct udevice *bus = pcie->bus;
28
29 if (!pcie->enabled)
30 return -ENXIO;
31
Simon Glass75e534b2020-12-16 21:20:07 -070032 if (PCI_BUS(bdf) < dev_seq(bus))
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +080033 return -EINVAL;
34
Simon Glass75e534b2020-12-16 21:20:07 -070035 if (PCI_BUS(bdf) > dev_seq(bus) && (!fsl_pcie_link_up(pcie) || pcie->mode))
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +080036 return -EINVAL;
37
Simon Glass75e534b2020-12-16 21:20:07 -070038 if (PCI_BUS(bdf) == dev_seq(bus) && (PCI_DEV(bdf) > 0 || PCI_FUNC(bdf) > 0))
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +080039 return -EINVAL;
40
Simon Glass75e534b2020-12-16 21:20:07 -070041 if (PCI_BUS(bdf) == (dev_seq(bus) + 1) && (PCI_DEV(bdf) > 0))
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +080042 return -EINVAL;
43
44 return 0;
45}
46
Simon Glass2a311e82020-01-27 08:49:37 -070047static int fsl_pcie_read_config(const struct udevice *bus, pci_dev_t bdf,
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +080048 uint offset, ulong *valuep,
49 enum pci_size_t size)
50{
51 struct fsl_pcie *pcie = dev_get_priv(bus);
52 ccsr_fsl_pci_t *regs = pcie->regs;
53 u32 val;
54
55 if (fsl_pcie_addr_valid(pcie, bdf)) {
56 *valuep = pci_get_ff(size);
57 return 0;
58 }
59
Simon Glass75e534b2020-12-16 21:20:07 -070060 bdf = bdf - PCI_BDF(dev_seq(bus), 0, 0);
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +080061 val = bdf | (offset & 0xfc) | ((offset & 0xf00) << 16) | 0x80000000;
62 out_be32(&regs->cfg_addr, val);
63
64 sync();
65
66 switch (size) {
67 case PCI_SIZE_8:
68 *valuep = in_8((u8 *)&regs->cfg_data + (offset & 3));
69 break;
70 case PCI_SIZE_16:
71 *valuep = in_le16((u16 *)((u8 *)&regs->cfg_data +
72 (offset & 2)));
73 break;
74 case PCI_SIZE_32:
75 *valuep = in_le32(&regs->cfg_data);
76 break;
77 }
78
79 return 0;
80}
81
82static int fsl_pcie_write_config(struct udevice *bus, pci_dev_t bdf,
83 uint offset, ulong value,
84 enum pci_size_t size)
85{
86 struct fsl_pcie *pcie = dev_get_priv(bus);
87 ccsr_fsl_pci_t *regs = pcie->regs;
88 u32 val;
89 u8 val_8;
90 u16 val_16;
91 u32 val_32;
92
93 if (fsl_pcie_addr_valid(pcie, bdf))
94 return 0;
95
Simon Glass75e534b2020-12-16 21:20:07 -070096 bdf = bdf - PCI_BDF(dev_seq(bus), 0, 0);
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +080097 val = bdf | (offset & 0xfc) | ((offset & 0xf00) << 16) | 0x80000000;
98 out_be32(&regs->cfg_addr, val);
99
100 sync();
101
102 switch (size) {
103 case PCI_SIZE_8:
104 val_8 = value;
105 out_8((u8 *)&regs->cfg_data + (offset & 3), val_8);
106 break;
107 case PCI_SIZE_16:
108 val_16 = value;
109 out_le16((u16 *)((u8 *)&regs->cfg_data + (offset & 2)), val_16);
110 break;
111 case PCI_SIZE_32:
112 val_32 = value;
113 out_le32(&regs->cfg_data, val_32);
114 break;
115 }
116
117 return 0;
118}
119
120static int fsl_pcie_hose_read_config(struct fsl_pcie *pcie, uint offset,
121 ulong *valuep, enum pci_size_t size)
122{
123 int ret;
124 struct udevice *bus = pcie->bus;
125
Simon Glass75e534b2020-12-16 21:20:07 -0700126 ret = fsl_pcie_read_config(bus, PCI_BDF(dev_seq(bus), 0, 0),
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800127 offset, valuep, size);
128
129 return ret;
130}
131
132static int fsl_pcie_hose_write_config(struct fsl_pcie *pcie, uint offset,
133 ulong value, enum pci_size_t size)
134{
135 struct udevice *bus = pcie->bus;
136
Simon Glass75e534b2020-12-16 21:20:07 -0700137 return fsl_pcie_write_config(bus, PCI_BDF(dev_seq(bus), 0, 0),
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800138 offset, value, size);
139}
140
141static int fsl_pcie_hose_read_config_byte(struct fsl_pcie *pcie, uint offset,
142 u8 *valuep)
143{
144 ulong val;
145 int ret;
146
147 ret = fsl_pcie_hose_read_config(pcie, offset, &val, PCI_SIZE_8);
148 *valuep = val;
149
150 return ret;
151}
152
153static int fsl_pcie_hose_read_config_word(struct fsl_pcie *pcie, uint offset,
154 u16 *valuep)
155{
156 ulong val;
157 int ret;
158
159 ret = fsl_pcie_hose_read_config(pcie, offset, &val, PCI_SIZE_16);
160 *valuep = val;
161
162 return ret;
163}
164
165static int fsl_pcie_hose_read_config_dword(struct fsl_pcie *pcie, uint offset,
166 u32 *valuep)
167{
168 ulong val;
169 int ret;
170
171 ret = fsl_pcie_hose_read_config(pcie, offset, &val, PCI_SIZE_32);
172 *valuep = val;
173
174 return ret;
175}
176
177static int fsl_pcie_hose_write_config_byte(struct fsl_pcie *pcie, uint offset,
178 u8 value)
179{
180 return fsl_pcie_hose_write_config(pcie, offset, value, PCI_SIZE_8);
181}
182
183static int fsl_pcie_hose_write_config_word(struct fsl_pcie *pcie, uint offset,
184 u16 value)
185{
186 return fsl_pcie_hose_write_config(pcie, offset, value, PCI_SIZE_16);
187}
188
189static int fsl_pcie_hose_write_config_dword(struct fsl_pcie *pcie, uint offset,
190 u32 value)
191{
192 return fsl_pcie_hose_write_config(pcie, offset, value, PCI_SIZE_32);
193}
194
195static int fsl_pcie_link_up(struct fsl_pcie *pcie)
196{
197 ccsr_fsl_pci_t *regs = pcie->regs;
198 u16 ltssm;
199
200 if (pcie->block_rev >= PEX_IP_BLK_REV_3_0) {
201 ltssm = (in_be32(&regs->pex_csr0)
202 & PEX_CSR0_LTSSM_MASK) >> PEX_CSR0_LTSSM_SHIFT;
203 return ltssm == LTSSM_L0_REV3;
204 }
205
206 fsl_pcie_hose_read_config_word(pcie, PCI_LTSSM, &ltssm);
207
208 return ltssm == LTSSM_L0;
209}
210
211static bool fsl_pcie_is_agent(struct fsl_pcie *pcie)
212{
213 u8 header_type;
214
215 fsl_pcie_hose_read_config_byte(pcie, PCI_HEADER_TYPE, &header_type);
216
217 return (header_type & 0x7f) == PCI_HEADER_TYPE_NORMAL;
218}
219
220static int fsl_pcie_setup_law(struct fsl_pcie *pcie)
221{
222 struct pci_region *io, *mem, *pref;
223
224 pci_get_regions(pcie->bus, &io, &mem, &pref);
225
226 if (mem)
227 set_next_law(mem->phys_start,
228 law_size_bits(mem->size),
229 pcie->law_trgt_if);
230
231 if (io)
232 set_next_law(io->phys_start,
233 law_size_bits(io->size),
234 pcie->law_trgt_if);
235
236 return 0;
237}
238
239static void fsl_pcie_config_ready(struct fsl_pcie *pcie)
240{
241 ccsr_fsl_pci_t *regs = pcie->regs;
242
243 if (pcie->block_rev >= PEX_IP_BLK_REV_3_0) {
244 setbits_be32(&regs->config, FSL_PCIE_V3_CFG_RDY);
245 return;
246 }
247
248 fsl_pcie_hose_write_config_byte(pcie, FSL_PCIE_CFG_RDY, 0x1);
249}
250
251static int fsl_pcie_setup_outbound_win(struct fsl_pcie *pcie, int idx,
252 int type, u64 phys, u64 bus_addr,
253 pci_size_t size)
254{
255 ccsr_fsl_pci_t *regs = pcie->regs;
256 pot_t *po = &regs->pot[idx];
257 u32 war, sz;
258
259 if (idx < 0)
260 return -EINVAL;
261
262 out_be32(&po->powbar, phys >> 12);
263 out_be32(&po->potar, bus_addr >> 12);
264#ifdef CONFIG_SYS_PCI_64BIT
265 out_be32(&po->potear, bus_addr >> 44);
266#else
267 out_be32(&po->potear, 0);
268#endif
269
270 sz = (__ilog2_u64((u64)size) - 1);
271 war = POWAR_EN | sz;
272
273 if (type == PCI_REGION_IO)
274 war |= POWAR_IO_READ | POWAR_IO_WRITE;
275 else
276 war |= POWAR_MEM_READ | POWAR_MEM_WRITE;
277
278 out_be32(&po->powar, war);
279
280 return 0;
281}
282
283static int fsl_pcie_setup_inbound_win(struct fsl_pcie *pcie, int idx,
284 bool pf, u64 phys, u64 bus_addr,
285 pci_size_t size)
286{
287 ccsr_fsl_pci_t *regs = pcie->regs;
288 pit_t *pi = &regs->pit[idx];
289 u32 sz = (__ilog2_u64(size) - 1);
290 u32 flag = PIWAR_LOCAL;
291
292 if (idx < 0)
293 return -EINVAL;
294
295 out_be32(&pi->pitar, phys >> 12);
296 out_be32(&pi->piwbar, bus_addr >> 12);
297
298#ifdef CONFIG_SYS_PCI_64BIT
299 out_be32(&pi->piwbear, bus_addr >> 44);
300#else
301 out_be32(&pi->piwbear, 0);
302#endif
303
Hou Zhiqiang87383332019-08-27 10:13:48 +0000304#ifdef CONFIG_SYS_FSL_ERRATUM_A005434
305 flag = 0;
306#endif
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800307
308 flag |= PIWAR_EN | PIWAR_READ_SNOOP | PIWAR_WRITE_SNOOP;
309 if (pf)
310 flag |= PIWAR_PF;
311 out_be32(&pi->piwar, flag | sz);
312
313 return 0;
314}
315
316static int fsl_pcie_setup_outbound_wins(struct fsl_pcie *pcie)
317{
318 struct pci_region *io, *mem, *pref;
319 int idx = 1; /* skip 0 */
320
321 pci_get_regions(pcie->bus, &io, &mem, &pref);
322
323 if (io)
324 /* ATU : OUTBOUND : IO */
325 fsl_pcie_setup_outbound_win(pcie, idx++,
326 PCI_REGION_IO,
327 io->phys_start,
328 io->bus_start,
329 io->size);
330
331 if (mem)
332 /* ATU : OUTBOUND : MEM */
333 fsl_pcie_setup_outbound_win(pcie, idx++,
334 PCI_REGION_MEM,
335 mem->phys_start,
336 mem->bus_start,
337 mem->size);
338 return 0;
339}
340
341static int fsl_pcie_setup_inbound_wins(struct fsl_pcie *pcie)
342{
343 phys_addr_t phys_start = CONFIG_SYS_PCI_MEMORY_PHYS;
344 pci_addr_t bus_start = CONFIG_SYS_PCI_MEMORY_BUS;
345 u64 sz = min((u64)gd->ram_size, (1ull << 32));
346 pci_size_t pci_sz;
347 int idx;
348
349 if (pcie->block_rev >= PEX_IP_BLK_REV_2_2)
350 idx = 2;
351 else
352 idx = 3;
353
354 pci_sz = 1ull << __ilog2_u64(sz);
355
356 dev_dbg(pcie->bus, "R0 bus_start: %llx phys_start: %llx size: %llx\n",
357 (u64)bus_start, (u64)phys_start, (u64)sz);
358
359 /* if we aren't an exact power of two match, pci_sz is smaller
360 * round it up to the next power of two. We report the actual
361 * size to pci region tracking.
362 */
363 if (pci_sz != sz)
364 sz = 2ull << __ilog2_u64(sz);
365
366 fsl_pcie_setup_inbound_win(pcie, idx--, true,
367 CONFIG_SYS_PCI_MEMORY_PHYS,
368 CONFIG_SYS_PCI_MEMORY_BUS, sz);
369#if defined(CONFIG_PHYS_64BIT) && defined(CONFIG_SYS_PCI_64BIT)
370 /*
371 * On 64-bit capable systems, set up a mapping for all of DRAM
372 * in high pci address space.
373 */
374 pci_sz = 1ull << __ilog2_u64(gd->ram_size);
375 /* round up to the next largest power of two */
376 if (gd->ram_size > pci_sz)
377 pci_sz = 1ull << (__ilog2_u64(gd->ram_size) + 1);
378
379 dev_dbg(pcie->bus, "R64 bus_start: %llx phys_start: %llx size: %llx\n",
380 (u64)CONFIG_SYS_PCI64_MEMORY_BUS,
381 (u64)CONFIG_SYS_PCI_MEMORY_PHYS, (u64)pci_sz);
382
383 fsl_pcie_setup_inbound_win(pcie, idx--, true,
384 CONFIG_SYS_PCI_MEMORY_PHYS,
385 CONFIG_SYS_PCI64_MEMORY_BUS, pci_sz);
386#endif
387
388 return 0;
389}
390
391static int fsl_pcie_init_atmu(struct fsl_pcie *pcie)
392{
393 fsl_pcie_setup_outbound_wins(pcie);
394 fsl_pcie_setup_inbound_wins(pcie);
395
396 return 0;
397}
398
Hou Zhiqiangc5977b12020-10-15 14:54:34 +0800399static void fsl_pcie_dbi_read_only_reg_write_enable(struct fsl_pcie *pcie,
400 bool enable)
401{
402 u32 val;
403
404 fsl_pcie_hose_read_config_dword(pcie, DBI_RO_WR_EN, &val);
405 if (enable)
406 val |= 1;
407 else
408 val &= ~1;
409 fsl_pcie_hose_write_config_dword(pcie, DBI_RO_WR_EN, val);
410}
411
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800412static int fsl_pcie_init_port(struct fsl_pcie *pcie)
413{
414 ccsr_fsl_pci_t *regs = pcie->regs;
415 u32 val_32;
416 u16 val_16;
417
418 fsl_pcie_init_atmu(pcie);
419
Hou Zhiqiang87383332019-08-27 10:13:48 +0000420#ifdef CONFIG_FSL_PCIE_DISABLE_ASPM
421 val_32 = 0;
422 fsl_pcie_hose_read_config_dword(pcie, PCI_LCR, &val_32);
423 val_32 &= ~0x03;
424 fsl_pcie_hose_write_config_dword(pcie, PCI_LCR, val_32);
425 udelay(1);
426#endif
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800427
Hou Zhiqiang87383332019-08-27 10:13:48 +0000428#ifdef CONFIG_FSL_PCIE_RESET
429 u16 ltssm;
430 int i;
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800431
Hou Zhiqiang87383332019-08-27 10:13:48 +0000432 if (pcie->block_rev >= PEX_IP_BLK_REV_3_0) {
433 /* assert PCIe reset */
434 setbits_be32(&regs->pdb_stat, 0x08000000);
435 (void)in_be32(&regs->pdb_stat);
436 udelay(1000);
437 /* clear PCIe reset */
438 clrbits_be32(&regs->pdb_stat, 0x08000000);
439 asm("sync;isync");
440 for (i = 0; i < 100 && !fsl_pcie_link_up(pcie); i++)
441 udelay(1000);
442 } else {
443 fsl_pcie_hose_read_config_word(pcie, PCI_LTSSM, &ltssm);
444 if (ltssm == 1) {
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800445 /* assert PCIe reset */
446 setbits_be32(&regs->pdb_stat, 0x08000000);
447 (void)in_be32(&regs->pdb_stat);
Hou Zhiqiang87383332019-08-27 10:13:48 +0000448 udelay(100);
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800449 /* clear PCIe reset */
450 clrbits_be32(&regs->pdb_stat, 0x08000000);
451 asm("sync;isync");
Hou Zhiqiang87383332019-08-27 10:13:48 +0000452 for (i = 0; i < 100 &&
453 !fsl_pcie_link_up(pcie); i++)
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800454 udelay(1000);
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800455 }
456 }
Hou Zhiqiang87383332019-08-27 10:13:48 +0000457#endif
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800458
Hou Zhiqiang87383332019-08-27 10:13:48 +0000459#ifdef CONFIG_SYS_P4080_ERRATUM_PCIE_A003
460 if (!fsl_pcie_link_up(pcie)) {
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800461 serdes_corenet_t *srds_regs;
462
463 srds_regs = (void *)CONFIG_SYS_FSL_CORENET_SERDES_ADDR;
464 val_32 = in_be32(&srds_regs->srdspccr0);
465
466 if ((val_32 >> 28) == 3) {
467 int i;
468
469 out_be32(&srds_regs->srdspccr0, 2 << 28);
470 setbits_be32(&regs->pdb_stat, 0x08000000);
471 in_be32(&regs->pdb_stat);
472 udelay(100);
473 clrbits_be32(&regs->pdb_stat, 0x08000000);
474 asm("sync;isync");
475 for (i = 0; i < 100 && !fsl_pcie_link_up(pcie); i++)
476 udelay(1000);
477 }
478 }
Hou Zhiqiang87383332019-08-27 10:13:48 +0000479#endif
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800480
481 /*
482 * The Read-Only Write Enable bit defaults to 1 instead of 0.
483 * Set to 0 to protect the read-only registers.
484 */
Hou Zhiqiang87383332019-08-27 10:13:48 +0000485#ifdef CONFIG_SYS_FSL_ERRATUM_A007815
Hou Zhiqiangc5977b12020-10-15 14:54:34 +0800486 fsl_pcie_dbi_read_only_reg_write_enable(pcie, false);
Hou Zhiqiang87383332019-08-27 10:13:48 +0000487#endif
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800488
489 /*
490 * Enable All Error Interrupts except
491 * - Master abort (pci)
492 * - Master PERR (pci)
493 * - ICCA (PCIe)
494 */
495 out_be32(&regs->peer, ~0x20140);
496
497 /* set URR, FER, NFER (but not CER) */
498 fsl_pcie_hose_read_config_dword(pcie, PCI_DCR, &val_32);
499 val_32 |= 0xf000e;
500 fsl_pcie_hose_write_config_dword(pcie, PCI_DCR, val_32);
501
502 /* Clear all error indications */
503 out_be32(&regs->pme_msg_det, 0xffffffff);
504 out_be32(&regs->pme_msg_int_en, 0xffffffff);
505 out_be32(&regs->pedr, 0xffffffff);
506
507 fsl_pcie_hose_read_config_word(pcie, PCI_DSR, &val_16);
508 if (val_16)
509 fsl_pcie_hose_write_config_word(pcie, PCI_DSR, 0xffff);
510
511 fsl_pcie_hose_read_config_word(pcie, PCI_SEC_STATUS, &val_16);
512 if (val_16)
513 fsl_pcie_hose_write_config_word(pcie, PCI_SEC_STATUS, 0xffff);
514
515 return 0;
516}
517
518static int fsl_pcie_fixup_classcode(struct fsl_pcie *pcie)
519{
Hou Zhiqiangd0f3d5e2019-08-27 10:13:51 +0000520 u32 classcode_reg;
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800521 u32 val;
522
Hou Zhiqiangd0f3d5e2019-08-27 10:13:51 +0000523 if (pcie->block_rev >= PEX_IP_BLK_REV_3_0) {
524 classcode_reg = PCI_CLASS_REVISION;
Hou Zhiqiangc5977b12020-10-15 14:54:34 +0800525 fsl_pcie_dbi_read_only_reg_write_enable(pcie, true);
Hou Zhiqiangd0f3d5e2019-08-27 10:13:51 +0000526 } else {
527 classcode_reg = CSR_CLASSCODE;
528 }
529
530 fsl_pcie_hose_read_config_dword(pcie, classcode_reg, &val);
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800531 val &= 0xff;
532 val |= PCI_CLASS_BRIDGE_PCI << 16;
Hou Zhiqiangd0f3d5e2019-08-27 10:13:51 +0000533 fsl_pcie_hose_write_config_dword(pcie, classcode_reg, val);
534
535 if (pcie->block_rev >= PEX_IP_BLK_REV_3_0)
Hou Zhiqiangc5977b12020-10-15 14:54:34 +0800536 fsl_pcie_dbi_read_only_reg_write_enable(pcie, false);
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800537
538 return 0;
539}
540
541static int fsl_pcie_init_rc(struct fsl_pcie *pcie)
542{
543 return fsl_pcie_fixup_classcode(pcie);
544}
545
546static int fsl_pcie_init_ep(struct fsl_pcie *pcie)
547{
548 fsl_pcie_config_ready(pcie);
549
550 return 0;
551}
552
553static int fsl_pcie_probe(struct udevice *dev)
554{
555 struct fsl_pcie *pcie = dev_get_priv(dev);
556 ccsr_fsl_pci_t *regs = pcie->regs;
557 u16 val_16;
558
559 pcie->bus = dev;
560 pcie->block_rev = in_be32(&regs->block_rev1);
561
562 list_add(&pcie->list, &fsl_pcie_list);
563 pcie->enabled = is_serdes_configured(PCIE1 + pcie->idx);
564 if (!pcie->enabled) {
565 printf("PCIe%d: %s disabled\n", pcie->idx, dev->name);
566 return 0;
567 }
568
569 fsl_pcie_setup_law(pcie);
570
571 pcie->mode = fsl_pcie_is_agent(pcie);
572
573 fsl_pcie_init_port(pcie);
574
575 printf("PCIe%d: %s ", pcie->idx, dev->name);
576
577 if (pcie->mode) {
578 printf("Endpoint");
579 fsl_pcie_init_ep(pcie);
580 } else {
581 printf("Root Complex");
582 fsl_pcie_init_rc(pcie);
583 }
584
585 if (!fsl_pcie_link_up(pcie)) {
586 printf(": %s\n", pcie->mode ? "undetermined link" : "no link");
587 return 0;
588 }
589
590 fsl_pcie_hose_read_config_word(pcie, PCI_LSR, &val_16);
591 printf(": x%d gen%d\n", (val_16 & 0x3f0) >> 4, (val_16 & 0xf));
592
593 return 0;
594}
595
Simon Glassaad29ae2020-12-03 16:55:21 -0700596static int fsl_pcie_of_to_plat(struct udevice *dev)
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800597{
598 struct fsl_pcie *pcie = dev_get_priv(dev);
Hou Zhiqiangf0906c92019-08-27 10:13:54 +0000599 struct fsl_pcie_data *info;
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800600 int ret;
601
602 pcie->regs = dev_remap_addr(dev);
603 if (!pcie->regs) {
604 pr_err("\"reg\" resource not found\n");
605 return -EINVAL;
606 }
607
608 ret = dev_read_u32(dev, "law_trgt_if", &pcie->law_trgt_if);
609 if (ret < 0) {
610 pr_err("\"law_trgt_if\" not found\n");
611 return ret;
612 }
613
Hou Zhiqiangf0906c92019-08-27 10:13:54 +0000614 info = (struct fsl_pcie_data *)dev_get_driver_data(dev);
615 pcie->info = info;
616 pcie->idx = abs((u32)(dev_read_addr(dev) & info->block_offset_mask) -
617 info->block_offset) / info->stride;
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800618
619 return 0;
620}
621
622static const struct dm_pci_ops fsl_pcie_ops = {
623 .read_config = fsl_pcie_read_config,
624 .write_config = fsl_pcie_write_config,
625};
626
Hou Zhiqiangae5c6242019-08-27 11:04:01 +0000627static struct fsl_pcie_data p1_p2_data = {
628 .block_offset = 0xa000,
629 .block_offset_mask = 0xffff,
630 .stride = 0x1000,
631};
632
Hou Zhiqiangafffa7b2019-08-27 11:04:25 +0000633static struct fsl_pcie_data p2041_data = {
634 .block_offset = 0x200000,
635 .block_offset_mask = 0x3fffff,
636 .stride = 0x1000,
637};
638
Hou Zhiqiangf0906c92019-08-27 10:13:54 +0000639static struct fsl_pcie_data t2080_data = {
640 .block_offset = 0x240000,
641 .block_offset_mask = 0x3fffff,
642 .stride = 0x10000,
643};
644
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800645static const struct udevice_id fsl_pcie_ids[] = {
Hou Zhiqiang71959862019-08-27 11:05:19 +0000646 { .compatible = "fsl,pcie-mpc8548", .data = (ulong)&p1_p2_data },
Hou Zhiqiangae5c6242019-08-27 11:04:01 +0000647 { .compatible = "fsl,pcie-p1_p2", .data = (ulong)&p1_p2_data },
Hou Zhiqiangafffa7b2019-08-27 11:04:25 +0000648 { .compatible = "fsl,pcie-p2041", .data = (ulong)&p2041_data },
Hou Zhiqiang4cbcf2c2019-08-27 11:04:39 +0000649 { .compatible = "fsl,pcie-p3041", .data = (ulong)&p2041_data },
Hou Zhiqiang48454072019-08-27 11:04:52 +0000650 { .compatible = "fsl,pcie-p4080", .data = (ulong)&p2041_data },
Hou Zhiqiang3ef654c2019-08-27 11:05:02 +0000651 { .compatible = "fsl,pcie-p5040", .data = (ulong)&p2041_data },
Hou Zhiqiang0e1cd0e2019-08-27 11:03:24 +0000652 { .compatible = "fsl,pcie-t102x", .data = (ulong)&t2080_data },
Hou Zhiqiang4b0b23d2019-08-27 11:03:44 +0000653 { .compatible = "fsl,pcie-t104x", .data = (ulong)&t2080_data },
Hou Zhiqiangf0906c92019-08-27 10:13:54 +0000654 { .compatible = "fsl,pcie-t2080", .data = (ulong)&t2080_data },
Hou Zhiqiangf8c8a3a2019-08-27 11:03:06 +0000655 { .compatible = "fsl,pcie-t4240", .data = (ulong)&t2080_data },
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800656 { }
657};
658
659U_BOOT_DRIVER(fsl_pcie) = {
660 .name = "fsl_pcie",
661 .id = UCLASS_PCI,
662 .of_match = fsl_pcie_ids,
663 .ops = &fsl_pcie_ops,
Simon Glassaad29ae2020-12-03 16:55:21 -0700664 .of_to_plat = fsl_pcie_of_to_plat,
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800665 .probe = fsl_pcie_probe,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700666 .priv_auto = sizeof(struct fsl_pcie),
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800667};