Message ID | 20170315173800.14841-1-jdmason@kudzu.us |
---|---|
State | New |
Headers | show |
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 --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 */