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