diff options
Diffstat (limited to 'arch/mips/pci/pci-bcm63xx.c')
| -rw-r--r-- | arch/mips/pci/pci-bcm63xx.c | 133 | 
1 files changed, 127 insertions, 6 deletions
diff --git a/arch/mips/pci/pci-bcm63xx.c b/arch/mips/pci/pci-bcm63xx.c index 39eb7c417e2..8a48139d219 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,17 +115,99 @@ static void bcm63xx_int_cfg_writel(u32 val, u32 reg)  void __iomem *pci_iospace_start; -static int __init bcm63xx_pci_init(void) +static void __init bcm63xx_reset_pcie(void)  { -	unsigned int mem_size;  	u32 val; -	if (!BCMCPU_IS_6348() && !BCMCPU_IS_6358() && !BCMCPU_IS_6368()) -		return -ENODEV; +	/* enable clock */ +	val = bcm_perf_readl(PERF_CKCTL_REG); +	val |= CKCTL_6328_PCIE_EN; +	bcm_perf_writel(val, PERF_CKCTL_REG); -	if (!bcm63xx_pci_enabled) -		return -ENODEV; +	/* 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; +	u32 val;  	/*  	 * configuration  access are  done through  IO space,  remap 4  	 * first bytes to access it from CPU. @@ -221,4 +324,22 @@ static int __init bcm63xx_pci_init(void)  	return 0;  } + +static int __init bcm63xx_pci_init(void) +{ +	if (!bcm63xx_pci_enabled) +		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: +		return bcm63xx_register_pci(); +	default: +		return -ENODEV; +	} +} +  arch_initcall(bcm63xx_pci_init);  |