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