1 /* 2 * PowerNV LPC bus handling. 3 * 4 * Copyright 2013 IBM Corp. 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation; either version 9 * 2 of the License, or (at your option) any later version. 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 26 static int opal_lpc_chip_id = -1; 27 28 static 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 39 static __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 } 51 static u16 opal_lpc_inw(unsigned long port) 52 { 53 return le16_to_cpu(__opal_lpc_inw(port)); 54 } 55 56 static __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 72 static u32 opal_lpc_inl(unsigned long port) 73 { 74 return le32_to_cpu(__opal_lpc_inl(port)); 75 } 76 77 static 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 84 static 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 96 static void opal_lpc_outw(u16 val, unsigned long port) 97 { 98 __opal_lpc_outw(cpu_to_le16(val), port); 99 } 100 101 static 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 115 static void opal_lpc_outl(u32 val, unsigned long port) 116 { 117 __opal_lpc_outl(cpu_to_le32(val), port); 118 } 119 120 static 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 128 static 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 136 static 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 144 static 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 152 static 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 160 static 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 168 static 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 184 struct lpc_debugfs_entry { 185 enum OpalLPCAddressType lpc_type; 186 }; 187 188 static 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 * Select access size based on count and alignment and 204 * access type. IO and MEM only support byte acceses, 205 * FW supports all 3. 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 switch(len) { 219 case 4: 220 rc = __put_user((u32)data, (u32 __user *)ubuf); 221 break; 222 case 2: 223 rc = __put_user((u16)data, (u16 __user *)ubuf); 224 break; 225 default: 226 rc = __put_user((u8)data, (u8 __user *)ubuf); 227 break; 228 } 229 if (rc) 230 return -EFAULT; 231 *ppos += len; 232 ubuf += len; 233 todo -= len; 234 } 235 236 return count; 237 } 238 239 static ssize_t lpc_debug_write(struct file *filp, const char __user *ubuf, 240 size_t count, loff_t *ppos) 241 { 242 struct lpc_debugfs_entry *lpc = filp->private_data; 243 u32 data, pos, len, todo; 244 int rc; 245 246 if (!access_ok(VERIFY_READ, ubuf, count)) 247 return -EFAULT; 248 249 todo = count; 250 while (todo) { 251 pos = *ppos; 252 253 /* 254 * Select access size based on count and alignment and 255 * access type. IO and MEM only support byte acceses, 256 * FW supports all 3. 257 */ 258 len = 1; 259 if (lpc->lpc_type == OPAL_LPC_FW) { 260 if (todo > 3 && (pos & 3) == 0) 261 len = 4; 262 else if (todo > 1 && (pos & 1) == 0) 263 len = 2; 264 } 265 switch(len) { 266 case 4: 267 rc = __get_user(data, (u32 __user *)ubuf); 268 break; 269 case 2: 270 rc = __get_user(data, (u16 __user *)ubuf); 271 break; 272 default: 273 rc = __get_user(data, (u8 __user *)ubuf); 274 break; 275 } 276 if (rc) 277 return -EFAULT; 278 279 rc = opal_lpc_write(opal_lpc_chip_id, lpc->lpc_type, pos, 280 data, len); 281 if (rc) 282 return -ENXIO; 283 *ppos += len; 284 ubuf += len; 285 todo -= len; 286 } 287 288 return count; 289 } 290 291 static const struct file_operations lpc_fops = { 292 .read = lpc_debug_read, 293 .write = lpc_debug_write, 294 .open = simple_open, 295 .llseek = default_llseek, 296 }; 297 298 static int opal_lpc_debugfs_create_type(struct dentry *folder, 299 const char *fname, 300 enum OpalLPCAddressType type) 301 { 302 struct lpc_debugfs_entry *entry; 303 entry = kzalloc(sizeof(*entry), GFP_KERNEL); 304 if (!entry) 305 return -ENOMEM; 306 entry->lpc_type = type; 307 debugfs_create_file(fname, 0600, folder, entry, &lpc_fops); 308 return 0; 309 } 310 311 static int opal_lpc_init_debugfs(void) 312 { 313 struct dentry *root; 314 int rc = 0; 315 316 if (opal_lpc_chip_id < 0) 317 return -ENODEV; 318 319 root = debugfs_create_dir("lpc", powerpc_debugfs_root); 320 321 rc |= opal_lpc_debugfs_create_type(root, "io", OPAL_LPC_IO); 322 rc |= opal_lpc_debugfs_create_type(root, "mem", OPAL_LPC_MEM); 323 rc |= opal_lpc_debugfs_create_type(root, "fw", OPAL_LPC_FW); 324 return rc; 325 } 326 device_initcall(opal_lpc_init_debugfs); 327 #endif /* CONFIG_DEBUG_FS */ 328 329 void opal_lpc_init(void) 330 { 331 struct device_node *np; 332 333 /* 334 * Look for a Power8 LPC bus tagged as "primary", 335 * we currently support only one though the OPAL APIs 336 * support any number. 337 */ 338 for_each_compatible_node(np, NULL, "ibm,power8-lpc") { 339 if (!of_device_is_available(np)) 340 continue; 341 if (!of_get_property(np, "primary", NULL)) 342 continue; 343 opal_lpc_chip_id = of_get_ibm_chip_id(np); 344 break; 345 } 346 if (opal_lpc_chip_id < 0) 347 return; 348 349 /* Setup special IO ops */ 350 ppc_pci_io = opal_lpc_io; 351 isa_io_special = true; 352 353 pr_info("OPAL: Power8 LPC bus found, chip ID %d\n", opal_lpc_chip_id); 354 } 355