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: 5961e115a5SMichael Buesch ssb_printk(KERN_ERR PFX "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 7061e115a5SMichael Buesch ssb_printk(KERN_INFO PFX 7161e115a5SMichael Buesch "Switching to %s core, index %d\n", 7261e115a5SMichael Buesch ssb_core_name(dev->id.coreid), 7361e115a5SMichael Buesch dev->core_index); 7461e115a5SMichael Buesch #endif 7561e115a5SMichael Buesch 7661e115a5SMichael Buesch spin_lock_irqsave(&bus->bar_lock, flags); 7761e115a5SMichael Buesch err = ssb_pci_switch_coreidx(bus, dev->core_index); 7861e115a5SMichael Buesch if (!err) 7961e115a5SMichael Buesch bus->mapped_device = dev; 8061e115a5SMichael Buesch spin_unlock_irqrestore(&bus->bar_lock, flags); 8161e115a5SMichael Buesch 8261e115a5SMichael Buesch return err; 8361e115a5SMichael Buesch } 8461e115a5SMichael Buesch 8561e115a5SMichael Buesch /* Enable/disable the on board crystal oscillator and/or PLL. */ 8661e115a5SMichael Buesch int ssb_pci_xtal(struct ssb_bus *bus, u32 what, int turn_on) 8761e115a5SMichael Buesch { 8861e115a5SMichael Buesch int err; 8961e115a5SMichael Buesch u32 in, out, outenable; 9061e115a5SMichael Buesch u16 pci_status; 9161e115a5SMichael Buesch 9261e115a5SMichael Buesch if (bus->bustype != SSB_BUSTYPE_PCI) 9361e115a5SMichael Buesch return 0; 9461e115a5SMichael Buesch 9561e115a5SMichael Buesch err = pci_read_config_dword(bus->host_pci, SSB_GPIO_IN, &in); 9661e115a5SMichael Buesch if (err) 9761e115a5SMichael Buesch goto err_pci; 9861e115a5SMichael Buesch err = pci_read_config_dword(bus->host_pci, SSB_GPIO_OUT, &out); 9961e115a5SMichael Buesch if (err) 10061e115a5SMichael Buesch goto err_pci; 10161e115a5SMichael Buesch err = pci_read_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE, &outenable); 10261e115a5SMichael Buesch if (err) 10361e115a5SMichael Buesch goto err_pci; 10461e115a5SMichael Buesch 10561e115a5SMichael Buesch outenable |= what; 10661e115a5SMichael Buesch 10761e115a5SMichael Buesch if (turn_on) { 10861e115a5SMichael Buesch /* Avoid glitching the clock if GPRS is already using it. 10961e115a5SMichael Buesch * We can't actually read the state of the PLLPD so we infer it 11061e115a5SMichael Buesch * by the value of XTAL_PU which *is* readable via gpioin. 11161e115a5SMichael Buesch */ 11261e115a5SMichael Buesch if (!(in & SSB_GPIO_XTAL)) { 11361e115a5SMichael Buesch if (what & SSB_GPIO_XTAL) { 11461e115a5SMichael Buesch /* Turn the crystal on */ 11561e115a5SMichael Buesch out |= SSB_GPIO_XTAL; 11661e115a5SMichael Buesch if (what & SSB_GPIO_PLL) 11761e115a5SMichael Buesch out |= SSB_GPIO_PLL; 11861e115a5SMichael Buesch err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out); 11961e115a5SMichael Buesch if (err) 12061e115a5SMichael Buesch goto err_pci; 12161e115a5SMichael Buesch err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE, 12261e115a5SMichael Buesch outenable); 12361e115a5SMichael Buesch if (err) 12461e115a5SMichael Buesch goto err_pci; 12561e115a5SMichael Buesch msleep(1); 12661e115a5SMichael Buesch } 12761e115a5SMichael Buesch if (what & SSB_GPIO_PLL) { 12861e115a5SMichael Buesch /* Turn the PLL on */ 12961e115a5SMichael Buesch out &= ~SSB_GPIO_PLL; 13061e115a5SMichael Buesch err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out); 13161e115a5SMichael Buesch if (err) 13261e115a5SMichael Buesch goto err_pci; 13361e115a5SMichael Buesch msleep(5); 13461e115a5SMichael Buesch } 13561e115a5SMichael Buesch } 13661e115a5SMichael Buesch 13761e115a5SMichael Buesch err = pci_read_config_word(bus->host_pci, PCI_STATUS, &pci_status); 13861e115a5SMichael Buesch if (err) 13961e115a5SMichael Buesch goto err_pci; 14061e115a5SMichael Buesch pci_status &= ~PCI_STATUS_SIG_TARGET_ABORT; 14161e115a5SMichael Buesch err = pci_write_config_word(bus->host_pci, PCI_STATUS, pci_status); 14261e115a5SMichael Buesch if (err) 14361e115a5SMichael Buesch goto err_pci; 14461e115a5SMichael Buesch } else { 14561e115a5SMichael Buesch if (what & SSB_GPIO_XTAL) { 14661e115a5SMichael Buesch /* Turn the crystal off */ 14761e115a5SMichael Buesch out &= ~SSB_GPIO_XTAL; 14861e115a5SMichael Buesch } 14961e115a5SMichael Buesch if (what & SSB_GPIO_PLL) { 15061e115a5SMichael Buesch /* Turn the PLL off */ 15161e115a5SMichael Buesch out |= SSB_GPIO_PLL; 15261e115a5SMichael Buesch } 15361e115a5SMichael Buesch err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out); 15461e115a5SMichael Buesch if (err) 15561e115a5SMichael Buesch goto err_pci; 15661e115a5SMichael Buesch err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE, outenable); 15761e115a5SMichael Buesch if (err) 15861e115a5SMichael Buesch goto err_pci; 15961e115a5SMichael Buesch } 16061e115a5SMichael Buesch 16161e115a5SMichael Buesch out: 16261e115a5SMichael Buesch return err; 16361e115a5SMichael Buesch 16461e115a5SMichael Buesch err_pci: 16561e115a5SMichael Buesch printk(KERN_ERR PFX "Error: ssb_pci_xtal() could not access PCI config space!\n"); 16661e115a5SMichael Buesch err = -EBUSY; 16761e115a5SMichael Buesch goto out; 16861e115a5SMichael Buesch } 16961e115a5SMichael Buesch 17061e115a5SMichael Buesch /* Get the word-offset for a SSB_SPROM_XXX define. */ 1710a182fd8SRafał Miłecki #define SPOFF(offset) ((offset) / sizeof(u16)) 17261e115a5SMichael Buesch /* Helper to extract some _offset, which is one of the SSB_SPROM_XXX defines. */ 173f679056bSGábor Stefanik #define SPEX16(_outvar, _offset, _mask, _shift) \ 17461e115a5SMichael Buesch out->_outvar = ((in[SPOFF(_offset)] & (_mask)) >> (_shift)) 175f679056bSGábor Stefanik #define SPEX32(_outvar, _offset, _mask, _shift) \ 176f679056bSGábor Stefanik out->_outvar = ((((u32)in[SPOFF((_offset)+2)] << 16 | \ 177f679056bSGábor Stefanik in[SPOFF(_offset)]) & (_mask)) >> (_shift)) 178f679056bSGábor Stefanik #define SPEX(_outvar, _offset, _mask, _shift) \ 179f679056bSGábor Stefanik SPEX16(_outvar, _offset, _mask, _shift) 180f679056bSGábor Stefanik 18161e115a5SMichael Buesch 18261e115a5SMichael Buesch static inline u8 ssb_crc8(u8 crc, u8 data) 18361e115a5SMichael Buesch { 18461e115a5SMichael Buesch /* Polynomial: x^8 + x^7 + x^6 + x^4 + x^2 + 1 */ 18561e115a5SMichael Buesch static const u8 t[] = { 18661e115a5SMichael Buesch 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B, 18761e115a5SMichael Buesch 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21, 18861e115a5SMichael Buesch 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF, 18961e115a5SMichael Buesch 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5, 19061e115a5SMichael Buesch 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14, 19161e115a5SMichael Buesch 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E, 19261e115a5SMichael Buesch 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80, 19361e115a5SMichael Buesch 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA, 19461e115a5SMichael Buesch 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95, 19561e115a5SMichael Buesch 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF, 19661e115a5SMichael Buesch 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01, 19761e115a5SMichael Buesch 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B, 19861e115a5SMichael Buesch 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA, 19961e115a5SMichael Buesch 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0, 20061e115a5SMichael Buesch 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E, 20161e115a5SMichael Buesch 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34, 20261e115a5SMichael Buesch 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0, 20361e115a5SMichael Buesch 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A, 20461e115a5SMichael Buesch 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54, 20561e115a5SMichael Buesch 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E, 20661e115a5SMichael Buesch 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF, 20761e115a5SMichael Buesch 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5, 20861e115a5SMichael Buesch 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B, 20961e115a5SMichael Buesch 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61, 21061e115a5SMichael Buesch 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E, 21161e115a5SMichael Buesch 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74, 21261e115a5SMichael Buesch 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA, 21361e115a5SMichael Buesch 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0, 21461e115a5SMichael Buesch 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41, 21561e115a5SMichael Buesch 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B, 21661e115a5SMichael Buesch 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5, 21761e115a5SMichael Buesch 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F, 21861e115a5SMichael Buesch }; 21961e115a5SMichael Buesch return t[crc ^ data]; 22061e115a5SMichael Buesch } 22161e115a5SMichael Buesch 222c272ef44SLarry Finger static u8 ssb_sprom_crc(const u16 *sprom, u16 size) 22361e115a5SMichael Buesch { 22461e115a5SMichael Buesch int word; 22561e115a5SMichael Buesch u8 crc = 0xFF; 22661e115a5SMichael Buesch 227c272ef44SLarry Finger for (word = 0; word < size - 1; word++) { 22861e115a5SMichael Buesch crc = ssb_crc8(crc, sprom[word] & 0x00FF); 22961e115a5SMichael Buesch crc = ssb_crc8(crc, (sprom[word] & 0xFF00) >> 8); 23061e115a5SMichael Buesch } 231c272ef44SLarry Finger crc = ssb_crc8(crc, sprom[size - 1] & 0x00FF); 23261e115a5SMichael Buesch crc ^= 0xFF; 23361e115a5SMichael Buesch 23461e115a5SMichael Buesch return crc; 23561e115a5SMichael Buesch } 23661e115a5SMichael Buesch 237e7ec2e32SMichael Buesch static int sprom_check_crc(const u16 *sprom, size_t size) 23861e115a5SMichael Buesch { 23961e115a5SMichael Buesch u8 crc; 24061e115a5SMichael Buesch u8 expected_crc; 24161e115a5SMichael Buesch u16 tmp; 24261e115a5SMichael Buesch 243c272ef44SLarry Finger crc = ssb_sprom_crc(sprom, size); 244c272ef44SLarry Finger tmp = sprom[size - 1] & SSB_SPROM_REVISION_CRC; 24561e115a5SMichael Buesch expected_crc = tmp >> SSB_SPROM_REVISION_CRC_SHIFT; 24661e115a5SMichael Buesch if (crc != expected_crc) 24761e115a5SMichael Buesch return -EPROTO; 24861e115a5SMichael Buesch 24961e115a5SMichael Buesch return 0; 25061e115a5SMichael Buesch } 25161e115a5SMichael Buesch 252e7ec2e32SMichael Buesch static int sprom_do_read(struct ssb_bus *bus, u16 *sprom) 25361e115a5SMichael Buesch { 25461e115a5SMichael Buesch int i; 25561e115a5SMichael Buesch 256c272ef44SLarry Finger for (i = 0; i < bus->sprom_size; i++) 257ea2db495SRafał Miłecki sprom[i] = ioread16(bus->mmio + bus->sprom_offset + (i * 2)); 258e7ec2e32SMichael Buesch 259e7ec2e32SMichael Buesch return 0; 26061e115a5SMichael Buesch } 26161e115a5SMichael Buesch 26261e115a5SMichael Buesch static int sprom_do_write(struct ssb_bus *bus, const u16 *sprom) 26361e115a5SMichael Buesch { 26461e115a5SMichael Buesch struct pci_dev *pdev = bus->host_pci; 26561e115a5SMichael Buesch int i, err; 26661e115a5SMichael Buesch u32 spromctl; 267c272ef44SLarry Finger u16 size = bus->sprom_size; 26861e115a5SMichael Buesch 26961e115a5SMichael Buesch ssb_printk(KERN_NOTICE PFX "Writing SPROM. Do NOT turn off the power! Please stand by...\n"); 27061e115a5SMichael Buesch err = pci_read_config_dword(pdev, SSB_SPROMCTL, &spromctl); 27161e115a5SMichael Buesch if (err) 27261e115a5SMichael Buesch goto err_ctlreg; 27361e115a5SMichael Buesch spromctl |= SSB_SPROMCTL_WE; 27461e115a5SMichael Buesch err = pci_write_config_dword(pdev, SSB_SPROMCTL, spromctl); 27561e115a5SMichael Buesch if (err) 27661e115a5SMichael Buesch goto err_ctlreg; 27761e115a5SMichael Buesch ssb_printk(KERN_NOTICE PFX "[ 0%%"); 27861e115a5SMichael Buesch msleep(500); 279c272ef44SLarry Finger for (i = 0; i < size; i++) { 280c272ef44SLarry Finger if (i == size / 4) 28161e115a5SMichael Buesch ssb_printk("25%%"); 282c272ef44SLarry Finger else if (i == size / 2) 28361e115a5SMichael Buesch ssb_printk("50%%"); 284c272ef44SLarry Finger else if (i == (size * 3) / 4) 28561e115a5SMichael Buesch ssb_printk("75%%"); 28661e115a5SMichael Buesch else if (i % 2) 28761e115a5SMichael Buesch ssb_printk("."); 288ea2db495SRafał Miłecki writew(sprom[i], bus->mmio + bus->sprom_offset + (i * 2)); 28961e115a5SMichael Buesch mmiowb(); 29061e115a5SMichael Buesch msleep(20); 29161e115a5SMichael Buesch } 29261e115a5SMichael Buesch err = pci_read_config_dword(pdev, SSB_SPROMCTL, &spromctl); 29361e115a5SMichael Buesch if (err) 29461e115a5SMichael Buesch goto err_ctlreg; 29561e115a5SMichael Buesch spromctl &= ~SSB_SPROMCTL_WE; 29661e115a5SMichael Buesch err = pci_write_config_dword(pdev, SSB_SPROMCTL, spromctl); 29761e115a5SMichael Buesch if (err) 29861e115a5SMichael Buesch goto err_ctlreg; 29961e115a5SMichael Buesch msleep(500); 30061e115a5SMichael Buesch ssb_printk("100%% ]\n"); 30161e115a5SMichael Buesch ssb_printk(KERN_NOTICE PFX "SPROM written.\n"); 30261e115a5SMichael Buesch 30361e115a5SMichael Buesch return 0; 30461e115a5SMichael Buesch err_ctlreg: 30561e115a5SMichael Buesch ssb_printk(KERN_ERR PFX "Could not access SPROM control register.\n"); 30661e115a5SMichael Buesch return err; 30761e115a5SMichael Buesch } 30861e115a5SMichael Buesch 309e861b98dSMichael Buesch static s8 r123_extract_antgain(u8 sprom_revision, const u16 *in, 310e861b98dSMichael Buesch u16 mask, u16 shift) 311e861b98dSMichael Buesch { 312e861b98dSMichael Buesch u16 v; 313e861b98dSMichael Buesch u8 gain; 314e861b98dSMichael Buesch 315e861b98dSMichael Buesch v = in[SPOFF(SSB_SPROM1_AGAIN)]; 316e861b98dSMichael Buesch gain = (v & mask) >> shift; 317e861b98dSMichael Buesch if (gain == 0xFF) 318e861b98dSMichael Buesch gain = 2; /* If unset use 2dBm */ 319e861b98dSMichael Buesch if (sprom_revision == 1) { 320e861b98dSMichael Buesch /* Convert to Q5.2 */ 321e861b98dSMichael Buesch gain <<= 2; 322e861b98dSMichael Buesch } else { 323e861b98dSMichael Buesch /* Q5.2 Fractional part is stored in 0xC0 */ 324e861b98dSMichael Buesch gain = ((gain & 0xC0) >> 6) | ((gain & 0x3F) << 2); 325e861b98dSMichael Buesch } 326e861b98dSMichael Buesch 327e861b98dSMichael Buesch return (s8)gain; 328e861b98dSMichael Buesch } 329e861b98dSMichael Buesch 330c272ef44SLarry Finger static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in) 331c272ef44SLarry Finger { 332c272ef44SLarry Finger int i; 333c272ef44SLarry Finger u16 v; 334c272ef44SLarry Finger u16 loc[3]; 335c272ef44SLarry Finger 33631ce12fbSLarry Finger if (out->revision == 3) /* rev 3 moved MAC */ 337c272ef44SLarry Finger loc[0] = SSB_SPROM3_IL0MAC; 33831ce12fbSLarry Finger else { 339c272ef44SLarry Finger loc[0] = SSB_SPROM1_IL0MAC; 340c272ef44SLarry Finger loc[1] = SSB_SPROM1_ET0MAC; 341c272ef44SLarry Finger loc[2] = SSB_SPROM1_ET1MAC; 342c272ef44SLarry Finger } 343c272ef44SLarry Finger for (i = 0; i < 3; i++) { 344c272ef44SLarry Finger v = in[SPOFF(loc[0]) + i]; 345c272ef44SLarry Finger *(((__be16 *)out->il0mac) + i) = cpu_to_be16(v); 346c272ef44SLarry Finger } 34731ce12fbSLarry Finger if (out->revision < 3) { /* only rev 1-2 have et0, et1 */ 348c272ef44SLarry Finger for (i = 0; i < 3; i++) { 349c272ef44SLarry Finger v = in[SPOFF(loc[1]) + i]; 350c272ef44SLarry Finger *(((__be16 *)out->et0mac) + i) = cpu_to_be16(v); 351c272ef44SLarry Finger } 352c272ef44SLarry Finger for (i = 0; i < 3; i++) { 353c272ef44SLarry Finger v = in[SPOFF(loc[2]) + i]; 354c272ef44SLarry Finger *(((__be16 *)out->et1mac) + i) = cpu_to_be16(v); 355c272ef44SLarry Finger } 35631ce12fbSLarry Finger } 357c272ef44SLarry Finger SPEX(et0phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0A, 0); 358c272ef44SLarry Finger SPEX(et1phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1A, 359c272ef44SLarry Finger SSB_SPROM1_ETHPHY_ET1A_SHIFT); 360e861b98dSMichael Buesch SPEX(et0mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0M, 14); 361e861b98dSMichael Buesch SPEX(et1mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1M, 15); 362e861b98dSMichael Buesch SPEX(board_rev, SSB_SPROM1_BINF, SSB_SPROM1_BINF_BREV, 0); 363bf7d420bSHauke Mehrtens if (out->revision == 1) 364c272ef44SLarry Finger SPEX(country_code, SSB_SPROM1_BINF, SSB_SPROM1_BINF_CCODE, 365c272ef44SLarry Finger SSB_SPROM1_BINF_CCODE_SHIFT); 366e861b98dSMichael Buesch SPEX(ant_available_a, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTA, 367e861b98dSMichael Buesch SSB_SPROM1_BINF_ANTA_SHIFT); 368e861b98dSMichael Buesch SPEX(ant_available_bg, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTBG, 369e861b98dSMichael Buesch SSB_SPROM1_BINF_ANTBG_SHIFT); 370c272ef44SLarry Finger SPEX(pa0b0, SSB_SPROM1_PA0B0, 0xFFFF, 0); 371c272ef44SLarry Finger SPEX(pa0b1, SSB_SPROM1_PA0B1, 0xFFFF, 0); 372c272ef44SLarry Finger SPEX(pa0b2, SSB_SPROM1_PA0B2, 0xFFFF, 0); 373c272ef44SLarry Finger SPEX(pa1b0, SSB_SPROM1_PA1B0, 0xFFFF, 0); 374c272ef44SLarry Finger SPEX(pa1b1, SSB_SPROM1_PA1B1, 0xFFFF, 0); 375c272ef44SLarry Finger SPEX(pa1b2, SSB_SPROM1_PA1B2, 0xFFFF, 0); 376c272ef44SLarry Finger SPEX(gpio0, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P0, 0); 377c272ef44SLarry Finger SPEX(gpio1, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P1, 378c272ef44SLarry Finger SSB_SPROM1_GPIOA_P1_SHIFT); 379c272ef44SLarry Finger SPEX(gpio2, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P2, 0); 380c272ef44SLarry Finger SPEX(gpio3, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P3, 381c272ef44SLarry Finger SSB_SPROM1_GPIOB_P3_SHIFT); 382c272ef44SLarry Finger SPEX(maxpwr_a, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_A, 383c272ef44SLarry Finger SSB_SPROM1_MAXPWR_A_SHIFT); 384c272ef44SLarry Finger SPEX(maxpwr_bg, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_BG, 0); 385c272ef44SLarry Finger SPEX(itssi_a, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_A, 386c272ef44SLarry Finger SSB_SPROM1_ITSSI_A_SHIFT); 387c272ef44SLarry Finger SPEX(itssi_bg, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_BG, 0); 388c272ef44SLarry Finger SPEX(boardflags_lo, SSB_SPROM1_BFLLO, 0xFFFF, 0); 389af4b7450SMichael Buesch if (out->revision >= 2) 390af4b7450SMichael Buesch SPEX(boardflags_hi, SSB_SPROM2_BFLHI, 0xFFFF, 0); 391bf7d420bSHauke Mehrtens SPEX(alpha2[0], SSB_SPROM1_CCODE, 0xff00, 8); 392bf7d420bSHauke Mehrtens SPEX(alpha2[1], SSB_SPROM1_CCODE, 0x00ff, 0); 393e861b98dSMichael Buesch 394e861b98dSMichael Buesch /* Extract the antenna gain values. */ 395f8f8a660SHauke Mehrtens out->antenna_gain.a0 = r123_extract_antgain(out->revision, in, 396e861b98dSMichael Buesch SSB_SPROM1_AGAIN_BG, 397c272ef44SLarry Finger SSB_SPROM1_AGAIN_BG_SHIFT); 398f8f8a660SHauke Mehrtens out->antenna_gain.a1 = r123_extract_antgain(out->revision, in, 399e861b98dSMichael Buesch SSB_SPROM1_AGAIN_A, 400e861b98dSMichael Buesch SSB_SPROM1_AGAIN_A_SHIFT); 401c272ef44SLarry Finger } 402c272ef44SLarry Finger 403172c69a4SRafał Miłecki /* Revs 4 5 and 8 have partially shared layout */ 404172c69a4SRafał Miłecki static void sprom_extract_r458(struct ssb_sprom *out, const u16 *in) 405172c69a4SRafał Miłecki { 406172c69a4SRafał Miłecki SPEX(txpid2g[0], SSB_SPROM4_TXPID2G01, 407172c69a4SRafał Miłecki SSB_SPROM4_TXPID2G0, SSB_SPROM4_TXPID2G0_SHIFT); 408172c69a4SRafał Miłecki SPEX(txpid2g[1], SSB_SPROM4_TXPID2G01, 409172c69a4SRafał Miłecki SSB_SPROM4_TXPID2G1, SSB_SPROM4_TXPID2G1_SHIFT); 410172c69a4SRafał Miłecki SPEX(txpid2g[2], SSB_SPROM4_TXPID2G23, 411172c69a4SRafał Miłecki SSB_SPROM4_TXPID2G2, SSB_SPROM4_TXPID2G2_SHIFT); 412172c69a4SRafał Miłecki SPEX(txpid2g[3], SSB_SPROM4_TXPID2G23, 413172c69a4SRafał Miłecki SSB_SPROM4_TXPID2G3, SSB_SPROM4_TXPID2G3_SHIFT); 414172c69a4SRafał Miłecki 415172c69a4SRafał Miłecki SPEX(txpid5gl[0], SSB_SPROM4_TXPID5GL01, 416172c69a4SRafał Miłecki SSB_SPROM4_TXPID5GL0, SSB_SPROM4_TXPID5GL0_SHIFT); 417172c69a4SRafał Miłecki SPEX(txpid5gl[1], SSB_SPROM4_TXPID5GL01, 418172c69a4SRafał Miłecki SSB_SPROM4_TXPID5GL1, SSB_SPROM4_TXPID5GL1_SHIFT); 419172c69a4SRafał Miłecki SPEX(txpid5gl[2], SSB_SPROM4_TXPID5GL23, 420172c69a4SRafał Miłecki SSB_SPROM4_TXPID5GL2, SSB_SPROM4_TXPID5GL2_SHIFT); 421172c69a4SRafał Miłecki SPEX(txpid5gl[3], SSB_SPROM4_TXPID5GL23, 422172c69a4SRafał Miłecki SSB_SPROM4_TXPID5GL3, SSB_SPROM4_TXPID5GL3_SHIFT); 423172c69a4SRafał Miłecki 424172c69a4SRafał Miłecki SPEX(txpid5g[0], SSB_SPROM4_TXPID5G01, 425172c69a4SRafał Miłecki SSB_SPROM4_TXPID5G0, SSB_SPROM4_TXPID5G0_SHIFT); 426172c69a4SRafał Miłecki SPEX(txpid5g[1], SSB_SPROM4_TXPID5G01, 427172c69a4SRafał Miłecki SSB_SPROM4_TXPID5G1, SSB_SPROM4_TXPID5G1_SHIFT); 428172c69a4SRafał Miłecki SPEX(txpid5g[2], SSB_SPROM4_TXPID5G23, 429172c69a4SRafał Miłecki SSB_SPROM4_TXPID5G2, SSB_SPROM4_TXPID5G2_SHIFT); 430172c69a4SRafał Miłecki SPEX(txpid5g[3], SSB_SPROM4_TXPID5G23, 431172c69a4SRafał Miłecki SSB_SPROM4_TXPID5G3, SSB_SPROM4_TXPID5G3_SHIFT); 432172c69a4SRafał Miłecki 433172c69a4SRafał Miłecki SPEX(txpid5gh[0], SSB_SPROM4_TXPID5GH01, 434172c69a4SRafał Miłecki SSB_SPROM4_TXPID5GH0, SSB_SPROM4_TXPID5GH0_SHIFT); 435172c69a4SRafał Miłecki SPEX(txpid5gh[1], SSB_SPROM4_TXPID5GH01, 436172c69a4SRafał Miłecki SSB_SPROM4_TXPID5GH1, SSB_SPROM4_TXPID5GH1_SHIFT); 437172c69a4SRafał Miłecki SPEX(txpid5gh[2], SSB_SPROM4_TXPID5GH23, 438172c69a4SRafał Miłecki SSB_SPROM4_TXPID5GH2, SSB_SPROM4_TXPID5GH2_SHIFT); 439172c69a4SRafał Miłecki SPEX(txpid5gh[3], SSB_SPROM4_TXPID5GH23, 440172c69a4SRafał Miłecki SSB_SPROM4_TXPID5GH3, SSB_SPROM4_TXPID5GH3_SHIFT); 441172c69a4SRafał Miłecki } 442172c69a4SRafał Miłecki 443095f695cSLarry Finger static void sprom_extract_r45(struct ssb_sprom *out, const u16 *in) 44461e115a5SMichael Buesch { 44561e115a5SMichael Buesch int i; 44661e115a5SMichael Buesch u16 v; 447095f695cSLarry Finger u16 il0mac_offset; 44861e115a5SMichael Buesch 449095f695cSLarry Finger if (out->revision == 4) 450095f695cSLarry Finger il0mac_offset = SSB_SPROM4_IL0MAC; 451095f695cSLarry Finger else 452095f695cSLarry Finger il0mac_offset = SSB_SPROM5_IL0MAC; 45331ce12fbSLarry Finger /* extract the MAC address */ 454c272ef44SLarry Finger for (i = 0; i < 3; i++) { 455095f695cSLarry Finger v = in[SPOFF(il0mac_offset) + i]; 456c272ef44SLarry Finger *(((__be16 *)out->il0mac) + i) = cpu_to_be16(v); 45761e115a5SMichael Buesch } 458c272ef44SLarry Finger SPEX(et0phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET0A, 0); 459c272ef44SLarry Finger SPEX(et1phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET1A, 460c272ef44SLarry Finger SSB_SPROM4_ETHPHY_ET1A_SHIFT); 461*673335c8SHauke Mehrtens SPEX(board_rev, SSB_SPROM4_BOARDREV, 0xFFFF, 0); 462095f695cSLarry Finger if (out->revision == 4) { 463bf7d420bSHauke Mehrtens SPEX(alpha2[0], SSB_SPROM4_CCODE, 0xff00, 8); 464bf7d420bSHauke Mehrtens SPEX(alpha2[1], SSB_SPROM4_CCODE, 0x00ff, 0); 465c272ef44SLarry Finger SPEX(boardflags_lo, SSB_SPROM4_BFLLO, 0xFFFF, 0); 466af4b7450SMichael Buesch SPEX(boardflags_hi, SSB_SPROM4_BFLHI, 0xFFFF, 0); 4676d1d4ea4SRafał Miłecki SPEX(boardflags2_lo, SSB_SPROM4_BFL2LO, 0xFFFF, 0); 4686d1d4ea4SRafał Miłecki SPEX(boardflags2_hi, SSB_SPROM4_BFL2HI, 0xFFFF, 0); 469095f695cSLarry Finger } else { 470bf7d420bSHauke Mehrtens SPEX(alpha2[0], SSB_SPROM5_CCODE, 0xff00, 8); 471bf7d420bSHauke Mehrtens SPEX(alpha2[1], SSB_SPROM5_CCODE, 0x00ff, 0); 472095f695cSLarry Finger SPEX(boardflags_lo, SSB_SPROM5_BFLLO, 0xFFFF, 0); 473095f695cSLarry Finger SPEX(boardflags_hi, SSB_SPROM5_BFLHI, 0xFFFF, 0); 4746d1d4ea4SRafał Miłecki SPEX(boardflags2_lo, SSB_SPROM5_BFL2LO, 0xFFFF, 0); 4756d1d4ea4SRafał Miłecki SPEX(boardflags2_hi, SSB_SPROM5_BFL2HI, 0xFFFF, 0); 476095f695cSLarry Finger } 477e861b98dSMichael Buesch SPEX(ant_available_a, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_A, 478e861b98dSMichael Buesch SSB_SPROM4_ANTAVAIL_A_SHIFT); 479e861b98dSMichael Buesch SPEX(ant_available_bg, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_BG, 480e861b98dSMichael Buesch SSB_SPROM4_ANTAVAIL_BG_SHIFT); 481d3c319f9SLarry Finger SPEX(maxpwr_bg, SSB_SPROM4_MAXP_BG, SSB_SPROM4_MAXP_BG_MASK, 0); 482d3c319f9SLarry Finger SPEX(itssi_bg, SSB_SPROM4_MAXP_BG, SSB_SPROM4_ITSSI_BG, 483d3c319f9SLarry Finger SSB_SPROM4_ITSSI_BG_SHIFT); 484d3c319f9SLarry Finger SPEX(maxpwr_a, SSB_SPROM4_MAXP_A, SSB_SPROM4_MAXP_A_MASK, 0); 485d3c319f9SLarry Finger SPEX(itssi_a, SSB_SPROM4_MAXP_A, SSB_SPROM4_ITSSI_A, 486d3c319f9SLarry Finger SSB_SPROM4_ITSSI_A_SHIFT); 487095f695cSLarry Finger if (out->revision == 4) { 488d3c319f9SLarry Finger SPEX(gpio0, SSB_SPROM4_GPIOA, SSB_SPROM4_GPIOA_P0, 0); 489d3c319f9SLarry Finger SPEX(gpio1, SSB_SPROM4_GPIOA, SSB_SPROM4_GPIOA_P1, 490d3c319f9SLarry Finger SSB_SPROM4_GPIOA_P1_SHIFT); 491d3c319f9SLarry Finger SPEX(gpio2, SSB_SPROM4_GPIOB, SSB_SPROM4_GPIOB_P2, 0); 492d3c319f9SLarry Finger SPEX(gpio3, SSB_SPROM4_GPIOB, SSB_SPROM4_GPIOB_P3, 493d3c319f9SLarry Finger SSB_SPROM4_GPIOB_P3_SHIFT); 494095f695cSLarry Finger } else { 495095f695cSLarry Finger SPEX(gpio0, SSB_SPROM5_GPIOA, SSB_SPROM5_GPIOA_P0, 0); 496095f695cSLarry Finger SPEX(gpio1, SSB_SPROM5_GPIOA, SSB_SPROM5_GPIOA_P1, 497095f695cSLarry Finger SSB_SPROM5_GPIOA_P1_SHIFT); 498095f695cSLarry Finger SPEX(gpio2, SSB_SPROM5_GPIOB, SSB_SPROM5_GPIOB_P2, 0); 499095f695cSLarry Finger SPEX(gpio3, SSB_SPROM5_GPIOB, SSB_SPROM5_GPIOB_P3, 500095f695cSLarry Finger SSB_SPROM5_GPIOB_P3_SHIFT); 501095f695cSLarry Finger } 502e861b98dSMichael Buesch 503e861b98dSMichael Buesch /* Extract the antenna gain values. */ 504f8f8a660SHauke Mehrtens SPEX(antenna_gain.a0, SSB_SPROM4_AGAIN01, 505e861b98dSMichael Buesch SSB_SPROM4_AGAIN0, SSB_SPROM4_AGAIN0_SHIFT); 506f8f8a660SHauke Mehrtens SPEX(antenna_gain.a1, SSB_SPROM4_AGAIN01, 507e861b98dSMichael Buesch SSB_SPROM4_AGAIN1, SSB_SPROM4_AGAIN1_SHIFT); 508f8f8a660SHauke Mehrtens SPEX(antenna_gain.a2, SSB_SPROM4_AGAIN23, 509e861b98dSMichael Buesch SSB_SPROM4_AGAIN2, SSB_SPROM4_AGAIN2_SHIFT); 510f8f8a660SHauke Mehrtens SPEX(antenna_gain.a3, SSB_SPROM4_AGAIN23, 511e861b98dSMichael Buesch SSB_SPROM4_AGAIN3, SSB_SPROM4_AGAIN3_SHIFT); 512e861b98dSMichael Buesch 513172c69a4SRafał Miłecki sprom_extract_r458(out, in); 514172c69a4SRafał Miłecki 515c272ef44SLarry Finger /* TODO - get remaining rev 4 stuff needed */ 51661e115a5SMichael Buesch } 51761e115a5SMichael Buesch 5186b1c7c67SMichael Buesch static void sprom_extract_r8(struct ssb_sprom *out, const u16 *in) 5196b1c7c67SMichael Buesch { 5206b1c7c67SMichael Buesch int i; 521b0f70292SRafał Miłecki u16 v, o; 522b0f70292SRafał Miłecki u16 pwr_info_offset[] = { 523b0f70292SRafał Miłecki SSB_SROM8_PWR_INFO_CORE0, SSB_SROM8_PWR_INFO_CORE1, 524b0f70292SRafał Miłecki SSB_SROM8_PWR_INFO_CORE2, SSB_SROM8_PWR_INFO_CORE3 525b0f70292SRafał Miłecki }; 526b0f70292SRafał Miłecki BUILD_BUG_ON(ARRAY_SIZE(pwr_info_offset) != 527b0f70292SRafał Miłecki ARRAY_SIZE(out->core_pwr_info)); 5286b1c7c67SMichael Buesch 5296b1c7c67SMichael Buesch /* extract the MAC address */ 5306b1c7c67SMichael Buesch for (i = 0; i < 3; i++) { 531f0ea6ce1SGábor Stefanik v = in[SPOFF(SSB_SPROM8_IL0MAC) + i]; 5326b1c7c67SMichael Buesch *(((__be16 *)out->il0mac) + i) = cpu_to_be16(v); 5336b1c7c67SMichael Buesch } 534*673335c8SHauke Mehrtens SPEX(board_rev, SSB_SPROM8_BOARDREV, 0xFFFF, 0); 535bf7d420bSHauke Mehrtens SPEX(alpha2[0], SSB_SPROM8_CCODE, 0xff00, 8); 536bf7d420bSHauke Mehrtens SPEX(alpha2[1], SSB_SPROM8_CCODE, 0x00ff, 0); 5376b1c7c67SMichael Buesch SPEX(boardflags_lo, SSB_SPROM8_BFLLO, 0xFFFF, 0); 5386b1c7c67SMichael Buesch SPEX(boardflags_hi, SSB_SPROM8_BFLHI, 0xFFFF, 0); 539f679056bSGábor Stefanik SPEX(boardflags2_lo, SSB_SPROM8_BFL2LO, 0xFFFF, 0); 540f679056bSGábor Stefanik SPEX(boardflags2_hi, SSB_SPROM8_BFL2HI, 0xFFFF, 0); 5416b1c7c67SMichael Buesch SPEX(ant_available_a, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_A, 5426b1c7c67SMichael Buesch SSB_SPROM8_ANTAVAIL_A_SHIFT); 5436b1c7c67SMichael Buesch SPEX(ant_available_bg, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_BG, 5446b1c7c67SMichael Buesch SSB_SPROM8_ANTAVAIL_BG_SHIFT); 5456b1c7c67SMichael Buesch SPEX(maxpwr_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_MAXP_BG_MASK, 0); 5466b1c7c67SMichael Buesch SPEX(itssi_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_ITSSI_BG, 5476b1c7c67SMichael Buesch SSB_SPROM8_ITSSI_BG_SHIFT); 5486b1c7c67SMichael Buesch SPEX(maxpwr_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_MAXP_A_MASK, 0); 5496b1c7c67SMichael Buesch SPEX(itssi_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_ITSSI_A, 5506b1c7c67SMichael Buesch SSB_SPROM8_ITSSI_A_SHIFT); 551f679056bSGábor Stefanik SPEX(maxpwr_ah, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AH_MASK, 0); 552f679056bSGábor Stefanik SPEX(maxpwr_al, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AL_MASK, 553f679056bSGábor Stefanik SSB_SPROM8_MAXP_AL_SHIFT); 5546b1c7c67SMichael Buesch SPEX(gpio0, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P0, 0); 5556b1c7c67SMichael Buesch SPEX(gpio1, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P1, 5566b1c7c67SMichael Buesch SSB_SPROM8_GPIOA_P1_SHIFT); 5576b1c7c67SMichael Buesch SPEX(gpio2, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P2, 0); 5586b1c7c67SMichael Buesch SPEX(gpio3, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P3, 5596b1c7c67SMichael Buesch SSB_SPROM8_GPIOB_P3_SHIFT); 560f679056bSGábor Stefanik SPEX(tri2g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI2G, 0); 561f679056bSGábor Stefanik SPEX(tri5g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI5G, 562f679056bSGábor Stefanik SSB_SPROM8_TRI5G_SHIFT); 563f679056bSGábor Stefanik SPEX(tri5gl, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GL, 0); 564f679056bSGábor Stefanik SPEX(tri5gh, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GH, 565f679056bSGábor Stefanik SSB_SPROM8_TRI5GH_SHIFT); 566f679056bSGábor Stefanik SPEX(rxpo2g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO2G, 0); 567f679056bSGábor Stefanik SPEX(rxpo5g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO5G, 568f679056bSGábor Stefanik SSB_SPROM8_RXPO5G_SHIFT); 569f679056bSGábor Stefanik SPEX(rssismf2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMF2G, 0); 570f679056bSGábor Stefanik SPEX(rssismc2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMC2G, 571f679056bSGábor Stefanik SSB_SPROM8_RSSISMC2G_SHIFT); 572f679056bSGábor Stefanik SPEX(rssisav2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISAV2G, 573f679056bSGábor Stefanik SSB_SPROM8_RSSISAV2G_SHIFT); 574f679056bSGábor Stefanik SPEX(bxa2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_BXA2G, 575f679056bSGábor Stefanik SSB_SPROM8_BXA2G_SHIFT); 576f679056bSGábor Stefanik SPEX(rssismf5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMF5G, 0); 577f679056bSGábor Stefanik SPEX(rssismc5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMC5G, 578f679056bSGábor Stefanik SSB_SPROM8_RSSISMC5G_SHIFT); 579f679056bSGábor Stefanik SPEX(rssisav5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISAV5G, 580f679056bSGábor Stefanik SSB_SPROM8_RSSISAV5G_SHIFT); 581f679056bSGábor Stefanik SPEX(bxa5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_BXA5G, 582f679056bSGábor Stefanik SSB_SPROM8_BXA5G_SHIFT); 583f679056bSGábor Stefanik SPEX(pa0b0, SSB_SPROM8_PA0B0, 0xFFFF, 0); 584f679056bSGábor Stefanik SPEX(pa0b1, SSB_SPROM8_PA0B1, 0xFFFF, 0); 585f679056bSGábor Stefanik SPEX(pa0b2, SSB_SPROM8_PA0B2, 0xFFFF, 0); 586f679056bSGábor Stefanik SPEX(pa1b0, SSB_SPROM8_PA1B0, 0xFFFF, 0); 587f679056bSGábor Stefanik SPEX(pa1b1, SSB_SPROM8_PA1B1, 0xFFFF, 0); 588f679056bSGábor Stefanik SPEX(pa1b2, SSB_SPROM8_PA1B2, 0xFFFF, 0); 589f679056bSGábor Stefanik SPEX(pa1lob0, SSB_SPROM8_PA1LOB0, 0xFFFF, 0); 590f679056bSGábor Stefanik SPEX(pa1lob1, SSB_SPROM8_PA1LOB1, 0xFFFF, 0); 591f679056bSGábor Stefanik SPEX(pa1lob2, SSB_SPROM8_PA1LOB2, 0xFFFF, 0); 592f679056bSGábor Stefanik SPEX(pa1hib0, SSB_SPROM8_PA1HIB0, 0xFFFF, 0); 593f679056bSGábor Stefanik SPEX(pa1hib1, SSB_SPROM8_PA1HIB1, 0xFFFF, 0); 594f679056bSGábor Stefanik SPEX(pa1hib2, SSB_SPROM8_PA1HIB2, 0xFFFF, 0); 595f679056bSGábor Stefanik SPEX(cck2gpo, SSB_SPROM8_CCK2GPO, 0xFFFF, 0); 596f679056bSGábor Stefanik SPEX32(ofdm2gpo, SSB_SPROM8_OFDM2GPO, 0xFFFFFFFF, 0); 597f679056bSGábor Stefanik SPEX32(ofdm5glpo, SSB_SPROM8_OFDM5GLPO, 0xFFFFFFFF, 0); 598f679056bSGábor Stefanik SPEX32(ofdm5gpo, SSB_SPROM8_OFDM5GPO, 0xFFFFFFFF, 0); 599f679056bSGábor Stefanik SPEX32(ofdm5ghpo, SSB_SPROM8_OFDM5GHPO, 0xFFFFFFFF, 0); 6006b1c7c67SMichael Buesch 6016b1c7c67SMichael Buesch /* Extract the antenna gain values. */ 602f8f8a660SHauke Mehrtens SPEX(antenna_gain.a0, SSB_SPROM8_AGAIN01, 6036b1c7c67SMichael Buesch SSB_SPROM8_AGAIN0, SSB_SPROM8_AGAIN0_SHIFT); 604f8f8a660SHauke Mehrtens SPEX(antenna_gain.a1, SSB_SPROM8_AGAIN01, 6056b1c7c67SMichael Buesch SSB_SPROM8_AGAIN1, SSB_SPROM8_AGAIN1_SHIFT); 606f8f8a660SHauke Mehrtens SPEX(antenna_gain.a2, SSB_SPROM8_AGAIN23, 6076b1c7c67SMichael Buesch SSB_SPROM8_AGAIN2, SSB_SPROM8_AGAIN2_SHIFT); 608f8f8a660SHauke Mehrtens SPEX(antenna_gain.a3, SSB_SPROM8_AGAIN23, 6096b1c7c67SMichael Buesch SSB_SPROM8_AGAIN3, SSB_SPROM8_AGAIN3_SHIFT); 6106b1c7c67SMichael Buesch 611b0f70292SRafał Miłecki /* Extract cores power info info */ 612b0f70292SRafał Miłecki for (i = 0; i < ARRAY_SIZE(pwr_info_offset); i++) { 613b0f70292SRafał Miłecki o = pwr_info_offset[i]; 614b0f70292SRafał Miłecki SPEX(core_pwr_info[i].itssi_2g, o + SSB_SROM8_2G_MAXP_ITSSI, 615b0f70292SRafał Miłecki SSB_SPROM8_2G_ITSSI, SSB_SPROM8_2G_ITSSI_SHIFT); 616b0f70292SRafał Miłecki SPEX(core_pwr_info[i].maxpwr_2g, o + SSB_SROM8_2G_MAXP_ITSSI, 617b0f70292SRafał Miłecki SSB_SPROM8_2G_MAXP, 0); 618b0f70292SRafał Miłecki 619b0f70292SRafał Miłecki SPEX(core_pwr_info[i].pa_2g[0], o + SSB_SROM8_2G_PA_0, ~0, 0); 620b0f70292SRafał Miłecki SPEX(core_pwr_info[i].pa_2g[1], o + SSB_SROM8_2G_PA_1, ~0, 0); 621b0f70292SRafał Miłecki SPEX(core_pwr_info[i].pa_2g[2], o + SSB_SROM8_2G_PA_2, ~0, 0); 622b0f70292SRafał Miłecki 623b0f70292SRafał Miłecki SPEX(core_pwr_info[i].itssi_5g, o + SSB_SROM8_5G_MAXP_ITSSI, 624b0f70292SRafał Miłecki SSB_SPROM8_5G_ITSSI, SSB_SPROM8_5G_ITSSI_SHIFT); 625b0f70292SRafał Miłecki SPEX(core_pwr_info[i].maxpwr_5g, o + SSB_SROM8_5G_MAXP_ITSSI, 626b0f70292SRafał Miłecki SSB_SPROM8_5G_MAXP, 0); 627b0f70292SRafał Miłecki SPEX(core_pwr_info[i].maxpwr_5gh, o + SSB_SPROM8_5GHL_MAXP, 628b0f70292SRafał Miłecki SSB_SPROM8_5GH_MAXP, 0); 629b0f70292SRafał Miłecki SPEX(core_pwr_info[i].maxpwr_5gl, o + SSB_SPROM8_5GHL_MAXP, 630b0f70292SRafał Miłecki SSB_SPROM8_5GL_MAXP, SSB_SPROM8_5GL_MAXP_SHIFT); 631b0f70292SRafał Miłecki 632b0f70292SRafał Miłecki SPEX(core_pwr_info[i].pa_5gl[0], o + SSB_SROM8_5GL_PA_0, ~0, 0); 633b0f70292SRafał Miłecki SPEX(core_pwr_info[i].pa_5gl[1], o + SSB_SROM8_5GL_PA_1, ~0, 0); 634b0f70292SRafał Miłecki SPEX(core_pwr_info[i].pa_5gl[2], o + SSB_SROM8_5GL_PA_2, ~0, 0); 635b0f70292SRafał Miłecki SPEX(core_pwr_info[i].pa_5g[0], o + SSB_SROM8_5G_PA_0, ~0, 0); 636b0f70292SRafał Miłecki SPEX(core_pwr_info[i].pa_5g[1], o + SSB_SROM8_5G_PA_1, ~0, 0); 637b0f70292SRafał Miłecki SPEX(core_pwr_info[i].pa_5g[2], o + SSB_SROM8_5G_PA_2, ~0, 0); 638b0f70292SRafał Miłecki SPEX(core_pwr_info[i].pa_5gh[0], o + SSB_SROM8_5GH_PA_0, ~0, 0); 639b0f70292SRafał Miłecki SPEX(core_pwr_info[i].pa_5gh[1], o + SSB_SROM8_5GH_PA_1, ~0, 0); 640b0f70292SRafał Miłecki SPEX(core_pwr_info[i].pa_5gh[2], o + SSB_SROM8_5GH_PA_2, ~0, 0); 641b0f70292SRafał Miłecki } 642b0f70292SRafał Miłecki 6438a5ac6ecSRafał Miłecki /* Extract FEM info */ 6448a5ac6ecSRafał Miłecki SPEX(fem.ghz2.tssipos, SSB_SPROM8_FEM2G, 6458a5ac6ecSRafał Miłecki SSB_SROM8_FEM_TSSIPOS, SSB_SROM8_FEM_TSSIPOS_SHIFT); 6468a5ac6ecSRafał Miłecki SPEX(fem.ghz2.extpa_gain, SSB_SPROM8_FEM2G, 6478a5ac6ecSRafał Miłecki SSB_SROM8_FEM_EXTPA_GAIN, SSB_SROM8_FEM_EXTPA_GAIN_SHIFT); 6488a5ac6ecSRafał Miłecki SPEX(fem.ghz2.pdet_range, SSB_SPROM8_FEM2G, 6498a5ac6ecSRafał Miłecki SSB_SROM8_FEM_PDET_RANGE, SSB_SROM8_FEM_PDET_RANGE_SHIFT); 6508a5ac6ecSRafał Miłecki SPEX(fem.ghz2.tr_iso, SSB_SPROM8_FEM2G, 6518a5ac6ecSRafał Miłecki SSB_SROM8_FEM_TR_ISO, SSB_SROM8_FEM_TR_ISO_SHIFT); 6528a5ac6ecSRafał Miłecki SPEX(fem.ghz2.antswlut, SSB_SPROM8_FEM2G, 6538a5ac6ecSRafał Miłecki SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT); 6548a5ac6ecSRafał Miłecki 6558a5ac6ecSRafał Miłecki SPEX(fem.ghz5.tssipos, SSB_SPROM8_FEM5G, 6568a5ac6ecSRafał Miłecki SSB_SROM8_FEM_TSSIPOS, SSB_SROM8_FEM_TSSIPOS_SHIFT); 6578a5ac6ecSRafał Miłecki SPEX(fem.ghz5.extpa_gain, SSB_SPROM8_FEM5G, 6588a5ac6ecSRafał Miłecki SSB_SROM8_FEM_EXTPA_GAIN, SSB_SROM8_FEM_EXTPA_GAIN_SHIFT); 6598a5ac6ecSRafał Miłecki SPEX(fem.ghz5.pdet_range, SSB_SPROM8_FEM5G, 6608a5ac6ecSRafał Miłecki SSB_SROM8_FEM_PDET_RANGE, SSB_SROM8_FEM_PDET_RANGE_SHIFT); 6618a5ac6ecSRafał Miłecki SPEX(fem.ghz5.tr_iso, SSB_SPROM8_FEM5G, 6628a5ac6ecSRafał Miłecki SSB_SROM8_FEM_TR_ISO, SSB_SROM8_FEM_TR_ISO_SHIFT); 6638a5ac6ecSRafał Miłecki SPEX(fem.ghz5.antswlut, SSB_SPROM8_FEM5G, 6648a5ac6ecSRafał Miłecki SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT); 6658a5ac6ecSRafał Miłecki 666172c69a4SRafał Miłecki sprom_extract_r458(out, in); 667172c69a4SRafał Miłecki 6686b1c7c67SMichael Buesch /* TODO - get remaining rev 8 stuff needed */ 6696b1c7c67SMichael Buesch } 6706b1c7c67SMichael Buesch 671c272ef44SLarry Finger static int sprom_extract(struct ssb_bus *bus, struct ssb_sprom *out, 672c272ef44SLarry Finger const u16 *in, u16 size) 67361e115a5SMichael Buesch { 67461e115a5SMichael Buesch memset(out, 0, sizeof(*out)); 67561e115a5SMichael Buesch 676c272ef44SLarry Finger out->revision = in[size - 1] & 0x00FF; 677e861b98dSMichael Buesch ssb_dprintk(KERN_DEBUG PFX "SPROM revision %d detected.\n", out->revision); 67831ce12fbSLarry Finger memset(out->et0mac, 0xFF, 6); /* preset et0 and et1 mac */ 67931ce12fbSLarry Finger memset(out->et1mac, 0xFF, 6); 68054435f9eSRafał Miłecki 68161e115a5SMichael Buesch if ((bus->chip_id & 0xFF00) == 0x4400) { 68261e115a5SMichael Buesch /* Workaround: The BCM44XX chip has a stupid revision 68361e115a5SMichael Buesch * number stored in the SPROM. 68461e115a5SMichael Buesch * Always extract r1. */ 685c272ef44SLarry Finger out->revision = 1; 68654435f9eSRafał Miłecki ssb_dprintk(KERN_DEBUG PFX "SPROM treated as revision %d\n", out->revision); 68754435f9eSRafał Miłecki } 68854435f9eSRafał Miłecki 6896b1c7c67SMichael Buesch switch (out->revision) { 6906b1c7c67SMichael Buesch case 1: 6916b1c7c67SMichael Buesch case 2: 6926b1c7c67SMichael Buesch case 3: 6936b1c7c67SMichael Buesch sprom_extract_r123(out, in); 6946b1c7c67SMichael Buesch break; 6956b1c7c67SMichael Buesch case 4: 6966b1c7c67SMichael Buesch case 5: 6976b1c7c67SMichael Buesch sprom_extract_r45(out, in); 6986b1c7c67SMichael Buesch break; 6996b1c7c67SMichael Buesch case 8: 7006b1c7c67SMichael Buesch sprom_extract_r8(out, in); 7016b1c7c67SMichael Buesch break; 7026b1c7c67SMichael Buesch default: 7036b1c7c67SMichael Buesch ssb_printk(KERN_WARNING PFX "Unsupported SPROM" 7046b1c7c67SMichael Buesch " revision %d detected. Will extract" 7056b1c7c67SMichael Buesch " v1\n", out->revision); 706cd559b36SLarry Finger out->revision = 1; 707c272ef44SLarry Finger sprom_extract_r123(out, in); 708c272ef44SLarry Finger } 70961e115a5SMichael Buesch 7104503183aSLarry Finger if (out->boardflags_lo == 0xFFFF) 7114503183aSLarry Finger out->boardflags_lo = 0; /* per specs */ 7124503183aSLarry Finger if (out->boardflags_hi == 0xFFFF) 7134503183aSLarry Finger out->boardflags_hi = 0; /* per specs */ 7144503183aSLarry Finger 71561e115a5SMichael Buesch return 0; 71661e115a5SMichael Buesch } 71761e115a5SMichael Buesch 71861e115a5SMichael Buesch static int ssb_pci_sprom_get(struct ssb_bus *bus, 71961e115a5SMichael Buesch struct ssb_sprom *sprom) 72061e115a5SMichael Buesch { 721ca4a0831SRafał Miłecki int err; 72261e115a5SMichael Buesch u16 *buf; 72361e115a5SMichael Buesch 724d53cdbb9SJohn W. Linville if (!ssb_is_sprom_available(bus)) { 725d53cdbb9SJohn W. Linville ssb_printk(KERN_ERR PFX "No SPROM available!\n"); 726d53cdbb9SJohn W. Linville return -ENODEV; 727d53cdbb9SJohn W. Linville } 72825985edcSLucas De Marchi if (bus->chipco.dev) { /* can be unavailable! */ 7299d1ac34eSLarry Finger /* 7309d1ac34eSLarry Finger * get SPROM offset: SSB_SPROM_BASE1 except for 7319d1ac34eSLarry Finger * chipcommon rev >= 31 or chip ID is 0x4312 and 7329d1ac34eSLarry Finger * chipcommon status & 3 == 2 7339d1ac34eSLarry Finger */ 7349d1ac34eSLarry Finger if (bus->chipco.dev->id.revision >= 31) 7359d1ac34eSLarry Finger bus->sprom_offset = SSB_SPROM_BASE31; 7369d1ac34eSLarry Finger else if (bus->chip_id == 0x4312 && 7379d1ac34eSLarry Finger (bus->chipco.status & 0x03) == 2) 7389d1ac34eSLarry Finger bus->sprom_offset = SSB_SPROM_BASE31; 7399d1ac34eSLarry Finger else 7409d1ac34eSLarry Finger bus->sprom_offset = SSB_SPROM_BASE1; 741da1fdb02SChristoph Fritz } else { 742da1fdb02SChristoph Fritz bus->sprom_offset = SSB_SPROM_BASE1; 743da1fdb02SChristoph Fritz } 7449d1ac34eSLarry Finger ssb_dprintk(KERN_INFO PFX "SPROM offset is 0x%x\n", bus->sprom_offset); 745ea2db495SRafał Miłecki 746c272ef44SLarry Finger buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL); 74761e115a5SMichael Buesch if (!buf) 748ca4a0831SRafał Miłecki return -ENOMEM; 749c272ef44SLarry Finger bus->sprom_size = SSB_SPROMSIZE_WORDS_R123; 75061e115a5SMichael Buesch sprom_do_read(bus, buf); 751c272ef44SLarry Finger err = sprom_check_crc(buf, bus->sprom_size); 75261e115a5SMichael Buesch if (err) { 7532afc4901SLarry.Finger@lwfinger.net /* try for a 440 byte SPROM - revision 4 and higher */ 754c272ef44SLarry Finger kfree(buf); 755c272ef44SLarry Finger buf = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16), 756c272ef44SLarry Finger GFP_KERNEL); 757c272ef44SLarry Finger if (!buf) 758ca4a0831SRafał Miłecki return -ENOMEM; 759c272ef44SLarry Finger bus->sprom_size = SSB_SPROMSIZE_WORDS_R4; 760c272ef44SLarry Finger sprom_do_read(bus, buf); 761c272ef44SLarry Finger err = sprom_check_crc(buf, bus->sprom_size); 762e79c1ba8SMichael Buesch if (err) { 763e79c1ba8SMichael Buesch /* All CRC attempts failed. 764e79c1ba8SMichael Buesch * Maybe there is no SPROM on the device? 765b3ae52b6SHauke Mehrtens * Now we ask the arch code if there is some sprom 766b3ae52b6SHauke Mehrtens * available for this device in some other storage */ 767b3ae52b6SHauke Mehrtens err = ssb_fill_sprom_with_fallback(bus, sprom); 768b3ae52b6SHauke Mehrtens if (err) { 769b3ae52b6SHauke Mehrtens ssb_printk(KERN_WARNING PFX "WARNING: Using" 770b3ae52b6SHauke Mehrtens " fallback SPROM failed (err %d)\n", 771b3ae52b6SHauke Mehrtens err); 772b3ae52b6SHauke Mehrtens } else { 773b3ae52b6SHauke Mehrtens ssb_dprintk(KERN_DEBUG PFX "Using SPROM" 774b3ae52b6SHauke Mehrtens " revision %d provided by" 775b3ae52b6SHauke Mehrtens " platform.\n", sprom->revision); 776e79c1ba8SMichael Buesch err = 0; 777e79c1ba8SMichael Buesch goto out_free; 778e79c1ba8SMichael Buesch } 779c272ef44SLarry Finger ssb_printk(KERN_WARNING PFX "WARNING: Invalid" 780c272ef44SLarry Finger " SPROM CRC (corrupt SPROM)\n"); 781c272ef44SLarry Finger } 782e79c1ba8SMichael Buesch } 783c272ef44SLarry Finger err = sprom_extract(bus, sprom, buf, bus->sprom_size); 78461e115a5SMichael Buesch 785e79c1ba8SMichael Buesch out_free: 78661e115a5SMichael Buesch kfree(buf); 78761e115a5SMichael Buesch return err; 78861e115a5SMichael Buesch } 78961e115a5SMichael Buesch 79061e115a5SMichael Buesch static void ssb_pci_get_boardinfo(struct ssb_bus *bus, 79161e115a5SMichael Buesch struct ssb_boardinfo *bi) 79261e115a5SMichael Buesch { 793115f9450SSergei Shtylyov bi->vendor = bus->host_pci->subsystem_vendor; 794115f9450SSergei Shtylyov bi->type = bus->host_pci->subsystem_device; 79561e115a5SMichael Buesch } 79661e115a5SMichael Buesch 79761e115a5SMichael Buesch int ssb_pci_get_invariants(struct ssb_bus *bus, 79861e115a5SMichael Buesch struct ssb_init_invariants *iv) 79961e115a5SMichael Buesch { 80061e115a5SMichael Buesch int err; 80161e115a5SMichael Buesch 80261e115a5SMichael Buesch err = ssb_pci_sprom_get(bus, &iv->sprom); 80361e115a5SMichael Buesch if (err) 80461e115a5SMichael Buesch goto out; 80561e115a5SMichael Buesch ssb_pci_get_boardinfo(bus, &iv->boardinfo); 80661e115a5SMichael Buesch 80761e115a5SMichael Buesch out: 80861e115a5SMichael Buesch return err; 80961e115a5SMichael Buesch } 81061e115a5SMichael Buesch 81161e115a5SMichael Buesch #ifdef CONFIG_SSB_DEBUG 81261e115a5SMichael Buesch static int ssb_pci_assert_buspower(struct ssb_bus *bus) 81361e115a5SMichael Buesch { 81461e115a5SMichael Buesch if (likely(bus->powered_up)) 81561e115a5SMichael Buesch return 0; 81661e115a5SMichael Buesch 81761e115a5SMichael Buesch printk(KERN_ERR PFX "FATAL ERROR: Bus powered down " 81861e115a5SMichael Buesch "while accessing PCI MMIO space\n"); 81961e115a5SMichael Buesch if (bus->power_warn_count <= 10) { 82061e115a5SMichael Buesch bus->power_warn_count++; 82161e115a5SMichael Buesch dump_stack(); 82261e115a5SMichael Buesch } 82361e115a5SMichael Buesch 82461e115a5SMichael Buesch return -ENODEV; 82561e115a5SMichael Buesch } 82661e115a5SMichael Buesch #else /* DEBUG */ 82761e115a5SMichael Buesch static inline int ssb_pci_assert_buspower(struct ssb_bus *bus) 82861e115a5SMichael Buesch { 82961e115a5SMichael Buesch return 0; 83061e115a5SMichael Buesch } 83161e115a5SMichael Buesch #endif /* DEBUG */ 83261e115a5SMichael Buesch 833ffc7689dSMichael Buesch static u8 ssb_pci_read8(struct ssb_device *dev, u16 offset) 834ffc7689dSMichael Buesch { 835ffc7689dSMichael Buesch struct ssb_bus *bus = dev->bus; 836ffc7689dSMichael Buesch 837ffc7689dSMichael Buesch if (unlikely(ssb_pci_assert_buspower(bus))) 838ffc7689dSMichael Buesch return 0xFF; 839ffc7689dSMichael Buesch if (unlikely(bus->mapped_device != dev)) { 840ffc7689dSMichael Buesch if (unlikely(ssb_pci_switch_core(bus, dev))) 841ffc7689dSMichael Buesch return 0xFF; 842ffc7689dSMichael Buesch } 843ffc7689dSMichael Buesch return ioread8(bus->mmio + offset); 844ffc7689dSMichael Buesch } 845ffc7689dSMichael Buesch 84661e115a5SMichael Buesch static u16 ssb_pci_read16(struct ssb_device *dev, u16 offset) 84761e115a5SMichael Buesch { 84861e115a5SMichael Buesch struct ssb_bus *bus = dev->bus; 84961e115a5SMichael Buesch 85061e115a5SMichael Buesch if (unlikely(ssb_pci_assert_buspower(bus))) 85161e115a5SMichael Buesch return 0xFFFF; 85261e115a5SMichael Buesch if (unlikely(bus->mapped_device != dev)) { 85361e115a5SMichael Buesch if (unlikely(ssb_pci_switch_core(bus, dev))) 85461e115a5SMichael Buesch return 0xFFFF; 85561e115a5SMichael Buesch } 8564b402c65SMichael Buesch return ioread16(bus->mmio + offset); 85761e115a5SMichael Buesch } 85861e115a5SMichael Buesch 85961e115a5SMichael Buesch static u32 ssb_pci_read32(struct ssb_device *dev, u16 offset) 86061e115a5SMichael Buesch { 86161e115a5SMichael Buesch struct ssb_bus *bus = dev->bus; 86261e115a5SMichael Buesch 86361e115a5SMichael Buesch if (unlikely(ssb_pci_assert_buspower(bus))) 86461e115a5SMichael Buesch return 0xFFFFFFFF; 86561e115a5SMichael Buesch if (unlikely(bus->mapped_device != dev)) { 86661e115a5SMichael Buesch if (unlikely(ssb_pci_switch_core(bus, dev))) 86761e115a5SMichael Buesch return 0xFFFFFFFF; 86861e115a5SMichael Buesch } 8694b402c65SMichael Buesch return ioread32(bus->mmio + offset); 87061e115a5SMichael Buesch } 87161e115a5SMichael Buesch 872d625a29bSMichael Buesch #ifdef CONFIG_SSB_BLOCKIO 873d625a29bSMichael Buesch static void ssb_pci_block_read(struct ssb_device *dev, void *buffer, 874d625a29bSMichael Buesch size_t count, u16 offset, u8 reg_width) 875d625a29bSMichael Buesch { 876d625a29bSMichael Buesch struct ssb_bus *bus = dev->bus; 877d625a29bSMichael Buesch void __iomem *addr = bus->mmio + offset; 878d625a29bSMichael Buesch 879d625a29bSMichael Buesch if (unlikely(ssb_pci_assert_buspower(bus))) 880d625a29bSMichael Buesch goto error; 881d625a29bSMichael Buesch if (unlikely(bus->mapped_device != dev)) { 882d625a29bSMichael Buesch if (unlikely(ssb_pci_switch_core(bus, dev))) 883d625a29bSMichael Buesch goto error; 884d625a29bSMichael Buesch } 885d625a29bSMichael Buesch switch (reg_width) { 886d625a29bSMichael Buesch case sizeof(u8): 887d625a29bSMichael Buesch ioread8_rep(addr, buffer, count); 888d625a29bSMichael Buesch break; 889d625a29bSMichael Buesch case sizeof(u16): 890d625a29bSMichael Buesch SSB_WARN_ON(count & 1); 891d625a29bSMichael Buesch ioread16_rep(addr, buffer, count >> 1); 892d625a29bSMichael Buesch break; 893d625a29bSMichael Buesch case sizeof(u32): 894d625a29bSMichael Buesch SSB_WARN_ON(count & 3); 895d625a29bSMichael Buesch ioread32_rep(addr, buffer, count >> 2); 896d625a29bSMichael Buesch break; 897d625a29bSMichael Buesch default: 898d625a29bSMichael Buesch SSB_WARN_ON(1); 899d625a29bSMichael Buesch } 900d625a29bSMichael Buesch 901d625a29bSMichael Buesch return; 902d625a29bSMichael Buesch error: 903d625a29bSMichael Buesch memset(buffer, 0xFF, count); 904d625a29bSMichael Buesch } 905d625a29bSMichael Buesch #endif /* CONFIG_SSB_BLOCKIO */ 906d625a29bSMichael Buesch 907ffc7689dSMichael Buesch static void ssb_pci_write8(struct ssb_device *dev, u16 offset, u8 value) 908ffc7689dSMichael Buesch { 909ffc7689dSMichael Buesch struct ssb_bus *bus = dev->bus; 910ffc7689dSMichael Buesch 911ffc7689dSMichael Buesch if (unlikely(ssb_pci_assert_buspower(bus))) 912ffc7689dSMichael Buesch return; 913ffc7689dSMichael Buesch if (unlikely(bus->mapped_device != dev)) { 914ffc7689dSMichael Buesch if (unlikely(ssb_pci_switch_core(bus, dev))) 915ffc7689dSMichael Buesch return; 916ffc7689dSMichael Buesch } 917ffc7689dSMichael Buesch iowrite8(value, bus->mmio + offset); 918ffc7689dSMichael Buesch } 919ffc7689dSMichael Buesch 92061e115a5SMichael Buesch static void ssb_pci_write16(struct ssb_device *dev, u16 offset, u16 value) 92161e115a5SMichael Buesch { 92261e115a5SMichael Buesch struct ssb_bus *bus = dev->bus; 92361e115a5SMichael Buesch 92461e115a5SMichael Buesch if (unlikely(ssb_pci_assert_buspower(bus))) 92561e115a5SMichael Buesch return; 92661e115a5SMichael Buesch if (unlikely(bus->mapped_device != dev)) { 92761e115a5SMichael Buesch if (unlikely(ssb_pci_switch_core(bus, dev))) 92861e115a5SMichael Buesch return; 92961e115a5SMichael Buesch } 9304b402c65SMichael Buesch iowrite16(value, bus->mmio + offset); 93161e115a5SMichael Buesch } 93261e115a5SMichael Buesch 93361e115a5SMichael Buesch static void ssb_pci_write32(struct ssb_device *dev, u16 offset, u32 value) 93461e115a5SMichael Buesch { 93561e115a5SMichael Buesch struct ssb_bus *bus = dev->bus; 93661e115a5SMichael Buesch 93761e115a5SMichael Buesch if (unlikely(ssb_pci_assert_buspower(bus))) 93861e115a5SMichael Buesch return; 93961e115a5SMichael Buesch if (unlikely(bus->mapped_device != dev)) { 94061e115a5SMichael Buesch if (unlikely(ssb_pci_switch_core(bus, dev))) 94161e115a5SMichael Buesch return; 94261e115a5SMichael Buesch } 9434b402c65SMichael Buesch iowrite32(value, bus->mmio + offset); 94461e115a5SMichael Buesch } 94561e115a5SMichael Buesch 946d625a29bSMichael Buesch #ifdef CONFIG_SSB_BLOCKIO 947d625a29bSMichael Buesch static void ssb_pci_block_write(struct ssb_device *dev, const void *buffer, 948d625a29bSMichael Buesch size_t count, u16 offset, u8 reg_width) 949d625a29bSMichael Buesch { 950d625a29bSMichael Buesch struct ssb_bus *bus = dev->bus; 951d625a29bSMichael Buesch void __iomem *addr = bus->mmio + offset; 952d625a29bSMichael Buesch 953d625a29bSMichael Buesch if (unlikely(ssb_pci_assert_buspower(bus))) 954d625a29bSMichael Buesch return; 955d625a29bSMichael Buesch if (unlikely(bus->mapped_device != dev)) { 956d625a29bSMichael Buesch if (unlikely(ssb_pci_switch_core(bus, dev))) 957d625a29bSMichael Buesch return; 958d625a29bSMichael Buesch } 959d625a29bSMichael Buesch switch (reg_width) { 960d625a29bSMichael Buesch case sizeof(u8): 961d625a29bSMichael Buesch iowrite8_rep(addr, buffer, count); 962d625a29bSMichael Buesch break; 963d625a29bSMichael Buesch case sizeof(u16): 964d625a29bSMichael Buesch SSB_WARN_ON(count & 1); 965d625a29bSMichael Buesch iowrite16_rep(addr, buffer, count >> 1); 966d625a29bSMichael Buesch break; 967d625a29bSMichael Buesch case sizeof(u32): 968d625a29bSMichael Buesch SSB_WARN_ON(count & 3); 969d625a29bSMichael Buesch iowrite32_rep(addr, buffer, count >> 2); 970d625a29bSMichael Buesch break; 971d625a29bSMichael Buesch default: 972d625a29bSMichael Buesch SSB_WARN_ON(1); 973d625a29bSMichael Buesch } 974d625a29bSMichael Buesch } 975d625a29bSMichael Buesch #endif /* CONFIG_SSB_BLOCKIO */ 976d625a29bSMichael Buesch 97761e115a5SMichael Buesch /* Not "static", as it's used in main.c */ 97861e115a5SMichael Buesch const struct ssb_bus_ops ssb_pci_ops = { 979ffc7689dSMichael Buesch .read8 = ssb_pci_read8, 98061e115a5SMichael Buesch .read16 = ssb_pci_read16, 98161e115a5SMichael Buesch .read32 = ssb_pci_read32, 982ffc7689dSMichael Buesch .write8 = ssb_pci_write8, 98361e115a5SMichael Buesch .write16 = ssb_pci_write16, 98461e115a5SMichael Buesch .write32 = ssb_pci_write32, 985d625a29bSMichael Buesch #ifdef CONFIG_SSB_BLOCKIO 986d625a29bSMichael Buesch .block_read = ssb_pci_block_read, 987d625a29bSMichael Buesch .block_write = ssb_pci_block_write, 988d625a29bSMichael Buesch #endif 98961e115a5SMichael Buesch }; 99061e115a5SMichael Buesch 99161e115a5SMichael Buesch static ssize_t ssb_pci_attr_sprom_show(struct device *pcidev, 99261e115a5SMichael Buesch struct device_attribute *attr, 99361e115a5SMichael Buesch char *buf) 99461e115a5SMichael Buesch { 99561e115a5SMichael Buesch struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev); 99661e115a5SMichael Buesch struct ssb_bus *bus; 99761e115a5SMichael Buesch 99861e115a5SMichael Buesch bus = ssb_pci_dev_to_bus(pdev); 99961e115a5SMichael Buesch if (!bus) 1000e7ec2e32SMichael Buesch return -ENODEV; 100161e115a5SMichael Buesch 1002e7ec2e32SMichael Buesch return ssb_attr_sprom_show(bus, buf, sprom_do_read); 100361e115a5SMichael Buesch } 100461e115a5SMichael Buesch 100561e115a5SMichael Buesch static ssize_t ssb_pci_attr_sprom_store(struct device *pcidev, 100661e115a5SMichael Buesch struct device_attribute *attr, 100761e115a5SMichael Buesch const char *buf, size_t count) 100861e115a5SMichael Buesch { 100961e115a5SMichael Buesch struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev); 101061e115a5SMichael Buesch struct ssb_bus *bus; 101161e115a5SMichael Buesch 101261e115a5SMichael Buesch bus = ssb_pci_dev_to_bus(pdev); 101361e115a5SMichael Buesch if (!bus) 1014e7ec2e32SMichael Buesch return -ENODEV; 101561e115a5SMichael Buesch 1016e7ec2e32SMichael Buesch return ssb_attr_sprom_store(bus, buf, count, 1017e7ec2e32SMichael Buesch sprom_check_crc, sprom_do_write); 101861e115a5SMichael Buesch } 101961e115a5SMichael Buesch 102061e115a5SMichael Buesch static DEVICE_ATTR(ssb_sprom, 0600, 102161e115a5SMichael Buesch ssb_pci_attr_sprom_show, 102261e115a5SMichael Buesch ssb_pci_attr_sprom_store); 102361e115a5SMichael Buesch 102461e115a5SMichael Buesch void ssb_pci_exit(struct ssb_bus *bus) 102561e115a5SMichael Buesch { 102661e115a5SMichael Buesch struct pci_dev *pdev; 102761e115a5SMichael Buesch 102861e115a5SMichael Buesch if (bus->bustype != SSB_BUSTYPE_PCI) 102961e115a5SMichael Buesch return; 103061e115a5SMichael Buesch 103161e115a5SMichael Buesch pdev = bus->host_pci; 103261e115a5SMichael Buesch device_remove_file(&pdev->dev, &dev_attr_ssb_sprom); 103361e115a5SMichael Buesch } 103461e115a5SMichael Buesch 103561e115a5SMichael Buesch int ssb_pci_init(struct ssb_bus *bus) 103661e115a5SMichael Buesch { 103761e115a5SMichael Buesch struct pci_dev *pdev; 103861e115a5SMichael Buesch int err; 103961e115a5SMichael Buesch 104061e115a5SMichael Buesch if (bus->bustype != SSB_BUSTYPE_PCI) 104161e115a5SMichael Buesch return 0; 104261e115a5SMichael Buesch 104361e115a5SMichael Buesch pdev = bus->host_pci; 1044e7ec2e32SMichael Buesch mutex_init(&bus->sprom_mutex); 104561e115a5SMichael Buesch err = device_create_file(&pdev->dev, &dev_attr_ssb_sprom); 104661e115a5SMichael Buesch if (err) 104761e115a5SMichael Buesch goto out; 104861e115a5SMichael Buesch 104961e115a5SMichael Buesch out: 105061e115a5SMichael Buesch return err; 105161e115a5SMichael Buesch } 1052