18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
38c2ecf20Sopenharmony_ci * License.  See the file "COPYING" in the main directory of this archive
48c2ecf20Sopenharmony_ci * for more details.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/types.h>
108c2ecf20Sopenharmony_ci#include <linux/pci.h>
118c2ecf20Sopenharmony_ci#include <linux/kernel.h>
128c2ecf20Sopenharmony_ci#include <linux/init.h>
138c2ecf20Sopenharmony_ci#include <linux/delay.h>
148c2ecf20Sopenharmony_ci#include <linux/clk.h>
158c2ecf20Sopenharmony_ci#include <asm/bootinfo.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include <bcm63xx_reset.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include "pci-bcm63xx.h"
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci/*
228c2ecf20Sopenharmony_ci * Allow PCI to be disabled at runtime depending on board nvram
238c2ecf20Sopenharmony_ci * configuration
248c2ecf20Sopenharmony_ci */
258c2ecf20Sopenharmony_ciint bcm63xx_pci_enabled;
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_cistatic struct resource bcm_pci_mem_resource = {
288c2ecf20Sopenharmony_ci	.name	= "bcm63xx PCI memory space",
298c2ecf20Sopenharmony_ci	.start	= BCM_PCI_MEM_BASE_PA,
308c2ecf20Sopenharmony_ci	.end	= BCM_PCI_MEM_END_PA,
318c2ecf20Sopenharmony_ci	.flags	= IORESOURCE_MEM
328c2ecf20Sopenharmony_ci};
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistatic struct resource bcm_pci_io_resource = {
358c2ecf20Sopenharmony_ci	.name	= "bcm63xx PCI IO space",
368c2ecf20Sopenharmony_ci	.start	= BCM_PCI_IO_BASE_PA,
378c2ecf20Sopenharmony_ci#ifdef CONFIG_CARDBUS
388c2ecf20Sopenharmony_ci	.end	= BCM_PCI_IO_HALF_PA,
398c2ecf20Sopenharmony_ci#else
408c2ecf20Sopenharmony_ci	.end	= BCM_PCI_IO_END_PA,
418c2ecf20Sopenharmony_ci#endif
428c2ecf20Sopenharmony_ci	.flags	= IORESOURCE_IO
438c2ecf20Sopenharmony_ci};
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_cistruct pci_controller bcm63xx_controller = {
468c2ecf20Sopenharmony_ci	.pci_ops	= &bcm63xx_pci_ops,
478c2ecf20Sopenharmony_ci	.io_resource	= &bcm_pci_io_resource,
488c2ecf20Sopenharmony_ci	.mem_resource	= &bcm_pci_mem_resource,
498c2ecf20Sopenharmony_ci};
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci/*
528c2ecf20Sopenharmony_ci * We handle cardbus  via a fake Cardbus bridge,  memory and io spaces
538c2ecf20Sopenharmony_ci * have to be  clearly separated from PCI one  since we have different
548c2ecf20Sopenharmony_ci * memory decoder.
558c2ecf20Sopenharmony_ci */
568c2ecf20Sopenharmony_ci#ifdef CONFIG_CARDBUS
578c2ecf20Sopenharmony_cistatic struct resource bcm_cb_mem_resource = {
588c2ecf20Sopenharmony_ci	.name	= "bcm63xx Cardbus memory space",
598c2ecf20Sopenharmony_ci	.start	= BCM_CB_MEM_BASE_PA,
608c2ecf20Sopenharmony_ci	.end	= BCM_CB_MEM_END_PA,
618c2ecf20Sopenharmony_ci	.flags	= IORESOURCE_MEM
628c2ecf20Sopenharmony_ci};
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_cistatic struct resource bcm_cb_io_resource = {
658c2ecf20Sopenharmony_ci	.name	= "bcm63xx Cardbus IO space",
668c2ecf20Sopenharmony_ci	.start	= BCM_PCI_IO_HALF_PA + 1,
678c2ecf20Sopenharmony_ci	.end	= BCM_PCI_IO_END_PA,
688c2ecf20Sopenharmony_ci	.flags	= IORESOURCE_IO
698c2ecf20Sopenharmony_ci};
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_cistruct pci_controller bcm63xx_cb_controller = {
728c2ecf20Sopenharmony_ci	.pci_ops	= &bcm63xx_cb_ops,
738c2ecf20Sopenharmony_ci	.io_resource	= &bcm_cb_io_resource,
748c2ecf20Sopenharmony_ci	.mem_resource	= &bcm_cb_mem_resource,
758c2ecf20Sopenharmony_ci};
768c2ecf20Sopenharmony_ci#endif
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_cistatic struct resource bcm_pcie_mem_resource = {
798c2ecf20Sopenharmony_ci	.name	= "bcm63xx PCIe memory space",
808c2ecf20Sopenharmony_ci	.start	= BCM_PCIE_MEM_BASE_PA,
818c2ecf20Sopenharmony_ci	.end	= BCM_PCIE_MEM_END_PA,
828c2ecf20Sopenharmony_ci	.flags	= IORESOURCE_MEM,
838c2ecf20Sopenharmony_ci};
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_cistatic struct resource bcm_pcie_io_resource = {
868c2ecf20Sopenharmony_ci	.name	= "bcm63xx PCIe IO space",
878c2ecf20Sopenharmony_ci	.start	= 0,
888c2ecf20Sopenharmony_ci	.end	= 0,
898c2ecf20Sopenharmony_ci	.flags	= 0,
908c2ecf20Sopenharmony_ci};
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_cistruct pci_controller bcm63xx_pcie_controller = {
938c2ecf20Sopenharmony_ci	.pci_ops	= &bcm63xx_pcie_ops,
948c2ecf20Sopenharmony_ci	.io_resource	= &bcm_pcie_io_resource,
958c2ecf20Sopenharmony_ci	.mem_resource	= &bcm_pcie_mem_resource,
968c2ecf20Sopenharmony_ci};
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_cistatic u32 bcm63xx_int_cfg_readl(u32 reg)
998c2ecf20Sopenharmony_ci{
1008c2ecf20Sopenharmony_ci	u32 tmp;
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	tmp = reg & MPI_PCICFGCTL_CFGADDR_MASK;
1038c2ecf20Sopenharmony_ci	tmp |= MPI_PCICFGCTL_WRITEEN_MASK;
1048c2ecf20Sopenharmony_ci	bcm_mpi_writel(tmp, MPI_PCICFGCTL_REG);
1058c2ecf20Sopenharmony_ci	iob();
1068c2ecf20Sopenharmony_ci	return bcm_mpi_readl(MPI_PCICFGDATA_REG);
1078c2ecf20Sopenharmony_ci}
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_cistatic void bcm63xx_int_cfg_writel(u32 val, u32 reg)
1108c2ecf20Sopenharmony_ci{
1118c2ecf20Sopenharmony_ci	u32 tmp;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	tmp = reg & MPI_PCICFGCTL_CFGADDR_MASK;
1148c2ecf20Sopenharmony_ci	tmp |=	MPI_PCICFGCTL_WRITEEN_MASK;
1158c2ecf20Sopenharmony_ci	bcm_mpi_writel(tmp, MPI_PCICFGCTL_REG);
1168c2ecf20Sopenharmony_ci	bcm_mpi_writel(val, MPI_PCICFGDATA_REG);
1178c2ecf20Sopenharmony_ci}
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_civoid __iomem *pci_iospace_start;
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_cistatic void __init bcm63xx_reset_pcie(void)
1228c2ecf20Sopenharmony_ci{
1238c2ecf20Sopenharmony_ci	u32 val;
1248c2ecf20Sopenharmony_ci	u32 reg;
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	/* enable SERDES */
1278c2ecf20Sopenharmony_ci	if (BCMCPU_IS_6328())
1288c2ecf20Sopenharmony_ci		reg = MISC_SERDES_CTRL_6328_REG;
1298c2ecf20Sopenharmony_ci	else
1308c2ecf20Sopenharmony_ci		reg = MISC_SERDES_CTRL_6362_REG;
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	val = bcm_misc_readl(reg);
1338c2ecf20Sopenharmony_ci	val |= SERDES_PCIE_EN | SERDES_PCIE_EXD_EN;
1348c2ecf20Sopenharmony_ci	bcm_misc_writel(val, reg);
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	/* reset the PCIe core */
1378c2ecf20Sopenharmony_ci	bcm63xx_core_set_reset(BCM63XX_RESET_PCIE, 1);
1388c2ecf20Sopenharmony_ci	bcm63xx_core_set_reset(BCM63XX_RESET_PCIE_EXT, 1);
1398c2ecf20Sopenharmony_ci	mdelay(10);
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	bcm63xx_core_set_reset(BCM63XX_RESET_PCIE, 0);
1428c2ecf20Sopenharmony_ci	mdelay(10);
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	bcm63xx_core_set_reset(BCM63XX_RESET_PCIE_EXT, 0);
1458c2ecf20Sopenharmony_ci	mdelay(200);
1468c2ecf20Sopenharmony_ci}
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_cistatic struct clk *pcie_clk;
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_cistatic int __init bcm63xx_register_pcie(void)
1518c2ecf20Sopenharmony_ci{
1528c2ecf20Sopenharmony_ci	u32 val;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	/* enable clock */
1558c2ecf20Sopenharmony_ci	pcie_clk = clk_get(NULL, "pcie");
1568c2ecf20Sopenharmony_ci	if (IS_ERR_OR_NULL(pcie_clk))
1578c2ecf20Sopenharmony_ci		return -ENODEV;
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	clk_prepare_enable(pcie_clk);
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	bcm63xx_reset_pcie();
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	/* configure the PCIe bridge */
1648c2ecf20Sopenharmony_ci	val = bcm_pcie_readl(PCIE_BRIDGE_OPT1_REG);
1658c2ecf20Sopenharmony_ci	val |= OPT1_RD_BE_OPT_EN;
1668c2ecf20Sopenharmony_ci	val |= OPT1_RD_REPLY_BE_FIX_EN;
1678c2ecf20Sopenharmony_ci	val |= OPT1_PCIE_BRIDGE_HOLE_DET_EN;
1688c2ecf20Sopenharmony_ci	val |= OPT1_L1_INT_STATUS_MASK_POL;
1698c2ecf20Sopenharmony_ci	bcm_pcie_writel(val, PCIE_BRIDGE_OPT1_REG);
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	/* setup the interrupts */
1728c2ecf20Sopenharmony_ci	val = bcm_pcie_readl(PCIE_BRIDGE_RC_INT_MASK_REG);
1738c2ecf20Sopenharmony_ci	val |= PCIE_RC_INT_A | PCIE_RC_INT_B | PCIE_RC_INT_C | PCIE_RC_INT_D;
1748c2ecf20Sopenharmony_ci	bcm_pcie_writel(val, PCIE_BRIDGE_RC_INT_MASK_REG);
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	val = bcm_pcie_readl(PCIE_BRIDGE_OPT2_REG);
1778c2ecf20Sopenharmony_ci	/* enable credit checking and error checking */
1788c2ecf20Sopenharmony_ci	val |= OPT2_TX_CREDIT_CHK_EN;
1798c2ecf20Sopenharmony_ci	val |= OPT2_UBUS_UR_DECODE_DIS;
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	/* set device bus/func for the pcie device */
1828c2ecf20Sopenharmony_ci	val |= (PCIE_BUS_DEVICE << OPT2_CFG_TYPE1_BUS_NO_SHIFT);
1838c2ecf20Sopenharmony_ci	val |= OPT2_CFG_TYPE1_BD_SEL;
1848c2ecf20Sopenharmony_ci	bcm_pcie_writel(val, PCIE_BRIDGE_OPT2_REG);
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	/* setup class code as bridge */
1878c2ecf20Sopenharmony_ci	val = bcm_pcie_readl(PCIE_IDVAL3_REG);
1888c2ecf20Sopenharmony_ci	val &= ~IDVAL3_CLASS_CODE_MASK;
1898c2ecf20Sopenharmony_ci	val |= (PCI_CLASS_BRIDGE_PCI << IDVAL3_SUBCLASS_SHIFT);
1908c2ecf20Sopenharmony_ci	bcm_pcie_writel(val, PCIE_IDVAL3_REG);
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	/* disable bar1 size */
1938c2ecf20Sopenharmony_ci	val = bcm_pcie_readl(PCIE_CONFIG2_REG);
1948c2ecf20Sopenharmony_ci	val &= ~CONFIG2_BAR1_SIZE_MASK;
1958c2ecf20Sopenharmony_ci	bcm_pcie_writel(val, PCIE_CONFIG2_REG);
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	/* set bar0 to little endian */
1988c2ecf20Sopenharmony_ci	val = (BCM_PCIE_MEM_BASE_PA >> 20) << BASEMASK_BASE_SHIFT;
1998c2ecf20Sopenharmony_ci	val |= (BCM_PCIE_MEM_BASE_PA >> 20) << BASEMASK_MASK_SHIFT;
2008c2ecf20Sopenharmony_ci	val |= BASEMASK_REMAP_EN;
2018c2ecf20Sopenharmony_ci	bcm_pcie_writel(val, PCIE_BRIDGE_BAR0_BASEMASK_REG);
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	val = (BCM_PCIE_MEM_BASE_PA >> 20) << REBASE_ADDR_BASE_SHIFT;
2048c2ecf20Sopenharmony_ci	bcm_pcie_writel(val, PCIE_BRIDGE_BAR0_REBASE_ADDR_REG);
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	register_pci_controller(&bcm63xx_pcie_controller);
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	return 0;
2098c2ecf20Sopenharmony_ci}
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_cistatic int __init bcm63xx_register_pci(void)
2128c2ecf20Sopenharmony_ci{
2138c2ecf20Sopenharmony_ci	unsigned int mem_size;
2148c2ecf20Sopenharmony_ci	u32 val;
2158c2ecf20Sopenharmony_ci	/*
2168c2ecf20Sopenharmony_ci	 * configuration  access are  done through  IO space,  remap 4
2178c2ecf20Sopenharmony_ci	 * first bytes to access it from CPU.
2188c2ecf20Sopenharmony_ci	 *
2198c2ecf20Sopenharmony_ci	 * this means that  no io access from CPU  should happen while
2208c2ecf20Sopenharmony_ci	 * we do a configuration cycle,	 but there's no way we can add
2218c2ecf20Sopenharmony_ci	 * a spinlock for each io access, so this is currently kind of
2228c2ecf20Sopenharmony_ci	 * broken on SMP.
2238c2ecf20Sopenharmony_ci	 */
2248c2ecf20Sopenharmony_ci	pci_iospace_start = ioremap(BCM_PCI_IO_BASE_PA, 4);
2258c2ecf20Sopenharmony_ci	if (!pci_iospace_start)
2268c2ecf20Sopenharmony_ci		return -ENOMEM;
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	/* setup local bus to PCI access (PCI memory) */
2298c2ecf20Sopenharmony_ci	val = BCM_PCI_MEM_BASE_PA & MPI_L2P_BASE_MASK;
2308c2ecf20Sopenharmony_ci	bcm_mpi_writel(val, MPI_L2PMEMBASE1_REG);
2318c2ecf20Sopenharmony_ci	bcm_mpi_writel(~(BCM_PCI_MEM_SIZE - 1), MPI_L2PMEMRANGE1_REG);
2328c2ecf20Sopenharmony_ci	bcm_mpi_writel(val | MPI_L2PREMAP_ENABLED_MASK, MPI_L2PMEMREMAP1_REG);
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	/* set Cardbus IDSEL (type 0 cfg access on primary bus for
2358c2ecf20Sopenharmony_ci	 * this IDSEL will be done on Cardbus instead) */
2368c2ecf20Sopenharmony_ci	val = bcm_pcmcia_readl(PCMCIA_C1_REG);
2378c2ecf20Sopenharmony_ci	val &= ~PCMCIA_C1_CBIDSEL_MASK;
2388c2ecf20Sopenharmony_ci	val |= (CARDBUS_PCI_IDSEL << PCMCIA_C1_CBIDSEL_SHIFT);
2398c2ecf20Sopenharmony_ci	bcm_pcmcia_writel(val, PCMCIA_C1_REG);
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci#ifdef CONFIG_CARDBUS
2428c2ecf20Sopenharmony_ci	/* setup local bus to PCI access (Cardbus memory) */
2438c2ecf20Sopenharmony_ci	val = BCM_CB_MEM_BASE_PA & MPI_L2P_BASE_MASK;
2448c2ecf20Sopenharmony_ci	bcm_mpi_writel(val, MPI_L2PMEMBASE2_REG);
2458c2ecf20Sopenharmony_ci	bcm_mpi_writel(~(BCM_CB_MEM_SIZE - 1), MPI_L2PMEMRANGE2_REG);
2468c2ecf20Sopenharmony_ci	val |= MPI_L2PREMAP_ENABLED_MASK | MPI_L2PREMAP_IS_CARDBUS_MASK;
2478c2ecf20Sopenharmony_ci	bcm_mpi_writel(val, MPI_L2PMEMREMAP2_REG);
2488c2ecf20Sopenharmony_ci#else
2498c2ecf20Sopenharmony_ci	/* disable second access windows */
2508c2ecf20Sopenharmony_ci	bcm_mpi_writel(0, MPI_L2PMEMREMAP2_REG);
2518c2ecf20Sopenharmony_ci#endif
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	/* setup local bus  to PCI access (IO memory),	we have only 1
2548c2ecf20Sopenharmony_ci	 * IO window  for both PCI  and cardbus, but it	 cannot handle
2558c2ecf20Sopenharmony_ci	 * both	 at the	 same time,  assume standard  PCI for  now, if
2568c2ecf20Sopenharmony_ci	 * cardbus card has  IO zone, PCI fixup will  change window to
2578c2ecf20Sopenharmony_ci	 * cardbus */
2588c2ecf20Sopenharmony_ci	val = BCM_PCI_IO_BASE_PA & MPI_L2P_BASE_MASK;
2598c2ecf20Sopenharmony_ci	bcm_mpi_writel(val, MPI_L2PIOBASE_REG);
2608c2ecf20Sopenharmony_ci	bcm_mpi_writel(~(BCM_PCI_IO_SIZE - 1), MPI_L2PIORANGE_REG);
2618c2ecf20Sopenharmony_ci	bcm_mpi_writel(val | MPI_L2PREMAP_ENABLED_MASK, MPI_L2PIOREMAP_REG);
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	/* enable PCI related GPIO pins */
2648c2ecf20Sopenharmony_ci	bcm_mpi_writel(MPI_LOCBUSCTL_EN_PCI_GPIO_MASK, MPI_LOCBUSCTL_REG);
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	/* setup PCI to local bus access, used by PCI device to target
2678c2ecf20Sopenharmony_ci	 * local RAM while bus mastering */
2688c2ecf20Sopenharmony_ci	bcm63xx_int_cfg_writel(0, PCI_BASE_ADDRESS_3);
2698c2ecf20Sopenharmony_ci	if (BCMCPU_IS_3368() || BCMCPU_IS_6358() || BCMCPU_IS_6368())
2708c2ecf20Sopenharmony_ci		val = MPI_SP0_REMAP_ENABLE_MASK;
2718c2ecf20Sopenharmony_ci	else
2728c2ecf20Sopenharmony_ci		val = 0;
2738c2ecf20Sopenharmony_ci	bcm_mpi_writel(val, MPI_SP0_REMAP_REG);
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	bcm63xx_int_cfg_writel(0x0, PCI_BASE_ADDRESS_4);
2768c2ecf20Sopenharmony_ci	bcm_mpi_writel(0, MPI_SP1_REMAP_REG);
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	mem_size = bcm63xx_get_memory_size();
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	/* 6348 before rev b0 exposes only 16 MB of RAM memory through
2818c2ecf20Sopenharmony_ci	 * PCI, throw a warning if we have more memory */
2828c2ecf20Sopenharmony_ci	if (BCMCPU_IS_6348() && (bcm63xx_get_cpu_rev() & 0xf0) == 0xa0) {
2838c2ecf20Sopenharmony_ci		if (mem_size > (16 * 1024 * 1024))
2848c2ecf20Sopenharmony_ci			printk(KERN_WARNING "bcm63xx: this CPU "
2858c2ecf20Sopenharmony_ci			       "revision cannot handle more than 16MB "
2868c2ecf20Sopenharmony_ci			       "of RAM for PCI bus mastering\n");
2878c2ecf20Sopenharmony_ci	} else {
2888c2ecf20Sopenharmony_ci		/* setup sp0 range to local RAM size */
2898c2ecf20Sopenharmony_ci		bcm_mpi_writel(~(mem_size - 1), MPI_SP0_RANGE_REG);
2908c2ecf20Sopenharmony_ci		bcm_mpi_writel(0, MPI_SP1_RANGE_REG);
2918c2ecf20Sopenharmony_ci	}
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	/* change  host bridge	retry  counter to  infinite number  of
2948c2ecf20Sopenharmony_ci	 * retry,  needed for  some broadcom  wifi cards  with Silicon
2958c2ecf20Sopenharmony_ci	 * Backplane bus where access to srom seems very slow  */
2968c2ecf20Sopenharmony_ci	val = bcm63xx_int_cfg_readl(BCMPCI_REG_TIMERS);
2978c2ecf20Sopenharmony_ci	val &= ~REG_TIMER_RETRY_MASK;
2988c2ecf20Sopenharmony_ci	bcm63xx_int_cfg_writel(val, BCMPCI_REG_TIMERS);
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	/* enable memory decoder and bus mastering */
3018c2ecf20Sopenharmony_ci	val = bcm63xx_int_cfg_readl(PCI_COMMAND);
3028c2ecf20Sopenharmony_ci	val |= (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
3038c2ecf20Sopenharmony_ci	bcm63xx_int_cfg_writel(val, PCI_COMMAND);
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	/* enable read prefetching & disable byte swapping for bus
3068c2ecf20Sopenharmony_ci	 * mastering transfers */
3078c2ecf20Sopenharmony_ci	val = bcm_mpi_readl(MPI_PCIMODESEL_REG);
3088c2ecf20Sopenharmony_ci	val &= ~MPI_PCIMODESEL_BAR1_NOSWAP_MASK;
3098c2ecf20Sopenharmony_ci	val &= ~MPI_PCIMODESEL_BAR2_NOSWAP_MASK;
3108c2ecf20Sopenharmony_ci	val &= ~MPI_PCIMODESEL_PREFETCH_MASK;
3118c2ecf20Sopenharmony_ci	val |= (8 << MPI_PCIMODESEL_PREFETCH_SHIFT);
3128c2ecf20Sopenharmony_ci	bcm_mpi_writel(val, MPI_PCIMODESEL_REG);
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	/* enable pci interrupt */
3158c2ecf20Sopenharmony_ci	val = bcm_mpi_readl(MPI_LOCINT_REG);
3168c2ecf20Sopenharmony_ci	val |= MPI_LOCINT_MASK(MPI_LOCINT_EXT_PCI_INT);
3178c2ecf20Sopenharmony_ci	bcm_mpi_writel(val, MPI_LOCINT_REG);
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	register_pci_controller(&bcm63xx_controller);
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci#ifdef CONFIG_CARDBUS
3228c2ecf20Sopenharmony_ci	register_pci_controller(&bcm63xx_cb_controller);
3238c2ecf20Sopenharmony_ci#endif
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	/* mark memory space used for IO mapping as reserved */
3268c2ecf20Sopenharmony_ci	request_mem_region(BCM_PCI_IO_BASE_PA, BCM_PCI_IO_SIZE,
3278c2ecf20Sopenharmony_ci			   "bcm63xx PCI IO space");
3288c2ecf20Sopenharmony_ci	return 0;
3298c2ecf20Sopenharmony_ci}
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_cistatic int __init bcm63xx_pci_init(void)
3338c2ecf20Sopenharmony_ci{
3348c2ecf20Sopenharmony_ci	if (!bcm63xx_pci_enabled)
3358c2ecf20Sopenharmony_ci		return -ENODEV;
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	switch (bcm63xx_get_cpu_id()) {
3388c2ecf20Sopenharmony_ci	case BCM6328_CPU_ID:
3398c2ecf20Sopenharmony_ci	case BCM6362_CPU_ID:
3408c2ecf20Sopenharmony_ci		return bcm63xx_register_pcie();
3418c2ecf20Sopenharmony_ci	case BCM3368_CPU_ID:
3428c2ecf20Sopenharmony_ci	case BCM6348_CPU_ID:
3438c2ecf20Sopenharmony_ci	case BCM6358_CPU_ID:
3448c2ecf20Sopenharmony_ci	case BCM6368_CPU_ID:
3458c2ecf20Sopenharmony_ci		return bcm63xx_register_pci();
3468c2ecf20Sopenharmony_ci	default:
3478c2ecf20Sopenharmony_ci		return -ENODEV;
3488c2ecf20Sopenharmony_ci	}
3498c2ecf20Sopenharmony_ci}
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ciarch_initcall(bcm63xx_pci_init);
352