xref: /linux/drivers/bcma/host_pci.c (revision 646e0827df85f1305eeebf2108e9daafeabe0e0d)
18369ae33SRafał Miłecki /*
28369ae33SRafał Miłecki  * Broadcom specific AMBA
38369ae33SRafał Miłecki  * PCI Host
48369ae33SRafał Miłecki  *
58369ae33SRafał Miłecki  * Licensed under the GNU/GPL. See COPYING for details.
68369ae33SRafał Miłecki  */
78369ae33SRafał Miłecki 
88369ae33SRafał Miłecki #include "bcma_private.h"
9ba7328b2SAndrew Morton #include <linux/slab.h>
108369ae33SRafał Miłecki #include <linux/bcma/bcma.h>
118369ae33SRafał Miłecki #include <linux/pci.h>
12200351c7SPaul Gortmaker #include <linux/module.h>
138369ae33SRafał Miłecki 
148369ae33SRafał Miłecki static void bcma_host_pci_switch_core(struct bcma_device *core)
158369ae33SRafał Miłecki {
168369ae33SRafał Miłecki 	pci_write_config_dword(core->bus->host_pci, BCMA_PCI_BAR0_WIN,
178369ae33SRafał Miłecki 			       core->addr);
188369ae33SRafał Miłecki 	pci_write_config_dword(core->bus->host_pci, BCMA_PCI_BAR0_WIN2,
198369ae33SRafał Miłecki 			       core->wrap);
208369ae33SRafał Miłecki 	core->bus->mapped_core = core;
213d9d8af3SRafał Miłecki 	bcma_debug(core->bus, "Switched to core: 0x%X\n", core->id.id);
228369ae33SRafał Miłecki }
238369ae33SRafał Miłecki 
24439678f8SRafał Miłecki /* Provides access to the requested core. Returns base offset that has to be
25439678f8SRafał Miłecki  * used. It makes use of fixed windows when possible. */
26439678f8SRafał Miłecki static u16 bcma_host_pci_provide_access_to_core(struct bcma_device *core)
278369ae33SRafał Miłecki {
28439678f8SRafał Miłecki 	switch (core->id.id) {
29439678f8SRafał Miłecki 	case BCMA_CORE_CHIPCOMMON:
30439678f8SRafał Miłecki 		return 3 * BCMA_CORE_SIZE;
31439678f8SRafał Miłecki 	case BCMA_CORE_PCIE:
32439678f8SRafał Miłecki 		return 2 * BCMA_CORE_SIZE;
33439678f8SRafał Miłecki 	}
34439678f8SRafał Miłecki 
358369ae33SRafał Miłecki 	if (core->bus->mapped_core != core)
368369ae33SRafał Miłecki 		bcma_host_pci_switch_core(core);
37439678f8SRafał Miłecki 	return 0;
38439678f8SRafał Miłecki }
39439678f8SRafał Miłecki 
40439678f8SRafał Miłecki static u8 bcma_host_pci_read8(struct bcma_device *core, u16 offset)
41439678f8SRafał Miłecki {
42439678f8SRafał Miłecki 	offset += bcma_host_pci_provide_access_to_core(core);
438369ae33SRafał Miłecki 	return ioread8(core->bus->mmio + offset);
448369ae33SRafał Miłecki }
458369ae33SRafał Miłecki 
468369ae33SRafał Miłecki static u16 bcma_host_pci_read16(struct bcma_device *core, u16 offset)
478369ae33SRafał Miłecki {
48439678f8SRafał Miłecki 	offset += bcma_host_pci_provide_access_to_core(core);
498369ae33SRafał Miłecki 	return ioread16(core->bus->mmio + offset);
508369ae33SRafał Miłecki }
518369ae33SRafał Miłecki 
528369ae33SRafał Miłecki static u32 bcma_host_pci_read32(struct bcma_device *core, u16 offset)
538369ae33SRafał Miłecki {
54439678f8SRafał Miłecki 	offset += bcma_host_pci_provide_access_to_core(core);
558369ae33SRafał Miłecki 	return ioread32(core->bus->mmio + offset);
568369ae33SRafał Miłecki }
578369ae33SRafał Miłecki 
588369ae33SRafał Miłecki static void bcma_host_pci_write8(struct bcma_device *core, u16 offset,
598369ae33SRafał Miłecki 				 u8 value)
608369ae33SRafał Miłecki {
61439678f8SRafał Miłecki 	offset += bcma_host_pci_provide_access_to_core(core);
628369ae33SRafał Miłecki 	iowrite8(value, core->bus->mmio + offset);
638369ae33SRafał Miłecki }
648369ae33SRafał Miłecki 
658369ae33SRafał Miłecki static void bcma_host_pci_write16(struct bcma_device *core, u16 offset,
668369ae33SRafał Miłecki 				 u16 value)
678369ae33SRafał Miłecki {
68439678f8SRafał Miłecki 	offset += bcma_host_pci_provide_access_to_core(core);
698369ae33SRafał Miłecki 	iowrite16(value, core->bus->mmio + offset);
708369ae33SRafał Miłecki }
718369ae33SRafał Miłecki 
728369ae33SRafał Miłecki static void bcma_host_pci_write32(struct bcma_device *core, u16 offset,
738369ae33SRafał Miłecki 				 u32 value)
748369ae33SRafał Miłecki {
75439678f8SRafał Miłecki 	offset += bcma_host_pci_provide_access_to_core(core);
768369ae33SRafał Miłecki 	iowrite32(value, core->bus->mmio + offset);
778369ae33SRafał Miłecki }
788369ae33SRafał Miłecki 
799d75ef0fSRafał Miłecki #ifdef CONFIG_BCMA_BLOCKIO
8094f3457fSHauke Mehrtens static void bcma_host_pci_block_read(struct bcma_device *core, void *buffer,
819d75ef0fSRafał Miłecki 				     size_t count, u16 offset, u8 reg_width)
829d75ef0fSRafał Miłecki {
839d75ef0fSRafał Miłecki 	void __iomem *addr = core->bus->mmio + offset;
849d75ef0fSRafał Miłecki 	if (core->bus->mapped_core != core)
859d75ef0fSRafał Miłecki 		bcma_host_pci_switch_core(core);
869d75ef0fSRafał Miłecki 	switch (reg_width) {
879d75ef0fSRafał Miłecki 	case sizeof(u8):
889d75ef0fSRafał Miłecki 		ioread8_rep(addr, buffer, count);
899d75ef0fSRafał Miłecki 		break;
909d75ef0fSRafał Miłecki 	case sizeof(u16):
919d75ef0fSRafał Miłecki 		WARN_ON(count & 1);
929d75ef0fSRafał Miłecki 		ioread16_rep(addr, buffer, count >> 1);
939d75ef0fSRafał Miłecki 		break;
949d75ef0fSRafał Miłecki 	case sizeof(u32):
959d75ef0fSRafał Miłecki 		WARN_ON(count & 3);
969d75ef0fSRafał Miłecki 		ioread32_rep(addr, buffer, count >> 2);
979d75ef0fSRafał Miłecki 		break;
989d75ef0fSRafał Miłecki 	default:
999d75ef0fSRafał Miłecki 		WARN_ON(1);
1009d75ef0fSRafał Miłecki 	}
1019d75ef0fSRafał Miłecki }
1029d75ef0fSRafał Miłecki 
10394f3457fSHauke Mehrtens static void bcma_host_pci_block_write(struct bcma_device *core,
10494f3457fSHauke Mehrtens 				      const void *buffer, size_t count,
10594f3457fSHauke Mehrtens 				      u16 offset, u8 reg_width)
1069d75ef0fSRafał Miłecki {
1079d75ef0fSRafał Miłecki 	void __iomem *addr = core->bus->mmio + offset;
1089d75ef0fSRafał Miłecki 	if (core->bus->mapped_core != core)
1099d75ef0fSRafał Miłecki 		bcma_host_pci_switch_core(core);
1109d75ef0fSRafał Miłecki 	switch (reg_width) {
1119d75ef0fSRafał Miłecki 	case sizeof(u8):
1129d75ef0fSRafał Miłecki 		iowrite8_rep(addr, buffer, count);
1139d75ef0fSRafał Miłecki 		break;
1149d75ef0fSRafał Miłecki 	case sizeof(u16):
1159d75ef0fSRafał Miłecki 		WARN_ON(count & 1);
1169d75ef0fSRafał Miłecki 		iowrite16_rep(addr, buffer, count >> 1);
1179d75ef0fSRafał Miłecki 		break;
1189d75ef0fSRafał Miłecki 	case sizeof(u32):
1199d75ef0fSRafał Miłecki 		WARN_ON(count & 3);
1209d75ef0fSRafał Miłecki 		iowrite32_rep(addr, buffer, count >> 2);
1219d75ef0fSRafał Miłecki 		break;
1229d75ef0fSRafał Miłecki 	default:
1239d75ef0fSRafał Miłecki 		WARN_ON(1);
1249d75ef0fSRafał Miłecki 	}
1259d75ef0fSRafał Miłecki }
1269d75ef0fSRafał Miłecki #endif
1279d75ef0fSRafał Miłecki 
1288369ae33SRafał Miłecki static u32 bcma_host_pci_aread32(struct bcma_device *core, u16 offset)
1298369ae33SRafał Miłecki {
1308369ae33SRafał Miłecki 	if (core->bus->mapped_core != core)
1318369ae33SRafał Miłecki 		bcma_host_pci_switch_core(core);
1328369ae33SRafał Miłecki 	return ioread32(core->bus->mmio + (1 * BCMA_CORE_SIZE) + offset);
1338369ae33SRafał Miłecki }
1348369ae33SRafał Miłecki 
1358369ae33SRafał Miłecki static void bcma_host_pci_awrite32(struct bcma_device *core, u16 offset,
1368369ae33SRafał Miłecki 				  u32 value)
1378369ae33SRafał Miłecki {
1388369ae33SRafał Miłecki 	if (core->bus->mapped_core != core)
1398369ae33SRafał Miłecki 		bcma_host_pci_switch_core(core);
1408369ae33SRafał Miłecki 	iowrite32(value, core->bus->mmio + (1 * BCMA_CORE_SIZE) + offset);
1418369ae33SRafał Miłecki }
1428369ae33SRafał Miłecki 
14394f3457fSHauke Mehrtens static const struct bcma_host_ops bcma_host_pci_ops = {
1448369ae33SRafał Miłecki 	.read8		= bcma_host_pci_read8,
1458369ae33SRafał Miłecki 	.read16		= bcma_host_pci_read16,
1468369ae33SRafał Miłecki 	.read32		= bcma_host_pci_read32,
1478369ae33SRafał Miłecki 	.write8		= bcma_host_pci_write8,
1488369ae33SRafał Miłecki 	.write16	= bcma_host_pci_write16,
1498369ae33SRafał Miłecki 	.write32	= bcma_host_pci_write32,
1509d75ef0fSRafał Miłecki #ifdef CONFIG_BCMA_BLOCKIO
1519d75ef0fSRafał Miłecki 	.block_read	= bcma_host_pci_block_read,
1529d75ef0fSRafał Miłecki 	.block_write	= bcma_host_pci_block_write,
1539d75ef0fSRafał Miłecki #endif
1548369ae33SRafał Miłecki 	.aread32	= bcma_host_pci_aread32,
1558369ae33SRafał Miłecki 	.awrite32	= bcma_host_pci_awrite32,
1568369ae33SRafał Miłecki };
1578369ae33SRafał Miłecki 
158d1a7a8e1SHauke Mehrtens static int __devinit bcma_host_pci_probe(struct pci_dev *dev,
1598369ae33SRafał Miłecki 					 const struct pci_device_id *id)
1608369ae33SRafał Miłecki {
1618369ae33SRafał Miłecki 	struct bcma_bus *bus;
1628369ae33SRafał Miłecki 	int err = -ENOMEM;
1638369ae33SRafał Miłecki 	const char *name;
1648369ae33SRafał Miłecki 	u32 val;
1658369ae33SRafał Miłecki 
1668369ae33SRafał Miłecki 	/* Alloc */
1678369ae33SRafał Miłecki 	bus = kzalloc(sizeof(*bus), GFP_KERNEL);
1688369ae33SRafał Miłecki 	if (!bus)
1698369ae33SRafał Miłecki 		goto out;
1708369ae33SRafał Miłecki 
1718369ae33SRafał Miłecki 	/* Basic PCI configuration */
1728369ae33SRafał Miłecki 	err = pci_enable_device(dev);
1738369ae33SRafał Miłecki 	if (err)
1748369ae33SRafał Miłecki 		goto err_kfree_bus;
1758369ae33SRafał Miłecki 
1768369ae33SRafał Miłecki 	name = dev_name(&dev->dev);
1778369ae33SRafał Miłecki 	if (dev->driver && dev->driver->name)
1788369ae33SRafał Miłecki 		name = dev->driver->name;
1798369ae33SRafał Miłecki 	err = pci_request_regions(dev, name);
1808369ae33SRafał Miłecki 	if (err)
1818369ae33SRafał Miłecki 		goto err_pci_disable;
1828369ae33SRafał Miłecki 	pci_set_master(dev);
1838369ae33SRafał Miłecki 
1848369ae33SRafał Miłecki 	/* Disable the RETRY_TIMEOUT register (0x41) to keep
1858369ae33SRafał Miłecki 	 * PCI Tx retries from interfering with C3 CPU state */
1868369ae33SRafał Miłecki 	pci_read_config_dword(dev, 0x40, &val);
1878369ae33SRafał Miłecki 	if ((val & 0x0000ff00) != 0)
1888369ae33SRafał Miłecki 		pci_write_config_dword(dev, 0x40, val & 0xffff00ff);
1898369ae33SRafał Miłecki 
1908369ae33SRafał Miłecki 	/* SSB needed additional powering up, do we have any AMBA PCI cards? */
1918369ae33SRafał Miłecki 	if (!pci_is_pcie(dev))
1923d9d8af3SRafał Miłecki 		bcma_err(bus, "PCI card detected, report problems.\n");
1938369ae33SRafał Miłecki 
1948369ae33SRafał Miłecki 	/* Map MMIO */
1958369ae33SRafał Miłecki 	err = -ENOMEM;
1968369ae33SRafał Miłecki 	bus->mmio = pci_iomap(dev, 0, ~0UL);
1978369ae33SRafał Miłecki 	if (!bus->mmio)
1988369ae33SRafał Miłecki 		goto err_pci_release_regions;
1998369ae33SRafał Miłecki 
2008369ae33SRafał Miłecki 	/* Host specific */
2018369ae33SRafał Miłecki 	bus->host_pci = dev;
2028369ae33SRafał Miłecki 	bus->hosttype = BCMA_HOSTTYPE_PCI;
2038369ae33SRafał Miłecki 	bus->ops = &bcma_host_pci_ops;
2048369ae33SRafał Miłecki 
2050a2fcaa7SHauke Mehrtens 	bus->boardinfo.vendor = bus->host_pci->subsystem_vendor;
2060a2fcaa7SHauke Mehrtens 	bus->boardinfo.type = bus->host_pci->subsystem_device;
2070a2fcaa7SHauke Mehrtens 
2088369ae33SRafał Miłecki 	/* Register */
2098369ae33SRafał Miłecki 	err = bcma_bus_register(bus);
2108369ae33SRafał Miłecki 	if (err)
2118369ae33SRafał Miłecki 		goto err_pci_unmap_mmio;
2128369ae33SRafał Miłecki 
2138369ae33SRafał Miłecki 	pci_set_drvdata(dev, bus);
2148369ae33SRafał Miłecki 
2158369ae33SRafał Miłecki out:
2168369ae33SRafał Miłecki 	return err;
2178369ae33SRafał Miłecki 
2188369ae33SRafał Miłecki err_pci_unmap_mmio:
2198369ae33SRafał Miłecki 	pci_iounmap(dev, bus->mmio);
2208369ae33SRafał Miłecki err_pci_release_regions:
2218369ae33SRafał Miłecki 	pci_release_regions(dev);
2228369ae33SRafał Miłecki err_pci_disable:
2238369ae33SRafał Miłecki 	pci_disable_device(dev);
2248369ae33SRafał Miłecki err_kfree_bus:
2258369ae33SRafał Miłecki 	kfree(bus);
2268369ae33SRafał Miłecki 	return err;
2278369ae33SRafał Miłecki }
2288369ae33SRafał Miłecki 
22916d75faeSNathan Hintz static void __devexit bcma_host_pci_remove(struct pci_dev *dev)
2308369ae33SRafał Miłecki {
2318369ae33SRafał Miłecki 	struct bcma_bus *bus = pci_get_drvdata(dev);
2328369ae33SRafał Miłecki 
2338369ae33SRafał Miłecki 	bcma_bus_unregister(bus);
2348369ae33SRafał Miłecki 	pci_iounmap(dev, bus->mmio);
2358369ae33SRafał Miłecki 	pci_release_regions(dev);
2368369ae33SRafał Miłecki 	pci_disable_device(dev);
2378369ae33SRafał Miłecki 	kfree(bus);
2388369ae33SRafał Miłecki 	pci_set_drvdata(dev, NULL);
2398369ae33SRafał Miłecki }
2408369ae33SRafał Miłecki 
241775ab521SRafał Miłecki #ifdef CONFIG_PM
2425d2031f2SLinus Torvalds static int bcma_host_pci_suspend(struct device *dev)
243775ab521SRafał Miłecki {
2445d2031f2SLinus Torvalds 	struct pci_dev *pdev = to_pci_dev(dev);
2455d2031f2SLinus Torvalds 	struct bcma_bus *bus = pci_get_drvdata(pdev);
246775ab521SRafał Miłecki 
24728e7d218SRafał Miłecki 	bus->mapped_core = NULL;
2485d2031f2SLinus Torvalds 
249685a4ef0SLinus Torvalds 	return bcma_bus_suspend(bus);
250775ab521SRafał Miłecki }
251775ab521SRafał Miłecki 
2525d2031f2SLinus Torvalds static int bcma_host_pci_resume(struct device *dev)
253775ab521SRafał Miłecki {
2545d2031f2SLinus Torvalds 	struct pci_dev *pdev = to_pci_dev(dev);
2555d2031f2SLinus Torvalds 	struct bcma_bus *bus = pci_get_drvdata(pdev);
256775ab521SRafał Miłecki 
2575d2031f2SLinus Torvalds 	return bcma_bus_resume(bus);
258775ab521SRafał Miłecki }
2595d2031f2SLinus Torvalds 
2605d2031f2SLinus Torvalds static SIMPLE_DEV_PM_OPS(bcma_pm_ops, bcma_host_pci_suspend,
2615d2031f2SLinus Torvalds 			 bcma_host_pci_resume);
2625d2031f2SLinus Torvalds #define BCMA_PM_OPS	(&bcma_pm_ops)
2635d2031f2SLinus Torvalds 
264775ab521SRafał Miłecki #else /* CONFIG_PM */
2655d2031f2SLinus Torvalds 
2665d2031f2SLinus Torvalds #define BCMA_PM_OPS     NULL
2675d2031f2SLinus Torvalds 
268775ab521SRafał Miłecki #endif /* CONFIG_PM */
269775ab521SRafał Miłecki 
2708369ae33SRafał Miłecki static DEFINE_PCI_DEVICE_TABLE(bcma_pci_bridge_tbl) = {
2719594b56dSRafał Miłecki 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x0576) },
27202817be0SHauke Mehrtens 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 43224) },
2738369ae33SRafał Miłecki 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4331) },
2748369ae33SRafał Miłecki 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4353) },
27591fa4b0aSRafał Miłecki 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4357) },
276*646e0827SRafał Miłecki 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4358) },
277c263c2c1SRafał Miłecki 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4359) },
2788369ae33SRafał Miłecki 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4727) },
2798369ae33SRafał Miłecki 	{ 0, },
2808369ae33SRafał Miłecki };
2818369ae33SRafał Miłecki MODULE_DEVICE_TABLE(pci, bcma_pci_bridge_tbl);
2828369ae33SRafał Miłecki 
2838369ae33SRafał Miłecki static struct pci_driver bcma_pci_bridge_driver = {
2848369ae33SRafał Miłecki 	.name = "bcma-pci-bridge",
2858369ae33SRafał Miłecki 	.id_table = bcma_pci_bridge_tbl,
2868369ae33SRafał Miłecki 	.probe = bcma_host_pci_probe,
28716d75faeSNathan Hintz 	.remove = __devexit_p(bcma_host_pci_remove),
2885d2031f2SLinus Torvalds 	.driver.pm = BCMA_PM_OPS,
2898369ae33SRafał Miłecki };
2908369ae33SRafał Miłecki 
2918369ae33SRafał Miłecki int __init bcma_host_pci_init(void)
2928369ae33SRafał Miłecki {
2938369ae33SRafał Miłecki 	return pci_register_driver(&bcma_pci_bridge_driver);
2948369ae33SRafał Miłecki }
2958369ae33SRafał Miłecki 
2968369ae33SRafał Miłecki void __exit bcma_host_pci_exit(void)
2978369ae33SRafał Miłecki {
2988369ae33SRafał Miłecki 	pci_unregister_driver(&bcma_pci_bridge_driver);
2998369ae33SRafał Miłecki }
300