fixes ifxmips pci support and adds GENERIC_GPIO
[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
This page took 0.455515 seconds and 5 git commands to generate.