xref: /linux/drivers/bcma/host_pci.c (revision 068df0f34e81bc06c5eb5012ec2eda25624e87aa)
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