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