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 #include <linux/module.h> 13 14 static void bcma_host_pci_switch_core(struct bcma_device *core) 15 { 16 pci_write_config_dword(core->bus->host_pci, BCMA_PCI_BAR0_WIN, 17 core->addr); 18 pci_write_config_dword(core->bus->host_pci, BCMA_PCI_BAR0_WIN2, 19 core->wrap); 20 core->bus->mapped_core = core; 21 pr_debug("Switched to core: 0x%X\n", core->id.id); 22 } 23 24 static u8 bcma_host_pci_read8(struct bcma_device *core, u16 offset) 25 { 26 if (core->bus->mapped_core != core) 27 bcma_host_pci_switch_core(core); 28 return ioread8(core->bus->mmio + offset); 29 } 30 31 static u16 bcma_host_pci_read16(struct bcma_device *core, u16 offset) 32 { 33 if (core->bus->mapped_core != core) 34 bcma_host_pci_switch_core(core); 35 return ioread16(core->bus->mmio + offset); 36 } 37 38 static u32 bcma_host_pci_read32(struct bcma_device *core, u16 offset) 39 { 40 if (core->bus->mapped_core != core) 41 bcma_host_pci_switch_core(core); 42 return ioread32(core->bus->mmio + offset); 43 } 44 45 static void bcma_host_pci_write8(struct bcma_device *core, u16 offset, 46 u8 value) 47 { 48 if (core->bus->mapped_core != core) 49 bcma_host_pci_switch_core(core); 50 iowrite8(value, core->bus->mmio + offset); 51 } 52 53 static void bcma_host_pci_write16(struct bcma_device *core, u16 offset, 54 u16 value) 55 { 56 if (core->bus->mapped_core != core) 57 bcma_host_pci_switch_core(core); 58 iowrite16(value, core->bus->mmio + offset); 59 } 60 61 static void bcma_host_pci_write32(struct bcma_device *core, u16 offset, 62 u32 value) 63 { 64 if (core->bus->mapped_core != core) 65 bcma_host_pci_switch_core(core); 66 iowrite32(value, core->bus->mmio + offset); 67 } 68 69 #ifdef CONFIG_BCMA_BLOCKIO 70 void bcma_host_pci_block_read(struct bcma_device *core, void *buffer, 71 size_t count, u16 offset, u8 reg_width) 72 { 73 void __iomem *addr = core->bus->mmio + offset; 74 if (core->bus->mapped_core != core) 75 bcma_host_pci_switch_core(core); 76 switch (reg_width) { 77 case sizeof(u8): 78 ioread8_rep(addr, buffer, count); 79 break; 80 case sizeof(u16): 81 WARN_ON(count & 1); 82 ioread16_rep(addr, buffer, count >> 1); 83 break; 84 case sizeof(u32): 85 WARN_ON(count & 3); 86 ioread32_rep(addr, buffer, count >> 2); 87 break; 88 default: 89 WARN_ON(1); 90 } 91 } 92 93 void bcma_host_pci_block_write(struct bcma_device *core, const void *buffer, 94 size_t count, u16 offset, u8 reg_width) 95 { 96 void __iomem *addr = core->bus->mmio + offset; 97 if (core->bus->mapped_core != core) 98 bcma_host_pci_switch_core(core); 99 switch (reg_width) { 100 case sizeof(u8): 101 iowrite8_rep(addr, buffer, count); 102 break; 103 case sizeof(u16): 104 WARN_ON(count & 1); 105 iowrite16_rep(addr, buffer, count >> 1); 106 break; 107 case sizeof(u32): 108 WARN_ON(count & 3); 109 iowrite32_rep(addr, buffer, count >> 2); 110 break; 111 default: 112 WARN_ON(1); 113 } 114 } 115 #endif 116 117 static u32 bcma_host_pci_aread32(struct bcma_device *core, u16 offset) 118 { 119 if (core->bus->mapped_core != core) 120 bcma_host_pci_switch_core(core); 121 return ioread32(core->bus->mmio + (1 * BCMA_CORE_SIZE) + offset); 122 } 123 124 static void bcma_host_pci_awrite32(struct bcma_device *core, u16 offset, 125 u32 value) 126 { 127 if (core->bus->mapped_core != core) 128 bcma_host_pci_switch_core(core); 129 iowrite32(value, core->bus->mmio + (1 * BCMA_CORE_SIZE) + offset); 130 } 131 132 const struct bcma_host_ops bcma_host_pci_ops = { 133 .read8 = bcma_host_pci_read8, 134 .read16 = bcma_host_pci_read16, 135 .read32 = bcma_host_pci_read32, 136 .write8 = bcma_host_pci_write8, 137 .write16 = bcma_host_pci_write16, 138 .write32 = bcma_host_pci_write32, 139 #ifdef CONFIG_BCMA_BLOCKIO 140 .block_read = bcma_host_pci_block_read, 141 .block_write = bcma_host_pci_block_write, 142 #endif 143 .aread32 = bcma_host_pci_aread32, 144 .awrite32 = bcma_host_pci_awrite32, 145 }; 146 147 static int bcma_host_pci_probe(struct pci_dev *dev, 148 const struct pci_device_id *id) 149 { 150 struct bcma_bus *bus; 151 int err = -ENOMEM; 152 const char *name; 153 u32 val; 154 155 /* Alloc */ 156 bus = kzalloc(sizeof(*bus), GFP_KERNEL); 157 if (!bus) 158 goto out; 159 160 /* Basic PCI configuration */ 161 err = pci_enable_device(dev); 162 if (err) 163 goto err_kfree_bus; 164 165 name = dev_name(&dev->dev); 166 if (dev->driver && dev->driver->name) 167 name = dev->driver->name; 168 err = pci_request_regions(dev, name); 169 if (err) 170 goto err_pci_disable; 171 pci_set_master(dev); 172 173 /* Disable the RETRY_TIMEOUT register (0x41) to keep 174 * PCI Tx retries from interfering with C3 CPU state */ 175 pci_read_config_dword(dev, 0x40, &val); 176 if ((val & 0x0000ff00) != 0) 177 pci_write_config_dword(dev, 0x40, val & 0xffff00ff); 178 179 /* SSB needed additional powering up, do we have any AMBA PCI cards? */ 180 if (!pci_is_pcie(dev)) 181 pr_err("PCI card detected, report problems.\n"); 182 183 /* Map MMIO */ 184 err = -ENOMEM; 185 bus->mmio = pci_iomap(dev, 0, ~0UL); 186 if (!bus->mmio) 187 goto err_pci_release_regions; 188 189 /* Host specific */ 190 bus->host_pci = dev; 191 bus->hosttype = BCMA_HOSTTYPE_PCI; 192 bus->ops = &bcma_host_pci_ops; 193 194 /* Register */ 195 err = bcma_bus_register(bus); 196 if (err) 197 goto err_pci_unmap_mmio; 198 199 pci_set_drvdata(dev, bus); 200 201 out: 202 return err; 203 204 err_pci_unmap_mmio: 205 pci_iounmap(dev, bus->mmio); 206 err_pci_release_regions: 207 pci_release_regions(dev); 208 err_pci_disable: 209 pci_disable_device(dev); 210 err_kfree_bus: 211 kfree(bus); 212 return err; 213 } 214 215 static void bcma_host_pci_remove(struct pci_dev *dev) 216 { 217 struct bcma_bus *bus = pci_get_drvdata(dev); 218 219 bcma_bus_unregister(bus); 220 pci_iounmap(dev, bus->mmio); 221 pci_release_regions(dev); 222 pci_disable_device(dev); 223 kfree(bus); 224 pci_set_drvdata(dev, NULL); 225 } 226 227 static DEFINE_PCI_DEVICE_TABLE(bcma_pci_bridge_tbl) = { 228 { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x0576) }, 229 { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4331) }, 230 { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4353) }, 231 { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4357) }, 232 { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4727) }, 233 { 0, }, 234 }; 235 MODULE_DEVICE_TABLE(pci, bcma_pci_bridge_tbl); 236 237 static struct pci_driver bcma_pci_bridge_driver = { 238 .name = "bcma-pci-bridge", 239 .id_table = bcma_pci_bridge_tbl, 240 .probe = bcma_host_pci_probe, 241 .remove = bcma_host_pci_remove, 242 }; 243 244 int __init bcma_host_pci_init(void) 245 { 246 return pci_register_driver(&bcma_pci_bridge_driver); 247 } 248 249 void __exit bcma_host_pci_exit(void) 250 { 251 pci_unregister_driver(&bcma_pci_bridge_driver); 252 } 253