diff options
Diffstat (limited to 'drivers/bcma/host_pci.c')
| -rw-r--r-- | drivers/bcma/host_pci.c | 196 | 
1 files changed, 196 insertions, 0 deletions
| diff --git a/drivers/bcma/host_pci.c b/drivers/bcma/host_pci.c new file mode 100644 index 000000000000..99dd36e8500b --- /dev/null +++ b/drivers/bcma/host_pci.c @@ -0,0 +1,196 @@ +/* + * Broadcom specific AMBA + * PCI Host + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include "bcma_private.h" +#include <linux/bcma/bcma.h> +#include <linux/pci.h> + +static void bcma_host_pci_switch_core(struct bcma_device *core) +{ +	pci_write_config_dword(core->bus->host_pci, BCMA_PCI_BAR0_WIN, +			       core->addr); +	pci_write_config_dword(core->bus->host_pci, BCMA_PCI_BAR0_WIN2, +			       core->wrap); +	core->bus->mapped_core = core; +	pr_debug("Switched to core: 0x%X\n", core->id.id); +} + +static u8 bcma_host_pci_read8(struct bcma_device *core, u16 offset) +{ +	if (core->bus->mapped_core != core) +		bcma_host_pci_switch_core(core); +	return ioread8(core->bus->mmio + offset); +} + +static u16 bcma_host_pci_read16(struct bcma_device *core, u16 offset) +{ +	if (core->bus->mapped_core != core) +		bcma_host_pci_switch_core(core); +	return ioread16(core->bus->mmio + offset); +} + +static u32 bcma_host_pci_read32(struct bcma_device *core, u16 offset) +{ +	if (core->bus->mapped_core != core) +		bcma_host_pci_switch_core(core); +	return ioread32(core->bus->mmio + offset); +} + +static void bcma_host_pci_write8(struct bcma_device *core, u16 offset, +				 u8 value) +{ +	if (core->bus->mapped_core != core) +		bcma_host_pci_switch_core(core); +	iowrite8(value, core->bus->mmio + offset); +} + +static void bcma_host_pci_write16(struct bcma_device *core, u16 offset, +				 u16 value) +{ +	if (core->bus->mapped_core != core) +		bcma_host_pci_switch_core(core); +	iowrite16(value, core->bus->mmio + offset); +} + +static void bcma_host_pci_write32(struct bcma_device *core, u16 offset, +				 u32 value) +{ +	if (core->bus->mapped_core != core) +		bcma_host_pci_switch_core(core); +	iowrite32(value, core->bus->mmio + offset); +} + +static u32 bcma_host_pci_aread32(struct bcma_device *core, u16 offset) +{ +	if (core->bus->mapped_core != core) +		bcma_host_pci_switch_core(core); +	return ioread32(core->bus->mmio + (1 * BCMA_CORE_SIZE) + offset); +} + +static void bcma_host_pci_awrite32(struct bcma_device *core, u16 offset, +				  u32 value) +{ +	if (core->bus->mapped_core != core) +		bcma_host_pci_switch_core(core); +	iowrite32(value, core->bus->mmio + (1 * BCMA_CORE_SIZE) + offset); +} + +const struct bcma_host_ops bcma_host_pci_ops = { +	.read8		= bcma_host_pci_read8, +	.read16		= bcma_host_pci_read16, +	.read32		= bcma_host_pci_read32, +	.write8		= bcma_host_pci_write8, +	.write16	= bcma_host_pci_write16, +	.write32	= bcma_host_pci_write32, +	.aread32	= bcma_host_pci_aread32, +	.awrite32	= bcma_host_pci_awrite32, +}; + +static int bcma_host_pci_probe(struct pci_dev *dev, +			     const struct pci_device_id *id) +{ +	struct bcma_bus *bus; +	int err = -ENOMEM; +	const char *name; +	u32 val; + +	/* Alloc */ +	bus = kzalloc(sizeof(*bus), GFP_KERNEL); +	if (!bus) +		goto out; + +	/* Basic PCI configuration */ +	err = pci_enable_device(dev); +	if (err) +		goto err_kfree_bus; + +	name = dev_name(&dev->dev); +	if (dev->driver && dev->driver->name) +		name = dev->driver->name; +	err = pci_request_regions(dev, name); +	if (err) +		goto err_pci_disable; +	pci_set_master(dev); + +	/* Disable the RETRY_TIMEOUT register (0x41) to keep +	 * PCI Tx retries from interfering with C3 CPU state */ +	pci_read_config_dword(dev, 0x40, &val); +	if ((val & 0x0000ff00) != 0) +		pci_write_config_dword(dev, 0x40, val & 0xffff00ff); + +	/* SSB needed additional powering up, do we have any AMBA PCI cards? */ +	if (!pci_is_pcie(dev)) +		pr_err("PCI card detected, report problems.\n"); + +	/* Map MMIO */ +	err = -ENOMEM; +	bus->mmio = pci_iomap(dev, 0, ~0UL); +	if (!bus->mmio) +		goto err_pci_release_regions; + +	/* Host specific */ +	bus->host_pci = dev; +	bus->hosttype = BCMA_HOSTTYPE_PCI; +	bus->ops = &bcma_host_pci_ops; + +	/* Register */ +	err = bcma_bus_register(bus); +	if (err) +		goto err_pci_unmap_mmio; + +	pci_set_drvdata(dev, bus); + +out: +	return err; + +err_pci_unmap_mmio: +	pci_iounmap(dev, bus->mmio); +err_pci_release_regions: +	pci_release_regions(dev); +err_pci_disable: +	pci_disable_device(dev); +err_kfree_bus: +	kfree(bus); +	return err; +} + +static void bcma_host_pci_remove(struct pci_dev *dev) +{ +	struct bcma_bus *bus = pci_get_drvdata(dev); + +	bcma_bus_unregister(bus); +	pci_iounmap(dev, bus->mmio); +	pci_release_regions(dev); +	pci_disable_device(dev); +	kfree(bus); +	pci_set_drvdata(dev, NULL); +} + +static DEFINE_PCI_DEVICE_TABLE(bcma_pci_bridge_tbl) = { +	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4331) }, +	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4353) }, +	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4727) }, +	{ 0, }, +}; +MODULE_DEVICE_TABLE(pci, bcma_pci_bridge_tbl); + +static struct pci_driver bcma_pci_bridge_driver = { +	.name = "bcma-pci-bridge", +	.id_table = bcma_pci_bridge_tbl, +	.probe = bcma_host_pci_probe, +	.remove = bcma_host_pci_remove, +}; + +int __init bcma_host_pci_init(void) +{ +	return pci_register_driver(&bcma_pci_bridge_driver); +} + +void __exit bcma_host_pci_exit(void) +{ +	pci_unregister_driver(&bcma_pci_bridge_driver); +} | 
