root/arch/x86/platform/olpc/olpc.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. olpc_ec_timeout_set
  2. ibf_status
  3. obf_status
  4. __wait_on_ibf
  5. __wait_on_obf
  6. olpc_xo1_ec_cmd
  7. check_ofw_architecture
  8. get_board_revision
  9. platform_detect
  10. add_xo1_platform_devices
  11. olpc_xo1_ec_suspend
  12. olpc_xo1_ec_resume
  13. olpc_init

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Support for the OLPC DCON and OLPC EC access
   4  *
   5  * Copyright © 2006  Advanced Micro Devices, Inc.
   6  * Copyright © 2007-2008  Andres Salomon <dilinger@debian.org>
   7  */
   8 
   9 #include <linux/kernel.h>
  10 #include <linux/init.h>
  11 #include <linux/export.h>
  12 #include <linux/delay.h>
  13 #include <linux/io.h>
  14 #include <linux/string.h>
  15 #include <linux/platform_device.h>
  16 #include <linux/of.h>
  17 #include <linux/syscore_ops.h>
  18 #include <linux/mutex.h>
  19 #include <linux/olpc-ec.h>
  20 
  21 #include <asm/geode.h>
  22 #include <asm/setup.h>
  23 #include <asm/olpc.h>
  24 #include <asm/olpc_ofw.h>
  25 
  26 struct olpc_platform_t olpc_platform_info;
  27 EXPORT_SYMBOL_GPL(olpc_platform_info);
  28 
  29 /* what the timeout *should* be (in ms) */
  30 #define EC_BASE_TIMEOUT 20
  31 
  32 /* the timeout that bugs in the EC might force us to actually use */
  33 static int ec_timeout = EC_BASE_TIMEOUT;
  34 
  35 static int __init olpc_ec_timeout_set(char *str)
  36 {
  37         if (get_option(&str, &ec_timeout) != 1) {
  38                 ec_timeout = EC_BASE_TIMEOUT;
  39                 printk(KERN_ERR "olpc-ec:  invalid argument to "
  40                                 "'olpc_ec_timeout=', ignoring!\n");
  41         }
  42         printk(KERN_DEBUG "olpc-ec:  using %d ms delay for EC commands.\n",
  43                         ec_timeout);
  44         return 1;
  45 }
  46 __setup("olpc_ec_timeout=", olpc_ec_timeout_set);
  47 
  48 /*
  49  * These {i,o}bf_status functions return whether the buffers are full or not.
  50  */
  51 
  52 static inline unsigned int ibf_status(unsigned int port)
  53 {
  54         return !!(inb(port) & 0x02);
  55 }
  56 
  57 static inline unsigned int obf_status(unsigned int port)
  58 {
  59         return inb(port) & 0x01;
  60 }
  61 
  62 #define wait_on_ibf(p, d) __wait_on_ibf(__LINE__, (p), (d))
  63 static int __wait_on_ibf(unsigned int line, unsigned int port, int desired)
  64 {
  65         unsigned int timeo;
  66         int state = ibf_status(port);
  67 
  68         for (timeo = ec_timeout; state != desired && timeo; timeo--) {
  69                 mdelay(1);
  70                 state = ibf_status(port);
  71         }
  72 
  73         if ((state == desired) && (ec_timeout > EC_BASE_TIMEOUT) &&
  74                         timeo < (ec_timeout - EC_BASE_TIMEOUT)) {
  75                 printk(KERN_WARNING "olpc-ec:  %d: waited %u ms for IBF!\n",
  76                                 line, ec_timeout - timeo);
  77         }
  78 
  79         return !(state == desired);
  80 }
  81 
  82 #define wait_on_obf(p, d) __wait_on_obf(__LINE__, (p), (d))
  83 static int __wait_on_obf(unsigned int line, unsigned int port, int desired)
  84 {
  85         unsigned int timeo;
  86         int state = obf_status(port);
  87 
  88         for (timeo = ec_timeout; state != desired && timeo; timeo--) {
  89                 mdelay(1);
  90                 state = obf_status(port);
  91         }
  92 
  93         if ((state == desired) && (ec_timeout > EC_BASE_TIMEOUT) &&
  94                         timeo < (ec_timeout - EC_BASE_TIMEOUT)) {
  95                 printk(KERN_WARNING "olpc-ec:  %d: waited %u ms for OBF!\n",
  96                                 line, ec_timeout - timeo);
  97         }
  98 
  99         return !(state == desired);
 100 }
 101 
 102 /*
 103  * This allows the kernel to run Embedded Controller commands.  The EC is
 104  * documented at <http://wiki.laptop.org/go/Embedded_controller>, and the
 105  * available EC commands are here:
 106  * <http://wiki.laptop.org/go/Ec_specification>.  Unfortunately, while
 107  * OpenFirmware's source is available, the EC's is not.
 108  */
 109 static int olpc_xo1_ec_cmd(u8 cmd, u8 *inbuf, size_t inlen, u8 *outbuf,
 110                 size_t outlen, void *arg)
 111 {
 112         int ret = -EIO;
 113         int i;
 114         int restarts = 0;
 115 
 116         /* Clear OBF */
 117         for (i = 0; i < 10 && (obf_status(0x6c) == 1); i++)
 118                 inb(0x68);
 119         if (i == 10) {
 120                 printk(KERN_ERR "olpc-ec:  timeout while attempting to "
 121                                 "clear OBF flag!\n");
 122                 goto err;
 123         }
 124 
 125         if (wait_on_ibf(0x6c, 0)) {
 126                 printk(KERN_ERR "olpc-ec:  timeout waiting for EC to "
 127                                 "quiesce!\n");
 128                 goto err;
 129         }
 130 
 131 restart:
 132         /*
 133          * Note that if we time out during any IBF checks, that's a failure;
 134          * we have to return.  There's no way for the kernel to clear that.
 135          *
 136          * If we time out during an OBF check, we can restart the command;
 137          * reissuing it will clear the OBF flag, and we should be alright.
 138          * The OBF flag will sometimes misbehave due to what we believe
 139          * is a hardware quirk..
 140          */
 141         pr_devel("olpc-ec:  running cmd 0x%x\n", cmd);
 142         outb(cmd, 0x6c);
 143 
 144         if (wait_on_ibf(0x6c, 0)) {
 145                 printk(KERN_ERR "olpc-ec:  timeout waiting for EC to read "
 146                                 "command!\n");
 147                 goto err;
 148         }
 149 
 150         if (inbuf && inlen) {
 151                 /* write data to EC */
 152                 for (i = 0; i < inlen; i++) {
 153                         pr_devel("olpc-ec:  sending cmd arg 0x%x\n", inbuf[i]);
 154                         outb(inbuf[i], 0x68);
 155                         if (wait_on_ibf(0x6c, 0)) {
 156                                 printk(KERN_ERR "olpc-ec:  timeout waiting for"
 157                                                 " EC accept data!\n");
 158                                 goto err;
 159                         }
 160                 }
 161         }
 162         if (outbuf && outlen) {
 163                 /* read data from EC */
 164                 for (i = 0; i < outlen; i++) {
 165                         if (wait_on_obf(0x6c, 1)) {
 166                                 printk(KERN_ERR "olpc-ec:  timeout waiting for"
 167                                                 " EC to provide data!\n");
 168                                 if (restarts++ < 10)
 169                                         goto restart;
 170                                 goto err;
 171                         }
 172                         outbuf[i] = inb(0x68);
 173                         pr_devel("olpc-ec:  received 0x%x\n", outbuf[i]);
 174                 }
 175         }
 176 
 177         ret = 0;
 178 err:
 179         return ret;
 180 }
 181 
 182 static bool __init check_ofw_architecture(struct device_node *root)
 183 {
 184         const char *olpc_arch;
 185         int propsize;
 186 
 187         olpc_arch = of_get_property(root, "architecture", &propsize);
 188         return propsize == 5 && strncmp("OLPC", olpc_arch, 5) == 0;
 189 }
 190 
 191 static u32 __init get_board_revision(struct device_node *root)
 192 {
 193         int propsize;
 194         const __be32 *rev;
 195 
 196         rev = of_get_property(root, "board-revision-int", &propsize);
 197         if (propsize != 4)
 198                 return 0;
 199 
 200         return be32_to_cpu(*rev);
 201 }
 202 
 203 static bool __init platform_detect(void)
 204 {
 205         struct device_node *root = of_find_node_by_path("/");
 206         bool success;
 207 
 208         if (!root)
 209                 return false;
 210 
 211         success = check_ofw_architecture(root);
 212         if (success) {
 213                 olpc_platform_info.boardrev = get_board_revision(root);
 214                 olpc_platform_info.flags |= OLPC_F_PRESENT;
 215 
 216                 pr_info("OLPC board revision %s%X\n",
 217                         ((olpc_platform_info.boardrev & 0xf) < 8) ? "pre" : "",
 218                         olpc_platform_info.boardrev >> 4);
 219         }
 220 
 221         of_node_put(root);
 222         return success;
 223 }
 224 
 225 static int __init add_xo1_platform_devices(void)
 226 {
 227         struct platform_device *pdev;
 228 
 229         pdev = platform_device_register_simple("xo1-rfkill", -1, NULL, 0);
 230         if (IS_ERR(pdev))
 231                 return PTR_ERR(pdev);
 232 
 233         pdev = platform_device_register_simple("olpc-xo1", -1, NULL, 0);
 234 
 235         return PTR_ERR_OR_ZERO(pdev);
 236 }
 237 
 238 static int olpc_xo1_ec_suspend(struct platform_device *pdev)
 239 {
 240         /*
 241          * Squelch SCIs while suspended.  This is a fix for
 242          * <http://dev.laptop.org/ticket/1835>.
 243          */
 244         return olpc_ec_cmd(EC_SET_SCI_INHIBIT, NULL, 0, NULL, 0);
 245 }
 246 
 247 static int olpc_xo1_ec_resume(struct platform_device *pdev)
 248 {
 249         /* Tell the EC to stop inhibiting SCIs */
 250         olpc_ec_cmd(EC_SET_SCI_INHIBIT_RELEASE, NULL, 0, NULL, 0);
 251 
 252         /*
 253          * Tell the wireless module to restart USB communication.
 254          * Must be done twice.
 255          */
 256         olpc_ec_cmd(EC_WAKE_UP_WLAN, NULL, 0, NULL, 0);
 257         olpc_ec_cmd(EC_WAKE_UP_WLAN, NULL, 0, NULL, 0);
 258 
 259         return 0;
 260 }
 261 
 262 static struct olpc_ec_driver ec_xo1_driver = {
 263         .suspend = olpc_xo1_ec_suspend,
 264         .resume = olpc_xo1_ec_resume,
 265         .ec_cmd = olpc_xo1_ec_cmd,
 266 #ifdef CONFIG_OLPC_XO1_SCI
 267         /*
 268          * XO-1 EC wakeups are available when olpc-xo1-sci driver is
 269          * compiled in
 270          */
 271         .wakeup_available = true,
 272 #endif
 273 };
 274 
 275 static struct olpc_ec_driver ec_xo1_5_driver = {
 276         .ec_cmd = olpc_xo1_ec_cmd,
 277 #ifdef CONFIG_OLPC_XO1_5_SCI
 278         /*
 279          * XO-1.5 EC wakeups are available when olpc-xo15-sci driver is
 280          * compiled in
 281          */
 282         .wakeup_available = true,
 283 #endif
 284 };
 285 
 286 static int __init olpc_init(void)
 287 {
 288         int r = 0;
 289 
 290         if (!olpc_ofw_present() || !platform_detect())
 291                 return 0;
 292 
 293         /* register the XO-1 and 1.5-specific EC handler */
 294         if (olpc_platform_info.boardrev < olpc_board_pre(0xd0)) /* XO-1 */
 295                 olpc_ec_driver_register(&ec_xo1_driver, NULL);
 296         else
 297                 olpc_ec_driver_register(&ec_xo1_5_driver, NULL);
 298         platform_device_register_simple("olpc-ec", -1, NULL, 0);
 299 
 300         /* assume B1 and above models always have a DCON */
 301         if (olpc_board_at_least(olpc_board(0xb1)))
 302                 olpc_platform_info.flags |= OLPC_F_DCON;
 303 
 304 #ifdef CONFIG_PCI_OLPC
 305         /* If the VSA exists let it emulate PCI, if not emulate in kernel.
 306          * XO-1 only. */
 307         if (olpc_platform_info.boardrev < olpc_board_pre(0xd0) &&
 308                         !cs5535_has_vsa2())
 309                 x86_init.pci.arch_init = pci_olpc_init;
 310 #endif
 311 
 312         if (olpc_platform_info.boardrev < olpc_board_pre(0xd0)) { /* XO-1 */
 313                 r = add_xo1_platform_devices();
 314                 if (r)
 315                         return r;
 316         }
 317 
 318         return 0;
 319 }
 320 
 321 postcore_initcall(olpc_init);

/* [<][>][^][v][top][bottom][index][help] */