xref: /OK3568_Linux_fs/u-boot/drivers/pci/pcie_layerscape_fixup.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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