162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Broadcom specific AMBA
362306a36Sopenharmony_ci * PCI Host
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Licensed under the GNU/GPL. See COPYING for details.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include "bcma_private.h"
962306a36Sopenharmony_ci#include <linux/slab.h>
1062306a36Sopenharmony_ci#include <linux/bcma/bcma.h>
1162306a36Sopenharmony_ci#include <linux/pci.h>
1262306a36Sopenharmony_ci#include <linux/module.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_cistatic void bcma_host_pci_switch_core(struct bcma_device *core)
1562306a36Sopenharmony_ci{
1662306a36Sopenharmony_ci	int win2 = core->bus->host_is_pcie2 ?
1762306a36Sopenharmony_ci		BCMA_PCIE2_BAR0_WIN2 : BCMA_PCI_BAR0_WIN2;
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci	pci_write_config_dword(core->bus->host_pci, BCMA_PCI_BAR0_WIN,
2062306a36Sopenharmony_ci			       core->addr);
2162306a36Sopenharmony_ci	pci_write_config_dword(core->bus->host_pci, win2, core->wrap);
2262306a36Sopenharmony_ci	core->bus->mapped_core = core;
2362306a36Sopenharmony_ci	bcma_debug(core->bus, "Switched to core: 0x%X\n", core->id.id);
2462306a36Sopenharmony_ci}
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci/* Provides access to the requested core. Returns base offset that has to be
2762306a36Sopenharmony_ci * used. It makes use of fixed windows when possible. */
2862306a36Sopenharmony_cistatic u16 bcma_host_pci_provide_access_to_core(struct bcma_device *core)
2962306a36Sopenharmony_ci{
3062306a36Sopenharmony_ci	switch (core->id.id) {
3162306a36Sopenharmony_ci	case BCMA_CORE_CHIPCOMMON:
3262306a36Sopenharmony_ci		return 3 * BCMA_CORE_SIZE;
3362306a36Sopenharmony_ci	case BCMA_CORE_PCIE:
3462306a36Sopenharmony_ci		return 2 * BCMA_CORE_SIZE;
3562306a36Sopenharmony_ci	}
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	if (core->bus->mapped_core != core)
3862306a36Sopenharmony_ci		bcma_host_pci_switch_core(core);
3962306a36Sopenharmony_ci	return 0;
4062306a36Sopenharmony_ci}
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistatic u8 bcma_host_pci_read8(struct bcma_device *core, u16 offset)
4362306a36Sopenharmony_ci{
4462306a36Sopenharmony_ci	offset += bcma_host_pci_provide_access_to_core(core);
4562306a36Sopenharmony_ci	return ioread8(core->bus->mmio + offset);
4662306a36Sopenharmony_ci}
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_cistatic u16 bcma_host_pci_read16(struct bcma_device *core, u16 offset)
4962306a36Sopenharmony_ci{
5062306a36Sopenharmony_ci	offset += bcma_host_pci_provide_access_to_core(core);
5162306a36Sopenharmony_ci	return ioread16(core->bus->mmio + offset);
5262306a36Sopenharmony_ci}
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_cistatic u32 bcma_host_pci_read32(struct bcma_device *core, u16 offset)
5562306a36Sopenharmony_ci{
5662306a36Sopenharmony_ci	offset += bcma_host_pci_provide_access_to_core(core);
5762306a36Sopenharmony_ci	return ioread32(core->bus->mmio + offset);
5862306a36Sopenharmony_ci}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_cistatic void bcma_host_pci_write8(struct bcma_device *core, u16 offset,
6162306a36Sopenharmony_ci				 u8 value)
6262306a36Sopenharmony_ci{
6362306a36Sopenharmony_ci	offset += bcma_host_pci_provide_access_to_core(core);
6462306a36Sopenharmony_ci	iowrite8(value, core->bus->mmio + offset);
6562306a36Sopenharmony_ci}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cistatic void bcma_host_pci_write16(struct bcma_device *core, u16 offset,
6862306a36Sopenharmony_ci				 u16 value)
6962306a36Sopenharmony_ci{
7062306a36Sopenharmony_ci	offset += bcma_host_pci_provide_access_to_core(core);
7162306a36Sopenharmony_ci	iowrite16(value, core->bus->mmio + offset);
7262306a36Sopenharmony_ci}
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_cistatic void bcma_host_pci_write32(struct bcma_device *core, u16 offset,
7562306a36Sopenharmony_ci				 u32 value)
7662306a36Sopenharmony_ci{
7762306a36Sopenharmony_ci	offset += bcma_host_pci_provide_access_to_core(core);
7862306a36Sopenharmony_ci	iowrite32(value, core->bus->mmio + offset);
7962306a36Sopenharmony_ci}
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci#ifdef CONFIG_BCMA_BLOCKIO
8262306a36Sopenharmony_cistatic void bcma_host_pci_block_read(struct bcma_device *core, void *buffer,
8362306a36Sopenharmony_ci				     size_t count, u16 offset, u8 reg_width)
8462306a36Sopenharmony_ci{
8562306a36Sopenharmony_ci	void __iomem *addr = core->bus->mmio + offset;
8662306a36Sopenharmony_ci	if (core->bus->mapped_core != core)
8762306a36Sopenharmony_ci		bcma_host_pci_switch_core(core);
8862306a36Sopenharmony_ci	switch (reg_width) {
8962306a36Sopenharmony_ci	case sizeof(u8):
9062306a36Sopenharmony_ci		ioread8_rep(addr, buffer, count);
9162306a36Sopenharmony_ci		break;
9262306a36Sopenharmony_ci	case sizeof(u16):
9362306a36Sopenharmony_ci		WARN_ON(count & 1);
9462306a36Sopenharmony_ci		ioread16_rep(addr, buffer, count >> 1);
9562306a36Sopenharmony_ci		break;
9662306a36Sopenharmony_ci	case sizeof(u32):
9762306a36Sopenharmony_ci		WARN_ON(count & 3);
9862306a36Sopenharmony_ci		ioread32_rep(addr, buffer, count >> 2);
9962306a36Sopenharmony_ci		break;
10062306a36Sopenharmony_ci	default:
10162306a36Sopenharmony_ci		WARN_ON(1);
10262306a36Sopenharmony_ci	}
10362306a36Sopenharmony_ci}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_cistatic void bcma_host_pci_block_write(struct bcma_device *core,
10662306a36Sopenharmony_ci				      const void *buffer, size_t count,
10762306a36Sopenharmony_ci				      u16 offset, u8 reg_width)
10862306a36Sopenharmony_ci{
10962306a36Sopenharmony_ci	void __iomem *addr = core->bus->mmio + offset;
11062306a36Sopenharmony_ci	if (core->bus->mapped_core != core)
11162306a36Sopenharmony_ci		bcma_host_pci_switch_core(core);
11262306a36Sopenharmony_ci	switch (reg_width) {
11362306a36Sopenharmony_ci	case sizeof(u8):
11462306a36Sopenharmony_ci		iowrite8_rep(addr, buffer, count);
11562306a36Sopenharmony_ci		break;
11662306a36Sopenharmony_ci	case sizeof(u16):
11762306a36Sopenharmony_ci		WARN_ON(count & 1);
11862306a36Sopenharmony_ci		iowrite16_rep(addr, buffer, count >> 1);
11962306a36Sopenharmony_ci		break;
12062306a36Sopenharmony_ci	case sizeof(u32):
12162306a36Sopenharmony_ci		WARN_ON(count & 3);
12262306a36Sopenharmony_ci		iowrite32_rep(addr, buffer, count >> 2);
12362306a36Sopenharmony_ci		break;
12462306a36Sopenharmony_ci	default:
12562306a36Sopenharmony_ci		WARN_ON(1);
12662306a36Sopenharmony_ci	}
12762306a36Sopenharmony_ci}
12862306a36Sopenharmony_ci#endif
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_cistatic u32 bcma_host_pci_aread32(struct bcma_device *core, u16 offset)
13162306a36Sopenharmony_ci{
13262306a36Sopenharmony_ci	if (core->bus->mapped_core != core)
13362306a36Sopenharmony_ci		bcma_host_pci_switch_core(core);
13462306a36Sopenharmony_ci	return ioread32(core->bus->mmio + (1 * BCMA_CORE_SIZE) + offset);
13562306a36Sopenharmony_ci}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_cistatic void bcma_host_pci_awrite32(struct bcma_device *core, u16 offset,
13862306a36Sopenharmony_ci				  u32 value)
13962306a36Sopenharmony_ci{
14062306a36Sopenharmony_ci	if (core->bus->mapped_core != core)
14162306a36Sopenharmony_ci		bcma_host_pci_switch_core(core);
14262306a36Sopenharmony_ci	iowrite32(value, core->bus->mmio + (1 * BCMA_CORE_SIZE) + offset);
14362306a36Sopenharmony_ci}
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_cistatic const struct bcma_host_ops bcma_host_pci_ops = {
14662306a36Sopenharmony_ci	.read8		= bcma_host_pci_read8,
14762306a36Sopenharmony_ci	.read16		= bcma_host_pci_read16,
14862306a36Sopenharmony_ci	.read32		= bcma_host_pci_read32,
14962306a36Sopenharmony_ci	.write8		= bcma_host_pci_write8,
15062306a36Sopenharmony_ci	.write16	= bcma_host_pci_write16,
15162306a36Sopenharmony_ci	.write32	= bcma_host_pci_write32,
15262306a36Sopenharmony_ci#ifdef CONFIG_BCMA_BLOCKIO
15362306a36Sopenharmony_ci	.block_read	= bcma_host_pci_block_read,
15462306a36Sopenharmony_ci	.block_write	= bcma_host_pci_block_write,
15562306a36Sopenharmony_ci#endif
15662306a36Sopenharmony_ci	.aread32	= bcma_host_pci_aread32,
15762306a36Sopenharmony_ci	.awrite32	= bcma_host_pci_awrite32,
15862306a36Sopenharmony_ci};
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_cistatic int bcma_host_pci_probe(struct pci_dev *dev,
16162306a36Sopenharmony_ci			       const struct pci_device_id *id)
16262306a36Sopenharmony_ci{
16362306a36Sopenharmony_ci	struct bcma_bus *bus;
16462306a36Sopenharmony_ci	int err = -ENOMEM;
16562306a36Sopenharmony_ci	u32 val;
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	/* Alloc */
16862306a36Sopenharmony_ci	bus = kzalloc(sizeof(*bus), GFP_KERNEL);
16962306a36Sopenharmony_ci	if (!bus)
17062306a36Sopenharmony_ci		goto out;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	/* Basic PCI configuration */
17362306a36Sopenharmony_ci	err = pci_enable_device(dev);
17462306a36Sopenharmony_ci	if (err)
17562306a36Sopenharmony_ci		goto err_kfree_bus;
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	err = pci_request_regions(dev, "bcma-pci-bridge");
17862306a36Sopenharmony_ci	if (err)
17962306a36Sopenharmony_ci		goto err_pci_disable;
18062306a36Sopenharmony_ci	pci_set_master(dev);
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	/* Disable the RETRY_TIMEOUT register (0x41) to keep
18362306a36Sopenharmony_ci	 * PCI Tx retries from interfering with C3 CPU state */
18462306a36Sopenharmony_ci	pci_read_config_dword(dev, 0x40, &val);
18562306a36Sopenharmony_ci	if ((val & 0x0000ff00) != 0)
18662306a36Sopenharmony_ci		pci_write_config_dword(dev, 0x40, val & 0xffff00ff);
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	/* SSB needed additional powering up, do we have any AMBA PCI cards? */
18962306a36Sopenharmony_ci	if (!pci_is_pcie(dev)) {
19062306a36Sopenharmony_ci		bcma_err(bus, "PCI card detected, they are not supported.\n");
19162306a36Sopenharmony_ci		err = -ENXIO;
19262306a36Sopenharmony_ci		goto err_pci_release_regions;
19362306a36Sopenharmony_ci	}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	bus->dev = &dev->dev;
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	/* Map MMIO */
19862306a36Sopenharmony_ci	err = -ENOMEM;
19962306a36Sopenharmony_ci	bus->mmio = pci_iomap(dev, 0, ~0UL);
20062306a36Sopenharmony_ci	if (!bus->mmio)
20162306a36Sopenharmony_ci		goto err_pci_release_regions;
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	/* Host specific */
20462306a36Sopenharmony_ci	bus->host_pci = dev;
20562306a36Sopenharmony_ci	bus->hosttype = BCMA_HOSTTYPE_PCI;
20662306a36Sopenharmony_ci	bus->ops = &bcma_host_pci_ops;
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	bus->boardinfo.vendor = bus->host_pci->subsystem_vendor;
20962306a36Sopenharmony_ci	bus->boardinfo.type = bus->host_pci->subsystem_device;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	/* Initialize struct, detect chip */
21262306a36Sopenharmony_ci	bcma_init_bus(bus);
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	/* Scan bus to find out generation of PCIe core */
21562306a36Sopenharmony_ci	err = bcma_bus_scan(bus);
21662306a36Sopenharmony_ci	if (err)
21762306a36Sopenharmony_ci		goto err_pci_unmap_mmio;
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	if (bcma_find_core(bus, BCMA_CORE_PCIE2))
22062306a36Sopenharmony_ci		bus->host_is_pcie2 = true;
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	/* Register */
22362306a36Sopenharmony_ci	err = bcma_bus_register(bus);
22462306a36Sopenharmony_ci	if (err)
22562306a36Sopenharmony_ci		goto err_unregister_cores;
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	pci_set_drvdata(dev, bus);
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ciout:
23062306a36Sopenharmony_ci	return err;
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_cierr_unregister_cores:
23362306a36Sopenharmony_ci	bcma_unregister_cores(bus);
23462306a36Sopenharmony_cierr_pci_unmap_mmio:
23562306a36Sopenharmony_ci	pci_iounmap(dev, bus->mmio);
23662306a36Sopenharmony_cierr_pci_release_regions:
23762306a36Sopenharmony_ci	pci_release_regions(dev);
23862306a36Sopenharmony_cierr_pci_disable:
23962306a36Sopenharmony_ci	pci_disable_device(dev);
24062306a36Sopenharmony_cierr_kfree_bus:
24162306a36Sopenharmony_ci	kfree(bus);
24262306a36Sopenharmony_ci	return err;
24362306a36Sopenharmony_ci}
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_cistatic void bcma_host_pci_remove(struct pci_dev *dev)
24662306a36Sopenharmony_ci{
24762306a36Sopenharmony_ci	struct bcma_bus *bus = pci_get_drvdata(dev);
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	bcma_bus_unregister(bus);
25062306a36Sopenharmony_ci	pci_iounmap(dev, bus->mmio);
25162306a36Sopenharmony_ci	pci_release_regions(dev);
25262306a36Sopenharmony_ci	pci_disable_device(dev);
25362306a36Sopenharmony_ci	kfree(bus);
25462306a36Sopenharmony_ci}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
25762306a36Sopenharmony_cistatic int bcma_host_pci_suspend(struct device *dev)
25862306a36Sopenharmony_ci{
25962306a36Sopenharmony_ci	struct bcma_bus *bus = dev_get_drvdata(dev);
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	bus->mapped_core = NULL;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	return bcma_bus_suspend(bus);
26462306a36Sopenharmony_ci}
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_cistatic int bcma_host_pci_resume(struct device *dev)
26762306a36Sopenharmony_ci{
26862306a36Sopenharmony_ci	struct bcma_bus *bus = dev_get_drvdata(dev);
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	return bcma_bus_resume(bus);
27162306a36Sopenharmony_ci}
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(bcma_pm_ops, bcma_host_pci_suspend,
27462306a36Sopenharmony_ci			 bcma_host_pci_resume);
27562306a36Sopenharmony_ci#define BCMA_PM_OPS	(&bcma_pm_ops)
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci#else /* CONFIG_PM_SLEEP */
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci#define BCMA_PM_OPS     NULL
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci#endif /* CONFIG_PM_SLEEP */
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_cistatic const struct pci_device_id bcma_pci_bridge_tbl[] = {
28462306a36Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x0576) },
28562306a36Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4313) },
28662306a36Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 43224) },	/* 0xa8d8 */
28762306a36Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4331) },
28862306a36Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4353) },
28962306a36Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4357) },
29062306a36Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4358) },
29162306a36Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4359) },
29262306a36Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4360) },
29362306a36Sopenharmony_ci	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_BROADCOM, 0x4365, PCI_VENDOR_ID_DELL, 0x0016) },
29462306a36Sopenharmony_ci	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_BROADCOM, 0x4365, PCI_VENDOR_ID_DELL, 0x0018) },
29562306a36Sopenharmony_ci	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_BROADCOM, 0x4365, PCI_VENDOR_ID_FOXCONN, 0xe092) },
29662306a36Sopenharmony_ci	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_BROADCOM, 0x4365, PCI_VENDOR_ID_HP, 0x804a) },
29762306a36Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43a0) },
29862306a36Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43a9) },
29962306a36Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43aa) },
30062306a36Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43b1) },
30162306a36Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4727) },
30262306a36Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 43227) },	/* 0xa8db, BCM43217 (sic!) */
30362306a36Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 43228) },	/* 0xa8dc */
30462306a36Sopenharmony_ci	{ 0, },
30562306a36Sopenharmony_ci};
30662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, bcma_pci_bridge_tbl);
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_cistatic struct pci_driver bcma_pci_bridge_driver = {
30962306a36Sopenharmony_ci	.name = "bcma-pci-bridge",
31062306a36Sopenharmony_ci	.id_table = bcma_pci_bridge_tbl,
31162306a36Sopenharmony_ci	.probe = bcma_host_pci_probe,
31262306a36Sopenharmony_ci	.remove = bcma_host_pci_remove,
31362306a36Sopenharmony_ci	.driver.pm = BCMA_PM_OPS,
31462306a36Sopenharmony_ci};
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ciint __init bcma_host_pci_init(void)
31762306a36Sopenharmony_ci{
31862306a36Sopenharmony_ci	return pci_register_driver(&bcma_pci_bridge_driver);
31962306a36Sopenharmony_ci}
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_civoid __exit bcma_host_pci_exit(void)
32262306a36Sopenharmony_ci{
32362306a36Sopenharmony_ci	pci_unregister_driver(&bcma_pci_bridge_driver);
32462306a36Sopenharmony_ci}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci/**************************************************
32762306a36Sopenharmony_ci * Runtime ops for drivers.
32862306a36Sopenharmony_ci **************************************************/
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci/* See also pcicore_up */
33162306a36Sopenharmony_civoid bcma_host_pci_up(struct bcma_bus *bus)
33262306a36Sopenharmony_ci{
33362306a36Sopenharmony_ci	if (bus->hosttype != BCMA_HOSTTYPE_PCI)
33462306a36Sopenharmony_ci		return;
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	if (bus->host_is_pcie2)
33762306a36Sopenharmony_ci		bcma_core_pcie2_up(&bus->drv_pcie2);
33862306a36Sopenharmony_ci	else
33962306a36Sopenharmony_ci		bcma_core_pci_up(&bus->drv_pci[0]);
34062306a36Sopenharmony_ci}
34162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(bcma_host_pci_up);
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci/* See also pcicore_down */
34462306a36Sopenharmony_civoid bcma_host_pci_down(struct bcma_bus *bus)
34562306a36Sopenharmony_ci{
34662306a36Sopenharmony_ci	if (bus->hosttype != BCMA_HOSTTYPE_PCI)
34762306a36Sopenharmony_ci		return;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	if (!bus->host_is_pcie2)
35062306a36Sopenharmony_ci		bcma_core_pci_down(&bus->drv_pci[0]);
35162306a36Sopenharmony_ci}
35262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(bcma_host_pci_down);
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci/* See also si_pci_setup */
35562306a36Sopenharmony_ciint bcma_host_pci_irq_ctl(struct bcma_bus *bus, struct bcma_device *core,
35662306a36Sopenharmony_ci			  bool enable)
35762306a36Sopenharmony_ci{
35862306a36Sopenharmony_ci	struct pci_dev *pdev;
35962306a36Sopenharmony_ci	u32 coremask, tmp;
36062306a36Sopenharmony_ci	int err = 0;
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	if (bus->hosttype != BCMA_HOSTTYPE_PCI) {
36362306a36Sopenharmony_ci		/* This bcma device is not on a PCI host-bus. So the IRQs are
36462306a36Sopenharmony_ci		 * not routed through the PCI core.
36562306a36Sopenharmony_ci		 * So we must not enable routing through the PCI core. */
36662306a36Sopenharmony_ci		goto out;
36762306a36Sopenharmony_ci	}
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	pdev = bus->host_pci;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	err = pci_read_config_dword(pdev, BCMA_PCI_IRQMASK, &tmp);
37262306a36Sopenharmony_ci	if (err)
37362306a36Sopenharmony_ci		goto out;
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	coremask = BIT(core->core_index) << 8;
37662306a36Sopenharmony_ci	if (enable)
37762306a36Sopenharmony_ci		tmp |= coremask;
37862306a36Sopenharmony_ci	else
37962306a36Sopenharmony_ci		tmp &= ~coremask;
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	err = pci_write_config_dword(pdev, BCMA_PCI_IRQMASK, tmp);
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ciout:
38462306a36Sopenharmony_ci	return err;
38562306a36Sopenharmony_ci}
38662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(bcma_host_pci_irq_ctl);
387