diff options
author | ryd <ryd@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2008-02-19 04:03:49 +0000 |
---|---|---|
committer | ryd <ryd@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2008-02-19 04:03:49 +0000 |
commit | e4a3634c00818e77664da2c3592a95e8c8fad5d6 (patch) | |
tree | 5aec8287ecd3034c53cbbeb5a6408389b1d34507 /target/linux/olpc/files/arch/i386/kernel | |
parent | ac24192a897d17c7416cfc1a58ad5432404662de (diff) |
Adding .24 support for olpc
kernel compiles fine, but graphic support is broken
to test new kernel version, change
target/linux/olpc/Makefile
from .23.16 to .24
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@10493 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'target/linux/olpc/files/arch/i386/kernel')
-rw-r--r-- | target/linux/olpc/files/arch/i386/kernel/mfgpt.c | 354 | ||||
-rw-r--r-- | target/linux/olpc/files/arch/i386/kernel/ofw.c | 100 | ||||
-rw-r--r-- | target/linux/olpc/files/arch/i386/kernel/olpc-pm.c | 785 | ||||
-rw-r--r-- | target/linux/olpc/files/arch/i386/kernel/olpc-sleep.S | 39 | ||||
-rw-r--r-- | target/linux/olpc/files/arch/i386/kernel/olpc-wakeup.S | 122 | ||||
-rw-r--r-- | target/linux/olpc/files/arch/i386/kernel/olpc.c | 320 | ||||
-rw-r--r-- | target/linux/olpc/files/arch/i386/kernel/prom.c | 478 |
7 files changed, 0 insertions, 2198 deletions
diff --git a/target/linux/olpc/files/arch/i386/kernel/mfgpt.c b/target/linux/olpc/files/arch/i386/kernel/mfgpt.c deleted file mode 100644 index 2e62a41e7f..0000000000 --- a/target/linux/olpc/files/arch/i386/kernel/mfgpt.c +++ /dev/null @@ -1,354 +0,0 @@ -/* Driver/API for AMD Geode Multi-Function General Purpose Timers (MFGPT) - * - * Copyright (C) 2006, 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 - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -/* The MFPGT timers on the CS5536 provide us with suitable timers to use - * as clock event sources - not as good as a HPET or APIC, but certainly - * better then the PIT. This isn't a general purpose MFGPT driver, but - * a simplified one designed specifically to act as a clock event source. - * For full details about the MFGPT, please consult the CS5536 data sheet. -*/ - -/* We are using the 32Khz input clock - its the only one that has the - * ranges we find desirable. The following table lists the suitable - * divisors and the associated hz, minimum interval - * and the maximum interval: - - Divisor Hz Min Delta (S) Max Delta (S) - 1 32000 .0005 2.048 - 2 16000 .001 4.096 - 4 8000 .002 8.192 - 8 4000 .004 16.384 - 16 2000 .008 32.768 - 32 1000 .016 65.536 - 64 500 .032 131.072 - 128 250 .064 262.144 - 256 125 .128 524.288 -*/ - -#include <linux/kernel.h> -#include <linux/interrupt.h> -#include <linux/module.h> -#include <linux/clocksource.h> -#include <linux/clockchips.h> -#include <asm/geode.h> - -#include "do_timer.h" - -#define MFGPT_MAX_TIMERS 8 - -#define F_AVAIL 0x01 - -static struct mfgpt_timer_t { - int flags; - struct module *owner; -} mfgpt_timers[MFGPT_MAX_TIMERS]; - -/* Selected from the table above */ - -#define MFGPT_DIVISOR 16 -#define MFGPT_SCALE 4 /* divisor = 2^(scale) */ -#define MFGPT_HZ (32000 / MFGPT_DIVISOR) -#define MFGPT_PERIODIC (MFGPT_HZ / HZ) - -#ifdef CONFIG_GEODE_MFGPT_TIMER -static int __init mfgpt_timer_setup(void); -#else -#define mfgpt_timer_setup() (0) -#endif - -/* Allow for disabling of MFGPTs */ -static int disable = 0; -static int __init mfgpt_disable(char *s) -{ - disable = 1; - return 1; -} -__setup("nomfgpt", mfgpt_disable); - -/* - * Check whether any MFGPTs are available for the kernel to use. In most - * cases, firmware that uses AMD's VSA code will claim all timers during - * bootup; we certainly don't want to take them if they're already in use. - * In other cases (such as with VSAless OpenFirmware), the system firmware - * leaves timers available for us to use. - */ -int __init geode_mfgpt_detect(void) -{ - int count = 0, i; - u16 val; - - if (disable) { - printk(KERN_INFO "geode-mfgpt: Skipping MFGPT setup\n"); - return 0; - } - - for (i = 0; i < MFGPT_MAX_TIMERS; i++) { - val = geode_mfgpt_read(i, MFGPT_REG_SETUP); - if (!(val & MFGPT_SETUP_SETUP)) { - mfgpt_timers[i].flags = F_AVAIL; - count++; - } - } - - /* set up clock event device, if desired */ - i = mfgpt_timer_setup(); - - return count; -} - -int geode_mfgpt_toggle_event(int timer, int cmp, int event, int enable) -{ - u32 msr, mask, value, dummy; - int shift = (cmp == MFGPT_CMP1) ? 0 : 8; - - if (timer < 0 || timer >= MFGPT_MAX_TIMERS) - return -EIO; - - /* - * The register maps for these are described in sections 6.17.1.x of - * the AMD Geode CS5536 Companion Device Data Book. - */ - switch(event) { - case MFGPT_EVENT_RESET: - /* XXX: According to the docs, we cannot reset timers above - * 6; that is, resets for 7 and 8 will be ignored. Is this - * a problem? */ - msr = MFGPT_NR_MSR; - mask = 1 << (timer + 24); - break; - - case MFGPT_EVENT_NMI: - msr = MFGPT_NR_MSR; - mask = 1 << (timer + shift); - break; - - case MFGPT_EVENT_IRQ: - msr = MFGPT_IRQ_MSR; - mask = 1 << (timer + shift); - break; - - default: - return -EIO; - } - - rdmsr(msr, value, dummy); - - if (enable) - value |= mask; - else - value &= ~mask; - - wrmsr(msr, value, dummy); - return 0; -} -EXPORT_SYMBOL(geode_mfgpt_toggle_event); - -int geode_mfgpt_set_irq(int timer, int cmp, int irq, int enable) -{ - u32 val, dummy; - int offset; - - if (timer < 0 || timer >= MFGPT_MAX_TIMERS) - return -EIO; - - if (geode_mfgpt_toggle_event(timer, cmp, MFGPT_EVENT_IRQ, enable)) - return -EIO; - - rdmsr(0x51400022, val, dummy); - - offset = (timer % 4) * 4; - - val &= ~((0xF << offset) | (0xF << (offset + 16))); - - if (enable) { - val |= (irq & 0x0F) << (offset); - val |= (irq & 0x0F) << (offset + 16); - } - - wrmsr(0x51400022, val, dummy); - return 0; -} -EXPORT_SYMBOL(geode_mfgpt_set_irq); - -static int mfgpt_get(int timer, struct module *owner) -{ - mfgpt_timers[timer].flags &= ~F_AVAIL; - mfgpt_timers[timer].owner = owner; - printk(KERN_INFO "geode-mfgpt: Registered timer %d\n", timer); - return timer; -} - -int geode_mfgpt_alloc_timer(int timer, int domain, struct module *owner) -{ - int i; - - if (!geode_get_dev_base(GEODE_DEV_MFGPT)) - return -ENODEV; - if (timer >= MFGPT_MAX_TIMERS) - return -EIO; - - if (timer < 0) { - /* Try to find an available timer */ - for (i = 0; i < MFGPT_MAX_TIMERS; i++) { - if (mfgpt_timers[i].flags & F_AVAIL) - return mfgpt_get(i, owner); - - if (i == 5 && domain == MFGPT_DOMAIN_WORKING) - break; - } - } - else { - /* If they requested a specific timer, try to honor that */ - if (mfgpt_timers[timer].flags & F_AVAIL) - return mfgpt_get(timer, owner); - } - - /* No timers available - too bad */ - return -1; -} -EXPORT_SYMBOL(geode_mfgpt_alloc_timer); - -#ifdef CONFIG_GEODE_MFGPT_TIMER - -static unsigned int mfgpt_tick_mode = CLOCK_EVT_MODE_SHUTDOWN; -static u16 mfgpt_event_clock; - -static int irq = 7; -static int __init mfgpt_setup(char *str) -{ - get_option(&str, &irq); - return 1; -} -__setup("mfgpt_irq=", mfgpt_setup); - -static inline void mfgpt_disable_timer(u16 clock) -{ - u16 val = geode_mfgpt_read(clock, MFGPT_REG_SETUP); - geode_mfgpt_write(clock, MFGPT_REG_SETUP, val & ~MFGPT_SETUP_CNTEN); -} - -static int mfgpt_next_event(unsigned long, struct clock_event_device *); -static void mfgpt_set_mode(enum clock_event_mode, struct clock_event_device *); - -static struct clock_event_device mfgpt_clockevent = { - .name = "mfgpt-timer", - .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, - .set_mode = mfgpt_set_mode, - .set_next_event = mfgpt_next_event, - .rating = 250, - .cpumask = CPU_MASK_ALL, - .shift = 32 -}; - -static inline void mfgpt_start_timer(u16 clock, u16 delta) -{ - geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_CMP2, (u16) delta); - geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_COUNTER, 0); - - geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_SETUP, - MFGPT_SETUP_CNTEN | MFGPT_SETUP_CMP2); -} - -static void mfgpt_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) -{ - mfgpt_disable_timer(mfgpt_event_clock); - - if (mode == CLOCK_EVT_MODE_PERIODIC) - mfgpt_start_timer(mfgpt_event_clock, MFGPT_PERIODIC); - - mfgpt_tick_mode = mode; -} - -static int mfgpt_next_event(unsigned long delta, struct clock_event_device *evt) -{ - mfgpt_start_timer(mfgpt_event_clock, delta); - return 0; -} - -/* Assume (foolishly?), that this interrupt was due to our tick */ - -static irqreturn_t mfgpt_tick(int irq, void *dev_id) -{ - if (mfgpt_tick_mode == CLOCK_EVT_MODE_SHUTDOWN) - return IRQ_HANDLED; - - /* Turn off the clock */ - mfgpt_disable_timer(mfgpt_event_clock); - - /* Clear the counter */ - geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_COUNTER, 0); - - /* Restart the clock in periodic mode */ - - if (mfgpt_tick_mode == CLOCK_EVT_MODE_PERIODIC) { - geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_SETUP, - MFGPT_SETUP_CNTEN | MFGPT_SETUP_CMP2); - } - - mfgpt_clockevent.event_handler(&mfgpt_clockevent); - return IRQ_HANDLED; -} - -static struct irqaction mfgptirq = { - .handler = mfgpt_tick, - .flags = IRQF_DISABLED | IRQF_NOBALANCING, - .mask = CPU_MASK_NONE, - .name = "mfgpt-timer" -}; - -static int __init mfgpt_timer_setup(void) -{ - int timer, ret; - u16 val; - - timer = geode_mfgpt_alloc_timer(MFGPT_TIMER_ANY, MFGPT_DOMAIN_WORKING, THIS_MODULE); - if (timer < 0) { - printk(KERN_ERR "mfgpt-timer: Could not allocate a MFPGT timer\n"); - return -ENODEV; - } - - 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 */ - if (geode_mfgpt_setup_irq(mfgpt_event_clock, MFGPT_CMP2, irq)) { - printk(KERN_ERR "mfgpt-timer: Could not set up IRQ %d\n", irq); - return -EIO; - } - - /* And register it with the kernel */ - ret = setup_irq(irq, &mfgptirq); - - if (ret) { - printk(KERN_ERR "mfgpt-timer: Unable to set up the interrupt.\n"); - goto err; - } - - /* Set up the clock event */ - mfgpt_clockevent.mult = div_sc(MFGPT_HZ, NSEC_PER_SEC, 32); - mfgpt_clockevent.min_delta_ns = clockevent_delta2ns(0xF, &mfgpt_clockevent); - mfgpt_clockevent.max_delta_ns = clockevent_delta2ns(0xFFFE, &mfgpt_clockevent); - - printk("mfgpt-timer: registering the MFGT timer as a clock event.\n"); - clockevents_register_device(&mfgpt_clockevent); - - return 0; - -err: - geode_mfgpt_release_irq(mfgpt_event_clock, MFGPT_CMP2, irq); - printk(KERN_ERR "mfgpt-timer: Unable to set up the MFGPT clock source\n"); - return -EIO; -} - -#endif diff --git a/target/linux/olpc/files/arch/i386/kernel/ofw.c b/target/linux/olpc/files/arch/i386/kernel/ofw.c deleted file mode 100644 index fdcd93629a..0000000000 --- a/target/linux/olpc/files/arch/i386/kernel/ofw.c +++ /dev/null @@ -1,100 +0,0 @@ -/* - * ofw.c - Open Firmware client interface for 32-bit systems. - * This code is intended to be portable to any 32-bit Open Firmware - * implementation with a standard client interface that can be - * called when Linux is running. - * - * Copyright (C) 2007 Mitch Bradley <wmb@firmworks.com> - * Copyright (C) 2007 Andres Salomon <dilinger@debian.org> - */ - -#include <stdarg.h> -#include <linux/spinlock.h> -#include <linux/module.h> -#include <asm/ofw.h> - - -int (*call_firmware)(int *); - -static DEFINE_SPINLOCK(prom_lock); - -#define MAXARGS 20 - -/* - * The return value from ofw() in all cases is 0 if the attempt to call the - * function succeeded, <0 otherwise. That return value is from the - * gateway function only. Any results from the called function are returned - * via output argument pointers. - * - * Here are call templates for all the standard OFW client services: - * - * ofw("test", 1, 1, namestr, &missing); - * ofw("peer", 1, 1, phandle, &sibling_phandle); - * ofw("child", 1, 1, phandle, &child_phandle); - * ofw("parent", 1, 1, phandle, &parent_phandle); - * ofw("instance_to_package", 1, 1, ihandle, &phandle); - * ofw("getproplen", 2, 1, phandle, namestr, &proplen); - * ofw("getprop", 4, 1, phandle, namestr, bufaddr, buflen, &size); - * ofw("nextprop", 3, 1, phandle, previousstr, bufaddr, &flag); - * ofw("setprop", 4, 1, phandle, namestr, bufaddr, len, &size); - * ofw("canon", 3, 1, devspecstr, bufaddr, buflen, &length); - * ofw("finddevice", 1, 1, devspecstr, &phandle); - * ofw("instance-to-path", 3, 1, ihandle, bufaddr, buflen, &length); - * ofw("package-to-path", 3, 1, phandle, bufaddr, buflen, &length); - * ofw("call_method", numin, numout, in0, in1, ..., &out0, &out1, ...); - * ofw("open", 1, 1, devspecstr, &ihandle); - * ofw("close", 1, 0, ihandle); - * ofw("read", 3, 1, ihandle, addr, len, &actual); - * ofw("write", 3, 1, ihandle, addr, len, &actual); - * ofw("seek", 3, 1, ihandle, pos_hi, pos_lo, &status); - * ofw("claim", 3, 1, virtaddr, size, align, &baseaddr); - * ofw("release", 2, 0, virtaddr, size); - * ofw("boot", 1, 0, bootspecstr); - * ofw("enter", 0, 0); - * ofw("exit", 0, 0); - * ofw("chain", 5, 0, virtaddr, size, entryaddr, argsaddr, len); - * ofw("interpret", numin+1, numout+1, cmdstr, in0, ..., &catchres, &out0, ...); - * ofw("set-callback", 1, 1, newfuncaddr, &oldfuncaddr); - * ofw("set-symbol-lookup", 2, 0, symtovaladdr, valtosymaddr); - * ofw("milliseconds", 0, 1, &ms); - */ - -int ofw(char *name, int numargs, int numres, ...) -{ - va_list ap; - int argarray[MAXARGS+3]; - int argnum = 3; - int retval; - int *intp; - unsigned long flags; - - if (!call_firmware) - return -1; - if ((numargs + numres) > MAXARGS) - return -1; /* spit out an error? */ - - argarray[0] = (int) name; - argarray[1] = numargs; - argarray[2] = numres; - - va_start(ap, numres); - while (numargs) { - argarray[argnum++] = va_arg(ap, int); - numargs--; - } - - spin_lock_irqsave(&prom_lock, flags); - retval = call_firmware(argarray); - spin_unlock_irqrestore(&prom_lock, flags); - - if (retval == 0) { - while (numres) { - intp = va_arg(ap, int *); - *intp = argarray[argnum++]; - numres--; - } - } - va_end(ap); - return retval; -} -EXPORT_SYMBOL(ofw); diff --git a/target/linux/olpc/files/arch/i386/kernel/olpc-pm.c b/target/linux/olpc/files/arch/i386/kernel/olpc-pm.c deleted file mode 100644 index 93149f1c38..0000000000 --- a/target/linux/olpc/files/arch/i386/kernel/olpc-pm.c +++ /dev/null @@ -1,785 +0,0 @@ -/* olpc-pm.c - * © 2006 Red Hat, Inc. - * Portions also copyright 2006 Advanced Micro Devices, Inc. - * GPLv2 - */ - -#include <linux/kernel.h> -#include <linux/interrupt.h> -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/input.h> -#include <linux/suspend.h> -#include <linux/bootmem.h> -#include <linux/platform_device.h> -#include <linux/rtc.h> -#include <linux/mc146818rtc.h> -#include <asm/io.h> - -#include <asm/olpc.h> - -/* A few words about accessing the ACPI and PM registers. Long story short, - byte and word accesses of the ACPI and PM registers is broken. The only - way to do it really correctly is to use dword accesses, which we do - throughout this code. For more details, please consult Eratta 17 and 18 - here: - - http://www.amd.com/files/connectivitysolutions/geode/geode_gx/34472D_CS5536_B1_specupdate.pdf -*/ - -#define PM_IRQ 3 - -#define CS5536_PM_PWRBTN (1 << 8) -#define CS5536_PM_RTC (1 << 10) - -#define GPIO_WAKEUP_EC (1 << 31) -#define GPIO_WAKEUP_LID (1 << 30) - -#define PM_MODE_NORMAL 0 -#define PM_MODE_TEST 1 -#define PM_MODE_MAX 2 - -/* These, and the battery EC commands, should be in an olpc.h. */ -#define EC_WRITE_SCI_MASK 0x1b -#define EC_READ_SCI_MASK 0x1c - -extern void do_olpc_suspend_lowlevel(void); - -static struct { - unsigned long address; - unsigned short segment; -} ofw_bios_entry = { 0, __KERNEL_CS }; - -static int olpc_pm_mode = PM_MODE_NORMAL; -static unsigned long acpi_base; -static unsigned long pms_base; -static int sci_irq; -static int olpc_lid_flag; - -static struct input_dev *pm_inputdev; -static struct input_dev *lid_inputdev; -static struct input_dev *ebook_inputdev; -static struct pm_ops olpc_pm_ops; - -static int gpio_wake_events = 0; -static int ebook_state = -1; -static u16 olpc_wakeup_mask = 0; - -struct platform_device olpc_powerbutton_dev = { - .name = "powerbutton", - .id = -1, -}; - -struct platform_device olpc_lid_dev = { - .name = "lid", - .id = -1, -}; - -static void __init init_ebook_state(void) -{ - if (olpc_ec_cmd(0x2a, NULL, 0, (unsigned char *) &ebook_state, 1)) { - printk(KERN_WARNING "olpc-pm: failed to get EBOOK state!\n"); - ebook_state = 0; - } - ebook_state &= 1; - - /* the input layer needs to know what value to default to as well */ - input_report_switch(ebook_inputdev, SW_TABLET_MODE, ebook_state); - input_sync(ebook_inputdev); -} - -static void (*battery_callback)(unsigned long); -static DEFINE_SPINLOCK(battery_callback_lock); - -/* propagate_events is non-NULL if run from workqueue, - NULL when called at init time to flush SCI queue */ -static void process_sci_queue(struct work_struct *propagate_events) -{ - unsigned char data = 0; - unsigned char battery_events = 0; - int ret; - - do { - ret = olpc_ec_cmd(0x84, NULL, 0, &data, 1); - if (!ret) { - printk(KERN_DEBUG "olpc-pm: SCI 0x%x received\n", - data); - - switch (data) { - case EC_SCI_SRC_EMPTY: - case EC_SCI_SRC_GAME: - case EC_SCI_SRC_WLAN: - /* we ignore these for now */ - break; - case EC_SCI_SRC_BATERR: - printk(KERN_ERR "olpc-pm: Battery Management System detected an error! Remove turnip from battery slot.\n"); - case EC_SCI_SRC_BATSOC: - case EC_SCI_SRC_BATTERY: - case EC_SCI_SRC_ACPWR: - battery_events |= data; - break; - case EC_SCI_SRC_EBOOK: - ebook_state = !ebook_state; - if (propagate_events) { - input_report_switch(ebook_inputdev, - SW_TABLET_MODE, ebook_state); - input_sync(ebook_inputdev); - } - break; - default: - printk(KERN_ERR "olpc-pm: Unknown SCI event 0x%x occurred!\n", data); - } - } - } while (data && !ret); - - if (battery_events && battery_callback && propagate_events) { - void (*cbk)(unsigned long); - - /* Older EC versions didn't distinguish between AC and battery - events */ - if (olpc_platform_info.ecver < 0x45) - battery_events = EC_SCI_SRC_BATTERY | EC_SCI_SRC_ACPWR; - - spin_lock(&battery_callback_lock); - cbk = battery_callback; - spin_unlock(&battery_callback_lock); - - cbk(battery_events); - } - - if (ret) - printk(KERN_WARNING "Failed to clear SCI queue!\n"); -} - -static DECLARE_WORK(sci_work, process_sci_queue); - -void olpc_register_battery_callback(void (*f)(unsigned long)) -{ - spin_lock(&battery_callback_lock); - battery_callback = f; - spin_unlock(&battery_callback_lock); -} -EXPORT_SYMBOL_GPL(olpc_register_battery_callback); - -void olpc_deregister_battery_callback(void) -{ - spin_lock(&battery_callback_lock); - battery_callback = NULL; - spin_unlock(&battery_callback_lock); - cancel_work_sync(&sci_work); -} -EXPORT_SYMBOL_GPL(olpc_deregister_battery_callback); - - -static int 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); - - if (olpc_get_rev() >= OLPC_REV_B2) { - gpe = inl(acpi_base + PM_GPE0_STS); - outl(0xFFFFFFFF, acpi_base + PM_GPE0_STS); - } - - if (sts & CS5536_PM_PWRBTN) { - input_report_key(pm_inputdev, KEY_POWER, 1); - input_sync(pm_inputdev); - printk(KERN_DEBUG "olpm-pm: PM_PWRBTN event received\n"); - /* Do we need to delay this (and hence schedule_work)? */ - input_report_key(pm_inputdev, KEY_POWER, 0); - input_sync(pm_inputdev); - } - - if (gpe & GPIO_WAKEUP_EC) { - geode_gpio_clear(OLPC_GPIO_ECSCI, GPIO_NEGATIVE_EDGE_STS); - schedule_work(&sci_work); - } - - if (gpe & GPIO_WAKEUP_LID) { - /* Disable events */ - geode_gpio_clear(OLPC_GPIO_LID, GPIO_EVENTS_ENABLE); - - /* Clear the edge */ - - if (olpc_lid_flag) - geode_gpio_clear(OLPC_GPIO_LID, GPIO_NEGATIVE_EDGE_EN); - else - geode_gpio_clear(OLPC_GPIO_LID, GPIO_POSITIVE_EDGE_EN); - - /* Clear the status too */ - geode_gpio_set(OLPC_GPIO_LID, GPIO_NEGATIVE_EDGE_STS); - geode_gpio_set(OLPC_GPIO_LID, GPIO_POSITIVE_EDGE_STS); - - /* The line is high when the LID is open, but SW_LID - * should be high when the LID is closed, so we pass the old - * value of olpc_lid_flag - */ - - input_report_switch(lid_inputdev, SW_LID, olpc_lid_flag); - input_sync(lid_inputdev); - - /* Swap the status */ - olpc_lid_flag = !olpc_lid_flag; - - if (olpc_lid_flag) - geode_gpio_set(OLPC_GPIO_LID, GPIO_NEGATIVE_EDGE_EN); - else - geode_gpio_set(OLPC_GPIO_LID, GPIO_POSITIVE_EDGE_EN); - - /* re-enable the event */ - geode_gpio_set(OLPC_GPIO_LID, GPIO_EVENTS_ENABLE); - } - - return IRQ_HANDLED; -} - -/* - * For now, only support STR. We also don't support suspending on - * B1s, due to difficulties with the cafe FPGA. - */ -static int olpc_pm_state_valid(suspend_state_t pm_state) -{ - if (pm_state == PM_SUSPEND_MEM && olpc_rev_after(OLPC_REV_B1)) - return 1; - - return 0; -} - -/* This is a catchall function for operations that just don't belong - * anywhere else. Later we will evaluate if these belong in the - * individual device drivers or the firmware. - * If you add something to this function, please explain yourself with - * a comment. - */ - -extern void gxfb_flatpanel_control(int state); - -static u32 gpio_wakeup[2]; -static u64 irq_sources[4]; -static u64 mfgpt_irq_msr, mfgpt_nr_msr; - -void olpc_fixup_wakeup(void) -{ - u32 base = geode_gpio_base(); - int i; - - /* This clears any pending events from the status register - - * the firmware also does this, but its possible that it tries - * it too early before the key has a chance to debounce - */ - - outl((CS5536_PM_PWRBTN << 16) | 0xFFFF, acpi_base + PM1_STS); - - /* Enable the flatpanel sequencing as early as possible, because - it takes ~64ms to resume. This probably belongs in the firmware */ - - //gxfb_flatpanel_control(1); - - /* Restore the interrupt sources */ - wrmsrl(MSR_PIC_YSEL_LOW, irq_sources[0]); - wrmsrl(MSR_PIC_ZSEL_LOW, irq_sources[1]); - wrmsrl(MSR_PIC_YSEL_HIGH, irq_sources[2]); - wrmsrl(MSR_PIC_ZSEL_HIGH, irq_sources[3]); - - /* Restore the X and Y sources for GPIO */ - outl(gpio_wakeup[0], base + GPIO_MAP_X); - outl(gpio_wakeup[1], base + GPIO_MAP_Y); - - /* Resture the MFGPT MSRs */ - wrmsrl(MFGPT_IRQ_MSR, mfgpt_irq_msr); - wrmsrl(MFGPT_NR_MSR, mfgpt_nr_msr); - - for (i=0;i<2;i++) { - /* tell the wireless module to restart USB communication */ - olpc_ec_cmd(0x24, NULL, 0, NULL, 0); - } -} - -void olpc_fixup_sleep(void) -{ - u32 base = geode_gpio_base(); - int i; - - /* Save the X and Y sources for GPIO */ - gpio_wakeup[0] = inl(base + GPIO_MAP_X); - gpio_wakeup[1] = inl(base + GPIO_MAP_Y); - - /* Save the Y and Z unrestricted sources */ - - rdmsrl(MSR_PIC_YSEL_LOW, irq_sources[0]); - rdmsrl(MSR_PIC_ZSEL_LOW, irq_sources[1]); - rdmsrl(MSR_PIC_YSEL_HIGH, irq_sources[2]); - rdmsrl(MSR_PIC_ZSEL_HIGH, irq_sources[3]); - - /* Turn off the MFGPT timers on the way down */ - - for(i = 0; i < 8; i++) { - u32 val = geode_mfgpt_read(i, MFGPT_REG_SETUP); - - if (val & MFGPT_SETUP_SETUP) { - val &= ~MFGPT_SETUP_CNTEN; - geode_mfgpt_write(i, MFGPT_REG_SETUP, val); - } - } - - /* Save the MFGPT MSRs */ - rdmsrl(MFGPT_IRQ_MSR, mfgpt_irq_msr); - rdmsrl(MFGPT_NR_MSR, mfgpt_nr_msr); - - if (device_may_wakeup(&olpc_powerbutton_dev.dev)) - olpc_wakeup_mask |= CS5536_PM_PWRBTN; - else - olpc_wakeup_mask &= ~(CS5536_PM_PWRBTN); - - if (device_may_wakeup(&olpc_lid_dev.dev)) { - geode_gpio_set(OLPC_GPIO_LID, GPIO_EVENTS_ENABLE); - gpio_wake_events |= GPIO_WAKEUP_LID; - } else { - geode_gpio_clear(OLPC_GPIO_LID, GPIO_EVENTS_ENABLE); - gpio_wake_events &= ~(GPIO_WAKEUP_LID); - } -} - -static int olpc_pm_enter(suspend_state_t pm_state) -{ - /* Only STR is supported */ - if (pm_state != PM_SUSPEND_MEM) - return -EINVAL; - - olpc_fixup_sleep(); - - /* Set the GPIO wakeup bits */ - outl(gpio_wake_events, acpi_base + PM_GPE0_EN); - outl(0xFFFFFFFF, acpi_base + PM_GPE0_STS); - - /* Save CPU state */ - do_olpc_suspend_lowlevel(); - - olpc_fixup_wakeup(); - - /* Restore the SCI wakeup events */ - outl(gpio_wake_events, acpi_base + PM_GPE0_EN); - - return 0; -} - -int asmlinkage olpc_do_sleep(u8 sleep_state) -{ - void *pgd_addr = __va(read_cr3()); - printk(KERN_ERR "olpc_do_sleep!\n"); /* this needs to remain here so - * that gcc doesn't optimize - * away our __va! */ - /* FIXME: Set the SCI bits we want to wake up on here */ - - /* FIXME: Set any other SCI events that we might want here */ - - outl((olpc_wakeup_mask << 16) | 0xFFFF, acpi_base + PM1_STS); - - /* If we are in test mode, then just return (simulate a successful - suspend/resume). Otherwise, if we are doing the real thing, - then go for the gusto */ - - if (olpc_pm_mode != PM_MODE_TEST) { - __asm__ __volatile__("movl %0,%%eax" : : "r" (pgd_addr)); - __asm__("call *(%%edi); cld" - : : "D" (&ofw_bios_entry)); - } - - return 0; -} - -/* This code will slowly disappear as we fixup the issues in the BIOS */ - -static void __init olpc_fixup_bios(void) -{ - unsigned long hi, lo; - - if (olpc_has_vsa()) { - /* The VSA aggressively sets up the ACPI and PM register for - * trapping - its not enough to force these values in the BIOS - - * they seem to be changed during PCI init as well. - */ - - /* Change the PM registers to decode to the DD */ - - rdmsr(0x510100e2, lo, hi); - hi |= 0x80000000; - wrmsr(0x510100e2, lo, hi); - - /* Change the ACPI registers to decode to the DD */ - - rdmsr(0x510100e3, lo, hi); - hi |= 0x80000000; - wrmsr(0x510100e3, lo, hi); - } - - /* GPIO24 controls WORK_AUX */ - - geode_gpio_set(OLPC_GPIO_WORKAUX, GPIO_OUTPUT_ENABLE); - geode_gpio_set(OLPC_GPIO_WORKAUX, GPIO_OUTPUT_AUX1); - - if (olpc_get_rev() >= OLPC_REV_B2) { - /* GPIO10 is connected to the thermal alarm */ - geode_gpio_set(OLPC_GPIO_THRM_ALRM, GPIO_INPUT_ENABLE); - geode_gpio_set(OLPC_GPIO_THRM_ALRM, GPIO_INPUT_AUX1); - - /* Set up to get LID events */ - geode_gpio_set(OLPC_GPIO_LID, GPIO_INPUT_ENABLE); - - /* Clear edge detection and event enable for now */ - geode_gpio_clear(OLPC_GPIO_LID, GPIO_EVENTS_ENABLE); - geode_gpio_clear(OLPC_GPIO_LID, GPIO_NEGATIVE_EDGE_EN); - geode_gpio_clear(OLPC_GPIO_LID, GPIO_POSITIVE_EDGE_EN); - - geode_gpio_set(OLPC_GPIO_LID, GPIO_NEGATIVE_EDGE_STS); - geode_gpio_set(OLPC_GPIO_LID, GPIO_POSITIVE_EDGE_STS); - - /* Set the LID to cause an PME event on group 6 */ - geode_gpio_event_pme(OLPC_GPIO_LID, 6); - - /* Set PME group 6 to fire the SCI interrupt */ - geode_gpio_set_irq(6, sci_irq); - } - - geode_gpio_set(OLPC_GPIO_ECSCI, GPIO_INPUT_ENABLE); - - /* Clear pending events */ - - geode_gpio_set(OLPC_GPIO_ECSCI, GPIO_NEGATIVE_EDGE_STS); - geode_gpio_set(OLPC_GPIO_ECSCI, GPIO_POSITIVE_EDGE_STS); - - //geode_gpio_set(OLPC_GPIO_ECSCI, GPIO_NEGATIVE_EDGE_EN); - geode_gpio_set(OLPC_GPIO_ECSCI, GPIO_EVENTS_ENABLE); - - /* Set the SCI to cause a PME event on group 7 */ - geode_gpio_event_pme(OLPC_GPIO_ECSCI, 7); - - /* And have group 6 also fire the SCI interrupt */ - geode_gpio_set_irq(7, sci_irq); -} - -/* This provides a control file for setting up testing of the - power management system. For now, there is just one setting: - "test" which means that we don't actually enter the power - off routine. -*/ - -static const char * const pm_states[] = { - [PM_MODE_NORMAL] = "normal", - [PM_MODE_TEST] = "test", -}; - -extern struct mutex pm_mutex; -extern struct kset power_subsys; - -static ssize_t control_show(struct kset *s, char *buf) -{ - return sprintf(buf, "%s\n", pm_states[olpc_pm_mode]); -} - -static ssize_t control_store(struct kset *s, const char *buf, size_t n) -{ - int i, len; - char *p; - - p = memchr(buf, '\n', n); - len = p ? p - buf : n; - - /* Grab the mutex */ - mutex_lock(&pm_mutex); - - for(i = 0; i < PM_MODE_MAX; i++) { - if (!strncmp(buf, pm_states[i], len)) { - olpc_pm_mode = i; - break; - } - } - - mutex_unlock(&pm_mutex); - - return (i == PM_MODE_MAX) ? -EINVAL : n; -} - -static struct subsys_attribute control_attr = { - .attr = { - .name = "olpc-pm", - .mode = 0644, - }, - .show = control_show, - .store = control_store, -}; - -static struct attribute * olpc_attributes[] = { - &control_attr.attr, - NULL -}; - -static struct attribute_group olpc_attrs = { - .attrs = olpc_attributes, -}; - -static int __init alloc_inputdevs(void) -{ - int ret = -ENOMEM; - - pm_inputdev = input_allocate_device(); - if (!pm_inputdev) - goto err; - - pm_inputdev->name = "OLPC PM"; - pm_inputdev->phys = "olpc_pm/input0"; - set_bit(EV_KEY, pm_inputdev->evbit); - set_bit(KEY_POWER, pm_inputdev->keybit); - - ret = input_register_device(pm_inputdev); - if (ret) { - printk(KERN_ERR "olpc-pm: failed to register PM input device: %d\n", ret); - goto err; - } - - lid_inputdev = input_allocate_device(); - if (!lid_inputdev) - goto err; - - lid_inputdev->name = "OLPC lid switch"; - lid_inputdev->phys = "olpc_pm/input1"; - set_bit(EV_SW, lid_inputdev->evbit); - set_bit(SW_LID, lid_inputdev->swbit); - - ret = input_register_device(lid_inputdev); - if (ret) { - printk(KERN_ERR "olpc-pm: failed to register lid input device: %d\n", ret); - goto err; - } - - ebook_inputdev = input_allocate_device(); - if (!ebook_inputdev) - goto err; - - ebook_inputdev->name = "OLPC ebook switch"; - ebook_inputdev->phys = "olpc_pm/input2"; - set_bit(EV_SW, ebook_inputdev->evbit); - set_bit(SW_TABLET_MODE, ebook_inputdev->swbit); - - ret = input_register_device(ebook_inputdev); - if (ret) { - printk(KERN_ERR "olpc-pm: failed to register ebook input device: %d\n", ret); - goto err; - } - - return ret; -err: - if (ebook_inputdev) { - input_unregister_device(ebook_inputdev); - ebook_inputdev = NULL; - } - if (lid_inputdev) { - input_unregister_device(lid_inputdev); - lid_inputdev = NULL; - } - if (pm_inputdev) { - input_unregister_device(pm_inputdev); - pm_inputdev = NULL; - } - - return ret; -} - -static int __init olpc_pm_init(void) -{ - uint32_t lo, hi; - int ret; - uint8_t ec_byte; - - if (!machine_is_olpc()) - return -ENODEV; - - acpi_base = geode_acpi_base(); - pms_base = geode_pms_base(); - - if (!acpi_base || !pms_base) - return -ENODEV; - - ret = alloc_inputdevs(); - if (ret) - return ret; - - rdmsr(0x51400020, lo, hi); - sci_irq = (lo >> 20) & 15; - - if (sci_irq) { - printk(KERN_INFO "SCI is mapped to IRQ %d\n", sci_irq); - } else { - /* Zero doesn't mean zero -- it means masked */ - printk(KERN_INFO "SCI unmapped. Mapping to IRQ 3\n"); - sci_irq = 3; - lo |= 0x00300000; - wrmsrl(0x51400020, lo); - } - - olpc_fixup_bios(); - - lo = inl(pms_base + PM_FSD); - - /* Lock, enable failsafe, 4 seconds */ - outl(0xc001f400, pms_base + PM_FSD); - - /* Here we set up the SCI events we're interested in during - * real-time. We have no sleep button, and the RTC doesn't make - * sense, so set up the power button - */ - - outl(inl(acpi_base) | ((CS5536_PM_PWRBTN) << 16), acpi_base); - - if (olpc_get_rev() >= OLPC_REV_B2) { - gpio_wake_events |= GPIO_WAKEUP_LID; - - /* Get the current value of the GPIO, and set up the edges */ - olpc_lid_flag = geode_gpio_isset(OLPC_GPIO_LID, GPIO_READ_BACK); - - /* Watch for the opposite edge */ - - if (olpc_lid_flag) - geode_gpio_set(OLPC_GPIO_LID, GPIO_NEGATIVE_EDGE_EN); - else - geode_gpio_set(OLPC_GPIO_LID, GPIO_POSITIVE_EDGE_EN); - - /* Enable the event */ - geode_gpio_set(OLPC_GPIO_LID, GPIO_EVENTS_ENABLE); - } - - /* Set up the mask for wakeups the EC will generate SCIs on */ - - ret = olpc_ec_cmd(EC_READ_SCI_MASK, NULL, 0, &ec_byte, 1); - if (ret) - printk(KERN_ERR "Error getting the EC SCI mask: %d\n", ret); - - /* Disable battery 1% charge wakeups */ - ec_byte &= ~EC_SCI_SRC_BATSOC; - - ret = olpc_ec_cmd(EC_WRITE_SCI_MASK, &ec_byte, 1, NULL, 0); - if (ret) - printk(KERN_ERR "Error setting the EC SCI mask: %d\n", ret); - - /* Set up the EC SCI */ - - gpio_wake_events |= GPIO_WAKEUP_EC; - - outl(gpio_wake_events, acpi_base + PM_GPE0_EN); - outl(0xFFFFFFFF, acpi_base + PM_GPE0_STS); - - /* Select level triggered in PIC */ - - if (sci_irq < 8) { - lo = inb(0x4d0); - lo |= 1 << sci_irq; - outb(lo, 0x4d0); - } else { - lo = inb(0x4d1); - lo |= 1 << (sci_irq - 8); - outb(lo, 0x4d1); - } - /* Clear pending interrupt */ - outl(inl(acpi_base) | 0xFFFF, acpi_base); - process_sci_queue(0); /* we just want to flush the queue here */ - init_ebook_state(); - - /* Enable the interrupt */ - - ret = request_irq(sci_irq, &olpc_pm_interrupt, 0, "SCI", &acpi_base); - - if (ret) { - printk(KERN_ERR "Error registering SCI: %d\n", ret); - return ret; - } - - ofw_bios_entry.address = 0xF0000 + PAGE_OFFSET; - pm_set_ops(&olpc_pm_ops); - - sysfs_create_group(&power_subsys.kobj, &olpc_attrs); - - return 0; -} - - -#if defined (CONFIG_RTC_DRV_CMOS) || defined (CONFIG_RTC_DRV_CMOS_MODULE) -struct resource rtc_platform_resource[2] = { - { - .flags = IORESOURCE_IO, - .start = RTC_PORT(0), - .end = RTC_PORT(0) + RTC_IO_EXTENT - }, - { - .flags = IORESOURCE_IRQ, - .start = 8, - .end = 8, - }, -}; - - -static void rtc_wake_on(struct device *dev) -{ - olpc_wakeup_mask |= CS5536_PM_RTC; -} - -static void rtc_wake_off(struct device *dev) -{ - olpc_wakeup_mask &= ~(CS5536_PM_RTC); -} - -static struct cmos_rtc_board_info rtc_info = { - .rtc_day_alarm = 0, - .rtc_mon_alarm = 0, - .rtc_century = 0, - .wake_on = rtc_wake_on, - .wake_off = rtc_wake_off, -}; - -struct platform_device olpc_rtc_device = { - .name = "rtc_cmos", - .id = -1, - .num_resources = ARRAY_SIZE(rtc_platform_resource), - .dev.platform_data = &rtc_info, - .resource = rtc_platform_resource, -}; - -static int __init olpc_platform_init(void) -{ - (void)platform_device_register(&olpc_rtc_device); - device_init_wakeup(&olpc_rtc_device.dev, 1); - - (void)platform_device_register(&olpc_powerbutton_dev); - device_init_wakeup(&olpc_powerbutton_dev.dev, 1); - - (void)platform_device_register(&olpc_lid_dev); - device_init_wakeup(&olpc_lid_dev.dev, 1); - - return 0; -} -arch_initcall(olpc_platform_init); -#endif /* CONFIG_RTC_DRV_CMOS */ - -static void olpc_pm_exit(void) -{ - /* Clear any pending events, and disable them */ - outl(0xFFFF, acpi_base+2); - - free_irq(sci_irq, &acpi_base); - input_unregister_device(pm_inputdev); - input_unregister_device(lid_inputdev); - input_unregister_device(ebook_inputdev); -} - -static struct pm_ops olpc_pm_ops = { - .valid = olpc_pm_state_valid, - .enter = olpc_pm_enter, -}; - -module_init(olpc_pm_init); -module_exit(olpc_pm_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>"); -MODULE_DESCRIPTION("AMD Geode power management for OLPC CL1"); diff --git a/target/linux/olpc/files/arch/i386/kernel/olpc-sleep.S b/target/linux/olpc/files/arch/i386/kernel/olpc-sleep.S deleted file mode 100644 index 9535c9a941..0000000000 --- a/target/linux/olpc/files/arch/i386/kernel/olpc-sleep.S +++ /dev/null @@ -1,39 +0,0 @@ -.text - -ENTRY(olpc_sleep_asm) -olpc_sleep: - ;; Get the value of PM1_CNT and store it off - - add 08h, ax - mov bx,dx - in dx,eax - or 2000h, ax - mov ax,di - - ;; flush the cache - wbinvd - - ;; GX2 must disable refresh before going into self-refresh - mov 2000000180xh, ecx - rdmsr - mov eax, esi - and 0FF0000FFh, eax - wrmsr - - ;; Now, put the memory into self refresh - mov 2004, cx - xor edx, edx - xor eax, eax - mov 04h, al - wrmsr - - ;; Thats all she wrote - time to go to sleep - - mov bx, dx - movzx di, eax - out eax, dx - - ;; - - - diff --git a/target/linux/olpc/files/arch/i386/kernel/olpc-wakeup.S b/target/linux/olpc/files/arch/i386/kernel/olpc-wakeup.S deleted file mode 100644 index a92cc61e24..0000000000 --- a/target/linux/olpc/files/arch/i386/kernel/olpc-wakeup.S +++ /dev/null @@ -1,122 +0,0 @@ -.text -#include <linux/linkage.h> -#include <asm/segment.h> -#include <asm/page.h> - -ALIGN - .align 4096 - -wakeup_start: -# jmp wakeup_start - - cli - cld - - # Clear any dangerous flags - - pushl $0 - popfl - - # Set up %cr3 - movl $swsusp_pg_dir - __PAGE_OFFSET, %eax - movl %eax, %cr3 - - movl saved_cr4, %eax - movl %eax, %cr4 - - movl saved_cr0, %eax - movl %eax, %cr0 - - jmp 1f -1: - ljmpl $__KERNEL_CS,$wakeup_return - - -.org 0x1000 - -wakeup_return: - movw $__KERNEL_DS, %ax - movw %ax, %ss - movw %ax, %ds - movw %ax, %es - movw %ax, %fs - movw %ax, %gs - - lgdt saved_gdt - lidt saved_idt - lldt saved_ldt - ljmp $(__KERNEL_CS),$1f -1: - movl %cr3, %eax - movl %eax, %cr3 - wbinvd - - # Go back to the return point - jmp ret_point - -save_registers: - sgdt saved_gdt - sidt saved_idt - sldt saved_ldt - - pushl %edx - movl %cr4, %edx - movl %edx, saved_cr4 - - movl %cr0, %edx - movl %edx, saved_cr0 - - popl %edx - - - 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 - - -ENTRY(do_olpc_suspend_lowlevel) - call save_processor_state - call save_registers - - # This is the stack context we want to remember - movl %esp, saved_context_esp - - pushl $3 - call olpc_do_sleep - - jmp wakeup_start - .p2align 4,,7 -ret_point: - movl saved_context_esp, %esp - - call restore_registers - call restore_processor_state - ret - -.data -ALIGN - -saved_gdt: .long 0,0 -saved_idt: .long 0,0 -saved_ldt: .long 0 -saved_cr4: .long 0 -saved_cr0: .long 0 - diff --git a/target/linux/olpc/files/arch/i386/kernel/olpc.c b/target/linux/olpc/files/arch/i386/kernel/olpc.c deleted file mode 100644 index d540cb0eae..0000000000 --- a/target/linux/olpc/files/arch/i386/kernel/olpc.c +++ /dev/null @@ -1,320 +0,0 @@ -/* Support for the OLPC DCON and OLPC EC access - * Copyright (C) 2006, 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 as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include <linux/autoconf.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/mc146818rtc.h> -#include <linux/delay.h> -#include <linux/spinlock.h> - -#include <asm/olpc.h> -#include <asm/ofw.h> - -/* This is our new multi-purpose structure used to contain the - * information about the platform that we detect - */ - -struct olpc_platform_t olpc_platform_info; -EXPORT_SYMBOL_GPL(olpc_platform_info); - -/********************************************************************* - * EC locking and access - *********************************************************************/ - -static DEFINE_SPINLOCK(ec_lock); - -/* what the timeout *should* be (in ms) */ -#define EC_BASE_TIMEOUT 20 - -/* the timeout that bugs in the EC might force us to actually use */ -static int ec_timeout = EC_BASE_TIMEOUT; - -static int __init olpc_ec_timeout_set(char *str) -{ - if (get_option(&str, &ec_timeout) != 1) { - ec_timeout = EC_BASE_TIMEOUT; - printk(KERN_ERR "olpc-ec: invalid argument to " - "'olpc_ec_timeout=', ignoring!\n"); - } - printk(KERN_DEBUG "olpc-ec: using %d ms delay for EC commands.\n", - ec_timeout); - return 1; -} -__setup("olpc_ec_timeout=", olpc_ec_timeout_set); - -/* - * These *bf_status functions return whether the buffers are full or not. - */ - -static inline unsigned int ibf_status(unsigned int port) -{ - return inb(port) & 0x02; -} - -static inline unsigned int obf_status(unsigned int port) -{ - return inb(port) & 0x01; -} - -#define wait_on_ibf(p, d) __wait_on_ibf(__LINE__, (p), (d)) -static int __wait_on_ibf(unsigned int line, unsigned int port, int desired) -{ - unsigned int timeo; - int state = ibf_status(port); - - for (timeo = ec_timeout; state != desired && timeo; timeo--) { - mdelay(1); - state = ibf_status(port); - } - - if ((state == desired) && (ec_timeout > EC_BASE_TIMEOUT) && - timeo < (ec_timeout - EC_BASE_TIMEOUT)) { - printk(KERN_WARNING "olpc-ec: waited %u ms for IBF (%d)!\n", - EC_BASE_TIMEOUT-timeo, line); - } - - return !(state == desired); -} - -#define wait_on_obf(p, d) __wait_on_obf(__LINE__, (p), (d)) -static int __wait_on_obf(unsigned int line, unsigned int port, int desired) -{ - unsigned int timeo; - int state = obf_status(port); - - for (timeo = ec_timeout; state != desired && timeo; timeo--) { - mdelay(1); - state = obf_status(port); - } - - if ((state == desired) && (ec_timeout > EC_BASE_TIMEOUT) && - timeo < (ec_timeout - EC_BASE_TIMEOUT)) { - printk(KERN_WARNING "olpc-ec: waited %u ms for OBF (%d)!\n", - EC_BASE_TIMEOUT-timeo, line); - } - - return !(state == desired); -} - -int olpc_ec_cmd(unsigned char cmd, unsigned char *inbuf, size_t inlen, - unsigned char *outbuf, size_t outlen) -{ - unsigned long flags; - int ret = -EIO; - int i; - - spin_lock_irqsave(&ec_lock, flags); - - if (wait_on_ibf(0x6c, 0)) { - printk(KERN_ERR "olpc-ec: timeout waiting for EC to " - "quiesce!\n"); - goto err; - } - -restart: - /* - * Note that if we time out during any IBF checks, that's a failure; - * we have to return. There's no way for the kernel to clear that. - * - * If we time out during an OBF check, we can restart the command; - * reissuing it will clear the OBF flag, and we should be alright. - * The OBF flag will sometimes misbehave due to what we believe - * is a hardware quirk.. - */ - printk(KERN_DEBUG "olpc-ec: running cmd 0x%x\n", cmd); - outb(cmd, 0x6c); - - if (wait_on_ibf(0x6c, 0)) { - printk(KERN_ERR "olpc-ec: timeout waiting for EC to read " - "command!\n"); - goto err; - } - - if (inbuf && inlen) { - /* write data to EC */ - for (i = 0; i < inlen; i++) { - if (wait_on_ibf(0x6c, 0)) { - printk(KERN_ERR "olpc-ec: timeout waiting for" - " EC accept data!\n"); - goto err; - } - printk(KERN_DEBUG "olpc-ec: sending cmd arg 0x%x\n", - inbuf[i]); - outb(inbuf[i], 0x68); - } - } - if (outbuf && outlen) { - /* read data from EC */ - for (i = 0; i < outlen; i++) { - if (wait_on_obf(0x6c, 1)) { - printk(KERN_ERR "olpc-ec: timeout waiting for" - " EC to provide data!\n"); - goto restart; - } - outbuf[i] = inb(0x68); - printk(KERN_DEBUG "olpc-ec: received 0x%x\n", - outbuf[i]); - } - } - - ret = 0; -err: - spin_unlock_irqrestore(&ec_lock, flags); - return ret; -} -EXPORT_SYMBOL_GPL(olpc_ec_cmd); - -/********************************************************************* - * DCON stuff - *********************************************************************/ - -static void olpc_power_off(void) -{ - printk(KERN_INFO "OLPC power off sequence...\n"); - outb(0xff, 0x381); - outb(0x14, 0x382); - outb(0x01, 0x383); - outb(0xff, 0x381); - outb(0x14, 0x382); - outb(0x00, 0x383); -} - -static void __init -ec_detect(void) -{ - olpc_ec_cmd(0x08, NULL, 0, (unsigned char *) &olpc_platform_info.ecver, 1); -} - -/* Check to see if this version of the OLPC board has VSA built - * in, and set a flag - */ - -static void __init vsa_detect(void) -{ - u16 rev; - - outw(0xFC53, 0xAC1C); - outw(0x0003, 0xAC1C); - - rev = inw(0xAC1E); - - if (rev == 0x4132) - olpc_platform_info.flags |= OLPC_F_VSA; -} - -/* Map OFW revisions to what OLPC_REV_* */ -static const char __initdata *olpc_boardrev_str[] = { - "A1", - "preB1", - "B1", - "preB2", - "B2", - "preB3", - "B3", - "B4", - "C1", - "R1", -}; - -static void __init platform_detect(char *revision, size_t len) -{ - size_t propsize; - int i; - - BUG_ON(ARRAY_SIZE(olpc_boardrev_str) != OLPC_REV_UNKNOWN); - - if (ofw("getprop", 4, 1, NULL, "model", revision, len, &propsize)) { - printk(KERN_ERR "ofw: getprop call failed!\n"); - goto failed; - } - if (len < propsize) { - printk(KERN_ERR "ofw: revision string is too long!\n"); - goto failed; - } - - for (i=0; i < ARRAY_SIZE(olpc_boardrev_str); i++) { - if (strcmp(revision, olpc_boardrev_str[i]) == 0) { - olpc_platform_info.boardrev = i; - return; - } - } - -failed: - strncpy(revision, "Unknown", len); - olpc_platform_info.boardrev = OLPC_REV_UNKNOWN; -} - -static int olpc_dcon_present = -1; -module_param(olpc_dcon_present, int, 0444); - -/* REV_A CMOS map: - * bit 440; DCON present bit - */ - -#define OLPC_CMOS_DCON_OFFSET (440 / 8) -#define OLPC_CMOS_DCON_MASK 0x01 - -static int __init olpc_init(void) -{ - unsigned char *romsig; - char revision[10]; - - spin_lock_init(&ec_lock); - - romsig = ioremap(0xffffffc0, 16); - - if (!romsig) - return 0; - - if (strncmp(romsig, "CL1 Q", 7)) - goto unmap; - if (strncmp(romsig+6, romsig+13, 3)) { - printk(KERN_INFO "OLPC BIOS signature looks invalid. Assuming not OLPC\n"); - goto unmap; - } - printk(KERN_INFO "OLPC board with OpenFirmware: %.16s\n", romsig); - - olpc_platform_info.flags |= OLPC_F_PRESENT; - - pm_power_off = olpc_power_off; - - /* Get the platform revision */ - platform_detect(revision, sizeof(revision)); - - /* If olpc_dcon_present isn't set by the command line, then - * "detect" it - */ - - if (olpc_dcon_present == -1) { - /* B1 and greater always has a DCON */ - if (olpc_platform_info.boardrev >= OLPC_REV_B1 && - olpc_platform_info.boardrev < OLPC_REV_UNKNOWN) - olpc_dcon_present = 1; - } - - if (olpc_dcon_present) - olpc_platform_info.flags |= OLPC_F_DCON; - - /* Get the EC revision */ - ec_detect(); - - /* Check to see if the VSA exists */ - vsa_detect(); - - printk(KERN_INFO "OLPC board revision: %s (EC=%x)\n", revision, - olpc_platform_info.ecver); - - unmap: - iounmap(romsig); - - return 0; -} - -postcore_initcall(olpc_init); diff --git a/target/linux/olpc/files/arch/i386/kernel/prom.c b/target/linux/olpc/files/arch/i386/kernel/prom.c deleted file mode 100644 index d64bb276f2..0000000000 --- a/target/linux/olpc/files/arch/i386/kernel/prom.c +++ /dev/null @@ -1,478 +0,0 @@ -/* - * Procedures for creating, accessing and interpreting the device tree. - * - * Paul Mackerras August 1996. - * Copyright (C) 1996-2005 Paul Mackerras. - * - * Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner. - * {engebret|bergner}@us.ibm.com - * - * Adapted for sparc64 by David S. Miller davem@davemloft.net - * - * Adapter for i386/OLPC by Andres Salomon <dilinger@debian.org> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/string.h> -#include <linux/mm.h> -#include <linux/bootmem.h> -#include <linux/module.h> -#include <asm/prom.h> -#include <asm/ofw.h> - -/* - * XXX: This is very much a stub; right now we're keeping 2 device trees - * in memory (one for promfs, and one here). That will not remain - * for long! - */ - -static struct device_node *allnodes; - -/* use when traversing tree through the allnext, child, sibling, - * or parent members of struct device_node. - */ -static DEFINE_RWLOCK(devtree_lock); - -int of_device_is_compatible(const struct device_node *device, - const char *compat) -{ - const char* cp; - int cplen, l; - - cp = of_get_property(device, "compatible", &cplen); - if (cp == NULL) - return 0; - while (cplen > 0) { - if (strncmp(cp, compat, strlen(compat)) == 0) - return 1; - l = strlen(cp) + 1; - cp += l; - cplen -= l; - } - - return 0; -} -EXPORT_SYMBOL(of_device_is_compatible); - -struct device_node *of_get_parent(const struct device_node *node) -{ - struct device_node *np; - - if (!node) - return NULL; - - np = node->parent; - - return np; -} -EXPORT_SYMBOL(of_get_parent); - -struct device_node *of_get_next_child(const struct device_node *node, - struct device_node *prev) -{ - struct device_node *next; - - next = prev ? prev->sibling : node->child; - for (; next != 0; next = next->sibling) { - break; - } - - return next; -} -EXPORT_SYMBOL(of_get_next_child); - -struct device_node *of_find_node_by_path(const char *path) -{ - struct device_node *np = allnodes; - - for (; np != 0; np = np->allnext) { - if (np->full_name != 0 && strcmp(np->full_name, path) == 0) - break; - } - - return np; -} -EXPORT_SYMBOL(of_find_node_by_path); - -struct device_node *of_find_node_by_phandle(phandle handle) -{ - struct device_node *np; - - for (np = allnodes; np != 0; np = np->allnext) - if (np->node == handle) - break; - - return np; -} -EXPORT_SYMBOL(of_find_node_by_phandle); - -struct device_node *of_find_node_by_name(struct device_node *from, - const char *name) -{ - struct device_node *np; - - np = from ? from->allnext : allnodes; - for (; np != NULL; np = np->allnext) - if (np->name != NULL && strcmp(np->name, name) == 0) - break; - - return np; -} -EXPORT_SYMBOL(of_find_node_by_name); - -struct device_node *of_find_node_by_type(struct device_node *from, - const char *type) -{ - struct device_node *np; - - np = from ? from->allnext : allnodes; - for (; np != 0; np = np->allnext) - if (np->type != 0 && strcmp(np->type, type) == 0) - break; - - return np; -} -EXPORT_SYMBOL(of_find_node_by_type); - -struct device_node *of_find_compatible_node(struct device_node *from, - const char *type, const char *compatible) -{ - struct device_node *np; - - np = from ? from->allnext : allnodes; - for (; np != 0; np = np->allnext) { - if (type != NULL - && !(np->type != 0 && strcmp(np->type, type) == 0)) - continue; - if (of_device_is_compatible(np, compatible)) - break; - } - - return np; -} -EXPORT_SYMBOL(of_find_compatible_node); - -struct property *of_find_property(const struct device_node *np, - const char *name, - int *lenp) -{ - struct property *pp; - - for (pp = np->properties; pp != 0; pp = pp->next) { - if (strcasecmp(pp->name, name) == 0) { - if (lenp != 0) - *lenp = pp->length; - break; - } - } - return pp; -} -EXPORT_SYMBOL(of_find_property); - -/* - * Find a property with a given name for a given node - * and return the value. - */ -const void *of_get_property(const struct device_node *np, const char *name, - int *lenp) -{ - struct property *pp = of_find_property(np,name,lenp); - return pp ? pp->value : NULL; -} -EXPORT_SYMBOL(of_get_property); - -int of_getintprop_default(struct device_node *np, const char *name, int def) -{ - struct property *prop; - int len; - - prop = of_find_property(np, name, &len); - if (!prop || len != 4) - return def; - - return *(int *) prop->value; -} -EXPORT_SYMBOL(of_getintprop_default); - -int of_n_addr_cells(struct device_node *np) -{ - const int* ip; - do { - if (np->parent) - np = np->parent; - ip = of_get_property(np, "#address-cells", NULL); - if (ip != NULL) - return *ip; - } while (np->parent); - /* No #address-cells property for the root node, default to 2 */ - return 2; -} -EXPORT_SYMBOL(of_n_addr_cells); - -int of_n_size_cells(struct device_node *np) -{ - const int* ip; - do { - if (np->parent) - np = np->parent; - ip = of_get_property(np, "#size-cells", NULL); - if (ip != NULL) - return *ip; - } while (np->parent); - /* No #size-cells property for the root node, default to 1 */ - return 1; -} -EXPORT_SYMBOL(of_n_size_cells); - -int of_set_property(struct device_node *dp, const char *name, void *val, int len) -{ - return -EIO; -} -EXPORT_SYMBOL(of_set_property); - -static unsigned int prom_early_allocated; - -static void * __init prom_early_alloc(unsigned long size) -{ - void *ret; - - ret = kmalloc(size, GFP_KERNEL); - if (ret != NULL) - memset(ret, 0, size); - else - printk(KERN_ERR "ACK! couldn't allocate prom memory!\n"); - - prom_early_allocated += size; - - return ret; -} - -static int is_root_node(const struct device_node *dp) -{ - if (!dp) - return 0; - - return (dp->parent == NULL); -} - -static char * __init build_path_component(struct device_node *dp) -{ - int pathlen; - char *n, *i; - - if (ofw("package-to-path", 3, 1, dp->node, NULL, 0, &pathlen)) { - printk(KERN_ERR "PROM: unable to get path name from OFW!\n"); - return "ERROR"; - } - n = prom_early_alloc(pathlen + 1); - if (ofw("package-to-path", 3, 1, dp->node, n, pathlen+1, &pathlen)) - printk(KERN_ERR "PROM: unable to get path name from OFW\n"); - - if ((i = strrchr(n, '/'))) - n = ++i; /* we only want the file name */ - return n; -} - -static char * __init build_full_name(struct device_node *dp) -{ - int len, ourlen, plen; - char *n; - - plen = strlen(dp->parent->full_name); - ourlen = strlen(dp->path_component_name); - len = ourlen + plen + 2; - - n = prom_early_alloc(len); - strcpy(n, dp->parent->full_name); - if (!is_root_node(dp->parent)) { - strcpy(n + plen, "/"); - plen++; - } - strcpy(n + plen, dp->path_component_name); - - return n; -} - -static struct property * __init build_one_prop(phandle node, char *prev, char *special_name, void *special_val, int special_len) -{ - static struct property *tmp = NULL; - struct property *p; - - if (tmp) { - p = tmp; - memset(p, 0, sizeof(*p) + 32); - tmp = NULL; - } else { - p = prom_early_alloc(sizeof(struct property) + 32); - } - - p->name = (char *) (p + 1); - if (special_name) { - strcpy(p->name, special_name); - p->length = special_len; - p->value = prom_early_alloc(special_len); - memcpy(p->value, special_val, special_len); - } else { - int fl; - if (prev == NULL) { - if (ofw("nextprop", 3, 1, node, "", p->name, &fl)) { - printk(KERN_ERR "PROM: %s: nextprop failed!\n", __func__); - return NULL; - } - } else { - if (ofw("nextprop", 3, 1, node, prev, p->name, &fl)) { - printk(KERN_ERR "PROM: %s: nextprop failed!\n", __func__); - return NULL; - } - } - if (strlen(p->name) == 0 || fl != 1) { - tmp = p; - return NULL; - } - if (ofw("getproplen", 2, 1, node, p->name, &p->length)) { - printk(KERN_ERR "PROM: %s: getproplen failed!\n", __func__); - return NULL; - } - if (p->length <= 0) { - p->length = 0; - } else { - p->value = prom_early_alloc(p->length + 1); - if (ofw("getprop", 4, 1, node, p->name, p->value, p->length, &p->length)) { - printk(KERN_ERR "PROM: %s: getprop failed!\n", __func__); - return NULL; - } - ((unsigned char *)p->value)[p->length] = '\0'; - } - } - return p; -} - -static struct property * __init build_prop_list(phandle node) -{ - struct property *head, *tail; - - head = tail = build_one_prop(node, NULL, - ".node", &node, sizeof(node)); - - tail->next = build_one_prop(node, NULL, NULL, NULL, 0); - tail = tail->next; - while(tail) { - tail->next = build_one_prop(node, tail->name, - NULL, NULL, 0); - tail = tail->next; - } - - return head; -} - -static char * __init get_one_property(phandle node, const char *name) -{ - char *buf = "<NULL>"; - int len; - - if (ofw("getproplen", 2, 1, node, name, &len)) { - printk(KERN_ERR "PROM: %s: getproplen failed!\n", __func__); - return NULL; - } - if (len > 0) { - buf = prom_early_alloc(len); - if (ofw("getprop", 4, 1, node, name, buf, len, &len)) { - printk(KERN_ERR "PROM: %s: getprop failed!\n", __func__); - return NULL; - } - } - - return buf; -} - -static struct device_node * __init create_node(phandle node, struct device_node *parent) -{ - struct device_node *dp; - - if (!node) - return NULL; - - dp = prom_early_alloc(sizeof(*dp)); - dp->parent = parent; - - kref_init(&dp->kref); - - dp->name = get_one_property(node, "name"); - dp->type = get_one_property(node, "device_type"); - dp->node = node; - - dp->properties = build_prop_list(node); - - return dp; -} - -static struct device_node * __init build_tree(struct device_node *parent, phandle node, struct device_node ***nextp) -{ - struct device_node *ret = NULL, *prev_sibling = NULL; - struct device_node *dp; - u32 child; - - while (1) { - dp = create_node(node, parent); - if (!dp) - break; - - if (prev_sibling) - prev_sibling->sibling = dp; - - if (!ret) - ret = dp; - prev_sibling = dp; - - *(*nextp) = dp; - *nextp = &dp->allnext; - - dp->path_component_name = build_path_component(dp); - dp->full_name = build_full_name(dp); - - if (ofw("child", 1, 1, node, &child)) { - printk(KERN_ERR "PROM: %s: fetching child failed!\n", __func__); - return NULL; - } - dp->child = build_tree(dp, child, nextp); - - if (ofw("peer", 1, 1, node, &node)) { - printk(KERN_ERR "PROM: %s: fetching peer failed!\n", __func__); - return NULL; - } - } - - return ret; -} - -static phandle root_node; - -void __init prom_build_devicetree(void) -{ - struct device_node **nextp; - u32 child; - - if (ofw("peer", 1, 1, 0, &root_node)) { - printk(KERN_ERR "PROM: unable to get root node from OFW!\n"); - return; - } - - allnodes = create_node(root_node, NULL); - allnodes->path_component_name = ""; - allnodes->full_name = "/"; - - nextp = &allnodes->allnext; - if (ofw("child", 1, 1, allnodes->node, &child)) { - printk(KERN_ERR "PROM: unable to get child node from OFW!\n"); - return; - } - allnodes->child = build_tree(allnodes, child, &nextp); - printk("PROM: Built device tree with %u bytes of memory.\n", - prom_early_allocated); -} |