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