ixp4xx: Update config-default to 2.6.24
[openwrt.git] / target / linux / olpc / patches-2.6.24 / 100-olpc.patch
1 diff -purN linux_2.6.24_org/arch/x86/Kconfig linux_2.6.24_olpc/arch/x86/Kconfig
2 --- linux_2.6.24_org/arch/x86/Kconfig 2008-02-15 20:11:57.000000000 +0000
3 +++ linux_2.6.24_olpc/arch/x86/Kconfig 2008-02-15 18:59:21.000000000 +0000
4 @@ -1415,6 +1415,9 @@ config PCI_GODIRECT
5 config PCI_GOANY
6 bool "Any"
7
8 +config PCI_GOOLPC
9 + bool "OLPC"
10 +
11 endchoice
12
13 config PCI_BIOS
14 @@ -1425,7 +1428,7 @@ config PCI_BIOS
15 # x86-64 doesn't support PCI BIOS access from long mode so always go direct.
16 config PCI_DIRECT
17 bool
18 - depends on PCI && (X86_64 || (PCI_GODIRECT || PCI_GOANY) || X86_VISWS)
19 + depends on PCI && (X86_64 || (PCI_GODIRECT || PCI_GOANY || PCI_GOOLPC) || X86_VISWS)
20 default y
21
22 config PCI_MMCONFIG
23 @@ -1442,6 +1445,11 @@ config PCI_MMCONFIG
24 bool "Support mmconfig PCI config space access"
25 depends on X86_64 && PCI && ACPI
26
27 +config PCI_OLPC
28 + bool
29 + depends on PCI && PCI_GOOLPC
30 + default y
31 +
32 config DMAR
33 bool "Support for DMA Remapping Devices (EXPERIMENTAL)"
34 depends on X86_64 && PCI_MSI && ACPI && EXPERIMENTAL
35 @@ -1561,6 +1569,21 @@ config K8_NB
36 def_bool y
37 depends on AGP_AMD64 || (X86_64 && (GART_IOMMU || (PCI && NUMA)))
38
39 +config OLPC
40 + bool "OLPC Support"
41 + default n
42 + help
43 + Add OLPC Support
44 +
45 +config OLPC_PM
46 + bool "OLPC power management support"
47 + default n
48 + depends on OLPC
49 +
50 +config OPEN_FIRMWARE
51 + bool "Support for Open Firmware"
52 + default y if OLPC
53 +
54 source "drivers/pcmcia/Kconfig"
55
56 source "drivers/pci/hotplug/Kconfig"
57 diff -purN linux_2.6.24_org/arch/x86/kernel/Makefile_32 linux_2.6.24_olpc/arch/x86/kernel/Makefile_32
58 --- linux_2.6.24_org/arch/x86/kernel/Makefile_32 2008-02-15 20:11:58.000000000 +0000
59 +++ linux_2.6.24_olpc/arch/x86/kernel/Makefile_32 2008-02-15 18:59:25.000000000 +0000
60 @@ -49,6 +49,13 @@ obj-y += pcspeaker.o
61
62 obj-$(CONFIG_SCx200) += scx200_32.o
63
64 +obj-$(CONFIG_OLPC) += olpc.o
65 +obj-$(CONFIG_OLPC_PM) += olpc-pm.o olpc-wakeup.o
66 +obj-$(CONFIG_OPEN_FIRMWARE) += ofw.o
67 +obj-$(PROM_FS) += promfs.o
68 +
69 +
70 +
71 # vsyscall_32.o contains the vsyscall DSO images as __initdata.
72 # We must build both images before we can assemble it.
73 # Note: kbuild does not track this dependency due to usage of .incbin
74 diff -purN linux_2.6.24_org/arch/x86/kernel/ofw.c linux_2.6.24_olpc/arch/x86/kernel/ofw.c
75 --- linux_2.6.24_org/arch/x86/kernel/ofw.c 1970-01-01 01:00:00.000000000 +0100
76 +++ linux_2.6.24_olpc/arch/x86/kernel/ofw.c 2008-02-15 18:59:25.000000000 +0000
77 @@ -0,0 +1,100 @@
78 +/*
79 + * ofw.c - Open Firmware client interface for 32-bit systems.
80 + * This code is intended to be portable to any 32-bit Open Firmware
81 + * implementation with a standard client interface that can be
82 + * called when Linux is running.
83 + *
84 + * Copyright (C) 2007 Mitch Bradley <wmb@firmworks.com>
85 + * Copyright (C) 2007 Andres Salomon <dilinger@debian.org>
86 + */
87 +
88 +#include <stdarg.h>
89 +#include <linux/spinlock.h>
90 +#include <linux/module.h>
91 +#include <asm/ofw.h>
92 +
93 +
94 +int (*call_firmware)(int *);
95 +
96 +static DEFINE_SPINLOCK(prom_lock);
97 +
98 +#define MAXARGS 20
99 +
100 +/*
101 + * The return value from ofw() in all cases is 0 if the attempt to call the
102 + * function succeeded, <0 otherwise. That return value is from the
103 + * gateway function only. Any results from the called function are returned
104 + * via output argument pointers.
105 + *
106 + * Here are call templates for all the standard OFW client services:
107 + *
108 + * ofw("test", 1, 1, namestr, &missing);
109 + * ofw("peer", 1, 1, phandle, &sibling_phandle);
110 + * ofw("child", 1, 1, phandle, &child_phandle);
111 + * ofw("parent", 1, 1, phandle, &parent_phandle);
112 + * ofw("instance_to_package", 1, 1, ihandle, &phandle);
113 + * ofw("getproplen", 2, 1, phandle, namestr, &proplen);
114 + * ofw("getprop", 4, 1, phandle, namestr, bufaddr, buflen, &size);
115 + * ofw("nextprop", 3, 1, phandle, previousstr, bufaddr, &flag);
116 + * ofw("setprop", 4, 1, phandle, namestr, bufaddr, len, &size);
117 + * ofw("canon", 3, 1, devspecstr, bufaddr, buflen, &length);
118 + * ofw("finddevice", 1, 1, devspecstr, &phandle);
119 + * ofw("instance-to-path", 3, 1, ihandle, bufaddr, buflen, &length);
120 + * ofw("package-to-path", 3, 1, phandle, bufaddr, buflen, &length);
121 + * ofw("call_method", numin, numout, in0, in1, ..., &out0, &out1, ...);
122 + * ofw("open", 1, 1, devspecstr, &ihandle);
123 + * ofw("close", 1, 0, ihandle);
124 + * ofw("read", 3, 1, ihandle, addr, len, &actual);
125 + * ofw("write", 3, 1, ihandle, addr, len, &actual);
126 + * ofw("seek", 3, 1, ihandle, pos_hi, pos_lo, &status);
127 + * ofw("claim", 3, 1, virtaddr, size, align, &baseaddr);
128 + * ofw("release", 2, 0, virtaddr, size);
129 + * ofw("boot", 1, 0, bootspecstr);
130 + * ofw("enter", 0, 0);
131 + * ofw("exit", 0, 0);
132 + * ofw("chain", 5, 0, virtaddr, size, entryaddr, argsaddr, len);
133 + * ofw("interpret", numin+1, numout+1, cmdstr, in0, ..., &catchres, &out0, ...);
134 + * ofw("set-callback", 1, 1, newfuncaddr, &oldfuncaddr);
135 + * ofw("set-symbol-lookup", 2, 0, symtovaladdr, valtosymaddr);
136 + * ofw("milliseconds", 0, 1, &ms);
137 + */
138 +
139 +int ofw(char *name, int numargs, int numres, ...)
140 +{
141 + va_list ap;
142 + int argarray[MAXARGS+3];
143 + int argnum = 3;
144 + int retval;
145 + int *intp;
146 + unsigned long flags;
147 +
148 + if (!call_firmware)
149 + return -1;
150 + if ((numargs + numres) > MAXARGS)
151 + return -1; /* spit out an error? */
152 +
153 + argarray[0] = (int) name;
154 + argarray[1] = numargs;
155 + argarray[2] = numres;
156 +
157 + va_start(ap, numres);
158 + while (numargs) {
159 + argarray[argnum++] = va_arg(ap, int);
160 + numargs--;
161 + }
162 +
163 + spin_lock_irqsave(&prom_lock, flags);
164 + retval = call_firmware(argarray);
165 + spin_unlock_irqrestore(&prom_lock, flags);
166 +
167 + if (retval == 0) {
168 + while (numres) {
169 + intp = va_arg(ap, int *);
170 + *intp = argarray[argnum++];
171 + numres--;
172 + }
173 + }
174 + va_end(ap);
175 + return retval;
176 +}
177 +EXPORT_SYMBOL(ofw);
178 diff -purN linux_2.6.24_org/arch/x86/kernel/olpc.c linux_2.6.24_olpc/arch/x86/kernel/olpc.c
179 --- linux_2.6.24_org/arch/x86/kernel/olpc.c 1970-01-01 01:00:00.000000000 +0100
180 +++ linux_2.6.24_olpc/arch/x86/kernel/olpc.c 2008-02-15 18:59:25.000000000 +0000
181 @@ -0,0 +1,287 @@
182 +/* Support for the OLPC DCON and OLPC EC access
183 + * Copyright (C) 2006, Advanced Micro Devices, Inc.
184 + *
185 + * This program is free software; you can redistribute it and/or modify
186 + * it under the terms of the GNU General Public License as published by
187 + * the Free Software Foundation; either version 2 of the License, or
188 + * (at your option) any later version.
189 + */
190 +
191 +#include <linux/autoconf.h>
192 +#include <linux/kernel.h>
193 +#include <linux/init.h>
194 +#include <linux/mc146818rtc.h>
195 +#include <linux/delay.h>
196 +#include <linux/spinlock.h>
197 +
198 +#include <asm/olpc.h>
199 +#include <asm/ofw.h>
200 +
201 +/* This is our new multi-purpose structure used to contain the
202 + * information about the platform that we detect
203 + */
204 +
205 +struct olpc_platform_t olpc_platform_info;
206 +EXPORT_SYMBOL_GPL(olpc_platform_info);
207 +
208 +/*********************************************************************
209 + * EC locking and access
210 + *********************************************************************/
211 +
212 +static DEFINE_SPINLOCK(ec_lock);
213 +
214 +/* what the timeout *should* be (in ms) */
215 +#define EC_BASE_TIMEOUT 20
216 +
217 +/* the timeout that bugs in the EC might force us to actually use */
218 +static int ec_timeout = EC_BASE_TIMEOUT;
219 +
220 +static int __init olpc_ec_timeout_set(char *str)
221 +{
222 + if (get_option(&str, &ec_timeout) != 1) {
223 + ec_timeout = EC_BASE_TIMEOUT;
224 + printk(KERN_ERR "olpc-ec: invalid argument to "
225 + "'olpc_ec_timeout=', ignoring!\n");
226 + }
227 + printk(KERN_DEBUG "olpc-ec: using %d ms delay for EC commands.\n",
228 + ec_timeout);
229 + return 1;
230 +}
231 +__setup("olpc_ec_timeout=", olpc_ec_timeout_set);
232 +
233 +/*
234 + * These *bf_status functions return whether the buffers are full or not.
235 + */
236 +
237 +static inline unsigned int ibf_status(unsigned int port)
238 +{
239 + return !!(inb(port) & 0x02);
240 +}
241 +
242 +static inline unsigned int obf_status(unsigned int port)
243 +{
244 + return inb(port) & 0x01;
245 +}
246 +
247 +#define wait_on_ibf(p, d) __wait_on_ibf(__LINE__, (p), (d))
248 +static int __wait_on_ibf(unsigned int line, unsigned int port, int desired)
249 +{
250 + unsigned int timeo;
251 + int state = ibf_status(port);
252 +
253 + for (timeo = ec_timeout; state != desired && timeo; timeo--) {
254 + mdelay(1);
255 + state = ibf_status(port);
256 + }
257 +
258 + if ((state == desired) && (ec_timeout > EC_BASE_TIMEOUT) &&
259 + timeo < (ec_timeout - EC_BASE_TIMEOUT)) {
260 + printk(KERN_WARNING "olpc-ec: %d: waited %u ms for IBF!\n",
261 + line, ec_timeout - timeo);
262 + }
263 +
264 + return !(state == desired);
265 +}
266 +
267 +#define wait_on_obf(p, d) __wait_on_obf(__LINE__, (p), (d))
268 +static int __wait_on_obf(unsigned int line, unsigned int port, int desired)
269 +{
270 + unsigned int timeo;
271 + int state = obf_status(port);
272 +
273 + for (timeo = ec_timeout; state != desired && timeo; timeo--) {
274 + mdelay(1);
275 + state = obf_status(port);
276 + }
277 +
278 + if ((state == desired) && (ec_timeout > EC_BASE_TIMEOUT) &&
279 + timeo < (ec_timeout - EC_BASE_TIMEOUT)) {
280 + printk(KERN_WARNING "olpc-ec: %d: waited %u ms for OBF!\n",
281 + line, ec_timeout - timeo);
282 + }
283 +
284 + return !(state == desired);
285 +}
286 +
287 +int olpc_ec_cmd(unsigned char cmd, unsigned char *inbuf, size_t inlen,
288 + unsigned char *outbuf, size_t outlen)
289 +{
290 + unsigned long flags;
291 + int ret = -EIO;
292 + int i;
293 +
294 + spin_lock_irqsave(&ec_lock, flags);
295 +
296 + /* Clear OBF */
297 + for (i = 0; i < 10 && (obf_status(0x6c) == 1); i++)
298 + inb(0x68);
299 + if (i == 10) {
300 + printk(KERN_ERR "olpc-ec: timeout while attempting to "
301 + "clear OBF flag!\n");
302 + goto err;
303 + }
304 +
305 + if (wait_on_ibf(0x6c, 0)) {
306 + printk(KERN_ERR "olpc-ec: timeout waiting for EC to "
307 + "quiesce!\n");
308 + goto err;
309 + }
310 +
311 +restart:
312 + /*
313 + * Note that if we time out during any IBF checks, that's a failure;
314 + * we have to return. There's no way for the kernel to clear that.
315 + *
316 + * If we time out during an OBF check, we can restart the command;
317 + * reissuing it will clear the OBF flag, and we should be alright.
318 + * The OBF flag will sometimes misbehave due to what we believe
319 + * is a hardware quirk..
320 + */
321 + printk(KERN_DEBUG "olpc-ec: running cmd 0x%x\n", cmd);
322 + outb(cmd, 0x6c);
323 +
324 + if (wait_on_ibf(0x6c, 0)) {
325 + printk(KERN_ERR "olpc-ec: timeout waiting for EC to read "
326 + "command!\n");
327 + goto err;
328 + }
329 +
330 + if (inbuf && inlen) {
331 + /* write data to EC */
332 + for (i = 0; i < inlen; i++) {
333 + if (wait_on_ibf(0x6c, 0)) {
334 + printk(KERN_ERR "olpc-ec: timeout waiting for"
335 + " EC accept data!\n");
336 + goto err;
337 + }
338 + printk(KERN_DEBUG "olpc-ec: sending cmd arg 0x%x\n",
339 + inbuf[i]);
340 + outb(inbuf[i], 0x68);
341 + }
342 + }
343 + if (outbuf && outlen) {
344 + /* read data from EC */
345 + for (i = 0; i < outlen; i++) {
346 + if (wait_on_obf(0x6c, 1)) {
347 + printk(KERN_ERR "olpc-ec: timeout waiting for"
348 + " EC to provide data!\n");
349 + goto restart;
350 + }
351 + outbuf[i] = inb(0x68);
352 + printk(KERN_DEBUG "olpc-ec: received 0x%x\n",
353 + outbuf[i]);
354 + }
355 + }
356 +
357 + ret = 0;
358 +err:
359 + spin_unlock_irqrestore(&ec_lock, flags);
360 + return ret;
361 +}
362 +EXPORT_SYMBOL_GPL(olpc_ec_cmd);
363 +
364 +/*********************************************************************
365 + * DCON stuff
366 + *********************************************************************/
367 +
368 +static void __init
369 +ec_detect(void)
370 +{
371 + olpc_ec_cmd(0x08, NULL, 0, (unsigned char *) &olpc_platform_info.ecver, 1);
372 +}
373 +
374 +/* Check to see if this version of the OLPC board has VSA built
375 + * in, and set a flag
376 + */
377 +
378 +static void __init vsa_detect(void)
379 +{
380 + u16 rev;
381 +
382 + outw(0xFC53, 0xAC1C);
383 + outw(0x0003, 0xAC1C);
384 +
385 + rev = inw(0xAC1E);
386 +
387 + if (rev == 0x4132)
388 + olpc_platform_info.flags |= OLPC_F_VSA;
389 +}
390 +
391 +static void __init platform_detect(void)
392 +{
393 + size_t propsize;
394 + u32 rev;
395 +
396 + if (ofw("getprop", 4, 1, NULL, "board-revision-int", &rev, 4,
397 + &propsize) || propsize != 4) {
398 + printk(KERN_ERR "ofw: getprop call failed!\n");
399 + rev = 0;
400 + }
401 + olpc_platform_info.boardrev = be32_to_cpu(rev);
402 +}
403 +
404 +static int olpc_dcon_present = -1;
405 +module_param(olpc_dcon_present, int, 0444);
406 +
407 +/* REV_A CMOS map:
408 + * bit 440; DCON present bit
409 + */
410 +
411 +#define OLPC_CMOS_DCON_OFFSET (440 / 8)
412 +#define OLPC_CMOS_DCON_MASK 0x01
413 +
414 +static int __init olpc_init(void)
415 +{
416 + unsigned char *romsig;
417 +
418 + spin_lock_init(&ec_lock);
419 +
420 + romsig = ioremap(0xffffffc0, 16);
421 +
422 + if (!romsig)
423 + return 0;
424 +
425 + if (strncmp(romsig, "CL1 Q", 7))
426 + goto unmap;
427 + if (strncmp(romsig+6, romsig+13, 3)) {
428 + printk(KERN_INFO "OLPC BIOS signature looks invalid. Assuming not OLPC\n");
429 + goto unmap;
430 + }
431 + printk(KERN_INFO "OLPC board with OpenFirmware: %.16s\n", romsig);
432 +
433 + olpc_platform_info.flags |= OLPC_F_PRESENT;
434 +
435 + /* Get the platform revision */
436 + platform_detect();
437 +
438 + /* If olpc_dcon_present isn't set by the command line, then
439 + * "detect" it
440 + */
441 +
442 + if (olpc_dcon_present == -1) {
443 + /* B1 and greater always has a DCON */
444 + if (olpc_board_at_least(olpc_board(0xb1)))
445 + olpc_dcon_present = 1;
446 + }
447 +
448 + if (olpc_dcon_present)
449 + olpc_platform_info.flags |= OLPC_F_DCON;
450 +
451 + /* Get the EC revision */
452 + ec_detect();
453 +
454 + /* Check to see if the VSA exists */
455 + vsa_detect();
456 +
457 + printk(KERN_INFO "OLPC board revision: %s%X (EC=%x)\n",
458 + ((olpc_platform_info.boardrev & 0xf) < 8) ? "pre" : "",
459 + olpc_platform_info.boardrev >> 4,
460 + olpc_platform_info.ecver);
461 +
462 + unmap:
463 + iounmap(romsig);
464 +
465 + return 0;
466 +}
467 +
468 +postcore_initcall(olpc_init);
469 diff -purN linux_2.6.24_org/arch/x86/kernel/olpc-pm.c linux_2.6.24_olpc/arch/x86/kernel/olpc-pm.c
470 --- linux_2.6.24_org/arch/x86/kernel/olpc-pm.c 1970-01-01 01:00:00.000000000 +0100
471 +++ linux_2.6.24_olpc/arch/x86/kernel/olpc-pm.c 2008-02-15 18:59:26.000000000 +0000
472 @@ -0,0 +1,946 @@
473 +/* olpc-pm.c
474 + * © 2006 Red Hat, Inc.
475 + * Portions also copyright 2006 Advanced Micro Devices, Inc.
476 + * GPLv2
477 + */
478 +
479 +#include <linux/kernel.h>
480 +#include <linux/interrupt.h>
481 +#include <linux/module.h>
482 +#include <linux/delay.h>
483 +#include <linux/input.h>
484 +#include <linux/suspend.h>
485 +#include <linux/bootmem.h>
486 +#include <linux/platform_device.h>
487 +#include <linux/rtc.h>
488 +#include <linux/mc146818rtc.h>
489 +#include <asm/io.h>
490 +
491 +#include <asm/olpc.h>
492 +
493 +/* A few words about accessing the ACPI and PM registers. Long story short,
494 + byte and word accesses of the ACPI and PM registers is broken. The only
495 + way to do it really correctly is to use dword accesses, which we do
496 + throughout this code. For more details, please consult Eratta 17 and 18
497 + here:
498 +
499 + http://www.amd.com/files/connectivitysolutions/geode/geode_gx/34472D_CS5536_B1_specupdate.pdf
500 +*/
501 +
502 +#define PM_IRQ 3
503 +
504 +#define CS5536_PM_PWRBTN (1 << 8)
505 +#define CS5536_PM_RTC (1 << 10)
506 +#define CS5536_PM_WAK (1 << 15)
507 +
508 +#define GPIO_WAKEUP_EC (1 << 31)
509 +#define GPIO_WAKEUP_LID (1 << 30)
510 +
511 +#define PM_MODE_NORMAL 0
512 +#define PM_MODE_TEST 1
513 +#define PM_MODE_MAX 2
514 +
515 +/* These, and the battery EC commands, should be in an olpc.h. */
516 +#define EC_WRITE_SCI_MASK 0x1b
517 +#define EC_READ_SCI_MASK 0x1c
518 +
519 +extern void do_olpc_suspend_lowlevel(void);
520 +
521 +static struct {
522 + unsigned long address;
523 + unsigned short segment;
524 +} ofw_bios_entry = { 0, __KERNEL_CS };
525 +
526 +static int olpc_pm_mode = PM_MODE_NORMAL;
527 +static unsigned long acpi_base;
528 +static unsigned long pms_base;
529 +static int sci_irq;
530 +static int olpc_lid_flag;
531 +
532 +static struct input_dev *pm_inputdev;
533 +static struct input_dev *lid_inputdev;
534 +static struct input_dev *ebook_inputdev;
535 +static struct platform_suspend_ops olpc_pm_ops;
536 +
537 +static int gpio_wake_events = 0;
538 +static int ebook_state = -1;
539 +static u16 olpc_wakeup_mask = 0;
540 +
541 +static unsigned int test_timeout = 0;
542 +static char *wackup_source = "none";
543 +
544 +struct platform_device olpc_powerbutton_dev = {
545 + .name = "powerbutton",
546 + .id = -1,
547 +};
548 +
549 +struct platform_device olpc_lid_dev = {
550 + .name = "lid",
551 + .id = -1,
552 +};
553 +
554 +static void __init init_ebook_state(void)
555 +{
556 + if (olpc_ec_cmd(0x2a, NULL, 0, (unsigned char *) &ebook_state, 1)) {
557 + printk(KERN_WARNING "olpc-pm: failed to get EBOOK state!\n");
558 + ebook_state = 0;
559 + }
560 + ebook_state &= 1;
561 +
562 + /* the input layer needs to know what value to default to as well */
563 + input_report_switch(ebook_inputdev, SW_TABLET_MODE, ebook_state);
564 + input_sync(ebook_inputdev);
565 +}
566 +
567 +static void (*battery_callback)(unsigned long);
568 +static DEFINE_SPINLOCK(battery_callback_lock);
569 +
570 +/* propagate_events is non-NULL if run from workqueue,
571 + NULL when called at init time to flush SCI queue */
572 +static void process_sci_queue(struct work_struct *propagate_events)
573 +{
574 + unsigned char data = 0;
575 + unsigned char battery_events = 0;
576 + int ret;
577 +
578 + do {
579 + ret = olpc_ec_cmd(0x84, NULL, 0, &data, 1);
580 + if (!ret) {
581 + printk(KERN_DEBUG "olpc-pm: SCI 0x%x received\n",
582 + data);
583 +
584 + if (wackup_source && !strcmp(wackup_source, "sci")) {
585 + /*
586 + * XXX: in order for this to not be racy, we
587 + * need assurance that we will never get
588 + * preempted by olpc_do_sleep here!
589 + */
590 + switch (data) {
591 + case EC_SCI_SRC_EMPTY:
592 + wackup_source = "empty sci";
593 + break;
594 + case EC_SCI_SRC_GAME:
595 + wackup_source = "key press";
596 + break;
597 + case EC_SCI_SRC_BATTERY:
598 + wackup_source = "battery";
599 + break;
600 + case EC_SCI_SRC_BATSOC:
601 + wackup_source = "battery state change";
602 + break;
603 + case EC_SCI_SRC_BATERR:
604 + wackup_source = "battery error";
605 + break;
606 + case EC_SCI_SRC_EBOOK:
607 + wackup_source = "ebook";
608 + break;
609 + case EC_SCI_SRC_WLAN:
610 + wackup_source = "wlan packet";
611 + break;
612 + case EC_SCI_SRC_ACPWR:
613 + wackup_source = "ac power";
614 + break;
615 + default:
616 + wackup_source = "unknown";
617 + }
618 + }
619 +
620 + if (data & (EC_SCI_SRC_BATERR | EC_SCI_SRC_BATSOC |
621 + EC_SCI_SRC_BATTERY | EC_SCI_SRC_ACPWR))
622 + battery_events |= data;
623 + else if (data == EC_SCI_SRC_EBOOK) {
624 + ebook_state = !ebook_state;
625 + if (propagate_events) {
626 + input_report_switch(ebook_inputdev,
627 + SW_TABLET_MODE, ebook_state);
628 + input_sync(ebook_inputdev);
629 + }
630 + }
631 + }
632 + } while (data && !ret);
633 +
634 + if (battery_events && battery_callback && propagate_events) {
635 + void (*cbk)(unsigned long);
636 +
637 + /* Older EC versions didn't distinguish between AC and battery
638 + events */
639 + if (olpc_platform_info.ecver < 0x51)
640 + battery_events = EC_SCI_SRC_BATTERY | EC_SCI_SRC_ACPWR;
641 +
642 + spin_lock(&battery_callback_lock);
643 + cbk = battery_callback;
644 + spin_unlock(&battery_callback_lock);
645 +
646 + cbk(battery_events);
647 + }
648 +
649 + if (ret)
650 + printk(KERN_WARNING "Failed to clear SCI queue!\n");
651 +}
652 +
653 +static DECLARE_WORK(sci_work, process_sci_queue);
654 +
655 +void olpc_register_battery_callback(void (*f)(unsigned long))
656 +{
657 + spin_lock(&battery_callback_lock);
658 + battery_callback = f;
659 + spin_unlock(&battery_callback_lock);
660 +}
661 +EXPORT_SYMBOL_GPL(olpc_register_battery_callback);
662 +
663 +void olpc_deregister_battery_callback(void)
664 +{
665 + spin_lock(&battery_callback_lock);
666 + battery_callback = NULL;
667 + spin_unlock(&battery_callback_lock);
668 + cancel_work_sync(&sci_work);
669 +}
670 +EXPORT_SYMBOL_GPL(olpc_deregister_battery_callback);
671 +
672 +
673 +static int olpc_pm_interrupt(int irq, void *id)
674 +{
675 + uint32_t sts, gpe = 0;
676 +
677 + sts = inl(acpi_base + PM1_STS);
678 + outl(sts | 0xFFFF, acpi_base + PM1_STS);
679 +
680 + if (olpc_board_at_least(olpc_board(0xb2))) {
681 + gpe = inl(acpi_base + PM_GPE0_STS);
682 + outl(0xFFFFFFFF, acpi_base + PM_GPE0_STS);
683 + }
684 +
685 + if (sts & CS5536_PM_PWRBTN) {
686 + if (!wackup_source)
687 + wackup_source = "power button";
688 + printk(KERN_DEBUG "olpm-pm: PM_PWRBTN %sevent received\n",
689 + sts & CS5536_PM_WAK ? "wakeup " : "");
690 + if (!(sts & CS5536_PM_WAK)) {
691 + input_report_key(pm_inputdev, KEY_POWER, 1);
692 + input_sync(pm_inputdev);
693 + /* Do we need to delay this? */
694 + input_report_key(pm_inputdev, KEY_POWER, 0);
695 + input_sync(pm_inputdev);
696 + }
697 + }
698 +
699 + if (gpe & GPIO_WAKEUP_EC) {
700 + geode_gpio_clear(OLPC_GPIO_ECSCI, GPIO_NEGATIVE_EDGE_STS);
701 + if (!wackup_source)
702 + wackup_source = "sci";
703 + schedule_work(&sci_work);
704 + }
705 +
706 + if (gpe & GPIO_WAKEUP_LID) {
707 + /* Disable events */
708 + geode_gpio_clear(OLPC_GPIO_LID, GPIO_EVENTS_ENABLE);
709 +
710 + /* Clear the edge */
711 +
712 + if (olpc_lid_flag)
713 + geode_gpio_clear(OLPC_GPIO_LID, GPIO_NEGATIVE_EDGE_EN);
714 + else
715 + geode_gpio_clear(OLPC_GPIO_LID, GPIO_POSITIVE_EDGE_EN);
716 +
717 + /* Clear the status too */
718 + geode_gpio_set(OLPC_GPIO_LID, GPIO_NEGATIVE_EDGE_STS);
719 + geode_gpio_set(OLPC_GPIO_LID, GPIO_POSITIVE_EDGE_STS);
720 +
721 + /* The line is high when the LID is open, but SW_LID
722 + * should be high when the LID is closed, so we pass the old
723 + * value of olpc_lid_flag
724 + */
725 +
726 + input_report_switch(lid_inputdev, SW_LID, olpc_lid_flag);
727 + input_sync(lid_inputdev);
728 + if (!wackup_source)
729 + wackup_source = "lid";
730 +
731 + /* Swap the status */
732 + olpc_lid_flag = !olpc_lid_flag;
733 +
734 + if (olpc_lid_flag)
735 + geode_gpio_set(OLPC_GPIO_LID, GPIO_NEGATIVE_EDGE_EN);
736 + else
737 + geode_gpio_set(OLPC_GPIO_LID, GPIO_POSITIVE_EDGE_EN);
738 +
739 + /* re-enable the event */
740 + geode_gpio_set(OLPC_GPIO_LID, GPIO_EVENTS_ENABLE);
741 + }
742 +
743 + return IRQ_HANDLED;
744 +}
745 +
746 +int olpc_ec_mask_set(u8 bits)
747 +{
748 + int ret;
749 + u8 byte;
750 +
751 + ret = olpc_ec_cmd(EC_READ_SCI_MASK, NULL, 0, &byte, 1);
752 + if (ret) {
753 + printk(KERN_ERR "olpc-pm: error getting SCI mask: %d\n", ret);
754 + return ret;
755 + }
756 + /* the high bit is unused, if it is ever unset, that is a good sign
757 + sign of EC communication corruption! */
758 + WARN_ON(!(byte & 0x80));
759 +
760 + byte |= bits;
761 + ret = olpc_ec_cmd(EC_WRITE_SCI_MASK, &byte, 1, NULL, 0);
762 + if (ret)
763 + printk(KERN_ERR "olpc-pm: error setting SCI mask: %d\n", ret);
764 +
765 + return ret;
766 +}
767 +EXPORT_SYMBOL_GPL(olpc_ec_mask_set);
768 +
769 +int olpc_ec_mask_unset(u8 bits)
770 +{
771 + int ret;
772 + u8 byte;
773 +
774 + ret = olpc_ec_cmd(EC_READ_SCI_MASK, NULL, 0, &byte, 1);
775 + if (ret) {
776 + printk(KERN_ERR "olpc-pm: error getting SCI mask: %d\n", ret);
777 + return ret;
778 + }
779 + /* the high bit is unused, if it is ever unset, that is a good sign
780 + sign of EC communication corruption! */
781 + WARN_ON(!(byte & 0x80));
782 +
783 + byte &= ~bits;
784 + ret = olpc_ec_cmd(EC_WRITE_SCI_MASK, &byte, 1, NULL, 0);
785 + if (ret)
786 + printk(KERN_ERR "olpc-pm: error setting SCI mask: %d\n", ret);
787 +
788 + return ret;
789 +}
790 +EXPORT_SYMBOL_GPL(olpc_ec_mask_unset);
791 +
792 +/*
793 + * For now, only support STR. We also don't support suspending on
794 + * B1s, due to difficulties with the cafe FPGA.
795 + */
796 +static int olpc_pm_state_valid(suspend_state_t pm_state)
797 +{
798 + if (pm_state == PM_SUSPEND_MEM && olpc_board_at_least(olpc_board(0xb2)))
799 + return 1;
800 +
801 + return 0;
802 +}
803 +
804 +/* This is a catchall function for operations that just don't belong
805 + * anywhere else. Later we will evaluate if these belong in the
806 + * individual device drivers or the firmware.
807 + * If you add something to this function, please explain yourself with
808 + * a comment.
809 + */
810 +
811 +extern void gxfb_flatpanel_control(int state);
812 +
813 +static u32 gpio_wakeup[2];
814 +static u64 irq_sources[4];
815 +static u64 mfgpt_irq_msr, mfgpt_nr_msr;
816 +
817 +void olpc_fixup_wakeup(void)
818 +{
819 + u32 base = geode_gpio_base();
820 + int i;
821 +
822 + /* Enable the flatpanel sequencing as early as possible, because
823 + it takes ~64ms to resume. This probably belongs in the firmware */
824 +
825 + //gxfb_flatpanel_control(1);
826 +
827 + /* Tell the EC to stop inhibiting SCIs */
828 + olpc_ec_cmd(0x34, NULL, 0, NULL, 0);
829 +
830 + /* Restore the interrupt sources */
831 + wrmsrl(MSR_PIC_YSEL_LOW, irq_sources[0]);
832 + wrmsrl(MSR_PIC_ZSEL_LOW, irq_sources[1]);
833 + wrmsrl(MSR_PIC_YSEL_HIGH, irq_sources[2]);
834 + wrmsrl(MSR_PIC_ZSEL_HIGH, irq_sources[3]);
835 +
836 + /* Restore the X and Y sources for GPIO */
837 + outl(gpio_wakeup[0], base + GPIO_MAP_X);
838 + outl(gpio_wakeup[1], base + GPIO_MAP_Y);
839 +
840 + /* Resture the MFGPT MSRs */
841 + wrmsrl(MFGPT_IRQ_MSR, mfgpt_irq_msr);
842 + wrmsrl(MFGPT_NR_MSR, mfgpt_nr_msr);
843 +
844 + for (i=0;i<2;i++) {
845 + /* tell the wireless module to restart USB communication */
846 + olpc_ec_cmd(0x24, NULL, 0, NULL, 0);
847 + }
848 +
849 + /* Turn all events on */
850 + olpc_ec_mask_set(EC_SCI_SRC_ALL);
851 +}
852 +
853 +void olpc_fixup_sleep(void)
854 +{
855 + u32 base = geode_gpio_base();
856 + int i;
857 +
858 + /* Save the X and Y sources for GPIO */
859 + gpio_wakeup[0] = inl(base + GPIO_MAP_X);
860 + gpio_wakeup[1] = inl(base + GPIO_MAP_Y);
861 +
862 + /* Save the Y and Z unrestricted sources */
863 +
864 + rdmsrl(MSR_PIC_YSEL_LOW, irq_sources[0]);
865 + rdmsrl(MSR_PIC_ZSEL_LOW, irq_sources[1]);
866 + rdmsrl(MSR_PIC_YSEL_HIGH, irq_sources[2]);
867 + rdmsrl(MSR_PIC_ZSEL_HIGH, irq_sources[3]);
868 +
869 + /* Turn off the MFGPT timers on the way down */
870 +
871 + for(i = 0; i < 8; i++) {
872 + u32 val = geode_mfgpt_read(i, MFGPT_REG_SETUP);
873 +
874 + if (val & MFGPT_SETUP_SETUP) {
875 + val &= ~MFGPT_SETUP_CNTEN;
876 + geode_mfgpt_write(i, MFGPT_REG_SETUP, val);
877 + }
878 + }
879 +
880 + /* Save the MFGPT MSRs */
881 + rdmsrl(MFGPT_IRQ_MSR, mfgpt_irq_msr);
882 + rdmsrl(MFGPT_NR_MSR, mfgpt_nr_msr);
883 +
884 + if (device_may_wakeup(&olpc_powerbutton_dev.dev))
885 + olpc_wakeup_mask |= CS5536_PM_PWRBTN;
886 + else
887 + olpc_wakeup_mask &= ~(CS5536_PM_PWRBTN);
888 +
889 + if (device_may_wakeup(&olpc_lid_dev.dev)) {
890 + geode_gpio_set(OLPC_GPIO_LID, GPIO_EVENTS_ENABLE);
891 + gpio_wake_events |= GPIO_WAKEUP_LID;
892 + } else {
893 + geode_gpio_clear(OLPC_GPIO_LID, GPIO_EVENTS_ENABLE);
894 + gpio_wake_events &= ~(GPIO_WAKEUP_LID);
895 + }
896 +
897 + /* We don't want to wake up on superfluous events */
898 + olpc_ec_mask_unset(EC_SCI_SRC_BATSOC | EC_SCI_SRC_ACPWR);
899 +
900 + /*
901 + * Cmd 0x32 tells the EC that we're going into suspend; this was
902 + * added to work around hardware races related to SCI events. This
903 + * should cause the EC to inhibit further SCIs while MAIN_ON is
904 + * transitioning low.
905 + *
906 + * There's also some sort of EC race whereby the EC gets its
907 + * IBF/OBF flags confused and all future communication (after
908 + * resuming) fails if we suspend too soon after updating
909 + * the EC SCI mask. Having this command after updating the
910 + * SCI mask allows the EC enough time to finish doing what it's
911 + * doing.
912 + */
913 + olpc_ec_cmd(0x32, NULL, 0, NULL, 0);
914 +}
915 +
916 +static int olpc_pm_enter(suspend_state_t pm_state)
917 +{
918 + /* Only STR is supported */
919 + if (pm_state != PM_SUSPEND_MEM)
920 + return -EINVAL;
921 +
922 + olpc_fixup_sleep();
923 +
924 + /* Set the GPIO wakeup bits */
925 + outl(gpio_wake_events, acpi_base + PM_GPE0_EN);
926 + outl(0xFFFFFFFF, acpi_base + PM_GPE0_STS);
927 +
928 + /* Save CPU state */
929 + do_olpc_suspend_lowlevel();
930 +
931 + olpc_fixup_wakeup();
932 +
933 + /* Restore the SCI wakeup events */
934 + outl(gpio_wake_events, acpi_base + PM_GPE0_EN);
935 +
936 + return 0;
937 +}
938 +
939 +int asmlinkage olpc_do_sleep(u8 sleep_state)
940 +{
941 + void *pgd_addr = __va(read_cr3());
942 + printk(KERN_ERR "olpc_do_sleep!\n"); /* this needs to remain here so
943 + * that gcc doesn't optimize
944 + * away our __va! */
945 + /* FIXME: Set the SCI bits we want to wake up on here */
946 +
947 + /* FIXME: Set any other SCI events that we might want here */
948 +
949 + outl((olpc_wakeup_mask << 16) | 0xFFFF, acpi_base + PM1_STS);
950 +
951 + wackup_source = NULL;
952 +
953 + /* If we are in test mode, then just return (simulate a successful
954 + suspend/resume). Otherwise, if we are doing the real thing,
955 + then go for the gusto */
956 +
957 + if (olpc_pm_mode != PM_MODE_TEST) {
958 + __asm__ __volatile__("movl %0,%%eax" : : "r" (pgd_addr));
959 + __asm__("call *(%%edi); cld"
960 + : : "D" (&ofw_bios_entry));
961 + __asm__ __volatile__("movb $0x34, %al\n\t"
962 + "outb %al, $0x70\n\t"
963 + "movb $0x30, %al\n\t"
964 + "outb %al, $0x71\n\t");
965 +
966 + }
967 + else if (test_timeout > 0) {
968 + int t;
969 +
970 + /* Delay N seconds for testing purposes */
971 +
972 + for(t = 0; t < test_timeout; t++)
973 + mdelay(1000);
974 + }
975 +
976 + return 0;
977 +}
978 +
979 +static void olpc_power_off(void)
980 +{
981 + printk(KERN_INFO "OLPC power off sequence...\n");
982 +
983 + /* Enable all of these controls with 0 delay */
984 + outl(0x40000000, pms_base + PM_SCLK);
985 + outl(0x40000000, pms_base + PM_IN_SLPCTL);
986 + outl(0x40000000, pms_base + PM_WKXD);
987 + outl(0x40000000, pms_base + PM_WKD);
988 +
989 + /* Clear status bits (possibly unnecessary) */
990 + outl(0x0002ffff, pms_base + PM_SSC);
991 + outl(0xffffffff, acpi_base + PM_GPE0_STS);
992 +
993 + /* Write SLP_EN bit to start the machinery */
994 + outl(0x00002000, acpi_base + PM1_CNT);
995 +}
996 +
997 +/* This code will slowly disappear as we fixup the issues in the BIOS */
998 +
999 +static void __init olpc_fixup_bios(void)
1000 +{
1001 + unsigned long hi, lo;
1002 +
1003 + if (olpc_has_vsa()) {
1004 + /* The VSA aggressively sets up the ACPI and PM register for
1005 + * trapping - its not enough to force these values in the BIOS -
1006 + * they seem to be changed during PCI init as well.
1007 + */
1008 +
1009 + /* Change the PM registers to decode to the DD */
1010 +
1011 + rdmsr(0x510100e2, lo, hi);
1012 + hi |= 0x80000000;
1013 + wrmsr(0x510100e2, lo, hi);
1014 +
1015 + /* Change the ACPI registers to decode to the DD */
1016 +
1017 + rdmsr(0x510100e3, lo, hi);
1018 + hi |= 0x80000000;
1019 + wrmsr(0x510100e3, lo, hi);
1020 + }
1021 +
1022 + /* GPIO24 controls WORK_AUX */
1023 +
1024 + geode_gpio_set(OLPC_GPIO_WORKAUX, GPIO_OUTPUT_ENABLE);
1025 + geode_gpio_set(OLPC_GPIO_WORKAUX, GPIO_OUTPUT_AUX1);
1026 +
1027 + if (olpc_board_at_least(olpc_board(0xb2))) {
1028 + /* GPIO10 is connected to the thermal alarm */
1029 + geode_gpio_set(OLPC_GPIO_THRM_ALRM, GPIO_INPUT_ENABLE);
1030 + geode_gpio_set(OLPC_GPIO_THRM_ALRM, GPIO_INPUT_AUX1);
1031 +
1032 + /* Set up to get LID events */
1033 + geode_gpio_set(OLPC_GPIO_LID, GPIO_INPUT_ENABLE);
1034 +
1035 + /* Clear edge detection and event enable for now */
1036 + geode_gpio_clear(OLPC_GPIO_LID, GPIO_EVENTS_ENABLE);
1037 + geode_gpio_clear(OLPC_GPIO_LID, GPIO_NEGATIVE_EDGE_EN);
1038 + geode_gpio_clear(OLPC_GPIO_LID, GPIO_POSITIVE_EDGE_EN);
1039 +
1040 + geode_gpio_set(OLPC_GPIO_LID, GPIO_NEGATIVE_EDGE_STS);
1041 + geode_gpio_set(OLPC_GPIO_LID, GPIO_POSITIVE_EDGE_STS);
1042 +
1043 + /* Set the LID to cause an PME event on group 6 */
1044 + geode_gpio_event_pme(OLPC_GPIO_LID, 6);
1045 +
1046 + /* Set PME group 6 to fire the SCI interrupt */
1047 + geode_gpio_set_irq(6, sci_irq);
1048 + }
1049 +
1050 + geode_gpio_set(OLPC_GPIO_ECSCI, GPIO_INPUT_ENABLE);
1051 +
1052 + /* Clear pending events */
1053 +
1054 + geode_gpio_set(OLPC_GPIO_ECSCI, GPIO_NEGATIVE_EDGE_STS);
1055 + geode_gpio_set(OLPC_GPIO_ECSCI, GPIO_POSITIVE_EDGE_STS);
1056 +
1057 + //geode_gpio_set(OLPC_GPIO_ECSCI, GPIO_NEGATIVE_EDGE_EN);
1058 + geode_gpio_set(OLPC_GPIO_ECSCI, GPIO_EVENTS_ENABLE);
1059 +
1060 + /* Set the SCI to cause a PME event on group 7 */
1061 + geode_gpio_event_pme(OLPC_GPIO_ECSCI, 7);
1062 +
1063 + /* And have group 6 also fire the SCI interrupt */
1064 + geode_gpio_set_irq(7, sci_irq);
1065 +}
1066 +
1067 +/* This provides a control file for setting up testing of the
1068 + power management system. For now, there is just one setting:
1069 + "test" which means that we don't actually enter the power
1070 + off routine.
1071 +*/
1072 +
1073 +static const char * const pm_states[] = {
1074 + [PM_MODE_NORMAL] = "normal",
1075 + [PM_MODE_TEST] = "test",
1076 +};
1077 +
1078 +extern struct mutex pm_mutex;
1079 +extern struct kset power_subsys;
1080 +
1081 +static ssize_t control_show(struct kset *s, char *buf)
1082 +{
1083 + return sprintf(buf, "%s\n", pm_states[olpc_pm_mode]);
1084 +}
1085 +
1086 +static ssize_t control_store(struct kset *s, const char *buf, size_t n)
1087 +{
1088 + int i, len;
1089 + char *p;
1090 +
1091 + p = memchr(buf, '\n', n);
1092 + len = p ? p - buf : n;
1093 +
1094 + /* Grab the mutex */
1095 + mutex_lock(&pm_mutex);
1096 +
1097 + for(i = 0; i < PM_MODE_MAX; i++) {
1098 + if (!strncmp(buf, pm_states[i], len)) {
1099 + olpc_pm_mode = i;
1100 + break;
1101 + }
1102 + }
1103 +
1104 + mutex_unlock(&pm_mutex);
1105 +
1106 + return (i == PM_MODE_MAX) ? -EINVAL : n;
1107 +}
1108 +
1109 +static ssize_t timeout_show(struct kset *s, char *buf)
1110 +{
1111 + return sprintf(buf, "%d\n", test_timeout);
1112 +}
1113 +
1114 +static ssize_t timeout_store(struct kset *s, const char *buf, size_t n)
1115 +{
1116 + unsigned int t = simple_strtoul(buf, NULL, 0);
1117 + test_timeout = t;
1118 +
1119 + return n;
1120 +}
1121 +
1122 +static ssize_t wackup_show(struct kset *s, char *buf)
1123 +{
1124 + return sprintf(buf, "%s\n", wackup_source ? wackup_source : "none");
1125 +}
1126 +
1127 +static struct subsys_attribute control_attr = {
1128 + .attr = {
1129 + .name = "olpc-pm",
1130 + .mode = 0644,
1131 + },
1132 + .show = control_show,
1133 + .store = control_store,
1134 +};
1135 +
1136 +static struct subsys_attribute test_attr = {
1137 + .attr = {
1138 + .name = "test-timeout",
1139 + .mode = 0644,
1140 + },
1141 + .show = timeout_show,
1142 + .store = timeout_store,
1143 +};
1144 +
1145 +static struct subsys_attribute wackup_attr = {
1146 + .attr = {
1147 + .name = "wakeup-source",
1148 + .mode = 0400,
1149 + },
1150 + .show = wackup_show,
1151 +};
1152 +
1153 +static struct attribute * olpc_attributes[] = {
1154 + &control_attr.attr,
1155 + &test_attr.attr,
1156 + &wackup_attr.attr,
1157 + NULL
1158 +};
1159 +
1160 +static struct attribute_group olpc_attrs = {
1161 + .attrs = olpc_attributes,
1162 +};
1163 +
1164 +static int __init alloc_inputdevs(void)
1165 +{
1166 + int ret = -ENOMEM;
1167 +
1168 + pm_inputdev = input_allocate_device();
1169 + if (!pm_inputdev)
1170 + goto err;
1171 +
1172 + pm_inputdev->name = "OLPC PM";
1173 + pm_inputdev->phys = "olpc_pm/input0";
1174 + set_bit(EV_KEY, pm_inputdev->evbit);
1175 + set_bit(KEY_POWER, pm_inputdev->keybit);
1176 +
1177 + ret = input_register_device(pm_inputdev);
1178 + if (ret) {
1179 + printk(KERN_ERR "olpc-pm: failed to register PM input device: %d\n", ret);
1180 + goto err;
1181 + }
1182 +
1183 + lid_inputdev = input_allocate_device();
1184 + if (!lid_inputdev)
1185 + goto err;
1186 +
1187 + lid_inputdev->name = "OLPC lid switch";
1188 + lid_inputdev->phys = "olpc_pm/input1";
1189 + set_bit(EV_SW, lid_inputdev->evbit);
1190 + set_bit(SW_LID, lid_inputdev->swbit);
1191 +
1192 + ret = input_register_device(lid_inputdev);
1193 + if (ret) {
1194 + printk(KERN_ERR "olpc-pm: failed to register lid input device: %d\n", ret);
1195 + goto err;
1196 + }
1197 +
1198 + ebook_inputdev = input_allocate_device();
1199 + if (!ebook_inputdev)
1200 + goto err;
1201 +
1202 + ebook_inputdev->name = "OLPC ebook switch";
1203 + ebook_inputdev->phys = "olpc_pm/input2";
1204 + set_bit(EV_SW, ebook_inputdev->evbit);
1205 + set_bit(SW_TABLET_MODE, ebook_inputdev->swbit);
1206 +
1207 + ret = input_register_device(ebook_inputdev);
1208 + if (ret) {
1209 + printk(KERN_ERR "olpc-pm: failed to register ebook input device: %d\n", ret);
1210 + goto err;
1211 + }
1212 +
1213 + return ret;
1214 +err:
1215 + if (ebook_inputdev) {
1216 + input_unregister_device(ebook_inputdev);
1217 + ebook_inputdev = NULL;
1218 + }
1219 + if (lid_inputdev) {
1220 + input_unregister_device(lid_inputdev);
1221 + lid_inputdev = NULL;
1222 + }
1223 + if (pm_inputdev) {
1224 + input_unregister_device(pm_inputdev);
1225 + pm_inputdev = NULL;
1226 + }
1227 +
1228 + return ret;
1229 +}
1230 +
1231 +static int __init olpc_pm_init(void)
1232 +{
1233 + uint32_t lo, hi;
1234 + int ret;
1235 +
1236 + if (!machine_is_olpc())
1237 + return -ENODEV;
1238 +
1239 + acpi_base = geode_acpi_base();
1240 + pms_base = geode_pms_base();
1241 +
1242 + if (!acpi_base || !pms_base)
1243 + return -ENODEV;
1244 +
1245 + pm_power_off = olpc_power_off;
1246 +
1247 + ret = alloc_inputdevs();
1248 + if (ret)
1249 + return ret;
1250 +
1251 + rdmsr(0x51400020, lo, hi);
1252 + sci_irq = (lo >> 20) & 15;
1253 +
1254 + if (sci_irq) {
1255 + printk(KERN_INFO "SCI is mapped to IRQ %d\n", sci_irq);
1256 + } else {
1257 + /* Zero doesn't mean zero -- it means masked */
1258 + printk(KERN_INFO "SCI unmapped. Mapping to IRQ 3\n");
1259 + sci_irq = 3;
1260 + lo |= 0x00300000;
1261 + wrmsrl(0x51400020, lo);
1262 + }
1263 +
1264 + olpc_fixup_bios();
1265 +
1266 + lo = inl(pms_base + PM_FSD);
1267 +
1268 + /* Lock, enable failsafe, 4 seconds */
1269 + outl(0xc001f400, pms_base + PM_FSD);
1270 +
1271 + /* Here we set up the SCI events we're interested in during
1272 + * real-time. We have no sleep button, and the RTC doesn't make
1273 + * sense, so set up the power button
1274 + */
1275 +
1276 + outl(inl(acpi_base) | ((CS5536_PM_PWRBTN) << 16), acpi_base);
1277 +
1278 + if (olpc_board_at_least(olpc_board(0xb2))) {
1279 + gpio_wake_events |= GPIO_WAKEUP_LID;
1280 +
1281 + /* Get the current value of the GPIO, and set up the edges */
1282 + olpc_lid_flag = geode_gpio_isset(OLPC_GPIO_LID, GPIO_READ_BACK);
1283 +
1284 + /* Watch for the opposite edge */
1285 +
1286 + if (olpc_lid_flag)
1287 + geode_gpio_set(OLPC_GPIO_LID, GPIO_NEGATIVE_EDGE_EN);
1288 + else
1289 + geode_gpio_set(OLPC_GPIO_LID, GPIO_POSITIVE_EDGE_EN);
1290 +
1291 + /* Enable the event */
1292 + geode_gpio_set(OLPC_GPIO_LID, GPIO_EVENTS_ENABLE);
1293 + }
1294 +
1295 + /* Set up the EC SCI */
1296 +
1297 + gpio_wake_events |= GPIO_WAKEUP_EC;
1298 +
1299 + outl(gpio_wake_events, acpi_base + PM_GPE0_EN);
1300 + outl(0xFFFFFFFF, acpi_base + PM_GPE0_STS);
1301 +
1302 + /* Select level triggered in PIC */
1303 +
1304 + if (sci_irq < 8) {
1305 + lo = inb(0x4d0);
1306 + lo |= 1 << sci_irq;
1307 + outb(lo, 0x4d0);
1308 + } else {
1309 + lo = inb(0x4d1);
1310 + lo |= 1 << (sci_irq - 8);
1311 + outb(lo, 0x4d1);
1312 + }
1313 + /* Clear pending interrupt */
1314 + outl(inl(acpi_base) | 0xFFFF, acpi_base);
1315 + process_sci_queue(0); /* we just want to flush the queue here */
1316 + init_ebook_state();
1317 +
1318 + /* Enable the interrupt */
1319 +
1320 + ret = request_irq(sci_irq, &olpc_pm_interrupt, 0, "SCI", &acpi_base);
1321 +
1322 + if (ret) {
1323 + printk(KERN_ERR "Error registering SCI: %d\n", ret);
1324 + return ret;
1325 + }
1326 +
1327 + ofw_bios_entry.address = 0xF0000 + PAGE_OFFSET;
1328 + suspend_set_ops(&olpc_pm_ops);
1329 +
1330 + sysfs_create_group(&power_subsys.kobj, &olpc_attrs);
1331 +
1332 + return 0;
1333 +}
1334 +
1335 +
1336 +#if defined (CONFIG_RTC_DRV_CMOS) || defined (CONFIG_RTC_DRV_CMOS_MODULE)
1337 +struct resource rtc_platform_resource[2] = {
1338 + {
1339 + .flags = IORESOURCE_IO,
1340 + .start = RTC_PORT(0),
1341 + .end = RTC_PORT(0) + RTC_IO_EXTENT
1342 + },
1343 + {
1344 + .flags = IORESOURCE_IRQ,
1345 + .start = 8,
1346 + .end = 8,
1347 + },
1348 +};
1349 +
1350 +
1351 +static void rtc_wake_on(struct device *dev)
1352 +{
1353 + olpc_wakeup_mask |= CS5536_PM_RTC;
1354 +}
1355 +
1356 +static void rtc_wake_off(struct device *dev)
1357 +{
1358 + olpc_wakeup_mask &= ~(CS5536_PM_RTC);
1359 +}
1360 +
1361 +static struct cmos_rtc_board_info rtc_info = {
1362 + .rtc_day_alarm = 0,
1363 + .rtc_mon_alarm = 0,
1364 + .rtc_century = 0,
1365 + .wake_on = rtc_wake_on,
1366 + .wake_off = rtc_wake_off,
1367 +};
1368 +
1369 +struct platform_device olpc_rtc_device = {
1370 + .name = "rtc_cmos",
1371 + .id = -1,
1372 + .num_resources = ARRAY_SIZE(rtc_platform_resource),
1373 + .dev.platform_data = &rtc_info,
1374 + .resource = rtc_platform_resource,
1375 +};
1376 +
1377 +static int __init olpc_platform_init(void)
1378 +{
1379 + rdmsrl(MSR_RTC_DOMA_OFFSET, rtc_info.rtc_day_alarm);
1380 + rdmsrl(MSR_RTC_MONA_OFFSET, rtc_info.rtc_mon_alarm);
1381 + rdmsrl(MSR_RTC_CEN_OFFSET, rtc_info.rtc_century);
1382 +
1383 + (void)platform_device_register(&olpc_rtc_device);
1384 + device_init_wakeup(&olpc_rtc_device.dev, 1);
1385 +
1386 + (void)platform_device_register(&olpc_powerbutton_dev);
1387 + device_init_wakeup(&olpc_powerbutton_dev.dev, 1);
1388 +
1389 + (void)platform_device_register(&olpc_lid_dev);
1390 + device_init_wakeup(&olpc_lid_dev.dev, 1);
1391 +
1392 + return 0;
1393 +}
1394 +arch_initcall(olpc_platform_init);
1395 +#endif /* CONFIG_RTC_DRV_CMOS */
1396 +
1397 +static void olpc_pm_exit(void)
1398 +{
1399 + /* Clear any pending events, and disable them */
1400 + outl(0xFFFF, acpi_base+2);
1401 +
1402 + free_irq(sci_irq, &acpi_base);
1403 + input_unregister_device(pm_inputdev);
1404 + input_unregister_device(lid_inputdev);
1405 + input_unregister_device(ebook_inputdev);
1406 +}
1407 +
1408 +static struct platform_suspend_ops olpc_pm_ops = {
1409 + .valid = olpc_pm_state_valid,
1410 + .enter = olpc_pm_enter,
1411 +};
1412 +
1413 +module_init(olpc_pm_init);
1414 +module_exit(olpc_pm_exit);
1415 +
1416 +MODULE_LICENSE("GPL");
1417 +MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
1418 +MODULE_DESCRIPTION("AMD Geode power management for OLPC CL1");
1419 diff -purN linux_2.6.24_org/arch/x86/kernel/olpc-sleep.S linux_2.6.24_olpc/arch/x86/kernel/olpc-sleep.S
1420 --- linux_2.6.24_org/arch/x86/kernel/olpc-sleep.S 1970-01-01 01:00:00.000000000 +0100
1421 +++ linux_2.6.24_olpc/arch/x86/kernel/olpc-sleep.S 2008-02-15 18:59:26.000000000 +0000
1422 @@ -0,0 +1,39 @@
1423 +.text
1424 +
1425 +ENTRY(olpc_sleep_asm)
1426 +olpc_sleep:
1427 + ;; Get the value of PM1_CNT and store it off
1428 +
1429 + add 08h, ax
1430 + mov bx,dx
1431 + in dx,eax
1432 + or 2000h, ax
1433 + mov ax,di
1434 +
1435 + ;; flush the cache
1436 + wbinvd
1437 +
1438 + ;; GX2 must disable refresh before going into self-refresh
1439 + mov 2000000180xh, ecx
1440 + rdmsr
1441 + mov eax, esi
1442 + and 0FF0000FFh, eax
1443 + wrmsr
1444 +
1445 + ;; Now, put the memory into self refresh
1446 + mov 2004, cx
1447 + xor edx, edx
1448 + xor eax, eax
1449 + mov 04h, al
1450 + wrmsr
1451 +
1452 + ;; Thats all she wrote - time to go to sleep
1453 +
1454 + mov bx, dx
1455 + movzx di, eax
1456 + out eax, dx
1457 +
1458 + ;;
1459 +
1460 +
1461 +
1462 diff -purN linux_2.6.24_org/arch/x86/kernel/olpc-wakeup.S linux_2.6.24_olpc/arch/x86/kernel/olpc-wakeup.S
1463 --- linux_2.6.24_org/arch/x86/kernel/olpc-wakeup.S 1970-01-01 01:00:00.000000000 +0100
1464 +++ linux_2.6.24_olpc/arch/x86/kernel/olpc-wakeup.S 2008-02-15 18:59:25.000000000 +0000
1465 @@ -0,0 +1,133 @@
1466 +.text
1467 +#include <linux/linkage.h>
1468 +#include <asm/segment.h>
1469 +#include <asm/page.h>
1470 +
1471 + .macro writepost,value
1472 + movb $0x34, %al
1473 + outb %al, $0x70
1474 + movb $\value, %al
1475 + outb %al, $0x71
1476 + .endm
1477 +
1478 +ALIGN
1479 + .align 4096
1480 +
1481 +wakeup_start:
1482 +# jmp wakeup_start
1483 +
1484 + cli
1485 + cld
1486 +
1487 + # Clear any dangerous flags
1488 +
1489 + pushl $0
1490 + popfl
1491 +
1492 + writepost 0x31
1493 +
1494 + # Set up %cr3
1495 + movl $swsusp_pg_dir - __PAGE_OFFSET, %eax
1496 + movl %eax, %cr3
1497 +
1498 + movl saved_cr4, %eax
1499 + movl %eax, %cr4
1500 +
1501 + movl saved_cr0, %eax
1502 + movl %eax, %cr0
1503 +
1504 + jmp 1f
1505 +1:
1506 + ljmpl $__KERNEL_CS,$wakeup_return
1507 +
1508 +
1509 +.org 0x1000
1510 +
1511 +wakeup_return:
1512 + movw $__KERNEL_DS, %ax
1513 + movw %ax, %ss
1514 + movw %ax, %ds
1515 + movw %ax, %es
1516 + movw %ax, %fs
1517 + movw %ax, %gs
1518 +
1519 + lgdt saved_gdt
1520 + lidt saved_idt
1521 + lldt saved_ldt
1522 + ljmp $(__KERNEL_CS),$1f
1523 +1:
1524 + movl %cr3, %eax
1525 + movl %eax, %cr3
1526 + wbinvd
1527 +
1528 + # Go back to the return point
1529 + jmp ret_point
1530 +
1531 +save_registers:
1532 + sgdt saved_gdt
1533 + sidt saved_idt
1534 + sldt saved_ldt
1535 +
1536 + pushl %edx
1537 + movl %cr4, %edx
1538 + movl %edx, saved_cr4
1539 +
1540 + movl %cr0, %edx
1541 + movl %edx, saved_cr0
1542 +
1543 + popl %edx
1544 +
1545 +
1546 + movl %ebx, saved_context_ebx
1547 + movl %ebp, saved_context_ebp
1548 + movl %esi, saved_context_esi
1549 + movl %edi, saved_context_edi
1550 +
1551 + pushfl
1552 + popl saved_context_eflags
1553 +
1554 + ret
1555 +
1556 +
1557 +restore_registers:
1558 + movl saved_context_ebp, %ebp
1559 + movl saved_context_ebx, %ebx
1560 + movl saved_context_esi, %esi
1561 + movl saved_context_edi, %edi
1562 +
1563 + pushl saved_context_eflags
1564 + popfl
1565 +
1566 + ret
1567 +
1568 +
1569 +ENTRY(do_olpc_suspend_lowlevel)
1570 + call save_processor_state
1571 + call save_registers
1572 +
1573 + # This is the stack context we want to remember
1574 + movl %esp, saved_context_esp
1575 +
1576 + pushl $3
1577 + call olpc_do_sleep
1578 +
1579 + jmp wakeup_start
1580 + .p2align 4,,7
1581 +ret_point:
1582 + movl saved_context_esp, %esp
1583 +
1584 + writepost 0x32
1585 +
1586 + call restore_registers
1587 + call restore_processor_state
1588 + ret
1589 +
1590 +.data
1591 +ALIGN
1592 +
1593 +saved_gdt: .long 0,0
1594 +saved_idt: .long 0,0
1595 +saved_ldt: .long 0
1596 +saved_cr4: .long 0
1597 +saved_cr0: .long 0
1598 +
1599 diff -purN linux_2.6.24_org/arch/x86/kernel/prom.c linux_2.6.24_olpc/arch/x86/kernel/prom.c
1600 --- linux_2.6.24_org/arch/x86/kernel/prom.c 1970-01-01 01:00:00.000000000 +0100
1601 +++ linux_2.6.24_olpc/arch/x86/kernel/prom.c 2008-02-15 18:59:26.000000000 +0000
1602 @@ -0,0 +1,478 @@
1603 +/*
1604 + * Procedures for creating, accessing and interpreting the device tree.
1605 + *
1606 + * Paul Mackerras August 1996.
1607 + * Copyright (C) 1996-2005 Paul Mackerras.
1608 + *
1609 + * Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
1610 + * {engebret|bergner}@us.ibm.com
1611 + *
1612 + * Adapted for sparc64 by David S. Miller davem@davemloft.net
1613 + *
1614 + * Adapter for i386/OLPC by Andres Salomon <dilinger@debian.org>
1615 + *
1616 + * This program is free software; you can redistribute it and/or
1617 + * modify it under the terms of the GNU General Public License
1618 + * as published by the Free Software Foundation; either version
1619 + * 2 of the License, or (at your option) any later version.
1620 + */
1621 +
1622 +#include <linux/kernel.h>
1623 +#include <linux/types.h>
1624 +#include <linux/string.h>
1625 +#include <linux/mm.h>
1626 +#include <linux/bootmem.h>
1627 +#include <linux/module.h>
1628 +#include <asm/prom.h>
1629 +#include <asm/ofw.h>
1630 +
1631 +/*
1632 + * XXX: This is very much a stub; right now we're keeping 2 device trees
1633 + * in memory (one for promfs, and one here). That will not remain
1634 + * for long!
1635 + */
1636 +
1637 +static struct device_node *allnodes;
1638 +
1639 +/* use when traversing tree through the allnext, child, sibling,
1640 + * or parent members of struct device_node.
1641 + */
1642 +static DEFINE_RWLOCK(devtree_lock);
1643 +
1644 +int of_device_is_compatible(const struct device_node *device,
1645 + const char *compat)
1646 +{
1647 + const char* cp;
1648 + int cplen, l;
1649 +
1650 + cp = of_get_property(device, "compatible", &cplen);
1651 + if (cp == NULL)
1652 + return 0;
1653 + while (cplen > 0) {
1654 + if (strncmp(cp, compat, strlen(compat)) == 0)
1655 + return 1;
1656 + l = strlen(cp) + 1;
1657 + cp += l;
1658 + cplen -= l;
1659 + }
1660 +
1661 + return 0;
1662 +}
1663 +EXPORT_SYMBOL(of_device_is_compatible);
1664 +
1665 +struct device_node *of_get_parent(const struct device_node *node)
1666 +{
1667 + struct device_node *np;
1668 +
1669 + if (!node)
1670 + return NULL;
1671 +
1672 + np = node->parent;
1673 +
1674 + return np;
1675 +}
1676 +EXPORT_SYMBOL(of_get_parent);
1677 +
1678 +struct device_node *of_get_next_child(const struct device_node *node,
1679 + struct device_node *prev)
1680 +{
1681 + struct device_node *next;
1682 +
1683 + next = prev ? prev->sibling : node->child;
1684 + for (; next != 0; next = next->sibling) {
1685 + break;
1686 + }
1687 +
1688 + return next;
1689 +}
1690 +EXPORT_SYMBOL(of_get_next_child);
1691 +
1692 +struct device_node *of_find_node_by_path(const char *path)
1693 +{
1694 + struct device_node *np = allnodes;
1695 +
1696 + for (; np != 0; np = np->allnext) {
1697 + if (np->full_name != 0 && strcmp(np->full_name, path) == 0)
1698 + break;
1699 + }
1700 +
1701 + return np;
1702 +}
1703 +EXPORT_SYMBOL(of_find_node_by_path);
1704 +
1705 +struct device_node *of_find_node_by_phandle(phandle handle)
1706 +{
1707 + struct device_node *np;
1708 +
1709 + for (np = allnodes; np != 0; np = np->allnext)
1710 + if (np->node == handle)
1711 + break;
1712 +
1713 + return np;
1714 +}
1715 +EXPORT_SYMBOL(of_find_node_by_phandle);
1716 +
1717 +struct device_node *of_find_node_by_name(struct device_node *from,
1718 + const char *name)
1719 +{
1720 + struct device_node *np;
1721 +
1722 + np = from ? from->allnext : allnodes;
1723 + for (; np != NULL; np = np->allnext)
1724 + if (np->name != NULL && strcmp(np->name, name) == 0)
1725 + break;
1726 +
1727 + return np;
1728 +}
1729 +EXPORT_SYMBOL(of_find_node_by_name);
1730 +
1731 +struct device_node *of_find_node_by_type(struct device_node *from,
1732 + const char *type)
1733 +{
1734 + struct device_node *np;
1735 +
1736 + np = from ? from->allnext : allnodes;
1737 + for (; np != 0; np = np->allnext)
1738 + if (np->type != 0 && strcmp(np->type, type) == 0)
1739 + break;
1740 +
1741 + return np;
1742 +}
1743 +EXPORT_SYMBOL(of_find_node_by_type);
1744 +
1745 +struct device_node *of_find_compatible_node(struct device_node *from,
1746 + const char *type, const char *compatible)
1747 +{
1748 + struct device_node *np;
1749 +
1750 + np = from ? from->allnext : allnodes;
1751 + for (; np != 0; np = np->allnext) {
1752 + if (type != NULL
1753 + && !(np->type != 0 && strcmp(np->type, type) == 0))
1754 + continue;
1755 + if (of_device_is_compatible(np, compatible))
1756 + break;
1757 + }
1758 +
1759 + return np;
1760 +}
1761 +EXPORT_SYMBOL(of_find_compatible_node);
1762 +
1763 +struct property *of_find_property(const struct device_node *np,
1764 + const char *name,
1765 + int *lenp)
1766 +{
1767 + struct property *pp;
1768 +
1769 + for (pp = np->properties; pp != 0; pp = pp->next) {
1770 + if (strcasecmp(pp->name, name) == 0) {
1771 + if (lenp != 0)
1772 + *lenp = pp->length;
1773 + break;
1774 + }
1775 + }
1776 + return pp;
1777 +}
1778 +EXPORT_SYMBOL(of_find_property);
1779 +
1780 +/*
1781 + * Find a property with a given name for a given node
1782 + * and return the value.
1783 + */
1784 +const void *of_get_property(const struct device_node *np, const char *name,
1785 + int *lenp)
1786 +{
1787 + struct property *pp = of_find_property(np,name,lenp);
1788 + return pp ? pp->value : NULL;
1789 +}
1790 +EXPORT_SYMBOL(of_get_property);
1791 +
1792 +int of_getintprop_default(struct device_node *np, const char *name, int def)
1793 +{
1794 + struct property *prop;
1795 + int len;
1796 +
1797 + prop = of_find_property(np, name, &len);
1798 + if (!prop || len != 4)
1799 + return def;
1800 +
1801 + return *(int *) prop->value;
1802 +}
1803 +EXPORT_SYMBOL(of_getintprop_default);
1804 +
1805 +int of_n_addr_cells(struct device_node *np)
1806 +{
1807 + const int* ip;
1808 + do {
1809 + if (np->parent)
1810 + np = np->parent;
1811 + ip = of_get_property(np, "#address-cells", NULL);
1812 + if (ip != NULL)
1813 + return *ip;
1814 + } while (np->parent);
1815 + /* No #address-cells property for the root node, default to 2 */
1816 + return 2;
1817 +}
1818 +EXPORT_SYMBOL(of_n_addr_cells);
1819 +
1820 +int of_n_size_cells(struct device_node *np)
1821 +{
1822 + const int* ip;
1823 + do {
1824 + if (np->parent)
1825 + np = np->parent;
1826 + ip = of_get_property(np, "#size-cells", NULL);
1827 + if (ip != NULL)
1828 + return *ip;
1829 + } while (np->parent);
1830 + /* No #size-cells property for the root node, default to 1 */
1831 + return 1;
1832 +}
1833 +EXPORT_SYMBOL(of_n_size_cells);
1834 +
1835 +int of_set_property(struct device_node *dp, const char *name, void *val, int len)
1836 +{
1837 + return -EIO;
1838 +}
1839 +EXPORT_SYMBOL(of_set_property);
1840 +
1841 +static unsigned int prom_early_allocated;
1842 +
1843 +static void * __init prom_early_alloc(unsigned long size)
1844 +{
1845 + void *ret;
1846 +
1847 + ret = kmalloc(size, GFP_KERNEL);
1848 + if (ret != NULL)
1849 + memset(ret, 0, size);
1850 + else
1851 + printk(KERN_ERR "ACK! couldn't allocate prom memory!\n");
1852 +
1853 + prom_early_allocated += size;
1854 +
1855 + return ret;
1856 +}
1857 +
1858 +static int is_root_node(const struct device_node *dp)
1859 +{
1860 + if (!dp)
1861 + return 0;
1862 +
1863 + return (dp->parent == NULL);
1864 +}
1865 +
1866 +static char * __init build_path_component(struct device_node *dp)
1867 +{
1868 + int pathlen;
1869 + char *n, *i;
1870 +
1871 + if (ofw("package-to-path", 3, 1, dp->node, NULL, 0, &pathlen)) {
1872 + printk(KERN_ERR "PROM: unable to get path name from OFW!\n");
1873 + return "ERROR";
1874 + }
1875 + n = prom_early_alloc(pathlen + 1);
1876 + if (ofw("package-to-path", 3, 1, dp->node, n, pathlen+1, &pathlen))
1877 + printk(KERN_ERR "PROM: unable to get path name from OFW\n");
1878 +
1879 + if ((i = strrchr(n, '/')))
1880 + n = ++i; /* we only want the file name */
1881 + return n;
1882 +}
1883 +
1884 +static char * __init build_full_name(struct device_node *dp)
1885 +{
1886 + int len, ourlen, plen;
1887 + char *n;
1888 +
1889 + plen = strlen(dp->parent->full_name);
1890 + ourlen = strlen(dp->path_component_name);
1891 + len = ourlen + plen + 2;
1892 +
1893 + n = prom_early_alloc(len);
1894 + strcpy(n, dp->parent->full_name);
1895 + if (!is_root_node(dp->parent)) {
1896 + strcpy(n + plen, "/");
1897 + plen++;
1898 + }
1899 + strcpy(n + plen, dp->path_component_name);
1900 +
1901 + return n;
1902 +}
1903 +
1904 +static struct property * __init build_one_prop(phandle node, char *prev, char *special_name, void *special_val, int special_len)
1905 +{
1906 + static struct property *tmp = NULL;
1907 + struct property *p;
1908 +
1909 + if (tmp) {
1910 + p = tmp;
1911 + memset(p, 0, sizeof(*p) + 32);
1912 + tmp = NULL;
1913 + } else {
1914 + p = prom_early_alloc(sizeof(struct property) + 32);
1915 + }
1916 +
1917 + p->name = (char *) (p + 1);
1918 + if (special_name) {
1919 + strcpy(p->name, special_name);
1920 + p->length = special_len;
1921 + p->value = prom_early_alloc(special_len);
1922 + memcpy(p->value, special_val, special_len);
1923 + } else {
1924 + int fl;
1925 + if (prev == NULL) {
1926 + if (ofw("nextprop", 3, 1, node, "", p->name, &fl)) {
1927 + printk(KERN_ERR "PROM: %s: nextprop failed!\n", __func__);
1928 + return NULL;
1929 + }
1930 + } else {
1931 + if (ofw("nextprop", 3, 1, node, prev, p->name, &fl)) {
1932 + printk(KERN_ERR "PROM: %s: nextprop failed!\n", __func__);
1933 + return NULL;
1934 + }
1935 + }
1936 + if (strlen(p->name) == 0 || fl != 1) {
1937 + tmp = p;
1938 + return NULL;
1939 + }
1940 + if (ofw("getproplen", 2, 1, node, p->name, &p->length)) {
1941 + printk(KERN_ERR "PROM: %s: getproplen failed!\n", __func__);
1942 + return NULL;
1943 + }
1944 + if (p->length <= 0) {
1945 + p->length = 0;
1946 + } else {
1947 + p->value = prom_early_alloc(p->length + 1);
1948 + if (ofw("getprop", 4, 1, node, p->name, p->value, p->length, &p->length)) {
1949 + printk(KERN_ERR "PROM: %s: getprop failed!\n", __func__);
1950 + return NULL;
1951 + }
1952 + ((unsigned char *)p->value)[p->length] = '\0';
1953 + }
1954 + }
1955 + return p;
1956 +}
1957 +
1958 +static struct property * __init build_prop_list(phandle node)
1959 +{
1960 + struct property *head, *tail;
1961 +
1962 + head = tail = build_one_prop(node, NULL,
1963 + ".node", &node, sizeof(node));
1964 +
1965 + tail->next = build_one_prop(node, NULL, NULL, NULL, 0);
1966 + tail = tail->next;
1967 + while(tail) {
1968 + tail->next = build_one_prop(node, tail->name,
1969 + NULL, NULL, 0);
1970 + tail = tail->next;
1971 + }
1972 +
1973 + return head;
1974 +}
1975 +
1976 +static char * __init get_one_property(phandle node, const char *name)
1977 +{
1978 + char *buf = "<NULL>";
1979 + int len;
1980 +
1981 + if (ofw("getproplen", 2, 1, node, name, &len)) {
1982 + printk(KERN_ERR "PROM: %s: getproplen failed!\n", __func__);
1983 + return NULL;
1984 + }
1985 + if (len > 0) {
1986 + buf = prom_early_alloc(len);
1987 + if (ofw("getprop", 4, 1, node, name, buf, len, &len)) {
1988 + printk(KERN_ERR "PROM: %s: getprop failed!\n", __func__);
1989 + return NULL;
1990 + }
1991 + }
1992 +
1993 + return buf;
1994 +}
1995 +
1996 +static struct device_node * __init create_node(phandle node, struct device_node *parent)
1997 +{
1998 + struct device_node *dp;
1999 +
2000 + if (!node)
2001 + return NULL;
2002 +
2003 + dp = prom_early_alloc(sizeof(*dp));
2004 + dp->parent = parent;
2005 +
2006 + kref_init(&dp->kref);
2007 +
2008 + dp->name = get_one_property(node, "name");
2009 + dp->type = get_one_property(node, "device_type");
2010 + dp->node = node;
2011 +
2012 + dp->properties = build_prop_list(node);
2013 +
2014 + return dp;
2015 +}
2016 +
2017 +static struct device_node * __init build_tree(struct device_node *parent, phandle node, struct device_node ***nextp)
2018 +{
2019 + struct device_node *ret = NULL, *prev_sibling = NULL;
2020 + struct device_node *dp;
2021 + u32 child;
2022 +
2023 + while (1) {
2024 + dp = create_node(node, parent);
2025 + if (!dp)
2026 + break;
2027 +
2028 + if (prev_sibling)
2029 + prev_sibling->sibling = dp;
2030 +
2031 + if (!ret)
2032 + ret = dp;
2033 + prev_sibling = dp;
2034 +
2035 + *(*nextp) = dp;
2036 + *nextp = &dp->allnext;
2037 +
2038 + dp->path_component_name = build_path_component(dp);
2039 + dp->full_name = build_full_name(dp);
2040 +
2041 + if (ofw("child", 1, 1, node, &child)) {
2042 + printk(KERN_ERR "PROM: %s: fetching child failed!\n", __func__);
2043 + return NULL;
2044 + }
2045 + dp->child = build_tree(dp, child, nextp);
2046 +
2047 + if (ofw("peer", 1, 1, node, &node)) {
2048 + printk(KERN_ERR "PROM: %s: fetching peer failed!\n", __func__);
2049 + return NULL;
2050 + }
2051 + }
2052 +
2053 + return ret;
2054 +}
2055 +
2056 +static phandle root_node;
2057 +
2058 +void __init prom_build_devicetree(void)
2059 +{
2060 + struct device_node **nextp;
2061 + u32 child;
2062 +
2063 + if (ofw("peer", 1, 1, 0, &root_node)) {
2064 + printk(KERN_ERR "PROM: unable to get root node from OFW!\n");
2065 + return;
2066 + }
2067 +
2068 + allnodes = create_node(root_node, NULL);
2069 + allnodes->path_component_name = "";
2070 + allnodes->full_name = "/";
2071 +
2072 + nextp = &allnodes->allnext;
2073 + if (ofw("child", 1, 1, allnodes->node, &child)) {
2074 + printk(KERN_ERR "PROM: unable to get child node from OFW!\n");
2075 + return;
2076 + }
2077 + allnodes->child = build_tree(allnodes, child, &nextp);
2078 + printk("PROM: Built device tree with %u bytes of memory.\n",
2079 + prom_early_allocated);
2080 +}
2081 diff -purN linux_2.6.24_org/arch/x86/pci/olpc.c linux_2.6.24_olpc/arch/x86/pci/olpc.c
2082 --- linux_2.6.24_org/arch/x86/pci/olpc.c 1970-01-01 01:00:00.000000000 +0100
2083 +++ linux_2.6.24_olpc/arch/x86/pci/olpc.c 2008-02-15 18:59:22.000000000 +0000
2084 @@ -0,0 +1,298 @@
2085 +/*
2086 + * olpcpci.c - Low-level PCI config space access for OLPC systems
2087 + * without the VSA PCI virtualization software.
2088 + *
2089 + * The AMD Geode chipset (GX2 processor, cs5536 I/O companion device)
2090 + * has some I/O functions (display, southbridge, sound, USB HCIs, etc)
2091 + * that more or less behave like PCI devices, but the hardware doesn't
2092 + * directly implement the PCI configuration space headers. AMD provides
2093 + * "VSA" (Virtual System Architecture) software that emulates PCI config
2094 + * space for these devices, by trapping I/O accesses to PCI config register
2095 + * (CF8/CFC) and running some code in System Management Mode interrupt state.
2096 + * On the OLPC platform, we don't want to use that VSA code because
2097 + * (a) it slows down suspend/resume, and (b) recompiling it requires special
2098 + * compilers that are hard to get. So instead of letting the complex VSA
2099 + * code simulate the PCI config registers for the on-chip devices, we
2100 + * just simulate them the easy way, by inserting the code into the
2101 + * pci_write_config and pci_read_config path. Most of the config registers
2102 + * are read-only anyway, so the bulk of the simulation is just table lookup.
2103 + */
2104 +
2105 +#include <linux/pci.h>
2106 +#include <linux/init.h>
2107 +#include <asm/olpc.h>
2108 +#include <asm/geode.h>
2109 +#include "pci.h"
2110 +
2111 +static int is_lx;
2112 +
2113 +/*
2114 + * In the tables below, the first two line (8 longwords) are the
2115 + * size masks that are used when the higher level PCI code determines
2116 + * the size of the region by writing ~0 to a base address register
2117 + * and reading back the result.
2118 + *
2119 + * The following lines are the values that are read during normal
2120 + * PCI config access cycles, i.e. not after just having written
2121 + * ~0 to a base address register.
2122 + */
2123 +
2124 +static const u32 lxnb_hdr[] = { /* dev 1 function 0 - devfn = 8 */
2125 + 0x0 , 0x0 , 0x0 , 0x0 ,
2126 + 0x0 , 0x0 , 0x0 , 0x0 ,
2127 +
2128 + 0x281022 , 0x2200005 , 0x6000021 , 0x80f808 , /* AMD Vendor ID */
2129 + 0x0 , 0x0 , 0x0 , 0x0 , /* No virtual registers, hence no BAR for them */
2130 + 0x0 , 0x0 , 0x0 , 0x28100b ,
2131 + 0x0 , 0x0 , 0x0 , 0x0 ,
2132 + 0x0 , 0x0 , 0x0 , 0x0 ,
2133 + 0x0 , 0x0 , 0x0 , 0x0 ,
2134 + 0x0 , 0x0 , 0x0 , 0x0 ,
2135 +};
2136 +
2137 +static const u32 gxnb_hdr[] = { /* dev 1 function 0 - devfn = 8 */
2138 + 0xfffffffd , 0x0 , 0x0 , 0x0 ,
2139 + 0x0 , 0x0 , 0x0 , 0x0 ,
2140 +
2141 + 0x28100b , 0x2200005 , 0x6000021 , 0x80f808 , /* NSC Vendor ID */
2142 + 0xac1d , 0x0 , 0x0 , 0x0 , /* I/O BAR - base of virtual registers */
2143 + 0x0 , 0x0 , 0x0 , 0x28100b ,
2144 + 0x0 , 0x0 , 0x0 , 0x0 ,
2145 + 0x0 , 0x0 , 0x0 , 0x0 ,
2146 + 0x0 , 0x0 , 0x0 , 0x0 ,
2147 + 0x0 , 0x0 , 0x0 , 0x0 ,
2148 +};
2149 +
2150 +static const u32 lxfb_hdr[] = { /* dev 1 function 1 - devfn = 9 */
2151 + 0xff800008 , 0xffffc000 , 0xffffc000 , 0xffffc000 ,
2152 + 0x0 , 0x0 , 0x0 , 0x0 ,
2153 +
2154 + 0x20811022 , 0x2200003 , 0x3000000 , 0x0 , /* AMD Vendor ID */
2155 + 0xfd000000 , 0xfe000000 , 0xfe004000 , 0xfe008000 , /* FB, GP, VG, DF */
2156 + 0xfe00c000 , 0x0 , 0x0 , 0x30100b , /* VIP */
2157 + 0x0 , 0x0 , 0x0 , 0x10e , /* INTA, IRQ14 for graphics accel */
2158 + 0x0 , 0x0 , 0x0 , 0x0 ,
2159 + 0x3d0 , 0x3c0 , 0xa0000 , 0x0 , /* VG IO, VG IO, EGA FB, MONO FB */
2160 + 0x0 , 0x0 , 0x0 , 0x0 ,
2161 +};
2162 +
2163 +static const u32 gxfb_hdr[] = { /* dev 1 function 1 - devfn = 9 */
2164 + 0xff800008 , 0xffffc000 , 0xffffc000 , 0xffffc000 ,
2165 + 0x0 , 0x0 , 0x0 , 0x0 ,
2166 +
2167 + 0x30100b , 0x2200003 , 0x3000000 , 0x0 , /* NSC Vendor ID */
2168 + 0xfd000000 , 0xfe000000 , 0xfe004000 , 0xfe008000 , /* FB, GP, VG, DF */
2169 + 0x0 , 0x0 , 0x0 , 0x30100b ,
2170 + 0x0 , 0x0 , 0x0 , 0x0 ,
2171 + 0x0 , 0x0 , 0x0 , 0x0 ,
2172 + 0x3d0 , 0x3c0 , 0xa0000 , 0x0 , /* VG IO, VG IO, EGA FB, MONO FB */
2173 + 0x0 , 0x0 , 0x0 , 0x0 ,
2174 +};
2175 +
2176 +static const u32 aes_hdr[] = { /* dev 1 function 2 - devfn = 0xa */
2177 + 0xffffc000 , 0x0 , 0x0 , 0x0 ,
2178 + 0x0 , 0x0 , 0x0 , 0x0 ,
2179 +
2180 + 0x20821022 , 0x2a00006 , 0x10100000 , 0x8 , /* NSC Vendor ID */
2181 + 0xfe010000 , 0x0 , 0x0 , 0x0 , /* AES registers */
2182 + 0x0 , 0x0 , 0x0 , 0x20821022 ,
2183 + 0x0 , 0x0 , 0x0 , 0x0 ,
2184 + 0x0 , 0x0 , 0x0 , 0x0 ,
2185 + 0x0 , 0x0 , 0x0 , 0x0 ,
2186 + 0x0 , 0x0 , 0x0 , 0x0 ,
2187 +};
2188 +
2189 +
2190 +static const u32 isa_hdr[] = { /* dev f function 0 - devfn = 78 */
2191 + 0xfffffff9 , 0xffffff01 , 0xffffffc1 , 0xffffffe1 ,
2192 + 0xffffff81 , 0xffffffc1 , 0x0 , 0x0 ,
2193 +
2194 + 0x20901022 , 0x2a00049 , 0x6010003 , 0x802000 ,
2195 + 0x18b1 , 0x1001 , 0x1801 , 0x1881 , /* SMB-8 GPIO-256 MFGPT-64 IRQ-32 */
2196 + 0x1401 , 0x1841 , 0x0 , 0x20901022 , /* PMS-128 ACPI-64 */
2197 + 0x0 , 0x0 , 0x0 , 0x0 ,
2198 + 0x0 , 0x0 , 0x0 , 0x0 ,
2199 + 0x0 , 0x0 , 0x0 , 0xaa5b , /* interrupt steering */
2200 + 0x0 , 0x0 , 0x0 , 0x0 ,
2201 +};
2202 +
2203 +static const u32 ac97_hdr[] = { /* dev f function 3 - devfn = 7b */
2204 + 0xffffff81 , 0x0 , 0x0 , 0x0 ,
2205 + 0x0 , 0x0 , 0x0 , 0x0 ,
2206 +
2207 + 0x20931022 , 0x2a00041 , 0x4010001 , 0x0 ,
2208 + 0x1481 , 0x0 , 0x0 , 0x0 , /* I/O BAR-128 */
2209 + 0x0 , 0x0 , 0x0 , 0x20931022 ,
2210 + 0x0 , 0x0 , 0x0 , 0x205 , /* IntB , IRQ5 */
2211 + 0x0 , 0x0 , 0x0 , 0x0 ,
2212 + 0x0 , 0x0 , 0x0 , 0x0 ,
2213 + 0x0 , 0x0 , 0x0 , 0x0 ,
2214 +};
2215 +
2216 +static const u32 ohci_hdr[] = { /* dev f function 4 - devfn = 7c */
2217 + 0xfffff000 , 0x0 , 0x0 , 0x0 ,
2218 + 0x0 , 0x0 , 0x0 , 0x0 ,
2219 +
2220 + 0x20941022 , 0x2300006 , 0xc031002 , 0x0 ,
2221 + 0xfe01a000 , 0x0 , 0x0 , 0x0 , /* MEMBAR-1000 */
2222 + 0x0 , 0x0 , 0x0 , 0x20941022 ,
2223 + 0x0 , 0x40 , 0x0 , 0x40a , /* CapPtr INT-D, IRQ A */
2224 + 0xc8020001 , 0x0 , 0x0 , 0x0 , /* Capabilities - 40 is R/O, 44 is mask 8103 (power control) */
2225 + 0x0 , 0x0 , 0x0 , 0x0 ,
2226 + 0x0 , 0x0 , 0x0 , 0x0 ,
2227 +};
2228 +
2229 +static const u32 ehci_hdr[] = { /* dev f function 4 - devfn = 7d */
2230 + 0xfffff000 , 0x0 , 0x0 , 0x0 ,
2231 + 0x0 , 0x0 , 0x0 , 0x0 ,
2232 +
2233 + 0x20951022 , 0x2300006 , 0xc032002 , 0x0 ,
2234 + 0xfe01b000 , 0x0 , 0x0 , 0x0 , /* MEMBAR-1000 */
2235 + 0x0 , 0x0 , 0x0 , 0x20951022 ,
2236 + 0x0 , 0x40 , 0x0 , 0x40a , /* CapPtr INT-D, IRQ A */
2237 + 0xc8020001 , 0x0 , 0x0 , 0x0 , /* Capabilities - 40 is R/O, 44 is mask 8103 (power control) */
2238 +#if 0
2239 + 0x1 , 0x40080000 , 0x0 , 0x0 , /* EECP - see section 2.1.7 of EHCI spec */
2240 +#endif
2241 + 0x01000001 , 0x00000000 , 0x0 , 0x0 , /* EECP - see section 2.1.7 of EHCI spec */
2242 + 0x2020 , 0x0 , 0x0 , 0x0 , /* (EHCI page 8) 60 SBRN (R/O), 61 FLADJ (R/W), PORTWAKECAP */
2243 +};
2244 +
2245 +static u32 ff_loc = ~0;
2246 +static u32 zero_loc = 0;
2247 +
2248 +static int bar_probing = 0; /* Set after a write of ~0 to a BAR */
2249 +
2250 +#define NB_SLOT 0x1 /* Northbridge - GX chip - Device 1 */
2251 +#define SB_SLOT 0xf /* Southbridge - CS5536 chip - Device F */
2252 +#define SIMULATED(bus, devfn) (((bus) == 0) && ((PCI_SLOT(devfn) == NB_SLOT) || (PCI_SLOT(devfn) == SB_SLOT)))
2253 +
2254 +static u32 *hdr_addr(const u32 *hdr, int reg)
2255 +{
2256 + u32 addr;
2257 +
2258 + /*
2259 + * This is a little bit tricky. The header maps consist of
2260 + * 0x20 bytes of size masks, followed by 0x70 bytes of header data.
2261 + * In the normal case, when not probing a BAR's size, we want
2262 + * to access the header data, so we add 0x20 to the reg offset,
2263 + * thus skipping the size mask area.
2264 + * In the BAR probing case, we want to access the size mask for
2265 + * the BAR, so we subtract 0x10 (the config header offset for
2266 + * BAR0), and don't skip the size mask area.
2267 + */
2268 +
2269 + addr = (u32)hdr + reg + (bar_probing ? -0x10 : 0x20);
2270 +
2271 + bar_probing = 0;
2272 + return (u32 *)addr;
2273 +}
2274 +
2275 +static int pci_olpc_read(unsigned int seg, unsigned int bus,
2276 + unsigned int devfn, int reg, int len, u32 *value)
2277 +{
2278 + u32 *addr;
2279 +
2280 + /* Use the hardware mechanism for non-simulated devices */
2281 + if (!SIMULATED(bus, devfn))
2282 + return pci_conf1_read(seg, bus, devfn, reg, len, value);
2283 +
2284 + /*
2285 + * No device has config registers past 0x70, so we save table space
2286 + * by not storing entries for the nonexistent registers
2287 + */
2288 + if (reg >= 0x70)
2289 + addr = &zero_loc;
2290 + else {
2291 + switch (devfn) {
2292 + case 0x8:
2293 + addr = hdr_addr(is_lx ? lxnb_hdr : gxnb_hdr, reg);
2294 + break;
2295 + case 0x9:
2296 + addr = hdr_addr(is_lx ? lxfb_hdr : gxfb_hdr, reg);
2297 + break;
2298 + case 0xa:
2299 + addr = is_lx ? hdr_addr(aes_hdr, reg) : &ff_loc;
2300 + break;
2301 + case 0x78:
2302 + addr = hdr_addr(isa_hdr, reg);
2303 + break;
2304 + case 0x7b:
2305 + addr = hdr_addr(ac97_hdr, reg);
2306 + break;
2307 + case 0x7c:
2308 + addr = hdr_addr(ohci_hdr, reg);
2309 + break;
2310 + case 0x7d:
2311 + addr = hdr_addr(ehci_hdr, reg);
2312 + break;
2313 + default:
2314 + addr = &ff_loc;
2315 + break;
2316 + }
2317 + }
2318 + switch (len) {
2319 + case 1:
2320 + *value = *(u8 *) addr;
2321 + break;
2322 + case 2:
2323 + *value = *(u16 *) addr;
2324 + break;
2325 + case 4:
2326 + *value = *addr;
2327 + break;
2328 + default:
2329 + BUG();
2330 + }
2331 +
2332 + return 0;
2333 +}
2334 +
2335 +static int pci_olpc_write(unsigned int seg, unsigned int bus,
2336 + unsigned int devfn, int reg, int len, u32 value)
2337 +{
2338 + /* Use the hardware mechanism for non-simulated devices */
2339 + if (!SIMULATED(bus, devfn))
2340 + return pci_conf1_write(seg, bus, devfn, reg, len, value);
2341 +
2342 + /* XXX we may want to extend this to simulate EHCI power management */
2343 +
2344 + /*
2345 + * Mostly we just discard writes, but if the write is a size probe
2346 + * (i.e. writing ~0 to a BAR), we remember it and arrange to return
2347 + * the appropriate size mask on the next read. This is cheating
2348 + * to some extent, because it depends on the fact that the next
2349 + * access after such a write will always be a read to the same BAR.
2350 + */
2351 +
2352 + if ((reg >= 0x10) && (reg < 0x2c)) {
2353 + /* Write is to a BAR */
2354 + if (value == ~0)
2355 + bar_probing = 1;
2356 + } else {
2357 + /*
2358 + * No warning on writes to ROM BAR, CMD, LATENCY_TIMER,
2359 + * CACHE_LINE_SIZE, or PM registers.
2360 + */
2361 + if ((reg != 0x30) && (reg != 0x04) && (reg != 0x0d) &&
2362 + (reg != 0x0c) && (reg != 0x44))
2363 + printk(KERN_WARNING "OLPC PCI: Config write to devfn %x reg %x value %x\n", devfn, reg, value);
2364 + }
2365 +
2366 + return 0;
2367 +}
2368 +
2369 +static struct pci_raw_ops pci_olpc_conf = {
2370 + .read = pci_olpc_read,
2371 + .write = pci_olpc_write,
2372 +};
2373 +
2374 +void __init pci_olpc_init(void)
2375 +{
2376 + if (!machine_is_olpc() || olpc_has_vsa())
2377 + return;
2378 +
2379 + printk(KERN_INFO "PCI: Using configuration type OLPC\n");
2380 + raw_pci_ops = &pci_olpc_conf;
2381 + is_lx = is_geode_lx();
2382 +}
2383 diff -purN linux_2.6.24_org/Documentation/kernel-parameters.txt linux_2.6.24_olpc/Documentation/kernel-parameters.txt
2384 --- linux_2.6.24_org/Documentation/kernel-parameters.txt 2008-02-15 20:12:29.000000000 +0000
2385 +++ linux_2.6.24_olpc/Documentation/kernel-parameters.txt 2008-02-15 18:59:54.000000000 +0000
2386 @@ -1244,6 +1244,13 @@ and is between 256 and 4096 characters.
2387
2388 nr_uarts= [SERIAL] maximum number of UARTs to be registered.
2389
2390 + olpc_ec_timeout= [OLPC] ms delay when issuing EC commands
2391 + Rather than timing out after 20 ms if an EC
2392 + command is not properly ACKed, override the length
2393 + of the timeout. We have interrupts disabled while
2394 + waiting for the ACK, so if this is set too high
2395 + interrupts *may* be lost!
2396 +
2397 opl3= [HW,OSS]
2398 Format: <io>
2399
2400 diff -purN linux_2.6.24_org/drivers/base/dd.c linux_2.6.24_olpc/drivers/base/dd.c
2401 --- linux_2.6.24_org/drivers/base/dd.c 2008-02-15 20:11:29.000000000 +0000
2402 +++ linux_2.6.24_olpc/drivers/base/dd.c 2008-02-15 18:58:46.000000000 +0000
2403 @@ -293,7 +293,6 @@ static void __device_release_driver(stru
2404 if (drv) {
2405 driver_sysfs_remove(dev);
2406 sysfs_remove_link(&dev->kobj, "driver");
2407 - klist_remove(&dev->knode_driver);
2408
2409 if (dev->bus)
2410 blocking_notifier_call_chain(&dev->bus->bus_notifier,
2411 @@ -306,6 +305,7 @@ static void __device_release_driver(stru
2412 drv->remove(dev);
2413 devres_release_all(dev);
2414 dev->driver = NULL;
2415 + klist_remove(&dev->knode_driver);
2416 put_driver(drv);
2417 }
2418 }
2419 diff -purN linux_2.6.24_org/drivers/char/vt_ioctl.c linux_2.6.24_olpc/drivers/char/vt_ioctl.c
2420 --- linux_2.6.24_org/drivers/char/vt_ioctl.c 2008-02-15 20:11:48.000000000 +0000
2421 +++ linux_2.6.24_olpc/drivers/char/vt_ioctl.c 2008-02-15 18:59:11.000000000 +0000
2422 @@ -38,6 +38,9 @@
2423 char vt_dont_switch;
2424 extern struct tty_driver *console_driver;
2425
2426 +/* Add a notifier chain to inform drivers of a VT_TEXT/VT_GRAPHICS switch */
2427 +RAW_NOTIFIER_HEAD(console_notifier_list);
2428 +
2429 #define VT_IS_IN_USE(i) (console_driver->ttys[i] && console_driver->ttys[i]->count)
2430 #define VT_BUSY(i) (VT_IS_IN_USE(i) || i == fg_console || vc_cons[i].d == sel_cons)
2431
2432 @@ -492,6 +495,14 @@ int vt_ioctl(struct tty_struct *tty, str
2433 vc->vc_mode = (unsigned char) arg;
2434 if (console != fg_console)
2435 return 0;
2436 +
2437 + /* Notify listeners if the current fg_console has switched */
2438 +
2439 + raw_notifier_call_chain(&console_notifier_list,
2440 + (arg == KD_TEXT) ?
2441 + CONSOLE_EVENT_SWITCH_TEXT :
2442 + CONSOLE_EVENT_SWITCH_GRAPHICS, 0);
2443 +
2444 /*
2445 * explicitly blank/unblank the screen if switching modes
2446 */
2447 diff -purN linux_2.6.24_org/drivers/i2c/busses/scx200_acb.c linux_2.6.24_olpc/drivers/i2c/busses/scx200_acb.c
2448 --- linux_2.6.24_org/drivers/i2c/busses/scx200_acb.c 2008-02-15 20:11:33.000000000 +0000
2449 +++ linux_2.6.24_olpc/drivers/i2c/busses/scx200_acb.c 2008-02-15 18:58:49.000000000 +0000
2450 @@ -46,6 +46,10 @@ static int base[MAX_DEVICES] = { 0x820,
2451 module_param_array(base, int, NULL, 0);
2452 MODULE_PARM_DESC(base, "Base addresses for the ACCESS.bus controllers");
2453
2454 +static unsigned int smbclk = 0x70;
2455 +module_param(smbclk, uint, 0);
2456 +MODULE_PARM_DESC(smbclk, "Specify the SMB_CLK value");
2457 +
2458 #define POLL_TIMEOUT (HZ/5)
2459
2460 enum scx200_acb_state {
2461 @@ -108,6 +112,7 @@ struct scx200_acb_iface {
2462 #define ACBADDR (iface->base + 4)
2463 #define ACBCTL2 (iface->base + 5)
2464 #define ACBCTL2_ENABLE 0x01
2465 +#define ACBCTL3 (iface->base + 6)
2466
2467 /************************************************************************/
2468
2469 @@ -392,11 +397,13 @@ static __init int scx200_acb_probe(struc
2470 {
2471 u8 val;
2472
2473 - /* Disable the ACCESS.bus device and Configure the SCL
2474 - frequency: 16 clock cycles */
2475 - outb(0x70, ACBCTL2);
2476 + /* Disable the ACCESS.bus device and Configure the SCL */
2477 +
2478 + outb((smbclk & 0x7F) << 1, ACBCTL2);
2479 +
2480 + outb((smbclk >> 7) & 0xFF, ACBCTL3);
2481
2482 - if (inb(ACBCTL2) != 0x70) {
2483 + if (inb(ACBCTL2) != ((smbclk & 0x7F) << 1)) {
2484 pr_debug(NAME ": ACBCTL2 readback failed\n");
2485 return -ENXIO;
2486 }
2487 diff -purN linux_2.6.24_org/drivers/input/keyboard/atkbd.c linux_2.6.24_olpc/drivers/input/keyboard/atkbd.c
2488 --- linux_2.6.24_org/drivers/input/keyboard/atkbd.c 2008-02-15 20:11:51.000000000 +0000
2489 +++ linux_2.6.24_olpc/drivers/input/keyboard/atkbd.c 2008-02-15 18:59:14.000000000 +0000
2490 @@ -63,12 +63,25 @@ static int atkbd_extra;
2491 module_param_named(extra, atkbd_extra, bool, 0);
2492 MODULE_PARM_DESC(extra, "Enable extra LEDs and keys on IBM RapidAcces, EzKey and similar keyboards");
2493
2494 +#define ATKBD_KEY_UNKNOWN 0
2495 +#define ATKBD_KEY_NULL 0xFF0000FF
2496 +
2497 +#define ATKBD_SCR_1 0xFF0000FE
2498 +#define ATKBD_SCR_2 0xFF0000FD
2499 +#define ATKBD_SCR_4 0xFF0000FC
2500 +#define ATKBD_SCR_8 0xFF0000FB
2501 +#define ATKBD_SCR_CLICK 0xFF0000FA
2502 +#define ATKBD_SCR_LEFT 0xFF0000F9
2503 +#define ATKBD_SCR_RIGHT 0xFF0000F8
2504 +
2505 +#define ATKBD_SPECIAL 0xFF0000F8
2506 +
2507 /*
2508 * Scancode to keycode tables. These are just the default setting, and
2509 * are loadable via an userland utility.
2510 */
2511
2512 -static unsigned char atkbd_set2_keycode[512] = {
2513 +static unsigned int atkbd_set2_keycode[512] = {
2514
2515 #ifdef CONFIG_KEYBOARD_ATKBD_HP_KEYCODES
2516
2517 @@ -87,11 +100,17 @@ static unsigned char atkbd_set2_keycode[
2518 82, 83, 80, 76, 77, 72, 1, 69, 87, 78, 81, 74, 55, 73, 70, 99,
2519
2520 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2521 - 217,100,255, 0, 97,165, 0, 0,156, 0, 0, 0, 0, 0, 0,125,
2522 +
2523 + 217,100,ATKBD_KEY_NULL, 0, 97,165, 0, 0,
2524 + 156, 0, 0, 0, 0, 0, 0,125,
2525 +
2526 173,114, 0,113, 0, 0, 0,126,128, 0, 0,140, 0, 0, 0,127,
2527 159, 0,115, 0,164, 0, 0,116,158, 0,172,166, 0, 0, 0,142,
2528 157, 0, 0, 0, 0, 0, 0, 0,155, 0, 98, 0, 0,163, 0, 0,
2529 - 226, 0, 0, 0, 0, 0, 0, 0, 0,255, 96, 0, 0, 0,143, 0,
2530 +
2531 + 226, 0, 0, 0, 0, 0, 0, 0,
2532 + 0,ATKBD_KEY_NULL, 96, 0, 0, 0,143, 0,
2533 +
2534 0, 0, 0, 0, 0, 0, 0, 0, 0,107, 0,105,102, 0, 0,112,
2535 110,111,108,112,106,103, 0,119, 0,118,109, 0, 99,104,119, 0,
2536
2537 @@ -150,19 +169,6 @@ static unsigned char atkbd_unxlate_table
2538 #define ATKBD_RET_HANGEUL 0xf2
2539 #define ATKBD_RET_ERR 0xff
2540
2541 -#define ATKBD_KEY_UNKNOWN 0
2542 -#define ATKBD_KEY_NULL 255
2543 -
2544 -#define ATKBD_SCR_1 254
2545 -#define ATKBD_SCR_2 253
2546 -#define ATKBD_SCR_4 252
2547 -#define ATKBD_SCR_8 251
2548 -#define ATKBD_SCR_CLICK 250
2549 -#define ATKBD_SCR_LEFT 249
2550 -#define ATKBD_SCR_RIGHT 248
2551 -
2552 -#define ATKBD_SPECIAL 248
2553 -
2554 #define ATKBD_LED_EVENT_BIT 0
2555 #define ATKBD_REP_EVENT_BIT 1
2556
2557 @@ -174,7 +180,7 @@ static unsigned char atkbd_unxlate_table
2558 #define ATKBD_XL_HANJA 0x20
2559
2560 static struct {
2561 - unsigned char keycode;
2562 + unsigned int keycode;
2563 unsigned char set2;
2564 } atkbd_scroll_keys[] = {
2565 { ATKBD_SCR_1, 0xc5 },
2566 @@ -200,7 +206,7 @@ struct atkbd {
2567 char phys[32];
2568
2569 unsigned short id;
2570 - unsigned char keycode[512];
2571 + unsigned int keycode[512];
2572 unsigned char set;
2573 unsigned char translated;
2574 unsigned char extra;
2575 @@ -351,7 +357,7 @@ static irqreturn_t atkbd_interrupt(struc
2576 unsigned int code = data;
2577 int scroll = 0, hscroll = 0, click = -1, add_release_event = 0;
2578 int value;
2579 - unsigned char keycode;
2580 + unsigned int keycode;
2581
2582 #ifdef ATKBD_DEBUG
2583 printk(KERN_DEBUG "atkbd.c: Received %02x flags %02x\n", data, flags);
2584 @@ -856,9 +862,11 @@ static void atkbd_set_keycode_table(stru
2585 atkbd->keycode[i | 0x80] = atkbd_scroll_keys[j].keycode;
2586 }
2587 } else if (atkbd->set == 3) {
2588 - memcpy(atkbd->keycode, atkbd_set3_keycode, sizeof(atkbd->keycode));
2589 + for (i = 0; i < ARRAY_SIZE(atkbd_set3_keycode); i++)
2590 + atkbd->keycode[i] = atkbd_set3_keycode[i];
2591 } else {
2592 - memcpy(atkbd->keycode, atkbd_set2_keycode, sizeof(atkbd->keycode));
2593 + for (i = 0; i < ARRAY_SIZE(atkbd_set2_keycode); i++)
2594 + atkbd->keycode[i] = atkbd_set2_keycode[i];
2595
2596 if (atkbd->scroll)
2597 for (i = 0; i < ARRAY_SIZE(atkbd_scroll_keys); i++)
2598 @@ -930,8 +938,8 @@ static void atkbd_set_device_attrs(struc
2599 }
2600
2601 input_dev->keycode = atkbd->keycode;
2602 - input_dev->keycodesize = sizeof(unsigned char);
2603 - input_dev->keycodemax = ARRAY_SIZE(atkbd_set2_keycode);
2604 + input_dev->keycodesize = sizeof(unsigned int);
2605 + input_dev->keycodemax = ARRAY_SIZE(atkbd->keycode);
2606
2607 for (i = 0; i < 512; i++)
2608 if (atkbd->keycode[i] && atkbd->keycode[i] < ATKBD_SPECIAL)
2609 @@ -1022,6 +1030,10 @@ static int atkbd_connect(struct serio *s
2610 return err;
2611 }
2612
2613 +#ifdef CONFIG_OLPC
2614 +#include <asm/olpc.h>
2615 +#endif
2616 +
2617 /*
2618 * atkbd_reconnect() tries to restore keyboard into a sane state and is
2619 * most likely called on resume.
2620 @@ -1032,6 +1044,12 @@ static int atkbd_reconnect(struct serio
2621 struct atkbd *atkbd = serio_get_drvdata(serio);
2622 struct serio_driver *drv = serio->drv;
2623
2624 +#ifdef CONFIG_OLPC
2625 + if (olpc_board_at_least(olpc_board_pre(0xb3)))
2626 + if (serio->dev.power.power_state.event != PM_EVENT_ON)
2627 + return 0;
2628 +#endif
2629 +
2630 if (!atkbd || !drv) {
2631 printk(KERN_DEBUG "atkbd: reconnect request, but serio is disconnected, ignoring...\n");
2632 return -1;
2633 diff -purN linux_2.6.24_org/drivers/input/mouse/Kconfig linux_2.6.24_olpc/drivers/input/mouse/Kconfig
2634 --- linux_2.6.24_org/drivers/input/mouse/Kconfig 2008-02-15 20:11:51.000000000 +0000
2635 +++ linux_2.6.24_olpc/drivers/input/mouse/Kconfig 2008-02-15 18:59:14.000000000 +0000
2636 @@ -96,6 +96,16 @@ config MOUSE_PS2_TOUCHKIT
2637
2638 If unsure, say N.
2639
2640 +config MOUSE_PS2_OLPC
2641 + bool "OLPC PS/2 mouse protocol extension" if EMBEDDED
2642 + default n
2643 + depends on MOUSE_PS2 && OLPC
2644 + ---help---
2645 + Say Y here if you have an OLPC PS/2 touchpad connected to
2646 + your system.
2647 +
2648 + If unsure, say N.
2649 +
2650 config MOUSE_SERIAL
2651 tristate "Serial mouse"
2652 select SERIO
2653 diff -purN linux_2.6.24_org/drivers/input/mouse/Makefile linux_2.6.24_olpc/drivers/input/mouse/Makefile
2654 --- linux_2.6.24_org/drivers/input/mouse/Makefile 2008-02-15 20:11:51.000000000 +0000
2655 +++ linux_2.6.24_olpc/drivers/input/mouse/Makefile 2008-02-15 18:59:14.000000000 +0000
2656 @@ -24,3 +24,4 @@ psmouse-$(CONFIG_MOUSE_PS2_LOGIPS2PP) +=
2657 psmouse-$(CONFIG_MOUSE_PS2_LIFEBOOK) += lifebook.o
2658 psmouse-$(CONFIG_MOUSE_PS2_TRACKPOINT) += trackpoint.o
2659 psmouse-$(CONFIG_MOUSE_PS2_TOUCHKIT) += touchkit_ps2.o
2660 +psmouse-$(CONFIG_MOUSE_PS2_OLPC) += olpc.o
2661 diff -purN linux_2.6.24_org/drivers/input/mouse/olpc.c linux_2.6.24_olpc/drivers/input/mouse/olpc.c
2662 --- linux_2.6.24_org/drivers/input/mouse/olpc.c 1970-01-01 01:00:00.000000000 +0100
2663 +++ linux_2.6.24_olpc/drivers/input/mouse/olpc.c 2008-02-15 18:59:14.000000000 +0000
2664 @@ -0,0 +1,837 @@
2665 +/*
2666 + * OLPC touchpad PS/2 mouse driver
2667 + *
2668 + * Copyright (c) 2006-2008 One Laptop Per Child
2669 + * Authors:
2670 + * Zephaniah E. Hull
2671 + * Andres Salomon <dilinger@laptop.org>
2672 + *
2673 + * This driver is partly based on the ALPS driver, which is:
2674 + *
2675 + * Copyright (c) 2003 Neil Brown <neilb@cse.unsw.edu.au>
2676 + * Copyright (c) 2003-2005 Peter Osterlund <petero2@telia.com>
2677 + * Copyright (c) 2004 Dmitry Torokhov <dtor@mail.ru>
2678 + * Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz>
2679 + *
2680 + * This program is free software; you can redistribute it and/or modify
2681 + * it under the terms of the GNU General Public License version 2 as
2682 + * published by the Free Software Foundation.
2683 + */
2684 +
2685 +/*
2686 + * The touchpad on the OLPC is fairly wide, with the entire area usable
2687 + * as a tablet (Pen Tablet/PT), and the center 1/3rd also usable as a
2688 + * touchpad (Glide Sensor/GS). The spec from ALPS is available from
2689 + * <http://wiki.laptop.org/go/Touch_Pad/Tablet>. It refers to this
2690 + * device as HGPK (Hybrid GS, PT, and Keymatrix).
2691 + *
2692 + * Earlier version of the device had simultaneous reporting; however, that
2693 + * was removed. Instead, the device now reports packets in one mode, and
2694 + * tells the driver when a mode switch needs to happen.
2695 + */
2696 +
2697 +#define DEBUG
2698 +#include <linux/input.h>
2699 +#include <linux/serio.h>
2700 +#include <linux/libps2.h>
2701 +#include <linux/delay.h>
2702 +#include <asm/olpc.h>
2703 +
2704 +#include "psmouse.h"
2705 +#include "olpc.h"
2706 +
2707 +static int tpdebug;
2708 +module_param(tpdebug, int, 0644);
2709 +
2710 +static int ignore_delta = 60;
2711 +module_param(ignore_delta, int, 0644);
2712 +MODULE_PARM_DESC(ignore_delta, "ignore packets that cause an X or Y delta larger than this value.");
2713 +
2714 +/*
2715 + * With older hardware, a finger-up event is sometimes not sent. If it's been
2716 + * more than 50mS since the last packet, we can safely assume that there was
2717 + * a finger-up event that we never received.
2718 + */
2719 +static void hgpk_fingerup_hack(struct psmouse *psmouse, struct hgpk_packet *p)
2720 +{
2721 + struct hgpk_data *priv = psmouse->private;
2722 + struct timeval now_tv;
2723 + s64 now_ns;
2724 +
2725 + if (psmouse->model >= HGPK_MODEL_C)
2726 + return;
2727 +
2728 + if (p->gs_down || p->pt_down) {
2729 + do_gettimeofday(&now_tv);
2730 + now_ns = timeval_to_ns(&now_tv);
2731 +
2732 + if (priv->late && now_ns >= priv->late) {
2733 + struct input_dev *pt = psmouse->dev;
2734 + struct input_dev *gs = priv->gs;
2735 +
2736 + input_report_key(pt, BTN_TOUCH, 0);
2737 + input_report_key(gs, BTN_TOUCH, 0);
2738 + input_sync(pt);
2739 + input_sync(gs);
2740 + hgpk_dbg(psmouse, "Missing finger-up packet detected, "
2741 + "working around buggy hardware.\n");
2742 + }
2743 + priv->late = now_ns + (50 * NSEC_PER_MSEC);
2744 + } else
2745 + priv->late = 0;
2746 +}
2747 +
2748 +/*
2749 + * C and D series touchpads send an extra finger-up packet to ensure we've
2750 + * seen it. That's all well and good, but for some uncomprehensible reason
2751 + * they sometimes also get stuck in a state where they also send an
2752 + * extra finger-down packet with coordinates of x=0, y=0. This royally
2753 + * screws relative positioning; end users see it as the touchpad jumping
2754 + * around when they first put their finger down. This works around that.
2755 + *
2756 + * *Sigh*. ALPS..
2757 + */
2758 +static void hgpk_fingerdown_hack(struct psmouse *psmouse, struct hgpk_packet *p)
2759 +{
2760 + if (psmouse->model < HGPK_MODEL_C)
2761 + return;
2762 +
2763 + /* we only care about x=0, y=0 packets */
2764 + if (p->x != 0 || p->y != 0)
2765 + return;
2766 +
2767 + /*
2768 + * if we're a gs_down packet but we were not previously down,
2769 + * we're going to assume that this is one of those spurious packets
2770 + * that needs to be worked around.
2771 + */
2772 + if (p->gs_down && !test_bit(BTN_TOUCH, p->dev->key)) {
2773 + hgpk_dbg(psmouse, "spurious GS finger-down packet\n");
2774 + p->gs_down = 0;
2775 + } else if (p->pt_down && !test_bit(BTN_TOUCH, p->dev->key)) {
2776 + hgpk_dbg(psmouse, "spurious PT finger-down packet\n");
2777 + p->pt_down = 0;
2778 + }
2779 +}
2780 +
2781 +/*
2782 + * In general, we have lots of calibration problems that manifest
2783 + * themselves as jumpy mouse pointers. Miscalibration, capacitance issues
2784 + * with the hardware, etc; these make the touchpad detect errant packets
2785 + * at random places all over the place. Since we don't expect large deltas
2786 + * to ever actually be useful, we'll large axis changes that go over our
2787 + * threshold.
2788 + */
2789 +static void hgpk_big_delta_hack(struct psmouse *psmouse, struct hgpk_packet *p)
2790 +{
2791 + struct hgpk_data *priv = psmouse->private;
2792 + struct input_dev *dev = p->dev;
2793 +
2794 + /* afaik, this happens on all hardware */
2795 +
2796 + /* ignore finger-up packets */
2797 + if (!p->pt_down && !p->gs_down)
2798 + goto done;
2799 +
2800 + /* ensure that we're not a finger-down packet */
2801 + if ((p->pt_down && !test_bit(BTN_TOUCH, dev->key)) ||
2802 + (p->gs_down && !test_bit(BTN_TOUCH, dev->key)))
2803 + goto done;
2804 +
2805 + if (abs(dev->abs[ABS_X] - p->x) > ignore_delta ||
2806 + abs(dev->abs[ABS_Y] - p->y) > ignore_delta) {
2807 + hgpk_dbg(psmouse, "axis change (%d,%d) => (%d,%d) is over "
2808 + "delta threshold\n", dev->abs[ABS_X],
2809 + dev->abs[ABS_Y], p->x, p->y);
2810 + input_report_key(dev, BTN_TOUCH, 0);
2811 + input_sync(dev);
2812 +
2813 +
2814 + /* two in a row is a pretty good indicator of miscalibration */
2815 + if (priv->axis_errors++) {
2816 + /* wait 2s for finger removal, and then recalibrate */
2817 + queue_delayed_work(kpsmoused_wq, &priv->recalib_wq,
2818 + msecs_to_jiffies(2000));
2819 + priv->axis_errors = 0;
2820 + }
2821 + return;
2822 + }
2823 +done:
2824 + priv->axis_errors = 0;
2825 +}
2826 +
2827 +/*
2828 + * This is my favorite touchpad hardware bug. I'm entirely not sure what
2829 + * triggers it (I've seen it triggered while the laptop was left on overnight,
2830 + * but my cat could have very well been using it/sleeping on it). However,
2831 + * the touchpad will randomly get stuck in a state where it constantly spews
2832 + * packets without a finger being on it. A recalibration will fix it, but
2833 + * without that it will go on for days (auto-recalibration doesn't catch it,
2834 + * either). The packets tend to either have the same coordinates, or be
2835 + * 1px away from each other; ie, (283,139,6) -> (284,139,5) -> (285,139,5) ->
2836 + * (286,139,6) -> (286,139,6) -> etc. We have a number of workarounds here..
2837 + */
2838 +static void hgpk_spewing_hack(struct psmouse *psmouse, struct hgpk_packet *p)
2839 +{
2840 + struct hgpk_data *priv = psmouse->private;
2841 + struct input_dev *dev = p->dev;
2842 + int repeat_axes;
2843 +
2844 + if (psmouse->model < HGPK_MODEL_C)
2845 + return;
2846 +
2847 + /* ignore 0, 0 packets */
2848 + if (p->x == 0 && p->y == 0)
2849 + return;
2850 +
2851 + /* PT packets don't count */
2852 + if (p->pt_down) {
2853 + priv->repeat_pkts = 0;
2854 + return;
2855 + }
2856 +
2857 + /*
2858 + * If we see 2s+ worth of packets that have at least 2 axis deltas of
2859 + * only 1px, that's a good indication that we're spewing packets.
2860 + * We're going to ignore z=15, though; that's pretty indicative of
2861 + * an actual finger on the touchpad just staying still.
2862 + */
2863 + if (p->z == 0 || p->z == 15)
2864 + goto next_hack;
2865 + repeat_axes = abs(p->x - dev->abs[ABS_X]) < 2 ? 1 : 0;
2866 + repeat_axes += abs(p->y - dev->abs[ABS_Y]) < 2 ? 1 : 0;
2867 + repeat_axes += abs(p->z - dev->abs[ABS_PRESSURE]) < 2 ? 1 : 0;
2868 + if (repeat_axes > 1) {
2869 + priv->repeat_pkts++;
2870 + /* we get 1 packet about every 24mS */
2871 + if (priv->repeat_pkts > 83) {
2872 + queue_delayed_work(kpsmoused_wq, &priv->recalib_wq, 0);
2873 + priv->repeat_pkts = 0;
2874 + }
2875 + }
2876 + else
2877 + priv->repeat_pkts = 0;
2878 + return;
2879 +
2880 +next_hack:
2881 + /*
2882 + * 10s of y and z not changing is another kind of miscalibration.
2883 + */
2884 + repeat_axes = (p->y == dev->abs[ABS_Y]) ? 1 : 0;
2885 + repeat_axes += (p->z == dev->abs[ABS_PRESSURE]) ? 1 : 0;
2886 + if (repeat_axes > 1) {
2887 + priv->repeat_pkts++;
2888 + if (priv->repeat_pkts > 416) {
2889 + queue_delayed_work(kpsmoused_wq, &priv->recalib_wq, 0);
2890 + priv->repeat_pkts = 0;
2891 + }
2892 + }
2893 + else
2894 + priv->repeat_pkts = 0;
2895 +}
2896 +
2897 +/*
2898 + * HGPK Advanced Mode - single-mode format
2899 + *
2900 + * byte 0(PT): 1 1 0 0 1 1 1 1
2901 + * byte 0(GS): 1 1 1 1 1 1 1 1
2902 + * byte 1: 0 x6 x5 x4 x3 x2 x1 x0
2903 + * byte 2(PT): 0 0 x9 x8 x7 ? pt-dsw 0
2904 + * byte 2(GS): 0 x10 x9 x8 x7 ? gs-dsw pt-dsw
2905 + * byte 3: 0 y9 y8 y7 1 0 swr swl
2906 + * byte 4: 0 y6 y5 y4 y3 y2 y1 y0
2907 + * byte 5: 0 z6 z5 z4 z3 z2 z1 z0
2908 + *
2909 + * ?'s are not defined in the protocol spec, may vary between models.
2910 + *
2911 + * swr/swl are the left/right buttons.
2912 + *
2913 + * pt-dsw/gs-dsw indicate that the pt/gs sensor is detecting a
2914 + * pen/finger
2915 + */
2916 +
2917 +static int hgpk_validate_byte(unsigned char *packet, int pktcnt)
2918 +{
2919 + BUG_ON(pktcnt < 1);
2920 +
2921 + if (packet[0] != HGPK_PT && packet[0] != HGPK_GS)
2922 + return -1;
2923 +
2924 + /* bytes 2 - 6 should have 0 in the highest bit */
2925 + if (pktcnt >= 2 && pktcnt <= 6 && (packet[pktcnt - 1] & 0x80))
2926 + return -1;
2927 +
2928 + return 0;
2929 +}
2930 +
2931 +static void hgpk_decode_packet(struct psmouse *psmouse, struct hgpk_packet *p)
2932 +{
2933 + unsigned char *packet = psmouse->packet;
2934 +
2935 + BUG_ON(psmouse->pktcnt < 6);
2936 +
2937 + p->left = packet[3] & 1;
2938 + p->right = !!(packet[3] & 2);
2939 + p->x = packet[1] | ((packet[2] & 0x78) << 4);
2940 + p->y = packet[4] | ((packet[3] & 0x70) << 3);
2941 + p->z = packet[5];
2942 +
2943 + if (packet[0] == HGPK_GS) {
2944 + p->pt_down = !!(packet[2] & 1);
2945 + p->gs_down = !!(packet[2] & 2);
2946 + p->dev = ((struct hgpk_data *) psmouse->private)->gs;
2947 + if (p->pt_down) {
2948 + /* we miss spurious PT finger-downs if pt_down is set */
2949 + p->mode_switch = HGPK_PT;
2950 + p->pt_down = 0;
2951 + } else {
2952 + p->mode_switch = 0;
2953 + }
2954 + } else if (packet[0] == HGPK_PT) {
2955 + p->pt_down = !!(packet[2] & 2);
2956 + p->gs_down = 0;
2957 + p->dev = psmouse->dev;
2958 + p->mode_switch = !p->pt_down ? HGPK_GS : 0;
2959 + }
2960 +
2961 + if (tpdebug) {
2962 + hgpk_dbg(psmouse, "l=%d r=%d p=%d g=%d x=%d y=%d z=%d m=%x\n",
2963 + p->left, p->right, p->pt_down, p->gs_down,
2964 + p->x, p->y, p->z, p->mode_switch);
2965 + }
2966 +}
2967 +
2968 +static void hgpk_process_packet_gspt(struct psmouse *psmouse)
2969 +{
2970 + struct hgpk_data *priv = psmouse->private;
2971 + struct input_dev *pt = psmouse->dev;
2972 + struct input_dev *gs = priv->gs;
2973 + struct hgpk_packet pkt;
2974 +
2975 + hgpk_decode_packet(psmouse, &pkt);
2976 +
2977 + hgpk_fingerup_hack(psmouse, &pkt);
2978 + hgpk_fingerdown_hack(psmouse, &pkt);
2979 + hgpk_big_delta_hack(psmouse, &pkt);
2980 + hgpk_spewing_hack(psmouse, &pkt);
2981 +
2982 + input_report_key(pt, BTN_LEFT, pkt.left);
2983 + input_report_key(pt, BTN_RIGHT, pkt.right);
2984 + input_report_key(pt, BTN_TOUCH, pkt.pt_down);
2985 +
2986 + input_report_key(gs, BTN_LEFT, pkt.left);
2987 + input_report_key(gs, BTN_RIGHT, pkt.right);
2988 + input_report_key(gs, BTN_TOUCH, pkt.gs_down);
2989 +
2990 + input_report_abs(pkt.dev, ABS_X, pkt.x);
2991 + input_report_abs(pkt.dev, ABS_Y, pkt.y);
2992 + input_report_abs(pkt.dev, ABS_PRESSURE, pkt.z);
2993 +
2994 + input_sync(pt);
2995 + input_sync(gs);
2996 +
2997 + if (priv->recalib_window) {
2998 + if (time_before(jiffies, priv->recalib_window)) {
2999 + /*
3000 + * ugh, got a packet inside our recalibration
3001 + * window, schedule another recalibration.
3002 + */
3003 + hgpk_dbg(psmouse, "packet inside calibration window, "
3004 + "queueing another recalibration\n");
3005 + queue_delayed_work(kpsmoused_wq, &priv->recalib_wq,
3006 + msecs_to_jiffies(1000));
3007 + }
3008 + priv->recalib_window = 0;
3009 + }
3010 +
3011 + if (psmouse->model != HGPK_MODEL_A) {
3012 + if (priv->pending_mode && (!pkt.mode_switch ||
3013 + priv->current_mode == pkt.mode_switch)) {
3014 + priv->pending_mode = 0;
3015 + cancel_delayed_work(&priv->switch_wq);
3016 + }
3017 + else if (priv->pending_mode != pkt.mode_switch) {
3018 + priv->pending_mode = pkt.mode_switch;
3019 +
3020 + /* allow for spurious mode_switch packets by delaying */
3021 + queue_delayed_work(kpsmoused_wq, &priv->switch_wq,
3022 + msecs_to_jiffies(50));
3023 + }
3024 + }
3025 +}
3026 +
3027 +static psmouse_ret_t hgpk_process_byte(struct psmouse *psmouse)
3028 +{
3029 + if (hgpk_validate_byte(psmouse->packet, psmouse->pktcnt)) {
3030 + hgpk_dbg(psmouse, "%s: (%d) %02x %02x %02x %02x %02x %02x\n",
3031 + __func__, psmouse->pktcnt, psmouse->packet[0],
3032 + psmouse->packet[1], psmouse->packet[2],
3033 + psmouse->packet[3], psmouse->packet[4],
3034 + psmouse->packet[5]);
3035 + return PSMOUSE_BAD_DATA;
3036 + }
3037 +
3038 + if (psmouse->pktcnt == 6) {
3039 + hgpk_process_packet_gspt(psmouse);
3040 + return PSMOUSE_FULL_PACKET;
3041 + }
3042 +
3043 + return PSMOUSE_GOOD_DATA;
3044 +}
3045 +
3046 +static int hgpk_force_recalibrate(struct psmouse *psmouse)
3047 +{
3048 + struct ps2dev *ps2dev = &psmouse->ps2dev;
3049 + struct hgpk_data *priv = psmouse->private;
3050 + struct input_dev *pt = psmouse->dev;
3051 + struct input_dev *gs = priv->gs;
3052 +
3053 + /* C-series touchpads added the recalibrate command */
3054 + if (psmouse->model < HGPK_MODEL_C)
3055 + return 0;
3056 +
3057 + if (ps2_command(ps2dev, NULL, 0xf5) ||
3058 + ps2_command(ps2dev, NULL, 0xf5) ||
3059 + ps2_command(ps2dev, NULL, 0xe6) ||
3060 + ps2_command(ps2dev, NULL, 0xf5))
3061 + return -1;
3062 +
3063 + /* send a finger-up event so the cursor doesn't jump around */
3064 + input_report_key(pt, BTN_TOUCH, 0);
3065 + input_report_key(gs, BTN_TOUCH, 0);
3066 + input_sync(pt);
3067 + input_sync(gs);
3068 +
3069 + /* according to ALPS, 150mS is required for recalibration */
3070 + msleep(150);
3071 +
3072 + /*
3073 + * XXX: If a finger is down during this delay, recalibration will
3074 + * detect capacitance incorrectly. This is a hardware bug, and
3075 + * we may need to work around that here.
3076 + */
3077 +
3078 + if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE))
3079 + return -1;
3080 +
3081 + /*
3082 + * After we recalibrate, we shouldn't get any packets for 2s. If
3083 + * we do, it's likely that someone's finger was on the touchpad.
3084 + * If someone's finger *was* on the touchpad, it's probably
3085 + * miscalibrated. So, we should schedule another recalibration
3086 + */
3087 + priv->recalib_window = jiffies + msecs_to_jiffies(2000);
3088 +
3089 + return 0;
3090 +}
3091 +
3092 +static enum hgpk_model_t hgpk_get_model(struct psmouse *psmouse)
3093 +{
3094 + struct ps2dev *ps2dev = &psmouse->ps2dev;
3095 + unsigned char param[3];
3096 +
3097 + /* E7, E7, E7, E9 gets us a 3 byte identifier */
3098 + if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
3099 + ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
3100 + ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
3101 + ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
3102 + return -EIO;
3103 +
3104 + hgpk_dbg(psmouse, "ID: %02x %02x %02x", param[0], param[1], param[2]);
3105 +
3106 + /* HGPK signature: 0x67, 0x00, 0x<model> */
3107 + if (param[0] != 0x67 || param[1] != 0x00)
3108 + return -ENODEV;
3109 +
3110 + hgpk_info(psmouse, "OLPC touchpad revision 0x%x\n", param[2]);
3111 + return param[2];
3112 +}
3113 +
3114 +/*
3115 + * Touchpad should be disabled before calling this!
3116 + */
3117 +static int hgpk_new_mode(struct psmouse *psmouse, int mode)
3118 +{
3119 + struct ps2dev *ps2dev = &psmouse->ps2dev;
3120 + struct hgpk_data *priv = psmouse->private;
3121 +
3122 + /*
3123 + * PT mode: F2, F2, F2, E7
3124 + * GS mode: F2, F2, F2, E6
3125 + */
3126 + if (ps2_command(ps2dev, NULL, 0xF2) ||
3127 + ps2_command(ps2dev, NULL, 0xF2) ||
3128 + ps2_command(ps2dev, NULL, 0xF2))
3129 + return -EIO;
3130 +
3131 + if (mode == HGPK_GS) {
3132 + if (ps2_command(ps2dev, NULL, 0xE6))
3133 + return -EIO;
3134 + } else {
3135 + if (ps2_command(ps2dev, NULL, 0xE7))
3136 + return -EIO;
3137 + }
3138 +
3139 + if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE))
3140 + return -EIO;
3141 +
3142 + /* tell the irq handler to stop ignoring packets */
3143 + psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
3144 +
3145 + priv->current_mode = mode;
3146 + priv->pending_mode = 0;
3147 + if (tpdebug)
3148 + hgpk_warn(psmouse, "Switched to mode 0x%x successful.\n", mode);
3149 +
3150 + return 0;
3151 +}
3152 +
3153 +static int hgpk_advanced_mode(struct psmouse *psmouse)
3154 +{
3155 + struct ps2dev *ps2dev = &psmouse->ps2dev;
3156 +
3157 + /* Switch to 'Advanced mode.', four disables in a row. */
3158 + if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
3159 + ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
3160 + ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
3161 + ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE))
3162 + return -1;
3163 +
3164 + return hgpk_new_mode(psmouse, HGPK_GS);
3165 +}
3166 +
3167 +/*
3168 + * This kills power to the touchpad; according to ALPS, current consumption
3169 + * goes down to 50uA after running this. To turn power back on, we drive
3170 + * MS-DAT low.
3171 + */
3172 +static int hgpk_toggle_power(struct psmouse *psmouse, int enable)
3173 +{
3174 + struct ps2dev *ps2dev = &psmouse->ps2dev;
3175 + int timeo;
3176 +
3177 + /* Added on D-series touchpads */
3178 + if (psmouse->model < HGPK_MODEL_D)
3179 + return 0;
3180 +
3181 + if (enable) {
3182 + psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
3183 +
3184 + /*
3185 + * Sending a byte will drive MS-DAT low; this will wake up
3186 + * the controller. Once we get an ACK back from it, it
3187 + * means we can continue with the touchpad re-init. ALPS
3188 + * tells us that 1s should be long enough, so set that as
3189 + * the upper bound.
3190 + */
3191 + for (timeo = 20; timeo > 0; timeo--) {
3192 + if (!ps2_sendbyte(&psmouse->ps2dev,
3193 + PSMOUSE_CMD_DISABLE, 20))
3194 + break;
3195 + msleep(50);
3196 + }
3197 +
3198 + psmouse_reset(psmouse);
3199 +
3200 + if (hgpk_advanced_mode(psmouse)) {
3201 + hgpk_err(psmouse, "Failed to reinit touchpad!\n");
3202 + return -1;
3203 + }
3204 + } else {
3205 + hgpk_dbg(psmouse, "Powering off touchpad.\n");
3206 + psmouse_set_state(psmouse, PSMOUSE_IGNORE);
3207 +
3208 + if (ps2_command(ps2dev, NULL, 0xec) ||
3209 + ps2_command(ps2dev, NULL, 0xec) ||
3210 + ps2_command(ps2dev, NULL, 0xea))
3211 + return -1;
3212 + /* probably won't see an ACK, the touchpad will be off */
3213 + ps2_sendbyte(&psmouse->ps2dev, 0xec, 20);
3214 + }
3215 +
3216 + return 0;
3217 +}
3218 +
3219 +/*
3220 + * poll the touchpad for current motion packet.
3221 + * Used in resync.
3222 + * Note: We can't poll, so always return failure.
3223 + */
3224 +static int hgpk_poll(struct psmouse *psmouse)
3225 +{
3226 + return -1;
3227 +}
3228 +
3229 +static int hgpk_reconnect(struct psmouse *psmouse)
3230 +{
3231 + if (olpc_board_at_least(olpc_board(0xb2)))
3232 + if (psmouse->ps2dev.serio->dev.power.power_state.event != PM_EVENT_ON)
3233 + return 0;
3234 +
3235 + psmouse_reset(psmouse);
3236 +
3237 + if (hgpk_advanced_mode(psmouse)) {
3238 + hgpk_err(psmouse, "failed to reenable advanced mode.\n");
3239 + return -1;
3240 + }
3241 +
3242 + return 0;
3243 +}
3244 +
3245 +static ssize_t hgpk_show_powered(struct device *dev,
3246 + struct device_attribute *attr, char *buf)
3247 +{
3248 + struct serio *serio = to_serio_port(dev);
3249 + struct psmouse *psmouse;
3250 + struct hgpk_data *priv;
3251 + int retval;
3252 +
3253 + retval = serio_pin_driver(serio);
3254 + if (retval)
3255 + return retval;
3256 +
3257 + psmouse = serio_get_drvdata(serio);
3258 + priv = psmouse->private;
3259 +
3260 + retval = sprintf(buf, "%d\n", priv->powered);
3261 + serio_unpin_driver(serio);
3262 + return retval;
3263 +}
3264 +
3265 +static ssize_t hgpk_set_powered(struct device *dev,
3266 + struct device_attribute *attr, const char *buf, size_t count)
3267 +{
3268 + struct serio *serio = to_serio_port(dev);
3269 + struct psmouse *psmouse;
3270 + struct hgpk_data *priv;
3271 + unsigned long val;
3272 + int retval;
3273 +
3274 + if (*buf == '1')
3275 + val = 1;
3276 + else if (*buf == '0')
3277 + val = 0;
3278 + else
3279 + return -EINVAL;
3280 +
3281 + retval = serio_pin_driver(serio);
3282 + if (retval)
3283 + return retval;
3284 +
3285 +/*
3286 + * FUCK IT. I don't fucking care. locking in psmouse is fucking retarded!
3287 + retval = mutex_lock_interruptible(&psmouse_mutex);
3288 + if (retval)
3289 + goto out_unpin;
3290 +*/
3291 +
3292 + psmouse = serio_get_drvdata(serio);
3293 + priv = psmouse->private;
3294 +
3295 + if (val == priv->powered)
3296 + goto done;
3297 +
3298 + retval = hgpk_toggle_power(psmouse, val);
3299 + if (!retval)
3300 + priv->powered = val;
3301 +
3302 +done:
3303 + serio_unpin_driver(serio);
3304 + return retval ? retval : count;
3305 +}
3306 +
3307 +static DEVICE_ATTR(powered, S_IWUSR | S_IRUGO, hgpk_show_powered,
3308 + hgpk_set_powered);
3309 +
3310 +static void hgpk_disconnect(struct psmouse *psmouse)
3311 +{
3312 + struct hgpk_data *priv = psmouse->private;
3313 +
3314 + device_remove_file(&psmouse->ps2dev.serio->dev, &dev_attr_powered);
3315 + psmouse_reset(psmouse);
3316 + flush_scheduled_work();
3317 + input_unregister_device(priv->gs);
3318 + kfree(priv);
3319 +}
3320 +
3321 +static void hgpk_mode_switch(struct work_struct *work)
3322 +{
3323 + struct delayed_work *w = container_of(work, struct delayed_work, work);
3324 + struct hgpk_data *priv = container_of(w, struct hgpk_data, switch_wq);
3325 + struct psmouse *psmouse = priv->psmouse;
3326 + struct ps2dev *ps2dev = &psmouse->ps2dev;
3327 + int pending_mode;
3328 +
3329 + if (tpdebug)
3330 + hgpk_dbg(psmouse, "Starting mode switch to 0x%x. [%lu]\n",
3331 + priv->pending_mode, jiffies);
3332 +
3333 + if (priv->pending_mode == priv->current_mode) {
3334 + priv->pending_mode = 0;
3335 + hgpk_dbg(psmouse, "Already in target mode, no-op.\n");
3336 + return;
3337 + }
3338 +
3339 + /* tell the irq handler to ignore any further packets */
3340 + psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
3341 + priv->late = 0;
3342 +
3343 + if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE))
3344 + goto bad;
3345 +
3346 + /*
3347 + * ALPS tells us that it may take up to 20msec for the disable to
3348 + * take effect; however, ps2_command() will wait up to 200msec for
3349 + * the ACK to come back (and I'm assuming that by the time the
3350 + * hardware sends back its ACK, it has stopped sending bytes).
3351 + */
3352 + pending_mode = priv->pending_mode;
3353 +
3354 + if (hgpk_new_mode(psmouse, priv->pending_mode))
3355 + goto bad;
3356 +
3357 + /*
3358 + * Deal with a potential race condition.
3359 + *
3360 + * If there is a brief tap of a stylus or a fingernail that
3361 + * triggers a mode switch to PT mode, and the stylus/fingernail is
3362 + * lifted after the DISABLE above, but before we reenable in the
3363 + * new mode then we can get stuck in PT mode.
3364 + */
3365 + if (pending_mode == HGPK_PT) {
3366 + priv->pending_mode = HGPK_GS;
3367 + queue_delayed_work(kpsmoused_wq, &priv->switch_wq,
3368 + msecs_to_jiffies(50));
3369 + }
3370 +
3371 + return;
3372 +bad:
3373 + hgpk_warn(psmouse, "Failure to switch modes, resetting device...\n");
3374 + hgpk_reconnect(psmouse);
3375 +}
3376 +
3377 +static void hgpk_recalib_work(struct work_struct *work)
3378 +{
3379 + struct delayed_work *w = container_of(work, struct delayed_work, work);
3380 + struct hgpk_data *priv = container_of(w, struct hgpk_data, recalib_wq);
3381 + struct psmouse *psmouse = priv->psmouse;
3382 +
3383 + if (tpdebug)
3384 + hgpk_dbg(psmouse, "Recalibrating touchpad..\n");
3385 +
3386 + if (hgpk_force_recalibrate(psmouse))
3387 + hgpk_err(psmouse, "Recalibration failed!\n");
3388 +}
3389 +
3390 +int olpc_init(struct psmouse *psmouse)
3391 +{
3392 + struct hgpk_data *priv;
3393 + struct input_dev *pt = psmouse->dev;
3394 + struct input_dev *gs;
3395 +
3396 + priv = kzalloc(sizeof(struct hgpk_data), GFP_KERNEL);
3397 + gs = input_allocate_device();
3398 + if (!priv || !gs)
3399 + goto init_fail;
3400 +
3401 + psmouse->private = priv;
3402 + priv->gs = gs;
3403 + priv->psmouse = psmouse;
3404 + priv->powered = 1;
3405 +
3406 + psmouse_reset(psmouse);
3407 +
3408 + if (hgpk_advanced_mode(psmouse)) {
3409 + hgpk_err(psmouse, "failed to enable advanced mode\n");
3410 + goto init_fail;
3411 + }
3412 +
3413 + /* Unset things that psmouse-base sets that we don't have */
3414 + pt->evbit[0] &= ~BIT(EV_REL);
3415 + pt->keybit[LONG(BTN_MOUSE)] &= ~BIT(BTN_MIDDLE);
3416 + pt->relbit[0] &= ~(BIT(REL_X) | BIT(REL_Y));
3417 +
3418 + /* Set all the things we *do* have */
3419 + set_bit(EV_KEY, pt->evbit);
3420 + set_bit(EV_ABS, pt->evbit);
3421 +
3422 + set_bit(BTN_LEFT, pt->keybit);
3423 + set_bit(BTN_RIGHT, pt->keybit);
3424 + set_bit(BTN_TOUCH, pt->keybit);
3425 +
3426 + input_set_abs_params(pt, ABS_X, 2, 1000, 0, 0);
3427 + input_set_abs_params(pt, ABS_Y, 0, 717, 0, 0);
3428 + input_set_abs_params(pt, ABS_PRESSURE, 0, 127, 0, 0);
3429 +
3430 + snprintf(priv->phys, sizeof(priv->phys),
3431 + "%s/input1", psmouse->ps2dev.serio->phys);
3432 + gs->phys = priv->phys;
3433 + gs->name = "OLPC ALPS GlideSensor";
3434 + gs->id.bustype = BUS_I8042;
3435 + gs->id.vendor = 0x0002;
3436 + gs->id.product = PSMOUSE_OLPC;
3437 + gs->id.version = psmouse->model;
3438 +
3439 + set_bit(EV_KEY, gs->evbit);
3440 + set_bit(EV_ABS, gs->evbit);
3441 +
3442 + set_bit(BTN_LEFT, gs->keybit);
3443 + set_bit(BTN_RIGHT, gs->keybit);
3444 + set_bit(BTN_TOUCH, gs->keybit);
3445 +
3446 + input_set_abs_params(gs, ABS_X, 350, 512, 0, 0);
3447 + input_set_abs_params(gs, ABS_Y, 70, 325, 0, 0);
3448 + input_set_abs_params(gs, ABS_PRESSURE, 0, 15, 0, 0);
3449 +
3450 + if (input_register_device(gs)) {
3451 + hgpk_err(psmouse, "Failed to register GlideSensor\n");
3452 + goto init_fail;
3453 + }
3454 +
3455 + psmouse->protocol_handler = hgpk_process_byte;
3456 + psmouse->poll = hgpk_poll;
3457 + psmouse->disconnect = hgpk_disconnect;
3458 + psmouse->reconnect = hgpk_reconnect;
3459 + psmouse->pktsize = 6;
3460 +
3461 + /* Disable the idle resync. */
3462 + psmouse->resync_time = 0;
3463 + /* Reset after a lot of bad bytes. */
3464 + psmouse->resetafter = 1024;
3465 +
3466 + INIT_DELAYED_WORK(&priv->switch_wq, hgpk_mode_switch);
3467 + INIT_DELAYED_WORK(&priv->recalib_wq, hgpk_recalib_work);
3468 +
3469 + if (device_create_file(&psmouse->ps2dev.serio->dev,
3470 + &dev_attr_powered)) {
3471 + hgpk_err(psmouse, "Failed to create sysfs attribute\n");
3472 + goto attr_fail;
3473 + }
3474 +
3475 +
3476 + return 0;
3477 +
3478 +attr_fail:
3479 + input_unregister_device(gs);
3480 + gs = NULL;
3481 +init_fail:
3482 + input_free_device(gs);
3483 + kfree(priv);
3484 + return -1;
3485 +}
3486 +
3487 +int olpc_detect(struct psmouse *psmouse, int set_properties)
3488 +{
3489 + int version;
3490 +
3491 + version = hgpk_get_model(psmouse);
3492 + if (version < 0)
3493 + return version;
3494 +
3495 + if (set_properties) {
3496 + psmouse->vendor = "ALPS";
3497 + psmouse->name = "PenTablet";
3498 + psmouse->model = version;
3499 + }
3500 + return 0;
3501 +}
3502 diff -purN linux_2.6.24_org/drivers/input/mouse/olpc.h linux_2.6.24_olpc/drivers/input/mouse/olpc.h
3503 --- linux_2.6.24_org/drivers/input/mouse/olpc.h 1970-01-01 01:00:00.000000000 +0100
3504 +++ linux_2.6.24_olpc/drivers/input/mouse/olpc.h 2008-02-15 18:59:14.000000000 +0000
3505 @@ -0,0 +1,78 @@
3506 +/*
3507 + * OLPC touchpad PS/2 mouse driver
3508 + *
3509 + * Copyright (c) 2006 One Laptop Per Child, inc.
3510 + *
3511 + * This driver is partly based on the ALPS driver.
3512 + * Copyright (c) 2003 Peter Osterlund <petero2@telia.com>
3513 + * Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz>
3514 + *
3515 + * This program is free software; you can redistribute it and/or modify it
3516 + * under the terms of the GNU General Public License version 2 as published by
3517 + * the Free Software Foundation.
3518 + */
3519 +
3520 +#ifndef _OLPC_H
3521 +#define _OLPC_H
3522 +
3523 +enum hgpk_model_t {
3524 + HGPK_MODEL_PreA = 0x0a, /* pre-B1s */
3525 + HGPK_MODEL_A = 0x14, /* found on B1s, PT disabled in hardware */
3526 + HGPK_MODEL_B = 0x28, /* B2s, has capacitance issues */
3527 + HGPK_MODEL_C = 0x3c,
3528 + HGPK_MODEL_D = 0x50, /* C1, mass production */
3529 +};
3530 +
3531 +#define HGPK_GS 0xff /* The GlideSensor */
3532 +#define HGPK_PT 0xcf /* The PenTablet */
3533 +
3534 +struct hgpk_packet {
3535 + struct input_dev *dev;
3536 + int x, y, z;
3537 + unsigned char mode_switch;
3538 + unsigned int pt_down:1, gs_down:1;
3539 + unsigned int left:1, right:1;
3540 +};
3541 +
3542 +struct hgpk_data {
3543 + struct input_dev *gs; /* GlideSensor */
3544 + struct psmouse *psmouse;
3545 + char name[32]; /* Name */
3546 + char phys[32]; /* Phys */
3547 + int pending_mode;
3548 + int current_mode;
3549 + s64 late;
3550 + int axis_errors;
3551 + int repeat_pkts;
3552 + int powered;
3553 + unsigned long recalib_window;
3554 + struct delayed_work switch_wq;
3555 + struct delayed_work recalib_wq;
3556 +};
3557 +
3558 +#define hgpk_dbg(psmouse, format, arg...) \
3559 + dev_dbg(&(psmouse)->ps2dev.serio->dev, format, ## arg)
3560 +#define hgpk_err(psmouse, format, arg...) \
3561 + dev_err(&(psmouse)->ps2dev.serio->dev, format, ## arg)
3562 +#define hgpk_info(psmouse, format, arg...) \
3563 + dev_info(&(psmouse)->ps2dev.serio->dev, format, ## arg)
3564 +#define hgpk_warn(psmouse, format, arg...) \
3565 + dev_warn(&(psmouse)->ps2dev.serio->dev, format, ## arg)
3566 +#define hgpk_notice(psmouse, format, arg...) \
3567 + dev_notice(&(psmouse)->ps2dev.serio->dev, format, ## arg)
3568 +
3569 +#ifdef CONFIG_MOUSE_PS2_OLPC
3570 +int olpc_detect(struct psmouse *psmouse, int set_properties);
3571 +int olpc_init(struct psmouse *psmouse);
3572 +#else
3573 +inline int olpc_detect(struct psmouse *psmouse, int set_properties)
3574 +{
3575 + return -ENOSYS;
3576 +}
3577 +inline int olpc_init(struct psmouse *psmouse)
3578 +{
3579 + return -ENOSYS;
3580 +}
3581 +#endif
3582 +
3583 +#endif
3584 diff -purN linux_2.6.24_org/drivers/input/mouse/psmouse-base.c linux_2.6.24_olpc/drivers/input/mouse/psmouse-base.c
3585 --- linux_2.6.24_org/drivers/input/mouse/psmouse-base.c 2008-02-15 20:11:51.000000000 +0000
3586 +++ linux_2.6.24_olpc/drivers/input/mouse/psmouse-base.c 2008-02-15 18:59:14.000000000 +0000
3587 @@ -26,6 +26,7 @@
3588 #include "synaptics.h"
3589 #include "logips2pp.h"
3590 #include "alps.h"
3591 +#include "olpc.h"
3592 #include "lifebook.h"
3593 #include "trackpoint.h"
3594 #include "touchkit_ps2.h"
3595 @@ -103,7 +104,7 @@ static struct attribute_group psmouse_at
3596 */
3597 static DEFINE_MUTEX(psmouse_mutex);
3598
3599 -static struct workqueue_struct *kpsmoused_wq;
3600 +struct workqueue_struct *kpsmoused_wq;
3601
3602 struct psmouse_protocol {
3603 enum psmouse_type type;
3604 @@ -221,7 +222,7 @@ static inline void __psmouse_set_state(s
3605 * is not a concern.
3606 */
3607
3608 -static void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state)
3609 +void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state)
3610 {
3611 serio_pause_rx(psmouse->ps2dev.serio);
3612 __psmouse_set_state(psmouse, new_state);
3613 @@ -320,7 +321,7 @@ static irqreturn_t psmouse_interrupt(str
3614 goto out;
3615 }
3616
3617 - if (psmouse->packet[1] == PSMOUSE_RET_ID) {
3618 + if (psmouse->packet[1] == PSMOUSE_RET_ID || psmouse->packet[1] == PSMOUSE_RET_BAT) {
3619 __psmouse_set_state(psmouse, PSMOUSE_IGNORE);
3620 serio_reconnect(serio);
3621 goto out;
3622 @@ -631,8 +632,21 @@ static int psmouse_extensions(struct psm
3623 }
3624 }
3625
3626 +/*
3627 + * Try OLPC touchpad.
3628 + */
3629 if (max_proto > PSMOUSE_IMEX) {
3630 + if (olpc_detect(psmouse, set_properties) == 0) {
3631 + if (!set_properties || olpc_init(psmouse) == 0)
3632 + return PSMOUSE_OLPC;
3633 +/*
3634 + * Init failed, try basic relative protocols
3635 + */
3636 + max_proto = PSMOUSE_IMEX;
3637 + }
3638 + }
3639
3640 + if (max_proto > PSMOUSE_IMEX) {
3641 if (genius_detect(psmouse, set_properties) == 0)
3642 return PSMOUSE_GENPS;
3643
3644 @@ -763,6 +777,14 @@ static const struct psmouse_protocol psm
3645 .detect = touchkit_ps2_detect,
3646 },
3647 #endif
3648 +#ifdef CONFIG_MOUSE_PS2_OLPC
3649 + {
3650 + .type = PSMOUSE_OLPC,
3651 + .name = "OLPC",
3652 + .alias = "olpc",
3653 + .detect = olpc_detect,
3654 + },
3655 +#endif
3656 {
3657 .type = PSMOUSE_CORTRON,
3658 .name = "CortronPS/2",
3659 diff -purN linux_2.6.24_org/drivers/input/mouse/psmouse.h linux_2.6.24_olpc/drivers/input/mouse/psmouse.h
3660 --- linux_2.6.24_org/drivers/input/mouse/psmouse.h 2008-02-15 20:11:51.000000000 +0000
3661 +++ linux_2.6.24_olpc/drivers/input/mouse/psmouse.h 2008-02-15 18:59:14.000000000 +0000
3662 @@ -88,6 +88,7 @@ enum psmouse_type {
3663 PSMOUSE_LIFEBOOK,
3664 PSMOUSE_TRACKPOINT,
3665 PSMOUSE_TOUCHKIT_PS2,
3666 + PSMOUSE_OLPC,
3667 PSMOUSE_CORTRON,
3668 PSMOUSE_AUTO /* This one should always be last */
3669 };
3670 @@ -95,7 +96,9 @@ enum psmouse_type {
3671 int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command);
3672 int psmouse_reset(struct psmouse *psmouse);
3673 void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution);
3674 +void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state);
3675
3676 +extern struct workqueue_struct *kpsmoused_wq;
3677
3678 struct psmouse_attribute {
3679 struct device_attribute dattr;
3680 diff -purN linux_2.6.24_org/drivers/input/serio/i8042.c linux_2.6.24_olpc/drivers/input/serio/i8042.c
3681 --- linux_2.6.24_org/drivers/input/serio/i8042.c 2008-02-15 20:11:51.000000000 +0000
3682 +++ linux_2.6.24_olpc/drivers/input/serio/i8042.c 2008-02-15 18:59:14.000000000 +0000
3683 @@ -874,6 +874,11 @@ static long i8042_panic_blink(long count
3684 #undef DELAY
3685
3686 #ifdef CONFIG_PM
3687 +
3688 +#ifdef CONFIG_OLPC
3689 +#include <asm/olpc.h>
3690 +#endif
3691 +
3692 /*
3693 * Here we try to restore the original BIOS settings. We only want to
3694 * do that once, when we really suspend, not when we taking memory
3695 @@ -884,8 +889,15 @@ static long i8042_panic_blink(long count
3696 static int i8042_suspend(struct platform_device *dev, pm_message_t state)
3697 {
3698 if (dev->dev.power.power_state.event != state.event) {
3699 +#ifdef CONFIG_OLPC
3700 + /* Anything newer than B2 remains powered; no reset needed */
3701 + if (!olpc_board_at_least(olpc_board_pre(0xb3))) {
3702 +#endif
3703 if (state.event == PM_EVENT_SUSPEND)
3704 i8042_controller_reset();
3705 +#ifdef CONFIG_OLPC
3706 + }
3707 +#endif
3708
3709 dev->dev.power.power_state = state;
3710 }
3711 @@ -908,9 +920,15 @@ static int i8042_resume(struct platform_
3712 if (dev->dev.power.power_state.event == PM_EVENT_ON)
3713 return 0;
3714
3715 +#ifdef CONFIG_OLPC
3716 + if (!olpc_board_at_least(olpc_board_pre(0xb3))) {
3717 +#endif
3718 error = i8042_controller_check();
3719 if (error)
3720 return error;
3721 +#ifdef CONFIG_OLPC
3722 + }
3723 +#endif
3724
3725 error = i8042_controller_selftest();
3726 if (error)
3727 diff -purN linux_2.6.24_org/drivers/input/serio/serio.c linux_2.6.24_olpc/drivers/input/serio/serio.c
3728 --- linux_2.6.24_org/drivers/input/serio/serio.c 2008-02-15 20:11:51.000000000 +0000
3729 +++ linux_2.6.24_olpc/drivers/input/serio/serio.c 2008-02-15 18:59:14.000000000 +0000
3730 @@ -910,11 +910,22 @@ static int serio_uevent(struct device *d
3731 #endif /* CONFIG_HOTPLUG */
3732
3733 #ifdef CONFIG_PM
3734 +
3735 +#ifdef CONFIG_OLPC
3736 +#include <asm/olpc.h>
3737 +#endif
3738 +
3739 static int serio_suspend(struct device *dev, pm_message_t state)
3740 {
3741 if (dev->power.power_state.event != state.event) {
3742 +#ifdef CONFIG_OLPC
3743 + if (!olpc_board_at_least(olpc_board_pre(0xb3))) {
3744 +#endif
3745 if (state.event == PM_EVENT_SUSPEND)
3746 serio_cleanup(to_serio_port(dev));
3747 +#ifdef CONFIG_OLPC
3748 + }
3749 +#endif
3750
3751 dev->power.power_state = state;
3752 }
3753 diff -purN linux_2.6.24_org/drivers/Kconfig linux_2.6.24_olpc/drivers/Kconfig
3754 --- linux_2.6.24_org/drivers/Kconfig 2008-02-15 20:11:21.000000000 +0000
3755 +++ linux_2.6.24_olpc/drivers/Kconfig 2008-02-15 18:58:34.000000000 +0000
3756 @@ -94,6 +94,8 @@ source "drivers/auxdisplay/Kconfig"
3757
3758 source "drivers/kvm/Kconfig"
3759
3760 +source "drivers/sysprof/Kconfig"
3761 +
3762 source "drivers/uio/Kconfig"
3763
3764 source "drivers/virtio/Kconfig"
3765 diff -purN linux_2.6.24_org/drivers/Makefile linux_2.6.24_olpc/drivers/Makefile
3766 --- linux_2.6.24_org/drivers/Makefile 2008-02-15 20:11:24.000000000 +0000
3767 +++ linux_2.6.24_olpc/drivers/Makefile 2008-02-15 18:58:43.000000000 +0000
3768 @@ -23,6 +23,8 @@ obj-y += char/
3769
3770 obj-$(CONFIG_CONNECTOR) += connector/
3771
3772 +obj-$(CONFIG_SYSPROF) += sysprof/
3773 +
3774 # i810fb and intelfb depend on char/agp/
3775 obj-$(CONFIG_FB_I810) += video/i810/
3776 obj-$(CONFIG_FB_INTEL) += video/intelfb/
3777 diff -purN linux_2.6.24_org/drivers/media/video/cafe_ccic.c linux_2.6.24_olpc/drivers/media/video/cafe_ccic.c
3778 --- linux_2.6.24_org/drivers/media/video/cafe_ccic.c 2008-02-15 20:11:25.000000000 +0000
3779 +++ linux_2.6.24_olpc/drivers/media/video/cafe_ccic.c 2008-02-15 18:58:44.000000000 +0000
3780 @@ -372,6 +372,10 @@ static int cafe_smbus_write_data(struct
3781 rval = value | ((command << TWSIC1_ADDR_SHIFT) & TWSIC1_ADDR);
3782 cafe_reg_write(cam, REG_TWSIC1, rval);
3783 spin_unlock_irqrestore(&cam->dev_lock, flags);
3784 + mdelay(2); /* It'll probably take about 900µs anyway, and the
3785 + CAFÉ is apparently quite sensitive to being poked
3786 + at this point. If we can work out precisely what's
3787 + going on and reduce this delay, it would be nice. */
3788
3789 /*
3790 * Time to wait for the write to complete. THIS IS A RACY
3791 @@ -907,8 +911,6 @@ static int cafe_cam_configure(struct caf
3792 struct v4l2_format fmt;
3793 int ret, zero = 0;
3794
3795 - if (cam->state != S_IDLE)
3796 - return -EINVAL;
3797 fmt.fmt.pix = cam->pix_format;
3798 ret = __cafe_cam_cmd(cam, VIDIOC_INT_INIT, &zero);
3799 if (ret == 0)
3800 @@ -2237,14 +2239,18 @@ static int cafe_pci_suspend(struct pci_d
3801 int ret;
3802 enum cafe_state cstate;
3803
3804 + mutex_lock(&cam->s_mutex);
3805 ret = pci_save_state(pdev);
3806 - if (ret)
3807 + if (ret) {
3808 + cam_warn(cam, "Unable to save PCI state\n");
3809 return ret;
3810 + }
3811 cstate = cam->state; /* HACK - stop_dma sets to idle */
3812 cafe_ctlr_stop_dma(cam);
3813 cafe_ctlr_power_down(cam);
3814 pci_disable_device(pdev);
3815 cam->state = cstate;
3816 + /* hold mutex until restore */
3817 return 0;
3818 }
3819
3820 @@ -2263,16 +2269,18 @@ static int cafe_pci_resume(struct pci_de
3821 cam_warn(cam, "Unable to re-enable device on resume!\n");
3822 return ret;
3823 }
3824 + /* we're still holding mutex from suspend */
3825 cafe_ctlr_init(cam);
3826 cafe_ctlr_power_down(cam);
3827
3828 - mutex_lock(&cam->s_mutex);
3829 - if (cam->users > 0) {
3830 - cafe_ctlr_power_up(cam);
3831 - __cafe_cam_reset(cam);
3832 - }
3833 - mutex_unlock(&cam->s_mutex);
3834 -
3835 + if (cam->users > 0) {
3836 + cafe_ctlr_power_up(cam);
3837 + __cafe_cam_reset(cam);
3838 + }
3839 + else
3840 + cafe_ctlr_power_down(cam);
3841 + mutex_unlock(&cam->s_mutex);
3842 +
3843 set_bit(CF_CONFIG_NEEDED, &cam->flags);
3844 if (cam->state == S_SPECREAD)
3845 cam->state = S_IDLE; /* Don't bother restarting */
3846 diff -purN linux_2.6.24_org/drivers/misc/Kconfig linux_2.6.24_olpc/drivers/misc/Kconfig
3847 --- linux_2.6.24_org/drivers/misc/Kconfig 2008-02-15 20:11:42.000000000 +0000
3848 +++ linux_2.6.24_olpc/drivers/misc/Kconfig 2008-02-15 18:58:52.000000000 +0000
3849 @@ -219,6 +219,11 @@ config THINKPAD_ACPI_BAY
3850
3851 If you are not sure, say Y here.
3852
3853 +config EEPROM_93CX6
3854 + tristate "EEPROM 93CX6 support"
3855 + ---help---
3856 + This is a driver for the EEPROM chipsets 93c46 and 93c66.
3857 + The driver supports both read as well as write commands.
3858
3859 config ATMEL_SSC
3860 tristate "Device driver for Atmel SSC peripheral"
3861 diff -purN linux_2.6.24_org/drivers/mmc/card/block.c linux_2.6.24_olpc/drivers/mmc/card/block.c
3862 --- linux_2.6.24_org/drivers/mmc/card/block.c 2008-02-15 20:11:13.000000000 +0000
3863 +++ linux_2.6.24_olpc/drivers/mmc/card/block.c 2008-02-15 18:58:17.000000000 +0000
3864 @@ -237,6 +237,13 @@ static int mmc_blk_issue_rq(struct mmc_q
3865 if (brq.data.blocks > card->host->max_blk_count)
3866 brq.data.blocks = card->host->max_blk_count;
3867
3868 + if (mmc_card_sd(card) && !card->host->ios.clock) {
3869 + printk(KERN_ERR "%s: I/O to stopped card\n",
3870 + req->rq_disk->disk_name);
3871 + goto cmd_err;
3872 + }
3873 + mmc_set_data_timeout(&brq.data, card);
3874 +
3875 /*
3876 * If the host doesn't support multiple block writes, force
3877 * block writes to single block. SD cards are excepted from
3878 diff -purN linux_2.6.24_org/drivers/mmc/host/sdhci.c linux_2.6.24_olpc/drivers/mmc/host/sdhci.c
3879 --- linux_2.6.24_org/drivers/mmc/host/sdhci.c 2008-02-15 20:11:13.000000000 +0000
3880 +++ linux_2.6.24_olpc/drivers/mmc/host/sdhci.c 2008-02-15 18:58:17.000000000 +0000
3881 @@ -441,6 +441,12 @@ static void sdhci_prepare_data(struct sd
3882 break;
3883 }
3884
3885 + /*
3886 + * There's an off-by-one error in the hw that we need to
3887 + * compensate for.
3888 + */
3889 + count++;
3890 +
3891 if (count >= 0xF) {
3892 printk(KERN_WARNING "%s: Too large timeout requested!\n",
3893 mmc_hostname(host->mmc));
3894 @@ -728,19 +734,17 @@ static void sdhci_set_power(struct sdhci
3895 if (!(host->chip->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE))
3896 writeb(0, host->ioaddr + SDHCI_POWER_CONTROL);
3897
3898 - pwr = SDHCI_POWER_ON;
3899 -
3900 switch (1 << power) {
3901 case MMC_VDD_165_195:
3902 - pwr |= SDHCI_POWER_180;
3903 + pwr = SDHCI_POWER_180;
3904 break;
3905 case MMC_VDD_29_30:
3906 case MMC_VDD_30_31:
3907 - pwr |= SDHCI_POWER_300;
3908 + pwr = SDHCI_POWER_300;
3909 break;
3910 case MMC_VDD_32_33:
3911 case MMC_VDD_33_34:
3912 - pwr |= SDHCI_POWER_330;
3913 + pwr = SDHCI_POWER_330;
3914 break;
3915 default:
3916 BUG();
3917 @@ -748,6 +752,10 @@ static void sdhci_set_power(struct sdhci
3918
3919 writeb(pwr, host->ioaddr + SDHCI_POWER_CONTROL);
3920
3921 + pwr |= SDHCI_POWER_ON;
3922 +
3923 + writeb(pwr, host->ioaddr + SDHCI_POWER_CONTROL);
3924 +
3925 out:
3926 host->power = power;
3927 }
3928 diff -purN linux_2.6.24_org/drivers/mtd/nand/cafe_nand.c linux_2.6.24_olpc/drivers/mtd/nand/cafe_nand.c
3929 --- linux_2.6.24_org/drivers/mtd/nand/cafe_nand.c 2008-02-15 20:11:46.000000000 +0000
3930 +++ linux_2.6.24_olpc/drivers/mtd/nand/cafe_nand.c 2008-02-15 18:58:57.000000000 +0000
3931 @@ -11,6 +11,7 @@
3932 #undef DEBUG
3933 #include <linux/mtd/mtd.h>
3934 #include <linux/mtd/nand.h>
3935 +#include <linux/mtd/partitions.h>
3936 #include <linux/rslib.h>
3937 #include <linux/pci.h>
3938 #include <linux/delay.h>
3939 @@ -52,6 +53,7 @@
3940
3941 struct cafe_priv {
3942 struct nand_chip nand;
3943 + struct mtd_partition *parts;
3944 struct pci_dev *pdev;
3945 void __iomem *mmio;
3946 struct rs_control *rs;
3947 @@ -84,6 +86,10 @@ static unsigned int numtimings;
3948 static int timing[3];
3949 module_param_array(timing, int, &numtimings, 0644);
3950
3951 +#ifdef CONFIG_MTD_PARTITIONS
3952 +static const char *part_probes[] = { "RedBoot", NULL };
3953 +#endif
3954 +
3955 /* Hrm. Why isn't this already conditional on something in the struct device? */
3956 #define cafe_dev_dbg(dev, args...) do { if (debug) dev_dbg(dev, ##args); } while(0)
3957
3958 @@ -620,7 +626,9 @@ static int __devinit cafe_nand_probe(str
3959 {
3960 struct mtd_info *mtd;
3961 struct cafe_priv *cafe;
3962 + struct mtd_partition *parts;
3963 uint32_t ctrl;
3964 + int nr_parts;
3965 int err = 0;
3966
3967 /* Very old versions shared the same PCI ident for all three
3968 @@ -787,7 +795,18 @@ static int __devinit cafe_nand_probe(str
3969 goto out_irq;
3970
3971 pci_set_drvdata(pdev, mtd);
3972 +
3973 + /* We register the whole device first, separate from the partitions */
3974 add_mtd_device(mtd);
3975 +
3976 +#ifdef CONFIG_MTD_PARTITIONS
3977 + nr_parts = parse_mtd_partitions(mtd, part_probes, &parts, 0);
3978 + if (nr_parts > 0) {
3979 + cafe->parts = parts;
3980 + dev_info(&cafe->pdev->dev, "%d RedBoot partitions found\n", nr_parts);
3981 + add_mtd_partitions(mtd, parts, nr_parts);
3982 + }
3983 +#endif
3984 goto out;
3985
3986 out_irq:
3987 diff -purN linux_2.6.24_org/drivers/mtd/redboot.c linux_2.6.24_olpc/drivers/mtd/redboot.c
3988 --- linux_2.6.24_org/drivers/mtd/redboot.c 2008-02-15 20:11:46.000000000 +0000
3989 +++ linux_2.6.24_olpc/drivers/mtd/redboot.c 2008-02-15 18:58:58.000000000 +0000
3990 @@ -59,16 +59,31 @@ static int parse_redboot_partitions(stru
3991 static char nullstring[] = "unallocated";
3992 #endif
3993
3994 + if ( directory < 0 ) {
3995 + offset = master->size + directory * master->erasesize;
3996 + while (master->block_isbad &&
3997 + master->block_isbad(master, offset)) {
3998 + if (!offset) {
3999 + nogood:
4000 + printk(KERN_NOTICE "Failed to find a non-bad block to check for RedBoot partition table\n");
4001 + return -EIO;
4002 + }
4003 + offset -= master->erasesize;
4004 + }
4005 + } else {
4006 + offset = directory * master->erasesize;
4007 + while (master->block_isbad &&
4008 + master->block_isbad(master, offset)) {
4009 + offset += master->erasesize;
4010 + if (offset == master->size)
4011 + goto nogood;
4012 + }
4013 + }
4014 buf = vmalloc(master->erasesize);
4015
4016 if (!buf)
4017 return -ENOMEM;
4018
4019 - if ( directory < 0 )
4020 - offset = master->size + directory*master->erasesize;
4021 - else
4022 - offset = directory*master->erasesize;
4023 -
4024 printk(KERN_NOTICE "Searching for RedBoot partition table in %s at offset 0x%lx\n",
4025 master->name, offset);
4026
4027 diff -purN linux_2.6.24_org/drivers/net/forcedeth.c linux_2.6.24_olpc/drivers/net/forcedeth.c
4028 --- linux_2.6.24_org/drivers/net/forcedeth.c 2008-02-15 20:11:19.000000000 +0000
4029 +++ linux_2.6.24_olpc/drivers/net/forcedeth.c 2008-02-15 18:58:33.000000000 +0000
4030 @@ -3559,11 +3559,13 @@ static int nv_request_irq(struct net_dev
4031 }
4032 if (ret != 0 && np->msi_flags & NV_MSI_CAPABLE) {
4033 if ((ret = pci_enable_msi(np->pci_dev)) == 0) {
4034 + pci_intx(np->pci_dev, 0);
4035 np->msi_flags |= NV_MSI_ENABLED;
4036 dev->irq = np->pci_dev->irq;
4037 if (request_irq(np->pci_dev->irq, handler, IRQF_SHARED, dev->name, dev) != 0) {
4038 printk(KERN_INFO "forcedeth: request_irq failed %d\n", ret);
4039 pci_disable_msi(np->pci_dev);
4040 + pci_intx(np->pci_dev, 1);
4041 np->msi_flags &= ~NV_MSI_ENABLED;
4042 dev->irq = np->pci_dev->irq;
4043 goto out_err;
4044 @@ -3606,6 +3608,7 @@ static void nv_free_irq(struct net_devic
4045 free_irq(np->pci_dev->irq, dev);
4046 if (np->msi_flags & NV_MSI_ENABLED) {
4047 pci_disable_msi(np->pci_dev);
4048 + pci_intx(np->pci_dev, 1);
4049 np->msi_flags &= ~NV_MSI_ENABLED;
4050 }
4051 }
4052 diff -purN linux_2.6.24_org/drivers/pci/quirks.c linux_2.6.24_olpc/drivers/pci/quirks.c
4053 --- linux_2.6.24_org/drivers/pci/quirks.c 2008-02-15 20:11:33.000000000 +0000
4054 +++ linux_2.6.24_olpc/drivers/pci/quirks.c 2008-02-15 18:58:50.000000000 +0000
4055 @@ -1359,6 +1359,17 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_IN
4056 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x260b, quirk_intel_pcie_pm);
4057
4058 /*
4059 + * According to Tom Sylla, the Geode does not support PCI power management
4060 + * transition, so we shouldn't need the D3hot delay.
4061 + */
4062 +static void __init quirk_geode_pci_pm(struct pci_dev *dev)
4063 +{
4064 + pci_pm_d3_delay = 0;
4065 +}
4066 +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_LEGACY, quirk_geode_pci_pm);
4067 +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA, quirk_geode_pci_pm);
4068 +
4069 +/*
4070 * Toshiba TC86C001 IDE controller reports the standard 8-byte BAR0 size
4071 * but the PIO transfers won't work if BAR0 falls at the odd 8 bytes.
4072 * Re-allocate the region if needed...
4073 diff -purN linux_2.6.24_org/drivers/power/ds2760_battery.c linux_2.6.24_olpc/drivers/power/ds2760_battery.c
4074 --- linux_2.6.24_org/drivers/power/ds2760_battery.c 2008-02-15 20:11:45.000000000 +0000
4075 +++ linux_2.6.24_olpc/drivers/power/ds2760_battery.c 2008-02-15 18:58:56.000000000 +0000
4076 @@ -409,6 +409,7 @@ static int ds2760_battery_suspend(struct
4077 struct ds2760_device_info *di = platform_get_drvdata(pdev);
4078
4079 di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN;
4080 + power_supply_changed(&di->bat);
4081
4082 return 0;
4083 }
4084 diff -purN linux_2.6.24_org/drivers/power/olpc_battery.c linux_2.6.24_olpc/drivers/power/olpc_battery.c
4085 --- linux_2.6.24_org/drivers/power/olpc_battery.c 2008-02-15 20:11:45.000000000 +0000
4086 +++ linux_2.6.24_olpc/drivers/power/olpc_battery.c 2008-02-15 18:58:56.000000000 +0000
4087 @@ -14,12 +14,13 @@
4088 #include <linux/power_supply.h>
4089 #include <linux/jiffies.h>
4090 #include <linux/sched.h>
4091 +#include <asm/io.h>
4092 #include <asm/olpc.h>
4093
4094
4095 #define EC_BAT_VOLTAGE 0x10 /* uint16_t, *9.76/32, mV */
4096 #define EC_BAT_CURRENT 0x11 /* int16_t, *15.625/120, mA */
4097 -#define EC_BAT_ACR 0x12
4098 +#define EC_BAT_ACR 0x12 /* int16_t *416.667 µAh */
4099 #define EC_BAT_TEMP 0x13 /* uint16_t, *100/256, °C */
4100 #define EC_AMB_TEMP 0x14 /* uint16_t, *100/256, °C */
4101 #define EC_BAT_STATUS 0x15 /* uint8_t, bitmask */
4102 @@ -84,6 +85,8 @@ static struct power_supply olpc_ac = {
4103 .get_property = olpc_ac_get_prop,
4104 };
4105
4106 +static char bat_serial[17]; /* Ick */
4107 +
4108 /*********************************************************************
4109 * Battery properties
4110 *********************************************************************/
4111 @@ -94,6 +97,7 @@ static int olpc_bat_get_property(struct
4112 int ret = 0;
4113 int16_t ec_word;
4114 uint8_t ec_byte;
4115 + uint64_t ser_buf;
4116
4117 ret = olpc_ec_cmd(EC_BAT_STATUS, NULL, 0, &ec_byte, 1);
4118 if (ret)
4119 @@ -127,8 +131,8 @@ static int olpc_bat_get_property(struct
4120 val->intval = POWER_SUPPLY_STATUS_FULL;
4121 else /* Not _necessarily_ true but EC doesn't tell all yet */
4122 val->intval = POWER_SUPPLY_STATUS_CHARGING;
4123 - break;
4124 }
4125 + break;
4126 case POWER_SUPPLY_PROP_PRESENT:
4127 val->intval = !!(ec_byte & BAT_STAT_PRESENT);
4128 break;
4129 @@ -249,6 +253,22 @@ static int olpc_bat_get_property(struct
4130 ec_word = be16_to_cpu(ec_word);
4131 val->intval = ec_word * 100 / 256;
4132 break;
4133 + case POWER_SUPPLY_PROP_ACCUM_CURRENT:
4134 + ret = olpc_ec_cmd(EC_BAT_ACR, NULL, 0, (void *)&ec_word, 2);
4135 + if (ret)
4136 + return ret;
4137 +
4138 + ec_word = be16_to_cpu(ec_word);
4139 + val->intval = (uint16_t)ec_word;
4140 + break;
4141 + case POWER_SUPPLY_PROP_SERIAL_NUMBER:
4142 + ret = olpc_ec_cmd(EC_BAT_SERIAL, NULL, 0, (void *)&ser_buf, 8);
4143 + if (ret)
4144 + return ret;
4145 +
4146 + sprintf(bat_serial, "%016llx", (long long)be64_to_cpu(ser_buf));
4147 + val->strval = bat_serial;
4148 + break;
4149 default:
4150 ret = -EINVAL;
4151 break;
4152 @@ -268,7 +288,51 @@ static enum power_supply_property olpc_b
4153 POWER_SUPPLY_PROP_CAPACITY_LEVEL,
4154 POWER_SUPPLY_PROP_TEMP,
4155 POWER_SUPPLY_PROP_TEMP_AMBIENT,
4156 + POWER_SUPPLY_PROP_ACCUM_CURRENT,
4157 POWER_SUPPLY_PROP_MANUFACTURER,
4158 + POWER_SUPPLY_PROP_SERIAL_NUMBER,
4159 +};
4160 +
4161 +/* EEPROM reading goes completely around the power_supply API, sadly */
4162 +
4163 +#define EEPROM_START 0x20
4164 +#define EEPROM_END 0x80
4165 +#define EEPROM_SIZE (EEPROM_END - EEPROM_START)
4166 +
4167 +static ssize_t olpc_bat_eeprom_read(struct kobject *kobj, char *buf, loff_t off,
4168 + size_t count)
4169 +{
4170 + uint8_t ec_byte;
4171 + int ret, end;
4172 +
4173 + if (off >= EEPROM_SIZE)
4174 + return 0;
4175 + if (off + count > EEPROM_SIZE)
4176 + count = EEPROM_SIZE - off;
4177 +
4178 + end = EEPROM_START + off + count;
4179 + for (ec_byte = EEPROM_START + off; ec_byte < end; ec_byte++) {
4180 + ret = olpc_ec_cmd(EC_BAT_EEPROM, &ec_byte, 1,
4181 + &buf[ec_byte - EEPROM_START], 1);
4182 + if (ret) {
4183 + printk(KERN_ERR "olpc-battery: EC command "
4184 + "EC_BAT_EEPROM @ 0x%x failed -"
4185 + " %d!\n", ec_byte, ret);
4186 + return -EIO;
4187 + }
4188 + }
4189 +
4190 + return count;
4191 +}
4192 +
4193 +static struct bin_attribute olpc_bat_eeprom = {
4194 + .attr = {
4195 + .name = "eeprom",
4196 + .mode = S_IRUGO,
4197 + .owner = THIS_MODULE,
4198 + },
4199 + .size = 0,
4200 + .read = olpc_bat_eeprom_read,
4201 };
4202
4203 /*********************************************************************
4204 @@ -299,7 +363,7 @@ static int __init olpc_bat_init(void)
4205
4206 if (!olpc_platform_info.ecver)
4207 return -ENXIO;
4208 - if (olpc_platform_info.ecver < 0x43) {
4209 + if (olpc_platform_info.ecver < 0x44) {
4210 printk(KERN_NOTICE "OLPC EC version 0x%02x too old for battery driver.\n", olpc_platform_info.ecver);
4211 return -ENXIO;
4212 }
4213 @@ -324,9 +388,15 @@ static int __init olpc_bat_init(void)
4214 if (ret)
4215 goto battery_failed;
4216
4217 + ret = device_create_bin_file(olpc_bat.dev, &olpc_bat_eeprom);
4218 + if (ret)
4219 + goto eeprom_failed;
4220 +
4221 olpc_register_battery_callback(&olpc_battery_trigger_uevent);
4222 goto success;
4223
4224 +eeprom_failed:
4225 + power_supply_unregister(&olpc_bat);
4226 battery_failed:
4227 power_supply_unregister(&olpc_ac);
4228 ac_failed:
4229 @@ -338,6 +408,7 @@ success:
4230 static void __exit olpc_bat_exit(void)
4231 {
4232 olpc_deregister_battery_callback();
4233 + device_remove_bin_file(olpc_bat.dev, &olpc_bat_eeprom);
4234 power_supply_unregister(&olpc_bat);
4235 power_supply_unregister(&olpc_ac);
4236 platform_device_unregister(bat_pdev);
4237 diff -purN linux_2.6.24_org/drivers/power/power_supply_sysfs.c linux_2.6.24_olpc/drivers/power/power_supply_sysfs.c
4238 --- linux_2.6.24_org/drivers/power/power_supply_sysfs.c 2008-02-15 20:11:45.000000000 +0000
4239 +++ linux_2.6.24_olpc/drivers/power/power_supply_sysfs.c 2008-02-15 18:58:56.000000000 +0000
4240 @@ -114,9 +114,11 @@ static struct device_attribute power_sup
4241 POWER_SUPPLY_ATTR(time_to_empty_avg),
4242 POWER_SUPPLY_ATTR(time_to_full_now),
4243 POWER_SUPPLY_ATTR(time_to_full_avg),
4244 + POWER_SUPPLY_ATTR(accum_current),
4245 /* Properties of type `const char *' */
4246 POWER_SUPPLY_ATTR(model_name),
4247 POWER_SUPPLY_ATTR(manufacturer),
4248 + POWER_SUPPLY_ATTR(serial_number),
4249 };
4250
4251 static ssize_t power_supply_show_static_attrs(struct device *dev,
4252 diff -purN linux_2.6.24_org/drivers/serial/serial_core.c linux_2.6.24_olpc/drivers/serial/serial_core.c
4253 --- linux_2.6.24_org/drivers/serial/serial_core.c 2008-02-15 20:11:33.000000000 +0000
4254 +++ linux_2.6.24_olpc/drivers/serial/serial_core.c 2008-02-15 18:58:51.000000000 +0000
4255 @@ -2013,6 +2013,7 @@ int uart_suspend_port(struct uart_driver
4256 int uart_resume_port(struct uart_driver *drv, struct uart_port *port)
4257 {
4258 struct uart_state *state = drv->state + port->line;
4259 + struct ktermios termios;
4260
4261 mutex_lock(&state->mutex);
4262
4263 @@ -2035,20 +2036,6 @@ int uart_resume_port(struct uart_driver
4264 * Re-enable the console device after suspending.
4265 */
4266 if (uart_console(port)) {
4267 - struct ktermios termios;
4268 -
4269 - /*
4270 - * First try to use the console cflag setting.
4271 - */
4272 - memset(&termios, 0, sizeof(struct ktermios));
4273 - termios.c_cflag = port->cons->cflag;
4274 -
4275 - /*
4276 - * If that's unset, use the tty termios setting.
4277 - */
4278 - if (state->info && state->info->tty && termios.c_cflag == 0)
4279 - termios = *state->info->tty->termios;
4280 -
4281 port->ops->set_termios(port, &termios, NULL);
4282 console_start(port->cons);
4283 }
4284 diff -purN linux_2.6.24_org/drivers/sysprof/config.h linux_2.6.24_olpc/drivers/sysprof/config.h
4285 --- linux_2.6.24_org/drivers/sysprof/config.h 1970-01-01 01:00:00.000000000 +0100
4286 +++ linux_2.6.24_olpc/drivers/sysprof/config.h 2008-02-15 18:58:59.000000000 +0000
4287 @@ -0,0 +1,23 @@
4288 +/* config.h. Generated by configure. */
4289 +/* config.h.in. Generated from configure.ac by autoheader. */
4290 +
4291 +/* Look for global separate debug info in this path */
4292 +#define DEBUGDIR "/usr/local/lib/debug"
4293 +
4294 +/* Define to 1 if you have the `iberty' library (-liberty). */
4295 +/* #undef HAVE_LIBIBERTY */
4296 +
4297 +/* Define to the address where bug reports for this package should be sent. */
4298 +#define PACKAGE_BUGREPORT ""
4299 +
4300 +/* Define to the full name of this package. */
4301 +#define PACKAGE_NAME "sysprof"
4302 +
4303 +/* Define to the full name and version of this package. */
4304 +#define PACKAGE_STRING "sysprof 1.0.8"
4305 +
4306 +/* Define to the one symbol short name of this package. */
4307 +#define PACKAGE_TARNAME "sysprof"
4308 +
4309 +/* Define to the version of this package. */
4310 +#define PACKAGE_VERSION "1.0.8"
4311 diff -purN linux_2.6.24_org/drivers/sysprof/Kconfig linux_2.6.24_olpc/drivers/sysprof/Kconfig
4312 --- linux_2.6.24_org/drivers/sysprof/Kconfig 1970-01-01 01:00:00.000000000 +0100
4313 +++ linux_2.6.24_olpc/drivers/sysprof/Kconfig 2008-02-15 18:58:59.000000000 +0000
4314 @@ -0,0 +1,12 @@
4315 +
4316 +menu "Sysprof"
4317 +
4318 +config SYSPROF
4319 + tristate "Sysprof support"
4320 + help
4321 + Say M here to include the sysprof-module.
4322 +
4323 + Sysprof is a sampling profiler that uses a kernel module,
4324 + sysprof-module, to generate stacktraces which are then interpreted by
4325 + the userspace program "sysprof".
4326 +endmenu
4327 diff -purN linux_2.6.24_org/drivers/sysprof/Makefile linux_2.6.24_olpc/drivers/sysprof/Makefile
4328 --- linux_2.6.24_org/drivers/sysprof/Makefile 1970-01-01 01:00:00.000000000 +0100
4329 +++ linux_2.6.24_olpc/drivers/sysprof/Makefile 2008-02-15 18:58:59.000000000 +0000
4330 @@ -0,0 +1 @@
4331 +obj-$(CONFIG_SYSPROF) += sysprof-module.o
4332 diff -purN linux_2.6.24_org/drivers/sysprof/sysprof-module.c linux_2.6.24_olpc/drivers/sysprof/sysprof-module.c
4333 --- linux_2.6.24_org/drivers/sysprof/sysprof-module.c 1970-01-01 01:00:00.000000000 +0100
4334 +++ linux_2.6.24_olpc/drivers/sysprof/sysprof-module.c 2008-02-15 18:58:59.000000000 +0000
4335 @@ -0,0 +1,271 @@
4336 +/* -*- c-basic-offset: 8 -*- */
4337 +
4338 +/* Sysprof -- Sampling, systemwide CPU profiler
4339 + * Copyright 2004, Red Hat, Inc.
4340 + * Copyright 2004, 2005, Soeren Sandmann
4341 + *
4342 + * This program is free software; you can redistribute it and/or modify
4343 + * it under the terms of the GNU General Public License as published by
4344 + * the Free Software Foundation; either version 2 of the License, or
4345 + * (at your option) any later version.
4346 + *
4347 + * This program is distributed in the hope that it will be useful,
4348 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
4349 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4350 + * GNU General Public License for more details.
4351 + *
4352 + * You should have received a copy of the GNU General Public License
4353 + * along with this program; if not, write to the Free Software
4354 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
4355 + */
4356 +
4357 +#ifdef CONFIG_SMP
4358 +# define __SMP__
4359 +#endif
4360 +#include <asm/atomic.h>
4361 +#include <linux/kernel.h> /* Needed for KERN_ALERT */
4362 +#include <linux/module.h> /* Needed by all modules */
4363 +#include <linux/sched.h>
4364 +
4365 +#include <linux/proc_fs.h>
4366 +#include <asm/uaccess.h>
4367 +#include <linux/poll.h>
4368 +#include <linux/highmem.h>
4369 +#include <linux/pagemap.h>
4370 +#include <linux/profile.h>
4371 +
4372 +#include "sysprof-module.h"
4373 +
4374 +#include "config.h"
4375 +
4376 +#include <linux/version.h>
4377 +
4378 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
4379 +#include <linux/config.h>
4380 +#endif
4381 +
4382 +#if !CONFIG_PROFILING
4383 +# error Sysprof needs a kernel with profiling support compiled in.
4384 +#endif
4385 +
4386 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11)
4387 +# error Sysprof needs a Linux 2.6.11 kernel or later
4388 +#endif
4389 +#include <linux/kallsyms.h>
4390 +
4391 +MODULE_LICENSE("GPL");
4392 +MODULE_AUTHOR("Soeren Sandmann (sandmann@daimi.au.dk)");
4393 +
4394 +#define SAMPLES_PER_SECOND (200)
4395 +#define INTERVAL ((HZ <= SAMPLES_PER_SECOND)? 1 : (HZ / SAMPLES_PER_SECOND))
4396 +#define N_TRACES 256
4397 +
4398 +static SysprofStackTrace stack_traces[N_TRACES];
4399 +static SysprofStackTrace * head = &stack_traces[0];
4400 +static SysprofStackTrace * tail = &stack_traces[0];
4401 +DECLARE_WAIT_QUEUE_HEAD (wait_for_trace);
4402 +DECLARE_WAIT_QUEUE_HEAD (wait_for_exit);
4403 +
4404 +/* Macro the names of the registers that are used on each architecture */
4405 +#if defined(CONFIG_X86_64)
4406 +# define REG_FRAME_PTR rbp
4407 +# define REG_INS_PTR rip
4408 +# define REG_STACK_PTR rsp
4409 +#elif defined(CONFIG_X86)
4410 +# define REG_FRAME_PTR ebp
4411 +# define REG_INS_PTR eip
4412 +# define REG_STACK_PTR esp
4413 +#else
4414 +# error Sysprof only supports the i386 and x86-64 architectures
4415 +#endif
4416 +
4417 +typedef struct userspace_reader userspace_reader;
4418 +struct userspace_reader
4419 +{
4420 + struct task_struct *task;
4421 + unsigned long cache_address;
4422 + unsigned long *cache;
4423 +};
4424 +
4425 +typedef struct StackFrame StackFrame;
4426 +struct StackFrame {
4427 + unsigned long next;
4428 + unsigned long return_address;
4429 +};
4430 +
4431 +struct work_struct work;
4432 +
4433 +static int
4434 +read_frame (void *frame_pointer, StackFrame *frame)
4435 +{
4436 +#if 0
4437 + /* This is commented out because we seem to be called with
4438 + * (current_thread_info()->addr_limit.seg)) == 0
4439 + * which means access_ok() _always_ fails.
4440 + *
4441 + * Not sure why (or if) this isn't the case for oprofile
4442 + */
4443 + if (!access_ok(VERIFY_READ, frame_pointer, sizeof(StackFrame)))
4444 + return 1;
4445 +#endif
4446 +
4447 + if (__copy_from_user_inatomic (
4448 + frame, frame_pointer, sizeof (StackFrame)))
4449 + return 1;
4450 +
4451 + return 0;
4452 +}
4453 +
4454 +DEFINE_PER_CPU(int, n_samples);
4455 +
4456 +static int
4457 +timer_notify (struct pt_regs *regs)
4458 +{
4459 + SysprofStackTrace *trace = head;
4460 + int i;
4461 + int is_user;
4462 + static atomic_t in_timer_notify = ATOMIC_INIT(1);
4463 + int n;
4464 +
4465 + n = ++get_cpu_var(n_samples);
4466 + put_cpu_var(n_samples);
4467 +
4468 + if (n % INTERVAL != 0)
4469 + return 0;
4470 +
4471 + /* 0: locked, 1: unlocked */
4472 +
4473 + if (!atomic_dec_and_test(&in_timer_notify))
4474 + goto out;
4475 +
4476 + is_user = user_mode(regs);
4477 +
4478 + if (!current || current->pid == 0)
4479 + goto out;
4480 +
4481 + if (is_user && current->state != TASK_RUNNING)
4482 + goto out;
4483 +
4484 + if (!is_user)
4485 + {
4486 + /* kernel */
4487 +
4488 + trace->pid = current->pid;
4489 + trace->truncated = 0;
4490 + trace->n_addresses = 1;
4491 +
4492 + /* 0x1 is taken by sysprof to mean "in kernel" */
4493 + trace->addresses[0] = (void *)0x1;
4494 + }
4495 + else
4496 + {
4497 + StackFrame *frame_pointer;
4498 + StackFrame frame;
4499 + memset(trace, 0, sizeof (SysprofStackTrace));
4500 +
4501 + trace->pid = current->pid;
4502 + trace->truncated = 0;
4503 +
4504 + i = 0;
4505 +
4506 + trace->addresses[i++] = (void *)regs->REG_INS_PTR;
4507 +
4508 + frame_pointer = (void *)regs->REG_FRAME_PTR;
4509 +
4510 + while (read_frame (frame_pointer, &frame) == 0 &&
4511 + i < SYSPROF_MAX_ADDRESSES &&
4512 + (unsigned long)frame_pointer >= regs->REG_STACK_PTR)
4513 + {
4514 + trace->addresses[i++] = (void *)frame.return_address;
4515 + frame_pointer = (StackFrame *)frame.next;
4516 + }
4517 +
4518 + trace->n_addresses = i;
4519 +
4520 + if (i == SYSPROF_MAX_ADDRESSES)
4521 + trace->truncated = 1;
4522 + else
4523 + trace->truncated = 0;
4524 + }
4525 +
4526 + if (head++ == &stack_traces[N_TRACES - 1])
4527 + head = &stack_traces[0];
4528 +
4529 + wake_up (&wait_for_trace);
4530 +
4531 +out:
4532 + atomic_inc(&in_timer_notify);
4533 + return 0;
4534 +}
4535 +
4536 +static int
4537 +procfile_read(char *buffer,
4538 + char **buffer_location,
4539 + off_t offset,
4540 + int buffer_len,
4541 + int *eof,
4542 + void *data)
4543 +{
4544 + if (head == tail)
4545 + return -EWOULDBLOCK;
4546 +
4547 + *buffer_location = (char *)tail;
4548 +
4549 + BUG_ON(tail->pid == 0);
4550 +
4551 + if (tail++ == &stack_traces[N_TRACES - 1])
4552 + tail = &stack_traces[0];
4553 +
4554 + return sizeof (SysprofStackTrace);
4555 +}
4556 +
4557 +struct proc_dir_entry *trace_proc_file;
4558 +static unsigned int
4559 +procfile_poll(struct file *filp, poll_table *poll_table)
4560 +{
4561 + if (head != tail)
4562 + return POLLIN | POLLRDNORM;
4563 +
4564 + poll_wait(filp, &wait_for_trace, poll_table);
4565 +
4566 + if (head != tail)
4567 + return POLLIN | POLLRDNORM;
4568 +
4569 + return 0;
4570 +}
4571 +
4572 +int
4573 +init_module(void)
4574 +{
4575 + static struct file_operations fops;
4576 +
4577 + trace_proc_file =
4578 + create_proc_entry ("sysprof-trace", S_IFREG | S_IRUGO, &proc_root);
4579 +
4580 + if (!trace_proc_file)
4581 + return 1;
4582 +
4583 + fops = *trace_proc_file->proc_fops;
4584 + fops.poll = procfile_poll;
4585 +
4586 + trace_proc_file->read_proc = procfile_read;
4587 + trace_proc_file->proc_fops = &fops;
4588 + trace_proc_file->size = sizeof (SysprofStackTrace);
4589 +
4590 + register_timer_hook (timer_notify);
4591 +
4592 + printk(KERN_ALERT "sysprof: loaded (%s)\n", PACKAGE_VERSION);
4593 +
4594 + return 0;
4595 +}
4596 +
4597 +void
4598 +cleanup_module(void)
4599 +{
4600 + unregister_timer_hook (timer_notify);
4601 +
4602 + remove_proc_entry("sysprof-trace", &proc_root);
4603 +
4604 + printk(KERN_ALERT "sysprof: unloaded\n");
4605 +}
4606 +
4607 diff -purN linux_2.6.24_org/drivers/sysprof/sysprof-module.h linux_2.6.24_olpc/drivers/sysprof/sysprof-module.h
4608 --- linux_2.6.24_org/drivers/sysprof/sysprof-module.h 1970-01-01 01:00:00.000000000 +0100
4609 +++ linux_2.6.24_olpc/drivers/sysprof/sysprof-module.h 2008-02-15 18:58:59.000000000 +0000
4610 @@ -0,0 +1,37 @@
4611 +/* Sysprof -- Sampling, systemwide CPU profiler
4612 + * Copyright 2004, Red Hat, Inc.
4613 + * Copyright 2004, 2005, Soeren Sandmann
4614 + *
4615 + * This program is free software; you can redistribute it and/or modify
4616 + * it under the terms of the GNU General Public License as published by
4617 + * the Free Software Foundation; either version 2 of the License, or
4618 + * (at your option) any later version.
4619 + *
4620 + * This program is distributed in the hope that it will be useful,
4621 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
4622 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4623 + * GNU General Public License for more details.
4624 + *
4625 + * You should have received a copy of the GNU General Public License
4626 + * along with this program; if not, write to the Free Software
4627 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
4628 + */
4629 +
4630 +#ifndef SYSPROF_MODULE_H
4631 +#define SYSPROF_MODULE_H
4632 +
4633 +typedef struct SysprofStackTrace SysprofStackTrace;
4634 +
4635 +#define SYSPROF_MAX_ADDRESSES 512
4636 +
4637 +struct SysprofStackTrace
4638 +{
4639 + int pid; /* -1 if in kernel */
4640 + int truncated;
4641 + int n_addresses; /* note: this can be 1 if the process was compiled
4642 + * with -fomit-frame-pointer or is otherwise weird
4643 + */
4644 + void *addresses[SYSPROF_MAX_ADDRESSES];
4645 +};
4646 +
4647 +#endif
4648 diff -purN linux_2.6.24_org/drivers/usb/core/driver.c linux_2.6.24_olpc/drivers/usb/core/driver.c
4649 --- linux_2.6.24_org/drivers/usb/core/driver.c 2008-02-15 20:11:09.000000000 +0000
4650 +++ linux_2.6.24_olpc/drivers/usb/core/driver.c 2008-02-15 18:58:14.000000000 +0000
4651 @@ -1062,8 +1062,15 @@ static int usb_suspend_both(struct usb_d
4652 break;
4653 }
4654 }
4655 - if (status == 0)
4656 + if (status == 0) {
4657 +
4658 + /* Non-root devices don't need to do anything for FREEZE
4659 + * or PRETHAW. */
4660 + if (udev->parent && (msg.event == PM_EVENT_FREEZE ||
4661 + msg.event == PM_EVENT_PRETHAW))
4662 + goto done;
4663 status = usb_suspend_device(udev, msg);
4664 + }
4665
4666 /* If the suspend failed, resume interfaces that did get suspended */
4667 if (status != 0) {
4668 diff -purN linux_2.6.24_org/drivers/usb/core/quirks.c linux_2.6.24_olpc/drivers/usb/core/quirks.c
4669 --- linux_2.6.24_org/drivers/usb/core/quirks.c 2008-02-15 20:11:09.000000000 +0000
4670 +++ linux_2.6.24_olpc/drivers/usb/core/quirks.c 2008-02-15 18:58:12.000000000 +0000
4671 @@ -45,6 +45,9 @@ static const struct usb_device_id usb_qu
4672 /* SKYMEDI USB_DRIVE */
4673 { USB_DEVICE(0x1516, 0x8628), .driver_info = USB_QUIRK_RESET_RESUME },
4674
4675 + /* Philips PSC805 audio device */
4676 + { USB_DEVICE(0x0471, 0x0155), .driver_info = USB_QUIRK_RESET_RESUME },
4677 +
4678 { } /* terminating entry must be last */
4679 };
4680
4681 diff -purN linux_2.6.24_org/drivers/usb/core/usb.h linux_2.6.24_olpc/drivers/usb/core/usb.h
4682 --- linux_2.6.24_org/drivers/usb/core/usb.h 2008-02-15 20:11:09.000000000 +0000
4683 +++ linux_2.6.24_olpc/drivers/usb/core/usb.h 2008-02-15 18:58:14.000000000 +0000
4684 @@ -41,6 +41,7 @@ extern void usb_host_cleanup(void);
4685 extern void usb_autosuspend_work(struct work_struct *work);
4686 extern int usb_port_suspend(struct usb_device *dev);
4687 extern int usb_port_resume(struct usb_device *dev);
4688 +extern int usb_reset_suspended_device(struct usb_device *udev);
4689 extern int usb_external_suspend_device(struct usb_device *udev,
4690 pm_message_t msg);
4691 extern int usb_external_resume_device(struct usb_device *udev);
4692 diff -purN linux_2.6.24_org/drivers/usb/host/ehci-hcd.c linux_2.6.24_olpc/drivers/usb/host/ehci-hcd.c
4693 --- linux_2.6.24_org/drivers/usb/host/ehci-hcd.c 2008-02-15 20:11:09.000000000 +0000
4694 +++ linux_2.6.24_olpc/drivers/usb/host/ehci-hcd.c 2008-02-15 18:58:12.000000000 +0000
4695 @@ -653,9 +653,16 @@ static irqreturn_t ehci_irq (struct usb_
4696
4697 /* complete the unlinking of some qh [4.15.2.3] */
4698 if (status & STS_IAA) {
4699 - COUNT (ehci->stats.reclaim);
4700 - ehci->reclaim_ready = 1;
4701 - bh = 1;
4702 + if (!ehci->reclaim) {
4703 + printk(KERN_WARNING "%s would set reclaim_ready with nothing to reclaim!\n", __func__);
4704 +printk(KERN_DEBUG "%s: USBCMD: 0x%x\n", __func__, ehci_readl(ehci, &ehci->regs->command));
4705 +printk(KERN_DEBUG "%s: USBSTS: 0x%x\n", __func__, ehci_readl(ehci, &ehci->regs->status));
4706 + WARN_ON(1);
4707 + } else {
4708 + COUNT (ehci->stats.reclaim);
4709 + ehci->reclaim_ready = 1;
4710 + bh = 1;
4711 + }
4712 }
4713
4714 /* remote wakeup [4.3.1] */
4715 diff -purN linux_2.6.24_org/drivers/usb/host/ehci-hub.c linux_2.6.24_olpc/drivers/usb/host/ehci-hub.c
4716 --- linux_2.6.24_org/drivers/usb/host/ehci-hub.c 2008-02-15 20:11:09.000000000 +0000
4717 +++ linux_2.6.24_olpc/drivers/usb/host/ehci-hub.c 2008-02-15 18:58:12.000000000 +0000
4718 @@ -132,10 +132,15 @@ static int ehci_bus_suspend (struct usb_
4719 ehci_quiesce (ehci);
4720 hcd->state = HC_STATE_QUIESCING;
4721 }
4722 +printk(KERN_DEBUG "%s: USBCMD: 0x%x\n", __func__, ehci_readl(ehci, &ehci->regs->command));
4723 +printk(KERN_DEBUG "%s: USBSTS: 0x%x\n", __func__, ehci_readl(ehci, &ehci->regs->status));
4724 +
4725 ehci->command = ehci_readl(ehci, &ehci->regs->command);
4726 if (ehci->reclaim)
4727 ehci->reclaim_ready = 1;
4728 ehci_work(ehci);
4729 +printk(KERN_DEBUG "%s: USBCMD: 0x%x\n", __func__, ehci_readl(ehci, &ehci->regs->command));
4730 +printk(KERN_DEBUG "%s: USBSTS: 0x%x\n", __func__, ehci_readl(ehci, &ehci->regs->status));
4731
4732 /* Unlike other USB host controller types, EHCI doesn't have
4733 * any notion of "global" or bus-wide suspend. The driver has
4734 @@ -175,6 +180,9 @@ static int ehci_bus_suspend (struct usb_
4735 ehci_halt (ehci);
4736 hcd->state = HC_STATE_SUSPENDED;
4737
4738 +printk(KERN_DEBUG "%s: USBCMD: 0x%x\n", __func__, ehci_readl(ehci, &ehci->regs->command));
4739 +printk(KERN_DEBUG "%s: USBSTS: 0x%x\n", __func__, ehci_readl(ehci, &ehci->regs->status));
4740 +
4741 /* allow remote wakeup */
4742 mask = INTR_MASK;
4743 if (!device_may_wakeup(&hcd->self.root_hub->dev))
4744 @@ -195,6 +203,18 @@ static int ehci_bus_resume (struct usb_h
4745 u32 temp;
4746 u32 power_okay;
4747 int i;
4748 +#ifdef CONFIG_OLPC
4749 + u32 lo;
4750 + static void __iomem *usb_ehc_addr;
4751 +
4752 + rdmsrl(0x51200009, lo);
4753 + usb_ehc_addr = ioremap(lo, 256);
4754 + writel(readl(usb_ehc_addr+0x54) | 0x1000, usb_ehc_addr+0x54);
4755 + writel(readl(usb_ehc_addr+0x58) | 0x1000, usb_ehc_addr+0x58);
4756 + writel(readl(usb_ehc_addr+0x5C) | 0x1000, usb_ehc_addr+0x5C);
4757 + writel(readl(usb_ehc_addr+0x60) | 0x1000, usb_ehc_addr+0x60);
4758 + iounmap(usb_ehc_addr);
4759 +#endif
4760
4761 if (time_before (jiffies, ehci->next_statechange))
4762 msleep(5);
4763 diff -purN linux_2.6.24_org/drivers/usb/host/ehci-pci.c linux_2.6.24_olpc/drivers/usb/host/ehci-pci.c
4764 --- linux_2.6.24_org/drivers/usb/host/ehci-pci.c 2008-02-15 20:11:09.000000000 +0000
4765 +++ linux_2.6.24_olpc/drivers/usb/host/ehci-pci.c 2008-02-15 18:58:12.000000000 +0000
4766 @@ -247,6 +247,9 @@ static int ehci_pci_suspend(struct usb_h
4767 rc = -EINVAL;
4768 goto bail;
4769 }
4770 +printk(KERN_DEBUG "%s: USBCMD: 0x%x\n", __func__, ehci_readl(ehci, &ehci->regs->command));
4771 +printk(KERN_DEBUG "%s: USBSTS: 0x%x\n", __func__, ehci_readl(ehci, &ehci->regs->status));
4772 +
4773 ehci_writel(ehci, 0, &ehci->regs->intr_enable);
4774 (void)ehci_readl(ehci, &ehci->regs->intr_enable);
4775
4776 diff -purN linux_2.6.24_org/drivers/usb/host/ehci-q.c linux_2.6.24_olpc/drivers/usb/host/ehci-q.c
4777 --- linux_2.6.24_org/drivers/usb/host/ehci-q.c 2008-02-15 20:11:09.000000000 +0000
4778 +++ linux_2.6.24_olpc/drivers/usb/host/ehci-q.c 2008-02-15 18:58:12.000000000 +0000
4779 @@ -177,7 +177,7 @@ static int qtd_copy_status (
4780 if (QTD_CERR (token))
4781 status = -EPIPE;
4782 else {
4783 - ehci_dbg (ehci, "devpath %s ep%d%s 3strikes\n",
4784 + printk(KERN_ERR "devpath %s ep%d%s 3strikes\n",
4785 urb->dev->devpath,
4786 usb_pipeendpoint (urb->pipe),
4787 usb_pipein (urb->pipe) ? "in" : "out");
4788 @@ -973,6 +973,11 @@ static void end_unlink_async (struct ehc
4789 struct ehci_qh *qh = ehci->reclaim;
4790 struct ehci_qh *next;
4791
4792 + if (!qh) {
4793 + printk(KERN_CRIT "%s with ehci->reclaim == NULL!\n", __func__);
4794 + WARN_ON(1);
4795 + return;
4796 + }
4797 timer_action_done (ehci, TIMER_IAA_WATCHDOG);
4798
4799 // qh->hw_next = cpu_to_hc32(qh->qh_dma);
4800 diff -purN linux_2.6.24_org/drivers/usb/host/ohci-pci.c linux_2.6.24_olpc/drivers/usb/host/ohci-pci.c
4801 --- linux_2.6.24_org/drivers/usb/host/ohci-pci.c 2008-02-15 20:11:09.000000000 +0000
4802 +++ linux_2.6.24_olpc/drivers/usb/host/ohci-pci.c 2008-02-15 18:58:12.000000000 +0000
4803 @@ -317,6 +317,8 @@ static int ohci_pci_resume (struct usb_h
4804 /* FIXME: we should try to detect loss of VBUS power here */
4805 prepare_for_handover(hcd);
4806
4807 + /* Force the PM core to resume the root hub */
4808 + hcd_to_bus(hcd)->root_hub->dev.power.prev_state.event = PM_EVENT_ON;
4809 return 0;
4810 }
4811
4812 diff -purN linux_2.6.24_org/drivers/usb/storage/usb.c linux_2.6.24_olpc/drivers/usb/storage/usb.c
4813 --- linux_2.6.24_org/drivers/usb/storage/usb.c 2008-02-15 20:11:09.000000000 +0000
4814 +++ linux_2.6.24_olpc/drivers/usb/storage/usb.c 2008-02-15 18:58:11.000000000 +0000
4815 @@ -244,7 +244,7 @@ static int storage_pre_reset(struct usb_
4816 return 0;
4817 }
4818
4819 -static int storage_post_reset(struct usb_interface *iface)
4820 +static void storage_post_reset(struct usb_interface *iface, int reset_resume)
4821 {
4822 struct us_data *us = usb_get_intfdata(iface);
4823
4824 @@ -256,8 +256,10 @@ static int storage_post_reset(struct usb
4825 /* FIXME: Notify the subdrivers that they need to reinitialize
4826 * the device */
4827
4828 - mutex_unlock(&us->dev_mutex);
4829 - return 0;
4830 + /* If this is a reset-resume then the pre_reset routine wasn't
4831 + * called, so we don't need to unlock the mutex. */
4832 + if (!reset_resume)
4833 + mutex_unlock(&us->dev_mutex);
4834 }
4835
4836 /*
4837 diff -purN linux_2.6.24_org/drivers/video/fbmem.c linux_2.6.24_olpc/drivers/video/fbmem.c
4838 --- linux_2.6.24_org/drivers/video/fbmem.c 2008-02-15 20:11:23.000000000 +0000
4839 +++ linux_2.6.24_olpc/drivers/video/fbmem.c 2008-02-15 18:58:42.000000000 +0000
4840 @@ -820,6 +820,53 @@ static void try_to_load(int fb)
4841 #endif /* CONFIG_KMOD */
4842
4843 int
4844 +fb_powerup(struct fb_info *info)
4845 +{
4846 + int ret = 0;
4847 +
4848 + if (!info || info->state == FBINFO_STATE_RUNNING)
4849 + return 0;
4850 +
4851 + if (info->fbops->fb_powerup)
4852 + ret = info->fbops->fb_powerup(info);
4853 +
4854 + if (!ret) {
4855 + acquire_console_sem();
4856 + fb_set_suspend(info, 0);
4857 + release_console_sem();
4858 + }
4859 +
4860 + return ret;
4861 +}
4862 +
4863 +int
4864 +fb_powerdown(struct fb_info *info)
4865 +{
4866 + int ret = 0;
4867 +
4868 + if (!info || info->state == FBINFO_STATE_SUSPENDED)
4869 + return 0;
4870 +
4871 + /* Tell everybody that the fbdev is going down */
4872 + acquire_console_sem();
4873 + fb_set_suspend(info, 1);
4874 + release_console_sem();
4875 +
4876 + if (info->fbops->fb_powerdown)
4877 + ret = info->fbops->fb_powerdown(info);
4878 +
4879 + /* If the power down failed, then un-notify */
4880 +
4881 + if (ret) {
4882 + acquire_console_sem();
4883 + fb_set_suspend(info, 0);
4884 + release_console_sem();
4885 + }
4886 +
4887 + return ret;
4888 +}
4889 +
4890 +int
4891 fb_pan_display(struct fb_info *info, struct fb_var_screeninfo *var)
4892 {
4893 struct fb_fix_screeninfo *fix = &info->fix;
4894 diff -purN linux_2.6.24_org/drivers/video/geode/display_gx.c linux_2.6.24_olpc/drivers/video/geode/display_gx.c
4895 --- linux_2.6.24_org/drivers/video/geode/display_gx.c 2008-02-15 20:11:23.000000000 +0000
4896 +++ linux_2.6.24_olpc/drivers/video/geode/display_gx.c 2008-02-15 18:58:41.000000000 +0000
4897 @@ -11,26 +11,44 @@
4898 * Free Software Foundation; either version 2 of the License, or * (at your
4899 * option) any later version.
4900 */
4901 +
4902 +#include <linux/kernel.h>
4903 #include <linux/spinlock.h>
4904 #include <linux/fb.h>
4905 #include <linux/delay.h>
4906 #include <asm/io.h>
4907 #include <asm/div64.h>
4908 #include <asm/delay.h>
4909 +#include <asm/olpc.h>
4910
4911 #include "geodefb.h"
4912 #include "display_gx.h"
4913
4914 -#ifdef CONFIG_FB_GEODE_GX_SET_FBSIZE
4915 -unsigned int gx_frame_buffer_size(void)
4916 +static inline void rmwl(u32 val, u32 *reg)
4917 {
4918 - return CONFIG_FB_GEODE_GX_FBSIZE;
4919 + u32 in = readl(reg);
4920 + if (in != val)
4921 + writel(val, reg);
4922 }
4923 -#else
4924 +
4925 unsigned int gx_frame_buffer_size(void)
4926 {
4927 unsigned int val;
4928
4929 +#ifdef CONFIG_OLPC
4930 + if (machine_is_olpc() && !olpc_has_vsa()) {
4931 + u32 hi,lo;
4932 + rdmsr(GLIU0_P2D_RO0, lo, hi);
4933 +
4934 + /* Top page number */
4935 + val = ((hi & 0xff) << 12) | ((lo & 0xfff00000) >> 20);
4936 +
4937 + val -= (lo & 0x000fffff); /* Subtract bottom page number */
4938 + val += 1; /* Adjust page count */
4939 + return (val << 12);
4940 + }
4941 +#endif
4942 +
4943 /* FB size is reported by a virtual register */
4944 /* Virtual register class = 0x02 */
4945 /* VG_MEM_SIZE(512Kb units) = 0x00 */
4946 @@ -41,7 +59,6 @@ unsigned int gx_frame_buffer_size(void)
4947 val = (unsigned int)(inw(0xAC1E)) & 0xFFl;
4948 return (val << 19);
4949 }
4950 -#endif
4951
4952 int gx_line_delta(int xres, int bpp)
4953 {
4954 @@ -63,23 +80,23 @@ static void gx_set_mode(struct fb_info *
4955 gcfg = readl(par->dc_regs + DC_GENERAL_CFG);
4956 dcfg = readl(par->dc_regs + DC_DISPLAY_CFG);
4957
4958 - /* Disable the timing generator. */
4959 - dcfg &= ~(DC_DCFG_TGEN);
4960 - writel(dcfg, par->dc_regs + DC_DISPLAY_CFG);
4961 -
4962 - /* Wait for pending memory requests before disabling the FIFO load. */
4963 - udelay(100);
4964 -
4965 - /* Disable FIFO load and compression. */
4966 - gcfg &= ~(DC_GCFG_DFLE | DC_GCFG_CMPE | DC_GCFG_DECE);
4967 - writel(gcfg, par->dc_regs + DC_GENERAL_CFG);
4968 -
4969 - /* Setup DCLK and its divisor. */
4970 - par->vid_ops->set_dclk(info);
4971 -
4972 - /*
4973 - * Setup new mode.
4974 - */
4975 + /* Programming the clock is costly and ugly, so avoid if if we can */
4976 +
4977 + if (par->curdclk != info->var.pixclock) {
4978 + /* Disable the timing generator. */
4979 + dcfg &= ~(DC_DCFG_TGEN);
4980 + writel(dcfg, par->dc_regs + DC_DISPLAY_CFG);
4981 +
4982 + /* Wait for pending memory requests before disabling the FIFO load. */
4983 + udelay(100);
4984 +
4985 + /* Disable FIFO load and compression. */
4986 + gcfg &= ~(DC_GCFG_DFLE | DC_GCFG_CMPE | DC_GCFG_DECE);
4987 + writel(gcfg, par->dc_regs + DC_GENERAL_CFG);
4988 +
4989 + /* Setup DCLK and its divisor. */
4990 + par->vid_ops->set_dclk(info);
4991 + }
4992
4993 /* Clear all unused feature bits. */
4994 gcfg &= DC_GCFG_YUVM | DC_GCFG_VDSE;
4995 @@ -90,12 +107,13 @@ static void gx_set_mode(struct fb_info *
4996 gcfg |= (6 << DC_GCFG_DFHPEL_POS) | (5 << DC_GCFG_DFHPSL_POS) | DC_GCFG_DFLE;
4997
4998 /* Framebuffer start offset. */
4999 - writel(0, par->dc_regs + DC_FB_ST_OFFSET);
5000 + rmwl(0, par->dc_regs + DC_FB_ST_OFFSET);
5001
5002 /* Line delta and line buffer length. */
5003 - writel(info->fix.line_length >> 3, par->dc_regs + DC_GFX_PITCH);
5004 - writel(((info->var.xres * info->var.bits_per_pixel/8) >> 3) + 2,
5005 - par->dc_regs + DC_LINE_SIZE);
5006 + rmwl(info->fix.line_length >> 3, par->dc_regs + DC_GFX_PITCH);
5007 +
5008 + rmwl(((info->var.xres * info->var.bits_per_pixel/8) >> 3) + 2,
5009 + par->dc_regs + DC_LINE_SIZE);
5010
5011
5012 /* Enable graphics and video data and unmask address lines. */
5013 @@ -134,17 +152,16 @@ static void gx_set_mode(struct fb_info *
5014 vblankend = vsyncend + info->var.upper_margin;
5015 vtotal = vblankend;
5016
5017 - writel((hactive - 1) | ((htotal - 1) << 16), par->dc_regs + DC_H_ACTIVE_TIMING);
5018 - writel((hblankstart - 1) | ((hblankend - 1) << 16), par->dc_regs + DC_H_BLANK_TIMING);
5019 - writel((hsyncstart - 1) | ((hsyncend - 1) << 16), par->dc_regs + DC_H_SYNC_TIMING);
5020 -
5021 - writel((vactive - 1) | ((vtotal - 1) << 16), par->dc_regs + DC_V_ACTIVE_TIMING);
5022 - writel((vblankstart - 1) | ((vblankend - 1) << 16), par->dc_regs + DC_V_BLANK_TIMING);
5023 - writel((vsyncstart - 1) | ((vsyncend - 1) << 16), par->dc_regs + DC_V_SYNC_TIMING);
5024 + rmwl((hactive - 1) | ((htotal - 1) << 16), par->dc_regs + DC_H_ACTIVE_TIMING);
5025 + rmwl((hblankstart - 1) | ((hblankend - 1) << 16), par->dc_regs + DC_H_BLANK_TIMING);
5026 + rmwl((hsyncstart - 1) | ((hsyncend - 1) << 16), par->dc_regs + DC_H_SYNC_TIMING);
5027 + rmwl((vactive - 1) | ((vtotal - 1) << 16), par->dc_regs + DC_V_ACTIVE_TIMING);
5028 + rmwl((vblankstart - 1) | ((vblankend - 1) << 16), par->dc_regs + DC_V_BLANK_TIMING);
5029 + rmwl((vsyncstart - 1) | ((vsyncend - 1) << 16), par->dc_regs + DC_V_SYNC_TIMING);
5030
5031 /* Write final register values. */
5032 - writel(dcfg, par->dc_regs + DC_DISPLAY_CFG);
5033 - writel(gcfg, par->dc_regs + DC_GENERAL_CFG);
5034 + rmwl(dcfg, par->dc_regs + DC_DISPLAY_CFG);
5035 + rmwl(gcfg, par->dc_regs + DC_GENERAL_CFG);
5036
5037 par->vid_ops->configure_display(info);
5038
5039 diff -purN linux_2.6.24_org/drivers/video/geode/display_gx.h linux_2.6.24_olpc/drivers/video/geode/display_gx.h
5040 --- linux_2.6.24_org/drivers/video/geode/display_gx.h 2008-02-15 20:11:23.000000000 +0000
5041 +++ linux_2.6.24_olpc/drivers/video/geode/display_gx.h 2008-02-15 18:58:41.000000000 +0000
5042 @@ -20,6 +20,9 @@ extern struct geode_dc_ops gx_dc_ops;
5043 #define GLD_MSR_CONFIG 0xC0002001
5044 #define GLD_MSR_CONFIG_DM_FP 0x40
5045
5046 +/* Used for memory dection on the OLPC */
5047 +#define GLIU0_P2D_RO0 0x10000029
5048 +
5049 /* Display controller registers */
5050
5051 #define DC_UNLOCK 0x00
5052 diff -purN linux_2.6.24_org/drivers/video/geode/geodefb.h linux_2.6.24_olpc/drivers/video/geode/geodefb.h
5053 --- linux_2.6.24_org/drivers/video/geode/geodefb.h 2008-02-15 20:11:23.000000000 +0000
5054 +++ linux_2.6.24_olpc/drivers/video/geode/geodefb.h 2008-02-15 18:58:41.000000000 +0000
5055 @@ -12,6 +12,10 @@
5056 #ifndef __GEODEFB_H__
5057 #define __GEODEFB_H__
5058
5059 +#define FB_POWER_STATE_OFF 0
5060 +#define FB_POWER_STATE_SUSPEND 1
5061 +#define FB_POWER_STATE_ON 2
5062 +
5063 struct geodefb_info;
5064
5065 struct geode_dc_ops {
5066 @@ -21,18 +25,24 @@ struct geode_dc_ops {
5067
5068 struct geode_vid_ops {
5069 void (*set_dclk)(struct fb_info *);
5070 + unsigned int (*get_dclk)(struct fb_info *);
5071 void (*configure_display)(struct fb_info *);
5072 int (*blank_display)(struct fb_info *, int blank_mode);
5073 };
5074
5075 struct geodefb_par {
5076 int enable_crt;
5077 + int fbactive; /* True if the current console is in KD_GRAPHICS mode */
5078 int panel_x; /* dimensions of an attached flat panel, non-zero => enable panel */
5079 int panel_y;
5080 + unsigned int curdclk; /* Used by GX to avoid unnessesary clock switching */
5081 void __iomem *dc_regs;
5082 void __iomem *vid_regs;
5083 + void __iomem *gp_regs;
5084 struct geode_dc_ops *dc_ops;
5085 struct geode_vid_ops *vid_ops;
5086 +
5087 + int state;
5088 };
5089
5090 #endif /* !__GEODEFB_H__ */
5091 diff -purN linux_2.6.24_org/drivers/video/geode/geode_regs.h linux_2.6.24_olpc/drivers/video/geode/geode_regs.h
5092 --- linux_2.6.24_org/drivers/video/geode/geode_regs.h 1970-01-01 01:00:00.000000000 +0100
5093 +++ linux_2.6.24_olpc/drivers/video/geode/geode_regs.h 2008-02-15 18:58:41.000000000 +0000
5094 @@ -0,0 +1,255 @@
5095 +/* This header file defines the registers and suspend/resume
5096 + structures for the Geode GX and LX. The lxfb driver defines
5097 + _GEODELX_ before including this file, which will unlock the
5098 + extra registers that are only valid for LX.
5099 +*/
5100 +
5101 +#ifndef _GEODE_REGS_H_
5102 +#define _GEODE_REGS_H_
5103 +
5104 +/* MSRs */
5105 +
5106 +#define GX_VP_MSR_PAD_SELECT 0xC0002011
5107 +#define LX_VP_MSR_PAD_SELECT 0x48000011
5108 +
5109 +#define GEODE_MSR_GLCP_DOTPLL 0x4c000015
5110 +
5111 +#define GLCP_DOTPLL_RESET (1 << 0)
5112 +#define GLCP_DOTPLL_BYPASS (1 << 15)
5113 +#define GLCP_DOTPLL_HALFPIX (1 << 24)
5114 +#define GLCP_DOTPLL_LOCK (1 << 25)
5115 +
5116 +/* Registers */
5117 +#define VP_FP_START 0x400
5118 +
5119 +
5120 +#ifdef _GEODELX_
5121 +
5122 +#define GP_REG_SIZE 0x7C
5123 +#define DC_REG_SIZE 0xF0
5124 +#define VP_REG_SIZE 0x158
5125 +#define FP_REG_SIZE 0x70
5126 +
5127 +#else
5128 +
5129 +#define GP_REG_SIZE 0x50
5130 +#define DC_REG_SIZE 0x90
5131 +#define VP_REG_SIZE 0x138
5132 +#define FP_REG_SIZE 0x70
5133 +
5134 +#endif
5135 +
5136 +#define DC_PAL_SIZE 0x105
5137 +#define VP_COEFF_COUNT 512
5138 +#define DC_HFILT_SIZE 256
5139 +#define DC_VFILT_SIZE 256
5140 +
5141 +struct geoderegs {
5142 +
5143 + struct {
5144 + u64 padsel;
5145 + u64 dotpll;
5146 +
5147 +#ifdef _GEODELX_
5148 + u64 dfglcfg;
5149 + u64 dcspare;
5150 +#else
5151 + u64 rstpll;
5152 +#endif
5153 + } msr;
5154 +
5155 + union {
5156 + unsigned char b[GP_REG_SIZE];
5157 + struct {
5158 + u32 dst_offset; /* 0x00 */
5159 + u32 src_offset; /* 0x04 */
5160 + u32 stride; /* 0x08 */
5161 + u32 wid_height; /* 0x0C */
5162 + u32 src_color_fg; /* 0x10 */
5163 + u32 src_color_bg; /* 0x14 */
5164 + u32 pat_color_0; /* 0x18 */
5165 + u32 pat_color_1; /* 0x1C */
5166 + u32 pat_color_2; /* 0x20 */
5167 + u32 pat_color_3; /* 0x24 */
5168 + u32 pat_color_4; /* 0x28 */
5169 + u32 pat_color_5; /* 0x2C */
5170 + u32 pat_data_0; /* 0x30 */
5171 + u32 pat_data_1; /* 0x34 */
5172 + u32 raster_mode; /* 0x38 */
5173 + u32 vector_mode; /* 0x3C */
5174 + u32 blt_mode; /* 0x40 */
5175 + u32 blit_status; /* 0x4C */
5176 + u32 hst_src; /* 0x48 */
5177 + u32 base_offset; /* 0x4C */
5178 +
5179 +#ifdef _GEODELX_
5180 + u32 cmd_top; /* 0x50 */
5181 + u32 cmd_bot; /* 0x54 */
5182 + u32 cmd_read; /* 0x58 */
5183 + u32 cmd_write; /* 0x5C */
5184 + u32 ch3_offset; /* 0x60 */
5185 + u32 ch3_mode_str; /* 0x64 */
5186 + u32 ch3_width; /* 0x68 */
5187 + u32 ch3_hsrc; /* 0x6C */
5188 + u32 lut_index; /* 0x70 */
5189 + u32 lut_data; /* 0x74 */
5190 + u32 int_cntrl; /* 0x78 */
5191 +#endif
5192 + } r;
5193 + } gp;
5194 +
5195 + union {
5196 + unsigned char b[DC_REG_SIZE];
5197 +
5198 + struct {
5199 + u32 unlock; /* 0x00 */
5200 + u32 gcfg; /* 0x04 */
5201 + u32 dcfg; /* 0x08 */
5202 + u32 arb; /* 0x0C */
5203 + u32 fb_st_offset; /* 0x10 */
5204 + u32 cb_st_offset; /* 0x14 */
5205 + u32 curs_st_offset; /* 0x18 */
5206 + u32 icon_st_offset; /* 0x1C */
5207 + u32 vid_y_st_offset; /* 0x20 */
5208 + u32 vid_u_st_offset; /* 0x24 */
5209 + u32 vid_v_st_offset; /* 0x28 */
5210 + u32 dctop; /* 0x2c */
5211 + u32 line_size; /* 0x30 */
5212 + u32 gfx_pitch; /* 0x34 */
5213 + u32 vid_yuv_pitch; /* 0x38 */
5214 + u32 rsvd2; /* 0x3C */
5215 + u32 h_active_timing; /* 0x40 */
5216 + u32 h_blank_timing; /* 0x44 */
5217 + u32 h_sync_timing; /* 0x48 */
5218 + u32 rsvd3; /* 0x4C */
5219 + u32 v_active_timing; /* 0x50 */
5220 + u32 v_blank_timing; /* 0x54 */
5221 + u32 v_sync_timing; /* 0x58 */
5222 + u32 fbactive; /* 0x5C */
5223 + u32 dc_cursor_x; /* 0x60 */
5224 + u32 dc_cursor_y; /* 0x64 */
5225 + u32 dc_icon_x; /* 0x68 */
5226 + u32 dc_line_cnt; /* 0x6C */
5227 + u32 rsvd5; /* 0x70 - palette address */
5228 + u32 rsvd6; /* 0x74 - palette data */
5229 + u32 dfifo_diag; /* 0x78 */
5230 + u32 cfifo_diag; /* 0x7C */
5231 + u32 dc_vid_ds_delta; /* 0x80 */
5232 + u32 gliu0_mem_offset; /* 0x84 */
5233 + u32 dv_ctl; /* 0x88 - added by LX */
5234 + u32 dv_acc; /* 0x8C */
5235 +
5236 +#ifdef _GEODELX_
5237 + u32 gfx_scale;
5238 + u32 irq_filt_ctl;
5239 + u32 filt_coeff1;
5240 + u32 filt_coeff2;
5241 + u32 vbi_event_ctl;
5242 + u32 vbi_odd_ctl;
5243 + u32 vbi_hor;
5244 + u32 vbi_ln_odd;
5245 + u32 vbi_ln_event;
5246 + u32 vbi_pitch;
5247 + u32 clr_key;
5248 + u32 clr_key_mask;
5249 + u32 clr_key_x;
5250 + u32 clr_key_y;
5251 + u32 irq;
5252 + u32 rsvd8;
5253 + u32 genlk_ctrl;
5254 + u32 vid_even_y_st_offset; /* 0xD8 */
5255 + u32 vid_even_u_st_offset; /* 0xDC */
5256 + u32 vid_even_v_st_offset; /* 0xE0 */
5257 + u32 v_active_even_timing; /* 0xE4 */
5258 + u32 v_blank_even_timing; /* 0xE8 */
5259 + u32 v_sync_even_timing; /* 0xEC */
5260 +#endif
5261 + } r;
5262 + } dc;
5263 +
5264 + union {
5265 + unsigned char b[VP_REG_SIZE];
5266 +
5267 + struct {
5268 + u64 vcfg; /* 0x00 */
5269 + u64 dcfg; /* 0x08 */
5270 + u64 vx; /* 0x10 */
5271 + u64 vy; /* 0x18 */
5272 + u64 vs; /* 0x20 */
5273 + u64 vck; /* 0x28 */
5274 + u64 vcm; /* 0x30 */
5275 + u64 rsvd1; /* 0x38 - Gamma address*/
5276 + u64 rsvd2; /* 0x40 - Gamma data*/
5277 + u64 slr; /* 0x48 - LX only*/
5278 + u64 misc; /* 0x50 */
5279 + u64 ccs; /* 0x58 */
5280 + u64 vys; /* 0x60 */
5281 + u64 vxs; /* 0x68 */
5282 + u64 rsvd4; /* 0x70 */
5283 + u64 vdc; /* 0x78 */
5284 + u64 vco; /* 0x80 */
5285 + u64 crc; /* 0x88 */
5286 + u64 crc32; /* 0x90 */
5287 + u64 vde; /* 0x98 */
5288 + u64 cck; /* 0xA0 */
5289 + u64 ccm; /* 0xA8 */
5290 + u64 cc1; /* 0xB0 */
5291 + u64 cc2; /* 0xB8 */
5292 + u64 a1x; /* 0xC0 */
5293 + u64 a1y; /* 0xC8 */
5294 + u64 a1c; /* 0xD0 */
5295 + u64 a1t; /* 0xD8 */
5296 + u64 a2x; /* 0xE0 */
5297 + u64 a2y; /* 0xE8 */
5298 + u64 a2c; /* 0xF0 */
5299 + u64 a2t; /* 0xF8 */
5300 + u64 a3x; /* 0x100 */
5301 + u64 a3y; /* 0x108 */
5302 + u64 a3c; /* 0x110 */
5303 + u64 a3t; /* 0x118 */
5304 + u64 vrr; /* 0x120 */
5305 + u64 awt; /* 0x128 */
5306 + u64 vtm; /* 0x130 */
5307 +#ifdef _GEODELX_
5308 + u64 vye; /* 0x138 */
5309 + u64 a1ye; /* 0x140 */
5310 + u32 a2ye; /* 0x148 */
5311 + u32 a3ye; /* 0x150 */
5312 +#endif
5313 + } r;
5314 + } vp;
5315 +
5316 + union {
5317 + unsigned char b[FP_REG_SIZE];
5318 +
5319 + struct {
5320 + u64 pt1; /* 0x400 */
5321 + u64 pt2; /* 0x408 */
5322 + u64 pm; /* 0x410 */
5323 + u64 dfc; /* 0x418 */
5324 + u64 blfsr; /* 0x420 */
5325 + u64 rlfsr; /* 0x428 */
5326 + u64 fmi; /* 0x430 */
5327 + u64 fmd; /* 0x438 */
5328 + u64 rsvd; /* 0x440 */
5329 + u64 dca; /* 0x448 */
5330 + u64 dmd; /* 0x450 */
5331 + u64 crc; /* 0x458 */
5332 + u64 fbb; /* 0x460 */
5333 + u64 crc32; /* 0x468 */
5334 + } r;
5335 + } fp;
5336 +
5337 + u32 pal[DC_PAL_SIZE];
5338 + u32 gamma[256];
5339 +
5340 +#ifdef _GEODELX_
5341 +
5342 + u32 hcoeff[DC_HFILT_SIZE * 2];
5343 + u32 vcoeff[DC_VFILT_SIZE];
5344 +
5345 + u32 vp_coeff[VP_COEFF_COUNT];
5346 +#endif
5347 +};
5348 +
5349 +#endif
5350 diff -purN linux_2.6.24_org/drivers/video/geode/gxfb_core.c linux_2.6.24_olpc/drivers/video/geode/gxfb_core.c
5351 --- linux_2.6.24_org/drivers/video/geode/gxfb_core.c 2008-02-15 20:11:23.000000000 +0000
5352 +++ linux_2.6.24_olpc/drivers/video/geode/gxfb_core.c 2008-02-15 18:58:41.000000000 +0000
5353 @@ -30,12 +30,31 @@
5354 #include <linux/fb.h>
5355 #include <linux/init.h>
5356 #include <linux/pci.h>
5357 +#include <linux/notifier.h>
5358 +#include <linux/vt_kern.h>
5359 +#include <linux/console.h>
5360 +#include <asm/uaccess.h>
5361 +#include <asm/olpc.h>
5362
5363 #include "geodefb.h"
5364 #include "display_gx.h"
5365 #include "video_gx.h"
5366
5367 +#define FBIOSGAMMA _IOW('F', 0x20, void *)
5368 +#define FBIOGGAMMA _IOW('F', 0x21, void *)
5369 +
5370 +#ifdef DEBUG
5371 +
5372 +#define FBIODUMPGP _IOW('F', 0x22, void *)
5373 +#define FBIODUMPDC _IOW('F', 0x23, void *)
5374 +#define FBIODUMPVP _IOW('F', 0x24, void *)
5375 +#define FBIODUMPFP _IOW('F', 0x25, void *)
5376 +
5377 +#endif
5378 +
5379 static char *mode_option;
5380 +static int noclear;
5381 +struct fb_info *gxfb_info;
5382
5383 /* Modes relevant to the GX (taken from modedb.c) */
5384 static const struct fb_videomode gx_modedb[] __initdata = {
5385 @@ -103,8 +122,20 @@ static const struct fb_videomode gx_mode
5386 { NULL, 85, 1600, 1200, 4357, 304, 64, 46, 1, 192, 3,
5387 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
5388 FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
5389 + /* 1200x900-75 - CRT timings for the OLPC mode */
5390 + { NULL, 75, 1200, 900, 8049, 104, 240, 29, 54, 136, 3,
5391 + 0, FB_VMODE_NONINTERLACED, 0 }
5392 };
5393
5394 +#ifdef CONFIG_OLPC
5395 +static const struct fb_videomode gx_dcon_modedb[] __initdata = {
5396 + /* The only mode the DCON has is 1200x900 */
5397 + { NULL, 50, 1200, 900, 17460, 24, 8, 4, 5, 8, 3,
5398 + 0, FB_VMODE_NONINTERLACED, 0 }
5399 +};
5400 +#endif
5401 +
5402 +
5403 static int gxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
5404 {
5405 if (var->xres > 1600 || var->yres > 1200)
5406 @@ -137,7 +168,7 @@ static int gxfb_check_var(struct fb_var_
5407 return 0;
5408 }
5409
5410 -static int gxfb_set_par(struct fb_info *info)
5411 +int gxfb_set_par(struct fb_info *info)
5412 {
5413 struct geodefb_par *par = info->par;
5414
5415 @@ -204,16 +235,26 @@ static int gxfb_blank(int blank_mode, st
5416 return par->vid_ops->blank_display(info, blank_mode);
5417 }
5418
5419 +static int fbsize;
5420 +
5421 static int __init gxfb_map_video_memory(struct fb_info *info, struct pci_dev *dev)
5422 {
5423 struct geodefb_par *par = info->par;
5424 - int fb_len;
5425 int ret;
5426
5427 ret = pci_enable_device(dev);
5428 if (ret < 0)
5429 return ret;
5430
5431 + ret = pci_request_region(dev, 1, "gxfb (graphics processor)");
5432 + if (ret < 0)
5433 + return ret;
5434 +
5435 + par->gp_regs = ioremap(pci_resource_start(dev, 1),
5436 + pci_resource_len(dev, 1));
5437 + if (!par->gp_regs)
5438 + return -ENOMEM;
5439 +
5440 ret = pci_request_region(dev, 3, "gxfb (video processor)");
5441 if (ret < 0)
5442 return ret;
5443 @@ -232,36 +273,118 @@ static int __init gxfb_map_video_memory(
5444 ret = pci_request_region(dev, 0, "gxfb (framebuffer)");
5445 if (ret < 0)
5446 return ret;
5447 - if ((fb_len = gx_frame_buffer_size()) < 0)
5448 - return -ENOMEM;
5449 +
5450 + /* If the fbsize wasn't specified then try to probe it */
5451 +
5452 + if (!fbsize) {
5453 + fbsize = gx_frame_buffer_size();
5454 + if (fbsize == 0)
5455 + return -ENOMEM;
5456 + }
5457 +
5458 info->fix.smem_start = pci_resource_start(dev, 0);
5459 - info->fix.smem_len = fb_len;
5460 + info->fix.smem_len = fbsize;
5461 info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len);
5462 if (!info->screen_base)
5463 return -ENOMEM;
5464
5465 - /* Set the 16MB aligned base address of the graphics memory region
5466 + /* Set the 16MiB aligned base address of the graphics memory region
5467 * in the display controller */
5468
5469 writel(info->fix.smem_start & 0xFF000000,
5470 par->dc_regs + DC_GLIU0_MEM_OFFSET);
5471
5472 - dev_info(&dev->dev, "%d Kibyte of video memory at 0x%lx\n",
5473 + dev_info(&dev->dev, "%d KiB of video memory at 0x%lx\n",
5474 info->fix.smem_len / 1024, info->fix.smem_start);
5475
5476 return 0;
5477 }
5478
5479 +static int gxfb_ioctl( struct fb_info *info, unsigned int cmd,
5480 + unsigned long arg)
5481 +{
5482 + unsigned int gamma[GXFB_GAMMA_DWORDS];
5483 + int ret = -EINVAL;
5484 + struct geodefb_par *par = info->par;
5485 + int i;
5486 +
5487 + switch(cmd) {
5488 + case FBIOSGAMMA:
5489 + /* Read the gamma information from the user - 256 dwords */
5490 +
5491 + if (copy_from_user(gamma, (void * __user) arg, GXFB_GAMMA_SIZE))
5492 + return -EFAULT;
5493 +
5494 + writel(0, par->vid_regs + GX_GAR);
5495 +
5496 + /* Sequential writes to the data register will increment the
5497 + address automatically */
5498 +
5499 + for(i = 0; i < GXFB_GAMMA_DWORDS; i++)
5500 + writel(gamma[i] & 0xFFFFFF, par->vid_regs + GX_GDR);
5501 +
5502 + writel(readl(par->vid_regs + GX_MISC) & ~GX_MISC_GAM_EN,
5503 + par->vid_regs + GX_MISC);
5504 +
5505 + ret = 0;
5506 + break;
5507 +
5508 + case FBIOGGAMMA:
5509 + if (readl(par->vid_regs + GX_MISC) & GX_MISC_GAM_EN)
5510 + return -EINVAL;
5511 +
5512 + memset(gamma, 0, GXFB_GAMMA_SIZE);
5513 + writel(0, par->vid_regs + GX_GAR);
5514 +
5515 + for(i = 0; i < GXFB_GAMMA_DWORDS;i++)
5516 + gamma[i] = readl(par->vid_regs + GX_GDR);
5517 +
5518 + if (copy_to_user((void * __user) arg, gamma, GXFB_GAMMA_SIZE))
5519 + ret = -EFAULT;
5520 + else
5521 + ret = 0;
5522 +
5523 + break;
5524 +
5525 +#ifdef DEBUG
5526 + case FBIODUMPGP:
5527 + ret = 0;
5528 + dump_regs(info, 0);
5529 + break;
5530 +
5531 + case FBIODUMPDC:
5532 + ret = 0;
5533 + dump_regs(info, 1);
5534 + break;
5535 +
5536 + case FBIODUMPVP:
5537 + ret = 0;
5538 + dump_regs(info, 2);
5539 + break;
5540 +
5541 + case FBIODUMPFP:
5542 + ret = 0;
5543 + dump_regs(info, 3);
5544 + break;
5545 +#endif
5546 + }
5547 +
5548 + return ret;
5549 +}
5550 +
5551 static struct fb_ops gxfb_ops = {
5552 .owner = THIS_MODULE,
5553 .fb_check_var = gxfb_check_var,
5554 .fb_set_par = gxfb_set_par,
5555 .fb_setcolreg = gxfb_setcolreg,
5556 .fb_blank = gxfb_blank,
5557 + .fb_ioctl = gxfb_ioctl,
5558 /* No HW acceleration for now. */
5559 .fb_fillrect = cfb_fillrect,
5560 .fb_copyarea = cfb_copyarea,
5561 .fb_imageblit = cfb_imageblit,
5562 + .fb_powerdown = gxfb_powerdown,
5563 + .fb_powerup = gxfb_powerup,
5564 };
5565
5566 static struct fb_info * __init gxfb_init_fbinfo(struct device *dev)
5567 @@ -303,23 +426,86 @@ static struct fb_info * __init gxfb_init
5568 return info;
5569 }
5570
5571 -static int __init gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
5572 +static int gxfb_console_notify(struct notifier_block *self,
5573 + unsigned long action, void *data)
5574 +{
5575 + if (gxfb_info != NULL) {
5576 + struct geodefb_par *par = gxfb_info->par;
5577 + par->fbactive = (action == CONSOLE_EVENT_SWITCH_TEXT) ? 0 : 1;
5578 + }
5579 +
5580 + return NOTIFY_OK;
5581 +}
5582 +
5583 +static struct notifier_block gxfb_console_notifier = {
5584 + .notifier_call = gxfb_console_notify
5585 +};
5586 +
5587 +#ifdef CONFIG_PM
5588 +
5589 +static int gxfb_suspend(struct pci_dev *pdev, pm_message_t state)
5590 +{
5591 + struct fb_info *info = pci_get_drvdata(pdev);
5592 + struct geodefb_par *par = info->par;
5593 +
5594 + if (pdev->dev.power.power_state.event == state.event)
5595 + return 0;
5596 +
5597 + if (state.event == PM_EVENT_SUSPEND) {
5598 +
5599 + acquire_console_sem();
5600 + gxfb_powerdown(info);
5601 +
5602 + par->state = FB_POWER_STATE_OFF;
5603 + fb_set_suspend(info, 1);
5604 +
5605 + release_console_sem();
5606 + }
5607 +
5608 + pdev->dev.power.power_state = state;
5609 + return 0;
5610 +}
5611 +
5612 +static int gxfb_resume(struct pci_dev *pdev)
5613 +{
5614 + struct fb_info *info = pci_get_drvdata(pdev);
5615 +
5616 + acquire_console_sem();
5617 +
5618 + /* Turn the engine completely on */
5619 +
5620 + if (gxfb_powerup(info))
5621 + printk(KERN_ERR "gxfb: Powerup failed\n");
5622 +
5623 + fb_set_suspend(info, 0);
5624 + release_console_sem();
5625 +
5626 + pdev->dev.power.power_state = PMSG_ON;
5627 + return 0;
5628 +}
5629 +#endif
5630 +
5631 +static int __init gxfb_probe(struct pci_dev *pdev,
5632 + const struct pci_device_id *id)
5633 {
5634 struct geodefb_par *par;
5635 - struct fb_info *info;
5636 int ret;
5637 unsigned long val;
5638
5639 - info = gxfb_init_fbinfo(&pdev->dev);
5640 - if (!info)
5641 + struct fb_videomode *modedb_ptr;
5642 + int modedb_size;
5643 +
5644 + gxfb_info = gxfb_init_fbinfo(&pdev->dev);
5645 + if (gxfb_info == NULL)
5646 return -ENOMEM;
5647 - par = info->par;
5648 +
5649 + par = gxfb_info->par;
5650
5651 /* GX display controller and GX video device. */
5652 par->dc_ops = &gx_dc_ops;
5653 par->vid_ops = &gx_vid_ops;
5654
5655 - if ((ret = gxfb_map_video_memory(info, pdev)) < 0) {
5656 + if ((ret = gxfb_map_video_memory(gxfb_info, pdev)) < 0) {
5657 dev_err(&pdev->dev, "failed to map frame buffer or controller registers\n");
5658 goto err;
5659 }
5660 @@ -333,32 +519,60 @@ static int __init gxfb_probe(struct pci_
5661 else
5662 par->enable_crt = 1;
5663
5664 - ret = fb_find_mode(&info->var, info, mode_option,
5665 - gx_modedb, ARRAY_SIZE(gx_modedb), NULL, 16);
5666 + /* Get the current dotclock */
5667 +
5668 + par->curdclk = (par->vid_ops->get_dclk) ? par->vid_ops->get_dclk(gxfb_info) : 0;
5669 +
5670 + /* We need to determine a display mode right now, so we will
5671 + * check to see if the DCON was previously detected by the BIOS
5672 + * and use that to make our mode database decision.
5673 + */
5674 +
5675 + modedb_ptr = (struct fb_videomode *) gx_modedb;
5676 + modedb_size = ARRAY_SIZE(gx_modedb);
5677 +
5678 +#ifdef CONFIG_OLPC
5679 + if (olpc_has_dcon()) {
5680 + modedb_ptr = (struct fb_videomode *) gx_dcon_modedb;
5681 + modedb_size = ARRAY_SIZE(gx_dcon_modedb);
5682 + }
5683 +#endif
5684 +
5685 + ret = fb_find_mode(&gxfb_info->var, gxfb_info, mode_option,
5686 + modedb_ptr, modedb_size, NULL, 16);
5687 +
5688 if (ret == 0 || ret == 4) {
5689 dev_err(&pdev->dev, "could not find valid video mode\n");
5690 ret = -EINVAL;
5691 goto err;
5692 }
5693
5694 + /* Clear the screen of garbage, unless noclear was specified,
5695 + * in which case we assume the user knows what he is doing */
5696 +
5697 + if (!noclear)
5698 + memset_io(gxfb_info->screen_base, 0, gxfb_info->fix.smem_len);
5699 +
5700 + gxfb_check_var(&gxfb_info->var, gxfb_info);
5701 + gxfb_set_par(gxfb_info);
5702 +
5703 + /* We are powered up */
5704 + par->state = FB_POWER_STATE_ON;
5705
5706 - /* Clear the frame buffer of garbage. */
5707 - memset_io(info->screen_base, 0, info->fix.smem_len);
5708
5709 - gxfb_check_var(&info->var, info);
5710 - gxfb_set_par(info);
5711 + console_event_register(&gxfb_console_notifier);
5712
5713 - if (register_framebuffer(info) < 0) {
5714 + if (register_framebuffer(gxfb_info) < 0) {
5715 ret = -EINVAL;
5716 goto err;
5717 }
5718 - pci_set_drvdata(pdev, info);
5719 - printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, info->fix.id);
5720 + pci_set_drvdata(pdev, gxfb_info);
5721 + printk(KERN_INFO "fb%d: %s frame buffer device\n", gxfb_info->node, gxfb_info->fix.id);
5722 return 0;
5723
5724 err:
5725 - if (info->screen_base) {
5726 - iounmap(info->screen_base);
5727 + if (gxfb_info->screen_base) {
5728 + iounmap(gxfb_info->screen_base);
5729 pci_release_region(pdev, 0);
5730 }
5731 if (par->vid_regs) {
5732 @@ -370,8 +584,9 @@ static int __init gxfb_probe(struct pci_
5733 pci_release_region(pdev, 2);
5734 }
5735
5736 - if (info)
5737 - framebuffer_release(info);
5738 + if (gxfb_info)
5739 + framebuffer_release(gxfb_info);
5740 +
5741 return ret;
5742 }
5743
5744 @@ -397,9 +612,7 @@ static void gxfb_remove(struct pci_dev *
5745 }
5746
5747 static struct pci_device_id gxfb_id_table[] = {
5748 - { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_GX_VIDEO,
5749 - PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
5750 - 0xff0000, 0 },
5751 + { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_GX_VIDEO) },
5752 { 0, }
5753 };
5754
5755 @@ -410,22 +623,30 @@ static struct pci_driver gxfb_driver = {
5756 .id_table = gxfb_id_table,
5757 .probe = gxfb_probe,
5758 .remove = gxfb_remove,
5759 +#ifdef CONFIG_PM
5760 + .suspend = gxfb_suspend,
5761 + .resume = gxfb_resume
5762 +#endif
5763 };
5764
5765 #ifndef MODULE
5766 -static int __init gxfb_setup(char *options)
5767 -{
5768 +static int __init gxfb_setup(char *options) {
5769
5770 char *opt;
5771
5772 if (!options || !*options)
5773 return 0;
5774
5775 - while ((opt = strsep(&options, ",")) != NULL) {
5776 + while((opt = strsep(&options, ",")) != NULL) {
5777 if (!*opt)
5778 continue;
5779
5780 - mode_option = opt;
5781 + if (!strncmp(opt, "fbsize:", 7))
5782 + fbsize = simple_strtoul(opt+7, NULL, 0);
5783 + else if (!strcmp(opt, "noclear"))
5784 + noclear = 1;
5785 + else
5786 + mode_option = opt;
5787 }
5788
5789 return 0;
5790 @@ -444,7 +665,6 @@ static int __init gxfb_init(void)
5791 #endif
5792 return pci_register_driver(&gxfb_driver);
5793 }
5794 -
5795 static void __exit gxfb_cleanup(void)
5796 {
5797 pci_unregister_driver(&gxfb_driver);
5798 @@ -456,5 +676,8 @@ module_exit(gxfb_cleanup);
5799 module_param(mode_option, charp, 0);
5800 MODULE_PARM_DESC(mode_option, "video mode (<x>x<y>[-<bpp>][@<refr>])");
5801
5802 +module_param(fbsize, int, 0);
5803 +MODULE_PARM_DESC(fbsize, "video memory size");
5804 +
5805 MODULE_DESCRIPTION("Framebuffer driver for the AMD Geode GX");
5806 MODULE_LICENSE("GPL");
5807 diff -purN linux_2.6.24_org/drivers/video/geode/Kconfig linux_2.6.24_olpc/drivers/video/geode/Kconfig
5808 --- linux_2.6.24_org/drivers/video/geode/Kconfig 2008-02-15 20:11:23.000000000 +0000
5809 +++ linux_2.6.24_olpc/drivers/video/geode/Kconfig 2008-02-15 18:58:41.000000000 +0000
5810 @@ -38,26 +38,6 @@ config FB_GEODE_GX
5811
5812 If unsure, say N.
5813
5814 -config FB_GEODE_GX_SET_FBSIZE
5815 - bool "Manually specify the Geode GX framebuffer size"
5816 - depends on FB_GEODE_GX
5817 - default n
5818 - ---help---
5819 - If you want to manually specify the size of your GX framebuffer,
5820 - say Y here, otherwise say N to dynamically probe it.
5821 -
5822 - Say N unless you know what you are doing.
5823 -
5824 -config FB_GEODE_GX_FBSIZE
5825 - hex "Size of the GX framebuffer, in bytes"
5826 - depends on FB_GEODE_GX_SET_FBSIZE
5827 - default "0x1600000"
5828 - ---help---
5829 - Specify the size of the GX framebuffer. Normally, you will
5830 - want this to be MB aligned. Common values are 0x80000 (8MB)
5831 - and 0x1600000 (16MB). Don't change this unless you know what
5832 - you are doing
5833 -
5834 config FB_GEODE_GX1
5835 tristate "AMD Geode GX1 framebuffer support (EXPERIMENTAL)"
5836 depends on FB && FB_GEODE && EXPERIMENTAL
5837 diff -purN linux_2.6.24_org/drivers/video/geode/lxfb_core.c linux_2.6.24_olpc/drivers/video/geode/lxfb_core.c
5838 --- linux_2.6.24_org/drivers/video/geode/lxfb_core.c 2008-02-15 20:11:23.000000000 +0000
5839 +++ linux_2.6.24_olpc/drivers/video/geode/lxfb_core.c 2008-02-15 18:58:41.000000000 +0000
5840 @@ -21,7 +21,8 @@
5841 #include <linux/fb.h>
5842 #include <linux/init.h>
5843 #include <linux/pci.h>
5844 -#include <linux/uaccess.h>
5845 +#include <asm/uaccess.h>
5846 +#include <asm/olpc.h>
5847
5848 #include "lxfb.h"
5849
5850 @@ -35,186 +36,84 @@ static int fbsize;
5851 */
5852
5853 const struct fb_videomode geode_modedb[] __initdata = {
5854 - /* 640x480-60 */
5855 - { NULL, 60, 640, 480, 39682, 48, 8, 25, 2, 88, 2,
5856 + /* 640x480-60 VESA */
5857 + { NULL, 60, 640, 480, 39682, 48, 16, 33, 10, 96, 2,
5858 + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
5859 + /* 640x480-75 VESA */
5860 + { NULL, 75, 640, 480, 31746, 120, 16, 16, 01, 64, 3,
5861 + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
5862 + /* 640x480-85 VESA */
5863 + { NULL, 85, 640, 480, 27777, 80, 56, 25, 01, 56, 3,
5864 + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
5865 + /* 800x600-60 VESA */
5866 + { NULL, 60, 800, 600, 25000, 88, 40, 23, 01, 128, 4,
5867 + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
5868 + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
5869 + /* 800x600-75 VESA */
5870 + { NULL, 75, 800, 600, 20202, 160, 16, 21, 01, 80, 3,
5871 + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
5872 + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
5873 + /* 800x600-85 VESA */
5874 + { NULL, 85, 800, 600, 17761, 152, 32, 27, 01, 64, 3,
5875 + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
5876 + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
5877 + /* 1024x768-60 VESA */
5878 + { NULL, 60, 1024, 768, 15384, 160, 24, 29, 3, 136, 6,
5879 + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
5880 + /* 1024x768-75 VESA */
5881 + { NULL, 75, 1024, 768, 12690, 176, 16, 28, 1, 96, 3,
5882 + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
5883 + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
5884 + /* 1024x768-85 VESA */
5885 + { NULL, 85, 1024, 768, 10582, 208, 48, 36, 1, 96, 3,
5886 + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
5887 + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
5888 + /* 1280x960-60 VESA */
5889 + { NULL, 60, 1280, 960, 9259, 312, 96, 36, 1, 112, 3,
5890 + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
5891 + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
5892 + /* 1280x960-85 VESA */
5893 + { NULL, 85, 1280, 960, 6734, 224, 64, 47, 1, 160, 3,
5894 + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
5895 + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
5896 + /* 1280x1024-60 VESA */
5897 + { NULL, 60, 1280, 1024, 9259, 248, 48, 38, 1, 112, 3,
5898 + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
5899 + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
5900 + /* 1280x1024-75 VESA */
5901 + { NULL, 75, 1280, 1024, 7407, 248, 16, 38, 1, 144, 3,
5902 + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
5903 + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
5904 + /* 1280x1024-85 VESA */
5905 + { NULL, 85, 1280, 1024, 6349, 224, 64, 44, 1, 160, 3,
5906 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
5907 - FB_VMODE_NONINTERLACED, 0 },
5908 - /* 640x400-70 */
5909 - { NULL, 70, 640, 400, 39770, 40, 8, 28, 5, 96, 2,
5910 - FB_SYNC_HOR_HIGH_ACT,
5911 - FB_VMODE_NONINTERLACED, 0 },
5912 - /* 640x480-70 */
5913 - { NULL, 70, 640, 480, 35014, 88, 24, 15, 2, 64, 3,
5914 - 0, FB_VMODE_NONINTERLACED, 0 },
5915 - /* 640x480-72 */
5916 - { NULL, 72, 640, 480, 32102, 120, 16, 20, 1, 40, 3,
5917 - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
5918 - FB_VMODE_NONINTERLACED, 0 },
5919 - /* 640x480-75 */
5920 - { NULL, 75, 640, 480, 31746, 120, 16, 16, 1, 64, 3,
5921 - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
5922 - FB_VMODE_NONINTERLACED, 0 },
5923 - /* 640x480-85 */
5924 - { NULL, 85, 640, 480, 27780, 80, 56, 25, 1, 56, 3,
5925 - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
5926 - FB_VMODE_NONINTERLACED, 0 },
5927 - /* 640x480-90 */
5928 - { NULL, 90, 640, 480, 26392, 96, 32, 22, 1, 64, 3,
5929 - 0, FB_VMODE_NONINTERLACED, 0 },
5930 - /* 640x480-100 */
5931 - { NULL, 100, 640, 480, 23167, 104, 40, 25, 1, 64, 3,
5932 - 0, FB_VMODE_NONINTERLACED, 0 },
5933 - /* 640x480-60 */
5934 - { NULL, 60, 640, 480, 39682, 48, 16, 25, 10, 88, 2,
5935 - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
5936 - FB_VMODE_NONINTERLACED, 0 },
5937 - /* 800x600-56 */
5938 - { NULL, 56, 800, 600, 27901, 128, 24, 22, 1, 72, 2,
5939 - 0, FB_VMODE_NONINTERLACED, 0 },
5940 - /* 800x600-60 */
5941 - { NULL, 60, 800, 600, 25131, 72, 32, 23, 1, 136, 4,
5942 - 0, FB_VMODE_NONINTERLACED, 0 },
5943 - /* 800x600-70 */
5944 - { NULL, 70, 800, 600, 21873, 120, 40, 21, 4, 80, 3,
5945 - 0, FB_VMODE_NONINTERLACED, 0 },
5946 - /* 800x600-72 */
5947 - { NULL, 72, 800, 600, 20052, 64, 56, 23, 37, 120, 6,
5948 - 0, FB_VMODE_NONINTERLACED, 0 },
5949 - /* 800x600-75 */
5950 - { NULL, 75, 800, 600, 20202, 160, 16, 21, 1, 80, 3,
5951 - 0, FB_VMODE_NONINTERLACED, 0 },
5952 - /* 800x600-85 */
5953 - { NULL, 85, 800, 600, 17790, 152, 32, 27, 1, 64, 3,
5954 - 0, FB_VMODE_NONINTERLACED, 0 },
5955 - /* 800x600-90 */
5956 - { NULL, 90, 800, 600, 16648, 128, 40, 28, 1, 88, 3,
5957 - 0, FB_VMODE_NONINTERLACED, 0 },
5958 - /* 800x600-100 */
5959 - { NULL, 100, 800, 600, 14667, 136, 48, 27, 1, 88, 3,
5960 - 0, FB_VMODE_NONINTERLACED, 0 },
5961 - /* 800x600-60 */
5962 - { NULL, 60, 800, 600, 25131, 88, 40, 23, 1, 128, 4,
5963 - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
5964 - FB_VMODE_NONINTERLACED, 0 },
5965 - /* 1024x768-60 */
5966 - { NULL, 60, 1024, 768, 15385, 160, 24, 29, 3, 136, 6,
5967 - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
5968 - FB_VMODE_NONINTERLACED, 0 },
5969 - /* 1024x768-70 */
5970 - { NULL, 70, 1024, 768, 13346, 144, 24, 29, 3, 136, 6,
5971 - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
5972 - FB_VMODE_NONINTERLACED, 0 },
5973 - /* 1024x768-72 */
5974 - { NULL, 72, 1024, 768, 12702, 168, 56, 29, 4, 112, 3,
5975 - 0, FB_VMODE_NONINTERLACED, 0 },
5976 - /* 1024x768-75 */
5977 - { NULL, 75, 1024, 768, 12703, 176, 16, 28, 1, 96, 3,
5978 - 0, FB_VMODE_NONINTERLACED, 0 },
5979 - /* 1024x768-85 */
5980 - { NULL, 85, 1024, 768, 10581, 208, 48, 36, 1, 96, 3,
5981 - 0, FB_VMODE_NONINTERLACED, 0 },
5982 - /* 1024x768-90 */
5983 - { NULL, 90, 1024, 768, 9981, 176, 64, 37, 1, 112, 3,
5984 - 0, FB_VMODE_NONINTERLACED, 0 },
5985 - /* 1024x768-100 */
5986 - { NULL, 100, 1024, 768, 8825, 184, 72, 42, 1, 112, 3,
5987 - 0, FB_VMODE_NONINTERLACED, 0 },
5988 - /* 1024x768-60 */
5989 - { NULL, 60, 1024, 768, 15385, 160, 24, 29, 3, 136, 6,
5990 - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
5991 - FB_VMODE_NONINTERLACED, 0 },
5992 - /* 1152x864-60 */
5993 - { NULL, 60, 1152, 864, 12251, 184, 64, 27, 1, 120, 3,
5994 - 0, FB_VMODE_NONINTERLACED, 0 },
5995 - /* 1152x864-70 */
5996 - { NULL, 70, 1152, 864, 10254, 192, 72, 32, 8, 120, 3,
5997 - 0, FB_VMODE_NONINTERLACED, 0 },
5998 - /* 1152x864-72 */
5999 - { NULL, 72, 1152, 864, 9866, 200, 72, 33, 7, 128, 3,
6000 - 0, FB_VMODE_NONINTERLACED, 0 },
6001 - /* 1152x864-75 */
6002 - { NULL, 75, 1152, 864, 9259, 256, 64, 32, 1, 128, 3,
6003 - 0, FB_VMODE_NONINTERLACED, 0 },
6004 - /* 1152x864-85 */
6005 - { NULL, 85, 1152, 864, 8357, 200, 72, 37, 3, 128, 3,
6006 - 0, FB_VMODE_NONINTERLACED, 0 },
6007 - /* 1152x864-90 */
6008 - { NULL, 90, 1152, 864, 7719, 208, 80, 42, 9, 128, 3,
6009 - 0, FB_VMODE_NONINTERLACED, 0 },
6010 - /* 1152x864-100 */
6011 - { NULL, 100, 1152, 864, 6947, 208, 80, 48, 3, 128, 3,
6012 - 0, FB_VMODE_NONINTERLACED, 0 },
6013 - /* 1152x864-60 */
6014 - { NULL, 60, 1152, 864, 12251, 184, 64, 27, 1, 120, 3,
6015 - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
6016 - FB_VMODE_NONINTERLACED, 0 },
6017 - /* 1280x1024-60 */
6018 - { NULL, 60, 1280, 1024, 9262, 248, 48, 38, 1, 112, 3,
6019 - 0, FB_VMODE_NONINTERLACED, 0 },
6020 - /* 1280x1024-70 */
6021 - { NULL, 70, 1280, 1024, 7719, 224, 88, 38, 6, 136, 3,
6022 - 0, FB_VMODE_NONINTERLACED, 0 },
6023 - /* 1280x1024-72 */
6024 - { NULL, 72, 1280, 1024, 7490, 224, 88, 39, 7, 136, 3,
6025 - 0, FB_VMODE_NONINTERLACED, 0 },
6026 - /* 1280x1024-75 */
6027 - { NULL, 75, 1280, 1024, 7409, 248, 16, 38, 1, 144, 3,
6028 - 0, FB_VMODE_NONINTERLACED, 0 },
6029 - /* 1280x1024-85 */
6030 - { NULL, 85, 1280, 1024, 6351, 224, 64, 44, 1, 160, 3,
6031 - 0, FB_VMODE_NONINTERLACED, 0 },
6032 - /* 1280x1024-90 */
6033 - { NULL, 90, 1280, 1024, 5791, 240, 96, 51, 12, 144, 3,
6034 - 0, FB_VMODE_NONINTERLACED, 0 },
6035 - /* 1280x1024-100 */
6036 - { NULL, 100, 1280, 1024, 5212, 240, 96, 57, 6, 144, 3,
6037 - 0, FB_VMODE_NONINTERLACED, 0 },
6038 - /* 1280x1024-60 */
6039 - { NULL, 60, 1280, 1024, 9262, 248, 48, 38, 1, 112, 3,
6040 - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
6041 - FB_VMODE_NONINTERLACED, 0 },
6042 - /* 1600x1200-60 */
6043 + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
6044 + /* 1600x1200-60 VESA */
6045 { NULL, 60, 1600, 1200, 6172, 304, 64, 46, 1, 192, 3,
6046 - 0, FB_VMODE_NONINTERLACED, 0 },
6047 - /* 1600x1200-70 */
6048 - { NULL, 70, 1600, 1200, 5291, 304, 64, 46, 1, 192, 3,
6049 - 0, FB_VMODE_NONINTERLACED, 0 },
6050 - /* 1600x1200-72 */
6051 - { NULL, 72, 1600, 1200, 5053, 288, 112, 47, 13, 176, 3,
6052 - 0, FB_VMODE_NONINTERLACED, 0 },
6053 - /* 1600x1200-75 */
6054 + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
6055 + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
6056 + /* 1600x1200-75 VESA */
6057 { NULL, 75, 1600, 1200, 4938, 304, 64, 46, 1, 192, 3,
6058 - 0, FB_VMODE_NONINTERLACED, 0 },
6059 - /* 1600x1200-85 */
6060 + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
6061 + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
6062 + /* 1600x1200-85 VESA */
6063 { NULL, 85, 1600, 1200, 4357, 304, 64, 46, 1, 192, 3,
6064 - 0, FB_VMODE_NONINTERLACED, 0 },
6065 - /* 1600x1200-90 */
6066 - { NULL, 90, 1600, 1200, 3981, 304, 128, 60, 1, 176, 3,
6067 - 0, FB_VMODE_NONINTERLACED, 0 },
6068 - /* 1600x1200-100 */
6069 - { NULL, 100, 1600, 1200, 3563, 304, 128, 67, 1, 176, 3,
6070 - 0, FB_VMODE_NONINTERLACED, 0 },
6071 - /* 1600x1200-60 */
6072 - { NULL, 60, 1600, 1200, 6172, 304, 64, 46, 1, 192, 3,
6073 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
6074 - FB_VMODE_NONINTERLACED, 0 },
6075 - /* 1920x1440-60 */
6076 - { NULL, 60, 1920, 1440, 4273, 344, 128, 56, 1, 208, 3,
6077 - 0, FB_VMODE_NONINTERLACED, 0 },
6078 - /* 1920x1440-70 */
6079 - { NULL, 70, 1920, 1440, 3593, 360, 152, 55, 8, 208, 3,
6080 - 0, FB_VMODE_NONINTERLACED, 0 },
6081 - /* 1920x1440-72 */
6082 - { NULL, 72, 1920, 1440, 3472, 360, 152, 68, 4, 208, 3,
6083 - 0, FB_VMODE_NONINTERLACED, 0 },
6084 - /* 1920x1440-75 */
6085 - { NULL, 75, 1920, 1440, 3367, 352, 144, 56, 1, 224, 3,
6086 - 0, FB_VMODE_NONINTERLACED, 0 },
6087 - /* 1920x1440-85 */
6088 - { NULL, 85, 1920, 1440, 2929, 368, 152, 68, 1, 216, 3,
6089 - 0, FB_VMODE_NONINTERLACED, 0 },
6090 + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
6091 + /* 1200x900-75 - CRT timings for the OLPC mode */
6092 + { NULL, 75, 1200, 900, 8049, 104, 240, 29, 54, 136, 3,
6093 + 0, FB_VMODE_NONINTERLACED, 0 }
6094 };
6095
6096 +#ifdef CONFIG_OLPC
6097 +const struct fb_videomode olpc_dcon_modedb[] __initdata = {
6098 + /* The only mode the DCON has is 1200x900 */
6099 + { NULL, 50, 1200, 900, 17460, 24, 8, 4, 5, 8, 3,
6100 + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
6101 + FB_VMODE_NONINTERLACED, 0 }
6102 +};
6103 +#endif
6104 +
6105 static int lxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
6106 {
6107 if (var->xres > 1920 || var->yres > 1440)
6108 @@ -255,8 +154,7 @@ static int lxfb_set_par(struct fb_info *
6109 fb_alloc_cmap(&info->cmap, 1<<info->var.bits_per_pixel, 0);
6110 }
6111
6112 - info->fix.line_length = lx_get_pitch(info->var.xres,
6113 - info->var.bits_per_pixel);
6114 + info->fix.line_length = lx_get_pitch(info->var.xres, info->var.bits_per_pixel);
6115
6116 lx_set_mode(info);
6117 return 0;
6118 @@ -371,24 +269,61 @@ static int __init lxfb_map_video_memory(
6119 writel(info->fix.smem_start & 0xFF000000,
6120 par->dc_regs + DC_PHY_MEM_OFFSET);
6121
6122 - writel(0, par->dc_regs + DC_UNLOCK);
6123 -
6124 dev_info(&dev->dev, "%d KB of video memory at 0x%lx\n",
6125 info->fix.smem_len / 1024, info->fix.smem_start);
6126
6127 return 0;
6128 }
6129
6130 +static int lxfb_set_gamma(struct fb_info *info, void * __user data)
6131 +{
6132 + unsigned int gamma[LXFB_GAMMA_DWORDS];
6133 +
6134 + if (copy_from_user(gamma, data, LXFB_GAMMA_SIZE))
6135 + return -EFAULT;
6136 +
6137 + lx_set_gamma(info, gamma, LXFB_GAMMA_SIZE);
6138 + return 0;
6139 +}
6140 +
6141 +static int lxfb_get_gamma(struct fb_info *info, void * __user data)
6142 +{
6143 + unsigned int gamma[LXFB_GAMMA_DWORDS];
6144 + memset(gamma, 0, sizeof(gamma));
6145 +
6146 + lx_get_gamma(info, gamma, LXFB_GAMMA_DWORDS);
6147 +
6148 + return copy_to_user(data, gamma, LXFB_GAMMA_SIZE) ?
6149 + -EFAULT : 0;
6150 +}
6151 +
6152 +static int lxfb_ioctl( struct fb_info *info, unsigned int cmd,
6153 + unsigned long arg)
6154 +{
6155 + switch(cmd) {
6156 + case FBIOSGAMMA:
6157 + return lxfb_set_gamma(info, (void * __user) arg);
6158 +
6159 + case FBIOGGAMMA:
6160 + return lxfb_get_gamma(info, (void * __user) arg);
6161 + }
6162 +
6163 + return -ENOTTY;
6164 +}
6165 +
6166 static struct fb_ops lxfb_ops = {
6167 .owner = THIS_MODULE,
6168 .fb_check_var = lxfb_check_var,
6169 .fb_set_par = lxfb_set_par,
6170 .fb_setcolreg = lxfb_setcolreg,
6171 .fb_blank = lxfb_blank,
6172 + .fb_ioctl = lxfb_ioctl,
6173 /* No HW acceleration for now. */
6174 .fb_fillrect = cfb_fillrect,
6175 .fb_copyarea = cfb_copyarea,
6176 .fb_imageblit = cfb_imageblit,
6177 + .fb_powerdown = lx_shutdown,
6178 + .fb_powerup = lx_powerup,
6179 };
6180
6181 static struct fb_info * __init lxfb_init_fbinfo(struct device *dev)
6182 @@ -431,6 +366,45 @@ static struct fb_info * __init lxfb_init
6183 return info;
6184 }
6185
6186 +#ifdef CONFIG_PM
6187 +
6188 +static int lxfb_suspend(struct pci_dev *pdev, pm_message_t state)
6189 +{
6190 + struct fb_info *info = pci_get_drvdata(pdev);
6191 +
6192 + if (pdev->dev.power.power_state.event == state.event)
6193 + return 0;
6194 +
6195 + if (state.event == PM_EVENT_SUSPEND) {
6196 +
6197 + acquire_console_sem();
6198 + lx_shutdown(info);
6199 + fb_set_suspend(info, 1);
6200 + release_console_sem();
6201 + }
6202 +
6203 + pdev->dev.power.power_state = state;
6204 + return 0;
6205 +}
6206 +
6207 +static int lxfb_resume(struct pci_dev *pdev)
6208 +{
6209 + struct fb_info *info = pci_get_drvdata(pdev);
6210 +
6211 + acquire_console_sem();
6212 +
6213 + /* Turn the engine completely on */
6214 +
6215 + lx_powerup(info);
6216 + fb_set_suspend(info, 0);
6217 + release_console_sem();
6218 +
6219 + pdev->dev.power.power_state = PMSG_ON;
6220 + return 0;
6221 +}
6222 +
6223 +#endif
6224 +
6225 static int __init lxfb_probe(struct pci_dev *pdev,
6226 const struct pci_device_id *id)
6227 {
6228 @@ -467,6 +441,13 @@ static int __init lxfb_probe(struct pci_
6229 modedb_ptr = (struct fb_videomode *) geode_modedb;
6230 modedb_size = ARRAY_SIZE(geode_modedb);
6231
6232 +#ifdef CONFIG_OLPC
6233 + if (olpc_has_dcon()) {
6234 + modedb_ptr = (struct fb_videomode *) olpc_dcon_modedb;
6235 + modedb_size = ARRAY_SIZE(olpc_dcon_modedb);
6236 + }
6237 +#endif
6238 +
6239 ret = fb_find_mode(&info->var, info, mode_option,
6240 modedb_ptr, modedb_size, NULL, 16);
6241
6242 @@ -556,6 +537,10 @@ static struct pci_driver lxfb_driver = {
6243 .id_table = lxfb_id_table,
6244 .probe = lxfb_probe,
6245 .remove = lxfb_remove,
6246 +#ifdef CONFIG_PM
6247 + .suspend = lxfb_suspend,
6248 + .resume = lxfb_resume
6249 +#endif
6250 };
6251
6252 #ifndef MODULE
6253 diff -purN linux_2.6.24_org/drivers/video/geode/lxfb.h linux_2.6.24_olpc/drivers/video/geode/lxfb.h
6254 --- linux_2.6.24_org/drivers/video/geode/lxfb.h 2008-02-15 20:11:23.000000000 +0000
6255 +++ linux_2.6.24_olpc/drivers/video/geode/lxfb.h 2008-02-15 18:58:41.000000000 +0000
6256 @@ -25,10 +25,23 @@ void lx_set_mode(struct fb_info *);
6257 void lx_get_gamma(struct fb_info *, unsigned int *, int);
6258 void lx_set_gamma(struct fb_info *, unsigned int *, int);
6259 unsigned int lx_framebuffer_size(void);
6260 +int lx_shutdown(struct fb_info *);
6261 +int lx_powerup(struct fb_info *);
6262 int lx_blank_display(struct fb_info *, int);
6263 void lx_set_palette_reg(struct fb_info *, unsigned int, unsigned int,
6264 unsigned int, unsigned int);
6265
6266 +
6267 +
6268 +/* ioctl() defines */
6269 +
6270 +#define FBIOSGAMMA _IOW('F', 0x20, void *)
6271 +#define FBIOGGAMMA _IOW('F', 0x21, void *)
6272 +
6273 +/* General definitions */
6274 +#define LXFB_GAMMA_DWORDS 256 /* number of dwords in the gamma ram */
6275 +#define LXFB_GAMMA_SIZE (LXFB_GAMMA_DWORDS * sizeof(unsigned int))
6276 +
6277 /* MSRS */
6278
6279 #define MSR_LX_GLD_CONFIG 0x48002001
6280 @@ -127,7 +140,7 @@ void lx_set_palette_reg(struct fb_info *
6281
6282 #define DC_GFX_SCALE 0x90
6283 #define DC_IRQ_FILT_CTL 0x94
6284 -
6285 +#define DC_IRQFILT_H_FILT_SEL 0x00000400
6286
6287 #define DC_IRQ 0xC8
6288 #define DC_IRQ_MASK (1 << 0)
6289 diff -purN linux_2.6.24_org/drivers/video/geode/lxfb_ops.c linux_2.6.24_olpc/drivers/video/geode/lxfb_ops.c
6290 --- linux_2.6.24_org/drivers/video/geode/lxfb_ops.c 2008-02-15 20:11:23.000000000 +0000
6291 +++ linux_2.6.24_olpc/drivers/video/geode/lxfb_ops.c 2008-02-15 18:58:41.000000000 +0000
6292 @@ -11,11 +11,15 @@
6293 #include <linux/kernel.h>
6294 #include <linux/errno.h>
6295 #include <linux/fb.h>
6296 -#include <linux/uaccess.h>
6297 -#include <linux/delay.h>
6298 +#include <asm/uaccess.h>
6299 +#include <asm/delay.h>
6300 +#include <asm/olpc.h>
6301
6302 #include "lxfb.h"
6303
6304 +#define _GEODELX_
6305 +#include "geode_regs.h"
6306 +
6307 /* TODO
6308 * Support panel scaling
6309 * Add acceleration
6310 @@ -290,6 +294,19 @@ unsigned int lx_framebuffer_size(void)
6311 {
6312 unsigned int val;
6313
6314 +#ifdef CONFIG_OLPC
6315 + if (machine_is_olpc() && !olpc_has_vsa()) {
6316 + u32 hi,lo;
6317 + rdmsr(MSR_LX_GLIU0_P2D_RO0, lo, hi);
6318 +
6319 + /* Top page number */
6320 + val = ((hi & 0xff) << 12) | ((lo & 0xfff00000) >> 20);
6321 + val -= (lo & 0x000fffff); /* Subtract bottom page number */
6322 + val += 1; /* Adjust page count */
6323 + return (val << 12);
6324 + }
6325 +#endif
6326 +
6327 /* The frame buffer size is reported by a VSM in VSA II */
6328 /* Virtual Register Class = 0x02 */
6329 /* VG_MEM_SIZE (1MB units) = 0x00 */
6330 @@ -301,6 +318,34 @@ unsigned int lx_framebuffer_size(void)
6331 return (val << 20);
6332 }
6333
6334 +void lx_set_gamma(struct fb_info *info, unsigned int *gamma, int len)
6335 +{
6336 + int i;
6337 + struct lxfb_par *par = info->par;
6338 +
6339 + writel(0, par->df_regs + DF_PAR);
6340 +
6341 + /* Sequential writes to the data register will increment the
6342 + address automatically */
6343 +
6344 + for(i = 0; i < len; i++)
6345 + writel(gamma[i] & 0xFFFFFF, par->df_regs + DF_PDR);
6346 +
6347 + writel(readl(par->df_regs + DF_MISC) & ~DF_MISC_GAM_BYPASS,
6348 + par->df_regs + DF_MISC);
6349 +}
6350 +
6351 +void lx_get_gamma(struct fb_info *info, unsigned int *gamma, int len)
6352 +{
6353 + int i;
6354 + struct lxfb_par *par = info->par;
6355 +
6356 + writel(0, par->df_regs + DF_PAR);
6357 +
6358 + for(i = 0; i < len;i++)
6359 + gamma[i] = readl(par->df_regs + DF_PDR);
6360 +}
6361 +
6362 void lx_set_mode(struct fb_info *info)
6363 {
6364 struct lxfb_par *par = info->par;
6365 @@ -313,6 +358,7 @@ void lx_set_mode(struct fb_info *info)
6366 int vactive, vblankstart, vsyncstart, vsyncend, vblankend, vtotal;
6367
6368 /* Unlock the DC registers */
6369 + readl(par->dc_regs + DC_UNLOCK);
6370 writel(DC_UNLOCK_CODE, par->dc_regs + DC_UNLOCK);
6371
6372 lx_graphics_disable(info);
6373 @@ -483,54 +529,408 @@ void lx_set_palette_reg(struct fb_info *
6374 writel(val, par->dc_regs + DC_PAL_DATA);
6375 }
6376
6377 +static int lx_blank_mode = FB_BLANK_UNBLANK;
6378 +
6379 int lx_blank_display(struct fb_info *info, int blank_mode)
6380 {
6381 struct lxfb_par *par = info->par;
6382 - u32 dcfg, fp_pm;
6383 - int blank, hsync, vsync;
6384 + u32 dcfg, val;
6385 +
6386 + if (blank_mode == lx_blank_mode)
6387 + return 0;
6388 +
6389 + writel(DC_UNLOCK_CODE, par->dc_regs + DC_UNLOCK);
6390 +
6391 + if (lx_blank_mode == FB_BLANK_POWERDOWN) {
6392 + val = readl(par->df_regs + DF_FP_PM);
6393 + writel(val | DF_FP_PM_P, par->df_regs + DF_FP_PM);
6394 + val = readl(par->df_regs + DF_MISC) & ~DF_MISC_DAC_PWRDN;
6395 + writel(val, par->df_regs + DF_MISC);
6396 +
6397 + val = readl(par->dc_regs + DC_GENERAL_CFG) | DC_GCFG_DFLE;
6398 + writel(val, par->dc_regs + DC_GENERAL_CFG);
6399 +
6400 + val = readl(par->dc_regs + DC_DISPLAY_CFG) | DC_DCFG_TGEN;
6401 + writel(val, par->dc_regs + DC_DISPLAY_CFG);
6402 + }
6403 +
6404 + dcfg = readl(par->df_regs + DF_DISPLAY_CFG);
6405
6406 /* CRT power saving modes. */
6407 switch (blank_mode) {
6408 case FB_BLANK_UNBLANK:
6409 - blank = 0; hsync = 1; vsync = 1;
6410 + dcfg |= DF_DCFG_CRT_EN | DF_DCFG_HSYNC_EN | DF_DCFG_VSYNC_EN;
6411 + dcfg |= DF_DCFG_DAC_BL_EN;
6412 break;
6413 case FB_BLANK_NORMAL:
6414 - blank = 1; hsync = 1; vsync = 1;
6415 + dcfg |= DF_DCFG_CRT_EN | DF_DCFG_HSYNC_EN | DF_DCFG_VSYNC_EN;
6416 + dcfg |= DF_DCFG_DAC_BL_EN;
6417 break;
6418 case FB_BLANK_VSYNC_SUSPEND:
6419 - blank = 1; hsync = 1; vsync = 0;
6420 + dcfg |= DF_DCFG_CRT_EN | DF_DCFG_HSYNC_EN | DF_DCFG_DAC_BL_EN;
6421 + dcfg &= ~DF_DCFG_VSYNC_EN;
6422 break;
6423 case FB_BLANK_HSYNC_SUSPEND:
6424 - blank = 1; hsync = 0; vsync = 1;
6425 + dcfg |= DF_DCFG_CRT_EN | DF_DCFG_VSYNC_EN | DF_DCFG_DAC_BL_EN;
6426 + dcfg &= ~DF_DCFG_HSYNC_EN;
6427 break;
6428 case FB_BLANK_POWERDOWN:
6429 - blank = 1; hsync = 0; vsync = 0;
6430 + dcfg &= ~DF_DCFG_DAC_BL_EN;
6431 + dcfg &= ~(DF_DCFG_CRT_EN | DF_DCFG_HSYNC_EN | DF_DCFG_VSYNC_EN);
6432 break;
6433 default:
6434 + writel(0, par->dc_regs + DC_UNLOCK);
6435 return -EINVAL;
6436 }
6437
6438 - dcfg = readl(par->df_regs + DF_DISPLAY_CFG);
6439 - dcfg &= ~(DF_DCFG_DAC_BL_EN
6440 - | DF_DCFG_HSYNC_EN | DF_DCFG_VSYNC_EN);
6441 - if (!blank)
6442 - dcfg |= DF_DCFG_DAC_BL_EN;
6443 - if (hsync)
6444 - dcfg |= DF_DCFG_HSYNC_EN;
6445 - if (vsync)
6446 - dcfg |= DF_DCFG_VSYNC_EN;
6447 - writel(dcfg, par->df_regs + DF_DISPLAY_CFG);
6448 + /* Turn off the engine when we are in power down mode */
6449 + if (blank_mode == FB_BLANK_POWERDOWN) {
6450 + val = readl(par->df_regs + DF_MISC) | DF_MISC_DAC_PWRDN;
6451 + writel(val, par->df_regs + DF_MISC);
6452 +
6453 + val = readl(par->dc_regs + DC_DISPLAY_CFG);
6454 + val &= ~DC_DCFG_TGEN;
6455 + writel(val, par->dc_regs + DC_DISPLAY_CFG);
6456 +
6457 + udelay(1000);
6458 +
6459 + val = readl(par->dc_regs + DC_GENERAL_CFG) & ~DC_GCFG_DFLE;
6460 + writel(val, par->dc_regs + DC_GENERAL_CFG);
6461 +
6462 + val = readl(par->df_regs + DF_FP_PM);
6463 + writel(val & ~DF_FP_PM_P, par->df_regs + DF_FP_PM);
6464 + }
6465
6466 + writel(0, par->dc_regs + DC_UNLOCK);
6467 +
6468 + lx_blank_mode = blank_mode;
6469 + return 0;
6470 +}
6471 +
6472 +static struct geoderegs saved_regs;
6473 +
6474 +static void lx_save_regs(struct fb_info *info, struct geoderegs *regs)
6475 +{
6476 + struct lxfb_par *par = info->par;
6477 + int i;
6478 + u32 filt;
6479 +
6480 + /* Wait for the command buffer to empty */
6481 + while(!(readl(par->gp_regs + 0x44) & (1 << 4)));
6482 +
6483 + /* Unlock the DC */
6484 + writel(DC_UNLOCK_CODE, par->dc_regs + DC_UNLOCK);
6485 +
6486 + rdmsrl(MSR_LX_DF_PADSEL, regs->msr.padsel);
6487 + rdmsrl(MSR_LX_GLCP_DOTPLL, regs->msr.dotpll);
6488 + rdmsrl(MSR_LX_DF_GLCONFIG, regs->msr.dfglcfg);
6489 + rdmsrl(MSR_LX_DC_SPARE, regs->msr.dcspare);
6490 +
6491 + writel(0x4758, par->dc_regs + 0x00);
6492 +
6493 + memcpy(regs->gp.b, par->gp_regs, GP_REG_SIZE);
6494 + memcpy(regs->dc.b, par->dc_regs, DC_REG_SIZE);
6495 + memcpy(regs->vp.b, par->df_regs, VP_REG_SIZE);
6496 + memcpy(regs->fp.b, par->df_regs + VP_FP_START, FP_REG_SIZE);
6497 +
6498 + /* Save the palette */
6499 + writel(0, par->dc_regs + 0x70);
6500 /* Power on/off flat panel */
6501 + for(i = 0; i < DC_PAL_SIZE; i++)
6502 + regs->pal[i] = readl(par->dc_regs + 0x74);
6503
6504 - if (par->output & OUTPUT_PANEL) {
6505 - fp_pm = readl(par->df_regs + DF_FP_PM);
6506 - if (blank_mode == FB_BLANK_POWERDOWN)
6507 - fp_pm &= ~DF_FP_PM_P;
6508 - else
6509 - fp_pm |= DF_FP_PM_P;
6510 - writel(fp_pm, par->df_regs + DF_FP_PM);
6511 + /* save the filter coefficients */
6512 +
6513 + filt = readl(par->dc_regs + 0x94);
6514 + filt |= DC_IRQFILT_H_FILT_SEL;
6515 +
6516 + for(i = 0; i < DC_HFILT_SIZE; i++) {
6517 + writel((filt & 0xFFFFFF00) | i, par->dc_regs + 0x94);
6518 + regs->hcoeff[i << 1] = readl(par->dc_regs + 0x98);
6519 + regs->hcoeff[(i << 1) + 1] = readl(par->dc_regs + 0x9c);
6520 + }
6521 +
6522 + filt &= ~DC_IRQFILT_H_FILT_SEL;
6523 +
6524 + for(i = 0; i < DC_VFILT_SIZE; i++) {
6525 + writel((filt & 0xFFFFFF00) | i, par->dc_regs + 0x94);
6526 + regs->vcoeff[i] = readl(par->dc_regs + 0x98);
6527 }
6528
6529 + /* Save the vg filter coefficients */
6530 + for(i = 0; i < VP_COEFF_COUNT; i++)
6531 + regs->vp_coeff[i] =
6532 + readl(par->df_regs + 0x1000 + (i << 2));
6533 +
6534 + /* Save the VP gamma */
6535 +
6536 + writel(0, par->df_regs + 0x38);
6537 +
6538 + for(i = 0; i <= 0xFF; i++)
6539 + regs->gamma[i] = readl(par->df_regs + 0x40);
6540 +}
6541 +
6542 +static void lx_restore_dc(struct lxfb_par *par, struct geoderegs *regs)
6543 +{
6544 + u32 filt;
6545 + int i;
6546 +
6547 + /* Unlock the registers */
6548 + writel(DC_UNLOCK_CODE, par->dc_regs + 0x00);
6549 +
6550 + /* Restore the framebuffer offset */
6551 + writel(regs->dc.r.gliu0_mem_offset, par->dc_regs + 0x84);
6552 +
6553 + /* Blank the configuration registers while we restore */
6554 + writel(0, par->dc_regs + 0x04);
6555 + writel(0, par->dc_regs + 0x08);
6556 +
6557 + /* Restore the bulk of the registers */
6558 +
6559 + writel(regs->dc.r.arb, par->dc_regs + 0x0C);
6560 + writel(regs->dc.r.fb_st_offset, par->dc_regs + 0x10);
6561 + writel(regs->dc.r.cb_st_offset, par->dc_regs + 0x14);
6562 + writel(regs->dc.r.curs_st_offset, par->dc_regs + 0x18);
6563 +
6564 + /* skip 0x1c */
6565 +
6566 + writel(regs->dc.r.vid_y_st_offset, par->dc_regs + 0x20);
6567 + writel(regs->dc.r.vid_u_st_offset, par->dc_regs + 0x24);
6568 + writel(regs->dc.r.vid_v_st_offset, par->dc_regs + 0x28);
6569 +
6570 + writel(regs->dc.r.dctop, par->dc_regs + 0x2c);
6571 + writel(regs->dc.r.line_size, par->dc_regs + 0x30);
6572 + writel(regs->dc.r.gfx_pitch, par->dc_regs + 0x34);
6573 + writel(regs->dc.r.vid_yuv_pitch, par->dc_regs + 0x38);
6574 + writel(regs->dc.r.h_active_timing, par->dc_regs + 0x40);
6575 + writel(regs->dc.r.h_blank_timing, par->dc_regs + 0x44);
6576 + writel(regs->dc.r.h_sync_timing, par->dc_regs + 0x48);
6577 + writel(regs->dc.r.v_active_timing, par->dc_regs + 0x50);
6578 + writel(regs->dc.r.v_blank_timing, par->dc_regs + 0x54);
6579 + writel(regs->dc.r.v_sync_timing, par->dc_regs + 0x58);
6580 + writel(regs->dc.r.fbactive, par->dc_regs + 0x5c);
6581 + writel(regs->dc.r.dc_cursor_x, par->dc_regs + 0x60);
6582 + writel(regs->dc.r.dc_cursor_y, par->dc_regs + 0x64);
6583 +
6584 + /* skip 0x68, 0x6c, 0x70, 0x74, 0x78, 0x7c */
6585 +
6586 + writel(regs->dc.r.dc_vid_ds_delta, par->dc_regs + 0x80);
6587 +
6588 + /* 0x84 was written above */
6589 +
6590 + writel(regs->dc.r.dv_ctl | 0x01, par->dc_regs + 0x88);
6591 + writel(regs->dc.r.gfx_scale, par->dc_regs + 0x90);
6592 + writel(regs->dc.r.irq_filt_ctl, par->dc_regs + 0x94);
6593 +
6594 + /* skip 0x98, 0x9c */
6595 +
6596 + writel(regs->dc.r.vbi_event_ctl, par->dc_regs + 0xA0);
6597 + writel(regs->dc.r.vbi_odd_ctl, par->dc_regs + 0xA4);
6598 + writel(regs->dc.r.vbi_hor, par->dc_regs + 0xA8);
6599 + writel(regs->dc.r.vbi_ln_odd, par->dc_regs + 0xAC);
6600 + writel(regs->dc.r.vbi_ln_event, par->dc_regs + 0xB0);
6601 + writel(regs->dc.r.vbi_pitch, par->dc_regs + 0xB4);
6602 + writel(regs->dc.r.clr_key, par->dc_regs + 0xB8);
6603 + writel(regs->dc.r.clr_key_mask, par->dc_regs + 0xBC);
6604 + writel(regs->dc.r.clr_key_x, par->dc_regs + 0xC0);
6605 + writel(regs->dc.r.clr_key_y, par->dc_regs + 0xC4);
6606 + writel(regs->dc.r.irq, par->dc_regs + 0xC8);
6607 + writel(regs->dc.r.genlk_ctrl, par->dc_regs + 0xD4);
6608 + writel(regs->dc.r.vid_even_y_st_offset, par->dc_regs + 0xD8);
6609 + writel(regs->dc.r.vid_even_u_st_offset, par->dc_regs + 0xDC);
6610 + writel(regs->dc.r.vid_even_v_st_offset, par->dc_regs + 0xE0);
6611 + writel(regs->dc.r.v_active_even_timing, par->dc_regs + 0xE4);
6612 + writel(regs->dc.r.v_blank_even_timing, par->dc_regs + 0xE8);
6613 + writel(regs->dc.r.v_sync_even_timing, par->dc_regs + 0xEC);
6614 +
6615 + /* Restore the palette */
6616 + writel(0, par->dc_regs + 0x70);
6617 +
6618 + for(i = 0; i < DC_PAL_SIZE; i++)
6619 + writel(regs->pal[i], par->dc_regs + 0x74);
6620 +
6621 + /* Restore the horizontal filter coefficients */
6622 + filt = readl(par->dc_regs + 0x94);
6623 + filt |= DC_IRQFILT_H_FILT_SEL;
6624 +
6625 + for(i = 0; i < DC_HFILT_SIZE; i++) {
6626 + writel(((filt & 0xFFFFFF00) | i), par->dc_regs + 0x94);
6627 + writel(regs->hcoeff[i << 1], par->dc_regs + 0x98);
6628 + writel(regs->hcoeff[(i << 1) + 1], par->dc_regs + 0x9c);
6629 + }
6630 +
6631 + filt &= ~DC_IRQFILT_H_FILT_SEL;
6632 +
6633 + for(i = 0; i < DC_VFILT_SIZE; i++) {
6634 + writel(((filt & 0xFFFFFF00) | i), par->dc_regs + 0x94);
6635 + writel(regs->vcoeff[i], par->dc_regs + 0x98);
6636 + }
6637 +
6638 + /* Turn on the dotpll */
6639 + lx_set_dotpll((u32) (regs->msr.dotpll >> 32));
6640 +
6641 + /* Restore MSRs */
6642 + wrmsrl(MSR_LX_DC_SPARE, regs->msr.dcspare);
6643 +
6644 + /* Restore the configuration registers */
6645 +
6646 + writel(regs->dc.r.dcfg, par->dc_regs + 0x08);
6647 + writel(regs->dc.r.gcfg, par->dc_regs + 0x04);
6648 +
6649 + /* Lock the DC again */
6650 + writel(0, par->dc_regs + 0x00);
6651 +}
6652 +
6653 +static void lx_restore_vp(struct lxfb_par *par, struct geoderegs *regs)
6654 +{
6655 + u32 val;
6656 + int i;
6657 +
6658 + /* Restore MSRs */
6659 +
6660 + wrmsrl(MSR_LX_DF_GLCONFIG, regs->msr.dfglcfg);
6661 + wrmsrl(MSR_LX_DF_PADSEL, regs->msr.padsel);
6662 +
6663 + /* Restore the registers */
6664 +
6665 + writel((u32) regs->vp.r.vx, par->df_regs + 0x10);
6666 + writel((u32) regs->vp.r.vy, par->df_regs + 0x18);
6667 + writel((u32) regs->vp.r.vs, par->df_regs + 0x20);
6668 + writel((u32) regs->vp.r.vck, par->df_regs + 0x28);
6669 + writel((u32) regs->vp.r.vcm, par->df_regs + 0x30);
6670 + /* skip 0x38 and 0x40 */
6671 + writel((u32) regs->vp.r.slr, par->df_regs + 0x48);
6672 + writel((u32) regs->vp.r.misc, par->df_regs + 0x50);
6673 + /* skip 0x58 */
6674 + writel((u32) regs->vp.r.vys, par->df_regs + 0x60);
6675 + writel((u32) regs->vp.r.vxs, par->df_regs + 0x68);
6676 + writel((u32) regs->vp.r.vde, par->df_regs + 0x98);
6677 + writel((u32) regs->vp.r.cck, par->df_regs + 0xA0);
6678 + writel((u32) regs->vp.r.ccm, par->df_regs + 0xA8);
6679 + writel((u32) regs->vp.r.cc1, par->df_regs + 0xB0);
6680 + writel((u32) regs->vp.r.cc2, par->df_regs + 0xB8);
6681 + writel((u32) regs->vp.r.a1x, par->df_regs + 0xC0);
6682 + writel((u32) regs->vp.r.a1y, par->df_regs + 0xC8);
6683 + writel((u32) regs->vp.r.a1c, par->df_regs + 0xD0);
6684 + writel((u32) regs->vp.r.a1t, par->df_regs + 0xD8);
6685 + writel((u32) regs->vp.r.a2x, par->df_regs + 0xE0);
6686 + writel((u32) regs->vp.r.a2y, par->df_regs + 0xE8);
6687 + writel((u32) regs->vp.r.a2c, par->df_regs + 0xF0);
6688 + writel((u32) regs->vp.r.a2t, par->df_regs + 0xF8);
6689 + writel((u32) regs->vp.r.a3x, par->df_regs + 0x100);
6690 + writel((u32) regs->vp.r.a3y, par->df_regs + 0x108);
6691 + writel((u32) regs->vp.r.a3c, par->df_regs + 0x110);
6692 + writel((u32) regs->vp.r.a3t, par->df_regs + 0x118);
6693 + writel((u32) regs->vp.r.vrr, par->df_regs + 0x120);
6694 + writel((u32) regs->vp.r.vye, par->df_regs + 0x138);
6695 + writel((u32) regs->vp.r.a1ye, par->df_regs + 0x140);
6696 + writel((u32) regs->vp.r.a2ye, par->df_regs + 0x148);
6697 + writel((u32) regs->vp.r.a3ye, par->df_regs + 0x150);
6698 +
6699 + /* Panel */
6700 +
6701 + writel((u32) regs->fp.r.pt1, par->df_regs + 0x400);
6702 + writel((u32) regs->fp.r.pt2, par->df_regs + 0x408);
6703 + writel((u32) regs->fp.r.dfc, par->df_regs + 0x418);
6704 +
6705 + /* Restore panel power */
6706 +
6707 + val = readl(par->df_regs + 0x410);
6708 +
6709 + if (regs->fp.r.pm & (1 << 24)) {
6710 + if (!(val & 0x09))
6711 + writel(regs->fp.r.pm, par->df_regs + 0x410);
6712 + }
6713 + else {
6714 + if (!(val & 0x05))
6715 + writel(regs->fp.r.pm, par->df_regs + 0x410);
6716 + }
6717 +
6718 + /* Restore the vp palette */
6719 +
6720 + writel(0, par->df_regs + 0x38);
6721 +
6722 + for(i = 0; i <= 0xFF; i++)
6723 + writel((u32) regs->gamma[i], par->df_regs + 0x40);
6724 +
6725 + /* Restore filter coefficients */
6726 +
6727 + for(i = 0; i < VP_COEFF_COUNT; i++)
6728 + writel(regs->vp_coeff[i],
6729 + par->df_regs + 0x1000 + (i << 2));
6730 +
6731 + /* Restore the configuration registers */
6732 +
6733 + writel((u32) regs->vp.r.dcfg, par->df_regs + 0x08);
6734 + writel((u32) regs->vp.r.vcfg, par->df_regs + 0x00);
6735 +}
6736 +
6737 +static void lx_restore_gp(struct lxfb_par *par, struct geoderegs *regs)
6738 +{
6739 + writel(regs->gp.r.dst_offset, par->gp_regs + 0x00);
6740 + writel(regs->gp.r.src_offset, par->gp_regs + 0x04);
6741 + writel(regs->gp.r.stride, par->gp_regs + 0x08);
6742 + writel(regs->gp.r.wid_height, par->gp_regs + 0x0C);
6743 + writel(regs->gp.r.src_color_fg, par->gp_regs + 0x10);
6744 + writel(regs->gp.r.src_color_bg, par->gp_regs + 0x14);
6745 + writel(regs->gp.r.pat_color_0, par->gp_regs + 0x18);
6746 + writel(regs->gp.r.pat_color_1, par->gp_regs + 0x1C);
6747 + writel(regs->gp.r.pat_color_2, par->gp_regs + 0x20);
6748 + writel(regs->gp.r.pat_color_3, par->gp_regs + 0x24);
6749 + writel(regs->gp.r.pat_color_4, par->gp_regs + 0x28);
6750 + writel(regs->gp.r.pat_color_5, par->gp_regs + 0x2C);
6751 + writel(regs->gp.r.pat_data_0, par->gp_regs + 0x30);
6752 + writel(regs->gp.r.pat_data_1, par->gp_regs + 0x34);
6753 +
6754 + /* Writing to these registers would cause a blt to happen */
6755 + /* 0x38, 0x3c, 0x40 */
6756 +
6757 + /* Status register (0x44) is read only */
6758 +
6759 + writel(regs->gp.r.hst_src, par->gp_regs + 0x48);
6760 + writel(regs->gp.r.base_offset, par->gp_regs + 0x4c);
6761 + writel(regs->gp.r.cmd_top, par->gp_regs + 0x50);
6762 + writel(regs->gp.r.cmd_bot, par->gp_regs + 0x54);
6763 + writel(regs->gp.r.cmd_read, par->gp_regs + 0x58);
6764 + writel(regs->gp.r.cmd_write, par->gp_regs + 0x5C);
6765 + writel(regs->gp.r.ch3_offset, par->gp_regs + 0x60);
6766 + writel(regs->gp.r.ch3_mode_str, par->gp_regs + 0x64);
6767 + writel(regs->gp.r.ch3_width, par->gp_regs + 0x6C);
6768 + writel(regs->gp.r.ch3_hsrc, par->gp_regs + 0x70);
6769 +
6770 + writel(regs->gp.r.int_cntrl, par->gp_regs + 0x70);
6771 +}
6772 +
6773 +static void lx_restore_regs(struct fb_info *info, struct geoderegs *regs)
6774 +{
6775 + struct lxfb_par *par = info->par;
6776 +
6777 + lx_restore_gp(par, regs);
6778 + lx_restore_vp(par, regs);
6779 + lx_restore_dc(par, regs);
6780 +}
6781 +
6782 +static int lx_power_on = 1;
6783 +
6784 +int lx_shutdown(struct fb_info *info)
6785 +{
6786 + if (lx_power_on == 0)
6787 + return 0;
6788 +
6789 + lx_save_regs(info, &saved_regs);
6790 + lx_graphics_disable(info);
6791 +
6792 + lx_power_on = 0;
6793 + return 0;
6794 +}
6795 +
6796 +int lx_powerup(struct fb_info *info)
6797 +{
6798 + if (lx_power_on == 1)
6799 + return 0;
6800 +
6801 + lx_restore_regs(info, &saved_regs);
6802 +
6803 + lx_power_on = 1;
6804 return 0;
6805 }
6806 diff -purN linux_2.6.24_org/drivers/video/geode/Makefile linux_2.6.24_olpc/drivers/video/geode/Makefile
6807 --- linux_2.6.24_org/drivers/video/geode/Makefile 2008-02-15 20:11:23.000000000 +0000
6808 +++ linux_2.6.24_olpc/drivers/video/geode/Makefile 2008-02-15 18:58:41.000000000 +0000
6809 @@ -5,5 +5,5 @@ obj-$(CONFIG_FB_GEODE_GX) += gxfb.o
6810 obj-$(CONFIG_FB_GEODE_LX) += lxfb.o
6811
6812 gx1fb-objs := gx1fb_core.o display_gx1.o video_cs5530.o
6813 -gxfb-objs := gxfb_core.o display_gx.o video_gx.o
6814 +gxfb-objs := gxfb_core.o display_gx.o video_gx.o suspend_gx.o
6815 lxfb-objs := lxfb_core.o lxfb_ops.o
6816 diff -purN linux_2.6.24_org/drivers/video/geode/suspend_gx.c linux_2.6.24_olpc/drivers/video/geode/suspend_gx.c
6817 --- linux_2.6.24_org/drivers/video/geode/suspend_gx.c 1970-01-01 01:00:00.000000000 +0100
6818 +++ linux_2.6.24_olpc/drivers/video/geode/suspend_gx.c 2008-02-15 18:58:41.000000000 +0000
6819 @@ -0,0 +1,272 @@
6820 +#include <linux/fb.h>
6821 +#include <asm/io.h>
6822 +#include <asm/msr.h>
6823 +
6824 +#include "geodefb.h"
6825 +#include "video_gx.h"
6826 +
6827 +void gx_set_dotpll(struct fb_info *info, struct geoderegs *regs)
6828 +{
6829 + int timeout = 1000;
6830 +
6831 + u64 rstpll, dotpll;
6832 +
6833 + rdmsrl(MSR_GLCP_SYS_RSTPLL, rstpll);
6834 + rdmsrl(MSR_GLCP_DOTPLL, dotpll);
6835 +
6836 + dotpll &= 0x00000000ffffffffull;
6837 + dotpll |= regs->msr.dotpll & 0xffffffff00000000ull;
6838 +
6839 + dotpll |= MSR_GLCP_DOTPLL_DOTRESET;
6840 + dotpll &= ~MSR_GLCP_DOTPLL_BYPASS;
6841 +
6842 + wrmsrl(MSR_GLCP_DOTPLL, dotpll);
6843 +
6844 + rstpll |= (regs->msr.rstpll &
6845 + ( MSR_GLCP_SYS_RSTPLL_DOTPREDIV2 |
6846 + MSR_GLCP_SYS_RSTPLL_DOTPREMULT2 |
6847 + MSR_GLCP_SYS_RSTPLL_DOTPOSTDIV3));
6848 +
6849 + wrmsrl(MSR_GLCP_SYS_RSTPLL, rstpll);
6850 + dotpll &= ~(MSR_GLCP_DOTPLL_DOTRESET);
6851 + wrmsrl(MSR_GLCP_DOTPLL, dotpll);
6852 +
6853 + do {
6854 + rdmsrl(MSR_GLCP_DOTPLL, dotpll);
6855 + } while (timeout-- && !(dotpll & MSR_GLCP_DOTPLL_LOCK));
6856 +}
6857 +
6858 +/* FIXME: Make sure nothing is read to clear */
6859 +
6860 +void gx_save_regs(struct fb_info *info, struct geoderegs *regs)
6861 +{
6862 + struct geodefb_par *par = info->par;
6863 + int i;
6864 +
6865 + /* Wait for the BLT engine to stop being busy */
6866 + while(readl(par->gp_regs + 0x44) & 0x05);
6867 +
6868 + rdmsrl(GX_VP_MSR_PAD_SELECT, regs->msr.padsel);
6869 + rdmsrl(MSR_GLCP_DOTPLL, regs->msr.dotpll);
6870 + rdmsrl(MSR_GLCP_SYS_RSTPLL, regs->msr.rstpll);
6871 +
6872 + writel(0x4758, par->dc_regs + 0x00);
6873 +
6874 + memcpy(regs->gp.b, par->gp_regs, GP_REG_SIZE);
6875 + memcpy(regs->dc.b, par->dc_regs, DC_REG_SIZE);
6876 + memcpy(regs->vp.b, par->vid_regs, VP_REG_SIZE);
6877 + memcpy(regs->fp.b, par->vid_regs + 0x400, FP_REG_SIZE);
6878 +
6879 + /* Save the palettes */
6880 + writel(0, par->dc_regs + 0x70);
6881 +
6882 + for(i = 0; i < DC_PAL_SIZE; i++)
6883 + regs->pal[i] = readl(par->dc_regs + 0x74);
6884 +
6885 + writel(0, par->vid_regs + 0x38);
6886 +
6887 + for(i = 0; i < 0xFF; i++)
6888 + regs->gamma[i] = readl(par->vid_regs + 0x40);
6889 +}
6890 +
6891 +void gx_restore_regs(struct fb_info *info, struct geoderegs *regs)
6892 +{
6893 + struct geodefb_par *par = info->par;
6894 + u32 val, i;
6895 +
6896 + /* DOTPLL */
6897 + gx_set_dotpll(info, regs);
6898 +
6899 + /* GP */
6900 +
6901 + writel(regs->gp.r.dst_offset, par->gp_regs + 0x00);
6902 + writel(regs->gp.r.src_offset, par->gp_regs + 0x04);
6903 + writel(regs->gp.r.stride, par->gp_regs + 0x08);
6904 + writel(regs->gp.r.wid_height, par->gp_regs + 0x0C);
6905 + writel(regs->gp.r.src_color_fg, par->gp_regs + 0x10);
6906 + writel(regs->gp.r.src_color_bg, par->gp_regs + 0x14);
6907 + writel(regs->gp.r.pat_color_0, par->gp_regs + 0x18);
6908 + writel(regs->gp.r.pat_color_1, par->gp_regs + 0x1C);
6909 + writel(regs->gp.r.pat_color_2, par->gp_regs + 0x20);
6910 + writel(regs->gp.r.pat_color_3, par->gp_regs + 0x24);
6911 + writel(regs->gp.r.pat_color_4, par->gp_regs + 0x28);
6912 + writel(regs->gp.r.pat_color_5, par->gp_regs + 0x2C);
6913 + writel(regs->gp.r.pat_data_0, par->gp_regs + 0x30);
6914 + writel(regs->gp.r.pat_data_1, par->gp_regs + 0x34);
6915 +
6916 + /* Don't write the raster / vector / blt mode regs */
6917 + /* status register is read only */
6918 +
6919 + writel(regs->gp.r.hst_src, par->gp_regs + 0x48);
6920 + writel(regs->gp.r.base_offset, par->gp_regs + 0x4c);
6921 +
6922 + /* DC */
6923 +
6924 + /* Write the unlock value */
6925 + writel(0x4758, par->dc_regs + 0x00);
6926 +
6927 + writel(0, par->dc_regs + 0x70);
6928 +
6929 + for(i = 0; i < DC_PAL_SIZE; i++)
6930 + writel(regs->pal[i], par->dc_regs + 0x74);
6931 +
6932 + /* Write the gcfg register without the enables */
6933 + writel(regs->dc.r.gcfg & ~0x0F, par->dc_regs + 0x04);
6934 +
6935 + /* Write the vcfg register without the enables */
6936 + writel(regs->dc.r.dcfg & ~0x19, par->dc_regs + 0x08);
6937 +
6938 + /* Write the rest of the active registers */
6939 +
6940 + writel(regs->dc.r.fb_st_offset, par->dc_regs + 0x10);
6941 + writel(regs->dc.r.cb_st_offset, par->dc_regs + 0x14);
6942 + writel(regs->dc.r.curs_st_offset, par->dc_regs + 0x18);
6943 + writel(regs->dc.r.icon_st_offset, par->dc_regs + 0x1C);
6944 + writel(regs->dc.r.vid_y_st_offset, par->dc_regs + 0x20);
6945 + writel(regs->dc.r.vid_u_st_offset, par->dc_regs + 0x24);
6946 + writel(regs->dc.r.vid_v_st_offset, par->dc_regs + 0x28);
6947 + writel(regs->dc.r.line_size, par->dc_regs + 0x30);
6948 + writel(regs->dc.r.gfx_pitch, par->dc_regs + 0x34);
6949 + writel(regs->dc.r.vid_yuv_pitch, par->dc_regs + 0x38);
6950 + writel(regs->dc.r.h_active_timing, par->dc_regs + 0x40);
6951 + writel(regs->dc.r.h_blank_timing, par->dc_regs + 0x44);
6952 + writel(regs->dc.r.h_sync_timing, par->dc_regs + 0x48);
6953 + writel(regs->dc.r.v_active_timing, par->dc_regs + 0x50);
6954 + writel(regs->dc.r.v_blank_timing, par->dc_regs + 0x54);
6955 + writel(regs->dc.r.v_sync_timing, par->dc_regs + 0x58);
6956 + writel(regs->dc.r.dc_cursor_x, par->dc_regs + 0x60);
6957 + writel(regs->dc.r.dc_cursor_y, par->dc_regs + 0x64);
6958 + writel(regs->dc.r.dc_icon_x, par->dc_regs + 0x68);
6959 +
6960 + /* Don't write the line_cnt or diag registers */
6961 +
6962 + writel(regs->dc.r.dc_vid_ds_delta, par->dc_regs + 0x80);
6963 + writel(regs->dc.r.gliu0_mem_offset, par->dc_regs + 0x84);
6964 + writel(regs->dc.r.dv_acc, par->dc_regs + 0x8C);
6965 +
6966 + /* VP */
6967 +
6968 + /* MSR */
6969 + wrmsrl(GX_VP_MSR_PAD_SELECT, regs->msr.padsel);
6970 +
6971 + writel(0, par->vid_regs + 0x38);
6972 +
6973 + for(i = 0; i < 0xFF; i++)
6974 + writel((u32) regs->gamma[i], par->vid_regs + 0x40);
6975 +
6976 + /* Don't enable video yet */
6977 + writel((u32) regs->vp.r.vcfg & ~0x01, par->vid_regs + 0x00);
6978 +
6979 + /* Don't enable the CRT yet */
6980 + writel((u32) regs->vp.r.dcfg & ~0x0F, par->vid_regs + 0x08);
6981 +
6982 + /* Write the rest of the VP registers */
6983 +
6984 + writel((u32) regs->vp.r.vx, par->vid_regs + 0x10);
6985 + writel((u32) regs->vp.r.vy, par->vid_regs + 0x18);
6986 + writel((u32) regs->vp.r.vs, par->vid_regs + 0x20);
6987 + writel((u32) regs->vp.r.vck, par->vid_regs + 0x28);
6988 + writel((u32) regs->vp.r.vcm, par->vid_regs + 0x30);
6989 + writel((u32) regs->vp.r.misc, par->vid_regs + 0x50);
6990 + writel((u32) regs->vp.r.ccs, par->vid_regs + 0x58);
6991 + writel((u32) regs->vp.r.vdc, par->vid_regs + 0x78);
6992 + writel((u32) regs->vp.r.vco, par->vid_regs + 0x80);
6993 + writel((u32) regs->vp.r.crc, par->vid_regs + 0x88);
6994 + writel((u32) regs->vp.r.vde, par->vid_regs + 0x98);
6995 + writel((u32) regs->vp.r.cck, par->vid_regs + 0xA0);
6996 + writel((u32) regs->vp.r.ccm, par->vid_regs + 0xA8);
6997 + writel((u32) regs->vp.r.cc1, par->vid_regs + 0xB0);
6998 + writel((u32) regs->vp.r.cc2, par->vid_regs + 0xB8);
6999 + writel((u32) regs->vp.r.a1x, par->vid_regs + 0xC0);
7000 + writel((u32) regs->vp.r.a1y, par->vid_regs + 0xC8);
7001 + writel((u32) regs->vp.r.a1c, par->vid_regs + 0xD0);
7002 + writel((u32) regs->vp.r.a1t, par->vid_regs + 0xD8);
7003 + writel((u32) regs->vp.r.a2x, par->vid_regs + 0xE0);
7004 + writel((u32) regs->vp.r.a2y, par->vid_regs + 0xE8);
7005 + writel((u32) regs->vp.r.a2c, par->vid_regs + 0xF0);
7006 + writel((u32) regs->vp.r.a2t, par->vid_regs + 0xF8);
7007 + writel((u32) regs->vp.r.a3x, par->vid_regs + 0x100);
7008 + writel((u32) regs->vp.r.a3y, par->vid_regs + 0x108);
7009 + writel((u32) regs->vp.r.a3c, par->vid_regs + 0x110);
7010 + writel((u32) regs->vp.r.a3t, par->vid_regs + 0x118);
7011 + writel((u32) regs->vp.r.vrr, par->vid_regs + 0x120);
7012 +
7013 +
7014 + /* FP registers */
7015 +
7016 + writel((u32) regs->fp.r.pt1, par->vid_regs + 0x400);
7017 + writel((u32) regs->fp.r.pt2, par->vid_regs + 0x408);
7018 +
7019 + writel((u32) regs->fp.r.dfc, par->vid_regs + 0x418);
7020 + writel(regs->fp.r.blfsr, par->vid_regs + 0x420);
7021 + writel(regs->fp.r.rlfsr, par->vid_regs + 0x428);
7022 + writel(regs->fp.r.fmi, par->vid_regs + 0x430);
7023 + writel(regs->fp.r.fmd, par->vid_regs + 0x438);
7024 + writel(regs->fp.r.dca, par->vid_regs + 0x448);
7025 + writel(regs->fp.r.dmd, par->vid_regs + 0x450);
7026 + writel(regs->fp.r.crc, par->vid_regs + 0x458);
7027 + writel(regs->fp.r.fbb, par->vid_regs + 0x460);
7028 +
7029 + /* Final enables */
7030 +
7031 + val = readl(par->vid_regs + 0x410);
7032 +
7033 + /* Control the panel */
7034 + if (regs->fp.r.pm & (1 << 24)) {
7035 +
7036 + if (!(val & 0x09))
7037 + writel(regs->fp.r.pm, par->vid_regs + 0x410);
7038 + }
7039 + else {
7040 + if (!(val & 0x05))
7041 + writel(regs->fp.r.pm, par->vid_regs + 0x410);
7042 + }
7043 +
7044 + /* Turn everything on */
7045 +
7046 + writel(regs->dc.r.gcfg, par->dc_regs + 0x04);
7047 + writel((u32) regs->vp.r.vcfg, par->vid_regs + 0x00);
7048 + writel((u32) regs->vp.r.dcfg, par->vid_regs + 0x08);
7049 + writel(regs->dc.r.dcfg, par->dc_regs + 0x08);
7050 +}
7051 +
7052 +
7053 +#ifdef DEBUG
7054 +
7055 +void dump_regs(struct fb_info *info, int mode) {
7056 +
7057 + struct geodefb_par *par = info->par;
7058 + u32 val;
7059 + int i;
7060 +
7061 + if (mode == 0) {
7062 + for(i = 0; i < GP_REG_SIZE; i += 4) {
7063 + val = readl(par->gp_regs + i);
7064 + }
7065 + }
7066 +
7067 + if (mode == 1) {
7068 + writel(0x4758, par->dc_regs + 0x00);
7069 +
7070 + for(i = 0; i < DC_REG_SIZE; i += 4) {
7071 + val = readl(par->dc_regs + i);
7072 + printk("DC%x: %x\n", i, val);
7073 + }
7074 + }
7075 +
7076 + if (mode == 2) {
7077 + for(i = 0; i < VP_REG_SIZE; i += 8) {
7078 + val = readl(par->vid_regs + i);
7079 + printk("VP%x: %x\n", i, val);
7080 + }
7081 + }
7082 +
7083 + if (mode == 3) {
7084 + for(i = 0; i < FP_REG_SIZE; i += 8) {
7085 + val = readl(par->vid_regs + 0x400 + i);
7086 + printk("FP%x: %x\n", i, val);
7087 + }
7088 + }
7089 +}
7090 +
7091 +#endif
7092 diff -purN linux_2.6.24_org/drivers/video/geode/video_gx.c linux_2.6.24_olpc/drivers/video/geode/video_gx.c
7093 --- linux_2.6.24_org/drivers/video/geode/video_gx.c 2008-02-15 20:11:23.000000000 +0000
7094 +++ linux_2.6.24_olpc/drivers/video/geode/video_gx.c 2008-02-15 18:58:41.000000000 +0000
7095 @@ -16,10 +16,14 @@
7096 #include <asm/io.h>
7097 #include <asm/delay.h>
7098 #include <asm/msr.h>
7099 +#include <asm/olpc.h>
7100
7101 #include "geodefb.h"
7102 #include "video_gx.h"
7103 +#include "display_gx.h"
7104
7105 +/* This structure is used to store the saved registers during suspend */
7106 +static struct geoderegs gx_saved_regs;
7107
7108 /*
7109 * Tables of register settings for various DOTCLKs.
7110 @@ -58,7 +62,7 @@ static const struct gx_pll_entry gx_pll_
7111 { 13888, POSTDIV3, 0x000007E1 }, /* 72.0000 */
7112 { 13426, PREMULT2, 0x00000F4A }, /* 74.4810 */
7113 { 13333, 0, 0x00000052 }, /* 75.0000 */
7114 - { 12698, 0, 0x00000056 }, /* 78.7500 */
7115 + { 12698, 0, 0x00000056 }, /* 78.7500 */
7116 { 12500, POSTDIV3|PREMULT2, 0x00000709 }, /* 80.0000 */
7117 { 11135, PREMULT2, 0x00000262 }, /* 89.8000 */
7118 { 10582, 0, 0x000002D2 }, /* 94.5000 */
7119 @@ -117,8 +121,9 @@ static const struct gx_pll_entry gx_pll_
7120 { 4357, 0, 0x0000057D }, /* 229.5000 */
7121 };
7122
7123 -static void gx_set_dclk_frequency(struct fb_info *info)
7124 +void gx_set_dclk_frequency(struct fb_info *info)
7125 {
7126 + struct geodefb_par *par = info->par;
7127 const struct gx_pll_entry *pll_table;
7128 int pll_table_len;
7129 int i, best_i;
7130 @@ -173,115 +178,169 @@ static void gx_set_dclk_frequency(struct
7131 do {
7132 rdmsrl(MSR_GLCP_DOTPLL, dotpll);
7133 } while (timeout-- && !(dotpll & MSR_GLCP_DOTPLL_LOCK));
7134 +
7135 + par->curdclk = pll_table[best_i].dotpll_value;
7136 }
7137
7138 -static void
7139 -gx_configure_tft(struct fb_info *info)
7140 +/* Find out the current clock - we will use this information to avoid
7141 + re-programming it if we don't need to */
7142 +
7143 +unsigned int gx_get_dclk(struct fb_info *info)
7144 {
7145 - struct geodefb_par *par = info->par;
7146 - unsigned long val;
7147 - unsigned long fp;
7148 + const struct gx_pll_entry *pll_table;
7149 + int pll_table_len;
7150 + u64 dotpll;
7151 + int i;
7152
7153 - /* Set up the DF pad select MSR */
7154 + if (cpu_data(0).x86_mask == 1) {
7155 + pll_table = gx_pll_table_14MHz;
7156 + pll_table_len = ARRAY_SIZE(gx_pll_table_14MHz);
7157 + } else {
7158 + pll_table = gx_pll_table_48MHz;
7159 + pll_table_len = ARRAY_SIZE(gx_pll_table_48MHz);
7160 + }
7161
7162 - rdmsrl(GX_VP_MSR_PAD_SELECT, val);
7163 - val &= ~GX_VP_PAD_SELECT_MASK;
7164 - val |= GX_VP_PAD_SELECT_TFT;
7165 - wrmsrl(GX_VP_MSR_PAD_SELECT, val);
7166 + rdmsrl(MSR_GLCP_DOTPLL, dotpll);
7167
7168 - /* Turn off the panel */
7169 + for(i = 0; i < pll_table_len; i++) {
7170 + if (pll_table[i].dotpll_value == (u32) (dotpll >> 32))
7171 + break;
7172 + }
7173 +
7174 + return (i == pll_table_len) ? 0 : pll_table[i].pixclock;
7175 +}
7176
7177 - fp = readl(par->vid_regs + GX_FP_PM);
7178 - fp &= ~GX_FP_PM_P;
7179 - writel(fp, par->vid_regs + GX_FP_PM);
7180
7181 - /* Set timing 1 */
7182 +#define CMP(val, mask, res) (((val) & (mask)) == (res))
7183
7184 - fp = readl(par->vid_regs + GX_FP_PT1);
7185 - fp &= GX_FP_PT1_VSIZE_MASK;
7186 - fp |= info->var.yres << GX_FP_PT1_VSIZE_SHIFT;
7187 - writel(fp, par->vid_regs + GX_FP_PT1);
7188 +static void
7189 +gx_configure_tft(struct fb_info *info) {
7190
7191 - /* Timing 2 */
7192 - /* Set bits that are always on for TFT */
7193 + struct geodefb_par *par = info->par;
7194 + u32 val, fp = 0, fp1, fp2, sync = 0;
7195
7196 - fp = 0x0F100000;
7197 + /* Set up the DF pad select MSR */
7198
7199 - /* Add sync polarity */
7200 + rdmsrl(GX_VP_MSR_PAD_SELECT, val);
7201 +
7202 + if ((val & GX_VP_PAD_SELECT_MASK) != GX_VP_PAD_SELECT_TFT) {
7203 + val &= ~GX_VP_PAD_SELECT_MASK;
7204 + val |= GX_VP_PAD_SELECT_TFT;
7205 + wrmsrl(GX_VP_MSR_PAD_SELECT, val);
7206 + }
7207
7208 if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
7209 - fp |= GX_FP_PT2_VSP;
7210 + sync |= GX_FP_PT2_VSP;
7211
7212 if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
7213 - fp |= GX_FP_PT2_HSP;
7214 + sync |= GX_FP_PT2_HSP;
7215
7216 - writel(fp, par->vid_regs + GX_FP_PT2);
7217 + /* We only need to turn off the panel if something changed */
7218
7219 - /* Set the dither control */
7220 - writel(0x70, par->vid_regs + GX_FP_DFC);
7221 + fp1 = readl(par->vid_regs + GX_FP_PT1);
7222 + fp2 = readl(par->vid_regs + GX_FP_PT2);
7223 +
7224 + if (!CMP(fp1, GX_FP_PT1_VSIZE_MASK, info->var.yres << GX_FP_PT1_VSIZE_SHIFT) ||
7225 + (fp2 != (0x0F100000 | sync))) {
7226 +
7227 + /* Turn off the panel */
7228 +
7229 +#ifdef NOTUSED
7230 + /* Do we really need to turn off the panel? */
7231 + /* Possibly - we have a glitch somewhere */
7232
7233 - /* Enable the FP data and power (in case the BIOS didn't) */
7234 + fp = readl(par->vid_regs + GX_FP_PM);
7235 + fp &= ~GX_FP_PM_P;
7236 + writel(fp, par->vid_regs + GX_FP_PM);
7237 +#endif
7238
7239 - fp = readl(par->vid_regs + GX_DCFG);
7240 - fp |= GX_DCFG_FP_PWR_EN | GX_DCFG_FP_DATA_EN;
7241 - writel(fp, par->vid_regs + GX_DCFG);
7242 + /* Timing 1 */
7243 + fp1 &= GX_FP_PT1_VSIZE_MASK;
7244 + fp1 |= info->var.yres << GX_FP_PT1_VSIZE_SHIFT;
7245 + writel(fp, par->vid_regs + GX_FP_PT1);
7246
7247 - /* Unblank the panel */
7248 + /* Timing 2 */
7249 + writel(0x0F100000 | sync, par->vid_regs + GX_FP_PT2);
7250 + }
7251 +
7252 + /* Set the dither control */
7253 + if (readl(par->vid_regs + GX_FP_DFC) != 0x70) {
7254 + writel(0x70, par->vid_regs + GX_FP_DFC);
7255 + }
7256 +
7257 + /* Turn on the panel */
7258
7259 fp = readl(par->vid_regs + GX_FP_PM);
7260 - fp |= GX_FP_PM_P;
7261 - writel(fp, par->vid_regs + GX_FP_PM);
7262 +
7263 + if (!(fp & 0x09))
7264 + writel(fp | GX_FP_PM_P, par->vid_regs + GX_FP_PM);
7265 }
7266
7267 +#define DCFG_DEFAULT_VAL GX_DCFG_CRT_SYNC_SKW_DFLT | GX_DCFG_HSYNC_EN | GX_DCFG_VSYNC_EN | \
7268 +GX_DCFG_CRT_EN | GX_DCFG_DAC_BL_EN
7269 +
7270 static void gx_configure_display(struct fb_info *info)
7271 {
7272 struct geodefb_par *par = info->par;
7273 - u32 dcfg, misc;
7274 + u32 dcfg, misc, sync = 0;
7275
7276 /* Set up the MISC register */
7277 -
7278 misc = readl(par->vid_regs + GX_MISC);
7279
7280 - /* Power up the DAC */
7281 - misc &= ~(GX_MISC_A_PWRDN | GX_MISC_DAC_PWRDN);
7282 + /* We leave gamma enabled if it was already enabled.
7283 + Although the hardware enables it without setting
7284 + up the gamma table, the BIOS or bootloader ought
7285 + to have either disabled it or loaded a table by now */
7286
7287 - /* Disable gamma correction */
7288 - misc |= GX_MISC_GAM_EN;
7289
7290 - writel(misc, par->vid_regs + GX_MISC);
7291
7292 - /* Write the display configuration */
7293 - dcfg = readl(par->vid_regs + GX_DCFG);
7294 + if (par->enable_crt) {
7295 + /* Power up the CRT DACs */
7296 + if (misc & ( GX_MISC_A_PWRDN | GX_MISC_DAC_PWRDN)) {
7297 + misc &= ~(GX_MISC_A_PWRDN | GX_MISC_DAC_PWRDN);
7298 + writel(misc, par->vid_regs + GX_MISC);
7299 + }
7300
7301 - /* Disable hsync and vsync */
7302 - dcfg &= ~(GX_DCFG_VSYNC_EN | GX_DCFG_HSYNC_EN);
7303 - writel(dcfg, par->vid_regs + GX_DCFG);
7304 + if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
7305 + sync |= GX_DCFG_CRT_HSYNC_POL;
7306
7307 - /* Clear bits from existing mode. */
7308 - dcfg &= ~(GX_DCFG_CRT_SYNC_SKW_MASK
7309 - | GX_DCFG_CRT_HSYNC_POL | GX_DCFG_CRT_VSYNC_POL
7310 - | GX_DCFG_VSYNC_EN | GX_DCFG_HSYNC_EN);
7311 + if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
7312 + sync |= GX_DCFG_CRT_VSYNC_POL;
7313 + }
7314 + else {
7315 + /* Turn off the CRT DACs in FP mode - we don't need them */
7316 + if ((misc & (GX_MISC_A_PWRDN | GX_MISC_DAC_PWRDN))) {
7317 + misc |= (GX_MISC_A_PWRDN | GX_MISC_DAC_PWRDN);
7318 + writel(misc, par->vid_regs + GX_MISC);
7319 + }
7320 + }
7321
7322 - /* Set default sync skew. */
7323 - dcfg |= GX_DCFG_CRT_SYNC_SKW_DFLT;
7324 + /* Write the display configuration */
7325 + dcfg = readl(par->vid_regs + GX_DCFG);
7326
7327 - /* Enable hsync and vsync. */
7328 - dcfg |= GX_DCFG_HSYNC_EN | GX_DCFG_VSYNC_EN;
7329 + if (!CMP(dcfg, DCFG_DEFAULT_VAL | GX_DCFG_CRT_HSYNC_POL | GX_DCFG_CRT_VSYNC_POL,
7330 + DCFG_DEFAULT_VAL | sync)) {
7331
7332 - /* Sync polarities. */
7333 - if (info->var.sync & FB_SYNC_HOR_HIGH_ACT)
7334 - dcfg |= GX_DCFG_CRT_HSYNC_POL;
7335 - if (info->var.sync & FB_SYNC_VERT_HIGH_ACT)
7336 - dcfg |= GX_DCFG_CRT_VSYNC_POL;
7337 + /* Disable hsync and vsync */
7338 + dcfg &= ~(GX_DCFG_VSYNC_EN | GX_DCFG_HSYNC_EN);
7339 + writel(dcfg, par->vid_regs + GX_DCFG);
7340
7341 - /* Enable the display logic */
7342 - /* Set up the DACS to blank normally */
7343 + /* Clear bits from existing mode. */
7344 + dcfg &= ~(GX_DCFG_CRT_SYNC_SKW_MASK
7345 + | GX_DCFG_CRT_HSYNC_POL | GX_DCFG_CRT_VSYNC_POL
7346 + | GX_DCFG_VSYNC_EN | GX_DCFG_HSYNC_EN);
7347
7348 - dcfg |= GX_DCFG_CRT_EN | GX_DCFG_DAC_BL_EN;
7349 + /* Set default sync skew. */
7350 + dcfg |= GX_DCFG_CRT_SYNC_SKW_DFLT;
7351
7352 - /* Enable the external DAC VREF? */
7353 + /* Enable hsync and vsync. */
7354 + dcfg |= GX_DCFG_HSYNC_EN | GX_DCFG_VSYNC_EN;
7355
7356 - writel(dcfg, par->vid_regs + GX_DCFG);
7357 + /* Enable the display logic */
7358 + dcfg |= GX_DCFG_CRT_EN | GX_DCFG_DAC_BL_EN;
7359 +
7360 + writel(dcfg, par->vid_regs + GX_DCFG);
7361 + }
7362
7363 /* Set up the flat panel (if it is enabled) */
7364
7365 @@ -289,6 +348,100 @@ static void gx_configure_display(struct
7366 gx_configure_tft(info);
7367 }
7368
7369 +int gxfb_powerdown(struct fb_info *info)
7370 +{
7371 + struct geodefb_par *par = info->par;
7372 +
7373 + /* We're already suspended */
7374 +
7375 + if (par->state != FB_POWER_STATE_ON)
7376 + return 0;
7377 +
7378 + /* Save the registers */
7379 + gx_save_regs(info, &gx_saved_regs);
7380 +
7381 + /* Shut down the engine */
7382 +
7383 + writel(gx_saved_regs.vp.r.vcfg & ~0x01, par->vid_regs + GX_VCFG);
7384 + writel(gx_saved_regs.vp.r.dcfg & ~0x0F, par->vid_regs + GX_DCFG);
7385 +
7386 + /* Turn off the flat panel unless we are attached to a DCON */
7387 + if (!olpc_has_dcon())
7388 + writel(gx_saved_regs.fp.r.pm & ~GX_FP_PM_P, par->vid_regs + GX_FP_PM);
7389 +
7390 + writel(0x4758, par->dc_regs + DC_UNLOCK);
7391 +
7392 + writel(gx_saved_regs.dc.r.gcfg & ~0x0F,
7393 + par->dc_regs + DC_GENERAL_CFG);
7394 +
7395 + writel(gx_saved_regs.dc.r.dcfg & ~0x19,
7396 + par->dc_regs + DC_DISPLAY_CFG);
7397 +
7398 + par->state = FB_POWER_STATE_SUSPEND;
7399 +
7400 + return 0;
7401 +}
7402 +
7403 +int gxfb_powerup(struct fb_info *info)
7404 +{
7405 + struct geodefb_par *par = info->par;
7406 + u32 val;
7407 +
7408 + if (par->state == FB_POWER_STATE_SUSPEND) {
7409 +
7410 + writel(gx_saved_regs.dc.r.dcfg,
7411 + par->dc_regs + DC_DISPLAY_CFG);
7412 +
7413 + writel(gx_saved_regs.vp.r.vcfg, par->vid_regs + GX_VCFG);
7414 + writel(gx_saved_regs.vp.r.dcfg, par->vid_regs + GX_DCFG);
7415 +
7416 + val = readl(par->vid_regs + GX_FP_PM);
7417 +
7418 + /* power up the panel if it needs it; we don't always power it down */
7419 + if (!(val & 0x09)) {
7420 + writel(gx_saved_regs.fp.r.pm, par->vid_regs + GX_FP_PM);
7421 + mdelay(64);
7422 + }
7423 + }
7424 +
7425 + /* If the panel is currently on its way up, then wait up to 100ms
7426 + for it */
7427 +
7428 + if (readl(par->vid_regs + GX_FP_PM) & 0x08) {
7429 + int i;
7430 +
7431 + for(i = 0; i < 10; i++) {
7432 + if (readl(par->vid_regs + GX_FP_PM) & 0x01)
7433 + break;
7434 +
7435 + mdelay(10);
7436 + }
7437 +
7438 + if (i == 10)
7439 + printk(KERN_ERR "gxfb: Panel power up timed out\n");
7440 + }
7441 +
7442 + if (par->state == FB_POWER_STATE_ON)
7443 + return 0;
7444 +
7445 + switch(par->state) {
7446 + case FB_POWER_STATE_OFF:
7447 + gx_restore_regs(info, &gx_saved_regs);
7448 + break;
7449 +
7450 + case FB_POWER_STATE_SUSPEND:
7451 + /* Do this because it will turn on the FIFO which will
7452 + start the line count */
7453 + writel(gx_saved_regs.dc.r.gcfg,
7454 + par->dc_regs + DC_GENERAL_CFG);
7455 + writel(0x0, par->dc_regs + DC_UNLOCK);
7456 + break;
7457 + }
7458 +
7459 + par->state = FB_POWER_STATE_ON;
7460 + return 0;
7461 +}
7462 +
7463 static int gx_blank_display(struct fb_info *info, int blank_mode)
7464 {
7465 struct geodefb_par *par = info->par;
7466 @@ -315,6 +468,7 @@ static int gx_blank_display(struct fb_in
7467 default:
7468 return -EINVAL;
7469 }
7470 +
7471 dcfg = readl(par->vid_regs + GX_DCFG);
7472 dcfg &= ~(GX_DCFG_DAC_BL_EN
7473 | GX_DCFG_HSYNC_EN | GX_DCFG_VSYNC_EN);
7474 @@ -326,7 +480,7 @@ static int gx_blank_display(struct fb_in
7475 dcfg |= GX_DCFG_VSYNC_EN;
7476 writel(dcfg, par->vid_regs + GX_DCFG);
7477
7478 - /* Power on/off flat panel. */
7479 + /* Power on/off flat panel */
7480
7481 if (par->enable_crt == 0) {
7482 fp_pm = readl(par->vid_regs + GX_FP_PM);
7483 @@ -340,8 +494,37 @@ static int gx_blank_display(struct fb_in
7484 return 0;
7485 }
7486
7487 +extern struct fb_info *gxfb_info;
7488 +
7489 +/* This function controls the flatpanel power sequencing - this is used
7490 + by the OLPC power management engine to enable the FP sequencing much
7491 + earlier in the resume process
7492 +*/
7493 +
7494 +void gxfb_flatpanel_control(int state)
7495 +{
7496 + struct geodefb_par *par = gxfb_info->par;
7497 + u32 val, fp = readl(par->vid_regs + GX_FP_PM);
7498 + val = fp;
7499 +
7500 + /* Turn on the panel if it isn't aleady */
7501 +
7502 + if (state) {
7503 + if (!(val & 0x01))
7504 + val |= GX_FP_PM_P;
7505 + }
7506 + else {
7507 + if (!(val & 0x02))
7508 + val &= ~GX_FP_PM_P;
7509 + }
7510 +
7511 + if (val != fp)
7512 + writel(val, par->vid_regs + GX_FP_PM);
7513 +}
7514 +
7515 struct geode_vid_ops gx_vid_ops = {
7516 .set_dclk = gx_set_dclk_frequency,
7517 + .get_dclk = gx_get_dclk,
7518 .configure_display = gx_configure_display,
7519 .blank_display = gx_blank_display,
7520 };
7521 diff -purN linux_2.6.24_org/drivers/video/geode/video_gx.h linux_2.6.24_olpc/drivers/video/geode/video_gx.h
7522 --- linux_2.6.24_org/drivers/video/geode/video_gx.h 2008-02-15 20:11:23.000000000 +0000
7523 +++ linux_2.6.24_olpc/drivers/video/geode/video_gx.h 2008-02-15 18:58:41.000000000 +0000
7524 @@ -11,6 +11,8 @@
7525 #ifndef __VIDEO_GX_H__
7526 #define __VIDEO_GX_H__
7527
7528 +#include "geode_regs.h"
7529 +
7530 extern struct geode_vid_ops gx_vid_ops;
7531
7532 /* GX Flatpanel control MSR */
7533 @@ -20,6 +22,8 @@ extern struct geode_vid_ops gx_vid_ops;
7534
7535 /* Geode GX video processor registers */
7536
7537 +#define GX_VCFG 0x0000
7538 +
7539 #define GX_DCFG 0x0008
7540 # define GX_DCFG_CRT_EN 0x00000001
7541 # define GX_DCFG_HSYNC_EN 0x00000002
7542 @@ -42,6 +46,14 @@ extern struct geode_vid_ops gx_vid_ops;
7543 #define GX_MISC_DAC_PWRDN 0x00000400
7544 #define GX_MISC_A_PWRDN 0x00000800
7545
7546 +/* Gamma correction RAM - address and data registers */
7547 +
7548 +#define GX_GAR 0x038
7549 +#define GX_GDR 0x040
7550 +
7551 +#define GXFB_GAMMA_DWORDS 256 /* number of dwords in the gamma ram */
7552 +#define GXFB_GAMMA_SIZE (GXFB_GAMMA_DWORDS * sizeof(unsigned int))
7553 +
7554 /* Geode GX flat panel display control registers */
7555
7556 #define GX_FP_PT1 0x0400
7557 @@ -69,4 +81,13 @@ extern struct geode_vid_ops gx_vid_ops;
7558 # define MSR_GLCP_DOTPLL_BYPASS (0x0000000000008000ull)
7559 # define MSR_GLCP_DOTPLL_LOCK (0x0000000002000000ull)
7560
7561 +int gxfb_powerdown(struct fb_info *info);
7562 +int gxfb_powerup(struct fb_info *info);
7563 +
7564 +void gx_set_dclk_frequency(struct fb_info *info);
7565 +unsigned int gx_get_dclk(struct fb_info *info);
7566 +
7567 +void gx_save_regs(struct fb_info *info, struct geoderegs *regs);
7568 +void gx_restore_regs(struct fb_info *info, struct geoderegs *regs);
7569 +
7570 #endif /* !__VIDEO_GX_H__ */
7571 diff -purN linux_2.6.24_org/drivers/video/Kconfig linux_2.6.24_olpc/drivers/video/Kconfig
7572 --- linux_2.6.24_org/drivers/video/Kconfig 2008-02-15 20:11:22.000000000 +0000
7573 +++ linux_2.6.24_olpc/drivers/video/Kconfig 2008-02-15 18:58:36.000000000 +0000
7574 @@ -1869,6 +1869,15 @@ config FB_PS3_DEFAULT_SIZE_M
7575 The default value can be overridden on the kernel command line
7576 using the "ps3fb" option (e.g. "ps3fb=9M");
7577
7578 +config FB_OLPC_DCON
7579 + tristate "One Laptop Per Child Display CONtroller support"
7580 + depends on OLPC
7581 + select I2C
7582 + ---help---
7583 + Add support for the OLPC DCON controller. This controller is only
7584 + available on OLPC platforms. Unless you have one of these
7585 + platforms, you will want to say 'N'.
7586 +
7587 config FB_XILINX
7588 tristate "Xilinx frame buffer support"
7589 depends on FB && XILINX_VIRTEX
7590 diff -purN linux_2.6.24_org/drivers/video/Makefile linux_2.6.24_olpc/drivers/video/Makefile
7591 --- linux_2.6.24_org/drivers/video/Makefile 2008-02-15 20:11:22.000000000 +0000
7592 +++ linux_2.6.24_olpc/drivers/video/Makefile 2008-02-15 18:58:36.000000000 +0000
7593 @@ -111,6 +111,7 @@ obj-$(CONFIG_FB_PNX4008_DUM_RGB) += pnx
7594 obj-$(CONFIG_FB_IBM_GXT4500) += gxt4500.o
7595 obj-$(CONFIG_FB_PS3) += ps3fb.o
7596 obj-$(CONFIG_FB_SM501) += sm501fb.o
7597 +obj-$(CONFIG_FB_OLPC_DCON) += olpc_dcon.o
7598 obj-$(CONFIG_FB_XILINX) += xilinxfb.o
7599 obj-$(CONFIG_FB_OMAP) += omap/
7600
7601 diff -purN linux_2.6.24_org/drivers/video/modedb.c linux_2.6.24_olpc/drivers/video/modedb.c
7602 --- linux_2.6.24_org/drivers/video/modedb.c 2008-02-15 20:11:23.000000000 +0000
7603 +++ linux_2.6.24_olpc/drivers/video/modedb.c 2008-02-15 18:58:41.000000000 +0000
7604 @@ -33,6 +33,8 @@ const char *fb_mode_option;
7605 * Standard video mode definitions (taken from XFree86)
7606 */
7607
7608 +#define DEFAULT_MODEDB_INDEX 0
7609 +
7610 static const struct fb_videomode modedb[] = {
7611 {
7612 /* 640x400 @ 70 Hz, 31.5 kHz hsync */
7613 @@ -508,7 +510,8 @@ int fb_find_mode(struct fb_var_screeninf
7614 }
7615
7616 if (!default_mode)
7617 - default_mode = &db[0];
7618 + default_mode = (db == modedb) ?
7619 + &modedb[DEFAULT_MODEDB_INDEX] : &db[0];
7620
7621 if (!default_bpp)
7622 default_bpp = 8;
7623 diff -purN linux_2.6.24_org/drivers/video/olpc_dcon.c linux_2.6.24_olpc/drivers/video/olpc_dcon.c
7624 --- linux_2.6.24_org/drivers/video/olpc_dcon.c 1970-01-01 01:00:00.000000000 +0100
7625 +++ linux_2.6.24_olpc/drivers/video/olpc_dcon.c 2008-02-15 18:58:42.000000000 +0000
7626 @@ -0,0 +1,946 @@
7627 +/*
7628 + * Mainly by David Woodhouse, somewhat modified by Jordan Crouse
7629 + *
7630 + * Copyright © 2006-2007 Red Hat, Inc.
7631 + * Copyright © 2006-2007 Advanced Micro Devices, Inc.
7632 + *
7633 + * This program is free software. You can redistribute it and/or
7634 + * modify it under the terms of version 2 of the GNU General Public
7635 + * License as published by the Free Software Foundation.
7636 + */
7637 +
7638 +
7639 +#include <linux/kernel.h>
7640 +#include <linux/fb.h>
7641 +#include <linux/console.h>
7642 +#include <linux/i2c.h>
7643 +#include <linux/platform_device.h>
7644 +#include <linux/i2c-id.h>
7645 +#include <linux/pci.h>
7646 +#include <linux/vt_kern.h>
7647 +#include <linux/pci_ids.h>
7648 +#include <linux/interrupt.h>
7649 +#include <linux/delay.h>
7650 +#include <linux/backlight.h>
7651 +#include <linux/device.h>
7652 +#include <linux/notifier.h>
7653 +#include <asm/uaccess.h>
7654 +#include <linux/ctype.h>
7655 +#include <linux/reboot.h>
7656 +#include <asm/tsc.h>
7657 +#include <asm/olpc.h>
7658 +#include <asm/geode.h>
7659 +
7660 +#include "olpc_dcon.h"
7661 +
7662 +/* Module definitions */
7663 +
7664 +static int resumeline = 898;
7665 +module_param(resumeline, int, 0444);
7666 +
7667 +static int noinit;
7668 +module_param(noinit, int, 0444);
7669 +
7670 +/* Default off since it doesn't work on DCON ASIC in B-test OLPC board */
7671 +static int useaa = 1;
7672 +module_param(useaa, int, 0444);
7673 +
7674 +/* I2C structures */
7675 +
7676 +static struct i2c_driver dcon_driver;
7677 +static struct i2c_client *dcon_client;
7678 +
7679 +/* Platform devices */
7680 +static struct platform_device *dcon_device;
7681 +
7682 +/* Backlight device */
7683 +static struct backlight_device *dcon_bl_dev;
7684 +
7685 +/* Base address of the GPIO registers */
7686 +static unsigned long gpio_base;
7687 +
7688 +static struct fb_info *fbinfo;
7689 +
7690 +/* Current source, initialized at probe time */
7691 +static int dcon_source;
7692 +
7693 +/* Desired source */
7694 +static int dcon_pending;
7695 +
7696 +/* Current output type */
7697 +static int dcon_output = DCON_OUTPUT_COLOR;
7698 +
7699 +/* Current sleep status (not yet implemented) */
7700 +static int dcon_sleep_val = DCON_ACTIVE;
7701 +
7702 +/* Shadow register for the DCON_REG_MODE register */
7703 +static unsigned short dcon_disp_mode;
7704 +
7705 +/* Variables used during switches */
7706 +static int dcon_switched;
7707 +
7708 +static DECLARE_WAIT_QUEUE_HEAD(dcon_wait_queue);
7709 +
7710 +static unsigned short normal_i2c[] = { 0x0D, I2C_CLIENT_END };
7711 +I2C_CLIENT_INSMOD;
7712 +
7713 +#define dcon_write(reg,val) i2c_smbus_write_word_data(dcon_client,reg,val)
7714 +#define dcon_read(reg) i2c_smbus_read_word_data(dcon_client,reg)
7715 +
7716 +/* The current backlight value - this saves us some smbus traffic */
7717 +static int bl_val = -1;
7718 +
7719 +/* ===== API functions - these are called by a variety of users ==== */
7720 +
7721 +static int dcon_request_irq(void);
7722 +
7723 +static int dcon_hw_init(struct i2c_client *client, int is_init)
7724 +{
7725 + uint16_t ver;
7726 + int rc = 0;
7727 +
7728 + ver = i2c_smbus_read_word_data(client, DCON_REG_ID);
7729 + if ((ver >> 8) != 0xDC) {
7730 + printk(KERN_ERR "olpc-dcon: DCON ID not 0xDCxx: 0x%04x "
7731 + "instead.\n", ver);
7732 + rc = -ENXIO;
7733 + goto err;
7734 + }
7735 +
7736 + if (is_init) {
7737 + printk(KERN_INFO "olpc-dcon: Discovered DCON version %x\n",
7738 + ver & 0xFF);
7739 + if ((rc = dcon_request_irq())) {
7740 + printk(KERN_ERR "olpc-dcon: Unable to grab IRQ.\n");
7741 + goto err;
7742 + }
7743 + }
7744 +
7745 + if (ver < 0xdc02 && !noinit) {
7746 + /* Initialize the DCON registers */
7747 +
7748 + /* Start with work-arounds for DCON ASIC */
7749 + i2c_smbus_write_word_data(client, 0x4b, 0x00cc);
7750 + i2c_smbus_write_word_data(client, 0x4b, 0x00cc);
7751 + i2c_smbus_write_word_data(client, 0x4b, 0x00cc);
7752 + i2c_smbus_write_word_data(client, 0x0b, 0x007a);
7753 + i2c_smbus_write_word_data(client, 0x36, 0x025c);
7754 + i2c_smbus_write_word_data(client, 0x37, 0x025e);
7755 +
7756 + /* Initialise SDRAM */
7757 +
7758 + i2c_smbus_write_word_data(client, 0x3b, 0x002b);
7759 + i2c_smbus_write_word_data(client, 0x41, 0x0101);
7760 + i2c_smbus_write_word_data(client, 0x42, 0x0101);
7761 + }
7762 + else if (!noinit) {
7763 + /* SDRAM setup/hold time */
7764 + i2c_smbus_write_word_data(client, 0x3a, 0xc040);
7765 + i2c_smbus_write_word_data(client, 0x41, 0x0000);
7766 + i2c_smbus_write_word_data(client, 0x41, 0x0101);
7767 + i2c_smbus_write_word_data(client, 0x42, 0x0101);
7768 + }
7769 +
7770 + /* Colour swizzle, AA, no passthrough, backlight */
7771 + if (is_init) {
7772 + dcon_disp_mode = MODE_PASSTHRU | MODE_BL_ENABLE | MODE_CSWIZZLE;
7773 + if (useaa)
7774 + dcon_disp_mode |= MODE_COL_AA;
7775 + }
7776 + i2c_smbus_write_word_data(client, DCON_REG_MODE, dcon_disp_mode);
7777 +
7778 +
7779 + /* Set the scanline to interrupt on during resume */
7780 +
7781 + i2c_smbus_write_word_data(client, DCON_REG_SCAN_INT, resumeline);
7782 +
7783 +err:
7784 + return rc;
7785 +}
7786 +
7787 +/*
7788 + * The smbus doesn't always come back due to what is believed to be
7789 + * hardware (power rail) bugs. For older models where this is known to
7790 + * occur, our solution is to attempt to wait for the bus to stabilize;
7791 + * if it doesn't happen, cut power to the dcon, repower it, and wait
7792 + * for the bus to stabilize. Rinse, repeat until we have a working
7793 + * smbus. For newer models, we simply BUG(); we want to know if this
7794 + * still happens despite the power fixes that have been made!
7795 + */
7796 +static int dcon_bus_stabilize(struct i2c_client *client, int is_powered_down)
7797 +{
7798 + unsigned long timeout;
7799 + int x;
7800 +
7801 +power_up:
7802 + if (is_powered_down) {
7803 + x = 1;
7804 + if ((x = olpc_ec_cmd(0x26, (unsigned char *) &x, 1, NULL, 0))) {
7805 + printk(KERN_WARNING "olpc-dcon: unable to force dcon "
7806 + "to power up: %d!\n", x);
7807 + return x;
7808 + }
7809 + msleep(10); /* we'll be conservative */
7810 + }
7811 +
7812 + /*
7813 + * According to HiMax, when powering the DCON up we should hold
7814 + * SMB_DATA high for 8 SMB_CLK cycles. This will force the DCON
7815 + * state machine to reset to a (sane) initial state. Mitch Bradley
7816 + * did some testing and discovered that holding for 16 SMB_CLK cycles
7817 + * worked a lot more reliably, so that's what we do here.
7818 + *
7819 + * According to the cs5536 spec, to set GPIO14 to SMB_CLK we must
7820 + * simultaneously set AUX1 IN/OUT to GPIO14; ditto for SMB_DATA and
7821 + * GPIO15.
7822 + */
7823 + geode_gpio_set(OLPC_GPIO_SMB_CLK|OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_VAL);
7824 + geode_gpio_set(OLPC_GPIO_SMB_CLK|OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_ENABLE);
7825 + geode_gpio_clear(OLPC_GPIO_SMB_CLK|OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_AUX1);
7826 + geode_gpio_clear(OLPC_GPIO_SMB_CLK|OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_AUX2);
7827 + geode_gpio_clear(OLPC_GPIO_SMB_CLK|OLPC_GPIO_SMB_DATA, GPIO_INPUT_AUX1);
7828 +
7829 + for (x = 0; x < 16; x++) {
7830 + udelay(5);
7831 + geode_gpio_clear(OLPC_GPIO_SMB_CLK, GPIO_OUTPUT_VAL);
7832 + udelay(5);
7833 + geode_gpio_set(OLPC_GPIO_SMB_CLK, GPIO_OUTPUT_VAL);
7834 + }
7835 + udelay(5);
7836 + geode_gpio_set(OLPC_GPIO_SMB_CLK|OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_AUX1);
7837 + geode_gpio_set(OLPC_GPIO_SMB_CLK|OLPC_GPIO_SMB_DATA, GPIO_INPUT_AUX1);
7838 +
7839 + for (x = -1, timeout = 50; timeout && x < 0; timeout--) {
7840 + msleep(1);
7841 + x = dcon_read(DCON_REG_ID);
7842 + }
7843 + if (x < 0) {
7844 + printk(KERN_ERR "olpc-dcon: unable to stabilize dcon's "
7845 + "smbus, reasserting power and praying.\n");
7846 + BUG_ON(olpc_board_at_least(olpc_board(0xc2)));
7847 + x = 0;
7848 + olpc_ec_cmd(0x26, (unsigned char *) &x, 1, NULL, 0);
7849 + msleep(100);
7850 + is_powered_down = 1;
7851 + goto power_up; /* argh, stupid hardware.. */
7852 + }
7853 +
7854 + if (is_powered_down)
7855 + return dcon_hw_init(client, 0);
7856 + return 0;
7857 +}
7858 +
7859 +
7860 +/* Backlight notes - turning off the backlight enable bit in the DCON
7861 + * doesn't save us any power over just pushing the BL to zero, so we
7862 + * don't use that bit in this code.
7863 + */
7864 +
7865 +static int dcon_get_backlight(void)
7866 +{
7867 + if (dcon_client == NULL)
7868 + return 0;
7869 +
7870 + if (bl_val == -1)
7871 + bl_val = dcon_read(DCON_REG_BRIGHT) & 0x0F;
7872 +
7873 + return bl_val;
7874 +}
7875 +
7876 +static void dcon_set_backlight(int level)
7877 +{
7878 + if (dcon_client == NULL)
7879 + return;
7880 +
7881 + if (bl_val == (level & 0x0F))
7882 + return;
7883 +
7884 + bl_val = level & 0x0F;
7885 + dcon_write(DCON_REG_BRIGHT, bl_val);
7886 +
7887 + /* Purposely turn off the backlight when we go to level 0 */
7888 +
7889 + if (bl_val == 0) {
7890 + dcon_disp_mode &= ~MODE_BL_ENABLE;
7891 + dcon_write(DCON_REG_MODE, dcon_disp_mode);
7892 + }
7893 + else if (!(dcon_disp_mode & MODE_BL_ENABLE)) {
7894 + dcon_disp_mode |= MODE_BL_ENABLE;
7895 + dcon_write(DCON_REG_MODE, dcon_disp_mode);
7896 + }
7897 +}
7898 +
7899 +/* Set the output type to either color or mono */
7900 +
7901 +static int dcon_set_output(int arg)
7902 +{
7903 + if (dcon_output == arg)
7904 + return 0;
7905 +
7906 + dcon_output = arg;
7907 +
7908 + if (arg == DCON_OUTPUT_MONO) {
7909 + dcon_disp_mode &= ~(MODE_CSWIZZLE | MODE_COL_AA);
7910 + dcon_disp_mode |= MODE_MONO_LUMA;
7911 + }
7912 + else {
7913 + dcon_disp_mode &= ~(MODE_MONO_LUMA);
7914 + dcon_disp_mode |= MODE_CSWIZZLE;
7915 + if (useaa)
7916 + dcon_disp_mode |= MODE_COL_AA;
7917 + }
7918 +
7919 + dcon_write(DCON_REG_MODE, dcon_disp_mode);
7920 + return 0;
7921 +}
7922 +
7923 +/* For now, this will be really stupid - we need to address how
7924 + * DCONLOAD works in a sleep and account for it accordingly
7925 + */
7926 +
7927 +static void dcon_sleep(int state)
7928 +{
7929 + int x;
7930 +
7931 + /* Turn off the backlight and put the DCON to sleep */
7932 +
7933 + if (state == dcon_sleep_val)
7934 + return;
7935 +
7936 + if (!olpc_board_at_least(olpc_board(0xc2)))
7937 + return;
7938 +
7939 + if (state == DCON_SLEEP) {
7940 + x = 0;
7941 + if ((x = olpc_ec_cmd(0x26, (unsigned char *) &x, 1, NULL, 0)))
7942 + printk(KERN_WARNING "olpc-dcon: unable to force dcon "
7943 + "to power down: %d!\n", x);
7944 + else
7945 + dcon_sleep_val = state;
7946 + }
7947 + else {
7948 + /* Only re-enable the backlight if the backlight value is set */
7949 + if (bl_val != 0)
7950 + dcon_disp_mode |= MODE_BL_ENABLE;
7951 +
7952 + if ((x=dcon_bus_stabilize(dcon_client, 1)))
7953 + printk(KERN_WARNING "olpc-dcon: unable to reinit dcon"
7954 + " hardware: %d!\n", x);
7955 + else
7956 + dcon_sleep_val = state;
7957 + }
7958 +
7959 + /* We should turn off some stuff in the framebuffer - but what? */
7960 +}
7961 +
7962 +/* Set the source of the display (CPU or DCON) */
7963 +
7964 +static void dcon_source_switch(struct work_struct *work)
7965 +{
7966 + DECLARE_WAITQUEUE(wait, current);
7967 + int source = dcon_pending;
7968 +
7969 + if (dcon_source == source)
7970 + return;
7971 +
7972 + dcon_switched = 0;
7973 +
7974 + switch (source) {
7975 + case DCON_SOURCE_CPU:
7976 +
7977 + /* Enable the scanline interrupt bit */
7978 + if (dcon_write(DCON_REG_MODE, dcon_disp_mode | MODE_SCAN_INT))
7979 + printk(KERN_ERR "olpc-dcon: couldn't enable scanline interrupt!\n");
7980 + else {
7981 + /* Wait up to one second for the scanline interrupt */
7982 + wait_event_timeout(dcon_wait_queue, dcon_switched == 1, HZ);
7983 + }
7984 +
7985 + if (!dcon_switched)
7986 + printk(KERN_ERR "olpc-dcon: Timeout entering CPU mode; expect a screen glitch.\n");
7987 +
7988 + /*
7989 + * Ideally we'd like to disable interrupts here so that the
7990 + * fb unblanking and DCON turn on happen at a known time value;
7991 + * however, we can't do that right now with fb_blank
7992 + * messing with semaphores.
7993 + *
7994 + * For now, we just hope..
7995 + */
7996 + acquire_console_sem();
7997 + if (fb_blank(fbinfo, FB_BLANK_UNBLANK)) {
7998 + release_console_sem();
7999 + printk(KERN_ERR "olpc-dcon: Failed to enter CPU mode\n");
8000 + dcon_pending = DCON_SOURCE_DCON;
8001 + return;
8002 + }
8003 + release_console_sem();
8004 +
8005 + /* And turn off the DCON */
8006 + outl(1<<11, gpio_base + GPIOx_OUT_VAL);
8007 +
8008 + /* Turn off the scanline interrupt */
8009 + if (dcon_write(DCON_REG_MODE, dcon_disp_mode))
8010 + printk(KERN_ERR "olpc-dcon: couldn't disable scanline interrupt!\n");
8011 +
8012 + printk(KERN_INFO "olpc-dcon: The CPU has control\n");
8013 + break;
8014 + case DCON_SOURCE_DCON:
8015 + {
8016 + int t;
8017 +
8018 + add_wait_queue(&dcon_wait_queue, &wait);
8019 + set_current_state(TASK_UNINTERRUPTIBLE);
8020 +
8021 + /* Clear GPIO11 (DCONLOAD) - this implies that the DCON is in
8022 + control */
8023 +
8024 + outl(1 << (11 + 16), gpio_base + GPIOx_OUT_VAL);
8025 +
8026 + t = schedule_timeout(HZ/2);
8027 + remove_wait_queue(&dcon_wait_queue, &wait);
8028 + set_current_state(TASK_RUNNING);
8029 +
8030 + if (!dcon_switched)
8031 + printk(KERN_ERR "olpc-dcon: Timeout entering DCON mode; expect a screen glitch.\n");
8032 +
8033 + acquire_console_sem();
8034 + if (fb_blank(fbinfo, FB_BLANK_POWERDOWN))
8035 + printk(KERN_ERR "olpc-dcon: couldn't blank fb!\n");
8036 + release_console_sem();
8037 +
8038 + printk(KERN_INFO "olpc-dcon: The DCON has control\n");
8039 + break;
8040 + }
8041 + default:
8042 + BUG();
8043 + }
8044 +
8045 + dcon_source = source;
8046 +}
8047 +
8048 +static DECLARE_WORK(dcon_work, dcon_source_switch);
8049 +
8050 +static int dcon_set_source(int arg)
8051 +{
8052 + if (arg != DCON_SOURCE_CPU && arg != DCON_SOURCE_DCON)
8053 + return -EINVAL;
8054 +
8055 + if (dcon_pending == arg)
8056 + return 0;
8057 +
8058 + dcon_pending = arg;
8059 + if ((dcon_source != arg) && !work_pending(&dcon_work))
8060 + schedule_work(&dcon_work);
8061 +
8062 + return 0;
8063 +}
8064 +
8065 +static int dcon_set_source_sync(int arg)
8066 +{
8067 + int ret = dcon_set_source(arg);
8068 + if (!ret)
8069 + flush_scheduled_work();
8070 + return ret;
8071 +}
8072 +
8073 +static int dconbl_set(struct backlight_device *dev) {
8074 +
8075 + int level = dev->props.brightness;
8076 +
8077 + if (dev->props.power != FB_BLANK_UNBLANK)
8078 + level = 0;
8079 +
8080 + dcon_set_backlight(level);
8081 + return 0;
8082 +}
8083 +
8084 +static int dconbl_get(struct backlight_device *dev) {
8085 + return dcon_get_backlight();
8086 +}
8087 +
8088 +static ssize_t dcon_mode_show(struct device *dev,
8089 + struct device_attribute *attr, char *buf)
8090 +{
8091 + return sprintf(buf, "%4.4X\n", dcon_disp_mode);
8092 +}
8093 +
8094 +static ssize_t dcon_sleep_show(struct device *dev,
8095 + struct device_attribute *attr, char *buf)
8096 +{
8097 + return sprintf(buf, "%d\n", dcon_sleep_val);
8098 +}
8099 +
8100 +static ssize_t /* __deprecated */ dcon_source_show(struct device *dev,
8101 + struct device_attribute *attr, char *buf)
8102 +{
8103 + printk(KERN_WARNING "olpc-dcon: using deprecated sysfs 'source' interface; use 'freeze' instead!\n");
8104 + return sprintf(buf, "%d\n", dcon_source);
8105 +}
8106 +
8107 +static ssize_t dcon_freeze_show(struct device *dev,
8108 + struct device_attribute *attr, char *buf)
8109 +{
8110 + return sprintf(buf, "%d\n", dcon_source == DCON_SOURCE_DCON ? 1 : 0);
8111 +}
8112 +
8113 +static ssize_t dcon_output_show(struct device *dev,
8114 + struct device_attribute *attr, char *buf)
8115 +{
8116 + return sprintf(buf, "%d\n", dcon_output);
8117 +}
8118 +
8119 +static ssize_t dcon_resumeline_show(struct device *dev,
8120 + struct device_attribute *attr, char *buf)
8121 +{
8122 + return sprintf(buf, "%d\n", resumeline);
8123 +}
8124 +
8125 +static int _strtoul(const char *buf, int len, unsigned int *val)
8126 +{
8127 +
8128 + char *endp;
8129 + unsigned int output = simple_strtoul(buf, &endp, 0);
8130 + int size = endp - buf;
8131 +
8132 + if (*endp && isspace(*endp))
8133 + size++;
8134 +
8135 + if (size != len)
8136 + return -EINVAL;
8137 +
8138 + *val = output;
8139 + return 0;
8140 +}
8141 +
8142 +static ssize_t dcon_output_store(struct device *dev,
8143 + struct device_attribute *attr, const char *buf, size_t count)
8144 +{
8145 + int output;
8146 + int rc = -EINVAL;
8147 +
8148 + if (_strtoul(buf, count, &output))
8149 + return -EINVAL;
8150 +
8151 + if (output == DCON_OUTPUT_COLOR || output == DCON_OUTPUT_MONO) {
8152 + dcon_set_output(output);
8153 + rc = count;
8154 + }
8155 +
8156 + return rc;
8157 +}
8158 +
8159 +static ssize_t /* __deprecated */ dcon_source_store(struct device *dev,
8160 + struct device_attribute *attr, const char *buf, size_t count)
8161 +{
8162 + int output;
8163 + int rc = -EINVAL;
8164 +
8165 + printk(KERN_WARNING "olpc-dcon: using deprecated sysfs 'source' interface; use 'freeze' instead!\n");
8166 + if (_strtoul(buf, count, &output))
8167 + return -EINVAL;
8168 +
8169 + dcon_set_source(output);
8170 + rc = count;
8171 +
8172 + return rc;
8173 +}
8174 +
8175 +static ssize_t dcon_freeze_store(struct device *dev,
8176 + struct device_attribute *attr, const char *buf, size_t count)
8177 +{
8178 + int output;
8179 + int rc = -EINVAL;
8180 +
8181 + if (_strtoul(buf, count, &output))
8182 + return rc;
8183 +
8184 + dcon_set_source(output ? DCON_SOURCE_DCON : DCON_SOURCE_CPU);
8185 + rc = count;
8186 +
8187 + return rc;
8188 +}
8189 +
8190 +static ssize_t dcon_resumeline_store(struct device *dev,
8191 + struct device_attribute *attr, const char *buf, size_t count)
8192 +{
8193 + int rl;
8194 + int rc = -EINVAL;
8195 +
8196 + if (_strtoul(buf, count, &rl))
8197 + return rc;
8198 +
8199 + resumeline = rl;
8200 + dcon_write(DCON_REG_SCAN_INT, resumeline);
8201 + rc = count;
8202 +
8203 + return rc;
8204 +}
8205 +
8206 +static ssize_t dcon_sleep_store(struct device *dev,
8207 + struct device_attribute *attr, const char *buf, size_t count)
8208 +{
8209 + int output;
8210 +
8211 + if (_strtoul(buf, count, &output))
8212 + return -EINVAL;
8213 +
8214 + dcon_sleep(output ? DCON_SLEEP : DCON_ACTIVE);
8215 + return count;
8216 +}
8217 +
8218 +static struct device_attribute dcon_device_files[] = {
8219 + __ATTR(mode, 0444, dcon_mode_show, NULL),
8220 + __ATTR(sleep, 0644, dcon_sleep_show, dcon_sleep_store),
8221 + __ATTR(source, 0644, dcon_source_show, dcon_source_store),
8222 + __ATTR(freeze, 0644, dcon_freeze_show, dcon_freeze_store),
8223 + __ATTR(output, 0644, dcon_output_show, dcon_output_store),
8224 + __ATTR(resumeline, 0644, dcon_resumeline_show, dcon_resumeline_store),
8225 +};
8226 +
8227 +static struct backlight_ops dcon_bl_ops = {
8228 + .get_brightness = dconbl_get,
8229 + .update_status = dconbl_set
8230 +};
8231 +
8232 +/* List of GPIOs that we care about:
8233 + (in) GPIO12 -- DCONBLNK
8234 + (in) GPIO[56] -- DCONSTAT[01]
8235 + (out) GPIO11 -- DCONLOAD
8236 +*/
8237 +
8238 +#define IN_GPIOS ((1<<5) | (1<<6) | (1<<7) | (1<<12))
8239 +#define OUT_GPIOS (1<<11)
8240 +
8241 +static irqreturn_t dcon_interrupt(int, void *);
8242 +
8243 +static int dcon_request_irq(void)
8244 +{
8245 + unsigned long lo, hi;
8246 + unsigned char lob;
8247 +
8248 + rdmsr(MSR_LBAR_GPIO, lo, hi);
8249 +
8250 + /* Check the mask and whether GPIO is enabled (sanity check) */
8251 + if (hi != 0x0000f001) {
8252 + printk(KERN_ERR "GPIO not enabled -- cannot use DCON\n");
8253 + return -ENODEV;
8254 + }
8255 +
8256 + /* Mask off the IO base address */
8257 + gpio_base = lo & 0x0000ff00;
8258 +
8259 + /* Turn off the event enable for GPIO7 just to be safe */
8260 + outl(1 << (16+7), gpio_base + GPIOx_EVNT_EN);
8261 +
8262 + /* Set the directions for the GPIO pins */
8263 + outl(OUT_GPIOS | (IN_GPIOS << 16), gpio_base + GPIOx_OUT_EN);
8264 + outl(IN_GPIOS | (OUT_GPIOS << 16), gpio_base + GPIOx_IN_EN);
8265 +
8266 + /* Set up the interrupt mappings */
8267 +
8268 + /* Set the IRQ to pair 2 */
8269 + geode_gpio_event_irq(OLPC_GPIO_DCON_IRQ, 2);
8270 +
8271 + /* Enable group 2 to trigger the DCON interrupt */
8272 + geode_gpio_set_irq(2, DCON_IRQ);
8273 +
8274 + /* Select edge level for interrupt (in PIC) */
8275 +
8276 + lob = inb(0x4d0);
8277 + lob &= ~(1 << DCON_IRQ);
8278 + outb(lob, 0x4d0);
8279 +
8280 + /* Register the interupt handler */
8281 + if (request_irq(DCON_IRQ, &dcon_interrupt, 0, "DCON", &dcon_driver))
8282 + return -EIO;
8283 +
8284 + /* Clear INV_EN for GPIO7 (DCONIRQ) */
8285 + outl((1<<(16+7)), gpio_base + GPIOx_INV_EN);
8286 +
8287 + /* Enable filter for GPIO12 (DCONBLANK) */
8288 + outl(1<<(12), gpio_base + GPIOx_IN_FLTR_EN);
8289 +
8290 + /* Disable filter for GPIO7 */
8291 + outl(1<<(16+7), gpio_base + GPIOx_IN_FLTR_EN);
8292 +
8293 + /* Disable event counter for GPIO7 (DCONIRQ) and GPIO12 (DCONBLANK) */
8294 +
8295 + outl(1<<(16+7), gpio_base + GPIOx_EVNTCNT_EN);
8296 + outl(1<<(16+12), gpio_base + GPIOx_EVNTCNT_EN);
8297 +
8298 + /* Add GPIO12 to the Filter Event Pair #7 */
8299 + outb(12, gpio_base + GPIO_FE7_SEL);
8300 +
8301 + /* Turn off negative Edge Enable for GPIO12 */
8302 + outl(1<<(16+12), gpio_base + GPIOx_NEGEDGE_EN);
8303 +
8304 + /* Enable negative Edge Enable for GPIO7 */
8305 + outl(1<<7, gpio_base + GPIOx_NEGEDGE_EN);
8306 +
8307 + /* Zero the filter amount for Filter Event Pair #7 */
8308 + outw(0, gpio_base + GPIO_FLT7_AMNT);
8309 +
8310 + /* Clear the negative edge status for GPIO7 and GPIO12 */
8311 + outl((1<<7) | (1<<12), gpio_base+0x4c);
8312 +
8313 + /* FIXME: Clear the posiitive status as well, just to be sure */
8314 + outl((1<<7) | (1<<12), gpio_base+0x48);
8315 +
8316 + /* Enable events for GPIO7 (DCONIRQ) and GPIO12 (DCONBLANK) */
8317 + outl((1<<(7))|(1<<12), gpio_base + GPIOx_EVNT_EN);
8318 +
8319 + /* Determine the current state by reading the GPIO bit */
8320 + /* Earlier stages of the boot process have established the state */
8321 + dcon_source = inl(gpio_base + GPIOx_OUT_VAL) & (1<<11)
8322 + ? DCON_SOURCE_CPU
8323 + : DCON_SOURCE_DCON;
8324 + dcon_pending = dcon_source;
8325 +
8326 + return 0;
8327 +}
8328 +
8329 +static int dcon_reboot_notify(struct notifier_block *nb, unsigned long foo, void *bar)
8330 +{
8331 + if (dcon_client == NULL)
8332 + return 0;
8333 +
8334 + /* Turn off the DCON. Entirely. */
8335 + dcon_write(DCON_REG_MODE, 0x39);
8336 + dcon_write(DCON_REG_MODE, 0x32);
8337 + return 0;
8338 +}
8339 +
8340 +static int dcon_conswitch_notify(struct notifier_block *nb,
8341 + unsigned long mode, void *dummy)
8342 +{
8343 + if (mode == CONSOLE_EVENT_SWITCH_TEXT)
8344 + dcon_sleep(DCON_ACTIVE);
8345 +
8346 + return 0;
8347 +}
8348 +
8349 +static struct notifier_block dcon_nb = {
8350 + .notifier_call = dcon_reboot_notify,
8351 + .priority = -1,
8352 +};
8353 +
8354 +static struct notifier_block dcon_console_nb = {
8355 + .notifier_call = dcon_conswitch_notify,
8356 + .priority = -1,
8357 +};
8358 +
8359 +static int unfreeze_on_panic(struct notifier_block *nb, unsigned long e, void *p)
8360 +{
8361 + outl(1<<11, gpio_base + GPIOx_OUT_VAL);
8362 + return NOTIFY_DONE;
8363 +}
8364 +
8365 +static struct notifier_block dcon_panic_nb = {
8366 + .notifier_call = unfreeze_on_panic,
8367 +};
8368 +
8369 +static int dcon_probe(struct i2c_adapter *adap, int addr, int kind)
8370 +{
8371 + struct i2c_client *client;
8372 + int rc, i;
8373 +
8374 + if (!olpc_has_dcon()) {
8375 + printk("olpc-dcon: No DCON is attached.\n");
8376 + return -ENODEV;
8377 + }
8378 +
8379 + if (num_registered_fb >= 1)
8380 + fbinfo = registered_fb[0];
8381 +
8382 + if (adap->id != I2C_HW_SMBUS_SCX200) {
8383 + printk(KERN_ERR "olpc-dcon: Invalid I2C bus (%d not %d)\n",
8384 + adap->id, I2C_HW_SMBUS_SCX200);
8385 + return -ENXIO;
8386 + }
8387 +
8388 + client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
8389 + if (client == NULL)
8390 + return -ENOMEM;
8391 +
8392 + strncpy(client->name, "OLPC-DCON", I2C_NAME_SIZE);
8393 + client->addr = addr;
8394 + client->adapter = adap;
8395 + client->driver = &dcon_driver;
8396 +
8397 + if ((rc = i2c_attach_client(client)) != 0) {
8398 + printk(KERN_ERR "olpc-dcon: Unable to attach the I2C client.\n");
8399 + goto eclient;
8400 + }
8401 +
8402 + rc = dcon_hw_init(client, 1);
8403 + if (rc)
8404 + goto ei2c;
8405 +
8406 + /* Add the DCON device */
8407 +
8408 + dcon_device = platform_device_alloc("dcon", -1);
8409 +
8410 + if (dcon_device == NULL) {
8411 + printk(KERN_ERR "dcon: Unable to create the DCON device\n");
8412 + rc = -ENOMEM;
8413 + goto eirq;
8414 + }
8415 +
8416 + if ((rc = platform_device_add(dcon_device))) {
8417 + printk(KERN_ERR "dcon: Unable to add the DCON device\n");
8418 + goto edev;
8419 + }
8420 +
8421 + for(i = 0; i < ARRAY_SIZE(dcon_device_files); i++)
8422 + device_create_file(&dcon_device->dev, &dcon_device_files[i]);
8423 +
8424 + /* Add the backlight device for the DCON */
8425 +
8426 + dcon_client = client;
8427 +
8428 + dcon_bl_dev = backlight_device_register("dcon-bl", &dcon_device->dev,
8429 + NULL, &dcon_bl_ops);
8430 +
8431 + if (IS_ERR(dcon_bl_dev)) {
8432 + printk(KERN_INFO "Could not register the backlight device for the DCON (%ld)\n", PTR_ERR(dcon_bl_dev));
8433 + dcon_bl_dev = NULL;
8434 + }
8435 + else {
8436 + dcon_bl_dev->props.max_brightness = 15;
8437 + dcon_bl_dev->props.power = FB_BLANK_UNBLANK;
8438 + dcon_bl_dev->props.brightness = dcon_get_backlight();
8439 +
8440 + backlight_update_status(dcon_bl_dev);
8441 + }
8442 +
8443 + register_reboot_notifier(&dcon_nb);
8444 + console_event_register(&dcon_console_nb);
8445 + atomic_notifier_chain_register(&panic_notifier_list, &dcon_panic_nb);
8446 +
8447 + return 0;
8448 +
8449 + edev:
8450 + platform_device_unregister(dcon_device);
8451 + dcon_device = NULL;
8452 + eirq:
8453 + free_irq(DCON_IRQ, &dcon_driver);
8454 + ei2c:
8455 + i2c_detach_client(client);
8456 + eclient:
8457 + kfree(client);
8458 +
8459 + return rc;
8460 +}
8461 +
8462 +static int dcon_attach(struct i2c_adapter *adap)
8463 +{
8464 + int ret;
8465 +
8466 + ret = i2c_probe(adap, &addr_data, dcon_probe);
8467 +
8468 + if (dcon_client == NULL)
8469 + printk(KERN_ERR "olpc-dcon: No DCON found on SMBus\n");
8470 +
8471 + return ret;
8472 +}
8473 +
8474 +static int dcon_detach(struct i2c_client *client)
8475 +{
8476 + int rc;
8477 + dcon_client = NULL;
8478 +
8479 + unregister_reboot_notifier(&dcon_nb);
8480 + console_event_unregister(&dcon_console_nb);
8481 + atomic_notifier_chain_unregister(&panic_notifier_list, &dcon_panic_nb);
8482 +
8483 + free_irq(DCON_IRQ, &dcon_driver);
8484 +
8485 + if ((rc = i2c_detach_client(client)) == 0)
8486 + kfree(i2c_get_clientdata(client));
8487 +
8488 + if (dcon_bl_dev != NULL)
8489 + backlight_device_unregister(dcon_bl_dev);
8490 +
8491 + if (dcon_device != NULL)
8492 + platform_device_unregister(dcon_device);
8493 + cancel_work_sync(&dcon_work);
8494 +
8495 + return rc;
8496 +}
8497 +
8498 +
8499 +#ifdef CONFIG_PM
8500 +static int dcon_suspend(struct i2c_client *client, pm_message_t state)
8501 +{
8502 + if (dcon_sleep_val != DCON_ACTIVE)
8503 + return 0;
8504 +
8505 + /* Set up the DCON to have the source */
8506 + return dcon_set_source_sync(DCON_SOURCE_DCON);
8507 +}
8508 +
8509 +static int dcon_resume(struct i2c_client *client)
8510 +{
8511 + if (dcon_sleep_val != DCON_ACTIVE)
8512 + return 0;
8513 +
8514 + dcon_bus_stabilize(client, 0);
8515 +
8516 + return dcon_set_source(DCON_SOURCE_CPU);
8517 +}
8518 +
8519 +#endif
8520 +
8521 +static irqreturn_t dcon_interrupt(int irq, void *id)
8522 +{
8523 + int status = inl(gpio_base + GPIOx_READ_BACK) >> 5;
8524 +
8525 + /* Clear the negative edge status for GPIO7 */
8526 + outl(1 << 7, gpio_base + GPIOx_NEGEDGE_STS);
8527 +
8528 + switch (status & 3) {
8529 + case 3:
8530 + printk(KERN_DEBUG "olpc-dcon: DCONLOAD_MISSED interrupt\n");
8531 + break;
8532 + case 2: /* switch to DCON mode */
8533 + case 1: /* switch to CPU mode */
8534 + dcon_switched = 1;
8535 + wake_up(&dcon_wait_queue);
8536 + break;
8537 + case 0:
8538 + printk(KERN_DEBUG "olpc-dcon: scanline interrupt w/CPU\n");
8539 + }
8540 +
8541 + return IRQ_HANDLED;
8542 +}
8543 +
8544 +static struct i2c_driver dcon_driver = {
8545 + .driver = {
8546 + .name = "OLPC-DCON",
8547 + },
8548 + .id = I2C_DRIVERID_DCON,
8549 + .attach_adapter = dcon_attach,
8550 + .detach_client = dcon_detach,
8551 +#ifdef CONFIG_PM
8552 + .suspend = dcon_suspend,
8553 + .resume = dcon_resume,
8554 +#endif
8555 +};
8556 +
8557 +
8558 +static int __init olpc_dcon_init(void)
8559 +{
8560 + i2c_add_driver(&dcon_driver);
8561 + return 0;
8562 +}
8563 +
8564 +static void __exit olpc_dcon_exit(void)
8565 +{
8566 + i2c_del_driver(&dcon_driver);
8567 +}
8568 +
8569 +module_init(olpc_dcon_init);
8570 +module_exit(olpc_dcon_exit);
8571 +
8572 +MODULE_LICENSE("GPL");
8573 Binary files linux_2.6.24_org/drivers/video/.olpc_dcon.c.swp and linux_2.6.24_olpc/drivers/video/.olpc_dcon.c.swp differ
8574 diff -purN linux_2.6.24_org/drivers/video/olpc_dcon.h linux_2.6.24_olpc/drivers/video/olpc_dcon.h
8575 --- linux_2.6.24_org/drivers/video/olpc_dcon.h 1970-01-01 01:00:00.000000000 +0100
8576 +++ linux_2.6.24_olpc/drivers/video/olpc_dcon.h 2008-02-15 18:58:35.000000000 +0000
8577 @@ -0,0 +1,75 @@
8578 +#ifndef OLPC_DCON_H_
8579 +#define OLPC_DCON_H_
8580 +
8581 +/* DCON registers */
8582 +
8583 +#define DCON_REG_ID 0
8584 +#define DCON_REG_MODE 1
8585 +
8586 +#define MODE_PASSTHRU (1<<0)
8587 +#define MODE_SLEEP (1<<1)
8588 +#define MODE_SLEEP_AUTO (1<<2)
8589 +#define MODE_BL_ENABLE (1<<3)
8590 +#define MODE_BLANK (1<<4)
8591 +#define MODE_CSWIZZLE (1<<5)
8592 +#define MODE_COL_AA (1<<6)
8593 +#define MODE_MONO_LUMA (1<<7)
8594 +#define MODE_SCAN_INT (1<<8)
8595 +#define MODE_CLOCKDIV (1<<9)
8596 +#define MODE_DEBUG (1<<14)
8597 +#define MODE_SELFTEST (1<<15)
8598 +
8599 +#define DCON_REG_HRES 2
8600 +#define DCON_REG_HTOTAL 3
8601 +#define DCON_REG_HSYNC_WIDTH 4
8602 +#define DCON_REG_VRES 5
8603 +#define DCON_REG_VTOTAL 6
8604 +#define DCON_REG_VSYNC_WIDTH 7
8605 +#define DCON_REG_TIMEOUT 8
8606 +#define DCON_REG_SCAN_INT 9
8607 +#define DCON_REG_BRIGHT 10
8608 +
8609 +/* GPIO registers (CS5536) */
8610 +
8611 +#define MSR_LBAR_GPIO 0x5140000C
8612 +
8613 +#define GPIOx_OUT_VAL 0x00
8614 +#define GPIOx_OUT_EN 0x04
8615 +#define GPIOx_IN_EN 0x20
8616 +#define GPIOx_INV_EN 0x24
8617 +#define GPIOx_IN_FLTR_EN 0x28
8618 +#define GPIOx_EVNTCNT_EN 0x2C
8619 +#define GPIOx_READ_BACK 0x30
8620 +#define GPIOx_EVNT_EN 0x38
8621 +#define GPIOx_NEGEDGE_EN 0x44
8622 +#define GPIOx_NEGEDGE_STS 0x4C
8623 +#define GPIO_FLT7_AMNT 0xD8
8624 +#define GPIO_MAP_X 0xE0
8625 +#define GPIO_MAP_Y 0xE4
8626 +#define GPIO_FE7_SEL 0xF7
8627 +
8628 +
8629 +/* Status values */
8630 +
8631 +#define DCONSTAT_SCANINT 0
8632 +#define DCONSTAT_SCANINT_DCON 1
8633 +#define DCONSTAT_DISPLAYLOAD 2
8634 +#define DCONSTAT_MISSED 3
8635 +
8636 +/* Source values */
8637 +
8638 +#define DCON_SOURCE_DCON 0
8639 +#define DCON_SOURCE_CPU 1
8640 +
8641 +/* Output values */
8642 +#define DCON_OUTPUT_COLOR 0
8643 +#define DCON_OUTPUT_MONO 1
8644 +
8645 +/* Sleep values */
8646 +#define DCON_ACTIVE 0
8647 +#define DCON_SLEEP 1
8648 +
8649 +/* Interrupt */
8650 +#define DCON_IRQ 6
8651 +
8652 +#endif
8653 diff -purN linux_2.6.24_org/fs/jffs2/nodelist.h linux_2.6.24_olpc/fs/jffs2/nodelist.h
8654 --- linux_2.6.24_org/fs/jffs2/nodelist.h 2008-02-15 20:10:35.000000000 +0000
8655 +++ linux_2.6.24_olpc/fs/jffs2/nodelist.h 2008-02-15 18:57:39.000000000 +0000
8656 @@ -197,7 +197,7 @@ struct jffs2_inode_cache {
8657 #define RAWNODE_CLASS_XATTR_DATUM 1
8658 #define RAWNODE_CLASS_XATTR_REF 2
8659
8660 -#define INOCACHE_HASHSIZE 128
8661 +#define INOCACHE_HASHSIZE 1024
8662
8663 #define write_ofs(c) ((c)->nextblock->offset + (c)->sector_size - (c)->nextblock->free_size)
8664
8665 diff -purN linux_2.6.24_org/fs/Kconfig linux_2.6.24_olpc/fs/Kconfig
8666 --- linux_2.6.24_org/fs/Kconfig 2008-02-15 20:10:31.000000000 +0000
8667 +++ linux_2.6.24_olpc/fs/Kconfig 2008-02-15 18:57:33.000000000 +0000
8668 @@ -1031,6 +1031,37 @@ config HUGETLBFS
8669 config HUGETLB_PAGE
8670 def_bool HUGETLBFS
8671
8672 +config PROMFS_FS
8673 + tristate "PromFS IEEE 1275 file system support"
8674 + depends on SPARC || PPC || OLPC
8675 + help
8676 + PromFS is a file system interface to various IEEE-1275 compatible
8677 + firmwares. If you have such a firmware (Sparc64, PowerPC, and
8678 + some other architectures and embedded systems have such firmwares,
8679 + with names like "OpenBoot (tm)" and "OpenFirmware"), say Y here
8680 + to be able to access the firmware's device-tree from Linux.
8681 +
8682 + The firmware device-tree is available as a virtual file system,
8683 + can be mounted under /prom with the command "mount -t promfs
8684 + none /prom".
8685 +
8686 + To compile PromFS support as a module, choose M here; the module
8687 + will be called promfs. If unsure, choose M.
8688 +
8689 +config RAMFS
8690 + bool
8691 + default y
8692 + ---help---
8693 + Ramfs is a file system which keeps all files in RAM. It allows
8694 + read and write access.
8695 +
8696 + It is more of an programming example than a useable file system. If
8697 + you need a file system which lives in RAM with limit checking use
8698 + tmpfs.
8699 +
8700 + To compile this as a module, choose M here: the module will be called
8701 + ramfs.
8702 +
8703 config CONFIGFS_FS
8704 tristate "Userspace-driven configuration filesystem (EXPERIMENTAL)"
8705 depends on SYSFS && EXPERIMENTAL
8706 diff -purN linux_2.6.24_org/fs/Makefile linux_2.6.24_olpc/fs/Makefile
8707 --- linux_2.6.24_org/fs/Makefile 2008-02-15 20:10:33.000000000 +0000
8708 +++ linux_2.6.24_olpc/fs/Makefile 2008-02-15 18:57:34.000000000 +0000
8709 @@ -110,6 +110,7 @@ obj-$(CONFIG_ADFS_FS) += adfs/
8710 obj-$(CONFIG_FUSE_FS) += fuse/
8711 obj-$(CONFIG_UDF_FS) += udf/
8712 obj-$(CONFIG_SUN_OPENPROMFS) += openpromfs/
8713 +obj-$(CONFIG_PROMFS_FS) += promfs/
8714 obj-$(CONFIG_JFS_FS) += jfs/
8715 obj-$(CONFIG_XFS_FS) += xfs/
8716 obj-$(CONFIG_9P_FS) += 9p/
8717 diff -purN linux_2.6.24_org/fs/promfs/Makefile linux_2.6.24_olpc/fs/promfs/Makefile
8718 --- linux_2.6.24_org/fs/promfs/Makefile 1970-01-01 01:00:00.000000000 +0100
8719 +++ linux_2.6.24_olpc/fs/promfs/Makefile 2008-02-15 18:57:33.000000000 +0000
8720 @@ -0,0 +1 @@
8721 +obj-$(CONFIG_PROMFS_FS) += promfs.o
8722 diff -purN linux_2.6.24_org/fs/promfs/promfs.c linux_2.6.24_olpc/fs/promfs/promfs.c
8723 --- linux_2.6.24_org/fs/promfs/promfs.c 1970-01-01 01:00:00.000000000 +0100
8724 +++ linux_2.6.24_olpc/fs/promfs/promfs.c 2008-02-15 18:57:33.000000000 +0000
8725 @@ -0,0 +1,295 @@
8726 +/*
8727 + * promfs.c - generic inode/dentry functions for IEEE 1275-based filesystems.
8728 + *
8729 + * This is based heavily upon prior ieee1275 and other virtual filesystems
8730 + * implementations; openpromfs, proc_devtree.c, oprofilefs, procfs, ...
8731 + *
8732 + * Copyright (C) 2007 Andres Salomon <dilinger@debian.org>
8733 + *
8734 + * This program is free software; you can redistribute it and/or modify
8735 + * it under the terms of the GNU General Public License as published by
8736 + * the Free Software Foundation; either version 2 of the License, or
8737 + * (at your option) any later version.
8738 + *
8739 + * This program is distributed in the hope that it will be useful,
8740 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
8741 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
8742 + * GNU General Public License for more details.
8743 + *
8744 + * You should have received a copy of the GNU General Public License along
8745 + * with this program; if not, write to the Free Software Foundation, Inc.,
8746 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
8747 + */
8748 +
8749 +#include <linux/init.h>
8750 +#include <linux/module.h>
8751 +#include <linux/pagemap.h>
8752 +#include <linux/fs.h>
8753 +//#include <linux/promfs.h>
8754 +#include <asm/prom.h>
8755 +
8756 +#define PROMFS_MAGIC 0x1f2f3fff
8757 +
8758 +MODULE_LICENSE("GPL");
8759 +MODULE_AUTHOR("Andres Salomon");
8760 +
8761 +struct promfs_inode
8762 +{
8763 + struct inode ino;
8764 + struct property *prop;
8765 +};
8766 +
8767 +static inline struct promfs_inode *to_promfs_inode(struct inode *inode)
8768 +{
8769 + return container_of(inode, struct promfs_inode, ino);
8770 +}
8771 +
8772 +#if 0
8773 +static DEFINE_SPINLOCK(promfs_lock);
8774 +
8775 +static struct of_node *of_tree = NULL;
8776 +static DEFINE_RWLOCK(of_tree_lock);
8777 +
8778 +void __init of_build_tree(void)
8779 +{
8780 +
8781 +
8782 +}
8783 +#endif
8784 +
8785 +static int promfs_open_file(struct inode *inode, struct file *file)
8786 +{
8787 + struct promfs_inode *ino;
8788 +
8789 + ino = to_promfs_inode(inode);
8790 + if (!ino->prop)
8791 + return -EIO;
8792 + file->private_data = ino->prop;
8793 +
8794 + return 0;
8795 +}
8796 +
8797 +static ssize_t promfs_read_file(struct file *file, char __user *data,
8798 + size_t len, loff_t *ppos)
8799 +{
8800 + struct property *prop = (struct property *) file->private_data;
8801 + return simple_read_from_buffer(data, len, ppos, prop->value,
8802 + prop->length);
8803 +}
8804 +
8805 +static ssize_t promfs_write_file(struct file *file, char const __user *buf,
8806 + size_t count, loff_t * offset)
8807 +{
8808 + /* TODO.... 'cause, y'know, it would be nice. */
8809 + return -EIO;
8810 +}
8811 +
8812 +static struct file_operations promfs_file_ops = {
8813 + .open = promfs_open_file,
8814 + .read = promfs_read_file,
8815 + .write = promfs_write_file,
8816 +};
8817 +
8818 +static struct kmem_cache *promfs_inode_cachep;
8819 +
8820 +static struct inode *promfs_alloc_inode(struct super_block *sb)
8821 +{
8822 + struct promfs_inode *pr_ino;
8823 +
8824 + pr_ino = kmem_cache_alloc(promfs_inode_cachep, GFP_KERNEL);
8825 + if (!pr_ino)
8826 + return NULL;
8827 + pr_ino->prop = NULL;
8828 +
8829 + return &pr_ino->ino;
8830 +}
8831 +
8832 +static void promfs_destroy_inode(struct inode *inode)
8833 +{
8834 + kmem_cache_free(promfs_inode_cachep, to_promfs_inode(inode));
8835 +}
8836 +
8837 +static void promfs_read_inode(struct inode *inode)
8838 +{
8839 + inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
8840 +}
8841 +
8842 +static int promfs_remount(struct super_block *sb, int *flags, char *data)
8843 +{
8844 + *flags |= MS_NOATIME;
8845 + return 0;
8846 +}
8847 +
8848 +static struct super_operations promfs_s_ops = {
8849 + .alloc_inode = promfs_alloc_inode,
8850 + .destroy_inode = promfs_destroy_inode,
8851 + .read_inode = promfs_read_inode,
8852 + .statfs = simple_statfs,
8853 + .drop_inode = generic_delete_inode,
8854 + .remount_fs = promfs_remount,
8855 +};
8856 +
8857 +static struct inode *promfs_get_inode(struct super_block *sb, int mode)
8858 +{
8859 + struct inode *inode = new_inode(sb);
8860 +
8861 + if (inode) {
8862 + inode->i_mode = mode;
8863 + inode->i_uid = 0;
8864 + inode->i_gid = 0;
8865 + inode->i_blocks = 0;
8866 + inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
8867 + }
8868 +
8869 + return inode;
8870 +}
8871 +
8872 +static int promfs_create_file(struct super_block *sb, struct dentry *root,
8873 + struct property *prop, const struct file_operations *fops)
8874 +{
8875 + struct dentry *dentry;
8876 + struct inode *inode;
8877 + struct promfs_inode *ino;
8878 +
8879 + dentry = d_alloc_name(root, prop->name);
8880 + if (!dentry)
8881 + goto err;
8882 +
8883 + inode = promfs_get_inode(sb, S_IFREG | 0644);
8884 + if (!inode)
8885 + goto err_dput;
8886 + inode->i_fop = fops;
8887 + ino = to_promfs_inode(inode);
8888 + ino->prop = prop;
8889 + d_add(dentry, inode);
8890 +
8891 + return 0;
8892 +
8893 +err_dput:
8894 + dput(dentry);
8895 +err:
8896 + return -EFAULT;
8897 +}
8898 +
8899 +struct dentry *promfs_create_dir(struct super_block *sb, struct dentry *root,
8900 + char const *name)
8901 +{
8902 + struct dentry *dentry;
8903 + struct inode *inode;
8904 +
8905 + dentry = d_alloc_name(root, name);
8906 + if (!dentry)
8907 + goto err;
8908 +
8909 + inode = promfs_get_inode(sb, S_IFDIR | 0755);
8910 + if (!inode)
8911 + goto err_dput;
8912 + inode->i_op = &simple_dir_inode_operations;
8913 + inode->i_fop = &simple_dir_operations;
8914 + d_add(dentry, inode);
8915 + return dentry;
8916 +
8917 +err_dput:
8918 + dput(dentry);
8919 +err:
8920 + return NULL;
8921 +}
8922 +
8923 +void promfs_populate(struct super_block *sb, struct dentry *root,
8924 + struct device_node *node)
8925 +{
8926 + struct dentry *dentry;
8927 + struct device_node *child;
8928 + struct property *prop;
8929 +
8930 + if (!node)
8931 + return;
8932 +
8933 + for (child = node->child; child; child = child->sibling) {
8934 + dentry = promfs_create_dir(sb, root, child->path_component_name);
8935 + promfs_populate(sb, dentry, child);
8936 + }
8937 + for (prop = node->properties; prop; prop = prop->next)
8938 + promfs_create_file(sb, root, prop, &promfs_file_ops);
8939 +}
8940 +
8941 +static int promfs_fill_super(struct super_block *sb, void *data, int silent)
8942 +{
8943 + struct inode *root_inode;
8944 + struct dentry *root_dentry;
8945 + struct promfs_inode *inode;
8946 +
8947 + sb->s_blocksize = PAGE_CACHE_SIZE;
8948 + sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
8949 + sb->s_magic = PROMFS_MAGIC;
8950 + sb->s_op = &promfs_s_ops;
8951 + sb->s_time_gran = 1;
8952 + sb->s_flags |= MS_NOATIME;
8953 +
8954 + root_inode = promfs_get_inode(sb, S_IFDIR | 0755);
8955 + if (!root_inode)
8956 + goto err;
8957 + root_inode->i_op = &simple_dir_inode_operations;
8958 + root_inode->i_fop = &simple_dir_operations;
8959 +
8960 + inode = to_promfs_inode(root_inode);
8961 +
8962 + root_dentry = d_alloc_root(root_inode);
8963 + if (!root_dentry)
8964 + goto err_iput;
8965 + sb->s_root = root_dentry;
8966 +
8967 + promfs_populate(sb, root_dentry, of_find_node_by_path("/"));
8968 + return 0;
8969 +
8970 +err_iput:
8971 + iput(root_inode);
8972 +err:
8973 + return -ENOMEM;
8974 +}
8975 +
8976 +static int promfs_get_sb(struct file_system_type *fs_type, int flags,
8977 + const char *dev_name, void *data, struct vfsmount *mnt)
8978 +{
8979 + return get_sb_single(fs_type, flags, data, promfs_fill_super, mnt);
8980 +}
8981 +
8982 +static struct file_system_type promfs_fs_type = {
8983 + .owner = THIS_MODULE,
8984 + .name = "promfs",
8985 + .get_sb = promfs_get_sb,
8986 + .kill_sb = kill_litter_super,
8987 +};
8988 +
8989 +static void init_once(void *i, struct kmem_cache *cachep, unsigned long fl)
8990 +{
8991 + struct promfs_inode *inode = (struct promfs_inode *) i;
8992 + inode_init_once(&inode->ino);
8993 +}
8994 +
8995 +static int __init init_promfs(void)
8996 +{
8997 + int err;
8998 +
8999 + prom_build_devicetree();
9000 + promfs_inode_cachep = kmem_cache_create("promfs_inode_cache",
9001 + sizeof(struct promfs_inode), 0,
9002 + SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, init_once, NULL);
9003 + if (!promfs_inode_cachep)
9004 + return -ENOMEM;
9005 +
9006 + err = register_filesystem(&promfs_fs_type);
9007 + if (err)
9008 + kmem_cache_destroy(promfs_inode_cachep);
9009 +
9010 + return err;
9011 +}
9012 +
9013 +static void __exit exit_promfs(void)
9014 +{
9015 + unregister_filesystem(&promfs_fs_type);
9016 + kmem_cache_destroy(promfs_inode_cachep);
9017 +}
9018 +
9019 +module_init(init_promfs);
9020 +module_exit(exit_promfs);
9021 diff -purN linux_2.6.24_org/include/asm-x86/ofw.h linux_2.6.24_olpc/include/asm-x86/ofw.h
9022 --- linux_2.6.24_org/include/asm-x86/ofw.h 1970-01-01 01:00:00.000000000 +0100
9023 +++ linux_2.6.24_olpc/include/asm-x86/ofw.h 2008-02-15 18:57:59.000000000 +0000
9024 @@ -0,0 +1,16 @@
9025 +/*
9026 + * Definitions for Open Firmware client interface on 32-bit system.
9027 + * OF Cell size is 4. Integer properties are encoded big endian,
9028 + * as with all OF implementations.
9029 + *
9030 + * This program is free software; you can redistribute it and/or
9031 + * modify it under the terms of the GNU General Public License
9032 + * as published by the Free Software Foundation; either version
9033 + * 2 of the License, or (at your option) any later version.
9034 + */
9035 +#ifndef _OFW_H
9036 +#define _OFW_H
9037 +
9038 +extern int ofw(char *, int, int, ...);
9039 +
9040 +#endif
9041 diff -purN linux_2.6.24_org/include/asm-x86/olpc.h linux_2.6.24_olpc/include/asm-x86/olpc.h
9042 --- linux_2.6.24_org/include/asm-x86/olpc.h 1970-01-01 01:00:00.000000000 +0100
9043 +++ linux_2.6.24_olpc/include/asm-x86/olpc.h 2008-02-15 18:57:59.000000000 +0000
9044 @@ -0,0 +1,107 @@
9045 +/* OLPC machine specific definitions */
9046 +
9047 +#ifndef ASM_OLPC_H_
9048 +#define ASM_OLPC_H_
9049 +
9050 +#include <asm/geode.h>
9051 +
9052 +struct olpc_platform_t {
9053 + int flags;
9054 + u32 boardrev;
9055 + int ecver;
9056 +};
9057 +
9058 +#define OLPC_F_PRESENT 0x01
9059 +#define OLPC_F_DCON 0x02
9060 +#define OLPC_F_VSA 0x04
9061 +
9062 +/*
9063 + * OLPC board IDs contain the major build number within the mask 0x0ff0,
9064 + * and the minor build number withing 0x000f. Pre-builds have a minor
9065 + * number less than 8, and normal builds start at 8. For example, 0x0B10
9066 + * is a PreB1, and 0x0C18 is a C1.
9067 + */
9068 +
9069 +static inline u32 olpc_board(u8 id)
9070 +{
9071 + return (id << 4) | 0x8;
9072 +}
9073 +
9074 +static inline u32 olpc_board_pre(u8 id)
9075 +{
9076 + return id << 4;
9077 +}
9078 +
9079 +#ifndef CONFIG_OLPC
9080 +
9081 +static inline int machine_is_olpc(void) { return 0; }
9082 +static inline int olpc_has_dcon(void) { return 0; }
9083 +static inline int olpc_has_vsa(void) { return 0; }
9084 +
9085 +#else
9086 +
9087 +extern struct olpc_platform_t olpc_platform_info;
9088 +
9089 +static inline int
9090 +machine_is_olpc(void)
9091 +{
9092 + return (olpc_platform_info.flags & OLPC_F_PRESENT) ? 1 : 0;
9093 +}
9094 +
9095 +static inline int
9096 +olpc_has_dcon(void)
9097 +{
9098 + return (olpc_platform_info.flags & OLPC_F_DCON) ? 1 : 0;
9099 +}
9100 +
9101 +static inline int
9102 +olpc_has_vsa(void)
9103 +{
9104 + return (olpc_platform_info.flags & OLPC_F_VSA) ? 1 : 0;
9105 +}
9106 +
9107 +static inline int olpc_board_at_least(u32 rev)
9108 +{
9109 + return olpc_platform_info.boardrev >= rev;
9110 +}
9111 +
9112 +#endif
9113 +
9114 +/* EC functions */
9115 +
9116 +int olpc_ec_cmd(unsigned char cmd, unsigned char *inbuf, size_t inlen,
9117 + unsigned char *outbuf, size_t outlen);
9118 +
9119 +void olpc_register_battery_callback(void (*f)(unsigned long));
9120 +void olpc_deregister_battery_callback(void);
9121 +
9122 +/* EC commands and responses */
9123 +
9124 +/* SCI source values */
9125 +
9126 +#define EC_SCI_SRC_EMPTY 0x00
9127 +#define EC_SCI_SRC_GAME 0x01
9128 +#define EC_SCI_SRC_BATTERY 0x02
9129 +#define EC_SCI_SRC_BATSOC 0x04
9130 +#define EC_SCI_SRC_BATERR 0x08
9131 +#define EC_SCI_SRC_EBOOK 0x10
9132 +#define EC_SCI_SRC_WLAN 0x20
9133 +#define EC_SCI_SRC_ACPWR 0x40
9134 +#define EC_SCI_SRC_ALL 0x7F
9135 +
9136 +int olpc_ec_mask_set(u8 bits);
9137 +int olpc_ec_mask_unset(u8 bits);
9138 +
9139 +/* GPIO assignments */
9140 +
9141 +#define OLPC_GPIO_MIC_AC (1 << 1)
9142 +#define OLPC_GPIO_DCON_IRQ (1 << 7)
9143 +#define OLPC_GPIO_THRM_ALRM (1 << 10)
9144 +#define OLPC_GPIO_SMB_CLK (1 << 14)
9145 +#define OLPC_GPIO_SMB_DATA (1 << 15)
9146 +#define OLPC_GPIO_WORKAUX (1 << 24)
9147 +#define OLPC_GPIO_LID (1 << 26)
9148 +#define OLPC_GPIO_ECSCI (1 << 27)
9149 +
9150 +#endif
9151 +
9152 diff -purN linux_2.6.24_org/include/asm-x86/prom.h linux_2.6.24_olpc/include/asm-x86/prom.h
9153 --- linux_2.6.24_org/include/asm-x86/prom.h 1970-01-01 01:00:00.000000000 +0100
9154 +++ linux_2.6.24_olpc/include/asm-x86/prom.h 2008-02-15 18:57:59.000000000 +0000
9155 @@ -0,0 +1,108 @@
9156 +#ifndef _I386_PROM_H
9157 +#define _I386_PROM_H
9158 +#ifdef __KERNEL__
9159 +
9160 +
9161 +/*
9162 + * Definitions for talking to the Open Firmware PROM on
9163 + * Power Macintosh computers.
9164 + *
9165 + * Copyright (C) 1996-2005 Paul Mackerras.
9166 + *
9167 + * Updates for PPC64 by Peter Bergner & David Engebretsen, IBM Corp.
9168 + * Updates for SPARC64 by David S. Miller
9169 + * Updates for i386/OLPC by Andres Salomon
9170 + *
9171 + * This program is free software; you can redistribute it and/or
9172 + * modify it under the terms of the GNU General Public License
9173 + * as published by the Free Software Foundation; either version
9174 + * 2 of the License, or (at your option) any later version.
9175 + */
9176 +
9177 +#include <linux/types.h>
9178 +#include <linux/proc_fs.h>
9179 +#include <asm/atomic.h>
9180 +
9181 +typedef u32 phandle;
9182 +typedef u32 ihandle;
9183 +
9184 +struct property {
9185 + char *name;
9186 + int length;
9187 + void *value;
9188 + struct property *next;
9189 +};
9190 +
9191 +struct device_node {
9192 + const char *name;
9193 + const char *type;
9194 + phandle node;
9195 +// phandle linux_phandle;
9196 + char *path_component_name;
9197 + char *full_name;
9198 +
9199 + struct property *properties;
9200 + struct property *deadprops; /* removed properties */
9201 + struct device_node *parent;
9202 + struct device_node *child;
9203 + struct device_node *sibling;
9204 + struct device_node *next; /* next device of same type */
9205 + struct device_node *allnext; /* next in list of all nodes */
9206 + struct proc_dir_entry *pde; /* this node's proc directory */
9207 + struct kref kref;
9208 + unsigned long _flags;
9209 + void *data;
9210 +};
9211 +
9212 +/* flag descriptions */
9213 +#define OF_DYNAMIC 1 /* node and properties were allocated via kmalloc */
9214 +
9215 +#define OF_IS_DYNAMIC(x) test_bit(OF_DYNAMIC, &x->_flags)
9216 +#define OF_MARK_DYNAMIC(x) set_bit(OF_DYNAMIC, &x->_flags)
9217 +
9218 +#define OF_BAD_ADDR ((u64)-1)
9219 +
9220 +static inline void set_node_proc_entry(struct device_node *dn, struct proc_dir_entry *de)
9221 +{
9222 + dn->pde = de;
9223 +}
9224 +
9225 +extern struct device_node *of_find_node_by_name(struct device_node *from,
9226 + const char *name);
9227 +#define for_each_node_by_name(dn, name) \
9228 + for (dn = of_find_node_by_name(NULL, name); dn; \
9229 + dn = of_find_node_by_name(dn, name))
9230 +extern struct device_node *of_find_node_by_type(struct device_node *from,
9231 + const char *type);
9232 +#define for_each_node_by_type(dn, type) \
9233 + for (dn = of_find_node_by_type(NULL, type); dn; \
9234 + dn = of_find_node_by_type(dn, type))
9235 +extern struct device_node *of_find_compatible_node(struct device_node *from,
9236 + const char *type, const char *compat);
9237 +extern struct device_node *of_find_node_by_path(const char *path);
9238 +extern struct device_node *of_find_node_by_phandle(phandle handle);
9239 +extern struct device_node *of_get_parent(const struct device_node *node);
9240 +extern struct device_node *of_get_next_child(const struct device_node *node,
9241 + struct device_node *prev);
9242 +extern struct property *of_find_property(const struct device_node *np,
9243 + const char *name,
9244 + int *lenp);
9245 +//extern struct device_node *of_node_get(struct device_node *node);
9246 +//extern void of_node_put(struct device_node *node);
9247 +extern int of_device_is_compatible(const struct device_node *device,
9248 + const char *);
9249 +extern const void *of_get_property(const struct device_node *node,
9250 + const char *name,
9251 + int *lenp);
9252 +#define get_property(node,name,lenp) of_get_property(node,name,lenp)
9253 +extern int of_set_property(struct device_node *node, const char *name, void *val, int len);
9254 +extern int of_getintprop_default(struct device_node *np,
9255 + const char *name,
9256 + int def);
9257 +extern int of_n_addr_cells(struct device_node *np);
9258 +extern int of_n_size_cells(struct device_node *np);
9259 +
9260 +extern void prom_build_devicetree(void);
9261 +
9262 +#endif /* __KERNEL__ */
9263 +#endif
9264 diff -purN linux_2.6.24_org/include/linux/battery.h linux_2.6.24_olpc/include/linux/battery.h
9265 --- linux_2.6.24_org/include/linux/battery.h 1970-01-01 01:00:00.000000000 +0100
9266 +++ linux_2.6.24_olpc/include/linux/battery.h 2008-02-15 18:58:06.000000000 +0000
9267 @@ -0,0 +1,101 @@
9268 +/*
9269 + * Driver model for batteries
9270 + *
9271 + * © 2006 David Woodhouse <dwmw2@infradead.org>
9272 + *
9273 + * Based on LED Class support, by John Lenz and Richard Purdie:
9274 + *
9275 + * © 2005 John Lenz <lenz@cs.wisc.edu>
9276 + * © 2005-2006 Richard Purdie <rpurdie@openedhand.com>
9277 + *
9278 + * This program is free software; you can redistribute it and/or modify
9279 + * it under the terms of the GNU General Public License version 2 as
9280 + * published by the Free Software Foundation.
9281 + *
9282 + */
9283 +#ifndef __LINUX_BATTERY_H__
9284 +#define __LINUX_BATTERY_H__
9285 +
9286 +struct device;
9287 +struct class_device;
9288 +
9289 +/*
9290 + * Battery Core
9291 + */
9292 +#define PWRDEV_TYPE_BATTERY 0
9293 +#define PWRDEV_TYPE_AC 1
9294 +
9295 +#define BAT_STAT_PRESENT (1<<0)
9296 +#define BAT_STAT_LOW (1<<1)
9297 +#define BAT_STAT_FULL (1<<2)
9298 +#define BAT_STAT_CHARGING (1<<3)
9299 +#define BAT_STAT_DISCHARGING (1<<4)
9300 +#define BAT_STAT_OVERTEMP (1<<5)
9301 +#define BAT_STAT_CRITICAL (1<<6)
9302 +#define BAT_STAT_FIRE (1<<7)
9303 +#define BAT_STAT_CHARGE_DONE (1<<8)
9304 +
9305 +/* Thou shalt not export any attributes in sysfs except these, and
9306 + with these units: */
9307 +#define BAT_INFO_STATUS "status" /* Not free-form. Use
9308 + provided function */
9309 +#define BAT_INFO_TEMP1 "temp1" /* °C/1000 */
9310 +#define BAT_INFO_TEMP1_NAME "temp1_name" /* string */
9311 +
9312 +#define BAT_INFO_TEMP2 "temp2" /* °C/1000 */
9313 +#define BAT_INFO_TEMP2_NAME "temp2_name" /* string */
9314 +
9315 +#define BAT_INFO_VOLTAGE "voltage" /* mV */
9316 +#define BAT_INFO_VOLTAGE_DESIGN "voltage_design" /* mV */
9317 +
9318 +#define BAT_INFO_CURRENT "current" /* mA */
9319 +#define BAT_INFO_CURRENT_NOW "current_now" /* mA */
9320 +
9321 +#define BAT_INFO_POWER "power" /* mW */
9322 +#define BAT_INFO_POWER_NOW "power_now" /* mW */
9323 +
9324 +/* The following capacity/charge properties are represented in either
9325 + mA or mW. The CAP_UNITS property MUST be provided if any of these are. */
9326 +#define BAT_INFO_RATE "rate" /* CAP_UNITS */
9327 +#define BAT_INFO_CAP_LEFT "capacity_left" /* CAP_UNITS*h */
9328 +#define BAT_INFO_CAP_DESIGN "capacity_design" /* CAP_UNITS*h */
9329 +#define BAT_INFO_CAP_LAST_FULL "capacity_last_full" /* CAP_UNITS*h */
9330 +#define BAT_INFO_CAP_LOW "capacity_low_thresh" /* CAP_UNITS*h */
9331 +#define BAT_INFO_CAP_WARN "capacity_warn_thresh" /* CAP_UNITS*h */
9332 +#define BAT_INFO_CAP_UNITS "capacity_units" /* string: must be
9333 + either mA or mW */
9334 +
9335 +#define BAT_INFO_CAP_PCT "capacity_percentage" /* integer */
9336 +
9337 +#define BAT_INFO_TIME_EMPTY "time_to_empty" /* seconds */
9338 +#define BAT_INFO_TIME_EMPTY_NOW "time_to_empty_now" /* seconds */
9339 +#define BAT_INFO_TIME_FULL "time_to_full" /* seconds */
9340 +#define BAT_INFO_TIME_FULL_NOW "time_to_full_now" /* seconds */
9341 +
9342 +#define BAT_INFO_MANUFACTURER "manufacturer" /* string */
9343 +#define BAT_INFO_TECHNOLOGY "technology" /* string */
9344 +#define BAT_INFO_MODEL "model" /* string */
9345 +#define BAT_INFO_SERIAL "serial" /* string */
9346 +#define BAT_INFO_OEM_INFO "oem_info" /* string */
9347 +
9348 +#define BAT_INFO_CYCLE_COUNT "cycle_count" /* integer */
9349 +#define BAT_INFO_DATE_MFR "date_manufactured" /* YYYY[-MM[-DD]] */
9350 +#define BAT_INFO_DATE_FIRST_USE "date_first_use" /* YYYY[-MM[-DD]] */
9351 +
9352 +struct battery_dev {
9353 + int status_cap;
9354 + int id;
9355 + int type;
9356 + const char *name;
9357 +
9358 + struct device *dev;
9359 +};
9360 +
9361 +int battery_device_register(struct device *parent,
9362 + struct battery_dev *battery_cdev);
9363 +void battery_device_unregister(struct battery_dev *battery_cdev);
9364 +
9365 +
9366 +ssize_t battery_attribute_show_status(char *buf, unsigned long status);
9367 +ssize_t battery_attribute_show_ac_status(char *buf, unsigned long status);
9368 +#endif /* __LINUX_BATTERY_H__ */
9369 diff -purN linux_2.6.24_org/include/linux/fb.h linux_2.6.24_olpc/include/linux/fb.h
9370 --- linux_2.6.24_org/include/linux/fb.h 2008-02-15 20:10:55.000000000 +0000
9371 +++ linux_2.6.24_olpc/include/linux/fb.h 2008-02-15 18:58:01.000000000 +0000
9372 @@ -666,6 +666,12 @@ struct fb_ops {
9373 /* restore saved state */
9374 void (*fb_restore_state)(struct fb_info *info);
9375
9376 + /* Shut down the graphics engine to save power */
9377 + int (*fb_powerdown)(struct fb_info *info);
9378 +
9379 + /* Power it back up */
9380 + int (*fb_powerup)(struct fb_info *info);
9381 +
9382 /* get capability given var */
9383 void (*fb_get_caps)(struct fb_info *info, struct fb_blit_caps *caps,
9384 struct fb_var_screeninfo *var);
9385 @@ -945,6 +951,9 @@ extern int fb_get_color_depth(struct fb_
9386 extern int fb_get_options(char *name, char **option);
9387 extern int fb_new_modelist(struct fb_info *info);
9388
9389 +extern int fb_powerdown(struct fb_info *info);
9390 +extern int fb_powerup(struct fb_info *info);
9391 +
9392 extern struct fb_info *registered_fb[FB_MAX];
9393 extern int num_registered_fb;
9394 extern struct class *fb_class;
9395 diff -purN linux_2.6.24_org/include/linux/i2c-id.h linux_2.6.24_olpc/include/linux/i2c-id.h
9396 --- linux_2.6.24_org/include/linux/i2c-id.h 2008-02-15 20:10:52.000000000 +0000
9397 +++ linux_2.6.24_olpc/include/linux/i2c-id.h 2008-02-15 18:58:00.000000000 +0000
9398 @@ -125,6 +125,7 @@
9399 #define I2C_DRIVERID_LM4857 92 /* LM4857 Audio Amplifier */
9400 #define I2C_DRIVERID_VP27SMPX 93 /* Panasonic VP27s tuner internal MPX */
9401 #define I2C_DRIVERID_CS4270 94 /* Cirrus Logic 4270 audio codec */
9402 +#define I2C_DRIVERID_DCON 95
9403
9404 #define I2C_DRIVERID_I2CDEV 900
9405 #define I2C_DRIVERID_ARP 902 /* SMBus ARP Client */
9406 diff -purN linux_2.6.24_org/include/linux/isl_38xx.h linux_2.6.24_olpc/include/linux/isl_38xx.h
9407 --- linux_2.6.24_org/include/linux/isl_38xx.h 1970-01-01 01:00:00.000000000 +0100
9408 +++ linux_2.6.24_olpc/include/linux/isl_38xx.h 2008-02-15 18:58:05.000000000 +0000
9409 @@ -0,0 +1,127 @@
9410 +/*
9411 + * Copyright (C) 2002 Intersil Americas Inc.
9412 + *
9413 + * This program is free software; you can redistribute it and/or modify
9414 + * it under the terms of the GNU General Public License as published by
9415 + * the Free Software Foundation; either version 2 of the License
9416 + *
9417 + * This program is distributed in the hope that it will be useful,
9418 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
9419 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9420 + * GNU General Public License for more details.
9421 + *
9422 + * You should have received a copy of the GNU General Public License
9423 + * along with this program; if not, write to the Free Software
9424 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
9425 + */
9426 +
9427 +#ifndef _LINUX_ISL_38XX_H
9428 +#define _LINUX_ISL_38XX_H
9429 +
9430 +#include <asm/io.h>
9431 +
9432 +#define ISL38XX_CB_RX_QSIZE 8
9433 +#define ISL38XX_CB_TX_QSIZE 32
9434 +
9435 +/* ISL38XX Access Point Specific definitions */
9436 +#define ISL38XX_MAX_WDS_LINKS 8
9437 +
9438 +/* ISL38xx Client Specific definitions */
9439 +#define ISL38XX_PSM_ACTIVE_STATE 0
9440 +#define ISL38XX_PSM_POWERSAVE_STATE 1
9441 +
9442 +/* ISL38XX Host Interface Definitions */
9443 +#define ISL38XX_PCI_MEM_SIZE 0x02000
9444 +#define ISL38XX_MEMORY_WINDOW_SIZE 0x01000
9445 +#define ISL38XX_DEV_FIRMWARE_ADDRES 0x20000
9446 +#define ISL38XX_WRITEIO_DELAY 10 /* in us */
9447 +#define ISL38XX_RESET_DELAY 50 /* in ms */
9448 +#define ISL38XX_WAIT_CYCLE 10 /* in 10ms */
9449 +#define ISL38XX_MAX_WAIT_CYCLES 10
9450 +
9451 +/* PCI Memory Area */
9452 +#define ISL38XX_HARDWARE_REG 0x0000
9453 +#define ISL38XX_CARDBUS_CIS 0x0800
9454 +#define ISL38XX_DIRECT_MEM_WIN 0x1000
9455 +
9456 +/* Hardware registers */
9457 +#define ISL38XX_DEV_INT_REG 0x0000
9458 +#define ISL38XX_INT_IDENT_REG 0x0010
9459 +#define ISL38XX_INT_ACK_REG 0x0014
9460 +#define ISL38XX_INT_EN_REG 0x0018
9461 +#define ISL38XX_GEN_PURP_COM_REG_1 0x0020
9462 +#define ISL38XX_GEN_PURP_COM_REG_2 0x0024
9463 +#define ISL38XX_CTRL_BLK_BASE_REG ISL38XX_GEN_PURP_COM_REG_1
9464 +#define ISL38XX_DIR_MEM_BASE_REG 0x0030
9465 +#define ISL38XX_CTRL_STAT_REG 0x0078
9466 +
9467 +/* High end mobos queue up pci writes, the following
9468 + * is used to "read" from after a write to force flush */
9469 +#define ISL38XX_PCI_POSTING_FLUSH ISL38XX_INT_EN_REG
9470 +
9471 +/**
9472 + * isl38xx_w32_flush - PCI iomem write helper
9473 + * @base: (host) memory base address of the device
9474 + * @val: 32bit value (host order) to write
9475 + * @offset: byte offset into @base to write value to
9476 + *
9477 + * This helper takes care of writing a 32bit datum to the
9478 + * specified offset into the device's pci memory space, and making sure
9479 + * the pci memory buffers get flushed by performing one harmless read
9480 + * from the %ISL38XX_PCI_POSTING_FLUSH offset.
9481 + */
9482 +static inline void
9483 +isl38xx_w32_flush(void __iomem *base, u32 val, unsigned long offset)
9484 +{
9485 + writel(val, base + offset);
9486 + (void) readl(base + ISL38XX_PCI_POSTING_FLUSH);
9487 +}
9488 +
9489 +/* Device Interrupt register bits */
9490 +#define ISL38XX_DEV_INT_RESET 0x0001
9491 +#define ISL38XX_DEV_INT_UPDATE 0x0002
9492 +#define ISL38XX_DEV_INT_WAKEUP 0x0008
9493 +#define ISL38XX_DEV_INT_SLEEP 0x0010
9494 +#define ISL38XX_DEV_INT_ABORT 0x0020
9495 +/* thos two only used in USB */
9496 +#define ISL38XX_DEV_INT_DATA 0x0040
9497 +#define ISL38XX_DEV_INT_MGMT 0x0080
9498 +
9499 +#define ISL38XX_DEV_INT_PCIUART_CTS 0x4000
9500 +#define ISL38XX_DEV_INT_PCIUART_DR 0x8000
9501 +
9502 +/* Interrupt Identification/Acknowledge/Enable register bits */
9503 +#define ISL38XX_INT_IDENT_UPDATE 0x0002
9504 +#define ISL38XX_INT_IDENT_INIT 0x0004
9505 +#define ISL38XX_INT_IDENT_WAKEUP 0x0008
9506 +#define ISL38XX_INT_IDENT_SLEEP 0x0010
9507 +#define ISL38XX_INT_IDENT_PCIUART_CTS 0x4000
9508 +#define ISL38XX_INT_IDENT_PCIUART_DR 0x8000
9509 +
9510 +#define ISL38XX_INT_SOURCES (ISL38XX_INT_IDENT_UPDATE | \
9511 + ISL38XX_INT_IDENT_INIT | \
9512 + ISL38XX_INT_IDENT_WAKEUP | \
9513 + ISL38XX_INT_IDENT_SLEEP | \
9514 + ISL38XX_INT_IDENT_PCIUART_CTS | \
9515 + ISL38XX_INT_IDENT_PCIUART_DR)
9516 +
9517 +/* Control/Status register bits */
9518 +/* Looks like there are other meaningful bits
9519 + 0x20004400 seen in normal operation,
9520 + 0x200044db at 'timeout waiting for mgmt response'
9521 +*/
9522 +#define ISL38XX_CTRL_STAT_SLEEPMODE 0x00000200
9523 +#define ISL38XX_CTRL_STAT_CLKRUN 0x00800000
9524 +#define ISL38XX_CTRL_STAT_RESET 0x10000000
9525 +#define ISL38XX_CTRL_STAT_RAMBOOT 0x20000000
9526 +#define ISL38XX_CTRL_STAT_STARTHALTED 0x40000000
9527 +#define ISL38XX_CTRL_STAT_HOST_OVERRIDE 0x80000000
9528 +
9529 +/* Some flags for the isl hardware registers controlling DMA inside the
9530 + * chip */
9531 +#define ISL38XX_DMA_STATUS_DONE 0x00000001
9532 +#define ISL38XX_DMA_STATUS_READY 0x00000002
9533 +#define NET2280_EPA_FIFO_PCI_ADDR 0x20000000
9534 +#define ISL38XX_DMA_MASTER_CONTROL_TRIGGER 0x00000004
9535 +
9536 +#endif /* _LINUX_ISL_38XX_H */
9537 diff -purN linux_2.6.24_org/include/linux/pm.h linux_2.6.24_olpc/include/linux/pm.h
9538 --- linux_2.6.24_org/include/linux/pm.h 2008-02-15 20:11:06.000000000 +0000
9539 +++ linux_2.6.24_olpc/include/linux/pm.h 2008-02-15 18:58:06.000000000 +0000
9540 @@ -178,6 +178,9 @@ struct dev_pm_info {
9541 unsigned can_wakeup:1;
9542 #ifdef CONFIG_PM_SLEEP
9543 unsigned should_wakeup:1;
9544 + pm_message_t prev_state;
9545 + void * saved_state;
9546 + struct device * pm_parent;
9547 struct list_head entry;
9548 #endif
9549 };
9550 diff -purN linux_2.6.24_org/include/linux/power_supply.h linux_2.6.24_olpc/include/linux/power_supply.h
9551 --- linux_2.6.24_org/include/linux/power_supply.h 2008-02-15 20:10:55.000000000 +0000
9552 +++ linux_2.6.24_olpc/include/linux/power_supply.h 2008-02-15 18:58:01.000000000 +0000
9553 @@ -98,9 +98,11 @@ enum power_supply_property {
9554 POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
9555 POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
9556 POWER_SUPPLY_PROP_TIME_TO_FULL_AVG,
9557 + POWER_SUPPLY_PROP_ACCUM_CURRENT,
9558 /* Properties of type `const char *' */
9559 POWER_SUPPLY_PROP_MODEL_NAME,
9560 POWER_SUPPLY_PROP_MANUFACTURER,
9561 + POWER_SUPPLY_PROP_SERIAL_NUMBER,
9562 };
9563
9564 enum power_supply_type {
9565 @@ -169,9 +171,10 @@ struct power_supply_info {
9566
9567 extern void power_supply_changed(struct power_supply *psy);
9568 extern int power_supply_am_i_supplied(struct power_supply *psy);
9569 +extern void power_supply_status_changed(struct power_supply *psy);
9570
9571 extern int power_supply_register(struct device *parent,
9572 - struct power_supply *psy);
9573 + struct power_supply *psy);
9574 extern void power_supply_unregister(struct power_supply *psy);
9575
9576 /* For APM emulation, think legacy userspace. */
9577 diff -purN linux_2.6.24_org/include/linux/vt_kern.h linux_2.6.24_olpc/include/linux/vt_kern.h
9578 --- linux_2.6.24_org/include/linux/vt_kern.h 2008-02-15 20:10:55.000000000 +0000
9579 +++ linux_2.6.24_olpc/include/linux/vt_kern.h 2008-02-15 18:58:02.000000000 +0000
9580 @@ -96,4 +96,23 @@ struct vt_spawn_console {
9581 };
9582 extern struct vt_spawn_console vt_spawn_con;
9583
9584 +/* A notifier list for console events */
9585 +extern struct raw_notifier_head console_notifier_list;
9586 +
9587 +/* Called when the FG console switches to KD_TEXT mode */
9588 +#define CONSOLE_EVENT_SWITCH_TEXT 0x01
9589 +
9590 +/* Called when the FG console switches to KD_GRAPHICS mode */
9591 +#define CONSOLE_EVENT_SWITCH_GRAPHICS 0x02
9592 +
9593 +static inline int console_event_register(struct notifier_block *n)
9594 +{
9595 + return raw_notifier_chain_register(&console_notifier_list, n);
9596 +}
9597 +
9598 +static inline int console_event_unregister(struct notifier_block *n)
9599 +{
9600 + return raw_notifier_chain_unregister(&console_notifier_list, n);
9601 +}
9602 +
9603 #endif /* _VT_KERN_H */
9604 diff -purN linux_2.6.24_org/include/sound/ac97_codec.h linux_2.6.24_olpc/include/sound/ac97_codec.h
9605 --- linux_2.6.24_org/include/sound/ac97_codec.h 2008-02-15 20:10:44.000000000 +0000
9606 +++ linux_2.6.24_olpc/include/sound/ac97_codec.h 2008-02-15 18:57:45.000000000 +0000
9607 @@ -281,10 +281,12 @@
9608 /* specific - Analog Devices */
9609 #define AC97_AD_TEST 0x5a /* test register */
9610 #define AC97_AD_TEST2 0x5c /* undocumented test register 2 */
9611 +#define AC97_AD_HPFD_SHIFT 12 /* High Pass Filter Disable */
9612 #define AC97_AD_CODEC_CFG 0x70 /* codec configuration */
9613 #define AC97_AD_JACK_SPDIF 0x72 /* Jack Sense & S/PDIF */
9614 #define AC97_AD_SERIAL_CFG 0x74 /* Serial Configuration */
9615 #define AC97_AD_MISC 0x76 /* Misc Control Bits */
9616 +#define AC97_AD_VREFD_SHIFT 2 /* V_REFOUT Disable (AD1888) */
9617
9618 /* specific - Cirrus Logic */
9619 #define AC97_CSR_ACMODE 0x5e /* AC Mode Register */
9620 diff -purN linux_2.6.24_org/kernel/power/console.c linux_2.6.24_olpc/kernel/power/console.c
9621 --- linux_2.6.24_org/kernel/power/console.c 2008-02-15 20:12:34.000000000 +0000
9622 +++ linux_2.6.24_olpc/kernel/power/console.c 2008-02-15 19:00:00.000000000 +0000
9623 @@ -9,7 +9,7 @@
9624 #include <linux/console.h>
9625 #include "power.h"
9626
9627 -#if defined(CONFIG_VT) && defined(CONFIG_VT_CONSOLE)
9628 +#if defined(CONFIG_VT) && defined(CONFIG_VT_CONSOLE) && !defined(CONFIG_DISABLE_SUSPEND_VT_SWITCH)
9629 #define SUSPEND_CONSOLE (MAX_NR_CONSOLES-1)
9630
9631 static int orig_fgconsole, orig_kmsg;
9632 diff -purN linux_2.6.24_org/kernel/power/Kconfig linux_2.6.24_olpc/kernel/power/Kconfig
9633 --- linux_2.6.24_org/kernel/power/Kconfig 2008-02-15 20:12:34.000000000 +0000
9634 +++ linux_2.6.24_olpc/kernel/power/Kconfig 2008-02-15 19:00:00.000000000 +0000
9635 @@ -37,9 +37,22 @@ config PM_DEBUG
9636 code. This is helpful when debugging and reporting PM bugs, like
9637 suspend support.
9638
9639 +config DISABLE_SUSPEND_VT_SWITCH
9640 + bool "Disable the console switch prior to suspend (DANGEROUS)"
9641 + depends on PM_DEBUG
9642 + default n
9643 + ---help---
9644 + This option disables the automatic switch to VT console that happens
9645 + prior to Linux going into a suspend/sleep. Your video card/framebuffer
9646 + must be able to properly restore the display (even if X is doing
9647 + something crazy!) in this scenario. This is useful for saving
9648 + precious milliseconds during suspend and resume.
9649 +
9650 + If unsure, say N.
9651 +
9652 config PM_VERBOSE
9653 bool "Verbose Power Management debugging"
9654 - depends on PM_DEBUG
9655 + depends on VT_CONSOLE && PM && EXPERIMENTAL
9656 default n
9657 ---help---
9658 This option enables verbose messages from the Power Management code.
9659 diff -purN linux_2.6.24_org/kernel/power/main.c linux_2.6.24_olpc/kernel/power/main.c
9660 --- linux_2.6.24_org/kernel/power/main.c 2008-02-15 20:12:34.000000000 +0000
9661 +++ linux_2.6.24_olpc/kernel/power/main.c 2008-02-15 19:00:00.000000000 +0000
9662 @@ -76,11 +76,13 @@ static int suspend_prepare(void)
9663 if (!suspend_ops || !suspend_ops->enter)
9664 return -EPERM;
9665
9666 +#ifndef CONFIG_OLPC_PM
9667 error = pm_notifier_call_chain(PM_SUSPEND_PREPARE);
9668 if (error)
9669 goto Finish;
9670
9671 pm_prepare_console();
9672 +#endif
9673
9674 if (freeze_processes()) {
9675 error = -EAGAIN;
9676 diff -purN linux_2.6.24_org/scripts/kconfig/conf.c linux_2.6.24_olpc/scripts/kconfig/conf.c
9677 --- linux_2.6.24_org/scripts/kconfig/conf.c 2008-02-15 20:10:15.000000000 +0000
9678 +++ linux_2.6.24_olpc/scripts/kconfig/conf.c 2008-02-15 18:57:09.000000000 +0000
9679 @@ -22,6 +22,7 @@ enum {
9680 ask_new,
9681 ask_silent,
9682 set_default,
9683 + set_silentdefault,
9684 set_yes,
9685 set_mod,
9686 set_no,
9687 @@ -64,10 +65,11 @@ static void strip(char *str)
9688
9689 static void check_stdin(void)
9690 {
9691 - if (!valid_stdin && input_mode == ask_silent) {
9692 + if (!valid_stdin && (input_mode == ask_silent ||
9693 + input_mode == set_silentdefault)) {
9694 printf(_("aborted!\n\n"));
9695 printf(_("Console input/output is redirected. "));
9696 - printf(_("Run 'make oldconfig' to update configuration.\n\n"));
9697 + printf(_("Configuration file needs to be updated.\n\n"));
9698 exit(1);
9699 }
9700 }
9701 @@ -102,6 +104,7 @@ static int conf_askvalue(struct symbol *
9702 break;
9703 case ask_new:
9704 case ask_silent:
9705 + case set_silentdefault:
9706 if (sym_has_value(sym)) {
9707 printf("%s\n", def);
9708 return 0;
9709 @@ -352,6 +355,7 @@ static int conf_choice(struct menu *menu
9710 switch (input_mode) {
9711 case ask_new:
9712 case ask_silent:
9713 + case set_silentdefault:
9714 if (!is_new) {
9715 cnt = def;
9716 printf("%d\n", cnt);
9717 @@ -424,7 +428,9 @@ static void conf(struct menu *menu)
9718
9719 switch (prop->type) {
9720 case P_MENU:
9721 - if (input_mode == ask_silent && rootEntry != menu) {
9722 + if ((input_mode == ask_silent ||
9723 + input_mode == set_silentdefault) &&
9724 + rootEntry != menu) {
9725 check_conf(menu);
9726 return;
9727 }
9728 @@ -508,6 +514,16 @@ int main(int ac, char **av)
9729 input_mode = ask_silent;
9730 valid_stdin = isatty(0) && isatty(1) && isatty(2);
9731 break;
9732 + case 'S':
9733 + input_mode = set_silentdefault;
9734 + valid_stdin = isatty(0) && isatty(1) && isatty(2);
9735 + defconfig_file = av[i++];
9736 + if (!defconfig_file) {
9737 + printf("%s: No default config file specified\n",
9738 + av[0]);
9739 + exit(1);
9740 + }
9741 + break;
9742 case 'd':
9743 input_mode = set_default;
9744 break;
9745 @@ -557,6 +573,14 @@ int main(int ac, char **av)
9746 exit(1);
9747 }
9748 break;
9749 + case set_silentdefault:
9750 + if (conf_read(defconfig_file)) {
9751 + printf("***\n"
9752 + "*** Can't find default configuration \"%s\"!\n"
9753 + "***\n", defconfig_file);
9754 + exit(1);
9755 + }
9756 + break;
9757 case ask_silent:
9758 if (stat(".config", &tmpstat)) {
9759 printf(_("***\n"
9760 @@ -597,7 +621,7 @@ int main(int ac, char **av)
9761 break;
9762 }
9763
9764 - if (input_mode != ask_silent) {
9765 + if (input_mode != ask_silent && input_mode != set_silentdefault) {
9766 rootEntry = &rootmenu;
9767 conf(&rootmenu);
9768 if (input_mode == ask_all) {
9769 @@ -610,19 +634,21 @@ int main(int ac, char **av)
9770 fprintf(stderr, _("\n*** Kernel configuration requires explicit update.\n\n"));
9771 return 1;
9772 }
9773 - } else
9774 + } else if (input_mode != set_silentdefault)
9775 goto skip_check;
9776
9777 do {
9778 conf_cnt = 0;
9779 check_conf(&rootmenu);
9780 } while (conf_cnt);
9781 - if (conf_write(NULL)) {
9782 + if (conf_write(NULL, input_mode == ask_silent ||
9783 + input_mode == set_silentdefault)) {
9784 fprintf(stderr, _("\n*** Error during writing of the kernel configuration.\n\n"));
9785 return 1;
9786 }
9787 skip_check:
9788 - if (input_mode == ask_silent && conf_write_autoconf()) {
9789 + if ((input_mode == ask_silent || input_mode == set_silentdefault) &&
9790 + conf_write_autoconf()) {
9791 fprintf(stderr, _("\n*** Error during writing of the kernel configuration.\n\n"));
9792 return 1;
9793 }
9794 diff -purN linux_2.6.24_org/scripts/kconfig/confdata.c linux_2.6.24_olpc/scripts/kconfig/confdata.c
9795 --- linux_2.6.24_org/scripts/kconfig/confdata.c 2008-02-15 20:10:15.000000000 +0000
9796 +++ linux_2.6.24_olpc/scripts/kconfig/confdata.c 2008-02-15 18:57:09.000000000 +0000
9797 @@ -393,7 +393,7 @@ int conf_read(const char *name)
9798 return 0;
9799 }
9800
9801 -int conf_write(const char *name)
9802 +int conf_write(const char *name, int quiet)
9803 {
9804 FILE *out;
9805 struct symbol *sym;
9806 @@ -548,9 +548,10 @@ int conf_write(const char *name)
9807 return 1;
9808 }
9809
9810 - printf(_("#\n"
9811 - "# configuration written to %s\n"
9812 - "#\n"), newname);
9813 + if (!quiet)
9814 + printf("#\n"
9815 + "# configuration written to %s\n"
9816 + "#\n", newname);
9817
9818 sym_set_change_count(0);
9819
9820 diff -purN linux_2.6.24_org/scripts/kconfig/gconf.c linux_2.6.24_olpc/scripts/kconfig/gconf.c
9821 --- linux_2.6.24_org/scripts/kconfig/gconf.c 2008-02-15 20:10:15.000000000 +0000
9822 +++ linux_2.6.24_olpc/scripts/kconfig/gconf.c 2008-02-15 18:57:09.000000000 +0000
9823 @@ -621,7 +621,7 @@ void on_load1_activate(GtkMenuItem * men
9824
9825 void on_save_activate(GtkMenuItem * menuitem, gpointer user_data)
9826 {
9827 - if (conf_write(NULL))
9828 + if (conf_write(NULL, 0))
9829 text_insert_msg(_("Error"), _("Unable to save configuration !"));
9830 }
9831
9832 @@ -634,7 +634,7 @@ store_filename(GtkFileSelection * file_s
9833 fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION
9834 (user_data));
9835
9836 - if (conf_write(fn))
9837 + if (conf_write(fn, 0))
9838 text_insert_msg(_("Error"), _("Unable to save configuration !"));
9839
9840 gtk_widget_destroy(GTK_WIDGET(user_data));
9841 diff -purN linux_2.6.24_org/scripts/kconfig/lkc_proto.h linux_2.6.24_olpc/scripts/kconfig/lkc_proto.h
9842 --- linux_2.6.24_org/scripts/kconfig/lkc_proto.h 2008-02-15 20:10:15.000000000 +0000
9843 +++ linux_2.6.24_olpc/scripts/kconfig/lkc_proto.h 2008-02-15 18:57:09.000000000 +0000
9844 @@ -3,7 +3,7 @@
9845 P(conf_parse,void,(const char *name));
9846 P(conf_read,int,(const char *name));
9847 P(conf_read_simple,int,(const char *name, int));
9848 -P(conf_write,int,(const char *name));
9849 +P(conf_write,int,(const char *name, int));
9850 P(conf_write_autoconf,int,(void));
9851 P(conf_get_changed,bool,(void));
9852 P(conf_set_changed_callback, void,(void (*fn)(void)));
9853 diff -purN linux_2.6.24_org/scripts/kconfig/Makefile linux_2.6.24_olpc/scripts/kconfig/Makefile
9854 --- linux_2.6.24_org/scripts/kconfig/Makefile 2008-02-15 20:10:15.000000000 +0000
9855 +++ linux_2.6.24_olpc/scripts/kconfig/Makefile 2008-02-15 18:57:09.000000000 +0000
9856 @@ -69,6 +69,9 @@ endif
9857 %_defconfig: $(obj)/conf
9858 $(Q)$< -D arch/$(SRCARCH)/configs/$@ $(Kconfig)
9859
9860 +%_silentdefconfig: $(obj)/conf
9861 + $(Q)$< -S arch/$(ARCH)/configs/$(subst _silentdefconfig,_defconfig,$@) arch/$(ARCH)/Kconfig
9862 +
9863 # Help text used by make help
9864 help:
9865 @echo ' config - Update current config utilising a line-oriented program'
9866 Binary files linux_2.6.24_org/scripts/kconfig/mconf and linux_2.6.24_olpc/scripts/kconfig/mconf differ
9867 diff -purN linux_2.6.24_org/scripts/kconfig/mconf.c linux_2.6.24_olpc/scripts/kconfig/mconf.c
9868 --- linux_2.6.24_org/scripts/kconfig/mconf.c 2008-02-15 20:10:15.000000000 +0000
9869 +++ linux_2.6.24_olpc/scripts/kconfig/mconf.c 2008-02-15 18:57:09.000000000 +0000
9870 @@ -885,7 +885,7 @@ static void conf_save(void)
9871 case 0:
9872 if (!dialog_input_result[0])
9873 return;
9874 - if (!conf_write(dialog_input_result)) {
9875 + if (!conf_write(dialog_input_result, 0)) {
9876 set_config_filename(dialog_input_result);
9877 return;
9878 }
9879 @@ -945,7 +945,7 @@ int main(int ac, char **av)
9880
9881 switch (res) {
9882 case 0:
9883 - if (conf_write(filename)) {
9884 + if (conf_write(filename, 0)) {
9885 fprintf(stderr, _("\n\n"
9886 "Error during writing of the kernel configuration.\n"
9887 "Your kernel configuration changes were NOT saved."
9888 diff -purN linux_2.6.24_org/scripts/kconfig/qconf.cc linux_2.6.24_olpc/scripts/kconfig/qconf.cc
9889 --- linux_2.6.24_org/scripts/kconfig/qconf.cc 2008-02-15 20:10:15.000000000 +0000
9890 +++ linux_2.6.24_olpc/scripts/kconfig/qconf.cc 2008-02-15 18:57:09.000000000 +0000
9891 @@ -1458,7 +1458,7 @@ void ConfigMainWindow::loadConfig(void)
9892
9893 void ConfigMainWindow::saveConfig(void)
9894 {
9895 - if (conf_write(NULL))
9896 + if (conf_write(NULL, 0))
9897 QMessageBox::information(this, "qconf", "Unable to save configuration!");
9898 }
9899
9900 @@ -1467,7 +1467,7 @@ void ConfigMainWindow::saveConfigAs(void
9901 QString s = QFileDialog::getSaveFileName(".config", NULL, this);
9902 if (s.isNull())
9903 return;
9904 - if (conf_write(QFile::encodeName(s)))
9905 + if (conf_write(QFile::encodeName(s), 0))
9906 QMessageBox::information(this, "qconf", "Unable to save configuration!");
9907 }
9908
9909 @@ -1619,7 +1619,7 @@ void ConfigMainWindow::closeEvent(QClose
9910 mb.setButtonText(QMessageBox::Cancel, "Cancel Exit");
9911 switch (mb.exec()) {
9912 case QMessageBox::Yes:
9913 - conf_write(NULL);
9914 + conf_write(NULL, 0);
9915 case QMessageBox::No:
9916 e->accept();
9917 break;
9918 diff -purN linux_2.6.24_org/sound/pci/ac97/ac97_patch.c linux_2.6.24_olpc/sound/pci/ac97/ac97_patch.c
9919 --- linux_2.6.24_org/sound/pci/ac97/ac97_patch.c 2008-02-15 20:10:24.000000000 +0000
9920 +++ linux_2.6.24_olpc/sound/pci/ac97/ac97_patch.c 2008-02-15 18:57:24.000000000 +0000
9921 @@ -2029,8 +2029,9 @@ static const struct snd_kcontrol_new snd
9922 .get = snd_ac97_ad1888_lohpsel_get,
9923 .put = snd_ac97_ad1888_lohpsel_put
9924 },
9925 - AC97_SINGLE("V_REFOUT Enable", AC97_AD_MISC, 2, 1, 1),
9926 - AC97_SINGLE("High Pass Filter Enable", AC97_AD_TEST2, 12, 1, 1),
9927 + AC97_SINGLE("V_REFOUT Enable", AC97_AD_MISC, AC97_AD_VREFD_SHIFT, 1, 1),
9928 + AC97_SINGLE("High Pass Filter Enable", AC97_AD_TEST2,
9929 + AC97_AD_HPFD_SHIFT, 1, 1),
9930 AC97_SINGLE("Spread Front to Surround and Center/LFE", AC97_AD_MISC, 7, 1, 0),
9931 {
9932 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9933 diff -purN linux_2.6.24_org/sound/pci/cs5535audio/cs5535audio.c linux_2.6.24_olpc/sound/pci/cs5535audio/cs5535audio.c
9934 --- linux_2.6.24_org/sound/pci/cs5535audio/cs5535audio.c 2008-02-15 20:10:23.000000000 +0000
9935 +++ linux_2.6.24_olpc/sound/pci/cs5535audio/cs5535audio.c 2008-02-15 18:57:23.000000000 +0000
9936 @@ -145,7 +145,7 @@ static unsigned short snd_cs5535audio_ac
9937 return snd_cs5535audio_codec_read(cs5535au, reg);
9938 }
9939
9940 -static int snd_cs5535audio_mixer(struct cs5535audio *cs5535au)
9941 +static int __devinit snd_cs5535audio_mixer(struct cs5535audio *cs5535au)
9942 {
9943 struct snd_card *card = cs5535au->card;
9944 struct snd_ac97_bus *pbus;
9945 @@ -160,10 +160,14 @@ static int snd_cs5535audio_mixer(struct
9946 return err;
9947
9948 memset(&ac97, 0, sizeof(ac97));
9949 - ac97.scaps = AC97_SCAP_AUDIO|AC97_SCAP_SKIP_MODEM;
9950 + ac97.scaps = AC97_SCAP_AUDIO | AC97_SCAP_SKIP_MODEM
9951 + | AC97_SCAP_POWER_SAVE;
9952 ac97.private_data = cs5535au;
9953 ac97.pci = cs5535au->pci;
9954
9955 + /* olpc_prequirks is dummied out if not olpc */
9956 + olpc_prequirks(card, &ac97);
9957 +
9958 if ((err = snd_ac97_mixer(pbus, &ac97, &cs5535au->ac97)) < 0) {
9959 snd_printk(KERN_ERR "mixer failed\n");
9960 return err;
9961 @@ -171,6 +175,12 @@ static int snd_cs5535audio_mixer(struct
9962
9963 snd_ac97_tune_hardware(cs5535au->ac97, ac97_quirks, ac97_quirk);
9964
9965 + /* olpc_quirks is dummied out if not olpc */
9966 + if (( err = olpc_quirks(card, cs5535au->ac97)) < 0) {
9967 + snd_printk(KERN_ERR "olpc quirks failed\n");
9968 + return err;
9969 + }
9970 +
9971 return 0;
9972 }
9973
9974 diff -purN linux_2.6.24_org/sound/pci/cs5535audio/cs5535audio.h linux_2.6.24_olpc/sound/pci/cs5535audio/cs5535audio.h
9975 --- linux_2.6.24_org/sound/pci/cs5535audio/cs5535audio.h 2008-02-15 20:10:23.000000000 +0000
9976 +++ linux_2.6.24_olpc/sound/pci/cs5535audio/cs5535audio.h 2008-02-15 18:57:23.000000000 +0000
9977 @@ -78,6 +78,7 @@ struct cs5535audio_dma {
9978 unsigned int buf_addr, buf_bytes;
9979 unsigned int period_bytes, periods;
9980 u32 saved_prd;
9981 + int pcm_open_flag;
9982 };
9983
9984 struct cs5535audio {
9985 @@ -93,8 +94,21 @@ struct cs5535audio {
9986 struct cs5535audio_dma dmas[NUM_CS5535AUDIO_DMAS];
9987 };
9988
9989 +#ifdef CONFIG_PM
9990 int snd_cs5535audio_suspend(struct pci_dev *pci, pm_message_t state);
9991 int snd_cs5535audio_resume(struct pci_dev *pci);
9992 +#endif
9993 +
9994 +#ifdef CONFIG_OLPC
9995 +void olpc_prequirks(struct snd_card *card, struct snd_ac97_template *ac97) __devinit;
9996 +int olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97) __devinit;
9997 +int olpc_ai_enable(struct snd_ac97 *ac97, u8 val);
9998 +#else
9999 +#define olpc_prequirks(arg,arg2) do {} while (0)
10000 +#define olpc_quirks(arg,arg2) (0)
10001 +#define olpc_ai_enable(a, v) (0)
10002 +#endif
10003 +
10004 int __devinit snd_cs5535audio_pcm(struct cs5535audio *cs5535audio);
10005
10006 #endif /* __SOUND_CS5535AUDIO_H */
10007 diff -purN linux_2.6.24_org/sound/pci/cs5535audio/cs5535audio_olpc.c linux_2.6.24_olpc/sound/pci/cs5535audio/cs5535audio_olpc.c
10008 --- linux_2.6.24_org/sound/pci/cs5535audio/cs5535audio_olpc.c 1970-01-01 01:00:00.000000000 +0100
10009 +++ linux_2.6.24_olpc/sound/pci/cs5535audio/cs5535audio_olpc.c 2008-02-15 18:57:23.000000000 +0000
10010 @@ -0,0 +1,110 @@
10011 +#include <sound/driver.h>
10012 +#include <sound/core.h>
10013 +#include <sound/info.h>
10014 +#include <sound/control.h>
10015 +#include <sound/ac97_codec.h>
10016 +
10017 +#include <asm/olpc.h>
10018 +#include "cs5535audio.h"
10019 +
10020 +/*
10021 + * OLPC has an additional feature on top of the regular AD1888 codec features.
10022 + * It has an Analog Input mode that is switched into (after disabling the
10023 + * High Pass Filter) via GPIO. It is only supported on B2 and later models.
10024 + */
10025 +
10026 +int olpc_ai_enable(struct snd_ac97 *ac97, u8 val)
10027 +{
10028 + int err;
10029 +
10030 + /*
10031 + * update the High Pass Filter (via AC97_AD_TEST2), and then set
10032 + * Analog Input mode through a GPIO.
10033 + */
10034 +
10035 + if (val) {
10036 + err = snd_ac97_update_bits(ac97, AC97_AD_TEST2,
10037 + 1<<AC97_AD_HPFD_SHIFT, 1<<AC97_AD_HPFD_SHIFT);
10038 + geode_gpio_set(OLPC_GPIO_MIC_AC, GPIO_OUTPUT_VAL);
10039 + }
10040 + else {
10041 + err = snd_ac97_update_bits(ac97, AC97_AD_TEST2,
10042 + 1<<AC97_AD_HPFD_SHIFT, 0);
10043 + geode_gpio_clear(OLPC_GPIO_MIC_AC, GPIO_OUTPUT_VAL);
10044 + }
10045 + if (err < 0)
10046 + snd_printk(KERN_ERR "Error updating AD_TEST2: %d\n", err);
10047 +
10048 + return err;
10049 +}
10050 +EXPORT_SYMBOL_GPL(olpc_ai_enable);
10051 +
10052 +static int snd_cs5535audio_ai_info(struct snd_kcontrol *kcontrol,
10053 + struct snd_ctl_elem_info *uinfo)
10054 +{
10055 + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
10056 + uinfo->count = 1;
10057 + uinfo->value.integer.min = 0;
10058 + uinfo->value.integer.max = 1;
10059 + return 0;
10060 +}
10061 +
10062 +static int snd_cs5535audio_ai_get(struct snd_kcontrol *kcontrol,
10063 + struct snd_ctl_elem_value *ucontrol)
10064 +{
10065 + ucontrol->value.integer.value[0] = geode_gpio_isset(OLPC_GPIO_MIC_AC,
10066 + GPIO_OUTPUT_VAL);
10067 + return 0;
10068 +}
10069 +
10070 +static int snd_cs5535audio_ai_put(struct snd_kcontrol *kcontrol,
10071 + struct snd_ctl_elem_value *ucontrol)
10072 +{
10073 + struct cs5535audio *cs5535au = snd_kcontrol_chip(kcontrol);
10074 + struct snd_ac97 *ac97 = cs5535au->ac97;
10075 +
10076 + olpc_ai_enable(ac97, ucontrol->value.integer.value[0]);
10077 +
10078 + return 1;
10079 +}
10080 +
10081 +static struct snd_kcontrol_new snd_cs5535audio_controls __devinitdata =
10082 +{
10083 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10084 + .name = "DC Mode Enable",
10085 + .info = snd_cs5535audio_ai_info,
10086 + .get = snd_cs5535audio_ai_get,
10087 + .put = snd_cs5535audio_ai_put,
10088 + .private_value = 0
10089 +};
10090 +
10091 +void __devinit olpc_prequirks(struct snd_card *card,
10092 + struct snd_ac97_template *ac97)
10093 +{
10094 + /* Bail if this isn't an OLPC platform */
10095 + if (!machine_is_olpc())
10096 + return;
10097 +
10098 + /* If on an OLPC B3 or higher, invert EAPD. */
10099 + if (olpc_board_at_least(olpc_board_pre(0xb3)))
10100 + ac97->scaps |= AC97_SCAP_INV_EAPD;
10101 +}
10102 +
10103 +int __devinit olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97)
10104 +{
10105 + struct snd_ctl_elem_id elem;
10106 +
10107 + /* Bail if this isn't an OLPC platform */
10108 + if (!machine_is_olpc())
10109 + return 0;
10110 +
10111 + /* drop the original ad1888 HPF control */
10112 + memset(&elem, 0, sizeof(elem));
10113 + elem.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
10114 + strcpy(elem.name, "High Pass Filter Enable");
10115 + snd_ctl_remove_id(card, &elem);
10116 +
10117 + /* add the override for OLPC's HPF */
10118 + return snd_ctl_add(card, snd_ctl_new1(&snd_cs5535audio_controls,
10119 + ac97->private_data));
10120 +}
10121 diff -purN linux_2.6.24_org/sound/pci/cs5535audio/cs5535audio_pcm.c linux_2.6.24_olpc/sound/pci/cs5535audio/cs5535audio_pcm.c
10122 --- linux_2.6.24_org/sound/pci/cs5535audio/cs5535audio_pcm.c 2008-02-15 20:10:23.000000000 +0000
10123 +++ linux_2.6.24_olpc/sound/pci/cs5535audio/cs5535audio_pcm.c 2008-02-15 18:57:23.000000000 +0000
10124 @@ -259,6 +259,9 @@ static int snd_cs5535audio_hw_params(str
10125 err = cs5535audio_build_dma_packets(cs5535au, dma, substream,
10126 params_periods(hw_params),
10127 params_period_bytes(hw_params));
10128 + if (!err)
10129 + dma->pcm_open_flag = 1;
10130 +
10131 return err;
10132 }
10133
10134 @@ -267,6 +270,15 @@ static int snd_cs5535audio_hw_free(struc
10135 struct cs5535audio *cs5535au = snd_pcm_substream_chip(substream);
10136 struct cs5535audio_dma *dma = substream->runtime->private_data;
10137
10138 + if (dma->pcm_open_flag) {
10139 + if (substream == cs5535au->playback_substream)
10140 + snd_ac97_update_power(cs5535au->ac97,
10141 + AC97_PCM_FRONT_DAC_RATE, 0);
10142 + else
10143 + snd_ac97_update_power(cs5535au->ac97,
10144 + AC97_PCM_LR_ADC_RATE, 0);
10145 + dma->pcm_open_flag = 0;
10146 + }
10147 cs5535audio_clear_dma_packets(cs5535au, dma, substream);
10148 return snd_pcm_lib_free_pages(substream);
10149 }
10150 @@ -341,6 +353,7 @@ static int snd_cs5535audio_capture_open(
10151 int err;
10152 struct cs5535audio *cs5535au = snd_pcm_substream_chip(substream);
10153 struct snd_pcm_runtime *runtime = substream->runtime;
10154 + struct snd_ac97 *ac97 = cs5535au->ac97;
10155
10156 runtime->hw = snd_cs5535audio_capture;
10157 cs5535au->capture_substream = substream;
10158 @@ -348,11 +361,29 @@ static int snd_cs5535audio_capture_open(
10159 if ((err = snd_pcm_hw_constraint_integer(runtime,
10160 SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
10161 return err;
10162 - return 0;
10163 +
10164 +#ifdef CONFIG_OLPC
10165 + /* Disable Analog Input */
10166 + olpc_ai_enable(ac97, 0);
10167 + /* Enable V_ref bias while recording. */
10168 + snd_ac97_update_bits(ac97, AC97_AD_MISC, 1<<AC97_AD_VREFD_SHIFT, 0);
10169 +#endif
10170 + return err;
10171 }
10172
10173 static int snd_cs5535audio_capture_close(struct snd_pcm_substream *substream)
10174 {
10175 +#ifdef CONFIG_OLPC
10176 + struct cs5535audio *cs5535au = snd_pcm_substream_chip(substream);
10177 + struct snd_ac97 *ac97 = cs5535au->ac97;
10178 +
10179 + /* Disable Analog Input */
10180 + olpc_ai_enable(ac97, 0);
10181 + /* Disable V_ref bias. */
10182 + snd_ac97_update_bits(ac97, AC97_AD_MISC, 1<<AC97_AD_VREFD_SHIFT,
10183 + 1<<AC97_AD_VREFD_SHIFT);
10184 +#endif
10185 +
10186 return 0;
10187 }
10188
10189 diff -purN linux_2.6.24_org/sound/pci/cs5535audio/Makefile linux_2.6.24_olpc/sound/pci/cs5535audio/Makefile
10190 --- linux_2.6.24_org/sound/pci/cs5535audio/Makefile 2008-02-15 20:10:23.000000000 +0000
10191 +++ linux_2.6.24_olpc/sound/pci/cs5535audio/Makefile 2008-02-15 18:57:23.000000000 +0000
10192 @@ -5,5 +5,9 @@
10193 snd-cs5535audio-y := cs5535audio.o cs5535audio_pcm.o
10194 snd-cs5535audio-$(CONFIG_PM) += cs5535audio_pm.o
10195
10196 +ifdef CONFIG_OLPC
10197 +snd-cs5535audio-objs += cs5535audio_olpc.o
10198 +endif
10199 +
10200 # Toplevel Module Dependency
10201 obj-$(CONFIG_SND_CS5535AUDIO) += snd-cs5535audio.o
This page took 0.656381 seconds and 5 git commands to generate.