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