xref: /openbmc/linux/drivers/ssb/pci.c (revision 8052d7245b6089992343c80b38b14dbbd8354651)
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:
5933a606acSJoe 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
7033a606acSJoe 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] >> 8;
238a9fac739SLarry Finger 		*mac++ = in[i];
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 
28933a606acSJoe 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;
29733a606acSJoe Perches 	ssb_notice("[ 0%%");
29861e115a5SMichael Buesch 	msleep(500);
299c272ef44SLarry Finger 	for (i = 0; i < size; i++) {
300c272ef44SLarry Finger 		if (i == size / 4)
30133a606acSJoe Perches 			ssb_cont("25%%");
302c272ef44SLarry Finger 		else if (i == size / 2)
30333a606acSJoe Perches 			ssb_cont("50%%");
304c272ef44SLarry Finger 		else if (i == (size * 3) / 4)
30533a606acSJoe Perches 			ssb_cont("75%%");
30661e115a5SMichael Buesch 		else if (i % 2)
30733a606acSJoe 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);
32033a606acSJoe Perches 	ssb_cont("100%% ]\n");
32133a606acSJoe Perches 	ssb_notice("SPROM written\n");
32261e115a5SMichael Buesch 
32361e115a5SMichael Buesch 	return 0;
32461e115a5SMichael Buesch err_ctlreg:
32533a606acSJoe Perches 	ssb_err("Could not access SPROM control register.\n");
32661e115a5SMichael Buesch 	return err;
32761e115a5SMichael Buesch }
32861e115a5SMichael Buesch 
32967d392c0SRafał Miłecki static s8 sprom_extract_antgain(u8 sprom_revision, const u16 *in, u16 offset,
330e861b98dSMichael Buesch 				u16 mask, u16 shift)
331e861b98dSMichael Buesch {
332e861b98dSMichael Buesch 	u16 v;
333e861b98dSMichael Buesch 	u8 gain;
334e861b98dSMichael Buesch 
33567d392c0SRafał Miłecki 	v = in[SPOFF(offset)];
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 
3507e4235acSHauke Mehrtens static void sprom_extract_r23(struct ssb_sprom *out, const u16 *in)
3517e4235acSHauke Mehrtens {
3527e4235acSHauke Mehrtens 	SPEX(boardflags_hi, SSB_SPROM2_BFLHI, 0xFFFF, 0);
3537e4235acSHauke Mehrtens 	SPEX(opo, SSB_SPROM2_OPO, SSB_SPROM2_OPO_VALUE, 0);
3547e4235acSHauke Mehrtens 	SPEX(pa1lob0, SSB_SPROM2_PA1LOB0, 0xFFFF, 0);
3557e4235acSHauke Mehrtens 	SPEX(pa1lob1, SSB_SPROM2_PA1LOB1, 0xFFFF, 0);
3567e4235acSHauke Mehrtens 	SPEX(pa1lob2, SSB_SPROM2_PA1LOB2, 0xFFFF, 0);
3577e4235acSHauke Mehrtens 	SPEX(pa1hib0, SSB_SPROM2_PA1HIB0, 0xFFFF, 0);
3587e4235acSHauke Mehrtens 	SPEX(pa1hib1, SSB_SPROM2_PA1HIB1, 0xFFFF, 0);
3597e4235acSHauke Mehrtens 	SPEX(pa1hib2, SSB_SPROM2_PA1HIB2, 0xFFFF, 0);
3607e4235acSHauke Mehrtens 	SPEX(maxpwr_ah, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_HI, 0);
3617e4235acSHauke Mehrtens 	SPEX(maxpwr_al, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_LO,
3627e4235acSHauke Mehrtens 	     SSB_SPROM2_MAXP_A_LO_SHIFT);
3637e4235acSHauke Mehrtens }
3647e4235acSHauke Mehrtens 
365c272ef44SLarry Finger static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in)
366c272ef44SLarry Finger {
367c272ef44SLarry Finger 	u16 loc[3];
368c272ef44SLarry Finger 
36931ce12fbSLarry Finger 	if (out->revision == 3)			/* rev 3 moved MAC */
370c272ef44SLarry Finger 		loc[0] = SSB_SPROM3_IL0MAC;
37131ce12fbSLarry Finger 	else {
372c272ef44SLarry Finger 		loc[0] = SSB_SPROM1_IL0MAC;
373c272ef44SLarry Finger 		loc[1] = SSB_SPROM1_ET0MAC;
374c272ef44SLarry Finger 		loc[2] = SSB_SPROM1_ET1MAC;
375c272ef44SLarry Finger 	}
376e5652756SJoe Perches 	sprom_get_mac(out->il0mac, &in[SPOFF(loc[0])]);
37731ce12fbSLarry Finger 	if (out->revision < 3) { 	/* only rev 1-2 have et0, et1 */
378e5652756SJoe Perches 		sprom_get_mac(out->et0mac, &in[SPOFF(loc[1])]);
379e5652756SJoe Perches 		sprom_get_mac(out->et1mac, &in[SPOFF(loc[2])]);
38031ce12fbSLarry Finger 	}
381c272ef44SLarry Finger 	SPEX(et0phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0A, 0);
382c272ef44SLarry Finger 	SPEX(et1phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1A,
383c272ef44SLarry Finger 	     SSB_SPROM1_ETHPHY_ET1A_SHIFT);
384e861b98dSMichael Buesch 	SPEX(et0mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0M, 14);
385e861b98dSMichael Buesch 	SPEX(et1mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1M, 15);
386e861b98dSMichael Buesch 	SPEX(board_rev, SSB_SPROM1_BINF, SSB_SPROM1_BINF_BREV, 0);
3873623b266SRafał Miłecki 	SPEX(board_type, SSB_SPROM1_SPID, 0xFFFF, 0);
388bf7d420bSHauke Mehrtens 	if (out->revision == 1)
389c272ef44SLarry Finger 		SPEX(country_code, SSB_SPROM1_BINF, SSB_SPROM1_BINF_CCODE,
390c272ef44SLarry Finger 		     SSB_SPROM1_BINF_CCODE_SHIFT);
391e861b98dSMichael Buesch 	SPEX(ant_available_a, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTA,
392e861b98dSMichael Buesch 	     SSB_SPROM1_BINF_ANTA_SHIFT);
393e861b98dSMichael Buesch 	SPEX(ant_available_bg, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTBG,
394e861b98dSMichael Buesch 	     SSB_SPROM1_BINF_ANTBG_SHIFT);
395c272ef44SLarry Finger 	SPEX(pa0b0, SSB_SPROM1_PA0B0, 0xFFFF, 0);
396c272ef44SLarry Finger 	SPEX(pa0b1, SSB_SPROM1_PA0B1, 0xFFFF, 0);
397c272ef44SLarry Finger 	SPEX(pa0b2, SSB_SPROM1_PA0B2, 0xFFFF, 0);
398c272ef44SLarry Finger 	SPEX(pa1b0, SSB_SPROM1_PA1B0, 0xFFFF, 0);
399c272ef44SLarry Finger 	SPEX(pa1b1, SSB_SPROM1_PA1B1, 0xFFFF, 0);
400c272ef44SLarry Finger 	SPEX(pa1b2, SSB_SPROM1_PA1B2, 0xFFFF, 0);
401c272ef44SLarry Finger 	SPEX(gpio0, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P0, 0);
402c272ef44SLarry Finger 	SPEX(gpio1, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P1,
403c272ef44SLarry Finger 	     SSB_SPROM1_GPIOA_P1_SHIFT);
404c272ef44SLarry Finger 	SPEX(gpio2, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P2, 0);
405c272ef44SLarry Finger 	SPEX(gpio3, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P3,
406c272ef44SLarry Finger 	     SSB_SPROM1_GPIOB_P3_SHIFT);
407c272ef44SLarry Finger 	SPEX(maxpwr_a, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_A,
408c272ef44SLarry Finger 	     SSB_SPROM1_MAXPWR_A_SHIFT);
409c272ef44SLarry Finger 	SPEX(maxpwr_bg, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_BG, 0);
410c272ef44SLarry Finger 	SPEX(itssi_a, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_A,
411c272ef44SLarry Finger 	     SSB_SPROM1_ITSSI_A_SHIFT);
412c272ef44SLarry Finger 	SPEX(itssi_bg, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_BG, 0);
413c272ef44SLarry Finger 	SPEX(boardflags_lo, SSB_SPROM1_BFLLO, 0xFFFF, 0);
4147e4235acSHauke Mehrtens 
415bf7d420bSHauke Mehrtens 	SPEX(alpha2[0], SSB_SPROM1_CCODE, 0xff00, 8);
416bf7d420bSHauke Mehrtens 	SPEX(alpha2[1], SSB_SPROM1_CCODE, 0x00ff, 0);
417e861b98dSMichael Buesch 
418e861b98dSMichael Buesch 	/* Extract the antenna gain values. */
41967d392c0SRafał Miłecki 	out->antenna_gain.a0 = sprom_extract_antgain(out->revision, in,
42067d392c0SRafał Miłecki 						     SSB_SPROM1_AGAIN,
421e861b98dSMichael Buesch 						     SSB_SPROM1_AGAIN_BG,
422c272ef44SLarry Finger 						     SSB_SPROM1_AGAIN_BG_SHIFT);
42367d392c0SRafał Miłecki 	out->antenna_gain.a1 = sprom_extract_antgain(out->revision, in,
42467d392c0SRafał Miłecki 						     SSB_SPROM1_AGAIN,
425e861b98dSMichael Buesch 						     SSB_SPROM1_AGAIN_A,
426e861b98dSMichael Buesch 						     SSB_SPROM1_AGAIN_A_SHIFT);
4277e4235acSHauke Mehrtens 	if (out->revision >= 2)
4287e4235acSHauke Mehrtens 		sprom_extract_r23(out, in);
429c272ef44SLarry Finger }
430c272ef44SLarry Finger 
431172c69a4SRafał Miłecki /* Revs 4 5 and 8 have partially shared layout */
432172c69a4SRafał Miłecki static void sprom_extract_r458(struct ssb_sprom *out, const u16 *in)
433172c69a4SRafał Miłecki {
434172c69a4SRafał Miłecki 	SPEX(txpid2g[0], SSB_SPROM4_TXPID2G01,
435172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID2G0, SSB_SPROM4_TXPID2G0_SHIFT);
436172c69a4SRafał Miłecki 	SPEX(txpid2g[1], SSB_SPROM4_TXPID2G01,
437172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID2G1, SSB_SPROM4_TXPID2G1_SHIFT);
438172c69a4SRafał Miłecki 	SPEX(txpid2g[2], SSB_SPROM4_TXPID2G23,
439172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID2G2, SSB_SPROM4_TXPID2G2_SHIFT);
440172c69a4SRafał Miłecki 	SPEX(txpid2g[3], SSB_SPROM4_TXPID2G23,
441172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID2G3, SSB_SPROM4_TXPID2G3_SHIFT);
442172c69a4SRafał Miłecki 
443172c69a4SRafał Miłecki 	SPEX(txpid5gl[0], SSB_SPROM4_TXPID5GL01,
444172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID5GL0, SSB_SPROM4_TXPID5GL0_SHIFT);
445172c69a4SRafał Miłecki 	SPEX(txpid5gl[1], SSB_SPROM4_TXPID5GL01,
446172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID5GL1, SSB_SPROM4_TXPID5GL1_SHIFT);
447172c69a4SRafał Miłecki 	SPEX(txpid5gl[2], SSB_SPROM4_TXPID5GL23,
448172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID5GL2, SSB_SPROM4_TXPID5GL2_SHIFT);
449172c69a4SRafał Miłecki 	SPEX(txpid5gl[3], SSB_SPROM4_TXPID5GL23,
450172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID5GL3, SSB_SPROM4_TXPID5GL3_SHIFT);
451172c69a4SRafał Miłecki 
452172c69a4SRafał Miłecki 	SPEX(txpid5g[0], SSB_SPROM4_TXPID5G01,
453172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID5G0, SSB_SPROM4_TXPID5G0_SHIFT);
454172c69a4SRafał Miłecki 	SPEX(txpid5g[1], SSB_SPROM4_TXPID5G01,
455172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID5G1, SSB_SPROM4_TXPID5G1_SHIFT);
456172c69a4SRafał Miłecki 	SPEX(txpid5g[2], SSB_SPROM4_TXPID5G23,
457172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID5G2, SSB_SPROM4_TXPID5G2_SHIFT);
458172c69a4SRafał Miłecki 	SPEX(txpid5g[3], SSB_SPROM4_TXPID5G23,
459172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID5G3, SSB_SPROM4_TXPID5G3_SHIFT);
460172c69a4SRafał Miłecki 
461172c69a4SRafał Miłecki 	SPEX(txpid5gh[0], SSB_SPROM4_TXPID5GH01,
462172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID5GH0, SSB_SPROM4_TXPID5GH0_SHIFT);
463172c69a4SRafał Miłecki 	SPEX(txpid5gh[1], SSB_SPROM4_TXPID5GH01,
464172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID5GH1, SSB_SPROM4_TXPID5GH1_SHIFT);
465172c69a4SRafał Miłecki 	SPEX(txpid5gh[2], SSB_SPROM4_TXPID5GH23,
466172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID5GH2, SSB_SPROM4_TXPID5GH2_SHIFT);
467172c69a4SRafał Miłecki 	SPEX(txpid5gh[3], SSB_SPROM4_TXPID5GH23,
468172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID5GH3, SSB_SPROM4_TXPID5GH3_SHIFT);
469172c69a4SRafał Miłecki }
470172c69a4SRafał Miłecki 
471095f695cSLarry Finger static void sprom_extract_r45(struct ssb_sprom *out, const u16 *in)
47261e115a5SMichael Buesch {
4736ad59343SRafał Miłecki 	static const u16 pwr_info_offset[] = {
4746ad59343SRafał Miłecki 		SSB_SPROM4_PWR_INFO_CORE0, SSB_SPROM4_PWR_INFO_CORE1,
4756ad59343SRafał Miłecki 		SSB_SPROM4_PWR_INFO_CORE2, SSB_SPROM4_PWR_INFO_CORE3
4766ad59343SRafał Miłecki 	};
477095f695cSLarry Finger 	u16 il0mac_offset;
4786ad59343SRafał Miłecki 	int i;
4796ad59343SRafał Miłecki 
4806ad59343SRafał Miłecki 	BUILD_BUG_ON(ARRAY_SIZE(pwr_info_offset) !=
4816ad59343SRafał Miłecki 		     ARRAY_SIZE(out->core_pwr_info));
48261e115a5SMichael Buesch 
483095f695cSLarry Finger 	if (out->revision == 4)
484095f695cSLarry Finger 		il0mac_offset = SSB_SPROM4_IL0MAC;
485095f695cSLarry Finger 	else
486095f695cSLarry Finger 		il0mac_offset = SSB_SPROM5_IL0MAC;
487e5652756SJoe Perches 
488e5652756SJoe Perches 	sprom_get_mac(out->il0mac, &in[SPOFF(il0mac_offset)]);
489e5652756SJoe Perches 
490c272ef44SLarry Finger 	SPEX(et0phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET0A, 0);
491c272ef44SLarry Finger 	SPEX(et1phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET1A,
492c272ef44SLarry Finger 	     SSB_SPROM4_ETHPHY_ET1A_SHIFT);
493673335c8SHauke Mehrtens 	SPEX(board_rev, SSB_SPROM4_BOARDREV, 0xFFFF, 0);
4943623b266SRafał Miłecki 	SPEX(board_type, SSB_SPROM1_SPID, 0xFFFF, 0);
495095f695cSLarry Finger 	if (out->revision == 4) {
496bf7d420bSHauke Mehrtens 		SPEX(alpha2[0], SSB_SPROM4_CCODE, 0xff00, 8);
497bf7d420bSHauke Mehrtens 		SPEX(alpha2[1], SSB_SPROM4_CCODE, 0x00ff, 0);
498c272ef44SLarry Finger 		SPEX(boardflags_lo, SSB_SPROM4_BFLLO, 0xFFFF, 0);
499af4b7450SMichael Buesch 		SPEX(boardflags_hi, SSB_SPROM4_BFLHI, 0xFFFF, 0);
5006d1d4ea4SRafał Miłecki 		SPEX(boardflags2_lo, SSB_SPROM4_BFL2LO, 0xFFFF, 0);
5016d1d4ea4SRafał Miłecki 		SPEX(boardflags2_hi, SSB_SPROM4_BFL2HI, 0xFFFF, 0);
502095f695cSLarry Finger 	} else {
503bf7d420bSHauke Mehrtens 		SPEX(alpha2[0], SSB_SPROM5_CCODE, 0xff00, 8);
504bf7d420bSHauke Mehrtens 		SPEX(alpha2[1], SSB_SPROM5_CCODE, 0x00ff, 0);
505095f695cSLarry Finger 		SPEX(boardflags_lo, SSB_SPROM5_BFLLO, 0xFFFF, 0);
506095f695cSLarry Finger 		SPEX(boardflags_hi, SSB_SPROM5_BFLHI, 0xFFFF, 0);
5076d1d4ea4SRafał Miłecki 		SPEX(boardflags2_lo, SSB_SPROM5_BFL2LO, 0xFFFF, 0);
5086d1d4ea4SRafał Miłecki 		SPEX(boardflags2_hi, SSB_SPROM5_BFL2HI, 0xFFFF, 0);
509095f695cSLarry Finger 	}
510e861b98dSMichael Buesch 	SPEX(ant_available_a, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_A,
511e861b98dSMichael Buesch 	     SSB_SPROM4_ANTAVAIL_A_SHIFT);
512e861b98dSMichael Buesch 	SPEX(ant_available_bg, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_BG,
513e861b98dSMichael Buesch 	     SSB_SPROM4_ANTAVAIL_BG_SHIFT);
514d3c319f9SLarry Finger 	SPEX(maxpwr_bg, SSB_SPROM4_MAXP_BG, SSB_SPROM4_MAXP_BG_MASK, 0);
515d3c319f9SLarry Finger 	SPEX(itssi_bg, SSB_SPROM4_MAXP_BG, SSB_SPROM4_ITSSI_BG,
516d3c319f9SLarry Finger 	     SSB_SPROM4_ITSSI_BG_SHIFT);
517d3c319f9SLarry Finger 	SPEX(maxpwr_a, SSB_SPROM4_MAXP_A, SSB_SPROM4_MAXP_A_MASK, 0);
518d3c319f9SLarry Finger 	SPEX(itssi_a, SSB_SPROM4_MAXP_A, SSB_SPROM4_ITSSI_A,
519d3c319f9SLarry Finger 	     SSB_SPROM4_ITSSI_A_SHIFT);
520095f695cSLarry Finger 	if (out->revision == 4) {
521d3c319f9SLarry Finger 		SPEX(gpio0, SSB_SPROM4_GPIOA, SSB_SPROM4_GPIOA_P0, 0);
522d3c319f9SLarry Finger 		SPEX(gpio1, SSB_SPROM4_GPIOA, SSB_SPROM4_GPIOA_P1,
523d3c319f9SLarry Finger 		     SSB_SPROM4_GPIOA_P1_SHIFT);
524d3c319f9SLarry Finger 		SPEX(gpio2, SSB_SPROM4_GPIOB, SSB_SPROM4_GPIOB_P2, 0);
525d3c319f9SLarry Finger 		SPEX(gpio3, SSB_SPROM4_GPIOB, SSB_SPROM4_GPIOB_P3,
526d3c319f9SLarry Finger 		     SSB_SPROM4_GPIOB_P3_SHIFT);
527095f695cSLarry Finger 	} else {
528095f695cSLarry Finger 		SPEX(gpio0, SSB_SPROM5_GPIOA, SSB_SPROM5_GPIOA_P0, 0);
529095f695cSLarry Finger 		SPEX(gpio1, SSB_SPROM5_GPIOA, SSB_SPROM5_GPIOA_P1,
530095f695cSLarry Finger 		     SSB_SPROM5_GPIOA_P1_SHIFT);
531095f695cSLarry Finger 		SPEX(gpio2, SSB_SPROM5_GPIOB, SSB_SPROM5_GPIOB_P2, 0);
532095f695cSLarry Finger 		SPEX(gpio3, SSB_SPROM5_GPIOB, SSB_SPROM5_GPIOB_P3,
533095f695cSLarry Finger 		     SSB_SPROM5_GPIOB_P3_SHIFT);
534095f695cSLarry Finger 	}
535e861b98dSMichael Buesch 
536e861b98dSMichael Buesch 	/* Extract the antenna gain values. */
5376daf4321SRafał Miłecki 	out->antenna_gain.a0 = sprom_extract_antgain(out->revision, in,
5386daf4321SRafał Miłecki 						     SSB_SPROM4_AGAIN01,
5396daf4321SRafał Miłecki 						     SSB_SPROM4_AGAIN0,
5406daf4321SRafał Miłecki 						     SSB_SPROM4_AGAIN0_SHIFT);
5416daf4321SRafał Miłecki 	out->antenna_gain.a1 = sprom_extract_antgain(out->revision, in,
5426daf4321SRafał Miłecki 						     SSB_SPROM4_AGAIN01,
5436daf4321SRafał Miłecki 						     SSB_SPROM4_AGAIN1,
5446daf4321SRafał Miłecki 						     SSB_SPROM4_AGAIN1_SHIFT);
5456daf4321SRafał Miłecki 	out->antenna_gain.a2 = sprom_extract_antgain(out->revision, in,
5466daf4321SRafał Miłecki 						     SSB_SPROM4_AGAIN23,
5476daf4321SRafał Miłecki 						     SSB_SPROM4_AGAIN2,
5486daf4321SRafał Miłecki 						     SSB_SPROM4_AGAIN2_SHIFT);
5496daf4321SRafał Miłecki 	out->antenna_gain.a3 = sprom_extract_antgain(out->revision, in,
5506daf4321SRafał Miłecki 						     SSB_SPROM4_AGAIN23,
5516daf4321SRafał Miłecki 						     SSB_SPROM4_AGAIN3,
5526daf4321SRafał Miłecki 						     SSB_SPROM4_AGAIN3_SHIFT);
553e861b98dSMichael Buesch 
5546ad59343SRafał Miłecki 	/* Extract cores power info info */
5556ad59343SRafał Miłecki 	for (i = 0; i < ARRAY_SIZE(pwr_info_offset); i++) {
5566ad59343SRafał Miłecki 		u16 o = pwr_info_offset[i];
5576ad59343SRafał Miłecki 
5586ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].itssi_2g, o + SSB_SPROM4_2G_MAXP_ITSSI,
5596ad59343SRafał Miłecki 			SSB_SPROM4_2G_ITSSI, SSB_SPROM4_2G_ITSSI_SHIFT);
5606ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].maxpwr_2g, o + SSB_SPROM4_2G_MAXP_ITSSI,
5616ad59343SRafał Miłecki 			SSB_SPROM4_2G_MAXP, 0);
5626ad59343SRafał Miłecki 
5636ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].pa_2g[0], o + SSB_SPROM4_2G_PA_0, ~0, 0);
5646ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].pa_2g[1], o + SSB_SPROM4_2G_PA_1, ~0, 0);
5656ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].pa_2g[2], o + SSB_SPROM4_2G_PA_2, ~0, 0);
5666ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].pa_2g[3], o + SSB_SPROM4_2G_PA_3, ~0, 0);
5676ad59343SRafał Miłecki 
5686ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].itssi_5g, o + SSB_SPROM4_5G_MAXP_ITSSI,
5696ad59343SRafał Miłecki 			SSB_SPROM4_5G_ITSSI, SSB_SPROM4_5G_ITSSI_SHIFT);
5706ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].maxpwr_5g, o + SSB_SPROM4_5G_MAXP_ITSSI,
5716ad59343SRafał Miłecki 			SSB_SPROM4_5G_MAXP, 0);
5726ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].maxpwr_5gh, o + SSB_SPROM4_5GHL_MAXP,
5736ad59343SRafał Miłecki 			SSB_SPROM4_5GH_MAXP, 0);
5746ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].maxpwr_5gl, o + SSB_SPROM4_5GHL_MAXP,
5756ad59343SRafał Miłecki 			SSB_SPROM4_5GL_MAXP, SSB_SPROM4_5GL_MAXP_SHIFT);
5766ad59343SRafał Miłecki 
5776ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gl[0], o + SSB_SPROM4_5GL_PA_0, ~0, 0);
5786ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gl[1], o + SSB_SPROM4_5GL_PA_1, ~0, 0);
5796ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gl[2], o + SSB_SPROM4_5GL_PA_2, ~0, 0);
5806ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gl[3], o + SSB_SPROM4_5GL_PA_3, ~0, 0);
5816ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5g[0], o + SSB_SPROM4_5G_PA_0, ~0, 0);
5826ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5g[1], o + SSB_SPROM4_5G_PA_1, ~0, 0);
5836ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5g[2], o + SSB_SPROM4_5G_PA_2, ~0, 0);
5846ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5g[3], o + SSB_SPROM4_5G_PA_3, ~0, 0);
5856ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gh[0], o + SSB_SPROM4_5GH_PA_0, ~0, 0);
5866ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gh[1], o + SSB_SPROM4_5GH_PA_1, ~0, 0);
5876ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gh[2], o + SSB_SPROM4_5GH_PA_2, ~0, 0);
5886ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gh[3], o + SSB_SPROM4_5GH_PA_3, ~0, 0);
5896ad59343SRafał Miłecki 	}
5906ad59343SRafał Miłecki 
591172c69a4SRafał Miłecki 	sprom_extract_r458(out, in);
592172c69a4SRafał Miłecki 
593c272ef44SLarry Finger 	/* TODO - get remaining rev 4 stuff needed */
59461e115a5SMichael Buesch }
59561e115a5SMichael Buesch 
5966b1c7c67SMichael Buesch static void sprom_extract_r8(struct ssb_sprom *out, const u16 *in)
5976b1c7c67SMichael Buesch {
5986b1c7c67SMichael Buesch 	int i;
599e5652756SJoe Perches 	u16 o;
600b0f70292SRafał Miłecki 	u16 pwr_info_offset[] = {
601b0f70292SRafał Miłecki 		SSB_SROM8_PWR_INFO_CORE0, SSB_SROM8_PWR_INFO_CORE1,
602b0f70292SRafał Miłecki 		SSB_SROM8_PWR_INFO_CORE2, SSB_SROM8_PWR_INFO_CORE3
603b0f70292SRafał Miłecki 	};
604b0f70292SRafał Miłecki 	BUILD_BUG_ON(ARRAY_SIZE(pwr_info_offset) !=
605b0f70292SRafał Miłecki 			ARRAY_SIZE(out->core_pwr_info));
6066b1c7c67SMichael Buesch 
6076b1c7c67SMichael Buesch 	/* extract the MAC address */
608e5652756SJoe Perches 	sprom_get_mac(out->il0mac, &in[SPOFF(SSB_SPROM8_IL0MAC)]);
609e5652756SJoe Perches 
610673335c8SHauke Mehrtens 	SPEX(board_rev, SSB_SPROM8_BOARDREV, 0xFFFF, 0);
6113623b266SRafał Miłecki 	SPEX(board_type, SSB_SPROM1_SPID, 0xFFFF, 0);
612bf7d420bSHauke Mehrtens 	SPEX(alpha2[0], SSB_SPROM8_CCODE, 0xff00, 8);
613bf7d420bSHauke Mehrtens 	SPEX(alpha2[1], SSB_SPROM8_CCODE, 0x00ff, 0);
6146b1c7c67SMichael Buesch 	SPEX(boardflags_lo, SSB_SPROM8_BFLLO, 0xFFFF, 0);
6156b1c7c67SMichael Buesch 	SPEX(boardflags_hi, SSB_SPROM8_BFLHI, 0xFFFF, 0);
616f679056bSGábor Stefanik 	SPEX(boardflags2_lo, SSB_SPROM8_BFL2LO, 0xFFFF, 0);
617f679056bSGábor Stefanik 	SPEX(boardflags2_hi, SSB_SPROM8_BFL2HI, 0xFFFF, 0);
6186b1c7c67SMichael Buesch 	SPEX(ant_available_a, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_A,
6196b1c7c67SMichael Buesch 	     SSB_SPROM8_ANTAVAIL_A_SHIFT);
6206b1c7c67SMichael Buesch 	SPEX(ant_available_bg, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_BG,
6216b1c7c67SMichael Buesch 	     SSB_SPROM8_ANTAVAIL_BG_SHIFT);
6226b1c7c67SMichael Buesch 	SPEX(maxpwr_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_MAXP_BG_MASK, 0);
6236b1c7c67SMichael Buesch 	SPEX(itssi_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_ITSSI_BG,
6246b1c7c67SMichael Buesch 	     SSB_SPROM8_ITSSI_BG_SHIFT);
6256b1c7c67SMichael Buesch 	SPEX(maxpwr_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_MAXP_A_MASK, 0);
6266b1c7c67SMichael Buesch 	SPEX(itssi_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_ITSSI_A,
6276b1c7c67SMichael Buesch 	     SSB_SPROM8_ITSSI_A_SHIFT);
628f679056bSGábor Stefanik 	SPEX(maxpwr_ah, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AH_MASK, 0);
629f679056bSGábor Stefanik 	SPEX(maxpwr_al, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AL_MASK,
630f679056bSGábor Stefanik 	     SSB_SPROM8_MAXP_AL_SHIFT);
6316b1c7c67SMichael Buesch 	SPEX(gpio0, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P0, 0);
6326b1c7c67SMichael Buesch 	SPEX(gpio1, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P1,
6336b1c7c67SMichael Buesch 	     SSB_SPROM8_GPIOA_P1_SHIFT);
6346b1c7c67SMichael Buesch 	SPEX(gpio2, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P2, 0);
6356b1c7c67SMichael Buesch 	SPEX(gpio3, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P3,
6366b1c7c67SMichael Buesch 	     SSB_SPROM8_GPIOB_P3_SHIFT);
637f679056bSGábor Stefanik 	SPEX(tri2g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI2G, 0);
638f679056bSGábor Stefanik 	SPEX(tri5g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI5G,
639f679056bSGábor Stefanik 	     SSB_SPROM8_TRI5G_SHIFT);
640f679056bSGábor Stefanik 	SPEX(tri5gl, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GL, 0);
641f679056bSGábor Stefanik 	SPEX(tri5gh, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GH,
642f679056bSGábor Stefanik 	     SSB_SPROM8_TRI5GH_SHIFT);
643f679056bSGábor Stefanik 	SPEX(rxpo2g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO2G, 0);
644f679056bSGábor Stefanik 	SPEX(rxpo5g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO5G,
645f679056bSGábor Stefanik 	     SSB_SPROM8_RXPO5G_SHIFT);
646f679056bSGábor Stefanik 	SPEX(rssismf2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMF2G, 0);
647f679056bSGábor Stefanik 	SPEX(rssismc2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMC2G,
648f679056bSGábor Stefanik 	     SSB_SPROM8_RSSISMC2G_SHIFT);
649f679056bSGábor Stefanik 	SPEX(rssisav2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISAV2G,
650f679056bSGábor Stefanik 	     SSB_SPROM8_RSSISAV2G_SHIFT);
651f679056bSGábor Stefanik 	SPEX(bxa2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_BXA2G,
652f679056bSGábor Stefanik 	     SSB_SPROM8_BXA2G_SHIFT);
653f679056bSGábor Stefanik 	SPEX(rssismf5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMF5G, 0);
654f679056bSGábor Stefanik 	SPEX(rssismc5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMC5G,
655f679056bSGábor Stefanik 	     SSB_SPROM8_RSSISMC5G_SHIFT);
656f679056bSGábor Stefanik 	SPEX(rssisav5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISAV5G,
657f679056bSGábor Stefanik 	     SSB_SPROM8_RSSISAV5G_SHIFT);
658f679056bSGábor Stefanik 	SPEX(bxa5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_BXA5G,
659f679056bSGábor Stefanik 	     SSB_SPROM8_BXA5G_SHIFT);
660f679056bSGábor Stefanik 	SPEX(pa0b0, SSB_SPROM8_PA0B0, 0xFFFF, 0);
661f679056bSGábor Stefanik 	SPEX(pa0b1, SSB_SPROM8_PA0B1, 0xFFFF, 0);
662f679056bSGábor Stefanik 	SPEX(pa0b2, SSB_SPROM8_PA0B2, 0xFFFF, 0);
663f679056bSGábor Stefanik 	SPEX(pa1b0, SSB_SPROM8_PA1B0, 0xFFFF, 0);
664f679056bSGábor Stefanik 	SPEX(pa1b1, SSB_SPROM8_PA1B1, 0xFFFF, 0);
665f679056bSGábor Stefanik 	SPEX(pa1b2, SSB_SPROM8_PA1B2, 0xFFFF, 0);
666f679056bSGábor Stefanik 	SPEX(pa1lob0, SSB_SPROM8_PA1LOB0, 0xFFFF, 0);
667f679056bSGábor Stefanik 	SPEX(pa1lob1, SSB_SPROM8_PA1LOB1, 0xFFFF, 0);
668f679056bSGábor Stefanik 	SPEX(pa1lob2, SSB_SPROM8_PA1LOB2, 0xFFFF, 0);
669f679056bSGábor Stefanik 	SPEX(pa1hib0, SSB_SPROM8_PA1HIB0, 0xFFFF, 0);
670f679056bSGábor Stefanik 	SPEX(pa1hib1, SSB_SPROM8_PA1HIB1, 0xFFFF, 0);
671f679056bSGábor Stefanik 	SPEX(pa1hib2, SSB_SPROM8_PA1HIB2, 0xFFFF, 0);
672f679056bSGábor Stefanik 	SPEX(cck2gpo, SSB_SPROM8_CCK2GPO, 0xFFFF, 0);
673f679056bSGábor Stefanik 	SPEX32(ofdm2gpo, SSB_SPROM8_OFDM2GPO, 0xFFFFFFFF, 0);
674f679056bSGábor Stefanik 	SPEX32(ofdm5glpo, SSB_SPROM8_OFDM5GLPO, 0xFFFFFFFF, 0);
675f679056bSGábor Stefanik 	SPEX32(ofdm5gpo, SSB_SPROM8_OFDM5GPO, 0xFFFFFFFF, 0);
676f679056bSGábor Stefanik 	SPEX32(ofdm5ghpo, SSB_SPROM8_OFDM5GHPO, 0xFFFFFFFF, 0);
6776b1c7c67SMichael Buesch 
6786b1c7c67SMichael Buesch 	/* Extract the antenna gain values. */
6796daf4321SRafał Miłecki 	out->antenna_gain.a0 = sprom_extract_antgain(out->revision, in,
6806daf4321SRafał Miłecki 						     SSB_SPROM8_AGAIN01,
6816daf4321SRafał Miłecki 						     SSB_SPROM8_AGAIN0,
6826daf4321SRafał Miłecki 						     SSB_SPROM8_AGAIN0_SHIFT);
6836daf4321SRafał Miłecki 	out->antenna_gain.a1 = sprom_extract_antgain(out->revision, in,
6846daf4321SRafał Miłecki 						     SSB_SPROM8_AGAIN01,
6856daf4321SRafał Miłecki 						     SSB_SPROM8_AGAIN1,
6866daf4321SRafał Miłecki 						     SSB_SPROM8_AGAIN1_SHIFT);
6876daf4321SRafał Miłecki 	out->antenna_gain.a2 = sprom_extract_antgain(out->revision, in,
6886daf4321SRafał Miłecki 						     SSB_SPROM8_AGAIN23,
6896daf4321SRafał Miłecki 						     SSB_SPROM8_AGAIN2,
6906daf4321SRafał Miłecki 						     SSB_SPROM8_AGAIN2_SHIFT);
6916daf4321SRafał Miłecki 	out->antenna_gain.a3 = sprom_extract_antgain(out->revision, in,
6926daf4321SRafał Miłecki 						     SSB_SPROM8_AGAIN23,
6936daf4321SRafał Miłecki 						     SSB_SPROM8_AGAIN3,
6946daf4321SRafał Miłecki 						     SSB_SPROM8_AGAIN3_SHIFT);
6956b1c7c67SMichael Buesch 
696b0f70292SRafał Miłecki 	/* Extract cores power info info */
697b0f70292SRafał Miłecki 	for (i = 0; i < ARRAY_SIZE(pwr_info_offset); i++) {
698b0f70292SRafał Miłecki 		o = pwr_info_offset[i];
699b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].itssi_2g, o + SSB_SROM8_2G_MAXP_ITSSI,
700b0f70292SRafał Miłecki 			SSB_SPROM8_2G_ITSSI, SSB_SPROM8_2G_ITSSI_SHIFT);
701b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].maxpwr_2g, o + SSB_SROM8_2G_MAXP_ITSSI,
702b0f70292SRafał Miłecki 			SSB_SPROM8_2G_MAXP, 0);
703b0f70292SRafał Miłecki 
704b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].pa_2g[0], o + SSB_SROM8_2G_PA_0, ~0, 0);
705b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].pa_2g[1], o + SSB_SROM8_2G_PA_1, ~0, 0);
706b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].pa_2g[2], o + SSB_SROM8_2G_PA_2, ~0, 0);
707b0f70292SRafał Miłecki 
708b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].itssi_5g, o + SSB_SROM8_5G_MAXP_ITSSI,
709b0f70292SRafał Miłecki 			SSB_SPROM8_5G_ITSSI, SSB_SPROM8_5G_ITSSI_SHIFT);
710b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].maxpwr_5g, o + SSB_SROM8_5G_MAXP_ITSSI,
711b0f70292SRafał Miłecki 			SSB_SPROM8_5G_MAXP, 0);
712b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].maxpwr_5gh, o + SSB_SPROM8_5GHL_MAXP,
713b0f70292SRafał Miłecki 			SSB_SPROM8_5GH_MAXP, 0);
714b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].maxpwr_5gl, o + SSB_SPROM8_5GHL_MAXP,
715b0f70292SRafał Miłecki 			SSB_SPROM8_5GL_MAXP, SSB_SPROM8_5GL_MAXP_SHIFT);
716b0f70292SRafał Miłecki 
717b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gl[0], o + SSB_SROM8_5GL_PA_0, ~0, 0);
718b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gl[1], o + SSB_SROM8_5GL_PA_1, ~0, 0);
719b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gl[2], o + SSB_SROM8_5GL_PA_2, ~0, 0);
720b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5g[0], o + SSB_SROM8_5G_PA_0, ~0, 0);
721b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5g[1], o + SSB_SROM8_5G_PA_1, ~0, 0);
722b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5g[2], o + SSB_SROM8_5G_PA_2, ~0, 0);
723b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gh[0], o + SSB_SROM8_5GH_PA_0, ~0, 0);
724b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gh[1], o + SSB_SROM8_5GH_PA_1, ~0, 0);
725b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gh[2], o + SSB_SROM8_5GH_PA_2, ~0, 0);
726b0f70292SRafał Miłecki 	}
727b0f70292SRafał Miłecki 
7288a5ac6ecSRafał Miłecki 	/* Extract FEM info */
7298a5ac6ecSRafał Miłecki 	SPEX(fem.ghz2.tssipos, SSB_SPROM8_FEM2G,
7308a5ac6ecSRafał Miłecki 		SSB_SROM8_FEM_TSSIPOS, SSB_SROM8_FEM_TSSIPOS_SHIFT);
7318a5ac6ecSRafał Miłecki 	SPEX(fem.ghz2.extpa_gain, SSB_SPROM8_FEM2G,
7328a5ac6ecSRafał Miłecki 		SSB_SROM8_FEM_EXTPA_GAIN, SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
7338a5ac6ecSRafał Miłecki 	SPEX(fem.ghz2.pdet_range, SSB_SPROM8_FEM2G,
7348a5ac6ecSRafał Miłecki 		SSB_SROM8_FEM_PDET_RANGE, SSB_SROM8_FEM_PDET_RANGE_SHIFT);
7358a5ac6ecSRafał Miłecki 	SPEX(fem.ghz2.tr_iso, SSB_SPROM8_FEM2G,
7368a5ac6ecSRafał Miłecki 		SSB_SROM8_FEM_TR_ISO, SSB_SROM8_FEM_TR_ISO_SHIFT);
7378a5ac6ecSRafał Miłecki 	SPEX(fem.ghz2.antswlut, SSB_SPROM8_FEM2G,
7388a5ac6ecSRafał Miłecki 		SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT);
7398a5ac6ecSRafał Miłecki 
7408a5ac6ecSRafał Miłecki 	SPEX(fem.ghz5.tssipos, SSB_SPROM8_FEM5G,
7418a5ac6ecSRafał Miłecki 		SSB_SROM8_FEM_TSSIPOS, SSB_SROM8_FEM_TSSIPOS_SHIFT);
7428a5ac6ecSRafał Miłecki 	SPEX(fem.ghz5.extpa_gain, SSB_SPROM8_FEM5G,
7438a5ac6ecSRafał Miłecki 		SSB_SROM8_FEM_EXTPA_GAIN, SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
7448a5ac6ecSRafał Miłecki 	SPEX(fem.ghz5.pdet_range, SSB_SPROM8_FEM5G,
7458a5ac6ecSRafał Miłecki 		SSB_SROM8_FEM_PDET_RANGE, SSB_SROM8_FEM_PDET_RANGE_SHIFT);
7468a5ac6ecSRafał Miłecki 	SPEX(fem.ghz5.tr_iso, SSB_SPROM8_FEM5G,
7478a5ac6ecSRafał Miłecki 		SSB_SROM8_FEM_TR_ISO, SSB_SROM8_FEM_TR_ISO_SHIFT);
7488a5ac6ecSRafał Miłecki 	SPEX(fem.ghz5.antswlut, SSB_SPROM8_FEM5G,
7498a5ac6ecSRafał Miłecki 		SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT);
7508a5ac6ecSRafał Miłecki 
751e2da4bd3SHauke Mehrtens 	SPEX(leddc_on_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_ON,
752e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_LEDDC_ON_SHIFT);
753e2da4bd3SHauke Mehrtens 	SPEX(leddc_off_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_OFF,
754e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_LEDDC_OFF_SHIFT);
755e2da4bd3SHauke Mehrtens 
756e2da4bd3SHauke Mehrtens 	SPEX(txchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_TXCHAIN,
757e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_TXRXC_TXCHAIN_SHIFT);
758e2da4bd3SHauke Mehrtens 	SPEX(rxchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_RXCHAIN,
759e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_TXRXC_RXCHAIN_SHIFT);
760e2da4bd3SHauke Mehrtens 	SPEX(antswitch, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_SWITCH,
761e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_TXRXC_SWITCH_SHIFT);
762e2da4bd3SHauke Mehrtens 
763e2da4bd3SHauke Mehrtens 	SPEX(opo, SSB_SPROM8_OFDM2GPO, 0x00ff, 0);
764e2da4bd3SHauke Mehrtens 
765e2da4bd3SHauke Mehrtens 	SPEX_ARRAY8(mcs2gpo, SSB_SPROM8_2G_MCSPO, ~0, 0);
766e2da4bd3SHauke Mehrtens 	SPEX_ARRAY8(mcs5gpo, SSB_SPROM8_5G_MCSPO, ~0, 0);
767e2da4bd3SHauke Mehrtens 	SPEX_ARRAY8(mcs5glpo, SSB_SPROM8_5GL_MCSPO, ~0, 0);
768e2da4bd3SHauke Mehrtens 	SPEX_ARRAY8(mcs5ghpo, SSB_SPROM8_5GH_MCSPO, ~0, 0);
769e2da4bd3SHauke Mehrtens 
770e2da4bd3SHauke Mehrtens 	SPEX(rawtempsense, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_RAWTEMP,
771e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_RAWTS_RAWTEMP_SHIFT);
772e2da4bd3SHauke Mehrtens 	SPEX(measpower, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_MEASPOWER,
773e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_RAWTS_MEASPOWER_SHIFT);
774e2da4bd3SHauke Mehrtens 	SPEX(tempsense_slope, SSB_SPROM8_OPT_CORRX,
775e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_OPT_CORRX_TEMP_SLOPE,
776e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_OPT_CORRX_TEMP_SLOPE_SHIFT);
777e2da4bd3SHauke Mehrtens 	SPEX(tempcorrx, SSB_SPROM8_OPT_CORRX, SSB_SPROM8_OPT_CORRX_TEMPCORRX,
778e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_OPT_CORRX_TEMPCORRX_SHIFT);
779e2da4bd3SHauke Mehrtens 	SPEX(tempsense_option, SSB_SPROM8_OPT_CORRX,
780e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_OPT_CORRX_TEMP_OPTION,
781e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_OPT_CORRX_TEMP_OPTION_SHIFT);
782e2da4bd3SHauke Mehrtens 	SPEX(freqoffset_corr, SSB_SPROM8_HWIQ_IQSWP,
783e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR,
784e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR_SHIFT);
785e2da4bd3SHauke Mehrtens 	SPEX(iqcal_swp_dis, SSB_SPROM8_HWIQ_IQSWP,
786e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP,
787e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP_SHIFT);
788e2da4bd3SHauke Mehrtens 	SPEX(hw_iqcal_en, SSB_SPROM8_HWIQ_IQSWP, SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL,
789e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL_SHIFT);
790e2da4bd3SHauke Mehrtens 
791e2da4bd3SHauke Mehrtens 	SPEX(bw40po, SSB_SPROM8_BW40PO, ~0, 0);
792e2da4bd3SHauke Mehrtens 	SPEX(cddpo, SSB_SPROM8_CDDPO, ~0, 0);
793e2da4bd3SHauke Mehrtens 	SPEX(stbcpo, SSB_SPROM8_STBCPO, ~0, 0);
794e2da4bd3SHauke Mehrtens 	SPEX(bwduppo, SSB_SPROM8_BWDUPPO, ~0, 0);
795e2da4bd3SHauke Mehrtens 
796e2da4bd3SHauke Mehrtens 	SPEX(tempthresh, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_TRESH,
797e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_THERMAL_TRESH_SHIFT);
798e2da4bd3SHauke Mehrtens 	SPEX(tempoffset, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_OFFSET,
799e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_THERMAL_OFFSET_SHIFT);
800e2da4bd3SHauke Mehrtens 	SPEX(phycal_tempdelta, SSB_SPROM8_TEMPDELTA,
801e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_TEMPDELTA_PHYCAL,
802e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_TEMPDELTA_PHYCAL_SHIFT);
803e2da4bd3SHauke Mehrtens 	SPEX(temps_period, SSB_SPROM8_TEMPDELTA, SSB_SPROM8_TEMPDELTA_PERIOD,
804e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_TEMPDELTA_PERIOD_SHIFT);
805e2da4bd3SHauke Mehrtens 	SPEX(temps_hysteresis, SSB_SPROM8_TEMPDELTA,
806e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_TEMPDELTA_HYSTERESIS,
807e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_TEMPDELTA_HYSTERESIS_SHIFT);
808172c69a4SRafał Miłecki 	sprom_extract_r458(out, in);
809172c69a4SRafał Miłecki 
8106b1c7c67SMichael Buesch 	/* TODO - get remaining rev 8 stuff needed */
8116b1c7c67SMichael Buesch }
8126b1c7c67SMichael Buesch 
813c272ef44SLarry Finger static int sprom_extract(struct ssb_bus *bus, struct ssb_sprom *out,
814c272ef44SLarry Finger 			 const u16 *in, u16 size)
81561e115a5SMichael Buesch {
81661e115a5SMichael Buesch 	memset(out, 0, sizeof(*out));
81761e115a5SMichael Buesch 
818c272ef44SLarry Finger 	out->revision = in[size - 1] & 0x00FF;
81933a606acSJoe Perches 	ssb_dbg("SPROM revision %d detected\n", out->revision);
82031ce12fbSLarry Finger 	memset(out->et0mac, 0xFF, 6);		/* preset et0 and et1 mac */
82131ce12fbSLarry Finger 	memset(out->et1mac, 0xFF, 6);
82254435f9eSRafał Miłecki 
82361e115a5SMichael Buesch 	if ((bus->chip_id & 0xFF00) == 0x4400) {
82461e115a5SMichael Buesch 		/* Workaround: The BCM44XX chip has a stupid revision
82561e115a5SMichael Buesch 		 * number stored in the SPROM.
82661e115a5SMichael Buesch 		 * Always extract r1. */
827c272ef44SLarry Finger 		out->revision = 1;
82833a606acSJoe Perches 		ssb_dbg("SPROM treated as revision %d\n", out->revision);
82954435f9eSRafał Miłecki 	}
83054435f9eSRafał Miłecki 
8316b1c7c67SMichael Buesch 	switch (out->revision) {
8326b1c7c67SMichael Buesch 	case 1:
8336b1c7c67SMichael Buesch 	case 2:
8346b1c7c67SMichael Buesch 	case 3:
8356b1c7c67SMichael Buesch 		sprom_extract_r123(out, in);
8366b1c7c67SMichael Buesch 		break;
8376b1c7c67SMichael Buesch 	case 4:
8386b1c7c67SMichael Buesch 	case 5:
8396b1c7c67SMichael Buesch 		sprom_extract_r45(out, in);
8406b1c7c67SMichael Buesch 		break;
8416b1c7c67SMichael Buesch 	case 8:
8426b1c7c67SMichael Buesch 		sprom_extract_r8(out, in);
8436b1c7c67SMichael Buesch 		break;
8446b1c7c67SMichael Buesch 	default:
84533a606acSJoe Perches 		ssb_warn("Unsupported SPROM revision %d detected. Will extract v1\n",
84633a606acSJoe Perches 			 out->revision);
847cd559b36SLarry Finger 		out->revision = 1;
848c272ef44SLarry Finger 		sprom_extract_r123(out, in);
849c272ef44SLarry Finger 	}
85061e115a5SMichael Buesch 
8514503183aSLarry Finger 	if (out->boardflags_lo == 0xFFFF)
8524503183aSLarry Finger 		out->boardflags_lo = 0;  /* per specs */
8534503183aSLarry Finger 	if (out->boardflags_hi == 0xFFFF)
8544503183aSLarry Finger 		out->boardflags_hi = 0;  /* per specs */
8554503183aSLarry Finger 
85661e115a5SMichael Buesch 	return 0;
85761e115a5SMichael Buesch }
85861e115a5SMichael Buesch 
85961e115a5SMichael Buesch static int ssb_pci_sprom_get(struct ssb_bus *bus,
86061e115a5SMichael Buesch 			     struct ssb_sprom *sprom)
86161e115a5SMichael Buesch {
862ca4a0831SRafał Miłecki 	int err;
86361e115a5SMichael Buesch 	u16 *buf;
86461e115a5SMichael Buesch 
865d53cdbb9SJohn W. Linville 	if (!ssb_is_sprom_available(bus)) {
86633a606acSJoe Perches 		ssb_err("No SPROM available!\n");
867d53cdbb9SJohn W. Linville 		return -ENODEV;
868d53cdbb9SJohn W. Linville 	}
86925985edcSLucas De Marchi 	if (bus->chipco.dev) {	/* can be unavailable! */
8709d1ac34eSLarry Finger 		/*
8719d1ac34eSLarry Finger 		 * get SPROM offset: SSB_SPROM_BASE1 except for
8729d1ac34eSLarry Finger 		 * chipcommon rev >= 31 or chip ID is 0x4312 and
8739d1ac34eSLarry Finger 		 * chipcommon status & 3 == 2
8749d1ac34eSLarry Finger 		 */
8759d1ac34eSLarry Finger 		if (bus->chipco.dev->id.revision >= 31)
8769d1ac34eSLarry Finger 			bus->sprom_offset = SSB_SPROM_BASE31;
8779d1ac34eSLarry Finger 		else if (bus->chip_id == 0x4312 &&
8789d1ac34eSLarry Finger 			 (bus->chipco.status & 0x03) == 2)
8799d1ac34eSLarry Finger 			bus->sprom_offset = SSB_SPROM_BASE31;
8809d1ac34eSLarry Finger 		else
8819d1ac34eSLarry Finger 			bus->sprom_offset = SSB_SPROM_BASE1;
882da1fdb02SChristoph Fritz 	} else {
883da1fdb02SChristoph Fritz 		bus->sprom_offset = SSB_SPROM_BASE1;
884da1fdb02SChristoph Fritz 	}
88533a606acSJoe Perches 	ssb_dbg("SPROM offset is 0x%x\n", bus->sprom_offset);
886ea2db495SRafał Miłecki 
887c272ef44SLarry Finger 	buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL);
88861e115a5SMichael Buesch 	if (!buf)
889ca4a0831SRafał Miłecki 		return -ENOMEM;
890c272ef44SLarry Finger 	bus->sprom_size = SSB_SPROMSIZE_WORDS_R123;
89161e115a5SMichael Buesch 	sprom_do_read(bus, buf);
892c272ef44SLarry Finger 	err = sprom_check_crc(buf, bus->sprom_size);
89361e115a5SMichael Buesch 	if (err) {
8942afc4901SLarry.Finger@lwfinger.net 		/* try for a 440 byte SPROM - revision 4 and higher */
895c272ef44SLarry Finger 		kfree(buf);
896c272ef44SLarry Finger 		buf = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
897c272ef44SLarry Finger 			      GFP_KERNEL);
898c272ef44SLarry Finger 		if (!buf)
899ca4a0831SRafał Miłecki 			return -ENOMEM;
900c272ef44SLarry Finger 		bus->sprom_size = SSB_SPROMSIZE_WORDS_R4;
901c272ef44SLarry Finger 		sprom_do_read(bus, buf);
902c272ef44SLarry Finger 		err = sprom_check_crc(buf, bus->sprom_size);
903e79c1ba8SMichael Buesch 		if (err) {
904e79c1ba8SMichael Buesch 			/* All CRC attempts failed.
905e79c1ba8SMichael Buesch 			 * Maybe there is no SPROM on the device?
906b3ae52b6SHauke Mehrtens 			 * Now we ask the arch code if there is some sprom
907b3ae52b6SHauke Mehrtens 			 * available for this device in some other storage */
908b3ae52b6SHauke Mehrtens 			err = ssb_fill_sprom_with_fallback(bus, sprom);
909b3ae52b6SHauke Mehrtens 			if (err) {
91033a606acSJoe Perches 				ssb_warn("WARNING: Using fallback SPROM failed (err %d)\n",
911b3ae52b6SHauke Mehrtens 					 err);
912*8052d724SLarry Finger 				goto out_free;
913b3ae52b6SHauke Mehrtens 			} else {
91433a606acSJoe Perches 				ssb_dbg("Using SPROM revision %d provided by platform\n",
91533a606acSJoe Perches 					sprom->revision);
916e79c1ba8SMichael Buesch 				err = 0;
917e79c1ba8SMichael Buesch 				goto out_free;
918e79c1ba8SMichael Buesch 			}
91933a606acSJoe Perches 			ssb_warn("WARNING: Invalid SPROM CRC (corrupt SPROM)\n");
920c272ef44SLarry Finger 		}
921e79c1ba8SMichael Buesch 	}
922c272ef44SLarry Finger 	err = sprom_extract(bus, sprom, buf, bus->sprom_size);
92361e115a5SMichael Buesch 
924e79c1ba8SMichael Buesch out_free:
92561e115a5SMichael Buesch 	kfree(buf);
92661e115a5SMichael Buesch 	return err;
92761e115a5SMichael Buesch }
92861e115a5SMichael Buesch 
92961e115a5SMichael Buesch static void ssb_pci_get_boardinfo(struct ssb_bus *bus,
93061e115a5SMichael Buesch 				  struct ssb_boardinfo *bi)
93161e115a5SMichael Buesch {
932115f9450SSergei Shtylyov 	bi->vendor = bus->host_pci->subsystem_vendor;
933115f9450SSergei Shtylyov 	bi->type = bus->host_pci->subsystem_device;
93461e115a5SMichael Buesch }
93561e115a5SMichael Buesch 
93661e115a5SMichael Buesch int ssb_pci_get_invariants(struct ssb_bus *bus,
93761e115a5SMichael Buesch 			   struct ssb_init_invariants *iv)
93861e115a5SMichael Buesch {
93961e115a5SMichael Buesch 	int err;
94061e115a5SMichael Buesch 
94161e115a5SMichael Buesch 	err = ssb_pci_sprom_get(bus, &iv->sprom);
94261e115a5SMichael Buesch 	if (err)
94361e115a5SMichael Buesch 		goto out;
94461e115a5SMichael Buesch 	ssb_pci_get_boardinfo(bus, &iv->boardinfo);
94561e115a5SMichael Buesch 
94661e115a5SMichael Buesch out:
94761e115a5SMichael Buesch 	return err;
94861e115a5SMichael Buesch }
94961e115a5SMichael Buesch 
95061e115a5SMichael Buesch #ifdef CONFIG_SSB_DEBUG
95161e115a5SMichael Buesch static int ssb_pci_assert_buspower(struct ssb_bus *bus)
95261e115a5SMichael Buesch {
95361e115a5SMichael Buesch 	if (likely(bus->powered_up))
95461e115a5SMichael Buesch 		return 0;
95561e115a5SMichael Buesch 
95661e115a5SMichael Buesch 	printk(KERN_ERR PFX "FATAL ERROR: Bus powered down "
95761e115a5SMichael Buesch 	       "while accessing PCI MMIO space\n");
95861e115a5SMichael Buesch 	if (bus->power_warn_count <= 10) {
95961e115a5SMichael Buesch 		bus->power_warn_count++;
96061e115a5SMichael Buesch 		dump_stack();
96161e115a5SMichael Buesch 	}
96261e115a5SMichael Buesch 
96361e115a5SMichael Buesch 	return -ENODEV;
96461e115a5SMichael Buesch }
96561e115a5SMichael Buesch #else /* DEBUG */
96661e115a5SMichael Buesch static inline int ssb_pci_assert_buspower(struct ssb_bus *bus)
96761e115a5SMichael Buesch {
96861e115a5SMichael Buesch 	return 0;
96961e115a5SMichael Buesch }
97061e115a5SMichael Buesch #endif /* DEBUG */
97161e115a5SMichael Buesch 
972ffc7689dSMichael Buesch static u8 ssb_pci_read8(struct ssb_device *dev, u16 offset)
973ffc7689dSMichael Buesch {
974ffc7689dSMichael Buesch 	struct ssb_bus *bus = dev->bus;
975ffc7689dSMichael Buesch 
976ffc7689dSMichael Buesch 	if (unlikely(ssb_pci_assert_buspower(bus)))
977ffc7689dSMichael Buesch 		return 0xFF;
978ffc7689dSMichael Buesch 	if (unlikely(bus->mapped_device != dev)) {
979ffc7689dSMichael Buesch 		if (unlikely(ssb_pci_switch_core(bus, dev)))
980ffc7689dSMichael Buesch 			return 0xFF;
981ffc7689dSMichael Buesch 	}
982ffc7689dSMichael Buesch 	return ioread8(bus->mmio + offset);
983ffc7689dSMichael Buesch }
984ffc7689dSMichael Buesch 
98561e115a5SMichael Buesch static u16 ssb_pci_read16(struct ssb_device *dev, u16 offset)
98661e115a5SMichael Buesch {
98761e115a5SMichael Buesch 	struct ssb_bus *bus = dev->bus;
98861e115a5SMichael Buesch 
98961e115a5SMichael Buesch 	if (unlikely(ssb_pci_assert_buspower(bus)))
99061e115a5SMichael Buesch 		return 0xFFFF;
99161e115a5SMichael Buesch 	if (unlikely(bus->mapped_device != dev)) {
99261e115a5SMichael Buesch 		if (unlikely(ssb_pci_switch_core(bus, dev)))
99361e115a5SMichael Buesch 			return 0xFFFF;
99461e115a5SMichael Buesch 	}
9954b402c65SMichael Buesch 	return ioread16(bus->mmio + offset);
99661e115a5SMichael Buesch }
99761e115a5SMichael Buesch 
99861e115a5SMichael Buesch static u32 ssb_pci_read32(struct ssb_device *dev, u16 offset)
99961e115a5SMichael Buesch {
100061e115a5SMichael Buesch 	struct ssb_bus *bus = dev->bus;
100161e115a5SMichael Buesch 
100261e115a5SMichael Buesch 	if (unlikely(ssb_pci_assert_buspower(bus)))
100361e115a5SMichael Buesch 		return 0xFFFFFFFF;
100461e115a5SMichael Buesch 	if (unlikely(bus->mapped_device != dev)) {
100561e115a5SMichael Buesch 		if (unlikely(ssb_pci_switch_core(bus, dev)))
100661e115a5SMichael Buesch 			return 0xFFFFFFFF;
100761e115a5SMichael Buesch 	}
10084b402c65SMichael Buesch 	return ioread32(bus->mmio + offset);
100961e115a5SMichael Buesch }
101061e115a5SMichael Buesch 
1011d625a29bSMichael Buesch #ifdef CONFIG_SSB_BLOCKIO
1012d625a29bSMichael Buesch static void ssb_pci_block_read(struct ssb_device *dev, void *buffer,
1013d625a29bSMichael Buesch 			       size_t count, u16 offset, u8 reg_width)
1014d625a29bSMichael Buesch {
1015d625a29bSMichael Buesch 	struct ssb_bus *bus = dev->bus;
1016d625a29bSMichael Buesch 	void __iomem *addr = bus->mmio + offset;
1017d625a29bSMichael Buesch 
1018d625a29bSMichael Buesch 	if (unlikely(ssb_pci_assert_buspower(bus)))
1019d625a29bSMichael Buesch 		goto error;
1020d625a29bSMichael Buesch 	if (unlikely(bus->mapped_device != dev)) {
1021d625a29bSMichael Buesch 		if (unlikely(ssb_pci_switch_core(bus, dev)))
1022d625a29bSMichael Buesch 			goto error;
1023d625a29bSMichael Buesch 	}
1024d625a29bSMichael Buesch 	switch (reg_width) {
1025d625a29bSMichael Buesch 	case sizeof(u8):
1026d625a29bSMichael Buesch 		ioread8_rep(addr, buffer, count);
1027d625a29bSMichael Buesch 		break;
1028d625a29bSMichael Buesch 	case sizeof(u16):
1029d625a29bSMichael Buesch 		SSB_WARN_ON(count & 1);
1030d625a29bSMichael Buesch 		ioread16_rep(addr, buffer, count >> 1);
1031d625a29bSMichael Buesch 		break;
1032d625a29bSMichael Buesch 	case sizeof(u32):
1033d625a29bSMichael Buesch 		SSB_WARN_ON(count & 3);
1034d625a29bSMichael Buesch 		ioread32_rep(addr, buffer, count >> 2);
1035d625a29bSMichael Buesch 		break;
1036d625a29bSMichael Buesch 	default:
1037d625a29bSMichael Buesch 		SSB_WARN_ON(1);
1038d625a29bSMichael Buesch 	}
1039d625a29bSMichael Buesch 
1040d625a29bSMichael Buesch 	return;
1041d625a29bSMichael Buesch error:
1042d625a29bSMichael Buesch 	memset(buffer, 0xFF, count);
1043d625a29bSMichael Buesch }
1044d625a29bSMichael Buesch #endif /* CONFIG_SSB_BLOCKIO */
1045d625a29bSMichael Buesch 
1046ffc7689dSMichael Buesch static void ssb_pci_write8(struct ssb_device *dev, u16 offset, u8 value)
1047ffc7689dSMichael Buesch {
1048ffc7689dSMichael Buesch 	struct ssb_bus *bus = dev->bus;
1049ffc7689dSMichael Buesch 
1050ffc7689dSMichael Buesch 	if (unlikely(ssb_pci_assert_buspower(bus)))
1051ffc7689dSMichael Buesch 		return;
1052ffc7689dSMichael Buesch 	if (unlikely(bus->mapped_device != dev)) {
1053ffc7689dSMichael Buesch 		if (unlikely(ssb_pci_switch_core(bus, dev)))
1054ffc7689dSMichael Buesch 			return;
1055ffc7689dSMichael Buesch 	}
1056ffc7689dSMichael Buesch 	iowrite8(value, bus->mmio + offset);
1057ffc7689dSMichael Buesch }
1058ffc7689dSMichael Buesch 
105961e115a5SMichael Buesch static void ssb_pci_write16(struct ssb_device *dev, u16 offset, u16 value)
106061e115a5SMichael Buesch {
106161e115a5SMichael Buesch 	struct ssb_bus *bus = dev->bus;
106261e115a5SMichael Buesch 
106361e115a5SMichael Buesch 	if (unlikely(ssb_pci_assert_buspower(bus)))
106461e115a5SMichael Buesch 		return;
106561e115a5SMichael Buesch 	if (unlikely(bus->mapped_device != dev)) {
106661e115a5SMichael Buesch 		if (unlikely(ssb_pci_switch_core(bus, dev)))
106761e115a5SMichael Buesch 			return;
106861e115a5SMichael Buesch 	}
10694b402c65SMichael Buesch 	iowrite16(value, bus->mmio + offset);
107061e115a5SMichael Buesch }
107161e115a5SMichael Buesch 
107261e115a5SMichael Buesch static void ssb_pci_write32(struct ssb_device *dev, u16 offset, u32 value)
107361e115a5SMichael Buesch {
107461e115a5SMichael Buesch 	struct ssb_bus *bus = dev->bus;
107561e115a5SMichael Buesch 
107661e115a5SMichael Buesch 	if (unlikely(ssb_pci_assert_buspower(bus)))
107761e115a5SMichael Buesch 		return;
107861e115a5SMichael Buesch 	if (unlikely(bus->mapped_device != dev)) {
107961e115a5SMichael Buesch 		if (unlikely(ssb_pci_switch_core(bus, dev)))
108061e115a5SMichael Buesch 			return;
108161e115a5SMichael Buesch 	}
10824b402c65SMichael Buesch 	iowrite32(value, bus->mmio + offset);
108361e115a5SMichael Buesch }
108461e115a5SMichael Buesch 
1085d625a29bSMichael Buesch #ifdef CONFIG_SSB_BLOCKIO
1086d625a29bSMichael Buesch static void ssb_pci_block_write(struct ssb_device *dev, const void *buffer,
1087d625a29bSMichael Buesch 				size_t count, u16 offset, u8 reg_width)
1088d625a29bSMichael Buesch {
1089d625a29bSMichael Buesch 	struct ssb_bus *bus = dev->bus;
1090d625a29bSMichael Buesch 	void __iomem *addr = bus->mmio + offset;
1091d625a29bSMichael Buesch 
1092d625a29bSMichael Buesch 	if (unlikely(ssb_pci_assert_buspower(bus)))
1093d625a29bSMichael Buesch 		return;
1094d625a29bSMichael Buesch 	if (unlikely(bus->mapped_device != dev)) {
1095d625a29bSMichael Buesch 		if (unlikely(ssb_pci_switch_core(bus, dev)))
1096d625a29bSMichael Buesch 			return;
1097d625a29bSMichael Buesch 	}
1098d625a29bSMichael Buesch 	switch (reg_width) {
1099d625a29bSMichael Buesch 	case sizeof(u8):
1100d625a29bSMichael Buesch 		iowrite8_rep(addr, buffer, count);
1101d625a29bSMichael Buesch 		break;
1102d625a29bSMichael Buesch 	case sizeof(u16):
1103d625a29bSMichael Buesch 		SSB_WARN_ON(count & 1);
1104d625a29bSMichael Buesch 		iowrite16_rep(addr, buffer, count >> 1);
1105d625a29bSMichael Buesch 		break;
1106d625a29bSMichael Buesch 	case sizeof(u32):
1107d625a29bSMichael Buesch 		SSB_WARN_ON(count & 3);
1108d625a29bSMichael Buesch 		iowrite32_rep(addr, buffer, count >> 2);
1109d625a29bSMichael Buesch 		break;
1110d625a29bSMichael Buesch 	default:
1111d625a29bSMichael Buesch 		SSB_WARN_ON(1);
1112d625a29bSMichael Buesch 	}
1113d625a29bSMichael Buesch }
1114d625a29bSMichael Buesch #endif /* CONFIG_SSB_BLOCKIO */
1115d625a29bSMichael Buesch 
111661e115a5SMichael Buesch /* Not "static", as it's used in main.c */
111761e115a5SMichael Buesch const struct ssb_bus_ops ssb_pci_ops = {
1118ffc7689dSMichael Buesch 	.read8		= ssb_pci_read8,
111961e115a5SMichael Buesch 	.read16		= ssb_pci_read16,
112061e115a5SMichael Buesch 	.read32		= ssb_pci_read32,
1121ffc7689dSMichael Buesch 	.write8		= ssb_pci_write8,
112261e115a5SMichael Buesch 	.write16	= ssb_pci_write16,
112361e115a5SMichael Buesch 	.write32	= ssb_pci_write32,
1124d625a29bSMichael Buesch #ifdef CONFIG_SSB_BLOCKIO
1125d625a29bSMichael Buesch 	.block_read	= ssb_pci_block_read,
1126d625a29bSMichael Buesch 	.block_write	= ssb_pci_block_write,
1127d625a29bSMichael Buesch #endif
112861e115a5SMichael Buesch };
112961e115a5SMichael Buesch 
113061e115a5SMichael Buesch static ssize_t ssb_pci_attr_sprom_show(struct device *pcidev,
113161e115a5SMichael Buesch 				       struct device_attribute *attr,
113261e115a5SMichael Buesch 				       char *buf)
113361e115a5SMichael Buesch {
113461e115a5SMichael Buesch 	struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev);
113561e115a5SMichael Buesch 	struct ssb_bus *bus;
113661e115a5SMichael Buesch 
113761e115a5SMichael Buesch 	bus = ssb_pci_dev_to_bus(pdev);
113861e115a5SMichael Buesch 	if (!bus)
1139e7ec2e32SMichael Buesch 		return -ENODEV;
114061e115a5SMichael Buesch 
1141e7ec2e32SMichael Buesch 	return ssb_attr_sprom_show(bus, buf, sprom_do_read);
114261e115a5SMichael Buesch }
114361e115a5SMichael Buesch 
114461e115a5SMichael Buesch static ssize_t ssb_pci_attr_sprom_store(struct device *pcidev,
114561e115a5SMichael Buesch 					struct device_attribute *attr,
114661e115a5SMichael Buesch 					const char *buf, size_t count)
114761e115a5SMichael Buesch {
114861e115a5SMichael Buesch 	struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev);
114961e115a5SMichael Buesch 	struct ssb_bus *bus;
115061e115a5SMichael Buesch 
115161e115a5SMichael Buesch 	bus = ssb_pci_dev_to_bus(pdev);
115261e115a5SMichael Buesch 	if (!bus)
1153e7ec2e32SMichael Buesch 		return -ENODEV;
115461e115a5SMichael Buesch 
1155e7ec2e32SMichael Buesch 	return ssb_attr_sprom_store(bus, buf, count,
1156e7ec2e32SMichael Buesch 				    sprom_check_crc, sprom_do_write);
115761e115a5SMichael Buesch }
115861e115a5SMichael Buesch 
115961e115a5SMichael Buesch static DEVICE_ATTR(ssb_sprom, 0600,
116061e115a5SMichael Buesch 		   ssb_pci_attr_sprom_show,
116161e115a5SMichael Buesch 		   ssb_pci_attr_sprom_store);
116261e115a5SMichael Buesch 
116361e115a5SMichael Buesch void ssb_pci_exit(struct ssb_bus *bus)
116461e115a5SMichael Buesch {
116561e115a5SMichael Buesch 	struct pci_dev *pdev;
116661e115a5SMichael Buesch 
116761e115a5SMichael Buesch 	if (bus->bustype != SSB_BUSTYPE_PCI)
116861e115a5SMichael Buesch 		return;
116961e115a5SMichael Buesch 
117061e115a5SMichael Buesch 	pdev = bus->host_pci;
117161e115a5SMichael Buesch 	device_remove_file(&pdev->dev, &dev_attr_ssb_sprom);
117261e115a5SMichael Buesch }
117361e115a5SMichael Buesch 
117461e115a5SMichael Buesch int ssb_pci_init(struct ssb_bus *bus)
117561e115a5SMichael Buesch {
117661e115a5SMichael Buesch 	struct pci_dev *pdev;
117761e115a5SMichael Buesch 	int err;
117861e115a5SMichael Buesch 
117961e115a5SMichael Buesch 	if (bus->bustype != SSB_BUSTYPE_PCI)
118061e115a5SMichael Buesch 		return 0;
118161e115a5SMichael Buesch 
118261e115a5SMichael Buesch 	pdev = bus->host_pci;
1183e7ec2e32SMichael Buesch 	mutex_init(&bus->sprom_mutex);
118461e115a5SMichael Buesch 	err = device_create_file(&pdev->dev, &dev_attr_ssb_sprom);
118561e115a5SMichael Buesch 	if (err)
118661e115a5SMichael Buesch 		goto out;
118761e115a5SMichael Buesch 
118861e115a5SMichael Buesch out:
118961e115a5SMichael Buesch 	return err;
119061e115a5SMichael Buesch }
1191