drivers/pci : move pci drivers to drivers/pci

Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
new file mode 100644
index 0000000..fe45839
--- /dev/null
+++ b/drivers/pci/Makefile
@@ -0,0 +1,51 @@
+#
+# (C) Copyright 2000-2007
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB 	:= $(obj)libpci.a
+
+COBJS-y += fsl_pci_init.o
+COBJS-y += pci.o
+COBJS-y += pci_auto.o
+COBJS-y += pci_indirect.o
+COBJS-y += tsi108_pci.o
+COBJS-y += w83c553f.o
+
+COBJS	:= $(COBJS-y)
+SRCS 	:= $(COBJS:.o=.c)
+OBJS 	:= $(addprefix $(obj),$(COBJS))
+
+all:	$(LIB)
+
+$(LIB):	$(obj).depend $(OBJS)
+	$(AR) $(ARFLAGS) $@ $(OBJS)
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/drivers/pci/fsl_pci_init.c b/drivers/pci/fsl_pci_init.c
new file mode 100644
index 0000000..1e77884
--- /dev/null
+++ b/drivers/pci/fsl_pci_init.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2007 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * Version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+
+#ifdef CONFIG_FSL_PCI_INIT
+
+/*
+ * PCI/PCIE Controller initialization for mpc85xx/mpc86xx soc's
+ *
+ * Initialize controller and call the common driver/pci pci_hose_scan to
+ * scan for bridges and devices.
+ *
+ * Hose fields which need to be pre-initialized by board specific code:
+ *   regions[]
+ *   first_busno
+ *
+ * Fields updated:
+ *   last_busno
+ */
+
+#include <pci.h>
+#include <asm/immap_fsl_pci.h>
+
+void pciauto_prescan_setup_bridge(struct pci_controller *hose,
+				pci_dev_t dev, int sub_bus);
+void pciauto_postscan_setup_bridge(struct pci_controller *hose,
+				pci_dev_t dev, int sub_bus);
+
+void pciauto_config_init(struct pci_controller *hose);
+void
+fsl_pci_init(struct pci_controller *hose)
+{
+	u16 temp16;
+	u32 temp32;
+	int busno = hose->first_busno;
+	int enabled;
+	u16 ltssm;
+	u8 temp8;
+	int r;
+	int bridge;
+	int inbound = 0;
+	volatile ccsr_fsl_pci_t *pci = (ccsr_fsl_pci_t *) hose->cfg_addr;
+	pci_dev_t dev = PCI_BDF(busno,0,0);
+
+	/* Initialize ATMU registers based on hose regions and flags */
+	volatile pot_t *po=&pci->pot[1];	/* skip 0 */
+	volatile pit_t *pi=&pci->pit[0];	/* ranges from: 3 to 1 */
+
+#ifdef DEBUG
+	int neg_link_w;
+#endif
+
+	for (r=0; r<hose->region_count; r++) {
+		if (hose->regions[r].flags & PCI_REGION_MEMORY) { /* inbound */
+			pi->pitar = (hose->regions[r].bus_start >> 12) & 0x000fffff;
+			pi->piwbar = (hose->regions[r].phys_start >> 12) & 0x000fffff;
+			pi->piwbear = 0;
+			pi->piwar = PIWAR_EN | PIWAR_PF | PIWAR_LOCAL |
+				PIWAR_READ_SNOOP | PIWAR_WRITE_SNOOP |
+				(__ilog2(hose->regions[r].size) - 1);
+			pi++;
+			inbound = hose->regions[r].size > 0;
+		} else { /* Outbound */
+			po->powbar = (hose->regions[r].phys_start >> 12) & 0x000fffff;
+			po->potar = (hose->regions[r].bus_start >> 12) & 0x000fffff;
+			po->potear = 0;
+			if (hose->regions[r].flags & PCI_REGION_IO)
+				po->powar = POWAR_EN | POWAR_IO_READ | POWAR_IO_WRITE |
+					(__ilog2(hose->regions[r].size) - 1);
+			else
+				po->powar = POWAR_EN | POWAR_MEM_READ | POWAR_MEM_WRITE |
+					(__ilog2(hose->regions[r].size) - 1);
+			po++;
+		}
+	}
+
+	pci_register_hose(hose);
+	pciauto_config_init(hose);	/* grab pci_{mem,prefetch,io} */
+	hose->current_busno = hose->first_busno;
+
+	pci->pedr = 0xffffffff;		/* Clear any errors */
+	pci->peer = ~0x20140;		/* Enable All Error Interupts except
+					 * - Master abort (pci)
+					 * - Master PERR (pci)
+					 * - ICCA (PCIe)
+					 */
+	pci_hose_read_config_dword (hose, dev, PCI_DCR, &temp32);
+	temp32 |= 0xf000e;		/* set URR, FER, NFER (but not CER) */
+	pci_hose_write_config_dword(hose, dev, PCI_DCR, temp32);
+
+	pci_hose_read_config_byte (hose, dev, PCI_HEADER_TYPE, &temp8);
+	bridge = temp8 & PCI_HEADER_TYPE_BRIDGE; /* Bridge, such as pcie */
+
+	if ( bridge ) {
+
+		pci_hose_read_config_word(hose, dev, PCI_LTSSM, &ltssm);
+		enabled = ltssm >= PCI_LTSSM_L0;
+
+		if (!enabled) {
+			debug("....PCIE link error.  Skipping scan."
+			      "LTSSM=0x%02x\n", ltssm);
+			hose->last_busno = hose->first_busno;
+			return;
+		}
+
+		pci->pme_msg_det = 0xffffffff;
+		pci->pme_msg_int_en = 0xffffffff;
+#ifdef DEBUG
+		pci_hose_read_config_word(hose, dev, PCI_LSR, &temp16);
+		neg_link_w = (temp16 & 0x3f0 ) >> 4;
+		printf("...PCIE LTSSM=0x%x, Negotiated link width=%d\n",
+		      ltssm, neg_link_w);
+#endif
+		hose->current_busno++; /* Start scan with secondary */
+		pciauto_prescan_setup_bridge(hose, dev, hose->current_busno);
+
+	}
+
+	/* Use generic setup_device to initialize standard pci regs,
+	 * but do not allocate any windows since any BAR found (such
+	 * as PCSRBAR) is not in this cpu's memory space.
+	 */
+
+	pciauto_setup_device(hose, dev, 0, hose->pci_mem,
+			     hose->pci_prefetch, hose->pci_io);
+
+	if (inbound) {
+		pci_hose_read_config_word(hose, dev, PCI_COMMAND, &temp16);
+		pci_hose_write_config_word(hose, dev, PCI_COMMAND,
+					   temp16 | PCI_COMMAND_MEMORY);
+	}
+
+#ifndef CONFIG_PCI_NOSCAN
+	printf ("               Scanning PCI bus %02x\n", hose->current_busno);
+	hose->last_busno = pci_hose_scan_bus(hose,hose->current_busno);
+
+	if ( bridge ) { /* update limit regs and subordinate busno */
+		pciauto_postscan_setup_bridge(hose, dev, hose->last_busno);
+	}
+#else
+	hose->last_busno = hose->current_busno;
+#endif
+
+	/* Clear all error indications */
+
+	pci->pme_msg_det = 0xffffffff;
+	pci->pedr = 0xffffffff;
+
+	pci_hose_read_config_word (hose, dev, PCI_DSR, &temp16);
+	if (temp16) {
+		pci_hose_write_config_word(hose, dev,
+					PCI_DSR, 0xffff);
+	}
+
+	pci_hose_read_config_word (hose, dev, PCI_SEC_STATUS, &temp16);
+	if (temp16) {
+		pci_hose_write_config_word(hose, dev, PCI_SEC_STATUS, 0xffff);
+	}
+}
+
+#endif /* CONFIG_FSL_PCI */
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
new file mode 100644
index 0000000..50ca6b0
--- /dev/null
+++ b/drivers/pci/pci.c
@@ -0,0 +1,526 @@
+/*
+ * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Andreas Heppel <aheppel@sysgo.de>
+ *
+ * (C) Copyright 2002, 2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * PCI routines
+ */
+
+#include <common.h>
+
+#ifdef CONFIG_PCI
+
+#include <command.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <pci.h>
+
+#define PCI_HOSE_OP(rw, size, type)					\
+int pci_hose_##rw##_config_##size(struct pci_controller *hose, 		\
+				  pci_dev_t dev, 			\
+				  int offset, type value)		\
+{									\
+	return hose->rw##_##size(hose, dev, offset, value);		\
+}
+
+PCI_HOSE_OP(read, byte, u8 *)
+PCI_HOSE_OP(read, word, u16 *)
+PCI_HOSE_OP(read, dword, u32 *)
+PCI_HOSE_OP(write, byte, u8)
+PCI_HOSE_OP(write, word, u16)
+PCI_HOSE_OP(write, dword, u32)
+
+#ifndef CONFIG_IXP425
+#define PCI_OP(rw, size, type, error_code)				\
+int pci_##rw##_config_##size(pci_dev_t dev, int offset, type value)	\
+{									\
+	struct pci_controller *hose = pci_bus_to_hose(PCI_BUS(dev));	\
+									\
+	if (!hose)							\
+	{								\
+		error_code;						\
+		return -1;						\
+	}								\
+									\
+	return pci_hose_##rw##_config_##size(hose, dev, offset, value);	\
+}
+
+PCI_OP(read, byte, u8 *, *value = 0xff)
+PCI_OP(read, word, u16 *, *value = 0xffff)
+PCI_OP(read, dword, u32 *, *value = 0xffffffff)
+PCI_OP(write, byte, u8, )
+PCI_OP(write, word, u16, )
+PCI_OP(write, dword, u32, )
+#endif	/* CONFIG_IXP425 */
+
+#define PCI_READ_VIA_DWORD_OP(size, type, off_mask)			\
+int pci_hose_read_config_##size##_via_dword(struct pci_controller *hose,\
+					pci_dev_t dev, 			\
+					int offset, type val)		\
+{									\
+	u32 val32;							\
+									\
+	if (pci_hose_read_config_dword(hose, dev, offset & 0xfc, &val32) < 0) {	\
+		*val = -1;						\
+		return -1;						\
+	}								\
+									\
+	*val = (val32 >> ((offset & (int)off_mask) * 8));		\
+									\
+	return 0;							\
+}
+
+#define PCI_WRITE_VIA_DWORD_OP(size, type, off_mask, val_mask)		\
+int pci_hose_write_config_##size##_via_dword(struct pci_controller *hose,\
+					     pci_dev_t dev, 		\
+					     int offset, type val)	\
+{									\
+	u32 val32, mask, ldata, shift;					\
+									\
+	if (pci_hose_read_config_dword(hose, dev, offset & 0xfc, &val32) < 0)\
+		return -1;						\
+									\
+	shift = ((offset & (int)off_mask) * 8);				\
+	ldata = (((unsigned long)val) & val_mask) << shift;		\
+	mask = val_mask << shift;					\
+	val32 = (val32 & ~mask) | ldata;				\
+									\
+	if (pci_hose_write_config_dword(hose, dev, offset & 0xfc, val32) < 0)\
+		return -1;						\
+									\
+	return 0;							\
+}
+
+PCI_READ_VIA_DWORD_OP(byte, u8 *, 0x03)
+PCI_READ_VIA_DWORD_OP(word, u16 *, 0x02)
+PCI_WRITE_VIA_DWORD_OP(byte, u8, 0x03, 0x000000ff)
+PCI_WRITE_VIA_DWORD_OP(word, u16, 0x02, 0x0000ffff)
+
+/*
+ *
+ */
+
+static struct pci_controller* hose_head = NULL;
+
+void pci_register_hose(struct pci_controller* hose)
+{
+	struct pci_controller **phose = &hose_head;
+
+	while(*phose)
+		phose = &(*phose)->next;
+
+	hose->next = NULL;
+
+	*phose = hose;
+}
+
+struct pci_controller *pci_bus_to_hose (int bus)
+{
+	struct pci_controller *hose;
+
+	for (hose = hose_head; hose; hose = hose->next)
+		if (bus >= hose->first_busno && bus <= hose->last_busno)
+			return hose;
+
+	printf("pci_bus_to_hose() failed\n");
+	return NULL;
+}
+
+#ifndef CONFIG_IXP425
+pci_dev_t pci_find_devices(struct pci_device_id *ids, int index)
+{
+	struct pci_controller * hose;
+	u16 vendor, device;
+	u8 header_type;
+	pci_dev_t bdf;
+	int i, bus, found_multi = 0;
+
+	for (hose = hose_head; hose; hose = hose->next)
+	{
+#ifdef CFG_SCSI_SCAN_BUS_REVERSE
+		for (bus = hose->last_busno; bus >= hose->first_busno; bus--)
+#else
+		for (bus = hose->first_busno; bus <= hose->last_busno; bus++)
+#endif
+			for (bdf = PCI_BDF(bus,0,0);
+#if defined(CONFIG_ELPPC) || defined(CONFIG_PPMC7XX)
+			     bdf < PCI_BDF(bus,PCI_MAX_PCI_DEVICES-1,PCI_MAX_PCI_FUNCTIONS-1);
+#else
+			     bdf < PCI_BDF(bus+1,0,0);
+#endif
+			     bdf += PCI_BDF(0,0,1))
+			{
+				if (!PCI_FUNC(bdf)) {
+					pci_read_config_byte(bdf,
+							     PCI_HEADER_TYPE,
+							     &header_type);
+
+					found_multi = header_type & 0x80;
+				} else {
+					if (!found_multi)
+						continue;
+				}
+
+				pci_read_config_word(bdf,
+						     PCI_VENDOR_ID,
+						     &vendor);
+				pci_read_config_word(bdf,
+						     PCI_DEVICE_ID,
+						     &device);
+
+				for (i=0; ids[i].vendor != 0; i++)
+					if (vendor == ids[i].vendor &&
+					    device == ids[i].device)
+					{
+						if (index <= 0)
+							return bdf;
+
+						index--;
+					}
+			}
+	}
+
+	return (-1);
+}
+#endif	/* CONFIG_IXP425 */
+
+pci_dev_t pci_find_device(unsigned int vendor, unsigned int device, int index)
+{
+	static struct pci_device_id ids[2] = {{}, {0, 0}};
+
+	ids[0].vendor = vendor;
+	ids[0].device = device;
+
+	return pci_find_devices(ids, index);
+}
+
+/*
+ *
+ */
+
+unsigned long pci_hose_phys_to_bus (struct pci_controller *hose,
+				    unsigned long phys_addr,
+				    unsigned long flags)
+{
+	struct pci_region *res;
+	unsigned long bus_addr;
+	int i;
+
+	if (!hose) {
+		printf ("pci_hose_phys_to_bus: %s\n", "invalid hose");
+		goto Done;
+	}
+
+	for (i = 0; i < hose->region_count; i++) {
+		res = &hose->regions[i];
+
+		if (((res->flags ^ flags) & PCI_REGION_TYPE) != 0)
+			continue;
+
+		bus_addr = phys_addr - res->phys_start + res->bus_start;
+
+		if (bus_addr >= res->bus_start &&
+			bus_addr < res->bus_start + res->size) {
+			return bus_addr;
+		}
+	}
+
+	printf ("pci_hose_phys_to_bus: %s\n", "invalid physical address");
+
+Done:
+	return 0;
+}
+
+unsigned long pci_hose_bus_to_phys(struct pci_controller* hose,
+				   unsigned long bus_addr,
+				   unsigned long flags)
+{
+	struct pci_region *res;
+	int i;
+
+	if (!hose) {
+		printf ("pci_hose_bus_to_phys: %s\n", "invalid hose");
+		goto Done;
+	}
+
+	for (i = 0; i < hose->region_count; i++) {
+		res = &hose->regions[i];
+
+		if (((res->flags ^ flags) & PCI_REGION_TYPE) != 0)
+			continue;
+
+		if (bus_addr >= res->bus_start &&
+			bus_addr < res->bus_start + res->size) {
+			return bus_addr - res->bus_start + res->phys_start;
+		}
+	}
+
+	printf ("pci_hose_bus_to_phys: %s\n", "invalid physical address");
+
+Done:
+	return 0;
+}
+
+/*
+ *
+ */
+
+int pci_hose_config_device(struct pci_controller *hose,
+			   pci_dev_t dev,
+			   unsigned long io,
+			   unsigned long mem,
+			   unsigned long command)
+{
+	unsigned int bar_response, bar_size, bar_value, old_command;
+	unsigned char pin;
+	int bar, found_mem64;
+
+	debug ("PCI Config: I/O=0x%lx, Memory=0x%lx, Command=0x%lx\n",
+		io, mem, command);
+
+	pci_hose_write_config_dword (hose, dev, PCI_COMMAND, 0);
+
+	for (bar = PCI_BASE_ADDRESS_0; bar < PCI_BASE_ADDRESS_5; bar += 4) {
+		pci_hose_write_config_dword (hose, dev, bar, 0xffffffff);
+		pci_hose_read_config_dword (hose, dev, bar, &bar_response);
+
+		if (!bar_response)
+			continue;
+
+		found_mem64 = 0;
+
+		/* Check the BAR type and set our address mask */
+		if (bar_response & PCI_BASE_ADDRESS_SPACE) {
+			bar_size = ~(bar_response & PCI_BASE_ADDRESS_IO_MASK) + 1;
+			/* round up region base address to a multiple of size */
+			io = ((io - 1) | (bar_size - 1)) + 1;
+			bar_value = io;
+			/* compute new region base address */
+			io = io + bar_size;
+		} else {
+			if ((bar_response & PCI_BASE_ADDRESS_MEM_TYPE_MASK) ==
+				PCI_BASE_ADDRESS_MEM_TYPE_64)
+				found_mem64 = 1;
+
+			bar_size = ~(bar_response & PCI_BASE_ADDRESS_MEM_MASK) + 1;
+
+			/* round up region base address to multiple of size */
+			mem = ((mem - 1) | (bar_size - 1)) + 1;
+			bar_value = mem;
+			/* compute new region base address */
+			mem = mem + bar_size;
+		}
+
+		/* Write it out and update our limit */
+		pci_hose_write_config_dword (hose, dev, bar, bar_value);
+
+		if (found_mem64) {
+			bar += 4;
+			pci_hose_write_config_dword (hose, dev, bar, 0x00000000);
+		}
+	}
+
+	/* Configure Cache Line Size Register */
+	pci_hose_write_config_byte (hose, dev, PCI_CACHE_LINE_SIZE, 0x08);
+
+	/* Configure Latency Timer */
+	pci_hose_write_config_byte (hose, dev, PCI_LATENCY_TIMER, 0x80);
+
+	/* Disable interrupt line, if device says it wants to use interrupts */
+	pci_hose_read_config_byte (hose, dev, PCI_INTERRUPT_PIN, &pin);
+	if (pin != 0) {
+		pci_hose_write_config_byte (hose, dev, PCI_INTERRUPT_LINE, 0xff);
+	}
+
+	pci_hose_read_config_dword (hose, dev, PCI_COMMAND, &old_command);
+	pci_hose_write_config_dword (hose, dev, PCI_COMMAND,
+				     (old_command & 0xffff0000) | command);
+
+	return 0;
+}
+
+/*
+ *
+ */
+
+struct pci_config_table *pci_find_config(struct pci_controller *hose,
+					 unsigned short class,
+					 unsigned int vendor,
+					 unsigned int device,
+					 unsigned int bus,
+					 unsigned int dev,
+					 unsigned int func)
+{
+	struct pci_config_table *table;
+
+	for (table = hose->config_table; table && table->vendor; table++) {
+		if ((table->vendor == PCI_ANY_ID || table->vendor == vendor) &&
+		    (table->device == PCI_ANY_ID || table->device == device) &&
+		    (table->class  == PCI_ANY_ID || table->class  == class)  &&
+		    (table->bus    == PCI_ANY_ID || table->bus    == bus)    &&
+		    (table->dev    == PCI_ANY_ID || table->dev    == dev)    &&
+		    (table->func   == PCI_ANY_ID || table->func   == func)) {
+			return table;
+		}
+	}
+
+	return NULL;
+}
+
+void pci_cfgfunc_config_device(struct pci_controller *hose,
+			       pci_dev_t dev,
+			       struct pci_config_table *entry)
+{
+	pci_hose_config_device(hose, dev, entry->priv[0], entry->priv[1], entry->priv[2]);
+}
+
+void pci_cfgfunc_do_nothing(struct pci_controller *hose,
+			    pci_dev_t dev, struct pci_config_table *entry)
+{
+}
+
+/*
+ *
+ */
+
+/* HJF: Changed this to return int. I think this is required
+ * to get the correct result when scanning bridges
+ */
+extern int pciauto_config_device(struct pci_controller *hose, pci_dev_t dev);
+extern void pciauto_config_init(struct pci_controller *hose);
+
+int pci_hose_scan_bus(struct pci_controller *hose, int bus)
+{
+	unsigned int sub_bus, found_multi=0;
+	unsigned short vendor, device, class;
+	unsigned char header_type;
+	struct pci_config_table *cfg;
+	pci_dev_t dev;
+
+	sub_bus = bus;
+
+	for (dev =  PCI_BDF(bus,0,0);
+	     dev <  PCI_BDF(bus,PCI_MAX_PCI_DEVICES-1,PCI_MAX_PCI_FUNCTIONS-1);
+	     dev += PCI_BDF(0,0,1))
+	{
+		/* Skip our host bridge */
+		if ( dev == PCI_BDF(hose->first_busno,0,0) ) {
+#if defined(CONFIG_PCI_CONFIG_HOST_BRIDGE)              /* don't skip host bridge */
+			/*
+			 * Only skip hostbridge configuration if "pciconfighost" is not set
+			 */
+			if (getenv("pciconfighost") == NULL) {
+				continue; /* Skip our host bridge */
+			}
+#else
+			continue; /* Skip our host bridge */
+#endif
+		}
+
+		if (PCI_FUNC(dev) && !found_multi)
+			continue;
+
+		pci_hose_read_config_byte(hose, dev, PCI_HEADER_TYPE, &header_type);
+
+		pci_hose_read_config_word(hose, dev, PCI_VENDOR_ID, &vendor);
+
+		if (vendor != 0xffff && vendor != 0x0000) {
+
+			if (!PCI_FUNC(dev))
+				found_multi = header_type & 0x80;
+
+			debug ("PCI Scan: Found Bus %d, Device %d, Function %d\n",
+				PCI_BUS(dev), PCI_DEV(dev), PCI_FUNC(dev) );
+
+			pci_hose_read_config_word(hose, dev, PCI_DEVICE_ID, &device);
+			pci_hose_read_config_word(hose, dev, PCI_CLASS_DEVICE, &class);
+
+			cfg = pci_find_config(hose, class, vendor, device,
+					      PCI_BUS(dev), PCI_DEV(dev), PCI_FUNC(dev));
+			if (cfg) {
+				cfg->config_device(hose, dev, cfg);
+				sub_bus = max(sub_bus, hose->current_busno);
+#ifdef CONFIG_PCI_PNP
+			} else {
+				int n = pciauto_config_device(hose, dev);
+
+				sub_bus = max(sub_bus, n);
+#endif
+			}
+			if (hose->fixup_irq)
+				hose->fixup_irq(hose, dev);
+
+#ifdef CONFIG_PCI_SCAN_SHOW
+			/* Skip our host bridge */
+			if ( dev != PCI_BDF(hose->first_busno,0,0) ) {
+			    unsigned char int_line;
+
+			    pci_hose_read_config_byte(hose, dev, PCI_INTERRUPT_LINE,
+						      &int_line);
+			    printf("        %02x  %02x  %04x  %04x  %04x  %02x\n",
+				   PCI_BUS(dev), PCI_DEV(dev), vendor, device, class,
+				   int_line);
+			}
+#endif
+		}
+	}
+
+	return sub_bus;
+}
+
+int pci_hose_scan(struct pci_controller *hose)
+{
+	/* Start scan at current_busno.
+	 * PCIe will start scan at first_busno+1.
+	 */
+	/* For legacy support, ensure current>=first */
+	if (hose->first_busno > hose->current_busno)
+		hose->current_busno = hose->first_busno;
+#ifdef CONFIG_PCI_PNP
+	pciauto_config_init(hose);
+#endif
+	return pci_hose_scan_bus(hose, hose->current_busno);
+}
+
+void pci_init(void)
+{
+#if defined(CONFIG_PCI_BOOTDELAY)
+	char *s;
+	int i;
+
+	/* wait "pcidelay" ms (if defined)... */
+	s = getenv ("pcidelay");
+	if (s) {
+		int val = simple_strtoul (s, NULL, 10);
+		for (i=0; i<val; i++)
+			udelay (1000);
+	}
+#endif /* CONFIG_PCI_BOOTDELAY */
+
+	/* now call board specific pci_init()... */
+	pci_init_board();
+}
+
+#endif /* CONFIG_PCI */
diff --git a/drivers/pci/pci_auto.c b/drivers/pci/pci_auto.c
new file mode 100644
index 0000000..acfda83
--- /dev/null
+++ b/drivers/pci/pci_auto.c
@@ -0,0 +1,412 @@
+/*
+ * arch/ppc/kernel/pci_auto.c
+ *
+ * PCI autoconfiguration library
+ *
+ * Author: Matt Porter <mporter@mvista.com>
+ *
+ * Copyright 2000 MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <common.h>
+
+#ifdef CONFIG_PCI
+
+#include <pci.h>
+
+#undef DEBUG
+#ifdef DEBUG
+#define DEBUGF(x...) printf(x)
+#else
+#define DEBUGF(x...)
+#endif /* DEBUG */
+
+#define	PCIAUTO_IDE_MODE_MASK		0x05
+
+/* the user can define CFG_PCI_CACHE_LINE_SIZE to avoid problems */
+#ifndef CFG_PCI_CACHE_LINE_SIZE
+#define CFG_PCI_CACHE_LINE_SIZE	8
+#endif
+
+/*
+ *
+ */
+
+void pciauto_region_init(struct pci_region* res)
+{
+	/*
+	 * Avoid allocating PCI resources from address 0 -- this is illegal
+	 * according to PCI 2.1 and moreover, this is known to cause Linux IDE
+	 * drivers to fail. Use a reasonable starting value of 0x1000 instead.
+	 */
+	res->bus_lower = res->bus_start ? res->bus_start : 0x1000;
+}
+
+void pciauto_region_align(struct pci_region *res, unsigned long size)
+{
+	res->bus_lower = ((res->bus_lower - 1) | (size - 1)) + 1;
+}
+
+int pciauto_region_allocate(struct pci_region* res, unsigned int size, unsigned int *bar)
+{
+	unsigned long addr;
+
+	if (!res) {
+		DEBUGF("No resource");
+		goto error;
+	}
+
+	addr = ((res->bus_lower - 1) | (size - 1)) + 1;
+
+	if (addr - res->bus_start + size > res->size) {
+		DEBUGF("No room in resource");
+		goto error;
+	}
+
+	res->bus_lower = addr + size;
+
+	DEBUGF("address=0x%lx bus_lower=%x", addr, res->bus_lower);
+
+	*bar = addr;
+	return 0;
+
+ error:
+	*bar = 0xffffffff;
+	return -1;
+}
+
+/*
+ *
+ */
+
+void pciauto_setup_device(struct pci_controller *hose,
+			  pci_dev_t dev, int bars_num,
+			  struct pci_region *mem,
+			  struct pci_region *prefetch,
+			  struct pci_region *io)
+{
+	unsigned int bar_value, bar_response, bar_size;
+	unsigned int cmdstat = 0;
+	struct pci_region *bar_res;
+	int bar, bar_nr = 0;
+	int found_mem64 = 0;
+
+	pci_hose_read_config_dword(hose, dev, PCI_COMMAND, &cmdstat);
+	cmdstat = (cmdstat & ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) | PCI_COMMAND_MASTER;
+
+	for (bar = PCI_BASE_ADDRESS_0; bar < PCI_BASE_ADDRESS_0 + (bars_num*4); bar += 4) {
+		/* Tickle the BAR and get the response */
+		pci_hose_write_config_dword(hose, dev, bar, 0xffffffff);
+		pci_hose_read_config_dword(hose, dev, bar, &bar_response);
+
+		/* If BAR is not implemented go to the next BAR */
+		if (!bar_response)
+			continue;
+
+		found_mem64 = 0;
+
+		/* Check the BAR type and set our address mask */
+		if (bar_response & PCI_BASE_ADDRESS_SPACE) {
+			bar_size = ((~(bar_response & PCI_BASE_ADDRESS_IO_MASK))
+				   & 0xffff) + 1;
+			bar_res = io;
+
+			DEBUGF("PCI Autoconfig: BAR %d, I/O, size=0x%x, ", bar_nr, bar_size);
+		} else {
+			if ( (bar_response & PCI_BASE_ADDRESS_MEM_TYPE_MASK) ==
+			     PCI_BASE_ADDRESS_MEM_TYPE_64)
+				found_mem64 = 1;
+
+			bar_size = ~(bar_response & PCI_BASE_ADDRESS_MEM_MASK) + 1;
+			if (prefetch && (bar_response & PCI_BASE_ADDRESS_MEM_PREFETCH))
+				bar_res = prefetch;
+			else
+				bar_res = mem;
+
+			DEBUGF("PCI Autoconfig: BAR %d, Mem, size=0x%x, ", bar_nr, bar_size);
+		}
+
+		if (pciauto_region_allocate(bar_res, bar_size, &bar_value) == 0) {
+			/* Write it out and update our limit */
+			pci_hose_write_config_dword(hose, dev, bar, bar_value);
+
+			/*
+			 * If we are a 64-bit decoder then increment to the
+			 * upper 32 bits of the bar and force it to locate
+			 * in the lower 4GB of memory.
+			 */
+			if (found_mem64) {
+				bar += 4;
+				pci_hose_write_config_dword(hose, dev, bar, 0x00000000);
+			}
+
+			cmdstat |= (bar_response & PCI_BASE_ADDRESS_SPACE) ?
+				PCI_COMMAND_IO : PCI_COMMAND_MEMORY;
+		}
+
+		DEBUGF("\n");
+
+		bar_nr++;
+	}
+
+	pci_hose_write_config_dword(hose, dev, PCI_COMMAND, cmdstat);
+	pci_hose_write_config_byte(hose, dev, PCI_CACHE_LINE_SIZE,
+		CFG_PCI_CACHE_LINE_SIZE);
+	pci_hose_write_config_byte(hose, dev, PCI_LATENCY_TIMER, 0x80);
+}
+
+void pciauto_prescan_setup_bridge(struct pci_controller *hose,
+					 pci_dev_t dev, int sub_bus)
+{
+	struct pci_region *pci_mem = hose->pci_mem;
+	struct pci_region *pci_prefetch = hose->pci_prefetch;
+	struct pci_region *pci_io = hose->pci_io;
+	unsigned int cmdstat;
+
+	pci_hose_read_config_dword(hose, dev, PCI_COMMAND, &cmdstat);
+
+	/* Configure bus number registers */
+	pci_hose_write_config_byte(hose, dev, PCI_PRIMARY_BUS,
+				   PCI_BUS(dev) - hose->first_busno);
+	pci_hose_write_config_byte(hose, dev, PCI_SECONDARY_BUS,
+				   sub_bus - hose->first_busno);
+	pci_hose_write_config_byte(hose, dev, PCI_SUBORDINATE_BUS, 0xff);
+
+	if (pci_mem) {
+		/* Round memory allocator to 1MB boundary */
+		pciauto_region_align(pci_mem, 0x100000);
+
+		/* Set up memory and I/O filter limits, assume 32-bit I/O space */
+		pci_hose_write_config_word(hose, dev, PCI_MEMORY_BASE,
+					(pci_mem->bus_lower & 0xfff00000) >> 16);
+
+		cmdstat |= PCI_COMMAND_MEMORY;
+	}
+
+	if (pci_prefetch) {
+		/* Round memory allocator to 1MB boundary */
+		pciauto_region_align(pci_prefetch, 0x100000);
+
+		/* Set up memory and I/O filter limits, assume 32-bit I/O space */
+		pci_hose_write_config_word(hose, dev, PCI_PREF_MEMORY_BASE,
+					(pci_prefetch->bus_lower & 0xfff00000) >> 16);
+
+		cmdstat |= PCI_COMMAND_MEMORY;
+	} else {
+		/* We don't support prefetchable memory for now, so disable */
+		pci_hose_write_config_word(hose, dev, PCI_PREF_MEMORY_BASE, 0x1000);
+		pci_hose_write_config_word(hose, dev, PCI_PREF_MEMORY_LIMIT, 0x0);
+	}
+
+	if (pci_io) {
+		/* Round I/O allocator to 4KB boundary */
+		pciauto_region_align(pci_io, 0x1000);
+
+		pci_hose_write_config_byte(hose, dev, PCI_IO_BASE,
+					(pci_io->bus_lower & 0x0000f000) >> 8);
+		pci_hose_write_config_word(hose, dev, PCI_IO_BASE_UPPER16,
+					(pci_io->bus_lower & 0xffff0000) >> 16);
+
+		cmdstat |= PCI_COMMAND_IO;
+	}
+
+	/* Enable memory and I/O accesses, enable bus master */
+	pci_hose_write_config_dword(hose, dev, PCI_COMMAND, cmdstat | PCI_COMMAND_MASTER);
+}
+
+void pciauto_postscan_setup_bridge(struct pci_controller *hose,
+					  pci_dev_t dev, int sub_bus)
+{
+	struct pci_region *pci_mem = hose->pci_mem;
+	struct pci_region *pci_prefetch = hose->pci_prefetch;
+	struct pci_region *pci_io = hose->pci_io;
+
+	/* Configure bus number registers */
+	pci_hose_write_config_byte(hose, dev, PCI_SUBORDINATE_BUS,
+				   sub_bus - hose->first_busno);
+
+	if (pci_mem) {
+		/* Round memory allocator to 1MB boundary */
+		pciauto_region_align(pci_mem, 0x100000);
+
+		pci_hose_write_config_word(hose, dev, PCI_MEMORY_LIMIT,
+					(pci_mem->bus_lower-1) >> 16);
+	}
+
+	if (pci_prefetch) {
+		/* Round memory allocator to 1MB boundary */
+		pciauto_region_align(pci_prefetch, 0x100000);
+
+		pci_hose_write_config_word(hose, dev, PCI_PREF_MEMORY_LIMIT,
+					(pci_prefetch->bus_lower-1) >> 16);
+	}
+
+	if (pci_io) {
+		/* Round I/O allocator to 4KB boundary */
+		pciauto_region_align(pci_io, 0x1000);
+
+		pci_hose_write_config_byte(hose, dev, PCI_IO_LIMIT,
+					((pci_io->bus_lower-1) & 0x0000f000) >> 8);
+		pci_hose_write_config_word(hose, dev, PCI_IO_LIMIT_UPPER16,
+					((pci_io->bus_lower-1) & 0xffff0000) >> 16);
+	}
+}
+
+/*
+ *
+ */
+
+void pciauto_config_init(struct pci_controller *hose)
+{
+	int i;
+
+	hose->pci_io = hose->pci_mem = NULL;
+
+	for (i=0; i<hose->region_count; i++) {
+		switch(hose->regions[i].flags) {
+		case PCI_REGION_IO:
+			if (!hose->pci_io ||
+			    hose->pci_io->size < hose->regions[i].size)
+				hose->pci_io = hose->regions + i;
+			break;
+		case PCI_REGION_MEM:
+			if (!hose->pci_mem ||
+			    hose->pci_mem->size < hose->regions[i].size)
+				hose->pci_mem = hose->regions + i;
+			break;
+		case (PCI_REGION_MEM | PCI_REGION_PREFETCH):
+			if (!hose->pci_prefetch ||
+			    hose->pci_prefetch->size < hose->regions[i].size)
+				hose->pci_prefetch = hose->regions + i;
+			break;
+		}
+	}
+
+
+	if (hose->pci_mem) {
+		pciauto_region_init(hose->pci_mem);
+
+		DEBUGF("PCI Autoconfig: Bus Memory region: [%lx-%lx],\n"
+		       "\t\tPhysical Memory [%x-%x]\n",
+		    hose->pci_mem->bus_start,
+		    hose->pci_mem->bus_start + hose->pci_mem->size - 1,
+		    hose->pci_mem->phys_start,
+		    hose->pci_mem->phys_start + hose->pci_mem->size - 1);
+	}
+
+	if (hose->pci_prefetch) {
+		pciauto_region_init(hose->pci_prefetch);
+
+		DEBUGF("PCI Autoconfig: Bus Prefetchable Mem: [%lx-%lx],\n"
+		       "\t\tPhysical Memory [%x-%x]\n",
+		    hose->pci_prefetch->bus_start,
+		    hose->pci_prefetch->bus_start + hose->pci_prefetch->size - 1,
+		    hose->pci_prefetch->phys_start,
+		    hose->pci_prefetch->phys_start +
+				hose->pci_prefetch->size - 1);
+	}
+
+	if (hose->pci_io) {
+		pciauto_region_init(hose->pci_io);
+
+		DEBUGF("PCI Autoconfig: Bus I/O region: [%lx-%lx],\n"
+		       "\t\tPhysical Memory: [%x-%x]\n",
+		    hose->pci_io->bus_start,
+		    hose->pci_io->bus_start + hose->pci_io->size - 1,
+		    hose->pci_io->phys_start,
+		    hose->pci_io->phys_start + hose->pci_io->size - 1);
+
+	}
+}
+
+/* HJF: Changed this to return int. I think this is required
+ * to get the correct result when scanning bridges
+ */
+int pciauto_config_device(struct pci_controller *hose, pci_dev_t dev)
+{
+	unsigned int sub_bus = PCI_BUS(dev);
+	unsigned short class;
+	unsigned char prg_iface;
+	int n;
+
+	pci_hose_read_config_word(hose, dev, PCI_CLASS_DEVICE, &class);
+
+	switch(class) {
+	case PCI_CLASS_PROCESSOR_POWERPC: /* an agent or end-point */
+		DEBUGF("PCI AutoConfig: Found PowerPC device\n");
+		pciauto_setup_device(hose, dev, 6, hose->pci_mem,
+				     hose->pci_prefetch, hose->pci_io);
+		break;
+
+	case PCI_CLASS_BRIDGE_PCI:
+		hose->current_busno++;
+		pciauto_setup_device(hose, dev, 2, hose->pci_mem, hose->pci_prefetch, hose->pci_io);
+
+		DEBUGF("PCI Autoconfig: Found P2P bridge, device %d\n", PCI_DEV(dev));
+
+		/* Passing in current_busno allows for sibling P2P bridges */
+		pciauto_prescan_setup_bridge(hose, dev, hose->current_busno);
+		/*
+		 * need to figure out if this is a subordinate bridge on the bus
+		 * to be able to properly set the pri/sec/sub bridge registers.
+		 */
+		n = pci_hose_scan_bus(hose, hose->current_busno);
+
+		/* figure out the deepest we've gone for this leg */
+		sub_bus = max(n, sub_bus);
+		pciauto_postscan_setup_bridge(hose, dev, sub_bus);
+
+		sub_bus = hose->current_busno;
+		break;
+
+	case PCI_CLASS_STORAGE_IDE:
+		pci_hose_read_config_byte(hose, dev, PCI_CLASS_PROG, &prg_iface);
+		if (!(prg_iface & PCIAUTO_IDE_MODE_MASK)) {
+			DEBUGF("PCI Autoconfig: Skipping legacy mode IDE controller\n");
+			return sub_bus;
+		}
+
+		pciauto_setup_device(hose, dev, 6, hose->pci_mem, hose->pci_prefetch, hose->pci_io);
+		break;
+
+	case PCI_CLASS_BRIDGE_CARDBUS:
+		/* just do a minimal setup of the bridge, let the OS take care of the rest */
+		pciauto_setup_device(hose, dev, 0, hose->pci_mem, hose->pci_prefetch, hose->pci_io);
+
+		DEBUGF("PCI Autoconfig: Found P2CardBus bridge, device %d\n", PCI_DEV(dev));
+
+		hose->current_busno++;
+		break;
+
+#ifdef CONFIG_MPC5200
+	case PCI_CLASS_BRIDGE_OTHER:
+		DEBUGF("PCI Autoconfig: Skipping bridge device %d\n",
+		       PCI_DEV(dev));
+		break;
+#endif
+#ifdef CONFIG_MPC834X
+	case PCI_CLASS_BRIDGE_OTHER:
+		/*
+		 * The host/PCI bridge 1 seems broken in 8349 - it presents
+		 * itself as 'PCI_CLASS_BRIDGE_OTHER' and appears as an _agent_
+		 * device claiming resources io/mem/irq.. we only allow for
+		 * the PIMMR window to be allocated (BAR0 - 1MB size)
+		 */
+		DEBUGF("PCI Autoconfig: Broken bridge found, only minimal config\n");
+		pciauto_setup_device(hose, dev, 0, hose->pci_mem, hose->pci_prefetch, hose->pci_io);
+		break;
+#endif
+	default:
+		pciauto_setup_device(hose, dev, 6, hose->pci_mem, hose->pci_prefetch, hose->pci_io);
+		break;
+	}
+
+	return sub_bus;
+}
+
+#endif /* CONFIG_PCI */
diff --git a/drivers/pci/pci_indirect.c b/drivers/pci/pci_indirect.c
new file mode 100644
index 0000000..a8220fb
--- /dev/null
+++ b/drivers/pci/pci_indirect.c
@@ -0,0 +1,138 @@
+/*
+ * Support for indirect PCI bridges.
+ *
+ * Copyright (C) 1998 Gabriel Paubert.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <common.h>
+
+#ifdef CONFIG_PCI
+#if (!defined(__I386__) && !defined(CONFIG_IXDP425))
+
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <pci.h>
+
+#define cfg_read(val, addr, type, op)	*val = op((type)(addr))
+#define cfg_write(val, addr, type, op)	op((type *)(addr), (val))
+
+#ifdef CONFIG_IXP425
+extern unsigned char	in_8 (volatile unsigned *addr);
+extern unsigned short	in_le16 (volatile unsigned *addr);
+extern unsigned		in_le32 (volatile unsigned *addr);
+extern void		out_8 (volatile unsigned *addr, char val);
+extern void		out_le16 (volatile unsigned *addr, unsigned short val);
+extern void		out_le32 (volatile unsigned *addr, unsigned int val);
+#endif	/* CONFIG_IXP425 */
+
+#if defined(CONFIG_MPC8260)
+#define INDIRECT_PCI_OP(rw, size, type, op, mask)			 \
+static int								 \
+indirect_##rw##_config_##size(struct pci_controller *hose, 		 \
+			      pci_dev_t dev, int offset, type val)	 \
+{									 \
+	u32 b, d,f;							 \
+	b = PCI_BUS(dev); d = PCI_DEV(dev); f = PCI_FUNC(dev);		 \
+	b = b - hose->first_busno;					 \
+	dev = PCI_BDF(b, d, f);						 \
+	out_le32(hose->cfg_addr, dev | (offset & 0xfc) | 0x80000000); 	 \
+	sync();								 \
+	cfg_##rw(val, hose->cfg_data + (offset & mask), type, op);	 \
+	return 0;    					 		 \
+}
+#elif defined(CONFIG_E500) || defined(CONFIG_MPC86xx)
+#define INDIRECT_PCI_OP(rw, size, type, op, mask)                        \
+static int                                                               \
+indirect_##rw##_config_##size(struct pci_controller *hose,               \
+			      pci_dev_t dev, int offset, type val)       \
+{                                                                        \
+	u32 b, d,f;							 \
+	b = PCI_BUS(dev); d = PCI_DEV(dev); f = PCI_FUNC(dev);		 \
+	b = b - hose->first_busno;					 \
+	dev = PCI_BDF(b, d, f);						 \
+	*(hose->cfg_addr) = dev | (offset & 0xfc) | ((offset & 0xf00) << 16) | 0x80000000; \
+	sync();                                                          \
+	cfg_##rw(val, hose->cfg_data + (offset & mask), type, op);       \
+	return 0;                                                        \
+}
+#elif defined(CONFIG_440GX) || defined(CONFIG_440EP) || defined(CONFIG_440GR) || defined(CONFIG_440SPE)
+#define INDIRECT_PCI_OP(rw, size, type, op, mask)			 \
+static int								 \
+indirect_##rw##_config_##size(struct pci_controller *hose, 		 \
+			      pci_dev_t dev, int offset, type val)	 \
+{									 \
+	u32 b, d,f;							 \
+	b = PCI_BUS(dev); d = PCI_DEV(dev); f = PCI_FUNC(dev);		 \
+	b = b - hose->first_busno;					 \
+	dev = PCI_BDF(b, d, f);						 \
+	if (PCI_BUS(dev) > 0)                                            \
+		out_le32(hose->cfg_addr, dev | (offset & 0xfc) | 0x80000001); \
+	else                                                             \
+		out_le32(hose->cfg_addr, dev | (offset & 0xfc) | 0x80000000); \
+	cfg_##rw(val, hose->cfg_data + (offset & mask), type, op);	 \
+	return 0;    					 		 \
+}
+#else
+#define INDIRECT_PCI_OP(rw, size, type, op, mask)			 \
+static int								 \
+indirect_##rw##_config_##size(struct pci_controller *hose, 		 \
+			      pci_dev_t dev, int offset, type val)	 \
+{									 \
+	u32 b, d,f;							 \
+	b = PCI_BUS(dev); d = PCI_DEV(dev); f = PCI_FUNC(dev);		 \
+	b = b - hose->first_busno;					 \
+	dev = PCI_BDF(b, d, f);						 \
+	out_le32(hose->cfg_addr, dev | (offset & 0xfc) | 0x80000000); 	 \
+	cfg_##rw(val, hose->cfg_data + (offset & mask), type, op);	 \
+	return 0;    					 		 \
+}
+#endif
+
+#define INDIRECT_PCI_OP_ERRATA6(rw, size, type, op, mask)		 \
+static int								 \
+indirect_##rw##_config_##size(struct pci_controller *hose, 		 \
+			      pci_dev_t dev, int offset, type val)	 \
+{									 \
+	unsigned int msr = mfmsr();					 \
+	mtmsr(msr & ~(MSR_EE | MSR_CE));				 \
+	out_le32(hose->cfg_addr, dev | (offset & 0xfc) | 0x80000000); 	 \
+	cfg_##rw(val, hose->cfg_data + (offset & mask), type, op);	 \
+	out_le32(hose->cfg_addr, 0x00000000); 				 \
+	mtmsr(msr);							 \
+	return 0;    					 		 \
+}
+
+INDIRECT_PCI_OP(read, byte, u8 *, in_8, 3)
+INDIRECT_PCI_OP(read, word, u16 *, in_le16, 2)
+INDIRECT_PCI_OP(read, dword, u32 *, in_le32, 0)
+#ifdef CONFIG_405GP
+INDIRECT_PCI_OP_ERRATA6(write, byte, u8, out_8, 3)
+INDIRECT_PCI_OP_ERRATA6(write, word, u16, out_le16, 2)
+INDIRECT_PCI_OP_ERRATA6(write, dword, u32, out_le32, 0)
+#else
+INDIRECT_PCI_OP(write, byte, u8, out_8, 3)
+INDIRECT_PCI_OP(write, word, u16, out_le16, 2)
+INDIRECT_PCI_OP(write, dword, u32, out_le32, 0)
+#endif
+
+void pci_setup_indirect(struct pci_controller* hose, u32 cfg_addr, u32 cfg_data)
+{
+	pci_set_ops(hose,
+		    indirect_read_config_byte,
+		    indirect_read_config_word,
+		    indirect_read_config_dword,
+		    indirect_write_config_byte,
+		    indirect_write_config_word,
+		    indirect_write_config_dword);
+
+	hose->cfg_addr = (unsigned int *) cfg_addr;
+	hose->cfg_data = (unsigned char *) cfg_data;
+}
+
+#endif	/* !__I386__ && !CONFIG_IXDP425 */
+#endif	/* CONFIG_PCI */
diff --git a/drivers/pci/tsi108_pci.c b/drivers/pci/tsi108_pci.c
new file mode 100644
index 0000000..d5f11e4
--- /dev/null
+++ b/drivers/pci/tsi108_pci.c
@@ -0,0 +1,181 @@
+/*
+ * (C) Copyright 2004 Tundra Semiconductor Corp.
+ * Alex Bounine <alexandreb@tundra.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * PCI initialisation for the Tsi108 EMU board.
+ */
+
+#include <config.h>
+
+#ifdef CONFIG_TSI108_PCI
+
+#include <common.h>
+#include <pci.h>
+#include <asm/io.h>
+#include <tsi108.h>
+#ifdef CONFIG_OF_FLAT_TREE
+#include <ft_build.h>
+#endif
+
+struct pci_controller local_hose;
+
+void tsi108_clear_pci_error (void)
+{
+	u32 err_stat, err_addr, pci_stat;
+
+	/*
+	 * Quietly clear errors signalled as result of PCI/X configuration read
+	 * requests.
+	 */
+	/* Read PB Error Log Registers */
+	err_stat = *(volatile u32 *)(CFG_TSI108_CSR_BASE +
+				     TSI108_PB_REG_OFFSET + PB_ERRCS);
+	err_addr = *(volatile u32 *)(CFG_TSI108_CSR_BASE +
+				     TSI108_PB_REG_OFFSET + PB_AERR);
+	if (err_stat & PB_ERRCS_ES) {
+		/* Clear PCI/X bus errors if applicable */
+		if ((err_addr & 0xFF000000) == CFG_PCI_CFG_BASE) {
+			/* Clear error flag */
+			*(u32 *) (CFG_TSI108_CSR_BASE +
+				  TSI108_PB_REG_OFFSET + PB_ERRCS) =
+			    PB_ERRCS_ES;
+
+			/* Clear read error reported in PB_ISR */
+			*(u32 *) (CFG_TSI108_CSR_BASE +
+				  TSI108_PB_REG_OFFSET + PB_ISR) =
+			    PB_ISR_PBS_RD_ERR;
+
+		/* Clear errors reported by PCI CSR (Normally Master Abort) */
+			pci_stat = *(volatile u32 *)(CFG_TSI108_CSR_BASE +
+						     TSI108_PCI_REG_OFFSET +
+						     PCI_CSR);
+			*(volatile u32 *)(CFG_TSI108_CSR_BASE +
+					  TSI108_PCI_REG_OFFSET + PCI_CSR) =
+			    pci_stat;
+
+			*(volatile u32 *)(CFG_TSI108_CSR_BASE +
+					  TSI108_PCI_REG_OFFSET +
+					  PCI_IRP_STAT) = PCI_IRP_STAT_P_CSR;
+		}
+	}
+
+	return;
+}
+
+unsigned int __get_pci_config_dword (u32 addr)
+{
+	unsigned int retval;
+
+	__asm__ __volatile__ ("       lwbrx %0,0,%1\n"
+			     "1:     eieio\n"
+			     "2:\n"
+			     ".section .fixup,\"ax\"\n"
+			     "3:     li %0,-1\n"
+			     "       b 2b\n"
+			     ".section __ex_table,\"a\"\n"
+			     "       .align 2\n"
+			     "       .long 1b,3b\n"
+			     ".text":"=r"(retval):"r"(addr));
+
+	return (retval);
+}
+
+static int tsi108_read_config_dword (struct pci_controller *hose,
+				    pci_dev_t dev, int offset, u32 * value)
+{
+	dev &= (CFG_PCI_CFG_SIZE - 1);
+	dev |= (CFG_PCI_CFG_BASE | (offset & 0xfc));
+	*value = __get_pci_config_dword(dev);
+	if (0xFFFFFFFF == *value)
+		tsi108_clear_pci_error ();
+	return 0;
+}
+
+static int tsi108_write_config_dword (struct pci_controller *hose,
+				     pci_dev_t dev, int offset, u32 value)
+{
+	dev &= (CFG_PCI_CFG_SIZE - 1);
+	dev |= (CFG_PCI_CFG_BASE | (offset & 0xfc));
+
+	out_le32 ((volatile unsigned *)dev, value);
+
+	return 0;
+}
+
+void pci_init_board (void)
+{
+	struct pci_controller *hose = (struct pci_controller *)&local_hose;
+
+	hose->first_busno = 0;
+	hose->last_busno = 0xff;
+
+	pci_set_region (hose->regions + 0,
+		       CFG_PCI_MEMORY_BUS,
+		       CFG_PCI_MEMORY_PHYS,
+		       CFG_PCI_MEMORY_SIZE, PCI_REGION_MEM | PCI_REGION_MEMORY);
+
+	/* PCI memory space */
+	pci_set_region (hose->regions + 1,
+		       CFG_PCI_MEM_BUS,
+		       CFG_PCI_MEM_PHYS, CFG_PCI_MEM_SIZE, PCI_REGION_MEM);
+
+	/* PCI I/O space */
+	pci_set_region (hose->regions + 2,
+		       CFG_PCI_IO_BUS,
+		       CFG_PCI_IO_PHYS, CFG_PCI_IO_SIZE, PCI_REGION_IO);
+
+	hose->region_count = 3;
+
+	pci_set_ops (hose,
+		    pci_hose_read_config_byte_via_dword,
+		    pci_hose_read_config_word_via_dword,
+		    tsi108_read_config_dword,
+		    pci_hose_write_config_byte_via_dword,
+		    pci_hose_write_config_word_via_dword,
+		    tsi108_write_config_dword);
+
+	pci_register_hose (hose);
+
+	hose->last_busno = pci_hose_scan (hose);
+
+	debug ("Done PCI initialization\n");
+	return;
+}
+
+#ifdef CONFIG_OF_FLAT_TREE
+void
+ft_pci_setup (void *blob, bd_t *bd)
+{
+	u32 *p;
+	int len;
+
+	p = (u32 *)ft_get_prop (blob, "/" OF_TSI "/pci@1000/bus-range", &len);
+	if (p != NULL) {
+		p[0] = local_hose.first_busno;
+		p[1] = local_hose.last_busno;
+	}
+
+}
+#endif
+
+#endif	/* CONFIG_TSI108_PCI */
diff --git a/drivers/pci/w83c553f.c b/drivers/pci/w83c553f.c
new file mode 100644
index 0000000..5d82ed4
--- /dev/null
+++ b/drivers/pci/w83c553f.c
@@ -0,0 +1,226 @@
+/*
+ * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Andreas Heppel <aheppel@sysgo.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * Initialisation of the PCI-to-ISA bridge and disabling the BIOS
+ * write protection (for flash) in function 0 of the chip.
+ * Enabling function 1 (IDE controller of the chip.
+ */
+
+#include <common.h>
+#include <config.h>
+
+#ifdef CFG_WINBOND_83C553
+
+#include <asm/io.h>
+#include <pci.h>
+
+#include <w83c553f.h>
+
+#define out8(addr,val)	do { \
+			out_8((u8*) (addr),(val)); udelay(1); \
+			} while (0)
+#define out16(addr,val)	do { \
+			out_be16((u16*) (addr),(val)); udelay(1); \
+			} while (0)
+
+extern uint ide_bus_offset[CFG_IDE_MAXBUS];
+
+void initialise_pic(void);
+void initialise_dma(void);
+
+void initialise_w83c553f(void)
+{
+	pci_dev_t devbusfn;
+	unsigned char reg8;
+	unsigned short reg16;
+	unsigned int reg32;
+
+	devbusfn = pci_find_device(W83C553F_VID, W83C553F_DID, 0);
+	if (devbusfn == -1)
+	{
+		printf("Error: Cannot find W83C553F controller on any PCI bus.");
+		return;
+	}
+
+	pci_read_config_word(devbusfn, PCI_COMMAND, &reg16);
+	reg16 |= PCI_COMMAND_MASTER | PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
+	pci_write_config_word(devbusfn, PCI_COMMAND, reg16);
+
+	pci_read_config_byte(devbusfn, WINBOND_IPADCR, &reg8);
+	/* 16 MB ISA memory space */
+	reg8 |= (IPADCR_IPATOM4 | IPADCR_IPATOM5 | IPADCR_IPATOM6 | IPADCR_IPATOM7);
+	reg8 &= ~IPADCR_MBE512;
+	pci_write_config_byte(devbusfn, WINBOND_IPADCR, reg8);
+
+	pci_read_config_byte(devbusfn, WINBOND_CSCR, &reg8);
+	/* switch off BIOS write protection */
+	reg8 |= CSCR_UBIOSCSE;
+	reg8 &= ~CSCR_BIOSWP;
+	pci_write_config_byte(devbusfn, WINBOND_CSCR, reg8);
+
+	/*
+	 * Interrupt routing:
+	 *  - IDE  -> IRQ 9/0
+	 *  - INTA -> IRQ 10
+	 *  - INTB -> IRQ 11
+	 *  - INTC -> IRQ 14
+	 *  - INTD -> IRQ 15
+	 */
+	pci_write_config_byte(devbusfn, WINBOND_IDEIRCR, 0x90);
+	pci_write_config_word(devbusfn, WINBOND_PCIIRCR, 0xABEF);
+
+	/*
+	 * Read IDE bus offsets from function 1 device.
+	 * We must unmask the LSB indicating that ist is an IO address.
+	 */
+	devbusfn |= PCI_BDF(0,0,1);
+
+	/*
+	 * Switch off legacy IRQ for IDE and IDE port 1.
+	 */
+	pci_write_config_byte(devbusfn, 0x09, 0x8F);
+
+	pci_read_config_dword(devbusfn, WINDOND_IDECSR, &reg32);
+	reg32 &= ~(IDECSR_LEGIRQ | IDECSR_P1EN | IDECSR_P1F16);
+	pci_write_config_dword(devbusfn, WINDOND_IDECSR, reg32);
+
+	pci_read_config_dword(devbusfn, PCI_BASE_ADDRESS_0, &ide_bus_offset[0]);
+	ide_bus_offset[0] &= ~1;
+#if CFG_IDE_MAXBUS > 1
+	pci_read_config_dword(devbusfn, PCI_BASE_ADDRESS_2, &ide_bus_offset[1]);
+	ide_bus_offset[1] &= ~1;
+#endif
+
+	/*
+	 * Enable function 1, IDE -> busmastering and IO space access
+	 */
+	pci_read_config_word(devbusfn, PCI_COMMAND, &reg16);
+	reg16 |= PCI_COMMAND_MASTER | PCI_COMMAND_IO;
+	pci_write_config_word(devbusfn, PCI_COMMAND, reg16);
+
+	/*
+	 * Initialise ISA interrupt controller
+	 */
+	initialise_pic();
+
+	/*
+	 * Initialise DMA controller
+	 */
+	initialise_dma();
+}
+
+void initialise_pic(void)
+{
+	out8(W83C553F_PIC1_ICW1, 0x11);
+	out8(W83C553F_PIC1_ICW2, 0x08);
+	out8(W83C553F_PIC1_ICW3, 0x04);
+	out8(W83C553F_PIC1_ICW4, 0x01);
+	out8(W83C553F_PIC1_OCW1, 0xfb);
+	out8(W83C553F_PIC1_ELC, 0x20);
+
+	out8(W83C553F_PIC2_ICW1, 0x11);
+	out8(W83C553F_PIC2_ICW2, 0x08);
+	out8(W83C553F_PIC2_ICW3, 0x02);
+	out8(W83C553F_PIC2_ICW4, 0x01);
+	out8(W83C553F_PIC2_OCW1, 0xff);
+	out8(W83C553F_PIC2_ELC, 0xce);
+
+	out8(W83C553F_TMR1_CMOD, 0x74);
+
+	out8(W83C553F_PIC2_OCW1, 0x20);
+	out8(W83C553F_PIC1_OCW1, 0x20);
+
+	out8(W83C553F_PIC2_OCW1, 0x2b);
+	out8(W83C553F_PIC1_OCW1, 0x2b);
+}
+
+void initialise_dma(void)
+{
+	unsigned int channel;
+	unsigned int rvalue1, rvalue2;
+
+	/* perform a H/W reset of the devices */
+
+	out8(W83C553F_DMA1 + W83C553F_DMA1_MC, 0x00);
+	out16(W83C553F_DMA2 + W83C553F_DMA2_MC, 0x0000);
+
+	/* initialise all channels to a sane state */
+
+	for (channel = 0; channel < 4; channel++) {
+		/*
+		 * dependent upon the channel, setup the specifics:
+		 *
+		 * demand
+		 * address-increment
+		 * autoinitialize-disable
+		 * verify-transfer
+		 */
+
+		switch (channel) {
+		case 0:
+			rvalue1 = (W83C553F_MODE_TM_DEMAND|W83C553F_MODE_CH0SEL|W83C553F_MODE_TT_VERIFY);
+			rvalue2 = (W83C553F_MODE_TM_CASCADE|W83C553F_MODE_CH0SEL);
+			break;
+	    	case 1:
+			rvalue1 = (W83C553F_MODE_TM_DEMAND|W83C553F_MODE_CH1SEL|W83C553F_MODE_TT_VERIFY);
+			rvalue2 = (W83C553F_MODE_TM_DEMAND|W83C553F_MODE_CH1SEL|W83C553F_MODE_TT_VERIFY);
+			break;
+		case 2:
+			rvalue1 = (W83C553F_MODE_TM_DEMAND|W83C553F_MODE_CH2SEL|W83C553F_MODE_TT_VERIFY);
+			rvalue2 = (W83C553F_MODE_TM_DEMAND|W83C553F_MODE_CH2SEL|W83C553F_MODE_TT_VERIFY);
+			break;
+		case 3:
+			rvalue1 = (W83C553F_MODE_TM_DEMAND|W83C553F_MODE_CH3SEL|W83C553F_MODE_TT_VERIFY);
+			rvalue2 = (W83C553F_MODE_TM_DEMAND|W83C553F_MODE_CH3SEL|W83C553F_MODE_TT_VERIFY);
+			break;
+		default:
+			rvalue1 = 0x00;
+			rvalue2 = 0x00;
+			break;
+		}
+
+		/* write to write mode registers */
+
+		out8(W83C553F_DMA1 + W83C553F_DMA1_WM, rvalue1 & 0xFF);
+		out16(W83C553F_DMA2 + W83C553F_DMA2_WM, rvalue2 & 0x00FF);
+	}
+
+	/* enable all channels */
+
+	out8(W83C553F_DMA1 + W83C553F_DMA1_CM, 0x00);
+	out16(W83C553F_DMA2 + W83C553F_DMA2_CM, 0x0000);
+	/*
+	 * initialize the global DMA configuration
+	 *
+	 * DACK# active low
+	 * DREQ active high
+	 * fixed priority
+	 * channel group enable
+	 */
+
+	out8(W83C553F_DMA1 + W83C553F_DMA1_CS, 0x00);
+	out16(W83C553F_DMA2 + W83C553F_DMA2_CS, 0x0000);
+}
+
+#endif /* CFG_WINBOND_83C553 */