Commit 49dc9577 authored by Hauke Mehrtens's avatar Hauke Mehrtens Committed by John W. Linville

bcma: add PCIe host controller

Some SoCs have a PCIe host controller to make it possible to attach
some other devices to it, like an other Wifi card.
This code was tested with an Netgear WNDR3400 (bcm4716 based), but
should work with all bcma based SoCs.
Signed-off-by: default avatarHauke Mehrtens <hauke@hauke-m.de>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent d1a7a8e1
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/ssb/ssb.h> #include <linux/ssb/ssb.h>
#include <linux/bcma/bcma.h>
#include <bcm47xx.h> #include <bcm47xx.h>
int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
...@@ -32,15 +33,12 @@ int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) ...@@ -32,15 +33,12 @@ int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
return 0; return 0;
} }
int pcibios_plat_dev_init(struct pci_dev *dev)
{
#ifdef CONFIG_BCM47XX_SSB #ifdef CONFIG_BCM47XX_SSB
static int bcm47xx_pcibios_plat_dev_init_ssb(struct pci_dev *dev)
{
int res; int res;
u8 slot, pin; u8 slot, pin;
if (bcm47xx_bus_type != BCM47XX_BUS_TYPE_SSB)
return 0;
res = ssb_pcibios_plat_dev_init(dev); res = ssb_pcibios_plat_dev_init(dev);
if (res < 0) { if (res < 0) {
printk(KERN_ALERT "PCI: Failed to init device %s\n", printk(KERN_ALERT "PCI: Failed to init device %s\n",
...@@ -60,6 +58,47 @@ int pcibios_plat_dev_init(struct pci_dev *dev) ...@@ -60,6 +58,47 @@ int pcibios_plat_dev_init(struct pci_dev *dev)
} }
dev->irq = res; dev->irq = res;
return 0;
}
#endif #endif
#ifdef CONFIG_BCM47XX_BCMA
static int bcm47xx_pcibios_plat_dev_init_bcma(struct pci_dev *dev)
{
int res;
res = bcma_core_pci_plat_dev_init(dev);
if (res < 0) {
printk(KERN_ALERT "PCI: Failed to init device %s\n",
pci_name(dev));
return res;
}
res = bcma_core_pci_pcibios_map_irq(dev);
/* IRQ-0 and IRQ-1 are software interrupts. */
if (res < 2) {
printk(KERN_ALERT "PCI: Failed to map IRQ of device %s\n",
pci_name(dev));
return res;
}
dev->irq = res;
return 0; return 0;
} }
#endif
int pcibios_plat_dev_init(struct pci_dev *dev)
{
#ifdef CONFIG_BCM47XX_SSB
if (bcm47xx_bus_type == BCM47XX_BUS_TYPE_SSB)
return bcm47xx_pcibios_plat_dev_init_ssb(dev);
else
#endif
#ifdef CONFIG_BCM47XX_BCMA
if (bcm47xx_bus_type == BCM47XX_BUS_TYPE_BCMA)
return bcm47xx_pcibios_plat_dev_init_bcma(dev);
else
#endif
return 0;
}
...@@ -52,6 +52,7 @@ extern void __exit bcma_host_pci_exit(void); ...@@ -52,6 +52,7 @@ extern void __exit bcma_host_pci_exit(void);
u32 bcma_pcie_read(struct bcma_drv_pci *pc, u32 address); u32 bcma_pcie_read(struct bcma_drv_pci *pc, u32 address);
#ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE #ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
bool __devinit bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc);
void __devinit bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc); void __devinit bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc);
#endif /* CONFIG_BCMA_DRIVER_PCI_HOSTMODE */ #endif /* CONFIG_BCMA_DRIVER_PCI_HOSTMODE */
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* Broadcom specific AMBA * Broadcom specific AMBA
* PCI Core * PCI Core
* *
* Copyright 2005, Broadcom Corporation * Copyright 2005, 2011, Broadcom Corporation
* Copyright 2006, 2007, Michael Buesch <m@bues.ch> * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
* Copyright 2011, 2012, Hauke Mehrtens <hauke@hauke-m.de> * Copyright 2011, 2012, Hauke Mehrtens <hauke@hauke-m.de>
* *
...@@ -179,47 +179,19 @@ static void __devinit bcma_core_pci_clientmode_init(struct bcma_drv_pci *pc) ...@@ -179,47 +179,19 @@ static void __devinit bcma_core_pci_clientmode_init(struct bcma_drv_pci *pc)
bcma_pcicore_serdes_workaround(pc); bcma_pcicore_serdes_workaround(pc);
} }
static bool __devinit bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc)
{
struct bcma_bus *bus = pc->core->bus;
u16 chipid_top;
chipid_top = (bus->chipinfo.id & 0xFF00);
if (chipid_top != 0x4700 &&
chipid_top != 0x5300)
return false;
#ifdef CONFIG_SSB_DRIVER_PCICORE
if (bus->sprom.boardflags_lo & SSB_BFL_NOPCI)
return false;
#endif /* CONFIG_SSB_DRIVER_PCICORE */
#if 0
/* TODO: on BCMA we use address from EROM instead of magic formula */
u32 tmp;
return !mips_busprobe32(tmp, (bus->mmio +
(pc->core->core_index * BCMA_CORE_SIZE)));
#endif
return true;
}
void __devinit bcma_core_pci_init(struct bcma_drv_pci *pc) void __devinit bcma_core_pci_init(struct bcma_drv_pci *pc)
{ {
if (pc->setup_done) if (pc->setup_done)
return; return;
if (bcma_core_pci_is_in_hostmode(pc)) {
#ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE #ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
pc->hostmode = bcma_core_pci_is_in_hostmode(pc);
if (pc->hostmode)
bcma_core_pci_hostmode_init(pc); bcma_core_pci_hostmode_init(pc);
#else
pr_err("Driver compiled without support for hostmode PCI\n");
#endif /* CONFIG_BCMA_DRIVER_PCI_HOSTMODE */ #endif /* CONFIG_BCMA_DRIVER_PCI_HOSTMODE */
} else {
bcma_core_pci_clientmode_init(pc);
}
pc->setup_done = true; if (!pc->hostmode)
bcma_core_pci_clientmode_init(pc);
} }
int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core, int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core,
......
This diff is collapsed.
...@@ -160,9 +160,44 @@ struct pci_dev; ...@@ -160,9 +160,44 @@ struct pci_dev;
/* PCIcore specific boardflags */ /* PCIcore specific boardflags */
#define BCMA_CORE_PCI_BFL_NOPCI 0x00000400 /* Board leaves PCI floating */ #define BCMA_CORE_PCI_BFL_NOPCI 0x00000400 /* Board leaves PCI floating */
/* PCIE Config space accessing MACROS */
#define BCMA_CORE_PCI_CFG_BUS_SHIFT 24 /* Bus shift */
#define BCMA_CORE_PCI_CFG_SLOT_SHIFT 19 /* Slot/Device shift */
#define BCMA_CORE_PCI_CFG_FUN_SHIFT 16 /* Function shift */
#define BCMA_CORE_PCI_CFG_OFF_SHIFT 0 /* Register shift */
#define BCMA_CORE_PCI_CFG_BUS_MASK 0xff /* Bus mask */
#define BCMA_CORE_PCI_CFG_SLOT_MASK 0x1f /* Slot/Device mask */
#define BCMA_CORE_PCI_CFG_FUN_MASK 7 /* Function mask */
#define BCMA_CORE_PCI_CFG_OFF_MASK 0xfff /* Register mask */
/* PCIE Root Capability Register bits (Host mode only) */
#define BCMA_CORE_PCI_RC_CRS_VISIBILITY 0x0001
struct bcma_drv_pci;
#ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
struct bcma_drv_pci_host {
struct bcma_drv_pci *pdev;
u32 host_cfg_addr;
spinlock_t cfgspace_lock;
struct pci_controller pci_controller;
struct pci_ops pci_ops;
struct resource mem_resource;
struct resource io_resource;
};
#endif
struct bcma_drv_pci { struct bcma_drv_pci {
struct bcma_device *core; struct bcma_device *core;
u8 setup_done:1; u8 setup_done:1;
u8 hostmode:1;
#ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
struct bcma_drv_pci_host *host_controller;
#endif
}; };
/* Register access */ /* Register access */
...@@ -173,4 +208,7 @@ extern void __devinit bcma_core_pci_init(struct bcma_drv_pci *pc); ...@@ -173,4 +208,7 @@ extern void __devinit bcma_core_pci_init(struct bcma_drv_pci *pc);
extern int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, extern int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc,
struct bcma_device *core, bool enable); struct bcma_device *core, bool enable);
extern int bcma_core_pci_pcibios_map_irq(const struct pci_dev *dev);
extern int bcma_core_pci_plat_dev_init(struct pci_dev *dev);
#endif /* LINUX_BCMA_DRIVER_PCI_H_ */ #endif /* LINUX_BCMA_DRIVER_PCI_H_ */
...@@ -56,4 +56,31 @@ ...@@ -56,4 +56,31 @@
#define BCMA_PCI_GPIO_XTAL 0x40 /* PCI config space GPIO 14 for Xtal powerup */ #define BCMA_PCI_GPIO_XTAL 0x40 /* PCI config space GPIO 14 for Xtal powerup */
#define BCMA_PCI_GPIO_PLL 0x80 /* PCI config space GPIO 15 for PLL powerdown */ #define BCMA_PCI_GPIO_PLL 0x80 /* PCI config space GPIO 15 for PLL powerdown */
/* SiliconBackplane Address Map.
* All regions may not exist on all chips.
*/
#define BCMA_SOC_SDRAM_BASE 0x00000000U /* Physical SDRAM */
#define BCMA_SOC_PCI_MEM 0x08000000U /* Host Mode sb2pcitranslation0 (64 MB) */
#define BCMA_SOC_PCI_MEM_SZ (64 * 1024 * 1024)
#define BCMA_SOC_PCI_CFG 0x0c000000U /* Host Mode sb2pcitranslation1 (64 MB) */
#define BCMA_SOC_SDRAM_SWAPPED 0x10000000U /* Byteswapped Physical SDRAM */
#define BCMA_SOC_SDRAM_R2 0x80000000U /* Region 2 for sdram (512 MB) */
#define BCMA_SOC_PCI_DMA 0x40000000U /* Client Mode sb2pcitranslation2 (1 GB) */
#define BCMA_SOC_PCI_DMA2 0x80000000U /* Client Mode sb2pcitranslation2 (1 GB) */
#define BCMA_SOC_PCI_DMA_SZ 0x40000000U /* Client Mode sb2pcitranslation2 size in bytes */
#define BCMA_SOC_PCIE_DMA_L32 0x00000000U /* PCIE Client Mode sb2pcitranslation2
* (2 ZettaBytes), low 32 bits
*/
#define BCMA_SOC_PCIE_DMA_H32 0x80000000U /* PCIE Client Mode sb2pcitranslation2
* (2 ZettaBytes), high 32 bits
*/
#define BCMA_SOC_PCI1_MEM 0x40000000U /* Host Mode sb2pcitranslation0 (64 MB) */
#define BCMA_SOC_PCI1_CFG 0x44000000U /* Host Mode sb2pcitranslation1 (64 MB) */
#define BCMA_SOC_PCIE1_DMA_H32 0xc0000000U /* PCIE Client Mode sb2pcitranslation2
* (2 ZettaBytes), high 32 bits
*/
#endif /* LINUX_BCMA_REGS_H_ */ #endif /* LINUX_BCMA_REGS_H_ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment