From: Jordan Crouse <[EMAIL PROTECTED]>

Update the OLPC power managment code to account for the new OFW handler.
Also, add support for restoring the MFGPT clock event timer.

Signed-off-by: Jordan Crouse <[EMAIL PROTECTED]>
---

 arch/i386/kernel/geode.c        |  266 ++++++++++++++++++++++++++++-----------
 arch/i386/kernel/olpc-pm.c      |   98 +++-----------
 arch/i386/kernel/olpc-wakeup.S  |  233 ++++------------------------------
 arch/i386/kernel/setup.c        |    5 -
 drivers/clocksource/mfgpt.c     |   44 +++++-
 drivers/i2c/busses/scx200_acb.c |  162 +++++++++++-------------
 include/asm-i386/geode.h        |   54 ++++++--
 7 files changed, 388 insertions(+), 474 deletions(-)

diff --git a/arch/i386/kernel/geode.c b/arch/i386/kernel/geode.c
index 9ee54b6..8a64e0c 100644
--- a/arch/i386/kernel/geode.c
+++ b/arch/i386/kernel/geode.c
@@ -1,5 +1,5 @@
 /* AMD Geode southbridge support code
- * Copyright (C) 2006, Advanced Micro Devices, Inc.
+ * Copyright (C) 2006-2007, Advanced Micro Devices, Inc.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -10,86 +10,105 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/ioport.h>
+#include <linux/pci.h>
 #include <asm/io.h>
 #include <asm/msr.h>
 #include <asm/geode.h>
 
+#define MFGPT_NAME "geode-mfgpt"
+
 static struct {
-       char *name;
-       u32 msr;
-       int size;
-       u32 base;
-} lbars[] = {
-       { "geode-pms",   MSR_LBAR_PMS, LBAR_PMS_SIZE, 0 },
-       { "geode-acpi",  MSR_LBAR_ACPI, LBAR_ACPI_SIZE, 0 },
-       { "geode-gpio",  MSR_LBAR_GPIO, LBAR_GPIO_SIZE, 0 },
-       { "geode-mfgpt", MSR_LBAR_MFGPT, LBAR_MFGPT_SIZE, 0 }
+       const char *name;
+       void __iomem *base;
+       int (*suspend)(pm_message_t, void *);
+       int (*resume)(void *);
+       void *data;
+} geode_devices[] = {
+       { "geode-smb" },
+       { "geode-gpio" },
+       { MFGPT_NAME },
+       { "geode-interrupt" },
+       { "geode-pms" },
+       { "geode-acpi" }
 };
 
-int
-geode_get_dev_base(unsigned int dev) {
-       if (dev < ARRAY_SIZE(lbars))
-               return lbars[dev].base;
-       return 0;
+void __iomem * geode_get_dev_base(unsigned int dev) {
+       if (dev < ARRAY_SIZE(geode_devices))
+               return geode_devices[dev].base;
+
+       return NULL;
 }
 
 EXPORT_SYMBOL_GPL(geode_get_dev_base);
 
+void geode_set_pm_hooks(unsigned int dev,
+                       int (*suspend)(pm_message_t, void *),
+                       int (*resume)(void *),
+                       void *data)
+{
+       if (dev < ARRAY_SIZE(geode_devices)) {
+               geode_devices[dev].suspend = suspend;
+               geode_devices[dev].resume = resume;
+               geode_devices[dev].data = data;
+       }
+}
+
+EXPORT_SYMBOL_GPL(geode_set_pm_hooks);
+
 /* === GPIO API === */
 
-void
-geode_gpio_set(unsigned int gpio, unsigned int reg)
+void geode_gpio_set(unsigned int gpio, unsigned int reg)
 {
-       u32 base = geode_get_dev_base(GEODE_DEV_GPIO);
+       void __iomem *base = geode_get_dev_base(GEODE_DEV_GPIO);
 
-       if (!base)
+       if (base == NULL)
                return;
 
        if (gpio < 16)
-               outl(1 << gpio, base + reg);
+               iowrite32(1 << gpio, base + reg);
        else
-               outl(1 << (gpio - 16), base + 0x80 + reg);
+               iowrite32(1 << (gpio - 16), base + 0x80 + reg);
 }
 
 EXPORT_SYMBOL_GPL(geode_gpio_set);
 
-void
-geode_gpio_clear(unsigned int gpio, unsigned int reg)
+void geode_gpio_clear(unsigned int gpio, unsigned int reg)
 {
-       u32 base = geode_get_dev_base(GEODE_DEV_GPIO);
+       void __iomem *base = geode_get_dev_base(GEODE_DEV_GPIO);
 
-       if (!base)
+       if (base == NULL)
                return;
 
        if (gpio < 16)
-               outl(1 << (gpio + 16), base + reg);
+               iowrite32(1 << (gpio + 16), base + reg);
        else
-               outl(1 << gpio, base + 0x80 + reg);
+               iowrite32(1 << gpio, base + 0x80 + reg);
 }
 
 EXPORT_SYMBOL_GPL(geode_gpio_clear);
 
-int
-geode_gpio_isset(unsigned int gpio, unsigned int reg)
+int geode_gpio_isset(unsigned int gpio, unsigned int reg)
 {
-       u32 base = geode_get_dev_base(GEODE_DEV_GPIO);
+       void __iomem *base = geode_get_dev_base(GEODE_DEV_GPIO);
 
-       if (!base)
+       if (base == NULL)
                return 0;
 
        if (gpio < 16)
-               return (inl(base + reg) & (1 << gpio)) ? 1 :0;
+               return (ioread32(base + reg) & (1 << gpio)) ? 1 :0;
        else
-               return (inl(base + 0x80 + reg) & (1 << (gpio - 16))) ? 1 : 0;
+               return (ioread32(base + 0x80 + reg) & (1 << (gpio - 16))) ? 1 : 
0;
 }
 
 EXPORT_SYMBOL_GPL(geode_gpio_isset);
 
-void
-geode_gpio_set_pme(unsigned int gpio, int pair) {
-       u32 base = geode_get_dev_base(GEODE_DEV_GPIO);
+void geode_gpio_set_pme(unsigned int gpio, int pair) {
+       void __iomem *base = geode_get_dev_base(GEODE_DEV_GPIO);
        u32 offset, shift, val;
 
+       if (base == NULL)
+               return;
+
        if (gpio >= 24)
                offset = GPIO_MAP_W;
        else if (gpio >= 16)
@@ -101,9 +120,9 @@ geode_gpio_set_pme(unsigned int gpio, in
 
        shift = (gpio % 8) * 4;
 
-       val = inl(base + offset);
+       val = ioread32(base + offset);
        val |= ((pair & 7) << shift) | (1 << (shift + 3));
-       outl(val, base + offset);
+       iowrite32(val, base + offset);
 }
 
 /* === MFGPT API === */
@@ -119,10 +138,29 @@ static struct mfgpt_timer_t {
        int index;
        int flags;
        struct module *owner;
+       void (*suspend)(int);
+       void (*resume)(int);
 } mfgpt_timers[MFGPT_MAX_TIMERS];
 
-void
-geode_mfgpt_toggle_event(int timer, int cmp, int event, int setup)
+static int geode_mfgpt_suspend(pm_message_t state, void *data)
+{
+       int i;
+       for(i = 0; i < MFGPT_MAX_TIMERS; i++)
+               if (mfgpt_timers[i].owner && mfgpt_timers[i].suspend)
+                       mfgpt_timers[i].suspend(i);
+       return 0;
+}
+
+static int geode_mfgpt_resume(void *data)
+{
+       int i;
+       for(i = 0; i < MFGPT_MAX_TIMERS; i++)
+               if (mfgpt_timers[i].owner && mfgpt_timers[i].resume)
+                       mfgpt_timers[i].resume(i);
+       return 0;
+}
+
+void geode_mfgpt_toggle_event(int timer, int cmp, int event, int setup)
 {
        u32 msr, mask, value, dummy;
        int shift = (cmp == MFGPT_CMP1) ? 0 : 8;
@@ -159,8 +197,7 @@ geode_mfgpt_toggle_event(int timer, int 
 
 EXPORT_SYMBOL(geode_mfgpt_toggle_event);
 
-void
-geode_mfgpt_set_irq(int timer, int cmp, int irq, int setup)
+void geode_mfgpt_set_irq(int timer, int cmp, int irq, int setup)
 {
        u32 val, dummy;
        int offset;
@@ -181,26 +218,33 @@ geode_mfgpt_set_irq(int timer, int cmp, 
        wrmsr(0x51400022, val, dummy);
 }
 
-int
-geode_mfgpt_alloc_timer(int timer, int domain, struct module *owner)
+static inline void geode_mfgpt_init_timer(int timer,
+                                         struct geode_mfgpt_timer_t *req)
+{
+       mfgpt_timers[timer].flags &= ~F_AVAIL;
+       mfgpt_timers[timer].owner = req->owner;
+       mfgpt_timers[timer].suspend = req->suspend;
+       mfgpt_timers[timer].resume = req->resume;
+}
+
+int geode_mfgpt_alloc_timer(struct geode_mfgpt_timer_t *req)
 {
        int i;
-       u32 base = geode_get_dev_base(GEODE_DEV_MFGPT);
+       void __iomem *base = geode_get_dev_base(GEODE_DEV_MFGPT);
 
-       /* If they requested a specific timer, try to honor that */
-       if (!base)
+       if (base == NULL)
                return -ENODEV;
 
-       if (timer != MFGPT_TIMER_ANY) {
-               if (mfgpt_timers[timer].flags & F_AVAIL) {
-                       mfgpt_timers[timer].flags &= ~F_AVAIL;
-                       mfgpt_timers[timer].owner = owner;
+       /* If they requested a specific timer, try to honor that */
 
-                       printk("geode-mfgpt:  Registered timer %d\n", timer);
-                       return timer;
+       if (req->timer != MFGPT_TIMER_ANY) {
+               if (mfgpt_timers[req->timer].flags & F_AVAIL) {
+                       geode_mfgpt_init_timer(req->timer, req);
+                       printk(KERN_INFO MFGPT_NAME ": Registered timer %d\n", 
req->timer);
+                       return req->timer;
                }
-               else if (mfgpt_timers[timer].owner == owner)
-                       return timer;
+               else if (mfgpt_timers[req->timer].owner == req->owner)
+                       return req->timer;
 
                /* Request failed - somebody else owns it */
                return -1;
@@ -212,14 +256,12 @@ geode_mfgpt_alloc_timer(int timer, int d
 
                if ((mfgpt_timers[i].flags & F_AVAIL) &&
                    !(mfgpt_timers[i].flags & F_RESERVED)) {
-                       mfgpt_timers[i].flags &= ~F_AVAIL;
-                       mfgpt_timers[i].owner = owner;
-
-                       printk("geode-mfgpt:  Registered timer %d\n", i);
+                       geode_mfgpt_init_timer(i, req);
+                       printk(KERN_INFO MFGPT_NAME ": Registered timer %d\n", 
i);
                        return i;
                }
 
-               if (i == 5 && domain == MFGPT_DOMAIN_WORKING)
+               if (i == 5 && req->domain == MFGPT_DOMAIN_WORKING)
                        break;
        }
 
@@ -229,8 +271,7 @@ geode_mfgpt_alloc_timer(int timer, int d
 
 EXPORT_SYMBOL(geode_mfgpt_alloc_timer);
 
-static int
-mfgpt_setup_timer(int timer)
+static int mfgpt_setup_timer(int timer)
 {
        u16 val = geode_mfgpt_read(timer, MFGPT_REG_SETUP);
        mfgpt_timers[timer].index = timer;
@@ -261,8 +302,8 @@ #ifdef CONFIG_OLPC
          */
 
        {
-               u64 val = 0xFF; 
-               if (geode_mfgpt_read(1, MFGPT_REG_SETUP) & (1 << 12))   
+               u64 val = 0xFF;
+               if (geode_mfgpt_read(1, MFGPT_REG_SETUP) & (1 << 12))
                        wrmsrl(0x5140002B, val);
        }
 #endif
@@ -270,29 +311,100 @@ #endif
        for(i = 0; i < MFGPT_MAX_TIMERS; i++)
                count += mfgpt_setup_timer(i);
 
-       printk(KERN_INFO "geode-mfgpt:  %d timers available.\n", count);
+
+       geode_set_pm_hooks(GEODE_DEV_MFGPT, geode_mfgpt_suspend,
+               geode_mfgpt_resume, NULL);
+
+       if (count > 0)
+               printk(KERN_INFO MFGPT_NAME ": %d timers available.\n", count);
+       else
+               printk(KERN_ERR MFGPT_NAME ": No timers are available. Your 
BIOS is broken.\n");
 }
 
-static int __init
-geode_southbridge_init(void) {
+#ifdef CONFIG_PM
 
-       u32 lo, hi;
+static int geode_dev_suspend(struct pci_dev *pdev,  pm_message_t state)
+{
        int i;
 
-       if (!is_geode())
-               return -1;
+       if (pdev->dev.power.power_state.event == state.event)
+                return 0;
+
+       for(i = 0; i < ARRAY_SIZE(geode_devices); i++)
+               if (geode_devices[i].suspend)
+                       geode_devices[i].suspend(state,
+                                                geode_devices[i].data);
+
+       pdev->dev.power.power_state = state;
+        return 0;
+}
+
+static int geode_dev_resume(struct pci_dev *pdev)
+{
+       int i;
+
+       for(i = 0; i < ARRAY_SIZE(geode_devices); i++)
+               if (geode_devices[i].resume)
+                       geode_devices[i].resume(geode_devices[i].data);
+
+       pdev->dev.power.power_state = PMSG_ON;
+       return 0;
+}
+
+#endif
+
+static int __init geode_dev_probe(struct pci_dev *dev,
+                                 const struct pci_device_id *id)
+{
+       int ret, i;
+
+       if ((ret = pci_enable_device(dev)) < 0)
+               return ret;
+
+       /* Allocate the bars for the device */
+
+       for(i = 0; i < ARRAY_SIZE(geode_devices); i++) {
+               ret = pci_request_region(dev, i, geode_devices[i].name);
+               if (ret < 0) {
+                       printk(KERN_ERR "geode: Unable to request region for 
%s\n",
+                              geode_devices[i].name);
+                       continue;
+               }
 
-       for(i = 0; i < ARRAY_SIZE(lbars); i++) {
-               rdmsr(lbars[i].msr, lo, hi);
-               if (hi & 0x01) 
-                       lbars[i].base = lo & 0x0000ffff;
+               geode_devices[i].base = pci_iomap(dev, i, 0);
 
-               if (lbars[i].base == 0)
-                       printk(KERN_ERR "geode:  Couldn't initialize '%s'\n", 
lbars[i].name);
+               if (!geode_devices[i].base)
+                       printk(KERN_ERR "geode: Unable to allocate memory for 
%s\n",
+                              geode_devices[i].name);
        }
 
        geode_mfgpt_init();
        return 0;
 }
 
-subsys_initcall(geode_southbridge_init);
+static struct pci_device_id geode_dev_id_table[] = {
+       { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA) },
+       { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) },
+};
+
+MODULE_DEVICE_TABLE(pci, geode_sb_id_table);
+
+static struct pci_driver geode_dev_driver = {
+       .name = "geode-southbridge",
+       .id_table = geode_dev_id_table,
+       .probe = geode_dev_probe,
+#ifdef CONFIG_PM
+       .suspend = geode_dev_suspend,
+       .resume = geode_dev_resume
+#endif
+};
+
+static int __init geode_southbridge_init(void) {
+
+       if (is_geode())
+               return pci_register_driver(&geode_dev_driver);
+       else 
+               return -1;
+}
+
+fs_initcall(geode_southbridge_init);
diff --git a/arch/i386/kernel/olpc-pm.c b/arch/i386/kernel/olpc-pm.c
index 4655b13..a7f0c55 100644
--- a/arch/i386/kernel/olpc-pm.c
+++ b/arch/i386/kernel/olpc-pm.c
@@ -37,8 +37,8 @@ extern char wakeup_start, wakeup_end;
 extern void do_olpc_suspend_lowlevel(void);
 extern unsigned long FASTCALL(olpc_copy_wakeup_routine(unsigned long));
 
-static unsigned long acpi_base;
-static unsigned long pms_base;
+static void __iomem * acpi_base;
+static void __iomem * pms_base;
 static int sci;
 static int olpc_lid_flag;
 
@@ -50,12 +50,12 @@ olpc_pm_interrupt(int irq, void *id)
 {
        uint32_t sts, gpe = 0;
 
-       sts = inl(acpi_base + PM1_STS);
-       outl(sts | 0xFFFF, acpi_base + PM1_STS);
+       sts = ioread32(acpi_base + PM1_STS);
+       iowrite32(sts | 0xFFFF, acpi_base + PM1_STS);
 
        if (olpc_get_rev() == OLPC_REV_B2) {
-               gpe = inl(acpi_base + PM_GPE0_STS);
-               outl(gpe | 0xFFFFFFFF, acpi_base + PM_GPE0_STS);
+               gpe = ioread32(acpi_base + PM_GPE0_STS);
+               iowrite32(gpe | 0xFFFFFFFF, acpi_base + PM_GPE0_STS);
        }
 
        if (sts & CS5536_PM_PWRBTN) {
@@ -125,63 +125,18 @@ static int olpc_pm_enter (suspend_state_
        return 0;
 }
 
-/* Put the memory into self refresh and go to sleep */
-
-static inline void olpc_sleep_asm(void)
-{
-  __asm__ __volatile__( "add $0x08, %%bx\n\t"
-                       "movw %%bx, %%dx\n\t"
-                       "inl %%dx, %%eax\n\t"
-                       "or $0x2000, %%ax\n\t"
-                       "movw %%ax, %%di\n\t"
-                       "wbinvd\n\t"
-                       "movl $0x20000018, %%ecx\n\t"
-                       "rdmsr\n\t"
-                       "and $0xFF0000FF, %%eax\n\t"
-                       "wrmsr\n\t"
-                       "movw $0x2004, %%cx\n\t"
-                       "xor %%edx, %%edx\n\t"
-                       "xor %%eax, %%eax\n\t"
-                       "movb $0x04, %%al\n\t"
-                       "wrmsr\n\t"
-                       "movw %%bx, %%dx\n\t"
-                       "movzx %%di, %%eax\n\t"
-                       "outl %%eax, %%dx\n\t"
-                       : : "b" (acpi_base));
-}
-
-#define PM_SCLK_VAL  0x40000e00 /* [29:0] is the delay */
-#define PM_SED_VAL   0x40004601 /* [29:0] is the delay */
-#define PM_WKXD_VAL  0x040000a0 /* [19:0] is the delay */
+/* This function handles any last minute configuration that we want 
+   to do before we go to sleep.  Mainly this will involve setting 
+   wake events. This is called from do_olpc_suspend_lowlevel */
 
 int asmlinkage
-olpc_enter_sleep_state(u8 sleep_state)
+olpc_setup_sleep_state(u8 sleep_state)
 {
-       /* Set up the PMC sleep clock */
-       outl(PM_SCLK_VAL, pms_base + PM_SCLK);
-
-       /* Set up the Sleep End Delay */
-       outl(PM_SED_VAL, pms_base + PM_SED);
-
-       /* Set up the WORK_AUX delay */
-       outl(PM_WKXD_VAL, pms_base + PM_WKXD);
-
-       /* Clear PM_SSC */
-       outl(0x2FFFF, pms_base + PM_SSC);
-
-       /* Save ourselves a read by setting the SCI events again here -
-        * we have to write the register anyway */
+       /* FIXME: Set the SCI bits we want to wake up on here */
 
-       /* FIXME:  Set any other SCI events that we might want here */
-
-       outl((CS5536_PM_PWRBTN << 16) | 0xFFFF, acpi_base + PM1_STS);
-
-       /* FIXME: Set any GPE events that we want here */
-       /* FIXME: Clear pending GPE events if we end up using any */
-
-       /* Actually go to sleep */
-       olpc_sleep_asm();
+       iowrite32((CS5536_PM_PWRBTN << 16) | 0xFFFF, acpi_base + PM1_STS);
 
+       /* FIXME: Set the GPE0 bits we want to wake on here */
        return 0;
 }
 
@@ -245,17 +200,6 @@ #ifdef ENABLE_EC_SCI
 #endif
 }
 
-void __init
-olpc_reserve_bootmem(void)
-{
-  olpc_wakeup_address = (unsigned long)alloc_bootmem_low(PAGE_SIZE);
-
-  if (!olpc_wakeup_address) {
-    printk(KERN_ERR "olpc-pm:  Could not allocate lowmem - suspend is 
disabled.\n");
-    return;
-  }
-}
-
 static int __init olpc_pm_init(void)
 {
        uint32_t lo, hi;
@@ -268,7 +212,7 @@ static int __init olpc_pm_init(void)
        acpi_base = geode_acpi_base();
        pms_base = geode_pms_base();
 
-       if (!acpi_base || !pms_base)
+       if (acpi_base == NULL || pms_base == NULL)
          return -ENODEV;
 
        pm_inputdev = input_allocate_device();
@@ -278,10 +222,10 @@ static int __init olpc_pm_init(void)
 
        olpc_fixup_bios();
 
-       lo = inl(pms_base + PM_FSD);
+       lo = ioread32(pms_base + PM_FSD);
 
        /* Lock, enable failsafe, 4 seconds */
-       outl(0xc001f400, pms_base + PM_FSD);
+       iowrite32(0xc001f400, pms_base + PM_FSD);
 
        rdmsr(0x51400020, lo, hi);
        sci = (lo >> 20) & 15;
@@ -323,11 +267,11 @@ static int __init olpc_pm_init(void)
         * sense, so set up the power button
         */
 
-       outl(inl(acpi_base) | ((CS5536_PM_PWRBTN) << 16), acpi_base);
+       iowrite32(ioread32(acpi_base) | ((CS5536_PM_PWRBTN) << 16), acpi_base);
 
 
        /* Set up the GPE events */
-       val = inl(acpi_base + PM_GPE0_EN);
+       val = ioread32(acpi_base + PM_GPE0_EN);
 
        if (olpc_get_rev() == OLPC_REV_B2) {
                val |= (1 << 30);
@@ -350,7 +294,7 @@ #ifdef ENABLE_EC_SCI
        val |= (1 << 31);
 #endif
 
-       outl(val, acpi_base + PM_GPE0_EN);
+       iowrite32(val, acpi_base + PM_GPE0_EN);
 
 
        /* Select level triggered in PIC */
@@ -365,7 +309,7 @@ #endif
                outb(lo, 0x4d1);
        }
        /* Clear pending interrupt */
-       outl(inl(acpi_base) | 0xFFFF, acpi_base);
+       iowrite32(ioread32(acpi_base) | 0xFFFF, acpi_base);
 
        pm_set_ops(&olpc_pm_ops);
 
@@ -375,7 +319,7 @@ #endif
 static void olpc_pm_exit(void)
 {
        /* Clear any pending events, and disable them */
-       outl(0xFFFF, acpi_base+2);
+       iowrite32(0xFFFF, acpi_base+2);
 
        free_irq(sci, &acpi_base);
        input_unregister_device(pm_inputdev);
diff --git a/arch/i386/kernel/olpc-wakeup.S b/arch/i386/kernel/olpc-wakeup.S
index 21ef6b2..c344a7f 100644
--- a/arch/i386/kernel/olpc-wakeup.S
+++ b/arch/i386/kernel/olpc-wakeup.S
@@ -3,226 +3,49 @@ #include <linux/linkage.h>
 #include <asm/segment.h>
 #include <asm/page.h>
 
-#
-# wakeup_code runs in real mode, and at unknown address (determined at 
run-time).
-# Therefore it must only use relative jumps/calls. 
-#
-# Do we need to deal with A20? It is okay: ACPI specs says A20 must be enabled
-#
-# If physical address of wakeup_code is 0x12345, BIOS should call us with
-# cs = 0x1234, eip = 0x05
-# 
-
-ALIGN
-       .align  4096
-ENTRY(wakeup_start)
-wakeup_code:
-       wakeup_code_start = .
-       .code16
-
-       movw    $0xb800, %ax
-       movw    %ax,%fs
-
-       cli
-       cld
-
-       # setup data segment
-       movw    %cs, %ax
-       movw    %ax, %ds                                        # Make ds:0 
point to wakeup_start
-       movw    %ax, %ss
-       mov     $(wakeup_stack - wakeup_code), %sp              # Private stack 
is needed for ASUS board
-
-       pushl   $0                                              # Kill any 
dangerous flags
-       popfl
-
-       movl    real_magic - wakeup_code, %eax
-       cmpl    $0x12345678, %eax
-       jne     bogus_real_magic
-
-       # set up page table
-       movl    $swsusp_pg_dir-__PAGE_OFFSET, %eax
-       movl    %eax, %cr3
-
-       testl   $1, real_efer_save_restore - wakeup_code
-       jz      4f
-       # restore efer setting
-       movl    real_save_efer_edx - wakeup_code, %edx
-       movl    real_save_efer_eax - wakeup_code, %eax
-       mov     $0xc0000080, %ecx
-       wrmsr
-4:
-       # make sure %cr4 is set correctly (features, etc)
-       movl    real_save_cr4 - wakeup_code, %eax
-       movl    %eax, %cr4
-       movw    $0xb800, %ax
-       movw    %ax,%fs
-       
-       # need a gdt -- use lgdtl to force 32-bit operands, in case
-       # the GDT is located past 16 megabytes.
-       lgdtl   real_save_gdt - wakeup_code
-
-       movl    real_save_cr0 - wakeup_code, %eax
-       movl    %eax, %cr0
-       jmp 1f
-1:
-
-       movl    real_magic - wakeup_code, %eax
-       cmpl    $0x12345678, %eax
-       jne     bogus_real_magic
-
-       ljmpl   $__KERNEL_CS,$wakeup_pmode_return
-
-real_save_gdt: .word 0
-               .long 0
-real_save_cr0: .long 0
-real_save_cr3: .long 0
-real_save_cr4: .long 0
-real_magic:    .long 0
-real_efer_save_restore:        .long 0
-real_save_efer_edx:    .long 0
-real_save_efer_eax:    .long 0
-
-bogus_real_magic:
-       jmp bogus_real_magic
-
-setbad:        clc
-       ret
-
-_setbad: jmp setbad
-
-       .code32
-       ALIGN
-
-.org   0x800
-wakeup_stack_begin:    # Stack grows down
-
-.org   0xff0           # Just below end of page
-wakeup_stack:
-ENTRY(wakeup_end)
-       
-.org   0x1000
-
-wakeup_pmode_return:
-       movw    $__KERNEL_DS, %ax
-       movw    %ax, %ss
-       movw    %ax, %ds
-       movw    %ax, %es
-       movw    %ax, %fs
-       movw    %ax, %gs
-
-       # reload the gdt, as we need the full 32 bit address
-       lgdt    saved_gdt
-       lidt    saved_idt
-       lldt    saved_ldt
-       ljmp    $(__KERNEL_CS),$1f
-1:
-       movl    %cr3, %eax
-       movl    %eax, %cr3
-       wbinvd
-
-       # and restore the stack ... but you need gdt for this to work
-       movl    saved_context_esp, %esp
-
-       movl    %cs:saved_magic, %eax
-       cmpl    $0x12345678, %eax
-       jne     bogus_magic
-
-       # jump to place where we left off
-       movl    saved_eip,%eax
-       jmp     *%eax
-
-bogus_magic:
-       jmp     bogus_magic
-
-
-##
-# olpc_copy_wakeup_routine
-#
-# Copy the above routine to low memory.
-#
-# Parameters:
-# %eax:        place to copy wakeup routine to
-#
-# Returned address is location of code in low memory (past data and stack)
-#
-ENTRY(olpc_copy_wakeup_routine)
-
-       sgdt    saved_gdt
-       sidt    saved_idt
-       sldt    saved_ldt
-       str     saved_tss
-
-       movl    nx_enabled, %edx
-       movl    %edx, real_efer_save_restore - wakeup_start (%eax)
-       testl   $1, real_efer_save_restore - wakeup_start (%eax)
-       jz      2f
-       # save efer setting
-       pushl   %eax
-       movl    %eax, %ebx
-       mov     $0xc0000080, %ecx
-       rdmsr
-       movl    %edx, real_save_efer_edx - wakeup_start (%ebx)
-       movl    %eax, real_save_efer_eax - wakeup_start (%ebx)
-       popl    %eax
-2:
-
-       movl    %cr3, %edx
-       movl    %edx, real_save_cr3 - wakeup_start (%eax)
-       movl    %cr4, %edx
-       movl    %edx, real_save_cr4 - wakeup_start (%eax)
-       movl    %cr0, %edx
-       movl    %edx, real_save_cr0 - wakeup_start (%eax)
-       sgdt    real_save_gdt - wakeup_start (%eax)
-
-       movl    $0x12345678, real_magic - wakeup_start (%eax)
-       movl    $0x12345678, saved_magic
-       ret
+# OFW will remember most of the protected mode settings - we just need
+# to worry about saving the current state, and then pass control to
+# OFW.  The very last C setup we do will be done by olpc_setup_sleep_state()
+# which will configure the wakeup events
 
 save_registers:
-       leal    4(%esp), %eax
-       movl    %eax, saved_context_esp
-       movl %ebx, saved_context_ebx
-       movl %ebp, saved_context_ebp
-       movl %esi, saved_context_esi
-       movl %edi, saved_context_edi
-       pushfl ; popl saved_context_eflags
-
-       movl $ret_point, saved_eip
-       ret
+        leal (%esp), %eax
+        movl %eax, saved_context_esp
+        movl %ebx, saved_context_ebx
+        movl %ebp, saved_context_ebp
+        movl %esi, saved_context_esi
+        movl %edi, saved_context_edi
+        pushfl ; popl saved_context_eflags
+        ret
 
 
 restore_registers:
-       movl saved_context_ebp, %ebp
-       movl saved_context_ebx, %ebx
-       movl saved_context_esi, %esi
-       movl saved_context_edi, %edi
-       pushl saved_context_eflags ; popfl
-       ret     
+        movl saved_context_ebp, %ebp
+        movl saved_context_ebx, %ebx
+        movl saved_context_esi, %esi
+        movl saved_context_edi, %edi
+        pushl saved_context_eflags ; popfl
+        ret
 
+       
 ENTRY(do_olpc_suspend_lowlevel)
        call    save_processor_state
        call    save_registers
        pushl   $3
-       call    olpc_enter_sleep_state
+       call    olpc_setup_sleep_state
        addl    $4, %esp
 
-#      In case of S3 failure, we'll emerge here.  Jump
-#      to ret_point to recover
+#      We're ready to sleep - go, go, gadget sleep
+       mov     $0xf0000,%eax
+       lcall   *(%eax)
+       
+#      We are back - restore the stack
+       movl    saved_context_esp, %esp
+               
+#      Jump to the return point and restore our state
        jmp     ret_point
        .p2align 4,,7
 ret_point:
        call    restore_registers
        call    restore_processor_state
        ret
-
-.data
-ALIGN
-ENTRY(saved_magic)     .long   0
-ENTRY(saved_eip)       .long   0
-
-# saved registers
-saved_gdt:     .long   0,0
-saved_idt:     .long   0,0
-saved_ldt:     .long   0
-saved_tss:     .long   0
-
diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c
index 0b476e1..122623d 100644
--- a/arch/i386/kernel/setup.c
+++ b/arch/i386/kernel/setup.c
@@ -437,11 +437,6 @@ #ifdef CONFIG_ACPI_SLEEP
         */
        acpi_reserve_bootmem();
 #endif
-#ifdef CONFIG_OLPC_PM
-       /* Reserve low memory for OLPC resume
-        */
-       olpc_reserve_bootmem();
-#endif
 #ifdef CONFIG_X86_FIND_SMP_CONFIG
        /*
         * Find and reserve possible boot-time SMP configuration:
diff --git a/drivers/clocksource/mfgpt.c b/drivers/clocksource/mfgpt.c
index 67f3e33..4f2cecf 100644
--- a/drivers/clocksource/mfgpt.c
+++ b/drivers/clocksource/mfgpt.c
@@ -1,6 +1,6 @@
 /* Driver/API for AMD Geode Multi-Function General Purpose Timers (MFGPT)
  *
- * Copyright (C) 2006, Advanced Micro Devices, Inc.
+ * Copyright (C) 2006-2007, Advanced Micro Devices, Inc.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -125,6 +125,22 @@ static irqreturn_t mfgpt_tick(int irq, v
        return IRQ_HANDLED;
 }
 
+static void mfgpt_timer_do_setup(void)
+{
+       geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_SETUP,
+                         MFGPT_SCALE | MFGPT_SETUP_CMP2_EVENT);
+
+       geode_mfgpt_setup_irq(mfgpt_event_clock, MFGPT_CMP2, irq);
+}
+
+static void mfgpt_timer_resume(int timer)
+{
+       if (timer != mfgpt_event_clock)
+               return;
+
+       mfgpt_timer_do_setup();
+}
+
 static struct irqaction mfgptirq  = {
        .handler = mfgpt_tick,
        .flags = IRQF_DISABLED | IRQF_NOBALANCING,
@@ -132,14 +148,21 @@ static struct irqaction mfgptirq  = {
        .name = "mfgpt-timer"
 };
 
-static int __init
-mfgpt_timer_setup(void)
+/* Note that we don't have a suspend hook - the setup value is known,
+ * so we don't really need to save it off.
+*/
+
+struct geode_mfgpt_timer_t tick_timer = {
+       .timer = MFGPT_TIMER_ANY,
+       .domain = MFGPT_DOMAIN_WORKING,
+       .owner = THIS_MODULE,
+       .resume = mfgpt_timer_resume
+};
+
+static int __init mfgpt_timer_setup(void)
 {
        int ret;
-       u16 val;
-
-       int timer = geode_mfgpt_alloc_timer(MFGPT_TIMER_ANY,
-       MFGPT_DOMAIN_WORKING, THIS_MODULE);
+       int timer = geode_mfgpt_alloc_timer(&tick_timer);
 
        if (timer < 0) {
                printk(KERN_ERR "mfgpt-timer:  Could not allocate a MFPGT 
timer\n");
@@ -147,13 +170,8 @@ mfgpt_timer_setup(void)
        }
 
        mfgpt_event_clock = timer;
-       /* Set the clock scale and enable the event mode for CMP2 */
-       val = MFGPT_SCALE | (3 << 8);
 
-       geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_SETUP, val);
-
-       /* Set up the IRQ on the MFGPT side */
-       geode_mfgpt_setup_irq(mfgpt_event_clock, MFGPT_CMP2, irq);
+       mfgpt_timer_do_setup();
 
        /* And register it with the kernel */
         ret = setup_irq(irq, &mfgptirq);
diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c
index e0eb06b..3d0988a 100644
--- a/drivers/i2c/busses/scx200_acb.c
+++ b/drivers/i2c/busses/scx200_acb.c
@@ -35,6 +35,7 @@ #include <linux/mutex.h>
 #include <asm/io.h>
 
 #include <linux/scx200.h>
+#include <asm/geode.h>
 
 #define NAME "scx200_acb"
 
@@ -73,6 +74,9 @@ static const char *scx200_acb_state_name
        "write",
 };
 
+#define IFACE_TYPE_ISA 0
+#define IFACE_TYPE_PCI 1
+
 /* Physical interface */
 struct scx200_acb_iface {
        struct scx200_acb_iface *next;
@@ -89,9 +93,7 @@ struct scx200_acb_iface {
        char needs_reset;
        unsigned len;
 
-       /* PCI device info */
-       struct pci_dev *pdev;
-       int bar;
+       int type;
 };
 
 /* Register Definitions */
@@ -488,41 +490,44 @@ static int __init scx200_acb_create(stru
        return 0;
 }
 
-static __init int scx200_create_pci(const char *text, struct pci_dev *pdev,
-               int bar)
+/* We don't need a suspend function -- the state will be retored on resume */
+
+static int scx200_resume(void *data)
+{
+       struct scx200_acb_iface *iface = (struct scx200_acb_iface *) data;
+
+       if (iface)
+               scx200_acb_reset(iface);
+
+       return 0;
+}
+
+static __init int scx200_create_geode_dev(const char *text)
 {
        struct scx200_acb_iface *iface;
+       unsigned long base = (unsigned long) geode_smbus_base();
        int rc;
 
-       iface = scx200_create_iface(text, &pdev->dev, 0);
+       if (base == 0)
+               return -ENODEV;
+
+       iface = scx200_create_iface(text, NULL, 0);
 
        if (iface == NULL)
                return -ENOMEM;
 
-       iface->pdev = pdev;
-       iface->bar = bar;
-
-       rc = pci_enable_device_bars(iface->pdev, 1 << iface->bar);
-       if (rc)
-               goto errout_free;
-
-       rc = pci_request_region(iface->pdev, iface->bar, iface->adapter.name);
-       if (rc) {
-               printk(KERN_ERR NAME ": can't allocate PCI BAR %d\n",
-                               iface->bar);
-               goto errout_free;
-       }
+       iface->base = base;
+       iface->type = IFACE_TYPE_PCI;
 
-       iface->base = pci_resource_start(iface->pdev, iface->bar);
        rc = scx200_acb_create(iface);
 
+       /* Set up the power management hooks for the device */
+
        if (rc == 0)
-               return 0;
+               geode_set_pm_hooks(GEODE_DEV_SMB, NULL, scx200_resume, iface);
+       else
+               kfree(iface);
 
-       pci_release_region(iface->pdev, iface->bar);
-       pci_dev_put(iface->pdev);
- errout_free:
-       kfree(iface);
        return rc;
 }
 
@@ -545,6 +550,8 @@ static int __init scx200_create_isa(cons
        }
 
        iface->base = base;
+       iface->type = IFACE_TYPE_ISA;
+
        rc = scx200_acb_create(iface);
 
        if (rc == 0)
@@ -556,84 +563,67 @@ static int __init scx200_create_isa(cons
        return rc;
 }
 
-/* Driver data is an index into the scx200_data array that indicates
- * the name and the BAR where the I/O address resource is located.  ISA
- * devices are flagged with a bar value of -1 */
-
-static struct pci_device_id scx200_pci[] = {
-       { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE),
-         .driver_data = 0 },
-       { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE),
-         .driver_data = 0 },
-       { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA),
-         .driver_data = 1 },
-       { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA),
-         .driver_data = 2 }
-};
-
-static struct {
-       const char *name;
-       int bar;
-} scx200_data[] = {
-       { "SCx200", -1 },
-       { "CS5535",  0 },
-       { "CS5536",  0 }
-};
-
-static __init int scx200_scan_pci(void)
+static __init int scx200_do_scan(void)
 {
-       int data, dev;
-       int rc = -ENODEV;
        struct pci_dev *pdev;
+       int ret;
 
-       for(dev = 0; dev < ARRAY_SIZE(scx200_pci); dev++) {
-               pdev = pci_get_device(scx200_pci[dev].vendor,
-                               scx200_pci[dev].device, NULL);
+       /* Search for a PCI device that will give us a clue as to which
+          SMBUS block we are dealing with. */
 
-               if (pdev == NULL)
-                       continue;
+       /* First - search for the SC1100/SC1200 device */
 
-               data = scx200_pci[dev].driver_data;
+       pdev = pci_get_device(PCI_VENDOR_ID_NS,
+               PCI_DEVICE_ID_NS_SCx200_BRIDGE, 0);
+       if (pdev == NULL)
+               pci_get_device(PCI_VENDOR_ID_NS,
+                       PCI_DEVICE_ID_NS_SC1100_BRIDGE, 0);
 
-               /* if .bar is greater or equal to zero, this is a
-                * PCI device - otherwise, we assume
-                  that the ports are ISA based
-               */
+       /* For SC1100/SC1200 devices - use the ISA ports */
 
-               if (scx200_data[data].bar >= 0)
-                       rc = scx200_create_pci(scx200_data[data].name, pdev,
-                                       scx200_data[data].bar);
-               else {
-                       int i;
+       if (pdev != NULL) {
+               int i;
 
-                       for (i = 0; i < MAX_DEVICES; ++i) {
-                               if (base[i] == 0)
-                                       continue;
+               for (i = 0; i < MAX_DEVICES; ++i) {
+                       if (base[i] == 0)
+                               continue;
 
-                               rc = scx200_create_isa(scx200_data[data].name,
-                                               base[i],
-                                               i);
-                       }
+                       ret = scx200_create_isa("SCx200", base[i], i);
                }
 
-               break;
+               return ret;
        }
 
-       return rc;
+       /* Now - we're on the hunt for a 5535 or 5536.  Since both chips
+          combine the SMBUS resources on the PCI header with 5 other
+          different devices, we can't just take over the PCI device.
+          Use the special Geode API to get the resources
+       */
+
+       pdev = pci_get_device(PCI_VENDOR_ID_AMD,
+               PCI_DEVICE_ID_AMD_CS5536_ISA, 0);
+       if (pdev == NULL)
+               pdev = pci_get_device(PCI_VENDOR_ID_NS,
+                       PCI_DEVICE_ID_NS_CS5535_ISA, 0);
+
+       /* Found a 5535 / 5536 */
+
+       if (pdev != NULL)
+               return scx200_create_geode_dev("CS553X");
+
+       /* Nothing suitable was found */
+       return -ENODEV;
 }
 
 static int __init scx200_acb_init(void)
 {
        int rc;
 
-       pr_debug(NAME ": NatSemi SCx200 ACCESS.bus Driver\n");
+       pr_debug(NAME ": Geode SCx200/CS553x ACCESS.bus driver\n");
 
-       rc = scx200_scan_pci();
+       rc = scx200_do_scan();
 
-       /* If at least one bus was created, init must succeed */
-       if (scx200_acb_list)
-               return 0;
-       return rc;
+       return (scx200_acb_list) ? 0 : rc;
 }
 
 static void __exit scx200_acb_cleanup(void)
@@ -647,12 +637,10 @@ static void __exit scx200_acb_cleanup(vo
 
                i2c_del_adapter(&iface->adapter);
 
-               if (iface->pdev) {
-                       pci_release_region(iface->pdev, iface->bar);
-                       pci_dev_put(iface->pdev);
-               }
-               else
+               if (iface->type == IFACE_TYPE_ISA)
                        release_region(iface->base, 8);
+               else
+                       geode_set_pm_hooks(GEODE_DEV_SMB, NULL, NULL, NULL);
 
                kfree(iface);
                down(&scx200_acb_list_mutex);
diff --git a/include/asm-i386/geode.h b/include/asm-i386/geode.h
index f9f29ec..2c5e53d 100644
--- a/include/asm-i386/geode.h
+++ b/include/asm-i386/geode.h
@@ -10,24 +10,31 @@
 #ifndef _ASM_GEODE_H_
 #define _ASM_GEODE_H_
 
+#include <linux/io.h>
 #include <asm/processor.h>
 #include <asm/io.h>
 
 /* Generic southbridge functions */
 
-#define GEODE_DEV_PMS 0
-#define GEODE_DEV_ACPI 1
-#define GEODE_DEV_GPIO 2
-#define GEODE_DEV_MFGPT 3
+#define GEODE_DEV_SMB   0
+#define GEODE_DEV_GPIO  1
+#define GEODE_DEV_MFGPT 2
+#define GEODE_DEV_IRQ   3
+#define GEODE_DEV_PMS   4
+#define GEODE_DEV_ACPI  5
 
 /* Useful macros */
 
-extern int geode_get_dev_base(unsigned int);
+void __iomem * geode_get_dev_base(unsigned int);
+void geode_set_pm_hooks(unsigned int,
+                       int (*suspend)(pm_message_t, void *),
+                       int (*resume)(void *), void *);
 
 #define geode_pms_base() geode_get_dev_base(GEODE_DEV_PMS)
 #define geode_acpi_base() geode_get_dev_base(GEODE_DEV_ACPI)
 #define geode_gpio_base() geode_get_dev_base(GEODE_DEV_GPIO)
 #define geode_mfgpt_base() geode_get_dev_base(GEODE_DEV_MFGPT)
+#define geode_smbus_base() geode_get_dev_base(GEODE_DEV_SMB)
 
 /* MSRS */
 
@@ -71,7 +78,7 @@ #define PM_SCXA                0x04
 #define PM_SCYA                0x08
 #define PM_OUT_SLPCTL          0x0C
 #define PM_SCLK                0x10
-#define PM_SED                 0x1
+#define PM_SED                 0x14
 #define PM_SCXD                0x18
 #define PM_SCYD                0x1C
 #define PM_IN_SLPCTL           0x20
@@ -135,6 +142,7 @@ #define MFGPT_EVENT_NMI   1
 #define MFGPT_EVENT_RESET 3
 
 #define MFGPT_REG_CMP1    0
+
 #define MFGPT_REG_CMP2    2
 #define MFGPT_REG_COUNTER 4
 #define MFGPT_REG_SETUP   6
@@ -145,26 +153,52 @@ #define MFGPT_SETUP_CMP1   (1 << 13)
 #define MFGPT_SETUP_SETUP  (1 << 12)
 #define MFGPT_SETUP_STOPEN (1 << 11)
 #define MFGPT_SETUP_EXTEN  (1 << 10)
+
+#define MFGPT_SETUP_CMP2_DISABLE 0
+#define MFGPT_SETUP_CMP2_EQUAL   (1 << 8)
+#define MFGPT_SETUP_CMP2_GE      (2 << 8)
+#define MFGPT_SETUP_CMP2_EVENT   (3 << 8)
+
+#define MFGPT_SETUP_CMP1_DISABLE 0
+#define MFGPT_SETUP_CMP1_EQUAL   (1 << 6)
+#define MFGPT_SETUP_CMP1_GE      (2 << 6)
+#define MFGPT_SETUP_CMP1_EVENT   (3 << 6)
+
+
 #define MFGPT_SETUP_REVEN  (1 << 5)
 #define MFGPT_SETUP_CLKSEL (1 << 4)
 
+struct geode_mfgpt_timer_t {
+       int timer;
+       int domain;
+       struct module *owner;
+       void (*suspend)(int);
+       void (*resume)(int);
+};
+
 static inline void
 geode_mfgpt_write(int i, u16 r, u16 v)
 {
-       u32 base = geode_get_dev_base(GEODE_DEV_MFGPT);
-       outw(v, base + r + (i * 8));
+       void __iomem *base = geode_get_dev_base(GEODE_DEV_MFGPT);
+       iowrite16(v, base + r + (i * 8));
 }
 
 static inline u16
 geode_mfgpt_read(int i, u16 r)
 {
-       u32 base = geode_get_dev_base(GEODE_DEV_MFGPT);
-       return inw(base + r + (i * 8));
+       void __iomem *base = geode_get_dev_base(GEODE_DEV_MFGPT);
+       return ioread16(base + r + (i * 8));
 }
 
+void geode_mfgpt_set_irq(int, int, int, int);
+int geode_mfgpt_alloc_timer(struct geode_mfgpt_timer_t *);
+void geode_mfgpt_toggle_event(int, int, int, int);
+
 #define geode_mfgpt_setup_irq(t,c,i) geode_mfgpt_set_irq((t),(c),(i),1)
 #define geode_mfgpt_release_irq(t,c,i) geode_mfgpt_set_irq((t),(c),(i),0)
 
+/* Generic Geode macros */
+
 static inline int
 is_geode_gx(void) {
        return ((boot_cpu_data.x86_vendor == X86_VENDOR_NSC) &&


_______________________________________________
Devel mailing list
[email protected]
http://mailman.laptop.org/mailman/listinfo/devel

Reply via email to