blob: 1b51d8b7ac8024698bc9b053322a2b82ddbe47ab [file] [log] [blame]
Rafał Miłecki8369ae32011-05-09 18:56:46 +02001/*
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"
Andrew Mortonba7328b2011-05-26 16:24:57 -07009#include <linux/slab.h>
Rafał Miłecki8369ae32011-05-09 18:56:46 +020010#include <linux/bcma/bcma.h>
11#include <linux/pci.h>
Paul Gortmaker200351c2011-07-01 16:06:37 -040012#include <linux/module.h>
Rafał Miłecki8369ae32011-05-09 18:56:46 +020013
14static 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
24static 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
31static 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
38static 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
45static 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
53static 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
61static 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
Rafał Miłecki9d75ef02011-05-20 03:27:06 +020069#ifdef CONFIG_BCMA_BLOCKIO
70void 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
93void 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
Rafał Miłecki8369ae32011-05-09 18:56:46 +0200117static 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
124static 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
132const 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,
Rafał Miłecki9d75ef02011-05-20 03:27:06 +0200139#ifdef CONFIG_BCMA_BLOCKIO
140 .block_read = bcma_host_pci_block_read,
141 .block_write = bcma_host_pci_block_write,
142#endif
Rafał Miłecki8369ae32011-05-09 18:56:46 +0200143 .aread32 = bcma_host_pci_aread32,
144 .awrite32 = bcma_host_pci_awrite32,
145};
146
147static 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
201out:
202 return err;
203
204err_pci_unmap_mmio:
205 pci_iounmap(dev, bus->mmio);
206err_pci_release_regions:
207 pci_release_regions(dev);
208err_pci_disable:
209 pci_disable_device(dev);
210err_kfree_bus:
211 kfree(bus);
212 return err;
213}
214
215static 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
227static DEFINE_PCI_DEVICE_TABLE(bcma_pci_bridge_tbl) = {
Rafał Miłecki9594b562011-05-14 10:31:46 +0200228 { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x0576) },
Rafał Miłecki8369ae32011-05-09 18:56:46 +0200229 { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4331) },
230 { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4353) },
Rafał Miłecki91fa4b02011-06-17 13:15:23 +0200231 { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4357) },
Rafał Miłecki8369ae32011-05-09 18:56:46 +0200232 { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4727) },
233 { 0, },
234};
235MODULE_DEVICE_TABLE(pci, bcma_pci_bridge_tbl);
236
237static 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
244int __init bcma_host_pci_init(void)
245{
246 return pci_register_driver(&bcma_pci_bridge_driver);
247}
248
249void __exit bcma_host_pci_exit(void)
250{
251 pci_unregister_driver(&bcma_pci_bridge_driver);
252}