Merge tag 'ti-v2020.10-rc4' of https://gitlab.denx.de/u-boot/custodians/u-boot-ti
[platform/kernel/u-boot.git] / drivers / pci / pcie_layerscape_fixup.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright 2017-2020 NXP
4  * Copyright 2014-2015 Freescale Semiconductor, Inc.
5  * Layerscape PCIe driver
6  */
7
8 #include <common.h>
9 #include <dm.h>
10 #include <init.h>
11 #include <log.h>
12 #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.h"
23 #include "pcie_layerscape_fixup_common.h"
24
25 #if defined(CONFIG_FSL_LSCH3) || defined(CONFIG_FSL_LSCH2)
26 /*
27  * Return next available LUT index.
28  */
29 static int ls_pcie_next_lut_index(struct ls_pcie_rc *pcie_rc)
30 {
31         if (pcie_rc->next_lut_index < PCIE_LUT_ENTRY_COUNT)
32                 return pcie_rc->next_lut_index++;
33         else
34                 return -ENOSPC;  /* LUT is full */
35 }
36
37 static void lut_writel(struct ls_pcie_rc *pcie_rc, unsigned int value,
38                        unsigned int offset)
39 {
40         struct ls_pcie *pcie = pcie_rc->pcie;
41
42         if (pcie->big_endian)
43                 out_be32(pcie->lut + offset, value);
44         else
45                 out_le32(pcie->lut + offset, value);
46 }
47
48 /*
49  * Program a single LUT entry
50  */
51 static void ls_pcie_lut_set_mapping(struct ls_pcie_rc *pcie_rc, int index,
52                                     u32 devid, u32 streamid)
53 {
54         /* leave mask as all zeroes, want to match all bits */
55         lut_writel(pcie_rc, devid << 16, PCIE_LUT_UDR(index));
56         lut_writel(pcie_rc, streamid | PCIE_LUT_ENABLE, PCIE_LUT_LDR(index));
57 }
58
59 /*
60  * An msi-map is a property to be added to the pci controller
61  * node.  It is a table, where each entry consists of 4 fields
62  * e.g.:
63  *
64  *      msi-map = <[devid] [phandle-to-msi-ctrl] [stream-id] [count]
65  *                 [devid] [phandle-to-msi-ctrl] [stream-id] [count]>;
66  */
67 static void fdt_pcie_set_msi_map_entry_ls(void *blob,
68                                           struct ls_pcie_rc *pcie_rc,
69                                           u32 devid, u32 streamid)
70 {
71         u32 *prop;
72         u32 phandle;
73         int nodeoffset;
74         uint svr;
75         char *compat = NULL;
76         struct ls_pcie *pcie = pcie_rc->pcie;
77
78         /* find pci controller node */
79         nodeoffset = fdt_node_offset_by_compat_reg(blob, "fsl,ls-pcie",
80                                                    pcie_rc->dbi_res.start);
81         if (nodeoffset < 0) {
82 #ifdef CONFIG_FSL_PCIE_COMPAT /* Compatible with older version of dts node */
83                 svr = (get_svr() >> SVR_VAR_PER_SHIFT) & 0xFFFFFE;
84                 if (svr == SVR_LS2088A || svr == SVR_LS2084A ||
85                     svr == SVR_LS2048A || svr == SVR_LS2044A ||
86                     svr == SVR_LS2081A || svr == SVR_LS2041A)
87                         compat = "fsl,ls2088a-pcie";
88                 else
89                         compat = CONFIG_FSL_PCIE_COMPAT;
90                 if (compat)
91                         nodeoffset = fdt_node_offset_by_compat_reg(blob,
92                                         compat, pcie_rc->dbi_res.start);
93 #endif
94                 if (nodeoffset < 0)
95                         return;
96         }
97
98         /* get phandle to MSI controller */
99         prop = (u32 *)fdt_getprop(blob, nodeoffset, "msi-parent", 0);
100         if (prop == NULL) {
101                 debug("\n%s: ERROR: missing msi-parent: PCIe%d\n",
102                       __func__, pcie->idx);
103                 return;
104         }
105         phandle = fdt32_to_cpu(*prop);
106
107         /* set one msi-map row */
108         fdt_appendprop_u32(blob, nodeoffset, "msi-map", devid);
109         fdt_appendprop_u32(blob, nodeoffset, "msi-map", phandle);
110         fdt_appendprop_u32(blob, nodeoffset, "msi-map", streamid);
111         fdt_appendprop_u32(blob, nodeoffset, "msi-map", 1);
112 }
113
114 /*
115  * An iommu-map is a property to be added to the pci controller
116  * node.  It is a table, where each entry consists of 4 fields
117  * e.g.:
118  *
119  *      iommu-map = <[devid] [phandle-to-iommu-ctrl] [stream-id] [count]
120  *                 [devid] [phandle-to-iommu-ctrl] [stream-id] [count]>;
121  */
122 static void fdt_pcie_set_iommu_map_entry_ls(void *blob,
123                                             struct ls_pcie_rc *pcie_rc,
124                                             u32 devid, u32 streamid)
125 {
126         u32 *prop;
127         u32 iommu_map[4];
128         int nodeoffset;
129         int lenp;
130         uint svr;
131         char *compat = NULL;
132         struct ls_pcie *pcie = pcie_rc->pcie;
133
134         /* find pci controller node */
135         nodeoffset = fdt_node_offset_by_compat_reg(blob, "fsl,ls-pcie",
136                                                    pcie_rc->dbi_res.start);
137         if (nodeoffset < 0) {
138 #ifdef CONFIG_FSL_PCIE_COMPAT /* Compatible with older version of dts node */
139                 svr = (get_svr() >> SVR_VAR_PER_SHIFT) & 0xFFFFFE;
140                 if (svr == SVR_LS2088A || svr == SVR_LS2084A ||
141                     svr == SVR_LS2048A || svr == SVR_LS2044A ||
142                     svr == SVR_LS2081A || svr == SVR_LS2041A)
143                         compat = "fsl,ls2088a-pcie";
144                 else
145                         compat = CONFIG_FSL_PCIE_COMPAT;
146
147                 if (compat)
148                         nodeoffset = fdt_node_offset_by_compat_reg(blob,
149                                                 compat, pcie_rc->dbi_res.start);
150 #endif
151                 if (nodeoffset < 0)
152                         return;
153         }
154
155         /* get phandle to iommu controller */
156         prop = fdt_getprop_w(blob, nodeoffset, "iommu-map", &lenp);
157         if (prop == NULL) {
158                 debug("\n%s: ERROR: missing iommu-map: PCIe%d\n",
159                       __func__, pcie->idx);
160                 return;
161         }
162
163         /* set iommu-map row */
164         iommu_map[0] = cpu_to_fdt32(devid);
165         iommu_map[1] = *++prop;
166         iommu_map[2] = cpu_to_fdt32(streamid);
167         iommu_map[3] = cpu_to_fdt32(1);
168
169         if (devid == 0) {
170                 fdt_setprop_inplace(blob, nodeoffset, "iommu-map",
171                                     iommu_map, 16);
172         } else {
173                 fdt_appendprop(blob, nodeoffset, "iommu-map", iommu_map, 16);
174         }
175 }
176
177 static void fdt_fixup_pcie_ls(void *blob)
178 {
179         struct udevice *dev, *bus;
180         struct ls_pcie_rc *pcie_rc;
181         int streamid;
182         int index;
183         pci_dev_t bdf;
184
185         /* Scan all known buses */
186         for (pci_find_first_device(&dev);
187              dev;
188              pci_find_next_device(&dev)) {
189                 for (bus = dev; device_is_on_pci_bus(bus);)
190                         bus = bus->parent;
191                 pcie_rc = dev_get_priv(bus);
192
193                 streamid = pcie_next_streamid(pcie_rc->stream_id_cur,
194                                               pcie_rc->pcie->idx);
195                 if (streamid < 0) {
196                         debug("ERROR: no stream ids free\n");
197                         continue;
198                 } else {
199                         pcie_rc->stream_id_cur++;
200                 }
201
202                 index = ls_pcie_next_lut_index(pcie_rc);
203                 if (index < 0) {
204                         debug("ERROR: no LUT indexes free\n");
205                         continue;
206                 }
207
208                 /* the DT fixup must be relative to the hose first_busno */
209                 bdf = dm_pci_get_bdf(dev) - PCI_BDF(bus->seq, 0, 0);
210                 /* map PCI b.d.f to streamID in LUT */
211                 ls_pcie_lut_set_mapping(pcie_rc, index, bdf >> 8,
212                                         streamid);
213                 /* update msi-map in device tree */
214                 fdt_pcie_set_msi_map_entry_ls(blob, pcie_rc, bdf >> 8,
215                                               streamid);
216                 /* update iommu-map in device tree */
217                 fdt_pcie_set_iommu_map_entry_ls(blob, pcie_rc, bdf >> 8,
218                                                 streamid);
219         }
220         pcie_board_fix_fdt(blob);
221 }
222 #endif
223
224 static void ft_pcie_rc_fix(void *blob, struct ls_pcie_rc *pcie_rc)
225 {
226         int off;
227         uint svr;
228         char *compat = NULL;
229         struct ls_pcie *pcie = pcie_rc->pcie;
230
231         off = fdt_node_offset_by_compat_reg(blob, "fsl,ls-pcie",
232                                             pcie_rc->dbi_res.start);
233         if (off < 0) {
234 #ifdef CONFIG_FSL_PCIE_COMPAT /* Compatible with older version of dts node */
235                 svr = (get_svr() >> SVR_VAR_PER_SHIFT) & 0xFFFFFE;
236                 if (svr == SVR_LS2088A || svr == SVR_LS2084A ||
237                     svr == SVR_LS2048A || svr == SVR_LS2044A ||
238                     svr == SVR_LS2081A || svr == SVR_LS2041A)
239                         compat = "fsl,ls2088a-pcie";
240                 else
241                         compat = CONFIG_FSL_PCIE_COMPAT;
242                 if (compat)
243                         off = fdt_node_offset_by_compat_reg(blob,
244                                         compat, pcie_rc->dbi_res.start);
245 #endif
246                 if (off < 0)
247                         return;
248         }
249
250         if (pcie_rc->enabled && pcie->mode == PCI_HEADER_TYPE_BRIDGE)
251                 fdt_set_node_status(blob, off, FDT_STATUS_OKAY, 0);
252         else
253                 fdt_set_node_status(blob, off, FDT_STATUS_DISABLED, 0);
254 }
255
256 static void ft_pcie_ep_fix(void *blob, struct ls_pcie_rc *pcie_rc)
257 {
258         int off;
259         struct ls_pcie *pcie = pcie_rc->pcie;
260
261         off = fdt_node_offset_by_compat_reg(blob, CONFIG_FSL_PCIE_EP_COMPAT,
262                                             pcie_rc->dbi_res.start);
263         if (off < 0)
264                 return;
265
266         if (pcie_rc->enabled && pcie->mode == PCI_HEADER_TYPE_NORMAL)
267                 fdt_set_node_status(blob, off, FDT_STATUS_OKAY, 0);
268         else
269                 fdt_set_node_status(blob, off, FDT_STATUS_DISABLED, 0);
270 }
271
272 static void ft_pcie_ls_setup(void *blob, struct ls_pcie_rc *pcie_rc)
273 {
274         ft_pcie_ep_fix(blob, pcie_rc);
275         ft_pcie_rc_fix(blob, pcie_rc);
276 }
277
278 /* Fixup Kernel DT for PCIe */
279 void ft_pci_setup_ls(void *blob, struct bd_info *bd)
280 {
281         struct ls_pcie_rc *pcie_rc;
282
283         list_for_each_entry(pcie_rc, &ls_pcie_list, list)
284                 ft_pcie_ls_setup(blob, pcie_rc);
285
286 #if defined(CONFIG_FSL_LSCH3) || defined(CONFIG_FSL_LSCH2)
287         fdt_fixup_pcie_ls(blob);
288 #endif
289 }
290
291 #else /* !CONFIG_OF_BOARD_SETUP */
292 void ft_pci_setup_ls(void *blob, struct bd_info *bd)
293 {
294 }
295 #endif