xref: /openbmc/linux/arch/x86/pci/olpc.c (revision 824877111cd7f2b4fd2fe6947c5c5cbbb3ac5bd8)
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