1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (C) 2006 PA Semi, Inc |
4 | * |
5 | * Authors: Kip Walker, PA Semi |
6 | * Olof Johansson, PA Semi |
7 | * |
8 | * Maintained by: Olof Johansson <olof@lixom.net> |
9 | * |
10 | * Based on arch/powerpc/platforms/maple/pci.c |
11 | */ |
12 | |
13 | |
14 | #include <linux/kernel.h> |
15 | #include <linux/of_address.h> |
16 | #include <linux/pci.h> |
17 | |
18 | #include <asm/pci-bridge.h> |
19 | #include <asm/isa-bridge.h> |
20 | #include <asm/machdep.h> |
21 | |
22 | #include <asm/ppc-pci.h> |
23 | |
24 | #include "pasemi.h" |
25 | |
26 | #define PA_PXP_CFA(bus, devfn, off) (((bus) << 20) | ((devfn) << 12) | (off)) |
27 | |
28 | static inline int pa_pxp_offset_valid(u8 bus, u8 devfn, int offset) |
29 | { |
30 | /* Device 0 Function 0 is special: It's config space spans function 1 as |
31 | * well, so allow larger offset. It's really a two-function device but the |
32 | * second function does not probe. |
33 | */ |
34 | if (bus == 0 && devfn == 0) |
35 | return offset < 8192; |
36 | else |
37 | return offset < 4096; |
38 | } |
39 | |
40 | static void volatile __iomem *pa_pxp_cfg_addr(struct pci_controller *hose, |
41 | u8 bus, u8 devfn, int offset) |
42 | { |
43 | return hose->cfg_data + PA_PXP_CFA(bus, devfn, offset); |
44 | } |
45 | |
46 | static inline int is_root_port(int busno, int devfn) |
47 | { |
48 | return ((busno == 0) && (PCI_FUNC(devfn) < 4) && |
49 | ((PCI_SLOT(devfn) == 16) || (PCI_SLOT(devfn) == 17))); |
50 | } |
51 | |
52 | static inline int is_5945_reg(int reg) |
53 | { |
54 | return (((reg >= 0x18) && (reg < 0x34)) || |
55 | ((reg >= 0x158) && (reg < 0x178))); |
56 | } |
57 | |
58 | static int workaround_5945(struct pci_bus *bus, unsigned int devfn, |
59 | int offset, int len, u32 *val) |
60 | { |
61 | struct pci_controller *hose; |
62 | void volatile __iomem *addr, *dummy; |
63 | int byte; |
64 | u32 tmp; |
65 | |
66 | if (!is_root_port(busno: bus->number, devfn) || !is_5945_reg(reg: offset)) |
67 | return 0; |
68 | |
69 | hose = pci_bus_to_host(bus); |
70 | |
71 | addr = pa_pxp_cfg_addr(hose, bus: bus->number, devfn, offset: offset & ~0x3); |
72 | byte = offset & 0x3; |
73 | |
74 | /* Workaround bug 5945: write 0 to a dummy register before reading, |
75 | * and write back what we read. We must read/write the full 32-bit |
76 | * contents so we need to shift and mask by hand. |
77 | */ |
78 | dummy = pa_pxp_cfg_addr(hose, bus: bus->number, devfn, offset: 0x10); |
79 | out_le32(dummy, 0); |
80 | tmp = in_le32(addr); |
81 | out_le32(addr, tmp); |
82 | |
83 | switch (len) { |
84 | case 1: |
85 | *val = (tmp >> (8*byte)) & 0xff; |
86 | break; |
87 | case 2: |
88 | if (byte == 0) |
89 | *val = tmp & 0xffff; |
90 | else |
91 | *val = (tmp >> 16) & 0xffff; |
92 | break; |
93 | default: |
94 | *val = tmp; |
95 | break; |
96 | } |
97 | |
98 | return 1; |
99 | } |
100 | |
101 | #ifdef CONFIG_PPC_PASEMI_NEMO |
102 | #define PXP_ERR_CFG_REG 0x4 |
103 | #define PXP_IGNORE_PCIE_ERRORS 0x800 |
104 | #define SB600_BUS 5 |
105 | |
106 | static void sb600_set_flag(int bus) |
107 | { |
108 | static void __iomem *iob_mapbase = NULL; |
109 | struct resource res; |
110 | struct device_node *dn; |
111 | int err; |
112 | |
113 | if (iob_mapbase == NULL) { |
114 | dn = of_find_compatible_node(NULL, "isa" , "pasemi,1682m-iob" ); |
115 | if (!dn) { |
116 | pr_crit("NEMO SB600 missing iob node\n" ); |
117 | return; |
118 | } |
119 | |
120 | err = of_address_to_resource(dn, 0, &res); |
121 | of_node_put(dn); |
122 | |
123 | if (err) { |
124 | pr_crit("NEMO SB600 missing resource\n" ); |
125 | return; |
126 | } |
127 | |
128 | pr_info("NEMO SB600 IOB base %08llx\n" ,res.start); |
129 | |
130 | iob_mapbase = ioremap(res.start + 0x100, 0x94); |
131 | } |
132 | |
133 | if (iob_mapbase != NULL) { |
134 | if (bus == SB600_BUS) { |
135 | /* |
136 | * This is the SB600's bus, tell the PCI-e root port |
137 | * to allow non-zero devices to enumerate. |
138 | */ |
139 | out_le32(iob_mapbase + PXP_ERR_CFG_REG, in_le32(iob_mapbase + PXP_ERR_CFG_REG) | PXP_IGNORE_PCIE_ERRORS); |
140 | } else { |
141 | /* |
142 | * Only scan device 0 on other busses |
143 | */ |
144 | out_le32(iob_mapbase + PXP_ERR_CFG_REG, in_le32(iob_mapbase + PXP_ERR_CFG_REG) & ~PXP_IGNORE_PCIE_ERRORS); |
145 | } |
146 | } |
147 | } |
148 | |
149 | #else |
150 | |
151 | static void sb600_set_flag(int bus) |
152 | { |
153 | } |
154 | #endif |
155 | |
156 | static int pa_pxp_read_config(struct pci_bus *bus, unsigned int devfn, |
157 | int offset, int len, u32 *val) |
158 | { |
159 | struct pci_controller *hose; |
160 | void volatile __iomem *addr; |
161 | |
162 | hose = pci_bus_to_host(bus); |
163 | if (!hose) |
164 | return PCIBIOS_DEVICE_NOT_FOUND; |
165 | |
166 | if (!pa_pxp_offset_valid(bus: bus->number, devfn, offset)) |
167 | return PCIBIOS_BAD_REGISTER_NUMBER; |
168 | |
169 | if (workaround_5945(bus, devfn, offset, len, val)) |
170 | return PCIBIOS_SUCCESSFUL; |
171 | |
172 | addr = pa_pxp_cfg_addr(hose, bus: bus->number, devfn, offset); |
173 | |
174 | sb600_set_flag(bus: bus->number); |
175 | |
176 | /* |
177 | * Note: the caller has already checked that offset is |
178 | * suitably aligned and that len is 1, 2 or 4. |
179 | */ |
180 | switch (len) { |
181 | case 1: |
182 | *val = in_8(addr); |
183 | break; |
184 | case 2: |
185 | *val = in_le16(addr); |
186 | break; |
187 | default: |
188 | *val = in_le32(addr); |
189 | break; |
190 | } |
191 | |
192 | return PCIBIOS_SUCCESSFUL; |
193 | } |
194 | |
195 | static int pa_pxp_write_config(struct pci_bus *bus, unsigned int devfn, |
196 | int offset, int len, u32 val) |
197 | { |
198 | struct pci_controller *hose; |
199 | void volatile __iomem *addr; |
200 | |
201 | hose = pci_bus_to_host(bus); |
202 | if (!hose) |
203 | return PCIBIOS_DEVICE_NOT_FOUND; |
204 | |
205 | if (!pa_pxp_offset_valid(bus: bus->number, devfn, offset)) |
206 | return PCIBIOS_BAD_REGISTER_NUMBER; |
207 | |
208 | addr = pa_pxp_cfg_addr(hose, bus: bus->number, devfn, offset); |
209 | |
210 | sb600_set_flag(bus: bus->number); |
211 | |
212 | /* |
213 | * Note: the caller has already checked that offset is |
214 | * suitably aligned and that len is 1, 2 or 4. |
215 | */ |
216 | switch (len) { |
217 | case 1: |
218 | out_8(addr, val); |
219 | break; |
220 | case 2: |
221 | out_le16(addr, val); |
222 | break; |
223 | default: |
224 | out_le32(addr, val); |
225 | break; |
226 | } |
227 | return PCIBIOS_SUCCESSFUL; |
228 | } |
229 | |
230 | static struct pci_ops pa_pxp_ops = { |
231 | .read = pa_pxp_read_config, |
232 | .write = pa_pxp_write_config, |
233 | }; |
234 | |
235 | static void __init setup_pa_pxp(struct pci_controller *hose) |
236 | { |
237 | hose->ops = &pa_pxp_ops; |
238 | hose->cfg_data = ioremap(offset: 0xe0000000, size: 0x10000000); |
239 | } |
240 | |
241 | static int __init pas_add_bridge(struct device_node *dev) |
242 | { |
243 | struct pci_controller *hose; |
244 | |
245 | pr_debug("Adding PCI host bridge %pOF\n" , dev); |
246 | |
247 | hose = pcibios_alloc_controller(dev); |
248 | if (!hose) |
249 | return -ENOMEM; |
250 | |
251 | hose->first_busno = 0; |
252 | hose->last_busno = 0xff; |
253 | hose->controller_ops = pasemi_pci_controller_ops; |
254 | |
255 | setup_pa_pxp(hose); |
256 | |
257 | pr_info("Found PA-PXP PCI host bridge.\n" ); |
258 | |
259 | /* Interpret the "ranges" property */ |
260 | pci_process_bridge_OF_ranges(hose, dev, 1); |
261 | |
262 | /* |
263 | * Scan for an isa bridge. This is needed to find the SB600 on the nemo |
264 | * and does nothing on machines without one. |
265 | */ |
266 | isa_bridge_find_early(hose); |
267 | |
268 | return 0; |
269 | } |
270 | |
271 | void __init pas_pci_init(void) |
272 | { |
273 | struct device_node *root = of_find_node_by_path(path: "/" ); |
274 | struct device_node *np; |
275 | int res; |
276 | |
277 | pci_set_flags(flags: PCI_SCAN_ALL_PCIE_DEVS); |
278 | |
279 | np = of_find_compatible_node(from: root, NULL, compat: "pasemi,rootbus" ); |
280 | if (np) { |
281 | res = pas_add_bridge(dev: np); |
282 | of_node_put(node: np); |
283 | } |
284 | of_node_put(node: root); |
285 | } |
286 | |
287 | void __iomem *__init pasemi_pci_getcfgaddr(struct pci_dev *dev, int offset) |
288 | { |
289 | struct pci_controller *hose; |
290 | |
291 | hose = pci_bus_to_host(dev->bus); |
292 | |
293 | return (void __iomem *)pa_pxp_cfg_addr(hose, bus: dev->bus->number, devfn: dev->devfn, offset); |
294 | } |
295 | |
296 | struct pci_controller_ops pasemi_pci_controller_ops; |
297 | |