127f18dc2SRafał Miłecki /*
227f18dc2SRafał Miłecki * Broadcom specific AMBA
327f18dc2SRafał Miłecki * SPROM reading
427f18dc2SRafał Miłecki *
5a027237aSHauke Mehrtens * Copyright 2011, 2012, Hauke Mehrtens <hauke@hauke-m.de>
6a027237aSHauke Mehrtens *
727f18dc2SRafał Miłecki * Licensed under the GNU/GPL. See COPYING for details.
827f18dc2SRafał Miłecki */
927f18dc2SRafał Miłecki
1027f18dc2SRafał Miłecki #include "bcma_private.h"
1127f18dc2SRafał Miłecki
1227f18dc2SRafał Miłecki #include <linux/bcma/bcma.h>
1327f18dc2SRafał Miłecki #include <linux/bcma/bcma_regs.h>
1427f18dc2SRafał Miłecki #include <linux/pci.h>
1527f18dc2SRafał Miłecki #include <linux/io.h>
1627f18dc2SRafał Miłecki #include <linux/dma-mapping.h>
1727f18dc2SRafał Miłecki #include <linux/slab.h>
1827f18dc2SRafał Miłecki
19a027237aSHauke Mehrtens static int(*get_fallback_sprom)(struct bcma_bus *dev, struct ssb_sprom *out);
20a027237aSHauke Mehrtens
21a027237aSHauke Mehrtens /**
22a027237aSHauke Mehrtens * bcma_arch_register_fallback_sprom - Registers a method providing a
23a027237aSHauke Mehrtens * fallback SPROM if no SPROM is found.
24a027237aSHauke Mehrtens *
25a027237aSHauke Mehrtens * @sprom_callback: The callback function.
26a027237aSHauke Mehrtens *
27a027237aSHauke Mehrtens * With this function the architecture implementation may register a
28a027237aSHauke Mehrtens * callback handler which fills the SPROM data structure. The fallback is
29a027237aSHauke Mehrtens * used for PCI based BCMA devices, where no valid SPROM can be found
30a027237aSHauke Mehrtens * in the shadow registers and to provide the SPROM for SoCs where BCMA is
31032931fdSTom Rix * to control the system bus.
32a027237aSHauke Mehrtens *
33a027237aSHauke Mehrtens * This function is useful for weird architectures that have a half-assed
34a027237aSHauke Mehrtens * BCMA device hardwired to their PCI bus.
35a027237aSHauke Mehrtens *
36a027237aSHauke Mehrtens * This function is available for architecture code, only. So it is not
37a027237aSHauke Mehrtens * exported.
38a027237aSHauke Mehrtens */
bcma_arch_register_fallback_sprom(int (* sprom_callback)(struct bcma_bus * bus,struct ssb_sprom * out))39a027237aSHauke Mehrtens int bcma_arch_register_fallback_sprom(int (*sprom_callback)(struct bcma_bus *bus,
40a027237aSHauke Mehrtens struct ssb_sprom *out))
41a027237aSHauke Mehrtens {
42a027237aSHauke Mehrtens if (get_fallback_sprom)
43a027237aSHauke Mehrtens return -EEXIST;
44a027237aSHauke Mehrtens get_fallback_sprom = sprom_callback;
45a027237aSHauke Mehrtens
46a027237aSHauke Mehrtens return 0;
47a027237aSHauke Mehrtens }
48a027237aSHauke Mehrtens
bcma_fill_sprom_with_fallback(struct bcma_bus * bus,struct ssb_sprom * out)49a027237aSHauke Mehrtens static int bcma_fill_sprom_with_fallback(struct bcma_bus *bus,
50a027237aSHauke Mehrtens struct ssb_sprom *out)
51a027237aSHauke Mehrtens {
524ac887cfSArend van Spriel int err;
53a027237aSHauke Mehrtens
544ac887cfSArend van Spriel if (!get_fallback_sprom) {
554ac887cfSArend van Spriel err = -ENOENT;
564ac887cfSArend van Spriel goto fail;
574ac887cfSArend van Spriel }
584ac887cfSArend van Spriel
594ac887cfSArend van Spriel err = get_fallback_sprom(bus, out);
604ac887cfSArend van Spriel if (err)
614ac887cfSArend van Spriel goto fail;
624ac887cfSArend van Spriel
633d9d8af3SRafał Miłecki bcma_debug(bus, "Using SPROM revision %d provided by platform.\n",
643d9d8af3SRafał Miłecki bus->sprom.revision);
654ac887cfSArend van Spriel return 0;
664ac887cfSArend van Spriel fail:
673d9d8af3SRafał Miłecki bcma_warn(bus, "Using fallback SPROM failed (err %d)\n", err);
684ac887cfSArend van Spriel return err;
69a027237aSHauke Mehrtens }
70a027237aSHauke Mehrtens
7127f18dc2SRafał Miłecki /**************************************************
7227f18dc2SRafał Miłecki * R/W ops.
7327f18dc2SRafał Miłecki **************************************************/
7427f18dc2SRafał Miłecki
bcma_sprom_read(struct bcma_bus * bus,u16 offset,u16 * sprom,size_t words)755179ed7cSRafał Miłecki static void bcma_sprom_read(struct bcma_bus *bus, u16 offset, u16 *sprom,
765179ed7cSRafał Miłecki size_t words)
7727f18dc2SRafał Miłecki {
7827f18dc2SRafał Miłecki int i;
795179ed7cSRafał Miłecki for (i = 0; i < words; i++)
805179ed7cSRafał Miłecki sprom[i] = bcma_read16(bus->drv_cc.core, offset + (i * 2));
8127f18dc2SRafał Miłecki }
8227f18dc2SRafał Miłecki
8327f18dc2SRafał Miłecki /**************************************************
8427f18dc2SRafał Miłecki * Validation.
8527f18dc2SRafał Miłecki **************************************************/
8627f18dc2SRafał Miłecki
bcma_crc8(u8 crc,u8 data)8727f18dc2SRafał Miłecki static inline u8 bcma_crc8(u8 crc, u8 data)
8827f18dc2SRafał Miłecki {
8927f18dc2SRafał Miłecki /* Polynomial: x^8 + x^7 + x^6 + x^4 + x^2 + 1 */
9027f18dc2SRafał Miłecki static const u8 t[] = {
9127f18dc2SRafał Miłecki 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
9227f18dc2SRafał Miłecki 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
9327f18dc2SRafał Miłecki 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
9427f18dc2SRafał Miłecki 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
9527f18dc2SRafał Miłecki 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
9627f18dc2SRafał Miłecki 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
9727f18dc2SRafał Miłecki 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
9827f18dc2SRafał Miłecki 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
9927f18dc2SRafał Miłecki 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
10027f18dc2SRafał Miłecki 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
10127f18dc2SRafał Miłecki 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
10227f18dc2SRafał Miłecki 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
10327f18dc2SRafał Miłecki 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
10427f18dc2SRafał Miłecki 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
10527f18dc2SRafał Miłecki 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
10627f18dc2SRafał Miłecki 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
10727f18dc2SRafał Miłecki 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
10827f18dc2SRafał Miłecki 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
10927f18dc2SRafał Miłecki 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
11027f18dc2SRafał Miłecki 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
11127f18dc2SRafał Miłecki 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
11227f18dc2SRafał Miłecki 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
11327f18dc2SRafał Miłecki 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
11427f18dc2SRafał Miłecki 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
11527f18dc2SRafał Miłecki 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
11627f18dc2SRafał Miłecki 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
11727f18dc2SRafał Miłecki 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
11827f18dc2SRafał Miłecki 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
11927f18dc2SRafał Miłecki 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
12027f18dc2SRafał Miłecki 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
12127f18dc2SRafał Miłecki 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
12227f18dc2SRafał Miłecki 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F,
12327f18dc2SRafał Miłecki };
12427f18dc2SRafał Miłecki return t[crc ^ data];
12527f18dc2SRafał Miłecki }
12627f18dc2SRafał Miłecki
bcma_sprom_crc(const u16 * sprom,size_t words)1275179ed7cSRafał Miłecki static u8 bcma_sprom_crc(const u16 *sprom, size_t words)
12827f18dc2SRafał Miłecki {
12927f18dc2SRafał Miłecki int word;
13027f18dc2SRafał Miłecki u8 crc = 0xFF;
13127f18dc2SRafał Miłecki
1325179ed7cSRafał Miłecki for (word = 0; word < words - 1; word++) {
13327f18dc2SRafał Miłecki crc = bcma_crc8(crc, sprom[word] & 0x00FF);
13427f18dc2SRafał Miłecki crc = bcma_crc8(crc, (sprom[word] & 0xFF00) >> 8);
13527f18dc2SRafał Miłecki }
1365179ed7cSRafał Miłecki crc = bcma_crc8(crc, sprom[words - 1] & 0x00FF);
13727f18dc2SRafał Miłecki crc ^= 0xFF;
13827f18dc2SRafał Miłecki
13927f18dc2SRafał Miłecki return crc;
14027f18dc2SRafał Miłecki }
14127f18dc2SRafał Miłecki
bcma_sprom_check_crc(const u16 * sprom,size_t words)1425179ed7cSRafał Miłecki static int bcma_sprom_check_crc(const u16 *sprom, size_t words)
14327f18dc2SRafał Miłecki {
14427f18dc2SRafał Miłecki u8 crc;
14527f18dc2SRafał Miłecki u8 expected_crc;
14627f18dc2SRafał Miłecki u16 tmp;
14727f18dc2SRafał Miłecki
1485179ed7cSRafał Miłecki crc = bcma_sprom_crc(sprom, words);
1495179ed7cSRafał Miłecki tmp = sprom[words - 1] & SSB_SPROM_REVISION_CRC;
15027f18dc2SRafał Miłecki expected_crc = tmp >> SSB_SPROM_REVISION_CRC_SHIFT;
15127f18dc2SRafał Miłecki if (crc != expected_crc)
15227f18dc2SRafał Miłecki return -EPROTO;
15327f18dc2SRafał Miłecki
15427f18dc2SRafał Miłecki return 0;
15527f18dc2SRafał Miłecki }
15627f18dc2SRafał Miłecki
bcma_sprom_valid(struct bcma_bus * bus,const u16 * sprom,size_t words)15778e578c5SRafał Miłecki static int bcma_sprom_valid(struct bcma_bus *bus, const u16 *sprom,
15878e578c5SRafał Miłecki size_t words)
15927f18dc2SRafał Miłecki {
16027f18dc2SRafał Miłecki u16 revision;
16127f18dc2SRafał Miłecki int err;
16227f18dc2SRafał Miłecki
1635179ed7cSRafał Miłecki err = bcma_sprom_check_crc(sprom, words);
16427f18dc2SRafał Miłecki if (err)
16527f18dc2SRafał Miłecki return err;
16627f18dc2SRafał Miłecki
1675179ed7cSRafał Miłecki revision = sprom[words - 1] & SSB_SPROM_REVISION_REV;
168*80bc5ae9SLinus Walleij if (revision < 8 || revision > 11) {
16927f18dc2SRafał Miłecki pr_err("Unsupported SPROM revision: %d\n", revision);
17027f18dc2SRafał Miłecki return -ENOENT;
17127f18dc2SRafał Miłecki }
17227f18dc2SRafał Miłecki
17378e578c5SRafał Miłecki bus->sprom.revision = revision;
17478e578c5SRafał Miłecki bcma_debug(bus, "Found SPROM revision %d\n", revision);
17578e578c5SRafał Miłecki
17627f18dc2SRafał Miłecki return 0;
17727f18dc2SRafał Miłecki }
17827f18dc2SRafał Miłecki
17927f18dc2SRafał Miłecki /**************************************************
18027f18dc2SRafał Miłecki * SPROM extraction.
18127f18dc2SRafał Miłecki **************************************************/
18227f18dc2SRafał Miłecki
183b35a9acaSRafał Miłecki #define SPOFF(offset) ((offset) / sizeof(u16))
184b35a9acaSRafał Miłecki
185b35a9acaSRafał Miłecki #define SPEX(_field, _offset, _mask, _shift) \
186b35a9acaSRafał Miłecki bus->sprom._field = ((sprom[SPOFF(_offset)] & (_mask)) >> (_shift))
187b35a9acaSRafał Miłecki
188432c4d1eSHauke Mehrtens #define SPEX32(_field, _offset, _mask, _shift) \
189432c4d1eSHauke Mehrtens bus->sprom._field = ((((u32)sprom[SPOFF((_offset)+2)] << 16 | \
190432c4d1eSHauke Mehrtens sprom[SPOFF(_offset)]) & (_mask)) >> (_shift))
191432c4d1eSHauke Mehrtens
192e2da4bd3SHauke Mehrtens #define SPEX_ARRAY8(_field, _offset, _mask, _shift) \
193e2da4bd3SHauke Mehrtens do { \
194e2da4bd3SHauke Mehrtens SPEX(_field[0], _offset + 0, _mask, _shift); \
195e2da4bd3SHauke Mehrtens SPEX(_field[1], _offset + 2, _mask, _shift); \
196e2da4bd3SHauke Mehrtens SPEX(_field[2], _offset + 4, _mask, _shift); \
197e2da4bd3SHauke Mehrtens SPEX(_field[3], _offset + 6, _mask, _shift); \
198e2da4bd3SHauke Mehrtens SPEX(_field[4], _offset + 8, _mask, _shift); \
199e2da4bd3SHauke Mehrtens SPEX(_field[5], _offset + 10, _mask, _shift); \
200e2da4bd3SHauke Mehrtens SPEX(_field[6], _offset + 12, _mask, _shift); \
201e2da4bd3SHauke Mehrtens SPEX(_field[7], _offset + 14, _mask, _shift); \
202e2da4bd3SHauke Mehrtens } while (0)
203e2da4bd3SHauke Mehrtens
sprom_extract_antgain(const u16 * in,u16 offset,u16 mask,u16 shift)204d8aef323SRafał Miłecki static s8 sprom_extract_antgain(const u16 *in, u16 offset, u16 mask, u16 shift)
205d8aef323SRafał Miłecki {
206d8aef323SRafał Miłecki u16 v;
207d8aef323SRafał Miłecki u8 gain;
208d8aef323SRafał Miłecki
209d8aef323SRafał Miłecki v = in[SPOFF(offset)];
210d8aef323SRafał Miłecki gain = (v & mask) >> shift;
211d8aef323SRafał Miłecki if (gain == 0xFF) {
212d8aef323SRafał Miłecki gain = 8; /* If unset use 2dBm */
213d8aef323SRafał Miłecki } else {
214d8aef323SRafał Miłecki /* Q5.2 Fractional part is stored in 0xC0 */
215d8aef323SRafał Miłecki gain = ((gain & 0xC0) >> 6) | ((gain & 0x3F) << 2);
216d8aef323SRafał Miłecki }
217d8aef323SRafał Miłecki
218d8aef323SRafał Miłecki return (s8)gain;
219d8aef323SRafał Miłecki }
220d8aef323SRafał Miłecki
bcma_sprom_extract_r8(struct bcma_bus * bus,const u16 * sprom)22127f18dc2SRafał Miłecki static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom)
22227f18dc2SRafał Miłecki {
223507f9a71SRafał Miłecki u16 v, o;
22427f18dc2SRafał Miłecki int i;
225c57391f4SColin Ian King static const u16 pwr_info_offset[] = {
226507f9a71SRafał Miłecki SSB_SROM8_PWR_INFO_CORE0, SSB_SROM8_PWR_INFO_CORE1,
227507f9a71SRafał Miłecki SSB_SROM8_PWR_INFO_CORE2, SSB_SROM8_PWR_INFO_CORE3
228507f9a71SRafał Miłecki };
229507f9a71SRafał Miłecki BUILD_BUG_ON(ARRAY_SIZE(pwr_info_offset) !=
230507f9a71SRafał Miłecki ARRAY_SIZE(bus->sprom.core_pwr_info));
23127f18dc2SRafał Miłecki
23227f18dc2SRafał Miłecki for (i = 0; i < 3; i++) {
23327f18dc2SRafał Miłecki v = sprom[SPOFF(SSB_SPROM8_IL0MAC) + i];
23427f18dc2SRafał Miłecki *(((__be16 *)bus->sprom.il0mac) + i) = cpu_to_be16(v);
23527f18dc2SRafał Miłecki }
236d703a5aeSRafał Miłecki
237b35a9acaSRafał Miłecki SPEX(board_rev, SSB_SPROM8_BOARDREV, ~0, 0);
2387b828f09SRafał Miłecki SPEX(board_type, SSB_SPROM1_SPID, ~0, 0);
239d703a5aeSRafał Miłecki
240b35a9acaSRafał Miłecki SPEX(txpid2g[0], SSB_SPROM4_TXPID2G01, SSB_SPROM4_TXPID2G0,
241b35a9acaSRafał Miłecki SSB_SPROM4_TXPID2G0_SHIFT);
242b35a9acaSRafał Miłecki SPEX(txpid2g[1], SSB_SPROM4_TXPID2G01, SSB_SPROM4_TXPID2G1,
243b35a9acaSRafał Miłecki SSB_SPROM4_TXPID2G1_SHIFT);
244b35a9acaSRafał Miłecki SPEX(txpid2g[2], SSB_SPROM4_TXPID2G23, SSB_SPROM4_TXPID2G2,
245b35a9acaSRafał Miłecki SSB_SPROM4_TXPID2G2_SHIFT);
246b35a9acaSRafał Miłecki SPEX(txpid2g[3], SSB_SPROM4_TXPID2G23, SSB_SPROM4_TXPID2G3,
247b35a9acaSRafał Miłecki SSB_SPROM4_TXPID2G3_SHIFT);
248daadc6b3SRafał Miłecki
249b35a9acaSRafał Miłecki SPEX(txpid5gl[0], SSB_SPROM4_TXPID5GL01, SSB_SPROM4_TXPID5GL0,
250b35a9acaSRafał Miłecki SSB_SPROM4_TXPID5GL0_SHIFT);
251b35a9acaSRafał Miłecki SPEX(txpid5gl[1], SSB_SPROM4_TXPID5GL01, SSB_SPROM4_TXPID5GL1,
252b35a9acaSRafał Miłecki SSB_SPROM4_TXPID5GL1_SHIFT);
253b35a9acaSRafał Miłecki SPEX(txpid5gl[2], SSB_SPROM4_TXPID5GL23, SSB_SPROM4_TXPID5GL2,
254b35a9acaSRafał Miłecki SSB_SPROM4_TXPID5GL2_SHIFT);
255b35a9acaSRafał Miłecki SPEX(txpid5gl[3], SSB_SPROM4_TXPID5GL23, SSB_SPROM4_TXPID5GL3,
256b35a9acaSRafał Miłecki SSB_SPROM4_TXPID5GL3_SHIFT);
257daadc6b3SRafał Miłecki
258b35a9acaSRafał Miłecki SPEX(txpid5g[0], SSB_SPROM4_TXPID5G01, SSB_SPROM4_TXPID5G0,
259b35a9acaSRafał Miłecki SSB_SPROM4_TXPID5G0_SHIFT);
260b35a9acaSRafał Miłecki SPEX(txpid5g[1], SSB_SPROM4_TXPID5G01, SSB_SPROM4_TXPID5G1,
261b35a9acaSRafał Miłecki SSB_SPROM4_TXPID5G1_SHIFT);
262b35a9acaSRafał Miłecki SPEX(txpid5g[2], SSB_SPROM4_TXPID5G23, SSB_SPROM4_TXPID5G2,
263b35a9acaSRafał Miłecki SSB_SPROM4_TXPID5G2_SHIFT);
264b35a9acaSRafał Miłecki SPEX(txpid5g[3], SSB_SPROM4_TXPID5G23, SSB_SPROM4_TXPID5G3,
265b35a9acaSRafał Miłecki SSB_SPROM4_TXPID5G3_SHIFT);
266daadc6b3SRafał Miłecki
267b35a9acaSRafał Miłecki SPEX(txpid5gh[0], SSB_SPROM4_TXPID5GH01, SSB_SPROM4_TXPID5GH0,
268b35a9acaSRafał Miłecki SSB_SPROM4_TXPID5GH0_SHIFT);
269b35a9acaSRafał Miłecki SPEX(txpid5gh[1], SSB_SPROM4_TXPID5GH01, SSB_SPROM4_TXPID5GH1,
270b35a9acaSRafał Miłecki SSB_SPROM4_TXPID5GH1_SHIFT);
271b35a9acaSRafał Miłecki SPEX(txpid5gh[2], SSB_SPROM4_TXPID5GH23, SSB_SPROM4_TXPID5GH2,
272b35a9acaSRafał Miłecki SSB_SPROM4_TXPID5GH2_SHIFT);
273b35a9acaSRafał Miłecki SPEX(txpid5gh[3], SSB_SPROM4_TXPID5GH23, SSB_SPROM4_TXPID5GH3,
274b35a9acaSRafał Miłecki SSB_SPROM4_TXPID5GH3_SHIFT);
275daadc6b3SRafał Miłecki
276b35a9acaSRafał Miłecki SPEX(boardflags_lo, SSB_SPROM8_BFLLO, ~0, 0);
277b35a9acaSRafał Miłecki SPEX(boardflags_hi, SSB_SPROM8_BFLHI, ~0, 0);
278b35a9acaSRafał Miłecki SPEX(boardflags2_lo, SSB_SPROM8_BFL2LO, ~0, 0);
279b35a9acaSRafał Miłecki SPEX(boardflags2_hi, SSB_SPROM8_BFL2HI, ~0, 0);
280d703a5aeSRafał Miłecki
281bf7d420bSHauke Mehrtens SPEX(alpha2[0], SSB_SPROM8_CCODE, 0xff00, 8);
282bf7d420bSHauke Mehrtens SPEX(alpha2[1], SSB_SPROM8_CCODE, 0x00ff, 0);
283aee5ed56SRafał Miłecki
284032931fdSTom Rix /* Extract core's power info */
285507f9a71SRafał Miłecki for (i = 0; i < ARRAY_SIZE(pwr_info_offset); i++) {
286507f9a71SRafał Miłecki o = pwr_info_offset[i];
287507f9a71SRafał Miłecki SPEX(core_pwr_info[i].itssi_2g, o + SSB_SROM8_2G_MAXP_ITSSI,
288507f9a71SRafał Miłecki SSB_SPROM8_2G_ITSSI, SSB_SPROM8_2G_ITSSI_SHIFT);
289507f9a71SRafał Miłecki SPEX(core_pwr_info[i].maxpwr_2g, o + SSB_SROM8_2G_MAXP_ITSSI,
290507f9a71SRafał Miłecki SSB_SPROM8_2G_MAXP, 0);
291507f9a71SRafał Miłecki
292507f9a71SRafał Miłecki SPEX(core_pwr_info[i].pa_2g[0], o + SSB_SROM8_2G_PA_0, ~0, 0);
293507f9a71SRafał Miłecki SPEX(core_pwr_info[i].pa_2g[1], o + SSB_SROM8_2G_PA_1, ~0, 0);
294507f9a71SRafał Miłecki SPEX(core_pwr_info[i].pa_2g[2], o + SSB_SROM8_2G_PA_2, ~0, 0);
295507f9a71SRafał Miłecki
296507f9a71SRafał Miłecki SPEX(core_pwr_info[i].itssi_5g, o + SSB_SROM8_5G_MAXP_ITSSI,
297507f9a71SRafał Miłecki SSB_SPROM8_5G_ITSSI, SSB_SPROM8_5G_ITSSI_SHIFT);
298507f9a71SRafał Miłecki SPEX(core_pwr_info[i].maxpwr_5g, o + SSB_SROM8_5G_MAXP_ITSSI,
299507f9a71SRafał Miłecki SSB_SPROM8_5G_MAXP, 0);
300507f9a71SRafał Miłecki SPEX(core_pwr_info[i].maxpwr_5gh, o + SSB_SPROM8_5GHL_MAXP,
301507f9a71SRafał Miłecki SSB_SPROM8_5GH_MAXP, 0);
302507f9a71SRafał Miłecki SPEX(core_pwr_info[i].maxpwr_5gl, o + SSB_SPROM8_5GHL_MAXP,
303507f9a71SRafał Miłecki SSB_SPROM8_5GL_MAXP, SSB_SPROM8_5GL_MAXP_SHIFT);
304507f9a71SRafał Miłecki
305507f9a71SRafał Miłecki SPEX(core_pwr_info[i].pa_5gl[0], o + SSB_SROM8_5GL_PA_0, ~0, 0);
306507f9a71SRafał Miłecki SPEX(core_pwr_info[i].pa_5gl[1], o + SSB_SROM8_5GL_PA_1, ~0, 0);
307507f9a71SRafał Miłecki SPEX(core_pwr_info[i].pa_5gl[2], o + SSB_SROM8_5GL_PA_2, ~0, 0);
308507f9a71SRafał Miłecki SPEX(core_pwr_info[i].pa_5g[0], o + SSB_SROM8_5G_PA_0, ~0, 0);
309507f9a71SRafał Miłecki SPEX(core_pwr_info[i].pa_5g[1], o + SSB_SROM8_5G_PA_1, ~0, 0);
310507f9a71SRafał Miłecki SPEX(core_pwr_info[i].pa_5g[2], o + SSB_SROM8_5G_PA_2, ~0, 0);
311507f9a71SRafał Miłecki SPEX(core_pwr_info[i].pa_5gh[0], o + SSB_SROM8_5GH_PA_0, ~0, 0);
312507f9a71SRafał Miłecki SPEX(core_pwr_info[i].pa_5gh[1], o + SSB_SROM8_5GH_PA_1, ~0, 0);
313507f9a71SRafał Miłecki SPEX(core_pwr_info[i].pa_5gh[2], o + SSB_SROM8_5GH_PA_2, ~0, 0);
314507f9a71SRafał Miłecki }
315507f9a71SRafał Miłecki
316b35a9acaSRafał Miłecki SPEX(fem.ghz2.tssipos, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_TSSIPOS,
317b35a9acaSRafał Miłecki SSB_SROM8_FEM_TSSIPOS_SHIFT);
318b35a9acaSRafał Miłecki SPEX(fem.ghz2.extpa_gain, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_EXTPA_GAIN,
319b35a9acaSRafał Miłecki SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
320b35a9acaSRafał Miłecki SPEX(fem.ghz2.pdet_range, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_PDET_RANGE,
321b35a9acaSRafał Miłecki SSB_SROM8_FEM_PDET_RANGE_SHIFT);
322b35a9acaSRafał Miłecki SPEX(fem.ghz2.tr_iso, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_TR_ISO,
323b35a9acaSRafał Miłecki SSB_SROM8_FEM_TR_ISO_SHIFT);
324b35a9acaSRafał Miłecki SPEX(fem.ghz2.antswlut, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_ANTSWLUT,
325b35a9acaSRafał Miłecki SSB_SROM8_FEM_ANTSWLUT_SHIFT);
326aee5ed56SRafał Miłecki
327b35a9acaSRafał Miłecki SPEX(fem.ghz5.tssipos, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_TSSIPOS,
328b35a9acaSRafał Miłecki SSB_SROM8_FEM_TSSIPOS_SHIFT);
329b35a9acaSRafał Miłecki SPEX(fem.ghz5.extpa_gain, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_EXTPA_GAIN,
330b35a9acaSRafał Miłecki SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
331b35a9acaSRafał Miłecki SPEX(fem.ghz5.pdet_range, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_PDET_RANGE,
332b35a9acaSRafał Miłecki SSB_SROM8_FEM_PDET_RANGE_SHIFT);
333b35a9acaSRafał Miłecki SPEX(fem.ghz5.tr_iso, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_TR_ISO,
334b35a9acaSRafał Miłecki SSB_SROM8_FEM_TR_ISO_SHIFT);
335b35a9acaSRafał Miłecki SPEX(fem.ghz5.antswlut, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_ANTSWLUT,
336b35a9acaSRafał Miłecki SSB_SROM8_FEM_ANTSWLUT_SHIFT);
337432c4d1eSHauke Mehrtens
338432c4d1eSHauke Mehrtens SPEX(ant_available_a, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_A,
339432c4d1eSHauke Mehrtens SSB_SPROM8_ANTAVAIL_A_SHIFT);
340432c4d1eSHauke Mehrtens SPEX(ant_available_bg, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_BG,
341432c4d1eSHauke Mehrtens SSB_SPROM8_ANTAVAIL_BG_SHIFT);
342432c4d1eSHauke Mehrtens SPEX(maxpwr_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_MAXP_BG_MASK, 0);
343432c4d1eSHauke Mehrtens SPEX(itssi_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_ITSSI_BG,
344432c4d1eSHauke Mehrtens SSB_SPROM8_ITSSI_BG_SHIFT);
345432c4d1eSHauke Mehrtens SPEX(maxpwr_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_MAXP_A_MASK, 0);
346432c4d1eSHauke Mehrtens SPEX(itssi_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_ITSSI_A,
347432c4d1eSHauke Mehrtens SSB_SPROM8_ITSSI_A_SHIFT);
348432c4d1eSHauke Mehrtens SPEX(maxpwr_ah, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AH_MASK, 0);
349432c4d1eSHauke Mehrtens SPEX(maxpwr_al, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AL_MASK,
350432c4d1eSHauke Mehrtens SSB_SPROM8_MAXP_AL_SHIFT);
351432c4d1eSHauke Mehrtens SPEX(gpio0, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P0, 0);
352432c4d1eSHauke Mehrtens SPEX(gpio1, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P1,
353432c4d1eSHauke Mehrtens SSB_SPROM8_GPIOA_P1_SHIFT);
354432c4d1eSHauke Mehrtens SPEX(gpio2, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P2, 0);
355432c4d1eSHauke Mehrtens SPEX(gpio3, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P3,
356432c4d1eSHauke Mehrtens SSB_SPROM8_GPIOB_P3_SHIFT);
357432c4d1eSHauke Mehrtens SPEX(tri2g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI2G, 0);
358432c4d1eSHauke Mehrtens SPEX(tri5g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI5G,
359432c4d1eSHauke Mehrtens SSB_SPROM8_TRI5G_SHIFT);
360432c4d1eSHauke Mehrtens SPEX(tri5gl, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GL, 0);
361432c4d1eSHauke Mehrtens SPEX(tri5gh, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GH,
362432c4d1eSHauke Mehrtens SSB_SPROM8_TRI5GH_SHIFT);
363432c4d1eSHauke Mehrtens SPEX(rxpo2g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO2G,
364432c4d1eSHauke Mehrtens SSB_SPROM8_RXPO2G_SHIFT);
365432c4d1eSHauke Mehrtens SPEX(rxpo5g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO5G,
366432c4d1eSHauke Mehrtens SSB_SPROM8_RXPO5G_SHIFT);
367432c4d1eSHauke Mehrtens SPEX(rssismf2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMF2G, 0);
368432c4d1eSHauke Mehrtens SPEX(rssismc2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMC2G,
369432c4d1eSHauke Mehrtens SSB_SPROM8_RSSISMC2G_SHIFT);
370432c4d1eSHauke Mehrtens SPEX(rssisav2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISAV2G,
371432c4d1eSHauke Mehrtens SSB_SPROM8_RSSISAV2G_SHIFT);
372432c4d1eSHauke Mehrtens SPEX(bxa2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_BXA2G,
373432c4d1eSHauke Mehrtens SSB_SPROM8_BXA2G_SHIFT);
374432c4d1eSHauke Mehrtens SPEX(rssismf5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMF5G, 0);
375432c4d1eSHauke Mehrtens SPEX(rssismc5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMC5G,
376432c4d1eSHauke Mehrtens SSB_SPROM8_RSSISMC5G_SHIFT);
377432c4d1eSHauke Mehrtens SPEX(rssisav5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISAV5G,
378432c4d1eSHauke Mehrtens SSB_SPROM8_RSSISAV5G_SHIFT);
379432c4d1eSHauke Mehrtens SPEX(bxa5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_BXA5G,
380432c4d1eSHauke Mehrtens SSB_SPROM8_BXA5G_SHIFT);
381432c4d1eSHauke Mehrtens
382432c4d1eSHauke Mehrtens SPEX(pa0b0, SSB_SPROM8_PA0B0, ~0, 0);
383432c4d1eSHauke Mehrtens SPEX(pa0b1, SSB_SPROM8_PA0B1, ~0, 0);
384432c4d1eSHauke Mehrtens SPEX(pa0b2, SSB_SPROM8_PA0B2, ~0, 0);
385432c4d1eSHauke Mehrtens SPEX(pa1b0, SSB_SPROM8_PA1B0, ~0, 0);
386432c4d1eSHauke Mehrtens SPEX(pa1b1, SSB_SPROM8_PA1B1, ~0, 0);
387432c4d1eSHauke Mehrtens SPEX(pa1b2, SSB_SPROM8_PA1B2, ~0, 0);
388432c4d1eSHauke Mehrtens SPEX(pa1lob0, SSB_SPROM8_PA1LOB0, ~0, 0);
389432c4d1eSHauke Mehrtens SPEX(pa1lob1, SSB_SPROM8_PA1LOB1, ~0, 0);
390432c4d1eSHauke Mehrtens SPEX(pa1lob2, SSB_SPROM8_PA1LOB2, ~0, 0);
391432c4d1eSHauke Mehrtens SPEX(pa1hib0, SSB_SPROM8_PA1HIB0, ~0, 0);
392432c4d1eSHauke Mehrtens SPEX(pa1hib1, SSB_SPROM8_PA1HIB1, ~0, 0);
393432c4d1eSHauke Mehrtens SPEX(pa1hib2, SSB_SPROM8_PA1HIB2, ~0, 0);
394432c4d1eSHauke Mehrtens SPEX(cck2gpo, SSB_SPROM8_CCK2GPO, ~0, 0);
395432c4d1eSHauke Mehrtens SPEX32(ofdm2gpo, SSB_SPROM8_OFDM2GPO, ~0, 0);
396432c4d1eSHauke Mehrtens SPEX32(ofdm5glpo, SSB_SPROM8_OFDM5GLPO, ~0, 0);
397432c4d1eSHauke Mehrtens SPEX32(ofdm5gpo, SSB_SPROM8_OFDM5GPO, ~0, 0);
398432c4d1eSHauke Mehrtens SPEX32(ofdm5ghpo, SSB_SPROM8_OFDM5GHPO, ~0, 0);
399432c4d1eSHauke Mehrtens
400432c4d1eSHauke Mehrtens /* Extract the antenna gain values. */
401d8aef323SRafał Miłecki bus->sprom.antenna_gain.a0 = sprom_extract_antgain(sprom,
402d8aef323SRafał Miłecki SSB_SPROM8_AGAIN01,
403d8aef323SRafał Miłecki SSB_SPROM8_AGAIN0,
404d8aef323SRafał Miłecki SSB_SPROM8_AGAIN0_SHIFT);
405d8aef323SRafał Miłecki bus->sprom.antenna_gain.a1 = sprom_extract_antgain(sprom,
406d8aef323SRafał Miłecki SSB_SPROM8_AGAIN01,
407d8aef323SRafał Miłecki SSB_SPROM8_AGAIN1,
408d8aef323SRafał Miłecki SSB_SPROM8_AGAIN1_SHIFT);
409d8aef323SRafał Miłecki bus->sprom.antenna_gain.a2 = sprom_extract_antgain(sprom,
410d8aef323SRafał Miłecki SSB_SPROM8_AGAIN23,
411d8aef323SRafał Miłecki SSB_SPROM8_AGAIN2,
412d8aef323SRafał Miłecki SSB_SPROM8_AGAIN2_SHIFT);
413d8aef323SRafał Miłecki bus->sprom.antenna_gain.a3 = sprom_extract_antgain(sprom,
414d8aef323SRafał Miłecki SSB_SPROM8_AGAIN23,
415d8aef323SRafał Miłecki SSB_SPROM8_AGAIN3,
416d8aef323SRafał Miłecki SSB_SPROM8_AGAIN3_SHIFT);
417e2da4bd3SHauke Mehrtens
418e2da4bd3SHauke Mehrtens SPEX(leddc_on_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_ON,
419e2da4bd3SHauke Mehrtens SSB_SPROM8_LEDDC_ON_SHIFT);
420e2da4bd3SHauke Mehrtens SPEX(leddc_off_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_OFF,
421e2da4bd3SHauke Mehrtens SSB_SPROM8_LEDDC_OFF_SHIFT);
422e2da4bd3SHauke Mehrtens
423e2da4bd3SHauke Mehrtens SPEX(txchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_TXCHAIN,
424e2da4bd3SHauke Mehrtens SSB_SPROM8_TXRXC_TXCHAIN_SHIFT);
425e2da4bd3SHauke Mehrtens SPEX(rxchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_RXCHAIN,
426e2da4bd3SHauke Mehrtens SSB_SPROM8_TXRXC_RXCHAIN_SHIFT);
427e2da4bd3SHauke Mehrtens SPEX(antswitch, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_SWITCH,
428e2da4bd3SHauke Mehrtens SSB_SPROM8_TXRXC_SWITCH_SHIFT);
429e2da4bd3SHauke Mehrtens
430e2da4bd3SHauke Mehrtens SPEX(opo, SSB_SPROM8_OFDM2GPO, 0x00ff, 0);
431e2da4bd3SHauke Mehrtens
432e2da4bd3SHauke Mehrtens SPEX_ARRAY8(mcs2gpo, SSB_SPROM8_2G_MCSPO, ~0, 0);
433e2da4bd3SHauke Mehrtens SPEX_ARRAY8(mcs5gpo, SSB_SPROM8_5G_MCSPO, ~0, 0);
434e2da4bd3SHauke Mehrtens SPEX_ARRAY8(mcs5glpo, SSB_SPROM8_5GL_MCSPO, ~0, 0);
435e2da4bd3SHauke Mehrtens SPEX_ARRAY8(mcs5ghpo, SSB_SPROM8_5GH_MCSPO, ~0, 0);
436e2da4bd3SHauke Mehrtens
437e2da4bd3SHauke Mehrtens SPEX(rawtempsense, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_RAWTEMP,
438e2da4bd3SHauke Mehrtens SSB_SPROM8_RAWTS_RAWTEMP_SHIFT);
439e2da4bd3SHauke Mehrtens SPEX(measpower, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_MEASPOWER,
440e2da4bd3SHauke Mehrtens SSB_SPROM8_RAWTS_MEASPOWER_SHIFT);
441e2da4bd3SHauke Mehrtens SPEX(tempsense_slope, SSB_SPROM8_OPT_CORRX,
442e2da4bd3SHauke Mehrtens SSB_SPROM8_OPT_CORRX_TEMP_SLOPE,
443e2da4bd3SHauke Mehrtens SSB_SPROM8_OPT_CORRX_TEMP_SLOPE_SHIFT);
444e2da4bd3SHauke Mehrtens SPEX(tempcorrx, SSB_SPROM8_OPT_CORRX, SSB_SPROM8_OPT_CORRX_TEMPCORRX,
445e2da4bd3SHauke Mehrtens SSB_SPROM8_OPT_CORRX_TEMPCORRX_SHIFT);
446e2da4bd3SHauke Mehrtens SPEX(tempsense_option, SSB_SPROM8_OPT_CORRX,
447e2da4bd3SHauke Mehrtens SSB_SPROM8_OPT_CORRX_TEMP_OPTION,
448e2da4bd3SHauke Mehrtens SSB_SPROM8_OPT_CORRX_TEMP_OPTION_SHIFT);
449e2da4bd3SHauke Mehrtens SPEX(freqoffset_corr, SSB_SPROM8_HWIQ_IQSWP,
450e2da4bd3SHauke Mehrtens SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR,
451e2da4bd3SHauke Mehrtens SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR_SHIFT);
452e2da4bd3SHauke Mehrtens SPEX(iqcal_swp_dis, SSB_SPROM8_HWIQ_IQSWP,
453e2da4bd3SHauke Mehrtens SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP,
454e2da4bd3SHauke Mehrtens SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP_SHIFT);
455e2da4bd3SHauke Mehrtens SPEX(hw_iqcal_en, SSB_SPROM8_HWIQ_IQSWP, SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL,
456e2da4bd3SHauke Mehrtens SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL_SHIFT);
457e2da4bd3SHauke Mehrtens
458e2da4bd3SHauke Mehrtens SPEX(bw40po, SSB_SPROM8_BW40PO, ~0, 0);
459e2da4bd3SHauke Mehrtens SPEX(cddpo, SSB_SPROM8_CDDPO, ~0, 0);
460e2da4bd3SHauke Mehrtens SPEX(stbcpo, SSB_SPROM8_STBCPO, ~0, 0);
461e2da4bd3SHauke Mehrtens SPEX(bwduppo, SSB_SPROM8_BWDUPPO, ~0, 0);
462e2da4bd3SHauke Mehrtens
463e2da4bd3SHauke Mehrtens SPEX(tempthresh, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_TRESH,
464e2da4bd3SHauke Mehrtens SSB_SPROM8_THERMAL_TRESH_SHIFT);
465e2da4bd3SHauke Mehrtens SPEX(tempoffset, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_OFFSET,
466e2da4bd3SHauke Mehrtens SSB_SPROM8_THERMAL_OFFSET_SHIFT);
467e2da4bd3SHauke Mehrtens SPEX(phycal_tempdelta, SSB_SPROM8_TEMPDELTA,
468e2da4bd3SHauke Mehrtens SSB_SPROM8_TEMPDELTA_PHYCAL,
469e2da4bd3SHauke Mehrtens SSB_SPROM8_TEMPDELTA_PHYCAL_SHIFT);
470e2da4bd3SHauke Mehrtens SPEX(temps_period, SSB_SPROM8_TEMPDELTA, SSB_SPROM8_TEMPDELTA_PERIOD,
471e2da4bd3SHauke Mehrtens SSB_SPROM8_TEMPDELTA_PERIOD_SHIFT);
472e2da4bd3SHauke Mehrtens SPEX(temps_hysteresis, SSB_SPROM8_TEMPDELTA,
473e2da4bd3SHauke Mehrtens SSB_SPROM8_TEMPDELTA_HYSTERESIS,
474e2da4bd3SHauke Mehrtens SSB_SPROM8_TEMPDELTA_HYSTERESIS_SHIFT);
47527f18dc2SRafał Miłecki }
47627f18dc2SRafał Miłecki
47710d8493cSArend van Spriel /*
47810d8493cSArend van Spriel * Indicates the presence of external SPROM.
47910d8493cSArend van Spriel */
bcma_sprom_ext_available(struct bcma_bus * bus)48010d8493cSArend van Spriel static bool bcma_sprom_ext_available(struct bcma_bus *bus)
481a027237aSHauke Mehrtens {
48210d8493cSArend van Spriel u32 chip_status;
48310d8493cSArend van Spriel u32 srom_control;
48410d8493cSArend van Spriel u32 present_mask;
485a027237aSHauke Mehrtens
48610d8493cSArend van Spriel if (bus->drv_cc.core->id.rev >= 31) {
487a027237aSHauke Mehrtens if (!(bus->drv_cc.capabilities & BCMA_CC_CAP_SPROM))
488a027237aSHauke Mehrtens return false;
489a027237aSHauke Mehrtens
49010d8493cSArend van Spriel srom_control = bcma_read32(bus->drv_cc.core,
49110d8493cSArend van Spriel BCMA_CC_SROM_CONTROL);
49210d8493cSArend van Spriel return srom_control & BCMA_CC_SROM_CONTROL_PRESENT;
493a027237aSHauke Mehrtens }
49410d8493cSArend van Spriel
49510d8493cSArend van Spriel /* older chipcommon revisions use chip status register */
49610d8493cSArend van Spriel chip_status = bcma_read32(bus->drv_cc.core, BCMA_CC_CHIPSTAT);
49710d8493cSArend van Spriel switch (bus->chipinfo.id) {
4984b4f5be2SHauke Mehrtens case BCMA_CHIP_ID_BCM4313:
49910d8493cSArend van Spriel present_mask = BCMA_CC_CHIPST_4313_SPROM_PRESENT;
50010d8493cSArend van Spriel break;
50110d8493cSArend van Spriel
5024b4f5be2SHauke Mehrtens case BCMA_CHIP_ID_BCM4331:
50310d8493cSArend van Spriel present_mask = BCMA_CC_CHIPST_4331_SPROM_PRESENT;
50410d8493cSArend van Spriel break;
50510d8493cSArend van Spriel
50610d8493cSArend van Spriel default:
507a027237aSHauke Mehrtens return true;
508a027237aSHauke Mehrtens }
509a027237aSHauke Mehrtens
51010d8493cSArend van Spriel return chip_status & present_mask;
51110d8493cSArend van Spriel }
51210d8493cSArend van Spriel
51310d8493cSArend van Spriel /*
51410d8493cSArend van Spriel * Indicates that on-chip OTP memory is present and enabled.
51510d8493cSArend van Spriel */
bcma_sprom_onchip_available(struct bcma_bus * bus)51610d8493cSArend van Spriel static bool bcma_sprom_onchip_available(struct bcma_bus *bus)
51710d8493cSArend van Spriel {
51810d8493cSArend van Spriel u32 chip_status;
51910d8493cSArend van Spriel u32 otpsize = 0;
52010d8493cSArend van Spriel bool present;
52110d8493cSArend van Spriel
52210d8493cSArend van Spriel chip_status = bcma_read32(bus->drv_cc.core, BCMA_CC_CHIPSTAT);
52310d8493cSArend van Spriel switch (bus->chipinfo.id) {
5244b4f5be2SHauke Mehrtens case BCMA_CHIP_ID_BCM4313:
52510d8493cSArend van Spriel present = chip_status & BCMA_CC_CHIPST_4313_OTP_PRESENT;
52610d8493cSArend van Spriel break;
52710d8493cSArend van Spriel
5284b4f5be2SHauke Mehrtens case BCMA_CHIP_ID_BCM4331:
52910d8493cSArend van Spriel present = chip_status & BCMA_CC_CHIPST_4331_OTP_PRESENT;
53010d8493cSArend van Spriel break;
53188f9b65dSRafał Miłecki case BCMA_CHIP_ID_BCM43142:
5324b4f5be2SHauke Mehrtens case BCMA_CHIP_ID_BCM43224:
5334b4f5be2SHauke Mehrtens case BCMA_CHIP_ID_BCM43225:
53410d8493cSArend van Spriel /* for these chips OTP is always available */
53510d8493cSArend van Spriel present = true;
53610d8493cSArend van Spriel break;
53727cfdb05SRafał Miłecki case BCMA_CHIP_ID_BCM43131:
538d1d3799fSRafał Miłecki case BCMA_CHIP_ID_BCM43217:
539646e0827SRafał Miłecki case BCMA_CHIP_ID_BCM43227:
540c263c2c1SRafał Miłecki case BCMA_CHIP_ID_BCM43228:
541646e0827SRafał Miłecki case BCMA_CHIP_ID_BCM43428:
542c263c2c1SRafał Miłecki present = chip_status & BCMA_CC_CHIPST_43228_OTP_PRESENT;
543c263c2c1SRafał Miłecki break;
54410d8493cSArend van Spriel default:
54510d8493cSArend van Spriel present = false;
54610d8493cSArend van Spriel break;
54710d8493cSArend van Spriel }
54810d8493cSArend van Spriel
54910d8493cSArend van Spriel if (present) {
55010d8493cSArend van Spriel otpsize = bus->drv_cc.capabilities & BCMA_CC_CAP_OTPS;
55110d8493cSArend van Spriel otpsize >>= BCMA_CC_CAP_OTPS_SHIFT;
55210d8493cSArend van Spriel }
55310d8493cSArend van Spriel
55410d8493cSArend van Spriel return otpsize != 0;
55510d8493cSArend van Spriel }
55610d8493cSArend van Spriel
55710d8493cSArend van Spriel /*
55810d8493cSArend van Spriel * Verify OTP is filled and determine the byte
55910d8493cSArend van Spriel * offset where SPROM data is located.
56010d8493cSArend van Spriel *
56110d8493cSArend van Spriel * On error, returns 0; byte offset otherwise.
56210d8493cSArend van Spriel */
bcma_sprom_onchip_offset(struct bcma_bus * bus)56310d8493cSArend van Spriel static int bcma_sprom_onchip_offset(struct bcma_bus *bus)
56410d8493cSArend van Spriel {
56510d8493cSArend van Spriel struct bcma_device *cc = bus->drv_cc.core;
56610d8493cSArend van Spriel u32 offset;
56710d8493cSArend van Spriel
56810d8493cSArend van Spriel /* verify OTP status */
56910d8493cSArend van Spriel if ((bcma_read32(cc, BCMA_CC_OTPS) & BCMA_CC_OTPS_GU_PROG_HW) == 0)
57010d8493cSArend van Spriel return 0;
57110d8493cSArend van Spriel
57210d8493cSArend van Spriel /* obtain bit offset from otplayout register */
57310d8493cSArend van Spriel offset = (bcma_read32(cc, BCMA_CC_OTPL) & BCMA_CC_OTPL_GURGN_OFFSET);
57410d8493cSArend van Spriel return BCMA_CC_SPROM + (offset >> 3);
57510d8493cSArend van Spriel }
57610d8493cSArend van Spriel
bcma_sprom_get(struct bcma_bus * bus)57727f18dc2SRafał Miłecki int bcma_sprom_get(struct bcma_bus *bus)
57827f18dc2SRafał Miłecki {
57910d8493cSArend van Spriel u16 offset = BCMA_CC_SPROM;
58027f18dc2SRafał Miłecki u16 *sprom;
581c57391f4SColin Ian King static const size_t sprom_sizes[] = {
582c57391f4SColin Ian King SSB_SPROMSIZE_WORDS_R4,
5833c313161SRafał Miłecki SSB_SPROMSIZE_WORDS_R10,
584c57391f4SColin Ian King SSB_SPROMSIZE_WORDS_R11,
585c57391f4SColin Ian King };
58692eb1642SRafał Miłecki int i, err = 0;
58727f18dc2SRafał Miłecki
58827f18dc2SRafał Miłecki if (!bus->drv_cc.core)
58927f18dc2SRafał Miłecki return -EOPNOTSUPP;
59027f18dc2SRafał Miłecki
59110d8493cSArend van Spriel if (!bcma_sprom_ext_available(bus)) {
59232998cc9SHauke Mehrtens bool sprom_onchip;
59332998cc9SHauke Mehrtens
59410d8493cSArend van Spriel /*
59510d8493cSArend van Spriel * External SPROM takes precedence so check
59610d8493cSArend van Spriel * on-chip OTP only when no external SPROM
59710d8493cSArend van Spriel * is present.
59810d8493cSArend van Spriel */
59932998cc9SHauke Mehrtens sprom_onchip = bcma_sprom_onchip_available(bus);
60032998cc9SHauke Mehrtens if (sprom_onchip) {
60110d8493cSArend van Spriel /* determine offset */
60210d8493cSArend van Spriel offset = bcma_sprom_onchip_offset(bus);
60310d8493cSArend van Spriel }
60432998cc9SHauke Mehrtens if (!offset || !sprom_onchip) {
605a027237aSHauke Mehrtens /*
606a027237aSHauke Mehrtens * Maybe there is no SPROM on the device?
607a027237aSHauke Mehrtens * Now we ask the arch code if there is some sprom
608a027237aSHauke Mehrtens * available for this device in some other storage.
609a027237aSHauke Mehrtens */
610a027237aSHauke Mehrtens err = bcma_fill_sprom_with_fallback(bus, &bus->sprom);
6114ac887cfSArend van Spriel return err;
612d6865dccSHauke Mehrtens }
61310d8493cSArend van Spriel }
614d6865dccSHauke Mehrtens
6154b4f5be2SHauke Mehrtens if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4331 ||
6164b4f5be2SHauke Mehrtens bus->chipinfo.id == BCMA_CHIP_ID_BCM43431)
617984e5befSRafał Miłecki bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, false);
618984e5befSRafał Miłecki
6193d9d8af3SRafał Miłecki bcma_debug(bus, "SPROM offset 0x%x\n", offset);
62092eb1642SRafał Miłecki for (i = 0; i < ARRAY_SIZE(sprom_sizes); i++) {
62192eb1642SRafał Miłecki size_t words = sprom_sizes[i];
62292eb1642SRafał Miłecki
62392eb1642SRafał Miłecki sprom = kcalloc(words, sizeof(u16), GFP_KERNEL);
62492eb1642SRafał Miłecki if (!sprom)
62592eb1642SRafał Miłecki return -ENOMEM;
62692eb1642SRafał Miłecki
62792eb1642SRafał Miłecki bcma_sprom_read(bus, offset, sprom, words);
62878e578c5SRafał Miłecki err = bcma_sprom_valid(bus, sprom, words);
62992eb1642SRafał Miłecki if (!err)
63092eb1642SRafał Miłecki break;
63192eb1642SRafał Miłecki
63292eb1642SRafał Miłecki kfree(sprom);
63392eb1642SRafał Miłecki }
63427f18dc2SRafał Miłecki
6354b4f5be2SHauke Mehrtens if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4331 ||
6364b4f5be2SHauke Mehrtens bus->chipinfo.id == BCMA_CHIP_ID_BCM43431)
637984e5befSRafał Miłecki bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true);
638984e5befSRafał Miłecki
639017c4c3bSHauke Mehrtens if (err) {
64092eb1642SRafał Miłecki bcma_warn(bus, "Invalid SPROM read from the PCIe card, trying to use fallback SPROM\n");
641017c4c3bSHauke Mehrtens err = bcma_fill_sprom_with_fallback(bus, &bus->sprom);
64292eb1642SRafał Miłecki } else {
64392eb1642SRafał Miłecki bcma_sprom_extract_r8(bus, sprom);
64492eb1642SRafał Miłecki kfree(sprom);
645017c4c3bSHauke Mehrtens }
64627f18dc2SRafał Miłecki
64727f18dc2SRafał Miłecki return err;
64827f18dc2SRafał Miłecki }
649