aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ssb/pci.c
diff options
context:
space:
mode:
authorMichael Buesch <mb@bu3sch.de>2007-09-18 15:12:50 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-10-10 19:51:36 -0400
commit61e115a56d1aafd6e6a8a9fee8ac099a6128ac7b (patch)
treeadd97bf6a1207a4caea3a86cf13495ad3dc477de /drivers/ssb/pci.c
parent5ee3afba88f5a79d0bff07ddd87af45919259f91 (diff)
[SSB]: add Sonics Silicon Backplane bus support
SSB is an SoC bus used in a number of embedded devices. The most well-known of these devices is probably the Linksys WRT54G, but there are others as well. The bus is also used internally on the BCM43xx and BCM44xx devices from Broadcom. This patch also includes support for SSB ID tables in modules, so that SSB drivers can be loaded automatically. Signed-off-by: Michael Buesch <mb@bu3sch.de> Signed-off-by: John W. Linville <linville@tuxdriver.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/ssb/pci.c')
-rw-r--r--drivers/ssb/pci.c740
1 files changed, 740 insertions, 0 deletions
diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c
new file mode 100644
index 000000000000..3d23ca4befe3
--- /dev/null
+++ b/drivers/ssb/pci.c
@@ -0,0 +1,740 @@
1/*
2 * Sonics Silicon Backplane PCI-Hostbus related functions.
3 *
4 * Copyright (C) 2005-2006 Michael Buesch <mb@bu3sch.de>
5 * Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
6 * Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
7 * Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
8 * Copyright (C) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
9 *
10 * Derived from the Broadcom 4400 device driver.
11 * Copyright (C) 2002 David S. Miller (davem@redhat.com)
12 * Fixed by Pekka Pietikainen (pp@ee.oulu.fi)
13 * Copyright (C) 2006 Broadcom Corporation.
14 *
15 * Licensed under the GNU/GPL. See COPYING for details.
16 */
17
18#include <linux/ssb/ssb.h>
19#include <linux/ssb/ssb_regs.h>
20#include <linux/pci.h>
21#include <linux/delay.h>
22
23#include "ssb_private.h"
24
25
26/* Define the following to 1 to enable a printk on each coreswitch. */
27#define SSB_VERBOSE_PCICORESWITCH_DEBUG 0
28
29
30/* Lowlevel coreswitching */
31int ssb_pci_switch_coreidx(struct ssb_bus *bus, u8 coreidx)
32{
33 int err;
34 int attempts = 0;
35 u32 cur_core;
36
37 while (1) {
38 err = pci_write_config_dword(bus->host_pci, SSB_BAR0_WIN,
39 (coreidx * SSB_CORE_SIZE)
40 + SSB_ENUM_BASE);
41 if (err)
42 goto error;
43 err = pci_read_config_dword(bus->host_pci, SSB_BAR0_WIN,
44 &cur_core);
45 if (err)
46 goto error;
47 cur_core = (cur_core - SSB_ENUM_BASE)
48 / SSB_CORE_SIZE;
49 if (cur_core == coreidx)
50 break;
51
52 if (attempts++ > SSB_BAR0_MAX_RETRIES)
53 goto error;
54 udelay(10);
55 }
56 return 0;
57error:
58 ssb_printk(KERN_ERR PFX "Failed to switch to core %u\n", coreidx);
59 return -ENODEV;
60}
61
62int ssb_pci_switch_core(struct ssb_bus *bus,
63 struct ssb_device *dev)
64{
65 int err;
66 unsigned long flags;
67
68#if SSB_VERBOSE_PCICORESWITCH_DEBUG
69 ssb_printk(KERN_INFO PFX
70 "Switching to %s core, index %d\n",
71 ssb_core_name(dev->id.coreid),
72 dev->core_index);
73#endif
74
75 spin_lock_irqsave(&bus->bar_lock, flags);
76 err = ssb_pci_switch_coreidx(bus, dev->core_index);
77 if (!err)
78 bus->mapped_device = dev;
79 spin_unlock_irqrestore(&bus->bar_lock, flags);
80
81 return err;
82}
83
84/* Enable/disable the on board crystal oscillator and/or PLL. */
85int ssb_pci_xtal(struct ssb_bus *bus, u32 what, int turn_on)
86{
87 int err;
88 u32 in, out, outenable;
89 u16 pci_status;
90
91 if (bus->bustype != SSB_BUSTYPE_PCI)
92 return 0;
93
94 err = pci_read_config_dword(bus->host_pci, SSB_GPIO_IN, &in);
95 if (err)
96 goto err_pci;
97 err = pci_read_config_dword(bus->host_pci, SSB_GPIO_OUT, &out);
98 if (err)
99 goto err_pci;
100 err = pci_read_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE, &outenable);
101 if (err)
102 goto err_pci;
103
104 outenable |= what;
105
106 if (turn_on) {
107 /* Avoid glitching the clock if GPRS is already using it.
108 * We can't actually read the state of the PLLPD so we infer it
109 * by the value of XTAL_PU which *is* readable via gpioin.
110 */
111 if (!(in & SSB_GPIO_XTAL)) {
112 if (what & SSB_GPIO_XTAL) {
113 /* Turn the crystal on */
114 out |= SSB_GPIO_XTAL;
115 if (what & SSB_GPIO_PLL)
116 out |= SSB_GPIO_PLL;
117 err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out);
118 if (err)
119 goto err_pci;
120 err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE,
121 outenable);
122 if (err)
123 goto err_pci;
124 msleep(1);
125 }
126 if (what & SSB_GPIO_PLL) {
127 /* Turn the PLL on */
128 out &= ~SSB_GPIO_PLL;
129 err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out);
130 if (err)
131 goto err_pci;
132 msleep(5);
133 }
134 }
135
136 err = pci_read_config_word(bus->host_pci, PCI_STATUS, &pci_status);
137 if (err)
138 goto err_pci;
139 pci_status &= ~PCI_STATUS_SIG_TARGET_ABORT;
140 err = pci_write_config_word(bus->host_pci, PCI_STATUS, pci_status);
141 if (err)
142 goto err_pci;
143 } else {
144 if (what & SSB_GPIO_XTAL) {
145 /* Turn the crystal off */
146 out &= ~SSB_GPIO_XTAL;
147 }
148 if (what & SSB_GPIO_PLL) {
149 /* Turn the PLL off */
150 out |= SSB_GPIO_PLL;
151 }
152 err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out);
153 if (err)
154 goto err_pci;
155 err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE, outenable);
156 if (err)
157 goto err_pci;
158 }
159
160out:
161 return err;
162
163err_pci:
164 printk(KERN_ERR PFX "Error: ssb_pci_xtal() could not access PCI config space!\n");
165 err = -EBUSY;
166 goto out;
167}
168
169/* Get the word-offset for a SSB_SPROM_XXX define. */
170#define SPOFF(offset) (((offset) - SSB_SPROM_BASE) / sizeof(u16))
171/* Helper to extract some _offset, which is one of the SSB_SPROM_XXX defines. */
172#define SPEX(_outvar, _offset, _mask, _shift) \
173 out->_outvar = ((in[SPOFF(_offset)] & (_mask)) >> (_shift))
174
175static inline u8 ssb_crc8(u8 crc, u8 data)
176{
177 /* Polynomial: x^8 + x^7 + x^6 + x^4 + x^2 + 1 */
178 static const u8 t[] = {
179 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
180 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
181 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
182 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
183 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
184 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
185 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
186 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
187 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
188 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
189 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
190 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
191 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
192 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
193 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
194 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
195 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
196 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
197 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
198 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
199 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
200 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
201 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
202 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
203 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
204 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
205 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
206 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
207 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
208 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
209 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
210 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F,
211 };
212 return t[crc ^ data];
213}
214
215static u8 ssb_sprom_crc(const u16 *sprom)
216{
217 int word;
218 u8 crc = 0xFF;
219
220 for (word = 0; word < SSB_SPROMSIZE_WORDS - 1; word++) {
221 crc = ssb_crc8(crc, sprom[word] & 0x00FF);
222 crc = ssb_crc8(crc, (sprom[word] & 0xFF00) >> 8);
223 }
224 crc = ssb_crc8(crc, sprom[SPOFF(SSB_SPROM_REVISION)] & 0x00FF);
225 crc ^= 0xFF;
226
227 return crc;
228}
229
230static int sprom_check_crc(const u16 *sprom)
231{
232 u8 crc;
233 u8 expected_crc;
234 u16 tmp;
235
236 crc = ssb_sprom_crc(sprom);
237 tmp = sprom[SPOFF(SSB_SPROM_REVISION)] & SSB_SPROM_REVISION_CRC;
238 expected_crc = tmp >> SSB_SPROM_REVISION_CRC_SHIFT;
239 if (crc != expected_crc)
240 return -EPROTO;
241
242 return 0;
243}
244
245static void sprom_do_read(struct ssb_bus *bus, u16 *sprom)
246{
247 int i;
248
249 for (i = 0; i < SSB_SPROMSIZE_WORDS; i++)
250 sprom[i] = readw(bus->mmio + SSB_SPROM_BASE + (i * 2));
251}
252
253static int sprom_do_write(struct ssb_bus *bus, const u16 *sprom)
254{
255 struct pci_dev *pdev = bus->host_pci;
256 int i, err;
257 u32 spromctl;
258
259 ssb_printk(KERN_NOTICE PFX "Writing SPROM. Do NOT turn off the power! Please stand by...\n");
260 err = pci_read_config_dword(pdev, SSB_SPROMCTL, &spromctl);
261 if (err)
262 goto err_ctlreg;
263 spromctl |= SSB_SPROMCTL_WE;
264 err = pci_write_config_dword(pdev, SSB_SPROMCTL, spromctl);
265 if (err)
266 goto err_ctlreg;
267 ssb_printk(KERN_NOTICE PFX "[ 0%%");
268 msleep(500);
269 for (i = 0; i < SSB_SPROMSIZE_WORDS; i++) {
270 if (i == SSB_SPROMSIZE_WORDS / 4)
271 ssb_printk("25%%");
272 else if (i == SSB_SPROMSIZE_WORDS / 2)
273 ssb_printk("50%%");
274 else if (i == (SSB_SPROMSIZE_WORDS / 4) * 3)
275 ssb_printk("75%%");
276 else if (i % 2)
277 ssb_printk(".");
278 writew(sprom[i], bus->mmio + SSB_SPROM_BASE + (i * 2));
279 mmiowb();
280 msleep(20);
281 }
282 err = pci_read_config_dword(pdev, SSB_SPROMCTL, &spromctl);
283 if (err)
284 goto err_ctlreg;
285 spromctl &= ~SSB_SPROMCTL_WE;
286 err = pci_write_config_dword(pdev, SSB_SPROMCTL, spromctl);
287 if (err)
288 goto err_ctlreg;
289 msleep(500);
290 ssb_printk("100%% ]\n");
291 ssb_printk(KERN_NOTICE PFX "SPROM written.\n");
292
293 return 0;
294err_ctlreg:
295 ssb_printk(KERN_ERR PFX "Could not access SPROM control register.\n");
296 return err;
297}
298
299static void sprom_extract_r1(struct ssb_sprom_r1 *out, const u16 *in)
300{
301 int i;
302 u16 v;
303
304 SPEX(pci_spid, SSB_SPROM1_SPID, 0xFFFF, 0);
305 SPEX(pci_svid, SSB_SPROM1_SVID, 0xFFFF, 0);
306 SPEX(pci_pid, SSB_SPROM1_PID, 0xFFFF, 0);
307 for (i = 0; i < 3; i++) {
308 v = in[SPOFF(SSB_SPROM1_IL0MAC) + i];
309 *(((u16 *)out->il0mac) + i) = cpu_to_be16(v);
310 }
311 for (i = 0; i < 3; i++) {
312 v = in[SPOFF(SSB_SPROM1_ET0MAC) + i];
313 *(((u16 *)out->et0mac) + i) = cpu_to_be16(v);
314 }
315 for (i = 0; i < 3; i++) {
316 v = in[SPOFF(SSB_SPROM1_ET1MAC) + i];
317 *(((u16 *)out->et1mac) + i) = cpu_to_be16(v);
318 }
319 SPEX(et0phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0A, 0);
320 SPEX(et1phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1A,
321 SSB_SPROM1_ETHPHY_ET1A_SHIFT);
322 SPEX(et0mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0M, 14);
323 SPEX(et1mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1M, 15);
324 SPEX(board_rev, SSB_SPROM1_BINF, SSB_SPROM1_BINF_BREV, 0);
325 SPEX(country_code, SSB_SPROM1_BINF, SSB_SPROM1_BINF_CCODE,
326 SSB_SPROM1_BINF_CCODE_SHIFT);
327 SPEX(antenna_a, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTA,
328 SSB_SPROM1_BINF_ANTA_SHIFT);
329 SPEX(antenna_bg, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTBG,
330 SSB_SPROM1_BINF_ANTBG_SHIFT);
331 SPEX(pa0b0, SSB_SPROM1_PA0B0, 0xFFFF, 0);
332 SPEX(pa0b1, SSB_SPROM1_PA0B1, 0xFFFF, 0);
333 SPEX(pa0b2, SSB_SPROM1_PA0B2, 0xFFFF, 0);
334 SPEX(pa1b0, SSB_SPROM1_PA1B0, 0xFFFF, 0);
335 SPEX(pa1b1, SSB_SPROM1_PA1B1, 0xFFFF, 0);
336 SPEX(pa1b2, SSB_SPROM1_PA1B2, 0xFFFF, 0);
337 SPEX(gpio0, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P0, 0);
338 SPEX(gpio1, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P1,
339 SSB_SPROM1_GPIOA_P1_SHIFT);
340 SPEX(gpio2, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P2, 0);
341 SPEX(gpio3, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P3,
342 SSB_SPROM1_GPIOB_P3_SHIFT);
343 SPEX(maxpwr_a, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_A,
344 SSB_SPROM1_MAXPWR_A_SHIFT);
345 SPEX(maxpwr_bg, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_BG, 0);
346 SPEX(itssi_a, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_A,
347 SSB_SPROM1_ITSSI_A_SHIFT);
348 SPEX(itssi_bg, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_BG, 0);
349 SPEX(boardflags_lo, SSB_SPROM1_BFLLO, 0xFFFF, 0);
350 SPEX(antenna_gain_a, SSB_SPROM1_AGAIN, SSB_SPROM1_AGAIN_A, 0);
351 SPEX(antenna_gain_bg, SSB_SPROM1_AGAIN, SSB_SPROM1_AGAIN_BG,
352 SSB_SPROM1_AGAIN_BG_SHIFT);
353 for (i = 0; i < 4; i++) {
354 v = in[SPOFF(SSB_SPROM1_OEM) + i];
355 *(((u16 *)out->oem) + i) = cpu_to_le16(v);
356 }
357}
358
359static void sprom_extract_r2(struct ssb_sprom_r2 *out, const u16 *in)
360{
361 int i;
362 u16 v;
363
364 SPEX(boardflags_hi, SSB_SPROM2_BFLHI, 0xFFFF, 0);
365 SPEX(maxpwr_a_hi, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_HI, 0);
366 SPEX(maxpwr_a_lo, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_LO,
367 SSB_SPROM2_MAXP_A_LO_SHIFT);
368 SPEX(pa1lob0, SSB_SPROM2_PA1LOB0, 0xFFFF, 0);
369 SPEX(pa1lob1, SSB_SPROM2_PA1LOB1, 0xFFFF, 0);
370 SPEX(pa1lob2, SSB_SPROM2_PA1LOB2, 0xFFFF, 0);
371 SPEX(pa1hib0, SSB_SPROM2_PA1HIB0, 0xFFFF, 0);
372 SPEX(pa1hib1, SSB_SPROM2_PA1HIB1, 0xFFFF, 0);
373 SPEX(pa1hib2, SSB_SPROM2_PA1HIB2, 0xFFFF, 0);
374 SPEX(ofdm_pwr_off, SSB_SPROM2_OPO, SSB_SPROM2_OPO_VALUE, 0);
375 for (i = 0; i < 4; i++) {
376 v = in[SPOFF(SSB_SPROM2_CCODE) + i];
377 *(((u16 *)out->country_str) + i) = cpu_to_le16(v);
378 }
379}
380
381static void sprom_extract_r3(struct ssb_sprom_r3 *out, const u16 *in)
382{
383 out->ofdmapo = (in[SPOFF(SSB_SPROM3_OFDMAPO) + 0] & 0xFF00) >> 8;
384 out->ofdmapo |= (in[SPOFF(SSB_SPROM3_OFDMAPO) + 0] & 0x00FF) << 8;
385 out->ofdmapo <<= 16;
386 out->ofdmapo |= (in[SPOFF(SSB_SPROM3_OFDMAPO) + 1] & 0xFF00) >> 8;
387 out->ofdmapo |= (in[SPOFF(SSB_SPROM3_OFDMAPO) + 1] & 0x00FF) << 8;
388
389 out->ofdmalpo = (in[SPOFF(SSB_SPROM3_OFDMALPO) + 0] & 0xFF00) >> 8;
390 out->ofdmalpo |= (in[SPOFF(SSB_SPROM3_OFDMALPO) + 0] & 0x00FF) << 8;
391 out->ofdmalpo <<= 16;
392 out->ofdmalpo |= (in[SPOFF(SSB_SPROM3_OFDMALPO) + 1] & 0xFF00) >> 8;
393 out->ofdmalpo |= (in[SPOFF(SSB_SPROM3_OFDMALPO) + 1] & 0x00FF) << 8;
394
395 out->ofdmahpo = (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 0] & 0xFF00) >> 8;
396 out->ofdmahpo |= (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 0] & 0x00FF) << 8;
397 out->ofdmahpo <<= 16;
398 out->ofdmahpo |= (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 1] & 0xFF00) >> 8;
399 out->ofdmahpo |= (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 1] & 0x00FF) << 8;
400
401 SPEX(gpioldc_on_cnt, SSB_SPROM3_GPIOLDC, SSB_SPROM3_GPIOLDC_ON,
402 SSB_SPROM3_GPIOLDC_ON_SHIFT);
403 SPEX(gpioldc_off_cnt, SSB_SPROM3_GPIOLDC, SSB_SPROM3_GPIOLDC_OFF,
404 SSB_SPROM3_GPIOLDC_OFF_SHIFT);
405 SPEX(cckpo_1M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_1M, 0);
406 SPEX(cckpo_2M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_2M,
407 SSB_SPROM3_CCKPO_2M_SHIFT);
408 SPEX(cckpo_55M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_55M,
409 SSB_SPROM3_CCKPO_55M_SHIFT);
410 SPEX(cckpo_11M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_11M,
411 SSB_SPROM3_CCKPO_11M_SHIFT);
412
413 out->ofdmgpo = (in[SPOFF(SSB_SPROM3_OFDMGPO) + 0] & 0xFF00) >> 8;
414 out->ofdmgpo |= (in[SPOFF(SSB_SPROM3_OFDMGPO) + 0] & 0x00FF) << 8;
415 out->ofdmgpo <<= 16;
416 out->ofdmgpo |= (in[SPOFF(SSB_SPROM3_OFDMGPO) + 1] & 0xFF00) >> 8;
417 out->ofdmgpo |= (in[SPOFF(SSB_SPROM3_OFDMGPO) + 1] & 0x00FF) << 8;
418}
419
420static int sprom_extract(struct ssb_bus *bus,
421 struct ssb_sprom *out, const u16 *in)
422{
423 memset(out, 0, sizeof(*out));
424
425 SPEX(revision, SSB_SPROM_REVISION, SSB_SPROM_REVISION_REV, 0);
426 SPEX(crc, SSB_SPROM_REVISION, SSB_SPROM_REVISION_CRC,
427 SSB_SPROM_REVISION_CRC_SHIFT);
428
429 if ((bus->chip_id & 0xFF00) == 0x4400) {
430 /* Workaround: The BCM44XX chip has a stupid revision
431 * number stored in the SPROM.
432 * Always extract r1. */
433 sprom_extract_r1(&out->r1, in);
434 } else {
435 if (out->revision == 0)
436 goto unsupported;
437 if (out->revision >= 1 && out->revision <= 3)
438 sprom_extract_r1(&out->r1, in);
439 if (out->revision >= 2 && out->revision <= 3)
440 sprom_extract_r2(&out->r2, in);
441 if (out->revision == 3)
442 sprom_extract_r3(&out->r3, in);
443 if (out->revision >= 4)
444 goto unsupported;
445 }
446
447 return 0;
448unsupported:
449 ssb_printk(KERN_WARNING PFX "Unsupported SPROM revision %d "
450 "detected. Will extract v1\n", out->revision);
451 sprom_extract_r1(&out->r1, in);
452 return 0;
453}
454
455static int ssb_pci_sprom_get(struct ssb_bus *bus,
456 struct ssb_sprom *sprom)
457{
458 int err = -ENOMEM;
459 u16 *buf;
460
461 buf = kcalloc(SSB_SPROMSIZE_WORDS, sizeof(u16), GFP_KERNEL);
462 if (!buf)
463 goto out;
464 sprom_do_read(bus, buf);
465 err = sprom_check_crc(buf);
466 if (err) {
467 ssb_printk(KERN_WARNING PFX
468 "WARNING: Invalid SPROM CRC (corrupt SPROM)\n");
469 }
470 err = sprom_extract(bus, sprom, buf);
471
472 kfree(buf);
473out:
474 return err;
475}
476
477static void ssb_pci_get_boardinfo(struct ssb_bus *bus,
478 struct ssb_boardinfo *bi)
479{
480 pci_read_config_word(bus->host_pci, PCI_SUBSYSTEM_VENDOR_ID,
481 &bi->vendor);
482 pci_read_config_word(bus->host_pci, PCI_SUBSYSTEM_ID,
483 &bi->type);
484 pci_read_config_word(bus->host_pci, PCI_REVISION_ID,
485 &bi->rev);
486}
487
488int ssb_pci_get_invariants(struct ssb_bus *bus,
489 struct ssb_init_invariants *iv)
490{
491 int err;
492
493 err = ssb_pci_sprom_get(bus, &iv->sprom);
494 if (err)
495 goto out;
496 ssb_pci_get_boardinfo(bus, &iv->boardinfo);
497
498out:
499 return err;
500}
501
502#ifdef CONFIG_SSB_DEBUG
503static int ssb_pci_assert_buspower(struct ssb_bus *bus)
504{
505 if (likely(bus->powered_up))
506 return 0;
507
508 printk(KERN_ERR PFX "FATAL ERROR: Bus powered down "
509 "while accessing PCI MMIO space\n");
510 if (bus->power_warn_count <= 10) {
511 bus->power_warn_count++;
512 dump_stack();
513 }
514
515 return -ENODEV;
516}
517#else /* DEBUG */
518static inline int ssb_pci_assert_buspower(struct ssb_bus *bus)
519{
520 return 0;
521}
522#endif /* DEBUG */
523
524static u16 ssb_pci_read16(struct ssb_device *dev, u16 offset)
525{
526 struct ssb_bus *bus = dev->bus;
527
528 if (unlikely(ssb_pci_assert_buspower(bus)))
529 return 0xFFFF;
530 if (unlikely(bus->mapped_device != dev)) {
531 if (unlikely(ssb_pci_switch_core(bus, dev)))
532 return 0xFFFF;
533 }
534 return readw(bus->mmio + offset);
535}
536
537static u32 ssb_pci_read32(struct ssb_device *dev, u16 offset)
538{
539 struct ssb_bus *bus = dev->bus;
540
541 if (unlikely(ssb_pci_assert_buspower(bus)))
542 return 0xFFFFFFFF;
543 if (unlikely(bus->mapped_device != dev)) {
544 if (unlikely(ssb_pci_switch_core(bus, dev)))
545 return 0xFFFFFFFF;
546 }
547 return readl(bus->mmio + offset);
548}
549
550static void ssb_pci_write16(struct ssb_device *dev, u16 offset, u16 value)
551{
552 struct ssb_bus *bus = dev->bus;
553
554 if (unlikely(ssb_pci_assert_buspower(bus)))
555 return;
556 if (unlikely(bus->mapped_device != dev)) {
557 if (unlikely(ssb_pci_switch_core(bus, dev)))
558 return;
559 }
560 writew(value, bus->mmio + offset);
561}
562
563static void ssb_pci_write32(struct ssb_device *dev, u16 offset, u32 value)
564{
565 struct ssb_bus *bus = dev->bus;
566
567 if (unlikely(ssb_pci_assert_buspower(bus)))
568 return;
569 if (unlikely(bus->mapped_device != dev)) {
570 if (unlikely(ssb_pci_switch_core(bus, dev)))
571 return;
572 }
573 writel(value, bus->mmio + offset);
574}
575
576/* Not "static", as it's used in main.c */
577const struct ssb_bus_ops ssb_pci_ops = {
578 .read16 = ssb_pci_read16,
579 .read32 = ssb_pci_read32,
580 .write16 = ssb_pci_write16,
581 .write32 = ssb_pci_write32,
582};
583
584static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len)
585{
586 int i, pos = 0;
587
588 for (i = 0; i < SSB_SPROMSIZE_WORDS; i++) {
589 pos += snprintf(buf + pos, buf_len - pos - 1,
590 "%04X", swab16(sprom[i]) & 0xFFFF);
591 }
592 pos += snprintf(buf + pos, buf_len - pos - 1, "\n");
593
594 return pos + 1;
595}
596
597static int hex2sprom(u16 *sprom, const char *dump, size_t len)
598{
599 char tmp[5] = { 0 };
600 int cnt = 0;
601 unsigned long parsed;
602
603 if (len < SSB_SPROMSIZE_BYTES * 2)
604 return -EINVAL;
605
606 while (cnt < SSB_SPROMSIZE_WORDS) {
607 memcpy(tmp, dump, 4);
608 dump += 4;
609 parsed = simple_strtoul(tmp, NULL, 16);
610 sprom[cnt++] = swab16((u16)parsed);
611 }
612
613 return 0;
614}
615
616static ssize_t ssb_pci_attr_sprom_show(struct device *pcidev,
617 struct device_attribute *attr,
618 char *buf)
619{
620 struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev);
621 struct ssb_bus *bus;
622 u16 *sprom;
623 int err = -ENODEV;
624 ssize_t count = 0;
625
626 bus = ssb_pci_dev_to_bus(pdev);
627 if (!bus)
628 goto out;
629 err = -ENOMEM;
630 sprom = kcalloc(SSB_SPROMSIZE_WORDS, sizeof(u16), GFP_KERNEL);
631 if (!sprom)
632 goto out;
633
634 /* Use interruptible locking, as the SPROM write might
635 * be holding the lock for several seconds. So allow userspace
636 * to cancel operation. */
637 err = -ERESTARTSYS;
638 if (mutex_lock_interruptible(&bus->pci_sprom_mutex))
639 goto out_kfree;
640 sprom_do_read(bus, sprom);
641 mutex_unlock(&bus->pci_sprom_mutex);
642
643 count = sprom2hex(sprom, buf, PAGE_SIZE);
644 err = 0;
645
646out_kfree:
647 kfree(sprom);
648out:
649 return err ? err : count;
650}
651
652static ssize_t ssb_pci_attr_sprom_store(struct device *pcidev,
653 struct device_attribute *attr,
654 const char *buf, size_t count)
655{
656 struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev);
657 struct ssb_bus *bus;
658 u16 *sprom;
659 int res = 0, err = -ENODEV;
660
661 bus = ssb_pci_dev_to_bus(pdev);
662 if (!bus)
663 goto out;
664 err = -ENOMEM;
665 sprom = kcalloc(SSB_SPROMSIZE_WORDS, sizeof(u16), GFP_KERNEL);
666 if (!sprom)
667 goto out;
668 err = hex2sprom(sprom, buf, count);
669 if (err) {
670 err = -EINVAL;
671 goto out_kfree;
672 }
673 err = sprom_check_crc(sprom);
674 if (err) {
675 err = -EINVAL;
676 goto out_kfree;
677 }
678
679 /* Use interruptible locking, as the SPROM write might
680 * be holding the lock for several seconds. So allow userspace
681 * to cancel operation. */
682 err = -ERESTARTSYS;
683 if (mutex_lock_interruptible(&bus->pci_sprom_mutex))
684 goto out_kfree;
685 err = ssb_devices_freeze(bus);
686 if (err == -EOPNOTSUPP) {
687 ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze devices. "
688 "No suspend support. Is CONFIG_PM enabled?\n");
689 goto out_unlock;
690 }
691 if (err) {
692 ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze all devices\n");
693 goto out_unlock;
694 }
695 res = sprom_do_write(bus, sprom);
696 err = ssb_devices_thaw(bus);
697 if (err)
698 ssb_printk(KERN_ERR PFX "SPROM write: Could not thaw all devices\n");
699out_unlock:
700 mutex_unlock(&bus->pci_sprom_mutex);
701out_kfree:
702 kfree(sprom);
703out:
704 if (res)
705 return res;
706 return err ? err : count;
707}
708
709static DEVICE_ATTR(ssb_sprom, 0600,
710 ssb_pci_attr_sprom_show,
711 ssb_pci_attr_sprom_store);
712
713void ssb_pci_exit(struct ssb_bus *bus)
714{
715 struct pci_dev *pdev;
716
717 if (bus->bustype != SSB_BUSTYPE_PCI)
718 return;
719
720 pdev = bus->host_pci;
721 device_remove_file(&pdev->dev, &dev_attr_ssb_sprom);
722}
723
724int ssb_pci_init(struct ssb_bus *bus)
725{
726 struct pci_dev *pdev;
727 int err;
728
729 if (bus->bustype != SSB_BUSTYPE_PCI)
730 return 0;
731
732 pdev = bus->host_pci;
733 mutex_init(&bus->pci_sprom_mutex);
734 err = device_create_file(&pdev->dev, &dev_attr_ssb_sprom);
735 if (err)
736 goto out;
737
738out:
739 return err;
740}