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