161e115a5SMichael Buesch /* 261e115a5SMichael Buesch * Sonics Silicon Backplane PCI-Hostbus related functions. 361e115a5SMichael Buesch * 4eb032b98SMichael Büsch * Copyright (C) 2005-2006 Michael Buesch <m@bues.ch> 561e115a5SMichael Buesch * Copyright (C) 2005 Martin Langer <martin-langer@gmx.de> 661e115a5SMichael Buesch * Copyright (C) 2005 Stefano Brivio <st3@riseup.net> 761e115a5SMichael Buesch * Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org> 861e115a5SMichael Buesch * Copyright (C) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch> 961e115a5SMichael Buesch * 1061e115a5SMichael Buesch * Derived from the Broadcom 4400 device driver. 1161e115a5SMichael Buesch * Copyright (C) 2002 David S. Miller (davem@redhat.com) 1261e115a5SMichael Buesch * Fixed by Pekka Pietikainen (pp@ee.oulu.fi) 1361e115a5SMichael Buesch * Copyright (C) 2006 Broadcom Corporation. 1461e115a5SMichael Buesch * 1561e115a5SMichael Buesch * Licensed under the GNU/GPL. See COPYING for details. 1661e115a5SMichael Buesch */ 1761e115a5SMichael Buesch 1861e115a5SMichael Buesch #include <linux/ssb/ssb.h> 1961e115a5SMichael Buesch #include <linux/ssb/ssb_regs.h> 205a0e3ad6STejun Heo #include <linux/slab.h> 2161e115a5SMichael Buesch #include <linux/pci.h> 2261e115a5SMichael Buesch #include <linux/delay.h> 2361e115a5SMichael Buesch 2461e115a5SMichael Buesch #include "ssb_private.h" 2561e115a5SMichael Buesch 2661e115a5SMichael Buesch 2761e115a5SMichael Buesch /* Define the following to 1 to enable a printk on each coreswitch. */ 2861e115a5SMichael Buesch #define SSB_VERBOSE_PCICORESWITCH_DEBUG 0 2961e115a5SMichael Buesch 3061e115a5SMichael Buesch 3161e115a5SMichael Buesch /* Lowlevel coreswitching */ 3261e115a5SMichael Buesch int ssb_pci_switch_coreidx(struct ssb_bus *bus, u8 coreidx) 3361e115a5SMichael Buesch { 3461e115a5SMichael Buesch int err; 3561e115a5SMichael Buesch int attempts = 0; 3661e115a5SMichael Buesch u32 cur_core; 3761e115a5SMichael Buesch 3861e115a5SMichael Buesch while (1) { 3961e115a5SMichael Buesch err = pci_write_config_dword(bus->host_pci, SSB_BAR0_WIN, 4061e115a5SMichael Buesch (coreidx * SSB_CORE_SIZE) 4161e115a5SMichael Buesch + SSB_ENUM_BASE); 4261e115a5SMichael Buesch if (err) 4361e115a5SMichael Buesch goto error; 4461e115a5SMichael Buesch err = pci_read_config_dword(bus->host_pci, SSB_BAR0_WIN, 4561e115a5SMichael Buesch &cur_core); 4661e115a5SMichael Buesch if (err) 4761e115a5SMichael Buesch goto error; 4861e115a5SMichael Buesch cur_core = (cur_core - SSB_ENUM_BASE) 4961e115a5SMichael Buesch / SSB_CORE_SIZE; 5061e115a5SMichael Buesch if (cur_core == coreidx) 5161e115a5SMichael Buesch break; 5261e115a5SMichael Buesch 5361e115a5SMichael Buesch if (attempts++ > SSB_BAR0_MAX_RETRIES) 5461e115a5SMichael Buesch goto error; 5561e115a5SMichael Buesch udelay(10); 5661e115a5SMichael Buesch } 5761e115a5SMichael Buesch return 0; 5861e115a5SMichael Buesch error: 5933a606acSJoe Perches ssb_err("Failed to switch to core %u\n", coreidx); 6061e115a5SMichael Buesch return -ENODEV; 6161e115a5SMichael Buesch } 6261e115a5SMichael Buesch 6361e115a5SMichael Buesch int ssb_pci_switch_core(struct ssb_bus *bus, 6461e115a5SMichael Buesch struct ssb_device *dev) 6561e115a5SMichael Buesch { 6661e115a5SMichael Buesch int err; 6761e115a5SMichael Buesch unsigned long flags; 6861e115a5SMichael Buesch 6961e115a5SMichael Buesch #if SSB_VERBOSE_PCICORESWITCH_DEBUG 7033a606acSJoe Perches ssb_info("Switching to %s core, index %d\n", 7161e115a5SMichael Buesch ssb_core_name(dev->id.coreid), 7261e115a5SMichael Buesch dev->core_index); 7361e115a5SMichael Buesch #endif 7461e115a5SMichael Buesch 7561e115a5SMichael Buesch spin_lock_irqsave(&bus->bar_lock, flags); 7661e115a5SMichael Buesch err = ssb_pci_switch_coreidx(bus, dev->core_index); 7761e115a5SMichael Buesch if (!err) 7861e115a5SMichael Buesch bus->mapped_device = dev; 7961e115a5SMichael Buesch spin_unlock_irqrestore(&bus->bar_lock, flags); 8061e115a5SMichael Buesch 8161e115a5SMichael Buesch return err; 8261e115a5SMichael Buesch } 8361e115a5SMichael Buesch 8461e115a5SMichael Buesch /* Enable/disable the on board crystal oscillator and/or PLL. */ 8561e115a5SMichael Buesch int ssb_pci_xtal(struct ssb_bus *bus, u32 what, int turn_on) 8661e115a5SMichael Buesch { 8761e115a5SMichael Buesch int err; 8861e115a5SMichael Buesch u32 in, out, outenable; 8961e115a5SMichael Buesch u16 pci_status; 9061e115a5SMichael Buesch 9161e115a5SMichael Buesch if (bus->bustype != SSB_BUSTYPE_PCI) 9261e115a5SMichael Buesch return 0; 9361e115a5SMichael Buesch 9461e115a5SMichael Buesch err = pci_read_config_dword(bus->host_pci, SSB_GPIO_IN, &in); 9561e115a5SMichael Buesch if (err) 9661e115a5SMichael Buesch goto err_pci; 9761e115a5SMichael Buesch err = pci_read_config_dword(bus->host_pci, SSB_GPIO_OUT, &out); 9861e115a5SMichael Buesch if (err) 9961e115a5SMichael Buesch goto err_pci; 10061e115a5SMichael Buesch err = pci_read_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE, &outenable); 10161e115a5SMichael Buesch if (err) 10261e115a5SMichael Buesch goto err_pci; 10361e115a5SMichael Buesch 10461e115a5SMichael Buesch outenable |= what; 10561e115a5SMichael Buesch 10661e115a5SMichael Buesch if (turn_on) { 10761e115a5SMichael Buesch /* Avoid glitching the clock if GPRS is already using it. 10861e115a5SMichael Buesch * We can't actually read the state of the PLLPD so we infer it 10961e115a5SMichael Buesch * by the value of XTAL_PU which *is* readable via gpioin. 11061e115a5SMichael Buesch */ 11161e115a5SMichael Buesch if (!(in & SSB_GPIO_XTAL)) { 11261e115a5SMichael Buesch if (what & SSB_GPIO_XTAL) { 11361e115a5SMichael Buesch /* Turn the crystal on */ 11461e115a5SMichael Buesch out |= SSB_GPIO_XTAL; 11561e115a5SMichael Buesch if (what & SSB_GPIO_PLL) 11661e115a5SMichael Buesch out |= SSB_GPIO_PLL; 11761e115a5SMichael Buesch err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out); 11861e115a5SMichael Buesch if (err) 11961e115a5SMichael Buesch goto err_pci; 12061e115a5SMichael Buesch err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE, 12161e115a5SMichael Buesch outenable); 12261e115a5SMichael Buesch if (err) 12361e115a5SMichael Buesch goto err_pci; 12461e115a5SMichael Buesch msleep(1); 12561e115a5SMichael Buesch } 12661e115a5SMichael Buesch if (what & SSB_GPIO_PLL) { 12761e115a5SMichael Buesch /* Turn the PLL on */ 12861e115a5SMichael Buesch out &= ~SSB_GPIO_PLL; 12961e115a5SMichael Buesch err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out); 13061e115a5SMichael Buesch if (err) 13161e115a5SMichael Buesch goto err_pci; 13261e115a5SMichael Buesch msleep(5); 13361e115a5SMichael Buesch } 13461e115a5SMichael Buesch } 13561e115a5SMichael Buesch 13661e115a5SMichael Buesch err = pci_read_config_word(bus->host_pci, PCI_STATUS, &pci_status); 13761e115a5SMichael Buesch if (err) 13861e115a5SMichael Buesch goto err_pci; 13961e115a5SMichael Buesch pci_status &= ~PCI_STATUS_SIG_TARGET_ABORT; 14061e115a5SMichael Buesch err = pci_write_config_word(bus->host_pci, PCI_STATUS, pci_status); 14161e115a5SMichael Buesch if (err) 14261e115a5SMichael Buesch goto err_pci; 14361e115a5SMichael Buesch } else { 14461e115a5SMichael Buesch if (what & SSB_GPIO_XTAL) { 14561e115a5SMichael Buesch /* Turn the crystal off */ 14661e115a5SMichael Buesch out &= ~SSB_GPIO_XTAL; 14761e115a5SMichael Buesch } 14861e115a5SMichael Buesch if (what & SSB_GPIO_PLL) { 14961e115a5SMichael Buesch /* Turn the PLL off */ 15061e115a5SMichael Buesch out |= SSB_GPIO_PLL; 15161e115a5SMichael Buesch } 15261e115a5SMichael Buesch err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out); 15361e115a5SMichael Buesch if (err) 15461e115a5SMichael Buesch goto err_pci; 15561e115a5SMichael Buesch err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE, outenable); 15661e115a5SMichael Buesch if (err) 15761e115a5SMichael Buesch goto err_pci; 15861e115a5SMichael Buesch } 15961e115a5SMichael Buesch 16061e115a5SMichael Buesch out: 16161e115a5SMichael Buesch return err; 16261e115a5SMichael Buesch 16361e115a5SMichael Buesch err_pci: 16461e115a5SMichael Buesch printk(KERN_ERR PFX "Error: ssb_pci_xtal() could not access PCI config space!\n"); 16561e115a5SMichael Buesch err = -EBUSY; 16661e115a5SMichael Buesch goto out; 16761e115a5SMichael Buesch } 16861e115a5SMichael Buesch 16961e115a5SMichael Buesch /* Get the word-offset for a SSB_SPROM_XXX define. */ 1700a182fd8SRafał Miłecki #define SPOFF(offset) ((offset) / sizeof(u16)) 17161e115a5SMichael Buesch /* Helper to extract some _offset, which is one of the SSB_SPROM_XXX defines. */ 172f679056bSGábor Stefanik #define SPEX16(_outvar, _offset, _mask, _shift) \ 17361e115a5SMichael Buesch out->_outvar = ((in[SPOFF(_offset)] & (_mask)) >> (_shift)) 174f679056bSGábor Stefanik #define SPEX32(_outvar, _offset, _mask, _shift) \ 175f679056bSGábor Stefanik out->_outvar = ((((u32)in[SPOFF((_offset)+2)] << 16 | \ 176f679056bSGábor Stefanik in[SPOFF(_offset)]) & (_mask)) >> (_shift)) 177f679056bSGábor Stefanik #define SPEX(_outvar, _offset, _mask, _shift) \ 178f679056bSGábor Stefanik SPEX16(_outvar, _offset, _mask, _shift) 179f679056bSGábor Stefanik 180e2da4bd3SHauke Mehrtens #define SPEX_ARRAY8(_field, _offset, _mask, _shift) \ 181e2da4bd3SHauke Mehrtens do { \ 182e2da4bd3SHauke Mehrtens SPEX(_field[0], _offset + 0, _mask, _shift); \ 183e2da4bd3SHauke Mehrtens SPEX(_field[1], _offset + 2, _mask, _shift); \ 184e2da4bd3SHauke Mehrtens SPEX(_field[2], _offset + 4, _mask, _shift); \ 185e2da4bd3SHauke Mehrtens SPEX(_field[3], _offset + 6, _mask, _shift); \ 186e2da4bd3SHauke Mehrtens SPEX(_field[4], _offset + 8, _mask, _shift); \ 187e2da4bd3SHauke Mehrtens SPEX(_field[5], _offset + 10, _mask, _shift); \ 188e2da4bd3SHauke Mehrtens SPEX(_field[6], _offset + 12, _mask, _shift); \ 189e2da4bd3SHauke Mehrtens SPEX(_field[7], _offset + 14, _mask, _shift); \ 190e2da4bd3SHauke Mehrtens } while (0) 191e2da4bd3SHauke Mehrtens 19261e115a5SMichael Buesch 19361e115a5SMichael Buesch static inline u8 ssb_crc8(u8 crc, u8 data) 19461e115a5SMichael Buesch { 19561e115a5SMichael Buesch /* Polynomial: x^8 + x^7 + x^6 + x^4 + x^2 + 1 */ 19661e115a5SMichael Buesch static const u8 t[] = { 19761e115a5SMichael Buesch 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B, 19861e115a5SMichael Buesch 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21, 19961e115a5SMichael Buesch 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF, 20061e115a5SMichael Buesch 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5, 20161e115a5SMichael Buesch 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14, 20261e115a5SMichael Buesch 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E, 20361e115a5SMichael Buesch 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80, 20461e115a5SMichael Buesch 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA, 20561e115a5SMichael Buesch 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95, 20661e115a5SMichael Buesch 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF, 20761e115a5SMichael Buesch 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01, 20861e115a5SMichael Buesch 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B, 20961e115a5SMichael Buesch 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA, 21061e115a5SMichael Buesch 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0, 21161e115a5SMichael Buesch 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E, 21261e115a5SMichael Buesch 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34, 21361e115a5SMichael Buesch 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0, 21461e115a5SMichael Buesch 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A, 21561e115a5SMichael Buesch 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54, 21661e115a5SMichael Buesch 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E, 21761e115a5SMichael Buesch 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF, 21861e115a5SMichael Buesch 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5, 21961e115a5SMichael Buesch 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B, 22061e115a5SMichael Buesch 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61, 22161e115a5SMichael Buesch 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E, 22261e115a5SMichael Buesch 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74, 22361e115a5SMichael Buesch 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA, 22461e115a5SMichael Buesch 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0, 22561e115a5SMichael Buesch 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41, 22661e115a5SMichael Buesch 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B, 22761e115a5SMichael Buesch 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5, 22861e115a5SMichael Buesch 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F, 22961e115a5SMichael Buesch }; 23061e115a5SMichael Buesch return t[crc ^ data]; 23161e115a5SMichael Buesch } 23261e115a5SMichael Buesch 233e5652756SJoe Perches static void sprom_get_mac(char *mac, const u16 *in) 234e5652756SJoe Perches { 235e5652756SJoe Perches int i; 236e5652756SJoe Perches for (i = 0; i < 3; i++) { 237e5652756SJoe Perches *mac++ = in[i] >> 8; 238a9fac739SLarry Finger *mac++ = in[i]; 239e5652756SJoe Perches } 240e5652756SJoe Perches } 241e5652756SJoe Perches 242c272ef44SLarry Finger static u8 ssb_sprom_crc(const u16 *sprom, u16 size) 24361e115a5SMichael Buesch { 24461e115a5SMichael Buesch int word; 24561e115a5SMichael Buesch u8 crc = 0xFF; 24661e115a5SMichael Buesch 247c272ef44SLarry Finger for (word = 0; word < size - 1; word++) { 24861e115a5SMichael Buesch crc = ssb_crc8(crc, sprom[word] & 0x00FF); 24961e115a5SMichael Buesch crc = ssb_crc8(crc, (sprom[word] & 0xFF00) >> 8); 25061e115a5SMichael Buesch } 251c272ef44SLarry Finger crc = ssb_crc8(crc, sprom[size - 1] & 0x00FF); 25261e115a5SMichael Buesch crc ^= 0xFF; 25361e115a5SMichael Buesch 25461e115a5SMichael Buesch return crc; 25561e115a5SMichael Buesch } 25661e115a5SMichael Buesch 257e7ec2e32SMichael Buesch static int sprom_check_crc(const u16 *sprom, size_t size) 25861e115a5SMichael Buesch { 25961e115a5SMichael Buesch u8 crc; 26061e115a5SMichael Buesch u8 expected_crc; 26161e115a5SMichael Buesch u16 tmp; 26261e115a5SMichael Buesch 263c272ef44SLarry Finger crc = ssb_sprom_crc(sprom, size); 264c272ef44SLarry Finger tmp = sprom[size - 1] & SSB_SPROM_REVISION_CRC; 26561e115a5SMichael Buesch expected_crc = tmp >> SSB_SPROM_REVISION_CRC_SHIFT; 26661e115a5SMichael Buesch if (crc != expected_crc) 26761e115a5SMichael Buesch return -EPROTO; 26861e115a5SMichael Buesch 26961e115a5SMichael Buesch return 0; 27061e115a5SMichael Buesch } 27161e115a5SMichael Buesch 272e7ec2e32SMichael Buesch static int sprom_do_read(struct ssb_bus *bus, u16 *sprom) 27361e115a5SMichael Buesch { 27461e115a5SMichael Buesch int i; 27561e115a5SMichael Buesch 276c272ef44SLarry Finger for (i = 0; i < bus->sprom_size; i++) 277ea2db495SRafał Miłecki sprom[i] = ioread16(bus->mmio + bus->sprom_offset + (i * 2)); 278e7ec2e32SMichael Buesch 279e7ec2e32SMichael Buesch return 0; 28061e115a5SMichael Buesch } 28161e115a5SMichael Buesch 28261e115a5SMichael Buesch static int sprom_do_write(struct ssb_bus *bus, const u16 *sprom) 28361e115a5SMichael Buesch { 28461e115a5SMichael Buesch struct pci_dev *pdev = bus->host_pci; 28561e115a5SMichael Buesch int i, err; 28661e115a5SMichael Buesch u32 spromctl; 287c272ef44SLarry Finger u16 size = bus->sprom_size; 28861e115a5SMichael Buesch 28933a606acSJoe Perches ssb_notice("Writing SPROM. Do NOT turn off the power! Please stand by...\n"); 29061e115a5SMichael Buesch err = pci_read_config_dword(pdev, SSB_SPROMCTL, &spromctl); 29161e115a5SMichael Buesch if (err) 29261e115a5SMichael Buesch goto err_ctlreg; 29361e115a5SMichael Buesch spromctl |= SSB_SPROMCTL_WE; 29461e115a5SMichael Buesch err = pci_write_config_dword(pdev, SSB_SPROMCTL, spromctl); 29561e115a5SMichael Buesch if (err) 29661e115a5SMichael Buesch goto err_ctlreg; 29733a606acSJoe Perches ssb_notice("[ 0%%"); 29861e115a5SMichael Buesch msleep(500); 299c272ef44SLarry Finger for (i = 0; i < size; i++) { 300c272ef44SLarry Finger if (i == size / 4) 30133a606acSJoe Perches ssb_cont("25%%"); 302c272ef44SLarry Finger else if (i == size / 2) 30333a606acSJoe Perches ssb_cont("50%%"); 304c272ef44SLarry Finger else if (i == (size * 3) / 4) 30533a606acSJoe Perches ssb_cont("75%%"); 30661e115a5SMichael Buesch else if (i % 2) 30733a606acSJoe Perches ssb_cont("."); 308ea2db495SRafał Miłecki writew(sprom[i], bus->mmio + bus->sprom_offset + (i * 2)); 30961e115a5SMichael Buesch mmiowb(); 31061e115a5SMichael Buesch msleep(20); 31161e115a5SMichael Buesch } 31261e115a5SMichael Buesch err = pci_read_config_dword(pdev, SSB_SPROMCTL, &spromctl); 31361e115a5SMichael Buesch if (err) 31461e115a5SMichael Buesch goto err_ctlreg; 31561e115a5SMichael Buesch spromctl &= ~SSB_SPROMCTL_WE; 31661e115a5SMichael Buesch err = pci_write_config_dword(pdev, SSB_SPROMCTL, spromctl); 31761e115a5SMichael Buesch if (err) 31861e115a5SMichael Buesch goto err_ctlreg; 31961e115a5SMichael Buesch msleep(500); 32033a606acSJoe Perches ssb_cont("100%% ]\n"); 32133a606acSJoe Perches ssb_notice("SPROM written\n"); 32261e115a5SMichael Buesch 32361e115a5SMichael Buesch return 0; 32461e115a5SMichael Buesch err_ctlreg: 32533a606acSJoe Perches ssb_err("Could not access SPROM control register.\n"); 32661e115a5SMichael Buesch return err; 32761e115a5SMichael Buesch } 32861e115a5SMichael Buesch 32967d392c0SRafał Miłecki static s8 sprom_extract_antgain(u8 sprom_revision, const u16 *in, u16 offset, 330e861b98dSMichael Buesch u16 mask, u16 shift) 331e861b98dSMichael Buesch { 332e861b98dSMichael Buesch u16 v; 333e861b98dSMichael Buesch u8 gain; 334e861b98dSMichael Buesch 33567d392c0SRafał Miłecki v = in[SPOFF(offset)]; 336e861b98dSMichael Buesch gain = (v & mask) >> shift; 337e861b98dSMichael Buesch if (gain == 0xFF) 338e861b98dSMichael Buesch gain = 2; /* If unset use 2dBm */ 339e861b98dSMichael Buesch if (sprom_revision == 1) { 340e861b98dSMichael Buesch /* Convert to Q5.2 */ 341e861b98dSMichael Buesch gain <<= 2; 342e861b98dSMichael Buesch } else { 343e861b98dSMichael Buesch /* Q5.2 Fractional part is stored in 0xC0 */ 344e861b98dSMichael Buesch gain = ((gain & 0xC0) >> 6) | ((gain & 0x3F) << 2); 345e861b98dSMichael Buesch } 346e861b98dSMichael Buesch 347e861b98dSMichael Buesch return (s8)gain; 348e861b98dSMichael Buesch } 349e861b98dSMichael Buesch 3507e4235acSHauke Mehrtens static void sprom_extract_r23(struct ssb_sprom *out, const u16 *in) 3517e4235acSHauke Mehrtens { 3527e4235acSHauke Mehrtens SPEX(boardflags_hi, SSB_SPROM2_BFLHI, 0xFFFF, 0); 3537e4235acSHauke Mehrtens SPEX(opo, SSB_SPROM2_OPO, SSB_SPROM2_OPO_VALUE, 0); 3547e4235acSHauke Mehrtens SPEX(pa1lob0, SSB_SPROM2_PA1LOB0, 0xFFFF, 0); 3557e4235acSHauke Mehrtens SPEX(pa1lob1, SSB_SPROM2_PA1LOB1, 0xFFFF, 0); 3567e4235acSHauke Mehrtens SPEX(pa1lob2, SSB_SPROM2_PA1LOB2, 0xFFFF, 0); 3577e4235acSHauke Mehrtens SPEX(pa1hib0, SSB_SPROM2_PA1HIB0, 0xFFFF, 0); 3587e4235acSHauke Mehrtens SPEX(pa1hib1, SSB_SPROM2_PA1HIB1, 0xFFFF, 0); 3597e4235acSHauke Mehrtens SPEX(pa1hib2, SSB_SPROM2_PA1HIB2, 0xFFFF, 0); 3607e4235acSHauke Mehrtens SPEX(maxpwr_ah, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_HI, 0); 3617e4235acSHauke Mehrtens SPEX(maxpwr_al, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_LO, 3627e4235acSHauke Mehrtens SSB_SPROM2_MAXP_A_LO_SHIFT); 3637e4235acSHauke Mehrtens } 3647e4235acSHauke Mehrtens 365c272ef44SLarry Finger static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in) 366c272ef44SLarry Finger { 367c272ef44SLarry Finger u16 loc[3]; 368c272ef44SLarry Finger 36931ce12fbSLarry Finger if (out->revision == 3) /* rev 3 moved MAC */ 370c272ef44SLarry Finger loc[0] = SSB_SPROM3_IL0MAC; 37131ce12fbSLarry Finger else { 372c272ef44SLarry Finger loc[0] = SSB_SPROM1_IL0MAC; 373c272ef44SLarry Finger loc[1] = SSB_SPROM1_ET0MAC; 374c272ef44SLarry Finger loc[2] = SSB_SPROM1_ET1MAC; 375c272ef44SLarry Finger } 376e5652756SJoe Perches sprom_get_mac(out->il0mac, &in[SPOFF(loc[0])]); 37731ce12fbSLarry Finger if (out->revision < 3) { /* only rev 1-2 have et0, et1 */ 378e5652756SJoe Perches sprom_get_mac(out->et0mac, &in[SPOFF(loc[1])]); 379e5652756SJoe Perches sprom_get_mac(out->et1mac, &in[SPOFF(loc[2])]); 38031ce12fbSLarry Finger } 381c272ef44SLarry Finger SPEX(et0phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0A, 0); 382c272ef44SLarry Finger SPEX(et1phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1A, 383c272ef44SLarry Finger SSB_SPROM1_ETHPHY_ET1A_SHIFT); 384e861b98dSMichael Buesch SPEX(et0mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0M, 14); 385e861b98dSMichael Buesch SPEX(et1mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1M, 15); 386e861b98dSMichael Buesch SPEX(board_rev, SSB_SPROM1_BINF, SSB_SPROM1_BINF_BREV, 0); 3873623b266SRafał Miłecki SPEX(board_type, SSB_SPROM1_SPID, 0xFFFF, 0); 388bf7d420bSHauke Mehrtens if (out->revision == 1) 389c272ef44SLarry Finger SPEX(country_code, SSB_SPROM1_BINF, SSB_SPROM1_BINF_CCODE, 390c272ef44SLarry Finger SSB_SPROM1_BINF_CCODE_SHIFT); 391e861b98dSMichael Buesch SPEX(ant_available_a, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTA, 392e861b98dSMichael Buesch SSB_SPROM1_BINF_ANTA_SHIFT); 393e861b98dSMichael Buesch SPEX(ant_available_bg, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTBG, 394e861b98dSMichael Buesch SSB_SPROM1_BINF_ANTBG_SHIFT); 395c272ef44SLarry Finger SPEX(pa0b0, SSB_SPROM1_PA0B0, 0xFFFF, 0); 396c272ef44SLarry Finger SPEX(pa0b1, SSB_SPROM1_PA0B1, 0xFFFF, 0); 397c272ef44SLarry Finger SPEX(pa0b2, SSB_SPROM1_PA0B2, 0xFFFF, 0); 398c272ef44SLarry Finger SPEX(pa1b0, SSB_SPROM1_PA1B0, 0xFFFF, 0); 399c272ef44SLarry Finger SPEX(pa1b1, SSB_SPROM1_PA1B1, 0xFFFF, 0); 400c272ef44SLarry Finger SPEX(pa1b2, SSB_SPROM1_PA1B2, 0xFFFF, 0); 401c272ef44SLarry Finger SPEX(gpio0, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P0, 0); 402c272ef44SLarry Finger SPEX(gpio1, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P1, 403c272ef44SLarry Finger SSB_SPROM1_GPIOA_P1_SHIFT); 404c272ef44SLarry Finger SPEX(gpio2, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P2, 0); 405c272ef44SLarry Finger SPEX(gpio3, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P3, 406c272ef44SLarry Finger SSB_SPROM1_GPIOB_P3_SHIFT); 407c272ef44SLarry Finger SPEX(maxpwr_a, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_A, 408c272ef44SLarry Finger SSB_SPROM1_MAXPWR_A_SHIFT); 409c272ef44SLarry Finger SPEX(maxpwr_bg, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_BG, 0); 410c272ef44SLarry Finger SPEX(itssi_a, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_A, 411c272ef44SLarry Finger SSB_SPROM1_ITSSI_A_SHIFT); 412c272ef44SLarry Finger SPEX(itssi_bg, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_BG, 0); 413c272ef44SLarry Finger SPEX(boardflags_lo, SSB_SPROM1_BFLLO, 0xFFFF, 0); 4147e4235acSHauke Mehrtens 415bf7d420bSHauke Mehrtens SPEX(alpha2[0], SSB_SPROM1_CCODE, 0xff00, 8); 416bf7d420bSHauke Mehrtens SPEX(alpha2[1], SSB_SPROM1_CCODE, 0x00ff, 0); 417e861b98dSMichael Buesch 418e861b98dSMichael Buesch /* Extract the antenna gain values. */ 41967d392c0SRafał Miłecki out->antenna_gain.a0 = sprom_extract_antgain(out->revision, in, 42067d392c0SRafał Miłecki SSB_SPROM1_AGAIN, 421e861b98dSMichael Buesch SSB_SPROM1_AGAIN_BG, 422c272ef44SLarry Finger SSB_SPROM1_AGAIN_BG_SHIFT); 42367d392c0SRafał Miłecki out->antenna_gain.a1 = sprom_extract_antgain(out->revision, in, 42467d392c0SRafał Miłecki SSB_SPROM1_AGAIN, 425e861b98dSMichael Buesch SSB_SPROM1_AGAIN_A, 426e861b98dSMichael Buesch SSB_SPROM1_AGAIN_A_SHIFT); 4277e4235acSHauke Mehrtens if (out->revision >= 2) 4287e4235acSHauke Mehrtens sprom_extract_r23(out, in); 429c272ef44SLarry Finger } 430c272ef44SLarry Finger 431172c69a4SRafał Miłecki /* Revs 4 5 and 8 have partially shared layout */ 432172c69a4SRafał Miłecki static void sprom_extract_r458(struct ssb_sprom *out, const u16 *in) 433172c69a4SRafał Miłecki { 434172c69a4SRafał Miłecki SPEX(txpid2g[0], SSB_SPROM4_TXPID2G01, 435172c69a4SRafał Miłecki SSB_SPROM4_TXPID2G0, SSB_SPROM4_TXPID2G0_SHIFT); 436172c69a4SRafał Miłecki SPEX(txpid2g[1], SSB_SPROM4_TXPID2G01, 437172c69a4SRafał Miłecki SSB_SPROM4_TXPID2G1, SSB_SPROM4_TXPID2G1_SHIFT); 438172c69a4SRafał Miłecki SPEX(txpid2g[2], SSB_SPROM4_TXPID2G23, 439172c69a4SRafał Miłecki SSB_SPROM4_TXPID2G2, SSB_SPROM4_TXPID2G2_SHIFT); 440172c69a4SRafał Miłecki SPEX(txpid2g[3], SSB_SPROM4_TXPID2G23, 441172c69a4SRafał Miłecki SSB_SPROM4_TXPID2G3, SSB_SPROM4_TXPID2G3_SHIFT); 442172c69a4SRafał Miłecki 443172c69a4SRafał Miłecki SPEX(txpid5gl[0], SSB_SPROM4_TXPID5GL01, 444172c69a4SRafał Miłecki SSB_SPROM4_TXPID5GL0, SSB_SPROM4_TXPID5GL0_SHIFT); 445172c69a4SRafał Miłecki SPEX(txpid5gl[1], SSB_SPROM4_TXPID5GL01, 446172c69a4SRafał Miłecki SSB_SPROM4_TXPID5GL1, SSB_SPROM4_TXPID5GL1_SHIFT); 447172c69a4SRafał Miłecki SPEX(txpid5gl[2], SSB_SPROM4_TXPID5GL23, 448172c69a4SRafał Miłecki SSB_SPROM4_TXPID5GL2, SSB_SPROM4_TXPID5GL2_SHIFT); 449172c69a4SRafał Miłecki SPEX(txpid5gl[3], SSB_SPROM4_TXPID5GL23, 450172c69a4SRafał Miłecki SSB_SPROM4_TXPID5GL3, SSB_SPROM4_TXPID5GL3_SHIFT); 451172c69a4SRafał Miłecki 452172c69a4SRafał Miłecki SPEX(txpid5g[0], SSB_SPROM4_TXPID5G01, 453172c69a4SRafał Miłecki SSB_SPROM4_TXPID5G0, SSB_SPROM4_TXPID5G0_SHIFT); 454172c69a4SRafał Miłecki SPEX(txpid5g[1], SSB_SPROM4_TXPID5G01, 455172c69a4SRafał Miłecki SSB_SPROM4_TXPID5G1, SSB_SPROM4_TXPID5G1_SHIFT); 456172c69a4SRafał Miłecki SPEX(txpid5g[2], SSB_SPROM4_TXPID5G23, 457172c69a4SRafał Miłecki SSB_SPROM4_TXPID5G2, SSB_SPROM4_TXPID5G2_SHIFT); 458172c69a4SRafał Miłecki SPEX(txpid5g[3], SSB_SPROM4_TXPID5G23, 459172c69a4SRafał Miłecki SSB_SPROM4_TXPID5G3, SSB_SPROM4_TXPID5G3_SHIFT); 460172c69a4SRafał Miłecki 461172c69a4SRafał Miłecki SPEX(txpid5gh[0], SSB_SPROM4_TXPID5GH01, 462172c69a4SRafał Miłecki SSB_SPROM4_TXPID5GH0, SSB_SPROM4_TXPID5GH0_SHIFT); 463172c69a4SRafał Miłecki SPEX(txpid5gh[1], SSB_SPROM4_TXPID5GH01, 464172c69a4SRafał Miłecki SSB_SPROM4_TXPID5GH1, SSB_SPROM4_TXPID5GH1_SHIFT); 465172c69a4SRafał Miłecki SPEX(txpid5gh[2], SSB_SPROM4_TXPID5GH23, 466172c69a4SRafał Miłecki SSB_SPROM4_TXPID5GH2, SSB_SPROM4_TXPID5GH2_SHIFT); 467172c69a4SRafał Miłecki SPEX(txpid5gh[3], SSB_SPROM4_TXPID5GH23, 468172c69a4SRafał Miłecki SSB_SPROM4_TXPID5GH3, SSB_SPROM4_TXPID5GH3_SHIFT); 469172c69a4SRafał Miłecki } 470172c69a4SRafał Miłecki 471095f695cSLarry Finger static void sprom_extract_r45(struct ssb_sprom *out, const u16 *in) 47261e115a5SMichael Buesch { 473095f695cSLarry Finger u16 il0mac_offset; 47461e115a5SMichael Buesch 475095f695cSLarry Finger if (out->revision == 4) 476095f695cSLarry Finger il0mac_offset = SSB_SPROM4_IL0MAC; 477095f695cSLarry Finger else 478095f695cSLarry Finger il0mac_offset = SSB_SPROM5_IL0MAC; 479e5652756SJoe Perches 480e5652756SJoe Perches sprom_get_mac(out->il0mac, &in[SPOFF(il0mac_offset)]); 481e5652756SJoe Perches 482c272ef44SLarry Finger SPEX(et0phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET0A, 0); 483c272ef44SLarry Finger SPEX(et1phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET1A, 484c272ef44SLarry Finger SSB_SPROM4_ETHPHY_ET1A_SHIFT); 485673335c8SHauke Mehrtens SPEX(board_rev, SSB_SPROM4_BOARDREV, 0xFFFF, 0); 4863623b266SRafał Miłecki SPEX(board_type, SSB_SPROM1_SPID, 0xFFFF, 0); 487095f695cSLarry Finger if (out->revision == 4) { 488bf7d420bSHauke Mehrtens SPEX(alpha2[0], SSB_SPROM4_CCODE, 0xff00, 8); 489bf7d420bSHauke Mehrtens SPEX(alpha2[1], SSB_SPROM4_CCODE, 0x00ff, 0); 490c272ef44SLarry Finger SPEX(boardflags_lo, SSB_SPROM4_BFLLO, 0xFFFF, 0); 491af4b7450SMichael Buesch SPEX(boardflags_hi, SSB_SPROM4_BFLHI, 0xFFFF, 0); 4926d1d4ea4SRafał Miłecki SPEX(boardflags2_lo, SSB_SPROM4_BFL2LO, 0xFFFF, 0); 4936d1d4ea4SRafał Miłecki SPEX(boardflags2_hi, SSB_SPROM4_BFL2HI, 0xFFFF, 0); 494095f695cSLarry Finger } else { 495bf7d420bSHauke Mehrtens SPEX(alpha2[0], SSB_SPROM5_CCODE, 0xff00, 8); 496bf7d420bSHauke Mehrtens SPEX(alpha2[1], SSB_SPROM5_CCODE, 0x00ff, 0); 497095f695cSLarry Finger SPEX(boardflags_lo, SSB_SPROM5_BFLLO, 0xFFFF, 0); 498095f695cSLarry Finger SPEX(boardflags_hi, SSB_SPROM5_BFLHI, 0xFFFF, 0); 4996d1d4ea4SRafał Miłecki SPEX(boardflags2_lo, SSB_SPROM5_BFL2LO, 0xFFFF, 0); 5006d1d4ea4SRafał Miłecki SPEX(boardflags2_hi, SSB_SPROM5_BFL2HI, 0xFFFF, 0); 501095f695cSLarry Finger } 502e861b98dSMichael Buesch SPEX(ant_available_a, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_A, 503e861b98dSMichael Buesch SSB_SPROM4_ANTAVAIL_A_SHIFT); 504e861b98dSMichael Buesch SPEX(ant_available_bg, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_BG, 505e861b98dSMichael Buesch SSB_SPROM4_ANTAVAIL_BG_SHIFT); 506d3c319f9SLarry Finger SPEX(maxpwr_bg, SSB_SPROM4_MAXP_BG, SSB_SPROM4_MAXP_BG_MASK, 0); 507d3c319f9SLarry Finger SPEX(itssi_bg, SSB_SPROM4_MAXP_BG, SSB_SPROM4_ITSSI_BG, 508d3c319f9SLarry Finger SSB_SPROM4_ITSSI_BG_SHIFT); 509d3c319f9SLarry Finger SPEX(maxpwr_a, SSB_SPROM4_MAXP_A, SSB_SPROM4_MAXP_A_MASK, 0); 510d3c319f9SLarry Finger SPEX(itssi_a, SSB_SPROM4_MAXP_A, SSB_SPROM4_ITSSI_A, 511d3c319f9SLarry Finger SSB_SPROM4_ITSSI_A_SHIFT); 512095f695cSLarry Finger if (out->revision == 4) { 513d3c319f9SLarry Finger SPEX(gpio0, SSB_SPROM4_GPIOA, SSB_SPROM4_GPIOA_P0, 0); 514d3c319f9SLarry Finger SPEX(gpio1, SSB_SPROM4_GPIOA, SSB_SPROM4_GPIOA_P1, 515d3c319f9SLarry Finger SSB_SPROM4_GPIOA_P1_SHIFT); 516d3c319f9SLarry Finger SPEX(gpio2, SSB_SPROM4_GPIOB, SSB_SPROM4_GPIOB_P2, 0); 517d3c319f9SLarry Finger SPEX(gpio3, SSB_SPROM4_GPIOB, SSB_SPROM4_GPIOB_P3, 518d3c319f9SLarry Finger SSB_SPROM4_GPIOB_P3_SHIFT); 519095f695cSLarry Finger } else { 520095f695cSLarry Finger SPEX(gpio0, SSB_SPROM5_GPIOA, SSB_SPROM5_GPIOA_P0, 0); 521095f695cSLarry Finger SPEX(gpio1, SSB_SPROM5_GPIOA, SSB_SPROM5_GPIOA_P1, 522095f695cSLarry Finger SSB_SPROM5_GPIOA_P1_SHIFT); 523095f695cSLarry Finger SPEX(gpio2, SSB_SPROM5_GPIOB, SSB_SPROM5_GPIOB_P2, 0); 524095f695cSLarry Finger SPEX(gpio3, SSB_SPROM5_GPIOB, SSB_SPROM5_GPIOB_P3, 525095f695cSLarry Finger SSB_SPROM5_GPIOB_P3_SHIFT); 526095f695cSLarry Finger } 527e861b98dSMichael Buesch 528e861b98dSMichael Buesch /* Extract the antenna gain values. */ 529*6daf4321SRafał Miłecki out->antenna_gain.a0 = sprom_extract_antgain(out->revision, in, 530*6daf4321SRafał Miłecki SSB_SPROM4_AGAIN01, 531*6daf4321SRafał Miłecki SSB_SPROM4_AGAIN0, 532*6daf4321SRafał Miłecki SSB_SPROM4_AGAIN0_SHIFT); 533*6daf4321SRafał Miłecki out->antenna_gain.a1 = sprom_extract_antgain(out->revision, in, 534*6daf4321SRafał Miłecki SSB_SPROM4_AGAIN01, 535*6daf4321SRafał Miłecki SSB_SPROM4_AGAIN1, 536*6daf4321SRafał Miłecki SSB_SPROM4_AGAIN1_SHIFT); 537*6daf4321SRafał Miłecki out->antenna_gain.a2 = sprom_extract_antgain(out->revision, in, 538*6daf4321SRafał Miłecki SSB_SPROM4_AGAIN23, 539*6daf4321SRafał Miłecki SSB_SPROM4_AGAIN2, 540*6daf4321SRafał Miłecki SSB_SPROM4_AGAIN2_SHIFT); 541*6daf4321SRafał Miłecki out->antenna_gain.a3 = sprom_extract_antgain(out->revision, in, 542*6daf4321SRafał Miłecki SSB_SPROM4_AGAIN23, 543*6daf4321SRafał Miłecki SSB_SPROM4_AGAIN3, 544*6daf4321SRafał Miłecki SSB_SPROM4_AGAIN3_SHIFT); 545e861b98dSMichael Buesch 546172c69a4SRafał Miłecki sprom_extract_r458(out, in); 547172c69a4SRafał Miłecki 548c272ef44SLarry Finger /* TODO - get remaining rev 4 stuff needed */ 54961e115a5SMichael Buesch } 55061e115a5SMichael Buesch 5516b1c7c67SMichael Buesch static void sprom_extract_r8(struct ssb_sprom *out, const u16 *in) 5526b1c7c67SMichael Buesch { 5536b1c7c67SMichael Buesch int i; 554e5652756SJoe Perches u16 o; 555b0f70292SRafał Miłecki u16 pwr_info_offset[] = { 556b0f70292SRafał Miłecki SSB_SROM8_PWR_INFO_CORE0, SSB_SROM8_PWR_INFO_CORE1, 557b0f70292SRafał Miłecki SSB_SROM8_PWR_INFO_CORE2, SSB_SROM8_PWR_INFO_CORE3 558b0f70292SRafał Miłecki }; 559b0f70292SRafał Miłecki BUILD_BUG_ON(ARRAY_SIZE(pwr_info_offset) != 560b0f70292SRafał Miłecki ARRAY_SIZE(out->core_pwr_info)); 5616b1c7c67SMichael Buesch 5626b1c7c67SMichael Buesch /* extract the MAC address */ 563e5652756SJoe Perches sprom_get_mac(out->il0mac, &in[SPOFF(SSB_SPROM8_IL0MAC)]); 564e5652756SJoe Perches 565673335c8SHauke Mehrtens SPEX(board_rev, SSB_SPROM8_BOARDREV, 0xFFFF, 0); 5663623b266SRafał Miłecki SPEX(board_type, SSB_SPROM1_SPID, 0xFFFF, 0); 567bf7d420bSHauke Mehrtens SPEX(alpha2[0], SSB_SPROM8_CCODE, 0xff00, 8); 568bf7d420bSHauke Mehrtens SPEX(alpha2[1], SSB_SPROM8_CCODE, 0x00ff, 0); 5696b1c7c67SMichael Buesch SPEX(boardflags_lo, SSB_SPROM8_BFLLO, 0xFFFF, 0); 5706b1c7c67SMichael Buesch SPEX(boardflags_hi, SSB_SPROM8_BFLHI, 0xFFFF, 0); 571f679056bSGábor Stefanik SPEX(boardflags2_lo, SSB_SPROM8_BFL2LO, 0xFFFF, 0); 572f679056bSGábor Stefanik SPEX(boardflags2_hi, SSB_SPROM8_BFL2HI, 0xFFFF, 0); 5736b1c7c67SMichael Buesch SPEX(ant_available_a, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_A, 5746b1c7c67SMichael Buesch SSB_SPROM8_ANTAVAIL_A_SHIFT); 5756b1c7c67SMichael Buesch SPEX(ant_available_bg, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_BG, 5766b1c7c67SMichael Buesch SSB_SPROM8_ANTAVAIL_BG_SHIFT); 5776b1c7c67SMichael Buesch SPEX(maxpwr_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_MAXP_BG_MASK, 0); 5786b1c7c67SMichael Buesch SPEX(itssi_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_ITSSI_BG, 5796b1c7c67SMichael Buesch SSB_SPROM8_ITSSI_BG_SHIFT); 5806b1c7c67SMichael Buesch SPEX(maxpwr_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_MAXP_A_MASK, 0); 5816b1c7c67SMichael Buesch SPEX(itssi_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_ITSSI_A, 5826b1c7c67SMichael Buesch SSB_SPROM8_ITSSI_A_SHIFT); 583f679056bSGábor Stefanik SPEX(maxpwr_ah, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AH_MASK, 0); 584f679056bSGábor Stefanik SPEX(maxpwr_al, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AL_MASK, 585f679056bSGábor Stefanik SSB_SPROM8_MAXP_AL_SHIFT); 5866b1c7c67SMichael Buesch SPEX(gpio0, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P0, 0); 5876b1c7c67SMichael Buesch SPEX(gpio1, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P1, 5886b1c7c67SMichael Buesch SSB_SPROM8_GPIOA_P1_SHIFT); 5896b1c7c67SMichael Buesch SPEX(gpio2, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P2, 0); 5906b1c7c67SMichael Buesch SPEX(gpio3, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P3, 5916b1c7c67SMichael Buesch SSB_SPROM8_GPIOB_P3_SHIFT); 592f679056bSGábor Stefanik SPEX(tri2g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI2G, 0); 593f679056bSGábor Stefanik SPEX(tri5g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI5G, 594f679056bSGábor Stefanik SSB_SPROM8_TRI5G_SHIFT); 595f679056bSGábor Stefanik SPEX(tri5gl, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GL, 0); 596f679056bSGábor Stefanik SPEX(tri5gh, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GH, 597f679056bSGábor Stefanik SSB_SPROM8_TRI5GH_SHIFT); 598f679056bSGábor Stefanik SPEX(rxpo2g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO2G, 0); 599f679056bSGábor Stefanik SPEX(rxpo5g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO5G, 600f679056bSGábor Stefanik SSB_SPROM8_RXPO5G_SHIFT); 601f679056bSGábor Stefanik SPEX(rssismf2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMF2G, 0); 602f679056bSGábor Stefanik SPEX(rssismc2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMC2G, 603f679056bSGábor Stefanik SSB_SPROM8_RSSISMC2G_SHIFT); 604f679056bSGábor Stefanik SPEX(rssisav2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISAV2G, 605f679056bSGábor Stefanik SSB_SPROM8_RSSISAV2G_SHIFT); 606f679056bSGábor Stefanik SPEX(bxa2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_BXA2G, 607f679056bSGábor Stefanik SSB_SPROM8_BXA2G_SHIFT); 608f679056bSGábor Stefanik SPEX(rssismf5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMF5G, 0); 609f679056bSGábor Stefanik SPEX(rssismc5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMC5G, 610f679056bSGábor Stefanik SSB_SPROM8_RSSISMC5G_SHIFT); 611f679056bSGábor Stefanik SPEX(rssisav5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISAV5G, 612f679056bSGábor Stefanik SSB_SPROM8_RSSISAV5G_SHIFT); 613f679056bSGábor Stefanik SPEX(bxa5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_BXA5G, 614f679056bSGábor Stefanik SSB_SPROM8_BXA5G_SHIFT); 615f679056bSGábor Stefanik SPEX(pa0b0, SSB_SPROM8_PA0B0, 0xFFFF, 0); 616f679056bSGábor Stefanik SPEX(pa0b1, SSB_SPROM8_PA0B1, 0xFFFF, 0); 617f679056bSGábor Stefanik SPEX(pa0b2, SSB_SPROM8_PA0B2, 0xFFFF, 0); 618f679056bSGábor Stefanik SPEX(pa1b0, SSB_SPROM8_PA1B0, 0xFFFF, 0); 619f679056bSGábor Stefanik SPEX(pa1b1, SSB_SPROM8_PA1B1, 0xFFFF, 0); 620f679056bSGábor Stefanik SPEX(pa1b2, SSB_SPROM8_PA1B2, 0xFFFF, 0); 621f679056bSGábor Stefanik SPEX(pa1lob0, SSB_SPROM8_PA1LOB0, 0xFFFF, 0); 622f679056bSGábor Stefanik SPEX(pa1lob1, SSB_SPROM8_PA1LOB1, 0xFFFF, 0); 623f679056bSGábor Stefanik SPEX(pa1lob2, SSB_SPROM8_PA1LOB2, 0xFFFF, 0); 624f679056bSGábor Stefanik SPEX(pa1hib0, SSB_SPROM8_PA1HIB0, 0xFFFF, 0); 625f679056bSGábor Stefanik SPEX(pa1hib1, SSB_SPROM8_PA1HIB1, 0xFFFF, 0); 626f679056bSGábor Stefanik SPEX(pa1hib2, SSB_SPROM8_PA1HIB2, 0xFFFF, 0); 627f679056bSGábor Stefanik SPEX(cck2gpo, SSB_SPROM8_CCK2GPO, 0xFFFF, 0); 628f679056bSGábor Stefanik SPEX32(ofdm2gpo, SSB_SPROM8_OFDM2GPO, 0xFFFFFFFF, 0); 629f679056bSGábor Stefanik SPEX32(ofdm5glpo, SSB_SPROM8_OFDM5GLPO, 0xFFFFFFFF, 0); 630f679056bSGábor Stefanik SPEX32(ofdm5gpo, SSB_SPROM8_OFDM5GPO, 0xFFFFFFFF, 0); 631f679056bSGábor Stefanik SPEX32(ofdm5ghpo, SSB_SPROM8_OFDM5GHPO, 0xFFFFFFFF, 0); 6326b1c7c67SMichael Buesch 6336b1c7c67SMichael Buesch /* Extract the antenna gain values. */ 634*6daf4321SRafał Miłecki out->antenna_gain.a0 = sprom_extract_antgain(out->revision, in, 635*6daf4321SRafał Miłecki SSB_SPROM8_AGAIN01, 636*6daf4321SRafał Miłecki SSB_SPROM8_AGAIN0, 637*6daf4321SRafał Miłecki SSB_SPROM8_AGAIN0_SHIFT); 638*6daf4321SRafał Miłecki out->antenna_gain.a1 = sprom_extract_antgain(out->revision, in, 639*6daf4321SRafał Miłecki SSB_SPROM8_AGAIN01, 640*6daf4321SRafał Miłecki SSB_SPROM8_AGAIN1, 641*6daf4321SRafał Miłecki SSB_SPROM8_AGAIN1_SHIFT); 642*6daf4321SRafał Miłecki out->antenna_gain.a2 = sprom_extract_antgain(out->revision, in, 643*6daf4321SRafał Miłecki SSB_SPROM8_AGAIN23, 644*6daf4321SRafał Miłecki SSB_SPROM8_AGAIN2, 645*6daf4321SRafał Miłecki SSB_SPROM8_AGAIN2_SHIFT); 646*6daf4321SRafał Miłecki out->antenna_gain.a3 = sprom_extract_antgain(out->revision, in, 647*6daf4321SRafał Miłecki SSB_SPROM8_AGAIN23, 648*6daf4321SRafał Miłecki SSB_SPROM8_AGAIN3, 649*6daf4321SRafał Miłecki SSB_SPROM8_AGAIN3_SHIFT); 6506b1c7c67SMichael Buesch 651b0f70292SRafał Miłecki /* Extract cores power info info */ 652b0f70292SRafał Miłecki for (i = 0; i < ARRAY_SIZE(pwr_info_offset); i++) { 653b0f70292SRafał Miłecki o = pwr_info_offset[i]; 654b0f70292SRafał Miłecki SPEX(core_pwr_info[i].itssi_2g, o + SSB_SROM8_2G_MAXP_ITSSI, 655b0f70292SRafał Miłecki SSB_SPROM8_2G_ITSSI, SSB_SPROM8_2G_ITSSI_SHIFT); 656b0f70292SRafał Miłecki SPEX(core_pwr_info[i].maxpwr_2g, o + SSB_SROM8_2G_MAXP_ITSSI, 657b0f70292SRafał Miłecki SSB_SPROM8_2G_MAXP, 0); 658b0f70292SRafał Miłecki 659b0f70292SRafał Miłecki SPEX(core_pwr_info[i].pa_2g[0], o + SSB_SROM8_2G_PA_0, ~0, 0); 660b0f70292SRafał Miłecki SPEX(core_pwr_info[i].pa_2g[1], o + SSB_SROM8_2G_PA_1, ~0, 0); 661b0f70292SRafał Miłecki SPEX(core_pwr_info[i].pa_2g[2], o + SSB_SROM8_2G_PA_2, ~0, 0); 662b0f70292SRafał Miłecki 663b0f70292SRafał Miłecki SPEX(core_pwr_info[i].itssi_5g, o + SSB_SROM8_5G_MAXP_ITSSI, 664b0f70292SRafał Miłecki SSB_SPROM8_5G_ITSSI, SSB_SPROM8_5G_ITSSI_SHIFT); 665b0f70292SRafał Miłecki SPEX(core_pwr_info[i].maxpwr_5g, o + SSB_SROM8_5G_MAXP_ITSSI, 666b0f70292SRafał Miłecki SSB_SPROM8_5G_MAXP, 0); 667b0f70292SRafał Miłecki SPEX(core_pwr_info[i].maxpwr_5gh, o + SSB_SPROM8_5GHL_MAXP, 668b0f70292SRafał Miłecki SSB_SPROM8_5GH_MAXP, 0); 669b0f70292SRafał Miłecki SPEX(core_pwr_info[i].maxpwr_5gl, o + SSB_SPROM8_5GHL_MAXP, 670b0f70292SRafał Miłecki SSB_SPROM8_5GL_MAXP, SSB_SPROM8_5GL_MAXP_SHIFT); 671b0f70292SRafał Miłecki 672b0f70292SRafał Miłecki SPEX(core_pwr_info[i].pa_5gl[0], o + SSB_SROM8_5GL_PA_0, ~0, 0); 673b0f70292SRafał Miłecki SPEX(core_pwr_info[i].pa_5gl[1], o + SSB_SROM8_5GL_PA_1, ~0, 0); 674b0f70292SRafał Miłecki SPEX(core_pwr_info[i].pa_5gl[2], o + SSB_SROM8_5GL_PA_2, ~0, 0); 675b0f70292SRafał Miłecki SPEX(core_pwr_info[i].pa_5g[0], o + SSB_SROM8_5G_PA_0, ~0, 0); 676b0f70292SRafał Miłecki SPEX(core_pwr_info[i].pa_5g[1], o + SSB_SROM8_5G_PA_1, ~0, 0); 677b0f70292SRafał Miłecki SPEX(core_pwr_info[i].pa_5g[2], o + SSB_SROM8_5G_PA_2, ~0, 0); 678b0f70292SRafał Miłecki SPEX(core_pwr_info[i].pa_5gh[0], o + SSB_SROM8_5GH_PA_0, ~0, 0); 679b0f70292SRafał Miłecki SPEX(core_pwr_info[i].pa_5gh[1], o + SSB_SROM8_5GH_PA_1, ~0, 0); 680b0f70292SRafał Miłecki SPEX(core_pwr_info[i].pa_5gh[2], o + SSB_SROM8_5GH_PA_2, ~0, 0); 681b0f70292SRafał Miłecki } 682b0f70292SRafał Miłecki 6838a5ac6ecSRafał Miłecki /* Extract FEM info */ 6848a5ac6ecSRafał Miłecki SPEX(fem.ghz2.tssipos, SSB_SPROM8_FEM2G, 6858a5ac6ecSRafał Miłecki SSB_SROM8_FEM_TSSIPOS, SSB_SROM8_FEM_TSSIPOS_SHIFT); 6868a5ac6ecSRafał Miłecki SPEX(fem.ghz2.extpa_gain, SSB_SPROM8_FEM2G, 6878a5ac6ecSRafał Miłecki SSB_SROM8_FEM_EXTPA_GAIN, SSB_SROM8_FEM_EXTPA_GAIN_SHIFT); 6888a5ac6ecSRafał Miłecki SPEX(fem.ghz2.pdet_range, SSB_SPROM8_FEM2G, 6898a5ac6ecSRafał Miłecki SSB_SROM8_FEM_PDET_RANGE, SSB_SROM8_FEM_PDET_RANGE_SHIFT); 6908a5ac6ecSRafał Miłecki SPEX(fem.ghz2.tr_iso, SSB_SPROM8_FEM2G, 6918a5ac6ecSRafał Miłecki SSB_SROM8_FEM_TR_ISO, SSB_SROM8_FEM_TR_ISO_SHIFT); 6928a5ac6ecSRafał Miłecki SPEX(fem.ghz2.antswlut, SSB_SPROM8_FEM2G, 6938a5ac6ecSRafał Miłecki SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT); 6948a5ac6ecSRafał Miłecki 6958a5ac6ecSRafał Miłecki SPEX(fem.ghz5.tssipos, SSB_SPROM8_FEM5G, 6968a5ac6ecSRafał Miłecki SSB_SROM8_FEM_TSSIPOS, SSB_SROM8_FEM_TSSIPOS_SHIFT); 6978a5ac6ecSRafał Miłecki SPEX(fem.ghz5.extpa_gain, SSB_SPROM8_FEM5G, 6988a5ac6ecSRafał Miłecki SSB_SROM8_FEM_EXTPA_GAIN, SSB_SROM8_FEM_EXTPA_GAIN_SHIFT); 6998a5ac6ecSRafał Miłecki SPEX(fem.ghz5.pdet_range, SSB_SPROM8_FEM5G, 7008a5ac6ecSRafał Miłecki SSB_SROM8_FEM_PDET_RANGE, SSB_SROM8_FEM_PDET_RANGE_SHIFT); 7018a5ac6ecSRafał Miłecki SPEX(fem.ghz5.tr_iso, SSB_SPROM8_FEM5G, 7028a5ac6ecSRafał Miłecki SSB_SROM8_FEM_TR_ISO, SSB_SROM8_FEM_TR_ISO_SHIFT); 7038a5ac6ecSRafał Miłecki SPEX(fem.ghz5.antswlut, SSB_SPROM8_FEM5G, 7048a5ac6ecSRafał Miłecki SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT); 7058a5ac6ecSRafał Miłecki 706e2da4bd3SHauke Mehrtens SPEX(leddc_on_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_ON, 707e2da4bd3SHauke Mehrtens SSB_SPROM8_LEDDC_ON_SHIFT); 708e2da4bd3SHauke Mehrtens SPEX(leddc_off_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_OFF, 709e2da4bd3SHauke Mehrtens SSB_SPROM8_LEDDC_OFF_SHIFT); 710e2da4bd3SHauke Mehrtens 711e2da4bd3SHauke Mehrtens SPEX(txchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_TXCHAIN, 712e2da4bd3SHauke Mehrtens SSB_SPROM8_TXRXC_TXCHAIN_SHIFT); 713e2da4bd3SHauke Mehrtens SPEX(rxchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_RXCHAIN, 714e2da4bd3SHauke Mehrtens SSB_SPROM8_TXRXC_RXCHAIN_SHIFT); 715e2da4bd3SHauke Mehrtens SPEX(antswitch, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_SWITCH, 716e2da4bd3SHauke Mehrtens SSB_SPROM8_TXRXC_SWITCH_SHIFT); 717e2da4bd3SHauke Mehrtens 718e2da4bd3SHauke Mehrtens SPEX(opo, SSB_SPROM8_OFDM2GPO, 0x00ff, 0); 719e2da4bd3SHauke Mehrtens 720e2da4bd3SHauke Mehrtens SPEX_ARRAY8(mcs2gpo, SSB_SPROM8_2G_MCSPO, ~0, 0); 721e2da4bd3SHauke Mehrtens SPEX_ARRAY8(mcs5gpo, SSB_SPROM8_5G_MCSPO, ~0, 0); 722e2da4bd3SHauke Mehrtens SPEX_ARRAY8(mcs5glpo, SSB_SPROM8_5GL_MCSPO, ~0, 0); 723e2da4bd3SHauke Mehrtens SPEX_ARRAY8(mcs5ghpo, SSB_SPROM8_5GH_MCSPO, ~0, 0); 724e2da4bd3SHauke Mehrtens 725e2da4bd3SHauke Mehrtens SPEX(rawtempsense, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_RAWTEMP, 726e2da4bd3SHauke Mehrtens SSB_SPROM8_RAWTS_RAWTEMP_SHIFT); 727e2da4bd3SHauke Mehrtens SPEX(measpower, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_MEASPOWER, 728e2da4bd3SHauke Mehrtens SSB_SPROM8_RAWTS_MEASPOWER_SHIFT); 729e2da4bd3SHauke Mehrtens SPEX(tempsense_slope, SSB_SPROM8_OPT_CORRX, 730e2da4bd3SHauke Mehrtens SSB_SPROM8_OPT_CORRX_TEMP_SLOPE, 731e2da4bd3SHauke Mehrtens SSB_SPROM8_OPT_CORRX_TEMP_SLOPE_SHIFT); 732e2da4bd3SHauke Mehrtens SPEX(tempcorrx, SSB_SPROM8_OPT_CORRX, SSB_SPROM8_OPT_CORRX_TEMPCORRX, 733e2da4bd3SHauke Mehrtens SSB_SPROM8_OPT_CORRX_TEMPCORRX_SHIFT); 734e2da4bd3SHauke Mehrtens SPEX(tempsense_option, SSB_SPROM8_OPT_CORRX, 735e2da4bd3SHauke Mehrtens SSB_SPROM8_OPT_CORRX_TEMP_OPTION, 736e2da4bd3SHauke Mehrtens SSB_SPROM8_OPT_CORRX_TEMP_OPTION_SHIFT); 737e2da4bd3SHauke Mehrtens SPEX(freqoffset_corr, SSB_SPROM8_HWIQ_IQSWP, 738e2da4bd3SHauke Mehrtens SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR, 739e2da4bd3SHauke Mehrtens SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR_SHIFT); 740e2da4bd3SHauke Mehrtens SPEX(iqcal_swp_dis, SSB_SPROM8_HWIQ_IQSWP, 741e2da4bd3SHauke Mehrtens SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP, 742e2da4bd3SHauke Mehrtens SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP_SHIFT); 743e2da4bd3SHauke Mehrtens SPEX(hw_iqcal_en, SSB_SPROM8_HWIQ_IQSWP, SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL, 744e2da4bd3SHauke Mehrtens SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL_SHIFT); 745e2da4bd3SHauke Mehrtens 746e2da4bd3SHauke Mehrtens SPEX(bw40po, SSB_SPROM8_BW40PO, ~0, 0); 747e2da4bd3SHauke Mehrtens SPEX(cddpo, SSB_SPROM8_CDDPO, ~0, 0); 748e2da4bd3SHauke Mehrtens SPEX(stbcpo, SSB_SPROM8_STBCPO, ~0, 0); 749e2da4bd3SHauke Mehrtens SPEX(bwduppo, SSB_SPROM8_BWDUPPO, ~0, 0); 750e2da4bd3SHauke Mehrtens 751e2da4bd3SHauke Mehrtens SPEX(tempthresh, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_TRESH, 752e2da4bd3SHauke Mehrtens SSB_SPROM8_THERMAL_TRESH_SHIFT); 753e2da4bd3SHauke Mehrtens SPEX(tempoffset, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_OFFSET, 754e2da4bd3SHauke Mehrtens SSB_SPROM8_THERMAL_OFFSET_SHIFT); 755e2da4bd3SHauke Mehrtens SPEX(phycal_tempdelta, SSB_SPROM8_TEMPDELTA, 756e2da4bd3SHauke Mehrtens SSB_SPROM8_TEMPDELTA_PHYCAL, 757e2da4bd3SHauke Mehrtens SSB_SPROM8_TEMPDELTA_PHYCAL_SHIFT); 758e2da4bd3SHauke Mehrtens SPEX(temps_period, SSB_SPROM8_TEMPDELTA, SSB_SPROM8_TEMPDELTA_PERIOD, 759e2da4bd3SHauke Mehrtens SSB_SPROM8_TEMPDELTA_PERIOD_SHIFT); 760e2da4bd3SHauke Mehrtens SPEX(temps_hysteresis, SSB_SPROM8_TEMPDELTA, 761e2da4bd3SHauke Mehrtens SSB_SPROM8_TEMPDELTA_HYSTERESIS, 762e2da4bd3SHauke Mehrtens SSB_SPROM8_TEMPDELTA_HYSTERESIS_SHIFT); 763172c69a4SRafał Miłecki sprom_extract_r458(out, in); 764172c69a4SRafał Miłecki 7656b1c7c67SMichael Buesch /* TODO - get remaining rev 8 stuff needed */ 7666b1c7c67SMichael Buesch } 7676b1c7c67SMichael Buesch 768c272ef44SLarry Finger static int sprom_extract(struct ssb_bus *bus, struct ssb_sprom *out, 769c272ef44SLarry Finger const u16 *in, u16 size) 77061e115a5SMichael Buesch { 77161e115a5SMichael Buesch memset(out, 0, sizeof(*out)); 77261e115a5SMichael Buesch 773c272ef44SLarry Finger out->revision = in[size - 1] & 0x00FF; 77433a606acSJoe Perches ssb_dbg("SPROM revision %d detected\n", out->revision); 77531ce12fbSLarry Finger memset(out->et0mac, 0xFF, 6); /* preset et0 and et1 mac */ 77631ce12fbSLarry Finger memset(out->et1mac, 0xFF, 6); 77754435f9eSRafał Miłecki 77861e115a5SMichael Buesch if ((bus->chip_id & 0xFF00) == 0x4400) { 77961e115a5SMichael Buesch /* Workaround: The BCM44XX chip has a stupid revision 78061e115a5SMichael Buesch * number stored in the SPROM. 78161e115a5SMichael Buesch * Always extract r1. */ 782c272ef44SLarry Finger out->revision = 1; 78333a606acSJoe Perches ssb_dbg("SPROM treated as revision %d\n", out->revision); 78454435f9eSRafał Miłecki } 78554435f9eSRafał Miłecki 7866b1c7c67SMichael Buesch switch (out->revision) { 7876b1c7c67SMichael Buesch case 1: 7886b1c7c67SMichael Buesch case 2: 7896b1c7c67SMichael Buesch case 3: 7906b1c7c67SMichael Buesch sprom_extract_r123(out, in); 7916b1c7c67SMichael Buesch break; 7926b1c7c67SMichael Buesch case 4: 7936b1c7c67SMichael Buesch case 5: 7946b1c7c67SMichael Buesch sprom_extract_r45(out, in); 7956b1c7c67SMichael Buesch break; 7966b1c7c67SMichael Buesch case 8: 7976b1c7c67SMichael Buesch sprom_extract_r8(out, in); 7986b1c7c67SMichael Buesch break; 7996b1c7c67SMichael Buesch default: 80033a606acSJoe Perches ssb_warn("Unsupported SPROM revision %d detected. Will extract v1\n", 80133a606acSJoe Perches out->revision); 802cd559b36SLarry Finger out->revision = 1; 803c272ef44SLarry Finger sprom_extract_r123(out, in); 804c272ef44SLarry Finger } 80561e115a5SMichael Buesch 8064503183aSLarry Finger if (out->boardflags_lo == 0xFFFF) 8074503183aSLarry Finger out->boardflags_lo = 0; /* per specs */ 8084503183aSLarry Finger if (out->boardflags_hi == 0xFFFF) 8094503183aSLarry Finger out->boardflags_hi = 0; /* per specs */ 8104503183aSLarry Finger 81161e115a5SMichael Buesch return 0; 81261e115a5SMichael Buesch } 81361e115a5SMichael Buesch 81461e115a5SMichael Buesch static int ssb_pci_sprom_get(struct ssb_bus *bus, 81561e115a5SMichael Buesch struct ssb_sprom *sprom) 81661e115a5SMichael Buesch { 817ca4a0831SRafał Miłecki int err; 81861e115a5SMichael Buesch u16 *buf; 81961e115a5SMichael Buesch 820d53cdbb9SJohn W. Linville if (!ssb_is_sprom_available(bus)) { 82133a606acSJoe Perches ssb_err("No SPROM available!\n"); 822d53cdbb9SJohn W. Linville return -ENODEV; 823d53cdbb9SJohn W. Linville } 82425985edcSLucas De Marchi if (bus->chipco.dev) { /* can be unavailable! */ 8259d1ac34eSLarry Finger /* 8269d1ac34eSLarry Finger * get SPROM offset: SSB_SPROM_BASE1 except for 8279d1ac34eSLarry Finger * chipcommon rev >= 31 or chip ID is 0x4312 and 8289d1ac34eSLarry Finger * chipcommon status & 3 == 2 8299d1ac34eSLarry Finger */ 8309d1ac34eSLarry Finger if (bus->chipco.dev->id.revision >= 31) 8319d1ac34eSLarry Finger bus->sprom_offset = SSB_SPROM_BASE31; 8329d1ac34eSLarry Finger else if (bus->chip_id == 0x4312 && 8339d1ac34eSLarry Finger (bus->chipco.status & 0x03) == 2) 8349d1ac34eSLarry Finger bus->sprom_offset = SSB_SPROM_BASE31; 8359d1ac34eSLarry Finger else 8369d1ac34eSLarry Finger bus->sprom_offset = SSB_SPROM_BASE1; 837da1fdb02SChristoph Fritz } else { 838da1fdb02SChristoph Fritz bus->sprom_offset = SSB_SPROM_BASE1; 839da1fdb02SChristoph Fritz } 84033a606acSJoe Perches ssb_dbg("SPROM offset is 0x%x\n", bus->sprom_offset); 841ea2db495SRafał Miłecki 842c272ef44SLarry Finger buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL); 84361e115a5SMichael Buesch if (!buf) 844ca4a0831SRafał Miłecki return -ENOMEM; 845c272ef44SLarry Finger bus->sprom_size = SSB_SPROMSIZE_WORDS_R123; 84661e115a5SMichael Buesch sprom_do_read(bus, buf); 847c272ef44SLarry Finger err = sprom_check_crc(buf, bus->sprom_size); 84861e115a5SMichael Buesch if (err) { 8492afc4901SLarry.Finger@lwfinger.net /* try for a 440 byte SPROM - revision 4 and higher */ 850c272ef44SLarry Finger kfree(buf); 851c272ef44SLarry Finger buf = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16), 852c272ef44SLarry Finger GFP_KERNEL); 853c272ef44SLarry Finger if (!buf) 854ca4a0831SRafał Miłecki return -ENOMEM; 855c272ef44SLarry Finger bus->sprom_size = SSB_SPROMSIZE_WORDS_R4; 856c272ef44SLarry Finger sprom_do_read(bus, buf); 857c272ef44SLarry Finger err = sprom_check_crc(buf, bus->sprom_size); 858e79c1ba8SMichael Buesch if (err) { 859e79c1ba8SMichael Buesch /* All CRC attempts failed. 860e79c1ba8SMichael Buesch * Maybe there is no SPROM on the device? 861b3ae52b6SHauke Mehrtens * Now we ask the arch code if there is some sprom 862b3ae52b6SHauke Mehrtens * available for this device in some other storage */ 863b3ae52b6SHauke Mehrtens err = ssb_fill_sprom_with_fallback(bus, sprom); 864b3ae52b6SHauke Mehrtens if (err) { 86533a606acSJoe Perches ssb_warn("WARNING: Using fallback SPROM failed (err %d)\n", 866b3ae52b6SHauke Mehrtens err); 867b3ae52b6SHauke Mehrtens } else { 86833a606acSJoe Perches ssb_dbg("Using SPROM revision %d provided by platform\n", 86933a606acSJoe Perches sprom->revision); 870e79c1ba8SMichael Buesch err = 0; 871e79c1ba8SMichael Buesch goto out_free; 872e79c1ba8SMichael Buesch } 87333a606acSJoe Perches ssb_warn("WARNING: Invalid SPROM CRC (corrupt SPROM)\n"); 874c272ef44SLarry Finger } 875e79c1ba8SMichael Buesch } 876c272ef44SLarry Finger err = sprom_extract(bus, sprom, buf, bus->sprom_size); 87761e115a5SMichael Buesch 878e79c1ba8SMichael Buesch out_free: 87961e115a5SMichael Buesch kfree(buf); 88061e115a5SMichael Buesch return err; 88161e115a5SMichael Buesch } 88261e115a5SMichael Buesch 88361e115a5SMichael Buesch static void ssb_pci_get_boardinfo(struct ssb_bus *bus, 88461e115a5SMichael Buesch struct ssb_boardinfo *bi) 88561e115a5SMichael Buesch { 886115f9450SSergei Shtylyov bi->vendor = bus->host_pci->subsystem_vendor; 887115f9450SSergei Shtylyov bi->type = bus->host_pci->subsystem_device; 88861e115a5SMichael Buesch } 88961e115a5SMichael Buesch 89061e115a5SMichael Buesch int ssb_pci_get_invariants(struct ssb_bus *bus, 89161e115a5SMichael Buesch struct ssb_init_invariants *iv) 89261e115a5SMichael Buesch { 89361e115a5SMichael Buesch int err; 89461e115a5SMichael Buesch 89561e115a5SMichael Buesch err = ssb_pci_sprom_get(bus, &iv->sprom); 89661e115a5SMichael Buesch if (err) 89761e115a5SMichael Buesch goto out; 89861e115a5SMichael Buesch ssb_pci_get_boardinfo(bus, &iv->boardinfo); 89961e115a5SMichael Buesch 90061e115a5SMichael Buesch out: 90161e115a5SMichael Buesch return err; 90261e115a5SMichael Buesch } 90361e115a5SMichael Buesch 90461e115a5SMichael Buesch #ifdef CONFIG_SSB_DEBUG 90561e115a5SMichael Buesch static int ssb_pci_assert_buspower(struct ssb_bus *bus) 90661e115a5SMichael Buesch { 90761e115a5SMichael Buesch if (likely(bus->powered_up)) 90861e115a5SMichael Buesch return 0; 90961e115a5SMichael Buesch 91061e115a5SMichael Buesch printk(KERN_ERR PFX "FATAL ERROR: Bus powered down " 91161e115a5SMichael Buesch "while accessing PCI MMIO space\n"); 91261e115a5SMichael Buesch if (bus->power_warn_count <= 10) { 91361e115a5SMichael Buesch bus->power_warn_count++; 91461e115a5SMichael Buesch dump_stack(); 91561e115a5SMichael Buesch } 91661e115a5SMichael Buesch 91761e115a5SMichael Buesch return -ENODEV; 91861e115a5SMichael Buesch } 91961e115a5SMichael Buesch #else /* DEBUG */ 92061e115a5SMichael Buesch static inline int ssb_pci_assert_buspower(struct ssb_bus *bus) 92161e115a5SMichael Buesch { 92261e115a5SMichael Buesch return 0; 92361e115a5SMichael Buesch } 92461e115a5SMichael Buesch #endif /* DEBUG */ 92561e115a5SMichael Buesch 926ffc7689dSMichael Buesch static u8 ssb_pci_read8(struct ssb_device *dev, u16 offset) 927ffc7689dSMichael Buesch { 928ffc7689dSMichael Buesch struct ssb_bus *bus = dev->bus; 929ffc7689dSMichael Buesch 930ffc7689dSMichael Buesch if (unlikely(ssb_pci_assert_buspower(bus))) 931ffc7689dSMichael Buesch return 0xFF; 932ffc7689dSMichael Buesch if (unlikely(bus->mapped_device != dev)) { 933ffc7689dSMichael Buesch if (unlikely(ssb_pci_switch_core(bus, dev))) 934ffc7689dSMichael Buesch return 0xFF; 935ffc7689dSMichael Buesch } 936ffc7689dSMichael Buesch return ioread8(bus->mmio + offset); 937ffc7689dSMichael Buesch } 938ffc7689dSMichael Buesch 93961e115a5SMichael Buesch static u16 ssb_pci_read16(struct ssb_device *dev, u16 offset) 94061e115a5SMichael Buesch { 94161e115a5SMichael Buesch struct ssb_bus *bus = dev->bus; 94261e115a5SMichael Buesch 94361e115a5SMichael Buesch if (unlikely(ssb_pci_assert_buspower(bus))) 94461e115a5SMichael Buesch return 0xFFFF; 94561e115a5SMichael Buesch if (unlikely(bus->mapped_device != dev)) { 94661e115a5SMichael Buesch if (unlikely(ssb_pci_switch_core(bus, dev))) 94761e115a5SMichael Buesch return 0xFFFF; 94861e115a5SMichael Buesch } 9494b402c65SMichael Buesch return ioread16(bus->mmio + offset); 95061e115a5SMichael Buesch } 95161e115a5SMichael Buesch 95261e115a5SMichael Buesch static u32 ssb_pci_read32(struct ssb_device *dev, u16 offset) 95361e115a5SMichael Buesch { 95461e115a5SMichael Buesch struct ssb_bus *bus = dev->bus; 95561e115a5SMichael Buesch 95661e115a5SMichael Buesch if (unlikely(ssb_pci_assert_buspower(bus))) 95761e115a5SMichael Buesch return 0xFFFFFFFF; 95861e115a5SMichael Buesch if (unlikely(bus->mapped_device != dev)) { 95961e115a5SMichael Buesch if (unlikely(ssb_pci_switch_core(bus, dev))) 96061e115a5SMichael Buesch return 0xFFFFFFFF; 96161e115a5SMichael Buesch } 9624b402c65SMichael Buesch return ioread32(bus->mmio + offset); 96361e115a5SMichael Buesch } 96461e115a5SMichael Buesch 965d625a29bSMichael Buesch #ifdef CONFIG_SSB_BLOCKIO 966d625a29bSMichael Buesch static void ssb_pci_block_read(struct ssb_device *dev, void *buffer, 967d625a29bSMichael Buesch size_t count, u16 offset, u8 reg_width) 968d625a29bSMichael Buesch { 969d625a29bSMichael Buesch struct ssb_bus *bus = dev->bus; 970d625a29bSMichael Buesch void __iomem *addr = bus->mmio + offset; 971d625a29bSMichael Buesch 972d625a29bSMichael Buesch if (unlikely(ssb_pci_assert_buspower(bus))) 973d625a29bSMichael Buesch goto error; 974d625a29bSMichael Buesch if (unlikely(bus->mapped_device != dev)) { 975d625a29bSMichael Buesch if (unlikely(ssb_pci_switch_core(bus, dev))) 976d625a29bSMichael Buesch goto error; 977d625a29bSMichael Buesch } 978d625a29bSMichael Buesch switch (reg_width) { 979d625a29bSMichael Buesch case sizeof(u8): 980d625a29bSMichael Buesch ioread8_rep(addr, buffer, count); 981d625a29bSMichael Buesch break; 982d625a29bSMichael Buesch case sizeof(u16): 983d625a29bSMichael Buesch SSB_WARN_ON(count & 1); 984d625a29bSMichael Buesch ioread16_rep(addr, buffer, count >> 1); 985d625a29bSMichael Buesch break; 986d625a29bSMichael Buesch case sizeof(u32): 987d625a29bSMichael Buesch SSB_WARN_ON(count & 3); 988d625a29bSMichael Buesch ioread32_rep(addr, buffer, count >> 2); 989d625a29bSMichael Buesch break; 990d625a29bSMichael Buesch default: 991d625a29bSMichael Buesch SSB_WARN_ON(1); 992d625a29bSMichael Buesch } 993d625a29bSMichael Buesch 994d625a29bSMichael Buesch return; 995d625a29bSMichael Buesch error: 996d625a29bSMichael Buesch memset(buffer, 0xFF, count); 997d625a29bSMichael Buesch } 998d625a29bSMichael Buesch #endif /* CONFIG_SSB_BLOCKIO */ 999d625a29bSMichael Buesch 1000ffc7689dSMichael Buesch static void ssb_pci_write8(struct ssb_device *dev, u16 offset, u8 value) 1001ffc7689dSMichael Buesch { 1002ffc7689dSMichael Buesch struct ssb_bus *bus = dev->bus; 1003ffc7689dSMichael Buesch 1004ffc7689dSMichael Buesch if (unlikely(ssb_pci_assert_buspower(bus))) 1005ffc7689dSMichael Buesch return; 1006ffc7689dSMichael Buesch if (unlikely(bus->mapped_device != dev)) { 1007ffc7689dSMichael Buesch if (unlikely(ssb_pci_switch_core(bus, dev))) 1008ffc7689dSMichael Buesch return; 1009ffc7689dSMichael Buesch } 1010ffc7689dSMichael Buesch iowrite8(value, bus->mmio + offset); 1011ffc7689dSMichael Buesch } 1012ffc7689dSMichael Buesch 101361e115a5SMichael Buesch static void ssb_pci_write16(struct ssb_device *dev, u16 offset, u16 value) 101461e115a5SMichael Buesch { 101561e115a5SMichael Buesch struct ssb_bus *bus = dev->bus; 101661e115a5SMichael Buesch 101761e115a5SMichael Buesch if (unlikely(ssb_pci_assert_buspower(bus))) 101861e115a5SMichael Buesch return; 101961e115a5SMichael Buesch if (unlikely(bus->mapped_device != dev)) { 102061e115a5SMichael Buesch if (unlikely(ssb_pci_switch_core(bus, dev))) 102161e115a5SMichael Buesch return; 102261e115a5SMichael Buesch } 10234b402c65SMichael Buesch iowrite16(value, bus->mmio + offset); 102461e115a5SMichael Buesch } 102561e115a5SMichael Buesch 102661e115a5SMichael Buesch static void ssb_pci_write32(struct ssb_device *dev, u16 offset, u32 value) 102761e115a5SMichael Buesch { 102861e115a5SMichael Buesch struct ssb_bus *bus = dev->bus; 102961e115a5SMichael Buesch 103061e115a5SMichael Buesch if (unlikely(ssb_pci_assert_buspower(bus))) 103161e115a5SMichael Buesch return; 103261e115a5SMichael Buesch if (unlikely(bus->mapped_device != dev)) { 103361e115a5SMichael Buesch if (unlikely(ssb_pci_switch_core(bus, dev))) 103461e115a5SMichael Buesch return; 103561e115a5SMichael Buesch } 10364b402c65SMichael Buesch iowrite32(value, bus->mmio + offset); 103761e115a5SMichael Buesch } 103861e115a5SMichael Buesch 1039d625a29bSMichael Buesch #ifdef CONFIG_SSB_BLOCKIO 1040d625a29bSMichael Buesch static void ssb_pci_block_write(struct ssb_device *dev, const void *buffer, 1041d625a29bSMichael Buesch size_t count, u16 offset, u8 reg_width) 1042d625a29bSMichael Buesch { 1043d625a29bSMichael Buesch struct ssb_bus *bus = dev->bus; 1044d625a29bSMichael Buesch void __iomem *addr = bus->mmio + offset; 1045d625a29bSMichael Buesch 1046d625a29bSMichael Buesch if (unlikely(ssb_pci_assert_buspower(bus))) 1047d625a29bSMichael Buesch return; 1048d625a29bSMichael Buesch if (unlikely(bus->mapped_device != dev)) { 1049d625a29bSMichael Buesch if (unlikely(ssb_pci_switch_core(bus, dev))) 1050d625a29bSMichael Buesch return; 1051d625a29bSMichael Buesch } 1052d625a29bSMichael Buesch switch (reg_width) { 1053d625a29bSMichael Buesch case sizeof(u8): 1054d625a29bSMichael Buesch iowrite8_rep(addr, buffer, count); 1055d625a29bSMichael Buesch break; 1056d625a29bSMichael Buesch case sizeof(u16): 1057d625a29bSMichael Buesch SSB_WARN_ON(count & 1); 1058d625a29bSMichael Buesch iowrite16_rep(addr, buffer, count >> 1); 1059d625a29bSMichael Buesch break; 1060d625a29bSMichael Buesch case sizeof(u32): 1061d625a29bSMichael Buesch SSB_WARN_ON(count & 3); 1062d625a29bSMichael Buesch iowrite32_rep(addr, buffer, count >> 2); 1063d625a29bSMichael Buesch break; 1064d625a29bSMichael Buesch default: 1065d625a29bSMichael Buesch SSB_WARN_ON(1); 1066d625a29bSMichael Buesch } 1067d625a29bSMichael Buesch } 1068d625a29bSMichael Buesch #endif /* CONFIG_SSB_BLOCKIO */ 1069d625a29bSMichael Buesch 107061e115a5SMichael Buesch /* Not "static", as it's used in main.c */ 107161e115a5SMichael Buesch const struct ssb_bus_ops ssb_pci_ops = { 1072ffc7689dSMichael Buesch .read8 = ssb_pci_read8, 107361e115a5SMichael Buesch .read16 = ssb_pci_read16, 107461e115a5SMichael Buesch .read32 = ssb_pci_read32, 1075ffc7689dSMichael Buesch .write8 = ssb_pci_write8, 107661e115a5SMichael Buesch .write16 = ssb_pci_write16, 107761e115a5SMichael Buesch .write32 = ssb_pci_write32, 1078d625a29bSMichael Buesch #ifdef CONFIG_SSB_BLOCKIO 1079d625a29bSMichael Buesch .block_read = ssb_pci_block_read, 1080d625a29bSMichael Buesch .block_write = ssb_pci_block_write, 1081d625a29bSMichael Buesch #endif 108261e115a5SMichael Buesch }; 108361e115a5SMichael Buesch 108461e115a5SMichael Buesch static ssize_t ssb_pci_attr_sprom_show(struct device *pcidev, 108561e115a5SMichael Buesch struct device_attribute *attr, 108661e115a5SMichael Buesch char *buf) 108761e115a5SMichael Buesch { 108861e115a5SMichael Buesch struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev); 108961e115a5SMichael Buesch struct ssb_bus *bus; 109061e115a5SMichael Buesch 109161e115a5SMichael Buesch bus = ssb_pci_dev_to_bus(pdev); 109261e115a5SMichael Buesch if (!bus) 1093e7ec2e32SMichael Buesch return -ENODEV; 109461e115a5SMichael Buesch 1095e7ec2e32SMichael Buesch return ssb_attr_sprom_show(bus, buf, sprom_do_read); 109661e115a5SMichael Buesch } 109761e115a5SMichael Buesch 109861e115a5SMichael Buesch static ssize_t ssb_pci_attr_sprom_store(struct device *pcidev, 109961e115a5SMichael Buesch struct device_attribute *attr, 110061e115a5SMichael Buesch const char *buf, size_t count) 110161e115a5SMichael Buesch { 110261e115a5SMichael Buesch struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev); 110361e115a5SMichael Buesch struct ssb_bus *bus; 110461e115a5SMichael Buesch 110561e115a5SMichael Buesch bus = ssb_pci_dev_to_bus(pdev); 110661e115a5SMichael Buesch if (!bus) 1107e7ec2e32SMichael Buesch return -ENODEV; 110861e115a5SMichael Buesch 1109e7ec2e32SMichael Buesch return ssb_attr_sprom_store(bus, buf, count, 1110e7ec2e32SMichael Buesch sprom_check_crc, sprom_do_write); 111161e115a5SMichael Buesch } 111261e115a5SMichael Buesch 111361e115a5SMichael Buesch static DEVICE_ATTR(ssb_sprom, 0600, 111461e115a5SMichael Buesch ssb_pci_attr_sprom_show, 111561e115a5SMichael Buesch ssb_pci_attr_sprom_store); 111661e115a5SMichael Buesch 111761e115a5SMichael Buesch void ssb_pci_exit(struct ssb_bus *bus) 111861e115a5SMichael Buesch { 111961e115a5SMichael Buesch struct pci_dev *pdev; 112061e115a5SMichael Buesch 112161e115a5SMichael Buesch if (bus->bustype != SSB_BUSTYPE_PCI) 112261e115a5SMichael Buesch return; 112361e115a5SMichael Buesch 112461e115a5SMichael Buesch pdev = bus->host_pci; 112561e115a5SMichael Buesch device_remove_file(&pdev->dev, &dev_attr_ssb_sprom); 112661e115a5SMichael Buesch } 112761e115a5SMichael Buesch 112861e115a5SMichael Buesch int ssb_pci_init(struct ssb_bus *bus) 112961e115a5SMichael Buesch { 113061e115a5SMichael Buesch struct pci_dev *pdev; 113161e115a5SMichael Buesch int err; 113261e115a5SMichael Buesch 113361e115a5SMichael Buesch if (bus->bustype != SSB_BUSTYPE_PCI) 113461e115a5SMichael Buesch return 0; 113561e115a5SMichael Buesch 113661e115a5SMichael Buesch pdev = bus->host_pci; 1137e7ec2e32SMichael Buesch mutex_init(&bus->sprom_mutex); 113861e115a5SMichael Buesch err = device_create_file(&pdev->dev, &dev_attr_ssb_sprom); 113961e115a5SMichael Buesch if (err) 114061e115a5SMichael Buesch goto out; 114161e115a5SMichael Buesch 114261e115a5SMichael Buesch out: 114361e115a5SMichael Buesch return err; 114461e115a5SMichael Buesch } 1145