1 /* 2 * Support for the OLPC DCON and OLPC EC access 3 * 4 * Copyright © 2006 Advanced Micro Devices, Inc. 5 * Copyright © 2007-2008 Andres Salomon <dilinger@debian.org> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 */ 12 13 #include <linux/kernel.h> 14 #include <linux/init.h> 15 #include <linux/module.h> 16 #include <linux/delay.h> 17 #include <linux/spinlock.h> 18 #include <linux/io.h> 19 #include <linux/string.h> 20 #include <linux/platform_device.h> 21 #include <linux/of.h> 22 #include <linux/syscore_ops.h> 23 #include <linux/debugfs.h> 24 #include <linux/mutex.h> 25 26 #include <asm/geode.h> 27 #include <asm/setup.h> 28 #include <asm/olpc.h> 29 #include <asm/olpc_ofw.h> 30 31 struct olpc_platform_t olpc_platform_info; 32 EXPORT_SYMBOL_GPL(olpc_platform_info); 33 34 static DEFINE_SPINLOCK(ec_lock); 35 36 /* debugfs interface to EC commands */ 37 #define EC_MAX_CMD_ARGS (5 + 1) /* cmd byte + 5 args */ 38 #define EC_MAX_CMD_REPLY (8) 39 40 static struct dentry *ec_debugfs_dir; 41 static DEFINE_MUTEX(ec_debugfs_cmd_lock); 42 static unsigned char ec_debugfs_resp[EC_MAX_CMD_REPLY]; 43 static unsigned int ec_debugfs_resp_bytes; 44 45 /* EC event mask to be applied during suspend (defining wakeup sources). */ 46 static u16 ec_wakeup_mask; 47 48 /* what the timeout *should* be (in ms) */ 49 #define EC_BASE_TIMEOUT 20 50 51 /* the timeout that bugs in the EC might force us to actually use */ 52 static int ec_timeout = EC_BASE_TIMEOUT; 53 54 static int __init olpc_ec_timeout_set(char *str) 55 { 56 if (get_option(&str, &ec_timeout) != 1) { 57 ec_timeout = EC_BASE_TIMEOUT; 58 printk(KERN_ERR "olpc-ec: invalid argument to " 59 "'olpc_ec_timeout=', ignoring!\n"); 60 } 61 printk(KERN_DEBUG "olpc-ec: using %d ms delay for EC commands.\n", 62 ec_timeout); 63 return 1; 64 } 65 __setup("olpc_ec_timeout=", olpc_ec_timeout_set); 66 67 /* 68 * These {i,o}bf_status functions return whether the buffers are full or not. 69 */ 70 71 static inline unsigned int ibf_status(unsigned int port) 72 { 73 return !!(inb(port) & 0x02); 74 } 75 76 static inline unsigned int obf_status(unsigned int port) 77 { 78 return inb(port) & 0x01; 79 } 80 81 #define wait_on_ibf(p, d) __wait_on_ibf(__LINE__, (p), (d)) 82 static int __wait_on_ibf(unsigned int line, unsigned int port, int desired) 83 { 84 unsigned int timeo; 85 int state = ibf_status(port); 86 87 for (timeo = ec_timeout; state != desired && timeo; timeo--) { 88 mdelay(1); 89 state = ibf_status(port); 90 } 91 92 if ((state == desired) && (ec_timeout > EC_BASE_TIMEOUT) && 93 timeo < (ec_timeout - EC_BASE_TIMEOUT)) { 94 printk(KERN_WARNING "olpc-ec: %d: waited %u ms for IBF!\n", 95 line, ec_timeout - timeo); 96 } 97 98 return !(state == desired); 99 } 100 101 #define wait_on_obf(p, d) __wait_on_obf(__LINE__, (p), (d)) 102 static int __wait_on_obf(unsigned int line, unsigned int port, int desired) 103 { 104 unsigned int timeo; 105 int state = obf_status(port); 106 107 for (timeo = ec_timeout; state != desired && timeo; timeo--) { 108 mdelay(1); 109 state = obf_status(port); 110 } 111 112 if ((state == desired) && (ec_timeout > EC_BASE_TIMEOUT) && 113 timeo < (ec_timeout - EC_BASE_TIMEOUT)) { 114 printk(KERN_WARNING "olpc-ec: %d: waited %u ms for OBF!\n", 115 line, ec_timeout - timeo); 116 } 117 118 return !(state == desired); 119 } 120 121 /* 122 * This allows the kernel to run Embedded Controller commands. The EC is 123 * documented at <http://wiki.laptop.org/go/Embedded_controller>, and the 124 * available EC commands are here: 125 * <http://wiki.laptop.org/go/Ec_specification>. Unfortunately, while 126 * OpenFirmware's source is available, the EC's is not. 127 */ 128 int olpc_ec_cmd(unsigned char cmd, unsigned char *inbuf, size_t inlen, 129 unsigned char *outbuf, size_t outlen) 130 { 131 unsigned long flags; 132 int ret = -EIO; 133 int i; 134 int restarts = 0; 135 136 spin_lock_irqsave(&ec_lock, flags); 137 138 /* Clear OBF */ 139 for (i = 0; i < 10 && (obf_status(0x6c) == 1); i++) 140 inb(0x68); 141 if (i == 10) { 142 printk(KERN_ERR "olpc-ec: timeout while attempting to " 143 "clear OBF flag!\n"); 144 goto err; 145 } 146 147 if (wait_on_ibf(0x6c, 0)) { 148 printk(KERN_ERR "olpc-ec: timeout waiting for EC to " 149 "quiesce!\n"); 150 goto err; 151 } 152 153 restart: 154 /* 155 * Note that if we time out during any IBF checks, that's a failure; 156 * we have to return. There's no way for the kernel to clear that. 157 * 158 * If we time out during an OBF check, we can restart the command; 159 * reissuing it will clear the OBF flag, and we should be alright. 160 * The OBF flag will sometimes misbehave due to what we believe 161 * is a hardware quirk.. 162 */ 163 pr_devel("olpc-ec: running cmd 0x%x\n", cmd); 164 outb(cmd, 0x6c); 165 166 if (wait_on_ibf(0x6c, 0)) { 167 printk(KERN_ERR "olpc-ec: timeout waiting for EC to read " 168 "command!\n"); 169 goto err; 170 } 171 172 if (inbuf && inlen) { 173 /* write data to EC */ 174 for (i = 0; i < inlen; i++) { 175 pr_devel("olpc-ec: sending cmd arg 0x%x\n", inbuf[i]); 176 outb(inbuf[i], 0x68); 177 if (wait_on_ibf(0x6c, 0)) { 178 printk(KERN_ERR "olpc-ec: timeout waiting for" 179 " EC accept data!\n"); 180 goto err; 181 } 182 } 183 } 184 if (outbuf && outlen) { 185 /* read data from EC */ 186 for (i = 0; i < outlen; i++) { 187 if (wait_on_obf(0x6c, 1)) { 188 printk(KERN_ERR "olpc-ec: timeout waiting for" 189 " EC to provide data!\n"); 190 if (restarts++ < 10) 191 goto restart; 192 goto err; 193 } 194 outbuf[i] = inb(0x68); 195 pr_devel("olpc-ec: received 0x%x\n", outbuf[i]); 196 } 197 } 198 199 ret = 0; 200 err: 201 spin_unlock_irqrestore(&ec_lock, flags); 202 return ret; 203 } 204 EXPORT_SYMBOL_GPL(olpc_ec_cmd); 205 206 void olpc_ec_wakeup_set(u16 value) 207 { 208 ec_wakeup_mask |= value; 209 } 210 EXPORT_SYMBOL_GPL(olpc_ec_wakeup_set); 211 212 void olpc_ec_wakeup_clear(u16 value) 213 { 214 ec_wakeup_mask &= ~value; 215 } 216 EXPORT_SYMBOL_GPL(olpc_ec_wakeup_clear); 217 218 /* 219 * Returns true if the compile and runtime configurations allow for EC events 220 * to wake the system. 221 */ 222 bool olpc_ec_wakeup_available(void) 223 { 224 if (!machine_is_olpc()) 225 return false; 226 227 /* 228 * XO-1 EC wakeups are available when olpc-xo1-sci driver is 229 * compiled in 230 */ 231 #ifdef CONFIG_OLPC_XO1_SCI 232 if (olpc_platform_info.boardrev < olpc_board_pre(0xd0)) /* XO-1 */ 233 return true; 234 #endif 235 236 /* 237 * XO-1.5 EC wakeups are available when olpc-xo15-sci driver is 238 * compiled in 239 */ 240 #ifdef CONFIG_OLPC_XO15_SCI 241 if (olpc_platform_info.boardrev >= olpc_board_pre(0xd0)) /* XO-1.5 */ 242 return true; 243 #endif 244 245 return false; 246 } 247 EXPORT_SYMBOL_GPL(olpc_ec_wakeup_available); 248 249 int olpc_ec_mask_write(u16 bits) 250 { 251 if (olpc_platform_info.flags & OLPC_F_EC_WIDE_SCI) { 252 __be16 ec_word = cpu_to_be16(bits); 253 return olpc_ec_cmd(EC_WRITE_EXT_SCI_MASK, (void *) &ec_word, 2, 254 NULL, 0); 255 } else { 256 unsigned char ec_byte = bits & 0xff; 257 return olpc_ec_cmd(EC_WRITE_SCI_MASK, &ec_byte, 1, NULL, 0); 258 } 259 } 260 EXPORT_SYMBOL_GPL(olpc_ec_mask_write); 261 262 int olpc_ec_sci_query(u16 *sci_value) 263 { 264 int ret; 265 266 if (olpc_platform_info.flags & OLPC_F_EC_WIDE_SCI) { 267 __be16 ec_word; 268 ret = olpc_ec_cmd(EC_EXT_SCI_QUERY, 269 NULL, 0, (void *) &ec_word, 2); 270 if (ret == 0) 271 *sci_value = be16_to_cpu(ec_word); 272 } else { 273 unsigned char ec_byte; 274 ret = olpc_ec_cmd(EC_SCI_QUERY, NULL, 0, &ec_byte, 1); 275 if (ret == 0) 276 *sci_value = ec_byte; 277 } 278 279 return ret; 280 } 281 EXPORT_SYMBOL_GPL(olpc_ec_sci_query); 282 283 static ssize_t ec_debugfs_cmd_write(struct file *file, const char __user *buf, 284 size_t size, loff_t *ppos) 285 { 286 int i, m; 287 unsigned char ec_cmd[EC_MAX_CMD_ARGS]; 288 unsigned int ec_cmd_int[EC_MAX_CMD_ARGS]; 289 char cmdbuf[64]; 290 int ec_cmd_bytes; 291 292 mutex_lock(&ec_debugfs_cmd_lock); 293 294 size = simple_write_to_buffer(cmdbuf, sizeof(cmdbuf), ppos, buf, size); 295 296 m = sscanf(cmdbuf, "%x:%u %x %x %x %x %x", &ec_cmd_int[0], 297 &ec_debugfs_resp_bytes, 298 &ec_cmd_int[1], &ec_cmd_int[2], &ec_cmd_int[3], 299 &ec_cmd_int[4], &ec_cmd_int[5]); 300 if (m < 2 || ec_debugfs_resp_bytes > EC_MAX_CMD_REPLY) { 301 /* reset to prevent overflow on read */ 302 ec_debugfs_resp_bytes = 0; 303 304 printk(KERN_DEBUG "olpc-ec: bad ec cmd: " 305 "cmd:response-count [arg1 [arg2 ...]]\n"); 306 size = -EINVAL; 307 goto out; 308 } 309 310 /* convert scanf'd ints to char */ 311 ec_cmd_bytes = m - 2; 312 for (i = 0; i <= ec_cmd_bytes; i++) 313 ec_cmd[i] = ec_cmd_int[i]; 314 315 printk(KERN_DEBUG "olpc-ec: debugfs cmd 0x%02x with %d args " 316 "%02x %02x %02x %02x %02x, want %d returns\n", 317 ec_cmd[0], ec_cmd_bytes, ec_cmd[1], ec_cmd[2], ec_cmd[3], 318 ec_cmd[4], ec_cmd[5], ec_debugfs_resp_bytes); 319 320 olpc_ec_cmd(ec_cmd[0], (ec_cmd_bytes == 0) ? NULL : &ec_cmd[1], 321 ec_cmd_bytes, ec_debugfs_resp, ec_debugfs_resp_bytes); 322 323 printk(KERN_DEBUG "olpc-ec: response " 324 "%02x %02x %02x %02x %02x %02x %02x %02x (%d bytes expected)\n", 325 ec_debugfs_resp[0], ec_debugfs_resp[1], ec_debugfs_resp[2], 326 ec_debugfs_resp[3], ec_debugfs_resp[4], ec_debugfs_resp[5], 327 ec_debugfs_resp[6], ec_debugfs_resp[7], ec_debugfs_resp_bytes); 328 329 out: 330 mutex_unlock(&ec_debugfs_cmd_lock); 331 return size; 332 } 333 334 static ssize_t ec_debugfs_cmd_read(struct file *file, char __user *buf, 335 size_t size, loff_t *ppos) 336 { 337 unsigned int i, r; 338 char *rp; 339 char respbuf[64]; 340 341 mutex_lock(&ec_debugfs_cmd_lock); 342 rp = respbuf; 343 rp += sprintf(rp, "%02x", ec_debugfs_resp[0]); 344 for (i = 1; i < ec_debugfs_resp_bytes; i++) 345 rp += sprintf(rp, ", %02x", ec_debugfs_resp[i]); 346 mutex_unlock(&ec_debugfs_cmd_lock); 347 rp += sprintf(rp, "\n"); 348 349 r = rp - respbuf; 350 return simple_read_from_buffer(buf, size, ppos, respbuf, r); 351 } 352 353 static const struct file_operations ec_debugfs_genops = { 354 .write = ec_debugfs_cmd_write, 355 .read = ec_debugfs_cmd_read, 356 }; 357 358 static void setup_debugfs(void) 359 { 360 ec_debugfs_dir = debugfs_create_dir("olpc-ec", 0); 361 if (ec_debugfs_dir == ERR_PTR(-ENODEV)) 362 return; 363 364 debugfs_create_file("cmd", 0600, ec_debugfs_dir, NULL, 365 &ec_debugfs_genops); 366 } 367 368 static int olpc_ec_suspend(void) 369 { 370 return olpc_ec_mask_write(ec_wakeup_mask); 371 } 372 373 static bool __init check_ofw_architecture(struct device_node *root) 374 { 375 const char *olpc_arch; 376 int propsize; 377 378 olpc_arch = of_get_property(root, "architecture", &propsize); 379 return propsize == 5 && strncmp("OLPC", olpc_arch, 5) == 0; 380 } 381 382 static u32 __init get_board_revision(struct device_node *root) 383 { 384 int propsize; 385 const __be32 *rev; 386 387 rev = of_get_property(root, "board-revision-int", &propsize); 388 if (propsize != 4) 389 return 0; 390 391 return be32_to_cpu(*rev); 392 } 393 394 static bool __init platform_detect(void) 395 { 396 struct device_node *root = of_find_node_by_path("/"); 397 bool success; 398 399 if (!root) 400 return false; 401 402 success = check_ofw_architecture(root); 403 if (success) { 404 olpc_platform_info.boardrev = get_board_revision(root); 405 olpc_platform_info.flags |= OLPC_F_PRESENT; 406 } 407 408 of_node_put(root); 409 return success; 410 } 411 412 static int __init add_xo1_platform_devices(void) 413 { 414 struct platform_device *pdev; 415 416 pdev = platform_device_register_simple("xo1-rfkill", -1, NULL, 0); 417 if (IS_ERR(pdev)) 418 return PTR_ERR(pdev); 419 420 pdev = platform_device_register_simple("olpc-xo1", -1, NULL, 0); 421 if (IS_ERR(pdev)) 422 return PTR_ERR(pdev); 423 424 return 0; 425 } 426 427 static struct syscore_ops olpc_syscore_ops = { 428 .suspend = olpc_ec_suspend, 429 }; 430 431 static int __init olpc_init(void) 432 { 433 int r = 0; 434 435 if (!olpc_ofw_present() || !platform_detect()) 436 return 0; 437 438 spin_lock_init(&ec_lock); 439 440 /* assume B1 and above models always have a DCON */ 441 if (olpc_board_at_least(olpc_board(0xb1))) 442 olpc_platform_info.flags |= OLPC_F_DCON; 443 444 /* get the EC revision */ 445 olpc_ec_cmd(EC_FIRMWARE_REV, NULL, 0, 446 (unsigned char *) &olpc_platform_info.ecver, 1); 447 448 #ifdef CONFIG_PCI_OLPC 449 /* If the VSA exists let it emulate PCI, if not emulate in kernel. 450 * XO-1 only. */ 451 if (olpc_platform_info.boardrev < olpc_board_pre(0xd0) && 452 !cs5535_has_vsa2()) 453 x86_init.pci.arch_init = pci_olpc_init; 454 #endif 455 /* EC version 0x5f adds support for wide SCI mask */ 456 if (olpc_platform_info.ecver >= 0x5f) 457 olpc_platform_info.flags |= OLPC_F_EC_WIDE_SCI; 458 459 printk(KERN_INFO "OLPC board revision %s%X (EC=%x)\n", 460 ((olpc_platform_info.boardrev & 0xf) < 8) ? "pre" : "", 461 olpc_platform_info.boardrev >> 4, 462 olpc_platform_info.ecver); 463 464 if (olpc_platform_info.boardrev < olpc_board_pre(0xd0)) { /* XO-1 */ 465 r = add_xo1_platform_devices(); 466 if (r) 467 return r; 468 } 469 470 register_syscore_ops(&olpc_syscore_ops); 471 setup_debugfs(); 472 473 return 0; 474 } 475 476 postcore_initcall(olpc_init); 477