linux/drivers/bcma/sprom.c
<<
>>
Prefs
   1/*
   2 * Broadcom specific AMBA
   3 * SPROM reading
   4 *
   5 * Copyright 2011, 2012, Hauke Mehrtens <hauke@hauke-m.de>
   6 *
   7 * Licensed under the GNU/GPL. See COPYING for details.
   8 */
   9
  10#include "bcma_private.h"
  11
  12#include <linux/bcma/bcma.h>
  13#include <linux/bcma/bcma_regs.h>
  14#include <linux/pci.h>
  15#include <linux/io.h>
  16#include <linux/dma-mapping.h>
  17#include <linux/slab.h>
  18
  19static int(*get_fallback_sprom)(struct bcma_bus *dev, struct ssb_sprom *out);
  20
  21/**
  22 * bcma_arch_register_fallback_sprom - Registers a method providing a
  23 * fallback SPROM if no SPROM is found.
  24 *
  25 * @sprom_callback: The callback function.
  26 *
  27 * With this function the architecture implementation may register a
  28 * callback handler which fills the SPROM data structure. The fallback is
  29 * used for PCI based BCMA devices, where no valid SPROM can be found
  30 * in the shadow registers and to provide the SPROM for SoCs where BCMA is
  31 * to controll the system bus.
  32 *
  33 * This function is useful for weird architectures that have a half-assed
  34 * BCMA device hardwired to their PCI bus.
  35 *
  36 * This function is available for architecture code, only. So it is not
  37 * exported.
  38 */
  39int bcma_arch_register_fallback_sprom(int (*sprom_callback)(struct bcma_bus *bus,
  40                                     struct ssb_sprom *out))
  41{
  42        if (get_fallback_sprom)
  43                return -EEXIST;
  44        get_fallback_sprom = sprom_callback;
  45
  46        return 0;
  47}
  48
  49static int bcma_fill_sprom_with_fallback(struct bcma_bus *bus,
  50                                         struct ssb_sprom *out)
  51{
  52        int err;
  53
  54        if (!get_fallback_sprom) {
  55                err = -ENOENT;
  56                goto fail;
  57        }
  58
  59        err = get_fallback_sprom(bus, out);
  60        if (err)
  61                goto fail;
  62
  63        bcma_debug(bus, "Using SPROM revision %d provided by platform.\n",
  64                   bus->sprom.revision);
  65        return 0;
  66fail:
  67        bcma_warn(bus, "Using fallback SPROM failed (err %d)\n", err);
  68        return err;
  69}
  70
  71/**************************************************
  72 * R/W ops.
  73 **************************************************/
  74
  75static void bcma_sprom_read(struct bcma_bus *bus, u16 offset, u16 *sprom,
  76                            size_t words)
  77{
  78        int i;
  79        for (i = 0; i < words; i++)
  80                sprom[i] = bcma_read16(bus->drv_cc.core, offset + (i * 2));
  81}
  82
  83/**************************************************
  84 * Validation.
  85 **************************************************/
  86
  87static inline u8 bcma_crc8(u8 crc, u8 data)
  88{
  89        /* Polynomial:   x^8 + x^7 + x^6 + x^4 + x^2 + 1   */
  90        static const u8 t[] = {
  91                0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
  92                0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
  93                0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
  94                0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
  95                0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
  96                0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
  97                0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
  98                0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
  99                0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
 100                0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
 101                0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
 102                0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
 103                0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
 104                0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
 105                0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
 106                0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
 107                0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
 108                0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
 109                0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
 110                0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
 111                0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
 112                0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
 113                0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
 114                0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
 115                0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
 116                0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
 117                0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
 118                0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
 119                0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
 120                0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
 121                0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
 122                0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F,
 123        };
 124        return t[crc ^ data];
 125}
 126
 127static u8 bcma_sprom_crc(const u16 *sprom, size_t words)
 128{
 129        int word;
 130        u8 crc = 0xFF;
 131
 132        for (word = 0; word < words - 1; word++) {
 133                crc = bcma_crc8(crc, sprom[word] & 0x00FF);
 134                crc = bcma_crc8(crc, (sprom[word] & 0xFF00) >> 8);
 135        }
 136        crc = bcma_crc8(crc, sprom[words - 1] & 0x00FF);
 137        crc ^= 0xFF;
 138
 139        return crc;
 140}
 141
 142static int bcma_sprom_check_crc(const u16 *sprom, size_t words)
 143{
 144        u8 crc;
 145        u8 expected_crc;
 146        u16 tmp;
 147
 148        crc = bcma_sprom_crc(sprom, words);
 149        tmp = sprom[words - 1] & SSB_SPROM_REVISION_CRC;
 150        expected_crc = tmp >> SSB_SPROM_REVISION_CRC_SHIFT;
 151        if (crc != expected_crc)
 152                return -EPROTO;
 153
 154        return 0;
 155}
 156
 157static int bcma_sprom_valid(struct bcma_bus *bus, const u16 *sprom,
 158                            size_t words)
 159{
 160        u16 revision;
 161        int err;
 162
 163        err = bcma_sprom_check_crc(sprom, words);
 164        if (err)
 165                return err;
 166
 167        revision = sprom[words - 1] & SSB_SPROM_REVISION_REV;
 168        if (revision != 8 && revision != 9 && revision != 10) {
 169                pr_err("Unsupported SPROM revision: %d\n", revision);
 170                return -ENOENT;
 171        }
 172
 173        bus->sprom.revision = revision;
 174        bcma_debug(bus, "Found SPROM revision %d\n", revision);
 175
 176        return 0;
 177}
 178
 179/**************************************************
 180 * SPROM extraction.
 181 **************************************************/
 182
 183#define SPOFF(offset)   ((offset) / sizeof(u16))
 184
 185#define SPEX(_field, _offset, _mask, _shift)    \
 186        bus->sprom._field = ((sprom[SPOFF(_offset)] & (_mask)) >> (_shift))
 187
 188#define SPEX32(_field, _offset, _mask, _shift)  \
 189        bus->sprom._field = ((((u32)sprom[SPOFF((_offset)+2)] << 16 | \
 190                                sprom[SPOFF(_offset)]) & (_mask)) >> (_shift))
 191
 192#define SPEX_ARRAY8(_field, _offset, _mask, _shift)     \
 193        do {    \
 194                SPEX(_field[0], _offset +  0, _mask, _shift);   \
 195                SPEX(_field[1], _offset +  2, _mask, _shift);   \
 196                SPEX(_field[2], _offset +  4, _mask, _shift);   \
 197                SPEX(_field[3], _offset +  6, _mask, _shift);   \
 198                SPEX(_field[4], _offset +  8, _mask, _shift);   \
 199                SPEX(_field[5], _offset + 10, _mask, _shift);   \
 200                SPEX(_field[6], _offset + 12, _mask, _shift);   \
 201                SPEX(_field[7], _offset + 14, _mask, _shift);   \
 202        } while (0)
 203
 204static s8 sprom_extract_antgain(const u16 *in, u16 offset, u16 mask, u16 shift)
 205{
 206        u16 v;
 207        u8 gain;
 208
 209        v = in[SPOFF(offset)];
 210        gain = (v & mask) >> shift;
 211        if (gain == 0xFF) {
 212                gain = 8; /* If unset use 2dBm */
 213        } else {
 214                /* Q5.2 Fractional part is stored in 0xC0 */
 215                gain = ((gain & 0xC0) >> 6) | ((gain & 0x3F) << 2);
 216        }
 217
 218        return (s8)gain;
 219}
 220
 221static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom)
 222{
 223        u16 v, o;
 224        int i;
 225        static const u16 pwr_info_offset[] = {
 226                SSB_SROM8_PWR_INFO_CORE0, SSB_SROM8_PWR_INFO_CORE1,
 227                SSB_SROM8_PWR_INFO_CORE2, SSB_SROM8_PWR_INFO_CORE3
 228        };
 229        BUILD_BUG_ON(ARRAY_SIZE(pwr_info_offset) !=
 230                        ARRAY_SIZE(bus->sprom.core_pwr_info));
 231
 232        for (i = 0; i < 3; i++) {
 233                v = sprom[SPOFF(SSB_SPROM8_IL0MAC) + i];
 234                *(((__be16 *)bus->sprom.il0mac) + i) = cpu_to_be16(v);
 235        }
 236
 237        SPEX(board_rev, SSB_SPROM8_BOARDREV, ~0, 0);
 238        SPEX(board_type, SSB_SPROM1_SPID, ~0, 0);
 239
 240        SPEX(txpid2g[0], SSB_SPROM4_TXPID2G01, SSB_SPROM4_TXPID2G0,
 241             SSB_SPROM4_TXPID2G0_SHIFT);
 242        SPEX(txpid2g[1], SSB_SPROM4_TXPID2G01, SSB_SPROM4_TXPID2G1,
 243             SSB_SPROM4_TXPID2G1_SHIFT);
 244        SPEX(txpid2g[2], SSB_SPROM4_TXPID2G23, SSB_SPROM4_TXPID2G2,
 245             SSB_SPROM4_TXPID2G2_SHIFT);
 246        SPEX(txpid2g[3], SSB_SPROM4_TXPID2G23, SSB_SPROM4_TXPID2G3,
 247             SSB_SPROM4_TXPID2G3_SHIFT);
 248
 249        SPEX(txpid5gl[0], SSB_SPROM4_TXPID5GL01, SSB_SPROM4_TXPID5GL0,
 250             SSB_SPROM4_TXPID5GL0_SHIFT);
 251        SPEX(txpid5gl[1], SSB_SPROM4_TXPID5GL01, SSB_SPROM4_TXPID5GL1,
 252             SSB_SPROM4_TXPID5GL1_SHIFT);
 253        SPEX(txpid5gl[2], SSB_SPROM4_TXPID5GL23, SSB_SPROM4_TXPID5GL2,
 254             SSB_SPROM4_TXPID5GL2_SHIFT);
 255        SPEX(txpid5gl[3], SSB_SPROM4_TXPID5GL23, SSB_SPROM4_TXPID5GL3,
 256             SSB_SPROM4_TXPID5GL3_SHIFT);
 257
 258        SPEX(txpid5g[0], SSB_SPROM4_TXPID5G01, SSB_SPROM4_TXPID5G0,
 259             SSB_SPROM4_TXPID5G0_SHIFT);
 260        SPEX(txpid5g[1], SSB_SPROM4_TXPID5G01, SSB_SPROM4_TXPID5G1,
 261             SSB_SPROM4_TXPID5G1_SHIFT);
 262        SPEX(txpid5g[2], SSB_SPROM4_TXPID5G23, SSB_SPROM4_TXPID5G2,
 263             SSB_SPROM4_TXPID5G2_SHIFT);
 264        SPEX(txpid5g[3], SSB_SPROM4_TXPID5G23, SSB_SPROM4_TXPID5G3,
 265             SSB_SPROM4_TXPID5G3_SHIFT);
 266
 267        SPEX(txpid5gh[0], SSB_SPROM4_TXPID5GH01, SSB_SPROM4_TXPID5GH0,
 268             SSB_SPROM4_TXPID5GH0_SHIFT);
 269        SPEX(txpid5gh[1], SSB_SPROM4_TXPID5GH01, SSB_SPROM4_TXPID5GH1,
 270             SSB_SPROM4_TXPID5GH1_SHIFT);
 271        SPEX(txpid5gh[2], SSB_SPROM4_TXPID5GH23, SSB_SPROM4_TXPID5GH2,
 272             SSB_SPROM4_TXPID5GH2_SHIFT);
 273        SPEX(txpid5gh[3], SSB_SPROM4_TXPID5GH23, SSB_SPROM4_TXPID5GH3,
 274             SSB_SPROM4_TXPID5GH3_SHIFT);
 275
 276        SPEX(boardflags_lo, SSB_SPROM8_BFLLO, ~0, 0);
 277        SPEX(boardflags_hi, SSB_SPROM8_BFLHI, ~0, 0);
 278        SPEX(boardflags2_lo, SSB_SPROM8_BFL2LO, ~0, 0);
 279        SPEX(boardflags2_hi, SSB_SPROM8_BFL2HI, ~0, 0);
 280
 281        SPEX(alpha2[0], SSB_SPROM8_CCODE, 0xff00, 8);
 282        SPEX(alpha2[1], SSB_SPROM8_CCODE, 0x00ff, 0);
 283
 284        /* Extract cores power info info */
 285        for (i = 0; i < ARRAY_SIZE(pwr_info_offset); i++) {
 286                o = pwr_info_offset[i];
 287                SPEX(core_pwr_info[i].itssi_2g, o + SSB_SROM8_2G_MAXP_ITSSI,
 288                        SSB_SPROM8_2G_ITSSI, SSB_SPROM8_2G_ITSSI_SHIFT);
 289                SPEX(core_pwr_info[i].maxpwr_2g, o + SSB_SROM8_2G_MAXP_ITSSI,
 290                        SSB_SPROM8_2G_MAXP, 0);
 291
 292                SPEX(core_pwr_info[i].pa_2g[0], o + SSB_SROM8_2G_PA_0, ~0, 0);
 293                SPEX(core_pwr_info[i].pa_2g[1], o + SSB_SROM8_2G_PA_1, ~0, 0);
 294                SPEX(core_pwr_info[i].pa_2g[2], o + SSB_SROM8_2G_PA_2, ~0, 0);
 295
 296                SPEX(core_pwr_info[i].itssi_5g, o + SSB_SROM8_5G_MAXP_ITSSI,
 297                        SSB_SPROM8_5G_ITSSI, SSB_SPROM8_5G_ITSSI_SHIFT);
 298                SPEX(core_pwr_info[i].maxpwr_5g, o + SSB_SROM8_5G_MAXP_ITSSI,
 299                        SSB_SPROM8_5G_MAXP, 0);
 300                SPEX(core_pwr_info[i].maxpwr_5gh, o + SSB_SPROM8_5GHL_MAXP,
 301                        SSB_SPROM8_5GH_MAXP, 0);
 302                SPEX(core_pwr_info[i].maxpwr_5gl, o + SSB_SPROM8_5GHL_MAXP,
 303                        SSB_SPROM8_5GL_MAXP, SSB_SPROM8_5GL_MAXP_SHIFT);
 304
 305                SPEX(core_pwr_info[i].pa_5gl[0], o + SSB_SROM8_5GL_PA_0, ~0, 0);
 306                SPEX(core_pwr_info[i].pa_5gl[1], o + SSB_SROM8_5GL_PA_1, ~0, 0);
 307                SPEX(core_pwr_info[i].pa_5gl[2], o + SSB_SROM8_5GL_PA_2, ~0, 0);
 308                SPEX(core_pwr_info[i].pa_5g[0], o + SSB_SROM8_5G_PA_0, ~0, 0);
 309                SPEX(core_pwr_info[i].pa_5g[1], o + SSB_SROM8_5G_PA_1, ~0, 0);
 310                SPEX(core_pwr_info[i].pa_5g[2], o + SSB_SROM8_5G_PA_2, ~0, 0);
 311                SPEX(core_pwr_info[i].pa_5gh[0], o + SSB_SROM8_5GH_PA_0, ~0, 0);
 312                SPEX(core_pwr_info[i].pa_5gh[1], o + SSB_SROM8_5GH_PA_1, ~0, 0);
 313                SPEX(core_pwr_info[i].pa_5gh[2], o + SSB_SROM8_5GH_PA_2, ~0, 0);
 314        }
 315
 316        SPEX(fem.ghz2.tssipos, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_TSSIPOS,
 317             SSB_SROM8_FEM_TSSIPOS_SHIFT);
 318        SPEX(fem.ghz2.extpa_gain, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_EXTPA_GAIN,
 319             SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
 320        SPEX(fem.ghz2.pdet_range, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_PDET_RANGE,
 321             SSB_SROM8_FEM_PDET_RANGE_SHIFT);
 322        SPEX(fem.ghz2.tr_iso, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_TR_ISO,
 323             SSB_SROM8_FEM_TR_ISO_SHIFT);
 324        SPEX(fem.ghz2.antswlut, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_ANTSWLUT,
 325             SSB_SROM8_FEM_ANTSWLUT_SHIFT);
 326
 327        SPEX(fem.ghz5.tssipos, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_TSSIPOS,
 328             SSB_SROM8_FEM_TSSIPOS_SHIFT);
 329        SPEX(fem.ghz5.extpa_gain, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_EXTPA_GAIN,
 330             SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
 331        SPEX(fem.ghz5.pdet_range, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_PDET_RANGE,
 332             SSB_SROM8_FEM_PDET_RANGE_SHIFT);
 333        SPEX(fem.ghz5.tr_iso, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_TR_ISO,
 334             SSB_SROM8_FEM_TR_ISO_SHIFT);
 335        SPEX(fem.ghz5.antswlut, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_ANTSWLUT,
 336             SSB_SROM8_FEM_ANTSWLUT_SHIFT);
 337
 338        SPEX(ant_available_a, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_A,
 339             SSB_SPROM8_ANTAVAIL_A_SHIFT);
 340        SPEX(ant_available_bg, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_BG,
 341             SSB_SPROM8_ANTAVAIL_BG_SHIFT);
 342        SPEX(maxpwr_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_MAXP_BG_MASK, 0);
 343        SPEX(itssi_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_ITSSI_BG,
 344             SSB_SPROM8_ITSSI_BG_SHIFT);
 345        SPEX(maxpwr_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_MAXP_A_MASK, 0);
 346        SPEX(itssi_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_ITSSI_A,
 347             SSB_SPROM8_ITSSI_A_SHIFT);
 348        SPEX(maxpwr_ah, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AH_MASK, 0);
 349        SPEX(maxpwr_al, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AL_MASK,
 350             SSB_SPROM8_MAXP_AL_SHIFT);
 351        SPEX(gpio0, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P0, 0);
 352        SPEX(gpio1, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P1,
 353             SSB_SPROM8_GPIOA_P1_SHIFT);
 354        SPEX(gpio2, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P2, 0);
 355        SPEX(gpio3, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P3,
 356             SSB_SPROM8_GPIOB_P3_SHIFT);
 357        SPEX(tri2g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI2G, 0);
 358        SPEX(tri5g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI5G,
 359             SSB_SPROM8_TRI5G_SHIFT);
 360        SPEX(tri5gl, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GL, 0);
 361        SPEX(tri5gh, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GH,
 362             SSB_SPROM8_TRI5GH_SHIFT);
 363        SPEX(rxpo2g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO2G,
 364             SSB_SPROM8_RXPO2G_SHIFT);
 365        SPEX(rxpo5g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO5G,
 366             SSB_SPROM8_RXPO5G_SHIFT);
 367        SPEX(rssismf2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMF2G, 0);
 368        SPEX(rssismc2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMC2G,
 369             SSB_SPROM8_RSSISMC2G_SHIFT);
 370        SPEX(rssisav2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISAV2G,
 371             SSB_SPROM8_RSSISAV2G_SHIFT);
 372        SPEX(bxa2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_BXA2G,
 373             SSB_SPROM8_BXA2G_SHIFT);
 374        SPEX(rssismf5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMF5G, 0);
 375        SPEX(rssismc5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMC5G,
 376             SSB_SPROM8_RSSISMC5G_SHIFT);
 377        SPEX(rssisav5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISAV5G,
 378             SSB_SPROM8_RSSISAV5G_SHIFT);
 379        SPEX(bxa5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_BXA5G,
 380             SSB_SPROM8_BXA5G_SHIFT);
 381
 382        SPEX(pa0b0, SSB_SPROM8_PA0B0, ~0, 0);
 383        SPEX(pa0b1, SSB_SPROM8_PA0B1, ~0, 0);
 384        SPEX(pa0b2, SSB_SPROM8_PA0B2, ~0, 0);
 385        SPEX(pa1b0, SSB_SPROM8_PA1B0, ~0, 0);
 386        SPEX(pa1b1, SSB_SPROM8_PA1B1, ~0, 0);
 387        SPEX(pa1b2, SSB_SPROM8_PA1B2, ~0, 0);
 388        SPEX(pa1lob0, SSB_SPROM8_PA1LOB0, ~0, 0);
 389        SPEX(pa1lob1, SSB_SPROM8_PA1LOB1, ~0, 0);
 390        SPEX(pa1lob2, SSB_SPROM8_PA1LOB2, ~0, 0);
 391        SPEX(pa1hib0, SSB_SPROM8_PA1HIB0, ~0, 0);
 392        SPEX(pa1hib1, SSB_SPROM8_PA1HIB1, ~0, 0);
 393        SPEX(pa1hib2, SSB_SPROM8_PA1HIB2, ~0, 0);
 394        SPEX(cck2gpo, SSB_SPROM8_CCK2GPO, ~0, 0);
 395        SPEX32(ofdm2gpo, SSB_SPROM8_OFDM2GPO, ~0, 0);
 396        SPEX32(ofdm5glpo, SSB_SPROM8_OFDM5GLPO, ~0, 0);
 397        SPEX32(ofdm5gpo, SSB_SPROM8_OFDM5GPO, ~0, 0);
 398        SPEX32(ofdm5ghpo, SSB_SPROM8_OFDM5GHPO, ~0, 0);
 399
 400        /* Extract the antenna gain values. */
 401        bus->sprom.antenna_gain.a0 = sprom_extract_antgain(sprom,
 402                                                           SSB_SPROM8_AGAIN01,
 403                                                           SSB_SPROM8_AGAIN0,
 404                                                           SSB_SPROM8_AGAIN0_SHIFT);
 405        bus->sprom.antenna_gain.a1 = sprom_extract_antgain(sprom,
 406                                                           SSB_SPROM8_AGAIN01,
 407                                                           SSB_SPROM8_AGAIN1,
 408                                                           SSB_SPROM8_AGAIN1_SHIFT);
 409        bus->sprom.antenna_gain.a2 = sprom_extract_antgain(sprom,
 410                                                           SSB_SPROM8_AGAIN23,
 411                                                           SSB_SPROM8_AGAIN2,
 412                                                           SSB_SPROM8_AGAIN2_SHIFT);
 413        bus->sprom.antenna_gain.a3 = sprom_extract_antgain(sprom,
 414                                                           SSB_SPROM8_AGAIN23,
 415                                                           SSB_SPROM8_AGAIN3,
 416                                                           SSB_SPROM8_AGAIN3_SHIFT);
 417
 418        SPEX(leddc_on_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_ON,
 419             SSB_SPROM8_LEDDC_ON_SHIFT);
 420        SPEX(leddc_off_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_OFF,
 421             SSB_SPROM8_LEDDC_OFF_SHIFT);
 422
 423        SPEX(txchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_TXCHAIN,
 424             SSB_SPROM8_TXRXC_TXCHAIN_SHIFT);
 425        SPEX(rxchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_RXCHAIN,
 426             SSB_SPROM8_TXRXC_RXCHAIN_SHIFT);
 427        SPEX(antswitch, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_SWITCH,
 428             SSB_SPROM8_TXRXC_SWITCH_SHIFT);
 429
 430        SPEX(opo, SSB_SPROM8_OFDM2GPO, 0x00ff, 0);
 431
 432        SPEX_ARRAY8(mcs2gpo, SSB_SPROM8_2G_MCSPO, ~0, 0);
 433        SPEX_ARRAY8(mcs5gpo, SSB_SPROM8_5G_MCSPO, ~0, 0);
 434        SPEX_ARRAY8(mcs5glpo, SSB_SPROM8_5GL_MCSPO, ~0, 0);
 435        SPEX_ARRAY8(mcs5ghpo, SSB_SPROM8_5GH_MCSPO, ~0, 0);
 436
 437        SPEX(rawtempsense, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_RAWTEMP,
 438             SSB_SPROM8_RAWTS_RAWTEMP_SHIFT);
 439        SPEX(measpower, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_MEASPOWER,
 440             SSB_SPROM8_RAWTS_MEASPOWER_SHIFT);
 441        SPEX(tempsense_slope, SSB_SPROM8_OPT_CORRX,
 442             SSB_SPROM8_OPT_CORRX_TEMP_SLOPE,
 443             SSB_SPROM8_OPT_CORRX_TEMP_SLOPE_SHIFT);
 444        SPEX(tempcorrx, SSB_SPROM8_OPT_CORRX, SSB_SPROM8_OPT_CORRX_TEMPCORRX,
 445             SSB_SPROM8_OPT_CORRX_TEMPCORRX_SHIFT);
 446        SPEX(tempsense_option, SSB_SPROM8_OPT_CORRX,
 447             SSB_SPROM8_OPT_CORRX_TEMP_OPTION,
 448             SSB_SPROM8_OPT_CORRX_TEMP_OPTION_SHIFT);
 449        SPEX(freqoffset_corr, SSB_SPROM8_HWIQ_IQSWP,
 450             SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR,
 451             SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR_SHIFT);
 452        SPEX(iqcal_swp_dis, SSB_SPROM8_HWIQ_IQSWP,
 453             SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP,
 454             SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP_SHIFT);
 455        SPEX(hw_iqcal_en, SSB_SPROM8_HWIQ_IQSWP, SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL,
 456             SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL_SHIFT);
 457
 458        SPEX(bw40po, SSB_SPROM8_BW40PO, ~0, 0);
 459        SPEX(cddpo, SSB_SPROM8_CDDPO, ~0, 0);
 460        SPEX(stbcpo, SSB_SPROM8_STBCPO, ~0, 0);
 461        SPEX(bwduppo, SSB_SPROM8_BWDUPPO, ~0, 0);
 462
 463        SPEX(tempthresh, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_TRESH,
 464             SSB_SPROM8_THERMAL_TRESH_SHIFT);
 465        SPEX(tempoffset, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_OFFSET,
 466             SSB_SPROM8_THERMAL_OFFSET_SHIFT);
 467        SPEX(phycal_tempdelta, SSB_SPROM8_TEMPDELTA,
 468             SSB_SPROM8_TEMPDELTA_PHYCAL,
 469             SSB_SPROM8_TEMPDELTA_PHYCAL_SHIFT);
 470        SPEX(temps_period, SSB_SPROM8_TEMPDELTA, SSB_SPROM8_TEMPDELTA_PERIOD,
 471             SSB_SPROM8_TEMPDELTA_PERIOD_SHIFT);
 472        SPEX(temps_hysteresis, SSB_SPROM8_TEMPDELTA,
 473             SSB_SPROM8_TEMPDELTA_HYSTERESIS,
 474             SSB_SPROM8_TEMPDELTA_HYSTERESIS_SHIFT);
 475}
 476
 477/*
 478 * Indicates the presence of external SPROM.
 479 */
 480static bool bcma_sprom_ext_available(struct bcma_bus *bus)
 481{
 482        u32 chip_status;
 483        u32 srom_control;
 484        u32 present_mask;
 485
 486        if (bus->drv_cc.core->id.rev >= 31) {
 487                if (!(bus->drv_cc.capabilities & BCMA_CC_CAP_SPROM))
 488                        return false;
 489
 490                srom_control = bcma_read32(bus->drv_cc.core,
 491                                           BCMA_CC_SROM_CONTROL);
 492                return srom_control & BCMA_CC_SROM_CONTROL_PRESENT;
 493        }
 494
 495        /* older chipcommon revisions use chip status register */
 496        chip_status = bcma_read32(bus->drv_cc.core, BCMA_CC_CHIPSTAT);
 497        switch (bus->chipinfo.id) {
 498        case BCMA_CHIP_ID_BCM4313:
 499                present_mask = BCMA_CC_CHIPST_4313_SPROM_PRESENT;
 500                break;
 501
 502        case BCMA_CHIP_ID_BCM4331:
 503                present_mask = BCMA_CC_CHIPST_4331_SPROM_PRESENT;
 504                break;
 505
 506        default:
 507                return true;
 508        }
 509
 510        return chip_status & present_mask;
 511}
 512
 513/*
 514 * Indicates that on-chip OTP memory is present and enabled.
 515 */
 516static bool bcma_sprom_onchip_available(struct bcma_bus *bus)
 517{
 518        u32 chip_status;
 519        u32 otpsize = 0;
 520        bool present;
 521
 522        chip_status = bcma_read32(bus->drv_cc.core, BCMA_CC_CHIPSTAT);
 523        switch (bus->chipinfo.id) {
 524        case BCMA_CHIP_ID_BCM4313:
 525                present = chip_status & BCMA_CC_CHIPST_4313_OTP_PRESENT;
 526                break;
 527
 528        case BCMA_CHIP_ID_BCM4331:
 529                present = chip_status & BCMA_CC_CHIPST_4331_OTP_PRESENT;
 530                break;
 531        case BCMA_CHIP_ID_BCM43142:
 532        case BCMA_CHIP_ID_BCM43224:
 533        case BCMA_CHIP_ID_BCM43225:
 534                /* for these chips OTP is always available */
 535                present = true;
 536                break;
 537        case BCMA_CHIP_ID_BCM43131:
 538        case BCMA_CHIP_ID_BCM43217:
 539        case BCMA_CHIP_ID_BCM43227:
 540        case BCMA_CHIP_ID_BCM43228:
 541        case BCMA_CHIP_ID_BCM43428:
 542                present = chip_status & BCMA_CC_CHIPST_43228_OTP_PRESENT;
 543                break;
 544        default:
 545                present = false;
 546                break;
 547        }
 548
 549        if (present) {
 550                otpsize = bus->drv_cc.capabilities & BCMA_CC_CAP_OTPS;
 551                otpsize >>= BCMA_CC_CAP_OTPS_SHIFT;
 552        }
 553
 554        return otpsize != 0;
 555}
 556
 557/*
 558 * Verify OTP is filled and determine the byte
 559 * offset where SPROM data is located.
 560 *
 561 * On error, returns 0; byte offset otherwise.
 562 */
 563static int bcma_sprom_onchip_offset(struct bcma_bus *bus)
 564{
 565        struct bcma_device *cc = bus->drv_cc.core;
 566        u32 offset;
 567
 568        /* verify OTP status */
 569        if ((bcma_read32(cc, BCMA_CC_OTPS) & BCMA_CC_OTPS_GU_PROG_HW) == 0)
 570                return 0;
 571
 572        /* obtain bit offset from otplayout register */
 573        offset = (bcma_read32(cc, BCMA_CC_OTPL) & BCMA_CC_OTPL_GURGN_OFFSET);
 574        return BCMA_CC_SPROM + (offset >> 3);
 575}
 576
 577int bcma_sprom_get(struct bcma_bus *bus)
 578{
 579        u16 offset = BCMA_CC_SPROM;
 580        u16 *sprom;
 581        static const size_t sprom_sizes[] = {
 582                SSB_SPROMSIZE_WORDS_R4,
 583                SSB_SPROMSIZE_WORDS_R10,
 584                SSB_SPROMSIZE_WORDS_R11,
 585        };
 586        int i, err = 0;
 587
 588        if (!bus->drv_cc.core)
 589                return -EOPNOTSUPP;
 590
 591        if (!bcma_sprom_ext_available(bus)) {
 592                bool sprom_onchip;
 593
 594                /*
 595                 * External SPROM takes precedence so check
 596                 * on-chip OTP only when no external SPROM
 597                 * is present.
 598                 */
 599                sprom_onchip = bcma_sprom_onchip_available(bus);
 600                if (sprom_onchip) {
 601                        /* determine offset */
 602                        offset = bcma_sprom_onchip_offset(bus);
 603                }
 604                if (!offset || !sprom_onchip) {
 605                        /*
 606                         * Maybe there is no SPROM on the device?
 607                         * Now we ask the arch code if there is some sprom
 608                         * available for this device in some other storage.
 609                         */
 610                        err = bcma_fill_sprom_with_fallback(bus, &bus->sprom);
 611                        return err;
 612                }
 613        }
 614
 615        if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4331 ||
 616            bus->chipinfo.id == BCMA_CHIP_ID_BCM43431)
 617                bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, false);
 618
 619        bcma_debug(bus, "SPROM offset 0x%x\n", offset);
 620        for (i = 0; i < ARRAY_SIZE(sprom_sizes); i++) {
 621                size_t words = sprom_sizes[i];
 622
 623                sprom = kcalloc(words, sizeof(u16), GFP_KERNEL);
 624                if (!sprom)
 625                        return -ENOMEM;
 626
 627                bcma_sprom_read(bus, offset, sprom, words);
 628                err = bcma_sprom_valid(bus, sprom, words);
 629                if (!err)
 630                        break;
 631
 632                kfree(sprom);
 633        }
 634
 635        if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4331 ||
 636            bus->chipinfo.id == BCMA_CHIP_ID_BCM43431)
 637                bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true);
 638
 639        if (err) {
 640                bcma_warn(bus, "Invalid SPROM read from the PCIe card, trying to use fallback SPROM\n");
 641                err = bcma_fill_sprom_with_fallback(bus, &bus->sprom);
 642        } else {
 643                bcma_sprom_extract_r8(bus, sprom);
 644                kfree(sprom);
 645        }
 646
 647        return err;
 648}
 649