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