xref: /openbmc/linux/drivers/ssb/pci.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
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 */
ssb_pci_switch_coreidx(struct ssb_bus * bus,u8 coreidx)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 
ssb_pci_switch_core(struct ssb_bus * bus,struct ssb_device * dev)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. */
ssb_pci_xtal(struct ssb_bus * bus,u32 what,int turn_on)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 
ssb_crc8(u8 crc,u8 data)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 
sprom_get_mac(char * mac,const u16 * in)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 
ssb_sprom_crc(const u16 * sprom,u16 size)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 
sprom_check_crc(const u16 * sprom,size_t size)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 
sprom_do_read(struct ssb_bus * bus,u16 * sprom)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 
sprom_do_write(struct ssb_bus * bus,const u16 * sprom)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 		msleep(20);
30961e115a5SMichael Buesch 	}
31061e115a5SMichael Buesch 	err = pci_read_config_dword(pdev, SSB_SPROMCTL, &spromctl);
31161e115a5SMichael Buesch 	if (err)
31261e115a5SMichael Buesch 		goto err_ctlreg;
31361e115a5SMichael Buesch 	spromctl &= ~SSB_SPROMCTL_WE;
31461e115a5SMichael Buesch 	err = pci_write_config_dword(pdev, SSB_SPROMCTL, spromctl);
31561e115a5SMichael Buesch 	if (err)
31661e115a5SMichael Buesch 		goto err_ctlreg;
31761e115a5SMichael Buesch 	msleep(500);
318b8b6069cSMichael Büsch 	pr_cont("100%% ]\n");
319b8b6069cSMichael Büsch 	pr_notice("SPROM written\n");
32061e115a5SMichael Buesch 
32161e115a5SMichael Buesch 	return 0;
32261e115a5SMichael Buesch err_ctlreg:
323b8b6069cSMichael Büsch 	pr_err("Could not access SPROM control register.\n");
32461e115a5SMichael Buesch 	return err;
32561e115a5SMichael Buesch }
32661e115a5SMichael Buesch 
sprom_extract_antgain(u8 sprom_revision,const u16 * in,u16 offset,u16 mask,u16 shift)32767d392c0SRafał Miłecki static s8 sprom_extract_antgain(u8 sprom_revision, const u16 *in, u16 offset,
328e861b98dSMichael Buesch 				u16 mask, u16 shift)
329e861b98dSMichael Buesch {
330e861b98dSMichael Buesch 	u16 v;
331e861b98dSMichael Buesch 	u8 gain;
332e861b98dSMichael Buesch 
33367d392c0SRafał Miłecki 	v = in[SPOFF(offset)];
334e861b98dSMichael Buesch 	gain = (v & mask) >> shift;
335e861b98dSMichael Buesch 	if (gain == 0xFF)
336e861b98dSMichael Buesch 		gain = 2; /* If unset use 2dBm */
337e861b98dSMichael Buesch 	if (sprom_revision == 1) {
338e861b98dSMichael Buesch 		/* Convert to Q5.2 */
339e861b98dSMichael Buesch 		gain <<= 2;
340e861b98dSMichael Buesch 	} else {
341e861b98dSMichael Buesch 		/* Q5.2 Fractional part is stored in 0xC0 */
342e861b98dSMichael Buesch 		gain = ((gain & 0xC0) >> 6) | ((gain & 0x3F) << 2);
343e861b98dSMichael Buesch 	}
344e861b98dSMichael Buesch 
345e861b98dSMichael Buesch 	return (s8)gain;
346e861b98dSMichael Buesch }
347e861b98dSMichael Buesch 
sprom_extract_r23(struct ssb_sprom * out,const u16 * in)3487e4235acSHauke Mehrtens static void sprom_extract_r23(struct ssb_sprom *out, const u16 *in)
3497e4235acSHauke Mehrtens {
3507e4235acSHauke Mehrtens 	SPEX(boardflags_hi, SSB_SPROM2_BFLHI, 0xFFFF, 0);
3517e4235acSHauke Mehrtens 	SPEX(opo, SSB_SPROM2_OPO, SSB_SPROM2_OPO_VALUE, 0);
3527e4235acSHauke Mehrtens 	SPEX(pa1lob0, SSB_SPROM2_PA1LOB0, 0xFFFF, 0);
3537e4235acSHauke Mehrtens 	SPEX(pa1lob1, SSB_SPROM2_PA1LOB1, 0xFFFF, 0);
3547e4235acSHauke Mehrtens 	SPEX(pa1lob2, SSB_SPROM2_PA1LOB2, 0xFFFF, 0);
3557e4235acSHauke Mehrtens 	SPEX(pa1hib0, SSB_SPROM2_PA1HIB0, 0xFFFF, 0);
3567e4235acSHauke Mehrtens 	SPEX(pa1hib1, SSB_SPROM2_PA1HIB1, 0xFFFF, 0);
3577e4235acSHauke Mehrtens 	SPEX(pa1hib2, SSB_SPROM2_PA1HIB2, 0xFFFF, 0);
3587e4235acSHauke Mehrtens 	SPEX(maxpwr_ah, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_HI, 0);
3597e4235acSHauke Mehrtens 	SPEX(maxpwr_al, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_LO,
3607e4235acSHauke Mehrtens 	     SSB_SPROM2_MAXP_A_LO_SHIFT);
3617e4235acSHauke Mehrtens }
3627e4235acSHauke Mehrtens 
sprom_extract_r123(struct ssb_sprom * out,const u16 * in)363c272ef44SLarry Finger static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in)
364c272ef44SLarry Finger {
365c272ef44SLarry Finger 	u16 loc[3];
366c272ef44SLarry Finger 
36731ce12fbSLarry Finger 	if (out->revision == 3)			/* rev 3 moved MAC */
368c272ef44SLarry Finger 		loc[0] = SSB_SPROM3_IL0MAC;
36931ce12fbSLarry Finger 	else {
370c272ef44SLarry Finger 		loc[0] = SSB_SPROM1_IL0MAC;
371c272ef44SLarry Finger 		loc[1] = SSB_SPROM1_ET0MAC;
372c272ef44SLarry Finger 		loc[2] = SSB_SPROM1_ET1MAC;
373c272ef44SLarry Finger 	}
374e5652756SJoe Perches 	sprom_get_mac(out->il0mac, &in[SPOFF(loc[0])]);
37531ce12fbSLarry Finger 	if (out->revision < 3) { 	/* only rev 1-2 have et0, et1 */
376e5652756SJoe Perches 		sprom_get_mac(out->et0mac, &in[SPOFF(loc[1])]);
377e5652756SJoe Perches 		sprom_get_mac(out->et1mac, &in[SPOFF(loc[2])]);
37831ce12fbSLarry Finger 	}
379c272ef44SLarry Finger 	SPEX(et0phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0A, 0);
380c272ef44SLarry Finger 	SPEX(et1phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1A,
381c272ef44SLarry Finger 	     SSB_SPROM1_ETHPHY_ET1A_SHIFT);
382e861b98dSMichael Buesch 	SPEX(et0mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0M, 14);
383e861b98dSMichael Buesch 	SPEX(et1mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1M, 15);
384e861b98dSMichael Buesch 	SPEX(board_rev, SSB_SPROM1_BINF, SSB_SPROM1_BINF_BREV, 0);
3853623b266SRafał Miłecki 	SPEX(board_type, SSB_SPROM1_SPID, 0xFFFF, 0);
386bf7d420bSHauke Mehrtens 	if (out->revision == 1)
387c272ef44SLarry Finger 		SPEX(country_code, SSB_SPROM1_BINF, SSB_SPROM1_BINF_CCODE,
388c272ef44SLarry Finger 		     SSB_SPROM1_BINF_CCODE_SHIFT);
389e861b98dSMichael Buesch 	SPEX(ant_available_a, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTA,
390e861b98dSMichael Buesch 	     SSB_SPROM1_BINF_ANTA_SHIFT);
391e861b98dSMichael Buesch 	SPEX(ant_available_bg, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTBG,
392e861b98dSMichael Buesch 	     SSB_SPROM1_BINF_ANTBG_SHIFT);
393c272ef44SLarry Finger 	SPEX(pa0b0, SSB_SPROM1_PA0B0, 0xFFFF, 0);
394c272ef44SLarry Finger 	SPEX(pa0b1, SSB_SPROM1_PA0B1, 0xFFFF, 0);
395c272ef44SLarry Finger 	SPEX(pa0b2, SSB_SPROM1_PA0B2, 0xFFFF, 0);
396c272ef44SLarry Finger 	SPEX(pa1b0, SSB_SPROM1_PA1B0, 0xFFFF, 0);
397c272ef44SLarry Finger 	SPEX(pa1b1, SSB_SPROM1_PA1B1, 0xFFFF, 0);
398c272ef44SLarry Finger 	SPEX(pa1b2, SSB_SPROM1_PA1B2, 0xFFFF, 0);
399c272ef44SLarry Finger 	SPEX(gpio0, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P0, 0);
400c272ef44SLarry Finger 	SPEX(gpio1, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P1,
401c272ef44SLarry Finger 	     SSB_SPROM1_GPIOA_P1_SHIFT);
402c272ef44SLarry Finger 	SPEX(gpio2, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P2, 0);
403c272ef44SLarry Finger 	SPEX(gpio3, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P3,
404c272ef44SLarry Finger 	     SSB_SPROM1_GPIOB_P3_SHIFT);
405c272ef44SLarry Finger 	SPEX(maxpwr_a, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_A,
406c272ef44SLarry Finger 	     SSB_SPROM1_MAXPWR_A_SHIFT);
407c272ef44SLarry Finger 	SPEX(maxpwr_bg, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_BG, 0);
408c272ef44SLarry Finger 	SPEX(itssi_a, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_A,
409c272ef44SLarry Finger 	     SSB_SPROM1_ITSSI_A_SHIFT);
410c272ef44SLarry Finger 	SPEX(itssi_bg, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_BG, 0);
411c272ef44SLarry Finger 	SPEX(boardflags_lo, SSB_SPROM1_BFLLO, 0xFFFF, 0);
4127e4235acSHauke Mehrtens 
413bf7d420bSHauke Mehrtens 	SPEX(alpha2[0], SSB_SPROM1_CCODE, 0xff00, 8);
414bf7d420bSHauke Mehrtens 	SPEX(alpha2[1], SSB_SPROM1_CCODE, 0x00ff, 0);
415e861b98dSMichael Buesch 
416e861b98dSMichael Buesch 	/* Extract the antenna gain values. */
41767d392c0SRafał Miłecki 	out->antenna_gain.a0 = sprom_extract_antgain(out->revision, in,
41867d392c0SRafał Miłecki 						     SSB_SPROM1_AGAIN,
419e861b98dSMichael Buesch 						     SSB_SPROM1_AGAIN_BG,
420c272ef44SLarry Finger 						     SSB_SPROM1_AGAIN_BG_SHIFT);
42167d392c0SRafał Miłecki 	out->antenna_gain.a1 = sprom_extract_antgain(out->revision, in,
42267d392c0SRafał Miłecki 						     SSB_SPROM1_AGAIN,
423e861b98dSMichael Buesch 						     SSB_SPROM1_AGAIN_A,
424e861b98dSMichael Buesch 						     SSB_SPROM1_AGAIN_A_SHIFT);
4257e4235acSHauke Mehrtens 	if (out->revision >= 2)
4267e4235acSHauke Mehrtens 		sprom_extract_r23(out, in);
427c272ef44SLarry Finger }
428c272ef44SLarry Finger 
429172c69a4SRafał Miłecki /* Revs 4 5 and 8 have partially shared layout */
sprom_extract_r458(struct ssb_sprom * out,const u16 * in)430172c69a4SRafał Miłecki static void sprom_extract_r458(struct ssb_sprom *out, const u16 *in)
431172c69a4SRafał Miłecki {
432172c69a4SRafał Miłecki 	SPEX(txpid2g[0], SSB_SPROM4_TXPID2G01,
433172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID2G0, SSB_SPROM4_TXPID2G0_SHIFT);
434172c69a4SRafał Miłecki 	SPEX(txpid2g[1], SSB_SPROM4_TXPID2G01,
435172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID2G1, SSB_SPROM4_TXPID2G1_SHIFT);
436172c69a4SRafał Miłecki 	SPEX(txpid2g[2], SSB_SPROM4_TXPID2G23,
437172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID2G2, SSB_SPROM4_TXPID2G2_SHIFT);
438172c69a4SRafał Miłecki 	SPEX(txpid2g[3], SSB_SPROM4_TXPID2G23,
439172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID2G3, SSB_SPROM4_TXPID2G3_SHIFT);
440172c69a4SRafał Miłecki 
441172c69a4SRafał Miłecki 	SPEX(txpid5gl[0], SSB_SPROM4_TXPID5GL01,
442172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID5GL0, SSB_SPROM4_TXPID5GL0_SHIFT);
443172c69a4SRafał Miłecki 	SPEX(txpid5gl[1], SSB_SPROM4_TXPID5GL01,
444172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID5GL1, SSB_SPROM4_TXPID5GL1_SHIFT);
445172c69a4SRafał Miłecki 	SPEX(txpid5gl[2], SSB_SPROM4_TXPID5GL23,
446172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID5GL2, SSB_SPROM4_TXPID5GL2_SHIFT);
447172c69a4SRafał Miłecki 	SPEX(txpid5gl[3], SSB_SPROM4_TXPID5GL23,
448172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID5GL3, SSB_SPROM4_TXPID5GL3_SHIFT);
449172c69a4SRafał Miłecki 
450172c69a4SRafał Miłecki 	SPEX(txpid5g[0], SSB_SPROM4_TXPID5G01,
451172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID5G0, SSB_SPROM4_TXPID5G0_SHIFT);
452172c69a4SRafał Miłecki 	SPEX(txpid5g[1], SSB_SPROM4_TXPID5G01,
453172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID5G1, SSB_SPROM4_TXPID5G1_SHIFT);
454172c69a4SRafał Miłecki 	SPEX(txpid5g[2], SSB_SPROM4_TXPID5G23,
455172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID5G2, SSB_SPROM4_TXPID5G2_SHIFT);
456172c69a4SRafał Miłecki 	SPEX(txpid5g[3], SSB_SPROM4_TXPID5G23,
457172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID5G3, SSB_SPROM4_TXPID5G3_SHIFT);
458172c69a4SRafał Miłecki 
459172c69a4SRafał Miłecki 	SPEX(txpid5gh[0], SSB_SPROM4_TXPID5GH01,
460172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID5GH0, SSB_SPROM4_TXPID5GH0_SHIFT);
461172c69a4SRafał Miłecki 	SPEX(txpid5gh[1], SSB_SPROM4_TXPID5GH01,
462172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID5GH1, SSB_SPROM4_TXPID5GH1_SHIFT);
463172c69a4SRafał Miłecki 	SPEX(txpid5gh[2], SSB_SPROM4_TXPID5GH23,
464172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID5GH2, SSB_SPROM4_TXPID5GH2_SHIFT);
465172c69a4SRafał Miłecki 	SPEX(txpid5gh[3], SSB_SPROM4_TXPID5GH23,
466172c69a4SRafał Miłecki 	     SSB_SPROM4_TXPID5GH3, SSB_SPROM4_TXPID5GH3_SHIFT);
467172c69a4SRafał Miłecki }
468172c69a4SRafał Miłecki 
sprom_extract_r45(struct ssb_sprom * out,const u16 * in)469095f695cSLarry Finger static void sprom_extract_r45(struct ssb_sprom *out, const u16 *in)
47061e115a5SMichael Buesch {
4716ad59343SRafał Miłecki 	static const u16 pwr_info_offset[] = {
4726ad59343SRafał Miłecki 		SSB_SPROM4_PWR_INFO_CORE0, SSB_SPROM4_PWR_INFO_CORE1,
4736ad59343SRafał Miłecki 		SSB_SPROM4_PWR_INFO_CORE2, SSB_SPROM4_PWR_INFO_CORE3
4746ad59343SRafał Miłecki 	};
475095f695cSLarry Finger 	u16 il0mac_offset;
4766ad59343SRafał Miłecki 	int i;
4776ad59343SRafał Miłecki 
4786ad59343SRafał Miłecki 	BUILD_BUG_ON(ARRAY_SIZE(pwr_info_offset) !=
4796ad59343SRafał Miłecki 		     ARRAY_SIZE(out->core_pwr_info));
48061e115a5SMichael Buesch 
481095f695cSLarry Finger 	if (out->revision == 4)
482095f695cSLarry Finger 		il0mac_offset = SSB_SPROM4_IL0MAC;
483095f695cSLarry Finger 	else
484095f695cSLarry Finger 		il0mac_offset = SSB_SPROM5_IL0MAC;
485e5652756SJoe Perches 
486e5652756SJoe Perches 	sprom_get_mac(out->il0mac, &in[SPOFF(il0mac_offset)]);
487e5652756SJoe Perches 
488c272ef44SLarry Finger 	SPEX(et0phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET0A, 0);
489c272ef44SLarry Finger 	SPEX(et1phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET1A,
490c272ef44SLarry Finger 	     SSB_SPROM4_ETHPHY_ET1A_SHIFT);
491673335c8SHauke Mehrtens 	SPEX(board_rev, SSB_SPROM4_BOARDREV, 0xFFFF, 0);
4923623b266SRafał Miłecki 	SPEX(board_type, SSB_SPROM1_SPID, 0xFFFF, 0);
493095f695cSLarry Finger 	if (out->revision == 4) {
494bf7d420bSHauke Mehrtens 		SPEX(alpha2[0], SSB_SPROM4_CCODE, 0xff00, 8);
495bf7d420bSHauke Mehrtens 		SPEX(alpha2[1], SSB_SPROM4_CCODE, 0x00ff, 0);
496c272ef44SLarry Finger 		SPEX(boardflags_lo, SSB_SPROM4_BFLLO, 0xFFFF, 0);
497af4b7450SMichael Buesch 		SPEX(boardflags_hi, SSB_SPROM4_BFLHI, 0xFFFF, 0);
4986d1d4ea4SRafał Miłecki 		SPEX(boardflags2_lo, SSB_SPROM4_BFL2LO, 0xFFFF, 0);
4996d1d4ea4SRafał Miłecki 		SPEX(boardflags2_hi, SSB_SPROM4_BFL2HI, 0xFFFF, 0);
500095f695cSLarry Finger 	} else {
501bf7d420bSHauke Mehrtens 		SPEX(alpha2[0], SSB_SPROM5_CCODE, 0xff00, 8);
502bf7d420bSHauke Mehrtens 		SPEX(alpha2[1], SSB_SPROM5_CCODE, 0x00ff, 0);
503095f695cSLarry Finger 		SPEX(boardflags_lo, SSB_SPROM5_BFLLO, 0xFFFF, 0);
504095f695cSLarry Finger 		SPEX(boardflags_hi, SSB_SPROM5_BFLHI, 0xFFFF, 0);
5056d1d4ea4SRafał Miłecki 		SPEX(boardflags2_lo, SSB_SPROM5_BFL2LO, 0xFFFF, 0);
5066d1d4ea4SRafał Miłecki 		SPEX(boardflags2_hi, SSB_SPROM5_BFL2HI, 0xFFFF, 0);
507095f695cSLarry Finger 	}
508e861b98dSMichael Buesch 	SPEX(ant_available_a, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_A,
509e861b98dSMichael Buesch 	     SSB_SPROM4_ANTAVAIL_A_SHIFT);
510e861b98dSMichael Buesch 	SPEX(ant_available_bg, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_BG,
511e861b98dSMichael Buesch 	     SSB_SPROM4_ANTAVAIL_BG_SHIFT);
512d3c319f9SLarry Finger 	SPEX(maxpwr_bg, SSB_SPROM4_MAXP_BG, SSB_SPROM4_MAXP_BG_MASK, 0);
513d3c319f9SLarry Finger 	SPEX(itssi_bg, SSB_SPROM4_MAXP_BG, SSB_SPROM4_ITSSI_BG,
514d3c319f9SLarry Finger 	     SSB_SPROM4_ITSSI_BG_SHIFT);
515d3c319f9SLarry Finger 	SPEX(maxpwr_a, SSB_SPROM4_MAXP_A, SSB_SPROM4_MAXP_A_MASK, 0);
516d3c319f9SLarry Finger 	SPEX(itssi_a, SSB_SPROM4_MAXP_A, SSB_SPROM4_ITSSI_A,
517d3c319f9SLarry Finger 	     SSB_SPROM4_ITSSI_A_SHIFT);
518095f695cSLarry Finger 	if (out->revision == 4) {
519d3c319f9SLarry Finger 		SPEX(gpio0, SSB_SPROM4_GPIOA, SSB_SPROM4_GPIOA_P0, 0);
520d3c319f9SLarry Finger 		SPEX(gpio1, SSB_SPROM4_GPIOA, SSB_SPROM4_GPIOA_P1,
521d3c319f9SLarry Finger 		     SSB_SPROM4_GPIOA_P1_SHIFT);
522d3c319f9SLarry Finger 		SPEX(gpio2, SSB_SPROM4_GPIOB, SSB_SPROM4_GPIOB_P2, 0);
523d3c319f9SLarry Finger 		SPEX(gpio3, SSB_SPROM4_GPIOB, SSB_SPROM4_GPIOB_P3,
524d3c319f9SLarry Finger 		     SSB_SPROM4_GPIOB_P3_SHIFT);
525095f695cSLarry Finger 	} else {
526095f695cSLarry Finger 		SPEX(gpio0, SSB_SPROM5_GPIOA, SSB_SPROM5_GPIOA_P0, 0);
527095f695cSLarry Finger 		SPEX(gpio1, SSB_SPROM5_GPIOA, SSB_SPROM5_GPIOA_P1,
528095f695cSLarry Finger 		     SSB_SPROM5_GPIOA_P1_SHIFT);
529095f695cSLarry Finger 		SPEX(gpio2, SSB_SPROM5_GPIOB, SSB_SPROM5_GPIOB_P2, 0);
530095f695cSLarry Finger 		SPEX(gpio3, SSB_SPROM5_GPIOB, SSB_SPROM5_GPIOB_P3,
531095f695cSLarry Finger 		     SSB_SPROM5_GPIOB_P3_SHIFT);
532095f695cSLarry Finger 	}
533e861b98dSMichael Buesch 
534e861b98dSMichael Buesch 	/* Extract the antenna gain values. */
5356daf4321SRafał Miłecki 	out->antenna_gain.a0 = sprom_extract_antgain(out->revision, in,
5366daf4321SRafał Miłecki 						     SSB_SPROM4_AGAIN01,
5376daf4321SRafał Miłecki 						     SSB_SPROM4_AGAIN0,
5386daf4321SRafał Miłecki 						     SSB_SPROM4_AGAIN0_SHIFT);
5396daf4321SRafał Miłecki 	out->antenna_gain.a1 = sprom_extract_antgain(out->revision, in,
5406daf4321SRafał Miłecki 						     SSB_SPROM4_AGAIN01,
5416daf4321SRafał Miłecki 						     SSB_SPROM4_AGAIN1,
5426daf4321SRafał Miłecki 						     SSB_SPROM4_AGAIN1_SHIFT);
5436daf4321SRafał Miłecki 	out->antenna_gain.a2 = sprom_extract_antgain(out->revision, in,
5446daf4321SRafał Miłecki 						     SSB_SPROM4_AGAIN23,
5456daf4321SRafał Miłecki 						     SSB_SPROM4_AGAIN2,
5466daf4321SRafał Miłecki 						     SSB_SPROM4_AGAIN2_SHIFT);
5476daf4321SRafał Miłecki 	out->antenna_gain.a3 = sprom_extract_antgain(out->revision, in,
5486daf4321SRafał Miłecki 						     SSB_SPROM4_AGAIN23,
5496daf4321SRafał Miłecki 						     SSB_SPROM4_AGAIN3,
5506daf4321SRafał Miłecki 						     SSB_SPROM4_AGAIN3_SHIFT);
551e861b98dSMichael Buesch 
5526ad59343SRafał Miłecki 	/* Extract cores power info info */
5536ad59343SRafał Miłecki 	for (i = 0; i < ARRAY_SIZE(pwr_info_offset); i++) {
5546ad59343SRafał Miłecki 		u16 o = pwr_info_offset[i];
5556ad59343SRafał Miłecki 
5566ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].itssi_2g, o + SSB_SPROM4_2G_MAXP_ITSSI,
5576ad59343SRafał Miłecki 			SSB_SPROM4_2G_ITSSI, SSB_SPROM4_2G_ITSSI_SHIFT);
5586ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].maxpwr_2g, o + SSB_SPROM4_2G_MAXP_ITSSI,
5596ad59343SRafał Miłecki 			SSB_SPROM4_2G_MAXP, 0);
5606ad59343SRafał Miłecki 
5616ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].pa_2g[0], o + SSB_SPROM4_2G_PA_0, ~0, 0);
5626ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].pa_2g[1], o + SSB_SPROM4_2G_PA_1, ~0, 0);
5636ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].pa_2g[2], o + SSB_SPROM4_2G_PA_2, ~0, 0);
5646ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].pa_2g[3], o + SSB_SPROM4_2G_PA_3, ~0, 0);
5656ad59343SRafał Miłecki 
5666ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].itssi_5g, o + SSB_SPROM4_5G_MAXP_ITSSI,
5676ad59343SRafał Miłecki 			SSB_SPROM4_5G_ITSSI, SSB_SPROM4_5G_ITSSI_SHIFT);
5686ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].maxpwr_5g, o + SSB_SPROM4_5G_MAXP_ITSSI,
5696ad59343SRafał Miłecki 			SSB_SPROM4_5G_MAXP, 0);
5706ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].maxpwr_5gh, o + SSB_SPROM4_5GHL_MAXP,
5716ad59343SRafał Miłecki 			SSB_SPROM4_5GH_MAXP, 0);
5726ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].maxpwr_5gl, o + SSB_SPROM4_5GHL_MAXP,
5736ad59343SRafał Miłecki 			SSB_SPROM4_5GL_MAXP, SSB_SPROM4_5GL_MAXP_SHIFT);
5746ad59343SRafał Miłecki 
5756ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gl[0], o + SSB_SPROM4_5GL_PA_0, ~0, 0);
5766ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gl[1], o + SSB_SPROM4_5GL_PA_1, ~0, 0);
5776ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gl[2], o + SSB_SPROM4_5GL_PA_2, ~0, 0);
5786ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gl[3], o + SSB_SPROM4_5GL_PA_3, ~0, 0);
5796ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5g[0], o + SSB_SPROM4_5G_PA_0, ~0, 0);
5806ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5g[1], o + SSB_SPROM4_5G_PA_1, ~0, 0);
5816ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5g[2], o + SSB_SPROM4_5G_PA_2, ~0, 0);
5826ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5g[3], o + SSB_SPROM4_5G_PA_3, ~0, 0);
5836ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gh[0], o + SSB_SPROM4_5GH_PA_0, ~0, 0);
5846ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gh[1], o + SSB_SPROM4_5GH_PA_1, ~0, 0);
5856ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gh[2], o + SSB_SPROM4_5GH_PA_2, ~0, 0);
5866ad59343SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gh[3], o + SSB_SPROM4_5GH_PA_3, ~0, 0);
5876ad59343SRafał Miłecki 	}
5886ad59343SRafał Miłecki 
589172c69a4SRafał Miłecki 	sprom_extract_r458(out, in);
590172c69a4SRafał Miłecki 
591c272ef44SLarry Finger 	/* TODO - get remaining rev 4 stuff needed */
59261e115a5SMichael Buesch }
59361e115a5SMichael Buesch 
sprom_extract_r8(struct ssb_sprom * out,const u16 * in)5946b1c7c67SMichael Buesch static void sprom_extract_r8(struct ssb_sprom *out, const u16 *in)
5956b1c7c67SMichael Buesch {
5966b1c7c67SMichael Buesch 	int i;
597e5652756SJoe Perches 	u16 o;
598d3bb2686SColin Ian King 	static const u16 pwr_info_offset[] = {
599b0f70292SRafał Miłecki 		SSB_SROM8_PWR_INFO_CORE0, SSB_SROM8_PWR_INFO_CORE1,
600b0f70292SRafał Miłecki 		SSB_SROM8_PWR_INFO_CORE2, SSB_SROM8_PWR_INFO_CORE3
601b0f70292SRafał Miłecki 	};
602b0f70292SRafał Miłecki 	BUILD_BUG_ON(ARRAY_SIZE(pwr_info_offset) !=
603b0f70292SRafał Miłecki 			ARRAY_SIZE(out->core_pwr_info));
6046b1c7c67SMichael Buesch 
6056b1c7c67SMichael Buesch 	/* extract the MAC address */
606e5652756SJoe Perches 	sprom_get_mac(out->il0mac, &in[SPOFF(SSB_SPROM8_IL0MAC)]);
607e5652756SJoe Perches 
608673335c8SHauke Mehrtens 	SPEX(board_rev, SSB_SPROM8_BOARDREV, 0xFFFF, 0);
6093623b266SRafał Miłecki 	SPEX(board_type, SSB_SPROM1_SPID, 0xFFFF, 0);
610bf7d420bSHauke Mehrtens 	SPEX(alpha2[0], SSB_SPROM8_CCODE, 0xff00, 8);
611bf7d420bSHauke Mehrtens 	SPEX(alpha2[1], SSB_SPROM8_CCODE, 0x00ff, 0);
6126b1c7c67SMichael Buesch 	SPEX(boardflags_lo, SSB_SPROM8_BFLLO, 0xFFFF, 0);
6136b1c7c67SMichael Buesch 	SPEX(boardflags_hi, SSB_SPROM8_BFLHI, 0xFFFF, 0);
614f679056bSGábor Stefanik 	SPEX(boardflags2_lo, SSB_SPROM8_BFL2LO, 0xFFFF, 0);
615f679056bSGábor Stefanik 	SPEX(boardflags2_hi, SSB_SPROM8_BFL2HI, 0xFFFF, 0);
6166b1c7c67SMichael Buesch 	SPEX(ant_available_a, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_A,
6176b1c7c67SMichael Buesch 	     SSB_SPROM8_ANTAVAIL_A_SHIFT);
6186b1c7c67SMichael Buesch 	SPEX(ant_available_bg, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_BG,
6196b1c7c67SMichael Buesch 	     SSB_SPROM8_ANTAVAIL_BG_SHIFT);
6206b1c7c67SMichael Buesch 	SPEX(maxpwr_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_MAXP_BG_MASK, 0);
6216b1c7c67SMichael Buesch 	SPEX(itssi_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_ITSSI_BG,
6226b1c7c67SMichael Buesch 	     SSB_SPROM8_ITSSI_BG_SHIFT);
6236b1c7c67SMichael Buesch 	SPEX(maxpwr_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_MAXP_A_MASK, 0);
6246b1c7c67SMichael Buesch 	SPEX(itssi_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_ITSSI_A,
6256b1c7c67SMichael Buesch 	     SSB_SPROM8_ITSSI_A_SHIFT);
626f679056bSGábor Stefanik 	SPEX(maxpwr_ah, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AH_MASK, 0);
627f679056bSGábor Stefanik 	SPEX(maxpwr_al, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AL_MASK,
628f679056bSGábor Stefanik 	     SSB_SPROM8_MAXP_AL_SHIFT);
6296b1c7c67SMichael Buesch 	SPEX(gpio0, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P0, 0);
6306b1c7c67SMichael Buesch 	SPEX(gpio1, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P1,
6316b1c7c67SMichael Buesch 	     SSB_SPROM8_GPIOA_P1_SHIFT);
6326b1c7c67SMichael Buesch 	SPEX(gpio2, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P2, 0);
6336b1c7c67SMichael Buesch 	SPEX(gpio3, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P3,
6346b1c7c67SMichael Buesch 	     SSB_SPROM8_GPIOB_P3_SHIFT);
635f679056bSGábor Stefanik 	SPEX(tri2g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI2G, 0);
636f679056bSGábor Stefanik 	SPEX(tri5g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI5G,
637f679056bSGábor Stefanik 	     SSB_SPROM8_TRI5G_SHIFT);
638f679056bSGábor Stefanik 	SPEX(tri5gl, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GL, 0);
639f679056bSGábor Stefanik 	SPEX(tri5gh, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GH,
640f679056bSGábor Stefanik 	     SSB_SPROM8_TRI5GH_SHIFT);
641f679056bSGábor Stefanik 	SPEX(rxpo2g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO2G, 0);
642f679056bSGábor Stefanik 	SPEX(rxpo5g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO5G,
643f679056bSGábor Stefanik 	     SSB_SPROM8_RXPO5G_SHIFT);
644f679056bSGábor Stefanik 	SPEX(rssismf2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMF2G, 0);
645f679056bSGábor Stefanik 	SPEX(rssismc2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMC2G,
646f679056bSGábor Stefanik 	     SSB_SPROM8_RSSISMC2G_SHIFT);
647f679056bSGábor Stefanik 	SPEX(rssisav2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISAV2G,
648f679056bSGábor Stefanik 	     SSB_SPROM8_RSSISAV2G_SHIFT);
649f679056bSGábor Stefanik 	SPEX(bxa2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_BXA2G,
650f679056bSGábor Stefanik 	     SSB_SPROM8_BXA2G_SHIFT);
651f679056bSGábor Stefanik 	SPEX(rssismf5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMF5G, 0);
652f679056bSGábor Stefanik 	SPEX(rssismc5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMC5G,
653f679056bSGábor Stefanik 	     SSB_SPROM8_RSSISMC5G_SHIFT);
654f679056bSGábor Stefanik 	SPEX(rssisav5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISAV5G,
655f679056bSGábor Stefanik 	     SSB_SPROM8_RSSISAV5G_SHIFT);
656f679056bSGábor Stefanik 	SPEX(bxa5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_BXA5G,
657f679056bSGábor Stefanik 	     SSB_SPROM8_BXA5G_SHIFT);
658f679056bSGábor Stefanik 	SPEX(pa0b0, SSB_SPROM8_PA0B0, 0xFFFF, 0);
659f679056bSGábor Stefanik 	SPEX(pa0b1, SSB_SPROM8_PA0B1, 0xFFFF, 0);
660f679056bSGábor Stefanik 	SPEX(pa0b2, SSB_SPROM8_PA0B2, 0xFFFF, 0);
661f679056bSGábor Stefanik 	SPEX(pa1b0, SSB_SPROM8_PA1B0, 0xFFFF, 0);
662f679056bSGábor Stefanik 	SPEX(pa1b1, SSB_SPROM8_PA1B1, 0xFFFF, 0);
663f679056bSGábor Stefanik 	SPEX(pa1b2, SSB_SPROM8_PA1B2, 0xFFFF, 0);
664f679056bSGábor Stefanik 	SPEX(pa1lob0, SSB_SPROM8_PA1LOB0, 0xFFFF, 0);
665f679056bSGábor Stefanik 	SPEX(pa1lob1, SSB_SPROM8_PA1LOB1, 0xFFFF, 0);
666f679056bSGábor Stefanik 	SPEX(pa1lob2, SSB_SPROM8_PA1LOB2, 0xFFFF, 0);
667f679056bSGábor Stefanik 	SPEX(pa1hib0, SSB_SPROM8_PA1HIB0, 0xFFFF, 0);
668f679056bSGábor Stefanik 	SPEX(pa1hib1, SSB_SPROM8_PA1HIB1, 0xFFFF, 0);
669f679056bSGábor Stefanik 	SPEX(pa1hib2, SSB_SPROM8_PA1HIB2, 0xFFFF, 0);
670f679056bSGábor Stefanik 	SPEX(cck2gpo, SSB_SPROM8_CCK2GPO, 0xFFFF, 0);
671f679056bSGábor Stefanik 	SPEX32(ofdm2gpo, SSB_SPROM8_OFDM2GPO, 0xFFFFFFFF, 0);
672f679056bSGábor Stefanik 	SPEX32(ofdm5glpo, SSB_SPROM8_OFDM5GLPO, 0xFFFFFFFF, 0);
673f679056bSGábor Stefanik 	SPEX32(ofdm5gpo, SSB_SPROM8_OFDM5GPO, 0xFFFFFFFF, 0);
674f679056bSGábor Stefanik 	SPEX32(ofdm5ghpo, SSB_SPROM8_OFDM5GHPO, 0xFFFFFFFF, 0);
6756b1c7c67SMichael Buesch 
6766b1c7c67SMichael Buesch 	/* Extract the antenna gain values. */
6776daf4321SRafał Miłecki 	out->antenna_gain.a0 = sprom_extract_antgain(out->revision, in,
6786daf4321SRafał Miłecki 						     SSB_SPROM8_AGAIN01,
6796daf4321SRafał Miłecki 						     SSB_SPROM8_AGAIN0,
6806daf4321SRafał Miłecki 						     SSB_SPROM8_AGAIN0_SHIFT);
6816daf4321SRafał Miłecki 	out->antenna_gain.a1 = sprom_extract_antgain(out->revision, in,
6826daf4321SRafał Miłecki 						     SSB_SPROM8_AGAIN01,
6836daf4321SRafał Miłecki 						     SSB_SPROM8_AGAIN1,
6846daf4321SRafał Miłecki 						     SSB_SPROM8_AGAIN1_SHIFT);
6856daf4321SRafał Miłecki 	out->antenna_gain.a2 = sprom_extract_antgain(out->revision, in,
6866daf4321SRafał Miłecki 						     SSB_SPROM8_AGAIN23,
6876daf4321SRafał Miłecki 						     SSB_SPROM8_AGAIN2,
6886daf4321SRafał Miłecki 						     SSB_SPROM8_AGAIN2_SHIFT);
6896daf4321SRafał Miłecki 	out->antenna_gain.a3 = sprom_extract_antgain(out->revision, in,
6906daf4321SRafał Miłecki 						     SSB_SPROM8_AGAIN23,
6916daf4321SRafał Miłecki 						     SSB_SPROM8_AGAIN3,
6926daf4321SRafał Miłecki 						     SSB_SPROM8_AGAIN3_SHIFT);
6936b1c7c67SMichael Buesch 
694b0f70292SRafał Miłecki 	/* Extract cores power info info */
695b0f70292SRafał Miłecki 	for (i = 0; i < ARRAY_SIZE(pwr_info_offset); i++) {
696b0f70292SRafał Miłecki 		o = pwr_info_offset[i];
697b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].itssi_2g, o + SSB_SROM8_2G_MAXP_ITSSI,
698b0f70292SRafał Miłecki 			SSB_SPROM8_2G_ITSSI, SSB_SPROM8_2G_ITSSI_SHIFT);
699b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].maxpwr_2g, o + SSB_SROM8_2G_MAXP_ITSSI,
700b0f70292SRafał Miłecki 			SSB_SPROM8_2G_MAXP, 0);
701b0f70292SRafał Miłecki 
702b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].pa_2g[0], o + SSB_SROM8_2G_PA_0, ~0, 0);
703b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].pa_2g[1], o + SSB_SROM8_2G_PA_1, ~0, 0);
704b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].pa_2g[2], o + SSB_SROM8_2G_PA_2, ~0, 0);
705b0f70292SRafał Miłecki 
706b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].itssi_5g, o + SSB_SROM8_5G_MAXP_ITSSI,
707b0f70292SRafał Miłecki 			SSB_SPROM8_5G_ITSSI, SSB_SPROM8_5G_ITSSI_SHIFT);
708b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].maxpwr_5g, o + SSB_SROM8_5G_MAXP_ITSSI,
709b0f70292SRafał Miłecki 			SSB_SPROM8_5G_MAXP, 0);
710b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].maxpwr_5gh, o + SSB_SPROM8_5GHL_MAXP,
711b0f70292SRafał Miłecki 			SSB_SPROM8_5GH_MAXP, 0);
712b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].maxpwr_5gl, o + SSB_SPROM8_5GHL_MAXP,
713b0f70292SRafał Miłecki 			SSB_SPROM8_5GL_MAXP, SSB_SPROM8_5GL_MAXP_SHIFT);
714b0f70292SRafał Miłecki 
715b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gl[0], o + SSB_SROM8_5GL_PA_0, ~0, 0);
716b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gl[1], o + SSB_SROM8_5GL_PA_1, ~0, 0);
717b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gl[2], o + SSB_SROM8_5GL_PA_2, ~0, 0);
718b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5g[0], o + SSB_SROM8_5G_PA_0, ~0, 0);
719b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5g[1], o + SSB_SROM8_5G_PA_1, ~0, 0);
720b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5g[2], o + SSB_SROM8_5G_PA_2, ~0, 0);
721b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gh[0], o + SSB_SROM8_5GH_PA_0, ~0, 0);
722b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gh[1], o + SSB_SROM8_5GH_PA_1, ~0, 0);
723b0f70292SRafał Miłecki 		SPEX(core_pwr_info[i].pa_5gh[2], o + SSB_SROM8_5GH_PA_2, ~0, 0);
724b0f70292SRafał Miłecki 	}
725b0f70292SRafał Miłecki 
7268a5ac6ecSRafał Miłecki 	/* Extract FEM info */
7278a5ac6ecSRafał Miłecki 	SPEX(fem.ghz2.tssipos, SSB_SPROM8_FEM2G,
7288a5ac6ecSRafał Miłecki 		SSB_SROM8_FEM_TSSIPOS, SSB_SROM8_FEM_TSSIPOS_SHIFT);
7298a5ac6ecSRafał Miłecki 	SPEX(fem.ghz2.extpa_gain, SSB_SPROM8_FEM2G,
7308a5ac6ecSRafał Miłecki 		SSB_SROM8_FEM_EXTPA_GAIN, SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
7318a5ac6ecSRafał Miłecki 	SPEX(fem.ghz2.pdet_range, SSB_SPROM8_FEM2G,
7328a5ac6ecSRafał Miłecki 		SSB_SROM8_FEM_PDET_RANGE, SSB_SROM8_FEM_PDET_RANGE_SHIFT);
7338a5ac6ecSRafał Miłecki 	SPEX(fem.ghz2.tr_iso, SSB_SPROM8_FEM2G,
7348a5ac6ecSRafał Miłecki 		SSB_SROM8_FEM_TR_ISO, SSB_SROM8_FEM_TR_ISO_SHIFT);
7358a5ac6ecSRafał Miłecki 	SPEX(fem.ghz2.antswlut, SSB_SPROM8_FEM2G,
7368a5ac6ecSRafał Miłecki 		SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT);
7378a5ac6ecSRafał Miłecki 
7388a5ac6ecSRafał Miłecki 	SPEX(fem.ghz5.tssipos, SSB_SPROM8_FEM5G,
7398a5ac6ecSRafał Miłecki 		SSB_SROM8_FEM_TSSIPOS, SSB_SROM8_FEM_TSSIPOS_SHIFT);
7408a5ac6ecSRafał Miłecki 	SPEX(fem.ghz5.extpa_gain, SSB_SPROM8_FEM5G,
7418a5ac6ecSRafał Miłecki 		SSB_SROM8_FEM_EXTPA_GAIN, SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
7428a5ac6ecSRafał Miłecki 	SPEX(fem.ghz5.pdet_range, SSB_SPROM8_FEM5G,
7438a5ac6ecSRafał Miłecki 		SSB_SROM8_FEM_PDET_RANGE, SSB_SROM8_FEM_PDET_RANGE_SHIFT);
7448a5ac6ecSRafał Miłecki 	SPEX(fem.ghz5.tr_iso, SSB_SPROM8_FEM5G,
7458a5ac6ecSRafał Miłecki 		SSB_SROM8_FEM_TR_ISO, SSB_SROM8_FEM_TR_ISO_SHIFT);
7468a5ac6ecSRafał Miłecki 	SPEX(fem.ghz5.antswlut, SSB_SPROM8_FEM5G,
7478a5ac6ecSRafał Miłecki 		SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT);
7488a5ac6ecSRafał Miłecki 
749e2da4bd3SHauke Mehrtens 	SPEX(leddc_on_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_ON,
750e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_LEDDC_ON_SHIFT);
751e2da4bd3SHauke Mehrtens 	SPEX(leddc_off_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_OFF,
752e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_LEDDC_OFF_SHIFT);
753e2da4bd3SHauke Mehrtens 
754e2da4bd3SHauke Mehrtens 	SPEX(txchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_TXCHAIN,
755e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_TXRXC_TXCHAIN_SHIFT);
756e2da4bd3SHauke Mehrtens 	SPEX(rxchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_RXCHAIN,
757e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_TXRXC_RXCHAIN_SHIFT);
758e2da4bd3SHauke Mehrtens 	SPEX(antswitch, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_SWITCH,
759e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_TXRXC_SWITCH_SHIFT);
760e2da4bd3SHauke Mehrtens 
761e2da4bd3SHauke Mehrtens 	SPEX(opo, SSB_SPROM8_OFDM2GPO, 0x00ff, 0);
762e2da4bd3SHauke Mehrtens 
763e2da4bd3SHauke Mehrtens 	SPEX_ARRAY8(mcs2gpo, SSB_SPROM8_2G_MCSPO, ~0, 0);
764e2da4bd3SHauke Mehrtens 	SPEX_ARRAY8(mcs5gpo, SSB_SPROM8_5G_MCSPO, ~0, 0);
765e2da4bd3SHauke Mehrtens 	SPEX_ARRAY8(mcs5glpo, SSB_SPROM8_5GL_MCSPO, ~0, 0);
766e2da4bd3SHauke Mehrtens 	SPEX_ARRAY8(mcs5ghpo, SSB_SPROM8_5GH_MCSPO, ~0, 0);
767e2da4bd3SHauke Mehrtens 
768e2da4bd3SHauke Mehrtens 	SPEX(rawtempsense, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_RAWTEMP,
769e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_RAWTS_RAWTEMP_SHIFT);
770e2da4bd3SHauke Mehrtens 	SPEX(measpower, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_MEASPOWER,
771e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_RAWTS_MEASPOWER_SHIFT);
772e2da4bd3SHauke Mehrtens 	SPEX(tempsense_slope, SSB_SPROM8_OPT_CORRX,
773e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_OPT_CORRX_TEMP_SLOPE,
774e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_OPT_CORRX_TEMP_SLOPE_SHIFT);
775e2da4bd3SHauke Mehrtens 	SPEX(tempcorrx, SSB_SPROM8_OPT_CORRX, SSB_SPROM8_OPT_CORRX_TEMPCORRX,
776e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_OPT_CORRX_TEMPCORRX_SHIFT);
777e2da4bd3SHauke Mehrtens 	SPEX(tempsense_option, SSB_SPROM8_OPT_CORRX,
778e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_OPT_CORRX_TEMP_OPTION,
779e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_OPT_CORRX_TEMP_OPTION_SHIFT);
780e2da4bd3SHauke Mehrtens 	SPEX(freqoffset_corr, SSB_SPROM8_HWIQ_IQSWP,
781e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR,
782e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR_SHIFT);
783e2da4bd3SHauke Mehrtens 	SPEX(iqcal_swp_dis, SSB_SPROM8_HWIQ_IQSWP,
784e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP,
785e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP_SHIFT);
786e2da4bd3SHauke Mehrtens 	SPEX(hw_iqcal_en, SSB_SPROM8_HWIQ_IQSWP, SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL,
787e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL_SHIFT);
788e2da4bd3SHauke Mehrtens 
789e2da4bd3SHauke Mehrtens 	SPEX(bw40po, SSB_SPROM8_BW40PO, ~0, 0);
790e2da4bd3SHauke Mehrtens 	SPEX(cddpo, SSB_SPROM8_CDDPO, ~0, 0);
791e2da4bd3SHauke Mehrtens 	SPEX(stbcpo, SSB_SPROM8_STBCPO, ~0, 0);
792e2da4bd3SHauke Mehrtens 	SPEX(bwduppo, SSB_SPROM8_BWDUPPO, ~0, 0);
793e2da4bd3SHauke Mehrtens 
794e2da4bd3SHauke Mehrtens 	SPEX(tempthresh, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_TRESH,
795e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_THERMAL_TRESH_SHIFT);
796e2da4bd3SHauke Mehrtens 	SPEX(tempoffset, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_OFFSET,
797e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_THERMAL_OFFSET_SHIFT);
798e2da4bd3SHauke Mehrtens 	SPEX(phycal_tempdelta, SSB_SPROM8_TEMPDELTA,
799e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_TEMPDELTA_PHYCAL,
800e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_TEMPDELTA_PHYCAL_SHIFT);
801e2da4bd3SHauke Mehrtens 	SPEX(temps_period, SSB_SPROM8_TEMPDELTA, SSB_SPROM8_TEMPDELTA_PERIOD,
802e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_TEMPDELTA_PERIOD_SHIFT);
803e2da4bd3SHauke Mehrtens 	SPEX(temps_hysteresis, SSB_SPROM8_TEMPDELTA,
804e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_TEMPDELTA_HYSTERESIS,
805e2da4bd3SHauke Mehrtens 	     SSB_SPROM8_TEMPDELTA_HYSTERESIS_SHIFT);
806172c69a4SRafał Miłecki 	sprom_extract_r458(out, in);
807172c69a4SRafał Miłecki 
8086b1c7c67SMichael Buesch 	/* TODO - get remaining rev 8 stuff needed */
8096b1c7c67SMichael Buesch }
8106b1c7c67SMichael Buesch 
sprom_extract(struct ssb_bus * bus,struct ssb_sprom * out,const u16 * in,u16 size)811c272ef44SLarry Finger static int sprom_extract(struct ssb_bus *bus, struct ssb_sprom *out,
812c272ef44SLarry Finger 			 const u16 *in, u16 size)
81361e115a5SMichael Buesch {
81461e115a5SMichael Buesch 	memset(out, 0, sizeof(*out));
81561e115a5SMichael Buesch 
816c272ef44SLarry Finger 	out->revision = in[size - 1] & 0x00FF;
817b8b6069cSMichael Büsch 	pr_debug("SPROM revision %d detected\n", out->revision);
81831ce12fbSLarry Finger 	memset(out->et0mac, 0xFF, 6);		/* preset et0 and et1 mac */
81931ce12fbSLarry Finger 	memset(out->et1mac, 0xFF, 6);
82054435f9eSRafał Miłecki 
82161e115a5SMichael Buesch 	if ((bus->chip_id & 0xFF00) == 0x4400) {
82261e115a5SMichael Buesch 		/* Workaround: The BCM44XX chip has a stupid revision
82361e115a5SMichael Buesch 		 * number stored in the SPROM.
82461e115a5SMichael Buesch 		 * Always extract r1. */
825c272ef44SLarry Finger 		out->revision = 1;
826b8b6069cSMichael Büsch 		pr_debug("SPROM treated as revision %d\n", out->revision);
82754435f9eSRafał Miłecki 	}
82854435f9eSRafał Miłecki 
8296b1c7c67SMichael Buesch 	switch (out->revision) {
8306b1c7c67SMichael Buesch 	case 1:
8316b1c7c67SMichael Buesch 	case 2:
8326b1c7c67SMichael Buesch 	case 3:
8336b1c7c67SMichael Buesch 		sprom_extract_r123(out, in);
8346b1c7c67SMichael Buesch 		break;
8356b1c7c67SMichael Buesch 	case 4:
8366b1c7c67SMichael Buesch 	case 5:
8376b1c7c67SMichael Buesch 		sprom_extract_r45(out, in);
8386b1c7c67SMichael Buesch 		break;
8396b1c7c67SMichael Buesch 	case 8:
8406b1c7c67SMichael Buesch 		sprom_extract_r8(out, in);
8416b1c7c67SMichael Buesch 		break;
8426b1c7c67SMichael Buesch 	default:
843b8b6069cSMichael Büsch 		pr_warn("Unsupported SPROM revision %d detected. Will extract v1\n",
84433a606acSJoe Perches 			out->revision);
845cd559b36SLarry Finger 		out->revision = 1;
846c272ef44SLarry Finger 		sprom_extract_r123(out, in);
847c272ef44SLarry Finger 	}
84861e115a5SMichael Buesch 
8494503183aSLarry Finger 	if (out->boardflags_lo == 0xFFFF)
8504503183aSLarry Finger 		out->boardflags_lo = 0;  /* per specs */
8514503183aSLarry Finger 	if (out->boardflags_hi == 0xFFFF)
8524503183aSLarry Finger 		out->boardflags_hi = 0;  /* per specs */
8534503183aSLarry Finger 
85461e115a5SMichael Buesch 	return 0;
85561e115a5SMichael Buesch }
85661e115a5SMichael Buesch 
ssb_pci_sprom_get(struct ssb_bus * bus,struct ssb_sprom * sprom)85761e115a5SMichael Buesch static int ssb_pci_sprom_get(struct ssb_bus *bus,
85861e115a5SMichael Buesch 			     struct ssb_sprom *sprom)
85961e115a5SMichael Buesch {
860ca4a0831SRafał Miłecki 	int err;
86161e115a5SMichael Buesch 	u16 *buf;
86261e115a5SMichael Buesch 
863d53cdbb9SJohn W. Linville 	if (!ssb_is_sprom_available(bus)) {
864b8b6069cSMichael Büsch 		pr_err("No SPROM available!\n");
865d53cdbb9SJohn W. Linville 		return -ENODEV;
866d53cdbb9SJohn W. Linville 	}
86725985edcSLucas De Marchi 	if (bus->chipco.dev) {	/* can be unavailable! */
8689d1ac34eSLarry Finger 		/*
8699d1ac34eSLarry Finger 		 * get SPROM offset: SSB_SPROM_BASE1 except for
8709d1ac34eSLarry Finger 		 * chipcommon rev >= 31 or chip ID is 0x4312 and
8719d1ac34eSLarry Finger 		 * chipcommon status & 3 == 2
8729d1ac34eSLarry Finger 		 */
8739d1ac34eSLarry Finger 		if (bus->chipco.dev->id.revision >= 31)
8749d1ac34eSLarry Finger 			bus->sprom_offset = SSB_SPROM_BASE31;
8759d1ac34eSLarry Finger 		else if (bus->chip_id == 0x4312 &&
8769d1ac34eSLarry Finger 			 (bus->chipco.status & 0x03) == 2)
8779d1ac34eSLarry Finger 			bus->sprom_offset = SSB_SPROM_BASE31;
8789d1ac34eSLarry Finger 		else
8799d1ac34eSLarry Finger 			bus->sprom_offset = SSB_SPROM_BASE1;
880da1fdb02SChristoph Fritz 	} else {
881da1fdb02SChristoph Fritz 		bus->sprom_offset = SSB_SPROM_BASE1;
882da1fdb02SChristoph Fritz 	}
883b8b6069cSMichael Büsch 	pr_debug("SPROM offset is 0x%x\n", bus->sprom_offset);
884ea2db495SRafał Miłecki 
885c272ef44SLarry Finger 	buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL);
88661e115a5SMichael Buesch 	if (!buf)
887ca4a0831SRafał Miłecki 		return -ENOMEM;
888c272ef44SLarry Finger 	bus->sprom_size = SSB_SPROMSIZE_WORDS_R123;
88961e115a5SMichael Buesch 	sprom_do_read(bus, buf);
890c272ef44SLarry Finger 	err = sprom_check_crc(buf, bus->sprom_size);
89161e115a5SMichael Buesch 	if (err) {
8922afc4901SLarry.Finger@lwfinger.net 		/* try for a 440 byte SPROM - revision 4 and higher */
893c272ef44SLarry Finger 		kfree(buf);
894c272ef44SLarry Finger 		buf = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
895c272ef44SLarry Finger 			      GFP_KERNEL);
896c272ef44SLarry Finger 		if (!buf)
897ca4a0831SRafał Miłecki 			return -ENOMEM;
898c272ef44SLarry Finger 		bus->sprom_size = SSB_SPROMSIZE_WORDS_R4;
899c272ef44SLarry Finger 		sprom_do_read(bus, buf);
900c272ef44SLarry Finger 		err = sprom_check_crc(buf, bus->sprom_size);
901e79c1ba8SMichael Buesch 		if (err) {
902e79c1ba8SMichael Buesch 			/* All CRC attempts failed.
903e79c1ba8SMichael Buesch 			 * Maybe there is no SPROM on the device?
904b3ae52b6SHauke Mehrtens 			 * Now we ask the arch code if there is some sprom
905b3ae52b6SHauke Mehrtens 			 * available for this device in some other storage */
906b3ae52b6SHauke Mehrtens 			err = ssb_fill_sprom_with_fallback(bus, sprom);
907b3ae52b6SHauke Mehrtens 			if (err) {
908b8b6069cSMichael Büsch 				pr_warn("WARNING: Using fallback SPROM failed (err %d)\n",
909b3ae52b6SHauke Mehrtens 					err);
9108052d724SLarry Finger 				goto out_free;
911b3ae52b6SHauke Mehrtens 			} else {
912b8b6069cSMichael Büsch 				pr_debug("Using SPROM revision %d provided by platform\n",
91333a606acSJoe Perches 					 sprom->revision);
914e79c1ba8SMichael Buesch 				err = 0;
915e79c1ba8SMichael Buesch 				goto out_free;
916e79c1ba8SMichael Buesch 			}
917c272ef44SLarry Finger 		}
918e79c1ba8SMichael Buesch 	}
919c272ef44SLarry Finger 	err = sprom_extract(bus, sprom, buf, bus->sprom_size);
92061e115a5SMichael Buesch 
921e79c1ba8SMichael Buesch out_free:
92261e115a5SMichael Buesch 	kfree(buf);
92361e115a5SMichael Buesch 	return err;
92461e115a5SMichael Buesch }
92561e115a5SMichael Buesch 
ssb_pci_get_boardinfo(struct ssb_bus * bus,struct ssb_boardinfo * bi)92661e115a5SMichael Buesch static void ssb_pci_get_boardinfo(struct ssb_bus *bus,
92761e115a5SMichael Buesch 				  struct ssb_boardinfo *bi)
92861e115a5SMichael Buesch {
929115f9450SSergei Shtylyov 	bi->vendor = bus->host_pci->subsystem_vendor;
930115f9450SSergei Shtylyov 	bi->type = bus->host_pci->subsystem_device;
93161e115a5SMichael Buesch }
93261e115a5SMichael Buesch 
ssb_pci_get_invariants(struct ssb_bus * bus,struct ssb_init_invariants * iv)93361e115a5SMichael Buesch int ssb_pci_get_invariants(struct ssb_bus *bus,
93461e115a5SMichael Buesch 			   struct ssb_init_invariants *iv)
93561e115a5SMichael Buesch {
93661e115a5SMichael Buesch 	int err;
93761e115a5SMichael Buesch 
93861e115a5SMichael Buesch 	err = ssb_pci_sprom_get(bus, &iv->sprom);
93961e115a5SMichael Buesch 	if (err)
94061e115a5SMichael Buesch 		goto out;
94161e115a5SMichael Buesch 	ssb_pci_get_boardinfo(bus, &iv->boardinfo);
94261e115a5SMichael Buesch 
94361e115a5SMichael Buesch out:
94461e115a5SMichael Buesch 	return err;
94561e115a5SMichael Buesch }
94661e115a5SMichael Buesch 
ssb_pci_assert_buspower(struct ssb_bus * bus)94761e115a5SMichael Buesch static int ssb_pci_assert_buspower(struct ssb_bus *bus)
94861e115a5SMichael Buesch {
94961e115a5SMichael Buesch 	if (likely(bus->powered_up))
95061e115a5SMichael Buesch 		return 0;
95161e115a5SMichael Buesch 
952b8b6069cSMichael Büsch 	pr_err("FATAL ERROR: Bus powered down while accessing PCI MMIO space\n");
95361e115a5SMichael Buesch 	if (bus->power_warn_count <= 10) {
95461e115a5SMichael Buesch 		bus->power_warn_count++;
95561e115a5SMichael Buesch 		dump_stack();
95661e115a5SMichael Buesch 	}
95761e115a5SMichael Buesch 
95861e115a5SMichael Buesch 	return -ENODEV;
95961e115a5SMichael Buesch }
96061e115a5SMichael Buesch 
ssb_pci_read8(struct ssb_device * dev,u16 offset)961ffc7689dSMichael Buesch static u8 ssb_pci_read8(struct ssb_device *dev, u16 offset)
962ffc7689dSMichael Buesch {
963ffc7689dSMichael Buesch 	struct ssb_bus *bus = dev->bus;
964ffc7689dSMichael Buesch 
965ffc7689dSMichael Buesch 	if (unlikely(ssb_pci_assert_buspower(bus)))
966ffc7689dSMichael Buesch 		return 0xFF;
967ffc7689dSMichael Buesch 	if (unlikely(bus->mapped_device != dev)) {
968ffc7689dSMichael Buesch 		if (unlikely(ssb_pci_switch_core(bus, dev)))
969ffc7689dSMichael Buesch 			return 0xFF;
970ffc7689dSMichael Buesch 	}
971ffc7689dSMichael Buesch 	return ioread8(bus->mmio + offset);
972ffc7689dSMichael Buesch }
973ffc7689dSMichael Buesch 
ssb_pci_read16(struct ssb_device * dev,u16 offset)97461e115a5SMichael Buesch static u16 ssb_pci_read16(struct ssb_device *dev, u16 offset)
97561e115a5SMichael Buesch {
97661e115a5SMichael Buesch 	struct ssb_bus *bus = dev->bus;
97761e115a5SMichael Buesch 
97861e115a5SMichael Buesch 	if (unlikely(ssb_pci_assert_buspower(bus)))
97961e115a5SMichael Buesch 		return 0xFFFF;
98061e115a5SMichael Buesch 	if (unlikely(bus->mapped_device != dev)) {
98161e115a5SMichael Buesch 		if (unlikely(ssb_pci_switch_core(bus, dev)))
98261e115a5SMichael Buesch 			return 0xFFFF;
98361e115a5SMichael Buesch 	}
9844b402c65SMichael Buesch 	return ioread16(bus->mmio + offset);
98561e115a5SMichael Buesch }
98661e115a5SMichael Buesch 
ssb_pci_read32(struct ssb_device * dev,u16 offset)98761e115a5SMichael Buesch static u32 ssb_pci_read32(struct ssb_device *dev, u16 offset)
98861e115a5SMichael Buesch {
98961e115a5SMichael Buesch 	struct ssb_bus *bus = dev->bus;
99061e115a5SMichael Buesch 
99161e115a5SMichael Buesch 	if (unlikely(ssb_pci_assert_buspower(bus)))
99261e115a5SMichael Buesch 		return 0xFFFFFFFF;
99361e115a5SMichael Buesch 	if (unlikely(bus->mapped_device != dev)) {
99461e115a5SMichael Buesch 		if (unlikely(ssb_pci_switch_core(bus, dev)))
99561e115a5SMichael Buesch 			return 0xFFFFFFFF;
99661e115a5SMichael Buesch 	}
9974b402c65SMichael Buesch 	return ioread32(bus->mmio + offset);
99861e115a5SMichael Buesch }
99961e115a5SMichael Buesch 
1000d625a29bSMichael Buesch #ifdef CONFIG_SSB_BLOCKIO
ssb_pci_block_read(struct ssb_device * dev,void * buffer,size_t count,u16 offset,u8 reg_width)1001d625a29bSMichael Buesch static void ssb_pci_block_read(struct ssb_device *dev, void *buffer,
1002d625a29bSMichael Buesch 			       size_t count, u16 offset, u8 reg_width)
1003d625a29bSMichael Buesch {
1004d625a29bSMichael Buesch 	struct ssb_bus *bus = dev->bus;
1005d625a29bSMichael Buesch 	void __iomem *addr = bus->mmio + offset;
1006d625a29bSMichael Buesch 
1007d625a29bSMichael Buesch 	if (unlikely(ssb_pci_assert_buspower(bus)))
1008d625a29bSMichael Buesch 		goto error;
1009d625a29bSMichael Buesch 	if (unlikely(bus->mapped_device != dev)) {
1010d625a29bSMichael Buesch 		if (unlikely(ssb_pci_switch_core(bus, dev)))
1011d625a29bSMichael Buesch 			goto error;
1012d625a29bSMichael Buesch 	}
1013d625a29bSMichael Buesch 	switch (reg_width) {
1014d625a29bSMichael Buesch 	case sizeof(u8):
1015d625a29bSMichael Buesch 		ioread8_rep(addr, buffer, count);
1016d625a29bSMichael Buesch 		break;
1017d625a29bSMichael Buesch 	case sizeof(u16):
1018209b4375SMichael Büsch 		WARN_ON(count & 1);
1019d625a29bSMichael Buesch 		ioread16_rep(addr, buffer, count >> 1);
1020d625a29bSMichael Buesch 		break;
1021d625a29bSMichael Buesch 	case sizeof(u32):
1022209b4375SMichael Büsch 		WARN_ON(count & 3);
1023d625a29bSMichael Buesch 		ioread32_rep(addr, buffer, count >> 2);
1024d625a29bSMichael Buesch 		break;
1025d625a29bSMichael Buesch 	default:
1026209b4375SMichael Büsch 		WARN_ON(1);
1027d625a29bSMichael Buesch 	}
1028d625a29bSMichael Buesch 
1029d625a29bSMichael Buesch 	return;
1030d625a29bSMichael Buesch error:
1031d625a29bSMichael Buesch 	memset(buffer, 0xFF, count);
1032d625a29bSMichael Buesch }
1033d625a29bSMichael Buesch #endif /* CONFIG_SSB_BLOCKIO */
1034d625a29bSMichael Buesch 
ssb_pci_write8(struct ssb_device * dev,u16 offset,u8 value)1035ffc7689dSMichael Buesch static void ssb_pci_write8(struct ssb_device *dev, u16 offset, u8 value)
1036ffc7689dSMichael Buesch {
1037ffc7689dSMichael Buesch 	struct ssb_bus *bus = dev->bus;
1038ffc7689dSMichael Buesch 
1039ffc7689dSMichael Buesch 	if (unlikely(ssb_pci_assert_buspower(bus)))
1040ffc7689dSMichael Buesch 		return;
1041ffc7689dSMichael Buesch 	if (unlikely(bus->mapped_device != dev)) {
1042ffc7689dSMichael Buesch 		if (unlikely(ssb_pci_switch_core(bus, dev)))
1043ffc7689dSMichael Buesch 			return;
1044ffc7689dSMichael Buesch 	}
1045ffc7689dSMichael Buesch 	iowrite8(value, bus->mmio + offset);
1046ffc7689dSMichael Buesch }
1047ffc7689dSMichael Buesch 
ssb_pci_write16(struct ssb_device * dev,u16 offset,u16 value)104861e115a5SMichael Buesch static void ssb_pci_write16(struct ssb_device *dev, u16 offset, u16 value)
104961e115a5SMichael Buesch {
105061e115a5SMichael Buesch 	struct ssb_bus *bus = dev->bus;
105161e115a5SMichael Buesch 
105261e115a5SMichael Buesch 	if (unlikely(ssb_pci_assert_buspower(bus)))
105361e115a5SMichael Buesch 		return;
105461e115a5SMichael Buesch 	if (unlikely(bus->mapped_device != dev)) {
105561e115a5SMichael Buesch 		if (unlikely(ssb_pci_switch_core(bus, dev)))
105661e115a5SMichael Buesch 			return;
105761e115a5SMichael Buesch 	}
10584b402c65SMichael Buesch 	iowrite16(value, bus->mmio + offset);
105961e115a5SMichael Buesch }
106061e115a5SMichael Buesch 
ssb_pci_write32(struct ssb_device * dev,u16 offset,u32 value)106161e115a5SMichael Buesch static void ssb_pci_write32(struct ssb_device *dev, u16 offset, u32 value)
106261e115a5SMichael Buesch {
106361e115a5SMichael Buesch 	struct ssb_bus *bus = dev->bus;
106461e115a5SMichael Buesch 
106561e115a5SMichael Buesch 	if (unlikely(ssb_pci_assert_buspower(bus)))
106661e115a5SMichael Buesch 		return;
106761e115a5SMichael Buesch 	if (unlikely(bus->mapped_device != dev)) {
106861e115a5SMichael Buesch 		if (unlikely(ssb_pci_switch_core(bus, dev)))
106961e115a5SMichael Buesch 			return;
107061e115a5SMichael Buesch 	}
10714b402c65SMichael Buesch 	iowrite32(value, bus->mmio + offset);
107261e115a5SMichael Buesch }
107361e115a5SMichael Buesch 
1074d625a29bSMichael Buesch #ifdef CONFIG_SSB_BLOCKIO
ssb_pci_block_write(struct ssb_device * dev,const void * buffer,size_t count,u16 offset,u8 reg_width)1075d625a29bSMichael Buesch static void ssb_pci_block_write(struct ssb_device *dev, const void *buffer,
1076d625a29bSMichael Buesch 				size_t count, u16 offset, u8 reg_width)
1077d625a29bSMichael Buesch {
1078d625a29bSMichael Buesch 	struct ssb_bus *bus = dev->bus;
1079d625a29bSMichael Buesch 	void __iomem *addr = bus->mmio + offset;
1080d625a29bSMichael Buesch 
1081d625a29bSMichael Buesch 	if (unlikely(ssb_pci_assert_buspower(bus)))
1082d625a29bSMichael Buesch 		return;
1083d625a29bSMichael Buesch 	if (unlikely(bus->mapped_device != dev)) {
1084d625a29bSMichael Buesch 		if (unlikely(ssb_pci_switch_core(bus, dev)))
1085d625a29bSMichael Buesch 			return;
1086d625a29bSMichael Buesch 	}
1087d625a29bSMichael Buesch 	switch (reg_width) {
1088d625a29bSMichael Buesch 	case sizeof(u8):
1089d625a29bSMichael Buesch 		iowrite8_rep(addr, buffer, count);
1090d625a29bSMichael Buesch 		break;
1091d625a29bSMichael Buesch 	case sizeof(u16):
1092209b4375SMichael Büsch 		WARN_ON(count & 1);
1093d625a29bSMichael Buesch 		iowrite16_rep(addr, buffer, count >> 1);
1094d625a29bSMichael Buesch 		break;
1095d625a29bSMichael Buesch 	case sizeof(u32):
1096209b4375SMichael Büsch 		WARN_ON(count & 3);
1097d625a29bSMichael Buesch 		iowrite32_rep(addr, buffer, count >> 2);
1098d625a29bSMichael Buesch 		break;
1099d625a29bSMichael Buesch 	default:
1100209b4375SMichael Büsch 		WARN_ON(1);
1101d625a29bSMichael Buesch 	}
1102d625a29bSMichael Buesch }
1103d625a29bSMichael Buesch #endif /* CONFIG_SSB_BLOCKIO */
1104d625a29bSMichael Buesch 
110561e115a5SMichael Buesch /* Not "static", as it's used in main.c */
110661e115a5SMichael Buesch const struct ssb_bus_ops ssb_pci_ops = {
1107ffc7689dSMichael Buesch 	.read8		= ssb_pci_read8,
110861e115a5SMichael Buesch 	.read16		= ssb_pci_read16,
110961e115a5SMichael Buesch 	.read32		= ssb_pci_read32,
1110ffc7689dSMichael Buesch 	.write8		= ssb_pci_write8,
111161e115a5SMichael Buesch 	.write16	= ssb_pci_write16,
111261e115a5SMichael Buesch 	.write32	= ssb_pci_write32,
1113d625a29bSMichael Buesch #ifdef CONFIG_SSB_BLOCKIO
1114d625a29bSMichael Buesch 	.block_read	= ssb_pci_block_read,
1115d625a29bSMichael Buesch 	.block_write	= ssb_pci_block_write,
1116d625a29bSMichael Buesch #endif
111761e115a5SMichael Buesch };
111861e115a5SMichael Buesch 
ssb_sprom_show(struct device * pcidev,struct device_attribute * attr,char * buf)1119*573f1af8SZhen Lei static ssize_t ssb_sprom_show(struct device *pcidev,
112061e115a5SMichael Buesch 			      struct device_attribute *attr,
112161e115a5SMichael Buesch 			      char *buf)
112261e115a5SMichael Buesch {
112361e115a5SMichael Buesch 	struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev);
112461e115a5SMichael Buesch 	struct ssb_bus *bus;
112561e115a5SMichael Buesch 
112661e115a5SMichael Buesch 	bus = ssb_pci_dev_to_bus(pdev);
112761e115a5SMichael Buesch 	if (!bus)
1128e7ec2e32SMichael Buesch 		return -ENODEV;
112961e115a5SMichael Buesch 
1130e7ec2e32SMichael Buesch 	return ssb_attr_sprom_show(bus, buf, sprom_do_read);
113161e115a5SMichael Buesch }
113261e115a5SMichael Buesch 
ssb_sprom_store(struct device * pcidev,struct device_attribute * attr,const char * buf,size_t count)1133*573f1af8SZhen Lei static ssize_t ssb_sprom_store(struct device *pcidev,
113461e115a5SMichael Buesch 			       struct device_attribute *attr,
113561e115a5SMichael Buesch 			       const char *buf, size_t count)
113661e115a5SMichael Buesch {
113761e115a5SMichael Buesch 	struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev);
113861e115a5SMichael Buesch 	struct ssb_bus *bus;
113961e115a5SMichael Buesch 
114061e115a5SMichael Buesch 	bus = ssb_pci_dev_to_bus(pdev);
114161e115a5SMichael Buesch 	if (!bus)
1142e7ec2e32SMichael Buesch 		return -ENODEV;
114361e115a5SMichael Buesch 
1144e7ec2e32SMichael Buesch 	return ssb_attr_sprom_store(bus, buf, count,
1145e7ec2e32SMichael Buesch 				    sprom_check_crc, sprom_do_write);
114661e115a5SMichael Buesch }
114761e115a5SMichael Buesch 
1148*573f1af8SZhen Lei static DEVICE_ATTR_ADMIN_RW(ssb_sprom);
114961e115a5SMichael Buesch 
ssb_pci_exit(struct ssb_bus * bus)115061e115a5SMichael Buesch void ssb_pci_exit(struct ssb_bus *bus)
115161e115a5SMichael Buesch {
115261e115a5SMichael Buesch 	struct pci_dev *pdev;
115361e115a5SMichael Buesch 
115461e115a5SMichael Buesch 	if (bus->bustype != SSB_BUSTYPE_PCI)
115561e115a5SMichael Buesch 		return;
115661e115a5SMichael Buesch 
115761e115a5SMichael Buesch 	pdev = bus->host_pci;
115861e115a5SMichael Buesch 	device_remove_file(&pdev->dev, &dev_attr_ssb_sprom);
115961e115a5SMichael Buesch }
116061e115a5SMichael Buesch 
ssb_pci_init(struct ssb_bus * bus)116161e115a5SMichael Buesch int ssb_pci_init(struct ssb_bus *bus)
116261e115a5SMichael Buesch {
116361e115a5SMichael Buesch 	struct pci_dev *pdev;
116461e115a5SMichael Buesch 
116561e115a5SMichael Buesch 	if (bus->bustype != SSB_BUSTYPE_PCI)
116661e115a5SMichael Buesch 		return 0;
116761e115a5SMichael Buesch 
116861e115a5SMichael Buesch 	pdev = bus->host_pci;
1169e7ec2e32SMichael Buesch 	mutex_init(&bus->sprom_mutex);
117061e115a5SMichael Buesch 
117141650c45SJing Xiangfeng 	return device_create_file(&pdev->dev, &dev_attr_ssb_sprom);
117261e115a5SMichael Buesch }
1173