Linux Audio

Check our new training course

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