1 /* 2 * Broadcom specific AMBA 3 * PCI Host 4 * 5 * Licensed under the GNU/GPL. See COPYING for details. 6 */ 7 8 #include "bcma_private.h" 9 #include <linux/slab.h> 10 #include <linux/bcma/bcma.h> 11 #include <linux/pci.h> 12 13 static void bcma_host_pci_switch_core(struct bcma_device *core) 14 { 15 pci_write_config_dword(core->bus->host_pci, BCMA_PCI_BAR0_WIN, 16 core->addr); 17 pci_write_config_dword(core->bus->host_pci, BCMA_PCI_BAR0_WIN2, 18 core->wrap); 19 core->bus->mapped_core = core; 20 pr_debug("Switched to core: 0x%X\n", core->id.id); 21 } 22 23 static u8 bcma_host_pci_read8(struct bcma_device *core, u16 offset) 24 { 25 if (core->bus->mapped_core != core) 26 bcma_host_pci_switch_core(core); 27 return ioread8(core->bus->mmio + offset); 28 } 29 30 static u16 bcma_host_pci_read16(struct bcma_device *core, u16 offset) 31 { 32 if (core->bus->mapped_core != core) 33 bcma_host_pci_switch_core(core); 34 return ioread16(core->bus->mmio + offset); 35 } 36 37 static u32 bcma_host_pci_read32(struct bcma_device *core, u16 offset) 38 { 39 if (core->bus->mapped_core != core) 40 bcma_host_pci_switch_core(core); 41 return ioread32(core->bus->mmio + offset); 42 } 43 44 static void bcma_host_pci_write8(struct bcma_device *core, u16 offset, 45 u8 value) 46 { 47 if (core->bus->mapped_core != core) 48 bcma_host_pci_switch_core(core); 49 iowrite8(value, core->bus->mmio + offset); 50 } 51 52 static void bcma_host_pci_write16(struct bcma_device *core, u16 offset, 53 u16 value) 54 { 55 if (core->bus->mapped_core != core) 56 bcma_host_pci_switch_core(core); 57 iowrite16(value, core->bus->mmio + offset); 58 } 59 60 static void bcma_host_pci_write32(struct bcma_device *core, u16 offset, 61 u32 value) 62 { 63 if (core->bus->mapped_core != core) 64 bcma_host_pci_switch_core(core); 65 iowrite32(value, core->bus->mmio + offset); 66 } 67 68 static u32 bcma_host_pci_aread32(struct bcma_device *core, u16 offset) 69 { 70 if (core->bus->mapped_core != core) 71 bcma_host_pci_switch_core(core); 72 return ioread32(core->bus->mmio + (1 * BCMA_CORE_SIZE) + offset); 73 } 74 75 static void bcma_host_pci_awrite32(struct bcma_device *core, u16 offset, 76 u32 value) 77 { 78 if (core->bus->mapped_core != core) 79 bcma_host_pci_switch_core(core); 80 iowrite32(value, core->bus->mmio + (1 * BCMA_CORE_SIZE) + offset); 81 } 82 83 const struct bcma_host_ops bcma_host_pci_ops = { 84 .read8 = bcma_host_pci_read8, 85 .read16 = bcma_host_pci_read16, 86 .read32 = bcma_host_pci_read32, 87 .write8 = bcma_host_pci_write8, 88 .write16 = bcma_host_pci_write16, 89 .write32 = bcma_host_pci_write32, 90 .aread32 = bcma_host_pci_aread32, 91 .awrite32 = bcma_host_pci_awrite32, 92 }; 93 94 static int bcma_host_pci_probe(struct pci_dev *dev, 95 const struct pci_device_id *id) 96 { 97 struct bcma_bus *bus; 98 int err = -ENOMEM; 99 const char *name; 100 u32 val; 101 102 /* Alloc */ 103 bus = kzalloc(sizeof(*bus), GFP_KERNEL); 104 if (!bus) 105 goto out; 106 107 /* Basic PCI configuration */ 108 err = pci_enable_device(dev); 109 if (err) 110 goto err_kfree_bus; 111 112 name = dev_name(&dev->dev); 113 if (dev->driver && dev->driver->name) 114 name = dev->driver->name; 115 err = pci_request_regions(dev, name); 116 if (err) 117 goto err_pci_disable; 118 pci_set_master(dev); 119 120 /* Disable the RETRY_TIMEOUT register (0x41) to keep 121 * PCI Tx retries from interfering with C3 CPU state */ 122 pci_read_config_dword(dev, 0x40, &val); 123 if ((val & 0x0000ff00) != 0) 124 pci_write_config_dword(dev, 0x40, val & 0xffff00ff); 125 126 /* SSB needed additional powering up, do we have any AMBA PCI cards? */ 127 if (!pci_is_pcie(dev)) 128 pr_err("PCI card detected, report problems.\n"); 129 130 /* Map MMIO */ 131 err = -ENOMEM; 132 bus->mmio = pci_iomap(dev, 0, ~0UL); 133 if (!bus->mmio) 134 goto err_pci_release_regions; 135 136 /* Host specific */ 137 bus->host_pci = dev; 138 bus->hosttype = BCMA_HOSTTYPE_PCI; 139 bus->ops = &bcma_host_pci_ops; 140 141 /* Register */ 142 err = bcma_bus_register(bus); 143 if (err) 144 goto err_pci_unmap_mmio; 145 146 pci_set_drvdata(dev, bus); 147 148 out: 149 return err; 150 151 err_pci_unmap_mmio: 152 pci_iounmap(dev, bus->mmio); 153 err_pci_release_regions: 154 pci_release_regions(dev); 155 err_pci_disable: 156 pci_disable_device(dev); 157 err_kfree_bus: 158 kfree(bus); 159 return err; 160 } 161 162 static void bcma_host_pci_remove(struct pci_dev *dev) 163 { 164 struct bcma_bus *bus = pci_get_drvdata(dev); 165 166 bcma_bus_unregister(bus); 167 pci_iounmap(dev, bus->mmio); 168 pci_release_regions(dev); 169 pci_disable_device(dev); 170 kfree(bus); 171 pci_set_drvdata(dev, NULL); 172 } 173 174 static DEFINE_PCI_DEVICE_TABLE(bcma_pci_bridge_tbl) = { 175 { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x0576) }, 176 { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4331) }, 177 { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4353) }, 178 { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4727) }, 179 { 0, }, 180 }; 181 MODULE_DEVICE_TABLE(pci, bcma_pci_bridge_tbl); 182 183 static struct pci_driver bcma_pci_bridge_driver = { 184 .name = "bcma-pci-bridge", 185 .id_table = bcma_pci_bridge_tbl, 186 .probe = bcma_host_pci_probe, 187 .remove = bcma_host_pci_remove, 188 }; 189 190 int __init bcma_host_pci_init(void) 191 { 192 return pci_register_driver(&bcma_pci_bridge_driver); 193 } 194 195 void __exit bcma_host_pci_exit(void) 196 { 197 pci_unregister_driver(&bcma_pci_bridge_driver); 198 } 199