1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Low-level PCI config space access for OLPC systems who lack the VSA |
4 | * PCI virtualization software. |
5 | * |
6 | * Copyright © 2006 Advanced Micro Devices, Inc. |
7 | * |
8 | * The AMD Geode chipset (ie: GX2 processor, cs5536 I/O companion device) |
9 | * has some I/O functions (display, southbridge, sound, USB HCIs, etc) |
10 | * that more or less behave like PCI devices, but the hardware doesn't |
11 | * directly implement the PCI configuration space headers. AMD provides |
12 | * "VSA" (Virtual System Architecture) software that emulates PCI config |
13 | * space for these devices, by trapping I/O accesses to PCI config register |
14 | * (CF8/CFC) and running some code in System Management Mode interrupt state. |
15 | * On the OLPC platform, we don't want to use that VSA code because |
16 | * (a) it slows down suspend/resume, and (b) recompiling it requires special |
17 | * compilers that are hard to get. So instead of letting the complex VSA |
18 | * code simulate the PCI config registers for the on-chip devices, we |
19 | * just simulate them the easy way, by inserting the code into the |
20 | * pci_write_config and pci_read_config path. Most of the config registers |
21 | * are read-only anyway, so the bulk of the simulation is just table lookup. |
22 | */ |
23 | |
24 | #include <linux/pci.h> |
25 | #include <linux/init.h> |
26 | #include <asm/olpc.h> |
27 | #include <asm/geode.h> |
28 | #include <asm/pci_x86.h> |
29 | |
30 | /* |
31 | * In the tables below, the first two line (8 longwords) are the |
32 | * size masks that are used when the higher level PCI code determines |
33 | * the size of the region by writing ~0 to a base address register |
34 | * and reading back the result. |
35 | * |
36 | * The following lines are the values that are read during normal |
37 | * PCI config access cycles, i.e. not after just having written |
38 | * ~0 to a base address register. |
39 | */ |
40 | |
41 | static const uint32_t lxnb_hdr[] = { /* dev 1 function 0 - devfn = 8 */ |
42 | 0x0, 0x0, 0x0, 0x0, |
43 | 0x0, 0x0, 0x0, 0x0, |
44 | |
45 | 0x281022, 0x2200005, 0x6000021, 0x80f808, /* AMD Vendor ID */ |
46 | 0x0, 0x0, 0x0, 0x0, /* No virtual registers, hence no BAR */ |
47 | 0x0, 0x0, 0x0, 0x28100b, |
48 | 0x0, 0x0, 0x0, 0x0, |
49 | 0x0, 0x0, 0x0, 0x0, |
50 | 0x0, 0x0, 0x0, 0x0, |
51 | 0x0, 0x0, 0x0, 0x0, |
52 | }; |
53 | |
54 | static const uint32_t gxnb_hdr[] = { /* dev 1 function 0 - devfn = 8 */ |
55 | 0xfffffffd, 0x0, 0x0, 0x0, |
56 | 0x0, 0x0, 0x0, 0x0, |
57 | |
58 | 0x28100b, 0x2200005, 0x6000021, 0x80f808, /* NSC Vendor ID */ |
59 | 0xac1d, 0x0, 0x0, 0x0, /* I/O BAR - base of virtual registers */ |
60 | 0x0, 0x0, 0x0, 0x28100b, |
61 | 0x0, 0x0, 0x0, 0x0, |
62 | 0x0, 0x0, 0x0, 0x0, |
63 | 0x0, 0x0, 0x0, 0x0, |
64 | 0x0, 0x0, 0x0, 0x0, |
65 | }; |
66 | |
67 | static const uint32_t lxfb_hdr[] = { /* dev 1 function 1 - devfn = 9 */ |
68 | 0xff000008, 0xffffc000, 0xffffc000, 0xffffc000, |
69 | 0xffffc000, 0x0, 0x0, 0x0, |
70 | |
71 | 0x20811022, 0x2200003, 0x3000000, 0x0, /* AMD Vendor ID */ |
72 | 0xfd000000, 0xfe000000, 0xfe004000, 0xfe008000, /* FB, GP, VG, DF */ |
73 | 0xfe00c000, 0x0, 0x0, 0x30100b, /* VIP */ |
74 | 0x0, 0x0, 0x0, 0x10e, /* INTA, IRQ14 for graphics accel */ |
75 | 0x0, 0x0, 0x0, 0x0, |
76 | 0x3d0, 0x3c0, 0xa0000, 0x0, /* VG IO, VG IO, EGA FB, MONO FB */ |
77 | 0x0, 0x0, 0x0, 0x0, |
78 | }; |
79 | |
80 | static const uint32_t gxfb_hdr[] = { /* dev 1 function 1 - devfn = 9 */ |
81 | 0xff800008, 0xffffc000, 0xffffc000, 0xffffc000, |
82 | 0x0, 0x0, 0x0, 0x0, |
83 | |
84 | 0x30100b, 0x2200003, 0x3000000, 0x0, /* NSC Vendor ID */ |
85 | 0xfd000000, 0xfe000000, 0xfe004000, 0xfe008000, /* FB, GP, VG, DF */ |
86 | 0x0, 0x0, 0x0, 0x30100b, |
87 | 0x0, 0x0, 0x0, 0x0, |
88 | 0x0, 0x0, 0x0, 0x0, |
89 | 0x3d0, 0x3c0, 0xa0000, 0x0, /* VG IO, VG IO, EGA FB, MONO FB */ |
90 | 0x0, 0x0, 0x0, 0x0, |
91 | }; |
92 | |
93 | static const uint32_t aes_hdr[] = { /* dev 1 function 2 - devfn = 0xa */ |
94 | 0xffffc000, 0x0, 0x0, 0x0, |
95 | 0x0, 0x0, 0x0, 0x0, |
96 | |
97 | 0x20821022, 0x2a00006, 0x10100000, 0x8, /* NSC Vendor ID */ |
98 | 0xfe010000, 0x0, 0x0, 0x0, /* AES registers */ |
99 | 0x0, 0x0, 0x0, 0x20821022, |
100 | 0x0, 0x0, 0x0, 0x0, |
101 | 0x0, 0x0, 0x0, 0x0, |
102 | 0x0, 0x0, 0x0, 0x0, |
103 | 0x0, 0x0, 0x0, 0x0, |
104 | }; |
105 | |
106 | |
107 | static const uint32_t isa_hdr[] = { /* dev f function 0 - devfn = 78 */ |
108 | 0xfffffff9, 0xffffff01, 0xffffffc1, 0xffffffe1, |
109 | 0xffffff81, 0xffffffc1, 0x0, 0x0, |
110 | |
111 | 0x20901022, 0x2a00049, 0x6010003, 0x802000, |
112 | 0x18b1, 0x1001, 0x1801, 0x1881, /* SMB-8 GPIO-256 MFGPT-64 IRQ-32 */ |
113 | 0x1401, 0x1841, 0x0, 0x20901022, /* PMS-128 ACPI-64 */ |
114 | 0x0, 0x0, 0x0, 0x0, |
115 | 0x0, 0x0, 0x0, 0x0, |
116 | 0x0, 0x0, 0x0, 0xaa5b, /* IRQ steering */ |
117 | 0x0, 0x0, 0x0, 0x0, |
118 | }; |
119 | |
120 | static const uint32_t ac97_hdr[] = { /* dev f function 3 - devfn = 7b */ |
121 | 0xffffff81, 0x0, 0x0, 0x0, |
122 | 0x0, 0x0, 0x0, 0x0, |
123 | |
124 | 0x20931022, 0x2a00041, 0x4010001, 0x0, |
125 | 0x1481, 0x0, 0x0, 0x0, /* I/O BAR-128 */ |
126 | 0x0, 0x0, 0x0, 0x20931022, |
127 | 0x0, 0x0, 0x0, 0x205, /* IntB, IRQ5 */ |
128 | 0x0, 0x0, 0x0, 0x0, |
129 | 0x0, 0x0, 0x0, 0x0, |
130 | 0x0, 0x0, 0x0, 0x0, |
131 | }; |
132 | |
133 | static const uint32_t ohci_hdr[] = { /* dev f function 4 - devfn = 7c */ |
134 | 0xfffff000, 0x0, 0x0, 0x0, |
135 | 0x0, 0x0, 0x0, 0x0, |
136 | |
137 | 0x20941022, 0x2300006, 0xc031002, 0x0, |
138 | 0xfe01a000, 0x0, 0x0, 0x0, /* MEMBAR-1000 */ |
139 | 0x0, 0x0, 0x0, 0x20941022, |
140 | 0x0, 0x40, 0x0, 0x40a, /* CapPtr INT-D, IRQA */ |
141 | 0xc8020001, 0x0, 0x0, 0x0, /* Capabilities - 40 is R/O, |
142 | 44 is mask 8103 (power control) */ |
143 | 0x0, 0x0, 0x0, 0x0, |
144 | 0x0, 0x0, 0x0, 0x0, |
145 | }; |
146 | |
147 | static const uint32_t ehci_hdr[] = { /* dev f function 4 - devfn = 7d */ |
148 | 0xfffff000, 0x0, 0x0, 0x0, |
149 | 0x0, 0x0, 0x0, 0x0, |
150 | |
151 | 0x20951022, 0x2300006, 0xc032002, 0x0, |
152 | 0xfe01b000, 0x0, 0x0, 0x0, /* MEMBAR-1000 */ |
153 | 0x0, 0x0, 0x0, 0x20951022, |
154 | 0x0, 0x40, 0x0, 0x40a, /* CapPtr INT-D, IRQA */ |
155 | 0xc8020001, 0x0, 0x0, 0x0, /* Capabilities - 40 is R/O, 44 is |
156 | mask 8103 (power control) */ |
157 | #if 0 |
158 | 0x1, 0x40080000, 0x0, 0x0, /* EECP - see EHCI spec section 2.1.7 */ |
159 | #endif |
160 | 0x01000001, 0x0, 0x0, 0x0, /* EECP - see EHCI spec section 2.1.7 */ |
161 | 0x2020, 0x0, 0x0, 0x0, /* (EHCI page 8) 60 SBRN (R/O), |
162 | 61 FLADJ (R/W), PORTWAKECAP */ |
163 | }; |
164 | |
165 | static uint32_t ff_loc = ~0; |
166 | static uint32_t zero_loc; |
167 | static int bar_probing; /* Set after a write of ~0 to a BAR */ |
168 | static int is_lx; |
169 | |
170 | #define NB_SLOT 0x1 /* Northbridge - GX chip - Device 1 */ |
171 | #define SB_SLOT 0xf /* Southbridge - CS5536 chip - Device F */ |
172 | |
173 | static int is_simulated(unsigned int bus, unsigned int devfn) |
174 | { |
175 | return (!bus && ((PCI_SLOT(devfn) == NB_SLOT) || |
176 | (PCI_SLOT(devfn) == SB_SLOT))); |
177 | } |
178 | |
179 | static uint32_t *hdr_addr(const uint32_t *hdr, int reg) |
180 | { |
181 | uint32_t addr; |
182 | |
183 | /* |
184 | * This is a little bit tricky. The header maps consist of |
185 | * 0x20 bytes of size masks, followed by 0x70 bytes of header data. |
186 | * In the normal case, when not probing a BAR's size, we want |
187 | * to access the header data, so we add 0x20 to the reg offset, |
188 | * thus skipping the size mask area. |
189 | * In the BAR probing case, we want to access the size mask for |
190 | * the BAR, so we subtract 0x10 (the config header offset for |
191 | * BAR0), and don't skip the size mask area. |
192 | */ |
193 | |
194 | addr = (uint32_t)hdr + reg + (bar_probing ? -0x10 : 0x20); |
195 | |
196 | bar_probing = 0; |
197 | return (uint32_t *)addr; |
198 | } |
199 | |
200 | static int pci_olpc_read(unsigned int seg, unsigned int bus, |
201 | unsigned int devfn, int reg, int len, uint32_t *value) |
202 | { |
203 | uint32_t *addr; |
204 | |
205 | WARN_ON(seg); |
206 | |
207 | /* Use the hardware mechanism for non-simulated devices */ |
208 | if (!is_simulated(bus, devfn)) |
209 | return pci_direct_conf1.read(seg, bus, devfn, reg, len, value); |
210 | |
211 | /* |
212 | * No device has config registers past 0x70, so we save table space |
213 | * by not storing entries for the nonexistent registers |
214 | */ |
215 | if (reg >= 0x70) |
216 | addr = &zero_loc; |
217 | else { |
218 | switch (devfn) { |
219 | case 0x8: |
220 | addr = hdr_addr(hdr: is_lx ? lxnb_hdr : gxnb_hdr, reg); |
221 | break; |
222 | case 0x9: |
223 | addr = hdr_addr(hdr: is_lx ? lxfb_hdr : gxfb_hdr, reg); |
224 | break; |
225 | case 0xa: |
226 | addr = is_lx ? hdr_addr(hdr: aes_hdr, reg) : &ff_loc; |
227 | break; |
228 | case 0x78: |
229 | addr = hdr_addr(hdr: isa_hdr, reg); |
230 | break; |
231 | case 0x7b: |
232 | addr = hdr_addr(hdr: ac97_hdr, reg); |
233 | break; |
234 | case 0x7c: |
235 | addr = hdr_addr(hdr: ohci_hdr, reg); |
236 | break; |
237 | case 0x7d: |
238 | addr = hdr_addr(hdr: ehci_hdr, reg); |
239 | break; |
240 | default: |
241 | addr = &ff_loc; |
242 | break; |
243 | } |
244 | } |
245 | switch (len) { |
246 | case 1: |
247 | *value = *(uint8_t *)addr; |
248 | break; |
249 | case 2: |
250 | *value = *(uint16_t *)addr; |
251 | break; |
252 | case 4: |
253 | *value = *addr; |
254 | break; |
255 | default: |
256 | BUG(); |
257 | } |
258 | |
259 | return 0; |
260 | } |
261 | |
262 | static int pci_olpc_write(unsigned int seg, unsigned int bus, |
263 | unsigned int devfn, int reg, int len, uint32_t value) |
264 | { |
265 | WARN_ON(seg); |
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 | |
300 | static const struct pci_raw_ops pci_olpc_conf = { |
301 | .read = pci_olpc_read, |
302 | .write = pci_olpc_write, |
303 | }; |
304 | |
305 | int __init pci_olpc_init(void) |
306 | { |
307 | printk(KERN_INFO "PCI: Using configuration type OLPC XO-1\n" ); |
308 | raw_pci_ops = &pci_olpc_conf; |
309 | is_lx = is_geode_lx(); |
310 | return 0; |
311 | } |
312 | |