/* * 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) 2008 Maxime Bizon <mbizon@freebox.fr>
*/
if (func > (MPI_L2PCFG_FUNC_MASK >> MPI_L2PCFG_FUNC_SHIFT)) return 1;
if (reg > (MPI_L2PCFG_REG_MASK >> MPI_L2PCFG_REG_SHIFT)) return 1;
/* ok, setup config access */
val = (reg << MPI_L2PCFG_REG_SHIFT);
val |= (func << MPI_L2PCFG_FUNC_SHIFT);
val |= (slot << MPI_L2PCFG_DEVNUM_SHIFT);
val |= MPI_L2PCFG_CFG_USEREG_MASK;
val |= MPI_L2PCFG_CFG_SEL_MASK; /* type 0 cycle for local bus, type 1 cycle for anything else */ if (type != 0) { /* FIXME: how to specify bus ??? */
val |= (1 << MPI_L2PCFG_CFG_TYPE_SHIFT);
}
bcm_mpi_writel(val, MPI_L2PCFG_REG);
return 0;
}
staticint bcm63xx_do_cfg_read(int type, unsignedint busn, unsignedint devfn, int where, int size,
u32 *val)
{
u32 data;
/* two phase cycle, first we write address, then read data at * another location, caller already has a spinlock so no need
* to add one here */ if (bcm63xx_setup_cfg_access(type, busn, devfn, where)) return PCIBIOS_DEVICE_NOT_FOUND;
iob();
data = le32_to_cpu(__raw_readl(pci_iospace_start)); /* restore IO space normal behaviour */
bcm_mpi_writel(0, MPI_L2PCFG_REG);
*val = postprocess_read(data, where, size);
return PCIBIOS_SUCCESSFUL;
}
staticint bcm63xx_do_cfg_write(int type, unsignedint busn, unsignedint devfn, int where, int size,
u32 val)
{
u32 data;
/* two phase cycle, first we write address, then write data to * another location, caller already has a spinlock so no need
* to add one here */ if (bcm63xx_setup_cfg_access(type, busn, devfn, where)) return PCIBIOS_DEVICE_NOT_FOUND;
iob();
data = le32_to_cpu(__raw_readl(pci_iospace_start));
data = preprocess_write(data, val, where, size);
__raw_writel(cpu_to_le32(data), pci_iospace_start);
wmb(); /* no way to know the access is done, we have to wait */
udelay(500); /* restore IO space normal behaviour */
bcm_mpi_writel(0, MPI_L2PCFG_REG);
return PCIBIOS_SUCCESSFUL;
}
staticint bcm63xx_pci_read(struct pci_bus *bus, unsignedint devfn, int where, int size, u32 *val)
{ int type;
type = bus->parent ? 1 : 0;
if (type == 0 && PCI_SLOT(devfn) == CARDBUS_PCI_IDSEL) return PCIBIOS_DEVICE_NOT_FOUND;
data = 0;
reg = where >> 2; switch (reg) { case (PCI_VENDOR_ID >> 2): case (PCI_CB_SUBSYSTEM_VENDOR_ID >> 2): /* create dummy vendor/device id from our cpu id */
data = (bcm63xx_get_cpu_id() << 16) | PCI_VENDOR_ID_BROADCOM; break;
case (PCI_COMMAND >> 2):
data = (PCI_STATUS_DEVSEL_SLOW << 16);
data |= fake_cb_bridge_regs.pci_command; break;
case (PCI_CLASS_REVISION >> 2):
data = (PCI_CLASS_BRIDGE_CARDBUS << 16); break;
case (PCI_CACHE_LINE_SIZE >> 2):
data = (PCI_HEADER_TYPE_CARDBUS << 16); break;
case (PCI_INTERRUPT_LINE >> 2): /* bridge control */
data = (fake_cb_bridge_regs.bridge_control << 16); /* pin:intA line:0xff */
data |= (0x1 << 8) | 0xff; break;
case (PCI_CB_PRIMARY_BUS >> 2):
data = (fake_cb_bridge_regs.cb_latency << 24);
data |= (fake_cb_bridge_regs.subordinate_busn << 16);
data |= (fake_cb_bridge_regs.cardbus_busn << 8);
data |= fake_cb_bridge_regs.pci_busn; break;
case (PCI_CB_MEMORY_BASE_0 >> 2):
data = fake_cb_bridge_regs.mem_base0; break;
case (PCI_CB_MEMORY_LIMIT_0 >> 2):
data = fake_cb_bridge_regs.mem_limit0; break;
case (PCI_CB_MEMORY_BASE_1 >> 2):
data = fake_cb_bridge_regs.mem_base1; break;
case (PCI_CB_MEMORY_LIMIT_1 >> 2):
data = fake_cb_bridge_regs.mem_limit1; break;
case (PCI_CB_IO_BASE_0 >> 2): /* | 1 for 32bits io support */
data = fake_cb_bridge_regs.io_base0 | 0x1; break;
case (PCI_CB_IO_LIMIT_0 >> 2):
data = fake_cb_bridge_regs.io_limit0; break;
case (PCI_CB_IO_BASE_1 >> 2): /* | 1 for 32bits io support */
data = fake_cb_bridge_regs.io_base1 | 0x1; break;
case (PCI_CB_IO_LIMIT_1 >> 2):
data = fake_cb_bridge_regs.io_limit1; break;
}
case (PCI_CB_MEMORY_BASE_0 >> 2):
fake_cb_bridge_regs.mem_base0 = data; break;
case (PCI_CB_MEMORY_LIMIT_0 >> 2):
fake_cb_bridge_regs.mem_limit0 = data; break;
case (PCI_CB_MEMORY_BASE_1 >> 2):
fake_cb_bridge_regs.mem_base1 = data; break;
case (PCI_CB_MEMORY_LIMIT_1 >> 2):
fake_cb_bridge_regs.mem_limit1 = data; break;
case (PCI_CB_IO_BASE_0 >> 2):
fake_cb_bridge_regs.io_base0 = data; break;
case (PCI_CB_IO_LIMIT_0 >> 2):
fake_cb_bridge_regs.io_limit0 = data; break;
case (PCI_CB_IO_BASE_1 >> 2):
fake_cb_bridge_regs.io_base1 = data; break;
case (PCI_CB_IO_LIMIT_1 >> 2):
fake_cb_bridge_regs.io_limit1 = data; break;
}
return PCIBIOS_SUCCESSFUL;
}
staticint bcm63xx_cb_read(struct pci_bus *bus, unsignedint devfn, int where, int size, u32 *val)
{ /* snoop access to slot 0x1e on root bus, we fake a cardbus
* bridge at this location */ if (!bus->parent && PCI_SLOT(devfn) == FAKE_CB_BRIDGE_SLOT) {
fake_cb_bridge_bus_number = bus->number; return fake_cb_bridge_read(where, size, val);
}
/* a configuration cycle for the device behind the cardbus * bridge is actually done as a type 0 cycle on the primary * bus. This means that only one device can be on the cardbus
* bus */ if (fake_cb_bridge_regs.bus_assigned &&
bus->number == fake_cb_bridge_regs.cardbus_busn &&
PCI_SLOT(devfn) == 0) return bcm63xx_do_cfg_read(0, 0,
PCI_DEVFN(CARDBUS_PCI_IDSEL, 0),
where, size, val);
return PCIBIOS_DEVICE_NOT_FOUND;
}
staticint bcm63xx_cb_write(struct pci_bus *bus, unsignedint devfn, int where, int size, u32 val)
{ if (!bus->parent && PCI_SLOT(devfn) == FAKE_CB_BRIDGE_SLOT) {
fake_cb_bridge_bus_number = bus->number; return fake_cb_bridge_write(where, size, val);
}
/* * only one IO window, so it cannot be shared by PCI and cardbus, use * fixup to choose and detect unhandled configuration
*/ staticvoid bcm63xx_fixup(struct pci_dev *dev)
{ staticint io_window = -1; int found, new_io_window; struct resource *r;
u32 val;
/* look for any io resource */
found = 0;
pci_dev_for_each_resource(dev, r) { if (resource_type(r) == IORESOURCE_IO) {
found = 1; break;
}
} if (!found) return;
/* skip our fake bus with only cardbus bridge on it */ if (dev->bus->number == fake_cb_bridge_bus_number) return;
/* find on which bus the device is */ if (fake_cb_bridge_regs.bus_assigned &&
dev->bus->number == fake_cb_bridge_regs.cardbus_busn &&
PCI_SLOT(dev->devfn) == 0)
new_io_window = 1; else
new_io_window = 0;
if (new_io_window == io_window) return;
if (io_window != -1) {
printk(KERN_ERR "bcm63xx: both PCI and cardbus devices " "need IO, which hardware cannot do\n"); return;
}
val = bcm_mpi_readl(MPI_L2PIOREMAP_REG); if (io_window)
val |= MPI_L2PREMAP_IS_CARDBUS_MASK; else
val &= ~MPI_L2PREMAP_IS_CARDBUS_MASK;
bcm_mpi_writel(val, MPI_L2PIOREMAP_REG);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.