blob: ec917ee7d5b87d4c2401e08f0cf5b6e53e26e593 [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>
Simon Glassbdd5f812023-09-14 18:21:46 -060019#include <linux/printk.h>
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +080020#include "pcie_fsl.h"
Simon Glass9bc15642020-02-03 07:36:16 -070021#include <dm/device_compat.h>
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +080022
23LIST_HEAD(fsl_pcie_list);
24
25static int fsl_pcie_link_up(struct fsl_pcie *pcie);
26
27static int fsl_pcie_addr_valid(struct fsl_pcie *pcie, pci_dev_t bdf)
28{
29 struct udevice *bus = pcie->bus;
30
31 if (!pcie->enabled)
32 return -ENXIO;
33
Simon Glass75e534b2020-12-16 21:20:07 -070034 if (PCI_BUS(bdf) < dev_seq(bus))
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +080035 return -EINVAL;
36
Simon Glass75e534b2020-12-16 21:20:07 -070037 if (PCI_BUS(bdf) > dev_seq(bus) && (!fsl_pcie_link_up(pcie) || pcie->mode))
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +080038 return -EINVAL;
39
Simon Glass75e534b2020-12-16 21:20:07 -070040 if (PCI_BUS(bdf) == dev_seq(bus) && (PCI_DEV(bdf) > 0 || PCI_FUNC(bdf) > 0))
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +080041 return -EINVAL;
42
Simon Glass75e534b2020-12-16 21:20:07 -070043 if (PCI_BUS(bdf) == (dev_seq(bus) + 1) && (PCI_DEV(bdf) > 0))
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +080044 return -EINVAL;
45
46 return 0;
47}
48
Simon Glass2a311e82020-01-27 08:49:37 -070049static int fsl_pcie_read_config(const struct udevice *bus, pci_dev_t bdf,
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +080050 uint offset, ulong *valuep,
51 enum pci_size_t size)
52{
53 struct fsl_pcie *pcie = dev_get_priv(bus);
54 ccsr_fsl_pci_t *regs = pcie->regs;
55 u32 val;
56
57 if (fsl_pcie_addr_valid(pcie, bdf)) {
58 *valuep = pci_get_ff(size);
59 return 0;
60 }
61
Pali Rohár14546c12023-05-02 19:53:57 +020062 /* Skip Freescale PCIe controller's PEXCSRBAR register */
63 if (PCI_BUS(bdf) - dev_seq(bus) == 0 &&
64 PCI_DEV(bdf) == 0 && PCI_FUNC(bdf) == 0 &&
65 (offset & ~3) == PCI_BASE_ADDRESS_0) {
66 *valuep = 0;
67 return 0;
68 }
69
Pali Rohárc8bb2872021-11-26 11:42:47 +010070 val = PCI_CONF1_EXT_ADDRESS(PCI_BUS(bdf) - dev_seq(bus),
71 PCI_DEV(bdf), PCI_FUNC(bdf),
72 offset);
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +080073 out_be32(&regs->cfg_addr, val);
74
75 sync();
76
77 switch (size) {
78 case PCI_SIZE_8:
79 *valuep = in_8((u8 *)&regs->cfg_data + (offset & 3));
80 break;
81 case PCI_SIZE_16:
82 *valuep = in_le16((u16 *)((u8 *)&regs->cfg_data +
83 (offset & 2)));
84 break;
85 case PCI_SIZE_32:
86 *valuep = in_le32(&regs->cfg_data);
87 break;
88 }
89
90 return 0;
91}
92
93static int fsl_pcie_write_config(struct udevice *bus, pci_dev_t bdf,
94 uint offset, ulong value,
95 enum pci_size_t size)
96{
97 struct fsl_pcie *pcie = dev_get_priv(bus);
98 ccsr_fsl_pci_t *regs = pcie->regs;
99 u32 val;
100 u8 val_8;
101 u16 val_16;
102 u32 val_32;
103
104 if (fsl_pcie_addr_valid(pcie, bdf))
105 return 0;
106
Pali Rohár14546c12023-05-02 19:53:57 +0200107 /* Skip Freescale PCIe controller's PEXCSRBAR register */
108 if (PCI_BUS(bdf) - dev_seq(bus) == 0 &&
109 PCI_DEV(bdf) == 0 && PCI_FUNC(bdf) == 0 &&
110 (offset & ~3) == PCI_BASE_ADDRESS_0)
111 return 0;
112
Pali Rohárc8bb2872021-11-26 11:42:47 +0100113 val = PCI_CONF1_EXT_ADDRESS(PCI_BUS(bdf) - dev_seq(bus),
114 PCI_DEV(bdf), PCI_FUNC(bdf),
115 offset);
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800116 out_be32(&regs->cfg_addr, val);
117
118 sync();
119
120 switch (size) {
121 case PCI_SIZE_8:
122 val_8 = value;
123 out_8((u8 *)&regs->cfg_data + (offset & 3), val_8);
124 break;
125 case PCI_SIZE_16:
126 val_16 = value;
127 out_le16((u16 *)((u8 *)&regs->cfg_data + (offset & 2)), val_16);
128 break;
129 case PCI_SIZE_32:
130 val_32 = value;
131 out_le32(&regs->cfg_data, val_32);
132 break;
133 }
134
135 return 0;
136}
137
138static int fsl_pcie_hose_read_config(struct fsl_pcie *pcie, uint offset,
139 ulong *valuep, enum pci_size_t size)
140{
141 int ret;
142 struct udevice *bus = pcie->bus;
143
Simon Glass75e534b2020-12-16 21:20:07 -0700144 ret = fsl_pcie_read_config(bus, PCI_BDF(dev_seq(bus), 0, 0),
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800145 offset, valuep, size);
146
147 return ret;
148}
149
150static int fsl_pcie_hose_write_config(struct fsl_pcie *pcie, uint offset,
151 ulong value, enum pci_size_t size)
152{
153 struct udevice *bus = pcie->bus;
154
Simon Glass75e534b2020-12-16 21:20:07 -0700155 return fsl_pcie_write_config(bus, PCI_BDF(dev_seq(bus), 0, 0),
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800156 offset, value, size);
157}
158
159static int fsl_pcie_hose_read_config_byte(struct fsl_pcie *pcie, uint offset,
160 u8 *valuep)
161{
162 ulong val;
163 int ret;
164
165 ret = fsl_pcie_hose_read_config(pcie, offset, &val, PCI_SIZE_8);
166 *valuep = val;
167
168 return ret;
169}
170
171static int fsl_pcie_hose_read_config_word(struct fsl_pcie *pcie, uint offset,
172 u16 *valuep)
173{
174 ulong val;
175 int ret;
176
177 ret = fsl_pcie_hose_read_config(pcie, offset, &val, PCI_SIZE_16);
178 *valuep = val;
179
180 return ret;
181}
182
183static int fsl_pcie_hose_read_config_dword(struct fsl_pcie *pcie, uint offset,
184 u32 *valuep)
185{
186 ulong val;
187 int ret;
188
189 ret = fsl_pcie_hose_read_config(pcie, offset, &val, PCI_SIZE_32);
190 *valuep = val;
191
192 return ret;
193}
194
195static int fsl_pcie_hose_write_config_byte(struct fsl_pcie *pcie, uint offset,
196 u8 value)
197{
198 return fsl_pcie_hose_write_config(pcie, offset, value, PCI_SIZE_8);
199}
200
201static int fsl_pcie_hose_write_config_word(struct fsl_pcie *pcie, uint offset,
202 u16 value)
203{
204 return fsl_pcie_hose_write_config(pcie, offset, value, PCI_SIZE_16);
205}
206
207static int fsl_pcie_hose_write_config_dword(struct fsl_pcie *pcie, uint offset,
208 u32 value)
209{
210 return fsl_pcie_hose_write_config(pcie, offset, value, PCI_SIZE_32);
211}
212
213static int fsl_pcie_link_up(struct fsl_pcie *pcie)
214{
215 ccsr_fsl_pci_t *regs = pcie->regs;
216 u16 ltssm;
217
218 if (pcie->block_rev >= PEX_IP_BLK_REV_3_0) {
219 ltssm = (in_be32(&regs->pex_csr0)
220 & PEX_CSR0_LTSSM_MASK) >> PEX_CSR0_LTSSM_SHIFT;
221 return ltssm == LTSSM_L0_REV3;
222 }
223
224 fsl_pcie_hose_read_config_word(pcie, PCI_LTSSM, &ltssm);
225
226 return ltssm == LTSSM_L0;
227}
228
229static bool fsl_pcie_is_agent(struct fsl_pcie *pcie)
230{
231 u8 header_type;
232
233 fsl_pcie_hose_read_config_byte(pcie, PCI_HEADER_TYPE, &header_type);
234
235 return (header_type & 0x7f) == PCI_HEADER_TYPE_NORMAL;
236}
237
238static int fsl_pcie_setup_law(struct fsl_pcie *pcie)
239{
240 struct pci_region *io, *mem, *pref;
241
242 pci_get_regions(pcie->bus, &io, &mem, &pref);
243
244 if (mem)
245 set_next_law(mem->phys_start,
246 law_size_bits(mem->size),
247 pcie->law_trgt_if);
248
249 if (io)
250 set_next_law(io->phys_start,
251 law_size_bits(io->size),
252 pcie->law_trgt_if);
253
254 return 0;
255}
256
257static void fsl_pcie_config_ready(struct fsl_pcie *pcie)
258{
259 ccsr_fsl_pci_t *regs = pcie->regs;
260
261 if (pcie->block_rev >= PEX_IP_BLK_REV_3_0) {
262 setbits_be32(&regs->config, FSL_PCIE_V3_CFG_RDY);
263 return;
264 }
265
266 fsl_pcie_hose_write_config_byte(pcie, FSL_PCIE_CFG_RDY, 0x1);
267}
268
269static int fsl_pcie_setup_outbound_win(struct fsl_pcie *pcie, int idx,
270 int type, u64 phys, u64 bus_addr,
271 pci_size_t size)
272{
273 ccsr_fsl_pci_t *regs = pcie->regs;
274 pot_t *po = &regs->pot[idx];
275 u32 war, sz;
276
277 if (idx < 0)
278 return -EINVAL;
279
280 out_be32(&po->powbar, phys >> 12);
281 out_be32(&po->potar, bus_addr >> 12);
282#ifdef CONFIG_SYS_PCI_64BIT
283 out_be32(&po->potear, bus_addr >> 44);
284#else
285 out_be32(&po->potear, 0);
286#endif
287
288 sz = (__ilog2_u64((u64)size) - 1);
289 war = POWAR_EN | sz;
290
291 if (type == PCI_REGION_IO)
292 war |= POWAR_IO_READ | POWAR_IO_WRITE;
293 else
294 war |= POWAR_MEM_READ | POWAR_MEM_WRITE;
295
296 out_be32(&po->powar, war);
297
298 return 0;
299}
300
301static int fsl_pcie_setup_inbound_win(struct fsl_pcie *pcie, int idx,
302 bool pf, u64 phys, u64 bus_addr,
303 pci_size_t size)
304{
305 ccsr_fsl_pci_t *regs = pcie->regs;
306 pit_t *pi = &regs->pit[idx];
307 u32 sz = (__ilog2_u64(size) - 1);
308 u32 flag = PIWAR_LOCAL;
309
310 if (idx < 0)
311 return -EINVAL;
312
313 out_be32(&pi->pitar, phys >> 12);
314 out_be32(&pi->piwbar, bus_addr >> 12);
315
316#ifdef CONFIG_SYS_PCI_64BIT
317 out_be32(&pi->piwbear, bus_addr >> 44);
318#else
319 out_be32(&pi->piwbear, 0);
320#endif
321
Hou Zhiqiang87383332019-08-27 10:13:48 +0000322#ifdef CONFIG_SYS_FSL_ERRATUM_A005434
323 flag = 0;
324#endif
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800325
326 flag |= PIWAR_EN | PIWAR_READ_SNOOP | PIWAR_WRITE_SNOOP;
327 if (pf)
328 flag |= PIWAR_PF;
329 out_be32(&pi->piwar, flag | sz);
330
331 return 0;
332}
333
334static int fsl_pcie_setup_outbound_wins(struct fsl_pcie *pcie)
335{
336 struct pci_region *io, *mem, *pref;
337 int idx = 1; /* skip 0 */
338
339 pci_get_regions(pcie->bus, &io, &mem, &pref);
340
341 if (io)
342 /* ATU : OUTBOUND : IO */
343 fsl_pcie_setup_outbound_win(pcie, idx++,
344 PCI_REGION_IO,
345 io->phys_start,
346 io->bus_start,
347 io->size);
348
349 if (mem)
350 /* ATU : OUTBOUND : MEM */
351 fsl_pcie_setup_outbound_win(pcie, idx++,
352 PCI_REGION_MEM,
353 mem->phys_start,
354 mem->bus_start,
355 mem->size);
356 return 0;
357}
358
359static int fsl_pcie_setup_inbound_wins(struct fsl_pcie *pcie)
360{
Tom Rini56af6592022-11-16 13:10:33 -0500361 phys_addr_t phys_start = CFG_SYS_PCI_MEMORY_PHYS;
362 pci_addr_t bus_start = CFG_SYS_PCI_MEMORY_BUS;
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800363 u64 sz = min((u64)gd->ram_size, (1ull << 32));
364 pci_size_t pci_sz;
365 int idx;
366
367 if (pcie->block_rev >= PEX_IP_BLK_REV_2_2)
368 idx = 2;
369 else
370 idx = 3;
371
372 pci_sz = 1ull << __ilog2_u64(sz);
373
374 dev_dbg(pcie->bus, "R0 bus_start: %llx phys_start: %llx size: %llx\n",
375 (u64)bus_start, (u64)phys_start, (u64)sz);
376
377 /* if we aren't an exact power of two match, pci_sz is smaller
378 * round it up to the next power of two. We report the actual
379 * size to pci region tracking.
380 */
381 if (pci_sz != sz)
382 sz = 2ull << __ilog2_u64(sz);
383
384 fsl_pcie_setup_inbound_win(pcie, idx--, true,
Tom Rini56af6592022-11-16 13:10:33 -0500385 CFG_SYS_PCI_MEMORY_PHYS,
386 CFG_SYS_PCI_MEMORY_BUS, sz);
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800387#if defined(CONFIG_PHYS_64BIT) && defined(CONFIG_SYS_PCI_64BIT)
388 /*
389 * On 64-bit capable systems, set up a mapping for all of DRAM
390 * in high pci address space.
391 */
392 pci_sz = 1ull << __ilog2_u64(gd->ram_size);
393 /* round up to the next largest power of two */
394 if (gd->ram_size > pci_sz)
395 pci_sz = 1ull << (__ilog2_u64(gd->ram_size) + 1);
396
397 dev_dbg(pcie->bus, "R64 bus_start: %llx phys_start: %llx size: %llx\n",
Tom Rini56af6592022-11-16 13:10:33 -0500398 (u64)CFG_SYS_PCI64_MEMORY_BUS,
399 (u64)CFG_SYS_PCI_MEMORY_PHYS, (u64)pci_sz);
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800400
401 fsl_pcie_setup_inbound_win(pcie, idx--, true,
Tom Rini56af6592022-11-16 13:10:33 -0500402 CFG_SYS_PCI_MEMORY_PHYS,
403 CFG_SYS_PCI64_MEMORY_BUS, pci_sz);
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800404#endif
405
406 return 0;
407}
408
409static int fsl_pcie_init_atmu(struct fsl_pcie *pcie)
410{
411 fsl_pcie_setup_outbound_wins(pcie);
412 fsl_pcie_setup_inbound_wins(pcie);
413
414 return 0;
415}
416
Hou Zhiqiangc5977b12020-10-15 14:54:34 +0800417static void fsl_pcie_dbi_read_only_reg_write_enable(struct fsl_pcie *pcie,
418 bool enable)
419{
420 u32 val;
421
422 fsl_pcie_hose_read_config_dword(pcie, DBI_RO_WR_EN, &val);
423 if (enable)
424 val |= 1;
425 else
426 val &= ~1;
427 fsl_pcie_hose_write_config_dword(pcie, DBI_RO_WR_EN, val);
428}
429
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800430static int fsl_pcie_init_port(struct fsl_pcie *pcie)
431{
432 ccsr_fsl_pci_t *regs = pcie->regs;
433 u32 val_32;
434 u16 val_16;
435
436 fsl_pcie_init_atmu(pcie);
437
Hou Zhiqiang87383332019-08-27 10:13:48 +0000438#ifdef CONFIG_FSL_PCIE_DISABLE_ASPM
439 val_32 = 0;
440 fsl_pcie_hose_read_config_dword(pcie, PCI_LCR, &val_32);
441 val_32 &= ~0x03;
442 fsl_pcie_hose_write_config_dword(pcie, PCI_LCR, val_32);
443 udelay(1);
444#endif
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800445
Hou Zhiqiang87383332019-08-27 10:13:48 +0000446#ifdef CONFIG_FSL_PCIE_RESET
447 u16 ltssm;
448 int i;
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800449
Hou Zhiqiang87383332019-08-27 10:13:48 +0000450 if (pcie->block_rev >= PEX_IP_BLK_REV_3_0) {
451 /* assert PCIe reset */
452 setbits_be32(&regs->pdb_stat, 0x08000000);
453 (void)in_be32(&regs->pdb_stat);
454 udelay(1000);
455 /* clear PCIe reset */
456 clrbits_be32(&regs->pdb_stat, 0x08000000);
457 asm("sync;isync");
458 for (i = 0; i < 100 && !fsl_pcie_link_up(pcie); i++)
459 udelay(1000);
460 } else {
461 fsl_pcie_hose_read_config_word(pcie, PCI_LTSSM, &ltssm);
462 if (ltssm == 1) {
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800463 /* assert PCIe reset */
464 setbits_be32(&regs->pdb_stat, 0x08000000);
465 (void)in_be32(&regs->pdb_stat);
Hou Zhiqiang87383332019-08-27 10:13:48 +0000466 udelay(100);
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800467 /* clear PCIe reset */
468 clrbits_be32(&regs->pdb_stat, 0x08000000);
469 asm("sync;isync");
Hou Zhiqiang87383332019-08-27 10:13:48 +0000470 for (i = 0; i < 100 &&
471 !fsl_pcie_link_up(pcie); i++)
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800472 udelay(1000);
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800473 }
474 }
Hou Zhiqiang87383332019-08-27 10:13:48 +0000475#endif
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800476
Hou Zhiqiang87383332019-08-27 10:13:48 +0000477#ifdef CONFIG_SYS_P4080_ERRATUM_PCIE_A003
478 if (!fsl_pcie_link_up(pcie)) {
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800479 serdes_corenet_t *srds_regs;
480
Tom Rini376b88a2022-10-28 20:27:13 -0400481 srds_regs = (void *)CFG_SYS_FSL_CORENET_SERDES_ADDR;
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800482 val_32 = in_be32(&srds_regs->srdspccr0);
483
484 if ((val_32 >> 28) == 3) {
485 int i;
486
487 out_be32(&srds_regs->srdspccr0, 2 << 28);
488 setbits_be32(&regs->pdb_stat, 0x08000000);
489 in_be32(&regs->pdb_stat);
490 udelay(100);
491 clrbits_be32(&regs->pdb_stat, 0x08000000);
492 asm("sync;isync");
493 for (i = 0; i < 100 && !fsl_pcie_link_up(pcie); i++)
494 udelay(1000);
495 }
496 }
Hou Zhiqiang87383332019-08-27 10:13:48 +0000497#endif
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800498
499 /*
500 * The Read-Only Write Enable bit defaults to 1 instead of 0.
501 * Set to 0 to protect the read-only registers.
502 */
Hou Zhiqiang87383332019-08-27 10:13:48 +0000503#ifdef CONFIG_SYS_FSL_ERRATUM_A007815
Hou Zhiqiangc5977b12020-10-15 14:54:34 +0800504 fsl_pcie_dbi_read_only_reg_write_enable(pcie, false);
Hou Zhiqiang87383332019-08-27 10:13:48 +0000505#endif
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800506
507 /*
508 * Enable All Error Interrupts except
509 * - Master abort (pci)
510 * - Master PERR (pci)
511 * - ICCA (PCIe)
512 */
513 out_be32(&regs->peer, ~0x20140);
514
515 /* set URR, FER, NFER (but not CER) */
516 fsl_pcie_hose_read_config_dword(pcie, PCI_DCR, &val_32);
517 val_32 |= 0xf000e;
518 fsl_pcie_hose_write_config_dword(pcie, PCI_DCR, val_32);
519
520 /* Clear all error indications */
521 out_be32(&regs->pme_msg_det, 0xffffffff);
522 out_be32(&regs->pme_msg_int_en, 0xffffffff);
523 out_be32(&regs->pedr, 0xffffffff);
524
525 fsl_pcie_hose_read_config_word(pcie, PCI_DSR, &val_16);
526 if (val_16)
527 fsl_pcie_hose_write_config_word(pcie, PCI_DSR, 0xffff);
528
529 fsl_pcie_hose_read_config_word(pcie, PCI_SEC_STATUS, &val_16);
530 if (val_16)
531 fsl_pcie_hose_write_config_word(pcie, PCI_SEC_STATUS, 0xffff);
532
533 return 0;
534}
535
536static int fsl_pcie_fixup_classcode(struct fsl_pcie *pcie)
537{
Hou Zhiqiangd0f3d5e2019-08-27 10:13:51 +0000538 u32 classcode_reg;
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800539 u32 val;
540
Hou Zhiqiangd0f3d5e2019-08-27 10:13:51 +0000541 if (pcie->block_rev >= PEX_IP_BLK_REV_3_0) {
542 classcode_reg = PCI_CLASS_REVISION;
Hou Zhiqiangc5977b12020-10-15 14:54:34 +0800543 fsl_pcie_dbi_read_only_reg_write_enable(pcie, true);
Hou Zhiqiangd0f3d5e2019-08-27 10:13:51 +0000544 } else {
545 classcode_reg = CSR_CLASSCODE;
546 }
547
548 fsl_pcie_hose_read_config_dword(pcie, classcode_reg, &val);
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800549 val &= 0xff;
Pali Rohár25781e22022-02-18 13:18:40 +0100550 val |= PCI_CLASS_BRIDGE_PCI_NORMAL << 8;
Hou Zhiqiangd0f3d5e2019-08-27 10:13:51 +0000551 fsl_pcie_hose_write_config_dword(pcie, classcode_reg, val);
552
553 if (pcie->block_rev >= PEX_IP_BLK_REV_3_0)
Hou Zhiqiangc5977b12020-10-15 14:54:34 +0800554 fsl_pcie_dbi_read_only_reg_write_enable(pcie, false);
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800555
556 return 0;
557}
558
559static int fsl_pcie_init_rc(struct fsl_pcie *pcie)
560{
561 return fsl_pcie_fixup_classcode(pcie);
562}
563
564static int fsl_pcie_init_ep(struct fsl_pcie *pcie)
565{
566 fsl_pcie_config_ready(pcie);
567
568 return 0;
569}
570
571static int fsl_pcie_probe(struct udevice *dev)
572{
573 struct fsl_pcie *pcie = dev_get_priv(dev);
574 ccsr_fsl_pci_t *regs = pcie->regs;
575 u16 val_16;
576
577 pcie->bus = dev;
578 pcie->block_rev = in_be32(&regs->block_rev1);
579
580 list_add(&pcie->list, &fsl_pcie_list);
581 pcie->enabled = is_serdes_configured(PCIE1 + pcie->idx);
582 if (!pcie->enabled) {
583 printf("PCIe%d: %s disabled\n", pcie->idx, dev->name);
584 return 0;
585 }
586
587 fsl_pcie_setup_law(pcie);
588
589 pcie->mode = fsl_pcie_is_agent(pcie);
590
591 fsl_pcie_init_port(pcie);
592
593 printf("PCIe%d: %s ", pcie->idx, dev->name);
594
595 if (pcie->mode) {
596 printf("Endpoint");
597 fsl_pcie_init_ep(pcie);
598 } else {
599 printf("Root Complex");
600 fsl_pcie_init_rc(pcie);
601 }
602
603 if (!fsl_pcie_link_up(pcie)) {
604 printf(": %s\n", pcie->mode ? "undetermined link" : "no link");
605 return 0;
606 }
607
608 fsl_pcie_hose_read_config_word(pcie, PCI_LSR, &val_16);
609 printf(": x%d gen%d\n", (val_16 & 0x3f0) >> 4, (val_16 & 0xf));
610
611 return 0;
612}
613
Simon Glassaad29ae2020-12-03 16:55:21 -0700614static int fsl_pcie_of_to_plat(struct udevice *dev)
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800615{
616 struct fsl_pcie *pcie = dev_get_priv(dev);
Hou Zhiqiangf0906c92019-08-27 10:13:54 +0000617 struct fsl_pcie_data *info;
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800618 int ret;
619
620 pcie->regs = dev_remap_addr(dev);
621 if (!pcie->regs) {
622 pr_err("\"reg\" resource not found\n");
623 return -EINVAL;
624 }
625
626 ret = dev_read_u32(dev, "law_trgt_if", &pcie->law_trgt_if);
627 if (ret < 0) {
628 pr_err("\"law_trgt_if\" not found\n");
629 return ret;
630 }
631
Hou Zhiqiangf0906c92019-08-27 10:13:54 +0000632 info = (struct fsl_pcie_data *)dev_get_driver_data(dev);
633 pcie->info = info;
634 pcie->idx = abs((u32)(dev_read_addr(dev) & info->block_offset_mask) -
635 info->block_offset) / info->stride;
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800636
637 return 0;
638}
639
640static const struct dm_pci_ops fsl_pcie_ops = {
641 .read_config = fsl_pcie_read_config,
642 .write_config = fsl_pcie_write_config,
643};
644
Hou Zhiqiangae5c6242019-08-27 11:04:01 +0000645static struct fsl_pcie_data p1_p2_data = {
646 .block_offset = 0xa000,
647 .block_offset_mask = 0xffff,
648 .stride = 0x1000,
649};
650
Hou Zhiqiangafffa7b2019-08-27 11:04:25 +0000651static struct fsl_pcie_data p2041_data = {
652 .block_offset = 0x200000,
653 .block_offset_mask = 0x3fffff,
654 .stride = 0x1000,
655};
656
Hou Zhiqiangf0906c92019-08-27 10:13:54 +0000657static struct fsl_pcie_data t2080_data = {
658 .block_offset = 0x240000,
659 .block_offset_mask = 0x3fffff,
660 .stride = 0x10000,
661};
662
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800663static const struct udevice_id fsl_pcie_ids[] = {
Pali Rohárccc205a2022-04-14 22:52:03 +0200664 { .compatible = "fsl,mpc8548-pcie", .data = (ulong)&p1_p2_data },
Hou Zhiqiangae5c6242019-08-27 11:04:01 +0000665 { .compatible = "fsl,pcie-p1_p2", .data = (ulong)&p1_p2_data },
Hou Zhiqiangafffa7b2019-08-27 11:04:25 +0000666 { .compatible = "fsl,pcie-p2041", .data = (ulong)&p2041_data },
Hou Zhiqiang4cbcf2c2019-08-27 11:04:39 +0000667 { .compatible = "fsl,pcie-p3041", .data = (ulong)&p2041_data },
Hou Zhiqiang48454072019-08-27 11:04:52 +0000668 { .compatible = "fsl,pcie-p4080", .data = (ulong)&p2041_data },
Hou Zhiqiang3ef654c2019-08-27 11:05:02 +0000669 { .compatible = "fsl,pcie-p5040", .data = (ulong)&p2041_data },
Hou Zhiqiang0e1cd0e2019-08-27 11:03:24 +0000670 { .compatible = "fsl,pcie-t102x", .data = (ulong)&t2080_data },
Hou Zhiqiang4b0b23d2019-08-27 11:03:44 +0000671 { .compatible = "fsl,pcie-t104x", .data = (ulong)&t2080_data },
Hou Zhiqiangf0906c92019-08-27 10:13:54 +0000672 { .compatible = "fsl,pcie-t2080", .data = (ulong)&t2080_data },
Hou Zhiqiangf8c8a3a2019-08-27 11:03:06 +0000673 { .compatible = "fsl,pcie-t4240", .data = (ulong)&t2080_data },
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800674 { }
675};
676
677U_BOOT_DRIVER(fsl_pcie) = {
678 .name = "fsl_pcie",
679 .id = UCLASS_PCI,
680 .of_match = fsl_pcie_ids,
681 .ops = &fsl_pcie_ops,
Simon Glassaad29ae2020-12-03 16:55:21 -0700682 .of_to_plat = fsl_pcie_of_to_plat,
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800683 .probe = fsl_pcie_probe,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700684 .priv_auto = sizeof(struct fsl_pcie),
Hou Zhiqiang25ff98c2019-04-24 22:33:02 +0800685};