Commit 80b11f5a authored by Ralf Bächle's avatar Ralf Bächle Committed by Linus Torvalds

[PATCH] PCI code

This is the entire MIPS PCI code which I'm consolidating in arch/mips/pci/.
Applying this patch will result in some code duplication; the remaining
patches I'm about to send will clean that.
parent 2395133b
#
# Makefile for the PCI specific kernel interface routines under Linux.
#
# This is all organized on a per system base which is horribly wrong and
# really wants a cleanup. You have been warned.
#
obj-$(CONFIG_NEW_PCI) += pci.o
obj-$(CONFIG_PCI_AUTO) += pci-auto.o
obj-$(CONFIG_DDB5074) += pci-ddb5074.o ops-ddb5074.o
obj-$(CONFIG_DDB5476) += pci-ddb5476.o ops-ddb5476.o
obj-$(CONFIG_DDB5477) += pci-ddb5477.o ops-ddb5477.o
obj-$(CONFIG_HP_LASERJET) += pci-hplj.o
obj-$(CONFIG_ITE_BOARD_GEN) += ops-it8172.o
obj-$(CONFIG_LASAT) += pci-lasat.o
obj-$(CONFIG_MIPS_BOARDS_GEN) += pci-mips.o
obj-$(CONFIG_MIPS_COBALT) += pci-cobalt.o
obj-$(CONFIG_MIPS_EV64120) += ops-ev64120.o
obj-$(CONFIG_MIPS_EV96100) += fixup-ev96100.o ops-ev96100.o
obj-$(CONFIG_MIPS_ITE8172) += fixup-ite8172g.o
obj-$(CONFIG_MIPS_IVR) += fixup-ivr.o
obj-$(CONFIG_MIPS_PB1500) += fixups-au1000.o ops-au1000.o
obj-$(CONFIG_MOMENCO_OCELOT) += fixups-ocelot.o ops-ocelot.o
obj-$(CONFIG_NEC_EAGLE) += fixup-eagle.o ops-vrc4173.o
obj-$(CONFIG_SGI_IP27) += pci-ip27.o
obj-$(CONFIG_SGI_IP32) += pci-ip32.o
obj-$(CONFIG_SIBYTE_SB1250) += pci-sb1250.o
obj-$(CONFIG_SNI_RM200_PCI) += pci-sni.o
obj-$(CONFIG_TANBAC_TB0226) += fixup-tb0226.o
obj-$(CONFIG_TANBAC_TB0229) += fixup-tb0229.o
obj-$(CONFIG_TOSHIBA_JMR3927) += fixup-jmr3927.o ops-jmr3927.o
#obj-$(CONFIG_MOMENCO_OCELOT_C) += pci-ocelot-c.o
obj-$(CONFIG_MOMENCO_OCELOT_G) += pci-ocelot-g.o
obj-$(CONFIG_VICTOR_MPC30X) += fixup-capcella.o
obj-$(CONFIG_VR41XX_COMMON) += pci-vr41xx.o
obj-$(CONFIG_ZAO_CAPCELLA) += fixup-victor-mpc30x.o
void __init pcibios_fixup_bus(struct pci_bus *b)
{
Dprintk("pcibios_fixup_bus()\n");
}
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",
dev->slot_name);
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",
dev->slot_name, old_cmd, cmd);
pci_write_config_word(dev, PCI_COMMAND, cmd);
}
return 0;
}
int pcibios_enable_device(struct pci_dev *dev, int mask)
{
int err;
if ((err = pcibios_enable_resources(dev, mask)) < 0)
return err;
return 0;
}
void __init pcibios_align_resource(void *data, struct resource *res,
unsigned long size, unsigned long align)
{
panic("Uhhoh called pcibios_align_resource");
}
unsigned __init int pcibios_assign_all_busses(void)
{
return 1;
}
char *pcibios_setup(char *str)
{
return str;
}
struct pci_fixup pcibios_fixups[] = {
{0}
};
/*
* 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/au1000.h>
//#include <asm/pb1500.h>
#ifdef CONFIG_MIPS_PB1000
#include <asm/pb1000.h>
#endif
#undef DEBUG
#ifdef DEBUG
#define DBG(x...) printk(x)
#else
#define DBG(x...)
#endif
static void fixup_resource(int r_num, struct pci_dev *dev);
#ifdef CONFIG_SOC_AU1500
static unsigned long virt_io_addr;
#endif
void __init pcibios_fixup_resources(struct pci_dev *dev)
{
/* will need to fixup IO resources */
}
void __init pcibios_fixup(void)
{
#ifdef CONFIG_SOC_AU1500
int i;
struct pci_dev *dev;
virt_io_addr = (unsigned long) ioremap(Au1500_PCI_IO_START,
Au1500_PCI_IO_END -
Au1500_PCI_IO_START + 1);
if (!virt_io_addr) {
printk(KERN_ERR "Unable to ioremap pci space\n");
return;
}
set_io_port_base(virt_io_addr);
#endif
#ifdef CONFIG_MIPS_PB1000 /* This is truly board specific */
unsigned long pci_mem_start = (unsigned long) PCI_MEM_START;
au_writel(0, PCI_BRIDGE_CONFIG); // set extend byte to 0
au_writel(0, SDRAM_MBAR); // set mbar to 0
au_writel(0x2, SDRAM_CMD); // enable memory accesses
au_sync_delay(1);
// set extend byte to mbar of ext slot
au_writel(((pci_mem_start >> 24) & 0xff) |
(1 << 8 | 1 << 9 | 1 << 10 | 1 << 27),
PCI_BRIDGE_CONFIG);
DBG("Set bridge config to %x\n", au_readl(PCI_BRIDGE_CONFIG));
#endif
}
void __init pcibios_fixup_irqs(void)
{
#ifdef CONFIG_SOC_AU1500
unsigned int slot, func;
unsigned char pin;
struct pci_dev *dev = NULL;
while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
if (dev->bus->number != 0)
return;
dev->irq = 0xff;
slot = PCI_SLOT(dev->devfn);
switch (slot) {
case 12:
case 13:
dev->irq = AU1000_PCI_INTA;
break;
}
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
DBG("slot %d irq %d\n", slot, dev->irq);
}
#endif
}
unsigned int pcibios_assign_all_busses(void)
{
return 0;
}
static void fixup_resource(int r_num, struct pci_dev *dev)
{
}
/*
* FILE NAME
* arch/mips/vr41xx/zao-capcella/pci_fixup.c
*
* BRIEF MODULE DESCRIPTION
* The ZAO Networks Capcella specific PCI fixups.
*
* Copyright 2002 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.
*/
#include <linux/init.h>
#include <linux/pci.h>
#include <asm/vr41xx/capcella.h>
void __init pcibios_fixup_resources(struct pci_dev *dev)
{
}
void __init pcibios_fixup(void)
{
}
void __init pcibios_fixup_irqs(void)
{
struct pci_dev *dev = NULL;
u8 slot, func, pin;
while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
slot = PCI_SLOT(dev->devfn);
func = PCI_FUNC(dev->devfn);
dev->irq = 0;
switch (slot) {
case 11:
dev->irq = RTL8139_1_IRQ;
break;
case 12:
dev->irq = RTL8139_2_IRQ;
break;
case 14:
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
switch (pin) {
case 1:
dev->irq = PC104PLUS_INTA_IRQ;
break;
case 2:
dev->irq = PC104PLUS_INTB_IRQ;
break;
case 3:
dev->irq = PC104PLUS_INTC_IRQ;
break;
case 4:
dev->irq = PC104PLUS_INTD_IRQ;
break;
}
break;
}
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
}
}
unsigned int pcibios_assign_all_busses(void)
{
return 0;
}
/*
* FILE NAME
* arch/mips/vr41xx/nec-eagle/pci_fixup.c
*
* BRIEF MODULE DESCRIPTION
* The NEC Eagle/Hawk Board specific PCI fixups.
*
* Author: Yoichi Yuasa
* yyuasa@mvista.com or source@mvista.com
*
* Copyright 2001,2002 MontaVista Software Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* 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.
*/
/*
* Changes:
* MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
* - Moved mips_pci_channels[] to arch/mips/vr41xx/vr4122/eagle/setup.c.
* - Added support for NEC Hawk.
*
* Paul Mundt <lethal@chaoticdreams.org>
* - Fix empty break statements.
*
* MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
* - New creation, NEC Eagle is supported.
*/
#include <linux/init.h>
#include <linux/pci.h>
#include <asm/vr41xx/eagle.h>
#include <asm/vr41xx/vrc4173.h>
void __init pcibios_fixup_resources(struct pci_dev *dev)
{
}
void __init pcibios_fixup(void)
{
}
void __init pcibios_fixup_irqs(void)
{
struct pci_dev *dev = NULL;
u8 slot, func, pin;
while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
slot = PCI_SLOT(dev->devfn);
func = PCI_FUNC(dev->devfn);
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
dev->irq = 0;
switch (slot) {
case 8:
switch (pin) {
case 1:
dev->irq = CP_INTA_IRQ;
break;
case 2:
dev->irq = CP_INTB_IRQ;
break;
case 3:
dev->irq = CP_INTC_IRQ;
break;
case 4:
dev->irq = CP_INTD_IRQ;
break;
}
break;
case 9:
switch (pin) {
case 1:
dev->irq = CP_INTD_IRQ;
break;
case 2:
dev->irq = CP_INTA_IRQ;
break;
case 3:
dev->irq = CP_INTB_IRQ;
break;
case 4:
dev->irq = CP_INTC_IRQ;
break;
}
break;
case 10:
switch (pin) {
case 1:
dev->irq = CP_INTC_IRQ;
break;
case 2:
dev->irq = CP_INTD_IRQ;
break;
case 3:
dev->irq = CP_INTA_IRQ;
break;
case 4:
dev->irq = CP_INTB_IRQ;
break;
}
break;
case 12:
dev->irq = VRC4173_PCMCIA1_IRQ;
break;
case 13:
dev->irq = VRC4173_PCMCIA2_IRQ;
break;
case 28:
dev->irq = LANINTA_IRQ;
break;
case 29:
switch (pin) {
case 1:
dev->irq = PCISLOT_IRQ;
break;
case 2:
dev->irq = CP_INTB_IRQ;
break;
case 3:
dev->irq = CP_INTC_IRQ;
break;
case 4:
dev->irq = CP_INTD_IRQ;
break;
}
break;
case 30:
switch (func) {
case 0:
dev->irq = VRC4173_CASCADE_IRQ;
break;
case 1:
dev->irq = VRC4173_AC97_IRQ;
break;
case 2:
dev->irq = VRC4173_USB_IRQ;
break;
}
break;
}
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
}
}
unsigned int pcibios_assign_all_busses(void)
{
return 0;
}
/*
* 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>
void __init pcibios_fixup_resources(struct pci_dev *dev)
{
}
void __init pcibios_fixup(void)
{
}
void __init pcibios_fixup_irqs(void)
{
unsigned int slot, func;
unsigned char pin;
struct pci_dev *dev = NULL;
const int internal_func_irqs[7] = {
IT8172_AC97_IRQ,
IT8172_DMA_IRQ,
IT8172_CDMA_IRQ,
IT8172_USB_IRQ,
IT8172_BRIDGE_MASTER_IRQ,
IT8172_IDE_IRQ,
IT8172_MC68K_IRQ
};
while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
if (dev->bus->number != 0)
return;
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
slot = PCI_SLOT(dev->devfn);
func = PCI_FUNC(dev->devfn);
switch (slot) {
case 0x01:
/*
* Internal device 1 is actually 7 different
* internal devices on the IT8172G (a multi-
* function device).
*/
if (func < 7)
dev->irq = internal_func_irqs[func];
break;
case 0x10:
switch (pin) {
case 1: /* pin A */
dev->irq = IT8172_PCI_INTA_IRQ;
break;
case 2: /* pin B */
dev->irq = IT8172_PCI_INTB_IRQ;
break;
case 3: /* pin C */
dev->irq = IT8172_PCI_INTC_IRQ;
break;
case 4: /* pin D */
dev->irq = IT8172_PCI_INTD_IRQ;
break;
default:
dev->irq = 0xff;
break;
}
break;
case 0x11:
switch (pin) {
case 1: /* pin A */
dev->irq = IT8172_PCI_INTA_IRQ;
break;
case 2: /* pin B */
dev->irq = IT8172_PCI_INTB_IRQ;
break;
case 3: /* pin C */
dev->irq = IT8172_PCI_INTC_IRQ;
break;
case 4: /* pin D */
dev->irq = IT8172_PCI_INTD_IRQ;
break;
default:
dev->irq = 0xff;
break;
}
break;
case 0x12:
switch (pin) {
case 1: /* pin A */
dev->irq = IT8172_PCI_INTB_IRQ;
break;
case 2: /* pin B */
dev->irq = IT8172_PCI_INTC_IRQ;
break;
case 3: /* pin C */
dev->irq = IT8172_PCI_INTD_IRQ;
break;
case 4: /* pin D */
dev->irq = IT8172_PCI_INTA_IRQ;
break;
default:
dev->irq = 0xff;
break;
}
break;
case 0x13:
switch (pin) {
case 1: /* pin A */
dev->irq = IT8172_PCI_INTC_IRQ;
break;
case 2: /* pin B */
dev->irq = IT8172_PCI_INTD_IRQ;
break;
case 3: /* pin C */
dev->irq = IT8172_PCI_INTA_IRQ;
break;
case 4: /* pin D */
dev->irq = IT8172_PCI_INTB_IRQ;
break;
default:
dev->irq = 0xff;
break;
}
break;
case 0x14:
switch (pin) {
case 1: /* pin A */
dev->irq = IT8172_PCI_INTD_IRQ;
break;
case 2: /* pin B */
dev->irq = IT8172_PCI_INTA_IRQ;
break;
case 3: /* pin C */
dev->irq = IT8172_PCI_INTB_IRQ;
break;
case 4: /* pin D */
dev->irq = IT8172_PCI_INTC_IRQ;
break;
default:
dev->irq = 0xff;
break;
}
break;
default:
continue; /* do nothing */
}
#ifdef DEBUG
printk("irq fixup: slot %d, int line %d, int number %d\n",
slot, pin, dev->irq);
#endif
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
}
}
/*
*
* 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>
void __init pcibios_fixup_resources(struct pci_dev *dev)
{
}
void __init pcibios_fixup(void)
{
}
void __init pcibios_fixup_irqs(void)
{
unsigned int slot, func;
unsigned char pin;
struct pci_dev *dev = NULL;
const int internal_func_irqs[7] = {
IT8172_AC97_IRQ,
IT8172_DMA_IRQ,
IT8172_CDMA_IRQ,
IT8172_USB_IRQ,
IT8172_BRIDGE_MASTER_IRQ,
IT8172_IDE_IRQ,
IT8172_MC68K_IRQ
};
while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
if (dev->bus->number != 0)
return;
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
slot = PCI_SLOT(dev->devfn);
func = PCI_FUNC(dev->devfn);
switch (slot) {
case 0x01:
/*
* Internal device 1 is actually 7 different
* internal devices on the IT8172G (multi-function
* device).
*/
if (func < 7)
dev->irq = internal_func_irqs[func];
break;
case 0x11: // Realtek RTL-8139
switch (pin) {
case 0: /* pin A, hardware bug */
case 1: /* pin A */
dev->irq = IT8172_PCI_INTC_IRQ;
break;
case 2: /* pin B */
dev->irq = IT8172_PCI_INTD_IRQ;
break;
case 3: /* pin C */
dev->irq = IT8172_PCI_INTA_IRQ;
break;
case 4: /* pin D */
dev->irq = IT8172_PCI_INTB_IRQ;
break;
default:
dev->irq = 0xff;
break;
}
break;
case 0x12: // ivr slot
switch (pin) {
case 0: /* pin A, hardware bug */
case 1: /* pin A */
dev->irq = IT8172_PCI_INTB_IRQ;
break;
case 2: /* pin B */
dev->irq = IT8172_PCI_INTB_IRQ;
break;
case 3: /* pin C */
dev->irq = IT8172_PCI_INTC_IRQ;
break;
case 4: /* pin D */
dev->irq = IT8172_PCI_INTD_IRQ;
break;
default:
dev->irq = 0xff;
break;
}
break;
case 0x13: // expansion slot
switch (pin) {
case 0: /* pin A, hardware bug */
case 1: /* pin A */
dev->irq = IT8172_PCI_INTA_IRQ;
break;
case 2: /* pin B */
dev->irq = IT8172_PCI_INTB_IRQ;
break;
case 3: /* pin C */
dev->irq = IT8172_PCI_INTC_IRQ;
break;
case 4: /* pin D */
dev->irq = IT8172_PCI_INTD_IRQ;
break;
default:
dev->irq = 0xff;
break;
}
break;
default:
break;
}
#ifdef DEBUG
printk("irq fixup: slot %d, int line %d, int number %d\n",
slot, pin, dev->irq);
#endif
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
}
}
/*
*
* 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>
#undef DEBUG
#ifdef DEBUG
#define DBG(x...) printk(x)
#else
#define DBG(x...)
#endif
void __init pcibios_fixup_resources(struct pci_dev *dev)
{
/* will need to fixup IO resources */
}
void __init pcibios_fixup(void)
{
/* nothing to do here */
}
int pci_get_irq(struct pci_dev *dev, int pin)
{
unsigned char irq = pin;
/* IRQ rotation (PICMG) */
irq--; /* 0-3 */
if (dev->bus->parent == NULL &&
PCI_SLOT(dev->devfn) == 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 &&
PCI_SLOT(dev->devfn) ==
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 + PCI_SLOT(dev->devfn)) % 4;
#if 0 /* ??? */
for (bus = dev->bus; bus->parent != NULL;
bus = bus->parent) {
irq = (irq + 3 + PCI_SLOT(bus->self->devfn)) % 4;
}
#endif
}
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 &&
PCI_SLOT(dev->devfn) == 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;
}
void __init pcibios_fixup_irqs(void)
{
unsigned char irq;
struct pci_dev *dev = NULL;
while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq);
if (irq == 0)
return;
/* SMSC SLC90E66 IDE uses irq 14, 15 (default) */
if (!(dev->vendor == PCI_VENDOR_ID_EFAR &&
dev->device == PCI_DEVICE_ID_EFAR_SLC90E66_1)) {
irq = pci_get_irq(dev, irq);
pci_write_config_byte(dev, PCI_INTERRUPT_LINE,
irq);
}
pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
printk(KERN_INFO "PCI: %02x:%02x IRQ %02x\n",
dev->bus->number, dev->devfn, irq);
dev->irq = irq;
}
}
/*
* 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/version.h>
#include <linux/init.h>
#include <asm/pci.h>
void __devinit gt64120_board_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
("gt64120_board_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);
}
}
/*
* FILE NAME
* arch/mips/vr41xx/tanbac-tb0226/pci_fixup.c
*
* BRIEF MODULE DESCRIPTION
* The TANBAC TB0226 specific PCI fixups.
*
* Copyright 2002,2003 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.
*/
#include <linux/init.h>
#include <linux/pci.h>
#include <asm/vr41xx/tb0226.h>
void __init pcibios_fixup_resources(struct pci_dev *dev)
{
}
void __init pcibios_fixup(void)
{
}
void __init pcibios_fixup_irqs(void)
{
struct pci_dev *dev = NULL;
u8 slot, pin;
while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
slot = PCI_SLOT(dev->devfn);
dev->irq = 0;
switch (slot) {
case 12:
vr41xx_set_irq_trigger(GD82559_1_PIN,
TRIGGER_LEVEL,
SIGNAL_THROUGH);
vr41xx_set_irq_level(GD82559_1_PIN, LEVEL_LOW);
dev->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);
dev->irq = GD82559_2_IRQ;
break;
case 14:
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
switch (pin) {
case 1:
vr41xx_set_irq_trigger(UPD720100_INTA_PIN,
TRIGGER_LEVEL,
SIGNAL_THROUGH);
vr41xx_set_irq_level(UPD720100_INTA_PIN,
LEVEL_LOW);
dev->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);
dev->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);
dev->irq = UPD720100_INTC_IRQ;
break;
}
break;
}
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
}
}
unsigned int pcibios_assign_all_busses(void)
{
return 0;
}
/*
* FILE NAME
* arch/mips/vr41xx/tanbac-tb0229/pci_fixup.c
*
* BRIEF MODULE DESCRIPTION
* The TANBAC TB0229(VR4131DIMM) specific PCI fixups.
*
* Copyright 2003 Megasolution Inc.
* matsu@megasolution.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.
*/
#include <linux/config.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <asm/vr41xx/tb0229.h>
void __init pcibios_fixup_resources(struct pci_dev *dev)
{
}
void __init pcibios_fixup(void)
{
}
void __init pcibios_fixup_irqs(void)
{
#ifdef CONFIG_TANBAC_TB0219
struct pci_dev *dev = NULL;
u8 slot;
while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
slot = PCI_SLOT(dev->devfn);
dev->irq = 0;
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);
dev->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);
dev->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);
dev->irq = TB0219_PCI_SLOT3_IRQ;
break;
default:
break;
}
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
}
#endif
}
unsigned int pcibios_assign_all_busses(void)
{
return 0;
}
/*
* FILE NAME
* arch/mips/vr41xx/victor-mpc30x/pci_fixup.c
*
* BRIEF MODULE DESCRIPTION
* The Victor MP-C303/304 specific PCI fixups.
*
* Copyright 2002 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.
*/
#include <linux/init.h>
#include <linux/pci.h>
#include <asm/vr41xx/vrc4173.h>
#include <asm/vr41xx/mpc30x.h>
void __init pcibios_fixup_resources(struct pci_dev *dev)
{
}
void __init pcibios_fixup(void)
{
}
void __init pcibios_fixup_irqs(void)
{
struct pci_dev *dev = NULL;
u8 slot, func;
while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
slot = PCI_SLOT(dev->devfn);
func = PCI_FUNC(dev->devfn);
dev->irq = 0;
switch (slot) {
case 12: /* NEC VRC4173 CARDU1 */
dev->irq = VRC4173_PCMCIA1_IRQ;
break;
case 13: /* NEC VRC4173 CARDU2 */
dev->irq = VRC4173_PCMCIA2_IRQ;
break;
case 29: /* mediaQ MQ-200 */
dev->irq = MQ200_IRQ;
break;
case 30:
switch (func) {
case 0: /* NEC VRC4173 */
dev->irq = VRC4173_CASCADE_IRQ;
break;
case 1: /* NEC VRC4173 AC97U */
dev->irq = VRC4173_AC97_IRQ;
break;
case 2: /* NEC VRC4173 USBU */
dev->irq = VRC4173_USB_IRQ;
break;
}
break;
}
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
}
}
unsigned int pcibios_assign_all_busses(void)
{
return 0;
}
/*
*
* 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/types.h>
#include <linux/pci.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/pci_ids.h>
#include <asm/gt64120.h>
#include <asm/galileo-boards/ev96100.h>
extern unsigned short get_gt_devid(void);
void __init pcibios_fixup_resources(struct pci_dev *dev)
{
}
void __init pcibios_fixup(void)
{
}
void __init pcibios_fixup_irqs(void)
{
struct pci_dev *dev = NULL;
unsigned int slot;
u32 vendor;
unsigned short gt_devid = get_gt_devid();
/*
** EV96100/A interrupt routing for pci bus 0
**
** Note: EV96100A board with irq jumper set on 'VxWorks'
** for EV96100 compatibility.
*/
while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
if (dev->bus->number != 0)
return;
slot = PCI_SLOT(dev->devfn);
pci_read_config_dword(dev, PCI_SUBSYSTEM_VENDOR_ID,
&vendor);
#ifdef DEBUG
printk("devfn %x, slot %d devid %x\n",
dev->devfn, slot, gt_devid);
#endif
/* fixup irq line based on slot # */
if (slot == 8) {
dev->irq = 5;
pci_write_config_byte(dev, PCI_INTERRUPT_LINE,
dev->irq);
} else if (slot == 9) {
dev->irq = 2;
pci_write_config_byte(dev, PCI_INTERRUPT_LINE,
dev->irq);
}
}
}
unsigned int pcibios_assign_all_busses(void)
{
return 0;
}
/*
* 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 <asm/au1000.h>
#ifdef CONFIG_MIPS_PB1000
#include <asm/pb1000.h>
#endif
#include <asm/pci_channel.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
/* TBD */
static struct resource pci_io_resource = {
"pci IO space",
(u32) PCI_IO_START,
(u32) PCI_IO_END,
IORESOURCE_IO
};
static struct resource pci_mem_resource = {
"pci memory space",
(u32) PCI_MEM_START,
(u32) PCI_MEM_END,
IORESOURCE_MEM
};
extern struct pci_ops au1x_pci_ops;
struct pci_channel mips_pci_channels[] = {
{&au1x_pci_ops, &pci_io_resource, &pci_mem_resource,
PCI_FIRST_DEVFN, PCI_LAST_DEVFN},
{(struct pci_ops *) NULL, (struct resource *) NULL,
(struct resource *) NULL, (int) NULL, (int) NULL}
};
#ifdef CONFIG_MIPS_PB1000
/*
* "Bus 2" is really the first and only external slot on the pb1000.
* We'll call that bus 0, and limit the accesses to that single
* external slot only. The SDRAM is already initialized in setup.c.
*/
static int config_access(unsigned char access_type, struct pci_dev *dev,
unsigned char where, u32 * data)
{
unsigned char bus = dev->bus->number;
unsigned char dev_fn = dev->devfn;
unsigned long config;
if (((dev_fn >> 3) != 0) || (bus != 0)) {
*data = 0xffffffff;
return -1;
}
config = PCI_CONFIG_BASE | (where & ~0x3);
if (access_type == PCI_ACCESS_WRITE) {
au_writel(*data, config);
} else {
*data = au_readl(config);
}
au_sync_udelay(1);
DBG("config_access: %d bus %d dev_fn %x at %x *data %x, conf %x\n",
access_type, bus, dev_fn, where, *data, config);
DBG("bridge config reg: %x (%x)\n", au_readl(PCI_BRIDGE_CONFIG),
*data);
if (au_readl(PCI_BRIDGE_CONFIG) & (1 << 16)) {
*data = 0xffffffff;
return -1;
} else {
return PCIBIOS_SUCCESSFUL;
}
}
#else
static int config_access(unsigned char access_type, struct pci_bus *bus,
unsigned int devfn, unsigned char where,
u32 * data)
{
#ifdef CONFIG_SOC_AU1500
unsigned int device = PCI_SLOT(devfn);
unsigned int function = PCI_FUNC(devfn);
unsigned long config, status;
unsigned long cfg_addr;
if (device > 19) {
*data = 0xffffffff;
return -1;
}
au_writel(((0x2000 << 16) |
(au_readl(Au1500_PCI_STATCMD) & 0xffff)),
Au1500_PCI_STATCMD);
//au_writel(au_readl(Au1500_PCI_CFG) & ~PCI_ERROR, Au1500_PCI_CFG);
au_sync_udelay(1);
/* setup the config window */
if (bus->number == 0) {
cfg_addr = (unsigned long) ioremap(Au1500_EXT_CFG |
((1 << device) << 11),
0x00100000);
} else {
cfg_addr = (unsigned long) ioremap(Au1500_EXT_CFG_TYPE1 |
(bus->
number << 16) | (device
<<
11),
0x00100000);
}
if (!cfg_addr)
panic(KERN_ERR "PCI unable to ioremap cfg space\n");
/* setup the lower bits of the 36 bit address */
config = cfg_addr | (function << 8) | (where & ~0x3);
#if 0
if (access_type == PCI_ACCESS_WRITE) {
printk("cfg write: ");
} else {
printk("cfg read: ");
}
printk("devfn %x, device %x func %x \n", devfn, device, function);
if (access_type == PCI_ACCESS_WRITE) {
printk("data %x\n", *data);
}
#endif
if (access_type == PCI_ACCESS_WRITE) {
au_writel(*data, config);
} else {
*data = au_readl(config);
}
au_sync_udelay(2);
DBG("config_access: %d bus %d device %d at %x *data %x, conf %x\n",
access_type, bus->number, device, where, *data, config);
/* unmap io space */
iounmap((void *) cfg_addr);
/* check master abort */
status = au_readl(Au1500_PCI_STATCMD);
#if 0
if (access_type == PCI_ACCESS_READ) {
printk("read data: %x\n", *data);
}
#endif
if (status & (1 << 29)) {
*data = 0xffffffff;
return -1;
} else if ((status >> 28) & 0xf) {
printk("PCI ERR detected: status %x\n", status);
*data = 0xffffffff;
return -1;
} else {
return PCIBIOS_SUCCESSFUL;
}
#endif
}
#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 (where & 1)
return PCIBIOS_BAD_REGISTER_NUMBER;
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 (where & 3)
return PCIBIOS_BAD_REGISTER_NUMBER;
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:
return read_config_byte(bus, devfn, where, (u8 *) val);
case 2:
return read_config_word(bus, devfn, where, (u16 *) val);
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
};
/*
* 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/config.h>
#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
};
#if defined(CONFIG_RUNTIME_DEBUG)
void jsun_scan_pci_bus(void)
{
struct pci_bus bus;
struct pci_dev dev;
unsigned int devfn;
int j;
pci_config_workaround = 0;
bus.parent = NULL; /* we scan the top level only */
dev.bus = &bus;
dev.sysdata = NULL;
/* scan ext pci bus and io pci bus */
for (j = 0; j < 1; j++) {
printk(KERN_INFO "scan ddb5476 external PCI bus:\n");
bus.ops = &ddb5476_ext_pci_ops;
for (devfn = 0; devfn < 0x100; devfn += 8) {
u32 temp;
u16 temp16;
u8 temp8;
int i;
dev.devfn = devfn;
db_verify(pci_read_config_dword(&dev, 0, &temp),
== PCIBIOS_SUCCESSFUL);
if (temp == 0xffffffff)
continue;
printk(KERN_INFO "slot %d: (addr %d) \n",
devfn / 8, 11 + devfn / 8);
/* verify read word and byte */
db_verify(pci_read_config_word(&dev, 2, &temp16),
== PCIBIOS_SUCCESSFUL);
db_assert(temp16 == (temp >> 16));
db_verify(pci_read_config_byte(&dev, 3, &temp8),
== PCIBIOS_SUCCESSFUL);
db_assert(temp8 == (temp >> 24));
db_verify(pci_read_config_byte(&dev, 1, &temp8),
== PCIBIOS_SUCCESSFUL);
db_assert(temp8 == ((temp >> 8) & 0xff));
for (i = 0; i < 16; i++) {
if ((i % 4) == 0)
printk(KERN_INFO);
db_verify(pci_read_config_dword
(&dev, i * 4, &temp),
== PCIBIOS_SUCCESSFUL);
printk("\t%08X", temp);
if ((i % 4) == 3)
printk("\n");
}
}
}
pci_config_workaround = 1;
}
#endif
/*
* 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/config.h>
#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
};
#if defined(CONFIG_RUNTIME_DEBUG)
void jsun_scan_pci_bus(void)
{
struct pci_bus bus;
struct pci_dev dev;
unsigned int devfn;
int j;
pci_config_workaround = 0;
bus.parent = NULL; /* we scan the top level only */
dev.bus = &bus;
dev.sysdata = NULL;
/* scan ext pci bus and io pci bus */
for (j = 0; j < 1; j++) {
printk(KERN_INFO "scan ddb5476 external PCI bus:\n");
bus.ops = &ddb5476_ext_pci_ops;
for (devfn = 0; devfn < 0x100; devfn += 8) {
u32 temp;
u16 temp16;
u8 temp8;
int i;
dev.devfn = devfn;
db_verify(pci_read_config_dword(&dev, 0, &temp),
== PCIBIOS_SUCCESSFUL);
if (temp == 0xffffffff)
continue;
printk(KERN_INFO "slot %d: (addr %d) \n",
devfn / 8, 11 + devfn / 8);
/* verify read word and byte */
db_verify(pci_read_config_word(&dev, 2, &temp16),
== PCIBIOS_SUCCESSFUL);
db_assert(temp16 == (temp >> 16));
db_verify(pci_read_config_byte(&dev, 3, &temp8),
== PCIBIOS_SUCCESSFUL);
db_assert(temp8 == (temp >> 24));
db_verify(pci_read_config_byte(&dev, 1, &temp8),
== PCIBIOS_SUCCESSFUL);
db_assert(temp8 == ((temp >> 8) & 0xff));
for (i = 0; i < 16; i++) {
if ((i % 4) == 0)
printk(KERN_INFO);
db_verify(pci_read_config_dword
(&dev, i * 4, &temp),
== PCIBIOS_SUCCESSFUL);
printk("\t%08X", temp);
if ((i % 4) == 3)
printk("\n");
}
}
}
pci_config_workaround = 1;
}
#endif
/***********************************************************************
* 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 = swap->config_base;
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 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_bus *bus, u32 where, u16 * val)
{
int status;
u32 result;
db_assert((where & 1) == 0);
status = read_config_dword(swap, bus, 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, unsigned int devfn,
u8 * val)
{
int status;
u32 result;
status = read_config_dword(swap, bus, 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, unsigned int devfn,
u32 val)
{
u32 busno, 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) {
busno = bus->number;
db_assert(busno != 0);
} else {
busno = 0;
}
slot_num = PCI_SLOT(devfn);
func_num = PCI_FUNC(devfn);
base = ddb_access_config_base(swap, busno, 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, unsigned int devfn,
int 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_bus *bus, unsigned int devfn,
int 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);
}
/*
* Dump solution for now so I don't break hw I can't test on ...
*/
#define MAKE_PCI_OPS(prefix, rw, unitname, unittype, pciswap) \
static int prefix##_##rw##_config(struct pci_bus *bus, int where, int size, unittype val) \
{ \
if (size == 1) \
return rw##_config_byte(pciswap, bus, where, val); \
else if (size == 2) \
return rw##_config_word(pciswap, bus, where, val); \
/* Size must be 4 */ \
return rw##_config_dword(pciswap, bus, 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
};
This diff is collapsed.
/*
*
* 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>
#include <asm/pci_channel.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
#define GT_PCI_MEM_BASE 0x12000000
#define GT_PCI_MEM_SIZE 0x02000000
#define GT_PCI_IO_BASE 0x10000000
#define GT_PCI_IO_SIZE 0x02000000
static struct resource pci_io_resource = {
"io pci IO space",
0x10000000,
0x10000000 + 0x02000000,
IORESOURCE_IO
};
static struct resource pci_mem_resource = {
"ext pci memory space",
0x12000000,
0x12000000 + 0x02000000,
IORESOURCE_MEM
};
extern struct pci_ops gt96100_pci_ops;
struct pci_channel mips_pci_channels[] = {
{&gt96100_pci_ops, &pci_io_resource, &pci_mem_resource, 1, 0xff},
{NULL, NULL, NULL, NULL, NULL}
};
int
static gt96100_config_access(unsigned char access_type,
struct pci_dev *dev, unsigned char where,
u32 * data)
{
unsigned char bus = dev->bus->number;
unsigned char dev_fn = dev->devfn;
u32 intr;
if ((bus == 0) && (dev_fn >= 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,
(bus << GT_PCI0_CFGADDR_BUSNUM_SHF) |
(dev_fn << 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 (dev_fn != 0) {
*data = le32_to_cpu(*data);
}
GT_WRITE(GT_PCI0_CFGDATA_OFS, *data);
} else {
GT_READ(GT_PCI0_CFGDATA_OFS, *data);
if (dev_fn != 0) {
*data = le32_to_cpu(*data);
}
}
udelay(2);
/* Check for master or target abort */
GT_READ(GT_INTRCAUSE_OFS, intr);
if (intr &
(GT_INTRCAUSE_MASABORT0_BIT | GT_INTRCAUSE_TARABORT0_BIT)) {
//printk("config access error: %x:%x\n", dev_fn,where);
/* Error occured */
/* Clear bits */
GT_WRITE(GT_INTRCAUSE_OFS, ~(GT_INTRCAUSE_MASABORT0_BIT |
GT_INTRCAUSE_TARABORT0_BIT));
if (access_type == PCI_ACCESS_READ) {
*data = 0xffffffff;
}
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 read_config_byte(struct pci_dev *dev, int where, u8 * val)
{
u32 data = 0;
if (gt96100_config_access(PCI_ACCESS_READ, dev, where, &data)) {
*val = 0xff;
return -1;
}
*val = (data >> ((where & 3) << 3)) & 0xff;
DBG("cfg read byte: bus %d dev_fn %x where %x: val %x\n",
dev->bus->number, dev->devfn, where, *val);
return PCIBIOS_SUCCESSFUL;
}
static int read_config_word(struct pci_dev *dev, int where, u16 * val)
{
u32 data = 0;
if (where & 1)
return PCIBIOS_BAD_REGISTER_NUMBER;
if (gt96100_config_access(PCI_ACCESS_READ, dev, where, &data)) {
*val = 0xffff;
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;
}
static int read_config_dword(struct pci_dev *dev, int where, u32 * val)
{
u32 data = 0;
if (where & 3)
return PCIBIOS_BAD_REGISTER_NUMBER;
if (gt96100_config_access(PCI_ACCESS_READ, dev, where, &data)) {
*val = 0xffffffff;
return -1;
}
*val = data;
DBG("cfg read dword: bus %d dev_fn %x where %x: val %x\n",
dev->bus->number, dev->devfn, where, *val);
return PCIBIOS_SUCCESSFUL;
}
static int write_config_byte(struct pci_dev *dev, int where, u8 val)
{
u32 data = 0;
if (gt96100_config_access(PCI_ACCESS_READ, dev, where, &data))
return -1;
data = (data & ~(0xff << ((where & 3) << 3))) |
(val << ((where & 3) << 3));
DBG("cfg write byte: bus %d dev_fn %x where %x: val %x\n",
dev->bus->number, dev->devfn, where, val);
if (gt96100_config_access(PCI_ACCESS_WRITE, dev, where, &data))
return -1;
return PCIBIOS_SUCCESSFUL;
}
static int write_config_word(struct pci_dev *dev, int where, u16 val)
{
u32 data = 0;
if (where & 1)
return PCIBIOS_BAD_REGISTER_NUMBER;
if (gt96100_config_access(PCI_ACCESS_READ, dev, where, &data))
return -1;
data = (data & ~(0xffff << ((where & 3) << 3))) |
(val << ((where & 3) << 3));
DBG("cfg write word: bus %d dev_fn %x where %x: val %x\n",
dev->bus->number, dev->devfn, where, val);
if (gt96100_config_access(PCI_ACCESS_WRITE, dev, where, &data))
return -1;
return PCIBIOS_SUCCESSFUL;
}
static int write_config_dword(struct pci_dev *dev, int where, u32 val)
{
if (where & 3)
return PCIBIOS_BAD_REGISTER_NUMBER;
if (gt96100_config_access(PCI_ACCESS_WRITE, dev, where, &val))
return -1;
DBG("cfg write dword: bus %d dev_fn %x where %x: val %x\n",
dev->bus->number, dev->devfn, where, val);
return PCIBIOS_SUCCESSFUL;
}
struct pci_ops gt96100_pci_ops = {
read_config_byte,
read_config_word,
read_config_dword,
write_config_byte,
write_config_word,
write_config_dword
};
/*
*
* 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
*
* 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/pci_channel.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_channel mips_pci_channels[] = {
{&it8172_pci_ops, &pci_io_resource, &pci_mem_resource_0, 0x10,
0xff},
{NULL, NULL, NULL, NULL, NULL}
};
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,
};
unsigned __init int pcibios_assign_all_busses(void)
{
return 1;
}
This diff is collapsed.
This diff is collapsed.
/*
* FILE NAME
* arch/mips/vr41xx/nec-eagle/vrc4173.c
*
* BRIEF MODULE DESCRIPTION
* Pre-setup for NEC VRC4173.
*
* Author: Yoichi Yuasa
* yyuasa@mvista.com or source@mvista.com
*
* Copyright 2001,2002 MontaVista Software Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* 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/pci.h>
#include <linux/module.h>
#include <asm/io.h>
#include <asm/vr41xx/eagle.h>
#include <asm/vr41xx/vrc4173.h>
#define PCI_CONFIG_ADDR KSEG1ADDR(0x0f000c18)
#define PCI_CONFIG_DATA KSEG1ADDR(0x0f000c14)
static inline void config_writeb(u8 reg, u8 val)
{
u32 data;
int shift;
writel((1UL << 0x1e) | (reg & 0xfc), PCI_CONFIG_ADDR);
data = readl(PCI_CONFIG_DATA);
shift = (reg & 3) << 3;
data &= ~(0xff << shift);
data |= (((u32) val) << shift);
writel(data, PCI_CONFIG_DATA);
}
static inline u16 config_readw(u8 reg)
{
u32 data;
writel(((1UL << 30) | (reg & 0xfc)), PCI_CONFIG_ADDR);
data = readl(PCI_CONFIG_DATA);
return (u16) (data >> ((reg & 2) << 3));
}
static inline u32 config_readl(u8 reg)
{
writel(((1UL << 30) | (reg & 0xfc)), PCI_CONFIG_ADDR);
return readl(PCI_CONFIG_DATA);
}
static inline void config_writel(u8 reg, u32 val)
{
writel((1UL << 0x1e) | (reg & 0xfc), PCI_CONFIG_ADDR);
writel(val, PCI_CONFIG_DATA);
}
void __init vrc4173_preinit(void)
{
u32 cmdsts, base;
u16 cmu_mask;
if ((config_readw(PCI_VENDOR_ID) == PCI_VENDOR_ID_NEC) &&
(config_readw(PCI_DEVICE_ID) == PCI_DEVICE_ID_NEC_VRC4173)) {
/*
* Initialized NEC VRC4173 Bus Control Unit
*/
cmdsts = config_readl(PCI_COMMAND);
config_writel(PCI_COMMAND,
cmdsts |
PCI_COMMAND_IO |
PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
config_writeb(PCI_LATENCY_TIMER, 0x80);
config_writel(PCI_BASE_ADDRESS_0, VR41XX_PCI_IO_START);
base = config_readl(PCI_BASE_ADDRESS_0);
base &= PCI_BASE_ADDRESS_IO_MASK;
config_writeb(0x40, 0x01);
/* CARDU1 IDSEL = AD12, CARDU2 IDSEL = AD13 */
config_writeb(0x41, 0);
cmu_mask = 0x1000;
outw(cmu_mask, base + 0x040);
cmu_mask |= 0x0800;
outw(cmu_mask, base + 0x040);
outw(0x000f, base + 0x042); /* Soft reset of CMU */
cmu_mask |= 0x05e0;
outw(cmu_mask, base + 0x040);
cmu_mask = inw(base + 0x040); /* dummy read */
outw(0x0000, base + 0x042);
}
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -24,8 +24,8 @@ obj-$(CONFIG_PARISC) += setup-bus.o
obj-$(CONFIG_SUPERH) += setup-bus.o setup-irq.o
obj-$(CONFIG_PPC32) += setup-irq.o
obj-$(CONFIG_PPC64) += setup-bus.o
obj-$(CONFIG_DDB5476) += setup-bus.o
obj-$(CONFIG_SGI_IP27) += setup-irq.o
obj-$(CONFIG_SGI_IP32) += setup-irq.o
obj-$(CONFIG_X86_VISWS) += setup-irq.o
# CompactPCI hotplug requires the pbus_* functions
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment