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