diff mbox

[U-Boot,v3] NS2: Add PCI support

Message ID 20170315173800.14841-1-jdmason@kudzu.us
State Deferred
Delegated to: Tom Rini
Headers show

Commit Message

Jon Mason March 15, 2017, 5:38 p.m. UTC
From: Jon Mason <jonmason@broadcom.com>

Write a new driver to add PCI support to iProc devices.  Currently, this
will only work for NS2 (due to some hard coding done in the driver), but
should be extensible in the future.  Some hacks had to be made due to
time constraints, but are documented in the code.

PCI was verified by tftpbooting over an e1000 PCI NIC.

Signed-off-by: Jon Mason <jon.mason@broadcom.com>
---
 configs/bcm958712k_defconfig     |   2 +
 drivers/pci/Kconfig              |   6 +
 drivers/pci/Makefile             |   1 +
 drivers/pci/pcie_iproc.c         | 285 +++++++++++++++++++++++++++++++++++++++
 include/configs/bcm_northstar2.h |   3 +
 5 files changed, 297 insertions(+)
 create mode 100644 drivers/pci/pcie_iproc.c

Comments

Jon Mason March 17, 2017, 4:11 p.m. UTC | #1
Please disregard this patch.  I meant to send out v3 of the core NS2
support, and not a half-baked PCI driver.

Thanks,
Jon

On Wed, Mar 15, 2017 at 1:38 PM, Jon Mason <jdmason@kudzu.us> wrote:
> From: Jon Mason <jonmason@broadcom.com>
>
> Write a new driver to add PCI support to iProc devices.  Currently, this
> will only work for NS2 (due to some hard coding done in the driver), but
> should be extensible in the future.  Some hacks had to be made due to
> time constraints, but are documented in the code.
>
> PCI was verified by tftpbooting over an e1000 PCI NIC.
>
> Signed-off-by: Jon Mason <jon.mason@broadcom.com>
> ---
>  configs/bcm958712k_defconfig     |   2 +
>  drivers/pci/Kconfig              |   6 +
>  drivers/pci/Makefile             |   1 +
>  drivers/pci/pcie_iproc.c         | 285 +++++++++++++++++++++++++++++++++++++++
>  include/configs/bcm_northstar2.h |   3 +
>  5 files changed, 297 insertions(+)
>  create mode 100644 drivers/pci/pcie_iproc.c
>
> diff --git a/configs/bcm958712k_defconfig b/configs/bcm958712k_defconfig
> index 96e4bce..0c4e566 100644
> --- a/configs/bcm958712k_defconfig
> +++ b/configs/bcm958712k_defconfig
> @@ -6,5 +6,7 @@ CONFIG_BOOTDELAY=5
>  # CONFIG_DISPLAY_CPUINFO is not set
>  CONFIG_SYS_PROMPT="u-boot> "
>  # CONFIG_CMD_IMLS is not set
> +CONFIG_PCI=y
> +CONFIG_PCIE_IPROC=y
>  CONFIG_SYS_NS16550=y
>  CONFIG_OF_LIBFDT=y
> diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
> index 692a398..001ddc1 100644
> --- a/drivers/pci/Kconfig
> +++ b/drivers/pci/Kconfig
> @@ -79,4 +79,10 @@ config PCIE_LAYERSCAPE
>           PCIe controllers. The PCIe may works in RC or EP mode according to
>           RCW[HOST_AGT_PEX] setting.
>
> +config PCIE_IPROC
> +       bool "iProc PCI support"
> +       depends on TARGET_BCMNS2
> +       help
> +         PCIe Support on iProc based SoCs
> +
>  endif
> diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
> index ad44e83..ddfde4c 100644
> --- a/drivers/pci/Makefile
> +++ b/drivers/pci/Makefile
> @@ -22,6 +22,7 @@ obj-$(CONFIG_PCI_INDIRECT_BRIDGE) += pci_indirect.o
>  obj-$(CONFIG_PCI_GT64120) += pci_gt64120.o
>  obj-$(CONFIG_PCI_MSC01) += pci_msc01.o
>  obj-$(CONFIG_PCIE_IMX) += pcie_imx.o
> +obj-$(CONFIG_PCIE_IPROC) += pcie_iproc.o
>  obj-$(CONFIG_FTPCI100) += pci_ftpci100.o
>  obj-$(CONFIG_PCI_MVEBU) += pci_mvebu.o
>  obj-$(CONFIG_SH4_PCI) += pci_sh4.o
> diff --git a/drivers/pci/pcie_iproc.c b/drivers/pci/pcie_iproc.c
> new file mode 100644
> index 0000000..66f5cb5
> --- /dev/null
> +++ b/drivers/pci/pcie_iproc.c
> @@ -0,0 +1,285 @@
> +/*
> + * Broadcom iProc PCI Express Root-Complex driver
> + *
> + * Copyright (C) 2016 Broadcom
> + *
> + * SPDX-License-Identifier:    GPL-2.0
> + */
> +#include <common.h>
> +#include <pci.h>
> +#include <asm/io.h>
> +#include <linux/sizes.h>
> +#include <linux/compat.h>
> +//#include <asm/arch/bcm_mdio.h>
> +//#include <asm/arch-bcm_ns2/socregs.h>
> +
> +#ifdef DEBUG
> +#define pr_debug       printf
> +#else
> +#define pr_debug(...)  do {} while (0)
> +#endif
> +
> +enum iproc_pcie_type {
> +       IPROC_PCI_GEN,
> +       IPROC_PCI_NITRO,
> +};
> +
> +struct iproc_pcie {
> +       void __iomem *reg;
> +
> +       struct pci_controller hose;
> +       enum iproc_pcie_type type;
> +};
> +
> +#define GEN_CFG_IND_ADDR_OFFSET                0x120
> +#define GEN_CFG_IND_DATA_OFFSET                0x124
> +
> +#define NITRO_CFG_IND_ADDR_OFFSET      0x1f0
> +#define NITRO_CFG_IND_DATA_OFFSET      0x1f4
> +
> +#define CLK_CONTROL_OFFSET             0x000
> +#define EP_PERST_SOURCE_SELECT_SHIFT   2
> +#define EP_PERST_SOURCE_SELECT         (1 << EP_PERST_SOURCE_SELECT_SHIFT)
> +#define EP_MODE_SURVIVE_PERST_SHIFT    1
> +#define EP_MODE_SURVIVE_PERST          (1 << EP_MODE_SURVIVE_PERST_SHIFT)
> +#define RC_PCIE_RST_OUTPUT_SHIFT       0
> +#define RC_PCIE_RST_OUTPUT             (1 << RC_PCIE_RST_OUTPUT_SHIFT)
> +
> +#define CFG_ADDR_OFFSET                        0x1F8
> +#define CFG_ADDR_BUS_NUM_SHIFT         20
> +#define CFG_ADDR_BUS_NUM_MASK          0x0FF00000
> +#define CFG_ADDR_DEV_NUM_SHIFT         15
> +#define CFG_ADDR_DEV_NUM_MASK          0x000F8000
> +#define CFG_ADDR_FUNC_NUM_SHIFT                12
> +#define CFG_ADDR_FUNC_NUM_MASK         0x00007000
> +#define CFG_ADDR_REG_NUM_SHIFT         2
> +#define CFG_ADDR_REG_NUM_MASK          0x00000FFC
> +#define CFG_ADDR_CFG_TYPE_SHIFT                0
> +#define CFG_ADDR_CFG_TYPE_MASK         0x00000003
> +
> +#define CFG_DATA_OFFSET                        0x1FC
> +#define CFG_IND_ADDR_MASK              0x00001FFC
> +
> +#define PCIE_LINK_STATUS_OFFSET                0xF0C
> +#define PCIE_PHYLINKUP_SHITF           3
> +#define PCIE_PHYLINKUP                 (1 << PCIE_PHYLINKUP_SHITF)
> +#define PCIE_DL_ACTIVE_SHIFT           2
> +#define PCIE_DL_ACTIVE                 (1 << PCIE_DL_ACTIVE_SHIFT)
> +
> +#define INVALID_ACCESS_OFFSET          0xFFFFFFFF
> +
> +#define PAXC_ROOT                      0x60c00000
> +#define PAXB_0_CLK_CONTROL             0x20020000
> +
> +
> +
> +static u32 iproc_pcie_conf_access(struct pci_controller *hose, pci_dev_t d,
> +                                 int where)
> +{
> +       struct iproc_pcie *pcie = hose->priv_data;
> +       int bus, dev, func;
> +       u32 val;
> +
> +       if (!pcie || !pcie->reg)
> +               return INVALID_ACCESS_OFFSET;
> +
> +       /* root complex access */
> +       if (PCI_DEV(d) == 0) {
> +               if (pcie->type == IPROC_PCI_NITRO) {
> +                       writel(where & CFG_IND_ADDR_MASK,
> +                              pcie->reg + NITRO_CFG_IND_ADDR_OFFSET);
> +                       return NITRO_CFG_IND_DATA_OFFSET;
> +               } else {
> +                       writel(where & CFG_IND_ADDR_MASK,
> +                              pcie->reg + GEN_CFG_IND_ADDR_OFFSET);
> +                       return GEN_CFG_IND_DATA_OFFSET;
> +               }
> +       }
> +
> +       pr_debug("%s:%d - Bus %x, Dev %x, Fun %x, where %x, val %x\n",
> +                __func__, __LINE__, PCI_BUS(d), PCI_DEV(d), PCI_FUNC(d), where,
> +                *val);
> +
> +       /* Note, u-boot starts off the dev at 1, but the func at 0.  Linux
> +        * starts at 0 for dev.  Our code assumes starting at 0, so we need to
> +        * subtact 1.
> +        */
> +       dev = PCI_DEV(d) - 1;
> +
> +       /* FIXME - Nitro only wants to respond if the Bus is 1, but the regular
> +        * PCI only wants to respond if the bus is 0.  Investigation needs to
> +        * be done to determine why
> +        */
> +       if (pcie->type == IPROC_PCI_NITRO)
> +               bus = 1;
> +       else
> +               bus = PCI_BUS(d) - pcie->hose.first_busno;
> +       func = PCI_FUNC(d);
> +
> +       /* FIXME - Quick and dirty hack to fix a problem only found on e1000
> +        * adapters.  For those adapters, a device is found for every "dev"
> +        * queried, even though only one is physically present.  To work
> +        * around that, stop looking after the first device
> +        */
> +       if (dev > 0)
> +               return INVALID_ACCESS_OFFSET;
> +
> +       /* access of EP deivce */
> +       val = (bus << CFG_ADDR_BUS_NUM_SHIFT) |
> +             (dev << CFG_ADDR_DEV_NUM_SHIFT) |
> +             (func << CFG_ADDR_FUNC_NUM_SHIFT) |
> +             (where & CFG_ADDR_REG_NUM_MASK) |
> +             (1 & CFG_ADDR_CFG_TYPE_MASK);
> +       writel(val, pcie->reg + CFG_ADDR_OFFSET);
> +
> +       return CFG_DATA_OFFSET;
> +}
> +
> +static int iproc_pcie_read_config(struct pci_controller *hose, pci_dev_t d,
> +                                 int where, u32 *val)
> +{
> +       struct iproc_pcie *pcie = hose->priv_data;
> +       u32 offset;
> +
> +
> +       offset = iproc_pcie_conf_access(hose, d, where);
> +       if (offset == INVALID_ACCESS_OFFSET)
> +               return -EINVAL;
> +
> +       *val = readl(pcie->reg + offset);
> +
> +
> +       return 0;
> +}
> +
> +static int iproc_pcie_write_config(struct pci_controller *hose, pci_dev_t d,
> +                                  int where, u32 val)
> +{
> +       struct iproc_pcie *pcie = hose->priv_data;
> +       u32 offset;
> +
> +       offset = iproc_pcie_conf_access(hose, d, where);
> +       if (offset == INVALID_ACCESS_OFFSET)
> +               return -EINVAL;
> +
> +       writel(val, pcie->reg + offset);
> +
> +       return 0;
> +}
> +
> +static int iproc_pcie_init_hose(struct iproc_pcie *pcie)
> +{
> +       u32 val32;
> +       u16 val;
> +
> +       /* Check for a device to be present.  Only proceed if one is present.
> +        * If not, it will cause a spurious interrupt (which is found when
> +        * booting Linux after the fact)
> +        */
> +       val32 = readl(pcie->reg + PCIE_LINK_STATUS_OFFSET);
> +       if (pcie->type != IPROC_PCI_NITRO &&
> +           (!(val32 & PCIE_PHYLINKUP) || !(val32 & PCIE_DL_ACTIVE)))
> +               return -ENODEV;
> +
> +       pcie->hose.priv_data = pcie;
> +
> +       /* FIXME - Major hack below.  This should be more limited than saying
> +        * all of memory
> +        */
> +       pci_set_region(&pcie->hose.regions[0], 0, 0, SZ_2G * 2 - 1,
> +                      PCI_REGION_MEM);
> +       pcie->hose.region_count = 1;
> +
> +       pci_set_ops(&pcie->hose,
> +                   pci_hose_read_config_byte_via_dword,
> +                   pci_hose_read_config_word_via_dword,
> +                   iproc_pcie_read_config,
> +                   pci_hose_write_config_byte_via_dword,
> +                   pci_hose_write_config_word_via_dword,
> +                   iproc_pcie_write_config);
> +
> +       /* Before we register, we need to fix up the bridge's incorrect device
> +        * class
> +        */
> +       pci_hose_write_config_word(&pcie->hose, PCI_BDF(0, 0, 0),
> +                                  PCI_CLASS_DEVICE, PCI_CLASS_BRIDGE_PCI);
> +
> +       pci_hose_read_config_word(&pcie->hose, PCI_BDF(0, 0, 0),
> +                                 PCI_CLASS_DEVICE, &val);
> +       pr_debug("%s:%d - Dev Class = %x\n", __func__, __LINE__, val);
> +
> +       pci_register_hose(&pcie->hose);
> +       pciauto_config_init(&pcie->hose);
> +       pcie->hose.last_busno = pci_hose_scan(&pcie->hose);
> +
> +       return 0;
> +}
> +
> +static void iproc_pcie_reset(struct iproc_pcie *pcie)
> +{
> +       if (pcie->type == IPROC_PCI_NITRO) {
> +               writel(0x0000007F, pcie->reg + CLK_CONTROL_OFFSET);
> +       } else {
> +               u32 val;
> +
> +               /*
> +                * Select perst_b signal as reset source, and put the device in
> +                * reset
> +                */
> +               val = readl(pcie->reg + CLK_CONTROL_OFFSET);
> +               val &= ~EP_PERST_SOURCE_SELECT & ~EP_MODE_SURVIVE_PERST &
> +                       ~RC_PCIE_RST_OUTPUT;
> +               writel(val, pcie->reg + CLK_CONTROL_OFFSET);
> +               udelay(250);
> +
> +               /* now bring it out of reset*/
> +               val |= RC_PCIE_RST_OUTPUT;
> +               writel(val, pcie->reg + CLK_CONTROL_OFFSET);
> +               mdelay(250);
> +       }
> +}
> +
> +void pci_init_board(void)
> +{
> +       struct iproc_pcie *pcie;
> +       int i, rc;
> +
> +       /* Do PCI slots first */
> +       for (i = 0; i < 2; i++) {
> +               pcie = kzalloc(sizeof(*pcie), GFP_KERNEL);
> +               if (!pcie)
> +                       return;
> +
> +               pcie->type = IPROC_PCI_GEN;
> +               pcie->hose.first_busno = i;
> +
> +               /* map registers */
> +               pcie->reg = (void *)PAXB_0_CLK_CONTROL + (0x30000000 * i);
> +
> +#if 0
> +               /* turn on the phys. NOTE: Only for NS2. */
> +               bcm_mdio_write(INTERNAL, CLAUS22, i * 7, 0, 0x1F, 0x2100);
> +               bcm_mdio_write(INTERNAL, CLAUS22, i * 7, 0, 0x3, 0x2b18);
> +#endif
> +               iproc_pcie_reset(pcie);
> +
> +               rc = iproc_pcie_init_hose(pcie);
> +               if (rc)
> +                       kfree(pcie);
> +       }
> +
> +       /* Now do Nitro */
> +       pcie = kzalloc(sizeof(*pcie), GFP_KERNEL);
> +       if (!pcie)
> +               return;
> +
> +       pcie->type = IPROC_PCI_NITRO;
> +       pcie->hose.first_busno = i;
> +       pcie->reg = (void *)PAXC_ROOT;
> +
> +       iproc_pcie_reset(pcie);
> +
> +       rc = iproc_pcie_init_hose(pcie);
> +       if (rc)
> +               kfree(pcie);
> +}
> diff --git a/include/configs/bcm_northstar2.h b/include/configs/bcm_northstar2.h
> index ec2ce3f..7a0d26e 100644
> --- a/include/configs/bcm_northstar2.h
> +++ b/include/configs/bcm_northstar2.h
> @@ -52,4 +52,7 @@
>  #define CONFIG_COMMAND_HISTORY
>  #define CONFIG_SYS_LONGHELP
>
> +/* PCI/PCIE */
> +#define CONFIG_CMD_PCI
> +
>  #endif /* __BCM_NORTHSTAR2_H */
> --
> 2.9.3
>
diff mbox

Patch

diff --git a/configs/bcm958712k_defconfig b/configs/bcm958712k_defconfig
index 96e4bce..0c4e566 100644
--- a/configs/bcm958712k_defconfig
+++ b/configs/bcm958712k_defconfig
@@ -6,5 +6,7 @@  CONFIG_BOOTDELAY=5
 # CONFIG_DISPLAY_CPUINFO is not set
 CONFIG_SYS_PROMPT="u-boot> "
 # CONFIG_CMD_IMLS is not set
+CONFIG_PCI=y
+CONFIG_PCIE_IPROC=y
 CONFIG_SYS_NS16550=y
 CONFIG_OF_LIBFDT=y
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 692a398..001ddc1 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -79,4 +79,10 @@  config PCIE_LAYERSCAPE
 	  PCIe controllers. The PCIe may works in RC or EP mode according to
 	  RCW[HOST_AGT_PEX] setting.
 
+config PCIE_IPROC
+	bool "iProc PCI support"
+	depends on TARGET_BCMNS2
+	help
+	  PCIe Support on iProc based SoCs
+
 endif
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index ad44e83..ddfde4c 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -22,6 +22,7 @@  obj-$(CONFIG_PCI_INDIRECT_BRIDGE) += pci_indirect.o
 obj-$(CONFIG_PCI_GT64120) += pci_gt64120.o
 obj-$(CONFIG_PCI_MSC01) += pci_msc01.o
 obj-$(CONFIG_PCIE_IMX) += pcie_imx.o
+obj-$(CONFIG_PCIE_IPROC) += pcie_iproc.o
 obj-$(CONFIG_FTPCI100) += pci_ftpci100.o
 obj-$(CONFIG_PCI_MVEBU) += pci_mvebu.o
 obj-$(CONFIG_SH4_PCI) += pci_sh4.o
diff --git a/drivers/pci/pcie_iproc.c b/drivers/pci/pcie_iproc.c
new file mode 100644
index 0000000..66f5cb5
--- /dev/null
+++ b/drivers/pci/pcie_iproc.c
@@ -0,0 +1,285 @@ 
+/*
+ * Broadcom iProc PCI Express Root-Complex driver
+ *
+ * Copyright (C) 2016 Broadcom
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+#include <common.h>
+#include <pci.h>
+#include <asm/io.h>
+#include <linux/sizes.h>
+#include <linux/compat.h>
+//#include <asm/arch/bcm_mdio.h>
+//#include <asm/arch-bcm_ns2/socregs.h>
+
+#ifdef DEBUG
+#define pr_debug	printf
+#else
+#define pr_debug(...)	do {} while (0)
+#endif
+
+enum iproc_pcie_type {
+	IPROC_PCI_GEN,
+	IPROC_PCI_NITRO,
+};
+
+struct iproc_pcie {
+	void __iomem *reg;
+
+	struct pci_controller hose;
+	enum iproc_pcie_type type;
+};
+
+#define GEN_CFG_IND_ADDR_OFFSET		0x120
+#define GEN_CFG_IND_DATA_OFFSET		0x124
+
+#define NITRO_CFG_IND_ADDR_OFFSET	0x1f0
+#define NITRO_CFG_IND_DATA_OFFSET	0x1f4
+
+#define CLK_CONTROL_OFFSET		0x000
+#define EP_PERST_SOURCE_SELECT_SHIFT	2
+#define EP_PERST_SOURCE_SELECT		(1 << EP_PERST_SOURCE_SELECT_SHIFT)
+#define EP_MODE_SURVIVE_PERST_SHIFT	1
+#define EP_MODE_SURVIVE_PERST		(1 << EP_MODE_SURVIVE_PERST_SHIFT)
+#define RC_PCIE_RST_OUTPUT_SHIFT	0
+#define RC_PCIE_RST_OUTPUT		(1 << RC_PCIE_RST_OUTPUT_SHIFT)
+
+#define CFG_ADDR_OFFSET			0x1F8
+#define CFG_ADDR_BUS_NUM_SHIFT		20
+#define CFG_ADDR_BUS_NUM_MASK		0x0FF00000
+#define CFG_ADDR_DEV_NUM_SHIFT		15
+#define CFG_ADDR_DEV_NUM_MASK		0x000F8000
+#define CFG_ADDR_FUNC_NUM_SHIFT		12
+#define CFG_ADDR_FUNC_NUM_MASK		0x00007000
+#define CFG_ADDR_REG_NUM_SHIFT		2
+#define CFG_ADDR_REG_NUM_MASK		0x00000FFC
+#define CFG_ADDR_CFG_TYPE_SHIFT		0
+#define CFG_ADDR_CFG_TYPE_MASK		0x00000003
+
+#define CFG_DATA_OFFSET			0x1FC
+#define CFG_IND_ADDR_MASK		0x00001FFC
+
+#define PCIE_LINK_STATUS_OFFSET		0xF0C
+#define PCIE_PHYLINKUP_SHITF		3
+#define PCIE_PHYLINKUP			(1 << PCIE_PHYLINKUP_SHITF)
+#define PCIE_DL_ACTIVE_SHIFT		2
+#define PCIE_DL_ACTIVE			(1 << PCIE_DL_ACTIVE_SHIFT)
+
+#define INVALID_ACCESS_OFFSET		0xFFFFFFFF
+
+#define PAXC_ROOT			0x60c00000
+#define PAXB_0_CLK_CONTROL		0x20020000
+
+
+
+static u32 iproc_pcie_conf_access(struct pci_controller *hose, pci_dev_t d,
+				  int where)
+{
+	struct iproc_pcie *pcie = hose->priv_data;
+	int bus, dev, func;
+	u32 val;
+
+	if (!pcie || !pcie->reg)
+		return INVALID_ACCESS_OFFSET;
+
+	/* root complex access */
+	if (PCI_DEV(d) == 0) {
+		if (pcie->type == IPROC_PCI_NITRO) {
+			writel(where & CFG_IND_ADDR_MASK,
+			       pcie->reg + NITRO_CFG_IND_ADDR_OFFSET);
+			return NITRO_CFG_IND_DATA_OFFSET;
+		} else {
+			writel(where & CFG_IND_ADDR_MASK,
+			       pcie->reg + GEN_CFG_IND_ADDR_OFFSET);
+			return GEN_CFG_IND_DATA_OFFSET;
+		}
+	}
+
+	pr_debug("%s:%d - Bus %x, Dev %x, Fun %x, where %x, val %x\n",
+		 __func__, __LINE__, PCI_BUS(d), PCI_DEV(d), PCI_FUNC(d), where,
+		 *val);
+
+	/* Note, u-boot starts off the dev at 1, but the func at 0.  Linux
+	 * starts at 0 for dev.  Our code assumes starting at 0, so we need to
+	 * subtact 1.
+	 */
+	dev = PCI_DEV(d) - 1;
+
+	/* FIXME - Nitro only wants to respond if the Bus is 1, but the regular
+	 * PCI only wants to respond if the bus is 0.  Investigation needs to
+	 * be done to determine why
+	 */
+	if (pcie->type == IPROC_PCI_NITRO)
+		bus = 1;
+	else
+		bus = PCI_BUS(d) - pcie->hose.first_busno;
+	func = PCI_FUNC(d);
+
+	/* FIXME - Quick and dirty hack to fix a problem only found on e1000
+	 * adapters.  For those adapters, a device is found for every "dev"
+	 * queried, even though only one is physically present.  To work
+	 * around that, stop looking after the first device
+	 */
+	if (dev > 0)
+		return INVALID_ACCESS_OFFSET;
+
+	/* access of EP deivce */
+	val = (bus << CFG_ADDR_BUS_NUM_SHIFT) |
+	      (dev << CFG_ADDR_DEV_NUM_SHIFT) |
+	      (func << CFG_ADDR_FUNC_NUM_SHIFT) |
+	      (where & CFG_ADDR_REG_NUM_MASK) |
+	      (1 & CFG_ADDR_CFG_TYPE_MASK);
+	writel(val, pcie->reg + CFG_ADDR_OFFSET);
+
+	return CFG_DATA_OFFSET;
+}
+
+static int iproc_pcie_read_config(struct pci_controller *hose, pci_dev_t d,
+				  int where, u32 *val)
+{
+	struct iproc_pcie *pcie = hose->priv_data;
+	u32 offset;
+
+
+	offset = iproc_pcie_conf_access(hose, d, where);
+	if (offset == INVALID_ACCESS_OFFSET)
+		return -EINVAL;
+
+	*val = readl(pcie->reg + offset);
+
+
+	return 0;
+}
+
+static int iproc_pcie_write_config(struct pci_controller *hose, pci_dev_t d,
+				   int where, u32 val)
+{
+	struct iproc_pcie *pcie = hose->priv_data;
+	u32 offset;
+
+	offset = iproc_pcie_conf_access(hose, d, where);
+	if (offset == INVALID_ACCESS_OFFSET)
+		return -EINVAL;
+
+	writel(val, pcie->reg + offset);
+
+	return 0;
+}
+
+static int iproc_pcie_init_hose(struct iproc_pcie *pcie)
+{
+	u32 val32;
+	u16 val;
+
+	/* Check for a device to be present.  Only proceed if one is present.
+	 * If not, it will cause a spurious interrupt (which is found when
+	 * booting Linux after the fact)
+	 */
+	val32 = readl(pcie->reg + PCIE_LINK_STATUS_OFFSET);
+	if (pcie->type != IPROC_PCI_NITRO &&
+	    (!(val32 & PCIE_PHYLINKUP) || !(val32 & PCIE_DL_ACTIVE)))
+		return -ENODEV;
+
+	pcie->hose.priv_data = pcie;
+
+	/* FIXME - Major hack below.  This should be more limited than saying
+	 * all of memory
+	 */
+	pci_set_region(&pcie->hose.regions[0], 0, 0, SZ_2G * 2 - 1,
+		       PCI_REGION_MEM);
+	pcie->hose.region_count = 1;
+
+	pci_set_ops(&pcie->hose,
+		    pci_hose_read_config_byte_via_dword,
+		    pci_hose_read_config_word_via_dword,
+		    iproc_pcie_read_config,
+		    pci_hose_write_config_byte_via_dword,
+		    pci_hose_write_config_word_via_dword,
+		    iproc_pcie_write_config);
+
+	/* Before we register, we need to fix up the bridge's incorrect device
+	 * class
+	 */
+	pci_hose_write_config_word(&pcie->hose, PCI_BDF(0, 0, 0),
+				   PCI_CLASS_DEVICE, PCI_CLASS_BRIDGE_PCI);
+
+	pci_hose_read_config_word(&pcie->hose, PCI_BDF(0, 0, 0),
+				  PCI_CLASS_DEVICE, &val);
+	pr_debug("%s:%d - Dev Class = %x\n", __func__, __LINE__, val);
+
+	pci_register_hose(&pcie->hose);
+	pciauto_config_init(&pcie->hose);
+	pcie->hose.last_busno = pci_hose_scan(&pcie->hose);
+
+	return 0;
+}
+
+static void iproc_pcie_reset(struct iproc_pcie *pcie)
+{
+	if (pcie->type == IPROC_PCI_NITRO) {
+		writel(0x0000007F, pcie->reg + CLK_CONTROL_OFFSET);
+	} else {
+		u32 val;
+
+		/*
+		 * Select perst_b signal as reset source, and put the device in
+		 * reset
+		 */
+		val = readl(pcie->reg + CLK_CONTROL_OFFSET);
+		val &= ~EP_PERST_SOURCE_SELECT & ~EP_MODE_SURVIVE_PERST &
+			~RC_PCIE_RST_OUTPUT;
+		writel(val, pcie->reg + CLK_CONTROL_OFFSET);
+		udelay(250);
+
+		/* now bring it out of reset*/
+		val |= RC_PCIE_RST_OUTPUT;
+		writel(val, pcie->reg + CLK_CONTROL_OFFSET);
+		mdelay(250);
+	}
+}
+
+void pci_init_board(void)
+{
+	struct iproc_pcie *pcie;
+	int i, rc;
+
+	/* Do PCI slots first */
+	for (i = 0; i < 2; i++) {
+		pcie = kzalloc(sizeof(*pcie), GFP_KERNEL);
+		if (!pcie)
+			return;
+
+		pcie->type = IPROC_PCI_GEN;
+		pcie->hose.first_busno = i;
+
+		/* map registers */
+		pcie->reg = (void *)PAXB_0_CLK_CONTROL + (0x30000000 * i);
+
+#if 0
+		/* turn on the phys. NOTE: Only for NS2. */
+		bcm_mdio_write(INTERNAL, CLAUS22, i * 7, 0, 0x1F, 0x2100);
+		bcm_mdio_write(INTERNAL, CLAUS22, i * 7, 0, 0x3, 0x2b18);
+#endif
+		iproc_pcie_reset(pcie);
+
+		rc = iproc_pcie_init_hose(pcie);
+		if (rc)
+			kfree(pcie);
+	}
+
+	/* Now do Nitro */
+	pcie = kzalloc(sizeof(*pcie), GFP_KERNEL);
+	if (!pcie)
+		return;
+
+	pcie->type = IPROC_PCI_NITRO;
+	pcie->hose.first_busno = i;
+	pcie->reg = (void *)PAXC_ROOT;
+
+	iproc_pcie_reset(pcie);
+
+	rc = iproc_pcie_init_hose(pcie);
+	if (rc)
+		kfree(pcie);
+}
diff --git a/include/configs/bcm_northstar2.h b/include/configs/bcm_northstar2.h
index ec2ce3f..7a0d26e 100644
--- a/include/configs/bcm_northstar2.h
+++ b/include/configs/bcm_northstar2.h
@@ -52,4 +52,7 @@ 
 #define CONFIG_COMMAND_HISTORY
 #define CONFIG_SYS_LONGHELP
 
+/* PCI/PCIE */
+#define CONFIG_CMD_PCI
+
 #endif /* __BCM_NORTHSTAR2_H */