blob: 97c38c0bfa7954856471f41a36ea5a3154f3cadb [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Hou Zhiqiang09716a7b2016-12-13 14:54:16 +08002/*
Hou Zhiqiang225a9a92021-11-09 16:56:24 +05303 * Copyright 2017-2021 NXP
Hou Zhiqiang09716a7b2016-12-13 14:54:16 +08004 * Copyright 2014-2015 Freescale Semiconductor, Inc.
5 * Layerscape PCIe driver
Hou Zhiqiang09716a7b2016-12-13 14:54:16 +08006 */
7
Simon Glasse4f61072020-07-19 10:15:49 -06008#include <dm.h>
Simon Glass97589732020-05-10 11:40:02 -06009#include <init.h>
Simon Glass0f2af882020-05-10 11:40:05 -060010#include <log.h>
Hou Zhiqiang09716a7b2016-12-13 14:54:16 +080011#include <pci.h>
12#include <asm/arch/fsl_serdes.h>
13#include <asm/io.h>
14#include <errno.h>
15#ifdef CONFIG_OF_BOARD_SETUP
Masahiro Yamada75f82d02018-03-05 01:20:11 +090016#include <linux/libfdt.h>
Hou Zhiqiang09716a7b2016-12-13 14:54:16 +080017#include <fdt_support.h>
Simon Glass243182c2017-05-17 08:23:06 -060018#ifdef CONFIG_ARM
19#include <asm/arch/clock.h>
20#endif
Laurentiu Tudor7fd23502020-09-10 12:42:19 +030021#include <malloc.h>
22#include <env.h>
Hou Zhiqiang09716a7b2016-12-13 14:54:16 +080023#include "pcie_layerscape.h"
Wasim Khan54e44ef2020-01-06 12:05:57 +000024#include "pcie_layerscape_fixup_common.h"
Hou Zhiqiang09716a7b2016-12-13 14:54:16 +080025
Hou Zhiqiang225a9a92021-11-09 16:56:24 +053026int next_stream_id;
27
Laurentiu Tudor8e6bb372020-09-10 12:42:17 +030028static int fdt_pcie_get_nodeoffset(void *blob, struct ls_pcie_rc *pcie_rc)
29{
30 int nodeoffset;
31 uint svr;
32 char *compat = NULL;
33
34 /* find pci controller node */
35 nodeoffset = fdt_node_offset_by_compat_reg(blob, "fsl,ls-pcie",
36 pcie_rc->dbi_res.start);
37 if (nodeoffset < 0) {
38#ifdef CONFIG_FSL_PCIE_COMPAT /* Compatible with older version of dts node */
39 svr = (get_svr() >> SVR_VAR_PER_SHIFT) & 0xFFFFFE;
40 if (svr == SVR_LS2088A || svr == SVR_LS2084A ||
41 svr == SVR_LS2048A || svr == SVR_LS2044A ||
42 svr == SVR_LS2081A || svr == SVR_LS2041A)
43 compat = "fsl,ls2088a-pcie";
44 else
45 compat = CONFIG_FSL_PCIE_COMPAT;
46
47 nodeoffset =
48 fdt_node_offset_by_compat_reg(blob, compat,
49 pcie_rc->dbi_res.start);
50#endif
51 }
52
53 return nodeoffset;
54}
55
Bharat Bhushan36e36be2017-03-22 12:06:30 +053056#if defined(CONFIG_FSL_LSCH3) || defined(CONFIG_FSL_LSCH2)
Hou Zhiqiang09716a7b2016-12-13 14:54:16 +080057/*
58 * Return next available LUT index.
59 */
Xiaowei Bao13b277f2020-07-09 23:31:33 +080060static int ls_pcie_next_lut_index(struct ls_pcie_rc *pcie_rc)
Hou Zhiqiang09716a7b2016-12-13 14:54:16 +080061{
Xiaowei Bao13b277f2020-07-09 23:31:33 +080062 if (pcie_rc->next_lut_index < PCIE_LUT_ENTRY_COUNT)
63 return pcie_rc->next_lut_index++;
Hou Zhiqiang09716a7b2016-12-13 14:54:16 +080064 else
65 return -ENOSPC; /* LUT is full */
66}
67
Xiaowei Bao13b277f2020-07-09 23:31:33 +080068static void lut_writel(struct ls_pcie_rc *pcie_rc, unsigned int value,
Minghuan Lianc1067842016-12-13 14:54:17 +080069 unsigned int offset)
70{
Xiaowei Bao13b277f2020-07-09 23:31:33 +080071 struct ls_pcie *pcie = pcie_rc->pcie;
72
Minghuan Lianc1067842016-12-13 14:54:17 +080073 if (pcie->big_endian)
74 out_be32(pcie->lut + offset, value);
75 else
76 out_le32(pcie->lut + offset, value);
77}
78
79/*
80 * Program a single LUT entry
81 */
Xiaowei Bao13b277f2020-07-09 23:31:33 +080082static void ls_pcie_lut_set_mapping(struct ls_pcie_rc *pcie_rc, int index,
83 u32 devid, u32 streamid)
Minghuan Lianc1067842016-12-13 14:54:17 +080084{
85 /* leave mask as all zeroes, want to match all bits */
Xiaowei Bao13b277f2020-07-09 23:31:33 +080086 lut_writel(pcie_rc, devid << 16, PCIE_LUT_UDR(index));
87 lut_writel(pcie_rc, streamid | PCIE_LUT_ENABLE, PCIE_LUT_LDR(index));
Minghuan Lianc1067842016-12-13 14:54:17 +080088}
89
90/*
91 * An msi-map is a property to be added to the pci controller
92 * node. It is a table, where each entry consists of 4 fields
93 * e.g.:
94 *
95 * msi-map = <[devid] [phandle-to-msi-ctrl] [stream-id] [count]
96 * [devid] [phandle-to-msi-ctrl] [stream-id] [count]>;
97 */
Xiaowei Bao13b277f2020-07-09 23:31:33 +080098static void fdt_pcie_set_msi_map_entry_ls(void *blob,
99 struct ls_pcie_rc *pcie_rc,
Wasim Khan8cb089e2019-11-15 09:23:35 +0000100 u32 devid, u32 streamid)
Minghuan Lianc1067842016-12-13 14:54:17 +0800101{
102 u32 *prop;
103 u32 phandle;
104 int nodeoffset;
Hou Zhiqiang8cd3f482017-03-03 12:35:10 +0800105 uint svr;
106 char *compat = NULL;
Xiaowei Bao13b277f2020-07-09 23:31:33 +0800107 struct ls_pcie *pcie = pcie_rc->pcie;
Minghuan Lianc1067842016-12-13 14:54:17 +0800108
109 /* find pci controller node */
110 nodeoffset = fdt_node_offset_by_compat_reg(blob, "fsl,ls-pcie",
Xiaowei Bao13b277f2020-07-09 23:31:33 +0800111 pcie_rc->dbi_res.start);
Minghuan Lianc1067842016-12-13 14:54:17 +0800112 if (nodeoffset < 0) {
Hou Zhiqiangd553bf22016-12-13 14:54:24 +0800113#ifdef CONFIG_FSL_PCIE_COMPAT /* Compatible with older version of dts node */
Hou Zhiqiang8cd3f482017-03-03 12:35:10 +0800114 svr = (get_svr() >> SVR_VAR_PER_SHIFT) & 0xFFFFFE;
115 if (svr == SVR_LS2088A || svr == SVR_LS2084A ||
Priyanka Jain2b361782017-04-27 15:08:06 +0530116 svr == SVR_LS2048A || svr == SVR_LS2044A ||
117 svr == SVR_LS2081A || svr == SVR_LS2041A)
Hou Zhiqiang8cd3f482017-03-03 12:35:10 +0800118 compat = "fsl,ls2088a-pcie";
119 else
120 compat = CONFIG_FSL_PCIE_COMPAT;
121 if (compat)
122 nodeoffset = fdt_node_offset_by_compat_reg(blob,
Xiaowei Bao13b277f2020-07-09 23:31:33 +0800123 compat, pcie_rc->dbi_res.start);
Hou Zhiqiang8cd3f482017-03-03 12:35:10 +0800124#endif
Minghuan Lianc1067842016-12-13 14:54:17 +0800125 if (nodeoffset < 0)
126 return;
Minghuan Lianc1067842016-12-13 14:54:17 +0800127 }
128
129 /* get phandle to MSI controller */
130 prop = (u32 *)fdt_getprop(blob, nodeoffset, "msi-parent", 0);
131 if (prop == NULL) {
132 debug("\n%s: ERROR: missing msi-parent: PCIe%d\n",
133 __func__, pcie->idx);
134 return;
135 }
136 phandle = fdt32_to_cpu(*prop);
137
138 /* set one msi-map row */
139 fdt_appendprop_u32(blob, nodeoffset, "msi-map", devid);
140 fdt_appendprop_u32(blob, nodeoffset, "msi-map", phandle);
141 fdt_appendprop_u32(blob, nodeoffset, "msi-map", streamid);
142 fdt_appendprop_u32(blob, nodeoffset, "msi-map", 1);
143}
144
Bharat Bhushan50514b92017-03-22 12:12:33 +0530145/*
146 * An iommu-map is a property to be added to the pci controller
147 * node. It is a table, where each entry consists of 4 fields
148 * e.g.:
149 *
150 * iommu-map = <[devid] [phandle-to-iommu-ctrl] [stream-id] [count]
151 * [devid] [phandle-to-iommu-ctrl] [stream-id] [count]>;
152 */
Xiaowei Bao13b277f2020-07-09 23:31:33 +0800153static void fdt_pcie_set_iommu_map_entry_ls(void *blob,
154 struct ls_pcie_rc *pcie_rc,
Wasim Khan8cb089e2019-11-15 09:23:35 +0000155 u32 devid, u32 streamid)
Bharat Bhushan50514b92017-03-22 12:12:33 +0530156{
157 u32 *prop;
158 u32 iommu_map[4];
159 int nodeoffset;
160 int lenp;
Xiaowei Bao13b277f2020-07-09 23:31:33 +0800161 struct ls_pcie *pcie = pcie_rc->pcie;
Bharat Bhushan50514b92017-03-22 12:12:33 +0530162
Laurentiu Tudor8e6bb372020-09-10 12:42:17 +0300163 nodeoffset = fdt_pcie_get_nodeoffset(blob, pcie_rc);
164 if (nodeoffset < 0)
165 return;
Bharat Bhushan50514b92017-03-22 12:12:33 +0530166
167 /* get phandle to iommu controller */
168 prop = fdt_getprop_w(blob, nodeoffset, "iommu-map", &lenp);
169 if (prop == NULL) {
170 debug("\n%s: ERROR: missing iommu-map: PCIe%d\n",
171 __func__, pcie->idx);
172 return;
173 }
174
175 /* set iommu-map row */
176 iommu_map[0] = cpu_to_fdt32(devid);
177 iommu_map[1] = *++prop;
178 iommu_map[2] = cpu_to_fdt32(streamid);
179 iommu_map[3] = cpu_to_fdt32(1);
180
181 if (devid == 0) {
182 fdt_setprop_inplace(blob, nodeoffset, "iommu-map",
183 iommu_map, 16);
184 } else {
185 fdt_appendprop(blob, nodeoffset, "iommu-map", iommu_map, 16);
186 }
187}
188
Laurentiu Tudor43dff4b2020-10-23 13:35:27 +0530189static int fdt_fixup_pcie_device_ls(void *blob, pci_dev_t bdf,
190 struct ls_pcie_rc *pcie_rc)
191{
192 int streamid, index;
193
194 streamid = pcie_next_streamid(pcie_rc->stream_id_cur,
195 pcie_rc->pcie->idx);
196 if (streamid < 0) {
197 printf("ERROR: out of stream ids for BDF %d.%d.%d\n",
198 PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
199 return -ENOENT;
200 }
201 pcie_rc->stream_id_cur++;
202
203 index = ls_pcie_next_lut_index(pcie_rc);
204 if (index < 0) {
205 printf("ERROR: out of LUT indexes for BDF %d.%d.%d\n",
206 PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
207 return -ENOENT;
208 }
209
210 /* map PCI b.d.f to streamID in LUT */
211 ls_pcie_lut_set_mapping(pcie_rc, index, bdf >> 8, streamid);
212 /* update msi-map in device tree */
213 fdt_pcie_set_msi_map_entry_ls(blob, pcie_rc, bdf >> 8, streamid);
214 /* update iommu-map in device tree */
215 fdt_pcie_set_iommu_map_entry_ls(blob, pcie_rc, bdf >> 8, streamid);
216
217 return 0;
218}
219
Laurentiu Tudor7fd23502020-09-10 12:42:19 +0300220struct extra_iommu_entry {
221 int action;
222 pci_dev_t bdf;
223 int num_vfs;
224 bool noari;
225};
226
227#define EXTRA_IOMMU_ENTRY_HOTPLUG 1
228#define EXTRA_IOMMU_ENTRY_VFS 2
229
230static struct extra_iommu_entry *get_extra_iommu_ents(void *blob,
231 int nodeoffset,
232 phys_addr_t addr,
233 int *cnt)
234{
235 const char *s, *p, *tok;
236 struct extra_iommu_entry *entries;
237 int i = 0, b, d, f;
238
239 /*
240 * Retrieve extra IOMMU configuration from env var or from device tree.
241 * Env var is given priority.
242 */
243 s = env_get("pci_iommu_extra");
244 if (!s) {
245 s = fdt_getprop(blob, nodeoffset, "pci-iommu-extra", NULL);
246 } else {
247 phys_addr_t pci_base;
248 char *endp;
249
250 /*
251 * In env var case the config string has "pci@0x..." in
252 * addition. Parse this part and match it by address against
253 * the input pci controller's registers base address.
254 */
255 tok = s;
256 p = strchrnul(s + 1, ',');
257 s = NULL;
258 do {
259 if (!strncmp(tok, "pci", 3)) {
260 pci_base = simple_strtoul(tok + 4, &endp, 0);
261 if (pci_base == addr) {
262 s = endp + 1;
263 break;
264 }
265 }
266 p = strchrnul(p + 1, ',');
267 tok = p + 1;
268 } while (*p);
269 }
270
271 /*
272 * If no env var or device tree property found or pci register base
273 * address mismatches, bail out
274 */
275 if (!s)
276 return NULL;
277
278 /*
279 * In order to find how many action entries to allocate, count number
280 * of actions by interating through the pairs of bdfs and actions.
281 */
282 *cnt = 0;
283 p = s;
284 while (*p && strncmp(p, "pci", 3)) {
285 if (*p == ',')
286 (*cnt)++;
287 p++;
288 }
289 if (!(*p))
290 (*cnt)++;
291
292 if (!(*cnt) || (*cnt) % 2) {
293 printf("ERROR: invalid or odd extra iommu token count %d\n",
294 *cnt);
295 return NULL;
296 }
297 *cnt = (*cnt) / 2;
298
299 entries = malloc((*cnt) * sizeof(*entries));
300 if (!entries) {
301 printf("ERROR: fail to allocate extra iommu entries\n");
302 return NULL;
303 }
304
305 /*
306 * Parse action entries one by one and store the information in the
307 * newly allocated actions array.
308 */
309 p = s;
310 while (p) {
311 /* Extract BDF */
312 b = simple_strtoul(p, (char **)&p, 0); p++;
313 d = simple_strtoul(p, (char **)&p, 0); p++;
314 f = simple_strtoul(p, (char **)&p, 0); p++;
315 entries[i].bdf = PCI_BDF(b, d, f);
316
317 /* Parse action */
318 if (!strncmp(p, "hp", 2)) {
319 /* Hot-plug entry */
320 entries[i].action = EXTRA_IOMMU_ENTRY_HOTPLUG;
321 p += 2;
322 } else if (!strncmp(p, "vfs", 3) ||
323 !strncmp(p, "noari_vfs", 9)) {
324 /* VFs or VFs with ARI disabled entry */
325 entries[i].action = EXTRA_IOMMU_ENTRY_VFS;
326 entries[i].noari = !strncmp(p, "noari_vfs", 9);
327
328 /*
329 * Parse and store total number of VFs to allocate
330 * IOMMU entries for.
331 */
332 p = strchr(p, '=');
333 entries[i].num_vfs = simple_strtoul(p + 1, (char **)&p,
334 0);
335 if (*p)
336 p++;
337 } else {
338 printf("ERROR: invalid action in extra iommu entry\n");
339 free(entries);
340
341 return NULL;
342 }
343
344 if (!(*p) || !strncmp(p, "pci", 3))
345 break;
346
347 i++;
348 }
349
350 return entries;
351}
352
353static void get_vf_offset_and_stride(struct udevice *dev, int sriov_pos,
354 struct extra_iommu_entry *entry,
355 u16 *offset, u16 *stride)
356{
357 u16 tmp16;
358 u32 tmp32;
359 bool have_ari = false;
360 int pos;
361 struct udevice *pf_dev;
362
363 dm_pci_read_config16(dev, sriov_pos + PCI_SRIOV_TOTAL_VF, &tmp16);
364 if (entry->num_vfs > tmp16) {
365 printf("WARN: requested no. of VFs %d exceeds total of %d\n",
366 entry->num_vfs, tmp16);
367 }
368
369 /*
370 * The code below implements the VF Discovery recomandations specified
371 * in PCIe base spec "9.2.1.2 VF Discovery", quoted below:
372 *
373 * VF Discovery
374 *
375 * The First VF Offset and VF Stride fields in the SR-IOV extended
376 * capability are 16-bit Routing ID offsets. These offsets are used to
377 * compute the Routing IDs for the VFs with the following restrictions:
378 * - The value in NumVFs in a PF (Section 9.3.3.7) may affect the
379 * values in First VF Offset (Section 9.3.3.9) and VF Stride
380 * (Section 9.3.3.10) of that PF.
381 * - The value in ARI Capable Hierarchy (Section 9.3.3.3.5) in the
382 * lowest-numbered PF of the Device (for example PF0) may affect
383 * the values in First VF Offset and VF Stride in all PFs of the
384 * Device.
385 * - NumVFs of a PF may only be changed when VF Enable
386 * (Section 9.3.3.3.1) of that PF is Clear.
387 * - ARI Capable Hierarchy (Section 9.3.3.3.5) may only be changed
388 * when VF Enable is Clear in all PFs of a Device.
389 */
390
391 /* Clear VF enable for all PFs */
392 device_foreach_child(pf_dev, dev->parent) {
393 dm_pci_read_config16(pf_dev, sriov_pos + PCI_SRIOV_CTRL,
394 &tmp16);
395 tmp16 &= ~PCI_SRIOV_CTRL_VFE;
396 dm_pci_write_config16(pf_dev, sriov_pos + PCI_SRIOV_CTRL,
397 tmp16);
398 }
399
400 /* Obtain a reference to PF0 device */
401 if (dm_pci_bus_find_bdf(PCI_BDF(PCI_BUS(entry->bdf),
402 PCI_DEV(entry->bdf), 0), &pf_dev)) {
403 printf("WARN: failed to get PF0\n");
404 }
405
406 if (entry->noari)
407 goto skip_ari;
408
409 /* Check that connected downstream port supports ARI Forwarding */
410 pos = dm_pci_find_capability(dev->parent, PCI_CAP_ID_EXP);
411 dm_pci_read_config32(dev->parent, pos + PCI_EXP_DEVCAP2, &tmp32);
412 if (!(tmp32 & PCI_EXP_DEVCAP2_ARI))
413 goto skip_ari;
414
415 /* Check that PF supports Alternate Routing ID */
416 if (!dm_pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ARI))
417 goto skip_ari;
418
419 /* Set ARI Capable Hierarcy for PF0 */
420 dm_pci_read_config16(pf_dev, sriov_pos + PCI_SRIOV_CTRL, &tmp16);
421 tmp16 |= PCI_SRIOV_CTRL_ARI;
422 dm_pci_write_config16(pf_dev, sriov_pos + PCI_SRIOV_CTRL, tmp16);
423 have_ari = true;
424
425skip_ari:
426 if (!have_ari) {
427 /*
428 * No ARI support or disabled so clear ARI Capable Hierarcy
429 * for PF0
430 */
431 dm_pci_read_config16(pf_dev, sriov_pos + PCI_SRIOV_CTRL,
432 &tmp16);
433 tmp16 &= ~PCI_SRIOV_CTRL_ARI;
434 dm_pci_write_config16(pf_dev, sriov_pos + PCI_SRIOV_CTRL,
435 tmp16);
436 }
437
438 /* Set requested number of VFs */
439 dm_pci_write_config16(dev, sriov_pos + PCI_SRIOV_NUM_VF,
440 entry->num_vfs);
441
442 /* Read VF stride and offset with the configs just made */
443 dm_pci_read_config16(dev, sriov_pos + PCI_SRIOV_VF_OFFSET, offset);
444 dm_pci_read_config16(dev, sriov_pos + PCI_SRIOV_VF_STRIDE, stride);
445
446 if (have_ari) {
447 /* Reset to default ARI Capable Hierarcy bit for PF0 */
448 dm_pci_read_config16(pf_dev, sriov_pos + PCI_SRIOV_CTRL,
449 &tmp16);
450 tmp16 &= ~PCI_SRIOV_CTRL_ARI;
451 dm_pci_write_config16(pf_dev, sriov_pos + PCI_SRIOV_CTRL,
452 tmp16);
453 }
454 /* Reset to default the number of VFs */
455 dm_pci_write_config16(dev, sriov_pos + PCI_SRIOV_NUM_VF, 0);
456}
457
458static int fdt_fixup_pci_vfs(void *blob, struct extra_iommu_entry *entry,
459 struct ls_pcie_rc *pcie_rc)
460{
461 struct udevice *dev, *bus;
462 u16 vf_offset, vf_stride;
463 int i, sriov_pos;
464 pci_dev_t bdf;
465
466 if (dm_pci_bus_find_bdf(entry->bdf, &dev)) {
467 printf("ERROR: BDF %d.%d.%d not found\n", PCI_BUS(entry->bdf),
468 PCI_DEV(entry->bdf), PCI_FUNC(entry->bdf));
469 return 0;
470 }
471
472 sriov_pos = dm_pci_find_ext_capability(dev, PCI_EXT_CAP_ID_SRIOV);
473 if (!sriov_pos) {
474 printf("WARN: trying to set VFs on non-SRIOV dev\n");
475 return 0;
476 }
477
478 get_vf_offset_and_stride(dev, sriov_pos, entry, &vf_offset, &vf_stride);
479
480 for (bus = dev; device_is_on_pci_bus(bus);)
481 bus = bus->parent;
482
Simon Glass75e534b2020-12-16 21:20:07 -0700483 bdf = entry->bdf - PCI_BDF(dev_seq(bus), 0, 0) + (vf_offset << 8);
Laurentiu Tudor7fd23502020-09-10 12:42:19 +0300484
485 for (i = 0; i < entry->num_vfs; i++) {
486 if (fdt_fixup_pcie_device_ls(blob, bdf, pcie_rc) < 0)
487 return -1;
488 bdf += vf_stride << 8;
489 }
490
491 printf("Added %d iommu VF mappings for PF %d.%d.%d\n",
492 entry->num_vfs, PCI_BUS(entry->bdf),
493 PCI_DEV(entry->bdf), PCI_FUNC(entry->bdf));
494
495 return 0;
496}
497
Wasim Khan8cb089e2019-11-15 09:23:35 +0000498static void fdt_fixup_pcie_ls(void *blob)
Minghuan Lianc1067842016-12-13 14:54:17 +0800499{
500 struct udevice *dev, *bus;
Xiaowei Bao13b277f2020-07-09 23:31:33 +0800501 struct ls_pcie_rc *pcie_rc;
Minghuan Lianc1067842016-12-13 14:54:17 +0800502 pci_dev_t bdf;
Laurentiu Tudor7fd23502020-09-10 12:42:19 +0300503 struct extra_iommu_entry *entries;
504 int i, cnt, nodeoffset;
505
Minghuan Lianc1067842016-12-13 14:54:17 +0800506 /* Scan all known buses */
507 for (pci_find_first_device(&dev);
508 dev;
509 pci_find_next_device(&dev)) {
510 for (bus = dev; device_is_on_pci_bus(bus);)
511 bus = bus->parent;
Michael Walle4f1b7b82020-08-04 00:16:33 +0200512
513 /* Only do the fixups for layerscape PCIe controllers */
514 if (!device_is_compatible(bus, "fsl,ls-pcie") &&
515 !device_is_compatible(bus, CONFIG_FSL_PCIE_COMPAT))
516 continue;
517
Xiaowei Bao13b277f2020-07-09 23:31:33 +0800518 pcie_rc = dev_get_priv(bus);
Minghuan Lianc1067842016-12-13 14:54:17 +0800519
Minghuan Lianc1067842016-12-13 14:54:17 +0800520 /* the DT fixup must be relative to the hose first_busno */
Simon Glass75e534b2020-12-16 21:20:07 -0700521 bdf = dm_pci_get_bdf(dev) - PCI_BDF(dev_seq(bus), 0, 0);
Laurentiu Tudor43dff4b2020-10-23 13:35:27 +0530522
523 if (fdt_fixup_pcie_device_ls(blob, bdf, pcie_rc) < 0)
524 break;
Minghuan Lianc1067842016-12-13 14:54:17 +0800525 }
Laurentiu Tudor7fd23502020-09-10 12:42:19 +0300526
527 if (!IS_ENABLED(CONFIG_PCI_IOMMU_EXTRA_MAPPINGS))
Hou Zhiqiang14de76e2021-12-07 18:13:12 +0800528 return;
Laurentiu Tudor7fd23502020-09-10 12:42:19 +0300529
530 list_for_each_entry(pcie_rc, &ls_pcie_list, list) {
531 nodeoffset = fdt_pcie_get_nodeoffset(blob, pcie_rc);
532 if (nodeoffset < 0) {
533 printf("ERROR: couldn't find pci node\n");
534 continue;
535 }
536
537 entries = get_extra_iommu_ents(blob, nodeoffset,
538 pcie_rc->dbi_res.start, &cnt);
539 if (!entries)
540 continue;
541
542 for (i = 0; i < cnt; i++) {
543 if (entries[i].action == EXTRA_IOMMU_ENTRY_HOTPLUG) {
544 bdf = entries[i].bdf;
545 printf("Added iommu map for hotplug %d.%d.%d\n",
546 PCI_BUS(bdf), PCI_DEV(bdf),
547 PCI_FUNC(bdf));
548 if (fdt_fixup_pcie_device_ls(blob, bdf,
549 pcie_rc) < 0) {
550 free(entries);
551 return;
552 }
553 } else if (entries[i].action == EXTRA_IOMMU_ENTRY_VFS) {
554 if (fdt_fixup_pci_vfs(blob, &entries[i],
555 pcie_rc) < 0) {
556 free(entries);
557 return;
558 }
559 } else {
560 printf("Invalid action %d for BDF %d.%d.%d\n",
561 entries[i].action,
562 PCI_BUS(entries[i].bdf),
563 PCI_DEV(entries[i].bdf),
564 PCI_FUNC(entries[i].bdf));
565 }
566 }
567 free(entries);
568 }
Minghuan Lianc1067842016-12-13 14:54:17 +0800569}
570#endif
571
Xiaowei Bao13b277f2020-07-09 23:31:33 +0800572static void ft_pcie_rc_fix(void *blob, struct ls_pcie_rc *pcie_rc)
Minghuan Lianc1067842016-12-13 14:54:17 +0800573{
574 int off;
Xiaowei Bao13b277f2020-07-09 23:31:33 +0800575 struct ls_pcie *pcie = pcie_rc->pcie;
Minghuan Lianc1067842016-12-13 14:54:17 +0800576
Laurentiu Tudor8e6bb372020-09-10 12:42:17 +0300577 off = fdt_pcie_get_nodeoffset(blob, pcie_rc);
578 if (off < 0)
579 return;
Minghuan Lianc1067842016-12-13 14:54:17 +0800580
Xiaowei Bao13b277f2020-07-09 23:31:33 +0800581 if (pcie_rc->enabled && pcie->mode == PCI_HEADER_TYPE_BRIDGE)
Marek Behúnf872e832021-11-26 14:57:08 +0100582 fdt_set_node_status(blob, off, FDT_STATUS_OKAY);
Minghuan Lianc1067842016-12-13 14:54:17 +0800583 else
Marek Behúnf872e832021-11-26 14:57:08 +0100584 fdt_set_node_status(blob, off, FDT_STATUS_DISABLED);
Minghuan Lianc1067842016-12-13 14:54:17 +0800585}
586
Xiaowei Bao13b277f2020-07-09 23:31:33 +0800587static void ft_pcie_ep_fix(void *blob, struct ls_pcie_rc *pcie_rc)
Xiaowei Bao8d7e2e82018-10-26 09:56:26 +0800588{
589 int off;
Xiaowei Bao13b277f2020-07-09 23:31:33 +0800590 struct ls_pcie *pcie = pcie_rc->pcie;
Xiaowei Bao8d7e2e82018-10-26 09:56:26 +0800591
Pankaj Bansal64d85a22019-11-30 13:14:10 +0000592 off = fdt_node_offset_by_compat_reg(blob, CONFIG_FSL_PCIE_EP_COMPAT,
Xiaowei Bao13b277f2020-07-09 23:31:33 +0800593 pcie_rc->dbi_res.start);
Xiaowei Bao8d7e2e82018-10-26 09:56:26 +0800594 if (off < 0)
595 return;
596
Xiaowei Bao13b277f2020-07-09 23:31:33 +0800597 if (pcie_rc->enabled && pcie->mode == PCI_HEADER_TYPE_NORMAL)
Marek Behúnf872e832021-11-26 14:57:08 +0100598 fdt_set_node_status(blob, off, FDT_STATUS_OKAY);
Xiaowei Bao8d7e2e82018-10-26 09:56:26 +0800599 else
Marek Behúnf872e832021-11-26 14:57:08 +0100600 fdt_set_node_status(blob, off, FDT_STATUS_DISABLED);
Xiaowei Bao8d7e2e82018-10-26 09:56:26 +0800601}
602
Xiaowei Bao13b277f2020-07-09 23:31:33 +0800603static void ft_pcie_ls_setup(void *blob, struct ls_pcie_rc *pcie_rc)
Xiaowei Bao8d7e2e82018-10-26 09:56:26 +0800604{
Xiaowei Bao13b277f2020-07-09 23:31:33 +0800605 ft_pcie_ep_fix(blob, pcie_rc);
606 ft_pcie_rc_fix(blob, pcie_rc);
Hou Zhiqiang225a9a92021-11-09 16:56:24 +0530607
608 pcie_rc->stream_id_cur = 0;
609 pcie_rc->next_lut_index = 0;
Xiaowei Bao8d7e2e82018-10-26 09:56:26 +0800610}
611
Minghuan Lianc1067842016-12-13 14:54:17 +0800612/* Fixup Kernel DT for PCIe */
Masahiro Yamadaf7ed78b2020-06-26 15:13:33 +0900613void ft_pci_setup_ls(void *blob, struct bd_info *bd)
Minghuan Lianc1067842016-12-13 14:54:17 +0800614{
Xiaowei Bao13b277f2020-07-09 23:31:33 +0800615 struct ls_pcie_rc *pcie_rc;
Minghuan Lianc1067842016-12-13 14:54:17 +0800616
Hou Zhiqiang14de76e2021-12-07 18:13:12 +0800617#if defined(CONFIG_FSL_LSCH3) || defined(CONFIG_FSL_LSCH2)
618 pcie_board_fix_fdt(blob);
619#endif
620
Xiaowei Bao13b277f2020-07-09 23:31:33 +0800621 list_for_each_entry(pcie_rc, &ls_pcie_list, list)
622 ft_pcie_ls_setup(blob, pcie_rc);
Hou Zhiqiang09716a7b2016-12-13 14:54:16 +0800623
Bharat Bhushan36e36be2017-03-22 12:06:30 +0530624#if defined(CONFIG_FSL_LSCH3) || defined(CONFIG_FSL_LSCH2)
Hou Zhiqiang225a9a92021-11-09 16:56:24 +0530625 next_stream_id = FSL_PEX_STREAM_ID_START;
Wasim Khan8cb089e2019-11-15 09:23:35 +0000626 fdt_fixup_pcie_ls(blob);
Hou Zhiqiang09716a7b2016-12-13 14:54:16 +0800627#endif
628}
Hou Zhiqiang09716a7b2016-12-13 14:54:16 +0800629
630#else /* !CONFIG_OF_BOARD_SETUP */
Masahiro Yamadaf7ed78b2020-06-26 15:13:33 +0900631void ft_pci_setup_ls(void *blob, struct bd_info *bd)
Hou Zhiqiang09716a7b2016-12-13 14:54:16 +0800632{
633}
634#endif