xref: /openbmc/linux/drivers/ssb/pci.c (revision 209b43759d65b2cc99ce7757249aacc82b03c4e2)
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 
18b8b6069cSMichael Büsch #include "ssb_private.h"
19b8b6069cSMichael Büsch 
2061e115a5SMichael Buesch #include <linux/ssb/ssb.h>
2161e115a5SMichael Buesch #include <linux/ssb/ssb_regs.h>
225a0e3ad6STejun Heo #include <linux/slab.h>
2361e115a5SMichael Buesch #include <linux/pci.h>
2461e115a5SMichael Buesch #include <linux/delay.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:
59b8b6069cSMichael Büsch 	pr_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
70b8b6069cSMichael Büsch 	pr_info("Switching to %s core, index %d\n",
71b8b6069cSMichael Büsch 		ssb_core_name(dev->id.coreid), dev->core_index);
7261e115a5SMichael Buesch #endif
7361e115a5SMichael Buesch 
7461e115a5SMichael Buesch 	spin_lock_irqsave(&bus->bar_lock, flags);
7561e115a5SMichael Buesch 	err = ssb_pci_switch_coreidx(bus, dev->core_index);
7661e115a5SMichael Buesch 	if (!err)
7761e115a5SMichael Buesch 		bus->mapped_device = dev;
7861e115a5SMichael Buesch 	spin_unlock_irqrestore(&bus->bar_lock, flags);
7961e115a5SMichael Buesch 
8061e115a5SMichael Buesch 	return err;
8161e115a5SMichael Buesch }
8261e115a5SMichael Buesch 
8361e115a5SMichael Buesch /* Enable/disable the on board crystal oscillator and/or PLL. */
8461e115a5SMichael Buesch int ssb_pci_xtal(struct ssb_bus *bus, u32 what, int turn_on)
8561e115a5SMichael Buesch {
8661e115a5SMichael Buesch 	int err;
8761e115a5SMichael Buesch 	u32 in, out, outenable;
8861e115a5SMichael Buesch 	u16 pci_status;
8961e115a5SMichael Buesch 
9061e115a5SMichael Buesch 	if (bus->bustype != SSB_BUSTYPE_PCI)
9161e115a5SMichael Buesch 		return 0;
9261e115a5SMichael Buesch 
9361e115a5SMichael Buesch 	err = pci_read_config_dword(bus->host_pci, SSB_GPIO_IN, &in);
9461e115a5SMichael Buesch 	if (err)
9561e115a5SMichael Buesch 		goto err_pci;
9661e115a5SMichael Buesch 	err = pci_read_config_dword(bus->host_pci, SSB_GPIO_OUT, &out);
9761e115a5SMichael Buesch 	if (err)
9861e115a5SMichael Buesch 		goto err_pci;
9961e115a5SMichael Buesch 	err = pci_read_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE, &outenable);
10061e115a5SMichael Buesch 	if (err)
10161e115a5SMichael Buesch 		goto err_pci;
10261e115a5SMichael Buesch 
10361e115a5SMichael Buesch 	outenable |= what;
10461e115a5SMichael Buesch 
10561e115a5SMichael Buesch 	if (turn_on) {
10661e115a5SMichael Buesch 		/* Avoid glitching the clock if GPRS is already using it.
10761e115a5SMichael Buesch 		 * We can't actually read the state of the PLLPD so we infer it
10861e115a5SMichael Buesch 		 * by the value of XTAL_PU which *is* readable via gpioin.
10961e115a5SMichael Buesch 		 */
11061e115a5SMichael Buesch 		if (!(in & SSB_GPIO_XTAL)) {
11161e115a5SMichael Buesch 			if (what & SSB_GPIO_XTAL) {
11261e115a5SMichael Buesch 				/* Turn the crystal on */
11361e115a5SMichael Buesch 				out |= SSB_GPIO_XTAL;
11461e115a5SMichael Buesch 				if (what & SSB_GPIO_PLL)
11561e115a5SMichael Buesch 					out |= SSB_GPIO_PLL;
11661e115a5SMichael Buesch 				err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out);
11761e115a5SMichael Buesch 				if (err)
11861e115a5SMichael Buesch 					goto err_pci;
11961e115a5SMichael Buesch 				err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE,
12061e115a5SMichael Buesch 							     outenable);
12161e115a5SMichael Buesch 				if (err)
12261e115a5SMichael Buesch 					goto err_pci;
12361e115a5SMichael Buesch 				msleep(1);
12461e115a5SMichael Buesch 			}
12561e115a5SMichael Buesch 			if (what & SSB_GPIO_PLL) {
12661e115a5SMichael Buesch 				/* Turn the PLL on */
12761e115a5SMichael Buesch 				out &= ~SSB_GPIO_PLL;
12861e115a5SMichael Buesch 				err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out);
12961e115a5SMichael Buesch 				if (err)
13061e115a5SMichael Buesch 					goto err_pci;
13161e115a5SMichael Buesch 				msleep(5);
13261e115a5SMichael Buesch 			}
13361e115a5SMichael Buesch 		}
13461e115a5SMichael Buesch 
13561e115a5SMichael Buesch 		err = pci_read_config_word(bus->host_pci, PCI_STATUS, &pci_status);
13661e115a5SMichael Buesch 		if (err)
13761e115a5SMichael Buesch 			goto err_pci;
13861e115a5SMichael Buesch 		pci_status &= ~PCI_STATUS_SIG_TARGET_ABORT;
13961e115a5SMichael Buesch 		err = pci_write_config_word(bus->host_pci, PCI_STATUS, pci_status);
14061e115a5SMichael Buesch 		if (err)
14161e115a5SMichael Buesch 			goto err_pci;
14261e115a5SMichael Buesch 	} else {
14361e115a5SMichael Buesch 		if (what & SSB_GPIO_XTAL) {
14461e115a5SMichael Buesch 			/* Turn the crystal off */
14561e115a5SMichael Buesch 			out &= ~SSB_GPIO_XTAL;
14661e115a5SMichael Buesch 		}
14761e115a5SMichael Buesch 		if (what & SSB_GPIO_PLL) {
14861e115a5SMichael Buesch 			/* Turn the PLL off */
14961e115a5SMichael Buesch 			out |= SSB_GPIO_PLL;
15061e115a5SMichael Buesch 		}
15161e115a5SMichael Buesch 		err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out);
15261e115a5SMichael Buesch 		if (err)
15361e115a5SMichael Buesch 			goto err_pci;
15461e115a5SMichael Buesch 		err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE, outenable);
15561e115a5SMichael Buesch 		if (err)
15661e115a5SMichael Buesch 			goto err_pci;
15761e115a5SMichael Buesch 	}
15861e115a5SMichael Buesch 
15961e115a5SMichael Buesch out:
16061e115a5SMichael Buesch 	return err;
16161e115a5SMichael Buesch 
16261e115a5SMichael Buesch err_pci:
163b8b6069cSMichael Büsch 	pr_err("Error: ssb_pci_xtal() could not access PCI config space!\n");
16461e115a5SMichael Buesch 	err = -EBUSY;
16561e115a5SMichael Buesch 	goto out;
16661e115a5SMichael Buesch }
16761e115a5SMichael Buesch 
16861e115a5SMichael Buesch /* Get the word-offset for a SSB_SPROM_XXX define. */
1690a182fd8SRafał Miłecki #define SPOFF(offset)	((offset) / sizeof(u16))
17061e115a5SMichael Buesch /* Helper to extract some _offset, which is one of the SSB_SPROM_XXX defines. */
171f679056bSGábor Stefanik #define SPEX16(_outvar, _offset, _mask, _shift)	\
17261e115a5SMichael Buesch 	out->_outvar = ((in[SPOFF(_offset)] & (_mask)) >> (_shift))
173f679056bSGábor Stefanik #define SPEX32(_outvar, _offset, _mask, _shift)	\
174f679056bSGábor Stefanik 	out->_outvar = ((((u32)in[SPOFF((_offset)+2)] << 16 | \
175f679056bSGábor Stefanik 			   in[SPOFF(_offset)]) & (_mask)) >> (_shift))
176f679056bSGábor Stefanik #define SPEX(_outvar, _offset, _mask, _shift) \
177f679056bSGábor Stefanik 	SPEX16(_outvar, _offset, _mask, _shift)
178f679056bSGábor Stefanik 
179e2da4bd3SHauke Mehrtens #define SPEX_ARRAY8(_field, _offset, _mask, _shift)	\
180e2da4bd3SHauke Mehrtens 	do {	\
181e2da4bd3SHauke Mehrtens 		SPEX(_field[0], _offset +  0, _mask, _shift);	\
182e2da4bd3SHauke Mehrtens 		SPEX(_field[1], _offset +  2, _mask, _shift);	\
183e2da4bd3SHauke Mehrtens 		SPEX(_field[2], _offset +  4, _mask, _shift);	\
184e2da4bd3SHauke Mehrtens 		SPEX(_field[3], _offset +  6, _mask, _shift);	\
185e2da4bd3SHauke Mehrtens 		SPEX(_field[4], _offset +  8, _mask, _shift);	\
186e2da4bd3SHauke Mehrtens 		SPEX(_field[5], _offset + 10, _mask, _shift);	\
187e2da4bd3SHauke Mehrtens 		SPEX(_field[6], _offset + 12, _mask, _shift);	\
188e2da4bd3SHauke Mehrtens 		SPEX(_field[7], _offset + 14, _mask, _shift);	\
189e2da4bd3SHauke Mehrtens 	} while (0)
190e2da4bd3SHauke Mehrtens 
19161e115a5SMichael Buesch 
19261e115a5SMichael Buesch static inline u8 ssb_crc8(u8 crc, u8 data)
19361e115a5SMichael Buesch {
19461e115a5SMichael Buesch 	/* Polynomial:   x^8 + x^7 + x^6 + x^4 + x^2 + 1   */
19561e115a5SMichael Buesch 	static const u8 t[] = {
19661e115a5SMichael Buesch 		0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
19761e115a5SMichael Buesch 		0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
19861e115a5SMichael Buesch 		0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
19961e115a5SMichael Buesch 		0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
20061e115a5SMichael Buesch 		0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
20161e115a5SMichael Buesch 		0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
20261e115a5SMichael Buesch 		0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
20361e115a5SMichael Buesch 		0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
20461e115a5SMichael Buesch 		0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
20561e115a5SMichael Buesch 		0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
20661e115a5SMichael Buesch 		0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
20761e115a5SMichael Buesch 		0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
20861e115a5SMichael Buesch 		0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
20961e115a5SMichael Buesch 		0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
21061e115a5SMichael Buesch 		0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
21161e115a5SMichael Buesch 		0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
21261e115a5SMichael Buesch 		0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
21361e115a5SMichael Buesch 		0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
21461e115a5SMichael Buesch 		0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
21561e115a5SMichael Buesch 		0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
21661e115a5SMichael Buesch 		0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
21761e115a5SMichael Buesch 		0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
21861e115a5SMichael Buesch 		0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
21961e115a5SMichael Buesch 		0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
22061e115a5SMichael Buesch 		0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
22161e115a5SMichael Buesch 		0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
22261e115a5SMichael Buesch 		0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
22361e115a5SMichael Buesch 		0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
22461e115a5SMichael Buesch 		0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
22561e115a5SMichael Buesch 		0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
22661e115a5SMichael Buesch 		0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
22761e115a5SMichael Buesch 		0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F,
22861e115a5SMichael Buesch 	};
22961e115a5SMichael Buesch 	return t[crc ^ data];
23061e115a5SMichael Buesch }
23161e115a5SMichael Buesch 
232e5652756SJoe Perches static void sprom_get_mac(char *mac, const u16 *in)
233e5652756SJoe Perches {
234e5652756SJoe Perches 	int i;
235e5652756SJoe Perches 	for (i = 0; i < 3; i++) {
236e5652756SJoe Perches 		*mac++ = in[i] >> 8;
237a9fac739SLarry Finger 		*mac++ = in[i];
238e5652756SJoe Perches 	}
239e5652756SJoe Perches }
240e5652756SJoe Perches 
241c272ef44SLarry Finger static u8 ssb_sprom_crc(const u16 *sprom, u16 size)
24261e115a5SMichael Buesch {
24361e115a5SMichael Buesch 	int word;
24461e115a5SMichael Buesch 	u8 crc = 0xFF;
24561e115a5SMichael Buesch 
246c272ef44SLarry Finger 	for (word = 0; word < size - 1; word++) {
24761e115a5SMichael Buesch 		crc = ssb_crc8(crc, sprom[word] & 0x00FF);
24861e115a5SMichael Buesch 		crc = ssb_crc8(crc, (sprom[word] & 0xFF00) >> 8);
24961e115a5SMichael Buesch 	}
250c272ef44SLarry Finger 	crc = ssb_crc8(crc, sprom[size - 1] & 0x00FF);
25161e115a5SMichael Buesch 	crc ^= 0xFF;
25261e115a5SMichael Buesch 
25361e115a5SMichael Buesch 	return crc;
25461e115a5SMichael Buesch }
25561e115a5SMichael Buesch 
256e7ec2e32SMichael Buesch static int sprom_check_crc(const u16 *sprom, size_t size)
25761e115a5SMichael Buesch {
25861e115a5SMichael Buesch 	u8 crc;
25961e115a5SMichael Buesch 	u8 expected_crc;
26061e115a5SMichael Buesch 	u16 tmp;
26161e115a5SMichael Buesch 
262c272ef44SLarry Finger 	crc = ssb_sprom_crc(sprom, size);
263c272ef44SLarry Finger 	tmp = sprom[size - 1] & SSB_SPROM_REVISION_CRC;
26461e115a5SMichael Buesch 	expected_crc = tmp >> SSB_SPROM_REVISION_CRC_SHIFT;
26561e115a5SMichael Buesch 	if (crc != expected_crc)
26661e115a5SMichael Buesch 		return -EPROTO;
26761e115a5SMichael Buesch 
26861e115a5SMichael Buesch 	return 0;
26961e115a5SMichael Buesch }
27061e115a5SMichael Buesch 
271e7ec2e32SMichael Buesch static int sprom_do_read(struct ssb_bus *bus, u16 *sprom)
27261e115a5SMichael Buesch {
27361e115a5SMichael Buesch 	int i;
27461e115a5SMichael Buesch 
275c272ef44SLarry Finger 	for (i = 0; i < bus->sprom_size; i++)
276ea2db495SRafał Miłecki 		sprom[i] = ioread16(bus->mmio + bus->sprom_offset + (i * 2));
277e7ec2e32SMichael Buesch 
278e7ec2e32SMichael Buesch 	return 0;
27961e115a5SMichael Buesch }
28061e115a5SMichael Buesch 
28161e115a5SMichael Buesch static int sprom_do_write(struct ssb_bus *bus, const u16 *sprom)
28261e115a5SMichael Buesch {
28361e115a5SMichael Buesch 	struct pci_dev *pdev = bus->host_pci;
28461e115a5SMichael Buesch 	int i, err;
28561e115a5SMichael Buesch 	u32 spromctl;
286c272ef44SLarry Finger 	u16 size = bus->sprom_size;
28761e115a5SMichael Buesch 
288b8b6069cSMichael Büsch 	pr_notice("Writing SPROM. Do NOT turn off the power! Please stand by...\n");
28961e115a5SMichael Buesch 	err = pci_read_config_dword(pdev, SSB_SPROMCTL, &spromctl);
29061e115a5SMichael Buesch 	if (err)
29161e115a5SMichael Buesch 		goto err_ctlreg;
29261e115a5SMichael Buesch 	spromctl |= SSB_SPROMCTL_WE;
29361e115a5SMichael Buesch 	err = pci_write_config_dword(pdev, SSB_SPROMCTL, spromctl);
29461e115a5SMichael Buesch 	if (err)
29561e115a5SMichael Buesch 		goto err_ctlreg;
296b8b6069cSMichael Büsch 	pr_notice("[ 0%%");
29761e115a5SMichael Buesch 	msleep(500);
298c272ef44SLarry Finger 	for (i = 0; i < size; i++) {
299c272ef44SLarry Finger 		if (i == size / 4)
300b8b6069cSMichael Büsch 			pr_cont("25%%");
301c272ef44SLarry Finger 		else if (i == size / 2)
302b8b6069cSMichael Büsch 			pr_cont("50%%");
303c272ef44SLarry Finger 		else if (i == (size * 3) / 4)
304b8b6069cSMichael Büsch 			pr_cont("75%%");
30561e115a5SMichael Buesch 		else if (i % 2)
306b8b6069cSMichael Büsch 			pr_cont(".");
307ea2db495SRafał Miłecki 		writew(sprom[i], bus->mmio + bus->sprom_offset + (i * 2));
30861e115a5SMichael Buesch 		mmiowb();
30961e115a5SMichael Buesch 		msleep(20);
31061e115a5SMichael Buesch 	}
31161e115a5SMichael Buesch 	err = pci_read_config_dword(pdev, SSB_SPROMCTL, &spromctl);
31261e115a5SMichael Buesch 	if (err)
31361e115a5SMichael Buesch 		goto err_ctlreg;
31461e115a5SMichael Buesch 	spromctl &= ~SSB_SPROMCTL_WE;
31561e115a5SMichael Buesch 	err = pci_write_config_dword(pdev, SSB_SPROMCTL, spromctl);
31661e115a5SMichael Buesch 	if (err)
31761e115a5SMichael Buesch 		goto err_ctlreg;
31861e115a5SMichael Buesch 	msleep(500);
319b8b6069cSMichael Büsch 	pr_cont("100%% ]\n");
320b8b6069cSMichael Büsch 	pr_notice("SPROM written\n");
32161e115a5SMichael Buesch 
32261e115a5SMichael Buesch 	return 0;
32361e115a5SMichael Buesch err_ctlreg:
324b8b6069cSMichael Büsch 	pr_err("Could not access SPROM control register.\n");
32561e115a5SMichael Buesch 	return err;
32661e115a5SMichael Buesch }
32761e115a5SMichael Buesch 
32867d392c0SRafał Miłecki static s8 sprom_extract_antgain(u8 sprom_revision, const u16 *in, u16 offset,
329e861b98dSMichael Buesch 				u16 mask, u16 shift)
330e861b98dSMichael Buesch {
331e861b98dSMichael Buesch 	u16 v;
332e861b98dSMichael Buesch 	u8 gain;
333e861b98dSMichael Buesch 
33467d392c0SRafał Miłecki 	v = in[SPOFF(offset)];
335e861b98dSMichael Buesch 	gain = (v & mask) >> shift;
336e861b98dSMichael Buesch 	if (gain == 0xFF)
337e861b98dSMichael Buesch 		gain = 2; /* If unset use 2dBm */
338e861b98dSMichael Buesch 	if (sprom_revision == 1) {
339e861b98dSMichael Buesch 		/* Convert to Q5.2 */
340e861b98dSMichael Buesch 		gain <<= 2;
341e861b98dSMichael Buesch 	} else {
342e861b98dSMichael Buesch 		/* Q5.2 Fractional part is stored in 0xC0 */
343e861b98dSMichael Buesch 		gain = ((gain & 0xC0) >> 6) | ((gain & 0x3F) << 2);
344e861b98dSMichael Buesch 	}
345e861b98dSMichael Buesch 
346e861b98dSMichael Buesch 	return (s8)gain;
347e861b98dSMichael Buesch }
348e861b98dSMichael Buesch 
3497e4235acSHauke Mehrtens static void sprom_extract_r23(struct ssb_sprom *out, const u16 *in)
3507e4235acSHauke Mehrtens {
3517e4235acSHauke Mehrtens 	SPEX(boardflags_hi, SSB_SPROM2_BFLHI, 0xFFFF, 0);
3527e4235acSHauke Mehrtens 	SPEX(opo, SSB_SPROM2_OPO, SSB_SPROM2_OPO_VALUE, 0);
3537e4235acSHauke Mehrtens 	SPEX(pa1lob0, SSB_SPROM2_PA1LOB0, 0xFFFF, 0);
3547e4235acSHauke Mehrtens 	SPEX(pa1lob1, SSB_SPROM2_PA1LOB1, 0xFFFF, 0);
3557e4235acSHauke Mehrtens 	SPEX(pa1lob2, SSB_SPROM2_PA1LOB2, 0xFFFF, 0);
3567e4235acSHauke Mehrtens 	SPEX(pa1hib0, SSB_SPROM2_PA1HIB0, 0xFFFF, 0);
3577e4235acSHauke Mehrtens 	SPEX(pa1hib1, SSB_SPROM2_PA1HIB1, 0xFFFF, 0);
3587e4235acSHauke Mehrtens 	SPEX(pa1hib2, SSB_SPROM2_PA1HIB2, 0xFFFF, 0);
3597e4235acSHauke Mehrtens 	SPEX(maxpwr_ah, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_HI, 0);
3607e4235acSHauke Mehrtens 	SPEX(maxpwr_al, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_LO,
3617e4235acSHauke Mehrtens 	     SSB_SPROM2_MAXP_A_LO_SHIFT);
3627e4235acSHauke Mehrtens }
3637e4235acSHauke Mehrtens 
364c272ef44SLarry Finger static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in)
365c272ef44SLarry Finger {
366c272ef44SLarry Finger 	u16 loc[3];
367c272ef44SLarry Finger 
36831ce12fbSLarry Finger 	if (out->revision == 3)			/* rev 3 moved MAC */
369c272ef44SLarry Finger 		loc[0] = SSB_SPROM3_IL0MAC;
37031ce12fbSLarry Finger 	else {
371c272ef44SLarry Finger 		loc[0] = SSB_SPROM1_IL0MAC;
372c272ef44SLarry Finger 		loc[1] = SSB_SPROM1_ET0MAC;
373c272ef44SLarry Finger 		loc[2] = SSB_SPROM1_ET1MAC;
374c272ef44SLarry Finger 	}
375e5652756SJoe Perches 	sprom_get_mac(out->il0mac, &in[SPOFF(loc[0])]);
37631ce12fbSLarry Finger 	if (out->revision < 3) { 	/* only rev 1-2 have et0, et1 */
377e5652756SJoe Perches 		sprom_get_mac(out->et0mac, &in[SPOFF(loc[1])]);
378e5652756SJoe Perches 		sprom_get_mac(out->et1mac, &in[SPOFF(loc[2])]);
37931ce12fbSLarry Finger 	}
380c272ef44SLarry Finger 	SPEX(et0phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0A, 0);
381c272ef44SLarry Finger 	SPEX(et1phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1A,
382c272ef44SLarry Finger 	     SSB_SPROM1_ETHPHY_ET1A_SHIFT);
383e861b98dSMichael Buesch 	SPEX(et0mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0M, 14);
384e861b98dSMichael Buesch 	SPEX(et1mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1M, 15);
385e861b98dSMichael Buesch 	SPEX(board_rev, SSB_SPROM1_BINF, SSB_SPROM1_BINF_BREV, 0);
3863623b266SRafał Miłecki 	SPEX(board_type, SSB_SPROM1_SPID, 0xFFFF, 0);
387bf7d420bSHauke Mehrtens 	if (out->revision == 1)
388c272ef44SLarry Finger 		SPEX(country_code, SSB_SPROM1_BINF, SSB_SPROM1_BINF_CCODE,
389c272ef44SLarry Finger 		     SSB_SPROM1_BINF_CCODE_SHIFT);
390e861b98dSMichael Buesch 	SPEX(ant_available_a, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTA,
391e861b98dSMichael Buesch 	     SSB_SPROM1_BINF_ANTA_SHIFT);
392e861b98dSMichael Buesch 	SPEX(ant_available_bg, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTBG,
393e861b98dSMichael Buesch 	     SSB_SPROM1_BINF_ANTBG_SHIFT);
394c272ef44SLarry Finger 	SPEX(pa0b0, SSB_SPROM1_PA0B0, 0xFFFF, 0);
395c272ef44SLarry Finger 	SPEX(pa0b1, SSB_SPROM1_PA0B1, 0xFFFF, 0);
396c272ef44SLarry Finger 	SPEX(pa0b2, SSB_SPROM1_PA0B2, 0xFFFF, 0);
397c272ef44SLarry Finger 	SPEX(pa1b0, SSB_SPROM1_PA1B0, 0xFFFF, 0);
398c272ef44SLarry Finger 	SPEX(pa1b1, SSB_SPROM1_PA1B1, 0xFFFF, 0);
399c272ef44SLarry Finger 	SPEX(pa1b2, SSB_SPROM1_PA1B2, 0xFFFF, 0);
400c272ef44SLarry Finger 	SPEX(gpio0, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P0, 0);
401c272ef44SLarry Finger 	SPEX(gpio1, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P1,
402c272ef44SLarry Finger 	     SSB_SPROM1_GPIOA_P1_SHIFT);
403c272ef44SLarry Finger 	SPEX(gpio2, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P2, 0);
404c272ef44SLarry Finger 	SPEX(gpio3, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P3,
405c272ef44SLarry Finger 	     SSB_SPROM1_GPIOB_P3_SHIFT);
406c272ef44SLarry Finger 	SPEX(maxpwr_a, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_A,
407c272ef44SLarry Finger 	     SSB_SPROM1_MAXPWR_A_SHIFT);
408c272ef44SLarry Finger 	SPEX(maxpwr_bg, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_BG, 0);
409c272ef44SLarry Finger 	SPEX(itssi_a, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_A,
410c272ef44SLarry Finger 	     SSB_SPROM1_ITSSI_A_SHIFT);
411c272ef44SLarry Finger 	SPEX(itssi_bg, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_BG, 0);
412c272ef44SLarry Finger 	SPEX(boardflags_lo, SSB_SPROM1_BFLLO, 0xFFFF, 0);
4137e4235acSHauke Mehrtens 
414bf7d420bSHauke Mehrtens 	SPEX(alpha2[0], SSB_SPROM1_CCODE, 0xff00, 8);
415bf7d420bSHauke Mehrtens 	SPEX(alpha2[1], SSB_SPROM1_CCODE, 0x00ff, 0);
416e861b98dSMichael Buesch 
417e861b98dSMichael Buesch 	/* Extract the antenna gain values. */
41867d392c0SRafał Miłecki 	out->antenna_gain.a0 = sprom_extract_antgain(out->revision, in,
41967d392c0SRafał Miłecki 						     SSB_SPROM1_AGAIN,
420e861b98dSMichael Buesch 						     SSB_SPROM1_AGAIN_BG,
421c272ef44SLarry Finger 						     SSB_SPROM1_AGAIN_BG_SHIFT);
42267d392c0SRafał Miłecki 	out->antenna_gain.a1 = sprom_extract_antgain(out->revision, in,
42367d392c0SRafał Miłecki 						     SSB_SPROM1_AGAIN,
424e861b98dSMichael Buesch 						     SSB_SPROM1_AGAIN_A,
425e861b98dSMichael Buesch 						     SSB_SPROM1_AGAIN_A_SHIFT);
4267e4235acSHauke Mehrtens 	if (out->revision >= 2)
4277e4235acSHauke Mehrtens 		sprom_extract_r23(out, in);
428c272ef44SLarry Finger }
429c272ef44SLarry Finger 
430172c69a4SRafał Miłecki /* Revs 4 5 and 8 have partially shared layout */
431172c69a4SRafał Miłecki static void sprom_extract_r458(struct ssb_sprom *out, const u16 *in)
432172c69a4SRafał Miłecki {
433172c69a4SRafał Miłecki 	SPEX(txpid2g[0], SSB_SPROM4_TXPID2G01,
434172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID2G0, SSB_SPROM4_TXPID2G0_SHIFT);
435172c69a4SRafał Miłecki 	SPEX(txpid2g[1], SSB_SPROM4_TXPID2G01,
436172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID2G1, SSB_SPROM4_TXPID2G1_SHIFT);
437172c69a4SRafał Miłecki 	SPEX(txpid2g[2], SSB_SPROM4_TXPID2G23,
438172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID2G2, SSB_SPROM4_TXPID2G2_SHIFT);
439172c69a4SRafał Miłecki 	SPEX(txpid2g[3], SSB_SPROM4_TXPID2G23,
440172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID2G3, SSB_SPROM4_TXPID2G3_SHIFT);
441172c69a4SRafał Miłecki 
442172c69a4SRafał Miłecki 	SPEX(txpid5gl[0], SSB_SPROM4_TXPID5GL01,
443172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID5GL0, SSB_SPROM4_TXPID5GL0_SHIFT);
444172c69a4SRafał Miłecki 	SPEX(txpid5gl[1], SSB_SPROM4_TXPID5GL01,
445172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID5GL1, SSB_SPROM4_TXPID5GL1_SHIFT);
446172c69a4SRafał Miłecki 	SPEX(txpid5gl[2], SSB_SPROM4_TXPID5GL23,
447172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID5GL2, SSB_SPROM4_TXPID5GL2_SHIFT);
448172c69a4SRafał Miłecki 	SPEX(txpid5gl[3], SSB_SPROM4_TXPID5GL23,
449172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID5GL3, SSB_SPROM4_TXPID5GL3_SHIFT);
450172c69a4SRafał Miłecki 
451172c69a4SRafał Miłecki 	SPEX(txpid5g[0], SSB_SPROM4_TXPID5G01,
452172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID5G0, SSB_SPROM4_TXPID5G0_SHIFT);
453172c69a4SRafał Miłecki 	SPEX(txpid5g[1], SSB_SPROM4_TXPID5G01,
454172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID5G1, SSB_SPROM4_TXPID5G1_SHIFT);
455172c69a4SRafał Miłecki 	SPEX(txpid5g[2], SSB_SPROM4_TXPID5G23,
456172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID5G2, SSB_SPROM4_TXPID5G2_SHIFT);
457172c69a4SRafał Miłecki 	SPEX(txpid5g[3], SSB_SPROM4_TXPID5G23,
458172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID5G3, SSB_SPROM4_TXPID5G3_SHIFT);
459172c69a4SRafał Miłecki 
460172c69a4SRafał Miłecki 	SPEX(txpid5gh[0], SSB_SPROM4_TXPID5GH01,
461172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID5GH0, SSB_SPROM4_TXPID5GH0_SHIFT);
462172c69a4SRafał Miłecki 	SPEX(txpid5gh[1], SSB_SPROM4_TXPID5GH01,
463172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID5GH1, SSB_SPROM4_TXPID5GH1_SHIFT);
464172c69a4SRafał Miłecki 	SPEX(txpid5gh[2], SSB_SPROM4_TXPID5GH23,
465172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID5GH2, SSB_SPROM4_TXPID5GH2_SHIFT);
466172c69a4SRafał Miłecki 	SPEX(txpid5gh[3], SSB_SPROM4_TXPID5GH23,
467172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID5GH3, SSB_SPROM4_TXPID5GH3_SHIFT);
468172c69a4SRafał Miłecki }
469172c69a4SRafał Miłecki 
470095f695cSLarry Finger static void sprom_extract_r45(struct ssb_sprom *out, const u16 *in)
47161e115a5SMichael Buesch {
4726ad59343SRafał Miłecki 	static const u16 pwr_info_offset[] = {
4736ad59343SRafał Miłecki 		SSB_SPROM4_PWR_INFO_CORE0, SSB_SPROM4_PWR_INFO_CORE1,
4746ad59343SRafał Miłecki 		SSB_SPROM4_PWR_INFO_CORE2, SSB_SPROM4_PWR_INFO_CORE3
4756ad59343SRafał Miłecki 	};
476095f695cSLarry Finger 	u16 il0mac_offset;
4776ad59343SRafał Miłecki 	int i;
4786ad59343SRafał Miłecki 
4796ad59343SRafał Miłecki 	BUILD_BUG_ON(ARRAY_SIZE(pwr_info_offset) !=
4806ad59343SRafał Miłecki 		     ARRAY_SIZE(out->core_pwr_info));
48161e115a5SMichael Buesch 
482095f695cSLarry Finger 	if (out->revision == 4)
483095f695cSLarry Finger 		il0mac_offset = SSB_SPROM4_IL0MAC;
484095f695cSLarry Finger 	else
485095f695cSLarry Finger 		il0mac_offset = SSB_SPROM5_IL0MAC;
486e5652756SJoe Perches 
487e5652756SJoe Perches 	sprom_get_mac(out->il0mac, &in[SPOFF(il0mac_offset)]);
488e5652756SJoe Perches 
489c272ef44SLarry Finger 	SPEX(et0phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET0A, 0);
490c272ef44SLarry Finger 	SPEX(et1phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET1A,
491c272ef44SLarry Finger 	     SSB_SPROM4_ETHPHY_ET1A_SHIFT);
492673335c8SHauke Mehrtens 	SPEX(board_rev, SSB_SPROM4_BOARDREV, 0xFFFF, 0);
4933623b266SRafał Miłecki 	SPEX(board_type, SSB_SPROM1_SPID, 0xFFFF, 0);
494095f695cSLarry Finger 	if (out->revision == 4) {
495bf7d420bSHauke Mehrtens 		SPEX(alpha2[0], SSB_SPROM4_CCODE, 0xff00, 8);
496bf7d420bSHauke Mehrtens 		SPEX(alpha2[1], SSB_SPROM4_CCODE, 0x00ff, 0);
497c272ef44SLarry Finger 		SPEX(boardflags_lo, SSB_SPROM4_BFLLO, 0xFFFF, 0);
498af4b7450SMichael Buesch 		SPEX(boardflags_hi, SSB_SPROM4_BFLHI, 0xFFFF, 0);
4996d1d4ea4SRafał Miłecki 		SPEX(boardflags2_lo, SSB_SPROM4_BFL2LO, 0xFFFF, 0);
5006d1d4ea4SRafał Miłecki 		SPEX(boardflags2_hi, SSB_SPROM4_BFL2HI, 0xFFFF, 0);
501095f695cSLarry Finger 	} else {
502bf7d420bSHauke Mehrtens 		SPEX(alpha2[0], SSB_SPROM5_CCODE, 0xff00, 8);
503bf7d420bSHauke Mehrtens 		SPEX(alpha2[1], SSB_SPROM5_CCODE, 0x00ff, 0);
504095f695cSLarry Finger 		SPEX(boardflags_lo, SSB_SPROM5_BFLLO, 0xFFFF, 0);
505095f695cSLarry Finger 		SPEX(boardflags_hi, SSB_SPROM5_BFLHI, 0xFFFF, 0);
5066d1d4ea4SRafał Miłecki 		SPEX(boardflags2_lo, SSB_SPROM5_BFL2LO, 0xFFFF, 0);
5076d1d4ea4SRafał Miłecki 		SPEX(boardflags2_hi, SSB_SPROM5_BFL2HI, 0xFFFF, 0);
508095f695cSLarry Finger 	}
509e861b98dSMichael Buesch 	SPEX(ant_available_a, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_A,
510e861b98dSMichael Buesch 	     SSB_SPROM4_ANTAVAIL_A_SHIFT);
511e861b98dSMichael Buesch 	SPEX(ant_available_bg, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_BG,
512e861b98dSMichael Buesch 	     SSB_SPROM4_ANTAVAIL_BG_SHIFT);
513d3c319f9SLarry Finger 	SPEX(maxpwr_bg, SSB_SPROM4_MAXP_BG, SSB_SPROM4_MAXP_BG_MASK, 0);
514d3c319f9SLarry Finger 	SPEX(itssi_bg, SSB_SPROM4_MAXP_BG, SSB_SPROM4_ITSSI_BG,
515d3c319f9SLarry Finger 	     SSB_SPROM4_ITSSI_BG_SHIFT);
516d3c319f9SLarry Finger 	SPEX(maxpwr_a, SSB_SPROM4_MAXP_A, SSB_SPROM4_MAXP_A_MASK, 0);
517d3c319f9SLarry Finger 	SPEX(itssi_a, SSB_SPROM4_MAXP_A, SSB_SPROM4_ITSSI_A,
518d3c319f9SLarry Finger 	     SSB_SPROM4_ITSSI_A_SHIFT);
519095f695cSLarry Finger 	if (out->revision == 4) {
520d3c319f9SLarry Finger 		SPEX(gpio0, SSB_SPROM4_GPIOA, SSB_SPROM4_GPIOA_P0, 0);
521d3c319f9SLarry Finger 		SPEX(gpio1, SSB_SPROM4_GPIOA, SSB_SPROM4_GPIOA_P1,
522d3c319f9SLarry Finger 		     SSB_SPROM4_GPIOA_P1_SHIFT);
523d3c319f9SLarry Finger 		SPEX(gpio2, SSB_SPROM4_GPIOB, SSB_SPROM4_GPIOB_P2, 0);
524d3c319f9SLarry Finger 		SPEX(gpio3, SSB_SPROM4_GPIOB, SSB_SPROM4_GPIOB_P3,
525d3c319f9SLarry Finger 		     SSB_SPROM4_GPIOB_P3_SHIFT);
526095f695cSLarry Finger 	} else {
527095f695cSLarry Finger 		SPEX(gpio0, SSB_SPROM5_GPIOA, SSB_SPROM5_GPIOA_P0, 0);
528095f695cSLarry Finger 		SPEX(gpio1, SSB_SPROM5_GPIOA, SSB_SPROM5_GPIOA_P1,
529095f695cSLarry Finger 		     SSB_SPROM5_GPIOA_P1_SHIFT);
530095f695cSLarry Finger 		SPEX(gpio2, SSB_SPROM5_GPIOB, SSB_SPROM5_GPIOB_P2, 0);
531095f695cSLarry Finger 		SPEX(gpio3, SSB_SPROM5_GPIOB, SSB_SPROM5_GPIOB_P3,
532095f695cSLarry Finger 		     SSB_SPROM5_GPIOB_P3_SHIFT);
533095f695cSLarry Finger 	}
534e861b98dSMichael Buesch 
535e861b98dSMichael Buesch 	/* Extract the antenna gain values. */
5366daf4321SRafał Miłecki 	out->antenna_gain.a0 = sprom_extract_antgain(out->revision, in,
5376daf4321SRafał Miłecki 						     SSB_SPROM4_AGAIN01,
5386daf4321SRafał Miłecki 						     SSB_SPROM4_AGAIN0,
5396daf4321SRafał Miłecki 						     SSB_SPROM4_AGAIN0_SHIFT);
5406daf4321SRafał Miłecki 	out->antenna_gain.a1 = sprom_extract_antgain(out->revision, in,
5416daf4321SRafał Miłecki 						     SSB_SPROM4_AGAIN01,
5426daf4321SRafał Miłecki 						     SSB_SPROM4_AGAIN1,
5436daf4321SRafał Miłecki 						     SSB_SPROM4_AGAIN1_SHIFT);
5446daf4321SRafał Miłecki 	out->antenna_gain.a2 = sprom_extract_antgain(out->revision, in,
5456daf4321SRafał Miłecki 						     SSB_SPROM4_AGAIN23,
5466daf4321SRafał Miłecki 						     SSB_SPROM4_AGAIN2,
5476daf4321SRafał Miłecki 						     SSB_SPROM4_AGAIN2_SHIFT);
5486daf4321SRafał Miłecki 	out->antenna_gain.a3 = sprom_extract_antgain(out->revision, in,
5496daf4321SRafał Miłecki 						     SSB_SPROM4_AGAIN23,
5506daf4321SRafał Miłecki 						     SSB_SPROM4_AGAIN3,
5516daf4321SRafał Miłecki 						     SSB_SPROM4_AGAIN3_SHIFT);
552e861b98dSMichael Buesch 
5536ad59343SRafał Miłecki 	/* Extract cores power info info */
5546ad59343SRafał Miłecki 	for (i = 0; i < ARRAY_SIZE(pwr_info_offset); i++) {
5556ad59343SRafał Miłecki 		u16 o = pwr_info_offset[i];
5566ad59343SRafał Miłecki 
5576ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].itssi_2g, o + SSB_SPROM4_2G_MAXP_ITSSI,
5586ad59343SRafał Miłecki 			SSB_SPROM4_2G_ITSSI, SSB_SPROM4_2G_ITSSI_SHIFT);
5596ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].maxpwr_2g, o + SSB_SPROM4_2G_MAXP_ITSSI,
5606ad59343SRafał Miłecki 			SSB_SPROM4_2G_MAXP, 0);
5616ad59343SRafał Miłecki 
5626ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].pa_2g[0], o + SSB_SPROM4_2G_PA_0, ~0, 0);
5636ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].pa_2g[1], o + SSB_SPROM4_2G_PA_1, ~0, 0);
5646ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].pa_2g[2], o + SSB_SPROM4_2G_PA_2, ~0, 0);
5656ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].pa_2g[3], o + SSB_SPROM4_2G_PA_3, ~0, 0);
5666ad59343SRafał Miłecki 
5676ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].itssi_5g, o + SSB_SPROM4_5G_MAXP_ITSSI,
5686ad59343SRafał Miłecki 			SSB_SPROM4_5G_ITSSI, SSB_SPROM4_5G_ITSSI_SHIFT);
5696ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].maxpwr_5g, o + SSB_SPROM4_5G_MAXP_ITSSI,
5706ad59343SRafał Miłecki 			SSB_SPROM4_5G_MAXP, 0);
5716ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].maxpwr_5gh, o + SSB_SPROM4_5GHL_MAXP,
5726ad59343SRafał Miłecki 			SSB_SPROM4_5GH_MAXP, 0);
5736ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].maxpwr_5gl, o + SSB_SPROM4_5GHL_MAXP,
5746ad59343SRafał Miłecki 			SSB_SPROM4_5GL_MAXP, SSB_SPROM4_5GL_MAXP_SHIFT);
5756ad59343SRafał Miłecki 
5766ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gl[0], o + SSB_SPROM4_5GL_PA_0, ~0, 0);
5776ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gl[1], o + SSB_SPROM4_5GL_PA_1, ~0, 0);
5786ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gl[2], o + SSB_SPROM4_5GL_PA_2, ~0, 0);
5796ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gl[3], o + SSB_SPROM4_5GL_PA_3, ~0, 0);
5806ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5g[0], o + SSB_SPROM4_5G_PA_0, ~0, 0);
5816ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5g[1], o + SSB_SPROM4_5G_PA_1, ~0, 0);
5826ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5g[2], o + SSB_SPROM4_5G_PA_2, ~0, 0);
5836ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5g[3], o + SSB_SPROM4_5G_PA_3, ~0, 0);
5846ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gh[0], o + SSB_SPROM4_5GH_PA_0, ~0, 0);
5856ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gh[1], o + SSB_SPROM4_5GH_PA_1, ~0, 0);
5866ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gh[2], o + SSB_SPROM4_5GH_PA_2, ~0, 0);
5876ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gh[3], o + SSB_SPROM4_5GH_PA_3, ~0, 0);
5886ad59343SRafał Miłecki 	}
5896ad59343SRafał Miłecki 
590172c69a4SRafał Miłecki 	sprom_extract_r458(out, in);
591172c69a4SRafał Miłecki 
592c272ef44SLarry Finger 	/* TODO - get remaining rev 4 stuff needed */
59361e115a5SMichael Buesch }
59461e115a5SMichael Buesch 
5956b1c7c67SMichael Buesch static void sprom_extract_r8(struct ssb_sprom *out, const u16 *in)
5966b1c7c67SMichael Buesch {
5976b1c7c67SMichael Buesch 	int i;
598e5652756SJoe Perches 	u16 o;
599b0f70292SRafał Miłecki 	u16 pwr_info_offset[] = {
600b0f70292SRafał Miłecki 		SSB_SROM8_PWR_INFO_CORE0, SSB_SROM8_PWR_INFO_CORE1,
601b0f70292SRafał Miłecki 		SSB_SROM8_PWR_INFO_CORE2, SSB_SROM8_PWR_INFO_CORE3
602b0f70292SRafał Miłecki 	};
603b0f70292SRafał Miłecki 	BUILD_BUG_ON(ARRAY_SIZE(pwr_info_offset) !=
604b0f70292SRafał Miłecki 			ARRAY_SIZE(out->core_pwr_info));
6056b1c7c67SMichael Buesch 
6066b1c7c67SMichael Buesch 	/* extract the MAC address */
607e5652756SJoe Perches 	sprom_get_mac(out->il0mac, &in[SPOFF(SSB_SPROM8_IL0MAC)]);
608e5652756SJoe Perches 
609673335c8SHauke Mehrtens 	SPEX(board_rev, SSB_SPROM8_BOARDREV, 0xFFFF, 0);
6103623b266SRafał Miłecki 	SPEX(board_type, SSB_SPROM1_SPID, 0xFFFF, 0);
611bf7d420bSHauke Mehrtens 	SPEX(alpha2[0], SSB_SPROM8_CCODE, 0xff00, 8);
612bf7d420bSHauke Mehrtens 	SPEX(alpha2[1], SSB_SPROM8_CCODE, 0x00ff, 0);
6136b1c7c67SMichael Buesch 	SPEX(boardflags_lo, SSB_SPROM8_BFLLO, 0xFFFF, 0);
6146b1c7c67SMichael Buesch 	SPEX(boardflags_hi, SSB_SPROM8_BFLHI, 0xFFFF, 0);
615f679056bSGábor Stefanik 	SPEX(boardflags2_lo, SSB_SPROM8_BFL2LO, 0xFFFF, 0);
616f679056bSGábor Stefanik 	SPEX(boardflags2_hi, SSB_SPROM8_BFL2HI, 0xFFFF, 0);
6176b1c7c67SMichael Buesch 	SPEX(ant_available_a, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_A,
6186b1c7c67SMichael Buesch 	     SSB_SPROM8_ANTAVAIL_A_SHIFT);
6196b1c7c67SMichael Buesch 	SPEX(ant_available_bg, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_BG,
6206b1c7c67SMichael Buesch 	     SSB_SPROM8_ANTAVAIL_BG_SHIFT);
6216b1c7c67SMichael Buesch 	SPEX(maxpwr_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_MAXP_BG_MASK, 0);
6226b1c7c67SMichael Buesch 	SPEX(itssi_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_ITSSI_BG,
6236b1c7c67SMichael Buesch 	     SSB_SPROM8_ITSSI_BG_SHIFT);
6246b1c7c67SMichael Buesch 	SPEX(maxpwr_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_MAXP_A_MASK, 0);
6256b1c7c67SMichael Buesch 	SPEX(itssi_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_ITSSI_A,
6266b1c7c67SMichael Buesch 	     SSB_SPROM8_ITSSI_A_SHIFT);
627f679056bSGábor Stefanik 	SPEX(maxpwr_ah, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AH_MASK, 0);
628f679056bSGábor Stefanik 	SPEX(maxpwr_al, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AL_MASK,
629f679056bSGábor Stefanik 	     SSB_SPROM8_MAXP_AL_SHIFT);
6306b1c7c67SMichael Buesch 	SPEX(gpio0, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P0, 0);
6316b1c7c67SMichael Buesch 	SPEX(gpio1, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P1,
6326b1c7c67SMichael Buesch 	     SSB_SPROM8_GPIOA_P1_SHIFT);
6336b1c7c67SMichael Buesch 	SPEX(gpio2, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P2, 0);
6346b1c7c67SMichael Buesch 	SPEX(gpio3, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P3,
6356b1c7c67SMichael Buesch 	     SSB_SPROM8_GPIOB_P3_SHIFT);
636f679056bSGábor Stefanik 	SPEX(tri2g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI2G, 0);
637f679056bSGábor Stefanik 	SPEX(tri5g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI5G,
638f679056bSGábor Stefanik 	     SSB_SPROM8_TRI5G_SHIFT);
639f679056bSGábor Stefanik 	SPEX(tri5gl, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GL, 0);
640f679056bSGábor Stefanik 	SPEX(tri5gh, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GH,
641f679056bSGábor Stefanik 	     SSB_SPROM8_TRI5GH_SHIFT);
642f679056bSGábor Stefanik 	SPEX(rxpo2g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO2G, 0);
643f679056bSGábor Stefanik 	SPEX(rxpo5g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO5G,
644f679056bSGábor Stefanik 	     SSB_SPROM8_RXPO5G_SHIFT);
645f679056bSGábor Stefanik 	SPEX(rssismf2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMF2G, 0);
646f679056bSGábor Stefanik 	SPEX(rssismc2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMC2G,
647f679056bSGábor Stefanik 	     SSB_SPROM8_RSSISMC2G_SHIFT);
648f679056bSGábor Stefanik 	SPEX(rssisav2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISAV2G,
649f679056bSGábor Stefanik 	     SSB_SPROM8_RSSISAV2G_SHIFT);
650f679056bSGábor Stefanik 	SPEX(bxa2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_BXA2G,
651f679056bSGábor Stefanik 	     SSB_SPROM8_BXA2G_SHIFT);
652f679056bSGábor Stefanik 	SPEX(rssismf5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMF5G, 0);
653f679056bSGábor Stefanik 	SPEX(rssismc5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMC5G,
654f679056bSGábor Stefanik 	     SSB_SPROM8_RSSISMC5G_SHIFT);
655f679056bSGábor Stefanik 	SPEX(rssisav5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISAV5G,
656f679056bSGábor Stefanik 	     SSB_SPROM8_RSSISAV5G_SHIFT);
657f679056bSGábor Stefanik 	SPEX(bxa5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_BXA5G,
658f679056bSGábor Stefanik 	     SSB_SPROM8_BXA5G_SHIFT);
659f679056bSGábor Stefanik 	SPEX(pa0b0, SSB_SPROM8_PA0B0, 0xFFFF, 0);
660f679056bSGábor Stefanik 	SPEX(pa0b1, SSB_SPROM8_PA0B1, 0xFFFF, 0);
661f679056bSGábor Stefanik 	SPEX(pa0b2, SSB_SPROM8_PA0B2, 0xFFFF, 0);
662f679056bSGábor Stefanik 	SPEX(pa1b0, SSB_SPROM8_PA1B0, 0xFFFF, 0);
663f679056bSGábor Stefanik 	SPEX(pa1b1, SSB_SPROM8_PA1B1, 0xFFFF, 0);
664f679056bSGábor Stefanik 	SPEX(pa1b2, SSB_SPROM8_PA1B2, 0xFFFF, 0);
665f679056bSGábor Stefanik 	SPEX(pa1lob0, SSB_SPROM8_PA1LOB0, 0xFFFF, 0);
666f679056bSGábor Stefanik 	SPEX(pa1lob1, SSB_SPROM8_PA1LOB1, 0xFFFF, 0);
667f679056bSGábor Stefanik 	SPEX(pa1lob2, SSB_SPROM8_PA1LOB2, 0xFFFF, 0);
668f679056bSGábor Stefanik 	SPEX(pa1hib0, SSB_SPROM8_PA1HIB0, 0xFFFF, 0);
669f679056bSGábor Stefanik 	SPEX(pa1hib1, SSB_SPROM8_PA1HIB1, 0xFFFF, 0);
670f679056bSGábor Stefanik 	SPEX(pa1hib2, SSB_SPROM8_PA1HIB2, 0xFFFF, 0);
671f679056bSGábor Stefanik 	SPEX(cck2gpo, SSB_SPROM8_CCK2GPO, 0xFFFF, 0);
672f679056bSGábor Stefanik 	SPEX32(ofdm2gpo, SSB_SPROM8_OFDM2GPO, 0xFFFFFFFF, 0);
673f679056bSGábor Stefanik 	SPEX32(ofdm5glpo, SSB_SPROM8_OFDM5GLPO, 0xFFFFFFFF, 0);
674f679056bSGábor Stefanik 	SPEX32(ofdm5gpo, SSB_SPROM8_OFDM5GPO, 0xFFFFFFFF, 0);
675f679056bSGábor Stefanik 	SPEX32(ofdm5ghpo, SSB_SPROM8_OFDM5GHPO, 0xFFFFFFFF, 0);
6766b1c7c67SMichael Buesch 
6776b1c7c67SMichael Buesch 	/* Extract the antenna gain values. */
6786daf4321SRafał Miłecki 	out->antenna_gain.a0 = sprom_extract_antgain(out->revision, in,
6796daf4321SRafał Miłecki 						     SSB_SPROM8_AGAIN01,
6806daf4321SRafał Miłecki 						     SSB_SPROM8_AGAIN0,
6816daf4321SRafał Miłecki 						     SSB_SPROM8_AGAIN0_SHIFT);
6826daf4321SRafał Miłecki 	out->antenna_gain.a1 = sprom_extract_antgain(out->revision, in,
6836daf4321SRafał Miłecki 						     SSB_SPROM8_AGAIN01,
6846daf4321SRafał Miłecki 						     SSB_SPROM8_AGAIN1,
6856daf4321SRafał Miłecki 						     SSB_SPROM8_AGAIN1_SHIFT);
6866daf4321SRafał Miłecki 	out->antenna_gain.a2 = sprom_extract_antgain(out->revision, in,
6876daf4321SRafał Miłecki 						     SSB_SPROM8_AGAIN23,
6886daf4321SRafał Miłecki 						     SSB_SPROM8_AGAIN2,
6896daf4321SRafał Miłecki 						     SSB_SPROM8_AGAIN2_SHIFT);
6906daf4321SRafał Miłecki 	out->antenna_gain.a3 = sprom_extract_antgain(out->revision, in,
6916daf4321SRafał Miłecki 						     SSB_SPROM8_AGAIN23,
6926daf4321SRafał Miłecki 						     SSB_SPROM8_AGAIN3,
6936daf4321SRafał Miłecki 						     SSB_SPROM8_AGAIN3_SHIFT);
6946b1c7c67SMichael Buesch 
695b0f70292SRafał Miłecki 	/* Extract cores power info info */
696b0f70292SRafał Miłecki 	for (i = 0; i < ARRAY_SIZE(pwr_info_offset); i++) {
697b0f70292SRafał Miłecki 		o = pwr_info_offset[i];
698b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].itssi_2g, o + SSB_SROM8_2G_MAXP_ITSSI,
699b0f70292SRafał Miłecki 			SSB_SPROM8_2G_ITSSI, SSB_SPROM8_2G_ITSSI_SHIFT);
700b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].maxpwr_2g, o + SSB_SROM8_2G_MAXP_ITSSI,
701b0f70292SRafał Miłecki 			SSB_SPROM8_2G_MAXP, 0);
702b0f70292SRafał Miłecki 
703b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].pa_2g[0], o + SSB_SROM8_2G_PA_0, ~0, 0);
704b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].pa_2g[1], o + SSB_SROM8_2G_PA_1, ~0, 0);
705b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].pa_2g[2], o + SSB_SROM8_2G_PA_2, ~0, 0);
706b0f70292SRafał Miłecki 
707b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].itssi_5g, o + SSB_SROM8_5G_MAXP_ITSSI,
708b0f70292SRafał Miłecki 			SSB_SPROM8_5G_ITSSI, SSB_SPROM8_5G_ITSSI_SHIFT);
709b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].maxpwr_5g, o + SSB_SROM8_5G_MAXP_ITSSI,
710b0f70292SRafał Miłecki 			SSB_SPROM8_5G_MAXP, 0);
711b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].maxpwr_5gh, o + SSB_SPROM8_5GHL_MAXP,
712b0f70292SRafał Miłecki 			SSB_SPROM8_5GH_MAXP, 0);
713b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].maxpwr_5gl, o + SSB_SPROM8_5GHL_MAXP,
714b0f70292SRafał Miłecki 			SSB_SPROM8_5GL_MAXP, SSB_SPROM8_5GL_MAXP_SHIFT);
715b0f70292SRafał Miłecki 
716b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gl[0], o + SSB_SROM8_5GL_PA_0, ~0, 0);
717b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gl[1], o + SSB_SROM8_5GL_PA_1, ~0, 0);
718b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gl[2], o + SSB_SROM8_5GL_PA_2, ~0, 0);
719b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5g[0], o + SSB_SROM8_5G_PA_0, ~0, 0);
720b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5g[1], o + SSB_SROM8_5G_PA_1, ~0, 0);
721b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5g[2], o + SSB_SROM8_5G_PA_2, ~0, 0);
722b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gh[0], o + SSB_SROM8_5GH_PA_0, ~0, 0);
723b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gh[1], o + SSB_SROM8_5GH_PA_1, ~0, 0);
724b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gh[2], o + SSB_SROM8_5GH_PA_2, ~0, 0);
725b0f70292SRafał Miłecki 	}
726b0f70292SRafał Miłecki 
7278a5ac6ecSRafał Miłecki 	/* Extract FEM info */
7288a5ac6ecSRafał Miłecki 	SPEX(fem.ghz2.tssipos, SSB_SPROM8_FEM2G,
7298a5ac6ecSRafał Miłecki 		SSB_SROM8_FEM_TSSIPOS, SSB_SROM8_FEM_TSSIPOS_SHIFT);
7308a5ac6ecSRafał Miłecki 	SPEX(fem.ghz2.extpa_gain, SSB_SPROM8_FEM2G,
7318a5ac6ecSRafał Miłecki 		SSB_SROM8_FEM_EXTPA_GAIN, SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
7328a5ac6ecSRafał Miłecki 	SPEX(fem.ghz2.pdet_range, SSB_SPROM8_FEM2G,
7338a5ac6ecSRafał Miłecki 		SSB_SROM8_FEM_PDET_RANGE, SSB_SROM8_FEM_PDET_RANGE_SHIFT);
7348a5ac6ecSRafał Miłecki 	SPEX(fem.ghz2.tr_iso, SSB_SPROM8_FEM2G,
7358a5ac6ecSRafał Miłecki 		SSB_SROM8_FEM_TR_ISO, SSB_SROM8_FEM_TR_ISO_SHIFT);
7368a5ac6ecSRafał Miłecki 	SPEX(fem.ghz2.antswlut, SSB_SPROM8_FEM2G,
7378a5ac6ecSRafał Miłecki 		SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT);
7388a5ac6ecSRafał Miłecki 
7398a5ac6ecSRafał Miłecki 	SPEX(fem.ghz5.tssipos, SSB_SPROM8_FEM5G,
7408a5ac6ecSRafał Miłecki 		SSB_SROM8_FEM_TSSIPOS, SSB_SROM8_FEM_TSSIPOS_SHIFT);
7418a5ac6ecSRafał Miłecki 	SPEX(fem.ghz5.extpa_gain, SSB_SPROM8_FEM5G,
7428a5ac6ecSRafał Miłecki 		SSB_SROM8_FEM_EXTPA_GAIN, SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
7438a5ac6ecSRafał Miłecki 	SPEX(fem.ghz5.pdet_range, SSB_SPROM8_FEM5G,
7448a5ac6ecSRafał Miłecki 		SSB_SROM8_FEM_PDET_RANGE, SSB_SROM8_FEM_PDET_RANGE_SHIFT);
7458a5ac6ecSRafał Miłecki 	SPEX(fem.ghz5.tr_iso, SSB_SPROM8_FEM5G,
7468a5ac6ecSRafał Miłecki 		SSB_SROM8_FEM_TR_ISO, SSB_SROM8_FEM_TR_ISO_SHIFT);
7478a5ac6ecSRafał Miłecki 	SPEX(fem.ghz5.antswlut, SSB_SPROM8_FEM5G,
7488a5ac6ecSRafał Miłecki 		SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT);
7498a5ac6ecSRafał Miłecki 
750e2da4bd3SHauke Mehrtens 	SPEX(leddc_on_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_ON,
751e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_LEDDC_ON_SHIFT);
752e2da4bd3SHauke Mehrtens 	SPEX(leddc_off_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_OFF,
753e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_LEDDC_OFF_SHIFT);
754e2da4bd3SHauke Mehrtens 
755e2da4bd3SHauke Mehrtens 	SPEX(txchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_TXCHAIN,
756e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_TXRXC_TXCHAIN_SHIFT);
757e2da4bd3SHauke Mehrtens 	SPEX(rxchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_RXCHAIN,
758e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_TXRXC_RXCHAIN_SHIFT);
759e2da4bd3SHauke Mehrtens 	SPEX(antswitch, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_SWITCH,
760e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_TXRXC_SWITCH_SHIFT);
761e2da4bd3SHauke Mehrtens 
762e2da4bd3SHauke Mehrtens 	SPEX(opo, SSB_SPROM8_OFDM2GPO, 0x00ff, 0);
763e2da4bd3SHauke Mehrtens 
764e2da4bd3SHauke Mehrtens 	SPEX_ARRAY8(mcs2gpo, SSB_SPROM8_2G_MCSPO, ~0, 0);
765e2da4bd3SHauke Mehrtens 	SPEX_ARRAY8(mcs5gpo, SSB_SPROM8_5G_MCSPO, ~0, 0);
766e2da4bd3SHauke Mehrtens 	SPEX_ARRAY8(mcs5glpo, SSB_SPROM8_5GL_MCSPO, ~0, 0);
767e2da4bd3SHauke Mehrtens 	SPEX_ARRAY8(mcs5ghpo, SSB_SPROM8_5GH_MCSPO, ~0, 0);
768e2da4bd3SHauke Mehrtens 
769e2da4bd3SHauke Mehrtens 	SPEX(rawtempsense, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_RAWTEMP,
770e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_RAWTS_RAWTEMP_SHIFT);
771e2da4bd3SHauke Mehrtens 	SPEX(measpower, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_MEASPOWER,
772e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_RAWTS_MEASPOWER_SHIFT);
773e2da4bd3SHauke Mehrtens 	SPEX(tempsense_slope, SSB_SPROM8_OPT_CORRX,
774e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_OPT_CORRX_TEMP_SLOPE,
775e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_OPT_CORRX_TEMP_SLOPE_SHIFT);
776e2da4bd3SHauke Mehrtens 	SPEX(tempcorrx, SSB_SPROM8_OPT_CORRX, SSB_SPROM8_OPT_CORRX_TEMPCORRX,
777e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_OPT_CORRX_TEMPCORRX_SHIFT);
778e2da4bd3SHauke Mehrtens 	SPEX(tempsense_option, SSB_SPROM8_OPT_CORRX,
779e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_OPT_CORRX_TEMP_OPTION,
780e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_OPT_CORRX_TEMP_OPTION_SHIFT);
781e2da4bd3SHauke Mehrtens 	SPEX(freqoffset_corr, SSB_SPROM8_HWIQ_IQSWP,
782e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR,
783e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR_SHIFT);
784e2da4bd3SHauke Mehrtens 	SPEX(iqcal_swp_dis, SSB_SPROM8_HWIQ_IQSWP,
785e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP,
786e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP_SHIFT);
787e2da4bd3SHauke Mehrtens 	SPEX(hw_iqcal_en, SSB_SPROM8_HWIQ_IQSWP, SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL,
788e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL_SHIFT);
789e2da4bd3SHauke Mehrtens 
790e2da4bd3SHauke Mehrtens 	SPEX(bw40po, SSB_SPROM8_BW40PO, ~0, 0);
791e2da4bd3SHauke Mehrtens 	SPEX(cddpo, SSB_SPROM8_CDDPO, ~0, 0);
792e2da4bd3SHauke Mehrtens 	SPEX(stbcpo, SSB_SPROM8_STBCPO, ~0, 0);
793e2da4bd3SHauke Mehrtens 	SPEX(bwduppo, SSB_SPROM8_BWDUPPO, ~0, 0);
794e2da4bd3SHauke Mehrtens 
795e2da4bd3SHauke Mehrtens 	SPEX(tempthresh, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_TRESH,
796e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_THERMAL_TRESH_SHIFT);
797e2da4bd3SHauke Mehrtens 	SPEX(tempoffset, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_OFFSET,
798e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_THERMAL_OFFSET_SHIFT);
799e2da4bd3SHauke Mehrtens 	SPEX(phycal_tempdelta, SSB_SPROM8_TEMPDELTA,
800e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_TEMPDELTA_PHYCAL,
801e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_TEMPDELTA_PHYCAL_SHIFT);
802e2da4bd3SHauke Mehrtens 	SPEX(temps_period, SSB_SPROM8_TEMPDELTA, SSB_SPROM8_TEMPDELTA_PERIOD,
803e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_TEMPDELTA_PERIOD_SHIFT);
804e2da4bd3SHauke Mehrtens 	SPEX(temps_hysteresis, SSB_SPROM8_TEMPDELTA,
805e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_TEMPDELTA_HYSTERESIS,
806e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_TEMPDELTA_HYSTERESIS_SHIFT);
807172c69a4SRafał Miłecki 	sprom_extract_r458(out, in);
808172c69a4SRafał Miłecki 
8096b1c7c67SMichael Buesch 	/* TODO - get remaining rev 8 stuff needed */
8106b1c7c67SMichael Buesch }
8116b1c7c67SMichael Buesch 
812c272ef44SLarry Finger static int sprom_extract(struct ssb_bus *bus, struct ssb_sprom *out,
813c272ef44SLarry Finger 			 const u16 *in, u16 size)
81461e115a5SMichael Buesch {
81561e115a5SMichael Buesch 	memset(out, 0, sizeof(*out));
81661e115a5SMichael Buesch 
817c272ef44SLarry Finger 	out->revision = in[size - 1] & 0x00FF;
818b8b6069cSMichael Büsch 	pr_debug("SPROM revision %d detected\n", out->revision);
81931ce12fbSLarry Finger 	memset(out->et0mac, 0xFF, 6);		/* preset et0 and et1 mac */
82031ce12fbSLarry Finger 	memset(out->et1mac, 0xFF, 6);
82154435f9eSRafał Miłecki 
82261e115a5SMichael Buesch 	if ((bus->chip_id & 0xFF00) == 0x4400) {
82361e115a5SMichael Buesch 		/* Workaround: The BCM44XX chip has a stupid revision
82461e115a5SMichael Buesch 		 * number stored in the SPROM.
82561e115a5SMichael Buesch 		 * Always extract r1. */
826c272ef44SLarry Finger 		out->revision = 1;
827b8b6069cSMichael Büsch 		pr_debug("SPROM treated as revision %d\n", out->revision);
82854435f9eSRafał Miłecki 	}
82954435f9eSRafał Miłecki 
8306b1c7c67SMichael Buesch 	switch (out->revision) {
8316b1c7c67SMichael Buesch 	case 1:
8326b1c7c67SMichael Buesch 	case 2:
8336b1c7c67SMichael Buesch 	case 3:
8346b1c7c67SMichael Buesch 		sprom_extract_r123(out, in);
8356b1c7c67SMichael Buesch 		break;
8366b1c7c67SMichael Buesch 	case 4:
8376b1c7c67SMichael Buesch 	case 5:
8386b1c7c67SMichael Buesch 		sprom_extract_r45(out, in);
8396b1c7c67SMichael Buesch 		break;
8406b1c7c67SMichael Buesch 	case 8:
8416b1c7c67SMichael Buesch 		sprom_extract_r8(out, in);
8426b1c7c67SMichael Buesch 		break;
8436b1c7c67SMichael Buesch 	default:
844b8b6069cSMichael Büsch 		pr_warn("Unsupported SPROM revision %d detected. Will extract v1\n",
84533a606acSJoe Perches 			out->revision);
846cd559b36SLarry Finger 		out->revision = 1;
847c272ef44SLarry Finger 		sprom_extract_r123(out, in);
848c272ef44SLarry Finger 	}
84961e115a5SMichael Buesch 
8504503183aSLarry Finger 	if (out->boardflags_lo == 0xFFFF)
8514503183aSLarry Finger 		out->boardflags_lo = 0;  /* per specs */
8524503183aSLarry Finger 	if (out->boardflags_hi == 0xFFFF)
8534503183aSLarry Finger 		out->boardflags_hi = 0;  /* per specs */
8544503183aSLarry Finger 
85561e115a5SMichael Buesch 	return 0;
85661e115a5SMichael Buesch }
85761e115a5SMichael Buesch 
85861e115a5SMichael Buesch static int ssb_pci_sprom_get(struct ssb_bus *bus,
85961e115a5SMichael Buesch 			     struct ssb_sprom *sprom)
86061e115a5SMichael Buesch {
861ca4a0831SRafał Miłecki 	int err;
86261e115a5SMichael Buesch 	u16 *buf;
86361e115a5SMichael Buesch 
864d53cdbb9SJohn W. Linville 	if (!ssb_is_sprom_available(bus)) {
865b8b6069cSMichael Büsch 		pr_err("No SPROM available!\n");
866d53cdbb9SJohn W. Linville 		return -ENODEV;
867d53cdbb9SJohn W. Linville 	}
86825985edcSLucas De Marchi 	if (bus->chipco.dev) {	/* can be unavailable! */
8699d1ac34eSLarry Finger 		/*
8709d1ac34eSLarry Finger 		 * get SPROM offset: SSB_SPROM_BASE1 except for
8719d1ac34eSLarry Finger 		 * chipcommon rev >= 31 or chip ID is 0x4312 and
8729d1ac34eSLarry Finger 		 * chipcommon status & 3 == 2
8739d1ac34eSLarry Finger 		 */
8749d1ac34eSLarry Finger 		if (bus->chipco.dev->id.revision >= 31)
8759d1ac34eSLarry Finger 			bus->sprom_offset = SSB_SPROM_BASE31;
8769d1ac34eSLarry Finger 		else if (bus->chip_id == 0x4312 &&
8779d1ac34eSLarry Finger 			 (bus->chipco.status & 0x03) == 2)
8789d1ac34eSLarry Finger 			bus->sprom_offset = SSB_SPROM_BASE31;
8799d1ac34eSLarry Finger 		else
8809d1ac34eSLarry Finger 			bus->sprom_offset = SSB_SPROM_BASE1;
881da1fdb02SChristoph Fritz 	} else {
882da1fdb02SChristoph Fritz 		bus->sprom_offset = SSB_SPROM_BASE1;
883da1fdb02SChristoph Fritz 	}
884b8b6069cSMichael Büsch 	pr_debug("SPROM offset is 0x%x\n", bus->sprom_offset);
885ea2db495SRafał Miłecki 
886c272ef44SLarry Finger 	buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL);
88761e115a5SMichael Buesch 	if (!buf)
888ca4a0831SRafał Miłecki 		return -ENOMEM;
889c272ef44SLarry Finger 	bus->sprom_size = SSB_SPROMSIZE_WORDS_R123;
89061e115a5SMichael Buesch 	sprom_do_read(bus, buf);
891c272ef44SLarry Finger 	err = sprom_check_crc(buf, bus->sprom_size);
89261e115a5SMichael Buesch 	if (err) {
8932afc4901SLarry.Finger@lwfinger.net 		/* try for a 440 byte SPROM - revision 4 and higher */
894c272ef44SLarry Finger 		kfree(buf);
895c272ef44SLarry Finger 		buf = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
896c272ef44SLarry Finger 			      GFP_KERNEL);
897c272ef44SLarry Finger 		if (!buf)
898ca4a0831SRafał Miłecki 			return -ENOMEM;
899c272ef44SLarry Finger 		bus->sprom_size = SSB_SPROMSIZE_WORDS_R4;
900c272ef44SLarry Finger 		sprom_do_read(bus, buf);
901c272ef44SLarry Finger 		err = sprom_check_crc(buf, bus->sprom_size);
902e79c1ba8SMichael Buesch 		if (err) {
903e79c1ba8SMichael Buesch 			/* All CRC attempts failed.
904e79c1ba8SMichael Buesch 			 * Maybe there is no SPROM on the device?
905b3ae52b6SHauke Mehrtens 			 * Now we ask the arch code if there is some sprom
906b3ae52b6SHauke Mehrtens 			 * available for this device in some other storage */
907b3ae52b6SHauke Mehrtens 			err = ssb_fill_sprom_with_fallback(bus, sprom);
908b3ae52b6SHauke Mehrtens 			if (err) {
909b8b6069cSMichael Büsch 				pr_warn("WARNING: Using fallback SPROM failed (err %d)\n",
910b3ae52b6SHauke Mehrtens 					err);
9118052d724SLarry Finger 				goto out_free;
912b3ae52b6SHauke Mehrtens 			} else {
913b8b6069cSMichael Büsch 				pr_debug("Using SPROM revision %d provided by platform\n",
91433a606acSJoe Perches 					 sprom->revision);
915e79c1ba8SMichael Buesch 				err = 0;
916e79c1ba8SMichael Buesch 				goto out_free;
917e79c1ba8SMichael Buesch 			}
918b8b6069cSMichael Büsch 			pr_warn("WARNING: Invalid SPROM CRC (corrupt SPROM)\n");
919c272ef44SLarry Finger 		}
920e79c1ba8SMichael Buesch 	}
921c272ef44SLarry Finger 	err = sprom_extract(bus, sprom, buf, bus->sprom_size);
92261e115a5SMichael Buesch 
923e79c1ba8SMichael Buesch out_free:
92461e115a5SMichael Buesch 	kfree(buf);
92561e115a5SMichael Buesch 	return err;
92661e115a5SMichael Buesch }
92761e115a5SMichael Buesch 
92861e115a5SMichael Buesch static void ssb_pci_get_boardinfo(struct ssb_bus *bus,
92961e115a5SMichael Buesch 				  struct ssb_boardinfo *bi)
93061e115a5SMichael Buesch {
931115f9450SSergei Shtylyov 	bi->vendor = bus->host_pci->subsystem_vendor;
932115f9450SSergei Shtylyov 	bi->type = bus->host_pci->subsystem_device;
93361e115a5SMichael Buesch }
93461e115a5SMichael Buesch 
93561e115a5SMichael Buesch int ssb_pci_get_invariants(struct ssb_bus *bus,
93661e115a5SMichael Buesch 			   struct ssb_init_invariants *iv)
93761e115a5SMichael Buesch {
93861e115a5SMichael Buesch 	int err;
93961e115a5SMichael Buesch 
94061e115a5SMichael Buesch 	err = ssb_pci_sprom_get(bus, &iv->sprom);
94161e115a5SMichael Buesch 	if (err)
94261e115a5SMichael Buesch 		goto out;
94361e115a5SMichael Buesch 	ssb_pci_get_boardinfo(bus, &iv->boardinfo);
94461e115a5SMichael Buesch 
94561e115a5SMichael Buesch out:
94661e115a5SMichael Buesch 	return err;
94761e115a5SMichael Buesch }
94861e115a5SMichael Buesch 
94961e115a5SMichael Buesch static int ssb_pci_assert_buspower(struct ssb_bus *bus)
95061e115a5SMichael Buesch {
95161e115a5SMichael Buesch 	if (likely(bus->powered_up))
95261e115a5SMichael Buesch 		return 0;
95361e115a5SMichael Buesch 
954b8b6069cSMichael Büsch 	pr_err("FATAL ERROR: Bus powered down while accessing PCI MMIO space\n");
95561e115a5SMichael Buesch 	if (bus->power_warn_count <= 10) {
95661e115a5SMichael Buesch 		bus->power_warn_count++;
95761e115a5SMichael Buesch 		dump_stack();
95861e115a5SMichael Buesch 	}
95961e115a5SMichael Buesch 
96061e115a5SMichael Buesch 	return -ENODEV;
96161e115a5SMichael Buesch }
96261e115a5SMichael Buesch 
963ffc7689dSMichael Buesch static u8 ssb_pci_read8(struct ssb_device *dev, u16 offset)
964ffc7689dSMichael Buesch {
965ffc7689dSMichael Buesch 	struct ssb_bus *bus = dev->bus;
966ffc7689dSMichael Buesch 
967ffc7689dSMichael Buesch 	if (unlikely(ssb_pci_assert_buspower(bus)))
968ffc7689dSMichael Buesch 		return 0xFF;
969ffc7689dSMichael Buesch 	if (unlikely(bus->mapped_device != dev)) {
970ffc7689dSMichael Buesch 		if (unlikely(ssb_pci_switch_core(bus, dev)))
971ffc7689dSMichael Buesch 			return 0xFF;
972ffc7689dSMichael Buesch 	}
973ffc7689dSMichael Buesch 	return ioread8(bus->mmio + offset);
974ffc7689dSMichael Buesch }
975ffc7689dSMichael Buesch 
97661e115a5SMichael Buesch static u16 ssb_pci_read16(struct ssb_device *dev, u16 offset)
97761e115a5SMichael Buesch {
97861e115a5SMichael Buesch 	struct ssb_bus *bus = dev->bus;
97961e115a5SMichael Buesch 
98061e115a5SMichael Buesch 	if (unlikely(ssb_pci_assert_buspower(bus)))
98161e115a5SMichael Buesch 		return 0xFFFF;
98261e115a5SMichael Buesch 	if (unlikely(bus->mapped_device != dev)) {
98361e115a5SMichael Buesch 		if (unlikely(ssb_pci_switch_core(bus, dev)))
98461e115a5SMichael Buesch 			return 0xFFFF;
98561e115a5SMichael Buesch 	}
9864b402c65SMichael Buesch 	return ioread16(bus->mmio + offset);
98761e115a5SMichael Buesch }
98861e115a5SMichael Buesch 
98961e115a5SMichael Buesch static u32 ssb_pci_read32(struct ssb_device *dev, u16 offset)
99061e115a5SMichael Buesch {
99161e115a5SMichael Buesch 	struct ssb_bus *bus = dev->bus;
99261e115a5SMichael Buesch 
99361e115a5SMichael Buesch 	if (unlikely(ssb_pci_assert_buspower(bus)))
99461e115a5SMichael Buesch 		return 0xFFFFFFFF;
99561e115a5SMichael Buesch 	if (unlikely(bus->mapped_device != dev)) {
99661e115a5SMichael Buesch 		if (unlikely(ssb_pci_switch_core(bus, dev)))
99761e115a5SMichael Buesch 			return 0xFFFFFFFF;
99861e115a5SMichael Buesch 	}
9994b402c65SMichael Buesch 	return ioread32(bus->mmio + offset);
100061e115a5SMichael Buesch }
100161e115a5SMichael Buesch 
1002d625a29bSMichael Buesch #ifdef CONFIG_SSB_BLOCKIO
1003d625a29bSMichael Buesch static void ssb_pci_block_read(struct ssb_device *dev, 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 		goto error;
1011d625a29bSMichael Buesch 	if (unlikely(bus->mapped_device != dev)) {
1012d625a29bSMichael Buesch 		if (unlikely(ssb_pci_switch_core(bus, dev)))
1013d625a29bSMichael Buesch 			goto error;
1014d625a29bSMichael Buesch 	}
1015d625a29bSMichael Buesch 	switch (reg_width) {
1016d625a29bSMichael Buesch 	case sizeof(u8):
1017d625a29bSMichael Buesch 		ioread8_rep(addr, buffer, count);
1018d625a29bSMichael Buesch 		break;
1019d625a29bSMichael Buesch 	case sizeof(u16):
1020*209b4375SMichael Büsch 		WARN_ON(count & 1);
1021d625a29bSMichael Buesch 		ioread16_rep(addr, buffer, count >> 1);
1022d625a29bSMichael Buesch 		break;
1023d625a29bSMichael Buesch 	case sizeof(u32):
1024*209b4375SMichael Büsch 		WARN_ON(count & 3);
1025d625a29bSMichael Buesch 		ioread32_rep(addr, buffer, count >> 2);
1026d625a29bSMichael Buesch 		break;
1027d625a29bSMichael Buesch 	default:
1028*209b4375SMichael Büsch 		WARN_ON(1);
1029d625a29bSMichael Buesch 	}
1030d625a29bSMichael Buesch 
1031d625a29bSMichael Buesch 	return;
1032d625a29bSMichael Buesch error:
1033d625a29bSMichael Buesch 	memset(buffer, 0xFF, count);
1034d625a29bSMichael Buesch }
1035d625a29bSMichael Buesch #endif /* CONFIG_SSB_BLOCKIO */
1036d625a29bSMichael Buesch 
1037ffc7689dSMichael Buesch static void ssb_pci_write8(struct ssb_device *dev, u16 offset, u8 value)
1038ffc7689dSMichael Buesch {
1039ffc7689dSMichael Buesch 	struct ssb_bus *bus = dev->bus;
1040ffc7689dSMichael Buesch 
1041ffc7689dSMichael Buesch 	if (unlikely(ssb_pci_assert_buspower(bus)))
1042ffc7689dSMichael Buesch 		return;
1043ffc7689dSMichael Buesch 	if (unlikely(bus->mapped_device != dev)) {
1044ffc7689dSMichael Buesch 		if (unlikely(ssb_pci_switch_core(bus, dev)))
1045ffc7689dSMichael Buesch 			return;
1046ffc7689dSMichael Buesch 	}
1047ffc7689dSMichael Buesch 	iowrite8(value, bus->mmio + offset);
1048ffc7689dSMichael Buesch }
1049ffc7689dSMichael Buesch 
105061e115a5SMichael Buesch static void ssb_pci_write16(struct ssb_device *dev, u16 offset, u16 value)
105161e115a5SMichael Buesch {
105261e115a5SMichael Buesch 	struct ssb_bus *bus = dev->bus;
105361e115a5SMichael Buesch 
105461e115a5SMichael Buesch 	if (unlikely(ssb_pci_assert_buspower(bus)))
105561e115a5SMichael Buesch 		return;
105661e115a5SMichael Buesch 	if (unlikely(bus->mapped_device != dev)) {
105761e115a5SMichael Buesch 		if (unlikely(ssb_pci_switch_core(bus, dev)))
105861e115a5SMichael Buesch 			return;
105961e115a5SMichael Buesch 	}
10604b402c65SMichael Buesch 	iowrite16(value, bus->mmio + offset);
106161e115a5SMichael Buesch }
106261e115a5SMichael Buesch 
106361e115a5SMichael Buesch static void ssb_pci_write32(struct ssb_device *dev, u16 offset, u32 value)
106461e115a5SMichael Buesch {
106561e115a5SMichael Buesch 	struct ssb_bus *bus = dev->bus;
106661e115a5SMichael Buesch 
106761e115a5SMichael Buesch 	if (unlikely(ssb_pci_assert_buspower(bus)))
106861e115a5SMichael Buesch 		return;
106961e115a5SMichael Buesch 	if (unlikely(bus->mapped_device != dev)) {
107061e115a5SMichael Buesch 		if (unlikely(ssb_pci_switch_core(bus, dev)))
107161e115a5SMichael Buesch 			return;
107261e115a5SMichael Buesch 	}
10734b402c65SMichael Buesch 	iowrite32(value, bus->mmio + offset);
107461e115a5SMichael Buesch }
107561e115a5SMichael Buesch 
1076d625a29bSMichael Buesch #ifdef CONFIG_SSB_BLOCKIO
1077d625a29bSMichael Buesch static void ssb_pci_block_write(struct ssb_device *dev, const void *buffer,
1078d625a29bSMichael Buesch 				size_t count, u16 offset, u8 reg_width)
1079d625a29bSMichael Buesch {
1080d625a29bSMichael Buesch 	struct ssb_bus *bus = dev->bus;
1081d625a29bSMichael Buesch 	void __iomem *addr = bus->mmio + offset;
1082d625a29bSMichael Buesch 
1083d625a29bSMichael Buesch 	if (unlikely(ssb_pci_assert_buspower(bus)))
1084d625a29bSMichael Buesch 		return;
1085d625a29bSMichael Buesch 	if (unlikely(bus->mapped_device != dev)) {
1086d625a29bSMichael Buesch 		if (unlikely(ssb_pci_switch_core(bus, dev)))
1087d625a29bSMichael Buesch 			return;
1088d625a29bSMichael Buesch 	}
1089d625a29bSMichael Buesch 	switch (reg_width) {
1090d625a29bSMichael Buesch 	case sizeof(u8):
1091d625a29bSMichael Buesch 		iowrite8_rep(addr, buffer, count);
1092d625a29bSMichael Buesch 		break;
1093d625a29bSMichael Buesch 	case sizeof(u16):
1094*209b4375SMichael Büsch 		WARN_ON(count & 1);
1095d625a29bSMichael Buesch 		iowrite16_rep(addr, buffer, count >> 1);
1096d625a29bSMichael Buesch 		break;
1097d625a29bSMichael Buesch 	case sizeof(u32):
1098*209b4375SMichael Büsch 		WARN_ON(count & 3);
1099d625a29bSMichael Buesch 		iowrite32_rep(addr, buffer, count >> 2);
1100d625a29bSMichael Buesch 		break;
1101d625a29bSMichael Buesch 	default:
1102*209b4375SMichael Büsch 		WARN_ON(1);
1103d625a29bSMichael Buesch 	}
1104d625a29bSMichael Buesch }
1105d625a29bSMichael Buesch #endif /* CONFIG_SSB_BLOCKIO */
1106d625a29bSMichael Buesch 
110761e115a5SMichael Buesch /* Not "static", as it's used in main.c */
110861e115a5SMichael Buesch const struct ssb_bus_ops ssb_pci_ops = {
1109ffc7689dSMichael Buesch 	.read8		= ssb_pci_read8,
111061e115a5SMichael Buesch 	.read16		= ssb_pci_read16,
111161e115a5SMichael Buesch 	.read32		= ssb_pci_read32,
1112ffc7689dSMichael Buesch 	.write8		= ssb_pci_write8,
111361e115a5SMichael Buesch 	.write16	= ssb_pci_write16,
111461e115a5SMichael Buesch 	.write32	= ssb_pci_write32,
1115d625a29bSMichael Buesch #ifdef CONFIG_SSB_BLOCKIO
1116d625a29bSMichael Buesch 	.block_read	= ssb_pci_block_read,
1117d625a29bSMichael Buesch 	.block_write	= ssb_pci_block_write,
1118d625a29bSMichael Buesch #endif
111961e115a5SMichael Buesch };
112061e115a5SMichael Buesch 
112161e115a5SMichael Buesch static ssize_t ssb_pci_attr_sprom_show(struct device *pcidev,
112261e115a5SMichael Buesch 				       struct device_attribute *attr,
112361e115a5SMichael Buesch 				       char *buf)
112461e115a5SMichael Buesch {
112561e115a5SMichael Buesch 	struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev);
112661e115a5SMichael Buesch 	struct ssb_bus *bus;
112761e115a5SMichael Buesch 
112861e115a5SMichael Buesch 	bus = ssb_pci_dev_to_bus(pdev);
112961e115a5SMichael Buesch 	if (!bus)
1130e7ec2e32SMichael Buesch 		return -ENODEV;
113161e115a5SMichael Buesch 
1132e7ec2e32SMichael Buesch 	return ssb_attr_sprom_show(bus, buf, sprom_do_read);
113361e115a5SMichael Buesch }
113461e115a5SMichael Buesch 
113561e115a5SMichael Buesch static ssize_t ssb_pci_attr_sprom_store(struct device *pcidev,
113661e115a5SMichael Buesch 					struct device_attribute *attr,
113761e115a5SMichael Buesch 					const char *buf, size_t count)
113861e115a5SMichael Buesch {
113961e115a5SMichael Buesch 	struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev);
114061e115a5SMichael Buesch 	struct ssb_bus *bus;
114161e115a5SMichael Buesch 
114261e115a5SMichael Buesch 	bus = ssb_pci_dev_to_bus(pdev);
114361e115a5SMichael Buesch 	if (!bus)
1144e7ec2e32SMichael Buesch 		return -ENODEV;
114561e115a5SMichael Buesch 
1146e7ec2e32SMichael Buesch 	return ssb_attr_sprom_store(bus, buf, count,
1147e7ec2e32SMichael Buesch 				    sprom_check_crc, sprom_do_write);
114861e115a5SMichael Buesch }
114961e115a5SMichael Buesch 
115061e115a5SMichael Buesch static DEVICE_ATTR(ssb_sprom, 0600,
115161e115a5SMichael Buesch 		   ssb_pci_attr_sprom_show,
115261e115a5SMichael Buesch 		   ssb_pci_attr_sprom_store);
115361e115a5SMichael Buesch 
115461e115a5SMichael Buesch void ssb_pci_exit(struct ssb_bus *bus)
115561e115a5SMichael Buesch {
115661e115a5SMichael Buesch 	struct pci_dev *pdev;
115761e115a5SMichael Buesch 
115861e115a5SMichael Buesch 	if (bus->bustype != SSB_BUSTYPE_PCI)
115961e115a5SMichael Buesch 		return;
116061e115a5SMichael Buesch 
116161e115a5SMichael Buesch 	pdev = bus->host_pci;
116261e115a5SMichael Buesch 	device_remove_file(&pdev->dev, &dev_attr_ssb_sprom);
116361e115a5SMichael Buesch }
116461e115a5SMichael Buesch 
116561e115a5SMichael Buesch int ssb_pci_init(struct ssb_bus *bus)
116661e115a5SMichael Buesch {
116761e115a5SMichael Buesch 	struct pci_dev *pdev;
116861e115a5SMichael Buesch 	int err;
116961e115a5SMichael Buesch 
117061e115a5SMichael Buesch 	if (bus->bustype != SSB_BUSTYPE_PCI)
117161e115a5SMichael Buesch 		return 0;
117261e115a5SMichael Buesch 
117361e115a5SMichael Buesch 	pdev = bus->host_pci;
1174e7ec2e32SMichael Buesch 	mutex_init(&bus->sprom_mutex);
117561e115a5SMichael Buesch 	err = device_create_file(&pdev->dev, &dev_attr_ssb_sprom);
117661e115a5SMichael Buesch 	if (err)
117761e115a5SMichael Buesch 		goto out;
117861e115a5SMichael Buesch 
117961e115a5SMichael Buesch out:
118061e115a5SMichael Buesch 	return err;
118161e115a5SMichael Buesch }
1182