1 diff -purN linux_2.6.24_org/arch/x86/Kconfig linux_2.6.24_olpc/arch/x86/Kconfig
2 --- linux_2.6.24_org/arch/x86/Kconfig 2008-02-15 20:11:57.000000000 +0000
3 +++ linux_2.6.24_olpc/arch/x86/Kconfig 2008-02-15 18:59:21.000000000 +0000
4 @@ -1415,6 +1415,9 @@ config PCI_GODIRECT
14 @@ -1425,7 +1428,7 @@ config PCI_BIOS
15 # x86-64 doesn't support PCI BIOS access from long mode so always go direct.
18 - depends on PCI && (X86_64 || (PCI_GODIRECT || PCI_GOANY) || X86_VISWS)
19 + depends on PCI && (X86_64 || (PCI_GODIRECT || PCI_GOANY || PCI_GOOLPC) || X86_VISWS)
23 @@ -1442,6 +1445,11 @@ config PCI_MMCONFIG
24 bool "Support mmconfig PCI config space access"
25 depends on X86_64 && PCI && ACPI
29 + depends on PCI && PCI_GOOLPC
33 bool "Support for DMA Remapping Devices (EXPERIMENTAL)"
34 depends on X86_64 && PCI_MSI && ACPI && EXPERIMENTAL
35 @@ -1561,6 +1569,21 @@ config K8_NB
37 depends on AGP_AMD64 || (X86_64 && (GART_IOMMU || (PCI && NUMA)))
46 + bool "OLPC power management support"
51 + bool "Support for Open Firmware"
54 source "drivers/pcmcia/Kconfig"
56 source "drivers/pci/hotplug/Kconfig"
57 diff -purN linux_2.6.24_org/arch/x86/kernel/Makefile_32 linux_2.6.24_olpc/arch/x86/kernel/Makefile_32
58 --- linux_2.6.24_org/arch/x86/kernel/Makefile_32 2008-02-15 20:11:58.000000000 +0000
59 +++ linux_2.6.24_olpc/arch/x86/kernel/Makefile_32 2008-02-15 18:59:25.000000000 +0000
60 @@ -49,6 +49,13 @@ obj-y += pcspeaker.o
62 obj-$(CONFIG_SCx200) += scx200_32.o
64 +obj-$(CONFIG_OLPC) += olpc.o
65 +obj-$(CONFIG_OLPC_PM) += olpc-pm.o olpc-wakeup.o
66 +obj-$(CONFIG_OPEN_FIRMWARE) += ofw.o
67 +obj-$(PROM_FS) += promfs.o
71 # vsyscall_32.o contains the vsyscall DSO images as __initdata.
72 # We must build both images before we can assemble it.
73 # Note: kbuild does not track this dependency due to usage of .incbin
74 diff -purN linux_2.6.24_org/arch/x86/kernel/ofw.c linux_2.6.24_olpc/arch/x86/kernel/ofw.c
75 --- linux_2.6.24_org/arch/x86/kernel/ofw.c 1970-01-01 01:00:00.000000000 +0100
76 +++ linux_2.6.24_olpc/arch/x86/kernel/ofw.c 2008-02-15 18:59:25.000000000 +0000
79 + * ofw.c - Open Firmware client interface for 32-bit systems.
80 + * This code is intended to be portable to any 32-bit Open Firmware
81 + * implementation with a standard client interface that can be
82 + * called when Linux is running.
84 + * Copyright (C) 2007 Mitch Bradley <wmb@firmworks.com>
85 + * Copyright (C) 2007 Andres Salomon <dilinger@debian.org>
89 +#include <linux/spinlock.h>
90 +#include <linux/module.h>
94 +int (*call_firmware)(int *);
96 +static DEFINE_SPINLOCK(prom_lock);
101 + * The return value from ofw() in all cases is 0 if the attempt to call the
102 + * function succeeded, <0 otherwise. That return value is from the
103 + * gateway function only. Any results from the called function are returned
104 + * via output argument pointers.
106 + * Here are call templates for all the standard OFW client services:
108 + * ofw("test", 1, 1, namestr, &missing);
109 + * ofw("peer", 1, 1, phandle, &sibling_phandle);
110 + * ofw("child", 1, 1, phandle, &child_phandle);
111 + * ofw("parent", 1, 1, phandle, &parent_phandle);
112 + * ofw("instance_to_package", 1, 1, ihandle, &phandle);
113 + * ofw("getproplen", 2, 1, phandle, namestr, &proplen);
114 + * ofw("getprop", 4, 1, phandle, namestr, bufaddr, buflen, &size);
115 + * ofw("nextprop", 3, 1, phandle, previousstr, bufaddr, &flag);
116 + * ofw("setprop", 4, 1, phandle, namestr, bufaddr, len, &size);
117 + * ofw("canon", 3, 1, devspecstr, bufaddr, buflen, &length);
118 + * ofw("finddevice", 1, 1, devspecstr, &phandle);
119 + * ofw("instance-to-path", 3, 1, ihandle, bufaddr, buflen, &length);
120 + * ofw("package-to-path", 3, 1, phandle, bufaddr, buflen, &length);
121 + * ofw("call_method", numin, numout, in0, in1, ..., &out0, &out1, ...);
122 + * ofw("open", 1, 1, devspecstr, &ihandle);
123 + * ofw("close", 1, 0, ihandle);
124 + * ofw("read", 3, 1, ihandle, addr, len, &actual);
125 + * ofw("write", 3, 1, ihandle, addr, len, &actual);
126 + * ofw("seek", 3, 1, ihandle, pos_hi, pos_lo, &status);
127 + * ofw("claim", 3, 1, virtaddr, size, align, &baseaddr);
128 + * ofw("release", 2, 0, virtaddr, size);
129 + * ofw("boot", 1, 0, bootspecstr);
130 + * ofw("enter", 0, 0);
131 + * ofw("exit", 0, 0);
132 + * ofw("chain", 5, 0, virtaddr, size, entryaddr, argsaddr, len);
133 + * ofw("interpret", numin+1, numout+1, cmdstr, in0, ..., &catchres, &out0, ...);
134 + * ofw("set-callback", 1, 1, newfuncaddr, &oldfuncaddr);
135 + * ofw("set-symbol-lookup", 2, 0, symtovaladdr, valtosymaddr);
136 + * ofw("milliseconds", 0, 1, &ms);
139 +int ofw(char *name, int numargs, int numres, ...)
142 + int argarray[MAXARGS+3];
146 + unsigned long flags;
148 + if (!call_firmware)
150 + if ((numargs + numres) > MAXARGS)
151 + return -1; /* spit out an error? */
153 + argarray[0] = (int) name;
154 + argarray[1] = numargs;
155 + argarray[2] = numres;
157 + va_start(ap, numres);
159 + argarray[argnum++] = va_arg(ap, int);
163 + spin_lock_irqsave(&prom_lock, flags);
164 + retval = call_firmware(argarray);
165 + spin_unlock_irqrestore(&prom_lock, flags);
169 + intp = va_arg(ap, int *);
170 + *intp = argarray[argnum++];
178 diff -purN linux_2.6.24_org/arch/x86/kernel/olpc.c linux_2.6.24_olpc/arch/x86/kernel/olpc.c
179 --- linux_2.6.24_org/arch/x86/kernel/olpc.c 1970-01-01 01:00:00.000000000 +0100
180 +++ linux_2.6.24_olpc/arch/x86/kernel/olpc.c 2008-02-15 18:59:25.000000000 +0000
182 +/* Support for the OLPC DCON and OLPC EC access
183 + * Copyright (C) 2006, Advanced Micro Devices, Inc.
185 + * This program is free software; you can redistribute it and/or modify
186 + * it under the terms of the GNU General Public License as published by
187 + * the Free Software Foundation; either version 2 of the License, or
188 + * (at your option) any later version.
191 +#include <linux/autoconf.h>
192 +#include <linux/kernel.h>
193 +#include <linux/init.h>
194 +#include <linux/mc146818rtc.h>
195 +#include <linux/delay.h>
196 +#include <linux/spinlock.h>
198 +#include <asm/olpc.h>
199 +#include <asm/ofw.h>
201 +/* This is our new multi-purpose structure used to contain the
202 + * information about the platform that we detect
205 +struct olpc_platform_t olpc_platform_info;
206 +EXPORT_SYMBOL_GPL(olpc_platform_info);
208 +/*********************************************************************
209 + * EC locking and access
210 + *********************************************************************/
212 +static DEFINE_SPINLOCK(ec_lock);
214 +/* what the timeout *should* be (in ms) */
215 +#define EC_BASE_TIMEOUT 20
217 +/* the timeout that bugs in the EC might force us to actually use */
218 +static int ec_timeout = EC_BASE_TIMEOUT;
220 +static int __init olpc_ec_timeout_set(char *str)
222 + if (get_option(&str, &ec_timeout) != 1) {
223 + ec_timeout = EC_BASE_TIMEOUT;
224 + printk(KERN_ERR "olpc-ec: invalid argument to "
225 + "'olpc_ec_timeout=', ignoring!\n");
227 + printk(KERN_DEBUG "olpc-ec: using %d ms delay for EC commands.\n",
231 +__setup("olpc_ec_timeout=", olpc_ec_timeout_set);
234 + * These *bf_status functions return whether the buffers are full or not.
237 +static inline unsigned int ibf_status(unsigned int port)
239 + return !!(inb(port) & 0x02);
242 +static inline unsigned int obf_status(unsigned int port)
244 + return inb(port) & 0x01;
247 +#define wait_on_ibf(p, d) __wait_on_ibf(__LINE__, (p), (d))
248 +static int __wait_on_ibf(unsigned int line, unsigned int port, int desired)
250 + unsigned int timeo;
251 + int state = ibf_status(port);
253 + for (timeo = ec_timeout; state != desired && timeo; timeo--) {
255 + state = ibf_status(port);
258 + if ((state == desired) && (ec_timeout > EC_BASE_TIMEOUT) &&
259 + timeo < (ec_timeout - EC_BASE_TIMEOUT)) {
260 + printk(KERN_WARNING "olpc-ec: %d: waited %u ms for IBF!\n",
261 + line, ec_timeout - timeo);
264 + return !(state == desired);
267 +#define wait_on_obf(p, d) __wait_on_obf(__LINE__, (p), (d))
268 +static int __wait_on_obf(unsigned int line, unsigned int port, int desired)
270 + unsigned int timeo;
271 + int state = obf_status(port);
273 + for (timeo = ec_timeout; state != desired && timeo; timeo--) {
275 + state = obf_status(port);
278 + if ((state == desired) && (ec_timeout > EC_BASE_TIMEOUT) &&
279 + timeo < (ec_timeout - EC_BASE_TIMEOUT)) {
280 + printk(KERN_WARNING "olpc-ec: %d: waited %u ms for OBF!\n",
281 + line, ec_timeout - timeo);
284 + return !(state == desired);
287 +int olpc_ec_cmd(unsigned char cmd, unsigned char *inbuf, size_t inlen,
288 + unsigned char *outbuf, size_t outlen)
290 + unsigned long flags;
294 + spin_lock_irqsave(&ec_lock, flags);
297 + for (i = 0; i < 10 && (obf_status(0x6c) == 1); i++)
300 + printk(KERN_ERR "olpc-ec: timeout while attempting to "
301 + "clear OBF flag!\n");
305 + if (wait_on_ibf(0x6c, 0)) {
306 + printk(KERN_ERR "olpc-ec: timeout waiting for EC to "
313 + * Note that if we time out during any IBF checks, that's a failure;
314 + * we have to return. There's no way for the kernel to clear that.
316 + * If we time out during an OBF check, we can restart the command;
317 + * reissuing it will clear the OBF flag, and we should be alright.
318 + * The OBF flag will sometimes misbehave due to what we believe
319 + * is a hardware quirk..
321 + printk(KERN_DEBUG "olpc-ec: running cmd 0x%x\n", cmd);
324 + if (wait_on_ibf(0x6c, 0)) {
325 + printk(KERN_ERR "olpc-ec: timeout waiting for EC to read "
330 + if (inbuf && inlen) {
331 + /* write data to EC */
332 + for (i = 0; i < inlen; i++) {
333 + if (wait_on_ibf(0x6c, 0)) {
334 + printk(KERN_ERR "olpc-ec: timeout waiting for"
335 + " EC accept data!\n");
338 + printk(KERN_DEBUG "olpc-ec: sending cmd arg 0x%x\n",
340 + outb(inbuf[i], 0x68);
343 + if (outbuf && outlen) {
344 + /* read data from EC */
345 + for (i = 0; i < outlen; i++) {
346 + if (wait_on_obf(0x6c, 1)) {
347 + printk(KERN_ERR "olpc-ec: timeout waiting for"
348 + " EC to provide data!\n");
351 + outbuf[i] = inb(0x68);
352 + printk(KERN_DEBUG "olpc-ec: received 0x%x\n",
359 + spin_unlock_irqrestore(&ec_lock, flags);
362 +EXPORT_SYMBOL_GPL(olpc_ec_cmd);
364 +/*********************************************************************
366 + *********************************************************************/
371 + olpc_ec_cmd(0x08, NULL, 0, (unsigned char *) &olpc_platform_info.ecver, 1);
374 +/* Check to see if this version of the OLPC board has VSA built
375 + * in, and set a flag
378 +static void __init vsa_detect(void)
382 + outw(0xFC53, 0xAC1C);
383 + outw(0x0003, 0xAC1C);
388 + olpc_platform_info.flags |= OLPC_F_VSA;
391 +static void __init platform_detect(void)
396 + if (ofw("getprop", 4, 1, NULL, "board-revision-int", &rev, 4,
397 + &propsize) || propsize != 4) {
398 + printk(KERN_ERR "ofw: getprop call failed!\n");
401 + olpc_platform_info.boardrev = be32_to_cpu(rev);
404 +static int olpc_dcon_present = -1;
405 +module_param(olpc_dcon_present, int, 0444);
408 + * bit 440; DCON present bit
411 +#define OLPC_CMOS_DCON_OFFSET (440 / 8)
412 +#define OLPC_CMOS_DCON_MASK 0x01
414 +static int __init olpc_init(void)
416 + unsigned char *romsig;
418 + spin_lock_init(&ec_lock);
420 + romsig = ioremap(0xffffffc0, 16);
425 + if (strncmp(romsig, "CL1 Q", 7))
427 + if (strncmp(romsig+6, romsig+13, 3)) {
428 + printk(KERN_INFO "OLPC BIOS signature looks invalid. Assuming not OLPC\n");
431 + printk(KERN_INFO "OLPC board with OpenFirmware: %.16s\n", romsig);
433 + olpc_platform_info.flags |= OLPC_F_PRESENT;
435 + /* Get the platform revision */
438 + /* If olpc_dcon_present isn't set by the command line, then
442 + if (olpc_dcon_present == -1) {
443 + /* B1 and greater always has a DCON */
444 + if (olpc_board_at_least(olpc_board(0xb1)))
445 + olpc_dcon_present = 1;
448 + if (olpc_dcon_present)
449 + olpc_platform_info.flags |= OLPC_F_DCON;
451 + /* Get the EC revision */
454 + /* Check to see if the VSA exists */
457 + printk(KERN_INFO "OLPC board revision: %s%X (EC=%x)\n",
458 + ((olpc_platform_info.boardrev & 0xf) < 8) ? "pre" : "",
459 + olpc_platform_info.boardrev >> 4,
460 + olpc_platform_info.ecver);
468 +postcore_initcall(olpc_init);
469 diff -purN linux_2.6.24_org/arch/x86/kernel/olpc-pm.c linux_2.6.24_olpc/arch/x86/kernel/olpc-pm.c
470 --- linux_2.6.24_org/arch/x86/kernel/olpc-pm.c 1970-01-01 01:00:00.000000000 +0100
471 +++ linux_2.6.24_olpc/arch/x86/kernel/olpc-pm.c 2008-02-15 18:59:26.000000000 +0000
474 + * © 2006 Red Hat, Inc.
475 + * Portions also copyright 2006 Advanced Micro Devices, Inc.
479 +#include <linux/kernel.h>
480 +#include <linux/interrupt.h>
481 +#include <linux/module.h>
482 +#include <linux/delay.h>
483 +#include <linux/input.h>
484 +#include <linux/suspend.h>
485 +#include <linux/bootmem.h>
486 +#include <linux/platform_device.h>
487 +#include <linux/rtc.h>
488 +#include <linux/mc146818rtc.h>
491 +#include <asm/olpc.h>
493 +/* A few words about accessing the ACPI and PM registers. Long story short,
494 + byte and word accesses of the ACPI and PM registers is broken. The only
495 + way to do it really correctly is to use dword accesses, which we do
496 + throughout this code. For more details, please consult Eratta 17 and 18
499 + http://www.amd.com/files/connectivitysolutions/geode/geode_gx/34472D_CS5536_B1_specupdate.pdf
504 +#define CS5536_PM_PWRBTN (1 << 8)
505 +#define CS5536_PM_RTC (1 << 10)
506 +#define CS5536_PM_WAK (1 << 15)
508 +#define GPIO_WAKEUP_EC (1 << 31)
509 +#define GPIO_WAKEUP_LID (1 << 30)
511 +#define PM_MODE_NORMAL 0
512 +#define PM_MODE_TEST 1
513 +#define PM_MODE_MAX 2
515 +/* These, and the battery EC commands, should be in an olpc.h. */
516 +#define EC_WRITE_SCI_MASK 0x1b
517 +#define EC_READ_SCI_MASK 0x1c
519 +extern void do_olpc_suspend_lowlevel(void);
522 + unsigned long address;
523 + unsigned short segment;
524 +} ofw_bios_entry = { 0, __KERNEL_CS };
526 +static int olpc_pm_mode = PM_MODE_NORMAL;
527 +static unsigned long acpi_base;
528 +static unsigned long pms_base;
530 +static int olpc_lid_flag;
532 +static struct input_dev *pm_inputdev;
533 +static struct input_dev *lid_inputdev;
534 +static struct input_dev *ebook_inputdev;
535 +static struct platform_suspend_ops olpc_pm_ops;
537 +static int gpio_wake_events = 0;
538 +static int ebook_state = -1;
539 +static u16 olpc_wakeup_mask = 0;
541 +static unsigned int test_timeout = 0;
542 +static char *wackup_source = "none";
544 +struct platform_device olpc_powerbutton_dev = {
545 + .name = "powerbutton",
549 +struct platform_device olpc_lid_dev = {
554 +static void __init init_ebook_state(void)
556 + if (olpc_ec_cmd(0x2a, NULL, 0, (unsigned char *) &ebook_state, 1)) {
557 + printk(KERN_WARNING "olpc-pm: failed to get EBOOK state!\n");
562 + /* the input layer needs to know what value to default to as well */
563 + input_report_switch(ebook_inputdev, SW_TABLET_MODE, ebook_state);
564 + input_sync(ebook_inputdev);
567 +static void (*battery_callback)(unsigned long);
568 +static DEFINE_SPINLOCK(battery_callback_lock);
570 +/* propagate_events is non-NULL if run from workqueue,
571 + NULL when called at init time to flush SCI queue */
572 +static void process_sci_queue(struct work_struct *propagate_events)
574 + unsigned char data = 0;
575 + unsigned char battery_events = 0;
579 + ret = olpc_ec_cmd(0x84, NULL, 0, &data, 1);
581 + printk(KERN_DEBUG "olpc-pm: SCI 0x%x received\n",
584 + if (wackup_source && !strcmp(wackup_source, "sci")) {
586 + * XXX: in order for this to not be racy, we
587 + * need assurance that we will never get
588 + * preempted by olpc_do_sleep here!
591 + case EC_SCI_SRC_EMPTY:
592 + wackup_source = "empty sci";
594 + case EC_SCI_SRC_GAME:
595 + wackup_source = "key press";
597 + case EC_SCI_SRC_BATTERY:
598 + wackup_source = "battery";
600 + case EC_SCI_SRC_BATSOC:
601 + wackup_source = "battery state change";
603 + case EC_SCI_SRC_BATERR:
604 + wackup_source = "battery error";
606 + case EC_SCI_SRC_EBOOK:
607 + wackup_source = "ebook";
609 + case EC_SCI_SRC_WLAN:
610 + wackup_source = "wlan packet";
612 + case EC_SCI_SRC_ACPWR:
613 + wackup_source = "ac power";
616 + wackup_source = "unknown";
620 + if (data & (EC_SCI_SRC_BATERR | EC_SCI_SRC_BATSOC |
621 + EC_SCI_SRC_BATTERY | EC_SCI_SRC_ACPWR))
622 + battery_events |= data;
623 + else if (data == EC_SCI_SRC_EBOOK) {
624 + ebook_state = !ebook_state;
625 + if (propagate_events) {
626 + input_report_switch(ebook_inputdev,
627 + SW_TABLET_MODE, ebook_state);
628 + input_sync(ebook_inputdev);
632 + } while (data && !ret);
634 + if (battery_events && battery_callback && propagate_events) {
635 + void (*cbk)(unsigned long);
637 + /* Older EC versions didn't distinguish between AC and battery
639 + if (olpc_platform_info.ecver < 0x51)
640 + battery_events = EC_SCI_SRC_BATTERY | EC_SCI_SRC_ACPWR;
642 + spin_lock(&battery_callback_lock);
643 + cbk = battery_callback;
644 + spin_unlock(&battery_callback_lock);
646 + cbk(battery_events);
650 + printk(KERN_WARNING "Failed to clear SCI queue!\n");
653 +static DECLARE_WORK(sci_work, process_sci_queue);
655 +void olpc_register_battery_callback(void (*f)(unsigned long))
657 + spin_lock(&battery_callback_lock);
658 + battery_callback = f;
659 + spin_unlock(&battery_callback_lock);
661 +EXPORT_SYMBOL_GPL(olpc_register_battery_callback);
663 +void olpc_deregister_battery_callback(void)
665 + spin_lock(&battery_callback_lock);
666 + battery_callback = NULL;
667 + spin_unlock(&battery_callback_lock);
668 + cancel_work_sync(&sci_work);
670 +EXPORT_SYMBOL_GPL(olpc_deregister_battery_callback);
673 +static int olpc_pm_interrupt(int irq, void *id)
675 + uint32_t sts, gpe = 0;
677 + sts = inl(acpi_base + PM1_STS);
678 + outl(sts | 0xFFFF, acpi_base + PM1_STS);
680 + if (olpc_board_at_least(olpc_board(0xb2))) {
681 + gpe = inl(acpi_base + PM_GPE0_STS);
682 + outl(0xFFFFFFFF, acpi_base + PM_GPE0_STS);
685 + if (sts & CS5536_PM_PWRBTN) {
686 + if (!wackup_source)
687 + wackup_source = "power button";
688 + printk(KERN_DEBUG "olpm-pm: PM_PWRBTN %sevent received\n",
689 + sts & CS5536_PM_WAK ? "wakeup " : "");
690 + if (!(sts & CS5536_PM_WAK)) {
691 + input_report_key(pm_inputdev, KEY_POWER, 1);
692 + input_sync(pm_inputdev);
693 + /* Do we need to delay this? */
694 + input_report_key(pm_inputdev, KEY_POWER, 0);
695 + input_sync(pm_inputdev);
699 + if (gpe & GPIO_WAKEUP_EC) {
700 + geode_gpio_clear(OLPC_GPIO_ECSCI, GPIO_NEGATIVE_EDGE_STS);
701 + if (!wackup_source)
702 + wackup_source = "sci";
703 + schedule_work(&sci_work);
706 + if (gpe & GPIO_WAKEUP_LID) {
707 + /* Disable events */
708 + geode_gpio_clear(OLPC_GPIO_LID, GPIO_EVENTS_ENABLE);
710 + /* Clear the edge */
713 + geode_gpio_clear(OLPC_GPIO_LID, GPIO_NEGATIVE_EDGE_EN);
715 + geode_gpio_clear(OLPC_GPIO_LID, GPIO_POSITIVE_EDGE_EN);
717 + /* Clear the status too */
718 + geode_gpio_set(OLPC_GPIO_LID, GPIO_NEGATIVE_EDGE_STS);
719 + geode_gpio_set(OLPC_GPIO_LID, GPIO_POSITIVE_EDGE_STS);
721 + /* The line is high when the LID is open, but SW_LID
722 + * should be high when the LID is closed, so we pass the old
723 + * value of olpc_lid_flag
726 + input_report_switch(lid_inputdev, SW_LID, olpc_lid_flag);
727 + input_sync(lid_inputdev);
728 + if (!wackup_source)
729 + wackup_source = "lid";
731 + /* Swap the status */
732 + olpc_lid_flag = !olpc_lid_flag;
735 + geode_gpio_set(OLPC_GPIO_LID, GPIO_NEGATIVE_EDGE_EN);
737 + geode_gpio_set(OLPC_GPIO_LID, GPIO_POSITIVE_EDGE_EN);
739 + /* re-enable the event */
740 + geode_gpio_set(OLPC_GPIO_LID, GPIO_EVENTS_ENABLE);
743 + return IRQ_HANDLED;
746 +int olpc_ec_mask_set(u8 bits)
751 + ret = olpc_ec_cmd(EC_READ_SCI_MASK, NULL, 0, &byte, 1);
753 + printk(KERN_ERR "olpc-pm: error getting SCI mask: %d\n", ret);
756 + /* the high bit is unused, if it is ever unset, that is a good sign
757 + sign of EC communication corruption! */
758 + WARN_ON(!(byte & 0x80));
761 + ret = olpc_ec_cmd(EC_WRITE_SCI_MASK, &byte, 1, NULL, 0);
763 + printk(KERN_ERR "olpc-pm: error setting SCI mask: %d\n", ret);
767 +EXPORT_SYMBOL_GPL(olpc_ec_mask_set);
769 +int olpc_ec_mask_unset(u8 bits)
774 + ret = olpc_ec_cmd(EC_READ_SCI_MASK, NULL, 0, &byte, 1);
776 + printk(KERN_ERR "olpc-pm: error getting SCI mask: %d\n", ret);
779 + /* the high bit is unused, if it is ever unset, that is a good sign
780 + sign of EC communication corruption! */
781 + WARN_ON(!(byte & 0x80));
784 + ret = olpc_ec_cmd(EC_WRITE_SCI_MASK, &byte, 1, NULL, 0);
786 + printk(KERN_ERR "olpc-pm: error setting SCI mask: %d\n", ret);
790 +EXPORT_SYMBOL_GPL(olpc_ec_mask_unset);
793 + * For now, only support STR. We also don't support suspending on
794 + * B1s, due to difficulties with the cafe FPGA.
796 +static int olpc_pm_state_valid(suspend_state_t pm_state)
798 + if (pm_state == PM_SUSPEND_MEM && olpc_board_at_least(olpc_board(0xb2)))
804 +/* This is a catchall function for operations that just don't belong
805 + * anywhere else. Later we will evaluate if these belong in the
806 + * individual device drivers or the firmware.
807 + * If you add something to this function, please explain yourself with
811 +extern void gxfb_flatpanel_control(int state);
813 +static u32 gpio_wakeup[2];
814 +static u64 irq_sources[4];
815 +static u64 mfgpt_irq_msr, mfgpt_nr_msr;
817 +void olpc_fixup_wakeup(void)
819 + u32 base = geode_gpio_base();
822 + /* Enable the flatpanel sequencing as early as possible, because
823 + it takes ~64ms to resume. This probably belongs in the firmware */
825 + //gxfb_flatpanel_control(1);
827 + /* Tell the EC to stop inhibiting SCIs */
828 + olpc_ec_cmd(0x34, NULL, 0, NULL, 0);
830 + /* Restore the interrupt sources */
831 + wrmsrl(MSR_PIC_YSEL_LOW, irq_sources[0]);
832 + wrmsrl(MSR_PIC_ZSEL_LOW, irq_sources[1]);
833 + wrmsrl(MSR_PIC_YSEL_HIGH, irq_sources[2]);
834 + wrmsrl(MSR_PIC_ZSEL_HIGH, irq_sources[3]);
836 + /* Restore the X and Y sources for GPIO */
837 + outl(gpio_wakeup[0], base + GPIO_MAP_X);
838 + outl(gpio_wakeup[1], base + GPIO_MAP_Y);
840 + /* Resture the MFGPT MSRs */
841 + wrmsrl(MFGPT_IRQ_MSR, mfgpt_irq_msr);
842 + wrmsrl(MFGPT_NR_MSR, mfgpt_nr_msr);
844 + for (i=0;i<2;i++) {
845 + /* tell the wireless module to restart USB communication */
846 + olpc_ec_cmd(0x24, NULL, 0, NULL, 0);
849 + /* Turn all events on */
850 + olpc_ec_mask_set(EC_SCI_SRC_ALL);
853 +void olpc_fixup_sleep(void)
855 + u32 base = geode_gpio_base();
858 + /* Save the X and Y sources for GPIO */
859 + gpio_wakeup[0] = inl(base + GPIO_MAP_X);
860 + gpio_wakeup[1] = inl(base + GPIO_MAP_Y);
862 + /* Save the Y and Z unrestricted sources */
864 + rdmsrl(MSR_PIC_YSEL_LOW, irq_sources[0]);
865 + rdmsrl(MSR_PIC_ZSEL_LOW, irq_sources[1]);
866 + rdmsrl(MSR_PIC_YSEL_HIGH, irq_sources[2]);
867 + rdmsrl(MSR_PIC_ZSEL_HIGH, irq_sources[3]);
869 + /* Turn off the MFGPT timers on the way down */
871 + for(i = 0; i < 8; i++) {
872 + u32 val = geode_mfgpt_read(i, MFGPT_REG_SETUP);
874 + if (val & MFGPT_SETUP_SETUP) {
875 + val &= ~MFGPT_SETUP_CNTEN;
876 + geode_mfgpt_write(i, MFGPT_REG_SETUP, val);
880 + /* Save the MFGPT MSRs */
881 + rdmsrl(MFGPT_IRQ_MSR, mfgpt_irq_msr);
882 + rdmsrl(MFGPT_NR_MSR, mfgpt_nr_msr);
884 + if (device_may_wakeup(&olpc_powerbutton_dev.dev))
885 + olpc_wakeup_mask |= CS5536_PM_PWRBTN;
887 + olpc_wakeup_mask &= ~(CS5536_PM_PWRBTN);
889 + if (device_may_wakeup(&olpc_lid_dev.dev)) {
890 + geode_gpio_set(OLPC_GPIO_LID, GPIO_EVENTS_ENABLE);
891 + gpio_wake_events |= GPIO_WAKEUP_LID;
893 + geode_gpio_clear(OLPC_GPIO_LID, GPIO_EVENTS_ENABLE);
894 + gpio_wake_events &= ~(GPIO_WAKEUP_LID);
897 + /* We don't want to wake up on superfluous events */
898 + olpc_ec_mask_unset(EC_SCI_SRC_BATSOC | EC_SCI_SRC_ACPWR);
901 + * Cmd 0x32 tells the EC that we're going into suspend; this was
902 + * added to work around hardware races related to SCI events. This
903 + * should cause the EC to inhibit further SCIs while MAIN_ON is
904 + * transitioning low.
906 + * There's also some sort of EC race whereby the EC gets its
907 + * IBF/OBF flags confused and all future communication (after
908 + * resuming) fails if we suspend too soon after updating
909 + * the EC SCI mask. Having this command after updating the
910 + * SCI mask allows the EC enough time to finish doing what it's
913 + olpc_ec_cmd(0x32, NULL, 0, NULL, 0);
916 +static int olpc_pm_enter(suspend_state_t pm_state)
918 + /* Only STR is supported */
919 + if (pm_state != PM_SUSPEND_MEM)
922 + olpc_fixup_sleep();
924 + /* Set the GPIO wakeup bits */
925 + outl(gpio_wake_events, acpi_base + PM_GPE0_EN);
926 + outl(0xFFFFFFFF, acpi_base + PM_GPE0_STS);
928 + /* Save CPU state */
929 + do_olpc_suspend_lowlevel();
931 + olpc_fixup_wakeup();
933 + /* Restore the SCI wakeup events */
934 + outl(gpio_wake_events, acpi_base + PM_GPE0_EN);
939 +int asmlinkage olpc_do_sleep(u8 sleep_state)
941 + void *pgd_addr = __va(read_cr3());
942 + printk(KERN_ERR "olpc_do_sleep!\n"); /* this needs to remain here so
943 + * that gcc doesn't optimize
944 + * away our __va! */
945 + /* FIXME: Set the SCI bits we want to wake up on here */
947 + /* FIXME: Set any other SCI events that we might want here */
949 + outl((olpc_wakeup_mask << 16) | 0xFFFF, acpi_base + PM1_STS);
951 + wackup_source = NULL;
953 + /* If we are in test mode, then just return (simulate a successful
954 + suspend/resume). Otherwise, if we are doing the real thing,
955 + then go for the gusto */
957 + if (olpc_pm_mode != PM_MODE_TEST) {
958 + __asm__ __volatile__("movl %0,%%eax" : : "r" (pgd_addr));
959 + __asm__("call *(%%edi); cld"
960 + : : "D" (&ofw_bios_entry));
961 + __asm__ __volatile__("movb $0x34, %al\n\t"
962 + "outb %al, $0x70\n\t"
963 + "movb $0x30, %al\n\t"
964 + "outb %al, $0x71\n\t");
967 + else if (test_timeout > 0) {
970 + /* Delay N seconds for testing purposes */
972 + for(t = 0; t < test_timeout; t++)
979 +static void olpc_power_off(void)
981 + printk(KERN_INFO "OLPC power off sequence...\n");
983 + /* Enable all of these controls with 0 delay */
984 + outl(0x40000000, pms_base + PM_SCLK);
985 + outl(0x40000000, pms_base + PM_IN_SLPCTL);
986 + outl(0x40000000, pms_base + PM_WKXD);
987 + outl(0x40000000, pms_base + PM_WKD);
989 + /* Clear status bits (possibly unnecessary) */
990 + outl(0x0002ffff, pms_base + PM_SSC);
991 + outl(0xffffffff, acpi_base + PM_GPE0_STS);
993 + /* Write SLP_EN bit to start the machinery */
994 + outl(0x00002000, acpi_base + PM1_CNT);
997 +/* This code will slowly disappear as we fixup the issues in the BIOS */
999 +static void __init olpc_fixup_bios(void)
1001 + unsigned long hi, lo;
1003 + if (olpc_has_vsa()) {
1004 + /* The VSA aggressively sets up the ACPI and PM register for
1005 + * trapping - its not enough to force these values in the BIOS -
1006 + * they seem to be changed during PCI init as well.
1009 + /* Change the PM registers to decode to the DD */
1011 + rdmsr(0x510100e2, lo, hi);
1013 + wrmsr(0x510100e2, lo, hi);
1015 + /* Change the ACPI registers to decode to the DD */
1017 + rdmsr(0x510100e3, lo, hi);
1019 + wrmsr(0x510100e3, lo, hi);
1022 + /* GPIO24 controls WORK_AUX */
1024 + geode_gpio_set(OLPC_GPIO_WORKAUX, GPIO_OUTPUT_ENABLE);
1025 + geode_gpio_set(OLPC_GPIO_WORKAUX, GPIO_OUTPUT_AUX1);
1027 + if (olpc_board_at_least(olpc_board(0xb2))) {
1028 + /* GPIO10 is connected to the thermal alarm */
1029 + geode_gpio_set(OLPC_GPIO_THRM_ALRM, GPIO_INPUT_ENABLE);
1030 + geode_gpio_set(OLPC_GPIO_THRM_ALRM, GPIO_INPUT_AUX1);
1032 + /* Set up to get LID events */
1033 + geode_gpio_set(OLPC_GPIO_LID, GPIO_INPUT_ENABLE);
1035 + /* Clear edge detection and event enable for now */
1036 + geode_gpio_clear(OLPC_GPIO_LID, GPIO_EVENTS_ENABLE);
1037 + geode_gpio_clear(OLPC_GPIO_LID, GPIO_NEGATIVE_EDGE_EN);
1038 + geode_gpio_clear(OLPC_GPIO_LID, GPIO_POSITIVE_EDGE_EN);
1040 + geode_gpio_set(OLPC_GPIO_LID, GPIO_NEGATIVE_EDGE_STS);
1041 + geode_gpio_set(OLPC_GPIO_LID, GPIO_POSITIVE_EDGE_STS);
1043 + /* Set the LID to cause an PME event on group 6 */
1044 + geode_gpio_event_pme(OLPC_GPIO_LID, 6);
1046 + /* Set PME group 6 to fire the SCI interrupt */
1047 + geode_gpio_set_irq(6, sci_irq);
1050 + geode_gpio_set(OLPC_GPIO_ECSCI, GPIO_INPUT_ENABLE);
1052 + /* Clear pending events */
1054 + geode_gpio_set(OLPC_GPIO_ECSCI, GPIO_NEGATIVE_EDGE_STS);
1055 + geode_gpio_set(OLPC_GPIO_ECSCI, GPIO_POSITIVE_EDGE_STS);
1057 + //geode_gpio_set(OLPC_GPIO_ECSCI, GPIO_NEGATIVE_EDGE_EN);
1058 + geode_gpio_set(OLPC_GPIO_ECSCI, GPIO_EVENTS_ENABLE);
1060 + /* Set the SCI to cause a PME event on group 7 */
1061 + geode_gpio_event_pme(OLPC_GPIO_ECSCI, 7);
1063 + /* And have group 6 also fire the SCI interrupt */
1064 + geode_gpio_set_irq(7, sci_irq);
1067 +/* This provides a control file for setting up testing of the
1068 + power management system. For now, there is just one setting:
1069 + "test" which means that we don't actually enter the power
1073 +static const char * const pm_states[] = {
1074 + [PM_MODE_NORMAL] = "normal",
1075 + [PM_MODE_TEST] = "test",
1078 +extern struct mutex pm_mutex;
1079 +extern struct kset power_subsys;
1081 +static ssize_t control_show(struct kset *s, char *buf)
1083 + return sprintf(buf, "%s\n", pm_states[olpc_pm_mode]);
1086 +static ssize_t control_store(struct kset *s, const char *buf, size_t n)
1091 + p = memchr(buf, '\n', n);
1092 + len = p ? p - buf : n;
1094 + /* Grab the mutex */
1095 + mutex_lock(&pm_mutex);
1097 + for(i = 0; i < PM_MODE_MAX; i++) {
1098 + if (!strncmp(buf, pm_states[i], len)) {
1104 + mutex_unlock(&pm_mutex);
1106 + return (i == PM_MODE_MAX) ? -EINVAL : n;
1109 +static ssize_t timeout_show(struct kset *s, char *buf)
1111 + return sprintf(buf, "%d\n", test_timeout);
1114 +static ssize_t timeout_store(struct kset *s, const char *buf, size_t n)
1116 + unsigned int t = simple_strtoul(buf, NULL, 0);
1122 +static ssize_t wackup_show(struct kset *s, char *buf)
1124 + return sprintf(buf, "%s\n", wackup_source ? wackup_source : "none");
1127 +static struct subsys_attribute control_attr = {
1129 + .name = "olpc-pm",
1132 + .show = control_show,
1133 + .store = control_store,
1136 +static struct subsys_attribute test_attr = {
1138 + .name = "test-timeout",
1141 + .show = timeout_show,
1142 + .store = timeout_store,
1145 +static struct subsys_attribute wackup_attr = {
1147 + .name = "wakeup-source",
1150 + .show = wackup_show,
1153 +static struct attribute * olpc_attributes[] = {
1154 + &control_attr.attr,
1156 + &wackup_attr.attr,
1160 +static struct attribute_group olpc_attrs = {
1161 + .attrs = olpc_attributes,
1164 +static int __init alloc_inputdevs(void)
1166 + int ret = -ENOMEM;
1168 + pm_inputdev = input_allocate_device();
1172 + pm_inputdev->name = "OLPC PM";
1173 + pm_inputdev->phys = "olpc_pm/input0";
1174 + set_bit(EV_KEY, pm_inputdev->evbit);
1175 + set_bit(KEY_POWER, pm_inputdev->keybit);
1177 + ret = input_register_device(pm_inputdev);
1179 + printk(KERN_ERR "olpc-pm: failed to register PM input device: %d\n", ret);
1183 + lid_inputdev = input_allocate_device();
1184 + if (!lid_inputdev)
1187 + lid_inputdev->name = "OLPC lid switch";
1188 + lid_inputdev->phys = "olpc_pm/input1";
1189 + set_bit(EV_SW, lid_inputdev->evbit);
1190 + set_bit(SW_LID, lid_inputdev->swbit);
1192 + ret = input_register_device(lid_inputdev);
1194 + printk(KERN_ERR "olpc-pm: failed to register lid input device: %d\n", ret);
1198 + ebook_inputdev = input_allocate_device();
1199 + if (!ebook_inputdev)
1202 + ebook_inputdev->name = "OLPC ebook switch";
1203 + ebook_inputdev->phys = "olpc_pm/input2";
1204 + set_bit(EV_SW, ebook_inputdev->evbit);
1205 + set_bit(SW_TABLET_MODE, ebook_inputdev->swbit);
1207 + ret = input_register_device(ebook_inputdev);
1209 + printk(KERN_ERR "olpc-pm: failed to register ebook input device: %d\n", ret);
1215 + if (ebook_inputdev) {
1216 + input_unregister_device(ebook_inputdev);
1217 + ebook_inputdev = NULL;
1219 + if (lid_inputdev) {
1220 + input_unregister_device(lid_inputdev);
1221 + lid_inputdev = NULL;
1223 + if (pm_inputdev) {
1224 + input_unregister_device(pm_inputdev);
1225 + pm_inputdev = NULL;
1231 +static int __init olpc_pm_init(void)
1236 + if (!machine_is_olpc())
1239 + acpi_base = geode_acpi_base();
1240 + pms_base = geode_pms_base();
1242 + if (!acpi_base || !pms_base)
1245 + pm_power_off = olpc_power_off;
1247 + ret = alloc_inputdevs();
1251 + rdmsr(0x51400020, lo, hi);
1252 + sci_irq = (lo >> 20) & 15;
1255 + printk(KERN_INFO "SCI is mapped to IRQ %d\n", sci_irq);
1257 + /* Zero doesn't mean zero -- it means masked */
1258 + printk(KERN_INFO "SCI unmapped. Mapping to IRQ 3\n");
1261 + wrmsrl(0x51400020, lo);
1264 + olpc_fixup_bios();
1266 + lo = inl(pms_base + PM_FSD);
1268 + /* Lock, enable failsafe, 4 seconds */
1269 + outl(0xc001f400, pms_base + PM_FSD);
1271 + /* Here we set up the SCI events we're interested in during
1272 + * real-time. We have no sleep button, and the RTC doesn't make
1273 + * sense, so set up the power button
1276 + outl(inl(acpi_base) | ((CS5536_PM_PWRBTN) << 16), acpi_base);
1278 + if (olpc_board_at_least(olpc_board(0xb2))) {
1279 + gpio_wake_events |= GPIO_WAKEUP_LID;
1281 + /* Get the current value of the GPIO, and set up the edges */
1282 + olpc_lid_flag = geode_gpio_isset(OLPC_GPIO_LID, GPIO_READ_BACK);
1284 + /* Watch for the opposite edge */
1286 + if (olpc_lid_flag)
1287 + geode_gpio_set(OLPC_GPIO_LID, GPIO_NEGATIVE_EDGE_EN);
1289 + geode_gpio_set(OLPC_GPIO_LID, GPIO_POSITIVE_EDGE_EN);
1291 + /* Enable the event */
1292 + geode_gpio_set(OLPC_GPIO_LID, GPIO_EVENTS_ENABLE);
1295 + /* Set up the EC SCI */
1297 + gpio_wake_events |= GPIO_WAKEUP_EC;
1299 + outl(gpio_wake_events, acpi_base + PM_GPE0_EN);
1300 + outl(0xFFFFFFFF, acpi_base + PM_GPE0_STS);
1302 + /* Select level triggered in PIC */
1304 + if (sci_irq < 8) {
1306 + lo |= 1 << sci_irq;
1310 + lo |= 1 << (sci_irq - 8);
1313 + /* Clear pending interrupt */
1314 + outl(inl(acpi_base) | 0xFFFF, acpi_base);
1315 + process_sci_queue(0); /* we just want to flush the queue here */
1316 + init_ebook_state();
1318 + /* Enable the interrupt */
1320 + ret = request_irq(sci_irq, &olpc_pm_interrupt, 0, "SCI", &acpi_base);
1323 + printk(KERN_ERR "Error registering SCI: %d\n", ret);
1327 + ofw_bios_entry.address = 0xF0000 + PAGE_OFFSET;
1328 + suspend_set_ops(&olpc_pm_ops);
1330 + sysfs_create_group(&power_subsys.kobj, &olpc_attrs);
1336 +#if defined (CONFIG_RTC_DRV_CMOS) || defined (CONFIG_RTC_DRV_CMOS_MODULE)
1337 +struct resource rtc_platform_resource[2] = {
1339 + .flags = IORESOURCE_IO,
1340 + .start = RTC_PORT(0),
1341 + .end = RTC_PORT(0) + RTC_IO_EXTENT
1344 + .flags = IORESOURCE_IRQ,
1351 +static void rtc_wake_on(struct device *dev)
1353 + olpc_wakeup_mask |= CS5536_PM_RTC;
1356 +static void rtc_wake_off(struct device *dev)
1358 + olpc_wakeup_mask &= ~(CS5536_PM_RTC);
1361 +static struct cmos_rtc_board_info rtc_info = {
1362 + .rtc_day_alarm = 0,
1363 + .rtc_mon_alarm = 0,
1365 + .wake_on = rtc_wake_on,
1366 + .wake_off = rtc_wake_off,
1369 +struct platform_device olpc_rtc_device = {
1370 + .name = "rtc_cmos",
1372 + .num_resources = ARRAY_SIZE(rtc_platform_resource),
1373 + .dev.platform_data = &rtc_info,
1374 + .resource = rtc_platform_resource,
1377 +static int __init olpc_platform_init(void)
1379 + rdmsrl(MSR_RTC_DOMA_OFFSET, rtc_info.rtc_day_alarm);
1380 + rdmsrl(MSR_RTC_MONA_OFFSET, rtc_info.rtc_mon_alarm);
1381 + rdmsrl(MSR_RTC_CEN_OFFSET, rtc_info.rtc_century);
1383 + (void)platform_device_register(&olpc_rtc_device);
1384 + device_init_wakeup(&olpc_rtc_device.dev, 1);
1386 + (void)platform_device_register(&olpc_powerbutton_dev);
1387 + device_init_wakeup(&olpc_powerbutton_dev.dev, 1);
1389 + (void)platform_device_register(&olpc_lid_dev);
1390 + device_init_wakeup(&olpc_lid_dev.dev, 1);
1394 +arch_initcall(olpc_platform_init);
1395 +#endif /* CONFIG_RTC_DRV_CMOS */
1397 +static void olpc_pm_exit(void)
1399 + /* Clear any pending events, and disable them */
1400 + outl(0xFFFF, acpi_base+2);
1402 + free_irq(sci_irq, &acpi_base);
1403 + input_unregister_device(pm_inputdev);
1404 + input_unregister_device(lid_inputdev);
1405 + input_unregister_device(ebook_inputdev);
1408 +static struct platform_suspend_ops olpc_pm_ops = {
1409 + .valid = olpc_pm_state_valid,
1410 + .enter = olpc_pm_enter,
1413 +module_init(olpc_pm_init);
1414 +module_exit(olpc_pm_exit);
1416 +MODULE_LICENSE("GPL");
1417 +MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
1418 +MODULE_DESCRIPTION("AMD Geode power management for OLPC CL1");
1419 diff -purN linux_2.6.24_org/arch/x86/kernel/olpc-sleep.S linux_2.6.24_olpc/arch/x86/kernel/olpc-sleep.S
1420 --- linux_2.6.24_org/arch/x86/kernel/olpc-sleep.S 1970-01-01 01:00:00.000000000 +0100
1421 +++ linux_2.6.24_olpc/arch/x86/kernel/olpc-sleep.S 2008-02-15 18:59:26.000000000 +0000
1425 +ENTRY(olpc_sleep_asm)
1427 + ;; Get the value of PM1_CNT and store it off
1435 + ;; flush the cache
1438 + ;; GX2 must disable refresh before going into self-refresh
1439 + mov 2000000180xh, ecx
1442 + and 0FF0000FFh, eax
1445 + ;; Now, put the memory into self refresh
1452 + ;; Thats all she wrote - time to go to sleep
1462 diff -purN linux_2.6.24_org/arch/x86/kernel/olpc-wakeup.S linux_2.6.24_olpc/arch/x86/kernel/olpc-wakeup.S
1463 --- linux_2.6.24_org/arch/x86/kernel/olpc-wakeup.S 1970-01-01 01:00:00.000000000 +0100
1464 +++ linux_2.6.24_olpc/arch/x86/kernel/olpc-wakeup.S 2008-02-15 18:59:25.000000000 +0000
1467 +#include <linux/linkage.h>
1468 +#include <asm/segment.h>
1469 +#include <asm/page.h>
1471 + .macro writepost,value
1487 + # Clear any dangerous flags
1495 + movl $swsusp_pg_dir - __PAGE_OFFSET, %eax
1498 + movl saved_cr4, %eax
1501 + movl saved_cr0, %eax
1506 + ljmpl $__KERNEL_CS,$wakeup_return
1512 + movw $__KERNEL_DS, %ax
1522 + ljmp $(__KERNEL_CS),$1f
1528 + # Go back to the return point
1538 + movl %edx, saved_cr4
1541 + movl %edx, saved_cr0
1546 + movl %ebx, saved_context_ebx
1547 + movl %ebp, saved_context_ebp
1548 + movl %esi, saved_context_esi
1549 + movl %edi, saved_context_edi
1552 + popl saved_context_eflags
1558 + movl saved_context_ebp, %ebp
1559 + movl saved_context_ebx, %ebx
1560 + movl saved_context_esi, %esi
1561 + movl saved_context_edi, %edi
1563 + pushl saved_context_eflags
1569 +ENTRY(do_olpc_suspend_lowlevel)
1570 + call save_processor_state
1571 + call save_registers
1573 + # This is the stack context we want to remember
1574 + movl %esp, saved_context_esp
1577 + call olpc_do_sleep
1582 + movl saved_context_esp, %esp
1586 + call restore_registers
1587 + call restore_processor_state
1593 +saved_gdt: .long 0,0
1594 +saved_idt: .long 0,0
1599 diff -purN linux_2.6.24_org/arch/x86/kernel/prom.c linux_2.6.24_olpc/arch/x86/kernel/prom.c
1600 --- linux_2.6.24_org/arch/x86/kernel/prom.c 1970-01-01 01:00:00.000000000 +0100
1601 +++ linux_2.6.24_olpc/arch/x86/kernel/prom.c 2008-02-15 18:59:26.000000000 +0000
1604 + * Procedures for creating, accessing and interpreting the device tree.
1606 + * Paul Mackerras August 1996.
1607 + * Copyright (C) 1996-2005 Paul Mackerras.
1609 + * Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
1610 + * {engebret|bergner}@us.ibm.com
1612 + * Adapted for sparc64 by David S. Miller davem@davemloft.net
1614 + * Adapter for i386/OLPC by Andres Salomon <dilinger@debian.org>
1616 + * This program is free software; you can redistribute it and/or
1617 + * modify it under the terms of the GNU General Public License
1618 + * as published by the Free Software Foundation; either version
1619 + * 2 of the License, or (at your option) any later version.
1622 +#include <linux/kernel.h>
1623 +#include <linux/types.h>
1624 +#include <linux/string.h>
1625 +#include <linux/mm.h>
1626 +#include <linux/bootmem.h>
1627 +#include <linux/module.h>
1628 +#include <asm/prom.h>
1629 +#include <asm/ofw.h>
1632 + * XXX: This is very much a stub; right now we're keeping 2 device trees
1633 + * in memory (one for promfs, and one here). That will not remain
1637 +static struct device_node *allnodes;
1639 +/* use when traversing tree through the allnext, child, sibling,
1640 + * or parent members of struct device_node.
1642 +static DEFINE_RWLOCK(devtree_lock);
1644 +int of_device_is_compatible(const struct device_node *device,
1645 + const char *compat)
1650 + cp = of_get_property(device, "compatible", &cplen);
1653 + while (cplen > 0) {
1654 + if (strncmp(cp, compat, strlen(compat)) == 0)
1656 + l = strlen(cp) + 1;
1663 +EXPORT_SYMBOL(of_device_is_compatible);
1665 +struct device_node *of_get_parent(const struct device_node *node)
1667 + struct device_node *np;
1672 + np = node->parent;
1676 +EXPORT_SYMBOL(of_get_parent);
1678 +struct device_node *of_get_next_child(const struct device_node *node,
1679 + struct device_node *prev)
1681 + struct device_node *next;
1683 + next = prev ? prev->sibling : node->child;
1684 + for (; next != 0; next = next->sibling) {
1690 +EXPORT_SYMBOL(of_get_next_child);
1692 +struct device_node *of_find_node_by_path(const char *path)
1694 + struct device_node *np = allnodes;
1696 + for (; np != 0; np = np->allnext) {
1697 + if (np->full_name != 0 && strcmp(np->full_name, path) == 0)
1703 +EXPORT_SYMBOL(of_find_node_by_path);
1705 +struct device_node *of_find_node_by_phandle(phandle handle)
1707 + struct device_node *np;
1709 + for (np = allnodes; np != 0; np = np->allnext)
1710 + if (np->node == handle)
1715 +EXPORT_SYMBOL(of_find_node_by_phandle);
1717 +struct device_node *of_find_node_by_name(struct device_node *from,
1720 + struct device_node *np;
1722 + np = from ? from->allnext : allnodes;
1723 + for (; np != NULL; np = np->allnext)
1724 + if (np->name != NULL && strcmp(np->name, name) == 0)
1729 +EXPORT_SYMBOL(of_find_node_by_name);
1731 +struct device_node *of_find_node_by_type(struct device_node *from,
1734 + struct device_node *np;
1736 + np = from ? from->allnext : allnodes;
1737 + for (; np != 0; np = np->allnext)
1738 + if (np->type != 0 && strcmp(np->type, type) == 0)
1743 +EXPORT_SYMBOL(of_find_node_by_type);
1745 +struct device_node *of_find_compatible_node(struct device_node *from,
1746 + const char *type, const char *compatible)
1748 + struct device_node *np;
1750 + np = from ? from->allnext : allnodes;
1751 + for (; np != 0; np = np->allnext) {
1753 + && !(np->type != 0 && strcmp(np->type, type) == 0))
1755 + if (of_device_is_compatible(np, compatible))
1761 +EXPORT_SYMBOL(of_find_compatible_node);
1763 +struct property *of_find_property(const struct device_node *np,
1767 + struct property *pp;
1769 + for (pp = np->properties; pp != 0; pp = pp->next) {
1770 + if (strcasecmp(pp->name, name) == 0) {
1772 + *lenp = pp->length;
1778 +EXPORT_SYMBOL(of_find_property);
1781 + * Find a property with a given name for a given node
1782 + * and return the value.
1784 +const void *of_get_property(const struct device_node *np, const char *name,
1787 + struct property *pp = of_find_property(np,name,lenp);
1788 + return pp ? pp->value : NULL;
1790 +EXPORT_SYMBOL(of_get_property);
1792 +int of_getintprop_default(struct device_node *np, const char *name, int def)
1794 + struct property *prop;
1797 + prop = of_find_property(np, name, &len);
1798 + if (!prop || len != 4)
1801 + return *(int *) prop->value;
1803 +EXPORT_SYMBOL(of_getintprop_default);
1805 +int of_n_addr_cells(struct device_node *np)
1811 + ip = of_get_property(np, "#address-cells", NULL);
1814 + } while (np->parent);
1815 + /* No #address-cells property for the root node, default to 2 */
1818 +EXPORT_SYMBOL(of_n_addr_cells);
1820 +int of_n_size_cells(struct device_node *np)
1826 + ip = of_get_property(np, "#size-cells", NULL);
1829 + } while (np->parent);
1830 + /* No #size-cells property for the root node, default to 1 */
1833 +EXPORT_SYMBOL(of_n_size_cells);
1835 +int of_set_property(struct device_node *dp, const char *name, void *val, int len)
1839 +EXPORT_SYMBOL(of_set_property);
1841 +static unsigned int prom_early_allocated;
1843 +static void * __init prom_early_alloc(unsigned long size)
1847 + ret = kmalloc(size, GFP_KERNEL);
1849 + memset(ret, 0, size);
1851 + printk(KERN_ERR "ACK! couldn't allocate prom memory!\n");
1853 + prom_early_allocated += size;
1858 +static int is_root_node(const struct device_node *dp)
1863 + return (dp->parent == NULL);
1866 +static char * __init build_path_component(struct device_node *dp)
1871 + if (ofw("package-to-path", 3, 1, dp->node, NULL, 0, &pathlen)) {
1872 + printk(KERN_ERR "PROM: unable to get path name from OFW!\n");
1875 + n = prom_early_alloc(pathlen + 1);
1876 + if (ofw("package-to-path", 3, 1, dp->node, n, pathlen+1, &pathlen))
1877 + printk(KERN_ERR "PROM: unable to get path name from OFW\n");
1879 + if ((i = strrchr(n, '/')))
1880 + n = ++i; /* we only want the file name */
1884 +static char * __init build_full_name(struct device_node *dp)
1886 + int len, ourlen, plen;
1889 + plen = strlen(dp->parent->full_name);
1890 + ourlen = strlen(dp->path_component_name);
1891 + len = ourlen + plen + 2;
1893 + n = prom_early_alloc(len);
1894 + strcpy(n, dp->parent->full_name);
1895 + if (!is_root_node(dp->parent)) {
1896 + strcpy(n + plen, "/");
1899 + strcpy(n + plen, dp->path_component_name);
1904 +static struct property * __init build_one_prop(phandle node, char *prev, char *special_name, void *special_val, int special_len)
1906 + static struct property *tmp = NULL;
1907 + struct property *p;
1911 + memset(p, 0, sizeof(*p) + 32);
1914 + p = prom_early_alloc(sizeof(struct property) + 32);
1917 + p->name = (char *) (p + 1);
1918 + if (special_name) {
1919 + strcpy(p->name, special_name);
1920 + p->length = special_len;
1921 + p->value = prom_early_alloc(special_len);
1922 + memcpy(p->value, special_val, special_len);
1925 + if (prev == NULL) {
1926 + if (ofw("nextprop", 3, 1, node, "", p->name, &fl)) {
1927 + printk(KERN_ERR "PROM: %s: nextprop failed!\n", __func__);
1931 + if (ofw("nextprop", 3, 1, node, prev, p->name, &fl)) {
1932 + printk(KERN_ERR "PROM: %s: nextprop failed!\n", __func__);
1936 + if (strlen(p->name) == 0 || fl != 1) {
1940 + if (ofw("getproplen", 2, 1, node, p->name, &p->length)) {
1941 + printk(KERN_ERR "PROM: %s: getproplen failed!\n", __func__);
1944 + if (p->length <= 0) {
1947 + p->value = prom_early_alloc(p->length + 1);
1948 + if (ofw("getprop", 4, 1, node, p->name, p->value, p->length, &p->length)) {
1949 + printk(KERN_ERR "PROM: %s: getprop failed!\n", __func__);
1952 + ((unsigned char *)p->value)[p->length] = '\0';
1958 +static struct property * __init build_prop_list(phandle node)
1960 + struct property *head, *tail;
1962 + head = tail = build_one_prop(node, NULL,
1963 + ".node", &node, sizeof(node));
1965 + tail->next = build_one_prop(node, NULL, NULL, NULL, 0);
1966 + tail = tail->next;
1968 + tail->next = build_one_prop(node, tail->name,
1970 + tail = tail->next;
1976 +static char * __init get_one_property(phandle node, const char *name)
1978 + char *buf = "<NULL>";
1981 + if (ofw("getproplen", 2, 1, node, name, &len)) {
1982 + printk(KERN_ERR "PROM: %s: getproplen failed!\n", __func__);
1986 + buf = prom_early_alloc(len);
1987 + if (ofw("getprop", 4, 1, node, name, buf, len, &len)) {
1988 + printk(KERN_ERR "PROM: %s: getprop failed!\n", __func__);
1996 +static struct device_node * __init create_node(phandle node, struct device_node *parent)
1998 + struct device_node *dp;
2003 + dp = prom_early_alloc(sizeof(*dp));
2004 + dp->parent = parent;
2006 + kref_init(&dp->kref);
2008 + dp->name = get_one_property(node, "name");
2009 + dp->type = get_one_property(node, "device_type");
2012 + dp->properties = build_prop_list(node);
2017 +static struct device_node * __init build_tree(struct device_node *parent, phandle node, struct device_node ***nextp)
2019 + struct device_node *ret = NULL, *prev_sibling = NULL;
2020 + struct device_node *dp;
2024 + dp = create_node(node, parent);
2029 + prev_sibling->sibling = dp;
2033 + prev_sibling = dp;
2036 + *nextp = &dp->allnext;
2038 + dp->path_component_name = build_path_component(dp);
2039 + dp->full_name = build_full_name(dp);
2041 + if (ofw("child", 1, 1, node, &child)) {
2042 + printk(KERN_ERR "PROM: %s: fetching child failed!\n", __func__);
2045 + dp->child = build_tree(dp, child, nextp);
2047 + if (ofw("peer", 1, 1, node, &node)) {
2048 + printk(KERN_ERR "PROM: %s: fetching peer failed!\n", __func__);
2056 +static phandle root_node;
2058 +void __init prom_build_devicetree(void)
2060 + struct device_node **nextp;
2063 + if (ofw("peer", 1, 1, 0, &root_node)) {
2064 + printk(KERN_ERR "PROM: unable to get root node from OFW!\n");
2068 + allnodes = create_node(root_node, NULL);
2069 + allnodes->path_component_name = "";
2070 + allnodes->full_name = "/";
2072 + nextp = &allnodes->allnext;
2073 + if (ofw("child", 1, 1, allnodes->node, &child)) {
2074 + printk(KERN_ERR "PROM: unable to get child node from OFW!\n");
2077 + allnodes->child = build_tree(allnodes, child, &nextp);
2078 + printk("PROM: Built device tree with %u bytes of memory.\n",
2079 + prom_early_allocated);
2081 diff -purN linux_2.6.24_org/arch/x86/pci/olpc.c linux_2.6.24_olpc/arch/x86/pci/olpc.c
2082 --- linux_2.6.24_org/arch/x86/pci/olpc.c 1970-01-01 01:00:00.000000000 +0100
2083 +++ linux_2.6.24_olpc/arch/x86/pci/olpc.c 2008-02-15 18:59:22.000000000 +0000
2086 + * olpcpci.c - Low-level PCI config space access for OLPC systems
2087 + * without the VSA PCI virtualization software.
2089 + * The AMD Geode chipset (GX2 processor, cs5536 I/O companion device)
2090 + * has some I/O functions (display, southbridge, sound, USB HCIs, etc)
2091 + * that more or less behave like PCI devices, but the hardware doesn't
2092 + * directly implement the PCI configuration space headers. AMD provides
2093 + * "VSA" (Virtual System Architecture) software that emulates PCI config
2094 + * space for these devices, by trapping I/O accesses to PCI config register
2095 + * (CF8/CFC) and running some code in System Management Mode interrupt state.
2096 + * On the OLPC platform, we don't want to use that VSA code because
2097 + * (a) it slows down suspend/resume, and (b) recompiling it requires special
2098 + * compilers that are hard to get. So instead of letting the complex VSA
2099 + * code simulate the PCI config registers for the on-chip devices, we
2100 + * just simulate them the easy way, by inserting the code into the
2101 + * pci_write_config and pci_read_config path. Most of the config registers
2102 + * are read-only anyway, so the bulk of the simulation is just table lookup.
2105 +#include <linux/pci.h>
2106 +#include <linux/init.h>
2107 +#include <asm/olpc.h>
2108 +#include <asm/geode.h>
2114 + * In the tables below, the first two line (8 longwords) are the
2115 + * size masks that are used when the higher level PCI code determines
2116 + * the size of the region by writing ~0 to a base address register
2117 + * and reading back the result.
2119 + * The following lines are the values that are read during normal
2120 + * PCI config access cycles, i.e. not after just having written
2121 + * ~0 to a base address register.
2124 +static const u32 lxnb_hdr[] = { /* dev 1 function 0 - devfn = 8 */
2125 + 0x0 , 0x0 , 0x0 , 0x0 ,
2126 + 0x0 , 0x0 , 0x0 , 0x0 ,
2128 + 0x281022 , 0x2200005 , 0x6000021 , 0x80f808 , /* AMD Vendor ID */
2129 + 0x0 , 0x0 , 0x0 , 0x0 , /* No virtual registers, hence no BAR for them */
2130 + 0x0 , 0x0 , 0x0 , 0x28100b ,
2131 + 0x0 , 0x0 , 0x0 , 0x0 ,
2132 + 0x0 , 0x0 , 0x0 , 0x0 ,
2133 + 0x0 , 0x0 , 0x0 , 0x0 ,
2134 + 0x0 , 0x0 , 0x0 , 0x0 ,
2137 +static const u32 gxnb_hdr[] = { /* dev 1 function 0 - devfn = 8 */
2138 + 0xfffffffd , 0x0 , 0x0 , 0x0 ,
2139 + 0x0 , 0x0 , 0x0 , 0x0 ,
2141 + 0x28100b , 0x2200005 , 0x6000021 , 0x80f808 , /* NSC Vendor ID */
2142 + 0xac1d , 0x0 , 0x0 , 0x0 , /* I/O BAR - base of virtual registers */
2143 + 0x0 , 0x0 , 0x0 , 0x28100b ,
2144 + 0x0 , 0x0 , 0x0 , 0x0 ,
2145 + 0x0 , 0x0 , 0x0 , 0x0 ,
2146 + 0x0 , 0x0 , 0x0 , 0x0 ,
2147 + 0x0 , 0x0 , 0x0 , 0x0 ,
2150 +static const u32 lxfb_hdr[] = { /* dev 1 function 1 - devfn = 9 */
2151 + 0xff800008 , 0xffffc000 , 0xffffc000 , 0xffffc000 ,
2152 + 0x0 , 0x0 , 0x0 , 0x0 ,
2154 + 0x20811022 , 0x2200003 , 0x3000000 , 0x0 , /* AMD Vendor ID */
2155 + 0xfd000000 , 0xfe000000 , 0xfe004000 , 0xfe008000 , /* FB, GP, VG, DF */
2156 + 0xfe00c000 , 0x0 , 0x0 , 0x30100b , /* VIP */
2157 + 0x0 , 0x0 , 0x0 , 0x10e , /* INTA, IRQ14 for graphics accel */
2158 + 0x0 , 0x0 , 0x0 , 0x0 ,
2159 + 0x3d0 , 0x3c0 , 0xa0000 , 0x0 , /* VG IO, VG IO, EGA FB, MONO FB */
2160 + 0x0 , 0x0 , 0x0 , 0x0 ,
2163 +static const u32 gxfb_hdr[] = { /* dev 1 function 1 - devfn = 9 */
2164 + 0xff800008 , 0xffffc000 , 0xffffc000 , 0xffffc000 ,
2165 + 0x0 , 0x0 , 0x0 , 0x0 ,
2167 + 0x30100b , 0x2200003 , 0x3000000 , 0x0 , /* NSC Vendor ID */
2168 + 0xfd000000 , 0xfe000000 , 0xfe004000 , 0xfe008000 , /* FB, GP, VG, DF */
2169 + 0x0 , 0x0 , 0x0 , 0x30100b ,
2170 + 0x0 , 0x0 , 0x0 , 0x0 ,
2171 + 0x0 , 0x0 , 0x0 , 0x0 ,
2172 + 0x3d0 , 0x3c0 , 0xa0000 , 0x0 , /* VG IO, VG IO, EGA FB, MONO FB */
2173 + 0x0 , 0x0 , 0x0 , 0x0 ,
2176 +static const u32 aes_hdr[] = { /* dev 1 function 2 - devfn = 0xa */
2177 + 0xffffc000 , 0x0 , 0x0 , 0x0 ,
2178 + 0x0 , 0x0 , 0x0 , 0x0 ,
2180 + 0x20821022 , 0x2a00006 , 0x10100000 , 0x8 , /* NSC Vendor ID */
2181 + 0xfe010000 , 0x0 , 0x0 , 0x0 , /* AES registers */
2182 + 0x0 , 0x0 , 0x0 , 0x20821022 ,
2183 + 0x0 , 0x0 , 0x0 , 0x0 ,
2184 + 0x0 , 0x0 , 0x0 , 0x0 ,
2185 + 0x0 , 0x0 , 0x0 , 0x0 ,
2186 + 0x0 , 0x0 , 0x0 , 0x0 ,
2190 +static const u32 isa_hdr[] = { /* dev f function 0 - devfn = 78 */
2191 + 0xfffffff9 , 0xffffff01 , 0xffffffc1 , 0xffffffe1 ,
2192 + 0xffffff81 , 0xffffffc1 , 0x0 , 0x0 ,
2194 + 0x20901022 , 0x2a00049 , 0x6010003 , 0x802000 ,
2195 + 0x18b1 , 0x1001 , 0x1801 , 0x1881 , /* SMB-8 GPIO-256 MFGPT-64 IRQ-32 */
2196 + 0x1401 , 0x1841 , 0x0 , 0x20901022 , /* PMS-128 ACPI-64 */
2197 + 0x0 , 0x0 , 0x0 , 0x0 ,
2198 + 0x0 , 0x0 , 0x0 , 0x0 ,
2199 + 0x0 , 0x0 , 0x0 , 0xaa5b , /* interrupt steering */
2200 + 0x0 , 0x0 , 0x0 , 0x0 ,
2203 +static const u32 ac97_hdr[] = { /* dev f function 3 - devfn = 7b */
2204 + 0xffffff81 , 0x0 , 0x0 , 0x0 ,
2205 + 0x0 , 0x0 , 0x0 , 0x0 ,
2207 + 0x20931022 , 0x2a00041 , 0x4010001 , 0x0 ,
2208 + 0x1481 , 0x0 , 0x0 , 0x0 , /* I/O BAR-128 */
2209 + 0x0 , 0x0 , 0x0 , 0x20931022 ,
2210 + 0x0 , 0x0 , 0x0 , 0x205 , /* IntB , IRQ5 */
2211 + 0x0 , 0x0 , 0x0 , 0x0 ,
2212 + 0x0 , 0x0 , 0x0 , 0x0 ,
2213 + 0x0 , 0x0 , 0x0 , 0x0 ,
2216 +static const u32 ohci_hdr[] = { /* dev f function 4 - devfn = 7c */
2217 + 0xfffff000 , 0x0 , 0x0 , 0x0 ,
2218 + 0x0 , 0x0 , 0x0 , 0x0 ,
2220 + 0x20941022 , 0x2300006 , 0xc031002 , 0x0 ,
2221 + 0xfe01a000 , 0x0 , 0x0 , 0x0 , /* MEMBAR-1000 */
2222 + 0x0 , 0x0 , 0x0 , 0x20941022 ,
2223 + 0x0 , 0x40 , 0x0 , 0x40a , /* CapPtr INT-D, IRQ A */
2224 + 0xc8020001 , 0x0 , 0x0 , 0x0 , /* Capabilities - 40 is R/O, 44 is mask 8103 (power control) */
2225 + 0x0 , 0x0 , 0x0 , 0x0 ,
2226 + 0x0 , 0x0 , 0x0 , 0x0 ,
2229 +static const u32 ehci_hdr[] = { /* dev f function 4 - devfn = 7d */
2230 + 0xfffff000 , 0x0 , 0x0 , 0x0 ,
2231 + 0x0 , 0x0 , 0x0 , 0x0 ,
2233 + 0x20951022 , 0x2300006 , 0xc032002 , 0x0 ,
2234 + 0xfe01b000 , 0x0 , 0x0 , 0x0 , /* MEMBAR-1000 */
2235 + 0x0 , 0x0 , 0x0 , 0x20951022 ,
2236 + 0x0 , 0x40 , 0x0 , 0x40a , /* CapPtr INT-D, IRQ A */
2237 + 0xc8020001 , 0x0 , 0x0 , 0x0 , /* Capabilities - 40 is R/O, 44 is mask 8103 (power control) */
2239 + 0x1 , 0x40080000 , 0x0 , 0x0 , /* EECP - see section 2.1.7 of EHCI spec */
2241 + 0x01000001 , 0x00000000 , 0x0 , 0x0 , /* EECP - see section 2.1.7 of EHCI spec */
2242 + 0x2020 , 0x0 , 0x0 , 0x0 , /* (EHCI page 8) 60 SBRN (R/O), 61 FLADJ (R/W), PORTWAKECAP */
2245 +static u32 ff_loc = ~0;
2246 +static u32 zero_loc = 0;
2248 +static int bar_probing = 0; /* Set after a write of ~0 to a BAR */
2250 +#define NB_SLOT 0x1 /* Northbridge - GX chip - Device 1 */
2251 +#define SB_SLOT 0xf /* Southbridge - CS5536 chip - Device F */
2252 +#define SIMULATED(bus, devfn) (((bus) == 0) && ((PCI_SLOT(devfn) == NB_SLOT) || (PCI_SLOT(devfn) == SB_SLOT)))
2254 +static u32 *hdr_addr(const u32 *hdr, int reg)
2259 + * This is a little bit tricky. The header maps consist of
2260 + * 0x20 bytes of size masks, followed by 0x70 bytes of header data.
2261 + * In the normal case, when not probing a BAR's size, we want
2262 + * to access the header data, so we add 0x20 to the reg offset,
2263 + * thus skipping the size mask area.
2264 + * In the BAR probing case, we want to access the size mask for
2265 + * the BAR, so we subtract 0x10 (the config header offset for
2266 + * BAR0), and don't skip the size mask area.
2269 + addr = (u32)hdr + reg + (bar_probing ? -0x10 : 0x20);
2272 + return (u32 *)addr;
2275 +static int pci_olpc_read(unsigned int seg, unsigned int bus,
2276 + unsigned int devfn, int reg, int len, u32 *value)
2280 + /* Use the hardware mechanism for non-simulated devices */
2281 + if (!SIMULATED(bus, devfn))
2282 + return pci_conf1_read(seg, bus, devfn, reg, len, value);
2285 + * No device has config registers past 0x70, so we save table space
2286 + * by not storing entries for the nonexistent registers
2293 + addr = hdr_addr(is_lx ? lxnb_hdr : gxnb_hdr, reg);
2296 + addr = hdr_addr(is_lx ? lxfb_hdr : gxfb_hdr, reg);
2299 + addr = is_lx ? hdr_addr(aes_hdr, reg) : &ff_loc;
2302 + addr = hdr_addr(isa_hdr, reg);
2305 + addr = hdr_addr(ac97_hdr, reg);
2308 + addr = hdr_addr(ohci_hdr, reg);
2311 + addr = hdr_addr(ehci_hdr, reg);
2320 + *value = *(u8 *) addr;
2323 + *value = *(u16 *) addr;
2335 +static int pci_olpc_write(unsigned int seg, unsigned int bus,
2336 + unsigned int devfn, int reg, int len, u32 value)
2338 + /* Use the hardware mechanism for non-simulated devices */
2339 + if (!SIMULATED(bus, devfn))
2340 + return pci_conf1_write(seg, bus, devfn, reg, len, value);
2342 + /* XXX we may want to extend this to simulate EHCI power management */
2345 + * Mostly we just discard writes, but if the write is a size probe
2346 + * (i.e. writing ~0 to a BAR), we remember it and arrange to return
2347 + * the appropriate size mask on the next read. This is cheating
2348 + * to some extent, because it depends on the fact that the next
2349 + * access after such a write will always be a read to the same BAR.
2352 + if ((reg >= 0x10) && (reg < 0x2c)) {
2353 + /* Write is to a BAR */
2358 + * No warning on writes to ROM BAR, CMD, LATENCY_TIMER,
2359 + * CACHE_LINE_SIZE, or PM registers.
2361 + if ((reg != 0x30) && (reg != 0x04) && (reg != 0x0d) &&
2362 + (reg != 0x0c) && (reg != 0x44))
2363 + printk(KERN_WARNING "OLPC PCI: Config write to devfn %x reg %x value %x\n", devfn, reg, value);
2369 +static struct pci_raw_ops pci_olpc_conf = {
2370 + .read = pci_olpc_read,
2371 + .write = pci_olpc_write,
2374 +void __init pci_olpc_init(void)
2376 + if (!machine_is_olpc() || olpc_has_vsa())
2379 + printk(KERN_INFO "PCI: Using configuration type OLPC\n");
2380 + raw_pci_ops = &pci_olpc_conf;
2381 + is_lx = is_geode_lx();
2383 diff -purN linux_2.6.24_org/Documentation/kernel-parameters.txt linux_2.6.24_olpc/Documentation/kernel-parameters.txt
2384 --- linux_2.6.24_org/Documentation/kernel-parameters.txt 2008-02-15 20:12:29.000000000 +0000
2385 +++ linux_2.6.24_olpc/Documentation/kernel-parameters.txt 2008-02-15 18:59:54.000000000 +0000
2386 @@ -1244,6 +1244,13 @@ and is between 256 and 4096 characters.
2388 nr_uarts= [SERIAL] maximum number of UARTs to be registered.
2390 + olpc_ec_timeout= [OLPC] ms delay when issuing EC commands
2391 + Rather than timing out after 20 ms if an EC
2392 + command is not properly ACKed, override the length
2393 + of the timeout. We have interrupts disabled while
2394 + waiting for the ACK, so if this is set too high
2395 + interrupts *may* be lost!
2400 diff -purN linux_2.6.24_org/drivers/base/dd.c linux_2.6.24_olpc/drivers/base/dd.c
2401 --- linux_2.6.24_org/drivers/base/dd.c 2008-02-15 20:11:29.000000000 +0000
2402 +++ linux_2.6.24_olpc/drivers/base/dd.c 2008-02-15 18:58:46.000000000 +0000
2403 @@ -293,7 +293,6 @@ static void __device_release_driver(stru
2405 driver_sysfs_remove(dev);
2406 sysfs_remove_link(&dev->kobj, "driver");
2407 - klist_remove(&dev->knode_driver);
2410 blocking_notifier_call_chain(&dev->bus->bus_notifier,
2411 @@ -306,6 +305,7 @@ static void __device_release_driver(stru
2413 devres_release_all(dev);
2415 + klist_remove(&dev->knode_driver);
2419 diff -purN linux_2.6.24_org/drivers/char/vt_ioctl.c linux_2.6.24_olpc/drivers/char/vt_ioctl.c
2420 --- linux_2.6.24_org/drivers/char/vt_ioctl.c 2008-02-15 20:11:48.000000000 +0000
2421 +++ linux_2.6.24_olpc/drivers/char/vt_ioctl.c 2008-02-15 18:59:11.000000000 +0000
2423 char vt_dont_switch;
2424 extern struct tty_driver *console_driver;
2426 +/* Add a notifier chain to inform drivers of a VT_TEXT/VT_GRAPHICS switch */
2427 +RAW_NOTIFIER_HEAD(console_notifier_list);
2429 #define VT_IS_IN_USE(i) (console_driver->ttys[i] && console_driver->ttys[i]->count)
2430 #define VT_BUSY(i) (VT_IS_IN_USE(i) || i == fg_console || vc_cons[i].d == sel_cons)
2432 @@ -492,6 +495,14 @@ int vt_ioctl(struct tty_struct *tty, str
2433 vc->vc_mode = (unsigned char) arg;
2434 if (console != fg_console)
2437 + /* Notify listeners if the current fg_console has switched */
2439 + raw_notifier_call_chain(&console_notifier_list,
2440 + (arg == KD_TEXT) ?
2441 + CONSOLE_EVENT_SWITCH_TEXT :
2442 + CONSOLE_EVENT_SWITCH_GRAPHICS, 0);
2445 * explicitly blank/unblank the screen if switching modes
2447 diff -purN linux_2.6.24_org/drivers/i2c/busses/scx200_acb.c linux_2.6.24_olpc/drivers/i2c/busses/scx200_acb.c
2448 --- linux_2.6.24_org/drivers/i2c/busses/scx200_acb.c 2008-02-15 20:11:33.000000000 +0000
2449 +++ linux_2.6.24_olpc/drivers/i2c/busses/scx200_acb.c 2008-02-15 18:58:49.000000000 +0000
2450 @@ -46,6 +46,10 @@ static int base[MAX_DEVICES] = { 0x820,
2451 module_param_array(base, int, NULL, 0);
2452 MODULE_PARM_DESC(base, "Base addresses for the ACCESS.bus controllers");
2454 +static unsigned int smbclk = 0x70;
2455 +module_param(smbclk, uint, 0);
2456 +MODULE_PARM_DESC(smbclk, "Specify the SMB_CLK value");
2458 #define POLL_TIMEOUT (HZ/5)
2460 enum scx200_acb_state {
2461 @@ -108,6 +112,7 @@ struct scx200_acb_iface {
2462 #define ACBADDR (iface->base + 4)
2463 #define ACBCTL2 (iface->base + 5)
2464 #define ACBCTL2_ENABLE 0x01
2465 +#define ACBCTL3 (iface->base + 6)
2467 /************************************************************************/
2469 @@ -392,11 +397,13 @@ static __init int scx200_acb_probe(struc
2473 - /* Disable the ACCESS.bus device and Configure the SCL
2474 - frequency: 16 clock cycles */
2475 - outb(0x70, ACBCTL2);
2476 + /* Disable the ACCESS.bus device and Configure the SCL */
2478 + outb((smbclk & 0x7F) << 1, ACBCTL2);
2480 + outb((smbclk >> 7) & 0xFF, ACBCTL3);
2482 - if (inb(ACBCTL2) != 0x70) {
2483 + if (inb(ACBCTL2) != ((smbclk & 0x7F) << 1)) {
2484 pr_debug(NAME ": ACBCTL2 readback failed\n");
2487 diff -purN linux_2.6.24_org/drivers/input/keyboard/atkbd.c linux_2.6.24_olpc/drivers/input/keyboard/atkbd.c
2488 --- linux_2.6.24_org/drivers/input/keyboard/atkbd.c 2008-02-15 20:11:51.000000000 +0000
2489 +++ linux_2.6.24_olpc/drivers/input/keyboard/atkbd.c 2008-02-15 18:59:14.000000000 +0000
2490 @@ -63,12 +63,25 @@ static int atkbd_extra;
2491 module_param_named(extra, atkbd_extra, bool, 0);
2492 MODULE_PARM_DESC(extra, "Enable extra LEDs and keys on IBM RapidAcces, EzKey and similar keyboards");
2494 +#define ATKBD_KEY_UNKNOWN 0
2495 +#define ATKBD_KEY_NULL 0xFF0000FF
2497 +#define ATKBD_SCR_1 0xFF0000FE
2498 +#define ATKBD_SCR_2 0xFF0000FD
2499 +#define ATKBD_SCR_4 0xFF0000FC
2500 +#define ATKBD_SCR_8 0xFF0000FB
2501 +#define ATKBD_SCR_CLICK 0xFF0000FA
2502 +#define ATKBD_SCR_LEFT 0xFF0000F9
2503 +#define ATKBD_SCR_RIGHT 0xFF0000F8
2505 +#define ATKBD_SPECIAL 0xFF0000F8
2508 * Scancode to keycode tables. These are just the default setting, and
2509 * are loadable via an userland utility.
2512 -static unsigned char atkbd_set2_keycode[512] = {
2513 +static unsigned int atkbd_set2_keycode[512] = {
2515 #ifdef CONFIG_KEYBOARD_ATKBD_HP_KEYCODES
2517 @@ -87,11 +100,17 @@ static unsigned char atkbd_set2_keycode[
2518 82, 83, 80, 76, 77, 72, 1, 69, 87, 78, 81, 74, 55, 73, 70, 99,
2520 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2521 - 217,100,255, 0, 97,165, 0, 0,156, 0, 0, 0, 0, 0, 0,125,
2523 + 217,100,ATKBD_KEY_NULL, 0, 97,165, 0, 0,
2524 + 156, 0, 0, 0, 0, 0, 0,125,
2526 173,114, 0,113, 0, 0, 0,126,128, 0, 0,140, 0, 0, 0,127,
2527 159, 0,115, 0,164, 0, 0,116,158, 0,172,166, 0, 0, 0,142,
2528 157, 0, 0, 0, 0, 0, 0, 0,155, 0, 98, 0, 0,163, 0, 0,
2529 - 226, 0, 0, 0, 0, 0, 0, 0, 0,255, 96, 0, 0, 0,143, 0,
2531 + 226, 0, 0, 0, 0, 0, 0, 0,
2532 + 0,ATKBD_KEY_NULL, 96, 0, 0, 0,143, 0,
2534 0, 0, 0, 0, 0, 0, 0, 0, 0,107, 0,105,102, 0, 0,112,
2535 110,111,108,112,106,103, 0,119, 0,118,109, 0, 99,104,119, 0,
2537 @@ -150,19 +169,6 @@ static unsigned char atkbd_unxlate_table
2538 #define ATKBD_RET_HANGEUL 0xf2
2539 #define ATKBD_RET_ERR 0xff
2541 -#define ATKBD_KEY_UNKNOWN 0
2542 -#define ATKBD_KEY_NULL 255
2544 -#define ATKBD_SCR_1 254
2545 -#define ATKBD_SCR_2 253
2546 -#define ATKBD_SCR_4 252
2547 -#define ATKBD_SCR_8 251
2548 -#define ATKBD_SCR_CLICK 250
2549 -#define ATKBD_SCR_LEFT 249
2550 -#define ATKBD_SCR_RIGHT 248
2552 -#define ATKBD_SPECIAL 248
2554 #define ATKBD_LED_EVENT_BIT 0
2555 #define ATKBD_REP_EVENT_BIT 1
2557 @@ -174,7 +180,7 @@ static unsigned char atkbd_unxlate_table
2558 #define ATKBD_XL_HANJA 0x20
2561 - unsigned char keycode;
2562 + unsigned int keycode;
2564 } atkbd_scroll_keys[] = {
2565 { ATKBD_SCR_1, 0xc5 },
2566 @@ -200,7 +206,7 @@ struct atkbd {
2570 - unsigned char keycode[512];
2571 + unsigned int keycode[512];
2573 unsigned char translated;
2574 unsigned char extra;
2575 @@ -351,7 +357,7 @@ static irqreturn_t atkbd_interrupt(struc
2576 unsigned int code = data;
2577 int scroll = 0, hscroll = 0, click = -1, add_release_event = 0;
2579 - unsigned char keycode;
2580 + unsigned int keycode;
2583 printk(KERN_DEBUG "atkbd.c: Received %02x flags %02x\n", data, flags);
2584 @@ -856,9 +862,11 @@ static void atkbd_set_keycode_table(stru
2585 atkbd->keycode[i | 0x80] = atkbd_scroll_keys[j].keycode;
2587 } else if (atkbd->set == 3) {
2588 - memcpy(atkbd->keycode, atkbd_set3_keycode, sizeof(atkbd->keycode));
2589 + for (i = 0; i < ARRAY_SIZE(atkbd_set3_keycode); i++)
2590 + atkbd->keycode[i] = atkbd_set3_keycode[i];
2592 - memcpy(atkbd->keycode, atkbd_set2_keycode, sizeof(atkbd->keycode));
2593 + for (i = 0; i < ARRAY_SIZE(atkbd_set2_keycode); i++)
2594 + atkbd->keycode[i] = atkbd_set2_keycode[i];
2597 for (i = 0; i < ARRAY_SIZE(atkbd_scroll_keys); i++)
2598 @@ -930,8 +938,8 @@ static void atkbd_set_device_attrs(struc
2601 input_dev->keycode = atkbd->keycode;
2602 - input_dev->keycodesize = sizeof(unsigned char);
2603 - input_dev->keycodemax = ARRAY_SIZE(atkbd_set2_keycode);
2604 + input_dev->keycodesize = sizeof(unsigned int);
2605 + input_dev->keycodemax = ARRAY_SIZE(atkbd->keycode);
2607 for (i = 0; i < 512; i++)
2608 if (atkbd->keycode[i] && atkbd->keycode[i] < ATKBD_SPECIAL)
2609 @@ -1022,6 +1030,10 @@ static int atkbd_connect(struct serio *s
2614 +#include <asm/olpc.h>
2618 * atkbd_reconnect() tries to restore keyboard into a sane state and is
2619 * most likely called on resume.
2620 @@ -1032,6 +1044,12 @@ static int atkbd_reconnect(struct serio
2621 struct atkbd *atkbd = serio_get_drvdata(serio);
2622 struct serio_driver *drv = serio->drv;
2625 + if (olpc_board_at_least(olpc_board_pre(0xb3)))
2626 + if (serio->dev.power.power_state.event != PM_EVENT_ON)
2630 if (!atkbd || !drv) {
2631 printk(KERN_DEBUG "atkbd: reconnect request, but serio is disconnected, ignoring...\n");
2633 diff -purN linux_2.6.24_org/drivers/input/mouse/Kconfig linux_2.6.24_olpc/drivers/input/mouse/Kconfig
2634 --- linux_2.6.24_org/drivers/input/mouse/Kconfig 2008-02-15 20:11:51.000000000 +0000
2635 +++ linux_2.6.24_olpc/drivers/input/mouse/Kconfig 2008-02-15 18:59:14.000000000 +0000
2636 @@ -96,6 +96,16 @@ config MOUSE_PS2_TOUCHKIT
2640 +config MOUSE_PS2_OLPC
2641 + bool "OLPC PS/2 mouse protocol extension" if EMBEDDED
2643 + depends on MOUSE_PS2 && OLPC
2645 + Say Y here if you have an OLPC PS/2 touchpad connected to
2651 tristate "Serial mouse"
2653 diff -purN linux_2.6.24_org/drivers/input/mouse/Makefile linux_2.6.24_olpc/drivers/input/mouse/Makefile
2654 --- linux_2.6.24_org/drivers/input/mouse/Makefile 2008-02-15 20:11:51.000000000 +0000
2655 +++ linux_2.6.24_olpc/drivers/input/mouse/Makefile 2008-02-15 18:59:14.000000000 +0000
2656 @@ -24,3 +24,4 @@ psmouse-$(CONFIG_MOUSE_PS2_LOGIPS2PP) +=
2657 psmouse-$(CONFIG_MOUSE_PS2_LIFEBOOK) += lifebook.o
2658 psmouse-$(CONFIG_MOUSE_PS2_TRACKPOINT) += trackpoint.o
2659 psmouse-$(CONFIG_MOUSE_PS2_TOUCHKIT) += touchkit_ps2.o
2660 +psmouse-$(CONFIG_MOUSE_PS2_OLPC) += olpc.o
2661 diff -purN linux_2.6.24_org/drivers/input/mouse/olpc.c linux_2.6.24_olpc/drivers/input/mouse/olpc.c
2662 --- linux_2.6.24_org/drivers/input/mouse/olpc.c 1970-01-01 01:00:00.000000000 +0100
2663 +++ linux_2.6.24_olpc/drivers/input/mouse/olpc.c 2008-02-15 18:59:14.000000000 +0000
2666 + * OLPC touchpad PS/2 mouse driver
2668 + * Copyright (c) 2006-2008 One Laptop Per Child
2670 + * Zephaniah E. Hull
2671 + * Andres Salomon <dilinger@laptop.org>
2673 + * This driver is partly based on the ALPS driver, which is:
2675 + * Copyright (c) 2003 Neil Brown <neilb@cse.unsw.edu.au>
2676 + * Copyright (c) 2003-2005 Peter Osterlund <petero2@telia.com>
2677 + * Copyright (c) 2004 Dmitry Torokhov <dtor@mail.ru>
2678 + * Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz>
2680 + * This program is free software; you can redistribute it and/or modify
2681 + * it under the terms of the GNU General Public License version 2 as
2682 + * published by the Free Software Foundation.
2686 + * The touchpad on the OLPC is fairly wide, with the entire area usable
2687 + * as a tablet (Pen Tablet/PT), and the center 1/3rd also usable as a
2688 + * touchpad (Glide Sensor/GS). The spec from ALPS is available from
2689 + * <http://wiki.laptop.org/go/Touch_Pad/Tablet>. It refers to this
2690 + * device as HGPK (Hybrid GS, PT, and Keymatrix).
2692 + * Earlier version of the device had simultaneous reporting; however, that
2693 + * was removed. Instead, the device now reports packets in one mode, and
2694 + * tells the driver when a mode switch needs to happen.
2698 +#include <linux/input.h>
2699 +#include <linux/serio.h>
2700 +#include <linux/libps2.h>
2701 +#include <linux/delay.h>
2702 +#include <asm/olpc.h>
2704 +#include "psmouse.h"
2707 +static int tpdebug;
2708 +module_param(tpdebug, int, 0644);
2710 +static int ignore_delta = 60;
2711 +module_param(ignore_delta, int, 0644);
2712 +MODULE_PARM_DESC(ignore_delta, "ignore packets that cause an X or Y delta larger than this value.");
2715 + * With older hardware, a finger-up event is sometimes not sent. If it's been
2716 + * more than 50mS since the last packet, we can safely assume that there was
2717 + * a finger-up event that we never received.
2719 +static void hgpk_fingerup_hack(struct psmouse *psmouse, struct hgpk_packet *p)
2721 + struct hgpk_data *priv = psmouse->private;
2722 + struct timeval now_tv;
2725 + if (psmouse->model >= HGPK_MODEL_C)
2728 + if (p->gs_down || p->pt_down) {
2729 + do_gettimeofday(&now_tv);
2730 + now_ns = timeval_to_ns(&now_tv);
2732 + if (priv->late && now_ns >= priv->late) {
2733 + struct input_dev *pt = psmouse->dev;
2734 + struct input_dev *gs = priv->gs;
2736 + input_report_key(pt, BTN_TOUCH, 0);
2737 + input_report_key(gs, BTN_TOUCH, 0);
2740 + hgpk_dbg(psmouse, "Missing finger-up packet detected, "
2741 + "working around buggy hardware.\n");
2743 + priv->late = now_ns + (50 * NSEC_PER_MSEC);
2749 + * C and D series touchpads send an extra finger-up packet to ensure we've
2750 + * seen it. That's all well and good, but for some uncomprehensible reason
2751 + * they sometimes also get stuck in a state where they also send an
2752 + * extra finger-down packet with coordinates of x=0, y=0. This royally
2753 + * screws relative positioning; end users see it as the touchpad jumping
2754 + * around when they first put their finger down. This works around that.
2758 +static void hgpk_fingerdown_hack(struct psmouse *psmouse, struct hgpk_packet *p)
2760 + if (psmouse->model < HGPK_MODEL_C)
2763 + /* we only care about x=0, y=0 packets */
2764 + if (p->x != 0 || p->y != 0)
2768 + * if we're a gs_down packet but we were not previously down,
2769 + * we're going to assume that this is one of those spurious packets
2770 + * that needs to be worked around.
2772 + if (p->gs_down && !test_bit(BTN_TOUCH, p->dev->key)) {
2773 + hgpk_dbg(psmouse, "spurious GS finger-down packet\n");
2775 + } else if (p->pt_down && !test_bit(BTN_TOUCH, p->dev->key)) {
2776 + hgpk_dbg(psmouse, "spurious PT finger-down packet\n");
2782 + * In general, we have lots of calibration problems that manifest
2783 + * themselves as jumpy mouse pointers. Miscalibration, capacitance issues
2784 + * with the hardware, etc; these make the touchpad detect errant packets
2785 + * at random places all over the place. Since we don't expect large deltas
2786 + * to ever actually be useful, we'll large axis changes that go over our
2789 +static void hgpk_big_delta_hack(struct psmouse *psmouse, struct hgpk_packet *p)
2791 + struct hgpk_data *priv = psmouse->private;
2792 + struct input_dev *dev = p->dev;
2794 + /* afaik, this happens on all hardware */
2796 + /* ignore finger-up packets */
2797 + if (!p->pt_down && !p->gs_down)
2800 + /* ensure that we're not a finger-down packet */
2801 + if ((p->pt_down && !test_bit(BTN_TOUCH, dev->key)) ||
2802 + (p->gs_down && !test_bit(BTN_TOUCH, dev->key)))
2805 + if (abs(dev->abs[ABS_X] - p->x) > ignore_delta ||
2806 + abs(dev->abs[ABS_Y] - p->y) > ignore_delta) {
2807 + hgpk_dbg(psmouse, "axis change (%d,%d) => (%d,%d) is over "
2808 + "delta threshold\n", dev->abs[ABS_X],
2809 + dev->abs[ABS_Y], p->x, p->y);
2810 + input_report_key(dev, BTN_TOUCH, 0);
2814 + /* two in a row is a pretty good indicator of miscalibration */
2815 + if (priv->axis_errors++) {
2816 + /* wait 2s for finger removal, and then recalibrate */
2817 + queue_delayed_work(kpsmoused_wq, &priv->recalib_wq,
2818 + msecs_to_jiffies(2000));
2819 + priv->axis_errors = 0;
2824 + priv->axis_errors = 0;
2828 + * This is my favorite touchpad hardware bug. I'm entirely not sure what
2829 + * triggers it (I've seen it triggered while the laptop was left on overnight,
2830 + * but my cat could have very well been using it/sleeping on it). However,
2831 + * the touchpad will randomly get stuck in a state where it constantly spews
2832 + * packets without a finger being on it. A recalibration will fix it, but
2833 + * without that it will go on for days (auto-recalibration doesn't catch it,
2834 + * either). The packets tend to either have the same coordinates, or be
2835 + * 1px away from each other; ie, (283,139,6) -> (284,139,5) -> (285,139,5) ->
2836 + * (286,139,6) -> (286,139,6) -> etc. We have a number of workarounds here..
2838 +static void hgpk_spewing_hack(struct psmouse *psmouse, struct hgpk_packet *p)
2840 + struct hgpk_data *priv = psmouse->private;
2841 + struct input_dev *dev = p->dev;
2844 + if (psmouse->model < HGPK_MODEL_C)
2847 + /* ignore 0, 0 packets */
2848 + if (p->x == 0 && p->y == 0)
2851 + /* PT packets don't count */
2853 + priv->repeat_pkts = 0;
2858 + * If we see 2s+ worth of packets that have at least 2 axis deltas of
2859 + * only 1px, that's a good indication that we're spewing packets.
2860 + * We're going to ignore z=15, though; that's pretty indicative of
2861 + * an actual finger on the touchpad just staying still.
2863 + if (p->z == 0 || p->z == 15)
2865 + repeat_axes = abs(p->x - dev->abs[ABS_X]) < 2 ? 1 : 0;
2866 + repeat_axes += abs(p->y - dev->abs[ABS_Y]) < 2 ? 1 : 0;
2867 + repeat_axes += abs(p->z - dev->abs[ABS_PRESSURE]) < 2 ? 1 : 0;
2868 + if (repeat_axes > 1) {
2869 + priv->repeat_pkts++;
2870 + /* we get 1 packet about every 24mS */
2871 + if (priv->repeat_pkts > 83) {
2872 + queue_delayed_work(kpsmoused_wq, &priv->recalib_wq, 0);
2873 + priv->repeat_pkts = 0;
2877 + priv->repeat_pkts = 0;
2882 + * 10s of y and z not changing is another kind of miscalibration.
2884 + repeat_axes = (p->y == dev->abs[ABS_Y]) ? 1 : 0;
2885 + repeat_axes += (p->z == dev->abs[ABS_PRESSURE]) ? 1 : 0;
2886 + if (repeat_axes > 1) {
2887 + priv->repeat_pkts++;
2888 + if (priv->repeat_pkts > 416) {
2889 + queue_delayed_work(kpsmoused_wq, &priv->recalib_wq, 0);
2890 + priv->repeat_pkts = 0;
2894 + priv->repeat_pkts = 0;
2898 + * HGPK Advanced Mode - single-mode format
2900 + * byte 0(PT): 1 1 0 0 1 1 1 1
2901 + * byte 0(GS): 1 1 1 1 1 1 1 1
2902 + * byte 1: 0 x6 x5 x4 x3 x2 x1 x0
2903 + * byte 2(PT): 0 0 x9 x8 x7 ? pt-dsw 0
2904 + * byte 2(GS): 0 x10 x9 x8 x7 ? gs-dsw pt-dsw
2905 + * byte 3: 0 y9 y8 y7 1 0 swr swl
2906 + * byte 4: 0 y6 y5 y4 y3 y2 y1 y0
2907 + * byte 5: 0 z6 z5 z4 z3 z2 z1 z0
2909 + * ?'s are not defined in the protocol spec, may vary between models.
2911 + * swr/swl are the left/right buttons.
2913 + * pt-dsw/gs-dsw indicate that the pt/gs sensor is detecting a
2917 +static int hgpk_validate_byte(unsigned char *packet, int pktcnt)
2919 + BUG_ON(pktcnt < 1);
2921 + if (packet[0] != HGPK_PT && packet[0] != HGPK_GS)
2924 + /* bytes 2 - 6 should have 0 in the highest bit */
2925 + if (pktcnt >= 2 && pktcnt <= 6 && (packet[pktcnt - 1] & 0x80))
2931 +static void hgpk_decode_packet(struct psmouse *psmouse, struct hgpk_packet *p)
2933 + unsigned char *packet = psmouse->packet;
2935 + BUG_ON(psmouse->pktcnt < 6);
2937 + p->left = packet[3] & 1;
2938 + p->right = !!(packet[3] & 2);
2939 + p->x = packet[1] | ((packet[2] & 0x78) << 4);
2940 + p->y = packet[4] | ((packet[3] & 0x70) << 3);
2943 + if (packet[0] == HGPK_GS) {
2944 + p->pt_down = !!(packet[2] & 1);
2945 + p->gs_down = !!(packet[2] & 2);
2946 + p->dev = ((struct hgpk_data *) psmouse->private)->gs;
2948 + /* we miss spurious PT finger-downs if pt_down is set */
2949 + p->mode_switch = HGPK_PT;
2952 + p->mode_switch = 0;
2954 + } else if (packet[0] == HGPK_PT) {
2955 + p->pt_down = !!(packet[2] & 2);
2957 + p->dev = psmouse->dev;
2958 + p->mode_switch = !p->pt_down ? HGPK_GS : 0;
2962 + hgpk_dbg(psmouse, "l=%d r=%d p=%d g=%d x=%d y=%d z=%d m=%x\n",
2963 + p->left, p->right, p->pt_down, p->gs_down,
2964 + p->x, p->y, p->z, p->mode_switch);
2968 +static void hgpk_process_packet_gspt(struct psmouse *psmouse)
2970 + struct hgpk_data *priv = psmouse->private;
2971 + struct input_dev *pt = psmouse->dev;
2972 + struct input_dev *gs = priv->gs;
2973 + struct hgpk_packet pkt;
2975 + hgpk_decode_packet(psmouse, &pkt);
2977 + hgpk_fingerup_hack(psmouse, &pkt);
2978 + hgpk_fingerdown_hack(psmouse, &pkt);
2979 + hgpk_big_delta_hack(psmouse, &pkt);
2980 + hgpk_spewing_hack(psmouse, &pkt);
2982 + input_report_key(pt, BTN_LEFT, pkt.left);
2983 + input_report_key(pt, BTN_RIGHT, pkt.right);
2984 + input_report_key(pt, BTN_TOUCH, pkt.pt_down);
2986 + input_report_key(gs, BTN_LEFT, pkt.left);
2987 + input_report_key(gs, BTN_RIGHT, pkt.right);
2988 + input_report_key(gs, BTN_TOUCH, pkt.gs_down);
2990 + input_report_abs(pkt.dev, ABS_X, pkt.x);
2991 + input_report_abs(pkt.dev, ABS_Y, pkt.y);
2992 + input_report_abs(pkt.dev, ABS_PRESSURE, pkt.z);
2997 + if (priv->recalib_window) {
2998 + if (time_before(jiffies, priv->recalib_window)) {
3000 + * ugh, got a packet inside our recalibration
3001 + * window, schedule another recalibration.
3003 + hgpk_dbg(psmouse, "packet inside calibration window, "
3004 + "queueing another recalibration\n");
3005 + queue_delayed_work(kpsmoused_wq, &priv->recalib_wq,
3006 + msecs_to_jiffies(1000));
3008 + priv->recalib_window = 0;
3011 + if (psmouse->model != HGPK_MODEL_A) {
3012 + if (priv->pending_mode && (!pkt.mode_switch ||
3013 + priv->current_mode == pkt.mode_switch)) {
3014 + priv->pending_mode = 0;
3015 + cancel_delayed_work(&priv->switch_wq);
3017 + else if (priv->pending_mode != pkt.mode_switch) {
3018 + priv->pending_mode = pkt.mode_switch;
3020 + /* allow for spurious mode_switch packets by delaying */
3021 + queue_delayed_work(kpsmoused_wq, &priv->switch_wq,
3022 + msecs_to_jiffies(50));
3027 +static psmouse_ret_t hgpk_process_byte(struct psmouse *psmouse)
3029 + if (hgpk_validate_byte(psmouse->packet, psmouse->pktcnt)) {
3030 + hgpk_dbg(psmouse, "%s: (%d) %02x %02x %02x %02x %02x %02x\n",
3031 + __func__, psmouse->pktcnt, psmouse->packet[0],
3032 + psmouse->packet[1], psmouse->packet[2],
3033 + psmouse->packet[3], psmouse->packet[4],
3034 + psmouse->packet[5]);
3035 + return PSMOUSE_BAD_DATA;
3038 + if (psmouse->pktcnt == 6) {
3039 + hgpk_process_packet_gspt(psmouse);
3040 + return PSMOUSE_FULL_PACKET;
3043 + return PSMOUSE_GOOD_DATA;
3046 +static int hgpk_force_recalibrate(struct psmouse *psmouse)
3048 + struct ps2dev *ps2dev = &psmouse->ps2dev;
3049 + struct hgpk_data *priv = psmouse->private;
3050 + struct input_dev *pt = psmouse->dev;
3051 + struct input_dev *gs = priv->gs;
3053 + /* C-series touchpads added the recalibrate command */
3054 + if (psmouse->model < HGPK_MODEL_C)
3057 + if (ps2_command(ps2dev, NULL, 0xf5) ||
3058 + ps2_command(ps2dev, NULL, 0xf5) ||
3059 + ps2_command(ps2dev, NULL, 0xe6) ||
3060 + ps2_command(ps2dev, NULL, 0xf5))
3063 + /* send a finger-up event so the cursor doesn't jump around */
3064 + input_report_key(pt, BTN_TOUCH, 0);
3065 + input_report_key(gs, BTN_TOUCH, 0);
3069 + /* according to ALPS, 150mS is required for recalibration */
3073 + * XXX: If a finger is down during this delay, recalibration will
3074 + * detect capacitance incorrectly. This is a hardware bug, and
3075 + * we may need to work around that here.
3078 + if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE))
3082 + * After we recalibrate, we shouldn't get any packets for 2s. If
3083 + * we do, it's likely that someone's finger was on the touchpad.
3084 + * If someone's finger *was* on the touchpad, it's probably
3085 + * miscalibrated. So, we should schedule another recalibration
3087 + priv->recalib_window = jiffies + msecs_to_jiffies(2000);
3092 +static enum hgpk_model_t hgpk_get_model(struct psmouse *psmouse)
3094 + struct ps2dev *ps2dev = &psmouse->ps2dev;
3095 + unsigned char param[3];
3097 + /* E7, E7, E7, E9 gets us a 3 byte identifier */
3098 + if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
3099 + ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
3100 + ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
3101 + ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
3104 + hgpk_dbg(psmouse, "ID: %02x %02x %02x", param[0], param[1], param[2]);
3106 + /* HGPK signature: 0x67, 0x00, 0x<model> */
3107 + if (param[0] != 0x67 || param[1] != 0x00)
3110 + hgpk_info(psmouse, "OLPC touchpad revision 0x%x\n", param[2]);
3115 + * Touchpad should be disabled before calling this!
3117 +static int hgpk_new_mode(struct psmouse *psmouse, int mode)
3119 + struct ps2dev *ps2dev = &psmouse->ps2dev;
3120 + struct hgpk_data *priv = psmouse->private;
3123 + * PT mode: F2, F2, F2, E7
3124 + * GS mode: F2, F2, F2, E6
3126 + if (ps2_command(ps2dev, NULL, 0xF2) ||
3127 + ps2_command(ps2dev, NULL, 0xF2) ||
3128 + ps2_command(ps2dev, NULL, 0xF2))
3131 + if (mode == HGPK_GS) {
3132 + if (ps2_command(ps2dev, NULL, 0xE6))
3135 + if (ps2_command(ps2dev, NULL, 0xE7))
3139 + if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE))
3142 + /* tell the irq handler to stop ignoring packets */
3143 + psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
3145 + priv->current_mode = mode;
3146 + priv->pending_mode = 0;
3148 + hgpk_warn(psmouse, "Switched to mode 0x%x successful.\n", mode);
3153 +static int hgpk_advanced_mode(struct psmouse *psmouse)
3155 + struct ps2dev *ps2dev = &psmouse->ps2dev;
3157 + /* Switch to 'Advanced mode.', four disables in a row. */
3158 + if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
3159 + ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
3160 + ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
3161 + ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE))
3164 + return hgpk_new_mode(psmouse, HGPK_GS);
3168 + * This kills power to the touchpad; according to ALPS, current consumption
3169 + * goes down to 50uA after running this. To turn power back on, we drive
3172 +static int hgpk_toggle_power(struct psmouse *psmouse, int enable)
3174 + struct ps2dev *ps2dev = &psmouse->ps2dev;
3177 + /* Added on D-series touchpads */
3178 + if (psmouse->model < HGPK_MODEL_D)
3182 + psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
3185 + * Sending a byte will drive MS-DAT low; this will wake up
3186 + * the controller. Once we get an ACK back from it, it
3187 + * means we can continue with the touchpad re-init. ALPS
3188 + * tells us that 1s should be long enough, so set that as
3189 + * the upper bound.
3191 + for (timeo = 20; timeo > 0; timeo--) {
3192 + if (!ps2_sendbyte(&psmouse->ps2dev,
3193 + PSMOUSE_CMD_DISABLE, 20))
3198 + psmouse_reset(psmouse);
3200 + if (hgpk_advanced_mode(psmouse)) {
3201 + hgpk_err(psmouse, "Failed to reinit touchpad!\n");
3205 + hgpk_dbg(psmouse, "Powering off touchpad.\n");
3206 + psmouse_set_state(psmouse, PSMOUSE_IGNORE);
3208 + if (ps2_command(ps2dev, NULL, 0xec) ||
3209 + ps2_command(ps2dev, NULL, 0xec) ||
3210 + ps2_command(ps2dev, NULL, 0xea))
3212 + /* probably won't see an ACK, the touchpad will be off */
3213 + ps2_sendbyte(&psmouse->ps2dev, 0xec, 20);
3220 + * poll the touchpad for current motion packet.
3222 + * Note: We can't poll, so always return failure.
3224 +static int hgpk_poll(struct psmouse *psmouse)
3229 +static int hgpk_reconnect(struct psmouse *psmouse)
3231 + if (olpc_board_at_least(olpc_board(0xb2)))
3232 + if (psmouse->ps2dev.serio->dev.power.power_state.event != PM_EVENT_ON)
3235 + psmouse_reset(psmouse);
3237 + if (hgpk_advanced_mode(psmouse)) {
3238 + hgpk_err(psmouse, "failed to reenable advanced mode.\n");
3245 +static ssize_t hgpk_show_powered(struct device *dev,
3246 + struct device_attribute *attr, char *buf)
3248 + struct serio *serio = to_serio_port(dev);
3249 + struct psmouse *psmouse;
3250 + struct hgpk_data *priv;
3253 + retval = serio_pin_driver(serio);
3257 + psmouse = serio_get_drvdata(serio);
3258 + priv = psmouse->private;
3260 + retval = sprintf(buf, "%d\n", priv->powered);
3261 + serio_unpin_driver(serio);
3265 +static ssize_t hgpk_set_powered(struct device *dev,
3266 + struct device_attribute *attr, const char *buf, size_t count)
3268 + struct serio *serio = to_serio_port(dev);
3269 + struct psmouse *psmouse;
3270 + struct hgpk_data *priv;
3271 + unsigned long val;
3276 + else if (*buf == '0')
3281 + retval = serio_pin_driver(serio);
3286 + * FUCK IT. I don't fucking care. locking in psmouse is fucking retarded!
3287 + retval = mutex_lock_interruptible(&psmouse_mutex);
3292 + psmouse = serio_get_drvdata(serio);
3293 + priv = psmouse->private;
3295 + if (val == priv->powered)
3298 + retval = hgpk_toggle_power(psmouse, val);
3300 + priv->powered = val;
3303 + serio_unpin_driver(serio);
3304 + return retval ? retval : count;
3307 +static DEVICE_ATTR(powered, S_IWUSR | S_IRUGO, hgpk_show_powered,
3308 + hgpk_set_powered);
3310 +static void hgpk_disconnect(struct psmouse *psmouse)
3312 + struct hgpk_data *priv = psmouse->private;
3314 + device_remove_file(&psmouse->ps2dev.serio->dev, &dev_attr_powered);
3315 + psmouse_reset(psmouse);
3316 + flush_scheduled_work();
3317 + input_unregister_device(priv->gs);
3321 +static void hgpk_mode_switch(struct work_struct *work)
3323 + struct delayed_work *w = container_of(work, struct delayed_work, work);
3324 + struct hgpk_data *priv = container_of(w, struct hgpk_data, switch_wq);
3325 + struct psmouse *psmouse = priv->psmouse;
3326 + struct ps2dev *ps2dev = &psmouse->ps2dev;
3330 + hgpk_dbg(psmouse, "Starting mode switch to 0x%x. [%lu]\n",
3331 + priv->pending_mode, jiffies);
3333 + if (priv->pending_mode == priv->current_mode) {
3334 + priv->pending_mode = 0;
3335 + hgpk_dbg(psmouse, "Already in target mode, no-op.\n");
3339 + /* tell the irq handler to ignore any further packets */
3340 + psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
3343 + if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE))
3347 + * ALPS tells us that it may take up to 20msec for the disable to
3348 + * take effect; however, ps2_command() will wait up to 200msec for
3349 + * the ACK to come back (and I'm assuming that by the time the
3350 + * hardware sends back its ACK, it has stopped sending bytes).
3352 + pending_mode = priv->pending_mode;
3354 + if (hgpk_new_mode(psmouse, priv->pending_mode))
3358 + * Deal with a potential race condition.
3360 + * If there is a brief tap of a stylus or a fingernail that
3361 + * triggers a mode switch to PT mode, and the stylus/fingernail is
3362 + * lifted after the DISABLE above, but before we reenable in the
3363 + * new mode then we can get stuck in PT mode.
3365 + if (pending_mode == HGPK_PT) {
3366 + priv->pending_mode = HGPK_GS;
3367 + queue_delayed_work(kpsmoused_wq, &priv->switch_wq,
3368 + msecs_to_jiffies(50));
3373 + hgpk_warn(psmouse, "Failure to switch modes, resetting device...\n");
3374 + hgpk_reconnect(psmouse);
3377 +static void hgpk_recalib_work(struct work_struct *work)
3379 + struct delayed_work *w = container_of(work, struct delayed_work, work);
3380 + struct hgpk_data *priv = container_of(w, struct hgpk_data, recalib_wq);
3381 + struct psmouse *psmouse = priv->psmouse;
3384 + hgpk_dbg(psmouse, "Recalibrating touchpad..\n");
3386 + if (hgpk_force_recalibrate(psmouse))
3387 + hgpk_err(psmouse, "Recalibration failed!\n");
3390 +int olpc_init(struct psmouse *psmouse)
3392 + struct hgpk_data *priv;
3393 + struct input_dev *pt = psmouse->dev;
3394 + struct input_dev *gs;
3396 + priv = kzalloc(sizeof(struct hgpk_data), GFP_KERNEL);
3397 + gs = input_allocate_device();
3401 + psmouse->private = priv;
3403 + priv->psmouse = psmouse;
3404 + priv->powered = 1;
3406 + psmouse_reset(psmouse);
3408 + if (hgpk_advanced_mode(psmouse)) {
3409 + hgpk_err(psmouse, "failed to enable advanced mode\n");
3413 + /* Unset things that psmouse-base sets that we don't have */
3414 + pt->evbit[0] &= ~BIT(EV_REL);
3415 + pt->keybit[LONG(BTN_MOUSE)] &= ~BIT(BTN_MIDDLE);
3416 + pt->relbit[0] &= ~(BIT(REL_X) | BIT(REL_Y));
3418 + /* Set all the things we *do* have */
3419 + set_bit(EV_KEY, pt->evbit);
3420 + set_bit(EV_ABS, pt->evbit);
3422 + set_bit(BTN_LEFT, pt->keybit);
3423 + set_bit(BTN_RIGHT, pt->keybit);
3424 + set_bit(BTN_TOUCH, pt->keybit);
3426 + input_set_abs_params(pt, ABS_X, 2, 1000, 0, 0);
3427 + input_set_abs_params(pt, ABS_Y, 0, 717, 0, 0);
3428 + input_set_abs_params(pt, ABS_PRESSURE, 0, 127, 0, 0);
3430 + snprintf(priv->phys, sizeof(priv->phys),
3431 + "%s/input1", psmouse->ps2dev.serio->phys);
3432 + gs->phys = priv->phys;
3433 + gs->name = "OLPC ALPS GlideSensor";
3434 + gs->id.bustype = BUS_I8042;
3435 + gs->id.vendor = 0x0002;
3436 + gs->id.product = PSMOUSE_OLPC;
3437 + gs->id.version = psmouse->model;
3439 + set_bit(EV_KEY, gs->evbit);
3440 + set_bit(EV_ABS, gs->evbit);
3442 + set_bit(BTN_LEFT, gs->keybit);
3443 + set_bit(BTN_RIGHT, gs->keybit);
3444 + set_bit(BTN_TOUCH, gs->keybit);
3446 + input_set_abs_params(gs, ABS_X, 350, 512, 0, 0);
3447 + input_set_abs_params(gs, ABS_Y, 70, 325, 0, 0);
3448 + input_set_abs_params(gs, ABS_PRESSURE, 0, 15, 0, 0);
3450 + if (input_register_device(gs)) {
3451 + hgpk_err(psmouse, "Failed to register GlideSensor\n");
3455 + psmouse->protocol_handler = hgpk_process_byte;
3456 + psmouse->poll = hgpk_poll;
3457 + psmouse->disconnect = hgpk_disconnect;
3458 + psmouse->reconnect = hgpk_reconnect;
3459 + psmouse->pktsize = 6;
3461 + /* Disable the idle resync. */
3462 + psmouse->resync_time = 0;
3463 + /* Reset after a lot of bad bytes. */
3464 + psmouse->resetafter = 1024;
3466 + INIT_DELAYED_WORK(&priv->switch_wq, hgpk_mode_switch);
3467 + INIT_DELAYED_WORK(&priv->recalib_wq, hgpk_recalib_work);
3469 + if (device_create_file(&psmouse->ps2dev.serio->dev,
3470 + &dev_attr_powered)) {
3471 + hgpk_err(psmouse, "Failed to create sysfs attribute\n");
3479 + input_unregister_device(gs);
3482 + input_free_device(gs);
3487 +int olpc_detect(struct psmouse *psmouse, int set_properties)
3491 + version = hgpk_get_model(psmouse);
3495 + if (set_properties) {
3496 + psmouse->vendor = "ALPS";
3497 + psmouse->name = "PenTablet";
3498 + psmouse->model = version;
3502 diff -purN linux_2.6.24_org/drivers/input/mouse/olpc.h linux_2.6.24_olpc/drivers/input/mouse/olpc.h
3503 --- linux_2.6.24_org/drivers/input/mouse/olpc.h 1970-01-01 01:00:00.000000000 +0100
3504 +++ linux_2.6.24_olpc/drivers/input/mouse/olpc.h 2008-02-15 18:59:14.000000000 +0000
3507 + * OLPC touchpad PS/2 mouse driver
3509 + * Copyright (c) 2006 One Laptop Per Child, inc.
3511 + * This driver is partly based on the ALPS driver.
3512 + * Copyright (c) 2003 Peter Osterlund <petero2@telia.com>
3513 + * Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz>
3515 + * This program is free software; you can redistribute it and/or modify it
3516 + * under the terms of the GNU General Public License version 2 as published by
3517 + * the Free Software Foundation.
3523 +enum hgpk_model_t {
3524 + HGPK_MODEL_PreA = 0x0a, /* pre-B1s */
3525 + HGPK_MODEL_A = 0x14, /* found on B1s, PT disabled in hardware */
3526 + HGPK_MODEL_B = 0x28, /* B2s, has capacitance issues */
3527 + HGPK_MODEL_C = 0x3c,
3528 + HGPK_MODEL_D = 0x50, /* C1, mass production */
3531 +#define HGPK_GS 0xff /* The GlideSensor */
3532 +#define HGPK_PT 0xcf /* The PenTablet */
3534 +struct hgpk_packet {
3535 + struct input_dev *dev;
3537 + unsigned char mode_switch;
3538 + unsigned int pt_down:1, gs_down:1;
3539 + unsigned int left:1, right:1;
3543 + struct input_dev *gs; /* GlideSensor */
3544 + struct psmouse *psmouse;
3545 + char name[32]; /* Name */
3546 + char phys[32]; /* Phys */
3553 + unsigned long recalib_window;
3554 + struct delayed_work switch_wq;
3555 + struct delayed_work recalib_wq;
3558 +#define hgpk_dbg(psmouse, format, arg...) \
3559 + dev_dbg(&(psmouse)->ps2dev.serio->dev, format, ## arg)
3560 +#define hgpk_err(psmouse, format, arg...) \
3561 + dev_err(&(psmouse)->ps2dev.serio->dev, format, ## arg)
3562 +#define hgpk_info(psmouse, format, arg...) \
3563 + dev_info(&(psmouse)->ps2dev.serio->dev, format, ## arg)
3564 +#define hgpk_warn(psmouse, format, arg...) \
3565 + dev_warn(&(psmouse)->ps2dev.serio->dev, format, ## arg)
3566 +#define hgpk_notice(psmouse, format, arg...) \
3567 + dev_notice(&(psmouse)->ps2dev.serio->dev, format, ## arg)
3569 +#ifdef CONFIG_MOUSE_PS2_OLPC
3570 +int olpc_detect(struct psmouse *psmouse, int set_properties);
3571 +int olpc_init(struct psmouse *psmouse);
3573 +inline int olpc_detect(struct psmouse *psmouse, int set_properties)
3577 +inline int olpc_init(struct psmouse *psmouse)
3584 diff -purN linux_2.6.24_org/drivers/input/mouse/psmouse-base.c linux_2.6.24_olpc/drivers/input/mouse/psmouse-base.c
3585 --- linux_2.6.24_org/drivers/input/mouse/psmouse-base.c 2008-02-15 20:11:51.000000000 +0000
3586 +++ linux_2.6.24_olpc/drivers/input/mouse/psmouse-base.c 2008-02-15 18:59:14.000000000 +0000
3588 #include "synaptics.h"
3589 #include "logips2pp.h"
3592 #include "lifebook.h"
3593 #include "trackpoint.h"
3594 #include "touchkit_ps2.h"
3595 @@ -103,7 +104,7 @@ static struct attribute_group psmouse_at
3597 static DEFINE_MUTEX(psmouse_mutex);
3599 -static struct workqueue_struct *kpsmoused_wq;
3600 +struct workqueue_struct *kpsmoused_wq;
3602 struct psmouse_protocol {
3603 enum psmouse_type type;
3604 @@ -221,7 +222,7 @@ static inline void __psmouse_set_state(s
3608 -static void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state)
3609 +void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state)
3611 serio_pause_rx(psmouse->ps2dev.serio);
3612 __psmouse_set_state(psmouse, new_state);
3613 @@ -320,7 +321,7 @@ static irqreturn_t psmouse_interrupt(str
3617 - if (psmouse->packet[1] == PSMOUSE_RET_ID) {
3618 + if (psmouse->packet[1] == PSMOUSE_RET_ID || psmouse->packet[1] == PSMOUSE_RET_BAT) {
3619 __psmouse_set_state(psmouse, PSMOUSE_IGNORE);
3620 serio_reconnect(serio);
3622 @@ -631,8 +632,21 @@ static int psmouse_extensions(struct psm
3627 + * Try OLPC touchpad.
3629 if (max_proto > PSMOUSE_IMEX) {
3630 + if (olpc_detect(psmouse, set_properties) == 0) {
3631 + if (!set_properties || olpc_init(psmouse) == 0)
3632 + return PSMOUSE_OLPC;
3634 + * Init failed, try basic relative protocols
3636 + max_proto = PSMOUSE_IMEX;
3640 + if (max_proto > PSMOUSE_IMEX) {
3641 if (genius_detect(psmouse, set_properties) == 0)
3642 return PSMOUSE_GENPS;
3644 @@ -763,6 +777,14 @@ static const struct psmouse_protocol psm
3645 .detect = touchkit_ps2_detect,
3648 +#ifdef CONFIG_MOUSE_PS2_OLPC
3650 + .type = PSMOUSE_OLPC,
3653 + .detect = olpc_detect,
3657 .type = PSMOUSE_CORTRON,
3658 .name = "CortronPS/2",
3659 diff -purN linux_2.6.24_org/drivers/input/mouse/psmouse.h linux_2.6.24_olpc/drivers/input/mouse/psmouse.h
3660 --- linux_2.6.24_org/drivers/input/mouse/psmouse.h 2008-02-15 20:11:51.000000000 +0000
3661 +++ linux_2.6.24_olpc/drivers/input/mouse/psmouse.h 2008-02-15 18:59:14.000000000 +0000
3662 @@ -88,6 +88,7 @@ enum psmouse_type {
3665 PSMOUSE_TOUCHKIT_PS2,
3668 PSMOUSE_AUTO /* This one should always be last */
3670 @@ -95,7 +96,9 @@ enum psmouse_type {
3671 int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command);
3672 int psmouse_reset(struct psmouse *psmouse);
3673 void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution);
3674 +void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state);
3676 +extern struct workqueue_struct *kpsmoused_wq;
3678 struct psmouse_attribute {
3679 struct device_attribute dattr;
3680 diff -purN linux_2.6.24_org/drivers/input/serio/i8042.c linux_2.6.24_olpc/drivers/input/serio/i8042.c
3681 --- linux_2.6.24_org/drivers/input/serio/i8042.c 2008-02-15 20:11:51.000000000 +0000
3682 +++ linux_2.6.24_olpc/drivers/input/serio/i8042.c 2008-02-15 18:59:14.000000000 +0000
3683 @@ -874,6 +874,11 @@ static long i8042_panic_blink(long count
3689 +#include <asm/olpc.h>
3693 * Here we try to restore the original BIOS settings. We only want to
3694 * do that once, when we really suspend, not when we taking memory
3695 @@ -884,8 +889,15 @@ static long i8042_panic_blink(long count
3696 static int i8042_suspend(struct platform_device *dev, pm_message_t state)
3698 if (dev->dev.power.power_state.event != state.event) {
3700 + /* Anything newer than B2 remains powered; no reset needed */
3701 + if (!olpc_board_at_least(olpc_board_pre(0xb3))) {
3703 if (state.event == PM_EVENT_SUSPEND)
3704 i8042_controller_reset();
3709 dev->dev.power.power_state = state;
3711 @@ -908,9 +920,15 @@ static int i8042_resume(struct platform_
3712 if (dev->dev.power.power_state.event == PM_EVENT_ON)
3716 + if (!olpc_board_at_least(olpc_board_pre(0xb3))) {
3718 error = i8042_controller_check();
3725 error = i8042_controller_selftest();
3727 diff -purN linux_2.6.24_org/drivers/input/serio/serio.c linux_2.6.24_olpc/drivers/input/serio/serio.c
3728 --- linux_2.6.24_org/drivers/input/serio/serio.c 2008-02-15 20:11:51.000000000 +0000
3729 +++ linux_2.6.24_olpc/drivers/input/serio/serio.c 2008-02-15 18:59:14.000000000 +0000
3730 @@ -910,11 +910,22 @@ static int serio_uevent(struct device *d
3731 #endif /* CONFIG_HOTPLUG */
3736 +#include <asm/olpc.h>
3739 static int serio_suspend(struct device *dev, pm_message_t state)
3741 if (dev->power.power_state.event != state.event) {
3743 + if (!olpc_board_at_least(olpc_board_pre(0xb3))) {
3745 if (state.event == PM_EVENT_SUSPEND)
3746 serio_cleanup(to_serio_port(dev));
3751 dev->power.power_state = state;
3753 diff -purN linux_2.6.24_org/drivers/Kconfig linux_2.6.24_olpc/drivers/Kconfig
3754 --- linux_2.6.24_org/drivers/Kconfig 2008-02-15 20:11:21.000000000 +0000
3755 +++ linux_2.6.24_olpc/drivers/Kconfig 2008-02-15 18:58:34.000000000 +0000
3756 @@ -94,6 +94,8 @@ source "drivers/auxdisplay/Kconfig"
3758 source "drivers/kvm/Kconfig"
3760 +source "drivers/sysprof/Kconfig"
3762 source "drivers/uio/Kconfig"
3764 source "drivers/virtio/Kconfig"
3765 diff -purN linux_2.6.24_org/drivers/Makefile linux_2.6.24_olpc/drivers/Makefile
3766 --- linux_2.6.24_org/drivers/Makefile 2008-02-15 20:11:24.000000000 +0000
3767 +++ linux_2.6.24_olpc/drivers/Makefile 2008-02-15 18:58:43.000000000 +0000
3768 @@ -23,6 +23,8 @@ obj-y += char/
3770 obj-$(CONFIG_CONNECTOR) += connector/
3772 +obj-$(CONFIG_SYSPROF) += sysprof/
3774 # i810fb and intelfb depend on char/agp/
3775 obj-$(CONFIG_FB_I810) += video/i810/
3776 obj-$(CONFIG_FB_INTEL) += video/intelfb/
3777 diff -purN linux_2.6.24_org/drivers/media/video/cafe_ccic.c linux_2.6.24_olpc/drivers/media/video/cafe_ccic.c
3778 --- linux_2.6.24_org/drivers/media/video/cafe_ccic.c 2008-02-15 20:11:25.000000000 +0000
3779 +++ linux_2.6.24_olpc/drivers/media/video/cafe_ccic.c 2008-02-15 18:58:44.000000000 +0000
3780 @@ -372,6 +372,10 @@ static int cafe_smbus_write_data(struct
3781 rval = value | ((command << TWSIC1_ADDR_SHIFT) & TWSIC1_ADDR);
3782 cafe_reg_write(cam, REG_TWSIC1, rval);
3783 spin_unlock_irqrestore(&cam->dev_lock, flags);
3784 + mdelay(2); /* It'll probably take about 900µs anyway, and the
3785 + CAFÉ is apparently quite sensitive to being poked
3786 + at this point. If we can work out precisely what's
3787 + going on and reduce this delay, it would be nice. */
3790 * Time to wait for the write to complete. THIS IS A RACY
3791 @@ -907,8 +911,6 @@ static int cafe_cam_configure(struct caf
3792 struct v4l2_format fmt;
3795 - if (cam->state != S_IDLE)
3797 fmt.fmt.pix = cam->pix_format;
3798 ret = __cafe_cam_cmd(cam, VIDIOC_INT_INIT, &zero);
3800 @@ -2237,14 +2239,18 @@ static int cafe_pci_suspend(struct pci_d
3802 enum cafe_state cstate;
3804 + mutex_lock(&cam->s_mutex);
3805 ret = pci_save_state(pdev);
3808 + cam_warn(cam, "Unable to save PCI state\n");
3811 cstate = cam->state; /* HACK - stop_dma sets to idle */
3812 cafe_ctlr_stop_dma(cam);
3813 cafe_ctlr_power_down(cam);
3814 pci_disable_device(pdev);
3815 cam->state = cstate;
3816 + /* hold mutex until restore */
3820 @@ -2263,16 +2269,18 @@ static int cafe_pci_resume(struct pci_de
3821 cam_warn(cam, "Unable to re-enable device on resume!\n");
3824 + /* we're still holding mutex from suspend */
3825 cafe_ctlr_init(cam);
3826 cafe_ctlr_power_down(cam);
3828 - mutex_lock(&cam->s_mutex);
3829 - if (cam->users > 0) {
3830 - cafe_ctlr_power_up(cam);
3831 - __cafe_cam_reset(cam);
3833 - mutex_unlock(&cam->s_mutex);
3835 + if (cam->users > 0) {
3836 + cafe_ctlr_power_up(cam);
3837 + __cafe_cam_reset(cam);
3840 + cafe_ctlr_power_down(cam);
3841 + mutex_unlock(&cam->s_mutex);
3843 set_bit(CF_CONFIG_NEEDED, &cam->flags);
3844 if (cam->state == S_SPECREAD)
3845 cam->state = S_IDLE; /* Don't bother restarting */
3846 diff -purN linux_2.6.24_org/drivers/misc/Kconfig linux_2.6.24_olpc/drivers/misc/Kconfig
3847 --- linux_2.6.24_org/drivers/misc/Kconfig 2008-02-15 20:11:42.000000000 +0000
3848 +++ linux_2.6.24_olpc/drivers/misc/Kconfig 2008-02-15 18:58:52.000000000 +0000
3849 @@ -219,6 +219,11 @@ config THINKPAD_ACPI_BAY
3851 If you are not sure, say Y here.
3853 +config EEPROM_93CX6
3854 + tristate "EEPROM 93CX6 support"
3856 + This is a driver for the EEPROM chipsets 93c46 and 93c66.
3857 + The driver supports both read as well as write commands.
3860 tristate "Device driver for Atmel SSC peripheral"
3861 diff -purN linux_2.6.24_org/drivers/mmc/card/block.c linux_2.6.24_olpc/drivers/mmc/card/block.c
3862 --- linux_2.6.24_org/drivers/mmc/card/block.c 2008-02-15 20:11:13.000000000 +0000
3863 +++ linux_2.6.24_olpc/drivers/mmc/card/block.c 2008-02-15 18:58:17.000000000 +0000
3864 @@ -237,6 +237,13 @@ static int mmc_blk_issue_rq(struct mmc_q
3865 if (brq.data.blocks > card->host->max_blk_count)
3866 brq.data.blocks = card->host->max_blk_count;
3868 + if (mmc_card_sd(card) && !card->host->ios.clock) {
3869 + printk(KERN_ERR "%s: I/O to stopped card\n",
3870 + req->rq_disk->disk_name);
3873 + mmc_set_data_timeout(&brq.data, card);
3876 * If the host doesn't support multiple block writes, force
3877 * block writes to single block. SD cards are excepted from
3878 diff -purN linux_2.6.24_org/drivers/mmc/host/sdhci.c linux_2.6.24_olpc/drivers/mmc/host/sdhci.c
3879 --- linux_2.6.24_org/drivers/mmc/host/sdhci.c 2008-02-15 20:11:13.000000000 +0000
3880 +++ linux_2.6.24_olpc/drivers/mmc/host/sdhci.c 2008-02-15 18:58:17.000000000 +0000
3881 @@ -441,6 +441,12 @@ static void sdhci_prepare_data(struct sd
3886 + * There's an off-by-one error in the hw that we need to
3892 printk(KERN_WARNING "%s: Too large timeout requested!\n",
3893 mmc_hostname(host->mmc));
3894 @@ -728,19 +734,17 @@ static void sdhci_set_power(struct sdhci
3895 if (!(host->chip->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE))
3896 writeb(0, host->ioaddr + SDHCI_POWER_CONTROL);
3898 - pwr = SDHCI_POWER_ON;
3900 switch (1 << power) {
3901 case MMC_VDD_165_195:
3902 - pwr |= SDHCI_POWER_180;
3903 + pwr = SDHCI_POWER_180;
3907 - pwr |= SDHCI_POWER_300;
3908 + pwr = SDHCI_POWER_300;
3912 - pwr |= SDHCI_POWER_330;
3913 + pwr = SDHCI_POWER_330;
3917 @@ -748,6 +752,10 @@ static void sdhci_set_power(struct sdhci
3919 writeb(pwr, host->ioaddr + SDHCI_POWER_CONTROL);
3921 + pwr |= SDHCI_POWER_ON;
3923 + writeb(pwr, host->ioaddr + SDHCI_POWER_CONTROL);
3926 host->power = power;
3928 diff -purN linux_2.6.24_org/drivers/mtd/nand/cafe_nand.c linux_2.6.24_olpc/drivers/mtd/nand/cafe_nand.c
3929 --- linux_2.6.24_org/drivers/mtd/nand/cafe_nand.c 2008-02-15 20:11:46.000000000 +0000
3930 +++ linux_2.6.24_olpc/drivers/mtd/nand/cafe_nand.c 2008-02-15 18:58:57.000000000 +0000
3933 #include <linux/mtd/mtd.h>
3934 #include <linux/mtd/nand.h>
3935 +#include <linux/mtd/partitions.h>
3936 #include <linux/rslib.h>
3937 #include <linux/pci.h>
3938 #include <linux/delay.h>
3942 struct nand_chip nand;
3943 + struct mtd_partition *parts;
3944 struct pci_dev *pdev;
3946 struct rs_control *rs;
3947 @@ -84,6 +86,10 @@ static unsigned int numtimings;
3948 static int timing[3];
3949 module_param_array(timing, int, &numtimings, 0644);
3951 +#ifdef CONFIG_MTD_PARTITIONS
3952 +static const char *part_probes[] = { "RedBoot", NULL };
3955 /* Hrm. Why isn't this already conditional on something in the struct device? */
3956 #define cafe_dev_dbg(dev, args...) do { if (debug) dev_dbg(dev, ##args); } while(0)
3958 @@ -620,7 +626,9 @@ static int __devinit cafe_nand_probe(str
3960 struct mtd_info *mtd;
3961 struct cafe_priv *cafe;
3962 + struct mtd_partition *parts;
3967 /* Very old versions shared the same PCI ident for all three
3968 @@ -787,7 +795,18 @@ static int __devinit cafe_nand_probe(str
3971 pci_set_drvdata(pdev, mtd);
3973 + /* We register the whole device first, separate from the partitions */
3974 add_mtd_device(mtd);
3976 +#ifdef CONFIG_MTD_PARTITIONS
3977 + nr_parts = parse_mtd_partitions(mtd, part_probes, &parts, 0);
3978 + if (nr_parts > 0) {
3979 + cafe->parts = parts;
3980 + dev_info(&cafe->pdev->dev, "%d RedBoot partitions found\n", nr_parts);
3981 + add_mtd_partitions(mtd, parts, nr_parts);
3987 diff -purN linux_2.6.24_org/drivers/mtd/redboot.c linux_2.6.24_olpc/drivers/mtd/redboot.c
3988 --- linux_2.6.24_org/drivers/mtd/redboot.c 2008-02-15 20:11:46.000000000 +0000
3989 +++ linux_2.6.24_olpc/drivers/mtd/redboot.c 2008-02-15 18:58:58.000000000 +0000
3990 @@ -59,16 +59,31 @@ static int parse_redboot_partitions(stru
3991 static char nullstring[] = "unallocated";
3994 + if ( directory < 0 ) {
3995 + offset = master->size + directory * master->erasesize;
3996 + while (master->block_isbad &&
3997 + master->block_isbad(master, offset)) {
4000 + printk(KERN_NOTICE "Failed to find a non-bad block to check for RedBoot partition table\n");
4003 + offset -= master->erasesize;
4006 + offset = directory * master->erasesize;
4007 + while (master->block_isbad &&
4008 + master->block_isbad(master, offset)) {
4009 + offset += master->erasesize;
4010 + if (offset == master->size)
4014 buf = vmalloc(master->erasesize);
4019 - if ( directory < 0 )
4020 - offset = master->size + directory*master->erasesize;
4022 - offset = directory*master->erasesize;
4024 printk(KERN_NOTICE "Searching for RedBoot partition table in %s at offset 0x%lx\n",
4025 master->name, offset);
4027 diff -purN linux_2.6.24_org/drivers/net/forcedeth.c linux_2.6.24_olpc/drivers/net/forcedeth.c
4028 --- linux_2.6.24_org/drivers/net/forcedeth.c 2008-02-15 20:11:19.000000000 +0000
4029 +++ linux_2.6.24_olpc/drivers/net/forcedeth.c 2008-02-15 18:58:33.000000000 +0000
4030 @@ -3559,11 +3559,13 @@ static int nv_request_irq(struct net_dev
4032 if (ret != 0 && np->msi_flags & NV_MSI_CAPABLE) {
4033 if ((ret = pci_enable_msi(np->pci_dev)) == 0) {
4034 + pci_intx(np->pci_dev, 0);
4035 np->msi_flags |= NV_MSI_ENABLED;
4036 dev->irq = np->pci_dev->irq;
4037 if (request_irq(np->pci_dev->irq, handler, IRQF_SHARED, dev->name, dev) != 0) {
4038 printk(KERN_INFO "forcedeth: request_irq failed %d\n", ret);
4039 pci_disable_msi(np->pci_dev);
4040 + pci_intx(np->pci_dev, 1);
4041 np->msi_flags &= ~NV_MSI_ENABLED;
4042 dev->irq = np->pci_dev->irq;
4044 @@ -3606,6 +3608,7 @@ static void nv_free_irq(struct net_devic
4045 free_irq(np->pci_dev->irq, dev);
4046 if (np->msi_flags & NV_MSI_ENABLED) {
4047 pci_disable_msi(np->pci_dev);
4048 + pci_intx(np->pci_dev, 1);
4049 np->msi_flags &= ~NV_MSI_ENABLED;
4052 diff -purN linux_2.6.24_org/drivers/pci/quirks.c linux_2.6.24_olpc/drivers/pci/quirks.c
4053 --- linux_2.6.24_org/drivers/pci/quirks.c 2008-02-15 20:11:33.000000000 +0000
4054 +++ linux_2.6.24_olpc/drivers/pci/quirks.c 2008-02-15 18:58:50.000000000 +0000
4055 @@ -1359,6 +1359,17 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_IN
4056 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x260b, quirk_intel_pcie_pm);
4059 + * According to Tom Sylla, the Geode does not support PCI power management
4060 + * transition, so we shouldn't need the D3hot delay.
4062 +static void __init quirk_geode_pci_pm(struct pci_dev *dev)
4064 + pci_pm_d3_delay = 0;
4066 +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_LEGACY, quirk_geode_pci_pm);
4067 +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA, quirk_geode_pci_pm);
4070 * Toshiba TC86C001 IDE controller reports the standard 8-byte BAR0 size
4071 * but the PIO transfers won't work if BAR0 falls at the odd 8 bytes.
4072 * Re-allocate the region if needed...
4073 diff -purN linux_2.6.24_org/drivers/power/ds2760_battery.c linux_2.6.24_olpc/drivers/power/ds2760_battery.c
4074 --- linux_2.6.24_org/drivers/power/ds2760_battery.c 2008-02-15 20:11:45.000000000 +0000
4075 +++ linux_2.6.24_olpc/drivers/power/ds2760_battery.c 2008-02-15 18:58:56.000000000 +0000
4076 @@ -409,6 +409,7 @@ static int ds2760_battery_suspend(struct
4077 struct ds2760_device_info *di = platform_get_drvdata(pdev);
4079 di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN;
4080 + power_supply_changed(&di->bat);
4084 diff -purN linux_2.6.24_org/drivers/power/olpc_battery.c linux_2.6.24_olpc/drivers/power/olpc_battery.c
4085 --- linux_2.6.24_org/drivers/power/olpc_battery.c 2008-02-15 20:11:45.000000000 +0000
4086 +++ linux_2.6.24_olpc/drivers/power/olpc_battery.c 2008-02-15 18:58:56.000000000 +0000
4088 #include <linux/power_supply.h>
4089 #include <linux/jiffies.h>
4090 #include <linux/sched.h>
4091 +#include <asm/io.h>
4092 #include <asm/olpc.h>
4095 #define EC_BAT_VOLTAGE 0x10 /* uint16_t, *9.76/32, mV */
4096 #define EC_BAT_CURRENT 0x11 /* int16_t, *15.625/120, mA */
4097 -#define EC_BAT_ACR 0x12
4098 +#define EC_BAT_ACR 0x12 /* int16_t *416.667 µAh */
4099 #define EC_BAT_TEMP 0x13 /* uint16_t, *100/256, °C */
4100 #define EC_AMB_TEMP 0x14 /* uint16_t, *100/256, °C */
4101 #define EC_BAT_STATUS 0x15 /* uint8_t, bitmask */
4102 @@ -84,6 +85,8 @@ static struct power_supply olpc_ac = {
4103 .get_property = olpc_ac_get_prop,
4106 +static char bat_serial[17]; /* Ick */
4108 /*********************************************************************
4109 * Battery properties
4110 *********************************************************************/
4111 @@ -94,6 +97,7 @@ static int olpc_bat_get_property(struct
4117 ret = olpc_ec_cmd(EC_BAT_STATUS, NULL, 0, &ec_byte, 1);
4119 @@ -127,8 +131,8 @@ static int olpc_bat_get_property(struct
4120 val->intval = POWER_SUPPLY_STATUS_FULL;
4121 else /* Not _necessarily_ true but EC doesn't tell all yet */
4122 val->intval = POWER_SUPPLY_STATUS_CHARGING;
4126 case POWER_SUPPLY_PROP_PRESENT:
4127 val->intval = !!(ec_byte & BAT_STAT_PRESENT);
4129 @@ -249,6 +253,22 @@ static int olpc_bat_get_property(struct
4130 ec_word = be16_to_cpu(ec_word);
4131 val->intval = ec_word * 100 / 256;
4133 + case POWER_SUPPLY_PROP_ACCUM_CURRENT:
4134 + ret = olpc_ec_cmd(EC_BAT_ACR, NULL, 0, (void *)&ec_word, 2);
4138 + ec_word = be16_to_cpu(ec_word);
4139 + val->intval = (uint16_t)ec_word;
4141 + case POWER_SUPPLY_PROP_SERIAL_NUMBER:
4142 + ret = olpc_ec_cmd(EC_BAT_SERIAL, NULL, 0, (void *)&ser_buf, 8);
4146 + sprintf(bat_serial, "%016llx", (long long)be64_to_cpu(ser_buf));
4147 + val->strval = bat_serial;
4152 @@ -268,7 +288,51 @@ static enum power_supply_property olpc_b
4153 POWER_SUPPLY_PROP_CAPACITY_LEVEL,
4154 POWER_SUPPLY_PROP_TEMP,
4155 POWER_SUPPLY_PROP_TEMP_AMBIENT,
4156 + POWER_SUPPLY_PROP_ACCUM_CURRENT,
4157 POWER_SUPPLY_PROP_MANUFACTURER,
4158 + POWER_SUPPLY_PROP_SERIAL_NUMBER,
4161 +/* EEPROM reading goes completely around the power_supply API, sadly */
4163 +#define EEPROM_START 0x20
4164 +#define EEPROM_END 0x80
4165 +#define EEPROM_SIZE (EEPROM_END - EEPROM_START)
4167 +static ssize_t olpc_bat_eeprom_read(struct kobject *kobj, char *buf, loff_t off,
4173 + if (off >= EEPROM_SIZE)
4175 + if (off + count > EEPROM_SIZE)
4176 + count = EEPROM_SIZE - off;
4178 + end = EEPROM_START + off + count;
4179 + for (ec_byte = EEPROM_START + off; ec_byte < end; ec_byte++) {
4180 + ret = olpc_ec_cmd(EC_BAT_EEPROM, &ec_byte, 1,
4181 + &buf[ec_byte - EEPROM_START], 1);
4183 + printk(KERN_ERR "olpc-battery: EC command "
4184 + "EC_BAT_EEPROM @ 0x%x failed -"
4185 + " %d!\n", ec_byte, ret);
4193 +static struct bin_attribute olpc_bat_eeprom = {
4197 + .owner = THIS_MODULE,
4200 + .read = olpc_bat_eeprom_read,
4203 /*********************************************************************
4204 @@ -299,7 +363,7 @@ static int __init olpc_bat_init(void)
4206 if (!olpc_platform_info.ecver)
4208 - if (olpc_platform_info.ecver < 0x43) {
4209 + if (olpc_platform_info.ecver < 0x44) {
4210 printk(KERN_NOTICE "OLPC EC version 0x%02x too old for battery driver.\n", olpc_platform_info.ecver);
4213 @@ -324,9 +388,15 @@ static int __init olpc_bat_init(void)
4215 goto battery_failed;
4217 + ret = device_create_bin_file(olpc_bat.dev, &olpc_bat_eeprom);
4219 + goto eeprom_failed;
4221 olpc_register_battery_callback(&olpc_battery_trigger_uevent);
4225 + power_supply_unregister(&olpc_bat);
4227 power_supply_unregister(&olpc_ac);
4229 @@ -338,6 +408,7 @@ success:
4230 static void __exit olpc_bat_exit(void)
4232 olpc_deregister_battery_callback();
4233 + device_remove_bin_file(olpc_bat.dev, &olpc_bat_eeprom);
4234 power_supply_unregister(&olpc_bat);
4235 power_supply_unregister(&olpc_ac);
4236 platform_device_unregister(bat_pdev);
4237 diff -purN linux_2.6.24_org/drivers/power/power_supply_sysfs.c linux_2.6.24_olpc/drivers/power/power_supply_sysfs.c
4238 --- linux_2.6.24_org/drivers/power/power_supply_sysfs.c 2008-02-15 20:11:45.000000000 +0000
4239 +++ linux_2.6.24_olpc/drivers/power/power_supply_sysfs.c 2008-02-15 18:58:56.000000000 +0000
4240 @@ -114,9 +114,11 @@ static struct device_attribute power_sup
4241 POWER_SUPPLY_ATTR(time_to_empty_avg),
4242 POWER_SUPPLY_ATTR(time_to_full_now),
4243 POWER_SUPPLY_ATTR(time_to_full_avg),
4244 + POWER_SUPPLY_ATTR(accum_current),
4245 /* Properties of type `const char *' */
4246 POWER_SUPPLY_ATTR(model_name),
4247 POWER_SUPPLY_ATTR(manufacturer),
4248 + POWER_SUPPLY_ATTR(serial_number),
4251 static ssize_t power_supply_show_static_attrs(struct device *dev,
4252 diff -purN linux_2.6.24_org/drivers/serial/serial_core.c linux_2.6.24_olpc/drivers/serial/serial_core.c
4253 --- linux_2.6.24_org/drivers/serial/serial_core.c 2008-02-15 20:11:33.000000000 +0000
4254 +++ linux_2.6.24_olpc/drivers/serial/serial_core.c 2008-02-15 18:58:51.000000000 +0000
4255 @@ -2013,6 +2013,7 @@ int uart_suspend_port(struct uart_driver
4256 int uart_resume_port(struct uart_driver *drv, struct uart_port *port)
4258 struct uart_state *state = drv->state + port->line;
4259 + struct ktermios termios;
4261 mutex_lock(&state->mutex);
4263 @@ -2035,20 +2036,6 @@ int uart_resume_port(struct uart_driver
4264 * Re-enable the console device after suspending.
4266 if (uart_console(port)) {
4267 - struct ktermios termios;
4270 - * First try to use the console cflag setting.
4272 - memset(&termios, 0, sizeof(struct ktermios));
4273 - termios.c_cflag = port->cons->cflag;
4276 - * If that's unset, use the tty termios setting.
4278 - if (state->info && state->info->tty && termios.c_cflag == 0)
4279 - termios = *state->info->tty->termios;
4281 port->ops->set_termios(port, &termios, NULL);
4282 console_start(port->cons);
4284 diff -purN linux_2.6.24_org/drivers/sysprof/config.h linux_2.6.24_olpc/drivers/sysprof/config.h
4285 --- linux_2.6.24_org/drivers/sysprof/config.h 1970-01-01 01:00:00.000000000 +0100
4286 +++ linux_2.6.24_olpc/drivers/sysprof/config.h 2008-02-15 18:58:59.000000000 +0000
4288 +/* config.h. Generated by configure. */
4289 +/* config.h.in. Generated from configure.ac by autoheader. */
4291 +/* Look for global separate debug info in this path */
4292 +#define DEBUGDIR "/usr/local/lib/debug"
4294 +/* Define to 1 if you have the `iberty' library (-liberty). */
4295 +/* #undef HAVE_LIBIBERTY */
4297 +/* Define to the address where bug reports for this package should be sent. */
4298 +#define PACKAGE_BUGREPORT ""
4300 +/* Define to the full name of this package. */
4301 +#define PACKAGE_NAME "sysprof"
4303 +/* Define to the full name and version of this package. */
4304 +#define PACKAGE_STRING "sysprof 1.0.8"
4306 +/* Define to the one symbol short name of this package. */
4307 +#define PACKAGE_TARNAME "sysprof"
4309 +/* Define to the version of this package. */
4310 +#define PACKAGE_VERSION "1.0.8"
4311 diff -purN linux_2.6.24_org/drivers/sysprof/Kconfig linux_2.6.24_olpc/drivers/sysprof/Kconfig
4312 --- linux_2.6.24_org/drivers/sysprof/Kconfig 1970-01-01 01:00:00.000000000 +0100
4313 +++ linux_2.6.24_olpc/drivers/sysprof/Kconfig 2008-02-15 18:58:59.000000000 +0000
4319 + tristate "Sysprof support"
4321 + Say M here to include the sysprof-module.
4323 + Sysprof is a sampling profiler that uses a kernel module,
4324 + sysprof-module, to generate stacktraces which are then interpreted by
4325 + the userspace program "sysprof".
4327 diff -purN linux_2.6.24_org/drivers/sysprof/Makefile linux_2.6.24_olpc/drivers/sysprof/Makefile
4328 --- linux_2.6.24_org/drivers/sysprof/Makefile 1970-01-01 01:00:00.000000000 +0100
4329 +++ linux_2.6.24_olpc/drivers/sysprof/Makefile 2008-02-15 18:58:59.000000000 +0000
4331 +obj-$(CONFIG_SYSPROF) += sysprof-module.o
4332 diff -purN linux_2.6.24_org/drivers/sysprof/sysprof-module.c linux_2.6.24_olpc/drivers/sysprof/sysprof-module.c
4333 --- linux_2.6.24_org/drivers/sysprof/sysprof-module.c 1970-01-01 01:00:00.000000000 +0100
4334 +++ linux_2.6.24_olpc/drivers/sysprof/sysprof-module.c 2008-02-15 18:58:59.000000000 +0000
4336 +/* -*- c-basic-offset: 8 -*- */
4338 +/* Sysprof -- Sampling, systemwide CPU profiler
4339 + * Copyright 2004, Red Hat, Inc.
4340 + * Copyright 2004, 2005, Soeren Sandmann
4342 + * This program is free software; you can redistribute it and/or modify
4343 + * it under the terms of the GNU General Public License as published by
4344 + * the Free Software Foundation; either version 2 of the License, or
4345 + * (at your option) any later version.
4347 + * This program is distributed in the hope that it will be useful,
4348 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
4349 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4350 + * GNU General Public License for more details.
4352 + * You should have received a copy of the GNU General Public License
4353 + * along with this program; if not, write to the Free Software
4354 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
4360 +#include <asm/atomic.h>
4361 +#include <linux/kernel.h> /* Needed for KERN_ALERT */
4362 +#include <linux/module.h> /* Needed by all modules */
4363 +#include <linux/sched.h>
4365 +#include <linux/proc_fs.h>
4366 +#include <asm/uaccess.h>
4367 +#include <linux/poll.h>
4368 +#include <linux/highmem.h>
4369 +#include <linux/pagemap.h>
4370 +#include <linux/profile.h>
4372 +#include "sysprof-module.h"
4374 +#include "config.h"
4376 +#include <linux/version.h>
4378 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
4379 +#include <linux/config.h>
4382 +#if !CONFIG_PROFILING
4383 +# error Sysprof needs a kernel with profiling support compiled in.
4386 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11)
4387 +# error Sysprof needs a Linux 2.6.11 kernel or later
4389 +#include <linux/kallsyms.h>
4391 +MODULE_LICENSE("GPL");
4392 +MODULE_AUTHOR("Soeren Sandmann (sandmann@daimi.au.dk)");
4394 +#define SAMPLES_PER_SECOND (200)
4395 +#define INTERVAL ((HZ <= SAMPLES_PER_SECOND)? 1 : (HZ / SAMPLES_PER_SECOND))
4396 +#define N_TRACES 256
4398 +static SysprofStackTrace stack_traces[N_TRACES];
4399 +static SysprofStackTrace * head = &stack_traces[0];
4400 +static SysprofStackTrace * tail = &stack_traces[0];
4401 +DECLARE_WAIT_QUEUE_HEAD (wait_for_trace);
4402 +DECLARE_WAIT_QUEUE_HEAD (wait_for_exit);
4404 +/* Macro the names of the registers that are used on each architecture */
4405 +#if defined(CONFIG_X86_64)
4406 +# define REG_FRAME_PTR rbp
4407 +# define REG_INS_PTR rip
4408 +# define REG_STACK_PTR rsp
4409 +#elif defined(CONFIG_X86)
4410 +# define REG_FRAME_PTR ebp
4411 +# define REG_INS_PTR eip
4412 +# define REG_STACK_PTR esp
4414 +# error Sysprof only supports the i386 and x86-64 architectures
4417 +typedef struct userspace_reader userspace_reader;
4418 +struct userspace_reader
4420 + struct task_struct *task;
4421 + unsigned long cache_address;
4422 + unsigned long *cache;
4425 +typedef struct StackFrame StackFrame;
4426 +struct StackFrame {
4427 + unsigned long next;
4428 + unsigned long return_address;
4431 +struct work_struct work;
4434 +read_frame (void *frame_pointer, StackFrame *frame)
4437 + /* This is commented out because we seem to be called with
4438 + * (current_thread_info()->addr_limit.seg)) == 0
4439 + * which means access_ok() _always_ fails.
4441 + * Not sure why (or if) this isn't the case for oprofile
4443 + if (!access_ok(VERIFY_READ, frame_pointer, sizeof(StackFrame)))
4447 + if (__copy_from_user_inatomic (
4448 + frame, frame_pointer, sizeof (StackFrame)))
4454 +DEFINE_PER_CPU(int, n_samples);
4457 +timer_notify (struct pt_regs *regs)
4459 + SysprofStackTrace *trace = head;
4462 + static atomic_t in_timer_notify = ATOMIC_INIT(1);
4465 + n = ++get_cpu_var(n_samples);
4466 + put_cpu_var(n_samples);
4468 + if (n % INTERVAL != 0)
4471 + /* 0: locked, 1: unlocked */
4473 + if (!atomic_dec_and_test(&in_timer_notify))
4476 + is_user = user_mode(regs);
4478 + if (!current || current->pid == 0)
4481 + if (is_user && current->state != TASK_RUNNING)
4488 + trace->pid = current->pid;
4489 + trace->truncated = 0;
4490 + trace->n_addresses = 1;
4492 + /* 0x1 is taken by sysprof to mean "in kernel" */
4493 + trace->addresses[0] = (void *)0x1;
4497 + StackFrame *frame_pointer;
4499 + memset(trace, 0, sizeof (SysprofStackTrace));
4501 + trace->pid = current->pid;
4502 + trace->truncated = 0;
4506 + trace->addresses[i++] = (void *)regs->REG_INS_PTR;
4508 + frame_pointer = (void *)regs->REG_FRAME_PTR;
4510 + while (read_frame (frame_pointer, &frame) == 0 &&
4511 + i < SYSPROF_MAX_ADDRESSES &&
4512 + (unsigned long)frame_pointer >= regs->REG_STACK_PTR)
4514 + trace->addresses[i++] = (void *)frame.return_address;
4515 + frame_pointer = (StackFrame *)frame.next;
4518 + trace->n_addresses = i;
4520 + if (i == SYSPROF_MAX_ADDRESSES)
4521 + trace->truncated = 1;
4523 + trace->truncated = 0;
4526 + if (head++ == &stack_traces[N_TRACES - 1])
4527 + head = &stack_traces[0];
4529 + wake_up (&wait_for_trace);
4532 + atomic_inc(&in_timer_notify);
4537 +procfile_read(char *buffer,
4538 + char **buffer_location,
4545 + return -EWOULDBLOCK;
4547 + *buffer_location = (char *)tail;
4549 + BUG_ON(tail->pid == 0);
4551 + if (tail++ == &stack_traces[N_TRACES - 1])
4552 + tail = &stack_traces[0];
4554 + return sizeof (SysprofStackTrace);
4557 +struct proc_dir_entry *trace_proc_file;
4558 +static unsigned int
4559 +procfile_poll(struct file *filp, poll_table *poll_table)
4562 + return POLLIN | POLLRDNORM;
4564 + poll_wait(filp, &wait_for_trace, poll_table);
4567 + return POLLIN | POLLRDNORM;
4575 + static struct file_operations fops;
4578 + create_proc_entry ("sysprof-trace", S_IFREG | S_IRUGO, &proc_root);
4580 + if (!trace_proc_file)
4583 + fops = *trace_proc_file->proc_fops;
4584 + fops.poll = procfile_poll;
4586 + trace_proc_file->read_proc = procfile_read;
4587 + trace_proc_file->proc_fops = &fops;
4588 + trace_proc_file->size = sizeof (SysprofStackTrace);
4590 + register_timer_hook (timer_notify);
4592 + printk(KERN_ALERT "sysprof: loaded (%s)\n", PACKAGE_VERSION);
4598 +cleanup_module(void)
4600 + unregister_timer_hook (timer_notify);
4602 + remove_proc_entry("sysprof-trace", &proc_root);
4604 + printk(KERN_ALERT "sysprof: unloaded\n");
4607 diff -purN linux_2.6.24_org/drivers/sysprof/sysprof-module.h linux_2.6.24_olpc/drivers/sysprof/sysprof-module.h
4608 --- linux_2.6.24_org/drivers/sysprof/sysprof-module.h 1970-01-01 01:00:00.000000000 +0100
4609 +++ linux_2.6.24_olpc/drivers/sysprof/sysprof-module.h 2008-02-15 18:58:59.000000000 +0000
4611 +/* Sysprof -- Sampling, systemwide CPU profiler
4612 + * Copyright 2004, Red Hat, Inc.
4613 + * Copyright 2004, 2005, Soeren Sandmann
4615 + * This program is free software; you can redistribute it and/or modify
4616 + * it under the terms of the GNU General Public License as published by
4617 + * the Free Software Foundation; either version 2 of the License, or
4618 + * (at your option) any later version.
4620 + * This program is distributed in the hope that it will be useful,
4621 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
4622 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4623 + * GNU General Public License for more details.
4625 + * You should have received a copy of the GNU General Public License
4626 + * along with this program; if not, write to the Free Software
4627 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
4630 +#ifndef SYSPROF_MODULE_H
4631 +#define SYSPROF_MODULE_H
4633 +typedef struct SysprofStackTrace SysprofStackTrace;
4635 +#define SYSPROF_MAX_ADDRESSES 512
4637 +struct SysprofStackTrace
4639 + int pid; /* -1 if in kernel */
4641 + int n_addresses; /* note: this can be 1 if the process was compiled
4642 + * with -fomit-frame-pointer or is otherwise weird
4644 + void *addresses[SYSPROF_MAX_ADDRESSES];
4648 diff -purN linux_2.6.24_org/drivers/usb/core/driver.c linux_2.6.24_olpc/drivers/usb/core/driver.c
4649 --- linux_2.6.24_org/drivers/usb/core/driver.c 2008-02-15 20:11:09.000000000 +0000
4650 +++ linux_2.6.24_olpc/drivers/usb/core/driver.c 2008-02-15 18:58:14.000000000 +0000
4651 @@ -1062,8 +1062,15 @@ static int usb_suspend_both(struct usb_d
4656 + if (status == 0) {
4658 + /* Non-root devices don't need to do anything for FREEZE
4660 + if (udev->parent && (msg.event == PM_EVENT_FREEZE ||
4661 + msg.event == PM_EVENT_PRETHAW))
4663 status = usb_suspend_device(udev, msg);
4666 /* If the suspend failed, resume interfaces that did get suspended */
4668 diff -purN linux_2.6.24_org/drivers/usb/core/quirks.c linux_2.6.24_olpc/drivers/usb/core/quirks.c
4669 --- linux_2.6.24_org/drivers/usb/core/quirks.c 2008-02-15 20:11:09.000000000 +0000
4670 +++ linux_2.6.24_olpc/drivers/usb/core/quirks.c 2008-02-15 18:58:12.000000000 +0000
4671 @@ -45,6 +45,9 @@ static const struct usb_device_id usb_qu
4672 /* SKYMEDI USB_DRIVE */
4673 { USB_DEVICE(0x1516, 0x8628), .driver_info = USB_QUIRK_RESET_RESUME },
4675 + /* Philips PSC805 audio device */
4676 + { USB_DEVICE(0x0471, 0x0155), .driver_info = USB_QUIRK_RESET_RESUME },
4678 { } /* terminating entry must be last */
4681 diff -purN linux_2.6.24_org/drivers/usb/core/usb.h linux_2.6.24_olpc/drivers/usb/core/usb.h
4682 --- linux_2.6.24_org/drivers/usb/core/usb.h 2008-02-15 20:11:09.000000000 +0000
4683 +++ linux_2.6.24_olpc/drivers/usb/core/usb.h 2008-02-15 18:58:14.000000000 +0000
4684 @@ -41,6 +41,7 @@ extern void usb_host_cleanup(void);
4685 extern void usb_autosuspend_work(struct work_struct *work);
4686 extern int usb_port_suspend(struct usb_device *dev);
4687 extern int usb_port_resume(struct usb_device *dev);
4688 +extern int usb_reset_suspended_device(struct usb_device *udev);
4689 extern int usb_external_suspend_device(struct usb_device *udev,
4691 extern int usb_external_resume_device(struct usb_device *udev);
4692 diff -purN linux_2.6.24_org/drivers/usb/host/ehci-hcd.c linux_2.6.24_olpc/drivers/usb/host/ehci-hcd.c
4693 --- linux_2.6.24_org/drivers/usb/host/ehci-hcd.c 2008-02-15 20:11:09.000000000 +0000
4694 +++ linux_2.6.24_olpc/drivers/usb/host/ehci-hcd.c 2008-02-15 18:58:12.000000000 +0000
4695 @@ -653,9 +653,16 @@ static irqreturn_t ehci_irq (struct usb_
4697 /* complete the unlinking of some qh [4.15.2.3] */
4698 if (status & STS_IAA) {
4699 - COUNT (ehci->stats.reclaim);
4700 - ehci->reclaim_ready = 1;
4702 + if (!ehci->reclaim) {
4703 + printk(KERN_WARNING "%s would set reclaim_ready with nothing to reclaim!\n", __func__);
4704 +printk(KERN_DEBUG "%s: USBCMD: 0x%x\n", __func__, ehci_readl(ehci, &ehci->regs->command));
4705 +printk(KERN_DEBUG "%s: USBSTS: 0x%x\n", __func__, ehci_readl(ehci, &ehci->regs->status));
4708 + COUNT (ehci->stats.reclaim);
4709 + ehci->reclaim_ready = 1;
4714 /* remote wakeup [4.3.1] */
4715 diff -purN linux_2.6.24_org/drivers/usb/host/ehci-hub.c linux_2.6.24_olpc/drivers/usb/host/ehci-hub.c
4716 --- linux_2.6.24_org/drivers/usb/host/ehci-hub.c 2008-02-15 20:11:09.000000000 +0000
4717 +++ linux_2.6.24_olpc/drivers/usb/host/ehci-hub.c 2008-02-15 18:58:12.000000000 +0000
4718 @@ -132,10 +132,15 @@ static int ehci_bus_suspend (struct usb_
4719 ehci_quiesce (ehci);
4720 hcd->state = HC_STATE_QUIESCING;
4722 +printk(KERN_DEBUG "%s: USBCMD: 0x%x\n", __func__, ehci_readl(ehci, &ehci->regs->command));
4723 +printk(KERN_DEBUG "%s: USBSTS: 0x%x\n", __func__, ehci_readl(ehci, &ehci->regs->status));
4725 ehci->command = ehci_readl(ehci, &ehci->regs->command);
4727 ehci->reclaim_ready = 1;
4729 +printk(KERN_DEBUG "%s: USBCMD: 0x%x\n", __func__, ehci_readl(ehci, &ehci->regs->command));
4730 +printk(KERN_DEBUG "%s: USBSTS: 0x%x\n", __func__, ehci_readl(ehci, &ehci->regs->status));
4732 /* Unlike other USB host controller types, EHCI doesn't have
4733 * any notion of "global" or bus-wide suspend. The driver has
4734 @@ -175,6 +180,9 @@ static int ehci_bus_suspend (struct usb_
4736 hcd->state = HC_STATE_SUSPENDED;
4738 +printk(KERN_DEBUG "%s: USBCMD: 0x%x\n", __func__, ehci_readl(ehci, &ehci->regs->command));
4739 +printk(KERN_DEBUG "%s: USBSTS: 0x%x\n", __func__, ehci_readl(ehci, &ehci->regs->status));
4741 /* allow remote wakeup */
4743 if (!device_may_wakeup(&hcd->self.root_hub->dev))
4744 @@ -195,6 +203,18 @@ static int ehci_bus_resume (struct usb_h
4750 + static void __iomem *usb_ehc_addr;
4752 + rdmsrl(0x51200009, lo);
4753 + usb_ehc_addr = ioremap(lo, 256);
4754 + writel(readl(usb_ehc_addr+0x54) | 0x1000, usb_ehc_addr+0x54);
4755 + writel(readl(usb_ehc_addr+0x58) | 0x1000, usb_ehc_addr+0x58);
4756 + writel(readl(usb_ehc_addr+0x5C) | 0x1000, usb_ehc_addr+0x5C);
4757 + writel(readl(usb_ehc_addr+0x60) | 0x1000, usb_ehc_addr+0x60);
4758 + iounmap(usb_ehc_addr);
4761 if (time_before (jiffies, ehci->next_statechange))
4763 diff -purN linux_2.6.24_org/drivers/usb/host/ehci-pci.c linux_2.6.24_olpc/drivers/usb/host/ehci-pci.c
4764 --- linux_2.6.24_org/drivers/usb/host/ehci-pci.c 2008-02-15 20:11:09.000000000 +0000
4765 +++ linux_2.6.24_olpc/drivers/usb/host/ehci-pci.c 2008-02-15 18:58:12.000000000 +0000
4766 @@ -247,6 +247,9 @@ static int ehci_pci_suspend(struct usb_h
4770 +printk(KERN_DEBUG "%s: USBCMD: 0x%x\n", __func__, ehci_readl(ehci, &ehci->regs->command));
4771 +printk(KERN_DEBUG "%s: USBSTS: 0x%x\n", __func__, ehci_readl(ehci, &ehci->regs->status));
4773 ehci_writel(ehci, 0, &ehci->regs->intr_enable);
4774 (void)ehci_readl(ehci, &ehci->regs->intr_enable);
4776 diff -purN linux_2.6.24_org/drivers/usb/host/ehci-q.c linux_2.6.24_olpc/drivers/usb/host/ehci-q.c
4777 --- linux_2.6.24_org/drivers/usb/host/ehci-q.c 2008-02-15 20:11:09.000000000 +0000
4778 +++ linux_2.6.24_olpc/drivers/usb/host/ehci-q.c 2008-02-15 18:58:12.000000000 +0000
4779 @@ -177,7 +177,7 @@ static int qtd_copy_status (
4780 if (QTD_CERR (token))
4783 - ehci_dbg (ehci, "devpath %s ep%d%s 3strikes\n",
4784 + printk(KERN_ERR "devpath %s ep%d%s 3strikes\n",
4786 usb_pipeendpoint (urb->pipe),
4787 usb_pipein (urb->pipe) ? "in" : "out");
4788 @@ -973,6 +973,11 @@ static void end_unlink_async (struct ehc
4789 struct ehci_qh *qh = ehci->reclaim;
4790 struct ehci_qh *next;
4793 + printk(KERN_CRIT "%s with ehci->reclaim == NULL!\n", __func__);
4797 timer_action_done (ehci, TIMER_IAA_WATCHDOG);
4799 // qh->hw_next = cpu_to_hc32(qh->qh_dma);
4800 diff -purN linux_2.6.24_org/drivers/usb/host/ohci-pci.c linux_2.6.24_olpc/drivers/usb/host/ohci-pci.c
4801 --- linux_2.6.24_org/drivers/usb/host/ohci-pci.c 2008-02-15 20:11:09.000000000 +0000
4802 +++ linux_2.6.24_olpc/drivers/usb/host/ohci-pci.c 2008-02-15 18:58:12.000000000 +0000
4803 @@ -317,6 +317,8 @@ static int ohci_pci_resume (struct usb_h
4804 /* FIXME: we should try to detect loss of VBUS power here */
4805 prepare_for_handover(hcd);
4807 + /* Force the PM core to resume the root hub */
4808 + hcd_to_bus(hcd)->root_hub->dev.power.prev_state.event = PM_EVENT_ON;
4812 diff -purN linux_2.6.24_org/drivers/usb/storage/usb.c linux_2.6.24_olpc/drivers/usb/storage/usb.c
4813 --- linux_2.6.24_org/drivers/usb/storage/usb.c 2008-02-15 20:11:09.000000000 +0000
4814 +++ linux_2.6.24_olpc/drivers/usb/storage/usb.c 2008-02-15 18:58:11.000000000 +0000
4815 @@ -244,7 +244,7 @@ static int storage_pre_reset(struct usb_
4819 -static int storage_post_reset(struct usb_interface *iface)
4820 +static void storage_post_reset(struct usb_interface *iface, int reset_resume)
4822 struct us_data *us = usb_get_intfdata(iface);
4824 @@ -256,8 +256,10 @@ static int storage_post_reset(struct usb
4825 /* FIXME: Notify the subdrivers that they need to reinitialize
4828 - mutex_unlock(&us->dev_mutex);
4830 + /* If this is a reset-resume then the pre_reset routine wasn't
4831 + * called, so we don't need to unlock the mutex. */
4832 + if (!reset_resume)
4833 + mutex_unlock(&us->dev_mutex);
4837 diff -purN linux_2.6.24_org/drivers/video/fbmem.c linux_2.6.24_olpc/drivers/video/fbmem.c
4838 --- linux_2.6.24_org/drivers/video/fbmem.c 2008-02-15 20:11:23.000000000 +0000
4839 +++ linux_2.6.24_olpc/drivers/video/fbmem.c 2008-02-15 18:58:42.000000000 +0000
4840 @@ -820,6 +820,53 @@ static void try_to_load(int fb)
4841 #endif /* CONFIG_KMOD */
4844 +fb_powerup(struct fb_info *info)
4848 + if (!info || info->state == FBINFO_STATE_RUNNING)
4851 + if (info->fbops->fb_powerup)
4852 + ret = info->fbops->fb_powerup(info);
4855 + acquire_console_sem();
4856 + fb_set_suspend(info, 0);
4857 + release_console_sem();
4864 +fb_powerdown(struct fb_info *info)
4868 + if (!info || info->state == FBINFO_STATE_SUSPENDED)
4871 + /* Tell everybody that the fbdev is going down */
4872 + acquire_console_sem();
4873 + fb_set_suspend(info, 1);
4874 + release_console_sem();
4876 + if (info->fbops->fb_powerdown)
4877 + ret = info->fbops->fb_powerdown(info);
4879 + /* If the power down failed, then un-notify */
4882 + acquire_console_sem();
4883 + fb_set_suspend(info, 0);
4884 + release_console_sem();
4891 fb_pan_display(struct fb_info *info, struct fb_var_screeninfo *var)
4893 struct fb_fix_screeninfo *fix = &info->fix;
4894 diff -purN linux_2.6.24_org/drivers/video/geode/display_gx.c linux_2.6.24_olpc/drivers/video/geode/display_gx.c
4895 --- linux_2.6.24_org/drivers/video/geode/display_gx.c 2008-02-15 20:11:23.000000000 +0000
4896 +++ linux_2.6.24_olpc/drivers/video/geode/display_gx.c 2008-02-15 18:58:41.000000000 +0000
4898 * Free Software Foundation; either version 2 of the License, or * (at your
4899 * option) any later version.
4902 +#include <linux/kernel.h>
4903 #include <linux/spinlock.h>
4904 #include <linux/fb.h>
4905 #include <linux/delay.h>
4907 #include <asm/div64.h>
4908 #include <asm/delay.h>
4909 +#include <asm/olpc.h>
4911 #include "geodefb.h"
4912 #include "display_gx.h"
4914 -#ifdef CONFIG_FB_GEODE_GX_SET_FBSIZE
4915 -unsigned int gx_frame_buffer_size(void)
4916 +static inline void rmwl(u32 val, u32 *reg)
4918 - return CONFIG_FB_GEODE_GX_FBSIZE;
4919 + u32 in = readl(reg);
4925 unsigned int gx_frame_buffer_size(void)
4930 + if (machine_is_olpc() && !olpc_has_vsa()) {
4932 + rdmsr(GLIU0_P2D_RO0, lo, hi);
4934 + /* Top page number */
4935 + val = ((hi & 0xff) << 12) | ((lo & 0xfff00000) >> 20);
4937 + val -= (lo & 0x000fffff); /* Subtract bottom page number */
4938 + val += 1; /* Adjust page count */
4939 + return (val << 12);
4943 /* FB size is reported by a virtual register */
4944 /* Virtual register class = 0x02 */
4945 /* VG_MEM_SIZE(512Kb units) = 0x00 */
4946 @@ -41,7 +59,6 @@ unsigned int gx_frame_buffer_size(void)
4947 val = (unsigned int)(inw(0xAC1E)) & 0xFFl;
4952 int gx_line_delta(int xres, int bpp)
4954 @@ -63,23 +80,23 @@ static void gx_set_mode(struct fb_info *
4955 gcfg = readl(par->dc_regs + DC_GENERAL_CFG);
4956 dcfg = readl(par->dc_regs + DC_DISPLAY_CFG);
4958 - /* Disable the timing generator. */
4959 - dcfg &= ~(DC_DCFG_TGEN);
4960 - writel(dcfg, par->dc_regs + DC_DISPLAY_CFG);
4962 - /* Wait for pending memory requests before disabling the FIFO load. */
4965 - /* Disable FIFO load and compression. */
4966 - gcfg &= ~(DC_GCFG_DFLE | DC_GCFG_CMPE | DC_GCFG_DECE);
4967 - writel(gcfg, par->dc_regs + DC_GENERAL_CFG);
4969 - /* Setup DCLK and its divisor. */
4970 - par->vid_ops->set_dclk(info);
4975 + /* Programming the clock is costly and ugly, so avoid if if we can */
4977 + if (par->curdclk != info->var.pixclock) {
4978 + /* Disable the timing generator. */
4979 + dcfg &= ~(DC_DCFG_TGEN);
4980 + writel(dcfg, par->dc_regs + DC_DISPLAY_CFG);
4982 + /* Wait for pending memory requests before disabling the FIFO load. */
4985 + /* Disable FIFO load and compression. */
4986 + gcfg &= ~(DC_GCFG_DFLE | DC_GCFG_CMPE | DC_GCFG_DECE);
4987 + writel(gcfg, par->dc_regs + DC_GENERAL_CFG);
4989 + /* Setup DCLK and its divisor. */
4990 + par->vid_ops->set_dclk(info);
4993 /* Clear all unused feature bits. */
4994 gcfg &= DC_GCFG_YUVM | DC_GCFG_VDSE;
4995 @@ -90,12 +107,13 @@ static void gx_set_mode(struct fb_info *
4996 gcfg |= (6 << DC_GCFG_DFHPEL_POS) | (5 << DC_GCFG_DFHPSL_POS) | DC_GCFG_DFLE;
4998 /* Framebuffer start offset. */
4999 - writel(0, par->dc_regs + DC_FB_ST_OFFSET);
5000 + rmwl(0, par->dc_regs + DC_FB_ST_OFFSET);
5002 /* Line delta and line buffer length. */
5003 - writel(info->fix.line_length >> 3, par->dc_regs + DC_GFX_PITCH);
5004 - writel(((info->var.xres * info->var.bits_per_pixel/8) >> 3) + 2,
5005 - par->dc_regs + DC_LINE_SIZE);
5006 + rmwl(info->fix.line_length >> 3, par->dc_regs + DC_GFX_PITCH);
5008 + rmwl(((info->var.xres * info->var.bits_per_pixel/8) >> 3) + 2,
5009 + par->dc_regs + DC_LINE_SIZE);
5012 /* Enable graphics and video data and unmask address lines. */
5013 @@ -134,17 +152,16 @@ static void gx_set_mode(struct fb_info *
5014 vblankend = vsyncend + info->var.upper_margin;
5017 - writel((hactive - 1) | ((htotal - 1) << 16), par->dc_regs + DC_H_ACTIVE_TIMING);
5018 - writel((hblankstart - 1) | ((hblankend - 1) << 16), par->dc_regs + DC_H_BLANK_TIMING);
5019 - writel((hsyncstart - 1) | ((hsyncend - 1) << 16), par->dc_regs + DC_H_SYNC_TIMING);
5021 - writel((vactive - 1) | ((vtotal - 1) << 16), par->dc_regs + DC_V_ACTIVE_TIMING);
5022 - writel((vblankstart - 1) | ((vblankend - 1) << 16), par->dc_regs + DC_V_BLANK_TIMING);
5023 - writel((vsyncstart - 1) | ((vsyncend - 1) << 16), par->dc_regs + DC_V_SYNC_TIMING);
5024 + rmwl((hactive - 1) | ((htotal - 1) << 16), par->dc_regs + DC_H_ACTIVE_TIMING);
5025 + rmwl((hblankstart - 1) | ((hblankend - 1) << 16), par->dc_regs + DC_H_BLANK_TIMING);
5026 + rmwl((hsyncstart - 1) | ((hsyncend - 1) << 16), par->dc_regs + DC_H_SYNC_TIMING);
5027 + rmwl((vactive - 1) | ((vtotal - 1) << 16), par->dc_regs + DC_V_ACTIVE_TIMING);
5028 + rmwl((vblankstart - 1) | ((vblankend - 1) << 16), par->dc_regs + DC_V_BLANK_TIMING);
5029 + rmwl((vsyncstart - 1) | ((vsyncend - 1) << 16), par->dc_regs + DC_V_SYNC_TIMING);
5031 /* Write final register values. */
5032 - writel(dcfg, par->dc_regs + DC_DISPLAY_CFG);
5033 - writel(gcfg, par->dc_regs + DC_GENERAL_CFG);
5034 + rmwl(dcfg, par->dc_regs + DC_DISPLAY_CFG);
5035 + rmwl(gcfg, par->dc_regs + DC_GENERAL_CFG);
5037 par->vid_ops->configure_display(info);
5039 diff -purN linux_2.6.24_org/drivers/video/geode/display_gx.h linux_2.6.24_olpc/drivers/video/geode/display_gx.h
5040 --- linux_2.6.24_org/drivers/video/geode/display_gx.h 2008-02-15 20:11:23.000000000 +0000
5041 +++ linux_2.6.24_olpc/drivers/video/geode/display_gx.h 2008-02-15 18:58:41.000000000 +0000
5042 @@ -20,6 +20,9 @@ extern struct geode_dc_ops gx_dc_ops;
5043 #define GLD_MSR_CONFIG 0xC0002001
5044 #define GLD_MSR_CONFIG_DM_FP 0x40
5046 +/* Used for memory dection on the OLPC */
5047 +#define GLIU0_P2D_RO0 0x10000029
5049 /* Display controller registers */
5051 #define DC_UNLOCK 0x00
5052 diff -purN linux_2.6.24_org/drivers/video/geode/geodefb.h linux_2.6.24_olpc/drivers/video/geode/geodefb.h
5053 --- linux_2.6.24_org/drivers/video/geode/geodefb.h 2008-02-15 20:11:23.000000000 +0000
5054 +++ linux_2.6.24_olpc/drivers/video/geode/geodefb.h 2008-02-15 18:58:41.000000000 +0000
5056 #ifndef __GEODEFB_H__
5057 #define __GEODEFB_H__
5059 +#define FB_POWER_STATE_OFF 0
5060 +#define FB_POWER_STATE_SUSPEND 1
5061 +#define FB_POWER_STATE_ON 2
5063 struct geodefb_info;
5065 struct geode_dc_ops {
5066 @@ -21,18 +25,24 @@ struct geode_dc_ops {
5068 struct geode_vid_ops {
5069 void (*set_dclk)(struct fb_info *);
5070 + unsigned int (*get_dclk)(struct fb_info *);
5071 void (*configure_display)(struct fb_info *);
5072 int (*blank_display)(struct fb_info *, int blank_mode);
5075 struct geodefb_par {
5077 + int fbactive; /* True if the current console is in KD_GRAPHICS mode */
5078 int panel_x; /* dimensions of an attached flat panel, non-zero => enable panel */
5080 + unsigned int curdclk; /* Used by GX to avoid unnessesary clock switching */
5081 void __iomem *dc_regs;
5082 void __iomem *vid_regs;
5083 + void __iomem *gp_regs;
5084 struct geode_dc_ops *dc_ops;
5085 struct geode_vid_ops *vid_ops;
5090 #endif /* !__GEODEFB_H__ */
5091 diff -purN linux_2.6.24_org/drivers/video/geode/geode_regs.h linux_2.6.24_olpc/drivers/video/geode/geode_regs.h
5092 --- linux_2.6.24_org/drivers/video/geode/geode_regs.h 1970-01-01 01:00:00.000000000 +0100
5093 +++ linux_2.6.24_olpc/drivers/video/geode/geode_regs.h 2008-02-15 18:58:41.000000000 +0000
5095 +/* This header file defines the registers and suspend/resume
5096 + structures for the Geode GX and LX. The lxfb driver defines
5097 + _GEODELX_ before including this file, which will unlock the
5098 + extra registers that are only valid for LX.
5101 +#ifndef _GEODE_REGS_H_
5102 +#define _GEODE_REGS_H_
5106 +#define GX_VP_MSR_PAD_SELECT 0xC0002011
5107 +#define LX_VP_MSR_PAD_SELECT 0x48000011
5109 +#define GEODE_MSR_GLCP_DOTPLL 0x4c000015
5111 +#define GLCP_DOTPLL_RESET (1 << 0)
5112 +#define GLCP_DOTPLL_BYPASS (1 << 15)
5113 +#define GLCP_DOTPLL_HALFPIX (1 << 24)
5114 +#define GLCP_DOTPLL_LOCK (1 << 25)
5117 +#define VP_FP_START 0x400
5122 +#define GP_REG_SIZE 0x7C
5123 +#define DC_REG_SIZE 0xF0
5124 +#define VP_REG_SIZE 0x158
5125 +#define FP_REG_SIZE 0x70
5129 +#define GP_REG_SIZE 0x50
5130 +#define DC_REG_SIZE 0x90
5131 +#define VP_REG_SIZE 0x138
5132 +#define FP_REG_SIZE 0x70
5136 +#define DC_PAL_SIZE 0x105
5137 +#define VP_COEFF_COUNT 512
5138 +#define DC_HFILT_SIZE 256
5139 +#define DC_VFILT_SIZE 256
5156 + unsigned char b[GP_REG_SIZE];
5158 + u32 dst_offset; /* 0x00 */
5159 + u32 src_offset; /* 0x04 */
5160 + u32 stride; /* 0x08 */
5161 + u32 wid_height; /* 0x0C */
5162 + u32 src_color_fg; /* 0x10 */
5163 + u32 src_color_bg; /* 0x14 */
5164 + u32 pat_color_0; /* 0x18 */
5165 + u32 pat_color_1; /* 0x1C */
5166 + u32 pat_color_2; /* 0x20 */
5167 + u32 pat_color_3; /* 0x24 */
5168 + u32 pat_color_4; /* 0x28 */
5169 + u32 pat_color_5; /* 0x2C */
5170 + u32 pat_data_0; /* 0x30 */
5171 + u32 pat_data_1; /* 0x34 */
5172 + u32 raster_mode; /* 0x38 */
5173 + u32 vector_mode; /* 0x3C */
5174 + u32 blt_mode; /* 0x40 */
5175 + u32 blit_status; /* 0x4C */
5176 + u32 hst_src; /* 0x48 */
5177 + u32 base_offset; /* 0x4C */
5180 + u32 cmd_top; /* 0x50 */
5181 + u32 cmd_bot; /* 0x54 */
5182 + u32 cmd_read; /* 0x58 */
5183 + u32 cmd_write; /* 0x5C */
5184 + u32 ch3_offset; /* 0x60 */
5185 + u32 ch3_mode_str; /* 0x64 */
5186 + u32 ch3_width; /* 0x68 */
5187 + u32 ch3_hsrc; /* 0x6C */
5188 + u32 lut_index; /* 0x70 */
5189 + u32 lut_data; /* 0x74 */
5190 + u32 int_cntrl; /* 0x78 */
5196 + unsigned char b[DC_REG_SIZE];
5199 + u32 unlock; /* 0x00 */
5200 + u32 gcfg; /* 0x04 */
5201 + u32 dcfg; /* 0x08 */
5202 + u32 arb; /* 0x0C */
5203 + u32 fb_st_offset; /* 0x10 */
5204 + u32 cb_st_offset; /* 0x14 */
5205 + u32 curs_st_offset; /* 0x18 */
5206 + u32 icon_st_offset; /* 0x1C */
5207 + u32 vid_y_st_offset; /* 0x20 */
5208 + u32 vid_u_st_offset; /* 0x24 */
5209 + u32 vid_v_st_offset; /* 0x28 */
5210 + u32 dctop; /* 0x2c */
5211 + u32 line_size; /* 0x30 */
5212 + u32 gfx_pitch; /* 0x34 */
5213 + u32 vid_yuv_pitch; /* 0x38 */
5214 + u32 rsvd2; /* 0x3C */
5215 + u32 h_active_timing; /* 0x40 */
5216 + u32 h_blank_timing; /* 0x44 */
5217 + u32 h_sync_timing; /* 0x48 */
5218 + u32 rsvd3; /* 0x4C */
5219 + u32 v_active_timing; /* 0x50 */
5220 + u32 v_blank_timing; /* 0x54 */
5221 + u32 v_sync_timing; /* 0x58 */
5222 + u32 fbactive; /* 0x5C */
5223 + u32 dc_cursor_x; /* 0x60 */
5224 + u32 dc_cursor_y; /* 0x64 */
5225 + u32 dc_icon_x; /* 0x68 */
5226 + u32 dc_line_cnt; /* 0x6C */
5227 + u32 rsvd5; /* 0x70 - palette address */
5228 + u32 rsvd6; /* 0x74 - palette data */
5229 + u32 dfifo_diag; /* 0x78 */
5230 + u32 cfifo_diag; /* 0x7C */
5231 + u32 dc_vid_ds_delta; /* 0x80 */
5232 + u32 gliu0_mem_offset; /* 0x84 */
5233 + u32 dv_ctl; /* 0x88 - added by LX */
5234 + u32 dv_acc; /* 0x8C */
5241 + u32 vbi_event_ctl;
5254 + u32 vid_even_y_st_offset; /* 0xD8 */
5255 + u32 vid_even_u_st_offset; /* 0xDC */
5256 + u32 vid_even_v_st_offset; /* 0xE0 */
5257 + u32 v_active_even_timing; /* 0xE4 */
5258 + u32 v_blank_even_timing; /* 0xE8 */
5259 + u32 v_sync_even_timing; /* 0xEC */
5265 + unsigned char b[VP_REG_SIZE];
5268 + u64 vcfg; /* 0x00 */
5269 + u64 dcfg; /* 0x08 */
5270 + u64 vx; /* 0x10 */
5271 + u64 vy; /* 0x18 */
5272 + u64 vs; /* 0x20 */
5273 + u64 vck; /* 0x28 */
5274 + u64 vcm; /* 0x30 */
5275 + u64 rsvd1; /* 0x38 - Gamma address*/
5276 + u64 rsvd2; /* 0x40 - Gamma data*/
5277 + u64 slr; /* 0x48 - LX only*/
5278 + u64 misc; /* 0x50 */
5279 + u64 ccs; /* 0x58 */
5280 + u64 vys; /* 0x60 */
5281 + u64 vxs; /* 0x68 */
5282 + u64 rsvd4; /* 0x70 */
5283 + u64 vdc; /* 0x78 */
5284 + u64 vco; /* 0x80 */
5285 + u64 crc; /* 0x88 */
5286 + u64 crc32; /* 0x90 */
5287 + u64 vde; /* 0x98 */
5288 + u64 cck; /* 0xA0 */
5289 + u64 ccm; /* 0xA8 */
5290 + u64 cc1; /* 0xB0 */
5291 + u64 cc2; /* 0xB8 */
5292 + u64 a1x; /* 0xC0 */
5293 + u64 a1y; /* 0xC8 */
5294 + u64 a1c; /* 0xD0 */
5295 + u64 a1t; /* 0xD8 */
5296 + u64 a2x; /* 0xE0 */
5297 + u64 a2y; /* 0xE8 */
5298 + u64 a2c; /* 0xF0 */
5299 + u64 a2t; /* 0xF8 */
5300 + u64 a3x; /* 0x100 */
5301 + u64 a3y; /* 0x108 */
5302 + u64 a3c; /* 0x110 */
5303 + u64 a3t; /* 0x118 */
5304 + u64 vrr; /* 0x120 */
5305 + u64 awt; /* 0x128 */
5306 + u64 vtm; /* 0x130 */
5308 + u64 vye; /* 0x138 */
5309 + u64 a1ye; /* 0x140 */
5310 + u32 a2ye; /* 0x148 */
5311 + u32 a3ye; /* 0x150 */
5317 + unsigned char b[FP_REG_SIZE];
5320 + u64 pt1; /* 0x400 */
5321 + u64 pt2; /* 0x408 */
5322 + u64 pm; /* 0x410 */
5323 + u64 dfc; /* 0x418 */
5324 + u64 blfsr; /* 0x420 */
5325 + u64 rlfsr; /* 0x428 */
5326 + u64 fmi; /* 0x430 */
5327 + u64 fmd; /* 0x438 */
5328 + u64 rsvd; /* 0x440 */
5329 + u64 dca; /* 0x448 */
5330 + u64 dmd; /* 0x450 */
5331 + u64 crc; /* 0x458 */
5332 + u64 fbb; /* 0x460 */
5333 + u64 crc32; /* 0x468 */
5337 + u32 pal[DC_PAL_SIZE];
5342 + u32 hcoeff[DC_HFILT_SIZE * 2];
5343 + u32 vcoeff[DC_VFILT_SIZE];
5345 + u32 vp_coeff[VP_COEFF_COUNT];
5350 diff -purN linux_2.6.24_org/drivers/video/geode/gxfb_core.c linux_2.6.24_olpc/drivers/video/geode/gxfb_core.c
5351 --- linux_2.6.24_org/drivers/video/geode/gxfb_core.c 2008-02-15 20:11:23.000000000 +0000
5352 +++ linux_2.6.24_olpc/drivers/video/geode/gxfb_core.c 2008-02-15 18:58:41.000000000 +0000
5354 #include <linux/fb.h>
5355 #include <linux/init.h>
5356 #include <linux/pci.h>
5357 +#include <linux/notifier.h>
5358 +#include <linux/vt_kern.h>
5359 +#include <linux/console.h>
5360 +#include <asm/uaccess.h>
5361 +#include <asm/olpc.h>
5363 #include "geodefb.h"
5364 #include "display_gx.h"
5365 #include "video_gx.h"
5367 +#define FBIOSGAMMA _IOW('F', 0x20, void *)
5368 +#define FBIOGGAMMA _IOW('F', 0x21, void *)
5372 +#define FBIODUMPGP _IOW('F', 0x22, void *)
5373 +#define FBIODUMPDC _IOW('F', 0x23, void *)
5374 +#define FBIODUMPVP _IOW('F', 0x24, void *)
5375 +#define FBIODUMPFP _IOW('F', 0x25, void *)
5379 static char *mode_option;
5380 +static int noclear;
5381 +struct fb_info *gxfb_info;
5383 /* Modes relevant to the GX (taken from modedb.c) */
5384 static const struct fb_videomode gx_modedb[] __initdata = {
5385 @@ -103,8 +122,20 @@ static const struct fb_videomode gx_mode
5386 { NULL, 85, 1600, 1200, 4357, 304, 64, 46, 1, 192, 3,
5387 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
5388 FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
5389 + /* 1200x900-75 - CRT timings for the OLPC mode */
5390 + { NULL, 75, 1200, 900, 8049, 104, 240, 29, 54, 136, 3,
5391 + 0, FB_VMODE_NONINTERLACED, 0 }
5395 +static const struct fb_videomode gx_dcon_modedb[] __initdata = {
5396 + /* The only mode the DCON has is 1200x900 */
5397 + { NULL, 50, 1200, 900, 17460, 24, 8, 4, 5, 8, 3,
5398 + 0, FB_VMODE_NONINTERLACED, 0 }
5403 static int gxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
5405 if (var->xres > 1600 || var->yres > 1200)
5406 @@ -137,7 +168,7 @@ static int gxfb_check_var(struct fb_var_
5410 -static int gxfb_set_par(struct fb_info *info)
5411 +int gxfb_set_par(struct fb_info *info)
5413 struct geodefb_par *par = info->par;
5415 @@ -204,16 +235,26 @@ static int gxfb_blank(int blank_mode, st
5416 return par->vid_ops->blank_display(info, blank_mode);
5421 static int __init gxfb_map_video_memory(struct fb_info *info, struct pci_dev *dev)
5423 struct geodefb_par *par = info->par;
5427 ret = pci_enable_device(dev);
5431 + ret = pci_request_region(dev, 1, "gxfb (graphics processor)");
5435 + par->gp_regs = ioremap(pci_resource_start(dev, 1),
5436 + pci_resource_len(dev, 1));
5437 + if (!par->gp_regs)
5440 ret = pci_request_region(dev, 3, "gxfb (video processor)");
5443 @@ -232,36 +273,118 @@ static int __init gxfb_map_video_memory(
5444 ret = pci_request_region(dev, 0, "gxfb (framebuffer)");
5447 - if ((fb_len = gx_frame_buffer_size()) < 0)
5450 + /* If the fbsize wasn't specified then try to probe it */
5453 + fbsize = gx_frame_buffer_size();
5458 info->fix.smem_start = pci_resource_start(dev, 0);
5459 - info->fix.smem_len = fb_len;
5460 + info->fix.smem_len = fbsize;
5461 info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len);
5462 if (!info->screen_base)
5465 - /* Set the 16MB aligned base address of the graphics memory region
5466 + /* Set the 16MiB aligned base address of the graphics memory region
5467 * in the display controller */
5469 writel(info->fix.smem_start & 0xFF000000,
5470 par->dc_regs + DC_GLIU0_MEM_OFFSET);
5472 - dev_info(&dev->dev, "%d Kibyte of video memory at 0x%lx\n",
5473 + dev_info(&dev->dev, "%d KiB of video memory at 0x%lx\n",
5474 info->fix.smem_len / 1024, info->fix.smem_start);
5479 +static int gxfb_ioctl( struct fb_info *info, unsigned int cmd,
5480 + unsigned long arg)
5482 + unsigned int gamma[GXFB_GAMMA_DWORDS];
5483 + int ret = -EINVAL;
5484 + struct geodefb_par *par = info->par;
5489 + /* Read the gamma information from the user - 256 dwords */
5491 + if (copy_from_user(gamma, (void * __user) arg, GXFB_GAMMA_SIZE))
5494 + writel(0, par->vid_regs + GX_GAR);
5496 + /* Sequential writes to the data register will increment the
5497 + address automatically */
5499 + for(i = 0; i < GXFB_GAMMA_DWORDS; i++)
5500 + writel(gamma[i] & 0xFFFFFF, par->vid_regs + GX_GDR);
5502 + writel(readl(par->vid_regs + GX_MISC) & ~GX_MISC_GAM_EN,
5503 + par->vid_regs + GX_MISC);
5509 + if (readl(par->vid_regs + GX_MISC) & GX_MISC_GAM_EN)
5512 + memset(gamma, 0, GXFB_GAMMA_SIZE);
5513 + writel(0, par->vid_regs + GX_GAR);
5515 + for(i = 0; i < GXFB_GAMMA_DWORDS;i++)
5516 + gamma[i] = readl(par->vid_regs + GX_GDR);
5518 + if (copy_to_user((void * __user) arg, gamma, GXFB_GAMMA_SIZE))
5528 + dump_regs(info, 0);
5533 + dump_regs(info, 1);
5538 + dump_regs(info, 2);
5543 + dump_regs(info, 3);
5551 static struct fb_ops gxfb_ops = {
5552 .owner = THIS_MODULE,
5553 .fb_check_var = gxfb_check_var,
5554 .fb_set_par = gxfb_set_par,
5555 .fb_setcolreg = gxfb_setcolreg,
5556 .fb_blank = gxfb_blank,
5557 + .fb_ioctl = gxfb_ioctl,
5558 /* No HW acceleration for now. */
5559 .fb_fillrect = cfb_fillrect,
5560 .fb_copyarea = cfb_copyarea,
5561 .fb_imageblit = cfb_imageblit,
5562 + .fb_powerdown = gxfb_powerdown,
5563 + .fb_powerup = gxfb_powerup,
5566 static struct fb_info * __init gxfb_init_fbinfo(struct device *dev)
5567 @@ -303,23 +426,86 @@ static struct fb_info * __init gxfb_init
5571 -static int __init gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
5572 +static int gxfb_console_notify(struct notifier_block *self,
5573 + unsigned long action, void *data)
5575 + if (gxfb_info != NULL) {
5576 + struct geodefb_par *par = gxfb_info->par;
5577 + par->fbactive = (action == CONSOLE_EVENT_SWITCH_TEXT) ? 0 : 1;
5583 +static struct notifier_block gxfb_console_notifier = {
5584 + .notifier_call = gxfb_console_notify
5589 +static int gxfb_suspend(struct pci_dev *pdev, pm_message_t state)
5591 + struct fb_info *info = pci_get_drvdata(pdev);
5592 + struct geodefb_par *par = info->par;
5594 + if (pdev->dev.power.power_state.event == state.event)
5597 + if (state.event == PM_EVENT_SUSPEND) {
5599 + acquire_console_sem();
5600 + gxfb_powerdown(info);
5602 + par->state = FB_POWER_STATE_OFF;
5603 + fb_set_suspend(info, 1);
5605 + release_console_sem();
5608 + pdev->dev.power.power_state = state;
5612 +static int gxfb_resume(struct pci_dev *pdev)
5614 + struct fb_info *info = pci_get_drvdata(pdev);
5616 + acquire_console_sem();
5618 + /* Turn the engine completely on */
5620 + if (gxfb_powerup(info))
5621 + printk(KERN_ERR "gxfb: Powerup failed\n");
5623 + fb_set_suspend(info, 0);
5624 + release_console_sem();
5626 + pdev->dev.power.power_state = PMSG_ON;
5631 +static int __init gxfb_probe(struct pci_dev *pdev,
5632 + const struct pci_device_id *id)
5634 struct geodefb_par *par;
5635 - struct fb_info *info;
5639 - info = gxfb_init_fbinfo(&pdev->dev);
5641 + struct fb_videomode *modedb_ptr;
5644 + gxfb_info = gxfb_init_fbinfo(&pdev->dev);
5645 + if (gxfb_info == NULL)
5649 + par = gxfb_info->par;
5651 /* GX display controller and GX video device. */
5652 par->dc_ops = &gx_dc_ops;
5653 par->vid_ops = &gx_vid_ops;
5655 - if ((ret = gxfb_map_video_memory(info, pdev)) < 0) {
5656 + if ((ret = gxfb_map_video_memory(gxfb_info, pdev)) < 0) {
5657 dev_err(&pdev->dev, "failed to map frame buffer or controller registers\n");
5660 @@ -333,32 +519,60 @@ static int __init gxfb_probe(struct pci_
5662 par->enable_crt = 1;
5664 - ret = fb_find_mode(&info->var, info, mode_option,
5665 - gx_modedb, ARRAY_SIZE(gx_modedb), NULL, 16);
5666 + /* Get the current dotclock */
5668 + par->curdclk = (par->vid_ops->get_dclk) ? par->vid_ops->get_dclk(gxfb_info) : 0;
5670 + /* We need to determine a display mode right now, so we will
5671 + * check to see if the DCON was previously detected by the BIOS
5672 + * and use that to make our mode database decision.
5675 + modedb_ptr = (struct fb_videomode *) gx_modedb;
5676 + modedb_size = ARRAY_SIZE(gx_modedb);
5679 + if (olpc_has_dcon()) {
5680 + modedb_ptr = (struct fb_videomode *) gx_dcon_modedb;
5681 + modedb_size = ARRAY_SIZE(gx_dcon_modedb);
5685 + ret = fb_find_mode(&gxfb_info->var, gxfb_info, mode_option,
5686 + modedb_ptr, modedb_size, NULL, 16);
5688 if (ret == 0 || ret == 4) {
5689 dev_err(&pdev->dev, "could not find valid video mode\n");
5694 + /* Clear the screen of garbage, unless noclear was specified,
5695 + * in which case we assume the user knows what he is doing */
5698 + memset_io(gxfb_info->screen_base, 0, gxfb_info->fix.smem_len);
5700 + gxfb_check_var(&gxfb_info->var, gxfb_info);
5701 + gxfb_set_par(gxfb_info);
5703 + /* We are powered up */
5704 + par->state = FB_POWER_STATE_ON;
5706 - /* Clear the frame buffer of garbage. */
5707 - memset_io(info->screen_base, 0, info->fix.smem_len);
5709 - gxfb_check_var(&info->var, info);
5710 - gxfb_set_par(info);
5711 + console_event_register(&gxfb_console_notifier);
5713 - if (register_framebuffer(info) < 0) {
5714 + if (register_framebuffer(gxfb_info) < 0) {
5718 - pci_set_drvdata(pdev, info);
5719 - printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, info->fix.id);
5720 + pci_set_drvdata(pdev, gxfb_info);
5721 + printk(KERN_INFO "fb%d: %s frame buffer device\n", gxfb_info->node, gxfb_info->fix.id);
5725 - if (info->screen_base) {
5726 - iounmap(info->screen_base);
5727 + if (gxfb_info->screen_base) {
5728 + iounmap(gxfb_info->screen_base);
5729 pci_release_region(pdev, 0);
5731 if (par->vid_regs) {
5732 @@ -370,8 +584,9 @@ static int __init gxfb_probe(struct pci_
5733 pci_release_region(pdev, 2);
5737 - framebuffer_release(info);
5739 + framebuffer_release(gxfb_info);
5744 @@ -397,9 +612,7 @@ static void gxfb_remove(struct pci_dev *
5747 static struct pci_device_id gxfb_id_table[] = {
5748 - { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_GX_VIDEO,
5749 - PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
5751 + { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_GX_VIDEO) },
5755 @@ -410,22 +623,30 @@ static struct pci_driver gxfb_driver = {
5756 .id_table = gxfb_id_table,
5757 .probe = gxfb_probe,
5758 .remove = gxfb_remove,
5760 + .suspend = gxfb_suspend,
5761 + .resume = gxfb_resume
5766 -static int __init gxfb_setup(char *options)
5768 +static int __init gxfb_setup(char *options) {
5772 if (!options || !*options)
5775 - while ((opt = strsep(&options, ",")) != NULL) {
5776 + while((opt = strsep(&options, ",")) != NULL) {
5780 - mode_option = opt;
5781 + if (!strncmp(opt, "fbsize:", 7))
5782 + fbsize = simple_strtoul(opt+7, NULL, 0);
5783 + else if (!strcmp(opt, "noclear"))
5786 + mode_option = opt;
5790 @@ -444,7 +665,6 @@ static int __init gxfb_init(void)
5792 return pci_register_driver(&gxfb_driver);
5795 static void __exit gxfb_cleanup(void)
5797 pci_unregister_driver(&gxfb_driver);
5798 @@ -456,5 +676,8 @@ module_exit(gxfb_cleanup);
5799 module_param(mode_option, charp, 0);
5800 MODULE_PARM_DESC(mode_option, "video mode (<x>x<y>[-<bpp>][@<refr>])");
5802 +module_param(fbsize, int, 0);
5803 +MODULE_PARM_DESC(fbsize, "video memory size");
5805 MODULE_DESCRIPTION("Framebuffer driver for the AMD Geode GX");
5806 MODULE_LICENSE("GPL");
5807 diff -purN linux_2.6.24_org/drivers/video/geode/Kconfig linux_2.6.24_olpc/drivers/video/geode/Kconfig
5808 --- linux_2.6.24_org/drivers/video/geode/Kconfig 2008-02-15 20:11:23.000000000 +0000
5809 +++ linux_2.6.24_olpc/drivers/video/geode/Kconfig 2008-02-15 18:58:41.000000000 +0000
5810 @@ -38,26 +38,6 @@ config FB_GEODE_GX
5814 -config FB_GEODE_GX_SET_FBSIZE
5815 - bool "Manually specify the Geode GX framebuffer size"
5816 - depends on FB_GEODE_GX
5819 - If you want to manually specify the size of your GX framebuffer,
5820 - say Y here, otherwise say N to dynamically probe it.
5822 - Say N unless you know what you are doing.
5824 -config FB_GEODE_GX_FBSIZE
5825 - hex "Size of the GX framebuffer, in bytes"
5826 - depends on FB_GEODE_GX_SET_FBSIZE
5827 - default "0x1600000"
5829 - Specify the size of the GX framebuffer. Normally, you will
5830 - want this to be MB aligned. Common values are 0x80000 (8MB)
5831 - and 0x1600000 (16MB). Don't change this unless you know what
5835 tristate "AMD Geode GX1 framebuffer support (EXPERIMENTAL)"
5836 depends on FB && FB_GEODE && EXPERIMENTAL
5837 diff -purN linux_2.6.24_org/drivers/video/geode/lxfb_core.c linux_2.6.24_olpc/drivers/video/geode/lxfb_core.c
5838 --- linux_2.6.24_org/drivers/video/geode/lxfb_core.c 2008-02-15 20:11:23.000000000 +0000
5839 +++ linux_2.6.24_olpc/drivers/video/geode/lxfb_core.c 2008-02-15 18:58:41.000000000 +0000
5841 #include <linux/fb.h>
5842 #include <linux/init.h>
5843 #include <linux/pci.h>
5844 -#include <linux/uaccess.h>
5845 +#include <asm/uaccess.h>
5846 +#include <asm/olpc.h>
5850 @@ -35,186 +36,84 @@ static int fbsize;
5853 const struct fb_videomode geode_modedb[] __initdata = {
5855 - { NULL, 60, 640, 480, 39682, 48, 8, 25, 2, 88, 2,
5856 + /* 640x480-60 VESA */
5857 + { NULL, 60, 640, 480, 39682, 48, 16, 33, 10, 96, 2,
5858 + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
5859 + /* 640x480-75 VESA */
5860 + { NULL, 75, 640, 480, 31746, 120, 16, 16, 01, 64, 3,
5861 + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
5862 + /* 640x480-85 VESA */
5863 + { NULL, 85, 640, 480, 27777, 80, 56, 25, 01, 56, 3,
5864 + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
5865 + /* 800x600-60 VESA */
5866 + { NULL, 60, 800, 600, 25000, 88, 40, 23, 01, 128, 4,
5867 + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
5868 + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
5869 + /* 800x600-75 VESA */
5870 + { NULL, 75, 800, 600, 20202, 160, 16, 21, 01, 80, 3,
5871 + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
5872 + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
5873 + /* 800x600-85 VESA */
5874 + { NULL, 85, 800, 600, 17761, 152, 32, 27, 01, 64, 3,
5875 + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
5876 + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
5877 + /* 1024x768-60 VESA */
5878 + { NULL, 60, 1024, 768, 15384, 160, 24, 29, 3, 136, 6,
5879 + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
5880 + /* 1024x768-75 VESA */
5881 + { NULL, 75, 1024, 768, 12690, 176, 16, 28, 1, 96, 3,
5882 + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
5883 + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
5884 + /* 1024x768-85 VESA */
5885 + { NULL, 85, 1024, 768, 10582, 208, 48, 36, 1, 96, 3,
5886 + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
5887 + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
5888 + /* 1280x960-60 VESA */
5889 + { NULL, 60, 1280, 960, 9259, 312, 96, 36, 1, 112, 3,
5890 + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
5891 + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
5892 + /* 1280x960-85 VESA */
5893 + { NULL, 85, 1280, 960, 6734, 224, 64, 47, 1, 160, 3,
5894 + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
5895 + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
5896 + /* 1280x1024-60 VESA */
5897 + { NULL, 60, 1280, 1024, 9259, 248, 48, 38, 1, 112, 3,
5898 + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
5899 + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
5900 + /* 1280x1024-75 VESA */
5901 + { NULL, 75, 1280, 1024, 7407, 248, 16, 38, 1, 144, 3,
5902 + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
5903 + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
5904 + /* 1280x1024-85 VESA */
5905 + { NULL, 85, 1280, 1024, 6349, 224, 64, 44, 1, 160, 3,
5906 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
5907 - FB_VMODE_NONINTERLACED, 0 },
5909 - { NULL, 70, 640, 400, 39770, 40, 8, 28, 5, 96, 2,
5910 - FB_SYNC_HOR_HIGH_ACT,
5911 - FB_VMODE_NONINTERLACED, 0 },
5913 - { NULL, 70, 640, 480, 35014, 88, 24, 15, 2, 64, 3,
5914 - 0, FB_VMODE_NONINTERLACED, 0 },
5916 - { NULL, 72, 640, 480, 32102, 120, 16, 20, 1, 40, 3,
5917 - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
5918 - FB_VMODE_NONINTERLACED, 0 },
5920 - { NULL, 75, 640, 480, 31746, 120, 16, 16, 1, 64, 3,
5921 - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
5922 - FB_VMODE_NONINTERLACED, 0 },
5924 - { NULL, 85, 640, 480, 27780, 80, 56, 25, 1, 56, 3,
5925 - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
5926 - FB_VMODE_NONINTERLACED, 0 },
5928 - { NULL, 90, 640, 480, 26392, 96, 32, 22, 1, 64, 3,
5929 - 0, FB_VMODE_NONINTERLACED, 0 },
5931 - { NULL, 100, 640, 480, 23167, 104, 40, 25, 1, 64, 3,
5932 - 0, FB_VMODE_NONINTERLACED, 0 },
5934 - { NULL, 60, 640, 480, 39682, 48, 16, 25, 10, 88, 2,
5935 - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
5936 - FB_VMODE_NONINTERLACED, 0 },
5938 - { NULL, 56, 800, 600, 27901, 128, 24, 22, 1, 72, 2,
5939 - 0, FB_VMODE_NONINTERLACED, 0 },
5941 - { NULL, 60, 800, 600, 25131, 72, 32, 23, 1, 136, 4,
5942 - 0, FB_VMODE_NONINTERLACED, 0 },
5944 - { NULL, 70, 800, 600, 21873, 120, 40, 21, 4, 80, 3,
5945 - 0, FB_VMODE_NONINTERLACED, 0 },
5947 - { NULL, 72, 800, 600, 20052, 64, 56, 23, 37, 120, 6,
5948 - 0, FB_VMODE_NONINTERLACED, 0 },
5950 - { NULL, 75, 800, 600, 20202, 160, 16, 21, 1, 80, 3,
5951 - 0, FB_VMODE_NONINTERLACED, 0 },
5953 - { NULL, 85, 800, 600, 17790, 152, 32, 27, 1, 64, 3,
5954 - 0, FB_VMODE_NONINTERLACED, 0 },
5956 - { NULL, 90, 800, 600, 16648, 128, 40, 28, 1, 88, 3,
5957 - 0, FB_VMODE_NONINTERLACED, 0 },
5959 - { NULL, 100, 800, 600, 14667, 136, 48, 27, 1, 88, 3,
5960 - 0, FB_VMODE_NONINTERLACED, 0 },
5962 - { NULL, 60, 800, 600, 25131, 88, 40, 23, 1, 128, 4,
5963 - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
5964 - FB_VMODE_NONINTERLACED, 0 },
5966 - { NULL, 60, 1024, 768, 15385, 160, 24, 29, 3, 136, 6,
5967 - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
5968 - FB_VMODE_NONINTERLACED, 0 },
5970 - { NULL, 70, 1024, 768, 13346, 144, 24, 29, 3, 136, 6,
5971 - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
5972 - FB_VMODE_NONINTERLACED, 0 },
5974 - { NULL, 72, 1024, 768, 12702, 168, 56, 29, 4, 112, 3,
5975 - 0, FB_VMODE_NONINTERLACED, 0 },
5977 - { NULL, 75, 1024, 768, 12703, 176, 16, 28, 1, 96, 3,
5978 - 0, FB_VMODE_NONINTERLACED, 0 },
5980 - { NULL, 85, 1024, 768, 10581, 208, 48, 36, 1, 96, 3,
5981 - 0, FB_VMODE_NONINTERLACED, 0 },
5983 - { NULL, 90, 1024, 768, 9981, 176, 64, 37, 1, 112, 3,
5984 - 0, FB_VMODE_NONINTERLACED, 0 },
5985 - /* 1024x768-100 */
5986 - { NULL, 100, 1024, 768, 8825, 184, 72, 42, 1, 112, 3,
5987 - 0, FB_VMODE_NONINTERLACED, 0 },
5989 - { NULL, 60, 1024, 768, 15385, 160, 24, 29, 3, 136, 6,
5990 - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
5991 - FB_VMODE_NONINTERLACED, 0 },
5993 - { NULL, 60, 1152, 864, 12251, 184, 64, 27, 1, 120, 3,
5994 - 0, FB_VMODE_NONINTERLACED, 0 },
5996 - { NULL, 70, 1152, 864, 10254, 192, 72, 32, 8, 120, 3,
5997 - 0, FB_VMODE_NONINTERLACED, 0 },
5999 - { NULL, 72, 1152, 864, 9866, 200, 72, 33, 7, 128, 3,
6000 - 0, FB_VMODE_NONINTERLACED, 0 },
6002 - { NULL, 75, 1152, 864, 9259, 256, 64, 32, 1, 128, 3,
6003 - 0, FB_VMODE_NONINTERLACED, 0 },
6005 - { NULL, 85, 1152, 864, 8357, 200, 72, 37, 3, 128, 3,
6006 - 0, FB_VMODE_NONINTERLACED, 0 },
6008 - { NULL, 90, 1152, 864, 7719, 208, 80, 42, 9, 128, 3,
6009 - 0, FB_VMODE_NONINTERLACED, 0 },
6010 - /* 1152x864-100 */
6011 - { NULL, 100, 1152, 864, 6947, 208, 80, 48, 3, 128, 3,
6012 - 0, FB_VMODE_NONINTERLACED, 0 },
6014 - { NULL, 60, 1152, 864, 12251, 184, 64, 27, 1, 120, 3,
6015 - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
6016 - FB_VMODE_NONINTERLACED, 0 },
6017 - /* 1280x1024-60 */
6018 - { NULL, 60, 1280, 1024, 9262, 248, 48, 38, 1, 112, 3,
6019 - 0, FB_VMODE_NONINTERLACED, 0 },
6020 - /* 1280x1024-70 */
6021 - { NULL, 70, 1280, 1024, 7719, 224, 88, 38, 6, 136, 3,
6022 - 0, FB_VMODE_NONINTERLACED, 0 },
6023 - /* 1280x1024-72 */
6024 - { NULL, 72, 1280, 1024, 7490, 224, 88, 39, 7, 136, 3,
6025 - 0, FB_VMODE_NONINTERLACED, 0 },
6026 - /* 1280x1024-75 */
6027 - { NULL, 75, 1280, 1024, 7409, 248, 16, 38, 1, 144, 3,
6028 - 0, FB_VMODE_NONINTERLACED, 0 },
6029 - /* 1280x1024-85 */
6030 - { NULL, 85, 1280, 1024, 6351, 224, 64, 44, 1, 160, 3,
6031 - 0, FB_VMODE_NONINTERLACED, 0 },
6032 - /* 1280x1024-90 */
6033 - { NULL, 90, 1280, 1024, 5791, 240, 96, 51, 12, 144, 3,
6034 - 0, FB_VMODE_NONINTERLACED, 0 },
6035 - /* 1280x1024-100 */
6036 - { NULL, 100, 1280, 1024, 5212, 240, 96, 57, 6, 144, 3,
6037 - 0, FB_VMODE_NONINTERLACED, 0 },
6038 - /* 1280x1024-60 */
6039 - { NULL, 60, 1280, 1024, 9262, 248, 48, 38, 1, 112, 3,
6040 - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
6041 - FB_VMODE_NONINTERLACED, 0 },
6042 - /* 1600x1200-60 */
6043 + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
6044 + /* 1600x1200-60 VESA */
6045 { NULL, 60, 1600, 1200, 6172, 304, 64, 46, 1, 192, 3,
6046 - 0, FB_VMODE_NONINTERLACED, 0 },
6047 - /* 1600x1200-70 */
6048 - { NULL, 70, 1600, 1200, 5291, 304, 64, 46, 1, 192, 3,
6049 - 0, FB_VMODE_NONINTERLACED, 0 },
6050 - /* 1600x1200-72 */
6051 - { NULL, 72, 1600, 1200, 5053, 288, 112, 47, 13, 176, 3,
6052 - 0, FB_VMODE_NONINTERLACED, 0 },
6053 - /* 1600x1200-75 */
6054 + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
6055 + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
6056 + /* 1600x1200-75 VESA */
6057 { NULL, 75, 1600, 1200, 4938, 304, 64, 46, 1, 192, 3,
6058 - 0, FB_VMODE_NONINTERLACED, 0 },
6059 - /* 1600x1200-85 */
6060 + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
6061 + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
6062 + /* 1600x1200-85 VESA */
6063 { NULL, 85, 1600, 1200, 4357, 304, 64, 46, 1, 192, 3,
6064 - 0, FB_VMODE_NONINTERLACED, 0 },
6065 - /* 1600x1200-90 */
6066 - { NULL, 90, 1600, 1200, 3981, 304, 128, 60, 1, 176, 3,
6067 - 0, FB_VMODE_NONINTERLACED, 0 },
6068 - /* 1600x1200-100 */
6069 - { NULL, 100, 1600, 1200, 3563, 304, 128, 67, 1, 176, 3,
6070 - 0, FB_VMODE_NONINTERLACED, 0 },
6071 - /* 1600x1200-60 */
6072 - { NULL, 60, 1600, 1200, 6172, 304, 64, 46, 1, 192, 3,
6073 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
6074 - FB_VMODE_NONINTERLACED, 0 },
6075 - /* 1920x1440-60 */
6076 - { NULL, 60, 1920, 1440, 4273, 344, 128, 56, 1, 208, 3,
6077 - 0, FB_VMODE_NONINTERLACED, 0 },
6078 - /* 1920x1440-70 */
6079 - { NULL, 70, 1920, 1440, 3593, 360, 152, 55, 8, 208, 3,
6080 - 0, FB_VMODE_NONINTERLACED, 0 },
6081 - /* 1920x1440-72 */
6082 - { NULL, 72, 1920, 1440, 3472, 360, 152, 68, 4, 208, 3,
6083 - 0, FB_VMODE_NONINTERLACED, 0 },
6084 - /* 1920x1440-75 */
6085 - { NULL, 75, 1920, 1440, 3367, 352, 144, 56, 1, 224, 3,
6086 - 0, FB_VMODE_NONINTERLACED, 0 },
6087 - /* 1920x1440-85 */
6088 - { NULL, 85, 1920, 1440, 2929, 368, 152, 68, 1, 216, 3,
6089 - 0, FB_VMODE_NONINTERLACED, 0 },
6090 + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
6091 + /* 1200x900-75 - CRT timings for the OLPC mode */
6092 + { NULL, 75, 1200, 900, 8049, 104, 240, 29, 54, 136, 3,
6093 + 0, FB_VMODE_NONINTERLACED, 0 }
6097 +const struct fb_videomode olpc_dcon_modedb[] __initdata = {
6098 + /* The only mode the DCON has is 1200x900 */
6099 + { NULL, 50, 1200, 900, 17460, 24, 8, 4, 5, 8, 3,
6100 + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
6101 + FB_VMODE_NONINTERLACED, 0 }
6105 static int lxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
6107 if (var->xres > 1920 || var->yres > 1440)
6108 @@ -255,8 +154,7 @@ static int lxfb_set_par(struct fb_info *
6109 fb_alloc_cmap(&info->cmap, 1<<info->var.bits_per_pixel, 0);
6112 - info->fix.line_length = lx_get_pitch(info->var.xres,
6113 - info->var.bits_per_pixel);
6114 + info->fix.line_length = lx_get_pitch(info->var.xres, info->var.bits_per_pixel);
6118 @@ -371,24 +269,61 @@ static int __init lxfb_map_video_memory(
6119 writel(info->fix.smem_start & 0xFF000000,
6120 par->dc_regs + DC_PHY_MEM_OFFSET);
6122 - writel(0, par->dc_regs + DC_UNLOCK);
6124 dev_info(&dev->dev, "%d KB of video memory at 0x%lx\n",
6125 info->fix.smem_len / 1024, info->fix.smem_start);
6130 +static int lxfb_set_gamma(struct fb_info *info, void * __user data)
6132 + unsigned int gamma[LXFB_GAMMA_DWORDS];
6134 + if (copy_from_user(gamma, data, LXFB_GAMMA_SIZE))
6137 + lx_set_gamma(info, gamma, LXFB_GAMMA_SIZE);
6141 +static int lxfb_get_gamma(struct fb_info *info, void * __user data)
6143 + unsigned int gamma[LXFB_GAMMA_DWORDS];
6144 + memset(gamma, 0, sizeof(gamma));
6146 + lx_get_gamma(info, gamma, LXFB_GAMMA_DWORDS);
6148 + return copy_to_user(data, gamma, LXFB_GAMMA_SIZE) ?
6152 +static int lxfb_ioctl( struct fb_info *info, unsigned int cmd,
6153 + unsigned long arg)
6157 + return lxfb_set_gamma(info, (void * __user) arg);
6160 + return lxfb_get_gamma(info, (void * __user) arg);
6166 static struct fb_ops lxfb_ops = {
6167 .owner = THIS_MODULE,
6168 .fb_check_var = lxfb_check_var,
6169 .fb_set_par = lxfb_set_par,
6170 .fb_setcolreg = lxfb_setcolreg,
6171 .fb_blank = lxfb_blank,
6172 + .fb_ioctl = lxfb_ioctl,
6173 /* No HW acceleration for now. */
6174 .fb_fillrect = cfb_fillrect,
6175 .fb_copyarea = cfb_copyarea,
6176 .fb_imageblit = cfb_imageblit,
6177 + .fb_powerdown = lx_shutdown,
6178 + .fb_powerup = lx_powerup,
6181 static struct fb_info * __init lxfb_init_fbinfo(struct device *dev)
6182 @@ -431,6 +366,45 @@ static struct fb_info * __init lxfb_init
6188 +static int lxfb_suspend(struct pci_dev *pdev, pm_message_t state)
6190 + struct fb_info *info = pci_get_drvdata(pdev);
6192 + if (pdev->dev.power.power_state.event == state.event)
6195 + if (state.event == PM_EVENT_SUSPEND) {
6197 + acquire_console_sem();
6198 + lx_shutdown(info);
6199 + fb_set_suspend(info, 1);
6200 + release_console_sem();
6203 + pdev->dev.power.power_state = state;
6207 +static int lxfb_resume(struct pci_dev *pdev)
6209 + struct fb_info *info = pci_get_drvdata(pdev);
6211 + acquire_console_sem();
6213 + /* Turn the engine completely on */
6216 + fb_set_suspend(info, 0);
6217 + release_console_sem();
6219 + pdev->dev.power.power_state = PMSG_ON;
6225 static int __init lxfb_probe(struct pci_dev *pdev,
6226 const struct pci_device_id *id)
6228 @@ -467,6 +441,13 @@ static int __init lxfb_probe(struct pci_
6229 modedb_ptr = (struct fb_videomode *) geode_modedb;
6230 modedb_size = ARRAY_SIZE(geode_modedb);
6233 + if (olpc_has_dcon()) {
6234 + modedb_ptr = (struct fb_videomode *) olpc_dcon_modedb;
6235 + modedb_size = ARRAY_SIZE(olpc_dcon_modedb);
6239 ret = fb_find_mode(&info->var, info, mode_option,
6240 modedb_ptr, modedb_size, NULL, 16);
6242 @@ -556,6 +537,10 @@ static struct pci_driver lxfb_driver = {
6243 .id_table = lxfb_id_table,
6244 .probe = lxfb_probe,
6245 .remove = lxfb_remove,
6247 + .suspend = lxfb_suspend,
6248 + .resume = lxfb_resume
6253 diff -purN linux_2.6.24_org/drivers/video/geode/lxfb.h linux_2.6.24_olpc/drivers/video/geode/lxfb.h
6254 --- linux_2.6.24_org/drivers/video/geode/lxfb.h 2008-02-15 20:11:23.000000000 +0000
6255 +++ linux_2.6.24_olpc/drivers/video/geode/lxfb.h 2008-02-15 18:58:41.000000000 +0000
6256 @@ -25,10 +25,23 @@ void lx_set_mode(struct fb_info *);
6257 void lx_get_gamma(struct fb_info *, unsigned int *, int);
6258 void lx_set_gamma(struct fb_info *, unsigned int *, int);
6259 unsigned int lx_framebuffer_size(void);
6260 +int lx_shutdown(struct fb_info *);
6261 +int lx_powerup(struct fb_info *);
6262 int lx_blank_display(struct fb_info *, int);
6263 void lx_set_palette_reg(struct fb_info *, unsigned int, unsigned int,
6264 unsigned int, unsigned int);
6268 +/* ioctl() defines */
6270 +#define FBIOSGAMMA _IOW('F', 0x20, void *)
6271 +#define FBIOGGAMMA _IOW('F', 0x21, void *)
6273 +/* General definitions */
6274 +#define LXFB_GAMMA_DWORDS 256 /* number of dwords in the gamma ram */
6275 +#define LXFB_GAMMA_SIZE (LXFB_GAMMA_DWORDS * sizeof(unsigned int))
6279 #define MSR_LX_GLD_CONFIG 0x48002001
6280 @@ -127,7 +140,7 @@ void lx_set_palette_reg(struct fb_info *
6282 #define DC_GFX_SCALE 0x90
6283 #define DC_IRQ_FILT_CTL 0x94
6285 +#define DC_IRQFILT_H_FILT_SEL 0x00000400
6288 #define DC_IRQ_MASK (1 << 0)
6289 diff -purN linux_2.6.24_org/drivers/video/geode/lxfb_ops.c linux_2.6.24_olpc/drivers/video/geode/lxfb_ops.c
6290 --- linux_2.6.24_org/drivers/video/geode/lxfb_ops.c 2008-02-15 20:11:23.000000000 +0000
6291 +++ linux_2.6.24_olpc/drivers/video/geode/lxfb_ops.c 2008-02-15 18:58:41.000000000 +0000
6293 #include <linux/kernel.h>
6294 #include <linux/errno.h>
6295 #include <linux/fb.h>
6296 -#include <linux/uaccess.h>
6297 -#include <linux/delay.h>
6298 +#include <asm/uaccess.h>
6299 +#include <asm/delay.h>
6300 +#include <asm/olpc.h>
6305 +#include "geode_regs.h"
6308 * Support panel scaling
6310 @@ -290,6 +294,19 @@ unsigned int lx_framebuffer_size(void)
6315 + if (machine_is_olpc() && !olpc_has_vsa()) {
6317 + rdmsr(MSR_LX_GLIU0_P2D_RO0, lo, hi);
6319 + /* Top page number */
6320 + val = ((hi & 0xff) << 12) | ((lo & 0xfff00000) >> 20);
6321 + val -= (lo & 0x000fffff); /* Subtract bottom page number */
6322 + val += 1; /* Adjust page count */
6323 + return (val << 12);
6327 /* The frame buffer size is reported by a VSM in VSA II */
6328 /* Virtual Register Class = 0x02 */
6329 /* VG_MEM_SIZE (1MB units) = 0x00 */
6330 @@ -301,6 +318,34 @@ unsigned int lx_framebuffer_size(void)
6334 +void lx_set_gamma(struct fb_info *info, unsigned int *gamma, int len)
6337 + struct lxfb_par *par = info->par;
6339 + writel(0, par->df_regs + DF_PAR);
6341 + /* Sequential writes to the data register will increment the
6342 + address automatically */
6344 + for(i = 0; i < len; i++)
6345 + writel(gamma[i] & 0xFFFFFF, par->df_regs + DF_PDR);
6347 + writel(readl(par->df_regs + DF_MISC) & ~DF_MISC_GAM_BYPASS,
6348 + par->df_regs + DF_MISC);
6351 +void lx_get_gamma(struct fb_info *info, unsigned int *gamma, int len)
6354 + struct lxfb_par *par = info->par;
6356 + writel(0, par->df_regs + DF_PAR);
6358 + for(i = 0; i < len;i++)
6359 + gamma[i] = readl(par->df_regs + DF_PDR);
6362 void lx_set_mode(struct fb_info *info)
6364 struct lxfb_par *par = info->par;
6365 @@ -313,6 +358,7 @@ void lx_set_mode(struct fb_info *info)
6366 int vactive, vblankstart, vsyncstart, vsyncend, vblankend, vtotal;
6368 /* Unlock the DC registers */
6369 + readl(par->dc_regs + DC_UNLOCK);
6370 writel(DC_UNLOCK_CODE, par->dc_regs + DC_UNLOCK);
6372 lx_graphics_disable(info);
6373 @@ -483,54 +529,408 @@ void lx_set_palette_reg(struct fb_info *
6374 writel(val, par->dc_regs + DC_PAL_DATA);
6377 +static int lx_blank_mode = FB_BLANK_UNBLANK;
6379 int lx_blank_display(struct fb_info *info, int blank_mode)
6381 struct lxfb_par *par = info->par;
6383 - int blank, hsync, vsync;
6386 + if (blank_mode == lx_blank_mode)
6389 + writel(DC_UNLOCK_CODE, par->dc_regs + DC_UNLOCK);
6391 + if (lx_blank_mode == FB_BLANK_POWERDOWN) {
6392 + val = readl(par->df_regs + DF_FP_PM);
6393 + writel(val | DF_FP_PM_P, par->df_regs + DF_FP_PM);
6394 + val = readl(par->df_regs + DF_MISC) & ~DF_MISC_DAC_PWRDN;
6395 + writel(val, par->df_regs + DF_MISC);
6397 + val = readl(par->dc_regs + DC_GENERAL_CFG) | DC_GCFG_DFLE;
6398 + writel(val, par->dc_regs + DC_GENERAL_CFG);
6400 + val = readl(par->dc_regs + DC_DISPLAY_CFG) | DC_DCFG_TGEN;
6401 + writel(val, par->dc_regs + DC_DISPLAY_CFG);
6404 + dcfg = readl(par->df_regs + DF_DISPLAY_CFG);
6406 /* CRT power saving modes. */
6407 switch (blank_mode) {
6408 case FB_BLANK_UNBLANK:
6409 - blank = 0; hsync = 1; vsync = 1;
6410 + dcfg |= DF_DCFG_CRT_EN | DF_DCFG_HSYNC_EN | DF_DCFG_VSYNC_EN;
6411 + dcfg |= DF_DCFG_DAC_BL_EN;
6413 case FB_BLANK_NORMAL:
6414 - blank = 1; hsync = 1; vsync = 1;
6415 + dcfg |= DF_DCFG_CRT_EN | DF_DCFG_HSYNC_EN | DF_DCFG_VSYNC_EN;
6416 + dcfg |= DF_DCFG_DAC_BL_EN;
6418 case FB_BLANK_VSYNC_SUSPEND:
6419 - blank = 1; hsync = 1; vsync = 0;
6420 + dcfg |= DF_DCFG_CRT_EN | DF_DCFG_HSYNC_EN | DF_DCFG_DAC_BL_EN;
6421 + dcfg &= ~DF_DCFG_VSYNC_EN;
6423 case FB_BLANK_HSYNC_SUSPEND:
6424 - blank = 1; hsync = 0; vsync = 1;
6425 + dcfg |= DF_DCFG_CRT_EN | DF_DCFG_VSYNC_EN | DF_DCFG_DAC_BL_EN;
6426 + dcfg &= ~DF_DCFG_HSYNC_EN;
6428 case FB_BLANK_POWERDOWN:
6429 - blank = 1; hsync = 0; vsync = 0;
6430 + dcfg &= ~DF_DCFG_DAC_BL_EN;
6431 + dcfg &= ~(DF_DCFG_CRT_EN | DF_DCFG_HSYNC_EN | DF_DCFG_VSYNC_EN);
6434 + writel(0, par->dc_regs + DC_UNLOCK);
6438 - dcfg = readl(par->df_regs + DF_DISPLAY_CFG);
6439 - dcfg &= ~(DF_DCFG_DAC_BL_EN
6440 - | DF_DCFG_HSYNC_EN | DF_DCFG_VSYNC_EN);
6442 - dcfg |= DF_DCFG_DAC_BL_EN;
6444 - dcfg |= DF_DCFG_HSYNC_EN;
6446 - dcfg |= DF_DCFG_VSYNC_EN;
6447 - writel(dcfg, par->df_regs + DF_DISPLAY_CFG);
6448 + /* Turn off the engine when we are in power down mode */
6449 + if (blank_mode == FB_BLANK_POWERDOWN) {
6450 + val = readl(par->df_regs + DF_MISC) | DF_MISC_DAC_PWRDN;
6451 + writel(val, par->df_regs + DF_MISC);
6453 + val = readl(par->dc_regs + DC_DISPLAY_CFG);
6454 + val &= ~DC_DCFG_TGEN;
6455 + writel(val, par->dc_regs + DC_DISPLAY_CFG);
6459 + val = readl(par->dc_regs + DC_GENERAL_CFG) & ~DC_GCFG_DFLE;
6460 + writel(val, par->dc_regs + DC_GENERAL_CFG);
6462 + val = readl(par->df_regs + DF_FP_PM);
6463 + writel(val & ~DF_FP_PM_P, par->df_regs + DF_FP_PM);
6466 + writel(0, par->dc_regs + DC_UNLOCK);
6468 + lx_blank_mode = blank_mode;
6472 +static struct geoderegs saved_regs;
6474 +static void lx_save_regs(struct fb_info *info, struct geoderegs *regs)
6476 + struct lxfb_par *par = info->par;
6480 + /* Wait for the command buffer to empty */
6481 + while(!(readl(par->gp_regs + 0x44) & (1 << 4)));
6483 + /* Unlock the DC */
6484 + writel(DC_UNLOCK_CODE, par->dc_regs + DC_UNLOCK);
6486 + rdmsrl(MSR_LX_DF_PADSEL, regs->msr.padsel);
6487 + rdmsrl(MSR_LX_GLCP_DOTPLL, regs->msr.dotpll);
6488 + rdmsrl(MSR_LX_DF_GLCONFIG, regs->msr.dfglcfg);
6489 + rdmsrl(MSR_LX_DC_SPARE, regs->msr.dcspare);
6491 + writel(0x4758, par->dc_regs + 0x00);
6493 + memcpy(regs->gp.b, par->gp_regs, GP_REG_SIZE);
6494 + memcpy(regs->dc.b, par->dc_regs, DC_REG_SIZE);
6495 + memcpy(regs->vp.b, par->df_regs, VP_REG_SIZE);
6496 + memcpy(regs->fp.b, par->df_regs + VP_FP_START, FP_REG_SIZE);
6498 + /* Save the palette */
6499 + writel(0, par->dc_regs + 0x70);
6500 /* Power on/off flat panel */
6501 + for(i = 0; i < DC_PAL_SIZE; i++)
6502 + regs->pal[i] = readl(par->dc_regs + 0x74);
6504 - if (par->output & OUTPUT_PANEL) {
6505 - fp_pm = readl(par->df_regs + DF_FP_PM);
6506 - if (blank_mode == FB_BLANK_POWERDOWN)
6507 - fp_pm &= ~DF_FP_PM_P;
6509 - fp_pm |= DF_FP_PM_P;
6510 - writel(fp_pm, par->df_regs + DF_FP_PM);
6511 + /* save the filter coefficients */
6513 + filt = readl(par->dc_regs + 0x94);
6514 + filt |= DC_IRQFILT_H_FILT_SEL;
6516 + for(i = 0; i < DC_HFILT_SIZE; i++) {
6517 + writel((filt & 0xFFFFFF00) | i, par->dc_regs + 0x94);
6518 + regs->hcoeff[i << 1] = readl(par->dc_regs + 0x98);
6519 + regs->hcoeff[(i << 1) + 1] = readl(par->dc_regs + 0x9c);
6522 + filt &= ~DC_IRQFILT_H_FILT_SEL;
6524 + for(i = 0; i < DC_VFILT_SIZE; i++) {
6525 + writel((filt & 0xFFFFFF00) | i, par->dc_regs + 0x94);
6526 + regs->vcoeff[i] = readl(par->dc_regs + 0x98);
6529 + /* Save the vg filter coefficients */
6530 + for(i = 0; i < VP_COEFF_COUNT; i++)
6531 + regs->vp_coeff[i] =
6532 + readl(par->df_regs + 0x1000 + (i << 2));
6534 + /* Save the VP gamma */
6536 + writel(0, par->df_regs + 0x38);
6538 + for(i = 0; i <= 0xFF; i++)
6539 + regs->gamma[i] = readl(par->df_regs + 0x40);
6542 +static void lx_restore_dc(struct lxfb_par *par, struct geoderegs *regs)
6547 + /* Unlock the registers */
6548 + writel(DC_UNLOCK_CODE, par->dc_regs + 0x00);
6550 + /* Restore the framebuffer offset */
6551 + writel(regs->dc.r.gliu0_mem_offset, par->dc_regs + 0x84);
6553 + /* Blank the configuration registers while we restore */
6554 + writel(0, par->dc_regs + 0x04);
6555 + writel(0, par->dc_regs + 0x08);
6557 + /* Restore the bulk of the registers */
6559 + writel(regs->dc.r.arb, par->dc_regs + 0x0C);
6560 + writel(regs->dc.r.fb_st_offset, par->dc_regs + 0x10);
6561 + writel(regs->dc.r.cb_st_offset, par->dc_regs + 0x14);
6562 + writel(regs->dc.r.curs_st_offset, par->dc_regs + 0x18);
6566 + writel(regs->dc.r.vid_y_st_offset, par->dc_regs + 0x20);
6567 + writel(regs->dc.r.vid_u_st_offset, par->dc_regs + 0x24);
6568 + writel(regs->dc.r.vid_v_st_offset, par->dc_regs + 0x28);
6570 + writel(regs->dc.r.dctop, par->dc_regs + 0x2c);
6571 + writel(regs->dc.r.line_size, par->dc_regs + 0x30);
6572 + writel(regs->dc.r.gfx_pitch, par->dc_regs + 0x34);
6573 + writel(regs->dc.r.vid_yuv_pitch, par->dc_regs + 0x38);
6574 + writel(regs->dc.r.h_active_timing, par->dc_regs + 0x40);
6575 + writel(regs->dc.r.h_blank_timing, par->dc_regs + 0x44);
6576 + writel(regs->dc.r.h_sync_timing, par->dc_regs + 0x48);
6577 + writel(regs->dc.r.v_active_timing, par->dc_regs + 0x50);
6578 + writel(regs->dc.r.v_blank_timing, par->dc_regs + 0x54);
6579 + writel(regs->dc.r.v_sync_timing, par->dc_regs + 0x58);
6580 + writel(regs->dc.r.fbactive, par->dc_regs + 0x5c);
6581 + writel(regs->dc.r.dc_cursor_x, par->dc_regs + 0x60);
6582 + writel(regs->dc.r.dc_cursor_y, par->dc_regs + 0x64);
6584 + /* skip 0x68, 0x6c, 0x70, 0x74, 0x78, 0x7c */
6586 + writel(regs->dc.r.dc_vid_ds_delta, par->dc_regs + 0x80);
6588 + /* 0x84 was written above */
6590 + writel(regs->dc.r.dv_ctl | 0x01, par->dc_regs + 0x88);
6591 + writel(regs->dc.r.gfx_scale, par->dc_regs + 0x90);
6592 + writel(regs->dc.r.irq_filt_ctl, par->dc_regs + 0x94);
6594 + /* skip 0x98, 0x9c */
6596 + writel(regs->dc.r.vbi_event_ctl, par->dc_regs + 0xA0);
6597 + writel(regs->dc.r.vbi_odd_ctl, par->dc_regs + 0xA4);
6598 + writel(regs->dc.r.vbi_hor, par->dc_regs + 0xA8);
6599 + writel(regs->dc.r.vbi_ln_odd, par->dc_regs + 0xAC);
6600 + writel(regs->dc.r.vbi_ln_event, par->dc_regs + 0xB0);
6601 + writel(regs->dc.r.vbi_pitch, par->dc_regs + 0xB4);
6602 + writel(regs->dc.r.clr_key, par->dc_regs + 0xB8);
6603 + writel(regs->dc.r.clr_key_mask, par->dc_regs + 0xBC);
6604 + writel(regs->dc.r.clr_key_x, par->dc_regs + 0xC0);
6605 + writel(regs->dc.r.clr_key_y, par->dc_regs + 0xC4);
6606 + writel(regs->dc.r.irq, par->dc_regs + 0xC8);
6607 + writel(regs->dc.r.genlk_ctrl, par->dc_regs + 0xD4);
6608 + writel(regs->dc.r.vid_even_y_st_offset, par->dc_regs + 0xD8);
6609 + writel(regs->dc.r.vid_even_u_st_offset, par->dc_regs + 0xDC);
6610 + writel(regs->dc.r.vid_even_v_st_offset, par->dc_regs + 0xE0);
6611 + writel(regs->dc.r.v_active_even_timing, par->dc_regs + 0xE4);
6612 + writel(regs->dc.r.v_blank_even_timing, par->dc_regs + 0xE8);
6613 + writel(regs->dc.r.v_sync_even_timing, par->dc_regs + 0xEC);
6615 + /* Restore the palette */
6616 + writel(0, par->dc_regs + 0x70);
6618 + for(i = 0; i < DC_PAL_SIZE; i++)
6619 + writel(regs->pal[i], par->dc_regs + 0x74);
6621 + /* Restore the horizontal filter coefficients */
6622 + filt = readl(par->dc_regs + 0x94);
6623 + filt |= DC_IRQFILT_H_FILT_SEL;
6625 + for(i = 0; i < DC_HFILT_SIZE; i++) {
6626 + writel(((filt & 0xFFFFFF00) | i), par->dc_regs + 0x94);
6627 + writel(regs->hcoeff[i << 1], par->dc_regs + 0x98);
6628 + writel(regs->hcoeff[(i << 1) + 1], par->dc_regs + 0x9c);
6631 + filt &= ~DC_IRQFILT_H_FILT_SEL;
6633 + for(i = 0; i < DC_VFILT_SIZE; i++) {
6634 + writel(((filt & 0xFFFFFF00) | i), par->dc_regs + 0x94);
6635 + writel(regs->vcoeff[i], par->dc_regs + 0x98);
6638 + /* Turn on the dotpll */
6639 + lx_set_dotpll((u32) (regs->msr.dotpll >> 32));
6641 + /* Restore MSRs */
6642 + wrmsrl(MSR_LX_DC_SPARE, regs->msr.dcspare);
6644 + /* Restore the configuration registers */
6646 + writel(regs->dc.r.dcfg, par->dc_regs + 0x08);
6647 + writel(regs->dc.r.gcfg, par->dc_regs + 0x04);
6649 + /* Lock the DC again */
6650 + writel(0, par->dc_regs + 0x00);
6653 +static void lx_restore_vp(struct lxfb_par *par, struct geoderegs *regs)
6658 + /* Restore MSRs */
6660 + wrmsrl(MSR_LX_DF_GLCONFIG, regs->msr.dfglcfg);
6661 + wrmsrl(MSR_LX_DF_PADSEL, regs->msr.padsel);
6663 + /* Restore the registers */
6665 + writel((u32) regs->vp.r.vx, par->df_regs + 0x10);
6666 + writel((u32) regs->vp.r.vy, par->df_regs + 0x18);
6667 + writel((u32) regs->vp.r.vs, par->df_regs + 0x20);
6668 + writel((u32) regs->vp.r.vck, par->df_regs + 0x28);
6669 + writel((u32) regs->vp.r.vcm, par->df_regs + 0x30);
6670 + /* skip 0x38 and 0x40 */
6671 + writel((u32) regs->vp.r.slr, par->df_regs + 0x48);
6672 + writel((u32) regs->vp.r.misc, par->df_regs + 0x50);
6674 + writel((u32) regs->vp.r.vys, par->df_regs + 0x60);
6675 + writel((u32) regs->vp.r.vxs, par->df_regs + 0x68);
6676 + writel((u32) regs->vp.r.vde, par->df_regs + 0x98);
6677 + writel((u32) regs->vp.r.cck, par->df_regs + 0xA0);
6678 + writel((u32) regs->vp.r.ccm, par->df_regs + 0xA8);
6679 + writel((u32) regs->vp.r.cc1, par->df_regs + 0xB0);
6680 + writel((u32) regs->vp.r.cc2, par->df_regs + 0xB8);
6681 + writel((u32) regs->vp.r.a1x, par->df_regs + 0xC0);
6682 + writel((u32) regs->vp.r.a1y, par->df_regs + 0xC8);
6683 + writel((u32) regs->vp.r.a1c, par->df_regs + 0xD0);
6684 + writel((u32) regs->vp.r.a1t, par->df_regs + 0xD8);
6685 + writel((u32) regs->vp.r.a2x, par->df_regs + 0xE0);
6686 + writel((u32) regs->vp.r.a2y, par->df_regs + 0xE8);
6687 + writel((u32) regs->vp.r.a2c, par->df_regs + 0xF0);
6688 + writel((u32) regs->vp.r.a2t, par->df_regs + 0xF8);
6689 + writel((u32) regs->vp.r.a3x, par->df_regs + 0x100);
6690 + writel((u32) regs->vp.r.a3y, par->df_regs + 0x108);
6691 + writel((u32) regs->vp.r.a3c, par->df_regs + 0x110);
6692 + writel((u32) regs->vp.r.a3t, par->df_regs + 0x118);
6693 + writel((u32) regs->vp.r.vrr, par->df_regs + 0x120);
6694 + writel((u32) regs->vp.r.vye, par->df_regs + 0x138);
6695 + writel((u32) regs->vp.r.a1ye, par->df_regs + 0x140);
6696 + writel((u32) regs->vp.r.a2ye, par->df_regs + 0x148);
6697 + writel((u32) regs->vp.r.a3ye, par->df_regs + 0x150);
6701 + writel((u32) regs->fp.r.pt1, par->df_regs + 0x400);
6702 + writel((u32) regs->fp.r.pt2, par->df_regs + 0x408);
6703 + writel((u32) regs->fp.r.dfc, par->df_regs + 0x418);
6705 + /* Restore panel power */
6707 + val = readl(par->df_regs + 0x410);
6709 + if (regs->fp.r.pm & (1 << 24)) {
6710 + if (!(val & 0x09))
6711 + writel(regs->fp.r.pm, par->df_regs + 0x410);
6714 + if (!(val & 0x05))
6715 + writel(regs->fp.r.pm, par->df_regs + 0x410);
6718 + /* Restore the vp palette */
6720 + writel(0, par->df_regs + 0x38);
6722 + for(i = 0; i <= 0xFF; i++)
6723 + writel((u32) regs->gamma[i], par->df_regs + 0x40);
6725 + /* Restore filter coefficients */
6727 + for(i = 0; i < VP_COEFF_COUNT; i++)
6728 + writel(regs->vp_coeff[i],
6729 + par->df_regs + 0x1000 + (i << 2));
6731 + /* Restore the configuration registers */
6733 + writel((u32) regs->vp.r.dcfg, par->df_regs + 0x08);
6734 + writel((u32) regs->vp.r.vcfg, par->df_regs + 0x00);
6737 +static void lx_restore_gp(struct lxfb_par *par, struct geoderegs *regs)
6739 + writel(regs->gp.r.dst_offset, par->gp_regs + 0x00);
6740 + writel(regs->gp.r.src_offset, par->gp_regs + 0x04);
6741 + writel(regs->gp.r.stride, par->gp_regs + 0x08);
6742 + writel(regs->gp.r.wid_height, par->gp_regs + 0x0C);
6743 + writel(regs->gp.r.src_color_fg, par->gp_regs + 0x10);
6744 + writel(regs->gp.r.src_color_bg, par->gp_regs + 0x14);
6745 + writel(regs->gp.r.pat_color_0, par->gp_regs + 0x18);
6746 + writel(regs->gp.r.pat_color_1, par->gp_regs + 0x1C);
6747 + writel(regs->gp.r.pat_color_2, par->gp_regs + 0x20);
6748 + writel(regs->gp.r.pat_color_3, par->gp_regs + 0x24);
6749 + writel(regs->gp.r.pat_color_4, par->gp_regs + 0x28);
6750 + writel(regs->gp.r.pat_color_5, par->gp_regs + 0x2C);
6751 + writel(regs->gp.r.pat_data_0, par->gp_regs + 0x30);
6752 + writel(regs->gp.r.pat_data_1, par->gp_regs + 0x34);
6754 + /* Writing to these registers would cause a blt to happen */
6755 + /* 0x38, 0x3c, 0x40 */
6757 + /* Status register (0x44) is read only */
6759 + writel(regs->gp.r.hst_src, par->gp_regs + 0x48);
6760 + writel(regs->gp.r.base_offset, par->gp_regs + 0x4c);
6761 + writel(regs->gp.r.cmd_top, par->gp_regs + 0x50);
6762 + writel(regs->gp.r.cmd_bot, par->gp_regs + 0x54);
6763 + writel(regs->gp.r.cmd_read, par->gp_regs + 0x58);
6764 + writel(regs->gp.r.cmd_write, par->gp_regs + 0x5C);
6765 + writel(regs->gp.r.ch3_offset, par->gp_regs + 0x60);
6766 + writel(regs->gp.r.ch3_mode_str, par->gp_regs + 0x64);
6767 + writel(regs->gp.r.ch3_width, par->gp_regs + 0x6C);
6768 + writel(regs->gp.r.ch3_hsrc, par->gp_regs + 0x70);
6770 + writel(regs->gp.r.int_cntrl, par->gp_regs + 0x70);
6773 +static void lx_restore_regs(struct fb_info *info, struct geoderegs *regs)
6775 + struct lxfb_par *par = info->par;
6777 + lx_restore_gp(par, regs);
6778 + lx_restore_vp(par, regs);
6779 + lx_restore_dc(par, regs);
6782 +static int lx_power_on = 1;
6784 +int lx_shutdown(struct fb_info *info)
6786 + if (lx_power_on == 0)
6789 + lx_save_regs(info, &saved_regs);
6790 + lx_graphics_disable(info);
6796 +int lx_powerup(struct fb_info *info)
6798 + if (lx_power_on == 1)
6801 + lx_restore_regs(info, &saved_regs);
6806 diff -purN linux_2.6.24_org/drivers/video/geode/Makefile linux_2.6.24_olpc/drivers/video/geode/Makefile
6807 --- linux_2.6.24_org/drivers/video/geode/Makefile 2008-02-15 20:11:23.000000000 +0000
6808 +++ linux_2.6.24_olpc/drivers/video/geode/Makefile 2008-02-15 18:58:41.000000000 +0000
6809 @@ -5,5 +5,5 @@ obj-$(CONFIG_FB_GEODE_GX) += gxfb.o
6810 obj-$(CONFIG_FB_GEODE_LX) += lxfb.o
6812 gx1fb-objs := gx1fb_core.o display_gx1.o video_cs5530.o
6813 -gxfb-objs := gxfb_core.o display_gx.o video_gx.o
6814 +gxfb-objs := gxfb_core.o display_gx.o video_gx.o suspend_gx.o
6815 lxfb-objs := lxfb_core.o lxfb_ops.o
6816 diff -purN linux_2.6.24_org/drivers/video/geode/suspend_gx.c linux_2.6.24_olpc/drivers/video/geode/suspend_gx.c
6817 --- linux_2.6.24_org/drivers/video/geode/suspend_gx.c 1970-01-01 01:00:00.000000000 +0100
6818 +++ linux_2.6.24_olpc/drivers/video/geode/suspend_gx.c 2008-02-15 18:58:41.000000000 +0000
6820 +#include <linux/fb.h>
6821 +#include <asm/io.h>
6822 +#include <asm/msr.h>
6824 +#include "geodefb.h"
6825 +#include "video_gx.h"
6827 +void gx_set_dotpll(struct fb_info *info, struct geoderegs *regs)
6829 + int timeout = 1000;
6831 + u64 rstpll, dotpll;
6833 + rdmsrl(MSR_GLCP_SYS_RSTPLL, rstpll);
6834 + rdmsrl(MSR_GLCP_DOTPLL, dotpll);
6836 + dotpll &= 0x00000000ffffffffull;
6837 + dotpll |= regs->msr.dotpll & 0xffffffff00000000ull;
6839 + dotpll |= MSR_GLCP_DOTPLL_DOTRESET;
6840 + dotpll &= ~MSR_GLCP_DOTPLL_BYPASS;
6842 + wrmsrl(MSR_GLCP_DOTPLL, dotpll);
6844 + rstpll |= (regs->msr.rstpll &
6845 + ( MSR_GLCP_SYS_RSTPLL_DOTPREDIV2 |
6846 + MSR_GLCP_SYS_RSTPLL_DOTPREMULT2 |
6847 + MSR_GLCP_SYS_RSTPLL_DOTPOSTDIV3));
6849 + wrmsrl(MSR_GLCP_SYS_RSTPLL, rstpll);
6850 + dotpll &= ~(MSR_GLCP_DOTPLL_DOTRESET);
6851 + wrmsrl(MSR_GLCP_DOTPLL, dotpll);
6854 + rdmsrl(MSR_GLCP_DOTPLL, dotpll);
6855 + } while (timeout-- && !(dotpll & MSR_GLCP_DOTPLL_LOCK));
6858 +/* FIXME: Make sure nothing is read to clear */
6860 +void gx_save_regs(struct fb_info *info, struct geoderegs *regs)
6862 + struct geodefb_par *par = info->par;
6865 + /* Wait for the BLT engine to stop being busy */
6866 + while(readl(par->gp_regs + 0x44) & 0x05);
6868 + rdmsrl(GX_VP_MSR_PAD_SELECT, regs->msr.padsel);
6869 + rdmsrl(MSR_GLCP_DOTPLL, regs->msr.dotpll);
6870 + rdmsrl(MSR_GLCP_SYS_RSTPLL, regs->msr.rstpll);
6872 + writel(0x4758, par->dc_regs + 0x00);
6874 + memcpy(regs->gp.b, par->gp_regs, GP_REG_SIZE);
6875 + memcpy(regs->dc.b, par->dc_regs, DC_REG_SIZE);
6876 + memcpy(regs->vp.b, par->vid_regs, VP_REG_SIZE);
6877 + memcpy(regs->fp.b, par->vid_regs + 0x400, FP_REG_SIZE);
6879 + /* Save the palettes */
6880 + writel(0, par->dc_regs + 0x70);
6882 + for(i = 0; i < DC_PAL_SIZE; i++)
6883 + regs->pal[i] = readl(par->dc_regs + 0x74);
6885 + writel(0, par->vid_regs + 0x38);
6887 + for(i = 0; i < 0xFF; i++)
6888 + regs->gamma[i] = readl(par->vid_regs + 0x40);
6891 +void gx_restore_regs(struct fb_info *info, struct geoderegs *regs)
6893 + struct geodefb_par *par = info->par;
6897 + gx_set_dotpll(info, regs);
6901 + writel(regs->gp.r.dst_offset, par->gp_regs + 0x00);
6902 + writel(regs->gp.r.src_offset, par->gp_regs + 0x04);
6903 + writel(regs->gp.r.stride, par->gp_regs + 0x08);
6904 + writel(regs->gp.r.wid_height, par->gp_regs + 0x0C);
6905 + writel(regs->gp.r.src_color_fg, par->gp_regs + 0x10);
6906 + writel(regs->gp.r.src_color_bg, par->gp_regs + 0x14);
6907 + writel(regs->gp.r.pat_color_0, par->gp_regs + 0x18);
6908 + writel(regs->gp.r.pat_color_1, par->gp_regs + 0x1C);
6909 + writel(regs->gp.r.pat_color_2, par->gp_regs + 0x20);
6910 + writel(regs->gp.r.pat_color_3, par->gp_regs + 0x24);
6911 + writel(regs->gp.r.pat_color_4, par->gp_regs + 0x28);
6912 + writel(regs->gp.r.pat_color_5, par->gp_regs + 0x2C);
6913 + writel(regs->gp.r.pat_data_0, par->gp_regs + 0x30);
6914 + writel(regs->gp.r.pat_data_1, par->gp_regs + 0x34);
6916 + /* Don't write the raster / vector / blt mode regs */
6917 + /* status register is read only */
6919 + writel(regs->gp.r.hst_src, par->gp_regs + 0x48);
6920 + writel(regs->gp.r.base_offset, par->gp_regs + 0x4c);
6924 + /* Write the unlock value */
6925 + writel(0x4758, par->dc_regs + 0x00);
6927 + writel(0, par->dc_regs + 0x70);
6929 + for(i = 0; i < DC_PAL_SIZE; i++)
6930 + writel(regs->pal[i], par->dc_regs + 0x74);
6932 + /* Write the gcfg register without the enables */
6933 + writel(regs->dc.r.gcfg & ~0x0F, par->dc_regs + 0x04);
6935 + /* Write the vcfg register without the enables */
6936 + writel(regs->dc.r.dcfg & ~0x19, par->dc_regs + 0x08);
6938 + /* Write the rest of the active registers */
6940 + writel(regs->dc.r.fb_st_offset, par->dc_regs + 0x10);
6941 + writel(regs->dc.r.cb_st_offset, par->dc_regs + 0x14);
6942 + writel(regs->dc.r.curs_st_offset, par->dc_regs + 0x18);
6943 + writel(regs->dc.r.icon_st_offset, par->dc_regs + 0x1C);
6944 + writel(regs->dc.r.vid_y_st_offset, par->dc_regs + 0x20);
6945 + writel(regs->dc.r.vid_u_st_offset, par->dc_regs + 0x24);
6946 + writel(regs->dc.r.vid_v_st_offset, par->dc_regs + 0x28);
6947 + writel(regs->dc.r.line_size, par->dc_regs + 0x30);
6948 + writel(regs->dc.r.gfx_pitch, par->dc_regs + 0x34);
6949 + writel(regs->dc.r.vid_yuv_pitch, par->dc_regs + 0x38);
6950 + writel(regs->dc.r.h_active_timing, par->dc_regs + 0x40);
6951 + writel(regs->dc.r.h_blank_timing, par->dc_regs + 0x44);
6952 + writel(regs->dc.r.h_sync_timing, par->dc_regs + 0x48);
6953 + writel(regs->dc.r.v_active_timing, par->dc_regs + 0x50);
6954 + writel(regs->dc.r.v_blank_timing, par->dc_regs + 0x54);
6955 + writel(regs->dc.r.v_sync_timing, par->dc_regs + 0x58);
6956 + writel(regs->dc.r.dc_cursor_x, par->dc_regs + 0x60);
6957 + writel(regs->dc.r.dc_cursor_y, par->dc_regs + 0x64);
6958 + writel(regs->dc.r.dc_icon_x, par->dc_regs + 0x68);
6960 + /* Don't write the line_cnt or diag registers */
6962 + writel(regs->dc.r.dc_vid_ds_delta, par->dc_regs + 0x80);
6963 + writel(regs->dc.r.gliu0_mem_offset, par->dc_regs + 0x84);
6964 + writel(regs->dc.r.dv_acc, par->dc_regs + 0x8C);
6969 + wrmsrl(GX_VP_MSR_PAD_SELECT, regs->msr.padsel);
6971 + writel(0, par->vid_regs + 0x38);
6973 + for(i = 0; i < 0xFF; i++)
6974 + writel((u32) regs->gamma[i], par->vid_regs + 0x40);
6976 + /* Don't enable video yet */
6977 + writel((u32) regs->vp.r.vcfg & ~0x01, par->vid_regs + 0x00);
6979 + /* Don't enable the CRT yet */
6980 + writel((u32) regs->vp.r.dcfg & ~0x0F, par->vid_regs + 0x08);
6982 + /* Write the rest of the VP registers */
6984 + writel((u32) regs->vp.r.vx, par->vid_regs + 0x10);
6985 + writel((u32) regs->vp.r.vy, par->vid_regs + 0x18);
6986 + writel((u32) regs->vp.r.vs, par->vid_regs + 0x20);
6987 + writel((u32) regs->vp.r.vck, par->vid_regs + 0x28);
6988 + writel((u32) regs->vp.r.vcm, par->vid_regs + 0x30);
6989 + writel((u32) regs->vp.r.misc, par->vid_regs + 0x50);
6990 + writel((u32) regs->vp.r.ccs, par->vid_regs + 0x58);
6991 + writel((u32) regs->vp.r.vdc, par->vid_regs + 0x78);
6992 + writel((u32) regs->vp.r.vco, par->vid_regs + 0x80);
6993 + writel((u32) regs->vp.r.crc, par->vid_regs + 0x88);
6994 + writel((u32) regs->vp.r.vde, par->vid_regs + 0x98);
6995 + writel((u32) regs->vp.r.cck, par->vid_regs + 0xA0);
6996 + writel((u32) regs->vp.r.ccm, par->vid_regs + 0xA8);
6997 + writel((u32) regs->vp.r.cc1, par->vid_regs + 0xB0);
6998 + writel((u32) regs->vp.r.cc2, par->vid_regs + 0xB8);
6999 + writel((u32) regs->vp.r.a1x, par->vid_regs + 0xC0);
7000 + writel((u32) regs->vp.r.a1y, par->vid_regs + 0xC8);
7001 + writel((u32) regs->vp.r.a1c, par->vid_regs + 0xD0);
7002 + writel((u32) regs->vp.r.a1t, par->vid_regs + 0xD8);
7003 + writel((u32) regs->vp.r.a2x, par->vid_regs + 0xE0);
7004 + writel((u32) regs->vp.r.a2y, par->vid_regs + 0xE8);
7005 + writel((u32) regs->vp.r.a2c, par->vid_regs + 0xF0);
7006 + writel((u32) regs->vp.r.a2t, par->vid_regs + 0xF8);
7007 + writel((u32) regs->vp.r.a3x, par->vid_regs + 0x100);
7008 + writel((u32) regs->vp.r.a3y, par->vid_regs + 0x108);
7009 + writel((u32) regs->vp.r.a3c, par->vid_regs + 0x110);
7010 + writel((u32) regs->vp.r.a3t, par->vid_regs + 0x118);
7011 + writel((u32) regs->vp.r.vrr, par->vid_regs + 0x120);
7014 + /* FP registers */
7016 + writel((u32) regs->fp.r.pt1, par->vid_regs + 0x400);
7017 + writel((u32) regs->fp.r.pt2, par->vid_regs + 0x408);
7019 + writel((u32) regs->fp.r.dfc, par->vid_regs + 0x418);
7020 + writel(regs->fp.r.blfsr, par->vid_regs + 0x420);
7021 + writel(regs->fp.r.rlfsr, par->vid_regs + 0x428);
7022 + writel(regs->fp.r.fmi, par->vid_regs + 0x430);
7023 + writel(regs->fp.r.fmd, par->vid_regs + 0x438);
7024 + writel(regs->fp.r.dca, par->vid_regs + 0x448);
7025 + writel(regs->fp.r.dmd, par->vid_regs + 0x450);
7026 + writel(regs->fp.r.crc, par->vid_regs + 0x458);
7027 + writel(regs->fp.r.fbb, par->vid_regs + 0x460);
7029 + /* Final enables */
7031 + val = readl(par->vid_regs + 0x410);
7033 + /* Control the panel */
7034 + if (regs->fp.r.pm & (1 << 24)) {
7036 + if (!(val & 0x09))
7037 + writel(regs->fp.r.pm, par->vid_regs + 0x410);
7040 + if (!(val & 0x05))
7041 + writel(regs->fp.r.pm, par->vid_regs + 0x410);
7044 + /* Turn everything on */
7046 + writel(regs->dc.r.gcfg, par->dc_regs + 0x04);
7047 + writel((u32) regs->vp.r.vcfg, par->vid_regs + 0x00);
7048 + writel((u32) regs->vp.r.dcfg, par->vid_regs + 0x08);
7049 + writel(regs->dc.r.dcfg, par->dc_regs + 0x08);
7055 +void dump_regs(struct fb_info *info, int mode) {
7057 + struct geodefb_par *par = info->par;
7062 + for(i = 0; i < GP_REG_SIZE; i += 4) {
7063 + val = readl(par->gp_regs + i);
7068 + writel(0x4758, par->dc_regs + 0x00);
7070 + for(i = 0; i < DC_REG_SIZE; i += 4) {
7071 + val = readl(par->dc_regs + i);
7072 + printk("DC%x: %x\n", i, val);
7077 + for(i = 0; i < VP_REG_SIZE; i += 8) {
7078 + val = readl(par->vid_regs + i);
7079 + printk("VP%x: %x\n", i, val);
7084 + for(i = 0; i < FP_REG_SIZE; i += 8) {
7085 + val = readl(par->vid_regs + 0x400 + i);
7086 + printk("FP%x: %x\n", i, val);
7092 diff -purN linux_2.6.24_org/drivers/video/geode/video_gx.c linux_2.6.24_olpc/drivers/video/geode/video_gx.c
7093 --- linux_2.6.24_org/drivers/video/geode/video_gx.c 2008-02-15 20:11:23.000000000 +0000
7094 +++ linux_2.6.24_olpc/drivers/video/geode/video_gx.c 2008-02-15 18:58:41.000000000 +0000
7097 #include <asm/delay.h>
7098 #include <asm/msr.h>
7099 +#include <asm/olpc.h>
7101 #include "geodefb.h"
7102 #include "video_gx.h"
7103 +#include "display_gx.h"
7105 +/* This structure is used to store the saved registers during suspend */
7106 +static struct geoderegs gx_saved_regs;
7109 * Tables of register settings for various DOTCLKs.
7110 @@ -58,7 +62,7 @@ static const struct gx_pll_entry gx_pll_
7111 { 13888, POSTDIV3, 0x000007E1 }, /* 72.0000 */
7112 { 13426, PREMULT2, 0x00000F4A }, /* 74.4810 */
7113 { 13333, 0, 0x00000052 }, /* 75.0000 */
7114 - { 12698, 0, 0x00000056 }, /* 78.7500 */
7115 + { 12698, 0, 0x00000056 }, /* 78.7500 */
7116 { 12500, POSTDIV3|PREMULT2, 0x00000709 }, /* 80.0000 */
7117 { 11135, PREMULT2, 0x00000262 }, /* 89.8000 */
7118 { 10582, 0, 0x000002D2 }, /* 94.5000 */
7119 @@ -117,8 +121,9 @@ static const struct gx_pll_entry gx_pll_
7120 { 4357, 0, 0x0000057D }, /* 229.5000 */
7123 -static void gx_set_dclk_frequency(struct fb_info *info)
7124 +void gx_set_dclk_frequency(struct fb_info *info)
7126 + struct geodefb_par *par = info->par;
7127 const struct gx_pll_entry *pll_table;
7130 @@ -173,115 +178,169 @@ static void gx_set_dclk_frequency(struct
7132 rdmsrl(MSR_GLCP_DOTPLL, dotpll);
7133 } while (timeout-- && !(dotpll & MSR_GLCP_DOTPLL_LOCK));
7135 + par->curdclk = pll_table[best_i].dotpll_value;
7139 -gx_configure_tft(struct fb_info *info)
7140 +/* Find out the current clock - we will use this information to avoid
7141 + re-programming it if we don't need to */
7143 +unsigned int gx_get_dclk(struct fb_info *info)
7145 - struct geodefb_par *par = info->par;
7146 - unsigned long val;
7148 + const struct gx_pll_entry *pll_table;
7149 + int pll_table_len;
7153 - /* Set up the DF pad select MSR */
7154 + if (cpu_data(0).x86_mask == 1) {
7155 + pll_table = gx_pll_table_14MHz;
7156 + pll_table_len = ARRAY_SIZE(gx_pll_table_14MHz);
7158 + pll_table = gx_pll_table_48MHz;
7159 + pll_table_len = ARRAY_SIZE(gx_pll_table_48MHz);
7162 - rdmsrl(GX_VP_MSR_PAD_SELECT, val);
7163 - val &= ~GX_VP_PAD_SELECT_MASK;
7164 - val |= GX_VP_PAD_SELECT_TFT;
7165 - wrmsrl(GX_VP_MSR_PAD_SELECT, val);
7166 + rdmsrl(MSR_GLCP_DOTPLL, dotpll);
7168 - /* Turn off the panel */
7169 + for(i = 0; i < pll_table_len; i++) {
7170 + if (pll_table[i].dotpll_value == (u32) (dotpll >> 32))
7174 + return (i == pll_table_len) ? 0 : pll_table[i].pixclock;
7177 - fp = readl(par->vid_regs + GX_FP_PM);
7178 - fp &= ~GX_FP_PM_P;
7179 - writel(fp, par->vid_regs + GX_FP_PM);
7181 - /* Set timing 1 */
7182 +#define CMP(val, mask, res) (((val) & (mask)) == (res))
7184 - fp = readl(par->vid_regs + GX_FP_PT1);
7185 - fp &= GX_FP_PT1_VSIZE_MASK;
7186 - fp |= info->var.yres << GX_FP_PT1_VSIZE_SHIFT;
7187 - writel(fp, par->vid_regs + GX_FP_PT1);
7189 +gx_configure_tft(struct fb_info *info) {
7192 - /* Set bits that are always on for TFT */
7193 + struct geodefb_par *par = info->par;
7194 + u32 val, fp = 0, fp1, fp2, sync = 0;
7197 + /* Set up the DF pad select MSR */
7199 - /* Add sync polarity */
7200 + rdmsrl(GX_VP_MSR_PAD_SELECT, val);
7202 + if ((val & GX_VP_PAD_SELECT_MASK) != GX_VP_PAD_SELECT_TFT) {
7203 + val &= ~GX_VP_PAD_SELECT_MASK;
7204 + val |= GX_VP_PAD_SELECT_TFT;
7205 + wrmsrl(GX_VP_MSR_PAD_SELECT, val);
7208 if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
7209 - fp |= GX_FP_PT2_VSP;
7210 + sync |= GX_FP_PT2_VSP;
7212 if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
7213 - fp |= GX_FP_PT2_HSP;
7214 + sync |= GX_FP_PT2_HSP;
7216 - writel(fp, par->vid_regs + GX_FP_PT2);
7217 + /* We only need to turn off the panel if something changed */
7219 - /* Set the dither control */
7220 - writel(0x70, par->vid_regs + GX_FP_DFC);
7221 + fp1 = readl(par->vid_regs + GX_FP_PT1);
7222 + fp2 = readl(par->vid_regs + GX_FP_PT2);
7224 + if (!CMP(fp1, GX_FP_PT1_VSIZE_MASK, info->var.yres << GX_FP_PT1_VSIZE_SHIFT) ||
7225 + (fp2 != (0x0F100000 | sync))) {
7227 + /* Turn off the panel */
7230 + /* Do we really need to turn off the panel? */
7231 + /* Possibly - we have a glitch somewhere */
7233 - /* Enable the FP data and power (in case the BIOS didn't) */
7234 + fp = readl(par->vid_regs + GX_FP_PM);
7235 + fp &= ~GX_FP_PM_P;
7236 + writel(fp, par->vid_regs + GX_FP_PM);
7239 - fp = readl(par->vid_regs + GX_DCFG);
7240 - fp |= GX_DCFG_FP_PWR_EN | GX_DCFG_FP_DATA_EN;
7241 - writel(fp, par->vid_regs + GX_DCFG);
7243 + fp1 &= GX_FP_PT1_VSIZE_MASK;
7244 + fp1 |= info->var.yres << GX_FP_PT1_VSIZE_SHIFT;
7245 + writel(fp, par->vid_regs + GX_FP_PT1);
7247 - /* Unblank the panel */
7249 + writel(0x0F100000 | sync, par->vid_regs + GX_FP_PT2);
7252 + /* Set the dither control */
7253 + if (readl(par->vid_regs + GX_FP_DFC) != 0x70) {
7254 + writel(0x70, par->vid_regs + GX_FP_DFC);
7257 + /* Turn on the panel */
7259 fp = readl(par->vid_regs + GX_FP_PM);
7261 - writel(fp, par->vid_regs + GX_FP_PM);
7264 + writel(fp | GX_FP_PM_P, par->vid_regs + GX_FP_PM);
7267 +#define DCFG_DEFAULT_VAL GX_DCFG_CRT_SYNC_SKW_DFLT | GX_DCFG_HSYNC_EN | GX_DCFG_VSYNC_EN | \
7268 +GX_DCFG_CRT_EN | GX_DCFG_DAC_BL_EN
7270 static void gx_configure_display(struct fb_info *info)
7272 struct geodefb_par *par = info->par;
7274 + u32 dcfg, misc, sync = 0;
7276 /* Set up the MISC register */
7278 misc = readl(par->vid_regs + GX_MISC);
7280 - /* Power up the DAC */
7281 - misc &= ~(GX_MISC_A_PWRDN | GX_MISC_DAC_PWRDN);
7282 + /* We leave gamma enabled if it was already enabled.
7283 + Although the hardware enables it without setting
7284 + up the gamma table, the BIOS or bootloader ought
7285 + to have either disabled it or loaded a table by now */
7287 - /* Disable gamma correction */
7288 - misc |= GX_MISC_GAM_EN;
7290 - writel(misc, par->vid_regs + GX_MISC);
7292 - /* Write the display configuration */
7293 - dcfg = readl(par->vid_regs + GX_DCFG);
7294 + if (par->enable_crt) {
7295 + /* Power up the CRT DACs */
7296 + if (misc & ( GX_MISC_A_PWRDN | GX_MISC_DAC_PWRDN)) {
7297 + misc &= ~(GX_MISC_A_PWRDN | GX_MISC_DAC_PWRDN);
7298 + writel(misc, par->vid_regs + GX_MISC);
7301 - /* Disable hsync and vsync */
7302 - dcfg &= ~(GX_DCFG_VSYNC_EN | GX_DCFG_HSYNC_EN);
7303 - writel(dcfg, par->vid_regs + GX_DCFG);
7304 + if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
7305 + sync |= GX_DCFG_CRT_HSYNC_POL;
7307 - /* Clear bits from existing mode. */
7308 - dcfg &= ~(GX_DCFG_CRT_SYNC_SKW_MASK
7309 - | GX_DCFG_CRT_HSYNC_POL | GX_DCFG_CRT_VSYNC_POL
7310 - | GX_DCFG_VSYNC_EN | GX_DCFG_HSYNC_EN);
7311 + if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
7312 + sync |= GX_DCFG_CRT_VSYNC_POL;
7315 + /* Turn off the CRT DACs in FP mode - we don't need them */
7316 + if ((misc & (GX_MISC_A_PWRDN | GX_MISC_DAC_PWRDN))) {
7317 + misc |= (GX_MISC_A_PWRDN | GX_MISC_DAC_PWRDN);
7318 + writel(misc, par->vid_regs + GX_MISC);
7322 - /* Set default sync skew. */
7323 - dcfg |= GX_DCFG_CRT_SYNC_SKW_DFLT;
7324 + /* Write the display configuration */
7325 + dcfg = readl(par->vid_regs + GX_DCFG);
7327 - /* Enable hsync and vsync. */
7328 - dcfg |= GX_DCFG_HSYNC_EN | GX_DCFG_VSYNC_EN;
7329 + if (!CMP(dcfg, DCFG_DEFAULT_VAL | GX_DCFG_CRT_HSYNC_POL | GX_DCFG_CRT_VSYNC_POL,
7330 + DCFG_DEFAULT_VAL | sync)) {
7332 - /* Sync polarities. */
7333 - if (info->var.sync & FB_SYNC_HOR_HIGH_ACT)
7334 - dcfg |= GX_DCFG_CRT_HSYNC_POL;
7335 - if (info->var.sync & FB_SYNC_VERT_HIGH_ACT)
7336 - dcfg |= GX_DCFG_CRT_VSYNC_POL;
7337 + /* Disable hsync and vsync */
7338 + dcfg &= ~(GX_DCFG_VSYNC_EN | GX_DCFG_HSYNC_EN);
7339 + writel(dcfg, par->vid_regs + GX_DCFG);
7341 - /* Enable the display logic */
7342 - /* Set up the DACS to blank normally */
7343 + /* Clear bits from existing mode. */
7344 + dcfg &= ~(GX_DCFG_CRT_SYNC_SKW_MASK
7345 + | GX_DCFG_CRT_HSYNC_POL | GX_DCFG_CRT_VSYNC_POL
7346 + | GX_DCFG_VSYNC_EN | GX_DCFG_HSYNC_EN);
7348 - dcfg |= GX_DCFG_CRT_EN | GX_DCFG_DAC_BL_EN;
7349 + /* Set default sync skew. */
7350 + dcfg |= GX_DCFG_CRT_SYNC_SKW_DFLT;
7352 - /* Enable the external DAC VREF? */
7353 + /* Enable hsync and vsync. */
7354 + dcfg |= GX_DCFG_HSYNC_EN | GX_DCFG_VSYNC_EN;
7356 - writel(dcfg, par->vid_regs + GX_DCFG);
7357 + /* Enable the display logic */
7358 + dcfg |= GX_DCFG_CRT_EN | GX_DCFG_DAC_BL_EN;
7360 + writel(dcfg, par->vid_regs + GX_DCFG);
7363 /* Set up the flat panel (if it is enabled) */
7365 @@ -289,6 +348,100 @@ static void gx_configure_display(struct
7366 gx_configure_tft(info);
7369 +int gxfb_powerdown(struct fb_info *info)
7371 + struct geodefb_par *par = info->par;
7373 + /* We're already suspended */
7375 + if (par->state != FB_POWER_STATE_ON)
7378 + /* Save the registers */
7379 + gx_save_regs(info, &gx_saved_regs);
7381 + /* Shut down the engine */
7383 + writel(gx_saved_regs.vp.r.vcfg & ~0x01, par->vid_regs + GX_VCFG);
7384 + writel(gx_saved_regs.vp.r.dcfg & ~0x0F, par->vid_regs + GX_DCFG);
7386 + /* Turn off the flat panel unless we are attached to a DCON */
7387 + if (!olpc_has_dcon())
7388 + writel(gx_saved_regs.fp.r.pm & ~GX_FP_PM_P, par->vid_regs + GX_FP_PM);
7390 + writel(0x4758, par->dc_regs + DC_UNLOCK);
7392 + writel(gx_saved_regs.dc.r.gcfg & ~0x0F,
7393 + par->dc_regs + DC_GENERAL_CFG);
7395 + writel(gx_saved_regs.dc.r.dcfg & ~0x19,
7396 + par->dc_regs + DC_DISPLAY_CFG);
7398 + par->state = FB_POWER_STATE_SUSPEND;
7403 +int gxfb_powerup(struct fb_info *info)
7405 + struct geodefb_par *par = info->par;
7408 + if (par->state == FB_POWER_STATE_SUSPEND) {
7410 + writel(gx_saved_regs.dc.r.dcfg,
7411 + par->dc_regs + DC_DISPLAY_CFG);
7413 + writel(gx_saved_regs.vp.r.vcfg, par->vid_regs + GX_VCFG);
7414 + writel(gx_saved_regs.vp.r.dcfg, par->vid_regs + GX_DCFG);
7416 + val = readl(par->vid_regs + GX_FP_PM);
7418 + /* power up the panel if it needs it; we don't always power it down */
7419 + if (!(val & 0x09)) {
7420 + writel(gx_saved_regs.fp.r.pm, par->vid_regs + GX_FP_PM);
7425 + /* If the panel is currently on its way up, then wait up to 100ms
7428 + if (readl(par->vid_regs + GX_FP_PM) & 0x08) {
7431 + for(i = 0; i < 10; i++) {
7432 + if (readl(par->vid_regs + GX_FP_PM) & 0x01)
7439 + printk(KERN_ERR "gxfb: Panel power up timed out\n");
7442 + if (par->state == FB_POWER_STATE_ON)
7445 + switch(par->state) {
7446 + case FB_POWER_STATE_OFF:
7447 + gx_restore_regs(info, &gx_saved_regs);
7450 + case FB_POWER_STATE_SUSPEND:
7451 + /* Do this because it will turn on the FIFO which will
7452 + start the line count */
7453 + writel(gx_saved_regs.dc.r.gcfg,
7454 + par->dc_regs + DC_GENERAL_CFG);
7455 + writel(0x0, par->dc_regs + DC_UNLOCK);
7459 + par->state = FB_POWER_STATE_ON;
7463 static int gx_blank_display(struct fb_info *info, int blank_mode)
7465 struct geodefb_par *par = info->par;
7466 @@ -315,6 +468,7 @@ static int gx_blank_display(struct fb_in
7471 dcfg = readl(par->vid_regs + GX_DCFG);
7472 dcfg &= ~(GX_DCFG_DAC_BL_EN
7473 | GX_DCFG_HSYNC_EN | GX_DCFG_VSYNC_EN);
7474 @@ -326,7 +480,7 @@ static int gx_blank_display(struct fb_in
7475 dcfg |= GX_DCFG_VSYNC_EN;
7476 writel(dcfg, par->vid_regs + GX_DCFG);
7478 - /* Power on/off flat panel. */
7479 + /* Power on/off flat panel */
7481 if (par->enable_crt == 0) {
7482 fp_pm = readl(par->vid_regs + GX_FP_PM);
7483 @@ -340,8 +494,37 @@ static int gx_blank_display(struct fb_in
7487 +extern struct fb_info *gxfb_info;
7489 +/* This function controls the flatpanel power sequencing - this is used
7490 + by the OLPC power management engine to enable the FP sequencing much
7491 + earlier in the resume process
7494 +void gxfb_flatpanel_control(int state)
7496 + struct geodefb_par *par = gxfb_info->par;
7497 + u32 val, fp = readl(par->vid_regs + GX_FP_PM);
7500 + /* Turn on the panel if it isn't aleady */
7503 + if (!(val & 0x01))
7504 + val |= GX_FP_PM_P;
7507 + if (!(val & 0x02))
7508 + val &= ~GX_FP_PM_P;
7512 + writel(val, par->vid_regs + GX_FP_PM);
7515 struct geode_vid_ops gx_vid_ops = {
7516 .set_dclk = gx_set_dclk_frequency,
7517 + .get_dclk = gx_get_dclk,
7518 .configure_display = gx_configure_display,
7519 .blank_display = gx_blank_display,
7521 diff -purN linux_2.6.24_org/drivers/video/geode/video_gx.h linux_2.6.24_olpc/drivers/video/geode/video_gx.h
7522 --- linux_2.6.24_org/drivers/video/geode/video_gx.h 2008-02-15 20:11:23.000000000 +0000
7523 +++ linux_2.6.24_olpc/drivers/video/geode/video_gx.h 2008-02-15 18:58:41.000000000 +0000
7525 #ifndef __VIDEO_GX_H__
7526 #define __VIDEO_GX_H__
7528 +#include "geode_regs.h"
7530 extern struct geode_vid_ops gx_vid_ops;
7532 /* GX Flatpanel control MSR */
7533 @@ -20,6 +22,8 @@ extern struct geode_vid_ops gx_vid_ops;
7535 /* Geode GX video processor registers */
7537 +#define GX_VCFG 0x0000
7539 #define GX_DCFG 0x0008
7540 # define GX_DCFG_CRT_EN 0x00000001
7541 # define GX_DCFG_HSYNC_EN 0x00000002
7542 @@ -42,6 +46,14 @@ extern struct geode_vid_ops gx_vid_ops;
7543 #define GX_MISC_DAC_PWRDN 0x00000400
7544 #define GX_MISC_A_PWRDN 0x00000800
7546 +/* Gamma correction RAM - address and data registers */
7548 +#define GX_GAR 0x038
7549 +#define GX_GDR 0x040
7551 +#define GXFB_GAMMA_DWORDS 256 /* number of dwords in the gamma ram */
7552 +#define GXFB_GAMMA_SIZE (GXFB_GAMMA_DWORDS * sizeof(unsigned int))
7554 /* Geode GX flat panel display control registers */
7556 #define GX_FP_PT1 0x0400
7557 @@ -69,4 +81,13 @@ extern struct geode_vid_ops gx_vid_ops;
7558 # define MSR_GLCP_DOTPLL_BYPASS (0x0000000000008000ull)
7559 # define MSR_GLCP_DOTPLL_LOCK (0x0000000002000000ull)
7561 +int gxfb_powerdown(struct fb_info *info);
7562 +int gxfb_powerup(struct fb_info *info);
7564 +void gx_set_dclk_frequency(struct fb_info *info);
7565 +unsigned int gx_get_dclk(struct fb_info *info);
7567 +void gx_save_regs(struct fb_info *info, struct geoderegs *regs);
7568 +void gx_restore_regs(struct fb_info *info, struct geoderegs *regs);
7570 #endif /* !__VIDEO_GX_H__ */
7571 diff -purN linux_2.6.24_org/drivers/video/Kconfig linux_2.6.24_olpc/drivers/video/Kconfig
7572 --- linux_2.6.24_org/drivers/video/Kconfig 2008-02-15 20:11:22.000000000 +0000
7573 +++ linux_2.6.24_olpc/drivers/video/Kconfig 2008-02-15 18:58:36.000000000 +0000
7574 @@ -1869,6 +1869,15 @@ config FB_PS3_DEFAULT_SIZE_M
7575 The default value can be overridden on the kernel command line
7576 using the "ps3fb" option (e.g. "ps3fb=9M");
7578 +config FB_OLPC_DCON
7579 + tristate "One Laptop Per Child Display CONtroller support"
7583 + Add support for the OLPC DCON controller. This controller is only
7584 + available on OLPC platforms. Unless you have one of these
7585 + platforms, you will want to say 'N'.
7588 tristate "Xilinx frame buffer support"
7589 depends on FB && XILINX_VIRTEX
7590 diff -purN linux_2.6.24_org/drivers/video/Makefile linux_2.6.24_olpc/drivers/video/Makefile
7591 --- linux_2.6.24_org/drivers/video/Makefile 2008-02-15 20:11:22.000000000 +0000
7592 +++ linux_2.6.24_olpc/drivers/video/Makefile 2008-02-15 18:58:36.000000000 +0000
7593 @@ -111,6 +111,7 @@ obj-$(CONFIG_FB_PNX4008_DUM_RGB) += pnx
7594 obj-$(CONFIG_FB_IBM_GXT4500) += gxt4500.o
7595 obj-$(CONFIG_FB_PS3) += ps3fb.o
7596 obj-$(CONFIG_FB_SM501) += sm501fb.o
7597 +obj-$(CONFIG_FB_OLPC_DCON) += olpc_dcon.o
7598 obj-$(CONFIG_FB_XILINX) += xilinxfb.o
7599 obj-$(CONFIG_FB_OMAP) += omap/
7601 diff -purN linux_2.6.24_org/drivers/video/modedb.c linux_2.6.24_olpc/drivers/video/modedb.c
7602 --- linux_2.6.24_org/drivers/video/modedb.c 2008-02-15 20:11:23.000000000 +0000
7603 +++ linux_2.6.24_olpc/drivers/video/modedb.c 2008-02-15 18:58:41.000000000 +0000
7604 @@ -33,6 +33,8 @@ const char *fb_mode_option;
7605 * Standard video mode definitions (taken from XFree86)
7608 +#define DEFAULT_MODEDB_INDEX 0
7610 static const struct fb_videomode modedb[] = {
7612 /* 640x400 @ 70 Hz, 31.5 kHz hsync */
7613 @@ -508,7 +510,8 @@ int fb_find_mode(struct fb_var_screeninf
7617 - default_mode = &db[0];
7618 + default_mode = (db == modedb) ?
7619 + &modedb[DEFAULT_MODEDB_INDEX] : &db[0];
7623 diff -purN linux_2.6.24_org/drivers/video/olpc_dcon.c linux_2.6.24_olpc/drivers/video/olpc_dcon.c
7624 --- linux_2.6.24_org/drivers/video/olpc_dcon.c 1970-01-01 01:00:00.000000000 +0100
7625 +++ linux_2.6.24_olpc/drivers/video/olpc_dcon.c 2008-02-15 18:58:42.000000000 +0000
7628 + * Mainly by David Woodhouse, somewhat modified by Jordan Crouse
7630 + * Copyright © 2006-2007 Red Hat, Inc.
7631 + * Copyright © 2006-2007 Advanced Micro Devices, Inc.
7633 + * This program is free software. You can redistribute it and/or
7634 + * modify it under the terms of version 2 of the GNU General Public
7635 + * License as published by the Free Software Foundation.
7639 +#include <linux/kernel.h>
7640 +#include <linux/fb.h>
7641 +#include <linux/console.h>
7642 +#include <linux/i2c.h>
7643 +#include <linux/platform_device.h>
7644 +#include <linux/i2c-id.h>
7645 +#include <linux/pci.h>
7646 +#include <linux/vt_kern.h>
7647 +#include <linux/pci_ids.h>
7648 +#include <linux/interrupt.h>
7649 +#include <linux/delay.h>
7650 +#include <linux/backlight.h>
7651 +#include <linux/device.h>
7652 +#include <linux/notifier.h>
7653 +#include <asm/uaccess.h>
7654 +#include <linux/ctype.h>
7655 +#include <linux/reboot.h>
7656 +#include <asm/tsc.h>
7657 +#include <asm/olpc.h>
7658 +#include <asm/geode.h>
7660 +#include "olpc_dcon.h"
7662 +/* Module definitions */
7664 +static int resumeline = 898;
7665 +module_param(resumeline, int, 0444);
7668 +module_param(noinit, int, 0444);
7670 +/* Default off since it doesn't work on DCON ASIC in B-test OLPC board */
7671 +static int useaa = 1;
7672 +module_param(useaa, int, 0444);
7674 +/* I2C structures */
7676 +static struct i2c_driver dcon_driver;
7677 +static struct i2c_client *dcon_client;
7679 +/* Platform devices */
7680 +static struct platform_device *dcon_device;
7682 +/* Backlight device */
7683 +static struct backlight_device *dcon_bl_dev;
7685 +/* Base address of the GPIO registers */
7686 +static unsigned long gpio_base;
7688 +static struct fb_info *fbinfo;
7690 +/* Current source, initialized at probe time */
7691 +static int dcon_source;
7693 +/* Desired source */
7694 +static int dcon_pending;
7696 +/* Current output type */
7697 +static int dcon_output = DCON_OUTPUT_COLOR;
7699 +/* Current sleep status (not yet implemented) */
7700 +static int dcon_sleep_val = DCON_ACTIVE;
7702 +/* Shadow register for the DCON_REG_MODE register */
7703 +static unsigned short dcon_disp_mode;
7705 +/* Variables used during switches */
7706 +static int dcon_switched;
7708 +static DECLARE_WAIT_QUEUE_HEAD(dcon_wait_queue);
7710 +static unsigned short normal_i2c[] = { 0x0D, I2C_CLIENT_END };
7713 +#define dcon_write(reg,val) i2c_smbus_write_word_data(dcon_client,reg,val)
7714 +#define dcon_read(reg) i2c_smbus_read_word_data(dcon_client,reg)
7716 +/* The current backlight value - this saves us some smbus traffic */
7717 +static int bl_val = -1;
7719 +/* ===== API functions - these are called by a variety of users ==== */
7721 +static int dcon_request_irq(void);
7723 +static int dcon_hw_init(struct i2c_client *client, int is_init)
7728 + ver = i2c_smbus_read_word_data(client, DCON_REG_ID);
7729 + if ((ver >> 8) != 0xDC) {
7730 + printk(KERN_ERR "olpc-dcon: DCON ID not 0xDCxx: 0x%04x "
7731 + "instead.\n", ver);
7737 + printk(KERN_INFO "olpc-dcon: Discovered DCON version %x\n",
7739 + if ((rc = dcon_request_irq())) {
7740 + printk(KERN_ERR "olpc-dcon: Unable to grab IRQ.\n");
7745 + if (ver < 0xdc02 && !noinit) {
7746 + /* Initialize the DCON registers */
7748 + /* Start with work-arounds for DCON ASIC */
7749 + i2c_smbus_write_word_data(client, 0x4b, 0x00cc);
7750 + i2c_smbus_write_word_data(client, 0x4b, 0x00cc);
7751 + i2c_smbus_write_word_data(client, 0x4b, 0x00cc);
7752 + i2c_smbus_write_word_data(client, 0x0b, 0x007a);
7753 + i2c_smbus_write_word_data(client, 0x36, 0x025c);
7754 + i2c_smbus_write_word_data(client, 0x37, 0x025e);
7756 + /* Initialise SDRAM */
7758 + i2c_smbus_write_word_data(client, 0x3b, 0x002b);
7759 + i2c_smbus_write_word_data(client, 0x41, 0x0101);
7760 + i2c_smbus_write_word_data(client, 0x42, 0x0101);
7762 + else if (!noinit) {
7763 + /* SDRAM setup/hold time */
7764 + i2c_smbus_write_word_data(client, 0x3a, 0xc040);
7765 + i2c_smbus_write_word_data(client, 0x41, 0x0000);
7766 + i2c_smbus_write_word_data(client, 0x41, 0x0101);
7767 + i2c_smbus_write_word_data(client, 0x42, 0x0101);
7770 + /* Colour swizzle, AA, no passthrough, backlight */
7772 + dcon_disp_mode = MODE_PASSTHRU | MODE_BL_ENABLE | MODE_CSWIZZLE;
7774 + dcon_disp_mode |= MODE_COL_AA;
7776 + i2c_smbus_write_word_data(client, DCON_REG_MODE, dcon_disp_mode);
7779 + /* Set the scanline to interrupt on during resume */
7781 + i2c_smbus_write_word_data(client, DCON_REG_SCAN_INT, resumeline);
7788 + * The smbus doesn't always come back due to what is believed to be
7789 + * hardware (power rail) bugs. For older models where this is known to
7790 + * occur, our solution is to attempt to wait for the bus to stabilize;
7791 + * if it doesn't happen, cut power to the dcon, repower it, and wait
7792 + * for the bus to stabilize. Rinse, repeat until we have a working
7793 + * smbus. For newer models, we simply BUG(); we want to know if this
7794 + * still happens despite the power fixes that have been made!
7796 +static int dcon_bus_stabilize(struct i2c_client *client, int is_powered_down)
7798 + unsigned long timeout;
7802 + if (is_powered_down) {
7804 + if ((x = olpc_ec_cmd(0x26, (unsigned char *) &x, 1, NULL, 0))) {
7805 + printk(KERN_WARNING "olpc-dcon: unable to force dcon "
7806 + "to power up: %d!\n", x);
7809 + msleep(10); /* we'll be conservative */
7813 + * According to HiMax, when powering the DCON up we should hold
7814 + * SMB_DATA high for 8 SMB_CLK cycles. This will force the DCON
7815 + * state machine to reset to a (sane) initial state. Mitch Bradley
7816 + * did some testing and discovered that holding for 16 SMB_CLK cycles
7817 + * worked a lot more reliably, so that's what we do here.
7819 + * According to the cs5536 spec, to set GPIO14 to SMB_CLK we must
7820 + * simultaneously set AUX1 IN/OUT to GPIO14; ditto for SMB_DATA and
7823 + geode_gpio_set(OLPC_GPIO_SMB_CLK|OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_VAL);
7824 + geode_gpio_set(OLPC_GPIO_SMB_CLK|OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_ENABLE);
7825 + geode_gpio_clear(OLPC_GPIO_SMB_CLK|OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_AUX1);
7826 + geode_gpio_clear(OLPC_GPIO_SMB_CLK|OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_AUX2);
7827 + geode_gpio_clear(OLPC_GPIO_SMB_CLK|OLPC_GPIO_SMB_DATA, GPIO_INPUT_AUX1);
7829 + for (x = 0; x < 16; x++) {
7831 + geode_gpio_clear(OLPC_GPIO_SMB_CLK, GPIO_OUTPUT_VAL);
7833 + geode_gpio_set(OLPC_GPIO_SMB_CLK, GPIO_OUTPUT_VAL);
7836 + geode_gpio_set(OLPC_GPIO_SMB_CLK|OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_AUX1);
7837 + geode_gpio_set(OLPC_GPIO_SMB_CLK|OLPC_GPIO_SMB_DATA, GPIO_INPUT_AUX1);
7839 + for (x = -1, timeout = 50; timeout && x < 0; timeout--) {
7841 + x = dcon_read(DCON_REG_ID);
7844 + printk(KERN_ERR "olpc-dcon: unable to stabilize dcon's "
7845 + "smbus, reasserting power and praying.\n");
7846 + BUG_ON(olpc_board_at_least(olpc_board(0xc2)));
7848 + olpc_ec_cmd(0x26, (unsigned char *) &x, 1, NULL, 0);
7850 + is_powered_down = 1;
7851 + goto power_up; /* argh, stupid hardware.. */
7854 + if (is_powered_down)
7855 + return dcon_hw_init(client, 0);
7860 +/* Backlight notes - turning off the backlight enable bit in the DCON
7861 + * doesn't save us any power over just pushing the BL to zero, so we
7862 + * don't use that bit in this code.
7865 +static int dcon_get_backlight(void)
7867 + if (dcon_client == NULL)
7871 + bl_val = dcon_read(DCON_REG_BRIGHT) & 0x0F;
7876 +static void dcon_set_backlight(int level)
7878 + if (dcon_client == NULL)
7881 + if (bl_val == (level & 0x0F))
7884 + bl_val = level & 0x0F;
7885 + dcon_write(DCON_REG_BRIGHT, bl_val);
7887 + /* Purposely turn off the backlight when we go to level 0 */
7889 + if (bl_val == 0) {
7890 + dcon_disp_mode &= ~MODE_BL_ENABLE;
7891 + dcon_write(DCON_REG_MODE, dcon_disp_mode);
7893 + else if (!(dcon_disp_mode & MODE_BL_ENABLE)) {
7894 + dcon_disp_mode |= MODE_BL_ENABLE;
7895 + dcon_write(DCON_REG_MODE, dcon_disp_mode);
7899 +/* Set the output type to either color or mono */
7901 +static int dcon_set_output(int arg)
7903 + if (dcon_output == arg)
7906 + dcon_output = arg;
7908 + if (arg == DCON_OUTPUT_MONO) {
7909 + dcon_disp_mode &= ~(MODE_CSWIZZLE | MODE_COL_AA);
7910 + dcon_disp_mode |= MODE_MONO_LUMA;
7913 + dcon_disp_mode &= ~(MODE_MONO_LUMA);
7914 + dcon_disp_mode |= MODE_CSWIZZLE;
7916 + dcon_disp_mode |= MODE_COL_AA;
7919 + dcon_write(DCON_REG_MODE, dcon_disp_mode);
7923 +/* For now, this will be really stupid - we need to address how
7924 + * DCONLOAD works in a sleep and account for it accordingly
7927 +static void dcon_sleep(int state)
7931 + /* Turn off the backlight and put the DCON to sleep */
7933 + if (state == dcon_sleep_val)
7936 + if (!olpc_board_at_least(olpc_board(0xc2)))
7939 + if (state == DCON_SLEEP) {
7941 + if ((x = olpc_ec_cmd(0x26, (unsigned char *) &x, 1, NULL, 0)))
7942 + printk(KERN_WARNING "olpc-dcon: unable to force dcon "
7943 + "to power down: %d!\n", x);
7945 + dcon_sleep_val = state;
7948 + /* Only re-enable the backlight if the backlight value is set */
7950 + dcon_disp_mode |= MODE_BL_ENABLE;
7952 + if ((x=dcon_bus_stabilize(dcon_client, 1)))
7953 + printk(KERN_WARNING "olpc-dcon: unable to reinit dcon"
7954 + " hardware: %d!\n", x);
7956 + dcon_sleep_val = state;
7959 + /* We should turn off some stuff in the framebuffer - but what? */
7962 +/* Set the source of the display (CPU or DCON) */
7964 +static void dcon_source_switch(struct work_struct *work)
7966 + DECLARE_WAITQUEUE(wait, current);
7967 + int source = dcon_pending;
7969 + if (dcon_source == source)
7972 + dcon_switched = 0;
7975 + case DCON_SOURCE_CPU:
7977 + /* Enable the scanline interrupt bit */
7978 + if (dcon_write(DCON_REG_MODE, dcon_disp_mode | MODE_SCAN_INT))
7979 + printk(KERN_ERR "olpc-dcon: couldn't enable scanline interrupt!\n");
7981 + /* Wait up to one second for the scanline interrupt */
7982 + wait_event_timeout(dcon_wait_queue, dcon_switched == 1, HZ);
7985 + if (!dcon_switched)
7986 + printk(KERN_ERR "olpc-dcon: Timeout entering CPU mode; expect a screen glitch.\n");
7989 + * Ideally we'd like to disable interrupts here so that the
7990 + * fb unblanking and DCON turn on happen at a known time value;
7991 + * however, we can't do that right now with fb_blank
7992 + * messing with semaphores.
7994 + * For now, we just hope..
7996 + acquire_console_sem();
7997 + if (fb_blank(fbinfo, FB_BLANK_UNBLANK)) {
7998 + release_console_sem();
7999 + printk(KERN_ERR "olpc-dcon: Failed to enter CPU mode\n");
8000 + dcon_pending = DCON_SOURCE_DCON;
8003 + release_console_sem();
8005 + /* And turn off the DCON */
8006 + outl(1<<11, gpio_base + GPIOx_OUT_VAL);
8008 + /* Turn off the scanline interrupt */
8009 + if (dcon_write(DCON_REG_MODE, dcon_disp_mode))
8010 + printk(KERN_ERR "olpc-dcon: couldn't disable scanline interrupt!\n");
8012 + printk(KERN_INFO "olpc-dcon: The CPU has control\n");
8014 + case DCON_SOURCE_DCON:
8018 + add_wait_queue(&dcon_wait_queue, &wait);
8019 + set_current_state(TASK_UNINTERRUPTIBLE);
8021 + /* Clear GPIO11 (DCONLOAD) - this implies that the DCON is in
8024 + outl(1 << (11 + 16), gpio_base + GPIOx_OUT_VAL);
8026 + t = schedule_timeout(HZ/2);
8027 + remove_wait_queue(&dcon_wait_queue, &wait);
8028 + set_current_state(TASK_RUNNING);
8030 + if (!dcon_switched)
8031 + printk(KERN_ERR "olpc-dcon: Timeout entering DCON mode; expect a screen glitch.\n");
8033 + acquire_console_sem();
8034 + if (fb_blank(fbinfo, FB_BLANK_POWERDOWN))
8035 + printk(KERN_ERR "olpc-dcon: couldn't blank fb!\n");
8036 + release_console_sem();
8038 + printk(KERN_INFO "olpc-dcon: The DCON has control\n");
8045 + dcon_source = source;
8048 +static DECLARE_WORK(dcon_work, dcon_source_switch);
8050 +static int dcon_set_source(int arg)
8052 + if (arg != DCON_SOURCE_CPU && arg != DCON_SOURCE_DCON)
8055 + if (dcon_pending == arg)
8058 + dcon_pending = arg;
8059 + if ((dcon_source != arg) && !work_pending(&dcon_work))
8060 + schedule_work(&dcon_work);
8065 +static int dcon_set_source_sync(int arg)
8067 + int ret = dcon_set_source(arg);
8069 + flush_scheduled_work();
8073 +static int dconbl_set(struct backlight_device *dev) {
8075 + int level = dev->props.brightness;
8077 + if (dev->props.power != FB_BLANK_UNBLANK)
8080 + dcon_set_backlight(level);
8084 +static int dconbl_get(struct backlight_device *dev) {
8085 + return dcon_get_backlight();
8088 +static ssize_t dcon_mode_show(struct device *dev,
8089 + struct device_attribute *attr, char *buf)
8091 + return sprintf(buf, "%4.4X\n", dcon_disp_mode);
8094 +static ssize_t dcon_sleep_show(struct device *dev,
8095 + struct device_attribute *attr, char *buf)
8097 + return sprintf(buf, "%d\n", dcon_sleep_val);
8100 +static ssize_t /* __deprecated */ dcon_source_show(struct device *dev,
8101 + struct device_attribute *attr, char *buf)
8103 + printk(KERN_WARNING "olpc-dcon: using deprecated sysfs 'source' interface; use 'freeze' instead!\n");
8104 + return sprintf(buf, "%d\n", dcon_source);
8107 +static ssize_t dcon_freeze_show(struct device *dev,
8108 + struct device_attribute *attr, char *buf)
8110 + return sprintf(buf, "%d\n", dcon_source == DCON_SOURCE_DCON ? 1 : 0);
8113 +static ssize_t dcon_output_show(struct device *dev,
8114 + struct device_attribute *attr, char *buf)
8116 + return sprintf(buf, "%d\n", dcon_output);
8119 +static ssize_t dcon_resumeline_show(struct device *dev,
8120 + struct device_attribute *attr, char *buf)
8122 + return sprintf(buf, "%d\n", resumeline);
8125 +static int _strtoul(const char *buf, int len, unsigned int *val)
8129 + unsigned int output = simple_strtoul(buf, &endp, 0);
8130 + int size = endp - buf;
8132 + if (*endp && isspace(*endp))
8142 +static ssize_t dcon_output_store(struct device *dev,
8143 + struct device_attribute *attr, const char *buf, size_t count)
8148 + if (_strtoul(buf, count, &output))
8151 + if (output == DCON_OUTPUT_COLOR || output == DCON_OUTPUT_MONO) {
8152 + dcon_set_output(output);
8159 +static ssize_t /* __deprecated */ dcon_source_store(struct device *dev,
8160 + struct device_attribute *attr, const char *buf, size_t count)
8165 + printk(KERN_WARNING "olpc-dcon: using deprecated sysfs 'source' interface; use 'freeze' instead!\n");
8166 + if (_strtoul(buf, count, &output))
8169 + dcon_set_source(output);
8175 +static ssize_t dcon_freeze_store(struct device *dev,
8176 + struct device_attribute *attr, const char *buf, size_t count)
8181 + if (_strtoul(buf, count, &output))
8184 + dcon_set_source(output ? DCON_SOURCE_DCON : DCON_SOURCE_CPU);
8190 +static ssize_t dcon_resumeline_store(struct device *dev,
8191 + struct device_attribute *attr, const char *buf, size_t count)
8196 + if (_strtoul(buf, count, &rl))
8200 + dcon_write(DCON_REG_SCAN_INT, resumeline);
8206 +static ssize_t dcon_sleep_store(struct device *dev,
8207 + struct device_attribute *attr, const char *buf, size_t count)
8211 + if (_strtoul(buf, count, &output))
8214 + dcon_sleep(output ? DCON_SLEEP : DCON_ACTIVE);
8218 +static struct device_attribute dcon_device_files[] = {
8219 + __ATTR(mode, 0444, dcon_mode_show, NULL),
8220 + __ATTR(sleep, 0644, dcon_sleep_show, dcon_sleep_store),
8221 + __ATTR(source, 0644, dcon_source_show, dcon_source_store),
8222 + __ATTR(freeze, 0644, dcon_freeze_show, dcon_freeze_store),
8223 + __ATTR(output, 0644, dcon_output_show, dcon_output_store),
8224 + __ATTR(resumeline, 0644, dcon_resumeline_show, dcon_resumeline_store),
8227 +static struct backlight_ops dcon_bl_ops = {
8228 + .get_brightness = dconbl_get,
8229 + .update_status = dconbl_set
8232 +/* List of GPIOs that we care about:
8233 + (in) GPIO12 -- DCONBLNK
8234 + (in) GPIO[56] -- DCONSTAT[01]
8235 + (out) GPIO11 -- DCONLOAD
8238 +#define IN_GPIOS ((1<<5) | (1<<6) | (1<<7) | (1<<12))
8239 +#define OUT_GPIOS (1<<11)
8241 +static irqreturn_t dcon_interrupt(int, void *);
8243 +static int dcon_request_irq(void)
8245 + unsigned long lo, hi;
8246 + unsigned char lob;
8248 + rdmsr(MSR_LBAR_GPIO, lo, hi);
8250 + /* Check the mask and whether GPIO is enabled (sanity check) */
8251 + if (hi != 0x0000f001) {
8252 + printk(KERN_ERR "GPIO not enabled -- cannot use DCON\n");
8256 + /* Mask off the IO base address */
8257 + gpio_base = lo & 0x0000ff00;
8259 + /* Turn off the event enable for GPIO7 just to be safe */
8260 + outl(1 << (16+7), gpio_base + GPIOx_EVNT_EN);
8262 + /* Set the directions for the GPIO pins */
8263 + outl(OUT_GPIOS | (IN_GPIOS << 16), gpio_base + GPIOx_OUT_EN);
8264 + outl(IN_GPIOS | (OUT_GPIOS << 16), gpio_base + GPIOx_IN_EN);
8266 + /* Set up the interrupt mappings */
8268 + /* Set the IRQ to pair 2 */
8269 + geode_gpio_event_irq(OLPC_GPIO_DCON_IRQ, 2);
8271 + /* Enable group 2 to trigger the DCON interrupt */
8272 + geode_gpio_set_irq(2, DCON_IRQ);
8274 + /* Select edge level for interrupt (in PIC) */
8277 + lob &= ~(1 << DCON_IRQ);
8280 + /* Register the interupt handler */
8281 + if (request_irq(DCON_IRQ, &dcon_interrupt, 0, "DCON", &dcon_driver))
8284 + /* Clear INV_EN for GPIO7 (DCONIRQ) */
8285 + outl((1<<(16+7)), gpio_base + GPIOx_INV_EN);
8287 + /* Enable filter for GPIO12 (DCONBLANK) */
8288 + outl(1<<(12), gpio_base + GPIOx_IN_FLTR_EN);
8290 + /* Disable filter for GPIO7 */
8291 + outl(1<<(16+7), gpio_base + GPIOx_IN_FLTR_EN);
8293 + /* Disable event counter for GPIO7 (DCONIRQ) and GPIO12 (DCONBLANK) */
8295 + outl(1<<(16+7), gpio_base + GPIOx_EVNTCNT_EN);
8296 + outl(1<<(16+12), gpio_base + GPIOx_EVNTCNT_EN);
8298 + /* Add GPIO12 to the Filter Event Pair #7 */
8299 + outb(12, gpio_base + GPIO_FE7_SEL);
8301 + /* Turn off negative Edge Enable for GPIO12 */
8302 + outl(1<<(16+12), gpio_base + GPIOx_NEGEDGE_EN);
8304 + /* Enable negative Edge Enable for GPIO7 */
8305 + outl(1<<7, gpio_base + GPIOx_NEGEDGE_EN);
8307 + /* Zero the filter amount for Filter Event Pair #7 */
8308 + outw(0, gpio_base + GPIO_FLT7_AMNT);
8310 + /* Clear the negative edge status for GPIO7 and GPIO12 */
8311 + outl((1<<7) | (1<<12), gpio_base+0x4c);
8313 + /* FIXME: Clear the posiitive status as well, just to be sure */
8314 + outl((1<<7) | (1<<12), gpio_base+0x48);
8316 + /* Enable events for GPIO7 (DCONIRQ) and GPIO12 (DCONBLANK) */
8317 + outl((1<<(7))|(1<<12), gpio_base + GPIOx_EVNT_EN);
8319 + /* Determine the current state by reading the GPIO bit */
8320 + /* Earlier stages of the boot process have established the state */
8321 + dcon_source = inl(gpio_base + GPIOx_OUT_VAL) & (1<<11)
8323 + : DCON_SOURCE_DCON;
8324 + dcon_pending = dcon_source;
8329 +static int dcon_reboot_notify(struct notifier_block *nb, unsigned long foo, void *bar)
8331 + if (dcon_client == NULL)
8334 + /* Turn off the DCON. Entirely. */
8335 + dcon_write(DCON_REG_MODE, 0x39);
8336 + dcon_write(DCON_REG_MODE, 0x32);
8340 +static int dcon_conswitch_notify(struct notifier_block *nb,
8341 + unsigned long mode, void *dummy)
8343 + if (mode == CONSOLE_EVENT_SWITCH_TEXT)
8344 + dcon_sleep(DCON_ACTIVE);
8349 +static struct notifier_block dcon_nb = {
8350 + .notifier_call = dcon_reboot_notify,
8354 +static struct notifier_block dcon_console_nb = {
8355 + .notifier_call = dcon_conswitch_notify,
8359 +static int unfreeze_on_panic(struct notifier_block *nb, unsigned long e, void *p)
8361 + outl(1<<11, gpio_base + GPIOx_OUT_VAL);
8362 + return NOTIFY_DONE;
8365 +static struct notifier_block dcon_panic_nb = {
8366 + .notifier_call = unfreeze_on_panic,
8369 +static int dcon_probe(struct i2c_adapter *adap, int addr, int kind)
8371 + struct i2c_client *client;
8374 + if (!olpc_has_dcon()) {
8375 + printk("olpc-dcon: No DCON is attached.\n");
8379 + if (num_registered_fb >= 1)
8380 + fbinfo = registered_fb[0];
8382 + if (adap->id != I2C_HW_SMBUS_SCX200) {
8383 + printk(KERN_ERR "olpc-dcon: Invalid I2C bus (%d not %d)\n",
8384 + adap->id, I2C_HW_SMBUS_SCX200);
8388 + client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
8389 + if (client == NULL)
8392 + strncpy(client->name, "OLPC-DCON", I2C_NAME_SIZE);
8393 + client->addr = addr;
8394 + client->adapter = adap;
8395 + client->driver = &dcon_driver;
8397 + if ((rc = i2c_attach_client(client)) != 0) {
8398 + printk(KERN_ERR "olpc-dcon: Unable to attach the I2C client.\n");
8402 + rc = dcon_hw_init(client, 1);
8406 + /* Add the DCON device */
8408 + dcon_device = platform_device_alloc("dcon", -1);
8410 + if (dcon_device == NULL) {
8411 + printk(KERN_ERR "dcon: Unable to create the DCON device\n");
8416 + if ((rc = platform_device_add(dcon_device))) {
8417 + printk(KERN_ERR "dcon: Unable to add the DCON device\n");
8421 + for(i = 0; i < ARRAY_SIZE(dcon_device_files); i++)
8422 + device_create_file(&dcon_device->dev, &dcon_device_files[i]);
8424 + /* Add the backlight device for the DCON */
8426 + dcon_client = client;
8428 + dcon_bl_dev = backlight_device_register("dcon-bl", &dcon_device->dev,
8429 + NULL, &dcon_bl_ops);
8431 + if (IS_ERR(dcon_bl_dev)) {
8432 + printk(KERN_INFO "Could not register the backlight device for the DCON (%ld)\n", PTR_ERR(dcon_bl_dev));
8433 + dcon_bl_dev = NULL;
8436 + dcon_bl_dev->props.max_brightness = 15;
8437 + dcon_bl_dev->props.power = FB_BLANK_UNBLANK;
8438 + dcon_bl_dev->props.brightness = dcon_get_backlight();
8440 + backlight_update_status(dcon_bl_dev);
8443 + register_reboot_notifier(&dcon_nb);
8444 + console_event_register(&dcon_console_nb);
8445 + atomic_notifier_chain_register(&panic_notifier_list, &dcon_panic_nb);
8450 + platform_device_unregister(dcon_device);
8451 + dcon_device = NULL;
8453 + free_irq(DCON_IRQ, &dcon_driver);
8455 + i2c_detach_client(client);
8462 +static int dcon_attach(struct i2c_adapter *adap)
8466 + ret = i2c_probe(adap, &addr_data, dcon_probe);
8468 + if (dcon_client == NULL)
8469 + printk(KERN_ERR "olpc-dcon: No DCON found on SMBus\n");
8474 +static int dcon_detach(struct i2c_client *client)
8477 + dcon_client = NULL;
8479 + unregister_reboot_notifier(&dcon_nb);
8480 + console_event_unregister(&dcon_console_nb);
8481 + atomic_notifier_chain_unregister(&panic_notifier_list, &dcon_panic_nb);
8483 + free_irq(DCON_IRQ, &dcon_driver);
8485 + if ((rc = i2c_detach_client(client)) == 0)
8486 + kfree(i2c_get_clientdata(client));
8488 + if (dcon_bl_dev != NULL)
8489 + backlight_device_unregister(dcon_bl_dev);
8491 + if (dcon_device != NULL)
8492 + platform_device_unregister(dcon_device);
8493 + cancel_work_sync(&dcon_work);
8500 +static int dcon_suspend(struct i2c_client *client, pm_message_t state)
8502 + if (dcon_sleep_val != DCON_ACTIVE)
8505 + /* Set up the DCON to have the source */
8506 + return dcon_set_source_sync(DCON_SOURCE_DCON);
8509 +static int dcon_resume(struct i2c_client *client)
8511 + if (dcon_sleep_val != DCON_ACTIVE)
8514 + dcon_bus_stabilize(client, 0);
8516 + return dcon_set_source(DCON_SOURCE_CPU);
8521 +static irqreturn_t dcon_interrupt(int irq, void *id)
8523 + int status = inl(gpio_base + GPIOx_READ_BACK) >> 5;
8525 + /* Clear the negative edge status for GPIO7 */
8526 + outl(1 << 7, gpio_base + GPIOx_NEGEDGE_STS);
8528 + switch (status & 3) {
8530 + printk(KERN_DEBUG "olpc-dcon: DCONLOAD_MISSED interrupt\n");
8532 + case 2: /* switch to DCON mode */
8533 + case 1: /* switch to CPU mode */
8534 + dcon_switched = 1;
8535 + wake_up(&dcon_wait_queue);
8538 + printk(KERN_DEBUG "olpc-dcon: scanline interrupt w/CPU\n");
8541 + return IRQ_HANDLED;
8544 +static struct i2c_driver dcon_driver = {
8546 + .name = "OLPC-DCON",
8548 + .id = I2C_DRIVERID_DCON,
8549 + .attach_adapter = dcon_attach,
8550 + .detach_client = dcon_detach,
8552 + .suspend = dcon_suspend,
8553 + .resume = dcon_resume,
8558 +static int __init olpc_dcon_init(void)
8560 + i2c_add_driver(&dcon_driver);
8564 +static void __exit olpc_dcon_exit(void)
8566 + i2c_del_driver(&dcon_driver);
8569 +module_init(olpc_dcon_init);
8570 +module_exit(olpc_dcon_exit);
8572 +MODULE_LICENSE("GPL");
8573 Binary files linux_2.6.24_org/drivers/video/.olpc_dcon.c.swp and linux_2.6.24_olpc/drivers/video/.olpc_dcon.c.swp differ
8574 diff -purN linux_2.6.24_org/drivers/video/olpc_dcon.h linux_2.6.24_olpc/drivers/video/olpc_dcon.h
8575 --- linux_2.6.24_org/drivers/video/olpc_dcon.h 1970-01-01 01:00:00.000000000 +0100
8576 +++ linux_2.6.24_olpc/drivers/video/olpc_dcon.h 2008-02-15 18:58:35.000000000 +0000
8578 +#ifndef OLPC_DCON_H_
8579 +#define OLPC_DCON_H_
8581 +/* DCON registers */
8583 +#define DCON_REG_ID 0
8584 +#define DCON_REG_MODE 1
8586 +#define MODE_PASSTHRU (1<<0)
8587 +#define MODE_SLEEP (1<<1)
8588 +#define MODE_SLEEP_AUTO (1<<2)
8589 +#define MODE_BL_ENABLE (1<<3)
8590 +#define MODE_BLANK (1<<4)
8591 +#define MODE_CSWIZZLE (1<<5)
8592 +#define MODE_COL_AA (1<<6)
8593 +#define MODE_MONO_LUMA (1<<7)
8594 +#define MODE_SCAN_INT (1<<8)
8595 +#define MODE_CLOCKDIV (1<<9)
8596 +#define MODE_DEBUG (1<<14)
8597 +#define MODE_SELFTEST (1<<15)
8599 +#define DCON_REG_HRES 2
8600 +#define DCON_REG_HTOTAL 3
8601 +#define DCON_REG_HSYNC_WIDTH 4
8602 +#define DCON_REG_VRES 5
8603 +#define DCON_REG_VTOTAL 6
8604 +#define DCON_REG_VSYNC_WIDTH 7
8605 +#define DCON_REG_TIMEOUT 8
8606 +#define DCON_REG_SCAN_INT 9
8607 +#define DCON_REG_BRIGHT 10
8609 +/* GPIO registers (CS5536) */
8611 +#define MSR_LBAR_GPIO 0x5140000C
8613 +#define GPIOx_OUT_VAL 0x00
8614 +#define GPIOx_OUT_EN 0x04
8615 +#define GPIOx_IN_EN 0x20
8616 +#define GPIOx_INV_EN 0x24
8617 +#define GPIOx_IN_FLTR_EN 0x28
8618 +#define GPIOx_EVNTCNT_EN 0x2C
8619 +#define GPIOx_READ_BACK 0x30
8620 +#define GPIOx_EVNT_EN 0x38
8621 +#define GPIOx_NEGEDGE_EN 0x44
8622 +#define GPIOx_NEGEDGE_STS 0x4C
8623 +#define GPIO_FLT7_AMNT 0xD8
8624 +#define GPIO_MAP_X 0xE0
8625 +#define GPIO_MAP_Y 0xE4
8626 +#define GPIO_FE7_SEL 0xF7
8629 +/* Status values */
8631 +#define DCONSTAT_SCANINT 0
8632 +#define DCONSTAT_SCANINT_DCON 1
8633 +#define DCONSTAT_DISPLAYLOAD 2
8634 +#define DCONSTAT_MISSED 3
8636 +/* Source values */
8638 +#define DCON_SOURCE_DCON 0
8639 +#define DCON_SOURCE_CPU 1
8641 +/* Output values */
8642 +#define DCON_OUTPUT_COLOR 0
8643 +#define DCON_OUTPUT_MONO 1
8646 +#define DCON_ACTIVE 0
8647 +#define DCON_SLEEP 1
8653 diff -purN linux_2.6.24_org/fs/jffs2/nodelist.h linux_2.6.24_olpc/fs/jffs2/nodelist.h
8654 --- linux_2.6.24_org/fs/jffs2/nodelist.h 2008-02-15 20:10:35.000000000 +0000
8655 +++ linux_2.6.24_olpc/fs/jffs2/nodelist.h 2008-02-15 18:57:39.000000000 +0000
8656 @@ -197,7 +197,7 @@ struct jffs2_inode_cache {
8657 #define RAWNODE_CLASS_XATTR_DATUM 1
8658 #define RAWNODE_CLASS_XATTR_REF 2
8660 -#define INOCACHE_HASHSIZE 128
8661 +#define INOCACHE_HASHSIZE 1024
8663 #define write_ofs(c) ((c)->nextblock->offset + (c)->sector_size - (c)->nextblock->free_size)
8665 diff -purN linux_2.6.24_org/fs/Kconfig linux_2.6.24_olpc/fs/Kconfig
8666 --- linux_2.6.24_org/fs/Kconfig 2008-02-15 20:10:31.000000000 +0000
8667 +++ linux_2.6.24_olpc/fs/Kconfig 2008-02-15 18:57:33.000000000 +0000
8668 @@ -1031,6 +1031,37 @@ config HUGETLBFS
8673 + tristate "PromFS IEEE 1275 file system support"
8674 + depends on SPARC || PPC || OLPC
8676 + PromFS is a file system interface to various IEEE-1275 compatible
8677 + firmwares. If you have such a firmware (Sparc64, PowerPC, and
8678 + some other architectures and embedded systems have such firmwares,
8679 + with names like "OpenBoot (tm)" and "OpenFirmware"), say Y here
8680 + to be able to access the firmware's device-tree from Linux.
8682 + The firmware device-tree is available as a virtual file system,
8683 + can be mounted under /prom with the command "mount -t promfs
8686 + To compile PromFS support as a module, choose M here; the module
8687 + will be called promfs. If unsure, choose M.
8693 + Ramfs is a file system which keeps all files in RAM. It allows
8694 + read and write access.
8696 + It is more of an programming example than a useable file system. If
8697 + you need a file system which lives in RAM with limit checking use
8700 + To compile this as a module, choose M here: the module will be called
8704 tristate "Userspace-driven configuration filesystem (EXPERIMENTAL)"
8705 depends on SYSFS && EXPERIMENTAL
8706 diff -purN linux_2.6.24_org/fs/Makefile linux_2.6.24_olpc/fs/Makefile
8707 --- linux_2.6.24_org/fs/Makefile 2008-02-15 20:10:33.000000000 +0000
8708 +++ linux_2.6.24_olpc/fs/Makefile 2008-02-15 18:57:34.000000000 +0000
8709 @@ -110,6 +110,7 @@ obj-$(CONFIG_ADFS_FS) += adfs/
8710 obj-$(CONFIG_FUSE_FS) += fuse/
8711 obj-$(CONFIG_UDF_FS) += udf/
8712 obj-$(CONFIG_SUN_OPENPROMFS) += openpromfs/
8713 +obj-$(CONFIG_PROMFS_FS) += promfs/
8714 obj-$(CONFIG_JFS_FS) += jfs/
8715 obj-$(CONFIG_XFS_FS) += xfs/
8716 obj-$(CONFIG_9P_FS) += 9p/
8717 diff -purN linux_2.6.24_org/fs/promfs/Makefile linux_2.6.24_olpc/fs/promfs/Makefile
8718 --- linux_2.6.24_org/fs/promfs/Makefile 1970-01-01 01:00:00.000000000 +0100
8719 +++ linux_2.6.24_olpc/fs/promfs/Makefile 2008-02-15 18:57:33.000000000 +0000
8721 +obj-$(CONFIG_PROMFS_FS) += promfs.o
8722 diff -purN linux_2.6.24_org/fs/promfs/promfs.c linux_2.6.24_olpc/fs/promfs/promfs.c
8723 --- linux_2.6.24_org/fs/promfs/promfs.c 1970-01-01 01:00:00.000000000 +0100
8724 +++ linux_2.6.24_olpc/fs/promfs/promfs.c 2008-02-15 18:57:33.000000000 +0000
8727 + * promfs.c - generic inode/dentry functions for IEEE 1275-based filesystems.
8729 + * This is based heavily upon prior ieee1275 and other virtual filesystems
8730 + * implementations; openpromfs, proc_devtree.c, oprofilefs, procfs, ...
8732 + * Copyright (C) 2007 Andres Salomon <dilinger@debian.org>
8734 + * This program is free software; you can redistribute it and/or modify
8735 + * it under the terms of the GNU General Public License as published by
8736 + * the Free Software Foundation; either version 2 of the License, or
8737 + * (at your option) any later version.
8739 + * This program is distributed in the hope that it will be useful,
8740 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
8741 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
8742 + * GNU General Public License for more details.
8744 + * You should have received a copy of the GNU General Public License along
8745 + * with this program; if not, write to the Free Software Foundation, Inc.,
8746 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
8749 +#include <linux/init.h>
8750 +#include <linux/module.h>
8751 +#include <linux/pagemap.h>
8752 +#include <linux/fs.h>
8753 +//#include <linux/promfs.h>
8754 +#include <asm/prom.h>
8756 +#define PROMFS_MAGIC 0x1f2f3fff
8758 +MODULE_LICENSE("GPL");
8759 +MODULE_AUTHOR("Andres Salomon");
8761 +struct promfs_inode
8764 + struct property *prop;
8767 +static inline struct promfs_inode *to_promfs_inode(struct inode *inode)
8769 + return container_of(inode, struct promfs_inode, ino);
8773 +static DEFINE_SPINLOCK(promfs_lock);
8775 +static struct of_node *of_tree = NULL;
8776 +static DEFINE_RWLOCK(of_tree_lock);
8778 +void __init of_build_tree(void)
8785 +static int promfs_open_file(struct inode *inode, struct file *file)
8787 + struct promfs_inode *ino;
8789 + ino = to_promfs_inode(inode);
8792 + file->private_data = ino->prop;
8797 +static ssize_t promfs_read_file(struct file *file, char __user *data,
8798 + size_t len, loff_t *ppos)
8800 + struct property *prop = (struct property *) file->private_data;
8801 + return simple_read_from_buffer(data, len, ppos, prop->value,
8805 +static ssize_t promfs_write_file(struct file *file, char const __user *buf,
8806 + size_t count, loff_t * offset)
8808 + /* TODO.... 'cause, y'know, it would be nice. */
8812 +static struct file_operations promfs_file_ops = {
8813 + .open = promfs_open_file,
8814 + .read = promfs_read_file,
8815 + .write = promfs_write_file,
8818 +static struct kmem_cache *promfs_inode_cachep;
8820 +static struct inode *promfs_alloc_inode(struct super_block *sb)
8822 + struct promfs_inode *pr_ino;
8824 + pr_ino = kmem_cache_alloc(promfs_inode_cachep, GFP_KERNEL);
8827 + pr_ino->prop = NULL;
8829 + return &pr_ino->ino;
8832 +static void promfs_destroy_inode(struct inode *inode)
8834 + kmem_cache_free(promfs_inode_cachep, to_promfs_inode(inode));
8837 +static void promfs_read_inode(struct inode *inode)
8839 + inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
8842 +static int promfs_remount(struct super_block *sb, int *flags, char *data)
8844 + *flags |= MS_NOATIME;
8848 +static struct super_operations promfs_s_ops = {
8849 + .alloc_inode = promfs_alloc_inode,
8850 + .destroy_inode = promfs_destroy_inode,
8851 + .read_inode = promfs_read_inode,
8852 + .statfs = simple_statfs,
8853 + .drop_inode = generic_delete_inode,
8854 + .remount_fs = promfs_remount,
8857 +static struct inode *promfs_get_inode(struct super_block *sb, int mode)
8859 + struct inode *inode = new_inode(sb);
8862 + inode->i_mode = mode;
8865 + inode->i_blocks = 0;
8866 + inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
8872 +static int promfs_create_file(struct super_block *sb, struct dentry *root,
8873 + struct property *prop, const struct file_operations *fops)
8875 + struct dentry *dentry;
8876 + struct inode *inode;
8877 + struct promfs_inode *ino;
8879 + dentry = d_alloc_name(root, prop->name);
8883 + inode = promfs_get_inode(sb, S_IFREG | 0644);
8886 + inode->i_fop = fops;
8887 + ino = to_promfs_inode(inode);
8889 + d_add(dentry, inode);
8899 +struct dentry *promfs_create_dir(struct super_block *sb, struct dentry *root,
8902 + struct dentry *dentry;
8903 + struct inode *inode;
8905 + dentry = d_alloc_name(root, name);
8909 + inode = promfs_get_inode(sb, S_IFDIR | 0755);
8912 + inode->i_op = &simple_dir_inode_operations;
8913 + inode->i_fop = &simple_dir_operations;
8914 + d_add(dentry, inode);
8923 +void promfs_populate(struct super_block *sb, struct dentry *root,
8924 + struct device_node *node)
8926 + struct dentry *dentry;
8927 + struct device_node *child;
8928 + struct property *prop;
8933 + for (child = node->child; child; child = child->sibling) {
8934 + dentry = promfs_create_dir(sb, root, child->path_component_name);
8935 + promfs_populate(sb, dentry, child);
8937 + for (prop = node->properties; prop; prop = prop->next)
8938 + promfs_create_file(sb, root, prop, &promfs_file_ops);
8941 +static int promfs_fill_super(struct super_block *sb, void *data, int silent)
8943 + struct inode *root_inode;
8944 + struct dentry *root_dentry;
8945 + struct promfs_inode *inode;
8947 + sb->s_blocksize = PAGE_CACHE_SIZE;
8948 + sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
8949 + sb->s_magic = PROMFS_MAGIC;
8950 + sb->s_op = &promfs_s_ops;
8951 + sb->s_time_gran = 1;
8952 + sb->s_flags |= MS_NOATIME;
8954 + root_inode = promfs_get_inode(sb, S_IFDIR | 0755);
8957 + root_inode->i_op = &simple_dir_inode_operations;
8958 + root_inode->i_fop = &simple_dir_operations;
8960 + inode = to_promfs_inode(root_inode);
8962 + root_dentry = d_alloc_root(root_inode);
8965 + sb->s_root = root_dentry;
8967 + promfs_populate(sb, root_dentry, of_find_node_by_path("/"));
8976 +static int promfs_get_sb(struct file_system_type *fs_type, int flags,
8977 + const char *dev_name, void *data, struct vfsmount *mnt)
8979 + return get_sb_single(fs_type, flags, data, promfs_fill_super, mnt);
8982 +static struct file_system_type promfs_fs_type = {
8983 + .owner = THIS_MODULE,
8985 + .get_sb = promfs_get_sb,
8986 + .kill_sb = kill_litter_super,
8989 +static void init_once(void *i, struct kmem_cache *cachep, unsigned long fl)
8991 + struct promfs_inode *inode = (struct promfs_inode *) i;
8992 + inode_init_once(&inode->ino);
8995 +static int __init init_promfs(void)
8999 + prom_build_devicetree();
9000 + promfs_inode_cachep = kmem_cache_create("promfs_inode_cache",
9001 + sizeof(struct promfs_inode), 0,
9002 + SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, init_once, NULL);
9003 + if (!promfs_inode_cachep)
9006 + err = register_filesystem(&promfs_fs_type);
9008 + kmem_cache_destroy(promfs_inode_cachep);
9013 +static void __exit exit_promfs(void)
9015 + unregister_filesystem(&promfs_fs_type);
9016 + kmem_cache_destroy(promfs_inode_cachep);
9019 +module_init(init_promfs);
9020 +module_exit(exit_promfs);
9021 diff -purN linux_2.6.24_org/include/asm-x86/ofw.h linux_2.6.24_olpc/include/asm-x86/ofw.h
9022 --- linux_2.6.24_org/include/asm-x86/ofw.h 1970-01-01 01:00:00.000000000 +0100
9023 +++ linux_2.6.24_olpc/include/asm-x86/ofw.h 2008-02-15 18:57:59.000000000 +0000
9026 + * Definitions for Open Firmware client interface on 32-bit system.
9027 + * OF Cell size is 4. Integer properties are encoded big endian,
9028 + * as with all OF implementations.
9030 + * This program is free software; you can redistribute it and/or
9031 + * modify it under the terms of the GNU General Public License
9032 + * as published by the Free Software Foundation; either version
9033 + * 2 of the License, or (at your option) any later version.
9038 +extern int ofw(char *, int, int, ...);
9041 diff -purN linux_2.6.24_org/include/asm-x86/olpc.h linux_2.6.24_olpc/include/asm-x86/olpc.h
9042 --- linux_2.6.24_org/include/asm-x86/olpc.h 1970-01-01 01:00:00.000000000 +0100
9043 +++ linux_2.6.24_olpc/include/asm-x86/olpc.h 2008-02-15 18:57:59.000000000 +0000
9045 +/* OLPC machine specific definitions */
9047 +#ifndef ASM_OLPC_H_
9048 +#define ASM_OLPC_H_
9050 +#include <asm/geode.h>
9052 +struct olpc_platform_t {
9058 +#define OLPC_F_PRESENT 0x01
9059 +#define OLPC_F_DCON 0x02
9060 +#define OLPC_F_VSA 0x04
9063 + * OLPC board IDs contain the major build number within the mask 0x0ff0,
9064 + * and the minor build number withing 0x000f. Pre-builds have a minor
9065 + * number less than 8, and normal builds start at 8. For example, 0x0B10
9066 + * is a PreB1, and 0x0C18 is a C1.
9069 +static inline u32 olpc_board(u8 id)
9071 + return (id << 4) | 0x8;
9074 +static inline u32 olpc_board_pre(u8 id)
9079 +#ifndef CONFIG_OLPC
9081 +static inline int machine_is_olpc(void) { return 0; }
9082 +static inline int olpc_has_dcon(void) { return 0; }
9083 +static inline int olpc_has_vsa(void) { return 0; }
9087 +extern struct olpc_platform_t olpc_platform_info;
9090 +machine_is_olpc(void)
9092 + return (olpc_platform_info.flags & OLPC_F_PRESENT) ? 1 : 0;
9096 +olpc_has_dcon(void)
9098 + return (olpc_platform_info.flags & OLPC_F_DCON) ? 1 : 0;
9104 + return (olpc_platform_info.flags & OLPC_F_VSA) ? 1 : 0;
9107 +static inline int olpc_board_at_least(u32 rev)
9109 + return olpc_platform_info.boardrev >= rev;
9116 +int olpc_ec_cmd(unsigned char cmd, unsigned char *inbuf, size_t inlen,
9117 + unsigned char *outbuf, size_t outlen);
9119 +void olpc_register_battery_callback(void (*f)(unsigned long));
9120 +void olpc_deregister_battery_callback(void);
9122 +/* EC commands and responses */
9124 +/* SCI source values */
9126 +#define EC_SCI_SRC_EMPTY 0x00
9127 +#define EC_SCI_SRC_GAME 0x01
9128 +#define EC_SCI_SRC_BATTERY 0x02
9129 +#define EC_SCI_SRC_BATSOC 0x04
9130 +#define EC_SCI_SRC_BATERR 0x08
9131 +#define EC_SCI_SRC_EBOOK 0x10
9132 +#define EC_SCI_SRC_WLAN 0x20
9133 +#define EC_SCI_SRC_ACPWR 0x40
9134 +#define EC_SCI_SRC_ALL 0x7F
9136 +int olpc_ec_mask_set(u8 bits);
9137 +int olpc_ec_mask_unset(u8 bits);
9139 +/* GPIO assignments */
9141 +#define OLPC_GPIO_MIC_AC (1 << 1)
9142 +#define OLPC_GPIO_DCON_IRQ (1 << 7)
9143 +#define OLPC_GPIO_THRM_ALRM (1 << 10)
9144 +#define OLPC_GPIO_SMB_CLK (1 << 14)
9145 +#define OLPC_GPIO_SMB_DATA (1 << 15)
9146 +#define OLPC_GPIO_WORKAUX (1 << 24)
9147 +#define OLPC_GPIO_LID (1 << 26)
9148 +#define OLPC_GPIO_ECSCI (1 << 27)
9152 diff -purN linux_2.6.24_org/include/asm-x86/prom.h linux_2.6.24_olpc/include/asm-x86/prom.h
9153 --- linux_2.6.24_org/include/asm-x86/prom.h 1970-01-01 01:00:00.000000000 +0100
9154 +++ linux_2.6.24_olpc/include/asm-x86/prom.h 2008-02-15 18:57:59.000000000 +0000
9156 +#ifndef _I386_PROM_H
9157 +#define _I386_PROM_H
9162 + * Definitions for talking to the Open Firmware PROM on
9163 + * Power Macintosh computers.
9165 + * Copyright (C) 1996-2005 Paul Mackerras.
9167 + * Updates for PPC64 by Peter Bergner & David Engebretsen, IBM Corp.
9168 + * Updates for SPARC64 by David S. Miller
9169 + * Updates for i386/OLPC by Andres Salomon
9171 + * This program is free software; you can redistribute it and/or
9172 + * modify it under the terms of the GNU General Public License
9173 + * as published by the Free Software Foundation; either version
9174 + * 2 of the License, or (at your option) any later version.
9177 +#include <linux/types.h>
9178 +#include <linux/proc_fs.h>
9179 +#include <asm/atomic.h>
9181 +typedef u32 phandle;
9182 +typedef u32 ihandle;
9188 + struct property *next;
9191 +struct device_node {
9195 +// phandle linux_phandle;
9196 + char *path_component_name;
9199 + struct property *properties;
9200 + struct property *deadprops; /* removed properties */
9201 + struct device_node *parent;
9202 + struct device_node *child;
9203 + struct device_node *sibling;
9204 + struct device_node *next; /* next device of same type */
9205 + struct device_node *allnext; /* next in list of all nodes */
9206 + struct proc_dir_entry *pde; /* this node's proc directory */
9208 + unsigned long _flags;
9212 +/* flag descriptions */
9213 +#define OF_DYNAMIC 1 /* node and properties were allocated via kmalloc */
9215 +#define OF_IS_DYNAMIC(x) test_bit(OF_DYNAMIC, &x->_flags)
9216 +#define OF_MARK_DYNAMIC(x) set_bit(OF_DYNAMIC, &x->_flags)
9218 +#define OF_BAD_ADDR ((u64)-1)
9220 +static inline void set_node_proc_entry(struct device_node *dn, struct proc_dir_entry *de)
9225 +extern struct device_node *of_find_node_by_name(struct device_node *from,
9226 + const char *name);
9227 +#define for_each_node_by_name(dn, name) \
9228 + for (dn = of_find_node_by_name(NULL, name); dn; \
9229 + dn = of_find_node_by_name(dn, name))
9230 +extern struct device_node *of_find_node_by_type(struct device_node *from,
9231 + const char *type);
9232 +#define for_each_node_by_type(dn, type) \
9233 + for (dn = of_find_node_by_type(NULL, type); dn; \
9234 + dn = of_find_node_by_type(dn, type))
9235 +extern struct device_node *of_find_compatible_node(struct device_node *from,
9236 + const char *type, const char *compat);
9237 +extern struct device_node *of_find_node_by_path(const char *path);
9238 +extern struct device_node *of_find_node_by_phandle(phandle handle);
9239 +extern struct device_node *of_get_parent(const struct device_node *node);
9240 +extern struct device_node *of_get_next_child(const struct device_node *node,
9241 + struct device_node *prev);
9242 +extern struct property *of_find_property(const struct device_node *np,
9245 +//extern struct device_node *of_node_get(struct device_node *node);
9246 +//extern void of_node_put(struct device_node *node);
9247 +extern int of_device_is_compatible(const struct device_node *device,
9249 +extern const void *of_get_property(const struct device_node *node,
9252 +#define get_property(node,name,lenp) of_get_property(node,name,lenp)
9253 +extern int of_set_property(struct device_node *node, const char *name, void *val, int len);
9254 +extern int of_getintprop_default(struct device_node *np,
9257 +extern int of_n_addr_cells(struct device_node *np);
9258 +extern int of_n_size_cells(struct device_node *np);
9260 +extern void prom_build_devicetree(void);
9262 +#endif /* __KERNEL__ */
9264 diff -purN linux_2.6.24_org/include/linux/battery.h linux_2.6.24_olpc/include/linux/battery.h
9265 --- linux_2.6.24_org/include/linux/battery.h 1970-01-01 01:00:00.000000000 +0100
9266 +++ linux_2.6.24_olpc/include/linux/battery.h 2008-02-15 18:58:06.000000000 +0000
9269 + * Driver model for batteries
9271 + * © 2006 David Woodhouse <dwmw2@infradead.org>
9273 + * Based on LED Class support, by John Lenz and Richard Purdie:
9275 + * © 2005 John Lenz <lenz@cs.wisc.edu>
9276 + * © 2005-2006 Richard Purdie <rpurdie@openedhand.com>
9278 + * This program is free software; you can redistribute it and/or modify
9279 + * it under the terms of the GNU General Public License version 2 as
9280 + * published by the Free Software Foundation.
9283 +#ifndef __LINUX_BATTERY_H__
9284 +#define __LINUX_BATTERY_H__
9287 +struct class_device;
9292 +#define PWRDEV_TYPE_BATTERY 0
9293 +#define PWRDEV_TYPE_AC 1
9295 +#define BAT_STAT_PRESENT (1<<0)
9296 +#define BAT_STAT_LOW (1<<1)
9297 +#define BAT_STAT_FULL (1<<2)
9298 +#define BAT_STAT_CHARGING (1<<3)
9299 +#define BAT_STAT_DISCHARGING (1<<4)
9300 +#define BAT_STAT_OVERTEMP (1<<5)
9301 +#define BAT_STAT_CRITICAL (1<<6)
9302 +#define BAT_STAT_FIRE (1<<7)
9303 +#define BAT_STAT_CHARGE_DONE (1<<8)
9305 +/* Thou shalt not export any attributes in sysfs except these, and
9306 + with these units: */
9307 +#define BAT_INFO_STATUS "status" /* Not free-form. Use
9308 + provided function */
9309 +#define BAT_INFO_TEMP1 "temp1" /* °C/1000 */
9310 +#define BAT_INFO_TEMP1_NAME "temp1_name" /* string */
9312 +#define BAT_INFO_TEMP2 "temp2" /* °C/1000 */
9313 +#define BAT_INFO_TEMP2_NAME "temp2_name" /* string */
9315 +#define BAT_INFO_VOLTAGE "voltage" /* mV */
9316 +#define BAT_INFO_VOLTAGE_DESIGN "voltage_design" /* mV */
9318 +#define BAT_INFO_CURRENT "current" /* mA */
9319 +#define BAT_INFO_CURRENT_NOW "current_now" /* mA */
9321 +#define BAT_INFO_POWER "power" /* mW */
9322 +#define BAT_INFO_POWER_NOW "power_now" /* mW */
9324 +/* The following capacity/charge properties are represented in either
9325 + mA or mW. The CAP_UNITS property MUST be provided if any of these are. */
9326 +#define BAT_INFO_RATE "rate" /* CAP_UNITS */
9327 +#define BAT_INFO_CAP_LEFT "capacity_left" /* CAP_UNITS*h */
9328 +#define BAT_INFO_CAP_DESIGN "capacity_design" /* CAP_UNITS*h */
9329 +#define BAT_INFO_CAP_LAST_FULL "capacity_last_full" /* CAP_UNITS*h */
9330 +#define BAT_INFO_CAP_LOW "capacity_low_thresh" /* CAP_UNITS*h */
9331 +#define BAT_INFO_CAP_WARN "capacity_warn_thresh" /* CAP_UNITS*h */
9332 +#define BAT_INFO_CAP_UNITS "capacity_units" /* string: must be
9333 + either mA or mW */
9335 +#define BAT_INFO_CAP_PCT "capacity_percentage" /* integer */
9337 +#define BAT_INFO_TIME_EMPTY "time_to_empty" /* seconds */
9338 +#define BAT_INFO_TIME_EMPTY_NOW "time_to_empty_now" /* seconds */
9339 +#define BAT_INFO_TIME_FULL "time_to_full" /* seconds */
9340 +#define BAT_INFO_TIME_FULL_NOW "time_to_full_now" /* seconds */
9342 +#define BAT_INFO_MANUFACTURER "manufacturer" /* string */
9343 +#define BAT_INFO_TECHNOLOGY "technology" /* string */
9344 +#define BAT_INFO_MODEL "model" /* string */
9345 +#define BAT_INFO_SERIAL "serial" /* string */
9346 +#define BAT_INFO_OEM_INFO "oem_info" /* string */
9348 +#define BAT_INFO_CYCLE_COUNT "cycle_count" /* integer */
9349 +#define BAT_INFO_DATE_MFR "date_manufactured" /* YYYY[-MM[-DD]] */
9350 +#define BAT_INFO_DATE_FIRST_USE "date_first_use" /* YYYY[-MM[-DD]] */
9352 +struct battery_dev {
9358 + struct device *dev;
9361 +int battery_device_register(struct device *parent,
9362 + struct battery_dev *battery_cdev);
9363 +void battery_device_unregister(struct battery_dev *battery_cdev);
9366 +ssize_t battery_attribute_show_status(char *buf, unsigned long status);
9367 +ssize_t battery_attribute_show_ac_status(char *buf, unsigned long status);
9368 +#endif /* __LINUX_BATTERY_H__ */
9369 diff -purN linux_2.6.24_org/include/linux/fb.h linux_2.6.24_olpc/include/linux/fb.h
9370 --- linux_2.6.24_org/include/linux/fb.h 2008-02-15 20:10:55.000000000 +0000
9371 +++ linux_2.6.24_olpc/include/linux/fb.h 2008-02-15 18:58:01.000000000 +0000
9372 @@ -666,6 +666,12 @@ struct fb_ops {
9373 /* restore saved state */
9374 void (*fb_restore_state)(struct fb_info *info);
9376 + /* Shut down the graphics engine to save power */
9377 + int (*fb_powerdown)(struct fb_info *info);
9379 + /* Power it back up */
9380 + int (*fb_powerup)(struct fb_info *info);
9382 /* get capability given var */
9383 void (*fb_get_caps)(struct fb_info *info, struct fb_blit_caps *caps,
9384 struct fb_var_screeninfo *var);
9385 @@ -945,6 +951,9 @@ extern int fb_get_color_depth(struct fb_
9386 extern int fb_get_options(char *name, char **option);
9387 extern int fb_new_modelist(struct fb_info *info);
9389 +extern int fb_powerdown(struct fb_info *info);
9390 +extern int fb_powerup(struct fb_info *info);
9392 extern struct fb_info *registered_fb[FB_MAX];
9393 extern int num_registered_fb;
9394 extern struct class *fb_class;
9395 diff -purN linux_2.6.24_org/include/linux/i2c-id.h linux_2.6.24_olpc/include/linux/i2c-id.h
9396 --- linux_2.6.24_org/include/linux/i2c-id.h 2008-02-15 20:10:52.000000000 +0000
9397 +++ linux_2.6.24_olpc/include/linux/i2c-id.h 2008-02-15 18:58:00.000000000 +0000
9399 #define I2C_DRIVERID_LM4857 92 /* LM4857 Audio Amplifier */
9400 #define I2C_DRIVERID_VP27SMPX 93 /* Panasonic VP27s tuner internal MPX */
9401 #define I2C_DRIVERID_CS4270 94 /* Cirrus Logic 4270 audio codec */
9402 +#define I2C_DRIVERID_DCON 95
9404 #define I2C_DRIVERID_I2CDEV 900
9405 #define I2C_DRIVERID_ARP 902 /* SMBus ARP Client */
9406 diff -purN linux_2.6.24_org/include/linux/isl_38xx.h linux_2.6.24_olpc/include/linux/isl_38xx.h
9407 --- linux_2.6.24_org/include/linux/isl_38xx.h 1970-01-01 01:00:00.000000000 +0100
9408 +++ linux_2.6.24_olpc/include/linux/isl_38xx.h 2008-02-15 18:58:05.000000000 +0000
9411 + * Copyright (C) 2002 Intersil Americas Inc.
9413 + * This program is free software; you can redistribute it and/or modify
9414 + * it under the terms of the GNU General Public License as published by
9415 + * the Free Software Foundation; either version 2 of the License
9417 + * This program is distributed in the hope that it will be useful,
9418 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
9419 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9420 + * GNU General Public License for more details.
9422 + * You should have received a copy of the GNU General Public License
9423 + * along with this program; if not, write to the Free Software
9424 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
9427 +#ifndef _LINUX_ISL_38XX_H
9428 +#define _LINUX_ISL_38XX_H
9430 +#include <asm/io.h>
9432 +#define ISL38XX_CB_RX_QSIZE 8
9433 +#define ISL38XX_CB_TX_QSIZE 32
9435 +/* ISL38XX Access Point Specific definitions */
9436 +#define ISL38XX_MAX_WDS_LINKS 8
9438 +/* ISL38xx Client Specific definitions */
9439 +#define ISL38XX_PSM_ACTIVE_STATE 0
9440 +#define ISL38XX_PSM_POWERSAVE_STATE 1
9442 +/* ISL38XX Host Interface Definitions */
9443 +#define ISL38XX_PCI_MEM_SIZE 0x02000
9444 +#define ISL38XX_MEMORY_WINDOW_SIZE 0x01000
9445 +#define ISL38XX_DEV_FIRMWARE_ADDRES 0x20000
9446 +#define ISL38XX_WRITEIO_DELAY 10 /* in us */
9447 +#define ISL38XX_RESET_DELAY 50 /* in ms */
9448 +#define ISL38XX_WAIT_CYCLE 10 /* in 10ms */
9449 +#define ISL38XX_MAX_WAIT_CYCLES 10
9451 +/* PCI Memory Area */
9452 +#define ISL38XX_HARDWARE_REG 0x0000
9453 +#define ISL38XX_CARDBUS_CIS 0x0800
9454 +#define ISL38XX_DIRECT_MEM_WIN 0x1000
9456 +/* Hardware registers */
9457 +#define ISL38XX_DEV_INT_REG 0x0000
9458 +#define ISL38XX_INT_IDENT_REG 0x0010
9459 +#define ISL38XX_INT_ACK_REG 0x0014
9460 +#define ISL38XX_INT_EN_REG 0x0018
9461 +#define ISL38XX_GEN_PURP_COM_REG_1 0x0020
9462 +#define ISL38XX_GEN_PURP_COM_REG_2 0x0024
9463 +#define ISL38XX_CTRL_BLK_BASE_REG ISL38XX_GEN_PURP_COM_REG_1
9464 +#define ISL38XX_DIR_MEM_BASE_REG 0x0030
9465 +#define ISL38XX_CTRL_STAT_REG 0x0078
9467 +/* High end mobos queue up pci writes, the following
9468 + * is used to "read" from after a write to force flush */
9469 +#define ISL38XX_PCI_POSTING_FLUSH ISL38XX_INT_EN_REG
9472 + * isl38xx_w32_flush - PCI iomem write helper
9473 + * @base: (host) memory base address of the device
9474 + * @val: 32bit value (host order) to write
9475 + * @offset: byte offset into @base to write value to
9477 + * This helper takes care of writing a 32bit datum to the
9478 + * specified offset into the device's pci memory space, and making sure
9479 + * the pci memory buffers get flushed by performing one harmless read
9480 + * from the %ISL38XX_PCI_POSTING_FLUSH offset.
9483 +isl38xx_w32_flush(void __iomem *base, u32 val, unsigned long offset)
9485 + writel(val, base + offset);
9486 + (void) readl(base + ISL38XX_PCI_POSTING_FLUSH);
9489 +/* Device Interrupt register bits */
9490 +#define ISL38XX_DEV_INT_RESET 0x0001
9491 +#define ISL38XX_DEV_INT_UPDATE 0x0002
9492 +#define ISL38XX_DEV_INT_WAKEUP 0x0008
9493 +#define ISL38XX_DEV_INT_SLEEP 0x0010
9494 +#define ISL38XX_DEV_INT_ABORT 0x0020
9495 +/* thos two only used in USB */
9496 +#define ISL38XX_DEV_INT_DATA 0x0040
9497 +#define ISL38XX_DEV_INT_MGMT 0x0080
9499 +#define ISL38XX_DEV_INT_PCIUART_CTS 0x4000
9500 +#define ISL38XX_DEV_INT_PCIUART_DR 0x8000
9502 +/* Interrupt Identification/Acknowledge/Enable register bits */
9503 +#define ISL38XX_INT_IDENT_UPDATE 0x0002
9504 +#define ISL38XX_INT_IDENT_INIT 0x0004
9505 +#define ISL38XX_INT_IDENT_WAKEUP 0x0008
9506 +#define ISL38XX_INT_IDENT_SLEEP 0x0010
9507 +#define ISL38XX_INT_IDENT_PCIUART_CTS 0x4000
9508 +#define ISL38XX_INT_IDENT_PCIUART_DR 0x8000
9510 +#define ISL38XX_INT_SOURCES (ISL38XX_INT_IDENT_UPDATE | \
9511 + ISL38XX_INT_IDENT_INIT | \
9512 + ISL38XX_INT_IDENT_WAKEUP | \
9513 + ISL38XX_INT_IDENT_SLEEP | \
9514 + ISL38XX_INT_IDENT_PCIUART_CTS | \
9515 + ISL38XX_INT_IDENT_PCIUART_DR)
9517 +/* Control/Status register bits */
9518 +/* Looks like there are other meaningful bits
9519 + 0x20004400 seen in normal operation,
9520 + 0x200044db at 'timeout waiting for mgmt response'
9522 +#define ISL38XX_CTRL_STAT_SLEEPMODE 0x00000200
9523 +#define ISL38XX_CTRL_STAT_CLKRUN 0x00800000
9524 +#define ISL38XX_CTRL_STAT_RESET 0x10000000
9525 +#define ISL38XX_CTRL_STAT_RAMBOOT 0x20000000
9526 +#define ISL38XX_CTRL_STAT_STARTHALTED 0x40000000
9527 +#define ISL38XX_CTRL_STAT_HOST_OVERRIDE 0x80000000
9529 +/* Some flags for the isl hardware registers controlling DMA inside the
9531 +#define ISL38XX_DMA_STATUS_DONE 0x00000001
9532 +#define ISL38XX_DMA_STATUS_READY 0x00000002
9533 +#define NET2280_EPA_FIFO_PCI_ADDR 0x20000000
9534 +#define ISL38XX_DMA_MASTER_CONTROL_TRIGGER 0x00000004
9536 +#endif /* _LINUX_ISL_38XX_H */
9537 diff -purN linux_2.6.24_org/include/linux/pm.h linux_2.6.24_olpc/include/linux/pm.h
9538 --- linux_2.6.24_org/include/linux/pm.h 2008-02-15 20:11:06.000000000 +0000
9539 +++ linux_2.6.24_olpc/include/linux/pm.h 2008-02-15 18:58:06.000000000 +0000
9540 @@ -178,6 +178,9 @@ struct dev_pm_info {
9541 unsigned can_wakeup:1;
9542 #ifdef CONFIG_PM_SLEEP
9543 unsigned should_wakeup:1;
9544 + pm_message_t prev_state;
9545 + void * saved_state;
9546 + struct device * pm_parent;
9547 struct list_head entry;
9550 diff -purN linux_2.6.24_org/include/linux/power_supply.h linux_2.6.24_olpc/include/linux/power_supply.h
9551 --- linux_2.6.24_org/include/linux/power_supply.h 2008-02-15 20:10:55.000000000 +0000
9552 +++ linux_2.6.24_olpc/include/linux/power_supply.h 2008-02-15 18:58:01.000000000 +0000
9553 @@ -98,9 +98,11 @@ enum power_supply_property {
9554 POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
9555 POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
9556 POWER_SUPPLY_PROP_TIME_TO_FULL_AVG,
9557 + POWER_SUPPLY_PROP_ACCUM_CURRENT,
9558 /* Properties of type `const char *' */
9559 POWER_SUPPLY_PROP_MODEL_NAME,
9560 POWER_SUPPLY_PROP_MANUFACTURER,
9561 + POWER_SUPPLY_PROP_SERIAL_NUMBER,
9564 enum power_supply_type {
9565 @@ -169,9 +171,10 @@ struct power_supply_info {
9567 extern void power_supply_changed(struct power_supply *psy);
9568 extern int power_supply_am_i_supplied(struct power_supply *psy);
9569 +extern void power_supply_status_changed(struct power_supply *psy);
9571 extern int power_supply_register(struct device *parent,
9572 - struct power_supply *psy);
9573 + struct power_supply *psy);
9574 extern void power_supply_unregister(struct power_supply *psy);
9576 /* For APM emulation, think legacy userspace. */
9577 diff -purN linux_2.6.24_org/include/linux/vt_kern.h linux_2.6.24_olpc/include/linux/vt_kern.h
9578 --- linux_2.6.24_org/include/linux/vt_kern.h 2008-02-15 20:10:55.000000000 +0000
9579 +++ linux_2.6.24_olpc/include/linux/vt_kern.h 2008-02-15 18:58:02.000000000 +0000
9580 @@ -96,4 +96,23 @@ struct vt_spawn_console {
9582 extern struct vt_spawn_console vt_spawn_con;
9584 +/* A notifier list for console events */
9585 +extern struct raw_notifier_head console_notifier_list;
9587 +/* Called when the FG console switches to KD_TEXT mode */
9588 +#define CONSOLE_EVENT_SWITCH_TEXT 0x01
9590 +/* Called when the FG console switches to KD_GRAPHICS mode */
9591 +#define CONSOLE_EVENT_SWITCH_GRAPHICS 0x02
9593 +static inline int console_event_register(struct notifier_block *n)
9595 + return raw_notifier_chain_register(&console_notifier_list, n);
9598 +static inline int console_event_unregister(struct notifier_block *n)
9600 + return raw_notifier_chain_unregister(&console_notifier_list, n);
9603 #endif /* _VT_KERN_H */
9604 diff -purN linux_2.6.24_org/include/sound/ac97_codec.h linux_2.6.24_olpc/include/sound/ac97_codec.h
9605 --- linux_2.6.24_org/include/sound/ac97_codec.h 2008-02-15 20:10:44.000000000 +0000
9606 +++ linux_2.6.24_olpc/include/sound/ac97_codec.h 2008-02-15 18:57:45.000000000 +0000
9607 @@ -281,10 +281,12 @@
9608 /* specific - Analog Devices */
9609 #define AC97_AD_TEST 0x5a /* test register */
9610 #define AC97_AD_TEST2 0x5c /* undocumented test register 2 */
9611 +#define AC97_AD_HPFD_SHIFT 12 /* High Pass Filter Disable */
9612 #define AC97_AD_CODEC_CFG 0x70 /* codec configuration */
9613 #define AC97_AD_JACK_SPDIF 0x72 /* Jack Sense & S/PDIF */
9614 #define AC97_AD_SERIAL_CFG 0x74 /* Serial Configuration */
9615 #define AC97_AD_MISC 0x76 /* Misc Control Bits */
9616 +#define AC97_AD_VREFD_SHIFT 2 /* V_REFOUT Disable (AD1888) */
9618 /* specific - Cirrus Logic */
9619 #define AC97_CSR_ACMODE 0x5e /* AC Mode Register */
9620 diff -purN linux_2.6.24_org/kernel/power/console.c linux_2.6.24_olpc/kernel/power/console.c
9621 --- linux_2.6.24_org/kernel/power/console.c 2008-02-15 20:12:34.000000000 +0000
9622 +++ linux_2.6.24_olpc/kernel/power/console.c 2008-02-15 19:00:00.000000000 +0000
9624 #include <linux/console.h>
9627 -#if defined(CONFIG_VT) && defined(CONFIG_VT_CONSOLE)
9628 +#if defined(CONFIG_VT) && defined(CONFIG_VT_CONSOLE) && !defined(CONFIG_DISABLE_SUSPEND_VT_SWITCH)
9629 #define SUSPEND_CONSOLE (MAX_NR_CONSOLES-1)
9631 static int orig_fgconsole, orig_kmsg;
9632 diff -purN linux_2.6.24_org/kernel/power/Kconfig linux_2.6.24_olpc/kernel/power/Kconfig
9633 --- linux_2.6.24_org/kernel/power/Kconfig 2008-02-15 20:12:34.000000000 +0000
9634 +++ linux_2.6.24_olpc/kernel/power/Kconfig 2008-02-15 19:00:00.000000000 +0000
9635 @@ -37,9 +37,22 @@ config PM_DEBUG
9636 code. This is helpful when debugging and reporting PM bugs, like
9639 +config DISABLE_SUSPEND_VT_SWITCH
9640 + bool "Disable the console switch prior to suspend (DANGEROUS)"
9641 + depends on PM_DEBUG
9644 + This option disables the automatic switch to VT console that happens
9645 + prior to Linux going into a suspend/sleep. Your video card/framebuffer
9646 + must be able to properly restore the display (even if X is doing
9647 + something crazy!) in this scenario. This is useful for saving
9648 + precious milliseconds during suspend and resume.
9653 bool "Verbose Power Management debugging"
9654 - depends on PM_DEBUG
9655 + depends on VT_CONSOLE && PM && EXPERIMENTAL
9658 This option enables verbose messages from the Power Management code.
9659 diff -purN linux_2.6.24_org/kernel/power/main.c linux_2.6.24_olpc/kernel/power/main.c
9660 --- linux_2.6.24_org/kernel/power/main.c 2008-02-15 20:12:34.000000000 +0000
9661 +++ linux_2.6.24_olpc/kernel/power/main.c 2008-02-15 19:00:00.000000000 +0000
9662 @@ -76,11 +76,13 @@ static int suspend_prepare(void)
9663 if (!suspend_ops || !suspend_ops->enter)
9666 +#ifndef CONFIG_OLPC_PM
9667 error = pm_notifier_call_chain(PM_SUSPEND_PREPARE);
9671 pm_prepare_console();
9674 if (freeze_processes()) {
9676 diff -purN linux_2.6.24_org/scripts/kconfig/conf.c linux_2.6.24_olpc/scripts/kconfig/conf.c
9677 --- linux_2.6.24_org/scripts/kconfig/conf.c 2008-02-15 20:10:15.000000000 +0000
9678 +++ linux_2.6.24_olpc/scripts/kconfig/conf.c 2008-02-15 18:57:09.000000000 +0000
9679 @@ -22,6 +22,7 @@ enum {
9683 + set_silentdefault,
9687 @@ -64,10 +65,11 @@ static void strip(char *str)
9689 static void check_stdin(void)
9691 - if (!valid_stdin && input_mode == ask_silent) {
9692 + if (!valid_stdin && (input_mode == ask_silent ||
9693 + input_mode == set_silentdefault)) {
9694 printf(_("aborted!\n\n"));
9695 printf(_("Console input/output is redirected. "));
9696 - printf(_("Run 'make oldconfig' to update configuration.\n\n"));
9697 + printf(_("Configuration file needs to be updated.\n\n"));
9701 @@ -102,6 +104,7 @@ static int conf_askvalue(struct symbol *
9705 + case set_silentdefault:
9706 if (sym_has_value(sym)) {
9707 printf("%s\n", def);
9709 @@ -352,6 +355,7 @@ static int conf_choice(struct menu *menu
9710 switch (input_mode) {
9713 + case set_silentdefault:
9716 printf("%d\n", cnt);
9717 @@ -424,7 +428,9 @@ static void conf(struct menu *menu)
9719 switch (prop->type) {
9721 - if (input_mode == ask_silent && rootEntry != menu) {
9722 + if ((input_mode == ask_silent ||
9723 + input_mode == set_silentdefault) &&
9724 + rootEntry != menu) {
9728 @@ -508,6 +514,16 @@ int main(int ac, char **av)
9729 input_mode = ask_silent;
9730 valid_stdin = isatty(0) && isatty(1) && isatty(2);
9733 + input_mode = set_silentdefault;
9734 + valid_stdin = isatty(0) && isatty(1) && isatty(2);
9735 + defconfig_file = av[i++];
9736 + if (!defconfig_file) {
9737 + printf("%s: No default config file specified\n",
9743 input_mode = set_default;
9745 @@ -557,6 +573,14 @@ int main(int ac, char **av)
9749 + case set_silentdefault:
9750 + if (conf_read(defconfig_file)) {
9752 + "*** Can't find default configuration \"%s\"!\n"
9753 + "***\n", defconfig_file);
9758 if (stat(".config", &tmpstat)) {
9760 @@ -597,7 +621,7 @@ int main(int ac, char **av)
9764 - if (input_mode != ask_silent) {
9765 + if (input_mode != ask_silent && input_mode != set_silentdefault) {
9766 rootEntry = &rootmenu;
9768 if (input_mode == ask_all) {
9769 @@ -610,19 +634,21 @@ int main(int ac, char **av)
9770 fprintf(stderr, _("\n*** Kernel configuration requires explicit update.\n\n"));
9774 + } else if (input_mode != set_silentdefault)
9779 check_conf(&rootmenu);
9781 - if (conf_write(NULL)) {
9782 + if (conf_write(NULL, input_mode == ask_silent ||
9783 + input_mode == set_silentdefault)) {
9784 fprintf(stderr, _("\n*** Error during writing of the kernel configuration.\n\n"));
9788 - if (input_mode == ask_silent && conf_write_autoconf()) {
9789 + if ((input_mode == ask_silent || input_mode == set_silentdefault) &&
9790 + conf_write_autoconf()) {
9791 fprintf(stderr, _("\n*** Error during writing of the kernel configuration.\n\n"));
9794 diff -purN linux_2.6.24_org/scripts/kconfig/confdata.c linux_2.6.24_olpc/scripts/kconfig/confdata.c
9795 --- linux_2.6.24_org/scripts/kconfig/confdata.c 2008-02-15 20:10:15.000000000 +0000
9796 +++ linux_2.6.24_olpc/scripts/kconfig/confdata.c 2008-02-15 18:57:09.000000000 +0000
9797 @@ -393,7 +393,7 @@ int conf_read(const char *name)
9801 -int conf_write(const char *name)
9802 +int conf_write(const char *name, int quiet)
9806 @@ -548,9 +548,10 @@ int conf_write(const char *name)
9811 - "# configuration written to %s\n"
9815 + "# configuration written to %s\n"
9818 sym_set_change_count(0);
9820 diff -purN linux_2.6.24_org/scripts/kconfig/gconf.c linux_2.6.24_olpc/scripts/kconfig/gconf.c
9821 --- linux_2.6.24_org/scripts/kconfig/gconf.c 2008-02-15 20:10:15.000000000 +0000
9822 +++ linux_2.6.24_olpc/scripts/kconfig/gconf.c 2008-02-15 18:57:09.000000000 +0000
9823 @@ -621,7 +621,7 @@ void on_load1_activate(GtkMenuItem * men
9825 void on_save_activate(GtkMenuItem * menuitem, gpointer user_data)
9827 - if (conf_write(NULL))
9828 + if (conf_write(NULL, 0))
9829 text_insert_msg(_("Error"), _("Unable to save configuration !"));
9832 @@ -634,7 +634,7 @@ store_filename(GtkFileSelection * file_s
9833 fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION
9836 - if (conf_write(fn))
9837 + if (conf_write(fn, 0))
9838 text_insert_msg(_("Error"), _("Unable to save configuration !"));
9840 gtk_widget_destroy(GTK_WIDGET(user_data));
9841 diff -purN linux_2.6.24_org/scripts/kconfig/lkc_proto.h linux_2.6.24_olpc/scripts/kconfig/lkc_proto.h
9842 --- linux_2.6.24_org/scripts/kconfig/lkc_proto.h 2008-02-15 20:10:15.000000000 +0000
9843 +++ linux_2.6.24_olpc/scripts/kconfig/lkc_proto.h 2008-02-15 18:57:09.000000000 +0000
9845 P(conf_parse,void,(const char *name));
9846 P(conf_read,int,(const char *name));
9847 P(conf_read_simple,int,(const char *name, int));
9848 -P(conf_write,int,(const char *name));
9849 +P(conf_write,int,(const char *name, int));
9850 P(conf_write_autoconf,int,(void));
9851 P(conf_get_changed,bool,(void));
9852 P(conf_set_changed_callback, void,(void (*fn)(void)));
9853 diff -purN linux_2.6.24_org/scripts/kconfig/Makefile linux_2.6.24_olpc/scripts/kconfig/Makefile
9854 --- linux_2.6.24_org/scripts/kconfig/Makefile 2008-02-15 20:10:15.000000000 +0000
9855 +++ linux_2.6.24_olpc/scripts/kconfig/Makefile 2008-02-15 18:57:09.000000000 +0000
9856 @@ -69,6 +69,9 @@ endif
9857 %_defconfig: $(obj)/conf
9858 $(Q)$< -D arch/$(SRCARCH)/configs/$@ $(Kconfig)
9860 +%_silentdefconfig: $(obj)/conf
9861 + $(Q)$< -S arch/$(ARCH)/configs/$(subst _silentdefconfig,_defconfig,$@) arch/$(ARCH)/Kconfig
9863 # Help text used by make help
9865 @echo ' config - Update current config utilising a line-oriented program'
9866 Binary files linux_2.6.24_org/scripts/kconfig/mconf and linux_2.6.24_olpc/scripts/kconfig/mconf differ
9867 diff -purN linux_2.6.24_org/scripts/kconfig/mconf.c linux_2.6.24_olpc/scripts/kconfig/mconf.c
9868 --- linux_2.6.24_org/scripts/kconfig/mconf.c 2008-02-15 20:10:15.000000000 +0000
9869 +++ linux_2.6.24_olpc/scripts/kconfig/mconf.c 2008-02-15 18:57:09.000000000 +0000
9870 @@ -885,7 +885,7 @@ static void conf_save(void)
9872 if (!dialog_input_result[0])
9874 - if (!conf_write(dialog_input_result)) {
9875 + if (!conf_write(dialog_input_result, 0)) {
9876 set_config_filename(dialog_input_result);
9879 @@ -945,7 +945,7 @@ int main(int ac, char **av)
9883 - if (conf_write(filename)) {
9884 + if (conf_write(filename, 0)) {
9885 fprintf(stderr, _("\n\n"
9886 "Error during writing of the kernel configuration.\n"
9887 "Your kernel configuration changes were NOT saved."
9888 diff -purN linux_2.6.24_org/scripts/kconfig/qconf.cc linux_2.6.24_olpc/scripts/kconfig/qconf.cc
9889 --- linux_2.6.24_org/scripts/kconfig/qconf.cc 2008-02-15 20:10:15.000000000 +0000
9890 +++ linux_2.6.24_olpc/scripts/kconfig/qconf.cc 2008-02-15 18:57:09.000000000 +0000
9891 @@ -1458,7 +1458,7 @@ void ConfigMainWindow::loadConfig(void)
9893 void ConfigMainWindow::saveConfig(void)
9895 - if (conf_write(NULL))
9896 + if (conf_write(NULL, 0))
9897 QMessageBox::information(this, "qconf", "Unable to save configuration!");
9900 @@ -1467,7 +1467,7 @@ void ConfigMainWindow::saveConfigAs(void
9901 QString s = QFileDialog::getSaveFileName(".config", NULL, this);
9904 - if (conf_write(QFile::encodeName(s)))
9905 + if (conf_write(QFile::encodeName(s), 0))
9906 QMessageBox::information(this, "qconf", "Unable to save configuration!");
9909 @@ -1619,7 +1619,7 @@ void ConfigMainWindow::closeEvent(QClose
9910 mb.setButtonText(QMessageBox::Cancel, "Cancel Exit");
9911 switch (mb.exec()) {
9912 case QMessageBox::Yes:
9914 + conf_write(NULL, 0);
9915 case QMessageBox::No:
9918 diff -purN linux_2.6.24_org/sound/pci/ac97/ac97_patch.c linux_2.6.24_olpc/sound/pci/ac97/ac97_patch.c
9919 --- linux_2.6.24_org/sound/pci/ac97/ac97_patch.c 2008-02-15 20:10:24.000000000 +0000
9920 +++ linux_2.6.24_olpc/sound/pci/ac97/ac97_patch.c 2008-02-15 18:57:24.000000000 +0000
9921 @@ -2029,8 +2029,9 @@ static const struct snd_kcontrol_new snd
9922 .get = snd_ac97_ad1888_lohpsel_get,
9923 .put = snd_ac97_ad1888_lohpsel_put
9925 - AC97_SINGLE("V_REFOUT Enable", AC97_AD_MISC, 2, 1, 1),
9926 - AC97_SINGLE("High Pass Filter Enable", AC97_AD_TEST2, 12, 1, 1),
9927 + AC97_SINGLE("V_REFOUT Enable", AC97_AD_MISC, AC97_AD_VREFD_SHIFT, 1, 1),
9928 + AC97_SINGLE("High Pass Filter Enable", AC97_AD_TEST2,
9929 + AC97_AD_HPFD_SHIFT, 1, 1),
9930 AC97_SINGLE("Spread Front to Surround and Center/LFE", AC97_AD_MISC, 7, 1, 0),
9932 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9933 diff -purN linux_2.6.24_org/sound/pci/cs5535audio/cs5535audio.c linux_2.6.24_olpc/sound/pci/cs5535audio/cs5535audio.c
9934 --- linux_2.6.24_org/sound/pci/cs5535audio/cs5535audio.c 2008-02-15 20:10:23.000000000 +0000
9935 +++ linux_2.6.24_olpc/sound/pci/cs5535audio/cs5535audio.c 2008-02-15 18:57:23.000000000 +0000
9936 @@ -145,7 +145,7 @@ static unsigned short snd_cs5535audio_ac
9937 return snd_cs5535audio_codec_read(cs5535au, reg);
9940 -static int snd_cs5535audio_mixer(struct cs5535audio *cs5535au)
9941 +static int __devinit snd_cs5535audio_mixer(struct cs5535audio *cs5535au)
9943 struct snd_card *card = cs5535au->card;
9944 struct snd_ac97_bus *pbus;
9945 @@ -160,10 +160,14 @@ static int snd_cs5535audio_mixer(struct
9948 memset(&ac97, 0, sizeof(ac97));
9949 - ac97.scaps = AC97_SCAP_AUDIO|AC97_SCAP_SKIP_MODEM;
9950 + ac97.scaps = AC97_SCAP_AUDIO | AC97_SCAP_SKIP_MODEM
9951 + | AC97_SCAP_POWER_SAVE;
9952 ac97.private_data = cs5535au;
9953 ac97.pci = cs5535au->pci;
9955 + /* olpc_prequirks is dummied out if not olpc */
9956 + olpc_prequirks(card, &ac97);
9958 if ((err = snd_ac97_mixer(pbus, &ac97, &cs5535au->ac97)) < 0) {
9959 snd_printk(KERN_ERR "mixer failed\n");
9961 @@ -171,6 +175,12 @@ static int snd_cs5535audio_mixer(struct
9963 snd_ac97_tune_hardware(cs5535au->ac97, ac97_quirks, ac97_quirk);
9965 + /* olpc_quirks is dummied out if not olpc */
9966 + if (( err = olpc_quirks(card, cs5535au->ac97)) < 0) {
9967 + snd_printk(KERN_ERR "olpc quirks failed\n");
9974 diff -purN linux_2.6.24_org/sound/pci/cs5535audio/cs5535audio.h linux_2.6.24_olpc/sound/pci/cs5535audio/cs5535audio.h
9975 --- linux_2.6.24_org/sound/pci/cs5535audio/cs5535audio.h 2008-02-15 20:10:23.000000000 +0000
9976 +++ linux_2.6.24_olpc/sound/pci/cs5535audio/cs5535audio.h 2008-02-15 18:57:23.000000000 +0000
9977 @@ -78,6 +78,7 @@ struct cs5535audio_dma {
9978 unsigned int buf_addr, buf_bytes;
9979 unsigned int period_bytes, periods;
9981 + int pcm_open_flag;
9984 struct cs5535audio {
9985 @@ -93,8 +94,21 @@ struct cs5535audio {
9986 struct cs5535audio_dma dmas[NUM_CS5535AUDIO_DMAS];
9990 int snd_cs5535audio_suspend(struct pci_dev *pci, pm_message_t state);
9991 int snd_cs5535audio_resume(struct pci_dev *pci);
9995 +void olpc_prequirks(struct snd_card *card, struct snd_ac97_template *ac97) __devinit;
9996 +int olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97) __devinit;
9997 +int olpc_ai_enable(struct snd_ac97 *ac97, u8 val);
9999 +#define olpc_prequirks(arg,arg2) do {} while (0)
10000 +#define olpc_quirks(arg,arg2) (0)
10001 +#define olpc_ai_enable(a, v) (0)
10004 int __devinit snd_cs5535audio_pcm(struct cs5535audio *cs5535audio);
10006 #endif /* __SOUND_CS5535AUDIO_H */
10007 diff -purN linux_2.6.24_org/sound/pci/cs5535audio/cs5535audio_olpc.c linux_2.6.24_olpc/sound/pci/cs5535audio/cs5535audio_olpc.c
10008 --- linux_2.6.24_org/sound/pci/cs5535audio/cs5535audio_olpc.c 1970-01-01 01:00:00.000000000 +0100
10009 +++ linux_2.6.24_olpc/sound/pci/cs5535audio/cs5535audio_olpc.c 2008-02-15 18:57:23.000000000 +0000
10011 +#include <sound/driver.h>
10012 +#include <sound/core.h>
10013 +#include <sound/info.h>
10014 +#include <sound/control.h>
10015 +#include <sound/ac97_codec.h>
10017 +#include <asm/olpc.h>
10018 +#include "cs5535audio.h"
10021 + * OLPC has an additional feature on top of the regular AD1888 codec features.
10022 + * It has an Analog Input mode that is switched into (after disabling the
10023 + * High Pass Filter) via GPIO. It is only supported on B2 and later models.
10026 +int olpc_ai_enable(struct snd_ac97 *ac97, u8 val)
10031 + * update the High Pass Filter (via AC97_AD_TEST2), and then set
10032 + * Analog Input mode through a GPIO.
10036 + err = snd_ac97_update_bits(ac97, AC97_AD_TEST2,
10037 + 1<<AC97_AD_HPFD_SHIFT, 1<<AC97_AD_HPFD_SHIFT);
10038 + geode_gpio_set(OLPC_GPIO_MIC_AC, GPIO_OUTPUT_VAL);
10041 + err = snd_ac97_update_bits(ac97, AC97_AD_TEST2,
10042 + 1<<AC97_AD_HPFD_SHIFT, 0);
10043 + geode_gpio_clear(OLPC_GPIO_MIC_AC, GPIO_OUTPUT_VAL);
10046 + snd_printk(KERN_ERR "Error updating AD_TEST2: %d\n", err);
10050 +EXPORT_SYMBOL_GPL(olpc_ai_enable);
10052 +static int snd_cs5535audio_ai_info(struct snd_kcontrol *kcontrol,
10053 + struct snd_ctl_elem_info *uinfo)
10055 + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
10056 + uinfo->count = 1;
10057 + uinfo->value.integer.min = 0;
10058 + uinfo->value.integer.max = 1;
10062 +static int snd_cs5535audio_ai_get(struct snd_kcontrol *kcontrol,
10063 + struct snd_ctl_elem_value *ucontrol)
10065 + ucontrol->value.integer.value[0] = geode_gpio_isset(OLPC_GPIO_MIC_AC,
10066 + GPIO_OUTPUT_VAL);
10070 +static int snd_cs5535audio_ai_put(struct snd_kcontrol *kcontrol,
10071 + struct snd_ctl_elem_value *ucontrol)
10073 + struct cs5535audio *cs5535au = snd_kcontrol_chip(kcontrol);
10074 + struct snd_ac97 *ac97 = cs5535au->ac97;
10076 + olpc_ai_enable(ac97, ucontrol->value.integer.value[0]);
10081 +static struct snd_kcontrol_new snd_cs5535audio_controls __devinitdata =
10083 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10084 + .name = "DC Mode Enable",
10085 + .info = snd_cs5535audio_ai_info,
10086 + .get = snd_cs5535audio_ai_get,
10087 + .put = snd_cs5535audio_ai_put,
10088 + .private_value = 0
10091 +void __devinit olpc_prequirks(struct snd_card *card,
10092 + struct snd_ac97_template *ac97)
10094 + /* Bail if this isn't an OLPC platform */
10095 + if (!machine_is_olpc())
10098 + /* If on an OLPC B3 or higher, invert EAPD. */
10099 + if (olpc_board_at_least(olpc_board_pre(0xb3)))
10100 + ac97->scaps |= AC97_SCAP_INV_EAPD;
10103 +int __devinit olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97)
10105 + struct snd_ctl_elem_id elem;
10107 + /* Bail if this isn't an OLPC platform */
10108 + if (!machine_is_olpc())
10111 + /* drop the original ad1888 HPF control */
10112 + memset(&elem, 0, sizeof(elem));
10113 + elem.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
10114 + strcpy(elem.name, "High Pass Filter Enable");
10115 + snd_ctl_remove_id(card, &elem);
10117 + /* add the override for OLPC's HPF */
10118 + return snd_ctl_add(card, snd_ctl_new1(&snd_cs5535audio_controls,
10119 + ac97->private_data));
10121 diff -purN linux_2.6.24_org/sound/pci/cs5535audio/cs5535audio_pcm.c linux_2.6.24_olpc/sound/pci/cs5535audio/cs5535audio_pcm.c
10122 --- linux_2.6.24_org/sound/pci/cs5535audio/cs5535audio_pcm.c 2008-02-15 20:10:23.000000000 +0000
10123 +++ linux_2.6.24_olpc/sound/pci/cs5535audio/cs5535audio_pcm.c 2008-02-15 18:57:23.000000000 +0000
10124 @@ -259,6 +259,9 @@ static int snd_cs5535audio_hw_params(str
10125 err = cs5535audio_build_dma_packets(cs5535au, dma, substream,
10126 params_periods(hw_params),
10127 params_period_bytes(hw_params));
10129 + dma->pcm_open_flag = 1;
10134 @@ -267,6 +270,15 @@ static int snd_cs5535audio_hw_free(struc
10135 struct cs5535audio *cs5535au = snd_pcm_substream_chip(substream);
10136 struct cs5535audio_dma *dma = substream->runtime->private_data;
10138 + if (dma->pcm_open_flag) {
10139 + if (substream == cs5535au->playback_substream)
10140 + snd_ac97_update_power(cs5535au->ac97,
10141 + AC97_PCM_FRONT_DAC_RATE, 0);
10143 + snd_ac97_update_power(cs5535au->ac97,
10144 + AC97_PCM_LR_ADC_RATE, 0);
10145 + dma->pcm_open_flag = 0;
10147 cs5535audio_clear_dma_packets(cs5535au, dma, substream);
10148 return snd_pcm_lib_free_pages(substream);
10150 @@ -341,6 +353,7 @@ static int snd_cs5535audio_capture_open(
10152 struct cs5535audio *cs5535au = snd_pcm_substream_chip(substream);
10153 struct snd_pcm_runtime *runtime = substream->runtime;
10154 + struct snd_ac97 *ac97 = cs5535au->ac97;
10156 runtime->hw = snd_cs5535audio_capture;
10157 cs5535au->capture_substream = substream;
10158 @@ -348,11 +361,29 @@ static int snd_cs5535audio_capture_open(
10159 if ((err = snd_pcm_hw_constraint_integer(runtime,
10160 SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
10164 +#ifdef CONFIG_OLPC
10165 + /* Disable Analog Input */
10166 + olpc_ai_enable(ac97, 0);
10167 + /* Enable V_ref bias while recording. */
10168 + snd_ac97_update_bits(ac97, AC97_AD_MISC, 1<<AC97_AD_VREFD_SHIFT, 0);
10173 static int snd_cs5535audio_capture_close(struct snd_pcm_substream *substream)
10175 +#ifdef CONFIG_OLPC
10176 + struct cs5535audio *cs5535au = snd_pcm_substream_chip(substream);
10177 + struct snd_ac97 *ac97 = cs5535au->ac97;
10179 + /* Disable Analog Input */
10180 + olpc_ai_enable(ac97, 0);
10181 + /* Disable V_ref bias. */
10182 + snd_ac97_update_bits(ac97, AC97_AD_MISC, 1<<AC97_AD_VREFD_SHIFT,
10183 + 1<<AC97_AD_VREFD_SHIFT);
10189 diff -purN linux_2.6.24_org/sound/pci/cs5535audio/Makefile linux_2.6.24_olpc/sound/pci/cs5535audio/Makefile
10190 --- linux_2.6.24_org/sound/pci/cs5535audio/Makefile 2008-02-15 20:10:23.000000000 +0000
10191 +++ linux_2.6.24_olpc/sound/pci/cs5535audio/Makefile 2008-02-15 18:57:23.000000000 +0000
10193 snd-cs5535audio-y := cs5535audio.o cs5535audio_pcm.o
10194 snd-cs5535audio-$(CONFIG_PM) += cs5535audio_pm.o
10197 +snd-cs5535audio-objs += cs5535audio_olpc.o
10200 # Toplevel Module Dependency
10201 obj-$(CONFIG_SND_CS5535AUDIO) += snd-cs5535audio.o