13fafe9c2SBenjamin Herrenschmidt /* 23fafe9c2SBenjamin Herrenschmidt * PowerNV LPC bus handling. 33fafe9c2SBenjamin Herrenschmidt * 43fafe9c2SBenjamin Herrenschmidt * Copyright 2013 IBM Corp. 53fafe9c2SBenjamin Herrenschmidt * 63fafe9c2SBenjamin Herrenschmidt * This program is free software; you can redistribute it and/or 73fafe9c2SBenjamin Herrenschmidt * modify it under the terms of the GNU General Public License 83fafe9c2SBenjamin Herrenschmidt * as published by the Free Software Foundation; either version 93fafe9c2SBenjamin Herrenschmidt * 2 of the License, or (at your option) any later version. 103fafe9c2SBenjamin Herrenschmidt */ 113fafe9c2SBenjamin Herrenschmidt 123fafe9c2SBenjamin Herrenschmidt #include <linux/kernel.h> 133fafe9c2SBenjamin Herrenschmidt #include <linux/of.h> 143fafe9c2SBenjamin Herrenschmidt #include <linux/bug.h> 15fa2dbe2eSBenjamin Herrenschmidt #include <linux/debugfs.h> 16fa2dbe2eSBenjamin Herrenschmidt #include <linux/io.h> 17fa2dbe2eSBenjamin Herrenschmidt #include <linux/slab.h> 183fafe9c2SBenjamin Herrenschmidt 193fafe9c2SBenjamin Herrenschmidt #include <asm/machdep.h> 203fafe9c2SBenjamin Herrenschmidt #include <asm/firmware.h> 213fafe9c2SBenjamin Herrenschmidt #include <asm/xics.h> 223fafe9c2SBenjamin Herrenschmidt #include <asm/opal.h> 2326a2056eSRob Herring #include <asm/prom.h> 24fa2dbe2eSBenjamin Herrenschmidt #include <asm/uaccess.h> 250c0a3e5aSBenjamin Herrenschmidt #include <asm/debug.h> 263fafe9c2SBenjamin Herrenschmidt 273fafe9c2SBenjamin Herrenschmidt static int opal_lpc_chip_id = -1; 283fafe9c2SBenjamin Herrenschmidt 293fafe9c2SBenjamin Herrenschmidt static u8 opal_lpc_inb(unsigned long port) 303fafe9c2SBenjamin Herrenschmidt { 313fafe9c2SBenjamin Herrenschmidt int64_t rc; 32803c2d2fSBenjamin Herrenschmidt __be32 data; 333fafe9c2SBenjamin Herrenschmidt 343fafe9c2SBenjamin Herrenschmidt if (opal_lpc_chip_id < 0 || port > 0xffff) 353fafe9c2SBenjamin Herrenschmidt return 0xff; 363fafe9c2SBenjamin Herrenschmidt rc = opal_lpc_read(opal_lpc_chip_id, OPAL_LPC_IO, port, &data, 1); 37803c2d2fSBenjamin Herrenschmidt return rc ? 0xff : be32_to_cpu(data); 383fafe9c2SBenjamin Herrenschmidt } 393fafe9c2SBenjamin Herrenschmidt 403fafe9c2SBenjamin Herrenschmidt static __le16 __opal_lpc_inw(unsigned long port) 413fafe9c2SBenjamin Herrenschmidt { 423fafe9c2SBenjamin Herrenschmidt int64_t rc; 43803c2d2fSBenjamin Herrenschmidt __be32 data; 443fafe9c2SBenjamin Herrenschmidt 453fafe9c2SBenjamin Herrenschmidt if (opal_lpc_chip_id < 0 || port > 0xfffe) 463fafe9c2SBenjamin Herrenschmidt return 0xffff; 473fafe9c2SBenjamin Herrenschmidt if (port & 1) 483fafe9c2SBenjamin Herrenschmidt return (__le16)opal_lpc_inb(port) << 8 | opal_lpc_inb(port + 1); 493fafe9c2SBenjamin Herrenschmidt rc = opal_lpc_read(opal_lpc_chip_id, OPAL_LPC_IO, port, &data, 2); 50803c2d2fSBenjamin Herrenschmidt return rc ? 0xffff : be32_to_cpu(data); 513fafe9c2SBenjamin Herrenschmidt } 523fafe9c2SBenjamin Herrenschmidt static u16 opal_lpc_inw(unsigned long port) 533fafe9c2SBenjamin Herrenschmidt { 543fafe9c2SBenjamin Herrenschmidt return le16_to_cpu(__opal_lpc_inw(port)); 553fafe9c2SBenjamin Herrenschmidt } 563fafe9c2SBenjamin Herrenschmidt 573fafe9c2SBenjamin Herrenschmidt static __le32 __opal_lpc_inl(unsigned long port) 583fafe9c2SBenjamin Herrenschmidt { 593fafe9c2SBenjamin Herrenschmidt int64_t rc; 60803c2d2fSBenjamin Herrenschmidt __be32 data; 613fafe9c2SBenjamin Herrenschmidt 623fafe9c2SBenjamin Herrenschmidt if (opal_lpc_chip_id < 0 || port > 0xfffc) 633fafe9c2SBenjamin Herrenschmidt return 0xffffffff; 643fafe9c2SBenjamin Herrenschmidt if (port & 3) 653fafe9c2SBenjamin Herrenschmidt return (__le32)opal_lpc_inb(port ) << 24 | 663fafe9c2SBenjamin Herrenschmidt (__le32)opal_lpc_inb(port + 1) << 16 | 673fafe9c2SBenjamin Herrenschmidt (__le32)opal_lpc_inb(port + 2) << 8 | 683fafe9c2SBenjamin Herrenschmidt opal_lpc_inb(port + 3); 693fafe9c2SBenjamin Herrenschmidt rc = opal_lpc_read(opal_lpc_chip_id, OPAL_LPC_IO, port, &data, 4); 70803c2d2fSBenjamin Herrenschmidt return rc ? 0xffffffff : be32_to_cpu(data); 713fafe9c2SBenjamin Herrenschmidt } 723fafe9c2SBenjamin Herrenschmidt 733fafe9c2SBenjamin Herrenschmidt static u32 opal_lpc_inl(unsigned long port) 743fafe9c2SBenjamin Herrenschmidt { 753fafe9c2SBenjamin Herrenschmidt return le32_to_cpu(__opal_lpc_inl(port)); 763fafe9c2SBenjamin Herrenschmidt } 773fafe9c2SBenjamin Herrenschmidt 783fafe9c2SBenjamin Herrenschmidt static void opal_lpc_outb(u8 val, unsigned long port) 793fafe9c2SBenjamin Herrenschmidt { 803fafe9c2SBenjamin Herrenschmidt if (opal_lpc_chip_id < 0 || port > 0xffff) 813fafe9c2SBenjamin Herrenschmidt return; 823fafe9c2SBenjamin Herrenschmidt opal_lpc_write(opal_lpc_chip_id, OPAL_LPC_IO, port, val, 1); 833fafe9c2SBenjamin Herrenschmidt } 843fafe9c2SBenjamin Herrenschmidt 853fafe9c2SBenjamin Herrenschmidt static void __opal_lpc_outw(__le16 val, unsigned long port) 863fafe9c2SBenjamin Herrenschmidt { 873fafe9c2SBenjamin Herrenschmidt if (opal_lpc_chip_id < 0 || port > 0xfffe) 883fafe9c2SBenjamin Herrenschmidt return; 893fafe9c2SBenjamin Herrenschmidt if (port & 1) { 903fafe9c2SBenjamin Herrenschmidt opal_lpc_outb(val >> 8, port); 913fafe9c2SBenjamin Herrenschmidt opal_lpc_outb(val , port + 1); 923fafe9c2SBenjamin Herrenschmidt return; 933fafe9c2SBenjamin Herrenschmidt } 943fafe9c2SBenjamin Herrenschmidt opal_lpc_write(opal_lpc_chip_id, OPAL_LPC_IO, port, val, 2); 953fafe9c2SBenjamin Herrenschmidt } 963fafe9c2SBenjamin Herrenschmidt 973fafe9c2SBenjamin Herrenschmidt static void opal_lpc_outw(u16 val, unsigned long port) 983fafe9c2SBenjamin Herrenschmidt { 993fafe9c2SBenjamin Herrenschmidt __opal_lpc_outw(cpu_to_le16(val), port); 1003fafe9c2SBenjamin Herrenschmidt } 1013fafe9c2SBenjamin Herrenschmidt 1023fafe9c2SBenjamin Herrenschmidt static void __opal_lpc_outl(__le32 val, unsigned long port) 1033fafe9c2SBenjamin Herrenschmidt { 1043fafe9c2SBenjamin Herrenschmidt if (opal_lpc_chip_id < 0 || port > 0xfffc) 1053fafe9c2SBenjamin Herrenschmidt return; 1063fafe9c2SBenjamin Herrenschmidt if (port & 3) { 1073fafe9c2SBenjamin Herrenschmidt opal_lpc_outb(val >> 24, port); 1083fafe9c2SBenjamin Herrenschmidt opal_lpc_outb(val >> 16, port + 1); 1093fafe9c2SBenjamin Herrenschmidt opal_lpc_outb(val >> 8, port + 2); 1103fafe9c2SBenjamin Herrenschmidt opal_lpc_outb(val , port + 3); 1113fafe9c2SBenjamin Herrenschmidt return; 1123fafe9c2SBenjamin Herrenschmidt } 1133fafe9c2SBenjamin Herrenschmidt opal_lpc_write(opal_lpc_chip_id, OPAL_LPC_IO, port, val, 4); 1143fafe9c2SBenjamin Herrenschmidt } 1153fafe9c2SBenjamin Herrenschmidt 1163fafe9c2SBenjamin Herrenschmidt static void opal_lpc_outl(u32 val, unsigned long port) 1173fafe9c2SBenjamin Herrenschmidt { 1183fafe9c2SBenjamin Herrenschmidt __opal_lpc_outl(cpu_to_le32(val), port); 1193fafe9c2SBenjamin Herrenschmidt } 1203fafe9c2SBenjamin Herrenschmidt 1213fafe9c2SBenjamin Herrenschmidt static void opal_lpc_insb(unsigned long p, void *b, unsigned long c) 1223fafe9c2SBenjamin Herrenschmidt { 1233fafe9c2SBenjamin Herrenschmidt u8 *ptr = b; 1243fafe9c2SBenjamin Herrenschmidt 1253fafe9c2SBenjamin Herrenschmidt while(c--) 1263fafe9c2SBenjamin Herrenschmidt *(ptr++) = opal_lpc_inb(p); 1273fafe9c2SBenjamin Herrenschmidt } 1283fafe9c2SBenjamin Herrenschmidt 1293fafe9c2SBenjamin Herrenschmidt static void opal_lpc_insw(unsigned long p, void *b, unsigned long c) 1303fafe9c2SBenjamin Herrenschmidt { 1313fafe9c2SBenjamin Herrenschmidt __le16 *ptr = b; 1323fafe9c2SBenjamin Herrenschmidt 1333fafe9c2SBenjamin Herrenschmidt while(c--) 1343fafe9c2SBenjamin Herrenschmidt *(ptr++) = __opal_lpc_inw(p); 1353fafe9c2SBenjamin Herrenschmidt } 1363fafe9c2SBenjamin Herrenschmidt 1373fafe9c2SBenjamin Herrenschmidt static void opal_lpc_insl(unsigned long p, void *b, unsigned long c) 1383fafe9c2SBenjamin Herrenschmidt { 1393fafe9c2SBenjamin Herrenschmidt __le32 *ptr = b; 1403fafe9c2SBenjamin Herrenschmidt 1413fafe9c2SBenjamin Herrenschmidt while(c--) 1423fafe9c2SBenjamin Herrenschmidt *(ptr++) = __opal_lpc_inl(p); 1433fafe9c2SBenjamin Herrenschmidt } 1443fafe9c2SBenjamin Herrenschmidt 1453fafe9c2SBenjamin Herrenschmidt static void opal_lpc_outsb(unsigned long p, const void *b, unsigned long c) 1463fafe9c2SBenjamin Herrenschmidt { 1473fafe9c2SBenjamin Herrenschmidt const u8 *ptr = b; 1483fafe9c2SBenjamin Herrenschmidt 1493fafe9c2SBenjamin Herrenschmidt while(c--) 1503fafe9c2SBenjamin Herrenschmidt opal_lpc_outb(*(ptr++), p); 1513fafe9c2SBenjamin Herrenschmidt } 1523fafe9c2SBenjamin Herrenschmidt 1533fafe9c2SBenjamin Herrenschmidt static void opal_lpc_outsw(unsigned long p, const void *b, unsigned long c) 1543fafe9c2SBenjamin Herrenschmidt { 1553fafe9c2SBenjamin Herrenschmidt const __le16 *ptr = b; 1563fafe9c2SBenjamin Herrenschmidt 1573fafe9c2SBenjamin Herrenschmidt while(c--) 1583fafe9c2SBenjamin Herrenschmidt __opal_lpc_outw(*(ptr++), p); 1593fafe9c2SBenjamin Herrenschmidt } 1603fafe9c2SBenjamin Herrenschmidt 1613fafe9c2SBenjamin Herrenschmidt static void opal_lpc_outsl(unsigned long p, const void *b, unsigned long c) 1623fafe9c2SBenjamin Herrenschmidt { 1633fafe9c2SBenjamin Herrenschmidt const __le32 *ptr = b; 1643fafe9c2SBenjamin Herrenschmidt 1653fafe9c2SBenjamin Herrenschmidt while(c--) 1663fafe9c2SBenjamin Herrenschmidt __opal_lpc_outl(*(ptr++), p); 1673fafe9c2SBenjamin Herrenschmidt } 1683fafe9c2SBenjamin Herrenschmidt 1693fafe9c2SBenjamin Herrenschmidt static const struct ppc_pci_io opal_lpc_io = { 1703fafe9c2SBenjamin Herrenschmidt .inb = opal_lpc_inb, 1713fafe9c2SBenjamin Herrenschmidt .inw = opal_lpc_inw, 1723fafe9c2SBenjamin Herrenschmidt .inl = opal_lpc_inl, 1733fafe9c2SBenjamin Herrenschmidt .outb = opal_lpc_outb, 1743fafe9c2SBenjamin Herrenschmidt .outw = opal_lpc_outw, 1753fafe9c2SBenjamin Herrenschmidt .outl = opal_lpc_outl, 1763fafe9c2SBenjamin Herrenschmidt .insb = opal_lpc_insb, 1773fafe9c2SBenjamin Herrenschmidt .insw = opal_lpc_insw, 1783fafe9c2SBenjamin Herrenschmidt .insl = opal_lpc_insl, 1793fafe9c2SBenjamin Herrenschmidt .outsb = opal_lpc_outsb, 1803fafe9c2SBenjamin Herrenschmidt .outsw = opal_lpc_outsw, 1813fafe9c2SBenjamin Herrenschmidt .outsl = opal_lpc_outsl, 1823fafe9c2SBenjamin Herrenschmidt }; 1833fafe9c2SBenjamin Herrenschmidt 184fa2dbe2eSBenjamin Herrenschmidt #ifdef CONFIG_DEBUG_FS 185fa2dbe2eSBenjamin Herrenschmidt struct lpc_debugfs_entry { 186fa2dbe2eSBenjamin Herrenschmidt enum OpalLPCAddressType lpc_type; 187fa2dbe2eSBenjamin Herrenschmidt }; 188fa2dbe2eSBenjamin Herrenschmidt 189fa2dbe2eSBenjamin Herrenschmidt static ssize_t lpc_debug_read(struct file *filp, char __user *ubuf, 190fa2dbe2eSBenjamin Herrenschmidt size_t count, loff_t *ppos) 191fa2dbe2eSBenjamin Herrenschmidt { 192fa2dbe2eSBenjamin Herrenschmidt struct lpc_debugfs_entry *lpc = filp->private_data; 193fa2dbe2eSBenjamin Herrenschmidt u32 data, pos, len, todo; 194fa2dbe2eSBenjamin Herrenschmidt int rc; 195fa2dbe2eSBenjamin Herrenschmidt 196fa2dbe2eSBenjamin Herrenschmidt if (!access_ok(VERIFY_WRITE, ubuf, count)) 197fa2dbe2eSBenjamin Herrenschmidt return -EFAULT; 198fa2dbe2eSBenjamin Herrenschmidt 199fa2dbe2eSBenjamin Herrenschmidt todo = count; 200fa2dbe2eSBenjamin Herrenschmidt while (todo) { 201fa2dbe2eSBenjamin Herrenschmidt pos = *ppos; 202fa2dbe2eSBenjamin Herrenschmidt 203fa2dbe2eSBenjamin Herrenschmidt /* 204fa2dbe2eSBenjamin Herrenschmidt * Select access size based on count and alignment and 205fa2dbe2eSBenjamin Herrenschmidt * access type. IO and MEM only support byte acceses, 206fa2dbe2eSBenjamin Herrenschmidt * FW supports all 3. 207fa2dbe2eSBenjamin Herrenschmidt */ 208fa2dbe2eSBenjamin Herrenschmidt len = 1; 209fa2dbe2eSBenjamin Herrenschmidt if (lpc->lpc_type == OPAL_LPC_FW) { 210fa2dbe2eSBenjamin Herrenschmidt if (todo > 3 && (pos & 3) == 0) 211fa2dbe2eSBenjamin Herrenschmidt len = 4; 212fa2dbe2eSBenjamin Herrenschmidt else if (todo > 1 && (pos & 1) == 0) 213fa2dbe2eSBenjamin Herrenschmidt len = 2; 214fa2dbe2eSBenjamin Herrenschmidt } 215fa2dbe2eSBenjamin Herrenschmidt rc = opal_lpc_read(opal_lpc_chip_id, lpc->lpc_type, pos, 216fa2dbe2eSBenjamin Herrenschmidt &data, len); 217fa2dbe2eSBenjamin Herrenschmidt if (rc) 218fa2dbe2eSBenjamin Herrenschmidt return -ENXIO; 219fa2dbe2eSBenjamin Herrenschmidt switch(len) { 220fa2dbe2eSBenjamin Herrenschmidt case 4: 221fa2dbe2eSBenjamin Herrenschmidt rc = __put_user((u32)data, (u32 __user *)ubuf); 222fa2dbe2eSBenjamin Herrenschmidt break; 223fa2dbe2eSBenjamin Herrenschmidt case 2: 224fa2dbe2eSBenjamin Herrenschmidt rc = __put_user((u16)data, (u16 __user *)ubuf); 225fa2dbe2eSBenjamin Herrenschmidt break; 226fa2dbe2eSBenjamin Herrenschmidt default: 227fa2dbe2eSBenjamin Herrenschmidt rc = __put_user((u8)data, (u8 __user *)ubuf); 228fa2dbe2eSBenjamin Herrenschmidt break; 229fa2dbe2eSBenjamin Herrenschmidt } 230fa2dbe2eSBenjamin Herrenschmidt if (rc) 231fa2dbe2eSBenjamin Herrenschmidt return -EFAULT; 232fa2dbe2eSBenjamin Herrenschmidt *ppos += len; 233fa2dbe2eSBenjamin Herrenschmidt ubuf += len; 234fa2dbe2eSBenjamin Herrenschmidt todo -= len; 235fa2dbe2eSBenjamin Herrenschmidt } 236fa2dbe2eSBenjamin Herrenschmidt 237fa2dbe2eSBenjamin Herrenschmidt return count; 238fa2dbe2eSBenjamin Herrenschmidt } 239fa2dbe2eSBenjamin Herrenschmidt 240fa2dbe2eSBenjamin Herrenschmidt static ssize_t lpc_debug_write(struct file *filp, const char __user *ubuf, 241fa2dbe2eSBenjamin Herrenschmidt size_t count, loff_t *ppos) 242fa2dbe2eSBenjamin Herrenschmidt { 243fa2dbe2eSBenjamin Herrenschmidt struct lpc_debugfs_entry *lpc = filp->private_data; 244fa2dbe2eSBenjamin Herrenschmidt u32 data, pos, len, todo; 245fa2dbe2eSBenjamin Herrenschmidt int rc; 246fa2dbe2eSBenjamin Herrenschmidt 247fa2dbe2eSBenjamin Herrenschmidt if (!access_ok(VERIFY_READ, ubuf, count)) 248fa2dbe2eSBenjamin Herrenschmidt return -EFAULT; 249fa2dbe2eSBenjamin Herrenschmidt 250fa2dbe2eSBenjamin Herrenschmidt todo = count; 251fa2dbe2eSBenjamin Herrenschmidt while (todo) { 252fa2dbe2eSBenjamin Herrenschmidt pos = *ppos; 253fa2dbe2eSBenjamin Herrenschmidt 254fa2dbe2eSBenjamin Herrenschmidt /* 255fa2dbe2eSBenjamin Herrenschmidt * Select access size based on count and alignment and 256fa2dbe2eSBenjamin Herrenschmidt * access type. IO and MEM only support byte acceses, 257fa2dbe2eSBenjamin Herrenschmidt * FW supports all 3. 258fa2dbe2eSBenjamin Herrenschmidt */ 259fa2dbe2eSBenjamin Herrenschmidt len = 1; 260fa2dbe2eSBenjamin Herrenschmidt if (lpc->lpc_type == OPAL_LPC_FW) { 261fa2dbe2eSBenjamin Herrenschmidt if (todo > 3 && (pos & 3) == 0) 262fa2dbe2eSBenjamin Herrenschmidt len = 4; 263fa2dbe2eSBenjamin Herrenschmidt else if (todo > 1 && (pos & 1) == 0) 264fa2dbe2eSBenjamin Herrenschmidt len = 2; 265fa2dbe2eSBenjamin Herrenschmidt } 266fa2dbe2eSBenjamin Herrenschmidt switch(len) { 267fa2dbe2eSBenjamin Herrenschmidt case 4: 268fa2dbe2eSBenjamin Herrenschmidt rc = __get_user(data, (u32 __user *)ubuf); 269fa2dbe2eSBenjamin Herrenschmidt break; 270fa2dbe2eSBenjamin Herrenschmidt case 2: 271fa2dbe2eSBenjamin Herrenschmidt rc = __get_user(data, (u16 __user *)ubuf); 272fa2dbe2eSBenjamin Herrenschmidt break; 273fa2dbe2eSBenjamin Herrenschmidt default: 274fa2dbe2eSBenjamin Herrenschmidt rc = __get_user(data, (u8 __user *)ubuf); 275fa2dbe2eSBenjamin Herrenschmidt break; 276fa2dbe2eSBenjamin Herrenschmidt } 277fa2dbe2eSBenjamin Herrenschmidt if (rc) 278fa2dbe2eSBenjamin Herrenschmidt return -EFAULT; 279fa2dbe2eSBenjamin Herrenschmidt 280fa2dbe2eSBenjamin Herrenschmidt rc = opal_lpc_write(opal_lpc_chip_id, lpc->lpc_type, pos, 281fa2dbe2eSBenjamin Herrenschmidt data, len); 282fa2dbe2eSBenjamin Herrenschmidt if (rc) 283fa2dbe2eSBenjamin Herrenschmidt return -ENXIO; 284fa2dbe2eSBenjamin Herrenschmidt *ppos += len; 285fa2dbe2eSBenjamin Herrenschmidt ubuf += len; 286fa2dbe2eSBenjamin Herrenschmidt todo -= len; 287fa2dbe2eSBenjamin Herrenschmidt } 288fa2dbe2eSBenjamin Herrenschmidt 289fa2dbe2eSBenjamin Herrenschmidt return count; 290fa2dbe2eSBenjamin Herrenschmidt } 291fa2dbe2eSBenjamin Herrenschmidt 292fa2dbe2eSBenjamin Herrenschmidt static const struct file_operations lpc_fops = { 293fa2dbe2eSBenjamin Herrenschmidt .read = lpc_debug_read, 294fa2dbe2eSBenjamin Herrenschmidt .write = lpc_debug_write, 295fa2dbe2eSBenjamin Herrenschmidt .open = simple_open, 296fa2dbe2eSBenjamin Herrenschmidt .llseek = default_llseek, 297fa2dbe2eSBenjamin Herrenschmidt }; 298fa2dbe2eSBenjamin Herrenschmidt 299fa2dbe2eSBenjamin Herrenschmidt static int opal_lpc_debugfs_create_type(struct dentry *folder, 300fa2dbe2eSBenjamin Herrenschmidt const char *fname, 301fa2dbe2eSBenjamin Herrenschmidt enum OpalLPCAddressType type) 302fa2dbe2eSBenjamin Herrenschmidt { 303fa2dbe2eSBenjamin Herrenschmidt struct lpc_debugfs_entry *entry; 304fa2dbe2eSBenjamin Herrenschmidt entry = kzalloc(sizeof(*entry), GFP_KERNEL); 305fa2dbe2eSBenjamin Herrenschmidt if (!entry) 306fa2dbe2eSBenjamin Herrenschmidt return -ENOMEM; 307fa2dbe2eSBenjamin Herrenschmidt entry->lpc_type = type; 308fa2dbe2eSBenjamin Herrenschmidt debugfs_create_file(fname, 0600, folder, entry, &lpc_fops); 309fa2dbe2eSBenjamin Herrenschmidt return 0; 310fa2dbe2eSBenjamin Herrenschmidt } 311fa2dbe2eSBenjamin Herrenschmidt 312fa2dbe2eSBenjamin Herrenschmidt static int opal_lpc_init_debugfs(void) 313fa2dbe2eSBenjamin Herrenschmidt { 314fa2dbe2eSBenjamin Herrenschmidt struct dentry *root; 315fa2dbe2eSBenjamin Herrenschmidt int rc = 0; 316fa2dbe2eSBenjamin Herrenschmidt 317fa2dbe2eSBenjamin Herrenschmidt if (opal_lpc_chip_id < 0) 318fa2dbe2eSBenjamin Herrenschmidt return -ENODEV; 319fa2dbe2eSBenjamin Herrenschmidt 320fa2dbe2eSBenjamin Herrenschmidt root = debugfs_create_dir("lpc", powerpc_debugfs_root); 321fa2dbe2eSBenjamin Herrenschmidt 322fa2dbe2eSBenjamin Herrenschmidt rc |= opal_lpc_debugfs_create_type(root, "io", OPAL_LPC_IO); 323fa2dbe2eSBenjamin Herrenschmidt rc |= opal_lpc_debugfs_create_type(root, "mem", OPAL_LPC_MEM); 324fa2dbe2eSBenjamin Herrenschmidt rc |= opal_lpc_debugfs_create_type(root, "fw", OPAL_LPC_FW); 325fa2dbe2eSBenjamin Herrenschmidt return rc; 326fa2dbe2eSBenjamin Herrenschmidt } 327b14726c5SMichael Ellerman machine_device_initcall(powernv, opal_lpc_init_debugfs); 328fa2dbe2eSBenjamin Herrenschmidt #endif /* CONFIG_DEBUG_FS */ 329fa2dbe2eSBenjamin Herrenschmidt 3303fafe9c2SBenjamin Herrenschmidt void opal_lpc_init(void) 3313fafe9c2SBenjamin Herrenschmidt { 3323fafe9c2SBenjamin Herrenschmidt struct device_node *np; 3333fafe9c2SBenjamin Herrenschmidt 3343fafe9c2SBenjamin Herrenschmidt /* 3353fafe9c2SBenjamin Herrenschmidt * Look for a Power8 LPC bus tagged as "primary", 3363fafe9c2SBenjamin Herrenschmidt * we currently support only one though the OPAL APIs 3373fafe9c2SBenjamin Herrenschmidt * support any number. 3383fafe9c2SBenjamin Herrenschmidt */ 3393fafe9c2SBenjamin Herrenschmidt for_each_compatible_node(np, NULL, "ibm,power8-lpc") { 3403fafe9c2SBenjamin Herrenschmidt if (!of_device_is_available(np)) 3413fafe9c2SBenjamin Herrenschmidt continue; 3423fafe9c2SBenjamin Herrenschmidt if (!of_get_property(np, "primary", NULL)) 3433fafe9c2SBenjamin Herrenschmidt continue; 3443fafe9c2SBenjamin Herrenschmidt opal_lpc_chip_id = of_get_ibm_chip_id(np); 3453fafe9c2SBenjamin Herrenschmidt break; 3463fafe9c2SBenjamin Herrenschmidt } 3473fafe9c2SBenjamin Herrenschmidt if (opal_lpc_chip_id < 0) 3483fafe9c2SBenjamin Herrenschmidt return; 3493fafe9c2SBenjamin Herrenschmidt 3503fafe9c2SBenjamin Herrenschmidt /* Setup special IO ops */ 3513fafe9c2SBenjamin Herrenschmidt ppc_pci_io = opal_lpc_io; 3523fafe9c2SBenjamin Herrenschmidt isa_io_special = true; 3533fafe9c2SBenjamin Herrenschmidt 3543fafe9c2SBenjamin Herrenschmidt pr_info("OPAL: Power8 LPC bus found, chip ID %d\n", opal_lpc_chip_id); 3553fafe9c2SBenjamin Herrenschmidt } 356