summaryrefslogtreecommitdiff
path: root/arch/mips/pci
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/pci')
-rw-r--r--arch/mips/pci/Makefile54
-rw-r--r--arch/mips/pci/fixup-atlas.c69
-rw-r--r--arch/mips/pci/fixup-au1000.c123
-rw-r--r--arch/mips/pci/fixup-capcella.c50
-rw-r--r--arch/mips/pci/fixup-cobalt.c112
-rw-r--r--arch/mips/pci/fixup-ddb5074.c21
-rw-r--r--arch/mips/pci/fixup-ddb5477.c78
-rw-r--r--arch/mips/pci/fixup-ev64120.c34
-rw-r--r--arch/mips/pci/fixup-ev96100.c48
-rw-r--r--arch/mips/pci/fixup-ip32.c51
-rw-r--r--arch/mips/pci/fixup-ite8172g.c80
-rw-r--r--arch/mips/pci/fixup-ivr.c75
-rw-r--r--arch/mips/pci/fixup-jaguar.c43
-rw-r--r--arch/mips/pci/fixup-jmr3927.c105
-rw-r--r--arch/mips/pci/fixup-malta.c103
-rw-r--r--arch/mips/pci/fixup-mpc30x.c50
-rw-r--r--arch/mips/pci/fixup-ocelot-c.c41
-rw-r--r--arch/mips/pci/fixup-ocelot-g.c37
-rw-r--r--arch/mips/pci/fixup-ocelot.c75
-rw-r--r--arch/mips/pci/fixup-ocelot3.c41
-rw-r--r--arch/mips/pci/fixup-rbtx4927.c140
-rw-r--r--arch/mips/pci/fixup-sb1250.c24
-rw-r--r--arch/mips/pci/fixup-sni.c89
-rw-r--r--arch/mips/pci/fixup-tb0219.c66
-rw-r--r--arch/mips/pci/fixup-tb0226.c85
-rw-r--r--arch/mips/pci/fixup-vr4133.c204
-rw-r--r--arch/mips/pci/fixup-yosemite.c41
-rw-r--r--arch/mips/pci/ops-au1000.c325
-rw-r--r--arch/mips/pci/ops-bonito64.c196
-rw-r--r--arch/mips/pci/ops-ddb5074.c271
-rw-r--r--arch/mips/pci/ops-ddb5476.c286
-rw-r--r--arch/mips/pci/ops-ddb5477.c278
-rw-r--r--arch/mips/pci/ops-gt64111.c100
-rw-r--r--arch/mips/pci/ops-gt64120.c154
-rw-r--r--arch/mips/pci/ops-gt96100.c169
-rw-r--r--arch/mips/pci/ops-it8172.c215
-rw-r--r--arch/mips/pci/ops-mace.c91
-rw-r--r--arch/mips/pci/ops-marvell.c93
-rw-r--r--arch/mips/pci/ops-msc.c169
-rw-r--r--arch/mips/pci/ops-nile4.c147
-rw-r--r--arch/mips/pci/ops-sni.c89
-rw-r--r--arch/mips/pci/ops-titan-ht.c125
-rw-r--r--arch/mips/pci/ops-titan.c100
-rw-r--r--arch/mips/pci/ops-tx3927.c391
-rw-r--r--arch/mips/pci/ops-tx4927.c209
-rw-r--r--arch/mips/pci/ops-vr41xx.c126
-rw-r--r--arch/mips/pci/pci-ddb5074.c79
-rw-r--r--arch/mips/pci/pci-ddb5476.c93
-rw-r--r--arch/mips/pci/pci-ddb5477.c207
-rw-r--r--arch/mips/pci/pci-ev96100.c63
-rw-r--r--arch/mips/pci/pci-ip27.c489
-rw-r--r--arch/mips/pci/pci-ip32.c145
-rw-r--r--arch/mips/pci/pci-jmr3927.c58
-rw-r--r--arch/mips/pci/pci-lasat.c95
-rw-r--r--arch/mips/pci/pci-ocelot-c.c143
-rw-r--r--arch/mips/pci/pci-ocelot-g.c97
-rw-r--r--arch/mips/pci/pci-ocelot.c107
-rw-r--r--arch/mips/pci/pci-sb1250.c292
-rw-r--r--arch/mips/pci/pci-vr41xx.c291
-rw-r--r--arch/mips/pci/pci-vr41xx.h151
-rw-r--r--arch/mips/pci/pci-yosemite.c60
-rw-r--r--arch/mips/pci/pci.c304
62 files changed, 8147 insertions, 0 deletions
diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile
new file mode 100644
index 00000000000..c53e4cb359b
--- /dev/null
+++ b/arch/mips/pci/Makefile
@@ -0,0 +1,54 @@
+#
+# Makefile for the PCI specific kernel interface routines under Linux.
+#
+
+obj-y += pci.o
+
+#
+# PCI bus host bridge specific code
+#
+obj-$(CONFIG_ITE_BOARD_GEN) += ops-it8172.o
+obj-$(CONFIG_MIPS_BONITO64) += ops-bonito64.o
+obj-$(CONFIG_MIPS_GT64111) += ops-gt64111.o
+obj-$(CONFIG_MIPS_GT64120) += ops-gt64120.o
+obj-$(CONFIG_MIPS_GT96100) += ops-gt96100.o
+obj-$(CONFIG_PCI_MARVELL) += ops-marvell.o
+obj-$(CONFIG_MIPS_MSC) += ops-msc.o
+obj-$(CONFIG_MIPS_NILE4) += ops-nile4.o
+obj-$(CONFIG_MIPS_TX3927) += ops-jmr3927.o
+obj-$(CONFIG_PCI_VR41XX) += ops-vr41xx.o pci-vr41xx.o
+obj-$(CONFIG_NEC_CMBVR4133) += fixup-vr4133.o
+
+#
+# These are still pretty much in the old state, watch, go blind.
+#
+obj-$(CONFIG_DDB5074) += fixup-ddb5074.o pci-ddb5074.o ops-ddb5074.o
+obj-$(CONFIG_DDB5476) += ops-ddb5476.o pci-ddb5476.o
+obj-$(CONFIG_DDB5477) += fixup-ddb5477.o pci-ddb5477.o ops-ddb5477.o
+obj-$(CONFIG_LASAT) += pci-lasat.o
+obj-$(CONFIG_MIPS_ATLAS) += fixup-atlas.o
+obj-$(CONFIG_MIPS_COBALT) += fixup-cobalt.o
+obj-$(CONFIG_MIPS_EV96100) += fixup-ev64120.o
+obj-$(CONFIG_MIPS_EV96100) += fixup-ev96100.o pci-ev96100.o
+obj-$(CONFIG_MIPS_ITE8172) += fixup-ite8172g.o
+obj-$(CONFIG_MIPS_IVR) += fixup-ivr.o
+obj-$(CONFIG_SOC_AU1500) += fixup-au1000.o ops-au1000.o
+obj-$(CONFIG_SOC_AU1550) += fixup-au1000.o ops-au1000.o
+obj-$(CONFIG_MIPS_MALTA) += fixup-malta.o
+obj-$(CONFIG_MOMENCO_JAGUAR_ATX)+= fixup-jaguar.o
+obj-$(CONFIG_MOMENCO_OCELOT) += fixup-ocelot.o pci-ocelot.o
+obj-$(CONFIG_MOMENCO_OCELOT_3) += fixup-ocelot3.o
+obj-$(CONFIG_MOMENCO_OCELOT_C) += fixup-ocelot-c.o pci-ocelot-c.o
+obj-$(CONFIG_MOMENCO_OCELOT_G) += fixup-ocelot-g.o pci-ocelot-g.o
+obj-$(CONFIG_PMC_YOSEMITE) += fixup-yosemite.o ops-titan.o ops-titan-ht.o \
+ pci-yosemite.o
+obj-$(CONFIG_SGI_IP27) += pci-ip27.o
+obj-$(CONFIG_SGI_IP32) += fixup-ip32.o ops-mace.o pci-ip32.o
+obj-$(CONFIG_SIBYTE_SB1250) += fixup-sb1250.o pci-sb1250.o
+obj-$(CONFIG_SNI_RM200_PCI) += fixup-sni.o ops-sni.o
+obj-$(CONFIG_TANBAC_TB0219) += fixup-tb0219.o
+obj-$(CONFIG_TANBAC_TB0226) += fixup-tb0226.o
+obj-$(CONFIG_TOSHIBA_JMR3927) += fixup-jmr3927.o pci-jmr3927.o
+obj-$(CONFIG_TOSHIBA_RBTX4927) += fixup-rbtx4927.o ops-tx4927.o
+obj-$(CONFIG_VICTOR_MPC30X) += fixup-mpc30x.o
+obj-$(CONFIG_ZAO_CAPCELLA) += fixup-capcella.o
diff --git a/arch/mips/pci/fixup-atlas.c b/arch/mips/pci/fixup-atlas.c
new file mode 100644
index 00000000000..2406835833d
--- /dev/null
+++ b/arch/mips/pci/fixup-atlas.c
@@ -0,0 +1,69 @@
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <asm/mips-boards/atlasint.h>
+
+#define INTD ATLASINT_INTD
+#define INTC ATLASINT_INTC
+#define INTB ATLASINT_INTB
+#define INTA ATLASINT_INTA
+#define SCSI ATLASINT_SCSI
+#define ETH ATLASINT_ETH
+
+static char irq_tab[][5] __initdata = {
+ /* INTA INTB INTC INTD */
+ {0, 0, 0, 0, 0 }, /* 0: Unused */
+ {0, 0, 0, 0, 0 }, /* 1: Unused */
+ {0, 0, 0, 0, 0 }, /* 2: Unused */
+ {0, 0, 0, 0, 0 }, /* 3: Unused */
+ {0, 0, 0, 0, 0 }, /* 4: Unused */
+ {0, 0, 0, 0, 0 }, /* 5: Unused */
+ {0, 0, 0, 0, 0 }, /* 6: Unused */
+ {0, 0, 0, 0, 0 }, /* 7: Unused */
+ {0, 0, 0, 0, 0 }, /* 8: Unused */
+ {0, 0, 0, 0, 0 }, /* 9: Unused */
+ {0, 0, 0, 0, 0 }, /* 10: Unused */
+ {0, 0, 0, 0, 0 }, /* 11: Unused */
+ {0, 0, 0, 0, 0 }, /* 12: Unused */
+ {0, 0, 0, 0, 0 }, /* 13: Unused */
+ {0, 0, 0, 0, 0 }, /* 14: Unused */
+ {0, 0, 0, 0, 0 }, /* 15: Unused */
+ {0, SCSI, 0, 0, 0 }, /* 16: SYM53C810A SCSI */
+ {0, 0, 0, 0, 0 }, /* 17: Core */
+ {0, INTA, INTB, INTC, INTD }, /* 18: PCI Slot 1 */
+ {0, ETH, 0, 0, 0 }, /* 19: SAA9730 Ethernet */
+ {0, 0, 0, 0, 0 }, /* 20: PCI Slot 3 */
+ {0, 0, 0, 0, 0 } /* 21: PCI Slot 4 */
+};
+
+int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ return irq_tab[slot][pin];
+}
+
+/* Do platform specific device initialization at pci_enable_device() time */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+ return 0;
+}
+
+#ifdef CONFIG_KGDB
+/*
+ * The PCI scan may have moved the saa9730 I/O address, so reread
+ * the address here.
+ * This does mean that it's not possible to debug the PCI bus configuration
+ * code, but it is better than nothing...
+ */
+
+static void atlas_saa9730_base_fixup (struct pci_dev *pdev)
+{
+ extern void *saa9730_base;
+ if (pdev->bus == 0 && PCI_SLOT(pdev->devfn) == 19)
+ (void) pci_read_config_dword (pdev, 0x14, (u32 *)&saa9730_base);
+ printk ("saa9730_base = %x\n", saa9730_base);
+}
+
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA9730,
+ atlas_saa9730_base_fixup);
+
+#endif
diff --git a/arch/mips/pci/fixup-au1000.c b/arch/mips/pci/fixup-au1000.c
new file mode 100644
index 00000000000..39fe2b16fce
--- /dev/null
+++ b/arch/mips/pci/fixup-au1000.c
@@ -0,0 +1,123 @@
+/*
+ * BRIEF MODULE DESCRIPTION
+ * Board specific pci fixups.
+ *
+ * Copyright 2001-2003 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ * ppopov@mvista.com or source@mvista.com
+ *
+ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 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.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/mach-au1x00/au1000.h>
+
+/*
+ * Shortcut
+ */
+#ifdef CONFIG_SOC_AU1500
+#define INTA AU1000_PCI_INTA
+#define INTB AU1000_PCI_INTB
+#define INTC AU1000_PCI_INTC
+#define INTD AU1000_PCI_INTD
+#endif
+
+#ifdef CONFIG_SOC_AU1550
+#define INTA AU1550_PCI_INTA
+#define INTB AU1550_PCI_INTB
+#define INTC AU1550_PCI_INTC
+#define INTD AU1550_PCI_INTD
+#endif
+
+#define INTX 0xFF /* not valid */
+
+#ifdef CONFIG_MIPS_DB1500
+static char irq_tab_alchemy[][5] __initdata = {
+ [12] = { -1, INTA, INTX, INTX, INTX}, /* IDSEL 12 - HPT371 */
+ [13] = { -1, INTA, INTB, INTC, INTD}, /* IDSEL 13 - PCI slot */
+};
+#endif
+
+#ifdef CONFIG_MIPS_BOSPORUS
+static char irq_tab_alchemy[][5] __initdata = {
+ [11] = { -1, INTA, INTB, INTX, INTX}, /* IDSEL 11 - miniPCI */
+ [12] = { -1, INTA, INTX, INTX, INTX}, /* IDSEL 12 - SN1741 */
+ [13] = { -1, INTA, INTB, INTC, INTD}, /* IDSEL 13 - PCI slot */
+};
+#endif
+
+#ifdef CONFIG_MIPS_MIRAGE
+static char irq_tab_alchemy[][5] __initdata = {
+ [11] = { -1, INTD, INTX, INTX, INTX}, /* IDSEL 11 - SMI VGX */
+ [12] = { -1, INTX, INTX, INTC, INTX}, /* IDSEL 12 - PNX1300 */
+ [13] = { -1, INTA, INTB, INTX, INTX}, /* IDSEL 13 - miniPCI */
+};
+#endif
+
+#ifdef CONFIG_MIPS_DB1550
+static char irq_tab_alchemy[][5] __initdata = {
+ [11] = { -1, INTC, INTX, INTX, INTX}, /* IDSEL 11 - on-board HPT371 */
+ [12] = { -1, INTB, INTC, INTD, INTA}, /* IDSEL 12 - PCI slot 2 (left) */
+ [13] = { -1, INTA, INTB, INTC, INTD}, /* IDSEL 13 - PCI slot 1 (right) */
+};
+#endif
+
+#ifdef CONFIG_MIPS_PB1500
+static char irq_tab_alchemy[][5] __initdata = {
+ [12] = { -1, INTA, INTX, INTX, INTX}, /* IDSEL 12 - HPT370 */
+ [13] = { -1, INTA, INTB, INTC, INTD}, /* IDSEL 13 - PCI slot */
+};
+#endif
+
+#ifdef CONFIG_MIPS_PB1550
+static char irq_tab_alchemy[][5] __initdata = {
+ [12] = { -1, INTB, INTC, INTD, INTA}, /* IDSEL 12 - PCI slot 2 (left) */
+ [13] = { -1, INTA, INTB, INTC, INTD}, /* IDSEL 13 - PCI slot 1 (right) */
+};
+#endif
+
+#ifdef CONFIG_MIPS_MTX1
+static char irq_tab_alchemy[][5] __initdata = {
+ [0] = { -1, INTA, INTB, INTX, INTX}, /* IDSEL 00 - AdapterA-Slot0 (top) */
+ [1] = { -1, INTB, INTA, INTX, INTX}, /* IDSEL 01 - AdapterA-Slot1 (bottom) */
+ [2] = { -1, INTC, INTD, INTX, INTX}, /* IDSEL 02 - AdapterB-Slot0 (top) */
+ [3] = { -1, INTD, INTC, INTX, INTX}, /* IDSEL 03 - AdapterB-Slot1 (bottom) */
+ [4] = { -1, INTA, INTB, INTX, INTX}, /* IDSEL 04 - AdapterC-Slot0 (top) */
+ [5] = { -1, INTB, INTA, INTX, INTX}, /* IDSEL 05 - AdapterC-Slot1 (bottom) */
+ [6] = { -1, INTC, INTD, INTX, INTX}, /* IDSEL 06 - AdapterD-Slot0 (top) */
+ [7] = { -1, INTD, INTC, INTX, INTX}, /* IDSEL 07 - AdapterD-Slot1 (bottom) */
+};
+#endif
+
+int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ return irq_tab_alchemy[slot][pin];
+}
+
+/* Do platform specific device initialization at pci_enable_device() time */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+ return 0;
+}
diff --git a/arch/mips/pci/fixup-capcella.c b/arch/mips/pci/fixup-capcella.c
new file mode 100644
index 00000000000..f2fc82c1c7c
--- /dev/null
+++ b/arch/mips/pci/fixup-capcella.c
@@ -0,0 +1,50 @@
+/*
+ * fixup-cappcela.c, The ZAO Networks Capcella specific PCI fixups.
+ *
+ * Copyright (C) 2002,2004 Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
+ *
+ * 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 <linux/init.h>
+#include <linux/pci.h>
+
+#include <asm/vr41xx/capcella.h>
+
+/*
+ * Shortcuts
+ */
+#define INT1 RTL8139_1_IRQ
+#define INT2 RTL8139_2_IRQ
+#define INTA PC104PLUS_INTA_IRQ
+#define INTB PC104PLUS_INTB_IRQ
+#define INTC PC104PLUS_INTC_IRQ
+#define INTD PC104PLUS_INTD_IRQ
+
+static char irq_tab_capcella[][5] __initdata = {
+ [11] = { -1, INT1, INT1, INT1, INT1 },
+ [12] = { -1, INT2, INT2, INT2, INT2 },
+ [14] = { -1, INTA, INTB, INTC, INTD }
+};
+
+int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ return irq_tab_capcella[slot][pin];
+}
+
+/* Do platform specific device initialization at pci_enable_device() time */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+ return 0;
+}
diff --git a/arch/mips/pci/fixup-cobalt.c b/arch/mips/pci/fixup-cobalt.c
new file mode 100644
index 00000000000..57e1ca2116b
--- /dev/null
+++ b/arch/mips/pci/fixup-cobalt.c
@@ -0,0 +1,112 @@
+/*
+ * Cobalt Qube/Raq PCI support
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1995, 1996, 1997, 2002, 2003 by Ralf Baechle
+ * Copyright (C) 2001, 2002, 2003 by Liam Davies (ldavies@agile.tv)
+ */
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/pci.h>
+#include <asm/io.h>
+#include <asm/gt64120.h>
+
+#include <asm/cobalt/cobalt.h>
+
+extern int cobalt_board_id;
+
+static void qube_raq_via_bmIDE_fixup(struct pci_dev *dev)
+{
+ unsigned short cfgword;
+ unsigned char lt;
+
+ /* Enable Bus Mastering and fast back to back. */
+ pci_read_config_word(dev, PCI_COMMAND, &cfgword);
+ cfgword |= (PCI_COMMAND_FAST_BACK | PCI_COMMAND_MASTER);
+ pci_write_config_word(dev, PCI_COMMAND, cfgword);
+
+ /* Enable both ide interfaces. ROM only enables primary one. */
+ pci_write_config_byte(dev, 0x40, 0xb);
+
+ /* Set latency timer to reasonable value. */
+ pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lt);
+ if (lt < 64)
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
+ pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 7);
+}
+
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1,
+ qube_raq_via_bmIDE_fixup);
+
+static void qube_raq_galileo_fixup(struct pci_dev *dev)
+{
+ unsigned short galileo_id;
+
+ /* Fix PCI latency-timer and cache-line-size values in Galileo
+ * host bridge.
+ */
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
+ pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 7);
+
+ /*
+ * On all machines prior to Q2, we had the STOP line disconnected
+ * from Galileo to VIA on PCI. The new Galileo does not function
+ * correctly unless we have it connected.
+ *
+ * Therefore we must set the disconnect/retry cycle values to
+ * something sensible when using the new Galileo.
+ */
+ pci_read_config_word(dev, PCI_REVISION_ID, &galileo_id);
+ galileo_id &= 0xff; /* mask off class info */
+ if (galileo_id >= 0x10) {
+ /* New Galileo, assumes PCI stop line to VIA is connected. */
+ GALILEO_OUTL(0x4020, GT_PCI0_TOR_OFS);
+ } else if (galileo_id == 0x1 || galileo_id == 0x2) {
+ signed int timeo;
+ /* XXX WE MUST DO THIS ELSE GALILEO LOCKS UP! -DaveM */
+ timeo = GALILEO_INL(GT_PCI0_TOR_OFS);
+ /* Old Galileo, assumes PCI STOP line to VIA is disconnected. */
+ GALILEO_OUTL(0xffff, GT_PCI0_TOR_OFS);
+ }
+}
+
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_GALILEO, PCI_ANY_ID,
+ qube_raq_galileo_fixup);
+
+static char irq_tab_cobalt[] __initdata = {
+ [COBALT_PCICONF_CPU] = 0,
+ [COBALT_PCICONF_ETH0] = COBALT_ETH0_IRQ,
+ [COBALT_PCICONF_RAQSCSI] = COBALT_SCSI_IRQ,
+ [COBALT_PCICONF_VIA] = 0,
+ [COBALT_PCICONF_PCISLOT] = COBALT_QUBE_SLOT_IRQ,
+ [COBALT_PCICONF_ETH1] = COBALT_ETH1_IRQ
+};
+
+static char irq_tab_raq2[] __initdata = {
+ [COBALT_PCICONF_CPU] = 0,
+ [COBALT_PCICONF_ETH0] = COBALT_ETH0_IRQ,
+ [COBALT_PCICONF_RAQSCSI] = COBALT_RAQ_SCSI_IRQ,
+ [COBALT_PCICONF_VIA] = 0,
+ [COBALT_PCICONF_PCISLOT] = COBALT_QUBE_SLOT_IRQ,
+ [COBALT_PCICONF_ETH1] = COBALT_ETH1_IRQ
+};
+
+int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ if (cobalt_board_id == COBALT_BRD_ID_RAQ2)
+ return irq_tab_raq2[slot];
+
+ return irq_tab_cobalt[slot];
+}
+
+/* Do platform specific device initialization at pci_enable_device() time */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+ return 0;
+}
diff --git a/arch/mips/pci/fixup-ddb5074.c b/arch/mips/pci/fixup-ddb5074.c
new file mode 100644
index 00000000000..b345e528a53
--- /dev/null
+++ b/arch/mips/pci/fixup-ddb5074.c
@@ -0,0 +1,21 @@
+/*
+ * It's nice to have the LEDs on the GPIO pins available for debugging
+ */
+static void ddb5074_fixup(struct pci_dev *dev)
+{
+ extern struct pci_dev *pci_pmu;
+ u8 t8;
+
+ pci_pmu = dev; /* for LEDs D2 and D3 */
+ /* Program the lines for LEDs D2 and D3 to output */
+ pci_read_config_byte(dev, 0x7d, &t8);
+ t8 |= 0xc0;
+ pci_write_config_byte(dev, 0x7d, t8);
+ /* Turn LEDs D2 and D3 off */
+ pci_read_config_byte(dev, 0x7e, &t8);
+ t8 |= 0xc0;
+ pci_write_config_byte(dev, 0x7e, t8);
+}
+
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101,
+ ddb5074_fixup);
diff --git a/arch/mips/pci/fixup-ddb5477.c b/arch/mips/pci/fixup-ddb5477.c
new file mode 100644
index 00000000000..6abdc88bab1
--- /dev/null
+++ b/arch/mips/pci/fixup-ddb5477.c
@@ -0,0 +1,78 @@
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ * Board specific pci fixups.
+ *
+ * Copyright 2001, 2002, 2003 MontaVista Software Inc.
+ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
+ *
+ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 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.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+static void ddb5477_fixup(struct pci_dev *dev)
+{
+ u8 old;
+
+ printk(KERN_NOTICE "Enabling ALI M1533/35 PS2 keyboard/mouse.\n");
+ pci_read_config_byte(dev, 0x41, &old);
+ pci_write_config_byte(dev, 0x41, old | 0xd0);
+}
+
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533,
+ ddb5477_fixup);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1535,
+ ddb5477_fixup);
+
+/*
+ * Fixup baseboard AMD chip so that tx does not underflow.
+ * bcr_18 |= 0x0800
+ * This sets NOUFLO bit which makes tx not start until whole pkt
+ * is fetched to the chip.
+ */
+#define PCNET32_WIO_RDP 0x10
+#define PCNET32_WIO_RAP 0x12
+#define PCNET32_WIO_RESET 0x14
+#define PCNET32_WIO_BDP 0x16
+
+static void ddb5477_amd_lance_fixup(struct pci_dev *dev)
+{
+ unsigned long ioaddr;
+ u16 temp;
+
+ ioaddr = pci_resource_start(dev, 0);
+
+ inw(ioaddr + PCNET32_WIO_RESET); /* reset chip */
+
+ /* bcr_18 |= 0x0800 */
+ outw(18, ioaddr + PCNET32_WIO_RAP);
+ temp = inw(ioaddr + PCNET32_WIO_BDP);
+ temp |= 0x0800;
+ outw(18, ioaddr + PCNET32_WIO_RAP);
+ outw(temp, ioaddr + PCNET32_WIO_BDP);
+}
+
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE,
+ ddb5477_amd_lance_fixup);
diff --git a/arch/mips/pci/fixup-ev64120.c b/arch/mips/pci/fixup-ev64120.c
new file mode 100644
index 00000000000..8dbb90d63f0
--- /dev/null
+++ b/arch/mips/pci/fixup-ev64120.c
@@ -0,0 +1,34 @@
+#include <linux/pci.h>
+#include <linux/init.h>
+
+int pci_range_ck(unsigned char bus, unsigned char dev)
+{
+ if (((bus == 0) || (bus == 1)) && (dev >= 6) && (dev <= 8))
+ return 0;
+
+ return -1;
+}
+
+/*
+ * After detecting all agents over the PCI , this function is called
+ * in order to give an interrupt number for each PCI device starting
+ * from IRQ 20. It does also enables master for each device.
+ */
+void __devinit pcibios_fixup_bus(struct pci_bus *bus)
+{
+ unsigned int irq = 20;
+ struct pci_bus *current_bus = bus;
+ struct pci_dev *dev;
+ struct list_head *devices_link;
+
+ list_for_each(devices_link, &(current_bus->devices)) {
+ dev = pci_dev_b(devices_link);
+ if (dev != NULL) {
+ dev->irq = irq++;
+
+ /* Assign an interrupt number for the device */
+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
+ pcibios_set_master(dev);
+ }
+ }
+}
diff --git a/arch/mips/pci/fixup-ev96100.c b/arch/mips/pci/fixup-ev96100.c
new file mode 100644
index 00000000000..e2bc977b6d5
--- /dev/null
+++ b/arch/mips/pci/fixup-ev96100.c
@@ -0,0 +1,48 @@
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ * EV96100 Board specific pci fixups.
+ *
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ * ppopov@mvista.com or source@mvista.com
+ *
+ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 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.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+
+static char irq_tab_ev96100[][5] __initdata = {
+ [8] = { 0, 5, 5, 5, 5 },
+ [9] = { 0, 2, 2, 2, 2 }
+};
+
+int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ return irq_tab_ev96100[slot][pin];
+}
+
+/* Do platform specific device initialization at pci_enable_device() time */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+ return 0;
+}
diff --git a/arch/mips/pci/fixup-ip32.c b/arch/mips/pci/fixup-ip32.c
new file mode 100644
index 00000000000..3e66b0aa63c
--- /dev/null
+++ b/arch/mips/pci/fixup-ip32.c
@@ -0,0 +1,51 @@
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <asm/ip32/ip32_ints.h>
+/*
+ * O2 has up to 5 PCI devices connected into the MACE bridge. The device
+ * map looks like this:
+ *
+ * 0 aic7xxx 0
+ * 1 aic7xxx 1
+ * 2 expansion slot
+ * 3 N/C
+ * 4 N/C
+ */
+
+#define SCSI0 MACEPCI_SCSI0_IRQ
+#define SCSI1 MACEPCI_SCSI1_IRQ
+#define INTA0 MACEPCI_SLOT0_IRQ
+#define INTA1 MACEPCI_SLOT1_IRQ
+#define INTA2 MACEPCI_SLOT2_IRQ
+#define INTB MACEPCI_SHARED0_IRQ
+#define INTC MACEPCI_SHARED1_IRQ
+#define INTD MACEPCI_SHARED2_IRQ
+static char irq_tab_mace[][5] __initdata = {
+ /* Dummy INT#A INT#B INT#C INT#D */
+ {0, 0, 0, 0, 0}, /* This is placeholder row - never used */
+ {0, SCSI0, SCSI0, SCSI0, SCSI0},
+ {0, SCSI1, SCSI1, SCSI1, SCSI1},
+ {0, INTA0, INTB, INTC, INTD},
+ {0, INTA1, INTC, INTD, INTB},
+ {0, INTA2, INTD, INTB, INTC},
+};
+
+
+/*
+ * Given a PCI slot number (a la PCI_SLOT(...)) and the interrupt pin of
+ * the device (1-4 => A-D), tell what irq to use. Note that we don't
+ * in theory have slots 4 and 5, and we never normally use the shared
+ * irqs. I suppose a device without a pin A will thank us for doing it
+ * right if there exists such a broken piece of crap.
+ */
+int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ return irq_tab_mace[slot][pin];
+}
+
+/* Do platform specific device initialization at pci_enable_device() time */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+ return 0;
+}
diff --git a/arch/mips/pci/fixup-ite8172g.c b/arch/mips/pci/fixup-ite8172g.c
new file mode 100644
index 00000000000..2290ea4228d
--- /dev/null
+++ b/arch/mips/pci/fixup-ite8172g.c
@@ -0,0 +1,80 @@
+/*
+ * BRIEF MODULE DESCRIPTION
+ * Board specific pci fixups.
+ *
+ * Copyright 2000 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ * ppopov@mvista.com or source@mvista.com
+ *
+ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 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.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/it8172/it8172.h>
+#include <asm/it8172/it8172_pci.h>
+#include <asm/it8172/it8172_int.h>
+
+/*
+ * Shortcuts
+ */
+#define INTA IT8172_PCI_INTA_IRQ
+#define INTB IT8172_PCI_INTB_IRQ
+#define INTC IT8172_PCI_INTC_IRQ
+#define INTD IT8172_PCI_INTD_IRQ
+
+static const int internal_func_irqs[7] __initdata = {
+ IT8172_AC97_IRQ,
+ IT8172_DMA_IRQ,
+ IT8172_CDMA_IRQ,
+ IT8172_USB_IRQ,
+ IT8172_BRIDGE_MASTER_IRQ,
+ IT8172_IDE_IRQ,
+ IT8172_MC68K_IRQ
+};
+
+static char irq_tab_ite8172g[][5] __initdata = {
+ [0x10] = { 0, INTA, INTB, INTC, INTD },
+ [0x11] = { 0, INTA, INTB, INTC, INTD },
+ [0x12] = { 0, INTB, INTC, INTD, INTA },
+ [0x13] = { 0, INTC, INTD, INTA, INTB },
+ [0x14] = { 0, INTD, INTA, INTB, INTC },
+};
+
+int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ /*
+ * Internal device 1 is actually 7 different internal devices on the
+ * IT8172G (a multifunction device).
+ */
+ if (slot == 1)
+ return internal_func_irqs[PCI_FUNC(dev->devfn)];
+
+ return irq_tab_ite8172g[slot][pin];
+}
+
+/* Do platform specific device initialization at pci_enable_device() time */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+ return 0;
+}
diff --git a/arch/mips/pci/fixup-ivr.c b/arch/mips/pci/fixup-ivr.c
new file mode 100644
index 00000000000..0c7c16464c1
--- /dev/null
+++ b/arch/mips/pci/fixup-ivr.c
@@ -0,0 +1,75 @@
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ * Globespan IVR board-specific pci fixups.
+ *
+ * Copyright 2000 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ * ppopov@mvista.com or source@mvista.com
+ *
+ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 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.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/it8172/it8172.h>
+#include <asm/it8172/it8172_pci.h>
+#include <asm/it8172/it8172_int.h>
+
+/*
+ * Shortcuts
+ */
+#define INTA IT8172_PCI_INTA_IRQ
+#define INTB IT8172_PCI_INTB_IRQ
+#define INTC IT8172_PCI_INTC_IRQ
+#define INTD IT8172_PCI_INTD_IRQ
+
+static const int internal_func_irqs[7] __initdata = {
+ IT8172_AC97_IRQ,
+ IT8172_DMA_IRQ,
+ IT8172_CDMA_IRQ,
+ IT8172_USB_IRQ,
+ IT8172_BRIDGE_MASTER_IRQ,
+ IT8172_IDE_IRQ,
+ IT8172_MC68K_IRQ
+};
+
+static char irq_tab_ivr[][5] __initdata = {
+ [0x11] = { INTC, INTC, INTD, INTA, INTB }, /* Realtek RTL-8139 */
+ [0x12] = { INTB, INTB, INTB, INTC, INTC }, /* IVR slot */
+ [0x13] = { INTA, INTA, INTB, INTC, INTD } /* Expansion slot */
+};
+
+int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ if (slot == 1)
+ return internal_func_irqs[PCI_FUNC(dev->devfn)];
+
+ return irq_tab_ivr[slot][pin];
+}
+
+/* Do platform specific device initialization at pci_enable_device() time */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+ return 0;
+}
diff --git a/arch/mips/pci/fixup-jaguar.c b/arch/mips/pci/fixup-jaguar.c
new file mode 100644
index 00000000000..6c5e1d47179
--- /dev/null
+++ b/arch/mips/pci/fixup-jaguar.c
@@ -0,0 +1,43 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Marvell MV64340 interrupt fixup code.
+ *
+ * Marvell wants an NDA for their docs so this was written without
+ * documentation. You've been warned.
+ *
+ * Copyright (C) 2004 Ralf Baechle (ralf@linux-mips.org)
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+
+#include <asm/mipsregs.h>
+
+/*
+ * WARNING: Example of how _NOT_ to do it.
+ */
+int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ int bus = dev->bus->number;
+
+ if (bus == 0 && slot == 1)
+ return 3; /* PCI-X A */
+ if (bus == 0 && slot == 2)
+ return 4; /* PCI-X B */
+ if (bus == 1 && slot == 1)
+ return 5; /* PCI A */
+ if (bus == 1 && slot == 2)
+ return 6; /* PCI B */
+
+return 0;
+ panic("Whooops in pcibios_map_irq");
+}
+
+/* Do platform specific device initialization at pci_enable_device() time */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+ return 0;
+}
diff --git a/arch/mips/pci/fixup-jmr3927.c b/arch/mips/pci/fixup-jmr3927.c
new file mode 100644
index 00000000000..f8696081c5b
--- /dev/null
+++ b/arch/mips/pci/fixup-jmr3927.c
@@ -0,0 +1,105 @@
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ * Board specific pci fixups.
+ *
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ * ppopov@mvista.com or source@mvista.com
+ *
+ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 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.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/jmr3927/jmr3927.h>
+
+int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ unsigned char irq = pin;
+
+ /* IRQ rotation (PICMG) */
+ irq--; /* 0-3 */
+ if (dev->bus->parent == NULL &&
+ slot == TX3927_PCIC_IDSEL_AD_TO_SLOT(23)) {
+ /* PCI CardSlot (IDSEL=A23, DevNu=12) */
+ /* PCIA => PCIC (IDSEL=A23) */
+ /* NOTE: JMR3927 JP1 must be set to OPEN */
+ irq = (irq + 2) % 4;
+ } else if (dev->bus->parent == NULL &&
+ slot == TX3927_PCIC_IDSEL_AD_TO_SLOT(22)) {
+ /* PCI CardSlot (IDSEL=A22, DevNu=11) */
+ /* PCIA => PCIA (IDSEL=A22) */
+ /* NOTE: JMR3927 JP1 must be set to OPEN */
+ irq = (irq + 0) % 4;
+ } else {
+ /* PCI Backplane */
+ irq = (irq + 3 + slot) % 4;
+ }
+ irq++; /* 1-4 */
+
+ switch (irq) {
+ case 1:
+ irq = JMR3927_IRQ_IOC_PCIA;
+ break;
+ case 2:
+ // wrong for backplane irq = JMR3927_IRQ_IOC_PCIB;
+ irq = JMR3927_IRQ_IOC_PCID;
+ break;
+ case 3:
+ irq = JMR3927_IRQ_IOC_PCIC;
+ break;
+ case 4:
+ // wrong for backplane irq = JMR3927_IRQ_IOC_PCID;
+ irq = JMR3927_IRQ_IOC_PCIB;
+ break;
+ }
+
+ /* Check OnBoard Ethernet (IDSEL=A24, DevNu=13) */
+ if (dev->bus->parent == NULL &&
+ slot == TX3927_PCIC_IDSEL_AD_TO_SLOT(24)) {
+ extern int jmr3927_ether1_irq;
+ /* check this irq line was reserved for ether1 */
+ if (jmr3927_ether1_irq != JMR3927_IRQ_ETHER0)
+ irq = JMR3927_IRQ_ETHER0;
+ else
+ irq = 0; /* disable */
+ }
+ return irq;
+}
+
+/* Do platform specific device initialization at pci_enable_device() time */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+ return 0;
+}
+
+int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ /* SMSC SLC90E66 IDE uses irq 14, 15 (default) */
+ if (!(dev->vendor == PCI_VENDOR_ID_EFAR &&
+ dev->device == PCI_DEVICE_ID_EFAR_SLC90E66_1))
+ return pci_get_irq(dev, pin);
+
+ dev->irq = irq;
+}
diff --git a/arch/mips/pci/fixup-malta.c b/arch/mips/pci/fixup-malta.c
new file mode 100644
index 00000000000..b9296d9942b
--- /dev/null
+++ b/arch/mips/pci/fixup-malta.c
@@ -0,0 +1,103 @@
+#include <linux/init.h>
+#include <linux/pci.h>
+
+/* PCI interrupt pins */
+#define PCIA 1
+#define PCIB 2
+#define PCIC 3
+#define PCID 4
+
+/* This table is filled in by interrogating the PIIX4 chip */
+static char pci_irq[5] __initdata;
+
+static char irq_tab[][5] __initdata = {
+ /* INTA INTB INTC INTD */
+ {0, 0, 0, 0, 0 }, /* 0: GT64120 PCI bridge */
+ {0, 0, 0, 0, 0 }, /* 1: Unused */
+ {0, 0, 0, 0, 0 }, /* 2: Unused */
+ {0, 0, 0, 0, 0 }, /* 3: Unused */
+ {0, 0, 0, 0, 0 }, /* 4: Unused */
+ {0, 0, 0, 0, 0 }, /* 5: Unused */
+ {0, 0, 0, 0, 0 }, /* 6: Unused */
+ {0, 0, 0, 0, 0 }, /* 7: Unused */
+ {0, 0, 0, 0, 0 }, /* 8: Unused */
+ {0, 0, 0, 0, 0 }, /* 9: Unused */
+ {0, 0, 0, 0, PCID }, /* 10: PIIX4 USB */
+ {0, PCIB, 0, 0, 0 }, /* 11: AMD 79C973 Ethernet */
+ {0, PCIC, 0, 0, 0 }, /* 12: Crystal 4281 Sound */
+ {0, 0, 0, 0, 0 }, /* 13: Unused */
+ {0, 0, 0, 0, 0 }, /* 14: Unused */
+ {0, 0, 0, 0, 0 }, /* 15: Unused */
+ {0, 0, 0, 0, 0 }, /* 16: Unused */
+ {0, 0, 0, 0, 0 }, /* 17: Bonito/SOC-it PCI Bridge*/
+ {0, PCIA, PCIB, PCIC, PCID }, /* 18: PCI Slot 1 */
+ {0, PCIB, PCIC, PCID, PCIA }, /* 19: PCI Slot 2 */
+ {0, PCIC, PCID, PCIA, PCIB }, /* 20: PCI Slot 3 */
+ {0, PCID, PCIA, PCIB, PCIC } /* 21: PCI Slot 4 */
+};
+
+int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ int virq;
+ virq = irq_tab[slot][pin];
+ return pci_irq[virq];
+}
+
+/* Do platform specific device initialization at pci_enable_device() time */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+ return 0;
+}
+
+static void __init malta_piix_func0_fixup(struct pci_dev *pdev)
+{
+ unsigned char reg_val;
+ static int piixirqmap[16] __initdata = { /* PIIX PIRQC[A:D] irq mappings */
+ 0, 0, 0, 3,
+ 4, 5, 6, 7,
+ 0, 9, 10, 11,
+ 12, 0, 14, 15
+ };
+ int i;
+
+ /* Interrogate PIIX4 to get PCI IRQ mapping */
+ for (i = 0; i <= 3; i++) {
+ pci_read_config_byte(pdev, 0x60+i, &reg_val);
+ if (reg_val & 0x80)
+ pci_irq[PCIA+i] = 0; /* Disabled */
+ else
+ pci_irq[PCIA+i] = piixirqmap[reg_val & 15];
+ }
+
+ /* Done by YAMON 2.00 onwards */
+ if (PCI_SLOT(pdev->devfn) == 10) {
+ /*
+ * Set top of main memory accessible by ISA or DMA
+ * devices to 16 Mb.
+ */
+ pci_read_config_byte(pdev, 0x69, &reg_val);
+ pci_write_config_byte(pdev, 0x69, reg_val | 0xf0);
+ }
+}
+
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0,
+ malta_piix_func0_fixup);
+
+static void __init malta_piix_func1_fixup(struct pci_dev *pdev)
+{
+ unsigned char reg_val;
+
+ /* Done by YAMON 2.02 onwards */
+ if (PCI_SLOT(pdev->devfn) == 10) {
+ /*
+ * IDE Decode enable.
+ */
+ pci_read_config_byte(pdev, 0x41, &reg_val);
+ pci_write_config_byte(pdev, 0x41, reg_val|0x80);
+ pci_read_config_byte(pdev, 0x43, &reg_val);
+ pci_write_config_byte(pdev, 0x43, reg_val|0x80);
+ }
+}
+
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB,
+ malta_piix_func1_fixup);
diff --git a/arch/mips/pci/fixup-mpc30x.c b/arch/mips/pci/fixup-mpc30x.c
new file mode 100644
index 00000000000..4975846da75
--- /dev/null
+++ b/arch/mips/pci/fixup-mpc30x.c
@@ -0,0 +1,50 @@
+/*
+ * fixup-mpc30x.c, The Victor MP-C303/304 specific PCI fixups.
+ *
+ * Copyright (C) 2002,2004 Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
+ *
+ * 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 <linux/init.h>
+#include <linux/pci.h>
+
+#include <asm/vr41xx/mpc30x.h>
+#include <asm/vr41xx/vrc4173.h>
+
+static const int internal_func_irqs[] __initdata = {
+ VRC4173_CASCADE_IRQ,
+ VRC4173_AC97_IRQ,
+ VRC4173_USB_IRQ,
+};
+
+static const int irq_tab_mpc30x[] __initdata = {
+ [12] = VRC4173_PCMCIA1_IRQ,
+ [13] = VRC4173_PCMCIA2_IRQ,
+ [29] = MQ200_IRQ,
+};
+
+int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ if (slot == 30)
+ return internal_func_irqs[PCI_FUNC(dev->devfn)];
+
+ return irq_tab_mpc30x[slot];
+}
+
+/* Do platform specific device initialization at pci_enable_device() time */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+ return 0;
+}
diff --git a/arch/mips/pci/fixup-ocelot-c.c b/arch/mips/pci/fixup-ocelot-c.c
new file mode 100644
index 00000000000..d45494807a3
--- /dev/null
+++ b/arch/mips/pci/fixup-ocelot-c.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2002 Momentum Computer Inc.
+ * Author: Matthew Dharm <mdharm@momenco.com>
+ *
+ * Based on work for the Linux port to the Ocelot board, which is
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
+ *
+ * arch/mips/momentum/ocelot_g/pci.c
+ * Board-specific PCI routines for mv64340 controller.
+ *
+ * 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 <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ int bus = dev->bus->number;
+
+ if (bus == 0 && slot == 1)
+ return 2; /* PCI-X A */
+ if (bus == 1 && slot == 1)
+ return 12; /* PCI-X B */
+ if (bus == 1 && slot == 2)
+ return 4; /* PCI B */
+
+return 0;
+ panic("Whooops in pcibios_map_irq");
+}
+
+/* Do platform specific device initialization at pci_enable_device() time */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+ return 0;
+}
diff --git a/arch/mips/pci/fixup-ocelot-g.c b/arch/mips/pci/fixup-ocelot-g.c
new file mode 100644
index 00000000000..d7a652e326c
--- /dev/null
+++ b/arch/mips/pci/fixup-ocelot-g.c
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2004 Ralf Baechle (ralf@linux-mips.org)
+ */
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ int bus = dev->bus->number;
+
+ if (bus == 0 && slot == 1) /* Intel 82543 Gigabit MAC */
+ return 2; /* irq_nr is 2 for INT0 */
+
+ if (bus == 0 && slot == 2) /* Intel 82543 Gigabit MAC */
+ return 3; /* irq_nr is 3 for INT1 */
+
+ if (bus == 1 && slot == 3) /* Intel 21555 bridge */
+ return 5; /* irq_nr is 8 for INT6 */
+
+ if (bus == 1 && slot == 4) /* PMC Slot */
+ return 9; /* irq_nr is 9 for INT7 */
+
+ return -1;
+}
+
+/* Do platform specific device initialization at pci_enable_device() time */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+ return 0;
+}
diff --git a/arch/mips/pci/fixup-ocelot.c b/arch/mips/pci/fixup-ocelot.c
new file mode 100644
index 00000000000..99629bd047c
--- /dev/null
+++ b/arch/mips/pci/fixup-ocelot.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
+ *
+ * arch/mips/gt64120/momenco_ocelot/pci.c
+ * Board-specific PCI routines for gt64120 controller.
+ *
+ * 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 <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <asm/pci.h>
+
+
+void __devinit pcibios_fixup_bus(struct pci_bus *bus)
+{
+ struct pci_bus *current_bus = bus;
+ struct pci_dev *devices;
+ struct list_head *devices_link;
+ u16 cmd;
+
+ list_for_each(devices_link, &(current_bus->devices)) {
+
+ devices = pci_dev_b(devices_link);
+ if (devices == NULL)
+ continue;
+
+ if (PCI_SLOT(devices->devfn) == 1) {
+ /*
+ * Slot 1 is primary ether port, i82559
+ * we double-check against that assumption
+ */
+ if ((devices->vendor != 0x8086) ||
+ (devices->device != 0x1209)) {
+ panic("pcibios_fixup_bus: found "
+ "unexpected PCI device in slot 1.");
+ }
+ devices->irq = 2; /* irq_nr is 2 for INT0 */
+ } else if (PCI_SLOT(devices->devfn) == 2) {
+ /*
+ * Slot 2 is secondary ether port, i21143
+ * we double-check against that assumption
+ */
+ if ((devices->vendor != 0x1011) ||
+ (devices->device != 0x19)) {
+ panic("galileo_pcibios_fixup_bus: "
+ "found unexpected PCI device in slot 2.");
+ }
+ devices->irq = 3; /* irq_nr is 3 for INT1 */
+ } else if (PCI_SLOT(devices->devfn) == 4) {
+ /* PMC Slot 1 */
+ devices->irq = 8; /* irq_nr is 8 for INT6 */
+ } else if (PCI_SLOT(devices->devfn) == 5) {
+ /* PMC Slot 1 */
+ devices->irq = 9; /* irq_nr is 9 for INT7 */
+ } else {
+ /* We don't have assign interrupts for other devices. */
+ devices->irq = 0xff;
+ }
+
+ /* Assign an interrupt number for the device */
+ bus->ops->write_byte(devices, PCI_INTERRUPT_LINE,
+ devices->irq);
+
+ /* enable master */
+ bus->ops->read_word(devices, PCI_COMMAND, &cmd);
+ cmd |= PCI_COMMAND_MASTER;
+ bus->ops->write_word(devices, PCI_COMMAND, cmd);
+ }
+}
diff --git a/arch/mips/pci/fixup-ocelot3.c b/arch/mips/pci/fixup-ocelot3.c
new file mode 100644
index 00000000000..ececc03ec62
--- /dev/null
+++ b/arch/mips/pci/fixup-ocelot3.c
@@ -0,0 +1,41 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2004 Montavista Software Inc.
+ * Author: Manish Lachwani (mlachwani@mvista.com)
+ *
+ * Looking at the schematics for the Ocelot-3 board, there are
+ * two PCI busses and each bus has two PCI slots.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <asm/mipsregs.h>
+
+/*
+ * Do platform specific device initialization at
+ * pci_enable_device() time
+ */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+ return 0;
+}
+
+int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ int bus = dev->bus->number;
+
+ if (bus == 0 && slot == 1)
+ return 2; /* PCI-X A */
+ if (bus == 0 && slot == 2)
+ return 3; /* PCI-X B */
+ if (bus == 1 && slot == 1)
+ return 4; /* PCI A */
+ if (bus == 1 && slot == 2)
+ return 5; /* PCI B */
+
+return 0;
+ panic("Whooops in pcibios_map_irq");
+}
diff --git a/arch/mips/pci/fixup-rbtx4927.c b/arch/mips/pci/fixup-rbtx4927.c
new file mode 100644
index 00000000000..de4e443da20
--- /dev/null
+++ b/arch/mips/pci/fixup-rbtx4927.c
@@ -0,0 +1,140 @@
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ * Board specific pci fixups for the Toshiba rbtx4927
+ *
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ * ppopov@mvista.com or source@mvista.com
+ *
+ * Copyright (C) 2000-2001 Toshiba Corporation
+ *
+ * Copyright (C) 2004 MontaVista Software Inc.
+ * Author: Manish Lachwani (mlachwani@mvista.com)
+ *
+ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 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.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/tx4927/tx4927.h>
+#include <asm/tx4927/tx4927_pci.h>
+
+#undef DEBUG
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+/* look up table for backplane pci irq for slots 17-20 by pin # */
+static unsigned char backplane_pci_irq[4][4] = {
+ /* PJ6 SLOT: 17, PIN: 1 */ {TX4927_IRQ_IOC_PCIA,
+ /* PJ6 SLOT: 17, PIN: 2 */
+ TX4927_IRQ_IOC_PCIB,
+ /* PJ6 SLOT: 17, PIN: 3 */
+ TX4927_IRQ_IOC_PCIC,
+ /* PJ6 SLOT: 17, PIN: 4 */
+ TX4927_IRQ_IOC_PCID},
+ /* SB SLOT: 18, PIN: 1 */ {TX4927_IRQ_IOC_PCIB,
+ /* SB SLOT: 18, PIN: 2 */
+ TX4927_IRQ_IOC_PCIC,
+ /* SB SLOT: 18, PIN: 3 */
+ TX4927_IRQ_IOC_PCID,
+ /* SB SLOT: 18, PIN: 4 */
+ TX4927_IRQ_IOC_PCIA},
+ /* PJ5 SLOT: 19, PIN: 1 */ {TX4927_IRQ_IOC_PCIC,
+ /* PJ5 SLOT: 19, PIN: 2 */
+ TX4927_IRQ_IOC_PCID,
+ /* PJ5 SLOT: 19, PIN: 3 */
+ TX4927_IRQ_IOC_PCIA,
+ /* PJ5 SLOT: 19, PIN: 4 */
+ TX4927_IRQ_IOC_PCIB},
+ /* PJ4 SLOT: 20, PIN: 1 */ {TX4927_IRQ_IOC_PCID,
+ /* PJ4 SLOT: 20, PIN: 2 */
+ TX4927_IRQ_IOC_PCIA,
+ /* PJ4 SLOT: 20, PIN: 3 */
+ TX4927_IRQ_IOC_PCIB,
+ /* PJ4 SLOT: 20, PIN: 4 */
+ TX4927_IRQ_IOC_PCIC}
+};
+
+int pci_get_irq(struct pci_dev *dev, int pin)
+{
+ unsigned char irq = pin;
+
+ DBG("pci_get_irq: pin is %d\n", pin);
+ /* IRQ rotation */
+ irq--; /* 0-3 */
+ if (dev->bus->parent == NULL &&
+ PCI_SLOT(dev->devfn) == TX4927_PCIC_IDSEL_AD_TO_SLOT(23)) {
+ printk("Onboard PCI_SLOT(dev->devfn) is %d\n",
+ PCI_SLOT(dev->devfn));
+ /* IDSEL=A23 is tx4927 onboard pci slot */
+ irq = (irq + PCI_SLOT(dev->devfn)) % 4;
+ irq++; /* 1-4 */
+ DBG("irq is now %d\n", irq);
+
+ switch (irq) {
+ case 1:
+ irq = TX4927_IRQ_IOC_PCIA;
+ break;
+ case 2:
+ irq = TX4927_IRQ_IOC_PCIB;
+ break;
+ case 3:
+ irq = TX4927_IRQ_IOC_PCIC;
+ break;
+ case 4:
+ irq = TX4927_IRQ_IOC_PCID;
+ break;
+ }
+ } else {
+ /* PCI Backplane */
+ DBG("PCI Backplane PCI_SLOT(dev->devfn) is %d\n",
+ PCI_SLOT(dev->devfn));
+ irq = backplane_pci_irq[PCI_SLOT(dev->devfn) - 17][irq];
+ }
+ DBG("assigned irq %d\n", irq);
+ return irq;
+}
+
+int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ unsigned char irq;
+
+ printk("PCI Setup for pin %d \n", pin);
+
+ if (dev->device == 0x9130) /* IDE */
+ irq = 14;
+ else
+ irq = pci_get_irq(dev, pin);
+
+ return irq;
+}
+
+/* Do platform specific device initialization at pci_enable_device() time */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+ return 0;
+}
diff --git a/arch/mips/pci/fixup-sb1250.c b/arch/mips/pci/fixup-sb1250.c
new file mode 100644
index 00000000000..13791b78e59
--- /dev/null
+++ b/arch/mips/pci/fixup-sb1250.c
@@ -0,0 +1,24 @@
+/*
+ * arch/mips/pci/fixup-sb1250.c
+ *
+ * Copyright (C) 2004 MIPS Technologies, Inc. All rights reserved.
+ * Author: Maciej W. Rozycki <macro@mips.com>
+ *
+ * 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 <linux/init.h>
+#include <linux/pci.h>
+
+/*
+ * The BCM1250, etc. PCI/HT bridge reports as a host bridge.
+ */
+static void __init quirk_sb1250_ht(struct pci_dev *dev)
+{
+ dev->class = PCI_CLASS_BRIDGE_PCI << 8;
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SIBYTE, PCI_DEVICE_ID_BCM1250_HT,
+ quirk_sb1250_ht);
diff --git a/arch/mips/pci/fixup-sni.c b/arch/mips/pci/fixup-sni.c
new file mode 100644
index 00000000000..c8ef01a017c
--- /dev/null
+++ b/arch/mips/pci/fixup-sni.c
@@ -0,0 +1,89 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * SNI specific PCI support for RM200/RM300.
+ *
+ * Copyright (C) 1997 - 2000, 2003, 04 Ralf Baechle (ralf@linux-mips.org)
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+
+#include <asm/mipsregs.h>
+#include <asm/sni.h>
+
+/*
+ * Shortcuts ...
+ */
+#define SCSI PCIMT_IRQ_SCSI
+#define ETH PCIMT_IRQ_ETHERNET
+#define INTA PCIMT_IRQ_INTA
+#define INTB PCIMT_IRQ_INTB
+#define INTC PCIMT_IRQ_INTC
+#define INTD PCIMT_IRQ_INTD
+
+/*
+ * Device 0: PCI EISA Bridge (directly routed)
+ * Device 1: NCR53c810 SCSI (directly routed)
+ * Device 2: PCnet32 Ethernet (directly routed)
+ * Device 3: VGA (routed to INTB)
+ * Device 4: Unused
+ * Device 5: Slot 2
+ * Device 6: Slot 3
+ * Device 7: Slot 4
+ *
+ * Documentation says the VGA is device 5 and device 3 is unused but that
+ * seem to be a documentation error. At least on my RM200C the Cirrus
+ * Logic CL-GD5434 VGA is device 3.
+ */
+static char irq_tab_rm200[8][5] __initdata = {
+ /* INTA INTB INTC INTD */
+ { 0, 0, 0, 0, 0 }, /* EISA bridge */
+ { SCSI, SCSI, SCSI, SCSI, SCSI }, /* SCSI */
+ { ETH, ETH, ETH, ETH, ETH }, /* Ethernet */
+ { INTB, INTB, INTB, INTB, INTB }, /* VGA */
+ { 0, 0, 0, 0, 0 }, /* Unused */
+ { 0, INTB, INTC, INTD, INTA }, /* Slot 2 */
+ { 0, INTC, INTD, INTA, INTB }, /* Slot 3 */
+ { 0, INTD, INTA, INTB, INTC }, /* Slot 4 */
+};
+
+/*
+ * In Revision D of the RM300 Device 2 has become a normal purpose Slot 1
+ *
+ * The VGA card is optional for RM300 systems.
+ */
+static char irq_tab_rm300d[8][5] __initdata = {
+ /* INTA INTB INTC INTD */
+ { 0, 0, 0, 0, 0 }, /* EISA bridge */
+ { SCSI, SCSI, SCSI, SCSI, SCSI }, /* SCSI */
+ { 0, INTC, INTD, INTA, INTB }, /* Slot 1 */
+ { INTB, INTB, INTB, INTB, INTB }, /* VGA */
+ { 0, 0, 0, 0, 0 }, /* Unused */
+ { 0, INTB, INTC, INTD, INTA }, /* Slot 2 */
+ { 0, INTC, INTD, INTA, INTB }, /* Slot 3 */
+ { 0, INTD, INTA, INTB, INTC }, /* Slot 4 */
+};
+
+static inline int is_rm300_revd(void)
+{
+ unsigned char csmsr = *(volatile unsigned char *)PCIMT_CSMSR;
+
+ return (csmsr & 0xa0) == 0x20;
+}
+
+int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ if (is_rm300_revd())
+ return irq_tab_rm300d[slot][pin];
+
+ return irq_tab_rm200[slot][pin];
+}
+
+/* Do platform specific device initialization at pci_enable_device() time */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+ return 0;
+}
diff --git a/arch/mips/pci/fixup-tb0219.c b/arch/mips/pci/fixup-tb0219.c
new file mode 100644
index 00000000000..850a900f0eb
--- /dev/null
+++ b/arch/mips/pci/fixup-tb0219.c
@@ -0,0 +1,66 @@
+/*
+ * fixup-tb0219.c, The TANBAC TB0219 specific PCI fixups.
+ *
+ * Copyright (C) 2003 Megasolution Inc. <matsu@megasolution.jp>
+ * Copyright (C) 2004 Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
+ *
+ * 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 <linux/init.h>
+#include <linux/pci.h>
+
+#include <asm/vr41xx/tb0219.h>
+
+int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ int irq = -1;
+
+ switch (slot) {
+ case 12:
+ vr41xx_set_irq_trigger(TB0219_PCI_SLOT1_PIN,
+ TRIGGER_LEVEL,
+ SIGNAL_THROUGH);
+ vr41xx_set_irq_level(TB0219_PCI_SLOT1_PIN,
+ LEVEL_LOW);
+ irq = TB0219_PCI_SLOT1_IRQ;
+ break;
+ case 13:
+ vr41xx_set_irq_trigger(TB0219_PCI_SLOT2_PIN,
+ TRIGGER_LEVEL,
+ SIGNAL_THROUGH);
+ vr41xx_set_irq_level(TB0219_PCI_SLOT2_PIN,
+ LEVEL_LOW);
+ irq = TB0219_PCI_SLOT2_IRQ;
+ break;
+ case 14:
+ vr41xx_set_irq_trigger(TB0219_PCI_SLOT3_PIN,
+ TRIGGER_LEVEL,
+ SIGNAL_THROUGH);
+ vr41xx_set_irq_level(TB0219_PCI_SLOT3_PIN,
+ LEVEL_LOW);
+ irq = TB0219_PCI_SLOT3_IRQ;
+ break;
+ default:
+ break;
+ }
+
+ return irq;
+}
+
+/* Do platform specific device initialization at pci_enable_device() time */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+ return 0;
+}
diff --git a/arch/mips/pci/fixup-tb0226.c b/arch/mips/pci/fixup-tb0226.c
new file mode 100644
index 00000000000..61513d5d97d
--- /dev/null
+++ b/arch/mips/pci/fixup-tb0226.c
@@ -0,0 +1,85 @@
+/*
+ * fixup-tb0226.c, The TANBAC TB0226 specific PCI fixups.
+ *
+ * Copyright (C) 2002-2004 Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
+ *
+ * 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 <linux/init.h>
+#include <linux/pci.h>
+
+#include <asm/vr41xx/tb0226.h>
+
+int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ int irq = -1;
+
+ switch (slot) {
+ case 12:
+ vr41xx_set_irq_trigger(GD82559_1_PIN,
+ TRIGGER_LEVEL,
+ SIGNAL_THROUGH);
+ vr41xx_set_irq_level(GD82559_1_PIN, LEVEL_LOW);
+ irq = GD82559_1_IRQ;
+ break;
+ case 13:
+ vr41xx_set_irq_trigger(GD82559_2_PIN,
+ TRIGGER_LEVEL,
+ SIGNAL_THROUGH);
+ vr41xx_set_irq_level(GD82559_2_PIN, LEVEL_LOW);
+ irq = GD82559_2_IRQ;
+ break;
+ case 14:
+ switch (pin) {
+ case 1:
+ vr41xx_set_irq_trigger(UPD720100_INTA_PIN,
+ TRIGGER_LEVEL,
+ SIGNAL_THROUGH);
+ vr41xx_set_irq_level(UPD720100_INTA_PIN,
+ LEVEL_LOW);
+ irq = UPD720100_INTA_IRQ;
+ break;
+ case 2:
+ vr41xx_set_irq_trigger(UPD720100_INTB_PIN,
+ TRIGGER_LEVEL,
+ SIGNAL_THROUGH);
+ vr41xx_set_irq_level(UPD720100_INTB_PIN,
+ LEVEL_LOW);
+ irq = UPD720100_INTB_IRQ;
+ break;
+ case 3:
+ vr41xx_set_irq_trigger(UPD720100_INTC_PIN,
+ TRIGGER_LEVEL,
+ SIGNAL_THROUGH);
+ vr41xx_set_irq_level(UPD720100_INTC_PIN,
+ LEVEL_LOW);
+ irq = UPD720100_INTC_IRQ;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return irq;
+}
+
+/* Do platform specific device initialization at pci_enable_device() time */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+ return 0;
+}
diff --git a/arch/mips/pci/fixup-vr4133.c b/arch/mips/pci/fixup-vr4133.c
new file mode 100644
index 00000000000..03a0ff2fc99
--- /dev/null
+++ b/arch/mips/pci/fixup-vr4133.c
@@ -0,0 +1,204 @@
+/*
+ * arch/mips/vr41xx/nec-cmbvr4133/pci_fixup.c
+ *
+ * The NEC CMB-VR4133 Board specific PCI fixups.
+ *
+ * Author: Yoichi Yuasa <yyuasa@mvista.com, or source@mvista.com> and
+ * Alex Sapkov <asapkov@ru.mvista.com>
+ *
+ * 2003-2004 (c) MontaVista, Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ *
+ * Modified for support in 2.6
+ * Author: Manish Lachwani (mlachwani@mvista.com)
+ *
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+
+#include <asm/io.h>
+#include <asm/vr41xx/cmbvr4133.h>
+
+extern int vr4133_rockhopper;
+extern void ali_m1535plus_init(struct pci_dev *dev);
+extern void ali_m5229_init(struct pci_dev *dev);
+
+/* Do platform specific device initialization at pci_enable_device() time */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+ /*
+ * We have to reset AMD PCnet adapter on Rockhopper since
+ * PMON leaves it enabled and generating interrupts. This leads
+ * to a lock if some PCI device driver later enables the IRQ line
+ * shared with PCnet and there is no AMD PCnet driver to catch its
+ * interrupts.
+ */
+#ifdef CONFIG_ROCKHOPPER
+ if (dev->vendor == PCI_VENDOR_ID_AMD &&
+ dev->device == PCI_DEVICE_ID_AMD_LANCE) {
+ inl(pci_resource_start(dev, 0) + 0x18);
+ }
+#endif
+
+ /*
+ * we have to open the bridges' windows down to 0 because otherwise
+ * we cannot access ISA south bridge I/O registers that get mapped from
+ * 0. for example, 8259 PIC would be unaccessible without that
+ */
+ if(dev->vendor == PCI_VENDOR_ID_INTEL && dev->device == PCI_DEVICE_ID_INTEL_S21152BB) {
+ pci_write_config_byte(dev, PCI_IO_BASE, 0);
+ if(dev->bus->number == 0) {
+ pci_write_config_word(dev, PCI_IO_BASE_UPPER16, 0);
+ } else {
+ pci_write_config_word(dev, PCI_IO_BASE_UPPER16, 1);
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * M1535 IRQ mapping
+ * Feel free to change this, although it shouldn't be needed
+ */
+#define M1535_IRQ_INTA 7
+#define M1535_IRQ_INTB 9
+#define M1535_IRQ_INTC 10
+#define M1535_IRQ_INTD 11
+
+#define M1535_IRQ_USB 9
+#define M1535_IRQ_IDE 14
+#define M1535_IRQ_IDE2 15
+#define M1535_IRQ_PS2 12
+#define M1535_IRQ_RTC 8
+#define M1535_IRQ_FDC 6
+#define M1535_IRQ_AUDIO 5
+#define M1535_IRQ_COM1 4
+#define M1535_IRQ_COM2 4
+#define M1535_IRQ_IRDA 3
+#define M1535_IRQ_KBD 1
+#define M1535_IRQ_TMR 0
+
+/* Rockhopper "slots" assignment; this is hard-coded ... */
+#define ROCKHOPPER_M5451_SLOT 1
+#define ROCKHOPPER_M1535_SLOT 2
+#define ROCKHOPPER_M5229_SLOT 11
+#define ROCKHOPPER_M5237_SLOT 15
+#define ROCKHOPPER_PMU_SLOT 12
+/* ... and hard-wired. */
+#define ROCKHOPPER_PCI1_SLOT 3
+#define ROCKHOPPER_PCI2_SLOT 4
+#define ROCKHOPPER_PCI3_SLOT 5
+#define ROCKHOPPER_PCI4_SLOT 6
+#define ROCKHOPPER_PCNET_SLOT 1
+
+#define M1535_IRQ_MASK(n) (1 << (n))
+
+#define M1535_IRQ_EDGE (M1535_IRQ_MASK(M1535_IRQ_TMR) | \
+ M1535_IRQ_MASK(M1535_IRQ_KBD) | \
+ M1535_IRQ_MASK(M1535_IRQ_COM1) | \
+ M1535_IRQ_MASK(M1535_IRQ_COM2) | \
+ M1535_IRQ_MASK(M1535_IRQ_IRDA) | \
+ M1535_IRQ_MASK(M1535_IRQ_RTC) | \
+ M1535_IRQ_MASK(M1535_IRQ_FDC) | \
+ M1535_IRQ_MASK(M1535_IRQ_PS2))
+
+#define M1535_IRQ_LEVEL (M1535_IRQ_MASK(M1535_IRQ_IDE) | \
+ M1535_IRQ_MASK(M1535_IRQ_USB) | \
+ M1535_IRQ_MASK(M1535_IRQ_INTA) | \
+ M1535_IRQ_MASK(M1535_IRQ_INTB) | \
+ M1535_IRQ_MASK(M1535_IRQ_INTC) | \
+ M1535_IRQ_MASK(M1535_IRQ_INTD))
+
+struct irq_map_entry {
+ u16 bus;
+ u8 slot;
+ u8 irq;
+};
+static struct irq_map_entry int_map[] = {
+ {1, ROCKHOPPER_M5451_SLOT, M1535_IRQ_AUDIO}, /* Audio controller */
+ {1, ROCKHOPPER_PCI1_SLOT, M1535_IRQ_INTD}, /* PCI slot #1 */
+ {1, ROCKHOPPER_PCI2_SLOT, M1535_IRQ_INTC}, /* PCI slot #2 */
+ {1, ROCKHOPPER_M5237_SLOT, M1535_IRQ_USB}, /* USB host controller */
+ {1, ROCKHOPPER_M5229_SLOT, IDE_PRIMARY_IRQ}, /* IDE controller */
+ {2, ROCKHOPPER_PCNET_SLOT, M1535_IRQ_INTD}, /* AMD Am79c973 on-board
+ ethernet */
+ {2, ROCKHOPPER_PCI3_SLOT, M1535_IRQ_INTB}, /* PCI slot #3 */
+ {2, ROCKHOPPER_PCI4_SLOT, M1535_IRQ_INTC} /* PCI slot #4 */
+};
+
+static int pci_intlines[] =
+ { M1535_IRQ_INTA, M1535_IRQ_INTB, M1535_IRQ_INTC, M1535_IRQ_INTD };
+
+/* Determine the Rockhopper IRQ line number for the PCI device */
+int rockhopper_get_irq(struct pci_dev *dev, u8 pin, u8 slot)
+{
+ struct pci_bus *bus;
+ int i;
+
+ bus = dev->bus;
+ if (bus == NULL)
+ return -1;
+
+ for (i = 0; i < sizeof (int_map) / sizeof (int_map[0]); i++) {
+ if (int_map[i].bus == bus->number && int_map[i].slot == slot) {
+ int line;
+ for (line = 0; line < 4; line++)
+ if (pci_intlines[line] == int_map[i].irq)
+ break;
+ if (line < 4)
+ return pci_intlines[(line + (pin - 1)) % 4];
+ else
+ return int_map[i].irq;
+ }
+ }
+ return -1;
+}
+
+#ifdef CONFIG_ROCKHOPPER
+void i8259_init(void)
+{
+ outb(0x11, 0x20); /* Master ICW1 */
+ outb(I8259_IRQ_BASE, 0x21); /* Master ICW2 */
+ outb(0x04, 0x21); /* Master ICW3 */
+ outb(0x01, 0x21); /* Master ICW4 */
+ outb(0xff, 0x21); /* Master IMW */
+
+ outb(0x11, 0xa0); /* Slave ICW1 */
+ outb(I8259_IRQ_BASE + 8, 0xa1); /* Slave ICW2 */
+ outb(0x02, 0xa1); /* Slave ICW3 */
+ outb(0x01, 0xa1); /* Slave ICW4 */
+ outb(0xff, 0xa1); /* Slave IMW */
+
+ outb(0x00, 0x4d0);
+ outb(0x02, 0x4d1); /* USB IRQ9 is level */
+}
+#endif
+
+int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ extern int pci_probe_only;
+ pci_probe_only = 1;
+
+#ifdef CONFIG_ROCKHOPPER
+ if( dev->bus->number == 1 && vr4133_rockhopper ) {
+ if(slot == ROCKHOPPER_PCI1_SLOT || slot == ROCKHOPPER_PCI2_SLOT)
+ dev->irq = CMBVR41XX_INTA_IRQ;
+ else
+ dev->irq = rockhopper_get_irq(dev, pin, slot);
+ } else
+ dev->irq = CMBVR41XX_INTA_IRQ;
+#else
+ dev->irq = CMBVR41XX_INTA_IRQ;
+#endif
+
+ return dev->irq;
+}
+
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, ali_m1535plus_init);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5229, ali_m5229_init);
+
+
diff --git a/arch/mips/pci/fixup-yosemite.c b/arch/mips/pci/fixup-yosemite.c
new file mode 100644
index 00000000000..81d77a587a5
--- /dev/null
+++ b/arch/mips/pci/fixup-yosemite.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2003 PMC-Sierra
+ * Author: Manish Lachwani (lachwani@pmc-sierra.com)
+ *
+ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 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.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+
+int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ if (pin == 0)
+ return -1;
+
+ return 3; /* Everything goes to one irq bit */
+}
+
+/* Do platform specific device initialization at pci_enable_device() time */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+ return 0;
+}
diff --git a/arch/mips/pci/ops-au1000.c b/arch/mips/pci/ops-au1000.c
new file mode 100644
index 00000000000..c1c91ca0f9c
--- /dev/null
+++ b/arch/mips/pci/ops-au1000.c
@@ -0,0 +1,325 @@
+/*
+ * BRIEF MODULE DESCRIPTION
+ * Alchemy/AMD Au1x00 pci support.
+ *
+ * Copyright 2001,2002,2003 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ * ppopov@mvista.com or source@mvista.com
+ *
+ * Support for all devices (greater than 16) added by David Gathright.
+ *
+ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 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.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/vmalloc.h>
+
+#include <asm/mach-au1x00/au1000.h>
+
+#undef DEBUG
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+#define PCI_ACCESS_READ 0
+#define PCI_ACCESS_WRITE 1
+
+
+int (*board_pci_idsel)(unsigned int devsel, int assert);
+
+/* CP0 hazard avoidance. */
+#define BARRIER __asm__ __volatile__(".set noreorder\n\t" \
+ "nop; nop; nop; nop;\t" \
+ ".set reorder\n\t")
+
+void mod_wired_entry(int entry, unsigned long entrylo0,
+ unsigned long entrylo1, unsigned long entryhi,
+ unsigned long pagemask)
+{
+ unsigned long old_pagemask;
+ unsigned long old_ctx;
+
+ /* Save old context and create impossible VPN2 value */
+ old_ctx = read_c0_entryhi() & 0xff;
+ old_pagemask = read_c0_pagemask();
+ write_c0_index(entry);
+ BARRIER;
+ write_c0_pagemask(pagemask);
+ write_c0_entryhi(entryhi);
+ write_c0_entrylo0(entrylo0);
+ write_c0_entrylo1(entrylo1);
+ BARRIER;
+ tlb_write_indexed();
+ BARRIER;
+ write_c0_entryhi(old_ctx);
+ BARRIER;
+ write_c0_pagemask(old_pagemask);
+}
+
+struct vm_struct *pci_cfg_vm;
+static int pci_cfg_wired_entry;
+static int first_cfg = 1;
+unsigned long last_entryLo0, last_entryLo1;
+
+static int config_access(unsigned char access_type, struct pci_bus *bus,
+ unsigned int dev_fn, unsigned char where,
+ u32 * data)
+{
+#if defined( CONFIG_SOC_AU1500 ) || defined( CONFIG_SOC_AU1550 )
+ unsigned int device = PCI_SLOT(dev_fn);
+ unsigned int function = PCI_FUNC(dev_fn);
+ unsigned long offset, status;
+ unsigned long cfg_base;
+ unsigned long flags;
+ int error = PCIBIOS_SUCCESSFUL;
+ unsigned long entryLo0, entryLo1;
+
+ if (device > 19) {
+ *data = 0xffffffff;
+ return -1;
+ }
+
+ local_irq_save(flags);
+ au_writel(((0x2000 << 16) | (au_readl(Au1500_PCI_STATCMD) & 0xffff)),
+ Au1500_PCI_STATCMD);
+ au_sync_udelay(1);
+
+ /*
+ * We can't ioremap the entire pci config space because it's
+ * too large. Nor can we call ioremap dynamically because some
+ * device drivers use the pci config routines from within
+ * interrupt handlers and that becomes a problem in get_vm_area().
+ * We use one wired tlb to handle all config accesses for all
+ * busses. To improve performance, if the current device
+ * is the same as the last device accessed, we don't touch the
+ * tlb.
+ */
+ if (first_cfg) {
+ /* reserve a wired entry for pci config accesses */
+ first_cfg = 0;
+ pci_cfg_vm = get_vm_area(0x2000, 0);
+ if (!pci_cfg_vm)
+ panic (KERN_ERR "PCI unable to get vm area\n");
+ pci_cfg_wired_entry = read_c0_wired();
+ add_wired_entry(0, 0, (unsigned long)pci_cfg_vm->addr, PM_4K);
+ last_entryLo0 = last_entryLo1 = 0xffffffff;
+ }
+
+ /* Since the Au1xxx doesn't do the idsel timing exactly to spec,
+ * many board vendors implement their own off-chip idsel, so call
+ * it now. If it doesn't succeed, may as well bail out at this point.
+ */
+ if (board_pci_idsel) {
+ if (board_pci_idsel(device, 1) == 0) {
+ *data = 0xffffffff;
+ local_irq_restore(flags);
+ return -1;
+ }
+ }
+
+ /* setup the config window */
+ if (bus->number == 0) {
+ cfg_base = ((1<<device)<<11);
+ } else {
+ cfg_base = 0x80000000 | (bus->number<<16) | (device<<11);
+ }
+
+ /* setup the lower bits of the 36 bit address */
+ offset = (function << 8) | (where & ~0x3);
+ /* pick up any address that falls below the page mask */
+ offset |= cfg_base & ~PAGE_MASK;
+
+ /* page boundary */
+ cfg_base = cfg_base & PAGE_MASK;
+
+ entryLo0 = (6 << 26) | (cfg_base >> 6) | (2 << 3) | 7;
+ entryLo1 = (6 << 26) | (cfg_base >> 6) | (0x1000 >> 6) | (2 << 3) | 7;
+
+ if ((entryLo0 != last_entryLo0) || (entryLo1 != last_entryLo1)) {
+ mod_wired_entry(pci_cfg_wired_entry, entryLo0, entryLo1,
+ (unsigned long)pci_cfg_vm->addr, PM_4K);
+ last_entryLo0 = entryLo0;
+ last_entryLo1 = entryLo1;
+ }
+
+ if (access_type == PCI_ACCESS_WRITE) {
+ au_writel(*data, (int)(pci_cfg_vm->addr + offset));
+ } else {
+ *data = au_readl((int)(pci_cfg_vm->addr + offset));
+ }
+ au_sync_udelay(2);
+
+ DBG("cfg_access %d bus->number %d dev %d at %x *data %x conf %x\n",
+ access_type, bus->number, device, where, *data, offset);
+
+ /* check master abort */
+ status = au_readl(Au1500_PCI_STATCMD);
+
+ if (status & (1<<29)) {
+ *data = 0xffffffff;
+ error = -1;
+ DBG("Au1x Master Abort\n");
+ } else if ((status >> 28) & 0xf) {
+ DBG("PCI ERR detected: status %x\n", status);
+ *data = 0xffffffff;
+ error = -1;
+ }
+
+ /* Take away the idsel.
+ */
+ if (board_pci_idsel) {
+ (void)board_pci_idsel(device, 0);
+ }
+
+ local_irq_restore(flags);
+ return error;
+#endif
+}
+
+static int read_config_byte(struct pci_bus *bus, unsigned int devfn,
+ int where, u8 * val)
+{
+ u32 data;
+ int ret;
+
+ ret = config_access(PCI_ACCESS_READ, bus, devfn, where, &data);
+ if (where & 1)
+ data >>= 8;
+ if (where & 2)
+ data >>= 16;
+ *val = data & 0xff;
+ return ret;
+}
+
+
+static int read_config_word(struct pci_bus *bus, unsigned int devfn,
+ int where, u16 * val)
+{
+ u32 data;
+ int ret;
+
+ ret = config_access(PCI_ACCESS_READ, bus, devfn, where, &data);
+ if (where & 2)
+ data >>= 16;
+ *val = data & 0xffff;
+ return ret;
+}
+
+static int read_config_dword(struct pci_bus *bus, unsigned int devfn,
+ int where, u32 * val)
+{
+ int ret;
+
+ ret = config_access(PCI_ACCESS_READ, bus, devfn, where, val);
+ return ret;
+}
+
+static int
+write_config_byte(struct pci_bus *bus, unsigned int devfn, int where,
+ u8 val)
+{
+ u32 data = 0;
+
+ if (config_access(PCI_ACCESS_READ, bus, devfn, where, &data))
+ return -1;
+
+ data = (data & ~(0xff << ((where & 3) << 3))) |
+ (val << ((where & 3) << 3));
+
+ if (config_access(PCI_ACCESS_WRITE, bus, devfn, where, &data))
+ return -1;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+write_config_word(struct pci_bus *bus, unsigned int devfn, int where,
+ u16 val)
+{
+ u32 data = 0;
+
+ if (config_access(PCI_ACCESS_READ, bus, devfn, where, &data))
+ return -1;
+
+ data = (data & ~(0xffff << ((where & 3) << 3))) |
+ (val << ((where & 3) << 3));
+
+ if (config_access(PCI_ACCESS_WRITE, bus, devfn, where, &data))
+ return -1;
+
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+write_config_dword(struct pci_bus *bus, unsigned int devfn, int where,
+ u32 val)
+{
+ if (config_access(PCI_ACCESS_WRITE, bus, devfn, where, &val))
+ return -1;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int config_read(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 * val)
+{
+ switch (size) {
+ case 1: {
+ u8 _val;
+ int rc = read_config_byte(bus, devfn, where, &_val);
+ *val = _val;
+ return rc;
+ }
+ case 2: {
+ u16 _val;
+ int rc = read_config_word(bus, devfn, where, &_val);
+ *val = _val;
+ return rc;
+ }
+ default:
+ return read_config_dword(bus, devfn, where, val);
+ }
+}
+
+static int config_write(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 val)
+{
+ switch (size) {
+ case 1:
+ return write_config_byte(bus, devfn, where, (u8) val);
+ case 2:
+ return write_config_word(bus, devfn, where, (u16) val);
+ default:
+ return write_config_dword(bus, devfn, where, val);
+ }
+}
+
+
+struct pci_ops au1x_pci_ops = {
+ config_read,
+ config_write
+};
diff --git a/arch/mips/pci/ops-bonito64.c b/arch/mips/pci/ops-bonito64.c
new file mode 100644
index 00000000000..4b4e086a7eb
--- /dev/null
+++ b/arch/mips/pci/ops-bonito64.c
@@ -0,0 +1,196 @@
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999, 2000 MIPS Technologies, Inc. All rights reserved.
+ *
+ * This program is free software; you can distribute 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 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.
+ *
+ * MIPS boards specific PCI support.
+ */
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/mips-boards/bonito64.h>
+
+#define PCI_ACCESS_READ 0
+#define PCI_ACCESS_WRITE 1
+
+/*
+ * PCI configuration cycle AD bus definition
+ */
+/* Type 0 */
+#define PCI_CFG_TYPE0_REG_SHF 0
+#define PCI_CFG_TYPE0_FUNC_SHF 8
+
+/* Type 1 */
+#define PCI_CFG_TYPE1_REG_SHF 0
+#define PCI_CFG_TYPE1_FUNC_SHF 8
+#define PCI_CFG_TYPE1_DEV_SHF 11
+#define PCI_CFG_TYPE1_BUS_SHF 16
+
+static int bonito64_pcibios_config_access(unsigned char access_type,
+ struct pci_bus *bus,
+ unsigned int devfn, int where,
+ u32 * data)
+{
+ unsigned char busnum = bus->number;
+ u32 dummy;
+ u64 pci_addr;
+
+ /* Algorithmics Bonito64 system controller. */
+
+ if ((busnum == 0) && (PCI_SLOT(devfn) > 21)) {
+ /* We number bus 0 devices from 0..21 */
+ return -1;
+ }
+
+#ifdef CONFIG_MIPS_BOARDS_GEN
+ if ((busnum == 0) && (PCI_SLOT(devfn) == 17)) {
+ /* MIPS Core boards have Bonito connected as device 17 */
+ return -1;
+ }
+#endif
+
+ /* Clear cause register bits */
+ BONITO_PCICMD |= (BONITO_PCICMD_MABORT_CLR |
+ BONITO_PCICMD_MTABORT_CLR);
+
+ /*
+ * Setup pattern to be used as PCI "address" for
+ * Type 0 cycle
+ */
+ if (busnum == 0) {
+ /* IDSEL */
+ pci_addr = (u64) 1 << (PCI_SLOT(devfn) + 10);
+ } else {
+ /* Bus number */
+ pci_addr = busnum << PCI_CFG_TYPE1_BUS_SHF;
+
+ /* Device number */
+ pci_addr |=
+ PCI_SLOT(devfn) << PCI_CFG_TYPE1_DEV_SHF;
+ }
+
+ /* Function (same for Type 0/1) */
+ pci_addr |= PCI_FUNC(devfn) << PCI_CFG_TYPE0_FUNC_SHF;
+
+ /* Register number (same for Type 0/1) */
+ pci_addr |= (where & ~0x3) << PCI_CFG_TYPE0_REG_SHF;
+
+ if (busnum == 0) {
+ /* Type 0 */
+ BONITO_PCIMAP_CFG = pci_addr >> 16;
+ } else {
+ /* Type 1 */
+ BONITO_PCIMAP_CFG = (pci_addr >> 16) | 0x10000;
+ }
+
+ pci_addr &= 0xffff;
+
+ /* Flush Bonito register block */
+ dummy = BONITO_PCIMAP_CFG;
+ iob(); /* sync */
+
+ /* Perform access */
+ if (access_type == PCI_ACCESS_WRITE) {
+ *(volatile u32 *) (_pcictrl_bonito_pcicfg + (u32)pci_addr) = *(u32 *) data;
+
+ /* Wait till done */
+ while (BONITO_PCIMSTAT & 0xF);
+ } else {
+ *(u32 *) data = *(volatile u32 *) (_pcictrl_bonito_pcicfg + (u32)pci_addr);
+ }
+
+ /* Detect Master/Target abort */
+ if (BONITO_PCICMD & (BONITO_PCICMD_MABORT_CLR |
+ BONITO_PCICMD_MTABORT_CLR)) {
+ /* Error occurred */
+
+ /* Clear bits */
+ BONITO_PCICMD |= (BONITO_PCICMD_MABORT_CLR |
+ BONITO_PCICMD_MTABORT_CLR);
+
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/*
+ * We can't address 8 and 16 bit words directly. Instead we have to
+ * read/write a 32bit word and mask/modify the data we actually want.
+ */
+static int bonito64_pcibios_read(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 * val)
+{
+ u32 data = 0;
+
+ if ((size == 2) && (where & 1))
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ else if ((size == 4) && (where & 3))
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ if (bonito64_pcibios_config_access(PCI_ACCESS_READ, bus, devfn, where,
+ &data))
+ return -1;
+
+ if (size == 1)
+ *val = (data >> ((where & 3) << 3)) & 0xff;
+ else if (size == 2)
+ *val = (data >> ((where & 3) << 3)) & 0xffff;
+ else
+ *val = data;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int bonito64_pcibios_write(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 val)
+{
+ u32 data = 0;
+
+ if ((size == 2) && (where & 1))
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ else if ((size == 4) && (where & 3))
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ if (size == 4)
+ data = val;
+ else {
+ if (bonito64_pcibios_config_access(PCI_ACCESS_READ, bus, devfn,
+ where, &data))
+ return -1;
+
+ if (size == 1)
+ data = (data & ~(0xff << ((where & 3) << 3))) |
+ (val << ((where & 3) << 3));
+ else if (size == 2)
+ data = (data & ~(0xffff << ((where & 3) << 3))) |
+ (val << ((where & 3) << 3));
+ }
+
+ if (bonito64_pcibios_config_access(PCI_ACCESS_WRITE, bus, devfn, where,
+ &data))
+ return -1;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+struct pci_ops bonito64_pci_ops = {
+ .read = bonito64_pcibios_read,
+ .write = bonito64_pcibios_write
+};
diff --git a/arch/mips/pci/ops-ddb5074.c b/arch/mips/pci/ops-ddb5074.c
new file mode 100644
index 00000000000..89f97bef4fc
--- /dev/null
+++ b/arch/mips/pci/ops-ddb5074.c
@@ -0,0 +1,271 @@
+/*
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
+ *
+ * arch/mips/ddb5xxx/ddb5476/pci_ops.c
+ * Define the pci_ops for DB5477.
+ *
+ * Much of the code is derived from the original DDB5074 port by
+ * Geert Uytterhoeven <geert@sonycom.com>
+ *
+ * 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 <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+
+#include <asm/addrspace.h>
+#include <asm/debug.h>
+
+#include <asm/ddb5xxx/ddb5xxx.h>
+
+/*
+ * config_swap structure records what set of pdar/pmr are used
+ * to access pci config space. It also provides a place hold the
+ * original values for future restoring.
+ */
+struct pci_config_swap {
+ u32 pdar;
+ u32 pmr;
+ u32 config_base;
+ u32 config_size;
+ u32 pdar_backup;
+ u32 pmr_backup;
+};
+
+/*
+ * On DDB5476, we have one set of swap registers
+ */
+struct pci_config_swap ext_pci_swap = {
+ DDB_PCIW0,
+ DDB_PCIINIT0,
+ DDB_PCI_CONFIG_BASE,
+ DDB_PCI_CONFIG_SIZE
+};
+
+static int pci_config_workaround = 1;
+
+/*
+ * access config space
+ */
+static inline u32 ddb_access_config_base(struct pci_config_swap *swap, u32 bus, /* 0 means top level bus */
+ u32 slot_num)
+{
+ u32 pci_addr = 0;
+ u32 pciinit_offset = 0;
+ u32 virt_addr = swap->config_base;
+ u32 option;
+
+ if (pci_config_workaround) {
+ if (slot_num == 5)
+ slot_num = 14;
+ } else {
+ if (slot_num == 5)
+ return DDB_BASE + DDB_PCI_BASE;
+ }
+
+ /* minimum pdar (window) size is 2MB */
+ db_assert(swap->config_size >= (2 << 20));
+
+ db_assert(slot_num < (1 << 5));
+ db_assert(bus < (1 << 8));
+
+ /* backup registers */
+ swap->pdar_backup = ddb_in32(swap->pdar);
+ swap->pmr_backup = ddb_in32(swap->pmr);
+
+ /* set the pdar (pci window) register */
+ ddb_set_pdar(swap->pdar, swap->config_base, swap->config_size, 32, /* 32 bit wide */
+ 0, /* not on local memory bus */
+ 0); /* not visible from PCI bus (N/A) */
+
+ /*
+ * calcuate the absolute pci config addr;
+ * according to the spec, we start scanning from adr:11 (0x800)
+ */
+ if (bus == 0) {
+ /* type 0 config */
+ pci_addr = 0x00040000 << slot_num;
+ } else {
+ /* type 1 config */
+ pci_addr = 0x00040000 << slot_num;
+ panic
+ ("ddb_access_config_base: we don't support type 1 config Yet");
+ }
+
+ /*
+ * if pci_addr is less than pci config window size, we set
+ * pciinit_offset to 0 and adjust the virt_address.
+ * Otherwise we will try to adjust pciinit_offset.
+ */
+ if (pci_addr < swap->config_size) {
+ virt_addr = KSEG1ADDR(swap->config_base + pci_addr);
+ pciinit_offset = 0;
+ } else {
+ db_assert((pci_addr & (swap->config_size - 1)) == 0);
+ virt_addr = KSEG1ADDR(swap->config_base);
+ pciinit_offset = pci_addr;
+ }
+
+ /* set the pmr register */
+ option = DDB_PCI_ACCESS_32;
+ if (bus != 0)
+ option |= DDB_PCI_CFGTYPE1;
+ ddb_set_pmr(swap->pmr, DDB_PCICMD_CFG, pciinit_offset, option);
+
+ return virt_addr;
+}
+
+static inline void ddb_close_config_base(struct pci_config_swap *swap)
+{
+ ddb_out32(swap->pdar, swap->pdar_backup);
+ ddb_out32(swap->pmr, swap->pmr_backup);
+}
+
+static int read_config_dword(struct pci_config_swap *swap,
+ struct pci_dev *dev, u32 where, u32 * val)
+{
+ u32 bus, slot_num, func_num;
+ u32 base;
+
+ db_assert((where & 3) == 0);
+ db_assert(where < (1 << 8));
+
+ /* check if the bus is top-level */
+ if (dev->bus->parent != NULL) {
+ bus = dev->bus->number;
+ db_assert(bus != 0);
+ } else {
+ bus = 0;
+ }
+
+ slot_num = PCI_SLOT(dev->devfn);
+ func_num = PCI_FUNC(dev->devfn);
+ base = ddb_access_config_base(swap, bus, slot_num);
+ *val = *(volatile u32 *) (base + (func_num << 8) + where);
+ ddb_close_config_base(swap);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int read_config_word(struct pci_config_swap *swap,
+ struct pci_dev *dev, u32 where, u16 * val)
+{
+ int status;
+ u32 result;
+
+ db_assert((where & 1) == 0);
+
+ status = read_config_dword(swap, dev, where & ~3, &result);
+ if (where & 2)
+ result >>= 16;
+ *val = result & 0xffff;
+ return status;
+}
+
+static int read_config_byte(struct pci_config_swap *swap,
+ struct pci_dev *dev, u32 where, u8 * val)
+{
+ int status;
+ u32 result;
+
+ status = read_config_dword(swap, dev, where & ~3, &result);
+ if (where & 1)
+ result >>= 8;
+ if (where & 2)
+ result >>= 16;
+ *val = result & 0xff;
+ return status;
+}
+
+static int write_config_dword(struct pci_config_swap *swap,
+ struct pci_dev *dev, u32 where, u32 val)
+{
+ u32 bus, slot_num, func_num;
+ u32 base;
+
+ db_assert((where & 3) == 0);
+ db_assert(where < (1 << 8));
+
+ /* check if the bus is top-level */
+ if (dev->bus->parent != NULL) {
+ bus = dev->bus->number;
+ db_assert(bus != 0);
+ } else {
+ bus = 0;
+ }
+
+ slot_num = PCI_SLOT(dev->devfn);
+ func_num = PCI_FUNC(dev->devfn);
+ base = ddb_access_config_base(swap, bus, slot_num);
+ *(volatile u32 *) (base + (func_num << 8) + where) = val;
+ ddb_close_config_base(swap);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int write_config_word(struct pci_config_swap *swap,
+ struct pci_dev *dev, u32 where, u16 val)
+{
+ int status, shift = 0;
+ u32 result;
+
+ db_assert((where & 1) == 0);
+
+ status = read_config_dword(swap, dev, where & ~3, &result);
+ if (status != PCIBIOS_SUCCESSFUL)
+ return status;
+
+ if (where & 2)
+ shift += 16;
+ result &= ~(0xffff << shift);
+ result |= val << shift;
+ return write_config_dword(swap, dev, where & ~3, result);
+}
+
+static int write_config_byte(struct pci_config_swap *swap,
+ struct pci_dev *dev, u32 where, u8 val)
+{
+ int status, shift = 0;
+ u32 result;
+
+ status = read_config_dword(swap, dev, where & ~3, &result);
+ if (status != PCIBIOS_SUCCESSFUL)
+ return status;
+
+ if (where & 2)
+ shift += 16;
+ if (where & 1)
+ shift += 8;
+ result &= ~(0xff << shift);
+ result |= val << shift;
+ return write_config_dword(swap, dev, where & ~3, result);
+}
+
+#define MAKE_PCI_OPS(prefix, rw, unitname, unittype, pciswap) \
+static int prefix##_##rw##_config_##unitname(struct pci_dev *dev, int where, unittype val) \
+{ \
+ return rw##_config_##unitname(pciswap, \
+ dev, \
+ where, \
+ val); \
+}
+
+MAKE_PCI_OPS(extpci, read, byte, u8 *, &ext_pci_swap)
+ MAKE_PCI_OPS(extpci, read, word, u16 *, &ext_pci_swap)
+ MAKE_PCI_OPS(extpci, read, dword, u32 *, &ext_pci_swap)
+
+ MAKE_PCI_OPS(extpci, write, byte, u8, &ext_pci_swap)
+ MAKE_PCI_OPS(extpci, write, word, u16, &ext_pci_swap)
+ MAKE_PCI_OPS(extpci, write, dword, u32, &ext_pci_swap)
+
+struct pci_ops ddb5476_ext_pci_ops = {
+ extpci_read_config_byte,
+ extpci_read_config_word,
+ extpci_read_config_dword,
+ extpci_write_config_byte,
+ extpci_write_config_word,
+ extpci_write_config_dword
+};
diff --git a/arch/mips/pci/ops-ddb5476.c b/arch/mips/pci/ops-ddb5476.c
new file mode 100644
index 00000000000..12da58e75ec
--- /dev/null
+++ b/arch/mips/pci/ops-ddb5476.c
@@ -0,0 +1,286 @@
+/*
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
+ *
+ * arch/mips/ddb5xxx/ddb5476/pci_ops.c
+ * Define the pci_ops for DB5477.
+ *
+ * Much of the code is derived from the original DDB5074 port by
+ * Geert Uytterhoeven <geert@sonycom.com>
+ *
+ * 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 <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+
+#include <asm/addrspace.h>
+#include <asm/debug.h>
+
+#include <asm/ddb5xxx/ddb5xxx.h>
+
+/*
+ * config_swap structure records what set of pdar/pmr are used
+ * to access pci config space. It also provides a place hold the
+ * original values for future restoring.
+ */
+struct pci_config_swap {
+ u32 pdar;
+ u32 pmr;
+ u32 config_base;
+ u32 config_size;
+ u32 pdar_backup;
+ u32 pmr_backup;
+};
+
+/*
+ * On DDB5476, we have one set of swap registers
+ */
+struct pci_config_swap ext_pci_swap = {
+ DDB_PCIW0,
+ DDB_PCIINIT0,
+ DDB_PCI_CONFIG_BASE,
+ DDB_PCI_CONFIG_SIZE
+};
+
+static int pci_config_workaround = 1;
+
+/*
+ * access config space
+ */
+static inline u32 ddb_access_config_base(struct pci_config_swap *swap, u32 bus, /* 0 means top level bus */
+ u32 slot_num)
+{
+ u32 pci_addr = 0;
+ u32 pciinit_offset = 0;
+ u32 virt_addr = swap->config_base;
+ u32 option;
+
+ if (pci_config_workaround) {
+ /* [jsun] work around Vrc5476 controller itself, returnning
+ * slot 0 essentially makes vrc5476 invisible
+ */
+ if (slot_num == 12)
+ slot_num = 0;
+
+#if 0
+ /* BUG : skip P2P bridge for now */
+ if (slot_num == 5)
+ slot_num = 0;
+#endif
+
+ } else {
+ /* now we have to be hornest, returning the true
+ * PCI config headers for vrc5476
+ */
+ if (slot_num == 12) {
+ swap->pdar_backup = ddb_in32(swap->pdar);
+ swap->pmr_backup = ddb_in32(swap->pmr);
+ return DDB_BASE + DDB_PCI_BASE;
+ }
+ }
+
+ /* minimum pdar (window) size is 2MB */
+ db_assert(swap->config_size >= (2 << 20));
+
+ db_assert(slot_num < (1 << 5));
+ db_assert(bus < (1 << 8));
+
+ /* backup registers */
+ swap->pdar_backup = ddb_in32(swap->pdar);
+ swap->pmr_backup = ddb_in32(swap->pmr);
+
+ /* set the pdar (pci window) register */
+ ddb_set_pdar(swap->pdar, swap->config_base, swap->config_size, 32, /* 32 bit wide */
+ 0, /* not on local memory bus */
+ 0); /* not visible from PCI bus (N/A) */
+
+ /*
+ * calcuate the absolute pci config addr;
+ * according to the spec, we start scanning from adr:11 (0x800)
+ */
+ if (bus == 0) {
+ /* type 0 config */
+ pci_addr = 0x800 << slot_num;
+ } else {
+ /* type 1 config */
+ pci_addr = (bus << 16) | (slot_num << 11);
+ /* panic("ddb_access_config_base: we don't support type 1 config Yet"); */
+ }
+
+ /*
+ * if pci_addr is less than pci config window size, we set
+ * pciinit_offset to 0 and adjust the virt_address.
+ * Otherwise we will try to adjust pciinit_offset.
+ */
+ if (pci_addr < swap->config_size) {
+ virt_addr = KSEG1ADDR(swap->config_base + pci_addr);
+ pciinit_offset = 0;
+ } else {
+ db_assert((pci_addr & (swap->config_size - 1)) == 0);
+ virt_addr = KSEG1ADDR(swap->config_base);
+ pciinit_offset = pci_addr;
+ }
+
+ /* set the pmr register */
+ option = DDB_PCI_ACCESS_32;
+ if (bus != 0)
+ option |= DDB_PCI_CFGTYPE1;
+ ddb_set_pmr(swap->pmr, DDB_PCICMD_CFG, pciinit_offset, option);
+
+ return virt_addr;
+}
+
+static inline void ddb_close_config_base(struct pci_config_swap *swap)
+{
+ ddb_out32(swap->pdar, swap->pdar_backup);
+ ddb_out32(swap->pmr, swap->pmr_backup);
+}
+
+static int read_config_dword(struct pci_config_swap *swap,
+ struct pci_dev *dev, u32 where, u32 * val)
+{
+ u32 bus, slot_num, func_num;
+ u32 base;
+
+ db_assert((where & 3) == 0);
+ db_assert(where < (1 << 8));
+
+ /* check if the bus is top-level */
+ if (dev->bus->parent != NULL) {
+ bus = dev->bus->number;
+ db_assert(bus != 0);
+ } else {
+ bus = 0;
+ }
+
+ slot_num = PCI_SLOT(dev->devfn);
+ func_num = PCI_FUNC(dev->devfn);
+ base = ddb_access_config_base(swap, bus, slot_num);
+ *val = *(volatile u32 *) (base + (func_num << 8) + where);
+ ddb_close_config_base(swap);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int read_config_word(struct pci_config_swap *swap,
+ struct pci_dev *dev, u32 where, u16 * val)
+{
+ int status;
+ u32 result;
+
+ db_assert((where & 1) == 0);
+
+ status = read_config_dword(swap, dev, where & ~3, &result);
+ if (where & 2)
+ result >>= 16;
+ *val = result & 0xffff;
+ return status;
+}
+
+static int read_config_byte(struct pci_config_swap *swap,
+ struct pci_dev *dev, u32 where, u8 * val)
+{
+ int status;
+ u32 result;
+
+ status = read_config_dword(swap, dev, where & ~3, &result);
+ if (where & 1)
+ result >>= 8;
+ if (where & 2)
+ result >>= 16;
+ *val = result & 0xff;
+ return status;
+}
+
+static int write_config_dword(struct pci_config_swap *swap,
+ struct pci_dev *dev, u32 where, u32 val)
+{
+ u32 bus, slot_num, func_num;
+ u32 base;
+
+ db_assert((where & 3) == 0);
+ db_assert(where < (1 << 8));
+
+ /* check if the bus is top-level */
+ if (dev->bus->parent != NULL) {
+ bus = dev->bus->number;
+ db_assert(bus != 0);
+ } else {
+ bus = 0;
+ }
+
+ slot_num = PCI_SLOT(dev->devfn);
+ func_num = PCI_FUNC(dev->devfn);
+ base = ddb_access_config_base(swap, bus, slot_num);
+ *(volatile u32 *) (base + (func_num << 8) + where) = val;
+ ddb_close_config_base(swap);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int write_config_word(struct pci_config_swap *swap,
+ struct pci_dev *dev, u32 where, u16 val)
+{
+ int status, shift = 0;
+ u32 result;
+
+ db_assert((where & 1) == 0);
+
+ status = read_config_dword(swap, dev, where & ~3, &result);
+ if (status != PCIBIOS_SUCCESSFUL)
+ return status;
+
+ if (where & 2)
+ shift += 16;
+ result &= ~(0xffff << shift);
+ result |= val << shift;
+ return write_config_dword(swap, dev, where & ~3, result);
+}
+
+static int write_config_byte(struct pci_config_swap *swap,
+ struct pci_dev *dev, u32 where, u8 val)
+{
+ int status, shift = 0;
+ u32 result;
+
+ status = read_config_dword(swap, dev, where & ~3, &result);
+ if (status != PCIBIOS_SUCCESSFUL)
+ return status;
+
+ if (where & 2)
+ shift += 16;
+ if (where & 1)
+ shift += 8;
+ result &= ~(0xff << shift);
+ result |= val << shift;
+ return write_config_dword(swap, dev, where & ~3, result);
+}
+
+#define MAKE_PCI_OPS(prefix, rw, unitname, unittype, pciswap) \
+static int prefix##_##rw##_config_##unitname(struct pci_dev *dev, int where, unittype val) \
+{ \
+ return rw##_config_##unitname(pciswap, \
+ dev, \
+ where, \
+ val); \
+}
+
+MAKE_PCI_OPS(extpci, read, byte, u8 *, &ext_pci_swap)
+ MAKE_PCI_OPS(extpci, read, word, u16 *, &ext_pci_swap)
+ MAKE_PCI_OPS(extpci, read, dword, u32 *, &ext_pci_swap)
+
+ MAKE_PCI_OPS(extpci, write, byte, u8, &ext_pci_swap)
+ MAKE_PCI_OPS(extpci, write, word, u16, &ext_pci_swap)
+ MAKE_PCI_OPS(extpci, write, dword, u32, &ext_pci_swap)
+
+struct pci_ops ddb5476_ext_pci_ops = {
+ extpci_read_config_byte,
+ extpci_read_config_word,
+ extpci_read_config_dword,
+ extpci_write_config_byte,
+ extpci_write_config_word,
+ extpci_write_config_dword
+};
diff --git a/arch/mips/pci/ops-ddb5477.c b/arch/mips/pci/ops-ddb5477.c
new file mode 100644
index 00000000000..e955443fedf
--- /dev/null
+++ b/arch/mips/pci/ops-ddb5477.c
@@ -0,0 +1,278 @@
+/***********************************************************************
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
+ *
+ * arch/mips/ddb5xxx/ddb5477/pci_ops.c
+ * Define the pci_ops for DB5477.
+ *
+ * Much of the code is derived from the original DDB5074 port by
+ * Geert Uytterhoeven <geert@sonycom.com>
+ *
+ * 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.
+ ***********************************************************************
+ */
+
+/*
+ * DDB5477 has two PCI channels, external PCI and IOPIC (internal)
+ * Therefore we provide two sets of pci_ops.
+ */
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+
+#include <asm/addrspace.h>
+#include <asm/debug.h>
+
+#include <asm/ddb5xxx/ddb5xxx.h>
+
+/*
+ * config_swap structure records what set of pdar/pmr are used
+ * to access pci config space. It also provides a place hold the
+ * original values for future restoring.
+ */
+struct pci_config_swap {
+ u32 pdar;
+ u32 pmr;
+ u32 config_base;
+ u32 config_size;
+ u32 pdar_backup;
+ u32 pmr_backup;
+};
+
+/*
+ * On DDB5477, we have two sets of swap registers, for ext PCI and IOPCI.
+ */
+struct pci_config_swap ext_pci_swap = {
+ DDB_PCIW0,
+ DDB_PCIINIT00,
+ DDB_PCI0_CONFIG_BASE,
+ DDB_PCI0_CONFIG_SIZE
+};
+struct pci_config_swap io_pci_swap = {
+ DDB_IOPCIW0,
+ DDB_PCIINIT01,
+ DDB_PCI1_CONFIG_BASE,
+ DDB_PCI1_CONFIG_SIZE
+};
+
+
+/*
+ * access config space
+ */
+static inline u32 ddb_access_config_base(struct pci_config_swap *swap, u32 bus, /* 0 means top level bus */
+ u32 slot_num)
+{
+ u32 pci_addr = 0;
+ u32 pciinit_offset = 0;
+ u32 virt_addr;
+ u32 option;
+
+ /* minimum pdar (window) size is 2MB */
+ db_assert(swap->config_size >= (2 << 20));
+
+ db_assert(slot_num < (1 << 5));
+ db_assert(bus < (1 << 8));
+
+ /* backup registers */
+ swap->pdar_backup = ddb_in32(swap->pdar);
+ swap->pmr_backup = ddb_in32(swap->pmr);
+
+ /* set the pdar (pci window) register */
+ ddb_set_pdar(swap->pdar, swap->config_base, swap->config_size, 32, /* 32 bit wide */
+ 0, /* not on local memory bus */
+ 0); /* not visible from PCI bus (N/A) */
+
+ /*
+ * calcuate the absolute pci config addr;
+ * according to the spec, we start scanning from adr:11 (0x800)
+ */
+ if (bus == 0) {
+ /* type 0 config */
+ pci_addr = 0x800 << slot_num;
+ } else {
+ /* type 1 config */
+ pci_addr = (bus << 16) | (slot_num << 11);
+ }
+
+ /*
+ * if pci_addr is less than pci config window size, we set
+ * pciinit_offset to 0 and adjust the virt_address.
+ * Otherwise we will try to adjust pciinit_offset.
+ */
+ if (pci_addr < swap->config_size) {
+ virt_addr = KSEG1ADDR(swap->config_base + pci_addr);
+ pciinit_offset = 0;
+ } else {
+ db_assert((pci_addr & (swap->config_size - 1)) == 0);
+ virt_addr = KSEG1ADDR(swap->config_base);
+ pciinit_offset = pci_addr;
+ }
+
+ /* set the pmr register */
+ option = DDB_PCI_ACCESS_32;
+ if (bus != 0)
+ option |= DDB_PCI_CFGTYPE1;
+ ddb_set_pmr(swap->pmr, DDB_PCICMD_CFG, pciinit_offset, option);
+
+ return virt_addr;
+}
+
+static inline void ddb_close_config_base(struct pci_config_swap *swap)
+{
+ ddb_out32(swap->pdar, swap->pdar_backup);
+ ddb_out32(swap->pmr, swap->pmr_backup);
+}
+
+static int read_config_dword(struct pci_config_swap *swap,
+ struct pci_bus *bus, u32 devfn, u32 where,
+ u32 * val)
+{
+ u32 bus_num, slot_num, func_num;
+ u32 base;
+
+ db_assert((where & 3) == 0);
+ db_assert(where < (1 << 8));
+
+ /* check if the bus is top-level */
+ if (bus->parent != NULL) {
+ bus_num = bus->number;
+ db_assert(bus_num != 0);
+ } else {
+ bus_num = 0;
+ }
+
+ slot_num = PCI_SLOT(devfn);
+ func_num = PCI_FUNC(devfn);
+ base = ddb_access_config_base(swap, bus_num, slot_num);
+ *val = *(volatile u32 *) (base + (func_num << 8) + where);
+ ddb_close_config_base(swap);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int read_config_word(struct pci_config_swap *swap,
+ struct pci_bus *bus, u32 devfn, u32 where,
+ u16 * val)
+{
+ int status;
+ u32 result;
+
+ db_assert((where & 1) == 0);
+
+ status = read_config_dword(swap, bus, devfn, where & ~3, &result);
+ if (where & 2)
+ result >>= 16;
+ *val = result & 0xffff;
+ return status;
+}
+
+static int read_config_byte(struct pci_config_swap *swap,
+ struct pci_bus *bus, u32 devfn, u32 where,
+ u8 * val)
+{
+ int status;
+ u32 result;
+
+ status = read_config_dword(swap, bus, devfn, where & ~3, &result);
+ if (where & 1)
+ result >>= 8;
+ if (where & 2)
+ result >>= 16;
+ *val = result & 0xff;
+
+ return status;
+}
+
+static int write_config_dword(struct pci_config_swap *swap,
+ struct pci_bus *bus, u32 devfn, u32 where,
+ u32 val)
+{
+ u32 bus_num, slot_num, func_num;
+ u32 base;
+
+ db_assert((where & 3) == 0);
+ db_assert(where < (1 << 8));
+
+ /* check if the bus is top-level */
+ if (bus->parent != NULL) {
+ bus_num = bus->number;
+ db_assert(bus_num != 0);
+ } else {
+ bus_num = 0;
+ }
+
+ slot_num = PCI_SLOT(devfn);
+ func_num = PCI_FUNC(devfn);
+ base = ddb_access_config_base(swap, bus_num, slot_num);
+ *(volatile u32 *) (base + (func_num << 8) + where) = val;
+ ddb_close_config_base(swap);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int write_config_word(struct pci_config_swap *swap,
+ struct pci_bus *bus, u32 devfn, u32 where, u16 val)
+{
+ int status, shift = 0;
+ u32 result;
+
+ db_assert((where & 1) == 0);
+
+ status = read_config_dword(swap, bus, devfn, where & ~3, &result);
+ if (status != PCIBIOS_SUCCESSFUL)
+ return status;
+
+ if (where & 2)
+ shift += 16;
+ result &= ~(0xffff << shift);
+ result |= val << shift;
+ return write_config_dword(swap, bus, devfn, where & ~3, result);
+}
+
+static int write_config_byte(struct pci_config_swap *swap,
+ struct pci_bus *bus, u32 devfn, u32 where, u8 val)
+{
+ int status, shift = 0;
+ u32 result;
+
+ status = read_config_dword(swap, bus, devfn, where & ~3, &result);
+ if (status != PCIBIOS_SUCCESSFUL)
+ return status;
+
+ if (where & 2)
+ shift += 16;
+ if (where & 1)
+ shift += 8;
+ result &= ~(0xff << shift);
+ result |= val << shift;
+ return write_config_dword(swap, bus, devfn, where & ~3, result);
+}
+
+#define MAKE_PCI_OPS(prefix, rw, pciswap, star) \
+static int prefix##_##rw##_config(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 star val) \
+{ \
+ if (size == 1) \
+ return rw##_config_byte(pciswap, bus, devfn, where, (u8 star)val); \
+ else if (size == 2) \
+ return rw##_config_word(pciswap, bus, devfn, where, (u16 star)val); \
+ /* Size must be 4 */ \
+ return rw##_config_dword(pciswap, bus, devfn, where, val); \
+}
+
+MAKE_PCI_OPS(extpci, read, &ext_pci_swap, *)
+MAKE_PCI_OPS(extpci, write, &ext_pci_swap,)
+
+MAKE_PCI_OPS(iopci, read, &io_pci_swap, *)
+MAKE_PCI_OPS(iopci, write, &io_pci_swap,)
+
+struct pci_ops ddb5477_ext_pci_ops = {
+ .read = extpci_read_config,
+ .write = extpci_write_config
+};
+
+
+struct pci_ops ddb5477_io_pci_ops = {
+ .read = iopci_read_config,
+ .write = iopci_write_config
+};
diff --git a/arch/mips/pci/ops-gt64111.c b/arch/mips/pci/ops-gt64111.c
new file mode 100644
index 00000000000..c5b0fc184c2
--- /dev/null
+++ b/arch/mips/pci/ops-gt64111.c
@@ -0,0 +1,100 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1995, 1996, 1997, 2002 by Ralf Baechle
+ * Copyright (C) 2001, 2002, 2003 by Liam Davies (ldavies@agile.tv)
+ */
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/pci.h>
+#include <asm/io.h>
+#include <asm/gt64120.h>
+
+#include <asm/cobalt/cobalt.h>
+
+/*
+ * Accessing device 31 hangs the GT64120. Not sure if this will also hang
+ * the GT64111, let's be paranoid for now.
+ */
+static inline int pci_range_ck(struct pci_bus *bus, unsigned int devfn)
+{
+ if (bus->number == 0 && devfn == PCI_DEVFN(31, 0))
+ return -1;
+
+ return 0;
+}
+
+static int gt64111_pci_read_config(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 * val)
+{
+ if (pci_range_ck(bus, devfn))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ switch (size) {
+ case 4:
+ PCI_CFG_SET(devfn, where);
+ *val = GALILEO_INL(GT_PCI0_CFGDATA_OFS);
+ return PCIBIOS_SUCCESSFUL;
+
+ case 2:
+ PCI_CFG_SET(devfn, (where & ~0x3));
+ *val = GALILEO_INL(GT_PCI0_CFGDATA_OFS)
+ >> ((where & 3) * 8);
+ return PCIBIOS_SUCCESSFUL;
+
+ case 1:
+ PCI_CFG_SET(devfn, (where & ~0x3));
+ *val = GALILEO_INL(GT_PCI0_CFGDATA_OFS)
+ >> ((where & 3) * 8);
+ return PCIBIOS_SUCCESSFUL;
+ }
+
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+}
+
+static int gt64111_pci_write_config(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 val)
+{
+ u32 tmp;
+
+ if (pci_range_ck(bus, devfn))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ switch (size) {
+ case 4:
+ PCI_CFG_SET(devfn, where);
+ GALILEO_OUTL(val, GT_PCI0_CFGDATA_OFS);
+
+ return PCIBIOS_SUCCESSFUL;
+
+ case 2:
+ PCI_CFG_SET(devfn, (where & ~0x3));
+ tmp = GALILEO_INL(GT_PCI0_CFGDATA_OFS);
+ tmp &= ~(0xffff << ((where & 0x3) * 8));
+ tmp |= (val << ((where & 0x3) * 8));
+ GALILEO_OUTL(tmp, GT_PCI0_CFGDATA_OFS);
+
+ return PCIBIOS_SUCCESSFUL;
+
+ case 1:
+ PCI_CFG_SET(devfn, (where & ~0x3));
+ tmp = GALILEO_INL(GT_PCI0_CFGDATA_OFS);
+ tmp &= ~(0xff << ((where & 0x3) * 8));
+ tmp |= (val << ((where & 0x3) * 8));
+ GALILEO_OUTL(tmp, GT_PCI0_CFGDATA_OFS);
+
+ return PCIBIOS_SUCCESSFUL;
+ }
+
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+}
+
+struct pci_ops gt64111_pci_ops = {
+ .read = gt64111_pci_read_config,
+ .write = gt64111_pci_write_config,
+};
diff --git a/arch/mips/pci/ops-gt64120.c b/arch/mips/pci/ops-gt64120.c
new file mode 100644
index 00000000000..7b99dfa33df
--- /dev/null
+++ b/arch/mips/pci/ops-gt64120.c
@@ -0,0 +1,154 @@
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999, 2000 MIPS Technologies, Inc. All rights reserved.
+ *
+ * This program is free software; you can distribute 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 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 <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+
+#include <asm/gt64120.h>
+
+#define PCI_ACCESS_READ 0
+#define PCI_ACCESS_WRITE 1
+
+/*
+ * PCI configuration cycle AD bus definition
+ */
+/* Type 0 */
+#define PCI_CFG_TYPE0_REG_SHF 0
+#define PCI_CFG_TYPE0_FUNC_SHF 8
+
+/* Type 1 */
+#define PCI_CFG_TYPE1_REG_SHF 0
+#define PCI_CFG_TYPE1_FUNC_SHF 8
+#define PCI_CFG_TYPE1_DEV_SHF 11
+#define PCI_CFG_TYPE1_BUS_SHF 16
+
+static int gt64120_pcibios_config_access(unsigned char access_type,
+ struct pci_bus *bus, unsigned int devfn, int where, u32 * data)
+{
+ unsigned char busnum = bus->number;
+ u32 intr;
+
+ if ((busnum == 0) && (PCI_SLOT(devfn) == 0))
+ /* Galileo itself is devfn 0, don't move it around */
+ return -1;
+
+ if ((busnum == 0) && (devfn >= PCI_DEVFN(31, 0)))
+ return -1; /* Because of a bug in the galileo (for slot 31). */
+
+ /* Clear cause register bits */
+ GT_WRITE(GT_INTRCAUSE_OFS, ~(GT_INTRCAUSE_MASABORT0_BIT |
+ GT_INTRCAUSE_TARABORT0_BIT));
+
+ /* Setup address */
+ GT_WRITE(GT_PCI0_CFGADDR_OFS,
+ (busnum << GT_PCI0_CFGADDR_BUSNUM_SHF) |
+ (devfn << GT_PCI0_CFGADDR_FUNCTNUM_SHF) |
+ ((where / 4) << GT_PCI0_CFGADDR_REGNUM_SHF) |
+ GT_PCI0_CFGADDR_CONFIGEN_BIT);
+
+ if (access_type == PCI_ACCESS_WRITE) {
+ if (busnum == 0 && PCI_SLOT(devfn) == 0) {
+ /*
+ * The Galileo system controller is acting
+ * differently than other devices.
+ */
+ GT_WRITE(GT_PCI0_CFGDATA_OFS, *data);
+ } else
+ __GT_WRITE(GT_PCI0_CFGDATA_OFS, *data);
+ } else {
+ if (busnum == 0 && PCI_SLOT(devfn) == 0) {
+ /*
+ * The Galileo system controller is acting
+ * differently than other devices.
+ */
+ *data = GT_READ(GT_PCI0_CFGDATA_OFS);
+ } else
+ *data = __GT_READ(GT_PCI0_CFGDATA_OFS);
+ }
+
+ /* Check for master or target abort */
+ intr = GT_READ(GT_INTRCAUSE_OFS);
+
+ if (intr & (GT_INTRCAUSE_MASABORT0_BIT | GT_INTRCAUSE_TARABORT0_BIT)) {
+ /* Error occurred */
+
+ /* Clear bits */
+ GT_WRITE(GT_INTRCAUSE_OFS, ~(GT_INTRCAUSE_MASABORT0_BIT |
+ GT_INTRCAUSE_TARABORT0_BIT));
+
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/*
+ * We can't address 8 and 16 bit words directly. Instead we have to
+ * read/write a 32bit word and mask/modify the data we actually want.
+ */
+static int gt64120_pcibios_read(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 * val)
+{
+ u32 data = 0;
+
+ if (gt64120_pcibios_config_access(PCI_ACCESS_READ, bus, devfn, where,
+ &data))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ if (size == 1)
+ *val = (data >> ((where & 3) << 3)) & 0xff;
+ else if (size == 2)
+ *val = (data >> ((where & 3) << 3)) & 0xffff;
+ else
+ *val = data;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int gt64120_pcibios_write(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 val)
+{
+ u32 data = 0;
+
+ if (size == 4)
+ data = val;
+ else {
+ if (gt64120_pcibios_config_access(PCI_ACCESS_READ, bus, devfn,
+ where, &data))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ if (size == 1)
+ data = (data & ~(0xff << ((where & 3) << 3))) |
+ (val << ((where & 3) << 3));
+ else if (size == 2)
+ data = (data & ~(0xffff << ((where & 3) << 3))) |
+ (val << ((where & 3) << 3));
+ }
+
+ if (gt64120_pcibios_config_access(PCI_ACCESS_WRITE, bus, devfn, where,
+ &data))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+struct pci_ops gt64120_pci_ops = {
+ .read = gt64120_pcibios_read,
+ .write = gt64120_pcibios_write
+};
diff --git a/arch/mips/pci/ops-gt96100.c b/arch/mips/pci/ops-gt96100.c
new file mode 100644
index 00000000000..9e4ea6627e2
--- /dev/null
+++ b/arch/mips/pci/ops-gt96100.c
@@ -0,0 +1,169 @@
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ * Galileo EV96100 board specific pci support.
+ *
+ * Copyright 2000 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ * ppopov@mvista.com or source@mvista.com
+ *
+ * This file was derived from Carsten Langgaard's
+ * arch/mips/mips-boards/generic/pci.c
+ *
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
+ *
+ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 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.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/delay.h>
+#include <asm/gt64120.h>
+#include <asm/galileo-boards/ev96100.h>
+
+#define PCI_ACCESS_READ 0
+#define PCI_ACCESS_WRITE 1
+
+static int static gt96100_config_access(unsigned char access_type,
+ struct pci_bus *bus, unsigned int devfn, int where, u32 * data)
+{
+ unsigned char bus = bus->number;
+ u32 intr;
+
+ /*
+ * Because of a bug in the galileo (for slot 31).
+ */
+ if (bus == 0 && devfn >= PCI_DEVFN(31, 0))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ /* Clear cause register bits */
+ GT_WRITE(GT_INTRCAUSE_OFS, ~(GT_INTRCAUSE_MASABORT0_BIT |
+ GT_INTRCAUSE_TARABORT0_BIT));
+
+ /* Setup address */
+ GT_WRITE(GT_PCI0_CFGADDR_OFS,
+ (bus << GT_PCI0_CFGADDR_BUSNUM_SHF) |
+ (devfn << GT_PCI0_CFGADDR_FUNCTNUM_SHF) |
+ ((where / 4) << GT_PCI0_CFGADDR_REGNUM_SHF) |
+ GT_PCI0_CFGADDR_CONFIGEN_BIT);
+ udelay(2);
+
+
+ if (access_type == PCI_ACCESS_WRITE) {
+ if (devfn != 0)
+ *data = le32_to_cpu(*data);
+ GT_WRITE(GT_PCI0_CFGDATA_OFS, *data);
+ } else {
+ *data = GT_READ(GT_PCI0_CFGDATA_OFS);
+ if (devfn != 0)
+ *data = le32_to_cpu(*data);
+ }
+
+ udelay(2);
+
+ /* Check for master or target abort */
+ intr = GT_READ(GT_INTRCAUSE_OFS);
+
+ if (intr & (GT_INTRCAUSE_MASABORT0_BIT | GT_INTRCAUSE_TARABORT0_BIT)) {
+ /* Error occured */
+
+ /* Clear bits */
+ GT_WRITE(GT_INTRCAUSE_OFS, ~(GT_INTRCAUSE_MASABORT0_BIT |
+ GT_INTRCAUSE_TARABORT0_BIT));
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * We can't address 8 and 16 bit words directly. Instead we have to
+ * read/write a 32bit word and mask/modify the data we actually want.
+ */
+static int gt96100_pcibios_read(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 * val)
+{
+ u32 data = 0;
+
+ if (gt96100_config_access(PCI_ACCESS_READ, bus, devfn, where, &data))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ switch (size) {
+ case 1:
+ *val = (data >> ((where & 3) << 3)) & 0xff;
+ break;
+
+ case 2:
+ *val = (data >> ((where & 3) << 3)) & 0xffff;
+ break;
+
+ case 4:
+ *val = data;
+ break;
+ }
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int gt96100_pcibios_write(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 val)
+{
+ u32 data = 0;
+
+ switch (size) {
+ case 1:
+ if (gt96100_config_access(PCI_ACCESS_READ, bus, devfn, where, &data))
+ return -1;
+
+ data = (data & ~(0xff << ((where & 3) << 3))) |
+ (val << ((where & 3) << 3));
+
+ if (gt96100_config_access(PCI_ACCESS_WRITE, bus, devfn, where, &data))
+ return -1;
+
+ return PCIBIOS_SUCCESSFUL;
+
+ case 2:
+ if (gt96100_config_access(PCI_ACCESS_READ, bus, devfn, where, &data))
+ return -1;
+
+ data = (data & ~(0xffff << ((where & 3) << 3))) |
+ (val << ((where & 3) << 3));
+
+ if (gt96100_config_access(PCI_ACCESS_WRITE, dev, where, &data))
+ return -1;
+
+
+ return PCIBIOS_SUCCESSFUL;
+
+ case 4:
+ if (gt96100_config_access(PCI_ACCESS_WRITE, dev, where, &val))
+ return -1;
+
+ return PCIBIOS_SUCCESSFUL;
+ }
+}
+
+struct pci_ops gt96100_pci_ops = {
+ .read = gt96100_pcibios_read,
+ .write = gt96100_pcibios_write
+};
diff --git a/arch/mips/pci/ops-it8172.c b/arch/mips/pci/ops-it8172.c
new file mode 100644
index 00000000000..b7a8b9a6f9d
--- /dev/null
+++ b/arch/mips/pci/ops-it8172.c
@@ -0,0 +1,215 @@
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ * IT8172 system controller specific pci support.
+ *
+ * Copyright 2000 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ * ppopov@mvista.com or source@mvista.com
+ *
+ * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org)
+ *
+ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 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.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/it8172/it8172.h>
+#include <asm/it8172/it8172_pci.h>
+
+#define PCI_ACCESS_READ 0
+#define PCI_ACCESS_WRITE 1
+
+#undef DEBUG
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+static struct resource pci_mem_resource_1;
+
+static struct resource pci_io_resource = {
+ "io pci IO space",
+ 0x14018000,
+ 0x17FFFFFF,
+ IORESOURCE_IO
+};
+
+static struct resource pci_mem_resource_0 = {
+ "ext pci memory space 0/1",
+ 0x10101000,
+ 0x13FFFFFF,
+ IORESOURCE_MEM,
+ &pci_mem_resource_0,
+ NULL,
+ &pci_mem_resource_1
+};
+
+static struct resource pci_mem_resource_1 = {
+ "ext pci memory space 2/3",
+ 0x1A000000,
+ 0x1FBFFFFF,
+ IORESOURCE_MEM,
+ &pci_mem_resource_0,
+ NULL,
+ NULL
+};
+
+extern struct pci_ops it8172_pci_ops;
+
+struct pci_controller it8172_controller = {
+ .pci_ops = &it8172_pci_ops,
+ .io_resource = &pci_io_resource,
+ .mem_resource = &pci_mem_resource_0,
+};
+
+static int it8172_pcibios_config_access(unsigned char access_type,
+ struct pci_bus *bus,
+ unsigned int devfn, int where,
+ u32 * data)
+{
+ /*
+ * config cycles are on 4 byte boundary only
+ */
+
+ /* Setup address */
+ IT_WRITE(IT_CONFADDR, (bus->number << IT_BUSNUM_SHF) |
+ (devfn << IT_FUNCNUM_SHF) | (where & ~0x3));
+
+ if (access_type == PCI_ACCESS_WRITE) {
+ IT_WRITE(IT_CONFDATA, *data);
+ } else {
+ IT_READ(IT_CONFDATA, *data);
+ }
+
+ /*
+ * Revisit: check for master or target abort.
+ */
+ return 0;
+}
+
+
+/*
+ * We can't address 8 and 16 bit words directly. Instead we have to
+ * read/write a 32bit word and mask/modify the data we actually want.
+ */
+static write_config(struct pci_bus *bus, unsigned int devfn, int where,
+ int size, u32 val)
+{
+ u32 data = 0;
+
+ switch (size) {
+ case 1:
+ if (it8172_pcibios_config_access
+ (PCI_ACCESS_READ, dev, where, &data))
+ return -1;
+
+ *val = (data >> ((where & 3) << 3)) & 0xff;
+
+ return PCIBIOS_SUCCESSFUL;
+
+ case 2:
+
+ if (where & 1)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ if (it8172_pcibios_config_access
+ (PCI_ACCESS_READ, dev, where, &data))
+ return -1;
+
+ *val = (data >> ((where & 3) << 3)) & 0xffff;
+ DBG("cfg read word: bus %d dev_fn %x where %x: val %x\n",
+ dev->bus->number, dev->devfn, where, *val);
+
+ return PCIBIOS_SUCCESSFUL;
+
+ case 4:
+
+ if (where & 3)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ if (it8172_pcibios_config_access
+ (PCI_ACCESS_READ, dev, where, &data))
+ return -1;
+
+ *val = data;
+
+ return PCIBIOS_SUCCESSFUL;
+ }
+}
+
+
+static write_config(struct pci_bus *bus, unsigned int devfn, int where,
+ int size, u32 val)
+{
+ u32 data = 0;
+
+ switch (size) {
+ case 1:
+ if (it8172_pcibios_config_access
+ (PCI_ACCESS_READ, dev, where, &data))
+ return -1;
+
+ data = (data & ~(0xff << ((where & 3) << 3))) |
+ (val << ((where & 3) << 3));
+
+ if (it8172_pcibios_config_access
+ (PCI_ACCESS_WRITE, dev, where, &data))
+ return -1;
+
+ return PCIBIOS_SUCCESSFUL;
+
+ case 2:
+ if (where & 1)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ if (it8172_pcibios_config_access
+ (PCI_ACCESS_READ, dev, where, &data))
+ eturn - 1;
+
+ data = (data & ~(0xffff << ((where & 3) << 3))) |
+ (val << ((where & 3) << 3));
+
+ if (it8172_pcibios_config_access
+ (PCI_ACCESS_WRITE, dev, where, &data))
+ return -1;
+
+ return PCIBIOS_SUCCESSFUL;
+
+ case 4:
+ if (where & 3)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ if (it8172_pcibios_config_access
+ (PCI_ACCESS_WRITE, dev, where, &val))
+ return -1;
+
+ return PCIBIOS_SUCCESSFUL;
+ }
+}
+
+struct pci_ops it8172_pci_ops = {
+ .read = read_config,
+ .write = write_config,
+};
diff --git a/arch/mips/pci/ops-mace.c b/arch/mips/pci/ops-mace.c
new file mode 100644
index 00000000000..8008e31c5e8
--- /dev/null
+++ b/arch/mips/pci/ops-mace.c
@@ -0,0 +1,91 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2000, 2001 Keith M Wesolowski
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/types.h>
+#include <asm/pci.h>
+#include <asm/ip32/mace.h>
+
+#if 0
+# define DPRINTK(args...) printk(args);
+#else
+# define DPRINTK(args...)
+#endif
+
+/*
+ * O2 has up to 5 PCI devices connected into the MACE bridge. The device
+ * map looks like this:
+ *
+ * 0 aic7xxx 0
+ * 1 aic7xxx 1
+ * 2 expansion slot
+ * 3 N/C
+ * 4 N/C
+ */
+
+#define chkslot(_bus,_devfn) \
+do { \
+ if ((_bus)->number > 0 || PCI_SLOT (_devfn) < 1 \
+ || PCI_SLOT (_devfn) > 3) \
+ return PCIBIOS_DEVICE_NOT_FOUND; \
+} while (0)
+
+#define mkaddr(_devfn, _reg) \
+((((_devfn) & 0xffUL) << 8) | ((_reg) & 0xfcUL))
+
+static int
+mace_pci_read_config(struct pci_bus *bus, unsigned int devfn,
+ int reg, int size, u32 *val)
+{
+ chkslot(bus, devfn);
+ mace->pci.config_addr = mkaddr(devfn, reg);
+ switch (size) {
+ case 1:
+ *val = mace->pci.config_data.b[(reg & 3) ^ 3];
+ break;
+ case 2:
+ *val = mace->pci.config_data.w[((reg >> 1) & 1) ^ 1];
+ break;
+ case 4:
+ *val = mace->pci.config_data.l;
+ break;
+ }
+
+ DPRINTK("read%d: reg=%08x,val=%02x\n", size * 8, reg, *val);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+mace_pci_write_config(struct pci_bus *bus, unsigned int devfn,
+ int reg, int size, u32 val)
+{
+ chkslot(bus, devfn);
+ mace->pci.config_addr = mkaddr(devfn, reg);
+ switch (size) {
+ case 1:
+ mace->pci.config_data.b[(reg & 3) ^ 3] = val;
+ break;
+ case 2:
+ mace->pci.config_data.w[((reg >> 1) & 1) ^ 1] = val;
+ break;
+ case 4:
+ mace->pci.config_data.l = val;
+ break;
+ }
+
+ DPRINTK("write%d: reg=%08x,val=%02x\n", size * 8, reg, val);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+struct pci_ops mace_pci_ops = {
+ .read = mace_pci_read_config,
+ .write = mace_pci_write_config,
+};
diff --git a/arch/mips/pci/ops-marvell.c b/arch/mips/pci/ops-marvell.c
new file mode 100644
index 00000000000..1ac5c59199d
--- /dev/null
+++ b/arch/mips/pci/ops-marvell.c
@@ -0,0 +1,93 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2003, 2004 Ralf Baechle (ralf@linux-mips.org)
+ */
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+
+#include <asm/marvell.h>
+
+static int mv_read_config(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 * val)
+{
+ struct mv_pci_controller *mvbc = bus->sysdata;
+ unsigned long address_reg, data_reg;
+ u32 address;
+
+ address_reg = mvbc->config_addr;
+ data_reg = mvbc->config_vreg;
+
+ /* Accessing device 31 crashes those Marvells. Since years.
+ Will they ever make sane controllers ... */
+ if (PCI_SLOT(devfn) == 31)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ address = (bus->number << 16) | (devfn << 8) |
+ (where & 0xfc) | 0x80000000;
+
+ /* start the configuration cycle */
+ MV_WRITE(address_reg, address);
+
+ switch (size) {
+ case 1:
+ *val = MV_READ_8(data_reg + (where & 0x3));
+ break;
+
+ case 2:
+ *val = MV_READ_16(data_reg + (where & 0x3));
+ break;
+
+ case 4:
+ *val = MV_READ(data_reg);
+ break;
+ }
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int mv_write_config(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 val)
+{
+ struct mv_pci_controller *mvbc = bus->sysdata;
+ unsigned long address_reg, data_reg;
+ u32 address;
+
+ address_reg = mvbc->config_addr;
+ data_reg = mvbc->config_vreg;
+
+ /* Accessing device 31 crashes those Marvells. Since years.
+ Will they ever make sane controllers ... */
+ if (PCI_SLOT(devfn) == 31)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ address = (bus->number << 16) | (devfn << 8) |
+ (where & 0xfc) | 0x80000000;
+
+ /* start the configuration cycle */
+ MV_WRITE(address_reg, address);
+
+ switch (size) {
+ case 1:
+ MV_WRITE_8(data_reg + (where & 0x3), val);
+ break;
+
+ case 2:
+ MV_WRITE_16(data_reg + (where & 0x3), val);
+ break;
+
+ case 4:
+ MV_WRITE(data_reg, val);
+ break;
+ }
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+struct pci_ops mv_pci_ops = {
+ .read = mv_read_config,
+ .write = mv_write_config
+};
diff --git a/arch/mips/pci/ops-msc.c b/arch/mips/pci/ops-msc.c
new file mode 100644
index 00000000000..7bc099643a9
--- /dev/null
+++ b/arch/mips/pci/ops-msc.c
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 1999, 2000, 2004, 2005 MIPS Technologies, Inc.
+ * All rights reserved.
+ * Authors: Carsten Langgaard <carstenl@mips.com>
+ * Maciej W. Rozycki <macro@mips.com>
+ * Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org)
+ *
+ * This program is free software; you can distribute 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 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.
+ *
+ * MIPS boards specific PCI support.
+ *
+ */
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/mips-boards/msc01_pci.h>
+
+#define PCI_ACCESS_READ 0
+#define PCI_ACCESS_WRITE 1
+
+/*
+ * PCI configuration cycle AD bus definition
+ */
+/* Type 0 */
+#define PCI_CFG_TYPE0_REG_SHF 0
+#define PCI_CFG_TYPE0_FUNC_SHF 8
+
+/* Type 1 */
+#define PCI_CFG_TYPE1_REG_SHF 0
+#define PCI_CFG_TYPE1_FUNC_SHF 8
+#define PCI_CFG_TYPE1_DEV_SHF 11
+#define PCI_CFG_TYPE1_BUS_SHF 16
+
+static int msc_pcibios_config_access(unsigned char access_type,
+ struct pci_bus *bus, unsigned int devfn, int where, u32 * data)
+{
+ unsigned char busnum = bus->number;
+ unsigned char type;
+ u32 intr;
+
+#ifdef CONFIG_MIPS_BOARDS_GEN
+ if ((busnum == 0) && (PCI_SLOT(devfn) == 17)) {
+ /* MIPS Core boards have SOCit connected as device 17 */
+ return -1;
+ }
+#endif
+
+ /* Clear status register bits. */
+ MSC_WRITE(MSC01_PCI_INTSTAT,
+ (MSC01_PCI_INTCFG_MA_BIT | MSC01_PCI_INTCFG_TA_BIT));
+
+ /* Setup address */
+ if (busnum == 0)
+ type = 0; /* Type 0 */
+ else
+ type = 1; /* Type 1 */
+
+ MSC_WRITE(MSC01_PCI_CFGADDR,
+ ((busnum << MSC01_PCI_CFGADDR_BNUM_SHF) |
+ (PCI_SLOT(devfn) << MSC01_PCI_CFGADDR_DNUM_SHF)
+ | (PCI_FUNC(devfn) <<
+ MSC01_PCI_CFGADDR_FNUM_SHF) | ((where /
+ 4) <<
+ MSC01_PCI_CFGADDR_RNUM_SHF)
+ | (type)));
+
+ /* Perform access */
+ if (access_type == PCI_ACCESS_WRITE)
+ MSC_WRITE(MSC01_PCI_CFGDATA, *data);
+ else
+ MSC_READ(MSC01_PCI_CFGDATA, *data);
+
+ /* Detect Master/Target abort */
+ MSC_READ(MSC01_PCI_INTSTAT, intr);
+ if (intr & (MSC01_PCI_INTCFG_MA_BIT |
+ MSC01_PCI_INTCFG_TA_BIT)) {
+ /* Error occurred */
+
+ /* Clear bits */
+ MSC_READ(MSC01_PCI_INTSTAT, intr);
+ MSC_WRITE(MSC01_PCI_INTSTAT,
+ (MSC01_PCI_INTCFG_MA_BIT |
+ MSC01_PCI_INTCFG_TA_BIT));
+
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/*
+ * We can't address 8 and 16 bit words directly. Instead we have to
+ * read/write a 32bit word and mask/modify the data we actually want.
+ */
+static int msc_pcibios_read(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 * val)
+{
+ u32 data = 0;
+
+ if ((size == 2) && (where & 1))
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ else if ((size == 4) && (where & 3))
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ if (msc_pcibios_config_access(PCI_ACCESS_READ, bus, devfn, where,
+ &data))
+ return -1;
+
+ if (size == 1)
+ *val = (data >> ((where & 3) << 3)) & 0xff;
+ else if (size == 2)
+ *val = (data >> ((where & 3) << 3)) & 0xffff;
+ else
+ *val = data;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int msc_pcibios_write(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 val)
+{
+ u32 data = 0;
+
+ if ((size == 2) && (where & 1))
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ else if ((size == 4) && (where & 3))
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ if (size == 4)
+ data = val;
+ else {
+ if (msc_pcibios_config_access(PCI_ACCESS_READ, bus, devfn,
+ where, &data))
+ return -1;
+
+ if (size == 1)
+ data = (data & ~(0xff << ((where & 3) << 3))) |
+ (val << ((where & 3) << 3));
+ else if (size == 2)
+ data = (data & ~(0xffff << ((where & 3) << 3))) |
+ (val << ((where & 3) << 3));
+ }
+
+ if (msc_pcibios_config_access(PCI_ACCESS_WRITE, bus, devfn, where,
+ &data))
+ return -1;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+struct pci_ops msc_pci_ops = {
+ .read = msc_pcibios_read,
+ .write = msc_pcibios_write
+};
diff --git a/arch/mips/pci/ops-nile4.c b/arch/mips/pci/ops-nile4.c
new file mode 100644
index 00000000000..a7169928b35
--- /dev/null
+++ b/arch/mips/pci/ops-nile4.c
@@ -0,0 +1,147 @@
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <asm/bootinfo.h>
+
+#include <asm/lasat/lasat.h>
+#include <asm/gt64120.h>
+#include <asm/nile4.h>
+
+#define PCI_ACCESS_READ 0
+#define PCI_ACCESS_WRITE 1
+
+#define LO(reg) (reg / 4)
+#define HI(reg) (reg / 4 + 1)
+
+volatile unsigned long *const vrc_pciregs = (void *) Vrc5074_BASE;
+
+static spinlock_t nile4_pci_lock;
+
+static int nile4_pcibios_config_access(unsigned char access_type,
+ struct pci_bus *bus, unsigned int devfn, int where, u32 * val)
+{
+ unsigned char busnum = bus->number;
+ u32 adr, mask, err;
+
+ if ((busnum == 0) && (PCI_SLOT(devfn) > 8))
+ /* The addressing scheme chosen leaves room for just
+ * 8 devices on the first busnum (besides the PCI
+ * controller itself) */
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ if ((busnum == 0) && (devfn == PCI_DEVFN(0, 0))) {
+ /* Access controller registers directly */
+ if (access_type == PCI_ACCESS_WRITE) {
+ vrc_pciregs[(0x200 + where) >> 2] = *val;
+ } else {
+ *val = vrc_pciregs[(0x200 + where) >> 2];
+ }
+ return PCIBIOS_SUCCESSFUL;
+ }
+
+ /* Temporarily map PCI Window 1 to config space */
+ mask = vrc_pciregs[LO(NILE4_PCIINIT1)];
+ vrc_pciregs[LO(NILE4_PCIINIT1)] = 0x0000001a | (busnum ? 0x200 : 0);
+
+ /* Clear PCI Error register. This also clears the Error Type
+ * bits in the Control register */
+ vrc_pciregs[LO(NILE4_PCIERR)] = 0;
+ vrc_pciregs[HI(NILE4_PCIERR)] = 0;
+
+ /* Setup address */
+ if (busnum == 0)
+ adr =
+ KSEG1ADDR(PCI_WINDOW1) +
+ ((1 << (PCI_SLOT(devfn) + 15)) | (PCI_FUNC(devfn) << 8)
+ | (where & ~3));
+ else
+ adr = KSEG1ADDR(PCI_WINDOW1) | (busnum << 16) | (devfn << 8) |
+ (where & ~3);
+
+ if (access_type == PCI_ACCESS_WRITE)
+ *(u32 *) adr = *val;
+ else
+ *val = *(u32 *) adr;
+
+ /* Check for master or target abort */
+ err = (vrc_pciregs[HI(NILE4_PCICTRL)] >> 5) & 0x7;
+
+ /* Restore PCI Window 1 */
+ vrc_pciregs[LO(NILE4_PCIINIT1)] = mask;
+
+ if (err)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int nile4_pcibios_read(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 * val)
+{
+ unsigned long flags;
+ u32 data = 0;
+ int err;
+
+ if ((size == 2) && (where & 1))
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ else if ((size == 4) && (where & 3))
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ spin_lock_irqsave(&nile4_pci_lock, flags);
+ err = nile4_pcibios_config_access(PCI_ACCESS_READ, bus, devfn, where,
+ &data);
+ spin_unlock_irqrestore(&nile4_pci_lock, flags);
+
+ if (err)
+ return err;
+
+ if (size == 1)
+ *val = (data >> ((where & 3) << 3)) & 0xff;
+ else if (size == 2)
+ *val = (data >> ((where & 3) << 3)) & 0xffff;
+ else
+ *val = data;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int nile4_pcibios_write(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 val)
+{
+ unsigned long flags;
+ u32 data = 0;
+ int err;
+
+ if ((size == 2) && (where & 1))
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ else if ((size == 4) && (where & 3))
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ spin_lock_irqsave(&nile4_pci_lock, flags);
+ err = nile4_pcibios_config_access(PCI_ACCESS_READ, bus, devfn, where,
+ &data);
+ spin_unlock_irqrestore(&nile4_pci_lock, flags);
+
+ if (err)
+ return err;
+
+ if (size == 1)
+ data = (data & ~(0xff << ((where & 3) << 3))) |
+ (val << ((where & 3) << 3));
+ else if (size == 2)
+ data = (data & ~(0xffff << ((where & 3) << 3))) |
+ (val << ((where & 3) << 3));
+ else
+ data = val;
+
+ if (nile4_pcibios_config_access
+ (PCI_ACCESS_WRITE, bus, devfn, where, &data))
+ return -1;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+struct pci_ops nile4_pci_ops = {
+ .read = nile4_pcibios_read,
+ .write = nile4_pcibios_write,
+};
diff --git a/arch/mips/pci/ops-sni.c b/arch/mips/pci/ops-sni.c
new file mode 100644
index 00000000000..62bdd19c7f8
--- /dev/null
+++ b/arch/mips/pci/ops-sni.c
@@ -0,0 +1,89 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * SNI specific PCI support for RM200/RM300.
+ *
+ * Copyright (C) 1997 - 2000, 2003 Ralf Baechle <ralf@linux-mips.org>
+ */
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/types.h>
+#include <asm/sni.h>
+
+/*
+ * It seems that on the RM200 only lower 3 bits of the 5 bit PCI device
+ * address are decoded. We therefore manually have to reject attempts at
+ * reading outside this range. Being on the paranoid side we only do this
+ * test for bus 0 and hope forwarding and decoding work properly for any
+ * subordinated busses.
+ *
+ * ASIC PCI only supports type 1 config cycles.
+ */
+static int set_config_address(unsigned int busno, unsigned int devfn, int reg)
+{
+ if ((devfn > 255) || (reg > 255))
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ if (busno == 0 && devfn >= PCI_DEVFN(8, 0))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ *(volatile u32 *)PCIMT_CONFIG_ADDRESS =
+ ((busno & 0xff) << 16) |
+ ((devfn & 0xff) << 8) |
+ (reg & 0xfc);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int pcimt_read(struct pci_bus *bus, unsigned int devfn, int reg,
+ int size, u32 * val)
+{
+ int res;
+
+ if ((res = set_config_address(bus->number, devfn, reg)))
+ return res;
+
+ switch (size) {
+ case 1:
+ *val = *(volatile u8 *) (PCIMT_CONFIG_DATA + (reg & 3));
+ break;
+ case 2:
+ *val = *(volatile u16 *) (PCIMT_CONFIG_DATA + (reg & 2));
+ break;
+ case 4:
+ *val = *(volatile u32 *) PCIMT_CONFIG_DATA;
+ break;
+ }
+
+ return 0;
+}
+
+static int pcimt_write(struct pci_bus *bus, unsigned int devfn, int reg,
+ int size, u32 val)
+{
+ int res;
+
+ if ((res = set_config_address(bus->number, devfn, reg)))
+ return res;
+
+ switch (size) {
+ case 1:
+ *(volatile u8 *) (PCIMT_CONFIG_DATA + (reg & 3)) = val;
+ break;
+ case 2:
+ *(volatile u16 *) (PCIMT_CONFIG_DATA + (reg & 2)) = val;
+ break;
+ case 4:
+ *(volatile u32 *) PCIMT_CONFIG_DATA = val;
+ break;
+ }
+
+ return 0;
+}
+
+struct pci_ops sni_pci_ops = {
+ .read = pcimt_read,
+ .write = pcimt_write,
+};
diff --git a/arch/mips/pci/ops-titan-ht.c b/arch/mips/pci/ops-titan-ht.c
new file mode 100644
index 00000000000..46c636c27e0
--- /dev/null
+++ b/arch/mips/pci/ops-titan-ht.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2003 PMC-Sierra
+ * Author: Manish Lachwani (lachwani@pmc-sierra.com)
+ *
+ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 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.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+
+#include <asm/titan_dep.h>
+
+static int titan_ht_config_read_dword(struct pci_bus *bus, unsigned int devfn,
+ int offset, u32 * val)
+{
+ volatile uint32_t address;
+ int busno;
+
+ busno = bus->number;
+
+ address = (busno << 16) | (devfn << 8) | (offset & 0xfc) | 0x80000000;
+ if (busno != 0)
+ address |= 1;
+
+ /*
+ * RM9000 HT Errata: Issue back to back HT config
+ * transcations. Issue a BIU sync before and
+ * after the HT cycle
+ */
+
+ *(volatile int32_t *) 0xfb0000f0 |= 0x2;
+
+ udelay(30);
+
+ *(volatile int32_t *) 0xfb0006f8 = address;
+ *(val) = *(volatile int32_t *) 0xfb0006fc;
+
+ udelay(30);
+
+ * (volatile int32_t *) 0xfb0000f0 |= 0x2;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int titan_ht_config_read(struct pci_bus *bus, unsigned int devfn,
+ int offset, int size, u32 * val)
+{
+ uint32_t dword;
+
+ titan_ht_config_read_dword(bus, devfn, offset, &dword);
+
+ dword >>= ((offset & 3) << 3);
+ dword &= (0xffffffffU >> ((4 - size) << 8));
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static inline int titan_ht_config_write_dword(struct pci_bus *bus,
+ unsigned int devfn, int offset, u32 val)
+{
+ volatile uint32_t address;
+ int busno;
+
+ busno = bus->number;
+
+ address = (busno << 16) | (devfn << 8) | (offset & 0xfc) | 0x80000000;
+ if (busno != 0)
+ address |= 1;
+
+ *(volatile int32_t *) 0xfb0000f0 |= 0x2;
+
+ udelay(30);
+
+ *(volatile int32_t *) 0xfb0006f8 = address;
+ *(volatile int32_t *) 0xfb0006fc = val;
+
+ udelay(30);
+
+ *(volatile int32_t *) 0xfb0000f0 |= 0x2;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int titan_ht_config_write(struct pci_bus *bus, unsigned int devfn,
+ int offset, int size, u32 val)
+{
+ uint32_t val1, val2, mask;
+
+ titan_ht_config_read_dword(bus, devfn, offset, &val2);
+
+ val1 = val << ((offset & 3) << 3);
+ mask = ~(0xffffffffU >> ((4 - size) << 8));
+ val2 &= ~(mask << ((offset & 3) << 8));
+
+ titan_ht_config_write_dword(bus, devfn, offset, val1 | val2);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+struct pci_ops titan_ht_pci_ops = {
+ .read = titan_ht_config_read,
+ .write = titan_ht_config_write,
+};
diff --git a/arch/mips/pci/ops-titan.c b/arch/mips/pci/ops-titan.c
new file mode 100644
index 00000000000..233ec6f2054
--- /dev/null
+++ b/arch/mips/pci/ops-titan.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2003 PMC-Sierra
+ * Author: Manish Lachwani (lachwani@pmc-sierra.com)
+ *
+ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 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.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+
+#include <asm/titan_dep.h>
+
+static int titan_read_config(struct pci_bus *bus, unsigned int devfn, int reg,
+ int size, u32 * val)
+{
+ uint32_t address, tmp;
+ int dev, busno, func;
+
+ busno = bus->number;
+ dev = PCI_SLOT(devfn);
+ func = PCI_FUNC(devfn);
+
+ address = (busno << 16) | (dev << 11) | (func << 8) |
+ (reg & 0xfc) | 0x80000000;
+
+
+ /* start the configuration cycle */
+ TITAN_WRITE(TITAN_PCI_0_CONFIG_ADDRESS, address);
+ tmp = TITAN_READ(TITAN_PCI_0_CONFIG_DATA) >> ((reg & 3) << 3);
+
+ switch (size) {
+ case 1:
+ tmp &= 0xff;
+ case 2:
+ tmp &= 0xffff;
+ }
+ *val = tmp;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int titan_write_config(struct pci_bus *bus, unsigned int devfn, int reg,
+ int size, u32 val)
+{
+ uint32_t address;
+ int dev, busno, func;
+
+ busno = bus->number;
+ dev = PCI_SLOT(devfn);
+ func = PCI_FUNC(devfn);
+
+ address = (busno << 16) | (dev << 11) | (func << 8) |
+ (reg & 0xfc) | 0x80000000;
+
+ /* start the configuration cycle */
+ TITAN_WRITE(TITAN_PCI_0_CONFIG_ADDRESS, address);
+
+ /* write the data */
+ switch (size) {
+ case 1:
+ TITAN_WRITE_8(TITAN_PCI_0_CONFIG_DATA + (~reg & 0x3), val);
+ break;
+
+ case 2:
+ TITAN_WRITE_16(TITAN_PCI_0_CONFIG_DATA + (~reg & 0x2), val);
+ break;
+
+ case 4:
+ TITAN_WRITE(TITAN_PCI_0_CONFIG_DATA, val);
+ break;
+ }
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+/*
+ * Titan PCI structure
+ */
+struct pci_ops titan_pci_ops = {
+ titan_read_config,
+ titan_write_config,
+};
diff --git a/arch/mips/pci/ops-tx3927.c b/arch/mips/pci/ops-tx3927.c
new file mode 100644
index 00000000000..0e0daadc303
--- /dev/null
+++ b/arch/mips/pci/ops-tx3927.c
@@ -0,0 +1,391 @@
+/*
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ * ahennessy@mvista.com
+ *
+ * Copyright (C) 2000-2001 Toshiba Corporation
+ * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org)
+ *
+ * Based on arch/mips/ddb5xxx/ddb5477/pci_ops.c
+ *
+ * Define the pci_ops for JMR3927.
+ *
+ * Much of the code is derived from the original DDB5074 port by
+ * Geert Uytterhoeven <geert@sonycom.com>
+ *
+ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 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.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/addrspace.h>
+#include <asm/jmr3927/jmr3927.h>
+#include <asm/debug.h>
+
+static inline int mkaddr(unsigned char bus, unsigned char dev_fn,
+ unsigned char where)
+{
+ if (bus == 0 && dev_fn >= PCI_DEVFN(TX3927_PCIC_MAX_DEVNU, 0))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ tx3927_pcicptr->ica = ((bus & 0xff) << 0x10) |
+ ((dev_fn & 0xff) << 0x08) |
+ (where & 0xfc);
+
+ /* clear M_ABORT and Disable M_ABORT Int. */
+ tx3927_pcicptr->pcistat |= PCI_STATUS_REC_MASTER_ABORT;
+ tx3927_pcicptr->pcistatim &= ~PCI_STATUS_REC_MASTER_ABORT;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static inline int check_abort(void)
+{
+ if (tx3927_pcicptr->pcistat & PCI_STATUS_REC_MASTER_ABORT)
+ tx3927_pcicptr->pcistat |= PCI_STATUS_REC_MASTER_ABORT;
+ tx3927_pcicptr->pcistatim |= PCI_STATUS_REC_MASTER_ABORT;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int jmr3927_pci_read_config(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 * val)
+{
+ int ret, busno;
+
+ /* check if the bus is top-level */
+ if (bus->parent != NULL)
+ busno = bus->number;
+
+ ret = mkaddr(busno, devfn, where);
+ if (ret)
+ return ret;
+
+ switch (size) {
+ case 1:
+ *val = *(volatile u8 *) ((unsigned long) & tx3927_pcicptr->icd | (where & 3));
+ break;
+
+ case 2:
+ *val = le16_to_cpu(*(volatile u16 *) ((unsigned long) & tx3927_pcicptr->icd | (where & 3)));
+ break;
+
+ case 4:
+ *val = le32_to_cpu(tx3927_pcicptr->icd);
+ break;
+ }
+
+ return check_abort();
+}
+
+static int jmr3927_pci_write_config(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 val)
+{
+ int ret, busno;
+
+ /* check if the bus is top-level */
+ if (bus->parent != NULL)
+ bus = bus->number;
+ else
+ bus = 0;
+
+ ret = mkaddr(busno, devfn, where);
+ if (ret)
+ return ret;
+
+ switch (size) {
+ case 1:
+ *(volatile u8 *) ((unsigned long) & tx3927_pcicptr->icd | (where & 3)) = val;
+ break;
+
+ case 2:
+ *(volatile u16 *) (unsigned longulong) & tx3927_pcicptr->icd | (where & 2)) =
+ cpu_to_le16(val);
+ break;
+
+ case 4:
+ tx3927_pcicptr->icd = cpu_to_le32(val);
+ }
+
+ if (tx3927_pcicptr->pcistat & PCI_STATUS_REC_MASTER_ABORT)
+ tx3927_pcicptr->pcistat |= PCI_STATUS_REC_MASTER_ABORT;
+ tx3927_pcicptr->pcistatim |= PCI_STATUS_REC_MASTER_ABORT;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ return check_abort();
+}
+
+struct pci_ops jmr3927_pci_ops = {
+ jmr3927_pcibios_read_config,
+ jmr3927_pcibios_write_config,
+};
+
+
+#ifndef JMR3927_INIT_INDIRECT_PCI
+
+inline unsigned long tc_readl(volatile __u32 * addr)
+{
+ return readl(addr);
+}
+
+inline void tc_writel(unsigned long data, volatile __u32 * addr)
+{
+ writel(data, addr);
+}
+#else
+
+unsigned long tc_readl(volatile __u32 * addr)
+{
+ unsigned long val;
+
+ addr = PHYSADDR(addr);
+ *(volatile u32 *) (ulong) & tx3927_pcicptr->ipciaddr =
+ (unsigned long) addr;
+ *(volatile u32 *) (ulong) & tx3927_pcicptr->ipcibe =
+ (PCI_IPCIBE_ICMD_MEMREAD << PCI_IPCIBE_ICMD_SHIFT) |
+ PCI_IPCIBE_IBE_LONG;
+ while (!(tx3927_pcicptr->istat & PCI_ISTAT_IDICC));
+ val =
+ le32_to_cpu(*(volatile u32 *) (ulong) & tx3927_pcicptr->
+ ipcidata);
+ /* clear by setting */
+ tx3927_pcicptr->istat |= PCI_ISTAT_IDICC;
+ return val;
+}
+
+void tc_writel(unsigned long data, volatile __u32 * addr)
+{
+ addr = PHYSADDR(addr);
+ *(volatile u32 *) (ulong) & tx3927_pcicptr->ipcidata =
+ cpu_to_le32(data);
+ *(volatile u32 *) (ulong) & tx3927_pcicptr->ipciaddr =
+ (unsigned long) addr;
+ *(volatile u32 *) (ulong) & tx3927_pcicptr->ipcibe =
+ (PCI_IPCIBE_ICMD_MEMWRITE << PCI_IPCIBE_ICMD_SHIFT) |
+ PCI_IPCIBE_IBE_LONG;
+ while (!(tx3927_pcicptr->istat & PCI_ISTAT_IDICC));
+ /* clear by setting */
+ tx3927_pcicptr->istat |= PCI_ISTAT_IDICC;
+}
+
+unsigned char tx_ioinb(unsigned char *addr)
+{
+ unsigned long val;
+ __u32 ioaddr;
+ int offset;
+ int byte;
+
+ ioaddr = (unsigned long) addr;
+ offset = ioaddr & 0x3;
+ if (offset == 0)
+ byte = 0x7;
+ else if (offset == 1)
+ byte = 0xb;
+ else if (offset == 2)
+ byte = 0xd;
+ else if (offset == 3)
+ byte = 0xe;
+ *(volatile u32 *) (ulong) & tx3927_pcicptr->ipciaddr =
+ (unsigned long) ioaddr;
+ *(volatile u32 *) (ulong) & tx3927_pcicptr->ipcibe =
+ (PCI_IPCIBE_ICMD_IOREAD << PCI_IPCIBE_ICMD_SHIFT) | byte;
+ while (!(tx3927_pcicptr->istat & PCI_ISTAT_IDICC));
+ val =
+ le32_to_cpu(*(volatile u32 *) (ulong) & tx3927_pcicptr->
+ ipcidata);
+ val = val & 0xff;
+ /* clear by setting */
+ tx3927_pcicptr->istat |= PCI_ISTAT_IDICC;
+ return val;
+}
+
+void tx_iooutb(unsigned long data, unsigned char *addr)
+{
+ __u32 ioaddr;
+ int offset;
+ int byte;
+
+ data = data | (data << 8) | (data << 16) | (data << 24);
+ ioaddr = (unsigned long) addr;
+ offset = ioaddr & 0x3;
+ if (offset == 0)
+ byte = 0x7;
+ else if (offset == 1)
+ byte = 0xb;
+ else if (offset == 2)
+ byte = 0xd;
+ else if (offset == 3)
+ byte = 0xe;
+ *(volatile u32 *) (ulong) & tx3927_pcicptr->ipcidata = data;
+ *(volatile u32 *) (ulong) & tx3927_pcicptr->ipciaddr =
+ (unsigned long) ioaddr;
+ *(volatile u32 *) (ulong) & tx3927_pcicptr->ipcibe =
+ (PCI_IPCIBE_ICMD_IOWRITE << PCI_IPCIBE_ICMD_SHIFT) | byte;
+ while (!(tx3927_pcicptr->istat & PCI_ISTAT_IDICC));
+ /* clear by setting */
+ tx3927_pcicptr->istat |= PCI_ISTAT_IDICC;
+}
+
+unsigned short tx_ioinw(unsigned short *addr)
+{
+ unsigned long val;
+ __u32 ioaddr;
+ int offset;
+ int byte;
+
+ ioaddr = (unsigned long) addr;
+ offset = ioaddr & 0x3;
+ if (offset == 0)
+ byte = 0x3;
+ else if (offset == 2)
+ byte = 0xc;
+ *(volatile u32 *) (ulong) & tx3927_pcicptr->ipciaddr =
+ (unsigned long) ioaddr;
+ *(volatile u32 *) (ulong) & tx3927_pcicptr->ipcibe =
+ (PCI_IPCIBE_ICMD_IOREAD << PCI_IPCIBE_ICMD_SHIFT) | byte;
+ while (!(tx3927_pcicptr->istat & PCI_ISTAT_IDICC));
+ val =
+ le32_to_cpu(*(volatile u32 *) (ulong) & tx3927_pcicptr->
+ ipcidata);
+ val = val & 0xffff;
+ /* clear by setting */
+ tx3927_pcicptr->istat |= PCI_ISTAT_IDICC;
+ return val;
+
+}
+
+void tx_iooutw(unsigned long data, unsigned short *addr)
+{
+ __u32 ioaddr;
+ int offset;
+ int byte;
+
+ data = data | (data << 16);
+ ioaddr = (unsigned long) addr;
+ offset = ioaddr & 0x3;
+ if (offset == 0)
+ byte = 0x3;
+ else if (offset == 2)
+ byte = 0xc;
+ *(volatile u32 *) (ulong) & tx3927_pcicptr->ipcidata = data;
+ *(volatile u32 *) (ulong) & tx3927_pcicptr->ipciaddr =
+ (unsigned long) ioaddr;
+ *(volatile u32 *) (ulong) & tx3927_pcicptr->ipcibe =
+ (PCI_IPCIBE_ICMD_IOWRITE << PCI_IPCIBE_ICMD_SHIFT) | byte;
+ while (!(tx3927_pcicptr->istat & PCI_ISTAT_IDICC));
+ /* clear by setting */
+ tx3927_pcicptr->istat |= PCI_ISTAT_IDICC;
+}
+
+unsigned long tx_ioinl(unsigned int *addr)
+{
+ unsigned long val;
+ __u32 ioaddr;
+
+ ioaddr = (unsigned long) addr;
+ *(volatile u32 *) (ulong) & tx3927_pcicptr->ipciaddr =
+ (unsigned long) ioaddr;
+ *(volatile u32 *) (ulong) & tx3927_pcicptr->ipcibe =
+ (PCI_IPCIBE_ICMD_IOREAD << PCI_IPCIBE_ICMD_SHIFT) |
+ PCI_IPCIBE_IBE_LONG;
+ while (!(tx3927_pcicptr->istat & PCI_ISTAT_IDICC));
+ val =
+ le32_to_cpu(*(volatile u32 *) (ulong) & tx3927_pcicptr->
+ ipcidata);
+ /* clear by setting */
+ tx3927_pcicptr->istat |= PCI_ISTAT_IDICC;
+ return val;
+}
+
+void tx_iooutl(unsigned long data, unsigned int *addr)
+{
+ __u32 ioaddr;
+
+ ioaddr = (unsigned long) addr;
+ *(volatile u32 *) (ulong) & tx3927_pcicptr->ipcidata =
+ cpu_to_le32(data);
+ *(volatile u32 *) (ulong) & tx3927_pcicptr->ipciaddr =
+ (unsigned long) ioaddr;
+ *(volatile u32 *) (ulong) & tx3927_pcicptr->ipcibe =
+ (PCI_IPCIBE_ICMD_IOWRITE << PCI_IPCIBE_ICMD_SHIFT) |
+ PCI_IPCIBE_IBE_LONG;
+ while (!(tx3927_pcicptr->istat & PCI_ISTAT_IDICC));
+ /* clear by setting */
+ tx3927_pcicptr->istat |= PCI_ISTAT_IDICC;
+}
+
+void tx_insbyte(unsigned char *addr, void *buffer, unsigned int count)
+{
+ unsigned char *ptr = (unsigned char *) buffer;
+
+ while (count--) {
+ *ptr++ = tx_ioinb(addr);
+ }
+}
+
+void tx_insword(unsigned short *addr, void *buffer, unsigned int count)
+{
+ unsigned short *ptr = (unsigned short *) buffer;
+
+ while (count--) {
+ *ptr++ = tx_ioinw(addr);
+ }
+}
+
+void tx_inslong(unsigned int *addr, void *buffer, unsigned int count)
+{
+ unsigned long *ptr = (unsigned long *) buffer;
+
+ while (count--) {
+ *ptr++ = tx_ioinl(addr);
+ }
+}
+
+void tx_outsbyte(unsigned char *addr, void *buffer, unsigned int count)
+{
+ unsigned char *ptr = (unsigned char *) buffer;
+
+ while (count--) {
+ tx_iooutb(*ptr++, addr);
+ }
+}
+
+void tx_outsword(unsigned short *addr, void *buffer, unsigned int count)
+{
+ unsigned short *ptr = (unsigned short *) buffer;
+
+ while (count--) {
+ tx_iooutw(*ptr++, addr);
+ }
+}
+
+void tx_outslong(unsigned int *addr, void *buffer, unsigned int count)
+{
+ unsigned long *ptr = (unsigned long *) buffer;
+
+ while (count--) {
+ tx_iooutl(*ptr++, addr);
+ }
+}
+#endif
diff --git a/arch/mips/pci/ops-tx4927.c b/arch/mips/pci/ops-tx4927.c
new file mode 100644
index 00000000000..2a9d7227fe8
--- /dev/null
+++ b/arch/mips/pci/ops-tx4927.c
@@ -0,0 +1,209 @@
+/*
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ * ahennessy@mvista.com
+ *
+ * Copyright (C) 2000-2001 Toshiba Corporation
+ * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org)
+ *
+ * Based on arch/mips/ddb5xxx/ddb5477/pci_ops.c
+ *
+ * Define the pci_ops for the Toshiba rbtx4927
+ *
+ * Much of the code is derived from the original DDB5074 port by
+ * Geert Uytterhoeven <geert@sonycom.com>
+ *
+ * Copyright 2004 MontaVista Software Inc.
+ * Author: Manish Lachwani (mlachwani@mvista.com)
+ *
+ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 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.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/addrspace.h>
+#include <asm/byteorder.h>
+#include <asm/tx4927/tx4927_pci.h>
+
+/* initialize in setup */
+struct resource pci_io_resource = {
+ .name = "TX4927 PCI IO SPACE",
+ .start = 0x1000,
+ .end = (0x1000 + (TX4927_PCIIO_SIZE)) - 1,
+ .flags = IORESOURCE_IO
+};
+
+/* initialize in setup */
+struct resource pci_mem_resource = {
+ .name = "TX4927 PCI MEM SPACE",
+ .start = TX4927_PCIMEM,
+ .end = TX4927_PCIMEM + TX4927_PCIMEM_SIZE - 1,
+ .flags = IORESOURCE_MEM
+};
+
+static int mkaddr(int bus, int dev_fn, int where, int *flagsp)
+{
+ if (bus > 0) {
+ /* Type 1 configuration */
+ tx4927_pcicptr->g2pcfgadrs = ((bus & 0xff) << 0x10) |
+ ((dev_fn & 0xff) << 0x08) | (where & 0xfc) | 1;
+ } else {
+ if (dev_fn >= PCI_DEVFN(TX4927_PCIC_MAX_DEVNU, 0))
+ return -1;
+
+ /* Type 0 configuration */
+ tx4927_pcicptr->g2pcfgadrs = ((bus & 0xff) << 0x10) |
+ ((dev_fn & 0xff) << 0x08) | (where & 0xfc);
+ }
+ /* clear M_ABORT and Disable M_ABORT Int. */
+ tx4927_pcicptr->pcistatus =
+ (tx4927_pcicptr->pcistatus & 0x0000ffff) |
+ (PCI_STATUS_REC_MASTER_ABORT << 16);
+ tx4927_pcicptr->pcimask &= ~PCI_STATUS_REC_MASTER_ABORT;
+ return 0;
+}
+
+static int check_abort(int flags)
+{
+ int code = PCIBIOS_SUCCESSFUL;
+ if (tx4927_pcicptr->
+ pcistatus & (PCI_STATUS_REC_MASTER_ABORT << 16)) {
+ tx4927_pcicptr->pcistatus =
+ (tx4927_pcicptr->
+ pcistatus & 0x0000ffff) | (PCI_STATUS_REC_MASTER_ABORT
+ << 16);
+ tx4927_pcicptr->pcimask |= PCI_STATUS_REC_MASTER_ABORT;
+ code = PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ return code;
+}
+
+static int tx4927_pcibios_read_config(struct pci_bus *bus, unsigned int devfn, int where,
+ int size, u32 * val)
+{
+ int flags, retval, dev, busno, func;
+
+ busno = bus->number;
+ dev = PCI_SLOT(devfn);
+ func = PCI_FUNC(devfn);
+
+ /* check if the bus is top-level */
+ if (bus->parent != NULL) {
+ busno = bus->number;
+ } else {
+ busno = 0;
+ }
+
+ if (mkaddr(busno, devfn, where, &flags))
+ return -1;
+
+ switch (size) {
+ case 1:
+ *val = *(volatile u8 *) ((ulong) & tx4927_pcicptr->
+ g2pcfgdata |
+#ifdef __LITTLE_ENDIAN
+ (where & 3));
+#else
+ ((where & 0x3) ^ 0x3));
+#endif
+ break;
+ case 2:
+ *val = *(volatile u16 *) ((ulong) & tx4927_pcicptr->
+ g2pcfgdata |
+#ifdef __LITTLE_ENDIAN
+ (where & 3));
+#else
+ ((where & 0x3) ^ 0x2));
+#endif
+ break;
+ case 4:
+ *val = tx4927_pcicptr->g2pcfgdata;
+ break;
+ }
+
+ retval = check_abort(flags);
+ if (retval == PCIBIOS_DEVICE_NOT_FOUND)
+ *val = 0xffffffff;
+
+ return retval;
+}
+
+static int tx4927_pcibios_write_config(struct pci_bus *bus, unsigned int devfn, int where,
+ int size, u32 val)
+{
+ int flags, dev, busno, func;
+ busno = bus->number;
+ dev = PCI_SLOT(devfn);
+ func = PCI_FUNC(devfn);
+
+ /* check if the bus is top-level */
+ if (bus->parent != NULL) {
+ busno = bus->number;
+ } else {
+ busno = 0;
+ }
+
+ if (mkaddr(busno, devfn, where, &flags))
+ return -1;
+
+ switch (size) {
+ case 1:
+ *(volatile u8 *) ((ulong) & tx4927_pcicptr->
+ g2pcfgdata |
+#ifdef __LITTLE_ENDIAN
+ (where & 3)) = val;
+#else
+ ((where & 0x3) ^ 0x3)) = val;
+#endif
+ break;
+
+ case 2:
+ *(volatile u16 *) ((ulong) & tx4927_pcicptr->
+ g2pcfgdata |
+#ifdef __LITTLE_ENDIAN
+ (where & 3)) = val;
+#else
+ ((where & 0x3) ^ 0x2)) = val;
+#endif
+ break;
+ case 4:
+ tx4927_pcicptr->g2pcfgdata = val;
+ break;
+ }
+
+ return check_abort(flags);
+}
+
+struct pci_ops tx4927_pci_ops = {
+ tx4927_pcibios_read_config,
+ tx4927_pcibios_write_config
+};
+
+/*
+ * h/w only supports devices 0x00 to 0x14
+ */
+struct pci_controller tx4927_controller = {
+ .pci_ops = &tx4927_pci_ops,
+ .io_resource = &pci_io_resource,
+ .mem_resource = &pci_mem_resource,
+};
diff --git a/arch/mips/pci/ops-vr41xx.c b/arch/mips/pci/ops-vr41xx.c
new file mode 100644
index 00000000000..44654605e46
--- /dev/null
+++ b/arch/mips/pci/ops-vr41xx.c
@@ -0,0 +1,126 @@
+/*
+ * ops-vr41xx.c, PCI configuration routines for the PCIU of NEC VR4100 series.
+ *
+ * Copyright (C) 2001-2003 MontaVista Software Inc.
+ * Author: Yoichi Yuasa <yyuasa@mvista.com or source@mvista.com>
+ * Copyright (C) 2004 Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
+ *
+ * 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
+ */
+/*
+ * Changes:
+ * MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
+ * - New creation, NEC VR4122 and VR4131 are supported.
+ */
+#include <linux/pci.h>
+#include <linux/types.h>
+
+#include <asm/io.h>
+
+#define PCICONFDREG KSEG1ADDR(0x0f000c14)
+#define PCICONFAREG KSEG1ADDR(0x0f000c18)
+
+static inline int set_pci_configuration_address(unsigned char number,
+ unsigned int devfn, int where)
+{
+ if (number == 0) {
+ /*
+ * Type 0 configuration
+ */
+ if (PCI_SLOT(devfn) < 11 || where > 0xff)
+ return -EINVAL;
+
+ writel((1U << PCI_SLOT(devfn)) | (PCI_FUNC(devfn) << 8) |
+ (where & 0xfc), PCICONFAREG);
+ } else {
+ /*
+ * Type 1 configuration
+ */
+ if (where > 0xff)
+ return -EINVAL;
+
+ writel(((uint32_t)number << 16) | ((devfn & 0xff) << 8) |
+ (where & 0xfc) | 1U, PCICONFAREG);
+ }
+
+ return 0;
+}
+
+static int pci_config_read(struct pci_bus *bus, unsigned int devfn, int where,
+ int size, uint32_t *val)
+{
+ uint32_t data;
+
+ *val = 0xffffffffU;
+ if (set_pci_configuration_address(bus->number, devfn, where) < 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ data = readl(PCICONFDREG);
+
+ switch (size) {
+ case 1:
+ *val = (data >> ((where & 3) << 3)) & 0xffU;
+ break;
+ case 2:
+ *val = (data >> ((where & 2) << 3)) & 0xffffU;
+ break;
+ case 4:
+ *val = data;
+ break;
+ default:
+ return PCIBIOS_FUNC_NOT_SUPPORTED;
+ }
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_config_write(struct pci_bus *bus, unsigned int devfn, int where,
+ int size, uint32_t val)
+{
+ uint32_t data;
+ int shift;
+
+ if (set_pci_configuration_address(bus->number, devfn, where) < 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ data = readl(PCICONFDREG);
+
+ switch (size) {
+ case 1:
+ shift = (where & 3) << 3;
+ data &= ~(0xffU << shift);
+ data |= ((val & 0xffU) << shift);
+ break;
+ case 2:
+ shift = (where & 2) << 3;
+ data &= ~(0xffffU << shift);
+ data |= ((val & 0xffffU) << shift);
+ break;
+ case 4:
+ data = val;
+ break;
+ default:
+ return PCIBIOS_FUNC_NOT_SUPPORTED;
+ }
+
+ writel(data, PCICONFDREG);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+struct pci_ops vr41xx_pci_ops = {
+ .read = pci_config_read,
+ .write = pci_config_write,
+};
diff --git a/arch/mips/pci/pci-ddb5074.c b/arch/mips/pci/pci-ddb5074.c
new file mode 100644
index 00000000000..73f9ceeb2f5
--- /dev/null
+++ b/arch/mips/pci/pci-ddb5074.c
@@ -0,0 +1,79 @@
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+
+#include <asm/debug.h>
+
+#include <asm/ddb5xxx/ddb5xxx.h>
+
+static struct resource extpci_io_resource = {
+ "pci IO space",
+ 0x1000, /* leave some room for ISA bus */
+ DDB_PCI_IO_SIZE - 1,
+ IORESOURCE_IO
+};
+
+static struct resource extpci_mem_resource = {
+ "pci memory space",
+ DDB_PCI_MEM_BASE + 0x00100000, /* leave 1 MB for RTC */
+ DDB_PCI_MEM_BASE + DDB_PCI_MEM_SIZE - 1,
+ IORESOURCE_MEM
+};
+
+extern struct pci_ops ddb5476_ext_pci_ops;
+
+struct pci_controller ddb5476_controller = {
+ .pci_ops = &ddb5476_ext_pci_ops,
+ .io_resource = &extpci_io_resource,
+ .mem_resource = &extpci_mem_resource,
+};
+
+#define PCI_EXT_INTA 8
+#define PCI_EXT_INTB 9
+#define PCI_EXT_INTC 10
+#define PCI_EXT_INTD 11
+#define PCI_EXT_INTE 12
+
+#define MAX_SLOT_NUM 14
+
+static unsigned char irq_map[MAX_SLOT_NUM] = {
+ [ 0] = nile4_to_irq(PCI_EXT_INTE),
+ [ 1] = nile4_to_irq(PCI_EXT_INTA),
+ [ 2] = nile4_to_irq(PCI_EXT_INTA),
+ [ 3] = nile4_to_irq(PCI_EXT_INTB),
+ [ 4] = nile4_to_irq(PCI_EXT_INTC),
+ [ 5] = nile4_to_irq(NILE4_INT_UART),
+ [10] = nile4_to_irq(PCI_EXT_INTE),
+ [13] = nile4_to_irq(PCI_EXT_INTE),
+};
+
+int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ return irq_map[slot];
+}
+
+/* Do platform specific device initialization at pci_enable_device() time */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+ return 0;
+}
+
+void __init ddb_pci_reset_bus(void)
+{
+ u32 temp;
+
+ /*
+ * I am not sure about the "official" procedure, the following
+ * steps work as far as I know:
+ * We first set PCI cold reset bit (bit 31) in PCICTRL-H.
+ * Then we clear the PCI warm reset bit (bit 30) to 0 in PCICTRL-H.
+ * The same is true for both PCI channels.
+ */
+ temp = ddb_in32(DDB_PCICTRL + 4);
+ temp |= 0x80000000;
+ ddb_out32(DDB_PCICTRL + 4, temp);
+ temp &= ~0xc0000000;
+ ddb_out32(DDB_PCICTRL + 4, temp);
+
+}
diff --git a/arch/mips/pci/pci-ddb5476.c b/arch/mips/pci/pci-ddb5476.c
new file mode 100644
index 00000000000..90dd4950980
--- /dev/null
+++ b/arch/mips/pci/pci-ddb5476.c
@@ -0,0 +1,93 @@
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+
+#include <asm/debug.h>
+
+#include <asm/ddb5xxx/ddb5xxx.h>
+
+static struct resource extpci_io_resource = {
+ "pci IO space",
+ 0x1000, /* leave some room for ISA bus */
+ DDB_PCI_IO_SIZE - 1,
+ IORESOURCE_IO
+};
+
+static struct resource extpci_mem_resource = {
+ "pci memory space",
+ DDB_PCI_MEM_BASE + 0x00100000, /* leave 1 MB for RTC */
+ DDB_PCI_MEM_BASE + DDB_PCI_MEM_SIZE - 1,
+ IORESOURCE_MEM
+};
+
+extern struct pci_ops ddb5476_ext_pci_ops;
+
+struct pci_controller ddb5476_controller = {
+ .pci_ops = &ddb5476_ext_pci_ops,
+ .io_resource = &extpci_io_resource,
+ .mem_resource = &extpci_mem_resource
+};
+
+
+/*
+ * we fix up irqs based on the slot number.
+ * The first entry is at AD:11.
+ *
+ * This does not work for devices on sub-buses yet.
+ */
+
+/*
+ * temporary
+ */
+
+#define PCI_EXT_INTA 8
+#define PCI_EXT_INTB 9
+#define PCI_EXT_INTC 10
+#define PCI_EXT_INTD 11
+#define PCI_EXT_INTE 12
+
+/*
+ * based on ddb5477 manual page 11
+ */
+#define MAX_SLOT_NUM 21
+static unsigned char irq_map[MAX_SLOT_NUM] = {
+ [ 2] = 9, /* AD:13 USB */
+ [ 3] = 10, /* AD:14 PMU */
+ [ 5] = 0, /* AD:16 P2P bridge */
+ [ 6] = nile4_to_irq(PCI_EXT_INTB), /* AD:17 */
+ [ 7] = nile4_to_irq(PCI_EXT_INTC), /* AD:18 */
+ [ 8] = nile4_to_irq(PCI_EXT_INTD), /* AD:19 */
+ [ 9] = nile4_to_irq(PCI_EXT_INTA), /* AD:20 */
+ [13] = 14, /* AD:24 HD controller, M5229 */
+};
+
+int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ return irq_map[slot];
+}
+
+/* Do platform specific device initialization at pci_enable_device() time */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+ return 0;
+}
+
+void __init ddb_pci_reset_bus(void)
+{
+ u32 temp;
+
+ /*
+ * I am not sure about the "official" procedure, the following
+ * steps work as far as I know:
+ * We first set PCI cold reset bit (bit 31) in PCICTRL-H.
+ * Then we clear the PCI warm reset bit (bit 30) to 0 in PCICTRL-H.
+ * The same is true for both PCI channels.
+ */
+ temp = ddb_in32(DDB_PCICTRL + 4);
+ temp |= 0x80000000;
+ ddb_out32(DDB_PCICTRL + 4, temp);
+ temp &= ~0xc0000000;
+ ddb_out32(DDB_PCICTRL + 4, temp);
+
+}
diff --git a/arch/mips/pci/pci-ddb5477.c b/arch/mips/pci/pci-ddb5477.c
new file mode 100644
index 00000000000..4ddd53eaf65
--- /dev/null
+++ b/arch/mips/pci/pci-ddb5477.c
@@ -0,0 +1,207 @@
+/*
+ * PCI code for DDB5477.
+ *
+ * Copyright (C) 2001 MontaVista Software Inc.
+ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
+ *
+ * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org)
+ *
+ * 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 <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+
+#include <asm/bootinfo.h>
+#include <asm/debug.h>
+
+#include <asm/ddb5xxx/ddb5xxx.h>
+
+static struct resource extpci_io_resource = {
+ "ext pci IO space",
+ DDB_PCI0_IO_BASE - DDB_PCI_IO_BASE + 0x4000,
+ DDB_PCI0_IO_BASE - DDB_PCI_IO_BASE + DDB_PCI0_IO_SIZE - 1,
+ IORESOURCE_IO
+};
+
+static struct resource extpci_mem_resource = {
+ "ext pci memory space",
+ DDB_PCI0_MEM_BASE + 0x100000,
+ DDB_PCI0_MEM_BASE + DDB_PCI0_MEM_SIZE - 1,
+ IORESOURCE_MEM
+};
+
+static struct resource iopci_io_resource = {
+ "io pci IO space",
+ DDB_PCI1_IO_BASE - DDB_PCI_IO_BASE,
+ DDB_PCI1_IO_BASE - DDB_PCI_IO_BASE + DDB_PCI1_IO_SIZE - 1,
+ IORESOURCE_IO
+};
+
+static struct resource iopci_mem_resource = {
+ "ext pci memory space",
+ DDB_PCI1_MEM_BASE,
+ DDB_PCI1_MEM_BASE + DDB_PCI1_MEM_SIZE - 1,
+ IORESOURCE_MEM
+};
+
+extern struct pci_ops ddb5477_ext_pci_ops;
+extern struct pci_ops ddb5477_io_pci_ops;
+
+struct pci_controller ddb5477_ext_controller = {
+ .pci_ops = &ddb5477_ext_pci_ops,
+ .io_resource = &extpci_io_resource,
+ .mem_resource = &extpci_mem_resource
+};
+
+struct pci_controller ddb5477_io_controller = {
+ .pci_ops = &ddb5477_io_pci_ops,
+ .io_resource = &iopci_io_resource,
+ .mem_resource = &iopci_mem_resource
+};
+
+
+
+/*
+ * we fix up irqs based on the slot number.
+ * The first entry is at AD:11.
+ * Fortunately this works because, although we have two pci buses,
+ * they all have different slot numbers (except for rockhopper slot 20
+ * which is handled below).
+ *
+ */
+
+/*
+ * irq mapping : device -> pci int # -> vrc4377 irq# ,
+ * ddb5477 board manual page 4 and vrc5477 manual page 46
+ */
+
+/*
+ * based on ddb5477 manual page 11
+ */
+#define MAX_SLOT_NUM 21
+static unsigned char irq_map[MAX_SLOT_NUM] = {
+ /* SLOT: 0, AD:11 */ 0xff,
+ /* SLOT: 1, AD:12 */ 0xff,
+ /* SLOT: 2, AD:13 */ 0xff,
+ /* SLOT: 3, AD:14 */ 0xff,
+ /* SLOT: 4, AD:15 */ VRC5477_IRQ_INTA, /* onboard tulip */
+ /* SLOT: 5, AD:16 */ VRC5477_IRQ_INTB, /* slot 1 */
+ /* SLOT: 6, AD:17 */ VRC5477_IRQ_INTC, /* slot 2 */
+ /* SLOT: 7, AD:18 */ VRC5477_IRQ_INTD, /* slot 3 */
+ /* SLOT: 8, AD:19 */ VRC5477_IRQ_INTE, /* slot 4 */
+ /* SLOT: 9, AD:20 */ 0xff,
+ /* SLOT: 10, AD:21 */ 0xff,
+ /* SLOT: 11, AD:22 */ 0xff,
+ /* SLOT: 12, AD:23 */ 0xff,
+ /* SLOT: 13, AD:24 */ 0xff,
+ /* SLOT: 14, AD:25 */ 0xff,
+ /* SLOT: 15, AD:26 */ 0xff,
+ /* SLOT: 16, AD:27 */ 0xff,
+ /* SLOT: 17, AD:28 */ 0xff,
+ /* SLOT: 18, AD:29 */ VRC5477_IRQ_IOPCI_INTC, /* vrc5477 ac97 */
+ /* SLOT: 19, AD:30 */ VRC5477_IRQ_IOPCI_INTB, /* vrc5477 usb peri */
+ /* SLOT: 20, AD:31 */ VRC5477_IRQ_IOPCI_INTA, /* vrc5477 usb host */
+};
+static unsigned char rockhopperII_irq_map[MAX_SLOT_NUM] = {
+ /* SLOT: 0, AD:11 */ 0xff,
+ /* SLOT: 1, AD:12 */ VRC5477_IRQ_INTB, /* onboard AMD PCNET */
+ /* SLOT: 2, AD:13 */ 0xff,
+ /* SLOT: 3, AD:14 */ 0xff,
+ /* SLOT: 4, AD:15 */ 14, /* M5229 ide ISA irq */
+ /* SLOT: 5, AD:16 */ VRC5477_IRQ_INTD, /* slot 3 */
+ /* SLOT: 6, AD:17 */ VRC5477_IRQ_INTA, /* slot 4 */
+ /* SLOT: 7, AD:18 */ VRC5477_IRQ_INTD, /* slot 5 */
+ /* SLOT: 8, AD:19 */ 0, /* M5457 modem nop */
+ /* SLOT: 9, AD:20 */ VRC5477_IRQ_INTA, /* slot 2 */
+ /* SLOT: 10, AD:21 */ 0xff,
+ /* SLOT: 11, AD:22 */ 0xff,
+ /* SLOT: 12, AD:23 */ 0xff,
+ /* SLOT: 13, AD:24 */ 0xff,
+ /* SLOT: 14, AD:25 */ 0xff,
+ /* SLOT: 15, AD:26 */ 0xff,
+ /* SLOT: 16, AD:27 */ 0xff,
+ /* SLOT: 17, AD:28 */ 0, /* M7101 PMU nop */
+ /* SLOT: 18, AD:29 */ VRC5477_IRQ_IOPCI_INTC, /* vrc5477 ac97 */
+ /* SLOT: 19, AD:30 */ VRC5477_IRQ_IOPCI_INTB, /* vrc5477 usb peri */
+ /* SLOT: 20, AD:31 */ VRC5477_IRQ_IOPCI_INTA, /* vrc5477 usb host */
+};
+
+int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ int slot_num;
+ unsigned char *slot_irq_map;
+ unsigned char irq;
+
+ /*
+ * We ignore the swizzled slot and pin values. The original
+ * pci_fixup_irq() codes largely base irq number on the dev slot
+ * numbers because except for one case they are unique even
+ * though there are multiple pci buses.
+ */
+
+ if (mips_machtype == MACH_NEC_ROCKHOPPERII)
+ slot_irq_map = rockhopperII_irq_map;
+ else
+ slot_irq_map = irq_map;
+
+ slot_num = PCI_SLOT(dev->devfn);
+ irq = slot_irq_map[slot_num];
+
+ db_assert(slot_num < MAX_SLOT_NUM);
+
+ db_assert(irq != 0xff);
+
+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
+
+ if (mips_machtype == MACH_NEC_ROCKHOPPERII) {
+ /* hack to distinquish overlapping slot 20s, one
+ * on bus 0 (ALI USB on the M1535 on the backplane),
+ * and one on bus 2 (NEC USB controller on the CPU board)
+ * Make the M1535 USB - ISA IRQ number 9.
+ */
+ if (slot_num == 20 && dev->bus->number == 0) {
+ pci_write_config_byte(dev,
+ PCI_INTERRUPT_LINE,
+ 9);
+ irq = 9;
+ }
+
+ }
+
+ return irq;
+}
+
+/* Do platform specific device initialization at pci_enable_device() time */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+ return 0;
+}
+
+void ddb_pci_reset_bus(void)
+{
+ u32 temp;
+
+ /*
+ * I am not sure about the "official" procedure, the following
+ * steps work as far as I know:
+ * We first set PCI cold reset bit (bit 31) in PCICTRL-H.
+ * Then we clear the PCI warm reset bit (bit 30) to 0 in PCICTRL-H.
+ * The same is true for both PCI channels.
+ */
+ temp = ddb_in32(DDB_PCICTL0_H);
+ temp |= 0x80000000;
+ ddb_out32(DDB_PCICTL0_H, temp);
+ temp &= ~0xc0000000;
+ ddb_out32(DDB_PCICTL0_H, temp);
+
+ temp = ddb_in32(DDB_PCICTL1_H);
+ temp |= 0x80000000;
+ ddb_out32(DDB_PCICTL1_H, temp);
+ temp &= ~0xc0000000;
+ ddb_out32(DDB_PCICTL1_H, temp);
+}
diff --git a/arch/mips/pci/pci-ev96100.c b/arch/mips/pci/pci-ev96100.c
new file mode 100644
index 00000000000..f9457ea00de
--- /dev/null
+++ b/arch/mips/pci/pci-ev96100.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2000 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ * ppopov@mvista.com or source@mvista.com
+ *
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
+ *
+ * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org)
+ *
+ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 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.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+static struct resource pci_io_resource = {
+ .name = "io pci IO space",
+ .start = 0x10000000,
+ .end = 0x11ffffff,
+ .flags = IORESOURCE_IO
+};
+
+static struct resource pci_mem_resource = {
+ .name = "ext pci memory space",
+ .start = 0x12000000,
+ .end = 0x13ffffff,
+ .flags = IORESOURCE_MEM
+};
+
+extern struct pci_ops gt96100_pci_ops;
+
+struct pci_controller ev96100_controller = {
+ .pci_ops = &gt96100_pci_ops,
+ .io_resource = &pci_io_resource,
+ .mem_resource = &pci_mem_resource,
+};
+
+static void ev96100_pci_init(void)
+{
+ register_pci_controller(&ev96100_controller);
+}
+
+arch_initcall(ev96100_pci_init);
diff --git a/arch/mips/pci/pci-ip27.c b/arch/mips/pci/pci-ip27.c
new file mode 100644
index 00000000000..068e0e508e1
--- /dev/null
+++ b/arch/mips/pci/pci-ip27.c
@@ -0,0 +1,489 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2003 Christoph Hellwig (hch@lst.de)
+ * Copyright (C) 1999, 2000, 04 Ralf Baechle (ralf@linux-mips.org)
+ * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <asm/sn/arch.h>
+#include <asm/pci/bridge.h>
+#include <asm/paccess.h>
+#include <asm/sn/intr.h>
+#include <asm/sn/sn0/hub.h>
+
+extern unsigned int allocate_irqno(void);
+
+/*
+ * Max #PCI busses we can handle; ie, max #PCI bridges.
+ */
+#define MAX_PCI_BUSSES 40
+
+/*
+ * Max #PCI devices (like scsi controllers) we handle on a bus.
+ */
+#define MAX_DEVICES_PER_PCIBUS 8
+
+/*
+ * XXX: No kmalloc available when we do our crosstalk scan,
+ * we should try to move it later in the boot process.
+ */
+static struct bridge_controller bridges[MAX_PCI_BUSSES];
+
+/*
+ * Translate from irq to software PCI bus number and PCI slot.
+ */
+struct bridge_controller *irq_to_bridge[MAX_PCI_BUSSES * MAX_DEVICES_PER_PCIBUS];
+int irq_to_slot[MAX_PCI_BUSSES * MAX_DEVICES_PER_PCIBUS];
+
+/*
+ * The Bridge ASIC supports both type 0 and type 1 access. Type 1 is
+ * not really documented, so right now I can't write code which uses it.
+ * Therefore we use type 0 accesses for now even though they won't work
+ * correcly for PCI-to-PCI bridges.
+ *
+ * The function is complicated by the ultimate brokeness of the IOC3 chip
+ * which is used in SGI systems. The IOC3 can only handle 32-bit PCI
+ * accesses and does only decode parts of it's address space.
+ */
+
+static int pci_conf0_read_config(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 * value)
+{
+ struct bridge_controller *bc = BRIDGE_CONTROLLER(bus);
+ bridge_t *bridge = bc->base;
+ int slot = PCI_SLOT(devfn);
+ int fn = PCI_FUNC(devfn);
+ volatile void *addr;
+ u32 cf, shift, mask;
+ int res;
+
+ addr = &bridge->b_type0_cfg_dev[slot].f[fn].c[PCI_VENDOR_ID];
+ if (get_dbe(cf, (u32 *) addr))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ /*
+ * IOC3 is fucked fucked beyond believe ... Don't even give the
+ * generic PCI code a chance to look at it for real ...
+ */
+ if (cf == (PCI_VENDOR_ID_SGI | (PCI_DEVICE_ID_SGI_IOC3 << 16)))
+ goto oh_my_gawd;
+
+ addr = &bridge->b_type0_cfg_dev[slot].f[fn].c[where ^ (4 - size)];
+
+ if (size == 1)
+ res = get_dbe(*value, (u8 *) addr);
+ else if (size == 2)
+ res = get_dbe(*value, (u16 *) addr);
+ else
+ res = get_dbe(*value, (u32 *) addr);
+
+ return res ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
+
+oh_my_gawd:
+
+ /*
+ * IOC3 is fucked fucked beyond believe ... Don't even give the
+ * generic PCI code a chance to look at the wrong register.
+ */
+ if ((where >= 0x14 && where < 0x40) || (where >= 0x48)) {
+ *value = 0;
+ return PCIBIOS_SUCCESSFUL;
+ }
+
+ /*
+ * IOC3 is fucked fucked beyond believe ... Don't try to access
+ * anything but 32-bit words ...
+ */
+ addr = &bridge->b_type0_cfg_dev[slot].f[fn].l[where >> 2];
+
+ if (get_dbe(cf, (u32 *) addr))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ shift = ((where & 3) << 3);
+ mask = (0xffffffffU >> ((4 - size) << 3));
+ *value = (cf >> shift) & mask;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_conf1_read_config(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 * value)
+{
+ struct bridge_controller *bc = BRIDGE_CONTROLLER(bus);
+ bridge_t *bridge = bc->base;
+ int busno = bus->number;
+ int slot = PCI_SLOT(devfn);
+ int fn = PCI_FUNC(devfn);
+ volatile void *addr;
+ u32 cf, shift, mask;
+ int res;
+
+ bridge->b_pci_cfg = (busno << 16) | (slot << 11);
+ addr = &bridge->b_type1_cfg.c[(fn << 8) | PCI_VENDOR_ID];
+ if (get_dbe(cf, (u32 *) addr))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ /*
+ * IOC3 is fucked fucked beyond believe ... Don't even give the
+ * generic PCI code a chance to look at it for real ...
+ */
+ if (cf == (PCI_VENDOR_ID_SGI | (PCI_DEVICE_ID_SGI_IOC3 << 16)))
+ goto oh_my_gawd;
+
+ bridge->b_pci_cfg = (busno << 16) | (slot << 11);
+ addr = &bridge->b_type1_cfg.c[(fn << 8) | (where ^ (4 - size))];
+
+ if (size == 1)
+ res = get_dbe(*value, (u8 *) addr);
+ else if (size == 2)
+ res = get_dbe(*value, (u16 *) addr);
+ else
+ res = get_dbe(*value, (u32 *) addr);
+
+ return res ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
+
+oh_my_gawd:
+
+ /*
+ * IOC3 is fucked fucked beyond believe ... Don't even give the
+ * generic PCI code a chance to look at the wrong register.
+ */
+ if ((where >= 0x14 && where < 0x40) || (where >= 0x48)) {
+ *value = 0;
+ return PCIBIOS_SUCCESSFUL;
+ }
+
+ /*
+ * IOC3 is fucked fucked beyond believe ... Don't try to access
+ * anything but 32-bit words ...
+ */
+ bridge->b_pci_cfg = (busno << 16) | (slot << 11);
+ addr = &bridge->b_type1_cfg.c[(fn << 8) | where];
+
+ if (get_dbe(cf, (u32 *) addr))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ shift = ((where & 3) << 3);
+ mask = (0xffffffffU >> ((4 - size) << 3));
+ *value = (cf >> shift) & mask;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_read_config(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 * value)
+{
+ if (bus->number > 0)
+ return pci_conf1_read_config(bus, devfn, where, size, value);
+
+ return pci_conf0_read_config(bus, devfn, where, size, value);
+}
+
+static int pci_conf0_write_config(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 value)
+{
+ struct bridge_controller *bc = BRIDGE_CONTROLLER(bus);
+ bridge_t *bridge = bc->base;
+ int slot = PCI_SLOT(devfn);
+ int fn = PCI_FUNC(devfn);
+ volatile void *addr;
+ u32 cf, shift, mask, smask;
+ int res;
+
+ addr = &bridge->b_type0_cfg_dev[slot].f[fn].c[PCI_VENDOR_ID];
+ if (get_dbe(cf, (u32 *) addr))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ /*
+ * IOC3 is fucked fucked beyond believe ... Don't even give the
+ * generic PCI code a chance to look at it for real ...
+ */
+ if (cf == (PCI_VENDOR_ID_SGI | (PCI_DEVICE_ID_SGI_IOC3 << 16)))
+ goto oh_my_gawd;
+
+ addr = &bridge->b_type0_cfg_dev[slot].f[fn].c[where ^ (4 - size)];
+
+ if (size == 1) {
+ res = put_dbe(value, (u8 *) addr);
+ } else if (size == 2) {
+ res = put_dbe(value, (u16 *) addr);
+ } else {
+ res = put_dbe(value, (u32 *) addr);
+ }
+
+ if (res)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ return PCIBIOS_SUCCESSFUL;
+
+oh_my_gawd:
+
+ /*
+ * IOC3 is fucked fucked beyond believe ... Don't even give the
+ * generic PCI code a chance to touch the wrong register.
+ */
+ if ((where >= 0x14 && where < 0x40) || (where >= 0x48))
+ return PCIBIOS_SUCCESSFUL;
+
+ /*
+ * IOC3 is fucked fucked beyond believe ... Don't try to access
+ * anything but 32-bit words ...
+ */
+ addr = &bridge->b_type0_cfg_dev[slot].f[fn].l[where >> 2];
+
+ if (get_dbe(cf, (u32 *) addr))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ shift = ((where & 3) << 3);
+ mask = (0xffffffffU >> ((4 - size) << 3));
+ smask = mask << shift;
+
+ cf = (cf & ~smask) | ((value & mask) << shift);
+ if (put_dbe(cf, (u32 *) addr))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_conf1_write_config(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 value)
+{
+ struct bridge_controller *bc = BRIDGE_CONTROLLER(bus);
+ bridge_t *bridge = bc->base;
+ int slot = PCI_SLOT(devfn);
+ int fn = PCI_FUNC(devfn);
+ int busno = bus->number;
+ volatile void *addr;
+ u32 cf, shift, mask, smask;
+ int res;
+
+ bridge->b_pci_cfg = (busno << 16) | (slot << 11);
+ addr = &bridge->b_type1_cfg.c[(fn << 8) | PCI_VENDOR_ID];
+ if (get_dbe(cf, (u32 *) addr))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ /*
+ * IOC3 is fucked fucked beyond believe ... Don't even give the
+ * generic PCI code a chance to look at it for real ...
+ */
+ if (cf == (PCI_VENDOR_ID_SGI | (PCI_DEVICE_ID_SGI_IOC3 << 16)))
+ goto oh_my_gawd;
+
+ addr = &bridge->b_type1_cfg.c[(fn << 8) | (where ^ (4 - size))];
+
+ if (size == 1) {
+ res = put_dbe(value, (u8 *) addr);
+ } else if (size == 2) {
+ res = put_dbe(value, (u16 *) addr);
+ } else {
+ res = put_dbe(value, (u32 *) addr);
+ }
+
+ if (res)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ return PCIBIOS_SUCCESSFUL;
+
+oh_my_gawd:
+
+ /*
+ * IOC3 is fucked fucked beyond believe ... Don't even give the
+ * generic PCI code a chance to touch the wrong register.
+ */
+ if ((where >= 0x14 && where < 0x40) || (where >= 0x48))
+ return PCIBIOS_SUCCESSFUL;
+
+ /*
+ * IOC3 is fucked fucked beyond believe ... Don't try to access
+ * anything but 32-bit words ...
+ */
+ addr = &bridge->b_type0_cfg_dev[slot].f[fn].l[where >> 2];
+
+ if (get_dbe(cf, (u32 *) addr))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ shift = ((where & 3) << 3);
+ mask = (0xffffffffU >> ((4 - size) << 3));
+ smask = mask << shift;
+
+ cf = (cf & ~smask) | ((value & mask) << shift);
+ if (put_dbe(cf, (u32 *) addr))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_write_config(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 value)
+{
+ if (bus->number > 0)
+ return pci_conf1_write_config(bus, devfn, where, size, value);
+
+ return pci_conf0_write_config(bus, devfn, where, size, value);
+}
+
+static struct pci_ops bridge_pci_ops = {
+ .read = pci_read_config,
+ .write = pci_write_config,
+};
+
+int __init bridge_probe(nasid_t nasid, int widget_id, int masterwid)
+{
+ unsigned long offset = NODE_OFFSET(nasid);
+ struct bridge_controller *bc;
+ static int num_bridges = 0;
+ bridge_t *bridge;
+ int slot;
+
+ printk("a bridge\n");
+
+ /* XXX: kludge alert.. */
+ if (!num_bridges)
+ ioport_resource.end = ~0UL;
+
+ bc = &bridges[num_bridges];
+
+ bc->pc.pci_ops = &bridge_pci_ops;
+ bc->pc.mem_resource = &bc->mem;
+ bc->pc.io_resource = &bc->io;
+
+ bc->pc.index = num_bridges;
+
+ bc->mem.name = "Bridge PCI MEM";
+ bc->pc.mem_offset = offset;
+ bc->mem.start = 0;
+ bc->mem.end = ~0UL;
+ bc->mem.flags = IORESOURCE_MEM;
+
+ bc->io.name = "Bridge IO MEM";
+ bc->pc.io_offset = offset;
+ bc->io.start = 0UL;
+ bc->io.end = ~0UL;
+ bc->io.flags = IORESOURCE_IO;
+
+ bc->irq_cpu = smp_processor_id();
+ bc->widget_id = widget_id;
+ bc->nasid = nasid;
+
+ bc->baddr = (u64)masterwid << 60;
+ bc->baddr |= (1UL << 56); /* Barrier set */
+
+ /*
+ * point to this bridge
+ */
+ bridge = (bridge_t *) RAW_NODE_SWIN_BASE(nasid, widget_id);
+
+ /*
+ * Clear all pending interrupts.
+ */
+ bridge->b_int_rst_stat = BRIDGE_IRR_ALL_CLR;
+
+ /*
+ * Until otherwise set up, assume all interrupts are from slot 0
+ */
+ bridge->b_int_device = 0x0;
+
+ /*
+ * swap pio's to pci mem and io space (big windows)
+ */
+ bridge->b_wid_control |= BRIDGE_CTRL_IO_SWAP |
+ BRIDGE_CTRL_MEM_SWAP;
+
+ /*
+ * Hmm... IRIX sets additional bits in the address which
+ * are documented as reserved in the bridge docs.
+ */
+ bridge->b_wid_int_upper = 0x8000 | (masterwid << 16);
+ bridge->b_wid_int_lower = 0x01800090; /* PI_INT_PEND_MOD off*/
+ bridge->b_dir_map = (masterwid << 20); /* DMA */
+ bridge->b_int_enable = 0;
+
+ for (slot = 0; slot < 8; slot ++) {
+ bridge->b_device[slot].reg |= BRIDGE_DEV_SWAP_DIR;
+ bc->pci_int[slot] = -1;
+ }
+ bridge->b_wid_tflush; /* wait until Bridge PIO complete */
+
+ bc->base = bridge;
+
+ register_pci_controller(&bc->pc);
+
+ num_bridges++;
+
+ return 0;
+}
+
+/*
+ * All observed requests have pin == 1. We could have a global here, that
+ * gets incremented and returned every time - unfortunately, pci_map_irq
+ * may be called on the same device over and over, and need to return the
+ * same value. On O2000, pin can be 0 or 1, and PCI slots can be [0..7].
+ *
+ * A given PCI device, in general, should be able to intr any of the cpus
+ * on any one of the hubs connected to its xbow.
+ */
+int __devinit pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ struct bridge_controller *bc = BRIDGE_CONTROLLER(dev->bus);
+ int irq = bc->pci_int[slot];
+
+ if (irq == -1) {
+ irq = bc->pci_int[slot] = request_bridge_irq(bc);
+ if (irq < 0)
+ panic("Can't allocate interrupt for PCI device %s\n",
+ pci_name(dev));
+ }
+
+ irq_to_bridge[irq] = bc;
+ irq_to_slot[irq] = slot;
+
+ return irq;
+}
+
+/* Do platform specific device initialization at pci_enable_device() time */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+ return 0;
+}
+
+/*
+ * Device might live on a subordinate PCI bus. XXX Walk up the chain of buses
+ * to find the slot number in sense of the bridge device register.
+ * XXX This also means multiple devices might rely on conflicting bridge
+ * settings.
+ */
+
+static inline void pci_disable_swapping(struct pci_dev *dev)
+{
+ struct bridge_controller *bc = BRIDGE_CONTROLLER(dev->bus);
+ bridge_t *bridge = bc->base;
+ int slot = PCI_SLOT(dev->devfn);
+
+ /* Turn off byte swapping */
+ bridge->b_device[slot].reg &= ~BRIDGE_DEV_SWAP_DIR;
+ bridge->b_widget.w_tflush; /* Flush */
+}
+
+static inline void pci_enable_swapping(struct pci_dev *dev)
+{
+ struct bridge_controller *bc = BRIDGE_CONTROLLER(dev->bus);
+ bridge_t *bridge = bc->base;
+ int slot = PCI_SLOT(dev->devfn);
+
+ /* Turn on byte swapping */
+ bridge->b_device[slot].reg |= BRIDGE_DEV_SWAP_DIR;
+ bridge->b_widget.w_tflush; /* Flush */
+}
+
+static void __init pci_fixup_ioc3(struct pci_dev *d)
+{
+ pci_disable_swapping(d);
+}
+
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3,
+ pci_fixup_ioc3);
diff --git a/arch/mips/pci/pci-ip32.c b/arch/mips/pci/pci-ip32.c
new file mode 100644
index 00000000000..1faeb034f06
--- /dev/null
+++ b/arch/mips/pci/pci-ip32.c
@@ -0,0 +1,145 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2000, 2001 Keith M Wesolowski
+ * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org)
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/types.h>
+#include <asm/ip32/mace.h>
+#include <asm/ip32/ip32_ints.h>
+
+#undef DEBUG_MACE_PCI
+
+/*
+ * Handle errors from the bridge. This includes master and target aborts,
+ * various command and address errors, and the interrupt test. This gets
+ * registered on the bridge error irq. It's conceivable that some of these
+ * conditions warrant a panic. Anybody care to say which ones?
+ */
+static irqreturn_t macepci_error(int irq, void *dev, struct pt_regs *regs)
+{
+ char s;
+ unsigned int flags = mace->pci.error;
+ unsigned int addr = mace->pci.error_addr;
+
+ if (flags & MACEPCI_ERROR_MEMORY_ADDR)
+ s = 'M';
+ else if (flags & MACEPCI_ERROR_CONFIG_ADDR)
+ s = 'C';
+ else
+ s = 'X';
+
+ if (flags & MACEPCI_ERROR_MASTER_ABORT) {
+ printk("MACEPCI: Master abort at 0x%08x (%c)\n", addr, s);
+ flags &= ~MACEPCI_ERROR_MASTER_ABORT;
+ }
+ if (flags & MACEPCI_ERROR_TARGET_ABORT) {
+ printk("MACEPCI: Target abort at 0x%08x (%c)\n", addr, s);
+ flags &= ~MACEPCI_ERROR_TARGET_ABORT;
+ }
+ if (flags & MACEPCI_ERROR_DATA_PARITY_ERR) {
+ printk("MACEPCI: Data parity error at 0x%08x (%c)\n", addr, s);
+ flags &= ~MACEPCI_ERROR_DATA_PARITY_ERR;
+ }
+ if (flags & MACEPCI_ERROR_RETRY_ERR) {
+ printk("MACEPCI: Retry error at 0x%08x (%c)\n", addr, s);
+ flags &= ~MACEPCI_ERROR_RETRY_ERR;
+ }
+ if (flags & MACEPCI_ERROR_ILLEGAL_CMD) {
+ printk("MACEPCI: Illegal command at 0x%08x (%c)\n", addr, s);
+ flags &= ~MACEPCI_ERROR_ILLEGAL_CMD;
+ }
+ if (flags & MACEPCI_ERROR_SYSTEM_ERR) {
+ printk("MACEPCI: System error at 0x%08x (%c)\n", addr, s);
+ flags &= ~MACEPCI_ERROR_SYSTEM_ERR;
+ }
+ if (flags & MACEPCI_ERROR_PARITY_ERR) {
+ printk("MACEPCI: Parity error at 0x%08x (%c)\n", addr, s);
+ flags &= ~MACEPCI_ERROR_PARITY_ERR;
+ }
+ if (flags & MACEPCI_ERROR_OVERRUN) {
+ printk("MACEPCI: Overrun error at 0x%08x (%c)\n", addr, s);
+ flags &= ~MACEPCI_ERROR_OVERRUN;
+ }
+ if (flags & MACEPCI_ERROR_SIG_TABORT) {
+ printk("MACEPCI: Signaled target abort (clearing)\n");
+ flags &= ~MACEPCI_ERROR_SIG_TABORT;
+ }
+ if (flags & MACEPCI_ERROR_INTERRUPT_TEST) {
+ printk("MACEPCI: Interrupt test triggered (clearing)\n");
+ flags &= ~MACEPCI_ERROR_INTERRUPT_TEST;
+ }
+
+ mace->pci.error = flags;
+
+ return IRQ_HANDLED;
+}
+
+
+extern struct pci_ops mace_pci_ops;
+#ifdef CONFIG_MIPS64
+static struct resource mace_pci_mem_resource = {
+ .name = "SGI O2 PCI MEM",
+ .start = MACEPCI_HI_MEMORY,
+ .end = 0x2FFFFFFFFUL,
+ .flags = IORESOURCE_MEM,
+};
+static struct resource mace_pci_io_resource = {
+ .name = "SGI O2 PCI IO",
+ .start = 0x00000000UL,
+ .end = 0xffffffffUL,
+ .flags = IORESOURCE_IO,
+};
+#define MACE_PCI_MEM_OFFSET 0x200000000
+#else
+static struct resource mace_pci_mem_resource = {
+ .name = "SGI O2 PCI MEM",
+ .start = MACEPCI_LOW_MEMORY,
+ .end = MACEPCI_LOW_MEMORY + 0x2000000 - 1,
+ .flags = IORESOURCE_MEM,
+};
+static struct resource mace_pci_io_resource = {
+ .name = "SGI O2 PCI IO",
+ .start = 0x00000000,
+ .end = 0xFFFFFFFF,
+ .flags = IORESOURCE_IO,
+};
+#define MACE_PCI_MEM_OFFSET (MACEPCI_LOW_MEMORY - 0x80000000)
+#endif
+static struct pci_controller mace_pci_controller = {
+ .pci_ops = &mace_pci_ops,
+ .mem_resource = &mace_pci_mem_resource,
+ .io_resource = &mace_pci_io_resource,
+ .iommu = 0,
+ .mem_offset = MACE_PCI_MEM_OFFSET,
+ .io_offset = 0,
+};
+
+static int __init mace_init(void)
+{
+ PCIBIOS_MIN_IO = 0x1000;
+
+ /* Clear any outstanding errors and enable interrupts */
+ mace->pci.error_addr = 0;
+ mace->pci.error = 0;
+ mace->pci.control = 0xff008500;
+
+ printk("MACE PCI rev %d\n", mace->pci.rev);
+
+ BUG_ON(request_irq(MACE_PCI_BRIDGE_IRQ, macepci_error, 0,
+ "MACE PCI error", NULL));
+
+ ioport_resource.end = mace_pci_io_resource.end;
+ register_pci_controller(&mace_pci_controller);
+
+ return 0;
+}
+
+arch_initcall(mace_init);
diff --git a/arch/mips/pci/pci-jmr3927.c b/arch/mips/pci/pci-jmr3927.c
new file mode 100644
index 00000000000..95a028769e5
--- /dev/null
+++ b/arch/mips/pci/pci-jmr3927.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ * ahennessy@mvista.com
+ *
+ * Copyright (C) 2000-2001 Toshiba Corporation
+ * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org)
+ *
+ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 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.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/jmr3927/jmr3927.h>
+#include <asm/debug.h>
+
+struct resource pci_io_resource = {
+ "IO MEM",
+ 0x1000, /* reserve regacy I/O space */
+ 0x1000 + JMR3927_PCIIO_SIZE - 1,
+ IORESOURCE_IO
+};
+
+struct resource pci_mem_resource = {
+ "PCI MEM",
+ JMR3927_PCIMEM,
+ JMR3927_PCIMEM + JMR3927_PCIMEM_SIZE - 1,
+ IORESOURCE_MEM
+};
+
+extern struct pci_ops jmr3927_pci_ops;
+
+struct pci_controller jmr3927_controller = {
+ .pci_ops = &jmr3927_pci_ops,
+ .io_resource = &pci_io_resource,
+ .mem_resource = &pci_mem_resource,
+ .mem_offset = JMR3927_PCIMEM;
+};
diff --git a/arch/mips/pci/pci-lasat.c b/arch/mips/pci/pci-lasat.c
new file mode 100644
index 00000000000..ae3cc4b254b
--- /dev/null
+++ b/arch/mips/pci/pci-lasat.c
@@ -0,0 +1,95 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2000, 2001, 04 Keith M Wesolowski
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <asm/bootinfo.h>
+
+extern struct pci_ops nile4_pci_ops;
+extern struct pci_ops gt64120_pci_ops;
+static struct resource lasat_pci_mem_resource = {
+ .name = "LASAT PCI MEM",
+ .start = 0x18000000,
+ .end = 0x19FFFFFF,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct resource lasat_pci_io_resource = {
+ .name = "LASAT PCI IO",
+ .start = 0x1a000000,
+ .end = 0x1bFFFFFF,
+ .flags = IORESOURCE_IO,
+};
+
+static struct pci_controller lasat_pci_controller = {
+ .mem_resource = &lasat_pci_mem_resource,
+ .io_resource = &lasat_pci_io_resource,
+};
+
+static int __init lasat_pci_setup(void)
+{
+ printk("PCI: starting\n");
+
+ switch (mips_machtype) {
+ case MACH_LASAT_100:
+ lasat_pci_controller.pci_ops = &gt64120_pci_ops;
+ break;
+ case MACH_LASAT_200:
+ lasat_pci_controller.pci_ops = &nile4_pci_ops;
+ break;
+ default:
+ panic("pcibios_init: mips_machtype incorrect");
+ }
+
+ register_pci_controller(&lasat_pci_controller);
+ return 0;
+}
+early_initcall(lasat_pci_setup);
+
+#define LASATINT_ETH1 0
+#define LASATINT_ETH0 1
+#define LASATINT_HDC 2
+#define LASATINT_COMP 3
+#define LASATINT_HDLC 4
+#define LASATINT_PCIA 5
+#define LASATINT_PCIB 6
+#define LASATINT_PCIC 7
+#define LASATINT_PCID 8
+
+int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ switch (slot) {
+ case 1:
+ return LASATINT_PCIA; /* Expansion Module 0 */
+ case 2:
+ return LASATINT_PCIB; /* Expansion Module 1 */
+ case 3:
+ return LASATINT_PCIC; /* Expansion Module 2 */
+ case 4:
+ return LASATINT_ETH1; /* Ethernet 1 (LAN 2) */
+ case 5:
+ return LASATINT_ETH0; /* Ethernet 0 (LAN 1) */
+ case 6:
+ return LASATINT_HDC; /* IDE controller */
+ default:
+ return 0xff; /* Illegal */
+ }
+
+ return -1;
+}
+
+/* Do platform specific device initialization at pci_enable_device() time */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+ return 0;
+}
diff --git a/arch/mips/pci/pci-ocelot-c.c b/arch/mips/pci/pci-ocelot-c.c
new file mode 100644
index 00000000000..1d84d36e034
--- /dev/null
+++ b/arch/mips/pci/pci-ocelot-c.c
@@ -0,0 +1,143 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org)
+ */
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <asm/mv64340.h>
+
+#include <linux/init.h>
+
+/*
+ * We assume the address ranges have already been setup appropriately by
+ * the firmware. PMON in case of the Ocelot C does that.
+ */
+static struct resource mv_pci_io_mem0_resource = {
+ .name = "MV64340 PCI0 IO MEM",
+ .flags = IORESOURCE_IO
+};
+
+static struct resource mv_pci_mem0_resource = {
+ .name = "MV64340 PCI0 MEM",
+ .flags = IORESOURCE_MEM
+};
+
+static struct mv_pci_controller mv_bus0_controller = {
+ .pcic = {
+ .pci_ops = &mv_pci_ops,
+ .mem_resource = &mv_pci_mem0_resource,
+ .io_resource = &mv_pci_io_mem0_resource,
+ },
+ .config_addr = MV64340_PCI_0_CONFIG_ADDR,
+ .config_vreg = MV64340_PCI_0_CONFIG_DATA_VIRTUAL_REG,
+};
+
+static uint32_t mv_io_base, mv_io_size;
+
+static void mv64340_pci0_init(void)
+{
+ uint32_t mem0_base, mem0_size;
+ uint32_t io_base, io_size;
+
+ io_base = MV_READ(MV64340_PCI_0_IO_BASE_ADDR) << 16;
+ io_size = (MV_READ(MV64340_PCI_0_IO_SIZE) + 1) << 16;
+ mem0_base = MV_READ(MV64340_PCI_0_MEMORY0_BASE_ADDR) << 16;
+ mem0_size = (MV_READ(MV64340_PCI_0_MEMORY0_SIZE) + 1) << 16;
+
+ mv_pci_io_mem0_resource.start = 0;
+ mv_pci_io_mem0_resource.end = io_size - 1;
+ mv_pci_mem0_resource.start = mem0_base;
+ mv_pci_mem0_resource.end = mem0_base + mem0_size - 1;
+ mv_bus0_controller.pcic.mem_offset = mem0_base;
+ mv_bus0_controller.pcic.io_offset = 0;
+
+ ioport_resource.end = io_size - 1;
+
+ register_pci_controller(&mv_bus0_controller.pcic);
+
+ mv_io_base = io_base;
+ mv_io_size = io_size;
+}
+
+static struct resource mv_pci_io_mem1_resource = {
+ .name = "MV64340 PCI1 IO MEM",
+ .flags = IORESOURCE_IO
+};
+
+static struct resource mv_pci_mem1_resource = {
+ .name = "MV64340 PCI1 MEM",
+ .flags = IORESOURCE_MEM
+};
+
+static struct mv_pci_controller mv_bus1_controller = {
+ .pcic = {
+ .pci_ops = &mv_pci_ops,
+ .mem_resource = &mv_pci_mem1_resource,
+ .io_resource = &mv_pci_io_mem1_resource,
+ },
+ .config_addr = MV64340_PCI_1_CONFIG_ADDR,
+ .config_vreg = MV64340_PCI_1_CONFIG_DATA_VIRTUAL_REG,
+};
+
+static __init void mv64340_pci1_init(void)
+{
+ uint32_t mem0_base, mem0_size;
+ uint32_t io_base, io_size;
+
+ io_base = MV_READ(MV64340_PCI_1_IO_BASE_ADDR) << 16;
+ io_size = (MV_READ(MV64340_PCI_1_IO_SIZE) + 1) << 16;
+ mem0_base = MV_READ(MV64340_PCI_1_MEMORY0_BASE_ADDR) << 16;
+ mem0_size = (MV_READ(MV64340_PCI_1_MEMORY0_SIZE) + 1) << 16;
+
+ /*
+ * Here we assume the I/O window of second bus to be contiguous with
+ * the first. A gap is no problem but would waste address space for
+ * remapping the port space.
+ */
+ mv_pci_io_mem1_resource.start = mv_io_size;
+ mv_pci_io_mem1_resource.end = mv_io_size + io_size - 1;
+ mv_pci_mem1_resource.start = mem0_base;
+ mv_pci_mem1_resource.end = mem0_base + mem0_size - 1;
+ mv_bus1_controller.pcic.mem_offset = mem0_base;
+ mv_bus1_controller.pcic.io_offset = 0;
+
+ ioport_resource.end = io_base + io_size -mv_io_base - 1;
+
+ register_pci_controller(&mv_bus1_controller.pcic);
+
+ mv_io_size = io_base + io_size - mv_io_base;
+}
+
+static __init int __init ocelot_c_pci_init(void)
+{
+ unsigned long io_v_base;
+ uint32_t enable;
+
+ enable = ~MV_READ(MV64340_BASE_ADDR_ENABLE);
+
+ /*
+ * We require at least one enabled I/O or PCI memory window or we
+ * will ignore this PCI bus. We ignore PCI windows 1, 2 and 3.
+ */
+ if (enable & (0x01 << 9) || enable & (0x01 << 10))
+ mv64340_pci0_init();
+
+ if (enable & (0x01 << 14) || enable & (0x01 << 15))
+ mv64340_pci1_init();
+
+ if (mv_io_size) {
+ io_v_base = (unsigned long) ioremap(mv_io_base, mv_io_size);
+ if (!io_v_base)
+ panic("Could not ioremap I/O port range");
+
+ set_io_port_base(io_v_base);
+ }
+
+ return 0;
+}
+
+arch_initcall(ocelot_c_pci_init);
diff --git a/arch/mips/pci/pci-ocelot-g.c b/arch/mips/pci/pci-ocelot-g.c
new file mode 100644
index 00000000000..1e3430154fa
--- /dev/null
+++ b/arch/mips/pci/pci-ocelot-g.c
@@ -0,0 +1,97 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org)
+ *
+ * This doesn't really fly - but I don't have a GT64240 system for testing.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <asm/gt64240.h>
+
+/*
+ * We assume these address ranges have been programmed into the GT-64240 by
+ * the firmware. PMON in case of the Ocelot G does that. Note the size of
+ * the I/O range is completly stupid; I/O mappings are limited to at most
+ * 256 bytes by the PCI spec and deprecated; and just to make things worse
+ * apparently many devices don't decode more than 64k of I/O space.
+ */
+
+#define gt_io_size 0x20000000UL
+#define gt_io_base 0xe0000000UL
+
+static struct resource gt_pci_mem0_resource = {
+ .name = "MV64240 PCI0 MEM",
+ .start = 0xc0000000UL,
+ .end = 0xcfffffffUL,
+ .flags = IORESOURCE_MEM
+};
+
+static struct resource gt_pci_io_mem0_resource = {
+ .name = "MV64240 PCI0 IO MEM",
+ .start = 0xe0000000UL,
+ .end = 0xefffffffUL,
+ .flags = IORESOURCE_IO
+};
+
+static struct mv_pci_controller gt_bus0_controller = {
+ .pcic = {
+ .pci_ops = &mv_pci_ops,
+ .mem_resource = &gt_pci_mem0_resource,
+ .mem_offset = 0xc0000000UL,
+ .io_resource = &gt_pci_io_mem0_resource,
+ .io_offset = 0x00000000UL
+ },
+ .config_addr = PCI_0CONFIGURATION_ADDRESS,
+ .config_vreg = PCI_0CONFIGURATION_DATA_VIRTUAL_REGISTER,
+};
+
+static struct resource gt_pci_mem1_resource = {
+ .name = "MV64240 PCI1 MEM",
+ .start = 0xd0000000UL,
+ .end = 0xdfffffffUL,
+ .flags = IORESOURCE_MEM
+};
+
+static struct resource gt_pci_io_mem1_resource = {
+ .name = "MV64240 PCI1 IO MEM",
+ .start = 0xf0000000UL,
+ .end = 0xffffffffUL,
+ .flags = IORESOURCE_IO
+};
+
+static struct mv_pci_controller gt_bus1_controller = {
+ .pcic = {
+ .pci_ops = &mv_pci_ops,
+ .mem_resource = &gt_pci_mem1_resource,
+ .mem_offset = 0xd0000000UL,
+ .io_resource = &gt_pci_io_mem1_resource,
+ .io_offset = 0x10000000UL
+ },
+ .config_addr = PCI_1CONFIGURATION_ADDRESS,
+ .config_vreg = PCI_1CONFIGURATION_DATA_VIRTUAL_REGISTER,
+};
+
+static __init int __init ocelot_g_pci_init(void)
+{
+ unsigned long io_v_base;
+
+ if (gt_io_size) {
+ io_v_base = (unsigned long) ioremap(gt_io_base, gt_io_size);
+ if (!io_v_base)
+ panic("Could not ioremap I/O port range");
+
+ set_io_port_base(io_v_base);
+ }
+
+ register_pci_controller(&gt_bus0_controller.pcic);
+ register_pci_controller(&gt_bus1_controller.pcic);
+
+ return 0;
+}
+
+arch_initcall(ocelot_g_pci_init);
diff --git a/arch/mips/pci/pci-ocelot.c b/arch/mips/pci/pci-ocelot.c
new file mode 100644
index 00000000000..3da8a4ee6ba
--- /dev/null
+++ b/arch/mips/pci/pci-ocelot.c
@@ -0,0 +1,107 @@
+/*
+ * BRIEF MODULE DESCRIPTION
+ * Galileo Evaluation Boards PCI support.
+ *
+ * The general-purpose functions to read/write and configure the GT64120A's
+ * PCI registers (function names start with pci0 or pci1) are either direct
+ * copies of functions written by Galileo Technology, or are modifications
+ * of their functions to work with Linux 2.4 vs Linux 2.2. These functions
+ * are Copyright - Galileo Technology.
+ *
+ * Other functions are derived from other MIPS PCI implementations, or were
+ * written by RidgeRun, Inc, Copyright (C) 2000 RidgeRun, Inc.
+ * glonnon@ridgerun.com, skranz@ridgerun.com, stevej@ridgerun.com
+ *
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
+ *
+ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 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.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/cache.h>
+#include <asm/pci.h>
+#include <asm/io.h>
+#include <asm/gt64120.h>
+
+static inline unsigned int pci0ReadConfigReg(unsigned int offset)
+{
+ unsigned int DataForRegCf8;
+ unsigned int data;
+
+ DataForRegCf8 = ((PCI_SLOT(device->devfn) << 11) |
+ (PCI_FUNC(device->devfn) << 8) |
+ (offset & ~0x3)) | 0x80000000;
+ GT_WRITE(GT_PCI0_CFGADDR_OFS, DataForRegCf8);
+ GT_READ(GT_PCI0_CFGDATA_OFS, &data);
+
+ return data;
+}
+
+static inline void pci0WriteConfigReg(unsigned int offset, unsigned int data)
+{
+ unsigned int DataForRegCf8;
+
+ DataForRegCf8 = ((PCI_SLOT(device->devfn) << 11) |
+ (PCI_FUNC(device->devfn) << 8) |
+ (offset & ~0x3)) | 0x80000000;
+ GT_WRITE(GT_PCI0_CFGADDR_OFS, DataForRegCf8);
+ GT_WRITE(GT_PCI0_CFGDATA_OFS, data);
+}
+
+static struct resource ocelot_mem_resource = {
+ iomem_resource.start = GT_PCI_MEM_BASE;
+ iomem_resource.end = GT_PCI_MEM_BASE + GT_PCI_MEM_BASE - 1;
+};
+
+static struct resource ocelot_io_resource = {
+ ioport_resource.start = GT_PCI_IO_BASE;
+ ioport_resource.end = GT_PCI_IO_BASE + GT_PCI_IO_SIZE - 1;
+};
+
+static struct pci_controller ocelot_pci_controller = {
+ .pci_ops = gt64120_pci_ops;
+ .mem_resource = &ocelot_mem_resource;
+ .io_resource = &ocelot_io_resource;
+};
+
+static int __init ocelot_pcibios_init(void)
+{
+ u32 tmp;
+
+ GT_READ(GT_PCI0_CMD_OFS, &tmp);
+ GT_READ(GT_PCI0_BARE_OFS, &tmp);
+
+ /*
+ * You have to enable bus mastering to configure any other
+ * card on the bus.
+ */
+ tmp = pci0ReadConfigReg(PCI_COMMAND);
+ tmp |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_SERR;
+ pci0WriteConfigReg(PCI_COMMAND, tmp);
+
+ register_pci_controller(&ocelot_pci_controller);
+}
+
+arch_initcall(ocelot_pcibios_init);
diff --git a/arch/mips/pci/pci-sb1250.c b/arch/mips/pci/pci-sb1250.c
new file mode 100644
index 00000000000..7cca3bde59b
--- /dev/null
+++ b/arch/mips/pci/pci-sb1250.c
@@ -0,0 +1,292 @@
+/*
+ * Copyright (C) 2001,2002,2003 Broadcom Corporation
+ * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org)
+ *
+ * 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.
+ */
+
+/*
+ * BCM1250-specific PCI support
+ *
+ * This module provides the glue between Linux's PCI subsystem
+ * and the hardware. We basically provide glue for accessing
+ * configuration space, and set up the translation for I/O
+ * space accesses.
+ *
+ * To access configuration space, we use ioremap. In the 32-bit
+ * kernel, this consumes either 4 or 8 page table pages, and 16MB of
+ * kernel mapped memory. Hopefully neither of these should be a huge
+ * problem.
+ */
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/console.h>
+#include <linux/tty.h>
+
+#include <asm/io.h>
+
+#include <asm/sibyte/sb1250_defs.h>
+#include <asm/sibyte/sb1250_regs.h>
+#include <asm/sibyte/sb1250_scd.h>
+#include <asm/sibyte/board.h>
+
+/*
+ * Macros for calculating offsets into config space given a device
+ * structure or dev/fun/reg
+ */
+#define CFGOFFSET(bus,devfn,where) (((bus)<<16) + ((devfn)<<8) + (where))
+#define CFGADDR(bus,devfn,where) CFGOFFSET((bus)->number,(devfn),where)
+
+static void *cfg_space;
+
+#define PCI_BUS_ENABLED 1
+#define LDT_BUS_ENABLED 2
+#define PCI_DEVICE_MODE 4
+
+static int sb1250_bus_status = 0;
+
+#define PCI_BRIDGE_DEVICE 0
+#define LDT_BRIDGE_DEVICE 1
+
+#ifdef CONFIG_SIBYTE_HAS_LDT
+/*
+ * HT's level-sensitive interrupts require EOI, which is generated
+ * through a 4MB memory-mapped region
+ */
+unsigned long ldt_eoi_space;
+#endif
+
+/*
+ * Read/write 32-bit values in config space.
+ */
+static inline u32 READCFG32(u32 addr)
+{
+ return *(u32 *) (cfg_space + (addr & ~3));
+}
+
+static inline void WRITECFG32(u32 addr, u32 data)
+{
+ *(u32 *) (cfg_space + (addr & ~3)) = data;
+}
+
+int pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ return dev->irq;
+}
+
+/* Do platform specific device initialization at pci_enable_device() time */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+ return 0;
+}
+
+/*
+ * Some checks before doing config cycles:
+ * In PCI Device Mode, hide everything on bus 0 except the LDT host
+ * bridge. Otherwise, access is controlled by bridge MasterEn bits.
+ */
+static int sb1250_pci_can_access(struct pci_bus *bus, int devfn)
+{
+ u32 devno;
+
+ if (!(sb1250_bus_status & (PCI_BUS_ENABLED | PCI_DEVICE_MODE)))
+ return 0;
+
+ if (bus->number == 0) {
+ devno = PCI_SLOT(devfn);
+ if (devno == LDT_BRIDGE_DEVICE)
+ return (sb1250_bus_status & LDT_BUS_ENABLED) != 0;
+ else if (sb1250_bus_status & PCI_DEVICE_MODE)
+ return 0;
+ else
+ return 1;
+ } else
+ return 1;
+}
+
+/*
+ * Read/write access functions for various sizes of values
+ * in config space. Return all 1's for disallowed accesses
+ * for a kludgy but adequate simulation of master aborts.
+ */
+
+static int sb1250_pcibios_read(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 * val)
+{
+ u32 data = 0;
+
+ if ((size == 2) && (where & 1))
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ else if ((size == 4) && (where & 3))
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ if (sb1250_pci_can_access(bus, devfn))
+ data = READCFG32(CFGADDR(bus, devfn, where));
+ else
+ data = 0xFFFFFFFF;
+
+ if (size == 1)
+ *val = (data >> ((where & 3) << 3)) & 0xff;
+ else if (size == 2)
+ *val = (data >> ((where & 3) << 3)) & 0xffff;
+ else
+ *val = data;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int sb1250_pcibios_write(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 val)
+{
+ u32 cfgaddr = CFGADDR(bus, devfn, where);
+ u32 data = 0;
+
+ if ((size == 2) && (where & 1))
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ else if ((size == 4) && (where & 3))
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ if (!sb1250_pci_can_access(bus, devfn))
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ data = READCFG32(cfgaddr);
+
+ if (size == 1)
+ data = (data & ~(0xff << ((where & 3) << 3))) |
+ (val << ((where & 3) << 3));
+ else if (size == 2)
+ data = (data & ~(0xffff << ((where & 3) << 3))) |
+ (val << ((where & 3) << 3));
+ else
+ data = val;
+
+ WRITECFG32(cfgaddr, data);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+struct pci_ops sb1250_pci_ops = {
+ .read = sb1250_pcibios_read,
+ .write = sb1250_pcibios_write,
+};
+
+static struct resource sb1250_mem_resource = {
+ .name = "SB1250 PCI MEM",
+ .start = 0x40000000UL,
+ .end = 0x5fffffffUL,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct resource sb1250_io_resource = {
+ .name = "SB1250 PCI I/O",
+ .start = 0x00000000UL,
+ .end = 0x01ffffffUL,
+ .flags = IORESOURCE_IO,
+};
+
+struct pci_controller sb1250_controller = {
+ .pci_ops = &sb1250_pci_ops,
+ .mem_resource = &sb1250_mem_resource,
+ .io_resource = &sb1250_io_resource,
+};
+
+static int __init sb1250_pcibios_init(void)
+{
+ uint32_t cmdreg;
+ uint64_t reg;
+ extern int pci_probe_only;
+
+ /* CFE will assign PCI resources */
+ pci_probe_only = 1;
+
+ /* Avoid ISA compat ranges. */
+ PCIBIOS_MIN_IO = 0x00008000UL;
+ PCIBIOS_MIN_MEM = 0x01000000UL;
+
+ /* Set I/O resource limits. */
+ ioport_resource.end = 0x01ffffffUL; /* 32MB accessible by sb1250 */
+ iomem_resource.end = 0xffffffffUL; /* no HT support yet */
+
+ cfg_space =
+ ioremap(A_PHYS_LDTPCI_CFG_MATCH_BITS, 16 * 1024 * 1024);
+
+ /*
+ * See if the PCI bus has been configured by the firmware.
+ */
+ reg = *((volatile uint64_t *) IOADDR(A_SCD_SYSTEM_CFG));
+ if (!(reg & M_SYS_PCI_HOST)) {
+ sb1250_bus_status |= PCI_DEVICE_MODE;
+ } else {
+ cmdreg =
+ READCFG32(CFGOFFSET
+ (0, PCI_DEVFN(PCI_BRIDGE_DEVICE, 0),
+ PCI_COMMAND));
+ if (!(cmdreg & PCI_COMMAND_MASTER)) {
+ printk
+ ("PCI: Skipping PCI probe. Bus is not initialized.\n");
+ iounmap(cfg_space);
+ return 0;
+ }
+ sb1250_bus_status |= PCI_BUS_ENABLED;
+ }
+
+ /*
+ * Establish mappings in KSEG2 (kernel virtual) to PCI I/O
+ * space. Use "match bytes" policy to make everything look
+ * little-endian. So, you need to also set
+ * CONFIG_SWAP_IO_SPACE, but this is the combination that
+ * works correctly with most of Linux's drivers.
+ * XXX ehs: Should this happen in PCI Device mode?
+ */
+
+ set_io_port_base((unsigned long)
+ ioremap(A_PHYS_LDTPCI_IO_MATCH_BYTES, 65536));
+ isa_slot_offset = (unsigned long)
+ ioremap(A_PHYS_LDTPCI_IO_MATCH_BYTES_32, 1024 * 1024);
+
+#ifdef CONFIG_SIBYTE_HAS_LDT
+ /*
+ * Also check the LDT bridge's enable, just in case we didn't
+ * initialize that one.
+ */
+
+ cmdreg = READCFG32(CFGOFFSET(0, PCI_DEVFN(LDT_BRIDGE_DEVICE, 0),
+ PCI_COMMAND));
+ if (cmdreg & PCI_COMMAND_MASTER) {
+ sb1250_bus_status |= LDT_BUS_ENABLED;
+
+ /*
+ * Need bits 23:16 to convey vector number. Note that
+ * this consumes 4MB of kernel-mapped memory
+ * (Kseg2/Kseg3) for 32-bit kernel.
+ */
+ ldt_eoi_space = (unsigned long)
+ ioremap(A_PHYS_LDT_SPECIAL_MATCH_BYTES,
+ 4 * 1024 * 1024);
+ }
+#endif
+
+ register_pci_controller(&sb1250_controller);
+
+#ifdef CONFIG_VGA_CONSOLE
+ take_over_console(&vga_con, 0, MAX_NR_CONSOLES - 1, 1);
+#endif
+ return 0;
+}
+arch_initcall(sb1250_pcibios_init);
diff --git a/arch/mips/pci/pci-vr41xx.c b/arch/mips/pci/pci-vr41xx.c
new file mode 100644
index 00000000000..f3ccbf7fada
--- /dev/null
+++ b/arch/mips/pci/pci-vr41xx.c
@@ -0,0 +1,291 @@
+/*
+ * pci-vr41xx.c, PCI Control Unit routines for the NEC VR4100 series.
+ *
+ * Copyright (C) 2001-2003 MontaVista Software Inc.
+ * Author: Yoichi Yuasa <yyuasa@mvista.com or source@mvista.com>
+ * Copyright (C) 2004 Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
+ * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org)
+ *
+ * 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
+ */
+/*
+ * Changes:
+ * MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
+ * - New creation, NEC VR4122 and VR4131 are supported.
+ */
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/types.h>
+
+#include <asm/cpu.h>
+#include <asm/io.h>
+#include <asm/vr41xx/vr41xx.h>
+
+#include "pci-vr41xx.h"
+
+extern struct pci_ops vr41xx_pci_ops;
+
+static struct pci_master_address_conversion pci_master_memory1 = {
+ .bus_base_address = PCI_MASTER_MEM1_BUS_BASE_ADDRESS,
+ .address_mask = PCI_MASTER_MEM1_ADDRESS_MASK,
+ .pci_base_address = PCI_MASTER_MEM1_PCI_BASE_ADDRESS,
+};
+
+static struct pci_target_address_conversion pci_target_memory1 = {
+ .address_mask = PCI_TARGET_MEM1_ADDRESS_MASK,
+ .bus_base_address = PCI_TARGET_MEM1_BUS_BASE_ADDRESS,
+};
+
+static struct pci_master_address_conversion pci_master_io = {
+ .bus_base_address = PCI_MASTER_IO_BUS_BASE_ADDRESS,
+ .address_mask = PCI_MASTER_IO_ADDRESS_MASK,
+ .pci_base_address = PCI_MASTER_IO_PCI_BASE_ADDRESS,
+};
+
+static struct pci_mailbox_address pci_mailbox = {
+ .base_address = PCI_MAILBOX_BASE_ADDRESS,
+};
+
+static struct pci_target_address_window pci_target_window1 = {
+ .base_address = PCI_TARGET_WINDOW1_BASE_ADDRESS,
+};
+
+static struct resource pci_mem_resource = {
+ .name = "PCI Memory resources",
+ .start = PCI_MEM_RESOURCE_START,
+ .end = PCI_MEM_RESOURCE_END,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct resource pci_io_resource = {
+ .name = "PCI I/O resources",
+ .start = PCI_IO_RESOURCE_START,
+ .end = PCI_IO_RESOURCE_END,
+ .flags = IORESOURCE_IO,
+};
+
+static struct pci_controller_unit_setup vr41xx_pci_controller_unit_setup = {
+ .master_memory1 = &pci_master_memory1,
+ .target_memory1 = &pci_target_memory1,
+ .master_io = &pci_master_io,
+ .exclusive_access = CANNOT_LOCK_FROM_DEVICE,
+ .wait_time_limit_from_irdy_to_trdy = 0,
+ .mailbox = &pci_mailbox,
+ .target_window1 = &pci_target_window1,
+ .master_latency_timer = 0x80,
+ .retry_limit = 0,
+ .arbiter_priority_control = PCI_ARBITRATION_MODE_FAIR,
+ .take_away_gnt_mode = PCI_TAKE_AWAY_GNT_DISABLE,
+};
+
+static struct pci_controller vr41xx_pci_controller = {
+ .pci_ops = &vr41xx_pci_ops,
+ .mem_resource = &pci_mem_resource,
+ .io_resource = &pci_io_resource,
+};
+
+void __init vr41xx_pciu_setup(struct pci_controller_unit_setup *setup)
+{
+ vr41xx_pci_controller_unit_setup = *setup;
+}
+
+static int __init vr41xx_pciu_init(void)
+{
+ struct pci_controller_unit_setup *setup;
+ struct pci_master_address_conversion *master;
+ struct pci_target_address_conversion *target;
+ struct pci_mailbox_address *mailbox;
+ struct pci_target_address_window *window;
+ unsigned long vtclock, pci_clock_max;
+ uint32_t val;
+
+ setup = &vr41xx_pci_controller_unit_setup;
+
+ /* Disable PCI interrupt */
+ vr41xx_disable_pciint();
+
+ /* Supply VTClock to PCIU */
+ vr41xx_supply_clock(PCIU_CLOCK);
+
+ /* Dummy write, waiting for supply of VTClock. */
+ vr41xx_disable_pciint();
+
+ /* Select PCI clock */
+ if (setup->pci_clock_max != 0)
+ pci_clock_max = setup->pci_clock_max;
+ else
+ pci_clock_max = PCI_CLOCK_MAX;
+ vtclock = vr41xx_get_vtclock_frequency();
+ if (vtclock < pci_clock_max)
+ writel(EQUAL_VTCLOCK, PCICLKSELREG);
+ else if ((vtclock / 2) < pci_clock_max)
+ writel(HALF_VTCLOCK, PCICLKSELREG);
+ else if (current_cpu_data.processor_id >= PRID_VR4131_REV2_1 &&
+ (vtclock / 3) < pci_clock_max)
+ writel(ONE_THIRD_VTCLOCK, PCICLKSELREG);
+ else if ((vtclock / 4) < pci_clock_max)
+ writel(QUARTER_VTCLOCK, PCICLKSELREG);
+ else {
+ printk(KERN_ERR "PCI Clock is over 33MHz.\n");
+ return -EINVAL;
+ }
+
+ /* Supply PCI clock by PCI bus */
+ vr41xx_supply_clock(PCI_CLOCK);
+
+ if (setup->master_memory1 != NULL) {
+ master = setup->master_memory1;
+ val = IBA(master->bus_base_address) |
+ MASTER_MSK(master->address_mask) |
+ WINEN |
+ PCIA(master->pci_base_address);
+ writel(val, PCIMMAW1REG);
+ } else {
+ val = readl(PCIMMAW1REG);
+ val &= ~WINEN;
+ writel(val, PCIMMAW1REG);
+ }
+
+ if (setup->master_memory2 != NULL) {
+ master = setup->master_memory2;
+ val = IBA(master->bus_base_address) |
+ MASTER_MSK(master->address_mask) |
+ WINEN |
+ PCIA(master->pci_base_address);
+ writel(val, PCIMMAW2REG);
+ } else {
+ val = readl(PCIMMAW2REG);
+ val &= ~WINEN;
+ writel(val, PCIMMAW2REG);
+ }
+
+ if (setup->target_memory1 != NULL) {
+ target = setup->target_memory1;
+ val = TARGET_MSK(target->address_mask) |
+ WINEN |
+ ITA(target->bus_base_address);
+ writel(val, PCITAW1REG);
+ } else {
+ val = readl(PCITAW1REG);
+ val &= ~WINEN;
+ writel(val, PCITAW1REG);
+ }
+
+ if (setup->target_memory2 != NULL) {
+ target = setup->target_memory2;
+ val = TARGET_MSK(target->address_mask) |
+ WINEN |
+ ITA(target->bus_base_address);
+ writel(val, PCITAW2REG);
+ } else {
+ val = readl(PCITAW2REG);
+ val &= ~WINEN;
+ writel(val, PCITAW2REG);
+ }
+
+ if (setup->master_io != NULL) {
+ master = setup->master_io;
+ val = IBA(master->bus_base_address) |
+ MASTER_MSK(master->address_mask) |
+ WINEN |
+ PCIIA(master->pci_base_address);
+ writel(val, PCIMIOAWREG);
+ } else {
+ val = readl(PCIMIOAWREG);
+ val &= ~WINEN;
+ writel(val, PCIMIOAWREG);
+ }
+
+ if (setup->exclusive_access == CANNOT_LOCK_FROM_DEVICE)
+ writel(UNLOCK, PCIEXACCREG);
+ else
+ writel(0, PCIEXACCREG);
+
+ if (current_cpu_data.cputype == CPU_VR4122)
+ writel(TRDYV(setup->wait_time_limit_from_irdy_to_trdy), PCITRDYVREG);
+
+ writel(MLTIM(setup->master_latency_timer), LATTIMEREG);
+
+ if (setup->mailbox != NULL) {
+ mailbox = setup->mailbox;
+ val = MBADD(mailbox->base_address) | TYPE_32BITSPACE |
+ MSI_MEMORY | PREF_APPROVAL;
+ writel(val, MAILBAREG);
+ }
+
+ if (setup->target_window1) {
+ window = setup->target_window1;
+ val = PMBA(window->base_address) | TYPE_32BITSPACE |
+ MSI_MEMORY | PREF_APPROVAL;
+ writel(val, PCIMBA1REG);
+ }
+
+ if (setup->target_window2) {
+ window = setup->target_window2;
+ val = PMBA(window->base_address) | TYPE_32BITSPACE |
+ MSI_MEMORY | PREF_APPROVAL;
+ writel(val, PCIMBA2REG);
+ }
+
+ val = readl(RETVALREG);
+ val &= ~RTYVAL_MASK;
+ val |= RTYVAL(setup->retry_limit);
+ writel(val, RETVALREG);
+
+ val = readl(PCIAPCNTREG);
+ val &= ~(TKYGNT | PAPC);
+
+ switch (setup->arbiter_priority_control) {
+ case PCI_ARBITRATION_MODE_ALTERNATE_0:
+ val |= PAPC_ALTERNATE_0;
+ break;
+ case PCI_ARBITRATION_MODE_ALTERNATE_B:
+ val |= PAPC_ALTERNATE_B;
+ break;
+ default:
+ val |= PAPC_FAIR;
+ break;
+ }
+
+ if (setup->take_away_gnt_mode == PCI_TAKE_AWAY_GNT_ENABLE)
+ val |= TKYGNT_ENABLE;
+
+ writel(val, PCIAPCNTREG);
+
+ writel(PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
+ PCI_COMMAND_PARITY | PCI_COMMAND_SERR, COMMANDREG);
+
+ /* Clear bus error */
+ readl(BUSERRADREG);
+
+ writel(BLOODY_CONFIG_DONE, PCIENREG);
+
+ if (setup->mem_resource != NULL)
+ vr41xx_pci_controller.mem_resource = setup->mem_resource;
+
+ if (setup->io_resource != NULL) {
+ vr41xx_pci_controller.io_resource = setup->io_resource;
+ } else {
+ set_io_port_base(IO_PORT_BASE);
+ ioport_resource.start = IO_PORT_RESOURCE_START;
+ ioport_resource.end = IO_PORT_RESOURCE_END;
+ }
+
+ register_pci_controller(&vr41xx_pci_controller);
+
+ return 0;
+}
+
+arch_initcall(vr41xx_pciu_init);
diff --git a/arch/mips/pci/pci-vr41xx.h b/arch/mips/pci/pci-vr41xx.h
new file mode 100644
index 00000000000..23815c8b903
--- /dev/null
+++ b/arch/mips/pci/pci-vr41xx.h
@@ -0,0 +1,151 @@
+/*
+ * pci-vr41xx.h, Include file for PCI Control Unit of the NEC VR4100 series.
+ *
+ * Copyright (C) 2002 MontaVista Software Inc.
+ * Author: Yoichi Yuasa <yyuasa@mvista.com or source@mvista.com>
+ * Copyright (C) 2004 Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
+ *
+ * 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
+ */
+#ifndef __PCI_VR41XX_H
+#define __PCI_VR41XX_H
+
+#define PCIMMAW1REG KSEG1ADDR(0x0f000c00)
+#define PCIMMAW2REG KSEG1ADDR(0x0f000c04)
+#define PCITAW1REG KSEG1ADDR(0x0f000c08)
+#define PCITAW2REG KSEG1ADDR(0x0f000c0c)
+#define PCIMIOAWREG KSEG1ADDR(0x0f000c10)
+ #define IBA(addr) ((addr) & 0xff000000U)
+ #define MASTER_MSK(mask) (((mask) >> 11) & 0x000fe000U)
+ #define PCIA(addr) (((addr) >> 24) & 0x000000ffU)
+ #define TARGET_MSK(mask) (((mask) >> 8) & 0x000fe000U)
+ #define ITA(addr) (((addr) >> 24) & 0x000000ffU)
+ #define PCIIA(addr) (((addr) >> 24) & 0x000000ffU)
+ #define WINEN 0x1000U
+#define PCICONFDREG KSEG1ADDR(0x0f000c14)
+#define PCICONFAREG KSEG1ADDR(0x0f000c18)
+#define PCIMAILREG KSEG1ADDR(0x0f000c1c)
+#define BUSERRADREG KSEG1ADDR(0x0f000c24)
+ #define EA(reg) ((reg) &0xfffffffc)
+
+#define INTCNTSTAREG KSEG1ADDR(0x0f000c28)
+ #define MABTCLR 0x80000000U
+ #define TRDYCLR 0x40000000U
+ #define PARCLR 0x20000000U
+ #define MBCLR 0x10000000U
+ #define SERRCLR 0x08000000U
+ #define RTYCLR 0x04000000U
+ #define MABCLR 0x02000000U
+ #define TABCLR 0x01000000U
+ /* RFU */
+ #define MABTMSK 0x00008000U
+ #define TRDYMSK 0x00004000U
+ #define PARMSK 0x00002000U
+ #define MBMSK 0x00001000U
+ #define SERRMSK 0x00000800U
+ #define RTYMSK 0x00000400U
+ #define MABMSK 0x00000200U
+ #define TABMSK 0x00000100U
+ #define IBAMABT 0x00000080U
+ #define TRDYRCH 0x00000040U
+ #define PAR 0x00000020U
+ #define MB 0x00000010U
+ #define PCISERR 0x00000008U
+ #define RTYRCH 0x00000004U
+ #define MABORT 0x00000002U
+ #define TABORT 0x00000001U
+
+#define PCIEXACCREG KSEG1ADDR(0x0f000c2c)
+ #define UNLOCK 0x2U
+ #define EAREQ 0x1U
+#define PCIRECONTREG KSEG1ADDR(0x0f000c30)
+ #define RTRYCNT(reg) ((reg) & 0x000000ffU)
+#define PCIENREG KSEG1ADDR(0x0f000c34)
+ #define BLOODY_CONFIG_DONE 0x4U
+#define PCICLKSELREG KSEG1ADDR(0x0f000c38)
+ #define EQUAL_VTCLOCK 0x2U
+ #define HALF_VTCLOCK 0x0U
+ #define ONE_THIRD_VTCLOCK 0x3U
+ #define QUARTER_VTCLOCK 0x1U
+#define PCITRDYVREG KSEG1ADDR(0x0f000c3c)
+ #define TRDYV(val) ((uint32_t)(val) & 0xffU)
+#define PCICLKRUNREG KSEG1ADDR(0x0f000c60)
+
+#define VENDORIDREG KSEG1ADDR(0x0f000d00)
+#define DEVICEIDREG KSEG1ADDR(0x0f000d00)
+#define COMMANDREG KSEG1ADDR(0x0f000d04)
+#define STATUSREG KSEG1ADDR(0x0f000d04)
+#define REVIDREG KSEG1ADDR(0x0f000d08)
+#define CLASSREG KSEG1ADDR(0x0f000d08)
+#define CACHELSREG KSEG1ADDR(0x0f000d0c)
+#define LATTIMEREG KSEG1ADDR(0x0f000d0c)
+ #define MLTIM(val) (((uint32_t)(val) << 7) & 0xff00U)
+#define MAILBAREG KSEG1ADDR(0x0f000d10)
+#define PCIMBA1REG KSEG1ADDR(0x0f000d14)
+#define PCIMBA2REG KSEG1ADDR(0x0f000d18)
+ #define MBADD(base) ((base) & 0xfffff800U)
+ #define PMBA(base) ((base) & 0xffe00000U)
+ #define PREF 0x8U
+ #define PREF_APPROVAL 0x8U
+ #define PREF_DISAPPROVAL 0x0U
+ #define TYPE 0x6U
+ #define TYPE_32BITSPACE 0x0U
+ #define MSI 0x1U
+ #define MSI_MEMORY 0x0U
+#define INTLINEREG KSEG1ADDR(0x0f000d3c)
+#define INTPINREG KSEG1ADDR(0x0f000d3c)
+#define RETVALREG KSEG1ADDR(0x0f000d40)
+#define PCIAPCNTREG KSEG1ADDR(0x0f000d40)
+ #define TKYGNT 0x04000000U
+ #define TKYGNT_ENABLE 0x04000000U
+ #define TKYGNT_DISABLE 0x00000000U
+ #define PAPC 0x03000000U
+ #define PAPC_ALTERNATE_B 0x02000000U
+ #define PAPC_ALTERNATE_0 0x01000000U
+ #define PAPC_FAIR 0x00000000U
+ #define RTYVAL(val) (((uint32_t)(val) << 7) & 0xff00U)
+ #define RTYVAL_MASK 0xff00U
+
+#define PCI_CLOCK_MAX 33333333U
+
+/*
+ * Default setup
+ */
+#define PCI_MASTER_MEM1_BUS_BASE_ADDRESS 0x10000000U
+#define PCI_MASTER_MEM1_ADDRESS_MASK 0x7c000000U
+#define PCI_MASTER_MEM1_PCI_BASE_ADDRESS 0x10000000U
+
+#define PCI_TARGET_MEM1_ADDRESS_MASK 0x08000000U
+#define PCI_TARGET_MEM1_BUS_BASE_ADDRESS 0x00000000U
+
+#define PCI_MASTER_IO_BUS_BASE_ADDRESS 0x16000000U
+#define PCI_MASTER_IO_ADDRESS_MASK 0x7e000000U
+#define PCI_MASTER_IO_PCI_BASE_ADDRESS 0x00000000U
+
+#define PCI_MAILBOX_BASE_ADDRESS 0x00000000U
+
+#define PCI_TARGET_WINDOW1_BASE_ADDRESS 0x00000000U
+
+#define IO_PORT_BASE KSEG1ADDR(PCI_MASTER_IO_BUS_BASE_ADDRESS)
+#define IO_PORT_RESOURCE_START PCI_MASTER_IO_PCI_BASE_ADDRESS
+#define IO_PORT_RESOURCE_END (~PCI_MASTER_IO_ADDRESS_MASK & PCI_MASTER_ADDRESS_MASK)
+
+#define PCI_IO_RESOURCE_START 0x01000000UL
+#define PCI_IO_RESOURCE_END 0x01ffffffUL
+
+#define PCI_MEM_RESOURCE_START 0x11000000UL
+#define PCI_MEM_RESOURCE_END 0x13ffffffUL
+
+#endif /* __PCI_VR41XX_H */
diff --git a/arch/mips/pci/pci-yosemite.c b/arch/mips/pci/pci-yosemite.c
new file mode 100644
index 00000000000..dac9ed4b0cc
--- /dev/null
+++ b/arch/mips/pci/pci-yosemite.c
@@ -0,0 +1,60 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org)
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <asm/titan_dep.h>
+
+extern struct pci_ops titan_pci_ops;
+
+static struct resource py_mem_resource = {
+ "Titan PCI MEM", 0xe0000000UL, 0xe3ffffffUL, IORESOURCE_MEM
+};
+
+/*
+ * PMON really reserves 16MB of I/O port space but that's stupid, nothing
+ * needs that much since allocations are limited to 256 bytes per device
+ * anyway. So we just claim 64kB here.
+ */
+#define TITAN_IO_SIZE 0x0000ffffUL
+#define TITAN_IO_BASE 0xe8000000UL
+
+static struct resource py_io_resource = {
+ "Titan IO MEM", 0x00001000UL, TITAN_IO_SIZE - 1, IORESOURCE_IO,
+};
+
+static struct pci_controller py_controller = {
+ .pci_ops = &titan_pci_ops,
+ .mem_resource = &py_mem_resource,
+ .mem_offset = 0x00000000UL,
+ .io_resource = &py_io_resource,
+ .io_offset = 0x00000000UL
+};
+
+static char ioremap_failed[] __initdata = "Could not ioremap I/O port range";
+
+static int __init pmc_yosemite_setup(void)
+{
+ unsigned long io_v_base;
+
+ io_v_base = (unsigned long) ioremap(TITAN_IO_BASE, TITAN_IO_SIZE);
+ if (!io_v_base)
+ panic(ioremap_failed);
+
+ set_io_port_base(io_v_base);
+ TITAN_WRITE(RM9000x2_OCD_LKM7, TITAN_READ(RM9000x2_OCD_LKM7) | 1);
+
+ ioport_resource.end = TITAN_IO_SIZE - 1;
+
+ register_pci_controller(&py_controller);
+
+ return 0;
+}
+
+arch_initcall(pmc_yosemite_setup);
diff --git a/arch/mips/pci/pci.c b/arch/mips/pci/pci.c
new file mode 100644
index 00000000000..8141dffac24
--- /dev/null
+++ b/arch/mips/pci/pci.c
@@ -0,0 +1,304 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2003, 04 Ralf Baechle (ralf@linux-mips.org)
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/bootmem.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+
+/*
+ * Indicate whether we respect the PCI setup left by the firmware.
+ *
+ * Make this long-lived so that we know when shutting down
+ * whether we probed only or not.
+ */
+int pci_probe_only;
+
+#define PCI_ASSIGN_ALL_BUSSES 1
+
+unsigned int pci_probe = PCI_ASSIGN_ALL_BUSSES;
+
+/*
+ * The PCI controller list.
+ */
+
+struct pci_controller *hose_head, **hose_tail = &hose_head;
+struct pci_controller *pci_isa_hose;
+
+unsigned long PCIBIOS_MIN_IO = 0x0000;
+unsigned long PCIBIOS_MIN_MEM = 0;
+
+/*
+ * We need to avoid collisions with `mirrored' VGA ports
+ * and other strange ISA hardware, so we always want the
+ * addresses to be allocated in the 0x000-0x0ff region
+ * modulo 0x400.
+ *
+ * Why? Because some silly external IO cards only decode
+ * the low 10 bits of the IO address. The 0x00-0xff region
+ * is reserved for motherboard devices that decode all 16
+ * bits, so it's ok to allocate at, say, 0x2800-0x28ff,
+ * but we want to try to avoid allocating at 0x2900-0x2bff
+ * which might have be mirrored at 0x0100-0x03ff..
+ */
+void
+pcibios_align_resource(void *data, struct resource *res,
+ unsigned long size, unsigned long align)
+{
+ struct pci_dev *dev = data;
+ struct pci_controller *hose = dev->sysdata;
+ unsigned long start = res->start;
+
+ if (res->flags & IORESOURCE_IO) {
+ /* Make sure we start at our min on all hoses */
+ if (start < PCIBIOS_MIN_IO + hose->io_resource->start)
+ start = PCIBIOS_MIN_IO + hose->io_resource->start;
+
+ /*
+ * Put everything into 0x00-0xff region modulo 0x400
+ */
+ if (start & 0x300)
+ start = (start + 0x3ff) & ~0x3ff;
+ } else if (res->flags & IORESOURCE_MEM) {
+ /* Make sure we start at our min on all hoses */
+ if (start < PCIBIOS_MIN_MEM + hose->mem_resource->start)
+ start = PCIBIOS_MIN_MEM + hose->mem_resource->start;
+ }
+
+ res->start = start;
+}
+
+struct pci_controller * __init alloc_pci_controller(void)
+{
+ return alloc_bootmem(sizeof(struct pci_controller));
+}
+
+void __init register_pci_controller(struct pci_controller *hose)
+{
+ *hose_tail = hose;
+ hose_tail = &hose->next;
+}
+
+/* Most MIPS systems have straight-forward swizzling needs. */
+
+static inline u8 bridge_swizzle(u8 pin, u8 slot)
+{
+ return (((pin - 1) + slot) % 4) + 1;
+}
+
+static u8 __init common_swizzle(struct pci_dev *dev, u8 *pinp)
+{
+ u8 pin = *pinp;
+
+ while (dev->bus->parent) {
+ pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn));
+ /* Move up the chain of bridges. */
+ dev = dev->bus->self;
+ }
+ *pinp = pin;
+
+ /* The slot is the slot of the last bridge. */
+ return PCI_SLOT(dev->devfn);
+}
+
+static int __init pcibios_init(void)
+{
+ struct pci_controller *hose;
+ struct pci_bus *bus;
+ int next_busno;
+ int need_domain_info = 0;
+
+ /* Scan all of the recorded PCI controllers. */
+ for (next_busno = 0, hose = hose_head; hose; hose = hose->next) {
+
+ if (request_resource(&iomem_resource, hose->mem_resource) < 0)
+ goto out;
+ if (request_resource(&ioport_resource, hose->io_resource) < 0)
+ goto out_free_mem_resource;
+
+ if (!hose->iommu)
+ PCI_DMA_BUS_IS_PHYS = 1;
+
+ bus = pci_scan_bus(next_busno, hose->pci_ops, hose);
+ hose->bus = bus;
+ hose->need_domain_info = need_domain_info;
+ next_busno = bus->subordinate + 1;
+ /* Don't allow 8-bit bus number overflow inside the hose -
+ reserve some space for bridges. */
+ if (next_busno > 224) {
+ next_busno = 0;
+ need_domain_info = 1;
+ }
+ continue;
+
+out_free_mem_resource:
+ release_resource(hose->mem_resource);
+
+out:
+ printk(KERN_WARNING
+ "Skipping PCI bus scan due to resource conflict\n");
+ }
+
+ if (!pci_probe_only)
+ pci_assign_unassigned_resources();
+ pci_fixup_irqs(common_swizzle, pcibios_map_irq);
+
+ return 0;
+}
+
+subsys_initcall(pcibios_init);
+
+static int pcibios_enable_resources(struct pci_dev *dev, int mask)
+{
+ u16 cmd, old_cmd;
+ int idx;
+ struct resource *r;
+
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ old_cmd = cmd;
+ for(idx=0; idx<6; idx++) {
+ /* Only set up the requested stuff */
+ if (!(mask & (1<<idx)))
+ continue;
+
+ r = &dev->resource[idx];
+ if (!r->start && r->end) {
+ printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", pci_name(dev));
+ return -EINVAL;
+ }
+ if (r->flags & IORESOURCE_IO)
+ cmd |= PCI_COMMAND_IO;
+ if (r->flags & IORESOURCE_MEM)
+ cmd |= PCI_COMMAND_MEMORY;
+ }
+ if (dev->resource[PCI_ROM_RESOURCE].start)
+ cmd |= PCI_COMMAND_MEMORY;
+ if (cmd != old_cmd) {
+ printk("PCI: Enabling device %s (%04x -> %04x)\n", pci_name(dev), old_cmd, cmd);
+ pci_write_config_word(dev, PCI_COMMAND, cmd);
+ }
+ return 0;
+}
+
+/*
+ * If we set up a device for bus mastering, we need to check the latency
+ * timer as certain crappy BIOSes forget to set it properly.
+ */
+unsigned int pcibios_max_latency = 255;
+
+void pcibios_set_master(struct pci_dev *dev)
+{
+ u8 lat;
+ pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
+ if (lat < 16)
+ lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency;
+ else if (lat > pcibios_max_latency)
+ lat = pcibios_max_latency;
+ else
+ return;
+ printk(KERN_DEBUG "PCI: Setting latency timer of device %s to %d\n",
+ pci_name(dev), lat);
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
+}
+
+unsigned int pcibios_assign_all_busses(void)
+{
+ return (pci_probe & PCI_ASSIGN_ALL_BUSSES) ? 1 : 0;
+}
+
+int pcibios_enable_device(struct pci_dev *dev, int mask)
+{
+ int err;
+
+ if ((err = pcibios_enable_resources(dev, mask)) < 0)
+ return err;
+
+ return pcibios_plat_dev_init(dev);
+}
+
+static void __init pcibios_fixup_device_resources(struct pci_dev *dev,
+ struct pci_bus *bus)
+{
+ /* Update device resources. */
+ struct pci_controller *hose = (struct pci_controller *)bus->sysdata;
+ unsigned long offset = 0;
+ int i;
+
+ for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+ if (!dev->resource[i].start)
+ continue;
+ if (dev->resource[i].flags & IORESOURCE_IO)
+ offset = hose->io_offset;
+ else if (dev->resource[i].flags & IORESOURCE_MEM)
+ offset = hose->mem_offset;
+
+ dev->resource[i].start += offset;
+ dev->resource[i].end += offset;
+ }
+}
+
+void __devinit pcibios_fixup_bus(struct pci_bus *bus)
+{
+ /* Propagate hose info into the subordinate devices. */
+
+ struct pci_controller *hose = bus->sysdata;
+ struct list_head *ln;
+ struct pci_dev *dev = bus->self;
+
+ if (!dev) {
+ bus->resource[0] = hose->io_resource;
+ bus->resource[1] = hose->mem_resource;
+ } else if (pci_probe_only &&
+ (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
+ pci_read_bridge_bases(bus);
+ pcibios_fixup_device_resources(dev, bus);
+ }
+
+ for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) {
+ struct pci_dev *dev = pci_dev_b(ln);
+
+ if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI)
+ pcibios_fixup_device_resources(dev, bus);
+ }
+}
+
+void __init
+pcibios_update_irq(struct pci_dev *dev, int irq)
+{
+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
+}
+
+void __devinit
+pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
+ struct resource *res)
+{
+ struct pci_controller *hose = (struct pci_controller *)dev->sysdata;
+ unsigned long offset = 0;
+
+ if (res->flags & IORESOURCE_IO)
+ offset = hose->io_offset;
+ else if (res->flags & IORESOURCE_MEM)
+ offset = hose->mem_offset;
+
+ region->start = res->start - offset;
+ region->end = res->end - offset;
+}
+
+#ifdef CONFIG_HOTPLUG
+EXPORT_SYMBOL(pcibios_resource_to_bus);
+EXPORT_SYMBOL(PCIBIOS_MIN_IO);
+EXPORT_SYMBOL(PCIBIOS_MIN_MEM);
+#endif
+
+char *pcibios_setup(char *str)
+{
+ return str;
+}