1*2874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
23ef0e1f8SAndres Salomon /*
33ef0e1f8SAndres Salomon * Low-level PCI config space access for OLPC systems who lack the VSA
43ef0e1f8SAndres Salomon * PCI virtualization software.
53ef0e1f8SAndres Salomon *
63ef0e1f8SAndres Salomon * Copyright © 2006 Advanced Micro Devices, Inc.
73ef0e1f8SAndres Salomon *
83ef0e1f8SAndres Salomon * The AMD Geode chipset (ie: GX2 processor, cs5536 I/O companion device)
93ef0e1f8SAndres Salomon * has some I/O functions (display, southbridge, sound, USB HCIs, etc)
103ef0e1f8SAndres Salomon * that more or less behave like PCI devices, but the hardware doesn't
113ef0e1f8SAndres Salomon * directly implement the PCI configuration space headers. AMD provides
123ef0e1f8SAndres Salomon * "VSA" (Virtual System Architecture) software that emulates PCI config
133ef0e1f8SAndres Salomon * space for these devices, by trapping I/O accesses to PCI config register
143ef0e1f8SAndres Salomon * (CF8/CFC) and running some code in System Management Mode interrupt state.
153ef0e1f8SAndres Salomon * On the OLPC platform, we don't want to use that VSA code because
163ef0e1f8SAndres Salomon * (a) it slows down suspend/resume, and (b) recompiling it requires special
173ef0e1f8SAndres Salomon * compilers that are hard to get. So instead of letting the complex VSA
183ef0e1f8SAndres Salomon * code simulate the PCI config registers for the on-chip devices, we
193ef0e1f8SAndres Salomon * just simulate them the easy way, by inserting the code into the
203ef0e1f8SAndres Salomon * pci_write_config and pci_read_config path. Most of the config registers
213ef0e1f8SAndres Salomon * are read-only anyway, so the bulk of the simulation is just table lookup.
223ef0e1f8SAndres Salomon */
233ef0e1f8SAndres Salomon
243ef0e1f8SAndres Salomon #include <linux/pci.h>
253ef0e1f8SAndres Salomon #include <linux/init.h>
263ef0e1f8SAndres Salomon #include <asm/olpc.h>
273ef0e1f8SAndres Salomon #include <asm/geode.h>
2882487711SJaswinder Singh Rajput #include <asm/pci_x86.h>
293ef0e1f8SAndres Salomon
303ef0e1f8SAndres Salomon /*
313ef0e1f8SAndres Salomon * In the tables below, the first two line (8 longwords) are the
323ef0e1f8SAndres Salomon * size masks that are used when the higher level PCI code determines
333ef0e1f8SAndres Salomon * the size of the region by writing ~0 to a base address register
343ef0e1f8SAndres Salomon * and reading back the result.
353ef0e1f8SAndres Salomon *
363ef0e1f8SAndres Salomon * The following lines are the values that are read during normal
373ef0e1f8SAndres Salomon * PCI config access cycles, i.e. not after just having written
383ef0e1f8SAndres Salomon * ~0 to a base address register.
393ef0e1f8SAndres Salomon */
403ef0e1f8SAndres Salomon
413ef0e1f8SAndres Salomon static const uint32_t lxnb_hdr[] = { /* dev 1 function 0 - devfn = 8 */
423ef0e1f8SAndres Salomon 0x0, 0x0, 0x0, 0x0,
433ef0e1f8SAndres Salomon 0x0, 0x0, 0x0, 0x0,
443ef0e1f8SAndres Salomon
453ef0e1f8SAndres Salomon 0x281022, 0x2200005, 0x6000021, 0x80f808, /* AMD Vendor ID */
463ef0e1f8SAndres Salomon 0x0, 0x0, 0x0, 0x0, /* No virtual registers, hence no BAR */
473ef0e1f8SAndres Salomon 0x0, 0x0, 0x0, 0x28100b,
483ef0e1f8SAndres Salomon 0x0, 0x0, 0x0, 0x0,
493ef0e1f8SAndres Salomon 0x0, 0x0, 0x0, 0x0,
503ef0e1f8SAndres Salomon 0x0, 0x0, 0x0, 0x0,
513ef0e1f8SAndres Salomon 0x0, 0x0, 0x0, 0x0,
523ef0e1f8SAndres Salomon };
533ef0e1f8SAndres Salomon
543ef0e1f8SAndres Salomon static const uint32_t gxnb_hdr[] = { /* dev 1 function 0 - devfn = 8 */
553ef0e1f8SAndres Salomon 0xfffffffd, 0x0, 0x0, 0x0,
563ef0e1f8SAndres Salomon 0x0, 0x0, 0x0, 0x0,
573ef0e1f8SAndres Salomon
583ef0e1f8SAndres Salomon 0x28100b, 0x2200005, 0x6000021, 0x80f808, /* NSC Vendor ID */
593ef0e1f8SAndres Salomon 0xac1d, 0x0, 0x0, 0x0, /* I/O BAR - base of virtual registers */
603ef0e1f8SAndres Salomon 0x0, 0x0, 0x0, 0x28100b,
613ef0e1f8SAndres Salomon 0x0, 0x0, 0x0, 0x0,
623ef0e1f8SAndres Salomon 0x0, 0x0, 0x0, 0x0,
633ef0e1f8SAndres Salomon 0x0, 0x0, 0x0, 0x0,
643ef0e1f8SAndres Salomon 0x0, 0x0, 0x0, 0x0,
653ef0e1f8SAndres Salomon };
663ef0e1f8SAndres Salomon
673ef0e1f8SAndres Salomon static const uint32_t lxfb_hdr[] = { /* dev 1 function 1 - devfn = 9 */
683ef0e1f8SAndres Salomon 0xff000008, 0xffffc000, 0xffffc000, 0xffffc000,
693ef0e1f8SAndres Salomon 0xffffc000, 0x0, 0x0, 0x0,
703ef0e1f8SAndres Salomon
713ef0e1f8SAndres Salomon 0x20811022, 0x2200003, 0x3000000, 0x0, /* AMD Vendor ID */
723ef0e1f8SAndres Salomon 0xfd000000, 0xfe000000, 0xfe004000, 0xfe008000, /* FB, GP, VG, DF */
733ef0e1f8SAndres Salomon 0xfe00c000, 0x0, 0x0, 0x30100b, /* VIP */
743ef0e1f8SAndres Salomon 0x0, 0x0, 0x0, 0x10e, /* INTA, IRQ14 for graphics accel */
753ef0e1f8SAndres Salomon 0x0, 0x0, 0x0, 0x0,
763ef0e1f8SAndres Salomon 0x3d0, 0x3c0, 0xa0000, 0x0, /* VG IO, VG IO, EGA FB, MONO FB */
773ef0e1f8SAndres Salomon 0x0, 0x0, 0x0, 0x0,
783ef0e1f8SAndres Salomon };
793ef0e1f8SAndres Salomon
803ef0e1f8SAndres Salomon static const uint32_t gxfb_hdr[] = { /* dev 1 function 1 - devfn = 9 */
813ef0e1f8SAndres Salomon 0xff800008, 0xffffc000, 0xffffc000, 0xffffc000,
823ef0e1f8SAndres Salomon 0x0, 0x0, 0x0, 0x0,
833ef0e1f8SAndres Salomon
843ef0e1f8SAndres Salomon 0x30100b, 0x2200003, 0x3000000, 0x0, /* NSC Vendor ID */
853ef0e1f8SAndres Salomon 0xfd000000, 0xfe000000, 0xfe004000, 0xfe008000, /* FB, GP, VG, DF */
863ef0e1f8SAndres Salomon 0x0, 0x0, 0x0, 0x30100b,
873ef0e1f8SAndres Salomon 0x0, 0x0, 0x0, 0x0,
883ef0e1f8SAndres Salomon 0x0, 0x0, 0x0, 0x0,
893ef0e1f8SAndres Salomon 0x3d0, 0x3c0, 0xa0000, 0x0, /* VG IO, VG IO, EGA FB, MONO FB */
903ef0e1f8SAndres Salomon 0x0, 0x0, 0x0, 0x0,
913ef0e1f8SAndres Salomon };
923ef0e1f8SAndres Salomon
933ef0e1f8SAndres Salomon static const uint32_t aes_hdr[] = { /* dev 1 function 2 - devfn = 0xa */
943ef0e1f8SAndres Salomon 0xffffc000, 0x0, 0x0, 0x0,
953ef0e1f8SAndres Salomon 0x0, 0x0, 0x0, 0x0,
963ef0e1f8SAndres Salomon
973ef0e1f8SAndres Salomon 0x20821022, 0x2a00006, 0x10100000, 0x8, /* NSC Vendor ID */
983ef0e1f8SAndres Salomon 0xfe010000, 0x0, 0x0, 0x0, /* AES registers */
993ef0e1f8SAndres Salomon 0x0, 0x0, 0x0, 0x20821022,
1003ef0e1f8SAndres Salomon 0x0, 0x0, 0x0, 0x0,
1013ef0e1f8SAndres Salomon 0x0, 0x0, 0x0, 0x0,
1023ef0e1f8SAndres Salomon 0x0, 0x0, 0x0, 0x0,
1033ef0e1f8SAndres Salomon 0x0, 0x0, 0x0, 0x0,
1043ef0e1f8SAndres Salomon };
1053ef0e1f8SAndres Salomon
1063ef0e1f8SAndres Salomon
1073ef0e1f8SAndres Salomon static const uint32_t isa_hdr[] = { /* dev f function 0 - devfn = 78 */
1083ef0e1f8SAndres Salomon 0xfffffff9, 0xffffff01, 0xffffffc1, 0xffffffe1,
1093ef0e1f8SAndres Salomon 0xffffff81, 0xffffffc1, 0x0, 0x0,
1103ef0e1f8SAndres Salomon
1113ef0e1f8SAndres Salomon 0x20901022, 0x2a00049, 0x6010003, 0x802000,
1123ef0e1f8SAndres Salomon 0x18b1, 0x1001, 0x1801, 0x1881, /* SMB-8 GPIO-256 MFGPT-64 IRQ-32 */
1133ef0e1f8SAndres Salomon 0x1401, 0x1841, 0x0, 0x20901022, /* PMS-128 ACPI-64 */
1143ef0e1f8SAndres Salomon 0x0, 0x0, 0x0, 0x0,
1153ef0e1f8SAndres Salomon 0x0, 0x0, 0x0, 0x0,
1163ef0e1f8SAndres Salomon 0x0, 0x0, 0x0, 0xaa5b, /* IRQ steering */
1173ef0e1f8SAndres Salomon 0x0, 0x0, 0x0, 0x0,
1183ef0e1f8SAndres Salomon };
1193ef0e1f8SAndres Salomon
1203ef0e1f8SAndres Salomon static const uint32_t ac97_hdr[] = { /* dev f function 3 - devfn = 7b */
1213ef0e1f8SAndres Salomon 0xffffff81, 0x0, 0x0, 0x0,
1223ef0e1f8SAndres Salomon 0x0, 0x0, 0x0, 0x0,
1233ef0e1f8SAndres Salomon
1243ef0e1f8SAndres Salomon 0x20931022, 0x2a00041, 0x4010001, 0x0,
1253ef0e1f8SAndres Salomon 0x1481, 0x0, 0x0, 0x0, /* I/O BAR-128 */
1263ef0e1f8SAndres Salomon 0x0, 0x0, 0x0, 0x20931022,
1273ef0e1f8SAndres Salomon 0x0, 0x0, 0x0, 0x205, /* IntB, IRQ5 */
1283ef0e1f8SAndres Salomon 0x0, 0x0, 0x0, 0x0,
1293ef0e1f8SAndres Salomon 0x0, 0x0, 0x0, 0x0,
1303ef0e1f8SAndres Salomon 0x0, 0x0, 0x0, 0x0,
1313ef0e1f8SAndres Salomon };
1323ef0e1f8SAndres Salomon
1333ef0e1f8SAndres Salomon static const uint32_t ohci_hdr[] = { /* dev f function 4 - devfn = 7c */
1343ef0e1f8SAndres Salomon 0xfffff000, 0x0, 0x0, 0x0,
1353ef0e1f8SAndres Salomon 0x0, 0x0, 0x0, 0x0,
1363ef0e1f8SAndres Salomon
1373ef0e1f8SAndres Salomon 0x20941022, 0x2300006, 0xc031002, 0x0,
1383ef0e1f8SAndres Salomon 0xfe01a000, 0x0, 0x0, 0x0, /* MEMBAR-1000 */
1393ef0e1f8SAndres Salomon 0x0, 0x0, 0x0, 0x20941022,
1403ef0e1f8SAndres Salomon 0x0, 0x40, 0x0, 0x40a, /* CapPtr INT-D, IRQA */
1413ef0e1f8SAndres Salomon 0xc8020001, 0x0, 0x0, 0x0, /* Capabilities - 40 is R/O,
1423ef0e1f8SAndres Salomon 44 is mask 8103 (power control) */
1433ef0e1f8SAndres Salomon 0x0, 0x0, 0x0, 0x0,
1443ef0e1f8SAndres Salomon 0x0, 0x0, 0x0, 0x0,
1453ef0e1f8SAndres Salomon };
1463ef0e1f8SAndres Salomon
1473ef0e1f8SAndres Salomon static const uint32_t ehci_hdr[] = { /* dev f function 4 - devfn = 7d */
1483ef0e1f8SAndres Salomon 0xfffff000, 0x0, 0x0, 0x0,
1493ef0e1f8SAndres Salomon 0x0, 0x0, 0x0, 0x0,
1503ef0e1f8SAndres Salomon
1513ef0e1f8SAndres Salomon 0x20951022, 0x2300006, 0xc032002, 0x0,
1523ef0e1f8SAndres Salomon 0xfe01b000, 0x0, 0x0, 0x0, /* MEMBAR-1000 */
1533ef0e1f8SAndres Salomon 0x0, 0x0, 0x0, 0x20951022,
1543ef0e1f8SAndres Salomon 0x0, 0x40, 0x0, 0x40a, /* CapPtr INT-D, IRQA */
1553ef0e1f8SAndres Salomon 0xc8020001, 0x0, 0x0, 0x0, /* Capabilities - 40 is R/O, 44 is
1563ef0e1f8SAndres Salomon mask 8103 (power control) */
1573ef0e1f8SAndres Salomon #if 0
1583ef0e1f8SAndres Salomon 0x1, 0x40080000, 0x0, 0x0, /* EECP - see EHCI spec section 2.1.7 */
1593ef0e1f8SAndres Salomon #endif
1603ef0e1f8SAndres Salomon 0x01000001, 0x0, 0x0, 0x0, /* EECP - see EHCI spec section 2.1.7 */
1613ef0e1f8SAndres Salomon 0x2020, 0x0, 0x0, 0x0, /* (EHCI page 8) 60 SBRN (R/O),
1623ef0e1f8SAndres Salomon 61 FLADJ (R/W), PORTWAKECAP */
1633ef0e1f8SAndres Salomon };
1643ef0e1f8SAndres Salomon
1653ef0e1f8SAndres Salomon static uint32_t ff_loc = ~0;
1663ef0e1f8SAndres Salomon static uint32_t zero_loc;
1673ef0e1f8SAndres Salomon static int bar_probing; /* Set after a write of ~0 to a BAR */
1683ef0e1f8SAndres Salomon static int is_lx;
1693ef0e1f8SAndres Salomon
1703ef0e1f8SAndres Salomon #define NB_SLOT 0x1 /* Northbridge - GX chip - Device 1 */
1713ef0e1f8SAndres Salomon #define SB_SLOT 0xf /* Southbridge - CS5536 chip - Device F */
1723ef0e1f8SAndres Salomon
is_simulated(unsigned int bus,unsigned int devfn)1733ef0e1f8SAndres Salomon static int is_simulated(unsigned int bus, unsigned int devfn)
1743ef0e1f8SAndres Salomon {
1753ef0e1f8SAndres Salomon return (!bus && ((PCI_SLOT(devfn) == NB_SLOT) ||
1763ef0e1f8SAndres Salomon (PCI_SLOT(devfn) == SB_SLOT)));
1773ef0e1f8SAndres Salomon }
1783ef0e1f8SAndres Salomon
hdr_addr(const uint32_t * hdr,int reg)1793ef0e1f8SAndres Salomon static uint32_t *hdr_addr(const uint32_t *hdr, int reg)
1803ef0e1f8SAndres Salomon {
1813ef0e1f8SAndres Salomon uint32_t addr;
1823ef0e1f8SAndres Salomon
1833ef0e1f8SAndres Salomon /*
1843ef0e1f8SAndres Salomon * This is a little bit tricky. The header maps consist of
1853ef0e1f8SAndres Salomon * 0x20 bytes of size masks, followed by 0x70 bytes of header data.
1863ef0e1f8SAndres Salomon * In the normal case, when not probing a BAR's size, we want
1873ef0e1f8SAndres Salomon * to access the header data, so we add 0x20 to the reg offset,
1883ef0e1f8SAndres Salomon * thus skipping the size mask area.
1893ef0e1f8SAndres Salomon * In the BAR probing case, we want to access the size mask for
1903ef0e1f8SAndres Salomon * the BAR, so we subtract 0x10 (the config header offset for
1913ef0e1f8SAndres Salomon * BAR0), and don't skip the size mask area.
1923ef0e1f8SAndres Salomon */
1933ef0e1f8SAndres Salomon
1943ef0e1f8SAndres Salomon addr = (uint32_t)hdr + reg + (bar_probing ? -0x10 : 0x20);
1953ef0e1f8SAndres Salomon
1963ef0e1f8SAndres Salomon bar_probing = 0;
1973ef0e1f8SAndres Salomon return (uint32_t *)addr;
1983ef0e1f8SAndres Salomon }
1993ef0e1f8SAndres Salomon
pci_olpc_read(unsigned int seg,unsigned int bus,unsigned int devfn,int reg,int len,uint32_t * value)2003ef0e1f8SAndres Salomon static int pci_olpc_read(unsigned int seg, unsigned int bus,
2013ef0e1f8SAndres Salomon unsigned int devfn, int reg, int len, uint32_t *value)
2023ef0e1f8SAndres Salomon {
2033ef0e1f8SAndres Salomon uint32_t *addr;
2043ef0e1f8SAndres Salomon
205db34a363SJan Beulich WARN_ON(seg);
206db34a363SJan Beulich
2073ef0e1f8SAndres Salomon /* Use the hardware mechanism for non-simulated devices */
2083ef0e1f8SAndres Salomon if (!is_simulated(bus, devfn))
2093ef0e1f8SAndres Salomon return pci_direct_conf1.read(seg, bus, devfn, reg, len, value);
2103ef0e1f8SAndres Salomon
2113ef0e1f8SAndres Salomon /*
2123ef0e1f8SAndres Salomon * No device has config registers past 0x70, so we save table space
2133ef0e1f8SAndres Salomon * by not storing entries for the nonexistent registers
2143ef0e1f8SAndres Salomon */
2153ef0e1f8SAndres Salomon if (reg >= 0x70)
2163ef0e1f8SAndres Salomon addr = &zero_loc;
2173ef0e1f8SAndres Salomon else {
2183ef0e1f8SAndres Salomon switch (devfn) {
2193ef0e1f8SAndres Salomon case 0x8:
2203ef0e1f8SAndres Salomon addr = hdr_addr(is_lx ? lxnb_hdr : gxnb_hdr, reg);
2213ef0e1f8SAndres Salomon break;
2223ef0e1f8SAndres Salomon case 0x9:
2233ef0e1f8SAndres Salomon addr = hdr_addr(is_lx ? lxfb_hdr : gxfb_hdr, reg);
2243ef0e1f8SAndres Salomon break;
2253ef0e1f8SAndres Salomon case 0xa:
2263ef0e1f8SAndres Salomon addr = is_lx ? hdr_addr(aes_hdr, reg) : &ff_loc;
2273ef0e1f8SAndres Salomon break;
2283ef0e1f8SAndres Salomon case 0x78:
2293ef0e1f8SAndres Salomon addr = hdr_addr(isa_hdr, reg);
2303ef0e1f8SAndres Salomon break;
2313ef0e1f8SAndres Salomon case 0x7b:
2323ef0e1f8SAndres Salomon addr = hdr_addr(ac97_hdr, reg);
2333ef0e1f8SAndres Salomon break;
2343ef0e1f8SAndres Salomon case 0x7c:
2353ef0e1f8SAndres Salomon addr = hdr_addr(ohci_hdr, reg);
2363ef0e1f8SAndres Salomon break;
2373ef0e1f8SAndres Salomon case 0x7d:
2383ef0e1f8SAndres Salomon addr = hdr_addr(ehci_hdr, reg);
2393ef0e1f8SAndres Salomon break;
2403ef0e1f8SAndres Salomon default:
2413ef0e1f8SAndres Salomon addr = &ff_loc;
2423ef0e1f8SAndres Salomon break;
2433ef0e1f8SAndres Salomon }
2443ef0e1f8SAndres Salomon }
2453ef0e1f8SAndres Salomon switch (len) {
2463ef0e1f8SAndres Salomon case 1:
2473ef0e1f8SAndres Salomon *value = *(uint8_t *)addr;
2483ef0e1f8SAndres Salomon break;
2493ef0e1f8SAndres Salomon case 2:
2503ef0e1f8SAndres Salomon *value = *(uint16_t *)addr;
2513ef0e1f8SAndres Salomon break;
2523ef0e1f8SAndres Salomon case 4:
2533ef0e1f8SAndres Salomon *value = *addr;
2543ef0e1f8SAndres Salomon break;
2553ef0e1f8SAndres Salomon default:
2563ef0e1f8SAndres Salomon BUG();
2573ef0e1f8SAndres Salomon }
2583ef0e1f8SAndres Salomon
2593ef0e1f8SAndres Salomon return 0;
2603ef0e1f8SAndres Salomon }
2613ef0e1f8SAndres Salomon
pci_olpc_write(unsigned int seg,unsigned int bus,unsigned int devfn,int reg,int len,uint32_t value)2623ef0e1f8SAndres Salomon static int pci_olpc_write(unsigned int seg, unsigned int bus,
2633ef0e1f8SAndres Salomon unsigned int devfn, int reg, int len, uint32_t value)
2643ef0e1f8SAndres Salomon {
265db34a363SJan Beulich WARN_ON(seg);
266db34a363SJan Beulich
2673ef0e1f8SAndres Salomon /* Use the hardware mechanism for non-simulated devices */
2683ef0e1f8SAndres Salomon if (!is_simulated(bus, devfn))
2693ef0e1f8SAndres Salomon return pci_direct_conf1.write(seg, bus, devfn, reg, len, value);
2703ef0e1f8SAndres Salomon
2713ef0e1f8SAndres Salomon /* XXX we may want to extend this to simulate EHCI power management */
2723ef0e1f8SAndres Salomon
2733ef0e1f8SAndres Salomon /*
2743ef0e1f8SAndres Salomon * Mostly we just discard writes, but if the write is a size probe
2753ef0e1f8SAndres Salomon * (i.e. writing ~0 to a BAR), we remember it and arrange to return
2763ef0e1f8SAndres Salomon * the appropriate size mask on the next read. This is cheating
2773ef0e1f8SAndres Salomon * to some extent, because it depends on the fact that the next
2783ef0e1f8SAndres Salomon * access after such a write will always be a read to the same BAR.
2793ef0e1f8SAndres Salomon */
2803ef0e1f8SAndres Salomon
2813ef0e1f8SAndres Salomon if ((reg >= 0x10) && (reg < 0x2c)) {
2823ef0e1f8SAndres Salomon /* write is to a BAR */
2833ef0e1f8SAndres Salomon if (value == ~0)
2843ef0e1f8SAndres Salomon bar_probing = 1;
2853ef0e1f8SAndres Salomon } else {
2863ef0e1f8SAndres Salomon /*
2873ef0e1f8SAndres Salomon * No warning on writes to ROM BAR, CMD, LATENCY_TIMER,
2883ef0e1f8SAndres Salomon * CACHE_LINE_SIZE, or PM registers.
2893ef0e1f8SAndres Salomon */
2903ef0e1f8SAndres Salomon if ((reg != PCI_ROM_ADDRESS) && (reg != PCI_COMMAND_MASTER) &&
2913ef0e1f8SAndres Salomon (reg != PCI_LATENCY_TIMER) &&
2923ef0e1f8SAndres Salomon (reg != PCI_CACHE_LINE_SIZE) && (reg != 0x44))
2933ef0e1f8SAndres Salomon printk(KERN_WARNING "OLPC PCI: Config write to devfn"
2943ef0e1f8SAndres Salomon " %x reg %x value %x\n", devfn, reg, value);
2953ef0e1f8SAndres Salomon }
2963ef0e1f8SAndres Salomon
2973ef0e1f8SAndres Salomon return 0;
2983ef0e1f8SAndres Salomon }
2993ef0e1f8SAndres Salomon
30072da0b07SJan Beulich static const struct pci_raw_ops pci_olpc_conf = {
3013ef0e1f8SAndres Salomon .read = pci_olpc_read,
3023ef0e1f8SAndres Salomon .write = pci_olpc_write,
3033ef0e1f8SAndres Salomon };
3043ef0e1f8SAndres Salomon
pci_olpc_init(void)3052bdd1b03SAndres Salomon int __init pci_olpc_init(void)
3063ef0e1f8SAndres Salomon {
30776fb6570SDaniel Drake printk(KERN_INFO "PCI: Using configuration type OLPC XO-1\n");
3083ef0e1f8SAndres Salomon raw_pci_ops = &pci_olpc_conf;
3093ef0e1f8SAndres Salomon is_lx = is_geode_lx();
3102bdd1b03SAndres Salomon return 0;
3113ef0e1f8SAndres Salomon }
312