blob: 1975004e5981d5bb98f91f42b6bf750b0581b697 [file] [log] [blame]
Hou Zhiqiang5a9a5ed2019-04-08 10:15:54 +00001// SPDX-License-Identifier: GPL-2.0+ OR X11
2/*
Wasim Khan54e44ef2020-01-06 12:05:57 +00003 * Copyright 2018-2020 NXP
Hou Zhiqiang5a9a5ed2019-04-08 10:15:54 +00004 *
5 * PCIe Gen4 driver for NXP Layerscape SoCs
6 * Author: Hou Zhiqiang <Minder.Hou@gmail.com>
7 *
8 */
9
10#include <common.h>
Simon Glass0f2af882020-05-10 11:40:05 -060011#include <log.h>
Hou Zhiqiang5a9a5ed2019-04-08 10:15:54 +000012#include <pci.h>
13#include <asm/arch/fsl_serdes.h>
14#include <asm/io.h>
15#include <errno.h>
16#ifdef CONFIG_OF_BOARD_SETUP
17#include <linux/libfdt.h>
18#include <fdt_support.h>
19#ifdef CONFIG_ARM
20#include <asm/arch/clock.h>
21#endif
22#include "pcie_layerscape_gen4.h"
Wasim Khan54e44ef2020-01-06 12:05:57 +000023#include "pcie_layerscape_fixup_common.h"
Hou Zhiqiang5a9a5ed2019-04-08 10:15:54 +000024
25#if defined(CONFIG_FSL_LSCH3) || defined(CONFIG_FSL_LSCH2)
26/*
27 * Return next available LUT index.
28 */
29static int ls_pcie_g4_next_lut_index(struct ls_pcie_g4 *pcie)
30{
31 if (pcie->next_lut_index < PCIE_LUT_ENTRY_COUNT)
32 return pcie->next_lut_index++;
33
34 return -ENOSPC; /* LUT is full */
35}
36
Hou Zhiqiang5a9a5ed2019-04-08 10:15:54 +000037/*
38 * Program a single LUT entry
39 */
40static void ls_pcie_g4_lut_set_mapping(struct ls_pcie_g4 *pcie, int index,
41 u32 devid, u32 streamid)
42{
43 /* leave mask as all zeroes, want to match all bits */
44 lut_writel(pcie, devid << 16, PCIE_LUT_UDR(index));
45 lut_writel(pcie, streamid | PCIE_LUT_ENABLE, PCIE_LUT_LDR(index));
46}
47
48/*
49 * An msi-map is a property to be added to the pci controller
50 * node. It is a table, where each entry consists of 4 fields
51 * e.g.:
52 *
53 * msi-map = <[devid] [phandle-to-msi-ctrl] [stream-id] [count]
54 * [devid] [phandle-to-msi-ctrl] [stream-id] [count]>;
55 */
Wasim Khanb1ec2812019-11-15 09:23:37 +000056static void fdt_pcie_set_msi_map_entry_ls_gen4(void *blob,
57 struct ls_pcie_g4 *pcie,
58 u32 devid, u32 streamid)
Hou Zhiqiang5a9a5ed2019-04-08 10:15:54 +000059{
60 u32 *prop;
61 u32 phandle;
62 int nodeoff;
63
64#ifdef CONFIG_FSL_PCIE_COMPAT
65 nodeoff = fdt_node_offset_by_compat_reg(blob, CONFIG_FSL_PCIE_COMPAT,
66 pcie->ccsr_res.start);
67#else
68#error "No CONFIG_FSL_PCIE_COMPAT defined"
69#endif
70 if (nodeoff < 0) {
71 debug("%s: ERROR: failed to find pcie compatiable\n", __func__);
72 return;
73 }
74
75 /* get phandle to MSI controller */
76 prop = (u32 *)fdt_getprop(blob, nodeoff, "msi-parent", 0);
77 if (!prop) {
78 debug("\n%s: ERROR: missing msi-parent: PCIe%d\n",
79 __func__, pcie->idx);
80 return;
81 }
82 phandle = fdt32_to_cpu(*prop);
83
84 /* set one msi-map row */
85 fdt_appendprop_u32(blob, nodeoff, "msi-map", devid);
86 fdt_appendprop_u32(blob, nodeoff, "msi-map", phandle);
87 fdt_appendprop_u32(blob, nodeoff, "msi-map", streamid);
88 fdt_appendprop_u32(blob, nodeoff, "msi-map", 1);
89}
90
91/*
92 * An iommu-map is a property to be added to the pci controller
93 * node. It is a table, where each entry consists of 4 fields
94 * e.g.:
95 *
96 * iommu-map = <[devid] [phandle-to-iommu-ctrl] [stream-id] [count]
97 * [devid] [phandle-to-iommu-ctrl] [stream-id] [count]>;
98 */
Wasim Khanb1ec2812019-11-15 09:23:37 +000099static void fdt_pcie_set_iommu_map_entry_ls_gen4(void *blob,
100 struct ls_pcie_g4 *pcie,
101 u32 devid, u32 streamid)
Hou Zhiqiang5a9a5ed2019-04-08 10:15:54 +0000102{
103 u32 *prop;
104 u32 iommu_map[4];
105 int nodeoff;
106 int lenp;
107
108#ifdef CONFIG_FSL_PCIE_COMPAT
109 nodeoff = fdt_node_offset_by_compat_reg(blob, CONFIG_FSL_PCIE_COMPAT,
110 pcie->ccsr_res.start);
111#else
112#error "No CONFIG_FSL_PCIE_COMPAT defined"
113#endif
114 if (nodeoff < 0) {
115 debug("%s: ERROR: failed to find pcie compatiable\n", __func__);
116 return;
117 }
118
119 /* get phandle to iommu controller */
120 prop = fdt_getprop_w(blob, nodeoff, "iommu-map", &lenp);
121 if (!prop) {
122 debug("\n%s: ERROR: missing iommu-map: PCIe%d\n",
123 __func__, pcie->idx);
124 return;
125 }
126
127 /* set iommu-map row */
128 iommu_map[0] = cpu_to_fdt32(devid);
129 iommu_map[1] = *++prop;
130 iommu_map[2] = cpu_to_fdt32(streamid);
131 iommu_map[3] = cpu_to_fdt32(1);
132
133 if (devid == 0)
134 fdt_setprop_inplace(blob, nodeoff, "iommu-map", iommu_map, 16);
135 else
136 fdt_appendprop(blob, nodeoff, "iommu-map", iommu_map, 16);
137}
138
Wasim Khanb1ec2812019-11-15 09:23:37 +0000139static void fdt_fixup_pcie_ls_gen4(void *blob)
Hou Zhiqiang5a9a5ed2019-04-08 10:15:54 +0000140{
141 struct udevice *dev, *bus;
142 struct ls_pcie_g4 *pcie;
143 int streamid;
144 int index;
145 pci_dev_t bdf;
146
147 /* Scan all known buses */
148 for (pci_find_first_device(&dev); dev; pci_find_next_device(&dev)) {
149 for (bus = dev; device_is_on_pci_bus(bus);)
150 bus = bus->parent;
151 pcie = dev_get_priv(bus);
152
Wasim Khan9d3d2302020-01-06 12:05:59 +0000153 streamid = pcie_next_streamid(pcie->stream_id_cur, pcie->idx);
Hou Zhiqiang5a9a5ed2019-04-08 10:15:54 +0000154 if (streamid < 0) {
155 debug("ERROR: no stream ids free\n");
156 continue;
Wasim Khan9d3d2302020-01-06 12:05:59 +0000157 } else {
158 pcie->stream_id_cur++;
Hou Zhiqiang5a9a5ed2019-04-08 10:15:54 +0000159 }
160
161 index = ls_pcie_g4_next_lut_index(pcie);
162 if (index < 0) {
163 debug("ERROR: no LUT indexes free\n");
164 continue;
165 }
166
167 /* the DT fixup must be relative to the hose first_busno */
168 bdf = dm_pci_get_bdf(dev) - PCI_BDF(bus->seq, 0, 0);
169 /* map PCI b.d.f to streamID in LUT */
170 ls_pcie_g4_lut_set_mapping(pcie, index, bdf >> 8, streamid);
171 /* update msi-map in device tree */
Wasim Khanb1ec2812019-11-15 09:23:37 +0000172 fdt_pcie_set_msi_map_entry_ls_gen4(blob, pcie, bdf >> 8,
173 streamid);
Hou Zhiqiang5a9a5ed2019-04-08 10:15:54 +0000174 /* update iommu-map in device tree */
Wasim Khanb1ec2812019-11-15 09:23:37 +0000175 fdt_pcie_set_iommu_map_entry_ls_gen4(blob, pcie, bdf >> 8,
176 streamid);
Hou Zhiqiang5a9a5ed2019-04-08 10:15:54 +0000177 }
178}
179#endif
180
181static void ft_pcie_ep_layerscape_gen4_fix(void *blob, struct ls_pcie_g4 *pcie)
182{
183 int off;
184
Pankaj Bansal64d85a22019-11-30 13:14:10 +0000185 off = fdt_node_offset_by_compat_reg(blob, CONFIG_FSL_PCIE_EP_COMPAT,
Hou Zhiqiang5a9a5ed2019-04-08 10:15:54 +0000186 pcie->ccsr_res.start);
187
188 if (off < 0) {
189 debug("%s: ERROR: failed to find pcie compatiable\n",
190 __func__);
191 return;
192 }
193
194 if (pcie->enabled && pcie->mode == PCI_HEADER_TYPE_NORMAL)
195 fdt_set_node_status(blob, off, FDT_STATUS_OKAY, 0);
196 else
197 fdt_set_node_status(blob, off, FDT_STATUS_DISABLED, 0);
198}
199
200static void ft_pcie_rc_layerscape_gen4_fix(void *blob, struct ls_pcie_g4 *pcie)
201{
202 int off;
203
204#ifdef CONFIG_FSL_PCIE_COMPAT
205 off = fdt_node_offset_by_compat_reg(blob, CONFIG_FSL_PCIE_COMPAT,
206 pcie->ccsr_res.start);
207#else
208#error "No CONFIG_FSL_PCIE_COMPAT defined"
209#endif
210 if (off < 0) {
211 debug("%s: ERROR: failed to find pcie compatiable\n", __func__);
212 return;
213 }
214
215 if (pcie->enabled && pcie->mode == PCI_HEADER_TYPE_BRIDGE)
216 fdt_set_node_status(blob, off, FDT_STATUS_OKAY, 0);
217 else
218 fdt_set_node_status(blob, off, FDT_STATUS_DISABLED, 0);
219}
220
221static void ft_pcie_layerscape_gen4_setup(void *blob, struct ls_pcie_g4 *pcie)
222{
223 ft_pcie_rc_layerscape_gen4_fix(blob, pcie);
224 ft_pcie_ep_layerscape_gen4_fix(blob, pcie);
225}
226
227/* Fixup Kernel DT for PCIe */
Wasim Khan54e44ef2020-01-06 12:05:57 +0000228void ft_pci_setup_ls_gen4(void *blob, bd_t *bd)
Hou Zhiqiang5a9a5ed2019-04-08 10:15:54 +0000229{
230 struct ls_pcie_g4 *pcie;
231
232 list_for_each_entry(pcie, &ls_pcie_g4_list, list)
233 ft_pcie_layerscape_gen4_setup(blob, pcie);
234
235#if defined(CONFIG_FSL_LSCH3) || defined(CONFIG_FSL_LSCH2)
Wasim Khanb1ec2812019-11-15 09:23:37 +0000236 fdt_fixup_pcie_ls_gen4(blob);
Hou Zhiqiang5a9a5ed2019-04-08 10:15:54 +0000237#endif
238}
239
240#else /* !CONFIG_OF_BOARD_SETUP */
Wasim Khan54e44ef2020-01-06 12:05:57 +0000241void ft_pci_setup_ls_gen4(void *blob, bd_t *bd)
Hou Zhiqiang5a9a5ed2019-04-08 10:15:54 +0000242{
243}
244#endif