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