xref: /openbmc/linux/drivers/ssb/pci.c (revision 33a606ac8020b47292bcfda30c7888c1ab5233e2)
161e115a5SMichael Buesch /*
261e115a5SMichael Buesch  * Sonics Silicon Backplane PCI-Hostbus related functions.
361e115a5SMichael Buesch  *
4eb032b98SMichael Büsch  * Copyright (C) 2005-2006 Michael Buesch <m@bues.ch>
561e115a5SMichael Buesch  * Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
661e115a5SMichael Buesch  * Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
761e115a5SMichael Buesch  * Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
861e115a5SMichael Buesch  * Copyright (C) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
961e115a5SMichael Buesch  *
1061e115a5SMichael Buesch  * Derived from the Broadcom 4400 device driver.
1161e115a5SMichael Buesch  * Copyright (C) 2002 David S. Miller (davem@redhat.com)
1261e115a5SMichael Buesch  * Fixed by Pekka Pietikainen (pp@ee.oulu.fi)
1361e115a5SMichael Buesch  * Copyright (C) 2006 Broadcom Corporation.
1461e115a5SMichael Buesch  *
1561e115a5SMichael Buesch  * Licensed under the GNU/GPL. See COPYING for details.
1661e115a5SMichael Buesch  */
1761e115a5SMichael Buesch 
1861e115a5SMichael Buesch #include <linux/ssb/ssb.h>
1961e115a5SMichael Buesch #include <linux/ssb/ssb_regs.h>
205a0e3ad6STejun Heo #include <linux/slab.h>
2161e115a5SMichael Buesch #include <linux/pci.h>
2261e115a5SMichael Buesch #include <linux/delay.h>
2361e115a5SMichael Buesch 
2461e115a5SMichael Buesch #include "ssb_private.h"
2561e115a5SMichael Buesch 
2661e115a5SMichael Buesch 
2761e115a5SMichael Buesch /* Define the following to 1 to enable a printk on each coreswitch. */
2861e115a5SMichael Buesch #define SSB_VERBOSE_PCICORESWITCH_DEBUG		0
2961e115a5SMichael Buesch 
3061e115a5SMichael Buesch 
3161e115a5SMichael Buesch /* Lowlevel coreswitching */
3261e115a5SMichael Buesch int ssb_pci_switch_coreidx(struct ssb_bus *bus, u8 coreidx)
3361e115a5SMichael Buesch {
3461e115a5SMichael Buesch 	int err;
3561e115a5SMichael Buesch 	int attempts = 0;
3661e115a5SMichael Buesch 	u32 cur_core;
3761e115a5SMichael Buesch 
3861e115a5SMichael Buesch 	while (1) {
3961e115a5SMichael Buesch 		err = pci_write_config_dword(bus->host_pci, SSB_BAR0_WIN,
4061e115a5SMichael Buesch 					     (coreidx * SSB_CORE_SIZE)
4161e115a5SMichael Buesch 					     + SSB_ENUM_BASE);
4261e115a5SMichael Buesch 		if (err)
4361e115a5SMichael Buesch 			goto error;
4461e115a5SMichael Buesch 		err = pci_read_config_dword(bus->host_pci, SSB_BAR0_WIN,
4561e115a5SMichael Buesch 					    &cur_core);
4661e115a5SMichael Buesch 		if (err)
4761e115a5SMichael Buesch 			goto error;
4861e115a5SMichael Buesch 		cur_core = (cur_core - SSB_ENUM_BASE)
4961e115a5SMichael Buesch 			   / SSB_CORE_SIZE;
5061e115a5SMichael Buesch 		if (cur_core == coreidx)
5161e115a5SMichael Buesch 			break;
5261e115a5SMichael Buesch 
5361e115a5SMichael Buesch 		if (attempts++ > SSB_BAR0_MAX_RETRIES)
5461e115a5SMichael Buesch 			goto error;
5561e115a5SMichael Buesch 		udelay(10);
5661e115a5SMichael Buesch 	}
5761e115a5SMichael Buesch 	return 0;
5861e115a5SMichael Buesch error:
59*33a606acSJoe Perches 	ssb_err("Failed to switch to core %u\n", coreidx);
6061e115a5SMichael Buesch 	return -ENODEV;
6161e115a5SMichael Buesch }
6261e115a5SMichael Buesch 
6361e115a5SMichael Buesch int ssb_pci_switch_core(struct ssb_bus *bus,
6461e115a5SMichael Buesch 			struct ssb_device *dev)
6561e115a5SMichael Buesch {
6661e115a5SMichael Buesch 	int err;
6761e115a5SMichael Buesch 	unsigned long flags;
6861e115a5SMichael Buesch 
6961e115a5SMichael Buesch #if SSB_VERBOSE_PCICORESWITCH_DEBUG
70*33a606acSJoe Perches 	ssb_info("Switching to %s core, index %d\n",
7161e115a5SMichael Buesch 		 ssb_core_name(dev->id.coreid),
7261e115a5SMichael Buesch 		 dev->core_index);
7361e115a5SMichael Buesch #endif
7461e115a5SMichael Buesch 
7561e115a5SMichael Buesch 	spin_lock_irqsave(&bus->bar_lock, flags);
7661e115a5SMichael Buesch 	err = ssb_pci_switch_coreidx(bus, dev->core_index);
7761e115a5SMichael Buesch 	if (!err)
7861e115a5SMichael Buesch 		bus->mapped_device = dev;
7961e115a5SMichael Buesch 	spin_unlock_irqrestore(&bus->bar_lock, flags);
8061e115a5SMichael Buesch 
8161e115a5SMichael Buesch 	return err;
8261e115a5SMichael Buesch }
8361e115a5SMichael Buesch 
8461e115a5SMichael Buesch /* Enable/disable the on board crystal oscillator and/or PLL. */
8561e115a5SMichael Buesch int ssb_pci_xtal(struct ssb_bus *bus, u32 what, int turn_on)
8661e115a5SMichael Buesch {
8761e115a5SMichael Buesch 	int err;
8861e115a5SMichael Buesch 	u32 in, out, outenable;
8961e115a5SMichael Buesch 	u16 pci_status;
9061e115a5SMichael Buesch 
9161e115a5SMichael Buesch 	if (bus->bustype != SSB_BUSTYPE_PCI)
9261e115a5SMichael Buesch 		return 0;
9361e115a5SMichael Buesch 
9461e115a5SMichael Buesch 	err = pci_read_config_dword(bus->host_pci, SSB_GPIO_IN, &in);
9561e115a5SMichael Buesch 	if (err)
9661e115a5SMichael Buesch 		goto err_pci;
9761e115a5SMichael Buesch 	err = pci_read_config_dword(bus->host_pci, SSB_GPIO_OUT, &out);
9861e115a5SMichael Buesch 	if (err)
9961e115a5SMichael Buesch 		goto err_pci;
10061e115a5SMichael Buesch 	err = pci_read_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE, &outenable);
10161e115a5SMichael Buesch 	if (err)
10261e115a5SMichael Buesch 		goto err_pci;
10361e115a5SMichael Buesch 
10461e115a5SMichael Buesch 	outenable |= what;
10561e115a5SMichael Buesch 
10661e115a5SMichael Buesch 	if (turn_on) {
10761e115a5SMichael Buesch 		/* Avoid glitching the clock if GPRS is already using it.
10861e115a5SMichael Buesch 		 * We can't actually read the state of the PLLPD so we infer it
10961e115a5SMichael Buesch 		 * by the value of XTAL_PU which *is* readable via gpioin.
11061e115a5SMichael Buesch 		 */
11161e115a5SMichael Buesch 		if (!(in & SSB_GPIO_XTAL)) {
11261e115a5SMichael Buesch 			if (what & SSB_GPIO_XTAL) {
11361e115a5SMichael Buesch 				/* Turn the crystal on */
11461e115a5SMichael Buesch 				out |= SSB_GPIO_XTAL;
11561e115a5SMichael Buesch 				if (what & SSB_GPIO_PLL)
11661e115a5SMichael Buesch 					out |= SSB_GPIO_PLL;
11761e115a5SMichael Buesch 				err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out);
11861e115a5SMichael Buesch 				if (err)
11961e115a5SMichael Buesch 					goto err_pci;
12061e115a5SMichael Buesch 				err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE,
12161e115a5SMichael Buesch 							     outenable);
12261e115a5SMichael Buesch 				if (err)
12361e115a5SMichael Buesch 					goto err_pci;
12461e115a5SMichael Buesch 				msleep(1);
12561e115a5SMichael Buesch 			}
12661e115a5SMichael Buesch 			if (what & SSB_GPIO_PLL) {
12761e115a5SMichael Buesch 				/* Turn the PLL on */
12861e115a5SMichael Buesch 				out &= ~SSB_GPIO_PLL;
12961e115a5SMichael Buesch 				err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out);
13061e115a5SMichael Buesch 				if (err)
13161e115a5SMichael Buesch 					goto err_pci;
13261e115a5SMichael Buesch 				msleep(5);
13361e115a5SMichael Buesch 			}
13461e115a5SMichael Buesch 		}
13561e115a5SMichael Buesch 
13661e115a5SMichael Buesch 		err = pci_read_config_word(bus->host_pci, PCI_STATUS, &pci_status);
13761e115a5SMichael Buesch 		if (err)
13861e115a5SMichael Buesch 			goto err_pci;
13961e115a5SMichael Buesch 		pci_status &= ~PCI_STATUS_SIG_TARGET_ABORT;
14061e115a5SMichael Buesch 		err = pci_write_config_word(bus->host_pci, PCI_STATUS, pci_status);
14161e115a5SMichael Buesch 		if (err)
14261e115a5SMichael Buesch 			goto err_pci;
14361e115a5SMichael Buesch 	} else {
14461e115a5SMichael Buesch 		if (what & SSB_GPIO_XTAL) {
14561e115a5SMichael Buesch 			/* Turn the crystal off */
14661e115a5SMichael Buesch 			out &= ~SSB_GPIO_XTAL;
14761e115a5SMichael Buesch 		}
14861e115a5SMichael Buesch 		if (what & SSB_GPIO_PLL) {
14961e115a5SMichael Buesch 			/* Turn the PLL off */
15061e115a5SMichael Buesch 			out |= SSB_GPIO_PLL;
15161e115a5SMichael Buesch 		}
15261e115a5SMichael Buesch 		err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out);
15361e115a5SMichael Buesch 		if (err)
15461e115a5SMichael Buesch 			goto err_pci;
15561e115a5SMichael Buesch 		err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE, outenable);
15661e115a5SMichael Buesch 		if (err)
15761e115a5SMichael Buesch 			goto err_pci;
15861e115a5SMichael Buesch 	}
15961e115a5SMichael Buesch 
16061e115a5SMichael Buesch out:
16161e115a5SMichael Buesch 	return err;
16261e115a5SMichael Buesch 
16361e115a5SMichael Buesch err_pci:
16461e115a5SMichael Buesch 	printk(KERN_ERR PFX "Error: ssb_pci_xtal() could not access PCI config space!\n");
16561e115a5SMichael Buesch 	err = -EBUSY;
16661e115a5SMichael Buesch 	goto out;
16761e115a5SMichael Buesch }
16861e115a5SMichael Buesch 
16961e115a5SMichael Buesch /* Get the word-offset for a SSB_SPROM_XXX define. */
1700a182fd8SRafał Miłecki #define SPOFF(offset)	((offset) / sizeof(u16))
17161e115a5SMichael Buesch /* Helper to extract some _offset, which is one of the SSB_SPROM_XXX defines. */
172f679056bSGábor Stefanik #define SPEX16(_outvar, _offset, _mask, _shift)	\
17361e115a5SMichael Buesch 	out->_outvar = ((in[SPOFF(_offset)] & (_mask)) >> (_shift))
174f679056bSGábor Stefanik #define SPEX32(_outvar, _offset, _mask, _shift)	\
175f679056bSGábor Stefanik 	out->_outvar = ((((u32)in[SPOFF((_offset)+2)] << 16 | \
176f679056bSGábor Stefanik 			   in[SPOFF(_offset)]) & (_mask)) >> (_shift))
177f679056bSGábor Stefanik #define SPEX(_outvar, _offset, _mask, _shift) \
178f679056bSGábor Stefanik 	SPEX16(_outvar, _offset, _mask, _shift)
179f679056bSGábor Stefanik 
180e2da4bd3SHauke Mehrtens #define SPEX_ARRAY8(_field, _offset, _mask, _shift)	\
181e2da4bd3SHauke Mehrtens 	do {	\
182e2da4bd3SHauke Mehrtens 		SPEX(_field[0], _offset +  0, _mask, _shift);	\
183e2da4bd3SHauke Mehrtens 		SPEX(_field[1], _offset +  2, _mask, _shift);	\
184e2da4bd3SHauke Mehrtens 		SPEX(_field[2], _offset +  4, _mask, _shift);	\
185e2da4bd3SHauke Mehrtens 		SPEX(_field[3], _offset +  6, _mask, _shift);	\
186e2da4bd3SHauke Mehrtens 		SPEX(_field[4], _offset +  8, _mask, _shift);	\
187e2da4bd3SHauke Mehrtens 		SPEX(_field[5], _offset + 10, _mask, _shift);	\
188e2da4bd3SHauke Mehrtens 		SPEX(_field[6], _offset + 12, _mask, _shift);	\
189e2da4bd3SHauke Mehrtens 		SPEX(_field[7], _offset + 14, _mask, _shift);	\
190e2da4bd3SHauke Mehrtens 	} while (0)
191e2da4bd3SHauke Mehrtens 
19261e115a5SMichael Buesch 
19361e115a5SMichael Buesch static inline u8 ssb_crc8(u8 crc, u8 data)
19461e115a5SMichael Buesch {
19561e115a5SMichael Buesch 	/* Polynomial:   x^8 + x^7 + x^6 + x^4 + x^2 + 1   */
19661e115a5SMichael Buesch 	static const u8 t[] = {
19761e115a5SMichael Buesch 		0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
19861e115a5SMichael Buesch 		0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
19961e115a5SMichael Buesch 		0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
20061e115a5SMichael Buesch 		0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
20161e115a5SMichael Buesch 		0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
20261e115a5SMichael Buesch 		0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
20361e115a5SMichael Buesch 		0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
20461e115a5SMichael Buesch 		0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
20561e115a5SMichael Buesch 		0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
20661e115a5SMichael Buesch 		0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
20761e115a5SMichael Buesch 		0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
20861e115a5SMichael Buesch 		0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
20961e115a5SMichael Buesch 		0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
21061e115a5SMichael Buesch 		0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
21161e115a5SMichael Buesch 		0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
21261e115a5SMichael Buesch 		0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
21361e115a5SMichael Buesch 		0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
21461e115a5SMichael Buesch 		0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
21561e115a5SMichael Buesch 		0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
21661e115a5SMichael Buesch 		0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
21761e115a5SMichael Buesch 		0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
21861e115a5SMichael Buesch 		0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
21961e115a5SMichael Buesch 		0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
22061e115a5SMichael Buesch 		0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
22161e115a5SMichael Buesch 		0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
22261e115a5SMichael Buesch 		0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
22361e115a5SMichael Buesch 		0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
22461e115a5SMichael Buesch 		0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
22561e115a5SMichael Buesch 		0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
22661e115a5SMichael Buesch 		0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
22761e115a5SMichael Buesch 		0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
22861e115a5SMichael Buesch 		0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F,
22961e115a5SMichael Buesch 	};
23061e115a5SMichael Buesch 	return t[crc ^ data];
23161e115a5SMichael Buesch }
23261e115a5SMichael Buesch 
233e5652756SJoe Perches static void sprom_get_mac(char *mac, const u16 *in)
234e5652756SJoe Perches {
235e5652756SJoe Perches 	int i;
236e5652756SJoe Perches 	for (i = 0; i < 3; i++) {
237e5652756SJoe Perches 		*mac++ = in[i];
238e5652756SJoe Perches 		*mac++ = in[i] >> 8;
239e5652756SJoe Perches 	}
240e5652756SJoe Perches }
241e5652756SJoe Perches 
242c272ef44SLarry Finger static u8 ssb_sprom_crc(const u16 *sprom, u16 size)
24361e115a5SMichael Buesch {
24461e115a5SMichael Buesch 	int word;
24561e115a5SMichael Buesch 	u8 crc = 0xFF;
24661e115a5SMichael Buesch 
247c272ef44SLarry Finger 	for (word = 0; word < size - 1; word++) {
24861e115a5SMichael Buesch 		crc = ssb_crc8(crc, sprom[word] & 0x00FF);
24961e115a5SMichael Buesch 		crc = ssb_crc8(crc, (sprom[word] & 0xFF00) >> 8);
25061e115a5SMichael Buesch 	}
251c272ef44SLarry Finger 	crc = ssb_crc8(crc, sprom[size - 1] & 0x00FF);
25261e115a5SMichael Buesch 	crc ^= 0xFF;
25361e115a5SMichael Buesch 
25461e115a5SMichael Buesch 	return crc;
25561e115a5SMichael Buesch }
25661e115a5SMichael Buesch 
257e7ec2e32SMichael Buesch static int sprom_check_crc(const u16 *sprom, size_t size)
25861e115a5SMichael Buesch {
25961e115a5SMichael Buesch 	u8 crc;
26061e115a5SMichael Buesch 	u8 expected_crc;
26161e115a5SMichael Buesch 	u16 tmp;
26261e115a5SMichael Buesch 
263c272ef44SLarry Finger 	crc = ssb_sprom_crc(sprom, size);
264c272ef44SLarry Finger 	tmp = sprom[size - 1] & SSB_SPROM_REVISION_CRC;
26561e115a5SMichael Buesch 	expected_crc = tmp >> SSB_SPROM_REVISION_CRC_SHIFT;
26661e115a5SMichael Buesch 	if (crc != expected_crc)
26761e115a5SMichael Buesch 		return -EPROTO;
26861e115a5SMichael Buesch 
26961e115a5SMichael Buesch 	return 0;
27061e115a5SMichael Buesch }
27161e115a5SMichael Buesch 
272e7ec2e32SMichael Buesch static int sprom_do_read(struct ssb_bus *bus, u16 *sprom)
27361e115a5SMichael Buesch {
27461e115a5SMichael Buesch 	int i;
27561e115a5SMichael Buesch 
276c272ef44SLarry Finger 	for (i = 0; i < bus->sprom_size; i++)
277ea2db495SRafał Miłecki 		sprom[i] = ioread16(bus->mmio + bus->sprom_offset + (i * 2));
278e7ec2e32SMichael Buesch 
279e7ec2e32SMichael Buesch 	return 0;
28061e115a5SMichael Buesch }
28161e115a5SMichael Buesch 
28261e115a5SMichael Buesch static int sprom_do_write(struct ssb_bus *bus, const u16 *sprom)
28361e115a5SMichael Buesch {
28461e115a5SMichael Buesch 	struct pci_dev *pdev = bus->host_pci;
28561e115a5SMichael Buesch 	int i, err;
28661e115a5SMichael Buesch 	u32 spromctl;
287c272ef44SLarry Finger 	u16 size = bus->sprom_size;
28861e115a5SMichael Buesch 
289*33a606acSJoe Perches 	ssb_notice("Writing SPROM. Do NOT turn off the power! Please stand by...\n");
29061e115a5SMichael Buesch 	err = pci_read_config_dword(pdev, SSB_SPROMCTL, &spromctl);
29161e115a5SMichael Buesch 	if (err)
29261e115a5SMichael Buesch 		goto err_ctlreg;
29361e115a5SMichael Buesch 	spromctl |= SSB_SPROMCTL_WE;
29461e115a5SMichael Buesch 	err = pci_write_config_dword(pdev, SSB_SPROMCTL, spromctl);
29561e115a5SMichael Buesch 	if (err)
29661e115a5SMichael Buesch 		goto err_ctlreg;
297*33a606acSJoe Perches 	ssb_notice("[ 0%%");
29861e115a5SMichael Buesch 	msleep(500);
299c272ef44SLarry Finger 	for (i = 0; i < size; i++) {
300c272ef44SLarry Finger 		if (i == size / 4)
301*33a606acSJoe Perches 			ssb_cont("25%%");
302c272ef44SLarry Finger 		else if (i == size / 2)
303*33a606acSJoe Perches 			ssb_cont("50%%");
304c272ef44SLarry Finger 		else if (i == (size * 3) / 4)
305*33a606acSJoe Perches 			ssb_cont("75%%");
30661e115a5SMichael Buesch 		else if (i % 2)
307*33a606acSJoe Perches 			ssb_cont(".");
308ea2db495SRafał Miłecki 		writew(sprom[i], bus->mmio + bus->sprom_offset + (i * 2));
30961e115a5SMichael Buesch 		mmiowb();
31061e115a5SMichael Buesch 		msleep(20);
31161e115a5SMichael Buesch 	}
31261e115a5SMichael Buesch 	err = pci_read_config_dword(pdev, SSB_SPROMCTL, &spromctl);
31361e115a5SMichael Buesch 	if (err)
31461e115a5SMichael Buesch 		goto err_ctlreg;
31561e115a5SMichael Buesch 	spromctl &= ~SSB_SPROMCTL_WE;
31661e115a5SMichael Buesch 	err = pci_write_config_dword(pdev, SSB_SPROMCTL, spromctl);
31761e115a5SMichael Buesch 	if (err)
31861e115a5SMichael Buesch 		goto err_ctlreg;
31961e115a5SMichael Buesch 	msleep(500);
320*33a606acSJoe Perches 	ssb_cont("100%% ]\n");
321*33a606acSJoe Perches 	ssb_notice("SPROM written\n");
32261e115a5SMichael Buesch 
32361e115a5SMichael Buesch 	return 0;
32461e115a5SMichael Buesch err_ctlreg:
325*33a606acSJoe Perches 	ssb_err("Could not access SPROM control register.\n");
32661e115a5SMichael Buesch 	return err;
32761e115a5SMichael Buesch }
32861e115a5SMichael Buesch 
329e861b98dSMichael Buesch static s8 r123_extract_antgain(u8 sprom_revision, const u16 *in,
330e861b98dSMichael Buesch 			       u16 mask, u16 shift)
331e861b98dSMichael Buesch {
332e861b98dSMichael Buesch 	u16 v;
333e861b98dSMichael Buesch 	u8 gain;
334e861b98dSMichael Buesch 
335e861b98dSMichael Buesch 	v = in[SPOFF(SSB_SPROM1_AGAIN)];
336e861b98dSMichael Buesch 	gain = (v & mask) >> shift;
337e861b98dSMichael Buesch 	if (gain == 0xFF)
338e861b98dSMichael Buesch 		gain = 2; /* If unset use 2dBm */
339e861b98dSMichael Buesch 	if (sprom_revision == 1) {
340e861b98dSMichael Buesch 		/* Convert to Q5.2 */
341e861b98dSMichael Buesch 		gain <<= 2;
342e861b98dSMichael Buesch 	} else {
343e861b98dSMichael Buesch 		/* Q5.2 Fractional part is stored in 0xC0 */
344e861b98dSMichael Buesch 		gain = ((gain & 0xC0) >> 6) | ((gain & 0x3F) << 2);
345e861b98dSMichael Buesch 	}
346e861b98dSMichael Buesch 
347e861b98dSMichael Buesch 	return (s8)gain;
348e861b98dSMichael Buesch }
349e861b98dSMichael Buesch 
350c272ef44SLarry Finger static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in)
351c272ef44SLarry Finger {
352c272ef44SLarry Finger 	u16 loc[3];
353c272ef44SLarry Finger 
35431ce12fbSLarry Finger 	if (out->revision == 3)			/* rev 3 moved MAC */
355c272ef44SLarry Finger 		loc[0] = SSB_SPROM3_IL0MAC;
35631ce12fbSLarry Finger 	else {
357c272ef44SLarry Finger 		loc[0] = SSB_SPROM1_IL0MAC;
358c272ef44SLarry Finger 		loc[1] = SSB_SPROM1_ET0MAC;
359c272ef44SLarry Finger 		loc[2] = SSB_SPROM1_ET1MAC;
360c272ef44SLarry Finger 	}
361e5652756SJoe Perches 	sprom_get_mac(out->il0mac, &in[SPOFF(loc[0])]);
36231ce12fbSLarry Finger 	if (out->revision < 3) { 	/* only rev 1-2 have et0, et1 */
363e5652756SJoe Perches 		sprom_get_mac(out->et0mac, &in[SPOFF(loc[1])]);
364e5652756SJoe Perches 		sprom_get_mac(out->et1mac, &in[SPOFF(loc[2])]);
36531ce12fbSLarry Finger 	}
366c272ef44SLarry Finger 	SPEX(et0phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0A, 0);
367c272ef44SLarry Finger 	SPEX(et1phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1A,
368c272ef44SLarry Finger 	     SSB_SPROM1_ETHPHY_ET1A_SHIFT);
369e861b98dSMichael Buesch 	SPEX(et0mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0M, 14);
370e861b98dSMichael Buesch 	SPEX(et1mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1M, 15);
371e861b98dSMichael Buesch 	SPEX(board_rev, SSB_SPROM1_BINF, SSB_SPROM1_BINF_BREV, 0);
372bf7d420bSHauke Mehrtens 	if (out->revision == 1)
373c272ef44SLarry Finger 		SPEX(country_code, SSB_SPROM1_BINF, SSB_SPROM1_BINF_CCODE,
374c272ef44SLarry Finger 		     SSB_SPROM1_BINF_CCODE_SHIFT);
375e861b98dSMichael Buesch 	SPEX(ant_available_a, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTA,
376e861b98dSMichael Buesch 	     SSB_SPROM1_BINF_ANTA_SHIFT);
377e861b98dSMichael Buesch 	SPEX(ant_available_bg, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTBG,
378e861b98dSMichael Buesch 	     SSB_SPROM1_BINF_ANTBG_SHIFT);
379c272ef44SLarry Finger 	SPEX(pa0b0, SSB_SPROM1_PA0B0, 0xFFFF, 0);
380c272ef44SLarry Finger 	SPEX(pa0b1, SSB_SPROM1_PA0B1, 0xFFFF, 0);
381c272ef44SLarry Finger 	SPEX(pa0b2, SSB_SPROM1_PA0B2, 0xFFFF, 0);
382c272ef44SLarry Finger 	SPEX(pa1b0, SSB_SPROM1_PA1B0, 0xFFFF, 0);
383c272ef44SLarry Finger 	SPEX(pa1b1, SSB_SPROM1_PA1B1, 0xFFFF, 0);
384c272ef44SLarry Finger 	SPEX(pa1b2, SSB_SPROM1_PA1B2, 0xFFFF, 0);
385c272ef44SLarry Finger 	SPEX(gpio0, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P0, 0);
386c272ef44SLarry Finger 	SPEX(gpio1, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P1,
387c272ef44SLarry Finger 	     SSB_SPROM1_GPIOA_P1_SHIFT);
388c272ef44SLarry Finger 	SPEX(gpio2, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P2, 0);
389c272ef44SLarry Finger 	SPEX(gpio3, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P3,
390c272ef44SLarry Finger 	     SSB_SPROM1_GPIOB_P3_SHIFT);
391c272ef44SLarry Finger 	SPEX(maxpwr_a, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_A,
392c272ef44SLarry Finger 	     SSB_SPROM1_MAXPWR_A_SHIFT);
393c272ef44SLarry Finger 	SPEX(maxpwr_bg, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_BG, 0);
394c272ef44SLarry Finger 	SPEX(itssi_a, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_A,
395c272ef44SLarry Finger 	     SSB_SPROM1_ITSSI_A_SHIFT);
396c272ef44SLarry Finger 	SPEX(itssi_bg, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_BG, 0);
397c272ef44SLarry Finger 	SPEX(boardflags_lo, SSB_SPROM1_BFLLO, 0xFFFF, 0);
398af4b7450SMichael Buesch 	if (out->revision >= 2)
399af4b7450SMichael Buesch 		SPEX(boardflags_hi, SSB_SPROM2_BFLHI, 0xFFFF, 0);
400bf7d420bSHauke Mehrtens 	SPEX(alpha2[0], SSB_SPROM1_CCODE, 0xff00, 8);
401bf7d420bSHauke Mehrtens 	SPEX(alpha2[1], SSB_SPROM1_CCODE, 0x00ff, 0);
402e861b98dSMichael Buesch 
403e861b98dSMichael Buesch 	/* Extract the antenna gain values. */
404f8f8a660SHauke Mehrtens 	out->antenna_gain.a0 = r123_extract_antgain(out->revision, in,
405e861b98dSMichael Buesch 						    SSB_SPROM1_AGAIN_BG,
406c272ef44SLarry Finger 						    SSB_SPROM1_AGAIN_BG_SHIFT);
407f8f8a660SHauke Mehrtens 	out->antenna_gain.a1 = r123_extract_antgain(out->revision, in,
408e861b98dSMichael Buesch 						    SSB_SPROM1_AGAIN_A,
409e861b98dSMichael Buesch 						    SSB_SPROM1_AGAIN_A_SHIFT);
410c272ef44SLarry Finger }
411c272ef44SLarry Finger 
412172c69a4SRafał Miłecki /* Revs 4 5 and 8 have partially shared layout */
413172c69a4SRafał Miłecki static void sprom_extract_r458(struct ssb_sprom *out, const u16 *in)
414172c69a4SRafał Miłecki {
415172c69a4SRafał Miłecki 	SPEX(txpid2g[0], SSB_SPROM4_TXPID2G01,
416172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID2G0, SSB_SPROM4_TXPID2G0_SHIFT);
417172c69a4SRafał Miłecki 	SPEX(txpid2g[1], SSB_SPROM4_TXPID2G01,
418172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID2G1, SSB_SPROM4_TXPID2G1_SHIFT);
419172c69a4SRafał Miłecki 	SPEX(txpid2g[2], SSB_SPROM4_TXPID2G23,
420172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID2G2, SSB_SPROM4_TXPID2G2_SHIFT);
421172c69a4SRafał Miłecki 	SPEX(txpid2g[3], SSB_SPROM4_TXPID2G23,
422172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID2G3, SSB_SPROM4_TXPID2G3_SHIFT);
423172c69a4SRafał Miłecki 
424172c69a4SRafał Miłecki 	SPEX(txpid5gl[0], SSB_SPROM4_TXPID5GL01,
425172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID5GL0, SSB_SPROM4_TXPID5GL0_SHIFT);
426172c69a4SRafał Miłecki 	SPEX(txpid5gl[1], SSB_SPROM4_TXPID5GL01,
427172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID5GL1, SSB_SPROM4_TXPID5GL1_SHIFT);
428172c69a4SRafał Miłecki 	SPEX(txpid5gl[2], SSB_SPROM4_TXPID5GL23,
429172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID5GL2, SSB_SPROM4_TXPID5GL2_SHIFT);
430172c69a4SRafał Miłecki 	SPEX(txpid5gl[3], SSB_SPROM4_TXPID5GL23,
431172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID5GL3, SSB_SPROM4_TXPID5GL3_SHIFT);
432172c69a4SRafał Miłecki 
433172c69a4SRafał Miłecki 	SPEX(txpid5g[0], SSB_SPROM4_TXPID5G01,
434172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID5G0, SSB_SPROM4_TXPID5G0_SHIFT);
435172c69a4SRafał Miłecki 	SPEX(txpid5g[1], SSB_SPROM4_TXPID5G01,
436172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID5G1, SSB_SPROM4_TXPID5G1_SHIFT);
437172c69a4SRafał Miłecki 	SPEX(txpid5g[2], SSB_SPROM4_TXPID5G23,
438172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID5G2, SSB_SPROM4_TXPID5G2_SHIFT);
439172c69a4SRafał Miłecki 	SPEX(txpid5g[3], SSB_SPROM4_TXPID5G23,
440172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID5G3, SSB_SPROM4_TXPID5G3_SHIFT);
441172c69a4SRafał Miłecki 
442172c69a4SRafał Miłecki 	SPEX(txpid5gh[0], SSB_SPROM4_TXPID5GH01,
443172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID5GH0, SSB_SPROM4_TXPID5GH0_SHIFT);
444172c69a4SRafał Miłecki 	SPEX(txpid5gh[1], SSB_SPROM4_TXPID5GH01,
445172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID5GH1, SSB_SPROM4_TXPID5GH1_SHIFT);
446172c69a4SRafał Miłecki 	SPEX(txpid5gh[2], SSB_SPROM4_TXPID5GH23,
447172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID5GH2, SSB_SPROM4_TXPID5GH2_SHIFT);
448172c69a4SRafał Miłecki 	SPEX(txpid5gh[3], SSB_SPROM4_TXPID5GH23,
449172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID5GH3, SSB_SPROM4_TXPID5GH3_SHIFT);
450172c69a4SRafał Miłecki }
451172c69a4SRafał Miłecki 
452095f695cSLarry Finger static void sprom_extract_r45(struct ssb_sprom *out, const u16 *in)
45361e115a5SMichael Buesch {
454095f695cSLarry Finger 	u16 il0mac_offset;
45561e115a5SMichael Buesch 
456095f695cSLarry Finger 	if (out->revision == 4)
457095f695cSLarry Finger 		il0mac_offset = SSB_SPROM4_IL0MAC;
458095f695cSLarry Finger 	else
459095f695cSLarry Finger 		il0mac_offset = SSB_SPROM5_IL0MAC;
460e5652756SJoe Perches 
461e5652756SJoe Perches 	sprom_get_mac(out->il0mac, &in[SPOFF(il0mac_offset)]);
462e5652756SJoe Perches 
463c272ef44SLarry Finger 	SPEX(et0phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET0A, 0);
464c272ef44SLarry Finger 	SPEX(et1phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET1A,
465c272ef44SLarry Finger 	     SSB_SPROM4_ETHPHY_ET1A_SHIFT);
466673335c8SHauke Mehrtens 	SPEX(board_rev, SSB_SPROM4_BOARDREV, 0xFFFF, 0);
467095f695cSLarry Finger 	if (out->revision == 4) {
468bf7d420bSHauke Mehrtens 		SPEX(alpha2[0], SSB_SPROM4_CCODE, 0xff00, 8);
469bf7d420bSHauke Mehrtens 		SPEX(alpha2[1], SSB_SPROM4_CCODE, 0x00ff, 0);
470c272ef44SLarry Finger 		SPEX(boardflags_lo, SSB_SPROM4_BFLLO, 0xFFFF, 0);
471af4b7450SMichael Buesch 		SPEX(boardflags_hi, SSB_SPROM4_BFLHI, 0xFFFF, 0);
4726d1d4ea4SRafał Miłecki 		SPEX(boardflags2_lo, SSB_SPROM4_BFL2LO, 0xFFFF, 0);
4736d1d4ea4SRafał Miłecki 		SPEX(boardflags2_hi, SSB_SPROM4_BFL2HI, 0xFFFF, 0);
474095f695cSLarry Finger 	} else {
475bf7d420bSHauke Mehrtens 		SPEX(alpha2[0], SSB_SPROM5_CCODE, 0xff00, 8);
476bf7d420bSHauke Mehrtens 		SPEX(alpha2[1], SSB_SPROM5_CCODE, 0x00ff, 0);
477095f695cSLarry Finger 		SPEX(boardflags_lo, SSB_SPROM5_BFLLO, 0xFFFF, 0);
478095f695cSLarry Finger 		SPEX(boardflags_hi, SSB_SPROM5_BFLHI, 0xFFFF, 0);
4796d1d4ea4SRafał Miłecki 		SPEX(boardflags2_lo, SSB_SPROM5_BFL2LO, 0xFFFF, 0);
4806d1d4ea4SRafał Miłecki 		SPEX(boardflags2_hi, SSB_SPROM5_BFL2HI, 0xFFFF, 0);
481095f695cSLarry Finger 	}
482e861b98dSMichael Buesch 	SPEX(ant_available_a, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_A,
483e861b98dSMichael Buesch 	     SSB_SPROM4_ANTAVAIL_A_SHIFT);
484e861b98dSMichael Buesch 	SPEX(ant_available_bg, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_BG,
485e861b98dSMichael Buesch 	     SSB_SPROM4_ANTAVAIL_BG_SHIFT);
486d3c319f9SLarry Finger 	SPEX(maxpwr_bg, SSB_SPROM4_MAXP_BG, SSB_SPROM4_MAXP_BG_MASK, 0);
487d3c319f9SLarry Finger 	SPEX(itssi_bg, SSB_SPROM4_MAXP_BG, SSB_SPROM4_ITSSI_BG,
488d3c319f9SLarry Finger 	     SSB_SPROM4_ITSSI_BG_SHIFT);
489d3c319f9SLarry Finger 	SPEX(maxpwr_a, SSB_SPROM4_MAXP_A, SSB_SPROM4_MAXP_A_MASK, 0);
490d3c319f9SLarry Finger 	SPEX(itssi_a, SSB_SPROM4_MAXP_A, SSB_SPROM4_ITSSI_A,
491d3c319f9SLarry Finger 	     SSB_SPROM4_ITSSI_A_SHIFT);
492095f695cSLarry Finger 	if (out->revision == 4) {
493d3c319f9SLarry Finger 		SPEX(gpio0, SSB_SPROM4_GPIOA, SSB_SPROM4_GPIOA_P0, 0);
494d3c319f9SLarry Finger 		SPEX(gpio1, SSB_SPROM4_GPIOA, SSB_SPROM4_GPIOA_P1,
495d3c319f9SLarry Finger 		     SSB_SPROM4_GPIOA_P1_SHIFT);
496d3c319f9SLarry Finger 		SPEX(gpio2, SSB_SPROM4_GPIOB, SSB_SPROM4_GPIOB_P2, 0);
497d3c319f9SLarry Finger 		SPEX(gpio3, SSB_SPROM4_GPIOB, SSB_SPROM4_GPIOB_P3,
498d3c319f9SLarry Finger 		     SSB_SPROM4_GPIOB_P3_SHIFT);
499095f695cSLarry Finger 	} else {
500095f695cSLarry Finger 		SPEX(gpio0, SSB_SPROM5_GPIOA, SSB_SPROM5_GPIOA_P0, 0);
501095f695cSLarry Finger 		SPEX(gpio1, SSB_SPROM5_GPIOA, SSB_SPROM5_GPIOA_P1,
502095f695cSLarry Finger 		     SSB_SPROM5_GPIOA_P1_SHIFT);
503095f695cSLarry Finger 		SPEX(gpio2, SSB_SPROM5_GPIOB, SSB_SPROM5_GPIOB_P2, 0);
504095f695cSLarry Finger 		SPEX(gpio3, SSB_SPROM5_GPIOB, SSB_SPROM5_GPIOB_P3,
505095f695cSLarry Finger 		     SSB_SPROM5_GPIOB_P3_SHIFT);
506095f695cSLarry Finger 	}
507e861b98dSMichael Buesch 
508e861b98dSMichael Buesch 	/* Extract the antenna gain values. */
509f8f8a660SHauke Mehrtens 	SPEX(antenna_gain.a0, SSB_SPROM4_AGAIN01,
510e861b98dSMichael Buesch 	     SSB_SPROM4_AGAIN0, SSB_SPROM4_AGAIN0_SHIFT);
511f8f8a660SHauke Mehrtens 	SPEX(antenna_gain.a1, SSB_SPROM4_AGAIN01,
512e861b98dSMichael Buesch 	     SSB_SPROM4_AGAIN1, SSB_SPROM4_AGAIN1_SHIFT);
513f8f8a660SHauke Mehrtens 	SPEX(antenna_gain.a2, SSB_SPROM4_AGAIN23,
514e861b98dSMichael Buesch 	     SSB_SPROM4_AGAIN2, SSB_SPROM4_AGAIN2_SHIFT);
515f8f8a660SHauke Mehrtens 	SPEX(antenna_gain.a3, SSB_SPROM4_AGAIN23,
516e861b98dSMichael Buesch 	     SSB_SPROM4_AGAIN3, SSB_SPROM4_AGAIN3_SHIFT);
517e861b98dSMichael Buesch 
518172c69a4SRafał Miłecki 	sprom_extract_r458(out, in);
519172c69a4SRafał Miłecki 
520c272ef44SLarry Finger 	/* TODO - get remaining rev 4 stuff needed */
52161e115a5SMichael Buesch }
52261e115a5SMichael Buesch 
5236b1c7c67SMichael Buesch static void sprom_extract_r8(struct ssb_sprom *out, const u16 *in)
5246b1c7c67SMichael Buesch {
5256b1c7c67SMichael Buesch 	int i;
526e5652756SJoe Perches 	u16 o;
527b0f70292SRafał Miłecki 	u16 pwr_info_offset[] = {
528b0f70292SRafał Miłecki 		SSB_SROM8_PWR_INFO_CORE0, SSB_SROM8_PWR_INFO_CORE1,
529b0f70292SRafał Miłecki 		SSB_SROM8_PWR_INFO_CORE2, SSB_SROM8_PWR_INFO_CORE3
530b0f70292SRafał Miłecki 	};
531b0f70292SRafał Miłecki 	BUILD_BUG_ON(ARRAY_SIZE(pwr_info_offset) !=
532b0f70292SRafał Miłecki 			ARRAY_SIZE(out->core_pwr_info));
5336b1c7c67SMichael Buesch 
5346b1c7c67SMichael Buesch 	/* extract the MAC address */
535e5652756SJoe Perches 	sprom_get_mac(out->il0mac, &in[SPOFF(SSB_SPROM8_IL0MAC)]);
536e5652756SJoe Perches 
537673335c8SHauke Mehrtens 	SPEX(board_rev, SSB_SPROM8_BOARDREV, 0xFFFF, 0);
538bf7d420bSHauke Mehrtens 	SPEX(alpha2[0], SSB_SPROM8_CCODE, 0xff00, 8);
539bf7d420bSHauke Mehrtens 	SPEX(alpha2[1], SSB_SPROM8_CCODE, 0x00ff, 0);
5406b1c7c67SMichael Buesch 	SPEX(boardflags_lo, SSB_SPROM8_BFLLO, 0xFFFF, 0);
5416b1c7c67SMichael Buesch 	SPEX(boardflags_hi, SSB_SPROM8_BFLHI, 0xFFFF, 0);
542f679056bSGábor Stefanik 	SPEX(boardflags2_lo, SSB_SPROM8_BFL2LO, 0xFFFF, 0);
543f679056bSGábor Stefanik 	SPEX(boardflags2_hi, SSB_SPROM8_BFL2HI, 0xFFFF, 0);
5446b1c7c67SMichael Buesch 	SPEX(ant_available_a, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_A,
5456b1c7c67SMichael Buesch 	     SSB_SPROM8_ANTAVAIL_A_SHIFT);
5466b1c7c67SMichael Buesch 	SPEX(ant_available_bg, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_BG,
5476b1c7c67SMichael Buesch 	     SSB_SPROM8_ANTAVAIL_BG_SHIFT);
5486b1c7c67SMichael Buesch 	SPEX(maxpwr_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_MAXP_BG_MASK, 0);
5496b1c7c67SMichael Buesch 	SPEX(itssi_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_ITSSI_BG,
5506b1c7c67SMichael Buesch 	     SSB_SPROM8_ITSSI_BG_SHIFT);
5516b1c7c67SMichael Buesch 	SPEX(maxpwr_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_MAXP_A_MASK, 0);
5526b1c7c67SMichael Buesch 	SPEX(itssi_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_ITSSI_A,
5536b1c7c67SMichael Buesch 	     SSB_SPROM8_ITSSI_A_SHIFT);
554f679056bSGábor Stefanik 	SPEX(maxpwr_ah, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AH_MASK, 0);
555f679056bSGábor Stefanik 	SPEX(maxpwr_al, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AL_MASK,
556f679056bSGábor Stefanik 	     SSB_SPROM8_MAXP_AL_SHIFT);
5576b1c7c67SMichael Buesch 	SPEX(gpio0, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P0, 0);
5586b1c7c67SMichael Buesch 	SPEX(gpio1, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P1,
5596b1c7c67SMichael Buesch 	     SSB_SPROM8_GPIOA_P1_SHIFT);
5606b1c7c67SMichael Buesch 	SPEX(gpio2, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P2, 0);
5616b1c7c67SMichael Buesch 	SPEX(gpio3, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P3,
5626b1c7c67SMichael Buesch 	     SSB_SPROM8_GPIOB_P3_SHIFT);
563f679056bSGábor Stefanik 	SPEX(tri2g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI2G, 0);
564f679056bSGábor Stefanik 	SPEX(tri5g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI5G,
565f679056bSGábor Stefanik 	     SSB_SPROM8_TRI5G_SHIFT);
566f679056bSGábor Stefanik 	SPEX(tri5gl, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GL, 0);
567f679056bSGábor Stefanik 	SPEX(tri5gh, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GH,
568f679056bSGábor Stefanik 	     SSB_SPROM8_TRI5GH_SHIFT);
569f679056bSGábor Stefanik 	SPEX(rxpo2g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO2G, 0);
570f679056bSGábor Stefanik 	SPEX(rxpo5g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO5G,
571f679056bSGábor Stefanik 	     SSB_SPROM8_RXPO5G_SHIFT);
572f679056bSGábor Stefanik 	SPEX(rssismf2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMF2G, 0);
573f679056bSGábor Stefanik 	SPEX(rssismc2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMC2G,
574f679056bSGábor Stefanik 	     SSB_SPROM8_RSSISMC2G_SHIFT);
575f679056bSGábor Stefanik 	SPEX(rssisav2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISAV2G,
576f679056bSGábor Stefanik 	     SSB_SPROM8_RSSISAV2G_SHIFT);
577f679056bSGábor Stefanik 	SPEX(bxa2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_BXA2G,
578f679056bSGábor Stefanik 	     SSB_SPROM8_BXA2G_SHIFT);
579f679056bSGábor Stefanik 	SPEX(rssismf5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMF5G, 0);
580f679056bSGábor Stefanik 	SPEX(rssismc5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMC5G,
581f679056bSGábor Stefanik 	     SSB_SPROM8_RSSISMC5G_SHIFT);
582f679056bSGábor Stefanik 	SPEX(rssisav5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISAV5G,
583f679056bSGábor Stefanik 	     SSB_SPROM8_RSSISAV5G_SHIFT);
584f679056bSGábor Stefanik 	SPEX(bxa5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_BXA5G,
585f679056bSGábor Stefanik 	     SSB_SPROM8_BXA5G_SHIFT);
586f679056bSGábor Stefanik 	SPEX(pa0b0, SSB_SPROM8_PA0B0, 0xFFFF, 0);
587f679056bSGábor Stefanik 	SPEX(pa0b1, SSB_SPROM8_PA0B1, 0xFFFF, 0);
588f679056bSGábor Stefanik 	SPEX(pa0b2, SSB_SPROM8_PA0B2, 0xFFFF, 0);
589f679056bSGábor Stefanik 	SPEX(pa1b0, SSB_SPROM8_PA1B0, 0xFFFF, 0);
590f679056bSGábor Stefanik 	SPEX(pa1b1, SSB_SPROM8_PA1B1, 0xFFFF, 0);
591f679056bSGábor Stefanik 	SPEX(pa1b2, SSB_SPROM8_PA1B2, 0xFFFF, 0);
592f679056bSGábor Stefanik 	SPEX(pa1lob0, SSB_SPROM8_PA1LOB0, 0xFFFF, 0);
593f679056bSGábor Stefanik 	SPEX(pa1lob1, SSB_SPROM8_PA1LOB1, 0xFFFF, 0);
594f679056bSGábor Stefanik 	SPEX(pa1lob2, SSB_SPROM8_PA1LOB2, 0xFFFF, 0);
595f679056bSGábor Stefanik 	SPEX(pa1hib0, SSB_SPROM8_PA1HIB0, 0xFFFF, 0);
596f679056bSGábor Stefanik 	SPEX(pa1hib1, SSB_SPROM8_PA1HIB1, 0xFFFF, 0);
597f679056bSGábor Stefanik 	SPEX(pa1hib2, SSB_SPROM8_PA1HIB2, 0xFFFF, 0);
598f679056bSGábor Stefanik 	SPEX(cck2gpo, SSB_SPROM8_CCK2GPO, 0xFFFF, 0);
599f679056bSGábor Stefanik 	SPEX32(ofdm2gpo, SSB_SPROM8_OFDM2GPO, 0xFFFFFFFF, 0);
600f679056bSGábor Stefanik 	SPEX32(ofdm5glpo, SSB_SPROM8_OFDM5GLPO, 0xFFFFFFFF, 0);
601f679056bSGábor Stefanik 	SPEX32(ofdm5gpo, SSB_SPROM8_OFDM5GPO, 0xFFFFFFFF, 0);
602f679056bSGábor Stefanik 	SPEX32(ofdm5ghpo, SSB_SPROM8_OFDM5GHPO, 0xFFFFFFFF, 0);
6036b1c7c67SMichael Buesch 
6046b1c7c67SMichael Buesch 	/* Extract the antenna gain values. */
605f8f8a660SHauke Mehrtens 	SPEX(antenna_gain.a0, SSB_SPROM8_AGAIN01,
6066b1c7c67SMichael Buesch 	     SSB_SPROM8_AGAIN0, SSB_SPROM8_AGAIN0_SHIFT);
607f8f8a660SHauke Mehrtens 	SPEX(antenna_gain.a1, SSB_SPROM8_AGAIN01,
6086b1c7c67SMichael Buesch 	     SSB_SPROM8_AGAIN1, SSB_SPROM8_AGAIN1_SHIFT);
609f8f8a660SHauke Mehrtens 	SPEX(antenna_gain.a2, SSB_SPROM8_AGAIN23,
6106b1c7c67SMichael Buesch 	     SSB_SPROM8_AGAIN2, SSB_SPROM8_AGAIN2_SHIFT);
611f8f8a660SHauke Mehrtens 	SPEX(antenna_gain.a3, SSB_SPROM8_AGAIN23,
6126b1c7c67SMichael Buesch 	     SSB_SPROM8_AGAIN3, SSB_SPROM8_AGAIN3_SHIFT);
6136b1c7c67SMichael Buesch 
614b0f70292SRafał Miłecki 	/* Extract cores power info info */
615b0f70292SRafał Miłecki 	for (i = 0; i < ARRAY_SIZE(pwr_info_offset); i++) {
616b0f70292SRafał Miłecki 		o = pwr_info_offset[i];
617b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].itssi_2g, o + SSB_SROM8_2G_MAXP_ITSSI,
618b0f70292SRafał Miłecki 			SSB_SPROM8_2G_ITSSI, SSB_SPROM8_2G_ITSSI_SHIFT);
619b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].maxpwr_2g, o + SSB_SROM8_2G_MAXP_ITSSI,
620b0f70292SRafał Miłecki 			SSB_SPROM8_2G_MAXP, 0);
621b0f70292SRafał Miłecki 
622b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].pa_2g[0], o + SSB_SROM8_2G_PA_0, ~0, 0);
623b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].pa_2g[1], o + SSB_SROM8_2G_PA_1, ~0, 0);
624b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].pa_2g[2], o + SSB_SROM8_2G_PA_2, ~0, 0);
625b0f70292SRafał Miłecki 
626b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].itssi_5g, o + SSB_SROM8_5G_MAXP_ITSSI,
627b0f70292SRafał Miłecki 			SSB_SPROM8_5G_ITSSI, SSB_SPROM8_5G_ITSSI_SHIFT);
628b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].maxpwr_5g, o + SSB_SROM8_5G_MAXP_ITSSI,
629b0f70292SRafał Miłecki 			SSB_SPROM8_5G_MAXP, 0);
630b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].maxpwr_5gh, o + SSB_SPROM8_5GHL_MAXP,
631b0f70292SRafał Miłecki 			SSB_SPROM8_5GH_MAXP, 0);
632b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].maxpwr_5gl, o + SSB_SPROM8_5GHL_MAXP,
633b0f70292SRafał Miłecki 			SSB_SPROM8_5GL_MAXP, SSB_SPROM8_5GL_MAXP_SHIFT);
634b0f70292SRafał Miłecki 
635b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gl[0], o + SSB_SROM8_5GL_PA_0, ~0, 0);
636b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gl[1], o + SSB_SROM8_5GL_PA_1, ~0, 0);
637b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gl[2], o + SSB_SROM8_5GL_PA_2, ~0, 0);
638b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5g[0], o + SSB_SROM8_5G_PA_0, ~0, 0);
639b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5g[1], o + SSB_SROM8_5G_PA_1, ~0, 0);
640b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5g[2], o + SSB_SROM8_5G_PA_2, ~0, 0);
641b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gh[0], o + SSB_SROM8_5GH_PA_0, ~0, 0);
642b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gh[1], o + SSB_SROM8_5GH_PA_1, ~0, 0);
643b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gh[2], o + SSB_SROM8_5GH_PA_2, ~0, 0);
644b0f70292SRafał Miłecki 	}
645b0f70292SRafał Miłecki 
6468a5ac6ecSRafał Miłecki 	/* Extract FEM info */
6478a5ac6ecSRafał Miłecki 	SPEX(fem.ghz2.tssipos, SSB_SPROM8_FEM2G,
6488a5ac6ecSRafał Miłecki 		SSB_SROM8_FEM_TSSIPOS, SSB_SROM8_FEM_TSSIPOS_SHIFT);
6498a5ac6ecSRafał Miłecki 	SPEX(fem.ghz2.extpa_gain, SSB_SPROM8_FEM2G,
6508a5ac6ecSRafał Miłecki 		SSB_SROM8_FEM_EXTPA_GAIN, SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
6518a5ac6ecSRafał Miłecki 	SPEX(fem.ghz2.pdet_range, SSB_SPROM8_FEM2G,
6528a5ac6ecSRafał Miłecki 		SSB_SROM8_FEM_PDET_RANGE, SSB_SROM8_FEM_PDET_RANGE_SHIFT);
6538a5ac6ecSRafał Miłecki 	SPEX(fem.ghz2.tr_iso, SSB_SPROM8_FEM2G,
6548a5ac6ecSRafał Miłecki 		SSB_SROM8_FEM_TR_ISO, SSB_SROM8_FEM_TR_ISO_SHIFT);
6558a5ac6ecSRafał Miłecki 	SPEX(fem.ghz2.antswlut, SSB_SPROM8_FEM2G,
6568a5ac6ecSRafał Miłecki 		SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT);
6578a5ac6ecSRafał Miłecki 
6588a5ac6ecSRafał Miłecki 	SPEX(fem.ghz5.tssipos, SSB_SPROM8_FEM5G,
6598a5ac6ecSRafał Miłecki 		SSB_SROM8_FEM_TSSIPOS, SSB_SROM8_FEM_TSSIPOS_SHIFT);
6608a5ac6ecSRafał Miłecki 	SPEX(fem.ghz5.extpa_gain, SSB_SPROM8_FEM5G,
6618a5ac6ecSRafał Miłecki 		SSB_SROM8_FEM_EXTPA_GAIN, SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
6628a5ac6ecSRafał Miłecki 	SPEX(fem.ghz5.pdet_range, SSB_SPROM8_FEM5G,
6638a5ac6ecSRafał Miłecki 		SSB_SROM8_FEM_PDET_RANGE, SSB_SROM8_FEM_PDET_RANGE_SHIFT);
6648a5ac6ecSRafał Miłecki 	SPEX(fem.ghz5.tr_iso, SSB_SPROM8_FEM5G,
6658a5ac6ecSRafał Miłecki 		SSB_SROM8_FEM_TR_ISO, SSB_SROM8_FEM_TR_ISO_SHIFT);
6668a5ac6ecSRafał Miłecki 	SPEX(fem.ghz5.antswlut, SSB_SPROM8_FEM5G,
6678a5ac6ecSRafał Miłecki 		SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT);
6688a5ac6ecSRafał Miłecki 
669e2da4bd3SHauke Mehrtens 	SPEX(leddc_on_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_ON,
670e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_LEDDC_ON_SHIFT);
671e2da4bd3SHauke Mehrtens 	SPEX(leddc_off_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_OFF,
672e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_LEDDC_OFF_SHIFT);
673e2da4bd3SHauke Mehrtens 
674e2da4bd3SHauke Mehrtens 	SPEX(txchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_TXCHAIN,
675e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_TXRXC_TXCHAIN_SHIFT);
676e2da4bd3SHauke Mehrtens 	SPEX(rxchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_RXCHAIN,
677e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_TXRXC_RXCHAIN_SHIFT);
678e2da4bd3SHauke Mehrtens 	SPEX(antswitch, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_SWITCH,
679e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_TXRXC_SWITCH_SHIFT);
680e2da4bd3SHauke Mehrtens 
681e2da4bd3SHauke Mehrtens 	SPEX(opo, SSB_SPROM8_OFDM2GPO, 0x00ff, 0);
682e2da4bd3SHauke Mehrtens 
683e2da4bd3SHauke Mehrtens 	SPEX_ARRAY8(mcs2gpo, SSB_SPROM8_2G_MCSPO, ~0, 0);
684e2da4bd3SHauke Mehrtens 	SPEX_ARRAY8(mcs5gpo, SSB_SPROM8_5G_MCSPO, ~0, 0);
685e2da4bd3SHauke Mehrtens 	SPEX_ARRAY8(mcs5glpo, SSB_SPROM8_5GL_MCSPO, ~0, 0);
686e2da4bd3SHauke Mehrtens 	SPEX_ARRAY8(mcs5ghpo, SSB_SPROM8_5GH_MCSPO, ~0, 0);
687e2da4bd3SHauke Mehrtens 
688e2da4bd3SHauke Mehrtens 	SPEX(rawtempsense, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_RAWTEMP,
689e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_RAWTS_RAWTEMP_SHIFT);
690e2da4bd3SHauke Mehrtens 	SPEX(measpower, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_MEASPOWER,
691e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_RAWTS_MEASPOWER_SHIFT);
692e2da4bd3SHauke Mehrtens 	SPEX(tempsense_slope, SSB_SPROM8_OPT_CORRX,
693e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_OPT_CORRX_TEMP_SLOPE,
694e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_OPT_CORRX_TEMP_SLOPE_SHIFT);
695e2da4bd3SHauke Mehrtens 	SPEX(tempcorrx, SSB_SPROM8_OPT_CORRX, SSB_SPROM8_OPT_CORRX_TEMPCORRX,
696e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_OPT_CORRX_TEMPCORRX_SHIFT);
697e2da4bd3SHauke Mehrtens 	SPEX(tempsense_option, SSB_SPROM8_OPT_CORRX,
698e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_OPT_CORRX_TEMP_OPTION,
699e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_OPT_CORRX_TEMP_OPTION_SHIFT);
700e2da4bd3SHauke Mehrtens 	SPEX(freqoffset_corr, SSB_SPROM8_HWIQ_IQSWP,
701e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR,
702e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR_SHIFT);
703e2da4bd3SHauke Mehrtens 	SPEX(iqcal_swp_dis, SSB_SPROM8_HWIQ_IQSWP,
704e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP,
705e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP_SHIFT);
706e2da4bd3SHauke Mehrtens 	SPEX(hw_iqcal_en, SSB_SPROM8_HWIQ_IQSWP, SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL,
707e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL_SHIFT);
708e2da4bd3SHauke Mehrtens 
709e2da4bd3SHauke Mehrtens 	SPEX(bw40po, SSB_SPROM8_BW40PO, ~0, 0);
710e2da4bd3SHauke Mehrtens 	SPEX(cddpo, SSB_SPROM8_CDDPO, ~0, 0);
711e2da4bd3SHauke Mehrtens 	SPEX(stbcpo, SSB_SPROM8_STBCPO, ~0, 0);
712e2da4bd3SHauke Mehrtens 	SPEX(bwduppo, SSB_SPROM8_BWDUPPO, ~0, 0);
713e2da4bd3SHauke Mehrtens 
714e2da4bd3SHauke Mehrtens 	SPEX(tempthresh, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_TRESH,
715e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_THERMAL_TRESH_SHIFT);
716e2da4bd3SHauke Mehrtens 	SPEX(tempoffset, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_OFFSET,
717e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_THERMAL_OFFSET_SHIFT);
718e2da4bd3SHauke Mehrtens 	SPEX(phycal_tempdelta, SSB_SPROM8_TEMPDELTA,
719e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_TEMPDELTA_PHYCAL,
720e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_TEMPDELTA_PHYCAL_SHIFT);
721e2da4bd3SHauke Mehrtens 	SPEX(temps_period, SSB_SPROM8_TEMPDELTA, SSB_SPROM8_TEMPDELTA_PERIOD,
722e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_TEMPDELTA_PERIOD_SHIFT);
723e2da4bd3SHauke Mehrtens 	SPEX(temps_hysteresis, SSB_SPROM8_TEMPDELTA,
724e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_TEMPDELTA_HYSTERESIS,
725e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_TEMPDELTA_HYSTERESIS_SHIFT);
726172c69a4SRafał Miłecki 	sprom_extract_r458(out, in);
727172c69a4SRafał Miłecki 
7286b1c7c67SMichael Buesch 	/* TODO - get remaining rev 8 stuff needed */
7296b1c7c67SMichael Buesch }
7306b1c7c67SMichael Buesch 
731c272ef44SLarry Finger static int sprom_extract(struct ssb_bus *bus, struct ssb_sprom *out,
732c272ef44SLarry Finger 			 const u16 *in, u16 size)
73361e115a5SMichael Buesch {
73461e115a5SMichael Buesch 	memset(out, 0, sizeof(*out));
73561e115a5SMichael Buesch 
736c272ef44SLarry Finger 	out->revision = in[size - 1] & 0x00FF;
737*33a606acSJoe Perches 	ssb_dbg("SPROM revision %d detected\n", out->revision);
73831ce12fbSLarry Finger 	memset(out->et0mac, 0xFF, 6);		/* preset et0 and et1 mac */
73931ce12fbSLarry Finger 	memset(out->et1mac, 0xFF, 6);
74054435f9eSRafał Miłecki 
74161e115a5SMichael Buesch 	if ((bus->chip_id & 0xFF00) == 0x4400) {
74261e115a5SMichael Buesch 		/* Workaround: The BCM44XX chip has a stupid revision
74361e115a5SMichael Buesch 		 * number stored in the SPROM.
74461e115a5SMichael Buesch 		 * Always extract r1. */
745c272ef44SLarry Finger 		out->revision = 1;
746*33a606acSJoe Perches 		ssb_dbg("SPROM treated as revision %d\n", out->revision);
74754435f9eSRafał Miłecki 	}
74854435f9eSRafał Miłecki 
7496b1c7c67SMichael Buesch 	switch (out->revision) {
7506b1c7c67SMichael Buesch 	case 1:
7516b1c7c67SMichael Buesch 	case 2:
7526b1c7c67SMichael Buesch 	case 3:
7536b1c7c67SMichael Buesch 		sprom_extract_r123(out, in);
7546b1c7c67SMichael Buesch 		break;
7556b1c7c67SMichael Buesch 	case 4:
7566b1c7c67SMichael Buesch 	case 5:
7576b1c7c67SMichael Buesch 		sprom_extract_r45(out, in);
7586b1c7c67SMichael Buesch 		break;
7596b1c7c67SMichael Buesch 	case 8:
7606b1c7c67SMichael Buesch 		sprom_extract_r8(out, in);
7616b1c7c67SMichael Buesch 		break;
7626b1c7c67SMichael Buesch 	default:
763*33a606acSJoe Perches 		ssb_warn("Unsupported SPROM revision %d detected. Will extract v1\n",
764*33a606acSJoe Perches 			 out->revision);
765cd559b36SLarry Finger 		out->revision = 1;
766c272ef44SLarry Finger 		sprom_extract_r123(out, in);
767c272ef44SLarry Finger 	}
76861e115a5SMichael Buesch 
7694503183aSLarry Finger 	if (out->boardflags_lo == 0xFFFF)
7704503183aSLarry Finger 		out->boardflags_lo = 0;  /* per specs */
7714503183aSLarry Finger 	if (out->boardflags_hi == 0xFFFF)
7724503183aSLarry Finger 		out->boardflags_hi = 0;  /* per specs */
7734503183aSLarry Finger 
77461e115a5SMichael Buesch 	return 0;
77561e115a5SMichael Buesch }
77661e115a5SMichael Buesch 
77761e115a5SMichael Buesch static int ssb_pci_sprom_get(struct ssb_bus *bus,
77861e115a5SMichael Buesch 			     struct ssb_sprom *sprom)
77961e115a5SMichael Buesch {
780ca4a0831SRafał Miłecki 	int err;
78161e115a5SMichael Buesch 	u16 *buf;
78261e115a5SMichael Buesch 
783d53cdbb9SJohn W. Linville 	if (!ssb_is_sprom_available(bus)) {
784*33a606acSJoe Perches 		ssb_err("No SPROM available!\n");
785d53cdbb9SJohn W. Linville 		return -ENODEV;
786d53cdbb9SJohn W. Linville 	}
78725985edcSLucas De Marchi 	if (bus->chipco.dev) {	/* can be unavailable! */
7889d1ac34eSLarry Finger 		/*
7899d1ac34eSLarry Finger 		 * get SPROM offset: SSB_SPROM_BASE1 except for
7909d1ac34eSLarry Finger 		 * chipcommon rev >= 31 or chip ID is 0x4312 and
7919d1ac34eSLarry Finger 		 * chipcommon status & 3 == 2
7929d1ac34eSLarry Finger 		 */
7939d1ac34eSLarry Finger 		if (bus->chipco.dev->id.revision >= 31)
7949d1ac34eSLarry Finger 			bus->sprom_offset = SSB_SPROM_BASE31;
7959d1ac34eSLarry Finger 		else if (bus->chip_id == 0x4312 &&
7969d1ac34eSLarry Finger 			 (bus->chipco.status & 0x03) == 2)
7979d1ac34eSLarry Finger 			bus->sprom_offset = SSB_SPROM_BASE31;
7989d1ac34eSLarry Finger 		else
7999d1ac34eSLarry Finger 			bus->sprom_offset = SSB_SPROM_BASE1;
800da1fdb02SChristoph Fritz 	} else {
801da1fdb02SChristoph Fritz 		bus->sprom_offset = SSB_SPROM_BASE1;
802da1fdb02SChristoph Fritz 	}
803*33a606acSJoe Perches 	ssb_dbg("SPROM offset is 0x%x\n", bus->sprom_offset);
804ea2db495SRafał Miłecki 
805c272ef44SLarry Finger 	buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL);
80661e115a5SMichael Buesch 	if (!buf)
807ca4a0831SRafał Miłecki 		return -ENOMEM;
808c272ef44SLarry Finger 	bus->sprom_size = SSB_SPROMSIZE_WORDS_R123;
80961e115a5SMichael Buesch 	sprom_do_read(bus, buf);
810c272ef44SLarry Finger 	err = sprom_check_crc(buf, bus->sprom_size);
81161e115a5SMichael Buesch 	if (err) {
8122afc4901SLarry.Finger@lwfinger.net 		/* try for a 440 byte SPROM - revision 4 and higher */
813c272ef44SLarry Finger 		kfree(buf);
814c272ef44SLarry Finger 		buf = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
815c272ef44SLarry Finger 			      GFP_KERNEL);
816c272ef44SLarry Finger 		if (!buf)
817ca4a0831SRafał Miłecki 			return -ENOMEM;
818c272ef44SLarry Finger 		bus->sprom_size = SSB_SPROMSIZE_WORDS_R4;
819c272ef44SLarry Finger 		sprom_do_read(bus, buf);
820c272ef44SLarry Finger 		err = sprom_check_crc(buf, bus->sprom_size);
821e79c1ba8SMichael Buesch 		if (err) {
822e79c1ba8SMichael Buesch 			/* All CRC attempts failed.
823e79c1ba8SMichael Buesch 			 * Maybe there is no SPROM on the device?
824b3ae52b6SHauke Mehrtens 			 * Now we ask the arch code if there is some sprom
825b3ae52b6SHauke Mehrtens 			 * available for this device in some other storage */
826b3ae52b6SHauke Mehrtens 			err = ssb_fill_sprom_with_fallback(bus, sprom);
827b3ae52b6SHauke Mehrtens 			if (err) {
828*33a606acSJoe Perches 				ssb_warn("WARNING: Using fallback SPROM failed (err %d)\n",
829b3ae52b6SHauke Mehrtens 					 err);
830b3ae52b6SHauke Mehrtens 			} else {
831*33a606acSJoe Perches 				ssb_dbg("Using SPROM revision %d provided by platform\n",
832*33a606acSJoe Perches 					sprom->revision);
833e79c1ba8SMichael Buesch 				err = 0;
834e79c1ba8SMichael Buesch 				goto out_free;
835e79c1ba8SMichael Buesch 			}
836*33a606acSJoe Perches 			ssb_warn("WARNING: Invalid SPROM CRC (corrupt SPROM)\n");
837c272ef44SLarry Finger 		}
838e79c1ba8SMichael Buesch 	}
839c272ef44SLarry Finger 	err = sprom_extract(bus, sprom, buf, bus->sprom_size);
84061e115a5SMichael Buesch 
841e79c1ba8SMichael Buesch out_free:
84261e115a5SMichael Buesch 	kfree(buf);
84361e115a5SMichael Buesch 	return err;
84461e115a5SMichael Buesch }
84561e115a5SMichael Buesch 
84661e115a5SMichael Buesch static void ssb_pci_get_boardinfo(struct ssb_bus *bus,
84761e115a5SMichael Buesch 				  struct ssb_boardinfo *bi)
84861e115a5SMichael Buesch {
849115f9450SSergei Shtylyov 	bi->vendor = bus->host_pci->subsystem_vendor;
850115f9450SSergei Shtylyov 	bi->type = bus->host_pci->subsystem_device;
85161e115a5SMichael Buesch }
85261e115a5SMichael Buesch 
85361e115a5SMichael Buesch int ssb_pci_get_invariants(struct ssb_bus *bus,
85461e115a5SMichael Buesch 			   struct ssb_init_invariants *iv)
85561e115a5SMichael Buesch {
85661e115a5SMichael Buesch 	int err;
85761e115a5SMichael Buesch 
85861e115a5SMichael Buesch 	err = ssb_pci_sprom_get(bus, &iv->sprom);
85961e115a5SMichael Buesch 	if (err)
86061e115a5SMichael Buesch 		goto out;
86161e115a5SMichael Buesch 	ssb_pci_get_boardinfo(bus, &iv->boardinfo);
86261e115a5SMichael Buesch 
86361e115a5SMichael Buesch out:
86461e115a5SMichael Buesch 	return err;
86561e115a5SMichael Buesch }
86661e115a5SMichael Buesch 
86761e115a5SMichael Buesch #ifdef CONFIG_SSB_DEBUG
86861e115a5SMichael Buesch static int ssb_pci_assert_buspower(struct ssb_bus *bus)
86961e115a5SMichael Buesch {
87061e115a5SMichael Buesch 	if (likely(bus->powered_up))
87161e115a5SMichael Buesch 		return 0;
87261e115a5SMichael Buesch 
87361e115a5SMichael Buesch 	printk(KERN_ERR PFX "FATAL ERROR: Bus powered down "
87461e115a5SMichael Buesch 	       "while accessing PCI MMIO space\n");
87561e115a5SMichael Buesch 	if (bus->power_warn_count <= 10) {
87661e115a5SMichael Buesch 		bus->power_warn_count++;
87761e115a5SMichael Buesch 		dump_stack();
87861e115a5SMichael Buesch 	}
87961e115a5SMichael Buesch 
88061e115a5SMichael Buesch 	return -ENODEV;
88161e115a5SMichael Buesch }
88261e115a5SMichael Buesch #else /* DEBUG */
88361e115a5SMichael Buesch static inline int ssb_pci_assert_buspower(struct ssb_bus *bus)
88461e115a5SMichael Buesch {
88561e115a5SMichael Buesch 	return 0;
88661e115a5SMichael Buesch }
88761e115a5SMichael Buesch #endif /* DEBUG */
88861e115a5SMichael Buesch 
889ffc7689dSMichael Buesch static u8 ssb_pci_read8(struct ssb_device *dev, u16 offset)
890ffc7689dSMichael Buesch {
891ffc7689dSMichael Buesch 	struct ssb_bus *bus = dev->bus;
892ffc7689dSMichael Buesch 
893ffc7689dSMichael Buesch 	if (unlikely(ssb_pci_assert_buspower(bus)))
894ffc7689dSMichael Buesch 		return 0xFF;
895ffc7689dSMichael Buesch 	if (unlikely(bus->mapped_device != dev)) {
896ffc7689dSMichael Buesch 		if (unlikely(ssb_pci_switch_core(bus, dev)))
897ffc7689dSMichael Buesch 			return 0xFF;
898ffc7689dSMichael Buesch 	}
899ffc7689dSMichael Buesch 	return ioread8(bus->mmio + offset);
900ffc7689dSMichael Buesch }
901ffc7689dSMichael Buesch 
90261e115a5SMichael Buesch static u16 ssb_pci_read16(struct ssb_device *dev, u16 offset)
90361e115a5SMichael Buesch {
90461e115a5SMichael Buesch 	struct ssb_bus *bus = dev->bus;
90561e115a5SMichael Buesch 
90661e115a5SMichael Buesch 	if (unlikely(ssb_pci_assert_buspower(bus)))
90761e115a5SMichael Buesch 		return 0xFFFF;
90861e115a5SMichael Buesch 	if (unlikely(bus->mapped_device != dev)) {
90961e115a5SMichael Buesch 		if (unlikely(ssb_pci_switch_core(bus, dev)))
91061e115a5SMichael Buesch 			return 0xFFFF;
91161e115a5SMichael Buesch 	}
9124b402c65SMichael Buesch 	return ioread16(bus->mmio + offset);
91361e115a5SMichael Buesch }
91461e115a5SMichael Buesch 
91561e115a5SMichael Buesch static u32 ssb_pci_read32(struct ssb_device *dev, u16 offset)
91661e115a5SMichael Buesch {
91761e115a5SMichael Buesch 	struct ssb_bus *bus = dev->bus;
91861e115a5SMichael Buesch 
91961e115a5SMichael Buesch 	if (unlikely(ssb_pci_assert_buspower(bus)))
92061e115a5SMichael Buesch 		return 0xFFFFFFFF;
92161e115a5SMichael Buesch 	if (unlikely(bus->mapped_device != dev)) {
92261e115a5SMichael Buesch 		if (unlikely(ssb_pci_switch_core(bus, dev)))
92361e115a5SMichael Buesch 			return 0xFFFFFFFF;
92461e115a5SMichael Buesch 	}
9254b402c65SMichael Buesch 	return ioread32(bus->mmio + offset);
92661e115a5SMichael Buesch }
92761e115a5SMichael Buesch 
928d625a29bSMichael Buesch #ifdef CONFIG_SSB_BLOCKIO
929d625a29bSMichael Buesch static void ssb_pci_block_read(struct ssb_device *dev, void *buffer,
930d625a29bSMichael Buesch 			       size_t count, u16 offset, u8 reg_width)
931d625a29bSMichael Buesch {
932d625a29bSMichael Buesch 	struct ssb_bus *bus = dev->bus;
933d625a29bSMichael Buesch 	void __iomem *addr = bus->mmio + offset;
934d625a29bSMichael Buesch 
935d625a29bSMichael Buesch 	if (unlikely(ssb_pci_assert_buspower(bus)))
936d625a29bSMichael Buesch 		goto error;
937d625a29bSMichael Buesch 	if (unlikely(bus->mapped_device != dev)) {
938d625a29bSMichael Buesch 		if (unlikely(ssb_pci_switch_core(bus, dev)))
939d625a29bSMichael Buesch 			goto error;
940d625a29bSMichael Buesch 	}
941d625a29bSMichael Buesch 	switch (reg_width) {
942d625a29bSMichael Buesch 	case sizeof(u8):
943d625a29bSMichael Buesch 		ioread8_rep(addr, buffer, count);
944d625a29bSMichael Buesch 		break;
945d625a29bSMichael Buesch 	case sizeof(u16):
946d625a29bSMichael Buesch 		SSB_WARN_ON(count & 1);
947d625a29bSMichael Buesch 		ioread16_rep(addr, buffer, count >> 1);
948d625a29bSMichael Buesch 		break;
949d625a29bSMichael Buesch 	case sizeof(u32):
950d625a29bSMichael Buesch 		SSB_WARN_ON(count & 3);
951d625a29bSMichael Buesch 		ioread32_rep(addr, buffer, count >> 2);
952d625a29bSMichael Buesch 		break;
953d625a29bSMichael Buesch 	default:
954d625a29bSMichael Buesch 		SSB_WARN_ON(1);
955d625a29bSMichael Buesch 	}
956d625a29bSMichael Buesch 
957d625a29bSMichael Buesch 	return;
958d625a29bSMichael Buesch error:
959d625a29bSMichael Buesch 	memset(buffer, 0xFF, count);
960d625a29bSMichael Buesch }
961d625a29bSMichael Buesch #endif /* CONFIG_SSB_BLOCKIO */
962d625a29bSMichael Buesch 
963ffc7689dSMichael Buesch static void ssb_pci_write8(struct ssb_device *dev, u16 offset, u8 value)
964ffc7689dSMichael Buesch {
965ffc7689dSMichael Buesch 	struct ssb_bus *bus = dev->bus;
966ffc7689dSMichael Buesch 
967ffc7689dSMichael Buesch 	if (unlikely(ssb_pci_assert_buspower(bus)))
968ffc7689dSMichael Buesch 		return;
969ffc7689dSMichael Buesch 	if (unlikely(bus->mapped_device != dev)) {
970ffc7689dSMichael Buesch 		if (unlikely(ssb_pci_switch_core(bus, dev)))
971ffc7689dSMichael Buesch 			return;
972ffc7689dSMichael Buesch 	}
973ffc7689dSMichael Buesch 	iowrite8(value, bus->mmio + offset);
974ffc7689dSMichael Buesch }
975ffc7689dSMichael Buesch 
97661e115a5SMichael Buesch static void ssb_pci_write16(struct ssb_device *dev, u16 offset, u16 value)
97761e115a5SMichael Buesch {
97861e115a5SMichael Buesch 	struct ssb_bus *bus = dev->bus;
97961e115a5SMichael Buesch 
98061e115a5SMichael Buesch 	if (unlikely(ssb_pci_assert_buspower(bus)))
98161e115a5SMichael Buesch 		return;
98261e115a5SMichael Buesch 	if (unlikely(bus->mapped_device != dev)) {
98361e115a5SMichael Buesch 		if (unlikely(ssb_pci_switch_core(bus, dev)))
98461e115a5SMichael Buesch 			return;
98561e115a5SMichael Buesch 	}
9864b402c65SMichael Buesch 	iowrite16(value, bus->mmio + offset);
98761e115a5SMichael Buesch }
98861e115a5SMichael Buesch 
98961e115a5SMichael Buesch static void ssb_pci_write32(struct ssb_device *dev, u16 offset, u32 value)
99061e115a5SMichael Buesch {
99161e115a5SMichael Buesch 	struct ssb_bus *bus = dev->bus;
99261e115a5SMichael Buesch 
99361e115a5SMichael Buesch 	if (unlikely(ssb_pci_assert_buspower(bus)))
99461e115a5SMichael Buesch 		return;
99561e115a5SMichael Buesch 	if (unlikely(bus->mapped_device != dev)) {
99661e115a5SMichael Buesch 		if (unlikely(ssb_pci_switch_core(bus, dev)))
99761e115a5SMichael Buesch 			return;
99861e115a5SMichael Buesch 	}
9994b402c65SMichael Buesch 	iowrite32(value, bus->mmio + offset);
100061e115a5SMichael Buesch }
100161e115a5SMichael Buesch 
1002d625a29bSMichael Buesch #ifdef CONFIG_SSB_BLOCKIO
1003d625a29bSMichael Buesch static void ssb_pci_block_write(struct ssb_device *dev, const void *buffer,
1004d625a29bSMichael Buesch 				size_t count, u16 offset, u8 reg_width)
1005d625a29bSMichael Buesch {
1006d625a29bSMichael Buesch 	struct ssb_bus *bus = dev->bus;
1007d625a29bSMichael Buesch 	void __iomem *addr = bus->mmio + offset;
1008d625a29bSMichael Buesch 
1009d625a29bSMichael Buesch 	if (unlikely(ssb_pci_assert_buspower(bus)))
1010d625a29bSMichael Buesch 		return;
1011d625a29bSMichael Buesch 	if (unlikely(bus->mapped_device != dev)) {
1012d625a29bSMichael Buesch 		if (unlikely(ssb_pci_switch_core(bus, dev)))
1013d625a29bSMichael Buesch 			return;
1014d625a29bSMichael Buesch 	}
1015d625a29bSMichael Buesch 	switch (reg_width) {
1016d625a29bSMichael Buesch 	case sizeof(u8):
1017d625a29bSMichael Buesch 		iowrite8_rep(addr, buffer, count);
1018d625a29bSMichael Buesch 		break;
1019d625a29bSMichael Buesch 	case sizeof(u16):
1020d625a29bSMichael Buesch 		SSB_WARN_ON(count & 1);
1021d625a29bSMichael Buesch 		iowrite16_rep(addr, buffer, count >> 1);
1022d625a29bSMichael Buesch 		break;
1023d625a29bSMichael Buesch 	case sizeof(u32):
1024d625a29bSMichael Buesch 		SSB_WARN_ON(count & 3);
1025d625a29bSMichael Buesch 		iowrite32_rep(addr, buffer, count >> 2);
1026d625a29bSMichael Buesch 		break;
1027d625a29bSMichael Buesch 	default:
1028d625a29bSMichael Buesch 		SSB_WARN_ON(1);
1029d625a29bSMichael Buesch 	}
1030d625a29bSMichael Buesch }
1031d625a29bSMichael Buesch #endif /* CONFIG_SSB_BLOCKIO */
1032d625a29bSMichael Buesch 
103361e115a5SMichael Buesch /* Not "static", as it's used in main.c */
103461e115a5SMichael Buesch const struct ssb_bus_ops ssb_pci_ops = {
1035ffc7689dSMichael Buesch 	.read8		= ssb_pci_read8,
103661e115a5SMichael Buesch 	.read16		= ssb_pci_read16,
103761e115a5SMichael Buesch 	.read32		= ssb_pci_read32,
1038ffc7689dSMichael Buesch 	.write8		= ssb_pci_write8,
103961e115a5SMichael Buesch 	.write16	= ssb_pci_write16,
104061e115a5SMichael Buesch 	.write32	= ssb_pci_write32,
1041d625a29bSMichael Buesch #ifdef CONFIG_SSB_BLOCKIO
1042d625a29bSMichael Buesch 	.block_read	= ssb_pci_block_read,
1043d625a29bSMichael Buesch 	.block_write	= ssb_pci_block_write,
1044d625a29bSMichael Buesch #endif
104561e115a5SMichael Buesch };
104661e115a5SMichael Buesch 
104761e115a5SMichael Buesch static ssize_t ssb_pci_attr_sprom_show(struct device *pcidev,
104861e115a5SMichael Buesch 				       struct device_attribute *attr,
104961e115a5SMichael Buesch 				       char *buf)
105061e115a5SMichael Buesch {
105161e115a5SMichael Buesch 	struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev);
105261e115a5SMichael Buesch 	struct ssb_bus *bus;
105361e115a5SMichael Buesch 
105461e115a5SMichael Buesch 	bus = ssb_pci_dev_to_bus(pdev);
105561e115a5SMichael Buesch 	if (!bus)
1056e7ec2e32SMichael Buesch 		return -ENODEV;
105761e115a5SMichael Buesch 
1058e7ec2e32SMichael Buesch 	return ssb_attr_sprom_show(bus, buf, sprom_do_read);
105961e115a5SMichael Buesch }
106061e115a5SMichael Buesch 
106161e115a5SMichael Buesch static ssize_t ssb_pci_attr_sprom_store(struct device *pcidev,
106261e115a5SMichael Buesch 					struct device_attribute *attr,
106361e115a5SMichael Buesch 					const char *buf, size_t count)
106461e115a5SMichael Buesch {
106561e115a5SMichael Buesch 	struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev);
106661e115a5SMichael Buesch 	struct ssb_bus *bus;
106761e115a5SMichael Buesch 
106861e115a5SMichael Buesch 	bus = ssb_pci_dev_to_bus(pdev);
106961e115a5SMichael Buesch 	if (!bus)
1070e7ec2e32SMichael Buesch 		return -ENODEV;
107161e115a5SMichael Buesch 
1072e7ec2e32SMichael Buesch 	return ssb_attr_sprom_store(bus, buf, count,
1073e7ec2e32SMichael Buesch 				    sprom_check_crc, sprom_do_write);
107461e115a5SMichael Buesch }
107561e115a5SMichael Buesch 
107661e115a5SMichael Buesch static DEVICE_ATTR(ssb_sprom, 0600,
107761e115a5SMichael Buesch 		   ssb_pci_attr_sprom_show,
107861e115a5SMichael Buesch 		   ssb_pci_attr_sprom_store);
107961e115a5SMichael Buesch 
108061e115a5SMichael Buesch void ssb_pci_exit(struct ssb_bus *bus)
108161e115a5SMichael Buesch {
108261e115a5SMichael Buesch 	struct pci_dev *pdev;
108361e115a5SMichael Buesch 
108461e115a5SMichael Buesch 	if (bus->bustype != SSB_BUSTYPE_PCI)
108561e115a5SMichael Buesch 		return;
108661e115a5SMichael Buesch 
108761e115a5SMichael Buesch 	pdev = bus->host_pci;
108861e115a5SMichael Buesch 	device_remove_file(&pdev->dev, &dev_attr_ssb_sprom);
108961e115a5SMichael Buesch }
109061e115a5SMichael Buesch 
109161e115a5SMichael Buesch int ssb_pci_init(struct ssb_bus *bus)
109261e115a5SMichael Buesch {
109361e115a5SMichael Buesch 	struct pci_dev *pdev;
109461e115a5SMichael Buesch 	int err;
109561e115a5SMichael Buesch 
109661e115a5SMichael Buesch 	if (bus->bustype != SSB_BUSTYPE_PCI)
109761e115a5SMichael Buesch 		return 0;
109861e115a5SMichael Buesch 
109961e115a5SMichael Buesch 	pdev = bus->host_pci;
1100e7ec2e32SMichael Buesch 	mutex_init(&bus->sprom_mutex);
110161e115a5SMichael Buesch 	err = device_create_file(&pdev->dev, &dev_attr_ssb_sprom);
110261e115a5SMichael Buesch 	if (err)
110361e115a5SMichael Buesch 		goto out;
110461e115a5SMichael Buesch 
110561e115a5SMichael Buesch out:
110661e115a5SMichael Buesch 	return err;
110761e115a5SMichael Buesch }
1108