Do not override classifier kernel configuration symbols
[openwrt.git] / target / linux / olpc / patches-2.6.24 / 100-olpc.patch
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
6  config PCI_GOANY
7         bool "Any"
8  
9 +config PCI_GOOLPC
10 +       bool "OLPC"
11 +
12  endchoice
13  
14  config PCI_BIOS
15 @@ -1425,7 +1428,7 @@ config PCI_BIOS
16  # x86-64 doesn't support PCI BIOS access from long mode so always go direct.
17  config PCI_DIRECT
18         bool
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)
21         default y
22  
23  config PCI_MMCONFIG
24 @@ -1442,6 +1445,11 @@ config PCI_MMCONFIG
25         bool "Support mmconfig PCI config space access"
26         depends on X86_64 && PCI && ACPI
27  
28 +config PCI_OLPC
29 +       bool 
30 +       depends on PCI && PCI_GOOLPC
31 +       default y
32 +
33  config DMAR
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
37         def_bool y
38         depends on AGP_AMD64 || (X86_64 && (GART_IOMMU || (PCI && NUMA)))
39  
40 +config OLPC
41 +       bool "OLPC Support"
42 +       default n
43 +       help
44 +         Add OLPC Support
45 +
46 +config OLPC_PM
47 +       bool "OLPC power management support"
48 +       default n
49 +       depends on OLPC
50 +
51 +config OPEN_FIRMWARE
52 +       bool "Support for Open Firmware"
53 +       default y if OLPC
54 +
55  source "drivers/pcmcia/Kconfig"
56  
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
63  
64  obj-$(CONFIG_SCx200)           += scx200_32.o
65  
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
70 +
71 +
72 +
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 ===================================================================
78 --- /dev/null
79 +++ linux-2.6.24.7/arch/x86/kernel/ofw.c
80 @@ -0,0 +1,100 @@
81 +/*
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.
86 + *
87 + * Copyright (C) 2007  Mitch Bradley <wmb@firmworks.com>
88 + * Copyright (C) 2007  Andres Salomon <dilinger@debian.org>
89 + */
90 +
91 +#include <stdarg.h>
92 +#include <linux/spinlock.h>
93 +#include <linux/module.h>
94 +#include <asm/ofw.h>
95 +
96 +
97 +int (*call_firmware)(int *);
98 +
99 +static DEFINE_SPINLOCK(prom_lock);
100 +
101 +#define MAXARGS 20
102 +
103 +/*
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. 
108 + *
109 + * Here are call templates for all the standard OFW client services:
110 + *
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);
140 + */
141 +
142 +int ofw(char *name, int numargs, int numres, ...)
143 +{
144 +       va_list ap;
145 +       int argarray[MAXARGS+3];
146 +       int argnum = 3;
147 +       int retval;
148 +       int *intp;
149 +       unsigned long flags;
150 +
151 +       if (!call_firmware)
152 +               return -1;
153 +       if ((numargs + numres) > MAXARGS)
154 +               return -1;      /* spit out an error? */
155 +
156 +       argarray[0] = (int) name;
157 +       argarray[1] = numargs;
158 +       argarray[2] = numres;
159 +
160 +       va_start(ap, numres);
161 +       while (numargs) {
162 +               argarray[argnum++] = va_arg(ap, int);
163 +               numargs--;
164 +       }
165 +
166 +       spin_lock_irqsave(&prom_lock, flags);
167 +       retval = call_firmware(argarray);
168 +       spin_unlock_irqrestore(&prom_lock, flags);
169 +
170 +       if (retval == 0) {
171 +               while (numres) {
172 +                       intp = va_arg(ap, int *);
173 +                       *intp = argarray[argnum++];
174 +                       numres--;
175 +               }
176 +       }
177 +       va_end(ap);
178 +       return retval;
179 +}
180 +EXPORT_SYMBOL(ofw);
181 Index: linux-2.6.24.7/arch/x86/kernel/olpc.c
182 ===================================================================
183 --- /dev/null
184 +++ linux-2.6.24.7/arch/x86/kernel/olpc.c
185 @@ -0,0 +1,287 @@
186 +/* Support for the OLPC DCON and OLPC EC access
187 + * Copyright (C) 2006, Advanced Micro Devices, Inc.
188 + *
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.
193 + */
194 +
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>
201 +
202 +#include <asm/olpc.h>
203 +#include <asm/ofw.h>
204 +
205 +/* This is our new multi-purpose structure used to contain the
206 + * information about the platform that we detect
207 + */
208 +
209 +struct olpc_platform_t olpc_platform_info;
210 +EXPORT_SYMBOL_GPL(olpc_platform_info);
211 +
212 +/*********************************************************************
213 + *             EC locking and access
214 + *********************************************************************/
215 +
216 +static DEFINE_SPINLOCK(ec_lock);
217 +
218 +/* what the timeout *should* be (in ms) */
219 +#define EC_BASE_TIMEOUT 20
220 +
221 +/* the timeout that bugs in the EC might force us to actually use */
222 +static int ec_timeout = EC_BASE_TIMEOUT;
223 +
224 +static int __init olpc_ec_timeout_set(char *str)
225 +{
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");
230 +       }
231 +       printk(KERN_DEBUG "olpc-ec:  using %d ms delay for EC commands.\n",
232 +                       ec_timeout);
233 +       return 1;
234 +}
235 +__setup("olpc_ec_timeout=", olpc_ec_timeout_set);
236 +
237 +/*
238 + * These *bf_status functions return whether the buffers are full or not.
239 + */
240 +
241 +static inline unsigned int ibf_status(unsigned int port)
242 +{
243 +       return !!(inb(port) & 0x02);
244 +}
245 +
246 +static inline unsigned int obf_status(unsigned int port)
247 +{
248 +       return inb(port) & 0x01;
249 +}
250 +
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)
253 +{
254 +       unsigned int timeo;
255 +       int state = ibf_status(port);
256 +
257 +       for (timeo = ec_timeout; state != desired && timeo; timeo--) {
258 +               mdelay(1);
259 +               state = ibf_status(port);
260 +       }
261 +
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);
266 +       }
267 +
268 +       return !(state == desired);
269 +}
270 +
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)
273 +{
274 +       unsigned int timeo;
275 +       int state = obf_status(port);
276 +
277 +       for (timeo = ec_timeout; state != desired && timeo; timeo--) {
278 +               mdelay(1);
279 +               state = obf_status(port);
280 +       }
281 +
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);
286 +       }
287 +
288 +       return !(state == desired);
289 +}
290 +
291 +int olpc_ec_cmd(unsigned char cmd, unsigned char *inbuf, size_t inlen,
292 +               unsigned char *outbuf,  size_t outlen)
293 +{
294 +       unsigned long flags;
295 +       int ret = -EIO;
296 +       int i;
297 +
298 +       spin_lock_irqsave(&ec_lock, flags);
299 +
300 +       /* Clear OBF */
301 +       for (i = 0; i < 10 && (obf_status(0x6c) == 1); i++)
302 +               inb(0x68);
303 +       if (i == 10) {
304 +               printk(KERN_ERR "olpc-ec:  timeout while attempting to "
305 +                               "clear OBF flag!\n");
306 +               goto err;
307 +       }
308 +
309 +       if (wait_on_ibf(0x6c, 0)) {
310 +               printk(KERN_ERR "olpc-ec:  timeout waiting for EC to "
311 +                               "quiesce!\n");
312 +               goto err;
313 +       }
314 +
315 +restart:
316 +       /*
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.
319 +        *
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..
324 +        */
325 +       printk(KERN_DEBUG "olpc-ec:  running cmd 0x%x\n", cmd);
326 +       outb(cmd, 0x6c);
327 +
328 +       if (wait_on_ibf(0x6c, 0)) {
329 +               printk(KERN_ERR "olpc-ec:  timeout waiting for EC to read "
330 +                               "command!\n");
331 +               goto err;
332 +       }
333 +
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");
340 +                               goto err;
341 +                       }
342 +                       printk(KERN_DEBUG "olpc-ec:  sending cmd arg 0x%x\n",
343 +                                       inbuf[i]);
344 +                       outb(inbuf[i], 0x68);
345 +               }
346 +       }
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");
353 +                               goto restart;
354 +                       }
355 +                       outbuf[i] = inb(0x68);
356 +                       printk(KERN_DEBUG "olpc-ec:  received 0x%x\n",
357 +                                       outbuf[i]);
358 +               }
359 +       }
360 +
361 +       ret = 0;
362 +err:
363 +       spin_unlock_irqrestore(&ec_lock, flags);
364 +       return ret;
365 +}
366 +EXPORT_SYMBOL_GPL(olpc_ec_cmd);
367 +
368 +/*********************************************************************
369 + *             DCON stuff
370 + *********************************************************************/
371 +
372 +static void __init
373 +ec_detect(void)
374 +{
375 +       olpc_ec_cmd(0x08, NULL, 0, (unsigned char *) &olpc_platform_info.ecver, 1);
376 +}
377 +
378 +/* Check to see if this version of the OLPC board has VSA built
379 + * in, and set a flag
380 + */
381 +
382 +static void __init vsa_detect(void)
383 +{
384 +       u16 rev;
385 +
386 +       outw(0xFC53, 0xAC1C);
387 +       outw(0x0003, 0xAC1C);
388 +
389 +       rev = inw(0xAC1E);
390 +
391 +       if (rev == 0x4132)
392 +               olpc_platform_info.flags |= OLPC_F_VSA;
393 +}
394 +
395 +static void __init platform_detect(void)
396 +{
397 +       size_t propsize;
398 +       u32 rev;
399 +
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");
403 +               rev = 0;
404 +       }
405 +       olpc_platform_info.boardrev = be32_to_cpu(rev);
406 +}
407 +
408 +static int olpc_dcon_present = -1;
409 +module_param(olpc_dcon_present, int, 0444);
410 +
411 +/* REV_A CMOS map:
412 + * bit 440;  DCON present bit
413 + */
414 +
415 +#define OLPC_CMOS_DCON_OFFSET (440 / 8)
416 +#define OLPC_CMOS_DCON_MASK   0x01
417 +
418 +static int __init olpc_init(void)
419 +{
420 +       unsigned char *romsig;
421 +
422 +       spin_lock_init(&ec_lock);
423 +
424 +       romsig = ioremap(0xffffffc0, 16);
425 +
426 +       if (!romsig)
427 +               return 0;
428 +
429 +       if (strncmp(romsig, "CL1   Q", 7))
430 +               goto unmap;
431 +       if (strncmp(romsig+6, romsig+13, 3)) {
432 +               printk(KERN_INFO "OLPC BIOS signature looks invalid. Assuming not OLPC\n");
433 +               goto unmap;
434 +       }
435 +       printk(KERN_INFO "OLPC board with OpenFirmware: %.16s\n", romsig);
436 +
437 +       olpc_platform_info.flags |= OLPC_F_PRESENT;
438 +
439 +       /* Get the platform revision */
440 +       platform_detect();
441 +
442 +       /* If olpc_dcon_present isn't set by the command line, then
443 +        * "detect" it
444 +        */
445 +
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;
450 +       }
451 +
452 +       if (olpc_dcon_present)
453 +               olpc_platform_info.flags |= OLPC_F_DCON;
454 +
455 +       /* Get the EC revision */
456 +       ec_detect();
457 +
458 +       /* Check to see if the VSA exists */
459 +       vsa_detect();
460 +
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);
465 +
466 + unmap:
467 +       iounmap(romsig);
468 +
469 +       return 0;
470 +}
471 +
472 +postcore_initcall(olpc_init);
473 Index: linux-2.6.24.7/arch/x86/kernel/olpc-pm.c
474 ===================================================================
475 --- /dev/null
476 +++ linux-2.6.24.7/arch/x86/kernel/olpc-pm.c
477 @@ -0,0 +1,946 @@
478 +/* olpc-pm.c
479 + * Â© 2006 Red Hat, Inc.
480 + * Portions also copyright 2006 Advanced Micro Devices, Inc.
481 + * GPLv2
482 + */
483 +
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>
494 +#include <asm/io.h>
495 +
496 +#include <asm/olpc.h>
497 +
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
502 +   here:
503 +
504 +   http://www.amd.com/files/connectivitysolutions/geode/geode_gx/34472D_CS5536_B1_specupdate.pdf
505 +*/
506 +
507 +#define PM_IRQ 3
508 +
509 +#define CS5536_PM_PWRBTN (1 << 8)
510 +#define CS5536_PM_RTC    (1 << 10)
511 +#define CS5536_PM_WAK    (1 << 15)
512 +
513 +#define GPIO_WAKEUP_EC (1 << 31)
514 +#define GPIO_WAKEUP_LID (1 << 30)
515 +
516 +#define PM_MODE_NORMAL 0
517 +#define PM_MODE_TEST   1
518 +#define PM_MODE_MAX    2
519 +
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
523 +
524 +extern void do_olpc_suspend_lowlevel(void);
525 +
526 +static struct {
527 +       unsigned long address;
528 +       unsigned short segment;
529 +} ofw_bios_entry = { 0, __KERNEL_CS };
530 +
531 +static int olpc_pm_mode = PM_MODE_NORMAL;
532 +static unsigned long acpi_base;
533 +static unsigned long pms_base;
534 +static int sci_irq;
535 +static int olpc_lid_flag;
536 +
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;
541 +
542 +static int gpio_wake_events = 0;
543 +static int ebook_state = -1;
544 +static u16 olpc_wakeup_mask = 0;
545 +
546 +static unsigned int test_timeout = 0;
547 +static char *wackup_source = "none";
548 +
549 +struct platform_device olpc_powerbutton_dev = {
550 +       .name = "powerbutton",
551 +       .id = -1,
552 +};
553 +
554 +struct platform_device olpc_lid_dev = {
555 +       .name = "lid",
556 +       .id = -1,
557 +};
558 +
559 +static void __init init_ebook_state(void)
560 +{
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");
563 +               ebook_state = 0;
564 +       }
565 +       ebook_state &= 1;
566 +
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);
570 +}
571 +
572 +static void (*battery_callback)(unsigned long);
573 +static DEFINE_SPINLOCK(battery_callback_lock);
574 +
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)
578 +{
579 +       unsigned char data = 0;
580 +       unsigned char battery_events = 0;
581 +       int ret;
582 +
583 +       do {
584 +               ret = olpc_ec_cmd(0x84, NULL, 0, &data, 1);
585 +               if (!ret) {
586 +                       printk(KERN_DEBUG "olpc-pm:  SCI 0x%x received\n",
587 +                                       data);
588 +
589 +                       if (wackup_source && !strcmp(wackup_source, "sci")) {
590 +                               /*
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!
594 +                                */
595 +                               switch (data) {
596 +                               case EC_SCI_SRC_EMPTY:
597 +                                       wackup_source = "empty sci";
598 +                                       break;
599 +                               case EC_SCI_SRC_GAME:
600 +                                       wackup_source = "key press";
601 +                                       break;
602 +                               case EC_SCI_SRC_BATTERY:
603 +                                       wackup_source = "battery";
604 +                                       break;
605 +                               case EC_SCI_SRC_BATSOC:
606 +                                       wackup_source = "battery state change";
607 +                                       break;
608 +                               case EC_SCI_SRC_BATERR:
609 +                                       wackup_source = "battery error";
610 +                                       break;
611 +                               case EC_SCI_SRC_EBOOK:
612 +                                       wackup_source = "ebook";
613 +                                       break;
614 +                               case EC_SCI_SRC_WLAN:
615 +                                       wackup_source = "wlan packet";
616 +                                       break;
617 +                               case EC_SCI_SRC_ACPWR:
618 +                                       wackup_source = "ac power";
619 +                                       break;
620 +                               default:
621 +                                       wackup_source = "unknown";
622 +                               }
623 +                       }
624 +
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);
634 +                               }
635 +                       }
636 +               }
637 +       } while (data && !ret);
638 +
639 +       if (battery_events && battery_callback && propagate_events) {
640 +               void (*cbk)(unsigned long);
641 +               
642 +               /* Older EC versions didn't distinguish between AC and battery
643 +                  events */
644 +               if (olpc_platform_info.ecver < 0x51)
645 +                       battery_events = EC_SCI_SRC_BATTERY | EC_SCI_SRC_ACPWR;
646 +
647 +               spin_lock(&battery_callback_lock);
648 +               cbk = battery_callback;
649 +               spin_unlock(&battery_callback_lock);
650 +
651 +               cbk(battery_events);
652 +       }
653 +
654 +       if (ret)
655 +               printk(KERN_WARNING "Failed to clear SCI queue!\n");
656 +}
657 +
658 +static DECLARE_WORK(sci_work, process_sci_queue);
659 +
660 +void olpc_register_battery_callback(void (*f)(unsigned long))
661 +{
662 +       spin_lock(&battery_callback_lock);
663 +       battery_callback = f;
664 +       spin_unlock(&battery_callback_lock);
665 +}
666 +EXPORT_SYMBOL_GPL(olpc_register_battery_callback);
667 +
668 +void olpc_deregister_battery_callback(void)
669 +{
670 +       spin_lock(&battery_callback_lock);
671 +       battery_callback = NULL;
672 +       spin_unlock(&battery_callback_lock);
673 +       cancel_work_sync(&sci_work);
674 +}
675 +EXPORT_SYMBOL_GPL(olpc_deregister_battery_callback);
676 +
677 +
678 +static int olpc_pm_interrupt(int irq, void *id)
679 +{
680 +       uint32_t sts, gpe = 0;
681 +
682 +       sts = inl(acpi_base + PM1_STS);
683 +       outl(sts | 0xFFFF, acpi_base + PM1_STS);
684 +
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);
688 +       }
689 +
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);
701 +               }
702 +       }
703 +
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);
709 +       }
710 +
711 +       if (gpe & GPIO_WAKEUP_LID) {
712 +               /* Disable events */
713 +               geode_gpio_clear(OLPC_GPIO_LID, GPIO_EVENTS_ENABLE);
714 +                       
715 +               /* Clear the edge */
716 +                       
717 +               if (olpc_lid_flag)
718 +                       geode_gpio_clear(OLPC_GPIO_LID, GPIO_NEGATIVE_EDGE_EN);
719 +               else
720 +                       geode_gpio_clear(OLPC_GPIO_LID, GPIO_POSITIVE_EDGE_EN);
721 +
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);
725 +
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
729 +                */
730 +
731 +               input_report_switch(lid_inputdev, SW_LID, olpc_lid_flag);
732 +               input_sync(lid_inputdev);
733 +               if (!wackup_source)
734 +                       wackup_source = "lid";
735 +
736 +               /* Swap the status */
737 +               olpc_lid_flag = !olpc_lid_flag;
738 +
739 +               if (olpc_lid_flag)
740 +                       geode_gpio_set(OLPC_GPIO_LID, GPIO_NEGATIVE_EDGE_EN);
741 +               else
742 +                       geode_gpio_set(OLPC_GPIO_LID, GPIO_POSITIVE_EDGE_EN);
743 +
744 +               /* re-enable the event */
745 +               geode_gpio_set(OLPC_GPIO_LID, GPIO_EVENTS_ENABLE);
746 +       }
747 +
748 +       return IRQ_HANDLED;
749 +}
750 +
751 +int olpc_ec_mask_set(u8 bits)
752 +{
753 +       int ret;
754 +       u8 byte;
755 +
756 +       ret = olpc_ec_cmd(EC_READ_SCI_MASK, NULL, 0, &byte, 1);
757 +       if (ret) { 
758 +               printk(KERN_ERR "olpc-pm:  error getting SCI mask: %d\n", ret);
759 +               return ret;
760 +       }
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));
764 +
765 +       byte |= bits;
766 +       ret = olpc_ec_cmd(EC_WRITE_SCI_MASK, &byte, 1, NULL, 0);
767 +       if (ret)
768 +               printk(KERN_ERR "olpc-pm:  error setting SCI mask: %d\n", ret);
769 +
770 +       return ret;
771 +}
772 +EXPORT_SYMBOL_GPL(olpc_ec_mask_set);
773 +
774 +int olpc_ec_mask_unset(u8 bits)
775 +{
776 +       int ret;
777 +       u8 byte;
778 +
779 +       ret = olpc_ec_cmd(EC_READ_SCI_MASK, NULL, 0, &byte, 1);
780 +       if (ret) { 
781 +               printk(KERN_ERR "olpc-pm:  error getting SCI mask: %d\n", ret);
782 +               return ret;
783 +       }
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));
787 +
788 +       byte &= ~bits;
789 +       ret = olpc_ec_cmd(EC_WRITE_SCI_MASK, &byte, 1, NULL, 0);
790 +       if (ret)
791 +               printk(KERN_ERR "olpc-pm:  error setting SCI mask: %d\n", ret);
792 +
793 +       return ret;
794 +}
795 +EXPORT_SYMBOL_GPL(olpc_ec_mask_unset);
796 +
797 +/*
798 + * For now, only support STR.  We also don't support suspending on
799 + * B1s, due to difficulties with the cafe FPGA.
800 + */
801 +static int olpc_pm_state_valid(suspend_state_t pm_state)
802 +{
803 +        if (pm_state == PM_SUSPEND_MEM && olpc_board_at_least(olpc_board(0xb2)))
804 +                return 1;
805 +
806 +        return 0;
807 +}
808 +
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
813 + * a comment.
814 + */
815 +
816 +extern void gxfb_flatpanel_control(int state);
817 +
818 +static u32 gpio_wakeup[2];
819 +static u64 irq_sources[4];
820 +static u64 mfgpt_irq_msr, mfgpt_nr_msr;
821 +
822 +void olpc_fixup_wakeup(void)
823 +{
824 +       u32 base = geode_gpio_base();
825 +       int i;
826 +
827 +       /* Enable the flatpanel sequencing as early as possible, because
828 +          it takes ~64ms to resume.  This probably belongs in the firmware */
829 +
830 +       //gxfb_flatpanel_control(1);
831 +
832 +       /* Tell the EC to stop inhibiting SCIs */
833 +       olpc_ec_cmd(0x34, NULL, 0, NULL, 0);
834 +
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]);
840 +
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);
844 +
845 +       /* Resture the MFGPT MSRs */
846 +       wrmsrl(MFGPT_IRQ_MSR, mfgpt_irq_msr);
847 +       wrmsrl(MFGPT_NR_MSR, mfgpt_nr_msr);
848 +
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);
852 +       }
853 +
854 +       /* Turn all events on */
855 +       olpc_ec_mask_set(EC_SCI_SRC_ALL);
856 +}
857 +
858 +void olpc_fixup_sleep(void)
859 +{
860 +       u32 base = geode_gpio_base();
861 +       int i;
862 +
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);
866 +
867 +       /* Save the Y and Z  unrestricted sources */
868 +
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]);
873 +
874 +       /* Turn off the MFGPT timers on the way down */
875 +
876 +       for(i = 0; i < 8; i++) {
877 +               u32 val = geode_mfgpt_read(i, MFGPT_REG_SETUP);
878 +
879 +               if (val & MFGPT_SETUP_SETUP) {
880 +                       val &= ~MFGPT_SETUP_CNTEN;
881 +                       geode_mfgpt_write(i, MFGPT_REG_SETUP, val);
882 +               }
883 +       }
884 +
885 +       /* Save the MFGPT MSRs */
886 +       rdmsrl(MFGPT_IRQ_MSR, mfgpt_irq_msr);
887 +       rdmsrl(MFGPT_NR_MSR, mfgpt_nr_msr);
888 +
889 +       if (device_may_wakeup(&olpc_powerbutton_dev.dev))
890 +               olpc_wakeup_mask |= CS5536_PM_PWRBTN;
891 +       else
892 +               olpc_wakeup_mask &= ~(CS5536_PM_PWRBTN);
893 +
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;
897 +       } else {
898 +               geode_gpio_clear(OLPC_GPIO_LID, GPIO_EVENTS_ENABLE);
899 +               gpio_wake_events &= ~(GPIO_WAKEUP_LID);
900 +       }
901 +
902 +       /* We don't want to wake up on superfluous events */
903 +       olpc_ec_mask_unset(EC_SCI_SRC_BATSOC | EC_SCI_SRC_ACPWR);
904 +
905 +       /* 
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.
910 +        *
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
916 +        * doing.
917 +        */
918 +       olpc_ec_cmd(0x32, NULL, 0, NULL, 0);
919 +}
920 +
921 +static int olpc_pm_enter(suspend_state_t pm_state)
922 +{
923 +        /* Only STR is supported */
924 +        if (pm_state != PM_SUSPEND_MEM)
925 +                return -EINVAL;
926 +
927 +       olpc_fixup_sleep();
928 +
929 +       /* Set the GPIO wakeup bits */
930 +       outl(gpio_wake_events, acpi_base + PM_GPE0_EN);
931 +       outl(0xFFFFFFFF, acpi_base + PM_GPE0_STS);
932 +
933 +        /* Save CPU state */
934 +        do_olpc_suspend_lowlevel();
935 +
936 +       olpc_fixup_wakeup();
937 +
938 +       /* Restore the SCI wakeup events */
939 +       outl(gpio_wake_events, acpi_base + PM_GPE0_EN);
940 +
941 +       return 0;
942 +}
943 +
944 +int asmlinkage olpc_do_sleep(u8 sleep_state)
945 +{
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 */
951 +
952 +       /* FIXME:  Set any other SCI events that we might want here */
953 +
954 +       outl((olpc_wakeup_mask << 16) | 0xFFFF, acpi_base + PM1_STS);
955 +
956 +       wackup_source = NULL;
957 +
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 */
961 +
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");
970 +
971 +       }
972 +       else if (test_timeout > 0) {
973 +         int t;
974 +
975 +         /* Delay N seconds for testing purposes */
976 +
977 +         for(t = 0; t < test_timeout; t++)
978 +           mdelay(1000);
979 +       }
980 +
981 +       return 0;
982 +}
983 +
984 +static void olpc_power_off(void)
985 +{
986 +       printk(KERN_INFO "OLPC power off sequence...\n");
987 +
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);
993 +
994 +       /* Clear status bits (possibly unnecessary) */
995 +       outl(0x0002ffff, pms_base  + PM_SSC);
996 +       outl(0xffffffff, acpi_base + PM_GPE0_STS);
997 +
998 +       /* Write SLP_EN bit to start the machinery */
999 +       outl(0x00002000, acpi_base + PM1_CNT);
1000 +}
1001 +
1002 +/* This code will slowly disappear as we fixup the issues in the BIOS */
1003 +
1004 +static void __init olpc_fixup_bios(void)
1005 +{
1006 +       unsigned long hi, lo;
1007 +
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.
1012 +                */
1013 +
1014 +               /* Change the PM registers to decode to the DD */
1015 +
1016 +               rdmsr(0x510100e2, lo, hi);
1017 +               hi |= 0x80000000;
1018 +               wrmsr(0x510100e2, lo, hi);
1019 +
1020 +               /* Change the ACPI registers to decode to the DD */
1021 +
1022 +               rdmsr(0x510100e3, lo, hi);
1023 +               hi |= 0x80000000;
1024 +               wrmsr(0x510100e3, lo, hi);
1025 +       }
1026 +
1027 +       /* GPIO24 controls WORK_AUX */
1028 +
1029 +       geode_gpio_set(OLPC_GPIO_WORKAUX, GPIO_OUTPUT_ENABLE);
1030 +       geode_gpio_set(OLPC_GPIO_WORKAUX, GPIO_OUTPUT_AUX1);
1031 +
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);
1036 +
1037 +               /* Set up to get LID events */
1038 +               geode_gpio_set(OLPC_GPIO_LID, GPIO_INPUT_ENABLE);
1039 +
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);
1044 +
1045 +               geode_gpio_set(OLPC_GPIO_LID, GPIO_NEGATIVE_EDGE_STS);
1046 +               geode_gpio_set(OLPC_GPIO_LID, GPIO_POSITIVE_EDGE_STS);
1047 +
1048 +               /* Set the LID to cause an PME event on group 6 */
1049 +               geode_gpio_event_pme(OLPC_GPIO_LID, 6);
1050 +
1051 +               /* Set PME group 6 to fire the SCI interrupt */
1052 +               geode_gpio_set_irq(6, sci_irq);
1053 +       }
1054 +
1055 +       geode_gpio_set(OLPC_GPIO_ECSCI, GPIO_INPUT_ENABLE);
1056 +
1057 +       /* Clear pending events */
1058 +
1059 +       geode_gpio_set(OLPC_GPIO_ECSCI, GPIO_NEGATIVE_EDGE_STS);
1060 +       geode_gpio_set(OLPC_GPIO_ECSCI, GPIO_POSITIVE_EDGE_STS);
1061 +
1062 +       //geode_gpio_set(OLPC_GPIO_ECSCI, GPIO_NEGATIVE_EDGE_EN);
1063 +       geode_gpio_set(OLPC_GPIO_ECSCI, GPIO_EVENTS_ENABLE);
1064 +
1065 +       /* Set the SCI to cause a PME event on group 7 */
1066 +       geode_gpio_event_pme(OLPC_GPIO_ECSCI, 7);
1067 +
1068 +       /* And have group 6 also fire the SCI interrupt */
1069 +       geode_gpio_set_irq(7, sci_irq);
1070 +}
1071 +
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
1075 +   off routine.
1076 +*/
1077 +
1078 +static const char * const pm_states[] = {
1079 +       [PM_MODE_NORMAL]  = "normal",
1080 +       [PM_MODE_TEST]    = "test",
1081 +};
1082 +
1083 +extern struct mutex pm_mutex;
1084 +extern struct kset power_subsys;
1085 +
1086 +static ssize_t control_show(struct kset *s, char *buf)
1087 +{
1088 +       return sprintf(buf, "%s\n", pm_states[olpc_pm_mode]);
1089 +}
1090 +
1091 +static ssize_t control_store(struct kset *s, const char *buf, size_t n)
1092 +{
1093 +       int i, len;
1094 +       char *p;
1095 +
1096 +       p = memchr(buf, '\n', n);
1097 +       len = p ? p - buf : n;
1098 +
1099 +       /* Grab the mutex */
1100 +       mutex_lock(&pm_mutex);
1101 +       
1102 +       for(i = 0; i < PM_MODE_MAX; i++) {
1103 +               if (!strncmp(buf, pm_states[i], len)) {
1104 +                       olpc_pm_mode = i;
1105 +                       break;
1106 +               }
1107 +       }
1108 +
1109 +       mutex_unlock(&pm_mutex);
1110 +
1111 +       return (i == PM_MODE_MAX) ? -EINVAL : n;
1112 +}
1113 +       
1114 +static ssize_t timeout_show(struct kset *s, char *buf) 
1115 +{
1116 +       return sprintf(buf, "%d\n", test_timeout);
1117 +}
1118 +
1119 +static ssize_t timeout_store(struct kset *s, const char *buf, size_t n)
1120 +{
1121 +       unsigned int t = simple_strtoul(buf, NULL, 0);
1122 +       test_timeout = t;
1123 +
1124 +       return n;
1125 +}
1126 +
1127 +static ssize_t wackup_show(struct kset *s, char *buf)
1128 +{
1129 +       return sprintf(buf, "%s\n", wackup_source ? wackup_source : "none");
1130 +}
1131 +
1132 +static struct subsys_attribute control_attr = {
1133 +       .attr = {
1134 +               .name = "olpc-pm",
1135 +               .mode = 0644,
1136 +       },
1137 +       .show = control_show,
1138 +       .store = control_store,
1139 +};
1140 +
1141 +static struct subsys_attribute test_attr = {
1142 +       .attr = {
1143 +               .name = "test-timeout",
1144 +               .mode = 0644,
1145 +       },
1146 +       .show = timeout_show,
1147 +       .store = timeout_store,
1148 +};
1149 +
1150 +static struct subsys_attribute wackup_attr = {
1151 +       .attr = {
1152 +               .name = "wakeup-source",
1153 +               .mode = 0400,
1154 +       },
1155 +       .show = wackup_show,
1156 +};
1157 +
1158 +static struct attribute * olpc_attributes[] = {
1159 +       &control_attr.attr,
1160 +       &test_attr.attr,
1161 +       &wackup_attr.attr,
1162 +       NULL
1163 +};
1164 +
1165 +static struct attribute_group olpc_attrs = {
1166 +       .attrs = olpc_attributes,
1167 +};
1168 +
1169 +static int __init alloc_inputdevs(void)
1170 +{
1171 +       int ret = -ENOMEM;
1172 +
1173 +       pm_inputdev = input_allocate_device();
1174 +       if (!pm_inputdev)
1175 +               goto err;
1176 +
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);
1181 +
1182 +       ret = input_register_device(pm_inputdev);
1183 +       if (ret) {
1184 +               printk(KERN_ERR "olpc-pm:  failed to register PM input device: %d\n", ret);
1185 +               goto err;
1186 +       }
1187 +
1188 +       lid_inputdev = input_allocate_device();
1189 +       if (!lid_inputdev)
1190 +               goto err;
1191 +
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);
1196 +
1197 +       ret = input_register_device(lid_inputdev);
1198 +       if (ret) {
1199 +               printk(KERN_ERR "olpc-pm:  failed to register lid input device: %d\n", ret);
1200 +               goto err;
1201 +       }
1202 +
1203 +       ebook_inputdev = input_allocate_device();
1204 +       if (!ebook_inputdev)
1205 +               goto err;
1206 +
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);
1211 +
1212 +       ret = input_register_device(ebook_inputdev);
1213 +       if (ret) {
1214 +               printk(KERN_ERR "olpc-pm:  failed to register ebook input device: %d\n", ret);
1215 +               goto err;
1216 +       }
1217 +
1218 +       return ret;
1219 +err:
1220 +       if (ebook_inputdev) {
1221 +               input_unregister_device(ebook_inputdev);
1222 +               ebook_inputdev = NULL;
1223 +       }
1224 +       if (lid_inputdev) {
1225 +               input_unregister_device(lid_inputdev);
1226 +               lid_inputdev = NULL;
1227 +       }
1228 +       if (pm_inputdev) {
1229 +               input_unregister_device(pm_inputdev);
1230 +               pm_inputdev = NULL;
1231 +       }
1232 +
1233 +       return ret;
1234 +}
1235 +
1236 +static int __init olpc_pm_init(void)
1237 +{
1238 +       uint32_t lo, hi;
1239 +       int ret;
1240 +
1241 +       if (!machine_is_olpc())
1242 +               return -ENODEV;
1243 +
1244 +       acpi_base = geode_acpi_base();
1245 +       pms_base = geode_pms_base();
1246 +
1247 +       if (!acpi_base || !pms_base)
1248 +         return -ENODEV;
1249 +
1250 +       pm_power_off = olpc_power_off;
1251 +
1252 +       ret = alloc_inputdevs();
1253 +       if (ret)
1254 +               return ret;
1255 +
1256 +       rdmsr(0x51400020, lo, hi);
1257 +       sci_irq = (lo >> 20) & 15;
1258 +
1259 +       if (sci_irq) {
1260 +               printk(KERN_INFO "SCI is mapped to IRQ %d\n", sci_irq);
1261 +       } else {
1262 +               /* Zero doesn't mean zero -- it means masked */
1263 +               printk(KERN_INFO "SCI unmapped. Mapping to IRQ 3\n");
1264 +               sci_irq = 3;
1265 +               lo |= 0x00300000;
1266 +               wrmsrl(0x51400020, lo);
1267 +       }
1268 +
1269 +       olpc_fixup_bios();
1270 +
1271 +       lo = inl(pms_base + PM_FSD);
1272 +
1273 +       /* Lock, enable failsafe, 4 seconds */
1274 +       outl(0xc001f400, pms_base + PM_FSD);
1275 +
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
1279 +        */
1280 +
1281 +       outl(inl(acpi_base) | ((CS5536_PM_PWRBTN) << 16), acpi_base);
1282 +
1283 +       if (olpc_board_at_least(olpc_board(0xb2))) {
1284 +               gpio_wake_events |= GPIO_WAKEUP_LID;
1285 +
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);
1288 +
1289 +               /* Watch for the opposite edge */
1290 +
1291 +               if (olpc_lid_flag)
1292 +                       geode_gpio_set(OLPC_GPIO_LID, GPIO_NEGATIVE_EDGE_EN);
1293 +               else
1294 +                       geode_gpio_set(OLPC_GPIO_LID, GPIO_POSITIVE_EDGE_EN);
1295 +
1296 +               /* Enable the event */
1297 +               geode_gpio_set(OLPC_GPIO_LID, GPIO_EVENTS_ENABLE);
1298 +       }
1299 +
1300 +       /* Set up the EC SCI */
1301 +
1302 +       gpio_wake_events |= GPIO_WAKEUP_EC;
1303 +
1304 +       outl(gpio_wake_events, acpi_base + PM_GPE0_EN);
1305 +       outl(0xFFFFFFFF, acpi_base + PM_GPE0_STS);
1306 +
1307 +       /* Select level triggered in PIC */
1308 +
1309 +       if (sci_irq < 8) {
1310 +               lo = inb(0x4d0);
1311 +               lo |= 1 << sci_irq;
1312 +               outb(lo, 0x4d0);
1313 +       } else {
1314 +               lo = inb(0x4d1);
1315 +               lo |= 1 << (sci_irq - 8);
1316 +               outb(lo, 0x4d1);
1317 +       }
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();
1322 +
1323 +       /* Enable the interrupt */
1324 +
1325 +       ret = request_irq(sci_irq, &olpc_pm_interrupt, 0, "SCI", &acpi_base);
1326 +
1327 +       if (ret) {
1328 +               printk(KERN_ERR "Error registering SCI: %d\n", ret);
1329 +               return ret;
1330 +       }
1331 +
1332 +       ofw_bios_entry.address = 0xF0000 + PAGE_OFFSET;
1333 +       suspend_set_ops(&olpc_pm_ops);
1334 +
1335 +       sysfs_create_group(&power_subsys.kobj, &olpc_attrs);
1336 +
1337 +       return 0;
1338 +}
1339 +
1340 +
1341 +#if defined (CONFIG_RTC_DRV_CMOS) || defined (CONFIG_RTC_DRV_CMOS_MODULE)
1342 +struct resource rtc_platform_resource[2] = {
1343 +       {
1344 +               .flags          = IORESOURCE_IO,
1345 +               .start          = RTC_PORT(0),
1346 +               .end            = RTC_PORT(0) + RTC_IO_EXTENT
1347 +       },
1348 +       {
1349 +               .flags = IORESOURCE_IRQ,
1350 +               .start = 8,
1351 +               .end = 8,
1352 +       },
1353 +};
1354 +
1355 +
1356 +static void rtc_wake_on(struct device *dev)
1357 +{
1358 +       olpc_wakeup_mask |= CS5536_PM_RTC;
1359 +}
1360 +
1361 +static void rtc_wake_off(struct device *dev)
1362 +{
1363 +       olpc_wakeup_mask &= ~(CS5536_PM_RTC);
1364 +}
1365 +
1366 +static struct cmos_rtc_board_info rtc_info = {
1367 +       .rtc_day_alarm = 0,
1368 +       .rtc_mon_alarm = 0,
1369 +       .rtc_century = 0,
1370 +       .wake_on = rtc_wake_on,
1371 +       .wake_off = rtc_wake_off,
1372 +};
1373 +
1374 +struct platform_device olpc_rtc_device = {
1375 +       .name = "rtc_cmos",
1376 +       .id = -1,
1377 +       .num_resources = ARRAY_SIZE(rtc_platform_resource),
1378 +       .dev.platform_data = &rtc_info,
1379 +       .resource = rtc_platform_resource,
1380 +};
1381 +
1382 +static int __init olpc_platform_init(void)
1383 +{
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);
1387 +
1388 +       (void)platform_device_register(&olpc_rtc_device);
1389 +       device_init_wakeup(&olpc_rtc_device.dev, 1);
1390 +
1391 +       (void)platform_device_register(&olpc_powerbutton_dev);
1392 +       device_init_wakeup(&olpc_powerbutton_dev.dev, 1);
1393 +
1394 +       (void)platform_device_register(&olpc_lid_dev);
1395 +       device_init_wakeup(&olpc_lid_dev.dev, 1);
1396 +
1397 +       return 0;
1398 +}
1399 +arch_initcall(olpc_platform_init);
1400 +#endif /* CONFIG_RTC_DRV_CMOS */
1401 +
1402 +static void olpc_pm_exit(void)
1403 +{
1404 +       /* Clear any pending events, and disable them */
1405 +       outl(0xFFFF, acpi_base+2);
1406 +
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);
1411 +}
1412 +
1413 +static struct platform_suspend_ops olpc_pm_ops = {
1414 +        .valid = olpc_pm_state_valid,
1415 +        .enter = olpc_pm_enter,
1416 +};
1417 +
1418 +module_init(olpc_pm_init);
1419 +module_exit(olpc_pm_exit);
1420 +
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 ===================================================================
1426 --- /dev/null
1427 +++ linux-2.6.24.7/arch/x86/kernel/olpc-sleep.S
1428 @@ -0,0 +1,39 @@
1429 +.text
1430 +
1431 +ENTRY(olpc_sleep_asm)
1432 +olpc_sleep:
1433 +       ;; Get the value of PM1_CNT and store it off
1434 +       
1435 +       add 08h, ax
1436 +       mov bx,dx
1437 +       in dx,eax
1438 +       or 2000h, ax
1439 +       mov ax,di
1440 +       
1441 +       ;; flush the cache
1442 +       wbinvd
1443 +
1444 +       ;; GX2 must disable refresh before going into self-refresh 
1445 +       mov 2000000180xh, ecx
1446 +       rdmsr
1447 +       mov eax, esi
1448 +       and 0FF0000FFh, eax
1449 +       wrmsr
1450 +
1451 +       ;; Now, put  the memory into self refresh
1452 +       mov 2004, cx
1453 +       xor edx, edx
1454 +       xor eax, eax
1455 +       mov 04h, al
1456 +       wrmsr
1457 +
1458 +       ;; Thats all she wrote - time to go to sleep
1459 +       
1460 +       mov bx, dx
1461 +       movzx di, eax
1462 +       out eax, dx
1463 +
1464 +       ;;  
1465 +       
1466 +       
1467 +       
1468 Index: linux-2.6.24.7/arch/x86/kernel/olpc-wakeup.S
1469 ===================================================================
1470 --- /dev/null
1471 +++ linux-2.6.24.7/arch/x86/kernel/olpc-wakeup.S
1472 @@ -0,0 +1,133 @@
1473 +.text
1474 +#include <linux/linkage.h>
1475 +#include <asm/segment.h>
1476 +#include <asm/page.h>
1477 +
1478 +       .macro writepost,value
1479 +               movb $0x34, %al
1480 +               outb %al, $0x70
1481 +               movb $\value, %al
1482 +               outb %al, $0x71
1483 +       .endm
1484 +       
1485 +ALIGN
1486 +       .align 4096
1487 +
1488 +wakeup_start:
1489 +#      jmp wakeup_start
1490 +
1491 +       cli
1492 +       cld
1493 +
1494 +       # Clear any dangerous flags
1495 +       
1496 +       pushl $0
1497 +       popfl
1498 +               
1499 +       writepost 0x31
1500 +
1501 +       # Set up %cr3
1502 +       movl $swsusp_pg_dir - __PAGE_OFFSET, %eax
1503 +       movl %eax, %cr3
1504 +
1505 +       movl saved_cr4, %eax
1506 +       movl %eax, %cr4
1507 +       
1508 +       movl saved_cr0, %eax
1509 +       movl %eax, %cr0
1510 +       
1511 +       jmp 1f
1512 +1:     
1513 +       ljmpl $__KERNEL_CS,$wakeup_return
1514 +       
1515 +
1516 +.org 0x1000
1517 +
1518 +wakeup_return:
1519 +       movw    $__KERNEL_DS, %ax
1520 +       movw    %ax, %ss
1521 +       movw    %ax, %ds
1522 +       movw    %ax, %es
1523 +       movw    %ax, %fs
1524 +       movw    %ax, %gs
1525 +       
1526 +       lgdt    saved_gdt
1527 +       lidt    saved_idt
1528 +       lldt    saved_ldt
1529 +       ljmp    $(__KERNEL_CS),$1f
1530 +1:
1531 +       movl    %cr3, %eax
1532 +       movl    %eax, %cr3
1533 +       wbinvd
1534 +
1535 +       # Go back to the return point
1536 +       jmp ret_point
1537 +       
1538 +save_registers:
1539 +       sgdt  saved_gdt
1540 +       sidt  saved_idt
1541 +       sldt  saved_ldt
1542 +
1543 +       pushl %edx
1544 +       movl %cr4, %edx
1545 +       movl %edx, saved_cr4
1546 +
1547 +       movl %cr0, %edx
1548 +       movl %edx, saved_cr0
1549 +
1550 +       popl %edx
1551 +               
1552 +       
1553 +        movl %ebx, saved_context_ebx
1554 +        movl %ebp, saved_context_ebp
1555 +        movl %esi, saved_context_esi
1556 +        movl %edi, saved_context_edi
1557 +
1558 +       pushfl
1559 +       popl saved_context_eflags
1560 +       
1561 +        ret
1562 +
1563 +
1564 +restore_registers:
1565 +        movl saved_context_ebp, %ebp
1566 +        movl saved_context_ebx, %ebx
1567 +        movl saved_context_esi, %esi
1568 +        movl saved_context_edi, %edi
1569 +
1570 +       pushl saved_context_eflags
1571 +       popfl
1572 +       
1573 +        ret
1574 +
1575 +       
1576 +ENTRY(do_olpc_suspend_lowlevel)
1577 +       call    save_processor_state
1578 +       call    save_registers
1579 +
1580 +       # This is the stack context we want to remember
1581 +       movl %esp, saved_context_esp
1582 +
1583 +       pushl   $3
1584 +       call    olpc_do_sleep
1585 +       
1586 +       jmp     wakeup_start
1587 +       .p2align 4,,7
1588 +ret_point:
1589 +       movl    saved_context_esp, %esp
1590 +
1591 +       writepost 0x32
1592 +
1593 +       call    restore_registers
1594 +       call    restore_processor_state
1595 +       ret
1596 +
1597 +.data
1598 +ALIGN
1599 +
1600 +saved_gdt:     .long   0,0
1601 +saved_idt:     .long   0,0
1602 +saved_ldt:     .long   0
1603 +saved_cr4:     .long   0
1604 +saved_cr0:     .long   0
1605 +
1606 Index: linux-2.6.24.7/arch/x86/kernel/prom.c
1607 ===================================================================
1608 --- /dev/null
1609 +++ linux-2.6.24.7/arch/x86/kernel/prom.c
1610 @@ -0,0 +1,478 @@
1611 +/*
1612 + * Procedures for creating, accessing and interpreting the device tree.
1613 + *
1614 + * Paul Mackerras      August 1996.
1615 + * Copyright (C) 1996-2005 Paul Mackerras.
1616 + * 
1617 + *  Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
1618 + *    {engebret|bergner}@us.ibm.com 
1619 + *
1620 + *  Adapted for sparc64 by David S. Miller davem@davemloft.net
1621 + *
1622 + *  Adapter for i386/OLPC by Andres Salomon <dilinger@debian.org>
1623 + *
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.
1628 + */
1629 +
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>
1638 +
1639 +/*
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
1642 + * for long!
1643 + */
1644 +
1645 +static struct device_node *allnodes;
1646 +
1647 +/* use when traversing tree through the allnext, child, sibling,
1648 + * or parent members of struct device_node.
1649 + */
1650 +static DEFINE_RWLOCK(devtree_lock);
1651 +
1652 +int of_device_is_compatible(const struct device_node *device,
1653 +                           const char *compat)
1654 +{
1655 +       const char* cp;
1656 +       int cplen, l;
1657 +
1658 +       cp = of_get_property(device, "compatible", &cplen);
1659 +       if (cp == NULL)
1660 +               return 0;
1661 +       while (cplen > 0) {
1662 +               if (strncmp(cp, compat, strlen(compat)) == 0)
1663 +                       return 1;
1664 +               l = strlen(cp) + 1;
1665 +               cp += l;
1666 +               cplen -= l;
1667 +       }
1668 +
1669 +       return 0;
1670 +}
1671 +EXPORT_SYMBOL(of_device_is_compatible);
1672 +
1673 +struct device_node *of_get_parent(const struct device_node *node)
1674 +{
1675 +       struct device_node *np;
1676 +
1677 +       if (!node)
1678 +               return NULL;
1679 +
1680 +       np = node->parent;
1681 +
1682 +       return np;
1683 +}
1684 +EXPORT_SYMBOL(of_get_parent);
1685 +
1686 +struct device_node *of_get_next_child(const struct device_node *node,
1687 +       struct device_node *prev)
1688 +{
1689 +       struct device_node *next;
1690 +
1691 +       next = prev ? prev->sibling : node->child;
1692 +       for (; next != 0; next = next->sibling) {
1693 +               break;
1694 +       }
1695 +
1696 +       return next;
1697 +}
1698 +EXPORT_SYMBOL(of_get_next_child);
1699 +
1700 +struct device_node *of_find_node_by_path(const char *path)
1701 +{
1702 +       struct device_node *np = allnodes;
1703 +
1704 +       for (; np != 0; np = np->allnext) {
1705 +               if (np->full_name != 0 && strcmp(np->full_name, path) == 0)
1706 +                       break;
1707 +       }
1708 +
1709 +       return np;
1710 +}
1711 +EXPORT_SYMBOL(of_find_node_by_path);
1712 +
1713 +struct device_node *of_find_node_by_phandle(phandle handle)
1714 +{
1715 +       struct device_node *np;
1716 +
1717 +       for (np = allnodes; np != 0; np = np->allnext)
1718 +               if (np->node == handle)
1719 +                       break;
1720 +
1721 +       return np;
1722 +}
1723 +EXPORT_SYMBOL(of_find_node_by_phandle);
1724 +
1725 +struct device_node *of_find_node_by_name(struct device_node *from,
1726 +       const char *name)
1727 +{
1728 +       struct device_node *np;
1729 +
1730 +       np = from ? from->allnext : allnodes;
1731 +       for (; np != NULL; np = np->allnext)
1732 +               if (np->name != NULL && strcmp(np->name, name) == 0)
1733 +                       break;
1734 +
1735 +       return np;
1736 +}
1737 +EXPORT_SYMBOL(of_find_node_by_name);
1738 +
1739 +struct device_node *of_find_node_by_type(struct device_node *from,
1740 +       const char *type)
1741 +{
1742 +       struct device_node *np;
1743 +
1744 +       np = from ? from->allnext : allnodes;
1745 +       for (; np != 0; np = np->allnext)
1746 +               if (np->type != 0 && strcmp(np->type, type) == 0)
1747 +                       break;
1748 +
1749 +       return np;
1750 +}
1751 +EXPORT_SYMBOL(of_find_node_by_type);
1752 +
1753 +struct device_node *of_find_compatible_node(struct device_node *from,
1754 +       const char *type, const char *compatible)
1755 +{
1756 +       struct device_node *np;
1757 +
1758 +       np = from ? from->allnext : allnodes;
1759 +       for (; np != 0; np = np->allnext) {
1760 +               if (type != NULL
1761 +                   && !(np->type != 0 && strcmp(np->type, type) == 0))
1762 +                       continue;
1763 +               if (of_device_is_compatible(np, compatible))
1764 +                       break;
1765 +       }
1766 +
1767 +       return np;
1768 +}
1769 +EXPORT_SYMBOL(of_find_compatible_node);
1770 +
1771 +struct property *of_find_property(const struct device_node *np,
1772 +                                 const char *name,
1773 +                                 int *lenp)
1774 +{
1775 +       struct property *pp;
1776 +
1777 +       for (pp = np->properties; pp != 0; pp = pp->next) {
1778 +               if (strcasecmp(pp->name, name) == 0) {
1779 +                       if (lenp != 0)
1780 +                               *lenp = pp->length;
1781 +                       break;
1782 +               }
1783 +       }
1784 +       return pp;
1785 +}
1786 +EXPORT_SYMBOL(of_find_property);
1787 +
1788 +/*
1789 + * Find a property with a given name for a given node
1790 + * and return the value.
1791 + */
1792 +const void *of_get_property(const struct device_node *np, const char *name,
1793 +                     int *lenp)
1794 +{
1795 +       struct property *pp = of_find_property(np,name,lenp);
1796 +       return pp ? pp->value : NULL;
1797 +}
1798 +EXPORT_SYMBOL(of_get_property);
1799 +
1800 +int of_getintprop_default(struct device_node *np, const char *name, int def)
1801 +{
1802 +       struct property *prop;
1803 +       int len;
1804 +
1805 +       prop = of_find_property(np, name, &len);
1806 +       if (!prop || len != 4)
1807 +               return def;
1808 +
1809 +       return *(int *) prop->value;
1810 +}
1811 +EXPORT_SYMBOL(of_getintprop_default);
1812 +
1813 +int of_n_addr_cells(struct device_node *np)
1814 +{
1815 +       const int* ip;
1816 +       do {
1817 +               if (np->parent)
1818 +                       np = np->parent;
1819 +               ip = of_get_property(np, "#address-cells", NULL);
1820 +               if (ip != NULL)
1821 +                       return *ip;
1822 +       } while (np->parent);
1823 +       /* No #address-cells property for the root node, default to 2 */
1824 +       return 2;
1825 +}
1826 +EXPORT_SYMBOL(of_n_addr_cells);
1827 +
1828 +int of_n_size_cells(struct device_node *np)
1829 +{
1830 +       const int* ip;
1831 +       do {
1832 +               if (np->parent)
1833 +                       np = np->parent;
1834 +               ip = of_get_property(np, "#size-cells", NULL);
1835 +               if (ip != NULL)
1836 +                       return *ip;
1837 +       } while (np->parent);
1838 +       /* No #size-cells property for the root node, default to 1 */
1839 +       return 1;
1840 +}
1841 +EXPORT_SYMBOL(of_n_size_cells);
1842 +
1843 +int of_set_property(struct device_node *dp, const char *name, void *val, int len)
1844 +{
1845 +       return -EIO;
1846 +}
1847 +EXPORT_SYMBOL(of_set_property);
1848 +
1849 +static unsigned int prom_early_allocated;
1850 +
1851 +static void * __init prom_early_alloc(unsigned long size)
1852 +{
1853 +       void *ret;
1854 +
1855 +       ret = kmalloc(size, GFP_KERNEL);
1856 +       if (ret != NULL)
1857 +               memset(ret, 0, size);
1858 +       else
1859 +               printk(KERN_ERR "ACK!  couldn't allocate prom memory!\n");
1860 +
1861 +       prom_early_allocated += size;
1862 +
1863 +       return ret;
1864 +}
1865 +
1866 +static int is_root_node(const struct device_node *dp)
1867 +{
1868 +       if (!dp)
1869 +               return 0;
1870 +
1871 +       return (dp->parent == NULL);
1872 +}
1873 +
1874 +static char * __init build_path_component(struct device_node *dp)
1875 +{
1876 +       int pathlen;
1877 +       char *n, *i;
1878 +
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");
1881 +               return "ERROR";
1882 +       }
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");
1886 +
1887 +       if ((i = strrchr(n, '/')))
1888 +               n = ++i;        /* we only want the file name */
1889 +       return n;
1890 +}
1891 +
1892 +static char * __init build_full_name(struct device_node *dp)
1893 +{
1894 +       int len, ourlen, plen;
1895 +       char *n;
1896 +
1897 +       plen = strlen(dp->parent->full_name);
1898 +       ourlen = strlen(dp->path_component_name);
1899 +       len = ourlen + plen + 2;
1900 +
1901 +       n = prom_early_alloc(len);
1902 +       strcpy(n, dp->parent->full_name);
1903 +       if (!is_root_node(dp->parent)) {
1904 +               strcpy(n + plen, "/");
1905 +               plen++;
1906 +       }
1907 +       strcpy(n + plen, dp->path_component_name);
1908 +
1909 +       return n;
1910 +}
1911 +
1912 +static struct property * __init build_one_prop(phandle node, char *prev, char *special_name, void *special_val, int special_len)
1913 +{
1914 +       static struct property *tmp = NULL;
1915 +       struct property *p;
1916 +
1917 +       if (tmp) {
1918 +               p = tmp;
1919 +               memset(p, 0, sizeof(*p) + 32);
1920 +               tmp = NULL;
1921 +       } else {
1922 +               p = prom_early_alloc(sizeof(struct property) + 32);
1923 +       }
1924 +
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);
1931 +       } else {
1932 +               int fl;
1933 +               if (prev == NULL) {
1934 +                       if (ofw("nextprop", 3, 1, node, "", p->name, &fl)) {
1935 +                               printk(KERN_ERR "PROM: %s: nextprop failed!\n", __func__);
1936 +                               return NULL;
1937 +                       }
1938 +               } else {
1939 +                       if (ofw("nextprop", 3, 1, node, prev, p->name, &fl)) {
1940 +                               printk(KERN_ERR "PROM: %s: nextprop failed!\n", __func__);
1941 +                               return NULL;
1942 +                       }
1943 +               }
1944 +               if (strlen(p->name) == 0 || fl != 1) {
1945 +                       tmp = p;
1946 +                       return NULL;
1947 +               }
1948 +               if (ofw("getproplen", 2, 1, node, p->name, &p->length)) {
1949 +                       printk(KERN_ERR "PROM: %s: getproplen failed!\n", __func__);
1950 +                       return NULL;
1951 +               }
1952 +               if (p->length <= 0) {
1953 +                       p->length = 0;
1954 +               } else {
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__);
1958 +                               return NULL;
1959 +                       }
1960 +                       ((unsigned char *)p->value)[p->length] = '\0';
1961 +               }
1962 +       }
1963 +       return p;
1964 +}
1965 +
1966 +static struct property * __init build_prop_list(phandle node)
1967 +{
1968 +       struct property *head, *tail;
1969 +
1970 +       head = tail = build_one_prop(node, NULL,
1971 +                                    ".node", &node, sizeof(node));
1972 +
1973 +       tail->next = build_one_prop(node, NULL, NULL, NULL, 0);
1974 +       tail = tail->next;
1975 +       while(tail) {
1976 +               tail->next = build_one_prop(node, tail->name,
1977 +                                           NULL, NULL, 0);
1978 +               tail = tail->next;
1979 +       }
1980 +
1981 +       return head;
1982 +}
1983 +
1984 +static char * __init get_one_property(phandle node, const char *name)
1985 +{
1986 +       char *buf = "<NULL>";
1987 +       int len;
1988 +
1989 +       if (ofw("getproplen", 2, 1, node, name, &len)) {
1990 +               printk(KERN_ERR "PROM: %s: getproplen failed!\n", __func__);
1991 +               return NULL;
1992 +       }
1993 +       if (len > 0) {
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__);
1997 +                       return NULL;
1998 +               }
1999 +       }
2000 +
2001 +       return buf;
2002 +}
2003 +
2004 +static struct device_node * __init create_node(phandle node, struct device_node *parent)
2005 +{
2006 +       struct device_node *dp;
2007 +
2008 +       if (!node)
2009 +               return NULL;
2010 +
2011 +       dp = prom_early_alloc(sizeof(*dp));
2012 +       dp->parent = parent;
2013 +
2014 +       kref_init(&dp->kref);
2015 +
2016 +       dp->name = get_one_property(node, "name");
2017 +       dp->type = get_one_property(node, "device_type");
2018 +       dp->node = node;
2019 +
2020 +       dp->properties = build_prop_list(node);
2021 +
2022 +       return dp;
2023 +}
2024 +
2025 +static struct device_node * __init build_tree(struct device_node *parent, phandle node, struct device_node ***nextp)
2026 +{
2027 +       struct device_node *ret = NULL, *prev_sibling = NULL;
2028 +       struct device_node *dp;
2029 +       u32 child;
2030 +
2031 +       while (1) {
2032 +               dp = create_node(node, parent);
2033 +               if (!dp)
2034 +                       break;
2035 +
2036 +               if (prev_sibling)
2037 +                       prev_sibling->sibling = dp;
2038 +
2039 +               if (!ret)
2040 +                       ret = dp;
2041 +               prev_sibling = dp;
2042 +
2043 +               *(*nextp) = dp;
2044 +               *nextp = &dp->allnext;
2045 +
2046 +               dp->path_component_name = build_path_component(dp);
2047 +               dp->full_name = build_full_name(dp);
2048 +
2049 +               if (ofw("child", 1, 1, node, &child)) {
2050 +                       printk(KERN_ERR "PROM: %s: fetching child failed!\n", __func__);
2051 +                       return NULL;
2052 +               }
2053 +               dp->child = build_tree(dp, child, nextp);
2054 +
2055 +               if (ofw("peer", 1, 1, node, &node)) {
2056 +                       printk(KERN_ERR "PROM: %s: fetching peer failed!\n", __func__);
2057 +                       return NULL;
2058 +               }
2059 +       }
2060 +
2061 +       return ret;
2062 +}
2063 +
2064 +static phandle root_node;
2065 +
2066 +void __init prom_build_devicetree(void)
2067 +{
2068 +       struct device_node **nextp;
2069 +       u32 child;
2070 +
2071 +       if (ofw("peer", 1, 1, 0, &root_node)) {
2072 +               printk(KERN_ERR "PROM: unable to get root node from OFW!\n");
2073 +               return;
2074 +       }
2075 +
2076 +       allnodes = create_node(root_node, NULL);
2077 +       allnodes->path_component_name = "";
2078 +       allnodes->full_name = "/";
2079 +
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");
2083 +               return;
2084 +       }
2085 +       allnodes->child = build_tree(allnodes, child, &nextp);
2086 +       printk("PROM: Built device tree with %u bytes of memory.\n",
2087 +              prom_early_allocated);
2088 +}
2089 Index: linux-2.6.24.7/arch/x86/pci/olpc.c
2090 ===================================================================
2091 --- /dev/null
2092 +++ linux-2.6.24.7/arch/x86/pci/olpc.c
2093 @@ -0,0 +1,298 @@
2094 +/*
2095 + * olpcpci.c - Low-level PCI config space access for OLPC systems
2096 + * without the VSA PCI virtualization software.
2097 + *
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.
2112 + */
2113 +
2114 +#include <linux/pci.h>
2115 +#include <linux/init.h>
2116 +#include <asm/olpc.h>
2117 +#include <asm/geode.h>
2118 +#include "pci.h"
2119 +
2120 +static int is_lx;
2121 +
2122 +/*
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.
2127 + *
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.
2131 + */
2132 +
2133 +static const u32 lxnb_hdr[] = {  /* dev 1 function 0 - devfn = 8 */
2134 +         0x0 ,        0x0 ,        0x0 ,        0x0 ,
2135 +         0x0 ,        0x0 ,        0x0 ,        0x0 ,
2136 +
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 ,
2144 +};
2145 +
2146 +static const u32 gxnb_hdr[] = {  /* dev 1 function 0 - devfn = 8 */
2147 +  0xfffffffd ,        0x0 ,        0x0 ,        0x0 ,
2148 +         0x0 ,        0x0 ,        0x0 ,        0x0 ,
2149 +
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 ,
2157 +};
2158 +
2159 +static const u32 lxfb_hdr[] = {  /* dev 1 function 1 - devfn = 9 */
2160 +  0xff800008 , 0xffffc000 , 0xffffc000 , 0xffffc000 ,
2161 +         0x0 ,        0x0 ,        0x0 ,        0x0 ,
2162 +
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 ,
2170 +};
2171 +
2172 +static const u32 gxfb_hdr[] = {  /* dev 1 function 1 - devfn = 9 */
2173 +  0xff800008 , 0xffffc000 , 0xffffc000 , 0xffffc000 ,
2174 +         0x0 ,        0x0 ,        0x0 ,        0x0 ,
2175 +
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 ,
2183 +};
2184 +
2185 +static const u32 aes_hdr[] = { /* dev 1 function 2 - devfn = 0xa */
2186 +  0xffffc000 ,        0x0 ,        0x0 ,        0x0 ,
2187 +         0x0 ,        0x0 ,        0x0 ,        0x0 ,
2188 +
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 ,
2196 +};
2197 +
2198 +
2199 +static const u32 isa_hdr[] = {  /* dev f function 0 - devfn = 78 */
2200 +  0xfffffff9 , 0xffffff01 , 0xffffffc1 , 0xffffffe1 ,
2201 +  0xffffff81 , 0xffffffc1 ,        0x0 ,        0x0 ,
2202 +
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 ,
2210 +};
2211 +
2212 +static const u32 ac97_hdr[] = {  /* dev f function 3 - devfn = 7b */
2213 +  0xffffff81 ,        0x0 ,        0x0 ,        0x0 ,
2214 +         0x0 ,        0x0 ,        0x0 ,        0x0 ,
2215 +
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 ,
2223 +};
2224 +
2225 +static const u32 ohci_hdr[] = {  /* dev f function 4 - devfn = 7c */
2226 +  0xfffff000 ,        0x0 ,        0x0 ,        0x0 ,
2227 +         0x0 ,        0x0 ,        0x0 ,        0x0 ,
2228 +
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 ,
2236 +};
2237 +
2238 +static const u32 ehci_hdr[] = {  /* dev f function 4 - devfn = 7d */
2239 +  0xfffff000 ,        0x0 ,        0x0 ,        0x0 ,
2240 +         0x0 ,        0x0 ,        0x0 ,        0x0 ,
2241 +
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) */
2247 +#if 0
2248 +         0x1 , 0x40080000 ,        0x0 ,        0x0 , /* EECP - see section 2.1.7 of EHCI spec */
2249 +#endif
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  */
2252 +};
2253 +
2254 +static u32 ff_loc    = ~0;
2255 +static u32 zero_loc  =  0;
2256 +
2257 +static int bar_probing = 0;       /* Set after a write of ~0 to a BAR */
2258 +
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)))
2262 +
2263 +static u32 *hdr_addr(const u32 *hdr, int reg)
2264 +{
2265 +       u32 addr;
2266 +
2267 +       /*
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.
2276 +        */
2277 +
2278 +       addr = (u32)hdr + reg + (bar_probing ? -0x10 : 0x20);
2279 +
2280 +       bar_probing = 0;
2281 +       return (u32 *)addr;
2282 +}
2283 +
2284 +static int pci_olpc_read(unsigned int seg, unsigned int bus,
2285 +               unsigned int devfn, int reg, int len, u32 *value)
2286 +{
2287 +       u32 *addr;
2288 +
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);
2292 +
2293 +       /*
2294 +        * No device has config registers past 0x70, so we save table space
2295 +        * by not storing entries for the nonexistent registers
2296 +        */
2297 +       if (reg >= 0x70)
2298 +               addr = &zero_loc;
2299 +       else {
2300 +               switch (devfn) {
2301 +                       case  0x8:
2302 +                               addr = hdr_addr(is_lx ? lxnb_hdr : gxnb_hdr, reg);
2303 +                               break;
2304 +                       case  0x9:
2305 +                               addr = hdr_addr(is_lx ? lxfb_hdr : gxfb_hdr, reg);
2306 +                               break;
2307 +                       case  0xa:
2308 +                               addr = is_lx ? hdr_addr(aes_hdr, reg) : &ff_loc;
2309 +                               break;
2310 +                       case 0x78:
2311 +                               addr = hdr_addr(isa_hdr, reg);
2312 +                               break;
2313 +                       case 0x7b:
2314 +                               addr = hdr_addr(ac97_hdr, reg);
2315 +                               break;
2316 +                       case 0x7c:
2317 +                               addr = hdr_addr(ohci_hdr, reg);
2318 +                               break;
2319 +                       case 0x7d:
2320 +                               addr = hdr_addr(ehci_hdr, reg);
2321 +                               break;
2322 +                       default:
2323 +                               addr = &ff_loc;
2324 +                               break;
2325 +               }
2326 +       }
2327 +       switch (len) {
2328 +               case 1:
2329 +                       *value = *(u8 *) addr;
2330 +                       break;
2331 +               case 2:
2332 +                       *value = *(u16 *) addr;
2333 +                       break;
2334 +               case 4:
2335 +                       *value = *addr;
2336 +                       break;
2337 +               default:
2338 +                       BUG();
2339 +       }
2340 +
2341 +       return 0;
2342 +}
2343 +
2344 +static int pci_olpc_write(unsigned int seg, unsigned int bus,
2345 +               unsigned int devfn, int reg, int len, u32 value)
2346 +{
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);
2350 +
2351 +       /* XXX we may want to extend this to simulate EHCI power management */
2352 +
2353 +       /*
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.
2359 +        */
2360 +
2361 +       if ((reg >= 0x10) && (reg < 0x2c)) {
2362 +               /* Write is to a BAR */
2363 +               if (value == ~0)
2364 +                       bar_probing = 1;
2365 +       } else {
2366 +               /*
2367 +                * No warning on writes to ROM BAR, CMD, LATENCY_TIMER,
2368 +                * CACHE_LINE_SIZE, or PM registers.
2369 +                */
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);
2373 +       }
2374 +
2375 +       return 0;
2376 +}
2377 +
2378 +static struct pci_raw_ops pci_olpc_conf = {
2379 +       .read =         pci_olpc_read,
2380 +       .write =        pci_olpc_write,
2381 +};
2382 +
2383 +void __init pci_olpc_init(void)
2384 +{
2385 +       if (!machine_is_olpc() || olpc_has_vsa())
2386 +               return;
2387 +
2388 +       printk(KERN_INFO "PCI: Using configuration type OLPC\n");
2389 +       raw_pci_ops = &pci_olpc_conf;
2390 +       is_lx = is_geode_lx();
2391 +}
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. 
2397  
2398         nr_uarts=       [SERIAL] maximum number of UARTs to be registered.
2399  
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!
2406 +
2407         opl3=           [HW,OSS]
2408                         Format: <io>
2409  
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
2415         if (drv) {
2416                 driver_sysfs_remove(dev);
2417                 sysfs_remove_link(&dev->kobj, "driver");
2418 -               klist_remove(&dev->knode_driver);
2419  
2420                 if (dev->bus)
2421                         blocking_notifier_call_chain(&dev->bus->bus_notifier,
2422 @@ -306,6 +305,7 @@ static void __device_release_driver(stru
2423                         drv->remove(dev);
2424                 devres_release_all(dev);
2425                 dev->driver = NULL;
2426 +               klist_remove(&dev->knode_driver);
2427                 put_driver(drv);
2428         }
2429  }
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
2434 @@ -38,6 +38,9 @@
2435  char vt_dont_switch;
2436  extern struct tty_driver *console_driver;
2437  
2438 +/* Add a notifier chain to inform drivers of a VT_TEXT/VT_GRAPHICS switch */
2439 +RAW_NOTIFIER_HEAD(console_notifier_list);
2440 +
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)
2443  
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)
2447                         return 0;
2448 +
2449 +               /* Notify listeners if the current fg_console has switched */
2450 +
2451 +               raw_notifier_call_chain(&console_notifier_list,
2452 +                       (arg == KD_TEXT) ?
2453 +                       CONSOLE_EVENT_SWITCH_TEXT :
2454 +                       CONSOLE_EVENT_SWITCH_GRAPHICS, 0);
2455 +
2456                 /*
2457                  * explicitly blank/unblank the screen if switching modes
2458                  */
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");
2466  
2467 +static unsigned int smbclk = 0x70;
2468 +module_param(smbclk, uint, 0);
2469 +MODULE_PARM_DESC(smbclk, "Specify the SMB_CLK value");
2470 +
2471  #define POLL_TIMEOUT   (HZ/5)
2472  
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)
2479  
2480  /************************************************************************/
2481  
2482 @@ -392,11 +397,13 @@ static __init int scx200_acb_probe(struc
2483  {
2484         u8 val;
2485  
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 */
2490 +
2491 +       outb((smbclk & 0x7F) << 1, ACBCTL2);
2492 +
2493 +       outb((smbclk >> 7) & 0xFF, ACBCTL3);
2494  
2495 -       if (inb(ACBCTL2) != 0x70) {
2496 +       if (inb(ACBCTL2) != ((smbclk & 0x7F) << 1)) {
2497                 pr_debug(NAME ": ACBCTL2 readback failed\n");
2498                 return -ENXIO;
2499         }
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");
2507  
2508 +#define ATKBD_KEY_UNKNOWN        0
2509 +#define ATKBD_KEY_NULL         0xFF0000FF
2510 +
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
2518 +
2519 +#define ATKBD_SPECIAL          0xFF0000F8
2520 +
2521  /*
2522   * Scancode to keycode tables. These are just the default setting, and
2523   * are loadable via an userland utility.
2524   */
2525  
2526 -static unsigned char atkbd_set2_keycode[512] = {
2527 +static unsigned int atkbd_set2_keycode[512] = {
2528  
2529  #ifdef CONFIG_KEYBOARD_ATKBD_HP_KEYCODES
2530  
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,
2533  
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,
2536 +
2537 +       217,100,ATKBD_KEY_NULL,  0, 97,165,  0,  0,
2538 +       156,  0,  0,  0,  0,  0,  0,125,
2539 +
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,
2544 +
2545 +       226,  0,  0,  0,  0,  0,  0,  0,
2546 +         0,ATKBD_KEY_NULL, 96,  0,  0,  0,143,  0,
2547 +
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,
2550  
2551 @@ -150,19 +169,6 @@ static unsigned char atkbd_unxlate_table
2552  #define ATKBD_RET_HANGEUL      0xf2
2553  #define ATKBD_RET_ERR          0xff
2554  
2555 -#define ATKBD_KEY_UNKNOWN        0
2556 -#define ATKBD_KEY_NULL         255
2557 -
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
2565 -
2566 -#define ATKBD_SPECIAL          248
2567 -
2568  #define ATKBD_LED_EVENT_BIT    0
2569  #define ATKBD_REP_EVENT_BIT    1
2570  
2571 @@ -174,7 +180,7 @@ static unsigned char atkbd_unxlate_table
2572  #define ATKBD_XL_HANJA         0x20
2573  
2574  static struct {
2575 -       unsigned char keycode;
2576 +       unsigned int keycode;
2577         unsigned char set2;
2578  } atkbd_scroll_keys[] = {
2579         { ATKBD_SCR_1,     0xc5 },
2580 @@ -200,7 +206,7 @@ struct atkbd {
2581         char phys[32];
2582  
2583         unsigned short id;
2584 -       unsigned char keycode[512];
2585 +       unsigned int keycode[512];
2586         unsigned char set;
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;
2592         int value;
2593 -       unsigned char keycode;
2594 +       unsigned int keycode;
2595  
2596  #ifdef ATKBD_DEBUG
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;
2600                 }
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];
2605         } else {
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];
2609  
2610                 if (atkbd->scroll)
2611                         for (i = 0; i < ARRAY_SIZE(atkbd_scroll_keys); i++)
2612 @@ -930,8 +938,8 @@ static void atkbd_set_device_attrs(struc
2613         }
2614  
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);
2620  
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
2624         return err;
2625  }
2626  
2627 +#ifdef CONFIG_OLPC
2628 +#include <asm/olpc.h>
2629 +#endif
2630 +
2631  /*
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;
2637  
2638 +#ifdef CONFIG_OLPC
2639 +       if (olpc_board_at_least(olpc_board_pre(0xb3)))
2640 +               if (serio->dev.power.power_state.event != PM_EVENT_ON)
2641 +                       return 0;
2642 +#endif
2643 +
2644         if (!atkbd || !drv) {
2645                 printk(KERN_DEBUG "atkbd: reconnect request, but serio is disconnected, ignoring...\n");
2646                 return -1;
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
2652  
2653           If unsure, say N.
2654  
2655 +config MOUSE_PS2_OLPC
2656 +       bool "OLPC PS/2 mouse protocol extension" if EMBEDDED
2657 +       default n
2658 +       depends on MOUSE_PS2 && OLPC
2659 +       ---help---
2660 +         Say Y here if you have an OLPC PS/2 touchpad connected to
2661 +         your system.
2662 +
2663 +         If unsure, say N.
2664 +
2665  config MOUSE_SERIAL
2666         tristate "Serial mouse"
2667         select SERIO
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 ===================================================================
2679 --- /dev/null
2680 +++ linux-2.6.24.7/drivers/input/mouse/olpc.c
2681 @@ -0,0 +1,837 @@
2682 +/*
2683 + * OLPC touchpad PS/2 mouse driver
2684 + *
2685 + * Copyright (c) 2006-2008 One Laptop Per Child
2686 + * Authors:
2687 + *   Zephaniah E. Hull
2688 + *   Andres Salomon <dilinger@laptop.org>
2689 + *
2690 + * This driver is partly based on the ALPS driver, which is:
2691 + *
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>
2696 + *
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.
2700 + */
2701 +
2702 +/*
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).
2708 + *
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.
2712 + */
2713 +
2714 +#define DEBUG
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>
2720 +
2721 +#include "psmouse.h"
2722 +#include "olpc.h"
2723 +
2724 +static int tpdebug;
2725 +module_param(tpdebug, int, 0644);
2726 +
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.");
2730 +
2731 +/*
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.
2735 + */
2736 +static void hgpk_fingerup_hack(struct psmouse *psmouse, struct hgpk_packet *p)
2737 +{
2738 +       struct hgpk_data *priv = psmouse->private;
2739 +       struct timeval now_tv;
2740 +       s64 now_ns;
2741 +
2742 +       if (psmouse->model >= HGPK_MODEL_C)
2743 +               return;
2744 +
2745 +       if (p->gs_down || p->pt_down) {
2746 +               do_gettimeofday(&now_tv);
2747 +               now_ns = timeval_to_ns(&now_tv);
2748 +
2749 +               if (priv->late && now_ns >= priv->late) {
2750 +                       struct input_dev *pt = psmouse->dev;
2751 +                       struct input_dev *gs = priv->gs;
2752 +
2753 +                       input_report_key(pt, BTN_TOUCH, 0);
2754 +                       input_report_key(gs, BTN_TOUCH, 0);
2755 +                       input_sync(pt);
2756 +                       input_sync(gs);
2757 +                       hgpk_dbg(psmouse, "Missing finger-up packet detected, "
2758 +                                       "working around buggy hardware.\n");
2759 +               }
2760 +               priv->late = now_ns + (50 * NSEC_PER_MSEC);
2761 +       } else
2762 +               priv->late = 0;
2763 +}
2764 +
2765 +/*
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.
2772 + *
2773 + * *Sigh*. ALPS..
2774 + */
2775 +static void hgpk_fingerdown_hack(struct psmouse *psmouse, struct hgpk_packet *p)
2776 +{
2777 +       if (psmouse->model < HGPK_MODEL_C)
2778 +               return;
2779 +
2780 +       /* we only care about x=0, y=0 packets */
2781 +       if (p->x != 0 || p->y != 0)
2782 +               return;
2783 +
2784 +       /*
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.
2788 +        */
2789 +       if (p->gs_down && !test_bit(BTN_TOUCH, p->dev->key)) {
2790 +               hgpk_dbg(psmouse, "spurious GS finger-down packet\n");
2791 +               p->gs_down = 0;
2792 +       } else if (p->pt_down && !test_bit(BTN_TOUCH, p->dev->key)) {
2793 +               hgpk_dbg(psmouse, "spurious PT finger-down packet\n");
2794 +               p->pt_down = 0;
2795 +       }
2796 +}
2797 +
2798 +/*
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
2804 + * threshold.
2805 + */
2806 +static void hgpk_big_delta_hack(struct psmouse *psmouse, struct hgpk_packet *p)
2807 +{
2808 +       struct hgpk_data *priv = psmouse->private;
2809 +       struct input_dev *dev = p->dev;
2810 +
2811 +       /* afaik, this happens on all hardware */
2812 +
2813 +       /* ignore finger-up packets */
2814 +       if (!p->pt_down && !p->gs_down)
2815 +               goto done;
2816 +
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)))
2820 +               goto done;
2821 +
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);
2828 +               input_sync(dev);
2829 +
2830 +
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;
2837 +               }
2838 +               return;
2839 +       }
2840 +done:
2841 +       priv->axis_errors = 0;  
2842 +}
2843 +
2844 +/*
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..
2854 + */
2855 +static void hgpk_spewing_hack(struct psmouse *psmouse, struct hgpk_packet *p)
2856 +{
2857 +       struct hgpk_data *priv = psmouse->private;
2858 +       struct input_dev *dev = p->dev;
2859 +       int repeat_axes;
2860 +
2861 +       if (psmouse->model < HGPK_MODEL_C)
2862 +               return;
2863 +
2864 +       /* ignore 0, 0 packets */
2865 +       if (p->x == 0 && p->y == 0)
2866 +               return;
2867 +
2868 +       /* PT packets don't count */
2869 +       if (p->pt_down) {
2870 +               priv->repeat_pkts = 0;
2871 +               return;
2872 +       }
2873 +
2874 +       /* 
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.
2879 +        */
2880 +       if (p->z == 0 || p->z == 15)
2881 +               goto next_hack;
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;
2891 +               }
2892 +       }
2893 +       else
2894 +               priv->repeat_pkts = 0;
2895 +       return;
2896 +
2897 +next_hack:
2898 +       /*
2899 +        * 10s of y and z not changing is another kind of miscalibration.
2900 +        */
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;
2908 +               }
2909 +       }
2910 +       else
2911 +               priv->repeat_pkts = 0;
2912 +}
2913 +
2914 +/*
2915 + * HGPK Advanced Mode - single-mode format
2916 + *
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
2925 + *
2926 + * ?'s are not defined in the protocol spec, may vary between models.
2927 + *
2928 + * swr/swl are the left/right buttons.
2929 + *
2930 + * pt-dsw/gs-dsw indicate that the pt/gs sensor is detecting a
2931 + * pen/finger
2932 + */
2933 +
2934 +static int hgpk_validate_byte(unsigned char *packet, int pktcnt)
2935 +{
2936 +       BUG_ON(pktcnt < 1);
2937 +
2938 +       if (packet[0] != HGPK_PT && packet[0] != HGPK_GS)
2939 +               return -1;
2940 +
2941 +       /* bytes 2 - 6 should have 0 in the highest bit */
2942 +       if (pktcnt >= 2 && pktcnt <= 6 && (packet[pktcnt - 1] & 0x80))
2943 +               return -1;
2944 +
2945 +       return 0;
2946 +}
2947 +
2948 +static void hgpk_decode_packet(struct psmouse *psmouse, struct hgpk_packet *p)
2949 +{
2950 +       unsigned char *packet = psmouse->packet;
2951 +
2952 +       BUG_ON(psmouse->pktcnt < 6);
2953 +       
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);
2958 +       p->z = packet[5];
2959 +
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;
2964 +               if (p->pt_down) {
2965 +                       /* we miss spurious PT finger-downs if pt_down is set */
2966 +                       p->mode_switch = HGPK_PT;
2967 +                       p->pt_down = 0;
2968 +               } else {
2969 +                       p->mode_switch = 0;
2970 +               }
2971 +       } else if (packet[0] == HGPK_PT) {
2972 +               p->pt_down = !!(packet[2] & 2);
2973 +               p->gs_down = 0;
2974 +               p->dev = psmouse->dev;
2975 +               p->mode_switch = !p->pt_down ? HGPK_GS : 0;
2976 +       }
2977 +
2978 +       if (tpdebug) {
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);
2982 +       }
2983 +}
2984 +
2985 +static void hgpk_process_packet_gspt(struct psmouse *psmouse)
2986 +{
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;
2991 +
2992 +       hgpk_decode_packet(psmouse, &pkt);      
2993 +
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);
2998 +
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);
3002 +
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);
3006 +
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);
3010 +
3011 +       input_sync(pt);
3012 +       input_sync(gs);
3013 +
3014 +       if (priv->recalib_window) {
3015 +               if (time_before(jiffies, priv->recalib_window)) {
3016 +                       /* 
3017 +                        * ugh, got a packet inside our recalibration
3018 +                        * window, schedule another recalibration.
3019 +                        */
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));
3024 +               }
3025 +               priv->recalib_window = 0;
3026 +       }
3027 +
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);
3033 +               }
3034 +               else if (priv->pending_mode != pkt.mode_switch) {
3035 +                       priv->pending_mode = pkt.mode_switch;
3036 +
3037 +                       /* allow for spurious mode_switch packets by delaying */
3038 +                       queue_delayed_work(kpsmoused_wq, &priv->switch_wq,
3039 +                                       msecs_to_jiffies(50));
3040 +               }
3041 +       }
3042 +}
3043 +
3044 +static psmouse_ret_t hgpk_process_byte(struct psmouse *psmouse)
3045 +{
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;
3053 +       }
3054 +
3055 +       if (psmouse->pktcnt == 6) {
3056 +               hgpk_process_packet_gspt(psmouse);
3057 +               return PSMOUSE_FULL_PACKET;
3058 +       }
3059 +
3060 +       return PSMOUSE_GOOD_DATA;
3061 +}
3062 +
3063 +static int hgpk_force_recalibrate(struct psmouse *psmouse)
3064 +{
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;
3069 +
3070 +       /* C-series touchpads added the recalibrate command */
3071 +       if (psmouse->model < HGPK_MODEL_C)
3072 +               return 0;
3073 +
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))
3078 +               return -1;
3079 +
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);
3083 +       input_sync(pt);
3084 +       input_sync(gs);
3085 +
3086 +       /* according to ALPS, 150mS is required for recalibration */
3087 +       msleep(150);
3088 +
3089 +       /*
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.
3093 +        */
3094 +
3095 +       if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE))
3096 +               return -1;
3097 +
3098 +       /*
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
3103 +        */
3104 +       priv->recalib_window = jiffies +  msecs_to_jiffies(2000);
3105 +
3106 +       return 0;
3107 +}
3108 +
3109 +static enum hgpk_model_t hgpk_get_model(struct psmouse *psmouse)
3110 +{
3111 +       struct ps2dev *ps2dev = &psmouse->ps2dev;
3112 +       unsigned char param[3];
3113 +
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))
3119 +               return -EIO;
3120 +
3121 +       hgpk_dbg(psmouse, "ID: %02x %02x %02x", param[0], param[1], param[2]);
3122 +
3123 +       /* HGPK signature: 0x67, 0x00, 0x<model> */
3124 +       if (param[0] != 0x67 || param[1] != 0x00)
3125 +               return -ENODEV;
3126 +       
3127 +       hgpk_info(psmouse, "OLPC touchpad revision 0x%x\n", param[2]);
3128 +       return param[2];
3129 +}
3130 +
3131 +/*
3132 + * Touchpad should be disabled before calling this!
3133 + */
3134 +static int hgpk_new_mode(struct psmouse *psmouse, int mode)
3135 +{
3136 +       struct ps2dev *ps2dev = &psmouse->ps2dev;
3137 +       struct hgpk_data *priv = psmouse->private;
3138 +
3139 +       /*
3140 +        * PT mode: F2, F2, F2, E7
3141 +        * GS mode: F2, F2, F2, E6
3142 +        */
3143 +       if (ps2_command(ps2dev, NULL, 0xF2) ||
3144 +                       ps2_command(ps2dev, NULL, 0xF2) ||
3145 +                       ps2_command(ps2dev, NULL, 0xF2))
3146 +               return -EIO;
3147 +
3148 +       if (mode == HGPK_GS) {
3149 +               if (ps2_command(ps2dev, NULL, 0xE6))
3150 +                       return -EIO;
3151 +       } else {
3152 +               if (ps2_command(ps2dev, NULL, 0xE7))
3153 +                       return -EIO;
3154 +       }
3155 +
3156 +       if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE))
3157 +               return -EIO;
3158 +
3159 +       /* tell the irq handler to stop ignoring packets */
3160 +       psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
3161 +
3162 +       priv->current_mode = mode;
3163 +       priv->pending_mode = 0;
3164 +       if (tpdebug)
3165 +               hgpk_warn(psmouse, "Switched to mode 0x%x successful.\n", mode);
3166 +
3167 +       return 0;
3168 +}
3169 +
3170 +static int hgpk_advanced_mode(struct psmouse *psmouse)
3171 +{
3172 +       struct ps2dev *ps2dev = &psmouse->ps2dev;
3173 +
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))
3179 +               return -1;
3180 +       
3181 +       return hgpk_new_mode(psmouse, HGPK_GS);
3182 +}
3183 +
3184 +/*
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
3187 + * MS-DAT low.
3188 + */
3189 +static int hgpk_toggle_power(struct psmouse *psmouse, int enable)
3190 +{
3191 +       struct ps2dev *ps2dev = &psmouse->ps2dev;
3192 +       int timeo;
3193 +
3194 +       /* Added on D-series touchpads */
3195 +       if (psmouse->model < HGPK_MODEL_D)
3196 +               return 0;
3197 +
3198 +       if (enable) {
3199 +               psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
3200 +
3201 +               /*
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.
3207 +                */
3208 +               for (timeo = 20; timeo > 0; timeo--) {
3209 +                       if (!ps2_sendbyte(&psmouse->ps2dev,
3210 +                                       PSMOUSE_CMD_DISABLE, 20))
3211 +                               break;
3212 +                       msleep(50);
3213 +               }
3214 +
3215 +               psmouse_reset(psmouse);
3216 +
3217 +               if (hgpk_advanced_mode(psmouse)) {
3218 +                       hgpk_err(psmouse, "Failed to reinit touchpad!\n");
3219 +                       return -1;
3220 +               }
3221 +       } else {
3222 +               hgpk_dbg(psmouse, "Powering off touchpad.\n");
3223 +               psmouse_set_state(psmouse, PSMOUSE_IGNORE);
3224 +
3225 +               if (ps2_command(ps2dev, NULL, 0xec) ||
3226 +                               ps2_command(ps2dev, NULL, 0xec) ||
3227 +                               ps2_command(ps2dev, NULL, 0xea))
3228 +                       return -1;
3229 +               /* probably won't see an ACK, the touchpad will be off */
3230 +               ps2_sendbyte(&psmouse->ps2dev, 0xec, 20);
3231 +       }
3232 +      
3233 +       return 0;
3234 +}
3235 +
3236 +/*
3237 + * poll the touchpad for current motion packet.
3238 + * Used in resync.
3239 + * Note: We can't poll, so always return failure.
3240 + */
3241 +static int hgpk_poll(struct psmouse *psmouse)
3242 +{
3243 +       return -1;
3244 +}
3245 +
3246 +static int hgpk_reconnect(struct psmouse *psmouse)
3247 +{
3248 +       if (olpc_board_at_least(olpc_board(0xb2)))
3249 +               if (psmouse->ps2dev.serio->dev.power.power_state.event != PM_EVENT_ON)
3250 +                       return 0;
3251 +
3252 +       psmouse_reset(psmouse);
3253 +
3254 +       if (hgpk_advanced_mode(psmouse)) {
3255 +               hgpk_err(psmouse, "failed to reenable advanced mode.\n");
3256 +               return -1;
3257 +       }
3258 +
3259 +       return 0;
3260 +}
3261 +
3262 +static ssize_t hgpk_show_powered(struct device *dev,
3263 +               struct device_attribute *attr, char *buf)
3264 +{
3265 +       struct serio *serio = to_serio_port(dev);
3266 +       struct psmouse *psmouse;
3267 +       struct hgpk_data *priv;
3268 +       int retval;
3269 +
3270 +       retval = serio_pin_driver(serio);
3271 +       if (retval)
3272 +               return retval;
3273 +
3274 +        psmouse = serio_get_drvdata(serio);
3275 +       priv = psmouse->private;
3276 +
3277 +       retval = sprintf(buf, "%d\n", priv->powered);
3278 +       serio_unpin_driver(serio);
3279 +       return retval;
3280 +}
3281 +
3282 +static ssize_t hgpk_set_powered(struct device *dev,
3283 +               struct device_attribute *attr, const char *buf, size_t count)
3284 +{
3285 +       struct serio *serio = to_serio_port(dev);
3286 +       struct psmouse *psmouse;
3287 +       struct hgpk_data *priv;
3288 +       unsigned long val;
3289 +       int retval;
3290 +
3291 +       if (*buf == '1')
3292 +               val = 1;
3293 +       else if (*buf == '0')
3294 +               val = 0;
3295 +       else
3296 +               return -EINVAL;
3297 +
3298 +       retval = serio_pin_driver(serio);
3299 +       if (retval)
3300 +               return retval;
3301 +
3302 +/*
3303 + * FUCK IT.  I don't fucking care.  locking in psmouse is fucking retarded!
3304 +       retval = mutex_lock_interruptible(&psmouse_mutex);
3305 +       if (retval)
3306 +               goto out_unpin;
3307 +*/
3308 +
3309 +       psmouse = serio_get_drvdata(serio);
3310 +       priv = psmouse->private;
3311 +
3312 +       if (val == priv->powered)
3313 +               goto done;
3314 +
3315 +       retval = hgpk_toggle_power(psmouse, val);
3316 +       if (!retval)
3317 +               priv->powered = val;
3318 +
3319 +done:
3320 +       serio_unpin_driver(serio);
3321 +       return retval ? retval : count;
3322 +}
3323 +
3324 +static DEVICE_ATTR(powered, S_IWUSR | S_IRUGO, hgpk_show_powered,
3325 +               hgpk_set_powered);
3326 +
3327 +static void hgpk_disconnect(struct psmouse *psmouse)
3328 +{
3329 +       struct hgpk_data *priv = psmouse->private;
3330 +       
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);
3335 +       kfree(priv);
3336 +}
3337 +
3338 +static void hgpk_mode_switch(struct work_struct *work)
3339 +{
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;
3344 +       int pending_mode;
3345 +
3346 +       if (tpdebug)
3347 +               hgpk_dbg(psmouse, "Starting mode switch to 0x%x. [%lu]\n",
3348 +                               priv->pending_mode, jiffies);
3349 +
3350 +       if (priv->pending_mode == priv->current_mode) {
3351 +               priv->pending_mode = 0;
3352 +               hgpk_dbg(psmouse, "Already in target mode, no-op.\n");
3353 +               return;
3354 +       }
3355 +
3356 +       /* tell the irq handler to ignore any further packets */
3357 +       psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
3358 +       priv->late = 0;
3359 +
3360 +       if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE))
3361 +               goto bad;
3362 +
3363 +       /*
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).
3368 +        */
3369 +       pending_mode = priv->pending_mode;
3370 +
3371 +       if (hgpk_new_mode(psmouse, priv->pending_mode))
3372 +               goto bad;
3373 +
3374 +       /*
3375 +        * Deal with a potential race condition.
3376 +        *
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.
3381 +        */
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));
3386 +       }
3387 +
3388 +       return;
3389 +bad:
3390 +       hgpk_warn(psmouse, "Failure to switch modes, resetting device...\n");
3391 +       hgpk_reconnect(psmouse);
3392 +}
3393 +
3394 +static void hgpk_recalib_work(struct work_struct *work)
3395 +{
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;
3399 +
3400 +       if (tpdebug)
3401 +               hgpk_dbg(psmouse, "Recalibrating touchpad..\n");
3402 +
3403 +       if (hgpk_force_recalibrate(psmouse))
3404 +               hgpk_err(psmouse, "Recalibration failed!\n");
3405 +}
3406 +
3407 +int olpc_init(struct psmouse *psmouse)
3408 +{
3409 +       struct hgpk_data *priv;
3410 +       struct input_dev *pt = psmouse->dev;
3411 +       struct input_dev *gs;
3412 +
3413 +       priv = kzalloc(sizeof(struct hgpk_data), GFP_KERNEL);
3414 +       gs = input_allocate_device();
3415 +       if (!priv || !gs)
3416 +               goto init_fail;
3417 +
3418 +       psmouse->private = priv;
3419 +       priv->gs = gs;
3420 +       priv->psmouse = psmouse;
3421 +       priv->powered = 1;
3422 +
3423 +       psmouse_reset(psmouse);
3424 +
3425 +       if (hgpk_advanced_mode(psmouse)) {
3426 +               hgpk_err(psmouse, "failed to enable advanced mode\n");
3427 +               goto init_fail;
3428 +       }
3429 +
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));
3434 +
3435 +       /* Set all the things we *do* have */
3436 +       set_bit(EV_KEY, pt->evbit);
3437 +       set_bit(EV_ABS, pt->evbit);
3438 +
3439 +       set_bit(BTN_LEFT, pt->keybit);
3440 +       set_bit(BTN_RIGHT, pt->keybit);
3441 +       set_bit(BTN_TOUCH, pt->keybit);
3442 +
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);
3446 +
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;
3455 +
3456 +       set_bit(EV_KEY, gs->evbit);
3457 +       set_bit(EV_ABS, gs->evbit);
3458 +
3459 +       set_bit(BTN_LEFT, gs->keybit);
3460 +       set_bit(BTN_RIGHT, gs->keybit);
3461 +       set_bit(BTN_TOUCH, gs->keybit);
3462 +
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);
3466 +
3467 +       if (input_register_device(gs)) {
3468 +               hgpk_err(psmouse, "Failed to register GlideSensor\n");
3469 +               goto init_fail;
3470 +       }
3471 +
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;
3477 +
3478 +       /* Disable the idle resync. */
3479 +       psmouse->resync_time = 0;
3480 +       /* Reset after a lot of bad bytes. */
3481 +       psmouse->resetafter = 1024;
3482 +
3483 +       INIT_DELAYED_WORK(&priv->switch_wq, hgpk_mode_switch);
3484 +       INIT_DELAYED_WORK(&priv->recalib_wq, hgpk_recalib_work);
3485 +
3486 +       if (device_create_file(&psmouse->ps2dev.serio->dev,
3487 +                       &dev_attr_powered)) {
3488 +               hgpk_err(psmouse, "Failed to create sysfs attribute\n");
3489 +               goto attr_fail;
3490 +       }
3491 +
3492 +
3493 +       return 0;
3494 +
3495 +attr_fail:
3496 +       input_unregister_device(gs);
3497 +       gs = NULL;
3498 +init_fail:
3499 +       input_free_device(gs);
3500 +       kfree(priv);
3501 +       return -1;
3502 +}
3503 +
3504 +int olpc_detect(struct psmouse *psmouse, int set_properties)
3505 +{
3506 +       int version;
3507 +
3508 +       version = hgpk_get_model(psmouse);
3509 +       if (version < 0)
3510 +               return version;
3511 +
3512 +       if (set_properties) {
3513 +               psmouse->vendor = "ALPS";
3514 +               psmouse->name = "PenTablet";
3515 +               psmouse->model = version;
3516 +       }
3517 +       return 0;
3518 +}
3519 Index: linux-2.6.24.7/drivers/input/mouse/olpc.h
3520 ===================================================================
3521 --- /dev/null
3522 +++ linux-2.6.24.7/drivers/input/mouse/olpc.h
3523 @@ -0,0 +1,78 @@
3524 +/*
3525 + * OLPC touchpad PS/2 mouse driver
3526 + *
3527 + * Copyright (c) 2006 One Laptop Per Child, inc.
3528 + *
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>
3532 + *
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.
3536 + */
3537 +
3538 +#ifndef _OLPC_H
3539 +#define _OLPC_H
3540 +
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 */
3547 +};
3548 +
3549 +#define HGPK_GS                0xff       /* The GlideSensor */
3550 +#define HGPK_PT                0xcf       /* The PenTablet */
3551 +
3552 +struct hgpk_packet {
3553 +       struct input_dev *dev;
3554 +       int x, y, z;
3555 +       unsigned char mode_switch;
3556 +       unsigned int pt_down:1, gs_down:1;
3557 +       unsigned int left:1, right:1;
3558 +};
3559 +
3560 +struct hgpk_data {
3561 +       struct input_dev *gs;           /* GlideSensor */
3562 +       struct psmouse *psmouse;
3563 +       char name[32];                  /* Name */
3564 +       char phys[32];                  /* Phys */
3565 +       int pending_mode;
3566 +       int current_mode;
3567 +       s64 late;
3568 +       int axis_errors;
3569 +       int repeat_pkts;
3570 +       int powered;
3571 +       unsigned long recalib_window;
3572 +       struct delayed_work switch_wq;
3573 +       struct delayed_work recalib_wq;
3574 +};
3575 +
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)
3586 +
3587 +#ifdef CONFIG_MOUSE_PS2_OLPC
3588 +int olpc_detect(struct psmouse *psmouse, int set_properties);
3589 +int olpc_init(struct psmouse *psmouse);
3590 +#else
3591 +inline int olpc_detect(struct psmouse *psmouse, int set_properties)
3592 +{
3593 +       return -ENOSYS;
3594 +}
3595 +inline int olpc_init(struct psmouse *psmouse)
3596 +{
3597 +       return -ENOSYS;
3598 +}
3599 +#endif
3600 +
3601 +#endif
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
3606 @@ -26,6 +26,7 @@
3607  #include "synaptics.h"
3608  #include "logips2pp.h"
3609  #include "alps.h"
3610 +#include "olpc.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
3615   */
3616  static DEFINE_MUTEX(psmouse_mutex);
3617  
3618 -static struct workqueue_struct *kpsmoused_wq;
3619 +struct workqueue_struct *kpsmoused_wq;
3620  
3621  struct psmouse_protocol {
3622         enum psmouse_type type;
3623 @@ -221,7 +222,7 @@ static inline void __psmouse_set_state(s
3624   * is not a concern.
3625   */
3626  
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)
3629  {
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
3633                         goto out;
3634                 }
3635  
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);
3640                         goto out;
3641 @@ -631,8 +632,21 @@ static int psmouse_extensions(struct psm
3642                 }
3643         }
3644  
3645 +/*
3646 + * Try OLPC touchpad.
3647 + */
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;
3652 +/*
3653 + * Init failed, try basic relative protocols
3654 + */
3655 +                       max_proto = PSMOUSE_IMEX;
3656 +               }
3657 +       }
3658  
3659 +       if (max_proto > PSMOUSE_IMEX) {
3660                 if (genius_detect(psmouse, set_properties) == 0)
3661                         return PSMOUSE_GENPS;
3662  
3663 @@ -763,6 +777,14 @@ static const struct psmouse_protocol psm
3664                 .detect         = touchkit_ps2_detect,
3665         },
3666  #endif
3667 +#ifdef CONFIG_MOUSE_PS2_OLPC
3668 +       {
3669 +               .type           = PSMOUSE_OLPC,
3670 +               .name           = "OLPC",
3671 +               .alias          = "olpc",
3672 +               .detect         = olpc_detect,
3673 +       },
3674 +#endif
3675         {
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 {
3683         PSMOUSE_LIFEBOOK,
3684         PSMOUSE_TRACKPOINT,
3685         PSMOUSE_TOUCHKIT_PS2,
3686 +       PSMOUSE_OLPC,
3687         PSMOUSE_CORTRON,
3688         PSMOUSE_AUTO            /* This one should always be last */
3689  };
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);
3695  
3696 +extern struct workqueue_struct *kpsmoused_wq;
3697  
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
3705  #undef DELAY
3706  
3707  #ifdef CONFIG_PM
3708 +
3709 +#ifdef CONFIG_OLPC
3710 +#include <asm/olpc.h>
3711 +#endif
3712 +
3713  /*
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)
3718  {
3719         if (dev->dev.power.power_state.event != state.event) {
3720 +#ifdef CONFIG_OLPC
3721 +               /* Anything newer than B2 remains powered; no reset needed */
3722 +               if (!olpc_board_at_least(olpc_board_pre(0xb3))) {
3723 +#endif
3724                 if (state.event == PM_EVENT_SUSPEND)
3725                         i8042_controller_reset();
3726 +#ifdef CONFIG_OLPC
3727 +               }
3728 +#endif
3729  
3730                 dev->dev.power.power_state = state;
3731         }
3732 @@ -908,9 +920,15 @@ static int i8042_resume(struct platform_
3733         if (dev->dev.power.power_state.event == PM_EVENT_ON)
3734                 return 0;
3735  
3736 +#ifdef CONFIG_OLPC
3737 +       if (!olpc_board_at_least(olpc_board_pre(0xb3))) {
3738 +#endif
3739         error = i8042_controller_check();
3740         if (error)
3741                 return error;
3742 +#ifdef CONFIG_OLPC
3743 +       }
3744 +#endif
3745  
3746         error = i8042_controller_selftest();
3747         if (error)
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 */
3754  
3755  #ifdef CONFIG_PM
3756 +
3757 +#ifdef CONFIG_OLPC
3758 +#include <asm/olpc.h>
3759 +#endif
3760 +
3761  static int serio_suspend(struct device *dev, pm_message_t state)
3762  {
3763         if (dev->power.power_state.event != state.event) {
3764 +#ifdef CONFIG_OLPC
3765 +               if (!olpc_board_at_least(olpc_board_pre(0xb3))) {
3766 +#endif
3767                 if (state.event == PM_EVENT_SUSPEND)
3768                         serio_cleanup(to_serio_port(dev));
3769 +#ifdef CONFIG_OLPC
3770 +               }
3771 +#endif
3772  
3773                 dev->power.power_state = state;
3774         }
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"
3780  
3781  source "drivers/kvm/Kconfig"
3782  
3783 +source "drivers/sysprof/Kconfig"
3784 +
3785  source "drivers/uio/Kconfig"
3786  
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/
3793  
3794  obj-$(CONFIG_CONNECTOR)                += connector/
3795  
3796 +obj-$(CONFIG_SYSPROF)          += sysprof/
3797 +
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. */
3813  
3814         /*
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;
3818         int ret, zero = 0;
3819  
3820 -       if (cam->state != S_IDLE)
3821 -               return -EINVAL;
3822         fmt.fmt.pix = cam->pix_format;
3823         ret = __cafe_cam_cmd(cam, VIDIOC_INT_INIT, &zero);
3824         if (ret == 0)
3825 @@ -2237,14 +2239,18 @@ static int cafe_pci_suspend(struct pci_d
3826         int ret;
3827         enum cafe_state cstate;
3828  
3829 +       mutex_lock(&cam->s_mutex);
3830         ret = pci_save_state(pdev);
3831 -       if (ret)
3832 +       if (ret) {
3833 +               cam_warn(cam, "Unable to save PCI state\n");
3834                 return ret;
3835 +       }
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 */
3842         return 0;
3843  }
3844  
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");
3847                 return ret;
3848         }
3849 +       /* we're still holding mutex from suspend */
3850         cafe_ctlr_init(cam);
3851         cafe_ctlr_power_down(cam);
3852  
3853 -       mutex_lock(&cam->s_mutex);
3854 -       if (cam->users > 0) {
3855 -               cafe_ctlr_power_up(cam);
3856 -               __cafe_cam_reset(cam);
3857 -       }
3858 -       mutex_unlock(&cam->s_mutex);
3859 -
3860 +       if (cam->users > 0) {
3861 +               cafe_ctlr_power_up(cam);
3862 +               __cafe_cam_reset(cam);
3863 +       }
3864 +       else
3865 +               cafe_ctlr_power_down(cam);
3866 +       mutex_unlock(&cam->s_mutex);
3867
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
3876  
3877           If you are not sure, say Y here.
3878  
3879 +config EEPROM_93CX6
3880 +       tristate "EEPROM 93CX6 support"
3881 +       ---help---
3882 +         This is a driver for the EEPROM chipsets 93c46 and 93c66.
3883 +         The driver supports both read as well as write commands.
3884  
3885  config ATMEL_SSC
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;
3894  
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);
3898 +                       goto cmd_err;
3899 +               }
3900 +               mmc_set_data_timeout(&brq.data, card);
3901 +
3902                 /*
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
3910                         break;
3911         }
3912  
3913 +       /*
3914 +        * There's an off-by-one error in the hw that we need to
3915 +        * compensate for.
3916 +        */
3917 +       count++;
3918 +
3919         if (count >= 0xF) {
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);
3925  
3926 -       pwr = SDHCI_POWER_ON;
3927 -
3928         switch (1 << power) {
3929         case MMC_VDD_165_195:
3930 -               pwr |= SDHCI_POWER_180;
3931 +               pwr = SDHCI_POWER_180;
3932                 break;
3933         case MMC_VDD_29_30:
3934         case MMC_VDD_30_31:
3935 -               pwr |= SDHCI_POWER_300;
3936 +               pwr = SDHCI_POWER_300;
3937                 break;
3938         case MMC_VDD_32_33:
3939         case MMC_VDD_33_34:
3940 -               pwr |= SDHCI_POWER_330;
3941 +               pwr = SDHCI_POWER_330;
3942                 break;
3943         default:
3944                 BUG();
3945 @@ -748,6 +752,10 @@ static void sdhci_set_power(struct sdhci
3946  
3947         writeb(pwr, host->ioaddr + SDHCI_POWER_CONTROL);
3948  
3949 +       pwr |= SDHCI_POWER_ON;
3950 +
3951 +       writeb(pwr, host->ioaddr + SDHCI_POWER_CONTROL);
3952 +
3953  out:
3954         host->power = power;
3955  }
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
3960 @@ -11,6 +11,7 @@
3961  #undef DEBUG
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>
3968 @@ -52,6 +53,7 @@
3969  
3970  struct cafe_priv {
3971         struct nand_chip nand;
3972 +       struct mtd_partition *parts;
3973         struct pci_dev *pdev;
3974         void __iomem *mmio;
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);
3979  
3980 +#ifdef CONFIG_MTD_PARTITIONS
3981 +static const char *part_probes[] = { "RedBoot", NULL };
3982 +#endif
3983 +
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)
3986  
3987 @@ -620,7 +626,9 @@ static int __devinit cafe_nand_probe(str
3988  {
3989         struct mtd_info *mtd;
3990         struct cafe_priv *cafe;
3991 +       struct mtd_partition *parts;
3992         uint32_t ctrl;
3993 +       int nr_parts;
3994         int err = 0;
3995  
3996         /* Very old versions shared the same PCI ident for all three
3997 @@ -787,7 +795,18 @@ static int __devinit cafe_nand_probe(str
3998                 goto out_irq;
3999  
4000         pci_set_drvdata(pdev, mtd);
4001 +
4002 +       /* We register the whole device first, separate from the partitions */
4003         add_mtd_device(mtd);
4004 +
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);
4011 +       }
4012 +#endif
4013         goto out;
4014  
4015   out_irq:
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";
4022  #endif
4023  
4024 +       if ( directory < 0 ) {
4025 +               offset = master->size + directory * master->erasesize;
4026 +               while (master->block_isbad && 
4027 +                      master->block_isbad(master, offset)) {
4028 +                       if (!offset) {
4029 +                       nogood:
4030 +                               printk(KERN_NOTICE "Failed to find a non-bad block to check for RedBoot partition table\n");
4031 +                               return -EIO;
4032 +                       }
4033 +                       offset -= master->erasesize;
4034 +               }
4035 +       } else {
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)
4041 +                               goto nogood;
4042 +               }
4043 +       }
4044         buf = vmalloc(master->erasesize);
4045  
4046         if (!buf)
4047                 return -ENOMEM;
4048  
4049 -       if ( directory < 0 )
4050 -               offset = master->size + directory*master->erasesize;
4051 -       else
4052 -               offset = directory*master->erasesize;
4053 -
4054         printk(KERN_NOTICE "Searching for RedBoot partition table in %s at offset 0x%lx\n",
4055                master->name, offset);
4056  
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
4062         }
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;
4074                                 goto out_err;
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;
4081                 }
4082         }
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);
4089  
4090  /*
4091 + * According to Tom Sylla, the Geode does not support PCI power management
4092 + * transition, so we shouldn't need the D3hot delay.
4093 + */
4094 +static void __init quirk_geode_pci_pm(struct pci_dev *dev)
4095 +{
4096 +       pci_pm_d3_delay = 0;
4097 +}
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);
4100 +
4101 +/*
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);
4111  
4112         di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN;
4113 +       power_supply_changed(&di->bat);
4114  
4115         return 0;
4116  }
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
4121 @@ -14,12 +14,13 @@
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>
4127  
4128  
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,
4138  };
4139  
4140 +static char bat_serial[17]; /* Ick */
4141 +
4142  /*********************************************************************
4143   *             Battery properties
4144   *********************************************************************/
4145 @@ -94,6 +97,7 @@ static int olpc_bat_get_property(struct 
4146         int ret = 0;
4147         int16_t ec_word;
4148         uint8_t ec_byte;
4149 +       uint64_t ser_buf;
4150  
4151         ret = olpc_ec_cmd(EC_BAT_STATUS, NULL, 0, &ec_byte, 1);
4152         if (ret)
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;
4157 -                       break;
4158                 }
4159 +               break;
4160         case POWER_SUPPLY_PROP_PRESENT:
4161                 val->intval = !!(ec_byte & BAT_STAT_PRESENT);
4162                 break;
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;
4166                 break;
4167 +       case POWER_SUPPLY_PROP_ACCUM_CURRENT:
4168 +               ret = olpc_ec_cmd(EC_BAT_ACR, NULL, 0, (void *)&ec_word, 2);
4169 +               if (ret)
4170 +                       return ret;
4171 +
4172 +               ec_word = be16_to_cpu(ec_word);
4173 +               val->intval = (uint16_t)ec_word;
4174 +               break;
4175 +       case POWER_SUPPLY_PROP_SERIAL_NUMBER:
4176 +               ret = olpc_ec_cmd(EC_BAT_SERIAL, NULL, 0, (void *)&ser_buf, 8);
4177 +               if (ret)
4178 +                       return ret;
4179 +
4180 +               sprintf(bat_serial, "%016llx", (long long)be64_to_cpu(ser_buf));
4181 +               val->strval = bat_serial;
4182 +               break;
4183         default:
4184                 ret = -EINVAL;
4185                 break;
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,
4193 +};
4194 +
4195 +/* EEPROM reading goes completely around the power_supply API, sadly */
4196 +
4197 +#define EEPROM_START   0x20
4198 +#define EEPROM_END     0x80
4199 +#define EEPROM_SIZE    (EEPROM_END - EEPROM_START)
4200 +
4201 +static ssize_t olpc_bat_eeprom_read(struct kobject *kobj, char *buf, loff_t off,
4202 +               size_t count)
4203 +{
4204 +       uint8_t ec_byte;
4205 +       int ret, end;
4206 +
4207 +       if (off >= EEPROM_SIZE)
4208 +               return 0;
4209 +       if (off + count > EEPROM_SIZE)
4210 +               count = EEPROM_SIZE - off;
4211 +
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);
4216 +               if (ret) {
4217 +                       printk(KERN_ERR "olpc-battery:  EC command "
4218 +                                       "EC_BAT_EEPROM @ 0x%x failed -"
4219 +                                       " %d!\n", ec_byte, ret);
4220 +                       return -EIO;
4221 +               }
4222 +       }
4223 +
4224 +       return count;
4225 +}
4226 +
4227 +static struct bin_attribute olpc_bat_eeprom = {
4228 +       .attr = {
4229 +               .name = "eeprom",
4230 +               .mode = S_IRUGO, 
4231 +               .owner = THIS_MODULE,
4232 +       },
4233 +       .size = 0,
4234 +       .read = olpc_bat_eeprom_read,
4235  };
4236  
4237  /*********************************************************************
4238 @@ -299,7 +363,7 @@ static int __init olpc_bat_init(void)
4239  
4240         if (!olpc_platform_info.ecver)
4241                 return -ENXIO;
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);
4245                 return -ENXIO;
4246         }
4247 @@ -324,9 +388,15 @@ static int __init olpc_bat_init(void)
4248         if (ret)
4249                 goto battery_failed;
4250  
4251 +       ret = device_create_bin_file(olpc_bat.dev, &olpc_bat_eeprom);
4252 +       if (ret)
4253 +               goto eeprom_failed;
4254 +
4255         olpc_register_battery_callback(&olpc_battery_trigger_uevent);
4256         goto success;
4257  
4258 +eeprom_failed:
4259 +       power_supply_unregister(&olpc_bat);
4260  battery_failed:
4261         power_supply_unregister(&olpc_ac);
4262  ac_failed:
4263 @@ -338,6 +408,7 @@ success:
4264  static void __exit olpc_bat_exit(void)
4265  {
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),
4284  };
4285  
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)
4293  {
4294         struct uart_state *state = drv->state + port->line;
4295 +       struct ktermios termios;
4296  
4297         mutex_lock(&state->mutex);
4298  
4299 @@ -2035,20 +2036,6 @@ int uart_resume_port(struct uart_driver 
4300          * Re-enable the console device after suspending.
4301          */
4302         if (uart_console(port)) {
4303 -               struct ktermios termios;
4304 -
4305 -               /*
4306 -                * First try to use the console cflag setting.
4307 -                */
4308 -               memset(&termios, 0, sizeof(struct ktermios));
4309 -               termios.c_cflag = port->cons->cflag;
4310 -
4311 -               /*
4312 -                * If that's unset, use the tty termios setting.
4313 -                */
4314 -               if (state->info && state->info->tty && termios.c_cflag == 0)
4315 -                       termios = *state->info->tty->termios;
4316 -
4317                 port->ops->set_termios(port, &termios, NULL);
4318                 console_start(port->cons);
4319         }
4320 Index: linux-2.6.24.7/drivers/sysprof/config.h
4321 ===================================================================
4322 --- /dev/null
4323 +++ linux-2.6.24.7/drivers/sysprof/config.h
4324 @@ -0,0 +1,23 @@
4325 +/* config.h.  Generated by configure.  */
4326 +/* config.h.in.  Generated from configure.ac by autoheader.  */
4327 +
4328 +/* Look for global separate debug info in this path */
4329 +#define DEBUGDIR "/usr/local/lib/debug"
4330 +
4331 +/* Define to 1 if you have the `iberty' library (-liberty). */
4332 +/* #undef HAVE_LIBIBERTY */
4333 +
4334 +/* Define to the address where bug reports for this package should be sent. */
4335 +#define PACKAGE_BUGREPORT ""
4336 +
4337 +/* Define to the full name of this package. */
4338 +#define PACKAGE_NAME "sysprof"
4339 +
4340 +/* Define to the full name and version of this package. */
4341 +#define PACKAGE_STRING "sysprof 1.0.8"
4342 +
4343 +/* Define to the one symbol short name of this package. */
4344 +#define PACKAGE_TARNAME "sysprof"
4345 +
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 ===================================================================
4350 --- /dev/null
4351 +++ linux-2.6.24.7/drivers/sysprof/Kconfig
4352 @@ -0,0 +1,12 @@
4353 +
4354 +menu "Sysprof"
4355 +
4356 +config SYSPROF
4357 +       tristate "Sysprof support"
4358 +       help
4359 +        Say M here to include the sysprof-module.
4360 +
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".
4364 +endmenu
4365 Index: linux-2.6.24.7/drivers/sysprof/Makefile
4366 ===================================================================
4367 --- /dev/null
4368 +++ linux-2.6.24.7/drivers/sysprof/Makefile
4369 @@ -0,0 +1 @@
4370 +obj-$(CONFIG_SYSPROF)  += sysprof-module.o
4371 Index: linux-2.6.24.7/drivers/sysprof/sysprof-module.c
4372 ===================================================================
4373 --- /dev/null
4374 +++ linux-2.6.24.7/drivers/sysprof/sysprof-module.c
4375 @@ -0,0 +1,271 @@
4376 +/* -*- c-basic-offset: 8 -*- */
4377 +
4378 +/* Sysprof -- Sampling, systemwide CPU profiler
4379 + * Copyright 2004, Red Hat, Inc.
4380 + * Copyright 2004, 2005, Soeren Sandmann
4381 + *
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.
4386 + *
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.
4391 + *
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.
4395 + */
4396 +
4397 +#ifdef CONFIG_SMP
4398 +# define __SMP__
4399 +#endif
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>
4404 +
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>
4411 +
4412 +#include "sysprof-module.h"
4413 +
4414 +#include "config.h"
4415 +
4416 +#include <linux/version.h>
4417 +
4418 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
4419 +#include <linux/config.h>
4420 +#endif
4421 +
4422 +#if !CONFIG_PROFILING
4423 +# error Sysprof needs a kernel with profiling support compiled in.
4424 +#endif
4425 +
4426 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11)
4427 +# error Sysprof needs a Linux 2.6.11 kernel or later
4428 +#endif
4429 +#include <linux/kallsyms.h>
4430 +
4431 +MODULE_LICENSE("GPL");
4432 +MODULE_AUTHOR("Soeren Sandmann (sandmann@daimi.au.dk)");
4433 +
4434 +#define SAMPLES_PER_SECOND (200)
4435 +#define INTERVAL ((HZ <= SAMPLES_PER_SECOND)? 1 : (HZ / SAMPLES_PER_SECOND))
4436 +#define N_TRACES 256
4437 +
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);
4443 +
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
4453 +#else
4454 +# error Sysprof only supports the i386 and x86-64 architectures
4455 +#endif
4456 +
4457 +typedef struct userspace_reader userspace_reader;
4458 +struct userspace_reader
4459 +{
4460 +       struct task_struct *task;
4461 +       unsigned long cache_address;
4462 +       unsigned long *cache;
4463 +};
4464 +
4465 +typedef struct StackFrame StackFrame;
4466 +struct StackFrame {
4467 +       unsigned long next;
4468 +       unsigned long return_address;
4469 +};
4470 +
4471 +struct work_struct work;
4472 +
4473 +static int
4474 +read_frame (void *frame_pointer, StackFrame *frame)
4475 +{
4476 +#if 0
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.
4480 +        *
4481 +        * Not sure why (or if) this isn't the case for oprofile
4482 +        */
4483 +       if (!access_ok(VERIFY_READ, frame_pointer, sizeof(StackFrame)))
4484 +               return 1;
4485 +#endif
4486 +
4487 +       if (__copy_from_user_inatomic (
4488 +                   frame, frame_pointer, sizeof (StackFrame)))
4489 +               return 1;
4490 +       
4491 +       return 0;
4492 +}
4493 +
4494 +DEFINE_PER_CPU(int, n_samples);
4495 +
4496 +static int
4497 +timer_notify (struct pt_regs *regs)
4498 +{
4499 +       SysprofStackTrace *trace = head;
4500 +       int i;
4501 +       int is_user;
4502 +       static atomic_t in_timer_notify = ATOMIC_INIT(1);
4503 +       int n;
4504 +
4505 +       n = ++get_cpu_var(n_samples);
4506 +       put_cpu_var(n_samples);
4507 +
4508 +       if (n % INTERVAL != 0)
4509 +               return 0;
4510 +
4511 +       /* 0: locked, 1: unlocked */
4512 +       
4513 +       if (!atomic_dec_and_test(&in_timer_notify))
4514 +               goto out;
4515 +       
4516 +       is_user = user_mode(regs);
4517 +
4518 +       if (!current || current->pid == 0)
4519 +               goto out;
4520 +       
4521 +       if (is_user && current->state != TASK_RUNNING)
4522 +               goto out;
4523 +
4524 +       if (!is_user)
4525 +       {
4526 +               /* kernel */
4527 +               
4528 +               trace->pid = current->pid;
4529 +               trace->truncated = 0;
4530 +               trace->n_addresses = 1;
4531 +
4532 +               /* 0x1 is taken by sysprof to mean "in kernel" */
4533 +               trace->addresses[0] = (void *)0x1;
4534 +       }
4535 +       else
4536 +       {
4537 +               StackFrame *frame_pointer;
4538 +               StackFrame frame;
4539 +               memset(trace, 0, sizeof (SysprofStackTrace));
4540 +               
4541 +               trace->pid = current->pid;
4542 +               trace->truncated = 0;
4543 +
4544 +               i = 0;
4545 +               
4546 +               trace->addresses[i++] = (void *)regs->REG_INS_PTR;
4547 +               
4548 +               frame_pointer = (void *)regs->REG_FRAME_PTR;
4549 +       
4550 +               while (read_frame (frame_pointer, &frame) == 0          &&
4551 +                      i < SYSPROF_MAX_ADDRESSES                        &&
4552 +                      (unsigned long)frame_pointer >= regs->REG_STACK_PTR)
4553 +               {
4554 +                       trace->addresses[i++] = (void *)frame.return_address;
4555 +                       frame_pointer = (StackFrame *)frame.next;
4556 +               }
4557 +               
4558 +               trace->n_addresses = i;
4559 +
4560 +               if (i == SYSPROF_MAX_ADDRESSES)
4561 +                       trace->truncated = 1;
4562 +               else
4563 +                       trace->truncated = 0;
4564 +       }
4565 +       
4566 +       if (head++ == &stack_traces[N_TRACES - 1])
4567 +               head = &stack_traces[0];
4568 +       
4569 +       wake_up (&wait_for_trace);
4570 +
4571 +out:
4572 +       atomic_inc(&in_timer_notify);
4573 +       return 0;
4574 +}
4575 +
4576 +static int
4577 +procfile_read(char *buffer, 
4578 +             char **buffer_location, 
4579 +             off_t offset, 
4580 +             int buffer_len,
4581 +             int *eof,
4582 +             void *data)
4583 +{
4584 +       if (head == tail)
4585 +               return -EWOULDBLOCK;
4586 +       
4587 +       *buffer_location = (char *)tail;
4588 +
4589 +       BUG_ON(tail->pid == 0);
4590 +       
4591 +       if (tail++ == &stack_traces[N_TRACES - 1])
4592 +               tail = &stack_traces[0];
4593 +       
4594 +       return sizeof (SysprofStackTrace);
4595 +}
4596 +
4597 +struct proc_dir_entry *trace_proc_file;
4598 +static unsigned int
4599 +procfile_poll(struct file *filp, poll_table *poll_table)
4600 +{
4601 +       if (head != tail)
4602 +               return POLLIN | POLLRDNORM;
4603 +       
4604 +       poll_wait(filp, &wait_for_trace, poll_table);
4605 +
4606 +       if (head != tail)
4607 +               return POLLIN | POLLRDNORM;
4608 +       
4609 +       return 0;
4610 +}
4611 +
4612 +int
4613 +init_module(void)
4614 +{
4615 +       static struct file_operations fops;
4616 +
4617 +       trace_proc_file =
4618 +               create_proc_entry ("sysprof-trace", S_IFREG | S_IRUGO, &proc_root);
4619 +       
4620 +       if (!trace_proc_file)
4621 +               return 1;
4622 +
4623 +       fops = *trace_proc_file->proc_fops;
4624 +       fops.poll = procfile_poll;
4625 +       
4626 +       trace_proc_file->read_proc = procfile_read;
4627 +       trace_proc_file->proc_fops = &fops;
4628 +       trace_proc_file->size = sizeof (SysprofStackTrace);
4629 +
4630 +       register_timer_hook (timer_notify);
4631 +       
4632 +       printk(KERN_ALERT "sysprof: loaded (%s)\n", PACKAGE_VERSION);
4633 +       
4634 +       return 0;
4635 +}
4636 +
4637 +void
4638 +cleanup_module(void)
4639 +{
4640 +       unregister_timer_hook (timer_notify);
4641 +       
4642 +       remove_proc_entry("sysprof-trace", &proc_root);
4643 +
4644 +       printk(KERN_ALERT "sysprof: unloaded\n");
4645 +}
4646 +
4647 Index: linux-2.6.24.7/drivers/sysprof/sysprof-module.h
4648 ===================================================================
4649 --- /dev/null
4650 +++ linux-2.6.24.7/drivers/sysprof/sysprof-module.h
4651 @@ -0,0 +1,37 @@
4652 +/* Sysprof -- Sampling, systemwide CPU profiler
4653 + * Copyright 2004, Red Hat, Inc.
4654 + * Copyright 2004, 2005, Soeren Sandmann
4655 + *
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.
4660 + *
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.
4665 + *
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.
4669 + */
4670 +
4671 +#ifndef SYSPROF_MODULE_H
4672 +#define SYSPROF_MODULE_H
4673 +
4674 +typedef struct SysprofStackTrace SysprofStackTrace;
4675 +
4676 +#define SYSPROF_MAX_ADDRESSES 512
4677 +
4678 +struct SysprofStackTrace
4679 +{
4680 +    int        pid;            /* -1 if in kernel */
4681 +    int truncated;
4682 +    int n_addresses;   /* note: this can be 1 if the process was compiled
4683 +                        * with -fomit-frame-pointer or is otherwise weird
4684 +                        */
4685 +    void *addresses[SYSPROF_MAX_ADDRESSES];
4686 +};
4687 +
4688 +#endif
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
4694                                 break;
4695                 }
4696         }
4697 -       if (status == 0)
4698 +       if (status == 0) {
4699 +
4700 +               /* Non-root devices don't need to do anything for FREEZE
4701 +                * or PRETHAW. */
4702 +               if (udev->parent && (msg.event == PM_EVENT_FREEZE ||
4703 +                               msg.event == PM_EVENT_PRETHAW))
4704 +                       goto done;
4705                 status = usb_suspend_device(udev, msg);
4706 +       }
4707  
4708         /* If the suspend failed, resume interfaces that did get suspended */
4709         if (status != 0) {
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 },
4717  
4718 +       /* Philips PSC805 audio device */
4719 +       { USB_DEVICE(0x0471, 0x0155), .driver_info = USB_QUIRK_RESET_RESUME },
4720 +
4721         { }  /* terminating entry must be last */
4722  };
4723  
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,
4734                 pm_message_t msg);
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_
4741  
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;
4746 -               bh = 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));
4751 +                       WARN_ON(1);
4752 +               } else {
4753 +                       COUNT (ehci->stats.reclaim);
4754 +                       ehci->reclaim_ready = 1;
4755 +                       bh = 1;
4756 +               }
4757         }
4758  
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;
4767         }
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));
4770 +
4771         ehci->command = ehci_readl(ehci, &ehci->regs->command);
4772         if (ehci->reclaim)
4773                 ehci->reclaim_ready = 1;
4774         ehci_work(ehci);
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));
4777  
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_
4781         ehci_halt (ehci);
4782         hcd->state = HC_STATE_SUSPENDED;
4783  
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));
4786 +
4787         /* allow remote wakeup */
4788         mask = INTR_MASK;
4789         if (!device_may_wakeup(&hcd->self.root_hub->dev))
4790 @@ -195,6 +203,18 @@ static int ehci_bus_resume (struct usb_h
4791         u32                     temp;
4792         u32                     power_okay;
4793         int                     i;
4794 +#ifdef CONFIG_OLPC
4795 +       u32 lo;
4796 +       static void __iomem *usb_ehc_addr;
4797 +
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);
4805 +#endif
4806  
4807         if (time_before (jiffies, ehci->next_statechange))
4808                 msleep(5);
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
4814                 rc = -EINVAL;
4815                 goto bail;
4816         }
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));
4819 +
4820         ehci_writel(ehci, 0, &ehci->regs->intr_enable);
4821         (void)ehci_readl(ehci, &ehci->regs->intr_enable);
4822  
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))
4829                                 status = -EPIPE;
4830                         else {
4831 -                               ehci_dbg (ehci, "devpath %s ep%d%s 3strikes\n",
4832 +                               printk(KERN_ERR "devpath %s ep%d%s 3strikes\n",
4833                                         urb->dev->devpath,
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;
4839  
4840 +       if (!qh) {
4841 +               printk(KERN_CRIT "%s with ehci->reclaim == NULL!\n", __func__);
4842 +               WARN_ON(1);
4843 +               return;
4844 +       }
4845         timer_action_done (ehci, TIMER_IAA_WATCHDOG);
4846  
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);
4855  
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;
4858         return 0;
4859  }
4860  
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_
4866         return 0;
4867  }
4868  
4869 -static int storage_post_reset(struct usb_interface *iface)
4870 +static void storage_post_reset(struct usb_interface *iface, int reset_resume)
4871  {
4872         struct us_data *us = usb_get_intfdata(iface);
4873  
4874 @@ -256,8 +256,10 @@ static int storage_post_reset(struct usb
4875         /* FIXME: Notify the subdrivers that they need to reinitialize
4876          * the device */
4877  
4878 -       mutex_unlock(&us->dev_mutex);
4879 -       return 0;
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);
4884  }
4885  
4886  /*
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 */
4893  
4894  int
4895 +fb_powerup(struct fb_info *info)
4896 +{
4897 +       int ret = 0;
4898 +
4899 +       if (!info || info->state == FBINFO_STATE_RUNNING)
4900 +               return 0;
4901 +
4902 +       if (info->fbops->fb_powerup)
4903 +               ret = info->fbops->fb_powerup(info);
4904 +
4905 +       if (!ret) {
4906 +               acquire_console_sem();
4907 +               fb_set_suspend(info, 0);
4908 +               release_console_sem();
4909 +       }
4910 +
4911 +       return ret;
4912 +}
4913 +
4914 +int
4915 +fb_powerdown(struct fb_info *info)
4916 +{
4917 +       int ret = 0;
4918 +
4919 +       if (!info || info->state == FBINFO_STATE_SUSPENDED)
4920 +               return 0;
4921 +
4922 +       /* Tell everybody that the fbdev is going down */
4923 +       acquire_console_sem();
4924 +       fb_set_suspend(info, 1);
4925 +       release_console_sem();
4926 +
4927 +       if (info->fbops->fb_powerdown)
4928 +               ret = info->fbops->fb_powerdown(info);
4929 +
4930 +       /* If the power down failed, then un-notify */
4931 +
4932 +       if (ret) {
4933 +               acquire_console_sem();
4934 +               fb_set_suspend(info, 0);
4935 +               release_console_sem();
4936 +       }
4937 +
4938 +       return ret;
4939 +}
4940 +
4941 +int
4942  fb_pan_display(struct fb_info *info, struct fb_var_screeninfo *var)
4943  {
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
4949 @@ -11,26 +11,44 @@
4950   *   Free Software Foundation; either version 2 of the License, or * (at your
4951   *   option) any later version.
4952   */
4953 +
4954 +#include <linux/kernel.h>
4955  #include <linux/spinlock.h>
4956  #include <linux/fb.h>
4957  #include <linux/delay.h>
4958  #include <asm/io.h>
4959  #include <asm/div64.h>
4960  #include <asm/delay.h>
4961 +#include <asm/olpc.h>
4962  
4963  #include "geodefb.h"
4964  #include "display_gx.h"
4965  
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)
4969  {
4970 -       return CONFIG_FB_GEODE_GX_FBSIZE;
4971 +       u32 in = readl(reg);
4972 +       if (in != val)
4973 +               writel(val, reg);
4974  }
4975 -#else
4976 +
4977  unsigned int gx_frame_buffer_size(void)
4978  {
4979         unsigned int val;
4980  
4981 +#ifdef CONFIG_OLPC
4982 +       if (machine_is_olpc() && !olpc_has_vsa()) {
4983 +               u32 hi,lo;      
4984 +               rdmsr(GLIU0_P2D_RO0, lo, hi);
4985 +
4986 +               /* Top page number */
4987 +               val = ((hi & 0xff) << 12) | ((lo & 0xfff00000) >> 20);  
4988 +
4989 +               val -= (lo & 0x000fffff); /* Subtract bottom page number */
4990 +               val += 1;                 /* Adjust page count */
4991 +               return (val << 12);
4992 +       }
4993 +#endif
4994 +
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;
5000         return (val << 19);
5001  }
5002 -#endif
5003  
5004  int gx_line_delta(int xres, int bpp)
5005  {
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);
5009  
5010 -       /* Disable the timing generator. */
5011 -       dcfg &= ~(DC_DCFG_TGEN);
5012 -       writel(dcfg, par->dc_regs + DC_DISPLAY_CFG);
5013 -
5014 -       /* Wait for pending memory requests before disabling the FIFO load. */
5015 -       udelay(100);
5016 -
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);
5020 -
5021 -       /* Setup DCLK and its divisor. */
5022 -       par->vid_ops->set_dclk(info);
5023 -
5024 -       /*
5025 -        * Setup new mode.
5026 -        */
5027 +       /* Programming the clock is costly and ugly, so avoid if if we can */
5028 +
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);
5033 +
5034 +               /* Wait for pending memory requests before disabling the FIFO load. */
5035 +               udelay(100);
5036 +
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);
5040 +
5041 +               /* Setup DCLK and its divisor. */
5042 +               par->vid_ops->set_dclk(info);
5043 +       }
5044  
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;
5049  
5050         /* Framebuffer start offset. */
5051 -       writel(0, par->dc_regs + DC_FB_ST_OFFSET);
5052 +       rmwl(0, par->dc_regs + DC_FB_ST_OFFSET);
5053  
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);
5059 +
5060 +       rmwl(((info->var.xres * info->var.bits_per_pixel/8) >> 3) + 2,
5061 +            par->dc_regs + DC_LINE_SIZE);
5062  
5063  
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;
5067         vtotal = vblankend;
5068  
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);
5072 -
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);
5082  
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);
5088  
5089         par->vid_ops->configure_display(info);
5090  
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
5098  
5099 +/* Used for memory dection on the OLPC */
5100 +#define GLIU0_P2D_RO0 0x10000029
5101 +
5102  /* Display controller registers */
5103  
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
5109 @@ -12,6 +12,10 @@
5110  #ifndef __GEODEFB_H__
5111  #define __GEODEFB_H__
5112  
5113 +#define FB_POWER_STATE_OFF      0
5114 +#define FB_POWER_STATE_SUSPEND  1
5115 +#define FB_POWER_STATE_ON       2
5116 +
5117  struct geodefb_info;
5118  
5119  struct geode_dc_ops {
5120 @@ -21,18 +25,24 @@ struct geode_dc_ops {
5121  
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);
5127  };
5128  
5129  struct geodefb_par {
5130         int enable_crt;
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 */
5133         int panel_y;
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;
5140 +
5141 +       int state;
5142  };
5143  
5144  #endif /* !__GEODEFB_H__ */
5145 Index: linux-2.6.24.7/drivers/video/geode/geode_regs.h
5146 ===================================================================
5147 --- /dev/null
5148 +++ linux-2.6.24.7/drivers/video/geode/geode_regs.h
5149 @@ -0,0 +1,255 @@
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.
5154 +*/
5155 +
5156 +#ifndef _GEODE_REGS_H_
5157 +#define _GEODE_REGS_H_
5158 +
5159 +/* MSRs */
5160 +
5161 +#define GX_VP_MSR_PAD_SELECT    0xC0002011
5162 +#define LX_VP_MSR_PAD_SELECT    0x48000011
5163 +
5164 +#define GEODE_MSR_GLCP_DOTPLL   0x4c000015
5165 +
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)
5170 +
5171 +/* Registers */
5172 +#define VP_FP_START          0x400
5173 +
5174 +
5175 +#ifdef _GEODELX_
5176 +
5177 +#define GP_REG_SIZE  0x7C
5178 +#define DC_REG_SIZE  0xF0
5179 +#define VP_REG_SIZE  0x158
5180 +#define FP_REG_SIZE  0x70
5181 +
5182 +#else
5183 +
5184 +#define GP_REG_SIZE 0x50
5185 +#define DC_REG_SIZE 0x90
5186 +#define VP_REG_SIZE 0x138
5187 +#define FP_REG_SIZE 0x70
5188 +
5189 +#endif
5190 +
5191 +#define DC_PAL_SIZE 0x105
5192 +#define VP_COEFF_COUNT 512
5193 +#define DC_HFILT_SIZE 256
5194 +#define DC_VFILT_SIZE 256
5195 +
5196 +struct geoderegs {
5197 +
5198 +       struct {
5199 +               u64 padsel;
5200 +               u64 dotpll;
5201 +
5202 +#ifdef _GEODELX_
5203 +               u64 dfglcfg;
5204 +               u64 dcspare;
5205 +#else
5206 +               u64 rstpll;
5207 +#endif
5208 +       } msr;
5209 +
5210 +       union {
5211 +               unsigned char b[GP_REG_SIZE];
5212 +               struct {
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 */
5233 +
5234 +#ifdef _GEODELX_
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 */
5246 +#endif
5247 +               } r;
5248 +       } gp;
5249 +
5250 +       union {
5251 +               unsigned char b[DC_REG_SIZE];
5252 +
5253 +               struct {
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 */
5290 +
5291 +#ifdef _GEODELX_
5292 +                       u32 gfx_scale;
5293 +                       u32 irq_filt_ctl;
5294 +                       u32 filt_coeff1;
5295 +                       u32 filt_coeff2;
5296 +                       u32 vbi_event_ctl;
5297 +                       u32 vbi_odd_ctl;
5298 +                       u32 vbi_hor;
5299 +                       u32 vbi_ln_odd;
5300 +                       u32 vbi_ln_event;
5301 +                       u32 vbi_pitch;
5302 +                       u32 clr_key;
5303 +                       u32 clr_key_mask;
5304 +                       u32 clr_key_x;
5305 +                       u32 clr_key_y;
5306 +                       u32 irq;
5307 +                       u32 rsvd8;
5308 +                       u32 genlk_ctrl;
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 */
5315 +#endif
5316 +               } r;
5317 +       } dc;
5318 +
5319 +       union {
5320 +               unsigned char b[VP_REG_SIZE];
5321 +
5322 +               struct {
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 */
5362 +#ifdef _GEODELX_
5363 +                       u64 vye;                /* 0x138 */
5364 +                       u64 a1ye;               /* 0x140 */
5365 +                       u32 a2ye;               /* 0x148 */
5366 +                       u32 a3ye;               /* 0x150 */
5367 +#endif
5368 +               } r;
5369 +       } vp;
5370 +
5371 +       union {
5372 +               unsigned char b[FP_REG_SIZE];
5373 +
5374 +               struct {
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 */
5389 +               } r;
5390 +       } fp;
5391 +
5392 +       u32 pal[DC_PAL_SIZE];
5393 +       u32 gamma[256];
5394 +
5395 +#ifdef _GEODELX_
5396 +
5397 +       u32 hcoeff[DC_HFILT_SIZE * 2];
5398 +       u32 vcoeff[DC_VFILT_SIZE];
5399 +
5400 +       u32 vp_coeff[VP_COEFF_COUNT];
5401 +#endif
5402 +};
5403 +
5404 +#endif
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
5409 @@ -30,12 +30,31 @@
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>
5418  
5419  #include "geodefb.h"
5420  #include "display_gx.h"
5421  #include "video_gx.h"
5422  
5423 +#define FBIOSGAMMA             _IOW('F', 0x20, void *)
5424 +#define FBIOGGAMMA             _IOW('F', 0x21, void *)
5425 +
5426 +#ifdef DEBUG
5427 +
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 *)
5432 +
5433 +#endif
5434 +
5435  static char *mode_option;
5436 +static int noclear;
5437 +struct fb_info *gxfb_info;
5438  
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 }
5448  };
5449  
5450 +#ifdef CONFIG_OLPC
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 }
5455 +};
5456 +#endif
5457 +
5458 +
5459  static int gxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
5460  {
5461         if (var->xres > 1600 || var->yres > 1200)
5462 @@ -137,7 +168,7 @@ static int gxfb_check_var(struct fb_var_
5463         return 0;
5464  }
5465  
5466 -static int gxfb_set_par(struct fb_info *info)
5467 +int gxfb_set_par(struct fb_info *info)
5468  {
5469         struct geodefb_par *par = info->par;
5470  
5471 @@ -204,16 +235,26 @@ static int gxfb_blank(int blank_mode, st
5472         return par->vid_ops->blank_display(info, blank_mode);
5473  }
5474  
5475 +static int fbsize;
5476 +
5477  static int __init gxfb_map_video_memory(struct fb_info *info, struct pci_dev *dev)
5478  {
5479         struct geodefb_par *par = info->par;
5480 -       int fb_len;
5481         int ret;
5482  
5483         ret = pci_enable_device(dev);
5484         if (ret < 0)
5485                 return ret;
5486  
5487 +       ret = pci_request_region(dev, 1, "gxfb (graphics processor)");
5488 +       if (ret < 0)
5489 +               return ret;
5490 +
5491 +       par->gp_regs = ioremap(pci_resource_start(dev, 1),
5492 +                               pci_resource_len(dev, 1));
5493 +       if (!par->gp_regs)
5494 +               return -ENOMEM;
5495 +
5496         ret = pci_request_region(dev, 3, "gxfb (video processor)");
5497         if (ret < 0)
5498                 return ret;
5499 @@ -232,36 +273,118 @@ static int __init gxfb_map_video_memory(
5500         ret = pci_request_region(dev, 0, "gxfb (framebuffer)");
5501         if (ret < 0)
5502                 return ret;
5503 -       if ((fb_len = gx_frame_buffer_size()) < 0)
5504 -               return -ENOMEM;
5505 +
5506 +       /* If the fbsize wasn't specified then try to probe it */
5507 +
5508 +       if (!fbsize) {
5509 +               fbsize = gx_frame_buffer_size();
5510 +               if (fbsize == 0)
5511 +                       return -ENOMEM;
5512 +       }
5513 +
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)
5519                 return -ENOMEM;
5520  
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 */
5524  
5525         writel(info->fix.smem_start & 0xFF000000,
5526                         par->dc_regs + DC_GLIU0_MEM_OFFSET);
5527  
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);
5531  
5532         return 0;
5533  }
5534  
5535 +static int gxfb_ioctl( struct fb_info *info, unsigned int cmd,
5536 +                      unsigned long arg)
5537 +{
5538 +       unsigned int gamma[GXFB_GAMMA_DWORDS];
5539 +       int ret = -EINVAL;
5540 +       struct geodefb_par *par = info->par;
5541 +       int i;
5542 +
5543 +       switch(cmd) {
5544 +       case FBIOSGAMMA:
5545 +               /* Read the gamma information from the user - 256 dwords */
5546 +
5547 +               if (copy_from_user(gamma, (void * __user) arg, GXFB_GAMMA_SIZE))
5548 +                       return -EFAULT;
5549 +
5550 +               writel(0, par->vid_regs + GX_GAR);
5551 +
5552 +               /* Sequential writes to the data register will increment the
5553 +                  address automatically  */
5554 +
5555 +               for(i = 0; i < GXFB_GAMMA_DWORDS; i++)
5556 +                       writel(gamma[i] & 0xFFFFFF, par->vid_regs + GX_GDR);
5557 +
5558 +               writel(readl(par->vid_regs + GX_MISC) & ~GX_MISC_GAM_EN,
5559 +                      par->vid_regs + GX_MISC);
5560 +
5561 +               ret = 0;
5562 +               break;
5563 +
5564 +       case FBIOGGAMMA:
5565 +               if (readl(par->vid_regs + GX_MISC) & GX_MISC_GAM_EN)
5566 +                       return -EINVAL;
5567 +
5568 +               memset(gamma, 0, GXFB_GAMMA_SIZE);
5569 +               writel(0, par->vid_regs + GX_GAR);
5570 +
5571 +               for(i = 0; i < GXFB_GAMMA_DWORDS;i++)
5572 +                       gamma[i] = readl(par->vid_regs + GX_GDR);
5573 +
5574 +               if (copy_to_user((void * __user) arg, gamma, GXFB_GAMMA_SIZE))
5575 +                       ret = -EFAULT;
5576 +               else
5577 +                       ret = 0;
5578 +
5579 +               break;
5580 +
5581 +#ifdef DEBUG
5582 +       case FBIODUMPGP:
5583 +               ret = 0;
5584 +               dump_regs(info, 0);
5585 +               break;
5586 +               
5587 +       case FBIODUMPDC:
5588 +               ret = 0;
5589 +               dump_regs(info, 1);
5590 +               break;
5591 +
5592 +       case FBIODUMPVP:
5593 +               ret = 0;
5594 +               dump_regs(info, 2);
5595 +               break;
5596 +
5597 +       case FBIODUMPFP:
5598 +               ret = 0;
5599 +               dump_regs(info, 3);
5600 +               break;
5601 +#endif
5602 +       }
5603 +
5604 +       return ret;
5605 +}
5606 +
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,
5620  };
5621  
5622  static struct fb_info * __init gxfb_init_fbinfo(struct device *dev)
5623 @@ -303,23 +426,86 @@ static struct fb_info * __init gxfb_init
5624         return info;
5625  }
5626  
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)
5630 +{
5631 +       if (gxfb_info != NULL) {
5632 +               struct geodefb_par *par = gxfb_info->par;
5633 +               par->fbactive = (action == CONSOLE_EVENT_SWITCH_TEXT) ? 0 : 1;
5634 +       }
5635 +
5636 +       return NOTIFY_OK;
5637 +}
5638 +
5639 +static struct notifier_block gxfb_console_notifier = {
5640 +       .notifier_call = gxfb_console_notify
5641 +};
5642 +
5643 +#ifdef CONFIG_PM
5644 +
5645 +static int gxfb_suspend(struct pci_dev *pdev,  pm_message_t state)
5646 +{
5647 +       struct fb_info *info = pci_get_drvdata(pdev);
5648 +       struct geodefb_par *par = info->par;
5649 +
5650 +       if (pdev->dev.power.power_state.event == state.event)
5651 +               return 0;
5652 +
5653 +       if (state.event == PM_EVENT_SUSPEND) {
5654 +        
5655 +               acquire_console_sem();
5656 +               gxfb_powerdown(info);
5657 +
5658 +               par->state = FB_POWER_STATE_OFF;
5659 +               fb_set_suspend(info, 1);
5660 +               
5661 +               release_console_sem();
5662 +       }
5663 +
5664 +       pdev->dev.power.power_state = state;
5665 +       return 0;
5666 +}
5667 +
5668 +static int gxfb_resume(struct pci_dev *pdev)
5669 +{
5670 +       struct fb_info *info = pci_get_drvdata(pdev);
5671 +
5672 +       acquire_console_sem();
5673 +       
5674 +       /* Turn the engine completely on */
5675 +
5676 +       if (gxfb_powerup(info))
5677 +         printk(KERN_ERR "gxfb:  Powerup failed\n");
5678 +
5679 +       fb_set_suspend(info, 0);
5680 +       release_console_sem();
5681 +
5682 +       pdev->dev.power.power_state = PMSG_ON;
5683 +        return 0;
5684 +}
5685 +#endif
5686 +
5687 +static int __init gxfb_probe(struct pci_dev *pdev,
5688 +                            const struct pci_device_id *id)
5689  {
5690         struct geodefb_par *par;
5691 -       struct fb_info *info;
5692         int ret;
5693         unsigned long val;
5694  
5695 -       info = gxfb_init_fbinfo(&pdev->dev);
5696 -       if (!info)
5697 +       struct fb_videomode *modedb_ptr;
5698 +       int modedb_size;
5699 +
5700 +       gxfb_info = gxfb_init_fbinfo(&pdev->dev);
5701 +       if (gxfb_info == NULL)
5702                 return -ENOMEM;
5703 -       par = info->par;
5704 +
5705 +       par = gxfb_info->par;
5706  
5707         /* GX display controller and GX video device. */
5708         par->dc_ops  = &gx_dc_ops;
5709         par->vid_ops = &gx_vid_ops;
5710  
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");
5714                 goto err;
5715         }
5716 @@ -333,32 +519,60 @@ static int __init gxfb_probe(struct pci_
5717         else
5718                 par->enable_crt = 1;
5719  
5720 -       ret = fb_find_mode(&info->var, info, mode_option,
5721 -                          gx_modedb, ARRAY_SIZE(gx_modedb), NULL, 16);
5722 +       /* Get the current dotclock */
5723 +
5724 +       par->curdclk = (par->vid_ops->get_dclk) ? par->vid_ops->get_dclk(gxfb_info) : 0;
5725 +
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.
5729 +        */
5730 +
5731 +       modedb_ptr = (struct fb_videomode *) gx_modedb;
5732 +       modedb_size = ARRAY_SIZE(gx_modedb);
5733 +
5734 +#ifdef CONFIG_OLPC
5735 +       if (olpc_has_dcon()) {
5736 +               modedb_ptr = (struct fb_videomode *) gx_dcon_modedb;
5737 +               modedb_size = ARRAY_SIZE(gx_dcon_modedb);
5738 +       }
5739 +#endif
5740 +
5741 +       ret = fb_find_mode(&gxfb_info->var, gxfb_info, mode_option,
5742 +                          modedb_ptr, modedb_size, NULL, 16);
5743 +
5744         if (ret == 0 || ret == 4) {
5745                 dev_err(&pdev->dev, "could not find valid video mode\n");
5746                 ret = -EINVAL;
5747                 goto err;
5748         }
5749  
5750 +       /* Clear the screen of garbage, unless noclear was specified,
5751 +        * in which case we assume the user knows what he is doing */
5752 +
5753 +       if (!noclear)
5754 +               memset_io(gxfb_info->screen_base, 0, gxfb_info->fix.smem_len);
5755 +
5756 +       gxfb_check_var(&gxfb_info->var, gxfb_info);
5757 +       gxfb_set_par(gxfb_info);
5758 +
5759 +       /* We are powered up */
5760 +       par->state = FB_POWER_STATE_ON;
5761  
5762 -       /* Clear the frame buffer of garbage. */
5763 -        memset_io(info->screen_base, 0, info->fix.smem_len);
5764  
5765 -       gxfb_check_var(&info->var, info);
5766 -       gxfb_set_par(info);
5767 +       console_event_register(&gxfb_console_notifier);
5768  
5769 -       if (register_framebuffer(info) < 0) {
5770 +       if (register_framebuffer(gxfb_info) < 0) {
5771                 ret = -EINVAL;
5772                 goto err;
5773         }
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);
5778         return 0;
5779  
5780    err:
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);
5786         }
5787         if (par->vid_regs) {
5788 @@ -370,8 +584,9 @@ static int __init gxfb_probe(struct pci_
5789                 pci_release_region(pdev, 2);
5790         }
5791  
5792 -       if (info)
5793 -               framebuffer_release(info);
5794 +       if (gxfb_info)
5795 +               framebuffer_release(gxfb_info);
5796 +
5797         return ret;
5798  }
5799  
5800 @@ -397,9 +612,7 @@ static void gxfb_remove(struct pci_dev *
5801  }
5802  
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,
5806 -         0xff0000, 0 },
5807 +       { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_GX_VIDEO) },
5808         { 0, }
5809  };
5810  
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,
5815 +#ifdef CONFIG_PM
5816 +       .suspend        = gxfb_suspend,
5817 +       .resume         = gxfb_resume
5818 +#endif
5819  };
5820  
5821  #ifndef MODULE
5822 -static int __init gxfb_setup(char *options)
5823 -{
5824 +static int __init gxfb_setup(char *options) {
5825  
5826         char *opt;
5827  
5828         if (!options || !*options)
5829                 return 0;
5830  
5831 -       while ((opt = strsep(&options, ",")) != NULL) {
5832 +       while((opt = strsep(&options, ",")) != NULL) {
5833                 if (!*opt)
5834                         continue;
5835  
5836 -               mode_option = opt;
5837 +               if (!strncmp(opt, "fbsize:", 7))
5838 +                       fbsize = simple_strtoul(opt+7, NULL, 0);
5839 +               else if (!strcmp(opt, "noclear"))
5840 +                       noclear = 1;
5841 +               else
5842 +                       mode_option = opt;
5843         }
5844  
5845         return 0;
5846 @@ -444,7 +665,6 @@ static int __init gxfb_init(void)
5847  #endif
5848         return pci_register_driver(&gxfb_driver);
5849  }
5850 -
5851  static void __exit gxfb_cleanup(void)
5852  {
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>])");
5857  
5858 +module_param(fbsize, int, 0);
5859 +MODULE_PARM_DESC(fbsize, "video memory size");
5860 +
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
5868  
5869           If unsure, say N.
5870  
5871 -config FB_GEODE_GX_SET_FBSIZE
5872 -       bool "Manually specify the Geode GX framebuffer size"
5873 -       depends on FB_GEODE_GX
5874 -       default n
5875 -       ---help---
5876 -         If you want to manually specify the size of your GX framebuffer,
5877 -         say Y here, otherwise say N to dynamically probe it.
5878 -
5879 -         Say N unless you know what you are doing.
5880 -
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"
5885 -       ---help---
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
5889 -         you are doing
5890 -
5891  config FB_GEODE_GX1
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
5898 @@ -21,7 +21,8 @@
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>
5905  
5906  #include "lxfb.h"
5907  
5908 @@ -35,186 +36,84 @@ static int fbsize;
5909   */
5910  
5911  const struct fb_videomode geode_modedb[] __initdata = {
5912 -       /* 640x480-60 */
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 },
5966 -       /* 640x400-70 */
5967 -       { NULL, 70, 640, 400, 39770, 40, 8, 28, 5, 96, 2,
5968 -         FB_SYNC_HOR_HIGH_ACT,
5969 -         FB_VMODE_NONINTERLACED, 0 },
5970 -       /* 640x480-70 */
5971 -       { NULL, 70, 640, 480, 35014, 88, 24, 15, 2, 64, 3,
5972 -         0, FB_VMODE_NONINTERLACED, 0 },
5973 -       /* 640x480-72 */
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 },
5977 -       /* 640x480-75 */
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 },
5981 -       /* 640x480-85 */
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 },
5985 -       /* 640x480-90 */
5986 -       { NULL, 90, 640, 480, 26392, 96, 32, 22, 1, 64, 3,
5987 -         0, FB_VMODE_NONINTERLACED, 0 },
5988 -       /* 640x480-100 */
5989 -       { NULL, 100, 640, 480, 23167, 104, 40, 25, 1, 64, 3,
5990 -         0, FB_VMODE_NONINTERLACED, 0 },
5991 -       /* 640x480-60 */
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 },
5995 -       /* 800x600-56 */
5996 -       { NULL, 56, 800, 600, 27901, 128, 24, 22, 1, 72, 2,
5997 -         0, FB_VMODE_NONINTERLACED, 0 },
5998 -       /* 800x600-60 */
5999 -       { NULL, 60, 800, 600, 25131, 72, 32, 23, 1, 136, 4,
6000 -         0, FB_VMODE_NONINTERLACED, 0 },
6001 -       /* 800x600-70 */
6002 -       { NULL, 70, 800, 600, 21873, 120, 40, 21, 4, 80, 3,
6003 -         0, FB_VMODE_NONINTERLACED, 0 },
6004 -       /* 800x600-72 */
6005 -       { NULL, 72, 800, 600, 20052, 64, 56, 23, 37, 120, 6,
6006 -         0, FB_VMODE_NONINTERLACED, 0 },
6007 -       /* 800x600-75 */
6008 -       { NULL, 75, 800, 600, 20202, 160, 16, 21, 1, 80, 3,
6009 -         0, FB_VMODE_NONINTERLACED, 0 },
6010 -       /* 800x600-85 */
6011 -       { NULL, 85, 800, 600, 17790, 152, 32, 27, 1, 64, 3,
6012 -         0, FB_VMODE_NONINTERLACED, 0 },
6013 -       /* 800x600-90 */
6014 -       { NULL, 90, 800, 600, 16648, 128, 40, 28, 1, 88, 3,
6015 -         0, FB_VMODE_NONINTERLACED, 0 },
6016 -       /* 800x600-100 */
6017 -       { NULL, 100, 800, 600, 14667, 136, 48, 27, 1, 88, 3,
6018 -         0, FB_VMODE_NONINTERLACED, 0 },
6019 -       /* 800x600-60 */
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 },
6023 -       /* 1024x768-60 */
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 },
6027 -       /* 1024x768-70 */
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 },
6031 -       /* 1024x768-72 */
6032 -       { NULL, 72, 1024, 768, 12702, 168, 56, 29, 4, 112, 3,
6033 -         0, FB_VMODE_NONINTERLACED, 0 },
6034 -       /* 1024x768-75 */
6035 -       { NULL, 75, 1024, 768, 12703, 176, 16, 28, 1, 96, 3,
6036 -         0, FB_VMODE_NONINTERLACED, 0 },
6037 -       /* 1024x768-85 */
6038 -       { NULL, 85, 1024, 768, 10581, 208, 48, 36, 1, 96, 3,
6039 -         0, FB_VMODE_NONINTERLACED, 0 },
6040 -       /* 1024x768-90 */
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 },
6046 -       /* 1024x768-60 */
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 },
6050 -       /* 1152x864-60 */
6051 -       { NULL, 60, 1152, 864, 12251, 184, 64, 27, 1, 120, 3,
6052 -         0, FB_VMODE_NONINTERLACED, 0 },
6053 -       /* 1152x864-70 */
6054 -       { NULL, 70, 1152, 864, 10254, 192, 72, 32, 8, 120, 3,
6055 -         0, FB_VMODE_NONINTERLACED, 0 },
6056 -       /* 1152x864-72 */
6057 -       { NULL, 72, 1152, 864, 9866, 200, 72, 33, 7, 128, 3,
6058 -         0, FB_VMODE_NONINTERLACED, 0 },
6059 -       /* 1152x864-75 */
6060 -       { NULL, 75, 1152, 864, 9259, 256, 64, 32, 1, 128, 3,
6061 -         0, FB_VMODE_NONINTERLACED, 0 },
6062 -       /* 1152x864-85 */
6063 -       { NULL, 85, 1152, 864, 8357, 200, 72, 37, 3, 128, 3,
6064 -         0, FB_VMODE_NONINTERLACED, 0 },
6065 -       /* 1152x864-90 */
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 },
6071 -       /* 1152x864-60 */
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 }
6152  };
6153  
6154 +#ifdef CONFIG_OLPC
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 }
6160 +};
6161 +#endif
6162 +
6163  static int lxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
6164  {
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);
6168         }
6169  
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);
6173  
6174         lx_set_mode(info);
6175         return 0;
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);
6179  
6180 -       writel(0, par->dc_regs + DC_UNLOCK);
6181 -
6182         dev_info(&dev->dev, "%d KB of video memory at 0x%lx\n",
6183                  info->fix.smem_len / 1024, info->fix.smem_start);
6184  
6185         return 0;
6186  }
6187  
6188 +static int lxfb_set_gamma(struct fb_info *info, void * __user data)
6189 +{
6190 +       unsigned int gamma[LXFB_GAMMA_DWORDS];
6191 +
6192 +       if (copy_from_user(gamma, data, LXFB_GAMMA_SIZE))
6193 +               return -EFAULT;
6194 +
6195 +       lx_set_gamma(info, gamma, LXFB_GAMMA_SIZE);
6196 +       return 0;
6197 +}
6198 +
6199 +static int lxfb_get_gamma(struct fb_info *info, void * __user data)
6200 +{
6201 +       unsigned int gamma[LXFB_GAMMA_DWORDS];
6202 +       memset(gamma, 0, sizeof(gamma));
6203 +
6204 +       lx_get_gamma(info, gamma, LXFB_GAMMA_DWORDS);
6205 +
6206 +       return copy_to_user(data, gamma, LXFB_GAMMA_SIZE) ?
6207 +               -EFAULT : 0;
6208 +}
6209 +
6210 +static int lxfb_ioctl( struct fb_info *info, unsigned int cmd,
6211 +                      unsigned long arg)
6212 +{
6213 +       switch(cmd) {
6214 +       case FBIOSGAMMA:
6215 +               return lxfb_set_gamma(info, (void * __user) arg);
6216 +
6217 +       case FBIOGGAMMA:
6218 +               return lxfb_get_gamma(info, (void * __user) arg);
6219 +       }
6220 +
6221 +       return -ENOTTY;
6222 +}
6223 +
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,
6237  };
6238  
6239  static struct fb_info * __init lxfb_init_fbinfo(struct device *dev)
6240 @@ -431,6 +366,45 @@ static struct fb_info * __init lxfb_init
6241         return info;
6242  }
6243  
6244 +#ifdef CONFIG_PM
6245 +
6246 +static int lxfb_suspend(struct pci_dev *pdev,  pm_message_t state)
6247 +{
6248 +       struct fb_info *info = pci_get_drvdata(pdev);
6249 +
6250 +       if (pdev->dev.power.power_state.event == state.event)
6251 +               return 0;
6252 +
6253 +       if (state.event == PM_EVENT_SUSPEND) {
6254 +
6255 +               acquire_console_sem();
6256 +               lx_shutdown(info);
6257 +               fb_set_suspend(info, 1);
6258 +               release_console_sem();
6259 +       }
6260 +
6261 +       pdev->dev.power.power_state = state;
6262 +       return 0;
6263 +}
6264 +
6265 +static int lxfb_resume(struct pci_dev *pdev)
6266 +{
6267 +       struct fb_info *info = pci_get_drvdata(pdev);
6268 +
6269 +       acquire_console_sem();
6270 +
6271 +       /* Turn the engine completely on */
6272 +
6273 +       lx_powerup(info);
6274 +       fb_set_suspend(info, 0);
6275 +       release_console_sem();
6276 +
6277 +       pdev->dev.power.power_state = PMSG_ON;
6278 +        return 0;
6279 +}
6280 +
6281 +#endif
6282 +
6283  static int __init lxfb_probe(struct pci_dev *pdev,
6284                              const struct pci_device_id *id)
6285  {
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);
6289  
6290 +#ifdef CONFIG_OLPC
6291 +       if (olpc_has_dcon()) {
6292 +               modedb_ptr = (struct fb_videomode *) olpc_dcon_modedb;
6293 +               modedb_size = ARRAY_SIZE(olpc_dcon_modedb);
6294 +       }
6295 +#endif
6296 +
6297         ret = fb_find_mode(&info->var, info, mode_option,
6298                            modedb_ptr, modedb_size, NULL, 16);
6299  
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,
6304 +#ifdef CONFIG_PM
6305 +       .suspend        = lxfb_suspend,
6306 +       .resume         = lxfb_resume
6307 +#endif
6308  };
6309  
6310  #ifndef MODULE
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);
6324  
6325 +
6326 +
6327 +/* ioctl() defines */
6328 +
6329 +#define FBIOSGAMMA              _IOW('F', 0x20, void *)
6330 +#define FBIOGGAMMA              _IOW('F', 0x21, void *)
6331 +
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))
6335 +
6336  /* MSRS */
6337  
6338  #define MSR_LX_GLD_CONFIG    0x48002001
6339 @@ -127,7 +140,7 @@ void lx_set_palette_reg(struct fb_info *
6340  
6341  #define DC_GFX_SCALE       0x90
6342  #define DC_IRQ_FILT_CTL    0x94
6343 -
6344 +#define DC_IRQFILT_H_FILT_SEL              0x00000400
6345  
6346  #define DC_IRQ               0xC8
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
6352 @@ -11,11 +11,15 @@
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>
6361  
6362  #include "lxfb.h"
6363  
6364 +#define _GEODELX_
6365 +#include "geode_regs.h"
6366 +
6367  /* TODO
6368   * Support panel scaling
6369   * Add acceleration
6370 @@ -290,6 +294,19 @@ unsigned int lx_framebuffer_size(void)
6371  {
6372         unsigned int val;
6373  
6374 +#ifdef CONFIG_OLPC
6375 +        if (machine_is_olpc() && !olpc_has_vsa()) {
6376 +               u32 hi,lo;
6377 +               rdmsr(MSR_LX_GLIU0_P2D_RO0, lo, hi);
6378 +
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);
6384 +       }
6385 +#endif
6386 +
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)
6391         return (val << 20);
6392  }
6393  
6394 +void lx_set_gamma(struct fb_info *info, unsigned int *gamma, int len)
6395 +{
6396 +       int i;
6397 +       struct lxfb_par *par = info->par;
6398 +
6399 +       writel(0, par->df_regs + DF_PAR);
6400 +
6401 +       /* Sequential writes to the data register will increment the
6402 +          address automatically  */
6403 +
6404 +       for(i = 0; i < len; i++)
6405 +               writel(gamma[i] & 0xFFFFFF, par->df_regs + DF_PDR);
6406 +
6407 +       writel(readl(par->df_regs + DF_MISC) & ~DF_MISC_GAM_BYPASS,
6408 +              par->df_regs + DF_MISC);
6409 +}
6410 +
6411 +void lx_get_gamma(struct fb_info *info, unsigned int *gamma, int len)
6412 +{
6413 +       int i;
6414 +       struct lxfb_par *par = info->par;
6415 +
6416 +       writel(0, par->df_regs + DF_PAR);
6417 +
6418 +       for(i = 0; i < len;i++)
6419 +               gamma[i] = readl(par->df_regs + DF_PDR);
6420 +}
6421 +
6422  void lx_set_mode(struct fb_info *info)
6423  {
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;
6427  
6428         /* Unlock the DC registers */
6429 +       readl(par->dc_regs + DC_UNLOCK);
6430         writel(DC_UNLOCK_CODE, par->dc_regs + DC_UNLOCK);
6431  
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);
6435  }
6436  
6437 +static int lx_blank_mode = FB_BLANK_UNBLANK;
6438 +
6439  int lx_blank_display(struct fb_info *info, int blank_mode)
6440  {
6441         struct lxfb_par *par = info->par;
6442 -       u32 dcfg, fp_pm;
6443 -       int blank, hsync, vsync;
6444 +       u32 dcfg, val;
6445 +
6446 +       if (blank_mode == lx_blank_mode)
6447 +               return 0;
6448 +
6449 +       writel(DC_UNLOCK_CODE, par->dc_regs + DC_UNLOCK);
6450 +
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);
6456 +
6457 +               val = readl(par->dc_regs + DC_GENERAL_CFG) | DC_GCFG_DFLE;
6458 +               writel(val, par->dc_regs + DC_GENERAL_CFG);
6459 +
6460 +               val = readl(par->dc_regs + DC_DISPLAY_CFG) | DC_DCFG_TGEN;
6461 +               writel(val, par->dc_regs + DC_DISPLAY_CFG);
6462 +       }
6463 +
6464 +       dcfg = readl(par->df_regs + DF_DISPLAY_CFG);
6465  
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;
6472                 break;
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;
6477                 break;
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;
6482                 break;
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;
6487                 break;
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);
6492                 break;
6493         default:
6494 +               writel(0, par->dc_regs + DC_UNLOCK);
6495                 return -EINVAL;
6496         }
6497  
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);
6501 -       if (!blank)
6502 -               dcfg |= DF_DCFG_DAC_BL_EN;
6503 -       if (hsync)
6504 -               dcfg |= DF_DCFG_HSYNC_EN;
6505 -       if (vsync)
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);
6512 +
6513 +               val = readl(par->dc_regs + DC_DISPLAY_CFG);
6514 +               val &= ~DC_DCFG_TGEN;
6515 +               writel(val, par->dc_regs + DC_DISPLAY_CFG);
6516 +
6517 +               udelay(1000);
6518 +
6519 +               val = readl(par->dc_regs + DC_GENERAL_CFG) & ~DC_GCFG_DFLE;
6520 +               writel(val, par->dc_regs + DC_GENERAL_CFG);
6521 +
6522 +               val = readl(par->df_regs + DF_FP_PM);
6523 +               writel(val & ~DF_FP_PM_P, par->df_regs + DF_FP_PM);
6524 +       }
6525  
6526 +       writel(0, par->dc_regs + DC_UNLOCK);
6527 +
6528 +       lx_blank_mode = blank_mode;
6529 +       return 0;
6530 +}
6531 +
6532 +static struct geoderegs saved_regs;
6533 +
6534 +static void lx_save_regs(struct fb_info *info, struct geoderegs *regs)
6535 +{
6536 +       struct lxfb_par *par = info->par;
6537 +       int i;
6538 +       u32 filt;
6539 +
6540 +       /* Wait for the command buffer to empty */
6541 +       while(!(readl(par->gp_regs + 0x44) & (1 << 4)));
6542 +
6543 +       /* Unlock the DC */
6544 +       writel(DC_UNLOCK_CODE, par->dc_regs + DC_UNLOCK);
6545 +
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);
6550 +
6551 +       writel(0x4758, par->dc_regs + 0x00);
6552 +
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);
6557 +
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);
6563  
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;
6568 -               else
6569 -                       fp_pm |= DF_FP_PM_P;
6570 -               writel(fp_pm, par->df_regs + DF_FP_PM);
6571 +       /* save the filter coefficients */
6572 +
6573 +       filt = readl(par->dc_regs + 0x94);
6574 +       filt |= DC_IRQFILT_H_FILT_SEL;
6575 +
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);
6580 +       }
6581 +
6582 +       filt &= ~DC_IRQFILT_H_FILT_SEL;
6583 +
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);
6587         }
6588  
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));
6593 +
6594 +       /* Save the VP gamma */
6595 +
6596 +       writel(0, par->df_regs + 0x38);
6597 +
6598 +       for(i = 0; i <= 0xFF; i++)
6599 +               regs->gamma[i] = readl(par->df_regs + 0x40);
6600 +}
6601 +
6602 +static void lx_restore_dc(struct lxfb_par *par, struct geoderegs *regs)
6603 +{
6604 +       u32 filt;
6605 +       int i;
6606 +
6607 +       /* Unlock the registers */
6608 +       writel(DC_UNLOCK_CODE, par->dc_regs + 0x00);
6609 +
6610 +       /* Restore the framebuffer offset */
6611 +       writel(regs->dc.r.gliu0_mem_offset, par->dc_regs + 0x84);
6612 +
6613 +       /* Blank the configuration registers while we restore */
6614 +       writel(0, par->dc_regs + 0x04);
6615 +       writel(0, par->dc_regs + 0x08);
6616 +
6617 +       /* Restore the bulk of the registers */
6618 +
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);
6623 +
6624 +       /* skip 0x1c */
6625 +
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);
6629 +
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);
6643 +
6644 +       /* skip 0x68, 0x6c, 0x70, 0x74, 0x78, 0x7c */
6645 +
6646 +       writel(regs->dc.r.dc_vid_ds_delta, par->dc_regs + 0x80);
6647 +
6648 +       /* 0x84 was written above */
6649 +
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);
6653 +
6654 +       /* skip 0x98, 0x9c */
6655 +
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);
6674 +
6675 +       /* Restore the palette */
6676 +       writel(0, par->dc_regs + 0x70);
6677 +
6678 +       for(i = 0; i < DC_PAL_SIZE; i++)
6679 +               writel(regs->pal[i], par->dc_regs + 0x74);
6680 +
6681 +       /* Restore the horizontal filter coefficients */
6682 +       filt = readl(par->dc_regs + 0x94);
6683 +       filt |= DC_IRQFILT_H_FILT_SEL;
6684 +
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);
6689 +       }
6690 +
6691 +       filt &= ~DC_IRQFILT_H_FILT_SEL;
6692 +
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);
6696 +       }
6697 +
6698 +       /* Turn on the dotpll */
6699 +       lx_set_dotpll((u32) (regs->msr.dotpll >> 32));
6700 +
6701 +       /* Restore MSRs */
6702 +       wrmsrl(MSR_LX_DC_SPARE, regs->msr.dcspare);
6703 +
6704 +       /* Restore the configuration registers */
6705 +
6706 +       writel(regs->dc.r.dcfg, par->dc_regs + 0x08);
6707 +       writel(regs->dc.r.gcfg, par->dc_regs + 0x04);
6708 +
6709 +       /* Lock the DC again */
6710 +       writel(0, par->dc_regs + 0x00);
6711 +}
6712 +
6713 +static void lx_restore_vp(struct lxfb_par *par, struct geoderegs *regs)
6714 +{
6715 +       u32 val;
6716 +       int i;
6717 +
6718 +       /* Restore MSRs */
6719 +
6720 +       wrmsrl(MSR_LX_DF_GLCONFIG, regs->msr.dfglcfg);
6721 +       wrmsrl(MSR_LX_DF_PADSEL, regs->msr.padsel);
6722 +
6723 +       /* Restore the registers */
6724 +
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);
6733 +       /* skip 0x58 */
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);
6758 +
6759 +       /* Panel */
6760 +
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);
6764 +
6765 +       /* Restore panel power */
6766 +
6767 +       val = readl(par->df_regs + 0x410);
6768 +
6769 +       if (regs->fp.r.pm & (1 << 24)) {
6770 +               if (!(val & 0x09))
6771 +                       writel(regs->fp.r.pm, par->df_regs + 0x410);
6772 +       }
6773 +       else {
6774 +               if (!(val & 0x05))
6775 +                       writel(regs->fp.r.pm, par->df_regs + 0x410);
6776 +       }
6777 +
6778 +       /* Restore the vp palette */
6779 +
6780 +       writel(0, par->df_regs + 0x38);
6781 +
6782 +       for(i = 0; i <= 0xFF; i++)
6783 +               writel((u32) regs->gamma[i], par->df_regs + 0x40);
6784 +
6785 +       /* Restore filter coefficients */
6786 +
6787 +       for(i = 0; i < VP_COEFF_COUNT; i++)
6788 +               writel(regs->vp_coeff[i],
6789 +                      par->df_regs + 0x1000 + (i << 2));
6790 +
6791 +       /* Restore the configuration registers */
6792 +
6793 +       writel((u32) regs->vp.r.dcfg, par->df_regs + 0x08);
6794 +       writel((u32) regs->vp.r.vcfg, par->df_regs + 0x00);
6795 +}
6796 +
6797 +static void lx_restore_gp(struct lxfb_par *par, struct geoderegs *regs)
6798 +{
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);
6813 +
6814 +       /* Writing to these registers would cause a blt to happen */
6815 +       /* 0x38, 0x3c, 0x40 */
6816 +
6817 +       /* Status register (0x44) is read only */
6818 +
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);
6829 +
6830 +       writel(regs->gp.r.int_cntrl, par->gp_regs + 0x70);
6831 +}
6832 +
6833 +static void lx_restore_regs(struct fb_info *info, struct geoderegs *regs)
6834 +{
6835 +       struct lxfb_par *par = info->par;
6836 +
6837 +       lx_restore_gp(par, regs);
6838 +       lx_restore_vp(par, regs);
6839 +       lx_restore_dc(par, regs);
6840 +}
6841 +
6842 +static int lx_power_on = 1;
6843 +
6844 +int lx_shutdown(struct fb_info *info)
6845 +{
6846 +       if (lx_power_on == 0)
6847 +               return 0;
6848 +
6849 +       lx_save_regs(info, &saved_regs);
6850 +       lx_graphics_disable(info);
6851 +
6852 +       lx_power_on = 0;
6853 +       return 0;
6854 +}
6855 +
6856 +int lx_powerup(struct fb_info *info)
6857 +{
6858 +       if (lx_power_on == 1)
6859 +               return 0;
6860 +
6861 +       lx_restore_regs(info, &saved_regs);
6862 +
6863 +       lx_power_on = 1;
6864         return 0;
6865  }
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
6872  
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 ===================================================================
6879 --- /dev/null
6880 +++ linux-2.6.24.7/drivers/video/geode/suspend_gx.c
6881 @@ -0,0 +1,272 @@
6882 +#include <linux/fb.h>
6883 +#include <asm/io.h>
6884 +#include <asm/msr.h>
6885 +
6886 +#include "geodefb.h"
6887 +#include "video_gx.h"
6888 +
6889 +void gx_set_dotpll(struct fb_info *info, struct geoderegs *regs)
6890 +{
6891 +       int timeout = 1000;
6892 +
6893 +       u64 rstpll, dotpll;
6894 +       
6895 +       rdmsrl(MSR_GLCP_SYS_RSTPLL, rstpll);
6896 +       rdmsrl(MSR_GLCP_DOTPLL, dotpll);
6897 +
6898 +       dotpll &= 0x00000000ffffffffull;
6899 +       dotpll |= regs->msr.dotpll & 0xffffffff00000000ull;
6900 +       
6901 +       dotpll |= MSR_GLCP_DOTPLL_DOTRESET;
6902 +       dotpll &= ~MSR_GLCP_DOTPLL_BYPASS;
6903 +       
6904 +       wrmsrl(MSR_GLCP_DOTPLL, dotpll);
6905 +
6906 +       rstpll |= (regs->msr.rstpll & 
6907 +                  ( MSR_GLCP_SYS_RSTPLL_DOTPREDIV2  |
6908 +                    MSR_GLCP_SYS_RSTPLL_DOTPREMULT2 |
6909 +                    MSR_GLCP_SYS_RSTPLL_DOTPOSTDIV3));
6910 +       
6911 +       wrmsrl(MSR_GLCP_SYS_RSTPLL, rstpll);
6912 +       dotpll &= ~(MSR_GLCP_DOTPLL_DOTRESET);
6913 +       wrmsrl(MSR_GLCP_DOTPLL, dotpll);
6914 +
6915 +       do {
6916 +               rdmsrl(MSR_GLCP_DOTPLL, dotpll);
6917 +       } while (timeout-- && !(dotpll & MSR_GLCP_DOTPLL_LOCK));
6918 +}
6919 +
6920 +/* FIXME: Make sure nothing is read to clear */
6921 +
6922 +void gx_save_regs(struct fb_info *info, struct geoderegs *regs)
6923 +{
6924 +       struct geodefb_par *par = info->par;
6925 +       int i;
6926 +
6927 +       /* Wait for the BLT engine to stop being busy */
6928 +       while(readl(par->gp_regs + 0x44) & 0x05);
6929 +
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);
6933 +
6934 +       writel(0x4758, par->dc_regs + 0x00);
6935 +
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);
6940 +
6941 +       /* Save the palettes */
6942 +       writel(0, par->dc_regs + 0x70);
6943 +
6944 +       for(i = 0; i < DC_PAL_SIZE; i++) 
6945 +               regs->pal[i] = readl(par->dc_regs + 0x74);
6946 +       
6947 +       writel(0, par->vid_regs + 0x38);
6948 +
6949 +       for(i = 0; i < 0xFF; i++)
6950 +               regs->gamma[i] = readl(par->vid_regs + 0x40);           
6951 +}
6952 +
6953 +void gx_restore_regs(struct fb_info *info, struct geoderegs *regs)
6954 +{
6955 +       struct geodefb_par *par = info->par;
6956 +       u32 val, i;
6957 +
6958 +       /* DOTPLL */
6959 +       gx_set_dotpll(info, regs);
6960 +
6961 +       /* GP */
6962 +
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);
6977 +
6978 +       /* Don't write the raster / vector / blt mode regs */
6979 +       /* status register is read only */
6980 +
6981 +       writel(regs->gp.r.hst_src, par->gp_regs + 0x48);
6982 +       writel(regs->gp.r.base_offset, par->gp_regs + 0x4c);
6983 +       
6984 +       /* DC */
6985 +       
6986 +       /* Write the unlock value */
6987 +       writel(0x4758, par->dc_regs + 0x00);
6988 +
6989 +       writel(0, par->dc_regs + 0x70);
6990 +       
6991 +       for(i = 0; i < DC_PAL_SIZE; i++)
6992 +               writel(regs->pal[i], par->dc_regs + 0x74);
6993 +
6994 +       /* Write the gcfg register without the enables */
6995 +       writel(regs->dc.r.gcfg & ~0x0F, par->dc_regs + 0x04);
6996 +       
6997 +       /* Write the vcfg register without the enables */
6998 +       writel(regs->dc.r.dcfg & ~0x19, par->dc_regs + 0x08);
6999 +       
7000 +       /* Write the rest of the active registers */
7001 +
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);
7021 +       
7022 +       /* Don't write the line_cnt or diag registers */
7023 +
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);
7027 +       
7028 +       /* VP */
7029 +
7030 +       /* MSR */
7031 +       wrmsrl(GX_VP_MSR_PAD_SELECT, regs->msr.padsel);
7032 +
7033 +       writel(0, par->vid_regs + 0x38);
7034 +       
7035 +       for(i = 0; i < 0xFF; i++)
7036 +               writel((u32) regs->gamma[i], par->vid_regs + 0x40);   
7037 +
7038 +       /* Don't enable video yet */
7039 +       writel((u32) regs->vp.r.vcfg & ~0x01, par->vid_regs + 0x00);
7040 +
7041 +       /* Don't enable the CRT yet */
7042 +       writel((u32) regs->vp.r.dcfg & ~0x0F, par->vid_regs + 0x08);
7043 +
7044 +       /* Write the rest of the VP registers */
7045 +
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);
7074 +       
7075 +       
7076 +       /* FP registers */
7077 +       
7078 +       writel((u32) regs->fp.r.pt1, par->vid_regs + 0x400);
7079 +       writel((u32) regs->fp.r.pt2, par->vid_regs + 0x408);
7080 +
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);
7090 +       
7091 +       /* Final enables */
7092 +
7093 +       val = readl(par->vid_regs + 0x410);
7094 +
7095 +       /* Control the panel */
7096 +       if (regs->fp.r.pm & (1 << 24)) {
7097 +
7098 +               if (!(val & 0x09))
7099 +                       writel(regs->fp.r.pm, par->vid_regs + 0x410);
7100 +       }
7101 +       else {
7102 +               if (!(val & 0x05))
7103 +                       writel(regs->fp.r.pm, par->vid_regs + 0x410);
7104 +       }
7105 +               
7106 +       /* Turn everything on */
7107 +
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);
7112 +}
7113 +
7114 +
7115 +#ifdef DEBUG
7116 +
7117 +void dump_regs(struct fb_info *info, int mode) {
7118 +
7119 +       struct geodefb_par *par = info->par;
7120 +       u32 val;
7121 +       int i;
7122 +
7123 +       if (mode == 0) {
7124 +               for(i = 0; i < GP_REG_SIZE; i += 4) {
7125 +                       val = readl(par->gp_regs + i);
7126 +               }
7127 +       }
7128 +
7129 +       if (mode == 1) {
7130 +               writel(0x4758, par->dc_regs + 0x00);
7131 +
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);
7135 +               }
7136 +       }
7137 +
7138 +       if (mode == 2) {
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);
7142 +               }
7143 +       }
7144 +
7145 +       if (mode == 3) {
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);
7149 +               }
7150 +       }
7151 +}
7152 +
7153 +#endif
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
7158 @@ -16,10 +16,14 @@
7159  #include <asm/io.h>
7160  #include <asm/delay.h>
7161  #include <asm/msr.h>
7162 +#include <asm/olpc.h>
7163  
7164  #include "geodefb.h"
7165  #include "video_gx.h"
7166 +#include "display_gx.h"
7167  
7168 +/* This structure is used to store the saved registers during suspend */
7169 +static struct geoderegs gx_saved_regs;
7170  
7171  /*
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 */
7184  };
7185  
7186 -static void gx_set_dclk_frequency(struct fb_info *info)
7187 +void gx_set_dclk_frequency(struct fb_info *info)
7188  {
7189 +       struct geodefb_par *par = info->par;
7190         const struct gx_pll_entry *pll_table;
7191         int pll_table_len;
7192         int i, best_i;
7193 @@ -173,115 +178,169 @@ static void gx_set_dclk_frequency(struct
7194         do {
7195                 rdmsrl(MSR_GLCP_DOTPLL, dotpll);
7196         } while (timeout-- && !(dotpll & MSR_GLCP_DOTPLL_LOCK));
7197 +
7198 +       par->curdclk = pll_table[best_i].dotpll_value;
7199  }
7200  
7201 -static void
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 */
7205 +
7206 +unsigned int gx_get_dclk(struct fb_info *info)
7207  {
7208 -       struct geodefb_par *par = info->par;
7209 -       unsigned long val;
7210 -       unsigned long fp;
7211 +       const struct gx_pll_entry *pll_table;
7212 +       int pll_table_len;
7213 +       u64 dotpll;
7214 +       int i;
7215  
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);
7220 +       } else {
7221 +               pll_table = gx_pll_table_48MHz;
7222 +               pll_table_len = ARRAY_SIZE(gx_pll_table_48MHz);
7223 +       }
7224  
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);
7230  
7231 -       /* Turn off the panel */
7232 +       for(i = 0; i < pll_table_len; i++) {
7233 +               if (pll_table[i].dotpll_value == (u32) (dotpll >> 32))
7234 +                       break;
7235 +       }
7236 +
7237 +       return (i == pll_table_len) ? 0 : pll_table[i].pixclock;
7238 +}
7239  
7240 -       fp = readl(par->vid_regs + GX_FP_PM);
7241 -       fp &= ~GX_FP_PM_P;
7242 -       writel(fp, par->vid_regs + GX_FP_PM);
7243  
7244 -       /* Set timing 1 */
7245 +#define CMP(val, mask, res) (((val) & (mask)) == (res))
7246  
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);
7251 +static void
7252 +gx_configure_tft(struct fb_info *info) {
7253  
7254 -       /* Timing 2 */
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;
7258  
7259 -       fp = 0x0F100000;
7260 +       /* Set up the DF pad select MSR */
7261  
7262 -       /* Add sync polarity */
7263 +       rdmsrl(GX_VP_MSR_PAD_SELECT, val);
7264 +
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);
7269 +       }
7270  
7271         if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
7272 -               fp |= GX_FP_PT2_VSP;
7273 +               sync |= GX_FP_PT2_VSP;
7274  
7275         if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
7276 -               fp |= GX_FP_PT2_HSP;
7277 +               sync |= GX_FP_PT2_HSP;
7278  
7279 -       writel(fp, par->vid_regs + GX_FP_PT2);
7280 +       /* We only need to turn off the panel if something changed */
7281  
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);
7286 +
7287 +       if (!CMP(fp1, GX_FP_PT1_VSIZE_MASK, info->var.yres << GX_FP_PT1_VSIZE_SHIFT) ||
7288 +           (fp2 != (0x0F100000 | sync))) {
7289 +
7290 +               /* Turn off the panel */
7291 +
7292 +#ifdef NOTUSED
7293 +               /* Do we really need to turn off the panel? */
7294 +               /* Possibly - we have a glitch somewhere */
7295  
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);
7300 +#endif
7301  
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);
7305 +               /* Timing 1 */
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);
7309  
7310 -       /* Unblank the panel */
7311 +               /* Timing 2 */
7312 +               writel(0x0F100000 | sync, par->vid_regs + GX_FP_PT2);
7313 +       }
7314 +
7315 +       /*  Set the dither control */
7316 +       if (readl(par->vid_regs + GX_FP_DFC) != 0x70) {
7317 +               writel(0x70, par->vid_regs + GX_FP_DFC);
7318 +       }
7319 +
7320 +       /* Turn on the panel */
7321  
7322         fp = readl(par->vid_regs + GX_FP_PM);
7323 -       fp |= GX_FP_PM_P;
7324 -       writel(fp, par->vid_regs + GX_FP_PM);
7325 +
7326 +       if (!(fp & 0x09))
7327 +               writel(fp | GX_FP_PM_P, par->vid_regs + GX_FP_PM);
7328  }
7329  
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
7332 +
7333  static void gx_configure_display(struct fb_info *info)
7334  {
7335         struct geodefb_par *par = info->par;
7336 -       u32 dcfg, misc;
7337 +       u32 dcfg, misc, sync = 0;
7338  
7339         /* Set up the MISC register */
7340 -
7341         misc = readl(par->vid_regs + GX_MISC);
7342  
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 */
7349  
7350 -       /* Disable gamma correction */
7351 -       misc |= GX_MISC_GAM_EN;
7352  
7353 -       writel(misc, par->vid_regs + GX_MISC);
7354  
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);
7362 +               }
7363  
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;
7369  
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;
7376 +       }
7377 +       else {
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);
7382 +               }
7383 +       }
7384  
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);
7389  
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)) {
7394  
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);
7403  
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);
7410  
7411 -       dcfg |= GX_DCFG_CRT_EN | GX_DCFG_DAC_BL_EN;
7412 +               /* Set default sync skew.  */
7413 +               dcfg |= GX_DCFG_CRT_SYNC_SKW_DFLT;
7414  
7415 -       /* Enable the external DAC VREF? */
7416 +               /* Enable hsync and vsync. */
7417 +               dcfg |= GX_DCFG_HSYNC_EN | GX_DCFG_VSYNC_EN;
7418  
7419 -       writel(dcfg, par->vid_regs + GX_DCFG);
7420 +               /* Enable the display logic */
7421 +               dcfg |= GX_DCFG_CRT_EN | GX_DCFG_DAC_BL_EN;
7422 +
7423 +               writel(dcfg, par->vid_regs + GX_DCFG);
7424 +       }
7425  
7426         /* Set up the flat panel (if it is enabled) */
7427  
7428 @@ -289,6 +348,100 @@ static void gx_configure_display(struct 
7429                 gx_configure_tft(info);
7430  }
7431  
7432 +int gxfb_powerdown(struct fb_info *info) 
7433 +{
7434 +       struct geodefb_par *par = info->par;
7435 +
7436 +       /* We're already suspended */
7437 +
7438 +       if (par->state != FB_POWER_STATE_ON)
7439 +               return 0;
7440 +
7441 +       /* Save the registers */
7442 +       gx_save_regs(info, &gx_saved_regs);
7443 +
7444 +       /* Shut down the engine */
7445 +
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);
7448 +
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);
7452 +
7453 +       writel(0x4758, par->dc_regs + DC_UNLOCK);
7454 +
7455 +       writel(gx_saved_regs.dc.r.gcfg & ~0x0F,
7456 +              par->dc_regs + DC_GENERAL_CFG);
7457 +
7458 +       writel(gx_saved_regs.dc.r.dcfg & ~0x19,
7459 +              par->dc_regs + DC_DISPLAY_CFG);
7460 +       
7461 +       par->state = FB_POWER_STATE_SUSPEND;
7462 +
7463 +       return 0;
7464 +}
7465 +
7466 +int gxfb_powerup(struct fb_info *info)
7467 +{
7468 +       struct geodefb_par *par = info->par;
7469 +       u32 val;
7470 +
7471 +       if (par->state == FB_POWER_STATE_SUSPEND) {
7472 +
7473 +               writel(gx_saved_regs.dc.r.dcfg,
7474 +                      par->dc_regs + DC_DISPLAY_CFG);
7475 +
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);
7478 +
7479 +               val = readl(par->vid_regs + GX_FP_PM);
7480 +
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);
7484 +                       mdelay(64);
7485 +               }
7486 +       }
7487 +
7488 +       /* If the panel is currently on its way up, then wait up to 100ms
7489 +          for it */
7490 +       
7491 +       if (readl(par->vid_regs + GX_FP_PM) & 0x08) {
7492 +               int i;
7493 +               
7494 +               for(i = 0; i < 10; i++) {
7495 +                       if (readl(par->vid_regs + GX_FP_PM) & 0x01)
7496 +                               break;
7497 +
7498 +                       mdelay(10);
7499 +               }
7500 +
7501 +               if (i == 10) 
7502 +                       printk(KERN_ERR "gxfb:  Panel power up timed out\n");
7503 +       }
7504 +
7505 +       if (par->state == FB_POWER_STATE_ON)
7506 +               return 0;
7507 +       
7508 +       switch(par->state) {
7509 +       case FB_POWER_STATE_OFF:
7510 +               gx_restore_regs(info, &gx_saved_regs);
7511 +               break;
7512 +
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);
7519 +               break;
7520 +       }
7521 +
7522 +       par->state = FB_POWER_STATE_ON;
7523 +       return 0;
7524 +}
7525 +
7526  static int gx_blank_display(struct fb_info *info, int blank_mode)
7527  {
7528         struct geodefb_par *par = info->par;
7529 @@ -315,6 +468,7 @@ static int gx_blank_display(struct fb_in
7530         default:
7531                 return -EINVAL;
7532         }
7533 +
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);
7540  
7541 -       /* Power on/off flat panel. */
7542 +       /* Power on/off flat panel */
7543  
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
7547         return 0;
7548  }
7549  
7550 +extern struct fb_info *gxfb_info;
7551 +
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
7555 +*/
7556 +
7557 +void gxfb_flatpanel_control(int state)
7558 +{
7559 +       struct geodefb_par *par = gxfb_info->par;
7560 +       u32 val, fp = readl(par->vid_regs + GX_FP_PM);
7561 +       val  = fp;
7562 +
7563 +       /* Turn on the panel if it isn't aleady */
7564 +
7565 +       if (state) {
7566 +               if (!(val & 0x01))
7567 +                       val |= GX_FP_PM_P;
7568 +       }
7569 +       else {
7570 +               if (!(val & 0x02))
7571 +                       val &= ~GX_FP_PM_P;
7572 +       }
7573 +
7574 +       if (val != fp)
7575 +               writel(val, par->vid_regs + GX_FP_PM);
7576 +}
7577 +
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,
7583  };
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
7588 @@ -11,6 +11,8 @@
7589  #ifndef __VIDEO_GX_H__
7590  #define __VIDEO_GX_H__
7591  
7592 +#include "geode_regs.h"
7593 +
7594  extern struct geode_vid_ops gx_vid_ops;
7595  
7596  /* GX Flatpanel control MSR */
7597 @@ -20,6 +22,8 @@ extern struct geode_vid_ops gx_vid_ops;
7598  
7599  /* Geode GX video processor registers */
7600  
7601 +#define GX_VCFG         0x0000
7602 +
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
7609  
7610 +/* Gamma correction RAM - address and data registers */
7611 +
7612 +#define GX_GAR 0x038
7613 +#define GX_GDR 0x040
7614 +
7615 +#define GXFB_GAMMA_DWORDS 256 /* number of dwords in the gamma ram */
7616 +#define GXFB_GAMMA_SIZE (GXFB_GAMMA_DWORDS * sizeof(unsigned int))
7617 +
7618  /* Geode GX flat panel display control registers */
7619  
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)
7624  
7625 +int gxfb_powerdown(struct fb_info *info);
7626 +int gxfb_powerup(struct fb_info *info);
7627 +
7628 +void gx_set_dclk_frequency(struct fb_info *info);
7629 +unsigned int gx_get_dclk(struct fb_info *info);
7630 +
7631 +void gx_save_regs(struct fb_info *info, struct geoderegs *regs);
7632 +void gx_restore_regs(struct fb_info *info, struct geoderegs *regs);
7633 +
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");
7642  
7643 +config FB_OLPC_DCON
7644 +       tristate "One Laptop Per Child Display CONtroller support"
7645 +       depends on OLPC
7646 +       select I2C
7647 +       ---help---
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'.
7651 +
7652  config FB_XILINX
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/
7666  
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)
7673       */
7674  
7675 +#define DEFAULT_MODEDB_INDEX   0
7676 +
7677  static const struct fb_videomode modedb[] = {
7678      {
7679         /* 640x400 @ 70 Hz, 31.5 kHz hsync */
7680 @@ -508,7 +510,8 @@ int fb_find_mode(struct fb_var_screeninf
7681      }
7682  
7683      if (!default_mode)
7684 -       default_mode = &db[0];
7685 +           default_mode = (db == modedb) ?
7686 +                   &modedb[DEFAULT_MODEDB_INDEX] : &db[0];
7687  
7688      if (!default_bpp)
7689         default_bpp = 8;
7690 Index: linux-2.6.24.7/drivers/video/olpc_dcon.c
7691 ===================================================================
7692 --- /dev/null
7693 +++ linux-2.6.24.7/drivers/video/olpc_dcon.c
7694 @@ -0,0 +1,946 @@
7695 +/*
7696 + * Mainly by David Woodhouse, somewhat modified by Jordan Crouse
7697 + *
7698 + * Copyright Â© 2006-2007  Red Hat, Inc.
7699 + * Copyright Â© 2006-2007  Advanced Micro Devices, Inc.
7700 + *
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.
7704 + */
7705 +
7706 +
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>
7727 +
7728 +#include "olpc_dcon.h"
7729 +
7730 +/* Module definitions */
7731 +
7732 +static int resumeline = 898;
7733 +module_param(resumeline, int, 0444);
7734 +
7735 +static int noinit;
7736 +module_param(noinit, int, 0444);
7737 +
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);
7741 +
7742 +/* I2C structures */
7743 +
7744 +static struct i2c_driver dcon_driver;
7745 +static struct i2c_client *dcon_client;
7746 +
7747 +/* Platform devices */
7748 +static struct platform_device *dcon_device;
7749 +
7750 +/* Backlight device */
7751 +static struct backlight_device *dcon_bl_dev;
7752 +
7753 +/* Base address of the GPIO registers */
7754 +static unsigned long gpio_base;
7755 +
7756 +static struct fb_info *fbinfo;
7757 +
7758 +/* Current source, initialized at probe time */
7759 +static int dcon_source;
7760 +
7761 +/* Desired source */
7762 +static int dcon_pending;
7763 +
7764 +/* Current output type */
7765 +static int dcon_output = DCON_OUTPUT_COLOR;
7766 +
7767 +/* Current sleep status (not yet implemented) */
7768 +static int dcon_sleep_val = DCON_ACTIVE;
7769 +
7770 +/* Shadow register for the DCON_REG_MODE register */
7771 +static unsigned short dcon_disp_mode;
7772 +
7773 +/* Variables used during switches */
7774 +static int dcon_switched;
7775 +
7776 +static DECLARE_WAIT_QUEUE_HEAD(dcon_wait_queue);
7777 +
7778 +static unsigned short normal_i2c[] = { 0x0D, I2C_CLIENT_END };
7779 +I2C_CLIENT_INSMOD;
7780 +
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)
7783 +
7784 +/* The current backlight value - this saves us some smbus traffic */
7785 +static int bl_val = -1;
7786 +
7787 +/* ===== API functions - these are called by a variety of users ==== */
7788 +
7789 +static int dcon_request_irq(void);
7790 +
7791 +static int dcon_hw_init(struct i2c_client *client, int is_init)
7792 +{
7793 +       uint16_t ver;
7794 +       int rc = 0;
7795 +
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);
7800 +               rc = -ENXIO;
7801 +               goto err;
7802 +       }
7803 +
7804 +       if (is_init) {
7805 +               printk(KERN_INFO "olpc-dcon:  Discovered DCON version %x\n",
7806 +                               ver & 0xFF);
7807 +               if ((rc = dcon_request_irq())) {
7808 +                       printk(KERN_ERR "olpc-dcon:  Unable to grab IRQ.\n");
7809 +                       goto err;
7810 +               }
7811 +       }
7812 +
7813 +       if (ver < 0xdc02 && !noinit) {
7814 +               /* Initialize the DCON registers */
7815 +
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);
7823 +               
7824 +               /* Initialise SDRAM */
7825 +
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);
7829 +       }
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);
7836 +       }
7837 +
7838 +       /* Colour swizzle, AA, no passthrough, backlight */
7839 +       if (is_init) {
7840 +               dcon_disp_mode = MODE_PASSTHRU | MODE_BL_ENABLE | MODE_CSWIZZLE;
7841 +               if (useaa)
7842 +                       dcon_disp_mode |= MODE_COL_AA;
7843 +       }
7844 +       i2c_smbus_write_word_data(client, DCON_REG_MODE, dcon_disp_mode);
7845 +
7846 +
7847 +       /* Set the scanline to interrupt on during resume */
7848 +
7849 +       i2c_smbus_write_word_data(client, DCON_REG_SCAN_INT, resumeline);
7850 +
7851 +err:
7852 +       return rc;
7853 +}
7854 +
7855 +/*
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!
7863 + */
7864 +static int dcon_bus_stabilize(struct i2c_client *client, int is_powered_down)
7865 +{
7866 +       unsigned long timeout;
7867 +       int x;
7868 +
7869 +power_up:
7870 +       if (is_powered_down) {
7871 +               x = 1;
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);
7875 +                       return x;
7876 +               }
7877 +               msleep(10); /* we'll be conservative */
7878 +       }
7879 +       
7880 +       /*
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.
7886 +        *
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
7889 +        * GPIO15.
7890 +        */
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);
7896 +
7897 +       for (x = 0; x < 16; x++) {
7898 +               udelay(5);
7899 +               geode_gpio_clear(OLPC_GPIO_SMB_CLK, GPIO_OUTPUT_VAL);
7900 +               udelay(5);
7901 +               geode_gpio_set(OLPC_GPIO_SMB_CLK, GPIO_OUTPUT_VAL);
7902 +       }
7903 +       udelay(5);
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);
7906 +
7907 +       for (x = -1, timeout = 50; timeout && x < 0; timeout--) {
7908 +               msleep(1);
7909 +               x = dcon_read(DCON_REG_ID);
7910 +       }
7911 +       if (x < 0) {
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)));
7915 +               x = 0;
7916 +               olpc_ec_cmd(0x26, (unsigned char *) &x, 1, NULL, 0);
7917 +               msleep(100);
7918 +               is_powered_down = 1;
7919 +               goto power_up;  /* argh, stupid hardware.. */
7920 +       }
7921 +
7922 +       if (is_powered_down)
7923 +               return dcon_hw_init(client, 0);
7924 +       return 0;
7925 +}
7926 +
7927 +
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.
7931 + */
7932 +
7933 +static int dcon_get_backlight(void)
7934 +{
7935 +       if (dcon_client == NULL)
7936 +               return 0;
7937 +
7938 +       if (bl_val == -1)
7939 +               bl_val = dcon_read(DCON_REG_BRIGHT) & 0x0F;
7940 +
7941 +       return bl_val;
7942 +}
7943 +
7944 +static void dcon_set_backlight(int level)
7945 +{
7946 +       if (dcon_client == NULL)
7947 +               return;
7948 +
7949 +       if (bl_val == (level & 0x0F))
7950 +               return;
7951 +
7952 +       bl_val = level & 0x0F;
7953 +       dcon_write(DCON_REG_BRIGHT, bl_val);
7954 +
7955 +       /* Purposely turn off the backlight when we go to level 0 */
7956 +
7957 +       if (bl_val == 0) {
7958 +         dcon_disp_mode &= ~MODE_BL_ENABLE;
7959 +         dcon_write(DCON_REG_MODE, dcon_disp_mode);
7960 +       }
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);
7964 +       }
7965 +}
7966 +
7967 +/* Set the output type to either color or mono */
7968 +
7969 +static int dcon_set_output(int arg)
7970 +{
7971 +       if (dcon_output == arg)
7972 +               return 0;
7973 +
7974 +       dcon_output = arg;
7975 +
7976 +       if (arg == DCON_OUTPUT_MONO) {
7977 +               dcon_disp_mode &= ~(MODE_CSWIZZLE | MODE_COL_AA);
7978 +               dcon_disp_mode |= MODE_MONO_LUMA;
7979 +       }
7980 +       else {
7981 +               dcon_disp_mode &= ~(MODE_MONO_LUMA);
7982 +               dcon_disp_mode |= MODE_CSWIZZLE;
7983 +               if (useaa)
7984 +                       dcon_disp_mode |= MODE_COL_AA;
7985 +       }
7986 +
7987 +       dcon_write(DCON_REG_MODE, dcon_disp_mode);
7988 +       return 0;
7989 +}
7990 +
7991 +/* For now, this will be really stupid - we need to address how
7992 + * DCONLOAD works in a sleep and account for it accordingly
7993 + */
7994 +
7995 +static void dcon_sleep(int state)
7996 +{
7997 +       int x;
7998 +
7999 +       /* Turn off the backlight and put the DCON to sleep */
8000 +
8001 +       if (state == dcon_sleep_val)
8002 +               return;
8003 +
8004 +       if (!olpc_board_at_least(olpc_board(0xc2)))
8005 +               return;
8006 +
8007 +       if (state == DCON_SLEEP) {
8008 +               x = 0;
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);
8012 +               else
8013 +                       dcon_sleep_val = state;
8014 +       }
8015 +       else {
8016 +               /* Only re-enable the backlight if the backlight value is set */
8017 +               if (bl_val != 0)
8018 +                       dcon_disp_mode |= MODE_BL_ENABLE;
8019 +
8020 +               if ((x=dcon_bus_stabilize(dcon_client, 1)))
8021 +                       printk(KERN_WARNING "olpc-dcon:  unable to reinit dcon"
8022 +                                       " hardware: %d!\n", x);
8023 +               else
8024 +                       dcon_sleep_val = state;
8025 +       }
8026 +
8027 +       /* We should turn off some stuff in the framebuffer - but what? */
8028 +}
8029 +
8030 +/* Set the source of the display (CPU or DCON) */
8031 +
8032 +static void dcon_source_switch(struct work_struct *work)
8033 +{
8034 +       DECLARE_WAITQUEUE(wait, current);
8035 +       int source = dcon_pending;
8036 +
8037 +       if (dcon_source == source)
8038 +               return;
8039 +
8040 +       dcon_switched = 0;
8041 +
8042 +       switch (source) {
8043 +       case DCON_SOURCE_CPU:
8044 +
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");
8048 +               else {
8049 +                       /* Wait up to one second for the scanline interrupt */
8050 +                       wait_event_timeout(dcon_wait_queue, dcon_switched == 1, HZ);
8051 +               }
8052 +
8053 +               if (!dcon_switched)
8054 +                       printk(KERN_ERR "olpc-dcon:  Timeout entering CPU mode; expect a screen glitch.\n");
8055 +
8056 +               /*
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.
8061 +                *
8062 +                * For now, we just hope..
8063 +                */
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;
8069 +                       return;
8070 +               }
8071 +               release_console_sem();
8072 +
8073 +               /* And turn off the DCON */
8074 +               outl(1<<11, gpio_base + GPIOx_OUT_VAL);
8075 +
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");
8079 +
8080 +               printk(KERN_INFO "olpc-dcon: The CPU has control\n");
8081 +               break;
8082 +       case DCON_SOURCE_DCON:
8083 +       {
8084 +               int t;
8085 +
8086 +               add_wait_queue(&dcon_wait_queue, &wait);
8087 +               set_current_state(TASK_UNINTERRUPTIBLE);
8088 +
8089 +               /* Clear GPIO11 (DCONLOAD) - this implies that the DCON is in
8090 +                  control */
8091 +
8092 +               outl(1 << (11 + 16), gpio_base + GPIOx_OUT_VAL);
8093 +
8094 +               t = schedule_timeout(HZ/2);
8095 +               remove_wait_queue(&dcon_wait_queue, &wait);
8096 +               set_current_state(TASK_RUNNING);
8097 +
8098 +               if (!dcon_switched)
8099 +                       printk(KERN_ERR "olpc-dcon: Timeout entering DCON mode; expect a screen glitch.\n");
8100 +
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();
8105 +
8106 +               printk(KERN_INFO "olpc-dcon: The DCON has control\n");
8107 +               break;
8108 +       }
8109 +       default:
8110 +               BUG();
8111 +       }
8112 +
8113 +       dcon_source = source;
8114 +}
8115 +
8116 +static DECLARE_WORK(dcon_work, dcon_source_switch);
8117 +
8118 +static int dcon_set_source(int arg)
8119 +{
8120 +       if (arg != DCON_SOURCE_CPU && arg != DCON_SOURCE_DCON)
8121 +               return -EINVAL;
8122 +
8123 +       if (dcon_pending == arg)
8124 +               return 0;
8125 +
8126 +       dcon_pending = arg;
8127 +       if ((dcon_source != arg) && !work_pending(&dcon_work))
8128 +               schedule_work(&dcon_work);
8129 +
8130 +       return 0;
8131 +}
8132 +
8133 +static int dcon_set_source_sync(int arg)
8134 +{
8135 +       int ret = dcon_set_source(arg);
8136 +       if (!ret)
8137 +               flush_scheduled_work();
8138 +       return ret;
8139 +}
8140 +
8141 +static int dconbl_set(struct backlight_device *dev) {
8142 +
8143 +       int level = dev->props.brightness;
8144 +
8145 +       if (dev->props.power != FB_BLANK_UNBLANK)
8146 +               level = 0;
8147 +
8148 +       dcon_set_backlight(level);
8149 +       return 0;
8150 +}
8151 +
8152 +static int dconbl_get(struct backlight_device *dev) {
8153 +       return dcon_get_backlight();
8154 +}
8155 +
8156 +static ssize_t dcon_mode_show(struct device *dev,
8157 +       struct device_attribute *attr, char *buf)
8158 +{
8159 +       return sprintf(buf, "%4.4X\n", dcon_disp_mode);
8160 +}
8161 +
8162 +static ssize_t dcon_sleep_show(struct device *dev,
8163 +       struct device_attribute *attr, char *buf)
8164 +{
8165 +       return sprintf(buf, "%d\n", dcon_sleep_val);
8166 +}
8167 +
8168 +static ssize_t /* __deprecated */ dcon_source_show(struct device *dev,
8169 +       struct device_attribute *attr, char *buf)
8170 +{
8171 +       printk(KERN_WARNING "olpc-dcon:  using deprecated sysfs 'source' interface; use 'freeze' instead!\n");
8172 +       return sprintf(buf, "%d\n", dcon_source);
8173 +}
8174 +
8175 +static ssize_t dcon_freeze_show(struct device *dev,
8176 +       struct device_attribute *attr, char *buf)
8177 +{
8178 +       return sprintf(buf, "%d\n", dcon_source == DCON_SOURCE_DCON ? 1 : 0);
8179 +}
8180 +
8181 +static ssize_t dcon_output_show(struct device *dev,
8182 +       struct device_attribute *attr, char *buf)
8183 +{
8184 +       return sprintf(buf, "%d\n", dcon_output);
8185 +}
8186 +
8187 +static ssize_t dcon_resumeline_show(struct device *dev,
8188 +       struct device_attribute *attr, char *buf)
8189 +{
8190 +       return sprintf(buf, "%d\n", resumeline);
8191 +}
8192 +
8193 +static int _strtoul(const char *buf, int len, unsigned int *val)
8194 +{
8195 +
8196 +       char *endp;
8197 +       unsigned int output = simple_strtoul(buf, &endp, 0);
8198 +       int size = endp - buf;
8199 +
8200 +       if (*endp && isspace(*endp))
8201 +               size++;
8202 +
8203 +       if (size != len)
8204 +               return -EINVAL;
8205 +
8206 +       *val = output;
8207 +       return 0;
8208 +}
8209 +
8210 +static ssize_t dcon_output_store(struct device *dev,
8211 +       struct device_attribute *attr, const char *buf, size_t count)
8212 +{
8213 +       int output;
8214 +       int rc = -EINVAL;
8215 +
8216 +       if (_strtoul(buf, count, &output))
8217 +               return -EINVAL;
8218 +
8219 +       if (output == DCON_OUTPUT_COLOR || output == DCON_OUTPUT_MONO) {
8220 +               dcon_set_output(output);
8221 +               rc = count;
8222 +       }
8223 +
8224 +       return rc;
8225 +}
8226 +
8227 +static ssize_t /* __deprecated */ dcon_source_store(struct device *dev,
8228 +       struct device_attribute *attr, const char *buf, size_t count)
8229 +{
8230 +       int output;
8231 +       int rc = -EINVAL;
8232 +
8233 +       printk(KERN_WARNING "olpc-dcon:  using deprecated sysfs 'source' interface; use 'freeze' instead!\n");
8234 +       if (_strtoul(buf, count, &output))
8235 +               return -EINVAL;
8236 +
8237 +       dcon_set_source(output);
8238 +       rc = count;
8239 +
8240 +       return rc;
8241 +}
8242 +
8243 +static ssize_t dcon_freeze_store(struct device *dev,
8244 +       struct device_attribute *attr, const char *buf, size_t count)
8245 +{
8246 +       int output;
8247 +       int rc = -EINVAL;
8248 +
8249 +       if (_strtoul(buf, count, &output))
8250 +               return rc;
8251 +
8252 +       dcon_set_source(output ? DCON_SOURCE_DCON : DCON_SOURCE_CPU);
8253 +       rc = count;
8254 +
8255 +       return rc;
8256 +}
8257 +
8258 +static ssize_t dcon_resumeline_store(struct device *dev,
8259 +       struct device_attribute *attr, const char *buf, size_t count)
8260 +{
8261 +       int rl;
8262 +       int rc = -EINVAL;
8263 +
8264 +       if (_strtoul(buf, count, &rl))
8265 +               return rc;
8266 +
8267 +       resumeline = rl;
8268 +       dcon_write(DCON_REG_SCAN_INT, resumeline);
8269 +       rc = count;
8270 +
8271 +       return rc;
8272 +}
8273 +
8274 +static ssize_t dcon_sleep_store(struct device *dev,
8275 +       struct device_attribute *attr, const char *buf, size_t count)
8276 +{
8277 +       int output;
8278 +
8279 +       if (_strtoul(buf, count, &output))
8280 +               return -EINVAL;
8281 +
8282 +       dcon_sleep(output ? DCON_SLEEP : DCON_ACTIVE);
8283 +       return count;
8284 +}
8285 +
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),
8293 +};
8294 +
8295 +static struct backlight_ops dcon_bl_ops = {
8296 +       .get_brightness = dconbl_get,
8297 +       .update_status = dconbl_set
8298 +};
8299 +
8300 +/* List of GPIOs that we care about:
8301 +   (in)  GPIO12   -- DCONBLNK
8302 +   (in)  GPIO[56] -- DCONSTAT[01]
8303 +   (out) GPIO11   -- DCONLOAD
8304 +*/
8305 +
8306 +#define IN_GPIOS ((1<<5) | (1<<6) | (1<<7) | (1<<12))
8307 +#define OUT_GPIOS (1<<11)
8308 +
8309 +static irqreturn_t dcon_interrupt(int, void *);
8310 +
8311 +static int dcon_request_irq(void)
8312 +{
8313 +       unsigned long lo, hi;
8314 +       unsigned char lob;
8315 +
8316 +       rdmsr(MSR_LBAR_GPIO, lo, hi);
8317 +
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");
8321 +               return -ENODEV;
8322 +       }
8323 +
8324 +       /* Mask off the IO base address */
8325 +       gpio_base = lo & 0x0000ff00;
8326 +
8327 +       /* Turn off the event enable for GPIO7 just to be safe */
8328 +       outl(1 << (16+7), gpio_base + GPIOx_EVNT_EN);
8329 +
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);
8333 +
8334 +       /* Set up the interrupt mappings */
8335 +
8336 +       /* Set the IRQ to pair 2 */
8337 +       geode_gpio_event_irq(OLPC_GPIO_DCON_IRQ, 2);
8338 +
8339 +       /* Enable group 2 to trigger the DCON interrupt */
8340 +       geode_gpio_set_irq(2, DCON_IRQ);
8341 +
8342 +       /* Select edge level for interrupt (in PIC) */
8343 +
8344 +       lob = inb(0x4d0);
8345 +       lob &= ~(1 << DCON_IRQ);
8346 +       outb(lob, 0x4d0);
8347 +
8348 +       /* Register the interupt handler */
8349 +       if (request_irq(DCON_IRQ, &dcon_interrupt, 0, "DCON", &dcon_driver))
8350 +               return -EIO;
8351 +
8352 +       /* Clear INV_EN for GPIO7 (DCONIRQ) */
8353 +       outl((1<<(16+7)), gpio_base + GPIOx_INV_EN);
8354 +
8355 +       /* Enable filter for GPIO12 (DCONBLANK) */
8356 +       outl(1<<(12), gpio_base + GPIOx_IN_FLTR_EN);
8357 +
8358 +       /* Disable filter for GPIO7 */
8359 +       outl(1<<(16+7), gpio_base + GPIOx_IN_FLTR_EN);
8360 +
8361 +       /* Disable event counter for GPIO7 (DCONIRQ) and GPIO12 (DCONBLANK) */
8362 +
8363 +       outl(1<<(16+7), gpio_base + GPIOx_EVNTCNT_EN);
8364 +       outl(1<<(16+12), gpio_base + GPIOx_EVNTCNT_EN);
8365 +
8366 +       /* Add GPIO12 to the Filter Event Pair #7 */
8367 +       outb(12, gpio_base + GPIO_FE7_SEL);
8368 +
8369 +       /* Turn off negative Edge Enable for GPIO12 */
8370 +       outl(1<<(16+12), gpio_base + GPIOx_NEGEDGE_EN);
8371 +
8372 +       /* Enable negative Edge Enable for GPIO7 */
8373 +       outl(1<<7, gpio_base + GPIOx_NEGEDGE_EN);
8374 +
8375 +       /* Zero the filter amount for Filter Event Pair #7 */
8376 +       outw(0, gpio_base + GPIO_FLT7_AMNT);
8377 +
8378 +       /* Clear the negative edge status for GPIO7 and GPIO12 */
8379 +       outl((1<<7) | (1<<12), gpio_base+0x4c);
8380 +
8381 +       /* FIXME:  Clear the posiitive status as well, just to be sure */
8382 +       outl((1<<7) | (1<<12), gpio_base+0x48);
8383 +
8384 +       /* Enable events for GPIO7 (DCONIRQ) and GPIO12 (DCONBLANK) */
8385 +       outl((1<<(7))|(1<<12), gpio_base + GPIOx_EVNT_EN);
8386 +
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)
8390 +               ? DCON_SOURCE_CPU
8391 +               : DCON_SOURCE_DCON;
8392 +       dcon_pending = dcon_source;
8393 +
8394 +       return 0;
8395 +}
8396 +
8397 +static int dcon_reboot_notify(struct notifier_block *nb, unsigned long foo, void *bar)
8398 +{
8399 +       if (dcon_client == NULL)
8400 +               return 0;
8401 +
8402 +       /* Turn off the DCON. Entirely. */
8403 +       dcon_write(DCON_REG_MODE, 0x39);
8404 +       dcon_write(DCON_REG_MODE, 0x32);
8405 +       return 0;
8406 +}
8407 +
8408 +static int dcon_conswitch_notify(struct notifier_block *nb,
8409 +                                unsigned long mode, void *dummy)
8410 +{
8411 +       if (mode == CONSOLE_EVENT_SWITCH_TEXT)
8412 +               dcon_sleep(DCON_ACTIVE);
8413 +
8414 +       return 0;
8415 +}
8416 +
8417 +static struct notifier_block dcon_nb = {
8418 +       .notifier_call = dcon_reboot_notify,
8419 +       .priority = -1,
8420 +};
8421 +
8422 +static struct notifier_block dcon_console_nb = {
8423 +       .notifier_call = dcon_conswitch_notify,
8424 +       .priority = -1,
8425 +};
8426 +
8427 +static int unfreeze_on_panic(struct notifier_block *nb, unsigned long e, void *p)
8428 +{
8429 +       outl(1<<11, gpio_base + GPIOx_OUT_VAL);
8430 +       return NOTIFY_DONE;
8431 +}
8432 +
8433 +static struct notifier_block dcon_panic_nb = {
8434 +       .notifier_call = unfreeze_on_panic,
8435 +};
8436 +
8437 +static int dcon_probe(struct i2c_adapter *adap, int addr, int kind)
8438 +{
8439 +       struct i2c_client *client;
8440 +       int rc, i;
8441 +
8442 +       if (!olpc_has_dcon()) {
8443 +               printk("olpc-dcon:  No DCON is attached.\n");
8444 +               return -ENODEV;
8445 +       }
8446 +
8447 +       if (num_registered_fb >= 1)
8448 +               fbinfo = registered_fb[0];
8449 +
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);
8453 +               return -ENXIO;
8454 +       }
8455 +
8456 +       client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
8457 +       if (client == NULL)
8458 +               return -ENOMEM;
8459 +
8460 +       strncpy(client->name, "OLPC-DCON", I2C_NAME_SIZE);
8461 +       client->addr = addr;
8462 +       client->adapter = adap;
8463 +       client->driver = &dcon_driver;
8464 +
8465 +       if ((rc = i2c_attach_client(client)) != 0) {
8466 +               printk(KERN_ERR "olpc-dcon: Unable to attach the I2C client.\n");
8467 +               goto eclient;
8468 +       }
8469 +
8470 +       rc = dcon_hw_init(client, 1);
8471 +       if (rc)
8472 +               goto ei2c;
8473 +
8474 +       /* Add the DCON device */
8475 +
8476 +       dcon_device = platform_device_alloc("dcon", -1);
8477 +
8478 +       if (dcon_device == NULL) {
8479 +               printk(KERN_ERR "dcon:  Unable to create the DCON device\n");
8480 +               rc = -ENOMEM;
8481 +               goto eirq;
8482 +       }
8483 +
8484 +       if ((rc = platform_device_add(dcon_device))) {
8485 +               printk(KERN_ERR "dcon:  Unable to add the DCON device\n");
8486 +               goto edev;
8487 +       }
8488 +
8489 +       for(i = 0; i < ARRAY_SIZE(dcon_device_files); i++)
8490 +               device_create_file(&dcon_device->dev, &dcon_device_files[i]);
8491 +
8492 +       /* Add the backlight device for the DCON */
8493 +
8494 +       dcon_client = client;
8495 +
8496 +       dcon_bl_dev = backlight_device_register("dcon-bl", &dcon_device->dev,
8497 +               NULL, &dcon_bl_ops);
8498 +
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;
8502 +       }
8503 +       else {
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();
8507 +
8508 +               backlight_update_status(dcon_bl_dev);
8509 +       }
8510 +
8511 +       register_reboot_notifier(&dcon_nb);
8512 +       console_event_register(&dcon_console_nb);
8513 +       atomic_notifier_chain_register(&panic_notifier_list, &dcon_panic_nb);
8514 +
8515 +       return 0;
8516 +
8517 + edev:
8518 +       platform_device_unregister(dcon_device);
8519 +       dcon_device = NULL;
8520 + eirq:
8521 +       free_irq(DCON_IRQ, &dcon_driver);
8522 + ei2c:
8523 +       i2c_detach_client(client);
8524 + eclient:
8525 +       kfree(client);
8526 +
8527 +       return rc;
8528 +}
8529 +
8530 +static int dcon_attach(struct i2c_adapter *adap)
8531 +{
8532 +       int ret;
8533 +
8534 +       ret = i2c_probe(adap, &addr_data, dcon_probe);
8535 +
8536 +       if (dcon_client == NULL)
8537 +               printk(KERN_ERR "olpc-dcon: No DCON found on SMBus\n");
8538 +
8539 +       return ret;
8540 +}
8541 +
8542 +static int dcon_detach(struct i2c_client *client)
8543 +{
8544 +       int rc;
8545 +       dcon_client = NULL;
8546 +
8547 +       unregister_reboot_notifier(&dcon_nb);
8548 +       console_event_unregister(&dcon_console_nb);
8549 +       atomic_notifier_chain_unregister(&panic_notifier_list, &dcon_panic_nb);
8550 +
8551 +       free_irq(DCON_IRQ, &dcon_driver);
8552 +
8553 +       if ((rc = i2c_detach_client(client)) == 0)
8554 +               kfree(i2c_get_clientdata(client));
8555 +
8556 +       if (dcon_bl_dev != NULL)
8557 +               backlight_device_unregister(dcon_bl_dev);
8558 +
8559 +       if (dcon_device != NULL)
8560 +               platform_device_unregister(dcon_device);
8561 +       cancel_work_sync(&dcon_work);
8562 +
8563 +       return rc;
8564 +}
8565 +
8566 +
8567 +#ifdef CONFIG_PM
8568 +static int dcon_suspend(struct i2c_client *client, pm_message_t state)
8569 +{
8570 +       if (dcon_sleep_val != DCON_ACTIVE)
8571 +               return 0;
8572 +
8573 +       /* Set up the DCON to have the source */
8574 +       return dcon_set_source_sync(DCON_SOURCE_DCON);
8575 +}
8576 +
8577 +static int dcon_resume(struct i2c_client *client)
8578 +{
8579 +       if (dcon_sleep_val != DCON_ACTIVE)
8580 +               return 0;
8581 +
8582 +       dcon_bus_stabilize(client, 0);
8583 +
8584 +       return dcon_set_source(DCON_SOURCE_CPU);
8585 +}
8586 +
8587 +#endif
8588 +
8589 +static irqreturn_t dcon_interrupt(int irq, void *id)
8590 +{
8591 +       int status = inl(gpio_base + GPIOx_READ_BACK) >> 5;
8592 +
8593 +       /* Clear the negative edge status for GPIO7 */
8594 +       outl(1 << 7, gpio_base + GPIOx_NEGEDGE_STS);
8595 +
8596 +       switch (status & 3) {
8597 +       case 3:
8598 +               printk(KERN_DEBUG "olpc-dcon: DCONLOAD_MISSED interrupt\n");
8599 +               break;
8600 +       case 2: /* switch to DCON mode */
8601 +       case 1: /* switch to CPU mode */
8602 +               dcon_switched = 1;
8603 +               wake_up(&dcon_wait_queue);
8604 +               break;
8605 +       case 0:
8606 +               printk(KERN_DEBUG "olpc-dcon: scanline interrupt w/CPU\n");
8607 +       }
8608 +
8609 +       return IRQ_HANDLED;
8610 +}
8611 +
8612 +static struct i2c_driver dcon_driver = {
8613 +       .driver = {
8614 +               .name   = "OLPC-DCON",
8615 +       },
8616 +       .id = I2C_DRIVERID_DCON,
8617 +       .attach_adapter = dcon_attach,
8618 +       .detach_client = dcon_detach,
8619 +#ifdef CONFIG_PM
8620 +       .suspend = dcon_suspend,
8621 +       .resume = dcon_resume,
8622 +#endif
8623 +};
8624 +
8625 +
8626 +static int __init olpc_dcon_init(void)
8627 +{
8628 +       i2c_add_driver(&dcon_driver);
8629 +       return 0;
8630 +}
8631 +
8632 +static void __exit olpc_dcon_exit(void)
8633 +{
8634 +       i2c_del_driver(&dcon_driver);
8635 +}
8636 +
8637 +module_init(olpc_dcon_init);
8638 +module_exit(olpc_dcon_exit);
8639 +
8640 +MODULE_LICENSE("GPL");
8641 Index: linux-2.6.24.7/drivers/video/olpc_dcon.h
8642 ===================================================================
8643 --- /dev/null
8644 +++ linux-2.6.24.7/drivers/video/olpc_dcon.h
8645 @@ -0,0 +1,75 @@
8646 +#ifndef OLPC_DCON_H_
8647 +#define OLPC_DCON_H_
8648 +
8649 +/* DCON registers */
8650 +
8651 +#define DCON_REG_ID             0
8652 +#define DCON_REG_MODE           1
8653 +
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)
8666 +
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
8676 +
8677 +/* GPIO registers (CS5536) */
8678 +
8679 +#define MSR_LBAR_GPIO          0x5140000C
8680 +
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
8695 +
8696 +
8697 +/* Status values */
8698 +
8699 +#define DCONSTAT_SCANINT       0
8700 +#define DCONSTAT_SCANINT_DCON  1
8701 +#define DCONSTAT_DISPLAYLOAD   2
8702 +#define DCONSTAT_MISSED                3
8703 +
8704 +/* Source values */
8705 +
8706 +#define DCON_SOURCE_DCON        0
8707 +#define DCON_SOURCE_CPU         1
8708 +
8709 +/* Output values */
8710 +#define DCON_OUTPUT_COLOR       0
8711 +#define DCON_OUTPUT_MONO        1
8712 +
8713 +/* Sleep values */
8714 +#define DCON_ACTIVE             0
8715 +#define DCON_SLEEP              1
8716 +
8717 +/* Interrupt */
8718 +#define DCON_IRQ                6
8719 +
8720 +#endif
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
8728  
8729 -#define INOCACHE_HASHSIZE 128
8730 +#define INOCACHE_HASHSIZE 1024
8731  
8732  #define write_ofs(c) ((c)->nextblock->offset + (c)->sector_size - (c)->nextblock->free_size)
8733  
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
8739  config HUGETLB_PAGE
8740         def_bool HUGETLBFS
8741  
8742 +config PROMFS_FS
8743 +       tristate "PromFS IEEE 1275 file system support"
8744 +       depends on SPARC || PPC || OLPC
8745 +       help
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.
8751 +
8752 +         The firmware device-tree is available as a virtual file system,
8753 +         can be mounted under /prom with the command "mount -t promfs
8754 +         none /prom".
8755 +
8756 +         To compile PromFS support as a module, choose M here; the module
8757 +         will be called promfs.  If unsure, choose M.
8758 +
8759 +config RAMFS
8760 +       bool
8761 +       default y
8762 +       ---help---
8763 +         Ramfs is a file system which keeps all files in RAM. It allows
8764 +         read and write access.
8765 +
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
8768 +         tmpfs.
8769 +
8770 +         To compile this as a module, choose M here: the module will be called
8771 +         ramfs.
8772 +
8773  config CONFIGFS_FS
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 ===================================================================
8790 --- /dev/null
8791 +++ linux-2.6.24.7/fs/promfs/Makefile
8792 @@ -0,0 +1 @@
8793 +obj-$(CONFIG_PROMFS_FS) += promfs.o
8794 Index: linux-2.6.24.7/fs/promfs/promfs.c
8795 ===================================================================
8796 --- /dev/null
8797 +++ linux-2.6.24.7/fs/promfs/promfs.c
8798 @@ -0,0 +1,295 @@
8799 +/*
8800 + * promfs.c - generic inode/dentry functions for IEEE 1275-based filesystems.
8801 + *
8802 + * This is based heavily upon prior ieee1275 and other virtual filesystems
8803 + * implementations; openpromfs, proc_devtree.c, oprofilefs, procfs, ...
8804 + * 
8805 + * Copyright (C) 2007 Andres Salomon <dilinger@debian.org>
8806 + *
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.
8811 + *
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.
8816 + *
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.
8820 + */
8821 +
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>
8828 +
8829 +#define PROMFS_MAGIC 0x1f2f3fff
8830 +
8831 +MODULE_LICENSE("GPL");
8832 +MODULE_AUTHOR("Andres Salomon");
8833 +
8834 +struct promfs_inode
8835 +{
8836 +       struct inode ino;
8837 +       struct property *prop;
8838 +};
8839 +
8840 +static inline struct promfs_inode *to_promfs_inode(struct inode *inode)
8841 +{
8842 +       return container_of(inode, struct promfs_inode, ino);
8843 +}
8844 +
8845 +#if 0
8846 +static DEFINE_SPINLOCK(promfs_lock);
8847 +
8848 +static struct of_node *of_tree = NULL;
8849 +static DEFINE_RWLOCK(of_tree_lock);
8850 +
8851 +void __init of_build_tree(void)
8852 +{
8853 +
8854 +
8855 +}
8856 +#endif
8857 +
8858 +static int promfs_open_file(struct inode *inode, struct file *file)
8859 +{
8860 +       struct promfs_inode *ino;
8861 +
8862 +       ino = to_promfs_inode(inode);
8863 +       if (!ino->prop)
8864 +               return -EIO;
8865 +       file->private_data = ino->prop;
8866 +
8867 +       return 0;
8868 +}
8869 +
8870 +static ssize_t promfs_read_file(struct file *file, char __user *data,
8871 +               size_t len, loff_t *ppos)
8872 +{
8873 +       struct property *prop = (struct property *) file->private_data;
8874 +       return simple_read_from_buffer(data, len, ppos, prop->value,
8875 +                       prop->length);
8876 +}
8877 +
8878 +static ssize_t promfs_write_file(struct file *file, char const __user *buf,
8879 +               size_t count, loff_t * offset)
8880 +{
8881 +       /* TODO.... 'cause, y'know, it would be nice. */
8882 +       return -EIO;
8883 +}
8884 +
8885 +static struct file_operations promfs_file_ops = {
8886 +       .open = promfs_open_file,
8887 +       .read = promfs_read_file,
8888 +       .write = promfs_write_file,
8889 +};
8890 +
8891 +static struct kmem_cache *promfs_inode_cachep;
8892 +
8893 +static struct inode *promfs_alloc_inode(struct super_block *sb)
8894 +{
8895 +       struct promfs_inode *pr_ino;
8896 +
8897 +       pr_ino = kmem_cache_alloc(promfs_inode_cachep, GFP_KERNEL);
8898 +       if (!pr_ino)
8899 +               return NULL;
8900 +       pr_ino->prop = NULL;
8901 +
8902 +       return &pr_ino->ino;
8903 +}
8904 +
8905 +static void promfs_destroy_inode(struct inode *inode)
8906 +{
8907 +       kmem_cache_free(promfs_inode_cachep, to_promfs_inode(inode));
8908 +}
8909 +
8910 +static void promfs_read_inode(struct inode *inode)
8911 +{
8912 +       inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
8913 +}
8914 +
8915 +static int promfs_remount(struct super_block *sb, int *flags, char *data)
8916 +{
8917 +       *flags |= MS_NOATIME;
8918 +       return 0;
8919 +}
8920 +
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,
8928 +};
8929 +
8930 +static struct inode *promfs_get_inode(struct super_block *sb, int mode)
8931 +{
8932 +       struct inode *inode = new_inode(sb);
8933 +
8934 +       if (inode) {
8935 +               inode->i_mode = mode;
8936 +               inode->i_uid = 0;
8937 +               inode->i_gid = 0;
8938 +               inode->i_blocks = 0;
8939 +               inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
8940 +       }
8941 +
8942 +       return inode;
8943 +}
8944 +
8945 +static int promfs_create_file(struct super_block *sb, struct dentry *root,
8946 +               struct property *prop, const struct file_operations *fops)
8947 +{
8948 +       struct dentry *dentry;
8949 +       struct inode *inode;
8950 +       struct promfs_inode *ino;
8951 +
8952 +       dentry = d_alloc_name(root, prop->name);
8953 +       if (!dentry)
8954 +               goto err;
8955 +
8956 +       inode = promfs_get_inode(sb, S_IFREG | 0644);
8957 +       if (!inode)
8958 +               goto err_dput;
8959 +       inode->i_fop = fops;
8960 +       ino = to_promfs_inode(inode);
8961 +       ino->prop = prop;
8962 +       d_add(dentry, inode);
8963 +
8964 +       return 0;
8965 +
8966 +err_dput:
8967 +       dput(dentry);
8968 +err:
8969 +       return -EFAULT;
8970 +}
8971 +
8972 +struct dentry *promfs_create_dir(struct super_block *sb, struct dentry *root,
8973 +               char const *name)
8974 +{
8975 +       struct dentry *dentry;
8976 +       struct inode *inode;
8977 +
8978 +       dentry = d_alloc_name(root, name);
8979 +       if (!dentry)
8980 +               goto err;
8981 +
8982 +       inode = promfs_get_inode(sb, S_IFDIR | 0755);
8983 +       if (!inode)
8984 +               goto err_dput;
8985 +       inode->i_op = &simple_dir_inode_operations;
8986 +       inode->i_fop = &simple_dir_operations;
8987 +       d_add(dentry, inode);
8988 +       return dentry;
8989 +
8990 +err_dput:
8991 +       dput(dentry);
8992 +err:
8993 +       return NULL;
8994 +}
8995 +
8996 +void promfs_populate(struct super_block *sb, struct dentry *root,
8997 +               struct device_node *node)
8998 +{
8999 +       struct dentry *dentry;
9000 +       struct device_node *child;
9001 +       struct property *prop;
9002 +
9003 +       if (!node)
9004 +               return;
9005 +
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);
9009 +       }
9010 +       for (prop = node->properties; prop; prop = prop->next)
9011 +               promfs_create_file(sb, root, prop, &promfs_file_ops);
9012 +}
9013 +
9014 +static int promfs_fill_super(struct super_block *sb, void *data, int silent)
9015 +{
9016 +       struct inode *root_inode;
9017 +       struct dentry *root_dentry;
9018 +       struct promfs_inode *inode;
9019 +
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;
9026 +
9027 +       root_inode = promfs_get_inode(sb, S_IFDIR | 0755);
9028 +       if (!root_inode)
9029 +               goto err;
9030 +       root_inode->i_op = &simple_dir_inode_operations;
9031 +       root_inode->i_fop = &simple_dir_operations;
9032 +
9033 +       inode = to_promfs_inode(root_inode);
9034 +
9035 +       root_dentry = d_alloc_root(root_inode);
9036 +       if (!root_dentry)
9037 +               goto err_iput;
9038 +       sb->s_root = root_dentry;
9039 +
9040 +       promfs_populate(sb, root_dentry, of_find_node_by_path("/"));
9041 +       return 0;
9042 +
9043 +err_iput:
9044 +       iput(root_inode);
9045 +err:
9046 +       return -ENOMEM;
9047 +}
9048 +
9049 +static int promfs_get_sb(struct file_system_type *fs_type, int flags,
9050 +               const char *dev_name, void *data, struct vfsmount *mnt)
9051 +{
9052 +       return get_sb_single(fs_type, flags, data, promfs_fill_super, mnt);
9053 +}
9054 +
9055 +static struct file_system_type promfs_fs_type = {
9056 +       .owner = THIS_MODULE,
9057 +       .name = "promfs",
9058 +       .get_sb = promfs_get_sb,
9059 +       .kill_sb = kill_litter_super,
9060 +};
9061 +
9062 +static void init_once(void *i, struct kmem_cache *cachep, unsigned long fl)
9063 +{
9064 +       struct promfs_inode *inode = (struct promfs_inode *) i;
9065 +       inode_init_once(&inode->ino);
9066 +}
9067 +
9068 +static int __init init_promfs(void)
9069 +{
9070 +       int err;
9071 +
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)
9077 +               return -ENOMEM;
9078 +
9079 +       err = register_filesystem(&promfs_fs_type);
9080 +       if (err)
9081 +               kmem_cache_destroy(promfs_inode_cachep);
9082 +               
9083 +       return err;
9084 +}
9085 +
9086 +static void __exit exit_promfs(void)
9087 +{
9088 +       unregister_filesystem(&promfs_fs_type);
9089 +       kmem_cache_destroy(promfs_inode_cachep);
9090 +}
9091 +
9092 +module_init(init_promfs);
9093 +module_exit(exit_promfs);
9094 Index: linux-2.6.24.7/include/asm-x86/ofw.h
9095 ===================================================================
9096 --- /dev/null
9097 +++ linux-2.6.24.7/include/asm-x86/ofw.h
9098 @@ -0,0 +1,16 @@
9099 +/*
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.
9103 + *
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.
9108 + */
9109 +#ifndef _OFW_H
9110 +#define _OFW_H
9111 +
9112 +extern int ofw(char *, int, int, ...); 
9113 +
9114 +#endif
9115 Index: linux-2.6.24.7/include/asm-x86/olpc.h
9116 ===================================================================
9117 --- /dev/null
9118 +++ linux-2.6.24.7/include/asm-x86/olpc.h
9119 @@ -0,0 +1,107 @@
9120 +/* OLPC machine specific definitions */
9121 +
9122 +#ifndef ASM_OLPC_H_
9123 +#define ASM_OLPC_H_
9124 +
9125 +#include <asm/geode.h>
9126 +
9127 +struct olpc_platform_t {
9128 +       int flags;
9129 +       u32 boardrev;
9130 +       int ecver;
9131 +};
9132 +
9133 +#define OLPC_F_PRESENT 0x01
9134 +#define OLPC_F_DCON    0x02
9135 +#define OLPC_F_VSA     0x04
9136 +
9137 +/*
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.
9142 + */
9143 +
9144 +static inline u32 olpc_board(u8 id)
9145 +{
9146 +       return (id << 4) | 0x8;
9147 +}
9148 +
9149 +static inline u32 olpc_board_pre(u8 id)
9150 +{
9151 +       return id << 4;
9152 +}
9153 +
9154 +#ifndef CONFIG_OLPC
9155 +
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; }
9159 +
9160 +#else
9161 +
9162 +extern struct olpc_platform_t olpc_platform_info;
9163 +
9164 +static inline int
9165 +machine_is_olpc(void)
9166 +{
9167 +       return (olpc_platform_info.flags & OLPC_F_PRESENT) ? 1 : 0;
9168 +}
9169 +
9170 +static inline int
9171 +olpc_has_dcon(void)
9172 +{
9173 +       return (olpc_platform_info.flags & OLPC_F_DCON) ? 1 : 0;
9174 +}
9175 +
9176 +static inline int
9177 +olpc_has_vsa(void)
9178 +{
9179 +       return (olpc_platform_info.flags & OLPC_F_VSA) ? 1 : 0;
9180 +}
9181 +
9182 +static inline int olpc_board_at_least(u32 rev)
9183 +{
9184 +       return olpc_platform_info.boardrev >= rev;
9185 +}
9186 +
9187 +#endif
9188 +
9189 +/* EC functions */
9190 +
9191 +int olpc_ec_cmd(unsigned char cmd, unsigned char *inbuf, size_t inlen,
9192 +               unsigned char *outbuf, size_t outlen);
9193 +
9194 +void olpc_register_battery_callback(void (*f)(unsigned long));
9195 +void olpc_deregister_battery_callback(void);
9196 +
9197 +/* EC commands and responses */
9198 +
9199 +/* SCI source values */
9200 +
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
9210 +
9211 +int olpc_ec_mask_set(u8 bits);
9212 +int olpc_ec_mask_unset(u8 bits);
9213 +
9214 +/* GPIO assignments */
9215 +
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)
9224 +
9225 +#endif
9226 +
9227 Index: linux-2.6.24.7/include/asm-x86/prom.h
9228 ===================================================================
9229 --- /dev/null
9230 +++ linux-2.6.24.7/include/asm-x86/prom.h
9231 @@ -0,0 +1,108 @@
9232 +#ifndef _I386_PROM_H
9233 +#define _I386_PROM_H
9234 +#ifdef __KERNEL__
9235 +
9236 +
9237 +/*
9238 + * Definitions for talking to the Open Firmware PROM on
9239 + * Power Macintosh computers.
9240 + *
9241 + * Copyright (C) 1996-2005 Paul Mackerras.
9242 + *
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
9246 + *
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.
9251 + */
9252 +
9253 +#include <linux/types.h>
9254 +#include <linux/proc_fs.h>
9255 +#include <asm/atomic.h>
9256 +
9257 +typedef u32 phandle;
9258 +typedef u32 ihandle;
9259 +
9260 +struct property {
9261 +       char    *name;
9262 +       int     length;
9263 +       void    *value;
9264 +       struct property *next;
9265 +};
9266 +
9267 +struct device_node {
9268 +       const char      *name;
9269 +       const char      *type;
9270 +       phandle node;
9271 +//        phandle linux_phandle;
9272 +       char    *path_component_name;
9273 +       char    *full_name;
9274 +
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 */
9283 +       struct  kref kref;
9284 +       unsigned long _flags;
9285 +       void    *data;
9286 +};
9287 +
9288 +/* flag descriptions */
9289 +#define OF_DYNAMIC 1 /* node and properties were allocated via kmalloc */
9290 +
9291 +#define OF_IS_DYNAMIC(x) test_bit(OF_DYNAMIC, &x->_flags)
9292 +#define OF_MARK_DYNAMIC(x) set_bit(OF_DYNAMIC, &x->_flags)
9293 +
9294 +#define OF_BAD_ADDR    ((u64)-1)
9295 +
9296 +static inline void set_node_proc_entry(struct device_node *dn, struct proc_dir_entry *de)
9297 +{
9298 +       dn->pde = de;
9299 +}
9300 +
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,
9319 +                                        const char *name,
9320 +                                        int *lenp);
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,
9324 +                                  const char *);
9325 +extern const void *of_get_property(const struct device_node *node,
9326 +                            const char *name,
9327 +                            int *lenp);
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,
9331 +                                const char *name,
9332 +                                int def);
9333 +extern int of_n_addr_cells(struct device_node *np);
9334 +extern int of_n_size_cells(struct device_node *np);
9335 +
9336 +extern void prom_build_devicetree(void);
9337 +
9338 +#endif /* __KERNEL__ */
9339 +#endif
9340 Index: linux-2.6.24.7/include/linux/battery.h
9341 ===================================================================
9342 --- /dev/null
9343 +++ linux-2.6.24.7/include/linux/battery.h
9344 @@ -0,0 +1,101 @@
9345 +/*
9346 + * Driver model for batteries
9347 + *
9348 + *     Â© 2006 David Woodhouse <dwmw2@infradead.org>
9349 + *
9350 + * Based on LED Class support, by John Lenz and Richard Purdie:
9351 + *
9352 + *     Â© 2005 John Lenz <lenz@cs.wisc.edu>
9353 + *     Â© 2005-2006 Richard Purdie <rpurdie@openedhand.com>
9354 + *
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.
9358 + *
9359 + */
9360 +#ifndef __LINUX_BATTERY_H__
9361 +#define __LINUX_BATTERY_H__
9362 +
9363 +struct device;
9364 +struct class_device;
9365 +
9366 +/*
9367 + * Battery Core
9368 + */
9369 +#define PWRDEV_TYPE_BATTERY    0
9370 +#define PWRDEV_TYPE_AC         1
9371 +
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)
9381 +
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 */
9388 +
9389 +#define BAT_INFO_TEMP2         "temp2"                 /* Â°C/1000 */
9390 +#define BAT_INFO_TEMP2_NAME    "temp2_name"            /* string */
9391 +
9392 +#define BAT_INFO_VOLTAGE       "voltage"               /* mV */
9393 +#define BAT_INFO_VOLTAGE_DESIGN        "voltage_design"        /* mV */
9394 +
9395 +#define BAT_INFO_CURRENT       "current"               /* mA */
9396 +#define BAT_INFO_CURRENT_NOW   "current_now"           /* mA */
9397 +
9398 +#define BAT_INFO_POWER         "power"                 /* mW */
9399 +#define BAT_INFO_POWER_NOW     "power_now"             /* mW */
9400 +
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 */
9411 +       
9412 +#define BAT_INFO_CAP_PCT       "capacity_percentage"   /* integer */
9413 +
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 */
9418 +
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 */
9424 +
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]] */
9428 +
9429 +struct battery_dev {
9430 +       int                     status_cap;
9431 +       int                     id;
9432 +       int                     type;
9433 +       const char              *name;
9434 +
9435 +       struct device           *dev;
9436 +};
9437 +
9438 +int battery_device_register(struct device *parent,
9439 +                           struct battery_dev *battery_cdev);
9440 +void battery_device_unregister(struct battery_dev *battery_cdev);
9441 +
9442 +
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);
9453  
9454 +       /* Shut down the graphics engine to save power */
9455 +       int (*fb_powerdown)(struct fb_info *info);
9456 +
9457 +       /* Power it back up */
9458 +       int (*fb_powerup)(struct fb_info *info);
9459 +
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);
9466  
9467 +extern int fb_powerdown(struct fb_info *info);
9468 +extern int fb_powerup(struct fb_info *info);
9469 +
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
9477 @@ -125,6 +125,7 @@
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
9482  
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 ===================================================================
9487 --- /dev/null
9488 +++ linux-2.6.24.7/include/linux/isl_38xx.h
9489 @@ -0,0 +1,127 @@
9490 +/*
9491 + *  Copyright (C) 2002 Intersil Americas Inc.
9492 + *
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
9496 + *
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.
9501 + *
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
9505 + */
9506 +
9507 +#ifndef _LINUX_ISL_38XX_H
9508 +#define _LINUX_ISL_38XX_H
9509 +
9510 +#include <asm/io.h>
9511 +
9512 +#define ISL38XX_CB_RX_QSIZE                     8
9513 +#define ISL38XX_CB_TX_QSIZE                     32
9514 +
9515 +/* ISL38XX Access Point Specific definitions */
9516 +#define ISL38XX_MAX_WDS_LINKS                   8
9517 +
9518 +/* ISL38xx Client Specific definitions */
9519 +#define ISL38XX_PSM_ACTIVE_STATE                0
9520 +#define ISL38XX_PSM_POWERSAVE_STATE             1
9521 +
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
9530 +
9531 +/* PCI Memory Area */
9532 +#define ISL38XX_HARDWARE_REG                    0x0000
9533 +#define ISL38XX_CARDBUS_CIS                     0x0800
9534 +#define ISL38XX_DIRECT_MEM_WIN                  0x1000
9535 +
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
9546 +
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
9550 +
9551 +/**
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
9556 + * 
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.
9561 + */
9562 +static inline void
9563 +isl38xx_w32_flush(void __iomem *base, u32 val, unsigned long offset)
9564 +{
9565 +       writel(val, base + offset);
9566 +       (void) readl(base + ISL38XX_PCI_POSTING_FLUSH);
9567 +}
9568 +
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
9578 +
9579 +#define ISL38XX_DEV_INT_PCIUART_CTS             0x4000
9580 +#define ISL38XX_DEV_INT_PCIUART_DR              0x8000
9581 +
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
9589 +
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)
9596 +
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'
9601 +*/
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
9608 +
9609 +/* Some flags for the isl hardware registers controlling DMA inside the
9610 + * chip */
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
9615 +
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;
9629  #endif
9630  };
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,
9644  };
9645  
9646  enum power_supply_type {
9647 @@ -169,9 +171,10 @@ struct power_supply_info {
9648  
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);
9652  
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);
9657  
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 {
9664  };
9665  extern struct vt_spawn_console vt_spawn_con;
9666  
9667 +/* A notifier list for console events  */
9668 +extern struct raw_notifier_head console_notifier_list;
9669 +
9670 +/* Called when the FG console switches to KD_TEXT mode */
9671 +#define CONSOLE_EVENT_SWITCH_TEXT 0x01
9672 +
9673 +/* Called when the FG console switches to KD_GRAPHICS mode */
9674 +#define CONSOLE_EVENT_SWITCH_GRAPHICS 0x02
9675 +
9676 +static inline int console_event_register(struct notifier_block *n)
9677 +{
9678 +       return raw_notifier_chain_register(&console_notifier_list, n);
9679 +}
9680 +
9681 +static inline int console_event_unregister(struct notifier_block *n)
9682 +{
9683 +       return raw_notifier_chain_unregister(&console_notifier_list, n);
9684 +}
9685 +
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) */
9701  
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
9708 @@ -9,7 +9,7 @@
9709  #include <linux/console.h>
9710  #include "power.h"
9711  
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)
9715  
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
9723         suspend support.
9724  
9725 +config DISABLE_SUSPEND_VT_SWITCH
9726 +       bool "Disable the console switch prior to suspend (DANGEROUS)"
9727 +       depends on PM_DEBUG
9728 +       default n
9729 +       ---help---
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.
9735 +
9736 +       If unsure, say N.
9737 +
9738  config PM_VERBOSE
9739         bool "Verbose Power Management debugging"
9740 -       depends on PM_DEBUG
9741 +       depends on VT_CONSOLE && PM && EXPERIMENTAL
9742         default n
9743         ---help---
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)
9751                 return -EPERM;
9752  
9753 +#ifndef CONFIG_OLPC_PM
9754         error = pm_notifier_call_chain(PM_SUSPEND_PREPARE);
9755         if (error)
9756                 goto Finish;
9757  
9758         pm_prepare_console();
9759 +#endif
9760  
9761         if (freeze_processes()) {
9762                 error = -EAGAIN;
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 {
9768         ask_new,
9769         ask_silent,
9770         set_default,
9771 +       set_silentdefault,
9772         set_yes,
9773         set_mod,
9774         set_no,
9775 @@ -64,10 +65,11 @@ static void strip(char *str)
9776  
9777  static void check_stdin(void)
9778  {
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"));
9786                 exit(1);
9787         }
9788  }
9789 @@ -102,6 +104,7 @@ static int conf_askvalue(struct symbol *
9790                 break;
9791         case ask_new:
9792         case ask_silent:
9793 +       case set_silentdefault:
9794                 if (sym_has_value(sym)) {
9795                         printf("%s\n", def);
9796                         return 0;
9797 @@ -352,6 +355,7 @@ static int conf_choice(struct menu *menu
9798                 switch (input_mode) {
9799                 case ask_new:
9800                 case ask_silent:
9801 +               case set_silentdefault:
9802                         if (!is_new) {
9803                                 cnt = def;
9804                                 printf("%d\n", cnt);
9805 @@ -424,7 +428,9 @@ static void conf(struct menu *menu)
9806  
9807                 switch (prop->type) {
9808                 case P_MENU:
9809 -                       if (input_mode == ask_silent && rootEntry != menu) {
9810 +                       if ((input_mode == ask_silent ||
9811 +                                       input_mode == set_silentdefault) &&
9812 +                                       rootEntry != menu) {
9813                                 check_conf(menu);
9814                                 return;
9815                         }
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);
9819                         break;
9820 +               case 'S':
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",
9826 +                                       av[0]);
9827 +                               exit(1);
9828 +                       }
9829 +                       break;
9830                 case 'd':
9831                         input_mode = set_default;
9832                         break;
9833 @@ -557,6 +573,14 @@ int main(int ac, char **av)
9834                         exit(1);
9835                 }
9836                 break;
9837 +       case set_silentdefault:
9838 +               if (conf_read(defconfig_file)) {
9839 +                       printf("***\n"
9840 +                               "*** Can't find default configuration \"%s\"!\n"
9841 +                               "***\n", defconfig_file);
9842 +                       exit(1);
9843 +               }
9844 +               break;
9845         case ask_silent:
9846                 if (stat(".config", &tmpstat)) {
9847                         printf(_("***\n"
9848 @@ -597,7 +621,7 @@ int main(int ac, char **av)
9849                 break;
9850         }
9851  
9852 -       if (input_mode != ask_silent) {
9853 +       if (input_mode != ask_silent && input_mode != set_silentdefault) {
9854                 rootEntry = &rootmenu;
9855                 conf(&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"));
9859                         return 1;
9860                 }
9861 -       } else
9862 +       } else if (input_mode != set_silentdefault)
9863                 goto skip_check;
9864  
9865         do {
9866                 conf_cnt = 0;
9867                 check_conf(&rootmenu);
9868         } while (conf_cnt);
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"));
9873                 return 1;
9874         }
9875  skip_check:
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"));
9880                 return 1;
9881         }
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)
9887         return 0;
9888  }
9889  
9890 -int conf_write(const char *name)
9891 +int conf_write(const char *name, int quiet)
9892  {
9893         FILE *out;
9894         struct symbol *sym;
9895 @@ -548,9 +548,10 @@ int conf_write(const char *name)
9896                         return 1;
9897         }
9898  
9899 -       printf(_("#\n"
9900 -                "# configuration written to %s\n"
9901 -                "#\n"), newname);
9902 +       if (!quiet)
9903 +               printf("#\n"
9904 +                       "# configuration written to %s\n"
9905 +                       "#\n", newname);
9906  
9907         sym_set_change_count(0);
9908  
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
9914  
9915  void on_save_activate(GtkMenuItem * menuitem, gpointer user_data)
9916  {
9917 -       if (conf_write(NULL))
9918 +       if (conf_write(NULL, 0))
9919                 text_insert_msg(_("Error"), _("Unable to save configuration !"));
9920  }
9921  
9922 @@ -634,7 +634,7 @@ store_filename(GtkFileSelection * file_s
9923         fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION
9924                                              (user_data));
9925  
9926 -       if (conf_write(fn))
9927 +       if (conf_write(fn, 0))
9928                 text_insert_msg(_("Error"), _("Unable to save configuration !"));
9929  
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
9935 @@ -3,7 +3,7 @@
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)
9951  
9952 +%_silentdefconfig: $(obj)/conf
9953 +       $(Q)$< -S arch/$(ARCH)/configs/$(subst _silentdefconfig,_defconfig,$@) arch/$(ARCH)/Kconfig
9954 +
9955  # Help text used by make help
9956  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)
9963                 case 0:
9964                         if (!dialog_input_result[0])
9965                                 return;
9966 -                       if (!conf_write(dialog_input_result)) {
9967 +                       if (!conf_write(dialog_input_result, 0)) {
9968                                 set_config_filename(dialog_input_result);
9969                                 return;
9970                         }
9971 @@ -945,7 +945,7 @@ int main(int ac, char **av)
9972  
9973         switch (res) {
9974         case 0:
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)
9985  
9986  void ConfigMainWindow::saveConfig(void)
9987  {
9988 -       if (conf_write(NULL))
9989 +       if (conf_write(NULL, 0))
9990                 QMessageBox::information(this, "qconf", "Unable to save configuration!");
9991  }
9992  
9993 @@ -1467,7 +1467,7 @@ void ConfigMainWindow::saveConfigAs(void
9994         QString s = QFileDialog::getSaveFileName(".config", NULL, this);
9995         if (s.isNull())
9996                 return;
9997 -       if (conf_write(QFile::encodeName(s)))
9998 +       if (conf_write(QFile::encodeName(s), 0))
9999                 QMessageBox::information(this, "qconf", "Unable to save configuration!");
10000  }
10001  
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:
10009                 e->accept();
10010                 break;
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
10018         },
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),
10025         {
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);
10033  }
10034  
10035 -static int snd_cs5535audio_mixer(struct cs5535audio *cs5535au)
10036 +static int __devinit snd_cs5535audio_mixer(struct cs5535audio *cs5535au)
10037  {
10038         struct snd_card *card = cs5535au->card;
10039         struct snd_ac97_bus *pbus;
10040 @@ -160,10 +160,14 @@ static int snd_cs5535audio_mixer(struct 
10041                 return err;
10042  
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;
10049  
10050 +       /* olpc_prequirks is dummied out if not olpc */
10051 +       olpc_prequirks(card, &ac97);
10052 +
10053         if ((err = snd_ac97_mixer(pbus, &ac97, &cs5535au->ac97)) < 0) {
10054                 snd_printk(KERN_ERR "mixer failed\n");
10055                 return err;
10056 @@ -171,6 +175,12 @@ static int snd_cs5535audio_mixer(struct 
10057  
10058         snd_ac97_tune_hardware(cs5535au->ac97, ac97_quirks, ac97_quirk);
10059  
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");
10063 +               return err;
10064 +       }
10065 +
10066         return 0;
10067  }
10068  
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;
10076         u32 saved_prd;
10077 +       int pcm_open_flag;
10078  };
10079  
10080  struct cs5535audio {
10081 @@ -93,8 +94,21 @@ struct cs5535audio {
10082         struct cs5535audio_dma dmas[NUM_CS5535AUDIO_DMAS];
10083  };
10084  
10085 +#ifdef CONFIG_PM
10086  int snd_cs5535audio_suspend(struct pci_dev *pci, pm_message_t state);
10087  int snd_cs5535audio_resume(struct pci_dev *pci);
10088 +#endif
10089 +
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);
10094 +#else
10095 +#define olpc_prequirks(arg,arg2)       do {} while (0)
10096 +#define olpc_quirks(arg,arg2)          (0)
10097 +#define olpc_ai_enable(a, v) (0)
10098 +#endif
10099 +
10100  int __devinit snd_cs5535audio_pcm(struct cs5535audio *cs5535audio);
10101  
10102  #endif /* __SOUND_CS5535AUDIO_H */
10103 Index: linux-2.6.24.7/sound/pci/cs5535audio/cs5535audio_olpc.c
10104 ===================================================================
10105 --- /dev/null
10106 +++ linux-2.6.24.7/sound/pci/cs5535audio/cs5535audio_olpc.c
10107 @@ -0,0 +1,110 @@
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>
10113 +
10114 +#include <asm/olpc.h>
10115 +#include "cs5535audio.h"
10116 +
10117 +/*
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.
10121 + */
10122 +
10123 +int olpc_ai_enable(struct snd_ac97 *ac97, u8 val)
10124 +{
10125 +       int err;
10126 +
10127 +       /*
10128 +        * update the High Pass Filter (via AC97_AD_TEST2), and then set
10129 +        * Analog Input mode through a GPIO.
10130 +        */
10131 +
10132 +       if (val) {
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);
10136 +       }
10137 +       else {
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);
10141 +       }
10142 +       if (err < 0)
10143 +               snd_printk(KERN_ERR "Error updating AD_TEST2: %d\n", err);
10144 +
10145 +       return err;
10146 +}
10147 +EXPORT_SYMBOL_GPL(olpc_ai_enable);
10148 +
10149 +static int snd_cs5535audio_ai_info(struct snd_kcontrol *kcontrol,
10150 +               struct snd_ctl_elem_info *uinfo)
10151 +{
10152 +       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
10153 +       uinfo->count = 1;
10154 +       uinfo->value.integer.min = 0;
10155 +       uinfo->value.integer.max = 1;
10156 +       return 0;
10157 +}
10158 +
10159 +static int snd_cs5535audio_ai_get(struct snd_kcontrol *kcontrol,
10160 +               struct snd_ctl_elem_value *ucontrol)
10161 +{
10162 +       ucontrol->value.integer.value[0] = geode_gpio_isset(OLPC_GPIO_MIC_AC,
10163 +                       GPIO_OUTPUT_VAL);
10164 +       return 0;
10165 +}
10166 +
10167 +static int snd_cs5535audio_ai_put(struct snd_kcontrol *kcontrol,
10168 +               struct snd_ctl_elem_value *ucontrol)
10169 +{
10170 +       struct cs5535audio *cs5535au = snd_kcontrol_chip(kcontrol);
10171 +       struct snd_ac97 *ac97 = cs5535au->ac97;
10172 +
10173 +       olpc_ai_enable(ac97, ucontrol->value.integer.value[0]);
10174 +
10175 +       return 1;
10176 +}
10177 +
10178 +static struct snd_kcontrol_new snd_cs5535audio_controls __devinitdata =
10179 +{
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
10186 +};
10187 +
10188 +void __devinit olpc_prequirks(struct snd_card *card,
10189 +               struct snd_ac97_template *ac97)
10190 +{
10191 +       /* Bail if this isn't an OLPC platform */
10192 +       if (!machine_is_olpc())
10193 +               return;
10194 +
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;
10198 +}
10199 +
10200 +int __devinit olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97)
10201 +{
10202 +       struct snd_ctl_elem_id elem;
10203 +
10204 +       /* Bail if this isn't an OLPC platform */
10205 +       if (!machine_is_olpc())
10206 +               return 0;
10207 +
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);
10213 +
10214 +       /* add the override for OLPC's HPF */
10215 +       return snd_ctl_add(card, snd_ctl_new1(&snd_cs5535audio_controls,
10216 +                       ac97->private_data));
10217 +}
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));
10226 +       if (!err)
10227 +               dma->pcm_open_flag = 1;
10228 +
10229         return err;
10230  }
10231  
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;
10235  
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);
10240 +               else
10241 +                       snd_ac97_update_power(cs5535au->ac97,
10242 +                                       AC97_PCM_LR_ADC_RATE, 0);
10243 +               dma->pcm_open_flag = 0;
10244 +       }
10245         cs5535audio_clear_dma_packets(cs5535au, dma, substream);
10246         return snd_pcm_lib_free_pages(substream);
10247  }
10248 @@ -341,6 +353,7 @@ static int snd_cs5535audio_capture_open(
10249         int err;
10250         struct cs5535audio *cs5535au = snd_pcm_substream_chip(substream);
10251         struct snd_pcm_runtime *runtime = substream->runtime;
10252 +       struct snd_ac97 *ac97 = cs5535au->ac97;
10253  
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)
10259                 return err;
10260 -       return 0;
10261 +
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);
10267 +#endif
10268 +       return err;
10269  }
10270  
10271  static int snd_cs5535audio_capture_close(struct snd_pcm_substream *substream)
10272  {
10273 +#ifdef CONFIG_OLPC
10274 +       struct cs5535audio *cs5535au = snd_pcm_substream_chip(substream);
10275 +       struct snd_ac97 *ac97 = cs5535au->ac97;
10276 +
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);
10282 +#endif
10283 +
10284         return 0;
10285  }
10286  
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
10291 @@ -5,5 +5,9 @@
10292  snd-cs5535audio-y := cs5535audio.o cs5535audio_pcm.o
10293  snd-cs5535audio-$(CONFIG_PM) += cs5535audio_pm.o
10294  
10295 +ifdef CONFIG_OLPC
10296 +snd-cs5535audio-objs += cs5535audio_olpc.o
10297 +endif
10298 +
10299  # Toplevel Module Dependency
10300  obj-$(CONFIG_SND_CS5535AUDIO) += snd-cs5535audio.o