161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch/*
261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch * Sonics Silicon Backplane PCI-Hostbus related functions.
361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch *
4eb032b9837a958e21ca000358a5bde5e17192ddbMichael Buesch * Copyright (C) 2005-2006 Michael Buesch <m@bues.ch>
561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch * Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch * Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch * Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch * Copyright (C) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch *
1061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch * Derived from the Broadcom 4400 device driver.
1161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch * Copyright (C) 2002 David S. Miller (davem@redhat.com)
1261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch * Fixed by Pekka Pietikainen (pp@ee.oulu.fi)
1361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch * Copyright (C) 2006 Broadcom Corporation.
1461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch *
1561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch * Licensed under the GNU/GPL. See COPYING for details.
1661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch */
1761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
1861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch#include <linux/ssb/ssb.h>
1961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch#include <linux/ssb/ssb_regs.h>
205a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
2161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch#include <linux/pci.h>
2261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch#include <linux/delay.h>
2361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
2461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch#include "ssb_private.h"
2561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
2661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
2761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch/* Define the following to 1 to enable a printk on each coreswitch. */
2861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch#define SSB_VERBOSE_PCICORESWITCH_DEBUG		0
2961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
3061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
3161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch/* Lowlevel coreswitching */
3261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschint ssb_pci_switch_coreidx(struct ssb_bus *bus, u8 coreidx)
3361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch{
3461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	int err;
3561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	int attempts = 0;
3661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	u32 cur_core;
3761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
3861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	while (1) {
3961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		err = pci_write_config_dword(bus->host_pci, SSB_BAR0_WIN,
4061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch					     (coreidx * SSB_CORE_SIZE)
4161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch					     + SSB_ENUM_BASE);
4261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		if (err)
4361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch			goto error;
4461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		err = pci_read_config_dword(bus->host_pci, SSB_BAR0_WIN,
4561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch					    &cur_core);
4661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		if (err)
4761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch			goto error;
4861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		cur_core = (cur_core - SSB_ENUM_BASE)
4961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch			   / SSB_CORE_SIZE;
5061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		if (cur_core == coreidx)
5161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch			break;
5261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
5361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		if (attempts++ > SSB_BAR0_MAX_RETRIES)
5461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch			goto error;
5561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		udelay(10);
5661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	}
5761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	return 0;
5861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buescherror:
5961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	ssb_printk(KERN_ERR PFX "Failed to switch to core %u\n", coreidx);
6061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	return -ENODEV;
6161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch}
6261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
6361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschint ssb_pci_switch_core(struct ssb_bus *bus,
6461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch			struct ssb_device *dev)
6561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch{
6661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	int err;
6761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	unsigned long flags;
6861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
6961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch#if SSB_VERBOSE_PCICORESWITCH_DEBUG
7061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	ssb_printk(KERN_INFO PFX
7161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		   "Switching to %s core, index %d\n",
7261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		   ssb_core_name(dev->id.coreid),
7361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		   dev->core_index);
7461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch#endif
7561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
7661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	spin_lock_irqsave(&bus->bar_lock, flags);
7761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	err = ssb_pci_switch_coreidx(bus, dev->core_index);
7861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	if (!err)
7961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		bus->mapped_device = dev;
8061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	spin_unlock_irqrestore(&bus->bar_lock, flags);
8161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
8261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	return err;
8361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch}
8461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
8561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch/* Enable/disable the on board crystal oscillator and/or PLL. */
8661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschint ssb_pci_xtal(struct ssb_bus *bus, u32 what, int turn_on)
8761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch{
8861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	int err;
8961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	u32 in, out, outenable;
9061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	u16 pci_status;
9161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
9261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	if (bus->bustype != SSB_BUSTYPE_PCI)
9361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		return 0;
9461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
9561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	err = pci_read_config_dword(bus->host_pci, SSB_GPIO_IN, &in);
9661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	if (err)
9761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		goto err_pci;
9861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	err = pci_read_config_dword(bus->host_pci, SSB_GPIO_OUT, &out);
9961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	if (err)
10061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		goto err_pci;
10161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	err = pci_read_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE, &outenable);
10261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	if (err)
10361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		goto err_pci;
10461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
10561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	outenable |= what;
10661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
10761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	if (turn_on) {
10861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		/* Avoid glitching the clock if GPRS is already using it.
10961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		 * We can't actually read the state of the PLLPD so we infer it
11061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		 * by the value of XTAL_PU which *is* readable via gpioin.
11161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		 */
11261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		if (!(in & SSB_GPIO_XTAL)) {
11361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch			if (what & SSB_GPIO_XTAL) {
11461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch				/* Turn the crystal on */
11561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch				out |= SSB_GPIO_XTAL;
11661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch				if (what & SSB_GPIO_PLL)
11761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch					out |= SSB_GPIO_PLL;
11861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch				err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out);
11961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch				if (err)
12061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch					goto err_pci;
12161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch				err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE,
12261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch							     outenable);
12361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch				if (err)
12461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch					goto err_pci;
12561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch				msleep(1);
12661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch			}
12761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch			if (what & SSB_GPIO_PLL) {
12861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch				/* Turn the PLL on */
12961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch				out &= ~SSB_GPIO_PLL;
13061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch				err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out);
13161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch				if (err)
13261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch					goto err_pci;
13361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch				msleep(5);
13461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch			}
13561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		}
13661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
13761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		err = pci_read_config_word(bus->host_pci, PCI_STATUS, &pci_status);
13861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		if (err)
13961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch			goto err_pci;
14061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		pci_status &= ~PCI_STATUS_SIG_TARGET_ABORT;
14161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		err = pci_write_config_word(bus->host_pci, PCI_STATUS, pci_status);
14261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		if (err)
14361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch			goto err_pci;
14461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	} else {
14561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		if (what & SSB_GPIO_XTAL) {
14661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch			/* Turn the crystal off */
14761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch			out &= ~SSB_GPIO_XTAL;
14861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		}
14961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		if (what & SSB_GPIO_PLL) {
15061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch			/* Turn the PLL off */
15161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch			out |= SSB_GPIO_PLL;
15261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		}
15361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out);
15461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		if (err)
15561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch			goto err_pci;
15661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE, outenable);
15761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		if (err)
15861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch			goto err_pci;
15961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	}
16061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
16161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschout:
16261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	return err;
16361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
16461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buescherr_pci:
16561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	printk(KERN_ERR PFX "Error: ssb_pci_xtal() could not access PCI config space!\n");
16661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	err = -EBUSY;
16761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	goto out;
16861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch}
16961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
17061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch/* Get the word-offset for a SSB_SPROM_XXX define. */
1710a182fd88f8180b342f753f04c7d5507b5891c96Rafał Miłecki#define SPOFF(offset)	((offset) / sizeof(u16))
17261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch/* Helper to extract some _offset, which is one of the SSB_SPROM_XXX defines. */
173f679056b2fdd4e9b7c8eb42ba447cd9646236305Gábor Stefanik#define SPEX16(_outvar, _offset, _mask, _shift)	\
17461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	out->_outvar = ((in[SPOFF(_offset)] & (_mask)) >> (_shift))
175f679056b2fdd4e9b7c8eb42ba447cd9646236305Gábor Stefanik#define SPEX32(_outvar, _offset, _mask, _shift)	\
176f679056b2fdd4e9b7c8eb42ba447cd9646236305Gábor Stefanik	out->_outvar = ((((u32)in[SPOFF((_offset)+2)] << 16 | \
177f679056b2fdd4e9b7c8eb42ba447cd9646236305Gábor Stefanik			   in[SPOFF(_offset)]) & (_mask)) >> (_shift))
178f679056b2fdd4e9b7c8eb42ba447cd9646236305Gábor Stefanik#define SPEX(_outvar, _offset, _mask, _shift) \
179f679056b2fdd4e9b7c8eb42ba447cd9646236305Gábor Stefanik	SPEX16(_outvar, _offset, _mask, _shift)
180f679056b2fdd4e9b7c8eb42ba447cd9646236305Gábor Stefanik
18161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
18261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschstatic inline u8 ssb_crc8(u8 crc, u8 data)
18361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch{
18461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	/* Polynomial:   x^8 + x^7 + x^6 + x^4 + x^2 + 1   */
18561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	static const u8 t[] = {
18661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
18761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
18861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
18961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
19061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
19161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
19261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
19361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
19461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
19561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
19661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
19761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
19861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
19961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
20061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
20161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
20261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
20361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
20461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
20561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
20661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
20761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
20861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
20961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
21061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
21161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
21261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
21361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
21461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
21561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
21661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
21761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F,
21861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	};
21961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	return t[crc ^ data];
22061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch}
22161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
222c272ef4403c271799a7f09a4ab7a236c86643843Larry Fingerstatic u8 ssb_sprom_crc(const u16 *sprom, u16 size)
22361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch{
22461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	int word;
22561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	u8 crc = 0xFF;
22661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
227c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger	for (word = 0; word < size - 1; word++) {
22861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		crc = ssb_crc8(crc, sprom[word] & 0x00FF);
22961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		crc = ssb_crc8(crc, (sprom[word] & 0xFF00) >> 8);
23061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	}
231c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger	crc = ssb_crc8(crc, sprom[size - 1] & 0x00FF);
23261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	crc ^= 0xFF;
23361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
23461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	return crc;
23561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch}
23661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
237e7ec2e3230633a858af1b0b359f6c4670dbeb997Michael Bueschstatic int sprom_check_crc(const u16 *sprom, size_t size)
23861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch{
23961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	u8 crc;
24061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	u8 expected_crc;
24161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	u16 tmp;
24261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
243c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger	crc = ssb_sprom_crc(sprom, size);
244c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger	tmp = sprom[size - 1] & SSB_SPROM_REVISION_CRC;
24561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	expected_crc = tmp >> SSB_SPROM_REVISION_CRC_SHIFT;
24661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	if (crc != expected_crc)
24761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		return -EPROTO;
24861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
24961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	return 0;
25061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch}
25161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
252e7ec2e3230633a858af1b0b359f6c4670dbeb997Michael Bueschstatic int sprom_do_read(struct ssb_bus *bus, u16 *sprom)
25361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch{
25461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	int i;
25561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
256c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger	for (i = 0; i < bus->sprom_size; i++)
257ea2db495f92ad2cf3301623e60cb95b4062bc484Rafał Miłecki		sprom[i] = ioread16(bus->mmio + bus->sprom_offset + (i * 2));
258e7ec2e3230633a858af1b0b359f6c4670dbeb997Michael Buesch
259e7ec2e3230633a858af1b0b359f6c4670dbeb997Michael Buesch	return 0;
26061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch}
26161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
26261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschstatic int sprom_do_write(struct ssb_bus *bus, const u16 *sprom)
26361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch{
26461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	struct pci_dev *pdev = bus->host_pci;
26561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	int i, err;
26661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	u32 spromctl;
267c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger	u16 size = bus->sprom_size;
26861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
26961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	ssb_printk(KERN_NOTICE PFX "Writing SPROM. Do NOT turn off the power! Please stand by...\n");
27061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	err = pci_read_config_dword(pdev, SSB_SPROMCTL, &spromctl);
27161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	if (err)
27261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		goto err_ctlreg;
27361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	spromctl |= SSB_SPROMCTL_WE;
27461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	err = pci_write_config_dword(pdev, SSB_SPROMCTL, spromctl);
27561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	if (err)
27661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		goto err_ctlreg;
27761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	ssb_printk(KERN_NOTICE PFX "[ 0%%");
27861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	msleep(500);
279c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger	for (i = 0; i < size; i++) {
280c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger		if (i == size / 4)
28161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch			ssb_printk("25%%");
282c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger		else if (i == size / 2)
28361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch			ssb_printk("50%%");
284c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger		else if (i == (size * 3) / 4)
28561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch			ssb_printk("75%%");
28661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		else if (i % 2)
28761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch			ssb_printk(".");
288ea2db495f92ad2cf3301623e60cb95b4062bc484Rafał Miłecki		writew(sprom[i], bus->mmio + bus->sprom_offset + (i * 2));
28961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		mmiowb();
29061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		msleep(20);
29161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	}
29261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	err = pci_read_config_dword(pdev, SSB_SPROMCTL, &spromctl);
29361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	if (err)
29461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		goto err_ctlreg;
29561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	spromctl &= ~SSB_SPROMCTL_WE;
29661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	err = pci_write_config_dword(pdev, SSB_SPROMCTL, spromctl);
29761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	if (err)
29861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		goto err_ctlreg;
29961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	msleep(500);
30061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	ssb_printk("100%% ]\n");
30161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	ssb_printk(KERN_NOTICE PFX "SPROM written.\n");
30261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
30361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	return 0;
30461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buescherr_ctlreg:
30561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	ssb_printk(KERN_ERR PFX "Could not access SPROM control register.\n");
30661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	return err;
30761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch}
30861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
309e861b98d5e1be769ca6483b6df97149b956ea834Michael Bueschstatic s8 r123_extract_antgain(u8 sprom_revision, const u16 *in,
310e861b98d5e1be769ca6483b6df97149b956ea834Michael Buesch			       u16 mask, u16 shift)
311e861b98d5e1be769ca6483b6df97149b956ea834Michael Buesch{
312e861b98d5e1be769ca6483b6df97149b956ea834Michael Buesch	u16 v;
313e861b98d5e1be769ca6483b6df97149b956ea834Michael Buesch	u8 gain;
314e861b98d5e1be769ca6483b6df97149b956ea834Michael Buesch
315e861b98d5e1be769ca6483b6df97149b956ea834Michael Buesch	v = in[SPOFF(SSB_SPROM1_AGAIN)];
316e861b98d5e1be769ca6483b6df97149b956ea834Michael Buesch	gain = (v & mask) >> shift;
317e861b98d5e1be769ca6483b6df97149b956ea834Michael Buesch	if (gain == 0xFF)
318e861b98d5e1be769ca6483b6df97149b956ea834Michael Buesch		gain = 2; /* If unset use 2dBm */
319e861b98d5e1be769ca6483b6df97149b956ea834Michael Buesch	if (sprom_revision == 1) {
320e861b98d5e1be769ca6483b6df97149b956ea834Michael Buesch		/* Convert to Q5.2 */
321e861b98d5e1be769ca6483b6df97149b956ea834Michael Buesch		gain <<= 2;
322e861b98d5e1be769ca6483b6df97149b956ea834Michael Buesch	} else {
323e861b98d5e1be769ca6483b6df97149b956ea834Michael Buesch		/* Q5.2 Fractional part is stored in 0xC0 */
324e861b98d5e1be769ca6483b6df97149b956ea834Michael Buesch		gain = ((gain & 0xC0) >> 6) | ((gain & 0x3F) << 2);
325e861b98d5e1be769ca6483b6df97149b956ea834Michael Buesch	}
326e861b98d5e1be769ca6483b6df97149b956ea834Michael Buesch
327e861b98d5e1be769ca6483b6df97149b956ea834Michael Buesch	return (s8)gain;
328e861b98d5e1be769ca6483b6df97149b956ea834Michael Buesch}
329e861b98d5e1be769ca6483b6df97149b956ea834Michael Buesch
330c272ef4403c271799a7f09a4ab7a236c86643843Larry Fingerstatic void sprom_extract_r123(struct ssb_sprom *out, const u16 *in)
33161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch{
33261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	int i;
33361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	u16 v;
334c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger	u16 loc[3];
33561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
33631ce12fb3ebf88b054deb99ad729e84888bf6125Larry Finger	if (out->revision == 3)			/* rev 3 moved MAC */
337c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger		loc[0] = SSB_SPROM3_IL0MAC;
33831ce12fb3ebf88b054deb99ad729e84888bf6125Larry Finger	else {
339c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger		loc[0] = SSB_SPROM1_IL0MAC;
340c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger		loc[1] = SSB_SPROM1_ET0MAC;
341c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger		loc[2] = SSB_SPROM1_ET1MAC;
342c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger	}
343c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger	for (i = 0; i < 3; i++) {
344c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger		v = in[SPOFF(loc[0]) + i];
345c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger		*(((__be16 *)out->il0mac) + i) = cpu_to_be16(v);
346c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger	}
34731ce12fb3ebf88b054deb99ad729e84888bf6125Larry Finger	if (out->revision < 3) { 	/* only rev 1-2 have et0, et1 */
34831ce12fb3ebf88b054deb99ad729e84888bf6125Larry Finger		for (i = 0; i < 3; i++) {
34931ce12fb3ebf88b054deb99ad729e84888bf6125Larry Finger			v = in[SPOFF(loc[1]) + i];
35031ce12fb3ebf88b054deb99ad729e84888bf6125Larry Finger			*(((__be16 *)out->et0mac) + i) = cpu_to_be16(v);
35131ce12fb3ebf88b054deb99ad729e84888bf6125Larry Finger		}
35231ce12fb3ebf88b054deb99ad729e84888bf6125Larry Finger		for (i = 0; i < 3; i++) {
35331ce12fb3ebf88b054deb99ad729e84888bf6125Larry Finger			v = in[SPOFF(loc[2]) + i];
35431ce12fb3ebf88b054deb99ad729e84888bf6125Larry Finger			*(((__be16 *)out->et1mac) + i) = cpu_to_be16(v);
35531ce12fb3ebf88b054deb99ad729e84888bf6125Larry Finger		}
35661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	}
357c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger	SPEX(et0phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0A, 0);
358c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger	SPEX(et1phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1A,
359c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger	     SSB_SPROM1_ETHPHY_ET1A_SHIFT);
360e861b98d5e1be769ca6483b6df97149b956ea834Michael Buesch	SPEX(et0mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0M, 14);
361e861b98d5e1be769ca6483b6df97149b956ea834Michael Buesch	SPEX(et1mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1M, 15);
362e861b98d5e1be769ca6483b6df97149b956ea834Michael Buesch	SPEX(board_rev, SSB_SPROM1_BINF, SSB_SPROM1_BINF_BREV, 0);
363c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger	SPEX(country_code, SSB_SPROM1_BINF, SSB_SPROM1_BINF_CCODE,
364c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger	     SSB_SPROM1_BINF_CCODE_SHIFT);
365e861b98d5e1be769ca6483b6df97149b956ea834Michael Buesch	SPEX(ant_available_a, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTA,
366e861b98d5e1be769ca6483b6df97149b956ea834Michael Buesch	     SSB_SPROM1_BINF_ANTA_SHIFT);
367e861b98d5e1be769ca6483b6df97149b956ea834Michael Buesch	SPEX(ant_available_bg, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTBG,
368e861b98d5e1be769ca6483b6df97149b956ea834Michael Buesch	     SSB_SPROM1_BINF_ANTBG_SHIFT);
369c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger	SPEX(pa0b0, SSB_SPROM1_PA0B0, 0xFFFF, 0);
370c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger	SPEX(pa0b1, SSB_SPROM1_PA0B1, 0xFFFF, 0);
371c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger	SPEX(pa0b2, SSB_SPROM1_PA0B2, 0xFFFF, 0);
372c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger	SPEX(pa1b0, SSB_SPROM1_PA1B0, 0xFFFF, 0);
373c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger	SPEX(pa1b1, SSB_SPROM1_PA1B1, 0xFFFF, 0);
374c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger	SPEX(pa1b2, SSB_SPROM1_PA1B2, 0xFFFF, 0);
375c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger	SPEX(gpio0, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P0, 0);
376c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger	SPEX(gpio1, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P1,
377c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger	     SSB_SPROM1_GPIOA_P1_SHIFT);
378c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger	SPEX(gpio2, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P2, 0);
379c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger	SPEX(gpio3, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P3,
380c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger	     SSB_SPROM1_GPIOB_P3_SHIFT);
381c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger	SPEX(maxpwr_a, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_A,
382c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger	     SSB_SPROM1_MAXPWR_A_SHIFT);
383c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger	SPEX(maxpwr_bg, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_BG, 0);
384c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger	SPEX(itssi_a, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_A,
385c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger	     SSB_SPROM1_ITSSI_A_SHIFT);
386c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger	SPEX(itssi_bg, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_BG, 0);
387c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger	SPEX(boardflags_lo, SSB_SPROM1_BFLLO, 0xFFFF, 0);
388af4b7450788426a113057ce2d85c25b4f4e440d1Michael Buesch	if (out->revision >= 2)
389af4b7450788426a113057ce2d85c25b4f4e440d1Michael Buesch		SPEX(boardflags_hi, SSB_SPROM2_BFLHI, 0xFFFF, 0);
390e861b98d5e1be769ca6483b6df97149b956ea834Michael Buesch
391e861b98d5e1be769ca6483b6df97149b956ea834Michael Buesch	/* Extract the antenna gain values. */
392f8f8a660ba501ad14617ccd0d91a1ed8ce54d6d0Hauke Mehrtens	out->antenna_gain.a0 = r123_extract_antgain(out->revision, in,
393f8f8a660ba501ad14617ccd0d91a1ed8ce54d6d0Hauke Mehrtens						    SSB_SPROM1_AGAIN_BG,
394f8f8a660ba501ad14617ccd0d91a1ed8ce54d6d0Hauke Mehrtens						    SSB_SPROM1_AGAIN_BG_SHIFT);
395f8f8a660ba501ad14617ccd0d91a1ed8ce54d6d0Hauke Mehrtens	out->antenna_gain.a1 = r123_extract_antgain(out->revision, in,
396f8f8a660ba501ad14617ccd0d91a1ed8ce54d6d0Hauke Mehrtens						    SSB_SPROM1_AGAIN_A,
397f8f8a660ba501ad14617ccd0d91a1ed8ce54d6d0Hauke Mehrtens						    SSB_SPROM1_AGAIN_A_SHIFT);
39861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch}
39961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
400172c69a47675dc1ca9c7243c031d8d77701bccc0Rafał Miłecki/* Revs 4 5 and 8 have partially shared layout */
401172c69a47675dc1ca9c7243c031d8d77701bccc0Rafał Miłeckistatic void sprom_extract_r458(struct ssb_sprom *out, const u16 *in)
402172c69a47675dc1ca9c7243c031d8d77701bccc0Rafał Miłecki{
403172c69a47675dc1ca9c7243c031d8d77701bccc0Rafał Miłecki	SPEX(txpid2g[0], SSB_SPROM4_TXPID2G01,
404172c69a47675dc1ca9c7243c031d8d77701bccc0Rafał Miłecki	     SSB_SPROM4_TXPID2G0, SSB_SPROM4_TXPID2G0_SHIFT);
405172c69a47675dc1ca9c7243c031d8d77701bccc0Rafał Miłecki	SPEX(txpid2g[1], SSB_SPROM4_TXPID2G01,
406172c69a47675dc1ca9c7243c031d8d77701bccc0Rafał Miłecki	     SSB_SPROM4_TXPID2G1, SSB_SPROM4_TXPID2G1_SHIFT);
407172c69a47675dc1ca9c7243c031d8d77701bccc0Rafał Miłecki	SPEX(txpid2g[2], SSB_SPROM4_TXPID2G23,
408172c69a47675dc1ca9c7243c031d8d77701bccc0Rafał Miłecki	     SSB_SPROM4_TXPID2G2, SSB_SPROM4_TXPID2G2_SHIFT);
409172c69a47675dc1ca9c7243c031d8d77701bccc0Rafał Miłecki	SPEX(txpid2g[3], SSB_SPROM4_TXPID2G23,
410172c69a47675dc1ca9c7243c031d8d77701bccc0Rafał Miłecki	     SSB_SPROM4_TXPID2G3, SSB_SPROM4_TXPID2G3_SHIFT);
411172c69a47675dc1ca9c7243c031d8d77701bccc0Rafał Miłecki
412172c69a47675dc1ca9c7243c031d8d77701bccc0Rafał Miłecki	SPEX(txpid5gl[0], SSB_SPROM4_TXPID5GL01,
413172c69a47675dc1ca9c7243c031d8d77701bccc0Rafał Miłecki	     SSB_SPROM4_TXPID5GL0, SSB_SPROM4_TXPID5GL0_SHIFT);
414172c69a47675dc1ca9c7243c031d8d77701bccc0Rafał Miłecki	SPEX(txpid5gl[1], SSB_SPROM4_TXPID5GL01,
415172c69a47675dc1ca9c7243c031d8d77701bccc0Rafał Miłecki	     SSB_SPROM4_TXPID5GL1, SSB_SPROM4_TXPID5GL1_SHIFT);
416172c69a47675dc1ca9c7243c031d8d77701bccc0Rafał Miłecki	SPEX(txpid5gl[2], SSB_SPROM4_TXPID5GL23,
417172c69a47675dc1ca9c7243c031d8d77701bccc0Rafał Miłecki	     SSB_SPROM4_TXPID5GL2, SSB_SPROM4_TXPID5GL2_SHIFT);
418172c69a47675dc1ca9c7243c031d8d77701bccc0Rafał Miłecki	SPEX(txpid5gl[3], SSB_SPROM4_TXPID5GL23,
419172c69a47675dc1ca9c7243c031d8d77701bccc0Rafał Miłecki	     SSB_SPROM4_TXPID5GL3, SSB_SPROM4_TXPID5GL3_SHIFT);
420172c69a47675dc1ca9c7243c031d8d77701bccc0Rafał Miłecki
421172c69a47675dc1ca9c7243c031d8d77701bccc0Rafał Miłecki	SPEX(txpid5g[0], SSB_SPROM4_TXPID5G01,
422172c69a47675dc1ca9c7243c031d8d77701bccc0Rafał Miłecki	     SSB_SPROM4_TXPID5G0, SSB_SPROM4_TXPID5G0_SHIFT);
423172c69a47675dc1ca9c7243c031d8d77701bccc0Rafał Miłecki	SPEX(txpid5g[1], SSB_SPROM4_TXPID5G01,
424172c69a47675dc1ca9c7243c031d8d77701bccc0Rafał Miłecki	     SSB_SPROM4_TXPID5G1, SSB_SPROM4_TXPID5G1_SHIFT);
425172c69a47675dc1ca9c7243c031d8d77701bccc0Rafał Miłecki	SPEX(txpid5g[2], SSB_SPROM4_TXPID5G23,
426172c69a47675dc1ca9c7243c031d8d77701bccc0Rafał Miłecki	     SSB_SPROM4_TXPID5G2, SSB_SPROM4_TXPID5G2_SHIFT);
427172c69a47675dc1ca9c7243c031d8d77701bccc0Rafał Miłecki	SPEX(txpid5g[3], SSB_SPROM4_TXPID5G23,
428172c69a47675dc1ca9c7243c031d8d77701bccc0Rafał Miłecki	     SSB_SPROM4_TXPID5G3, SSB_SPROM4_TXPID5G3_SHIFT);
429172c69a47675dc1ca9c7243c031d8d77701bccc0Rafał Miłecki
430172c69a47675dc1ca9c7243c031d8d77701bccc0Rafał Miłecki	SPEX(txpid5gh[0], SSB_SPROM4_TXPID5GH01,
431172c69a47675dc1ca9c7243c031d8d77701bccc0Rafał Miłecki	     SSB_SPROM4_TXPID5GH0, SSB_SPROM4_TXPID5GH0_SHIFT);
432172c69a47675dc1ca9c7243c031d8d77701bccc0Rafał Miłecki	SPEX(txpid5gh[1], SSB_SPROM4_TXPID5GH01,
433172c69a47675dc1ca9c7243c031d8d77701bccc0Rafał Miłecki	     SSB_SPROM4_TXPID5GH1, SSB_SPROM4_TXPID5GH1_SHIFT);
434172c69a47675dc1ca9c7243c031d8d77701bccc0Rafał Miłecki	SPEX(txpid5gh[2], SSB_SPROM4_TXPID5GH23,
435172c69a47675dc1ca9c7243c031d8d77701bccc0Rafał Miłecki	     SSB_SPROM4_TXPID5GH2, SSB_SPROM4_TXPID5GH2_SHIFT);
436172c69a47675dc1ca9c7243c031d8d77701bccc0Rafał Miłecki	SPEX(txpid5gh[3], SSB_SPROM4_TXPID5GH23,
437172c69a47675dc1ca9c7243c031d8d77701bccc0Rafał Miłecki	     SSB_SPROM4_TXPID5GH3, SSB_SPROM4_TXPID5GH3_SHIFT);
438172c69a47675dc1ca9c7243c031d8d77701bccc0Rafał Miłecki}
439172c69a47675dc1ca9c7243c031d8d77701bccc0Rafał Miłecki
440095f695cbb07281682462da0618fffabb499d0beLarry Fingerstatic void sprom_extract_r45(struct ssb_sprom *out, const u16 *in)
44161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch{
442c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger	int i;
443c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger	u16 v;
444095f695cbb07281682462da0618fffabb499d0beLarry Finger	u16 il0mac_offset;
445c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger
446095f695cbb07281682462da0618fffabb499d0beLarry Finger	if (out->revision == 4)
447095f695cbb07281682462da0618fffabb499d0beLarry Finger		il0mac_offset = SSB_SPROM4_IL0MAC;
448095f695cbb07281682462da0618fffabb499d0beLarry Finger	else
449095f695cbb07281682462da0618fffabb499d0beLarry Finger		il0mac_offset = SSB_SPROM5_IL0MAC;
45031ce12fb3ebf88b054deb99ad729e84888bf6125Larry Finger	/* extract the MAC address */
451c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger	for (i = 0; i < 3; i++) {
452095f695cbb07281682462da0618fffabb499d0beLarry Finger		v = in[SPOFF(il0mac_offset) + i];
453c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger		*(((__be16 *)out->il0mac) + i) = cpu_to_be16(v);
454c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger	}
455c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger	SPEX(et0phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET0A, 0);
456c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger	SPEX(et1phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET1A,
457c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger	     SSB_SPROM4_ETHPHY_ET1A_SHIFT);
458095f695cbb07281682462da0618fffabb499d0beLarry Finger	if (out->revision == 4) {
459095f695cbb07281682462da0618fffabb499d0beLarry Finger		SPEX(country_code, SSB_SPROM4_CCODE, 0xFFFF, 0);
460095f695cbb07281682462da0618fffabb499d0beLarry Finger		SPEX(boardflags_lo, SSB_SPROM4_BFLLO, 0xFFFF, 0);
461095f695cbb07281682462da0618fffabb499d0beLarry Finger		SPEX(boardflags_hi, SSB_SPROM4_BFLHI, 0xFFFF, 0);
4626d1d4ea4a82f8c17a3ff7c2f677bc3d41ea7484bRafał Miłecki		SPEX(boardflags2_lo, SSB_SPROM4_BFL2LO, 0xFFFF, 0);
4636d1d4ea4a82f8c17a3ff7c2f677bc3d41ea7484bRafał Miłecki		SPEX(boardflags2_hi, SSB_SPROM4_BFL2HI, 0xFFFF, 0);
464095f695cbb07281682462da0618fffabb499d0beLarry Finger	} else {
465095f695cbb07281682462da0618fffabb499d0beLarry Finger		SPEX(country_code, SSB_SPROM5_CCODE, 0xFFFF, 0);
466095f695cbb07281682462da0618fffabb499d0beLarry Finger		SPEX(boardflags_lo, SSB_SPROM5_BFLLO, 0xFFFF, 0);
467095f695cbb07281682462da0618fffabb499d0beLarry Finger		SPEX(boardflags_hi, SSB_SPROM5_BFLHI, 0xFFFF, 0);
4686d1d4ea4a82f8c17a3ff7c2f677bc3d41ea7484bRafał Miłecki		SPEX(boardflags2_lo, SSB_SPROM5_BFL2LO, 0xFFFF, 0);
4696d1d4ea4a82f8c17a3ff7c2f677bc3d41ea7484bRafał Miłecki		SPEX(boardflags2_hi, SSB_SPROM5_BFL2HI, 0xFFFF, 0);
470095f695cbb07281682462da0618fffabb499d0beLarry Finger	}
471e861b98d5e1be769ca6483b6df97149b956ea834Michael Buesch	SPEX(ant_available_a, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_A,
472e861b98d5e1be769ca6483b6df97149b956ea834Michael Buesch	     SSB_SPROM4_ANTAVAIL_A_SHIFT);
473e861b98d5e1be769ca6483b6df97149b956ea834Michael Buesch	SPEX(ant_available_bg, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_BG,
474e861b98d5e1be769ca6483b6df97149b956ea834Michael Buesch	     SSB_SPROM4_ANTAVAIL_BG_SHIFT);
475d3c319f9c8d9ee2c042c60b8a1bbd909dcc42782Larry Finger	SPEX(maxpwr_bg, SSB_SPROM4_MAXP_BG, SSB_SPROM4_MAXP_BG_MASK, 0);
476d3c319f9c8d9ee2c042c60b8a1bbd909dcc42782Larry Finger	SPEX(itssi_bg, SSB_SPROM4_MAXP_BG, SSB_SPROM4_ITSSI_BG,
477d3c319f9c8d9ee2c042c60b8a1bbd909dcc42782Larry Finger	     SSB_SPROM4_ITSSI_BG_SHIFT);
478d3c319f9c8d9ee2c042c60b8a1bbd909dcc42782Larry Finger	SPEX(maxpwr_a, SSB_SPROM4_MAXP_A, SSB_SPROM4_MAXP_A_MASK, 0);
479d3c319f9c8d9ee2c042c60b8a1bbd909dcc42782Larry Finger	SPEX(itssi_a, SSB_SPROM4_MAXP_A, SSB_SPROM4_ITSSI_A,
480d3c319f9c8d9ee2c042c60b8a1bbd909dcc42782Larry Finger	     SSB_SPROM4_ITSSI_A_SHIFT);
481095f695cbb07281682462da0618fffabb499d0beLarry Finger	if (out->revision == 4) {
482095f695cbb07281682462da0618fffabb499d0beLarry Finger		SPEX(gpio0, SSB_SPROM4_GPIOA, SSB_SPROM4_GPIOA_P0, 0);
483095f695cbb07281682462da0618fffabb499d0beLarry Finger		SPEX(gpio1, SSB_SPROM4_GPIOA, SSB_SPROM4_GPIOA_P1,
484095f695cbb07281682462da0618fffabb499d0beLarry Finger		     SSB_SPROM4_GPIOA_P1_SHIFT);
485095f695cbb07281682462da0618fffabb499d0beLarry Finger		SPEX(gpio2, SSB_SPROM4_GPIOB, SSB_SPROM4_GPIOB_P2, 0);
486095f695cbb07281682462da0618fffabb499d0beLarry Finger		SPEX(gpio3, SSB_SPROM4_GPIOB, SSB_SPROM4_GPIOB_P3,
487095f695cbb07281682462da0618fffabb499d0beLarry Finger		     SSB_SPROM4_GPIOB_P3_SHIFT);
488095f695cbb07281682462da0618fffabb499d0beLarry Finger	} else {
489095f695cbb07281682462da0618fffabb499d0beLarry Finger		SPEX(gpio0, SSB_SPROM5_GPIOA, SSB_SPROM5_GPIOA_P0, 0);
490095f695cbb07281682462da0618fffabb499d0beLarry Finger		SPEX(gpio1, SSB_SPROM5_GPIOA, SSB_SPROM5_GPIOA_P1,
491095f695cbb07281682462da0618fffabb499d0beLarry Finger		     SSB_SPROM5_GPIOA_P1_SHIFT);
492095f695cbb07281682462da0618fffabb499d0beLarry Finger		SPEX(gpio2, SSB_SPROM5_GPIOB, SSB_SPROM5_GPIOB_P2, 0);
493095f695cbb07281682462da0618fffabb499d0beLarry Finger		SPEX(gpio3, SSB_SPROM5_GPIOB, SSB_SPROM5_GPIOB_P3,
494095f695cbb07281682462da0618fffabb499d0beLarry Finger		     SSB_SPROM5_GPIOB_P3_SHIFT);
495095f695cbb07281682462da0618fffabb499d0beLarry Finger	}
496e861b98d5e1be769ca6483b6df97149b956ea834Michael Buesch
497e861b98d5e1be769ca6483b6df97149b956ea834Michael Buesch	/* Extract the antenna gain values. */
498f8f8a660ba501ad14617ccd0d91a1ed8ce54d6d0Hauke Mehrtens	SPEX(antenna_gain.a0, SSB_SPROM4_AGAIN01,
499e861b98d5e1be769ca6483b6df97149b956ea834Michael Buesch	     SSB_SPROM4_AGAIN0, SSB_SPROM4_AGAIN0_SHIFT);
500f8f8a660ba501ad14617ccd0d91a1ed8ce54d6d0Hauke Mehrtens	SPEX(antenna_gain.a1, SSB_SPROM4_AGAIN01,
501e861b98d5e1be769ca6483b6df97149b956ea834Michael Buesch	     SSB_SPROM4_AGAIN1, SSB_SPROM4_AGAIN1_SHIFT);
502f8f8a660ba501ad14617ccd0d91a1ed8ce54d6d0Hauke Mehrtens	SPEX(antenna_gain.a2, SSB_SPROM4_AGAIN23,
503e861b98d5e1be769ca6483b6df97149b956ea834Michael Buesch	     SSB_SPROM4_AGAIN2, SSB_SPROM4_AGAIN2_SHIFT);
504f8f8a660ba501ad14617ccd0d91a1ed8ce54d6d0Hauke Mehrtens	SPEX(antenna_gain.a3, SSB_SPROM4_AGAIN23,
505e861b98d5e1be769ca6483b6df97149b956ea834Michael Buesch	     SSB_SPROM4_AGAIN3, SSB_SPROM4_AGAIN3_SHIFT);
506e861b98d5e1be769ca6483b6df97149b956ea834Michael Buesch
507172c69a47675dc1ca9c7243c031d8d77701bccc0Rafał Miłecki	sprom_extract_r458(out, in);
508172c69a47675dc1ca9c7243c031d8d77701bccc0Rafał Miłecki
509c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger	/* TODO - get remaining rev 4 stuff needed */
51061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch}
51161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
5126b1c7c67603efdf0b39f6056989b0f8194cdc1f3Michael Bueschstatic void sprom_extract_r8(struct ssb_sprom *out, const u16 *in)
5136b1c7c67603efdf0b39f6056989b0f8194cdc1f3Michael Buesch{
5146b1c7c67603efdf0b39f6056989b0f8194cdc1f3Michael Buesch	int i;
515b0f70292053a0f68f406564a721a7a3f2d66b44fRafał Miłecki	u16 v, o;
516b0f70292053a0f68f406564a721a7a3f2d66b44fRafał Miłecki	u16 pwr_info_offset[] = {
517b0f70292053a0f68f406564a721a7a3f2d66b44fRafał Miłecki		SSB_SROM8_PWR_INFO_CORE0, SSB_SROM8_PWR_INFO_CORE1,
518b0f70292053a0f68f406564a721a7a3f2d66b44fRafał Miłecki		SSB_SROM8_PWR_INFO_CORE2, SSB_SROM8_PWR_INFO_CORE3
519b0f70292053a0f68f406564a721a7a3f2d66b44fRafał Miłecki	};
520b0f70292053a0f68f406564a721a7a3f2d66b44fRafał Miłecki	BUILD_BUG_ON(ARRAY_SIZE(pwr_info_offset) !=
521b0f70292053a0f68f406564a721a7a3f2d66b44fRafał Miłecki			ARRAY_SIZE(out->core_pwr_info));
5226b1c7c67603efdf0b39f6056989b0f8194cdc1f3Michael Buesch
5236b1c7c67603efdf0b39f6056989b0f8194cdc1f3Michael Buesch	/* extract the MAC address */
5246b1c7c67603efdf0b39f6056989b0f8194cdc1f3Michael Buesch	for (i = 0; i < 3; i++) {
525f0ea6ce14ae2a72a353ddf8ab370c09ba403d897Gábor Stefanik		v = in[SPOFF(SSB_SPROM8_IL0MAC) + i];
5266b1c7c67603efdf0b39f6056989b0f8194cdc1f3Michael Buesch		*(((__be16 *)out->il0mac) + i) = cpu_to_be16(v);
5276b1c7c67603efdf0b39f6056989b0f8194cdc1f3Michael Buesch	}
5286b1c7c67603efdf0b39f6056989b0f8194cdc1f3Michael Buesch	SPEX(country_code, SSB_SPROM8_CCODE, 0xFFFF, 0);
5296b1c7c67603efdf0b39f6056989b0f8194cdc1f3Michael Buesch	SPEX(boardflags_lo, SSB_SPROM8_BFLLO, 0xFFFF, 0);
5306b1c7c67603efdf0b39f6056989b0f8194cdc1f3Michael Buesch	SPEX(boardflags_hi, SSB_SPROM8_BFLHI, 0xFFFF, 0);
531f679056b2fdd4e9b7c8eb42ba447cd9646236305Gábor Stefanik	SPEX(boardflags2_lo, SSB_SPROM8_BFL2LO, 0xFFFF, 0);
532f679056b2fdd4e9b7c8eb42ba447cd9646236305Gábor Stefanik	SPEX(boardflags2_hi, SSB_SPROM8_BFL2HI, 0xFFFF, 0);
5336b1c7c67603efdf0b39f6056989b0f8194cdc1f3Michael Buesch	SPEX(ant_available_a, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_A,
5346b1c7c67603efdf0b39f6056989b0f8194cdc1f3Michael Buesch	     SSB_SPROM8_ANTAVAIL_A_SHIFT);
5356b1c7c67603efdf0b39f6056989b0f8194cdc1f3Michael Buesch	SPEX(ant_available_bg, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_BG,
5366b1c7c67603efdf0b39f6056989b0f8194cdc1f3Michael Buesch	     SSB_SPROM8_ANTAVAIL_BG_SHIFT);
5376b1c7c67603efdf0b39f6056989b0f8194cdc1f3Michael Buesch	SPEX(maxpwr_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_MAXP_BG_MASK, 0);
5386b1c7c67603efdf0b39f6056989b0f8194cdc1f3Michael Buesch	SPEX(itssi_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_ITSSI_BG,
5396b1c7c67603efdf0b39f6056989b0f8194cdc1f3Michael Buesch	     SSB_SPROM8_ITSSI_BG_SHIFT);
5406b1c7c67603efdf0b39f6056989b0f8194cdc1f3Michael Buesch	SPEX(maxpwr_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_MAXP_A_MASK, 0);
5416b1c7c67603efdf0b39f6056989b0f8194cdc1f3Michael Buesch	SPEX(itssi_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_ITSSI_A,
5426b1c7c67603efdf0b39f6056989b0f8194cdc1f3Michael Buesch	     SSB_SPROM8_ITSSI_A_SHIFT);
543f679056b2fdd4e9b7c8eb42ba447cd9646236305Gábor Stefanik	SPEX(maxpwr_ah, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AH_MASK, 0);
544f679056b2fdd4e9b7c8eb42ba447cd9646236305Gábor Stefanik	SPEX(maxpwr_al, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AL_MASK,
545f679056b2fdd4e9b7c8eb42ba447cd9646236305Gábor Stefanik	     SSB_SPROM8_MAXP_AL_SHIFT);
5466b1c7c67603efdf0b39f6056989b0f8194cdc1f3Michael Buesch	SPEX(gpio0, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P0, 0);
5476b1c7c67603efdf0b39f6056989b0f8194cdc1f3Michael Buesch	SPEX(gpio1, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P1,
5486b1c7c67603efdf0b39f6056989b0f8194cdc1f3Michael Buesch	     SSB_SPROM8_GPIOA_P1_SHIFT);
5496b1c7c67603efdf0b39f6056989b0f8194cdc1f3Michael Buesch	SPEX(gpio2, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P2, 0);
5506b1c7c67603efdf0b39f6056989b0f8194cdc1f3Michael Buesch	SPEX(gpio3, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P3,
5516b1c7c67603efdf0b39f6056989b0f8194cdc1f3Michael Buesch	     SSB_SPROM8_GPIOB_P3_SHIFT);
552f679056b2fdd4e9b7c8eb42ba447cd9646236305Gábor Stefanik	SPEX(tri2g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI2G, 0);
553f679056b2fdd4e9b7c8eb42ba447cd9646236305Gábor Stefanik	SPEX(tri5g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI5G,
554f679056b2fdd4e9b7c8eb42ba447cd9646236305Gábor Stefanik	     SSB_SPROM8_TRI5G_SHIFT);
555f679056b2fdd4e9b7c8eb42ba447cd9646236305Gábor Stefanik	SPEX(tri5gl, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GL, 0);
556f679056b2fdd4e9b7c8eb42ba447cd9646236305Gábor Stefanik	SPEX(tri5gh, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GH,
557f679056b2fdd4e9b7c8eb42ba447cd9646236305Gábor Stefanik	     SSB_SPROM8_TRI5GH_SHIFT);
558f679056b2fdd4e9b7c8eb42ba447cd9646236305Gábor Stefanik	SPEX(rxpo2g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO2G, 0);
559f679056b2fdd4e9b7c8eb42ba447cd9646236305Gábor Stefanik	SPEX(rxpo5g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO5G,
560f679056b2fdd4e9b7c8eb42ba447cd9646236305Gábor Stefanik	     SSB_SPROM8_RXPO5G_SHIFT);
561f679056b2fdd4e9b7c8eb42ba447cd9646236305Gábor Stefanik	SPEX(rssismf2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMF2G, 0);
562f679056b2fdd4e9b7c8eb42ba447cd9646236305Gábor Stefanik	SPEX(rssismc2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMC2G,
563f679056b2fdd4e9b7c8eb42ba447cd9646236305Gábor Stefanik	     SSB_SPROM8_RSSISMC2G_SHIFT);
564f679056b2fdd4e9b7c8eb42ba447cd9646236305Gábor Stefanik	SPEX(rssisav2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISAV2G,
565f679056b2fdd4e9b7c8eb42ba447cd9646236305Gábor Stefanik	     SSB_SPROM8_RSSISAV2G_SHIFT);
566f679056b2fdd4e9b7c8eb42ba447cd9646236305Gábor Stefanik	SPEX(bxa2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_BXA2G,
567f679056b2fdd4e9b7c8eb42ba447cd9646236305Gábor Stefanik	     SSB_SPROM8_BXA2G_SHIFT);
568f679056b2fdd4e9b7c8eb42ba447cd9646236305Gábor Stefanik	SPEX(rssismf5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMF5G, 0);
569f679056b2fdd4e9b7c8eb42ba447cd9646236305Gábor Stefanik	SPEX(rssismc5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMC5G,
570f679056b2fdd4e9b7c8eb42ba447cd9646236305Gábor Stefanik	     SSB_SPROM8_RSSISMC5G_SHIFT);
571f679056b2fdd4e9b7c8eb42ba447cd9646236305Gábor Stefanik	SPEX(rssisav5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISAV5G,
572f679056b2fdd4e9b7c8eb42ba447cd9646236305Gábor Stefanik	     SSB_SPROM8_RSSISAV5G_SHIFT);
573f679056b2fdd4e9b7c8eb42ba447cd9646236305Gábor Stefanik	SPEX(bxa5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_BXA5G,
574f679056b2fdd4e9b7c8eb42ba447cd9646236305Gábor Stefanik	     SSB_SPROM8_BXA5G_SHIFT);
575f679056b2fdd4e9b7c8eb42ba447cd9646236305Gábor Stefanik	SPEX(pa0b0, SSB_SPROM8_PA0B0, 0xFFFF, 0);
576f679056b2fdd4e9b7c8eb42ba447cd9646236305Gábor Stefanik	SPEX(pa0b1, SSB_SPROM8_PA0B1, 0xFFFF, 0);
577f679056b2fdd4e9b7c8eb42ba447cd9646236305Gábor Stefanik	SPEX(pa0b2, SSB_SPROM8_PA0B2, 0xFFFF, 0);
578f679056b2fdd4e9b7c8eb42ba447cd9646236305Gábor Stefanik	SPEX(pa1b0, SSB_SPROM8_PA1B0, 0xFFFF, 0);
579f679056b2fdd4e9b7c8eb42ba447cd9646236305Gábor Stefanik	SPEX(pa1b1, SSB_SPROM8_PA1B1, 0xFFFF, 0);
580f679056b2fdd4e9b7c8eb42ba447cd9646236305Gábor Stefanik	SPEX(pa1b2, SSB_SPROM8_PA1B2, 0xFFFF, 0);
581f679056b2fdd4e9b7c8eb42ba447cd9646236305Gábor Stefanik	SPEX(pa1lob0, SSB_SPROM8_PA1LOB0, 0xFFFF, 0);
582f679056b2fdd4e9b7c8eb42ba447cd9646236305Gábor Stefanik	SPEX(pa1lob1, SSB_SPROM8_PA1LOB1, 0xFFFF, 0);
583f679056b2fdd4e9b7c8eb42ba447cd9646236305Gábor Stefanik	SPEX(pa1lob2, SSB_SPROM8_PA1LOB2, 0xFFFF, 0);
584f679056b2fdd4e9b7c8eb42ba447cd9646236305Gábor Stefanik	SPEX(pa1hib0, SSB_SPROM8_PA1HIB0, 0xFFFF, 0);
585f679056b2fdd4e9b7c8eb42ba447cd9646236305Gábor Stefanik	SPEX(pa1hib1, SSB_SPROM8_PA1HIB1, 0xFFFF, 0);
586f679056b2fdd4e9b7c8eb42ba447cd9646236305Gábor Stefanik	SPEX(pa1hib2, SSB_SPROM8_PA1HIB2, 0xFFFF, 0);
587f679056b2fdd4e9b7c8eb42ba447cd9646236305Gábor Stefanik	SPEX(cck2gpo, SSB_SPROM8_CCK2GPO, 0xFFFF, 0);
588f679056b2fdd4e9b7c8eb42ba447cd9646236305Gábor Stefanik	SPEX32(ofdm2gpo, SSB_SPROM8_OFDM2GPO, 0xFFFFFFFF, 0);
589f679056b2fdd4e9b7c8eb42ba447cd9646236305Gábor Stefanik	SPEX32(ofdm5glpo, SSB_SPROM8_OFDM5GLPO, 0xFFFFFFFF, 0);
590f679056b2fdd4e9b7c8eb42ba447cd9646236305Gábor Stefanik	SPEX32(ofdm5gpo, SSB_SPROM8_OFDM5GPO, 0xFFFFFFFF, 0);
591f679056b2fdd4e9b7c8eb42ba447cd9646236305Gábor Stefanik	SPEX32(ofdm5ghpo, SSB_SPROM8_OFDM5GHPO, 0xFFFFFFFF, 0);
5926b1c7c67603efdf0b39f6056989b0f8194cdc1f3Michael Buesch
5936b1c7c67603efdf0b39f6056989b0f8194cdc1f3Michael Buesch	/* Extract the antenna gain values. */
594f8f8a660ba501ad14617ccd0d91a1ed8ce54d6d0Hauke Mehrtens	SPEX(antenna_gain.a0, SSB_SPROM8_AGAIN01,
5956b1c7c67603efdf0b39f6056989b0f8194cdc1f3Michael Buesch	     SSB_SPROM8_AGAIN0, SSB_SPROM8_AGAIN0_SHIFT);
596f8f8a660ba501ad14617ccd0d91a1ed8ce54d6d0Hauke Mehrtens	SPEX(antenna_gain.a1, SSB_SPROM8_AGAIN01,
5976b1c7c67603efdf0b39f6056989b0f8194cdc1f3Michael Buesch	     SSB_SPROM8_AGAIN1, SSB_SPROM8_AGAIN1_SHIFT);
598f8f8a660ba501ad14617ccd0d91a1ed8ce54d6d0Hauke Mehrtens	SPEX(antenna_gain.a2, SSB_SPROM8_AGAIN23,
5996b1c7c67603efdf0b39f6056989b0f8194cdc1f3Michael Buesch	     SSB_SPROM8_AGAIN2, SSB_SPROM8_AGAIN2_SHIFT);
600f8f8a660ba501ad14617ccd0d91a1ed8ce54d6d0Hauke Mehrtens	SPEX(antenna_gain.a3, SSB_SPROM8_AGAIN23,
6016b1c7c67603efdf0b39f6056989b0f8194cdc1f3Michael Buesch	     SSB_SPROM8_AGAIN3, SSB_SPROM8_AGAIN3_SHIFT);
6026b1c7c67603efdf0b39f6056989b0f8194cdc1f3Michael Buesch
603b0f70292053a0f68f406564a721a7a3f2d66b44fRafał Miłecki	/* Extract cores power info info */
604b0f70292053a0f68f406564a721a7a3f2d66b44fRafał Miłecki	for (i = 0; i < ARRAY_SIZE(pwr_info_offset); i++) {
605b0f70292053a0f68f406564a721a7a3f2d66b44fRafał Miłecki		o = pwr_info_offset[i];
606b0f70292053a0f68f406564a721a7a3f2d66b44fRafał Miłecki		SPEX(core_pwr_info[i].itssi_2g, o + SSB_SROM8_2G_MAXP_ITSSI,
607b0f70292053a0f68f406564a721a7a3f2d66b44fRafał Miłecki			SSB_SPROM8_2G_ITSSI, SSB_SPROM8_2G_ITSSI_SHIFT);
608b0f70292053a0f68f406564a721a7a3f2d66b44fRafał Miłecki		SPEX(core_pwr_info[i].maxpwr_2g, o + SSB_SROM8_2G_MAXP_ITSSI,
609b0f70292053a0f68f406564a721a7a3f2d66b44fRafał Miłecki			SSB_SPROM8_2G_MAXP, 0);
610b0f70292053a0f68f406564a721a7a3f2d66b44fRafał Miłecki
611b0f70292053a0f68f406564a721a7a3f2d66b44fRafał Miłecki		SPEX(core_pwr_info[i].pa_2g[0], o + SSB_SROM8_2G_PA_0, ~0, 0);
612b0f70292053a0f68f406564a721a7a3f2d66b44fRafał Miłecki		SPEX(core_pwr_info[i].pa_2g[1], o + SSB_SROM8_2G_PA_1, ~0, 0);
613b0f70292053a0f68f406564a721a7a3f2d66b44fRafał Miłecki		SPEX(core_pwr_info[i].pa_2g[2], o + SSB_SROM8_2G_PA_2, ~0, 0);
614b0f70292053a0f68f406564a721a7a3f2d66b44fRafał Miłecki
615b0f70292053a0f68f406564a721a7a3f2d66b44fRafał Miłecki		SPEX(core_pwr_info[i].itssi_5g, o + SSB_SROM8_5G_MAXP_ITSSI,
616b0f70292053a0f68f406564a721a7a3f2d66b44fRafał Miłecki			SSB_SPROM8_5G_ITSSI, SSB_SPROM8_5G_ITSSI_SHIFT);
617b0f70292053a0f68f406564a721a7a3f2d66b44fRafał Miłecki		SPEX(core_pwr_info[i].maxpwr_5g, o + SSB_SROM8_5G_MAXP_ITSSI,
618b0f70292053a0f68f406564a721a7a3f2d66b44fRafał Miłecki			SSB_SPROM8_5G_MAXP, 0);
619b0f70292053a0f68f406564a721a7a3f2d66b44fRafał Miłecki		SPEX(core_pwr_info[i].maxpwr_5gh, o + SSB_SPROM8_5GHL_MAXP,
620b0f70292053a0f68f406564a721a7a3f2d66b44fRafał Miłecki			SSB_SPROM8_5GH_MAXP, 0);
621b0f70292053a0f68f406564a721a7a3f2d66b44fRafał Miłecki		SPEX(core_pwr_info[i].maxpwr_5gl, o + SSB_SPROM8_5GHL_MAXP,
622b0f70292053a0f68f406564a721a7a3f2d66b44fRafał Miłecki			SSB_SPROM8_5GL_MAXP, SSB_SPROM8_5GL_MAXP_SHIFT);
623b0f70292053a0f68f406564a721a7a3f2d66b44fRafał Miłecki
624b0f70292053a0f68f406564a721a7a3f2d66b44fRafał Miłecki		SPEX(core_pwr_info[i].pa_5gl[0], o + SSB_SROM8_5GL_PA_0, ~0, 0);
625b0f70292053a0f68f406564a721a7a3f2d66b44fRafał Miłecki		SPEX(core_pwr_info[i].pa_5gl[1], o + SSB_SROM8_5GL_PA_1, ~0, 0);
626b0f70292053a0f68f406564a721a7a3f2d66b44fRafał Miłecki		SPEX(core_pwr_info[i].pa_5gl[2], o + SSB_SROM8_5GL_PA_2, ~0, 0);
627b0f70292053a0f68f406564a721a7a3f2d66b44fRafał Miłecki		SPEX(core_pwr_info[i].pa_5g[0], o + SSB_SROM8_5G_PA_0, ~0, 0);
628b0f70292053a0f68f406564a721a7a3f2d66b44fRafał Miłecki		SPEX(core_pwr_info[i].pa_5g[1], o + SSB_SROM8_5G_PA_1, ~0, 0);
629b0f70292053a0f68f406564a721a7a3f2d66b44fRafał Miłecki		SPEX(core_pwr_info[i].pa_5g[2], o + SSB_SROM8_5G_PA_2, ~0, 0);
630b0f70292053a0f68f406564a721a7a3f2d66b44fRafał Miłecki		SPEX(core_pwr_info[i].pa_5gh[0], o + SSB_SROM8_5GH_PA_0, ~0, 0);
631b0f70292053a0f68f406564a721a7a3f2d66b44fRafał Miłecki		SPEX(core_pwr_info[i].pa_5gh[1], o + SSB_SROM8_5GH_PA_1, ~0, 0);
632b0f70292053a0f68f406564a721a7a3f2d66b44fRafał Miłecki		SPEX(core_pwr_info[i].pa_5gh[2], o + SSB_SROM8_5GH_PA_2, ~0, 0);
633b0f70292053a0f68f406564a721a7a3f2d66b44fRafał Miłecki	}
634b0f70292053a0f68f406564a721a7a3f2d66b44fRafał Miłecki
6358a5ac6ecd56756ee72588627aa23ab6cf9b790dbRafał Miłecki	/* Extract FEM info */
6368a5ac6ecd56756ee72588627aa23ab6cf9b790dbRafał Miłecki	SPEX(fem.ghz2.tssipos, SSB_SPROM8_FEM2G,
6378a5ac6ecd56756ee72588627aa23ab6cf9b790dbRafał Miłecki		SSB_SROM8_FEM_TSSIPOS, SSB_SROM8_FEM_TSSIPOS_SHIFT);
6388a5ac6ecd56756ee72588627aa23ab6cf9b790dbRafał Miłecki	SPEX(fem.ghz2.extpa_gain, SSB_SPROM8_FEM2G,
6398a5ac6ecd56756ee72588627aa23ab6cf9b790dbRafał Miłecki		SSB_SROM8_FEM_EXTPA_GAIN, SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
6408a5ac6ecd56756ee72588627aa23ab6cf9b790dbRafał Miłecki	SPEX(fem.ghz2.pdet_range, SSB_SPROM8_FEM2G,
6418a5ac6ecd56756ee72588627aa23ab6cf9b790dbRafał Miłecki		SSB_SROM8_FEM_PDET_RANGE, SSB_SROM8_FEM_PDET_RANGE_SHIFT);
6428a5ac6ecd56756ee72588627aa23ab6cf9b790dbRafał Miłecki	SPEX(fem.ghz2.tr_iso, SSB_SPROM8_FEM2G,
6438a5ac6ecd56756ee72588627aa23ab6cf9b790dbRafał Miłecki		SSB_SROM8_FEM_TR_ISO, SSB_SROM8_FEM_TR_ISO_SHIFT);
6448a5ac6ecd56756ee72588627aa23ab6cf9b790dbRafał Miłecki	SPEX(fem.ghz2.antswlut, SSB_SPROM8_FEM2G,
6458a5ac6ecd56756ee72588627aa23ab6cf9b790dbRafał Miłecki		SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT);
6468a5ac6ecd56756ee72588627aa23ab6cf9b790dbRafał Miłecki
6478a5ac6ecd56756ee72588627aa23ab6cf9b790dbRafał Miłecki	SPEX(fem.ghz5.tssipos, SSB_SPROM8_FEM5G,
6488a5ac6ecd56756ee72588627aa23ab6cf9b790dbRafał Miłecki		SSB_SROM8_FEM_TSSIPOS, SSB_SROM8_FEM_TSSIPOS_SHIFT);
6498a5ac6ecd56756ee72588627aa23ab6cf9b790dbRafał Miłecki	SPEX(fem.ghz5.extpa_gain, SSB_SPROM8_FEM5G,
6508a5ac6ecd56756ee72588627aa23ab6cf9b790dbRafał Miłecki		SSB_SROM8_FEM_EXTPA_GAIN, SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
6518a5ac6ecd56756ee72588627aa23ab6cf9b790dbRafał Miłecki	SPEX(fem.ghz5.pdet_range, SSB_SPROM8_FEM5G,
6528a5ac6ecd56756ee72588627aa23ab6cf9b790dbRafał Miłecki		SSB_SROM8_FEM_PDET_RANGE, SSB_SROM8_FEM_PDET_RANGE_SHIFT);
6538a5ac6ecd56756ee72588627aa23ab6cf9b790dbRafał Miłecki	SPEX(fem.ghz5.tr_iso, SSB_SPROM8_FEM5G,
6548a5ac6ecd56756ee72588627aa23ab6cf9b790dbRafał Miłecki		SSB_SROM8_FEM_TR_ISO, SSB_SROM8_FEM_TR_ISO_SHIFT);
6558a5ac6ecd56756ee72588627aa23ab6cf9b790dbRafał Miłecki	SPEX(fem.ghz5.antswlut, SSB_SPROM8_FEM5G,
6568a5ac6ecd56756ee72588627aa23ab6cf9b790dbRafał Miłecki		SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT);
6578a5ac6ecd56756ee72588627aa23ab6cf9b790dbRafał Miłecki
658172c69a47675dc1ca9c7243c031d8d77701bccc0Rafał Miłecki	sprom_extract_r458(out, in);
659172c69a47675dc1ca9c7243c031d8d77701bccc0Rafał Miłecki
6606b1c7c67603efdf0b39f6056989b0f8194cdc1f3Michael Buesch	/* TODO - get remaining rev 8 stuff needed */
6616b1c7c67603efdf0b39f6056989b0f8194cdc1f3Michael Buesch}
6626b1c7c67603efdf0b39f6056989b0f8194cdc1f3Michael Buesch
663c272ef4403c271799a7f09a4ab7a236c86643843Larry Fingerstatic int sprom_extract(struct ssb_bus *bus, struct ssb_sprom *out,
664c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger			 const u16 *in, u16 size)
66561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch{
66661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	memset(out, 0, sizeof(*out));
66761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
668c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger	out->revision = in[size - 1] & 0x00FF;
669e861b98d5e1be769ca6483b6df97149b956ea834Michael Buesch	ssb_dprintk(KERN_DEBUG PFX "SPROM revision %d detected.\n", out->revision);
67031ce12fb3ebf88b054deb99ad729e84888bf6125Larry Finger	memset(out->et0mac, 0xFF, 6);		/* preset et0 and et1 mac */
67131ce12fb3ebf88b054deb99ad729e84888bf6125Larry Finger	memset(out->et1mac, 0xFF, 6);
67254435f9ec837cf0bb0ea02a2bb6362a6aaef5250Rafał Miłecki
67361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	if ((bus->chip_id & 0xFF00) == 0x4400) {
67461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		/* Workaround: The BCM44XX chip has a stupid revision
67561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		 * number stored in the SPROM.
67661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		 * Always extract r1. */
677c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger		out->revision = 1;
67854435f9ec837cf0bb0ea02a2bb6362a6aaef5250Rafał Miłecki		ssb_dprintk(KERN_DEBUG PFX "SPROM treated as revision %d\n", out->revision);
67954435f9ec837cf0bb0ea02a2bb6362a6aaef5250Rafał Miłecki	}
68054435f9ec837cf0bb0ea02a2bb6362a6aaef5250Rafał Miłecki
68154435f9ec837cf0bb0ea02a2bb6362a6aaef5250Rafał Miłecki	switch (out->revision) {
68254435f9ec837cf0bb0ea02a2bb6362a6aaef5250Rafał Miłecki	case 1:
68354435f9ec837cf0bb0ea02a2bb6362a6aaef5250Rafał Miłecki	case 2:
68454435f9ec837cf0bb0ea02a2bb6362a6aaef5250Rafał Miłecki	case 3:
68554435f9ec837cf0bb0ea02a2bb6362a6aaef5250Rafał Miłecki		sprom_extract_r123(out, in);
68654435f9ec837cf0bb0ea02a2bb6362a6aaef5250Rafał Miłecki		break;
68754435f9ec837cf0bb0ea02a2bb6362a6aaef5250Rafał Miłecki	case 4:
68854435f9ec837cf0bb0ea02a2bb6362a6aaef5250Rafał Miłecki	case 5:
689095f695cbb07281682462da0618fffabb499d0beLarry Finger		sprom_extract_r45(out, in);
69054435f9ec837cf0bb0ea02a2bb6362a6aaef5250Rafał Miłecki		break;
69154435f9ec837cf0bb0ea02a2bb6362a6aaef5250Rafał Miłecki	case 8:
69254435f9ec837cf0bb0ea02a2bb6362a6aaef5250Rafał Miłecki		sprom_extract_r8(out, in);
69354435f9ec837cf0bb0ea02a2bb6362a6aaef5250Rafał Miłecki		break;
69454435f9ec837cf0bb0ea02a2bb6362a6aaef5250Rafał Miłecki	default:
69554435f9ec837cf0bb0ea02a2bb6362a6aaef5250Rafał Miłecki		ssb_printk(KERN_WARNING PFX "Unsupported SPROM"
69698605c2ed4963c44aa72799e697ae4bc7085ffcdRafał Miłecki			   " revision %d detected. Will extract"
69754435f9ec837cf0bb0ea02a2bb6362a6aaef5250Rafał Miłecki			   " v1\n", out->revision);
69854435f9ec837cf0bb0ea02a2bb6362a6aaef5250Rafał Miłecki		out->revision = 1;
69954435f9ec837cf0bb0ea02a2bb6362a6aaef5250Rafał Miłecki		sprom_extract_r123(out, in);
70061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	}
70161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
7024503183aa32e6886400d82282292934fa64a81b0Larry Finger	if (out->boardflags_lo == 0xFFFF)
7034503183aa32e6886400d82282292934fa64a81b0Larry Finger		out->boardflags_lo = 0;  /* per specs */
7044503183aa32e6886400d82282292934fa64a81b0Larry Finger	if (out->boardflags_hi == 0xFFFF)
7054503183aa32e6886400d82282292934fa64a81b0Larry Finger		out->boardflags_hi = 0;  /* per specs */
7064503183aa32e6886400d82282292934fa64a81b0Larry Finger
70761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	return 0;
70861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch}
70961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
71061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschstatic int ssb_pci_sprom_get(struct ssb_bus *bus,
71161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch			     struct ssb_sprom *sprom)
71261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch{
713ca4a0831917d6541b45f03542257fcb20dc9cf4aRafał Miłecki	int err;
71461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	u16 *buf;
71561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
716d53cdbb94a52a920d5420ed64d986c3523a56743John W. Linville	if (!ssb_is_sprom_available(bus)) {
717d53cdbb94a52a920d5420ed64d986c3523a56743John W. Linville		ssb_printk(KERN_ERR PFX "No SPROM available!\n");
718d53cdbb94a52a920d5420ed64d986c3523a56743John W. Linville		return -ENODEV;
719d53cdbb94a52a920d5420ed64d986c3523a56743John W. Linville	}
72025985edcedea6396277003854657b5f3cb31a628Lucas De Marchi	if (bus->chipco.dev) {	/* can be unavailable! */
7219d1ac34ec3a67713308ae0883c3359c557f14d17Larry Finger		/*
7229d1ac34ec3a67713308ae0883c3359c557f14d17Larry Finger		 * get SPROM offset: SSB_SPROM_BASE1 except for
7239d1ac34ec3a67713308ae0883c3359c557f14d17Larry Finger		 * chipcommon rev >= 31 or chip ID is 0x4312 and
7249d1ac34ec3a67713308ae0883c3359c557f14d17Larry Finger		 * chipcommon status & 3 == 2
7259d1ac34ec3a67713308ae0883c3359c557f14d17Larry Finger		 */
7269d1ac34ec3a67713308ae0883c3359c557f14d17Larry Finger		if (bus->chipco.dev->id.revision >= 31)
7279d1ac34ec3a67713308ae0883c3359c557f14d17Larry Finger			bus->sprom_offset = SSB_SPROM_BASE31;
7289d1ac34ec3a67713308ae0883c3359c557f14d17Larry Finger		else if (bus->chip_id == 0x4312 &&
7299d1ac34ec3a67713308ae0883c3359c557f14d17Larry Finger			 (bus->chipco.status & 0x03) == 2)
7309d1ac34ec3a67713308ae0883c3359c557f14d17Larry Finger			bus->sprom_offset = SSB_SPROM_BASE31;
7319d1ac34ec3a67713308ae0883c3359c557f14d17Larry Finger		else
7329d1ac34ec3a67713308ae0883c3359c557f14d17Larry Finger			bus->sprom_offset = SSB_SPROM_BASE1;
733da1fdb02d9200ff28b6f3a380d21930335fe5429Christoph Fritz	} else {
734da1fdb02d9200ff28b6f3a380d21930335fe5429Christoph Fritz		bus->sprom_offset = SSB_SPROM_BASE1;
735da1fdb02d9200ff28b6f3a380d21930335fe5429Christoph Fritz	}
7369d1ac34ec3a67713308ae0883c3359c557f14d17Larry Finger	ssb_dprintk(KERN_INFO PFX "SPROM offset is 0x%x\n", bus->sprom_offset);
737ea2db495f92ad2cf3301623e60cb95b4062bc484Rafał Miłecki
738c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger	buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL);
73961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	if (!buf)
740ca4a0831917d6541b45f03542257fcb20dc9cf4aRafał Miłecki		return -ENOMEM;
741c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger	bus->sprom_size = SSB_SPROMSIZE_WORDS_R123;
74261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	sprom_do_read(bus, buf);
743c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger	err = sprom_check_crc(buf, bus->sprom_size);
74461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	if (err) {
7452afc49015db927fea7bc6ca33c0a60bf5d7c2c5fLarry.Finger@lwfinger.net		/* try for a 440 byte SPROM - revision 4 and higher */
7462afc49015db927fea7bc6ca33c0a60bf5d7c2c5fLarry.Finger@lwfinger.net		kfree(buf);
7472afc49015db927fea7bc6ca33c0a60bf5d7c2c5fLarry.Finger@lwfinger.net		buf = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
7482afc49015db927fea7bc6ca33c0a60bf5d7c2c5fLarry.Finger@lwfinger.net			      GFP_KERNEL);
7492afc49015db927fea7bc6ca33c0a60bf5d7c2c5fLarry.Finger@lwfinger.net		if (!buf)
750ca4a0831917d6541b45f03542257fcb20dc9cf4aRafał Miłecki			return -ENOMEM;
7512afc49015db927fea7bc6ca33c0a60bf5d7c2c5fLarry.Finger@lwfinger.net		bus->sprom_size = SSB_SPROMSIZE_WORDS_R4;
7522afc49015db927fea7bc6ca33c0a60bf5d7c2c5fLarry.Finger@lwfinger.net		sprom_do_read(bus, buf);
7532afc49015db927fea7bc6ca33c0a60bf5d7c2c5fLarry.Finger@lwfinger.net		err = sprom_check_crc(buf, bus->sprom_size);
754e79c1ba84c68de9161d541bd2bcc8ea65c89955cMichael Buesch		if (err) {
755e79c1ba84c68de9161d541bd2bcc8ea65c89955cMichael Buesch			/* All CRC attempts failed.
756e79c1ba84c68de9161d541bd2bcc8ea65c89955cMichael Buesch			 * Maybe there is no SPROM on the device?
757b3ae52b6b0335eba547221aad2cb3c50902e3d2dHauke Mehrtens			 * Now we ask the arch code if there is some sprom
758b3ae52b6b0335eba547221aad2cb3c50902e3d2dHauke Mehrtens			 * available for this device in some other storage */
759b3ae52b6b0335eba547221aad2cb3c50902e3d2dHauke Mehrtens			err = ssb_fill_sprom_with_fallback(bus, sprom);
760b3ae52b6b0335eba547221aad2cb3c50902e3d2dHauke Mehrtens			if (err) {
761b3ae52b6b0335eba547221aad2cb3c50902e3d2dHauke Mehrtens				ssb_printk(KERN_WARNING PFX "WARNING: Using"
762b3ae52b6b0335eba547221aad2cb3c50902e3d2dHauke Mehrtens					   " fallback SPROM failed (err %d)\n",
763b3ae52b6b0335eba547221aad2cb3c50902e3d2dHauke Mehrtens					   err);
764b3ae52b6b0335eba547221aad2cb3c50902e3d2dHauke Mehrtens			} else {
765b3ae52b6b0335eba547221aad2cb3c50902e3d2dHauke Mehrtens				ssb_dprintk(KERN_DEBUG PFX "Using SPROM"
766b3ae52b6b0335eba547221aad2cb3c50902e3d2dHauke Mehrtens					    " revision %d provided by"
767b3ae52b6b0335eba547221aad2cb3c50902e3d2dHauke Mehrtens					    " platform.\n", sprom->revision);
768e79c1ba84c68de9161d541bd2bcc8ea65c89955cMichael Buesch				err = 0;
769e79c1ba84c68de9161d541bd2bcc8ea65c89955cMichael Buesch				goto out_free;
770e79c1ba84c68de9161d541bd2bcc8ea65c89955cMichael Buesch			}
771c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger			ssb_printk(KERN_WARNING PFX "WARNING: Invalid"
772c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger				   " SPROM CRC (corrupt SPROM)\n");
773e79c1ba84c68de9161d541bd2bcc8ea65c89955cMichael Buesch		}
77461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	}
775c272ef4403c271799a7f09a4ab7a236c86643843Larry Finger	err = sprom_extract(bus, sprom, buf, bus->sprom_size);
77661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
777e79c1ba84c68de9161d541bd2bcc8ea65c89955cMichael Bueschout_free:
77861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	kfree(buf);
77961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	return err;
78061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch}
78161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
78261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschstatic void ssb_pci_get_boardinfo(struct ssb_bus *bus,
78361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch				  struct ssb_boardinfo *bi)
78461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch{
785115f9450babbf2ed530db04e16a99df28cec85ddSergei Shtylyov	bi->vendor = bus->host_pci->subsystem_vendor;
786115f9450babbf2ed530db04e16a99df28cec85ddSergei Shtylyov	bi->type = bus->host_pci->subsystem_device;
7872fa2319027dd498edde332afe9a27f1b34b34d7fSergei Shtylyov	bi->rev = bus->host_pci->revision;
78861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch}
78961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
79061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschint ssb_pci_get_invariants(struct ssb_bus *bus,
79161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch			   struct ssb_init_invariants *iv)
79261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch{
79361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	int err;
79461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
79561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	err = ssb_pci_sprom_get(bus, &iv->sprom);
79661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	if (err)
79761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		goto out;
79861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	ssb_pci_get_boardinfo(bus, &iv->boardinfo);
79961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
80061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschout:
80161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	return err;
80261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch}
80361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
80461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch#ifdef CONFIG_SSB_DEBUG
80561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschstatic int ssb_pci_assert_buspower(struct ssb_bus *bus)
80661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch{
80761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	if (likely(bus->powered_up))
80861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		return 0;
80961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
81061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	printk(KERN_ERR PFX "FATAL ERROR: Bus powered down "
81161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	       "while accessing PCI MMIO space\n");
81261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	if (bus->power_warn_count <= 10) {
81361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		bus->power_warn_count++;
81461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		dump_stack();
81561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	}
81661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
81761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	return -ENODEV;
81861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch}
81961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch#else /* DEBUG */
82061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschstatic inline int ssb_pci_assert_buspower(struct ssb_bus *bus)
82161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch{
82261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	return 0;
82361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch}
82461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch#endif /* DEBUG */
82561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
826ffc7689ddae5cbe12bde437ae0f2b386d568b5cdMichael Bueschstatic u8 ssb_pci_read8(struct ssb_device *dev, u16 offset)
827ffc7689ddae5cbe12bde437ae0f2b386d568b5cdMichael Buesch{
828ffc7689ddae5cbe12bde437ae0f2b386d568b5cdMichael Buesch	struct ssb_bus *bus = dev->bus;
829ffc7689ddae5cbe12bde437ae0f2b386d568b5cdMichael Buesch
830ffc7689ddae5cbe12bde437ae0f2b386d568b5cdMichael Buesch	if (unlikely(ssb_pci_assert_buspower(bus)))
831ffc7689ddae5cbe12bde437ae0f2b386d568b5cdMichael Buesch		return 0xFF;
832ffc7689ddae5cbe12bde437ae0f2b386d568b5cdMichael Buesch	if (unlikely(bus->mapped_device != dev)) {
833ffc7689ddae5cbe12bde437ae0f2b386d568b5cdMichael Buesch		if (unlikely(ssb_pci_switch_core(bus, dev)))
834ffc7689ddae5cbe12bde437ae0f2b386d568b5cdMichael Buesch			return 0xFF;
835ffc7689ddae5cbe12bde437ae0f2b386d568b5cdMichael Buesch	}
836ffc7689ddae5cbe12bde437ae0f2b386d568b5cdMichael Buesch	return ioread8(bus->mmio + offset);
837ffc7689ddae5cbe12bde437ae0f2b386d568b5cdMichael Buesch}
838ffc7689ddae5cbe12bde437ae0f2b386d568b5cdMichael Buesch
83961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschstatic u16 ssb_pci_read16(struct ssb_device *dev, u16 offset)
84061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch{
84161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	struct ssb_bus *bus = dev->bus;
84261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
84361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	if (unlikely(ssb_pci_assert_buspower(bus)))
84461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		return 0xFFFF;
84561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	if (unlikely(bus->mapped_device != dev)) {
84661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		if (unlikely(ssb_pci_switch_core(bus, dev)))
84761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch			return 0xFFFF;
84861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	}
8494b402c65a3a17257af45875159395278e4a2f0cdMichael Buesch	return ioread16(bus->mmio + offset);
85061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch}
85161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
85261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschstatic u32 ssb_pci_read32(struct ssb_device *dev, u16 offset)
85361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch{
85461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	struct ssb_bus *bus = dev->bus;
85561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
85661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	if (unlikely(ssb_pci_assert_buspower(bus)))
85761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		return 0xFFFFFFFF;
85861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	if (unlikely(bus->mapped_device != dev)) {
85961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		if (unlikely(ssb_pci_switch_core(bus, dev)))
86061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch			return 0xFFFFFFFF;
86161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	}
8624b402c65a3a17257af45875159395278e4a2f0cdMichael Buesch	return ioread32(bus->mmio + offset);
86361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch}
86461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
865d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch#ifdef CONFIG_SSB_BLOCKIO
866d625a29ba649a4df6027520ffc378f23c0e6883eMichael Bueschstatic void ssb_pci_block_read(struct ssb_device *dev, void *buffer,
867d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch			       size_t count, u16 offset, u8 reg_width)
868d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch{
869d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch	struct ssb_bus *bus = dev->bus;
870d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch	void __iomem *addr = bus->mmio + offset;
871d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch
872d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch	if (unlikely(ssb_pci_assert_buspower(bus)))
873d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch		goto error;
874d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch	if (unlikely(bus->mapped_device != dev)) {
875d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch		if (unlikely(ssb_pci_switch_core(bus, dev)))
876d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch			goto error;
877d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch	}
878d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch	switch (reg_width) {
879d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch	case sizeof(u8):
880d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch		ioread8_rep(addr, buffer, count);
881d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch		break;
882d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch	case sizeof(u16):
883d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch		SSB_WARN_ON(count & 1);
884d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch		ioread16_rep(addr, buffer, count >> 1);
885d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch		break;
886d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch	case sizeof(u32):
887d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch		SSB_WARN_ON(count & 3);
888d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch		ioread32_rep(addr, buffer, count >> 2);
889d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch		break;
890d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch	default:
891d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch		SSB_WARN_ON(1);
892d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch	}
893d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch
894d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch	return;
895d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buescherror:
896d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch	memset(buffer, 0xFF, count);
897d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch}
898d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch#endif /* CONFIG_SSB_BLOCKIO */
899d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch
900ffc7689ddae5cbe12bde437ae0f2b386d568b5cdMichael Bueschstatic void ssb_pci_write8(struct ssb_device *dev, u16 offset, u8 value)
901ffc7689ddae5cbe12bde437ae0f2b386d568b5cdMichael Buesch{
902ffc7689ddae5cbe12bde437ae0f2b386d568b5cdMichael Buesch	struct ssb_bus *bus = dev->bus;
903ffc7689ddae5cbe12bde437ae0f2b386d568b5cdMichael Buesch
904ffc7689ddae5cbe12bde437ae0f2b386d568b5cdMichael Buesch	if (unlikely(ssb_pci_assert_buspower(bus)))
905ffc7689ddae5cbe12bde437ae0f2b386d568b5cdMichael Buesch		return;
906ffc7689ddae5cbe12bde437ae0f2b386d568b5cdMichael Buesch	if (unlikely(bus->mapped_device != dev)) {
907ffc7689ddae5cbe12bde437ae0f2b386d568b5cdMichael Buesch		if (unlikely(ssb_pci_switch_core(bus, dev)))
908ffc7689ddae5cbe12bde437ae0f2b386d568b5cdMichael Buesch			return;
909ffc7689ddae5cbe12bde437ae0f2b386d568b5cdMichael Buesch	}
910ffc7689ddae5cbe12bde437ae0f2b386d568b5cdMichael Buesch	iowrite8(value, bus->mmio + offset);
911ffc7689ddae5cbe12bde437ae0f2b386d568b5cdMichael Buesch}
912ffc7689ddae5cbe12bde437ae0f2b386d568b5cdMichael Buesch
91361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschstatic void ssb_pci_write16(struct ssb_device *dev, u16 offset, u16 value)
91461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch{
91561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	struct ssb_bus *bus = dev->bus;
91661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
91761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	if (unlikely(ssb_pci_assert_buspower(bus)))
91861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		return;
91961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	if (unlikely(bus->mapped_device != dev)) {
92061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		if (unlikely(ssb_pci_switch_core(bus, dev)))
92161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch			return;
92261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	}
9234b402c65a3a17257af45875159395278e4a2f0cdMichael Buesch	iowrite16(value, bus->mmio + offset);
92461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch}
92561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
92661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschstatic void ssb_pci_write32(struct ssb_device *dev, u16 offset, u32 value)
92761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch{
92861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	struct ssb_bus *bus = dev->bus;
92961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
93061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	if (unlikely(ssb_pci_assert_buspower(bus)))
93161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		return;
93261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	if (unlikely(bus->mapped_device != dev)) {
93361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		if (unlikely(ssb_pci_switch_core(bus, dev)))
93461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch			return;
93561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	}
9364b402c65a3a17257af45875159395278e4a2f0cdMichael Buesch	iowrite32(value, bus->mmio + offset);
93761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch}
93861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
939d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch#ifdef CONFIG_SSB_BLOCKIO
940d625a29ba649a4df6027520ffc378f23c0e6883eMichael Bueschstatic void ssb_pci_block_write(struct ssb_device *dev, const void *buffer,
941d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch				size_t count, u16 offset, u8 reg_width)
942d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch{
943d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch	struct ssb_bus *bus = dev->bus;
944d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch	void __iomem *addr = bus->mmio + offset;
945d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch
946d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch	if (unlikely(ssb_pci_assert_buspower(bus)))
947d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch		return;
948d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch	if (unlikely(bus->mapped_device != dev)) {
949d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch		if (unlikely(ssb_pci_switch_core(bus, dev)))
950d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch			return;
951d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch	}
952d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch	switch (reg_width) {
953d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch	case sizeof(u8):
954d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch		iowrite8_rep(addr, buffer, count);
955d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch		break;
956d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch	case sizeof(u16):
957d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch		SSB_WARN_ON(count & 1);
958d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch		iowrite16_rep(addr, buffer, count >> 1);
959d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch		break;
960d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch	case sizeof(u32):
961d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch		SSB_WARN_ON(count & 3);
962d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch		iowrite32_rep(addr, buffer, count >> 2);
963d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch		break;
964d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch	default:
965d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch		SSB_WARN_ON(1);
966d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch	}
967d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch}
968d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch#endif /* CONFIG_SSB_BLOCKIO */
969d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch
97061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch/* Not "static", as it's used in main.c */
97161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschconst struct ssb_bus_ops ssb_pci_ops = {
972ffc7689ddae5cbe12bde437ae0f2b386d568b5cdMichael Buesch	.read8		= ssb_pci_read8,
97361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	.read16		= ssb_pci_read16,
97461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	.read32		= ssb_pci_read32,
975ffc7689ddae5cbe12bde437ae0f2b386d568b5cdMichael Buesch	.write8		= ssb_pci_write8,
97661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	.write16	= ssb_pci_write16,
97761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	.write32	= ssb_pci_write32,
978d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch#ifdef CONFIG_SSB_BLOCKIO
979d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch	.block_read	= ssb_pci_block_read,
980d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch	.block_write	= ssb_pci_block_write,
981d625a29ba649a4df6027520ffc378f23c0e6883eMichael Buesch#endif
98261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch};
98361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
98461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschstatic ssize_t ssb_pci_attr_sprom_show(struct device *pcidev,
98561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch				       struct device_attribute *attr,
98661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch				       char *buf)
98761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch{
98861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev);
98961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	struct ssb_bus *bus;
99061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
99161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	bus = ssb_pci_dev_to_bus(pdev);
99261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	if (!bus)
993e7ec2e3230633a858af1b0b359f6c4670dbeb997Michael Buesch		return -ENODEV;
99461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
995e7ec2e3230633a858af1b0b359f6c4670dbeb997Michael Buesch	return ssb_attr_sprom_show(bus, buf, sprom_do_read);
99661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch}
99761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
99861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschstatic ssize_t ssb_pci_attr_sprom_store(struct device *pcidev,
99961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch					struct device_attribute *attr,
100061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch					const char *buf, size_t count)
100161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch{
100261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev);
100361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	struct ssb_bus *bus;
100461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
100561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	bus = ssb_pci_dev_to_bus(pdev);
100661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	if (!bus)
1007e7ec2e3230633a858af1b0b359f6c4670dbeb997Michael Buesch		return -ENODEV;
100861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
1009e7ec2e3230633a858af1b0b359f6c4670dbeb997Michael Buesch	return ssb_attr_sprom_store(bus, buf, count,
1010e7ec2e3230633a858af1b0b359f6c4670dbeb997Michael Buesch				    sprom_check_crc, sprom_do_write);
101161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch}
101261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
101361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschstatic DEVICE_ATTR(ssb_sprom, 0600,
101461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		   ssb_pci_attr_sprom_show,
101561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		   ssb_pci_attr_sprom_store);
101661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
101761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschvoid ssb_pci_exit(struct ssb_bus *bus)
101861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch{
101961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	struct pci_dev *pdev;
102061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
102161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	if (bus->bustype != SSB_BUSTYPE_PCI)
102261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		return;
102361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
102461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	pdev = bus->host_pci;
102561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	device_remove_file(&pdev->dev, &dev_attr_ssb_sprom);
102661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch}
102761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
102861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschint ssb_pci_init(struct ssb_bus *bus)
102961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch{
103061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	struct pci_dev *pdev;
103161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	int err;
103261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
103361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	if (bus->bustype != SSB_BUSTYPE_PCI)
103461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		return 0;
103561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
103661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	pdev = bus->host_pci;
1037e7ec2e3230633a858af1b0b359f6c4670dbeb997Michael Buesch	mutex_init(&bus->sprom_mutex);
103861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	err = device_create_file(&pdev->dev, &dev_attr_ssb_sprom);
103961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	if (err)
104061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		goto out;
104161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
104261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschout:
104361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	return err;
104461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch}
1045