diff options
Diffstat (limited to 'target/linux/bcm53xx/patches-3.14/170-pcie2-bcma-add-new-PCIe2-driver-for-bcma.patch')
-rw-r--r-- | target/linux/bcm53xx/patches-3.14/170-pcie2-bcma-add-new-PCIe2-driver-for-bcma.patch | 645 |
1 files changed, 0 insertions, 645 deletions
diff --git a/target/linux/bcm53xx/patches-3.14/170-pcie2-bcma-add-new-PCIe2-driver-for-bcma.patch b/target/linux/bcm53xx/patches-3.14/170-pcie2-bcma-add-new-PCIe2-driver-for-bcma.patch deleted file mode 100644 index 4e32ed8..0000000 --- a/target/linux/bcm53xx/patches-3.14/170-pcie2-bcma-add-new-PCIe2-driver-for-bcma.patch +++ /dev/null @@ -1,645 +0,0 @@ -From 7475eee716d11f487076f78f26a6e403c06d0c76 Mon Sep 17 00:00:00 2001 -From: Hauke Mehrtens <hauke@hauke-m.de> -Date: Mon, 12 May 2014 11:55:20 +0200 -Subject: [PATCH 14/15] pcie2-bcma: add new PCIe2 driver for bcma - -This driver supports the PCIe controller found on the BCM4708 and -similar SoCs. The controller itself is automatically detected by bcma. - -Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de> ---- - arch/arm/mach-bcm/Kconfig | 1 + - drivers/pci/host/Kconfig | 7 + - drivers/pci/host/Makefile | 1 + - drivers/pci/host/pcie2-bcma.c | 594 ++++++++++++++++++++++++++++++++++++++++++ - 4 files changed, 603 insertions(+) - create mode 100644 drivers/pci/host/pcie2-bcma.c - ---- a/arch/arm/mach-bcm/Kconfig -+++ b/arch/arm/mach-bcm/Kconfig -@@ -45,6 +45,7 @@ config ARCH_BCM_5301X - select ARM_GLOBAL_TIMER - select CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK - select MIGHT_HAVE_PCI -+ select PCI_DOMAINS if PCI - help - Support for Broadcom BCM470X and BCM5301X SoCs with ARM CPU cores. - ---- a/drivers/pci/host/Kconfig -+++ b/drivers/pci/host/Kconfig -@@ -33,4 +33,11 @@ config PCI_RCAR_GEN2 - There are 3 internal PCI controllers available with a single - built-in EHCI/OHCI host controller present on each one. - -+config PCI_BCMA -+ bool "BCMA PCIe2 host controller" -+ depends on BCMA && OF -+ help -+ Say Y here if you want to support a simple generic PCI host -+ controller, such as the one emulated by kvmtool. -+ - endmenu ---- a/drivers/pci/host/Makefile -+++ b/drivers/pci/host/Makefile -@@ -4,3 +4,4 @@ obj-$(CONFIG_PCI_IMX6) += pci-imx6.o - obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o - obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o - obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o -+obj-$(CONFIG_PCI_BCMA) += pcie2-bcma.o ---- /dev/null -+++ b/drivers/pci/host/pcie2-bcma.c -@@ -0,0 +1,594 @@ -+/* -+ * Northstar PCI-Express driver -+ * Only supports Root-Complex (RC) mode -+ * -+ * Notes: -+ * PCI Domains are being used to identify the PCIe port 1:1. -+ * -+ * Only MEM access is supported, PAX does not support IO. -+ * -+ * TODO: -+ * MSI interrupts, -+ * DRAM > 128 MBytes (e.g. DMA zones) -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/bug.h> -+#include <linux/delay.h> -+#include <linux/pci.h> -+#include <linux/io.h> -+#include <linux/ioport.h> -+#include <linux/interrupt.h> -+#include <linux/bcma/bcma.h> -+ -+#define SI_ENUM_BASE 0x18000000 /* Enumeration space base */ -+ -+/* -+ * Register offset definitions -+ */ -+#define SOC_PCIE_CONTROL 0x000 /* a.k.a. CLK_CONTROL reg */ -+#define SOC_PCIE_PM_STATUS 0x008 -+#define SOC_PCIE_PM_CONTROL 0x00c /* in EP mode only ! */ -+ -+#define SOC_PCIE_EXT_CFG_ADDR 0x120 -+#define SOC_PCIE_EXT_CFG_DATA 0x124 -+#define SOC_PCIE_CFG_ADDR 0x1f8 -+#define SOC_PCIE_CFG_DATA 0x1fc -+ -+#define SOC_PCIE_SYS_RC_INTX_EN 0x330 -+#define SOC_PCIE_SYS_RC_INTX_CSR 0x334 -+#define SOC_PCIE_SYS_HOST_INTR_EN 0x344 -+#define SOC_PCIE_SYS_HOST_INTR_CSR 0x348 -+ -+#define SOC_PCIE_HDR_OFF 0x400 /* 256 bytes per function */ -+ -+/* 32-bit 4KB in-bound mapping windows for Function 0..3, n=0..7 */ -+#define SOC_PCIE_SYS_IMAP0(f, n) (0xc00 + ((f) << 9)((n) << 2)) -+/* 64-bit in-bound mapping windows for func 0..3 */ -+#define SOC_PCIE_SYS_IMAP1(f) (0xc80 + ((f) << 3)) -+#define SOC_PCIE_SYS_IMAP2(f) (0xcc0 + ((f) << 3)) -+/* 64-bit in-bound address range n=0..2 */ -+#define SOC_PCIE_SYS_IARR(n) (0xd00 + ((n) << 3)) -+/* 64-bit out-bound address filter n=0..2 */ -+#define SOC_PCIE_SYS_OARR(n) (0xd20 + ((n) << 3)) -+/* 64-bit out-bound mapping windows n=0..2 */ -+#define SOC_PCIE_SYS_OMAP(n) (0xd40 + ((n) << 3)) -+ -+#define BCM4360_D11AC_ID 0x43a0 -+#define BCM4360_D11AC2G_ID 0x43a1 -+#define BCM4360_D11AC5G_ID 0x43a2 -+#define BCM4352_D11AC_ID 0x43b1 /* 4352 802.11ac dualband device */ -+#define BCM4352_D11AC2G_ID 0x43b2 /* 4352 802.11ac 2.4G device */ -+#define BCM4352_D11AC5G_ID 0x43b3 /* 4352 802.11ac 5G device */ -+ -+static int bcma_pcie2_map_irq(const struct pci_dev *pdev, u8 slot, u8 pin) -+{ -+ struct pci_sys_data *sys = pdev->sysdata; -+ struct bcma_device *bdev = sys->private_data; -+ -+ return bdev->irq; -+} -+ -+static u32 bcma_pcie2_cfg_base(struct bcma_device *bdev, int busno, -+ unsigned int devfn, int where) -+{ -+ int slot = PCI_SLOT(devfn); -+ int fn = PCI_FUNC(devfn); -+ u32 addr_reg; -+ -+ if (busno == 0) { -+ if (slot >= 1) -+ return 0; -+ bcma_write32(bdev, SOC_PCIE_EXT_CFG_ADDR, where & 0xffc); -+ return SOC_PCIE_EXT_CFG_DATA; -+ } else { -+ if (fn > 1) -+ return 0; -+ addr_reg = (busno & 0xff) << 20 | (slot << 15) | (fn << 12) | -+ (where & 0xffc) | (1 & 0x3); -+ -+ bcma_write32(bdev, SOC_PCIE_CFG_ADDR, addr_reg); -+ return SOC_PCIE_CFG_DATA; -+ } -+} -+ -+static u32 bcma_pcie2_read_config(struct bcma_device *bdev, int busno, -+ unsigned int devfn, int where, int size) -+{ -+ u32 base; -+ u32 data_reg; -+ -+ base = bcma_pcie2_cfg_base(bdev, busno, devfn, where); -+ -+ if (!base) -+ return ~0UL; -+ -+ data_reg = bcma_read32(bdev, base); -+ -+ /* NS: CLASS field is R/O, and set to wrong 0x200 value */ -+ if (busno == 0 && devfn == 0) { -+ /* -+ * RC's class is 0x0280, but Linux PCI driver needs 0x604 -+ * for a PCIe bridge. So we must fixup the class code -+ * to 0x604 here. -+ */ -+ if ((where & 0xffc) == PCI_CLASS_REVISION) { -+ data_reg &= 0xff; -+ data_reg |= 0x604 << 16; -+ } -+ } -+ /* HEADER_TYPE=00 indicates the port in EP mode */ -+ -+ if (size == 4) { -+ return data_reg; -+ } else { -+ u32 mask = (1 << (size * 8)) - 1; -+ int shift = (where % 4) * 8; -+ return (data_reg >> shift) & mask; -+ } -+} -+ -+static void bcma_pcie2_write_config(struct bcma_device *bdev, int busno, -+ unsigned int devfn, int where, int size, -+ u32 val) -+{ -+ u32 base; -+ u32 data_reg; -+ -+ base = bcma_pcie2_cfg_base(bdev, busno, devfn, where); -+ -+ if (!base) -+ return; -+ -+ if (size < 4) { -+ u32 mask = (1 << (size * 8)) - 1; -+ int shift = (where % 4) * 8; -+ data_reg = bcma_read32(bdev, base); -+ data_reg &= ~(mask << shift); -+ data_reg |= (val & mask) << shift; -+ } else { -+ data_reg = val; -+ } -+ -+ bcma_write32(bdev, base, data_reg); -+} -+ -+static u8 bcma_pcie2_read_config8(struct bcma_device *bdev, int busno, -+ unsigned int devfn, int where) -+{ -+ return bcma_pcie2_read_config(bdev, busno, devfn, where, 1); -+} -+ -+static u16 bcma_pcie2_read_config16(struct bcma_device *bdev, int busno, -+ unsigned int devfn, int where) -+{ -+ return bcma_pcie2_read_config(bdev, busno, devfn, where, 2); -+} -+ -+static u32 bcma_pcie2_read_config32(struct bcma_device *bdev, int busno, -+ unsigned int devfn, int where) -+{ -+ return bcma_pcie2_read_config(bdev, busno, devfn, where, 4); -+} -+ -+static void bcma_pcie2_write_config8(struct bcma_device *bdev, int busno, -+ unsigned int devfn, int where, u8 val) -+{ -+ return bcma_pcie2_write_config(bdev, busno, devfn, where, 1, val); -+} -+ -+static void bcma_pcie2_write_config16(struct bcma_device *bdev, int busno, -+ unsigned int devfn, int where, u16 val) -+{ -+ return bcma_pcie2_write_config(bdev, busno, devfn, where, 2, val); -+} -+ -+static void bcma_pcie2_write_config32(struct bcma_device *bdev, int busno, -+ unsigned int devfn, int where, u32 val) -+{ -+ return bcma_pcie2_write_config(bdev, busno, devfn, where, 4, val); -+} -+ -+static int bcma_pcie2_read_config_pci(struct pci_bus *bus, unsigned int devfn, -+ int where, int size, u32 *val) -+{ -+ struct pci_sys_data *sys = bus->sysdata; -+ struct bcma_device *bdev = sys->private_data; -+ -+ *val = bcma_pcie2_read_config(bdev, bus->number, devfn, where, size); -+ -+ return PCIBIOS_SUCCESSFUL; -+} -+ -+static int bcma_pcie2_write_config_pci(struct pci_bus *bus, unsigned int devfn, -+ int where, int size, u32 val) -+{ -+ struct pci_sys_data *sys = bus->sysdata; -+ struct bcma_device *bdev = sys->private_data; -+ -+ bcma_pcie2_write_config(bdev, bus->number, devfn, where, size, val); -+ -+ return PCIBIOS_SUCCESSFUL; -+} -+ -+/* -+ * Check link status, return 0 if link is up in RC mode, -+ * otherwise return non-zero -+ */ -+static int bcma_pcie2_check_link(struct bcma_device *bdev, u32 allow_gen2) -+{ -+ u32 devfn = 0; -+ u8 tmp8; -+ u32 tmp32; -+ -+ tmp32 = bcma_pcie2_read_config32(bdev, 0, devfn, 0xdc); -+ tmp32 &= ~0xf; -+ if (allow_gen2) -+ tmp32 |= 2; -+ else { -+ /* force PCIE GEN1 */ -+ tmp32 |= 1; -+ } -+ bcma_pcie2_write_config32(bdev, 0, devfn, 0xdc, tmp32); -+ -+ /* See if the port is in EP mode, indicated by header type 00 */ -+ tmp8 = bcma_pcie2_read_config8(bdev, 0, devfn, PCI_HEADER_TYPE); -+ if (tmp8 != PCI_HEADER_TYPE_BRIDGE) { -+ dev_info(&bdev->dev, "Port %d in End-Point mode - ignored\n", -+ bdev->core_unit); -+ return -ENODEV; -+ } -+ -+ return 0; -+} -+ -+/* -+ * Initializte the PCIe controller -+ */ -+static void bcma_pcie2_hw_init(struct bcma_device *bdev) -+{ -+ u32 devfn = 0; -+ u32 tmp32; -+ u16 tmp16; -+ -+ /* Change MPS and MRRS to 512 */ -+ tmp16 = bcma_pcie2_read_config16(bdev, 0, devfn, 0x4d4); -+ tmp16 &= ~7; -+ tmp16 |= 2; -+ bcma_pcie2_write_config16(bdev, 0, devfn, 0x4d4, tmp16); -+ -+ tmp32 = bcma_pcie2_read_config32(bdev, 0, devfn, 0xb4); -+ tmp32 &= ~((7 << 12) | (7 << 5)); -+ tmp32 |= (2 << 12) | (2 << 5); -+ bcma_pcie2_write_config32(bdev, 0, devfn, 0xb4, tmp32); -+ -+ /* Turn-on Root-Complex (RC) mode, from reset defailt of EP */ -+ -+ /* The mode is set by straps, can be overwritten via DMU -+ register <cru_straps_control> bit 5, "1" means RC -+ */ -+ -+ /* Send a downstream reset */ -+ bcma_write32(bdev, SOC_PCIE_CONTROL, 0x3); -+ udelay(250); -+ bcma_write32(bdev, SOC_PCIE_CONTROL, 0x1); -+ mdelay(250); -+ -+ /* TBD: take care of PM, check we're on */ -+} -+ -+/* -+ * Setup the address translation -+ */ -+static void bcma_pcie2_map_init(struct bcma_device *bdev) -+{ -+ unsigned size, i; -+ u32 addr; -+ -+ /* -+ * NOTE: -+ * All PCI-to-CPU address mapping are 1:1 for simplicity -+ */ -+ -+ /* Outbound address translation setup */ -+ size = SZ_128M; -+ addr = bdev->addr_s[0]; -+ BUG_ON(!addr); -+ BUG_ON(addr & ((1 << 25) - 1)); /* 64MB alignment */ -+ -+ for (i = 0; i < 3; i++) { -+ const unsigned win_size = SZ_64M; -+ /* 64-bit LE regs, write low word, high is 0 at reset */ -+ bcma_write32(bdev, SOC_PCIE_SYS_OMAP(i), addr); -+ bcma_write32(bdev, SOC_PCIE_SYS_OARR(i), addr|0x1); -+ addr += win_size; -+ if (size >= win_size) -+ size -= win_size; -+ if (size == 0) -+ break; -+ } -+ WARN_ON(size > 0); -+ -+ /* -+ * Inbound address translation setup -+ * Northstar only maps up to 128 MiB inbound, DRAM could be up to 1 GiB. -+ * -+ * For now allow access to entire DRAM, assuming it is less than 128MiB, -+ * otherwise DMA bouncing mechanism may be required. -+ * Also consider DMA mask to limit DMA physical address -+ */ -+ size = SZ_128M; -+ addr = PHYS_OFFSET; -+ -+ size >>= 20; /* In MB */ -+ size &= 0xff; /* Size is an 8-bit field */ -+ -+ WARN_ON(size == 0); -+ /* 64-bit LE regs, write low word, high is 0 at reset */ -+ bcma_write32(bdev, SOC_PCIE_SYS_IMAP1(0), addr | 0x1); -+ bcma_write32(bdev, SOC_PCIE_SYS_IARR(1), addr | size); -+ -+#ifdef CONFIG_SPARSEMEM -+ addr = PHYS_OFFSET2; -+ bcma_write32(bdev, SOC_PCIE_SYS_IMAP2(0), addr | 0x1); -+ bcma_write32(bdev, SOC_PCIE_SYS_IARR(2), addr | size); -+#endif -+} -+ -+/* -+ * Setup PCIE Host bridge -+ */ -+static void bcma_pcie2_bridge_init(struct bcma_device *bdev) -+{ -+ u32 devfn = 0; -+ u8 tmp8; -+ u16 tmp16; -+ -+ bcma_pcie2_write_config8(bdev, 0, devfn, PCI_PRIMARY_BUS, 0); -+ bcma_pcie2_write_config8(bdev, 0, devfn, PCI_SECONDARY_BUS, 1); -+ bcma_pcie2_write_config8(bdev, 0, devfn, PCI_SUBORDINATE_BUS, 4); -+ -+ tmp8 = bcma_pcie2_read_config8(bdev, 0, devfn, PCI_PRIMARY_BUS); -+ tmp8 = bcma_pcie2_read_config8(bdev, 0, devfn, PCI_SECONDARY_BUS); -+ tmp8 = bcma_pcie2_read_config8(bdev, 0, devfn, PCI_SUBORDINATE_BUS); -+ -+ /* MEM_BASE, MEM_LIM require 1MB alignment */ -+ BUG_ON((bdev->addr_s[0] >> 16) & 0xf); -+ bcma_pcie2_write_config16(bdev, 0, devfn, PCI_MEMORY_BASE, -+ bdev->addr_s[0] >> 16); -+ BUG_ON(((bdev->addr_s[0] + SZ_128M) >> 16) & 0xf); -+ bcma_pcie2_write_config16(bdev, 0, devfn, PCI_MEMORY_LIMIT, -+ (bdev->addr_s[0] + SZ_128M) >> 16); -+ -+ /* These registers are not supported on the NS */ -+ bcma_pcie2_write_config16(bdev, 0, devfn, PCI_IO_BASE_UPPER16, 0); -+ bcma_pcie2_write_config16(bdev, 0, devfn, PCI_IO_LIMIT_UPPER16, 0); -+ -+ /* Force class to that of a Bridge */ -+ bcma_pcie2_write_config16(bdev, 0, devfn, PCI_CLASS_DEVICE, -+ PCI_CLASS_BRIDGE_PCI); -+ -+ tmp16 = bcma_pcie2_read_config16(bdev, 0, devfn, PCI_CLASS_DEVICE); -+ tmp16 = bcma_pcie2_read_config16(bdev, 0, devfn, PCI_MEMORY_BASE); -+ tmp16 = bcma_pcie2_read_config16(bdev, 0, devfn, PCI_MEMORY_LIMIT); -+} -+ -+static int bcma_pcie2_allow_gen2_rc(struct bcma_device *bdev) -+{ -+ u32 vendorid, devid, chipid, chiprev; -+ u32 val, bar; -+ void __iomem *base; -+ int allow = 1; -+ -+ /* Read PCI vendor/device ID's */ -+ bcma_write32(bdev, SOC_PCIE_CFG_ADDR, 0x0); -+ val = bcma_read32(bdev, SOC_PCIE_CFG_DATA); -+ vendorid = val & 0xffff; -+ devid = val >> 16; -+ if (vendorid == PCI_VENDOR_ID_BROADCOM && -+ (devid == BCMA_CHIP_ID_BCM4360 || devid == BCM4360_D11AC_ID || -+ devid == BCM4360_D11AC2G_ID || devid == BCM4360_D11AC5G_ID || -+ devid == BCM4352_D11AC_ID || devid == BCM4352_D11AC2G_ID || -+ devid == BCM4352_D11AC5G_ID)) { -+ /* Config BAR0 */ -+ bar = bdev->addr_s[0]; -+ bcma_write32(bdev, SOC_PCIE_CFG_ADDR, 0x10); -+ bcma_write32(bdev, SOC_PCIE_CFG_DATA, bar); -+ /* Config BAR0 window to access chipc */ -+ bcma_write32(bdev, SOC_PCIE_CFG_ADDR, 0x80); -+ bcma_write32(bdev, SOC_PCIE_CFG_DATA, SI_ENUM_BASE); -+ -+ /* Enable memory resource */ -+ bcma_write32(bdev, SOC_PCIE_CFG_ADDR, 0x4); -+ val = bcma_read32(bdev, SOC_PCIE_CFG_DATA); -+ val |= PCI_COMMAND_MEMORY; -+ bcma_write32(bdev, SOC_PCIE_CFG_DATA, val); -+ /* Enable memory and bus master */ -+ bcma_write32(bdev, SOC_PCIE_HDR_OFF + 4, 0x6); -+ -+ /* Read CHIP ID */ -+ base = ioremap(bar, 0x1000); -+ val = __raw_readl(base); -+ iounmap(base); -+ chipid = val & 0xffff; -+ chiprev = (val >> 16) & 0xf; -+ if ((chipid == BCMA_CHIP_ID_BCM4360 || -+ chipid == BCMA_CHIP_ID_BCM43460 || -+ chipid == BCMA_CHIP_ID_BCM4352) && (chiprev < 3)) -+ allow = 0; -+ } -+ return allow; -+} -+ -+static void bcma_pcie2_3rd_init(struct bcma_bus *bus) -+{ -+ /* PCIE PLL block register (base 0x8000) */ -+ bcma_chipco_b_mii_write(&bus->drv_cc_b, 0x00000088, 0x57fe8000); -+ /* Check PCIE PLL lock status */ -+ bcma_chipco_b_mii_write(&bus->drv_cc_b, 0x00000088, 0x67c60000); -+} -+ -+/* To improve PCIE phy jitter */ -+static void bcma_pcie2_improve_phy_jitter(struct bcma_bus *bus, int phyaddr) -+{ -+ u32 val; -+ -+ /* Change blkaddr */ -+ val = (1 << 30) | (1 << 28) | (phyaddr << 23) | (0x1f << 18) | -+ (2 << 16) | (0x863 << 4); -+ bcma_chipco_b_mii_write(&bus->drv_cc_b, 0x0000009a, val); -+ -+ /* Write 0x0190 to 0x13 regaddr */ -+ val = (1 << 30) | (1 << 28) | (phyaddr << 23) | (0x13 << 18) | -+ (2 << 16) | 0x0190; -+ bcma_chipco_b_mii_write(&bus->drv_cc_b, 0x0000009a, val); -+ -+ /* Write 0x0191 to 0x19 regaddr */ -+ val = (1 << 30) | (1 << 28) | (phyaddr << 23) | (0x19 << 18) | -+ (2 << 16) | 0x0191; -+ bcma_chipco_b_mii_write(&bus->drv_cc_b, 0x0000009a, val); -+} -+ -+static int bcma_pcie2_setup(int nr, struct pci_sys_data *sys) -+{ -+ struct bcma_device *bdev = sys->private_data; -+ struct bcma_bus *bus = bdev->bus; -+ struct resource *res; -+ struct bcma_device *arm_core; -+ u32 cru_straps_ctrl; -+ int allow_gen2, linkfail; -+ int phyaddr; -+ -+ if (bdev->core_unit == 2) { -+ arm_core = bcma_find_core(bus, BCMA_CORE_ARMCA9); -+ cru_straps_ctrl = bcma_read32(arm_core, 0x2a0); -+ -+ /* 3rd PCIE is not selected */ -+ if (cru_straps_ctrl & 0x10) -+ return -ENODEV; -+ -+ bcma_pcie2_3rd_init(bus); -+ phyaddr = 0xf; -+ } else { -+ phyaddr = bdev->core_unit; -+ } -+ bcma_pcie2_improve_phy_jitter(bus, phyaddr); -+ -+ /* create mem resource */ -+ res = devm_kzalloc(&bdev->dev, sizeof(*res), GFP_KERNEL); -+ if (!res) { -+ dev_info(&bdev->dev, "requesting resource at 0x%x failed\n", -+ bdev->addr_s[0]); -+ return -EINVAL; -+ } -+ res->start = bdev->addr_s[0]; -+ res->end = res->start + SZ_128M - 1; -+ res->name = "PCIe Configuration Space"; -+ res->flags = IORESOURCE_MEM; -+ -+ pci_add_resource(&sys->resources, res); -+ -+ /* This PCIe controller does not support IO Mem, so use a dummy one. */ -+ res = devm_kzalloc(&bdev->dev, sizeof(*res), GFP_KERNEL); -+ if (!res) { -+ dev_info(&bdev->dev, "requesting resource at 0x%x failed\n", -+ bdev->addr_s[0]); -+ return -EINVAL; -+ } -+ res->start = bdev->addr_s[0]; -+ res->end = res->start + SZ_128M - 1; -+ res->name = "PCIe Configuration Space"; -+ res->flags = IORESOURCE_IO; -+ -+ pci_add_resource(&sys->resources, res); -+ -+ for (allow_gen2 = 0; allow_gen2 <= 1; allow_gen2++) { -+ bcma_pcie2_hw_init(bdev); -+ bcma_pcie2_map_init(bdev); -+ -+ /* -+ * Skip inactive ports - -+ * will need to change this for hot-plugging -+ */ -+ linkfail = bcma_pcie2_check_link(bdev, allow_gen2); -+ if (linkfail) -+ break; -+ -+ bcma_pcie2_bridge_init(bdev); -+ -+ if (allow_gen2 == 0) { -+ if (bcma_pcie2_allow_gen2_rc(bdev) == 0) -+ break; -+ dev_info(&bdev->dev, "switching to GEN2\n"); -+ } -+ } -+ -+ if (linkfail) -+ return -1; -+ -+ return 1; -+} -+ -+/* -+ * Methods for accessing configuration registers -+ */ -+static struct pci_ops bcma_pcie2_ops = { -+ .read = bcma_pcie2_read_config_pci, -+ .write = bcma_pcie2_write_config_pci, -+}; -+ -+static int bcma_pcie2_probe(struct bcma_device *bdev) -+{ -+ struct hw_pci hw; -+ -+ dev_info(&bdev->dev, "scanning bus\n"); -+ -+ hw = (struct hw_pci) { -+ .nr_controllers = 1, -+ .domain = bdev->core_unit, -+ .private_data = (void **)&bdev, -+ .setup = bcma_pcie2_setup, -+ .map_irq = bcma_pcie2_map_irq, -+ .ops = &bcma_pcie2_ops, -+ }; -+ -+ /* Announce this port to ARM/PCI common code */ -+ pci_common_init_dev(&bdev->dev, &hw); -+ -+ /* Setup virtual-wire interrupts */ -+ bcma_write32(bdev, SOC_PCIE_SYS_RC_INTX_EN, 0xf); -+ -+ /* Enable memory and bus master */ -+ bcma_write32(bdev, SOC_PCIE_HDR_OFF + 4, 0x6); -+ -+ return 0; -+} -+ -+static const struct bcma_device_id bcma_pcie2_table[] = { -+ BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_NS_PCIEG2, BCMA_ANY_REV, BCMA_ANY_CLASS), -+ BCMA_CORETABLE_END -+}; -+MODULE_DEVICE_TABLE(bcma, bcma_pcie2_table); -+ -+static struct bcma_driver bcma_pcie2_driver = { -+ .name = KBUILD_MODNAME, -+ .id_table = bcma_pcie2_table, -+ .probe = bcma_pcie2_probe, -+}; -+ -+static int __init bcma_pcie2_init(void) -+{ -+ return bcma_driver_register(&bcma_pcie2_driver); -+} -+module_init(bcma_pcie2_init); -+ -+static void __exit bcma_pcie2_exit(void) -+{ -+ bcma_driver_unregister(&bcma_pcie2_driver); -+} -+module_exit(bcma_pcie2_exit); -+ -+MODULE_AUTHOR("Hauke Mehrtens"); -+MODULE_DESCRIPTION("PCIe Gen2 driver for BCMA"); -+MODULE_LICENSE("GPLv2"); |