1/*
2 * Sonics Silicon Backplane PCI-Hostbus related functions.
3 *
4 * Copyright (C) 2005-2006 Michael Buesch <m@bues.ch>
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 "ssb_private.h"
19
20#include <linux/ssb/ssb.h>
21#include <linux/ssb/ssb_regs.h>
22#include <linux/slab.h>
23#include <linux/pci.h>
24#include <linux/delay.h>
25
26
27/* Define the following to 1 to enable a printk on each coreswitch. */
28#define SSB_VERBOSE_PCICORESWITCH_DEBUG 0
29
30
31/* Lowlevel coreswitching */
32int ssb_pci_switch_coreidx(struct ssb_bus *bus, u8 coreidx)
33{
34 int err;
35 int attempts = 0;
36 u32 cur_core;
37
38 while (1) {
39 err = pci_write_config_dword(bus->host_pci, SSB_BAR0_WIN,
40 (coreidx * SSB_CORE_SIZE)
41 + SSB_ENUM_BASE);
42 if (err)
43 goto error;
44 err = pci_read_config_dword(bus->host_pci, SSB_BAR0_WIN,
45 &cur_core);
46 if (err)
47 goto error;
48 cur_core = (cur_core - SSB_ENUM_BASE)
49 / SSB_CORE_SIZE;
50 if (cur_core == coreidx)
51 break;
52
53 if (attempts++ > SSB_BAR0_MAX_RETRIES)
54 goto error;
55 udelay(10);
56 }
57 return 0;
58error:
59 pr_err("Failed to switch to core %u\n", coreidx);
60 return -ENODEV;
61}
62
63int ssb_pci_switch_core(struct ssb_bus *bus,
64 struct ssb_device *dev)
65{
66 int err;
67 unsigned long flags;
68
69#if SSB_VERBOSE_PCICORESWITCH_DEBUG
70 pr_info("Switching to %s core, index %d\n",
71 ssb_core_name(dev->id.coreid), dev->core_index);
72#endif
73
74 spin_lock_irqsave(&bus->bar_lock, flags);
75 err = ssb_pci_switch_coreidx(bus, dev->core_index);
76 if (!err)
77 bus->mapped_device = dev;
78 spin_unlock_irqrestore(&bus->bar_lock, flags);
79
80 return err;
81}
82
83/* Enable/disable the on board crystal oscillator and/or PLL. */
84int ssb_pci_xtal(struct ssb_bus *bus, u32 what, int turn_on)
85{
86 int err;
87 u32 in, out, outenable;
88 u16 pci_status;
89
90 if (bus->bustype != SSB_BUSTYPE_PCI)
91 return 0;
92
93 err = pci_read_config_dword(bus->host_pci, SSB_GPIO_IN, &in);
94 if (err)
95 goto err_pci;
96 err = pci_read_config_dword(bus->host_pci, SSB_GPIO_OUT, &out);
97 if (err)
98 goto err_pci;
99 err = pci_read_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE, &outenable);
100 if (err)
101 goto err_pci;
102
103 outenable |= what;
104
105 if (turn_on) {
106 /* Avoid glitching the clock if GPRS is already using it.
107 * We can't actually read the state of the PLLPD so we infer it
108 * by the value of XTAL_PU which *is* readable via gpioin.
109 */
110 if (!(in & SSB_GPIO_XTAL)) {
111 if (what & SSB_GPIO_XTAL) {
112 /* Turn the crystal on */
113 out |= SSB_GPIO_XTAL;
114 if (what & SSB_GPIO_PLL)
115 out |= SSB_GPIO_PLL;
116 err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out);
117 if (err)
118 goto err_pci;
119 err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE,
120 outenable);
121 if (err)
122 goto err_pci;
123 msleep(1);
124 }
125 if (what & SSB_GPIO_PLL) {
126 /* Turn the PLL on */
127 out &= ~SSB_GPIO_PLL;
128 err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out);
129 if (err)
130 goto err_pci;
131 msleep(5);
132 }
133 }
134
135 err = pci_read_config_word(bus->host_pci, PCI_STATUS, &pci_status);
136 if (err)
137 goto err_pci;
138 pci_status &= ~PCI_STATUS_SIG_TARGET_ABORT;
139 err = pci_write_config_word(bus->host_pci, PCI_STATUS, pci_status);
140 if (err)
141 goto err_pci;
142 } else {
143 if (what & SSB_GPIO_XTAL) {
144 /* Turn the crystal off */
145 out &= ~SSB_GPIO_XTAL;
146 }
147 if (what & SSB_GPIO_PLL) {
148 /* Turn the PLL off */
149 out |= SSB_GPIO_PLL;
150 }
151 err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out);
152 if (err)
153 goto err_pci;
154 err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE, outenable);
155 if (err)
156 goto err_pci;
157 }
158
159out:
160 return err;
161
162err_pci:
163 pr_err("Error: ssb_pci_xtal() could not access PCI config space!\n");
164 err = -EBUSY;
165 goto out;
166}
167
168/* Get the word-offset for a SSB_SPROM_XXX define. */
169#define SPOFF(offset) ((offset) / sizeof(u16))
170/* Helper to extract some _offset, which is one of the SSB_SPROM_XXX defines. */
171#define SPEX16(_outvar, _offset, _mask, _shift) \
172 out->_outvar = ((in[SPOFF(_offset)] & (_mask)) >> (_shift))
173#define SPEX32(_outvar, _offset, _mask, _shift) \
174 out->_outvar = ((((u32)in[SPOFF((_offset)+2)] << 16 | \
175 in[SPOFF(_offset)]) & (_mask)) >> (_shift))
176#define SPEX(_outvar, _offset, _mask, _shift) \
177 SPEX16(_outvar, _offset, _mask, _shift)
178
179#define SPEX_ARRAY8(_field, _offset, _mask, _shift) \
180 do { \
181 SPEX(_field[0], _offset + 0, _mask, _shift); \
182 SPEX(_field[1], _offset + 2, _mask, _shift); \
183 SPEX(_field[2], _offset + 4, _mask, _shift); \
184 SPEX(_field[3], _offset + 6, _mask, _shift); \
185 SPEX(_field[4], _offset + 8, _mask, _shift); \
186 SPEX(_field[5], _offset + 10, _mask, _shift); \
187 SPEX(_field[6], _offset + 12, _mask, _shift); \
188 SPEX(_field[7], _offset + 14, _mask, _shift); \
189 } while (0)
190
191
192static inline u8 ssb_crc8(u8 crc, u8 data)
193{
194 /* Polynomial: x^8 + x^7 + x^6 + x^4 + x^2 + 1 */
195 static const u8 t[] = {
196 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
197 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
198 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
199 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
200 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
201 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
202 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
203 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
204 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
205 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
206 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
207 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
208 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
209 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
210 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
211 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
212 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
213 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
214 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
215 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
216 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
217 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
218 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
219 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
220 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
221 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
222 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
223 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
224 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
225 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
226 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
227 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F,
228 };
229 return t[crc ^ data];
230}
231
232static void sprom_get_mac(char *mac, const u16 *in)
233{
234 int i;
235 for (i = 0; i < 3; i++) {
236 *mac++ = in[i] >> 8;
237 *mac++ = in[i];
238 }
239}
240
241static u8 ssb_sprom_crc(const u16 *sprom, u16 size)
242{
243 int word;
244 u8 crc = 0xFF;
245
246 for (word = 0; word < size - 1; word++) {
247 crc = ssb_crc8(crc, sprom[word] & 0x00FF);
248 crc = ssb_crc8(crc, (sprom[word] & 0xFF00) >> 8);
249 }
250 crc = ssb_crc8(crc, sprom[size - 1] & 0x00FF);
251 crc ^= 0xFF;
252
253 return crc;
254}
255
256static int sprom_check_crc(const u16 *sprom, size_t size)
257{
258 u8 crc;
259 u8 expected_crc;
260 u16 tmp;
261
262 crc = ssb_sprom_crc(sprom, size);
263 tmp = sprom[size - 1] & SSB_SPROM_REVISION_CRC;
264 expected_crc = tmp >> SSB_SPROM_REVISION_CRC_SHIFT;
265 if (crc != expected_crc)
266 return -EPROTO;
267
268 return 0;
269}
270
271static int sprom_do_read(struct ssb_bus *bus, u16 *sprom)
272{
273 int i;
274
275 for (i = 0; i < bus->sprom_size; i++)
276 sprom[i] = ioread16(bus->mmio + bus->sprom_offset + (i * 2));
277
278 return 0;
279}
280
281static int sprom_do_write(struct ssb_bus *bus, const u16 *sprom)
282{
283 struct pci_dev *pdev = bus->host_pci;
284 int i, err;
285 u32 spromctl;
286 u16 size = bus->sprom_size;
287
288 pr_notice("Writing SPROM. Do NOT turn off the power! Please stand by...\n");
289 err = pci_read_config_dword(pdev, SSB_SPROMCTL, &spromctl);
290 if (err)
291 goto err_ctlreg;
292 spromctl |= SSB_SPROMCTL_WE;
293 err = pci_write_config_dword(pdev, SSB_SPROMCTL, spromctl);
294 if (err)
295 goto err_ctlreg;
296 pr_notice("[ 0%%");
297 msleep(500);
298 for (i = 0; i < size; i++) {
299 if (i == size / 4)
300 pr_cont("25%%");
301 else if (i == size / 2)
302 pr_cont("50%%");
303 else if (i == (size * 3) / 4)
304 pr_cont("75%%");
305 else if (i % 2)
306 pr_cont(".");
307 writew(sprom[i], bus->mmio + bus->sprom_offset + (i * 2));
308 mmiowb();
309 msleep(20);
310 }
311 err = pci_read_config_dword(pdev, SSB_SPROMCTL, &spromctl);
312 if (err)
313 goto err_ctlreg;
314 spromctl &= ~SSB_SPROMCTL_WE;
315 err = pci_write_config_dword(pdev, SSB_SPROMCTL, spromctl);
316 if (err)
317 goto err_ctlreg;
318 msleep(500);
319 pr_cont("100%% ]\n");
320 pr_notice("SPROM written\n");
321
322 return 0;
323err_ctlreg:
324 pr_err("Could not access SPROM control register.\n");
325 return err;
326}
327
328static s8 sprom_extract_antgain(u8 sprom_revision, const u16 *in, u16 offset,
329 u16 mask, u16 shift)
330{
331 u16 v;
332 u8 gain;
333
334 v = in[SPOFF(offset)];
335 gain = (v & mask) >> shift;
336 if (gain == 0xFF)
337 gain = 2; /* If unset use 2dBm */
338 if (sprom_revision == 1) {
339 /* Convert to Q5.2 */
340 gain <<= 2;
341 } else {
342 /* Q5.2 Fractional part is stored in 0xC0 */
343 gain = ((gain & 0xC0) >> 6) | ((gain & 0x3F) << 2);
344 }
345
346 return (s8)gain;
347}
348
349static void sprom_extract_r23(struct ssb_sprom *out, const u16 *in)
350{
351 SPEX(boardflags_hi, SSB_SPROM2_BFLHI, 0xFFFF, 0);
352 SPEX(opo, SSB_SPROM2_OPO, SSB_SPROM2_OPO_VALUE, 0);
353 SPEX(pa1lob0, SSB_SPROM2_PA1LOB0, 0xFFFF, 0);
354 SPEX(pa1lob1, SSB_SPROM2_PA1LOB1, 0xFFFF, 0);
355 SPEX(pa1lob2, SSB_SPROM2_PA1LOB2, 0xFFFF, 0);
356 SPEX(pa1hib0, SSB_SPROM2_PA1HIB0, 0xFFFF, 0);
357 SPEX(pa1hib1, SSB_SPROM2_PA1HIB1, 0xFFFF, 0);
358 SPEX(pa1hib2, SSB_SPROM2_PA1HIB2, 0xFFFF, 0);
359 SPEX(maxpwr_ah, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_HI, 0);
360 SPEX(maxpwr_al, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_LO,
361 SSB_SPROM2_MAXP_A_LO_SHIFT);
362}
363
364static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in)
365{
366 u16 loc[3];
367
368 if (out->revision == 3) /* rev 3 moved MAC */
369 loc[0] = SSB_SPROM3_IL0MAC;
370 else {
371 loc[0] = SSB_SPROM1_IL0MAC;
372 loc[1] = SSB_SPROM1_ET0MAC;
373 loc[2] = SSB_SPROM1_ET1MAC;
374 }
375 sprom_get_mac(out->il0mac, &in[SPOFF(loc[0])]);
376 if (out->revision < 3) { /* only rev 1-2 have et0, et1 */
377 sprom_get_mac(out->et0mac, &in[SPOFF(loc[1])]);
378 sprom_get_mac(out->et1mac, &in[SPOFF(loc[2])]);
379 }
380 SPEX(et0phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0A, 0);
381 SPEX(et1phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1A,
382 SSB_SPROM1_ETHPHY_ET1A_SHIFT);
383 SPEX(et0mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0M, 14);
384 SPEX(et1mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1M, 15);
385 SPEX(board_rev, SSB_SPROM1_BINF, SSB_SPROM1_BINF_BREV, 0);
386 SPEX(board_type, SSB_SPROM1_SPID, 0xFFFF, 0);
387 if (out->revision == 1)
388 SPEX(country_code, SSB_SPROM1_BINF, SSB_SPROM1_BINF_CCODE,
389 SSB_SPROM1_BINF_CCODE_SHIFT);
390 SPEX(ant_available_a, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTA,
391 SSB_SPROM1_BINF_ANTA_SHIFT);
392 SPEX(ant_available_bg, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTBG,
393 SSB_SPROM1_BINF_ANTBG_SHIFT);
394 SPEX(pa0b0, SSB_SPROM1_PA0B0, 0xFFFF, 0);
395 SPEX(pa0b1, SSB_SPROM1_PA0B1, 0xFFFF, 0);
396 SPEX(pa0b2, SSB_SPROM1_PA0B2, 0xFFFF, 0);
397 SPEX(pa1b0, SSB_SPROM1_PA1B0, 0xFFFF, 0);
398 SPEX(pa1b1, SSB_SPROM1_PA1B1, 0xFFFF, 0);
399 SPEX(pa1b2, SSB_SPROM1_PA1B2, 0xFFFF, 0);
400 SPEX(gpio0, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P0, 0);
401 SPEX(gpio1, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P1,
402 SSB_SPROM1_GPIOA_P1_SHIFT);
403 SPEX(gpio2, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P2, 0);
404 SPEX(gpio3, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P3,
405 SSB_SPROM1_GPIOB_P3_SHIFT);
406 SPEX(maxpwr_a, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_A,
407 SSB_SPROM1_MAXPWR_A_SHIFT);
408 SPEX(maxpwr_bg, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_BG, 0);
409 SPEX(itssi_a, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_A,
410 SSB_SPROM1_ITSSI_A_SHIFT);
411 SPEX(itssi_bg, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_BG, 0);
412 SPEX(boardflags_lo, SSB_SPROM1_BFLLO, 0xFFFF, 0);
413
414 SPEX(alpha2[0], SSB_SPROM1_CCODE, 0xff00, 8);
415 SPEX(alpha2[1], SSB_SPROM1_CCODE, 0x00ff, 0);
416
417 /* Extract the antenna gain values. */
418 out->antenna_gain.a0 = sprom_extract_antgain(out->revision, in,
419 SSB_SPROM1_AGAIN,
420 SSB_SPROM1_AGAIN_BG,
421 SSB_SPROM1_AGAIN_BG_SHIFT);
422 out->antenna_gain.a1 = sprom_extract_antgain(out->revision, in,
423 SSB_SPROM1_AGAIN,
424 SSB_SPROM1_AGAIN_A,
425 SSB_SPROM1_AGAIN_A_SHIFT);
426 if (out->revision >= 2)
427 sprom_extract_r23(out, in);
428}
429
430/* Revs 4 5 and 8 have partially shared layout */
431static void sprom_extract_r458(struct ssb_sprom *out, const u16 *in)
432{
433 SPEX(txpid2g[0], SSB_SPROM4_TXPID2G01,
434 SSB_SPROM4_TXPID2G0, SSB_SPROM4_TXPID2G0_SHIFT);
435 SPEX(txpid2g[1], SSB_SPROM4_TXPID2G01,
436 SSB_SPROM4_TXPID2G1, SSB_SPROM4_TXPID2G1_SHIFT);
437 SPEX(txpid2g[2], SSB_SPROM4_TXPID2G23,
438 SSB_SPROM4_TXPID2G2, SSB_SPROM4_TXPID2G2_SHIFT);
439 SPEX(txpid2g[3], SSB_SPROM4_TXPID2G23,
440 SSB_SPROM4_TXPID2G3, SSB_SPROM4_TXPID2G3_SHIFT);
441
442 SPEX(txpid5gl[0], SSB_SPROM4_TXPID5GL01,
443 SSB_SPROM4_TXPID5GL0, SSB_SPROM4_TXPID5GL0_SHIFT);
444 SPEX(txpid5gl[1], SSB_SPROM4_TXPID5GL01,
445 SSB_SPROM4_TXPID5GL1, SSB_SPROM4_TXPID5GL1_SHIFT);
446 SPEX(txpid5gl[2], SSB_SPROM4_TXPID5GL23,
447 SSB_SPROM4_TXPID5GL2, SSB_SPROM4_TXPID5GL2_SHIFT);
448 SPEX(txpid5gl[3], SSB_SPROM4_TXPID5GL23,
449 SSB_SPROM4_TXPID5GL3, SSB_SPROM4_TXPID5GL3_SHIFT);
450
451 SPEX(txpid5g[0], SSB_SPROM4_TXPID5G01,
452 SSB_SPROM4_TXPID5G0, SSB_SPROM4_TXPID5G0_SHIFT);
453 SPEX(txpid5g[1], SSB_SPROM4_TXPID5G01,
454 SSB_SPROM4_TXPID5G1, SSB_SPROM4_TXPID5G1_SHIFT);
455 SPEX(txpid5g[2], SSB_SPROM4_TXPID5G23,
456 SSB_SPROM4_TXPID5G2, SSB_SPROM4_TXPID5G2_SHIFT);
457 SPEX(txpid5g[3], SSB_SPROM4_TXPID5G23,
458 SSB_SPROM4_TXPID5G3, SSB_SPROM4_TXPID5G3_SHIFT);
459
460 SPEX(txpid5gh[0], SSB_SPROM4_TXPID5GH01,
461 SSB_SPROM4_TXPID5GH0, SSB_SPROM4_TXPID5GH0_SHIFT);
462 SPEX(txpid5gh[1], SSB_SPROM4_TXPID5GH01,
463 SSB_SPROM4_TXPID5GH1, SSB_SPROM4_TXPID5GH1_SHIFT);
464 SPEX(txpid5gh[2], SSB_SPROM4_TXPID5GH23,
465 SSB_SPROM4_TXPID5GH2, SSB_SPROM4_TXPID5GH2_SHIFT);
466 SPEX(txpid5gh[3], SSB_SPROM4_TXPID5GH23,
467 SSB_SPROM4_TXPID5GH3, SSB_SPROM4_TXPID5GH3_SHIFT);
468}
469
470static void sprom_extract_r45(struct ssb_sprom *out, const u16 *in)
471{
472 static const u16 pwr_info_offset[] = {
473 SSB_SPROM4_PWR_INFO_CORE0, SSB_SPROM4_PWR_INFO_CORE1,
474 SSB_SPROM4_PWR_INFO_CORE2, SSB_SPROM4_PWR_INFO_CORE3
475 };
476 u16 il0mac_offset;
477 int i;
478
479 BUILD_BUG_ON(ARRAY_SIZE(pwr_info_offset) !=
480 ARRAY_SIZE(out->core_pwr_info));
481
482 if (out->revision == 4)
483 il0mac_offset = SSB_SPROM4_IL0MAC;
484 else
485 il0mac_offset = SSB_SPROM5_IL0MAC;
486
487 sprom_get_mac(out->il0mac, &in[SPOFF(il0mac_offset)]);
488
489 SPEX(et0phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET0A, 0);
490 SPEX(et1phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET1A,
491 SSB_SPROM4_ETHPHY_ET1A_SHIFT);
492 SPEX(board_rev, SSB_SPROM4_BOARDREV, 0xFFFF, 0);
493 SPEX(board_type, SSB_SPROM1_SPID, 0xFFFF, 0);
494 if (out->revision == 4) {
495 SPEX(alpha2[0], SSB_SPROM4_CCODE, 0xff00, 8);
496 SPEX(alpha2[1], SSB_SPROM4_CCODE, 0x00ff, 0);
497 SPEX(boardflags_lo, SSB_SPROM4_BFLLO, 0xFFFF, 0);
498 SPEX(boardflags_hi, SSB_SPROM4_BFLHI, 0xFFFF, 0);
499 SPEX(boardflags2_lo, SSB_SPROM4_BFL2LO, 0xFFFF, 0);
500 SPEX(boardflags2_hi, SSB_SPROM4_BFL2HI, 0xFFFF, 0);
501 } else {
502 SPEX(alpha2[0], SSB_SPROM5_CCODE, 0xff00, 8);
503 SPEX(alpha2[1], SSB_SPROM5_CCODE, 0x00ff, 0);
504 SPEX(boardflags_lo, SSB_SPROM5_BFLLO, 0xFFFF, 0);
505 SPEX(boardflags_hi, SSB_SPROM5_BFLHI, 0xFFFF, 0);
506 SPEX(boardflags2_lo, SSB_SPROM5_BFL2LO, 0xFFFF, 0);
507 SPEX(boardflags2_hi, SSB_SPROM5_BFL2HI, 0xFFFF, 0);
508 }
509 SPEX(ant_available_a, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_A,
510 SSB_SPROM4_ANTAVAIL_A_SHIFT);
511 SPEX(ant_available_bg, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_BG,
512 SSB_SPROM4_ANTAVAIL_BG_SHIFT);
513 SPEX(maxpwr_bg, SSB_SPROM4_MAXP_BG, SSB_SPROM4_MAXP_BG_MASK, 0);
514 SPEX(itssi_bg, SSB_SPROM4_MAXP_BG, SSB_SPROM4_ITSSI_BG,
515 SSB_SPROM4_ITSSI_BG_SHIFT);
516 SPEX(maxpwr_a, SSB_SPROM4_MAXP_A, SSB_SPROM4_MAXP_A_MASK, 0);
517 SPEX(itssi_a, SSB_SPROM4_MAXP_A, SSB_SPROM4_ITSSI_A,
518 SSB_SPROM4_ITSSI_A_SHIFT);
519 if (out->revision == 4) {
520 SPEX(gpio0, SSB_SPROM4_GPIOA, SSB_SPROM4_GPIOA_P0, 0);
521 SPEX(gpio1, SSB_SPROM4_GPIOA, SSB_SPROM4_GPIOA_P1,
522 SSB_SPROM4_GPIOA_P1_SHIFT);
523 SPEX(gpio2, SSB_SPROM4_GPIOB, SSB_SPROM4_GPIOB_P2, 0);
524 SPEX(gpio3, SSB_SPROM4_GPIOB, SSB_SPROM4_GPIOB_P3,
525 SSB_SPROM4_GPIOB_P3_SHIFT);
526 } else {
527 SPEX(gpio0, SSB_SPROM5_GPIOA, SSB_SPROM5_GPIOA_P0, 0);
528 SPEX(gpio1, SSB_SPROM5_GPIOA, SSB_SPROM5_GPIOA_P1,
529 SSB_SPROM5_GPIOA_P1_SHIFT);
530 SPEX(gpio2, SSB_SPROM5_GPIOB, SSB_SPROM5_GPIOB_P2, 0);
531 SPEX(gpio3, SSB_SPROM5_GPIOB, SSB_SPROM5_GPIOB_P3,
532 SSB_SPROM5_GPIOB_P3_SHIFT);
533 }
534
535 /* Extract the antenna gain values. */
536 out->antenna_gain.a0 = sprom_extract_antgain(out->revision, in,
537 SSB_SPROM4_AGAIN01,
538 SSB_SPROM4_AGAIN0,
539 SSB_SPROM4_AGAIN0_SHIFT);
540 out->antenna_gain.a1 = sprom_extract_antgain(out->revision, in,
541 SSB_SPROM4_AGAIN01,
542 SSB_SPROM4_AGAIN1,
543 SSB_SPROM4_AGAIN1_SHIFT);
544 out->antenna_gain.a2 = sprom_extract_antgain(out->revision, in,
545 SSB_SPROM4_AGAIN23,
546 SSB_SPROM4_AGAIN2,
547 SSB_SPROM4_AGAIN2_SHIFT);
548 out->antenna_gain.a3 = sprom_extract_antgain(out->revision, in,
549 SSB_SPROM4_AGAIN23,
550 SSB_SPROM4_AGAIN3,
551 SSB_SPROM4_AGAIN3_SHIFT);
552
553 /* Extract cores power info info */
554 for (i = 0; i < ARRAY_SIZE(pwr_info_offset); i++) {
555 u16 o = pwr_info_offset[i];
556
557 SPEX(core_pwr_info[i].itssi_2g, o + SSB_SPROM4_2G_MAXP_ITSSI,
558 SSB_SPROM4_2G_ITSSI, SSB_SPROM4_2G_ITSSI_SHIFT);
559 SPEX(core_pwr_info[i].maxpwr_2g, o + SSB_SPROM4_2G_MAXP_ITSSI,
560 SSB_SPROM4_2G_MAXP, 0);
561
562 SPEX(core_pwr_info[i].pa_2g[0], o + SSB_SPROM4_2G_PA_0, ~0, 0);
563 SPEX(core_pwr_info[i].pa_2g[1], o + SSB_SPROM4_2G_PA_1, ~0, 0);
564 SPEX(core_pwr_info[i].pa_2g[2], o + SSB_SPROM4_2G_PA_2, ~0, 0);
565 SPEX(core_pwr_info[i].pa_2g[3], o + SSB_SPROM4_2G_PA_3, ~0, 0);
566
567 SPEX(core_pwr_info[i].itssi_5g, o + SSB_SPROM4_5G_MAXP_ITSSI,
568 SSB_SPROM4_5G_ITSSI, SSB_SPROM4_5G_ITSSI_SHIFT);
569 SPEX(core_pwr_info[i].maxpwr_5g, o + SSB_SPROM4_5G_MAXP_ITSSI,
570 SSB_SPROM4_5G_MAXP, 0);
571 SPEX(core_pwr_info[i].maxpwr_5gh, o + SSB_SPROM4_5GHL_MAXP,
572 SSB_SPROM4_5GH_MAXP, 0);
573 SPEX(core_pwr_info[i].maxpwr_5gl, o + SSB_SPROM4_5GHL_MAXP,
574 SSB_SPROM4_5GL_MAXP, SSB_SPROM4_5GL_MAXP_SHIFT);
575
576 SPEX(core_pwr_info[i].pa_5gl[0], o + SSB_SPROM4_5GL_PA_0, ~0, 0);
577 SPEX(core_pwr_info[i].pa_5gl[1], o + SSB_SPROM4_5GL_PA_1, ~0, 0);
578 SPEX(core_pwr_info[i].pa_5gl[2], o + SSB_SPROM4_5GL_PA_2, ~0, 0);
579 SPEX(core_pwr_info[i].pa_5gl[3], o + SSB_SPROM4_5GL_PA_3, ~0, 0);
580 SPEX(core_pwr_info[i].pa_5g[0], o + SSB_SPROM4_5G_PA_0, ~0, 0);
581 SPEX(core_pwr_info[i].pa_5g[1], o + SSB_SPROM4_5G_PA_1, ~0, 0);
582 SPEX(core_pwr_info[i].pa_5g[2], o + SSB_SPROM4_5G_PA_2, ~0, 0);
583 SPEX(core_pwr_info[i].pa_5g[3], o + SSB_SPROM4_5G_PA_3, ~0, 0);
584 SPEX(core_pwr_info[i].pa_5gh[0], o + SSB_SPROM4_5GH_PA_0, ~0, 0);
585 SPEX(core_pwr_info[i].pa_5gh[1], o + SSB_SPROM4_5GH_PA_1, ~0, 0);
586 SPEX(core_pwr_info[i].pa_5gh[2], o + SSB_SPROM4_5GH_PA_2, ~0, 0);
587 SPEX(core_pwr_info[i].pa_5gh[3], o + SSB_SPROM4_5GH_PA_3, ~0, 0);
588 }
589
590 sprom_extract_r458(out, in);
591
592 /* TODO - get remaining rev 4 stuff needed */
593}
594
595static void sprom_extract_r8(struct ssb_sprom *out, const u16 *in)
596{
597 int i;
598 u16 o;
599 u16 pwr_info_offset[] = {
600 SSB_SROM8_PWR_INFO_CORE0, SSB_SROM8_PWR_INFO_CORE1,
601 SSB_SROM8_PWR_INFO_CORE2, SSB_SROM8_PWR_INFO_CORE3
602 };
603 BUILD_BUG_ON(ARRAY_SIZE(pwr_info_offset) !=
604 ARRAY_SIZE(out->core_pwr_info));
605
606 /* extract the MAC address */
607 sprom_get_mac(out->il0mac, &in[SPOFF(SSB_SPROM8_IL0MAC)]);
608
609 SPEX(board_rev, SSB_SPROM8_BOARDREV, 0xFFFF, 0);
610 SPEX(board_type, SSB_SPROM1_SPID, 0xFFFF, 0);
611 SPEX(alpha2[0], SSB_SPROM8_CCODE, 0xff00, 8);
612 SPEX(alpha2[1], SSB_SPROM8_CCODE, 0x00ff, 0);
613 SPEX(boardflags_lo, SSB_SPROM8_BFLLO, 0xFFFF, 0);
614 SPEX(boardflags_hi, SSB_SPROM8_BFLHI, 0xFFFF, 0);
615 SPEX(boardflags2_lo, SSB_SPROM8_BFL2LO, 0xFFFF, 0);
616 SPEX(boardflags2_hi, SSB_SPROM8_BFL2HI, 0xFFFF, 0);
617 SPEX(ant_available_a, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_A,
618 SSB_SPROM8_ANTAVAIL_A_SHIFT);
619 SPEX(ant_available_bg, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_BG,
620 SSB_SPROM8_ANTAVAIL_BG_SHIFT);
621 SPEX(maxpwr_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_MAXP_BG_MASK, 0);
622 SPEX(itssi_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_ITSSI_BG,
623 SSB_SPROM8_ITSSI_BG_SHIFT);
624 SPEX(maxpwr_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_MAXP_A_MASK, 0);
625 SPEX(itssi_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_ITSSI_A,
626 SSB_SPROM8_ITSSI_A_SHIFT);
627 SPEX(maxpwr_ah, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AH_MASK, 0);
628 SPEX(maxpwr_al, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AL_MASK,
629 SSB_SPROM8_MAXP_AL_SHIFT);
630 SPEX(gpio0, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P0, 0);
631 SPEX(gpio1, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P1,
632 SSB_SPROM8_GPIOA_P1_SHIFT);
633 SPEX(gpio2, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P2, 0);
634 SPEX(gpio3, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P3,
635 SSB_SPROM8_GPIOB_P3_SHIFT);
636 SPEX(tri2g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI2G, 0);
637 SPEX(tri5g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI5G,
638 SSB_SPROM8_TRI5G_SHIFT);
639 SPEX(tri5gl, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GL, 0);
640 SPEX(tri5gh, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GH,
641 SSB_SPROM8_TRI5GH_SHIFT);
642 SPEX(rxpo2g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO2G, 0);
643 SPEX(rxpo5g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO5G,
644 SSB_SPROM8_RXPO5G_SHIFT);
645 SPEX(rssismf2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMF2G, 0);
646 SPEX(rssismc2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMC2G,
647 SSB_SPROM8_RSSISMC2G_SHIFT);
648 SPEX(rssisav2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISAV2G,
649 SSB_SPROM8_RSSISAV2G_SHIFT);
650 SPEX(bxa2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_BXA2G,
651 SSB_SPROM8_BXA2G_SHIFT);
652 SPEX(rssismf5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMF5G, 0);
653 SPEX(rssismc5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMC5G,
654 SSB_SPROM8_RSSISMC5G_SHIFT);
655 SPEX(rssisav5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISAV5G,
656 SSB_SPROM8_RSSISAV5G_SHIFT);
657 SPEX(bxa5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_BXA5G,
658 SSB_SPROM8_BXA5G_SHIFT);
659 SPEX(pa0b0, SSB_SPROM8_PA0B0, 0xFFFF, 0);
660 SPEX(pa0b1, SSB_SPROM8_PA0B1, 0xFFFF, 0);
661 SPEX(pa0b2, SSB_SPROM8_PA0B2, 0xFFFF, 0);
662 SPEX(pa1b0, SSB_SPROM8_PA1B0, 0xFFFF, 0);
663 SPEX(pa1b1, SSB_SPROM8_PA1B1, 0xFFFF, 0);
664 SPEX(pa1b2, SSB_SPROM8_PA1B2, 0xFFFF, 0);
665 SPEX(pa1lob0, SSB_SPROM8_PA1LOB0, 0xFFFF, 0);
666 SPEX(pa1lob1, SSB_SPROM8_PA1LOB1, 0xFFFF, 0);
667 SPEX(pa1lob2, SSB_SPROM8_PA1LOB2, 0xFFFF, 0);
668 SPEX(pa1hib0, SSB_SPROM8_PA1HIB0, 0xFFFF, 0);
669 SPEX(pa1hib1, SSB_SPROM8_PA1HIB1, 0xFFFF, 0);
670 SPEX(pa1hib2, SSB_SPROM8_PA1HIB2, 0xFFFF, 0);
671 SPEX(cck2gpo, SSB_SPROM8_CCK2GPO, 0xFFFF, 0);
672 SPEX32(ofdm2gpo, SSB_SPROM8_OFDM2GPO, 0xFFFFFFFF, 0);
673 SPEX32(ofdm5glpo, SSB_SPROM8_OFDM5GLPO, 0xFFFFFFFF, 0);
674 SPEX32(ofdm5gpo, SSB_SPROM8_OFDM5GPO, 0xFFFFFFFF, 0);
675 SPEX32(ofdm5ghpo, SSB_SPROM8_OFDM5GHPO, 0xFFFFFFFF, 0);
676
677 /* Extract the antenna gain values. */
678 out->antenna_gain.a0 = sprom_extract_antgain(out->revision, in,
679 SSB_SPROM8_AGAIN01,
680 SSB_SPROM8_AGAIN0,
681 SSB_SPROM8_AGAIN0_SHIFT);
682 out->antenna_gain.a1 = sprom_extract_antgain(out->revision, in,
683 SSB_SPROM8_AGAIN01,
684 SSB_SPROM8_AGAIN1,
685 SSB_SPROM8_AGAIN1_SHIFT);
686 out->antenna_gain.a2 = sprom_extract_antgain(out->revision, in,
687 SSB_SPROM8_AGAIN23,
688 SSB_SPROM8_AGAIN2,
689 SSB_SPROM8_AGAIN2_SHIFT);
690 out->antenna_gain.a3 = sprom_extract_antgain(out->revision, in,
691 SSB_SPROM8_AGAIN23,
692 SSB_SPROM8_AGAIN3,
693 SSB_SPROM8_AGAIN3_SHIFT);
694
695 /* Extract cores power info info */
696 for (i = 0; i < ARRAY_SIZE(pwr_info_offset); i++) {
697 o = pwr_info_offset[i];
698 SPEX(core_pwr_info[i].itssi_2g, o + SSB_SROM8_2G_MAXP_ITSSI,
699 SSB_SPROM8_2G_ITSSI, SSB_SPROM8_2G_ITSSI_SHIFT);
700 SPEX(core_pwr_info[i].maxpwr_2g, o + SSB_SROM8_2G_MAXP_ITSSI,
701 SSB_SPROM8_2G_MAXP, 0);
702
703 SPEX(core_pwr_info[i].pa_2g[0], o + SSB_SROM8_2G_PA_0, ~0, 0);
704 SPEX(core_pwr_info[i].pa_2g[1], o + SSB_SROM8_2G_PA_1, ~0, 0);
705 SPEX(core_pwr_info[i].pa_2g[2], o + SSB_SROM8_2G_PA_2, ~0, 0);
706
707 SPEX(core_pwr_info[i].itssi_5g, o + SSB_SROM8_5G_MAXP_ITSSI,
708 SSB_SPROM8_5G_ITSSI, SSB_SPROM8_5G_ITSSI_SHIFT);
709 SPEX(core_pwr_info[i].maxpwr_5g, o + SSB_SROM8_5G_MAXP_ITSSI,
710 SSB_SPROM8_5G_MAXP, 0);
711 SPEX(core_pwr_info[i].maxpwr_5gh, o + SSB_SPROM8_5GHL_MAXP,
712 SSB_SPROM8_5GH_MAXP, 0);
713 SPEX(core_pwr_info[i].maxpwr_5gl, o + SSB_SPROM8_5GHL_MAXP,
714 SSB_SPROM8_5GL_MAXP, SSB_SPROM8_5GL_MAXP_SHIFT);
715
716 SPEX(core_pwr_info[i].pa_5gl[0], o + SSB_SROM8_5GL_PA_0, ~0, 0);
717 SPEX(core_pwr_info[i].pa_5gl[1], o + SSB_SROM8_5GL_PA_1, ~0, 0);
718 SPEX(core_pwr_info[i].pa_5gl[2], o + SSB_SROM8_5GL_PA_2, ~0, 0);
719 SPEX(core_pwr_info[i].pa_5g[0], o + SSB_SROM8_5G_PA_0, ~0, 0);
720 SPEX(core_pwr_info[i].pa_5g[1], o + SSB_SROM8_5G_PA_1, ~0, 0);
721 SPEX(core_pwr_info[i].pa_5g[2], o + SSB_SROM8_5G_PA_2, ~0, 0);
722 SPEX(core_pwr_info[i].pa_5gh[0], o + SSB_SROM8_5GH_PA_0, ~0, 0);
723 SPEX(core_pwr_info[i].pa_5gh[1], o + SSB_SROM8_5GH_PA_1, ~0, 0);
724 SPEX(core_pwr_info[i].pa_5gh[2], o + SSB_SROM8_5GH_PA_2, ~0, 0);
725 }
726
727 /* Extract FEM info */
728 SPEX(fem.ghz2.tssipos, SSB_SPROM8_FEM2G,
729 SSB_SROM8_FEM_TSSIPOS, SSB_SROM8_FEM_TSSIPOS_SHIFT);
730 SPEX(fem.ghz2.extpa_gain, SSB_SPROM8_FEM2G,
731 SSB_SROM8_FEM_EXTPA_GAIN, SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
732 SPEX(fem.ghz2.pdet_range, SSB_SPROM8_FEM2G,
733 SSB_SROM8_FEM_PDET_RANGE, SSB_SROM8_FEM_PDET_RANGE_SHIFT);
734 SPEX(fem.ghz2.tr_iso, SSB_SPROM8_FEM2G,
735 SSB_SROM8_FEM_TR_ISO, SSB_SROM8_FEM_TR_ISO_SHIFT);
736 SPEX(fem.ghz2.antswlut, SSB_SPROM8_FEM2G,
737 SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT);
738
739 SPEX(fem.ghz5.tssipos, SSB_SPROM8_FEM5G,
740 SSB_SROM8_FEM_TSSIPOS, SSB_SROM8_FEM_TSSIPOS_SHIFT);
741 SPEX(fem.ghz5.extpa_gain, SSB_SPROM8_FEM5G,
742 SSB_SROM8_FEM_EXTPA_GAIN, SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
743 SPEX(fem.ghz5.pdet_range, SSB_SPROM8_FEM5G,
744 SSB_SROM8_FEM_PDET_RANGE, SSB_SROM8_FEM_PDET_RANGE_SHIFT);
745 SPEX(fem.ghz5.tr_iso, SSB_SPROM8_FEM5G,
746 SSB_SROM8_FEM_TR_ISO, SSB_SROM8_FEM_TR_ISO_SHIFT);
747 SPEX(fem.ghz5.antswlut, SSB_SPROM8_FEM5G,
748 SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT);
749
750 SPEX(leddc_on_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_ON,
751 SSB_SPROM8_LEDDC_ON_SHIFT);
752 SPEX(leddc_off_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_OFF,
753 SSB_SPROM8_LEDDC_OFF_SHIFT);
754
755 SPEX(txchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_TXCHAIN,
756 SSB_SPROM8_TXRXC_TXCHAIN_SHIFT);
757 SPEX(rxchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_RXCHAIN,
758 SSB_SPROM8_TXRXC_RXCHAIN_SHIFT);
759 SPEX(antswitch, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_SWITCH,
760 SSB_SPROM8_TXRXC_SWITCH_SHIFT);
761
762 SPEX(opo, SSB_SPROM8_OFDM2GPO, 0x00ff, 0);
763
764 SPEX_ARRAY8(mcs2gpo, SSB_SPROM8_2G_MCSPO, ~0, 0);
765 SPEX_ARRAY8(mcs5gpo, SSB_SPROM8_5G_MCSPO, ~0, 0);
766 SPEX_ARRAY8(mcs5glpo, SSB_SPROM8_5GL_MCSPO, ~0, 0);
767 SPEX_ARRAY8(mcs5ghpo, SSB_SPROM8_5GH_MCSPO, ~0, 0);
768
769 SPEX(rawtempsense, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_RAWTEMP,
770 SSB_SPROM8_RAWTS_RAWTEMP_SHIFT);
771 SPEX(measpower, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_MEASPOWER,
772 SSB_SPROM8_RAWTS_MEASPOWER_SHIFT);
773 SPEX(tempsense_slope, SSB_SPROM8_OPT_CORRX,
774 SSB_SPROM8_OPT_CORRX_TEMP_SLOPE,
775 SSB_SPROM8_OPT_CORRX_TEMP_SLOPE_SHIFT);
776 SPEX(tempcorrx, SSB_SPROM8_OPT_CORRX, SSB_SPROM8_OPT_CORRX_TEMPCORRX,
777 SSB_SPROM8_OPT_CORRX_TEMPCORRX_SHIFT);
778 SPEX(tempsense_option, SSB_SPROM8_OPT_CORRX,
779 SSB_SPROM8_OPT_CORRX_TEMP_OPTION,
780 SSB_SPROM8_OPT_CORRX_TEMP_OPTION_SHIFT);
781 SPEX(freqoffset_corr, SSB_SPROM8_HWIQ_IQSWP,
782 SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR,
783 SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR_SHIFT);
784 SPEX(iqcal_swp_dis, SSB_SPROM8_HWIQ_IQSWP,
785 SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP,
786 SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP_SHIFT);
787 SPEX(hw_iqcal_en, SSB_SPROM8_HWIQ_IQSWP, SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL,
788 SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL_SHIFT);
789
790 SPEX(bw40po, SSB_SPROM8_BW40PO, ~0, 0);
791 SPEX(cddpo, SSB_SPROM8_CDDPO, ~0, 0);
792 SPEX(stbcpo, SSB_SPROM8_STBCPO, ~0, 0);
793 SPEX(bwduppo, SSB_SPROM8_BWDUPPO, ~0, 0);
794
795 SPEX(tempthresh, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_TRESH,
796 SSB_SPROM8_THERMAL_TRESH_SHIFT);
797 SPEX(tempoffset, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_OFFSET,
798 SSB_SPROM8_THERMAL_OFFSET_SHIFT);
799 SPEX(phycal_tempdelta, SSB_SPROM8_TEMPDELTA,
800 SSB_SPROM8_TEMPDELTA_PHYCAL,
801 SSB_SPROM8_TEMPDELTA_PHYCAL_SHIFT);
802 SPEX(temps_period, SSB_SPROM8_TEMPDELTA, SSB_SPROM8_TEMPDELTA_PERIOD,
803 SSB_SPROM8_TEMPDELTA_PERIOD_SHIFT);
804 SPEX(temps_hysteresis, SSB_SPROM8_TEMPDELTA,
805 SSB_SPROM8_TEMPDELTA_HYSTERESIS,
806 SSB_SPROM8_TEMPDELTA_HYSTERESIS_SHIFT);
807 sprom_extract_r458(out, in);
808
809 /* TODO - get remaining rev 8 stuff needed */
810}
811
812static int sprom_extract(struct ssb_bus *bus, struct ssb_sprom *out,
813 const u16 *in, u16 size)
814{
815 memset(out, 0, sizeof(*out));
816
817 out->revision = in[size - 1] & 0x00FF;
818 pr_debug("SPROM revision %d detected\n", out->revision);
819 memset(out->et0mac, 0xFF, 6); /* preset et0 and et1 mac */
820 memset(out->et1mac, 0xFF, 6);
821
822 if ((bus->chip_id & 0xFF00) == 0x4400) {
823 /* Workaround: The BCM44XX chip has a stupid revision
824 * number stored in the SPROM.
825 * Always extract r1. */
826 out->revision = 1;
827 pr_debug("SPROM treated as revision %d\n", out->revision);
828 }
829
830 switch (out->revision) {
831 case 1:
832 case 2:
833 case 3:
834 sprom_extract_r123(out, in);
835 break;
836 case 4:
837 case 5:
838 sprom_extract_r45(out, in);
839 break;
840 case 8:
841 sprom_extract_r8(out, in);
842 break;
843 default:
844 pr_warn("Unsupported SPROM revision %d detected. Will extract v1\n",
845 out->revision);
846 out->revision = 1;
847 sprom_extract_r123(out, in);
848 }
849
850 if (out->boardflags_lo == 0xFFFF)
851 out->boardflags_lo = 0; /* per specs */
852 if (out->boardflags_hi == 0xFFFF)
853 out->boardflags_hi = 0; /* per specs */
854
855 return 0;
856}
857
858static int ssb_pci_sprom_get(struct ssb_bus *bus,
859 struct ssb_sprom *sprom)
860{
861 int err;
862 u16 *buf;
863
864 if (!ssb_is_sprom_available(bus)) {
865 pr_err("No SPROM available!\n");
866 return -ENODEV;
867 }
868 if (bus->chipco.dev) { /* can be unavailable! */
869 /*
870 * get SPROM offset: SSB_SPROM_BASE1 except for
871 * chipcommon rev >= 31 or chip ID is 0x4312 and
872 * chipcommon status & 3 == 2
873 */
874 if (bus->chipco.dev->id.revision >= 31)
875 bus->sprom_offset = SSB_SPROM_BASE31;
876 else if (bus->chip_id == 0x4312 &&
877 (bus->chipco.status & 0x03) == 2)
878 bus->sprom_offset = SSB_SPROM_BASE31;
879 else
880 bus->sprom_offset = SSB_SPROM_BASE1;
881 } else {
882 bus->sprom_offset = SSB_SPROM_BASE1;
883 }
884 pr_debug("SPROM offset is 0x%x\n", bus->sprom_offset);
885
886 buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL);
887 if (!buf)
888 return -ENOMEM;
889 bus->sprom_size = SSB_SPROMSIZE_WORDS_R123;
890 sprom_do_read(bus, buf);
891 err = sprom_check_crc(buf, bus->sprom_size);
892 if (err) {
893 /* try for a 440 byte SPROM - revision 4 and higher */
894 kfree(buf);
895 buf = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
896 GFP_KERNEL);
897 if (!buf)
898 return -ENOMEM;
899 bus->sprom_size = SSB_SPROMSIZE_WORDS_R4;
900 sprom_do_read(bus, buf);
901 err = sprom_check_crc(buf, bus->sprom_size);
902 if (err) {
903 /* All CRC attempts failed.
904 * Maybe there is no SPROM on the device?
905 * Now we ask the arch code if there is some sprom
906 * available for this device in some other storage */
907 err = ssb_fill_sprom_with_fallback(bus, sprom);
908 if (err) {
909 pr_warn("WARNING: Using fallback SPROM failed (err %d)\n",
910 err);
911 goto out_free;
912 } else {
913 pr_debug("Using SPROM revision %d provided by platform\n",
914 sprom->revision);
915 err = 0;
916 goto out_free;
917 }
918 pr_warn("WARNING: Invalid SPROM CRC (corrupt SPROM)\n");
919 }
920 }
921 err = sprom_extract(bus, sprom, buf, bus->sprom_size);
922
923out_free:
924 kfree(buf);
925 return err;
926}
927
928static void ssb_pci_get_boardinfo(struct ssb_bus *bus,
929 struct ssb_boardinfo *bi)
930{
931 bi->vendor = bus->host_pci->subsystem_vendor;
932 bi->type = bus->host_pci->subsystem_device;
933}
934
935int ssb_pci_get_invariants(struct ssb_bus *bus,
936 struct ssb_init_invariants *iv)
937{
938 int err;
939
940 err = ssb_pci_sprom_get(bus, &iv->sprom);
941 if (err)
942 goto out;
943 ssb_pci_get_boardinfo(bus, &iv->boardinfo);
944
945out:
946 return err;
947}
948
949static int ssb_pci_assert_buspower(struct ssb_bus *bus)
950{
951 if (likely(bus->powered_up))
952 return 0;
953
954 pr_err("FATAL ERROR: Bus powered down while accessing PCI MMIO space\n");
955 if (bus->power_warn_count <= 10) {
956 bus->power_warn_count++;
957 dump_stack();
958 }
959
960 return -ENODEV;
961}
962
963static u8 ssb_pci_read8(struct ssb_device *dev, u16 offset)
964{
965 struct ssb_bus *bus = dev->bus;
966
967 if (unlikely(ssb_pci_assert_buspower(bus)))
968 return 0xFF;
969 if (unlikely(bus->mapped_device != dev)) {
970 if (unlikely(ssb_pci_switch_core(bus, dev)))
971 return 0xFF;
972 }
973 return ioread8(bus->mmio + offset);
974}
975
976static u16 ssb_pci_read16(struct ssb_device *dev, u16 offset)
977{
978 struct ssb_bus *bus = dev->bus;
979
980 if (unlikely(ssb_pci_assert_buspower(bus)))
981 return 0xFFFF;
982 if (unlikely(bus->mapped_device != dev)) {
983 if (unlikely(ssb_pci_switch_core(bus, dev)))
984 return 0xFFFF;
985 }
986 return ioread16(bus->mmio + offset);
987}
988
989static u32 ssb_pci_read32(struct ssb_device *dev, u16 offset)
990{
991 struct ssb_bus *bus = dev->bus;
992
993 if (unlikely(ssb_pci_assert_buspower(bus)))
994 return 0xFFFFFFFF;
995 if (unlikely(bus->mapped_device != dev)) {
996 if (unlikely(ssb_pci_switch_core(bus, dev)))
997 return 0xFFFFFFFF;
998 }
999 return ioread32(bus->mmio + offset);
1000}
1001
1002#ifdef CONFIG_SSB_BLOCKIO
1003static void ssb_pci_block_read(struct ssb_device *dev, void *buffer,
1004 size_t count, u16 offset, u8 reg_width)
1005{
1006 struct ssb_bus *bus = dev->bus;
1007 void __iomem *addr = bus->mmio + offset;
1008
1009 if (unlikely(ssb_pci_assert_buspower(bus)))
1010 goto error;
1011 if (unlikely(bus->mapped_device != dev)) {
1012 if (unlikely(ssb_pci_switch_core(bus, dev)))
1013 goto error;
1014 }
1015 switch (reg_width) {
1016 case sizeof(u8):
1017 ioread8_rep(addr, buffer, count);
1018 break;
1019 case sizeof(u16):
1020 WARN_ON(count & 1);
1021 ioread16_rep(addr, buffer, count >> 1);
1022 break;
1023 case sizeof(u32):
1024 WARN_ON(count & 3);
1025 ioread32_rep(addr, buffer, count >> 2);
1026 break;
1027 default:
1028 WARN_ON(1);
1029 }
1030
1031 return;
1032error:
1033 memset(buffer, 0xFF, count);
1034}
1035#endif /* CONFIG_SSB_BLOCKIO */
1036
1037static void ssb_pci_write8(struct ssb_device *dev, u16 offset, u8 value)
1038{
1039 struct ssb_bus *bus = dev->bus;
1040
1041 if (unlikely(ssb_pci_assert_buspower(bus)))
1042 return;
1043 if (unlikely(bus->mapped_device != dev)) {
1044 if (unlikely(ssb_pci_switch_core(bus, dev)))
1045 return;
1046 }
1047 iowrite8(value, bus->mmio + offset);
1048}
1049
1050static void ssb_pci_write16(struct ssb_device *dev, u16 offset, u16 value)
1051{
1052 struct ssb_bus *bus = dev->bus;
1053
1054 if (unlikely(ssb_pci_assert_buspower(bus)))
1055 return;
1056 if (unlikely(bus->mapped_device != dev)) {
1057 if (unlikely(ssb_pci_switch_core(bus, dev)))
1058 return;
1059 }
1060 iowrite16(value, bus->mmio + offset);
1061}
1062
1063static void ssb_pci_write32(struct ssb_device *dev, u16 offset, u32 value)
1064{
1065 struct ssb_bus *bus = dev->bus;
1066
1067 if (unlikely(ssb_pci_assert_buspower(bus)))
1068 return;
1069 if (unlikely(bus->mapped_device != dev)) {
1070 if (unlikely(ssb_pci_switch_core(bus, dev)))
1071 return;
1072 }
1073 iowrite32(value, bus->mmio + offset);
1074}
1075
1076#ifdef CONFIG_SSB_BLOCKIO
1077static void ssb_pci_block_write(struct ssb_device *dev, const void *buffer,
1078 size_t count, u16 offset, u8 reg_width)
1079{
1080 struct ssb_bus *bus = dev->bus;
1081 void __iomem *addr = bus->mmio + offset;
1082
1083 if (unlikely(ssb_pci_assert_buspower(bus)))
1084 return;
1085 if (unlikely(bus->mapped_device != dev)) {
1086 if (unlikely(ssb_pci_switch_core(bus, dev)))
1087 return;
1088 }
1089 switch (reg_width) {
1090 case sizeof(u8):
1091 iowrite8_rep(addr, buffer, count);
1092 break;
1093 case sizeof(u16):
1094 WARN_ON(count & 1);
1095 iowrite16_rep(addr, buffer, count >> 1);
1096 break;
1097 case sizeof(u32):
1098 WARN_ON(count & 3);
1099 iowrite32_rep(addr, buffer, count >> 2);
1100 break;
1101 default:
1102 WARN_ON(1);
1103 }
1104}
1105#endif /* CONFIG_SSB_BLOCKIO */
1106
1107/* Not "static", as it's used in main.c */
1108const struct ssb_bus_ops ssb_pci_ops = {
1109 .read8 = ssb_pci_read8,
1110 .read16 = ssb_pci_read16,
1111 .read32 = ssb_pci_read32,
1112 .write8 = ssb_pci_write8,
1113 .write16 = ssb_pci_write16,
1114 .write32 = ssb_pci_write32,
1115#ifdef CONFIG_SSB_BLOCKIO
1116 .block_read = ssb_pci_block_read,
1117 .block_write = ssb_pci_block_write,
1118#endif
1119};
1120
1121static ssize_t ssb_pci_attr_sprom_show(struct device *pcidev,
1122 struct device_attribute *attr,
1123 char *buf)
1124{
1125 struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev);
1126 struct ssb_bus *bus;
1127
1128 bus = ssb_pci_dev_to_bus(pdev);
1129 if (!bus)
1130 return -ENODEV;
1131
1132 return ssb_attr_sprom_show(bus, buf, sprom_do_read);
1133}
1134
1135static ssize_t ssb_pci_attr_sprom_store(struct device *pcidev,
1136 struct device_attribute *attr,
1137 const char *buf, size_t count)
1138{
1139 struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev);
1140 struct ssb_bus *bus;
1141
1142 bus = ssb_pci_dev_to_bus(pdev);
1143 if (!bus)
1144 return -ENODEV;
1145
1146 return ssb_attr_sprom_store(bus, buf, count,
1147 sprom_check_crc, sprom_do_write);
1148}
1149
1150static DEVICE_ATTR(ssb_sprom, 0600,
1151 ssb_pci_attr_sprom_show,
1152 ssb_pci_attr_sprom_store);
1153
1154void ssb_pci_exit(struct ssb_bus *bus)
1155{
1156 struct pci_dev *pdev;
1157
1158 if (bus->bustype != SSB_BUSTYPE_PCI)
1159 return;
1160
1161 pdev = bus->host_pci;
1162 device_remove_file(&pdev->dev, &dev_attr_ssb_sprom);
1163}
1164
1165int ssb_pci_init(struct ssb_bus *bus)
1166{
1167 struct pci_dev *pdev;
1168 int err;
1169
1170 if (bus->bustype != SSB_BUSTYPE_PCI)
1171 return 0;
1172
1173 pdev = bus->host_pci;
1174 mutex_init(&bus->sprom_mutex);
1175 err = device_create_file(&pdev->dev, &dev_attr_ssb_sprom);
1176 if (err)
1177 goto out;
1178
1179out:
1180 return err;
1181}
1182