aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
diff options
context:
space:
mode:
authorAndres Salomon <dilinger@queued.net>2008-04-29 03:59:53 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-04-29 11:06:07 -0400
commit3ef0e1f8cad0a851b3dbf91802b14af7dd780352 (patch)
tree805450fdb2c056e7ba61ac3c26529cccd09e952f /arch/x86
parent2f9b12a31fcb738ea8c9eb0d4ddf906c6f1d696c (diff)
x86: olpc: add One Laptop Per Child architecture support
This adds support for OLPC XO hardware. Open Firmware on XOs don't contain the VSA, so it is necessary to emulate the PCI BARs in the kernel. This also adds functionality for running EC commands, and a CONFIG_OLPC. A number of OLPC drivers depend upon CONFIG_OLPC. olpc_ec_timeout is a hack to work around Embedded Controller bugs. [akpm@linux-foundation.org: build fix] [akpm@linux-foundation.org: geode_has_vsa build fix] [akpm@linux-foundation.org: olpc_register_battery_callback doesn't exist] Signed-off-by: Andres Salomon <dilinger@debian.org> Acked-by: Ingo Molnar <mingo@elte.hu> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Andi Kleen <ak@suse.de> Cc: Jordan Crouse <jordan.crouse@amd.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/x86')
-rw-r--r--arch/x86/Kconfig18
-rw-r--r--arch/x86/kernel/Makefile2
-rw-r--r--arch/x86/kernel/olpc.c260
-rw-r--r--arch/x86/pci/Makefile_321
-rw-r--r--arch/x86/pci/init.c3
-rw-r--r--arch/x86/pci/olpc.c313
-rw-r--r--arch/x86/pci/pci.h1
7 files changed, 597 insertions, 1 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 1d9d874cba59..f70e3e3a9fa7 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -1504,6 +1504,10 @@ config PCI_GODIRECT
1504config PCI_GOANY 1504config PCI_GOANY
1505 bool "Any" 1505 bool "Any"
1506 1506
1507config PCI_GOOLPC
1508 bool "OLPC"
1509 depends on OLPC
1510
1507endchoice 1511endchoice
1508 1512
1509config PCI_BIOS 1513config PCI_BIOS
@@ -1513,12 +1517,17 @@ config PCI_BIOS
1513# x86-64 doesn't support PCI BIOS access from long mode so always go direct. 1517# x86-64 doesn't support PCI BIOS access from long mode so always go direct.
1514config PCI_DIRECT 1518config PCI_DIRECT
1515 def_bool y 1519 def_bool y
1516 depends on PCI && (X86_64 || (PCI_GODIRECT || PCI_GOANY) || X86_VISWS) 1520 depends on PCI && (X86_64 || (PCI_GODIRECT || PCI_GOANY || PCI_GOOLPC) || X86_VISWS)
1517 1521
1518config PCI_MMCONFIG 1522config PCI_MMCONFIG
1519 def_bool y 1523 def_bool y
1520 depends on X86_32 && PCI && ACPI && (PCI_GOMMCONFIG || PCI_GOANY) 1524 depends on X86_32 && PCI && ACPI && (PCI_GOMMCONFIG || PCI_GOANY)
1521 1525
1526config PCI_OLPC
1527 bool
1528 depends on PCI && PCI_GOOLPC
1529 default y
1530
1522config PCI_DOMAINS 1531config PCI_DOMAINS
1523 def_bool y 1532 def_bool y
1524 depends on PCI 1533 depends on PCI
@@ -1638,6 +1647,13 @@ config GEODE_MFGPT_TIMER
1638 MFGPTs have a better resolution and max interval than the 1647 MFGPTs have a better resolution and max interval than the
1639 generic PIT, and are suitable for use as high-res timers. 1648 generic PIT, and are suitable for use as high-res timers.
1640 1649
1650config OLPC
1651 bool "One Laptop Per Child support"
1652 default n
1653 help
1654 Add support for detecting the unique features of the OLPC
1655 XO hardware.
1656
1641endif # X86_32 1657endif # X86_32
1642 1658
1643config K8_NB 1659config K8_NB
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index fa19c3819540..350eb1b2a208 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -91,6 +91,8 @@ endif
91obj-$(CONFIG_SCx200) += scx200.o 91obj-$(CONFIG_SCx200) += scx200.o
92scx200-y += scx200_32.o 92scx200-y += scx200_32.o
93 93
94obj-$(CONFIG_OLPC) += olpc.o
95
94### 96###
95# 64 bit specific files 97# 64 bit specific files
96ifeq ($(CONFIG_X86_64),y) 98ifeq ($(CONFIG_X86_64),y)
diff --git a/arch/x86/kernel/olpc.c b/arch/x86/kernel/olpc.c
new file mode 100644
index 000000000000..3e6672274807
--- /dev/null
+++ b/arch/x86/kernel/olpc.c
@@ -0,0 +1,260 @@
1/*
2 * Support for the OLPC DCON and OLPC EC access
3 *
4 * Copyright © 2006 Advanced Micro Devices, Inc.
5 * Copyright © 2007-2008 Andres Salomon <dilinger@debian.org>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <linux/kernel.h>
14#include <linux/init.h>
15#include <linux/module.h>
16#include <linux/delay.h>
17#include <linux/spinlock.h>
18#include <linux/io.h>
19#include <linux/string.h>
20#include <asm/geode.h>
21#include <asm/olpc.h>
22
23#ifdef CONFIG_OPEN_FIRMWARE
24#include <asm/ofw.h>
25#endif
26
27struct olpc_platform_t olpc_platform_info;
28EXPORT_SYMBOL_GPL(olpc_platform_info);
29
30static DEFINE_SPINLOCK(ec_lock);
31
32/* what the timeout *should* be (in ms) */
33#define EC_BASE_TIMEOUT 20
34
35/* the timeout that bugs in the EC might force us to actually use */
36static int ec_timeout = EC_BASE_TIMEOUT;
37
38static int __init olpc_ec_timeout_set(char *str)
39{
40 if (get_option(&str, &ec_timeout) != 1) {
41 ec_timeout = EC_BASE_TIMEOUT;
42 printk(KERN_ERR "olpc-ec: invalid argument to "
43 "'olpc_ec_timeout=', ignoring!\n");
44 }
45 printk(KERN_DEBUG "olpc-ec: using %d ms delay for EC commands.\n",
46 ec_timeout);
47 return 1;
48}
49__setup("olpc_ec_timeout=", olpc_ec_timeout_set);
50
51/*
52 * These {i,o}bf_status functions return whether the buffers are full or not.
53 */
54
55static inline unsigned int ibf_status(unsigned int port)
56{
57 return !!(inb(port) & 0x02);
58}
59
60static inline unsigned int obf_status(unsigned int port)
61{
62 return inb(port) & 0x01;
63}
64
65#define wait_on_ibf(p, d) __wait_on_ibf(__LINE__, (p), (d))
66static int __wait_on_ibf(unsigned int line, unsigned int port, int desired)
67{
68 unsigned int timeo;
69 int state = ibf_status(port);
70
71 for (timeo = ec_timeout; state != desired && timeo; timeo--) {
72 mdelay(1);
73 state = ibf_status(port);
74 }
75
76 if ((state == desired) && (ec_timeout > EC_BASE_TIMEOUT) &&
77 timeo < (ec_timeout - EC_BASE_TIMEOUT)) {
78 printk(KERN_WARNING "olpc-ec: %d: waited %u ms for IBF!\n",
79 line, ec_timeout - timeo);
80 }
81
82 return !(state == desired);
83}
84
85#define wait_on_obf(p, d) __wait_on_obf(__LINE__, (p), (d))
86static int __wait_on_obf(unsigned int line, unsigned int port, int desired)
87{
88 unsigned int timeo;
89 int state = obf_status(port);
90
91 for (timeo = ec_timeout; state != desired && timeo; timeo--) {
92 mdelay(1);
93 state = obf_status(port);
94 }
95
96 if ((state == desired) && (ec_timeout > EC_BASE_TIMEOUT) &&
97 timeo < (ec_timeout - EC_BASE_TIMEOUT)) {
98 printk(KERN_WARNING "olpc-ec: %d: waited %u ms for OBF!\n",
99 line, ec_timeout - timeo);
100 }
101
102 return !(state == desired);
103}
104
105/*
106 * This allows the kernel to run Embedded Controller commands. The EC is
107 * documented at <http://wiki.laptop.org/go/Embedded_controller>, and the
108 * available EC commands are here:
109 * <http://wiki.laptop.org/go/Ec_specification>. Unfortunately, while
110 * OpenFirmware's source is available, the EC's is not.
111 */
112int olpc_ec_cmd(unsigned char cmd, unsigned char *inbuf, size_t inlen,
113 unsigned char *outbuf, size_t outlen)
114{
115 unsigned long flags;
116 int ret = -EIO;
117 int i;
118
119 spin_lock_irqsave(&ec_lock, flags);
120
121 /* Clear OBF */
122 for (i = 0; i < 10 && (obf_status(0x6c) == 1); i++)
123 inb(0x68);
124 if (i == 10) {
125 printk(KERN_ERR "olpc-ec: timeout while attempting to "
126 "clear OBF flag!\n");
127 goto err;
128 }
129
130 if (wait_on_ibf(0x6c, 0)) {
131 printk(KERN_ERR "olpc-ec: timeout waiting for EC to "
132 "quiesce!\n");
133 goto err;
134 }
135
136restart:
137 /*
138 * Note that if we time out during any IBF checks, that's a failure;
139 * we have to return. There's no way for the kernel to clear that.
140 *
141 * If we time out during an OBF check, we can restart the command;
142 * reissuing it will clear the OBF flag, and we should be alright.
143 * The OBF flag will sometimes misbehave due to what we believe
144 * is a hardware quirk..
145 */
146 printk(KERN_DEBUG "olpc-ec: running cmd 0x%x\n", cmd);
147 outb(cmd, 0x6c);
148
149 if (wait_on_ibf(0x6c, 0)) {
150 printk(KERN_ERR "olpc-ec: timeout waiting for EC to read "
151 "command!\n");
152 goto err;
153 }
154
155 if (inbuf && inlen) {
156 /* write data to EC */
157 for (i = 0; i < inlen; i++) {
158 if (wait_on_ibf(0x6c, 0)) {
159 printk(KERN_ERR "olpc-ec: timeout waiting for"
160 " EC accept data!\n");
161 goto err;
162 }
163 printk(KERN_DEBUG "olpc-ec: sending cmd arg 0x%x\n",
164 inbuf[i]);
165 outb(inbuf[i], 0x68);
166 }
167 }
168 if (outbuf && outlen) {
169 /* read data from EC */
170 for (i = 0; i < outlen; i++) {
171 if (wait_on_obf(0x6c, 1)) {
172 printk(KERN_ERR "olpc-ec: timeout waiting for"
173 " EC to provide data!\n");
174 goto restart;
175 }
176 outbuf[i] = inb(0x68);
177 printk(KERN_DEBUG "olpc-ec: received 0x%x\n",
178 outbuf[i]);
179 }
180 }
181
182 ret = 0;
183err:
184 spin_unlock_irqrestore(&ec_lock, flags);
185 return ret;
186}
187EXPORT_SYMBOL_GPL(olpc_ec_cmd);
188
189#ifdef CONFIG_OPEN_FIRMWARE
190static void __init platform_detect(void)
191{
192 size_t propsize;
193 u32 rev;
194
195 if (ofw("getprop", 4, 1, NULL, "board-revision-int", &rev, 4,
196 &propsize) || propsize != 4) {
197 printk(KERN_ERR "ofw: getprop call failed!\n");
198 rev = 0;
199 }
200 olpc_platform_info.boardrev = be32_to_cpu(rev);
201}
202#else
203static void __init platform_detect(void)
204{
205 /* stopgap until OFW support is added to the kernel */
206 olpc_platform_info.boardrev = be32_to_cpu(0xc2);
207}
208#endif
209
210static int __init olpc_init(void)
211{
212 unsigned char *romsig;
213
214 /* The ioremap check is dangerous; limit what we run it on */
215 if (!is_geode() || geode_has_vsa2())
216 return 0;
217
218 spin_lock_init(&ec_lock);
219
220 romsig = ioremap(0xffffffc0, 16);
221 if (!romsig)
222 return 0;
223
224 if (strncmp(romsig, "CL1 Q", 7))
225 goto unmap;
226 if (strncmp(romsig+6, romsig+13, 3)) {
227 printk(KERN_INFO "OLPC BIOS signature looks invalid. "
228 "Assuming not OLPC\n");
229 goto unmap;
230 }
231
232 printk(KERN_INFO "OLPC board with OpenFirmware %.16s\n", romsig);
233 olpc_platform_info.flags |= OLPC_F_PRESENT;
234
235 /* get the platform revision */
236 platform_detect();
237
238 /* assume B1 and above models always have a DCON */
239 if (olpc_board_at_least(olpc_board(0xb1)))
240 olpc_platform_info.flags |= OLPC_F_DCON;
241
242 /* get the EC revision */
243 olpc_ec_cmd(EC_FIRMWARE_REV, NULL, 0,
244 (unsigned char *) &olpc_platform_info.ecver, 1);
245
246 /* check to see if the VSA exists */
247 if (geode_has_vsa2())
248 olpc_platform_info.flags |= OLPC_F_VSA;
249
250 printk(KERN_INFO "OLPC board revision %s%X (EC=%x)\n",
251 ((olpc_platform_info.boardrev & 0xf) < 8) ? "pre" : "",
252 olpc_platform_info.boardrev >> 4,
253 olpc_platform_info.ecver);
254
255unmap:
256 iounmap(romsig);
257 return 0;
258}
259
260postcore_initcall(olpc_init);
diff --git a/arch/x86/pci/Makefile_32 b/arch/x86/pci/Makefile_32
index cdd6828b5abb..b859047a6376 100644
--- a/arch/x86/pci/Makefile_32
+++ b/arch/x86/pci/Makefile_32
@@ -3,6 +3,7 @@ obj-y := i386.o init.o
3obj-$(CONFIG_PCI_BIOS) += pcbios.o 3obj-$(CONFIG_PCI_BIOS) += pcbios.o
4obj-$(CONFIG_PCI_MMCONFIG) += mmconfig_32.o direct.o mmconfig-shared.o 4obj-$(CONFIG_PCI_MMCONFIG) += mmconfig_32.o direct.o mmconfig-shared.o
5obj-$(CONFIG_PCI_DIRECT) += direct.o 5obj-$(CONFIG_PCI_DIRECT) += direct.o
6obj-$(CONFIG_PCI_OLPC) += olpc.o
6 7
7pci-y := fixup.o 8pci-y := fixup.o
8pci-$(CONFIG_ACPI) += acpi.o 9pci-$(CONFIG_ACPI) += acpi.o
diff --git a/arch/x86/pci/init.c b/arch/x86/pci/init.c
index 3de9f9ba2da6..0f5f7dd2a620 100644
--- a/arch/x86/pci/init.c
+++ b/arch/x86/pci/init.c
@@ -14,6 +14,9 @@ static __init int pci_access_init(void)
14#ifdef CONFIG_PCI_MMCONFIG 14#ifdef CONFIG_PCI_MMCONFIG
15 pci_mmcfg_init(type); 15 pci_mmcfg_init(type);
16#endif 16#endif
17#ifdef CONFIG_PCI_OLPC
18 pci_olpc_init();
19#endif
17 if (raw_pci_ops) 20 if (raw_pci_ops)
18 return 0; 21 return 0;
19#ifdef CONFIG_PCI_BIOS 22#ifdef CONFIG_PCI_BIOS
diff --git a/arch/x86/pci/olpc.c b/arch/x86/pci/olpc.c
new file mode 100644
index 000000000000..5e7636558c02
--- /dev/null
+++ b/arch/x86/pci/olpc.c
@@ -0,0 +1,313 @@
1/*
2 * Low-level PCI config space access for OLPC systems who lack the VSA
3 * PCI virtualization software.
4 *
5 * Copyright © 2006 Advanced Micro Devices, Inc.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * The AMD Geode chipset (ie: GX2 processor, cs5536 I/O companion device)
13 * has some I/O functions (display, southbridge, sound, USB HCIs, etc)
14 * that more or less behave like PCI devices, but the hardware doesn't
15 * directly implement the PCI configuration space headers. AMD provides
16 * "VSA" (Virtual System Architecture) software that emulates PCI config
17 * space for these devices, by trapping I/O accesses to PCI config register
18 * (CF8/CFC) and running some code in System Management Mode interrupt state.
19 * On the OLPC platform, we don't want to use that VSA code because
20 * (a) it slows down suspend/resume, and (b) recompiling it requires special
21 * compilers that are hard to get. So instead of letting the complex VSA
22 * code simulate the PCI config registers for the on-chip devices, we
23 * just simulate them the easy way, by inserting the code into the
24 * pci_write_config and pci_read_config path. Most of the config registers
25 * are read-only anyway, so the bulk of the simulation is just table lookup.
26 */
27
28#include <linux/pci.h>
29#include <linux/init.h>
30#include <asm/olpc.h>
31#include <asm/geode.h>
32#include "pci.h"
33
34/*
35 * In the tables below, the first two line (8 longwords) are the
36 * size masks that are used when the higher level PCI code determines
37 * the size of the region by writing ~0 to a base address register
38 * and reading back the result.
39 *
40 * The following lines are the values that are read during normal
41 * PCI config access cycles, i.e. not after just having written
42 * ~0 to a base address register.
43 */
44
45static const uint32_t lxnb_hdr[] = { /* dev 1 function 0 - devfn = 8 */
46 0x0, 0x0, 0x0, 0x0,
47 0x0, 0x0, 0x0, 0x0,
48
49 0x281022, 0x2200005, 0x6000021, 0x80f808, /* AMD Vendor ID */
50 0x0, 0x0, 0x0, 0x0, /* No virtual registers, hence no BAR */
51 0x0, 0x0, 0x0, 0x28100b,
52 0x0, 0x0, 0x0, 0x0,
53 0x0, 0x0, 0x0, 0x0,
54 0x0, 0x0, 0x0, 0x0,
55 0x0, 0x0, 0x0, 0x0,
56};
57
58static const uint32_t gxnb_hdr[] = { /* dev 1 function 0 - devfn = 8 */
59 0xfffffffd, 0x0, 0x0, 0x0,
60 0x0, 0x0, 0x0, 0x0,
61
62 0x28100b, 0x2200005, 0x6000021, 0x80f808, /* NSC Vendor ID */
63 0xac1d, 0x0, 0x0, 0x0, /* I/O BAR - base of virtual registers */
64 0x0, 0x0, 0x0, 0x28100b,
65 0x0, 0x0, 0x0, 0x0,
66 0x0, 0x0, 0x0, 0x0,
67 0x0, 0x0, 0x0, 0x0,
68 0x0, 0x0, 0x0, 0x0,
69};
70
71static const uint32_t lxfb_hdr[] = { /* dev 1 function 1 - devfn = 9 */
72 0xff000008, 0xffffc000, 0xffffc000, 0xffffc000,
73 0xffffc000, 0x0, 0x0, 0x0,
74
75 0x20811022, 0x2200003, 0x3000000, 0x0, /* AMD Vendor ID */
76 0xfd000000, 0xfe000000, 0xfe004000, 0xfe008000, /* FB, GP, VG, DF */
77 0xfe00c000, 0x0, 0x0, 0x30100b, /* VIP */
78 0x0, 0x0, 0x0, 0x10e, /* INTA, IRQ14 for graphics accel */
79 0x0, 0x0, 0x0, 0x0,
80 0x3d0, 0x3c0, 0xa0000, 0x0, /* VG IO, VG IO, EGA FB, MONO FB */
81 0x0, 0x0, 0x0, 0x0,
82};
83
84static const uint32_t gxfb_hdr[] = { /* dev 1 function 1 - devfn = 9 */
85 0xff800008, 0xffffc000, 0xffffc000, 0xffffc000,
86 0x0, 0x0, 0x0, 0x0,
87
88 0x30100b, 0x2200003, 0x3000000, 0x0, /* NSC Vendor ID */
89 0xfd000000, 0xfe000000, 0xfe004000, 0xfe008000, /* FB, GP, VG, DF */
90 0x0, 0x0, 0x0, 0x30100b,
91 0x0, 0x0, 0x0, 0x0,
92 0x0, 0x0, 0x0, 0x0,
93 0x3d0, 0x3c0, 0xa0000, 0x0, /* VG IO, VG IO, EGA FB, MONO FB */
94 0x0, 0x0, 0x0, 0x0,
95};
96
97static const uint32_t aes_hdr[] = { /* dev 1 function 2 - devfn = 0xa */
98 0xffffc000, 0x0, 0x0, 0x0,
99 0x0, 0x0, 0x0, 0x0,
100
101 0x20821022, 0x2a00006, 0x10100000, 0x8, /* NSC Vendor ID */
102 0xfe010000, 0x0, 0x0, 0x0, /* AES registers */
103 0x0, 0x0, 0x0, 0x20821022,
104 0x0, 0x0, 0x0, 0x0,
105 0x0, 0x0, 0x0, 0x0,
106 0x0, 0x0, 0x0, 0x0,
107 0x0, 0x0, 0x0, 0x0,
108};
109
110
111static const uint32_t isa_hdr[] = { /* dev f function 0 - devfn = 78 */
112 0xfffffff9, 0xffffff01, 0xffffffc1, 0xffffffe1,
113 0xffffff81, 0xffffffc1, 0x0, 0x0,
114
115 0x20901022, 0x2a00049, 0x6010003, 0x802000,
116 0x18b1, 0x1001, 0x1801, 0x1881, /* SMB-8 GPIO-256 MFGPT-64 IRQ-32 */
117 0x1401, 0x1841, 0x0, 0x20901022, /* PMS-128 ACPI-64 */
118 0x0, 0x0, 0x0, 0x0,
119 0x0, 0x0, 0x0, 0x0,
120 0x0, 0x0, 0x0, 0xaa5b, /* IRQ steering */
121 0x0, 0x0, 0x0, 0x0,
122};
123
124static const uint32_t ac97_hdr[] = { /* dev f function 3 - devfn = 7b */
125 0xffffff81, 0x0, 0x0, 0x0,
126 0x0, 0x0, 0x0, 0x0,
127
128 0x20931022, 0x2a00041, 0x4010001, 0x0,
129 0x1481, 0x0, 0x0, 0x0, /* I/O BAR-128 */
130 0x0, 0x0, 0x0, 0x20931022,
131 0x0, 0x0, 0x0, 0x205, /* IntB, IRQ5 */
132 0x0, 0x0, 0x0, 0x0,
133 0x0, 0x0, 0x0, 0x0,
134 0x0, 0x0, 0x0, 0x0,
135};
136
137static const uint32_t ohci_hdr[] = { /* dev f function 4 - devfn = 7c */
138 0xfffff000, 0x0, 0x0, 0x0,
139 0x0, 0x0, 0x0, 0x0,
140
141 0x20941022, 0x2300006, 0xc031002, 0x0,
142 0xfe01a000, 0x0, 0x0, 0x0, /* MEMBAR-1000 */
143 0x0, 0x0, 0x0, 0x20941022,
144 0x0, 0x40, 0x0, 0x40a, /* CapPtr INT-D, IRQA */
145 0xc8020001, 0x0, 0x0, 0x0, /* Capabilities - 40 is R/O,
146 44 is mask 8103 (power control) */
147 0x0, 0x0, 0x0, 0x0,
148 0x0, 0x0, 0x0, 0x0,
149};
150
151static const uint32_t ehci_hdr[] = { /* dev f function 4 - devfn = 7d */
152 0xfffff000, 0x0, 0x0, 0x0,
153 0x0, 0x0, 0x0, 0x0,
154
155 0x20951022, 0x2300006, 0xc032002, 0x0,
156 0xfe01b000, 0x0, 0x0, 0x0, /* MEMBAR-1000 */
157 0x0, 0x0, 0x0, 0x20951022,
158 0x0, 0x40, 0x0, 0x40a, /* CapPtr INT-D, IRQA */
159 0xc8020001, 0x0, 0x0, 0x0, /* Capabilities - 40 is R/O, 44 is
160 mask 8103 (power control) */
161#if 0
162 0x1, 0x40080000, 0x0, 0x0, /* EECP - see EHCI spec section 2.1.7 */
163#endif
164 0x01000001, 0x0, 0x0, 0x0, /* EECP - see EHCI spec section 2.1.7 */
165 0x2020, 0x0, 0x0, 0x0, /* (EHCI page 8) 60 SBRN (R/O),
166 61 FLADJ (R/W), PORTWAKECAP */
167};
168
169static uint32_t ff_loc = ~0;
170static uint32_t zero_loc;
171static int bar_probing; /* Set after a write of ~0 to a BAR */
172static int is_lx;
173
174#define NB_SLOT 0x1 /* Northbridge - GX chip - Device 1 */
175#define SB_SLOT 0xf /* Southbridge - CS5536 chip - Device F */
176
177static int is_simulated(unsigned int bus, unsigned int devfn)
178{
179 return (!bus && ((PCI_SLOT(devfn) == NB_SLOT) ||
180 (PCI_SLOT(devfn) == SB_SLOT)));
181}
182
183static uint32_t *hdr_addr(const uint32_t *hdr, int reg)
184{
185 uint32_t addr;
186
187 /*
188 * This is a little bit tricky. The header maps consist of
189 * 0x20 bytes of size masks, followed by 0x70 bytes of header data.
190 * In the normal case, when not probing a BAR's size, we want
191 * to access the header data, so we add 0x20 to the reg offset,
192 * thus skipping the size mask area.
193 * In the BAR probing case, we want to access the size mask for
194 * the BAR, so we subtract 0x10 (the config header offset for
195 * BAR0), and don't skip the size mask area.
196 */
197
198 addr = (uint32_t)hdr + reg + (bar_probing ? -0x10 : 0x20);
199
200 bar_probing = 0;
201 return (uint32_t *)addr;
202}
203
204static int pci_olpc_read(unsigned int seg, unsigned int bus,
205 unsigned int devfn, int reg, int len, uint32_t *value)
206{
207 uint32_t *addr;
208
209 /* Use the hardware mechanism for non-simulated devices */
210 if (!is_simulated(bus, devfn))
211 return pci_direct_conf1.read(seg, bus, devfn, reg, len, value);
212
213 /*
214 * No device has config registers past 0x70, so we save table space
215 * by not storing entries for the nonexistent registers
216 */
217 if (reg >= 0x70)
218 addr = &zero_loc;
219 else {
220 switch (devfn) {
221 case 0x8:
222 addr = hdr_addr(is_lx ? lxnb_hdr : gxnb_hdr, reg);
223 break;
224 case 0x9:
225 addr = hdr_addr(is_lx ? lxfb_hdr : gxfb_hdr, reg);
226 break;
227 case 0xa:
228 addr = is_lx ? hdr_addr(aes_hdr, reg) : &ff_loc;
229 break;
230 case 0x78:
231 addr = hdr_addr(isa_hdr, reg);
232 break;
233 case 0x7b:
234 addr = hdr_addr(ac97_hdr, reg);
235 break;
236 case 0x7c:
237 addr = hdr_addr(ohci_hdr, reg);
238 break;
239 case 0x7d:
240 addr = hdr_addr(ehci_hdr, reg);
241 break;
242 default:
243 addr = &ff_loc;
244 break;
245 }
246 }
247 switch (len) {
248 case 1:
249 *value = *(uint8_t *)addr;
250 break;
251 case 2:
252 *value = *(uint16_t *)addr;
253 break;
254 case 4:
255 *value = *addr;
256 break;
257 default:
258 BUG();
259 }
260
261 return 0;
262}
263
264static int pci_olpc_write(unsigned int seg, unsigned int bus,
265 unsigned int devfn, int reg, int len, uint32_t value)
266{
267 /* Use the hardware mechanism for non-simulated devices */
268 if (!is_simulated(bus, devfn))
269 return pci_direct_conf1.write(seg, bus, devfn, reg, len, value);
270
271 /* XXX we may want to extend this to simulate EHCI power management */
272
273 /*
274 * Mostly we just discard writes, but if the write is a size probe
275 * (i.e. writing ~0 to a BAR), we remember it and arrange to return
276 * the appropriate size mask on the next read. This is cheating
277 * to some extent, because it depends on the fact that the next
278 * access after such a write will always be a read to the same BAR.
279 */
280
281 if ((reg >= 0x10) && (reg < 0x2c)) {
282 /* write is to a BAR */
283 if (value == ~0)
284 bar_probing = 1;
285 } else {
286 /*
287 * No warning on writes to ROM BAR, CMD, LATENCY_TIMER,
288 * CACHE_LINE_SIZE, or PM registers.
289 */
290 if ((reg != PCI_ROM_ADDRESS) && (reg != PCI_COMMAND_MASTER) &&
291 (reg != PCI_LATENCY_TIMER) &&
292 (reg != PCI_CACHE_LINE_SIZE) && (reg != 0x44))
293 printk(KERN_WARNING "OLPC PCI: Config write to devfn"
294 " %x reg %x value %x\n", devfn, reg, value);
295 }
296
297 return 0;
298}
299
300static struct pci_raw_ops pci_olpc_conf = {
301 .read = pci_olpc_read,
302 .write = pci_olpc_write,
303};
304
305void __init pci_olpc_init(void)
306{
307 if (!machine_is_olpc() || olpc_has_vsa())
308 return;
309
310 printk(KERN_INFO "PCI: Using configuration type OLPC\n");
311 raw_pci_ops = &pci_olpc_conf;
312 is_lx = is_geode_lx();
313}
diff --git a/arch/x86/pci/pci.h b/arch/x86/pci/pci.h
index c4bddaeff619..7d84e813e958 100644
--- a/arch/x86/pci/pci.h
+++ b/arch/x86/pci/pci.h
@@ -98,6 +98,7 @@ extern int pci_direct_probe(void);
98extern void pci_direct_init(int type); 98extern void pci_direct_init(int type);
99extern void pci_pcbios_init(void); 99extern void pci_pcbios_init(void);
100extern void pci_mmcfg_init(int type); 100extern void pci_mmcfg_init(int type);
101extern void pci_olpc_init(void);
101 102
102/* pci-mmconfig.c */ 103/* pci-mmconfig.c */
103 104