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 329e861b98dSMichael Buesch static s8 r123_extract_antgain(u8 sprom_revision, const u16 *in, 330e861b98dSMichael Buesch u16 mask, u16 shift) 331e861b98dSMichael Buesch { 332e861b98dSMichael Buesch u16 v; 333e861b98dSMichael Buesch u8 gain; 334e861b98dSMichael Buesch 335e861b98dSMichael Buesch v = in[SPOFF(SSB_SPROM1_AGAIN)]; 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 350c272ef44SLarry Finger static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in) 351c272ef44SLarry Finger { 352c272ef44SLarry Finger u16 loc[3]; 353c272ef44SLarry Finger 35431ce12fbSLarry Finger if (out->revision == 3) /* rev 3 moved MAC */ 355c272ef44SLarry Finger loc[0] = SSB_SPROM3_IL0MAC; 35631ce12fbSLarry Finger else { 357c272ef44SLarry Finger loc[0] = SSB_SPROM1_IL0MAC; 358c272ef44SLarry Finger loc[1] = SSB_SPROM1_ET0MAC; 359c272ef44SLarry Finger loc[2] = SSB_SPROM1_ET1MAC; 360c272ef44SLarry Finger } 361e5652756SJoe Perches sprom_get_mac(out->il0mac, &in[SPOFF(loc[0])]); 36231ce12fbSLarry Finger if (out->revision < 3) { /* only rev 1-2 have et0, et1 */ 363e5652756SJoe Perches sprom_get_mac(out->et0mac, &in[SPOFF(loc[1])]); 364e5652756SJoe Perches sprom_get_mac(out->et1mac, &in[SPOFF(loc[2])]); 36531ce12fbSLarry Finger } 366c272ef44SLarry Finger SPEX(et0phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0A, 0); 367c272ef44SLarry Finger SPEX(et1phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1A, 368c272ef44SLarry Finger SSB_SPROM1_ETHPHY_ET1A_SHIFT); 369e861b98dSMichael Buesch SPEX(et0mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0M, 14); 370e861b98dSMichael Buesch SPEX(et1mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1M, 15); 371e861b98dSMichael Buesch SPEX(board_rev, SSB_SPROM1_BINF, SSB_SPROM1_BINF_BREV, 0); 372*3623b266SRafał Miłecki SPEX(board_type, SSB_SPROM1_SPID, 0xFFFF, 0); 373bf7d420bSHauke Mehrtens if (out->revision == 1) 374c272ef44SLarry Finger SPEX(country_code, SSB_SPROM1_BINF, SSB_SPROM1_BINF_CCODE, 375c272ef44SLarry Finger SSB_SPROM1_BINF_CCODE_SHIFT); 376e861b98dSMichael Buesch SPEX(ant_available_a, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTA, 377e861b98dSMichael Buesch SSB_SPROM1_BINF_ANTA_SHIFT); 378e861b98dSMichael Buesch SPEX(ant_available_bg, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTBG, 379e861b98dSMichael Buesch SSB_SPROM1_BINF_ANTBG_SHIFT); 380c272ef44SLarry Finger SPEX(pa0b0, SSB_SPROM1_PA0B0, 0xFFFF, 0); 381c272ef44SLarry Finger SPEX(pa0b1, SSB_SPROM1_PA0B1, 0xFFFF, 0); 382c272ef44SLarry Finger SPEX(pa0b2, SSB_SPROM1_PA0B2, 0xFFFF, 0); 383c272ef44SLarry Finger SPEX(pa1b0, SSB_SPROM1_PA1B0, 0xFFFF, 0); 384c272ef44SLarry Finger SPEX(pa1b1, SSB_SPROM1_PA1B1, 0xFFFF, 0); 385c272ef44SLarry Finger SPEX(pa1b2, SSB_SPROM1_PA1B2, 0xFFFF, 0); 386c272ef44SLarry Finger SPEX(gpio0, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P0, 0); 387c272ef44SLarry Finger SPEX(gpio1, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P1, 388c272ef44SLarry Finger SSB_SPROM1_GPIOA_P1_SHIFT); 389c272ef44SLarry Finger SPEX(gpio2, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P2, 0); 390c272ef44SLarry Finger SPEX(gpio3, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P3, 391c272ef44SLarry Finger SSB_SPROM1_GPIOB_P3_SHIFT); 392c272ef44SLarry Finger SPEX(maxpwr_a, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_A, 393c272ef44SLarry Finger SSB_SPROM1_MAXPWR_A_SHIFT); 394c272ef44SLarry Finger SPEX(maxpwr_bg, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_BG, 0); 395c272ef44SLarry Finger SPEX(itssi_a, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_A, 396c272ef44SLarry Finger SSB_SPROM1_ITSSI_A_SHIFT); 397c272ef44SLarry Finger SPEX(itssi_bg, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_BG, 0); 398c272ef44SLarry Finger SPEX(boardflags_lo, SSB_SPROM1_BFLLO, 0xFFFF, 0); 399af4b7450SMichael Buesch if (out->revision >= 2) 400af4b7450SMichael Buesch SPEX(boardflags_hi, SSB_SPROM2_BFLHI, 0xFFFF, 0); 401bf7d420bSHauke Mehrtens SPEX(alpha2[0], SSB_SPROM1_CCODE, 0xff00, 8); 402bf7d420bSHauke Mehrtens SPEX(alpha2[1], SSB_SPROM1_CCODE, 0x00ff, 0); 403e861b98dSMichael Buesch 404e861b98dSMichael Buesch /* Extract the antenna gain values. */ 405f8f8a660SHauke Mehrtens out->antenna_gain.a0 = r123_extract_antgain(out->revision, in, 406e861b98dSMichael Buesch SSB_SPROM1_AGAIN_BG, 407c272ef44SLarry Finger SSB_SPROM1_AGAIN_BG_SHIFT); 408f8f8a660SHauke Mehrtens out->antenna_gain.a1 = r123_extract_antgain(out->revision, in, 409e861b98dSMichael Buesch SSB_SPROM1_AGAIN_A, 410e861b98dSMichael Buesch SSB_SPROM1_AGAIN_A_SHIFT); 411c272ef44SLarry Finger } 412c272ef44SLarry Finger 413172c69a4SRafał Miłecki /* Revs 4 5 and 8 have partially shared layout */ 414172c69a4SRafał Miłecki static void sprom_extract_r458(struct ssb_sprom *out, const u16 *in) 415172c69a4SRafał Miłecki { 416172c69a4SRafał Miłecki SPEX(txpid2g[0], SSB_SPROM4_TXPID2G01, 417172c69a4SRafał Miłecki SSB_SPROM4_TXPID2G0, SSB_SPROM4_TXPID2G0_SHIFT); 418172c69a4SRafał Miłecki SPEX(txpid2g[1], SSB_SPROM4_TXPID2G01, 419172c69a4SRafał Miłecki SSB_SPROM4_TXPID2G1, SSB_SPROM4_TXPID2G1_SHIFT); 420172c69a4SRafał Miłecki SPEX(txpid2g[2], SSB_SPROM4_TXPID2G23, 421172c69a4SRafał Miłecki SSB_SPROM4_TXPID2G2, SSB_SPROM4_TXPID2G2_SHIFT); 422172c69a4SRafał Miłecki SPEX(txpid2g[3], SSB_SPROM4_TXPID2G23, 423172c69a4SRafał Miłecki SSB_SPROM4_TXPID2G3, SSB_SPROM4_TXPID2G3_SHIFT); 424172c69a4SRafał Miłecki 425172c69a4SRafał Miłecki SPEX(txpid5gl[0], SSB_SPROM4_TXPID5GL01, 426172c69a4SRafał Miłecki SSB_SPROM4_TXPID5GL0, SSB_SPROM4_TXPID5GL0_SHIFT); 427172c69a4SRafał Miłecki SPEX(txpid5gl[1], SSB_SPROM4_TXPID5GL01, 428172c69a4SRafał Miłecki SSB_SPROM4_TXPID5GL1, SSB_SPROM4_TXPID5GL1_SHIFT); 429172c69a4SRafał Miłecki SPEX(txpid5gl[2], SSB_SPROM4_TXPID5GL23, 430172c69a4SRafał Miłecki SSB_SPROM4_TXPID5GL2, SSB_SPROM4_TXPID5GL2_SHIFT); 431172c69a4SRafał Miłecki SPEX(txpid5gl[3], SSB_SPROM4_TXPID5GL23, 432172c69a4SRafał Miłecki SSB_SPROM4_TXPID5GL3, SSB_SPROM4_TXPID5GL3_SHIFT); 433172c69a4SRafał Miłecki 434172c69a4SRafał Miłecki SPEX(txpid5g[0], SSB_SPROM4_TXPID5G01, 435172c69a4SRafał Miłecki SSB_SPROM4_TXPID5G0, SSB_SPROM4_TXPID5G0_SHIFT); 436172c69a4SRafał Miłecki SPEX(txpid5g[1], SSB_SPROM4_TXPID5G01, 437172c69a4SRafał Miłecki SSB_SPROM4_TXPID5G1, SSB_SPROM4_TXPID5G1_SHIFT); 438172c69a4SRafał Miłecki SPEX(txpid5g[2], SSB_SPROM4_TXPID5G23, 439172c69a4SRafał Miłecki SSB_SPROM4_TXPID5G2, SSB_SPROM4_TXPID5G2_SHIFT); 440172c69a4SRafał Miłecki SPEX(txpid5g[3], SSB_SPROM4_TXPID5G23, 441172c69a4SRafał Miłecki SSB_SPROM4_TXPID5G3, SSB_SPROM4_TXPID5G3_SHIFT); 442172c69a4SRafał Miłecki 443172c69a4SRafał Miłecki SPEX(txpid5gh[0], SSB_SPROM4_TXPID5GH01, 444172c69a4SRafał Miłecki SSB_SPROM4_TXPID5GH0, SSB_SPROM4_TXPID5GH0_SHIFT); 445172c69a4SRafał Miłecki SPEX(txpid5gh[1], SSB_SPROM4_TXPID5GH01, 446172c69a4SRafał Miłecki SSB_SPROM4_TXPID5GH1, SSB_SPROM4_TXPID5GH1_SHIFT); 447172c69a4SRafał Miłecki SPEX(txpid5gh[2], SSB_SPROM4_TXPID5GH23, 448172c69a4SRafał Miłecki SSB_SPROM4_TXPID5GH2, SSB_SPROM4_TXPID5GH2_SHIFT); 449172c69a4SRafał Miłecki SPEX(txpid5gh[3], SSB_SPROM4_TXPID5GH23, 450172c69a4SRafał Miłecki SSB_SPROM4_TXPID5GH3, SSB_SPROM4_TXPID5GH3_SHIFT); 451172c69a4SRafał Miłecki } 452172c69a4SRafał Miłecki 453095f695cSLarry Finger static void sprom_extract_r45(struct ssb_sprom *out, const u16 *in) 45461e115a5SMichael Buesch { 455095f695cSLarry Finger u16 il0mac_offset; 45661e115a5SMichael Buesch 457095f695cSLarry Finger if (out->revision == 4) 458095f695cSLarry Finger il0mac_offset = SSB_SPROM4_IL0MAC; 459095f695cSLarry Finger else 460095f695cSLarry Finger il0mac_offset = SSB_SPROM5_IL0MAC; 461e5652756SJoe Perches 462e5652756SJoe Perches sprom_get_mac(out->il0mac, &in[SPOFF(il0mac_offset)]); 463e5652756SJoe Perches 464c272ef44SLarry Finger SPEX(et0phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET0A, 0); 465c272ef44SLarry Finger SPEX(et1phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET1A, 466c272ef44SLarry Finger SSB_SPROM4_ETHPHY_ET1A_SHIFT); 467673335c8SHauke Mehrtens SPEX(board_rev, SSB_SPROM4_BOARDREV, 0xFFFF, 0); 468*3623b266SRafał Miłecki SPEX(board_type, SSB_SPROM1_SPID, 0xFFFF, 0); 469095f695cSLarry Finger if (out->revision == 4) { 470bf7d420bSHauke Mehrtens SPEX(alpha2[0], SSB_SPROM4_CCODE, 0xff00, 8); 471bf7d420bSHauke Mehrtens SPEX(alpha2[1], SSB_SPROM4_CCODE, 0x00ff, 0); 472c272ef44SLarry Finger SPEX(boardflags_lo, SSB_SPROM4_BFLLO, 0xFFFF, 0); 473af4b7450SMichael Buesch SPEX(boardflags_hi, SSB_SPROM4_BFLHI, 0xFFFF, 0); 4746d1d4ea4SRafał Miłecki SPEX(boardflags2_lo, SSB_SPROM4_BFL2LO, 0xFFFF, 0); 4756d1d4ea4SRafał Miłecki SPEX(boardflags2_hi, SSB_SPROM4_BFL2HI, 0xFFFF, 0); 476095f695cSLarry Finger } else { 477bf7d420bSHauke Mehrtens SPEX(alpha2[0], SSB_SPROM5_CCODE, 0xff00, 8); 478bf7d420bSHauke Mehrtens SPEX(alpha2[1], SSB_SPROM5_CCODE, 0x00ff, 0); 479095f695cSLarry Finger SPEX(boardflags_lo, SSB_SPROM5_BFLLO, 0xFFFF, 0); 480095f695cSLarry Finger SPEX(boardflags_hi, SSB_SPROM5_BFLHI, 0xFFFF, 0); 4816d1d4ea4SRafał Miłecki SPEX(boardflags2_lo, SSB_SPROM5_BFL2LO, 0xFFFF, 0); 4826d1d4ea4SRafał Miłecki SPEX(boardflags2_hi, SSB_SPROM5_BFL2HI, 0xFFFF, 0); 483095f695cSLarry Finger } 484e861b98dSMichael Buesch SPEX(ant_available_a, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_A, 485e861b98dSMichael Buesch SSB_SPROM4_ANTAVAIL_A_SHIFT); 486e861b98dSMichael Buesch SPEX(ant_available_bg, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_BG, 487e861b98dSMichael Buesch SSB_SPROM4_ANTAVAIL_BG_SHIFT); 488d3c319f9SLarry Finger SPEX(maxpwr_bg, SSB_SPROM4_MAXP_BG, SSB_SPROM4_MAXP_BG_MASK, 0); 489d3c319f9SLarry Finger SPEX(itssi_bg, SSB_SPROM4_MAXP_BG, SSB_SPROM4_ITSSI_BG, 490d3c319f9SLarry Finger SSB_SPROM4_ITSSI_BG_SHIFT); 491d3c319f9SLarry Finger SPEX(maxpwr_a, SSB_SPROM4_MAXP_A, SSB_SPROM4_MAXP_A_MASK, 0); 492d3c319f9SLarry Finger SPEX(itssi_a, SSB_SPROM4_MAXP_A, SSB_SPROM4_ITSSI_A, 493d3c319f9SLarry Finger SSB_SPROM4_ITSSI_A_SHIFT); 494095f695cSLarry Finger if (out->revision == 4) { 495d3c319f9SLarry Finger SPEX(gpio0, SSB_SPROM4_GPIOA, SSB_SPROM4_GPIOA_P0, 0); 496d3c319f9SLarry Finger SPEX(gpio1, SSB_SPROM4_GPIOA, SSB_SPROM4_GPIOA_P1, 497d3c319f9SLarry Finger SSB_SPROM4_GPIOA_P1_SHIFT); 498d3c319f9SLarry Finger SPEX(gpio2, SSB_SPROM4_GPIOB, SSB_SPROM4_GPIOB_P2, 0); 499d3c319f9SLarry Finger SPEX(gpio3, SSB_SPROM4_GPIOB, SSB_SPROM4_GPIOB_P3, 500d3c319f9SLarry Finger SSB_SPROM4_GPIOB_P3_SHIFT); 501095f695cSLarry Finger } else { 502095f695cSLarry Finger SPEX(gpio0, SSB_SPROM5_GPIOA, SSB_SPROM5_GPIOA_P0, 0); 503095f695cSLarry Finger SPEX(gpio1, SSB_SPROM5_GPIOA, SSB_SPROM5_GPIOA_P1, 504095f695cSLarry Finger SSB_SPROM5_GPIOA_P1_SHIFT); 505095f695cSLarry Finger SPEX(gpio2, SSB_SPROM5_GPIOB, SSB_SPROM5_GPIOB_P2, 0); 506095f695cSLarry Finger SPEX(gpio3, SSB_SPROM5_GPIOB, SSB_SPROM5_GPIOB_P3, 507095f695cSLarry Finger SSB_SPROM5_GPIOB_P3_SHIFT); 508095f695cSLarry Finger } 509e861b98dSMichael Buesch 510e861b98dSMichael Buesch /* Extract the antenna gain values. */ 511f8f8a660SHauke Mehrtens SPEX(antenna_gain.a0, SSB_SPROM4_AGAIN01, 512e861b98dSMichael Buesch SSB_SPROM4_AGAIN0, SSB_SPROM4_AGAIN0_SHIFT); 513f8f8a660SHauke Mehrtens SPEX(antenna_gain.a1, SSB_SPROM4_AGAIN01, 514e861b98dSMichael Buesch SSB_SPROM4_AGAIN1, SSB_SPROM4_AGAIN1_SHIFT); 515f8f8a660SHauke Mehrtens SPEX(antenna_gain.a2, SSB_SPROM4_AGAIN23, 516e861b98dSMichael Buesch SSB_SPROM4_AGAIN2, SSB_SPROM4_AGAIN2_SHIFT); 517f8f8a660SHauke Mehrtens SPEX(antenna_gain.a3, SSB_SPROM4_AGAIN23, 518e861b98dSMichael Buesch SSB_SPROM4_AGAIN3, SSB_SPROM4_AGAIN3_SHIFT); 519e861b98dSMichael Buesch 520172c69a4SRafał Miłecki sprom_extract_r458(out, in); 521172c69a4SRafał Miłecki 522c272ef44SLarry Finger /* TODO - get remaining rev 4 stuff needed */ 52361e115a5SMichael Buesch } 52461e115a5SMichael Buesch 5256b1c7c67SMichael Buesch static void sprom_extract_r8(struct ssb_sprom *out, const u16 *in) 5266b1c7c67SMichael Buesch { 5276b1c7c67SMichael Buesch int i; 528e5652756SJoe Perches u16 o; 529b0f70292SRafał Miłecki u16 pwr_info_offset[] = { 530b0f70292SRafał Miłecki SSB_SROM8_PWR_INFO_CORE0, SSB_SROM8_PWR_INFO_CORE1, 531b0f70292SRafał Miłecki SSB_SROM8_PWR_INFO_CORE2, SSB_SROM8_PWR_INFO_CORE3 532b0f70292SRafał Miłecki }; 533b0f70292SRafał Miłecki BUILD_BUG_ON(ARRAY_SIZE(pwr_info_offset) != 534b0f70292SRafał Miłecki ARRAY_SIZE(out->core_pwr_info)); 5356b1c7c67SMichael Buesch 5366b1c7c67SMichael Buesch /* extract the MAC address */ 537e5652756SJoe Perches sprom_get_mac(out->il0mac, &in[SPOFF(SSB_SPROM8_IL0MAC)]); 538e5652756SJoe Perches 539673335c8SHauke Mehrtens SPEX(board_rev, SSB_SPROM8_BOARDREV, 0xFFFF, 0); 540*3623b266SRafał Miłecki SPEX(board_type, SSB_SPROM1_SPID, 0xFFFF, 0); 541bf7d420bSHauke Mehrtens SPEX(alpha2[0], SSB_SPROM8_CCODE, 0xff00, 8); 542bf7d420bSHauke Mehrtens SPEX(alpha2[1], SSB_SPROM8_CCODE, 0x00ff, 0); 5436b1c7c67SMichael Buesch SPEX(boardflags_lo, SSB_SPROM8_BFLLO, 0xFFFF, 0); 5446b1c7c67SMichael Buesch SPEX(boardflags_hi, SSB_SPROM8_BFLHI, 0xFFFF, 0); 545f679056bSGábor Stefanik SPEX(boardflags2_lo, SSB_SPROM8_BFL2LO, 0xFFFF, 0); 546f679056bSGábor Stefanik SPEX(boardflags2_hi, SSB_SPROM8_BFL2HI, 0xFFFF, 0); 5476b1c7c67SMichael Buesch SPEX(ant_available_a, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_A, 5486b1c7c67SMichael Buesch SSB_SPROM8_ANTAVAIL_A_SHIFT); 5496b1c7c67SMichael Buesch SPEX(ant_available_bg, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_BG, 5506b1c7c67SMichael Buesch SSB_SPROM8_ANTAVAIL_BG_SHIFT); 5516b1c7c67SMichael Buesch SPEX(maxpwr_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_MAXP_BG_MASK, 0); 5526b1c7c67SMichael Buesch SPEX(itssi_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_ITSSI_BG, 5536b1c7c67SMichael Buesch SSB_SPROM8_ITSSI_BG_SHIFT); 5546b1c7c67SMichael Buesch SPEX(maxpwr_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_MAXP_A_MASK, 0); 5556b1c7c67SMichael Buesch SPEX(itssi_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_ITSSI_A, 5566b1c7c67SMichael Buesch SSB_SPROM8_ITSSI_A_SHIFT); 557f679056bSGábor Stefanik SPEX(maxpwr_ah, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AH_MASK, 0); 558f679056bSGábor Stefanik SPEX(maxpwr_al, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AL_MASK, 559f679056bSGábor Stefanik SSB_SPROM8_MAXP_AL_SHIFT); 5606b1c7c67SMichael Buesch SPEX(gpio0, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P0, 0); 5616b1c7c67SMichael Buesch SPEX(gpio1, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P1, 5626b1c7c67SMichael Buesch SSB_SPROM8_GPIOA_P1_SHIFT); 5636b1c7c67SMichael Buesch SPEX(gpio2, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P2, 0); 5646b1c7c67SMichael Buesch SPEX(gpio3, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P3, 5656b1c7c67SMichael Buesch SSB_SPROM8_GPIOB_P3_SHIFT); 566f679056bSGábor Stefanik SPEX(tri2g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI2G, 0); 567f679056bSGábor Stefanik SPEX(tri5g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI5G, 568f679056bSGábor Stefanik SSB_SPROM8_TRI5G_SHIFT); 569f679056bSGábor Stefanik SPEX(tri5gl, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GL, 0); 570f679056bSGábor Stefanik SPEX(tri5gh, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GH, 571f679056bSGábor Stefanik SSB_SPROM8_TRI5GH_SHIFT); 572f679056bSGábor Stefanik SPEX(rxpo2g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO2G, 0); 573f679056bSGábor Stefanik SPEX(rxpo5g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO5G, 574f679056bSGábor Stefanik SSB_SPROM8_RXPO5G_SHIFT); 575f679056bSGábor Stefanik SPEX(rssismf2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMF2G, 0); 576f679056bSGábor Stefanik SPEX(rssismc2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMC2G, 577f679056bSGábor Stefanik SSB_SPROM8_RSSISMC2G_SHIFT); 578f679056bSGábor Stefanik SPEX(rssisav2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISAV2G, 579f679056bSGábor Stefanik SSB_SPROM8_RSSISAV2G_SHIFT); 580f679056bSGábor Stefanik SPEX(bxa2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_BXA2G, 581f679056bSGábor Stefanik SSB_SPROM8_BXA2G_SHIFT); 582f679056bSGábor Stefanik SPEX(rssismf5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMF5G, 0); 583f679056bSGábor Stefanik SPEX(rssismc5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMC5G, 584f679056bSGábor Stefanik SSB_SPROM8_RSSISMC5G_SHIFT); 585f679056bSGábor Stefanik SPEX(rssisav5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISAV5G, 586f679056bSGábor Stefanik SSB_SPROM8_RSSISAV5G_SHIFT); 587f679056bSGábor Stefanik SPEX(bxa5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_BXA5G, 588f679056bSGábor Stefanik SSB_SPROM8_BXA5G_SHIFT); 589f679056bSGábor Stefanik SPEX(pa0b0, SSB_SPROM8_PA0B0, 0xFFFF, 0); 590f679056bSGábor Stefanik SPEX(pa0b1, SSB_SPROM8_PA0B1, 0xFFFF, 0); 591f679056bSGábor Stefanik SPEX(pa0b2, SSB_SPROM8_PA0B2, 0xFFFF, 0); 592f679056bSGábor Stefanik SPEX(pa1b0, SSB_SPROM8_PA1B0, 0xFFFF, 0); 593f679056bSGábor Stefanik SPEX(pa1b1, SSB_SPROM8_PA1B1, 0xFFFF, 0); 594f679056bSGábor Stefanik SPEX(pa1b2, SSB_SPROM8_PA1B2, 0xFFFF, 0); 595f679056bSGábor Stefanik SPEX(pa1lob0, SSB_SPROM8_PA1LOB0, 0xFFFF, 0); 596f679056bSGábor Stefanik SPEX(pa1lob1, SSB_SPROM8_PA1LOB1, 0xFFFF, 0); 597f679056bSGábor Stefanik SPEX(pa1lob2, SSB_SPROM8_PA1LOB2, 0xFFFF, 0); 598f679056bSGábor Stefanik SPEX(pa1hib0, SSB_SPROM8_PA1HIB0, 0xFFFF, 0); 599f679056bSGábor Stefanik SPEX(pa1hib1, SSB_SPROM8_PA1HIB1, 0xFFFF, 0); 600f679056bSGábor Stefanik SPEX(pa1hib2, SSB_SPROM8_PA1HIB2, 0xFFFF, 0); 601f679056bSGábor Stefanik SPEX(cck2gpo, SSB_SPROM8_CCK2GPO, 0xFFFF, 0); 602f679056bSGábor Stefanik SPEX32(ofdm2gpo, SSB_SPROM8_OFDM2GPO, 0xFFFFFFFF, 0); 603f679056bSGábor Stefanik SPEX32(ofdm5glpo, SSB_SPROM8_OFDM5GLPO, 0xFFFFFFFF, 0); 604f679056bSGábor Stefanik SPEX32(ofdm5gpo, SSB_SPROM8_OFDM5GPO, 0xFFFFFFFF, 0); 605f679056bSGábor Stefanik SPEX32(ofdm5ghpo, SSB_SPROM8_OFDM5GHPO, 0xFFFFFFFF, 0); 6066b1c7c67SMichael Buesch 6076b1c7c67SMichael Buesch /* Extract the antenna gain values. */ 608f8f8a660SHauke Mehrtens SPEX(antenna_gain.a0, SSB_SPROM8_AGAIN01, 6096b1c7c67SMichael Buesch SSB_SPROM8_AGAIN0, SSB_SPROM8_AGAIN0_SHIFT); 610f8f8a660SHauke Mehrtens SPEX(antenna_gain.a1, SSB_SPROM8_AGAIN01, 6116b1c7c67SMichael Buesch SSB_SPROM8_AGAIN1, SSB_SPROM8_AGAIN1_SHIFT); 612f8f8a660SHauke Mehrtens SPEX(antenna_gain.a2, SSB_SPROM8_AGAIN23, 6136b1c7c67SMichael Buesch SSB_SPROM8_AGAIN2, SSB_SPROM8_AGAIN2_SHIFT); 614f8f8a660SHauke Mehrtens SPEX(antenna_gain.a3, SSB_SPROM8_AGAIN23, 6156b1c7c67SMichael Buesch SSB_SPROM8_AGAIN3, SSB_SPROM8_AGAIN3_SHIFT); 6166b1c7c67SMichael Buesch 617b0f70292SRafał Miłecki /* Extract cores power info info */ 618b0f70292SRafał Miłecki for (i = 0; i < ARRAY_SIZE(pwr_info_offset); i++) { 619b0f70292SRafał Miłecki o = pwr_info_offset[i]; 620b0f70292SRafał Miłecki SPEX(core_pwr_info[i].itssi_2g, o + SSB_SROM8_2G_MAXP_ITSSI, 621b0f70292SRafał Miłecki SSB_SPROM8_2G_ITSSI, SSB_SPROM8_2G_ITSSI_SHIFT); 622b0f70292SRafał Miłecki SPEX(core_pwr_info[i].maxpwr_2g, o + SSB_SROM8_2G_MAXP_ITSSI, 623b0f70292SRafał Miłecki SSB_SPROM8_2G_MAXP, 0); 624b0f70292SRafał Miłecki 625b0f70292SRafał Miłecki SPEX(core_pwr_info[i].pa_2g[0], o + SSB_SROM8_2G_PA_0, ~0, 0); 626b0f70292SRafał Miłecki SPEX(core_pwr_info[i].pa_2g[1], o + SSB_SROM8_2G_PA_1, ~0, 0); 627b0f70292SRafał Miłecki SPEX(core_pwr_info[i].pa_2g[2], o + SSB_SROM8_2G_PA_2, ~0, 0); 628b0f70292SRafał Miłecki 629b0f70292SRafał Miłecki SPEX(core_pwr_info[i].itssi_5g, o + SSB_SROM8_5G_MAXP_ITSSI, 630b0f70292SRafał Miłecki SSB_SPROM8_5G_ITSSI, SSB_SPROM8_5G_ITSSI_SHIFT); 631b0f70292SRafał Miłecki SPEX(core_pwr_info[i].maxpwr_5g, o + SSB_SROM8_5G_MAXP_ITSSI, 632b0f70292SRafał Miłecki SSB_SPROM8_5G_MAXP, 0); 633b0f70292SRafał Miłecki SPEX(core_pwr_info[i].maxpwr_5gh, o + SSB_SPROM8_5GHL_MAXP, 634b0f70292SRafał Miłecki SSB_SPROM8_5GH_MAXP, 0); 635b0f70292SRafał Miłecki SPEX(core_pwr_info[i].maxpwr_5gl, o + SSB_SPROM8_5GHL_MAXP, 636b0f70292SRafał Miłecki SSB_SPROM8_5GL_MAXP, SSB_SPROM8_5GL_MAXP_SHIFT); 637b0f70292SRafał Miłecki 638b0f70292SRafał Miłecki SPEX(core_pwr_info[i].pa_5gl[0], o + SSB_SROM8_5GL_PA_0, ~0, 0); 639b0f70292SRafał Miłecki SPEX(core_pwr_info[i].pa_5gl[1], o + SSB_SROM8_5GL_PA_1, ~0, 0); 640b0f70292SRafał Miłecki SPEX(core_pwr_info[i].pa_5gl[2], o + SSB_SROM8_5GL_PA_2, ~0, 0); 641b0f70292SRafał Miłecki SPEX(core_pwr_info[i].pa_5g[0], o + SSB_SROM8_5G_PA_0, ~0, 0); 642b0f70292SRafał Miłecki SPEX(core_pwr_info[i].pa_5g[1], o + SSB_SROM8_5G_PA_1, ~0, 0); 643b0f70292SRafał Miłecki SPEX(core_pwr_info[i].pa_5g[2], o + SSB_SROM8_5G_PA_2, ~0, 0); 644b0f70292SRafał Miłecki SPEX(core_pwr_info[i].pa_5gh[0], o + SSB_SROM8_5GH_PA_0, ~0, 0); 645b0f70292SRafał Miłecki SPEX(core_pwr_info[i].pa_5gh[1], o + SSB_SROM8_5GH_PA_1, ~0, 0); 646b0f70292SRafał Miłecki SPEX(core_pwr_info[i].pa_5gh[2], o + SSB_SROM8_5GH_PA_2, ~0, 0); 647b0f70292SRafał Miłecki } 648b0f70292SRafał Miłecki 6498a5ac6ecSRafał Miłecki /* Extract FEM info */ 6508a5ac6ecSRafał Miłecki SPEX(fem.ghz2.tssipos, SSB_SPROM8_FEM2G, 6518a5ac6ecSRafał Miłecki SSB_SROM8_FEM_TSSIPOS, SSB_SROM8_FEM_TSSIPOS_SHIFT); 6528a5ac6ecSRafał Miłecki SPEX(fem.ghz2.extpa_gain, SSB_SPROM8_FEM2G, 6538a5ac6ecSRafał Miłecki SSB_SROM8_FEM_EXTPA_GAIN, SSB_SROM8_FEM_EXTPA_GAIN_SHIFT); 6548a5ac6ecSRafał Miłecki SPEX(fem.ghz2.pdet_range, SSB_SPROM8_FEM2G, 6558a5ac6ecSRafał Miłecki SSB_SROM8_FEM_PDET_RANGE, SSB_SROM8_FEM_PDET_RANGE_SHIFT); 6568a5ac6ecSRafał Miłecki SPEX(fem.ghz2.tr_iso, SSB_SPROM8_FEM2G, 6578a5ac6ecSRafał Miłecki SSB_SROM8_FEM_TR_ISO, SSB_SROM8_FEM_TR_ISO_SHIFT); 6588a5ac6ecSRafał Miłecki SPEX(fem.ghz2.antswlut, SSB_SPROM8_FEM2G, 6598a5ac6ecSRafał Miłecki SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT); 6608a5ac6ecSRafał Miłecki 6618a5ac6ecSRafał Miłecki SPEX(fem.ghz5.tssipos, SSB_SPROM8_FEM5G, 6628a5ac6ecSRafał Miłecki SSB_SROM8_FEM_TSSIPOS, SSB_SROM8_FEM_TSSIPOS_SHIFT); 6638a5ac6ecSRafał Miłecki SPEX(fem.ghz5.extpa_gain, SSB_SPROM8_FEM5G, 6648a5ac6ecSRafał Miłecki SSB_SROM8_FEM_EXTPA_GAIN, SSB_SROM8_FEM_EXTPA_GAIN_SHIFT); 6658a5ac6ecSRafał Miłecki SPEX(fem.ghz5.pdet_range, SSB_SPROM8_FEM5G, 6668a5ac6ecSRafał Miłecki SSB_SROM8_FEM_PDET_RANGE, SSB_SROM8_FEM_PDET_RANGE_SHIFT); 6678a5ac6ecSRafał Miłecki SPEX(fem.ghz5.tr_iso, SSB_SPROM8_FEM5G, 6688a5ac6ecSRafał Miłecki SSB_SROM8_FEM_TR_ISO, SSB_SROM8_FEM_TR_ISO_SHIFT); 6698a5ac6ecSRafał Miłecki SPEX(fem.ghz5.antswlut, SSB_SPROM8_FEM5G, 6708a5ac6ecSRafał Miłecki SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT); 6718a5ac6ecSRafał Miłecki 672e2da4bd3SHauke Mehrtens SPEX(leddc_on_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_ON, 673e2da4bd3SHauke Mehrtens SSB_SPROM8_LEDDC_ON_SHIFT); 674e2da4bd3SHauke Mehrtens SPEX(leddc_off_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_OFF, 675e2da4bd3SHauke Mehrtens SSB_SPROM8_LEDDC_OFF_SHIFT); 676e2da4bd3SHauke Mehrtens 677e2da4bd3SHauke Mehrtens SPEX(txchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_TXCHAIN, 678e2da4bd3SHauke Mehrtens SSB_SPROM8_TXRXC_TXCHAIN_SHIFT); 679e2da4bd3SHauke Mehrtens SPEX(rxchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_RXCHAIN, 680e2da4bd3SHauke Mehrtens SSB_SPROM8_TXRXC_RXCHAIN_SHIFT); 681e2da4bd3SHauke Mehrtens SPEX(antswitch, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_SWITCH, 682e2da4bd3SHauke Mehrtens SSB_SPROM8_TXRXC_SWITCH_SHIFT); 683e2da4bd3SHauke Mehrtens 684e2da4bd3SHauke Mehrtens SPEX(opo, SSB_SPROM8_OFDM2GPO, 0x00ff, 0); 685e2da4bd3SHauke Mehrtens 686e2da4bd3SHauke Mehrtens SPEX_ARRAY8(mcs2gpo, SSB_SPROM8_2G_MCSPO, ~0, 0); 687e2da4bd3SHauke Mehrtens SPEX_ARRAY8(mcs5gpo, SSB_SPROM8_5G_MCSPO, ~0, 0); 688e2da4bd3SHauke Mehrtens SPEX_ARRAY8(mcs5glpo, SSB_SPROM8_5GL_MCSPO, ~0, 0); 689e2da4bd3SHauke Mehrtens SPEX_ARRAY8(mcs5ghpo, SSB_SPROM8_5GH_MCSPO, ~0, 0); 690e2da4bd3SHauke Mehrtens 691e2da4bd3SHauke Mehrtens SPEX(rawtempsense, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_RAWTEMP, 692e2da4bd3SHauke Mehrtens SSB_SPROM8_RAWTS_RAWTEMP_SHIFT); 693e2da4bd3SHauke Mehrtens SPEX(measpower, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_MEASPOWER, 694e2da4bd3SHauke Mehrtens SSB_SPROM8_RAWTS_MEASPOWER_SHIFT); 695e2da4bd3SHauke Mehrtens SPEX(tempsense_slope, SSB_SPROM8_OPT_CORRX, 696e2da4bd3SHauke Mehrtens SSB_SPROM8_OPT_CORRX_TEMP_SLOPE, 697e2da4bd3SHauke Mehrtens SSB_SPROM8_OPT_CORRX_TEMP_SLOPE_SHIFT); 698e2da4bd3SHauke Mehrtens SPEX(tempcorrx, SSB_SPROM8_OPT_CORRX, SSB_SPROM8_OPT_CORRX_TEMPCORRX, 699e2da4bd3SHauke Mehrtens SSB_SPROM8_OPT_CORRX_TEMPCORRX_SHIFT); 700e2da4bd3SHauke Mehrtens SPEX(tempsense_option, SSB_SPROM8_OPT_CORRX, 701e2da4bd3SHauke Mehrtens SSB_SPROM8_OPT_CORRX_TEMP_OPTION, 702e2da4bd3SHauke Mehrtens SSB_SPROM8_OPT_CORRX_TEMP_OPTION_SHIFT); 703e2da4bd3SHauke Mehrtens SPEX(freqoffset_corr, SSB_SPROM8_HWIQ_IQSWP, 704e2da4bd3SHauke Mehrtens SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR, 705e2da4bd3SHauke Mehrtens SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR_SHIFT); 706e2da4bd3SHauke Mehrtens SPEX(iqcal_swp_dis, SSB_SPROM8_HWIQ_IQSWP, 707e2da4bd3SHauke Mehrtens SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP, 708e2da4bd3SHauke Mehrtens SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP_SHIFT); 709e2da4bd3SHauke Mehrtens SPEX(hw_iqcal_en, SSB_SPROM8_HWIQ_IQSWP, SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL, 710e2da4bd3SHauke Mehrtens SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL_SHIFT); 711e2da4bd3SHauke Mehrtens 712e2da4bd3SHauke Mehrtens SPEX(bw40po, SSB_SPROM8_BW40PO, ~0, 0); 713e2da4bd3SHauke Mehrtens SPEX(cddpo, SSB_SPROM8_CDDPO, ~0, 0); 714e2da4bd3SHauke Mehrtens SPEX(stbcpo, SSB_SPROM8_STBCPO, ~0, 0); 715e2da4bd3SHauke Mehrtens SPEX(bwduppo, SSB_SPROM8_BWDUPPO, ~0, 0); 716e2da4bd3SHauke Mehrtens 717e2da4bd3SHauke Mehrtens SPEX(tempthresh, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_TRESH, 718e2da4bd3SHauke Mehrtens SSB_SPROM8_THERMAL_TRESH_SHIFT); 719e2da4bd3SHauke Mehrtens SPEX(tempoffset, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_OFFSET, 720e2da4bd3SHauke Mehrtens SSB_SPROM8_THERMAL_OFFSET_SHIFT); 721e2da4bd3SHauke Mehrtens SPEX(phycal_tempdelta, SSB_SPROM8_TEMPDELTA, 722e2da4bd3SHauke Mehrtens SSB_SPROM8_TEMPDELTA_PHYCAL, 723e2da4bd3SHauke Mehrtens SSB_SPROM8_TEMPDELTA_PHYCAL_SHIFT); 724e2da4bd3SHauke Mehrtens SPEX(temps_period, SSB_SPROM8_TEMPDELTA, SSB_SPROM8_TEMPDELTA_PERIOD, 725e2da4bd3SHauke Mehrtens SSB_SPROM8_TEMPDELTA_PERIOD_SHIFT); 726e2da4bd3SHauke Mehrtens SPEX(temps_hysteresis, SSB_SPROM8_TEMPDELTA, 727e2da4bd3SHauke Mehrtens SSB_SPROM8_TEMPDELTA_HYSTERESIS, 728e2da4bd3SHauke Mehrtens SSB_SPROM8_TEMPDELTA_HYSTERESIS_SHIFT); 729172c69a4SRafał Miłecki sprom_extract_r458(out, in); 730172c69a4SRafał Miłecki 7316b1c7c67SMichael Buesch /* TODO - get remaining rev 8 stuff needed */ 7326b1c7c67SMichael Buesch } 7336b1c7c67SMichael Buesch 734c272ef44SLarry Finger static int sprom_extract(struct ssb_bus *bus, struct ssb_sprom *out, 735c272ef44SLarry Finger const u16 *in, u16 size) 73661e115a5SMichael Buesch { 73761e115a5SMichael Buesch memset(out, 0, sizeof(*out)); 73861e115a5SMichael Buesch 739c272ef44SLarry Finger out->revision = in[size - 1] & 0x00FF; 74033a606acSJoe Perches ssb_dbg("SPROM revision %d detected\n", out->revision); 74131ce12fbSLarry Finger memset(out->et0mac, 0xFF, 6); /* preset et0 and et1 mac */ 74231ce12fbSLarry Finger memset(out->et1mac, 0xFF, 6); 74354435f9eSRafał Miłecki 74461e115a5SMichael Buesch if ((bus->chip_id & 0xFF00) == 0x4400) { 74561e115a5SMichael Buesch /* Workaround: The BCM44XX chip has a stupid revision 74661e115a5SMichael Buesch * number stored in the SPROM. 74761e115a5SMichael Buesch * Always extract r1. */ 748c272ef44SLarry Finger out->revision = 1; 74933a606acSJoe Perches ssb_dbg("SPROM treated as revision %d\n", out->revision); 75054435f9eSRafał Miłecki } 75154435f9eSRafał Miłecki 7526b1c7c67SMichael Buesch switch (out->revision) { 7536b1c7c67SMichael Buesch case 1: 7546b1c7c67SMichael Buesch case 2: 7556b1c7c67SMichael Buesch case 3: 7566b1c7c67SMichael Buesch sprom_extract_r123(out, in); 7576b1c7c67SMichael Buesch break; 7586b1c7c67SMichael Buesch case 4: 7596b1c7c67SMichael Buesch case 5: 7606b1c7c67SMichael Buesch sprom_extract_r45(out, in); 7616b1c7c67SMichael Buesch break; 7626b1c7c67SMichael Buesch case 8: 7636b1c7c67SMichael Buesch sprom_extract_r8(out, in); 7646b1c7c67SMichael Buesch break; 7656b1c7c67SMichael Buesch default: 76633a606acSJoe Perches ssb_warn("Unsupported SPROM revision %d detected. Will extract v1\n", 76733a606acSJoe Perches out->revision); 768cd559b36SLarry Finger out->revision = 1; 769c272ef44SLarry Finger sprom_extract_r123(out, in); 770c272ef44SLarry Finger } 77161e115a5SMichael Buesch 7724503183aSLarry Finger if (out->boardflags_lo == 0xFFFF) 7734503183aSLarry Finger out->boardflags_lo = 0; /* per specs */ 7744503183aSLarry Finger if (out->boardflags_hi == 0xFFFF) 7754503183aSLarry Finger out->boardflags_hi = 0; /* per specs */ 7764503183aSLarry Finger 77761e115a5SMichael Buesch return 0; 77861e115a5SMichael Buesch } 77961e115a5SMichael Buesch 78061e115a5SMichael Buesch static int ssb_pci_sprom_get(struct ssb_bus *bus, 78161e115a5SMichael Buesch struct ssb_sprom *sprom) 78261e115a5SMichael Buesch { 783ca4a0831SRafał Miłecki int err; 78461e115a5SMichael Buesch u16 *buf; 78561e115a5SMichael Buesch 786d53cdbb9SJohn W. Linville if (!ssb_is_sprom_available(bus)) { 78733a606acSJoe Perches ssb_err("No SPROM available!\n"); 788d53cdbb9SJohn W. Linville return -ENODEV; 789d53cdbb9SJohn W. Linville } 79025985edcSLucas De Marchi if (bus->chipco.dev) { /* can be unavailable! */ 7919d1ac34eSLarry Finger /* 7929d1ac34eSLarry Finger * get SPROM offset: SSB_SPROM_BASE1 except for 7939d1ac34eSLarry Finger * chipcommon rev >= 31 or chip ID is 0x4312 and 7949d1ac34eSLarry Finger * chipcommon status & 3 == 2 7959d1ac34eSLarry Finger */ 7969d1ac34eSLarry Finger if (bus->chipco.dev->id.revision >= 31) 7979d1ac34eSLarry Finger bus->sprom_offset = SSB_SPROM_BASE31; 7989d1ac34eSLarry Finger else if (bus->chip_id == 0x4312 && 7999d1ac34eSLarry Finger (bus->chipco.status & 0x03) == 2) 8009d1ac34eSLarry Finger bus->sprom_offset = SSB_SPROM_BASE31; 8019d1ac34eSLarry Finger else 8029d1ac34eSLarry Finger bus->sprom_offset = SSB_SPROM_BASE1; 803da1fdb02SChristoph Fritz } else { 804da1fdb02SChristoph Fritz bus->sprom_offset = SSB_SPROM_BASE1; 805da1fdb02SChristoph Fritz } 80633a606acSJoe Perches ssb_dbg("SPROM offset is 0x%x\n", bus->sprom_offset); 807ea2db495SRafał Miłecki 808c272ef44SLarry Finger buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL); 80961e115a5SMichael Buesch if (!buf) 810ca4a0831SRafał Miłecki return -ENOMEM; 811c272ef44SLarry Finger bus->sprom_size = SSB_SPROMSIZE_WORDS_R123; 81261e115a5SMichael Buesch sprom_do_read(bus, buf); 813c272ef44SLarry Finger err = sprom_check_crc(buf, bus->sprom_size); 81461e115a5SMichael Buesch if (err) { 8152afc4901SLarry.Finger@lwfinger.net /* try for a 440 byte SPROM - revision 4 and higher */ 816c272ef44SLarry Finger kfree(buf); 817c272ef44SLarry Finger buf = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16), 818c272ef44SLarry Finger GFP_KERNEL); 819c272ef44SLarry Finger if (!buf) 820ca4a0831SRafał Miłecki return -ENOMEM; 821c272ef44SLarry Finger bus->sprom_size = SSB_SPROMSIZE_WORDS_R4; 822c272ef44SLarry Finger sprom_do_read(bus, buf); 823c272ef44SLarry Finger err = sprom_check_crc(buf, bus->sprom_size); 824e79c1ba8SMichael Buesch if (err) { 825e79c1ba8SMichael Buesch /* All CRC attempts failed. 826e79c1ba8SMichael Buesch * Maybe there is no SPROM on the device? 827b3ae52b6SHauke Mehrtens * Now we ask the arch code if there is some sprom 828b3ae52b6SHauke Mehrtens * available for this device in some other storage */ 829b3ae52b6SHauke Mehrtens err = ssb_fill_sprom_with_fallback(bus, sprom); 830b3ae52b6SHauke Mehrtens if (err) { 83133a606acSJoe Perches ssb_warn("WARNING: Using fallback SPROM failed (err %d)\n", 832b3ae52b6SHauke Mehrtens err); 833b3ae52b6SHauke Mehrtens } else { 83433a606acSJoe Perches ssb_dbg("Using SPROM revision %d provided by platform\n", 83533a606acSJoe Perches sprom->revision); 836e79c1ba8SMichael Buesch err = 0; 837e79c1ba8SMichael Buesch goto out_free; 838e79c1ba8SMichael Buesch } 83933a606acSJoe Perches ssb_warn("WARNING: Invalid SPROM CRC (corrupt SPROM)\n"); 840c272ef44SLarry Finger } 841e79c1ba8SMichael Buesch } 842c272ef44SLarry Finger err = sprom_extract(bus, sprom, buf, bus->sprom_size); 84361e115a5SMichael Buesch 844e79c1ba8SMichael Buesch out_free: 84561e115a5SMichael Buesch kfree(buf); 84661e115a5SMichael Buesch return err; 84761e115a5SMichael Buesch } 84861e115a5SMichael Buesch 84961e115a5SMichael Buesch static void ssb_pci_get_boardinfo(struct ssb_bus *bus, 85061e115a5SMichael Buesch struct ssb_boardinfo *bi) 85161e115a5SMichael Buesch { 852115f9450SSergei Shtylyov bi->vendor = bus->host_pci->subsystem_vendor; 853115f9450SSergei Shtylyov bi->type = bus->host_pci->subsystem_device; 85461e115a5SMichael Buesch } 85561e115a5SMichael Buesch 85661e115a5SMichael Buesch int ssb_pci_get_invariants(struct ssb_bus *bus, 85761e115a5SMichael Buesch struct ssb_init_invariants *iv) 85861e115a5SMichael Buesch { 85961e115a5SMichael Buesch int err; 86061e115a5SMichael Buesch 86161e115a5SMichael Buesch err = ssb_pci_sprom_get(bus, &iv->sprom); 86261e115a5SMichael Buesch if (err) 86361e115a5SMichael Buesch goto out; 86461e115a5SMichael Buesch ssb_pci_get_boardinfo(bus, &iv->boardinfo); 86561e115a5SMichael Buesch 86661e115a5SMichael Buesch out: 86761e115a5SMichael Buesch return err; 86861e115a5SMichael Buesch } 86961e115a5SMichael Buesch 87061e115a5SMichael Buesch #ifdef CONFIG_SSB_DEBUG 87161e115a5SMichael Buesch static int ssb_pci_assert_buspower(struct ssb_bus *bus) 87261e115a5SMichael Buesch { 87361e115a5SMichael Buesch if (likely(bus->powered_up)) 87461e115a5SMichael Buesch return 0; 87561e115a5SMichael Buesch 87661e115a5SMichael Buesch printk(KERN_ERR PFX "FATAL ERROR: Bus powered down " 87761e115a5SMichael Buesch "while accessing PCI MMIO space\n"); 87861e115a5SMichael Buesch if (bus->power_warn_count <= 10) { 87961e115a5SMichael Buesch bus->power_warn_count++; 88061e115a5SMichael Buesch dump_stack(); 88161e115a5SMichael Buesch } 88261e115a5SMichael Buesch 88361e115a5SMichael Buesch return -ENODEV; 88461e115a5SMichael Buesch } 88561e115a5SMichael Buesch #else /* DEBUG */ 88661e115a5SMichael Buesch static inline int ssb_pci_assert_buspower(struct ssb_bus *bus) 88761e115a5SMichael Buesch { 88861e115a5SMichael Buesch return 0; 88961e115a5SMichael Buesch } 89061e115a5SMichael Buesch #endif /* DEBUG */ 89161e115a5SMichael Buesch 892ffc7689dSMichael Buesch static u8 ssb_pci_read8(struct ssb_device *dev, u16 offset) 893ffc7689dSMichael Buesch { 894ffc7689dSMichael Buesch struct ssb_bus *bus = dev->bus; 895ffc7689dSMichael Buesch 896ffc7689dSMichael Buesch if (unlikely(ssb_pci_assert_buspower(bus))) 897ffc7689dSMichael Buesch return 0xFF; 898ffc7689dSMichael Buesch if (unlikely(bus->mapped_device != dev)) { 899ffc7689dSMichael Buesch if (unlikely(ssb_pci_switch_core(bus, dev))) 900ffc7689dSMichael Buesch return 0xFF; 901ffc7689dSMichael Buesch } 902ffc7689dSMichael Buesch return ioread8(bus->mmio + offset); 903ffc7689dSMichael Buesch } 904ffc7689dSMichael Buesch 90561e115a5SMichael Buesch static u16 ssb_pci_read16(struct ssb_device *dev, u16 offset) 90661e115a5SMichael Buesch { 90761e115a5SMichael Buesch struct ssb_bus *bus = dev->bus; 90861e115a5SMichael Buesch 90961e115a5SMichael Buesch if (unlikely(ssb_pci_assert_buspower(bus))) 91061e115a5SMichael Buesch return 0xFFFF; 91161e115a5SMichael Buesch if (unlikely(bus->mapped_device != dev)) { 91261e115a5SMichael Buesch if (unlikely(ssb_pci_switch_core(bus, dev))) 91361e115a5SMichael Buesch return 0xFFFF; 91461e115a5SMichael Buesch } 9154b402c65SMichael Buesch return ioread16(bus->mmio + offset); 91661e115a5SMichael Buesch } 91761e115a5SMichael Buesch 91861e115a5SMichael Buesch static u32 ssb_pci_read32(struct ssb_device *dev, u16 offset) 91961e115a5SMichael Buesch { 92061e115a5SMichael Buesch struct ssb_bus *bus = dev->bus; 92161e115a5SMichael Buesch 92261e115a5SMichael Buesch if (unlikely(ssb_pci_assert_buspower(bus))) 92361e115a5SMichael Buesch return 0xFFFFFFFF; 92461e115a5SMichael Buesch if (unlikely(bus->mapped_device != dev)) { 92561e115a5SMichael Buesch if (unlikely(ssb_pci_switch_core(bus, dev))) 92661e115a5SMichael Buesch return 0xFFFFFFFF; 92761e115a5SMichael Buesch } 9284b402c65SMichael Buesch return ioread32(bus->mmio + offset); 92961e115a5SMichael Buesch } 93061e115a5SMichael Buesch 931d625a29bSMichael Buesch #ifdef CONFIG_SSB_BLOCKIO 932d625a29bSMichael Buesch static void ssb_pci_block_read(struct ssb_device *dev, void *buffer, 933d625a29bSMichael Buesch size_t count, u16 offset, u8 reg_width) 934d625a29bSMichael Buesch { 935d625a29bSMichael Buesch struct ssb_bus *bus = dev->bus; 936d625a29bSMichael Buesch void __iomem *addr = bus->mmio + offset; 937d625a29bSMichael Buesch 938d625a29bSMichael Buesch if (unlikely(ssb_pci_assert_buspower(bus))) 939d625a29bSMichael Buesch goto error; 940d625a29bSMichael Buesch if (unlikely(bus->mapped_device != dev)) { 941d625a29bSMichael Buesch if (unlikely(ssb_pci_switch_core(bus, dev))) 942d625a29bSMichael Buesch goto error; 943d625a29bSMichael Buesch } 944d625a29bSMichael Buesch switch (reg_width) { 945d625a29bSMichael Buesch case sizeof(u8): 946d625a29bSMichael Buesch ioread8_rep(addr, buffer, count); 947d625a29bSMichael Buesch break; 948d625a29bSMichael Buesch case sizeof(u16): 949d625a29bSMichael Buesch SSB_WARN_ON(count & 1); 950d625a29bSMichael Buesch ioread16_rep(addr, buffer, count >> 1); 951d625a29bSMichael Buesch break; 952d625a29bSMichael Buesch case sizeof(u32): 953d625a29bSMichael Buesch SSB_WARN_ON(count & 3); 954d625a29bSMichael Buesch ioread32_rep(addr, buffer, count >> 2); 955d625a29bSMichael Buesch break; 956d625a29bSMichael Buesch default: 957d625a29bSMichael Buesch SSB_WARN_ON(1); 958d625a29bSMichael Buesch } 959d625a29bSMichael Buesch 960d625a29bSMichael Buesch return; 961d625a29bSMichael Buesch error: 962d625a29bSMichael Buesch memset(buffer, 0xFF, count); 963d625a29bSMichael Buesch } 964d625a29bSMichael Buesch #endif /* CONFIG_SSB_BLOCKIO */ 965d625a29bSMichael Buesch 966ffc7689dSMichael Buesch static void ssb_pci_write8(struct ssb_device *dev, u16 offset, u8 value) 967ffc7689dSMichael Buesch { 968ffc7689dSMichael Buesch struct ssb_bus *bus = dev->bus; 969ffc7689dSMichael Buesch 970ffc7689dSMichael Buesch if (unlikely(ssb_pci_assert_buspower(bus))) 971ffc7689dSMichael Buesch return; 972ffc7689dSMichael Buesch if (unlikely(bus->mapped_device != dev)) { 973ffc7689dSMichael Buesch if (unlikely(ssb_pci_switch_core(bus, dev))) 974ffc7689dSMichael Buesch return; 975ffc7689dSMichael Buesch } 976ffc7689dSMichael Buesch iowrite8(value, bus->mmio + offset); 977ffc7689dSMichael Buesch } 978ffc7689dSMichael Buesch 97961e115a5SMichael Buesch static void ssb_pci_write16(struct ssb_device *dev, u16 offset, u16 value) 98061e115a5SMichael Buesch { 98161e115a5SMichael Buesch struct ssb_bus *bus = dev->bus; 98261e115a5SMichael Buesch 98361e115a5SMichael Buesch if (unlikely(ssb_pci_assert_buspower(bus))) 98461e115a5SMichael Buesch return; 98561e115a5SMichael Buesch if (unlikely(bus->mapped_device != dev)) { 98661e115a5SMichael Buesch if (unlikely(ssb_pci_switch_core(bus, dev))) 98761e115a5SMichael Buesch return; 98861e115a5SMichael Buesch } 9894b402c65SMichael Buesch iowrite16(value, bus->mmio + offset); 99061e115a5SMichael Buesch } 99161e115a5SMichael Buesch 99261e115a5SMichael Buesch static void ssb_pci_write32(struct ssb_device *dev, u16 offset, u32 value) 99361e115a5SMichael Buesch { 99461e115a5SMichael Buesch struct ssb_bus *bus = dev->bus; 99561e115a5SMichael Buesch 99661e115a5SMichael Buesch if (unlikely(ssb_pci_assert_buspower(bus))) 99761e115a5SMichael Buesch return; 99861e115a5SMichael Buesch if (unlikely(bus->mapped_device != dev)) { 99961e115a5SMichael Buesch if (unlikely(ssb_pci_switch_core(bus, dev))) 100061e115a5SMichael Buesch return; 100161e115a5SMichael Buesch } 10024b402c65SMichael Buesch iowrite32(value, bus->mmio + offset); 100361e115a5SMichael Buesch } 100461e115a5SMichael Buesch 1005d625a29bSMichael Buesch #ifdef CONFIG_SSB_BLOCKIO 1006d625a29bSMichael Buesch static void ssb_pci_block_write(struct ssb_device *dev, const void *buffer, 1007d625a29bSMichael Buesch size_t count, u16 offset, u8 reg_width) 1008d625a29bSMichael Buesch { 1009d625a29bSMichael Buesch struct ssb_bus *bus = dev->bus; 1010d625a29bSMichael Buesch void __iomem *addr = bus->mmio + offset; 1011d625a29bSMichael Buesch 1012d625a29bSMichael Buesch if (unlikely(ssb_pci_assert_buspower(bus))) 1013d625a29bSMichael Buesch return; 1014d625a29bSMichael Buesch if (unlikely(bus->mapped_device != dev)) { 1015d625a29bSMichael Buesch if (unlikely(ssb_pci_switch_core(bus, dev))) 1016d625a29bSMichael Buesch return; 1017d625a29bSMichael Buesch } 1018d625a29bSMichael Buesch switch (reg_width) { 1019d625a29bSMichael Buesch case sizeof(u8): 1020d625a29bSMichael Buesch iowrite8_rep(addr, buffer, count); 1021d625a29bSMichael Buesch break; 1022d625a29bSMichael Buesch case sizeof(u16): 1023d625a29bSMichael Buesch SSB_WARN_ON(count & 1); 1024d625a29bSMichael Buesch iowrite16_rep(addr, buffer, count >> 1); 1025d625a29bSMichael Buesch break; 1026d625a29bSMichael Buesch case sizeof(u32): 1027d625a29bSMichael Buesch SSB_WARN_ON(count & 3); 1028d625a29bSMichael Buesch iowrite32_rep(addr, buffer, count >> 2); 1029d625a29bSMichael Buesch break; 1030d625a29bSMichael Buesch default: 1031d625a29bSMichael Buesch SSB_WARN_ON(1); 1032d625a29bSMichael Buesch } 1033d625a29bSMichael Buesch } 1034d625a29bSMichael Buesch #endif /* CONFIG_SSB_BLOCKIO */ 1035d625a29bSMichael Buesch 103661e115a5SMichael Buesch /* Not "static", as it's used in main.c */ 103761e115a5SMichael Buesch const struct ssb_bus_ops ssb_pci_ops = { 1038ffc7689dSMichael Buesch .read8 = ssb_pci_read8, 103961e115a5SMichael Buesch .read16 = ssb_pci_read16, 104061e115a5SMichael Buesch .read32 = ssb_pci_read32, 1041ffc7689dSMichael Buesch .write8 = ssb_pci_write8, 104261e115a5SMichael Buesch .write16 = ssb_pci_write16, 104361e115a5SMichael Buesch .write32 = ssb_pci_write32, 1044d625a29bSMichael Buesch #ifdef CONFIG_SSB_BLOCKIO 1045d625a29bSMichael Buesch .block_read = ssb_pci_block_read, 1046d625a29bSMichael Buesch .block_write = ssb_pci_block_write, 1047d625a29bSMichael Buesch #endif 104861e115a5SMichael Buesch }; 104961e115a5SMichael Buesch 105061e115a5SMichael Buesch static ssize_t ssb_pci_attr_sprom_show(struct device *pcidev, 105161e115a5SMichael Buesch struct device_attribute *attr, 105261e115a5SMichael Buesch char *buf) 105361e115a5SMichael Buesch { 105461e115a5SMichael Buesch struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev); 105561e115a5SMichael Buesch struct ssb_bus *bus; 105661e115a5SMichael Buesch 105761e115a5SMichael Buesch bus = ssb_pci_dev_to_bus(pdev); 105861e115a5SMichael Buesch if (!bus) 1059e7ec2e32SMichael Buesch return -ENODEV; 106061e115a5SMichael Buesch 1061e7ec2e32SMichael Buesch return ssb_attr_sprom_show(bus, buf, sprom_do_read); 106261e115a5SMichael Buesch } 106361e115a5SMichael Buesch 106461e115a5SMichael Buesch static ssize_t ssb_pci_attr_sprom_store(struct device *pcidev, 106561e115a5SMichael Buesch struct device_attribute *attr, 106661e115a5SMichael Buesch const char *buf, size_t count) 106761e115a5SMichael Buesch { 106861e115a5SMichael Buesch struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev); 106961e115a5SMichael Buesch struct ssb_bus *bus; 107061e115a5SMichael Buesch 107161e115a5SMichael Buesch bus = ssb_pci_dev_to_bus(pdev); 107261e115a5SMichael Buesch if (!bus) 1073e7ec2e32SMichael Buesch return -ENODEV; 107461e115a5SMichael Buesch 1075e7ec2e32SMichael Buesch return ssb_attr_sprom_store(bus, buf, count, 1076e7ec2e32SMichael Buesch sprom_check_crc, sprom_do_write); 107761e115a5SMichael Buesch } 107861e115a5SMichael Buesch 107961e115a5SMichael Buesch static DEVICE_ATTR(ssb_sprom, 0600, 108061e115a5SMichael Buesch ssb_pci_attr_sprom_show, 108161e115a5SMichael Buesch ssb_pci_attr_sprom_store); 108261e115a5SMichael Buesch 108361e115a5SMichael Buesch void ssb_pci_exit(struct ssb_bus *bus) 108461e115a5SMichael Buesch { 108561e115a5SMichael Buesch struct pci_dev *pdev; 108661e115a5SMichael Buesch 108761e115a5SMichael Buesch if (bus->bustype != SSB_BUSTYPE_PCI) 108861e115a5SMichael Buesch return; 108961e115a5SMichael Buesch 109061e115a5SMichael Buesch pdev = bus->host_pci; 109161e115a5SMichael Buesch device_remove_file(&pdev->dev, &dev_attr_ssb_sprom); 109261e115a5SMichael Buesch } 109361e115a5SMichael Buesch 109461e115a5SMichael Buesch int ssb_pci_init(struct ssb_bus *bus) 109561e115a5SMichael Buesch { 109661e115a5SMichael Buesch struct pci_dev *pdev; 109761e115a5SMichael Buesch int err; 109861e115a5SMichael Buesch 109961e115a5SMichael Buesch if (bus->bustype != SSB_BUSTYPE_PCI) 110061e115a5SMichael Buesch return 0; 110161e115a5SMichael Buesch 110261e115a5SMichael Buesch pdev = bus->host_pci; 1103e7ec2e32SMichael Buesch mutex_init(&bus->sprom_mutex); 110461e115a5SMichael Buesch err = device_create_file(&pdev->dev, &dev_attr_ssb_sprom); 110561e115a5SMichael Buesch if (err) 110661e115a5SMichael Buesch goto out; 110761e115a5SMichael Buesch 110861e115a5SMichael Buesch out: 110961e115a5SMichael Buesch return err; 111061e115a5SMichael Buesch } 1111