diff -Naurp linux-2.6.16.7-generic-patched/arch/mips/pci/Makefile linux-2.6.16.7-patched/arch/mips/pci/Makefile --- linux-2.6.16.7-generic-patched/arch/mips/pci/Makefile 2006-04-17 23:53:25.000000000 +0200 +++ linux-2.6.16.7-patched/arch/mips/pci/Makefile 2006-07-05 15:21:58.000000000 +0200 @@ -18,6 +18,7 @@ obj-$(CONFIG_MIPS_NILE4) += ops-nile4.o obj-$(CONFIG_MIPS_TX3927) += ops-tx3927.o obj-$(CONFIG_PCI_VR41XX) += ops-vr41xx.o pci-vr41xx.o obj-$(CONFIG_NEC_CMBVR4133) += fixup-vr4133.o +obj-$(CONFIG_BCM_PCI) += fixup-bcm96348.o pci-bcm96348.o ops-bcm96348.o # # These are still pretty much in the old state, watch, go blind. diff -Naurp linux-2.6.16.7-generic-patched/arch/mips/pci/fixup-bcm96348.c linux-2.6.16.7-patched/arch/mips/pci/fixup-bcm96348.c --- linux-2.6.16.7-generic-patched/arch/mips/pci/fixup-bcm96348.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.7-patched/arch/mips/pci/fixup-bcm96348.c 2006-07-05 15:21:58.000000000 +0200 @@ -0,0 +1,85 @@ +/* +<:copyright-gpl + Copyright 2002 Broadcom Corp. All Rights Reserved. + + This program is free software; you can distribute it and/or modify it + under the terms of the GNU General Public License (Version 2) as + published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. +:> +*/ +#include +#include +#include + +#include +#include +#include + +static volatile MpiRegisters * mpi = (MpiRegisters *)(MPI_BASE); + +static char irq_tab_bcm96348[] __initdata = { + [0] = INTERRUPT_ID_MPI, + [1] = INTERRUPT_ID_MPI, +#if defined(CONFIG_USB) + [USB_HOST_SLOT] = INTERRUPT_ID_USBH +#endif +}; + +int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + return irq_tab_bcm96348[slot]; +} + +static void bcm96348_fixup(struct pci_dev *dev) +{ + uint32 memaddr; + uint32 size; + + memaddr = pci_resource_start(dev, 0); + size = pci_resource_len(dev, 0); + + switch (PCI_SLOT(dev->devfn)) { + case 0: + // UBUS to PCI address range + // Memory Window 1. Mask determines which bits are decoded. + mpi->l2pmrange1 = ~(size-1); + // UBUS to PCI Memory base address. This is akin to the ChipSelect base + // register. + mpi->l2pmbase1 = memaddr & BCM_PCI_ADDR_MASK; + // UBUS to PCI Remap Address. Replaces the masked address bits in the + // range register with this setting. + // Also, enable direct I/O and direct Memory accesses + mpi->l2pmremap1 = (memaddr | MEM_WINDOW_EN); + break; + + case 1: + // Memory Window 2 + mpi->l2pmrange2 = ~(size-1); + // UBUS to PCI Memory base address. + mpi->l2pmbase2 = memaddr & BCM_PCI_ADDR_MASK; + // UBUS to PCI Remap Address + mpi->l2pmremap2 = (memaddr | MEM_WINDOW_EN); + break; + +#if defined(CONFIG_USB) + case USB_HOST_SLOT: + dev->resource[0].start = USB_HOST_BASE; + dev->resource[0].end = USB_HOST_BASE+USB_BAR0_MEM_SIZE-1; + break; +#endif + } +} + +struct pci_fixup pcibios_fixups[] = { + { PCI_FIXUP_FINAL, PCI_ANY_ID, PCI_ANY_ID, bcm96348_fixup }, + {0} +}; diff -Naurp linux-2.6.16.7-generic-patched/arch/mips/pci/ops-bcm96348.c linux-2.6.16.7-patched/arch/mips/pci/ops-bcm96348.c --- linux-2.6.16.7-generic-patched/arch/mips/pci/ops-bcm96348.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.7-patched/arch/mips/pci/ops-bcm96348.c 2006-07-05 15:21:58.000000000 +0200 @@ -0,0 +1,276 @@ +/* +<:copyright-gpl + Copyright 2002 Broadcom Corp. All Rights Reserved. + + This program is free software; you can distribute it and/or modify it + under the terms of the GNU General Public License (Version 2) as + published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. +:> +*/ +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#if defined(CONFIG_USB) +#if 0 +#define DPRINT(x...) printk(x) +#else +#define DPRINT(x...) +#endif + +static int +pci63xx_int_read(unsigned int devfn, int where, u32 * value, int size); +static int +pci63xx_int_write(unsigned int devfn, int where, u32 * value, int size); + +static bool usb_mem_size_rd = FALSE; +static uint32 usb_mem_base = 0; +static uint32 usb_cfg_space_cmd_reg = 0; +#endif +static bool pci_mem_size_rd = FALSE; + +static volatile MpiRegisters * mpi = (MpiRegisters *)(MPI_BASE); + +static void mpi_SetupPciConfigAccess(uint32 addr) +{ + mpi->l2pcfgctl = (DIR_CFG_SEL | DIR_CFG_USEREG | addr) & ~CONFIG_TYPE; +} + +static void mpi_ClearPciConfigAccess(void) +{ + mpi->l2pcfgctl = 0x00000000; +} + +#if defined(CONFIG_USB) +/* -------------------------------------------------------------------------- + Name: pci63xx_int_write +Abstract: PCI Config write on internal device(s) + -------------------------------------------------------------------------- */ +static int +pci63xx_int_write(unsigned int devfn, int where, u32 * value, int size) +{ + if (PCI_SLOT(devfn) != USB_HOST_SLOT) { + return PCIBIOS_SUCCESSFUL; + } + + switch (size) { + case 1: + DPRINT("W => Slot: %d Where: %2X Len: %d Data: %02X\n", + PCI_SLOT(devfn), where, size, *value); + break; + case 2: + DPRINT("W => Slot: %d Where: %2X Len: %d Data: %04X\n", + PCI_SLOT(devfn), where, size, *value); + switch (where) { + case PCI_COMMAND: + usb_cfg_space_cmd_reg = *value; + break; + default: + break; + } + break; + case 4: + DPRINT("W => Slot: %d Where: %2X Len: %d Data: %08lX\n", + PCI_SLOT(devfn), where, size, *value); + switch (where) { + case PCI_BASE_ADDRESS_0: + if (*value == 0xffffffff) { + usb_mem_size_rd = TRUE; + } else { + usb_mem_base = *value; + } + break; + default: + break; + } + break; + default: + break; + } + + return PCIBIOS_SUCCESSFUL; +} + +/* -------------------------------------------------------------------------- + Name: pci63xx_int_read +Abstract: PCI Config read on internal device(s) + -------------------------------------------------------------------------- */ +static int +pci63xx_int_read(unsigned int devfn, int where, u32 * value, int size) +{ + uint32 retValue = 0xFFFFFFFF; + + if (PCI_SLOT(devfn) != USB_HOST_SLOT) { + return PCIBIOS_SUCCESSFUL; + } + + // For now, this is specific to the USB Host controller. We can + // make it more general if we have to... + // Emulate PCI Config accesses + switch (where) { + case PCI_VENDOR_ID: + case PCI_DEVICE_ID: + retValue = PCI_VENDOR_ID_BROADCOM | 0x63000000; + break; + case PCI_COMMAND: + case PCI_STATUS: + retValue = (0x0006 << 16) | usb_cfg_space_cmd_reg; + break; + case PCI_CLASS_REVISION: + case PCI_CLASS_DEVICE: + retValue = (PCI_CLASS_SERIAL_USB << 16) | (0x10 << 8) | 0x01; + break; + case PCI_BASE_ADDRESS_0: + if (usb_mem_size_rd) { + retValue = USB_BAR0_MEM_SIZE; + } else { + if (usb_mem_base != 0) + retValue = usb_mem_base; + else + retValue = USB_HOST_BASE; + } + usb_mem_size_rd = FALSE; + break; + case PCI_CACHE_LINE_SIZE: + case PCI_LATENCY_TIMER: + retValue = 0; + break; + case PCI_HEADER_TYPE: + retValue = PCI_HEADER_TYPE_NORMAL; + break; + case PCI_SUBSYSTEM_VENDOR_ID: + retValue = PCI_VENDOR_ID_BROADCOM; + break; + case PCI_SUBSYSTEM_ID: + retValue = 0x6300; + break; + case PCI_INTERRUPT_LINE: + retValue = INTERRUPT_ID_USBH; + break; + default: + break; + } + + switch (size) { + case 1: + *value = (retValue >> ((where & 3) << 3)) & 0xff; + DPRINT("R <= Slot: %d Where: %2X Len: %d Data: %02X\n", + PCI_SLOT(devfn), where, size, *value); + break; + case 2: + *value = (retValue >> ((where & 3) << 3)) & 0xffff; + DPRINT("R <= Slot: %d Where: %2X Len: %d Data: %04X\n", + PCI_SLOT(devfn), where, size, *value); + break; + case 4: + *value = retValue; + DPRINT("R <= Slot: %d Where: %2X Len: %d Data: %08lX\n", + PCI_SLOT(devfn), where, size, *value); + break; + default: + break; + } + + return PCIBIOS_SUCCESSFUL; +} +#endif + +static int bcm96348_pcibios_read(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 * val) +{ + volatile unsigned char *ioBase = (unsigned char *)(mpi->l2piobase | KSEG1); + uint32 data; + +#if defined(CONFIG_USB) + if (PCI_SLOT(devfn) == USB_HOST_SLOT) + return pci63xx_int_read(devfn, where, val, size); +#endif + + mpi_SetupPciConfigAccess(BCM_PCI_CFG(PCI_SLOT(devfn), PCI_FUNC(devfn), where)); + data = *(uint32 *)ioBase; + switch(size) { + case 1: + *val = (data >> ((where & 3) << 3)) & 0xff; + break; + case 2: + *val = (data >> ((where & 3) << 3)) & 0xffff; + break; + case 4: + *val = data; + /* Special case for reading PCI device range */ + if ((where >= PCI_BASE_ADDRESS_0) && (where <= PCI_BASE_ADDRESS_5)) { + if (pci_mem_size_rd) { + /* bcm6348 PCI memory window minimum size is 64K */ + *val &= PCI_SIZE_64K; + } + } + break; + default: + break; + } + pci_mem_size_rd = FALSE; + mpi_ClearPciConfigAccess(); + + return PCIBIOS_SUCCESSFUL; +} + +static int bcm96348_pcibios_write(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 val) +{ + volatile unsigned char *ioBase = (unsigned char *)(mpi->l2piobase | KSEG1); + uint32 data; + +#if defined(CONFIG_USB) + if (PCI_SLOT(devfn) == USB_HOST_SLOT) + return pci63xx_int_write(devfn, where, &val, size); +#endif + mpi_SetupPciConfigAccess(BCM_PCI_CFG(PCI_SLOT(devfn), PCI_FUNC(devfn), where)); + data = *(uint32 *)ioBase; + switch(size) { + case 1: + data = (data & ~(0xff << ((where & 3) << 3))) | + (val << ((where & 3) << 3)); + break; + case 2: + data = (data & ~(0xffff << ((where & 3) << 3))) | + (val << ((where & 3) << 3)); + break; + case 4: + data = val; + /* Special case for reading PCI device range */ + if ((where >= PCI_BASE_ADDRESS_0) && (where <= PCI_BASE_ADDRESS_5)) { + if (val == 0xffffffff) + pci_mem_size_rd = TRUE; + } + break; + default: + break; + } + *(uint32 *)ioBase = data; + udelay(500); + mpi_ClearPciConfigAccess(); + + return PCIBIOS_SUCCESSFUL; +} + +struct pci_ops bcm96348_pci_ops = { + .read = bcm96348_pcibios_read, + .write = bcm96348_pcibios_write +}; diff -Naurp linux-2.6.16.7-generic-patched/arch/mips/pci/pci-bcm96348.c linux-2.6.16.7-patched/arch/mips/pci/pci-bcm96348.c --- linux-2.6.16.7-generic-patched/arch/mips/pci/pci-bcm96348.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.7-patched/arch/mips/pci/pci-bcm96348.c 2006-07-05 15:21:58.000000000 +0200 @@ -0,0 +1,54 @@ +/* +<:copyright-gpl + Copyright 2002 Broadcom Corp. All Rights Reserved. + + This program is free software; you can distribute it and/or modify it + under the terms of the GNU General Public License (Version 2) as + published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. +:> +*/ +#include +#include +#include +#include + +#include +#include + +static struct resource bcm_pci_io_resource = { + .name = "bcm96348 pci IO space", + .start = BCM_PCI_IO_BASE, + .end = BCM_PCI_IO_BASE + BCM_PCI_IO_SIZE_64KB - 1, + .flags = IORESOURCE_IO +}; + +static struct resource bcm_pci_mem_resource = { + .name = "bcm96348 pci memory space", + .start = BCM_PCI_MEM_BASE, + .end = BCM_PCI_MEM_BASE + BCM_PCI_MEM_SIZE_16MB - 1, + .flags = IORESOURCE_MEM +}; + +extern struct pci_ops bcm96348_pci_ops; + +struct pci_controller bcm96348_controller = { + .pci_ops = &bcm96348_pci_ops, + .io_resource = &bcm_pci_io_resource, + .mem_resource = &bcm_pci_mem_resource, +}; + +static void bcm96348_pci_init(void) +{ + register_pci_controller(&bcm96348_controller); +} + +arch_initcall(bcm96348_pci_init);