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