982 lines
30 KiB
C
982 lines
30 KiB
C
/*
|
|
* Copyright (c) 2010 Broadcom Corporation
|
|
*
|
|
* Permission to use, copy, modify, and/or distribute this software for any
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
* copyright notice and this permission notice appear in all copies.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
|
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
|
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/string.h>
|
|
#include <linux/io.h>
|
|
#include <linux/etherdevice.h>
|
|
#include <linux/crc8.h>
|
|
#include <stdarg.h>
|
|
|
|
#include <chipcommon.h>
|
|
#include <brcmu_utils.h>
|
|
#include "pub.h"
|
|
#include "nicpci.h"
|
|
#include "aiutils.h"
|
|
#include "otp.h"
|
|
#include "srom.h"
|
|
#include "soc.h"
|
|
|
|
/*
|
|
* SROM CRC8 polynomial value:
|
|
*
|
|
* x^8 + x^7 +x^6 + x^4 + x^2 + 1
|
|
*/
|
|
#define SROM_CRC8_POLY 0xAB
|
|
|
|
/* Maximum srom: 6 Kilobits == 768 bytes */
|
|
#define SROM_MAX 768
|
|
|
|
/* PCI fields */
|
|
#define PCI_F0DEVID 48
|
|
|
|
#define SROM_WORDS 64
|
|
|
|
#define SROM_SSID 2
|
|
|
|
#define SROM_WL1LHMAXP 29
|
|
|
|
#define SROM_WL1LPAB0 30
|
|
#define SROM_WL1LPAB1 31
|
|
#define SROM_WL1LPAB2 32
|
|
|
|
#define SROM_WL1HPAB0 33
|
|
#define SROM_WL1HPAB1 34
|
|
#define SROM_WL1HPAB2 35
|
|
|
|
#define SROM_MACHI_IL0 36
|
|
#define SROM_MACMID_IL0 37
|
|
#define SROM_MACLO_IL0 38
|
|
#define SROM_MACHI_ET1 42
|
|
#define SROM_MACMID_ET1 43
|
|
#define SROM_MACLO_ET1 44
|
|
|
|
#define SROM_BXARSSI2G 40
|
|
#define SROM_BXARSSI5G 41
|
|
|
|
#define SROM_TRI52G 42
|
|
#define SROM_TRI5GHL 43
|
|
|
|
#define SROM_RXPO52G 45
|
|
|
|
#define SROM_AABREV 46
|
|
/* Fields in AABREV */
|
|
#define SROM_BR_MASK 0x00ff
|
|
#define SROM_CC_MASK 0x0f00
|
|
#define SROM_CC_SHIFT 8
|
|
#define SROM_AA0_MASK 0x3000
|
|
#define SROM_AA0_SHIFT 12
|
|
#define SROM_AA1_MASK 0xc000
|
|
#define SROM_AA1_SHIFT 14
|
|
|
|
#define SROM_WL0PAB0 47
|
|
#define SROM_WL0PAB1 48
|
|
#define SROM_WL0PAB2 49
|
|
|
|
#define SROM_LEDBH10 50
|
|
#define SROM_LEDBH32 51
|
|
|
|
#define SROM_WL10MAXP 52
|
|
|
|
#define SROM_WL1PAB0 53
|
|
#define SROM_WL1PAB1 54
|
|
#define SROM_WL1PAB2 55
|
|
|
|
#define SROM_ITT 56
|
|
|
|
#define SROM_BFL 57
|
|
#define SROM_BFL2 28
|
|
|
|
#define SROM_AG10 58
|
|
|
|
#define SROM_CCODE 59
|
|
|
|
#define SROM_OPO 60
|
|
|
|
#define SROM_CRCREV 63
|
|
|
|
#define SROM4_WORDS 220
|
|
|
|
#define SROM4_TXCHAIN_MASK 0x000f
|
|
#define SROM4_RXCHAIN_MASK 0x00f0
|
|
#define SROM4_SWITCH_MASK 0xff00
|
|
|
|
/* Per-path fields */
|
|
#define MAX_PATH_SROM 4
|
|
|
|
#define SROM4_CRCREV 219
|
|
|
|
/* SROM Rev 8: Make space for a 48word hardware header for PCIe rev >= 6.
|
|
* This is acombined srom for both MIMO and SISO boards, usable in
|
|
* the .130 4Kilobit OTP with hardware redundancy.
|
|
*/
|
|
#define SROM8_BREV 65
|
|
|
|
#define SROM8_BFL0 66
|
|
#define SROM8_BFL1 67
|
|
#define SROM8_BFL2 68
|
|
#define SROM8_BFL3 69
|
|
|
|
#define SROM8_MACHI 70
|
|
#define SROM8_MACMID 71
|
|
#define SROM8_MACLO 72
|
|
|
|
#define SROM8_CCODE 73
|
|
#define SROM8_REGREV 74
|
|
|
|
#define SROM8_LEDBH10 75
|
|
#define SROM8_LEDBH32 76
|
|
|
|
#define SROM8_LEDDC 77
|
|
|
|
#define SROM8_AA 78
|
|
|
|
#define SROM8_AG10 79
|
|
#define SROM8_AG32 80
|
|
|
|
#define SROM8_TXRXC 81
|
|
|
|
#define SROM8_BXARSSI2G 82
|
|
#define SROM8_BXARSSI5G 83
|
|
#define SROM8_TRI52G 84
|
|
#define SROM8_TRI5GHL 85
|
|
#define SROM8_RXPO52G 86
|
|
|
|
#define SROM8_FEM2G 87
|
|
#define SROM8_FEM5G 88
|
|
#define SROM8_FEM_ANTSWLUT_MASK 0xf800
|
|
#define SROM8_FEM_ANTSWLUT_SHIFT 11
|
|
#define SROM8_FEM_TR_ISO_MASK 0x0700
|
|
#define SROM8_FEM_TR_ISO_SHIFT 8
|
|
#define SROM8_FEM_PDET_RANGE_MASK 0x00f8
|
|
#define SROM8_FEM_PDET_RANGE_SHIFT 3
|
|
#define SROM8_FEM_EXTPA_GAIN_MASK 0x0006
|
|
#define SROM8_FEM_EXTPA_GAIN_SHIFT 1
|
|
#define SROM8_FEM_TSSIPOS_MASK 0x0001
|
|
#define SROM8_FEM_TSSIPOS_SHIFT 0
|
|
|
|
#define SROM8_THERMAL 89
|
|
|
|
/* Temp sense related entries */
|
|
#define SROM8_MPWR_RAWTS 90
|
|
#define SROM8_TS_SLP_OPT_CORRX 91
|
|
/* FOC: freiquency offset correction, HWIQ: H/W IOCAL enable,
|
|
* IQSWP: IQ CAL swap disable */
|
|
#define SROM8_FOC_HWIQ_IQSWP 92
|
|
|
|
/* Temperature delta for PHY calibration */
|
|
#define SROM8_PHYCAL_TEMPDELTA 93
|
|
|
|
/* Per-path offsets & fields */
|
|
#define SROM8_PATH0 96
|
|
#define SROM8_PATH1 112
|
|
#define SROM8_PATH2 128
|
|
#define SROM8_PATH3 144
|
|
|
|
#define SROM8_2G_ITT_MAXP 0
|
|
#define SROM8_2G_PA 1
|
|
#define SROM8_5G_ITT_MAXP 4
|
|
#define SROM8_5GLH_MAXP 5
|
|
#define SROM8_5G_PA 6
|
|
#define SROM8_5GL_PA 9
|
|
#define SROM8_5GH_PA 12
|
|
|
|
/* All the miriad power offsets */
|
|
#define SROM8_2G_CCKPO 160
|
|
|
|
#define SROM8_2G_OFDMPO 161
|
|
#define SROM8_5G_OFDMPO 163
|
|
#define SROM8_5GL_OFDMPO 165
|
|
#define SROM8_5GH_OFDMPO 167
|
|
|
|
#define SROM8_2G_MCSPO 169
|
|
#define SROM8_5G_MCSPO 177
|
|
#define SROM8_5GL_MCSPO 185
|
|
#define SROM8_5GH_MCSPO 193
|
|
|
|
#define SROM8_CDDPO 201
|
|
#define SROM8_STBCPO 202
|
|
#define SROM8_BW40PO 203
|
|
#define SROM8_BWDUPPO 204
|
|
|
|
/* SISO PA parameters are in the path0 spaces */
|
|
#define SROM8_SISO 96
|
|
|
|
/* Legacy names for SISO PA paramters */
|
|
#define SROM8_W0_ITTMAXP (SROM8_SISO + SROM8_2G_ITT_MAXP)
|
|
#define SROM8_W0_PAB0 (SROM8_SISO + SROM8_2G_PA)
|
|
#define SROM8_W0_PAB1 (SROM8_SISO + SROM8_2G_PA + 1)
|
|
#define SROM8_W0_PAB2 (SROM8_SISO + SROM8_2G_PA + 2)
|
|
#define SROM8_W1_ITTMAXP (SROM8_SISO + SROM8_5G_ITT_MAXP)
|
|
#define SROM8_W1_MAXP_LCHC (SROM8_SISO + SROM8_5GLH_MAXP)
|
|
#define SROM8_W1_PAB0 (SROM8_SISO + SROM8_5G_PA)
|
|
#define SROM8_W1_PAB1 (SROM8_SISO + SROM8_5G_PA + 1)
|
|
#define SROM8_W1_PAB2 (SROM8_SISO + SROM8_5G_PA + 2)
|
|
#define SROM8_W1_PAB0_LC (SROM8_SISO + SROM8_5GL_PA)
|
|
#define SROM8_W1_PAB1_LC (SROM8_SISO + SROM8_5GL_PA + 1)
|
|
#define SROM8_W1_PAB2_LC (SROM8_SISO + SROM8_5GL_PA + 2)
|
|
#define SROM8_W1_PAB0_HC (SROM8_SISO + SROM8_5GH_PA)
|
|
#define SROM8_W1_PAB1_HC (SROM8_SISO + SROM8_5GH_PA + 1)
|
|
#define SROM8_W1_PAB2_HC (SROM8_SISO + SROM8_5GH_PA + 2)
|
|
|
|
/* SROM REV 9 */
|
|
#define SROM9_2GPO_CCKBW20 160
|
|
#define SROM9_2GPO_CCKBW20UL 161
|
|
#define SROM9_2GPO_LOFDMBW20 162
|
|
#define SROM9_2GPO_LOFDMBW20UL 164
|
|
|
|
#define SROM9_5GLPO_LOFDMBW20 166
|
|
#define SROM9_5GLPO_LOFDMBW20UL 168
|
|
#define SROM9_5GMPO_LOFDMBW20 170
|
|
#define SROM9_5GMPO_LOFDMBW20UL 172
|
|
#define SROM9_5GHPO_LOFDMBW20 174
|
|
#define SROM9_5GHPO_LOFDMBW20UL 176
|
|
|
|
#define SROM9_2GPO_MCSBW20 178
|
|
#define SROM9_2GPO_MCSBW20UL 180
|
|
#define SROM9_2GPO_MCSBW40 182
|
|
|
|
#define SROM9_5GLPO_MCSBW20 184
|
|
#define SROM9_5GLPO_MCSBW20UL 186
|
|
#define SROM9_5GLPO_MCSBW40 188
|
|
#define SROM9_5GMPO_MCSBW20 190
|
|
#define SROM9_5GMPO_MCSBW20UL 192
|
|
#define SROM9_5GMPO_MCSBW40 194
|
|
#define SROM9_5GHPO_MCSBW20 196
|
|
#define SROM9_5GHPO_MCSBW20UL 198
|
|
#define SROM9_5GHPO_MCSBW40 200
|
|
|
|
#define SROM9_PO_MCS32 202
|
|
#define SROM9_PO_LOFDM40DUP 203
|
|
|
|
/* SROM flags (see sromvar_t) */
|
|
|
|
/* value continues as described by the next entry */
|
|
#define SRFL_MORE 1
|
|
#define SRFL_NOFFS 2 /* value bits can't be all one's */
|
|
#define SRFL_PRHEX 4 /* value is in hexdecimal format */
|
|
#define SRFL_PRSIGN 8 /* value is in signed decimal format */
|
|
#define SRFL_CCODE 0x10 /* value is in country code format */
|
|
#define SRFL_ETHADDR 0x20 /* value is an Ethernet address */
|
|
#define SRFL_LEDDC 0x40 /* value is an LED duty cycle */
|
|
/* do not generate a nvram param, entry is for mfgc */
|
|
#define SRFL_NOVAR 0x80
|
|
|
|
/* Max. nvram variable table size */
|
|
#define MAXSZ_NVRAM_VARS 4096
|
|
|
|
/*
|
|
* indicates type of value.
|
|
*/
|
|
enum brcms_srom_var_type {
|
|
BRCMS_SROM_STRING,
|
|
BRCMS_SROM_SNUMBER,
|
|
BRCMS_SROM_UNUMBER
|
|
};
|
|
|
|
/*
|
|
* storage type for srom variable.
|
|
*
|
|
* var_list: for linked list operations.
|
|
* varid: identifier of the variable.
|
|
* var_type: type of variable.
|
|
* buf: variable value when var_type == BRCMS_SROM_STRING.
|
|
* uval: unsigned variable value when var_type == BRCMS_SROM_UNUMBER.
|
|
* sval: signed variable value when var_type == BRCMS_SROM_SNUMBER.
|
|
*/
|
|
struct brcms_srom_list_head {
|
|
struct list_head var_list;
|
|
enum brcms_srom_id varid;
|
|
enum brcms_srom_var_type var_type;
|
|
union {
|
|
char buf[0];
|
|
u32 uval;
|
|
s32 sval;
|
|
};
|
|
};
|
|
|
|
struct brcms_sromvar {
|
|
enum brcms_srom_id varid;
|
|
u32 revmask;
|
|
u32 flags;
|
|
u16 off;
|
|
u16 mask;
|
|
};
|
|
|
|
struct brcms_varbuf {
|
|
char *base; /* pointer to buffer base */
|
|
char *buf; /* pointer to current position */
|
|
unsigned int size; /* current (residual) size in bytes */
|
|
};
|
|
|
|
/*
|
|
* Assumptions:
|
|
* - Ethernet address spans across 3 consecutive words
|
|
*
|
|
* Table rules:
|
|
* - Add multiple entries next to each other if a value spans across multiple
|
|
* words (even multiple fields in the same word) with each entry except the
|
|
* last having it's SRFL_MORE bit set.
|
|
* - Ethernet address entry does not follow above rule and must not have
|
|
* SRFL_MORE bit set. Its SRFL_ETHADDR bit implies it takes multiple words.
|
|
* - The last entry's name field must be NULL to indicate the end of the table.
|
|
* Other entries must have non-NULL name.
|
|
*/
|
|
static const struct brcms_sromvar pci_sromvars[] = {
|
|
{BRCMS_SROM_DEVID, 0xffffff00, SRFL_PRHEX | SRFL_NOVAR, PCI_F0DEVID,
|
|
0xffff},
|
|
{BRCMS_SROM_BOARDREV, 0xffffff00, SRFL_PRHEX, SROM8_BREV, 0xffff},
|
|
{BRCMS_SROM_BOARDFLAGS, 0xffffff00, SRFL_PRHEX | SRFL_MORE, SROM8_BFL0,
|
|
0xffff},
|
|
{BRCMS_SROM_CONT, 0, 0, SROM8_BFL1, 0xffff},
|
|
{BRCMS_SROM_BOARDFLAGS2, 0xffffff00, SRFL_PRHEX | SRFL_MORE, SROM8_BFL2,
|
|
0xffff},
|
|
{BRCMS_SROM_CONT, 0, 0, SROM8_BFL3, 0xffff},
|
|
{BRCMS_SROM_BOARDTYPE, 0xfffffffc, SRFL_PRHEX, SROM_SSID, 0xffff},
|
|
{BRCMS_SROM_BOARDNUM, 0xffffff00, 0, SROM8_MACLO, 0xffff},
|
|
{BRCMS_SROM_REGREV, 0xffffff00, 0, SROM8_REGREV, 0x00ff},
|
|
{BRCMS_SROM_LEDBH0, 0xffffff00, SRFL_NOFFS, SROM8_LEDBH10, 0x00ff},
|
|
{BRCMS_SROM_LEDBH1, 0xffffff00, SRFL_NOFFS, SROM8_LEDBH10, 0xff00},
|
|
{BRCMS_SROM_LEDBH2, 0xffffff00, SRFL_NOFFS, SROM8_LEDBH32, 0x00ff},
|
|
{BRCMS_SROM_LEDBH3, 0xffffff00, SRFL_NOFFS, SROM8_LEDBH32, 0xff00},
|
|
{BRCMS_SROM_PA0B0, 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB0, 0xffff},
|
|
{BRCMS_SROM_PA0B1, 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB1, 0xffff},
|
|
{BRCMS_SROM_PA0B2, 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB2, 0xffff},
|
|
{BRCMS_SROM_PA0ITSSIT, 0xffffff00, 0, SROM8_W0_ITTMAXP, 0xff00},
|
|
{BRCMS_SROM_PA0MAXPWR, 0xffffff00, 0, SROM8_W0_ITTMAXP, 0x00ff},
|
|
{BRCMS_SROM_OPO, 0xffffff00, 0, SROM8_2G_OFDMPO, 0x00ff},
|
|
{BRCMS_SROM_AA2G, 0xffffff00, 0, SROM8_AA, 0x00ff},
|
|
{BRCMS_SROM_AA5G, 0xffffff00, 0, SROM8_AA, 0xff00},
|
|
{BRCMS_SROM_AG0, 0xffffff00, 0, SROM8_AG10, 0x00ff},
|
|
{BRCMS_SROM_AG1, 0xffffff00, 0, SROM8_AG10, 0xff00},
|
|
{BRCMS_SROM_AG2, 0xffffff00, 0, SROM8_AG32, 0x00ff},
|
|
{BRCMS_SROM_AG3, 0xffffff00, 0, SROM8_AG32, 0xff00},
|
|
{BRCMS_SROM_PA1B0, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB0, 0xffff},
|
|
{BRCMS_SROM_PA1B1, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB1, 0xffff},
|
|
{BRCMS_SROM_PA1B2, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB2, 0xffff},
|
|
{BRCMS_SROM_PA1LOB0, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB0_LC, 0xffff},
|
|
{BRCMS_SROM_PA1LOB1, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB1_LC, 0xffff},
|
|
{BRCMS_SROM_PA1LOB2, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB2_LC, 0xffff},
|
|
{BRCMS_SROM_PA1HIB0, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB0_HC, 0xffff},
|
|
{BRCMS_SROM_PA1HIB1, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB1_HC, 0xffff},
|
|
{BRCMS_SROM_PA1HIB2, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB2_HC, 0xffff},
|
|
{BRCMS_SROM_PA1ITSSIT, 0xffffff00, 0, SROM8_W1_ITTMAXP, 0xff00},
|
|
{BRCMS_SROM_PA1MAXPWR, 0xffffff00, 0, SROM8_W1_ITTMAXP, 0x00ff},
|
|
{BRCMS_SROM_PA1LOMAXPWR, 0xffffff00, 0, SROM8_W1_MAXP_LCHC, 0xff00},
|
|
{BRCMS_SROM_PA1HIMAXPWR, 0xffffff00, 0, SROM8_W1_MAXP_LCHC, 0x00ff},
|
|
{BRCMS_SROM_BXA2G, 0xffffff00, 0, SROM8_BXARSSI2G, 0x1800},
|
|
{BRCMS_SROM_RSSISAV2G, 0xffffff00, 0, SROM8_BXARSSI2G, 0x0700},
|
|
{BRCMS_SROM_RSSISMC2G, 0xffffff00, 0, SROM8_BXARSSI2G, 0x00f0},
|
|
{BRCMS_SROM_RSSISMF2G, 0xffffff00, 0, SROM8_BXARSSI2G, 0x000f},
|
|
{BRCMS_SROM_BXA5G, 0xffffff00, 0, SROM8_BXARSSI5G, 0x1800},
|
|
{BRCMS_SROM_RSSISAV5G, 0xffffff00, 0, SROM8_BXARSSI5G, 0x0700},
|
|
{BRCMS_SROM_RSSISMC5G, 0xffffff00, 0, SROM8_BXARSSI5G, 0x00f0},
|
|
{BRCMS_SROM_RSSISMF5G, 0xffffff00, 0, SROM8_BXARSSI5G, 0x000f},
|
|
{BRCMS_SROM_TRI2G, 0xffffff00, 0, SROM8_TRI52G, 0x00ff},
|
|
{BRCMS_SROM_TRI5G, 0xffffff00, 0, SROM8_TRI52G, 0xff00},
|
|
{BRCMS_SROM_TRI5GL, 0xffffff00, 0, SROM8_TRI5GHL, 0x00ff},
|
|
{BRCMS_SROM_TRI5GH, 0xffffff00, 0, SROM8_TRI5GHL, 0xff00},
|
|
{BRCMS_SROM_RXPO2G, 0xffffff00, SRFL_PRSIGN, SROM8_RXPO52G, 0x00ff},
|
|
{BRCMS_SROM_RXPO5G, 0xffffff00, SRFL_PRSIGN, SROM8_RXPO52G, 0xff00},
|
|
{BRCMS_SROM_TXCHAIN, 0xffffff00, SRFL_NOFFS, SROM8_TXRXC,
|
|
SROM4_TXCHAIN_MASK},
|
|
{BRCMS_SROM_RXCHAIN, 0xffffff00, SRFL_NOFFS, SROM8_TXRXC,
|
|
SROM4_RXCHAIN_MASK},
|
|
{BRCMS_SROM_ANTSWITCH, 0xffffff00, SRFL_NOFFS, SROM8_TXRXC,
|
|
SROM4_SWITCH_MASK},
|
|
{BRCMS_SROM_TSSIPOS2G, 0xffffff00, 0, SROM8_FEM2G,
|
|
SROM8_FEM_TSSIPOS_MASK},
|
|
{BRCMS_SROM_EXTPAGAIN2G, 0xffffff00, 0, SROM8_FEM2G,
|
|
SROM8_FEM_EXTPA_GAIN_MASK},
|
|
{BRCMS_SROM_PDETRANGE2G, 0xffffff00, 0, SROM8_FEM2G,
|
|
SROM8_FEM_PDET_RANGE_MASK},
|
|
{BRCMS_SROM_TRISO2G, 0xffffff00, 0, SROM8_FEM2G, SROM8_FEM_TR_ISO_MASK},
|
|
{BRCMS_SROM_ANTSWCTL2G, 0xffffff00, 0, SROM8_FEM2G,
|
|
SROM8_FEM_ANTSWLUT_MASK},
|
|
{BRCMS_SROM_TSSIPOS5G, 0xffffff00, 0, SROM8_FEM5G,
|
|
SROM8_FEM_TSSIPOS_MASK},
|
|
{BRCMS_SROM_EXTPAGAIN5G, 0xffffff00, 0, SROM8_FEM5G,
|
|
SROM8_FEM_EXTPA_GAIN_MASK},
|
|
{BRCMS_SROM_PDETRANGE5G, 0xffffff00, 0, SROM8_FEM5G,
|
|
SROM8_FEM_PDET_RANGE_MASK},
|
|
{BRCMS_SROM_TRISO5G, 0xffffff00, 0, SROM8_FEM5G, SROM8_FEM_TR_ISO_MASK},
|
|
{BRCMS_SROM_ANTSWCTL5G, 0xffffff00, 0, SROM8_FEM5G,
|
|
SROM8_FEM_ANTSWLUT_MASK},
|
|
{BRCMS_SROM_TEMPTHRESH, 0xffffff00, 0, SROM8_THERMAL, 0xff00},
|
|
{BRCMS_SROM_TEMPOFFSET, 0xffffff00, 0, SROM8_THERMAL, 0x00ff},
|
|
|
|
{BRCMS_SROM_CCODE, 0xffffff00, SRFL_CCODE, SROM8_CCODE, 0xffff},
|
|
{BRCMS_SROM_MACADDR, 0xffffff00, SRFL_ETHADDR, SROM8_MACHI, 0xffff},
|
|
{BRCMS_SROM_LEDDC, 0xffffff00, SRFL_NOFFS | SRFL_LEDDC, SROM8_LEDDC,
|
|
0xffff},
|
|
{BRCMS_SROM_RAWTEMPSENSE, 0xffffff00, SRFL_PRHEX, SROM8_MPWR_RAWTS,
|
|
0x01ff},
|
|
{BRCMS_SROM_MEASPOWER, 0xffffff00, SRFL_PRHEX, SROM8_MPWR_RAWTS,
|
|
0xfe00},
|
|
{BRCMS_SROM_TEMPSENSE_SLOPE, 0xffffff00, SRFL_PRHEX,
|
|
SROM8_TS_SLP_OPT_CORRX, 0x00ff},
|
|
{BRCMS_SROM_TEMPCORRX, 0xffffff00, SRFL_PRHEX, SROM8_TS_SLP_OPT_CORRX,
|
|
0xfc00},
|
|
{BRCMS_SROM_TEMPSENSE_OPTION, 0xffffff00, SRFL_PRHEX,
|
|
SROM8_TS_SLP_OPT_CORRX, 0x0300},
|
|
{BRCMS_SROM_FREQOFFSET_CORR, 0xffffff00, SRFL_PRHEX,
|
|
SROM8_FOC_HWIQ_IQSWP, 0x000f},
|
|
{BRCMS_SROM_IQCAL_SWP_DIS, 0xffffff00, SRFL_PRHEX, SROM8_FOC_HWIQ_IQSWP,
|
|
0x0010},
|
|
{BRCMS_SROM_HW_IQCAL_EN, 0xffffff00, SRFL_PRHEX, SROM8_FOC_HWIQ_IQSWP,
|
|
0x0020},
|
|
{BRCMS_SROM_PHYCAL_TEMPDELTA, 0xffffff00, 0, SROM8_PHYCAL_TEMPDELTA,
|
|
0x00ff},
|
|
|
|
{BRCMS_SROM_CCK2GPO, 0x00000100, 0, SROM8_2G_CCKPO, 0xffff},
|
|
{BRCMS_SROM_OFDM2GPO, 0x00000100, SRFL_MORE, SROM8_2G_OFDMPO, 0xffff},
|
|
{BRCMS_SROM_CONT, 0, 0, SROM8_2G_OFDMPO + 1, 0xffff},
|
|
{BRCMS_SROM_OFDM5GPO, 0x00000100, SRFL_MORE, SROM8_5G_OFDMPO, 0xffff},
|
|
{BRCMS_SROM_CONT, 0, 0, SROM8_5G_OFDMPO + 1, 0xffff},
|
|
{BRCMS_SROM_OFDM5GLPO, 0x00000100, SRFL_MORE, SROM8_5GL_OFDMPO, 0xffff},
|
|
{BRCMS_SROM_CONT, 0, 0, SROM8_5GL_OFDMPO + 1, 0xffff},
|
|
{BRCMS_SROM_OFDM5GHPO, 0x00000100, SRFL_MORE, SROM8_5GH_OFDMPO, 0xffff},
|
|
{BRCMS_SROM_CONT, 0, 0, SROM8_5GH_OFDMPO + 1, 0xffff},
|
|
{BRCMS_SROM_MCS2GPO0, 0x00000100, 0, SROM8_2G_MCSPO, 0xffff},
|
|
{BRCMS_SROM_MCS2GPO1, 0x00000100, 0, SROM8_2G_MCSPO + 1, 0xffff},
|
|
{BRCMS_SROM_MCS2GPO2, 0x00000100, 0, SROM8_2G_MCSPO + 2, 0xffff},
|
|
{BRCMS_SROM_MCS2GPO3, 0x00000100, 0, SROM8_2G_MCSPO + 3, 0xffff},
|
|
{BRCMS_SROM_MCS2GPO4, 0x00000100, 0, SROM8_2G_MCSPO + 4, 0xffff},
|
|
{BRCMS_SROM_MCS2GPO5, 0x00000100, 0, SROM8_2G_MCSPO + 5, 0xffff},
|
|
{BRCMS_SROM_MCS2GPO6, 0x00000100, 0, SROM8_2G_MCSPO + 6, 0xffff},
|
|
{BRCMS_SROM_MCS2GPO7, 0x00000100, 0, SROM8_2G_MCSPO + 7, 0xffff},
|
|
{BRCMS_SROM_MCS5GPO0, 0x00000100, 0, SROM8_5G_MCSPO, 0xffff},
|
|
{BRCMS_SROM_MCS5GPO1, 0x00000100, 0, SROM8_5G_MCSPO + 1, 0xffff},
|
|
{BRCMS_SROM_MCS5GPO2, 0x00000100, 0, SROM8_5G_MCSPO + 2, 0xffff},
|
|
{BRCMS_SROM_MCS5GPO3, 0x00000100, 0, SROM8_5G_MCSPO + 3, 0xffff},
|
|
{BRCMS_SROM_MCS5GPO4, 0x00000100, 0, SROM8_5G_MCSPO + 4, 0xffff},
|
|
{BRCMS_SROM_MCS5GPO5, 0x00000100, 0, SROM8_5G_MCSPO + 5, 0xffff},
|
|
{BRCMS_SROM_MCS5GPO6, 0x00000100, 0, SROM8_5G_MCSPO + 6, 0xffff},
|
|
{BRCMS_SROM_MCS5GPO7, 0x00000100, 0, SROM8_5G_MCSPO + 7, 0xffff},
|
|
{BRCMS_SROM_MCS5GLPO0, 0x00000100, 0, SROM8_5GL_MCSPO, 0xffff},
|
|
{BRCMS_SROM_MCS5GLPO1, 0x00000100, 0, SROM8_5GL_MCSPO + 1, 0xffff},
|
|
{BRCMS_SROM_MCS5GLPO2, 0x00000100, 0, SROM8_5GL_MCSPO + 2, 0xffff},
|
|
{BRCMS_SROM_MCS5GLPO3, 0x00000100, 0, SROM8_5GL_MCSPO + 3, 0xffff},
|
|
{BRCMS_SROM_MCS5GLPO4, 0x00000100, 0, SROM8_5GL_MCSPO + 4, 0xffff},
|
|
{BRCMS_SROM_MCS5GLPO5, 0x00000100, 0, SROM8_5GL_MCSPO + 5, 0xffff},
|
|
{BRCMS_SROM_MCS5GLPO6, 0x00000100, 0, SROM8_5GL_MCSPO + 6, 0xffff},
|
|
{BRCMS_SROM_MCS5GLPO7, 0x00000100, 0, SROM8_5GL_MCSPO + 7, 0xffff},
|
|
{BRCMS_SROM_MCS5GHPO0, 0x00000100, 0, SROM8_5GH_MCSPO, 0xffff},
|
|
{BRCMS_SROM_MCS5GHPO1, 0x00000100, 0, SROM8_5GH_MCSPO + 1, 0xffff},
|
|
{BRCMS_SROM_MCS5GHPO2, 0x00000100, 0, SROM8_5GH_MCSPO + 2, 0xffff},
|
|
{BRCMS_SROM_MCS5GHPO3, 0x00000100, 0, SROM8_5GH_MCSPO + 3, 0xffff},
|
|
{BRCMS_SROM_MCS5GHPO4, 0x00000100, 0, SROM8_5GH_MCSPO + 4, 0xffff},
|
|
{BRCMS_SROM_MCS5GHPO5, 0x00000100, 0, SROM8_5GH_MCSPO + 5, 0xffff},
|
|
{BRCMS_SROM_MCS5GHPO6, 0x00000100, 0, SROM8_5GH_MCSPO + 6, 0xffff},
|
|
{BRCMS_SROM_MCS5GHPO7, 0x00000100, 0, SROM8_5GH_MCSPO + 7, 0xffff},
|
|
{BRCMS_SROM_CDDPO, 0x00000100, 0, SROM8_CDDPO, 0xffff},
|
|
{BRCMS_SROM_STBCPO, 0x00000100, 0, SROM8_STBCPO, 0xffff},
|
|
{BRCMS_SROM_BW40PO, 0x00000100, 0, SROM8_BW40PO, 0xffff},
|
|
{BRCMS_SROM_BWDUPPO, 0x00000100, 0, SROM8_BWDUPPO, 0xffff},
|
|
|
|
/* power per rate from sromrev 9 */
|
|
{BRCMS_SROM_CCKBW202GPO, 0xfffffe00, 0, SROM9_2GPO_CCKBW20, 0xffff},
|
|
{BRCMS_SROM_CCKBW20UL2GPO, 0xfffffe00, 0, SROM9_2GPO_CCKBW20UL, 0xffff},
|
|
{BRCMS_SROM_LEGOFDMBW202GPO, 0xfffffe00, SRFL_MORE,
|
|
SROM9_2GPO_LOFDMBW20, 0xffff},
|
|
{BRCMS_SROM_CONT, 0, 0, SROM9_2GPO_LOFDMBW20 + 1, 0xffff},
|
|
{BRCMS_SROM_LEGOFDMBW20UL2GPO, 0xfffffe00, SRFL_MORE,
|
|
SROM9_2GPO_LOFDMBW20UL, 0xffff},
|
|
{BRCMS_SROM_CONT, 0, 0, SROM9_2GPO_LOFDMBW20UL + 1, 0xffff},
|
|
{BRCMS_SROM_LEGOFDMBW205GLPO, 0xfffffe00, SRFL_MORE,
|
|
SROM9_5GLPO_LOFDMBW20, 0xffff},
|
|
{BRCMS_SROM_CONT, 0, 0, SROM9_5GLPO_LOFDMBW20 + 1, 0xffff},
|
|
{BRCMS_SROM_LEGOFDMBW20UL5GLPO, 0xfffffe00, SRFL_MORE,
|
|
SROM9_5GLPO_LOFDMBW20UL, 0xffff},
|
|
{BRCMS_SROM_CONT, 0, 0, SROM9_5GLPO_LOFDMBW20UL + 1, 0xffff},
|
|
{BRCMS_SROM_LEGOFDMBW205GMPO, 0xfffffe00, SRFL_MORE,
|
|
SROM9_5GMPO_LOFDMBW20, 0xffff},
|
|
{BRCMS_SROM_CONT, 0, 0, SROM9_5GMPO_LOFDMBW20 + 1, 0xffff},
|
|
{BRCMS_SROM_LEGOFDMBW20UL5GMPO, 0xfffffe00, SRFL_MORE,
|
|
SROM9_5GMPO_LOFDMBW20UL, 0xffff},
|
|
{BRCMS_SROM_CONT, 0, 0, SROM9_5GMPO_LOFDMBW20UL + 1, 0xffff},
|
|
{BRCMS_SROM_LEGOFDMBW205GHPO, 0xfffffe00, SRFL_MORE,
|
|
SROM9_5GHPO_LOFDMBW20, 0xffff},
|
|
{BRCMS_SROM_CONT, 0, 0, SROM9_5GHPO_LOFDMBW20 + 1, 0xffff},
|
|
{BRCMS_SROM_LEGOFDMBW20UL5GHPO, 0xfffffe00, SRFL_MORE,
|
|
SROM9_5GHPO_LOFDMBW20UL, 0xffff},
|
|
{BRCMS_SROM_CONT, 0, 0, SROM9_5GHPO_LOFDMBW20UL + 1, 0xffff},
|
|
{BRCMS_SROM_MCSBW202GPO, 0xfffffe00, SRFL_MORE, SROM9_2GPO_MCSBW20,
|
|
0xffff},
|
|
{BRCMS_SROM_CONT, 0, 0, SROM9_2GPO_MCSBW20 + 1, 0xffff},
|
|
{BRCMS_SROM_MCSBW20UL2GPO, 0xfffffe00, SRFL_MORE, SROM9_2GPO_MCSBW20UL,
|
|
0xffff},
|
|
{BRCMS_SROM_CONT, 0, 0, SROM9_2GPO_MCSBW20UL + 1, 0xffff},
|
|
{BRCMS_SROM_MCSBW402GPO, 0xfffffe00, SRFL_MORE, SROM9_2GPO_MCSBW40,
|
|
0xffff},
|
|
{BRCMS_SROM_CONT, 0, 0, SROM9_2GPO_MCSBW40 + 1, 0xffff},
|
|
{BRCMS_SROM_MCSBW205GLPO, 0xfffffe00, SRFL_MORE, SROM9_5GLPO_MCSBW20,
|
|
0xffff},
|
|
{BRCMS_SROM_CONT, 0, 0, SROM9_5GLPO_MCSBW20 + 1, 0xffff},
|
|
{BRCMS_SROM_MCSBW20UL5GLPO, 0xfffffe00, SRFL_MORE,
|
|
SROM9_5GLPO_MCSBW20UL, 0xffff},
|
|
{BRCMS_SROM_CONT, 0, 0, SROM9_5GLPO_MCSBW20UL + 1, 0xffff},
|
|
{BRCMS_SROM_MCSBW405GLPO, 0xfffffe00, SRFL_MORE, SROM9_5GLPO_MCSBW40,
|
|
0xffff},
|
|
{BRCMS_SROM_CONT, 0, 0, SROM9_5GLPO_MCSBW40 + 1, 0xffff},
|
|
{BRCMS_SROM_MCSBW205GMPO, 0xfffffe00, SRFL_MORE, SROM9_5GMPO_MCSBW20,
|
|
0xffff},
|
|
{BRCMS_SROM_CONT, 0, 0, SROM9_5GMPO_MCSBW20 + 1, 0xffff},
|
|
{BRCMS_SROM_MCSBW20UL5GMPO, 0xfffffe00, SRFL_MORE,
|
|
SROM9_5GMPO_MCSBW20UL, 0xffff},
|
|
{BRCMS_SROM_CONT, 0, 0, SROM9_5GMPO_MCSBW20UL + 1, 0xffff},
|
|
{BRCMS_SROM_MCSBW405GMPO, 0xfffffe00, SRFL_MORE, SROM9_5GMPO_MCSBW40,
|
|
0xffff},
|
|
{BRCMS_SROM_CONT, 0, 0, SROM9_5GMPO_MCSBW40 + 1, 0xffff},
|
|
{BRCMS_SROM_MCSBW205GHPO, 0xfffffe00, SRFL_MORE, SROM9_5GHPO_MCSBW20,
|
|
0xffff},
|
|
{BRCMS_SROM_CONT, 0, 0, SROM9_5GHPO_MCSBW20 + 1, 0xffff},
|
|
{BRCMS_SROM_MCSBW20UL5GHPO, 0xfffffe00, SRFL_MORE,
|
|
SROM9_5GHPO_MCSBW20UL, 0xffff},
|
|
{BRCMS_SROM_CONT, 0, 0, SROM9_5GHPO_MCSBW20UL + 1, 0xffff},
|
|
{BRCMS_SROM_MCSBW405GHPO, 0xfffffe00, SRFL_MORE, SROM9_5GHPO_MCSBW40,
|
|
0xffff},
|
|
{BRCMS_SROM_CONT, 0, 0, SROM9_5GHPO_MCSBW40 + 1, 0xffff},
|
|
{BRCMS_SROM_MCS32PO, 0xfffffe00, 0, SROM9_PO_MCS32, 0xffff},
|
|
{BRCMS_SROM_LEGOFDM40DUPPO, 0xfffffe00, 0, SROM9_PO_LOFDM40DUP, 0xffff},
|
|
|
|
{BRCMS_SROM_NULL, 0, 0, 0, 0}
|
|
};
|
|
|
|
static const struct brcms_sromvar perpath_pci_sromvars[] = {
|
|
{BRCMS_SROM_MAXP2GA0, 0xffffff00, 0, SROM8_2G_ITT_MAXP, 0x00ff},
|
|
{BRCMS_SROM_ITT2GA0, 0xffffff00, 0, SROM8_2G_ITT_MAXP, 0xff00},
|
|
{BRCMS_SROM_ITT5GA0, 0xffffff00, 0, SROM8_5G_ITT_MAXP, 0xff00},
|
|
{BRCMS_SROM_PA2GW0A0, 0xffffff00, SRFL_PRHEX, SROM8_2G_PA, 0xffff},
|
|
{BRCMS_SROM_PA2GW1A0, 0xffffff00, SRFL_PRHEX, SROM8_2G_PA + 1, 0xffff},
|
|
{BRCMS_SROM_PA2GW2A0, 0xffffff00, SRFL_PRHEX, SROM8_2G_PA + 2, 0xffff},
|
|
{BRCMS_SROM_MAXP5GA0, 0xffffff00, 0, SROM8_5G_ITT_MAXP, 0x00ff},
|
|
{BRCMS_SROM_MAXP5GHA0, 0xffffff00, 0, SROM8_5GLH_MAXP, 0x00ff},
|
|
{BRCMS_SROM_MAXP5GLA0, 0xffffff00, 0, SROM8_5GLH_MAXP, 0xff00},
|
|
{BRCMS_SROM_PA5GW0A0, 0xffffff00, SRFL_PRHEX, SROM8_5G_PA, 0xffff},
|
|
{BRCMS_SROM_PA5GW1A0, 0xffffff00, SRFL_PRHEX, SROM8_5G_PA + 1, 0xffff},
|
|
{BRCMS_SROM_PA5GW2A0, 0xffffff00, SRFL_PRHEX, SROM8_5G_PA + 2, 0xffff},
|
|
{BRCMS_SROM_PA5GLW0A0, 0xffffff00, SRFL_PRHEX, SROM8_5GL_PA, 0xffff},
|
|
{BRCMS_SROM_PA5GLW1A0, 0xffffff00, SRFL_PRHEX, SROM8_5GL_PA + 1,
|
|
0xffff},
|
|
{BRCMS_SROM_PA5GLW2A0, 0xffffff00, SRFL_PRHEX, SROM8_5GL_PA + 2,
|
|
0xffff},
|
|
{BRCMS_SROM_PA5GHW0A0, 0xffffff00, SRFL_PRHEX, SROM8_5GH_PA, 0xffff},
|
|
{BRCMS_SROM_PA5GHW1A0, 0xffffff00, SRFL_PRHEX, SROM8_5GH_PA + 1,
|
|
0xffff},
|
|
{BRCMS_SROM_PA5GHW2A0, 0xffffff00, SRFL_PRHEX, SROM8_5GH_PA + 2,
|
|
0xffff},
|
|
{BRCMS_SROM_NULL, 0, 0, 0, 0}
|
|
};
|
|
|
|
/* crc table has the same contents for every device instance, so it can be
|
|
* shared between devices. */
|
|
static u8 brcms_srom_crc8_table[CRC8_TABLE_SIZE];
|
|
|
|
static u8 __iomem *
|
|
srom_window_address(struct si_pub *sih, u8 __iomem *curmap)
|
|
{
|
|
if (sih->ccrev < 32)
|
|
return curmap + PCI_BAR0_SPROM_OFFSET;
|
|
if (sih->cccaps & CC_CAP_SROM)
|
|
return curmap + PCI_16KB0_CCREGS_OFFSET + CC_SROM_OTP;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static uint mask_shift(u16 mask)
|
|
{
|
|
uint i;
|
|
for (i = 0; i < (sizeof(mask) << 3); i++) {
|
|
if (mask & (1 << i))
|
|
return i;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static uint mask_width(u16 mask)
|
|
{
|
|
int i;
|
|
for (i = (sizeof(mask) << 3) - 1; i >= 0; i--) {
|
|
if (mask & (1 << i))
|
|
return (uint) (i - mask_shift(mask) + 1);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static inline void le16_to_cpu_buf(u16 *buf, uint nwords)
|
|
{
|
|
while (nwords--)
|
|
*(buf + nwords) = le16_to_cpu(*(__le16 *)(buf + nwords));
|
|
}
|
|
|
|
static inline void cpu_to_le16_buf(u16 *buf, uint nwords)
|
|
{
|
|
while (nwords--)
|
|
*(__le16 *)(buf + nwords) = cpu_to_le16(*(buf + nwords));
|
|
}
|
|
|
|
/*
|
|
* convert binary srom data into linked list of srom variable items.
|
|
*/
|
|
static void
|
|
_initvars_srom_pci(u8 sromrev, u16 *srom, struct list_head *var_list)
|
|
{
|
|
struct brcms_srom_list_head *entry;
|
|
enum brcms_srom_id id;
|
|
u16 w;
|
|
u32 val = 0;
|
|
const struct brcms_sromvar *srv;
|
|
uint width;
|
|
uint flags;
|
|
u32 sr = (1 << sromrev);
|
|
uint p;
|
|
uint pb = SROM8_PATH0;
|
|
const uint psz = SROM8_PATH1 - SROM8_PATH0;
|
|
|
|
/* first store the srom revision */
|
|
entry = kzalloc(sizeof(struct brcms_srom_list_head), GFP_KERNEL);
|
|
entry->varid = BRCMS_SROM_REV;
|
|
entry->var_type = BRCMS_SROM_UNUMBER;
|
|
entry->uval = sromrev;
|
|
list_add(&entry->var_list, var_list);
|
|
|
|
for (srv = pci_sromvars; srv->varid != BRCMS_SROM_NULL; srv++) {
|
|
enum brcms_srom_var_type type;
|
|
u8 ea[ETH_ALEN];
|
|
u8 extra_space = 0;
|
|
|
|
if ((srv->revmask & sr) == 0)
|
|
continue;
|
|
|
|
flags = srv->flags;
|
|
id = srv->varid;
|
|
|
|
/* This entry is for mfgc only. Don't generate param for it, */
|
|
if (flags & SRFL_NOVAR)
|
|
continue;
|
|
|
|
if (flags & SRFL_ETHADDR) {
|
|
/*
|
|
* stored in string format XX:XX:XX:XX:XX:XX (17 chars)
|
|
*/
|
|
ea[0] = (srom[srv->off] >> 8) & 0xff;
|
|
ea[1] = srom[srv->off] & 0xff;
|
|
ea[2] = (srom[srv->off + 1] >> 8) & 0xff;
|
|
ea[3] = srom[srv->off + 1] & 0xff;
|
|
ea[4] = (srom[srv->off + 2] >> 8) & 0xff;
|
|
ea[5] = srom[srv->off + 2] & 0xff;
|
|
/* 17 characters + string terminator - union size */
|
|
extra_space = 18 - sizeof(s32);
|
|
type = BRCMS_SROM_STRING;
|
|
} else {
|
|
w = srom[srv->off];
|
|
val = (w & srv->mask) >> mask_shift(srv->mask);
|
|
width = mask_width(srv->mask);
|
|
|
|
while (srv->flags & SRFL_MORE) {
|
|
srv++;
|
|
if (srv->off == 0)
|
|
continue;
|
|
|
|
w = srom[srv->off];
|
|
val +=
|
|
((w & srv->mask) >> mask_shift(srv->
|
|
mask)) <<
|
|
width;
|
|
width += mask_width(srv->mask);
|
|
}
|
|
|
|
if ((flags & SRFL_NOFFS)
|
|
&& ((int)val == (1 << width) - 1))
|
|
continue;
|
|
|
|
if (flags & SRFL_CCODE) {
|
|
type = BRCMS_SROM_STRING;
|
|
} else if (flags & SRFL_LEDDC) {
|
|
/* LED Powersave duty cycle has to be scaled:
|
|
*(oncount >> 24) (offcount >> 8)
|
|
*/
|
|
u32 w32 = /* oncount */
|
|
(((val >> 8) & 0xff) << 24) |
|
|
/* offcount */
|
|
(((val & 0xff)) << 8);
|
|
type = BRCMS_SROM_UNUMBER;
|
|
val = w32;
|
|
} else if ((flags & SRFL_PRSIGN)
|
|
&& (val & (1 << (width - 1)))) {
|
|
type = BRCMS_SROM_SNUMBER;
|
|
val |= ~0 << width;
|
|
} else
|
|
type = BRCMS_SROM_UNUMBER;
|
|
}
|
|
|
|
entry = kzalloc(sizeof(struct brcms_srom_list_head) +
|
|
extra_space, GFP_KERNEL);
|
|
entry->varid = id;
|
|
entry->var_type = type;
|
|
if (flags & SRFL_ETHADDR) {
|
|
snprintf(entry->buf, 18, "%pM", ea);
|
|
} else if (flags & SRFL_CCODE) {
|
|
if (val == 0)
|
|
entry->buf[0] = '\0';
|
|
else
|
|
snprintf(entry->buf, 3, "%c%c",
|
|
(val >> 8), (val & 0xff));
|
|
} else {
|
|
entry->uval = val;
|
|
}
|
|
|
|
list_add(&entry->var_list, var_list);
|
|
}
|
|
|
|
for (p = 0; p < MAX_PATH_SROM; p++) {
|
|
for (srv = perpath_pci_sromvars;
|
|
srv->varid != BRCMS_SROM_NULL; srv++) {
|
|
if ((srv->revmask & sr) == 0)
|
|
continue;
|
|
|
|
if (srv->flags & SRFL_NOVAR)
|
|
continue;
|
|
|
|
w = srom[pb + srv->off];
|
|
val = (w & srv->mask) >> mask_shift(srv->mask);
|
|
width = mask_width(srv->mask);
|
|
|
|
/* Cheating: no per-path var is more than
|
|
* 1 word */
|
|
if ((srv->flags & SRFL_NOFFS)
|
|
&& ((int)val == (1 << width) - 1))
|
|
continue;
|
|
|
|
entry =
|
|
kzalloc(sizeof(struct brcms_srom_list_head),
|
|
GFP_KERNEL);
|
|
entry->varid = srv->varid+p;
|
|
entry->var_type = BRCMS_SROM_UNUMBER;
|
|
entry->uval = val;
|
|
list_add(&entry->var_list, var_list);
|
|
}
|
|
pb += psz;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Read in and validate sprom.
|
|
* Return 0 on success, nonzero on error.
|
|
*/
|
|
static int
|
|
sprom_read_pci(struct si_pub *sih, u8 __iomem *sprom, uint wordoff,
|
|
u16 *buf, uint nwords, bool check_crc)
|
|
{
|
|
int err = 0;
|
|
uint i;
|
|
u8 *bbuf = (u8 *)buf; /* byte buffer */
|
|
uint nbytes = nwords << 1;
|
|
|
|
/* read the sprom in bytes */
|
|
for (i = 0; i < nbytes; i++)
|
|
bbuf[i] = readb(sprom+i);
|
|
|
|
if (buf[0] == 0xffff)
|
|
/*
|
|
* The hardware thinks that an srom that starts with
|
|
* 0xffff is blank, regardless of the rest of the
|
|
* content, so declare it bad.
|
|
*/
|
|
return -ENODATA;
|
|
|
|
if (check_crc &&
|
|
crc8(brcms_srom_crc8_table, bbuf, nbytes, CRC8_INIT_VALUE) !=
|
|
CRC8_GOOD_VALUE(brcms_srom_crc8_table))
|
|
err = -EIO;
|
|
else
|
|
/* now correct the endianness of the byte array */
|
|
le16_to_cpu_buf(buf, nwords);
|
|
|
|
return err;
|
|
}
|
|
|
|
static int otp_read_pci(struct si_pub *sih, u16 *buf, uint nwords)
|
|
{
|
|
u8 *otp;
|
|
uint sz = OTP_SZ_MAX / 2; /* size in words */
|
|
int err = 0;
|
|
|
|
otp = kzalloc(OTP_SZ_MAX, GFP_ATOMIC);
|
|
if (otp == NULL)
|
|
return -ENOMEM;
|
|
|
|
err = otp_read_region(sih, OTP_HW_RGN, (u16 *) otp, &sz);
|
|
|
|
sz = min_t(uint, sz, nwords);
|
|
memcpy(buf, otp, sz * 2);
|
|
|
|
kfree(otp);
|
|
|
|
/* Check CRC */
|
|
if (buf[0] == 0xffff)
|
|
/* The hardware thinks that an srom that starts with 0xffff
|
|
* is blank, regardless of the rest of the content, so declare
|
|
* it bad.
|
|
*/
|
|
return -ENODATA;
|
|
|
|
/* fixup the endianness so crc8 will pass */
|
|
cpu_to_le16_buf(buf, sz);
|
|
if (crc8(brcms_srom_crc8_table, (u8 *) buf, sz * 2,
|
|
CRC8_INIT_VALUE) != CRC8_GOOD_VALUE(brcms_srom_crc8_table))
|
|
err = -EIO;
|
|
else
|
|
/* now correct the endianness of the byte array */
|
|
le16_to_cpu_buf(buf, sz);
|
|
|
|
return err;
|
|
}
|
|
|
|
/*
|
|
* Initialize nonvolatile variable table from sprom.
|
|
* Return 0 on success, nonzero on error.
|
|
*/
|
|
static int initvars_srom_pci(struct si_pub *sih, void __iomem *curmap)
|
|
{
|
|
u16 *srom;
|
|
u8 __iomem *sromwindow;
|
|
u8 sromrev = 0;
|
|
u32 sr;
|
|
int err = 0;
|
|
|
|
/*
|
|
* Apply CRC over SROM content regardless SROM is present or not.
|
|
*/
|
|
srom = kmalloc(SROM_MAX, GFP_ATOMIC);
|
|
if (!srom)
|
|
return -ENOMEM;
|
|
|
|
sromwindow = srom_window_address(sih, curmap);
|
|
|
|
crc8_populate_lsb(brcms_srom_crc8_table, SROM_CRC8_POLY);
|
|
if (ai_is_sprom_available(sih)) {
|
|
err = sprom_read_pci(sih, sromwindow, 0, srom,
|
|
SROM4_WORDS, true);
|
|
|
|
if (err == 0)
|
|
/* srom read and passed crc */
|
|
/* top word of sprom contains version and crc8 */
|
|
sromrev = srom[SROM4_CRCREV] & 0xff;
|
|
} else {
|
|
/* Use OTP if SPROM not available */
|
|
err = otp_read_pci(sih, srom, SROM4_WORDS);
|
|
if (err == 0)
|
|
/* OTP only contain SROM rev8/rev9 for now */
|
|
sromrev = srom[SROM4_CRCREV] & 0xff;
|
|
}
|
|
|
|
if (!err) {
|
|
struct si_info *sii = (struct si_info *)sih;
|
|
|
|
/* Bitmask for the sromrev */
|
|
sr = 1 << sromrev;
|
|
|
|
/*
|
|
* srom version check: Current valid versions: 8, 9
|
|
*/
|
|
if ((sr & 0x300) == 0) {
|
|
err = -EINVAL;
|
|
goto errout;
|
|
}
|
|
|
|
INIT_LIST_HEAD(&sii->var_list);
|
|
|
|
/* parse SROM into name=value pairs. */
|
|
_initvars_srom_pci(sromrev, srom, &sii->var_list);
|
|
}
|
|
|
|
errout:
|
|
kfree(srom);
|
|
return err;
|
|
}
|
|
|
|
void srom_free_vars(struct si_pub *sih)
|
|
{
|
|
struct si_info *sii;
|
|
struct brcms_srom_list_head *entry, *next;
|
|
|
|
sii = (struct si_info *)sih;
|
|
list_for_each_entry_safe(entry, next, &sii->var_list, var_list) {
|
|
list_del(&entry->var_list);
|
|
kfree(entry);
|
|
}
|
|
}
|
|
/*
|
|
* Initialize local vars from the right source for this platform.
|
|
* Return 0 on success, nonzero on error.
|
|
*/
|
|
int srom_var_init(struct si_pub *sih, void __iomem *curmap)
|
|
{
|
|
uint len;
|
|
|
|
len = 0;
|
|
|
|
if (curmap != NULL)
|
|
return initvars_srom_pci(sih, curmap);
|
|
|
|
return -EINVAL;
|
|
}
|
|
|
|
/*
|
|
* Search the name=value vars for a specific one and return its value.
|
|
* Returns NULL if not found.
|
|
*/
|
|
char *getvar(struct si_pub *sih, enum brcms_srom_id id)
|
|
{
|
|
struct si_info *sii;
|
|
struct brcms_srom_list_head *entry;
|
|
|
|
sii = (struct si_info *)sih;
|
|
|
|
list_for_each_entry(entry, &sii->var_list, var_list)
|
|
if (entry->varid == id)
|
|
return &entry->buf[0];
|
|
|
|
/* nothing found */
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Search the vars for a specific one and return its value as
|
|
* an integer. Returns 0 if not found.-
|
|
*/
|
|
int getintvar(struct si_pub *sih, enum brcms_srom_id id)
|
|
{
|
|
struct si_info *sii;
|
|
struct brcms_srom_list_head *entry;
|
|
unsigned long res;
|
|
|
|
sii = (struct si_info *)sih;
|
|
|
|
list_for_each_entry(entry, &sii->var_list, var_list)
|
|
if (entry->varid == id) {
|
|
if (entry->var_type == BRCMS_SROM_SNUMBER ||
|
|
entry->var_type == BRCMS_SROM_UNUMBER)
|
|
return (int)entry->sval;
|
|
else if (!kstrtoul(&entry->buf[0], 0, &res))
|
|
return (int)res;
|
|
}
|
|
|
|
return 0;
|
|
}
|