1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17#include <linux/kernel.h>
18#include <linux/init.h>
19#include <linux/of_address.h>
20#include <linux/of_pci.h>
21#include <linux/pci-ecam.h>
22#include <linux/platform_device.h>
23
24#define PEM_CFG_WR 0x28
25#define PEM_CFG_RD 0x30
26
27struct thunder_pem_pci {
28 u32 ea_entry[3];
29 void __iomem *pem_reg_base;
30};
31
32static int thunder_pem_bridge_read(struct pci_bus *bus, unsigned int devfn,
33 int where, int size, u32 *val)
34{
35 u64 read_val;
36 struct pci_config_window *cfg = bus->sysdata;
37 struct thunder_pem_pci *pem_pci = (struct thunder_pem_pci *)cfg->priv;
38
39 if (devfn != 0 || where >= 2048) {
40 *val = ~0;
41 return PCIBIOS_DEVICE_NOT_FOUND;
42 }
43
44
45
46
47
48
49 read_val = where & ~3ull;
50 writeq(read_val, pem_pci->pem_reg_base + PEM_CFG_RD);
51 read_val = readq(pem_pci->pem_reg_base + PEM_CFG_RD);
52 read_val >>= 32;
53
54
55
56
57
58 switch (where & ~3) {
59 case 0x40:
60 read_val &= 0xffff00ff;
61 read_val |= 0x00007000;
62 break;
63 case 0x70:
64
65 read_val |= (2u << 25);
66 break;
67 case 0xb0:
68
69 read_val &= 0xc00000ff;
70 read_val |= 0x0003bc00;
71 break;
72 case 0xb4:
73
74 read_val = 0x00000000;
75 break;
76 case 0xb8:
77
78 read_val = 0x000f0000;
79 break;
80 case 0xbc:
81
82 read_val = 0x00010014;
83 break;
84 case 0xc0:
85
86 read_val = 0x00000000;
87 break;
88 case 0xc4:
89
90 read_val = 0x80ff0003;
91 break;
92 case 0xc8:
93 read_val = pem_pci->ea_entry[0];
94 break;
95 case 0xcc:
96 read_val = pem_pci->ea_entry[1];
97 break;
98 case 0xd0:
99 read_val = pem_pci->ea_entry[2];
100 break;
101 default:
102 break;
103 }
104 read_val >>= (8 * (where & 3));
105 switch (size) {
106 case 1:
107 read_val &= 0xff;
108 break;
109 case 2:
110 read_val &= 0xffff;
111 break;
112 default:
113 break;
114 }
115 *val = read_val;
116 return PCIBIOS_SUCCESSFUL;
117}
118
119static int thunder_pem_config_read(struct pci_bus *bus, unsigned int devfn,
120 int where, int size, u32 *val)
121{
122 struct pci_config_window *cfg = bus->sysdata;
123
124 if (bus->number < cfg->busr.start ||
125 bus->number > cfg->busr.end)
126 return PCIBIOS_DEVICE_NOT_FOUND;
127
128
129
130
131
132 if (bus->number == cfg->busr.start)
133 return thunder_pem_bridge_read(bus, devfn, where, size, val);
134
135 return pci_generic_config_read(bus, devfn, where, size, val);
136}
137
138
139
140
141
142
143static u32 thunder_pem_bridge_w1c_bits(u64 where_aligned)
144{
145 u32 w1c_bits = 0;
146
147 switch (where_aligned) {
148 case 0x04:
149 case 0x1c:
150 w1c_bits = 0xff000000;
151 break;
152 case 0x44:
153 w1c_bits = 0xfffffe00;
154 break;
155 case 0x78:
156 case 0x80:
157 case 0x88:
158 case 0x90:
159 case 0xa0:
160 w1c_bits = 0xffff0000;
161 break;
162 case 0x104:
163 case 0x110:
164 case 0x130:
165 case 0x160:
166 w1c_bits = 0xffffffff;
167 break;
168 default:
169 break;
170 }
171 return w1c_bits;
172}
173
174
175static u32 thunder_pem_bridge_w1_bits(u64 where_aligned)
176{
177 u32 w1_bits;
178
179 switch (where_aligned) {
180 case 0x1c:
181
182 w1_bits = 0x0101;
183 break;
184 case 0x24:
185
186 w1_bits = 0x00010001;
187 break;
188 default:
189 w1_bits = 0;
190 break;
191 }
192 return w1_bits;
193}
194
195static int thunder_pem_bridge_write(struct pci_bus *bus, unsigned int devfn,
196 int where, int size, u32 val)
197{
198 struct pci_config_window *cfg = bus->sysdata;
199 struct thunder_pem_pci *pem_pci = (struct thunder_pem_pci *)cfg->priv;
200 u64 write_val, read_val;
201 u64 where_aligned = where & ~3ull;
202 u32 mask = 0;
203
204
205 if (devfn != 0 || where >= 2048)
206 return PCIBIOS_DEVICE_NOT_FOUND;
207
208
209
210
211
212
213
214 switch (size) {
215 case 1:
216 writeq(where_aligned, pem_pci->pem_reg_base + PEM_CFG_RD);
217 read_val = readq(pem_pci->pem_reg_base + PEM_CFG_RD);
218 read_val >>= 32;
219 mask = ~(0xff << (8 * (where & 3)));
220 read_val &= mask;
221 val = (val & 0xff) << (8 * (where & 3));
222 val |= (u32)read_val;
223 break;
224 case 2:
225 writeq(where_aligned, pem_pci->pem_reg_base + PEM_CFG_RD);
226 read_val = readq(pem_pci->pem_reg_base + PEM_CFG_RD);
227 read_val >>= 32;
228 mask = ~(0xffff << (8 * (where & 3)));
229 read_val &= mask;
230 val = (val & 0xffff) << (8 * (where & 3));
231 val |= (u32)read_val;
232 break;
233 default:
234 break;
235 }
236
237
238
239
240
241
242
243 if (mask) {
244 u32 w1c_bits = thunder_pem_bridge_w1c_bits(where);
245
246 if (w1c_bits) {
247 mask &= w1c_bits;
248 val &= ~mask;
249 }
250 }
251
252
253
254
255
256
257 val |= thunder_pem_bridge_w1_bits(where_aligned);
258
259
260
261
262
263 write_val = (((u64)val) << 32) | where_aligned;
264 writeq(write_val, pem_pci->pem_reg_base + PEM_CFG_WR);
265 return PCIBIOS_SUCCESSFUL;
266}
267
268static int thunder_pem_config_write(struct pci_bus *bus, unsigned int devfn,
269 int where, int size, u32 val)
270{
271 struct pci_config_window *cfg = bus->sysdata;
272
273 if (bus->number < cfg->busr.start ||
274 bus->number > cfg->busr.end)
275 return PCIBIOS_DEVICE_NOT_FOUND;
276
277
278
279
280 if (bus->number == cfg->busr.start)
281 return thunder_pem_bridge_write(bus, devfn, where, size, val);
282
283
284 return pci_generic_config_write(bus, devfn, where, size, val);
285}
286
287static int thunder_pem_init(struct pci_config_window *cfg)
288{
289 struct device *dev = cfg->parent;
290 resource_size_t bar4_start;
291 struct resource *res_pem;
292 struct thunder_pem_pci *pem_pci;
293 struct platform_device *pdev;
294
295
296 if (!dev->of_node)
297 return -EINVAL;
298
299 pem_pci = devm_kzalloc(dev, sizeof(*pem_pci), GFP_KERNEL);
300 if (!pem_pci)
301 return -ENOMEM;
302
303 pdev = to_platform_device(dev);
304
305
306
307
308
309
310 res_pem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
311 if (!res_pem) {
312 dev_err(dev, "missing \"reg[1]\"property\n");
313 return -EINVAL;
314 }
315
316 pem_pci->pem_reg_base = devm_ioremap(dev, res_pem->start, 0x10000);
317 if (!pem_pci->pem_reg_base)
318 return -ENOMEM;
319
320
321
322
323
324
325
326 bar4_start = res_pem->start + 0xf00000;
327 pem_pci->ea_entry[0] = (u32)bar4_start | 2;
328 pem_pci->ea_entry[1] = (u32)(res_pem->end - bar4_start) & ~3u;
329 pem_pci->ea_entry[2] = (u32)(bar4_start >> 32);
330
331 cfg->priv = pem_pci;
332 return 0;
333}
334
335static struct pci_ecam_ops pci_thunder_pem_ops = {
336 .bus_shift = 24,
337 .init = thunder_pem_init,
338 .pci_ops = {
339 .map_bus = pci_ecam_map_bus,
340 .read = thunder_pem_config_read,
341 .write = thunder_pem_config_write,
342 }
343};
344
345static const struct of_device_id thunder_pem_of_match[] = {
346 { .compatible = "cavium,pci-host-thunder-pem" },
347 { },
348};
349
350static int thunder_pem_probe(struct platform_device *pdev)
351{
352 return pci_host_common_probe(pdev, &pci_thunder_pem_ops);
353}
354
355static struct platform_driver thunder_pem_driver = {
356 .driver = {
357 .name = KBUILD_MODNAME,
358 .of_match_table = thunder_pem_of_match,
359 },
360 .probe = thunder_pem_probe,
361};
362builtin_platform_driver(thunder_pem_driver);
363