diff options
author | Jonas Gorski <jonas.gorski@gmail.com> | 2012-07-24 16:33:13 +0200 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2012-07-24 16:33:13 +0200 |
commit | 19c860d932de520017c9b2d88cd9dff90b71ba36 (patch) | |
tree | 2feb7f7cb1c91f5bdd6ce761ff4e421814237274 /arch/mips/pci/pci-bcm63xx.c | |
parent | 76f42fe8117c85fced0135b23835890cfa41a47b (diff) |
MIPS: BCM63XX: Add PCIe Support for BCM6328
Add support for the PCIe port found on BCM6328.
Signed-off-by: Jonas Gorski <jonas.gorski@gmail.com>
Cc: linux-mips@linux-mips.org
Cc: Maxime Bizon <mbizon@freebox.fr>
Cc: Florian Fainelli <florian@openwrt.org>
Cc: Kevin Cernekee <cernekee@gmail.com>
Patchwork: https://patchwork.linux-mips.org/patch/3956/
Reviewed-by: Florian Fainelli <florian@openwrt.org>
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/pci/pci-bcm63xx.c')
-rw-r--r-- | arch/mips/pci/pci-bcm63xx.c | 112 |
1 files changed, 112 insertions, 0 deletions
diff --git a/arch/mips/pci/pci-bcm63xx.c b/arch/mips/pci/pci-bcm63xx.c index a2b6d55a2492..8a48139d219c 100644 --- a/arch/mips/pci/pci-bcm63xx.c +++ b/arch/mips/pci/pci-bcm63xx.c @@ -10,6 +10,7 @@ #include <linux/pci.h> #include <linux/kernel.h> #include <linux/init.h> +#include <linux/delay.h> #include <asm/bootinfo.h> #include "pci-bcm63xx.h" @@ -71,6 +72,26 @@ struct pci_controller bcm63xx_cb_controller = { }; #endif +static struct resource bcm_pcie_mem_resource = { + .name = "bcm63xx PCIe memory space", + .start = BCM_PCIE_MEM_BASE_PA, + .end = BCM_PCIE_MEM_END_PA, + .flags = IORESOURCE_MEM, +}; + +static struct resource bcm_pcie_io_resource = { + .name = "bcm63xx PCIe IO space", + .start = 0, + .end = 0, + .flags = 0, +}; + +struct pci_controller bcm63xx_pcie_controller = { + .pci_ops = &bcm63xx_pcie_ops, + .io_resource = &bcm_pcie_io_resource, + .mem_resource = &bcm_pcie_mem_resource, +}; + static u32 bcm63xx_int_cfg_readl(u32 reg) { u32 tmp; @@ -94,6 +115,95 @@ static void bcm63xx_int_cfg_writel(u32 val, u32 reg) void __iomem *pci_iospace_start; +static void __init bcm63xx_reset_pcie(void) +{ + u32 val; + + /* enable clock */ + val = bcm_perf_readl(PERF_CKCTL_REG); + val |= CKCTL_6328_PCIE_EN; + bcm_perf_writel(val, PERF_CKCTL_REG); + + /* enable SERDES */ + val = bcm_misc_readl(MISC_SERDES_CTRL_REG); + val |= SERDES_PCIE_EN | SERDES_PCIE_EXD_EN; + bcm_misc_writel(val, MISC_SERDES_CTRL_REG); + + /* reset the PCIe core */ + val = bcm_perf_readl(PERF_SOFTRESET_6328_REG); + + val &= ~SOFTRESET_6328_PCIE_MASK; + val &= ~SOFTRESET_6328_PCIE_CORE_MASK; + val &= ~SOFTRESET_6328_PCIE_HARD_MASK; + val &= ~SOFTRESET_6328_PCIE_EXT_MASK; + bcm_perf_writel(val, PERF_SOFTRESET_6328_REG); + mdelay(10); + + val |= SOFTRESET_6328_PCIE_MASK; + val |= SOFTRESET_6328_PCIE_CORE_MASK; + val |= SOFTRESET_6328_PCIE_HARD_MASK; + bcm_perf_writel(val, PERF_SOFTRESET_6328_REG); + mdelay(10); + + val |= SOFTRESET_6328_PCIE_EXT_MASK; + bcm_perf_writel(val, PERF_SOFTRESET_6328_REG); + mdelay(200); +} + +static int __init bcm63xx_register_pcie(void) +{ + u32 val; + + bcm63xx_reset_pcie(); + + /* configure the PCIe bridge */ + val = bcm_pcie_readl(PCIE_BRIDGE_OPT1_REG); + val |= OPT1_RD_BE_OPT_EN; + val |= OPT1_RD_REPLY_BE_FIX_EN; + val |= OPT1_PCIE_BRIDGE_HOLE_DET_EN; + val |= OPT1_L1_INT_STATUS_MASK_POL; + bcm_pcie_writel(val, PCIE_BRIDGE_OPT1_REG); + + /* setup the interrupts */ + val = bcm_pcie_readl(PCIE_BRIDGE_RC_INT_MASK_REG); + val |= PCIE_RC_INT_A | PCIE_RC_INT_B | PCIE_RC_INT_C | PCIE_RC_INT_D; + bcm_pcie_writel(val, PCIE_BRIDGE_RC_INT_MASK_REG); + + val = bcm_pcie_readl(PCIE_BRIDGE_OPT2_REG); + /* enable credit checking and error checking */ + val |= OPT2_TX_CREDIT_CHK_EN; + val |= OPT2_UBUS_UR_DECODE_DIS; + + /* set device bus/func for the pcie device */ + val |= (PCIE_BUS_DEVICE << OPT2_CFG_TYPE1_BUS_NO_SHIFT); + val |= OPT2_CFG_TYPE1_BD_SEL; + bcm_pcie_writel(val, PCIE_BRIDGE_OPT2_REG); + + /* setup class code as bridge */ + val = bcm_pcie_readl(PCIE_IDVAL3_REG); + val &= ~IDVAL3_CLASS_CODE_MASK; + val |= (PCI_CLASS_BRIDGE_PCI << IDVAL3_SUBCLASS_SHIFT); + bcm_pcie_writel(val, PCIE_IDVAL3_REG); + + /* disable bar1 size */ + val = bcm_pcie_readl(PCIE_CONFIG2_REG); + val &= ~CONFIG2_BAR1_SIZE_MASK; + bcm_pcie_writel(val, PCIE_CONFIG2_REG); + + /* set bar0 to little endian */ + val = (BCM_PCIE_MEM_BASE_PA >> 20) << BASEMASK_BASE_SHIFT; + val |= (BCM_PCIE_MEM_BASE_PA >> 20) << BASEMASK_MASK_SHIFT; + val |= BASEMASK_REMAP_EN; + bcm_pcie_writel(val, PCIE_BRIDGE_BAR0_BASEMASK_REG); + + val = (BCM_PCIE_MEM_BASE_PA >> 20) << REBASE_ADDR_BASE_SHIFT; + bcm_pcie_writel(val, PCIE_BRIDGE_BAR0_REBASE_ADDR_REG); + + register_pci_controller(&bcm63xx_pcie_controller); + + return 0; +} + static int __init bcm63xx_register_pci(void) { unsigned int mem_size; @@ -221,6 +331,8 @@ static int __init bcm63xx_pci_init(void) return -ENODEV; switch (bcm63xx_get_cpu_id()) { + case BCM6328_CPU_ID: + return bcm63xx_register_pcie(); case BCM6348_CPU_ID: case BCM6358_CPU_ID: case BCM6368_CPU_ID: |