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