diff options
Diffstat (limited to 'drivers/bcma/sprom.c')
| -rw-r--r-- | drivers/bcma/sprom.c | 264 |
1 files changed, 216 insertions, 48 deletions
diff --git a/drivers/bcma/sprom.c b/drivers/bcma/sprom.c index cdcf75c0954..72bf4540f56 100644 --- a/drivers/bcma/sprom.c +++ b/drivers/bcma/sprom.c @@ -60,11 +60,11 @@ static int bcma_fill_sprom_with_fallback(struct bcma_bus *bus, if (err) goto fail; - pr_debug("Using SPROM revision %d provided by" - " platform.\n", bus->sprom.revision); + bcma_debug(bus, "Using SPROM revision %d provided by platform.\n", + bus->sprom.revision); return 0; fail: - pr_warn("Using fallback SPROM failed (err %d)\n", err); + bcma_warn(bus, "Using fallback SPROM failed (err %d)\n", err); return err; } @@ -72,12 +72,12 @@ fail: * R/W ops. **************************************************/ -static void bcma_sprom_read(struct bcma_bus *bus, u16 offset, u16 *sprom) +static void bcma_sprom_read(struct bcma_bus *bus, u16 offset, u16 *sprom, + size_t words) { int i; - for (i = 0; i < SSB_SPROMSIZE_WORDS_R4; i++) - sprom[i] = bcma_read16(bus->drv_cc.core, - offset + (i * 2)); + for (i = 0; i < words; i++) + sprom[i] = bcma_read16(bus->drv_cc.core, offset + (i * 2)); } /************************************************** @@ -124,29 +124,29 @@ static inline u8 bcma_crc8(u8 crc, u8 data) return t[crc ^ data]; } -static u8 bcma_sprom_crc(const u16 *sprom) +static u8 bcma_sprom_crc(const u16 *sprom, size_t words) { int word; u8 crc = 0xFF; - for (word = 0; word < SSB_SPROMSIZE_WORDS_R4 - 1; word++) { + for (word = 0; word < words - 1; word++) { crc = bcma_crc8(crc, sprom[word] & 0x00FF); crc = bcma_crc8(crc, (sprom[word] & 0xFF00) >> 8); } - crc = bcma_crc8(crc, sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & 0x00FF); + crc = bcma_crc8(crc, sprom[words - 1] & 0x00FF); crc ^= 0xFF; return crc; } -static int bcma_sprom_check_crc(const u16 *sprom) +static int bcma_sprom_check_crc(const u16 *sprom, size_t words) { u8 crc; u8 expected_crc; u16 tmp; - crc = bcma_sprom_crc(sprom); - tmp = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & SSB_SPROM_REVISION_CRC; + crc = bcma_sprom_crc(sprom, words); + tmp = sprom[words - 1] & SSB_SPROM_REVISION_CRC; expected_crc = tmp >> SSB_SPROM_REVISION_CRC_SHIFT; if (crc != expected_crc) return -EPROTO; @@ -154,21 +154,25 @@ static int bcma_sprom_check_crc(const u16 *sprom) return 0; } -static int bcma_sprom_valid(const u16 *sprom) +static int bcma_sprom_valid(struct bcma_bus *bus, const u16 *sprom, + size_t words) { u16 revision; int err; - err = bcma_sprom_check_crc(sprom); + err = bcma_sprom_check_crc(sprom, words); if (err) return err; - revision = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & SSB_SPROM_REVISION_REV; - if (revision != 8 && revision != 9) { + revision = sprom[words - 1] & SSB_SPROM_REVISION_REV; + if (revision != 8 && revision != 9 && revision != 10) { pr_err("Unsupported SPROM revision: %d\n", revision); return -ENOENT; } + bus->sprom.revision = revision; + bcma_debug(bus, "Found SPROM revision %d\n", revision); + return 0; } @@ -181,6 +185,22 @@ static int bcma_sprom_valid(const u16 *sprom) #define SPEX(_field, _offset, _mask, _shift) \ bus->sprom._field = ((sprom[SPOFF(_offset)] & (_mask)) >> (_shift)) +#define SPEX32(_field, _offset, _mask, _shift) \ + bus->sprom._field = ((((u32)sprom[SPOFF((_offset)+2)] << 16 | \ + sprom[SPOFF(_offset)]) & (_mask)) >> (_shift)) + +#define SPEX_ARRAY8(_field, _offset, _mask, _shift) \ + do { \ + SPEX(_field[0], _offset + 0, _mask, _shift); \ + SPEX(_field[1], _offset + 2, _mask, _shift); \ + SPEX(_field[2], _offset + 4, _mask, _shift); \ + SPEX(_field[3], _offset + 6, _mask, _shift); \ + SPEX(_field[4], _offset + 8, _mask, _shift); \ + SPEX(_field[5], _offset + 10, _mask, _shift); \ + SPEX(_field[6], _offset + 12, _mask, _shift); \ + SPEX(_field[7], _offset + 14, _mask, _shift); \ + } while (0) + static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom) { u16 v, o; @@ -192,15 +212,13 @@ static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom) BUILD_BUG_ON(ARRAY_SIZE(pwr_info_offset) != ARRAY_SIZE(bus->sprom.core_pwr_info)); - bus->sprom.revision = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & - SSB_SPROM_REVISION_REV; - for (i = 0; i < 3; i++) { v = sprom[SPOFF(SSB_SPROM8_IL0MAC) + i]; *(((__be16 *)bus->sprom.il0mac) + i) = cpu_to_be16(v); } SPEX(board_rev, SSB_SPROM8_BOARDREV, ~0, 0); + SPEX(board_type, SSB_SPROM1_SPID, ~0, 0); SPEX(txpid2g[0], SSB_SPROM4_TXPID2G01, SSB_SPROM4_TXPID2G0, SSB_SPROM4_TXPID2G0_SHIFT); @@ -243,7 +261,8 @@ static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom) SPEX(boardflags2_lo, SSB_SPROM8_BFL2LO, ~0, 0); SPEX(boardflags2_hi, SSB_SPROM8_BFL2HI, ~0, 0); - SPEX(country_code, SSB_SPROM8_CCODE, ~0, 0); + SPEX(alpha2[0], SSB_SPROM8_CCODE, 0xff00, 8); + SPEX(alpha2[1], SSB_SPROM8_CCODE, 0x00ff, 0); /* Extract cores power info info */ for (i = 0; i < ARRAY_SIZE(pwr_info_offset); i++) { @@ -298,6 +317,136 @@ static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom) SSB_SROM8_FEM_TR_ISO_SHIFT); SPEX(fem.ghz5.antswlut, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT); + + SPEX(ant_available_a, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_A, + SSB_SPROM8_ANTAVAIL_A_SHIFT); + SPEX(ant_available_bg, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_BG, + SSB_SPROM8_ANTAVAIL_BG_SHIFT); + SPEX(maxpwr_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_MAXP_BG_MASK, 0); + SPEX(itssi_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_ITSSI_BG, + SSB_SPROM8_ITSSI_BG_SHIFT); + SPEX(maxpwr_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_MAXP_A_MASK, 0); + SPEX(itssi_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_ITSSI_A, + SSB_SPROM8_ITSSI_A_SHIFT); + SPEX(maxpwr_ah, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AH_MASK, 0); + SPEX(maxpwr_al, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AL_MASK, + SSB_SPROM8_MAXP_AL_SHIFT); + SPEX(gpio0, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P0, 0); + SPEX(gpio1, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P1, + SSB_SPROM8_GPIOA_P1_SHIFT); + SPEX(gpio2, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P2, 0); + SPEX(gpio3, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P3, + SSB_SPROM8_GPIOB_P3_SHIFT); + SPEX(tri2g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI2G, 0); + SPEX(tri5g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI5G, + SSB_SPROM8_TRI5G_SHIFT); + SPEX(tri5gl, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GL, 0); + SPEX(tri5gh, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GH, + SSB_SPROM8_TRI5GH_SHIFT); + SPEX(rxpo2g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO2G, + SSB_SPROM8_RXPO2G_SHIFT); + SPEX(rxpo5g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO5G, + SSB_SPROM8_RXPO5G_SHIFT); + SPEX(rssismf2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMF2G, 0); + SPEX(rssismc2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMC2G, + SSB_SPROM8_RSSISMC2G_SHIFT); + SPEX(rssisav2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISAV2G, + SSB_SPROM8_RSSISAV2G_SHIFT); + SPEX(bxa2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_BXA2G, + SSB_SPROM8_BXA2G_SHIFT); + SPEX(rssismf5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMF5G, 0); + SPEX(rssismc5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMC5G, + SSB_SPROM8_RSSISMC5G_SHIFT); + SPEX(rssisav5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISAV5G, + SSB_SPROM8_RSSISAV5G_SHIFT); + SPEX(bxa5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_BXA5G, + SSB_SPROM8_BXA5G_SHIFT); + + SPEX(pa0b0, SSB_SPROM8_PA0B0, ~0, 0); + SPEX(pa0b1, SSB_SPROM8_PA0B1, ~0, 0); + SPEX(pa0b2, SSB_SPROM8_PA0B2, ~0, 0); + SPEX(pa1b0, SSB_SPROM8_PA1B0, ~0, 0); + SPEX(pa1b1, SSB_SPROM8_PA1B1, ~0, 0); + SPEX(pa1b2, SSB_SPROM8_PA1B2, ~0, 0); + SPEX(pa1lob0, SSB_SPROM8_PA1LOB0, ~0, 0); + SPEX(pa1lob1, SSB_SPROM8_PA1LOB1, ~0, 0); + SPEX(pa1lob2, SSB_SPROM8_PA1LOB2, ~0, 0); + SPEX(pa1hib0, SSB_SPROM8_PA1HIB0, ~0, 0); + SPEX(pa1hib1, SSB_SPROM8_PA1HIB1, ~0, 0); + SPEX(pa1hib2, SSB_SPROM8_PA1HIB2, ~0, 0); + SPEX(cck2gpo, SSB_SPROM8_CCK2GPO, ~0, 0); + SPEX32(ofdm2gpo, SSB_SPROM8_OFDM2GPO, ~0, 0); + SPEX32(ofdm5glpo, SSB_SPROM8_OFDM5GLPO, ~0, 0); + SPEX32(ofdm5gpo, SSB_SPROM8_OFDM5GPO, ~0, 0); + SPEX32(ofdm5ghpo, SSB_SPROM8_OFDM5GHPO, ~0, 0); + + /* Extract the antenna gain values. */ + SPEX(antenna_gain.a0, SSB_SPROM8_AGAIN01, + SSB_SPROM8_AGAIN0, SSB_SPROM8_AGAIN0_SHIFT); + SPEX(antenna_gain.a1, SSB_SPROM8_AGAIN01, + SSB_SPROM8_AGAIN1, SSB_SPROM8_AGAIN1_SHIFT); + SPEX(antenna_gain.a2, SSB_SPROM8_AGAIN23, + SSB_SPROM8_AGAIN2, SSB_SPROM8_AGAIN2_SHIFT); + SPEX(antenna_gain.a3, SSB_SPROM8_AGAIN23, + SSB_SPROM8_AGAIN3, SSB_SPROM8_AGAIN3_SHIFT); + + SPEX(leddc_on_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_ON, + SSB_SPROM8_LEDDC_ON_SHIFT); + SPEX(leddc_off_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_OFF, + SSB_SPROM8_LEDDC_OFF_SHIFT); + + SPEX(txchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_TXCHAIN, + SSB_SPROM8_TXRXC_TXCHAIN_SHIFT); + SPEX(rxchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_RXCHAIN, + SSB_SPROM8_TXRXC_RXCHAIN_SHIFT); + SPEX(antswitch, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_SWITCH, + SSB_SPROM8_TXRXC_SWITCH_SHIFT); + + SPEX(opo, SSB_SPROM8_OFDM2GPO, 0x00ff, 0); + + SPEX_ARRAY8(mcs2gpo, SSB_SPROM8_2G_MCSPO, ~0, 0); + SPEX_ARRAY8(mcs5gpo, SSB_SPROM8_5G_MCSPO, ~0, 0); + SPEX_ARRAY8(mcs5glpo, SSB_SPROM8_5GL_MCSPO, ~0, 0); + SPEX_ARRAY8(mcs5ghpo, SSB_SPROM8_5GH_MCSPO, ~0, 0); + + SPEX(rawtempsense, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_RAWTEMP, + SSB_SPROM8_RAWTS_RAWTEMP_SHIFT); + SPEX(measpower, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_MEASPOWER, + SSB_SPROM8_RAWTS_MEASPOWER_SHIFT); + SPEX(tempsense_slope, SSB_SPROM8_OPT_CORRX, + SSB_SPROM8_OPT_CORRX_TEMP_SLOPE, + SSB_SPROM8_OPT_CORRX_TEMP_SLOPE_SHIFT); + SPEX(tempcorrx, SSB_SPROM8_OPT_CORRX, SSB_SPROM8_OPT_CORRX_TEMPCORRX, + SSB_SPROM8_OPT_CORRX_TEMPCORRX_SHIFT); + SPEX(tempsense_option, SSB_SPROM8_OPT_CORRX, + SSB_SPROM8_OPT_CORRX_TEMP_OPTION, + SSB_SPROM8_OPT_CORRX_TEMP_OPTION_SHIFT); + SPEX(freqoffset_corr, SSB_SPROM8_HWIQ_IQSWP, + SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR, + SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR_SHIFT); + SPEX(iqcal_swp_dis, SSB_SPROM8_HWIQ_IQSWP, + SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP, + SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP_SHIFT); + SPEX(hw_iqcal_en, SSB_SPROM8_HWIQ_IQSWP, SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL, + SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL_SHIFT); + + SPEX(bw40po, SSB_SPROM8_BW40PO, ~0, 0); + SPEX(cddpo, SSB_SPROM8_CDDPO, ~0, 0); + SPEX(stbcpo, SSB_SPROM8_STBCPO, ~0, 0); + SPEX(bwduppo, SSB_SPROM8_BWDUPPO, ~0, 0); + + SPEX(tempthresh, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_TRESH, + SSB_SPROM8_THERMAL_TRESH_SHIFT); + SPEX(tempoffset, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_OFFSET, + SSB_SPROM8_THERMAL_OFFSET_SHIFT); + SPEX(phycal_tempdelta, SSB_SPROM8_TEMPDELTA, + SSB_SPROM8_TEMPDELTA_PHYCAL, + SSB_SPROM8_TEMPDELTA_PHYCAL_SHIFT); + SPEX(temps_period, SSB_SPROM8_TEMPDELTA, SSB_SPROM8_TEMPDELTA_PERIOD, + SSB_SPROM8_TEMPDELTA_PERIOD_SHIFT); + SPEX(temps_hysteresis, SSB_SPROM8_TEMPDELTA, + SSB_SPROM8_TEMPDELTA_HYSTERESIS, + SSB_SPROM8_TEMPDELTA_HYSTERESIS_SHIFT); } /* @@ -321,11 +470,11 @@ static bool bcma_sprom_ext_available(struct bcma_bus *bus) /* older chipcommon revisions use chip status register */ chip_status = bcma_read32(bus->drv_cc.core, BCMA_CC_CHIPSTAT); switch (bus->chipinfo.id) { - case 0x4313: + case BCMA_CHIP_ID_BCM4313: present_mask = BCMA_CC_CHIPST_4313_SPROM_PRESENT; break; - case 0x4331: + case BCMA_CHIP_ID_BCM4331: present_mask = BCMA_CC_CHIPST_4331_SPROM_PRESENT; break; @@ -347,20 +496,24 @@ static bool bcma_sprom_onchip_available(struct bcma_bus *bus) chip_status = bcma_read32(bus->drv_cc.core, BCMA_CC_CHIPSTAT); switch (bus->chipinfo.id) { - case 0x4313: + case BCMA_CHIP_ID_BCM4313: present = chip_status & BCMA_CC_CHIPST_4313_OTP_PRESENT; break; - case 0x4331: + case BCMA_CHIP_ID_BCM4331: present = chip_status & BCMA_CC_CHIPST_4331_OTP_PRESENT; break; - - case 43224: - case 43225: + case BCMA_CHIP_ID_BCM43142: + case BCMA_CHIP_ID_BCM43224: + case BCMA_CHIP_ID_BCM43225: /* for these chips OTP is always available */ present = true; break; - + case BCMA_CHIP_ID_BCM43227: + case BCMA_CHIP_ID_BCM43228: + case BCMA_CHIP_ID_BCM43428: + present = chip_status & BCMA_CC_CHIPST_43228_OTP_PRESENT; + break; default: present = false; break; @@ -398,22 +551,27 @@ int bcma_sprom_get(struct bcma_bus *bus) { u16 offset = BCMA_CC_SPROM; u16 *sprom; - int err = 0; + size_t sprom_sizes[] = { SSB_SPROMSIZE_WORDS_R4, + SSB_SPROMSIZE_WORDS_R10, }; + int i, err = 0; if (!bus->drv_cc.core) return -EOPNOTSUPP; if (!bcma_sprom_ext_available(bus)) { + bool sprom_onchip; + /* * External SPROM takes precedence so check * on-chip OTP only when no external SPROM * is present. */ - if (bcma_sprom_onchip_available(bus)) { + sprom_onchip = bcma_sprom_onchip_available(bus); + if (sprom_onchip) { /* determine offset */ offset = bcma_sprom_onchip_offset(bus); } - if (!offset) { + if (!offset || !sprom_onchip) { /* * Maybe there is no SPROM on the device? * Now we ask the arch code if there is some sprom @@ -424,27 +582,37 @@ int bcma_sprom_get(struct bcma_bus *bus) } } - sprom = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16), - GFP_KERNEL); - if (!sprom) - return -ENOMEM; - - if (bus->chipinfo.id == 0x4331) + if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4331 || + bus->chipinfo.id == BCMA_CHIP_ID_BCM43431) bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, false); - pr_debug("SPROM offset 0x%x\n", offset); - bcma_sprom_read(bus, offset, sprom); + bcma_debug(bus, "SPROM offset 0x%x\n", offset); + for (i = 0; i < ARRAY_SIZE(sprom_sizes); i++) { + size_t words = sprom_sizes[i]; - if (bus->chipinfo.id == 0x4331) - bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true); + sprom = kcalloc(words, sizeof(u16), GFP_KERNEL); + if (!sprom) + return -ENOMEM; - err = bcma_sprom_valid(sprom); - if (err) - goto out; + bcma_sprom_read(bus, offset, sprom, words); + err = bcma_sprom_valid(bus, sprom, words); + if (!err) + break; + + kfree(sprom); + } + + if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4331 || + bus->chipinfo.id == BCMA_CHIP_ID_BCM43431) + bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true); - bcma_sprom_extract_r8(bus, sprom); + if (err) { + bcma_warn(bus, "Invalid SPROM read from the PCIe card, trying to use fallback SPROM\n"); + err = bcma_fill_sprom_with_fallback(bus, &bus->sprom); + } else { + bcma_sprom_extract_r8(bus, sprom); + kfree(sprom); + } -out: - kfree(sprom); return err; } |
