X-Git-Url: https://git.rohieb.name/openwrt.git/blobdiff_plain/d8297bb0a4e520c83175a987ff70e4a72f2bd603..d9c2b6a237f6481353e98dcdace3b14a3c9ca3de:/target/linux/brcm63xx/patches-2.6.27/004_add_pci_support.patch diff --git a/target/linux/brcm63xx/patches-2.6.27/004_add_pci_support.patch b/target/linux/brcm63xx/patches-2.6.27/004_add_pci_support.patch index 36117257a..47390f30a 100644 --- a/target/linux/brcm63xx/patches-2.6.27/004_add_pci_support.patch +++ b/target/linux/brcm63xx/patches-2.6.27/004_add_pci_support.patch @@ -20,27 +20,6 @@ Signed-off-by: Maxime Bizon create mode 100644 arch/mips/pci/pci-bcm63xx.h create mode 100644 include/asm-mips/mach-bcm63xx/bcm63xx_dev_pci.h ---- a/arch/mips/bcm63xx/Kconfig -+++ b/arch/mips/bcm63xx/Kconfig -@@ -3,7 +3,9 @@ menu "CPU support" - - config BCM63XX_CPU_6348 - bool "support 6348 CPU" -+ select HW_HAS_PCI - - config BCM63XX_CPU_6358 - bool "support 6358 CPU" -+ select HW_HAS_PCI - endmenu ---- a/arch/mips/bcm63xx/setup.c -+++ b/arch/mips/bcm63xx/setup.c -@@ -105,4 +105,6 @@ void __init plat_mem_setup(void) - pm_power_off = bcm63xx_machine_halt; - - set_io_port_base(0); -+ ioport_resource.start = 0; -+ ioport_resource.end = ~0; - } --- a/arch/mips/pci/Makefile +++ b/arch/mips/pci/Makefile @@ -16,6 +16,8 @@ obj-$(CONFIG_PCI_VR41XX) += ops-vr41xx.o @@ -52,429 +31,3 @@ Signed-off-by: Maxime Bizon # # These are still pretty much in the old state, watch, go blind. ---- /dev/null -+++ b/arch/mips/pci/fixup-bcm63xx.c -@@ -0,0 +1,21 @@ -+/* -+ * 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 -+ */ -+ -+#include -+#include -+#include -+ -+int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) -+{ -+ return bcm63xx_get_irq_number(IRQ_PCI); -+} -+ -+int pcibios_plat_dev_init(struct pci_dev *dev) -+{ -+ return 0; -+} ---- /dev/null -+++ b/arch/mips/pci/ops-bcm63xx.c -@@ -0,0 +1,179 @@ -+/* -+ * 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 -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "pci-bcm63xx.h" -+ -+/* -+ * swizzle 32bits data to return only the needed part -+ */ -+static int postprocess_read(u32 data, int where, unsigned int size) -+{ -+ u32 ret; -+ -+ ret = 0; -+ switch (size) { -+ case 1: -+ ret = (data >> ((where & 3) << 3)) & 0xff; -+ break; -+ case 2: -+ ret = (data >> ((where & 3) << 3)) & 0xffff; -+ break; -+ case 4: -+ ret = data; -+ break; -+ } -+ return ret; -+} -+ -+static int preprocess_write(u32 orig_data, u32 val, int where, -+ unsigned int size) -+{ -+ u32 ret; -+ -+ ret = 0; -+ switch (size) { -+ case 1: -+ ret = (orig_data & ~(0xff << ((where & 3) << 3))) | -+ (val << ((where & 3) << 3)); -+ break; -+ case 2: -+ ret = (orig_data & ~(0xffff << ((where & 3) << 3))) | -+ (val << ((where & 3) << 3)); -+ break; -+ case 4: -+ ret = val; -+ break; -+ } -+ return ret; -+} -+ -+/* -+ * setup hardware for a configuration cycle with given parameters -+ */ -+static int bcm63xx_setup_cfg_access(int type, unsigned int busn, -+ unsigned int devfn, int where) -+{ -+ unsigned int slot, func, reg; -+ u32 val; -+ -+ slot = PCI_SLOT(devfn); -+ func = PCI_FUNC(devfn); -+ reg = where >> 2; -+ -+ /* sanity check */ -+ if (slot > (MPI_L2PCFG_DEVNUM_MASK >> MPI_L2PCFG_DEVNUM_SHIFT)) -+ return 1; -+ -+ 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; -+} -+ -+static int bcm63xx_do_cfg_read(int type, unsigned int busn, -+ unsigned int 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; -+} -+ -+static int bcm63xx_do_cfg_write(int type, unsigned int busn, -+ unsigned int 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; -+} -+ -+static int bcm63xx_pci_read(struct pci_bus *bus, unsigned int 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; -+ -+ return bcm63xx_do_cfg_read(type, bus->number, devfn, -+ where, size, val); -+} -+ -+static int bcm63xx_pci_write(struct pci_bus *bus, unsigned int 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; -+ -+ return bcm63xx_do_cfg_write(type, bus->number, devfn, -+ where, size, val); -+} -+ -+struct pci_ops bcm63xx_pci_ops = { -+ .read = bcm63xx_pci_read, -+ .write = bcm63xx_pci_write -+}; ---- /dev/null -+++ b/arch/mips/pci/pci-bcm63xx.c -@@ -0,0 +1,178 @@ -+/* -+ * 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 -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "pci-bcm63xx.h" -+ -+/* allow PCI to be disabled at runtime depending on board nvram -+ * configuration */ -+int bcm63xx_pci_enabled = 0; -+ -+static struct resource bcm_pci_mem_resource = { -+ .name = "bcm63xx PCI memory space", -+ .start = BCM_PCI_MEM_BASE_PA, -+ .end = BCM_PCI_MEM_END_PA, -+ .flags = IORESOURCE_MEM -+}; -+ -+static struct resource bcm_pci_io_resource = { -+ .name = "bcm63xx PCI IO space", -+ .start = BCM_PCI_IO_BASE_PA, -+ .end = BCM_PCI_IO_END_PA, -+ .flags = IORESOURCE_IO -+}; -+ -+struct pci_controller bcm63xx_controller = { -+ .pci_ops = &bcm63xx_pci_ops, -+ .io_resource = &bcm_pci_io_resource, -+ .mem_resource = &bcm_pci_mem_resource, -+}; -+ -+static u32 bcm63xx_int_cfg_readl(u32 reg) -+{ -+ u32 tmp; -+ -+ tmp = reg & MPI_PCICFGCTL_CFGADDR_MASK; -+ tmp |= MPI_PCICFGCTL_WRITEEN_MASK; -+ bcm_mpi_writel(tmp, MPI_PCICFGCTL_REG); -+ iob(); -+ return bcm_mpi_readl(MPI_PCICFGDATA_REG); -+} -+ -+static void bcm63xx_int_cfg_writel(u32 val, u32 reg) -+{ -+ u32 tmp; -+ -+ tmp = reg & MPI_PCICFGCTL_CFGADDR_MASK; -+ tmp |= MPI_PCICFGCTL_WRITEEN_MASK; -+ bcm_mpi_writel(tmp, MPI_PCICFGCTL_REG); -+ bcm_mpi_writel(val, MPI_PCICFGDATA_REG); -+} -+ -+void __iomem *pci_iospace_start; -+ -+static int __init bcm63xx_pci_init(void) -+{ -+ unsigned int mem_size; -+ u32 val; -+ -+ if (!BCMCPU_IS_6348() && !BCMCPU_IS_6358()) -+ return -ENODEV; -+ -+ if (!bcm63xx_pci_enabled) -+ return -ENODEV; -+ -+ /* -+ * configuration access are done through IO space, remap 4 -+ * first bytes to access it from CPU. -+ * -+ * this means that no io access from CPU should happen while -+ * we do a configuration cycle, but there's no way we can add -+ * a spinlock for each io access, so this is currently kind of -+ * broken on SMP. -+ */ -+ pci_iospace_start = ioremap_nocache(BCM_PCI_IO_BASE_PA, 4); -+ if (!pci_iospace_start) -+ return -ENOMEM; -+ -+ /* setup local bus to PCI access (PCI memory) */ -+ val = BCM_PCI_MEM_BASE_PA & MPI_L2P_BASE_MASK; -+ bcm_mpi_writel(val, MPI_L2PMEMBASE1_REG); -+ bcm_mpi_writel(~(BCM_PCI_MEM_SIZE - 1), MPI_L2PMEMRANGE1_REG); -+ bcm_mpi_writel(val | MPI_L2PREMAP_ENABLED_MASK, MPI_L2PMEMREMAP1_REG); -+ -+ /* set Cardbus IDSEL (type 0 cfg access on primary bus for -+ * this IDSEL will be done on Cardbus instead) */ -+ val = bcm_pcmcia_readl(PCMCIA_C1_REG); -+ val &= ~PCMCIA_C1_CBIDSEL_MASK; -+ val |= (CARDBUS_PCI_IDSEL << PCMCIA_C1_CBIDSEL_SHIFT); -+ bcm_pcmcia_writel(val, PCMCIA_C1_REG); -+ -+ /* disable second access windows */ -+ bcm_mpi_writel(0, MPI_L2PMEMREMAP2_REG); -+ -+ /* setup local bus to PCI access (IO memory), we have only 1 -+ * IO window for both PCI and cardbus, but it cannot handle -+ * both at the same time, assume standard PCI for now, if -+ * cardbus card has IO zone, PCI fixup will change window to -+ * cardbus */ -+ val = BCM_PCI_IO_BASE_PA & MPI_L2P_BASE_MASK; -+ bcm_mpi_writel(val, MPI_L2PIOBASE_REG); -+ bcm_mpi_writel(~(BCM_PCI_IO_SIZE - 1), MPI_L2PIORANGE_REG); -+ bcm_mpi_writel(val | MPI_L2PREMAP_ENABLED_MASK, MPI_L2PIOREMAP_REG); -+ -+ /* enable PCI related GPIO pins */ -+ bcm_mpi_writel(MPI_LOCBUSCTL_EN_PCI_GPIO_MASK, MPI_LOCBUSCTL_REG); -+ -+ /* setup PCI to local bus access, used by PCI device to target -+ * local RAM while bus mastering */ -+ bcm63xx_int_cfg_writel(0, PCI_BASE_ADDRESS_3); -+ if (BCMCPU_IS_6358()) -+ val = MPI_SP0_REMAP_ENABLE_MASK; -+ else -+ val = 0; -+ bcm_mpi_writel(val, MPI_SP0_REMAP_REG); -+ -+ bcm63xx_int_cfg_writel(0x0, PCI_BASE_ADDRESS_4); -+ bcm_mpi_writel(0, MPI_SP1_REMAP_REG); -+ -+ mem_size = bcm63xx_get_memory_size(); -+ -+ /* 6348 before rev b0 exposes only 16 MB of RAM memory through -+ * PCI, throw a warning if we have more memory */ -+ if (BCMCPU_IS_6348() && (bcm63xx_get_cpu_rev() & 0xf0) == 0xa0) { -+ if (mem_size > (16 * 1024 * 1024)) -+ printk(KERN_WARNING "bcm63xx: this CPU " -+ "revision cannot handle more than 16MB " -+ "of RAM for PCI bus mastering\n"); -+ } else { -+ /* setup sp0 range to local RAM size */ -+ bcm_mpi_writel(~(mem_size - 1), MPI_SP0_RANGE_REG); -+ bcm_mpi_writel(0, MPI_SP1_RANGE_REG); -+ } -+ -+ /* change host bridge retry counter to infinite number of -+ * retry, needed for some broadcom wifi cards with Silicon -+ * Backplane bus where access to srom seems very slow */ -+ val = bcm63xx_int_cfg_readl(BCMPCI_REG_TIMERS); -+ val &= ~REG_TIMER_RETRY_MASK; -+ bcm63xx_int_cfg_writel(val, BCMPCI_REG_TIMERS); -+ -+ /* enable memory decoder and bus mastering */ -+ val = bcm63xx_int_cfg_readl(PCI_COMMAND); -+ val |= (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); -+ bcm63xx_int_cfg_writel(val, PCI_COMMAND); -+ -+ /* enable read prefetching & disable byte swapping for bus -+ * mastering transfers */ -+ val = bcm_mpi_readl(MPI_PCIMODESEL_REG); -+ val &= ~MPI_PCIMODESEL_BAR1_NOSWAP_MASK; -+ val &= ~MPI_PCIMODESEL_BAR2_NOSWAP_MASK; -+ val &= ~MPI_PCIMODESEL_PREFETCH_MASK; -+ val |= (8 << MPI_PCIMODESEL_PREFETCH_SHIFT); -+ bcm_mpi_writel(val, MPI_PCIMODESEL_REG); -+ -+ /* enable pci interrupt */ -+ val = bcm_mpi_readl(MPI_LOCINT_REG); -+ val |= MPI_LOCINT_MASK(MPI_LOCINT_EXT_PCI_INT); -+ bcm_mpi_writel(val, MPI_LOCINT_REG); -+ -+ register_pci_controller(&bcm63xx_controller); -+ -+ /* mark memory space used for IO mapping as reserved */ -+ request_mem_region(BCM_PCI_IO_BASE_PA, BCM_PCI_IO_SIZE, -+ "bcm63xx PCI IO space"); -+ return 0; -+} -+ -+arch_initcall(bcm63xx_pci_init); ---- /dev/null -+++ b/arch/mips/pci/pci-bcm63xx.h -@@ -0,0 +1,27 @@ -+#ifndef PCI_BCM63XX_H_ -+#define PCI_BCM63XX_H_ -+ -+#include -+#include -+#include -+#include -+ -+/* -+ * Cardbus shares the PCI bus, but has no IDSEL, so a special id is -+ * reserved for it. If you have a standard PCI device at this id, you -+ * need to change the following definition. -+ */ -+#define CARDBUS_PCI_IDSEL 0x8 -+ -+/* -+ * defined in ops-bcm63xx.c -+ */ -+extern struct pci_ops bcm63xx_pci_ops; -+extern struct pci_ops bcm63xx_cb_ops; -+ -+/* -+ * defined in pci-bcm63xx.c -+ */ -+extern void __iomem *pci_iospace_start; -+ -+#endif /* ! PCI_BCM63XX_H_ */ ---- /dev/null -+++ b/include/asm-mips/mach-bcm63xx/bcm63xx_dev_pci.h -@@ -0,0 +1,6 @@ -+#ifndef BCM63XX_DEV_PCI_H_ -+#define BCM63XX_DEV_PCI_H_ -+ -+extern int bcm63xx_pci_enabled; -+ -+#endif /* BCM63XX_DEV_PCI_H_ */