1
2
3
4
5
6
7
8
9
10
11
12#include <linux/kernel.h>
13#include <linux/of.h>
14#include <linux/bug.h>
15#include <linux/io.h>
16#include <linux/slab.h>
17
18#include <asm/machdep.h>
19#include <asm/firmware.h>
20#include <asm/opal.h>
21#include <asm/prom.h>
22#include <linux/uaccess.h>
23#include <asm/debugfs.h>
24#include <asm/isa-bridge.h>
25
26static int opal_lpc_chip_id = -1;
27
28static u8 opal_lpc_inb(unsigned long port)
29{
30 int64_t rc;
31 __be32 data;
32
33 if (opal_lpc_chip_id < 0 || port > 0xffff)
34 return 0xff;
35 rc = opal_lpc_read(opal_lpc_chip_id, OPAL_LPC_IO, port, &data, 1);
36 return rc ? 0xff : be32_to_cpu(data);
37}
38
39static __le16 __opal_lpc_inw(unsigned long port)
40{
41 int64_t rc;
42 __be32 data;
43
44 if (opal_lpc_chip_id < 0 || port > 0xfffe)
45 return 0xffff;
46 if (port & 1)
47 return (__le16)opal_lpc_inb(port) << 8 | opal_lpc_inb(port + 1);
48 rc = opal_lpc_read(opal_lpc_chip_id, OPAL_LPC_IO, port, &data, 2);
49 return rc ? 0xffff : be32_to_cpu(data);
50}
51static u16 opal_lpc_inw(unsigned long port)
52{
53 return le16_to_cpu(__opal_lpc_inw(port));
54}
55
56static __le32 __opal_lpc_inl(unsigned long port)
57{
58 int64_t rc;
59 __be32 data;
60
61 if (opal_lpc_chip_id < 0 || port > 0xfffc)
62 return 0xffffffff;
63 if (port & 3)
64 return (__le32)opal_lpc_inb(port ) << 24 |
65 (__le32)opal_lpc_inb(port + 1) << 16 |
66 (__le32)opal_lpc_inb(port + 2) << 8 |
67 opal_lpc_inb(port + 3);
68 rc = opal_lpc_read(opal_lpc_chip_id, OPAL_LPC_IO, port, &data, 4);
69 return rc ? 0xffffffff : be32_to_cpu(data);
70}
71
72static u32 opal_lpc_inl(unsigned long port)
73{
74 return le32_to_cpu(__opal_lpc_inl(port));
75}
76
77static void opal_lpc_outb(u8 val, unsigned long port)
78{
79 if (opal_lpc_chip_id < 0 || port > 0xffff)
80 return;
81 opal_lpc_write(opal_lpc_chip_id, OPAL_LPC_IO, port, val, 1);
82}
83
84static void __opal_lpc_outw(__le16 val, unsigned long port)
85{
86 if (opal_lpc_chip_id < 0 || port > 0xfffe)
87 return;
88 if (port & 1) {
89 opal_lpc_outb(val >> 8, port);
90 opal_lpc_outb(val , port + 1);
91 return;
92 }
93 opal_lpc_write(opal_lpc_chip_id, OPAL_LPC_IO, port, val, 2);
94}
95
96static void opal_lpc_outw(u16 val, unsigned long port)
97{
98 __opal_lpc_outw(cpu_to_le16(val), port);
99}
100
101static void __opal_lpc_outl(__le32 val, unsigned long port)
102{
103 if (opal_lpc_chip_id < 0 || port > 0xfffc)
104 return;
105 if (port & 3) {
106 opal_lpc_outb(val >> 24, port);
107 opal_lpc_outb(val >> 16, port + 1);
108 opal_lpc_outb(val >> 8, port + 2);
109 opal_lpc_outb(val , port + 3);
110 return;
111 }
112 opal_lpc_write(opal_lpc_chip_id, OPAL_LPC_IO, port, val, 4);
113}
114
115static void opal_lpc_outl(u32 val, unsigned long port)
116{
117 __opal_lpc_outl(cpu_to_le32(val), port);
118}
119
120static void opal_lpc_insb(unsigned long p, void *b, unsigned long c)
121{
122 u8 *ptr = b;
123
124 while(c--)
125 *(ptr++) = opal_lpc_inb(p);
126}
127
128static void opal_lpc_insw(unsigned long p, void *b, unsigned long c)
129{
130 __le16 *ptr = b;
131
132 while(c--)
133 *(ptr++) = __opal_lpc_inw(p);
134}
135
136static void opal_lpc_insl(unsigned long p, void *b, unsigned long c)
137{
138 __le32 *ptr = b;
139
140 while(c--)
141 *(ptr++) = __opal_lpc_inl(p);
142}
143
144static void opal_lpc_outsb(unsigned long p, const void *b, unsigned long c)
145{
146 const u8 *ptr = b;
147
148 while(c--)
149 opal_lpc_outb(*(ptr++), p);
150}
151
152static void opal_lpc_outsw(unsigned long p, const void *b, unsigned long c)
153{
154 const __le16 *ptr = b;
155
156 while(c--)
157 __opal_lpc_outw(*(ptr++), p);
158}
159
160static void opal_lpc_outsl(unsigned long p, const void *b, unsigned long c)
161{
162 const __le32 *ptr = b;
163
164 while(c--)
165 __opal_lpc_outl(*(ptr++), p);
166}
167
168static const struct ppc_pci_io opal_lpc_io = {
169 .inb = opal_lpc_inb,
170 .inw = opal_lpc_inw,
171 .inl = opal_lpc_inl,
172 .outb = opal_lpc_outb,
173 .outw = opal_lpc_outw,
174 .outl = opal_lpc_outl,
175 .insb = opal_lpc_insb,
176 .insw = opal_lpc_insw,
177 .insl = opal_lpc_insl,
178 .outsb = opal_lpc_outsb,
179 .outsw = opal_lpc_outsw,
180 .outsl = opal_lpc_outsl,
181};
182
183#ifdef CONFIG_DEBUG_FS
184struct lpc_debugfs_entry {
185 enum OpalLPCAddressType lpc_type;
186};
187
188static ssize_t lpc_debug_read(struct file *filp, char __user *ubuf,
189 size_t count, loff_t *ppos)
190{
191 struct lpc_debugfs_entry *lpc = filp->private_data;
192 u32 data, pos, len, todo;
193 int rc;
194
195 if (!access_ok(VERIFY_WRITE, ubuf, count))
196 return -EFAULT;
197
198 todo = count;
199 while (todo) {
200 pos = *ppos;
201
202
203
204
205
206
207 len = 1;
208 if (lpc->lpc_type == OPAL_LPC_FW) {
209 if (todo > 3 && (pos & 3) == 0)
210 len = 4;
211 else if (todo > 1 && (pos & 1) == 0)
212 len = 2;
213 }
214 rc = opal_lpc_read(opal_lpc_chip_id, lpc->lpc_type, pos,
215 &data, len);
216 if (rc)
217 return -ENXIO;
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252 switch(len) {
253 case 4:
254 rc = __put_user((u32)data, (u32 __user *)ubuf);
255 break;
256 case 2:
257#ifdef __LITTLE_ENDIAN__
258 data >>= 16;
259#endif
260 rc = __put_user((u16)data, (u16 __user *)ubuf);
261 break;
262 default:
263#ifdef __LITTLE_ENDIAN__
264 data >>= 24;
265#endif
266 rc = __put_user((u8)data, (u8 __user *)ubuf);
267 break;
268 }
269 if (rc)
270 return -EFAULT;
271 *ppos += len;
272 ubuf += len;
273 todo -= len;
274 }
275
276 return count;
277}
278
279static ssize_t lpc_debug_write(struct file *filp, const char __user *ubuf,
280 size_t count, loff_t *ppos)
281{
282 struct lpc_debugfs_entry *lpc = filp->private_data;
283 u32 data, pos, len, todo;
284 int rc;
285
286 if (!access_ok(VERIFY_READ, ubuf, count))
287 return -EFAULT;
288
289 todo = count;
290 while (todo) {
291 pos = *ppos;
292
293
294
295
296
297
298 len = 1;
299 if (lpc->lpc_type == OPAL_LPC_FW) {
300 if (todo > 3 && (pos & 3) == 0)
301 len = 4;
302 else if (todo > 1 && (pos & 1) == 0)
303 len = 2;
304 }
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322 switch(len) {
323 case 4:
324 rc = __get_user(data, (u32 __user *)ubuf);
325 data = cpu_to_be32(data);
326 break;
327 case 2:
328 rc = __get_user(data, (u16 __user *)ubuf);
329 data = cpu_to_be16(data);
330 break;
331 default:
332 rc = __get_user(data, (u8 __user *)ubuf);
333 break;
334 }
335 if (rc)
336 return -EFAULT;
337
338 rc = opal_lpc_write(opal_lpc_chip_id, lpc->lpc_type, pos,
339 data, len);
340 if (rc)
341 return -ENXIO;
342 *ppos += len;
343 ubuf += len;
344 todo -= len;
345 }
346
347 return count;
348}
349
350static const struct file_operations lpc_fops = {
351 .read = lpc_debug_read,
352 .write = lpc_debug_write,
353 .open = simple_open,
354 .llseek = default_llseek,
355};
356
357static int opal_lpc_debugfs_create_type(struct dentry *folder,
358 const char *fname,
359 enum OpalLPCAddressType type)
360{
361 struct lpc_debugfs_entry *entry;
362 entry = kzalloc(sizeof(*entry), GFP_KERNEL);
363 if (!entry)
364 return -ENOMEM;
365 entry->lpc_type = type;
366 debugfs_create_file(fname, 0600, folder, entry, &lpc_fops);
367 return 0;
368}
369
370static int opal_lpc_init_debugfs(void)
371{
372 struct dentry *root;
373 int rc = 0;
374
375 if (opal_lpc_chip_id < 0)
376 return -ENODEV;
377
378 root = debugfs_create_dir("lpc", powerpc_debugfs_root);
379
380 rc |= opal_lpc_debugfs_create_type(root, "io", OPAL_LPC_IO);
381 rc |= opal_lpc_debugfs_create_type(root, "mem", OPAL_LPC_MEM);
382 rc |= opal_lpc_debugfs_create_type(root, "fw", OPAL_LPC_FW);
383 return rc;
384}
385machine_device_initcall(powernv, opal_lpc_init_debugfs);
386#endif
387
388void __init opal_lpc_init(void)
389{
390 struct device_node *np;
391
392
393
394
395
396
397 for_each_compatible_node(np, NULL, "ibm,power8-lpc") {
398 if (!of_device_is_available(np))
399 continue;
400 if (!of_get_property(np, "primary", NULL))
401 continue;
402 opal_lpc_chip_id = of_get_ibm_chip_id(np);
403 break;
404 }
405 if (opal_lpc_chip_id < 0)
406 return;
407
408
409 if (of_get_property(np, "ranges", NULL)) {
410 pr_info("OPAL: Found memory mapped LPC bus on chip %d\n",
411 opal_lpc_chip_id);
412 isa_bridge_init_non_pci(np);
413 } else {
414 pr_info("OPAL: Found non-mapped LPC bus on chip %d\n",
415 opal_lpc_chip_id);
416
417
418 ppc_pci_io = opal_lpc_io;
419 isa_io_special = true;
420 }
421}
422