xref: /openbmc/linux/drivers/bcma/sprom.c (revision 7ae9fb1b7ecbb5d85d07857943f677fd1a559b18)
127f18dc2SRafał Miłecki /*
227f18dc2SRafał Miłecki  * Broadcom specific AMBA
327f18dc2SRafał Miłecki  * SPROM reading
427f18dc2SRafał Miłecki  *
5a027237aSHauke Mehrtens  * Copyright 2011, 2012, Hauke Mehrtens <hauke@hauke-m.de>
6a027237aSHauke Mehrtens  *
727f18dc2SRafał Miłecki  * Licensed under the GNU/GPL. See COPYING for details.
827f18dc2SRafał Miłecki  */
927f18dc2SRafał Miłecki 
1027f18dc2SRafał Miłecki #include "bcma_private.h"
1127f18dc2SRafał Miłecki 
1227f18dc2SRafał Miłecki #include <linux/bcma/bcma.h>
1327f18dc2SRafał Miłecki #include <linux/bcma/bcma_regs.h>
1427f18dc2SRafał Miłecki #include <linux/pci.h>
1527f18dc2SRafał Miłecki #include <linux/io.h>
1627f18dc2SRafał Miłecki #include <linux/dma-mapping.h>
1727f18dc2SRafał Miłecki #include <linux/slab.h>
1827f18dc2SRafał Miłecki 
19a027237aSHauke Mehrtens static int(*get_fallback_sprom)(struct bcma_bus *dev, struct ssb_sprom *out);
20a027237aSHauke Mehrtens 
21a027237aSHauke Mehrtens /**
22a027237aSHauke Mehrtens  * bcma_arch_register_fallback_sprom - Registers a method providing a
23a027237aSHauke Mehrtens  * fallback SPROM if no SPROM is found.
24a027237aSHauke Mehrtens  *
25a027237aSHauke Mehrtens  * @sprom_callback: The callback function.
26a027237aSHauke Mehrtens  *
27a027237aSHauke Mehrtens  * With this function the architecture implementation may register a
28a027237aSHauke Mehrtens  * callback handler which fills the SPROM data structure. The fallback is
29a027237aSHauke Mehrtens  * used for PCI based BCMA devices, where no valid SPROM can be found
30a027237aSHauke Mehrtens  * in the shadow registers and to provide the SPROM for SoCs where BCMA is
31032931fdSTom Rix  * to control the system bus.
32a027237aSHauke Mehrtens  *
33a027237aSHauke Mehrtens  * This function is useful for weird architectures that have a half-assed
34a027237aSHauke Mehrtens  * BCMA device hardwired to their PCI bus.
35a027237aSHauke Mehrtens  *
36a027237aSHauke Mehrtens  * This function is available for architecture code, only. So it is not
37a027237aSHauke Mehrtens  * exported.
38a027237aSHauke Mehrtens  */
bcma_arch_register_fallback_sprom(int (* sprom_callback)(struct bcma_bus * bus,struct ssb_sprom * out))39a027237aSHauke Mehrtens int bcma_arch_register_fallback_sprom(int (*sprom_callback)(struct bcma_bus *bus,
40a027237aSHauke Mehrtens 				     struct ssb_sprom *out))
41a027237aSHauke Mehrtens {
42a027237aSHauke Mehrtens 	if (get_fallback_sprom)
43a027237aSHauke Mehrtens 		return -EEXIST;
44a027237aSHauke Mehrtens 	get_fallback_sprom = sprom_callback;
45a027237aSHauke Mehrtens 
46a027237aSHauke Mehrtens 	return 0;
47a027237aSHauke Mehrtens }
48a027237aSHauke Mehrtens 
bcma_fill_sprom_with_fallback(struct bcma_bus * bus,struct ssb_sprom * out)49a027237aSHauke Mehrtens static int bcma_fill_sprom_with_fallback(struct bcma_bus *bus,
50a027237aSHauke Mehrtens 					 struct ssb_sprom *out)
51a027237aSHauke Mehrtens {
524ac887cfSArend van Spriel 	int err;
53a027237aSHauke Mehrtens 
544ac887cfSArend van Spriel 	if (!get_fallback_sprom) {
554ac887cfSArend van Spriel 		err = -ENOENT;
564ac887cfSArend van Spriel 		goto fail;
574ac887cfSArend van Spriel 	}
584ac887cfSArend van Spriel 
594ac887cfSArend van Spriel 	err = get_fallback_sprom(bus, out);
604ac887cfSArend van Spriel 	if (err)
614ac887cfSArend van Spriel 		goto fail;
624ac887cfSArend van Spriel 
633d9d8af3SRafał Miłecki 	bcma_debug(bus, "Using SPROM revision %d provided by platform.\n",
643d9d8af3SRafał Miłecki 		   bus->sprom.revision);
654ac887cfSArend van Spriel 	return 0;
664ac887cfSArend van Spriel fail:
673d9d8af3SRafał Miłecki 	bcma_warn(bus, "Using fallback SPROM failed (err %d)\n", err);
684ac887cfSArend van Spriel 	return err;
69a027237aSHauke Mehrtens }
70a027237aSHauke Mehrtens 
7127f18dc2SRafał Miłecki /**************************************************
7227f18dc2SRafał Miłecki  * R/W ops.
7327f18dc2SRafał Miłecki  **************************************************/
7427f18dc2SRafał Miłecki 
bcma_sprom_read(struct bcma_bus * bus,u16 offset,u16 * sprom,size_t words)755179ed7cSRafał Miłecki static void bcma_sprom_read(struct bcma_bus *bus, u16 offset, u16 *sprom,
765179ed7cSRafał Miłecki 			    size_t words)
7727f18dc2SRafał Miłecki {
7827f18dc2SRafał Miłecki 	int i;
795179ed7cSRafał Miłecki 	for (i = 0; i < words; i++)
805179ed7cSRafał Miłecki 		sprom[i] = bcma_read16(bus->drv_cc.core, offset + (i * 2));
8127f18dc2SRafał Miłecki }
8227f18dc2SRafał Miłecki 
8327f18dc2SRafał Miłecki /**************************************************
8427f18dc2SRafał Miłecki  * Validation.
8527f18dc2SRafał Miłecki  **************************************************/
8627f18dc2SRafał Miłecki 
bcma_crc8(u8 crc,u8 data)8727f18dc2SRafał Miłecki static inline u8 bcma_crc8(u8 crc, u8 data)
8827f18dc2SRafał Miłecki {
8927f18dc2SRafał Miłecki 	/* Polynomial:   x^8 + x^7 + x^6 + x^4 + x^2 + 1   */
9027f18dc2SRafał Miłecki 	static const u8 t[] = {
9127f18dc2SRafał Miłecki 		0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
9227f18dc2SRafał Miłecki 		0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
9327f18dc2SRafał Miłecki 		0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
9427f18dc2SRafał Miłecki 		0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
9527f18dc2SRafał Miłecki 		0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
9627f18dc2SRafał Miłecki 		0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
9727f18dc2SRafał Miłecki 		0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
9827f18dc2SRafał Miłecki 		0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
9927f18dc2SRafał Miłecki 		0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
10027f18dc2SRafał Miłecki 		0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
10127f18dc2SRafał Miłecki 		0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
10227f18dc2SRafał Miłecki 		0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
10327f18dc2SRafał Miłecki 		0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
10427f18dc2SRafał Miłecki 		0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
10527f18dc2SRafał Miłecki 		0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
10627f18dc2SRafał Miłecki 		0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
10727f18dc2SRafał Miłecki 		0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
10827f18dc2SRafał Miłecki 		0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
10927f18dc2SRafał Miłecki 		0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
11027f18dc2SRafał Miłecki 		0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
11127f18dc2SRafał Miłecki 		0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
11227f18dc2SRafał Miłecki 		0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
11327f18dc2SRafał Miłecki 		0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
11427f18dc2SRafał Miłecki 		0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
11527f18dc2SRafał Miłecki 		0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
11627f18dc2SRafał Miłecki 		0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
11727f18dc2SRafał Miłecki 		0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
11827f18dc2SRafał Miłecki 		0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
11927f18dc2SRafał Miłecki 		0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
12027f18dc2SRafał Miłecki 		0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
12127f18dc2SRafał Miłecki 		0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
12227f18dc2SRafał Miłecki 		0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F,
12327f18dc2SRafał Miłecki 	};
12427f18dc2SRafał Miłecki 	return t[crc ^ data];
12527f18dc2SRafał Miłecki }
12627f18dc2SRafał Miłecki 
bcma_sprom_crc(const u16 * sprom,size_t words)1275179ed7cSRafał Miłecki static u8 bcma_sprom_crc(const u16 *sprom, size_t words)
12827f18dc2SRafał Miłecki {
12927f18dc2SRafał Miłecki 	int word;
13027f18dc2SRafał Miłecki 	u8 crc = 0xFF;
13127f18dc2SRafał Miłecki 
1325179ed7cSRafał Miłecki 	for (word = 0; word < words - 1; word++) {
13327f18dc2SRafał Miłecki 		crc = bcma_crc8(crc, sprom[word] & 0x00FF);
13427f18dc2SRafał Miłecki 		crc = bcma_crc8(crc, (sprom[word] & 0xFF00) >> 8);
13527f18dc2SRafał Miłecki 	}
1365179ed7cSRafał Miłecki 	crc = bcma_crc8(crc, sprom[words - 1] & 0x00FF);
13727f18dc2SRafał Miłecki 	crc ^= 0xFF;
13827f18dc2SRafał Miłecki 
13927f18dc2SRafał Miłecki 	return crc;
14027f18dc2SRafał Miłecki }
14127f18dc2SRafał Miłecki 
bcma_sprom_check_crc(const u16 * sprom,size_t words)1425179ed7cSRafał Miłecki static int bcma_sprom_check_crc(const u16 *sprom, size_t words)
14327f18dc2SRafał Miłecki {
14427f18dc2SRafał Miłecki 	u8 crc;
14527f18dc2SRafał Miłecki 	u8 expected_crc;
14627f18dc2SRafał Miłecki 	u16 tmp;
14727f18dc2SRafał Miłecki 
1485179ed7cSRafał Miłecki 	crc = bcma_sprom_crc(sprom, words);
1495179ed7cSRafał Miłecki 	tmp = sprom[words - 1] & SSB_SPROM_REVISION_CRC;
15027f18dc2SRafał Miłecki 	expected_crc = tmp >> SSB_SPROM_REVISION_CRC_SHIFT;
15127f18dc2SRafał Miłecki 	if (crc != expected_crc)
15227f18dc2SRafał Miłecki 		return -EPROTO;
15327f18dc2SRafał Miłecki 
15427f18dc2SRafał Miłecki 	return 0;
15527f18dc2SRafał Miłecki }
15627f18dc2SRafał Miłecki 
bcma_sprom_valid(struct bcma_bus * bus,const u16 * sprom,size_t words)15778e578c5SRafał Miłecki static int bcma_sprom_valid(struct bcma_bus *bus, const u16 *sprom,
15878e578c5SRafał Miłecki 			    size_t words)
15927f18dc2SRafał Miłecki {
16027f18dc2SRafał Miłecki 	u16 revision;
16127f18dc2SRafał Miłecki 	int err;
16227f18dc2SRafał Miłecki 
1635179ed7cSRafał Miłecki 	err = bcma_sprom_check_crc(sprom, words);
16427f18dc2SRafał Miłecki 	if (err)
16527f18dc2SRafał Miłecki 		return err;
16627f18dc2SRafał Miłecki 
1675179ed7cSRafał Miłecki 	revision = sprom[words - 1] & SSB_SPROM_REVISION_REV;
168*80bc5ae9SLinus Walleij 	if (revision < 8 || revision > 11) {
16927f18dc2SRafał Miłecki 		pr_err("Unsupported SPROM revision: %d\n", revision);
17027f18dc2SRafał Miłecki 		return -ENOENT;
17127f18dc2SRafał Miłecki 	}
17227f18dc2SRafał Miłecki 
17378e578c5SRafał Miłecki 	bus->sprom.revision = revision;
17478e578c5SRafał Miłecki 	bcma_debug(bus, "Found SPROM revision %d\n", revision);
17578e578c5SRafał Miłecki 
17627f18dc2SRafał Miłecki 	return 0;
17727f18dc2SRafał Miłecki }
17827f18dc2SRafał Miłecki 
17927f18dc2SRafał Miłecki /**************************************************
18027f18dc2SRafał Miłecki  * SPROM extraction.
18127f18dc2SRafał Miłecki  **************************************************/
18227f18dc2SRafał Miłecki 
183b35a9acaSRafał Miłecki #define SPOFF(offset)	((offset) / sizeof(u16))
184b35a9acaSRafał Miłecki 
185b35a9acaSRafał Miłecki #define SPEX(_field, _offset, _mask, _shift)	\
186b35a9acaSRafał Miłecki 	bus->sprom._field = ((sprom[SPOFF(_offset)] & (_mask)) >> (_shift))
187b35a9acaSRafał Miłecki 
188432c4d1eSHauke Mehrtens #define SPEX32(_field, _offset, _mask, _shift)	\
189432c4d1eSHauke Mehrtens 	bus->sprom._field = ((((u32)sprom[SPOFF((_offset)+2)] << 16 | \
190432c4d1eSHauke Mehrtens 				sprom[SPOFF(_offset)]) & (_mask)) >> (_shift))
191432c4d1eSHauke Mehrtens 
192e2da4bd3SHauke Mehrtens #define SPEX_ARRAY8(_field, _offset, _mask, _shift)	\
193e2da4bd3SHauke Mehrtens 	do {	\
194e2da4bd3SHauke Mehrtens 		SPEX(_field[0], _offset +  0, _mask, _shift);	\
195e2da4bd3SHauke Mehrtens 		SPEX(_field[1], _offset +  2, _mask, _shift);	\
196e2da4bd3SHauke Mehrtens 		SPEX(_field[2], _offset +  4, _mask, _shift);	\
197e2da4bd3SHauke Mehrtens 		SPEX(_field[3], _offset +  6, _mask, _shift);	\
198e2da4bd3SHauke Mehrtens 		SPEX(_field[4], _offset +  8, _mask, _shift);	\
199e2da4bd3SHauke Mehrtens 		SPEX(_field[5], _offset + 10, _mask, _shift);	\
200e2da4bd3SHauke Mehrtens 		SPEX(_field[6], _offset + 12, _mask, _shift);	\
201e2da4bd3SHauke Mehrtens 		SPEX(_field[7], _offset + 14, _mask, _shift);	\
202e2da4bd3SHauke Mehrtens 	} while (0)
203e2da4bd3SHauke Mehrtens 
sprom_extract_antgain(const u16 * in,u16 offset,u16 mask,u16 shift)204d8aef323SRafał Miłecki static s8 sprom_extract_antgain(const u16 *in, u16 offset, u16 mask, u16 shift)
205d8aef323SRafał Miłecki {
206d8aef323SRafał Miłecki 	u16 v;
207d8aef323SRafał Miłecki 	u8 gain;
208d8aef323SRafał Miłecki 
209d8aef323SRafał Miłecki 	v = in[SPOFF(offset)];
210d8aef323SRafał Miłecki 	gain = (v & mask) >> shift;
211d8aef323SRafał Miłecki 	if (gain == 0xFF) {
212d8aef323SRafał Miłecki 		gain = 8; /* If unset use 2dBm */
213d8aef323SRafał Miłecki 	} else {
214d8aef323SRafał Miłecki 		/* Q5.2 Fractional part is stored in 0xC0 */
215d8aef323SRafał Miłecki 		gain = ((gain & 0xC0) >> 6) | ((gain & 0x3F) << 2);
216d8aef323SRafał Miłecki 	}
217d8aef323SRafał Miłecki 
218d8aef323SRafał Miłecki 	return (s8)gain;
219d8aef323SRafał Miłecki }
220d8aef323SRafał Miłecki 
bcma_sprom_extract_r8(struct bcma_bus * bus,const u16 * sprom)22127f18dc2SRafał Miłecki static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom)
22227f18dc2SRafał Miłecki {
223507f9a71SRafał Miłecki 	u16 v, o;
22427f18dc2SRafał Miłecki 	int i;
225c57391f4SColin Ian King 	static const u16 pwr_info_offset[] = {
226507f9a71SRafał Miłecki 		SSB_SROM8_PWR_INFO_CORE0, SSB_SROM8_PWR_INFO_CORE1,
227507f9a71SRafał Miłecki 		SSB_SROM8_PWR_INFO_CORE2, SSB_SROM8_PWR_INFO_CORE3
228507f9a71SRafał Miłecki 	};
229507f9a71SRafał Miłecki 	BUILD_BUG_ON(ARRAY_SIZE(pwr_info_offset) !=
230507f9a71SRafał Miłecki 			ARRAY_SIZE(bus->sprom.core_pwr_info));
23127f18dc2SRafał Miłecki 
23227f18dc2SRafał Miłecki 	for (i = 0; i < 3; i++) {
23327f18dc2SRafał Miłecki 		v = sprom[SPOFF(SSB_SPROM8_IL0MAC) + i];
23427f18dc2SRafał Miłecki 		*(((__be16 *)bus->sprom.il0mac) + i) = cpu_to_be16(v);
23527f18dc2SRafał Miłecki 	}
236d703a5aeSRafał Miłecki 
237b35a9acaSRafał Miłecki 	SPEX(board_rev, SSB_SPROM8_BOARDREV, ~0, 0);
2387b828f09SRafał Miłecki 	SPEX(board_type, SSB_SPROM1_SPID, ~0, 0);
239d703a5aeSRafał Miłecki 
240b35a9acaSRafał Miłecki 	SPEX(txpid2g[0], SSB_SPROM4_TXPID2G01, SSB_SPROM4_TXPID2G0,
241b35a9acaSRafał Miłecki 	     SSB_SPROM4_TXPID2G0_SHIFT);
242b35a9acaSRafał Miłecki 	SPEX(txpid2g[1], SSB_SPROM4_TXPID2G01, SSB_SPROM4_TXPID2G1,
243b35a9acaSRafał Miłecki 	     SSB_SPROM4_TXPID2G1_SHIFT);
244b35a9acaSRafał Miłecki 	SPEX(txpid2g[2], SSB_SPROM4_TXPID2G23, SSB_SPROM4_TXPID2G2,
245b35a9acaSRafał Miłecki 	     SSB_SPROM4_TXPID2G2_SHIFT);
246b35a9acaSRafał Miłecki 	SPEX(txpid2g[3], SSB_SPROM4_TXPID2G23, SSB_SPROM4_TXPID2G3,
247b35a9acaSRafał Miłecki 	     SSB_SPROM4_TXPID2G3_SHIFT);
248daadc6b3SRafał Miłecki 
249b35a9acaSRafał Miłecki 	SPEX(txpid5gl[0], SSB_SPROM4_TXPID5GL01, SSB_SPROM4_TXPID5GL0,
250b35a9acaSRafał Miłecki 	     SSB_SPROM4_TXPID5GL0_SHIFT);
251b35a9acaSRafał Miłecki 	SPEX(txpid5gl[1], SSB_SPROM4_TXPID5GL01, SSB_SPROM4_TXPID5GL1,
252b35a9acaSRafał Miłecki 	     SSB_SPROM4_TXPID5GL1_SHIFT);
253b35a9acaSRafał Miłecki 	SPEX(txpid5gl[2], SSB_SPROM4_TXPID5GL23, SSB_SPROM4_TXPID5GL2,
254b35a9acaSRafał Miłecki 	     SSB_SPROM4_TXPID5GL2_SHIFT);
255b35a9acaSRafał Miłecki 	SPEX(txpid5gl[3], SSB_SPROM4_TXPID5GL23, SSB_SPROM4_TXPID5GL3,
256b35a9acaSRafał Miłecki 	     SSB_SPROM4_TXPID5GL3_SHIFT);
257daadc6b3SRafał Miłecki 
258b35a9acaSRafał Miłecki 	SPEX(txpid5g[0], SSB_SPROM4_TXPID5G01, SSB_SPROM4_TXPID5G0,
259b35a9acaSRafał Miłecki 	     SSB_SPROM4_TXPID5G0_SHIFT);
260b35a9acaSRafał Miłecki 	SPEX(txpid5g[1], SSB_SPROM4_TXPID5G01, SSB_SPROM4_TXPID5G1,
261b35a9acaSRafał Miłecki 	     SSB_SPROM4_TXPID5G1_SHIFT);
262b35a9acaSRafał Miłecki 	SPEX(txpid5g[2], SSB_SPROM4_TXPID5G23, SSB_SPROM4_TXPID5G2,
263b35a9acaSRafał Miłecki 	     SSB_SPROM4_TXPID5G2_SHIFT);
264b35a9acaSRafał Miłecki 	SPEX(txpid5g[3], SSB_SPROM4_TXPID5G23, SSB_SPROM4_TXPID5G3,
265b35a9acaSRafał Miłecki 	     SSB_SPROM4_TXPID5G3_SHIFT);
266daadc6b3SRafał Miłecki 
267b35a9acaSRafał Miłecki 	SPEX(txpid5gh[0], SSB_SPROM4_TXPID5GH01, SSB_SPROM4_TXPID5GH0,
268b35a9acaSRafał Miłecki 	     SSB_SPROM4_TXPID5GH0_SHIFT);
269b35a9acaSRafał Miłecki 	SPEX(txpid5gh[1], SSB_SPROM4_TXPID5GH01, SSB_SPROM4_TXPID5GH1,
270b35a9acaSRafał Miłecki 	     SSB_SPROM4_TXPID5GH1_SHIFT);
271b35a9acaSRafał Miłecki 	SPEX(txpid5gh[2], SSB_SPROM4_TXPID5GH23, SSB_SPROM4_TXPID5GH2,
272b35a9acaSRafał Miłecki 	     SSB_SPROM4_TXPID5GH2_SHIFT);
273b35a9acaSRafał Miłecki 	SPEX(txpid5gh[3], SSB_SPROM4_TXPID5GH23, SSB_SPROM4_TXPID5GH3,
274b35a9acaSRafał Miłecki 	     SSB_SPROM4_TXPID5GH3_SHIFT);
275daadc6b3SRafał Miłecki 
276b35a9acaSRafał Miłecki 	SPEX(boardflags_lo, SSB_SPROM8_BFLLO, ~0, 0);
277b35a9acaSRafał Miłecki 	SPEX(boardflags_hi, SSB_SPROM8_BFLHI, ~0, 0);
278b35a9acaSRafał Miłecki 	SPEX(boardflags2_lo, SSB_SPROM8_BFL2LO, ~0, 0);
279b35a9acaSRafał Miłecki 	SPEX(boardflags2_hi, SSB_SPROM8_BFL2HI, ~0, 0);
280d703a5aeSRafał Miłecki 
281bf7d420bSHauke Mehrtens 	SPEX(alpha2[0], SSB_SPROM8_CCODE, 0xff00, 8);
282bf7d420bSHauke Mehrtens 	SPEX(alpha2[1], SSB_SPROM8_CCODE, 0x00ff, 0);
283aee5ed56SRafał Miłecki 
284032931fdSTom Rix 	/* Extract core's power info */
285507f9a71SRafał Miłecki 	for (i = 0; i < ARRAY_SIZE(pwr_info_offset); i++) {
286507f9a71SRafał Miłecki 		o = pwr_info_offset[i];
287507f9a71SRafał Miłecki 		SPEX(core_pwr_info[i].itssi_2g, o + SSB_SROM8_2G_MAXP_ITSSI,
288507f9a71SRafał Miłecki 			SSB_SPROM8_2G_ITSSI, SSB_SPROM8_2G_ITSSI_SHIFT);
289507f9a71SRafał Miłecki 		SPEX(core_pwr_info[i].maxpwr_2g, o + SSB_SROM8_2G_MAXP_ITSSI,
290507f9a71SRafał Miłecki 			SSB_SPROM8_2G_MAXP, 0);
291507f9a71SRafał Miłecki 
292507f9a71SRafał Miłecki 		SPEX(core_pwr_info[i].pa_2g[0], o + SSB_SROM8_2G_PA_0, ~0, 0);
293507f9a71SRafał Miłecki 		SPEX(core_pwr_info[i].pa_2g[1], o + SSB_SROM8_2G_PA_1, ~0, 0);
294507f9a71SRafał Miłecki 		SPEX(core_pwr_info[i].pa_2g[2], o + SSB_SROM8_2G_PA_2, ~0, 0);
295507f9a71SRafał Miłecki 
296507f9a71SRafał Miłecki 		SPEX(core_pwr_info[i].itssi_5g, o + SSB_SROM8_5G_MAXP_ITSSI,
297507f9a71SRafał Miłecki 			SSB_SPROM8_5G_ITSSI, SSB_SPROM8_5G_ITSSI_SHIFT);
298507f9a71SRafał Miłecki 		SPEX(core_pwr_info[i].maxpwr_5g, o + SSB_SROM8_5G_MAXP_ITSSI,
299507f9a71SRafał Miłecki 			SSB_SPROM8_5G_MAXP, 0);
300507f9a71SRafał Miłecki 		SPEX(core_pwr_info[i].maxpwr_5gh, o + SSB_SPROM8_5GHL_MAXP,
301507f9a71SRafał Miłecki 			SSB_SPROM8_5GH_MAXP, 0);
302507f9a71SRafał Miłecki 		SPEX(core_pwr_info[i].maxpwr_5gl, o + SSB_SPROM8_5GHL_MAXP,
303507f9a71SRafał Miłecki 			SSB_SPROM8_5GL_MAXP, SSB_SPROM8_5GL_MAXP_SHIFT);
304507f9a71SRafał Miłecki 
305507f9a71SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gl[0], o + SSB_SROM8_5GL_PA_0, ~0, 0);
306507f9a71SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gl[1], o + SSB_SROM8_5GL_PA_1, ~0, 0);
307507f9a71SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gl[2], o + SSB_SROM8_5GL_PA_2, ~0, 0);
308507f9a71SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5g[0], o + SSB_SROM8_5G_PA_0, ~0, 0);
309507f9a71SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5g[1], o + SSB_SROM8_5G_PA_1, ~0, 0);
310507f9a71SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5g[2], o + SSB_SROM8_5G_PA_2, ~0, 0);
311507f9a71SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gh[0], o + SSB_SROM8_5GH_PA_0, ~0, 0);
312507f9a71SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gh[1], o + SSB_SROM8_5GH_PA_1, ~0, 0);
313507f9a71SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gh[2], o + SSB_SROM8_5GH_PA_2, ~0, 0);
314507f9a71SRafał Miłecki 	}
315507f9a71SRafał Miłecki 
316b35a9acaSRafał Miłecki 	SPEX(fem.ghz2.tssipos, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_TSSIPOS,
317b35a9acaSRafał Miłecki 	     SSB_SROM8_FEM_TSSIPOS_SHIFT);
318b35a9acaSRafał Miłecki 	SPEX(fem.ghz2.extpa_gain, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_EXTPA_GAIN,
319b35a9acaSRafał Miłecki 	     SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
320b35a9acaSRafał Miłecki 	SPEX(fem.ghz2.pdet_range, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_PDET_RANGE,
321b35a9acaSRafał Miłecki 	     SSB_SROM8_FEM_PDET_RANGE_SHIFT);
322b35a9acaSRafał Miłecki 	SPEX(fem.ghz2.tr_iso, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_TR_ISO,
323b35a9acaSRafał Miłecki 	     SSB_SROM8_FEM_TR_ISO_SHIFT);
324b35a9acaSRafał Miłecki 	SPEX(fem.ghz2.antswlut, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_ANTSWLUT,
325b35a9acaSRafał Miłecki 	     SSB_SROM8_FEM_ANTSWLUT_SHIFT);
326aee5ed56SRafał Miłecki 
327b35a9acaSRafał Miłecki 	SPEX(fem.ghz5.tssipos, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_TSSIPOS,
328b35a9acaSRafał Miłecki 	     SSB_SROM8_FEM_TSSIPOS_SHIFT);
329b35a9acaSRafał Miłecki 	SPEX(fem.ghz5.extpa_gain, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_EXTPA_GAIN,
330b35a9acaSRafał Miłecki 	     SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
331b35a9acaSRafał Miłecki 	SPEX(fem.ghz5.pdet_range, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_PDET_RANGE,
332b35a9acaSRafał Miłecki 	     SSB_SROM8_FEM_PDET_RANGE_SHIFT);
333b35a9acaSRafał Miłecki 	SPEX(fem.ghz5.tr_iso, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_TR_ISO,
334b35a9acaSRafał Miłecki 	     SSB_SROM8_FEM_TR_ISO_SHIFT);
335b35a9acaSRafał Miłecki 	SPEX(fem.ghz5.antswlut, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_ANTSWLUT,
336b35a9acaSRafał Miłecki 	     SSB_SROM8_FEM_ANTSWLUT_SHIFT);
337432c4d1eSHauke Mehrtens 
338432c4d1eSHauke Mehrtens 	SPEX(ant_available_a, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_A,
339432c4d1eSHauke Mehrtens 	     SSB_SPROM8_ANTAVAIL_A_SHIFT);
340432c4d1eSHauke Mehrtens 	SPEX(ant_available_bg, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_BG,
341432c4d1eSHauke Mehrtens 	     SSB_SPROM8_ANTAVAIL_BG_SHIFT);
342432c4d1eSHauke Mehrtens 	SPEX(maxpwr_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_MAXP_BG_MASK, 0);
343432c4d1eSHauke Mehrtens 	SPEX(itssi_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_ITSSI_BG,
344432c4d1eSHauke Mehrtens 	     SSB_SPROM8_ITSSI_BG_SHIFT);
345432c4d1eSHauke Mehrtens 	SPEX(maxpwr_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_MAXP_A_MASK, 0);
346432c4d1eSHauke Mehrtens 	SPEX(itssi_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_ITSSI_A,
347432c4d1eSHauke Mehrtens 	     SSB_SPROM8_ITSSI_A_SHIFT);
348432c4d1eSHauke Mehrtens 	SPEX(maxpwr_ah, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AH_MASK, 0);
349432c4d1eSHauke Mehrtens 	SPEX(maxpwr_al, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AL_MASK,
350432c4d1eSHauke Mehrtens 	     SSB_SPROM8_MAXP_AL_SHIFT);
351432c4d1eSHauke Mehrtens 	SPEX(gpio0, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P0, 0);
352432c4d1eSHauke Mehrtens 	SPEX(gpio1, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P1,
353432c4d1eSHauke Mehrtens 	     SSB_SPROM8_GPIOA_P1_SHIFT);
354432c4d1eSHauke Mehrtens 	SPEX(gpio2, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P2, 0);
355432c4d1eSHauke Mehrtens 	SPEX(gpio3, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P3,
356432c4d1eSHauke Mehrtens 	     SSB_SPROM8_GPIOB_P3_SHIFT);
357432c4d1eSHauke Mehrtens 	SPEX(tri2g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI2G, 0);
358432c4d1eSHauke Mehrtens 	SPEX(tri5g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI5G,
359432c4d1eSHauke Mehrtens 	     SSB_SPROM8_TRI5G_SHIFT);
360432c4d1eSHauke Mehrtens 	SPEX(tri5gl, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GL, 0);
361432c4d1eSHauke Mehrtens 	SPEX(tri5gh, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GH,
362432c4d1eSHauke Mehrtens 	     SSB_SPROM8_TRI5GH_SHIFT);
363432c4d1eSHauke Mehrtens 	SPEX(rxpo2g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO2G,
364432c4d1eSHauke Mehrtens 	     SSB_SPROM8_RXPO2G_SHIFT);
365432c4d1eSHauke Mehrtens 	SPEX(rxpo5g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO5G,
366432c4d1eSHauke Mehrtens 	     SSB_SPROM8_RXPO5G_SHIFT);
367432c4d1eSHauke Mehrtens 	SPEX(rssismf2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMF2G, 0);
368432c4d1eSHauke Mehrtens 	SPEX(rssismc2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMC2G,
369432c4d1eSHauke Mehrtens 	     SSB_SPROM8_RSSISMC2G_SHIFT);
370432c4d1eSHauke Mehrtens 	SPEX(rssisav2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISAV2G,
371432c4d1eSHauke Mehrtens 	     SSB_SPROM8_RSSISAV2G_SHIFT);
372432c4d1eSHauke Mehrtens 	SPEX(bxa2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_BXA2G,
373432c4d1eSHauke Mehrtens 	     SSB_SPROM8_BXA2G_SHIFT);
374432c4d1eSHauke Mehrtens 	SPEX(rssismf5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMF5G, 0);
375432c4d1eSHauke Mehrtens 	SPEX(rssismc5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMC5G,
376432c4d1eSHauke Mehrtens 	     SSB_SPROM8_RSSISMC5G_SHIFT);
377432c4d1eSHauke Mehrtens 	SPEX(rssisav5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISAV5G,
378432c4d1eSHauke Mehrtens 	     SSB_SPROM8_RSSISAV5G_SHIFT);
379432c4d1eSHauke Mehrtens 	SPEX(bxa5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_BXA5G,
380432c4d1eSHauke Mehrtens 	     SSB_SPROM8_BXA5G_SHIFT);
381432c4d1eSHauke Mehrtens 
382432c4d1eSHauke Mehrtens 	SPEX(pa0b0, SSB_SPROM8_PA0B0, ~0, 0);
383432c4d1eSHauke Mehrtens 	SPEX(pa0b1, SSB_SPROM8_PA0B1, ~0, 0);
384432c4d1eSHauke Mehrtens 	SPEX(pa0b2, SSB_SPROM8_PA0B2, ~0, 0);
385432c4d1eSHauke Mehrtens 	SPEX(pa1b0, SSB_SPROM8_PA1B0, ~0, 0);
386432c4d1eSHauke Mehrtens 	SPEX(pa1b1, SSB_SPROM8_PA1B1, ~0, 0);
387432c4d1eSHauke Mehrtens 	SPEX(pa1b2, SSB_SPROM8_PA1B2, ~0, 0);
388432c4d1eSHauke Mehrtens 	SPEX(pa1lob0, SSB_SPROM8_PA1LOB0, ~0, 0);
389432c4d1eSHauke Mehrtens 	SPEX(pa1lob1, SSB_SPROM8_PA1LOB1, ~0, 0);
390432c4d1eSHauke Mehrtens 	SPEX(pa1lob2, SSB_SPROM8_PA1LOB2, ~0, 0);
391432c4d1eSHauke Mehrtens 	SPEX(pa1hib0, SSB_SPROM8_PA1HIB0, ~0, 0);
392432c4d1eSHauke Mehrtens 	SPEX(pa1hib1, SSB_SPROM8_PA1HIB1, ~0, 0);
393432c4d1eSHauke Mehrtens 	SPEX(pa1hib2, SSB_SPROM8_PA1HIB2, ~0, 0);
394432c4d1eSHauke Mehrtens 	SPEX(cck2gpo, SSB_SPROM8_CCK2GPO, ~0, 0);
395432c4d1eSHauke Mehrtens 	SPEX32(ofdm2gpo, SSB_SPROM8_OFDM2GPO, ~0, 0);
396432c4d1eSHauke Mehrtens 	SPEX32(ofdm5glpo, SSB_SPROM8_OFDM5GLPO, ~0, 0);
397432c4d1eSHauke Mehrtens 	SPEX32(ofdm5gpo, SSB_SPROM8_OFDM5GPO, ~0, 0);
398432c4d1eSHauke Mehrtens 	SPEX32(ofdm5ghpo, SSB_SPROM8_OFDM5GHPO, ~0, 0);
399432c4d1eSHauke Mehrtens 
400432c4d1eSHauke Mehrtens 	/* Extract the antenna gain values. */
401d8aef323SRafał Miłecki 	bus->sprom.antenna_gain.a0 = sprom_extract_antgain(sprom,
402d8aef323SRafał Miłecki 							   SSB_SPROM8_AGAIN01,
403d8aef323SRafał Miłecki 							   SSB_SPROM8_AGAIN0,
404d8aef323SRafał Miłecki 							   SSB_SPROM8_AGAIN0_SHIFT);
405d8aef323SRafał Miłecki 	bus->sprom.antenna_gain.a1 = sprom_extract_antgain(sprom,
406d8aef323SRafał Miłecki 							   SSB_SPROM8_AGAIN01,
407d8aef323SRafał Miłecki 							   SSB_SPROM8_AGAIN1,
408d8aef323SRafał Miłecki 							   SSB_SPROM8_AGAIN1_SHIFT);
409d8aef323SRafał Miłecki 	bus->sprom.antenna_gain.a2 = sprom_extract_antgain(sprom,
410d8aef323SRafał Miłecki 							   SSB_SPROM8_AGAIN23,
411d8aef323SRafał Miłecki 							   SSB_SPROM8_AGAIN2,
412d8aef323SRafał Miłecki 							   SSB_SPROM8_AGAIN2_SHIFT);
413d8aef323SRafał Miłecki 	bus->sprom.antenna_gain.a3 = sprom_extract_antgain(sprom,
414d8aef323SRafał Miłecki 							   SSB_SPROM8_AGAIN23,
415d8aef323SRafał Miłecki 							   SSB_SPROM8_AGAIN3,
416d8aef323SRafał Miłecki 							   SSB_SPROM8_AGAIN3_SHIFT);
417e2da4bd3SHauke Mehrtens 
418e2da4bd3SHauke Mehrtens 	SPEX(leddc_on_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_ON,
419e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_LEDDC_ON_SHIFT);
420e2da4bd3SHauke Mehrtens 	SPEX(leddc_off_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_OFF,
421e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_LEDDC_OFF_SHIFT);
422e2da4bd3SHauke Mehrtens 
423e2da4bd3SHauke Mehrtens 	SPEX(txchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_TXCHAIN,
424e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_TXRXC_TXCHAIN_SHIFT);
425e2da4bd3SHauke Mehrtens 	SPEX(rxchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_RXCHAIN,
426e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_TXRXC_RXCHAIN_SHIFT);
427e2da4bd3SHauke Mehrtens 	SPEX(antswitch, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_SWITCH,
428e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_TXRXC_SWITCH_SHIFT);
429e2da4bd3SHauke Mehrtens 
430e2da4bd3SHauke Mehrtens 	SPEX(opo, SSB_SPROM8_OFDM2GPO, 0x00ff, 0);
431e2da4bd3SHauke Mehrtens 
432e2da4bd3SHauke Mehrtens 	SPEX_ARRAY8(mcs2gpo, SSB_SPROM8_2G_MCSPO, ~0, 0);
433e2da4bd3SHauke Mehrtens 	SPEX_ARRAY8(mcs5gpo, SSB_SPROM8_5G_MCSPO, ~0, 0);
434e2da4bd3SHauke Mehrtens 	SPEX_ARRAY8(mcs5glpo, SSB_SPROM8_5GL_MCSPO, ~0, 0);
435e2da4bd3SHauke Mehrtens 	SPEX_ARRAY8(mcs5ghpo, SSB_SPROM8_5GH_MCSPO, ~0, 0);
436e2da4bd3SHauke Mehrtens 
437e2da4bd3SHauke Mehrtens 	SPEX(rawtempsense, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_RAWTEMP,
438e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_RAWTS_RAWTEMP_SHIFT);
439e2da4bd3SHauke Mehrtens 	SPEX(measpower, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_MEASPOWER,
440e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_RAWTS_MEASPOWER_SHIFT);
441e2da4bd3SHauke Mehrtens 	SPEX(tempsense_slope, SSB_SPROM8_OPT_CORRX,
442e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_OPT_CORRX_TEMP_SLOPE,
443e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_OPT_CORRX_TEMP_SLOPE_SHIFT);
444e2da4bd3SHauke Mehrtens 	SPEX(tempcorrx, SSB_SPROM8_OPT_CORRX, SSB_SPROM8_OPT_CORRX_TEMPCORRX,
445e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_OPT_CORRX_TEMPCORRX_SHIFT);
446e2da4bd3SHauke Mehrtens 	SPEX(tempsense_option, SSB_SPROM8_OPT_CORRX,
447e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_OPT_CORRX_TEMP_OPTION,
448e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_OPT_CORRX_TEMP_OPTION_SHIFT);
449e2da4bd3SHauke Mehrtens 	SPEX(freqoffset_corr, SSB_SPROM8_HWIQ_IQSWP,
450e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR,
451e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR_SHIFT);
452e2da4bd3SHauke Mehrtens 	SPEX(iqcal_swp_dis, SSB_SPROM8_HWIQ_IQSWP,
453e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP,
454e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP_SHIFT);
455e2da4bd3SHauke Mehrtens 	SPEX(hw_iqcal_en, SSB_SPROM8_HWIQ_IQSWP, SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL,
456e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL_SHIFT);
457e2da4bd3SHauke Mehrtens 
458e2da4bd3SHauke Mehrtens 	SPEX(bw40po, SSB_SPROM8_BW40PO, ~0, 0);
459e2da4bd3SHauke Mehrtens 	SPEX(cddpo, SSB_SPROM8_CDDPO, ~0, 0);
460e2da4bd3SHauke Mehrtens 	SPEX(stbcpo, SSB_SPROM8_STBCPO, ~0, 0);
461e2da4bd3SHauke Mehrtens 	SPEX(bwduppo, SSB_SPROM8_BWDUPPO, ~0, 0);
462e2da4bd3SHauke Mehrtens 
463e2da4bd3SHauke Mehrtens 	SPEX(tempthresh, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_TRESH,
464e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_THERMAL_TRESH_SHIFT);
465e2da4bd3SHauke Mehrtens 	SPEX(tempoffset, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_OFFSET,
466e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_THERMAL_OFFSET_SHIFT);
467e2da4bd3SHauke Mehrtens 	SPEX(phycal_tempdelta, SSB_SPROM8_TEMPDELTA,
468e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_TEMPDELTA_PHYCAL,
469e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_TEMPDELTA_PHYCAL_SHIFT);
470e2da4bd3SHauke Mehrtens 	SPEX(temps_period, SSB_SPROM8_TEMPDELTA, SSB_SPROM8_TEMPDELTA_PERIOD,
471e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_TEMPDELTA_PERIOD_SHIFT);
472e2da4bd3SHauke Mehrtens 	SPEX(temps_hysteresis, SSB_SPROM8_TEMPDELTA,
473e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_TEMPDELTA_HYSTERESIS,
474e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_TEMPDELTA_HYSTERESIS_SHIFT);
47527f18dc2SRafał Miłecki }
47627f18dc2SRafał Miłecki 
47710d8493cSArend van Spriel /*
47810d8493cSArend van Spriel  * Indicates the presence of external SPROM.
47910d8493cSArend van Spriel  */
bcma_sprom_ext_available(struct bcma_bus * bus)48010d8493cSArend van Spriel static bool bcma_sprom_ext_available(struct bcma_bus *bus)
481a027237aSHauke Mehrtens {
48210d8493cSArend van Spriel 	u32 chip_status;
48310d8493cSArend van Spriel 	u32 srom_control;
48410d8493cSArend van Spriel 	u32 present_mask;
485a027237aSHauke Mehrtens 
48610d8493cSArend van Spriel 	if (bus->drv_cc.core->id.rev >= 31) {
487a027237aSHauke Mehrtens 		if (!(bus->drv_cc.capabilities & BCMA_CC_CAP_SPROM))
488a027237aSHauke Mehrtens 			return false;
489a027237aSHauke Mehrtens 
49010d8493cSArend van Spriel 		srom_control = bcma_read32(bus->drv_cc.core,
49110d8493cSArend van Spriel 					   BCMA_CC_SROM_CONTROL);
49210d8493cSArend van Spriel 		return srom_control & BCMA_CC_SROM_CONTROL_PRESENT;
493a027237aSHauke Mehrtens 	}
49410d8493cSArend van Spriel 
49510d8493cSArend van Spriel 	/* older chipcommon revisions use chip status register */
49610d8493cSArend van Spriel 	chip_status = bcma_read32(bus->drv_cc.core, BCMA_CC_CHIPSTAT);
49710d8493cSArend van Spriel 	switch (bus->chipinfo.id) {
4984b4f5be2SHauke Mehrtens 	case BCMA_CHIP_ID_BCM4313:
49910d8493cSArend van Spriel 		present_mask = BCMA_CC_CHIPST_4313_SPROM_PRESENT;
50010d8493cSArend van Spriel 		break;
50110d8493cSArend van Spriel 
5024b4f5be2SHauke Mehrtens 	case BCMA_CHIP_ID_BCM4331:
50310d8493cSArend van Spriel 		present_mask = BCMA_CC_CHIPST_4331_SPROM_PRESENT;
50410d8493cSArend van Spriel 		break;
50510d8493cSArend van Spriel 
50610d8493cSArend van Spriel 	default:
507a027237aSHauke Mehrtens 		return true;
508a027237aSHauke Mehrtens 	}
509a027237aSHauke Mehrtens 
51010d8493cSArend van Spriel 	return chip_status & present_mask;
51110d8493cSArend van Spriel }
51210d8493cSArend van Spriel 
51310d8493cSArend van Spriel /*
51410d8493cSArend van Spriel  * Indicates that on-chip OTP memory is present and enabled.
51510d8493cSArend van Spriel  */
bcma_sprom_onchip_available(struct bcma_bus * bus)51610d8493cSArend van Spriel static bool bcma_sprom_onchip_available(struct bcma_bus *bus)
51710d8493cSArend van Spriel {
51810d8493cSArend van Spriel 	u32 chip_status;
51910d8493cSArend van Spriel 	u32 otpsize = 0;
52010d8493cSArend van Spriel 	bool present;
52110d8493cSArend van Spriel 
52210d8493cSArend van Spriel 	chip_status = bcma_read32(bus->drv_cc.core, BCMA_CC_CHIPSTAT);
52310d8493cSArend van Spriel 	switch (bus->chipinfo.id) {
5244b4f5be2SHauke Mehrtens 	case BCMA_CHIP_ID_BCM4313:
52510d8493cSArend van Spriel 		present = chip_status & BCMA_CC_CHIPST_4313_OTP_PRESENT;
52610d8493cSArend van Spriel 		break;
52710d8493cSArend van Spriel 
5284b4f5be2SHauke Mehrtens 	case BCMA_CHIP_ID_BCM4331:
52910d8493cSArend van Spriel 		present = chip_status & BCMA_CC_CHIPST_4331_OTP_PRESENT;
53010d8493cSArend van Spriel 		break;
53188f9b65dSRafał Miłecki 	case BCMA_CHIP_ID_BCM43142:
5324b4f5be2SHauke Mehrtens 	case BCMA_CHIP_ID_BCM43224:
5334b4f5be2SHauke Mehrtens 	case BCMA_CHIP_ID_BCM43225:
53410d8493cSArend van Spriel 		/* for these chips OTP is always available */
53510d8493cSArend van Spriel 		present = true;
53610d8493cSArend van Spriel 		break;
53727cfdb05SRafał Miłecki 	case BCMA_CHIP_ID_BCM43131:
538d1d3799fSRafał Miłecki 	case BCMA_CHIP_ID_BCM43217:
539646e0827SRafał Miłecki 	case BCMA_CHIP_ID_BCM43227:
540c263c2c1SRafał Miłecki 	case BCMA_CHIP_ID_BCM43228:
541646e0827SRafał Miłecki 	case BCMA_CHIP_ID_BCM43428:
542c263c2c1SRafał Miłecki 		present = chip_status & BCMA_CC_CHIPST_43228_OTP_PRESENT;
543c263c2c1SRafał Miłecki 		break;
54410d8493cSArend van Spriel 	default:
54510d8493cSArend van Spriel 		present = false;
54610d8493cSArend van Spriel 		break;
54710d8493cSArend van Spriel 	}
54810d8493cSArend van Spriel 
54910d8493cSArend van Spriel 	if (present) {
55010d8493cSArend van Spriel 		otpsize = bus->drv_cc.capabilities & BCMA_CC_CAP_OTPS;
55110d8493cSArend van Spriel 		otpsize >>= BCMA_CC_CAP_OTPS_SHIFT;
55210d8493cSArend van Spriel 	}
55310d8493cSArend van Spriel 
55410d8493cSArend van Spriel 	return otpsize != 0;
55510d8493cSArend van Spriel }
55610d8493cSArend van Spriel 
55710d8493cSArend van Spriel /*
55810d8493cSArend van Spriel  * Verify OTP is filled and determine the byte
55910d8493cSArend van Spriel  * offset where SPROM data is located.
56010d8493cSArend van Spriel  *
56110d8493cSArend van Spriel  * On error, returns 0; byte offset otherwise.
56210d8493cSArend van Spriel  */
bcma_sprom_onchip_offset(struct bcma_bus * bus)56310d8493cSArend van Spriel static int bcma_sprom_onchip_offset(struct bcma_bus *bus)
56410d8493cSArend van Spriel {
56510d8493cSArend van Spriel 	struct bcma_device *cc = bus->drv_cc.core;
56610d8493cSArend van Spriel 	u32 offset;
56710d8493cSArend van Spriel 
56810d8493cSArend van Spriel 	/* verify OTP status */
56910d8493cSArend van Spriel 	if ((bcma_read32(cc, BCMA_CC_OTPS) & BCMA_CC_OTPS_GU_PROG_HW) == 0)
57010d8493cSArend van Spriel 		return 0;
57110d8493cSArend van Spriel 
57210d8493cSArend van Spriel 	/* obtain bit offset from otplayout register */
57310d8493cSArend van Spriel 	offset = (bcma_read32(cc, BCMA_CC_OTPL) & BCMA_CC_OTPL_GURGN_OFFSET);
57410d8493cSArend van Spriel 	return BCMA_CC_SPROM + (offset >> 3);
57510d8493cSArend van Spriel }
57610d8493cSArend van Spriel 
bcma_sprom_get(struct bcma_bus * bus)57727f18dc2SRafał Miłecki int bcma_sprom_get(struct bcma_bus *bus)
57827f18dc2SRafał Miłecki {
57910d8493cSArend van Spriel 	u16 offset = BCMA_CC_SPROM;
58027f18dc2SRafał Miłecki 	u16 *sprom;
581c57391f4SColin Ian King 	static const size_t sprom_sizes[] = {
582c57391f4SColin Ian King 		SSB_SPROMSIZE_WORDS_R4,
5833c313161SRafał Miłecki 		SSB_SPROMSIZE_WORDS_R10,
584c57391f4SColin Ian King 		SSB_SPROMSIZE_WORDS_R11,
585c57391f4SColin Ian King 	};
58692eb1642SRafał Miłecki 	int i, err = 0;
58727f18dc2SRafał Miłecki 
58827f18dc2SRafał Miłecki 	if (!bus->drv_cc.core)
58927f18dc2SRafał Miłecki 		return -EOPNOTSUPP;
59027f18dc2SRafał Miłecki 
59110d8493cSArend van Spriel 	if (!bcma_sprom_ext_available(bus)) {
59232998cc9SHauke Mehrtens 		bool sprom_onchip;
59332998cc9SHauke Mehrtens 
59410d8493cSArend van Spriel 		/*
59510d8493cSArend van Spriel 		 * External SPROM takes precedence so check
59610d8493cSArend van Spriel 		 * on-chip OTP only when no external SPROM
59710d8493cSArend van Spriel 		 * is present.
59810d8493cSArend van Spriel 		 */
59932998cc9SHauke Mehrtens 		sprom_onchip = bcma_sprom_onchip_available(bus);
60032998cc9SHauke Mehrtens 		if (sprom_onchip) {
60110d8493cSArend van Spriel 			/* determine offset */
60210d8493cSArend van Spriel 			offset = bcma_sprom_onchip_offset(bus);
60310d8493cSArend van Spriel 		}
60432998cc9SHauke Mehrtens 		if (!offset || !sprom_onchip) {
605a027237aSHauke Mehrtens 			/*
606a027237aSHauke Mehrtens 			 * Maybe there is no SPROM on the device?
607a027237aSHauke Mehrtens 			 * Now we ask the arch code if there is some sprom
608a027237aSHauke Mehrtens 			 * available for this device in some other storage.
609a027237aSHauke Mehrtens 			 */
610a027237aSHauke Mehrtens 			err = bcma_fill_sprom_with_fallback(bus, &bus->sprom);
6114ac887cfSArend van Spriel 			return err;
612d6865dccSHauke Mehrtens 		}
61310d8493cSArend van Spriel 	}
614d6865dccSHauke Mehrtens 
6154b4f5be2SHauke Mehrtens 	if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4331 ||
6164b4f5be2SHauke Mehrtens 	    bus->chipinfo.id == BCMA_CHIP_ID_BCM43431)
617984e5befSRafał Miłecki 		bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, false);
618984e5befSRafał Miłecki 
6193d9d8af3SRafał Miłecki 	bcma_debug(bus, "SPROM offset 0x%x\n", offset);
62092eb1642SRafał Miłecki 	for (i = 0; i < ARRAY_SIZE(sprom_sizes); i++) {
62192eb1642SRafał Miłecki 		size_t words = sprom_sizes[i];
62292eb1642SRafał Miłecki 
62392eb1642SRafał Miłecki 		sprom = kcalloc(words, sizeof(u16), GFP_KERNEL);
62492eb1642SRafał Miłecki 		if (!sprom)
62592eb1642SRafał Miłecki 			return -ENOMEM;
62692eb1642SRafał Miłecki 
62792eb1642SRafał Miłecki 		bcma_sprom_read(bus, offset, sprom, words);
62878e578c5SRafał Miłecki 		err = bcma_sprom_valid(bus, sprom, words);
62992eb1642SRafał Miłecki 		if (!err)
63092eb1642SRafał Miłecki 			break;
63192eb1642SRafał Miłecki 
63292eb1642SRafał Miłecki 		kfree(sprom);
63392eb1642SRafał Miłecki 	}
63427f18dc2SRafał Miłecki 
6354b4f5be2SHauke Mehrtens 	if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4331 ||
6364b4f5be2SHauke Mehrtens 	    bus->chipinfo.id == BCMA_CHIP_ID_BCM43431)
637984e5befSRafał Miłecki 		bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true);
638984e5befSRafał Miłecki 
639017c4c3bSHauke Mehrtens 	if (err) {
64092eb1642SRafał Miłecki 		bcma_warn(bus, "Invalid SPROM read from the PCIe card, trying to use fallback SPROM\n");
641017c4c3bSHauke Mehrtens 		err = bcma_fill_sprom_with_fallback(bus, &bus->sprom);
64292eb1642SRafał Miłecki 	} else {
64392eb1642SRafał Miłecki 		bcma_sprom_extract_r8(bus, sprom);
64492eb1642SRafał Miłecki 		kfree(sprom);
645017c4c3bSHauke Mehrtens 	}
64627f18dc2SRafał Miłecki 
64727f18dc2SRafał Miłecki 	return err;
64827f18dc2SRafał Miłecki }
649