12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 23fafe9c2SBenjamin Herrenschmidt /* 33fafe9c2SBenjamin Herrenschmidt * PowerNV LPC bus handling. 43fafe9c2SBenjamin Herrenschmidt * 53fafe9c2SBenjamin Herrenschmidt * Copyright 2013 IBM Corp. 63fafe9c2SBenjamin Herrenschmidt */ 73fafe9c2SBenjamin Herrenschmidt 83fafe9c2SBenjamin Herrenschmidt #include <linux/kernel.h> 93fafe9c2SBenjamin Herrenschmidt #include <linux/of.h> 103fafe9c2SBenjamin Herrenschmidt #include <linux/bug.h> 11fa2dbe2eSBenjamin Herrenschmidt #include <linux/io.h> 12fa2dbe2eSBenjamin Herrenschmidt #include <linux/slab.h> 13*dbf77fedSAneesh Kumar K.V #include <linux/debugfs.h> 143fafe9c2SBenjamin Herrenschmidt 153fafe9c2SBenjamin Herrenschmidt #include <asm/machdep.h> 163fafe9c2SBenjamin Herrenschmidt #include <asm/firmware.h> 173fafe9c2SBenjamin Herrenschmidt #include <asm/opal.h> 1826a2056eSRob Herring #include <asm/prom.h> 197c0f6ba6SLinus Torvalds #include <linux/uaccess.h> 2038e9d36bSBenjamin Herrenschmidt #include <asm/isa-bridge.h> 213fafe9c2SBenjamin Herrenschmidt 223fafe9c2SBenjamin Herrenschmidt static int opal_lpc_chip_id = -1; 233fafe9c2SBenjamin Herrenschmidt 243fafe9c2SBenjamin Herrenschmidt static u8 opal_lpc_inb(unsigned long port) 253fafe9c2SBenjamin Herrenschmidt { 263fafe9c2SBenjamin Herrenschmidt int64_t rc; 27803c2d2fSBenjamin Herrenschmidt __be32 data; 283fafe9c2SBenjamin Herrenschmidt 293fafe9c2SBenjamin Herrenschmidt if (opal_lpc_chip_id < 0 || port > 0xffff) 303fafe9c2SBenjamin Herrenschmidt return 0xff; 313fafe9c2SBenjamin Herrenschmidt rc = opal_lpc_read(opal_lpc_chip_id, OPAL_LPC_IO, port, &data, 1); 32803c2d2fSBenjamin Herrenschmidt return rc ? 0xff : be32_to_cpu(data); 333fafe9c2SBenjamin Herrenschmidt } 343fafe9c2SBenjamin Herrenschmidt 353fafe9c2SBenjamin Herrenschmidt static __le16 __opal_lpc_inw(unsigned long port) 363fafe9c2SBenjamin Herrenschmidt { 373fafe9c2SBenjamin Herrenschmidt int64_t rc; 38803c2d2fSBenjamin Herrenschmidt __be32 data; 393fafe9c2SBenjamin Herrenschmidt 403fafe9c2SBenjamin Herrenschmidt if (opal_lpc_chip_id < 0 || port > 0xfffe) 413fafe9c2SBenjamin Herrenschmidt return 0xffff; 423fafe9c2SBenjamin Herrenschmidt if (port & 1) 433fafe9c2SBenjamin Herrenschmidt return (__le16)opal_lpc_inb(port) << 8 | opal_lpc_inb(port + 1); 443fafe9c2SBenjamin Herrenschmidt rc = opal_lpc_read(opal_lpc_chip_id, OPAL_LPC_IO, port, &data, 2); 45803c2d2fSBenjamin Herrenschmidt return rc ? 0xffff : be32_to_cpu(data); 463fafe9c2SBenjamin Herrenschmidt } 473fafe9c2SBenjamin Herrenschmidt static u16 opal_lpc_inw(unsigned long port) 483fafe9c2SBenjamin Herrenschmidt { 493fafe9c2SBenjamin Herrenschmidt return le16_to_cpu(__opal_lpc_inw(port)); 503fafe9c2SBenjamin Herrenschmidt } 513fafe9c2SBenjamin Herrenschmidt 523fafe9c2SBenjamin Herrenschmidt static __le32 __opal_lpc_inl(unsigned long port) 533fafe9c2SBenjamin Herrenschmidt { 543fafe9c2SBenjamin Herrenschmidt int64_t rc; 55803c2d2fSBenjamin Herrenschmidt __be32 data; 563fafe9c2SBenjamin Herrenschmidt 573fafe9c2SBenjamin Herrenschmidt if (opal_lpc_chip_id < 0 || port > 0xfffc) 583fafe9c2SBenjamin Herrenschmidt return 0xffffffff; 593fafe9c2SBenjamin Herrenschmidt if (port & 3) 603fafe9c2SBenjamin Herrenschmidt return (__le32)opal_lpc_inb(port ) << 24 | 613fafe9c2SBenjamin Herrenschmidt (__le32)opal_lpc_inb(port + 1) << 16 | 623fafe9c2SBenjamin Herrenschmidt (__le32)opal_lpc_inb(port + 2) << 8 | 633fafe9c2SBenjamin Herrenschmidt opal_lpc_inb(port + 3); 643fafe9c2SBenjamin Herrenschmidt rc = opal_lpc_read(opal_lpc_chip_id, OPAL_LPC_IO, port, &data, 4); 65803c2d2fSBenjamin Herrenschmidt return rc ? 0xffffffff : be32_to_cpu(data); 663fafe9c2SBenjamin Herrenschmidt } 673fafe9c2SBenjamin Herrenschmidt 683fafe9c2SBenjamin Herrenschmidt static u32 opal_lpc_inl(unsigned long port) 693fafe9c2SBenjamin Herrenschmidt { 703fafe9c2SBenjamin Herrenschmidt return le32_to_cpu(__opal_lpc_inl(port)); 713fafe9c2SBenjamin Herrenschmidt } 723fafe9c2SBenjamin Herrenschmidt 733fafe9c2SBenjamin Herrenschmidt static void opal_lpc_outb(u8 val, unsigned long port) 743fafe9c2SBenjamin Herrenschmidt { 753fafe9c2SBenjamin Herrenschmidt if (opal_lpc_chip_id < 0 || port > 0xffff) 763fafe9c2SBenjamin Herrenschmidt return; 773fafe9c2SBenjamin Herrenschmidt opal_lpc_write(opal_lpc_chip_id, OPAL_LPC_IO, port, val, 1); 783fafe9c2SBenjamin Herrenschmidt } 793fafe9c2SBenjamin Herrenschmidt 803fafe9c2SBenjamin Herrenschmidt static void __opal_lpc_outw(__le16 val, unsigned long port) 813fafe9c2SBenjamin Herrenschmidt { 823fafe9c2SBenjamin Herrenschmidt if (opal_lpc_chip_id < 0 || port > 0xfffe) 833fafe9c2SBenjamin Herrenschmidt return; 843fafe9c2SBenjamin Herrenschmidt if (port & 1) { 853fafe9c2SBenjamin Herrenschmidt opal_lpc_outb(val >> 8, port); 863fafe9c2SBenjamin Herrenschmidt opal_lpc_outb(val , port + 1); 873fafe9c2SBenjamin Herrenschmidt return; 883fafe9c2SBenjamin Herrenschmidt } 893fafe9c2SBenjamin Herrenschmidt opal_lpc_write(opal_lpc_chip_id, OPAL_LPC_IO, port, val, 2); 903fafe9c2SBenjamin Herrenschmidt } 913fafe9c2SBenjamin Herrenschmidt 923fafe9c2SBenjamin Herrenschmidt static void opal_lpc_outw(u16 val, unsigned long port) 933fafe9c2SBenjamin Herrenschmidt { 943fafe9c2SBenjamin Herrenschmidt __opal_lpc_outw(cpu_to_le16(val), port); 953fafe9c2SBenjamin Herrenschmidt } 963fafe9c2SBenjamin Herrenschmidt 973fafe9c2SBenjamin Herrenschmidt static void __opal_lpc_outl(__le32 val, unsigned long port) 983fafe9c2SBenjamin Herrenschmidt { 993fafe9c2SBenjamin Herrenschmidt if (opal_lpc_chip_id < 0 || port > 0xfffc) 1003fafe9c2SBenjamin Herrenschmidt return; 1013fafe9c2SBenjamin Herrenschmidt if (port & 3) { 1023fafe9c2SBenjamin Herrenschmidt opal_lpc_outb(val >> 24, port); 1033fafe9c2SBenjamin Herrenschmidt opal_lpc_outb(val >> 16, port + 1); 1043fafe9c2SBenjamin Herrenschmidt opal_lpc_outb(val >> 8, port + 2); 1053fafe9c2SBenjamin Herrenschmidt opal_lpc_outb(val , port + 3); 1063fafe9c2SBenjamin Herrenschmidt return; 1073fafe9c2SBenjamin Herrenschmidt } 1083fafe9c2SBenjamin Herrenschmidt opal_lpc_write(opal_lpc_chip_id, OPAL_LPC_IO, port, val, 4); 1093fafe9c2SBenjamin Herrenschmidt } 1103fafe9c2SBenjamin Herrenschmidt 1113fafe9c2SBenjamin Herrenschmidt static void opal_lpc_outl(u32 val, unsigned long port) 1123fafe9c2SBenjamin Herrenschmidt { 1133fafe9c2SBenjamin Herrenschmidt __opal_lpc_outl(cpu_to_le32(val), port); 1143fafe9c2SBenjamin Herrenschmidt } 1153fafe9c2SBenjamin Herrenschmidt 1163fafe9c2SBenjamin Herrenschmidt static void opal_lpc_insb(unsigned long p, void *b, unsigned long c) 1173fafe9c2SBenjamin Herrenschmidt { 1183fafe9c2SBenjamin Herrenschmidt u8 *ptr = b; 1193fafe9c2SBenjamin Herrenschmidt 1203fafe9c2SBenjamin Herrenschmidt while(c--) 1213fafe9c2SBenjamin Herrenschmidt *(ptr++) = opal_lpc_inb(p); 1223fafe9c2SBenjamin Herrenschmidt } 1233fafe9c2SBenjamin Herrenschmidt 1243fafe9c2SBenjamin Herrenschmidt static void opal_lpc_insw(unsigned long p, void *b, unsigned long c) 1253fafe9c2SBenjamin Herrenschmidt { 1263fafe9c2SBenjamin Herrenschmidt __le16 *ptr = b; 1273fafe9c2SBenjamin Herrenschmidt 1283fafe9c2SBenjamin Herrenschmidt while(c--) 1293fafe9c2SBenjamin Herrenschmidt *(ptr++) = __opal_lpc_inw(p); 1303fafe9c2SBenjamin Herrenschmidt } 1313fafe9c2SBenjamin Herrenschmidt 1323fafe9c2SBenjamin Herrenschmidt static void opal_lpc_insl(unsigned long p, void *b, unsigned long c) 1333fafe9c2SBenjamin Herrenschmidt { 1343fafe9c2SBenjamin Herrenschmidt __le32 *ptr = b; 1353fafe9c2SBenjamin Herrenschmidt 1363fafe9c2SBenjamin Herrenschmidt while(c--) 1373fafe9c2SBenjamin Herrenschmidt *(ptr++) = __opal_lpc_inl(p); 1383fafe9c2SBenjamin Herrenschmidt } 1393fafe9c2SBenjamin Herrenschmidt 1403fafe9c2SBenjamin Herrenschmidt static void opal_lpc_outsb(unsigned long p, const void *b, unsigned long c) 1413fafe9c2SBenjamin Herrenschmidt { 1423fafe9c2SBenjamin Herrenschmidt const u8 *ptr = b; 1433fafe9c2SBenjamin Herrenschmidt 1443fafe9c2SBenjamin Herrenschmidt while(c--) 1453fafe9c2SBenjamin Herrenschmidt opal_lpc_outb(*(ptr++), p); 1463fafe9c2SBenjamin Herrenschmidt } 1473fafe9c2SBenjamin Herrenschmidt 1483fafe9c2SBenjamin Herrenschmidt static void opal_lpc_outsw(unsigned long p, const void *b, unsigned long c) 1493fafe9c2SBenjamin Herrenschmidt { 1503fafe9c2SBenjamin Herrenschmidt const __le16 *ptr = b; 1513fafe9c2SBenjamin Herrenschmidt 1523fafe9c2SBenjamin Herrenschmidt while(c--) 1533fafe9c2SBenjamin Herrenschmidt __opal_lpc_outw(*(ptr++), p); 1543fafe9c2SBenjamin Herrenschmidt } 1553fafe9c2SBenjamin Herrenschmidt 1563fafe9c2SBenjamin Herrenschmidt static void opal_lpc_outsl(unsigned long p, const void *b, unsigned long c) 1573fafe9c2SBenjamin Herrenschmidt { 1583fafe9c2SBenjamin Herrenschmidt const __le32 *ptr = b; 1593fafe9c2SBenjamin Herrenschmidt 1603fafe9c2SBenjamin Herrenschmidt while(c--) 1613fafe9c2SBenjamin Herrenschmidt __opal_lpc_outl(*(ptr++), p); 1623fafe9c2SBenjamin Herrenschmidt } 1633fafe9c2SBenjamin Herrenschmidt 1643fafe9c2SBenjamin Herrenschmidt static const struct ppc_pci_io opal_lpc_io = { 1653fafe9c2SBenjamin Herrenschmidt .inb = opal_lpc_inb, 1663fafe9c2SBenjamin Herrenschmidt .inw = opal_lpc_inw, 1673fafe9c2SBenjamin Herrenschmidt .inl = opal_lpc_inl, 1683fafe9c2SBenjamin Herrenschmidt .outb = opal_lpc_outb, 1693fafe9c2SBenjamin Herrenschmidt .outw = opal_lpc_outw, 1703fafe9c2SBenjamin Herrenschmidt .outl = opal_lpc_outl, 1713fafe9c2SBenjamin Herrenschmidt .insb = opal_lpc_insb, 1723fafe9c2SBenjamin Herrenschmidt .insw = opal_lpc_insw, 1733fafe9c2SBenjamin Herrenschmidt .insl = opal_lpc_insl, 1743fafe9c2SBenjamin Herrenschmidt .outsb = opal_lpc_outsb, 1753fafe9c2SBenjamin Herrenschmidt .outsw = opal_lpc_outsw, 1763fafe9c2SBenjamin Herrenschmidt .outsl = opal_lpc_outsl, 1773fafe9c2SBenjamin Herrenschmidt }; 1783fafe9c2SBenjamin Herrenschmidt 179fa2dbe2eSBenjamin Herrenschmidt #ifdef CONFIG_DEBUG_FS 180fa2dbe2eSBenjamin Herrenschmidt struct lpc_debugfs_entry { 181fa2dbe2eSBenjamin Herrenschmidt enum OpalLPCAddressType lpc_type; 182fa2dbe2eSBenjamin Herrenschmidt }; 183fa2dbe2eSBenjamin Herrenschmidt 184fa2dbe2eSBenjamin Herrenschmidt static ssize_t lpc_debug_read(struct file *filp, char __user *ubuf, 185fa2dbe2eSBenjamin Herrenschmidt size_t count, loff_t *ppos) 186fa2dbe2eSBenjamin Herrenschmidt { 187fa2dbe2eSBenjamin Herrenschmidt struct lpc_debugfs_entry *lpc = filp->private_data; 188fa2dbe2eSBenjamin Herrenschmidt u32 data, pos, len, todo; 189fa2dbe2eSBenjamin Herrenschmidt int rc; 190fa2dbe2eSBenjamin Herrenschmidt 19196d4f267SLinus Torvalds if (!access_ok(ubuf, count)) 192fa2dbe2eSBenjamin Herrenschmidt return -EFAULT; 193fa2dbe2eSBenjamin Herrenschmidt 194fa2dbe2eSBenjamin Herrenschmidt todo = count; 195fa2dbe2eSBenjamin Herrenschmidt while (todo) { 196fa2dbe2eSBenjamin Herrenschmidt pos = *ppos; 197fa2dbe2eSBenjamin Herrenschmidt 198fa2dbe2eSBenjamin Herrenschmidt /* 199fa2dbe2eSBenjamin Herrenschmidt * Select access size based on count and alignment and 200fa2dbe2eSBenjamin Herrenschmidt * access type. IO and MEM only support byte acceses, 201fa2dbe2eSBenjamin Herrenschmidt * FW supports all 3. 202fa2dbe2eSBenjamin Herrenschmidt */ 203fa2dbe2eSBenjamin Herrenschmidt len = 1; 204fa2dbe2eSBenjamin Herrenschmidt if (lpc->lpc_type == OPAL_LPC_FW) { 205fa2dbe2eSBenjamin Herrenschmidt if (todo > 3 && (pos & 3) == 0) 206fa2dbe2eSBenjamin Herrenschmidt len = 4; 207fa2dbe2eSBenjamin Herrenschmidt else if (todo > 1 && (pos & 1) == 0) 208fa2dbe2eSBenjamin Herrenschmidt len = 2; 209fa2dbe2eSBenjamin Herrenschmidt } 210fa2dbe2eSBenjamin Herrenschmidt rc = opal_lpc_read(opal_lpc_chip_id, lpc->lpc_type, pos, 211bf19edd2SMichael Ellerman &data, len); 212fa2dbe2eSBenjamin Herrenschmidt if (rc) 213fa2dbe2eSBenjamin Herrenschmidt return -ENXIO; 214325e4114SBenjamin Herrenschmidt 215325e4114SBenjamin Herrenschmidt /* 216325e4114SBenjamin Herrenschmidt * Now there is some trickery with the data returned by OPAL 217325e4114SBenjamin Herrenschmidt * as it's the desired data right justified in a 32-bit BE 218325e4114SBenjamin Herrenschmidt * word. 219325e4114SBenjamin Herrenschmidt * 220325e4114SBenjamin Herrenschmidt * This is a very bad interface and I'm to blame for it :-( 221325e4114SBenjamin Herrenschmidt * 222325e4114SBenjamin Herrenschmidt * So we can't just apply a 32-bit swap to what comes from OPAL, 223325e4114SBenjamin Herrenschmidt * because user space expects the *bytes* to be in their proper 224325e4114SBenjamin Herrenschmidt * respective positions (ie, LPC position). 225325e4114SBenjamin Herrenschmidt * 226325e4114SBenjamin Herrenschmidt * So what we really want to do here is to shift data right 227325e4114SBenjamin Herrenschmidt * appropriately on a LE kernel. 228325e4114SBenjamin Herrenschmidt * 229325e4114SBenjamin Herrenschmidt * IE. If the LPC transaction has bytes B0, B1, B2 and B3 in that 230325e4114SBenjamin Herrenschmidt * order, we have in memory written to by OPAL at the "data" 231325e4114SBenjamin Herrenschmidt * pointer: 232325e4114SBenjamin Herrenschmidt * 233325e4114SBenjamin Herrenschmidt * Bytes: OPAL "data" LE "data" 234325e4114SBenjamin Herrenschmidt * 32-bit: B0 B1 B2 B3 B0B1B2B3 B3B2B1B0 235325e4114SBenjamin Herrenschmidt * 16-bit: B0 B1 0000B0B1 B1B00000 236325e4114SBenjamin Herrenschmidt * 8-bit: B0 000000B0 B0000000 237325e4114SBenjamin Herrenschmidt * 238325e4114SBenjamin Herrenschmidt * So a BE kernel will have the leftmost of the above in the MSB 239325e4114SBenjamin Herrenschmidt * and rightmost in the LSB and can just then "cast" the u32 "data" 240325e4114SBenjamin Herrenschmidt * down to the appropriate quantity and write it. 241325e4114SBenjamin Herrenschmidt * 242325e4114SBenjamin Herrenschmidt * However, an LE kernel can't. It doesn't need to swap because a 243325e4114SBenjamin Herrenschmidt * load from data followed by a store to user are going to preserve 244325e4114SBenjamin Herrenschmidt * the byte ordering which is the wire byte order which is what the 245325e4114SBenjamin Herrenschmidt * user wants, but in order to "crop" to the right size, we need to 246325e4114SBenjamin Herrenschmidt * shift right first. 247325e4114SBenjamin Herrenschmidt */ 248fa2dbe2eSBenjamin Herrenschmidt switch(len) { 249fa2dbe2eSBenjamin Herrenschmidt case 4: 250fa2dbe2eSBenjamin Herrenschmidt rc = __put_user((u32)data, (u32 __user *)ubuf); 251fa2dbe2eSBenjamin Herrenschmidt break; 252fa2dbe2eSBenjamin Herrenschmidt case 2: 253325e4114SBenjamin Herrenschmidt #ifdef __LITTLE_ENDIAN__ 254325e4114SBenjamin Herrenschmidt data >>= 16; 255325e4114SBenjamin Herrenschmidt #endif 256fa2dbe2eSBenjamin Herrenschmidt rc = __put_user((u16)data, (u16 __user *)ubuf); 257fa2dbe2eSBenjamin Herrenschmidt break; 258fa2dbe2eSBenjamin Herrenschmidt default: 259325e4114SBenjamin Herrenschmidt #ifdef __LITTLE_ENDIAN__ 260325e4114SBenjamin Herrenschmidt data >>= 24; 261325e4114SBenjamin Herrenschmidt #endif 262fa2dbe2eSBenjamin Herrenschmidt rc = __put_user((u8)data, (u8 __user *)ubuf); 263fa2dbe2eSBenjamin Herrenschmidt break; 264fa2dbe2eSBenjamin Herrenschmidt } 265fa2dbe2eSBenjamin Herrenschmidt if (rc) 266fa2dbe2eSBenjamin Herrenschmidt return -EFAULT; 267fa2dbe2eSBenjamin Herrenschmidt *ppos += len; 268fa2dbe2eSBenjamin Herrenschmidt ubuf += len; 269fa2dbe2eSBenjamin Herrenschmidt todo -= len; 270fa2dbe2eSBenjamin Herrenschmidt } 271fa2dbe2eSBenjamin Herrenschmidt 272fa2dbe2eSBenjamin Herrenschmidt return count; 273fa2dbe2eSBenjamin Herrenschmidt } 274fa2dbe2eSBenjamin Herrenschmidt 275fa2dbe2eSBenjamin Herrenschmidt static ssize_t lpc_debug_write(struct file *filp, const char __user *ubuf, 276fa2dbe2eSBenjamin Herrenschmidt size_t count, loff_t *ppos) 277fa2dbe2eSBenjamin Herrenschmidt { 278fa2dbe2eSBenjamin Herrenschmidt struct lpc_debugfs_entry *lpc = filp->private_data; 279fa2dbe2eSBenjamin Herrenschmidt u32 data, pos, len, todo; 280fa2dbe2eSBenjamin Herrenschmidt int rc; 281fa2dbe2eSBenjamin Herrenschmidt 28296d4f267SLinus Torvalds if (!access_ok(ubuf, count)) 283fa2dbe2eSBenjamin Herrenschmidt return -EFAULT; 284fa2dbe2eSBenjamin Herrenschmidt 285fa2dbe2eSBenjamin Herrenschmidt todo = count; 286fa2dbe2eSBenjamin Herrenschmidt while (todo) { 287fa2dbe2eSBenjamin Herrenschmidt pos = *ppos; 288fa2dbe2eSBenjamin Herrenschmidt 289fa2dbe2eSBenjamin Herrenschmidt /* 290fa2dbe2eSBenjamin Herrenschmidt * Select access size based on count and alignment and 291fa2dbe2eSBenjamin Herrenschmidt * access type. IO and MEM only support byte acceses, 292fa2dbe2eSBenjamin Herrenschmidt * FW supports all 3. 293fa2dbe2eSBenjamin Herrenschmidt */ 294fa2dbe2eSBenjamin Herrenschmidt len = 1; 295fa2dbe2eSBenjamin Herrenschmidt if (lpc->lpc_type == OPAL_LPC_FW) { 296fa2dbe2eSBenjamin Herrenschmidt if (todo > 3 && (pos & 3) == 0) 297fa2dbe2eSBenjamin Herrenschmidt len = 4; 298fa2dbe2eSBenjamin Herrenschmidt else if (todo > 1 && (pos & 1) == 0) 299fa2dbe2eSBenjamin Herrenschmidt len = 2; 300fa2dbe2eSBenjamin Herrenschmidt } 301325e4114SBenjamin Herrenschmidt 302325e4114SBenjamin Herrenschmidt /* 303325e4114SBenjamin Herrenschmidt * Similarly to the read case, we have some trickery here but 304325e4114SBenjamin Herrenschmidt * it's different to handle. We need to pass the value to OPAL in 305325e4114SBenjamin Herrenschmidt * a register whose layout depends on the access size. We want 306325e4114SBenjamin Herrenschmidt * to reproduce the memory layout of the user, however we aren't 307325e4114SBenjamin Herrenschmidt * doing a load from user and a store to another memory location 308325e4114SBenjamin Herrenschmidt * which would achieve that. Here we pass the value to OPAL via 309325e4114SBenjamin Herrenschmidt * a register which is expected to contain the "BE" interpretation 310325e4114SBenjamin Herrenschmidt * of the byte sequence. IE: for a 32-bit access, byte 0 should be 311325e4114SBenjamin Herrenschmidt * in the MSB. So here we *do* need to byteswap on LE. 312325e4114SBenjamin Herrenschmidt * 313325e4114SBenjamin Herrenschmidt * User bytes: LE "data" OPAL "data" 314325e4114SBenjamin Herrenschmidt * 32-bit: B0 B1 B2 B3 B3B2B1B0 B0B1B2B3 315325e4114SBenjamin Herrenschmidt * 16-bit: B0 B1 0000B1B0 0000B0B1 316325e4114SBenjamin Herrenschmidt * 8-bit: B0 000000B0 000000B0 317325e4114SBenjamin Herrenschmidt */ 318fa2dbe2eSBenjamin Herrenschmidt switch(len) { 319fa2dbe2eSBenjamin Herrenschmidt case 4: 320fa2dbe2eSBenjamin Herrenschmidt rc = __get_user(data, (u32 __user *)ubuf); 321325e4114SBenjamin Herrenschmidt data = cpu_to_be32(data); 322fa2dbe2eSBenjamin Herrenschmidt break; 323fa2dbe2eSBenjamin Herrenschmidt case 2: 324fa2dbe2eSBenjamin Herrenschmidt rc = __get_user(data, (u16 __user *)ubuf); 325325e4114SBenjamin Herrenschmidt data = cpu_to_be16(data); 326fa2dbe2eSBenjamin Herrenschmidt break; 327fa2dbe2eSBenjamin Herrenschmidt default: 328fa2dbe2eSBenjamin Herrenschmidt rc = __get_user(data, (u8 __user *)ubuf); 329fa2dbe2eSBenjamin Herrenschmidt break; 330fa2dbe2eSBenjamin Herrenschmidt } 331fa2dbe2eSBenjamin Herrenschmidt if (rc) 332fa2dbe2eSBenjamin Herrenschmidt return -EFAULT; 333fa2dbe2eSBenjamin Herrenschmidt 334fa2dbe2eSBenjamin Herrenschmidt rc = opal_lpc_write(opal_lpc_chip_id, lpc->lpc_type, pos, 335fa2dbe2eSBenjamin Herrenschmidt data, len); 336fa2dbe2eSBenjamin Herrenschmidt if (rc) 337fa2dbe2eSBenjamin Herrenschmidt return -ENXIO; 338fa2dbe2eSBenjamin Herrenschmidt *ppos += len; 339fa2dbe2eSBenjamin Herrenschmidt ubuf += len; 340fa2dbe2eSBenjamin Herrenschmidt todo -= len; 341fa2dbe2eSBenjamin Herrenschmidt } 342fa2dbe2eSBenjamin Herrenschmidt 343fa2dbe2eSBenjamin Herrenschmidt return count; 344fa2dbe2eSBenjamin Herrenschmidt } 345fa2dbe2eSBenjamin Herrenschmidt 346fa2dbe2eSBenjamin Herrenschmidt static const struct file_operations lpc_fops = { 347fa2dbe2eSBenjamin Herrenschmidt .read = lpc_debug_read, 348fa2dbe2eSBenjamin Herrenschmidt .write = lpc_debug_write, 349fa2dbe2eSBenjamin Herrenschmidt .open = simple_open, 350fa2dbe2eSBenjamin Herrenschmidt .llseek = default_llseek, 351fa2dbe2eSBenjamin Herrenschmidt }; 352fa2dbe2eSBenjamin Herrenschmidt 353fa2dbe2eSBenjamin Herrenschmidt static int opal_lpc_debugfs_create_type(struct dentry *folder, 354fa2dbe2eSBenjamin Herrenschmidt const char *fname, 355fa2dbe2eSBenjamin Herrenschmidt enum OpalLPCAddressType type) 356fa2dbe2eSBenjamin Herrenschmidt { 357fa2dbe2eSBenjamin Herrenschmidt struct lpc_debugfs_entry *entry; 358fa2dbe2eSBenjamin Herrenschmidt entry = kzalloc(sizeof(*entry), GFP_KERNEL); 359fa2dbe2eSBenjamin Herrenschmidt if (!entry) 360fa2dbe2eSBenjamin Herrenschmidt return -ENOMEM; 361fa2dbe2eSBenjamin Herrenschmidt entry->lpc_type = type; 362fa2dbe2eSBenjamin Herrenschmidt debugfs_create_file(fname, 0600, folder, entry, &lpc_fops); 363fa2dbe2eSBenjamin Herrenschmidt return 0; 364fa2dbe2eSBenjamin Herrenschmidt } 365fa2dbe2eSBenjamin Herrenschmidt 366fa2dbe2eSBenjamin Herrenschmidt static int opal_lpc_init_debugfs(void) 367fa2dbe2eSBenjamin Herrenschmidt { 368fa2dbe2eSBenjamin Herrenschmidt struct dentry *root; 369fa2dbe2eSBenjamin Herrenschmidt int rc = 0; 370fa2dbe2eSBenjamin Herrenschmidt 371fa2dbe2eSBenjamin Herrenschmidt if (opal_lpc_chip_id < 0) 372fa2dbe2eSBenjamin Herrenschmidt return -ENODEV; 373fa2dbe2eSBenjamin Herrenschmidt 374*dbf77fedSAneesh Kumar K.V root = debugfs_create_dir("lpc", arch_debugfs_dir); 375fa2dbe2eSBenjamin Herrenschmidt 376fa2dbe2eSBenjamin Herrenschmidt rc |= opal_lpc_debugfs_create_type(root, "io", OPAL_LPC_IO); 377fa2dbe2eSBenjamin Herrenschmidt rc |= opal_lpc_debugfs_create_type(root, "mem", OPAL_LPC_MEM); 378fa2dbe2eSBenjamin Herrenschmidt rc |= opal_lpc_debugfs_create_type(root, "fw", OPAL_LPC_FW); 379fa2dbe2eSBenjamin Herrenschmidt return rc; 380fa2dbe2eSBenjamin Herrenschmidt } 381b14726c5SMichael Ellerman machine_device_initcall(powernv, opal_lpc_init_debugfs); 382fa2dbe2eSBenjamin Herrenschmidt #endif /* CONFIG_DEBUG_FS */ 383fa2dbe2eSBenjamin Herrenschmidt 3840b1c7643SMichael Ellerman void __init opal_lpc_init(void) 3853fafe9c2SBenjamin Herrenschmidt { 3863fafe9c2SBenjamin Herrenschmidt struct device_node *np; 3873fafe9c2SBenjamin Herrenschmidt 3883fafe9c2SBenjamin Herrenschmidt /* 3893fafe9c2SBenjamin Herrenschmidt * Look for a Power8 LPC bus tagged as "primary", 3903fafe9c2SBenjamin Herrenschmidt * we currently support only one though the OPAL APIs 3913fafe9c2SBenjamin Herrenschmidt * support any number. 3923fafe9c2SBenjamin Herrenschmidt */ 3933fafe9c2SBenjamin Herrenschmidt for_each_compatible_node(np, NULL, "ibm,power8-lpc") { 3943fafe9c2SBenjamin Herrenschmidt if (!of_device_is_available(np)) 3953fafe9c2SBenjamin Herrenschmidt continue; 3963fafe9c2SBenjamin Herrenschmidt if (!of_get_property(np, "primary", NULL)) 3973fafe9c2SBenjamin Herrenschmidt continue; 3983fafe9c2SBenjamin Herrenschmidt opal_lpc_chip_id = of_get_ibm_chip_id(np); 3993fafe9c2SBenjamin Herrenschmidt break; 4003fafe9c2SBenjamin Herrenschmidt } 4013fafe9c2SBenjamin Herrenschmidt if (opal_lpc_chip_id < 0) 4023fafe9c2SBenjamin Herrenschmidt return; 4033fafe9c2SBenjamin Herrenschmidt 404023b13a5SBenjamin Herrenschmidt /* Does it support direct mapping ? */ 405023b13a5SBenjamin Herrenschmidt if (of_get_property(np, "ranges", NULL)) { 406023b13a5SBenjamin Herrenschmidt pr_info("OPAL: Found memory mapped LPC bus on chip %d\n", 407023b13a5SBenjamin Herrenschmidt opal_lpc_chip_id); 408023b13a5SBenjamin Herrenschmidt isa_bridge_init_non_pci(np); 409023b13a5SBenjamin Herrenschmidt } else { 410023b13a5SBenjamin Herrenschmidt pr_info("OPAL: Found non-mapped LPC bus on chip %d\n", 411023b13a5SBenjamin Herrenschmidt opal_lpc_chip_id); 412023b13a5SBenjamin Herrenschmidt 4133fafe9c2SBenjamin Herrenschmidt /* Setup special IO ops */ 4143fafe9c2SBenjamin Herrenschmidt ppc_pci_io = opal_lpc_io; 4153fafe9c2SBenjamin Herrenschmidt isa_io_special = true; 416023b13a5SBenjamin Herrenschmidt } 4173fafe9c2SBenjamin Herrenschmidt } 418