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