Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Broadcom specific AMBA
0003  * SPROM reading
0004  *
0005  * Copyright 2011, 2012, Hauke Mehrtens <hauke@hauke-m.de>
0006  *
0007  * Licensed under the GNU/GPL. See COPYING for details.
0008  */
0009 
0010 #include "bcma_private.h"
0011 
0012 #include <linux/bcma/bcma.h>
0013 #include <linux/bcma/bcma_regs.h>
0014 #include <linux/pci.h>
0015 #include <linux/io.h>
0016 #include <linux/dma-mapping.h>
0017 #include <linux/slab.h>
0018 
0019 static int(*get_fallback_sprom)(struct bcma_bus *dev, struct ssb_sprom *out);
0020 
0021 /**
0022  * bcma_arch_register_fallback_sprom - Registers a method providing a
0023  * fallback SPROM if no SPROM is found.
0024  *
0025  * @sprom_callback: The callback function.
0026  *
0027  * With this function the architecture implementation may register a
0028  * callback handler which fills the SPROM data structure. The fallback is
0029  * used for PCI based BCMA devices, where no valid SPROM can be found
0030  * in the shadow registers and to provide the SPROM for SoCs where BCMA is
0031  * to control the system bus.
0032  *
0033  * This function is useful for weird architectures that have a half-assed
0034  * BCMA device hardwired to their PCI bus.
0035  *
0036  * This function is available for architecture code, only. So it is not
0037  * exported.
0038  */
0039 int bcma_arch_register_fallback_sprom(int (*sprom_callback)(struct bcma_bus *bus,
0040                      struct ssb_sprom *out))
0041 {
0042     if (get_fallback_sprom)
0043         return -EEXIST;
0044     get_fallback_sprom = sprom_callback;
0045 
0046     return 0;
0047 }
0048 
0049 static int bcma_fill_sprom_with_fallback(struct bcma_bus *bus,
0050                      struct ssb_sprom *out)
0051 {
0052     int err;
0053 
0054     if (!get_fallback_sprom) {
0055         err = -ENOENT;
0056         goto fail;
0057     }
0058 
0059     err = get_fallback_sprom(bus, out);
0060     if (err)
0061         goto fail;
0062 
0063     bcma_debug(bus, "Using SPROM revision %d provided by platform.\n",
0064            bus->sprom.revision);
0065     return 0;
0066 fail:
0067     bcma_warn(bus, "Using fallback SPROM failed (err %d)\n", err);
0068     return err;
0069 }
0070 
0071 /**************************************************
0072  * R/W ops.
0073  **************************************************/
0074 
0075 static void bcma_sprom_read(struct bcma_bus *bus, u16 offset, u16 *sprom,
0076                 size_t words)
0077 {
0078     int i;
0079     for (i = 0; i < words; i++)
0080         sprom[i] = bcma_read16(bus->drv_cc.core, offset + (i * 2));
0081 }
0082 
0083 /**************************************************
0084  * Validation.
0085  **************************************************/
0086 
0087 static inline u8 bcma_crc8(u8 crc, u8 data)
0088 {
0089     /* Polynomial:   x^8 + x^7 + x^6 + x^4 + x^2 + 1   */
0090     static const u8 t[] = {
0091         0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
0092         0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
0093         0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
0094         0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
0095         0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
0096         0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
0097         0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
0098         0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
0099         0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
0100         0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
0101         0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
0102         0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
0103         0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
0104         0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
0105         0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
0106         0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
0107         0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
0108         0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
0109         0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
0110         0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
0111         0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
0112         0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
0113         0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
0114         0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
0115         0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
0116         0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
0117         0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
0118         0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
0119         0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
0120         0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
0121         0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
0122         0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F,
0123     };
0124     return t[crc ^ data];
0125 }
0126 
0127 static u8 bcma_sprom_crc(const u16 *sprom, size_t words)
0128 {
0129     int word;
0130     u8 crc = 0xFF;
0131 
0132     for (word = 0; word < words - 1; word++) {
0133         crc = bcma_crc8(crc, sprom[word] & 0x00FF);
0134         crc = bcma_crc8(crc, (sprom[word] & 0xFF00) >> 8);
0135     }
0136     crc = bcma_crc8(crc, sprom[words - 1] & 0x00FF);
0137     crc ^= 0xFF;
0138 
0139     return crc;
0140 }
0141 
0142 static int bcma_sprom_check_crc(const u16 *sprom, size_t words)
0143 {
0144     u8 crc;
0145     u8 expected_crc;
0146     u16 tmp;
0147 
0148     crc = bcma_sprom_crc(sprom, words);
0149     tmp = sprom[words - 1] & SSB_SPROM_REVISION_CRC;
0150     expected_crc = tmp >> SSB_SPROM_REVISION_CRC_SHIFT;
0151     if (crc != expected_crc)
0152         return -EPROTO;
0153 
0154     return 0;
0155 }
0156 
0157 static int bcma_sprom_valid(struct bcma_bus *bus, const u16 *sprom,
0158                 size_t words)
0159 {
0160     u16 revision;
0161     int err;
0162 
0163     err = bcma_sprom_check_crc(sprom, words);
0164     if (err)
0165         return err;
0166 
0167     revision = sprom[words - 1] & SSB_SPROM_REVISION_REV;
0168     if (revision != 8 && revision != 9 && revision != 10) {
0169         pr_err("Unsupported SPROM revision: %d\n", revision);
0170         return -ENOENT;
0171     }
0172 
0173     bus->sprom.revision = revision;
0174     bcma_debug(bus, "Found SPROM revision %d\n", revision);
0175 
0176     return 0;
0177 }
0178 
0179 /**************************************************
0180  * SPROM extraction.
0181  **************************************************/
0182 
0183 #define SPOFF(offset)   ((offset) / sizeof(u16))
0184 
0185 #define SPEX(_field, _offset, _mask, _shift)    \
0186     bus->sprom._field = ((sprom[SPOFF(_offset)] & (_mask)) >> (_shift))
0187 
0188 #define SPEX32(_field, _offset, _mask, _shift)  \
0189     bus->sprom._field = ((((u32)sprom[SPOFF((_offset)+2)] << 16 | \
0190                 sprom[SPOFF(_offset)]) & (_mask)) >> (_shift))
0191 
0192 #define SPEX_ARRAY8(_field, _offset, _mask, _shift) \
0193     do {    \
0194         SPEX(_field[0], _offset +  0, _mask, _shift);   \
0195         SPEX(_field[1], _offset +  2, _mask, _shift);   \
0196         SPEX(_field[2], _offset +  4, _mask, _shift);   \
0197         SPEX(_field[3], _offset +  6, _mask, _shift);   \
0198         SPEX(_field[4], _offset +  8, _mask, _shift);   \
0199         SPEX(_field[5], _offset + 10, _mask, _shift);   \
0200         SPEX(_field[6], _offset + 12, _mask, _shift);   \
0201         SPEX(_field[7], _offset + 14, _mask, _shift);   \
0202     } while (0)
0203 
0204 static s8 sprom_extract_antgain(const u16 *in, u16 offset, u16 mask, u16 shift)
0205 {
0206     u16 v;
0207     u8 gain;
0208 
0209     v = in[SPOFF(offset)];
0210     gain = (v & mask) >> shift;
0211     if (gain == 0xFF) {
0212         gain = 8; /* If unset use 2dBm */
0213     } else {
0214         /* Q5.2 Fractional part is stored in 0xC0 */
0215         gain = ((gain & 0xC0) >> 6) | ((gain & 0x3F) << 2);
0216     }
0217 
0218     return (s8)gain;
0219 }
0220 
0221 static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom)
0222 {
0223     u16 v, o;
0224     int i;
0225     static const u16 pwr_info_offset[] = {
0226         SSB_SROM8_PWR_INFO_CORE0, SSB_SROM8_PWR_INFO_CORE1,
0227         SSB_SROM8_PWR_INFO_CORE2, SSB_SROM8_PWR_INFO_CORE3
0228     };
0229     BUILD_BUG_ON(ARRAY_SIZE(pwr_info_offset) !=
0230             ARRAY_SIZE(bus->sprom.core_pwr_info));
0231 
0232     for (i = 0; i < 3; i++) {
0233         v = sprom[SPOFF(SSB_SPROM8_IL0MAC) + i];
0234         *(((__be16 *)bus->sprom.il0mac) + i) = cpu_to_be16(v);
0235     }
0236 
0237     SPEX(board_rev, SSB_SPROM8_BOARDREV, ~0, 0);
0238     SPEX(board_type, SSB_SPROM1_SPID, ~0, 0);
0239 
0240     SPEX(txpid2g[0], SSB_SPROM4_TXPID2G01, SSB_SPROM4_TXPID2G0,
0241          SSB_SPROM4_TXPID2G0_SHIFT);
0242     SPEX(txpid2g[1], SSB_SPROM4_TXPID2G01, SSB_SPROM4_TXPID2G1,
0243          SSB_SPROM4_TXPID2G1_SHIFT);
0244     SPEX(txpid2g[2], SSB_SPROM4_TXPID2G23, SSB_SPROM4_TXPID2G2,
0245          SSB_SPROM4_TXPID2G2_SHIFT);
0246     SPEX(txpid2g[3], SSB_SPROM4_TXPID2G23, SSB_SPROM4_TXPID2G3,
0247          SSB_SPROM4_TXPID2G3_SHIFT);
0248 
0249     SPEX(txpid5gl[0], SSB_SPROM4_TXPID5GL01, SSB_SPROM4_TXPID5GL0,
0250          SSB_SPROM4_TXPID5GL0_SHIFT);
0251     SPEX(txpid5gl[1], SSB_SPROM4_TXPID5GL01, SSB_SPROM4_TXPID5GL1,
0252          SSB_SPROM4_TXPID5GL1_SHIFT);
0253     SPEX(txpid5gl[2], SSB_SPROM4_TXPID5GL23, SSB_SPROM4_TXPID5GL2,
0254          SSB_SPROM4_TXPID5GL2_SHIFT);
0255     SPEX(txpid5gl[3], SSB_SPROM4_TXPID5GL23, SSB_SPROM4_TXPID5GL3,
0256          SSB_SPROM4_TXPID5GL3_SHIFT);
0257 
0258     SPEX(txpid5g[0], SSB_SPROM4_TXPID5G01, SSB_SPROM4_TXPID5G0,
0259          SSB_SPROM4_TXPID5G0_SHIFT);
0260     SPEX(txpid5g[1], SSB_SPROM4_TXPID5G01, SSB_SPROM4_TXPID5G1,
0261          SSB_SPROM4_TXPID5G1_SHIFT);
0262     SPEX(txpid5g[2], SSB_SPROM4_TXPID5G23, SSB_SPROM4_TXPID5G2,
0263          SSB_SPROM4_TXPID5G2_SHIFT);
0264     SPEX(txpid5g[3], SSB_SPROM4_TXPID5G23, SSB_SPROM4_TXPID5G3,
0265          SSB_SPROM4_TXPID5G3_SHIFT);
0266 
0267     SPEX(txpid5gh[0], SSB_SPROM4_TXPID5GH01, SSB_SPROM4_TXPID5GH0,
0268          SSB_SPROM4_TXPID5GH0_SHIFT);
0269     SPEX(txpid5gh[1], SSB_SPROM4_TXPID5GH01, SSB_SPROM4_TXPID5GH1,
0270          SSB_SPROM4_TXPID5GH1_SHIFT);
0271     SPEX(txpid5gh[2], SSB_SPROM4_TXPID5GH23, SSB_SPROM4_TXPID5GH2,
0272          SSB_SPROM4_TXPID5GH2_SHIFT);
0273     SPEX(txpid5gh[3], SSB_SPROM4_TXPID5GH23, SSB_SPROM4_TXPID5GH3,
0274          SSB_SPROM4_TXPID5GH3_SHIFT);
0275 
0276     SPEX(boardflags_lo, SSB_SPROM8_BFLLO, ~0, 0);
0277     SPEX(boardflags_hi, SSB_SPROM8_BFLHI, ~0, 0);
0278     SPEX(boardflags2_lo, SSB_SPROM8_BFL2LO, ~0, 0);
0279     SPEX(boardflags2_hi, SSB_SPROM8_BFL2HI, ~0, 0);
0280 
0281     SPEX(alpha2[0], SSB_SPROM8_CCODE, 0xff00, 8);
0282     SPEX(alpha2[1], SSB_SPROM8_CCODE, 0x00ff, 0);
0283 
0284     /* Extract core's power info */
0285     for (i = 0; i < ARRAY_SIZE(pwr_info_offset); i++) {
0286         o = pwr_info_offset[i];
0287         SPEX(core_pwr_info[i].itssi_2g, o + SSB_SROM8_2G_MAXP_ITSSI,
0288             SSB_SPROM8_2G_ITSSI, SSB_SPROM8_2G_ITSSI_SHIFT);
0289         SPEX(core_pwr_info[i].maxpwr_2g, o + SSB_SROM8_2G_MAXP_ITSSI,
0290             SSB_SPROM8_2G_MAXP, 0);
0291 
0292         SPEX(core_pwr_info[i].pa_2g[0], o + SSB_SROM8_2G_PA_0, ~0, 0);
0293         SPEX(core_pwr_info[i].pa_2g[1], o + SSB_SROM8_2G_PA_1, ~0, 0);
0294         SPEX(core_pwr_info[i].pa_2g[2], o + SSB_SROM8_2G_PA_2, ~0, 0);
0295 
0296         SPEX(core_pwr_info[i].itssi_5g, o + SSB_SROM8_5G_MAXP_ITSSI,
0297             SSB_SPROM8_5G_ITSSI, SSB_SPROM8_5G_ITSSI_SHIFT);
0298         SPEX(core_pwr_info[i].maxpwr_5g, o + SSB_SROM8_5G_MAXP_ITSSI,
0299             SSB_SPROM8_5G_MAXP, 0);
0300         SPEX(core_pwr_info[i].maxpwr_5gh, o + SSB_SPROM8_5GHL_MAXP,
0301             SSB_SPROM8_5GH_MAXP, 0);
0302         SPEX(core_pwr_info[i].maxpwr_5gl, o + SSB_SPROM8_5GHL_MAXP,
0303             SSB_SPROM8_5GL_MAXP, SSB_SPROM8_5GL_MAXP_SHIFT);
0304 
0305         SPEX(core_pwr_info[i].pa_5gl[0], o + SSB_SROM8_5GL_PA_0, ~0, 0);
0306         SPEX(core_pwr_info[i].pa_5gl[1], o + SSB_SROM8_5GL_PA_1, ~0, 0);
0307         SPEX(core_pwr_info[i].pa_5gl[2], o + SSB_SROM8_5GL_PA_2, ~0, 0);
0308         SPEX(core_pwr_info[i].pa_5g[0], o + SSB_SROM8_5G_PA_0, ~0, 0);
0309         SPEX(core_pwr_info[i].pa_5g[1], o + SSB_SROM8_5G_PA_1, ~0, 0);
0310         SPEX(core_pwr_info[i].pa_5g[2], o + SSB_SROM8_5G_PA_2, ~0, 0);
0311         SPEX(core_pwr_info[i].pa_5gh[0], o + SSB_SROM8_5GH_PA_0, ~0, 0);
0312         SPEX(core_pwr_info[i].pa_5gh[1], o + SSB_SROM8_5GH_PA_1, ~0, 0);
0313         SPEX(core_pwr_info[i].pa_5gh[2], o + SSB_SROM8_5GH_PA_2, ~0, 0);
0314     }
0315 
0316     SPEX(fem.ghz2.tssipos, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_TSSIPOS,
0317          SSB_SROM8_FEM_TSSIPOS_SHIFT);
0318     SPEX(fem.ghz2.extpa_gain, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_EXTPA_GAIN,
0319          SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
0320     SPEX(fem.ghz2.pdet_range, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_PDET_RANGE,
0321          SSB_SROM8_FEM_PDET_RANGE_SHIFT);
0322     SPEX(fem.ghz2.tr_iso, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_TR_ISO,
0323          SSB_SROM8_FEM_TR_ISO_SHIFT);
0324     SPEX(fem.ghz2.antswlut, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_ANTSWLUT,
0325          SSB_SROM8_FEM_ANTSWLUT_SHIFT);
0326 
0327     SPEX(fem.ghz5.tssipos, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_TSSIPOS,
0328          SSB_SROM8_FEM_TSSIPOS_SHIFT);
0329     SPEX(fem.ghz5.extpa_gain, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_EXTPA_GAIN,
0330          SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
0331     SPEX(fem.ghz5.pdet_range, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_PDET_RANGE,
0332          SSB_SROM8_FEM_PDET_RANGE_SHIFT);
0333     SPEX(fem.ghz5.tr_iso, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_TR_ISO,
0334          SSB_SROM8_FEM_TR_ISO_SHIFT);
0335     SPEX(fem.ghz5.antswlut, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_ANTSWLUT,
0336          SSB_SROM8_FEM_ANTSWLUT_SHIFT);
0337 
0338     SPEX(ant_available_a, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_A,
0339          SSB_SPROM8_ANTAVAIL_A_SHIFT);
0340     SPEX(ant_available_bg, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_BG,
0341          SSB_SPROM8_ANTAVAIL_BG_SHIFT);
0342     SPEX(maxpwr_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_MAXP_BG_MASK, 0);
0343     SPEX(itssi_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_ITSSI_BG,
0344          SSB_SPROM8_ITSSI_BG_SHIFT);
0345     SPEX(maxpwr_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_MAXP_A_MASK, 0);
0346     SPEX(itssi_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_ITSSI_A,
0347          SSB_SPROM8_ITSSI_A_SHIFT);
0348     SPEX(maxpwr_ah, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AH_MASK, 0);
0349     SPEX(maxpwr_al, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AL_MASK,
0350          SSB_SPROM8_MAXP_AL_SHIFT);
0351     SPEX(gpio0, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P0, 0);
0352     SPEX(gpio1, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P1,
0353          SSB_SPROM8_GPIOA_P1_SHIFT);
0354     SPEX(gpio2, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P2, 0);
0355     SPEX(gpio3, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P3,
0356          SSB_SPROM8_GPIOB_P3_SHIFT);
0357     SPEX(tri2g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI2G, 0);
0358     SPEX(tri5g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI5G,
0359          SSB_SPROM8_TRI5G_SHIFT);
0360     SPEX(tri5gl, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GL, 0);
0361     SPEX(tri5gh, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GH,
0362          SSB_SPROM8_TRI5GH_SHIFT);
0363     SPEX(rxpo2g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO2G,
0364          SSB_SPROM8_RXPO2G_SHIFT);
0365     SPEX(rxpo5g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO5G,
0366          SSB_SPROM8_RXPO5G_SHIFT);
0367     SPEX(rssismf2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMF2G, 0);
0368     SPEX(rssismc2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMC2G,
0369          SSB_SPROM8_RSSISMC2G_SHIFT);
0370     SPEX(rssisav2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISAV2G,
0371          SSB_SPROM8_RSSISAV2G_SHIFT);
0372     SPEX(bxa2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_BXA2G,
0373          SSB_SPROM8_BXA2G_SHIFT);
0374     SPEX(rssismf5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMF5G, 0);
0375     SPEX(rssismc5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMC5G,
0376          SSB_SPROM8_RSSISMC5G_SHIFT);
0377     SPEX(rssisav5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISAV5G,
0378          SSB_SPROM8_RSSISAV5G_SHIFT);
0379     SPEX(bxa5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_BXA5G,
0380          SSB_SPROM8_BXA5G_SHIFT);
0381 
0382     SPEX(pa0b0, SSB_SPROM8_PA0B0, ~0, 0);
0383     SPEX(pa0b1, SSB_SPROM8_PA0B1, ~0, 0);
0384     SPEX(pa0b2, SSB_SPROM8_PA0B2, ~0, 0);
0385     SPEX(pa1b0, SSB_SPROM8_PA1B0, ~0, 0);
0386     SPEX(pa1b1, SSB_SPROM8_PA1B1, ~0, 0);
0387     SPEX(pa1b2, SSB_SPROM8_PA1B2, ~0, 0);
0388     SPEX(pa1lob0, SSB_SPROM8_PA1LOB0, ~0, 0);
0389     SPEX(pa1lob1, SSB_SPROM8_PA1LOB1, ~0, 0);
0390     SPEX(pa1lob2, SSB_SPROM8_PA1LOB2, ~0, 0);
0391     SPEX(pa1hib0, SSB_SPROM8_PA1HIB0, ~0, 0);
0392     SPEX(pa1hib1, SSB_SPROM8_PA1HIB1, ~0, 0);
0393     SPEX(pa1hib2, SSB_SPROM8_PA1HIB2, ~0, 0);
0394     SPEX(cck2gpo, SSB_SPROM8_CCK2GPO, ~0, 0);
0395     SPEX32(ofdm2gpo, SSB_SPROM8_OFDM2GPO, ~0, 0);
0396     SPEX32(ofdm5glpo, SSB_SPROM8_OFDM5GLPO, ~0, 0);
0397     SPEX32(ofdm5gpo, SSB_SPROM8_OFDM5GPO, ~0, 0);
0398     SPEX32(ofdm5ghpo, SSB_SPROM8_OFDM5GHPO, ~0, 0);
0399 
0400     /* Extract the antenna gain values. */
0401     bus->sprom.antenna_gain.a0 = sprom_extract_antgain(sprom,
0402                                SSB_SPROM8_AGAIN01,
0403                                SSB_SPROM8_AGAIN0,
0404                                SSB_SPROM8_AGAIN0_SHIFT);
0405     bus->sprom.antenna_gain.a1 = sprom_extract_antgain(sprom,
0406                                SSB_SPROM8_AGAIN01,
0407                                SSB_SPROM8_AGAIN1,
0408                                SSB_SPROM8_AGAIN1_SHIFT);
0409     bus->sprom.antenna_gain.a2 = sprom_extract_antgain(sprom,
0410                                SSB_SPROM8_AGAIN23,
0411                                SSB_SPROM8_AGAIN2,
0412                                SSB_SPROM8_AGAIN2_SHIFT);
0413     bus->sprom.antenna_gain.a3 = sprom_extract_antgain(sprom,
0414                                SSB_SPROM8_AGAIN23,
0415                                SSB_SPROM8_AGAIN3,
0416                                SSB_SPROM8_AGAIN3_SHIFT);
0417 
0418     SPEX(leddc_on_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_ON,
0419          SSB_SPROM8_LEDDC_ON_SHIFT);
0420     SPEX(leddc_off_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_OFF,
0421          SSB_SPROM8_LEDDC_OFF_SHIFT);
0422 
0423     SPEX(txchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_TXCHAIN,
0424          SSB_SPROM8_TXRXC_TXCHAIN_SHIFT);
0425     SPEX(rxchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_RXCHAIN,
0426          SSB_SPROM8_TXRXC_RXCHAIN_SHIFT);
0427     SPEX(antswitch, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_SWITCH,
0428          SSB_SPROM8_TXRXC_SWITCH_SHIFT);
0429 
0430     SPEX(opo, SSB_SPROM8_OFDM2GPO, 0x00ff, 0);
0431 
0432     SPEX_ARRAY8(mcs2gpo, SSB_SPROM8_2G_MCSPO, ~0, 0);
0433     SPEX_ARRAY8(mcs5gpo, SSB_SPROM8_5G_MCSPO, ~0, 0);
0434     SPEX_ARRAY8(mcs5glpo, SSB_SPROM8_5GL_MCSPO, ~0, 0);
0435     SPEX_ARRAY8(mcs5ghpo, SSB_SPROM8_5GH_MCSPO, ~0, 0);
0436 
0437     SPEX(rawtempsense, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_RAWTEMP,
0438          SSB_SPROM8_RAWTS_RAWTEMP_SHIFT);
0439     SPEX(measpower, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_MEASPOWER,
0440          SSB_SPROM8_RAWTS_MEASPOWER_SHIFT);
0441     SPEX(tempsense_slope, SSB_SPROM8_OPT_CORRX,
0442          SSB_SPROM8_OPT_CORRX_TEMP_SLOPE,
0443          SSB_SPROM8_OPT_CORRX_TEMP_SLOPE_SHIFT);
0444     SPEX(tempcorrx, SSB_SPROM8_OPT_CORRX, SSB_SPROM8_OPT_CORRX_TEMPCORRX,
0445          SSB_SPROM8_OPT_CORRX_TEMPCORRX_SHIFT);
0446     SPEX(tempsense_option, SSB_SPROM8_OPT_CORRX,
0447          SSB_SPROM8_OPT_CORRX_TEMP_OPTION,
0448          SSB_SPROM8_OPT_CORRX_TEMP_OPTION_SHIFT);
0449     SPEX(freqoffset_corr, SSB_SPROM8_HWIQ_IQSWP,
0450          SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR,
0451          SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR_SHIFT);
0452     SPEX(iqcal_swp_dis, SSB_SPROM8_HWIQ_IQSWP,
0453          SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP,
0454          SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP_SHIFT);
0455     SPEX(hw_iqcal_en, SSB_SPROM8_HWIQ_IQSWP, SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL,
0456          SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL_SHIFT);
0457 
0458     SPEX(bw40po, SSB_SPROM8_BW40PO, ~0, 0);
0459     SPEX(cddpo, SSB_SPROM8_CDDPO, ~0, 0);
0460     SPEX(stbcpo, SSB_SPROM8_STBCPO, ~0, 0);
0461     SPEX(bwduppo, SSB_SPROM8_BWDUPPO, ~0, 0);
0462 
0463     SPEX(tempthresh, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_TRESH,
0464          SSB_SPROM8_THERMAL_TRESH_SHIFT);
0465     SPEX(tempoffset, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_OFFSET,
0466          SSB_SPROM8_THERMAL_OFFSET_SHIFT);
0467     SPEX(phycal_tempdelta, SSB_SPROM8_TEMPDELTA,
0468          SSB_SPROM8_TEMPDELTA_PHYCAL,
0469          SSB_SPROM8_TEMPDELTA_PHYCAL_SHIFT);
0470     SPEX(temps_period, SSB_SPROM8_TEMPDELTA, SSB_SPROM8_TEMPDELTA_PERIOD,
0471          SSB_SPROM8_TEMPDELTA_PERIOD_SHIFT);
0472     SPEX(temps_hysteresis, SSB_SPROM8_TEMPDELTA,
0473          SSB_SPROM8_TEMPDELTA_HYSTERESIS,
0474          SSB_SPROM8_TEMPDELTA_HYSTERESIS_SHIFT);
0475 }
0476 
0477 /*
0478  * Indicates the presence of external SPROM.
0479  */
0480 static bool bcma_sprom_ext_available(struct bcma_bus *bus)
0481 {
0482     u32 chip_status;
0483     u32 srom_control;
0484     u32 present_mask;
0485 
0486     if (bus->drv_cc.core->id.rev >= 31) {
0487         if (!(bus->drv_cc.capabilities & BCMA_CC_CAP_SPROM))
0488             return false;
0489 
0490         srom_control = bcma_read32(bus->drv_cc.core,
0491                        BCMA_CC_SROM_CONTROL);
0492         return srom_control & BCMA_CC_SROM_CONTROL_PRESENT;
0493     }
0494 
0495     /* older chipcommon revisions use chip status register */
0496     chip_status = bcma_read32(bus->drv_cc.core, BCMA_CC_CHIPSTAT);
0497     switch (bus->chipinfo.id) {
0498     case BCMA_CHIP_ID_BCM4313:
0499         present_mask = BCMA_CC_CHIPST_4313_SPROM_PRESENT;
0500         break;
0501 
0502     case BCMA_CHIP_ID_BCM4331:
0503         present_mask = BCMA_CC_CHIPST_4331_SPROM_PRESENT;
0504         break;
0505 
0506     default:
0507         return true;
0508     }
0509 
0510     return chip_status & present_mask;
0511 }
0512 
0513 /*
0514  * Indicates that on-chip OTP memory is present and enabled.
0515  */
0516 static bool bcma_sprom_onchip_available(struct bcma_bus *bus)
0517 {
0518     u32 chip_status;
0519     u32 otpsize = 0;
0520     bool present;
0521 
0522     chip_status = bcma_read32(bus->drv_cc.core, BCMA_CC_CHIPSTAT);
0523     switch (bus->chipinfo.id) {
0524     case BCMA_CHIP_ID_BCM4313:
0525         present = chip_status & BCMA_CC_CHIPST_4313_OTP_PRESENT;
0526         break;
0527 
0528     case BCMA_CHIP_ID_BCM4331:
0529         present = chip_status & BCMA_CC_CHIPST_4331_OTP_PRESENT;
0530         break;
0531     case BCMA_CHIP_ID_BCM43142:
0532     case BCMA_CHIP_ID_BCM43224:
0533     case BCMA_CHIP_ID_BCM43225:
0534         /* for these chips OTP is always available */
0535         present = true;
0536         break;
0537     case BCMA_CHIP_ID_BCM43131:
0538     case BCMA_CHIP_ID_BCM43217:
0539     case BCMA_CHIP_ID_BCM43227:
0540     case BCMA_CHIP_ID_BCM43228:
0541     case BCMA_CHIP_ID_BCM43428:
0542         present = chip_status & BCMA_CC_CHIPST_43228_OTP_PRESENT;
0543         break;
0544     default:
0545         present = false;
0546         break;
0547     }
0548 
0549     if (present) {
0550         otpsize = bus->drv_cc.capabilities & BCMA_CC_CAP_OTPS;
0551         otpsize >>= BCMA_CC_CAP_OTPS_SHIFT;
0552     }
0553 
0554     return otpsize != 0;
0555 }
0556 
0557 /*
0558  * Verify OTP is filled and determine the byte
0559  * offset where SPROM data is located.
0560  *
0561  * On error, returns 0; byte offset otherwise.
0562  */
0563 static int bcma_sprom_onchip_offset(struct bcma_bus *bus)
0564 {
0565     struct bcma_device *cc = bus->drv_cc.core;
0566     u32 offset;
0567 
0568     /* verify OTP status */
0569     if ((bcma_read32(cc, BCMA_CC_OTPS) & BCMA_CC_OTPS_GU_PROG_HW) == 0)
0570         return 0;
0571 
0572     /* obtain bit offset from otplayout register */
0573     offset = (bcma_read32(cc, BCMA_CC_OTPL) & BCMA_CC_OTPL_GURGN_OFFSET);
0574     return BCMA_CC_SPROM + (offset >> 3);
0575 }
0576 
0577 int bcma_sprom_get(struct bcma_bus *bus)
0578 {
0579     u16 offset = BCMA_CC_SPROM;
0580     u16 *sprom;
0581     static const size_t sprom_sizes[] = {
0582         SSB_SPROMSIZE_WORDS_R4,
0583         SSB_SPROMSIZE_WORDS_R10,
0584         SSB_SPROMSIZE_WORDS_R11,
0585     };
0586     int i, err = 0;
0587 
0588     if (!bus->drv_cc.core)
0589         return -EOPNOTSUPP;
0590 
0591     if (!bcma_sprom_ext_available(bus)) {
0592         bool sprom_onchip;
0593 
0594         /*
0595          * External SPROM takes precedence so check
0596          * on-chip OTP only when no external SPROM
0597          * is present.
0598          */
0599         sprom_onchip = bcma_sprom_onchip_available(bus);
0600         if (sprom_onchip) {
0601             /* determine offset */
0602             offset = bcma_sprom_onchip_offset(bus);
0603         }
0604         if (!offset || !sprom_onchip) {
0605             /*
0606              * Maybe there is no SPROM on the device?
0607              * Now we ask the arch code if there is some sprom
0608              * available for this device in some other storage.
0609              */
0610             err = bcma_fill_sprom_with_fallback(bus, &bus->sprom);
0611             return err;
0612         }
0613     }
0614 
0615     if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4331 ||
0616         bus->chipinfo.id == BCMA_CHIP_ID_BCM43431)
0617         bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, false);
0618 
0619     bcma_debug(bus, "SPROM offset 0x%x\n", offset);
0620     for (i = 0; i < ARRAY_SIZE(sprom_sizes); i++) {
0621         size_t words = sprom_sizes[i];
0622 
0623         sprom = kcalloc(words, sizeof(u16), GFP_KERNEL);
0624         if (!sprom)
0625             return -ENOMEM;
0626 
0627         bcma_sprom_read(bus, offset, sprom, words);
0628         err = bcma_sprom_valid(bus, sprom, words);
0629         if (!err)
0630             break;
0631 
0632         kfree(sprom);
0633     }
0634 
0635     if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4331 ||
0636         bus->chipinfo.id == BCMA_CHIP_ID_BCM43431)
0637         bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true);
0638 
0639     if (err) {
0640         bcma_warn(bus, "Invalid SPROM read from the PCIe card, trying to use fallback SPROM\n");
0641         err = bcma_fill_sprom_with_fallback(bus, &bus->sprom);
0642     } else {
0643         bcma_sprom_extract_r8(bus, sprom);
0644         kfree(sprom);
0645     }
0646 
0647     return err;
0648 }