bcm53xx: update the PCIe driver
authorHauke Mehrtens <hauke@openwrt.org>
Sun, 7 Dec 2014 21:54:53 +0000 (21:54 +0000)
committerHauke Mehrtens <hauke@openwrt.org>
Sun, 7 Dec 2014 21:54:53 +0000 (21:54 +0000)
This adds some updates to the PCIe driver and refreshed the config.

Most of these changes are done in preparation for mainling it.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@43545 3c298f89-4303-0410-b956-a3cf2f4a3e73

target/linux/bcm53xx/config-3.14
target/linux/bcm53xx/config-3.18
target/linux/bcm53xx/patches-3.14/170-pcie2-bcma-add-new-PCIe2-driver-for-bcma.patch
target/linux/bcm53xx/patches-3.18/170-pcie2-bcma-add-new-PCIe2-driver-for-bcma.patch

index 322da68..4c9ec0c 100644 (file)
@@ -110,7 +110,6 @@ CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
 CONFIG_GENERIC_IDLE_POLL_SETUP=y
 CONFIG_GENERIC_IO=y
 CONFIG_GENERIC_IRQ_SHOW=y
 CONFIG_GENERIC_IDLE_POLL_SETUP=y
 CONFIG_GENERIC_IO=y
 CONFIG_GENERIC_IRQ_SHOW=y
-CONFIG_GENERIC_NET_UTILS=y
 CONFIG_GENERIC_PCI_IOMAP=y
 CONFIG_GENERIC_SCHED_CLOCK=y
 CONFIG_GENERIC_SMP_IDLE_THREAD=y
 CONFIG_GENERIC_PCI_IOMAP=y
 CONFIG_GENERIC_SCHED_CLOCK=y
 CONFIG_GENERIC_SMP_IDLE_THREAD=y
@@ -220,7 +219,7 @@ CONFIG_OUTER_CACHE_SYNC=y
 CONFIG_PAGEFLAGS_EXTENDED=y
 CONFIG_PAGE_OFFSET=0xC0000000
 CONFIG_PCI=y
 CONFIG_PAGEFLAGS_EXTENDED=y
 CONFIG_PAGE_OFFSET=0xC0000000
 CONFIG_PCI=y
-CONFIG_PCI_BCMA=y
+CONFIG_PCI_BCM5301X=y
 CONFIG_PCI_DOMAINS=y
 CONFIG_PERF_USE_VMALLOC=y
 CONFIG_PHYLIB=y
 CONFIG_PCI_DOMAINS=y
 CONFIG_PERF_USE_VMALLOC=y
 CONFIG_PHYLIB=y
index 3d6f3cd..f42639a 100644 (file)
@@ -10,18 +10,13 @@ CONFIG_ARCH_HAS_SG_CHAIN=y
 CONFIG_ARCH_HAS_TICK_BROADCAST=y
 CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
 CONFIG_ARCH_HIBERNATION_POSSIBLE=y
 CONFIG_ARCH_HAS_TICK_BROADCAST=y
 CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
 CONFIG_ARCH_HIBERNATION_POSSIBLE=y
-# CONFIG_ARCH_HISI is not set
-# CONFIG_ARCH_MEDIATEK is not set
-# CONFIG_ARCH_MESON is not set
 CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
 CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
-# CONFIG_ARCH_MSM is not set
 CONFIG_ARCH_MULTIPLATFORM=y
 # CONFIG_ARCH_MULTI_CPU_AUTO is not set
 CONFIG_ARCH_MULTI_V6_V7=y
 CONFIG_ARCH_MULTI_V7=y
 # CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
 CONFIG_ARCH_NR_GPIO=0
 CONFIG_ARCH_MULTIPLATFORM=y
 # CONFIG_ARCH_MULTI_CPU_AUTO is not set
 CONFIG_ARCH_MULTI_V6_V7=y
 CONFIG_ARCH_MULTI_V7=y
 # CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
 CONFIG_ARCH_NR_GPIO=0
-# CONFIG_ARCH_QCOM is not set
 # CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
 # CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
 CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y
 # CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
 # CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
 CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y
@@ -122,7 +117,6 @@ CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
 CONFIG_GENERIC_IDLE_POLL_SETUP=y
 CONFIG_GENERIC_IO=y
 CONFIG_GENERIC_IRQ_SHOW=y
 CONFIG_GENERIC_IDLE_POLL_SETUP=y
 CONFIG_GENERIC_IO=y
 CONFIG_GENERIC_IRQ_SHOW=y
-CONFIG_GENERIC_NET_UTILS=y
 CONFIG_GENERIC_PCI_IOMAP=y
 CONFIG_GENERIC_SCHED_CLOCK=y
 CONFIG_GENERIC_SMP_IDLE_THREAD=y
 CONFIG_GENERIC_PCI_IOMAP=y
 CONFIG_GENERIC_SCHED_CLOCK=y
 CONFIG_GENERIC_SMP_IDLE_THREAD=y
@@ -204,7 +198,6 @@ CONFIG_MTD_NAND_ECC=y
 # CONFIG_MTD_PHYSMAP_OF is not set
 CONFIG_MTD_SPI_BCM53XXSPIFLASH=y
 CONFIG_MTD_SPI_NOR=y
 # CONFIG_MTD_PHYSMAP_OF is not set
 CONFIG_MTD_SPI_BCM53XXSPIFLASH=y
 CONFIG_MTD_SPI_NOR=y
-# CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set
 CONFIG_MTD_UBI=y
 CONFIG_MTD_UBI_BEB_LIMIT=20
 CONFIG_MTD_UBI_BLOCK=y
 CONFIG_MTD_UBI=y
 CONFIG_MTD_UBI_BEB_LIMIT=20
 CONFIG_MTD_UBI_BLOCK=y
@@ -237,7 +230,7 @@ CONFIG_OUTER_CACHE_SYNC=y
 CONFIG_PAGEFLAGS_EXTENDED=y
 CONFIG_PAGE_OFFSET=0xC0000000
 CONFIG_PCI=y
 CONFIG_PAGEFLAGS_EXTENDED=y
 CONFIG_PAGE_OFFSET=0xC0000000
 CONFIG_PCI=y
-CONFIG_PCI_BCMA=y
+CONFIG_PCI_BCM5301X=y
 CONFIG_PCI_DOMAINS=y
 CONFIG_PERF_USE_VMALLOC=y
 CONFIG_PHYLIB=y
 CONFIG_PCI_DOMAINS=y
 CONFIG_PERF_USE_VMALLOC=y
 CONFIG_PHYLIB=y
index 1b6149f..dcdbb8f 100644 (file)
@@ -1,19 +1,43 @@
-From cc2cda651fcbc498bf513a6b802dca19944bcb37 Mon Sep 17 00:00:00 2001
+From cf067bf8bb993d6cfdc42d750ae241c43f88403f Mon Sep 17 00:00:00 2001
 From: Hauke Mehrtens <hauke@hauke-m.de>
 Date: Mon, 12 May 2014 11:55:20 +0200
 From: Hauke Mehrtens <hauke@hauke-m.de>
 Date: Mon, 12 May 2014 11:55:20 +0200
-Subject: [PATCH 13/17] pcie2-bcma: add new PCIe2 driver for bcma
+Subject: [PATCH 1/2] PCI: BCM5301X: add PCIe2 driver for BCM5301X SoCs
 
 This driver supports the PCIe controller found on the BCM4708 and
 similar SoCs. The controller itself is automatically detected by bcma.
 
 
 This driver supports the PCIe controller found on the BCM4708 and
 similar SoCs. The controller itself is automatically detected by bcma.
 
+This controller is found on SoCs usually used in SOHO routers to
+connect the wifi cards to the SoC. All the of the BCM5301X SoCs I know
+of have 2 or 3 of these controllers in the SoC.
+
+I had to use PCI domains otherwise the pci_create_root_bus() function
+in drivers/pci/probe.c would fail for the second controller being
+registered because pci_find_bus() would find the same PCIe bus again
+and assume it is already registered, which ends up in a kernel panic in
+pcibios_init_hw() in arch/arm/kernel/bios32.c
+
+The ARM PCI code assumes that every controller has an I/O space and
+adds a dummy area if the driver does not specify one. This will work
+for the first controller, but when we register the second one this will
+result in an error. To prevent this problem we add an empty I/O space.
+
+Currently I have problems with probing the devices on the bus, because
+pci_bus_add_devices() is called too early in pci_scan_root_bus() in
+drivers/pci/probe.c, before pci_bus_assign_resources() was called in
+pci_common_init_dev() in arch/arm/kernel/bios32.c. When the devices are
+added too early they do not have any resources and adding fails. I have
+to remove the call to pci_bus_add_devices() in pci_scan_root_bus() to
+make registration work, calling pci_bus_add_devices() later again does
+not fix this problem.
+
 Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
 ---
 Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
 ---
- arch/arm/mach-bcm/Kconfig     |   2 +
- drivers/pci/host/Kconfig      |   7 +
- drivers/pci/host/Makefile     |   1 +
- drivers/pci/host/pcie2-bcma.c | 591 ++++++++++++++++++++++++++++++++++++++++++
- 4 files changed, 601 insertions(+)
- create mode 100644 drivers/pci/host/pcie2-bcma.c
+ arch/arm/mach-bcm/Kconfig            |   1 +
+ drivers/pci/host/Kconfig             |   7 +
+ drivers/pci/host/Makefile            |   1 +
+ drivers/pci/host/pci-host-bcm5301x.c | 428 +++++++++++++++++++++++++++++++++++
+ 4 files changed, 437 insertions(+)
+ create mode 100644 drivers/pci/host/pci-host-bcm5301x.c
 
 --- a/arch/arm/mach-bcm/Kconfig
 +++ b/arch/arm/mach-bcm/Kconfig
 
 --- a/arch/arm/mach-bcm/Kconfig
 +++ b/arch/arm/mach-bcm/Kconfig
@@ -31,12 +55,12 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
          There are 3 internal PCI controllers available with a single
          built-in EHCI/OHCI host controller present on each one.
  
          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
++config PCI_BCM5301X
++      bool "BCM5301X PCIe2 host controller"
++      depends on BCMA && OF && ARM && PCI_DOMAINS
 +      help
 +      help
-+        Say Y here if you want to support a simple generic PCI host
-+        controller, such as the one emulated by kvmtool.
++        Say Y here if you want to support the PCIe host controller found
++        on Broadcom BCM5301X and BCM470X (Northstar) SoCs.
 +
  endmenu
 --- a/drivers/pci/host/Makefile
 +
  endmenu
 --- a/drivers/pci/host/Makefile
@@ -45,10 +69,10 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
  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_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
++obj-$(CONFIG_PCI_BCM5301X) += pci-host-bcm5301x.o
 --- /dev/null
 --- /dev/null
-+++ b/drivers/pci/host/pcie2-bcma.c
-@@ -0,0 +1,619 @@
++++ b/drivers/pci/host/pci-host-bcm5301x.c
+@@ -0,0 +1,428 @@
 +/*
 + * Northstar PCI-Express driver
 + * Only supports Root-Complex (RC) mode
 +/*
 + * Northstar PCI-Express driver
 + * Only supports Root-Complex (RC) mode
@@ -58,63 +82,25 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
 + *
 + * Only MEM access is supported, PAX does not support IO.
 + *
 + *
 + * Only MEM access is supported, PAX does not support IO.
 + *
-+ * TODO:
-+ *    MSI interrupts,
-+ *    DRAM > 128 MBytes (e.g. DMA zones)
++ * Copyright 2012-2014, Broadcom Corporation
++ * Copyright 2014, Hauke Mehrtens <hauke@hauke-m.de>
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
 + */
 +
 +#include <linux/kernel.h>
 +#include <linux/module.h>
 + */
 +
 +#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>
 +#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
++#include <linux/bcma/bcma_driver_pcie2.h>
++#include <linux/of_irq.h>
 +
 +#define       SOC_PCIE_HDR_OFF        0x400   /* 256 bytes per function */
 +
 +
 +#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 struct pci_ops bcma_pcie2_ops;
-+
 +static int bcma_pcie2_map_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
 +{
 +      struct pci_sys_data *sys = pdev->sysdata;
 +static int bcma_pcie2_map_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
 +{
 +      struct pci_sys_data *sys = pdev->sysdata;
@@ -133,16 +119,17 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
 +      if (busno == 0) {
 +              if (slot >= 1)
 +                      return 0;
 +      if (busno == 0) {
 +              if (slot >= 1)
 +                      return 0;
-+              bcma_write32(bdev, SOC_PCIE_EXT_CFG_ADDR, where & 0xffc);
-+              return SOC_PCIE_EXT_CFG_DATA;
++              bcma_write32(bdev, BCMA_CORE_PCIE2_CONFIGINDADDR,
++                           where & 0xffc);
++              return BCMA_CORE_PCIE2_CONFIGINDDATA;
 +      }
 +      if (fn > 1)
 +              return 0;
 +      addr_reg = (busno & 0xff) << 20 | (slot << 15) | (fn << 12) |
 +                 (where & 0xffc) | (1 & 0x3);
 +
 +      }
 +      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;
++      bcma_write32(bdev, BCMA_CORE_PCIE2_CFG_ADDR, addr_reg);
++      return BCMA_CORE_PCIE2_CFG_DATA;
 +}
 +
 +static u32 bcma_pcie2_read_config(struct bcma_device *bdev, int busno,
 +}
 +
 +static u32 bcma_pcie2_read_config(struct bcma_device *bdev, int busno,
@@ -160,20 +147,6 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
 +
 +      data_reg = bcma_read32(bdev, base);
 +
 +
 +      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;
 +
 +      if (size == 4)
 +              return data_reg;
 +
@@ -208,42 +181,6 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
 +      bcma_write32(bdev, base, data_reg);
 +}
 +
 +      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)
 +{
 +static int bcma_pcie2_read_config_pci(struct pci_bus *bus, unsigned int devfn,
 +                                 int where, int size, u32 *val)
 +{
@@ -267,31 +204,31 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
 +}
 +
 +/*
 +}
 +
 +/*
++ * Methods for accessing configuration registers
++ */
++static struct pci_ops bcma_pcie2_ops = {
++      .read = bcma_pcie2_read_config_pci,
++      .write = bcma_pcie2_write_config_pci,
++};
++
++/* NS: CLASS field is R/O, and set to wrong 0x200 value */
++static void bcma_pcie2_fixup_class(struct pci_dev *dev)
++{
++      dev->class = PCI_CLASS_BRIDGE_PCI << 8;
++}
++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_BROADCOM, 0x8011, bcma_pcie2_fixup_class);
++
++/*
 + * Check link status, return 0 if link is up in RC mode,
 + * otherwise return non-zero
 + */
 + * 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,
-+                               struct pci_sys_data *sys, u32 allow_gen2)
++static int bcma_pcie2_check_link(struct bcma_device *bdev, bool allow_gen2)
 +{
 +      u32 devfn = 0;
 +      u32 tmp32;
 +{
 +      u32 devfn = 0;
 +      u32 tmp32;
-+      u16 tmp16;
 +      u8 tmp8;
 +      u8 tmp8;
-+      int pos;
-+      bool link = false;
-+      /*
-+       * Setup callback (bcma_pcie2_setup) is called in pcibios_init_hw before
-+       * creating bus root, so we don't have it here yet. On the other hand
-+       * we really want to use pci_bus_find_capability helper to check NLW.
-+       * Let's fake simple pci_bus just to query for capabilities.
-+       */
-+      struct pci_bus bus = {
-+              .number = 0,
-+              .ops = &bcma_pcie2_ops,
-+              .sysdata = sys,
-+      };
 +
 +
-+      tmp32 = bcma_pcie2_read_config32(bdev, 0, devfn, 0xdc);
++      tmp32 = bcma_pcie2_read_config(bdev, 0, devfn, 0xdc, 4);
 +      tmp32 &= ~0xf;
 +      if (allow_gen2)
 +              tmp32 |= 2;
 +      tmp32 &= ~0xf;
 +      if (allow_gen2)
 +              tmp32 |= 2;
@@ -299,28 +236,17 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
 +              /* force PCIE GEN1 */
 +              tmp32 |= 1;
 +      }
 +              /* force PCIE GEN1 */
 +              tmp32 |= 1;
 +      }
-+      bcma_pcie2_write_config32(bdev, 0, devfn, 0xdc, tmp32);
++      bcma_pcie2_write_config(bdev, 0, devfn, 0xdc, 4, tmp32);
 +
 +      /* See if the port is in EP mode, indicated by header type 00 */
 +
 +      /* See if the port is in EP mode, indicated by header type 00 */
-+      tmp8 = bcma_pcie2_read_config8(bdev, 0, devfn, PCI_HEADER_TYPE);
++      tmp8 = bcma_pcie2_read_config(bdev, 0, devfn, PCI_HEADER_TYPE, 1);
 +      if (tmp8 != PCI_HEADER_TYPE_BRIDGE) {
 +              dev_info(&bdev->dev, "Port %d in End-Point mode - ignored\n",
 +                       bdev->core_unit);
 +              return -ENODEV;
 +      }
 +
 +      if (tmp8 != PCI_HEADER_TYPE_BRIDGE) {
 +              dev_info(&bdev->dev, "Port %d in End-Point mode - ignored\n",
 +                       bdev->core_unit);
 +              return -ENODEV;
 +      }
 +
-+      /* NS PAX only changes NLW field when card is present */
-+      pos = pci_bus_find_capability(&bus, devfn, PCI_CAP_ID_EXP);
-+      if (pos) {
-+              u8 nlw;
-+
-+              pci_bus_read_config_word(&bus, devfn, pos + PCI_EXP_LNKSTA,
-+                                       &tmp16);
-+              nlw = (tmp16 & PCI_EXP_LNKSTA_NLW) >> PCI_EXP_LNKSTA_NLW_SHIFT;
-+              link = (tmp16 & PCI_EXP_LNKSTA_DLLLA) || nlw != 0;
-+      }
-+
-+      return link ? 0 : -ENODEV;
++      return 0;
 +}
 +
 +/*
 +}
 +
 +/*
@@ -328,67 +254,52 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
 + */
 +static void bcma_pcie2_hw_init(struct bcma_device *bdev)
 +{
 + */
 +static void bcma_pcie2_hw_init(struct bcma_device *bdev)
 +{
-+      u32 devfn = 0;
 +      u32 tmp32;
 +      u16 tmp16;
 +
 +      /* Change MPS and MRRS to 512 */
 +      u32 tmp32;
 +      u16 tmp16;
 +
 +      /* Change MPS and MRRS to 512 */
-+      tmp16 = bcma_pcie2_read_config16(bdev, 0, devfn, 0x4d4);
++      tmp16 = bcma_pcie2_read_config(bdev, 0, 0, 0x4d4, 2);
 +      tmp16 &= ~7;
 +      tmp16 |= 2;
 +      tmp16 &= ~7;
 +      tmp16 |= 2;
-+      bcma_pcie2_write_config16(bdev, 0, devfn, 0x4d4, tmp16);
++      bcma_pcie2_write_config(bdev, 0, 0, 0x4d4, 2, tmp16);
 +
 +
-+      tmp32 = bcma_pcie2_read_config32(bdev, 0, devfn, 0xb4);
++      tmp32 = bcma_pcie2_read_config(bdev, 0, 0, 0xb4, 4);
 +      tmp32 &= ~((7 << 12) | (7 << 5));
 +      tmp32 |= (2 << 12) | (2 << 5);
 +      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 */
++      bcma_pcie2_write_config(bdev, 0, 0, 0xb4, 4, tmp32);
 +
 +
-+      /* The mode is set by straps, can be overwritten via DMU
-+         register <cru_straps_control> bit 5, "1" means RC
++      /*
++       * Turn-on Root-Complex (RC) mode, from reset default 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 */
 +       */
 +
 +      /* Send a downstream reset */
-+      bcma_write32(bdev, SOC_PCIE_CONTROL, 0x3);
-+      udelay(250);
-+      bcma_write32(bdev, SOC_PCIE_CONTROL, 0x1);
-+      mdelay(250);
++      bcma_write32(bdev, BCMA_CORE_PCIE2_CLK_CONTROL,
++                   PCIE2_CLKC_RST_OE | PCIE2_CLKC_RST);
++      usleep_range(250, 400);
++      bcma_write32(bdev, BCMA_CORE_PCIE2_CLK_CONTROL, PCIE2_CLKC_RST_OE);
++      msleep(250);
 +
 +      /* TBD: take care of PM, check we're on */
 +}
 +
 +/*
 + * Setup the address translation
 +
 +      /* TBD: take care of PM, check we're on */
 +}
 +
 +/*
 + * Setup the address translation
++ *
++ * NOTE: All PCI-to-CPU address mapping are 1:1 for simplicity
 + */
 + */
-+static void bcma_pcie2_map_init(struct bcma_device *bdev)
++static int bcma_pcie2_map_init(struct bcma_device *bdev, u32 addr)
 +{
 +{
-+      unsigned size, i;
-+      u32 addr;
++      /* 64MB alignment */
++      if (!addr || (addr & (SZ_64M - 1)))
++              return -EINVAL;
 +
 +
-+      /*
-+       * NOTE:
-+       * All PCI-to-CPU address mapping are 1:1 for simplicity
-+       */
++      bcma_write32(bdev, BCMA_CORE_PCIE2_OMAP0_LOWER, addr);
++      bcma_write32(bdev, BCMA_CORE_PCIE2_OARR0, addr | 0x01);
 +
 +
-+      /* 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);
++      bcma_write32(bdev, BCMA_CORE_PCIE2_OMAP1_LOWER, addr + SZ_64M);
++      bcma_write32(bdev, BCMA_CORE_PCIE2_OARR1, (addr + SZ_64M) | 0x01);
 +
 +      /*
 +       * Inbound address translation setup
 +
 +      /*
 +       * Inbound address translation setup
@@ -398,107 +309,46 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
 +       * otherwise DMA bouncing mechanism may be required.
 +       * Also consider DMA mask to limit DMA physical address
 +       */
 +       * 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 */
 +      /* 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
++      bcma_write32(bdev, BCMA_CORE_PCIE2_FUNC0_IMAP1, PHYS_OFFSET | 0x1);
++      bcma_write32(bdev, BCMA_CORE_PCIE2_IARR1_LOWER,
++                         PHYS_OFFSET | ((SZ_128M >> 20) & 0xff));
++      return 0;
 +}
 +
 +/*
 + * Setup PCIE Host bridge
 + */
 +}
 +
 +/*
 + * Setup PCIE Host bridge
 + */
-+static void bcma_pcie2_bridge_init(struct bcma_device *bdev)
++static int bcma_pcie2_bridge_init(struct bcma_device *bdev, u32 addr, u32 size)
 +{
 +{
-+      u32 devfn = 0;
-+      u8 tmp8;
-+      u16 tmp16;
++      bcma_pcie2_write_config(bdev, 0, 0, PCI_PRIMARY_BUS, 1, 0);
++      bcma_pcie2_write_config(bdev, 0, 0, PCI_SECONDARY_BUS, 1, 1);
++      bcma_pcie2_write_config(bdev, 0, 0, PCI_SUBORDINATE_BUS, 1, 4);
 +
 +
-+      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);
++      bcma_pcie2_read_config(bdev, 0, 0, PCI_PRIMARY_BUS, 1);
++      bcma_pcie2_read_config(bdev, 0, 0, PCI_SECONDARY_BUS, 1);
++      bcma_pcie2_read_config(bdev, 0, 0, PCI_SUBORDINATE_BUS, 1);
 +
 +      /* MEM_BASE, MEM_LIM require 1MB alignment */
 +
 +      /* 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);
++      if (((addr >> 16) & 0xf) || (((addr + size) >> 16) & 0xf))
++              return -EINVAL;
++
++      bcma_pcie2_write_config(bdev, 0, 0, PCI_MEMORY_BASE, 2, addr >> 16);
++      bcma_pcie2_write_config(bdev, 0, 0, PCI_MEMORY_LIMIT, 2,
++                              (addr + size) >> 16);
 +
 +      /* These registers are not supported on the NS */
 +
 +      /* 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);
++      bcma_pcie2_write_config(bdev, 0, 0, PCI_IO_BASE_UPPER16, 2, 0);
++      bcma_pcie2_write_config(bdev, 0, 0, PCI_IO_LIMIT_UPPER16, 2, 0);
 +
 +      /* Force class to that of a Bridge */
 +
 +      /* 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);
-+}
++      bcma_pcie2_write_config(bdev, 0, 0, PCI_CLASS_DEVICE, 2,
++                              PCI_CLASS_BRIDGE_PCI);
 +
 +
-+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;
++      bcma_pcie2_read_config(bdev, 0, 0, PCI_CLASS_DEVICE, 2);
++      bcma_pcie2_read_config(bdev, 0, 0, PCI_MEMORY_BASE, 2);
++      bcma_pcie2_read_config(bdev, 0, 0, PCI_MEMORY_LIMIT, 2);
++      return 0;
 +}
 +
 +static void bcma_pcie2_3rd_init(struct bcma_bus *bus)
 +}
 +
 +static void bcma_pcie2_3rd_init(struct bcma_bus *bus)
@@ -537,7 +387,7 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
 +      struct resource *res;
 +      struct bcma_device *arm_core;
 +      u32 cru_straps_ctrl;
 +      struct resource *res;
 +      struct bcma_device *arm_core;
 +      u32 cru_straps_ctrl;
-+      int allow_gen2, linkfail;
++      int ret;
 +      int phyaddr;
 +
 +      if (bdev->core_unit == 2) {
 +      int phyaddr;
 +
 +      if (bdev->core_unit == 2) {
@@ -561,8 +411,8 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
 +              return -EINVAL;
 +
 +      res->start = 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->end = bdev->addr_s[0] + SZ_128M -1;
++      res->name = "PCIe dummy IO space";
 +      res->flags = IORESOURCE_MEM;
 +
 +      pci_add_resource(&sys->resources, res);
 +      res->flags = IORESOURCE_MEM;
 +
 +      pci_add_resource(&sys->resources, res);
@@ -572,55 +422,36 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
 +      if (!res)
 +              return -EINVAL;
 +
 +      if (!res)
 +              return -EINVAL;
 +
-+      res->start = bdev->addr_s[0];
-+      res->end = res->start + SZ_128M - 1;
-+      res->name = "PCIe Configuration Space";
++      res->start = 0;
++      res->end = 0;
++      res->name = "PCIe dummy IO space";
 +      res->flags = IORESOURCE_IO;
 +
 +      pci_add_resource(&sys->resources, res);
 +
 +      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, sys, 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");
-+              }
-+      }
++      bcma_pcie2_hw_init(bdev);
++      ret = bcma_pcie2_map_init(bdev, bdev->addr_s[0]);
++      if (ret)
++              return ret;
++
++      /*
++       * Skip inactive ports -
++       * will need to change this for hot-plugging
++       */
++      ret = bcma_pcie2_check_link(bdev, true);
++      if (ret)
++              return ret;
 +
 +
-+      if (linkfail)
-+              return -1;
++      ret = bcma_pcie2_bridge_init(bdev, bdev->addr_s[0], SZ_128M);
++      if (ret)
++              return ret;
 +
 +      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)
 +{
 +static int bcma_pcie2_probe(struct bcma_device *bdev)
 +{
-+      struct hw_pci hw;
-+
-+      dev_info(&bdev->dev, "scanning bus\n");
-+
-+      hw = (struct hw_pci) {
++      struct hw_pci hw = {
 +              .nr_controllers = 1,
 +              .domain         = bdev->core_unit,
 +              .private_data   = (void **)&bdev,
 +              .nr_controllers = 1,
 +              .domain         = bdev->core_unit,
 +              .private_data   = (void **)&bdev,
@@ -629,11 +460,13 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
 +              .ops            = &bcma_pcie2_ops,
 +      };
 +
 +              .ops            = &bcma_pcie2_ops,
 +      };
 +
++      dev_info(&bdev->dev, "initializing PCIe controller\n");
++
 +      /* Announce this port to ARM/PCI common code */
 +      pci_common_init_dev(&bdev->dev, &hw);
 +
 +      /* Setup virtual-wire interrupts */
 +      /* 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);
++      bcma_write32(bdev, BCMA_CORE_PCIE2_SYS_RC_INTX_EN, 0xf);
 +
 +      /* Enable memory and bus master */
 +      bcma_write32(bdev, SOC_PCIE_HDR_OFF + 4, 0x6);
 +
 +      /* Enable memory and bus master */
 +      bcma_write32(bdev, SOC_PCIE_HDR_OFF + 4, 0x6);
@@ -666,5 +499,5 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
 +module_exit(bcma_pcie2_exit);
 +
 +MODULE_AUTHOR("Hauke Mehrtens");
 +module_exit(bcma_pcie2_exit);
 +
 +MODULE_AUTHOR("Hauke Mehrtens");
-+MODULE_DESCRIPTION("PCIe Gen2 driver for BCMA");
++MODULE_DESCRIPTION("BCM5301X PCIe host controller");
 +MODULE_LICENSE("GPLv2");
 +MODULE_LICENSE("GPLv2");
index 3efdeea..fc616d7 100644 (file)
@@ -1,19 +1,43 @@
-From cc2cda651fcbc498bf513a6b802dca19944bcb37 Mon Sep 17 00:00:00 2001
+From cf067bf8bb993d6cfdc42d750ae241c43f88403f Mon Sep 17 00:00:00 2001
 From: Hauke Mehrtens <hauke@hauke-m.de>
 Date: Mon, 12 May 2014 11:55:20 +0200
 From: Hauke Mehrtens <hauke@hauke-m.de>
 Date: Mon, 12 May 2014 11:55:20 +0200
-Subject: [PATCH 13/17] pcie2-bcma: add new PCIe2 driver for bcma
+Subject: [PATCH 1/2] PCI: BCM5301X: add PCIe2 driver for BCM5301X SoCs
 
 This driver supports the PCIe controller found on the BCM4708 and
 similar SoCs. The controller itself is automatically detected by bcma.
 
 
 This driver supports the PCIe controller found on the BCM4708 and
 similar SoCs. The controller itself is automatically detected by bcma.
 
+This controller is found on SoCs usually used in SOHO routers to
+connect the wifi cards to the SoC. All the of the BCM5301X SoCs I know
+of have 2 or 3 of these controllers in the SoC.
+
+I had to use PCI domains otherwise the pci_create_root_bus() function
+in drivers/pci/probe.c would fail for the second controller being
+registered because pci_find_bus() would find the same PCIe bus again
+and assume it is already registered, which ends up in a kernel panic in
+pcibios_init_hw() in arch/arm/kernel/bios32.c
+
+The ARM PCI code assumes that every controller has an I/O space and
+adds a dummy area if the driver does not specify one. This will work
+for the first controller, but when we register the second one this will
+result in an error. To prevent this problem we add an empty I/O space.
+
+Currently I have problems with probing the devices on the bus, because
+pci_bus_add_devices() is called too early in pci_scan_root_bus() in
+drivers/pci/probe.c, before pci_bus_assign_resources() was called in
+pci_common_init_dev() in arch/arm/kernel/bios32.c. When the devices are
+added too early they do not have any resources and adding fails. I have
+to remove the call to pci_bus_add_devices() in pci_scan_root_bus() to
+make registration work, calling pci_bus_add_devices() later again does
+not fix this problem.
+
 Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
 ---
 Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
 ---
- arch/arm/mach-bcm/Kconfig     |   2 +
- drivers/pci/host/Kconfig      |   7 +
- drivers/pci/host/Makefile     |   1 +
- drivers/pci/host/pcie2-bcma.c | 591 ++++++++++++++++++++++++++++++++++++++++++
- 4 files changed, 601 insertions(+)
- create mode 100644 drivers/pci/host/pcie2-bcma.c
+ arch/arm/mach-bcm/Kconfig            |   1 +
+ drivers/pci/host/Kconfig             |   7 +
+ drivers/pci/host/Makefile            |   1 +
+ drivers/pci/host/pci-host-bcm5301x.c | 428 +++++++++++++++++++++++++++++++++++
+ 4 files changed, 437 insertions(+)
+ create mode 100644 drivers/pci/host/pci-host-bcm5301x.c
 
 --- a/arch/arm/mach-bcm/Kconfig
 +++ b/arch/arm/mach-bcm/Kconfig
 
 --- a/arch/arm/mach-bcm/Kconfig
 +++ b/arch/arm/mach-bcm/Kconfig
@@ -31,12 +55,12 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
          There are 5 internal PCIe ports available. Each port is GEN3 capable
          and have varied lanes from x1 to x8.
  
          There are 5 internal PCIe ports available. Each port is GEN3 capable
          and have varied lanes from x1 to x8.
  
-+config PCI_BCMA
-+      bool "BCMA PCIe2 host controller"
-+      depends on BCMA && OF
++config PCI_BCM5301X
++      bool "BCM5301X PCIe2 host controller"
++      depends on BCMA && OF && ARM && PCI_DOMAINS
 +      help
 +      help
-+        Say Y here if you want to support a simple generic PCI host
-+        controller, such as the one emulated by kvmtool.
++        Say Y here if you want to support the PCIe host controller found
++        on Broadcom BCM5301X and BCM470X (Northstar) SoCs.
 +
  endmenu
 --- a/drivers/pci/host/Makefile
 +
  endmenu
 --- a/drivers/pci/host/Makefile
@@ -45,10 +69,10 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
  obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone-dw.o pci-keystone.o
  obj-$(CONFIG_PCIE_XILINX) += pcie-xilinx.o
  obj-$(CONFIG_PCI_XGENE) += pci-xgene.o
  obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone-dw.o pci-keystone.o
  obj-$(CONFIG_PCIE_XILINX) += pcie-xilinx.o
  obj-$(CONFIG_PCI_XGENE) += pci-xgene.o
-+obj-$(CONFIG_PCI_BCMA) += pcie2-bcma.o
++obj-$(CONFIG_PCI_BCM5301X) += pci-host-bcm5301x.o
 --- /dev/null
 --- /dev/null
-+++ b/drivers/pci/host/pcie2-bcma.c
-@@ -0,0 +1,619 @@
++++ b/drivers/pci/host/pci-host-bcm5301x.c
+@@ -0,0 +1,428 @@
 +/*
 + * Northstar PCI-Express driver
 + * Only supports Root-Complex (RC) mode
 +/*
 + * Northstar PCI-Express driver
 + * Only supports Root-Complex (RC) mode
@@ -58,63 +82,25 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
 + *
 + * Only MEM access is supported, PAX does not support IO.
 + *
 + *
 + * Only MEM access is supported, PAX does not support IO.
 + *
-+ * TODO:
-+ *    MSI interrupts,
-+ *    DRAM > 128 MBytes (e.g. DMA zones)
++ * Copyright 2012-2014, Broadcom Corporation
++ * Copyright 2014, Hauke Mehrtens <hauke@hauke-m.de>
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
 + */
 +
 +#include <linux/kernel.h>
 +#include <linux/module.h>
 + */
 +
 +#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>
 +#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
++#include <linux/bcma/bcma_driver_pcie2.h>
++#include <linux/of_irq.h>
 +
 +#define       SOC_PCIE_HDR_OFF        0x400   /* 256 bytes per function */
 +
 +
 +#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 struct pci_ops bcma_pcie2_ops;
-+
 +static int bcma_pcie2_map_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
 +{
 +      struct pci_sys_data *sys = pdev->sysdata;
 +static int bcma_pcie2_map_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
 +{
 +      struct pci_sys_data *sys = pdev->sysdata;
@@ -133,16 +119,17 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
 +      if (busno == 0) {
 +              if (slot >= 1)
 +                      return 0;
 +      if (busno == 0) {
 +              if (slot >= 1)
 +                      return 0;
-+              bcma_write32(bdev, SOC_PCIE_EXT_CFG_ADDR, where & 0xffc);
-+              return SOC_PCIE_EXT_CFG_DATA;
++              bcma_write32(bdev, BCMA_CORE_PCIE2_CONFIGINDADDR,
++                           where & 0xffc);
++              return BCMA_CORE_PCIE2_CONFIGINDDATA;
 +      }
 +      if (fn > 1)
 +              return 0;
 +      addr_reg = (busno & 0xff) << 20 | (slot << 15) | (fn << 12) |
 +                 (where & 0xffc) | (1 & 0x3);
 +
 +      }
 +      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;
++      bcma_write32(bdev, BCMA_CORE_PCIE2_CFG_ADDR, addr_reg);
++      return BCMA_CORE_PCIE2_CFG_DATA;
 +}
 +
 +static u32 bcma_pcie2_read_config(struct bcma_device *bdev, int busno,
 +}
 +
 +static u32 bcma_pcie2_read_config(struct bcma_device *bdev, int busno,
@@ -160,20 +147,6 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
 +
 +      data_reg = bcma_read32(bdev, base);
 +
 +
 +      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;
 +
 +      if (size == 4)
 +              return data_reg;
 +
@@ -208,42 +181,6 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
 +      bcma_write32(bdev, base, data_reg);
 +}
 +
 +      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)
 +{
 +static int bcma_pcie2_read_config_pci(struct pci_bus *bus, unsigned int devfn,
 +                                 int where, int size, u32 *val)
 +{
@@ -267,31 +204,31 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
 +}
 +
 +/*
 +}
 +
 +/*
++ * Methods for accessing configuration registers
++ */
++static struct pci_ops bcma_pcie2_ops = {
++      .read = bcma_pcie2_read_config_pci,
++      .write = bcma_pcie2_write_config_pci,
++};
++
++/* NS: CLASS field is R/O, and set to wrong 0x200 value */
++static void bcma_pcie2_fixup_class(struct pci_dev *dev)
++{
++      dev->class = PCI_CLASS_BRIDGE_PCI << 8;
++}
++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_BROADCOM, 0x8011, bcma_pcie2_fixup_class);
++
++/*
 + * Check link status, return 0 if link is up in RC mode,
 + * otherwise return non-zero
 + */
 + * 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,
-+                               struct pci_sys_data *sys, u32 allow_gen2)
++static int bcma_pcie2_check_link(struct bcma_device *bdev, bool allow_gen2)
 +{
 +      u32 devfn = 0;
 +      u32 tmp32;
 +{
 +      u32 devfn = 0;
 +      u32 tmp32;
-+      u16 tmp16;
 +      u8 tmp8;
 +      u8 tmp8;
-+      int pos;
-+      bool link = false;
-+      /*
-+       * Setup callback (bcma_pcie2_setup) is called in pcibios_init_hw before
-+       * creating bus root, so we don't have it here yet. On the other hand
-+       * we really want to use pci_bus_find_capability helper to check NLW.
-+       * Let's fake simple pci_bus just to query for capabilities.
-+       */
-+      struct pci_bus bus = {
-+              .number = 0,
-+              .ops = &bcma_pcie2_ops,
-+              .sysdata = sys,
-+      };
 +
 +
-+      tmp32 = bcma_pcie2_read_config32(bdev, 0, devfn, 0xdc);
++      tmp32 = bcma_pcie2_read_config(bdev, 0, devfn, 0xdc, 4);
 +      tmp32 &= ~0xf;
 +      if (allow_gen2)
 +              tmp32 |= 2;
 +      tmp32 &= ~0xf;
 +      if (allow_gen2)
 +              tmp32 |= 2;
@@ -299,28 +236,17 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
 +              /* force PCIE GEN1 */
 +              tmp32 |= 1;
 +      }
 +              /* force PCIE GEN1 */
 +              tmp32 |= 1;
 +      }
-+      bcma_pcie2_write_config32(bdev, 0, devfn, 0xdc, tmp32);
++      bcma_pcie2_write_config(bdev, 0, devfn, 0xdc, 4, tmp32);
 +
 +      /* See if the port is in EP mode, indicated by header type 00 */
 +
 +      /* See if the port is in EP mode, indicated by header type 00 */
-+      tmp8 = bcma_pcie2_read_config8(bdev, 0, devfn, PCI_HEADER_TYPE);
++      tmp8 = bcma_pcie2_read_config(bdev, 0, devfn, PCI_HEADER_TYPE, 1);
 +      if (tmp8 != PCI_HEADER_TYPE_BRIDGE) {
 +              dev_info(&bdev->dev, "Port %d in End-Point mode - ignored\n",
 +                       bdev->core_unit);
 +              return -ENODEV;
 +      }
 +
 +      if (tmp8 != PCI_HEADER_TYPE_BRIDGE) {
 +              dev_info(&bdev->dev, "Port %d in End-Point mode - ignored\n",
 +                       bdev->core_unit);
 +              return -ENODEV;
 +      }
 +
-+      /* NS PAX only changes NLW field when card is present */
-+      pos = pci_bus_find_capability(&bus, devfn, PCI_CAP_ID_EXP);
-+      if (pos) {
-+              u8 nlw;
-+
-+              pci_bus_read_config_word(&bus, devfn, pos + PCI_EXP_LNKSTA,
-+                                       &tmp16);
-+              nlw = (tmp16 & PCI_EXP_LNKSTA_NLW) >> PCI_EXP_LNKSTA_NLW_SHIFT;
-+              link = (tmp16 & PCI_EXP_LNKSTA_DLLLA) || nlw != 0;
-+      }
-+
-+      return link ? 0 : -ENODEV;
++      return 0;
 +}
 +
 +/*
 +}
 +
 +/*
@@ -328,67 +254,52 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
 + */
 +static void bcma_pcie2_hw_init(struct bcma_device *bdev)
 +{
 + */
 +static void bcma_pcie2_hw_init(struct bcma_device *bdev)
 +{
-+      u32 devfn = 0;
 +      u32 tmp32;
 +      u16 tmp16;
 +
 +      /* Change MPS and MRRS to 512 */
 +      u32 tmp32;
 +      u16 tmp16;
 +
 +      /* Change MPS and MRRS to 512 */
-+      tmp16 = bcma_pcie2_read_config16(bdev, 0, devfn, 0x4d4);
++      tmp16 = bcma_pcie2_read_config(bdev, 0, 0, 0x4d4, 2);
 +      tmp16 &= ~7;
 +      tmp16 |= 2;
 +      tmp16 &= ~7;
 +      tmp16 |= 2;
-+      bcma_pcie2_write_config16(bdev, 0, devfn, 0x4d4, tmp16);
++      bcma_pcie2_write_config(bdev, 0, 0, 0x4d4, 2, tmp16);
 +
 +
-+      tmp32 = bcma_pcie2_read_config32(bdev, 0, devfn, 0xb4);
++      tmp32 = bcma_pcie2_read_config(bdev, 0, 0, 0xb4, 4);
 +      tmp32 &= ~((7 << 12) | (7 << 5));
 +      tmp32 |= (2 << 12) | (2 << 5);
 +      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 */
++      bcma_pcie2_write_config(bdev, 0, 0, 0xb4, 4, tmp32);
 +
 +
-+      /* The mode is set by straps, can be overwritten via DMU
-+         register <cru_straps_control> bit 5, "1" means RC
++      /*
++       * Turn-on Root-Complex (RC) mode, from reset default 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 */
 +       */
 +
 +      /* Send a downstream reset */
-+      bcma_write32(bdev, SOC_PCIE_CONTROL, 0x3);
-+      udelay(250);
-+      bcma_write32(bdev, SOC_PCIE_CONTROL, 0x1);
-+      mdelay(250);
++      bcma_write32(bdev, BCMA_CORE_PCIE2_CLK_CONTROL,
++                   PCIE2_CLKC_RST_OE | PCIE2_CLKC_RST);
++      usleep_range(250, 400);
++      bcma_write32(bdev, BCMA_CORE_PCIE2_CLK_CONTROL, PCIE2_CLKC_RST_OE);
++      msleep(250);
 +
 +      /* TBD: take care of PM, check we're on */
 +}
 +
 +/*
 + * Setup the address translation
 +
 +      /* TBD: take care of PM, check we're on */
 +}
 +
 +/*
 + * Setup the address translation
++ *
++ * NOTE: All PCI-to-CPU address mapping are 1:1 for simplicity
 + */
 + */
-+static void bcma_pcie2_map_init(struct bcma_device *bdev)
++static int bcma_pcie2_map_init(struct bcma_device *bdev, u32 addr)
 +{
 +{
-+      unsigned size, i;
-+      u32 addr;
++      /* 64MB alignment */
++      if (!addr || (addr & (SZ_64M - 1)))
++              return -EINVAL;
 +
 +
-+      /*
-+       * NOTE:
-+       * All PCI-to-CPU address mapping are 1:1 for simplicity
-+       */
++      bcma_write32(bdev, BCMA_CORE_PCIE2_OMAP0_LOWER, addr);
++      bcma_write32(bdev, BCMA_CORE_PCIE2_OARR0, addr | 0x01);
 +
 +
-+      /* 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);
++      bcma_write32(bdev, BCMA_CORE_PCIE2_OMAP1_LOWER, addr + SZ_64M);
++      bcma_write32(bdev, BCMA_CORE_PCIE2_OARR1, (addr + SZ_64M) | 0x01);
 +
 +      /*
 +       * Inbound address translation setup
 +
 +      /*
 +       * Inbound address translation setup
@@ -398,107 +309,46 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
 +       * otherwise DMA bouncing mechanism may be required.
 +       * Also consider DMA mask to limit DMA physical address
 +       */
 +       * 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 */
 +      /* 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
++      bcma_write32(bdev, BCMA_CORE_PCIE2_FUNC0_IMAP1, PHYS_OFFSET | 0x1);
++      bcma_write32(bdev, BCMA_CORE_PCIE2_IARR1_LOWER,
++                         PHYS_OFFSET | ((SZ_128M >> 20) & 0xff));
++      return 0;
 +}
 +
 +/*
 + * Setup PCIE Host bridge
 + */
 +}
 +
 +/*
 + * Setup PCIE Host bridge
 + */
-+static void bcma_pcie2_bridge_init(struct bcma_device *bdev)
++static int bcma_pcie2_bridge_init(struct bcma_device *bdev, u32 addr, u32 size)
 +{
 +{
-+      u32 devfn = 0;
-+      u8 tmp8;
-+      u16 tmp16;
++      bcma_pcie2_write_config(bdev, 0, 0, PCI_PRIMARY_BUS, 1, 0);
++      bcma_pcie2_write_config(bdev, 0, 0, PCI_SECONDARY_BUS, 1, 1);
++      bcma_pcie2_write_config(bdev, 0, 0, PCI_SUBORDINATE_BUS, 1, 4);
 +
 +
-+      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);
++      bcma_pcie2_read_config(bdev, 0, 0, PCI_PRIMARY_BUS, 1);
++      bcma_pcie2_read_config(bdev, 0, 0, PCI_SECONDARY_BUS, 1);
++      bcma_pcie2_read_config(bdev, 0, 0, PCI_SUBORDINATE_BUS, 1);
 +
 +      /* MEM_BASE, MEM_LIM require 1MB alignment */
 +
 +      /* 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);
++      if (((addr >> 16) & 0xf) || (((addr + size) >> 16) & 0xf))
++              return -EINVAL;
++
++      bcma_pcie2_write_config(bdev, 0, 0, PCI_MEMORY_BASE, 2, addr >> 16);
++      bcma_pcie2_write_config(bdev, 0, 0, PCI_MEMORY_LIMIT, 2,
++                              (addr + size) >> 16);
 +
 +      /* These registers are not supported on the NS */
 +
 +      /* 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);
++      bcma_pcie2_write_config(bdev, 0, 0, PCI_IO_BASE_UPPER16, 2, 0);
++      bcma_pcie2_write_config(bdev, 0, 0, PCI_IO_LIMIT_UPPER16, 2, 0);
 +
 +      /* Force class to that of a Bridge */
 +
 +      /* 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);
-+}
++      bcma_pcie2_write_config(bdev, 0, 0, PCI_CLASS_DEVICE, 2,
++                              PCI_CLASS_BRIDGE_PCI);
 +
 +
-+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;
++      bcma_pcie2_read_config(bdev, 0, 0, PCI_CLASS_DEVICE, 2);
++      bcma_pcie2_read_config(bdev, 0, 0, PCI_MEMORY_BASE, 2);
++      bcma_pcie2_read_config(bdev, 0, 0, PCI_MEMORY_LIMIT, 2);
++      return 0;
 +}
 +
 +static void bcma_pcie2_3rd_init(struct bcma_bus *bus)
 +}
 +
 +static void bcma_pcie2_3rd_init(struct bcma_bus *bus)
@@ -537,7 +387,7 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
 +      struct resource *res;
 +      struct bcma_device *arm_core;
 +      u32 cru_straps_ctrl;
 +      struct resource *res;
 +      struct bcma_device *arm_core;
 +      u32 cru_straps_ctrl;
-+      int allow_gen2, linkfail;
++      int ret;
 +      int phyaddr;
 +
 +      if (bdev->core_unit == 2) {
 +      int phyaddr;
 +
 +      if (bdev->core_unit == 2) {
@@ -561,8 +411,8 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
 +              return -EINVAL;
 +
 +      res->start = 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->end = bdev->addr_s[0] + SZ_128M -1;
++      res->name = "PCIe dummy IO space";
 +      res->flags = IORESOURCE_MEM;
 +
 +      pci_add_resource(&sys->resources, res);
 +      res->flags = IORESOURCE_MEM;
 +
 +      pci_add_resource(&sys->resources, res);
@@ -572,55 +422,36 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
 +      if (!res)
 +              return -EINVAL;
 +
 +      if (!res)
 +              return -EINVAL;
 +
-+      res->start = bdev->addr_s[0];
-+      res->end = res->start + SZ_128M - 1;
-+      res->name = "PCIe Configuration Space";
++      res->start = 0;
++      res->end = 0;
++      res->name = "PCIe dummy IO space";
 +      res->flags = IORESOURCE_IO;
 +
 +      pci_add_resource(&sys->resources, res);
 +
 +      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, sys, 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");
-+              }
-+      }
++      bcma_pcie2_hw_init(bdev);
++      ret = bcma_pcie2_map_init(bdev, bdev->addr_s[0]);
++      if (ret)
++              return ret;
++
++      /*
++       * Skip inactive ports -
++       * will need to change this for hot-plugging
++       */
++      ret = bcma_pcie2_check_link(bdev, true);
++      if (ret)
++              return ret;
 +
 +
-+      if (linkfail)
-+              return -1;
++      ret = bcma_pcie2_bridge_init(bdev, bdev->addr_s[0], SZ_128M);
++      if (ret)
++              return ret;
 +
 +      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)
 +{
 +static int bcma_pcie2_probe(struct bcma_device *bdev)
 +{
-+      struct hw_pci hw;
-+
-+      dev_info(&bdev->dev, "scanning bus\n");
-+
-+      hw = (struct hw_pci) {
++      struct hw_pci hw = {
 +              .nr_controllers = 1,
 +              .domain         = bdev->core_unit,
 +              .private_data   = (void **)&bdev,
 +              .nr_controllers = 1,
 +              .domain         = bdev->core_unit,
 +              .private_data   = (void **)&bdev,
@@ -629,11 +460,13 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
 +              .ops            = &bcma_pcie2_ops,
 +      };
 +
 +              .ops            = &bcma_pcie2_ops,
 +      };
 +
++      dev_info(&bdev->dev, "initializing PCIe controller\n");
++
 +      /* Announce this port to ARM/PCI common code */
 +      pci_common_init_dev(&bdev->dev, &hw);
 +
 +      /* Setup virtual-wire interrupts */
 +      /* 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);
++      bcma_write32(bdev, BCMA_CORE_PCIE2_SYS_RC_INTX_EN, 0xf);
 +
 +      /* Enable memory and bus master */
 +      bcma_write32(bdev, SOC_PCIE_HDR_OFF + 4, 0x6);
 +
 +      /* Enable memory and bus master */
 +      bcma_write32(bdev, SOC_PCIE_HDR_OFF + 4, 0x6);
@@ -666,5 +499,5 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
 +module_exit(bcma_pcie2_exit);
 +
 +MODULE_AUTHOR("Hauke Mehrtens");
 +module_exit(bcma_pcie2_exit);
 +
 +MODULE_AUTHOR("Hauke Mehrtens");
-+MODULE_DESCRIPTION("PCIe Gen2 driver for BCMA");
++MODULE_DESCRIPTION("BCM5301X PCIe host controller");
 +MODULE_LICENSE("GPLv2");
 +MODULE_LICENSE("GPLv2");