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