1 Index: linux-2.6.24.7/arch/x86/Kconfig
2 ===================================================================
3 --- linux-2.6.24.7.orig/arch/x86/Kconfig
4 +++ linux-2.6.24.7/arch/x86/Kconfig
5 @@ -1415,6 +1415,9 @@ config PCI_GODIRECT
15 @@ -1425,7 +1428,7 @@ config PCI_BIOS
16 # x86-64 doesn't support PCI BIOS access from long mode so always go direct.
19 - depends on PCI && (X86_64 || (PCI_GODIRECT || PCI_GOANY) || X86_VISWS)
20 + depends on PCI && (X86_64 || (PCI_GODIRECT || PCI_GOANY || PCI_GOOLPC) || X86_VISWS)
24 @@ -1442,6 +1445,11 @@ config PCI_MMCONFIG
25 bool "Support mmconfig PCI config space access"
26 depends on X86_64 && PCI && ACPI
30 + depends on PCI && PCI_GOOLPC
34 bool "Support for DMA Remapping Devices (EXPERIMENTAL)"
35 depends on X86_64 && PCI_MSI && ACPI && EXPERIMENTAL
36 @@ -1561,6 +1569,21 @@ config K8_NB
38 depends on AGP_AMD64 || (X86_64 && (GART_IOMMU || (PCI && NUMA)))
47 + bool "OLPC power management support"
52 + bool "Support for Open Firmware"
55 source "drivers/pcmcia/Kconfig"
57 source "drivers/pci/hotplug/Kconfig"
58 Index: linux-2.6.24.7/arch/x86/kernel/Makefile_32
59 ===================================================================
60 --- linux-2.6.24.7.orig/arch/x86/kernel/Makefile_32
61 +++ linux-2.6.24.7/arch/x86/kernel/Makefile_32
62 @@ -50,6 +50,13 @@ obj-y += pcspeaker.o
64 obj-$(CONFIG_SCx200) += scx200_32.o
66 +obj-$(CONFIG_OLPC) += olpc.o
67 +obj-$(CONFIG_OLPC_PM) += olpc-pm.o olpc-wakeup.o
68 +obj-$(CONFIG_OPEN_FIRMWARE) += ofw.o
69 +obj-$(PROM_FS) += promfs.o
73 # vsyscall_32.o contains the vsyscall DSO images as __initdata.
74 # We must build both images before we can assemble it.
75 # Note: kbuild does not track this dependency due to usage of .incbin
76 Index: linux-2.6.24.7/arch/x86/kernel/ofw.c
77 ===================================================================
79 +++ linux-2.6.24.7/arch/x86/kernel/ofw.c
82 + * ofw.c - Open Firmware client interface for 32-bit systems.
83 + * This code is intended to be portable to any 32-bit Open Firmware
84 + * implementation with a standard client interface that can be
85 + * called when Linux is running.
87 + * Copyright (C) 2007 Mitch Bradley <wmb@firmworks.com>
88 + * Copyright (C) 2007 Andres Salomon <dilinger@debian.org>
92 +#include <linux/spinlock.h>
93 +#include <linux/module.h>
97 +int (*call_firmware)(int *);
99 +static DEFINE_SPINLOCK(prom_lock);
104 + * The return value from ofw() in all cases is 0 if the attempt to call the
105 + * function succeeded, <0 otherwise. That return value is from the
106 + * gateway function only. Any results from the called function are returned
107 + * via output argument pointers.
109 + * Here are call templates for all the standard OFW client services:
111 + * ofw("test", 1, 1, namestr, &missing);
112 + * ofw("peer", 1, 1, phandle, &sibling_phandle);
113 + * ofw("child", 1, 1, phandle, &child_phandle);
114 + * ofw("parent", 1, 1, phandle, &parent_phandle);
115 + * ofw("instance_to_package", 1, 1, ihandle, &phandle);
116 + * ofw("getproplen", 2, 1, phandle, namestr, &proplen);
117 + * ofw("getprop", 4, 1, phandle, namestr, bufaddr, buflen, &size);
118 + * ofw("nextprop", 3, 1, phandle, previousstr, bufaddr, &flag);
119 + * ofw("setprop", 4, 1, phandle, namestr, bufaddr, len, &size);
120 + * ofw("canon", 3, 1, devspecstr, bufaddr, buflen, &length);
121 + * ofw("finddevice", 1, 1, devspecstr, &phandle);
122 + * ofw("instance-to-path", 3, 1, ihandle, bufaddr, buflen, &length);
123 + * ofw("package-to-path", 3, 1, phandle, bufaddr, buflen, &length);
124 + * ofw("call_method", numin, numout, in0, in1, ..., &out0, &out1, ...);
125 + * ofw("open", 1, 1, devspecstr, &ihandle);
126 + * ofw("close", 1, 0, ihandle);
127 + * ofw("read", 3, 1, ihandle, addr, len, &actual);
128 + * ofw("write", 3, 1, ihandle, addr, len, &actual);
129 + * ofw("seek", 3, 1, ihandle, pos_hi, pos_lo, &status);
130 + * ofw("claim", 3, 1, virtaddr, size, align, &baseaddr);
131 + * ofw("release", 2, 0, virtaddr, size);
132 + * ofw("boot", 1, 0, bootspecstr);
133 + * ofw("enter", 0, 0);
134 + * ofw("exit", 0, 0);
135 + * ofw("chain", 5, 0, virtaddr, size, entryaddr, argsaddr, len);
136 + * ofw("interpret", numin+1, numout+1, cmdstr, in0, ..., &catchres, &out0, ...);
137 + * ofw("set-callback", 1, 1, newfuncaddr, &oldfuncaddr);
138 + * ofw("set-symbol-lookup", 2, 0, symtovaladdr, valtosymaddr);
139 + * ofw("milliseconds", 0, 1, &ms);
142 +int ofw(char *name, int numargs, int numres, ...)
145 + int argarray[MAXARGS+3];
149 + unsigned long flags;
151 + if (!call_firmware)
153 + if ((numargs + numres) > MAXARGS)
154 + return -1; /* spit out an error? */
156 + argarray[0] = (int) name;
157 + argarray[1] = numargs;
158 + argarray[2] = numres;
160 + va_start(ap, numres);
162 + argarray[argnum++] = va_arg(ap, int);
166 + spin_lock_irqsave(&prom_lock, flags);
167 + retval = call_firmware(argarray);
168 + spin_unlock_irqrestore(&prom_lock, flags);
172 + intp = va_arg(ap, int *);
173 + *intp = argarray[argnum++];
181 Index: linux-2.6.24.7/arch/x86/kernel/olpc.c
182 ===================================================================
184 +++ linux-2.6.24.7/arch/x86/kernel/olpc.c
186 +/* Support for the OLPC DCON and OLPC EC access
187 + * Copyright (C) 2006, Advanced Micro Devices, Inc.
189 + * This program is free software; you can redistribute it and/or modify
190 + * it under the terms of the GNU General Public License as published by
191 + * the Free Software Foundation; either version 2 of the License, or
192 + * (at your option) any later version.
195 +#include <linux/autoconf.h>
196 +#include <linux/kernel.h>
197 +#include <linux/init.h>
198 +#include <linux/mc146818rtc.h>
199 +#include <linux/delay.h>
200 +#include <linux/spinlock.h>
202 +#include <asm/olpc.h>
203 +#include <asm/ofw.h>
205 +/* This is our new multi-purpose structure used to contain the
206 + * information about the platform that we detect
209 +struct olpc_platform_t olpc_platform_info;
210 +EXPORT_SYMBOL_GPL(olpc_platform_info);
212 +/*********************************************************************
213 + * EC locking and access
214 + *********************************************************************/
216 +static DEFINE_SPINLOCK(ec_lock);
218 +/* what the timeout *should* be (in ms) */
219 +#define EC_BASE_TIMEOUT 20
221 +/* the timeout that bugs in the EC might force us to actually use */
222 +static int ec_timeout = EC_BASE_TIMEOUT;
224 +static int __init olpc_ec_timeout_set(char *str)
226 + if (get_option(&str, &ec_timeout) != 1) {
227 + ec_timeout = EC_BASE_TIMEOUT;
228 + printk(KERN_ERR "olpc-ec: invalid argument to "
229 + "'olpc_ec_timeout=', ignoring!\n");
231 + printk(KERN_DEBUG "olpc-ec: using %d ms delay for EC commands.\n",
235 +__setup("olpc_ec_timeout=", olpc_ec_timeout_set);
238 + * These *bf_status functions return whether the buffers are full or not.
241 +static inline unsigned int ibf_status(unsigned int port)
243 + return !!(inb(port) & 0x02);
246 +static inline unsigned int obf_status(unsigned int port)
248 + return inb(port) & 0x01;
251 +#define wait_on_ibf(p, d) __wait_on_ibf(__LINE__, (p), (d))
252 +static int __wait_on_ibf(unsigned int line, unsigned int port, int desired)
254 + unsigned int timeo;
255 + int state = ibf_status(port);
257 + for (timeo = ec_timeout; state != desired && timeo; timeo--) {
259 + state = ibf_status(port);
262 + if ((state == desired) && (ec_timeout > EC_BASE_TIMEOUT) &&
263 + timeo < (ec_timeout - EC_BASE_TIMEOUT)) {
264 + printk(KERN_WARNING "olpc-ec: %d: waited %u ms for IBF!\n",
265 + line, ec_timeout - timeo);
268 + return !(state == desired);
271 +#define wait_on_obf(p, d) __wait_on_obf(__LINE__, (p), (d))
272 +static int __wait_on_obf(unsigned int line, unsigned int port, int desired)
274 + unsigned int timeo;
275 + int state = obf_status(port);
277 + for (timeo = ec_timeout; state != desired && timeo; timeo--) {
279 + state = obf_status(port);
282 + if ((state == desired) && (ec_timeout > EC_BASE_TIMEOUT) &&
283 + timeo < (ec_timeout - EC_BASE_TIMEOUT)) {
284 + printk(KERN_WARNING "olpc-ec: %d: waited %u ms for OBF!\n",
285 + line, ec_timeout - timeo);
288 + return !(state == desired);
291 +int olpc_ec_cmd(unsigned char cmd, unsigned char *inbuf, size_t inlen,
292 + unsigned char *outbuf, size_t outlen)
294 + unsigned long flags;
298 + spin_lock_irqsave(&ec_lock, flags);
301 + for (i = 0; i < 10 && (obf_status(0x6c) == 1); i++)
304 + printk(KERN_ERR "olpc-ec: timeout while attempting to "
305 + "clear OBF flag!\n");
309 + if (wait_on_ibf(0x6c, 0)) {
310 + printk(KERN_ERR "olpc-ec: timeout waiting for EC to "
317 + * Note that if we time out during any IBF checks, that's a failure;
318 + * we have to return. There's no way for the kernel to clear that.
320 + * If we time out during an OBF check, we can restart the command;
321 + * reissuing it will clear the OBF flag, and we should be alright.
322 + * The OBF flag will sometimes misbehave due to what we believe
323 + * is a hardware quirk..
325 + printk(KERN_DEBUG "olpc-ec: running cmd 0x%x\n", cmd);
328 + if (wait_on_ibf(0x6c, 0)) {
329 + printk(KERN_ERR "olpc-ec: timeout waiting for EC to read "
334 + if (inbuf && inlen) {
335 + /* write data to EC */
336 + for (i = 0; i < inlen; i++) {
337 + if (wait_on_ibf(0x6c, 0)) {
338 + printk(KERN_ERR "olpc-ec: timeout waiting for"
339 + " EC accept data!\n");
342 + printk(KERN_DEBUG "olpc-ec: sending cmd arg 0x%x\n",
344 + outb(inbuf[i], 0x68);
347 + if (outbuf && outlen) {
348 + /* read data from EC */
349 + for (i = 0; i < outlen; i++) {
350 + if (wait_on_obf(0x6c, 1)) {
351 + printk(KERN_ERR "olpc-ec: timeout waiting for"
352 + " EC to provide data!\n");
355 + outbuf[i] = inb(0x68);
356 + printk(KERN_DEBUG "olpc-ec: received 0x%x\n",
363 + spin_unlock_irqrestore(&ec_lock, flags);
366 +EXPORT_SYMBOL_GPL(olpc_ec_cmd);
368 +/*********************************************************************
370 + *********************************************************************/
375 + olpc_ec_cmd(0x08, NULL, 0, (unsigned char *) &olpc_platform_info.ecver, 1);
378 +/* Check to see if this version of the OLPC board has VSA built
379 + * in, and set a flag
382 +static void __init vsa_detect(void)
386 + outw(0xFC53, 0xAC1C);
387 + outw(0x0003, 0xAC1C);
392 + olpc_platform_info.flags |= OLPC_F_VSA;
395 +static void __init platform_detect(void)
400 + if (ofw("getprop", 4, 1, NULL, "board-revision-int", &rev, 4,
401 + &propsize) || propsize != 4) {
402 + printk(KERN_ERR "ofw: getprop call failed!\n");
405 + olpc_platform_info.boardrev = be32_to_cpu(rev);
408 +static int olpc_dcon_present = -1;
409 +module_param(olpc_dcon_present, int, 0444);
412 + * bit 440; DCON present bit
415 +#define OLPC_CMOS_DCON_OFFSET (440 / 8)
416 +#define OLPC_CMOS_DCON_MASK 0x01
418 +static int __init olpc_init(void)
420 + unsigned char *romsig;
422 + spin_lock_init(&ec_lock);
424 + romsig = ioremap(0xffffffc0, 16);
429 + if (strncmp(romsig, "CL1 Q", 7))
431 + if (strncmp(romsig+6, romsig+13, 3)) {
432 + printk(KERN_INFO "OLPC BIOS signature looks invalid. Assuming not OLPC\n");
435 + printk(KERN_INFO "OLPC board with OpenFirmware: %.16s\n", romsig);
437 + olpc_platform_info.flags |= OLPC_F_PRESENT;
439 + /* Get the platform revision */
442 + /* If olpc_dcon_present isn't set by the command line, then
446 + if (olpc_dcon_present == -1) {
447 + /* B1 and greater always has a DCON */
448 + if (olpc_board_at_least(olpc_board(0xb1)))
449 + olpc_dcon_present = 1;
452 + if (olpc_dcon_present)
453 + olpc_platform_info.flags |= OLPC_F_DCON;
455 + /* Get the EC revision */
458 + /* Check to see if the VSA exists */
461 + printk(KERN_INFO "OLPC board revision: %s%X (EC=%x)\n",
462 + ((olpc_platform_info.boardrev & 0xf) < 8) ? "pre" : "",
463 + olpc_platform_info.boardrev >> 4,
464 + olpc_platform_info.ecver);
472 +postcore_initcall(olpc_init);
473 Index: linux-2.6.24.7/arch/x86/kernel/olpc-pm.c
474 ===================================================================
476 +++ linux-2.6.24.7/arch/x86/kernel/olpc-pm.c
479 + * © 2006 Red Hat, Inc.
480 + * Portions also copyright 2006 Advanced Micro Devices, Inc.
484 +#include <linux/kernel.h>
485 +#include <linux/interrupt.h>
486 +#include <linux/module.h>
487 +#include <linux/delay.h>
488 +#include <linux/input.h>
489 +#include <linux/suspend.h>
490 +#include <linux/bootmem.h>
491 +#include <linux/platform_device.h>
492 +#include <linux/rtc.h>
493 +#include <linux/mc146818rtc.h>
496 +#include <asm/olpc.h>
498 +/* A few words about accessing the ACPI and PM registers. Long story short,
499 + byte and word accesses of the ACPI and PM registers is broken. The only
500 + way to do it really correctly is to use dword accesses, which we do
501 + throughout this code. For more details, please consult Eratta 17 and 18
504 + http://www.amd.com/files/connectivitysolutions/geode/geode_gx/34472D_CS5536_B1_specupdate.pdf
509 +#define CS5536_PM_PWRBTN (1 << 8)
510 +#define CS5536_PM_RTC (1 << 10)
511 +#define CS5536_PM_WAK (1 << 15)
513 +#define GPIO_WAKEUP_EC (1 << 31)
514 +#define GPIO_WAKEUP_LID (1 << 30)
516 +#define PM_MODE_NORMAL 0
517 +#define PM_MODE_TEST 1
518 +#define PM_MODE_MAX 2
520 +/* These, and the battery EC commands, should be in an olpc.h. */
521 +#define EC_WRITE_SCI_MASK 0x1b
522 +#define EC_READ_SCI_MASK 0x1c
524 +extern void do_olpc_suspend_lowlevel(void);
527 + unsigned long address;
528 + unsigned short segment;
529 +} ofw_bios_entry = { 0, __KERNEL_CS };
531 +static int olpc_pm_mode = PM_MODE_NORMAL;
532 +static unsigned long acpi_base;
533 +static unsigned long pms_base;
535 +static int olpc_lid_flag;
537 +static struct input_dev *pm_inputdev;
538 +static struct input_dev *lid_inputdev;
539 +static struct input_dev *ebook_inputdev;
540 +static struct platform_suspend_ops olpc_pm_ops;
542 +static int gpio_wake_events = 0;
543 +static int ebook_state = -1;
544 +static u16 olpc_wakeup_mask = 0;
546 +static unsigned int test_timeout = 0;
547 +static char *wackup_source = "none";
549 +struct platform_device olpc_powerbutton_dev = {
550 + .name = "powerbutton",
554 +struct platform_device olpc_lid_dev = {
559 +static void __init init_ebook_state(void)
561 + if (olpc_ec_cmd(0x2a, NULL, 0, (unsigned char *) &ebook_state, 1)) {
562 + printk(KERN_WARNING "olpc-pm: failed to get EBOOK state!\n");
567 + /* the input layer needs to know what value to default to as well */
568 + input_report_switch(ebook_inputdev, SW_TABLET_MODE, ebook_state);
569 + input_sync(ebook_inputdev);
572 +static void (*battery_callback)(unsigned long);
573 +static DEFINE_SPINLOCK(battery_callback_lock);
575 +/* propagate_events is non-NULL if run from workqueue,
576 + NULL when called at init time to flush SCI queue */
577 +static void process_sci_queue(struct work_struct *propagate_events)
579 + unsigned char data = 0;
580 + unsigned char battery_events = 0;
584 + ret = olpc_ec_cmd(0x84, NULL, 0, &data, 1);
586 + printk(KERN_DEBUG "olpc-pm: SCI 0x%x received\n",
589 + if (wackup_source && !strcmp(wackup_source, "sci")) {
591 + * XXX: in order for this to not be racy, we
592 + * need assurance that we will never get
593 + * preempted by olpc_do_sleep here!
596 + case EC_SCI_SRC_EMPTY:
597 + wackup_source = "empty sci";
599 + case EC_SCI_SRC_GAME:
600 + wackup_source = "key press";
602 + case EC_SCI_SRC_BATTERY:
603 + wackup_source = "battery";
605 + case EC_SCI_SRC_BATSOC:
606 + wackup_source = "battery state change";
608 + case EC_SCI_SRC_BATERR:
609 + wackup_source = "battery error";
611 + case EC_SCI_SRC_EBOOK:
612 + wackup_source = "ebook";
614 + case EC_SCI_SRC_WLAN:
615 + wackup_source = "wlan packet";
617 + case EC_SCI_SRC_ACPWR:
618 + wackup_source = "ac power";
621 + wackup_source = "unknown";
625 + if (data & (EC_SCI_SRC_BATERR | EC_SCI_SRC_BATSOC |
626 + EC_SCI_SRC_BATTERY | EC_SCI_SRC_ACPWR))
627 + battery_events |= data;
628 + else if (data == EC_SCI_SRC_EBOOK) {
629 + ebook_state = !ebook_state;
630 + if (propagate_events) {
631 + input_report_switch(ebook_inputdev,
632 + SW_TABLET_MODE, ebook_state);
633 + input_sync(ebook_inputdev);
637 + } while (data && !ret);
639 + if (battery_events && battery_callback && propagate_events) {
640 + void (*cbk)(unsigned long);
642 + /* Older EC versions didn't distinguish between AC and battery
644 + if (olpc_platform_info.ecver < 0x51)
645 + battery_events = EC_SCI_SRC_BATTERY | EC_SCI_SRC_ACPWR;
647 + spin_lock(&battery_callback_lock);
648 + cbk = battery_callback;
649 + spin_unlock(&battery_callback_lock);
651 + cbk(battery_events);
655 + printk(KERN_WARNING "Failed to clear SCI queue!\n");
658 +static DECLARE_WORK(sci_work, process_sci_queue);
660 +void olpc_register_battery_callback(void (*f)(unsigned long))
662 + spin_lock(&battery_callback_lock);
663 + battery_callback = f;
664 + spin_unlock(&battery_callback_lock);
666 +EXPORT_SYMBOL_GPL(olpc_register_battery_callback);
668 +void olpc_deregister_battery_callback(void)
670 + spin_lock(&battery_callback_lock);
671 + battery_callback = NULL;
672 + spin_unlock(&battery_callback_lock);
673 + cancel_work_sync(&sci_work);
675 +EXPORT_SYMBOL_GPL(olpc_deregister_battery_callback);
678 +static int olpc_pm_interrupt(int irq, void *id)
680 + uint32_t sts, gpe = 0;
682 + sts = inl(acpi_base + PM1_STS);
683 + outl(sts | 0xFFFF, acpi_base + PM1_STS);
685 + if (olpc_board_at_least(olpc_board(0xb2))) {
686 + gpe = inl(acpi_base + PM_GPE0_STS);
687 + outl(0xFFFFFFFF, acpi_base + PM_GPE0_STS);
690 + if (sts & CS5536_PM_PWRBTN) {
691 + if (!wackup_source)
692 + wackup_source = "power button";
693 + printk(KERN_DEBUG "olpm-pm: PM_PWRBTN %sevent received\n",
694 + sts & CS5536_PM_WAK ? "wakeup " : "");
695 + if (!(sts & CS5536_PM_WAK)) {
696 + input_report_key(pm_inputdev, KEY_POWER, 1);
697 + input_sync(pm_inputdev);
698 + /* Do we need to delay this? */
699 + input_report_key(pm_inputdev, KEY_POWER, 0);
700 + input_sync(pm_inputdev);
704 + if (gpe & GPIO_WAKEUP_EC) {
705 + geode_gpio_clear(OLPC_GPIO_ECSCI, GPIO_NEGATIVE_EDGE_STS);
706 + if (!wackup_source)
707 + wackup_source = "sci";
708 + schedule_work(&sci_work);
711 + if (gpe & GPIO_WAKEUP_LID) {
712 + /* Disable events */
713 + geode_gpio_clear(OLPC_GPIO_LID, GPIO_EVENTS_ENABLE);
715 + /* Clear the edge */
718 + geode_gpio_clear(OLPC_GPIO_LID, GPIO_NEGATIVE_EDGE_EN);
720 + geode_gpio_clear(OLPC_GPIO_LID, GPIO_POSITIVE_EDGE_EN);
722 + /* Clear the status too */
723 + geode_gpio_set(OLPC_GPIO_LID, GPIO_NEGATIVE_EDGE_STS);
724 + geode_gpio_set(OLPC_GPIO_LID, GPIO_POSITIVE_EDGE_STS);
726 + /* The line is high when the LID is open, but SW_LID
727 + * should be high when the LID is closed, so we pass the old
728 + * value of olpc_lid_flag
731 + input_report_switch(lid_inputdev, SW_LID, olpc_lid_flag);
732 + input_sync(lid_inputdev);
733 + if (!wackup_source)
734 + wackup_source = "lid";
736 + /* Swap the status */
737 + olpc_lid_flag = !olpc_lid_flag;
740 + geode_gpio_set(OLPC_GPIO_LID, GPIO_NEGATIVE_EDGE_EN);
742 + geode_gpio_set(OLPC_GPIO_LID, GPIO_POSITIVE_EDGE_EN);
744 + /* re-enable the event */
745 + geode_gpio_set(OLPC_GPIO_LID, GPIO_EVENTS_ENABLE);
748 + return IRQ_HANDLED;
751 +int olpc_ec_mask_set(u8 bits)
756 + ret = olpc_ec_cmd(EC_READ_SCI_MASK, NULL, 0, &byte, 1);
758 + printk(KERN_ERR "olpc-pm: error getting SCI mask: %d\n", ret);
761 + /* the high bit is unused, if it is ever unset, that is a good sign
762 + sign of EC communication corruption! */
763 + WARN_ON(!(byte & 0x80));
766 + ret = olpc_ec_cmd(EC_WRITE_SCI_MASK, &byte, 1, NULL, 0);
768 + printk(KERN_ERR "olpc-pm: error setting SCI mask: %d\n", ret);
772 +EXPORT_SYMBOL_GPL(olpc_ec_mask_set);
774 +int olpc_ec_mask_unset(u8 bits)
779 + ret = olpc_ec_cmd(EC_READ_SCI_MASK, NULL, 0, &byte, 1);
781 + printk(KERN_ERR "olpc-pm: error getting SCI mask: %d\n", ret);
784 + /* the high bit is unused, if it is ever unset, that is a good sign
785 + sign of EC communication corruption! */
786 + WARN_ON(!(byte & 0x80));
789 + ret = olpc_ec_cmd(EC_WRITE_SCI_MASK, &byte, 1, NULL, 0);
791 + printk(KERN_ERR "olpc-pm: error setting SCI mask: %d\n", ret);
795 +EXPORT_SYMBOL_GPL(olpc_ec_mask_unset);
798 + * For now, only support STR. We also don't support suspending on
799 + * B1s, due to difficulties with the cafe FPGA.
801 +static int olpc_pm_state_valid(suspend_state_t pm_state)
803 + if (pm_state == PM_SUSPEND_MEM && olpc_board_at_least(olpc_board(0xb2)))
809 +/* This is a catchall function for operations that just don't belong
810 + * anywhere else. Later we will evaluate if these belong in the
811 + * individual device drivers or the firmware.
812 + * If you add something to this function, please explain yourself with
816 +extern void gxfb_flatpanel_control(int state);
818 +static u32 gpio_wakeup[2];
819 +static u64 irq_sources[4];
820 +static u64 mfgpt_irq_msr, mfgpt_nr_msr;
822 +void olpc_fixup_wakeup(void)
824 + u32 base = geode_gpio_base();
827 + /* Enable the flatpanel sequencing as early as possible, because
828 + it takes ~64ms to resume. This probably belongs in the firmware */
830 + //gxfb_flatpanel_control(1);
832 + /* Tell the EC to stop inhibiting SCIs */
833 + olpc_ec_cmd(0x34, NULL, 0, NULL, 0);
835 + /* Restore the interrupt sources */
836 + wrmsrl(MSR_PIC_YSEL_LOW, irq_sources[0]);
837 + wrmsrl(MSR_PIC_ZSEL_LOW, irq_sources[1]);
838 + wrmsrl(MSR_PIC_YSEL_HIGH, irq_sources[2]);
839 + wrmsrl(MSR_PIC_ZSEL_HIGH, irq_sources[3]);
841 + /* Restore the X and Y sources for GPIO */
842 + outl(gpio_wakeup[0], base + GPIO_MAP_X);
843 + outl(gpio_wakeup[1], base + GPIO_MAP_Y);
845 + /* Resture the MFGPT MSRs */
846 + wrmsrl(MFGPT_IRQ_MSR, mfgpt_irq_msr);
847 + wrmsrl(MFGPT_NR_MSR, mfgpt_nr_msr);
849 + for (i=0;i<2;i++) {
850 + /* tell the wireless module to restart USB communication */
851 + olpc_ec_cmd(0x24, NULL, 0, NULL, 0);
854 + /* Turn all events on */
855 + olpc_ec_mask_set(EC_SCI_SRC_ALL);
858 +void olpc_fixup_sleep(void)
860 + u32 base = geode_gpio_base();
863 + /* Save the X and Y sources for GPIO */
864 + gpio_wakeup[0] = inl(base + GPIO_MAP_X);
865 + gpio_wakeup[1] = inl(base + GPIO_MAP_Y);
867 + /* Save the Y and Z unrestricted sources */
869 + rdmsrl(MSR_PIC_YSEL_LOW, irq_sources[0]);
870 + rdmsrl(MSR_PIC_ZSEL_LOW, irq_sources[1]);
871 + rdmsrl(MSR_PIC_YSEL_HIGH, irq_sources[2]);
872 + rdmsrl(MSR_PIC_ZSEL_HIGH, irq_sources[3]);
874 + /* Turn off the MFGPT timers on the way down */
876 + for(i = 0; i < 8; i++) {
877 + u32 val = geode_mfgpt_read(i, MFGPT_REG_SETUP);
879 + if (val & MFGPT_SETUP_SETUP) {
880 + val &= ~MFGPT_SETUP_CNTEN;
881 + geode_mfgpt_write(i, MFGPT_REG_SETUP, val);
885 + /* Save the MFGPT MSRs */
886 + rdmsrl(MFGPT_IRQ_MSR, mfgpt_irq_msr);
887 + rdmsrl(MFGPT_NR_MSR, mfgpt_nr_msr);
889 + if (device_may_wakeup(&olpc_powerbutton_dev.dev))
890 + olpc_wakeup_mask |= CS5536_PM_PWRBTN;
892 + olpc_wakeup_mask &= ~(CS5536_PM_PWRBTN);
894 + if (device_may_wakeup(&olpc_lid_dev.dev)) {
895 + geode_gpio_set(OLPC_GPIO_LID, GPIO_EVENTS_ENABLE);
896 + gpio_wake_events |= GPIO_WAKEUP_LID;
898 + geode_gpio_clear(OLPC_GPIO_LID, GPIO_EVENTS_ENABLE);
899 + gpio_wake_events &= ~(GPIO_WAKEUP_LID);
902 + /* We don't want to wake up on superfluous events */
903 + olpc_ec_mask_unset(EC_SCI_SRC_BATSOC | EC_SCI_SRC_ACPWR);
906 + * Cmd 0x32 tells the EC that we're going into suspend; this was
907 + * added to work around hardware races related to SCI events. This
908 + * should cause the EC to inhibit further SCIs while MAIN_ON is
909 + * transitioning low.
911 + * There's also some sort of EC race whereby the EC gets its
912 + * IBF/OBF flags confused and all future communication (after
913 + * resuming) fails if we suspend too soon after updating
914 + * the EC SCI mask. Having this command after updating the
915 + * SCI mask allows the EC enough time to finish doing what it's
918 + olpc_ec_cmd(0x32, NULL, 0, NULL, 0);
921 +static int olpc_pm_enter(suspend_state_t pm_state)
923 + /* Only STR is supported */
924 + if (pm_state != PM_SUSPEND_MEM)
927 + olpc_fixup_sleep();
929 + /* Set the GPIO wakeup bits */
930 + outl(gpio_wake_events, acpi_base + PM_GPE0_EN);
931 + outl(0xFFFFFFFF, acpi_base + PM_GPE0_STS);
933 + /* Save CPU state */
934 + do_olpc_suspend_lowlevel();
936 + olpc_fixup_wakeup();
938 + /* Restore the SCI wakeup events */
939 + outl(gpio_wake_events, acpi_base + PM_GPE0_EN);
944 +int asmlinkage olpc_do_sleep(u8 sleep_state)
946 + void *pgd_addr = __va(read_cr3());
947 + printk(KERN_ERR "olpc_do_sleep!\n"); /* this needs to remain here so
948 + * that gcc doesn't optimize
949 + * away our __va! */
950 + /* FIXME: Set the SCI bits we want to wake up on here */
952 + /* FIXME: Set any other SCI events that we might want here */
954 + outl((olpc_wakeup_mask << 16) | 0xFFFF, acpi_base + PM1_STS);
956 + wackup_source = NULL;
958 + /* If we are in test mode, then just return (simulate a successful
959 + suspend/resume). Otherwise, if we are doing the real thing,
960 + then go for the gusto */
962 + if (olpc_pm_mode != PM_MODE_TEST) {
963 + __asm__ __volatile__("movl %0,%%eax" : : "r" (pgd_addr));
964 + __asm__("call *(%%edi); cld"
965 + : : "D" (&ofw_bios_entry));
966 + __asm__ __volatile__("movb $0x34, %al\n\t"
967 + "outb %al, $0x70\n\t"
968 + "movb $0x30, %al\n\t"
969 + "outb %al, $0x71\n\t");
972 + else if (test_timeout > 0) {
975 + /* Delay N seconds for testing purposes */
977 + for(t = 0; t < test_timeout; t++)
984 +static void olpc_power_off(void)
986 + printk(KERN_INFO "OLPC power off sequence...\n");
988 + /* Enable all of these controls with 0 delay */
989 + outl(0x40000000, pms_base + PM_SCLK);
990 + outl(0x40000000, pms_base + PM_IN_SLPCTL);
991 + outl(0x40000000, pms_base + PM_WKXD);
992 + outl(0x40000000, pms_base + PM_WKD);
994 + /* Clear status bits (possibly unnecessary) */
995 + outl(0x0002ffff, pms_base + PM_SSC);
996 + outl(0xffffffff, acpi_base + PM_GPE0_STS);
998 + /* Write SLP_EN bit to start the machinery */
999 + outl(0x00002000, acpi_base + PM1_CNT);
1002 +/* This code will slowly disappear as we fixup the issues in the BIOS */
1004 +static void __init olpc_fixup_bios(void)
1006 + unsigned long hi, lo;
1008 + if (olpc_has_vsa()) {
1009 + /* The VSA aggressively sets up the ACPI and PM register for
1010 + * trapping - its not enough to force these values in the BIOS -
1011 + * they seem to be changed during PCI init as well.
1014 + /* Change the PM registers to decode to the DD */
1016 + rdmsr(0x510100e2, lo, hi);
1018 + wrmsr(0x510100e2, lo, hi);
1020 + /* Change the ACPI registers to decode to the DD */
1022 + rdmsr(0x510100e3, lo, hi);
1024 + wrmsr(0x510100e3, lo, hi);
1027 + /* GPIO24 controls WORK_AUX */
1029 + geode_gpio_set(OLPC_GPIO_WORKAUX, GPIO_OUTPUT_ENABLE);
1030 + geode_gpio_set(OLPC_GPIO_WORKAUX, GPIO_OUTPUT_AUX1);
1032 + if (olpc_board_at_least(olpc_board(0xb2))) {
1033 + /* GPIO10 is connected to the thermal alarm */
1034 + geode_gpio_set(OLPC_GPIO_THRM_ALRM, GPIO_INPUT_ENABLE);
1035 + geode_gpio_set(OLPC_GPIO_THRM_ALRM, GPIO_INPUT_AUX1);
1037 + /* Set up to get LID events */
1038 + geode_gpio_set(OLPC_GPIO_LID, GPIO_INPUT_ENABLE);
1040 + /* Clear edge detection and event enable for now */
1041 + geode_gpio_clear(OLPC_GPIO_LID, GPIO_EVENTS_ENABLE);
1042 + geode_gpio_clear(OLPC_GPIO_LID, GPIO_NEGATIVE_EDGE_EN);
1043 + geode_gpio_clear(OLPC_GPIO_LID, GPIO_POSITIVE_EDGE_EN);
1045 + geode_gpio_set(OLPC_GPIO_LID, GPIO_NEGATIVE_EDGE_STS);
1046 + geode_gpio_set(OLPC_GPIO_LID, GPIO_POSITIVE_EDGE_STS);
1048 + /* Set the LID to cause an PME event on group 6 */
1049 + geode_gpio_event_pme(OLPC_GPIO_LID, 6);
1051 + /* Set PME group 6 to fire the SCI interrupt */
1052 + geode_gpio_set_irq(6, sci_irq);
1055 + geode_gpio_set(OLPC_GPIO_ECSCI, GPIO_INPUT_ENABLE);
1057 + /* Clear pending events */
1059 + geode_gpio_set(OLPC_GPIO_ECSCI, GPIO_NEGATIVE_EDGE_STS);
1060 + geode_gpio_set(OLPC_GPIO_ECSCI, GPIO_POSITIVE_EDGE_STS);
1062 + //geode_gpio_set(OLPC_GPIO_ECSCI, GPIO_NEGATIVE_EDGE_EN);
1063 + geode_gpio_set(OLPC_GPIO_ECSCI, GPIO_EVENTS_ENABLE);
1065 + /* Set the SCI to cause a PME event on group 7 */
1066 + geode_gpio_event_pme(OLPC_GPIO_ECSCI, 7);
1068 + /* And have group 6 also fire the SCI interrupt */
1069 + geode_gpio_set_irq(7, sci_irq);
1072 +/* This provides a control file for setting up testing of the
1073 + power management system. For now, there is just one setting:
1074 + "test" which means that we don't actually enter the power
1078 +static const char * const pm_states[] = {
1079 + [PM_MODE_NORMAL] = "normal",
1080 + [PM_MODE_TEST] = "test",
1083 +extern struct mutex pm_mutex;
1084 +extern struct kset power_subsys;
1086 +static ssize_t control_show(struct kset *s, char *buf)
1088 + return sprintf(buf, "%s\n", pm_states[olpc_pm_mode]);
1091 +static ssize_t control_store(struct kset *s, const char *buf, size_t n)
1096 + p = memchr(buf, '\n', n);
1097 + len = p ? p - buf : n;
1099 + /* Grab the mutex */
1100 + mutex_lock(&pm_mutex);
1102 + for(i = 0; i < PM_MODE_MAX; i++) {
1103 + if (!strncmp(buf, pm_states[i], len)) {
1109 + mutex_unlock(&pm_mutex);
1111 + return (i == PM_MODE_MAX) ? -EINVAL : n;
1114 +static ssize_t timeout_show(struct kset *s, char *buf)
1116 + return sprintf(buf, "%d\n", test_timeout);
1119 +static ssize_t timeout_store(struct kset *s, const char *buf, size_t n)
1121 + unsigned int t = simple_strtoul(buf, NULL, 0);
1127 +static ssize_t wackup_show(struct kset *s, char *buf)
1129 + return sprintf(buf, "%s\n", wackup_source ? wackup_source : "none");
1132 +static struct subsys_attribute control_attr = {
1134 + .name = "olpc-pm",
1137 + .show = control_show,
1138 + .store = control_store,
1141 +static struct subsys_attribute test_attr = {
1143 + .name = "test-timeout",
1146 + .show = timeout_show,
1147 + .store = timeout_store,
1150 +static struct subsys_attribute wackup_attr = {
1152 + .name = "wakeup-source",
1155 + .show = wackup_show,
1158 +static struct attribute * olpc_attributes[] = {
1159 + &control_attr.attr,
1161 + &wackup_attr.attr,
1165 +static struct attribute_group olpc_attrs = {
1166 + .attrs = olpc_attributes,
1169 +static int __init alloc_inputdevs(void)
1171 + int ret = -ENOMEM;
1173 + pm_inputdev = input_allocate_device();
1177 + pm_inputdev->name = "OLPC PM";
1178 + pm_inputdev->phys = "olpc_pm/input0";
1179 + set_bit(EV_KEY, pm_inputdev->evbit);
1180 + set_bit(KEY_POWER, pm_inputdev->keybit);
1182 + ret = input_register_device(pm_inputdev);
1184 + printk(KERN_ERR "olpc-pm: failed to register PM input device: %d\n", ret);
1188 + lid_inputdev = input_allocate_device();
1189 + if (!lid_inputdev)
1192 + lid_inputdev->name = "OLPC lid switch";
1193 + lid_inputdev->phys = "olpc_pm/input1";
1194 + set_bit(EV_SW, lid_inputdev->evbit);
1195 + set_bit(SW_LID, lid_inputdev->swbit);
1197 + ret = input_register_device(lid_inputdev);
1199 + printk(KERN_ERR "olpc-pm: failed to register lid input device: %d\n", ret);
1203 + ebook_inputdev = input_allocate_device();
1204 + if (!ebook_inputdev)
1207 + ebook_inputdev->name = "OLPC ebook switch";
1208 + ebook_inputdev->phys = "olpc_pm/input2";
1209 + set_bit(EV_SW, ebook_inputdev->evbit);
1210 + set_bit(SW_TABLET_MODE, ebook_inputdev->swbit);
1212 + ret = input_register_device(ebook_inputdev);
1214 + printk(KERN_ERR "olpc-pm: failed to register ebook input device: %d\n", ret);
1220 + if (ebook_inputdev) {
1221 + input_unregister_device(ebook_inputdev);
1222 + ebook_inputdev = NULL;
1224 + if (lid_inputdev) {
1225 + input_unregister_device(lid_inputdev);
1226 + lid_inputdev = NULL;
1228 + if (pm_inputdev) {
1229 + input_unregister_device(pm_inputdev);
1230 + pm_inputdev = NULL;
1236 +static int __init olpc_pm_init(void)
1241 + if (!machine_is_olpc())
1244 + acpi_base = geode_acpi_base();
1245 + pms_base = geode_pms_base();
1247 + if (!acpi_base || !pms_base)
1250 + pm_power_off = olpc_power_off;
1252 + ret = alloc_inputdevs();
1256 + rdmsr(0x51400020, lo, hi);
1257 + sci_irq = (lo >> 20) & 15;
1260 + printk(KERN_INFO "SCI is mapped to IRQ %d\n", sci_irq);
1262 + /* Zero doesn't mean zero -- it means masked */
1263 + printk(KERN_INFO "SCI unmapped. Mapping to IRQ 3\n");
1266 + wrmsrl(0x51400020, lo);
1269 + olpc_fixup_bios();
1271 + lo = inl(pms_base + PM_FSD);
1273 + /* Lock, enable failsafe, 4 seconds */
1274 + outl(0xc001f400, pms_base + PM_FSD);
1276 + /* Here we set up the SCI events we're interested in during
1277 + * real-time. We have no sleep button, and the RTC doesn't make
1278 + * sense, so set up the power button
1281 + outl(inl(acpi_base) | ((CS5536_PM_PWRBTN) << 16), acpi_base);
1283 + if (olpc_board_at_least(olpc_board(0xb2))) {
1284 + gpio_wake_events |= GPIO_WAKEUP_LID;
1286 + /* Get the current value of the GPIO, and set up the edges */
1287 + olpc_lid_flag = geode_gpio_isset(OLPC_GPIO_LID, GPIO_READ_BACK);
1289 + /* Watch for the opposite edge */
1291 + if (olpc_lid_flag)
1292 + geode_gpio_set(OLPC_GPIO_LID, GPIO_NEGATIVE_EDGE_EN);
1294 + geode_gpio_set(OLPC_GPIO_LID, GPIO_POSITIVE_EDGE_EN);
1296 + /* Enable the event */
1297 + geode_gpio_set(OLPC_GPIO_LID, GPIO_EVENTS_ENABLE);
1300 + /* Set up the EC SCI */
1302 + gpio_wake_events |= GPIO_WAKEUP_EC;
1304 + outl(gpio_wake_events, acpi_base + PM_GPE0_EN);
1305 + outl(0xFFFFFFFF, acpi_base + PM_GPE0_STS);
1307 + /* Select level triggered in PIC */
1309 + if (sci_irq < 8) {
1311 + lo |= 1 << sci_irq;
1315 + lo |= 1 << (sci_irq - 8);
1318 + /* Clear pending interrupt */
1319 + outl(inl(acpi_base) | 0xFFFF, acpi_base);
1320 + process_sci_queue(0); /* we just want to flush the queue here */
1321 + init_ebook_state();
1323 + /* Enable the interrupt */
1325 + ret = request_irq(sci_irq, &olpc_pm_interrupt, 0, "SCI", &acpi_base);
1328 + printk(KERN_ERR "Error registering SCI: %d\n", ret);
1332 + ofw_bios_entry.address = 0xF0000 + PAGE_OFFSET;
1333 + suspend_set_ops(&olpc_pm_ops);
1335 + sysfs_create_group(&power_subsys.kobj, &olpc_attrs);
1341 +#if defined (CONFIG_RTC_DRV_CMOS) || defined (CONFIG_RTC_DRV_CMOS_MODULE)
1342 +struct resource rtc_platform_resource[2] = {
1344 + .flags = IORESOURCE_IO,
1345 + .start = RTC_PORT(0),
1346 + .end = RTC_PORT(0) + RTC_IO_EXTENT
1349 + .flags = IORESOURCE_IRQ,
1356 +static void rtc_wake_on(struct device *dev)
1358 + olpc_wakeup_mask |= CS5536_PM_RTC;
1361 +static void rtc_wake_off(struct device *dev)
1363 + olpc_wakeup_mask &= ~(CS5536_PM_RTC);
1366 +static struct cmos_rtc_board_info rtc_info = {
1367 + .rtc_day_alarm = 0,
1368 + .rtc_mon_alarm = 0,
1370 + .wake_on = rtc_wake_on,
1371 + .wake_off = rtc_wake_off,
1374 +struct platform_device olpc_rtc_device = {
1375 + .name = "rtc_cmos",
1377 + .num_resources = ARRAY_SIZE(rtc_platform_resource),
1378 + .dev.platform_data = &rtc_info,
1379 + .resource = rtc_platform_resource,
1382 +static int __init olpc_platform_init(void)
1384 + rdmsrl(MSR_RTC_DOMA_OFFSET, rtc_info.rtc_day_alarm);
1385 + rdmsrl(MSR_RTC_MONA_OFFSET, rtc_info.rtc_mon_alarm);
1386 + rdmsrl(MSR_RTC_CEN_OFFSET, rtc_info.rtc_century);
1388 + (void)platform_device_register(&olpc_rtc_device);
1389 + device_init_wakeup(&olpc_rtc_device.dev, 1);
1391 + (void)platform_device_register(&olpc_powerbutton_dev);
1392 + device_init_wakeup(&olpc_powerbutton_dev.dev, 1);
1394 + (void)platform_device_register(&olpc_lid_dev);
1395 + device_init_wakeup(&olpc_lid_dev.dev, 1);
1399 +arch_initcall(olpc_platform_init);
1400 +#endif /* CONFIG_RTC_DRV_CMOS */
1402 +static void olpc_pm_exit(void)
1404 + /* Clear any pending events, and disable them */
1405 + outl(0xFFFF, acpi_base+2);
1407 + free_irq(sci_irq, &acpi_base);
1408 + input_unregister_device(pm_inputdev);
1409 + input_unregister_device(lid_inputdev);
1410 + input_unregister_device(ebook_inputdev);
1413 +static struct platform_suspend_ops olpc_pm_ops = {
1414 + .valid = olpc_pm_state_valid,
1415 + .enter = olpc_pm_enter,
1418 +module_init(olpc_pm_init);
1419 +module_exit(olpc_pm_exit);
1421 +MODULE_LICENSE("GPL");
1422 +MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
1423 +MODULE_DESCRIPTION("AMD Geode power management for OLPC CL1");
1424 Index: linux-2.6.24.7/arch/x86/kernel/olpc-sleep.S
1425 ===================================================================
1427 +++ linux-2.6.24.7/arch/x86/kernel/olpc-sleep.S
1431 +ENTRY(olpc_sleep_asm)
1433 + ;; Get the value of PM1_CNT and store it off
1441 + ;; flush the cache
1444 + ;; GX2 must disable refresh before going into self-refresh
1445 + mov 2000000180xh, ecx
1448 + and 0FF0000FFh, eax
1451 + ;; Now, put the memory into self refresh
1458 + ;; Thats all she wrote - time to go to sleep
1468 Index: linux-2.6.24.7/arch/x86/kernel/olpc-wakeup.S
1469 ===================================================================
1471 +++ linux-2.6.24.7/arch/x86/kernel/olpc-wakeup.S
1474 +#include <linux/linkage.h>
1475 +#include <asm/segment.h>
1476 +#include <asm/page.h>
1478 + .macro writepost,value
1494 + # Clear any dangerous flags
1502 + movl $swsusp_pg_dir - __PAGE_OFFSET, %eax
1505 + movl saved_cr4, %eax
1508 + movl saved_cr0, %eax
1513 + ljmpl $__KERNEL_CS,$wakeup_return
1519 + movw $__KERNEL_DS, %ax
1529 + ljmp $(__KERNEL_CS),$1f
1535 + # Go back to the return point
1545 + movl %edx, saved_cr4
1548 + movl %edx, saved_cr0
1553 + movl %ebx, saved_context_ebx
1554 + movl %ebp, saved_context_ebp
1555 + movl %esi, saved_context_esi
1556 + movl %edi, saved_context_edi
1559 + popl saved_context_eflags
1565 + movl saved_context_ebp, %ebp
1566 + movl saved_context_ebx, %ebx
1567 + movl saved_context_esi, %esi
1568 + movl saved_context_edi, %edi
1570 + pushl saved_context_eflags
1576 +ENTRY(do_olpc_suspend_lowlevel)
1577 + call save_processor_state
1578 + call save_registers
1580 + # This is the stack context we want to remember
1581 + movl %esp, saved_context_esp
1584 + call olpc_do_sleep
1589 + movl saved_context_esp, %esp
1593 + call restore_registers
1594 + call restore_processor_state
1600 +saved_gdt: .long 0,0
1601 +saved_idt: .long 0,0
1606 Index: linux-2.6.24.7/arch/x86/kernel/prom.c
1607 ===================================================================
1609 +++ linux-2.6.24.7/arch/x86/kernel/prom.c
1612 + * Procedures for creating, accessing and interpreting the device tree.
1614 + * Paul Mackerras August 1996.
1615 + * Copyright (C) 1996-2005 Paul Mackerras.
1617 + * Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
1618 + * {engebret|bergner}@us.ibm.com
1620 + * Adapted for sparc64 by David S. Miller davem@davemloft.net
1622 + * Adapter for i386/OLPC by Andres Salomon <dilinger@debian.org>
1624 + * This program is free software; you can redistribute it and/or
1625 + * modify it under the terms of the GNU General Public License
1626 + * as published by the Free Software Foundation; either version
1627 + * 2 of the License, or (at your option) any later version.
1630 +#include <linux/kernel.h>
1631 +#include <linux/types.h>
1632 +#include <linux/string.h>
1633 +#include <linux/mm.h>
1634 +#include <linux/bootmem.h>
1635 +#include <linux/module.h>
1636 +#include <asm/prom.h>
1637 +#include <asm/ofw.h>
1640 + * XXX: This is very much a stub; right now we're keeping 2 device trees
1641 + * in memory (one for promfs, and one here). That will not remain
1645 +static struct device_node *allnodes;
1647 +/* use when traversing tree through the allnext, child, sibling,
1648 + * or parent members of struct device_node.
1650 +static DEFINE_RWLOCK(devtree_lock);
1652 +int of_device_is_compatible(const struct device_node *device,
1653 + const char *compat)
1658 + cp = of_get_property(device, "compatible", &cplen);
1661 + while (cplen > 0) {
1662 + if (strncmp(cp, compat, strlen(compat)) == 0)
1664 + l = strlen(cp) + 1;
1671 +EXPORT_SYMBOL(of_device_is_compatible);
1673 +struct device_node *of_get_parent(const struct device_node *node)
1675 + struct device_node *np;
1680 + np = node->parent;
1684 +EXPORT_SYMBOL(of_get_parent);
1686 +struct device_node *of_get_next_child(const struct device_node *node,
1687 + struct device_node *prev)
1689 + struct device_node *next;
1691 + next = prev ? prev->sibling : node->child;
1692 + for (; next != 0; next = next->sibling) {
1698 +EXPORT_SYMBOL(of_get_next_child);
1700 +struct device_node *of_find_node_by_path(const char *path)
1702 + struct device_node *np = allnodes;
1704 + for (; np != 0; np = np->allnext) {
1705 + if (np->full_name != 0 && strcmp(np->full_name, path) == 0)
1711 +EXPORT_SYMBOL(of_find_node_by_path);
1713 +struct device_node *of_find_node_by_phandle(phandle handle)
1715 + struct device_node *np;
1717 + for (np = allnodes; np != 0; np = np->allnext)
1718 + if (np->node == handle)
1723 +EXPORT_SYMBOL(of_find_node_by_phandle);
1725 +struct device_node *of_find_node_by_name(struct device_node *from,
1728 + struct device_node *np;
1730 + np = from ? from->allnext : allnodes;
1731 + for (; np != NULL; np = np->allnext)
1732 + if (np->name != NULL && strcmp(np->name, name) == 0)
1737 +EXPORT_SYMBOL(of_find_node_by_name);
1739 +struct device_node *of_find_node_by_type(struct device_node *from,
1742 + struct device_node *np;
1744 + np = from ? from->allnext : allnodes;
1745 + for (; np != 0; np = np->allnext)
1746 + if (np->type != 0 && strcmp(np->type, type) == 0)
1751 +EXPORT_SYMBOL(of_find_node_by_type);
1753 +struct device_node *of_find_compatible_node(struct device_node *from,
1754 + const char *type, const char *compatible)
1756 + struct device_node *np;
1758 + np = from ? from->allnext : allnodes;
1759 + for (; np != 0; np = np->allnext) {
1761 + && !(np->type != 0 && strcmp(np->type, type) == 0))
1763 + if (of_device_is_compatible(np, compatible))
1769 +EXPORT_SYMBOL(of_find_compatible_node);
1771 +struct property *of_find_property(const struct device_node *np,
1775 + struct property *pp;
1777 + for (pp = np->properties; pp != 0; pp = pp->next) {
1778 + if (strcasecmp(pp->name, name) == 0) {
1780 + *lenp = pp->length;
1786 +EXPORT_SYMBOL(of_find_property);
1789 + * Find a property with a given name for a given node
1790 + * and return the value.
1792 +const void *of_get_property(const struct device_node *np, const char *name,
1795 + struct property *pp = of_find_property(np,name,lenp);
1796 + return pp ? pp->value : NULL;
1798 +EXPORT_SYMBOL(of_get_property);
1800 +int of_getintprop_default(struct device_node *np, const char *name, int def)
1802 + struct property *prop;
1805 + prop = of_find_property(np, name, &len);
1806 + if (!prop || len != 4)
1809 + return *(int *) prop->value;
1811 +EXPORT_SYMBOL(of_getintprop_default);
1813 +int of_n_addr_cells(struct device_node *np)
1819 + ip = of_get_property(np, "#address-cells", NULL);
1822 + } while (np->parent);
1823 + /* No #address-cells property for the root node, default to 2 */
1826 +EXPORT_SYMBOL(of_n_addr_cells);
1828 +int of_n_size_cells(struct device_node *np)
1834 + ip = of_get_property(np, "#size-cells", NULL);
1837 + } while (np->parent);
1838 + /* No #size-cells property for the root node, default to 1 */
1841 +EXPORT_SYMBOL(of_n_size_cells);
1843 +int of_set_property(struct device_node *dp, const char *name, void *val, int len)
1847 +EXPORT_SYMBOL(of_set_property);
1849 +static unsigned int prom_early_allocated;
1851 +static void * __init prom_early_alloc(unsigned long size)
1855 + ret = kmalloc(size, GFP_KERNEL);
1857 + memset(ret, 0, size);
1859 + printk(KERN_ERR "ACK! couldn't allocate prom memory!\n");
1861 + prom_early_allocated += size;
1866 +static int is_root_node(const struct device_node *dp)
1871 + return (dp->parent == NULL);
1874 +static char * __init build_path_component(struct device_node *dp)
1879 + if (ofw("package-to-path", 3, 1, dp->node, NULL, 0, &pathlen)) {
1880 + printk(KERN_ERR "PROM: unable to get path name from OFW!\n");
1883 + n = prom_early_alloc(pathlen + 1);
1884 + if (ofw("package-to-path", 3, 1, dp->node, n, pathlen+1, &pathlen))
1885 + printk(KERN_ERR "PROM: unable to get path name from OFW\n");
1887 + if ((i = strrchr(n, '/')))
1888 + n = ++i; /* we only want the file name */
1892 +static char * __init build_full_name(struct device_node *dp)
1894 + int len, ourlen, plen;
1897 + plen = strlen(dp->parent->full_name);
1898 + ourlen = strlen(dp->path_component_name);
1899 + len = ourlen + plen + 2;
1901 + n = prom_early_alloc(len);
1902 + strcpy(n, dp->parent->full_name);
1903 + if (!is_root_node(dp->parent)) {
1904 + strcpy(n + plen, "/");
1907 + strcpy(n + plen, dp->path_component_name);
1912 +static struct property * __init build_one_prop(phandle node, char *prev, char *special_name, void *special_val, int special_len)
1914 + static struct property *tmp = NULL;
1915 + struct property *p;
1919 + memset(p, 0, sizeof(*p) + 32);
1922 + p = prom_early_alloc(sizeof(struct property) + 32);
1925 + p->name = (char *) (p + 1);
1926 + if (special_name) {
1927 + strcpy(p->name, special_name);
1928 + p->length = special_len;
1929 + p->value = prom_early_alloc(special_len);
1930 + memcpy(p->value, special_val, special_len);
1933 + if (prev == NULL) {
1934 + if (ofw("nextprop", 3, 1, node, "", p->name, &fl)) {
1935 + printk(KERN_ERR "PROM: %s: nextprop failed!\n", __func__);
1939 + if (ofw("nextprop", 3, 1, node, prev, p->name, &fl)) {
1940 + printk(KERN_ERR "PROM: %s: nextprop failed!\n", __func__);
1944 + if (strlen(p->name) == 0 || fl != 1) {
1948 + if (ofw("getproplen", 2, 1, node, p->name, &p->length)) {
1949 + printk(KERN_ERR "PROM: %s: getproplen failed!\n", __func__);
1952 + if (p->length <= 0) {
1955 + p->value = prom_early_alloc(p->length + 1);
1956 + if (ofw("getprop", 4, 1, node, p->name, p->value, p->length, &p->length)) {
1957 + printk(KERN_ERR "PROM: %s: getprop failed!\n", __func__);
1960 + ((unsigned char *)p->value)[p->length] = '\0';
1966 +static struct property * __init build_prop_list(phandle node)
1968 + struct property *head, *tail;
1970 + head = tail = build_one_prop(node, NULL,
1971 + ".node", &node, sizeof(node));
1973 + tail->next = build_one_prop(node, NULL, NULL, NULL, 0);
1974 + tail = tail->next;
1976 + tail->next = build_one_prop(node, tail->name,
1978 + tail = tail->next;
1984 +static char * __init get_one_property(phandle node, const char *name)
1986 + char *buf = "<NULL>";
1989 + if (ofw("getproplen", 2, 1, node, name, &len)) {
1990 + printk(KERN_ERR "PROM: %s: getproplen failed!\n", __func__);
1994 + buf = prom_early_alloc(len);
1995 + if (ofw("getprop", 4, 1, node, name, buf, len, &len)) {
1996 + printk(KERN_ERR "PROM: %s: getprop failed!\n", __func__);
2004 +static struct device_node * __init create_node(phandle node, struct device_node *parent)
2006 + struct device_node *dp;
2011 + dp = prom_early_alloc(sizeof(*dp));
2012 + dp->parent = parent;
2014 + kref_init(&dp->kref);
2016 + dp->name = get_one_property(node, "name");
2017 + dp->type = get_one_property(node, "device_type");
2020 + dp->properties = build_prop_list(node);
2025 +static struct device_node * __init build_tree(struct device_node *parent, phandle node, struct device_node ***nextp)
2027 + struct device_node *ret = NULL, *prev_sibling = NULL;
2028 + struct device_node *dp;
2032 + dp = create_node(node, parent);
2037 + prev_sibling->sibling = dp;
2041 + prev_sibling = dp;
2044 + *nextp = &dp->allnext;
2046 + dp->path_component_name = build_path_component(dp);
2047 + dp->full_name = build_full_name(dp);
2049 + if (ofw("child", 1, 1, node, &child)) {
2050 + printk(KERN_ERR "PROM: %s: fetching child failed!\n", __func__);
2053 + dp->child = build_tree(dp, child, nextp);
2055 + if (ofw("peer", 1, 1, node, &node)) {
2056 + printk(KERN_ERR "PROM: %s: fetching peer failed!\n", __func__);
2064 +static phandle root_node;
2066 +void __init prom_build_devicetree(void)
2068 + struct device_node **nextp;
2071 + if (ofw("peer", 1, 1, 0, &root_node)) {
2072 + printk(KERN_ERR "PROM: unable to get root node from OFW!\n");
2076 + allnodes = create_node(root_node, NULL);
2077 + allnodes->path_component_name = "";
2078 + allnodes->full_name = "/";
2080 + nextp = &allnodes->allnext;
2081 + if (ofw("child", 1, 1, allnodes->node, &child)) {
2082 + printk(KERN_ERR "PROM: unable to get child node from OFW!\n");
2085 + allnodes->child = build_tree(allnodes, child, &nextp);
2086 + printk("PROM: Built device tree with %u bytes of memory.\n",
2087 + prom_early_allocated);
2089 Index: linux-2.6.24.7/arch/x86/pci/olpc.c
2090 ===================================================================
2092 +++ linux-2.6.24.7/arch/x86/pci/olpc.c
2095 + * olpcpci.c - Low-level PCI config space access for OLPC systems
2096 + * without the VSA PCI virtualization software.
2098 + * The AMD Geode chipset (GX2 processor, cs5536 I/O companion device)
2099 + * has some I/O functions (display, southbridge, sound, USB HCIs, etc)
2100 + * that more or less behave like PCI devices, but the hardware doesn't
2101 + * directly implement the PCI configuration space headers. AMD provides
2102 + * "VSA" (Virtual System Architecture) software that emulates PCI config
2103 + * space for these devices, by trapping I/O accesses to PCI config register
2104 + * (CF8/CFC) and running some code in System Management Mode interrupt state.
2105 + * On the OLPC platform, we don't want to use that VSA code because
2106 + * (a) it slows down suspend/resume, and (b) recompiling it requires special
2107 + * compilers that are hard to get. So instead of letting the complex VSA
2108 + * code simulate the PCI config registers for the on-chip devices, we
2109 + * just simulate them the easy way, by inserting the code into the
2110 + * pci_write_config and pci_read_config path. Most of the config registers
2111 + * are read-only anyway, so the bulk of the simulation is just table lookup.
2114 +#include <linux/pci.h>
2115 +#include <linux/init.h>
2116 +#include <asm/olpc.h>
2117 +#include <asm/geode.h>
2123 + * In the tables below, the first two line (8 longwords) are the
2124 + * size masks that are used when the higher level PCI code determines
2125 + * the size of the region by writing ~0 to a base address register
2126 + * and reading back the result.
2128 + * The following lines are the values that are read during normal
2129 + * PCI config access cycles, i.e. not after just having written
2130 + * ~0 to a base address register.
2133 +static const u32 lxnb_hdr[] = { /* dev 1 function 0 - devfn = 8 */
2134 + 0x0 , 0x0 , 0x0 , 0x0 ,
2135 + 0x0 , 0x0 , 0x0 , 0x0 ,
2137 + 0x281022 , 0x2200005 , 0x6000021 , 0x80f808 , /* AMD Vendor ID */
2138 + 0x0 , 0x0 , 0x0 , 0x0 , /* No virtual registers, hence no BAR for them */
2139 + 0x0 , 0x0 , 0x0 , 0x28100b ,
2140 + 0x0 , 0x0 , 0x0 , 0x0 ,
2141 + 0x0 , 0x0 , 0x0 , 0x0 ,
2142 + 0x0 , 0x0 , 0x0 , 0x0 ,
2143 + 0x0 , 0x0 , 0x0 , 0x0 ,
2146 +static const u32 gxnb_hdr[] = { /* dev 1 function 0 - devfn = 8 */
2147 + 0xfffffffd , 0x0 , 0x0 , 0x0 ,
2148 + 0x0 , 0x0 , 0x0 , 0x0 ,
2150 + 0x28100b , 0x2200005 , 0x6000021 , 0x80f808 , /* NSC Vendor ID */
2151 + 0xac1d , 0x0 , 0x0 , 0x0 , /* I/O BAR - base of virtual registers */
2152 + 0x0 , 0x0 , 0x0 , 0x28100b ,
2153 + 0x0 , 0x0 , 0x0 , 0x0 ,
2154 + 0x0 , 0x0 , 0x0 , 0x0 ,
2155 + 0x0 , 0x0 , 0x0 , 0x0 ,
2156 + 0x0 , 0x0 , 0x0 , 0x0 ,
2159 +static const u32 lxfb_hdr[] = { /* dev 1 function 1 - devfn = 9 */
2160 + 0xff800008 , 0xffffc000 , 0xffffc000 , 0xffffc000 ,
2161 + 0x0 , 0x0 , 0x0 , 0x0 ,
2163 + 0x20811022 , 0x2200003 , 0x3000000 , 0x0 , /* AMD Vendor ID */
2164 + 0xfd000000 , 0xfe000000 , 0xfe004000 , 0xfe008000 , /* FB, GP, VG, DF */
2165 + 0xfe00c000 , 0x0 , 0x0 , 0x30100b , /* VIP */
2166 + 0x0 , 0x0 , 0x0 , 0x10e , /* INTA, IRQ14 for graphics accel */
2167 + 0x0 , 0x0 , 0x0 , 0x0 ,
2168 + 0x3d0 , 0x3c0 , 0xa0000 , 0x0 , /* VG IO, VG IO, EGA FB, MONO FB */
2169 + 0x0 , 0x0 , 0x0 , 0x0 ,
2172 +static const u32 gxfb_hdr[] = { /* dev 1 function 1 - devfn = 9 */
2173 + 0xff800008 , 0xffffc000 , 0xffffc000 , 0xffffc000 ,
2174 + 0x0 , 0x0 , 0x0 , 0x0 ,
2176 + 0x30100b , 0x2200003 , 0x3000000 , 0x0 , /* NSC Vendor ID */
2177 + 0xfd000000 , 0xfe000000 , 0xfe004000 , 0xfe008000 , /* FB, GP, VG, DF */
2178 + 0x0 , 0x0 , 0x0 , 0x30100b ,
2179 + 0x0 , 0x0 , 0x0 , 0x0 ,
2180 + 0x0 , 0x0 , 0x0 , 0x0 ,
2181 + 0x3d0 , 0x3c0 , 0xa0000 , 0x0 , /* VG IO, VG IO, EGA FB, MONO FB */
2182 + 0x0 , 0x0 , 0x0 , 0x0 ,
2185 +static const u32 aes_hdr[] = { /* dev 1 function 2 - devfn = 0xa */
2186 + 0xffffc000 , 0x0 , 0x0 , 0x0 ,
2187 + 0x0 , 0x0 , 0x0 , 0x0 ,
2189 + 0x20821022 , 0x2a00006 , 0x10100000 , 0x8 , /* NSC Vendor ID */
2190 + 0xfe010000 , 0x0 , 0x0 , 0x0 , /* AES registers */
2191 + 0x0 , 0x0 , 0x0 , 0x20821022 ,
2192 + 0x0 , 0x0 , 0x0 , 0x0 ,
2193 + 0x0 , 0x0 , 0x0 , 0x0 ,
2194 + 0x0 , 0x0 , 0x0 , 0x0 ,
2195 + 0x0 , 0x0 , 0x0 , 0x0 ,
2199 +static const u32 isa_hdr[] = { /* dev f function 0 - devfn = 78 */
2200 + 0xfffffff9 , 0xffffff01 , 0xffffffc1 , 0xffffffe1 ,
2201 + 0xffffff81 , 0xffffffc1 , 0x0 , 0x0 ,
2203 + 0x20901022 , 0x2a00049 , 0x6010003 , 0x802000 ,
2204 + 0x18b1 , 0x1001 , 0x1801 , 0x1881 , /* SMB-8 GPIO-256 MFGPT-64 IRQ-32 */
2205 + 0x1401 , 0x1841 , 0x0 , 0x20901022 , /* PMS-128 ACPI-64 */
2206 + 0x0 , 0x0 , 0x0 , 0x0 ,
2207 + 0x0 , 0x0 , 0x0 , 0x0 ,
2208 + 0x0 , 0x0 , 0x0 , 0xaa5b , /* interrupt steering */
2209 + 0x0 , 0x0 , 0x0 , 0x0 ,
2212 +static const u32 ac97_hdr[] = { /* dev f function 3 - devfn = 7b */
2213 + 0xffffff81 , 0x0 , 0x0 , 0x0 ,
2214 + 0x0 , 0x0 , 0x0 , 0x0 ,
2216 + 0x20931022 , 0x2a00041 , 0x4010001 , 0x0 ,
2217 + 0x1481 , 0x0 , 0x0 , 0x0 , /* I/O BAR-128 */
2218 + 0x0 , 0x0 , 0x0 , 0x20931022 ,
2219 + 0x0 , 0x0 , 0x0 , 0x205 , /* IntB , IRQ5 */
2220 + 0x0 , 0x0 , 0x0 , 0x0 ,
2221 + 0x0 , 0x0 , 0x0 , 0x0 ,
2222 + 0x0 , 0x0 , 0x0 , 0x0 ,
2225 +static const u32 ohci_hdr[] = { /* dev f function 4 - devfn = 7c */
2226 + 0xfffff000 , 0x0 , 0x0 , 0x0 ,
2227 + 0x0 , 0x0 , 0x0 , 0x0 ,
2229 + 0x20941022 , 0x2300006 , 0xc031002 , 0x0 ,
2230 + 0xfe01a000 , 0x0 , 0x0 , 0x0 , /* MEMBAR-1000 */
2231 + 0x0 , 0x0 , 0x0 , 0x20941022 ,
2232 + 0x0 , 0x40 , 0x0 , 0x40a , /* CapPtr INT-D, IRQ A */
2233 + 0xc8020001 , 0x0 , 0x0 , 0x0 , /* Capabilities - 40 is R/O, 44 is mask 8103 (power control) */
2234 + 0x0 , 0x0 , 0x0 , 0x0 ,
2235 + 0x0 , 0x0 , 0x0 , 0x0 ,
2238 +static const u32 ehci_hdr[] = { /* dev f function 4 - devfn = 7d */
2239 + 0xfffff000 , 0x0 , 0x0 , 0x0 ,
2240 + 0x0 , 0x0 , 0x0 , 0x0 ,
2242 + 0x20951022 , 0x2300006 , 0xc032002 , 0x0 ,
2243 + 0xfe01b000 , 0x0 , 0x0 , 0x0 , /* MEMBAR-1000 */
2244 + 0x0 , 0x0 , 0x0 , 0x20951022 ,
2245 + 0x0 , 0x40 , 0x0 , 0x40a , /* CapPtr INT-D, IRQ A */
2246 + 0xc8020001 , 0x0 , 0x0 , 0x0 , /* Capabilities - 40 is R/O, 44 is mask 8103 (power control) */
2248 + 0x1 , 0x40080000 , 0x0 , 0x0 , /* EECP - see section 2.1.7 of EHCI spec */
2250 + 0x01000001 , 0x00000000 , 0x0 , 0x0 , /* EECP - see section 2.1.7 of EHCI spec */
2251 + 0x2020 , 0x0 , 0x0 , 0x0 , /* (EHCI page 8) 60 SBRN (R/O), 61 FLADJ (R/W), PORTWAKECAP */
2254 +static u32 ff_loc = ~0;
2255 +static u32 zero_loc = 0;
2257 +static int bar_probing = 0; /* Set after a write of ~0 to a BAR */
2259 +#define NB_SLOT 0x1 /* Northbridge - GX chip - Device 1 */
2260 +#define SB_SLOT 0xf /* Southbridge - CS5536 chip - Device F */
2261 +#define SIMULATED(bus, devfn) (((bus) == 0) && ((PCI_SLOT(devfn) == NB_SLOT) || (PCI_SLOT(devfn) == SB_SLOT)))
2263 +static u32 *hdr_addr(const u32 *hdr, int reg)
2268 + * This is a little bit tricky. The header maps consist of
2269 + * 0x20 bytes of size masks, followed by 0x70 bytes of header data.
2270 + * In the normal case, when not probing a BAR's size, we want
2271 + * to access the header data, so we add 0x20 to the reg offset,
2272 + * thus skipping the size mask area.
2273 + * In the BAR probing case, we want to access the size mask for
2274 + * the BAR, so we subtract 0x10 (the config header offset for
2275 + * BAR0), and don't skip the size mask area.
2278 + addr = (u32)hdr + reg + (bar_probing ? -0x10 : 0x20);
2281 + return (u32 *)addr;
2284 +static int pci_olpc_read(unsigned int seg, unsigned int bus,
2285 + unsigned int devfn, int reg, int len, u32 *value)
2289 + /* Use the hardware mechanism for non-simulated devices */
2290 + if (!SIMULATED(bus, devfn))
2291 + return pci_conf1_read(seg, bus, devfn, reg, len, value);
2294 + * No device has config registers past 0x70, so we save table space
2295 + * by not storing entries for the nonexistent registers
2302 + addr = hdr_addr(is_lx ? lxnb_hdr : gxnb_hdr, reg);
2305 + addr = hdr_addr(is_lx ? lxfb_hdr : gxfb_hdr, reg);
2308 + addr = is_lx ? hdr_addr(aes_hdr, reg) : &ff_loc;
2311 + addr = hdr_addr(isa_hdr, reg);
2314 + addr = hdr_addr(ac97_hdr, reg);
2317 + addr = hdr_addr(ohci_hdr, reg);
2320 + addr = hdr_addr(ehci_hdr, reg);
2329 + *value = *(u8 *) addr;
2332 + *value = *(u16 *) addr;
2344 +static int pci_olpc_write(unsigned int seg, unsigned int bus,
2345 + unsigned int devfn, int reg, int len, u32 value)
2347 + /* Use the hardware mechanism for non-simulated devices */
2348 + if (!SIMULATED(bus, devfn))
2349 + return pci_conf1_write(seg, bus, devfn, reg, len, value);
2351 + /* XXX we may want to extend this to simulate EHCI power management */
2354 + * Mostly we just discard writes, but if the write is a size probe
2355 + * (i.e. writing ~0 to a BAR), we remember it and arrange to return
2356 + * the appropriate size mask on the next read. This is cheating
2357 + * to some extent, because it depends on the fact that the next
2358 + * access after such a write will always be a read to the same BAR.
2361 + if ((reg >= 0x10) && (reg < 0x2c)) {
2362 + /* Write is to a BAR */
2367 + * No warning on writes to ROM BAR, CMD, LATENCY_TIMER,
2368 + * CACHE_LINE_SIZE, or PM registers.
2370 + if ((reg != 0x30) && (reg != 0x04) && (reg != 0x0d) &&
2371 + (reg != 0x0c) && (reg != 0x44))
2372 + printk(KERN_WARNING "OLPC PCI: Config write to devfn %x reg %x value %x\n", devfn, reg, value);
2378 +static struct pci_raw_ops pci_olpc_conf = {
2379 + .read = pci_olpc_read,
2380 + .write = pci_olpc_write,
2383 +void __init pci_olpc_init(void)
2385 + if (!machine_is_olpc() || olpc_has_vsa())
2388 + printk(KERN_INFO "PCI: Using configuration type OLPC\n");
2389 + raw_pci_ops = &pci_olpc_conf;
2390 + is_lx = is_geode_lx();
2392 Index: linux-2.6.24.7/Documentation/kernel-parameters.txt
2393 ===================================================================
2394 --- linux-2.6.24.7.orig/Documentation/kernel-parameters.txt
2395 +++ linux-2.6.24.7/Documentation/kernel-parameters.txt
2396 @@ -1244,6 +1244,13 @@ and is between 256 and 4096 characters.
2398 nr_uarts= [SERIAL] maximum number of UARTs to be registered.
2400 + olpc_ec_timeout= [OLPC] ms delay when issuing EC commands
2401 + Rather than timing out after 20 ms if an EC
2402 + command is not properly ACKed, override the length
2403 + of the timeout. We have interrupts disabled while
2404 + waiting for the ACK, so if this is set too high
2405 + interrupts *may* be lost!
2410 Index: linux-2.6.24.7/drivers/base/dd.c
2411 ===================================================================
2412 --- linux-2.6.24.7.orig/drivers/base/dd.c
2413 +++ linux-2.6.24.7/drivers/base/dd.c
2414 @@ -293,7 +293,6 @@ static void __device_release_driver(stru
2416 driver_sysfs_remove(dev);
2417 sysfs_remove_link(&dev->kobj, "driver");
2418 - klist_remove(&dev->knode_driver);
2421 blocking_notifier_call_chain(&dev->bus->bus_notifier,
2422 @@ -306,6 +305,7 @@ static void __device_release_driver(stru
2424 devres_release_all(dev);
2426 + klist_remove(&dev->knode_driver);
2430 Index: linux-2.6.24.7/drivers/char/vt_ioctl.c
2431 ===================================================================
2432 --- linux-2.6.24.7.orig/drivers/char/vt_ioctl.c
2433 +++ linux-2.6.24.7/drivers/char/vt_ioctl.c
2435 char vt_dont_switch;
2436 extern struct tty_driver *console_driver;
2438 +/* Add a notifier chain to inform drivers of a VT_TEXT/VT_GRAPHICS switch */
2439 +RAW_NOTIFIER_HEAD(console_notifier_list);
2441 #define VT_IS_IN_USE(i) (console_driver->ttys[i] && console_driver->ttys[i]->count)
2442 #define VT_BUSY(i) (VT_IS_IN_USE(i) || i == fg_console || vc_cons[i].d == sel_cons)
2444 @@ -492,6 +495,14 @@ int vt_ioctl(struct tty_struct *tty, str
2445 vc->vc_mode = (unsigned char) arg;
2446 if (console != fg_console)
2449 + /* Notify listeners if the current fg_console has switched */
2451 + raw_notifier_call_chain(&console_notifier_list,
2452 + (arg == KD_TEXT) ?
2453 + CONSOLE_EVENT_SWITCH_TEXT :
2454 + CONSOLE_EVENT_SWITCH_GRAPHICS, 0);
2457 * explicitly blank/unblank the screen if switching modes
2459 Index: linux-2.6.24.7/drivers/i2c/busses/scx200_acb.c
2460 ===================================================================
2461 --- linux-2.6.24.7.orig/drivers/i2c/busses/scx200_acb.c
2462 +++ linux-2.6.24.7/drivers/i2c/busses/scx200_acb.c
2463 @@ -46,6 +46,10 @@ static int base[MAX_DEVICES] = { 0x820,
2464 module_param_array(base, int, NULL, 0);
2465 MODULE_PARM_DESC(base, "Base addresses for the ACCESS.bus controllers");
2467 +static unsigned int smbclk = 0x70;
2468 +module_param(smbclk, uint, 0);
2469 +MODULE_PARM_DESC(smbclk, "Specify the SMB_CLK value");
2471 #define POLL_TIMEOUT (HZ/5)
2473 enum scx200_acb_state {
2474 @@ -108,6 +112,7 @@ struct scx200_acb_iface {
2475 #define ACBADDR (iface->base + 4)
2476 #define ACBCTL2 (iface->base + 5)
2477 #define ACBCTL2_ENABLE 0x01
2478 +#define ACBCTL3 (iface->base + 6)
2480 /************************************************************************/
2482 @@ -392,11 +397,13 @@ static __init int scx200_acb_probe(struc
2486 - /* Disable the ACCESS.bus device and Configure the SCL
2487 - frequency: 16 clock cycles */
2488 - outb(0x70, ACBCTL2);
2489 + /* Disable the ACCESS.bus device and Configure the SCL */
2491 + outb((smbclk & 0x7F) << 1, ACBCTL2);
2493 + outb((smbclk >> 7) & 0xFF, ACBCTL3);
2495 - if (inb(ACBCTL2) != 0x70) {
2496 + if (inb(ACBCTL2) != ((smbclk & 0x7F) << 1)) {
2497 pr_debug(NAME ": ACBCTL2 readback failed\n");
2500 Index: linux-2.6.24.7/drivers/input/keyboard/atkbd.c
2501 ===================================================================
2502 --- linux-2.6.24.7.orig/drivers/input/keyboard/atkbd.c
2503 +++ linux-2.6.24.7/drivers/input/keyboard/atkbd.c
2504 @@ -63,12 +63,25 @@ static int atkbd_extra;
2505 module_param_named(extra, atkbd_extra, bool, 0);
2506 MODULE_PARM_DESC(extra, "Enable extra LEDs and keys on IBM RapidAcces, EzKey and similar keyboards");
2508 +#define ATKBD_KEY_UNKNOWN 0
2509 +#define ATKBD_KEY_NULL 0xFF0000FF
2511 +#define ATKBD_SCR_1 0xFF0000FE
2512 +#define ATKBD_SCR_2 0xFF0000FD
2513 +#define ATKBD_SCR_4 0xFF0000FC
2514 +#define ATKBD_SCR_8 0xFF0000FB
2515 +#define ATKBD_SCR_CLICK 0xFF0000FA
2516 +#define ATKBD_SCR_LEFT 0xFF0000F9
2517 +#define ATKBD_SCR_RIGHT 0xFF0000F8
2519 +#define ATKBD_SPECIAL 0xFF0000F8
2522 * Scancode to keycode tables. These are just the default setting, and
2523 * are loadable via an userland utility.
2526 -static unsigned char atkbd_set2_keycode[512] = {
2527 +static unsigned int atkbd_set2_keycode[512] = {
2529 #ifdef CONFIG_KEYBOARD_ATKBD_HP_KEYCODES
2531 @@ -87,11 +100,17 @@ static unsigned char atkbd_set2_keycode[
2532 82, 83, 80, 76, 77, 72, 1, 69, 87, 78, 81, 74, 55, 73, 70, 99,
2534 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2535 - 217,100,255, 0, 97,165, 0, 0,156, 0, 0, 0, 0, 0, 0,125,
2537 + 217,100,ATKBD_KEY_NULL, 0, 97,165, 0, 0,
2538 + 156, 0, 0, 0, 0, 0, 0,125,
2540 173,114, 0,113, 0, 0, 0,126,128, 0, 0,140, 0, 0, 0,127,
2541 159, 0,115, 0,164, 0, 0,116,158, 0,172,166, 0, 0, 0,142,
2542 157, 0, 0, 0, 0, 0, 0, 0,155, 0, 98, 0, 0,163, 0, 0,
2543 - 226, 0, 0, 0, 0, 0, 0, 0, 0,255, 96, 0, 0, 0,143, 0,
2545 + 226, 0, 0, 0, 0, 0, 0, 0,
2546 + 0,ATKBD_KEY_NULL, 96, 0, 0, 0,143, 0,
2548 0, 0, 0, 0, 0, 0, 0, 0, 0,107, 0,105,102, 0, 0,112,
2549 110,111,108,112,106,103, 0,119, 0,118,109, 0, 99,104,119, 0,
2551 @@ -150,19 +169,6 @@ static unsigned char atkbd_unxlate_table
2552 #define ATKBD_RET_HANGEUL 0xf2
2553 #define ATKBD_RET_ERR 0xff
2555 -#define ATKBD_KEY_UNKNOWN 0
2556 -#define ATKBD_KEY_NULL 255
2558 -#define ATKBD_SCR_1 254
2559 -#define ATKBD_SCR_2 253
2560 -#define ATKBD_SCR_4 252
2561 -#define ATKBD_SCR_8 251
2562 -#define ATKBD_SCR_CLICK 250
2563 -#define ATKBD_SCR_LEFT 249
2564 -#define ATKBD_SCR_RIGHT 248
2566 -#define ATKBD_SPECIAL 248
2568 #define ATKBD_LED_EVENT_BIT 0
2569 #define ATKBD_REP_EVENT_BIT 1
2571 @@ -174,7 +180,7 @@ static unsigned char atkbd_unxlate_table
2572 #define ATKBD_XL_HANJA 0x20
2575 - unsigned char keycode;
2576 + unsigned int keycode;
2578 } atkbd_scroll_keys[] = {
2579 { ATKBD_SCR_1, 0xc5 },
2580 @@ -200,7 +206,7 @@ struct atkbd {
2584 - unsigned char keycode[512];
2585 + unsigned int keycode[512];
2587 unsigned char translated;
2588 unsigned char extra;
2589 @@ -351,7 +357,7 @@ static irqreturn_t atkbd_interrupt(struc
2590 unsigned int code = data;
2591 int scroll = 0, hscroll = 0, click = -1, add_release_event = 0;
2593 - unsigned char keycode;
2594 + unsigned int keycode;
2597 printk(KERN_DEBUG "atkbd.c: Received %02x flags %02x\n", data, flags);
2598 @@ -856,9 +862,11 @@ static void atkbd_set_keycode_table(stru
2599 atkbd->keycode[i | 0x80] = atkbd_scroll_keys[j].keycode;
2601 } else if (atkbd->set == 3) {
2602 - memcpy(atkbd->keycode, atkbd_set3_keycode, sizeof(atkbd->keycode));
2603 + for (i = 0; i < ARRAY_SIZE(atkbd_set3_keycode); i++)
2604 + atkbd->keycode[i] = atkbd_set3_keycode[i];
2606 - memcpy(atkbd->keycode, atkbd_set2_keycode, sizeof(atkbd->keycode));
2607 + for (i = 0; i < ARRAY_SIZE(atkbd_set2_keycode); i++)
2608 + atkbd->keycode[i] = atkbd_set2_keycode[i];
2611 for (i = 0; i < ARRAY_SIZE(atkbd_scroll_keys); i++)
2612 @@ -930,8 +938,8 @@ static void atkbd_set_device_attrs(struc
2615 input_dev->keycode = atkbd->keycode;
2616 - input_dev->keycodesize = sizeof(unsigned char);
2617 - input_dev->keycodemax = ARRAY_SIZE(atkbd_set2_keycode);
2618 + input_dev->keycodesize = sizeof(unsigned int);
2619 + input_dev->keycodemax = ARRAY_SIZE(atkbd->keycode);
2621 for (i = 0; i < 512; i++)
2622 if (atkbd->keycode[i] && atkbd->keycode[i] < ATKBD_SPECIAL)
2623 @@ -1022,6 +1030,10 @@ static int atkbd_connect(struct serio *s
2628 +#include <asm/olpc.h>
2632 * atkbd_reconnect() tries to restore keyboard into a sane state and is
2633 * most likely called on resume.
2634 @@ -1032,6 +1044,12 @@ static int atkbd_reconnect(struct serio
2635 struct atkbd *atkbd = serio_get_drvdata(serio);
2636 struct serio_driver *drv = serio->drv;
2639 + if (olpc_board_at_least(olpc_board_pre(0xb3)))
2640 + if (serio->dev.power.power_state.event != PM_EVENT_ON)
2644 if (!atkbd || !drv) {
2645 printk(KERN_DEBUG "atkbd: reconnect request, but serio is disconnected, ignoring...\n");
2647 Index: linux-2.6.24.7/drivers/input/mouse/Kconfig
2648 ===================================================================
2649 --- linux-2.6.24.7.orig/drivers/input/mouse/Kconfig
2650 +++ linux-2.6.24.7/drivers/input/mouse/Kconfig
2651 @@ -96,6 +96,16 @@ config MOUSE_PS2_TOUCHKIT
2655 +config MOUSE_PS2_OLPC
2656 + bool "OLPC PS/2 mouse protocol extension" if EMBEDDED
2658 + depends on MOUSE_PS2 && OLPC
2660 + Say Y here if you have an OLPC PS/2 touchpad connected to
2666 tristate "Serial mouse"
2668 Index: linux-2.6.24.7/drivers/input/mouse/Makefile
2669 ===================================================================
2670 --- linux-2.6.24.7.orig/drivers/input/mouse/Makefile
2671 +++ linux-2.6.24.7/drivers/input/mouse/Makefile
2672 @@ -24,3 +24,4 @@ psmouse-$(CONFIG_MOUSE_PS2_LOGIPS2PP) +=
2673 psmouse-$(CONFIG_MOUSE_PS2_LIFEBOOK) += lifebook.o
2674 psmouse-$(CONFIG_MOUSE_PS2_TRACKPOINT) += trackpoint.o
2675 psmouse-$(CONFIG_MOUSE_PS2_TOUCHKIT) += touchkit_ps2.o
2676 +psmouse-$(CONFIG_MOUSE_PS2_OLPC) += olpc.o
2677 Index: linux-2.6.24.7/drivers/input/mouse/olpc.c
2678 ===================================================================
2680 +++ linux-2.6.24.7/drivers/input/mouse/olpc.c
2683 + * OLPC touchpad PS/2 mouse driver
2685 + * Copyright (c) 2006-2008 One Laptop Per Child
2687 + * Zephaniah E. Hull
2688 + * Andres Salomon <dilinger@laptop.org>
2690 + * This driver is partly based on the ALPS driver, which is:
2692 + * Copyright (c) 2003 Neil Brown <neilb@cse.unsw.edu.au>
2693 + * Copyright (c) 2003-2005 Peter Osterlund <petero2@telia.com>
2694 + * Copyright (c) 2004 Dmitry Torokhov <dtor@mail.ru>
2695 + * Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz>
2697 + * This program is free software; you can redistribute it and/or modify
2698 + * it under the terms of the GNU General Public License version 2 as
2699 + * published by the Free Software Foundation.
2703 + * The touchpad on the OLPC is fairly wide, with the entire area usable
2704 + * as a tablet (Pen Tablet/PT), and the center 1/3rd also usable as a
2705 + * touchpad (Glide Sensor/GS). The spec from ALPS is available from
2706 + * <http://wiki.laptop.org/go/Touch_Pad/Tablet>. It refers to this
2707 + * device as HGPK (Hybrid GS, PT, and Keymatrix).
2709 + * Earlier version of the device had simultaneous reporting; however, that
2710 + * was removed. Instead, the device now reports packets in one mode, and
2711 + * tells the driver when a mode switch needs to happen.
2715 +#include <linux/input.h>
2716 +#include <linux/serio.h>
2717 +#include <linux/libps2.h>
2718 +#include <linux/delay.h>
2719 +#include <asm/olpc.h>
2721 +#include "psmouse.h"
2724 +static int tpdebug;
2725 +module_param(tpdebug, int, 0644);
2727 +static int ignore_delta = 60;
2728 +module_param(ignore_delta, int, 0644);
2729 +MODULE_PARM_DESC(ignore_delta, "ignore packets that cause an X or Y delta larger than this value.");
2732 + * With older hardware, a finger-up event is sometimes not sent. If it's been
2733 + * more than 50mS since the last packet, we can safely assume that there was
2734 + * a finger-up event that we never received.
2736 +static void hgpk_fingerup_hack(struct psmouse *psmouse, struct hgpk_packet *p)
2738 + struct hgpk_data *priv = psmouse->private;
2739 + struct timeval now_tv;
2742 + if (psmouse->model >= HGPK_MODEL_C)
2745 + if (p->gs_down || p->pt_down) {
2746 + do_gettimeofday(&now_tv);
2747 + now_ns = timeval_to_ns(&now_tv);
2749 + if (priv->late && now_ns >= priv->late) {
2750 + struct input_dev *pt = psmouse->dev;
2751 + struct input_dev *gs = priv->gs;
2753 + input_report_key(pt, BTN_TOUCH, 0);
2754 + input_report_key(gs, BTN_TOUCH, 0);
2757 + hgpk_dbg(psmouse, "Missing finger-up packet detected, "
2758 + "working around buggy hardware.\n");
2760 + priv->late = now_ns + (50 * NSEC_PER_MSEC);
2766 + * C and D series touchpads send an extra finger-up packet to ensure we've
2767 + * seen it. That's all well and good, but for some uncomprehensible reason
2768 + * they sometimes also get stuck in a state where they also send an
2769 + * extra finger-down packet with coordinates of x=0, y=0. This royally
2770 + * screws relative positioning; end users see it as the touchpad jumping
2771 + * around when they first put their finger down. This works around that.
2775 +static void hgpk_fingerdown_hack(struct psmouse *psmouse, struct hgpk_packet *p)
2777 + if (psmouse->model < HGPK_MODEL_C)
2780 + /* we only care about x=0, y=0 packets */
2781 + if (p->x != 0 || p->y != 0)
2785 + * if we're a gs_down packet but we were not previously down,
2786 + * we're going to assume that this is one of those spurious packets
2787 + * that needs to be worked around.
2789 + if (p->gs_down && !test_bit(BTN_TOUCH, p->dev->key)) {
2790 + hgpk_dbg(psmouse, "spurious GS finger-down packet\n");
2792 + } else if (p->pt_down && !test_bit(BTN_TOUCH, p->dev->key)) {
2793 + hgpk_dbg(psmouse, "spurious PT finger-down packet\n");
2799 + * In general, we have lots of calibration problems that manifest
2800 + * themselves as jumpy mouse pointers. Miscalibration, capacitance issues
2801 + * with the hardware, etc; these make the touchpad detect errant packets
2802 + * at random places all over the place. Since we don't expect large deltas
2803 + * to ever actually be useful, we'll large axis changes that go over our
2806 +static void hgpk_big_delta_hack(struct psmouse *psmouse, struct hgpk_packet *p)
2808 + struct hgpk_data *priv = psmouse->private;
2809 + struct input_dev *dev = p->dev;
2811 + /* afaik, this happens on all hardware */
2813 + /* ignore finger-up packets */
2814 + if (!p->pt_down && !p->gs_down)
2817 + /* ensure that we're not a finger-down packet */
2818 + if ((p->pt_down && !test_bit(BTN_TOUCH, dev->key)) ||
2819 + (p->gs_down && !test_bit(BTN_TOUCH, dev->key)))
2822 + if (abs(dev->abs[ABS_X] - p->x) > ignore_delta ||
2823 + abs(dev->abs[ABS_Y] - p->y) > ignore_delta) {
2824 + hgpk_dbg(psmouse, "axis change (%d,%d) => (%d,%d) is over "
2825 + "delta threshold\n", dev->abs[ABS_X],
2826 + dev->abs[ABS_Y], p->x, p->y);
2827 + input_report_key(dev, BTN_TOUCH, 0);
2831 + /* two in a row is a pretty good indicator of miscalibration */
2832 + if (priv->axis_errors++) {
2833 + /* wait 2s for finger removal, and then recalibrate */
2834 + queue_delayed_work(kpsmoused_wq, &priv->recalib_wq,
2835 + msecs_to_jiffies(2000));
2836 + priv->axis_errors = 0;
2841 + priv->axis_errors = 0;
2845 + * This is my favorite touchpad hardware bug. I'm entirely not sure what
2846 + * triggers it (I've seen it triggered while the laptop was left on overnight,
2847 + * but my cat could have very well been using it/sleeping on it). However,
2848 + * the touchpad will randomly get stuck in a state where it constantly spews
2849 + * packets without a finger being on it. A recalibration will fix it, but
2850 + * without that it will go on for days (auto-recalibration doesn't catch it,
2851 + * either). The packets tend to either have the same coordinates, or be
2852 + * 1px away from each other; ie, (283,139,6) -> (284,139,5) -> (285,139,5) ->
2853 + * (286,139,6) -> (286,139,6) -> etc. We have a number of workarounds here..
2855 +static void hgpk_spewing_hack(struct psmouse *psmouse, struct hgpk_packet *p)
2857 + struct hgpk_data *priv = psmouse->private;
2858 + struct input_dev *dev = p->dev;
2861 + if (psmouse->model < HGPK_MODEL_C)
2864 + /* ignore 0, 0 packets */
2865 + if (p->x == 0 && p->y == 0)
2868 + /* PT packets don't count */
2870 + priv->repeat_pkts = 0;
2875 + * If we see 2s+ worth of packets that have at least 2 axis deltas of
2876 + * only 1px, that's a good indication that we're spewing packets.
2877 + * We're going to ignore z=15, though; that's pretty indicative of
2878 + * an actual finger on the touchpad just staying still.
2880 + if (p->z == 0 || p->z == 15)
2882 + repeat_axes = abs(p->x - dev->abs[ABS_X]) < 2 ? 1 : 0;
2883 + repeat_axes += abs(p->y - dev->abs[ABS_Y]) < 2 ? 1 : 0;
2884 + repeat_axes += abs(p->z - dev->abs[ABS_PRESSURE]) < 2 ? 1 : 0;
2885 + if (repeat_axes > 1) {
2886 + priv->repeat_pkts++;
2887 + /* we get 1 packet about every 24mS */
2888 + if (priv->repeat_pkts > 83) {
2889 + queue_delayed_work(kpsmoused_wq, &priv->recalib_wq, 0);
2890 + priv->repeat_pkts = 0;
2894 + priv->repeat_pkts = 0;
2899 + * 10s of y and z not changing is another kind of miscalibration.
2901 + repeat_axes = (p->y == dev->abs[ABS_Y]) ? 1 : 0;
2902 + repeat_axes += (p->z == dev->abs[ABS_PRESSURE]) ? 1 : 0;
2903 + if (repeat_axes > 1) {
2904 + priv->repeat_pkts++;
2905 + if (priv->repeat_pkts > 416) {
2906 + queue_delayed_work(kpsmoused_wq, &priv->recalib_wq, 0);
2907 + priv->repeat_pkts = 0;
2911 + priv->repeat_pkts = 0;
2915 + * HGPK Advanced Mode - single-mode format
2917 + * byte 0(PT): 1 1 0 0 1 1 1 1
2918 + * byte 0(GS): 1 1 1 1 1 1 1 1
2919 + * byte 1: 0 x6 x5 x4 x3 x2 x1 x0
2920 + * byte 2(PT): 0 0 x9 x8 x7 ? pt-dsw 0
2921 + * byte 2(GS): 0 x10 x9 x8 x7 ? gs-dsw pt-dsw
2922 + * byte 3: 0 y9 y8 y7 1 0 swr swl
2923 + * byte 4: 0 y6 y5 y4 y3 y2 y1 y0
2924 + * byte 5: 0 z6 z5 z4 z3 z2 z1 z0
2926 + * ?'s are not defined in the protocol spec, may vary between models.
2928 + * swr/swl are the left/right buttons.
2930 + * pt-dsw/gs-dsw indicate that the pt/gs sensor is detecting a
2934 +static int hgpk_validate_byte(unsigned char *packet, int pktcnt)
2936 + BUG_ON(pktcnt < 1);
2938 + if (packet[0] != HGPK_PT && packet[0] != HGPK_GS)
2941 + /* bytes 2 - 6 should have 0 in the highest bit */
2942 + if (pktcnt >= 2 && pktcnt <= 6 && (packet[pktcnt - 1] & 0x80))
2948 +static void hgpk_decode_packet(struct psmouse *psmouse, struct hgpk_packet *p)
2950 + unsigned char *packet = psmouse->packet;
2952 + BUG_ON(psmouse->pktcnt < 6);
2954 + p->left = packet[3] & 1;
2955 + p->right = !!(packet[3] & 2);
2956 + p->x = packet[1] | ((packet[2] & 0x78) << 4);
2957 + p->y = packet[4] | ((packet[3] & 0x70) << 3);
2960 + if (packet[0] == HGPK_GS) {
2961 + p->pt_down = !!(packet[2] & 1);
2962 + p->gs_down = !!(packet[2] & 2);
2963 + p->dev = ((struct hgpk_data *) psmouse->private)->gs;
2965 + /* we miss spurious PT finger-downs if pt_down is set */
2966 + p->mode_switch = HGPK_PT;
2969 + p->mode_switch = 0;
2971 + } else if (packet[0] == HGPK_PT) {
2972 + p->pt_down = !!(packet[2] & 2);
2974 + p->dev = psmouse->dev;
2975 + p->mode_switch = !p->pt_down ? HGPK_GS : 0;
2979 + hgpk_dbg(psmouse, "l=%d r=%d p=%d g=%d x=%d y=%d z=%d m=%x\n",
2980 + p->left, p->right, p->pt_down, p->gs_down,
2981 + p->x, p->y, p->z, p->mode_switch);
2985 +static void hgpk_process_packet_gspt(struct psmouse *psmouse)
2987 + struct hgpk_data *priv = psmouse->private;
2988 + struct input_dev *pt = psmouse->dev;
2989 + struct input_dev *gs = priv->gs;
2990 + struct hgpk_packet pkt;
2992 + hgpk_decode_packet(psmouse, &pkt);
2994 + hgpk_fingerup_hack(psmouse, &pkt);
2995 + hgpk_fingerdown_hack(psmouse, &pkt);
2996 + hgpk_big_delta_hack(psmouse, &pkt);
2997 + hgpk_spewing_hack(psmouse, &pkt);
2999 + input_report_key(pt, BTN_LEFT, pkt.left);
3000 + input_report_key(pt, BTN_RIGHT, pkt.right);
3001 + input_report_key(pt, BTN_TOUCH, pkt.pt_down);
3003 + input_report_key(gs, BTN_LEFT, pkt.left);
3004 + input_report_key(gs, BTN_RIGHT, pkt.right);
3005 + input_report_key(gs, BTN_TOUCH, pkt.gs_down);
3007 + input_report_abs(pkt.dev, ABS_X, pkt.x);
3008 + input_report_abs(pkt.dev, ABS_Y, pkt.y);
3009 + input_report_abs(pkt.dev, ABS_PRESSURE, pkt.z);
3014 + if (priv->recalib_window) {
3015 + if (time_before(jiffies, priv->recalib_window)) {
3017 + * ugh, got a packet inside our recalibration
3018 + * window, schedule another recalibration.
3020 + hgpk_dbg(psmouse, "packet inside calibration window, "
3021 + "queueing another recalibration\n");
3022 + queue_delayed_work(kpsmoused_wq, &priv->recalib_wq,
3023 + msecs_to_jiffies(1000));
3025 + priv->recalib_window = 0;
3028 + if (psmouse->model != HGPK_MODEL_A) {
3029 + if (priv->pending_mode && (!pkt.mode_switch ||
3030 + priv->current_mode == pkt.mode_switch)) {
3031 + priv->pending_mode = 0;
3032 + cancel_delayed_work(&priv->switch_wq);
3034 + else if (priv->pending_mode != pkt.mode_switch) {
3035 + priv->pending_mode = pkt.mode_switch;
3037 + /* allow for spurious mode_switch packets by delaying */
3038 + queue_delayed_work(kpsmoused_wq, &priv->switch_wq,
3039 + msecs_to_jiffies(50));
3044 +static psmouse_ret_t hgpk_process_byte(struct psmouse *psmouse)
3046 + if (hgpk_validate_byte(psmouse->packet, psmouse->pktcnt)) {
3047 + hgpk_dbg(psmouse, "%s: (%d) %02x %02x %02x %02x %02x %02x\n",
3048 + __func__, psmouse->pktcnt, psmouse->packet[0],
3049 + psmouse->packet[1], psmouse->packet[2],
3050 + psmouse->packet[3], psmouse->packet[4],
3051 + psmouse->packet[5]);
3052 + return PSMOUSE_BAD_DATA;
3055 + if (psmouse->pktcnt == 6) {
3056 + hgpk_process_packet_gspt(psmouse);
3057 + return PSMOUSE_FULL_PACKET;
3060 + return PSMOUSE_GOOD_DATA;
3063 +static int hgpk_force_recalibrate(struct psmouse *psmouse)
3065 + struct ps2dev *ps2dev = &psmouse->ps2dev;
3066 + struct hgpk_data *priv = psmouse->private;
3067 + struct input_dev *pt = psmouse->dev;
3068 + struct input_dev *gs = priv->gs;
3070 + /* C-series touchpads added the recalibrate command */
3071 + if (psmouse->model < HGPK_MODEL_C)
3074 + if (ps2_command(ps2dev, NULL, 0xf5) ||
3075 + ps2_command(ps2dev, NULL, 0xf5) ||
3076 + ps2_command(ps2dev, NULL, 0xe6) ||
3077 + ps2_command(ps2dev, NULL, 0xf5))
3080 + /* send a finger-up event so the cursor doesn't jump around */
3081 + input_report_key(pt, BTN_TOUCH, 0);
3082 + input_report_key(gs, BTN_TOUCH, 0);
3086 + /* according to ALPS, 150mS is required for recalibration */
3090 + * XXX: If a finger is down during this delay, recalibration will
3091 + * detect capacitance incorrectly. This is a hardware bug, and
3092 + * we may need to work around that here.
3095 + if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE))
3099 + * After we recalibrate, we shouldn't get any packets for 2s. If
3100 + * we do, it's likely that someone's finger was on the touchpad.
3101 + * If someone's finger *was* on the touchpad, it's probably
3102 + * miscalibrated. So, we should schedule another recalibration
3104 + priv->recalib_window = jiffies + msecs_to_jiffies(2000);
3109 +static enum hgpk_model_t hgpk_get_model(struct psmouse *psmouse)
3111 + struct ps2dev *ps2dev = &psmouse->ps2dev;
3112 + unsigned char param[3];
3114 + /* E7, E7, E7, E9 gets us a 3 byte identifier */
3115 + if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
3116 + ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
3117 + ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
3118 + ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
3121 + hgpk_dbg(psmouse, "ID: %02x %02x %02x", param[0], param[1], param[2]);
3123 + /* HGPK signature: 0x67, 0x00, 0x<model> */
3124 + if (param[0] != 0x67 || param[1] != 0x00)
3127 + hgpk_info(psmouse, "OLPC touchpad revision 0x%x\n", param[2]);
3132 + * Touchpad should be disabled before calling this!
3134 +static int hgpk_new_mode(struct psmouse *psmouse, int mode)
3136 + struct ps2dev *ps2dev = &psmouse->ps2dev;
3137 + struct hgpk_data *priv = psmouse->private;
3140 + * PT mode: F2, F2, F2, E7
3141 + * GS mode: F2, F2, F2, E6
3143 + if (ps2_command(ps2dev, NULL, 0xF2) ||
3144 + ps2_command(ps2dev, NULL, 0xF2) ||
3145 + ps2_command(ps2dev, NULL, 0xF2))
3148 + if (mode == HGPK_GS) {
3149 + if (ps2_command(ps2dev, NULL, 0xE6))
3152 + if (ps2_command(ps2dev, NULL, 0xE7))
3156 + if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE))
3159 + /* tell the irq handler to stop ignoring packets */
3160 + psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
3162 + priv->current_mode = mode;
3163 + priv->pending_mode = 0;
3165 + hgpk_warn(psmouse, "Switched to mode 0x%x successful.\n", mode);
3170 +static int hgpk_advanced_mode(struct psmouse *psmouse)
3172 + struct ps2dev *ps2dev = &psmouse->ps2dev;
3174 + /* Switch to 'Advanced mode.', four disables in a row. */
3175 + if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
3176 + ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
3177 + ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
3178 + ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE))
3181 + return hgpk_new_mode(psmouse, HGPK_GS);
3185 + * This kills power to the touchpad; according to ALPS, current consumption
3186 + * goes down to 50uA after running this. To turn power back on, we drive
3189 +static int hgpk_toggle_power(struct psmouse *psmouse, int enable)
3191 + struct ps2dev *ps2dev = &psmouse->ps2dev;
3194 + /* Added on D-series touchpads */
3195 + if (psmouse->model < HGPK_MODEL_D)
3199 + psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
3202 + * Sending a byte will drive MS-DAT low; this will wake up
3203 + * the controller. Once we get an ACK back from it, it
3204 + * means we can continue with the touchpad re-init. ALPS
3205 + * tells us that 1s should be long enough, so set that as
3206 + * the upper bound.
3208 + for (timeo = 20; timeo > 0; timeo--) {
3209 + if (!ps2_sendbyte(&psmouse->ps2dev,
3210 + PSMOUSE_CMD_DISABLE, 20))
3215 + psmouse_reset(psmouse);
3217 + if (hgpk_advanced_mode(psmouse)) {
3218 + hgpk_err(psmouse, "Failed to reinit touchpad!\n");
3222 + hgpk_dbg(psmouse, "Powering off touchpad.\n");
3223 + psmouse_set_state(psmouse, PSMOUSE_IGNORE);
3225 + if (ps2_command(ps2dev, NULL, 0xec) ||
3226 + ps2_command(ps2dev, NULL, 0xec) ||
3227 + ps2_command(ps2dev, NULL, 0xea))
3229 + /* probably won't see an ACK, the touchpad will be off */
3230 + ps2_sendbyte(&psmouse->ps2dev, 0xec, 20);
3237 + * poll the touchpad for current motion packet.
3239 + * Note: We can't poll, so always return failure.
3241 +static int hgpk_poll(struct psmouse *psmouse)
3246 +static int hgpk_reconnect(struct psmouse *psmouse)
3248 + if (olpc_board_at_least(olpc_board(0xb2)))
3249 + if (psmouse->ps2dev.serio->dev.power.power_state.event != PM_EVENT_ON)
3252 + psmouse_reset(psmouse);
3254 + if (hgpk_advanced_mode(psmouse)) {
3255 + hgpk_err(psmouse, "failed to reenable advanced mode.\n");
3262 +static ssize_t hgpk_show_powered(struct device *dev,
3263 + struct device_attribute *attr, char *buf)
3265 + struct serio *serio = to_serio_port(dev);
3266 + struct psmouse *psmouse;
3267 + struct hgpk_data *priv;
3270 + retval = serio_pin_driver(serio);
3274 + psmouse = serio_get_drvdata(serio);
3275 + priv = psmouse->private;
3277 + retval = sprintf(buf, "%d\n", priv->powered);
3278 + serio_unpin_driver(serio);
3282 +static ssize_t hgpk_set_powered(struct device *dev,
3283 + struct device_attribute *attr, const char *buf, size_t count)
3285 + struct serio *serio = to_serio_port(dev);
3286 + struct psmouse *psmouse;
3287 + struct hgpk_data *priv;
3288 + unsigned long val;
3293 + else if (*buf == '0')
3298 + retval = serio_pin_driver(serio);
3303 + * FUCK IT. I don't fucking care. locking in psmouse is fucking retarded!
3304 + retval = mutex_lock_interruptible(&psmouse_mutex);
3309 + psmouse = serio_get_drvdata(serio);
3310 + priv = psmouse->private;
3312 + if (val == priv->powered)
3315 + retval = hgpk_toggle_power(psmouse, val);
3317 + priv->powered = val;
3320 + serio_unpin_driver(serio);
3321 + return retval ? retval : count;
3324 +static DEVICE_ATTR(powered, S_IWUSR | S_IRUGO, hgpk_show_powered,
3325 + hgpk_set_powered);
3327 +static void hgpk_disconnect(struct psmouse *psmouse)
3329 + struct hgpk_data *priv = psmouse->private;
3331 + device_remove_file(&psmouse->ps2dev.serio->dev, &dev_attr_powered);
3332 + psmouse_reset(psmouse);
3333 + flush_scheduled_work();
3334 + input_unregister_device(priv->gs);
3338 +static void hgpk_mode_switch(struct work_struct *work)
3340 + struct delayed_work *w = container_of(work, struct delayed_work, work);
3341 + struct hgpk_data *priv = container_of(w, struct hgpk_data, switch_wq);
3342 + struct psmouse *psmouse = priv->psmouse;
3343 + struct ps2dev *ps2dev = &psmouse->ps2dev;
3347 + hgpk_dbg(psmouse, "Starting mode switch to 0x%x. [%lu]\n",
3348 + priv->pending_mode, jiffies);
3350 + if (priv->pending_mode == priv->current_mode) {
3351 + priv->pending_mode = 0;
3352 + hgpk_dbg(psmouse, "Already in target mode, no-op.\n");
3356 + /* tell the irq handler to ignore any further packets */
3357 + psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
3360 + if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE))
3364 + * ALPS tells us that it may take up to 20msec for the disable to
3365 + * take effect; however, ps2_command() will wait up to 200msec for
3366 + * the ACK to come back (and I'm assuming that by the time the
3367 + * hardware sends back its ACK, it has stopped sending bytes).
3369 + pending_mode = priv->pending_mode;
3371 + if (hgpk_new_mode(psmouse, priv->pending_mode))
3375 + * Deal with a potential race condition.
3377 + * If there is a brief tap of a stylus or a fingernail that
3378 + * triggers a mode switch to PT mode, and the stylus/fingernail is
3379 + * lifted after the DISABLE above, but before we reenable in the
3380 + * new mode then we can get stuck in PT mode.
3382 + if (pending_mode == HGPK_PT) {
3383 + priv->pending_mode = HGPK_GS;
3384 + queue_delayed_work(kpsmoused_wq, &priv->switch_wq,
3385 + msecs_to_jiffies(50));
3390 + hgpk_warn(psmouse, "Failure to switch modes, resetting device...\n");
3391 + hgpk_reconnect(psmouse);
3394 +static void hgpk_recalib_work(struct work_struct *work)
3396 + struct delayed_work *w = container_of(work, struct delayed_work, work);
3397 + struct hgpk_data *priv = container_of(w, struct hgpk_data, recalib_wq);
3398 + struct psmouse *psmouse = priv->psmouse;
3401 + hgpk_dbg(psmouse, "Recalibrating touchpad..\n");
3403 + if (hgpk_force_recalibrate(psmouse))
3404 + hgpk_err(psmouse, "Recalibration failed!\n");
3407 +int olpc_init(struct psmouse *psmouse)
3409 + struct hgpk_data *priv;
3410 + struct input_dev *pt = psmouse->dev;
3411 + struct input_dev *gs;
3413 + priv = kzalloc(sizeof(struct hgpk_data), GFP_KERNEL);
3414 + gs = input_allocate_device();
3418 + psmouse->private = priv;
3420 + priv->psmouse = psmouse;
3421 + priv->powered = 1;
3423 + psmouse_reset(psmouse);
3425 + if (hgpk_advanced_mode(psmouse)) {
3426 + hgpk_err(psmouse, "failed to enable advanced mode\n");
3430 + /* Unset things that psmouse-base sets that we don't have */
3431 + pt->evbit[0] &= ~BIT(EV_REL);
3432 + pt->keybit[LONG(BTN_MOUSE)] &= ~BIT(BTN_MIDDLE);
3433 + pt->relbit[0] &= ~(BIT(REL_X) | BIT(REL_Y));
3435 + /* Set all the things we *do* have */
3436 + set_bit(EV_KEY, pt->evbit);
3437 + set_bit(EV_ABS, pt->evbit);
3439 + set_bit(BTN_LEFT, pt->keybit);
3440 + set_bit(BTN_RIGHT, pt->keybit);
3441 + set_bit(BTN_TOUCH, pt->keybit);
3443 + input_set_abs_params(pt, ABS_X, 2, 1000, 0, 0);
3444 + input_set_abs_params(pt, ABS_Y, 0, 717, 0, 0);
3445 + input_set_abs_params(pt, ABS_PRESSURE, 0, 127, 0, 0);
3447 + snprintf(priv->phys, sizeof(priv->phys),
3448 + "%s/input1", psmouse->ps2dev.serio->phys);
3449 + gs->phys = priv->phys;
3450 + gs->name = "OLPC ALPS GlideSensor";
3451 + gs->id.bustype = BUS_I8042;
3452 + gs->id.vendor = 0x0002;
3453 + gs->id.product = PSMOUSE_OLPC;
3454 + gs->id.version = psmouse->model;
3456 + set_bit(EV_KEY, gs->evbit);
3457 + set_bit(EV_ABS, gs->evbit);
3459 + set_bit(BTN_LEFT, gs->keybit);
3460 + set_bit(BTN_RIGHT, gs->keybit);
3461 + set_bit(BTN_TOUCH, gs->keybit);
3463 + input_set_abs_params(gs, ABS_X, 350, 512, 0, 0);
3464 + input_set_abs_params(gs, ABS_Y, 70, 325, 0, 0);
3465 + input_set_abs_params(gs, ABS_PRESSURE, 0, 15, 0, 0);
3467 + if (input_register_device(gs)) {
3468 + hgpk_err(psmouse, "Failed to register GlideSensor\n");
3472 + psmouse->protocol_handler = hgpk_process_byte;
3473 + psmouse->poll = hgpk_poll;
3474 + psmouse->disconnect = hgpk_disconnect;
3475 + psmouse->reconnect = hgpk_reconnect;
3476 + psmouse->pktsize = 6;
3478 + /* Disable the idle resync. */
3479 + psmouse->resync_time = 0;
3480 + /* Reset after a lot of bad bytes. */
3481 + psmouse->resetafter = 1024;
3483 + INIT_DELAYED_WORK(&priv->switch_wq, hgpk_mode_switch);
3484 + INIT_DELAYED_WORK(&priv->recalib_wq, hgpk_recalib_work);
3486 + if (device_create_file(&psmouse->ps2dev.serio->dev,
3487 + &dev_attr_powered)) {
3488 + hgpk_err(psmouse, "Failed to create sysfs attribute\n");
3496 + input_unregister_device(gs);
3499 + input_free_device(gs);
3504 +int olpc_detect(struct psmouse *psmouse, int set_properties)
3508 + version = hgpk_get_model(psmouse);
3512 + if (set_properties) {
3513 + psmouse->vendor = "ALPS";
3514 + psmouse->name = "PenTablet";
3515 + psmouse->model = version;
3519 Index: linux-2.6.24.7/drivers/input/mouse/olpc.h
3520 ===================================================================
3522 +++ linux-2.6.24.7/drivers/input/mouse/olpc.h
3525 + * OLPC touchpad PS/2 mouse driver
3527 + * Copyright (c) 2006 One Laptop Per Child, inc.
3529 + * This driver is partly based on the ALPS driver.
3530 + * Copyright (c) 2003 Peter Osterlund <petero2@telia.com>
3531 + * Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz>
3533 + * This program is free software; you can redistribute it and/or modify it
3534 + * under the terms of the GNU General Public License version 2 as published by
3535 + * the Free Software Foundation.
3541 +enum hgpk_model_t {
3542 + HGPK_MODEL_PreA = 0x0a, /* pre-B1s */
3543 + HGPK_MODEL_A = 0x14, /* found on B1s, PT disabled in hardware */
3544 + HGPK_MODEL_B = 0x28, /* B2s, has capacitance issues */
3545 + HGPK_MODEL_C = 0x3c,
3546 + HGPK_MODEL_D = 0x50, /* C1, mass production */
3549 +#define HGPK_GS 0xff /* The GlideSensor */
3550 +#define HGPK_PT 0xcf /* The PenTablet */
3552 +struct hgpk_packet {
3553 + struct input_dev *dev;
3555 + unsigned char mode_switch;
3556 + unsigned int pt_down:1, gs_down:1;
3557 + unsigned int left:1, right:1;
3561 + struct input_dev *gs; /* GlideSensor */
3562 + struct psmouse *psmouse;
3563 + char name[32]; /* Name */
3564 + char phys[32]; /* Phys */
3571 + unsigned long recalib_window;
3572 + struct delayed_work switch_wq;
3573 + struct delayed_work recalib_wq;
3576 +#define hgpk_dbg(psmouse, format, arg...) \
3577 + dev_dbg(&(psmouse)->ps2dev.serio->dev, format, ## arg)
3578 +#define hgpk_err(psmouse, format, arg...) \
3579 + dev_err(&(psmouse)->ps2dev.serio->dev, format, ## arg)
3580 +#define hgpk_info(psmouse, format, arg...) \
3581 + dev_info(&(psmouse)->ps2dev.serio->dev, format, ## arg)
3582 +#define hgpk_warn(psmouse, format, arg...) \
3583 + dev_warn(&(psmouse)->ps2dev.serio->dev, format, ## arg)
3584 +#define hgpk_notice(psmouse, format, arg...) \
3585 + dev_notice(&(psmouse)->ps2dev.serio->dev, format, ## arg)
3587 +#ifdef CONFIG_MOUSE_PS2_OLPC
3588 +int olpc_detect(struct psmouse *psmouse, int set_properties);
3589 +int olpc_init(struct psmouse *psmouse);
3591 +inline int olpc_detect(struct psmouse *psmouse, int set_properties)
3595 +inline int olpc_init(struct psmouse *psmouse)
3602 Index: linux-2.6.24.7/drivers/input/mouse/psmouse-base.c
3603 ===================================================================
3604 --- linux-2.6.24.7.orig/drivers/input/mouse/psmouse-base.c
3605 +++ linux-2.6.24.7/drivers/input/mouse/psmouse-base.c
3607 #include "synaptics.h"
3608 #include "logips2pp.h"
3611 #include "lifebook.h"
3612 #include "trackpoint.h"
3613 #include "touchkit_ps2.h"
3614 @@ -103,7 +104,7 @@ static struct attribute_group psmouse_at
3616 static DEFINE_MUTEX(psmouse_mutex);
3618 -static struct workqueue_struct *kpsmoused_wq;
3619 +struct workqueue_struct *kpsmoused_wq;
3621 struct psmouse_protocol {
3622 enum psmouse_type type;
3623 @@ -221,7 +222,7 @@ static inline void __psmouse_set_state(s
3627 -static void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state)
3628 +void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state)
3630 serio_pause_rx(psmouse->ps2dev.serio);
3631 __psmouse_set_state(psmouse, new_state);
3632 @@ -320,7 +321,7 @@ static irqreturn_t psmouse_interrupt(str
3636 - if (psmouse->packet[1] == PSMOUSE_RET_ID) {
3637 + if (psmouse->packet[1] == PSMOUSE_RET_ID || psmouse->packet[1] == PSMOUSE_RET_BAT) {
3638 __psmouse_set_state(psmouse, PSMOUSE_IGNORE);
3639 serio_reconnect(serio);
3641 @@ -631,8 +632,21 @@ static int psmouse_extensions(struct psm
3646 + * Try OLPC touchpad.
3648 if (max_proto > PSMOUSE_IMEX) {
3649 + if (olpc_detect(psmouse, set_properties) == 0) {
3650 + if (!set_properties || olpc_init(psmouse) == 0)
3651 + return PSMOUSE_OLPC;
3653 + * Init failed, try basic relative protocols
3655 + max_proto = PSMOUSE_IMEX;
3659 + if (max_proto > PSMOUSE_IMEX) {
3660 if (genius_detect(psmouse, set_properties) == 0)
3661 return PSMOUSE_GENPS;
3663 @@ -763,6 +777,14 @@ static const struct psmouse_protocol psm
3664 .detect = touchkit_ps2_detect,
3667 +#ifdef CONFIG_MOUSE_PS2_OLPC
3669 + .type = PSMOUSE_OLPC,
3672 + .detect = olpc_detect,
3676 .type = PSMOUSE_CORTRON,
3677 .name = "CortronPS/2",
3678 Index: linux-2.6.24.7/drivers/input/mouse/psmouse.h
3679 ===================================================================
3680 --- linux-2.6.24.7.orig/drivers/input/mouse/psmouse.h
3681 +++ linux-2.6.24.7/drivers/input/mouse/psmouse.h
3682 @@ -88,6 +88,7 @@ enum psmouse_type {
3685 PSMOUSE_TOUCHKIT_PS2,
3688 PSMOUSE_AUTO /* This one should always be last */
3690 @@ -95,7 +96,9 @@ enum psmouse_type {
3691 int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command);
3692 int psmouse_reset(struct psmouse *psmouse);
3693 void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution);
3694 +void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state);
3696 +extern struct workqueue_struct *kpsmoused_wq;
3698 struct psmouse_attribute {
3699 struct device_attribute dattr;
3700 Index: linux-2.6.24.7/drivers/input/serio/i8042.c
3701 ===================================================================
3702 --- linux-2.6.24.7.orig/drivers/input/serio/i8042.c
3703 +++ linux-2.6.24.7/drivers/input/serio/i8042.c
3704 @@ -874,6 +874,11 @@ static long i8042_panic_blink(long count
3710 +#include <asm/olpc.h>
3714 * Here we try to restore the original BIOS settings. We only want to
3715 * do that once, when we really suspend, not when we taking memory
3716 @@ -884,8 +889,15 @@ static long i8042_panic_blink(long count
3717 static int i8042_suspend(struct platform_device *dev, pm_message_t state)
3719 if (dev->dev.power.power_state.event != state.event) {
3721 + /* Anything newer than B2 remains powered; no reset needed */
3722 + if (!olpc_board_at_least(olpc_board_pre(0xb3))) {
3724 if (state.event == PM_EVENT_SUSPEND)
3725 i8042_controller_reset();
3730 dev->dev.power.power_state = state;
3732 @@ -908,9 +920,15 @@ static int i8042_resume(struct platform_
3733 if (dev->dev.power.power_state.event == PM_EVENT_ON)
3737 + if (!olpc_board_at_least(olpc_board_pre(0xb3))) {
3739 error = i8042_controller_check();
3746 error = i8042_controller_selftest();
3748 Index: linux-2.6.24.7/drivers/input/serio/serio.c
3749 ===================================================================
3750 --- linux-2.6.24.7.orig/drivers/input/serio/serio.c
3751 +++ linux-2.6.24.7/drivers/input/serio/serio.c
3752 @@ -910,11 +910,22 @@ static int serio_uevent(struct device *d
3753 #endif /* CONFIG_HOTPLUG */
3758 +#include <asm/olpc.h>
3761 static int serio_suspend(struct device *dev, pm_message_t state)
3763 if (dev->power.power_state.event != state.event) {
3765 + if (!olpc_board_at_least(olpc_board_pre(0xb3))) {
3767 if (state.event == PM_EVENT_SUSPEND)
3768 serio_cleanup(to_serio_port(dev));
3773 dev->power.power_state = state;
3775 Index: linux-2.6.24.7/drivers/Kconfig
3776 ===================================================================
3777 --- linux-2.6.24.7.orig/drivers/Kconfig
3778 +++ linux-2.6.24.7/drivers/Kconfig
3779 @@ -94,6 +94,8 @@ source "drivers/auxdisplay/Kconfig"
3781 source "drivers/kvm/Kconfig"
3783 +source "drivers/sysprof/Kconfig"
3785 source "drivers/uio/Kconfig"
3787 source "drivers/virtio/Kconfig"
3788 Index: linux-2.6.24.7/drivers/Makefile
3789 ===================================================================
3790 --- linux-2.6.24.7.orig/drivers/Makefile
3791 +++ linux-2.6.24.7/drivers/Makefile
3792 @@ -23,6 +23,8 @@ obj-y += char/
3794 obj-$(CONFIG_CONNECTOR) += connector/
3796 +obj-$(CONFIG_SYSPROF) += sysprof/
3798 # i810fb and intelfb depend on char/agp/
3799 obj-$(CONFIG_FB_I810) += video/i810/
3800 obj-$(CONFIG_FB_INTEL) += video/intelfb/
3801 Index: linux-2.6.24.7/drivers/media/video/cafe_ccic.c
3802 ===================================================================
3803 --- linux-2.6.24.7.orig/drivers/media/video/cafe_ccic.c
3804 +++ linux-2.6.24.7/drivers/media/video/cafe_ccic.c
3805 @@ -372,6 +372,10 @@ static int cafe_smbus_write_data(struct
3806 rval = value | ((command << TWSIC1_ADDR_SHIFT) & TWSIC1_ADDR);
3807 cafe_reg_write(cam, REG_TWSIC1, rval);
3808 spin_unlock_irqrestore(&cam->dev_lock, flags);
3809 + mdelay(2); /* It'll probably take about 900µs anyway, and the
3810 + CAFÉ is apparently quite sensitive to being poked
3811 + at this point. If we can work out precisely what's
3812 + going on and reduce this delay, it would be nice. */
3815 * Time to wait for the write to complete. THIS IS A RACY
3816 @@ -907,8 +911,6 @@ static int cafe_cam_configure(struct caf
3817 struct v4l2_format fmt;
3820 - if (cam->state != S_IDLE)
3822 fmt.fmt.pix = cam->pix_format;
3823 ret = __cafe_cam_cmd(cam, VIDIOC_INT_INIT, &zero);
3825 @@ -2237,14 +2239,18 @@ static int cafe_pci_suspend(struct pci_d
3827 enum cafe_state cstate;
3829 + mutex_lock(&cam->s_mutex);
3830 ret = pci_save_state(pdev);
3833 + cam_warn(cam, "Unable to save PCI state\n");
3836 cstate = cam->state; /* HACK - stop_dma sets to idle */
3837 cafe_ctlr_stop_dma(cam);
3838 cafe_ctlr_power_down(cam);
3839 pci_disable_device(pdev);
3840 cam->state = cstate;
3841 + /* hold mutex until restore */
3845 @@ -2263,16 +2269,18 @@ static int cafe_pci_resume(struct pci_de
3846 cam_warn(cam, "Unable to re-enable device on resume!\n");
3849 + /* we're still holding mutex from suspend */
3850 cafe_ctlr_init(cam);
3851 cafe_ctlr_power_down(cam);
3853 - mutex_lock(&cam->s_mutex);
3854 - if (cam->users > 0) {
3855 - cafe_ctlr_power_up(cam);
3856 - __cafe_cam_reset(cam);
3858 - mutex_unlock(&cam->s_mutex);
3860 + if (cam->users > 0) {
3861 + cafe_ctlr_power_up(cam);
3862 + __cafe_cam_reset(cam);
3865 + cafe_ctlr_power_down(cam);
3866 + mutex_unlock(&cam->s_mutex);
3868 set_bit(CF_CONFIG_NEEDED, &cam->flags);
3869 if (cam->state == S_SPECREAD)
3870 cam->state = S_IDLE; /* Don't bother restarting */
3871 Index: linux-2.6.24.7/drivers/misc/Kconfig
3872 ===================================================================
3873 --- linux-2.6.24.7.orig/drivers/misc/Kconfig
3874 +++ linux-2.6.24.7/drivers/misc/Kconfig
3875 @@ -219,6 +219,11 @@ config THINKPAD_ACPI_BAY
3877 If you are not sure, say Y here.
3879 +config EEPROM_93CX6
3880 + tristate "EEPROM 93CX6 support"
3882 + This is a driver for the EEPROM chipsets 93c46 and 93c66.
3883 + The driver supports both read as well as write commands.
3886 tristate "Device driver for Atmel SSC peripheral"
3887 Index: linux-2.6.24.7/drivers/mmc/card/block.c
3888 ===================================================================
3889 --- linux-2.6.24.7.orig/drivers/mmc/card/block.c
3890 +++ linux-2.6.24.7/drivers/mmc/card/block.c
3891 @@ -237,6 +237,13 @@ static int mmc_blk_issue_rq(struct mmc_q
3892 if (brq.data.blocks > card->host->max_blk_count)
3893 brq.data.blocks = card->host->max_blk_count;
3895 + if (mmc_card_sd(card) && !card->host->ios.clock) {
3896 + printk(KERN_ERR "%s: I/O to stopped card\n",
3897 + req->rq_disk->disk_name);
3900 + mmc_set_data_timeout(&brq.data, card);
3903 * If the host doesn't support multiple block writes, force
3904 * block writes to single block. SD cards are excepted from
3905 Index: linux-2.6.24.7/drivers/mmc/host/sdhci.c
3906 ===================================================================
3907 --- linux-2.6.24.7.orig/drivers/mmc/host/sdhci.c
3908 +++ linux-2.6.24.7/drivers/mmc/host/sdhci.c
3909 @@ -441,6 +441,12 @@ static void sdhci_prepare_data(struct sd
3914 + * There's an off-by-one error in the hw that we need to
3920 printk(KERN_WARNING "%s: Too large timeout requested!\n",
3921 mmc_hostname(host->mmc));
3922 @@ -728,19 +734,17 @@ static void sdhci_set_power(struct sdhci
3923 if (!(host->chip->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE))
3924 writeb(0, host->ioaddr + SDHCI_POWER_CONTROL);
3926 - pwr = SDHCI_POWER_ON;
3928 switch (1 << power) {
3929 case MMC_VDD_165_195:
3930 - pwr |= SDHCI_POWER_180;
3931 + pwr = SDHCI_POWER_180;
3935 - pwr |= SDHCI_POWER_300;
3936 + pwr = SDHCI_POWER_300;
3940 - pwr |= SDHCI_POWER_330;
3941 + pwr = SDHCI_POWER_330;
3945 @@ -748,6 +752,10 @@ static void sdhci_set_power(struct sdhci
3947 writeb(pwr, host->ioaddr + SDHCI_POWER_CONTROL);
3949 + pwr |= SDHCI_POWER_ON;
3951 + writeb(pwr, host->ioaddr + SDHCI_POWER_CONTROL);
3954 host->power = power;
3956 Index: linux-2.6.24.7/drivers/mtd/nand/cafe_nand.c
3957 ===================================================================
3958 --- linux-2.6.24.7.orig/drivers/mtd/nand/cafe_nand.c
3959 +++ linux-2.6.24.7/drivers/mtd/nand/cafe_nand.c
3962 #include <linux/mtd/mtd.h>
3963 #include <linux/mtd/nand.h>
3964 +#include <linux/mtd/partitions.h>
3965 #include <linux/rslib.h>
3966 #include <linux/pci.h>
3967 #include <linux/delay.h>
3971 struct nand_chip nand;
3972 + struct mtd_partition *parts;
3973 struct pci_dev *pdev;
3975 struct rs_control *rs;
3976 @@ -84,6 +86,10 @@ static unsigned int numtimings;
3977 static int timing[3];
3978 module_param_array(timing, int, &numtimings, 0644);
3980 +#ifdef CONFIG_MTD_PARTITIONS
3981 +static const char *part_probes[] = { "RedBoot", NULL };
3984 /* Hrm. Why isn't this already conditional on something in the struct device? */
3985 #define cafe_dev_dbg(dev, args...) do { if (debug) dev_dbg(dev, ##args); } while(0)
3987 @@ -620,7 +626,9 @@ static int __devinit cafe_nand_probe(str
3989 struct mtd_info *mtd;
3990 struct cafe_priv *cafe;
3991 + struct mtd_partition *parts;
3996 /* Very old versions shared the same PCI ident for all three
3997 @@ -787,7 +795,18 @@ static int __devinit cafe_nand_probe(str
4000 pci_set_drvdata(pdev, mtd);
4002 + /* We register the whole device first, separate from the partitions */
4003 add_mtd_device(mtd);
4005 +#ifdef CONFIG_MTD_PARTITIONS
4006 + nr_parts = parse_mtd_partitions(mtd, part_probes, &parts, 0);
4007 + if (nr_parts > 0) {
4008 + cafe->parts = parts;
4009 + dev_info(&cafe->pdev->dev, "%d RedBoot partitions found\n", nr_parts);
4010 + add_mtd_partitions(mtd, parts, nr_parts);
4016 Index: linux-2.6.24.7/drivers/mtd/redboot.c
4017 ===================================================================
4018 --- linux-2.6.24.7.orig/drivers/mtd/redboot.c
4019 +++ linux-2.6.24.7/drivers/mtd/redboot.c
4020 @@ -59,16 +59,31 @@ static int parse_redboot_partitions(stru
4021 static char nullstring[] = "unallocated";
4024 + if ( directory < 0 ) {
4025 + offset = master->size + directory * master->erasesize;
4026 + while (master->block_isbad &&
4027 + master->block_isbad(master, offset)) {
4030 + printk(KERN_NOTICE "Failed to find a non-bad block to check for RedBoot partition table\n");
4033 + offset -= master->erasesize;
4036 + offset = directory * master->erasesize;
4037 + while (master->block_isbad &&
4038 + master->block_isbad(master, offset)) {
4039 + offset += master->erasesize;
4040 + if (offset == master->size)
4044 buf = vmalloc(master->erasesize);
4049 - if ( directory < 0 )
4050 - offset = master->size + directory*master->erasesize;
4052 - offset = directory*master->erasesize;
4054 printk(KERN_NOTICE "Searching for RedBoot partition table in %s at offset 0x%lx\n",
4055 master->name, offset);
4057 Index: linux-2.6.24.7/drivers/net/forcedeth.c
4058 ===================================================================
4059 --- linux-2.6.24.7.orig/drivers/net/forcedeth.c
4060 +++ linux-2.6.24.7/drivers/net/forcedeth.c
4061 @@ -3559,11 +3559,13 @@ static int nv_request_irq(struct net_dev
4063 if (ret != 0 && np->msi_flags & NV_MSI_CAPABLE) {
4064 if ((ret = pci_enable_msi(np->pci_dev)) == 0) {
4065 + pci_intx(np->pci_dev, 0);
4066 np->msi_flags |= NV_MSI_ENABLED;
4067 dev->irq = np->pci_dev->irq;
4068 if (request_irq(np->pci_dev->irq, handler, IRQF_SHARED, dev->name, dev) != 0) {
4069 printk(KERN_INFO "forcedeth: request_irq failed %d\n", ret);
4070 pci_disable_msi(np->pci_dev);
4071 + pci_intx(np->pci_dev, 1);
4072 np->msi_flags &= ~NV_MSI_ENABLED;
4073 dev->irq = np->pci_dev->irq;
4075 @@ -3606,6 +3608,7 @@ static void nv_free_irq(struct net_devic
4076 free_irq(np->pci_dev->irq, dev);
4077 if (np->msi_flags & NV_MSI_ENABLED) {
4078 pci_disable_msi(np->pci_dev);
4079 + pci_intx(np->pci_dev, 1);
4080 np->msi_flags &= ~NV_MSI_ENABLED;
4083 Index: linux-2.6.24.7/drivers/pci/quirks.c
4084 ===================================================================
4085 --- linux-2.6.24.7.orig/drivers/pci/quirks.c
4086 +++ linux-2.6.24.7/drivers/pci/quirks.c
4087 @@ -1360,6 +1360,17 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_IN
4088 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x260b, quirk_intel_pcie_pm);
4091 + * According to Tom Sylla, the Geode does not support PCI power management
4092 + * transition, so we shouldn't need the D3hot delay.
4094 +static void __init quirk_geode_pci_pm(struct pci_dev *dev)
4096 + pci_pm_d3_delay = 0;
4098 +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_LEGACY, quirk_geode_pci_pm);
4099 +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA, quirk_geode_pci_pm);
4102 * Toshiba TC86C001 IDE controller reports the standard 8-byte BAR0 size
4103 * but the PIO transfers won't work if BAR0 falls at the odd 8 bytes.
4104 * Re-allocate the region if needed...
4105 Index: linux-2.6.24.7/drivers/power/ds2760_battery.c
4106 ===================================================================
4107 --- linux-2.6.24.7.orig/drivers/power/ds2760_battery.c
4108 +++ linux-2.6.24.7/drivers/power/ds2760_battery.c
4109 @@ -409,6 +409,7 @@ static int ds2760_battery_suspend(struct
4110 struct ds2760_device_info *di = platform_get_drvdata(pdev);
4112 di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN;
4113 + power_supply_changed(&di->bat);
4117 Index: linux-2.6.24.7/drivers/power/olpc_battery.c
4118 ===================================================================
4119 --- linux-2.6.24.7.orig/drivers/power/olpc_battery.c
4120 +++ linux-2.6.24.7/drivers/power/olpc_battery.c
4122 #include <linux/power_supply.h>
4123 #include <linux/jiffies.h>
4124 #include <linux/sched.h>
4125 +#include <asm/io.h>
4126 #include <asm/olpc.h>
4129 #define EC_BAT_VOLTAGE 0x10 /* uint16_t, *9.76/32, mV */
4130 #define EC_BAT_CURRENT 0x11 /* int16_t, *15.625/120, mA */
4131 -#define EC_BAT_ACR 0x12
4132 +#define EC_BAT_ACR 0x12 /* int16_t *416.667 µAh */
4133 #define EC_BAT_TEMP 0x13 /* uint16_t, *100/256, °C */
4134 #define EC_AMB_TEMP 0x14 /* uint16_t, *100/256, °C */
4135 #define EC_BAT_STATUS 0x15 /* uint8_t, bitmask */
4136 @@ -84,6 +85,8 @@ static struct power_supply olpc_ac = {
4137 .get_property = olpc_ac_get_prop,
4140 +static char bat_serial[17]; /* Ick */
4142 /*********************************************************************
4143 * Battery properties
4144 *********************************************************************/
4145 @@ -94,6 +97,7 @@ static int olpc_bat_get_property(struct
4151 ret = olpc_ec_cmd(EC_BAT_STATUS, NULL, 0, &ec_byte, 1);
4153 @@ -127,8 +131,8 @@ static int olpc_bat_get_property(struct
4154 val->intval = POWER_SUPPLY_STATUS_FULL;
4155 else /* Not _necessarily_ true but EC doesn't tell all yet */
4156 val->intval = POWER_SUPPLY_STATUS_CHARGING;
4160 case POWER_SUPPLY_PROP_PRESENT:
4161 val->intval = !!(ec_byte & BAT_STAT_PRESENT);
4163 @@ -249,6 +253,22 @@ static int olpc_bat_get_property(struct
4164 ec_word = be16_to_cpu(ec_word);
4165 val->intval = ec_word * 100 / 256;
4167 + case POWER_SUPPLY_PROP_ACCUM_CURRENT:
4168 + ret = olpc_ec_cmd(EC_BAT_ACR, NULL, 0, (void *)&ec_word, 2);
4172 + ec_word = be16_to_cpu(ec_word);
4173 + val->intval = (uint16_t)ec_word;
4175 + case POWER_SUPPLY_PROP_SERIAL_NUMBER:
4176 + ret = olpc_ec_cmd(EC_BAT_SERIAL, NULL, 0, (void *)&ser_buf, 8);
4180 + sprintf(bat_serial, "%016llx", (long long)be64_to_cpu(ser_buf));
4181 + val->strval = bat_serial;
4186 @@ -268,7 +288,51 @@ static enum power_supply_property olpc_b
4187 POWER_SUPPLY_PROP_CAPACITY_LEVEL,
4188 POWER_SUPPLY_PROP_TEMP,
4189 POWER_SUPPLY_PROP_TEMP_AMBIENT,
4190 + POWER_SUPPLY_PROP_ACCUM_CURRENT,
4191 POWER_SUPPLY_PROP_MANUFACTURER,
4192 + POWER_SUPPLY_PROP_SERIAL_NUMBER,
4195 +/* EEPROM reading goes completely around the power_supply API, sadly */
4197 +#define EEPROM_START 0x20
4198 +#define EEPROM_END 0x80
4199 +#define EEPROM_SIZE (EEPROM_END - EEPROM_START)
4201 +static ssize_t olpc_bat_eeprom_read(struct kobject *kobj, char *buf, loff_t off,
4207 + if (off >= EEPROM_SIZE)
4209 + if (off + count > EEPROM_SIZE)
4210 + count = EEPROM_SIZE - off;
4212 + end = EEPROM_START + off + count;
4213 + for (ec_byte = EEPROM_START + off; ec_byte < end; ec_byte++) {
4214 + ret = olpc_ec_cmd(EC_BAT_EEPROM, &ec_byte, 1,
4215 + &buf[ec_byte - EEPROM_START], 1);
4217 + printk(KERN_ERR "olpc-battery: EC command "
4218 + "EC_BAT_EEPROM @ 0x%x failed -"
4219 + " %d!\n", ec_byte, ret);
4227 +static struct bin_attribute olpc_bat_eeprom = {
4231 + .owner = THIS_MODULE,
4234 + .read = olpc_bat_eeprom_read,
4237 /*********************************************************************
4238 @@ -299,7 +363,7 @@ static int __init olpc_bat_init(void)
4240 if (!olpc_platform_info.ecver)
4242 - if (olpc_platform_info.ecver < 0x43) {
4243 + if (olpc_platform_info.ecver < 0x44) {
4244 printk(KERN_NOTICE "OLPC EC version 0x%02x too old for battery driver.\n", olpc_platform_info.ecver);
4247 @@ -324,9 +388,15 @@ static int __init olpc_bat_init(void)
4249 goto battery_failed;
4251 + ret = device_create_bin_file(olpc_bat.dev, &olpc_bat_eeprom);
4253 + goto eeprom_failed;
4255 olpc_register_battery_callback(&olpc_battery_trigger_uevent);
4259 + power_supply_unregister(&olpc_bat);
4261 power_supply_unregister(&olpc_ac);
4263 @@ -338,6 +408,7 @@ success:
4264 static void __exit olpc_bat_exit(void)
4266 olpc_deregister_battery_callback();
4267 + device_remove_bin_file(olpc_bat.dev, &olpc_bat_eeprom);
4268 power_supply_unregister(&olpc_bat);
4269 power_supply_unregister(&olpc_ac);
4270 platform_device_unregister(bat_pdev);
4271 Index: linux-2.6.24.7/drivers/power/power_supply_sysfs.c
4272 ===================================================================
4273 --- linux-2.6.24.7.orig/drivers/power/power_supply_sysfs.c
4274 +++ linux-2.6.24.7/drivers/power/power_supply_sysfs.c
4275 @@ -114,9 +114,11 @@ static struct device_attribute power_sup
4276 POWER_SUPPLY_ATTR(time_to_empty_avg),
4277 POWER_SUPPLY_ATTR(time_to_full_now),
4278 POWER_SUPPLY_ATTR(time_to_full_avg),
4279 + POWER_SUPPLY_ATTR(accum_current),
4280 /* Properties of type `const char *' */
4281 POWER_SUPPLY_ATTR(model_name),
4282 POWER_SUPPLY_ATTR(manufacturer),
4283 + POWER_SUPPLY_ATTR(serial_number),
4286 static ssize_t power_supply_show_static_attrs(struct device *dev,
4287 Index: linux-2.6.24.7/drivers/serial/serial_core.c
4288 ===================================================================
4289 --- linux-2.6.24.7.orig/drivers/serial/serial_core.c
4290 +++ linux-2.6.24.7/drivers/serial/serial_core.c
4291 @@ -2013,6 +2013,7 @@ int uart_suspend_port(struct uart_driver
4292 int uart_resume_port(struct uart_driver *drv, struct uart_port *port)
4294 struct uart_state *state = drv->state + port->line;
4295 + struct ktermios termios;
4297 mutex_lock(&state->mutex);
4299 @@ -2035,20 +2036,6 @@ int uart_resume_port(struct uart_driver
4300 * Re-enable the console device after suspending.
4302 if (uart_console(port)) {
4303 - struct ktermios termios;
4306 - * First try to use the console cflag setting.
4308 - memset(&termios, 0, sizeof(struct ktermios));
4309 - termios.c_cflag = port->cons->cflag;
4312 - * If that's unset, use the tty termios setting.
4314 - if (state->info && state->info->tty && termios.c_cflag == 0)
4315 - termios = *state->info->tty->termios;
4317 port->ops->set_termios(port, &termios, NULL);
4318 console_start(port->cons);
4320 Index: linux-2.6.24.7/drivers/sysprof/config.h
4321 ===================================================================
4323 +++ linux-2.6.24.7/drivers/sysprof/config.h
4325 +/* config.h. Generated by configure. */
4326 +/* config.h.in. Generated from configure.ac by autoheader. */
4328 +/* Look for global separate debug info in this path */
4329 +#define DEBUGDIR "/usr/local/lib/debug"
4331 +/* Define to 1 if you have the `iberty' library (-liberty). */
4332 +/* #undef HAVE_LIBIBERTY */
4334 +/* Define to the address where bug reports for this package should be sent. */
4335 +#define PACKAGE_BUGREPORT ""
4337 +/* Define to the full name of this package. */
4338 +#define PACKAGE_NAME "sysprof"
4340 +/* Define to the full name and version of this package. */
4341 +#define PACKAGE_STRING "sysprof 1.0.8"
4343 +/* Define to the one symbol short name of this package. */
4344 +#define PACKAGE_TARNAME "sysprof"
4346 +/* Define to the version of this package. */
4347 +#define PACKAGE_VERSION "1.0.8"
4348 Index: linux-2.6.24.7/drivers/sysprof/Kconfig
4349 ===================================================================
4351 +++ linux-2.6.24.7/drivers/sysprof/Kconfig
4357 + tristate "Sysprof support"
4359 + Say M here to include the sysprof-module.
4361 + Sysprof is a sampling profiler that uses a kernel module,
4362 + sysprof-module, to generate stacktraces which are then interpreted by
4363 + the userspace program "sysprof".
4365 Index: linux-2.6.24.7/drivers/sysprof/Makefile
4366 ===================================================================
4368 +++ linux-2.6.24.7/drivers/sysprof/Makefile
4370 +obj-$(CONFIG_SYSPROF) += sysprof-module.o
4371 Index: linux-2.6.24.7/drivers/sysprof/sysprof-module.c
4372 ===================================================================
4374 +++ linux-2.6.24.7/drivers/sysprof/sysprof-module.c
4376 +/* -*- c-basic-offset: 8 -*- */
4378 +/* Sysprof -- Sampling, systemwide CPU profiler
4379 + * Copyright 2004, Red Hat, Inc.
4380 + * Copyright 2004, 2005, Soeren Sandmann
4382 + * This program is free software; you can redistribute it and/or modify
4383 + * it under the terms of the GNU General Public License as published by
4384 + * the Free Software Foundation; either version 2 of the License, or
4385 + * (at your option) any later version.
4387 + * This program is distributed in the hope that it will be useful,
4388 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
4389 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4390 + * GNU General Public License for more details.
4392 + * You should have received a copy of the GNU General Public License
4393 + * along with this program; if not, write to the Free Software
4394 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
4400 +#include <asm/atomic.h>
4401 +#include <linux/kernel.h> /* Needed for KERN_ALERT */
4402 +#include <linux/module.h> /* Needed by all modules */
4403 +#include <linux/sched.h>
4405 +#include <linux/proc_fs.h>
4406 +#include <asm/uaccess.h>
4407 +#include <linux/poll.h>
4408 +#include <linux/highmem.h>
4409 +#include <linux/pagemap.h>
4410 +#include <linux/profile.h>
4412 +#include "sysprof-module.h"
4414 +#include "config.h"
4416 +#include <linux/version.h>
4418 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
4419 +#include <linux/config.h>
4422 +#if !CONFIG_PROFILING
4423 +# error Sysprof needs a kernel with profiling support compiled in.
4426 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11)
4427 +# error Sysprof needs a Linux 2.6.11 kernel or later
4429 +#include <linux/kallsyms.h>
4431 +MODULE_LICENSE("GPL");
4432 +MODULE_AUTHOR("Soeren Sandmann (sandmann@daimi.au.dk)");
4434 +#define SAMPLES_PER_SECOND (200)
4435 +#define INTERVAL ((HZ <= SAMPLES_PER_SECOND)? 1 : (HZ / SAMPLES_PER_SECOND))
4436 +#define N_TRACES 256
4438 +static SysprofStackTrace stack_traces[N_TRACES];
4439 +static SysprofStackTrace * head = &stack_traces[0];
4440 +static SysprofStackTrace * tail = &stack_traces[0];
4441 +DECLARE_WAIT_QUEUE_HEAD (wait_for_trace);
4442 +DECLARE_WAIT_QUEUE_HEAD (wait_for_exit);
4444 +/* Macro the names of the registers that are used on each architecture */
4445 +#if defined(CONFIG_X86_64)
4446 +# define REG_FRAME_PTR rbp
4447 +# define REG_INS_PTR rip
4448 +# define REG_STACK_PTR rsp
4449 +#elif defined(CONFIG_X86)
4450 +# define REG_FRAME_PTR ebp
4451 +# define REG_INS_PTR eip
4452 +# define REG_STACK_PTR esp
4454 +# error Sysprof only supports the i386 and x86-64 architectures
4457 +typedef struct userspace_reader userspace_reader;
4458 +struct userspace_reader
4460 + struct task_struct *task;
4461 + unsigned long cache_address;
4462 + unsigned long *cache;
4465 +typedef struct StackFrame StackFrame;
4466 +struct StackFrame {
4467 + unsigned long next;
4468 + unsigned long return_address;
4471 +struct work_struct work;
4474 +read_frame (void *frame_pointer, StackFrame *frame)
4477 + /* This is commented out because we seem to be called with
4478 + * (current_thread_info()->addr_limit.seg)) == 0
4479 + * which means access_ok() _always_ fails.
4481 + * Not sure why (or if) this isn't the case for oprofile
4483 + if (!access_ok(VERIFY_READ, frame_pointer, sizeof(StackFrame)))
4487 + if (__copy_from_user_inatomic (
4488 + frame, frame_pointer, sizeof (StackFrame)))
4494 +DEFINE_PER_CPU(int, n_samples);
4497 +timer_notify (struct pt_regs *regs)
4499 + SysprofStackTrace *trace = head;
4502 + static atomic_t in_timer_notify = ATOMIC_INIT(1);
4505 + n = ++get_cpu_var(n_samples);
4506 + put_cpu_var(n_samples);
4508 + if (n % INTERVAL != 0)
4511 + /* 0: locked, 1: unlocked */
4513 + if (!atomic_dec_and_test(&in_timer_notify))
4516 + is_user = user_mode(regs);
4518 + if (!current || current->pid == 0)
4521 + if (is_user && current->state != TASK_RUNNING)
4528 + trace->pid = current->pid;
4529 + trace->truncated = 0;
4530 + trace->n_addresses = 1;
4532 + /* 0x1 is taken by sysprof to mean "in kernel" */
4533 + trace->addresses[0] = (void *)0x1;
4537 + StackFrame *frame_pointer;
4539 + memset(trace, 0, sizeof (SysprofStackTrace));
4541 + trace->pid = current->pid;
4542 + trace->truncated = 0;
4546 + trace->addresses[i++] = (void *)regs->REG_INS_PTR;
4548 + frame_pointer = (void *)regs->REG_FRAME_PTR;
4550 + while (read_frame (frame_pointer, &frame) == 0 &&
4551 + i < SYSPROF_MAX_ADDRESSES &&
4552 + (unsigned long)frame_pointer >= regs->REG_STACK_PTR)
4554 + trace->addresses[i++] = (void *)frame.return_address;
4555 + frame_pointer = (StackFrame *)frame.next;
4558 + trace->n_addresses = i;
4560 + if (i == SYSPROF_MAX_ADDRESSES)
4561 + trace->truncated = 1;
4563 + trace->truncated = 0;
4566 + if (head++ == &stack_traces[N_TRACES - 1])
4567 + head = &stack_traces[0];
4569 + wake_up (&wait_for_trace);
4572 + atomic_inc(&in_timer_notify);
4577 +procfile_read(char *buffer,
4578 + char **buffer_location,
4585 + return -EWOULDBLOCK;
4587 + *buffer_location = (char *)tail;
4589 + BUG_ON(tail->pid == 0);
4591 + if (tail++ == &stack_traces[N_TRACES - 1])
4592 + tail = &stack_traces[0];
4594 + return sizeof (SysprofStackTrace);
4597 +struct proc_dir_entry *trace_proc_file;
4598 +static unsigned int
4599 +procfile_poll(struct file *filp, poll_table *poll_table)
4602 + return POLLIN | POLLRDNORM;
4604 + poll_wait(filp, &wait_for_trace, poll_table);
4607 + return POLLIN | POLLRDNORM;
4615 + static struct file_operations fops;
4618 + create_proc_entry ("sysprof-trace", S_IFREG | S_IRUGO, &proc_root);
4620 + if (!trace_proc_file)
4623 + fops = *trace_proc_file->proc_fops;
4624 + fops.poll = procfile_poll;
4626 + trace_proc_file->read_proc = procfile_read;
4627 + trace_proc_file->proc_fops = &fops;
4628 + trace_proc_file->size = sizeof (SysprofStackTrace);
4630 + register_timer_hook (timer_notify);
4632 + printk(KERN_ALERT "sysprof: loaded (%s)\n", PACKAGE_VERSION);
4638 +cleanup_module(void)
4640 + unregister_timer_hook (timer_notify);
4642 + remove_proc_entry("sysprof-trace", &proc_root);
4644 + printk(KERN_ALERT "sysprof: unloaded\n");
4647 Index: linux-2.6.24.7/drivers/sysprof/sysprof-module.h
4648 ===================================================================
4650 +++ linux-2.6.24.7/drivers/sysprof/sysprof-module.h
4652 +/* Sysprof -- Sampling, systemwide CPU profiler
4653 + * Copyright 2004, Red Hat, Inc.
4654 + * Copyright 2004, 2005, Soeren Sandmann
4656 + * This program is free software; you can redistribute it and/or modify
4657 + * it under the terms of the GNU General Public License as published by
4658 + * the Free Software Foundation; either version 2 of the License, or
4659 + * (at your option) any later version.
4661 + * This program is distributed in the hope that it will be useful,
4662 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
4663 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4664 + * GNU General Public License for more details.
4666 + * You should have received a copy of the GNU General Public License
4667 + * along with this program; if not, write to the Free Software
4668 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
4671 +#ifndef SYSPROF_MODULE_H
4672 +#define SYSPROF_MODULE_H
4674 +typedef struct SysprofStackTrace SysprofStackTrace;
4676 +#define SYSPROF_MAX_ADDRESSES 512
4678 +struct SysprofStackTrace
4680 + int pid; /* -1 if in kernel */
4682 + int n_addresses; /* note: this can be 1 if the process was compiled
4683 + * with -fomit-frame-pointer or is otherwise weird
4685 + void *addresses[SYSPROF_MAX_ADDRESSES];
4689 Index: linux-2.6.24.7/drivers/usb/core/driver.c
4690 ===================================================================
4691 --- linux-2.6.24.7.orig/drivers/usb/core/driver.c
4692 +++ linux-2.6.24.7/drivers/usb/core/driver.c
4693 @@ -1062,8 +1062,15 @@ static int usb_suspend_both(struct usb_d
4698 + if (status == 0) {
4700 + /* Non-root devices don't need to do anything for FREEZE
4702 + if (udev->parent && (msg.event == PM_EVENT_FREEZE ||
4703 + msg.event == PM_EVENT_PRETHAW))
4705 status = usb_suspend_device(udev, msg);
4708 /* If the suspend failed, resume interfaces that did get suspended */
4710 Index: linux-2.6.24.7/drivers/usb/core/quirks.c
4711 ===================================================================
4712 --- linux-2.6.24.7.orig/drivers/usb/core/quirks.c
4713 +++ linux-2.6.24.7/drivers/usb/core/quirks.c
4714 @@ -48,6 +48,9 @@ static const struct usb_device_id usb_qu
4715 /* SKYMEDI USB_DRIVE */
4716 { USB_DEVICE(0x1516, 0x8628), .driver_info = USB_QUIRK_RESET_RESUME },
4718 + /* Philips PSC805 audio device */
4719 + { USB_DEVICE(0x0471, 0x0155), .driver_info = USB_QUIRK_RESET_RESUME },
4721 { } /* terminating entry must be last */
4724 Index: linux-2.6.24.7/drivers/usb/core/usb.h
4725 ===================================================================
4726 --- linux-2.6.24.7.orig/drivers/usb/core/usb.h
4727 +++ linux-2.6.24.7/drivers/usb/core/usb.h
4728 @@ -41,6 +41,7 @@ extern void usb_host_cleanup(void);
4729 extern void usb_autosuspend_work(struct work_struct *work);
4730 extern int usb_port_suspend(struct usb_device *dev);
4731 extern int usb_port_resume(struct usb_device *dev);
4732 +extern int usb_reset_suspended_device(struct usb_device *udev);
4733 extern int usb_external_suspend_device(struct usb_device *udev,
4735 extern int usb_external_resume_device(struct usb_device *udev);
4736 Index: linux-2.6.24.7/drivers/usb/host/ehci-hcd.c
4737 ===================================================================
4738 --- linux-2.6.24.7.orig/drivers/usb/host/ehci-hcd.c
4739 +++ linux-2.6.24.7/drivers/usb/host/ehci-hcd.c
4740 @@ -653,9 +653,16 @@ static irqreturn_t ehci_irq (struct usb_
4742 /* complete the unlinking of some qh [4.15.2.3] */
4743 if (status & STS_IAA) {
4744 - COUNT (ehci->stats.reclaim);
4745 - ehci->reclaim_ready = 1;
4747 + if (!ehci->reclaim) {
4748 + printk(KERN_WARNING "%s would set reclaim_ready with nothing to reclaim!\n", __func__);
4749 +printk(KERN_DEBUG "%s: USBCMD: 0x%x\n", __func__, ehci_readl(ehci, &ehci->regs->command));
4750 +printk(KERN_DEBUG "%s: USBSTS: 0x%x\n", __func__, ehci_readl(ehci, &ehci->regs->status));
4753 + COUNT (ehci->stats.reclaim);
4754 + ehci->reclaim_ready = 1;
4759 /* remote wakeup [4.3.1] */
4760 Index: linux-2.6.24.7/drivers/usb/host/ehci-hub.c
4761 ===================================================================
4762 --- linux-2.6.24.7.orig/drivers/usb/host/ehci-hub.c
4763 +++ linux-2.6.24.7/drivers/usb/host/ehci-hub.c
4764 @@ -132,10 +132,15 @@ static int ehci_bus_suspend (struct usb_
4765 ehci_quiesce (ehci);
4766 hcd->state = HC_STATE_QUIESCING;
4768 +printk(KERN_DEBUG "%s: USBCMD: 0x%x\n", __func__, ehci_readl(ehci, &ehci->regs->command));
4769 +printk(KERN_DEBUG "%s: USBSTS: 0x%x\n", __func__, ehci_readl(ehci, &ehci->regs->status));
4771 ehci->command = ehci_readl(ehci, &ehci->regs->command);
4773 ehci->reclaim_ready = 1;
4775 +printk(KERN_DEBUG "%s: USBCMD: 0x%x\n", __func__, ehci_readl(ehci, &ehci->regs->command));
4776 +printk(KERN_DEBUG "%s: USBSTS: 0x%x\n", __func__, ehci_readl(ehci, &ehci->regs->status));
4778 /* Unlike other USB host controller types, EHCI doesn't have
4779 * any notion of "global" or bus-wide suspend. The driver has
4780 @@ -175,6 +180,9 @@ static int ehci_bus_suspend (struct usb_
4782 hcd->state = HC_STATE_SUSPENDED;
4784 +printk(KERN_DEBUG "%s: USBCMD: 0x%x\n", __func__, ehci_readl(ehci, &ehci->regs->command));
4785 +printk(KERN_DEBUG "%s: USBSTS: 0x%x\n", __func__, ehci_readl(ehci, &ehci->regs->status));
4787 /* allow remote wakeup */
4789 if (!device_may_wakeup(&hcd->self.root_hub->dev))
4790 @@ -195,6 +203,18 @@ static int ehci_bus_resume (struct usb_h
4796 + static void __iomem *usb_ehc_addr;
4798 + rdmsrl(0x51200009, lo);
4799 + usb_ehc_addr = ioremap(lo, 256);
4800 + writel(readl(usb_ehc_addr+0x54) | 0x1000, usb_ehc_addr+0x54);
4801 + writel(readl(usb_ehc_addr+0x58) | 0x1000, usb_ehc_addr+0x58);
4802 + writel(readl(usb_ehc_addr+0x5C) | 0x1000, usb_ehc_addr+0x5C);
4803 + writel(readl(usb_ehc_addr+0x60) | 0x1000, usb_ehc_addr+0x60);
4804 + iounmap(usb_ehc_addr);
4807 if (time_before (jiffies, ehci->next_statechange))
4809 Index: linux-2.6.24.7/drivers/usb/host/ehci-pci.c
4810 ===================================================================
4811 --- linux-2.6.24.7.orig/drivers/usb/host/ehci-pci.c
4812 +++ linux-2.6.24.7/drivers/usb/host/ehci-pci.c
4813 @@ -247,6 +247,9 @@ static int ehci_pci_suspend(struct usb_h
4817 +printk(KERN_DEBUG "%s: USBCMD: 0x%x\n", __func__, ehci_readl(ehci, &ehci->regs->command));
4818 +printk(KERN_DEBUG "%s: USBSTS: 0x%x\n", __func__, ehci_readl(ehci, &ehci->regs->status));
4820 ehci_writel(ehci, 0, &ehci->regs->intr_enable);
4821 (void)ehci_readl(ehci, &ehci->regs->intr_enable);
4823 Index: linux-2.6.24.7/drivers/usb/host/ehci-q.c
4824 ===================================================================
4825 --- linux-2.6.24.7.orig/drivers/usb/host/ehci-q.c
4826 +++ linux-2.6.24.7/drivers/usb/host/ehci-q.c
4827 @@ -177,7 +177,7 @@ static int qtd_copy_status (
4828 if (QTD_CERR (token))
4831 - ehci_dbg (ehci, "devpath %s ep%d%s 3strikes\n",
4832 + printk(KERN_ERR "devpath %s ep%d%s 3strikes\n",
4834 usb_pipeendpoint (urb->pipe),
4835 usb_pipein (urb->pipe) ? "in" : "out");
4836 @@ -973,6 +973,11 @@ static void end_unlink_async (struct ehc
4837 struct ehci_qh *qh = ehci->reclaim;
4838 struct ehci_qh *next;
4841 + printk(KERN_CRIT "%s with ehci->reclaim == NULL!\n", __func__);
4845 timer_action_done (ehci, TIMER_IAA_WATCHDOG);
4847 // qh->hw_next = cpu_to_hc32(qh->qh_dma);
4848 Index: linux-2.6.24.7/drivers/usb/host/ohci-pci.c
4849 ===================================================================
4850 --- linux-2.6.24.7.orig/drivers/usb/host/ohci-pci.c
4851 +++ linux-2.6.24.7/drivers/usb/host/ohci-pci.c
4852 @@ -317,6 +317,8 @@ static int ohci_pci_resume (struct usb_h
4853 /* FIXME: we should try to detect loss of VBUS power here */
4854 prepare_for_handover(hcd);
4856 + /* Force the PM core to resume the root hub */
4857 + hcd_to_bus(hcd)->root_hub->dev.power.prev_state.event = PM_EVENT_ON;
4861 Index: linux-2.6.24.7/drivers/usb/storage/usb.c
4862 ===================================================================
4863 --- linux-2.6.24.7.orig/drivers/usb/storage/usb.c
4864 +++ linux-2.6.24.7/drivers/usb/storage/usb.c
4865 @@ -244,7 +244,7 @@ static int storage_pre_reset(struct usb_
4869 -static int storage_post_reset(struct usb_interface *iface)
4870 +static void storage_post_reset(struct usb_interface *iface, int reset_resume)
4872 struct us_data *us = usb_get_intfdata(iface);
4874 @@ -256,8 +256,10 @@ static int storage_post_reset(struct usb
4875 /* FIXME: Notify the subdrivers that they need to reinitialize
4878 - mutex_unlock(&us->dev_mutex);
4880 + /* If this is a reset-resume then the pre_reset routine wasn't
4881 + * called, so we don't need to unlock the mutex. */
4882 + if (!reset_resume)
4883 + mutex_unlock(&us->dev_mutex);
4887 Index: linux-2.6.24.7/drivers/video/fbmem.c
4888 ===================================================================
4889 --- linux-2.6.24.7.orig/drivers/video/fbmem.c
4890 +++ linux-2.6.24.7/drivers/video/fbmem.c
4891 @@ -820,6 +820,53 @@ static void try_to_load(int fb)
4892 #endif /* CONFIG_KMOD */
4895 +fb_powerup(struct fb_info *info)
4899 + if (!info || info->state == FBINFO_STATE_RUNNING)
4902 + if (info->fbops->fb_powerup)
4903 + ret = info->fbops->fb_powerup(info);
4906 + acquire_console_sem();
4907 + fb_set_suspend(info, 0);
4908 + release_console_sem();
4915 +fb_powerdown(struct fb_info *info)
4919 + if (!info || info->state == FBINFO_STATE_SUSPENDED)
4922 + /* Tell everybody that the fbdev is going down */
4923 + acquire_console_sem();
4924 + fb_set_suspend(info, 1);
4925 + release_console_sem();
4927 + if (info->fbops->fb_powerdown)
4928 + ret = info->fbops->fb_powerdown(info);
4930 + /* If the power down failed, then un-notify */
4933 + acquire_console_sem();
4934 + fb_set_suspend(info, 0);
4935 + release_console_sem();
4942 fb_pan_display(struct fb_info *info, struct fb_var_screeninfo *var)
4944 struct fb_fix_screeninfo *fix = &info->fix;
4945 Index: linux-2.6.24.7/drivers/video/geode/display_gx.c
4946 ===================================================================
4947 --- linux-2.6.24.7.orig/drivers/video/geode/display_gx.c
4948 +++ linux-2.6.24.7/drivers/video/geode/display_gx.c
4950 * Free Software Foundation; either version 2 of the License, or * (at your
4951 * option) any later version.
4954 +#include <linux/kernel.h>
4955 #include <linux/spinlock.h>
4956 #include <linux/fb.h>
4957 #include <linux/delay.h>
4959 #include <asm/div64.h>
4960 #include <asm/delay.h>
4961 +#include <asm/olpc.h>
4963 #include "geodefb.h"
4964 #include "display_gx.h"
4966 -#ifdef CONFIG_FB_GEODE_GX_SET_FBSIZE
4967 -unsigned int gx_frame_buffer_size(void)
4968 +static inline void rmwl(u32 val, u32 *reg)
4970 - return CONFIG_FB_GEODE_GX_FBSIZE;
4971 + u32 in = readl(reg);
4977 unsigned int gx_frame_buffer_size(void)
4982 + if (machine_is_olpc() && !olpc_has_vsa()) {
4984 + rdmsr(GLIU0_P2D_RO0, lo, hi);
4986 + /* Top page number */
4987 + val = ((hi & 0xff) << 12) | ((lo & 0xfff00000) >> 20);
4989 + val -= (lo & 0x000fffff); /* Subtract bottom page number */
4990 + val += 1; /* Adjust page count */
4991 + return (val << 12);
4995 /* FB size is reported by a virtual register */
4996 /* Virtual register class = 0x02 */
4997 /* VG_MEM_SIZE(512Kb units) = 0x00 */
4998 @@ -41,7 +59,6 @@ unsigned int gx_frame_buffer_size(void)
4999 val = (unsigned int)(inw(0xAC1E)) & 0xFFl;
5004 int gx_line_delta(int xres, int bpp)
5006 @@ -63,23 +80,23 @@ static void gx_set_mode(struct fb_info *
5007 gcfg = readl(par->dc_regs + DC_GENERAL_CFG);
5008 dcfg = readl(par->dc_regs + DC_DISPLAY_CFG);
5010 - /* Disable the timing generator. */
5011 - dcfg &= ~(DC_DCFG_TGEN);
5012 - writel(dcfg, par->dc_regs + DC_DISPLAY_CFG);
5014 - /* Wait for pending memory requests before disabling the FIFO load. */
5017 - /* Disable FIFO load and compression. */
5018 - gcfg &= ~(DC_GCFG_DFLE | DC_GCFG_CMPE | DC_GCFG_DECE);
5019 - writel(gcfg, par->dc_regs + DC_GENERAL_CFG);
5021 - /* Setup DCLK and its divisor. */
5022 - par->vid_ops->set_dclk(info);
5027 + /* Programming the clock is costly and ugly, so avoid if if we can */
5029 + if (par->curdclk != info->var.pixclock) {
5030 + /* Disable the timing generator. */
5031 + dcfg &= ~(DC_DCFG_TGEN);
5032 + writel(dcfg, par->dc_regs + DC_DISPLAY_CFG);
5034 + /* Wait for pending memory requests before disabling the FIFO load. */
5037 + /* Disable FIFO load and compression. */
5038 + gcfg &= ~(DC_GCFG_DFLE | DC_GCFG_CMPE | DC_GCFG_DECE);
5039 + writel(gcfg, par->dc_regs + DC_GENERAL_CFG);
5041 + /* Setup DCLK and its divisor. */
5042 + par->vid_ops->set_dclk(info);
5045 /* Clear all unused feature bits. */
5046 gcfg &= DC_GCFG_YUVM | DC_GCFG_VDSE;
5047 @@ -90,12 +107,13 @@ static void gx_set_mode(struct fb_info *
5048 gcfg |= (6 << DC_GCFG_DFHPEL_POS) | (5 << DC_GCFG_DFHPSL_POS) | DC_GCFG_DFLE;
5050 /* Framebuffer start offset. */
5051 - writel(0, par->dc_regs + DC_FB_ST_OFFSET);
5052 + rmwl(0, par->dc_regs + DC_FB_ST_OFFSET);
5054 /* Line delta and line buffer length. */
5055 - writel(info->fix.line_length >> 3, par->dc_regs + DC_GFX_PITCH);
5056 - writel(((info->var.xres * info->var.bits_per_pixel/8) >> 3) + 2,
5057 - par->dc_regs + DC_LINE_SIZE);
5058 + rmwl(info->fix.line_length >> 3, par->dc_regs + DC_GFX_PITCH);
5060 + rmwl(((info->var.xres * info->var.bits_per_pixel/8) >> 3) + 2,
5061 + par->dc_regs + DC_LINE_SIZE);
5064 /* Enable graphics and video data and unmask address lines. */
5065 @@ -134,17 +152,16 @@ static void gx_set_mode(struct fb_info *
5066 vblankend = vsyncend + info->var.upper_margin;
5069 - writel((hactive - 1) | ((htotal - 1) << 16), par->dc_regs + DC_H_ACTIVE_TIMING);
5070 - writel((hblankstart - 1) | ((hblankend - 1) << 16), par->dc_regs + DC_H_BLANK_TIMING);
5071 - writel((hsyncstart - 1) | ((hsyncend - 1) << 16), par->dc_regs + DC_H_SYNC_TIMING);
5073 - writel((vactive - 1) | ((vtotal - 1) << 16), par->dc_regs + DC_V_ACTIVE_TIMING);
5074 - writel((vblankstart - 1) | ((vblankend - 1) << 16), par->dc_regs + DC_V_BLANK_TIMING);
5075 - writel((vsyncstart - 1) | ((vsyncend - 1) << 16), par->dc_regs + DC_V_SYNC_TIMING);
5076 + rmwl((hactive - 1) | ((htotal - 1) << 16), par->dc_regs + DC_H_ACTIVE_TIMING);
5077 + rmwl((hblankstart - 1) | ((hblankend - 1) << 16), par->dc_regs + DC_H_BLANK_TIMING);
5078 + rmwl((hsyncstart - 1) | ((hsyncend - 1) << 16), par->dc_regs + DC_H_SYNC_TIMING);
5079 + rmwl((vactive - 1) | ((vtotal - 1) << 16), par->dc_regs + DC_V_ACTIVE_TIMING);
5080 + rmwl((vblankstart - 1) | ((vblankend - 1) << 16), par->dc_regs + DC_V_BLANK_TIMING);
5081 + rmwl((vsyncstart - 1) | ((vsyncend - 1) << 16), par->dc_regs + DC_V_SYNC_TIMING);
5083 /* Write final register values. */
5084 - writel(dcfg, par->dc_regs + DC_DISPLAY_CFG);
5085 - writel(gcfg, par->dc_regs + DC_GENERAL_CFG);
5086 + rmwl(dcfg, par->dc_regs + DC_DISPLAY_CFG);
5087 + rmwl(gcfg, par->dc_regs + DC_GENERAL_CFG);
5089 par->vid_ops->configure_display(info);
5091 Index: linux-2.6.24.7/drivers/video/geode/display_gx.h
5092 ===================================================================
5093 --- linux-2.6.24.7.orig/drivers/video/geode/display_gx.h
5094 +++ linux-2.6.24.7/drivers/video/geode/display_gx.h
5095 @@ -20,6 +20,9 @@ extern struct geode_dc_ops gx_dc_ops;
5096 #define GLD_MSR_CONFIG 0xC0002001
5097 #define GLD_MSR_CONFIG_DM_FP 0x40
5099 +/* Used for memory dection on the OLPC */
5100 +#define GLIU0_P2D_RO0 0x10000029
5102 /* Display controller registers */
5104 #define DC_UNLOCK 0x00
5105 Index: linux-2.6.24.7/drivers/video/geode/geodefb.h
5106 ===================================================================
5107 --- linux-2.6.24.7.orig/drivers/video/geode/geodefb.h
5108 +++ linux-2.6.24.7/drivers/video/geode/geodefb.h
5110 #ifndef __GEODEFB_H__
5111 #define __GEODEFB_H__
5113 +#define FB_POWER_STATE_OFF 0
5114 +#define FB_POWER_STATE_SUSPEND 1
5115 +#define FB_POWER_STATE_ON 2
5117 struct geodefb_info;
5119 struct geode_dc_ops {
5120 @@ -21,18 +25,24 @@ struct geode_dc_ops {
5122 struct geode_vid_ops {
5123 void (*set_dclk)(struct fb_info *);
5124 + unsigned int (*get_dclk)(struct fb_info *);
5125 void (*configure_display)(struct fb_info *);
5126 int (*blank_display)(struct fb_info *, int blank_mode);
5129 struct geodefb_par {
5131 + int fbactive; /* True if the current console is in KD_GRAPHICS mode */
5132 int panel_x; /* dimensions of an attached flat panel, non-zero => enable panel */
5134 + unsigned int curdclk; /* Used by GX to avoid unnessesary clock switching */
5135 void __iomem *dc_regs;
5136 void __iomem *vid_regs;
5137 + void __iomem *gp_regs;
5138 struct geode_dc_ops *dc_ops;
5139 struct geode_vid_ops *vid_ops;
5144 #endif /* !__GEODEFB_H__ */
5145 Index: linux-2.6.24.7/drivers/video/geode/geode_regs.h
5146 ===================================================================
5148 +++ linux-2.6.24.7/drivers/video/geode/geode_regs.h
5150 +/* This header file defines the registers and suspend/resume
5151 + structures for the Geode GX and LX. The lxfb driver defines
5152 + _GEODELX_ before including this file, which will unlock the
5153 + extra registers that are only valid for LX.
5156 +#ifndef _GEODE_REGS_H_
5157 +#define _GEODE_REGS_H_
5161 +#define GX_VP_MSR_PAD_SELECT 0xC0002011
5162 +#define LX_VP_MSR_PAD_SELECT 0x48000011
5164 +#define GEODE_MSR_GLCP_DOTPLL 0x4c000015
5166 +#define GLCP_DOTPLL_RESET (1 << 0)
5167 +#define GLCP_DOTPLL_BYPASS (1 << 15)
5168 +#define GLCP_DOTPLL_HALFPIX (1 << 24)
5169 +#define GLCP_DOTPLL_LOCK (1 << 25)
5172 +#define VP_FP_START 0x400
5177 +#define GP_REG_SIZE 0x7C
5178 +#define DC_REG_SIZE 0xF0
5179 +#define VP_REG_SIZE 0x158
5180 +#define FP_REG_SIZE 0x70
5184 +#define GP_REG_SIZE 0x50
5185 +#define DC_REG_SIZE 0x90
5186 +#define VP_REG_SIZE 0x138
5187 +#define FP_REG_SIZE 0x70
5191 +#define DC_PAL_SIZE 0x105
5192 +#define VP_COEFF_COUNT 512
5193 +#define DC_HFILT_SIZE 256
5194 +#define DC_VFILT_SIZE 256
5211 + unsigned char b[GP_REG_SIZE];
5213 + u32 dst_offset; /* 0x00 */
5214 + u32 src_offset; /* 0x04 */
5215 + u32 stride; /* 0x08 */
5216 + u32 wid_height; /* 0x0C */
5217 + u32 src_color_fg; /* 0x10 */
5218 + u32 src_color_bg; /* 0x14 */
5219 + u32 pat_color_0; /* 0x18 */
5220 + u32 pat_color_1; /* 0x1C */
5221 + u32 pat_color_2; /* 0x20 */
5222 + u32 pat_color_3; /* 0x24 */
5223 + u32 pat_color_4; /* 0x28 */
5224 + u32 pat_color_5; /* 0x2C */
5225 + u32 pat_data_0; /* 0x30 */
5226 + u32 pat_data_1; /* 0x34 */
5227 + u32 raster_mode; /* 0x38 */
5228 + u32 vector_mode; /* 0x3C */
5229 + u32 blt_mode; /* 0x40 */
5230 + u32 blit_status; /* 0x4C */
5231 + u32 hst_src; /* 0x48 */
5232 + u32 base_offset; /* 0x4C */
5235 + u32 cmd_top; /* 0x50 */
5236 + u32 cmd_bot; /* 0x54 */
5237 + u32 cmd_read; /* 0x58 */
5238 + u32 cmd_write; /* 0x5C */
5239 + u32 ch3_offset; /* 0x60 */
5240 + u32 ch3_mode_str; /* 0x64 */
5241 + u32 ch3_width; /* 0x68 */
5242 + u32 ch3_hsrc; /* 0x6C */
5243 + u32 lut_index; /* 0x70 */
5244 + u32 lut_data; /* 0x74 */
5245 + u32 int_cntrl; /* 0x78 */
5251 + unsigned char b[DC_REG_SIZE];
5254 + u32 unlock; /* 0x00 */
5255 + u32 gcfg; /* 0x04 */
5256 + u32 dcfg; /* 0x08 */
5257 + u32 arb; /* 0x0C */
5258 + u32 fb_st_offset; /* 0x10 */
5259 + u32 cb_st_offset; /* 0x14 */
5260 + u32 curs_st_offset; /* 0x18 */
5261 + u32 icon_st_offset; /* 0x1C */
5262 + u32 vid_y_st_offset; /* 0x20 */
5263 + u32 vid_u_st_offset; /* 0x24 */
5264 + u32 vid_v_st_offset; /* 0x28 */
5265 + u32 dctop; /* 0x2c */
5266 + u32 line_size; /* 0x30 */
5267 + u32 gfx_pitch; /* 0x34 */
5268 + u32 vid_yuv_pitch; /* 0x38 */
5269 + u32 rsvd2; /* 0x3C */
5270 + u32 h_active_timing; /* 0x40 */
5271 + u32 h_blank_timing; /* 0x44 */
5272 + u32 h_sync_timing; /* 0x48 */
5273 + u32 rsvd3; /* 0x4C */
5274 + u32 v_active_timing; /* 0x50 */
5275 + u32 v_blank_timing; /* 0x54 */
5276 + u32 v_sync_timing; /* 0x58 */
5277 + u32 fbactive; /* 0x5C */
5278 + u32 dc_cursor_x; /* 0x60 */
5279 + u32 dc_cursor_y; /* 0x64 */
5280 + u32 dc_icon_x; /* 0x68 */
5281 + u32 dc_line_cnt; /* 0x6C */
5282 + u32 rsvd5; /* 0x70 - palette address */
5283 + u32 rsvd6; /* 0x74 - palette data */
5284 + u32 dfifo_diag; /* 0x78 */
5285 + u32 cfifo_diag; /* 0x7C */
5286 + u32 dc_vid_ds_delta; /* 0x80 */
5287 + u32 gliu0_mem_offset; /* 0x84 */
5288 + u32 dv_ctl; /* 0x88 - added by LX */
5289 + u32 dv_acc; /* 0x8C */
5296 + u32 vbi_event_ctl;
5309 + u32 vid_even_y_st_offset; /* 0xD8 */
5310 + u32 vid_even_u_st_offset; /* 0xDC */
5311 + u32 vid_even_v_st_offset; /* 0xE0 */
5312 + u32 v_active_even_timing; /* 0xE4 */
5313 + u32 v_blank_even_timing; /* 0xE8 */
5314 + u32 v_sync_even_timing; /* 0xEC */
5320 + unsigned char b[VP_REG_SIZE];
5323 + u64 vcfg; /* 0x00 */
5324 + u64 dcfg; /* 0x08 */
5325 + u64 vx; /* 0x10 */
5326 + u64 vy; /* 0x18 */
5327 + u64 vs; /* 0x20 */
5328 + u64 vck; /* 0x28 */
5329 + u64 vcm; /* 0x30 */
5330 + u64 rsvd1; /* 0x38 - Gamma address*/
5331 + u64 rsvd2; /* 0x40 - Gamma data*/
5332 + u64 slr; /* 0x48 - LX only*/
5333 + u64 misc; /* 0x50 */
5334 + u64 ccs; /* 0x58 */
5335 + u64 vys; /* 0x60 */
5336 + u64 vxs; /* 0x68 */
5337 + u64 rsvd4; /* 0x70 */
5338 + u64 vdc; /* 0x78 */
5339 + u64 vco; /* 0x80 */
5340 + u64 crc; /* 0x88 */
5341 + u64 crc32; /* 0x90 */
5342 + u64 vde; /* 0x98 */
5343 + u64 cck; /* 0xA0 */
5344 + u64 ccm; /* 0xA8 */
5345 + u64 cc1; /* 0xB0 */
5346 + u64 cc2; /* 0xB8 */
5347 + u64 a1x; /* 0xC0 */
5348 + u64 a1y; /* 0xC8 */
5349 + u64 a1c; /* 0xD0 */
5350 + u64 a1t; /* 0xD8 */
5351 + u64 a2x; /* 0xE0 */
5352 + u64 a2y; /* 0xE8 */
5353 + u64 a2c; /* 0xF0 */
5354 + u64 a2t; /* 0xF8 */
5355 + u64 a3x; /* 0x100 */
5356 + u64 a3y; /* 0x108 */
5357 + u64 a3c; /* 0x110 */
5358 + u64 a3t; /* 0x118 */
5359 + u64 vrr; /* 0x120 */
5360 + u64 awt; /* 0x128 */
5361 + u64 vtm; /* 0x130 */
5363 + u64 vye; /* 0x138 */
5364 + u64 a1ye; /* 0x140 */
5365 + u32 a2ye; /* 0x148 */
5366 + u32 a3ye; /* 0x150 */
5372 + unsigned char b[FP_REG_SIZE];
5375 + u64 pt1; /* 0x400 */
5376 + u64 pt2; /* 0x408 */
5377 + u64 pm; /* 0x410 */
5378 + u64 dfc; /* 0x418 */
5379 + u64 blfsr; /* 0x420 */
5380 + u64 rlfsr; /* 0x428 */
5381 + u64 fmi; /* 0x430 */
5382 + u64 fmd; /* 0x438 */
5383 + u64 rsvd; /* 0x440 */
5384 + u64 dca; /* 0x448 */
5385 + u64 dmd; /* 0x450 */
5386 + u64 crc; /* 0x458 */
5387 + u64 fbb; /* 0x460 */
5388 + u64 crc32; /* 0x468 */
5392 + u32 pal[DC_PAL_SIZE];
5397 + u32 hcoeff[DC_HFILT_SIZE * 2];
5398 + u32 vcoeff[DC_VFILT_SIZE];
5400 + u32 vp_coeff[VP_COEFF_COUNT];
5405 Index: linux-2.6.24.7/drivers/video/geode/gxfb_core.c
5406 ===================================================================
5407 --- linux-2.6.24.7.orig/drivers/video/geode/gxfb_core.c
5408 +++ linux-2.6.24.7/drivers/video/geode/gxfb_core.c
5410 #include <linux/fb.h>
5411 #include <linux/init.h>
5412 #include <linux/pci.h>
5413 +#include <linux/notifier.h>
5414 +#include <linux/vt_kern.h>
5415 +#include <linux/console.h>
5416 +#include <asm/uaccess.h>
5417 +#include <asm/olpc.h>
5419 #include "geodefb.h"
5420 #include "display_gx.h"
5421 #include "video_gx.h"
5423 +#define FBIOSGAMMA _IOW('F', 0x20, void *)
5424 +#define FBIOGGAMMA _IOW('F', 0x21, void *)
5428 +#define FBIODUMPGP _IOW('F', 0x22, void *)
5429 +#define FBIODUMPDC _IOW('F', 0x23, void *)
5430 +#define FBIODUMPVP _IOW('F', 0x24, void *)
5431 +#define FBIODUMPFP _IOW('F', 0x25, void *)
5435 static char *mode_option;
5436 +static int noclear;
5437 +struct fb_info *gxfb_info;
5439 /* Modes relevant to the GX (taken from modedb.c) */
5440 static const struct fb_videomode gx_modedb[] __initdata = {
5441 @@ -103,8 +122,20 @@ static const struct fb_videomode gx_mode
5442 { NULL, 85, 1600, 1200, 4357, 304, 64, 46, 1, 192, 3,
5443 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
5444 FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
5445 + /* 1200x900-75 - CRT timings for the OLPC mode */
5446 + { NULL, 75, 1200, 900, 8049, 104, 240, 29, 54, 136, 3,
5447 + 0, FB_VMODE_NONINTERLACED, 0 }
5451 +static const struct fb_videomode gx_dcon_modedb[] __initdata = {
5452 + /* The only mode the DCON has is 1200x900 */
5453 + { NULL, 50, 1200, 900, 17460, 24, 8, 4, 5, 8, 3,
5454 + 0, FB_VMODE_NONINTERLACED, 0 }
5459 static int gxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
5461 if (var->xres > 1600 || var->yres > 1200)
5462 @@ -137,7 +168,7 @@ static int gxfb_check_var(struct fb_var_
5466 -static int gxfb_set_par(struct fb_info *info)
5467 +int gxfb_set_par(struct fb_info *info)
5469 struct geodefb_par *par = info->par;
5471 @@ -204,16 +235,26 @@ static int gxfb_blank(int blank_mode, st
5472 return par->vid_ops->blank_display(info, blank_mode);
5477 static int __init gxfb_map_video_memory(struct fb_info *info, struct pci_dev *dev)
5479 struct geodefb_par *par = info->par;
5483 ret = pci_enable_device(dev);
5487 + ret = pci_request_region(dev, 1, "gxfb (graphics processor)");
5491 + par->gp_regs = ioremap(pci_resource_start(dev, 1),
5492 + pci_resource_len(dev, 1));
5493 + if (!par->gp_regs)
5496 ret = pci_request_region(dev, 3, "gxfb (video processor)");
5499 @@ -232,36 +273,118 @@ static int __init gxfb_map_video_memory(
5500 ret = pci_request_region(dev, 0, "gxfb (framebuffer)");
5503 - if ((fb_len = gx_frame_buffer_size()) < 0)
5506 + /* If the fbsize wasn't specified then try to probe it */
5509 + fbsize = gx_frame_buffer_size();
5514 info->fix.smem_start = pci_resource_start(dev, 0);
5515 - info->fix.smem_len = fb_len;
5516 + info->fix.smem_len = fbsize;
5517 info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len);
5518 if (!info->screen_base)
5521 - /* Set the 16MB aligned base address of the graphics memory region
5522 + /* Set the 16MiB aligned base address of the graphics memory region
5523 * in the display controller */
5525 writel(info->fix.smem_start & 0xFF000000,
5526 par->dc_regs + DC_GLIU0_MEM_OFFSET);
5528 - dev_info(&dev->dev, "%d Kibyte of video memory at 0x%lx\n",
5529 + dev_info(&dev->dev, "%d KiB of video memory at 0x%lx\n",
5530 info->fix.smem_len / 1024, info->fix.smem_start);
5535 +static int gxfb_ioctl( struct fb_info *info, unsigned int cmd,
5536 + unsigned long arg)
5538 + unsigned int gamma[GXFB_GAMMA_DWORDS];
5539 + int ret = -EINVAL;
5540 + struct geodefb_par *par = info->par;
5545 + /* Read the gamma information from the user - 256 dwords */
5547 + if (copy_from_user(gamma, (void * __user) arg, GXFB_GAMMA_SIZE))
5550 + writel(0, par->vid_regs + GX_GAR);
5552 + /* Sequential writes to the data register will increment the
5553 + address automatically */
5555 + for(i = 0; i < GXFB_GAMMA_DWORDS; i++)
5556 + writel(gamma[i] & 0xFFFFFF, par->vid_regs + GX_GDR);
5558 + writel(readl(par->vid_regs + GX_MISC) & ~GX_MISC_GAM_EN,
5559 + par->vid_regs + GX_MISC);
5565 + if (readl(par->vid_regs + GX_MISC) & GX_MISC_GAM_EN)
5568 + memset(gamma, 0, GXFB_GAMMA_SIZE);
5569 + writel(0, par->vid_regs + GX_GAR);
5571 + for(i = 0; i < GXFB_GAMMA_DWORDS;i++)
5572 + gamma[i] = readl(par->vid_regs + GX_GDR);
5574 + if (copy_to_user((void * __user) arg, gamma, GXFB_GAMMA_SIZE))
5584 + dump_regs(info, 0);
5589 + dump_regs(info, 1);
5594 + dump_regs(info, 2);
5599 + dump_regs(info, 3);
5607 static struct fb_ops gxfb_ops = {
5608 .owner = THIS_MODULE,
5609 .fb_check_var = gxfb_check_var,
5610 .fb_set_par = gxfb_set_par,
5611 .fb_setcolreg = gxfb_setcolreg,
5612 .fb_blank = gxfb_blank,
5613 + .fb_ioctl = gxfb_ioctl,
5614 /* No HW acceleration for now. */
5615 .fb_fillrect = cfb_fillrect,
5616 .fb_copyarea = cfb_copyarea,
5617 .fb_imageblit = cfb_imageblit,
5618 + .fb_powerdown = gxfb_powerdown,
5619 + .fb_powerup = gxfb_powerup,
5622 static struct fb_info * __init gxfb_init_fbinfo(struct device *dev)
5623 @@ -303,23 +426,86 @@ static struct fb_info * __init gxfb_init
5627 -static int __init gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
5628 +static int gxfb_console_notify(struct notifier_block *self,
5629 + unsigned long action, void *data)
5631 + if (gxfb_info != NULL) {
5632 + struct geodefb_par *par = gxfb_info->par;
5633 + par->fbactive = (action == CONSOLE_EVENT_SWITCH_TEXT) ? 0 : 1;
5639 +static struct notifier_block gxfb_console_notifier = {
5640 + .notifier_call = gxfb_console_notify
5645 +static int gxfb_suspend(struct pci_dev *pdev, pm_message_t state)
5647 + struct fb_info *info = pci_get_drvdata(pdev);
5648 + struct geodefb_par *par = info->par;
5650 + if (pdev->dev.power.power_state.event == state.event)
5653 + if (state.event == PM_EVENT_SUSPEND) {
5655 + acquire_console_sem();
5656 + gxfb_powerdown(info);
5658 + par->state = FB_POWER_STATE_OFF;
5659 + fb_set_suspend(info, 1);
5661 + release_console_sem();
5664 + pdev->dev.power.power_state = state;
5668 +static int gxfb_resume(struct pci_dev *pdev)
5670 + struct fb_info *info = pci_get_drvdata(pdev);
5672 + acquire_console_sem();
5674 + /* Turn the engine completely on */
5676 + if (gxfb_powerup(info))
5677 + printk(KERN_ERR "gxfb: Powerup failed\n");
5679 + fb_set_suspend(info, 0);
5680 + release_console_sem();
5682 + pdev->dev.power.power_state = PMSG_ON;
5687 +static int __init gxfb_probe(struct pci_dev *pdev,
5688 + const struct pci_device_id *id)
5690 struct geodefb_par *par;
5691 - struct fb_info *info;
5695 - info = gxfb_init_fbinfo(&pdev->dev);
5697 + struct fb_videomode *modedb_ptr;
5700 + gxfb_info = gxfb_init_fbinfo(&pdev->dev);
5701 + if (gxfb_info == NULL)
5705 + par = gxfb_info->par;
5707 /* GX display controller and GX video device. */
5708 par->dc_ops = &gx_dc_ops;
5709 par->vid_ops = &gx_vid_ops;
5711 - if ((ret = gxfb_map_video_memory(info, pdev)) < 0) {
5712 + if ((ret = gxfb_map_video_memory(gxfb_info, pdev)) < 0) {
5713 dev_err(&pdev->dev, "failed to map frame buffer or controller registers\n");
5716 @@ -333,32 +519,60 @@ static int __init gxfb_probe(struct pci_
5718 par->enable_crt = 1;
5720 - ret = fb_find_mode(&info->var, info, mode_option,
5721 - gx_modedb, ARRAY_SIZE(gx_modedb), NULL, 16);
5722 + /* Get the current dotclock */
5724 + par->curdclk = (par->vid_ops->get_dclk) ? par->vid_ops->get_dclk(gxfb_info) : 0;
5726 + /* We need to determine a display mode right now, so we will
5727 + * check to see if the DCON was previously detected by the BIOS
5728 + * and use that to make our mode database decision.
5731 + modedb_ptr = (struct fb_videomode *) gx_modedb;
5732 + modedb_size = ARRAY_SIZE(gx_modedb);
5735 + if (olpc_has_dcon()) {
5736 + modedb_ptr = (struct fb_videomode *) gx_dcon_modedb;
5737 + modedb_size = ARRAY_SIZE(gx_dcon_modedb);
5741 + ret = fb_find_mode(&gxfb_info->var, gxfb_info, mode_option,
5742 + modedb_ptr, modedb_size, NULL, 16);
5744 if (ret == 0 || ret == 4) {
5745 dev_err(&pdev->dev, "could not find valid video mode\n");
5750 + /* Clear the screen of garbage, unless noclear was specified,
5751 + * in which case we assume the user knows what he is doing */
5754 + memset_io(gxfb_info->screen_base, 0, gxfb_info->fix.smem_len);
5756 + gxfb_check_var(&gxfb_info->var, gxfb_info);
5757 + gxfb_set_par(gxfb_info);
5759 + /* We are powered up */
5760 + par->state = FB_POWER_STATE_ON;
5762 - /* Clear the frame buffer of garbage. */
5763 - memset_io(info->screen_base, 0, info->fix.smem_len);
5765 - gxfb_check_var(&info->var, info);
5766 - gxfb_set_par(info);
5767 + console_event_register(&gxfb_console_notifier);
5769 - if (register_framebuffer(info) < 0) {
5770 + if (register_framebuffer(gxfb_info) < 0) {
5774 - pci_set_drvdata(pdev, info);
5775 - printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, info->fix.id);
5776 + pci_set_drvdata(pdev, gxfb_info);
5777 + printk(KERN_INFO "fb%d: %s frame buffer device\n", gxfb_info->node, gxfb_info->fix.id);
5781 - if (info->screen_base) {
5782 - iounmap(info->screen_base);
5783 + if (gxfb_info->screen_base) {
5784 + iounmap(gxfb_info->screen_base);
5785 pci_release_region(pdev, 0);
5787 if (par->vid_regs) {
5788 @@ -370,8 +584,9 @@ static int __init gxfb_probe(struct pci_
5789 pci_release_region(pdev, 2);
5793 - framebuffer_release(info);
5795 + framebuffer_release(gxfb_info);
5800 @@ -397,9 +612,7 @@ static void gxfb_remove(struct pci_dev *
5803 static struct pci_device_id gxfb_id_table[] = {
5804 - { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_GX_VIDEO,
5805 - PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
5807 + { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_GX_VIDEO) },
5811 @@ -410,22 +623,30 @@ static struct pci_driver gxfb_driver = {
5812 .id_table = gxfb_id_table,
5813 .probe = gxfb_probe,
5814 .remove = gxfb_remove,
5816 + .suspend = gxfb_suspend,
5817 + .resume = gxfb_resume
5822 -static int __init gxfb_setup(char *options)
5824 +static int __init gxfb_setup(char *options) {
5828 if (!options || !*options)
5831 - while ((opt = strsep(&options, ",")) != NULL) {
5832 + while((opt = strsep(&options, ",")) != NULL) {
5836 - mode_option = opt;
5837 + if (!strncmp(opt, "fbsize:", 7))
5838 + fbsize = simple_strtoul(opt+7, NULL, 0);
5839 + else if (!strcmp(opt, "noclear"))
5842 + mode_option = opt;
5846 @@ -444,7 +665,6 @@ static int __init gxfb_init(void)
5848 return pci_register_driver(&gxfb_driver);
5851 static void __exit gxfb_cleanup(void)
5853 pci_unregister_driver(&gxfb_driver);
5854 @@ -456,5 +676,8 @@ module_exit(gxfb_cleanup);
5855 module_param(mode_option, charp, 0);
5856 MODULE_PARM_DESC(mode_option, "video mode (<x>x<y>[-<bpp>][@<refr>])");
5858 +module_param(fbsize, int, 0);
5859 +MODULE_PARM_DESC(fbsize, "video memory size");
5861 MODULE_DESCRIPTION("Framebuffer driver for the AMD Geode GX");
5862 MODULE_LICENSE("GPL");
5863 Index: linux-2.6.24.7/drivers/video/geode/Kconfig
5864 ===================================================================
5865 --- linux-2.6.24.7.orig/drivers/video/geode/Kconfig
5866 +++ linux-2.6.24.7/drivers/video/geode/Kconfig
5867 @@ -38,26 +38,6 @@ config FB_GEODE_GX
5871 -config FB_GEODE_GX_SET_FBSIZE
5872 - bool "Manually specify the Geode GX framebuffer size"
5873 - depends on FB_GEODE_GX
5876 - If you want to manually specify the size of your GX framebuffer,
5877 - say Y here, otherwise say N to dynamically probe it.
5879 - Say N unless you know what you are doing.
5881 -config FB_GEODE_GX_FBSIZE
5882 - hex "Size of the GX framebuffer, in bytes"
5883 - depends on FB_GEODE_GX_SET_FBSIZE
5884 - default "0x1600000"
5886 - Specify the size of the GX framebuffer. Normally, you will
5887 - want this to be MB aligned. Common values are 0x80000 (8MB)
5888 - and 0x1600000 (16MB). Don't change this unless you know what
5892 tristate "AMD Geode GX1 framebuffer support (EXPERIMENTAL)"
5893 depends on FB && FB_GEODE && EXPERIMENTAL
5894 Index: linux-2.6.24.7/drivers/video/geode/lxfb_core.c
5895 ===================================================================
5896 --- linux-2.6.24.7.orig/drivers/video/geode/lxfb_core.c
5897 +++ linux-2.6.24.7/drivers/video/geode/lxfb_core.c
5899 #include <linux/fb.h>
5900 #include <linux/init.h>
5901 #include <linux/pci.h>
5902 -#include <linux/uaccess.h>
5903 +#include <asm/uaccess.h>
5904 +#include <asm/olpc.h>
5908 @@ -35,186 +36,84 @@ static int fbsize;
5911 const struct fb_videomode geode_modedb[] __initdata = {
5913 - { NULL, 60, 640, 480, 39682, 48, 8, 25, 2, 88, 2,
5914 + /* 640x480-60 VESA */
5915 + { NULL, 60, 640, 480, 39682, 48, 16, 33, 10, 96, 2,
5916 + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
5917 + /* 640x480-75 VESA */
5918 + { NULL, 75, 640, 480, 31746, 120, 16, 16, 01, 64, 3,
5919 + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
5920 + /* 640x480-85 VESA */
5921 + { NULL, 85, 640, 480, 27777, 80, 56, 25, 01, 56, 3,
5922 + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
5923 + /* 800x600-60 VESA */
5924 + { NULL, 60, 800, 600, 25000, 88, 40, 23, 01, 128, 4,
5925 + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
5926 + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
5927 + /* 800x600-75 VESA */
5928 + { NULL, 75, 800, 600, 20202, 160, 16, 21, 01, 80, 3,
5929 + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
5930 + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
5931 + /* 800x600-85 VESA */
5932 + { NULL, 85, 800, 600, 17761, 152, 32, 27, 01, 64, 3,
5933 + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
5934 + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
5935 + /* 1024x768-60 VESA */
5936 + { NULL, 60, 1024, 768, 15384, 160, 24, 29, 3, 136, 6,
5937 + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
5938 + /* 1024x768-75 VESA */
5939 + { NULL, 75, 1024, 768, 12690, 176, 16, 28, 1, 96, 3,
5940 + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
5941 + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
5942 + /* 1024x768-85 VESA */
5943 + { NULL, 85, 1024, 768, 10582, 208, 48, 36, 1, 96, 3,
5944 + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
5945 + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
5946 + /* 1280x960-60 VESA */
5947 + { NULL, 60, 1280, 960, 9259, 312, 96, 36, 1, 112, 3,
5948 + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
5949 + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
5950 + /* 1280x960-85 VESA */
5951 + { NULL, 85, 1280, 960, 6734, 224, 64, 47, 1, 160, 3,
5952 + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
5953 + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
5954 + /* 1280x1024-60 VESA */
5955 + { NULL, 60, 1280, 1024, 9259, 248, 48, 38, 1, 112, 3,
5956 + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
5957 + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
5958 + /* 1280x1024-75 VESA */
5959 + { NULL, 75, 1280, 1024, 7407, 248, 16, 38, 1, 144, 3,
5960 + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
5961 + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
5962 + /* 1280x1024-85 VESA */
5963 + { NULL, 85, 1280, 1024, 6349, 224, 64, 44, 1, 160, 3,
5964 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
5965 - FB_VMODE_NONINTERLACED, 0 },
5967 - { NULL, 70, 640, 400, 39770, 40, 8, 28, 5, 96, 2,
5968 - FB_SYNC_HOR_HIGH_ACT,
5969 - FB_VMODE_NONINTERLACED, 0 },
5971 - { NULL, 70, 640, 480, 35014, 88, 24, 15, 2, 64, 3,
5972 - 0, FB_VMODE_NONINTERLACED, 0 },
5974 - { NULL, 72, 640, 480, 32102, 120, 16, 20, 1, 40, 3,
5975 - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
5976 - FB_VMODE_NONINTERLACED, 0 },
5978 - { NULL, 75, 640, 480, 31746, 120, 16, 16, 1, 64, 3,
5979 - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
5980 - FB_VMODE_NONINTERLACED, 0 },
5982 - { NULL, 85, 640, 480, 27780, 80, 56, 25, 1, 56, 3,
5983 - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
5984 - FB_VMODE_NONINTERLACED, 0 },
5986 - { NULL, 90, 640, 480, 26392, 96, 32, 22, 1, 64, 3,
5987 - 0, FB_VMODE_NONINTERLACED, 0 },
5989 - { NULL, 100, 640, 480, 23167, 104, 40, 25, 1, 64, 3,
5990 - 0, FB_VMODE_NONINTERLACED, 0 },
5992 - { NULL, 60, 640, 480, 39682, 48, 16, 25, 10, 88, 2,
5993 - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
5994 - FB_VMODE_NONINTERLACED, 0 },
5996 - { NULL, 56, 800, 600, 27901, 128, 24, 22, 1, 72, 2,
5997 - 0, FB_VMODE_NONINTERLACED, 0 },
5999 - { NULL, 60, 800, 600, 25131, 72, 32, 23, 1, 136, 4,
6000 - 0, FB_VMODE_NONINTERLACED, 0 },
6002 - { NULL, 70, 800, 600, 21873, 120, 40, 21, 4, 80, 3,
6003 - 0, FB_VMODE_NONINTERLACED, 0 },
6005 - { NULL, 72, 800, 600, 20052, 64, 56, 23, 37, 120, 6,
6006 - 0, FB_VMODE_NONINTERLACED, 0 },
6008 - { NULL, 75, 800, 600, 20202, 160, 16, 21, 1, 80, 3,
6009 - 0, FB_VMODE_NONINTERLACED, 0 },
6011 - { NULL, 85, 800, 600, 17790, 152, 32, 27, 1, 64, 3,
6012 - 0, FB_VMODE_NONINTERLACED, 0 },
6014 - { NULL, 90, 800, 600, 16648, 128, 40, 28, 1, 88, 3,
6015 - 0, FB_VMODE_NONINTERLACED, 0 },
6017 - { NULL, 100, 800, 600, 14667, 136, 48, 27, 1, 88, 3,
6018 - 0, FB_VMODE_NONINTERLACED, 0 },
6020 - { NULL, 60, 800, 600, 25131, 88, 40, 23, 1, 128, 4,
6021 - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
6022 - FB_VMODE_NONINTERLACED, 0 },
6024 - { NULL, 60, 1024, 768, 15385, 160, 24, 29, 3, 136, 6,
6025 - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
6026 - FB_VMODE_NONINTERLACED, 0 },
6028 - { NULL, 70, 1024, 768, 13346, 144, 24, 29, 3, 136, 6,
6029 - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
6030 - FB_VMODE_NONINTERLACED, 0 },
6032 - { NULL, 72, 1024, 768, 12702, 168, 56, 29, 4, 112, 3,
6033 - 0, FB_VMODE_NONINTERLACED, 0 },
6035 - { NULL, 75, 1024, 768, 12703, 176, 16, 28, 1, 96, 3,
6036 - 0, FB_VMODE_NONINTERLACED, 0 },
6038 - { NULL, 85, 1024, 768, 10581, 208, 48, 36, 1, 96, 3,
6039 - 0, FB_VMODE_NONINTERLACED, 0 },
6041 - { NULL, 90, 1024, 768, 9981, 176, 64, 37, 1, 112, 3,
6042 - 0, FB_VMODE_NONINTERLACED, 0 },
6043 - /* 1024x768-100 */
6044 - { NULL, 100, 1024, 768, 8825, 184, 72, 42, 1, 112, 3,
6045 - 0, FB_VMODE_NONINTERLACED, 0 },
6047 - { NULL, 60, 1024, 768, 15385, 160, 24, 29, 3, 136, 6,
6048 - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
6049 - FB_VMODE_NONINTERLACED, 0 },
6051 - { NULL, 60, 1152, 864, 12251, 184, 64, 27, 1, 120, 3,
6052 - 0, FB_VMODE_NONINTERLACED, 0 },
6054 - { NULL, 70, 1152, 864, 10254, 192, 72, 32, 8, 120, 3,
6055 - 0, FB_VMODE_NONINTERLACED, 0 },
6057 - { NULL, 72, 1152, 864, 9866, 200, 72, 33, 7, 128, 3,
6058 - 0, FB_VMODE_NONINTERLACED, 0 },
6060 - { NULL, 75, 1152, 864, 9259, 256, 64, 32, 1, 128, 3,
6061 - 0, FB_VMODE_NONINTERLACED, 0 },
6063 - { NULL, 85, 1152, 864, 8357, 200, 72, 37, 3, 128, 3,
6064 - 0, FB_VMODE_NONINTERLACED, 0 },
6066 - { NULL, 90, 1152, 864, 7719, 208, 80, 42, 9, 128, 3,
6067 - 0, FB_VMODE_NONINTERLACED, 0 },
6068 - /* 1152x864-100 */
6069 - { NULL, 100, 1152, 864, 6947, 208, 80, 48, 3, 128, 3,
6070 - 0, FB_VMODE_NONINTERLACED, 0 },
6072 - { NULL, 60, 1152, 864, 12251, 184, 64, 27, 1, 120, 3,
6073 - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
6074 - FB_VMODE_NONINTERLACED, 0 },
6075 - /* 1280x1024-60 */
6076 - { NULL, 60, 1280, 1024, 9262, 248, 48, 38, 1, 112, 3,
6077 - 0, FB_VMODE_NONINTERLACED, 0 },
6078 - /* 1280x1024-70 */
6079 - { NULL, 70, 1280, 1024, 7719, 224, 88, 38, 6, 136, 3,
6080 - 0, FB_VMODE_NONINTERLACED, 0 },
6081 - /* 1280x1024-72 */
6082 - { NULL, 72, 1280, 1024, 7490, 224, 88, 39, 7, 136, 3,
6083 - 0, FB_VMODE_NONINTERLACED, 0 },
6084 - /* 1280x1024-75 */
6085 - { NULL, 75, 1280, 1024, 7409, 248, 16, 38, 1, 144, 3,
6086 - 0, FB_VMODE_NONINTERLACED, 0 },
6087 - /* 1280x1024-85 */
6088 - { NULL, 85, 1280, 1024, 6351, 224, 64, 44, 1, 160, 3,
6089 - 0, FB_VMODE_NONINTERLACED, 0 },
6090 - /* 1280x1024-90 */
6091 - { NULL, 90, 1280, 1024, 5791, 240, 96, 51, 12, 144, 3,
6092 - 0, FB_VMODE_NONINTERLACED, 0 },
6093 - /* 1280x1024-100 */
6094 - { NULL, 100, 1280, 1024, 5212, 240, 96, 57, 6, 144, 3,
6095 - 0, FB_VMODE_NONINTERLACED, 0 },
6096 - /* 1280x1024-60 */
6097 - { NULL, 60, 1280, 1024, 9262, 248, 48, 38, 1, 112, 3,
6098 - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
6099 - FB_VMODE_NONINTERLACED, 0 },
6100 - /* 1600x1200-60 */
6101 + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
6102 + /* 1600x1200-60 VESA */
6103 { NULL, 60, 1600, 1200, 6172, 304, 64, 46, 1, 192, 3,
6104 - 0, FB_VMODE_NONINTERLACED, 0 },
6105 - /* 1600x1200-70 */
6106 - { NULL, 70, 1600, 1200, 5291, 304, 64, 46, 1, 192, 3,
6107 - 0, FB_VMODE_NONINTERLACED, 0 },
6108 - /* 1600x1200-72 */
6109 - { NULL, 72, 1600, 1200, 5053, 288, 112, 47, 13, 176, 3,
6110 - 0, FB_VMODE_NONINTERLACED, 0 },
6111 - /* 1600x1200-75 */
6112 + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
6113 + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
6114 + /* 1600x1200-75 VESA */
6115 { NULL, 75, 1600, 1200, 4938, 304, 64, 46, 1, 192, 3,
6116 - 0, FB_VMODE_NONINTERLACED, 0 },
6117 - /* 1600x1200-85 */
6118 + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
6119 + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
6120 + /* 1600x1200-85 VESA */
6121 { NULL, 85, 1600, 1200, 4357, 304, 64, 46, 1, 192, 3,
6122 - 0, FB_VMODE_NONINTERLACED, 0 },
6123 - /* 1600x1200-90 */
6124 - { NULL, 90, 1600, 1200, 3981, 304, 128, 60, 1, 176, 3,
6125 - 0, FB_VMODE_NONINTERLACED, 0 },
6126 - /* 1600x1200-100 */
6127 - { NULL, 100, 1600, 1200, 3563, 304, 128, 67, 1, 176, 3,
6128 - 0, FB_VMODE_NONINTERLACED, 0 },
6129 - /* 1600x1200-60 */
6130 - { NULL, 60, 1600, 1200, 6172, 304, 64, 46, 1, 192, 3,
6131 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
6132 - FB_VMODE_NONINTERLACED, 0 },
6133 - /* 1920x1440-60 */
6134 - { NULL, 60, 1920, 1440, 4273, 344, 128, 56, 1, 208, 3,
6135 - 0, FB_VMODE_NONINTERLACED, 0 },
6136 - /* 1920x1440-70 */
6137 - { NULL, 70, 1920, 1440, 3593, 360, 152, 55, 8, 208, 3,
6138 - 0, FB_VMODE_NONINTERLACED, 0 },
6139 - /* 1920x1440-72 */
6140 - { NULL, 72, 1920, 1440, 3472, 360, 152, 68, 4, 208, 3,
6141 - 0, FB_VMODE_NONINTERLACED, 0 },
6142 - /* 1920x1440-75 */
6143 - { NULL, 75, 1920, 1440, 3367, 352, 144, 56, 1, 224, 3,
6144 - 0, FB_VMODE_NONINTERLACED, 0 },
6145 - /* 1920x1440-85 */
6146 - { NULL, 85, 1920, 1440, 2929, 368, 152, 68, 1, 216, 3,
6147 - 0, FB_VMODE_NONINTERLACED, 0 },
6148 + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
6149 + /* 1200x900-75 - CRT timings for the OLPC mode */
6150 + { NULL, 75, 1200, 900, 8049, 104, 240, 29, 54, 136, 3,
6151 + 0, FB_VMODE_NONINTERLACED, 0 }
6155 +const struct fb_videomode olpc_dcon_modedb[] __initdata = {
6156 + /* The only mode the DCON has is 1200x900 */
6157 + { NULL, 50, 1200, 900, 17460, 24, 8, 4, 5, 8, 3,
6158 + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
6159 + FB_VMODE_NONINTERLACED, 0 }
6163 static int lxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
6165 if (var->xres > 1920 || var->yres > 1440)
6166 @@ -255,8 +154,7 @@ static int lxfb_set_par(struct fb_info *
6167 fb_alloc_cmap(&info->cmap, 1<<info->var.bits_per_pixel, 0);
6170 - info->fix.line_length = lx_get_pitch(info->var.xres,
6171 - info->var.bits_per_pixel);
6172 + info->fix.line_length = lx_get_pitch(info->var.xres, info->var.bits_per_pixel);
6176 @@ -371,24 +269,61 @@ static int __init lxfb_map_video_memory(
6177 writel(info->fix.smem_start & 0xFF000000,
6178 par->dc_regs + DC_PHY_MEM_OFFSET);
6180 - writel(0, par->dc_regs + DC_UNLOCK);
6182 dev_info(&dev->dev, "%d KB of video memory at 0x%lx\n",
6183 info->fix.smem_len / 1024, info->fix.smem_start);
6188 +static int lxfb_set_gamma(struct fb_info *info, void * __user data)
6190 + unsigned int gamma[LXFB_GAMMA_DWORDS];
6192 + if (copy_from_user(gamma, data, LXFB_GAMMA_SIZE))
6195 + lx_set_gamma(info, gamma, LXFB_GAMMA_SIZE);
6199 +static int lxfb_get_gamma(struct fb_info *info, void * __user data)
6201 + unsigned int gamma[LXFB_GAMMA_DWORDS];
6202 + memset(gamma, 0, sizeof(gamma));
6204 + lx_get_gamma(info, gamma, LXFB_GAMMA_DWORDS);
6206 + return copy_to_user(data, gamma, LXFB_GAMMA_SIZE) ?
6210 +static int lxfb_ioctl( struct fb_info *info, unsigned int cmd,
6211 + unsigned long arg)
6215 + return lxfb_set_gamma(info, (void * __user) arg);
6218 + return lxfb_get_gamma(info, (void * __user) arg);
6224 static struct fb_ops lxfb_ops = {
6225 .owner = THIS_MODULE,
6226 .fb_check_var = lxfb_check_var,
6227 .fb_set_par = lxfb_set_par,
6228 .fb_setcolreg = lxfb_setcolreg,
6229 .fb_blank = lxfb_blank,
6230 + .fb_ioctl = lxfb_ioctl,
6231 /* No HW acceleration for now. */
6232 .fb_fillrect = cfb_fillrect,
6233 .fb_copyarea = cfb_copyarea,
6234 .fb_imageblit = cfb_imageblit,
6235 + .fb_powerdown = lx_shutdown,
6236 + .fb_powerup = lx_powerup,
6239 static struct fb_info * __init lxfb_init_fbinfo(struct device *dev)
6240 @@ -431,6 +366,45 @@ static struct fb_info * __init lxfb_init
6246 +static int lxfb_suspend(struct pci_dev *pdev, pm_message_t state)
6248 + struct fb_info *info = pci_get_drvdata(pdev);
6250 + if (pdev->dev.power.power_state.event == state.event)
6253 + if (state.event == PM_EVENT_SUSPEND) {
6255 + acquire_console_sem();
6256 + lx_shutdown(info);
6257 + fb_set_suspend(info, 1);
6258 + release_console_sem();
6261 + pdev->dev.power.power_state = state;
6265 +static int lxfb_resume(struct pci_dev *pdev)
6267 + struct fb_info *info = pci_get_drvdata(pdev);
6269 + acquire_console_sem();
6271 + /* Turn the engine completely on */
6274 + fb_set_suspend(info, 0);
6275 + release_console_sem();
6277 + pdev->dev.power.power_state = PMSG_ON;
6283 static int __init lxfb_probe(struct pci_dev *pdev,
6284 const struct pci_device_id *id)
6286 @@ -467,6 +441,13 @@ static int __init lxfb_probe(struct pci_
6287 modedb_ptr = (struct fb_videomode *) geode_modedb;
6288 modedb_size = ARRAY_SIZE(geode_modedb);
6291 + if (olpc_has_dcon()) {
6292 + modedb_ptr = (struct fb_videomode *) olpc_dcon_modedb;
6293 + modedb_size = ARRAY_SIZE(olpc_dcon_modedb);
6297 ret = fb_find_mode(&info->var, info, mode_option,
6298 modedb_ptr, modedb_size, NULL, 16);
6300 @@ -556,6 +537,10 @@ static struct pci_driver lxfb_driver = {
6301 .id_table = lxfb_id_table,
6302 .probe = lxfb_probe,
6303 .remove = lxfb_remove,
6305 + .suspend = lxfb_suspend,
6306 + .resume = lxfb_resume
6311 Index: linux-2.6.24.7/drivers/video/geode/lxfb.h
6312 ===================================================================
6313 --- linux-2.6.24.7.orig/drivers/video/geode/lxfb.h
6314 +++ linux-2.6.24.7/drivers/video/geode/lxfb.h
6315 @@ -25,10 +25,23 @@ void lx_set_mode(struct fb_info *);
6316 void lx_get_gamma(struct fb_info *, unsigned int *, int);
6317 void lx_set_gamma(struct fb_info *, unsigned int *, int);
6318 unsigned int lx_framebuffer_size(void);
6319 +int lx_shutdown(struct fb_info *);
6320 +int lx_powerup(struct fb_info *);
6321 int lx_blank_display(struct fb_info *, int);
6322 void lx_set_palette_reg(struct fb_info *, unsigned int, unsigned int,
6323 unsigned int, unsigned int);
6327 +/* ioctl() defines */
6329 +#define FBIOSGAMMA _IOW('F', 0x20, void *)
6330 +#define FBIOGGAMMA _IOW('F', 0x21, void *)
6332 +/* General definitions */
6333 +#define LXFB_GAMMA_DWORDS 256 /* number of dwords in the gamma ram */
6334 +#define LXFB_GAMMA_SIZE (LXFB_GAMMA_DWORDS * sizeof(unsigned int))
6338 #define MSR_LX_GLD_CONFIG 0x48002001
6339 @@ -127,7 +140,7 @@ void lx_set_palette_reg(struct fb_info *
6341 #define DC_GFX_SCALE 0x90
6342 #define DC_IRQ_FILT_CTL 0x94
6344 +#define DC_IRQFILT_H_FILT_SEL 0x00000400
6347 #define DC_IRQ_MASK (1 << 0)
6348 Index: linux-2.6.24.7/drivers/video/geode/lxfb_ops.c
6349 ===================================================================
6350 --- linux-2.6.24.7.orig/drivers/video/geode/lxfb_ops.c
6351 +++ linux-2.6.24.7/drivers/video/geode/lxfb_ops.c
6353 #include <linux/kernel.h>
6354 #include <linux/errno.h>
6355 #include <linux/fb.h>
6356 -#include <linux/uaccess.h>
6357 -#include <linux/delay.h>
6358 +#include <asm/uaccess.h>
6359 +#include <asm/delay.h>
6360 +#include <asm/olpc.h>
6365 +#include "geode_regs.h"
6368 * Support panel scaling
6370 @@ -290,6 +294,19 @@ unsigned int lx_framebuffer_size(void)
6375 + if (machine_is_olpc() && !olpc_has_vsa()) {
6377 + rdmsr(MSR_LX_GLIU0_P2D_RO0, lo, hi);
6379 + /* Top page number */
6380 + val = ((hi & 0xff) << 12) | ((lo & 0xfff00000) >> 20);
6381 + val -= (lo & 0x000fffff); /* Subtract bottom page number */
6382 + val += 1; /* Adjust page count */
6383 + return (val << 12);
6387 /* The frame buffer size is reported by a VSM in VSA II */
6388 /* Virtual Register Class = 0x02 */
6389 /* VG_MEM_SIZE (1MB units) = 0x00 */
6390 @@ -301,6 +318,34 @@ unsigned int lx_framebuffer_size(void)
6394 +void lx_set_gamma(struct fb_info *info, unsigned int *gamma, int len)
6397 + struct lxfb_par *par = info->par;
6399 + writel(0, par->df_regs + DF_PAR);
6401 + /* Sequential writes to the data register will increment the
6402 + address automatically */
6404 + for(i = 0; i < len; i++)
6405 + writel(gamma[i] & 0xFFFFFF, par->df_regs + DF_PDR);
6407 + writel(readl(par->df_regs + DF_MISC) & ~DF_MISC_GAM_BYPASS,
6408 + par->df_regs + DF_MISC);
6411 +void lx_get_gamma(struct fb_info *info, unsigned int *gamma, int len)
6414 + struct lxfb_par *par = info->par;
6416 + writel(0, par->df_regs + DF_PAR);
6418 + for(i = 0; i < len;i++)
6419 + gamma[i] = readl(par->df_regs + DF_PDR);
6422 void lx_set_mode(struct fb_info *info)
6424 struct lxfb_par *par = info->par;
6425 @@ -313,6 +358,7 @@ void lx_set_mode(struct fb_info *info)
6426 int vactive, vblankstart, vsyncstart, vsyncend, vblankend, vtotal;
6428 /* Unlock the DC registers */
6429 + readl(par->dc_regs + DC_UNLOCK);
6430 writel(DC_UNLOCK_CODE, par->dc_regs + DC_UNLOCK);
6432 lx_graphics_disable(info);
6433 @@ -483,54 +529,408 @@ void lx_set_palette_reg(struct fb_info *
6434 writel(val, par->dc_regs + DC_PAL_DATA);
6437 +static int lx_blank_mode = FB_BLANK_UNBLANK;
6439 int lx_blank_display(struct fb_info *info, int blank_mode)
6441 struct lxfb_par *par = info->par;
6443 - int blank, hsync, vsync;
6446 + if (blank_mode == lx_blank_mode)
6449 + writel(DC_UNLOCK_CODE, par->dc_regs + DC_UNLOCK);
6451 + if (lx_blank_mode == FB_BLANK_POWERDOWN) {
6452 + val = readl(par->df_regs + DF_FP_PM);
6453 + writel(val | DF_FP_PM_P, par->df_regs + DF_FP_PM);
6454 + val = readl(par->df_regs + DF_MISC) & ~DF_MISC_DAC_PWRDN;
6455 + writel(val, par->df_regs + DF_MISC);
6457 + val = readl(par->dc_regs + DC_GENERAL_CFG) | DC_GCFG_DFLE;
6458 + writel(val, par->dc_regs + DC_GENERAL_CFG);
6460 + val = readl(par->dc_regs + DC_DISPLAY_CFG) | DC_DCFG_TGEN;
6461 + writel(val, par->dc_regs + DC_DISPLAY_CFG);
6464 + dcfg = readl(par->df_regs + DF_DISPLAY_CFG);
6466 /* CRT power saving modes. */
6467 switch (blank_mode) {
6468 case FB_BLANK_UNBLANK:
6469 - blank = 0; hsync = 1; vsync = 1;
6470 + dcfg |= DF_DCFG_CRT_EN | DF_DCFG_HSYNC_EN | DF_DCFG_VSYNC_EN;
6471 + dcfg |= DF_DCFG_DAC_BL_EN;
6473 case FB_BLANK_NORMAL:
6474 - blank = 1; hsync = 1; vsync = 1;
6475 + dcfg |= DF_DCFG_CRT_EN | DF_DCFG_HSYNC_EN | DF_DCFG_VSYNC_EN;
6476 + dcfg |= DF_DCFG_DAC_BL_EN;
6478 case FB_BLANK_VSYNC_SUSPEND:
6479 - blank = 1; hsync = 1; vsync = 0;
6480 + dcfg |= DF_DCFG_CRT_EN | DF_DCFG_HSYNC_EN | DF_DCFG_DAC_BL_EN;
6481 + dcfg &= ~DF_DCFG_VSYNC_EN;
6483 case FB_BLANK_HSYNC_SUSPEND:
6484 - blank = 1; hsync = 0; vsync = 1;
6485 + dcfg |= DF_DCFG_CRT_EN | DF_DCFG_VSYNC_EN | DF_DCFG_DAC_BL_EN;
6486 + dcfg &= ~DF_DCFG_HSYNC_EN;
6488 case FB_BLANK_POWERDOWN:
6489 - blank = 1; hsync = 0; vsync = 0;
6490 + dcfg &= ~DF_DCFG_DAC_BL_EN;
6491 + dcfg &= ~(DF_DCFG_CRT_EN | DF_DCFG_HSYNC_EN | DF_DCFG_VSYNC_EN);
6494 + writel(0, par->dc_regs + DC_UNLOCK);
6498 - dcfg = readl(par->df_regs + DF_DISPLAY_CFG);
6499 - dcfg &= ~(DF_DCFG_DAC_BL_EN
6500 - | DF_DCFG_HSYNC_EN | DF_DCFG_VSYNC_EN);
6502 - dcfg |= DF_DCFG_DAC_BL_EN;
6504 - dcfg |= DF_DCFG_HSYNC_EN;
6506 - dcfg |= DF_DCFG_VSYNC_EN;
6507 - writel(dcfg, par->df_regs + DF_DISPLAY_CFG);
6508 + /* Turn off the engine when we are in power down mode */
6509 + if (blank_mode == FB_BLANK_POWERDOWN) {
6510 + val = readl(par->df_regs + DF_MISC) | DF_MISC_DAC_PWRDN;
6511 + writel(val, par->df_regs + DF_MISC);
6513 + val = readl(par->dc_regs + DC_DISPLAY_CFG);
6514 + val &= ~DC_DCFG_TGEN;
6515 + writel(val, par->dc_regs + DC_DISPLAY_CFG);
6519 + val = readl(par->dc_regs + DC_GENERAL_CFG) & ~DC_GCFG_DFLE;
6520 + writel(val, par->dc_regs + DC_GENERAL_CFG);
6522 + val = readl(par->df_regs + DF_FP_PM);
6523 + writel(val & ~DF_FP_PM_P, par->df_regs + DF_FP_PM);
6526 + writel(0, par->dc_regs + DC_UNLOCK);
6528 + lx_blank_mode = blank_mode;
6532 +static struct geoderegs saved_regs;
6534 +static void lx_save_regs(struct fb_info *info, struct geoderegs *regs)
6536 + struct lxfb_par *par = info->par;
6540 + /* Wait for the command buffer to empty */
6541 + while(!(readl(par->gp_regs + 0x44) & (1 << 4)));
6543 + /* Unlock the DC */
6544 + writel(DC_UNLOCK_CODE, par->dc_regs + DC_UNLOCK);
6546 + rdmsrl(MSR_LX_DF_PADSEL, regs->msr.padsel);
6547 + rdmsrl(MSR_LX_GLCP_DOTPLL, regs->msr.dotpll);
6548 + rdmsrl(MSR_LX_DF_GLCONFIG, regs->msr.dfglcfg);
6549 + rdmsrl(MSR_LX_DC_SPARE, regs->msr.dcspare);
6551 + writel(0x4758, par->dc_regs + 0x00);
6553 + memcpy(regs->gp.b, par->gp_regs, GP_REG_SIZE);
6554 + memcpy(regs->dc.b, par->dc_regs, DC_REG_SIZE);
6555 + memcpy(regs->vp.b, par->df_regs, VP_REG_SIZE);
6556 + memcpy(regs->fp.b, par->df_regs + VP_FP_START, FP_REG_SIZE);
6558 + /* Save the palette */
6559 + writel(0, par->dc_regs + 0x70);
6560 /* Power on/off flat panel */
6561 + for(i = 0; i < DC_PAL_SIZE; i++)
6562 + regs->pal[i] = readl(par->dc_regs + 0x74);
6564 - if (par->output & OUTPUT_PANEL) {
6565 - fp_pm = readl(par->df_regs + DF_FP_PM);
6566 - if (blank_mode == FB_BLANK_POWERDOWN)
6567 - fp_pm &= ~DF_FP_PM_P;
6569 - fp_pm |= DF_FP_PM_P;
6570 - writel(fp_pm, par->df_regs + DF_FP_PM);
6571 + /* save the filter coefficients */
6573 + filt = readl(par->dc_regs + 0x94);
6574 + filt |= DC_IRQFILT_H_FILT_SEL;
6576 + for(i = 0; i < DC_HFILT_SIZE; i++) {
6577 + writel((filt & 0xFFFFFF00) | i, par->dc_regs + 0x94);
6578 + regs->hcoeff[i << 1] = readl(par->dc_regs + 0x98);
6579 + regs->hcoeff[(i << 1) + 1] = readl(par->dc_regs + 0x9c);
6582 + filt &= ~DC_IRQFILT_H_FILT_SEL;
6584 + for(i = 0; i < DC_VFILT_SIZE; i++) {
6585 + writel((filt & 0xFFFFFF00) | i, par->dc_regs + 0x94);
6586 + regs->vcoeff[i] = readl(par->dc_regs + 0x98);
6589 + /* Save the vg filter coefficients */
6590 + for(i = 0; i < VP_COEFF_COUNT; i++)
6591 + regs->vp_coeff[i] =
6592 + readl(par->df_regs + 0x1000 + (i << 2));
6594 + /* Save the VP gamma */
6596 + writel(0, par->df_regs + 0x38);
6598 + for(i = 0; i <= 0xFF; i++)
6599 + regs->gamma[i] = readl(par->df_regs + 0x40);
6602 +static void lx_restore_dc(struct lxfb_par *par, struct geoderegs *regs)
6607 + /* Unlock the registers */
6608 + writel(DC_UNLOCK_CODE, par->dc_regs + 0x00);
6610 + /* Restore the framebuffer offset */
6611 + writel(regs->dc.r.gliu0_mem_offset, par->dc_regs + 0x84);
6613 + /* Blank the configuration registers while we restore */
6614 + writel(0, par->dc_regs + 0x04);
6615 + writel(0, par->dc_regs + 0x08);
6617 + /* Restore the bulk of the registers */
6619 + writel(regs->dc.r.arb, par->dc_regs + 0x0C);
6620 + writel(regs->dc.r.fb_st_offset, par->dc_regs + 0x10);
6621 + writel(regs->dc.r.cb_st_offset, par->dc_regs + 0x14);
6622 + writel(regs->dc.r.curs_st_offset, par->dc_regs + 0x18);
6626 + writel(regs->dc.r.vid_y_st_offset, par->dc_regs + 0x20);
6627 + writel(regs->dc.r.vid_u_st_offset, par->dc_regs + 0x24);
6628 + writel(regs->dc.r.vid_v_st_offset, par->dc_regs + 0x28);
6630 + writel(regs->dc.r.dctop, par->dc_regs + 0x2c);
6631 + writel(regs->dc.r.line_size, par->dc_regs + 0x30);
6632 + writel(regs->dc.r.gfx_pitch, par->dc_regs + 0x34);
6633 + writel(regs->dc.r.vid_yuv_pitch, par->dc_regs + 0x38);
6634 + writel(regs->dc.r.h_active_timing, par->dc_regs + 0x40);
6635 + writel(regs->dc.r.h_blank_timing, par->dc_regs + 0x44);
6636 + writel(regs->dc.r.h_sync_timing, par->dc_regs + 0x48);
6637 + writel(regs->dc.r.v_active_timing, par->dc_regs + 0x50);
6638 + writel(regs->dc.r.v_blank_timing, par->dc_regs + 0x54);
6639 + writel(regs->dc.r.v_sync_timing, par->dc_regs + 0x58);
6640 + writel(regs->dc.r.fbactive, par->dc_regs + 0x5c);
6641 + writel(regs->dc.r.dc_cursor_x, par->dc_regs + 0x60);
6642 + writel(regs->dc.r.dc_cursor_y, par->dc_regs + 0x64);
6644 + /* skip 0x68, 0x6c, 0x70, 0x74, 0x78, 0x7c */
6646 + writel(regs->dc.r.dc_vid_ds_delta, par->dc_regs + 0x80);
6648 + /* 0x84 was written above */
6650 + writel(regs->dc.r.dv_ctl | 0x01, par->dc_regs + 0x88);
6651 + writel(regs->dc.r.gfx_scale, par->dc_regs + 0x90);
6652 + writel(regs->dc.r.irq_filt_ctl, par->dc_regs + 0x94);
6654 + /* skip 0x98, 0x9c */
6656 + writel(regs->dc.r.vbi_event_ctl, par->dc_regs + 0xA0);
6657 + writel(regs->dc.r.vbi_odd_ctl, par->dc_regs + 0xA4);
6658 + writel(regs->dc.r.vbi_hor, par->dc_regs + 0xA8);
6659 + writel(regs->dc.r.vbi_ln_odd, par->dc_regs + 0xAC);
6660 + writel(regs->dc.r.vbi_ln_event, par->dc_regs + 0xB0);
6661 + writel(regs->dc.r.vbi_pitch, par->dc_regs + 0xB4);
6662 + writel(regs->dc.r.clr_key, par->dc_regs + 0xB8);
6663 + writel(regs->dc.r.clr_key_mask, par->dc_regs + 0xBC);
6664 + writel(regs->dc.r.clr_key_x, par->dc_regs + 0xC0);
6665 + writel(regs->dc.r.clr_key_y, par->dc_regs + 0xC4);
6666 + writel(regs->dc.r.irq, par->dc_regs + 0xC8);
6667 + writel(regs->dc.r.genlk_ctrl, par->dc_regs + 0xD4);
6668 + writel(regs->dc.r.vid_even_y_st_offset, par->dc_regs + 0xD8);
6669 + writel(regs->dc.r.vid_even_u_st_offset, par->dc_regs + 0xDC);
6670 + writel(regs->dc.r.vid_even_v_st_offset, par->dc_regs + 0xE0);
6671 + writel(regs->dc.r.v_active_even_timing, par->dc_regs + 0xE4);
6672 + writel(regs->dc.r.v_blank_even_timing, par->dc_regs + 0xE8);
6673 + writel(regs->dc.r.v_sync_even_timing, par->dc_regs + 0xEC);
6675 + /* Restore the palette */
6676 + writel(0, par->dc_regs + 0x70);
6678 + for(i = 0; i < DC_PAL_SIZE; i++)
6679 + writel(regs->pal[i], par->dc_regs + 0x74);
6681 + /* Restore the horizontal filter coefficients */
6682 + filt = readl(par->dc_regs + 0x94);
6683 + filt |= DC_IRQFILT_H_FILT_SEL;
6685 + for(i = 0; i < DC_HFILT_SIZE; i++) {
6686 + writel(((filt & 0xFFFFFF00) | i), par->dc_regs + 0x94);
6687 + writel(regs->hcoeff[i << 1], par->dc_regs + 0x98);
6688 + writel(regs->hcoeff[(i << 1) + 1], par->dc_regs + 0x9c);
6691 + filt &= ~DC_IRQFILT_H_FILT_SEL;
6693 + for(i = 0; i < DC_VFILT_SIZE; i++) {
6694 + writel(((filt & 0xFFFFFF00) | i), par->dc_regs + 0x94);
6695 + writel(regs->vcoeff[i], par->dc_regs + 0x98);
6698 + /* Turn on the dotpll */
6699 + lx_set_dotpll((u32) (regs->msr.dotpll >> 32));
6701 + /* Restore MSRs */
6702 + wrmsrl(MSR_LX_DC_SPARE, regs->msr.dcspare);
6704 + /* Restore the configuration registers */
6706 + writel(regs->dc.r.dcfg, par->dc_regs + 0x08);
6707 + writel(regs->dc.r.gcfg, par->dc_regs + 0x04);
6709 + /* Lock the DC again */
6710 + writel(0, par->dc_regs + 0x00);
6713 +static void lx_restore_vp(struct lxfb_par *par, struct geoderegs *regs)
6718 + /* Restore MSRs */
6720 + wrmsrl(MSR_LX_DF_GLCONFIG, regs->msr.dfglcfg);
6721 + wrmsrl(MSR_LX_DF_PADSEL, regs->msr.padsel);
6723 + /* Restore the registers */
6725 + writel((u32) regs->vp.r.vx, par->df_regs + 0x10);
6726 + writel((u32) regs->vp.r.vy, par->df_regs + 0x18);
6727 + writel((u32) regs->vp.r.vs, par->df_regs + 0x20);
6728 + writel((u32) regs->vp.r.vck, par->df_regs + 0x28);
6729 + writel((u32) regs->vp.r.vcm, par->df_regs + 0x30);
6730 + /* skip 0x38 and 0x40 */
6731 + writel((u32) regs->vp.r.slr, par->df_regs + 0x48);
6732 + writel((u32) regs->vp.r.misc, par->df_regs + 0x50);
6734 + writel((u32) regs->vp.r.vys, par->df_regs + 0x60);
6735 + writel((u32) regs->vp.r.vxs, par->df_regs + 0x68);
6736 + writel((u32) regs->vp.r.vde, par->df_regs + 0x98);
6737 + writel((u32) regs->vp.r.cck, par->df_regs + 0xA0);
6738 + writel((u32) regs->vp.r.ccm, par->df_regs + 0xA8);
6739 + writel((u32) regs->vp.r.cc1, par->df_regs + 0xB0);
6740 + writel((u32) regs->vp.r.cc2, par->df_regs + 0xB8);
6741 + writel((u32) regs->vp.r.a1x, par->df_regs + 0xC0);
6742 + writel((u32) regs->vp.r.a1y, par->df_regs + 0xC8);
6743 + writel((u32) regs->vp.r.a1c, par->df_regs + 0xD0);
6744 + writel((u32) regs->vp.r.a1t, par->df_regs + 0xD8);
6745 + writel((u32) regs->vp.r.a2x, par->df_regs + 0xE0);
6746 + writel((u32) regs->vp.r.a2y, par->df_regs + 0xE8);
6747 + writel((u32) regs->vp.r.a2c, par->df_regs + 0xF0);
6748 + writel((u32) regs->vp.r.a2t, par->df_regs + 0xF8);
6749 + writel((u32) regs->vp.r.a3x, par->df_regs + 0x100);
6750 + writel((u32) regs->vp.r.a3y, par->df_regs + 0x108);
6751 + writel((u32) regs->vp.r.a3c, par->df_regs + 0x110);
6752 + writel((u32) regs->vp.r.a3t, par->df_regs + 0x118);
6753 + writel((u32) regs->vp.r.vrr, par->df_regs + 0x120);
6754 + writel((u32) regs->vp.r.vye, par->df_regs + 0x138);
6755 + writel((u32) regs->vp.r.a1ye, par->df_regs + 0x140);
6756 + writel((u32) regs->vp.r.a2ye, par->df_regs + 0x148);
6757 + writel((u32) regs->vp.r.a3ye, par->df_regs + 0x150);
6761 + writel((u32) regs->fp.r.pt1, par->df_regs + 0x400);
6762 + writel((u32) regs->fp.r.pt2, par->df_regs + 0x408);
6763 + writel((u32) regs->fp.r.dfc, par->df_regs + 0x418);
6765 + /* Restore panel power */
6767 + val = readl(par->df_regs + 0x410);
6769 + if (regs->fp.r.pm & (1 << 24)) {
6770 + if (!(val & 0x09))
6771 + writel(regs->fp.r.pm, par->df_regs + 0x410);
6774 + if (!(val & 0x05))
6775 + writel(regs->fp.r.pm, par->df_regs + 0x410);
6778 + /* Restore the vp palette */
6780 + writel(0, par->df_regs + 0x38);
6782 + for(i = 0; i <= 0xFF; i++)
6783 + writel((u32) regs->gamma[i], par->df_regs + 0x40);
6785 + /* Restore filter coefficients */
6787 + for(i = 0; i < VP_COEFF_COUNT; i++)
6788 + writel(regs->vp_coeff[i],
6789 + par->df_regs + 0x1000 + (i << 2));
6791 + /* Restore the configuration registers */
6793 + writel((u32) regs->vp.r.dcfg, par->df_regs + 0x08);
6794 + writel((u32) regs->vp.r.vcfg, par->df_regs + 0x00);
6797 +static void lx_restore_gp(struct lxfb_par *par, struct geoderegs *regs)
6799 + writel(regs->gp.r.dst_offset, par->gp_regs + 0x00);
6800 + writel(regs->gp.r.src_offset, par->gp_regs + 0x04);
6801 + writel(regs->gp.r.stride, par->gp_regs + 0x08);
6802 + writel(regs->gp.r.wid_height, par->gp_regs + 0x0C);
6803 + writel(regs->gp.r.src_color_fg, par->gp_regs + 0x10);
6804 + writel(regs->gp.r.src_color_bg, par->gp_regs + 0x14);
6805 + writel(regs->gp.r.pat_color_0, par->gp_regs + 0x18);
6806 + writel(regs->gp.r.pat_color_1, par->gp_regs + 0x1C);
6807 + writel(regs->gp.r.pat_color_2, par->gp_regs + 0x20);
6808 + writel(regs->gp.r.pat_color_3, par->gp_regs + 0x24);
6809 + writel(regs->gp.r.pat_color_4, par->gp_regs + 0x28);
6810 + writel(regs->gp.r.pat_color_5, par->gp_regs + 0x2C);
6811 + writel(regs->gp.r.pat_data_0, par->gp_regs + 0x30);
6812 + writel(regs->gp.r.pat_data_1, par->gp_regs + 0x34);
6814 + /* Writing to these registers would cause a blt to happen */
6815 + /* 0x38, 0x3c, 0x40 */
6817 + /* Status register (0x44) is read only */
6819 + writel(regs->gp.r.hst_src, par->gp_regs + 0x48);
6820 + writel(regs->gp.r.base_offset, par->gp_regs + 0x4c);
6821 + writel(regs->gp.r.cmd_top, par->gp_regs + 0x50);
6822 + writel(regs->gp.r.cmd_bot, par->gp_regs + 0x54);
6823 + writel(regs->gp.r.cmd_read, par->gp_regs + 0x58);
6824 + writel(regs->gp.r.cmd_write, par->gp_regs + 0x5C);
6825 + writel(regs->gp.r.ch3_offset, par->gp_regs + 0x60);
6826 + writel(regs->gp.r.ch3_mode_str, par->gp_regs + 0x64);
6827 + writel(regs->gp.r.ch3_width, par->gp_regs + 0x6C);
6828 + writel(regs->gp.r.ch3_hsrc, par->gp_regs + 0x70);
6830 + writel(regs->gp.r.int_cntrl, par->gp_regs + 0x70);
6833 +static void lx_restore_regs(struct fb_info *info, struct geoderegs *regs)
6835 + struct lxfb_par *par = info->par;
6837 + lx_restore_gp(par, regs);
6838 + lx_restore_vp(par, regs);
6839 + lx_restore_dc(par, regs);
6842 +static int lx_power_on = 1;
6844 +int lx_shutdown(struct fb_info *info)
6846 + if (lx_power_on == 0)
6849 + lx_save_regs(info, &saved_regs);
6850 + lx_graphics_disable(info);
6856 +int lx_powerup(struct fb_info *info)
6858 + if (lx_power_on == 1)
6861 + lx_restore_regs(info, &saved_regs);
6866 Index: linux-2.6.24.7/drivers/video/geode/Makefile
6867 ===================================================================
6868 --- linux-2.6.24.7.orig/drivers/video/geode/Makefile
6869 +++ linux-2.6.24.7/drivers/video/geode/Makefile
6870 @@ -5,5 +5,5 @@ obj-$(CONFIG_FB_GEODE_GX) += gxfb.o
6871 obj-$(CONFIG_FB_GEODE_LX) += lxfb.o
6873 gx1fb-objs := gx1fb_core.o display_gx1.o video_cs5530.o
6874 -gxfb-objs := gxfb_core.o display_gx.o video_gx.o
6875 +gxfb-objs := gxfb_core.o display_gx.o video_gx.o suspend_gx.o
6876 lxfb-objs := lxfb_core.o lxfb_ops.o
6877 Index: linux-2.6.24.7/drivers/video/geode/suspend_gx.c
6878 ===================================================================
6880 +++ linux-2.6.24.7/drivers/video/geode/suspend_gx.c
6882 +#include <linux/fb.h>
6883 +#include <asm/io.h>
6884 +#include <asm/msr.h>
6886 +#include "geodefb.h"
6887 +#include "video_gx.h"
6889 +void gx_set_dotpll(struct fb_info *info, struct geoderegs *regs)
6891 + int timeout = 1000;
6893 + u64 rstpll, dotpll;
6895 + rdmsrl(MSR_GLCP_SYS_RSTPLL, rstpll);
6896 + rdmsrl(MSR_GLCP_DOTPLL, dotpll);
6898 + dotpll &= 0x00000000ffffffffull;
6899 + dotpll |= regs->msr.dotpll & 0xffffffff00000000ull;
6901 + dotpll |= MSR_GLCP_DOTPLL_DOTRESET;
6902 + dotpll &= ~MSR_GLCP_DOTPLL_BYPASS;
6904 + wrmsrl(MSR_GLCP_DOTPLL, dotpll);
6906 + rstpll |= (regs->msr.rstpll &
6907 + ( MSR_GLCP_SYS_RSTPLL_DOTPREDIV2 |
6908 + MSR_GLCP_SYS_RSTPLL_DOTPREMULT2 |
6909 + MSR_GLCP_SYS_RSTPLL_DOTPOSTDIV3));
6911 + wrmsrl(MSR_GLCP_SYS_RSTPLL, rstpll);
6912 + dotpll &= ~(MSR_GLCP_DOTPLL_DOTRESET);
6913 + wrmsrl(MSR_GLCP_DOTPLL, dotpll);
6916 + rdmsrl(MSR_GLCP_DOTPLL, dotpll);
6917 + } while (timeout-- && !(dotpll & MSR_GLCP_DOTPLL_LOCK));
6920 +/* FIXME: Make sure nothing is read to clear */
6922 +void gx_save_regs(struct fb_info *info, struct geoderegs *regs)
6924 + struct geodefb_par *par = info->par;
6927 + /* Wait for the BLT engine to stop being busy */
6928 + while(readl(par->gp_regs + 0x44) & 0x05);
6930 + rdmsrl(GX_VP_MSR_PAD_SELECT, regs->msr.padsel);
6931 + rdmsrl(MSR_GLCP_DOTPLL, regs->msr.dotpll);
6932 + rdmsrl(MSR_GLCP_SYS_RSTPLL, regs->msr.rstpll);
6934 + writel(0x4758, par->dc_regs + 0x00);
6936 + memcpy(regs->gp.b, par->gp_regs, GP_REG_SIZE);
6937 + memcpy(regs->dc.b, par->dc_regs, DC_REG_SIZE);
6938 + memcpy(regs->vp.b, par->vid_regs, VP_REG_SIZE);
6939 + memcpy(regs->fp.b, par->vid_regs + 0x400, FP_REG_SIZE);
6941 + /* Save the palettes */
6942 + writel(0, par->dc_regs + 0x70);
6944 + for(i = 0; i < DC_PAL_SIZE; i++)
6945 + regs->pal[i] = readl(par->dc_regs + 0x74);
6947 + writel(0, par->vid_regs + 0x38);
6949 + for(i = 0; i < 0xFF; i++)
6950 + regs->gamma[i] = readl(par->vid_regs + 0x40);
6953 +void gx_restore_regs(struct fb_info *info, struct geoderegs *regs)
6955 + struct geodefb_par *par = info->par;
6959 + gx_set_dotpll(info, regs);
6963 + writel(regs->gp.r.dst_offset, par->gp_regs + 0x00);
6964 + writel(regs->gp.r.src_offset, par->gp_regs + 0x04);
6965 + writel(regs->gp.r.stride, par->gp_regs + 0x08);
6966 + writel(regs->gp.r.wid_height, par->gp_regs + 0x0C);
6967 + writel(regs->gp.r.src_color_fg, par->gp_regs + 0x10);
6968 + writel(regs->gp.r.src_color_bg, par->gp_regs + 0x14);
6969 + writel(regs->gp.r.pat_color_0, par->gp_regs + 0x18);
6970 + writel(regs->gp.r.pat_color_1, par->gp_regs + 0x1C);
6971 + writel(regs->gp.r.pat_color_2, par->gp_regs + 0x20);
6972 + writel(regs->gp.r.pat_color_3, par->gp_regs + 0x24);
6973 + writel(regs->gp.r.pat_color_4, par->gp_regs + 0x28);
6974 + writel(regs->gp.r.pat_color_5, par->gp_regs + 0x2C);
6975 + writel(regs->gp.r.pat_data_0, par->gp_regs + 0x30);
6976 + writel(regs->gp.r.pat_data_1, par->gp_regs + 0x34);
6978 + /* Don't write the raster / vector / blt mode regs */
6979 + /* status register is read only */
6981 + writel(regs->gp.r.hst_src, par->gp_regs + 0x48);
6982 + writel(regs->gp.r.base_offset, par->gp_regs + 0x4c);
6986 + /* Write the unlock value */
6987 + writel(0x4758, par->dc_regs + 0x00);
6989 + writel(0, par->dc_regs + 0x70);
6991 + for(i = 0; i < DC_PAL_SIZE; i++)
6992 + writel(regs->pal[i], par->dc_regs + 0x74);
6994 + /* Write the gcfg register without the enables */
6995 + writel(regs->dc.r.gcfg & ~0x0F, par->dc_regs + 0x04);
6997 + /* Write the vcfg register without the enables */
6998 + writel(regs->dc.r.dcfg & ~0x19, par->dc_regs + 0x08);
7000 + /* Write the rest of the active registers */
7002 + writel(regs->dc.r.fb_st_offset, par->dc_regs + 0x10);
7003 + writel(regs->dc.r.cb_st_offset, par->dc_regs + 0x14);
7004 + writel(regs->dc.r.curs_st_offset, par->dc_regs + 0x18);
7005 + writel(regs->dc.r.icon_st_offset, par->dc_regs + 0x1C);
7006 + writel(regs->dc.r.vid_y_st_offset, par->dc_regs + 0x20);
7007 + writel(regs->dc.r.vid_u_st_offset, par->dc_regs + 0x24);
7008 + writel(regs->dc.r.vid_v_st_offset, par->dc_regs + 0x28);
7009 + writel(regs->dc.r.line_size, par->dc_regs + 0x30);
7010 + writel(regs->dc.r.gfx_pitch, par->dc_regs + 0x34);
7011 + writel(regs->dc.r.vid_yuv_pitch, par->dc_regs + 0x38);
7012 + writel(regs->dc.r.h_active_timing, par->dc_regs + 0x40);
7013 + writel(regs->dc.r.h_blank_timing, par->dc_regs + 0x44);
7014 + writel(regs->dc.r.h_sync_timing, par->dc_regs + 0x48);
7015 + writel(regs->dc.r.v_active_timing, par->dc_regs + 0x50);
7016 + writel(regs->dc.r.v_blank_timing, par->dc_regs + 0x54);
7017 + writel(regs->dc.r.v_sync_timing, par->dc_regs + 0x58);
7018 + writel(regs->dc.r.dc_cursor_x, par->dc_regs + 0x60);
7019 + writel(regs->dc.r.dc_cursor_y, par->dc_regs + 0x64);
7020 + writel(regs->dc.r.dc_icon_x, par->dc_regs + 0x68);
7022 + /* Don't write the line_cnt or diag registers */
7024 + writel(regs->dc.r.dc_vid_ds_delta, par->dc_regs + 0x80);
7025 + writel(regs->dc.r.gliu0_mem_offset, par->dc_regs + 0x84);
7026 + writel(regs->dc.r.dv_acc, par->dc_regs + 0x8C);
7031 + wrmsrl(GX_VP_MSR_PAD_SELECT, regs->msr.padsel);
7033 + writel(0, par->vid_regs + 0x38);
7035 + for(i = 0; i < 0xFF; i++)
7036 + writel((u32) regs->gamma[i], par->vid_regs + 0x40);
7038 + /* Don't enable video yet */
7039 + writel((u32) regs->vp.r.vcfg & ~0x01, par->vid_regs + 0x00);
7041 + /* Don't enable the CRT yet */
7042 + writel((u32) regs->vp.r.dcfg & ~0x0F, par->vid_regs + 0x08);
7044 + /* Write the rest of the VP registers */
7046 + writel((u32) regs->vp.r.vx, par->vid_regs + 0x10);
7047 + writel((u32) regs->vp.r.vy, par->vid_regs + 0x18);
7048 + writel((u32) regs->vp.r.vs, par->vid_regs + 0x20);
7049 + writel((u32) regs->vp.r.vck, par->vid_regs + 0x28);
7050 + writel((u32) regs->vp.r.vcm, par->vid_regs + 0x30);
7051 + writel((u32) regs->vp.r.misc, par->vid_regs + 0x50);
7052 + writel((u32) regs->vp.r.ccs, par->vid_regs + 0x58);
7053 + writel((u32) regs->vp.r.vdc, par->vid_regs + 0x78);
7054 + writel((u32) regs->vp.r.vco, par->vid_regs + 0x80);
7055 + writel((u32) regs->vp.r.crc, par->vid_regs + 0x88);
7056 + writel((u32) regs->vp.r.vde, par->vid_regs + 0x98);
7057 + writel((u32) regs->vp.r.cck, par->vid_regs + 0xA0);
7058 + writel((u32) regs->vp.r.ccm, par->vid_regs + 0xA8);
7059 + writel((u32) regs->vp.r.cc1, par->vid_regs + 0xB0);
7060 + writel((u32) regs->vp.r.cc2, par->vid_regs + 0xB8);
7061 + writel((u32) regs->vp.r.a1x, par->vid_regs + 0xC0);
7062 + writel((u32) regs->vp.r.a1y, par->vid_regs + 0xC8);
7063 + writel((u32) regs->vp.r.a1c, par->vid_regs + 0xD0);
7064 + writel((u32) regs->vp.r.a1t, par->vid_regs + 0xD8);
7065 + writel((u32) regs->vp.r.a2x, par->vid_regs + 0xE0);
7066 + writel((u32) regs->vp.r.a2y, par->vid_regs + 0xE8);
7067 + writel((u32) regs->vp.r.a2c, par->vid_regs + 0xF0);
7068 + writel((u32) regs->vp.r.a2t, par->vid_regs + 0xF8);
7069 + writel((u32) regs->vp.r.a3x, par->vid_regs + 0x100);
7070 + writel((u32) regs->vp.r.a3y, par->vid_regs + 0x108);
7071 + writel((u32) regs->vp.r.a3c, par->vid_regs + 0x110);
7072 + writel((u32) regs->vp.r.a3t, par->vid_regs + 0x118);
7073 + writel((u32) regs->vp.r.vrr, par->vid_regs + 0x120);
7076 + /* FP registers */
7078 + writel((u32) regs->fp.r.pt1, par->vid_regs + 0x400);
7079 + writel((u32) regs->fp.r.pt2, par->vid_regs + 0x408);
7081 + writel((u32) regs->fp.r.dfc, par->vid_regs + 0x418);
7082 + writel(regs->fp.r.blfsr, par->vid_regs + 0x420);
7083 + writel(regs->fp.r.rlfsr, par->vid_regs + 0x428);
7084 + writel(regs->fp.r.fmi, par->vid_regs + 0x430);
7085 + writel(regs->fp.r.fmd, par->vid_regs + 0x438);
7086 + writel(regs->fp.r.dca, par->vid_regs + 0x448);
7087 + writel(regs->fp.r.dmd, par->vid_regs + 0x450);
7088 + writel(regs->fp.r.crc, par->vid_regs + 0x458);
7089 + writel(regs->fp.r.fbb, par->vid_regs + 0x460);
7091 + /* Final enables */
7093 + val = readl(par->vid_regs + 0x410);
7095 + /* Control the panel */
7096 + if (regs->fp.r.pm & (1 << 24)) {
7098 + if (!(val & 0x09))
7099 + writel(regs->fp.r.pm, par->vid_regs + 0x410);
7102 + if (!(val & 0x05))
7103 + writel(regs->fp.r.pm, par->vid_regs + 0x410);
7106 + /* Turn everything on */
7108 + writel(regs->dc.r.gcfg, par->dc_regs + 0x04);
7109 + writel((u32) regs->vp.r.vcfg, par->vid_regs + 0x00);
7110 + writel((u32) regs->vp.r.dcfg, par->vid_regs + 0x08);
7111 + writel(regs->dc.r.dcfg, par->dc_regs + 0x08);
7117 +void dump_regs(struct fb_info *info, int mode) {
7119 + struct geodefb_par *par = info->par;
7124 + for(i = 0; i < GP_REG_SIZE; i += 4) {
7125 + val = readl(par->gp_regs + i);
7130 + writel(0x4758, par->dc_regs + 0x00);
7132 + for(i = 0; i < DC_REG_SIZE; i += 4) {
7133 + val = readl(par->dc_regs + i);
7134 + printk("DC%x: %x\n", i, val);
7139 + for(i = 0; i < VP_REG_SIZE; i += 8) {
7140 + val = readl(par->vid_regs + i);
7141 + printk("VP%x: %x\n", i, val);
7146 + for(i = 0; i < FP_REG_SIZE; i += 8) {
7147 + val = readl(par->vid_regs + 0x400 + i);
7148 + printk("FP%x: %x\n", i, val);
7154 Index: linux-2.6.24.7/drivers/video/geode/video_gx.c
7155 ===================================================================
7156 --- linux-2.6.24.7.orig/drivers/video/geode/video_gx.c
7157 +++ linux-2.6.24.7/drivers/video/geode/video_gx.c
7160 #include <asm/delay.h>
7161 #include <asm/msr.h>
7162 +#include <asm/olpc.h>
7164 #include "geodefb.h"
7165 #include "video_gx.h"
7166 +#include "display_gx.h"
7168 +/* This structure is used to store the saved registers during suspend */
7169 +static struct geoderegs gx_saved_regs;
7172 * Tables of register settings for various DOTCLKs.
7173 @@ -58,7 +62,7 @@ static const struct gx_pll_entry gx_pll_
7174 { 13888, POSTDIV3, 0x000007E1 }, /* 72.0000 */
7175 { 13426, PREMULT2, 0x00000F4A }, /* 74.4810 */
7176 { 13333, 0, 0x00000052 }, /* 75.0000 */
7177 - { 12698, 0, 0x00000056 }, /* 78.7500 */
7178 + { 12698, 0, 0x00000056 }, /* 78.7500 */
7179 { 12500, POSTDIV3|PREMULT2, 0x00000709 }, /* 80.0000 */
7180 { 11135, PREMULT2, 0x00000262 }, /* 89.8000 */
7181 { 10582, 0, 0x000002D2 }, /* 94.5000 */
7182 @@ -117,8 +121,9 @@ static const struct gx_pll_entry gx_pll_
7183 { 4357, 0, 0x0000057D }, /* 229.5000 */
7186 -static void gx_set_dclk_frequency(struct fb_info *info)
7187 +void gx_set_dclk_frequency(struct fb_info *info)
7189 + struct geodefb_par *par = info->par;
7190 const struct gx_pll_entry *pll_table;
7193 @@ -173,115 +178,169 @@ static void gx_set_dclk_frequency(struct
7195 rdmsrl(MSR_GLCP_DOTPLL, dotpll);
7196 } while (timeout-- && !(dotpll & MSR_GLCP_DOTPLL_LOCK));
7198 + par->curdclk = pll_table[best_i].dotpll_value;
7202 -gx_configure_tft(struct fb_info *info)
7203 +/* Find out the current clock - we will use this information to avoid
7204 + re-programming it if we don't need to */
7206 +unsigned int gx_get_dclk(struct fb_info *info)
7208 - struct geodefb_par *par = info->par;
7209 - unsigned long val;
7211 + const struct gx_pll_entry *pll_table;
7212 + int pll_table_len;
7216 - /* Set up the DF pad select MSR */
7217 + if (cpu_data(0).x86_mask == 1) {
7218 + pll_table = gx_pll_table_14MHz;
7219 + pll_table_len = ARRAY_SIZE(gx_pll_table_14MHz);
7221 + pll_table = gx_pll_table_48MHz;
7222 + pll_table_len = ARRAY_SIZE(gx_pll_table_48MHz);
7225 - rdmsrl(GX_VP_MSR_PAD_SELECT, val);
7226 - val &= ~GX_VP_PAD_SELECT_MASK;
7227 - val |= GX_VP_PAD_SELECT_TFT;
7228 - wrmsrl(GX_VP_MSR_PAD_SELECT, val);
7229 + rdmsrl(MSR_GLCP_DOTPLL, dotpll);
7231 - /* Turn off the panel */
7232 + for(i = 0; i < pll_table_len; i++) {
7233 + if (pll_table[i].dotpll_value == (u32) (dotpll >> 32))
7237 + return (i == pll_table_len) ? 0 : pll_table[i].pixclock;
7240 - fp = readl(par->vid_regs + GX_FP_PM);
7241 - fp &= ~GX_FP_PM_P;
7242 - writel(fp, par->vid_regs + GX_FP_PM);
7244 - /* Set timing 1 */
7245 +#define CMP(val, mask, res) (((val) & (mask)) == (res))
7247 - fp = readl(par->vid_regs + GX_FP_PT1);
7248 - fp &= GX_FP_PT1_VSIZE_MASK;
7249 - fp |= info->var.yres << GX_FP_PT1_VSIZE_SHIFT;
7250 - writel(fp, par->vid_regs + GX_FP_PT1);
7252 +gx_configure_tft(struct fb_info *info) {
7255 - /* Set bits that are always on for TFT */
7256 + struct geodefb_par *par = info->par;
7257 + u32 val, fp = 0, fp1, fp2, sync = 0;
7260 + /* Set up the DF pad select MSR */
7262 - /* Add sync polarity */
7263 + rdmsrl(GX_VP_MSR_PAD_SELECT, val);
7265 + if ((val & GX_VP_PAD_SELECT_MASK) != GX_VP_PAD_SELECT_TFT) {
7266 + val &= ~GX_VP_PAD_SELECT_MASK;
7267 + val |= GX_VP_PAD_SELECT_TFT;
7268 + wrmsrl(GX_VP_MSR_PAD_SELECT, val);
7271 if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
7272 - fp |= GX_FP_PT2_VSP;
7273 + sync |= GX_FP_PT2_VSP;
7275 if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
7276 - fp |= GX_FP_PT2_HSP;
7277 + sync |= GX_FP_PT2_HSP;
7279 - writel(fp, par->vid_regs + GX_FP_PT2);
7280 + /* We only need to turn off the panel if something changed */
7282 - /* Set the dither control */
7283 - writel(0x70, par->vid_regs + GX_FP_DFC);
7284 + fp1 = readl(par->vid_regs + GX_FP_PT1);
7285 + fp2 = readl(par->vid_regs + GX_FP_PT2);
7287 + if (!CMP(fp1, GX_FP_PT1_VSIZE_MASK, info->var.yres << GX_FP_PT1_VSIZE_SHIFT) ||
7288 + (fp2 != (0x0F100000 | sync))) {
7290 + /* Turn off the panel */
7293 + /* Do we really need to turn off the panel? */
7294 + /* Possibly - we have a glitch somewhere */
7296 - /* Enable the FP data and power (in case the BIOS didn't) */
7297 + fp = readl(par->vid_regs + GX_FP_PM);
7298 + fp &= ~GX_FP_PM_P;
7299 + writel(fp, par->vid_regs + GX_FP_PM);
7302 - fp = readl(par->vid_regs + GX_DCFG);
7303 - fp |= GX_DCFG_FP_PWR_EN | GX_DCFG_FP_DATA_EN;
7304 - writel(fp, par->vid_regs + GX_DCFG);
7306 + fp1 &= GX_FP_PT1_VSIZE_MASK;
7307 + fp1 |= info->var.yres << GX_FP_PT1_VSIZE_SHIFT;
7308 + writel(fp, par->vid_regs + GX_FP_PT1);
7310 - /* Unblank the panel */
7312 + writel(0x0F100000 | sync, par->vid_regs + GX_FP_PT2);
7315 + /* Set the dither control */
7316 + if (readl(par->vid_regs + GX_FP_DFC) != 0x70) {
7317 + writel(0x70, par->vid_regs + GX_FP_DFC);
7320 + /* Turn on the panel */
7322 fp = readl(par->vid_regs + GX_FP_PM);
7324 - writel(fp, par->vid_regs + GX_FP_PM);
7327 + writel(fp | GX_FP_PM_P, par->vid_regs + GX_FP_PM);
7330 +#define DCFG_DEFAULT_VAL GX_DCFG_CRT_SYNC_SKW_DFLT | GX_DCFG_HSYNC_EN | GX_DCFG_VSYNC_EN | \
7331 +GX_DCFG_CRT_EN | GX_DCFG_DAC_BL_EN
7333 static void gx_configure_display(struct fb_info *info)
7335 struct geodefb_par *par = info->par;
7337 + u32 dcfg, misc, sync = 0;
7339 /* Set up the MISC register */
7341 misc = readl(par->vid_regs + GX_MISC);
7343 - /* Power up the DAC */
7344 - misc &= ~(GX_MISC_A_PWRDN | GX_MISC_DAC_PWRDN);
7345 + /* We leave gamma enabled if it was already enabled.
7346 + Although the hardware enables it without setting
7347 + up the gamma table, the BIOS or bootloader ought
7348 + to have either disabled it or loaded a table by now */
7350 - /* Disable gamma correction */
7351 - misc |= GX_MISC_GAM_EN;
7353 - writel(misc, par->vid_regs + GX_MISC);
7355 - /* Write the display configuration */
7356 - dcfg = readl(par->vid_regs + GX_DCFG);
7357 + if (par->enable_crt) {
7358 + /* Power up the CRT DACs */
7359 + if (misc & ( GX_MISC_A_PWRDN | GX_MISC_DAC_PWRDN)) {
7360 + misc &= ~(GX_MISC_A_PWRDN | GX_MISC_DAC_PWRDN);
7361 + writel(misc, par->vid_regs + GX_MISC);
7364 - /* Disable hsync and vsync */
7365 - dcfg &= ~(GX_DCFG_VSYNC_EN | GX_DCFG_HSYNC_EN);
7366 - writel(dcfg, par->vid_regs + GX_DCFG);
7367 + if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
7368 + sync |= GX_DCFG_CRT_HSYNC_POL;
7370 - /* Clear bits from existing mode. */
7371 - dcfg &= ~(GX_DCFG_CRT_SYNC_SKW_MASK
7372 - | GX_DCFG_CRT_HSYNC_POL | GX_DCFG_CRT_VSYNC_POL
7373 - | GX_DCFG_VSYNC_EN | GX_DCFG_HSYNC_EN);
7374 + if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
7375 + sync |= GX_DCFG_CRT_VSYNC_POL;
7378 + /* Turn off the CRT DACs in FP mode - we don't need them */
7379 + if ((misc & (GX_MISC_A_PWRDN | GX_MISC_DAC_PWRDN))) {
7380 + misc |= (GX_MISC_A_PWRDN | GX_MISC_DAC_PWRDN);
7381 + writel(misc, par->vid_regs + GX_MISC);
7385 - /* Set default sync skew. */
7386 - dcfg |= GX_DCFG_CRT_SYNC_SKW_DFLT;
7387 + /* Write the display configuration */
7388 + dcfg = readl(par->vid_regs + GX_DCFG);
7390 - /* Enable hsync and vsync. */
7391 - dcfg |= GX_DCFG_HSYNC_EN | GX_DCFG_VSYNC_EN;
7392 + if (!CMP(dcfg, DCFG_DEFAULT_VAL | GX_DCFG_CRT_HSYNC_POL | GX_DCFG_CRT_VSYNC_POL,
7393 + DCFG_DEFAULT_VAL | sync)) {
7395 - /* Sync polarities. */
7396 - if (info->var.sync & FB_SYNC_HOR_HIGH_ACT)
7397 - dcfg |= GX_DCFG_CRT_HSYNC_POL;
7398 - if (info->var.sync & FB_SYNC_VERT_HIGH_ACT)
7399 - dcfg |= GX_DCFG_CRT_VSYNC_POL;
7400 + /* Disable hsync and vsync */
7401 + dcfg &= ~(GX_DCFG_VSYNC_EN | GX_DCFG_HSYNC_EN);
7402 + writel(dcfg, par->vid_regs + GX_DCFG);
7404 - /* Enable the display logic */
7405 - /* Set up the DACS to blank normally */
7406 + /* Clear bits from existing mode. */
7407 + dcfg &= ~(GX_DCFG_CRT_SYNC_SKW_MASK
7408 + | GX_DCFG_CRT_HSYNC_POL | GX_DCFG_CRT_VSYNC_POL
7409 + | GX_DCFG_VSYNC_EN | GX_DCFG_HSYNC_EN);
7411 - dcfg |= GX_DCFG_CRT_EN | GX_DCFG_DAC_BL_EN;
7412 + /* Set default sync skew. */
7413 + dcfg |= GX_DCFG_CRT_SYNC_SKW_DFLT;
7415 - /* Enable the external DAC VREF? */
7416 + /* Enable hsync and vsync. */
7417 + dcfg |= GX_DCFG_HSYNC_EN | GX_DCFG_VSYNC_EN;
7419 - writel(dcfg, par->vid_regs + GX_DCFG);
7420 + /* Enable the display logic */
7421 + dcfg |= GX_DCFG_CRT_EN | GX_DCFG_DAC_BL_EN;
7423 + writel(dcfg, par->vid_regs + GX_DCFG);
7426 /* Set up the flat panel (if it is enabled) */
7428 @@ -289,6 +348,100 @@ static void gx_configure_display(struct
7429 gx_configure_tft(info);
7432 +int gxfb_powerdown(struct fb_info *info)
7434 + struct geodefb_par *par = info->par;
7436 + /* We're already suspended */
7438 + if (par->state != FB_POWER_STATE_ON)
7441 + /* Save the registers */
7442 + gx_save_regs(info, &gx_saved_regs);
7444 + /* Shut down the engine */
7446 + writel(gx_saved_regs.vp.r.vcfg & ~0x01, par->vid_regs + GX_VCFG);
7447 + writel(gx_saved_regs.vp.r.dcfg & ~0x0F, par->vid_regs + GX_DCFG);
7449 + /* Turn off the flat panel unless we are attached to a DCON */
7450 + if (!olpc_has_dcon())
7451 + writel(gx_saved_regs.fp.r.pm & ~GX_FP_PM_P, par->vid_regs + GX_FP_PM);
7453 + writel(0x4758, par->dc_regs + DC_UNLOCK);
7455 + writel(gx_saved_regs.dc.r.gcfg & ~0x0F,
7456 + par->dc_regs + DC_GENERAL_CFG);
7458 + writel(gx_saved_regs.dc.r.dcfg & ~0x19,
7459 + par->dc_regs + DC_DISPLAY_CFG);
7461 + par->state = FB_POWER_STATE_SUSPEND;
7466 +int gxfb_powerup(struct fb_info *info)
7468 + struct geodefb_par *par = info->par;
7471 + if (par->state == FB_POWER_STATE_SUSPEND) {
7473 + writel(gx_saved_regs.dc.r.dcfg,
7474 + par->dc_regs + DC_DISPLAY_CFG);
7476 + writel(gx_saved_regs.vp.r.vcfg, par->vid_regs + GX_VCFG);
7477 + writel(gx_saved_regs.vp.r.dcfg, par->vid_regs + GX_DCFG);
7479 + val = readl(par->vid_regs + GX_FP_PM);
7481 + /* power up the panel if it needs it; we don't always power it down */
7482 + if (!(val & 0x09)) {
7483 + writel(gx_saved_regs.fp.r.pm, par->vid_regs + GX_FP_PM);
7488 + /* If the panel is currently on its way up, then wait up to 100ms
7491 + if (readl(par->vid_regs + GX_FP_PM) & 0x08) {
7494 + for(i = 0; i < 10; i++) {
7495 + if (readl(par->vid_regs + GX_FP_PM) & 0x01)
7502 + printk(KERN_ERR "gxfb: Panel power up timed out\n");
7505 + if (par->state == FB_POWER_STATE_ON)
7508 + switch(par->state) {
7509 + case FB_POWER_STATE_OFF:
7510 + gx_restore_regs(info, &gx_saved_regs);
7513 + case FB_POWER_STATE_SUSPEND:
7514 + /* Do this because it will turn on the FIFO which will
7515 + start the line count */
7516 + writel(gx_saved_regs.dc.r.gcfg,
7517 + par->dc_regs + DC_GENERAL_CFG);
7518 + writel(0x0, par->dc_regs + DC_UNLOCK);
7522 + par->state = FB_POWER_STATE_ON;
7526 static int gx_blank_display(struct fb_info *info, int blank_mode)
7528 struct geodefb_par *par = info->par;
7529 @@ -315,6 +468,7 @@ static int gx_blank_display(struct fb_in
7534 dcfg = readl(par->vid_regs + GX_DCFG);
7535 dcfg &= ~(GX_DCFG_DAC_BL_EN
7536 | GX_DCFG_HSYNC_EN | GX_DCFG_VSYNC_EN);
7537 @@ -326,7 +480,7 @@ static int gx_blank_display(struct fb_in
7538 dcfg |= GX_DCFG_VSYNC_EN;
7539 writel(dcfg, par->vid_regs + GX_DCFG);
7541 - /* Power on/off flat panel. */
7542 + /* Power on/off flat panel */
7544 if (par->enable_crt == 0) {
7545 fp_pm = readl(par->vid_regs + GX_FP_PM);
7546 @@ -340,8 +494,37 @@ static int gx_blank_display(struct fb_in
7550 +extern struct fb_info *gxfb_info;
7552 +/* This function controls the flatpanel power sequencing - this is used
7553 + by the OLPC power management engine to enable the FP sequencing much
7554 + earlier in the resume process
7557 +void gxfb_flatpanel_control(int state)
7559 + struct geodefb_par *par = gxfb_info->par;
7560 + u32 val, fp = readl(par->vid_regs + GX_FP_PM);
7563 + /* Turn on the panel if it isn't aleady */
7566 + if (!(val & 0x01))
7567 + val |= GX_FP_PM_P;
7570 + if (!(val & 0x02))
7571 + val &= ~GX_FP_PM_P;
7575 + writel(val, par->vid_regs + GX_FP_PM);
7578 struct geode_vid_ops gx_vid_ops = {
7579 .set_dclk = gx_set_dclk_frequency,
7580 + .get_dclk = gx_get_dclk,
7581 .configure_display = gx_configure_display,
7582 .blank_display = gx_blank_display,
7584 Index: linux-2.6.24.7/drivers/video/geode/video_gx.h
7585 ===================================================================
7586 --- linux-2.6.24.7.orig/drivers/video/geode/video_gx.h
7587 +++ linux-2.6.24.7/drivers/video/geode/video_gx.h
7589 #ifndef __VIDEO_GX_H__
7590 #define __VIDEO_GX_H__
7592 +#include "geode_regs.h"
7594 extern struct geode_vid_ops gx_vid_ops;
7596 /* GX Flatpanel control MSR */
7597 @@ -20,6 +22,8 @@ extern struct geode_vid_ops gx_vid_ops;
7599 /* Geode GX video processor registers */
7601 +#define GX_VCFG 0x0000
7603 #define GX_DCFG 0x0008
7604 # define GX_DCFG_CRT_EN 0x00000001
7605 # define GX_DCFG_HSYNC_EN 0x00000002
7606 @@ -42,6 +46,14 @@ extern struct geode_vid_ops gx_vid_ops;
7607 #define GX_MISC_DAC_PWRDN 0x00000400
7608 #define GX_MISC_A_PWRDN 0x00000800
7610 +/* Gamma correction RAM - address and data registers */
7612 +#define GX_GAR 0x038
7613 +#define GX_GDR 0x040
7615 +#define GXFB_GAMMA_DWORDS 256 /* number of dwords in the gamma ram */
7616 +#define GXFB_GAMMA_SIZE (GXFB_GAMMA_DWORDS * sizeof(unsigned int))
7618 /* Geode GX flat panel display control registers */
7620 #define GX_FP_PT1 0x0400
7621 @@ -69,4 +81,13 @@ extern struct geode_vid_ops gx_vid_ops;
7622 # define MSR_GLCP_DOTPLL_BYPASS (0x0000000000008000ull)
7623 # define MSR_GLCP_DOTPLL_LOCK (0x0000000002000000ull)
7625 +int gxfb_powerdown(struct fb_info *info);
7626 +int gxfb_powerup(struct fb_info *info);
7628 +void gx_set_dclk_frequency(struct fb_info *info);
7629 +unsigned int gx_get_dclk(struct fb_info *info);
7631 +void gx_save_regs(struct fb_info *info, struct geoderegs *regs);
7632 +void gx_restore_regs(struct fb_info *info, struct geoderegs *regs);
7634 #endif /* !__VIDEO_GX_H__ */
7635 Index: linux-2.6.24.7/drivers/video/Kconfig
7636 ===================================================================
7637 --- linux-2.6.24.7.orig/drivers/video/Kconfig
7638 +++ linux-2.6.24.7/drivers/video/Kconfig
7639 @@ -1869,6 +1869,15 @@ config FB_PS3_DEFAULT_SIZE_M
7640 The default value can be overridden on the kernel command line
7641 using the "ps3fb" option (e.g. "ps3fb=9M");
7643 +config FB_OLPC_DCON
7644 + tristate "One Laptop Per Child Display CONtroller support"
7648 + Add support for the OLPC DCON controller. This controller is only
7649 + available on OLPC platforms. Unless you have one of these
7650 + platforms, you will want to say 'N'.
7653 tristate "Xilinx frame buffer support"
7654 depends on FB && XILINX_VIRTEX
7655 Index: linux-2.6.24.7/drivers/video/Makefile
7656 ===================================================================
7657 --- linux-2.6.24.7.orig/drivers/video/Makefile
7658 +++ linux-2.6.24.7/drivers/video/Makefile
7659 @@ -111,6 +111,7 @@ obj-$(CONFIG_FB_PNX4008_DUM_RGB) += pnx
7660 obj-$(CONFIG_FB_IBM_GXT4500) += gxt4500.o
7661 obj-$(CONFIG_FB_PS3) += ps3fb.o
7662 obj-$(CONFIG_FB_SM501) += sm501fb.o
7663 +obj-$(CONFIG_FB_OLPC_DCON) += olpc_dcon.o
7664 obj-$(CONFIG_FB_XILINX) += xilinxfb.o
7665 obj-$(CONFIG_FB_OMAP) += omap/
7667 Index: linux-2.6.24.7/drivers/video/modedb.c
7668 ===================================================================
7669 --- linux-2.6.24.7.orig/drivers/video/modedb.c
7670 +++ linux-2.6.24.7/drivers/video/modedb.c
7671 @@ -33,6 +33,8 @@ const char *fb_mode_option;
7672 * Standard video mode definitions (taken from XFree86)
7675 +#define DEFAULT_MODEDB_INDEX 0
7677 static const struct fb_videomode modedb[] = {
7679 /* 640x400 @ 70 Hz, 31.5 kHz hsync */
7680 @@ -508,7 +510,8 @@ int fb_find_mode(struct fb_var_screeninf
7684 - default_mode = &db[0];
7685 + default_mode = (db == modedb) ?
7686 + &modedb[DEFAULT_MODEDB_INDEX] : &db[0];
7690 Index: linux-2.6.24.7/drivers/video/olpc_dcon.c
7691 ===================================================================
7693 +++ linux-2.6.24.7/drivers/video/olpc_dcon.c
7696 + * Mainly by David Woodhouse, somewhat modified by Jordan Crouse
7698 + * Copyright © 2006-2007 Red Hat, Inc.
7699 + * Copyright © 2006-2007 Advanced Micro Devices, Inc.
7701 + * This program is free software. You can redistribute it and/or
7702 + * modify it under the terms of version 2 of the GNU General Public
7703 + * License as published by the Free Software Foundation.
7707 +#include <linux/kernel.h>
7708 +#include <linux/fb.h>
7709 +#include <linux/console.h>
7710 +#include <linux/i2c.h>
7711 +#include <linux/platform_device.h>
7712 +#include <linux/i2c-id.h>
7713 +#include <linux/pci.h>
7714 +#include <linux/vt_kern.h>
7715 +#include <linux/pci_ids.h>
7716 +#include <linux/interrupt.h>
7717 +#include <linux/delay.h>
7718 +#include <linux/backlight.h>
7719 +#include <linux/device.h>
7720 +#include <linux/notifier.h>
7721 +#include <asm/uaccess.h>
7722 +#include <linux/ctype.h>
7723 +#include <linux/reboot.h>
7724 +#include <asm/tsc.h>
7725 +#include <asm/olpc.h>
7726 +#include <asm/geode.h>
7728 +#include "olpc_dcon.h"
7730 +/* Module definitions */
7732 +static int resumeline = 898;
7733 +module_param(resumeline, int, 0444);
7736 +module_param(noinit, int, 0444);
7738 +/* Default off since it doesn't work on DCON ASIC in B-test OLPC board */
7739 +static int useaa = 1;
7740 +module_param(useaa, int, 0444);
7742 +/* I2C structures */
7744 +static struct i2c_driver dcon_driver;
7745 +static struct i2c_client *dcon_client;
7747 +/* Platform devices */
7748 +static struct platform_device *dcon_device;
7750 +/* Backlight device */
7751 +static struct backlight_device *dcon_bl_dev;
7753 +/* Base address of the GPIO registers */
7754 +static unsigned long gpio_base;
7756 +static struct fb_info *fbinfo;
7758 +/* Current source, initialized at probe time */
7759 +static int dcon_source;
7761 +/* Desired source */
7762 +static int dcon_pending;
7764 +/* Current output type */
7765 +static int dcon_output = DCON_OUTPUT_COLOR;
7767 +/* Current sleep status (not yet implemented) */
7768 +static int dcon_sleep_val = DCON_ACTIVE;
7770 +/* Shadow register for the DCON_REG_MODE register */
7771 +static unsigned short dcon_disp_mode;
7773 +/* Variables used during switches */
7774 +static int dcon_switched;
7776 +static DECLARE_WAIT_QUEUE_HEAD(dcon_wait_queue);
7778 +static unsigned short normal_i2c[] = { 0x0D, I2C_CLIENT_END };
7781 +#define dcon_write(reg,val) i2c_smbus_write_word_data(dcon_client,reg,val)
7782 +#define dcon_read(reg) i2c_smbus_read_word_data(dcon_client,reg)
7784 +/* The current backlight value - this saves us some smbus traffic */
7785 +static int bl_val = -1;
7787 +/* ===== API functions - these are called by a variety of users ==== */
7789 +static int dcon_request_irq(void);
7791 +static int dcon_hw_init(struct i2c_client *client, int is_init)
7796 + ver = i2c_smbus_read_word_data(client, DCON_REG_ID);
7797 + if ((ver >> 8) != 0xDC) {
7798 + printk(KERN_ERR "olpc-dcon: DCON ID not 0xDCxx: 0x%04x "
7799 + "instead.\n", ver);
7805 + printk(KERN_INFO "olpc-dcon: Discovered DCON version %x\n",
7807 + if ((rc = dcon_request_irq())) {
7808 + printk(KERN_ERR "olpc-dcon: Unable to grab IRQ.\n");
7813 + if (ver < 0xdc02 && !noinit) {
7814 + /* Initialize the DCON registers */
7816 + /* Start with work-arounds for DCON ASIC */
7817 + i2c_smbus_write_word_data(client, 0x4b, 0x00cc);
7818 + i2c_smbus_write_word_data(client, 0x4b, 0x00cc);
7819 + i2c_smbus_write_word_data(client, 0x4b, 0x00cc);
7820 + i2c_smbus_write_word_data(client, 0x0b, 0x007a);
7821 + i2c_smbus_write_word_data(client, 0x36, 0x025c);
7822 + i2c_smbus_write_word_data(client, 0x37, 0x025e);
7824 + /* Initialise SDRAM */
7826 + i2c_smbus_write_word_data(client, 0x3b, 0x002b);
7827 + i2c_smbus_write_word_data(client, 0x41, 0x0101);
7828 + i2c_smbus_write_word_data(client, 0x42, 0x0101);
7830 + else if (!noinit) {
7831 + /* SDRAM setup/hold time */
7832 + i2c_smbus_write_word_data(client, 0x3a, 0xc040);
7833 + i2c_smbus_write_word_data(client, 0x41, 0x0000);
7834 + i2c_smbus_write_word_data(client, 0x41, 0x0101);
7835 + i2c_smbus_write_word_data(client, 0x42, 0x0101);
7838 + /* Colour swizzle, AA, no passthrough, backlight */
7840 + dcon_disp_mode = MODE_PASSTHRU | MODE_BL_ENABLE | MODE_CSWIZZLE;
7842 + dcon_disp_mode |= MODE_COL_AA;
7844 + i2c_smbus_write_word_data(client, DCON_REG_MODE, dcon_disp_mode);
7847 + /* Set the scanline to interrupt on during resume */
7849 + i2c_smbus_write_word_data(client, DCON_REG_SCAN_INT, resumeline);
7856 + * The smbus doesn't always come back due to what is believed to be
7857 + * hardware (power rail) bugs. For older models where this is known to
7858 + * occur, our solution is to attempt to wait for the bus to stabilize;
7859 + * if it doesn't happen, cut power to the dcon, repower it, and wait
7860 + * for the bus to stabilize. Rinse, repeat until we have a working
7861 + * smbus. For newer models, we simply BUG(); we want to know if this
7862 + * still happens despite the power fixes that have been made!
7864 +static int dcon_bus_stabilize(struct i2c_client *client, int is_powered_down)
7866 + unsigned long timeout;
7870 + if (is_powered_down) {
7872 + if ((x = olpc_ec_cmd(0x26, (unsigned char *) &x, 1, NULL, 0))) {
7873 + printk(KERN_WARNING "olpc-dcon: unable to force dcon "
7874 + "to power up: %d!\n", x);
7877 + msleep(10); /* we'll be conservative */
7881 + * According to HiMax, when powering the DCON up we should hold
7882 + * SMB_DATA high for 8 SMB_CLK cycles. This will force the DCON
7883 + * state machine to reset to a (sane) initial state. Mitch Bradley
7884 + * did some testing and discovered that holding for 16 SMB_CLK cycles
7885 + * worked a lot more reliably, so that's what we do here.
7887 + * According to the cs5536 spec, to set GPIO14 to SMB_CLK we must
7888 + * simultaneously set AUX1 IN/OUT to GPIO14; ditto for SMB_DATA and
7891 + geode_gpio_set(OLPC_GPIO_SMB_CLK|OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_VAL);
7892 + geode_gpio_set(OLPC_GPIO_SMB_CLK|OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_ENABLE);
7893 + geode_gpio_clear(OLPC_GPIO_SMB_CLK|OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_AUX1);
7894 + geode_gpio_clear(OLPC_GPIO_SMB_CLK|OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_AUX2);
7895 + geode_gpio_clear(OLPC_GPIO_SMB_CLK|OLPC_GPIO_SMB_DATA, GPIO_INPUT_AUX1);
7897 + for (x = 0; x < 16; x++) {
7899 + geode_gpio_clear(OLPC_GPIO_SMB_CLK, GPIO_OUTPUT_VAL);
7901 + geode_gpio_set(OLPC_GPIO_SMB_CLK, GPIO_OUTPUT_VAL);
7904 + geode_gpio_set(OLPC_GPIO_SMB_CLK|OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_AUX1);
7905 + geode_gpio_set(OLPC_GPIO_SMB_CLK|OLPC_GPIO_SMB_DATA, GPIO_INPUT_AUX1);
7907 + for (x = -1, timeout = 50; timeout && x < 0; timeout--) {
7909 + x = dcon_read(DCON_REG_ID);
7912 + printk(KERN_ERR "olpc-dcon: unable to stabilize dcon's "
7913 + "smbus, reasserting power and praying.\n");
7914 + BUG_ON(olpc_board_at_least(olpc_board(0xc2)));
7916 + olpc_ec_cmd(0x26, (unsigned char *) &x, 1, NULL, 0);
7918 + is_powered_down = 1;
7919 + goto power_up; /* argh, stupid hardware.. */
7922 + if (is_powered_down)
7923 + return dcon_hw_init(client, 0);
7928 +/* Backlight notes - turning off the backlight enable bit in the DCON
7929 + * doesn't save us any power over just pushing the BL to zero, so we
7930 + * don't use that bit in this code.
7933 +static int dcon_get_backlight(void)
7935 + if (dcon_client == NULL)
7939 + bl_val = dcon_read(DCON_REG_BRIGHT) & 0x0F;
7944 +static void dcon_set_backlight(int level)
7946 + if (dcon_client == NULL)
7949 + if (bl_val == (level & 0x0F))
7952 + bl_val = level & 0x0F;
7953 + dcon_write(DCON_REG_BRIGHT, bl_val);
7955 + /* Purposely turn off the backlight when we go to level 0 */
7957 + if (bl_val == 0) {
7958 + dcon_disp_mode &= ~MODE_BL_ENABLE;
7959 + dcon_write(DCON_REG_MODE, dcon_disp_mode);
7961 + else if (!(dcon_disp_mode & MODE_BL_ENABLE)) {
7962 + dcon_disp_mode |= MODE_BL_ENABLE;
7963 + dcon_write(DCON_REG_MODE, dcon_disp_mode);
7967 +/* Set the output type to either color or mono */
7969 +static int dcon_set_output(int arg)
7971 + if (dcon_output == arg)
7974 + dcon_output = arg;
7976 + if (arg == DCON_OUTPUT_MONO) {
7977 + dcon_disp_mode &= ~(MODE_CSWIZZLE | MODE_COL_AA);
7978 + dcon_disp_mode |= MODE_MONO_LUMA;
7981 + dcon_disp_mode &= ~(MODE_MONO_LUMA);
7982 + dcon_disp_mode |= MODE_CSWIZZLE;
7984 + dcon_disp_mode |= MODE_COL_AA;
7987 + dcon_write(DCON_REG_MODE, dcon_disp_mode);
7991 +/* For now, this will be really stupid - we need to address how
7992 + * DCONLOAD works in a sleep and account for it accordingly
7995 +static void dcon_sleep(int state)
7999 + /* Turn off the backlight and put the DCON to sleep */
8001 + if (state == dcon_sleep_val)
8004 + if (!olpc_board_at_least(olpc_board(0xc2)))
8007 + if (state == DCON_SLEEP) {
8009 + if ((x = olpc_ec_cmd(0x26, (unsigned char *) &x, 1, NULL, 0)))
8010 + printk(KERN_WARNING "olpc-dcon: unable to force dcon "
8011 + "to power down: %d!\n", x);
8013 + dcon_sleep_val = state;
8016 + /* Only re-enable the backlight if the backlight value is set */
8018 + dcon_disp_mode |= MODE_BL_ENABLE;
8020 + if ((x=dcon_bus_stabilize(dcon_client, 1)))
8021 + printk(KERN_WARNING "olpc-dcon: unable to reinit dcon"
8022 + " hardware: %d!\n", x);
8024 + dcon_sleep_val = state;
8027 + /* We should turn off some stuff in the framebuffer - but what? */
8030 +/* Set the source of the display (CPU or DCON) */
8032 +static void dcon_source_switch(struct work_struct *work)
8034 + DECLARE_WAITQUEUE(wait, current);
8035 + int source = dcon_pending;
8037 + if (dcon_source == source)
8040 + dcon_switched = 0;
8043 + case DCON_SOURCE_CPU:
8045 + /* Enable the scanline interrupt bit */
8046 + if (dcon_write(DCON_REG_MODE, dcon_disp_mode | MODE_SCAN_INT))
8047 + printk(KERN_ERR "olpc-dcon: couldn't enable scanline interrupt!\n");
8049 + /* Wait up to one second for the scanline interrupt */
8050 + wait_event_timeout(dcon_wait_queue, dcon_switched == 1, HZ);
8053 + if (!dcon_switched)
8054 + printk(KERN_ERR "olpc-dcon: Timeout entering CPU mode; expect a screen glitch.\n");
8057 + * Ideally we'd like to disable interrupts here so that the
8058 + * fb unblanking and DCON turn on happen at a known time value;
8059 + * however, we can't do that right now with fb_blank
8060 + * messing with semaphores.
8062 + * For now, we just hope..
8064 + acquire_console_sem();
8065 + if (fb_blank(fbinfo, FB_BLANK_UNBLANK)) {
8066 + release_console_sem();
8067 + printk(KERN_ERR "olpc-dcon: Failed to enter CPU mode\n");
8068 + dcon_pending = DCON_SOURCE_DCON;
8071 + release_console_sem();
8073 + /* And turn off the DCON */
8074 + outl(1<<11, gpio_base + GPIOx_OUT_VAL);
8076 + /* Turn off the scanline interrupt */
8077 + if (dcon_write(DCON_REG_MODE, dcon_disp_mode))
8078 + printk(KERN_ERR "olpc-dcon: couldn't disable scanline interrupt!\n");
8080 + printk(KERN_INFO "olpc-dcon: The CPU has control\n");
8082 + case DCON_SOURCE_DCON:
8086 + add_wait_queue(&dcon_wait_queue, &wait);
8087 + set_current_state(TASK_UNINTERRUPTIBLE);
8089 + /* Clear GPIO11 (DCONLOAD) - this implies that the DCON is in
8092 + outl(1 << (11 + 16), gpio_base + GPIOx_OUT_VAL);
8094 + t = schedule_timeout(HZ/2);
8095 + remove_wait_queue(&dcon_wait_queue, &wait);
8096 + set_current_state(TASK_RUNNING);
8098 + if (!dcon_switched)
8099 + printk(KERN_ERR "olpc-dcon: Timeout entering DCON mode; expect a screen glitch.\n");
8101 + acquire_console_sem();
8102 + if (fb_blank(fbinfo, FB_BLANK_POWERDOWN))
8103 + printk(KERN_ERR "olpc-dcon: couldn't blank fb!\n");
8104 + release_console_sem();
8106 + printk(KERN_INFO "olpc-dcon: The DCON has control\n");
8113 + dcon_source = source;
8116 +static DECLARE_WORK(dcon_work, dcon_source_switch);
8118 +static int dcon_set_source(int arg)
8120 + if (arg != DCON_SOURCE_CPU && arg != DCON_SOURCE_DCON)
8123 + if (dcon_pending == arg)
8126 + dcon_pending = arg;
8127 + if ((dcon_source != arg) && !work_pending(&dcon_work))
8128 + schedule_work(&dcon_work);
8133 +static int dcon_set_source_sync(int arg)
8135 + int ret = dcon_set_source(arg);
8137 + flush_scheduled_work();
8141 +static int dconbl_set(struct backlight_device *dev) {
8143 + int level = dev->props.brightness;
8145 + if (dev->props.power != FB_BLANK_UNBLANK)
8148 + dcon_set_backlight(level);
8152 +static int dconbl_get(struct backlight_device *dev) {
8153 + return dcon_get_backlight();
8156 +static ssize_t dcon_mode_show(struct device *dev,
8157 + struct device_attribute *attr, char *buf)
8159 + return sprintf(buf, "%4.4X\n", dcon_disp_mode);
8162 +static ssize_t dcon_sleep_show(struct device *dev,
8163 + struct device_attribute *attr, char *buf)
8165 + return sprintf(buf, "%d\n", dcon_sleep_val);
8168 +static ssize_t /* __deprecated */ dcon_source_show(struct device *dev,
8169 + struct device_attribute *attr, char *buf)
8171 + printk(KERN_WARNING "olpc-dcon: using deprecated sysfs 'source' interface; use 'freeze' instead!\n");
8172 + return sprintf(buf, "%d\n", dcon_source);
8175 +static ssize_t dcon_freeze_show(struct device *dev,
8176 + struct device_attribute *attr, char *buf)
8178 + return sprintf(buf, "%d\n", dcon_source == DCON_SOURCE_DCON ? 1 : 0);
8181 +static ssize_t dcon_output_show(struct device *dev,
8182 + struct device_attribute *attr, char *buf)
8184 + return sprintf(buf, "%d\n", dcon_output);
8187 +static ssize_t dcon_resumeline_show(struct device *dev,
8188 + struct device_attribute *attr, char *buf)
8190 + return sprintf(buf, "%d\n", resumeline);
8193 +static int _strtoul(const char *buf, int len, unsigned int *val)
8197 + unsigned int output = simple_strtoul(buf, &endp, 0);
8198 + int size = endp - buf;
8200 + if (*endp && isspace(*endp))
8210 +static ssize_t dcon_output_store(struct device *dev,
8211 + struct device_attribute *attr, const char *buf, size_t count)
8216 + if (_strtoul(buf, count, &output))
8219 + if (output == DCON_OUTPUT_COLOR || output == DCON_OUTPUT_MONO) {
8220 + dcon_set_output(output);
8227 +static ssize_t /* __deprecated */ dcon_source_store(struct device *dev,
8228 + struct device_attribute *attr, const char *buf, size_t count)
8233 + printk(KERN_WARNING "olpc-dcon: using deprecated sysfs 'source' interface; use 'freeze' instead!\n");
8234 + if (_strtoul(buf, count, &output))
8237 + dcon_set_source(output);
8243 +static ssize_t dcon_freeze_store(struct device *dev,
8244 + struct device_attribute *attr, const char *buf, size_t count)
8249 + if (_strtoul(buf, count, &output))
8252 + dcon_set_source(output ? DCON_SOURCE_DCON : DCON_SOURCE_CPU);
8258 +static ssize_t dcon_resumeline_store(struct device *dev,
8259 + struct device_attribute *attr, const char *buf, size_t count)
8264 + if (_strtoul(buf, count, &rl))
8268 + dcon_write(DCON_REG_SCAN_INT, resumeline);
8274 +static ssize_t dcon_sleep_store(struct device *dev,
8275 + struct device_attribute *attr, const char *buf, size_t count)
8279 + if (_strtoul(buf, count, &output))
8282 + dcon_sleep(output ? DCON_SLEEP : DCON_ACTIVE);
8286 +static struct device_attribute dcon_device_files[] = {
8287 + __ATTR(mode, 0444, dcon_mode_show, NULL),
8288 + __ATTR(sleep, 0644, dcon_sleep_show, dcon_sleep_store),
8289 + __ATTR(source, 0644, dcon_source_show, dcon_source_store),
8290 + __ATTR(freeze, 0644, dcon_freeze_show, dcon_freeze_store),
8291 + __ATTR(output, 0644, dcon_output_show, dcon_output_store),
8292 + __ATTR(resumeline, 0644, dcon_resumeline_show, dcon_resumeline_store),
8295 +static struct backlight_ops dcon_bl_ops = {
8296 + .get_brightness = dconbl_get,
8297 + .update_status = dconbl_set
8300 +/* List of GPIOs that we care about:
8301 + (in) GPIO12 -- DCONBLNK
8302 + (in) GPIO[56] -- DCONSTAT[01]
8303 + (out) GPIO11 -- DCONLOAD
8306 +#define IN_GPIOS ((1<<5) | (1<<6) | (1<<7) | (1<<12))
8307 +#define OUT_GPIOS (1<<11)
8309 +static irqreturn_t dcon_interrupt(int, void *);
8311 +static int dcon_request_irq(void)
8313 + unsigned long lo, hi;
8314 + unsigned char lob;
8316 + rdmsr(MSR_LBAR_GPIO, lo, hi);
8318 + /* Check the mask and whether GPIO is enabled (sanity check) */
8319 + if (hi != 0x0000f001) {
8320 + printk(KERN_ERR "GPIO not enabled -- cannot use DCON\n");
8324 + /* Mask off the IO base address */
8325 + gpio_base = lo & 0x0000ff00;
8327 + /* Turn off the event enable for GPIO7 just to be safe */
8328 + outl(1 << (16+7), gpio_base + GPIOx_EVNT_EN);
8330 + /* Set the directions for the GPIO pins */
8331 + outl(OUT_GPIOS | (IN_GPIOS << 16), gpio_base + GPIOx_OUT_EN);
8332 + outl(IN_GPIOS | (OUT_GPIOS << 16), gpio_base + GPIOx_IN_EN);
8334 + /* Set up the interrupt mappings */
8336 + /* Set the IRQ to pair 2 */
8337 + geode_gpio_event_irq(OLPC_GPIO_DCON_IRQ, 2);
8339 + /* Enable group 2 to trigger the DCON interrupt */
8340 + geode_gpio_set_irq(2, DCON_IRQ);
8342 + /* Select edge level for interrupt (in PIC) */
8345 + lob &= ~(1 << DCON_IRQ);
8348 + /* Register the interupt handler */
8349 + if (request_irq(DCON_IRQ, &dcon_interrupt, 0, "DCON", &dcon_driver))
8352 + /* Clear INV_EN for GPIO7 (DCONIRQ) */
8353 + outl((1<<(16+7)), gpio_base + GPIOx_INV_EN);
8355 + /* Enable filter for GPIO12 (DCONBLANK) */
8356 + outl(1<<(12), gpio_base + GPIOx_IN_FLTR_EN);
8358 + /* Disable filter for GPIO7 */
8359 + outl(1<<(16+7), gpio_base + GPIOx_IN_FLTR_EN);
8361 + /* Disable event counter for GPIO7 (DCONIRQ) and GPIO12 (DCONBLANK) */
8363 + outl(1<<(16+7), gpio_base + GPIOx_EVNTCNT_EN);
8364 + outl(1<<(16+12), gpio_base + GPIOx_EVNTCNT_EN);
8366 + /* Add GPIO12 to the Filter Event Pair #7 */
8367 + outb(12, gpio_base + GPIO_FE7_SEL);
8369 + /* Turn off negative Edge Enable for GPIO12 */
8370 + outl(1<<(16+12), gpio_base + GPIOx_NEGEDGE_EN);
8372 + /* Enable negative Edge Enable for GPIO7 */
8373 + outl(1<<7, gpio_base + GPIOx_NEGEDGE_EN);
8375 + /* Zero the filter amount for Filter Event Pair #7 */
8376 + outw(0, gpio_base + GPIO_FLT7_AMNT);
8378 + /* Clear the negative edge status for GPIO7 and GPIO12 */
8379 + outl((1<<7) | (1<<12), gpio_base+0x4c);
8381 + /* FIXME: Clear the posiitive status as well, just to be sure */
8382 + outl((1<<7) | (1<<12), gpio_base+0x48);
8384 + /* Enable events for GPIO7 (DCONIRQ) and GPIO12 (DCONBLANK) */
8385 + outl((1<<(7))|(1<<12), gpio_base + GPIOx_EVNT_EN);
8387 + /* Determine the current state by reading the GPIO bit */
8388 + /* Earlier stages of the boot process have established the state */
8389 + dcon_source = inl(gpio_base + GPIOx_OUT_VAL) & (1<<11)
8391 + : DCON_SOURCE_DCON;
8392 + dcon_pending = dcon_source;
8397 +static int dcon_reboot_notify(struct notifier_block *nb, unsigned long foo, void *bar)
8399 + if (dcon_client == NULL)
8402 + /* Turn off the DCON. Entirely. */
8403 + dcon_write(DCON_REG_MODE, 0x39);
8404 + dcon_write(DCON_REG_MODE, 0x32);
8408 +static int dcon_conswitch_notify(struct notifier_block *nb,
8409 + unsigned long mode, void *dummy)
8411 + if (mode == CONSOLE_EVENT_SWITCH_TEXT)
8412 + dcon_sleep(DCON_ACTIVE);
8417 +static struct notifier_block dcon_nb = {
8418 + .notifier_call = dcon_reboot_notify,
8422 +static struct notifier_block dcon_console_nb = {
8423 + .notifier_call = dcon_conswitch_notify,
8427 +static int unfreeze_on_panic(struct notifier_block *nb, unsigned long e, void *p)
8429 + outl(1<<11, gpio_base + GPIOx_OUT_VAL);
8430 + return NOTIFY_DONE;
8433 +static struct notifier_block dcon_panic_nb = {
8434 + .notifier_call = unfreeze_on_panic,
8437 +static int dcon_probe(struct i2c_adapter *adap, int addr, int kind)
8439 + struct i2c_client *client;
8442 + if (!olpc_has_dcon()) {
8443 + printk("olpc-dcon: No DCON is attached.\n");
8447 + if (num_registered_fb >= 1)
8448 + fbinfo = registered_fb[0];
8450 + if (adap->id != I2C_HW_SMBUS_SCX200) {
8451 + printk(KERN_ERR "olpc-dcon: Invalid I2C bus (%d not %d)\n",
8452 + adap->id, I2C_HW_SMBUS_SCX200);
8456 + client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
8457 + if (client == NULL)
8460 + strncpy(client->name, "OLPC-DCON", I2C_NAME_SIZE);
8461 + client->addr = addr;
8462 + client->adapter = adap;
8463 + client->driver = &dcon_driver;
8465 + if ((rc = i2c_attach_client(client)) != 0) {
8466 + printk(KERN_ERR "olpc-dcon: Unable to attach the I2C client.\n");
8470 + rc = dcon_hw_init(client, 1);
8474 + /* Add the DCON device */
8476 + dcon_device = platform_device_alloc("dcon", -1);
8478 + if (dcon_device == NULL) {
8479 + printk(KERN_ERR "dcon: Unable to create the DCON device\n");
8484 + if ((rc = platform_device_add(dcon_device))) {
8485 + printk(KERN_ERR "dcon: Unable to add the DCON device\n");
8489 + for(i = 0; i < ARRAY_SIZE(dcon_device_files); i++)
8490 + device_create_file(&dcon_device->dev, &dcon_device_files[i]);
8492 + /* Add the backlight device for the DCON */
8494 + dcon_client = client;
8496 + dcon_bl_dev = backlight_device_register("dcon-bl", &dcon_device->dev,
8497 + NULL, &dcon_bl_ops);
8499 + if (IS_ERR(dcon_bl_dev)) {
8500 + printk(KERN_INFO "Could not register the backlight device for the DCON (%ld)\n", PTR_ERR(dcon_bl_dev));
8501 + dcon_bl_dev = NULL;
8504 + dcon_bl_dev->props.max_brightness = 15;
8505 + dcon_bl_dev->props.power = FB_BLANK_UNBLANK;
8506 + dcon_bl_dev->props.brightness = dcon_get_backlight();
8508 + backlight_update_status(dcon_bl_dev);
8511 + register_reboot_notifier(&dcon_nb);
8512 + console_event_register(&dcon_console_nb);
8513 + atomic_notifier_chain_register(&panic_notifier_list, &dcon_panic_nb);
8518 + platform_device_unregister(dcon_device);
8519 + dcon_device = NULL;
8521 + free_irq(DCON_IRQ, &dcon_driver);
8523 + i2c_detach_client(client);
8530 +static int dcon_attach(struct i2c_adapter *adap)
8534 + ret = i2c_probe(adap, &addr_data, dcon_probe);
8536 + if (dcon_client == NULL)
8537 + printk(KERN_ERR "olpc-dcon: No DCON found on SMBus\n");
8542 +static int dcon_detach(struct i2c_client *client)
8545 + dcon_client = NULL;
8547 + unregister_reboot_notifier(&dcon_nb);
8548 + console_event_unregister(&dcon_console_nb);
8549 + atomic_notifier_chain_unregister(&panic_notifier_list, &dcon_panic_nb);
8551 + free_irq(DCON_IRQ, &dcon_driver);
8553 + if ((rc = i2c_detach_client(client)) == 0)
8554 + kfree(i2c_get_clientdata(client));
8556 + if (dcon_bl_dev != NULL)
8557 + backlight_device_unregister(dcon_bl_dev);
8559 + if (dcon_device != NULL)
8560 + platform_device_unregister(dcon_device);
8561 + cancel_work_sync(&dcon_work);
8568 +static int dcon_suspend(struct i2c_client *client, pm_message_t state)
8570 + if (dcon_sleep_val != DCON_ACTIVE)
8573 + /* Set up the DCON to have the source */
8574 + return dcon_set_source_sync(DCON_SOURCE_DCON);
8577 +static int dcon_resume(struct i2c_client *client)
8579 + if (dcon_sleep_val != DCON_ACTIVE)
8582 + dcon_bus_stabilize(client, 0);
8584 + return dcon_set_source(DCON_SOURCE_CPU);
8589 +static irqreturn_t dcon_interrupt(int irq, void *id)
8591 + int status = inl(gpio_base + GPIOx_READ_BACK) >> 5;
8593 + /* Clear the negative edge status for GPIO7 */
8594 + outl(1 << 7, gpio_base + GPIOx_NEGEDGE_STS);
8596 + switch (status & 3) {
8598 + printk(KERN_DEBUG "olpc-dcon: DCONLOAD_MISSED interrupt\n");
8600 + case 2: /* switch to DCON mode */
8601 + case 1: /* switch to CPU mode */
8602 + dcon_switched = 1;
8603 + wake_up(&dcon_wait_queue);
8606 + printk(KERN_DEBUG "olpc-dcon: scanline interrupt w/CPU\n");
8609 + return IRQ_HANDLED;
8612 +static struct i2c_driver dcon_driver = {
8614 + .name = "OLPC-DCON",
8616 + .id = I2C_DRIVERID_DCON,
8617 + .attach_adapter = dcon_attach,
8618 + .detach_client = dcon_detach,
8620 + .suspend = dcon_suspend,
8621 + .resume = dcon_resume,
8626 +static int __init olpc_dcon_init(void)
8628 + i2c_add_driver(&dcon_driver);
8632 +static void __exit olpc_dcon_exit(void)
8634 + i2c_del_driver(&dcon_driver);
8637 +module_init(olpc_dcon_init);
8638 +module_exit(olpc_dcon_exit);
8640 +MODULE_LICENSE("GPL");
8641 Index: linux-2.6.24.7/drivers/video/olpc_dcon.h
8642 ===================================================================
8644 +++ linux-2.6.24.7/drivers/video/olpc_dcon.h
8646 +#ifndef OLPC_DCON_H_
8647 +#define OLPC_DCON_H_
8649 +/* DCON registers */
8651 +#define DCON_REG_ID 0
8652 +#define DCON_REG_MODE 1
8654 +#define MODE_PASSTHRU (1<<0)
8655 +#define MODE_SLEEP (1<<1)
8656 +#define MODE_SLEEP_AUTO (1<<2)
8657 +#define MODE_BL_ENABLE (1<<3)
8658 +#define MODE_BLANK (1<<4)
8659 +#define MODE_CSWIZZLE (1<<5)
8660 +#define MODE_COL_AA (1<<6)
8661 +#define MODE_MONO_LUMA (1<<7)
8662 +#define MODE_SCAN_INT (1<<8)
8663 +#define MODE_CLOCKDIV (1<<9)
8664 +#define MODE_DEBUG (1<<14)
8665 +#define MODE_SELFTEST (1<<15)
8667 +#define DCON_REG_HRES 2
8668 +#define DCON_REG_HTOTAL 3
8669 +#define DCON_REG_HSYNC_WIDTH 4
8670 +#define DCON_REG_VRES 5
8671 +#define DCON_REG_VTOTAL 6
8672 +#define DCON_REG_VSYNC_WIDTH 7
8673 +#define DCON_REG_TIMEOUT 8
8674 +#define DCON_REG_SCAN_INT 9
8675 +#define DCON_REG_BRIGHT 10
8677 +/* GPIO registers (CS5536) */
8679 +#define MSR_LBAR_GPIO 0x5140000C
8681 +#define GPIOx_OUT_VAL 0x00
8682 +#define GPIOx_OUT_EN 0x04
8683 +#define GPIOx_IN_EN 0x20
8684 +#define GPIOx_INV_EN 0x24
8685 +#define GPIOx_IN_FLTR_EN 0x28
8686 +#define GPIOx_EVNTCNT_EN 0x2C
8687 +#define GPIOx_READ_BACK 0x30
8688 +#define GPIOx_EVNT_EN 0x38
8689 +#define GPIOx_NEGEDGE_EN 0x44
8690 +#define GPIOx_NEGEDGE_STS 0x4C
8691 +#define GPIO_FLT7_AMNT 0xD8
8692 +#define GPIO_MAP_X 0xE0
8693 +#define GPIO_MAP_Y 0xE4
8694 +#define GPIO_FE7_SEL 0xF7
8697 +/* Status values */
8699 +#define DCONSTAT_SCANINT 0
8700 +#define DCONSTAT_SCANINT_DCON 1
8701 +#define DCONSTAT_DISPLAYLOAD 2
8702 +#define DCONSTAT_MISSED 3
8704 +/* Source values */
8706 +#define DCON_SOURCE_DCON 0
8707 +#define DCON_SOURCE_CPU 1
8709 +/* Output values */
8710 +#define DCON_OUTPUT_COLOR 0
8711 +#define DCON_OUTPUT_MONO 1
8714 +#define DCON_ACTIVE 0
8715 +#define DCON_SLEEP 1
8721 Index: linux-2.6.24.7/fs/jffs2/nodelist.h
8722 ===================================================================
8723 --- linux-2.6.24.7.orig/fs/jffs2/nodelist.h
8724 +++ linux-2.6.24.7/fs/jffs2/nodelist.h
8725 @@ -197,7 +197,7 @@ struct jffs2_inode_cache {
8726 #define RAWNODE_CLASS_XATTR_DATUM 1
8727 #define RAWNODE_CLASS_XATTR_REF 2
8729 -#define INOCACHE_HASHSIZE 128
8730 +#define INOCACHE_HASHSIZE 1024
8732 #define write_ofs(c) ((c)->nextblock->offset + (c)->sector_size - (c)->nextblock->free_size)
8734 Index: linux-2.6.24.7/fs/Kconfig
8735 ===================================================================
8736 --- linux-2.6.24.7.orig/fs/Kconfig
8737 +++ linux-2.6.24.7/fs/Kconfig
8738 @@ -1031,6 +1031,37 @@ config HUGETLBFS
8743 + tristate "PromFS IEEE 1275 file system support"
8744 + depends on SPARC || PPC || OLPC
8746 + PromFS is a file system interface to various IEEE-1275 compatible
8747 + firmwares. If you have such a firmware (Sparc64, PowerPC, and
8748 + some other architectures and embedded systems have such firmwares,
8749 + with names like "OpenBoot (tm)" and "OpenFirmware"), say Y here
8750 + to be able to access the firmware's device-tree from Linux.
8752 + The firmware device-tree is available as a virtual file system,
8753 + can be mounted under /prom with the command "mount -t promfs
8756 + To compile PromFS support as a module, choose M here; the module
8757 + will be called promfs. If unsure, choose M.
8763 + Ramfs is a file system which keeps all files in RAM. It allows
8764 + read and write access.
8766 + It is more of an programming example than a useable file system. If
8767 + you need a file system which lives in RAM with limit checking use
8770 + To compile this as a module, choose M here: the module will be called
8774 tristate "Userspace-driven configuration filesystem (EXPERIMENTAL)"
8775 depends on SYSFS && EXPERIMENTAL
8776 Index: linux-2.6.24.7/fs/Makefile
8777 ===================================================================
8778 --- linux-2.6.24.7.orig/fs/Makefile
8779 +++ linux-2.6.24.7/fs/Makefile
8780 @@ -110,6 +110,7 @@ obj-$(CONFIG_ADFS_FS) += adfs/
8781 obj-$(CONFIG_FUSE_FS) += fuse/
8782 obj-$(CONFIG_UDF_FS) += udf/
8783 obj-$(CONFIG_SUN_OPENPROMFS) += openpromfs/
8784 +obj-$(CONFIG_PROMFS_FS) += promfs/
8785 obj-$(CONFIG_JFS_FS) += jfs/
8786 obj-$(CONFIG_XFS_FS) += xfs/
8787 obj-$(CONFIG_9P_FS) += 9p/
8788 Index: linux-2.6.24.7/fs/promfs/Makefile
8789 ===================================================================
8791 +++ linux-2.6.24.7/fs/promfs/Makefile
8793 +obj-$(CONFIG_PROMFS_FS) += promfs.o
8794 Index: linux-2.6.24.7/fs/promfs/promfs.c
8795 ===================================================================
8797 +++ linux-2.6.24.7/fs/promfs/promfs.c
8800 + * promfs.c - generic inode/dentry functions for IEEE 1275-based filesystems.
8802 + * This is based heavily upon prior ieee1275 and other virtual filesystems
8803 + * implementations; openpromfs, proc_devtree.c, oprofilefs, procfs, ...
8805 + * Copyright (C) 2007 Andres Salomon <dilinger@debian.org>
8807 + * This program is free software; you can redistribute it and/or modify
8808 + * it under the terms of the GNU General Public License as published by
8809 + * the Free Software Foundation; either version 2 of the License, or
8810 + * (at your option) any later version.
8812 + * This program is distributed in the hope that it will be useful,
8813 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
8814 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
8815 + * GNU General Public License for more details.
8817 + * You should have received a copy of the GNU General Public License along
8818 + * with this program; if not, write to the Free Software Foundation, Inc.,
8819 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
8822 +#include <linux/init.h>
8823 +#include <linux/module.h>
8824 +#include <linux/pagemap.h>
8825 +#include <linux/fs.h>
8826 +//#include <linux/promfs.h>
8827 +#include <asm/prom.h>
8829 +#define PROMFS_MAGIC 0x1f2f3fff
8831 +MODULE_LICENSE("GPL");
8832 +MODULE_AUTHOR("Andres Salomon");
8834 +struct promfs_inode
8837 + struct property *prop;
8840 +static inline struct promfs_inode *to_promfs_inode(struct inode *inode)
8842 + return container_of(inode, struct promfs_inode, ino);
8846 +static DEFINE_SPINLOCK(promfs_lock);
8848 +static struct of_node *of_tree = NULL;
8849 +static DEFINE_RWLOCK(of_tree_lock);
8851 +void __init of_build_tree(void)
8858 +static int promfs_open_file(struct inode *inode, struct file *file)
8860 + struct promfs_inode *ino;
8862 + ino = to_promfs_inode(inode);
8865 + file->private_data = ino->prop;
8870 +static ssize_t promfs_read_file(struct file *file, char __user *data,
8871 + size_t len, loff_t *ppos)
8873 + struct property *prop = (struct property *) file->private_data;
8874 + return simple_read_from_buffer(data, len, ppos, prop->value,
8878 +static ssize_t promfs_write_file(struct file *file, char const __user *buf,
8879 + size_t count, loff_t * offset)
8881 + /* TODO.... 'cause, y'know, it would be nice. */
8885 +static struct file_operations promfs_file_ops = {
8886 + .open = promfs_open_file,
8887 + .read = promfs_read_file,
8888 + .write = promfs_write_file,
8891 +static struct kmem_cache *promfs_inode_cachep;
8893 +static struct inode *promfs_alloc_inode(struct super_block *sb)
8895 + struct promfs_inode *pr_ino;
8897 + pr_ino = kmem_cache_alloc(promfs_inode_cachep, GFP_KERNEL);
8900 + pr_ino->prop = NULL;
8902 + return &pr_ino->ino;
8905 +static void promfs_destroy_inode(struct inode *inode)
8907 + kmem_cache_free(promfs_inode_cachep, to_promfs_inode(inode));
8910 +static void promfs_read_inode(struct inode *inode)
8912 + inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
8915 +static int promfs_remount(struct super_block *sb, int *flags, char *data)
8917 + *flags |= MS_NOATIME;
8921 +static struct super_operations promfs_s_ops = {
8922 + .alloc_inode = promfs_alloc_inode,
8923 + .destroy_inode = promfs_destroy_inode,
8924 + .read_inode = promfs_read_inode,
8925 + .statfs = simple_statfs,
8926 + .drop_inode = generic_delete_inode,
8927 + .remount_fs = promfs_remount,
8930 +static struct inode *promfs_get_inode(struct super_block *sb, int mode)
8932 + struct inode *inode = new_inode(sb);
8935 + inode->i_mode = mode;
8938 + inode->i_blocks = 0;
8939 + inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
8945 +static int promfs_create_file(struct super_block *sb, struct dentry *root,
8946 + struct property *prop, const struct file_operations *fops)
8948 + struct dentry *dentry;
8949 + struct inode *inode;
8950 + struct promfs_inode *ino;
8952 + dentry = d_alloc_name(root, prop->name);
8956 + inode = promfs_get_inode(sb, S_IFREG | 0644);
8959 + inode->i_fop = fops;
8960 + ino = to_promfs_inode(inode);
8962 + d_add(dentry, inode);
8972 +struct dentry *promfs_create_dir(struct super_block *sb, struct dentry *root,
8975 + struct dentry *dentry;
8976 + struct inode *inode;
8978 + dentry = d_alloc_name(root, name);
8982 + inode = promfs_get_inode(sb, S_IFDIR | 0755);
8985 + inode->i_op = &simple_dir_inode_operations;
8986 + inode->i_fop = &simple_dir_operations;
8987 + d_add(dentry, inode);
8996 +void promfs_populate(struct super_block *sb, struct dentry *root,
8997 + struct device_node *node)
8999 + struct dentry *dentry;
9000 + struct device_node *child;
9001 + struct property *prop;
9006 + for (child = node->child; child; child = child->sibling) {
9007 + dentry = promfs_create_dir(sb, root, child->path_component_name);
9008 + promfs_populate(sb, dentry, child);
9010 + for (prop = node->properties; prop; prop = prop->next)
9011 + promfs_create_file(sb, root, prop, &promfs_file_ops);
9014 +static int promfs_fill_super(struct super_block *sb, void *data, int silent)
9016 + struct inode *root_inode;
9017 + struct dentry *root_dentry;
9018 + struct promfs_inode *inode;
9020 + sb->s_blocksize = PAGE_CACHE_SIZE;
9021 + sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
9022 + sb->s_magic = PROMFS_MAGIC;
9023 + sb->s_op = &promfs_s_ops;
9024 + sb->s_time_gran = 1;
9025 + sb->s_flags |= MS_NOATIME;
9027 + root_inode = promfs_get_inode(sb, S_IFDIR | 0755);
9030 + root_inode->i_op = &simple_dir_inode_operations;
9031 + root_inode->i_fop = &simple_dir_operations;
9033 + inode = to_promfs_inode(root_inode);
9035 + root_dentry = d_alloc_root(root_inode);
9038 + sb->s_root = root_dentry;
9040 + promfs_populate(sb, root_dentry, of_find_node_by_path("/"));
9049 +static int promfs_get_sb(struct file_system_type *fs_type, int flags,
9050 + const char *dev_name, void *data, struct vfsmount *mnt)
9052 + return get_sb_single(fs_type, flags, data, promfs_fill_super, mnt);
9055 +static struct file_system_type promfs_fs_type = {
9056 + .owner = THIS_MODULE,
9058 + .get_sb = promfs_get_sb,
9059 + .kill_sb = kill_litter_super,
9062 +static void init_once(void *i, struct kmem_cache *cachep, unsigned long fl)
9064 + struct promfs_inode *inode = (struct promfs_inode *) i;
9065 + inode_init_once(&inode->ino);
9068 +static int __init init_promfs(void)
9072 + prom_build_devicetree();
9073 + promfs_inode_cachep = kmem_cache_create("promfs_inode_cache",
9074 + sizeof(struct promfs_inode), 0,
9075 + SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, init_once, NULL);
9076 + if (!promfs_inode_cachep)
9079 + err = register_filesystem(&promfs_fs_type);
9081 + kmem_cache_destroy(promfs_inode_cachep);
9086 +static void __exit exit_promfs(void)
9088 + unregister_filesystem(&promfs_fs_type);
9089 + kmem_cache_destroy(promfs_inode_cachep);
9092 +module_init(init_promfs);
9093 +module_exit(exit_promfs);
9094 Index: linux-2.6.24.7/include/asm-x86/ofw.h
9095 ===================================================================
9097 +++ linux-2.6.24.7/include/asm-x86/ofw.h
9100 + * Definitions for Open Firmware client interface on 32-bit system.
9101 + * OF Cell size is 4. Integer properties are encoded big endian,
9102 + * as with all OF implementations.
9104 + * This program is free software; you can redistribute it and/or
9105 + * modify it under the terms of the GNU General Public License
9106 + * as published by the Free Software Foundation; either version
9107 + * 2 of the License, or (at your option) any later version.
9112 +extern int ofw(char *, int, int, ...);
9115 Index: linux-2.6.24.7/include/asm-x86/olpc.h
9116 ===================================================================
9118 +++ linux-2.6.24.7/include/asm-x86/olpc.h
9120 +/* OLPC machine specific definitions */
9122 +#ifndef ASM_OLPC_H_
9123 +#define ASM_OLPC_H_
9125 +#include <asm/geode.h>
9127 +struct olpc_platform_t {
9133 +#define OLPC_F_PRESENT 0x01
9134 +#define OLPC_F_DCON 0x02
9135 +#define OLPC_F_VSA 0x04
9138 + * OLPC board IDs contain the major build number within the mask 0x0ff0,
9139 + * and the minor build number withing 0x000f. Pre-builds have a minor
9140 + * number less than 8, and normal builds start at 8. For example, 0x0B10
9141 + * is a PreB1, and 0x0C18 is a C1.
9144 +static inline u32 olpc_board(u8 id)
9146 + return (id << 4) | 0x8;
9149 +static inline u32 olpc_board_pre(u8 id)
9154 +#ifndef CONFIG_OLPC
9156 +static inline int machine_is_olpc(void) { return 0; }
9157 +static inline int olpc_has_dcon(void) { return 0; }
9158 +static inline int olpc_has_vsa(void) { return 0; }
9162 +extern struct olpc_platform_t olpc_platform_info;
9165 +machine_is_olpc(void)
9167 + return (olpc_platform_info.flags & OLPC_F_PRESENT) ? 1 : 0;
9171 +olpc_has_dcon(void)
9173 + return (olpc_platform_info.flags & OLPC_F_DCON) ? 1 : 0;
9179 + return (olpc_platform_info.flags & OLPC_F_VSA) ? 1 : 0;
9182 +static inline int olpc_board_at_least(u32 rev)
9184 + return olpc_platform_info.boardrev >= rev;
9191 +int olpc_ec_cmd(unsigned char cmd, unsigned char *inbuf, size_t inlen,
9192 + unsigned char *outbuf, size_t outlen);
9194 +void olpc_register_battery_callback(void (*f)(unsigned long));
9195 +void olpc_deregister_battery_callback(void);
9197 +/* EC commands and responses */
9199 +/* SCI source values */
9201 +#define EC_SCI_SRC_EMPTY 0x00
9202 +#define EC_SCI_SRC_GAME 0x01
9203 +#define EC_SCI_SRC_BATTERY 0x02
9204 +#define EC_SCI_SRC_BATSOC 0x04
9205 +#define EC_SCI_SRC_BATERR 0x08
9206 +#define EC_SCI_SRC_EBOOK 0x10
9207 +#define EC_SCI_SRC_WLAN 0x20
9208 +#define EC_SCI_SRC_ACPWR 0x40
9209 +#define EC_SCI_SRC_ALL 0x7F
9211 +int olpc_ec_mask_set(u8 bits);
9212 +int olpc_ec_mask_unset(u8 bits);
9214 +/* GPIO assignments */
9216 +#define OLPC_GPIO_MIC_AC (1 << 1)
9217 +#define OLPC_GPIO_DCON_IRQ (1 << 7)
9218 +#define OLPC_GPIO_THRM_ALRM (1 << 10)
9219 +#define OLPC_GPIO_SMB_CLK (1 << 14)
9220 +#define OLPC_GPIO_SMB_DATA (1 << 15)
9221 +#define OLPC_GPIO_WORKAUX (1 << 24)
9222 +#define OLPC_GPIO_LID (1 << 26)
9223 +#define OLPC_GPIO_ECSCI (1 << 27)
9227 Index: linux-2.6.24.7/include/asm-x86/prom.h
9228 ===================================================================
9230 +++ linux-2.6.24.7/include/asm-x86/prom.h
9232 +#ifndef _I386_PROM_H
9233 +#define _I386_PROM_H
9238 + * Definitions for talking to the Open Firmware PROM on
9239 + * Power Macintosh computers.
9241 + * Copyright (C) 1996-2005 Paul Mackerras.
9243 + * Updates for PPC64 by Peter Bergner & David Engebretsen, IBM Corp.
9244 + * Updates for SPARC64 by David S. Miller
9245 + * Updates for i386/OLPC by Andres Salomon
9247 + * This program is free software; you can redistribute it and/or
9248 + * modify it under the terms of the GNU General Public License
9249 + * as published by the Free Software Foundation; either version
9250 + * 2 of the License, or (at your option) any later version.
9253 +#include <linux/types.h>
9254 +#include <linux/proc_fs.h>
9255 +#include <asm/atomic.h>
9257 +typedef u32 phandle;
9258 +typedef u32 ihandle;
9264 + struct property *next;
9267 +struct device_node {
9271 +// phandle linux_phandle;
9272 + char *path_component_name;
9275 + struct property *properties;
9276 + struct property *deadprops; /* removed properties */
9277 + struct device_node *parent;
9278 + struct device_node *child;
9279 + struct device_node *sibling;
9280 + struct device_node *next; /* next device of same type */
9281 + struct device_node *allnext; /* next in list of all nodes */
9282 + struct proc_dir_entry *pde; /* this node's proc directory */
9284 + unsigned long _flags;
9288 +/* flag descriptions */
9289 +#define OF_DYNAMIC 1 /* node and properties were allocated via kmalloc */
9291 +#define OF_IS_DYNAMIC(x) test_bit(OF_DYNAMIC, &x->_flags)
9292 +#define OF_MARK_DYNAMIC(x) set_bit(OF_DYNAMIC, &x->_flags)
9294 +#define OF_BAD_ADDR ((u64)-1)
9296 +static inline void set_node_proc_entry(struct device_node *dn, struct proc_dir_entry *de)
9301 +extern struct device_node *of_find_node_by_name(struct device_node *from,
9302 + const char *name);
9303 +#define for_each_node_by_name(dn, name) \
9304 + for (dn = of_find_node_by_name(NULL, name); dn; \
9305 + dn = of_find_node_by_name(dn, name))
9306 +extern struct device_node *of_find_node_by_type(struct device_node *from,
9307 + const char *type);
9308 +#define for_each_node_by_type(dn, type) \
9309 + for (dn = of_find_node_by_type(NULL, type); dn; \
9310 + dn = of_find_node_by_type(dn, type))
9311 +extern struct device_node *of_find_compatible_node(struct device_node *from,
9312 + const char *type, const char *compat);
9313 +extern struct device_node *of_find_node_by_path(const char *path);
9314 +extern struct device_node *of_find_node_by_phandle(phandle handle);
9315 +extern struct device_node *of_get_parent(const struct device_node *node);
9316 +extern struct device_node *of_get_next_child(const struct device_node *node,
9317 + struct device_node *prev);
9318 +extern struct property *of_find_property(const struct device_node *np,
9321 +//extern struct device_node *of_node_get(struct device_node *node);
9322 +//extern void of_node_put(struct device_node *node);
9323 +extern int of_device_is_compatible(const struct device_node *device,
9325 +extern const void *of_get_property(const struct device_node *node,
9328 +#define get_property(node,name,lenp) of_get_property(node,name,lenp)
9329 +extern int of_set_property(struct device_node *node, const char *name, void *val, int len);
9330 +extern int of_getintprop_default(struct device_node *np,
9333 +extern int of_n_addr_cells(struct device_node *np);
9334 +extern int of_n_size_cells(struct device_node *np);
9336 +extern void prom_build_devicetree(void);
9338 +#endif /* __KERNEL__ */
9340 Index: linux-2.6.24.7/include/linux/battery.h
9341 ===================================================================
9343 +++ linux-2.6.24.7/include/linux/battery.h
9346 + * Driver model for batteries
9348 + * © 2006 David Woodhouse <dwmw2@infradead.org>
9350 + * Based on LED Class support, by John Lenz and Richard Purdie:
9352 + * © 2005 John Lenz <lenz@cs.wisc.edu>
9353 + * © 2005-2006 Richard Purdie <rpurdie@openedhand.com>
9355 + * This program is free software; you can redistribute it and/or modify
9356 + * it under the terms of the GNU General Public License version 2 as
9357 + * published by the Free Software Foundation.
9360 +#ifndef __LINUX_BATTERY_H__
9361 +#define __LINUX_BATTERY_H__
9364 +struct class_device;
9369 +#define PWRDEV_TYPE_BATTERY 0
9370 +#define PWRDEV_TYPE_AC 1
9372 +#define BAT_STAT_PRESENT (1<<0)
9373 +#define BAT_STAT_LOW (1<<1)
9374 +#define BAT_STAT_FULL (1<<2)
9375 +#define BAT_STAT_CHARGING (1<<3)
9376 +#define BAT_STAT_DISCHARGING (1<<4)
9377 +#define BAT_STAT_OVERTEMP (1<<5)
9378 +#define BAT_STAT_CRITICAL (1<<6)
9379 +#define BAT_STAT_FIRE (1<<7)
9380 +#define BAT_STAT_CHARGE_DONE (1<<8)
9382 +/* Thou shalt not export any attributes in sysfs except these, and
9383 + with these units: */
9384 +#define BAT_INFO_STATUS "status" /* Not free-form. Use
9385 + provided function */
9386 +#define BAT_INFO_TEMP1 "temp1" /* °C/1000 */
9387 +#define BAT_INFO_TEMP1_NAME "temp1_name" /* string */
9389 +#define BAT_INFO_TEMP2 "temp2" /* °C/1000 */
9390 +#define BAT_INFO_TEMP2_NAME "temp2_name" /* string */
9392 +#define BAT_INFO_VOLTAGE "voltage" /* mV */
9393 +#define BAT_INFO_VOLTAGE_DESIGN "voltage_design" /* mV */
9395 +#define BAT_INFO_CURRENT "current" /* mA */
9396 +#define BAT_INFO_CURRENT_NOW "current_now" /* mA */
9398 +#define BAT_INFO_POWER "power" /* mW */
9399 +#define BAT_INFO_POWER_NOW "power_now" /* mW */
9401 +/* The following capacity/charge properties are represented in either
9402 + mA or mW. The CAP_UNITS property MUST be provided if any of these are. */
9403 +#define BAT_INFO_RATE "rate" /* CAP_UNITS */
9404 +#define BAT_INFO_CAP_LEFT "capacity_left" /* CAP_UNITS*h */
9405 +#define BAT_INFO_CAP_DESIGN "capacity_design" /* CAP_UNITS*h */
9406 +#define BAT_INFO_CAP_LAST_FULL "capacity_last_full" /* CAP_UNITS*h */
9407 +#define BAT_INFO_CAP_LOW "capacity_low_thresh" /* CAP_UNITS*h */
9408 +#define BAT_INFO_CAP_WARN "capacity_warn_thresh" /* CAP_UNITS*h */
9409 +#define BAT_INFO_CAP_UNITS "capacity_units" /* string: must be
9410 + either mA or mW */
9412 +#define BAT_INFO_CAP_PCT "capacity_percentage" /* integer */
9414 +#define BAT_INFO_TIME_EMPTY "time_to_empty" /* seconds */
9415 +#define BAT_INFO_TIME_EMPTY_NOW "time_to_empty_now" /* seconds */
9416 +#define BAT_INFO_TIME_FULL "time_to_full" /* seconds */
9417 +#define BAT_INFO_TIME_FULL_NOW "time_to_full_now" /* seconds */
9419 +#define BAT_INFO_MANUFACTURER "manufacturer" /* string */
9420 +#define BAT_INFO_TECHNOLOGY "technology" /* string */
9421 +#define BAT_INFO_MODEL "model" /* string */
9422 +#define BAT_INFO_SERIAL "serial" /* string */
9423 +#define BAT_INFO_OEM_INFO "oem_info" /* string */
9425 +#define BAT_INFO_CYCLE_COUNT "cycle_count" /* integer */
9426 +#define BAT_INFO_DATE_MFR "date_manufactured" /* YYYY[-MM[-DD]] */
9427 +#define BAT_INFO_DATE_FIRST_USE "date_first_use" /* YYYY[-MM[-DD]] */
9429 +struct battery_dev {
9435 + struct device *dev;
9438 +int battery_device_register(struct device *parent,
9439 + struct battery_dev *battery_cdev);
9440 +void battery_device_unregister(struct battery_dev *battery_cdev);
9443 +ssize_t battery_attribute_show_status(char *buf, unsigned long status);
9444 +ssize_t battery_attribute_show_ac_status(char *buf, unsigned long status);
9445 +#endif /* __LINUX_BATTERY_H__ */
9446 Index: linux-2.6.24.7/include/linux/fb.h
9447 ===================================================================
9448 --- linux-2.6.24.7.orig/include/linux/fb.h
9449 +++ linux-2.6.24.7/include/linux/fb.h
9450 @@ -666,6 +666,12 @@ struct fb_ops {
9451 /* restore saved state */
9452 void (*fb_restore_state)(struct fb_info *info);
9454 + /* Shut down the graphics engine to save power */
9455 + int (*fb_powerdown)(struct fb_info *info);
9457 + /* Power it back up */
9458 + int (*fb_powerup)(struct fb_info *info);
9460 /* get capability given var */
9461 void (*fb_get_caps)(struct fb_info *info, struct fb_blit_caps *caps,
9462 struct fb_var_screeninfo *var);
9463 @@ -945,6 +951,9 @@ extern int fb_get_color_depth(struct fb_
9464 extern int fb_get_options(char *name, char **option);
9465 extern int fb_new_modelist(struct fb_info *info);
9467 +extern int fb_powerdown(struct fb_info *info);
9468 +extern int fb_powerup(struct fb_info *info);
9470 extern struct fb_info *registered_fb[FB_MAX];
9471 extern int num_registered_fb;
9472 extern struct class *fb_class;
9473 Index: linux-2.6.24.7/include/linux/i2c-id.h
9474 ===================================================================
9475 --- linux-2.6.24.7.orig/include/linux/i2c-id.h
9476 +++ linux-2.6.24.7/include/linux/i2c-id.h
9478 #define I2C_DRIVERID_LM4857 92 /* LM4857 Audio Amplifier */
9479 #define I2C_DRIVERID_VP27SMPX 93 /* Panasonic VP27s tuner internal MPX */
9480 #define I2C_DRIVERID_CS4270 94 /* Cirrus Logic 4270 audio codec */
9481 +#define I2C_DRIVERID_DCON 95
9483 #define I2C_DRIVERID_I2CDEV 900
9484 #define I2C_DRIVERID_ARP 902 /* SMBus ARP Client */
9485 Index: linux-2.6.24.7/include/linux/isl_38xx.h
9486 ===================================================================
9488 +++ linux-2.6.24.7/include/linux/isl_38xx.h
9491 + * Copyright (C) 2002 Intersil Americas Inc.
9493 + * This program is free software; you can redistribute it and/or modify
9494 + * it under the terms of the GNU General Public License as published by
9495 + * the Free Software Foundation; either version 2 of the License
9497 + * This program is distributed in the hope that it will be useful,
9498 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
9499 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9500 + * GNU General Public License for more details.
9502 + * You should have received a copy of the GNU General Public License
9503 + * along with this program; if not, write to the Free Software
9504 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
9507 +#ifndef _LINUX_ISL_38XX_H
9508 +#define _LINUX_ISL_38XX_H
9510 +#include <asm/io.h>
9512 +#define ISL38XX_CB_RX_QSIZE 8
9513 +#define ISL38XX_CB_TX_QSIZE 32
9515 +/* ISL38XX Access Point Specific definitions */
9516 +#define ISL38XX_MAX_WDS_LINKS 8
9518 +/* ISL38xx Client Specific definitions */
9519 +#define ISL38XX_PSM_ACTIVE_STATE 0
9520 +#define ISL38XX_PSM_POWERSAVE_STATE 1
9522 +/* ISL38XX Host Interface Definitions */
9523 +#define ISL38XX_PCI_MEM_SIZE 0x02000
9524 +#define ISL38XX_MEMORY_WINDOW_SIZE 0x01000
9525 +#define ISL38XX_DEV_FIRMWARE_ADDRES 0x20000
9526 +#define ISL38XX_WRITEIO_DELAY 10 /* in us */
9527 +#define ISL38XX_RESET_DELAY 50 /* in ms */
9528 +#define ISL38XX_WAIT_CYCLE 10 /* in 10ms */
9529 +#define ISL38XX_MAX_WAIT_CYCLES 10
9531 +/* PCI Memory Area */
9532 +#define ISL38XX_HARDWARE_REG 0x0000
9533 +#define ISL38XX_CARDBUS_CIS 0x0800
9534 +#define ISL38XX_DIRECT_MEM_WIN 0x1000
9536 +/* Hardware registers */
9537 +#define ISL38XX_DEV_INT_REG 0x0000
9538 +#define ISL38XX_INT_IDENT_REG 0x0010
9539 +#define ISL38XX_INT_ACK_REG 0x0014
9540 +#define ISL38XX_INT_EN_REG 0x0018
9541 +#define ISL38XX_GEN_PURP_COM_REG_1 0x0020
9542 +#define ISL38XX_GEN_PURP_COM_REG_2 0x0024
9543 +#define ISL38XX_CTRL_BLK_BASE_REG ISL38XX_GEN_PURP_COM_REG_1
9544 +#define ISL38XX_DIR_MEM_BASE_REG 0x0030
9545 +#define ISL38XX_CTRL_STAT_REG 0x0078
9547 +/* High end mobos queue up pci writes, the following
9548 + * is used to "read" from after a write to force flush */
9549 +#define ISL38XX_PCI_POSTING_FLUSH ISL38XX_INT_EN_REG
9552 + * isl38xx_w32_flush - PCI iomem write helper
9553 + * @base: (host) memory base address of the device
9554 + * @val: 32bit value (host order) to write
9555 + * @offset: byte offset into @base to write value to
9557 + * This helper takes care of writing a 32bit datum to the
9558 + * specified offset into the device's pci memory space, and making sure
9559 + * the pci memory buffers get flushed by performing one harmless read
9560 + * from the %ISL38XX_PCI_POSTING_FLUSH offset.
9563 +isl38xx_w32_flush(void __iomem *base, u32 val, unsigned long offset)
9565 + writel(val, base + offset);
9566 + (void) readl(base + ISL38XX_PCI_POSTING_FLUSH);
9569 +/* Device Interrupt register bits */
9570 +#define ISL38XX_DEV_INT_RESET 0x0001
9571 +#define ISL38XX_DEV_INT_UPDATE 0x0002
9572 +#define ISL38XX_DEV_INT_WAKEUP 0x0008
9573 +#define ISL38XX_DEV_INT_SLEEP 0x0010
9574 +#define ISL38XX_DEV_INT_ABORT 0x0020
9575 +/* thos two only used in USB */
9576 +#define ISL38XX_DEV_INT_DATA 0x0040
9577 +#define ISL38XX_DEV_INT_MGMT 0x0080
9579 +#define ISL38XX_DEV_INT_PCIUART_CTS 0x4000
9580 +#define ISL38XX_DEV_INT_PCIUART_DR 0x8000
9582 +/* Interrupt Identification/Acknowledge/Enable register bits */
9583 +#define ISL38XX_INT_IDENT_UPDATE 0x0002
9584 +#define ISL38XX_INT_IDENT_INIT 0x0004
9585 +#define ISL38XX_INT_IDENT_WAKEUP 0x0008
9586 +#define ISL38XX_INT_IDENT_SLEEP 0x0010
9587 +#define ISL38XX_INT_IDENT_PCIUART_CTS 0x4000
9588 +#define ISL38XX_INT_IDENT_PCIUART_DR 0x8000
9590 +#define ISL38XX_INT_SOURCES (ISL38XX_INT_IDENT_UPDATE | \
9591 + ISL38XX_INT_IDENT_INIT | \
9592 + ISL38XX_INT_IDENT_WAKEUP | \
9593 + ISL38XX_INT_IDENT_SLEEP | \
9594 + ISL38XX_INT_IDENT_PCIUART_CTS | \
9595 + ISL38XX_INT_IDENT_PCIUART_DR)
9597 +/* Control/Status register bits */
9598 +/* Looks like there are other meaningful bits
9599 + 0x20004400 seen in normal operation,
9600 + 0x200044db at 'timeout waiting for mgmt response'
9602 +#define ISL38XX_CTRL_STAT_SLEEPMODE 0x00000200
9603 +#define ISL38XX_CTRL_STAT_CLKRUN 0x00800000
9604 +#define ISL38XX_CTRL_STAT_RESET 0x10000000
9605 +#define ISL38XX_CTRL_STAT_RAMBOOT 0x20000000
9606 +#define ISL38XX_CTRL_STAT_STARTHALTED 0x40000000
9607 +#define ISL38XX_CTRL_STAT_HOST_OVERRIDE 0x80000000
9609 +/* Some flags for the isl hardware registers controlling DMA inside the
9611 +#define ISL38XX_DMA_STATUS_DONE 0x00000001
9612 +#define ISL38XX_DMA_STATUS_READY 0x00000002
9613 +#define NET2280_EPA_FIFO_PCI_ADDR 0x20000000
9614 +#define ISL38XX_DMA_MASTER_CONTROL_TRIGGER 0x00000004
9616 +#endif /* _LINUX_ISL_38XX_H */
9617 Index: linux-2.6.24.7/include/linux/pm.h
9618 ===================================================================
9619 --- linux-2.6.24.7.orig/include/linux/pm.h
9620 +++ linux-2.6.24.7/include/linux/pm.h
9621 @@ -178,6 +178,9 @@ struct dev_pm_info {
9622 unsigned can_wakeup:1;
9623 #ifdef CONFIG_PM_SLEEP
9624 unsigned should_wakeup:1;
9625 + pm_message_t prev_state;
9626 + void * saved_state;
9627 + struct device * pm_parent;
9628 struct list_head entry;
9631 Index: linux-2.6.24.7/include/linux/power_supply.h
9632 ===================================================================
9633 --- linux-2.6.24.7.orig/include/linux/power_supply.h
9634 +++ linux-2.6.24.7/include/linux/power_supply.h
9635 @@ -98,9 +98,11 @@ enum power_supply_property {
9636 POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
9637 POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
9638 POWER_SUPPLY_PROP_TIME_TO_FULL_AVG,
9639 + POWER_SUPPLY_PROP_ACCUM_CURRENT,
9640 /* Properties of type `const char *' */
9641 POWER_SUPPLY_PROP_MODEL_NAME,
9642 POWER_SUPPLY_PROP_MANUFACTURER,
9643 + POWER_SUPPLY_PROP_SERIAL_NUMBER,
9646 enum power_supply_type {
9647 @@ -169,9 +171,10 @@ struct power_supply_info {
9649 extern void power_supply_changed(struct power_supply *psy);
9650 extern int power_supply_am_i_supplied(struct power_supply *psy);
9651 +extern void power_supply_status_changed(struct power_supply *psy);
9653 extern int power_supply_register(struct device *parent,
9654 - struct power_supply *psy);
9655 + struct power_supply *psy);
9656 extern void power_supply_unregister(struct power_supply *psy);
9658 /* For APM emulation, think legacy userspace. */
9659 Index: linux-2.6.24.7/include/linux/vt_kern.h
9660 ===================================================================
9661 --- linux-2.6.24.7.orig/include/linux/vt_kern.h
9662 +++ linux-2.6.24.7/include/linux/vt_kern.h
9663 @@ -96,4 +96,23 @@ struct vt_spawn_console {
9665 extern struct vt_spawn_console vt_spawn_con;
9667 +/* A notifier list for console events */
9668 +extern struct raw_notifier_head console_notifier_list;
9670 +/* Called when the FG console switches to KD_TEXT mode */
9671 +#define CONSOLE_EVENT_SWITCH_TEXT 0x01
9673 +/* Called when the FG console switches to KD_GRAPHICS mode */
9674 +#define CONSOLE_EVENT_SWITCH_GRAPHICS 0x02
9676 +static inline int console_event_register(struct notifier_block *n)
9678 + return raw_notifier_chain_register(&console_notifier_list, n);
9681 +static inline int console_event_unregister(struct notifier_block *n)
9683 + return raw_notifier_chain_unregister(&console_notifier_list, n);
9686 #endif /* _VT_KERN_H */
9687 Index: linux-2.6.24.7/include/sound/ac97_codec.h
9688 ===================================================================
9689 --- linux-2.6.24.7.orig/include/sound/ac97_codec.h
9690 +++ linux-2.6.24.7/include/sound/ac97_codec.h
9691 @@ -281,10 +281,12 @@
9692 /* specific - Analog Devices */
9693 #define AC97_AD_TEST 0x5a /* test register */
9694 #define AC97_AD_TEST2 0x5c /* undocumented test register 2 */
9695 +#define AC97_AD_HPFD_SHIFT 12 /* High Pass Filter Disable */
9696 #define AC97_AD_CODEC_CFG 0x70 /* codec configuration */
9697 #define AC97_AD_JACK_SPDIF 0x72 /* Jack Sense & S/PDIF */
9698 #define AC97_AD_SERIAL_CFG 0x74 /* Serial Configuration */
9699 #define AC97_AD_MISC 0x76 /* Misc Control Bits */
9700 +#define AC97_AD_VREFD_SHIFT 2 /* V_REFOUT Disable (AD1888) */
9702 /* specific - Cirrus Logic */
9703 #define AC97_CSR_ACMODE 0x5e /* AC Mode Register */
9704 Index: linux-2.6.24.7/kernel/power/console.c
9705 ===================================================================
9706 --- linux-2.6.24.7.orig/kernel/power/console.c
9707 +++ linux-2.6.24.7/kernel/power/console.c
9709 #include <linux/console.h>
9712 -#if defined(CONFIG_VT) && defined(CONFIG_VT_CONSOLE)
9713 +#if defined(CONFIG_VT) && defined(CONFIG_VT_CONSOLE) && !defined(CONFIG_DISABLE_SUSPEND_VT_SWITCH)
9714 #define SUSPEND_CONSOLE (MAX_NR_CONSOLES-1)
9716 static int orig_fgconsole, orig_kmsg;
9717 Index: linux-2.6.24.7/kernel/power/Kconfig
9718 ===================================================================
9719 --- linux-2.6.24.7.orig/kernel/power/Kconfig
9720 +++ linux-2.6.24.7/kernel/power/Kconfig
9721 @@ -37,9 +37,22 @@ config PM_DEBUG
9722 code. This is helpful when debugging and reporting PM bugs, like
9725 +config DISABLE_SUSPEND_VT_SWITCH
9726 + bool "Disable the console switch prior to suspend (DANGEROUS)"
9727 + depends on PM_DEBUG
9730 + This option disables the automatic switch to VT console that happens
9731 + prior to Linux going into a suspend/sleep. Your video card/framebuffer
9732 + must be able to properly restore the display (even if X is doing
9733 + something crazy!) in this scenario. This is useful for saving
9734 + precious milliseconds during suspend and resume.
9739 bool "Verbose Power Management debugging"
9740 - depends on PM_DEBUG
9741 + depends on VT_CONSOLE && PM && EXPERIMENTAL
9744 This option enables verbose messages from the Power Management code.
9745 Index: linux-2.6.24.7/kernel/power/main.c
9746 ===================================================================
9747 --- linux-2.6.24.7.orig/kernel/power/main.c
9748 +++ linux-2.6.24.7/kernel/power/main.c
9749 @@ -76,11 +76,13 @@ static int suspend_prepare(void)
9750 if (!suspend_ops || !suspend_ops->enter)
9753 +#ifndef CONFIG_OLPC_PM
9754 error = pm_notifier_call_chain(PM_SUSPEND_PREPARE);
9758 pm_prepare_console();
9761 if (freeze_processes()) {
9763 Index: linux-2.6.24.7/scripts/kconfig/conf.c
9764 ===================================================================
9765 --- linux-2.6.24.7.orig/scripts/kconfig/conf.c
9766 +++ linux-2.6.24.7/scripts/kconfig/conf.c
9767 @@ -22,6 +22,7 @@ enum {
9771 + set_silentdefault,
9775 @@ -64,10 +65,11 @@ static void strip(char *str)
9777 static void check_stdin(void)
9779 - if (!valid_stdin && input_mode == ask_silent) {
9780 + if (!valid_stdin && (input_mode == ask_silent ||
9781 + input_mode == set_silentdefault)) {
9782 printf(_("aborted!\n\n"));
9783 printf(_("Console input/output is redirected. "));
9784 - printf(_("Run 'make oldconfig' to update configuration.\n\n"));
9785 + printf(_("Configuration file needs to be updated.\n\n"));
9789 @@ -102,6 +104,7 @@ static int conf_askvalue(struct symbol *
9793 + case set_silentdefault:
9794 if (sym_has_value(sym)) {
9795 printf("%s\n", def);
9797 @@ -352,6 +355,7 @@ static int conf_choice(struct menu *menu
9798 switch (input_mode) {
9801 + case set_silentdefault:
9804 printf("%d\n", cnt);
9805 @@ -424,7 +428,9 @@ static void conf(struct menu *menu)
9807 switch (prop->type) {
9809 - if (input_mode == ask_silent && rootEntry != menu) {
9810 + if ((input_mode == ask_silent ||
9811 + input_mode == set_silentdefault) &&
9812 + rootEntry != menu) {
9816 @@ -508,6 +514,16 @@ int main(int ac, char **av)
9817 input_mode = ask_silent;
9818 valid_stdin = isatty(0) && isatty(1) && isatty(2);
9821 + input_mode = set_silentdefault;
9822 + valid_stdin = isatty(0) && isatty(1) && isatty(2);
9823 + defconfig_file = av[i++];
9824 + if (!defconfig_file) {
9825 + printf("%s: No default config file specified\n",
9831 input_mode = set_default;
9833 @@ -557,6 +573,14 @@ int main(int ac, char **av)
9837 + case set_silentdefault:
9838 + if (conf_read(defconfig_file)) {
9840 + "*** Can't find default configuration \"%s\"!\n"
9841 + "***\n", defconfig_file);
9846 if (stat(".config", &tmpstat)) {
9848 @@ -597,7 +621,7 @@ int main(int ac, char **av)
9852 - if (input_mode != ask_silent) {
9853 + if (input_mode != ask_silent && input_mode != set_silentdefault) {
9854 rootEntry = &rootmenu;
9856 if (input_mode == ask_all) {
9857 @@ -610,19 +634,21 @@ int main(int ac, char **av)
9858 fprintf(stderr, _("\n*** Kernel configuration requires explicit update.\n\n"));
9862 + } else if (input_mode != set_silentdefault)
9867 check_conf(&rootmenu);
9869 - if (conf_write(NULL)) {
9870 + if (conf_write(NULL, input_mode == ask_silent ||
9871 + input_mode == set_silentdefault)) {
9872 fprintf(stderr, _("\n*** Error during writing of the kernel configuration.\n\n"));
9876 - if (input_mode == ask_silent && conf_write_autoconf()) {
9877 + if ((input_mode == ask_silent || input_mode == set_silentdefault) &&
9878 + conf_write_autoconf()) {
9879 fprintf(stderr, _("\n*** Error during writing of the kernel configuration.\n\n"));
9882 Index: linux-2.6.24.7/scripts/kconfig/confdata.c
9883 ===================================================================
9884 --- linux-2.6.24.7.orig/scripts/kconfig/confdata.c
9885 +++ linux-2.6.24.7/scripts/kconfig/confdata.c
9886 @@ -393,7 +393,7 @@ int conf_read(const char *name)
9890 -int conf_write(const char *name)
9891 +int conf_write(const char *name, int quiet)
9895 @@ -548,9 +548,10 @@ int conf_write(const char *name)
9900 - "# configuration written to %s\n"
9904 + "# configuration written to %s\n"
9907 sym_set_change_count(0);
9909 Index: linux-2.6.24.7/scripts/kconfig/gconf.c
9910 ===================================================================
9911 --- linux-2.6.24.7.orig/scripts/kconfig/gconf.c
9912 +++ linux-2.6.24.7/scripts/kconfig/gconf.c
9913 @@ -621,7 +621,7 @@ void on_load1_activate(GtkMenuItem * men
9915 void on_save_activate(GtkMenuItem * menuitem, gpointer user_data)
9917 - if (conf_write(NULL))
9918 + if (conf_write(NULL, 0))
9919 text_insert_msg(_("Error"), _("Unable to save configuration !"));
9922 @@ -634,7 +634,7 @@ store_filename(GtkFileSelection * file_s
9923 fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION
9926 - if (conf_write(fn))
9927 + if (conf_write(fn, 0))
9928 text_insert_msg(_("Error"), _("Unable to save configuration !"));
9930 gtk_widget_destroy(GTK_WIDGET(user_data));
9931 Index: linux-2.6.24.7/scripts/kconfig/lkc_proto.h
9932 ===================================================================
9933 --- linux-2.6.24.7.orig/scripts/kconfig/lkc_proto.h
9934 +++ linux-2.6.24.7/scripts/kconfig/lkc_proto.h
9936 P(conf_parse,void,(const char *name));
9937 P(conf_read,int,(const char *name));
9938 P(conf_read_simple,int,(const char *name, int));
9939 -P(conf_write,int,(const char *name));
9940 +P(conf_write,int,(const char *name, int));
9941 P(conf_write_autoconf,int,(void));
9942 P(conf_get_changed,bool,(void));
9943 P(conf_set_changed_callback, void,(void (*fn)(void)));
9944 Index: linux-2.6.24.7/scripts/kconfig/Makefile
9945 ===================================================================
9946 --- linux-2.6.24.7.orig/scripts/kconfig/Makefile
9947 +++ linux-2.6.24.7/scripts/kconfig/Makefile
9948 @@ -69,6 +69,9 @@ endif
9949 %_defconfig: $(obj)/conf
9950 $(Q)$< -D arch/$(SRCARCH)/configs/$@ $(Kconfig)
9952 +%_silentdefconfig: $(obj)/conf
9953 + $(Q)$< -S arch/$(ARCH)/configs/$(subst _silentdefconfig,_defconfig,$@) arch/$(ARCH)/Kconfig
9955 # Help text used by make help
9957 @echo ' config - Update current config utilising a line-oriented program'
9958 Index: linux-2.6.24.7/scripts/kconfig/mconf.c
9959 ===================================================================
9960 --- linux-2.6.24.7.orig/scripts/kconfig/mconf.c
9961 +++ linux-2.6.24.7/scripts/kconfig/mconf.c
9962 @@ -885,7 +885,7 @@ static void conf_save(void)
9964 if (!dialog_input_result[0])
9966 - if (!conf_write(dialog_input_result)) {
9967 + if (!conf_write(dialog_input_result, 0)) {
9968 set_config_filename(dialog_input_result);
9971 @@ -945,7 +945,7 @@ int main(int ac, char **av)
9975 - if (conf_write(filename)) {
9976 + if (conf_write(filename, 0)) {
9977 fprintf(stderr, _("\n\n"
9978 "Error during writing of the kernel configuration.\n"
9979 "Your kernel configuration changes were NOT saved."
9980 Index: linux-2.6.24.7/scripts/kconfig/qconf.cc
9981 ===================================================================
9982 --- linux-2.6.24.7.orig/scripts/kconfig/qconf.cc
9983 +++ linux-2.6.24.7/scripts/kconfig/qconf.cc
9984 @@ -1458,7 +1458,7 @@ void ConfigMainWindow::loadConfig(void)
9986 void ConfigMainWindow::saveConfig(void)
9988 - if (conf_write(NULL))
9989 + if (conf_write(NULL, 0))
9990 QMessageBox::information(this, "qconf", "Unable to save configuration!");
9993 @@ -1467,7 +1467,7 @@ void ConfigMainWindow::saveConfigAs(void
9994 QString s = QFileDialog::getSaveFileName(".config", NULL, this);
9997 - if (conf_write(QFile::encodeName(s)))
9998 + if (conf_write(QFile::encodeName(s), 0))
9999 QMessageBox::information(this, "qconf", "Unable to save configuration!");
10002 @@ -1619,7 +1619,7 @@ void ConfigMainWindow::closeEvent(QClose
10003 mb.setButtonText(QMessageBox::Cancel, "Cancel Exit");
10004 switch (mb.exec()) {
10005 case QMessageBox::Yes:
10006 - conf_write(NULL);
10007 + conf_write(NULL, 0);
10008 case QMessageBox::No:
10011 Index: linux-2.6.24.7/sound/pci/ac97/ac97_patch.c
10012 ===================================================================
10013 --- linux-2.6.24.7.orig/sound/pci/ac97/ac97_patch.c
10014 +++ linux-2.6.24.7/sound/pci/ac97/ac97_patch.c
10015 @@ -2029,8 +2029,9 @@ static const struct snd_kcontrol_new snd
10016 .get = snd_ac97_ad1888_lohpsel_get,
10017 .put = snd_ac97_ad1888_lohpsel_put
10019 - AC97_SINGLE("V_REFOUT Enable", AC97_AD_MISC, 2, 1, 1),
10020 - AC97_SINGLE("High Pass Filter Enable", AC97_AD_TEST2, 12, 1, 1),
10021 + AC97_SINGLE("V_REFOUT Enable", AC97_AD_MISC, AC97_AD_VREFD_SHIFT, 1, 1),
10022 + AC97_SINGLE("High Pass Filter Enable", AC97_AD_TEST2,
10023 + AC97_AD_HPFD_SHIFT, 1, 1),
10024 AC97_SINGLE("Spread Front to Surround and Center/LFE", AC97_AD_MISC, 7, 1, 0),
10026 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10027 Index: linux-2.6.24.7/sound/pci/cs5535audio/cs5535audio.c
10028 ===================================================================
10029 --- linux-2.6.24.7.orig/sound/pci/cs5535audio/cs5535audio.c
10030 +++ linux-2.6.24.7/sound/pci/cs5535audio/cs5535audio.c
10031 @@ -145,7 +145,7 @@ static unsigned short snd_cs5535audio_ac
10032 return snd_cs5535audio_codec_read(cs5535au, reg);
10035 -static int snd_cs5535audio_mixer(struct cs5535audio *cs5535au)
10036 +static int __devinit snd_cs5535audio_mixer(struct cs5535audio *cs5535au)
10038 struct snd_card *card = cs5535au->card;
10039 struct snd_ac97_bus *pbus;
10040 @@ -160,10 +160,14 @@ static int snd_cs5535audio_mixer(struct
10043 memset(&ac97, 0, sizeof(ac97));
10044 - ac97.scaps = AC97_SCAP_AUDIO|AC97_SCAP_SKIP_MODEM;
10045 + ac97.scaps = AC97_SCAP_AUDIO | AC97_SCAP_SKIP_MODEM
10046 + | AC97_SCAP_POWER_SAVE;
10047 ac97.private_data = cs5535au;
10048 ac97.pci = cs5535au->pci;
10050 + /* olpc_prequirks is dummied out if not olpc */
10051 + olpc_prequirks(card, &ac97);
10053 if ((err = snd_ac97_mixer(pbus, &ac97, &cs5535au->ac97)) < 0) {
10054 snd_printk(KERN_ERR "mixer failed\n");
10056 @@ -171,6 +175,12 @@ static int snd_cs5535audio_mixer(struct
10058 snd_ac97_tune_hardware(cs5535au->ac97, ac97_quirks, ac97_quirk);
10060 + /* olpc_quirks is dummied out if not olpc */
10061 + if (( err = olpc_quirks(card, cs5535au->ac97)) < 0) {
10062 + snd_printk(KERN_ERR "olpc quirks failed\n");
10069 Index: linux-2.6.24.7/sound/pci/cs5535audio/cs5535audio.h
10070 ===================================================================
10071 --- linux-2.6.24.7.orig/sound/pci/cs5535audio/cs5535audio.h
10072 +++ linux-2.6.24.7/sound/pci/cs5535audio/cs5535audio.h
10073 @@ -78,6 +78,7 @@ struct cs5535audio_dma {
10074 unsigned int buf_addr, buf_bytes;
10075 unsigned int period_bytes, periods;
10077 + int pcm_open_flag;
10080 struct cs5535audio {
10081 @@ -93,8 +94,21 @@ struct cs5535audio {
10082 struct cs5535audio_dma dmas[NUM_CS5535AUDIO_DMAS];
10086 int snd_cs5535audio_suspend(struct pci_dev *pci, pm_message_t state);
10087 int snd_cs5535audio_resume(struct pci_dev *pci);
10090 +#ifdef CONFIG_OLPC
10091 +void olpc_prequirks(struct snd_card *card, struct snd_ac97_template *ac97) __devinit;
10092 +int olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97) __devinit;
10093 +int olpc_ai_enable(struct snd_ac97 *ac97, u8 val);
10095 +#define olpc_prequirks(arg,arg2) do {} while (0)
10096 +#define olpc_quirks(arg,arg2) (0)
10097 +#define olpc_ai_enable(a, v) (0)
10100 int __devinit snd_cs5535audio_pcm(struct cs5535audio *cs5535audio);
10102 #endif /* __SOUND_CS5535AUDIO_H */
10103 Index: linux-2.6.24.7/sound/pci/cs5535audio/cs5535audio_olpc.c
10104 ===================================================================
10106 +++ linux-2.6.24.7/sound/pci/cs5535audio/cs5535audio_olpc.c
10108 +#include <sound/driver.h>
10109 +#include <sound/core.h>
10110 +#include <sound/info.h>
10111 +#include <sound/control.h>
10112 +#include <sound/ac97_codec.h>
10114 +#include <asm/olpc.h>
10115 +#include "cs5535audio.h"
10118 + * OLPC has an additional feature on top of the regular AD1888 codec features.
10119 + * It has an Analog Input mode that is switched into (after disabling the
10120 + * High Pass Filter) via GPIO. It is only supported on B2 and later models.
10123 +int olpc_ai_enable(struct snd_ac97 *ac97, u8 val)
10128 + * update the High Pass Filter (via AC97_AD_TEST2), and then set
10129 + * Analog Input mode through a GPIO.
10133 + err = snd_ac97_update_bits(ac97, AC97_AD_TEST2,
10134 + 1<<AC97_AD_HPFD_SHIFT, 1<<AC97_AD_HPFD_SHIFT);
10135 + geode_gpio_set(OLPC_GPIO_MIC_AC, GPIO_OUTPUT_VAL);
10138 + err = snd_ac97_update_bits(ac97, AC97_AD_TEST2,
10139 + 1<<AC97_AD_HPFD_SHIFT, 0);
10140 + geode_gpio_clear(OLPC_GPIO_MIC_AC, GPIO_OUTPUT_VAL);
10143 + snd_printk(KERN_ERR "Error updating AD_TEST2: %d\n", err);
10147 +EXPORT_SYMBOL_GPL(olpc_ai_enable);
10149 +static int snd_cs5535audio_ai_info(struct snd_kcontrol *kcontrol,
10150 + struct snd_ctl_elem_info *uinfo)
10152 + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
10153 + uinfo->count = 1;
10154 + uinfo->value.integer.min = 0;
10155 + uinfo->value.integer.max = 1;
10159 +static int snd_cs5535audio_ai_get(struct snd_kcontrol *kcontrol,
10160 + struct snd_ctl_elem_value *ucontrol)
10162 + ucontrol->value.integer.value[0] = geode_gpio_isset(OLPC_GPIO_MIC_AC,
10163 + GPIO_OUTPUT_VAL);
10167 +static int snd_cs5535audio_ai_put(struct snd_kcontrol *kcontrol,
10168 + struct snd_ctl_elem_value *ucontrol)
10170 + struct cs5535audio *cs5535au = snd_kcontrol_chip(kcontrol);
10171 + struct snd_ac97 *ac97 = cs5535au->ac97;
10173 + olpc_ai_enable(ac97, ucontrol->value.integer.value[0]);
10178 +static struct snd_kcontrol_new snd_cs5535audio_controls __devinitdata =
10180 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10181 + .name = "DC Mode Enable",
10182 + .info = snd_cs5535audio_ai_info,
10183 + .get = snd_cs5535audio_ai_get,
10184 + .put = snd_cs5535audio_ai_put,
10185 + .private_value = 0
10188 +void __devinit olpc_prequirks(struct snd_card *card,
10189 + struct snd_ac97_template *ac97)
10191 + /* Bail if this isn't an OLPC platform */
10192 + if (!machine_is_olpc())
10195 + /* If on an OLPC B3 or higher, invert EAPD. */
10196 + if (olpc_board_at_least(olpc_board_pre(0xb3)))
10197 + ac97->scaps |= AC97_SCAP_INV_EAPD;
10200 +int __devinit olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97)
10202 + struct snd_ctl_elem_id elem;
10204 + /* Bail if this isn't an OLPC platform */
10205 + if (!machine_is_olpc())
10208 + /* drop the original ad1888 HPF control */
10209 + memset(&elem, 0, sizeof(elem));
10210 + elem.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
10211 + strcpy(elem.name, "High Pass Filter Enable");
10212 + snd_ctl_remove_id(card, &elem);
10214 + /* add the override for OLPC's HPF */
10215 + return snd_ctl_add(card, snd_ctl_new1(&snd_cs5535audio_controls,
10216 + ac97->private_data));
10218 Index: linux-2.6.24.7/sound/pci/cs5535audio/cs5535audio_pcm.c
10219 ===================================================================
10220 --- linux-2.6.24.7.orig/sound/pci/cs5535audio/cs5535audio_pcm.c
10221 +++ linux-2.6.24.7/sound/pci/cs5535audio/cs5535audio_pcm.c
10222 @@ -259,6 +259,9 @@ static int snd_cs5535audio_hw_params(str
10223 err = cs5535audio_build_dma_packets(cs5535au, dma, substream,
10224 params_periods(hw_params),
10225 params_period_bytes(hw_params));
10227 + dma->pcm_open_flag = 1;
10232 @@ -267,6 +270,15 @@ static int snd_cs5535audio_hw_free(struc
10233 struct cs5535audio *cs5535au = snd_pcm_substream_chip(substream);
10234 struct cs5535audio_dma *dma = substream->runtime->private_data;
10236 + if (dma->pcm_open_flag) {
10237 + if (substream == cs5535au->playback_substream)
10238 + snd_ac97_update_power(cs5535au->ac97,
10239 + AC97_PCM_FRONT_DAC_RATE, 0);
10241 + snd_ac97_update_power(cs5535au->ac97,
10242 + AC97_PCM_LR_ADC_RATE, 0);
10243 + dma->pcm_open_flag = 0;
10245 cs5535audio_clear_dma_packets(cs5535au, dma, substream);
10246 return snd_pcm_lib_free_pages(substream);
10248 @@ -341,6 +353,7 @@ static int snd_cs5535audio_capture_open(
10250 struct cs5535audio *cs5535au = snd_pcm_substream_chip(substream);
10251 struct snd_pcm_runtime *runtime = substream->runtime;
10252 + struct snd_ac97 *ac97 = cs5535au->ac97;
10254 runtime->hw = snd_cs5535audio_capture;
10255 cs5535au->capture_substream = substream;
10256 @@ -348,11 +361,29 @@ static int snd_cs5535audio_capture_open(
10257 if ((err = snd_pcm_hw_constraint_integer(runtime,
10258 SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
10262 +#ifdef CONFIG_OLPC
10263 + /* Disable Analog Input */
10264 + olpc_ai_enable(ac97, 0);
10265 + /* Enable V_ref bias while recording. */
10266 + snd_ac97_update_bits(ac97, AC97_AD_MISC, 1<<AC97_AD_VREFD_SHIFT, 0);
10271 static int snd_cs5535audio_capture_close(struct snd_pcm_substream *substream)
10273 +#ifdef CONFIG_OLPC
10274 + struct cs5535audio *cs5535au = snd_pcm_substream_chip(substream);
10275 + struct snd_ac97 *ac97 = cs5535au->ac97;
10277 + /* Disable Analog Input */
10278 + olpc_ai_enable(ac97, 0);
10279 + /* Disable V_ref bias. */
10280 + snd_ac97_update_bits(ac97, AC97_AD_MISC, 1<<AC97_AD_VREFD_SHIFT,
10281 + 1<<AC97_AD_VREFD_SHIFT);
10287 Index: linux-2.6.24.7/sound/pci/cs5535audio/Makefile
10288 ===================================================================
10289 --- linux-2.6.24.7.orig/sound/pci/cs5535audio/Makefile
10290 +++ linux-2.6.24.7/sound/pci/cs5535audio/Makefile
10292 snd-cs5535audio-y := cs5535audio.o cs5535audio_pcm.o
10293 snd-cs5535audio-$(CONFIG_PM) += cs5535audio_pm.o
10296 +snd-cs5535audio-objs += cs5535audio_olpc.o
10299 # Toplevel Module Dependency
10300 obj-$(CONFIG_SND_CS5535AUDIO) += snd-cs5535audio.o