mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-05 18:39:59 +00:00
![Bjorn Helgaas](/assets/img/avatar_default.png)
Tell the PCI core about host bridge address translation so it can take care of bus-to-resource conversion for us. Here's the wrinkle on Cobalt: we can't generate normal I/O port addresses on PCI because the GT-64111 doesn't do any address translation, so we have this: CPU I/O port addresses [io 0x0000-0xffffff] PCI bus I/O port addresses [io 0x10000000-0x10ffffff] Legacy-mode IDE controllers start out with the legacy bus addresses, e.g., 0x1f0, assigned by pci_setup_device(). These are outside the range of addresses GT-64111 can generate on PCI, but pcibios_fixup_device_resources() converted them to CPU addresses anyway by adding io_offset. Therefore, we had to pre-adjust them in cobalt_legacy_ide_fixup(). With io_offset = 0xf0000000, we had this: res->start = 0x1f0 initialized in pci_setup_device() res->start = 0x100001f0 -= io_offset in cobalt_legacy_ide_fixup() res->start = 0x1f0 += io_offset in pcibios_fixup_device_resources() The difference after this patch is that the generic pci_bus_to_resource() only adds the offset if the bus address is inside a host bridge window. Since 0x1f0 is not a valid bus address and is not inside any windows, it is unaffected, so we now have this: region->start = 0x1f0 initialized in pci_setup_device() res->start = 0x1f0 no offset by pci_bus_to_resource() That means we can remove both pcibios_fixup_device_resources() and cobalt_legacy_ide_fixup(). I would *rather* set the host bridge offset to zero (which corresponds to what the GT-64111 actually does), and have both CPU and PCI addresses of [io 0x10000000-0x10ffffff]. However, that would require changes to generic code that assumes legacy I/O addresses, such as pic1_io_resource ([io 0x0020-0x00021]), and we'd have to keep a Cobalt IDE fixup. Of course, none of this changes the fact that references to I/O port 0x1f0 actually go to port 0x100001f0, not 0x1f0, on the Cobalt PCI bus. Fortunately the VT82C586 IDE controller only decodes the low 24 address bits, so it does work. CC: Ralf Baechle <ralf@linux-mips.org> CC: Yoichi Yuasa <yuasa@linux-mips.org> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
193 lines
5.4 KiB
C
193 lines
5.4 KiB
C
/*
|
|
* Cobalt Qube/Raq PCI support
|
|
*
|
|
* This file is subject to the terms and conditions of the GNU General Public
|
|
* License. See the file "COPYING" in the main directory of this archive
|
|
* for more details.
|
|
*
|
|
* Copyright (C) 1995, 1996, 1997, 2002, 2003 by Ralf Baechle
|
|
* Copyright (C) 2001, 2002, 2003 by Liam Davies (ldavies@agile.tv)
|
|
*/
|
|
#include <linux/types.h>
|
|
#include <linux/pci.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/init.h>
|
|
|
|
#include <asm/pci.h>
|
|
#include <asm/io.h>
|
|
#include <asm/gt64120.h>
|
|
|
|
#include <cobalt.h>
|
|
#include <irq.h>
|
|
|
|
/*
|
|
* PCI slot numbers
|
|
*/
|
|
#define COBALT_PCICONF_CPU 0x06
|
|
#define COBALT_PCICONF_ETH0 0x07
|
|
#define COBALT_PCICONF_RAQSCSI 0x08
|
|
#define COBALT_PCICONF_VIA 0x09
|
|
#define COBALT_PCICONF_PCISLOT 0x0A
|
|
#define COBALT_PCICONF_ETH1 0x0C
|
|
|
|
/*
|
|
* The Cobalt board ID information. The boards have an ID number wired
|
|
* into the VIA that is available in the high nibble of register 94.
|
|
*/
|
|
#define VIA_COBALT_BRD_ID_REG 0x94
|
|
#define VIA_COBALT_BRD_REG_to_ID(reg) ((unsigned char)(reg) >> 4)
|
|
|
|
static void qube_raq_galileo_early_fixup(struct pci_dev *dev)
|
|
{
|
|
if (dev->devfn == PCI_DEVFN(0, 0) &&
|
|
(dev->class >> 8) == PCI_CLASS_MEMORY_OTHER) {
|
|
|
|
dev->class = (PCI_CLASS_BRIDGE_HOST << 8) | (dev->class & 0xff);
|
|
|
|
printk(KERN_INFO "Galileo: fixed bridge class\n");
|
|
}
|
|
}
|
|
|
|
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_MARVELL, PCI_DEVICE_ID_MARVELL_GT64111,
|
|
qube_raq_galileo_early_fixup);
|
|
|
|
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, <);
|
|
if (lt < 64)
|
|
pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
|
|
pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 8);
|
|
}
|
|
|
|
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1,
|
|
qube_raq_via_bmIDE_fixup);
|
|
|
|
static void qube_raq_galileo_fixup(struct pci_dev *dev)
|
|
{
|
|
if (dev->devfn != PCI_DEVFN(0, 0))
|
|
return;
|
|
|
|
/* 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, 8);
|
|
|
|
/*
|
|
* The code described by the comment below has been removed
|
|
* as it causes bus mastering by the Ethernet controllers
|
|
* to break under any kind of network load. We always set
|
|
* the retry timeouts to their maximum.
|
|
*
|
|
* --x--x--x--x--x--x--x--x--x--x--x--x--x--x--x--x--x--x--x--x--
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
printk(KERN_INFO "Galileo: revision %u\n", dev->revision);
|
|
|
|
#if 0
|
|
if (dev->revision >= 0x10) {
|
|
/* New Galileo, assumes PCI stop line to VIA is connected. */
|
|
GT_WRITE(GT_PCI0_TOR_OFS, 0x4020);
|
|
} else if (dev->revision == 0x1 || dev->revision == 0x2)
|
|
#endif
|
|
{
|
|
signed int timeo;
|
|
/* XXX WE MUST DO THIS ELSE GALILEO LOCKS UP! -DaveM */
|
|
timeo = GT_READ(GT_PCI0_TOR_OFS);
|
|
/* Old Galileo, assumes PCI STOP line to VIA is disconnected. */
|
|
GT_WRITE(GT_PCI0_TOR_OFS,
|
|
(0xff << 16) | /* retry count */
|
|
(0xff << 8) | /* timeout 1 */
|
|
0xff); /* timeout 0 */
|
|
|
|
/* enable PCI retry exceeded interrupt */
|
|
GT_WRITE(GT_INTRMASK_OFS, GT_INTR_RETRYCTR0_MSK | GT_READ(GT_INTRMASK_OFS));
|
|
}
|
|
}
|
|
|
|
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL, PCI_DEVICE_ID_MARVELL_GT64111,
|
|
qube_raq_galileo_fixup);
|
|
|
|
int cobalt_board_id;
|
|
|
|
static void qube_raq_via_board_id_fixup(struct pci_dev *dev)
|
|
{
|
|
u8 id;
|
|
int retval;
|
|
|
|
retval = pci_read_config_byte(dev, VIA_COBALT_BRD_ID_REG, &id);
|
|
if (retval) {
|
|
panic("Cannot read board ID");
|
|
return;
|
|
}
|
|
|
|
cobalt_board_id = VIA_COBALT_BRD_REG_to_ID(id);
|
|
|
|
printk(KERN_INFO "Cobalt board ID: %d\n", cobalt_board_id);
|
|
}
|
|
|
|
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0,
|
|
qube_raq_via_board_id_fixup);
|
|
|
|
static char irq_tab_qube1[] __initdata = {
|
|
[COBALT_PCICONF_CPU] = 0,
|
|
[COBALT_PCICONF_ETH0] = QUBE1_ETH0_IRQ,
|
|
[COBALT_PCICONF_RAQSCSI] = SCSI_IRQ,
|
|
[COBALT_PCICONF_VIA] = 0,
|
|
[COBALT_PCICONF_PCISLOT] = PCISLOT_IRQ,
|
|
[COBALT_PCICONF_ETH1] = 0
|
|
};
|
|
|
|
static char irq_tab_cobalt[] __initdata = {
|
|
[COBALT_PCICONF_CPU] = 0,
|
|
[COBALT_PCICONF_ETH0] = ETH0_IRQ,
|
|
[COBALT_PCICONF_RAQSCSI] = SCSI_IRQ,
|
|
[COBALT_PCICONF_VIA] = 0,
|
|
[COBALT_PCICONF_PCISLOT] = PCISLOT_IRQ,
|
|
[COBALT_PCICONF_ETH1] = ETH1_IRQ
|
|
};
|
|
|
|
static char irq_tab_raq2[] __initdata = {
|
|
[COBALT_PCICONF_CPU] = 0,
|
|
[COBALT_PCICONF_ETH0] = ETH0_IRQ,
|
|
[COBALT_PCICONF_RAQSCSI] = RAQ2_SCSI_IRQ,
|
|
[COBALT_PCICONF_VIA] = 0,
|
|
[COBALT_PCICONF_PCISLOT] = PCISLOT_IRQ,
|
|
[COBALT_PCICONF_ETH1] = ETH1_IRQ
|
|
};
|
|
|
|
int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
|
|
{
|
|
if (cobalt_board_id <= COBALT_BRD_ID_QUBE1)
|
|
return irq_tab_qube1[slot];
|
|
|
|
if (cobalt_board_id == COBALT_BRD_ID_RAQ2)
|
|
return irq_tab_raq2[slot];
|
|
|
|
return irq_tab_cobalt[slot];
|
|
}
|
|
|
|
/* Do platform specific device initialization at pci_enable_device() time */
|
|
int pcibios_plat_dev_init(struct pci_dev *dev)
|
|
{
|
|
return 0;
|
|
}
|