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 void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom)
 205{
 206        u16 v, o;
 207        int i;
 208        u16 pwr_info_offset[] = {
 209                SSB_SROM8_PWR_INFO_CORE0, SSB_SROM8_PWR_INFO_CORE1,
 210                SSB_SROM8_PWR_INFO_CORE2, SSB_SROM8_PWR_INFO_CORE3
 211        };
 212        BUILD_BUG_ON(ARRAY_SIZE(pwr_info_offset) !=
 213                        ARRAY_SIZE(bus->sprom.core_pwr_info));
 214
 215        for (i = 0; i < 3; i++) {
 216                v = sprom[SPOFF(SSB_SPROM8_IL0MAC) + i];
 217                *(((__be16 *)bus->sprom.il0mac) + i) = cpu_to_be16(v);
 218        }
 219
 220        SPEX(board_rev, SSB_SPROM8_BOARDREV, ~0, 0);
 221        SPEX(board_type, SSB_SPROM1_SPID, ~0, 0);
 222
 223        SPEX(txpid2g[0], SSB_SPROM4_TXPID2G01, SSB_SPROM4_TXPID2G0,
 224             SSB_SPROM4_TXPID2G0_SHIFT);
 225        SPEX(txpid2g[1], SSB_SPROM4_TXPID2G01, SSB_SPROM4_TXPID2G1,
 226             SSB_SPROM4_TXPID2G1_SHIFT);
 227        SPEX(txpid2g[2], SSB_SPROM4_TXPID2G23, SSB_SPROM4_TXPID2G2,
 228             SSB_SPROM4_TXPID2G2_SHIFT);
 229        SPEX(txpid2g[3], SSB_SPROM4_TXPID2G23, SSB_SPROM4_TXPID2G3,
 230             SSB_SPROM4_TXPID2G3_SHIFT);
 231
 232        SPEX(txpid5gl[0], SSB_SPROM4_TXPID5GL01, SSB_SPROM4_TXPID5GL0,
 233             SSB_SPROM4_TXPID5GL0_SHIFT);
 234        SPEX(txpid5gl[1], SSB_SPROM4_TXPID5GL01, SSB_SPROM4_TXPID5GL1,
 235             SSB_SPROM4_TXPID5GL1_SHIFT);
 236        SPEX(txpid5gl[2], SSB_SPROM4_TXPID5GL23, SSB_SPROM4_TXPID5GL2,
 237             SSB_SPROM4_TXPID5GL2_SHIFT);
 238        SPEX(txpid5gl[3], SSB_SPROM4_TXPID5GL23, SSB_SPROM4_TXPID5GL3,
 239             SSB_SPROM4_TXPID5GL3_SHIFT);
 240
 241        SPEX(txpid5g[0], SSB_SPROM4_TXPID5G01, SSB_SPROM4_TXPID5G0,
 242             SSB_SPROM4_TXPID5G0_SHIFT);
 243        SPEX(txpid5g[1], SSB_SPROM4_TXPID5G01, SSB_SPROM4_TXPID5G1,
 244             SSB_SPROM4_TXPID5G1_SHIFT);
 245        SPEX(txpid5g[2], SSB_SPROM4_TXPID5G23, SSB_SPROM4_TXPID5G2,
 246             SSB_SPROM4_TXPID5G2_SHIFT);
 247        SPEX(txpid5g[3], SSB_SPROM4_TXPID5G23, SSB_SPROM4_TXPID5G3,
 248             SSB_SPROM4_TXPID5G3_SHIFT);
 249
 250        SPEX(txpid5gh[0], SSB_SPROM4_TXPID5GH01, SSB_SPROM4_TXPID5GH0,
 251             SSB_SPROM4_TXPID5GH0_SHIFT);
 252        SPEX(txpid5gh[1], SSB_SPROM4_TXPID5GH01, SSB_SPROM4_TXPID5GH1,
 253             SSB_SPROM4_TXPID5GH1_SHIFT);
 254        SPEX(txpid5gh[2], SSB_SPROM4_TXPID5GH23, SSB_SPROM4_TXPID5GH2,
 255             SSB_SPROM4_TXPID5GH2_SHIFT);
 256        SPEX(txpid5gh[3], SSB_SPROM4_TXPID5GH23, SSB_SPROM4_TXPID5GH3,
 257             SSB_SPROM4_TXPID5GH3_SHIFT);
 258
 259        SPEX(boardflags_lo, SSB_SPROM8_BFLLO, ~0, 0);
 260        SPEX(boardflags_hi, SSB_SPROM8_BFLHI, ~0, 0);
 261        SPEX(boardflags2_lo, SSB_SPROM8_BFL2LO, ~0, 0);
 262        SPEX(boardflags2_hi, SSB_SPROM8_BFL2HI, ~0, 0);
 263
 264        SPEX(alpha2[0], SSB_SPROM8_CCODE, 0xff00, 8);
 265        SPEX(alpha2[1], SSB_SPROM8_CCODE, 0x00ff, 0);
 266
 267        /* Extract cores power info info */
 268        for (i = 0; i < ARRAY_SIZE(pwr_info_offset); i++) {
 269                o = pwr_info_offset[i];
 270                SPEX(core_pwr_info[i].itssi_2g, o + SSB_SROM8_2G_MAXP_ITSSI,
 271                        SSB_SPROM8_2G_ITSSI, SSB_SPROM8_2G_ITSSI_SHIFT);
 272                SPEX(core_pwr_info[i].maxpwr_2g, o + SSB_SROM8_2G_MAXP_ITSSI,
 273                        SSB_SPROM8_2G_MAXP, 0);
 274
 275                SPEX(core_pwr_info[i].pa_2g[0], o + SSB_SROM8_2G_PA_0, ~0, 0);
 276                SPEX(core_pwr_info[i].pa_2g[1], o + SSB_SROM8_2G_PA_1, ~0, 0);
 277                SPEX(core_pwr_info[i].pa_2g[2], o + SSB_SROM8_2G_PA_2, ~0, 0);
 278
 279                SPEX(core_pwr_info[i].itssi_5g, o + SSB_SROM8_5G_MAXP_ITSSI,
 280                        SSB_SPROM8_5G_ITSSI, SSB_SPROM8_5G_ITSSI_SHIFT);
 281                SPEX(core_pwr_info[i].maxpwr_5g, o + SSB_SROM8_5G_MAXP_ITSSI,
 282                        SSB_SPROM8_5G_MAXP, 0);
 283                SPEX(core_pwr_info[i].maxpwr_5gh, o + SSB_SPROM8_5GHL_MAXP,
 284                        SSB_SPROM8_5GH_MAXP, 0);
 285                SPEX(core_pwr_info[i].maxpwr_5gl, o + SSB_SPROM8_5GHL_MAXP,
 286                        SSB_SPROM8_5GL_MAXP, SSB_SPROM8_5GL_MAXP_SHIFT);
 287
 288                SPEX(core_pwr_info[i].pa_5gl[0], o + SSB_SROM8_5GL_PA_0, ~0, 0);
 289                SPEX(core_pwr_info[i].pa_5gl[1], o + SSB_SROM8_5GL_PA_1, ~0, 0);
 290                SPEX(core_pwr_info[i].pa_5gl[2], o + SSB_SROM8_5GL_PA_2, ~0, 0);
 291                SPEX(core_pwr_info[i].pa_5g[0], o + SSB_SROM8_5G_PA_0, ~0, 0);
 292                SPEX(core_pwr_info[i].pa_5g[1], o + SSB_SROM8_5G_PA_1, ~0, 0);
 293                SPEX(core_pwr_info[i].pa_5g[2], o + SSB_SROM8_5G_PA_2, ~0, 0);
 294                SPEX(core_pwr_info[i].pa_5gh[0], o + SSB_SROM8_5GH_PA_0, ~0, 0);
 295                SPEX(core_pwr_info[i].pa_5gh[1], o + SSB_SROM8_5GH_PA_1, ~0, 0);
 296                SPEX(core_pwr_info[i].pa_5gh[2], o + SSB_SROM8_5GH_PA_2, ~0, 0);
 297        }
 298
 299        SPEX(fem.ghz2.tssipos, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_TSSIPOS,
 300             SSB_SROM8_FEM_TSSIPOS_SHIFT);
 301        SPEX(fem.ghz2.extpa_gain, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_EXTPA_GAIN,
 302             SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
 303        SPEX(fem.ghz2.pdet_range, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_PDET_RANGE,
 304             SSB_SROM8_FEM_PDET_RANGE_SHIFT);
 305        SPEX(fem.ghz2.tr_iso, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_TR_ISO,
 306             SSB_SROM8_FEM_TR_ISO_SHIFT);
 307        SPEX(fem.ghz2.antswlut, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_ANTSWLUT,
 308             SSB_SROM8_FEM_ANTSWLUT_SHIFT);
 309
 310        SPEX(fem.ghz5.tssipos, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_TSSIPOS,
 311             SSB_SROM8_FEM_TSSIPOS_SHIFT);
 312        SPEX(fem.ghz5.extpa_gain, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_EXTPA_GAIN,
 313             SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
 314        SPEX(fem.ghz5.pdet_range, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_PDET_RANGE,
 315             SSB_SROM8_FEM_PDET_RANGE_SHIFT);
 316        SPEX(fem.ghz5.tr_iso, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_TR_ISO,
 317             SSB_SROM8_FEM_TR_ISO_SHIFT);
 318        SPEX(fem.ghz5.antswlut, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_ANTSWLUT,
 319             SSB_SROM8_FEM_ANTSWLUT_SHIFT);
 320
 321        SPEX(ant_available_a, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_A,
 322             SSB_SPROM8_ANTAVAIL_A_SHIFT);
 323        SPEX(ant_available_bg, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_BG,
 324             SSB_SPROM8_ANTAVAIL_BG_SHIFT);
 325        SPEX(maxpwr_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_MAXP_BG_MASK, 0);
 326        SPEX(itssi_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_ITSSI_BG,
 327             SSB_SPROM8_ITSSI_BG_SHIFT);
 328        SPEX(maxpwr_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_MAXP_A_MASK, 0);
 329        SPEX(itssi_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_ITSSI_A,
 330             SSB_SPROM8_ITSSI_A_SHIFT);
 331        SPEX(maxpwr_ah, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AH_MASK, 0);
 332        SPEX(maxpwr_al, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AL_MASK,
 333             SSB_SPROM8_MAXP_AL_SHIFT);
 334        SPEX(gpio0, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P0, 0);
 335        SPEX(gpio1, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P1,
 336             SSB_SPROM8_GPIOA_P1_SHIFT);
 337        SPEX(gpio2, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P2, 0);
 338        SPEX(gpio3, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P3,
 339             SSB_SPROM8_GPIOB_P3_SHIFT);
 340        SPEX(tri2g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI2G, 0);
 341        SPEX(tri5g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI5G,
 342             SSB_SPROM8_TRI5G_SHIFT);
 343        SPEX(tri5gl, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GL, 0);
 344        SPEX(tri5gh, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GH,
 345             SSB_SPROM8_TRI5GH_SHIFT);
 346        SPEX(rxpo2g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO2G,
 347             SSB_SPROM8_RXPO2G_SHIFT);
 348        SPEX(rxpo5g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO5G,
 349             SSB_SPROM8_RXPO5G_SHIFT);
 350        SPEX(rssismf2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMF2G, 0);
 351        SPEX(rssismc2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMC2G,
 352             SSB_SPROM8_RSSISMC2G_SHIFT);
 353        SPEX(rssisav2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISAV2G,
 354             SSB_SPROM8_RSSISAV2G_SHIFT);
 355        SPEX(bxa2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_BXA2G,
 356             SSB_SPROM8_BXA2G_SHIFT);
 357        SPEX(rssismf5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMF5G, 0);
 358        SPEX(rssismc5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMC5G,
 359             SSB_SPROM8_RSSISMC5G_SHIFT);
 360        SPEX(rssisav5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISAV5G,
 361             SSB_SPROM8_RSSISAV5G_SHIFT);
 362        SPEX(bxa5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_BXA5G,
 363             SSB_SPROM8_BXA5G_SHIFT);
 364
 365        SPEX(pa0b0, SSB_SPROM8_PA0B0, ~0, 0);
 366        SPEX(pa0b1, SSB_SPROM8_PA0B1, ~0, 0);
 367        SPEX(pa0b2, SSB_SPROM8_PA0B2, ~0, 0);
 368        SPEX(pa1b0, SSB_SPROM8_PA1B0, ~0, 0);
 369        SPEX(pa1b1, SSB_SPROM8_PA1B1, ~0, 0);
 370        SPEX(pa1b2, SSB_SPROM8_PA1B2, ~0, 0);
 371        SPEX(pa1lob0, SSB_SPROM8_PA1LOB0, ~0, 0);
 372        SPEX(pa1lob1, SSB_SPROM8_PA1LOB1, ~0, 0);
 373        SPEX(pa1lob2, SSB_SPROM8_PA1LOB2, ~0, 0);
 374        SPEX(pa1hib0, SSB_SPROM8_PA1HIB0, ~0, 0);
 375        SPEX(pa1hib1, SSB_SPROM8_PA1HIB1, ~0, 0);
 376        SPEX(pa1hib2, SSB_SPROM8_PA1HIB2, ~0, 0);
 377        SPEX(cck2gpo, SSB_SPROM8_CCK2GPO, ~0, 0);
 378        SPEX32(ofdm2gpo, SSB_SPROM8_OFDM2GPO, ~0, 0);
 379        SPEX32(ofdm5glpo, SSB_SPROM8_OFDM5GLPO, ~0, 0);
 380        SPEX32(ofdm5gpo, SSB_SPROM8_OFDM5GPO, ~0, 0);
 381        SPEX32(ofdm5ghpo, SSB_SPROM8_OFDM5GHPO, ~0, 0);
 382
 383        /* Extract the antenna gain values. */
 384        SPEX(antenna_gain.a0, SSB_SPROM8_AGAIN01,
 385             SSB_SPROM8_AGAIN0, SSB_SPROM8_AGAIN0_SHIFT);
 386        SPEX(antenna_gain.a1, SSB_SPROM8_AGAIN01,
 387             SSB_SPROM8_AGAIN1, SSB_SPROM8_AGAIN1_SHIFT);
 388        SPEX(antenna_gain.a2, SSB_SPROM8_AGAIN23,
 389             SSB_SPROM8_AGAIN2, SSB_SPROM8_AGAIN2_SHIFT);
 390        SPEX(antenna_gain.a3, SSB_SPROM8_AGAIN23,
 391             SSB_SPROM8_AGAIN3, SSB_SPROM8_AGAIN3_SHIFT);
 392
 393        SPEX(leddc_on_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_ON,
 394             SSB_SPROM8_LEDDC_ON_SHIFT);
 395        SPEX(leddc_off_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_OFF,
 396             SSB_SPROM8_LEDDC_OFF_SHIFT);
 397
 398        SPEX(txchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_TXCHAIN,
 399             SSB_SPROM8_TXRXC_TXCHAIN_SHIFT);
 400        SPEX(rxchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_RXCHAIN,
 401             SSB_SPROM8_TXRXC_RXCHAIN_SHIFT);
 402        SPEX(antswitch, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_SWITCH,
 403             SSB_SPROM8_TXRXC_SWITCH_SHIFT);
 404
 405        SPEX(opo, SSB_SPROM8_OFDM2GPO, 0x00ff, 0);
 406
 407        SPEX_ARRAY8(mcs2gpo, SSB_SPROM8_2G_MCSPO, ~0, 0);
 408        SPEX_ARRAY8(mcs5gpo, SSB_SPROM8_5G_MCSPO, ~0, 0);
 409        SPEX_ARRAY8(mcs5glpo, SSB_SPROM8_5GL_MCSPO, ~0, 0);
 410        SPEX_ARRAY8(mcs5ghpo, SSB_SPROM8_5GH_MCSPO, ~0, 0);
 411
 412        SPEX(rawtempsense, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_RAWTEMP,
 413             SSB_SPROM8_RAWTS_RAWTEMP_SHIFT);
 414        SPEX(measpower, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_MEASPOWER,
 415             SSB_SPROM8_RAWTS_MEASPOWER_SHIFT);
 416        SPEX(tempsense_slope, SSB_SPROM8_OPT_CORRX,
 417             SSB_SPROM8_OPT_CORRX_TEMP_SLOPE,
 418             SSB_SPROM8_OPT_CORRX_TEMP_SLOPE_SHIFT);
 419        SPEX(tempcorrx, SSB_SPROM8_OPT_CORRX, SSB_SPROM8_OPT_CORRX_TEMPCORRX,
 420             SSB_SPROM8_OPT_CORRX_TEMPCORRX_SHIFT);
 421        SPEX(tempsense_option, SSB_SPROM8_OPT_CORRX,
 422             SSB_SPROM8_OPT_CORRX_TEMP_OPTION,
 423             SSB_SPROM8_OPT_CORRX_TEMP_OPTION_SHIFT);
 424        SPEX(freqoffset_corr, SSB_SPROM8_HWIQ_IQSWP,
 425             SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR,
 426             SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR_SHIFT);
 427        SPEX(iqcal_swp_dis, SSB_SPROM8_HWIQ_IQSWP,
 428             SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP,
 429             SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP_SHIFT);
 430        SPEX(hw_iqcal_en, SSB_SPROM8_HWIQ_IQSWP, SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL,
 431             SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL_SHIFT);
 432
 433        SPEX(bw40po, SSB_SPROM8_BW40PO, ~0, 0);
 434        SPEX(cddpo, SSB_SPROM8_CDDPO, ~0, 0);
 435        SPEX(stbcpo, SSB_SPROM8_STBCPO, ~0, 0);
 436        SPEX(bwduppo, SSB_SPROM8_BWDUPPO, ~0, 0);
 437
 438        SPEX(tempthresh, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_TRESH,
 439             SSB_SPROM8_THERMAL_TRESH_SHIFT);
 440        SPEX(tempoffset, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_OFFSET,
 441             SSB_SPROM8_THERMAL_OFFSET_SHIFT);
 442        SPEX(phycal_tempdelta, SSB_SPROM8_TEMPDELTA,
 443             SSB_SPROM8_TEMPDELTA_PHYCAL,
 444             SSB_SPROM8_TEMPDELTA_PHYCAL_SHIFT);
 445        SPEX(temps_period, SSB_SPROM8_TEMPDELTA, SSB_SPROM8_TEMPDELTA_PERIOD,
 446             SSB_SPROM8_TEMPDELTA_PERIOD_SHIFT);
 447        SPEX(temps_hysteresis, SSB_SPROM8_TEMPDELTA,
 448             SSB_SPROM8_TEMPDELTA_HYSTERESIS,
 449             SSB_SPROM8_TEMPDELTA_HYSTERESIS_SHIFT);
 450}
 451
 452/*
 453 * Indicates the presence of external SPROM.
 454 */
 455static bool bcma_sprom_ext_available(struct bcma_bus *bus)
 456{
 457        u32 chip_status;
 458        u32 srom_control;
 459        u32 present_mask;
 460
 461        if (bus->drv_cc.core->id.rev >= 31) {
 462                if (!(bus->drv_cc.capabilities & BCMA_CC_CAP_SPROM))
 463                        return false;
 464
 465                srom_control = bcma_read32(bus->drv_cc.core,
 466                                           BCMA_CC_SROM_CONTROL);
 467                return srom_control & BCMA_CC_SROM_CONTROL_PRESENT;
 468        }
 469
 470        /* older chipcommon revisions use chip status register */
 471        chip_status = bcma_read32(bus->drv_cc.core, BCMA_CC_CHIPSTAT);
 472        switch (bus->chipinfo.id) {
 473        case BCMA_CHIP_ID_BCM4313:
 474                present_mask = BCMA_CC_CHIPST_4313_SPROM_PRESENT;
 475                break;
 476
 477        case BCMA_CHIP_ID_BCM4331:
 478                present_mask = BCMA_CC_CHIPST_4331_SPROM_PRESENT;
 479                break;
 480
 481        default:
 482                return true;
 483        }
 484
 485        return chip_status & present_mask;
 486}
 487
 488/*
 489 * Indicates that on-chip OTP memory is present and enabled.
 490 */
 491static bool bcma_sprom_onchip_available(struct bcma_bus *bus)
 492{
 493        u32 chip_status;
 494        u32 otpsize = 0;
 495        bool present;
 496
 497        chip_status = bcma_read32(bus->drv_cc.core, BCMA_CC_CHIPSTAT);
 498        switch (bus->chipinfo.id) {
 499        case BCMA_CHIP_ID_BCM4313:
 500                present = chip_status & BCMA_CC_CHIPST_4313_OTP_PRESENT;
 501                break;
 502
 503        case BCMA_CHIP_ID_BCM4331:
 504                present = chip_status & BCMA_CC_CHIPST_4331_OTP_PRESENT;
 505                break;
 506        case BCMA_CHIP_ID_BCM43142:
 507        case BCMA_CHIP_ID_BCM43224:
 508        case BCMA_CHIP_ID_BCM43225:
 509                /* for these chips OTP is always available */
 510                present = true;
 511                break;
 512        case BCMA_CHIP_ID_BCM43227:
 513        case BCMA_CHIP_ID_BCM43228:
 514        case BCMA_CHIP_ID_BCM43428:
 515                present = chip_status & BCMA_CC_CHIPST_43228_OTP_PRESENT;
 516                break;
 517        default:
 518                present = false;
 519                break;
 520        }
 521
 522        if (present) {
 523                otpsize = bus->drv_cc.capabilities & BCMA_CC_CAP_OTPS;
 524                otpsize >>= BCMA_CC_CAP_OTPS_SHIFT;
 525        }
 526
 527        return otpsize != 0;
 528}
 529
 530/*
 531 * Verify OTP is filled and determine the byte
 532 * offset where SPROM data is located.
 533 *
 534 * On error, returns 0; byte offset otherwise.
 535 */
 536static int bcma_sprom_onchip_offset(struct bcma_bus *bus)
 537{
 538        struct bcma_device *cc = bus->drv_cc.core;
 539        u32 offset;
 540
 541        /* verify OTP status */
 542        if ((bcma_read32(cc, BCMA_CC_OTPS) & BCMA_CC_OTPS_GU_PROG_HW) == 0)
 543                return 0;
 544
 545        /* obtain bit offset from otplayout register */
 546        offset = (bcma_read32(cc, BCMA_CC_OTPL) & BCMA_CC_OTPL_GURGN_OFFSET);
 547        return BCMA_CC_SPROM + (offset >> 3);
 548}
 549
 550int bcma_sprom_get(struct bcma_bus *bus)
 551{
 552        u16 offset = BCMA_CC_SPROM;
 553        u16 *sprom;
 554        size_t sprom_sizes[] = { SSB_SPROMSIZE_WORDS_R4,
 555                                 SSB_SPROMSIZE_WORDS_R10, };
 556        int i, err = 0;
 557
 558        if (!bus->drv_cc.core)
 559                return -EOPNOTSUPP;
 560
 561        if (!bcma_sprom_ext_available(bus)) {
 562                bool sprom_onchip;
 563
 564                /*
 565                 * External SPROM takes precedence so check
 566                 * on-chip OTP only when no external SPROM
 567                 * is present.
 568                 */
 569                sprom_onchip = bcma_sprom_onchip_available(bus);
 570                if (sprom_onchip) {
 571                        /* determine offset */
 572                        offset = bcma_sprom_onchip_offset(bus);
 573                }
 574                if (!offset || !sprom_onchip) {
 575                        /*
 576                         * Maybe there is no SPROM on the device?
 577                         * Now we ask the arch code if there is some sprom
 578                         * available for this device in some other storage.
 579                         */
 580                        err = bcma_fill_sprom_with_fallback(bus, &bus->sprom);
 581                        return err;
 582                }
 583        }
 584
 585        if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4331 ||
 586            bus->chipinfo.id == BCMA_CHIP_ID_BCM43431)
 587                bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, false);
 588
 589        bcma_debug(bus, "SPROM offset 0x%x\n", offset);
 590        for (i = 0; i < ARRAY_SIZE(sprom_sizes); i++) {
 591                size_t words = sprom_sizes[i];
 592
 593                sprom = kcalloc(words, sizeof(u16), GFP_KERNEL);
 594                if (!sprom)
 595                        return -ENOMEM;
 596
 597                bcma_sprom_read(bus, offset, sprom, words);
 598                err = bcma_sprom_valid(bus, sprom, words);
 599                if (!err)
 600                        break;
 601
 602                kfree(sprom);
 603        }
 604
 605        if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4331 ||
 606            bus->chipinfo.id == BCMA_CHIP_ID_BCM43431)
 607                bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true);
 608
 609        if (err) {
 610                bcma_warn(bus, "Invalid SPROM read from the PCIe card, trying to use fallback SPROM\n");
 611                err = bcma_fill_sprom_with_fallback(bus, &bus->sprom);
 612        } else {
 613                bcma_sprom_extract_r8(bus, sprom);
 614                kfree(sprom);
 615        }
 616
 617        return err;
 618}
 619
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.