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
};
/*
* 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
*
* 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/version.h>
#include <asm/pci.h>
#include <asm/io.h>
#include <asm/galileo-boards/ev64120.h>
#include <asm/gt64120.h>
#include <linux/init.h>
#undef PCI_DEBUG
#ifdef PCI_DEBUG
#define DBG(x...) printk(x)
#else
#define DBG(x...)
#endif
#define SELF 0
/*
* These functions and structures provide the BIOS scan and mapping of the PCI
* devices.
*/
#define MAX_PCI_DEVS 10
struct pci_device {
u32 slot;
u32 BARtype[6];
u32 BARsize[6];
};
static void __init scan_and_initialize_pci(void);
static u32 __init scan_pci_bus(struct pci_device *pci_devices);
static void __init allocate_pci_space(struct pci_device *pci_devices);
static void __devinit galileo_pcibios_fixup_bus(struct pci_bus *bus);
/*
* The functions that actually read and write to the controller.
* Copied from or modified from Galileo Technology code.
*/
static unsigned int pci0ReadConfigReg(int offset, struct pci_dev *device);
static void pci0WriteConfigReg(unsigned int offset,
struct pci_dev *device, unsigned int data);
static unsigned int pci1ReadConfigReg(int offset, struct pci_dev *device);
static void pci1WriteConfigReg(unsigned int offset,
struct pci_dev *device, unsigned int data);
static void pci0MapIOspace(unsigned int pci0IoBase,
unsigned int pci0IoLength);
static void pci1MapIOspace(unsigned int pci1IoBase,
unsigned int pci1IoLength);
static void pci0MapMemory0space(unsigned int pci0Mem0Base,
unsigned int pci0Mem0Length);
static void pci1MapMemory0space(unsigned int pci1Mem0Base,
unsigned int pci1Mem0Length);
static void pci0MapMemory1space(unsigned int pci0Mem1Base,
unsigned int pci0Mem1Length);
static void pci1MapMemory1space(unsigned int pci1Mem1Base,
unsigned int pci1Mem1Length);
static unsigned int pci0GetIOspaceBase(void);
static unsigned int pci0GetIOspaceSize(void);
static unsigned int pci0GetMemory0Base(void);
static unsigned int pci0GetMemory0Size(void);
static unsigned int pci0GetMemory1Base(void);
static unsigned int pci0GetMemory1Size(void);
static unsigned int pci1GetIOspaceBase(void);
static unsigned int pci1GetIOspaceSize(void);
static unsigned int pci1GetMemory0Base(void);
static unsigned int pci1GetMemory0Size(void);
static unsigned int pci1GetMemory1Base(void);
static unsigned int pci1GetMemory1Size(void);
/* Functions to implement "pci ops" */
static int galileo_pcibios_read_config_word(struct pci_dev *dev,
int offset, u16 * val);
static int galileo_pcibios_read_config_byte(struct pci_dev *dev,
int offset, u8 * val);
static int galileo_pcibios_read_config_dword(struct pci_dev *dev,
int offset, u32 * val);
static int galileo_pcibios_write_config_byte(struct pci_dev *dev,
int offset, u8 val);
static int galileo_pcibios_write_config_word(struct pci_dev *dev,
int offset, u16 val);
static int galileo_pcibios_write_config_dword(struct pci_dev *dev,
int offset, u32 val);
static void galileo_pcibios_set_master(struct pci_dev *dev);
/*
* General-purpose PCI functions.
*/
/*
* pci0MapIOspace - Maps PCI0 IO space for the master.
* Inputs: base and length of pci0Io
*/
static void pci0MapIOspace(unsigned int pci0IoBase,
unsigned int pci0IoLength)
{
unsigned int pci0IoTop =
(unsigned int) (pci0IoBase + pci0IoLength);
if (pci0IoLength == 0)
pci0IoTop++;
pci0IoBase = (unsigned int) (pci0IoBase >> 21);
pci0IoTop = (unsigned int) (((pci0IoTop - 1) & 0x0fffffff) >> 21);
GT_WRITE(GT_PCI0IOLD_OFS, pci0IoBase);
GT_WRITE(GT_PCI0IOHD_OFS, pci0IoTop);
}
/*
* pci1MapIOspace - Maps PCI1 IO space for the master.
* Inputs: base and length of pci1Io
*/
static void pci1MapIOspace(unsigned int pci1IoBase,
unsigned int pci1IoLength)
{
unsigned int pci1IoTop =
(unsigned int) (pci1IoBase + pci1IoLength);
if (pci1IoLength == 0)
pci1IoTop++;
pci1IoBase = (unsigned int) (pci1IoBase >> 21);
pci1IoTop = (unsigned int) (((pci1IoTop - 1) & 0x0fffffff) >> 21);
GT_WRITE(GT_PCI1IOLD_OFS, pci1IoBase);
GT_WRITE(GT_PCI1IOHD_OFS, pci1IoTop);
}
/*
* pci0MapMemory0space - Maps PCI0 memory0 space for the master.
* Inputs: base and length of pci0Mem0
*/
static void pci0MapMemory0space(unsigned int pci0Mem0Base,
unsigned int pci0Mem0Length)
{
unsigned int pci0Mem0Top = pci0Mem0Base + pci0Mem0Length;
if (pci0Mem0Length == 0)
pci0Mem0Top++;
pci0Mem0Base = pci0Mem0Base >> 21;
pci0Mem0Top = ((pci0Mem0Top - 1) & 0x0fffffff) >> 21;
GT_WRITE(GT_PCI0M0LD_OFS, pci0Mem0Base);
GT_WRITE(GT_PCI0M0HD_OFS, pci0Mem0Top);
}
/*
* pci1MapMemory0space - Maps PCI1 memory0 space for the master.
* Inputs: base and length of pci1Mem0
*/
static void pci1MapMemory0space(unsigned int pci1Mem0Base,
unsigned int pci1Mem0Length)
{
unsigned int pci1Mem0Top = pci1Mem0Base + pci1Mem0Length;
if (pci1Mem0Length == 0)
pci1Mem0Top++;
pci1Mem0Base = pci1Mem0Base >> 21;
pci1Mem0Top = ((pci1Mem0Top - 1) & 0x0fffffff) >> 21;
GT_WRITE(GT_PCI1M0LD_OFS, pci1Mem0Base);
GT_WRITE(GT_PCI1M0HD_OFS, pci1Mem0Top);
}
/*
* pci0MapMemory1space - Maps PCI0 memory1 space for the master.
* Inputs: base and length of pci0Mem1
*/
static void pci0MapMemory1space(unsigned int pci0Mem1Base,
unsigned int pci0Mem1Length)
{
unsigned int pci0Mem1Top = pci0Mem1Base + pci0Mem1Length;
if (pci0Mem1Length == 0)
pci0Mem1Top++;
pci0Mem1Base = pci0Mem1Base >> 21;
pci0Mem1Top = ((pci0Mem1Top - 1) & 0x0fffffff) >> 21;
GT_WRITE(GT_PCI0M1LD_OFS, pci0Mem1Base);
GT_WRITE(GT_PCI0M1HD_OFS, pci0Mem1Top);
}
/*
* pci1MapMemory1space - Maps PCI1 memory1 space for the master.
* Inputs: base and length of pci1Mem1
*/
static void pci1MapMemory1space(unsigned int pci1Mem1Base,
unsigned int pci1Mem1Length)
{
unsigned int pci1Mem1Top = pci1Mem1Base + pci1Mem1Length;
if (pci1Mem1Length == 0)
pci1Mem1Top++;
pci1Mem1Base = pci1Mem1Base >> 21;
pci1Mem1Top = ((pci1Mem1Top - 1) & 0x0fffffff) >> 21;
GT_WRITE(GT_PCI1M1LD_OFS, pci1Mem1Base);
GT_WRITE(GT_PCI1M1HD_OFS, pci1Mem1Top);
}
/*
* pci0GetIOspaceBase - Return PCI0 IO Base Address.
* Inputs: N/A
* Returns: PCI0 IO Base Address.
*/
static unsigned int pci0GetIOspaceBase(void)
{
unsigned int base;
GT_READ(GT_PCI0IOLD_OFS, &base);
base = base << 21;
return base;
}
/*
* pci0GetIOspaceSize - Return PCI0 IO Bar Size.
* Inputs: N/A
* Returns: PCI0 IO Bar Size.
*/
static unsigned int pci0GetIOspaceSize(void)
{
unsigned int top, base, size;
GT_READ(GT_PCI0IOLD_OFS, &base);
base = base << 21;
GT_READ(GT_PCI0IOHD_OFS, &top);
top = (top << 21);
size = ((top - base) & 0xfffffff);
size = size | 0x1fffff;
return (size + 1);
}
/*
* pci0GetMemory0Base - Return PCI0 Memory 0 Base Address.
* Inputs: N/A
* Returns: PCI0 Memory 0 Base Address.
*/
static unsigned int pci0GetMemory0Base(void)
{
unsigned int base;
GT_READ(GT_PCI0M0LD_OFS, &base);
base = base << 21;
return base;
}
/*
* pci0GetMemory0Size - Return PCI0 Memory 0 Bar Size.
* Inputs: N/A
* Returns: PCI0 Memory 0 Bar Size.
*/
static unsigned int pci0GetMemory0Size(void)
{
unsigned int top, base, size;
GT_READ(GT_PCI0M0LD_OFS, &base);
base = base << 21;
GT_READ(GT_PCI0M0HD_OFS, &top);
top = (top << 21);
size = ((top - base) & 0xfffffff);
size = size | 0x1fffff;
return (size + 1);
}
/*
* pci0GetMemory1Base - Return PCI0 Memory 1 Base Address.
* Inputs: N/A
* Returns: PCI0 Memory 1 Base Address.
*/
static unsigned int pci0GetMemory1Base(void)
{
unsigned int base;
GT_READ(GT_PCI0M1LD_OFS, &base);
base = base << 21;
return base;
}
/*
* pci0GetMemory1Size - Return PCI0 Memory 1 Bar Size.
* Inputs: N/A
* Returns: PCI0 Memory 1 Bar Size.
*/
static unsigned int pci0GetMemory1Size(void)
{
unsigned int top, base, size;
GT_READ(GT_PCI0M1LD_OFS, &base);
base = base << 21;
GT_READ(GT_PCI0M1HD_OFS, &top);
top = (top << 21);
size = ((top - base) & 0xfffffff);
size = size | 0x1fffff;
return (size + 1);
}
/*
* pci1GetIOspaceBase - Return PCI1 IO Base Address.
* Inputs: N/A
* Returns: PCI1 IO Base Address.
*/
static unsigned int pci1GetIOspaceBase(void)
{
unsigned int base;
GT_READ(GT_PCI1IOLD_OFS, &base);
base = base << 21;
return base;
}
/*
* pci1GetIOspaceSize - Return PCI1 IO Bar Size.
* Inputs: N/A
* Returns: PCI1 IO Bar Size.
*/
static unsigned int pci1GetIOspaceSize(void)
{
unsigned int top, base, size;
GT_READ(GT_PCI1IOLD_OFS, &base);
base = base << 21;
GT_READ(GT_PCI1IOHD_OFS, &top);
top = (top << 21);
size = ((top - base) & 0xfffffff);
size = size | 0x1fffff;
return (size + 1);
}
/*
* pci1GetMemory0Base - Return PCI1 Memory 0 Base Address.
* Inputs: N/A
* Returns: PCI1 Memory 0 Base Address.
*/
static unsigned int pci1GetMemory0Base(void)
{
unsigned int base;
GT_READ(GT_PCI1M0LD_OFS, &base);
base = base << 21;
return base;
}
/*
* pci1GetMemory0Size - Return PCI1 Memory 0 Bar Size.
* Inputs: N/A
* Returns: PCI1 Memory 0 Bar Size.
*/
static unsigned int pci1GetMemory0Size(void)
{
unsigned int top, base, size;
GT_READ(GT_PCI1M1LD_OFS, &base);
base = base << 21;
GT_READ(GT_PCI1M1HD_OFS, &top);
top = (top << 21);
size = ((top - base) & 0xfffffff);
size = size | 0x1fffff;
return (size + 1);
}
/*
* pci1GetMemory1Base - Return PCI1 Memory 1 Base Address.
* Inputs: N/A
* Returns: PCI1 Memory 1 Base Address.
*/
static unsigned int pci1GetMemory1Base(void)
{
unsigned int base;
GT_READ(GT_PCI1M1LD_OFS, &base);
base = base << 21;
return base;
}
/*
* pci1GetMemory1Size - Return PCI1 Memory 1 Bar Size.
* Inputs: N/A
* Returns: PCI1 Memory 1 Bar Size.
*/
static unsigned int pci1GetMemory1Size(void)
{
unsigned int top, base, size;
GT_READ(GT_PCI1M1LD_OFS, &base);
base = base << 21;
GT_READ(GT_PCI1M1HD_OFS, &top);
top = (top << 21);
size = ((top - base) & 0xfffffff);
size = size | 0x1fffff;
return (size + 1);
}
/*
* pci_range_ck -
*
* Check if the pci device that are trying to access does really exists
* on the evaluation board.
*
* Inputs :
* bus - bus number (0 for PCI 0 ; 1 for PCI 1)
* dev - number of device on the specific pci bus
*
* Outpus :
* 0 - if OK , 1 - if failure
*/
static __inline__ int pci_range_ck(unsigned char bus, unsigned char dev)
{
//DBG(KERN_INFO "p_r_c %d %d\n",bus,dev);
if (((bus == 0) || (bus == 1)) && (dev >= 6) && (dev <= 8))
return 0; // Bus/Device Number OK
return -1; // Bus/Device Number not OK
}
/*
* pciXReadConfigReg - Read from a PCI configuration register
* - Make sure the GT is configured as a master before
* reading from another device on the PCI.
* - The function takes care of Big/Little endian conversion.
* INPUTS: regOffset: The register offset as it apears in the GT spec (or PCI
* spec)
* pciDevNum: The device number needs to be addressed.
* RETURNS: data , if the data == 0xffffffff check the master abort bit in the
* cause register to make sure the data is valid
*
* Configuration Address 0xCF8:
*
* 31 30 24 23 16 15 11 10 8 7 2 0 <=bit Number
* |congif|Reserved| Bus |Device|Function|Register|00|
* |Enable| |Number|Number| Number | Number | | <=field Name
*
*/
static unsigned int pci0ReadConfigReg(int offset, struct pci_dev *device)
{
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);
/* The casual observer might wonder why the READ is duplicated here,
rather than immediately following the WRITE, and just have the
swap in the "if". That's because there is a latency problem
with trying to read immediately after setting up the address
register. The "if" check gives enough time for the address
to stabilize, so the READ can work.
*/
if (PCI_SLOT(device->devfn) == SELF) { /* This board */
GT_READ(GT_PCI0_CFGDATA_OFS, &data);
return data;
} else { /* The PCI is working in LE Mode so swap the Data. */
GT_READ(GT_PCI0_CFGDATA_OFS, &data);
return cpu_to_le32(data);
}
}
static unsigned int pci1ReadConfigReg(int offset, struct pci_dev *device)
{
unsigned int DataForRegCf8;
unsigned int data;
DataForRegCf8 = ((PCI_SLOT(device->devfn) << 11) |
(PCI_FUNC(device->devfn) << 8) |
(offset & ~0x3)) | 0x80000000;
/* The casual observer might wonder why the READ is duplicated here,
rather than immediately following the WRITE, and just have the
swap in the "if". That's because there is a latency problem
with trying to read immediately after setting up the address
register. The "if" check gives enough time for the address
to stabilize, so the READ can work.
*/
if (PCI_SLOT(device->devfn) == SELF) { /* This board */
/* when configurating our own PCI 1 L-unit the access is through
the PCI 0 interface with reg number = reg number + 0x80 */
DataForRegCf8 |= 0x80;
GT_WRITE(GT_PCI0_CFGADDR_OFS, DataForRegCf8);
} else { /* The PCI is working in LE Mode so swap the Data. */
GT_WRITE(GT_PCI1_CFGADDR_OFS, DataForRegCf8);
}
if (PCI_SLOT(device->devfn) == SELF) { /* This board */
GT_READ(GT_PCI0_CFGDATA_OFS, &data);
return data;
} else {
GT_READ(GT_PCI1_CFGDATA_OFS, &data);
return cpu_to_le32(data);
}
}
/*
* pciXWriteConfigReg - Write to a PCI configuration register
* - Make sure the GT is configured as a master before
* writingto another device on the PCI.
* - The function takes care of Big/Little endian conversion.
* Inputs: unsigned int regOffset: The register offset as it apears in the
* GT spec
* (or any other PCI device spec)
* pciDevNum: The device number needs to be addressed.
*
* Configuration Address 0xCF8:
*
* 31 30 24 23 16 15 11 10 8 7 2 0 <=bit Number
* |congif|Reserved| Bus |Device|Function|Register|00|
* |Enable| |Number|Number| Number | Number | | <=field Name
*
*/
static void pci0WriteConfigReg(unsigned int offset,
struct pci_dev *device, 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);
if (PCI_SLOT(device->devfn) == SELF) { /* This board */
GT_WRITE(GT_PCI0_CFGDATA_OFS, data);
} else { /* configuration Transaction over the pci. */
/* The PCI is working in LE Mode so swap the Data. */
GT_WRITE(GT_PCI0_CFGDATA_OFS, le32_to_cpu(data));
}
}
static void pci1WriteConfigReg(unsigned int offset,
struct pci_dev *device, unsigned int data)
{
unsigned int DataForRegCf8;
DataForRegCf8 = ((PCI_SLOT(device->devfn) << 11) |
(PCI_FUNC(device->devfn) << 8) |
(offset & ~0x3)) | 0x80000000;
/* There is a latency problem
with trying to read immediately after setting up the address
register. The "if" check gives enough time for the address
to stabilize, so the WRITE can work.
*/
if (PCI_SLOT(device->devfn) == SELF) { /* This board */
/* when configurating our own PCI 1 L-unit the access is through
the PCI 0 interface with reg number = reg number + 0x80 */
DataForRegCf8 |= 0x80;
GT_WRITE(GT_PCI0_CFGADDR_OFS, DataForRegCf8);
} else { /* configuration Transaction over the pci. */
/* The PCI is working in LE Mode so swap the Data. */
GT_WRITE(GT_PCI1_CFGADDR_OFS, DataForRegCf8);
}
if (PCI_SLOT(device->devfn) == SELF) { /* This board */
GT_WRITE(GT_PCI0_CFGDATA_OFS, data);
} else { /* configuration Transaction over the pci. */
GT_WRITE(GT_PCI1_CFGADDR_OFS, le32_to_cpu(data));
}
}
/*
* galileo_pcibios_(read/write)_config_(dword/word/byte) -
*
* reads/write a dword/word/byte register from the configuration space
* of a device.
*
* Inputs :
* bus - bus number
* dev - device number
* offset - register offset in the configuration space
* val - value to be written / read
*
* Outputs :
* PCIBIOS_SUCCESSFUL when operation was succesfull
* PCIBIOS_DEVICE_NOT_FOUND when the bus or dev is errorneous
* PCIBIOS_BAD_REGISTER_NUMBER when accessing non aligned
*/
static int galileo_pcibios_read_config_dword(struct pci_dev *device,
int offset, u32 * val)
{
int dev, bus;
//DBG(KERN_INFO "rcd entry \n",offset,val);
bus = device->bus->number;
dev = PCI_SLOT(device->devfn);
if (pci_range_ck(bus, dev)) {
*val = 0xffffffff;
return PCIBIOS_DEVICE_NOT_FOUND;
}
if (offset & 0x3)
return PCIBIOS_BAD_REGISTER_NUMBER;
if (bus == 0)
*val = pci0ReadConfigReg(offset, device);
// if (bus == 1) *val = pci1ReadConfigReg (offset,device);
DBG(KERN_INFO "rr: rcd dev %d offset %x %x\n", dev, offset, *val);
/*
* This is so that the upper PCI layer will get the correct return
* value if we're not attached to anything.
*/
if ((offset == 0) && (*val == 0xffffffff)) {
return PCIBIOS_DEVICE_NOT_FOUND;
}
return PCIBIOS_SUCCESSFUL;
}
static int galileo_pcibios_read_config_word(struct pci_dev *device,
int offset, u16 * val)
{
int dev, bus;
bus = device->bus->number;
dev = PCI_SLOT(device->devfn);
if (pci_range_ck(bus, dev)) {
*val = 0xffff;
return PCIBIOS_DEVICE_NOT_FOUND;
}
if (offset & 0x1)
return PCIBIOS_BAD_REGISTER_NUMBER;
if (bus == 0)
*val =
(unsigned short) (pci0ReadConfigReg(offset, device) >>
((offset & ~0x3) * 8));
// if (bus == 1) *val = (unsigned short) (pci1ReadConfigReg(offset,device) >> ((offset & ~0x3) * 8));
DBG(KERN_INFO "rr: rcw dev %d offset %x %x\n", dev, offset, *val);
return PCIBIOS_SUCCESSFUL;
}
static int galileo_pcibios_read_config_byte(struct pci_dev *device,
int offset, u8 * val)
{
int dev, bus;
bus = device->bus->number;
dev = PCI_SLOT(device->devfn);
if (pci_range_ck(bus, dev)) {
*val = 0xff;
return PCIBIOS_DEVICE_NOT_FOUND;
}
if (bus == 0)
*val =
(unsigned char) (pci0ReadConfigReg(offset, device) >>
((offset & ~0x3) * 8));
// if (bus == 1) *val = (unsigned char) (pci1ReadConfigReg(offset,device) >> ((offset & ~0x3) * 8));
DBG(KERN_INFO "rr: rcb dev %d offset %x %x\n", dev, offset, *val);
/* This is so that the upper PCI layer will get the correct return value if
we're not attached to anything. */
if ((offset == 0xe) && (*val == 0xff)) {
u32 MasterAbort;
GT_READ(GT_INTRCAUSE_OFS, &MasterAbort);
if (MasterAbort & 0x40000) {
DBG(KERN_INFO "PCI Master Abort, ICR %x\n",
MasterAbort);
GT_WRITE(GT_INTRCAUSE_OFS,
(MasterAbort & 0xfffbffff));
return PCIBIOS_DEVICE_NOT_FOUND;
}
}
return PCIBIOS_SUCCESSFUL;
}
static int galileo_pcibios_write_config_dword(struct pci_dev *device,
int offset, u32 val)
{
int dev, bus;
bus = device->bus->number;
dev = PCI_SLOT(device->devfn);
if (pci_range_ck(bus, dev))
return PCIBIOS_DEVICE_NOT_FOUND;
if (offset & 0x3)
return PCIBIOS_BAD_REGISTER_NUMBER;
if (bus == 0)
pci0WriteConfigReg(offset, device, val);
// if (bus == 1) pci1WriteConfigReg (offset,device,val);
DBG(KERN_INFO "rr: wcd dev %d, offset %x, val %x\n", dev, offset,
val);
return PCIBIOS_SUCCESSFUL;
}
static int galileo_pcibios_write_config_word(struct pci_dev *device,
int offset, u16 val)
{
int dev, bus;
unsigned long tmp;
bus = device->bus->number;
dev = PCI_SLOT(device->devfn);
if (pci_range_ck(bus, dev))
return PCIBIOS_DEVICE_NOT_FOUND;
if (offset & 0x1)
return PCIBIOS_BAD_REGISTER_NUMBER;
if (bus == 0)
tmp = pci0ReadConfigReg(offset, device);
// if (bus == 1) tmp = pci1ReadConfigReg (offset,device);
if ((offset % 4) == 0)
tmp = (tmp & 0xffff0000) | (val & 0xffff);
if ((offset % 4) == 2)
tmp = (tmp & 0x0000ffff) | ((val & 0xffff) << 16);
if (bus == 0)
pci0WriteConfigReg(offset, device, tmp);
// if (bus == 1) pci1WriteConfigReg (offset,device,tmp);
DBG(KERN_INFO "rr: wcw dev %d, offset %x, val %x\n", dev, offset,
val);
return PCIBIOS_SUCCESSFUL;
}
static int galileo_pcibios_write_config_byte(struct pci_dev *device,
int offset, u8 val)
{
int dev, bus;
unsigned long tmp;
bus = device->bus->number;
dev = PCI_SLOT(device->devfn);
if (pci_range_ck(bus, dev))
return PCIBIOS_DEVICE_NOT_FOUND;
if (bus == 0)
tmp = pci0ReadConfigReg(offset, device);
// if (bus == 1) tmp = pci1ReadConfigReg (offset,device);
if ((offset % 4) == 0)
tmp = (tmp & 0xffffff00) | (val & 0xff);
if ((offset % 4) == 1)
tmp = (tmp & 0xffff00ff) | ((val & 0xff) << 8);
if ((offset % 4) == 2)
tmp = (tmp & 0xff00ffff) | ((val & 0xff) << 16);
if ((offset % 4) == 3)
tmp = (tmp & 0x00ffffff) | ((val & 0xff) << 24);
if (bus == 0)
pci0WriteConfigReg(offset, device, tmp);
// if (bus == 1) pci1WriteConfigReg (offset,device,tmp);
DBG(KERN_INFO "rr: wcb dev %d, offset %x, val %x\n", dev, offset,
val);
return PCIBIOS_SUCCESSFUL;
}
static void galileo_pcibios_set_master(struct pci_dev *dev)
{
u16 cmd;
DBG(KERN_INFO "rr: galileo_pcibios_set_master\n");
galileo_pcibios_read_config_word(dev, PCI_COMMAND, &cmd);
cmd |= PCI_COMMAND_MASTER;
galileo_pcibios_write_config_word(dev, PCI_COMMAND, cmd);
DBG("PCI: Enabling device %s (%04x)\n", dev->slot_name, cmd);
}
/* Externally-expected functions. Do not change function names */
int pcibios_enable_resources(struct pci_dev *dev)
{
u16 cmd, old_cmd;
u16 tmp;
u8 tmp1;
int idx;
struct resource *r;
DBG(KERN_INFO "rr: pcibios_enable_resources\n");
galileo_pcibios_read_config_word(dev, PCI_COMMAND, &cmd);
old_cmd = cmd;
for (idx = 0; idx < 6; idx++) {
r = &dev->resource[idx];
DBG(KERN_INFO
"rr: BAR %d, start %lx, end %lx, flags %lx\n", idx,
r->start, r->end, r->flags);
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 (cmd != old_cmd) {
DBG(KERN_INFO "PCI: Enabling device %s (%04x -> %04x)\n",
dev->slot_name, old_cmd, cmd);
galileo_pcibios_write_config_word(dev, PCI_COMMAND, cmd);
}
/*
Let's fix up the latency timer and cache line size here. Cache line size =
32 bytes / sizeof dword (4) = 8.
Latency timer must be > 8. 32 is random but appears to work.
*/
galileo_pcibios_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &tmp1);
if (tmp1 != 8) {
DBG(KERN_INFO
"rr: PCI setting cache line size to 8 from %d\n",
tmp1);
galileo_pcibios_write_config_byte(dev, PCI_CACHE_LINE_SIZE,
8);
}
galileo_pcibios_read_config_byte(dev, PCI_LATENCY_TIMER, &tmp1);
if (tmp1 < 32) {
DBG(KERN_INFO
"rr: PCI setting latency timer to 32 from %d\n", tmp1);
galileo_pcibios_write_config_byte(dev, PCI_LATENCY_TIMER,
32);
}
return 0;
}
int pcibios_enable_device(struct pci_dev *dev, int mask)
{
DBG(KERN_INFO "rr: pcibios_enable_device\n");
return pcibios_enable_resources(dev);
}
void pcibios_align_resource(void *data, struct resource *res,
unsigned long size, unsigned long align)
{
if (res->flags & IORESOURCE_IO) {
unsigned long start = res->start;
/* We need to avoid collisions with `mirrored' VGA ports
and other strange ISA hardware, so we always want the
addresses kilobyte aligned. */
if (size > 0x100) {
DBG(KERN_ERR "PCI: I/O Region %s/%d too large"
" (%ld bytes)\n", dev->slot_name,
dev->resource - res, size);
}
start = (start + 1024 - 1) & ~(1024 - 1);
res->start = start;
}
}
/*
* structure galileo_pci_ops
*
* This structure holds the pointers for the PCI configuration space
* access, and the fixup for the interrupts.
* This structure is registered to the operating system in boot time
*/
struct pci_ops galileo_pci_ops = {
galileo_pcibios_read_config_byte,
galileo_pcibios_read_config_word,
galileo_pcibios_read_config_dword,
galileo_pcibios_write_config_byte,
galileo_pcibios_write_config_word,
galileo_pcibios_write_config_dword
};
/*
* galileo_pcibios_fixup_bus -
*
* 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.
*
* Inputs :
* mem_start , mem_end are not relevant in MIPS architecture.
*
* Outpus :
* return always mem_start
*/
static void __devinit galileo_pcibios_fixup_bus(struct pci_bus *bus)
{
unsigned int Current_IRQ = 20;
struct pci_bus *current_bus = bus;
struct pci_dev *devices;
struct list_head *devices_link;
list_for_each(devices_link, &(current_bus->devices)) {
devices = pci_dev_b(devices_link);
if (devices != NULL) {
devices->irq = Current_IRQ++;
/* Assign an interrupt number for the device */
galileo_pcibios_write_config_byte(devices,
PCI_INTERRUPT_LINE,
Current_IRQ);
galileo_pcibios_set_master(devices);
}
}
}
struct pci_fixup pcibios_fixups[] = {
// { PCI_FIXUP_HEADER, 0x4620, 0x11ab, galileo_pcibios_fixup },
{0}
};
void __devinit pcibios_fixup_bus(struct pci_bus *c)
{
DBG(KERN_INFO "rr: pcibios_fixup_bus\n");
galileo_pcibios_fixup_bus(c);
}
/*
* This code was derived from Galileo Technology's example
* and significantly reworked.
*
* This is very simple. It does not scan multiple function devices. It does
* not scan behind bridges. Those would be simple to implement, but we don't
* currently need this.
*/
static void __init scan_and_initialize_pci(void)
{
struct pci_device pci_devices[MAX_PCI_DEVS];
if (scan_pci_bus(pci_devices)) {
allocate_pci_space(pci_devices);
}
}
/*
* This is your basic PCI scan. It goes through each slot and checks to
* see if there's something that responds. If so, then get the size and
* type of each of the responding BARs. Save them for later.
*/
static u32 __init scan_pci_bus(struct pci_device *pci_devices)
{
u32 arrayCounter = 0;
u32 memType;
u32 memSize;
u32 pci_slot, bar;
u32 id;
u32 c18RegValue;
struct pci_dev device;
DBG(KERN_INFO "rr: scan_pci_bus\n");
/*
According to PCI REV 2.1 MAX agents on the bus are 21.
We don't bother scanning ourselves (slot 0).
*/
for (pci_slot = 1; pci_slot < 22; pci_slot++) {
device.devfn = PCI_DEVFN(pci_slot, 0);
id = pci0ReadConfigReg(PCI_VENDOR_ID, &device);
/* Check for a PCI Master Abort (nothing responds in the slot) */
GT_READ(GT_INTRCAUSE_OFS, &c18RegValue);
/* Clearing bit 18 of in the Cause Register 0xc18 by writting 0. */
GT_WRITE(GT_INTRCAUSE_OFS, (c18RegValue & 0xfffbffff));
if ((id != 0xffffffff) && !(c18RegValue & 0x40000)) {
DBG(KERN_INFO "rr: found device %x, slot %d\n", id,
pci_slot);
pci_devices[arrayCounter].slot = pci_slot;
for (bar = 0; bar < 6; bar++) {
memType =
pci0ReadConfigReg(PCI_BASE_ADDRESS_0 +
(bar * 4), &device);
pci_devices[arrayCounter].BARtype[bar] =
memType & 1;
pci0WriteConfigReg(PCI_BASE_ADDRESS_0 +
(bar * 4), &device,
0xffffffff);
memSize =
pci0ReadConfigReg(PCI_BASE_ADDRESS_0 +
(bar * 4), &device);
if (memType & 1) { /* IO space */
pci_devices[arrayCounter].
BARsize[bar] =
~(memSize & 0xfffffffc) + 1;
} else { /* memory space */
pci_devices[arrayCounter].
BARsize[bar] =
~(memSize & 0xfffffff0) + 1;
}
DBG(KERN_INFO
"rr: BAR %d, type %d, size %x\n", bar,
(memType & 1),
pci_devices[arrayCounter].
BARsize[bar]);
} /* BAR counter */
arrayCounter++;
}
/* found a device */
} /* slot counter */
DBG(KERN_INFO "rr: found %d devices\n", arrayCounter);
if (arrayCounter < MAX_PCI_DEVS) {
pci_devices[arrayCounter].slot = -1;
}
return (arrayCounter);
}
#define ALIGN(val,align) (((val) + ((align) - 1)) & ~((align) - 1))
#define MAX(val1, val2) ((val1) > (val2) ? (val1) : (val2))
/*
* This function goes through the list of devices and allocates the BARs in
* either IO or MEM space. It does it in order of size, which will limit the
* amount of fragmentation we have in the IO and MEM spaces.
*/
static void __init allocate_pci_space(struct pci_device *pci_devices)
{
u32 count, maxcount, bar;
u32 maxSize, maxDevice, maxBAR;
u32 alignto;
u32 base;
u32 pci0_mem_base = pci0GetMemory0Base();
u32 pci0_io_base = pci0GetIOspaceBase();
struct pci_dev device;
DBG(KERN_INFO "rr: allocate_pci_space\n");
DBG(KERN_INFO "pci0_io_base %x\n", pci0_io_base);
DBG(KERN_INFO "pci0_mem_base %x\n", pci0_mem_base);
/* How many PCI devices do we have? */
maxcount = MAX_PCI_DEVS;
for (count = 0; count < MAX_PCI_DEVS; count++) {
if (pci_devices[count].slot == -1) {
maxcount = count;
break;
}
}
// DBG(KERN_INFO "Found %d devices\n", maxcount);
do {
/* Find the largest size BAR we need to allocate */
maxSize = 0;
for (count = 0; count < maxcount; count++) {
for (bar = 0; bar < 6; bar++) {
if (pci_devices[count].BARsize[bar] >
maxSize) {
maxSize =
pci_devices[count].
BARsize[bar];
maxDevice = count;
maxBAR = bar;
}
}
}
/*
We've found the largest BAR. Allocate it into IO or
mem space. We don't idiot check the bases to make
sure they haven't overflowed the current size for that aperture.
Don't bother to enable the device's IO or MEM space here. That will
be done in pci_enable_resources if the device is activated by a driver.
*/
if (maxSize) {
device.devfn =
PCI_DEVFN(pci_devices[maxDevice].slot, 0);
if (pci_devices[maxDevice].BARtype[maxBAR] == 1) {
alignto = MAX(0x1000, maxSize);
base = ALIGN(pci0_io_base, alignto);
pci0WriteConfigReg(PCI_BASE_ADDRESS_0 +
(maxBAR * 4), &device,
base | 0x1);
pci0_io_base = base + alignto;
DBG(KERN_INFO
"Device %d BAR %d address %x\n",
pci_devices[maxDevice].slot, maxBAR,
base);
DBG(KERN_INFO "New IO base %x\n",
pci0_io_base);
} else {
alignto = MAX(0x1000, maxSize);
base = ALIGN(pci0_mem_base, alignto);
pci0WriteConfigReg(PCI_BASE_ADDRESS_0 +
(maxBAR * 4), &device,
base);
pci0_mem_base = base + alignto;
DBG(KERN_INFO
"Device %d BAR %d address %x\n",
pci_devices[maxDevice].slot, maxBAR,
base);
DBG(KERN_INFO "New mem base %x\n",
pci0_mem_base);
}
/*
This entry is finished. Remove it from the list we'll scan.
*/
pci_devices[maxDevice].BARsize[maxBAR] = 0;
}
} while (maxSize);
}
unsigned __init int pcibios_assign_all_busses(void)
{
return 1;
}
static int __init pcibios_init(void)
{
u32 tmp;
struct pci_dev controller;
controller.devfn = SELF;
DBG(KERN_INFO "rr: pcibios_init\n");
GT_READ(GT_PCI0_CMD_OFS, &tmp);
DBG(KERN_INFO "rr: PCI0 command - %x\n", tmp);
GT_READ(GT_PCI0_BARE_OFS, &tmp);
DBG(KERN_INFO "rr: BAR0 - %x\n", tmp);
/*
* You have to enable bus mastering to configure any other
* card on the bus.
*/
tmp = pci0ReadConfigReg(PCI_COMMAND, &controller);
DBG(KERN_INFO "rr: command/status - %x\n", tmp);
tmp |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_SERR;
DBG(KERN_INFO "rr: new command/status - %x\n", tmp);
pci0WriteConfigReg(PCI_COMMAND, &controller, tmp);
/* This scans the PCI bus and sets up initial values. */
scan_and_initialize_pci();
/*
* Reset PCI I/O and PCI MEM values to ones supported by EVM.
*/
ioport_resource.start = 0x10000000;
ioport_resource.end = 0x11ffffff; /* 32 MB */
iomem_resource.start = 0x12000000;
iomem_resource.end = 0x13ffffff; /* 32 MB */
pci_scan_bus(0, &galileo_pci_ops, NULL);
return 0;
}
subsys_initcall(pcibios_init);
char *pcibios_setup(char *str)
{
printk(KERN_INFO "rr: pcibios_setup\n");
/* Nothing to do for now. */
return str;
}
/*
*
* 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;
}
/***********************************************************************
* Copyright 2001 MontaVista Software Inc.
* Author: MontaVista Software, Inc.
* ahennessy@mvista.com
*
* Copyright (C) 2000-2001 Toshiba Corporation
*
* 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/pci_channel.h>
#include <asm/jmr3927/jmr3927.h>
#include <asm/debug.h>
struct resource pci_io_resource = {
"pci IO space",
0x1000, /* reserve regacy I/O space */
0x1000 + JMR3927_PCIIO_SIZE - 1,
IORESOURCE_IO
};
struct resource pci_mem_resource = {
"pci memory space",
JMR3927_PCIMEM,
JMR3927_PCIMEM + JMR3927_PCIMEM_SIZE - 1,
IORESOURCE_MEM
};
extern struct pci_ops jmr3927_pci_ops;
struct pci_channel mips_pci_channels[] = {
{&jmr3927_pci_ops, &pci_io_resource, &pci_mem_resource, 0, 0xff},
{NULL, NULL, NULL, NULL, NULL}
};
unsigned int pcibios_assign_all_busses(void)
{
return 1;
}
static int
mkaddr(unsigned char bus, unsigned char dev_fn, unsigned char where,
int *flagsp)
{
if (bus == 0 && dev_fn >= PCI_DEVFN(TX3927_PCIC_MAX_DEVNU, 0))
return -1;
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 0;
}
static int check_abort(int flags)
{
int code = PCIBIOS_SUCCESSFUL;
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;
code = PCIBIOS_DEVICE_NOT_FOUND;
}
return code;
}
/*
* 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 jmr3927_pcibios_read_config_byte(struct pci_dev *dev,
int where, unsigned char *val)
{
int flags;
unsigned char bus, func_num;
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;
}
func_num = PCI_FUNC(dev->devfn);
if (mkaddr(bus, dev->devfn, where, &flags))
return -1;
*val =
*(volatile u8 *) ((ulong) & tx3927_pcicptr->icd | (where & 3));
return check_abort(flags);
}
static int jmr3927_pcibios_read_config_word(struct pci_dev *dev,
int where, unsigned short *val)
{
int flags;
unsigned char bus, func_num;
if (where & 1)
return PCIBIOS_BAD_REGISTER_NUMBER;
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;
}
func_num = PCI_FUNC(dev->devfn);
if (mkaddr(bus, dev->devfn, where, &flags))
return -1;
*val =
le16_to_cpu(*(volatile u16 *)
((ulong) & tx3927_pcicptr->icd | (where & 3)));
return check_abort(flags);
}
static int jmr3927_pcibios_read_config_dword(struct pci_dev *dev,
int where, unsigned int *val)
{
int flags;
unsigned char bus, func_num;
if (where & 3)
return PCIBIOS_BAD_REGISTER_NUMBER;
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;
}
func_num = PCI_FUNC(dev->devfn);
if (mkaddr(bus, dev->devfn, where, &flags))
return -1;
*val = le32_to_cpu(tx3927_pcicptr->icd);
return check_abort(flags);
}
static int jmr3927_pcibios_write_config_byte(struct pci_dev *dev,
int where, unsigned char val)
{
int flags;
unsigned char bus, func_num;
/* check if the bus is top-level */
if (dev->bus->parent != NULL) {
bus = dev->bus->number;
db_assert(bus != 0);
} else {
bus = 0;
}
func_num = PCI_FUNC(dev->devfn);
if (mkaddr(bus, dev->devfn, where, &flags))
return -1;
*(volatile u8 *) ((ulong) & tx3927_pcicptr->icd | (where & 3)) =
val;
return check_abort(flags);
}
static int jmr3927_pcibios_write_config_word(struct pci_dev *dev,
int where, unsigned short val)
{
int flags;
unsigned char bus, func_num;
if (where & 1)
return PCIBIOS_BAD_REGISTER_NUMBER;
/* check if the bus is top-level */
if (dev->bus->parent != NULL) {
bus = dev->bus->number;
db_assert(bus != 0);
} else {
bus = 0;
}
func_num = PCI_FUNC(dev->devfn);
if (mkaddr(bus, dev->devfn, where, &flags))
return -1;
*(volatile u16 *) ((ulong) & tx3927_pcicptr->icd | (where & 3)) =
cpu_to_le16(val);
return check_abort(flags);
}
static int jmr3927_pcibios_write_config_dword(struct pci_dev *dev,
int where, unsigned int val)
{
int flags;
unsigned char bus, func_num;
if (where & 3)
return PCIBIOS_BAD_REGISTER_NUMBER;
/* check if the bus is top-level */
if (dev->bus->parent != NULL) {
bus = dev->bus->number;
db_assert(bus != 0);
} else {
bus = 0;
}
func_num = PCI_FUNC(dev->devfn);
if (mkaddr(bus, dev->devfn, where, &flags))
return -1;
tx3927_pcicptr->icd = cpu_to_le32(val);
return check_abort(flags);
}
struct pci_ops jmr3927_pci_ops = {
jmr3927_pcibios_read_config_byte,
jmr3927_pcibios_read_config_word,
jmr3927_pcibios_read_config_dword,
jmr3927_pcibios_write_config_byte,
jmr3927_pcibios_write_config_word,
jmr3927_pcibios_write_config_dword
};
#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
/*
* 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/types.h>
#include <linux/pci.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/version.h>
#include <linux/cache.h>
#include <asm/pci.h>
#include <asm/io.h>
#include <asm/gt64120/gt64120.h>
#include <linux/init.h>
#define SELF 0
/*
* These functions and structures provide the BIOS scan and mapping of the PCI
* devices.
*/
#define MAX_PCI_DEVS 10
struct pci_device {
u32 slot;
u32 BARtype[6];
u32 BARsize[6];
};
static void __init scan_and_initialize_pci(void);
static u32 __init scan_pci_bus(struct pci_device *pci_devices);
static void __init allocate_pci_space(struct pci_device *pci_devices);
/*
* The functions that actually read and write to the controller.
*
* Copied from or modified from Galileo Technology code.
*/
static unsigned int pci0ReadConfigReg(int offset, struct pci_dev *device);
static void pci0WriteConfigReg(unsigned int offset,
struct pci_dev *device, unsigned int data);
static unsigned int pci1ReadConfigReg(int offset, struct pci_dev *device);
static void pci1WriteConfigReg(unsigned int offset,
struct pci_dev *device, unsigned int data);
static void pci0MapIOspace(unsigned int pci0IoBase,
unsigned int pci0IoLength);
static void pci1MapIOspace(unsigned int pci1IoBase,
unsigned int pci1IoLength);
static void pci0MapMemory0space(unsigned int pci0Mem0Base,
unsigned int pci0Mem0Length);
static void pci1MapMemory0space(unsigned int pci1Mem0Base,
unsigned int pci1Mem0Length);
static void pci0MapMemory1space(unsigned int pci0Mem1Base,
unsigned int pci0Mem1Length);
static void pci1MapMemory1space(unsigned int pci1Mem1Base,
unsigned int pci1Mem1Length);
static unsigned int pci0GetIOspaceBase(void);
static unsigned int pci0GetIOspaceSize(void);
static unsigned int pci0GetMemory0Base(void);
static unsigned int pci0GetMemory0Size(void);
static unsigned int pci0GetMemory1Base(void);
static unsigned int pci0GetMemory1Size(void);
static unsigned int pci1GetIOspaceBase(void);
static unsigned int pci1GetIOspaceSize(void);
static unsigned int pci1GetMemory0Base(void);
static unsigned int pci1GetMemory0Size(void);
static unsigned int pci1GetMemory1Base(void);
static unsigned int pci1GetMemory1Size(void);
/* Functions to implement "pci ops" */
static int galileo_pcibios_read(struct pci_bus *bus, unsigned int devfn,
int offset, int size, u32 * val);
static int galileo_pcibios_write(struct pci_bus *bus, unsigned int devfn,
int offset, int size, u32 val);
static void galileo_pcibios_set_master(struct pci_dev *dev);
/*
* General-purpose PCI functions.
*/
/*
* pci0MapIOspace - Maps PCI0 IO space for the master.
* Inputs: base and length of pci0Io
*/
static void pci0MapIOspace(unsigned int pci0IoBase,
unsigned int pci0IoLength)
{
unsigned int pci0IoTop =
(unsigned int) (pci0IoBase + pci0IoLength);
if (pci0IoLength == 0)
pci0IoTop++;
pci0IoBase = (unsigned int) (pci0IoBase >> 21);
pci0IoTop = (unsigned int) (((pci0IoTop - 1) & 0x0fffffff) >> 21);
GT_WRITE(GT_PCI0IOLD_OFS, pci0IoBase);
GT_WRITE(GT_PCI0IOHD_OFS, pci0IoTop);
}
/*
* pci1MapIOspace - Maps PCI1 IO space for the master.
* Inputs: base and length of pci1Io
*/
static void pci1MapIOspace(unsigned int pci1IoBase,
unsigned int pci1IoLength)
{
unsigned int pci1IoTop =
(unsigned int) (pci1IoBase + pci1IoLength);
if (pci1IoLength == 0)
pci1IoTop++;
pci1IoBase = (unsigned int) (pci1IoBase >> 21);
pci1IoTop = (unsigned int) (((pci1IoTop - 1) & 0x0fffffff) >> 21);
GT_WRITE(GT_PCI1IOLD_OFS, pci1IoBase);
GT_WRITE(GT_PCI1IOHD_OFS, pci1IoTop);
}
/*
* pci0MapMemory0space - Maps PCI0 memory0 space for the master.
* Inputs: base and length of pci0Mem0
*/
static void pci0MapMemory0space(unsigned int pci0Mem0Base,
unsigned int pci0Mem0Length)
{
unsigned int pci0Mem0Top = pci0Mem0Base + pci0Mem0Length;
if (pci0Mem0Length == 0)
pci0Mem0Top++;
pci0Mem0Base = pci0Mem0Base >> 21;
pci0Mem0Top = ((pci0Mem0Top - 1) & 0x0fffffff) >> 21;
GT_WRITE(GT_PCI0M0LD_OFS, pci0Mem0Base);
GT_WRITE(GT_PCI0M0HD_OFS, pci0Mem0Top);
}
/*
* pci1MapMemory0space - Maps PCI1 memory0 space for the master.
* Inputs: base and length of pci1Mem0
*/
static void pci1MapMemory0space(unsigned int pci1Mem0Base,
unsigned int pci1Mem0Length)
{
unsigned int pci1Mem0Top = pci1Mem0Base + pci1Mem0Length;
if (pci1Mem0Length == 0)
pci1Mem0Top++;
pci1Mem0Base = pci1Mem0Base >> 21;
pci1Mem0Top = ((pci1Mem0Top - 1) & 0x0fffffff) >> 21;
GT_WRITE(GT_PCI1M0LD_OFS, pci1Mem0Base);
GT_WRITE(GT_PCI1M0HD_OFS, pci1Mem0Top);
}
/*
* pci0MapMemory1space - Maps PCI0 memory1 space for the master.
* Inputs: base and length of pci0Mem1
*/
static void pci0MapMemory1space(unsigned int pci0Mem1Base,
unsigned int pci0Mem1Length)
{
unsigned int pci0Mem1Top = pci0Mem1Base + pci0Mem1Length;
if (pci0Mem1Length == 0)
pci0Mem1Top++;
pci0Mem1Base = pci0Mem1Base >> 21;
pci0Mem1Top = ((pci0Mem1Top - 1) & 0x0fffffff) >> 21;
GT_WRITE(GT_PCI0M1LD_OFS, pci0Mem1Base);
GT_WRITE(GT_PCI0M1HD_OFS, pci0Mem1Top);
}
/*
* pci1MapMemory1space - Maps PCI1 memory1 space for the master.
* Inputs: base and length of pci1Mem1
*/
static void pci1MapMemory1space(unsigned int pci1Mem1Base,
unsigned int pci1Mem1Length)
{
unsigned int pci1Mem1Top = pci1Mem1Base + pci1Mem1Length;
if (pci1Mem1Length == 0)
pci1Mem1Top++;
pci1Mem1Base = pci1Mem1Base >> 21;
pci1Mem1Top = ((pci1Mem1Top - 1) & 0x0fffffff) >> 21;
GT_WRITE(GT_PCI1M1LD_OFS, pci1Mem1Base);
GT_WRITE(GT_PCI1M1HD_OFS, pci1Mem1Top);
}
/*
* pci0GetIOspaceBase - Return PCI0 IO Base Address.
* Inputs: N/A
* Returns: PCI0 IO Base Address.
*/
static unsigned int pci0GetIOspaceBase(void)
{
unsigned int base;
GT_READ(GT_PCI0IOLD_OFS, &base);
base = base << 21;
return base;
}
/*
* pci0GetIOspaceSize - Return PCI0 IO Bar Size.
* Inputs: N/A
* Returns: PCI0 IO Bar Size.
*/
static unsigned int pci0GetIOspaceSize(void)
{
unsigned int top, base, size;
GT_READ(GT_PCI0IOLD_OFS, &base);
base = base << 21;
GT_READ(GT_PCI0IOHD_OFS, &top);
top = (top << 21);
size = ((top - base) & 0xfffffff);
size = size | 0x1fffff;
return (size + 1);
}
/*
* pci0GetMemory0Base - Return PCI0 Memory 0 Base Address.
* Inputs: N/A
* Returns: PCI0 Memory 0 Base Address.
*/
static unsigned int pci0GetMemory0Base(void)
{
unsigned int base;
GT_READ(GT_PCI0M0LD_OFS, &base);
base = base << 21;
return base;
}
/*
* pci0GetMemory0Size - Return PCI0 Memory 0 Bar Size.
* Inputs: N/A
* Returns: PCI0 Memory 0 Bar Size.
*/
static unsigned int pci0GetMemory0Size(void)
{
unsigned int top, base, size;
GT_READ(GT_PCI0M0LD_OFS, &base);
base = base << 21;
GT_READ(GT_PCI0M0HD_OFS, &top);
top = (top << 21);
size = ((top - base) & 0xfffffff);
size = size | 0x1fffff;
return (size + 1);
}
/*
* pci0GetMemory1Base - Return PCI0 Memory 1 Base Address.
* Inputs: N/A
* Returns: PCI0 Memory 1 Base Address.
*/
static unsigned int pci0GetMemory1Base(void)
{
unsigned int base;
GT_READ(GT_PCI0M1LD_OFS, &base);
base = base << 21;
return base;
}
/*
* pci0GetMemory1Size - Return PCI0 Memory 1 Bar Size.
* Inputs: N/A
* Returns: PCI0 Memory 1 Bar Size.
*/
static unsigned int pci0GetMemory1Size(void)
{
unsigned int top, base, size;
GT_READ(GT_PCI0M1LD_OFS, &base);
base = base << 21;
GT_READ(GT_PCI0M1HD_OFS, &top);
top = (top << 21);
size = ((top - base) & 0xfffffff);
size = size | 0x1fffff;
return (size + 1);
}
/*
* pci1GetIOspaceBase - Return PCI1 IO Base Address.
* Inputs: N/A
* Returns: PCI1 IO Base Address.
*/
static unsigned int pci1GetIOspaceBase(void)
{
unsigned int base;
GT_READ(GT_PCI1IOLD_OFS, &base);
base = base << 21;
return base;
}
/*
* pci1GetIOspaceSize - Return PCI1 IO Bar Size.
* Inputs: N/A
* Returns: PCI1 IO Bar Size.
*/
static unsigned int pci1GetIOspaceSize(void)
{
unsigned int top, base, size;
GT_READ(GT_PCI1IOLD_OFS, &base);
base = base << 21;
GT_READ(GT_PCI1IOHD_OFS, &top);
top = (top << 21);
size = ((top - base) & 0xfffffff);
size = size | 0x1fffff;
return (size + 1);
}
/*
* pci1GetMemory0Base - Return PCI1 Memory 0 Base Address.
* Inputs: N/A
* Returns: PCI1 Memory 0 Base Address.
*/
static unsigned int pci1GetMemory0Base(void)
{
unsigned int base;
GT_READ(GT_PCI1M0LD_OFS, &base);
base = base << 21;
return base;
}
/*
* pci1GetMemory0Size - Return PCI1 Memory 0 Bar Size.
* Inputs: N/A
* Returns: PCI1 Memory 0 Bar Size.
*/
static unsigned int pci1GetMemory0Size(void)
{
unsigned int top, base, size;
GT_READ(GT_PCI1M1LD_OFS, &base);
base = base << 21;
GT_READ(GT_PCI1M1HD_OFS, &top);
top = (top << 21);
size = ((top - base) & 0xfffffff);
size = size | 0x1fffff;
return (size + 1);
}
/*
* pci1GetMemory1Base - Return PCI1 Memory 1 Base Address.
* Inputs: N/A
* Returns: PCI1 Memory 1 Base Address.
*/
static unsigned int pci1GetMemory1Base(void)
{
unsigned int base;
GT_READ(GT_PCI1M1LD_OFS, &base);
base = base << 21;
return base;
}
/*
* pci1GetMemory1Size - Return PCI1 Memory 1 Bar Size.
* Inputs: N/A
* Returns: PCI1 Memory 1 Bar Size.
*/
static unsigned int pci1GetMemory1Size(void)
{
unsigned int top, base, size;
GT_READ(GT_PCI1M1LD_OFS, &base);
base = base << 21;
GT_READ(GT_PCI1M1HD_OFS, &top);
top = (top << 21);
size = ((top - base) & 0xfffffff);
size = size | 0x1fffff;
return (size + 1);
}
/*
* pci_range_ck -
*
* Check if the pci device that are trying to access does really exists
* on the evaluation board.
*
* Inputs :
* bus - bus number (0 for PCI 0 ; 1 for PCI 1)
* dev - number of device on the specific pci bus
*
* Outpus :
* 0 - if OK , 1 - if failure
*/
static __inline__ int pci_range_ck(unsigned char bus, unsigned char dev)
{
/*
* We don't even pretend to handle other busses than bus 0 correctly.
* Accessing device 31 crashes the CP7000 for some reason.
*/
if ((bus == 0) && (dev != 31))
return 0;
return -1;
}
/*
* pciXReadConfigReg - Read from a PCI configuration register
* - Make sure the GT is configured as a master before
* reading from another device on the PCI.
* - The function takes care of Big/Little endian conversion.
* INPUTS: regOffset: The register offset as it apears in the GT spec (or PCI
* spec)
* pciDevNum: The device number needs to be addressed.
* RETURNS: data , if the data == 0xffffffff check the master abort bit in the
* cause register to make sure the data is valid
*
* Configuration Address 0xCF8:
*
* 31 30 24 23 16 15 11 10 8 7 2 0 <=bit Number
* |congif|Reserved| Bus |Device|Function|Register|00|
* |Enable| |Number|Number| Number | Number | | <=field Name
*
*/
static unsigned int pci0ReadConfigReg(int offset, struct pci_dev *device)
{
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);
/*
* The casual observer might wonder why the READ is duplicated here,
* rather than immediately following the WRITE, and just have the swap
* in the "if". That's because there is a latency problem with trying
* to read immediately after setting up the address register. The "if"
* check gives enough time for the address to stabilize, so the READ
* can work.
*/
if (PCI_SLOT(device->devfn) == SELF) { /* This board */
GT_READ(GT_PCI0_CFGDATA_OFS, &data);
return data;
} else { /* The PCI is working in LE Mode so swap the Data. */
GT_READ(GT_PCI0_CFGDATA_OFS, &data);
return cpu_to_le32(data);
}
}
static unsigned int pci1ReadConfigReg(int offset, struct pci_dev *device)
{
unsigned int DataForRegCf8;
unsigned int data;
DataForRegCf8 = ((PCI_SLOT(device->devfn) << 11) |
(PCI_FUNC(device->devfn) << 8) |
(offset & ~0x3)) | 0x80000000;
/*
* The casual observer might wonder why the READ is duplicated here,
* rather than immediately following the WRITE, and just have the
* swap in the "if". That's because there is a latency problem
* with trying to read immediately after setting up the address
* register. The "if" check gives enough time for the address
* to stabilize, so the READ can work.
*/
if (PCI_SLOT(device->devfn) == SELF) { /* This board */
/* when configurating our own PCI 1 L-unit the access is through
the PCI 0 interface with reg number = reg number + 0x80 */
DataForRegCf8 |= 0x80;
GT_WRITE(GT_PCI0_CFGADDR_OFS, DataForRegCf8);
} else { /* The PCI is working in LE Mode so swap the Data. */
GT_WRITE(GT_PCI1_CFGADDR_OFS, DataForRegCf8);
}
if (PCI_SLOT(device->devfn) == SELF) { /* This board */
GT_READ(GT_PCI0_CFGDATA_OFS, &data);
return data;
} else {
GT_READ(GT_PCI1_CFGDATA_OFS, &data);
return cpu_to_le32(data);
}
}
/*
* pciXWriteConfigReg - Write to a PCI configuration register
* - Make sure the GT is configured as a master before
* writingto another device on the PCI.
* - The function takes care of Big/Little endian conversion.
* Inputs: unsigned int regOffset: The register offset as it apears in the
* GT spec
* (or any other PCI device spec)
* pciDevNum: The device number needs to be addressed.
*
* Configuration Address 0xCF8:
*
* 31 30 24 23 16 15 11 10 8 7 2 0 <=bit Number
* |congif|Reserved| Bus |Device|Function|Register|00|
* |Enable| |Number|Number| Number | Number | | <=field Name
*
*/
static void pci0WriteConfigReg(unsigned int offset,
struct pci_dev *device, 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);
if (PCI_SLOT(device->devfn) == SELF) { /* This board */
GT_WRITE(GT_PCI0_CFGDATA_OFS, data);
} else { /* configuration Transaction over the pci. */
/* The PCI is working in LE Mode so swap the Data. */
GT_WRITE(GT_PCI0_CFGDATA_OFS, le32_to_cpu(data));
}
}
static void pci1WriteConfigReg(unsigned int offset,
struct pci_dev *device, unsigned int data)
{
unsigned int DataForRegCf8;
DataForRegCf8 = ((PCI_SLOT(device->devfn) << 11) |
(PCI_FUNC(device->devfn) << 8) |
(offset & ~0x3)) | 0x80000000;
/*
* There is a latency problem
* with trying to read immediately after setting up the address
* register. The "if" check gives enough time for the address
* to stabilize, so the WRITE can work.
*/
if (PCI_SLOT(device->devfn) == SELF) { /* This board */
/*
* when configurating our own PCI 1 L-unit the access is through
* the PCI 0 interface with reg number = reg number + 0x80
*/
DataForRegCf8 |= 0x80;
GT_WRITE(GT_PCI0_CFGADDR_OFS, DataForRegCf8);
} else { /* configuration Transaction over the pci. */
/* The PCI is working in LE Mode so swap the Data. */
GT_WRITE(GT_PCI1_CFGADDR_OFS, DataForRegCf8);
}
if (PCI_SLOT(device->devfn) == SELF) { /* This board */
GT_WRITE(GT_PCI0_CFGDATA_OFS, data);
} else { /* configuration Transaction over the pci. */
GT_WRITE(GT_PCI1_CFGADDR_OFS, le32_to_cpu(data));
}
}
/*
* galileo_pcibios_(read/write) -
*
* reads/write a dword/word/byte register from the configuration space
* of a device.
*
* Inputs :
* bus - bus number
* devfn - device function index
* offset - register offset in the configuration space
* size - size of value (1=byte,2=word,4-dword)
* val - value to be written / read
*
* Outputs :
* PCIBIOS_SUCCESSFUL when operation was succesfull
* PCIBIOS_DEVICE_NOT_FOUND when the bus or dev is errorneous
* PCIBIOS_BAD_REGISTER_NUMBER when accessing non aligned
*/
static int galileo_pcibios_read(struct pci_bus *bus, unsigned int devfn,
int offset, int size, u32 * val)
{
int dev, busnum;
busnum = bus->number;
dev = PCI_SLOT(devfn);
if (pci_range_ck(busnum, dev)) {
if (size == 1)
*val = (u8) 0xff;
else if (size == 2)
*val = (u16) 0xffff;
else if (size == 4)
*val = 0xffffffff;
return PCIBIOS_DEVICE_NOT_FOUND;
}
if ((size == 2) && (offset & 0x1))
return PCIBIOS_BAD_REGISTER_NUMBER;
else if ((size == 4) && (offset & 0x3))
return PCIBIOS_BAD_REGISTER_NUMBER;
if (busnum == 0) {
if (size == 1) {
*val = (u8) (pci0ReadConfigReg(offset, bus->dev) >>
((offset & ~0x3) * 8));
} else if (size == 2) {
*val =
(u16) (pci0ReadConfigReg(offset, bus->dev) >>
((offset & ~0x3) * 8));
} else if (size == 4) {
*val = pci0ReadConfigReg(offset, bus->dev);
}
}
/*
* This is so that the upper PCI layer will get the correct return
* value if we're not attached to anything.
*/
switch (size) {
case 1:
if ((offset == 0xe) && (*val == (u8) 0xff)) {
u32 MasterAbort;
GT_READ(GT_INTRCAUSE_OFS, &MasterAbort);
if (MasterAbort & 0x40000) {
GT_WRITE(GT_INTRCAUSE_OFS,
(MasterAbort & 0xfffbffff));
return PCIBIOS_DEVICE_NOT_FOUND;
}
}
break;
case 4:
if ((offset == 0) && (*val == 0xffffffff)) {
return PCIBIOS_DEVICE_NOT_FOUND;
}
break}
return PCIBIOS_SUCCESSFUL;
}
static int galileo_pcibios_write(struct pci_bus *bus, unsigned int devfn,
int offset, int size, u32 val)
{
int dev, busnum;
unsigned long tmp;
busnum = bus->number;
dev = PCI_SLOT(devfn);
if (pci_range_ck(busnum, dev))
return PCIBIOS_DEVICE_NOT_FOUND;
if (size == 4) {
if (offset & 0x3)
return PCIBIOS_BAD_REGISTER_NUMBER;
if (busnum == 0)
pci0WriteConfigReg(offset, bus->dev, val);
//if (busnum == 1) pci1WriteConfigReg (offset,bus->dev,val);
return PCIBIOS_SUCCESSFUL;
}
if ((size == 2) && (offset & 0x1))
return PCIBIOS_BAD_REGISTER_NUMBER;
if (busnum == 0) {
tmp = pci0ReadConfigReg(offset, bus->dev);
//if (busnum == 1) tmp = pci1ReadConfigReg (offset,bus->dev);
if (size == 1) {
if ((offset % 4) == 0)
tmp =
(tmp & 0xffffff00) | (val & (u8) 0xff);
if ((offset % 4) == 1)
tmp =
(tmp & 0xffff00ff) | ((val & (u8) 0xff)
<< 8);
if ((offset % 4) == 2)
tmp =
(tmp & 0xff00ffff) | ((val & (u8) 0xff)
<< 16);
if ((offset % 4) == 3)
tmp =
(tmp & 0x00ffffff) | ((val & (u8) 0xff)
<< 24);
} else if (size == 2) {
if ((offset % 4) == 0)
tmp =
(tmp & 0xffff0000) | (val & (u16)
0xffff);
if ((offset % 4) == 2)
tmp =
(tmp & 0x0000ffff) |
((val & (u16) 0xffff) << 16);
}
if (busnum == 0)
pci0WriteConfigReg(offset, bus->dev, tmp);
//if (busnum == 1) pci1WriteConfigReg (offset,bus->dev,tmp);
}
return PCIBIOS_SUCCESSFUL;
}
static void galileo_pcibios_set_master(struct pci_dev *dev)
{
u16 cmd;
galileo_pcibios_read(dev->bus, dev->devfn, PCI_COMMAND, 2, &cmd);
cmd |= PCI_COMMAND_MASTER;
galileo_pcibios_write(dev->bus, dev->devfn, PCI_COMMAND, 2, cmd);
}
/* Externally-expected functions. Do not change function names */
int pcibios_enable_resources(struct pci_dev *dev)
{
u16 cmd, old_cmd;
u8 tmp1;
int idx;
struct resource *r;
galileo_pcibios_read(dev->bus, dev->devfn, PCI_COMMAND, 2, &cmd);
old_cmd = cmd;
for (idx = 0; idx < 6; idx++) {
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 (cmd != old_cmd) {
galileo_pcibios_write(dev->bus, dev->devfn, PCI_COMMAND, 2,
cmd);
}
/*
* Let's fix up the latency timer and cache line size here. Cache
* line size = 32 bytes / sizeof dword (4) = 8.
* Latency timer must be > 8. 32 is random but appears to work.
*/
galileo_pcibios_read(dev->bus, dev->devfn, PCI_CACHE_LINE_SIZE, 1,
&tmp1);
if (tmp1 != 8) {
printk(KERN_WARNING
"PCI setting cache line size to 8 from " "%d\n",
tmp1);
galileo_pcibios_write(dev->bus, dev->devfn,
PCI_CACHE_LINE_SIZE, 1, 8);
}
galileo_pcibios_read(dev->bus, dev->devfn, PCI_LATENCY_TIMER, 1,
&tmp1);
if (tmp1 < 32) {
printk(KERN_WARNING
"PCI setting latency timer to 32 from %d\n", tmp1);
galileo_pcibios_write(dev->bus, dev->devfn,
PCI_LATENCY_TIMER, 1, 32);
}
return 0;
}
int pcibios_enable_device(struct pci_dev *dev, int mask)
{
return pcibios_enable_resources(dev);
}
void pcibios_align_resource(void *data, struct resource *res,
unsigned long size, unsigned long align)
{
struct pci_dev *dev = data;
if (res->flags & IORESOURCE_IO) {
unsigned long start = res->start;
/* We need to avoid collisions with `mirrored' VGA ports
and other strange ISA hardware, so we always want the
addresses kilobyte aligned. */
if (size > 0x100) {
printk(KERN_ERR "PCI: I/O Region %s/%d too large"
" (%ld bytes)\n", dev->slot_name,
dev->resource - res, size);
}
start = (start + 1024 - 1) & ~(1024 - 1);
res->start = start;
}
}
struct pci_ops galileo_pci_ops = {
.read = galileo_pcibios_read,
.write = galileo_pcibios_write,
};
struct pci_fixup pcibios_fixups[] = {
{0}
};
void __devinit pcibios_fixup_bus(struct pci_bus *c)
{
gt64120_board_pcibios_fixup_bus(c);
}
/*
* This code was derived from Galileo Technology's example
* and significantly reworked.
*
* This is very simple. It does not scan multiple function devices. It does
* not scan behind bridges. Those would be simple to implement, but we don't
* currently need this.
*/
static void __init scan_and_initialize_pci(void)
{
struct pci_device pci_devices[MAX_PCI_DEVS];
if (scan_pci_bus(pci_devices)) {
allocate_pci_space(pci_devices);
}
}
/*
* This is your basic PCI scan. It goes through each slot and checks to
* see if there's something that responds. If so, then get the size and
* type of each of the responding BARs. Save them for later.
*/
static u32 __init scan_pci_bus(struct pci_device *pci_devices)
{
u32 arrayCounter = 0;
u32 memType;
u32 memSize;
u32 pci_slot, bar;
u32 id;
u32 c18RegValue;
struct pci_dev device;
/*
* According to PCI REV 2.1 MAX agents on the bus are 21.
* We don't bother scanning ourselves (slot 0).
*/
for (pci_slot = 1; pci_slot < 22; pci_slot++) {
device.devfn = PCI_DEVFN(pci_slot, 0);
id = pci0ReadConfigReg(PCI_VENDOR_ID, &device);
/*
* Check for a PCI Master Abort (nothing responds in the
* slot)
*/
GT_READ(GT_INTRCAUSE_OFS, &c18RegValue);
/*
* Clearing bit 18 of in the Cause Register 0xc18 by
* writting 0.
*/
GT_WRITE(GT_INTRCAUSE_OFS, (c18RegValue & 0xfffbffff));
if ((id != 0xffffffff) && !(c18RegValue & 0x40000)) {
pci_devices[arrayCounter].slot = pci_slot;
for (bar = 0; bar < 6; bar++) {
memType =
pci0ReadConfigReg(PCI_BASE_ADDRESS_0 +
(bar * 4), &device);
pci_devices[arrayCounter].BARtype[bar] =
memType & 1;
pci0WriteConfigReg(PCI_BASE_ADDRESS_0 +
(bar * 4), &device,
0xffffffff);
memSize =
pci0ReadConfigReg(PCI_BASE_ADDRESS_0 +
(bar * 4), &device);
if (memType & 1) { /* IO space */
pci_devices[arrayCounter].
BARsize[bar] =
~(memSize & 0xfffffffc) + 1;
} else { /* memory space */
pci_devices[arrayCounter].
BARsize[bar] =
~(memSize & 0xfffffff0) + 1;
}
} /* BAR counter */
arrayCounter++;
}
/* found a device */
} /* slot counter */
if (arrayCounter < MAX_PCI_DEVS)
pci_devices[arrayCounter].slot = -1;
return arrayCounter;
}
/*
* This function goes through the list of devices and allocates the BARs in
* either IO or MEM space. It does it in order of size, which will limit the
* amount of fragmentation we have in the IO and MEM spaces.
*/
static void __init allocate_pci_space(struct pci_device *pci_devices)
{
u32 count, maxcount, bar;
u32 maxSize, maxDevice, maxBAR;
u32 alignto;
u32 base;
u32 pci0_mem_base = pci0GetMemory0Base();
u32 pci0_io_base = pci0GetIOspaceBase();
struct pci_dev device;
/* How many PCI devices do we have? */
maxcount = MAX_PCI_DEVS;
for (count = 0; count < MAX_PCI_DEVS; count++) {
if (pci_devices[count].slot == -1) {
maxcount = count;
break;
}
}
do {
/* Find the largest size BAR we need to allocate */
maxSize = 0;
for (count = 0; count < maxcount; count++) {
for (bar = 0; bar < 6; bar++) {
if (pci_devices[count].BARsize[bar] >
maxSize) {
maxSize =
pci_devices[count].
BARsize[bar];
maxDevice = count;
maxBAR = bar;
}
}
}
/*
* We've found the largest BAR. Allocate it into IO or
* mem space. We don't idiot check the bases to make
* sure they haven't overflowed the current size for that
* aperture.
* Don't bother to enable the device's IO or MEM space here.
* That will be done in pci_enable_resources if the device is
* activated by a driver.
*/
if (maxSize) {
device.devfn =
PCI_DEVFN(pci_devices[maxDevice].slot, 0);
if (pci_devices[maxDevice].BARtype[maxBAR] == 1) {
alignto = max(0x1000U, maxSize);
base = ALIGN(pci0_io_base, alignto);
pci0WriteConfigReg(PCI_BASE_ADDRESS_0 +
(maxBAR * 4), &device,
base | 0x1);
pci0_io_base = base + alignto;
} else {
alignto = max(0x1000U, maxSize);
base = ALIGN(pci0_mem_base, alignto);
pci0WriteConfigReg(PCI_BASE_ADDRESS_0 +
(maxBAR * 4), &device,
base);
pci0_mem_base = base + alignto;
}
/*
* This entry is finished. Remove it from the list
* we'll scan.
*/
pci_devices[maxDevice].BARsize[maxBAR] = 0;
}
} while (maxSize);
}
static int __init pcibios_init(void)
{
u32 tmp;
struct pci_dev controller;
controller.devfn = SELF;
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, &controller);
tmp |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_SERR;
pci0WriteConfigReg(PCI_COMMAND, &controller, tmp);
/* This scans the PCI bus and sets up initial values. */
scan_and_initialize_pci();
/*
* Reset PCI I/O and PCI MEM values to ones supported by EVM.
*/
ioport_resource.start = GT_PCI_IO_BASE;
ioport_resource.end = GT_PCI_IO_BASE + GT_PCI_IO_SIZE - 1;
iomem_resource.start = GT_PCI_MEM_BASE;
iomem_resource.end = GT_PCI_MEM_BASE + GT_PCI_MEM_BASE - 1;
pci_scan_bus(0, &galileo_pci_ops, NULL);
return 0;
}
subsys_initcall(pcibios_init);
/*
* for parsing "pci=" kernel boot arguments.
*/
char *pcibios_setup(char *str)
{
printk(KERN_INFO "rr: pcibios_setup\n");
/* Nothing to do for now. */
return str;
}
unsigned __init int pcibios_assign_all_busses(void)
{
return 1;
}
/*
* 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);
}
}
/*
* PCI autoconfiguration library
*
* Author: Matt Porter <mporter@mvista.com>
*
* Copyright 2000, 2001, 2002, 2003 MontaVista Software Inc.
* Copyright 2001 Bradley D. LaRonde <brad@ltc.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.
*/
/*
* Modified for MIPS by Jun Sun, jsun@mvista.com
*
* . Simplify the interface between pci_auto and the rest: a single function.
* . Assign resources from low address to upper address.
* . change most int to u32.
*
* Further modified to include it as mips generic code, ppopov@mvista.com.
*
* 2001-10-26 Bradley D. LaRonde <brad@ltc.com>
* - Add a top_bus argument to the "early config" functions so that
* they can set a fake parent bus pointer to convince the underlying
* pci ops to use type 1 configuration for sub busses.
* - Set bridge base and limit registers correctly.
* - Align io and memory base properly before and after bridge setup.
* - Don't fall through to pci_setup_bars for bridge.
* - Reformat the debug output to look more like lspci's output.
*
* 2003-04-09 Yoichi Yuasa, Alice Hennessy, Jun Sun
* - Add cardbus bridge support, mostly copied from PPC
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <asm/pci_channel.h>
#define DEBUG
#ifdef DEBUG
#define DBG(x...) printk(x)
#else
#define DBG(x...)
#endif
/*
* These functions are used early on before PCI scanning is done
* and all of the pci_dev and pci_bus structures have been created.
*/
static struct pci_dev *fake_pci_dev(struct pci_channel *hose,
int top_bus, int busnr, int devfn)
{
static struct pci_dev dev;
static struct pci_bus bus;
dev.bus = &bus;
dev.sysdata = hose;
dev.devfn = devfn;
bus.number = busnr;
bus.ops = hose->pci_ops;
if (busnr != top_bus)
/* Fake a parent bus structure. */
bus.parent = &bus;
else
bus.parent = NULL;
return &dev;
}
#define EARLY_PCI_OP(rw, size, type) \
int early_##rw##_config_##size(struct pci_channel *hose, \
int top_bus, int bus, int devfn, int offset, type value) \
{ \
return pci_##rw##_config_##size( \
fake_pci_dev(hose, top_bus, bus, devfn), \
offset, value); \
}
EARLY_PCI_OP(read, byte, u8 *)
EARLY_PCI_OP(read, word, u16 *)
EARLY_PCI_OP(read, dword, u32 *)
EARLY_PCI_OP(write, byte, u8)
EARLY_PCI_OP(write, word, u16)
EARLY_PCI_OP(write, dword, u32)
static struct resource *io_resource_inuse;
static struct resource *mem_resource_inuse;
static u32 pciauto_lower_iospc;
static u32 pciauto_upper_iospc;
static u32 pciauto_lower_memspc;
static u32 pciauto_upper_memspc;
void __init
pciauto_setup_bars(struct pci_channel *hose,
int top_bus,
int current_bus, int pci_devfn, int bar_limit)
{
u32 bar_response, bar_size, bar_value;
u32 bar, addr_mask, bar_nr = 0;
u32 *upper_limit;
u32 *lower_limit;
int found_mem64 = 0;
for (bar = PCI_BASE_ADDRESS_0; bar <= bar_limit; bar += 4) {
/* Tickle the BAR and get the response */
early_write_config_dword(hose, top_bus,
current_bus,
pci_devfn, bar, 0xffffffff);
early_read_config_dword(hose, top_bus,
current_bus,
pci_devfn, bar, &bar_response);
/* If BAR is not implemented go to the next BAR */
if (!bar_response)
continue;
/*
* Workaround for a BAR that doesn't use its upper word,
* like the ALi 1535D+ PCI DC-97 Controller Modem (M5457).
* bdl <brad@ltc.com>
*/
if (!(bar_response & 0xffff0000))
bar_response |= 0xffff0000;
retry:
/* Check the BAR type and set our address mask */
if (bar_response & PCI_BASE_ADDRESS_SPACE) {
addr_mask = PCI_BASE_ADDRESS_IO_MASK;
upper_limit = &pciauto_upper_iospc;
lower_limit = &pciauto_lower_iospc;
DBG(" I/O");
} else {
if ((bar_response & PCI_BASE_ADDRESS_MEM_TYPE_MASK)
== PCI_BASE_ADDRESS_MEM_TYPE_64)
found_mem64 = 1;
addr_mask = PCI_BASE_ADDRESS_MEM_MASK;
upper_limit = &pciauto_upper_memspc;
lower_limit = &pciauto_lower_memspc;
DBG(" Mem");
}
/* Calculate requested size */
bar_size = ~(bar_response & addr_mask) + 1;
/* Allocate a base address */
bar_value =
((*lower_limit - 1) & ~(bar_size - 1)) + bar_size;
if ((bar_value + bar_size) > *upper_limit) {
if (bar_response & PCI_BASE_ADDRESS_SPACE) {
if (io_resource_inuse->child) {
io_resource_inuse =
io_resource_inuse->child;
pciauto_lower_iospc =
io_resource_inuse->start;
pciauto_upper_iospc =
io_resource_inuse->end + 1;
goto retry;
}
} else {
if (mem_resource_inuse->child) {
mem_resource_inuse =
mem_resource_inuse->child;
pciauto_lower_memspc =
mem_resource_inuse->start;
pciauto_upper_memspc =
mem_resource_inuse->end + 1;
goto retry;
}
}
DBG(" unavailable -- skipping\n");
continue;
}
/* Write it out and update our limit */
early_write_config_dword(hose, top_bus, current_bus,
pci_devfn, bar, bar_value);
*lower_limit = bar_value + bar_size;
/*
* If we are a 64-bit decoder then increment to the
* upper 32 bits of the bar and force it to locate
* in the lower 4GB of memory.
*/
if (found_mem64) {
bar += 4;
early_write_config_dword(hose, top_bus,
current_bus,
pci_devfn,
bar, 0x00000000);
}
DBG(" at 0x%.8x [size=0x%x]\n", bar_value, bar_size);
bar_nr++;
}
}
void __init
pciauto_prescan_setup_bridge(struct pci_channel *hose,
int top_bus,
int current_bus, int pci_devfn, int sub_bus)
{
/* Configure bus number registers */
early_write_config_byte(hose, top_bus, current_bus, pci_devfn,
PCI_PRIMARY_BUS, current_bus);
early_write_config_byte(hose, top_bus, current_bus, pci_devfn,
PCI_SECONDARY_BUS, sub_bus + 1);
early_write_config_byte(hose, top_bus, current_bus, pci_devfn,
PCI_SUBORDINATE_BUS, 0xff);
/* Align memory and I/O to 1MB and 4KB boundaries. */
pciauto_lower_memspc = (pciauto_lower_memspc + (0x100000 - 1))
& ~(0x100000 - 1);
pciauto_lower_iospc = (pciauto_lower_iospc + (0x1000 - 1))
& ~(0x1000 - 1);
/* Set base (lower limit) of address range behind bridge. */
early_write_config_word(hose, top_bus, current_bus, pci_devfn,
PCI_MEMORY_BASE,
pciauto_lower_memspc >> 16);
early_write_config_byte(hose, top_bus, current_bus, pci_devfn,
PCI_IO_BASE,
(pciauto_lower_iospc & 0x0000f000) >> 8);
early_write_config_word(hose, top_bus, current_bus, pci_devfn,
PCI_IO_BASE_UPPER16,
pciauto_lower_iospc >> 16);
/* We don't support prefetchable memory for now, so disable */
early_write_config_word(hose, top_bus, current_bus, pci_devfn,
PCI_PREF_MEMORY_BASE, 0);
early_write_config_word(hose, top_bus, current_bus, pci_devfn,
PCI_PREF_MEMORY_LIMIT, 0);
}
void __init
pciauto_postscan_setup_bridge(struct pci_channel *hose,
int top_bus,
int current_bus, int pci_devfn, int sub_bus)
{
u32 temp;
/*
* [jsun] we always bump up baselines a little, so that if there
* nothing behind P2P bridge, we don't wind up overlapping IO/MEM
* spaces.
*/
pciauto_lower_memspc += 1;
pciauto_lower_iospc += 1;
/* Configure bus number registers */
early_write_config_byte(hose, top_bus, current_bus, pci_devfn,
PCI_SUBORDINATE_BUS, sub_bus);
/* Set upper limit of address range behind bridge. */
early_write_config_word(hose, top_bus, current_bus, pci_devfn,
PCI_MEMORY_LIMIT,
pciauto_lower_memspc >> 16);
early_write_config_byte(hose, top_bus, current_bus, pci_devfn,
PCI_IO_LIMIT,
(pciauto_lower_iospc & 0x0000f000) >> 8);
early_write_config_word(hose, top_bus, current_bus, pci_devfn,
PCI_IO_LIMIT_UPPER16,
pciauto_lower_iospc >> 16);
/* Align memory and I/O to 1MB and 4KB boundaries. */
pciauto_lower_memspc = (pciauto_lower_memspc + (0x100000 - 1))
& ~(0x100000 - 1);
pciauto_lower_iospc = (pciauto_lower_iospc + (0x1000 - 1))
& ~(0x1000 - 1);
/* Enable memory and I/O accesses, enable bus master */
early_read_config_dword(hose, top_bus, current_bus, pci_devfn,
PCI_COMMAND, &temp);
early_write_config_dword(hose, top_bus, current_bus, pci_devfn,
PCI_COMMAND,
temp | PCI_COMMAND_IO | PCI_COMMAND_MEMORY
| PCI_COMMAND_MASTER);
}
void __init
pciauto_prescan_setup_cardbus_bridge(struct pci_channel *hose,
int top_bus,
int current_bus,
int pci_devfn, int sub_bus)
{
/* Configure bus number registers */
early_write_config_byte(hose, top_bus, current_bus, pci_devfn,
PCI_PRIMARY_BUS, current_bus);
early_write_config_byte(hose, top_bus, current_bus, pci_devfn,
PCI_SECONDARY_BUS, sub_bus + 1);
early_write_config_byte(hose, top_bus, current_bus, pci_devfn,
PCI_SUBORDINATE_BUS, 0xff);
/* Align memory and I/O to 4KB and 4 byte boundaries. */
pciauto_lower_memspc = (pciauto_lower_memspc + (0x1000 - 1))
& ~(0x1000 - 1);
pciauto_lower_iospc = (pciauto_lower_iospc + (0x4 - 1))
& ~(0x4 - 1);
early_write_config_dword(hose, top_bus, current_bus, pci_devfn,
PCI_CB_MEMORY_BASE_0,
pciauto_lower_memspc);
early_write_config_dword(hose, top_bus, current_bus, pci_devfn,
PCI_CB_IO_BASE_0, pciauto_lower_iospc);
}
void __init
pciauto_postscan_setup_cardbus_bridge(struct pci_channel *hose,
int top_bus,
int current_bus,
int pci_devfn, int sub_bus)
{
u32 temp;
/*
* Configure subordinate bus number. The PCI subsystem
* bus scan will renumber buses (reserving three additional
* for this PCI<->CardBus bridge for the case where a CardBus
* adapter contains a P2P or CB2CB bridge.
*/
early_write_config_byte(hose, top_bus, current_bus, pci_devfn,
PCI_SUBORDINATE_BUS, sub_bus);
/*
* Reserve an additional 4MB for mem space and 16KB for
* I/O space. This should cover any additional space
* requirement of unusual CardBus devices with
* additional bridges that can consume more address space.
*
* Although pcmcia-cs currently will reprogram bridge
* windows, the goal is to add an option to leave them
* alone and use the bridge window ranges as the regions
* that are searched for free resources upon hot-insertion
* of a device. This will allow a PCI<->CardBus bridge
* configured by this routine to happily live behind a
* P2P bridge in a system.
*/
pciauto_lower_memspc += 0x00400000;
pciauto_lower_iospc += 0x00004000;
/* Align memory and I/O to 4KB and 4 byte boundaries. */
pciauto_lower_memspc = (pciauto_lower_memspc + (0x1000 - 1))
& ~(0x1000 - 1);
pciauto_lower_iospc = (pciauto_lower_iospc + (0x4 - 1))
& ~(0x4 - 1);
/* Set up memory and I/O filter limits, assume 32-bit I/O space */
early_write_config_dword(hose, top_bus, current_bus, pci_devfn,
PCI_CB_MEMORY_LIMIT_0,
pciauto_lower_memspc - 1);
early_write_config_dword(hose, top_bus, current_bus, pci_devfn,
PCI_CB_IO_LIMIT_0,
pciauto_lower_iospc - 1);
/* Enable memory and I/O accesses, enable bus master */
early_read_config_dword(hose, top_bus, current_bus, pci_devfn,
PCI_COMMAND, &temp);
early_write_config_dword(hose, top_bus, current_bus, pci_devfn,
PCI_COMMAND,
temp | PCI_COMMAND_IO | PCI_COMMAND_MEMORY
| PCI_COMMAND_MASTER);
}
#define PCIAUTO_IDE_MODE_MASK 0x05
int __init
pciauto_bus_scan(struct pci_channel *hose, int top_bus, int current_bus)
{
int sub_bus;
u32 pci_devfn, pci_class, cmdstat, found_multi = 0;
unsigned short vid, did;
unsigned char header_type;
int devfn_start = 0;
int devfn_stop = 0xff;
sub_bus = current_bus;
if (hose->first_devfn)
devfn_start = hose->first_devfn;
if (hose->last_devfn)
devfn_stop = hose->last_devfn;
for (pci_devfn = devfn_start; pci_devfn < devfn_stop; pci_devfn++) {
if (PCI_FUNC(pci_devfn) && !found_multi)
continue;
early_read_config_word(hose, top_bus, current_bus,
pci_devfn, PCI_VENDOR_ID, &vid);
if (vid == 0xffff)
continue;
early_read_config_byte(hose, top_bus, current_bus,
pci_devfn, PCI_HEADER_TYPE,
&header_type);
if (!PCI_FUNC(pci_devfn))
found_multi = header_type & 0x80;
early_read_config_word(hose, top_bus, current_bus,
pci_devfn, PCI_DEVICE_ID, &did);
early_read_config_dword(hose, top_bus, current_bus,
pci_devfn, PCI_CLASS_REVISION,
&pci_class);
DBG("%.2x:%.2x.%x Class %.4x: %.4x:%.4x",
current_bus, PCI_SLOT(pci_devfn), PCI_FUNC(pci_devfn),
pci_class >> 16, vid, did);
if (pci_class & 0xff)
DBG(" (rev %.2x)", pci_class & 0xff);
DBG("\n");
if ((pci_class >> 16) == PCI_CLASS_BRIDGE_PCI) {
DBG(" Bridge: primary=%.2x, secondary=%.2x\n", current_bus, sub_bus + 1);
pciauto_setup_bars(hose, top_bus, current_bus,
pci_devfn, PCI_BASE_ADDRESS_1);
pciauto_prescan_setup_bridge(hose, top_bus,
current_bus,
pci_devfn, sub_bus);
DBG("Scanning sub bus %.2x, I/O 0x%.8x, Mem 0x%.8x\n", sub_bus + 1, pciauto_lower_iospc, pciauto_lower_memspc);
sub_bus =
pciauto_bus_scan(hose, top_bus, sub_bus + 1);
DBG("Back to bus %.2x\n", current_bus);
pciauto_postscan_setup_bridge(hose, top_bus,
current_bus,
pci_devfn, sub_bus);
continue;
} else if ((pci_class >> 16) == PCI_CLASS_BRIDGE_CARDBUS) {
DBG(" CARDBUS Bridge: primary=%.2x, secondary=%.2x\n", current_bus, sub_bus + 1);
DBG("PCI Autoconfig: Found CardBus bridge, device %d function %d\n", PCI_SLOT(pci_devfn), PCI_FUNC(pci_devfn));
/* Place CardBus Socket/ExCA registers */
pciauto_setup_bars(hose, top_bus, current_bus,
pci_devfn, PCI_BASE_ADDRESS_0);
pciauto_prescan_setup_cardbus_bridge(hose, top_bus,
current_bus,
pci_devfn,
sub_bus);
DBG("Scanning sub bus %.2x, I/O 0x%.8x, Mem 0x%.8x\n", sub_bus + 1, pciauto_lower_iospc, pciauto_lower_memspc);
sub_bus =
pciauto_bus_scan(hose, top_bus, sub_bus + 1);
DBG("Back to bus %.2x, sub_bus is %x\n",
current_bus, sub_bus);
pciauto_postscan_setup_cardbus_bridge(hose,
top_bus,
current_bus,
pci_devfn,
sub_bus);
continue;
} else if ((pci_class >> 16) == PCI_CLASS_STORAGE_IDE) {
unsigned char prg_iface;
early_read_config_byte(hose, top_bus, current_bus,
pci_devfn, PCI_CLASS_PROG,
&prg_iface);
if (!(prg_iface & PCIAUTO_IDE_MODE_MASK)) {
DBG("Skipping legacy mode IDE controller\n");
continue;
}
}
/*
* Found a peripheral, enable some standard
* settings
*/
early_read_config_dword(hose, top_bus, current_bus,
pci_devfn, PCI_COMMAND, &cmdstat);
early_write_config_dword(hose, top_bus, current_bus,
pci_devfn, PCI_COMMAND,
cmdstat | PCI_COMMAND_IO |
PCI_COMMAND_MEMORY |
PCI_COMMAND_MASTER);
early_write_config_byte(hose, top_bus, current_bus,
pci_devfn, PCI_LATENCY_TIMER,
0x80);
/* Allocate PCI I/O and/or memory space */
pciauto_setup_bars(hose, top_bus, current_bus, pci_devfn,
PCI_BASE_ADDRESS_5);
}
return sub_bus;
}
int __init pciauto_assign_resources(int busno, struct pci_channel *hose)
{
/* setup resource limits */
io_resource_inuse = hose->io_resource;
mem_resource_inuse = hose->mem_resource;
pciauto_lower_iospc = io_resource_inuse->start;
pciauto_upper_iospc = io_resource_inuse->end + 1;
pciauto_lower_memspc = mem_resource_inuse->start;
pciauto_upper_memspc = mem_resource_inuse->end + 1;
DBG("Autoconfig PCI channel 0x%p\n", hose);
DBG("Scanning bus %.2x, I/O 0x%.8x:0x%.8x, Mem 0x%.8x:0x%.8x\n",
busno, pciauto_lower_iospc, pciauto_upper_iospc,
pciauto_lower_memspc, pciauto_upper_memspc);
return pciauto_bus_scan(hose, busno, busno);
}
/*
* 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 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>
int cobalt_board_id;
static void qube_expansion_slot_bist(struct pci_dev *dev)
{
unsigned char ctrl;
int timeout = 100000;
pci_read_config_byte(dev, PCI_BIST, &ctrl);
if (!(ctrl & PCI_BIST_CAPABLE))
return;
pci_write_config_byte(dev, PCI_BIST, ctrl | PCI_BIST_START);
do {
pci_read_config_byte(dev, PCI_BIST, &ctrl);
if (!(ctrl & PCI_BIST_START))
break;
} while (--timeout > 0);
if ((timeout <= 0) || (ctrl & PCI_BIST_CODE_MASK))
printk
("PCI: Expansion slot card failed BIST with code %x\n",
(ctrl & PCI_BIST_CODE_MASK));
}
static void qube_expansion_slot_fixup(struct pci_dev *dev)
{
unsigned short pci_cmd;
unsigned long ioaddr_base = 0x10108000; /* It's magic, ask Doug. */
unsigned long memaddr_base = 0x12001000;
int i;
/* Enable bits in COMMAND so driver can talk to it. */
pci_read_config_word(dev, PCI_COMMAND, &pci_cmd);
pci_cmd |=
(PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
pci_write_config_word(dev, PCI_COMMAND, pci_cmd);
/* Give it a working IRQ. */
pci_write_config_byte(dev, PCI_INTERRUPT_LINE,
COBALT_QUBE_SLOT_IRQ);
dev->irq = COBALT_QUBE_SLOT_IRQ;
ioaddr_base += 0x2000 * PCI_FUNC(dev->devfn);
memaddr_base += 0x2000 * PCI_FUNC(dev->devfn);
/* Fixup base addresses, we only support I/O at the moment. */
for (i = 0; i <= 5; i++) {
unsigned int regaddr = (PCI_BASE_ADDRESS_0 + (i * 4));
unsigned int rval, mask, size, alignme, aspace;
unsigned long *basep = &ioaddr_base;
/* Check type first, punt if non-IO. */
pci_read_config_dword(dev, regaddr, &rval);
aspace = (rval & PCI_BASE_ADDRESS_SPACE);
if (aspace != PCI_BASE_ADDRESS_SPACE_IO)
basep = &memaddr_base;
/* Figure out how much it wants, if anything. */
pci_write_config_dword(dev, regaddr, 0xffffffff);
pci_read_config_dword(dev, regaddr, &rval);
/* Unused? */
if (rval == 0)
continue;
rval &= PCI_BASE_ADDRESS_IO_MASK;
mask = (~rval << 1) | 0x1;
size = (mask & rval) & 0xffffffff;
alignme = size;
if (alignme < 0x400)
alignme = 0x400;
rval = ((*basep + (alignme - 1)) & ~(alignme - 1));
*basep = (rval + size);
pci_write_config_dword(dev, regaddr, rval | aspace);
dev->resource[i].start = rval;
dev->resource[i].end = *basep - 1;
if (aspace == PCI_BASE_ADDRESS_SPACE_IO) {
dev->resource[i].start -= 0x10000000;
dev->resource[i].end -= 0x10000000;
}
}
qube_expansion_slot_bist(dev);
}
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);
}
static void qube_raq_tulip_fixup(struct pci_dev *dev)
{
unsigned short pci_cmd;
/* Fixup the first tulip located at device PCICONF_ETH0 */
if (PCI_SLOT(dev->devfn) == COBALT_PCICONF_ETH0) {
/* Setup the first Tulip */
pci_write_config_byte(dev, PCI_INTERRUPT_LINE,
COBALT_ETH0_IRQ);
dev->irq = COBALT_ETH0_IRQ;
dev->resource[0].start = 0x100000;
dev->resource[0].end = 0x10007f;
dev->resource[1].start = 0x12000000;
dev->resource[1].end = dev->resource[1].start + 0x3ff;
pci_write_config_dword(dev, PCI_BASE_ADDRESS_1,
dev->resource[1].start);
/* Fixup the second tulip located at device PCICONF_ETH1 */
} else if (PCI_SLOT(dev->devfn) == COBALT_PCICONF_ETH1) {
/* Enable the second Tulip device. */
pci_read_config_word(dev, PCI_COMMAND, &pci_cmd);
pci_cmd |= (PCI_COMMAND_IO | PCI_COMMAND_MASTER);
pci_write_config_word(dev, PCI_COMMAND, pci_cmd);
/* Give it it's IRQ. */
pci_write_config_byte(dev, PCI_INTERRUPT_LINE,
COBALT_ETH1_IRQ);
dev->irq = COBALT_ETH1_IRQ;
/* And finally, a usable I/O space allocation, right after what
* the first Tulip uses.
*/
dev->resource[0].start = 0x101000;
dev->resource[0].end = 0x10107f;
dev->resource[1].start = 0x12000400;
dev->resource[1].end = dev->resource[1].start + 0x3ff;
pci_write_config_dword(dev, PCI_BASE_ADDRESS_1,
dev->resource[1].start);
}
}
static void qube_raq_scsi_fixup(struct pci_dev *dev)
{
unsigned short pci_cmd;
/*
* Tell the SCSI device that we expect an interrupt at
* IRQ 7 and not the default 0.
*/
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, COBALT_SCSI_IRQ);
dev->irq = COBALT_SCSI_IRQ;
if (cobalt_board_id == COBALT_BRD_ID_RAQ2) {
/* Enable the device. */
pci_read_config_word(dev, PCI_COMMAND, &pci_cmd);
pci_cmd |=
(PCI_COMMAND_IO | PCI_COMMAND_MASTER |
PCI_COMMAND_MEMORY | PCI_COMMAND_INVALIDATE);
pci_write_config_word(dev, PCI_COMMAND, pci_cmd);
/* Give it it's RAQ IRQ. */
pci_write_config_byte(dev, PCI_INTERRUPT_LINE,
COBALT_RAQ_SCSI_IRQ);
dev->irq = COBALT_RAQ_SCSI_IRQ;
/* And finally, a usable I/O space allocation, right after what
* the second Tulip uses.
*/
dev->resource[0].start = 0x102000;
dev->resource[0].end = dev->resource[0].start + 0xff;
pci_write_config_dword(dev, PCI_BASE_ADDRESS_0,
0x10102000);
pci_write_config_dword(dev, PCI_BASE_ADDRESS_1,
0x00002000);
pci_write_config_dword(dev, PCI_BASE_ADDRESS_2,
0x00100000);
}
}
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);
}
}
static void qube_pcibios_fixup(struct pci_dev *dev)
{
if (PCI_SLOT(dev->devfn) == COBALT_PCICONF_PCISLOT) {
unsigned int tmp;
/* See if there is a device in the expansion slot, if so
* discover its resources and fixup whatever we need to
*/
pci_read_config_dword(dev, PCI_VENDOR_ID, &tmp);
if (tmp != 0xffffffff && tmp != 0x00000000)
qube_expansion_slot_fixup(dev);
}
}
struct pci_fixup pcibios_fixups[] = {
{PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1,
qube_raq_via_bmIDE_fixup},
{PCI_FIXUP_HEADER, PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21142,
qube_raq_tulip_fixup},
{PCI_FIXUP_HEADER, PCI_VENDOR_ID_GALILEO, PCI_ANY_ID,
qube_raq_galileo_fixup},
{PCI_FIXUP_HEADER, PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C860,
qube_raq_scsi_fixup},
{PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, qube_pcibios_fixup}
};
static inline int pci_range_ck(struct pci_bus *bus, unsigned int devfn)
{
if ((bus->number == 0)
&& ((PCI_SLOT(devfn) == 0)
|| ((PCI_SLOT(devfn) > 6)
&& (PCI_SLOT(devfn) <= 12))))
return 0; /* OK device number */
return -1; /* NOT ok device number */
}
#define PCI_CFG_SET(devfn,where) \
GALILEO_OUTL((0x80000000 | (PCI_SLOT (devfn) << 11) | \
(PCI_FUNC (devfn) << 8) | (where)), \
GT_PCI0_CFGADDR_OFS)
static int qube_pci_read_config(struct pci_bus *bus, unsigned int devfn,
int where, int size, u32 * val)
{
switch (size) {
case 4:
if (where & 0x3)
return PCIBIOS_BAD_REGISTER_NUMBER;
if (pci_range_ck(bus, devfn)) {
*val = 0xFFFFFFFF;
return PCIBIOS_DEVICE_NOT_FOUND;
}
PCI_CFG_SET(devfn, where);
*val = GALILEO_INL(GT_PCI0_CFGDATA_OFS);
return PCIBIOS_SUCCESSFUL;
case 2:
if (where & 0x1)
return PCIBIOS_BAD_REGISTER_NUMBER;
if (pci_range_ck(bus, devfn)) {
*val = 0xffff;
return PCIBIOS_DEVICE_NOT_FOUND;
}
PCI_CFG_SET(devfn, (where & ~0x3));
*val = GALILEO_INL(GT_PCI0_CFGDATA_OFS)
>> ((where & 3) * 8);
return PCIBIOS_SUCCESSFUL;
case 1:
if (pci_range_ck(bus, devfn)) {
*val = 0xff;
return PCIBIOS_DEVICE_NOT_FOUND;
}
PCI_CFG_SET(devfn, (where & ~0x3));
*val = GALILEO_INL(GT_PCI0_CFGDATA_OFS)
>> ((where & 3) * 8);
return PCIBIOS_SUCCESSFUL;
}
}
static int qube_pci_write_config(struct pci_bus *bus, unsigned int devfn,
int where, int size, u32 val)
{
u32 tmp;
switch (size) {
case 4:
if (where & 0x3)
return PCIBIOS_BAD_REGISTER_NUMBER;
if (pci_range_ck(bus, devfn))
return PCIBIOS_DEVICE_NOT_FOUND;
PCI_CFG_SET(devfn, where);
GALILEO_OUTL(val, GT_PCI0_CFGDATA_OFS);
return PCIBIOS_SUCCESSFUL;
case 2:
if (where & 0x1)
return PCIBIOS_BAD_REGISTER_NUMBER;
if (pci_range_ck(bus, devfn))
return PCIBIOS_DEVICE_NOT_FOUND;
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:
if (pci_range_ck(bus, devfn))
return PCIBIOS_DEVICE_NOT_FOUND;
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;
}
}
struct pci_ops qube_pci_ops = {
.read = qube_pci_read_config,
.write = qube_pci_write_config,
};
static int __init pcibios_init(void)
{
unsigned int devfn = PCI_DEVFN(COBALT_PCICONF_VIA, 0);
printk("PCI: Probing PCI hardware\n");
/* Read the cobalt id register out of the PCI config space */
PCI_CFG_SET(devfn, (VIA_COBALT_BRD_ID_REG & ~0x3));
cobalt_board_id = GALILEO_INL(GT_PCI0_CFGDATA_OFS)
>> ((VIA_COBALT_BRD_ID_REG & 3) * 8);
cobalt_board_id = VIA_COBALT_BRD_REG_to_ID(cobalt_board_id);
printk("Cobalt Board ID: %d\n", cobalt_board_id);
ioport_resource.start = 0x00000000;
ioport_resource.end = 0x0fffffff;
iomem_resource.start = 0x01000000;
iomem_resource.end = 0xffffffff;
pci_scan_bus(0, &qube_pci_ops, NULL);
return 0;
}
subsys_initcall(pcibios_init);
char *pcibios_setup(char *str)
{
return str;
}
int pcibios_enable_device(struct pci_dev *dev, int mask)
{
u16 cmd, status;
pci_read_config_word(dev, PCI_COMMAND, &cmd);
pci_read_config_word(dev, PCI_STATUS, &status);
printk("PCI: Enabling device %s (%04x %04x)\n", dev->slot_name,
cmd, status);
/* We'll sort this out when we know it isn't enabled ;) */
return 0;
}
void pcibios_align_resource(void *data, struct resource *res,
unsigned long size, unsigned long align)
{
panic("Uhhoh called pcibios_align_resource\n");
}
void __devinit pcibios_fixup_bus(struct pci_bus *bus)
{
/* We don't have sub-busses to fixup here */
}
unsigned int __init pcibios_assign_all_busses(void)
{
return 1;
}
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <asm/pci_channel.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_channel mips_pci_channels[] = {
{&ddb5476_ext_pci_ops, &extpci_io_resource, &extpci_mem_resource},
{NULL, NULL, NULL}
};
#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] = {
/* SLOT: 0 */ nile4_to_irq(PCI_EXT_INTE),
/* SLOT: 1 */ nile4_to_irq(PCI_EXT_INTA),
/* SLOT: 2 */ nile4_to_irq(PCI_EXT_INTA),
/* SLOT: 3 */ nile4_to_irq(PCI_EXT_INTB),
/* SLOT: 4 */ nile4_to_irq(PCI_EXT_INTC),
/* SLOT: 5 */ nile4_to_irq(NILE4_INT_UART),
/* SLOT: 6 */ 0xff,
/* SLOT: 7 */ 0xff,
/* SLOT: 8 */ 0xff,
/* SLOT: 9 */ 0xff,
/* SLOT: 10 */ nile4_to_irq(PCI_EXT_INTE),
/* SLOT: 11 */ 0xff,
/* SLOT: 12 */ 0xff,
/* SLOT: 13 */ nile4_to_irq(PCI_EXT_INTE),
};
void __init pcibios_fixup_irqs(void)
{
struct pci_dev *dev = NULL;
int slot_num;
while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
slot_num = PCI_SLOT(dev->devfn);
db_assert(slot_num < MAX_SLOT_NUM);
printk("irq_map[%d]: %02x\n", slot_num, irq_map[slot_num]);
db_assert(irq_map[slot_num] != 0xff);
pci_write_config_byte(dev,
PCI_INTERRUPT_LINE,
irq_map[slot_num]);
dev->irq = irq_map[slot_num];
}
}
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);
}
unsigned __init int pcibios_assign_all_busses(void)
{
/* we hope pci_auto has assigned the bus numbers to all buses */
return 1;
}
void __init pcibios_fixup_resources(struct pci_dev *dev)
{
}
void __init pcibios_fixup(void)
{
struct pci_dev *dev = NULL;
while ((dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101,
dev)) != NULL) {
/*
* It's nice to have the LEDs on the GPIO pins
* available for debugging
*/
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);
}
}
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <asm/pci_channel.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_channel mips_pci_channels[] = {
{&ddb5476_ext_pci_ops, &extpci_io_resource, &extpci_mem_resource},
{NULL, NULL, NULL}
};
/*
* 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] = {
/* SLOT: 0, AD:11 */ 0xff,
/* SLOT: 1, AD:12 */ 0xff,
/* SLOT: 2, AD:13 */ 9,
/* USB */
/* SLOT: 3, AD:14 */ 10,
/* PMU */
/* SLOT: 4, AD:15 */ 0xff,
/* SLOT: 5, AD:16 */ 0x0,
/* P2P bridge */
/* SLOT: 6, AD:17 */ nile4_to_irq(PCI_EXT_INTB),
/* SLOT: 7, AD:18 */ nile4_to_irq(PCI_EXT_INTC),
/* SLOT: 8, AD:19 */ nile4_to_irq(PCI_EXT_INTD),
/* SLOT: 9, AD:20 */ nile4_to_irq(PCI_EXT_INTA),
/* SLOT: 10, AD:21 */ 0xff,
/* SLOT: 11, AD:22 */ 0xff,
/* SLOT: 12, AD:23 */ 0xff,
/* SLOT: 13, AD:24 */ 14,
/* HD controller, M5229 */
/* SLOT: 14, AD:25 */ 0xff,
/* SLOT: 15, AD:26 */ 0xff,
/* SLOT: 16, AD:27 */ 0xff,
/* SLOT: 17, AD:28 */ 0xff,
/* SLOT: 18, AD:29 */ 0xff,
/* SLOT: 19, AD:30 */ 0xff,
/* SLOT: 20, AD:31 */ 0xff
};
extern int vrc5477_irq_to_irq(int irq);
void __init pcibios_fixup_irqs(void)
{
struct pci_dev *dev = NULL;
int slot_num;
while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
slot_num = PCI_SLOT(dev->devfn);
/* we don't do IRQ fixup for sub-bus yet */
if (dev->bus->parent != NULL) {
db_run(printk
("Don't know how to fixup irq for PCI device %d on sub-bus %d\n",
slot_num, dev->bus->number));
continue;
}
db_assert(slot_num < MAX_SLOT_NUM);
db_assert(irq_map[slot_num] != 0xff);
pci_write_config_byte(dev,
PCI_INTERRUPT_LINE,
irq_map[slot_num]);
dev->irq = irq_map[slot_num];
}
}
#if defined(CONFIG_RUNTIME_DEBUG)
extern void jsun_scan_pci_bus(void);
#endif
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);
}
unsigned __init int pcibios_assign_all_busses(void)
{
/* we hope pci_auto has assigned the bus numbers to all buses */
return 1;
}
void __init pcibios_fixup_resources(struct pci_dev *dev)
{
}
void __init pcibios_fixup(void)
{
}
/*
* PCI code for DDB5477.
*
* Copyright (C) 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.
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <asm/bootinfo.h>
#include <asm/pci_channel.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_channel mips_pci_channels[] = {
{&ddb5477_ext_pci_ops, &extpci_io_resource, &extpci_mem_resource},
{&ddb5477_io_pci_ops, &iopci_io_resource, &iopci_mem_resource},
{NULL, NULL, NULL}
};
/*
* 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 */
};
void __init pcibios_fixup_irqs(void)
{
struct pci_dev *dev = NULL;
int slot_num;
unsigned char *slot_irq_map;
unsigned char irq;
if (mips_machtype == MACH_NEC_ROCKHOPPERII)
slot_irq_map = rockhopperII_irq_map;
else
slot_irq_map = irq_map;
while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
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);
dev->irq = 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);
dev->irq = 9;
}
}
}
}
#if defined(CONFIG_RUNTIME_DEBUG)
extern void jsun_scan_pci_bus(void);
extern void jsun_assign_pci_resource(void);
#endif
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);
}
unsigned __init int pcibios_assign_all_busses(void)
{
/* we hope pci_auto has assigned the bus numbers to all buses */
return 1;
}
void __init pcibios_fixup_resources(struct pci_dev *dev)
{
}
/*
* 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
void __init fix_amd_lance(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);
}
void __init pcibios_fixup(void)
{
struct pci_dev *dev = NULL;
if (mips_machtype != MACH_NEC_ROCKHOPPERII)
return;
#define M1535_CONFIG_PORT 0x3f0
#define M1535_INDEX_PORT 0x3f0
#define M1535_DATA_PORT 0x3f1
printk("Configuring ALI M1535 Super I/O mouse irq.\n");
request_region(M1535_CONFIG_PORT, 2, "M1535 Super I/O config");
/* Enter config mode. */
outb(0x51, M1535_CONFIG_PORT);
outb(0x23, M1535_CONFIG_PORT);
/* Select device 0x07. */
outb(0x07, M1535_INDEX_PORT);
outb(0x07, M1535_DATA_PORT);
/* Set mouse irq (register 0x72) to 12. */
outb(0x72, M1535_INDEX_PORT);
outb(0x0c, M1535_DATA_PORT);
/* Exit config mode. */
outb(0xbb, M1535_CONFIG_PORT);
while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
if (dev->vendor == PCI_VENDOR_ID_AL)
if (dev->device == PCI_DEVICE_ID_AL_M1535
|| dev->device == PCI_DEVICE_ID_AL_M1533) {
u8 old;
printk
("Enabling ALI M1533/35 PS2 keyboard/mouse.\n");
pci_read_config_byte(dev, 0x41, &old);
pci_write_config_byte(dev, 0x41, old | 0xd0);
}
if (dev->vendor == PCI_VENDOR_ID_AMD &&
dev->device == PCI_DEVICE_ID_AMD_LANCE)
fix_amd_lance(dev);
}
}
/*
* 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 Ralf Baechle
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/types.h>
#include <asm/byteorder.h>
#include <asm/pci_channel.h>
#include <asm/hp-lj/asic.h>
volatile u32 *pci_config_address_reg = (volatile u32 *) 0xfdead000;
volatile u32 *pci_config_data_reg = (volatile u32 *) 0xfdead000;
#define cfgaddr(dev, where) (((dev->bus->number & 0xff) << 0x10) | \
((dev->devfn & 0xff) << 0x08) | \
(where & 0xfc))
/*
* 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 pcimt_read_config_byte(struct pci_dev *dev,
int where, unsigned char *val)
{
*pci_config_address_reg = cfgaddr(dev, where);
*val =
(le32_to_cpu(*pci_config_data_reg) >> ((where & 3) << 3)) &
0xff;
//printk("pci_read_byte 0x%x == 0x%x\n", where, *val);
return PCIBIOS_SUCCESSFUL;
}
static int pcimt_read_config_word(struct pci_dev *dev,
int where, unsigned short *val)
{
if (where & 1)
return PCIBIOS_BAD_REGISTER_NUMBER;
*pci_config_address_reg = cfgaddr(dev, where);
*val =
(le32_to_cpu(*pci_config_data_reg) >> ((where & 3) << 3)) &
0xffff;
//printk("pci_read_word 0x%x == 0x%x\n", where, *val);
return PCIBIOS_SUCCESSFUL;
}
int pcimt_read_config_dword(struct pci_dev *dev,
int where, unsigned int *val)
{
if (where & 3)
return PCIBIOS_BAD_REGISTER_NUMBER;
*pci_config_address_reg = cfgaddr(dev, where);
*val = le32_to_cpu(*pci_config_data_reg);
//printk("pci_read_dword 0x%x == 0x%x\n", where, *val);
return PCIBIOS_SUCCESSFUL;
}
static int pcimt_write_config_byte(struct pci_dev *dev,
int where, unsigned char val)
{
*pci_config_address_reg = cfgaddr(dev, where);
*(volatile u8 *) (((int) pci_config_data_reg) + (where & 3)) = val;
//printk("pci_write_byte 0x%x = 0x%x\n", where, val);
return PCIBIOS_SUCCESSFUL;
}
static int pcimt_write_config_word(struct pci_dev *dev,
int where, unsigned short val)
{
if (where & 1)
return PCIBIOS_BAD_REGISTER_NUMBER;
*pci_config_address_reg = cfgaddr(dev, where);
*(volatile u16 *) (((int) pci_config_data_reg) + (where & 2)) =
le16_to_cpu(val);
//printk("pci_write_word 0x%x = 0x%x\n", where, val);
return PCIBIOS_SUCCESSFUL;
}
int pcimt_write_config_dword(struct pci_dev *dev,
int where, unsigned int val)
{
if (where & 3)
return PCIBIOS_BAD_REGISTER_NUMBER;
*pci_config_address_reg = cfgaddr(dev, where);
*pci_config_data_reg = le32_to_cpu(val);
//printk("pci_write_dword 0x%x = 0x%x\n", where, val);
return PCIBIOS_SUCCESSFUL;
}
struct pci_ops hp_pci_ops = {
pcimt_read_config_byte,
pcimt_read_config_word,
pcimt_read_config_dword,
pcimt_write_config_byte,
pcimt_write_config_word,
pcimt_write_config_dword
};
struct pci_channel mips_pci_channels[] = {
{&hp_pci_ops, &ioport_resource, &iomem_resource},
{NULL, NULL, NULL}
};
unsigned __init int pcibios_assign_all_busses(void)
{
return 1;
}
void __init pcibios_fixup(void)
{
}
void __init pcibios_fixup_irqs(void)
{
struct pci_dev *dev = NULL;
int slot_num;
while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
slot_num = PCI_SLOT(dev->devfn);
switch (slot_num) {
case 2:
dev->irq = 3;
break;
case 3:
dev->irq = 4;
break;
case 4:
dev->irq = 5;
break;
default:
break;
}
}
}
#define IO_MEM_LOGICAL_START 0x3e000000
#define IO_MEM_LOGICAL_END 0x3fefffff
#define IO_PORT_LOGICAL_START 0x3ff00000
#define IO_PORT_LOGICAL_END 0x3fffffff
#define IO_MEM_VIRTUAL_OFFSET 0xb0000000
#define IO_PORT_VIRTUAL_OFFSET 0xb0000000
#define ONE_MEG (1024 * 1024)
void __init pci_setup(void)
{
u32 pci_regs_base_offset = 0xfdead000;
switch (GetAsicId()) {
case AndrosAsic:
pci_regs_base_offset = 0xbff80000;
break;
case HarmonyAsic:
pci_regs_base_offset = 0xbff70000;
break;
default:
printk("ERROR: PCI does not support %s Asic\n",
GetAsicName());
while (1);
break;
}
// set bus stat/command reg
// REVIST this setting may need vary depending on the hardware
*((volatile unsigned int *) (pci_regs_base_offset | 0x0004)) =
0x38000007;
iomem_resource.start =
IO_MEM_LOGICAL_START + IO_MEM_VIRTUAL_OFFSET;
iomem_resource.end = IO_MEM_LOGICAL_END + IO_MEM_VIRTUAL_OFFSET;
ioport_resource.start =
IO_PORT_LOGICAL_START + IO_PORT_VIRTUAL_OFFSET;
ioport_resource.end = IO_PORT_LOGICAL_END + IO_PORT_VIRTUAL_OFFSET;
// KLUDGE (mips_io_port_base is screwed up, we've got to work around it here)
// by letting both low (illegal) and high (legal) addresses appear in pci io space
ioport_resource.start = 0x0;
set_io_port_base(IO_PORT_LOGICAL_START + IO_PORT_VIRTUAL_OFFSET);
// map the PCI address space
// global map - all levels & processes can access
// except that the range is outside user space
// parameters: lo0, lo1, hi, pagemask
// lo indicates physical page, hi indicates virtual address
add_wired_entry((IO_MEM_LOGICAL_START >> 6) | 0x17,
((IO_MEM_LOGICAL_START +
(16 * ONE_MEG)) >> 6) | 0x17, 0xee000000,
PM_16M);
// These are used in pci r/w routines so need to preceed bus scan
pci_config_data_reg = (u32 *) (((u32) mips_io_port_base) | 0xcfc);
pci_config_address_reg =
(u32 *) (((u32) pci_regs_base_offset) | 0xcf8);
}
void __init pcibios_fixup_resources(struct pci_dev *dev)
{
int pos;
int bases;
printk("adjusting pci device: %s\n", dev->name);
switch (dev->hdr_type) {
case PCI_HEADER_TYPE_NORMAL:
bases = 6;
break;
case PCI_HEADER_TYPE_BRIDGE:
bases = 2;
break;
case PCI_HEADER_TYPE_CARDBUS:
bases = 1;
break;
default:
bases = 0;
break;
}
for (pos = 0; pos < bases; pos++) {
struct resource *res = &dev->resource[pos];
if (res->start >= IO_MEM_LOGICAL_START &&
res->end <= IO_MEM_LOGICAL_END) {
res->start += IO_MEM_VIRTUAL_OFFSET;
res->end += IO_MEM_VIRTUAL_OFFSET;
}
if (res->start >= IO_PORT_LOGICAL_START &&
res->end <= IO_PORT_LOGICAL_END) {
res->start += IO_PORT_VIRTUAL_OFFSET;
res->end += IO_PORT_VIRTUAL_OFFSET;
}
}
}
/*
* 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) 1999, 2000 Ralf Baechle (ralf@gnu.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/sn0/ip27.h>
#include <asm/sn/sn0/hub.h>
/*
* 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
/*
* No locking needed until PCI initialization is done parallely.
*/
int irqstore[MAX_PCI_BUSSES][MAX_DEVICES_PER_PCIBUS];
int lastirq = BASE_PCI_IRQ;
/*
* Translate from irq to software PCI bus number and PCI slot.
*/
int irq_to_bus[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.
*/
#define CF0_READ_PCI_CFG(bus,devfn,where,value,bm,mask) \
do { \
bridge_t *bridge; \
int slot = PCI_SLOT(devfn); \
int fn = PCI_FUNC(devfn); \
volatile u32 *addr; \
u32 cf, __bit; \
unsigned int bus_id = (unsigned) bus->number; \
\
bridge = (bridge_t *) NODE_SWIN_BASE(bus_to_nid[bus_id], \
bus_to_wid[bus_id]); \
\
__bit = (((where) & (bm)) << 3); \
addr = &bridge->b_type0_cfg_dev[slot].f[fn].l[where >> 2]; \
if (get_dbe(cf, addr)) \
return PCIBIOS_DEVICE_NOT_FOUND; \
*value = (cf >> __bit) & (mask); \
return PCIBIOS_SUCCESSFUL; \
} while (0)
static int pci_conf0_read_config(struct pci_bus *bus, unsigned int devfn,
int where, int size, u32 * value)
{
u32 vprod;
CF0_READ_PCI_CFG(bus, devfn, PCI_VENDOR_ID, &vprod, 0, 0xffffffff);
if (vprod == (PCI_VENDOR_ID_SGI | (PCI_DEVICE_ID_SGI_IOC3 << 16))
&& ((where >= 0x14 && where < 0x40) || (where >= 0x48))) {
*value = 0;
return PCIBIOS_SUCCESSFUL;
}
if (size == 1)
CF0_READ_PCI_CFG(bus, devfn, where, (u8 *) value, 3, 0xff);
else if (size == 2)
CF0_READ_PCI_CFG(bus, devfn, where, (u16 *) value, 2,
0xffff);
else
CF0_READ_PCI_CFG(bus, devfn, where, (u32 *) value, 0,
0xffffffff);
}
#define CF0_WRITE_PCI_CFG(bus,devfn,where,value,bm,mask) \
do { \
bridge_t *bridge; \
int slot = PCI_SLOT(devfn); \
int fn = PCI_FUNC(devfn); \
volatile u32 *addr; \
u32 cf, __bit; \
unsigned int bus_id = (unsigned) bus->number; \
\
bridge = (bridge_t *) NODE_SWIN_BASE(bus_to_nid[bus_id], \
bus_to_wid[bus_id]); \
\
__bit = (((where) & (bm)) << 3); \
addr = &bridge->b_type0_cfg_dev[slot].f[fn].l[where >> 2]; \
if (get_dbe(cf, addr)) \
return PCIBIOS_DEVICE_NOT_FOUND; \
cf &= (~mask); \
cf |= (value); \
put_dbe(cf, addr); \
return PCIBIOS_SUCCESSFUL; \
} while (0)
static int pci_conf0_write_config(struct pci_bus *bus, unsigned int devfn,
int where, int size, u32 value)
{
u32 vprod;
CF0_READ_PCI_CFG(bus, devfn, PCI_VENDOR_ID, &vprod, 0, 0xffffffff);
if (vprod == (PCI_VENDOR_ID_SGI | (PCI_DEVICE_ID_SGI_IOC3 << 16))
&& ((where >= 0x14 && where < 0x40) || (where >= 0x48))) {
return PCIBIOS_SUCCESSFUL;
}
if (size == 1)
CF0_WRITE_PCI_CFG(bus, devfn, where, (u8) value, 3, 0xff);
else if (size == 2)
CF0_WRITE_PCI_CFG(bus, devfn, where, (u16) value, 2,
0xffff);
else
CF0_WRITE_PCI_CFG(bus, devfn, where, (u32) value, 0,
0xffffffff);
}
static struct pci_ops bridge_pci_ops = {
.read = pci_conf0_read_config,
.write = pci_conf0_write_config,
};
static int __init pcibios_init(void)
{
struct pci_ops *ops = &bridge_pci_ops;
int i;
ioport_resource.end = ~0UL;
for (i = 0; i < num_bridges; i++) {
printk("PCI: Probing PCI hardware on host bus %2d.\n", i);
pci_scan_bus(i, ops, NULL);
}
return 0;
}
subsys_initcall(pcibios_init);
static inline u8 bridge_swizzle(u8 pin, u8 slot)
{
return (((pin - 1) + slot) % 4) + 1;
}
static u8 __devinit pci_swizzle(struct pci_dev *dev, u8 * pinp)
{
u8 pin = *pinp;
while (dev->bus->self) { /* Move up the chain of bridges. */
pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn));
dev = dev->bus->self;
}
*pinp = pin;
return PCI_SLOT(dev->devfn);
}
/*
* 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.
*/
static int __devinit pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
{
if ((dev->bus->number >= MAX_PCI_BUSSES)
|| (pin != 1)
|| (slot >= MAX_DEVICES_PER_PCIBUS))
panic("Increase supported PCI busses %d,%d,%d",
dev->bus->number, slot, pin);
/*
* Already assigned? Then return previously assigned value ...
*/
if (irqstore[dev->bus->number][slot])
return irqstore[dev->bus->number][slot];
irq_to_bus[lastirq] = dev->bus->number;
irq_to_slot[lastirq] = slot;
irqstore[dev->bus->number][slot] = lastirq;
lastirq++;
return lastirq - 1;
}
void __init pcibios_update_irq(struct pci_dev *dev, int irq)
{
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
}
void __devinit pcibios_fixup_bus(struct pci_bus *b)
{
pci_fixup_irqs(pci_swizzle, pci_map_irq);
}
int pcibios_enable_device(struct pci_dev *dev, int mask)
{
/* Not needed, since we enable all devices at startup. */
return 0;
}
void pcibios_align_resource(void *data, struct resource *res,
unsigned long size, unsigned long align)
{
}
unsigned int pcibios_assign_all_busses(void)
{
return 0;
}
char *__devinit pcibios_setup(char *str)
{
/* Nothing to do for now. */
return str;
}
/*
* 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 void __init pci_disable_swapping(struct pci_dev *dev)
{
unsigned int bus_id = (unsigned) dev->bus->number;
bridge_t *bridge = (bridge_t *) NODE_SWIN_BASE(bus_to_nid[bus_id],
bus_to_wid[bus_id]);
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 void __init pci_enable_swapping(struct pci_dev *dev)
{
unsigned int bus_id = (unsigned) dev->bus->number;
bridge_t *bridge = (bridge_t *) NODE_SWIN_BASE(bus_to_nid[bus_id],
bus_to_wid[bus_id]);
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)
{
unsigned long bus_id = (unsigned) d->bus->number;
printk("PCI: Fixing base addresses for IOC3 device %s\n",
d->slot_name);
d->resource[0].start |= NODE_OFFSET(bus_to_nid[bus_id]);
d->resource[0].end |= NODE_OFFSET(bus_to_nid[bus_id]);
pci_disable_swapping(d);
}
static void __init pci_fixup_isp1020(struct pci_dev *d)
{
unsigned short command;
d->resource[0].start |=
((unsigned long) (bus_to_nid[d->bus->number]) << 32);
printk("PCI: Fixing isp1020 in [bus:slot.fn] %s\n", d->slot_name);
/*
* Configure device to allow bus mastering, i/o and memory mapping.
* Older qlogicisp driver expects to have the IO space enable
* bit set. Things stop working if we program the controllers as not
* having PCI_COMMAND_MEMORY, so we have to fudge the mem_flags.
*/
pci_set_master(d);
pci_read_config_word(d, PCI_COMMAND, &command);
command |= PCI_COMMAND_MEMORY;
command |= PCI_COMMAND_IO;
pci_write_config_word(d, PCI_COMMAND, command);
d->resource[1].flags |= 1;
pci_enable_swapping(d);
}
static void __init pci_fixup_isp2x00(struct pci_dev *d)
{
unsigned int bus_id = (unsigned) d->bus->number;
bridge_t *bridge = (bridge_t *) NODE_SWIN_BASE(bus_to_nid[bus_id],
bus_to_wid[bus_id]);
bridgereg_t devreg;
int i;
int slot = PCI_SLOT(d->devfn);
unsigned int start;
unsigned short command;
printk("PCI: Fixing isp2x00 in [bus:slot.fn] %s\n", d->slot_name);
/* set the resource struct for this device */
start = (u32) (u64) bridge; /* yes, we want to lose the upper 32 bits here */
start |= BRIDGE_DEVIO(slot);
d->resource[0].start = start;
d->resource[0].end = d->resource[0].start + 0xff;
d->resource[0].flags = IORESOURCE_IO;
d->resource[1].start = start;
d->resource[1].end = d->resource[0].start + 0xfff;
d->resource[1].flags = IORESOURCE_MEM;
/*
* set the bridge device(x) reg for this device
*/
devreg = bridge->b_device[slot].reg;
/* point device(x) to it appropriate small window */
devreg &= ~BRIDGE_DEV_OFF_MASK;
devreg |= (start >> 20) & BRIDGE_DEV_OFF_MASK;
bridge->b_device[slot].reg = devreg;
pci_enable_swapping(d);
/* set card's base addr reg */
//pci_write_config_dword(d, PCI_BASE_ADDRESS_0, 0x500001);
//pci_write_config_dword(d, PCI_BASE_ADDRESS_1, 0x8b00000);
//pci_write_config_dword(d, PCI_ROM_ADDRESS, 0x8b20000);
/* I got these from booting irix on system... */
pci_write_config_dword(d, PCI_BASE_ADDRESS_0, 0x200001);
//pci_write_config_dword(d, PCI_BASE_ADDRESS_1, 0xf800000);
pci_write_config_dword(d, PCI_ROM_ADDRESS, 0x10200000);
pci_write_config_dword(d, PCI_BASE_ADDRESS_1, start);
//pci_write_config_dword(d, PCI_ROM_ADDRESS, (start | 0x20000));
/* set cache line size */
pci_write_config_dword(d, PCI_CACHE_LINE_SIZE, 0xf080);
/* set pci bus timeout */
bridge->b_bus_timeout |= BRIDGE_BUS_PCI_RETRY_HLD(0x3);
bridge->b_wid_tflush;
printk("PCI: bridge bus timeout= 0x%x \n", bridge->b_bus_timeout);
/* set host error field */
bridge->b_int_host_err = 0x44;
bridge->b_wid_tflush;
bridge->b_wid_tflush; /* wait until Bridge PIO complete */
for (i = 0; i < 8; i++)
printk("PCI: device(%d)= 0x%x\n", i,
bridge->b_device[i].reg);
/* configure device to allow bus mastering, i/o and memory mapping */
pci_set_master(d);
pci_read_config_word(d, PCI_COMMAND, &command);
command |= PCI_COMMAND_MEMORY;
command |= PCI_COMMAND_IO;
pci_write_config_word(d, PCI_COMMAND, command);
/*d->resource[1].flags |= 1; */
}
struct pci_fixup pcibios_fixups[] = {
{PCI_FIXUP_HEADER, PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3,
pci_fixup_ioc3},
{PCI_FIXUP_HEADER, PCI_VENDOR_ID_QLOGIC,
PCI_DEVICE_ID_QLOGIC_ISP1020,
pci_fixup_isp1020},
{PCI_FIXUP_HEADER, PCI_VENDOR_ID_QLOGIC,
PCI_DEVICE_ID_QLOGIC_ISP2100,
pci_fixup_isp2x00},
{PCI_FIXUP_HEADER, PCI_VENDOR_ID_QLOGIC,
PCI_DEVICE_ID_QLOGIC_ISP2200,
pci_fixup_isp2x00},
{0}
};
/*
* 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>
#include <asm/ip32/crime.h>
#include <asm/ip32/ip32_ints.h>
#include <linux/delay.h>
#undef DEBUG_MACE_PCI
/*
* 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, where) \
((((_devfn) & 0xffUL) << 8) | ((where) & 0xfcUL))
void macepci_error(int irq, void *dev, struct pt_regs *regs);
static int macepci_read_config(struct pci_bus *bus, unsigned int devfn,
int where, int size, u32 * val)
{
switch (size) {
case 1:
*val = 0xff;
chkslot(bus, devfn);
mace_write_32(MACEPCI_CONFIG_ADDR, mkaddr(devfn, where));
*val =
mace_read_8(MACEPCI_CONFIG_DATA +
((where & 3UL) ^ 3UL));
return PCIBIOS_SUCCESSFUL;
case 2:
*val = 0xffff;
chkslot(bus, devfn);
if (where & 1)
return PCIBIOS_BAD_REGISTER_NUMBER;
mace_write_32(MACEPCI_CONFIG_ADDR, mkaddr(devfn, where));
*val =
mace_read_16(MACEPCI_CONFIG_DATA +
((where & 2UL) ^ 2UL));
return PCIBIOS_SUCCESSFUL;
case 4:
*val = 0xffffffff;
chkslot(bus, devfn);
if (where & 3)
return PCIBIOS_BAD_REGISTER_NUMBER;
mace_write_32(MACEPCI_CONFIG_ADDR, mkaddr(devfn, where));
*val = mace_read_32(MACEPCI_CONFIG_DATA);
return PCIBIOS_SUCCESSFUL;
}
}
static int macepci_write_config(struct pci_bus *bus, unsigned int devfn,
int where, int size, u32 val)
{
switch (size) {
case 1:
chkslot(bus, devfn);
mace_write_32(MACEPCI_CONFIG_ADDR, mkaddr(devfn, where));
mace_write_8(MACEPCI_CONFIG_DATA + ((where & 3UL) ^ 3UL),
val);
return PCIBIOS_SUCCESSFUL;
case 2:
chkslot(bus, devfn);
if (where & 1)
return PCIBIOS_BAD_REGISTER_NUMBER;
mace_write_32(MACEPCI_CONFIG_ADDR, mkaddr(devfn, where));
mace_write_16(MACEPCI_CONFIG_DATA + ((where & 2UL) ^ 2UL),
val);
return PCIBIOS_SUCCESSFUL;
case 4:
chkslot(bus, devfn);
if (where & 3)
return PCIBIOS_BAD_REGISTER_NUMBER;
mace_write_32(MACEPCI_CONFIG_ADDR, mkaddr(devfn, where));
mace_write_32(MACEPCI_CONFIG_DATA, val);
return PCIBIOS_SUCCESSFUL;
}
}
static struct pci_ops macepci_ops = {
.read = macepci_read_config,
.write = macepci_write_config,
};
struct pci_fixup pcibios_fixups[] = { {0} };
static int __init pcibios_init(void)
{
struct pci_dev *dev = NULL;
u32 start, size;
u16 cmd;
u32 base_io = 0x3000; /* The first i/o address to assign after SCSI */
u32 base_mem = 0x80100000; /* Likewise */
u32 rev = mace_read_32(MACEPCI_REV);
int i;
printk("MACE: PCI rev %d detected at %016lx\n", rev,
(u64) MACE_BASE + MACE_PCI);
/* These are *bus* addresses */
ioport_resource.start = 0;
ioport_resource.end = 0xffffffffUL;
iomem_resource.start = 0x80000000UL;
iomem_resource.end = 0xffffffffUL;
/* Clear any outstanding errors and enable interrupts */
mace_write_32(MACEPCI_ERROR_ADDR, 0);
mace_write_32(MACEPCI_ERROR_FLAGS, 0);
mace_write_32(MACEPCI_CONTROL, 0xff008500);
crime_write_64(CRIME_HARD_INT, 0UL);
crime_write_64(CRIME_SOFT_INT, 0UL);
crime_write_64(CRIME_INT_STAT, 0x000000000000ff00UL);
if (request_irq(MACE_PCI_BRIDGE_IRQ, macepci_error, 0,
"MACE PCI error", NULL))
panic("PCI bridge can't get interrupt; can't happen.");
pci_scan_bus(0, &macepci_ops, NULL);
#ifdef DEBUG_MACE_PCI
while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
printk("Device: %d/%d/%d ARCS-assigned bus resource map\n",
dev->bus->number, PCI_SLOT(dev->devfn),
PCI_FUNC(dev->devfn));
for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
if (dev->resource[i].start == 0)
continue;
printk("%d: %016lx - %016lx (flags %04lx)\n",
i, dev->resource[i].start,
dev->resource[i].end,
dev->resource[i].flags);
}
}
#endif
/*
* Assign sane resources to and enable all devices. The requirement
* for the SCSI controllers is well-known: a 256-byte I/O region
* which we must assign, and a 1-page memory region which is
* assigned by the system firmware.
*/
dev = NULL;
while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
switch (PCI_SLOT(dev->devfn)) {
case 1: /* SCSI bus 0 */
dev->resource[0].start = 0x1000UL;
dev->resource[0].end = 0x10ffUL;
break;
case 2: /* SCSI bus 1 */
dev->resource[0].start = 0x2000UL;
dev->resource[0].end = 0x20ffUL;
break;
default: /* Slots - I guess we have only 1 */
for (i = 0; i < 6; i++) {
size = dev->resource[i].end
- dev->resource[i].start;
if (!size
|| !(dev->resource[i].flags
& (IORESOURCE_IO |
IORESOURCE_MEM))) {
dev->resource[i].start =
dev->resource[i].end = 0UL;
continue;
}
if (dev->resource[i].flags & IORESOURCE_IO) {
dev->resource[i].start = base_io;
base_io += PAGE_ALIGN(size);
} else {
dev->resource[i].start = base_mem;
base_mem += 0x100000UL;
}
dev->resource[i].end =
dev->resource[i].start + size;
}
break;
}
for (i = 0; i < 6; i++) {
if (dev->resource[i].start == 0)
continue;
start = dev->resource[i].start;
if (dev->resource[i].flags & IORESOURCE_IO)
start |= 1;
pci_write_config_dword(dev,
PCI_BASE_ADDRESS_0 +
(i << 2), (u32) start);
}
pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 0x20);
pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x30);
pci_read_config_word(dev, PCI_COMMAND, &cmd);
cmd |=
(PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
PCI_COMMAND_SPECIAL | PCI_COMMAND_INVALIDATE |
PCI_COMMAND_PARITY);
pci_write_config_word(dev, PCI_COMMAND, cmd);
pci_set_master(dev);
}
/*
* Fixup O2 PCI slot. Bad hack.
*/
/* devtag = pci_make_tag(0, 0, 3, 0);
slot = macepci_conf_read(0, devtag, PCI_COMMAND_STATUS_REG);
slot |= PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE;
macepci_conf_write(0, devtag, PCI_COMMAND_STATUS_REG, slot);
slot = macepci_conf_read(0, devtag, PCI_MAPREG_START);
if (slot == 0xffffffe1)
macepci_conf_write(0, devtag, PCI_MAPREG_START, 0x00001000);
slot = macepci_conf_read(0, devtag, PCI_MAPREG_START + (2 << 2));
if ((slot & 0xffff0000) == 0) {
slot += 0x00010000;
macepci_conf_write(0, devtag, PCI_MAPREG_START + (2 << 2),
0x00000000);
}
*/
#ifdef DEBUG_MACE_PCI
printk("Triggering PCI bridge interrupt...\n");
mace_write_32(MACEPCI_ERROR_FLAGS, MACEPCI_ERROR_INTERRUPT_TEST);
dev = NULL;
while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
printk("Device: %d/%d/%d final bus resource map\n",
dev->bus->number, PCI_SLOT(dev->devfn),
PCI_FUNC(dev->devfn));
for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
if (dev->resource[i].start == 0)
continue;
printk("%d: %016lx - %016lx (flags %04lx)\n",
i, dev->resource[i].start,
dev->resource[i].end,
dev->resource[i].flags);
}
}
#endif
return 0;
}
subsys_initcall(pcibios_init);
/*
* 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.
*/
static int __devinit macepci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
{
chkslot(dev->bus, dev->devfn);
if (pin == 0)
pin = 1;
switch (slot) {
case 1:
return MACEPCI_SCSI0_IRQ;
case 2:
return MACEPCI_SCSI1_IRQ;
case 3:
switch (pin) {
case 2:
return MACEPCI_SHARED0_IRQ;
case 3:
return MACEPCI_SHARED1_IRQ;
case 4:
return MACEPCI_SHARED2_IRQ;
case 1:
default:
return MACEPCI_SLOT0_IRQ;
}
case 4:
switch (pin) {
case 2:
return MACEPCI_SHARED2_IRQ;
case 3:
return MACEPCI_SHARED0_IRQ;
case 4:
return MACEPCI_SHARED1_IRQ;
case 1:
default:
return MACEPCI_SLOT1_IRQ;
}
return MACEPCI_SLOT1_IRQ;
case 5:
switch (pin) {
case 2:
return MACEPCI_SHARED1_IRQ;
case 3:
return MACEPCI_SHARED2_IRQ;
case 4:
return MACEPCI_SHARED0_IRQ;
case 1:
default:
return MACEPCI_SLOT2_IRQ;
}
default:
return 0;
}
}
/*
* It's not entirely clear what this does in a system with no bridges.
* In any case, bridges are not supported by Linux in O2.
*/
static u8 __init macepci_swizzle(struct pci_dev *dev, u8 * pinp)
{
if (PCI_SLOT(dev->devfn) == 2)
*pinp = 2;
else
*pinp = 1;
return PCI_SLOT(dev->devfn);
}
/* All devices are enabled during initialization. */
int pcibios_enable_device(struct pci_dev *dev, int mask)
{
return PCIBIOS_SUCCESSFUL;
}
char *__init pcibios_setup(char *str)
{
return str;
}
void pcibios_align_resource(void *data, struct resource *res,
unsigned long size, unsigned long align)
{
}
void __init pcibios_update_irq(struct pci_dev *dev, int irq)
{
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
}
void __devinit pcibios_fixup_bus(struct pci_bus *b)
{
pci_fixup_irqs(macepci_swizzle, macepci_map_irq);
}
/*
* 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?
*/
void macepci_error(int irq, void *dev, struct pt_regs *regs)
{
u32 flags, error_addr;
char space;
flags = mace_read_32(MACEPCI_ERROR_FLAGS);
error_addr = mace_read_32(MACEPCI_ERROR_ADDR);
if (flags & MACEPCI_ERROR_MEMORY_ADDR)
space = 'M';
else if (flags & MACEPCI_ERROR_CONFIG_ADDR)
space = 'C';
else
space = 'X';
if (flags & MACEPCI_ERROR_MASTER_ABORT) {
printk("MACEPCI: Master abort at 0x%08x (%c)\n",
error_addr, space);
mace_write_32(MACEPCI_ERROR_FLAGS,
flags & ~MACEPCI_ERROR_MASTER_ABORT);
}
if (flags & MACEPCI_ERROR_TARGET_ABORT) {
printk("MACEPCI: Target abort at 0x%08x (%c)\n",
error_addr, space);
mace_write_32(MACEPCI_ERROR_FLAGS,
flags & ~MACEPCI_ERROR_TARGET_ABORT);
}
if (flags & MACEPCI_ERROR_DATA_PARITY_ERR) {
printk("MACEPCI: Data parity error at 0x%08x (%c)\n",
error_addr, space);
mace_write_32(MACEPCI_ERROR_FLAGS, flags
& ~MACEPCI_ERROR_DATA_PARITY_ERR);
}
if (flags & MACEPCI_ERROR_RETRY_ERR) {
printk("MACEPCI: Retry error at 0x%08x (%c)\n", error_addr,
space);
mace_write_32(MACEPCI_ERROR_FLAGS, flags
& ~MACEPCI_ERROR_RETRY_ERR);
}
if (flags & MACEPCI_ERROR_ILLEGAL_CMD) {
printk("MACEPCI: Illegal command at 0x%08x (%c)\n",
error_addr, space);
mace_write_32(MACEPCI_ERROR_FLAGS,
flags & ~MACEPCI_ERROR_ILLEGAL_CMD);
}
if (flags & MACEPCI_ERROR_SYSTEM_ERR) {
printk("MACEPCI: System error at 0x%08x (%c)\n",
error_addr, space);
mace_write_32(MACEPCI_ERROR_FLAGS, flags
& ~MACEPCI_ERROR_SYSTEM_ERR);
}
if (flags & MACEPCI_ERROR_PARITY_ERR) {
printk("MACEPCI: Parity error at 0x%08x (%c)\n",
error_addr, space);
mace_write_32(MACEPCI_ERROR_FLAGS,
flags & ~MACEPCI_ERROR_PARITY_ERR);
}
if (flags & MACEPCI_ERROR_OVERRUN) {
printk("MACEPCI: Overrun error at 0x%08x (%c)\n",
error_addr, space);
mace_write_32(MACEPCI_ERROR_FLAGS, flags
& ~MACEPCI_ERROR_OVERRUN);
}
if (flags & MACEPCI_ERROR_SIG_TABORT) {
printk("MACEPCI: Signaled target abort (clearing)\n");
mace_write_32(MACEPCI_ERROR_FLAGS, flags
& ~MACEPCI_ERROR_SIG_TABORT);
}
if (flags & MACEPCI_ERROR_INTERRUPT_TEST) {
printk("MACEPCI: Interrupt test triggered (clearing)\n");
mace_write_32(MACEPCI_ERROR_FLAGS, flags
& ~MACEPCI_ERROR_INTERRUPT_TEST);
}
}
unsigned int pcibios_assign_all_busses(void)
{
return 0;
}
#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
#undef DEBUG_PCI
#ifdef DEBUG_PCI
#define Dprintk(fmt...) printk(fmt)
#else
#define Dprintk(fmt...)
#endif
static int (*lasat_pcibios_config_access) (unsigned char access_type,
struct pci_bus * bus,
unsigned int devfn, int where,
u32 * val);
/*
* Because of an error/peculiarity in the Galileo chip, we need to swap the
* bytes when running bigendian.
*/
#define GT_WRITE(ofs, data) \
*(volatile u32 *)(LASAT_GT_BASE+ofs) = cpu_to_le32(data)
#define GT_READ(ofs, data) \
data = le32_to_cpu(*(volatile u32 *)(LASAT_GT_BASE+ofs))
static int lasat_pcibios_config_access_100(unsigned char access_type,
struct pci_bus *bus,
unsigned int devfn, int where,
u32 * val)
{
unsigned char busnum = bus->number;
u32 intr;
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) {
GT_WRITE(GT_PCI0_CFGDATA_OFS, *val);
} else {
GT_READ(GT_PCI0_CFGDATA_OFS, *val);
}
/* Check for master or target abort */
GT_READ(GT_INTRCAUSE_OFS, intr);
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;
}
#define LO(reg) (reg / 4)
#define HI(reg) (reg / 4 + 1)
volatile unsigned long *const vrc_pciregs = (void *) Vrc5074_BASE;
static int lasat_pcibios_config_access_200(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 -1;
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 0;
}
/* 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);
#ifdef DEBUG_PCI
printk("PCI config %s: adr %x",
access_type == PCI_ACCESS_WRITE ? "write" : "read", adr);
#endif
if (access_type == PCI_ACCESS_WRITE) {
*(u32 *) adr = *val;
} else {
*val = *(u32 *) adr;
}
#ifdef DEBUG_PCI
printk(" value = %x\n", *val);
#endif
/* 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) {
/* Error occured */
#ifdef DEBUG_PCI
printk("\terror %x at adr %x\n", err,
vrc_pciregs[LO(NILE4_PCIERR)]);
#endif
return -1;
}
return 0;
}
static int lasat_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 (lasat_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 lasat_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 (lasat_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));
else
data = val;
if (lasat_pcibios_config_access
(PCI_ACCESS_WRITE, bus, devfn, where, &data))
return -1;
return PCIBIOS_SUCCESSFUL;
}
struct pci_ops lasat_pci_ops = {
.read = lasat_pcibios_read,
.write = lasat_pcibios_write,
};
static int __init pcibios_init(void)
{
switch (mips_machtype) {
case MACH_LASAT_100:
lasat_pcibios_config_access =
&lasat_pcibios_config_access_100;
break;
case MACH_LASAT_200:
lasat_pcibios_config_access =
&lasat_pcibios_config_access_200;
break;
default:
panic("pcibios_init: mips_machtype incorrect");
}
Dprintk("pcibios_init()\n");
pci_scan_bus(0, &lasat_pci_ops, NULL);
return 0;
}
unsigned __init int pcibios_assign_all_busses(void)
{
return 1;
}
/*
* 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/generic.h>
#include <asm/gt64120.h>
#include <asm/mips-boards/bonito64.h>
#ifdef CONFIG_MIPS_MALTA
#include <asm/mips-boards/malta.h>
#endif
#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 mips_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, dummy;
u64 pci_addr;
switch (mips_revision_corid) {
case MIPS_REVISION_CORID_QED_RM5261:
case MIPS_REVISION_CORID_CORE_LV:
case MIPS_REVISION_CORID_CORE_FPGA:
/* Galileo GT64120 system controller. */
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_READ(GT_INTRCAUSE_OFS, intr);
GT_WRITE(GT_INTRCAUSE_OFS, intr &
~(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 && devfn == 0) {
/*
* The Galileo system controller is acting
* differently than other devices.
*/
GT_WRITE(GT_PCI0_CFGDATA_OFS, *data);
} else {
GT_PCI_WRITE(GT_PCI0_CFGDATA_OFS, *data);
}
} else {
if (busnum == 0 && devfn == 0) {
/*
* The Galileo system controller is acting
* differently than other devices.
*/
GT_READ(GT_PCI0_CFGDATA_OFS, *data);
} else {
GT_PCI_READ(GT_PCI0_CFGDATA_OFS, *data);
}
}
/* Check for master or target abort */
GT_READ(GT_INTRCAUSE_OFS, intr);
if (intr & (GT_INTRCAUSE_MASABORT0_BIT |
GT_INTRCAUSE_TARABORT0_BIT)) {
/* Error occurred */
/* Clear bits */
GT_READ(GT_INTRCAUSE_OFS, intr);
GT_WRITE(GT_INTRCAUSE_OFS, intr &
~(GT_INTRCAUSE_MASABORT0_BIT |
GT_INTRCAUSE_TARABORT0_BIT));
return -1;
}
break;
case MIPS_REVISION_CORID_BONITO64:
case MIPS_REVISION_CORID_CORE_20K:
/* Algorithmics Bonito64 system controller. */
if ((busnum == 0) && (PCI_SLOT(devfn) == 0)) {
return -1;
}
/* 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;
}
/* Flush Bonito register block */
dummy = BONITO_PCIMAP_CFG;
iob(); /* sync */
/* Perform access */
if (access_type == PCI_ACCESS_WRITE) {
*(volatile u32 *) (KSEG1ADDR(BONITO_PCICFG_BASE +
(pci_addr & 0xffff)))
= *(u32 *) data;
/* Wait till done */
while (BONITO_PCIMSTAT & 0xF);
} else {
*(u32 *) data =
*(volatile u32
*) (KSEG1ADDR(BONITO_PCICFG_BASE +
(pci_addr & 0xffff)));
}
/* 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;
}
break;
case MIPS_REVISION_CORID_CORE_MSC:
/* MIPS system controller. */
if ((busnum == 0) && (PCI_SLOT(devfn) == 0)) {
return -1;
}
/* 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;
}
break;
default:
printk
("Unknown Core card, don't know the system controller.\n");
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 mips_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 (mips_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 mips_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 (mips_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 (mips_pcibios_config_access(PCI_ACCESS_WRITE, bus, devfn, where,
&data))
return -1;
return PCIBIOS_SUCCESSFUL;
}
struct pci_ops mips_pci_ops = {
.read = mips_pcibios_read,
.write = mips_pcibios_write
};
int mips_pcibios_iack(void)
{
int irq;
u32 dummy;
/*
* Determine highest priority pending interrupt by performing
* a PCI Interrupt Acknowledge cycle.
*/
switch (mips_revision_corid) {
case MIPS_REVISION_CORID_QED_RM5261:
case MIPS_REVISION_CORID_CORE_LV:
case MIPS_REVISION_CORID_CORE_FPGA:
case MIPS_REVISION_CORID_CORE_MSC:
if (mips_revision_corid == MIPS_REVISION_CORID_CORE_MSC)
MSC_READ(MSC01_PCI_IACK, irq);
else
GT_READ(GT_PCI0_IACK_OFS, irq);
irq &= 0xff;
break;
case MIPS_REVISION_CORID_BONITO64:
case MIPS_REVISION_CORID_CORE_20K:
/* The following will generate a PCI IACK cycle on the
* Bonito controller. It's a little bit kludgy, but it
* was the easiest way to implement it in hardware at
* the given time.
*/
BONITO_PCIMAP_CFG = 0x20000;
/* Flush Bonito register block */
dummy = BONITO_PCIMAP_CFG;
iob(); /* sync */
irq = *(volatile u32 *) (KSEG1ADDR(BONITO_PCICFG_BASE));
iob(); /* sync */
irq &= 0xff;
BONITO_PCIMAP_CFG = 0;
break;
default:
printk
("Unknown Core card, don't know the system controller.\n");
return -1;
}
return irq;
}
static int __init pcibios_init(void)
{
#ifdef CONFIG_MIPS_MALTA
struct pci_dev *pdev = NULL;
unsigned char reg_val;
#endif
printk("PCI: Probing PCI hardware on host bus 0.\n");
pci_scan_bus(0, &mips_pci_ops, NULL);
switch (mips_revision_corid) {
case MIPS_REVISION_CORID_QED_RM5261:
case MIPS_REVISION_CORID_CORE_LV:
case MIPS_REVISION_CORID_CORE_FPGA:
/*
* Due to a bug in the Galileo system controller, we need
* to setup the PCI BAR for the Galileo internal registers.
* This should be done in the bios/bootprom and will be
* fixed in a later revision of YAMON (the MIPS boards
* boot prom).
*/
GT_WRITE(GT_PCI0_CFGADDR_OFS, (0 << GT_PCI0_CFGADDR_BUSNUM_SHF) | /* Local bus */
(0 << GT_PCI0_CFGADDR_DEVNUM_SHF) | /* GT64120 dev */
(0 << GT_PCI0_CFGADDR_FUNCTNUM_SHF) | /* Function 0 */
((0x20 / 4) << GT_PCI0_CFGADDR_REGNUM_SHF) | /* BAR 4 */
GT_PCI0_CFGADDR_CONFIGEN_BIT);
/* Perform the write */
GT_WRITE(GT_PCI0_CFGDATA_OFS, PHYSADDR(MIPS_GT_BASE));
break;
}
#ifdef CONFIG_MIPS_MALTA
while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) {
if ((pdev->vendor == PCI_VENDOR_ID_INTEL)
&& (pdev->device == PCI_DEVICE_ID_INTEL_82371AB)
&& (PCI_SLOT(pdev->devfn) == 0x0a)) {
/*
* 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);
}
if ((pdev->vendor == PCI_VENDOR_ID_INTEL)
&& (pdev->device == PCI_DEVICE_ID_INTEL_82371AB_0)
&& (PCI_SLOT(pdev->devfn) == 0x0a)) {
/*
* 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);
}
}
/*
* Activate Floppy Controller in the SMSC FDC37M817 Super I/O
* Controller.
* This should be done in the bios/bootprom and will be fixed in
* a later revision of YAMON (the MIPS boards boot prom).
*/
/* Entering config state. */
SMSC_WRITE(SMSC_CONFIG_ENTER, SMSC_CONFIG_REG);
/* Activate floppy controller. */
SMSC_WRITE(SMSC_CONFIG_DEVNUM, SMSC_CONFIG_REG);
SMSC_WRITE(SMSC_CONFIG_DEVNUM_FLOPPY, SMSC_DATA_REG);
SMSC_WRITE(SMSC_CONFIG_ACTIVATE, SMSC_CONFIG_REG);
SMSC_WRITE(SMSC_CONFIG_ACTIVATE_ENABLE, SMSC_DATA_REG);
/* Exit config state. */
SMSC_WRITE(SMSC_CONFIG_EXIT, SMSC_CONFIG_REG);
#endif
return 0;
}
subsys_initcall(pcibios_init);
int pcibios_enable_device(struct pci_dev *dev, int mask)
{
/* Not needed, since we enable all devices at startup. */
return 0;
}
void pcibios_align_resource(void *data, struct resource *res,
unsigned long size, unsigned long align)
{
}
char *__init pcibios_setup(char *str)
{
/* Nothing to do for now. */
return str;
}
struct pci_fixup pcibios_fixups[] = {
{0}
};
/*
* Called after each bus is probed, but before its children
* are examined.
*/
void __devinit pcibios_fixup_bus(struct pci_bus *b)
{
pci_read_bridge_bases(b);
}
unsigned int pcibios_assign_all_busses(void)
{
return 1;
}
/*
* Copyright 2002 Momentum Computer
* Author: Matthew Dharm <mdharm@momenco.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/version.h>
#include <asm/pci.h>
#include <asm/io.h>
#include <asm/mv64340.h>
#include <linux/init.h>
/*
* These functions and structures provide the BIOS scan and mapping of the PCI
* devices.
*/
#define MAX_PCI_DEVS 10
void mv64340_board_pcibios_fixup_bus(struct pci_bus *c);
/* Functions to implement "pci ops" */
static int marvell_pcibios_read_config_word(struct pci_dev *dev,
int offset, u16 * val);
static int marvell_pcibios_read_config_byte(struct pci_dev *dev,
int offset, u8 * val);
static int marvell_pcibios_read_config_dword(struct pci_dev *dev,
int offset, u32 * val);
static int marvell_pcibios_write_config_byte(struct pci_dev *dev,
int offset, u8 val);
static int marvell_pcibios_write_config_word(struct pci_dev *dev,
int offset, u16 val);
static int marvell_pcibios_write_config_dword(struct pci_dev *dev,
int offset, u32 val);
static void marvell_pcibios_set_master(struct pci_dev *dev);
/*
* General-purpose PCI functions.
*/
/*
* pci_range_ck -
*
* Check if the pci device that are trying to access does really exists
* on the evaluation board.
*
* Inputs :
* bus - bus number (0 for PCI 0 ; 1 for PCI 1)
* dev - number of device on the specific pci bus
*
* Outpus :
* 0 - if OK , 1 - if failure
*/
static __inline__ int pci_range_ck(unsigned char bus, unsigned char dev)
{
/* Accessing device 31 crashes the MV-64340. */
if (dev < 5)
return 0;
return -1;
}
/*
* marvell_pcibios_(read/write)_config_(dword/word/byte) -
*
* reads/write a dword/word/byte register from the configuration space
* of a device.
*
* Note that bus 0 and bus 1 are local, and we assume all other busses are
* bridged from bus 1. This is a safe assumption, since any other
* configuration will require major modifications to the CP7000G
*
* Inputs :
* bus - bus number
* dev - device number
* offset - register offset in the configuration space
* val - value to be written / read
*
* Outputs :
* PCIBIOS_SUCCESSFUL when operation was succesfull
* PCIBIOS_DEVICE_NOT_FOUND when the bus or dev is errorneous
* PCIBIOS_BAD_REGISTER_NUMBER when accessing non aligned
*/
static int marvell_pcibios_read_config_dword(struct pci_dev *device,
int offset, u32 * val)
{
int dev, bus, func;
uint32_t address_reg, data_reg;
uint32_t address;
bus = device->bus->number;
dev = PCI_SLOT(device->devfn);
func = PCI_FUNC(device->devfn);
/* verify the range */
if (pci_range_ck(bus, dev))
return PCIBIOS_DEVICE_NOT_FOUND;
/* select the MV-64340 registers to communicate with the PCI bus */
if (bus == 0) {
address_reg = MV64340_PCI_0_CONFIG_ADDR;
data_reg = MV64340_PCI_0_CONFIG_DATA_VIRTUAL_REG;
} else {
address_reg = MV64340_PCI_1_CONFIG_ADDR;
data_reg = MV64340_PCI_1_CONFIG_DATA_VIRTUAL_REG;
}
address = (bus << 16) | (dev << 11) | (func << 8) |
(offset & 0xfc) | 0x80000000;
/* start the configuration cycle */
MV_WRITE(address_reg, address);
/* read the data */
MV_READ(data_reg, val);
return PCIBIOS_SUCCESSFUL;
}
static int marvell_pcibios_read_config_word(struct pci_dev *device,
int offset, u16 * val)
{
int dev, bus, func;
uint32_t address_reg, data_reg;
uint32_t address;
bus = device->bus->number;
dev = PCI_SLOT(device->devfn);
func = PCI_FUNC(device->devfn);
/* verify the range */
if (pci_range_ck(bus, dev))
return PCIBIOS_DEVICE_NOT_FOUND;
/* select the MV-64340 registers to communicate with the PCI bus */
if (bus == 0) {
address_reg = MV64340_PCI_0_CONFIG_ADDR;
data_reg = MV64340_PCI_0_CONFIG_DATA_VIRTUAL_REG;
} else {
address_reg = MV64340_PCI_1_CONFIG_ADDR;
data_reg = MV64340_PCI_1_CONFIG_DATA_VIRTUAL_REG;
}
address = (bus << 16) | (dev << 11) | (func << 8) |
(offset & 0xfc) | 0x80000000;
/* start the configuration cycle */
MV_WRITE(address_reg, address);
/* read the data */
MV_READ_16(data_reg + (offset & 0x3), val);
return PCIBIOS_SUCCESSFUL;
}
static int marvell_pcibios_read_config_byte(struct pci_dev *device,
int offset, u8 * val)
{
int dev, bus, func;
uint32_t address_reg, data_reg;
uint32_t address;
bus = device->bus->number;
dev = PCI_SLOT(device->devfn);
func = PCI_FUNC(device->devfn);
/* verify the range */
if (pci_range_ck(bus, dev))
return PCIBIOS_DEVICE_NOT_FOUND;
/* select the MV-64340 registers to communicate with the PCI bus */
if (bus == 0) {
address_reg = MV64340_PCI_0_CONFIG_ADDR;
data_reg = MV64340_PCI_0_CONFIG_DATA_VIRTUAL_REG;
} else {
address_reg = MV64340_PCI_1_CONFIG_ADDR;
data_reg = MV64340_PCI_1_CONFIG_DATA_VIRTUAL_REG;
}
address = (bus << 16) | (dev << 11) | (func << 8) |
(offset & 0xfc) | 0x80000000;
/* start the configuration cycle */
MV_WRITE(address_reg, address);
/* write the data */
MV_READ_8(data_reg + (offset & 0x3), val);
return PCIBIOS_SUCCESSFUL;
}
static int marvell_pcibios_write_config_dword(struct pci_dev *device,
int offset, u32 val)
{
int dev, bus, func;
uint32_t address_reg, data_reg;
uint32_t address;
bus = device->bus->number;
dev = PCI_SLOT(device->devfn);
func = PCI_FUNC(device->devfn);
/* verify the range */
if (pci_range_ck(bus, dev))
return PCIBIOS_DEVICE_NOT_FOUND;
/* select the MV-64340 registers to communicate with the PCI bus */
if (bus == 0) {
address_reg = MV64340_PCI_0_CONFIG_ADDR;
data_reg = MV64340_PCI_0_CONFIG_DATA_VIRTUAL_REG;
} else {
address_reg = MV64340_PCI_1_CONFIG_ADDR;
data_reg = MV64340_PCI_1_CONFIG_DATA_VIRTUAL_REG;
}
address = (bus << 16) | (dev << 11) | (func << 8) |
(offset & 0xfc) | 0x80000000;
/* start the configuration cycle */
MV_WRITE(address_reg, address);
/* write the data */
MV_WRITE(data_reg, val);
return PCIBIOS_SUCCESSFUL;
}
static int marvell_pcibios_write_config_word(struct pci_dev *device,
int offset, u16 val)
{
int dev, bus, func;
uint32_t address_reg, data_reg;
uint32_t address;
bus = device->bus->number;
dev = PCI_SLOT(device->devfn);
func = PCI_FUNC(device->devfn);
/* verify the range */
if (pci_range_ck(bus, dev))
return PCIBIOS_DEVICE_NOT_FOUND;
/* select the MV-64340 registers to communicate with the PCI bus */
if (bus == 0) {
address_reg = MV64340_PCI_0_CONFIG_ADDR;
data_reg = MV64340_PCI_0_CONFIG_DATA_VIRTUAL_REG;
} else {
address_reg = MV64340_PCI_1_CONFIG_ADDR;
data_reg = MV64340_PCI_1_CONFIG_DATA_VIRTUAL_REG;
}
address = (bus << 16) | (dev << 11) | (func << 8) |
(offset & 0xfc) | 0x80000000;
/* start the configuration cycle */
MV_WRITE(address_reg, address);
/* write the data */
MV_WRITE_16(data_reg + (offset & 0x3), val);
return PCIBIOS_SUCCESSFUL;
}
static int marvell_pcibios_write_config_byte(struct pci_dev *device,
int offset, u8 val)
{
int dev, bus, func;
uint32_t address_reg, data_reg;
uint32_t address;
bus = device->bus->number;
dev = PCI_SLOT(device->devfn);
func = PCI_FUNC(device->devfn);
/* verify the range */
if (pci_range_ck(bus, dev))
return PCIBIOS_DEVICE_NOT_FOUND;
/* select the MV-64340 registers to communicate with the PCI bus */
if (bus == 0) {
address_reg = MV64340_PCI_0_CONFIG_ADDR;
data_reg = MV64340_PCI_0_CONFIG_DATA_VIRTUAL_REG;
} else {
address_reg = MV64340_PCI_1_CONFIG_ADDR;
data_reg = MV64340_PCI_1_CONFIG_DATA_VIRTUAL_REG;
}
address = (bus << 16) | (dev << 11) | (func << 8) |
(offset & 0xfc) | 0x80000000;
/* start the configuration cycle */
MV_WRITE(address_reg, address);
/* write the data */
MV_WRITE_8(data_reg + (offset & 0x3), val);
return PCIBIOS_SUCCESSFUL;
}
static void marvell_pcibios_set_master(struct pci_dev *dev)
{
u16 cmd;
marvell_pcibios_read_config_word(dev, PCI_COMMAND, &cmd);
cmd |= PCI_COMMAND_MASTER;
marvell_pcibios_write_config_word(dev, PCI_COMMAND, cmd);
}
/* Externally-expected functions. Do not change function names */
int pcibios_enable_resources(struct pci_dev *dev)
{
u16 cmd, old_cmd;
u8 tmp1;
int idx;
struct resource *r;
marvell_pcibios_read_config_word(dev, PCI_COMMAND, &cmd);
old_cmd = cmd;
for (idx = 0; idx < 6; idx++) {
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 (cmd != old_cmd) {
marvell_pcibios_write_config_word(dev, PCI_COMMAND, cmd);
}
/*
* Let's fix up the latency timer and cache line size here. Cache
* line size = 32 bytes / sizeof dword (4) = 8.
* Latency timer must be > 8. 32 is random but appears to work.
*/
marvell_pcibios_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &tmp1);
if (tmp1 != 8) {
printk(KERN_WARNING
"PCI setting cache line size to 8 from " "%d\n",
tmp1);
marvell_pcibios_write_config_byte(dev, PCI_CACHE_LINE_SIZE,
8);
}
marvell_pcibios_read_config_byte(dev, PCI_LATENCY_TIMER, &tmp1);
if (tmp1 < 32) {
printk(KERN_WARNING
"PCI setting latency timer to 32 from %d\n", tmp1);
marvell_pcibios_write_config_byte(dev, PCI_LATENCY_TIMER,
32);
}
return 0;
}
int pcibios_enable_device(struct pci_dev *dev, int mask)
{
return pcibios_enable_resources(dev);
}
void pcibios_align_resource(void *data, struct resource *res,
unsigned long size)
{
struct pci_dev *dev = data;
if (res->flags & IORESOURCE_IO) {
unsigned long start = res->start;
/* We need to avoid collisions with `mirrored' VGA ports
and other strange ISA hardware, so we always want the
addresses kilobyte aligned. */
if (size > 0x100) {
printk(KERN_ERR "PCI: I/O Region %s/%d too large"
" (%ld bytes)\n", dev->slot_name,
dev->resource - res, size);
}
start = (start + 1024 - 1) & ~(1024 - 1);
res->start = start;
}
}
struct pci_ops marvell_pci_ops = {
marvell_pcibios_read_config_byte,
marvell_pcibios_read_config_word,
marvell_pcibios_read_config_dword,
marvell_pcibios_write_config_byte,
marvell_pcibios_write_config_word,
marvell_pcibios_write_config_dword
};
struct pci_fixup pcibios_fixups[] = {
{0}
};
void __init pcibios_fixup_bus(struct pci_bus *c)
{
mv64340_board_pcibios_fixup_bus(c);
}
void __init pcibios_init(void)
{
/* Reset PCI I/O and PCI MEM values */
ioport_resource.start = 0xe0000000;
ioport_resource.end = 0xe0000000 + 0x20000000 - 1;
iomem_resource.start = 0xc0000000;
iomem_resource.end = 0xc0000000 + 0x20000000 - 1;
pci_scan_bus(0, &marvell_pci_ops, NULL);
pci_scan_bus(1, &marvell_pci_ops, NULL);
}
/*
* for parsing "pci=" kernel boot arguments.
*/
char *pcibios_setup(char *str)
{
printk(KERN_INFO "rr: pcibios_setup\n");
/* Nothing to do for now. */
return str;
}
unsigned __init int pcibios_assign_all_busses(void)
{
return 1;
}
/*
* Copyright 2002 Momentum Computer
* Author: Matthew Dharm <mdharm@momenco.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/version.h>
#include <asm/pci.h>
#include <asm/io.h>
#include "gt64240.h"
#include <linux/init.h>
#define SELF 0
#define MASTER_ABORT_BIT 0x100
/*
* These functions and structures provide the BIOS scan and mapping of the PCI
* devices.
*/
#define MAX_PCI_DEVS 10
void gt64240_board_pcibios_fixup_bus(struct pci_bus *c);
/* Functions to implement "pci ops" */
static int galileo_pcibios_read_config_word(int bus, int devfn,
int offset, u16 * val);
static int galileo_pcibios_read_config_byte(int bus, int devfn,
int offset, u8 * val);
static int galileo_pcibios_read_config_dword(int bus, int devfn,
int offset, u32 * val);
static int galileo_pcibios_write_config_byte(int bus, int devfn,
int offset, u8 val);
static int galileo_pcibios_write_config_word(int bus, int devfn,
int offset, u16 val);
static int galileo_pcibios_write_config_dword(int bus, int devfn,
int offset, u32 val);
#if 0
static void galileo_pcibios_set_master(struct pci_dev *dev);
#endif
static int pci_read(struct pci_bus *bus, unsigned int devfs, int where,
int size, u32 * val);
static int pci_write(struct pci_bus *bus, unsigned int devfs, int where,
int size, u32 val);
/*
* General-purpose PCI functions.
*/
/*
* pci_range_ck -
*
* Check if the pci device that are trying to access does really exists
* on the evaluation board.
*
* Inputs :
* bus - bus number (0 for PCI 0 ; 1 for PCI 1)
* dev - number of device on the specific pci bus
*
* Outpus :
* 0 - if OK , 1 - if failure
*/
static __inline__ int pci_range_ck(unsigned char bus, unsigned char dev)
{
/* Accessing device 31 crashes the GT-64240. */
if (dev < 5)
return 0;
return -1;
}
/*
* galileo_pcibios_(read/write)_config_(dword/word/byte) -
*
* reads/write a dword/word/byte register from the configuration space
* of a device.
*
* Note that bus 0 and bus 1 are local, and we assume all other busses are
* bridged from bus 1. This is a safe assumption, since any other
* configuration will require major modifications to the CP7000G
*
* Inputs :
* bus - bus number
* dev - device number
* offset - register offset in the configuration space
* val - value to be written / read
*
* Outputs :
* PCIBIOS_SUCCESSFUL when operation was succesfull
* PCIBIOS_DEVICE_NOT_FOUND when the bus or dev is errorneous
* PCIBIOS_BAD_REGISTER_NUMBER when accessing non aligned
*/
static int galileo_pcibios_read_config_dword(int bus, int devfn,
int offset, u32 * val)
{
int dev, func;
uint32_t address_reg, data_reg;
uint32_t address;
dev = PCI_SLOT(devfn);
func = PCI_FUNC(devfn);
/* verify the range */
if (pci_range_ck(bus, dev))
return PCIBIOS_DEVICE_NOT_FOUND;
/* select the GT-64240 registers to communicate with the PCI bus */
if (bus == 0) {
address_reg = PCI_0CONFIGURATION_ADDRESS;
data_reg = PCI_0CONFIGURATION_DATA_VIRTUAL_REGISTER;
GT_WRITE(PCI_0ERROR_CAUSE, ~MASTER_ABORT_BIT);
} else {
address_reg = PCI_1CONFIGURATION_ADDRESS;
data_reg = PCI_1CONFIGURATION_DATA_VIRTUAL_REGISTER;
GT_WRITE(PCI_1ERROR_CAUSE, ~MASTER_ABORT_BIT);
if (bus == 1)
bus = 0;
}
address = (bus << 16) | (dev << 11) | (func << 8) |
(offset & 0xfc) | 0x80000000;
/* start the configuration cycle */
GT_WRITE(address_reg, address);
/* read the data */
GT_READ(data_reg, val);
return PCIBIOS_SUCCESSFUL;
}
static int galileo_pcibios_read_config_word(int bus, int devfn,
int offset, u16 * val)
{
int dev, func;
uint32_t address_reg, data_reg;
uint32_t address;
dev = PCI_SLOT(devfn);
func = PCI_FUNC(devfn);
/* verify the range */
if (pci_range_ck(bus, dev))
return PCIBIOS_DEVICE_NOT_FOUND;
/* select the GT-64240 registers to communicate with the PCI bus */
if (bus == 0) {
address_reg = PCI_0CONFIGURATION_ADDRESS;
data_reg = PCI_0CONFIGURATION_DATA_VIRTUAL_REGISTER;
GT_WRITE(PCI_0ERROR_CAUSE, ~MASTER_ABORT_BIT);
} else {
address_reg = PCI_1CONFIGURATION_ADDRESS;
data_reg = PCI_1CONFIGURATION_DATA_VIRTUAL_REGISTER;
GT_WRITE(PCI_1ERROR_CAUSE, ~MASTER_ABORT_BIT);
if (bus == 1)
bus = 0;
}
address = (bus << 16) | (dev << 11) | (func << 8) |
(offset & 0xfc) | 0x80000000;
/* start the configuration cycle */
GT_WRITE(address_reg, address);
/* read the data */
GT_READ_16(data_reg + (offset & 0x3), val);
return PCIBIOS_SUCCESSFUL;
}
static int galileo_pcibios_read_config_byte(int bus, int devfn,
int offset, u8 * val)
{
int dev, func;
uint32_t address_reg, data_reg;
uint32_t address;
dev = PCI_SLOT(devfn);
func = PCI_FUNC(devfn);
/* verify the range */
if (pci_range_ck(bus, dev))
return PCIBIOS_DEVICE_NOT_FOUND;
/* select the GT-64240 registers to communicate with the PCI bus */
if (bus == 0) {
address_reg = PCI_0CONFIGURATION_ADDRESS;
data_reg = PCI_0CONFIGURATION_DATA_VIRTUAL_REGISTER;
} else {
address_reg = PCI_1CONFIGURATION_ADDRESS;
data_reg = PCI_1CONFIGURATION_DATA_VIRTUAL_REGISTER;
if (bus == 1)
bus = 0;
}
address = (bus << 16) | (dev << 11) | (func << 8) |
(offset & 0xfc) | 0x80000000;
/* start the configuration cycle */
GT_WRITE(address_reg, address);
/* write the data */
GT_READ_8(data_reg + (offset & 0x3), val);
return PCIBIOS_SUCCESSFUL;
}
static int galileo_pcibios_write_config_dword(int bus, int devfn,
int offset, u32 val)
{
int dev, func;
uint32_t address_reg, data_reg;
uint32_t address;
dev = PCI_SLOT(devfn);
func = PCI_FUNC(devfn);
/* verify the range */
if (pci_range_ck(bus, dev))
return PCIBIOS_DEVICE_NOT_FOUND;
/* select the GT-64240 registers to communicate with the PCI bus */
if (bus == 0) {
address_reg = PCI_0CONFIGURATION_ADDRESS;
data_reg = PCI_0CONFIGURATION_DATA_VIRTUAL_REGISTER;
} else {
address_reg = PCI_1CONFIGURATION_ADDRESS;
data_reg = PCI_1CONFIGURATION_DATA_VIRTUAL_REGISTER;
if (bus == 1)
bus = 0;
}
address = (bus << 16) | (dev << 11) | (func << 8) |
(offset & 0xfc) | 0x80000000;
/* start the configuration cycle */
GT_WRITE(address_reg, address);
/* write the data */
GT_WRITE(data_reg, val);
return PCIBIOS_SUCCESSFUL;
}
static int galileo_pcibios_write_config_word(int bus, int devfn,
int offset, u16 val)
{
int dev, func;
uint32_t address_reg, data_reg;
uint32_t address;
dev = PCI_SLOT(devfn);
func = PCI_FUNC(devfn);
/* verify the range */
if (pci_range_ck(bus, dev))
return PCIBIOS_DEVICE_NOT_FOUND;
/* select the GT-64240 registers to communicate with the PCI bus */
if (bus == 0) {
address_reg = PCI_0CONFIGURATION_ADDRESS;
data_reg = PCI_0CONFIGURATION_DATA_VIRTUAL_REGISTER;
} else {
address_reg = PCI_1CONFIGURATION_ADDRESS;
data_reg = PCI_1CONFIGURATION_DATA_VIRTUAL_REGISTER;
if (bus == 1)
bus = 0;
}
address = (bus << 16) | (dev << 11) | (func << 8) |
(offset & 0xfc) | 0x80000000;
/* start the configuration cycle */
GT_WRITE(address_reg, address);
/* write the data */
GT_WRITE_16(data_reg + (offset & 0x3), val);
return PCIBIOS_SUCCESSFUL;
}
static int galileo_pcibios_write_config_byte(int bus, int devfn,
int offset, u8 val)
{
int dev, func;
uint32_t address_reg, data_reg;
uint32_t address;
dev = PCI_SLOT(devfn);
func = PCI_FUNC(devfn);
/* verify the range */
if (pci_range_ck(bus, dev))
return PCIBIOS_DEVICE_NOT_FOUND;
/* select the GT-64240 registers to communicate with the PCI bus */
if (bus == 0) {
address_reg = PCI_0CONFIGURATION_ADDRESS;
data_reg = PCI_0CONFIGURATION_DATA_VIRTUAL_REGISTER;
} else {
address_reg = PCI_1CONFIGURATION_ADDRESS;
data_reg = PCI_1CONFIGURATION_DATA_VIRTUAL_REGISTER;
if (bus == 1)
bus = 0;
}
address = (bus << 16) | (dev << 11) | (func << 8) |
(offset & 0xfc) | 0x80000000;
/* start the configuration cycle */
GT_WRITE(address_reg, address);
/* write the data */
GT_WRITE_8(data_reg + (offset & 0x3), val);
return PCIBIOS_SUCCESSFUL;
}
#if 0
static void galileo_pcibios_set_master(struct pci_dev *dev)
{
u16 cmd;
galileo_pcibios_read_config_word(dev, PCI_COMMAND, &cmd);
cmd |= PCI_COMMAND_MASTER;
galileo_pcibios_write_config_word(dev, PCI_COMMAND, cmd);
}
#endif
/* Externally-expected functions. Do not change function names */
int pcibios_enable_resources(struct pci_dev *dev)
{
u16 cmd, old_cmd;
u8 tmp1;
int idx;
struct resource *r;
pci_read(dev->bus, dev->devfn, PCI_COMMAND, 2, (u32 *) & cmd);
old_cmd = cmd;
for (idx = 0; idx < 6; idx++) {
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 (cmd != old_cmd) {
pci_write(dev->bus, dev->devfn, PCI_COMMAND, 2, cmd);
}
/*
* Let's fix up the latency timer and cache line size here. Cache
* line size = 32 bytes / sizeof dword (4) = 8.
* Latency timer must be > 8. 32 is random but appears to work.
*/
pci_read(dev->bus, dev->devfn, PCI_CACHE_LINE_SIZE, 1,
(u32 *) & tmp1);
if (tmp1 != 8) {
printk(KERN_WARNING
"PCI setting cache line size to 8 from " "%d\n",
tmp1);
pci_write(dev->bus, dev->devfn, PCI_CACHE_LINE_SIZE, 1, 8);
}
pci_read(dev->bus, dev->devfn, PCI_LATENCY_TIMER, 1,
(u32 *) & tmp1);
if (tmp1 < 32) {
printk(KERN_WARNING
"PCI setting latency timer to 32 from %d\n", tmp1);
pci_write(dev->bus, dev->devfn, PCI_LATENCY_TIMER, 1, 32);
}
return 0;
}
int pcibios_enable_device(struct pci_dev *dev, int mask)
{
return pcibios_enable_resources(dev);
}
void pcibios_align_resource(void *data, struct resource *res,
unsigned long size, unsigned long align)
{
struct pci_dev *dev = data;
if (res->flags & IORESOURCE_IO) {
unsigned long start = res->start;
/* We need to avoid collisions with `mirrored' VGA ports
and other strange ISA hardware, so we always want the
addresses kilobyte aligned. */
if (size > 0x100) {
printk(KERN_ERR "PCI: I/O Region %s/%d too large"
" (%ld bytes)\n", dev->slot_name,
dev->resource - res, size);
}
start = (start + 1024 - 1) & ~(1024 - 1);
res->start = start;
}
}
struct pci_ops galileo_pci_ops = {
.read = pci_read,
.write = pci_write
};
static int pci_read(struct pci_bus *bus, unsigned int devfn, int where,
int size, u32 * val)
{
switch (size) {
case 1:
return galileo_pcibios_read_config_byte(bus->number,
devfn, where,
(u8 *) val);
case 2:
return galileo_pcibios_read_config_word(bus->number,
devfn, where,
(u16 *) val);
case 4:
return galileo_pcibios_read_config_dword(bus->number,
devfn, where,
(u32 *) val);
}
return PCIBIOS_FUNC_NOT_SUPPORTED;
}
static int pci_write(struct pci_bus *bus, unsigned int devfn, int where,
int size, u32 val)
{
switch (size) {
case 1:
return galileo_pcibios_write_config_byte(bus->number,
devfn, where,
val);
case 2:
return galileo_pcibios_write_config_word(bus->number,
devfn, where,
val);
case 4:
return galileo_pcibios_write_config_dword(bus->number,
devfn, where,
val);
}
return PCIBIOS_FUNC_NOT_SUPPORTED;
}
struct pci_fixup pcibios_fixups[] = {
{0}
};
void __devinit pcibios_fixup_bus(struct pci_bus *c)
{
gt64240_board_pcibios_fixup_bus(c);
}
/********************************************************************
* pci0P2PConfig - This function set the PCI_0 P2P configurate.
* For more information on the P2P read PCI spec.
*
* Inputs: unsigned int SecondBusLow - Secondery PCI interface Bus Range Lower
* Boundry.
* unsigned int SecondBusHigh - Secondry PCI interface Bus Range upper
* Boundry.
* unsigned int busNum - The CPI bus number to which the PCI interface
* is connected.
* unsigned int devNum - The PCI interface's device number.
*
* Returns: true.
*/
void pci0P2PConfig(unsigned int SecondBusLow, unsigned int SecondBusHigh,
unsigned int busNum, unsigned int devNum)
{
uint32_t regData;
regData = (SecondBusLow & 0xff) | ((SecondBusHigh & 0xff) << 8) |
((busNum & 0xff) << 16) | ((devNum & 0x1f) << 24);
GT_WRITE(PCI_0P2P_CONFIGURATION, regData);
}
/********************************************************************
* pci1P2PConfig - This function set the PCI_1 P2P configurate.
* For more information on the P2P read PCI spec.
*
* Inputs: unsigned int SecondBusLow - Secondery PCI interface Bus Range Lower
* Boundry.
* unsigned int SecondBusHigh - Secondry PCI interface Bus Range upper
* Boundry.
* unsigned int busNum - The CPI bus number to which the PCI interface
* is connected.
* unsigned int devNum - The PCI interface's device number.
*
* Returns: true.
*/
void pci1P2PConfig(unsigned int SecondBusLow, unsigned int SecondBusHigh,
unsigned int busNum, unsigned int devNum)
{
uint32_t regData;
regData = (SecondBusLow & 0xff) | ((SecondBusHigh & 0xff) << 8) |
((busNum & 0xff) << 16) | ((devNum & 0x1f) << 24);
GT_WRITE(PCI_1P2P_CONFIGURATION, regData);
}
#define PCI0_STATUS_COMMAND_REG 0x4
#define PCI1_STATUS_COMMAND_REG 0x84
static int __init pcibios_init(void)
{
/* Reset PCI I/O and PCI MEM values */
ioport_resource.start = 0xe0000000;
ioport_resource.end = 0xe0000000 + 0x20000000 - 1;
iomem_resource.start = 0xc0000000;
iomem_resource.end = 0xc0000000 + 0x20000000 - 1;
pci_scan_bus(0, &galileo_pci_ops, NULL);
pci_scan_bus(1, &galileo_pci_ops, NULL);
return 0;
}
subsys_initcall(pcibios_init);
/*
* for parsing "pci=" kernel boot arguments.
*/
char *pcibios_setup(char *str)
{
printk(KERN_INFO "rr: pcibios_setup\n");
/* Nothing to do for now. */
return str;
}
unsigned __init int pcibios_assign_all_busses(void)
{
return 1;
}
/*
* Copyright (C) 2001,2002 Broadcom Corporation
*
* 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 <asm/sibyte/sb1250_defs.h>
#include <asm/sibyte/sb1250_regs.h>
#include <asm/sibyte/sb1250_scd.h>
#include <asm/io.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;
}
/*
* 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));
WRITECFG32(cfgaddr, data);
return PCIBIOS_SUCCESSFUL;
}
struct pci_ops sb1250_pci_ops = {
.read = sb1250_pcibios_read,
.write = sb1250_pcibios_write
};
void __init pcibios_init(void)
{
uint32_t cmdreg;
uint64_t reg;
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 *) KSEG1ADDR(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;
}
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
/* Probe for PCI hardware */
printk("PCI: Probing PCI hardware on host bus 0.\n");
pci_scan_bus(0, &sb1250_pci_ops, NULL);
#ifdef CONFIG_VGA_CONSOLE
take_over_console(&vga_con, 0, MAX_NR_CONSOLES - 1, 1);
#endif
}
int pcibios_enable_device(struct pci_dev *dev, int mask)
{
/* Not needed, since we enable all devices at startup. */
return 0;
}
void pcibios_align_resource(void *data, struct resource *res,
unsigned long size, unsigned long align)
{
}
char *__init pcibios_setup(char *str)
{
/* Nothing to do for now. */
return str;
}
struct pci_fixup pcibios_fixups[] = {
{0}
};
/*
* Called after each bus is probed, but before its children
* are examined.
*/
void __devinit pcibios_fixup_bus(struct pci_bus *b)
{
pci_read_bridge_bases(b);
}
unsigned int pcibios_assign_all_busses(void)
{
return 1;
}
/*
* 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 Ralf Baechle
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/types.h>
#include <asm/byteorder.h>
#include <asm/sni.h>
#define mkaddr(bus, devfn, where) \
do { \
if (bus->number == 0) \
return -1; \
*(volatile u32 *)PCIMT_CONFIG_ADDRESS = \
((bus->number & 0xff) << 0x10) | \
((devfn & 0xff) << 0x08) | \
(where & 0xfc); \
} while(0)
#if 0
/* To do: Bring this uptodate ... */
static void pcimt_pcibios_fixup(void)
{
struct pci_dev *dev = NULL;
while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
/*
* TODO: Take care of RM300 revision D boards for where the
* network slot became an ordinary PCI slot.
*/
if (dev->devfn == PCI_DEVFN(1, 0)) {
/* Evil hack ... */
set_cp0_config(CONF_CM_CMASK,
CONF_CM_CACHABLE_NO_WA);
dev->irq = PCIMT_IRQ_SCSI;
continue;
}
if (dev->devfn == PCI_DEVFN(2, 0)) {
dev->irq = PCIMT_IRQ_ETHERNET;
continue;
}
switch (dev->irq) {
case 1...4:
dev->irq += PCIMT_IRQ_INTA - 1;
break;
case 0:
break;
default:
printk("PCI device on bus %d, dev %d, function %d "
"impossible interrupt configured.\n",
dev->bus->number, PCI_SLOT(dev->devfn),
PCI_SLOT(dev->devfn));
}
}
}
#endif
/*
* 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 pcimt_read(struct pci_bus *bus, unsigned int devfn, int where,
int size, u32 * val)
{
u32 res;
switch (size) {
case 1:
mkaddr(bus, devfn, where);
res = *(volatile u32 *) PCIMT_CONFIG_DATA;
res = (le32_to_cpu(res) >> ((where & 3) << 3)) & 0xff;
*val = (u8) res;
break;
case 2:
if (where & 1)
return PCIBIOS_BAD_REGISTER_NUMBER;
mkaddr(bus, devfn, where);
res = *(volatile u32 *) PCIMT_CONFIG_DATA;
res = (le32_to_cpu(res) >> ((where & 3) << 3)) & 0xffff;
*val = (u16) res;
break;
case 4:
if (where & 3)
return PCIBIOS_BAD_REGISTER_NUMBER;
mkaddr(bus, devfn, where);
res = *(volatile u32 *) PCIMT_CONFIG_DATA;
res = le32_to_cpu(res);
*val = res;
break;
}
return PCIBIOS_SUCCESSFUL;
}
static int pcimt_write(struct pci_bus *bus, unsigned int devfn, int where,
int size, u32 val)
{
switch (size) {
case 1:
mkaddr(bus, devfn, where);
*(volatile u8 *) (PCIMT_CONFIG_DATA + (where & 3)) =
(u8) le32_to_cpu(val);
break;
case 2:
if (where & 1)
return PCIBIOS_BAD_REGISTER_NUMBER;
mkaddr(bus, devfn, where);
*(volatile u16 *) (PCIMT_CONFIG_DATA + (where & 3)) =
(u16) le32_to_cpu(val);
break;
case 4:
if (where & 3)
return PCIBIOS_BAD_REGISTER_NUMBER;
mkaddr(bus, devfn, where);
*(volatile u32 *) PCIMT_CONFIG_DATA = le32_to_cpu(val);
break;
}
return PCIBIOS_SUCCESSFUL;
}
struct pci_ops sni_pci_ops = {
.read = pcimt_read,
.write = pcimt_write,
};
void __devinit pcibios_fixup_bus(struct pci_bus *b)
{
}
static int __init pcibios_init(void)
{
struct pci_ops *ops = &sni_pci_ops;
pci_scan_bus(0, ops, NULL);
return 0;
}
subsys_initcall(pcibios_init);
int __init pcibios_enable_device(struct pci_dev *dev, int mask)
{
/* Not needed, since we enable all devices at startup. */
return 0;
}
void pcibios_align_resource(void *data, struct resource *res,
unsigned long size, unsigned long align)
{
}
unsigned __init int pcibios_assign_all_busses(void)
{
return 0;
}
char *__init pcibios_setup(char *str)
{
/* Nothing to do for now. */
return str;
}
struct pci_fixup pcibios_fixups[] = {
{0}
};
/*
* FILE NAME
* arch/mips/vr41xx/common/pciu.c
*
* BRIEF MODULE DESCRIPTION
* PCI Control Unit routines for the NEC VR4100 series.
*
* 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:
* Paul Mundt <lethal@chaoticdreams.org>
* - Fix deadlock-causing PCIU access race for VR4131.
*
* MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
* - New creation, NEC VR4122 and VR4131 are supported.
*/
#include <linux/config.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <asm/cpu.h>
#include <asm/io.h>
#include <asm/pci_channel.h>
#include <asm/vr41xx/vr41xx.h>
#include "pciu.h"
extern unsigned long vr41xx_vtclock;
static inline int vr41xx_pci_config_access(unsigned char bus,
unsigned int devfn, int where)
{
if (bus == 0) {
/*
* Type 0 configuration
*/
if (PCI_SLOT(devfn) < 11 || where > 255)
return -1;
writel((1UL << PCI_SLOT(devfn)) |
(PCI_FUNC(devfn) << 8) |
(where & 0xfc), PCICONFAREG);
} else {
/*
* Type 1 configuration
*/
if (where > 255)
return -1;
writel((bus << 16) |
(devfn << 8) | (where & 0xfc) | 1UL, PCICONFAREG);
}
return 0;
}
static int vr41xx_pci_config_read(struct pci_bus *bus, unsigned int devfn,
int where, int size, u32 * val)
{
u32 data;
*val = 0xffffffffUL;
if (vr41xx_pci_config_access(bus->number, devfn, where) < 0)
return PCIBIOS_DEVICE_NOT_FOUND;
data = readl(PCICONFDREG);
switch (size) {
case 1:
*val = (data >> ((where & 3) << 3)) & 0xffUL;
break;
case 2:
*val = (data >> ((where & 2) << 3)) & 0xffffUL;
break;
case 4:
*val = data;
break;
default:
return PCIBIOS_FUNC_NOT_SUPPORTED;
}
return PCIBIOS_SUCCESSFUL;
}
static int vr41xx_pci_config_write(struct pci_bus *bus, unsigned int devfn,
int where, int size, u32 val)
{
u32 data;
int shift;
if (vr41xx_pci_config_access(bus->number, devfn, where) < 0)
return PCIBIOS_DEVICE_NOT_FOUND;
data = readl(PCICONFDREG);
switch (size) {
case 1:
shift = (where & 3) << 3;
data &= ~(0xff << shift);
data |= ((val & 0xff) << shift);
break;
case 2:
shift = (where & 2) << 3;
data &= ~(0xffff << shift);
data |= ((val & 0xffff) << 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 = vr41xx_pci_config_read,
.write = vr41xx_pci_config_write,
};
void __init vr41xx_pciu_init(struct vr41xx_pci_address_map *map)
{
struct vr41xx_pci_address_space *s;
u32 config;
int n;
if (!map)
return;
/* Disable PCI interrupt */
writew(0, MPCIINTREG);
/* Supply VTClock to PCIU */
vr41xx_clock_supply(PCIU_CLOCK);
/*
* Sleep for 1us after setting MSKPPCIU bit in CMUCLKMSK
* before doing any PCIU access to avoid deadlock on VR4131.
*/
udelay(1);
/* Select PCI clock */
if (vr41xx_vtclock < MAX_PCI_CLOCK)
writel(EQUAL_VTCLOCK, PCICLKSELREG);
else if ((vr41xx_vtclock / 2) < MAX_PCI_CLOCK)
writel(HALF_VTCLOCK, PCICLKSELREG);
else if ((vr41xx_vtclock / 4) < MAX_PCI_CLOCK)
writel(QUARTER_VTCLOCK, PCICLKSELREG);
else
printk(KERN_INFO "Warning: PCI Clock is over 33MHz.\n");
/* Supply PCI clock by PCI bus */
vr41xx_clock_supply(PCI_CLOCK);
/*
* Set PCI memory & I/O space address conversion registers
* for master transaction.
*/
if (map->mem1 != NULL) {
s = map->mem1;
config = (s->internal_base & 0xff000000) |
((s->address_mask & 0x7f000000) >> 11) | (1UL << 12) |
((s->pci_base & 0xff000000) >> 24);
writel(config, PCIMMAW1REG);
}
if (map->mem2 != NULL) {
s = map->mem2;
config = (s->internal_base & 0xff000000) |
((s->address_mask & 0x7f000000) >> 11) | (1UL << 12) |
((s->pci_base & 0xff000000) >> 24);
writel(config, PCIMMAW2REG);
}
if (map->io != NULL) {
s = map->io;
config = (s->internal_base & 0xff000000) |
((s->address_mask & 0x7f000000) >> 11) | (1UL << 12) |
((s->pci_base & 0xff000000) >> 24);
writel(config, PCIMIOAWREG);
}
/* Set target memory windows */
writel(0x00081000, PCITAW1REG);
writel(0UL, PCITAW2REG);
pciu_write_config_dword(PCI_BASE_ADDRESS_0, 0UL);
pciu_write_config_dword(PCI_BASE_ADDRESS_1, 0UL);
/* Clear bus error */
n = readl(BUSERRADREG);
if (current_cpu_data.cputype == CPU_VR4122) {
writel(0UL, PCITRDYVREG);
pciu_write_config_dword(PCI_CACHE_LINE_SIZE, 0x0000f804);
} else {
writel(100UL, PCITRDYVREG);
pciu_write_config_dword(PCI_CACHE_LINE_SIZE, 0x00008004);
}
writel(CONFIG_DONE, PCIENREG);
pciu_write_config_dword(PCI_COMMAND,
PCI_COMMAND_IO |
PCI_COMMAND_MEMORY |
PCI_COMMAND_MASTER |
PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
}
/*
* FILE NAME
* arch/mips/vr41xx/common/pciu.h
*
* BRIEF MODULE DESCRIPTION
* Include file for PCI Control Unit of the NEC VR4100 series.
*
* Author: Yoichi Yuasa
* yyuasa@mvista.com or source@mvista.com
*
* Copyright 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>
* - New creation, NEC VR4122 and VR4131 are supported.
*/
#ifndef __VR41XX_PCIU_H
#define __VR41XX_PCIU_H
#include <linux/config.h>
#include <asm/addrspace.h>
#define BIT(x) (1 << (x))
#define PCIMMAW1REG KSEG1ADDR(0x0f000c00)
#define PCIMMAW2REG KSEG1ADDR(0x0f000c04)
#define PCITAW1REG KSEG1ADDR(0x0f000c08)
#define PCITAW2REG KSEG1ADDR(0x0f000c0c)
#define PCIMIOAWREG KSEG1ADDR(0x0f000c10)
#define INTERNAL_BUS_BASE_ADDRESS 0xff000000
#define ADDRESS_MASK 0x000fe000
#define PCI_ACCESS_ENABLE BIT(12)
#define PCI_ADDRESS_SETTING 0x000000ff
#define PCICONFDREG KSEG1ADDR(0x0f000c14)
#define PCICONFAREG KSEG1ADDR(0x0f000c18)
#define PCIMAILREG KSEG1ADDR(0x0f000c1c)
#define BUSERRADREG KSEG1ADDR(0x0f000c24)
#define ERROR_ADDRESS 0xfffffffc
#define INTCNTSTAREG KSEG1ADDR(0x0f000c28)
#define MABTCLR BIT(31)
#define TRDYCLR BIT(30)
#define PARCLR BIT(29)
#define MBCLR BIT(28)
#define SERRCLR BIT(27)
#define PCIEXACCREG KSEG1ADDR(0x0f000c2c)
#define UNLOCK BIT(1)
#define EAREQ BIT(0)
#define PCIRECONTREG KSEG1ADDR(0x0f000c30)
#define RTRYCNT 0x000000ff
#define PCIENREG KSEG1ADDR(0x0f000c34)
#define CONFIG_DONE BIT(2)
#define PCICLKSELREG KSEG1ADDR(0x0f000c38)
#define EQUAL_VTCLOCK 0x00000002
#define HALF_VTCLOCK 0x00000000
#define QUARTER_VTCLOCK 0x00000001
#define PCITRDYVREG KSEG1ADDR(0x0f000c3c)
#define PCICLKRUNREG KSEG1ADDR(0x0f000c60)
#define PCIU_CONFIGREGS_BASE KSEG1ADDR(0x0f000d00)
#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 MAILBAREG KSEG1ADDR(0x0f000d10)
#define PCIMBA1REG KSEG1ADDR(0x0f000d14)
#define PCIMBA2REG KSEG1ADDR(0x0f000d18)
#define INTLINEREG KSEG1ADDR(0x0f000d3c)
#define INTPINREG KSEG1ADDR(0x0f000d3c)
#define RETVALREG KSEG1ADDR(0x0f000d40)
#define PCIAPCNTREG KSEG1ADDR(0x0f000d40)
#define MPCIINTREG KSEG1ADDR(0x0f0000b2)
#define MAX_PCI_CLOCK 33333333
#define PCIU_CLOCK 0x0080
#define PCI_CLOCK 0x2000
static inline int pciu_read_config_byte(int where, u8 * val)
{
u32 data;
data = readl(PCIU_CONFIGREGS_BASE + where);
*val = (u8) (data >> ((where & 3) << 3));
return PCIBIOS_SUCCESSFUL;
}
static inline int pciu_read_config_word(int where, u16 * val)
{
u32 data;
if (where & 1)
return PCIBIOS_BAD_REGISTER_NUMBER;
data = readl(PCIU_CONFIGREGS_BASE + where);
*val = (u16) (data >> ((where & 2) << 3));
return PCIBIOS_SUCCESSFUL;
}
static inline int pciu_read_config_dword(int where, u32 * val)
{
if (where & 3)
return PCIBIOS_BAD_REGISTER_NUMBER;
*val = readl(PCIU_CONFIGREGS_BASE + where);
return PCIBIOS_SUCCESSFUL;
}
static inline int pciu_write_config_byte(int where, u8 val)
{
writel(val, PCIU_CONFIGREGS_BASE + where);
return 0;
}
static inline int pciu_write_config_word(int where, u16 val)
{
writel(val, PCIU_CONFIGREGS_BASE + where);
return 0;
}
static inline int pciu_write_config_dword(int where, u32 val)
{
writel(val, PCIU_CONFIGREGS_BASE + where);
return 0;
}
#endif /* __VR41XX_PCIU_H */
/*
* Copyright 2001 MontaVista Software Inc.
* Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
*
* Modified to be mips generic, ppopov@mvista.com
* arch/mips/kernel/pci.c
* Common MIPS PCI routines.
*
* 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 file contains common PCI routines meant to be shared for
* all MIPS machines.
*
* Strategies:
*
* . We rely on pci_auto.c file to assign PCI resources (MEM and IO)
* TODO: this should be optional for some machines where they do have
* a real "pcibios" that does resource assignment.
*
* . We then use pci_scan_bus() to "discover" all the resources for
* later use by Linux.
*
* . We finally reply on a board supplied function, pcibios_fixup_irq(), to
* to assign the interrupts. We may use setup-irq.c under drivers/pci
* later.
*
* . Specifically, we will *NOT* use pci_assign_unassigned_resources(),
* because we assume all PCI devices should have the resources correctly
* assigned and recorded.
*
* Limitations:
*
* . We "collapse" all IO and MEM spaces in sub-buses under a top-level bus
* into a contiguous range.
*
* . In the case of Memory space, the rnage is 1:1 mapping with CPU physical
* address space.
*
* . In the case of IO space, it starts from 0, and the beginning address
* is mapped to KSEG0ADDR(mips_io_port) in the CPU physical address.
*
* . These are the current MIPS limitations (by ioremap, etc). In the
* future, we may remove them.
*
* Credits:
* Most of the code are derived from the pci routines from PPC and Alpha,
* which were mostly writtne by
* Cort Dougan, cort@fsmlabs.com
* Matt Porter, mporter@mvista.com
* Dave Rusling david.rusling@reo.mts.dec.com
* David Mosberger davidm@cs.arizona.edu
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <asm/pci_channel.h>
extern void pcibios_fixup(void);
extern void pcibios_fixup_irqs(void);
void __init pcibios_fixup_irqs(void)
{
struct pci_dev *dev = NULL;
int slot_num;
while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
slot_num = PCI_SLOT(dev->devfn);
switch (slot_num) {
case 2:
dev->irq = 3;
break;
case 3:
dev->irq = 4;
break;
case 4:
dev->irq = 5;
break;
default:
break;
}
}
}
void __init pcibios_fixup_resources(struct pci_dev *dev)
{ /* HP-LJ */
int pos;
int bases;
printk("adjusting pci device: %s\n", dev->name);
switch (dev->hdr_type) {
case PCI_HEADER_TYPE_NORMAL:
bases = 6;
break;
case PCI_HEADER_TYPE_BRIDGE:
bases = 2;
break;
case PCI_HEADER_TYPE_CARDBUS:
bases = 1;
break;
default:
bases = 0;
break;
}
for (pos = 0; pos < bases; pos++) {
struct resource *res = &dev->resource[pos];
if (res->start >= IO_MEM_LOGICAL_START &&
res->end <= IO_MEM_LOGICAL_END) {
res->start += IO_MEM_VIRTUAL_OFFSET;
res->end += IO_MEM_VIRTUAL_OFFSET;
}
if (res->start >= IO_PORT_LOGICAL_START &&
res->end <= IO_PORT_LOGICAL_END) {
res->start += IO_PORT_VIRTUAL_OFFSET;
res->end += IO_PORT_VIRTUAL_OFFSET;
}
}
}
struct pci_fixup pcibios_fixups[] = {
{PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID,
pcibios_fixup_resources},
{0}
};
extern int pciauto_assign_resources(int busno, struct pci_channel *hose);
static int __init pcibios_init(void)
{
struct pci_channel *p;
struct pci_bus *bus;
int busno;
#ifdef CONFIG_PCI_AUTO
/* assign resources */
busno = 0;
for (p = mips_pci_channels; p->pci_ops != NULL; p++) {
busno = pciauto_assign_resources(busno, p) + 1;
}
#endif
/* scan the buses */
busno = 0;
for (p = mips_pci_channels; p->pci_ops != NULL; p++) {
bus = pci_scan_bus(busno, p->pci_ops, p);
busno = bus->subordinate + 1;
}
/* machine dependent fixups */
pcibios_fixup();
/* fixup irqs (board specific routines) */
pcibios_fixup_irqs();
return 0;
}
subsys_initcall(pcibios_init);
int pcibios_enable_device(struct pci_dev *dev, int mask)
{
/* pciauto_assign_resources() will enable all devices found */
return 0;
}
unsigned long __init pci_bridge_check_io(struct pci_dev *bridge)
{
u16 io;
pci_read_config_word(bridge, PCI_IO_BASE, &io);
if (!io) {
pci_write_config_word(bridge, PCI_IO_BASE, 0xf0f0);
pci_read_config_word(bridge, PCI_IO_BASE, &io);
pci_write_config_word(bridge, PCI_IO_BASE, 0x0);
}
if (io)
return IORESOURCE_IO;
//printk(KERN_WARNING "PCI: bridge %s does not support I/O forwarding!\n", bridge->name);
return 0;
}
void __devinit pcibios_fixup_bus(struct pci_bus *bus)
{
/* Propogate hose info into the subordinate devices. */
struct pci_channel *hose = bus->sysdata;
struct pci_dev *dev = bus->self;
if (!dev) {
/* Root bus */
bus->resource[0] = hose->io_resource;
bus->resource[1] = hose->mem_resource;
} else {
/* This is a bridge. Do not care how it's initialized,
just link its resources to the bus ones */
int i;
for (i = 0; i < 3; i++) {
bus->resource[i] =
&dev->resource[PCI_BRIDGE_RESOURCES + i];
bus->resource[i]->name = bus->name;
}
bus->resource[0]->flags |= pci_bridge_check_io(dev);
bus->resource[1]->flags |= IORESOURCE_MEM;
/* For now, propagate hose limits to the bus;
we'll adjust them later. */
bus->resource[0]->end = hose->io_resource->end;
bus->resource[1]->end = hose->mem_resource->end;
/* Turn off downstream PF memory address range by default */
bus->resource[2]->start = 1024 * 1024;
bus->resource[2]->end = bus->resource[2]->start - 1;
}
}
char *pcibios_setup(char *str)
{
return str;
}
void pcibios_align_resource(void *data, struct resource *res,
unsigned long size, unsigned long align)
{
/* this should not be called */
}
...@@ -24,8 +24,8 @@ obj-$(CONFIG_PARISC) += setup-bus.o ...@@ -24,8 +24,8 @@ obj-$(CONFIG_PARISC) += setup-bus.o
obj-$(CONFIG_SUPERH) += setup-bus.o setup-irq.o obj-$(CONFIG_SUPERH) += setup-bus.o setup-irq.o
obj-$(CONFIG_PPC32) += setup-irq.o obj-$(CONFIG_PPC32) += setup-irq.o
obj-$(CONFIG_PPC64) += setup-bus.o obj-$(CONFIG_PPC64) += setup-bus.o
obj-$(CONFIG_DDB5476) += setup-bus.o
obj-$(CONFIG_SGI_IP27) += setup-irq.o obj-$(CONFIG_SGI_IP27) += setup-irq.o
obj-$(CONFIG_SGI_IP32) += setup-irq.o
obj-$(CONFIG_X86_VISWS) += setup-irq.o obj-$(CONFIG_X86_VISWS) += setup-irq.o
# CompactPCI hotplug requires the pbus_* functions # 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