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