cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

sprom.c (21411B)


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