blob: 84807a9b4b13abbc58e5449b486ee1e3a6d58892 [file] [log] [blame]
Michael Buesch61e115a2007-09-18 15:12:50 -04001/*
2 * Sonics Silicon Backplane PCI-Hostbus related functions.
3 *
Michael Büscheb032b92011-07-04 20:50:05 +02004 * Copyright (C) 2005-2006 Michael Buesch <m@bues.ch>
Michael Buesch61e115a2007-09-18 15:12:50 -04005 * Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
6 * Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
7 * Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
8 * Copyright (C) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
9 *
10 * Derived from the Broadcom 4400 device driver.
11 * Copyright (C) 2002 David S. Miller (davem@redhat.com)
12 * Fixed by Pekka Pietikainen (pp@ee.oulu.fi)
13 * Copyright (C) 2006 Broadcom Corporation.
14 *
15 * Licensed under the GNU/GPL. See COPYING for details.
16 */
17
Michael Büschb8b60692018-07-31 21:56:38 +020018#include "ssb_private.h"
19
Michael Buesch61e115a2007-09-18 15:12:50 -040020#include <linux/ssb/ssb.h>
21#include <linux/ssb/ssb_regs.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090022#include <linux/slab.h>
Michael Buesch61e115a2007-09-18 15:12:50 -040023#include <linux/pci.h>
24#include <linux/delay.h>
25
Michael Buesch61e115a2007-09-18 15:12:50 -040026
27/* Define the following to 1 to enable a printk on each coreswitch. */
28#define SSB_VERBOSE_PCICORESWITCH_DEBUG 0
29
30
31/* Lowlevel coreswitching */
32int ssb_pci_switch_coreidx(struct ssb_bus *bus, u8 coreidx)
33{
34 int err;
35 int attempts = 0;
36 u32 cur_core;
37
38 while (1) {
39 err = pci_write_config_dword(bus->host_pci, SSB_BAR0_WIN,
40 (coreidx * SSB_CORE_SIZE)
41 + SSB_ENUM_BASE);
42 if (err)
43 goto error;
44 err = pci_read_config_dword(bus->host_pci, SSB_BAR0_WIN,
45 &cur_core);
46 if (err)
47 goto error;
48 cur_core = (cur_core - SSB_ENUM_BASE)
49 / SSB_CORE_SIZE;
50 if (cur_core == coreidx)
51 break;
52
53 if (attempts++ > SSB_BAR0_MAX_RETRIES)
54 goto error;
55 udelay(10);
56 }
57 return 0;
58error:
Michael Büschb8b60692018-07-31 21:56:38 +020059 pr_err("Failed to switch to core %u\n", coreidx);
Michael Buesch61e115a2007-09-18 15:12:50 -040060 return -ENODEV;
61}
62
63int ssb_pci_switch_core(struct ssb_bus *bus,
64 struct ssb_device *dev)
65{
66 int err;
67 unsigned long flags;
68
69#if SSB_VERBOSE_PCICORESWITCH_DEBUG
Michael Büschb8b60692018-07-31 21:56:38 +020070 pr_info("Switching to %s core, index %d\n",
71 ssb_core_name(dev->id.coreid), dev->core_index);
Michael Buesch61e115a2007-09-18 15:12:50 -040072#endif
73
74 spin_lock_irqsave(&bus->bar_lock, flags);
75 err = ssb_pci_switch_coreidx(bus, dev->core_index);
76 if (!err)
77 bus->mapped_device = dev;
78 spin_unlock_irqrestore(&bus->bar_lock, flags);
79
80 return err;
81}
82
83/* Enable/disable the on board crystal oscillator and/or PLL. */
84int ssb_pci_xtal(struct ssb_bus *bus, u32 what, int turn_on)
85{
86 int err;
87 u32 in, out, outenable;
88 u16 pci_status;
89
90 if (bus->bustype != SSB_BUSTYPE_PCI)
91 return 0;
92
93 err = pci_read_config_dword(bus->host_pci, SSB_GPIO_IN, &in);
94 if (err)
95 goto err_pci;
96 err = pci_read_config_dword(bus->host_pci, SSB_GPIO_OUT, &out);
97 if (err)
98 goto err_pci;
99 err = pci_read_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE, &outenable);
100 if (err)
101 goto err_pci;
102
103 outenable |= what;
104
105 if (turn_on) {
106 /* Avoid glitching the clock if GPRS is already using it.
107 * We can't actually read the state of the PLLPD so we infer it
108 * by the value of XTAL_PU which *is* readable via gpioin.
109 */
110 if (!(in & SSB_GPIO_XTAL)) {
111 if (what & SSB_GPIO_XTAL) {
112 /* Turn the crystal on */
113 out |= SSB_GPIO_XTAL;
114 if (what & SSB_GPIO_PLL)
115 out |= SSB_GPIO_PLL;
116 err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out);
117 if (err)
118 goto err_pci;
119 err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE,
120 outenable);
121 if (err)
122 goto err_pci;
123 msleep(1);
124 }
125 if (what & SSB_GPIO_PLL) {
126 /* Turn the PLL on */
127 out &= ~SSB_GPIO_PLL;
128 err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out);
129 if (err)
130 goto err_pci;
131 msleep(5);
132 }
133 }
134
135 err = pci_read_config_word(bus->host_pci, PCI_STATUS, &pci_status);
136 if (err)
137 goto err_pci;
138 pci_status &= ~PCI_STATUS_SIG_TARGET_ABORT;
139 err = pci_write_config_word(bus->host_pci, PCI_STATUS, pci_status);
140 if (err)
141 goto err_pci;
142 } else {
143 if (what & SSB_GPIO_XTAL) {
144 /* Turn the crystal off */
145 out &= ~SSB_GPIO_XTAL;
146 }
147 if (what & SSB_GPIO_PLL) {
148 /* Turn the PLL off */
149 out |= SSB_GPIO_PLL;
150 }
151 err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out);
152 if (err)
153 goto err_pci;
154 err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE, outenable);
155 if (err)
156 goto err_pci;
157 }
158
159out:
160 return err;
161
162err_pci:
Michael Büschb8b60692018-07-31 21:56:38 +0200163 pr_err("Error: ssb_pci_xtal() could not access PCI config space!\n");
Michael Buesch61e115a2007-09-18 15:12:50 -0400164 err = -EBUSY;
165 goto out;
166}
167
168/* Get the word-offset for a SSB_SPROM_XXX define. */
Rafał Miłecki0a182fd2010-03-31 22:54:18 +0200169#define SPOFF(offset) ((offset) / sizeof(u16))
Michael Buesch61e115a2007-09-18 15:12:50 -0400170/* Helper to extract some _offset, which is one of the SSB_SPROM_XXX defines. */
Gábor Stefanikf6790562009-08-10 21:23:08 +0200171#define SPEX16(_outvar, _offset, _mask, _shift) \
Michael Buesch61e115a2007-09-18 15:12:50 -0400172 out->_outvar = ((in[SPOFF(_offset)] & (_mask)) >> (_shift))
Gábor Stefanikf6790562009-08-10 21:23:08 +0200173#define SPEX32(_outvar, _offset, _mask, _shift) \
174 out->_outvar = ((((u32)in[SPOFF((_offset)+2)] << 16 | \
175 in[SPOFF(_offset)]) & (_mask)) >> (_shift))
176#define SPEX(_outvar, _offset, _mask, _shift) \
177 SPEX16(_outvar, _offset, _mask, _shift)
178
Hauke Mehrtense2da4bd2012-04-29 02:04:13 +0200179#define SPEX_ARRAY8(_field, _offset, _mask, _shift) \
180 do { \
181 SPEX(_field[0], _offset + 0, _mask, _shift); \
182 SPEX(_field[1], _offset + 2, _mask, _shift); \
183 SPEX(_field[2], _offset + 4, _mask, _shift); \
184 SPEX(_field[3], _offset + 6, _mask, _shift); \
185 SPEX(_field[4], _offset + 8, _mask, _shift); \
186 SPEX(_field[5], _offset + 10, _mask, _shift); \
187 SPEX(_field[6], _offset + 12, _mask, _shift); \
188 SPEX(_field[7], _offset + 14, _mask, _shift); \
189 } while (0)
190
Michael Buesch61e115a2007-09-18 15:12:50 -0400191
192static inline u8 ssb_crc8(u8 crc, u8 data)
193{
194 /* Polynomial: x^8 + x^7 + x^6 + x^4 + x^2 + 1 */
195 static const u8 t[] = {
196 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
197 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
198 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
199 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
200 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
201 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
202 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
203 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
204 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
205 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
206 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
207 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
208 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
209 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
210 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
211 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
212 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
213 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
214 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
215 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
216 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
217 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
218 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
219 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
220 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
221 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
222 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
223 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
224 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
225 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
226 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
227 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F,
228 };
229 return t[crc ^ data];
230}
231
Joe Perchese5652752013-02-20 12:11:05 -0800232static void sprom_get_mac(char *mac, const u16 *in)
233{
234 int i;
235 for (i = 0; i < 3; i++) {
Joe Perchese5652752013-02-20 12:11:05 -0800236 *mac++ = in[i] >> 8;
Larry Fingera9fac732013-03-11 15:38:26 -0500237 *mac++ = in[i];
Joe Perchese5652752013-02-20 12:11:05 -0800238 }
239}
240
Larry Fingerc272ef42007-11-09 16:56:25 -0600241static u8 ssb_sprom_crc(const u16 *sprom, u16 size)
Michael Buesch61e115a2007-09-18 15:12:50 -0400242{
243 int word;
244 u8 crc = 0xFF;
245
Larry Fingerc272ef42007-11-09 16:56:25 -0600246 for (word = 0; word < size - 1; word++) {
Michael Buesch61e115a2007-09-18 15:12:50 -0400247 crc = ssb_crc8(crc, sprom[word] & 0x00FF);
248 crc = ssb_crc8(crc, (sprom[word] & 0xFF00) >> 8);
249 }
Larry Fingerc272ef42007-11-09 16:56:25 -0600250 crc = ssb_crc8(crc, sprom[size - 1] & 0x00FF);
Michael Buesch61e115a2007-09-18 15:12:50 -0400251 crc ^= 0xFF;
252
253 return crc;
254}
255
Michael Buesche7ec2e32008-03-10 17:26:32 +0100256static int sprom_check_crc(const u16 *sprom, size_t size)
Michael Buesch61e115a2007-09-18 15:12:50 -0400257{
258 u8 crc;
259 u8 expected_crc;
260 u16 tmp;
261
Larry Fingerc272ef42007-11-09 16:56:25 -0600262 crc = ssb_sprom_crc(sprom, size);
263 tmp = sprom[size - 1] & SSB_SPROM_REVISION_CRC;
Michael Buesch61e115a2007-09-18 15:12:50 -0400264 expected_crc = tmp >> SSB_SPROM_REVISION_CRC_SHIFT;
265 if (crc != expected_crc)
266 return -EPROTO;
267
268 return 0;
269}
270
Michael Buesche7ec2e32008-03-10 17:26:32 +0100271static int sprom_do_read(struct ssb_bus *bus, u16 *sprom)
Michael Buesch61e115a2007-09-18 15:12:50 -0400272{
273 int i;
274
Larry Fingerc272ef42007-11-09 16:56:25 -0600275 for (i = 0; i < bus->sprom_size; i++)
Rafał Miłeckiea2db492010-03-31 21:59:21 +0200276 sprom[i] = ioread16(bus->mmio + bus->sprom_offset + (i * 2));
Michael Buesche7ec2e32008-03-10 17:26:32 +0100277
278 return 0;
Michael Buesch61e115a2007-09-18 15:12:50 -0400279}
280
281static int sprom_do_write(struct ssb_bus *bus, const u16 *sprom)
282{
283 struct pci_dev *pdev = bus->host_pci;
284 int i, err;
285 u32 spromctl;
Larry Fingerc272ef42007-11-09 16:56:25 -0600286 u16 size = bus->sprom_size;
Michael Buesch61e115a2007-09-18 15:12:50 -0400287
Michael Büschb8b60692018-07-31 21:56:38 +0200288 pr_notice("Writing SPROM. Do NOT turn off the power! Please stand by...\n");
Michael Buesch61e115a2007-09-18 15:12:50 -0400289 err = pci_read_config_dword(pdev, SSB_SPROMCTL, &spromctl);
290 if (err)
291 goto err_ctlreg;
292 spromctl |= SSB_SPROMCTL_WE;
293 err = pci_write_config_dword(pdev, SSB_SPROMCTL, spromctl);
294 if (err)
295 goto err_ctlreg;
Michael Büschb8b60692018-07-31 21:56:38 +0200296 pr_notice("[ 0%%");
Michael Buesch61e115a2007-09-18 15:12:50 -0400297 msleep(500);
Larry Fingerc272ef42007-11-09 16:56:25 -0600298 for (i = 0; i < size; i++) {
299 if (i == size / 4)
Michael Büschb8b60692018-07-31 21:56:38 +0200300 pr_cont("25%%");
Larry Fingerc272ef42007-11-09 16:56:25 -0600301 else if (i == size / 2)
Michael Büschb8b60692018-07-31 21:56:38 +0200302 pr_cont("50%%");
Larry Fingerc272ef42007-11-09 16:56:25 -0600303 else if (i == (size * 3) / 4)
Michael Büschb8b60692018-07-31 21:56:38 +0200304 pr_cont("75%%");
Michael Buesch61e115a2007-09-18 15:12:50 -0400305 else if (i % 2)
Michael Büschb8b60692018-07-31 21:56:38 +0200306 pr_cont(".");
Rafał Miłeckiea2db492010-03-31 21:59:21 +0200307 writew(sprom[i], bus->mmio + bus->sprom_offset + (i * 2));
Michael Buesch61e115a2007-09-18 15:12:50 -0400308 mmiowb();
309 msleep(20);
310 }
311 err = pci_read_config_dword(pdev, SSB_SPROMCTL, &spromctl);
312 if (err)
313 goto err_ctlreg;
314 spromctl &= ~SSB_SPROMCTL_WE;
315 err = pci_write_config_dword(pdev, SSB_SPROMCTL, spromctl);
316 if (err)
317 goto err_ctlreg;
318 msleep(500);
Michael Büschb8b60692018-07-31 21:56:38 +0200319 pr_cont("100%% ]\n");
320 pr_notice("SPROM written\n");
Michael Buesch61e115a2007-09-18 15:12:50 -0400321
322 return 0;
323err_ctlreg:
Michael Büschb8b60692018-07-31 21:56:38 +0200324 pr_err("Could not access SPROM control register.\n");
Michael Buesch61e115a2007-09-18 15:12:50 -0400325 return err;
326}
327
Rafał Miłecki67d392c2014-07-12 16:42:09 +0200328static s8 sprom_extract_antgain(u8 sprom_revision, const u16 *in, u16 offset,
329 u16 mask, u16 shift)
Michael Buesche861b982007-12-22 21:51:30 +0100330{
331 u16 v;
332 u8 gain;
333
Rafał Miłecki67d392c2014-07-12 16:42:09 +0200334 v = in[SPOFF(offset)];
Michael Buesche861b982007-12-22 21:51:30 +0100335 gain = (v & mask) >> shift;
336 if (gain == 0xFF)
337 gain = 2; /* If unset use 2dBm */
338 if (sprom_revision == 1) {
339 /* Convert to Q5.2 */
340 gain <<= 2;
341 } else {
342 /* Q5.2 Fractional part is stored in 0xC0 */
343 gain = ((gain & 0xC0) >> 6) | ((gain & 0x3F) << 2);
344 }
345
346 return (s8)gain;
347}
348
Hauke Mehrtens7e4235a2013-03-21 20:25:21 +0100349static void sprom_extract_r23(struct ssb_sprom *out, const u16 *in)
350{
351 SPEX(boardflags_hi, SSB_SPROM2_BFLHI, 0xFFFF, 0);
352 SPEX(opo, SSB_SPROM2_OPO, SSB_SPROM2_OPO_VALUE, 0);
353 SPEX(pa1lob0, SSB_SPROM2_PA1LOB0, 0xFFFF, 0);
354 SPEX(pa1lob1, SSB_SPROM2_PA1LOB1, 0xFFFF, 0);
355 SPEX(pa1lob2, SSB_SPROM2_PA1LOB2, 0xFFFF, 0);
356 SPEX(pa1hib0, SSB_SPROM2_PA1HIB0, 0xFFFF, 0);
357 SPEX(pa1hib1, SSB_SPROM2_PA1HIB1, 0xFFFF, 0);
358 SPEX(pa1hib2, SSB_SPROM2_PA1HIB2, 0xFFFF, 0);
359 SPEX(maxpwr_ah, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_HI, 0);
360 SPEX(maxpwr_al, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_LO,
361 SSB_SPROM2_MAXP_A_LO_SHIFT);
362}
363
Larry Fingerc272ef42007-11-09 16:56:25 -0600364static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in)
365{
Larry Fingerc272ef42007-11-09 16:56:25 -0600366 u16 loc[3];
367
Larry Finger31ce12f2008-08-20 17:45:06 -0500368 if (out->revision == 3) /* rev 3 moved MAC */
Larry Fingerc272ef42007-11-09 16:56:25 -0600369 loc[0] = SSB_SPROM3_IL0MAC;
Larry Finger31ce12f2008-08-20 17:45:06 -0500370 else {
Larry Fingerc272ef42007-11-09 16:56:25 -0600371 loc[0] = SSB_SPROM1_IL0MAC;
372 loc[1] = SSB_SPROM1_ET0MAC;
373 loc[2] = SSB_SPROM1_ET1MAC;
374 }
Joe Perchese5652752013-02-20 12:11:05 -0800375 sprom_get_mac(out->il0mac, &in[SPOFF(loc[0])]);
Larry Finger31ce12f2008-08-20 17:45:06 -0500376 if (out->revision < 3) { /* only rev 1-2 have et0, et1 */
Joe Perchese5652752013-02-20 12:11:05 -0800377 sprom_get_mac(out->et0mac, &in[SPOFF(loc[1])]);
378 sprom_get_mac(out->et1mac, &in[SPOFF(loc[2])]);
Larry Fingerc272ef42007-11-09 16:56:25 -0600379 }
380 SPEX(et0phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0A, 0);
381 SPEX(et1phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1A,
382 SSB_SPROM1_ETHPHY_ET1A_SHIFT);
Michael Buesche861b982007-12-22 21:51:30 +0100383 SPEX(et0mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0M, 14);
384 SPEX(et1mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1M, 15);
385 SPEX(board_rev, SSB_SPROM1_BINF, SSB_SPROM1_BINF_BREV, 0);
Rafał Miłecki3623b262013-03-19 13:18:43 +0100386 SPEX(board_type, SSB_SPROM1_SPID, 0xFFFF, 0);
Hauke Mehrtensbf7d4202012-04-29 02:04:10 +0200387 if (out->revision == 1)
388 SPEX(country_code, SSB_SPROM1_BINF, SSB_SPROM1_BINF_CCODE,
389 SSB_SPROM1_BINF_CCODE_SHIFT);
Michael Buesche861b982007-12-22 21:51:30 +0100390 SPEX(ant_available_a, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTA,
391 SSB_SPROM1_BINF_ANTA_SHIFT);
392 SPEX(ant_available_bg, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTBG,
393 SSB_SPROM1_BINF_ANTBG_SHIFT);
Larry Fingerc272ef42007-11-09 16:56:25 -0600394 SPEX(pa0b0, SSB_SPROM1_PA0B0, 0xFFFF, 0);
395 SPEX(pa0b1, SSB_SPROM1_PA0B1, 0xFFFF, 0);
396 SPEX(pa0b2, SSB_SPROM1_PA0B2, 0xFFFF, 0);
397 SPEX(pa1b0, SSB_SPROM1_PA1B0, 0xFFFF, 0);
398 SPEX(pa1b1, SSB_SPROM1_PA1B1, 0xFFFF, 0);
399 SPEX(pa1b2, SSB_SPROM1_PA1B2, 0xFFFF, 0);
400 SPEX(gpio0, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P0, 0);
401 SPEX(gpio1, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P1,
402 SSB_SPROM1_GPIOA_P1_SHIFT);
403 SPEX(gpio2, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P2, 0);
404 SPEX(gpio3, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P3,
405 SSB_SPROM1_GPIOB_P3_SHIFT);
406 SPEX(maxpwr_a, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_A,
407 SSB_SPROM1_MAXPWR_A_SHIFT);
408 SPEX(maxpwr_bg, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_BG, 0);
409 SPEX(itssi_a, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_A,
410 SSB_SPROM1_ITSSI_A_SHIFT);
411 SPEX(itssi_bg, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_BG, 0);
412 SPEX(boardflags_lo, SSB_SPROM1_BFLLO, 0xFFFF, 0);
Hauke Mehrtens7e4235a2013-03-21 20:25:21 +0100413
Hauke Mehrtensbf7d4202012-04-29 02:04:10 +0200414 SPEX(alpha2[0], SSB_SPROM1_CCODE, 0xff00, 8);
415 SPEX(alpha2[1], SSB_SPROM1_CCODE, 0x00ff, 0);
Michael Buesche861b982007-12-22 21:51:30 +0100416
417 /* Extract the antenna gain values. */
Rafał Miłecki67d392c2014-07-12 16:42:09 +0200418 out->antenna_gain.a0 = sprom_extract_antgain(out->revision, in,
419 SSB_SPROM1_AGAIN,
420 SSB_SPROM1_AGAIN_BG,
421 SSB_SPROM1_AGAIN_BG_SHIFT);
422 out->antenna_gain.a1 = sprom_extract_antgain(out->revision, in,
423 SSB_SPROM1_AGAIN,
424 SSB_SPROM1_AGAIN_A,
425 SSB_SPROM1_AGAIN_A_SHIFT);
Hauke Mehrtens7e4235a2013-03-21 20:25:21 +0100426 if (out->revision >= 2)
427 sprom_extract_r23(out, in);
Larry Fingerc272ef42007-11-09 16:56:25 -0600428}
429
Rafał Miłecki172c69a2010-11-28 10:39:35 +0100430/* Revs 4 5 and 8 have partially shared layout */
431static void sprom_extract_r458(struct ssb_sprom *out, const u16 *in)
432{
433 SPEX(txpid2g[0], SSB_SPROM4_TXPID2G01,
434 SSB_SPROM4_TXPID2G0, SSB_SPROM4_TXPID2G0_SHIFT);
435 SPEX(txpid2g[1], SSB_SPROM4_TXPID2G01,
436 SSB_SPROM4_TXPID2G1, SSB_SPROM4_TXPID2G1_SHIFT);
437 SPEX(txpid2g[2], SSB_SPROM4_TXPID2G23,
438 SSB_SPROM4_TXPID2G2, SSB_SPROM4_TXPID2G2_SHIFT);
439 SPEX(txpid2g[3], SSB_SPROM4_TXPID2G23,
440 SSB_SPROM4_TXPID2G3, SSB_SPROM4_TXPID2G3_SHIFT);
441
442 SPEX(txpid5gl[0], SSB_SPROM4_TXPID5GL01,
443 SSB_SPROM4_TXPID5GL0, SSB_SPROM4_TXPID5GL0_SHIFT);
444 SPEX(txpid5gl[1], SSB_SPROM4_TXPID5GL01,
445 SSB_SPROM4_TXPID5GL1, SSB_SPROM4_TXPID5GL1_SHIFT);
446 SPEX(txpid5gl[2], SSB_SPROM4_TXPID5GL23,
447 SSB_SPROM4_TXPID5GL2, SSB_SPROM4_TXPID5GL2_SHIFT);
448 SPEX(txpid5gl[3], SSB_SPROM4_TXPID5GL23,
449 SSB_SPROM4_TXPID5GL3, SSB_SPROM4_TXPID5GL3_SHIFT);
450
451 SPEX(txpid5g[0], SSB_SPROM4_TXPID5G01,
452 SSB_SPROM4_TXPID5G0, SSB_SPROM4_TXPID5G0_SHIFT);
453 SPEX(txpid5g[1], SSB_SPROM4_TXPID5G01,
454 SSB_SPROM4_TXPID5G1, SSB_SPROM4_TXPID5G1_SHIFT);
455 SPEX(txpid5g[2], SSB_SPROM4_TXPID5G23,
456 SSB_SPROM4_TXPID5G2, SSB_SPROM4_TXPID5G2_SHIFT);
457 SPEX(txpid5g[3], SSB_SPROM4_TXPID5G23,
458 SSB_SPROM4_TXPID5G3, SSB_SPROM4_TXPID5G3_SHIFT);
459
460 SPEX(txpid5gh[0], SSB_SPROM4_TXPID5GH01,
461 SSB_SPROM4_TXPID5GH0, SSB_SPROM4_TXPID5GH0_SHIFT);
462 SPEX(txpid5gh[1], SSB_SPROM4_TXPID5GH01,
463 SSB_SPROM4_TXPID5GH1, SSB_SPROM4_TXPID5GH1_SHIFT);
464 SPEX(txpid5gh[2], SSB_SPROM4_TXPID5GH23,
465 SSB_SPROM4_TXPID5GH2, SSB_SPROM4_TXPID5GH2_SHIFT);
466 SPEX(txpid5gh[3], SSB_SPROM4_TXPID5GH23,
467 SSB_SPROM4_TXPID5GH3, SSB_SPROM4_TXPID5GH3_SHIFT);
468}
469
Larry Finger095f6952008-08-19 12:50:31 -0500470static void sprom_extract_r45(struct ssb_sprom *out, const u16 *in)
Michael Buesch61e115a2007-09-18 15:12:50 -0400471{
Rafał Miłecki6ad59342014-07-15 16:18:57 +0200472 static const u16 pwr_info_offset[] = {
473 SSB_SPROM4_PWR_INFO_CORE0, SSB_SPROM4_PWR_INFO_CORE1,
474 SSB_SPROM4_PWR_INFO_CORE2, SSB_SPROM4_PWR_INFO_CORE3
475 };
Larry Finger095f6952008-08-19 12:50:31 -0500476 u16 il0mac_offset;
Rafał Miłecki6ad59342014-07-15 16:18:57 +0200477 int i;
478
479 BUILD_BUG_ON(ARRAY_SIZE(pwr_info_offset) !=
480 ARRAY_SIZE(out->core_pwr_info));
Michael Buesch61e115a2007-09-18 15:12:50 -0400481
Larry Finger095f6952008-08-19 12:50:31 -0500482 if (out->revision == 4)
483 il0mac_offset = SSB_SPROM4_IL0MAC;
484 else
485 il0mac_offset = SSB_SPROM5_IL0MAC;
Joe Perchese5652752013-02-20 12:11:05 -0800486
487 sprom_get_mac(out->il0mac, &in[SPOFF(il0mac_offset)]);
488
Larry Fingerc272ef42007-11-09 16:56:25 -0600489 SPEX(et0phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET0A, 0);
490 SPEX(et1phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET1A,
491 SSB_SPROM4_ETHPHY_ET1A_SHIFT);
Hauke Mehrtens673335c2012-04-29 02:04:11 +0200492 SPEX(board_rev, SSB_SPROM4_BOARDREV, 0xFFFF, 0);
Rafał Miłecki3623b262013-03-19 13:18:43 +0100493 SPEX(board_type, SSB_SPROM1_SPID, 0xFFFF, 0);
Larry Finger095f6952008-08-19 12:50:31 -0500494 if (out->revision == 4) {
Hauke Mehrtensbf7d4202012-04-29 02:04:10 +0200495 SPEX(alpha2[0], SSB_SPROM4_CCODE, 0xff00, 8);
496 SPEX(alpha2[1], SSB_SPROM4_CCODE, 0x00ff, 0);
Larry Finger095f6952008-08-19 12:50:31 -0500497 SPEX(boardflags_lo, SSB_SPROM4_BFLLO, 0xFFFF, 0);
498 SPEX(boardflags_hi, SSB_SPROM4_BFLHI, 0xFFFF, 0);
Rafał Miłecki6d1d4ea2011-02-08 23:32:17 +0100499 SPEX(boardflags2_lo, SSB_SPROM4_BFL2LO, 0xFFFF, 0);
500 SPEX(boardflags2_hi, SSB_SPROM4_BFL2HI, 0xFFFF, 0);
Larry Finger095f6952008-08-19 12:50:31 -0500501 } else {
Hauke Mehrtensbf7d4202012-04-29 02:04:10 +0200502 SPEX(alpha2[0], SSB_SPROM5_CCODE, 0xff00, 8);
503 SPEX(alpha2[1], SSB_SPROM5_CCODE, 0x00ff, 0);
Larry Finger095f6952008-08-19 12:50:31 -0500504 SPEX(boardflags_lo, SSB_SPROM5_BFLLO, 0xFFFF, 0);
505 SPEX(boardflags_hi, SSB_SPROM5_BFLHI, 0xFFFF, 0);
Rafał Miłecki6d1d4ea2011-02-08 23:32:17 +0100506 SPEX(boardflags2_lo, SSB_SPROM5_BFL2LO, 0xFFFF, 0);
507 SPEX(boardflags2_hi, SSB_SPROM5_BFL2HI, 0xFFFF, 0);
Larry Finger095f6952008-08-19 12:50:31 -0500508 }
Michael Buesche861b982007-12-22 21:51:30 +0100509 SPEX(ant_available_a, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_A,
510 SSB_SPROM4_ANTAVAIL_A_SHIFT);
511 SPEX(ant_available_bg, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_BG,
512 SSB_SPROM4_ANTAVAIL_BG_SHIFT);
Larry Fingerd3c319f2007-11-09 16:58:20 -0600513 SPEX(maxpwr_bg, SSB_SPROM4_MAXP_BG, SSB_SPROM4_MAXP_BG_MASK, 0);
514 SPEX(itssi_bg, SSB_SPROM4_MAXP_BG, SSB_SPROM4_ITSSI_BG,
515 SSB_SPROM4_ITSSI_BG_SHIFT);
516 SPEX(maxpwr_a, SSB_SPROM4_MAXP_A, SSB_SPROM4_MAXP_A_MASK, 0);
517 SPEX(itssi_a, SSB_SPROM4_MAXP_A, SSB_SPROM4_ITSSI_A,
518 SSB_SPROM4_ITSSI_A_SHIFT);
Larry Finger095f6952008-08-19 12:50:31 -0500519 if (out->revision == 4) {
520 SPEX(gpio0, SSB_SPROM4_GPIOA, SSB_SPROM4_GPIOA_P0, 0);
521 SPEX(gpio1, SSB_SPROM4_GPIOA, SSB_SPROM4_GPIOA_P1,
522 SSB_SPROM4_GPIOA_P1_SHIFT);
523 SPEX(gpio2, SSB_SPROM4_GPIOB, SSB_SPROM4_GPIOB_P2, 0);
524 SPEX(gpio3, SSB_SPROM4_GPIOB, SSB_SPROM4_GPIOB_P3,
525 SSB_SPROM4_GPIOB_P3_SHIFT);
526 } else {
527 SPEX(gpio0, SSB_SPROM5_GPIOA, SSB_SPROM5_GPIOA_P0, 0);
528 SPEX(gpio1, SSB_SPROM5_GPIOA, SSB_SPROM5_GPIOA_P1,
529 SSB_SPROM5_GPIOA_P1_SHIFT);
530 SPEX(gpio2, SSB_SPROM5_GPIOB, SSB_SPROM5_GPIOB_P2, 0);
531 SPEX(gpio3, SSB_SPROM5_GPIOB, SSB_SPROM5_GPIOB_P3,
532 SSB_SPROM5_GPIOB_P3_SHIFT);
533 }
Michael Buesche861b982007-12-22 21:51:30 +0100534
535 /* Extract the antenna gain values. */
Rafał Miłecki6daf4322014-07-12 16:42:10 +0200536 out->antenna_gain.a0 = sprom_extract_antgain(out->revision, in,
537 SSB_SPROM4_AGAIN01,
538 SSB_SPROM4_AGAIN0,
539 SSB_SPROM4_AGAIN0_SHIFT);
540 out->antenna_gain.a1 = sprom_extract_antgain(out->revision, in,
541 SSB_SPROM4_AGAIN01,
542 SSB_SPROM4_AGAIN1,
543 SSB_SPROM4_AGAIN1_SHIFT);
544 out->antenna_gain.a2 = sprom_extract_antgain(out->revision, in,
545 SSB_SPROM4_AGAIN23,
546 SSB_SPROM4_AGAIN2,
547 SSB_SPROM4_AGAIN2_SHIFT);
548 out->antenna_gain.a3 = sprom_extract_antgain(out->revision, in,
549 SSB_SPROM4_AGAIN23,
550 SSB_SPROM4_AGAIN3,
551 SSB_SPROM4_AGAIN3_SHIFT);
Michael Buesche861b982007-12-22 21:51:30 +0100552
Rafał Miłecki6ad59342014-07-15 16:18:57 +0200553 /* Extract cores power info info */
554 for (i = 0; i < ARRAY_SIZE(pwr_info_offset); i++) {
555 u16 o = pwr_info_offset[i];
556
557 SPEX(core_pwr_info[i].itssi_2g, o + SSB_SPROM4_2G_MAXP_ITSSI,
558 SSB_SPROM4_2G_ITSSI, SSB_SPROM4_2G_ITSSI_SHIFT);
559 SPEX(core_pwr_info[i].maxpwr_2g, o + SSB_SPROM4_2G_MAXP_ITSSI,
560 SSB_SPROM4_2G_MAXP, 0);
561
562 SPEX(core_pwr_info[i].pa_2g[0], o + SSB_SPROM4_2G_PA_0, ~0, 0);
563 SPEX(core_pwr_info[i].pa_2g[1], o + SSB_SPROM4_2G_PA_1, ~0, 0);
564 SPEX(core_pwr_info[i].pa_2g[2], o + SSB_SPROM4_2G_PA_2, ~0, 0);
565 SPEX(core_pwr_info[i].pa_2g[3], o + SSB_SPROM4_2G_PA_3, ~0, 0);
566
567 SPEX(core_pwr_info[i].itssi_5g, o + SSB_SPROM4_5G_MAXP_ITSSI,
568 SSB_SPROM4_5G_ITSSI, SSB_SPROM4_5G_ITSSI_SHIFT);
569 SPEX(core_pwr_info[i].maxpwr_5g, o + SSB_SPROM4_5G_MAXP_ITSSI,
570 SSB_SPROM4_5G_MAXP, 0);
571 SPEX(core_pwr_info[i].maxpwr_5gh, o + SSB_SPROM4_5GHL_MAXP,
572 SSB_SPROM4_5GH_MAXP, 0);
573 SPEX(core_pwr_info[i].maxpwr_5gl, o + SSB_SPROM4_5GHL_MAXP,
574 SSB_SPROM4_5GL_MAXP, SSB_SPROM4_5GL_MAXP_SHIFT);
575
576 SPEX(core_pwr_info[i].pa_5gl[0], o + SSB_SPROM4_5GL_PA_0, ~0, 0);
577 SPEX(core_pwr_info[i].pa_5gl[1], o + SSB_SPROM4_5GL_PA_1, ~0, 0);
578 SPEX(core_pwr_info[i].pa_5gl[2], o + SSB_SPROM4_5GL_PA_2, ~0, 0);
579 SPEX(core_pwr_info[i].pa_5gl[3], o + SSB_SPROM4_5GL_PA_3, ~0, 0);
580 SPEX(core_pwr_info[i].pa_5g[0], o + SSB_SPROM4_5G_PA_0, ~0, 0);
581 SPEX(core_pwr_info[i].pa_5g[1], o + SSB_SPROM4_5G_PA_1, ~0, 0);
582 SPEX(core_pwr_info[i].pa_5g[2], o + SSB_SPROM4_5G_PA_2, ~0, 0);
583 SPEX(core_pwr_info[i].pa_5g[3], o + SSB_SPROM4_5G_PA_3, ~0, 0);
584 SPEX(core_pwr_info[i].pa_5gh[0], o + SSB_SPROM4_5GH_PA_0, ~0, 0);
585 SPEX(core_pwr_info[i].pa_5gh[1], o + SSB_SPROM4_5GH_PA_1, ~0, 0);
586 SPEX(core_pwr_info[i].pa_5gh[2], o + SSB_SPROM4_5GH_PA_2, ~0, 0);
587 SPEX(core_pwr_info[i].pa_5gh[3], o + SSB_SPROM4_5GH_PA_3, ~0, 0);
588 }
589
Rafał Miłecki172c69a2010-11-28 10:39:35 +0100590 sprom_extract_r458(out, in);
591
Larry Fingerc272ef42007-11-09 16:56:25 -0600592 /* TODO - get remaining rev 4 stuff needed */
Michael Buesch61e115a2007-09-18 15:12:50 -0400593}
594
Michael Buesch6b1c7c62008-12-25 00:39:28 +0100595static void sprom_extract_r8(struct ssb_sprom *out, const u16 *in)
596{
597 int i;
Joe Perchese5652752013-02-20 12:11:05 -0800598 u16 o;
Rafał Miłeckib0f70292012-01-02 08:41:23 +0100599 u16 pwr_info_offset[] = {
600 SSB_SROM8_PWR_INFO_CORE0, SSB_SROM8_PWR_INFO_CORE1,
601 SSB_SROM8_PWR_INFO_CORE2, SSB_SROM8_PWR_INFO_CORE3
602 };
603 BUILD_BUG_ON(ARRAY_SIZE(pwr_info_offset) !=
604 ARRAY_SIZE(out->core_pwr_info));
Michael Buesch6b1c7c62008-12-25 00:39:28 +0100605
606 /* extract the MAC address */
Joe Perchese5652752013-02-20 12:11:05 -0800607 sprom_get_mac(out->il0mac, &in[SPOFF(SSB_SPROM8_IL0MAC)]);
608
Hauke Mehrtens673335c2012-04-29 02:04:11 +0200609 SPEX(board_rev, SSB_SPROM8_BOARDREV, 0xFFFF, 0);
Rafał Miłecki3623b262013-03-19 13:18:43 +0100610 SPEX(board_type, SSB_SPROM1_SPID, 0xFFFF, 0);
Hauke Mehrtensbf7d4202012-04-29 02:04:10 +0200611 SPEX(alpha2[0], SSB_SPROM8_CCODE, 0xff00, 8);
612 SPEX(alpha2[1], SSB_SPROM8_CCODE, 0x00ff, 0);
Michael Buesch6b1c7c62008-12-25 00:39:28 +0100613 SPEX(boardflags_lo, SSB_SPROM8_BFLLO, 0xFFFF, 0);
614 SPEX(boardflags_hi, SSB_SPROM8_BFLHI, 0xFFFF, 0);
Gábor Stefanikf6790562009-08-10 21:23:08 +0200615 SPEX(boardflags2_lo, SSB_SPROM8_BFL2LO, 0xFFFF, 0);
616 SPEX(boardflags2_hi, SSB_SPROM8_BFL2HI, 0xFFFF, 0);
Michael Buesch6b1c7c62008-12-25 00:39:28 +0100617 SPEX(ant_available_a, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_A,
618 SSB_SPROM8_ANTAVAIL_A_SHIFT);
619 SPEX(ant_available_bg, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_BG,
620 SSB_SPROM8_ANTAVAIL_BG_SHIFT);
621 SPEX(maxpwr_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_MAXP_BG_MASK, 0);
622 SPEX(itssi_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_ITSSI_BG,
623 SSB_SPROM8_ITSSI_BG_SHIFT);
624 SPEX(maxpwr_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_MAXP_A_MASK, 0);
625 SPEX(itssi_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_ITSSI_A,
626 SSB_SPROM8_ITSSI_A_SHIFT);
Gábor Stefanikf6790562009-08-10 21:23:08 +0200627 SPEX(maxpwr_ah, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AH_MASK, 0);
628 SPEX(maxpwr_al, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AL_MASK,
629 SSB_SPROM8_MAXP_AL_SHIFT);
Michael Buesch6b1c7c62008-12-25 00:39:28 +0100630 SPEX(gpio0, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P0, 0);
631 SPEX(gpio1, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P1,
632 SSB_SPROM8_GPIOA_P1_SHIFT);
633 SPEX(gpio2, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P2, 0);
634 SPEX(gpio3, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P3,
635 SSB_SPROM8_GPIOB_P3_SHIFT);
Gábor Stefanikf6790562009-08-10 21:23:08 +0200636 SPEX(tri2g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI2G, 0);
637 SPEX(tri5g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI5G,
638 SSB_SPROM8_TRI5G_SHIFT);
639 SPEX(tri5gl, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GL, 0);
640 SPEX(tri5gh, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GH,
641 SSB_SPROM8_TRI5GH_SHIFT);
642 SPEX(rxpo2g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO2G, 0);
643 SPEX(rxpo5g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO5G,
644 SSB_SPROM8_RXPO5G_SHIFT);
645 SPEX(rssismf2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMF2G, 0);
646 SPEX(rssismc2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMC2G,
647 SSB_SPROM8_RSSISMC2G_SHIFT);
648 SPEX(rssisav2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISAV2G,
649 SSB_SPROM8_RSSISAV2G_SHIFT);
650 SPEX(bxa2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_BXA2G,
651 SSB_SPROM8_BXA2G_SHIFT);
652 SPEX(rssismf5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMF5G, 0);
653 SPEX(rssismc5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMC5G,
654 SSB_SPROM8_RSSISMC5G_SHIFT);
655 SPEX(rssisav5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISAV5G,
656 SSB_SPROM8_RSSISAV5G_SHIFT);
657 SPEX(bxa5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_BXA5G,
658 SSB_SPROM8_BXA5G_SHIFT);
659 SPEX(pa0b0, SSB_SPROM8_PA0B0, 0xFFFF, 0);
660 SPEX(pa0b1, SSB_SPROM8_PA0B1, 0xFFFF, 0);
661 SPEX(pa0b2, SSB_SPROM8_PA0B2, 0xFFFF, 0);
662 SPEX(pa1b0, SSB_SPROM8_PA1B0, 0xFFFF, 0);
663 SPEX(pa1b1, SSB_SPROM8_PA1B1, 0xFFFF, 0);
664 SPEX(pa1b2, SSB_SPROM8_PA1B2, 0xFFFF, 0);
665 SPEX(pa1lob0, SSB_SPROM8_PA1LOB0, 0xFFFF, 0);
666 SPEX(pa1lob1, SSB_SPROM8_PA1LOB1, 0xFFFF, 0);
667 SPEX(pa1lob2, SSB_SPROM8_PA1LOB2, 0xFFFF, 0);
668 SPEX(pa1hib0, SSB_SPROM8_PA1HIB0, 0xFFFF, 0);
669 SPEX(pa1hib1, SSB_SPROM8_PA1HIB1, 0xFFFF, 0);
670 SPEX(pa1hib2, SSB_SPROM8_PA1HIB2, 0xFFFF, 0);
671 SPEX(cck2gpo, SSB_SPROM8_CCK2GPO, 0xFFFF, 0);
672 SPEX32(ofdm2gpo, SSB_SPROM8_OFDM2GPO, 0xFFFFFFFF, 0);
673 SPEX32(ofdm5glpo, SSB_SPROM8_OFDM5GLPO, 0xFFFFFFFF, 0);
674 SPEX32(ofdm5gpo, SSB_SPROM8_OFDM5GPO, 0xFFFFFFFF, 0);
675 SPEX32(ofdm5ghpo, SSB_SPROM8_OFDM5GHPO, 0xFFFFFFFF, 0);
Michael Buesch6b1c7c62008-12-25 00:39:28 +0100676
677 /* Extract the antenna gain values. */
Rafał Miłecki6daf4322014-07-12 16:42:10 +0200678 out->antenna_gain.a0 = sprom_extract_antgain(out->revision, in,
679 SSB_SPROM8_AGAIN01,
680 SSB_SPROM8_AGAIN0,
681 SSB_SPROM8_AGAIN0_SHIFT);
682 out->antenna_gain.a1 = sprom_extract_antgain(out->revision, in,
683 SSB_SPROM8_AGAIN01,
684 SSB_SPROM8_AGAIN1,
685 SSB_SPROM8_AGAIN1_SHIFT);
686 out->antenna_gain.a2 = sprom_extract_antgain(out->revision, in,
687 SSB_SPROM8_AGAIN23,
688 SSB_SPROM8_AGAIN2,
689 SSB_SPROM8_AGAIN2_SHIFT);
690 out->antenna_gain.a3 = sprom_extract_antgain(out->revision, in,
691 SSB_SPROM8_AGAIN23,
692 SSB_SPROM8_AGAIN3,
693 SSB_SPROM8_AGAIN3_SHIFT);
Michael Buesch6b1c7c62008-12-25 00:39:28 +0100694
Rafał Miłeckib0f70292012-01-02 08:41:23 +0100695 /* Extract cores power info info */
696 for (i = 0; i < ARRAY_SIZE(pwr_info_offset); i++) {
697 o = pwr_info_offset[i];
698 SPEX(core_pwr_info[i].itssi_2g, o + SSB_SROM8_2G_MAXP_ITSSI,
699 SSB_SPROM8_2G_ITSSI, SSB_SPROM8_2G_ITSSI_SHIFT);
700 SPEX(core_pwr_info[i].maxpwr_2g, o + SSB_SROM8_2G_MAXP_ITSSI,
701 SSB_SPROM8_2G_MAXP, 0);
702
703 SPEX(core_pwr_info[i].pa_2g[0], o + SSB_SROM8_2G_PA_0, ~0, 0);
704 SPEX(core_pwr_info[i].pa_2g[1], o + SSB_SROM8_2G_PA_1, ~0, 0);
705 SPEX(core_pwr_info[i].pa_2g[2], o + SSB_SROM8_2G_PA_2, ~0, 0);
706
707 SPEX(core_pwr_info[i].itssi_5g, o + SSB_SROM8_5G_MAXP_ITSSI,
708 SSB_SPROM8_5G_ITSSI, SSB_SPROM8_5G_ITSSI_SHIFT);
709 SPEX(core_pwr_info[i].maxpwr_5g, o + SSB_SROM8_5G_MAXP_ITSSI,
710 SSB_SPROM8_5G_MAXP, 0);
711 SPEX(core_pwr_info[i].maxpwr_5gh, o + SSB_SPROM8_5GHL_MAXP,
712 SSB_SPROM8_5GH_MAXP, 0);
713 SPEX(core_pwr_info[i].maxpwr_5gl, o + SSB_SPROM8_5GHL_MAXP,
714 SSB_SPROM8_5GL_MAXP, SSB_SPROM8_5GL_MAXP_SHIFT);
715
716 SPEX(core_pwr_info[i].pa_5gl[0], o + SSB_SROM8_5GL_PA_0, ~0, 0);
717 SPEX(core_pwr_info[i].pa_5gl[1], o + SSB_SROM8_5GL_PA_1, ~0, 0);
718 SPEX(core_pwr_info[i].pa_5gl[2], o + SSB_SROM8_5GL_PA_2, ~0, 0);
719 SPEX(core_pwr_info[i].pa_5g[0], o + SSB_SROM8_5G_PA_0, ~0, 0);
720 SPEX(core_pwr_info[i].pa_5g[1], o + SSB_SROM8_5G_PA_1, ~0, 0);
721 SPEX(core_pwr_info[i].pa_5g[2], o + SSB_SROM8_5G_PA_2, ~0, 0);
722 SPEX(core_pwr_info[i].pa_5gh[0], o + SSB_SROM8_5GH_PA_0, ~0, 0);
723 SPEX(core_pwr_info[i].pa_5gh[1], o + SSB_SROM8_5GH_PA_1, ~0, 0);
724 SPEX(core_pwr_info[i].pa_5gh[2], o + SSB_SROM8_5GH_PA_2, ~0, 0);
725 }
726
Rafał Miłecki8a5ac6e2011-12-08 18:02:21 +0100727 /* Extract FEM info */
728 SPEX(fem.ghz2.tssipos, SSB_SPROM8_FEM2G,
729 SSB_SROM8_FEM_TSSIPOS, SSB_SROM8_FEM_TSSIPOS_SHIFT);
730 SPEX(fem.ghz2.extpa_gain, SSB_SPROM8_FEM2G,
731 SSB_SROM8_FEM_EXTPA_GAIN, SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
732 SPEX(fem.ghz2.pdet_range, SSB_SPROM8_FEM2G,
733 SSB_SROM8_FEM_PDET_RANGE, SSB_SROM8_FEM_PDET_RANGE_SHIFT);
734 SPEX(fem.ghz2.tr_iso, SSB_SPROM8_FEM2G,
735 SSB_SROM8_FEM_TR_ISO, SSB_SROM8_FEM_TR_ISO_SHIFT);
736 SPEX(fem.ghz2.antswlut, SSB_SPROM8_FEM2G,
737 SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT);
738
739 SPEX(fem.ghz5.tssipos, SSB_SPROM8_FEM5G,
740 SSB_SROM8_FEM_TSSIPOS, SSB_SROM8_FEM_TSSIPOS_SHIFT);
741 SPEX(fem.ghz5.extpa_gain, SSB_SPROM8_FEM5G,
742 SSB_SROM8_FEM_EXTPA_GAIN, SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
743 SPEX(fem.ghz5.pdet_range, SSB_SPROM8_FEM5G,
744 SSB_SROM8_FEM_PDET_RANGE, SSB_SROM8_FEM_PDET_RANGE_SHIFT);
745 SPEX(fem.ghz5.tr_iso, SSB_SPROM8_FEM5G,
746 SSB_SROM8_FEM_TR_ISO, SSB_SROM8_FEM_TR_ISO_SHIFT);
747 SPEX(fem.ghz5.antswlut, SSB_SPROM8_FEM5G,
748 SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT);
749
Hauke Mehrtense2da4bd2012-04-29 02:04:13 +0200750 SPEX(leddc_on_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_ON,
751 SSB_SPROM8_LEDDC_ON_SHIFT);
752 SPEX(leddc_off_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_OFF,
753 SSB_SPROM8_LEDDC_OFF_SHIFT);
754
755 SPEX(txchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_TXCHAIN,
756 SSB_SPROM8_TXRXC_TXCHAIN_SHIFT);
757 SPEX(rxchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_RXCHAIN,
758 SSB_SPROM8_TXRXC_RXCHAIN_SHIFT);
759 SPEX(antswitch, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_SWITCH,
760 SSB_SPROM8_TXRXC_SWITCH_SHIFT);
761
762 SPEX(opo, SSB_SPROM8_OFDM2GPO, 0x00ff, 0);
763
764 SPEX_ARRAY8(mcs2gpo, SSB_SPROM8_2G_MCSPO, ~0, 0);
765 SPEX_ARRAY8(mcs5gpo, SSB_SPROM8_5G_MCSPO, ~0, 0);
766 SPEX_ARRAY8(mcs5glpo, SSB_SPROM8_5GL_MCSPO, ~0, 0);
767 SPEX_ARRAY8(mcs5ghpo, SSB_SPROM8_5GH_MCSPO, ~0, 0);
768
769 SPEX(rawtempsense, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_RAWTEMP,
770 SSB_SPROM8_RAWTS_RAWTEMP_SHIFT);
771 SPEX(measpower, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_MEASPOWER,
772 SSB_SPROM8_RAWTS_MEASPOWER_SHIFT);
773 SPEX(tempsense_slope, SSB_SPROM8_OPT_CORRX,
774 SSB_SPROM8_OPT_CORRX_TEMP_SLOPE,
775 SSB_SPROM8_OPT_CORRX_TEMP_SLOPE_SHIFT);
776 SPEX(tempcorrx, SSB_SPROM8_OPT_CORRX, SSB_SPROM8_OPT_CORRX_TEMPCORRX,
777 SSB_SPROM8_OPT_CORRX_TEMPCORRX_SHIFT);
778 SPEX(tempsense_option, SSB_SPROM8_OPT_CORRX,
779 SSB_SPROM8_OPT_CORRX_TEMP_OPTION,
780 SSB_SPROM8_OPT_CORRX_TEMP_OPTION_SHIFT);
781 SPEX(freqoffset_corr, SSB_SPROM8_HWIQ_IQSWP,
782 SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR,
783 SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR_SHIFT);
784 SPEX(iqcal_swp_dis, SSB_SPROM8_HWIQ_IQSWP,
785 SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP,
786 SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP_SHIFT);
787 SPEX(hw_iqcal_en, SSB_SPROM8_HWIQ_IQSWP, SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL,
788 SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL_SHIFT);
789
790 SPEX(bw40po, SSB_SPROM8_BW40PO, ~0, 0);
791 SPEX(cddpo, SSB_SPROM8_CDDPO, ~0, 0);
792 SPEX(stbcpo, SSB_SPROM8_STBCPO, ~0, 0);
793 SPEX(bwduppo, SSB_SPROM8_BWDUPPO, ~0, 0);
794
795 SPEX(tempthresh, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_TRESH,
796 SSB_SPROM8_THERMAL_TRESH_SHIFT);
797 SPEX(tempoffset, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_OFFSET,
798 SSB_SPROM8_THERMAL_OFFSET_SHIFT);
799 SPEX(phycal_tempdelta, SSB_SPROM8_TEMPDELTA,
800 SSB_SPROM8_TEMPDELTA_PHYCAL,
801 SSB_SPROM8_TEMPDELTA_PHYCAL_SHIFT);
802 SPEX(temps_period, SSB_SPROM8_TEMPDELTA, SSB_SPROM8_TEMPDELTA_PERIOD,
803 SSB_SPROM8_TEMPDELTA_PERIOD_SHIFT);
804 SPEX(temps_hysteresis, SSB_SPROM8_TEMPDELTA,
805 SSB_SPROM8_TEMPDELTA_HYSTERESIS,
806 SSB_SPROM8_TEMPDELTA_HYSTERESIS_SHIFT);
Rafał Miłecki172c69a2010-11-28 10:39:35 +0100807 sprom_extract_r458(out, in);
808
Michael Buesch6b1c7c62008-12-25 00:39:28 +0100809 /* TODO - get remaining rev 8 stuff needed */
810}
811
Larry Fingerc272ef42007-11-09 16:56:25 -0600812static int sprom_extract(struct ssb_bus *bus, struct ssb_sprom *out,
813 const u16 *in, u16 size)
Michael Buesch61e115a2007-09-18 15:12:50 -0400814{
815 memset(out, 0, sizeof(*out));
816
Larry Fingerc272ef42007-11-09 16:56:25 -0600817 out->revision = in[size - 1] & 0x00FF;
Michael Büschb8b60692018-07-31 21:56:38 +0200818 pr_debug("SPROM revision %d detected\n", out->revision);
Larry Finger31ce12f2008-08-20 17:45:06 -0500819 memset(out->et0mac, 0xFF, 6); /* preset et0 and et1 mac */
820 memset(out->et1mac, 0xFF, 6);
Rafał Miłecki54435f92010-11-03 22:06:26 +0100821
Michael Buesch61e115a2007-09-18 15:12:50 -0400822 if ((bus->chip_id & 0xFF00) == 0x4400) {
823 /* Workaround: The BCM44XX chip has a stupid revision
824 * number stored in the SPROM.
825 * Always extract r1. */
Larry Fingerc272ef42007-11-09 16:56:25 -0600826 out->revision = 1;
Michael Büschb8b60692018-07-31 21:56:38 +0200827 pr_debug("SPROM treated as revision %d\n", out->revision);
Rafał Miłecki54435f92010-11-03 22:06:26 +0100828 }
829
830 switch (out->revision) {
831 case 1:
832 case 2:
833 case 3:
834 sprom_extract_r123(out, in);
835 break;
836 case 4:
837 case 5:
Larry Finger095f6952008-08-19 12:50:31 -0500838 sprom_extract_r45(out, in);
Rafał Miłecki54435f92010-11-03 22:06:26 +0100839 break;
840 case 8:
841 sprom_extract_r8(out, in);
842 break;
843 default:
Michael Büschb8b60692018-07-31 21:56:38 +0200844 pr_warn("Unsupported SPROM revision %d detected. Will extract v1\n",
845 out->revision);
Rafał Miłecki54435f92010-11-03 22:06:26 +0100846 out->revision = 1;
847 sprom_extract_r123(out, in);
Michael Buesch61e115a2007-09-18 15:12:50 -0400848 }
849
Larry Finger45031832008-04-19 17:52:12 +0200850 if (out->boardflags_lo == 0xFFFF)
851 out->boardflags_lo = 0; /* per specs */
852 if (out->boardflags_hi == 0xFFFF)
853 out->boardflags_hi = 0; /* per specs */
854
Michael Buesch61e115a2007-09-18 15:12:50 -0400855 return 0;
Michael Buesch61e115a2007-09-18 15:12:50 -0400856}
857
858static int ssb_pci_sprom_get(struct ssb_bus *bus,
859 struct ssb_sprom *sprom)
860{
Rafał Miłeckica4a0832010-11-03 23:28:45 +0100861 int err;
Michael Buesch61e115a2007-09-18 15:12:50 -0400862 u16 *buf;
863
John W. Linvilled53cdbb92010-03-31 21:39:35 +0200864 if (!ssb_is_sprom_available(bus)) {
Michael Büschb8b60692018-07-31 21:56:38 +0200865 pr_err("No SPROM available!\n");
John W. Linvilled53cdbb92010-03-31 21:39:35 +0200866 return -ENODEV;
867 }
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300868 if (bus->chipco.dev) { /* can be unavailable! */
Larry Finger9d1ac342010-05-14 22:08:58 -0500869 /*
870 * get SPROM offset: SSB_SPROM_BASE1 except for
871 * chipcommon rev >= 31 or chip ID is 0x4312 and
872 * chipcommon status & 3 == 2
873 */
874 if (bus->chipco.dev->id.revision >= 31)
875 bus->sprom_offset = SSB_SPROM_BASE31;
876 else if (bus->chip_id == 0x4312 &&
877 (bus->chipco.status & 0x03) == 2)
878 bus->sprom_offset = SSB_SPROM_BASE31;
879 else
880 bus->sprom_offset = SSB_SPROM_BASE1;
Christoph Fritzda1fdb02010-05-28 10:45:59 +0200881 } else {
882 bus->sprom_offset = SSB_SPROM_BASE1;
883 }
Michael Büschb8b60692018-07-31 21:56:38 +0200884 pr_debug("SPROM offset is 0x%x\n", bus->sprom_offset);
Rafał Miłeckiea2db492010-03-31 21:59:21 +0200885
Larry Fingerc272ef42007-11-09 16:56:25 -0600886 buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL);
Michael Buesch61e115a2007-09-18 15:12:50 -0400887 if (!buf)
Rafał Miłeckica4a0832010-11-03 23:28:45 +0100888 return -ENOMEM;
Larry Fingerc272ef42007-11-09 16:56:25 -0600889 bus->sprom_size = SSB_SPROMSIZE_WORDS_R123;
Michael Buesch61e115a2007-09-18 15:12:50 -0400890 sprom_do_read(bus, buf);
Larry Fingerc272ef42007-11-09 16:56:25 -0600891 err = sprom_check_crc(buf, bus->sprom_size);
Michael Buesch61e115a2007-09-18 15:12:50 -0400892 if (err) {
Larry.Finger@lwfinger.net2afc4902008-04-19 16:24:09 +0200893 /* try for a 440 byte SPROM - revision 4 and higher */
894 kfree(buf);
895 buf = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
896 GFP_KERNEL);
897 if (!buf)
Rafał Miłeckica4a0832010-11-03 23:28:45 +0100898 return -ENOMEM;
Larry.Finger@lwfinger.net2afc4902008-04-19 16:24:09 +0200899 bus->sprom_size = SSB_SPROMSIZE_WORDS_R4;
900 sprom_do_read(bus, buf);
901 err = sprom_check_crc(buf, bus->sprom_size);
Michael Buesche79c1ba2009-02-27 16:59:05 +0100902 if (err) {
903 /* All CRC attempts failed.
904 * Maybe there is no SPROM on the device?
Hauke Mehrtensb3ae52b2011-05-10 23:31:30 +0200905 * Now we ask the arch code if there is some sprom
906 * available for this device in some other storage */
907 err = ssb_fill_sprom_with_fallback(bus, sprom);
908 if (err) {
Michael Büschb8b60692018-07-31 21:56:38 +0200909 pr_warn("WARNING: Using fallback SPROM failed (err %d)\n",
910 err);
Larry Finger8052d722016-11-05 14:08:57 -0500911 goto out_free;
Hauke Mehrtensb3ae52b2011-05-10 23:31:30 +0200912 } else {
Michael Büschb8b60692018-07-31 21:56:38 +0200913 pr_debug("Using SPROM revision %d provided by platform\n",
914 sprom->revision);
Michael Buesche79c1ba2009-02-27 16:59:05 +0100915 err = 0;
916 goto out_free;
917 }
Michael Büschb8b60692018-07-31 21:56:38 +0200918 pr_warn("WARNING: Invalid SPROM CRC (corrupt SPROM)\n");
Michael Buesche79c1ba2009-02-27 16:59:05 +0100919 }
Michael Buesch61e115a2007-09-18 15:12:50 -0400920 }
Larry Fingerc272ef42007-11-09 16:56:25 -0600921 err = sprom_extract(bus, sprom, buf, bus->sprom_size);
Michael Buesch61e115a2007-09-18 15:12:50 -0400922
Michael Buesche79c1ba2009-02-27 16:59:05 +0100923out_free:
Michael Buesch61e115a2007-09-18 15:12:50 -0400924 kfree(buf);
Michael Buesch61e115a2007-09-18 15:12:50 -0400925 return err;
926}
927
928static void ssb_pci_get_boardinfo(struct ssb_bus *bus,
929 struct ssb_boardinfo *bi)
930{
Sergei Shtylyov115f9452011-07-01 22:34:42 +0400931 bi->vendor = bus->host_pci->subsystem_vendor;
932 bi->type = bus->host_pci->subsystem_device;
Michael Buesch61e115a2007-09-18 15:12:50 -0400933}
934
935int ssb_pci_get_invariants(struct ssb_bus *bus,
936 struct ssb_init_invariants *iv)
937{
938 int err;
939
940 err = ssb_pci_sprom_get(bus, &iv->sprom);
941 if (err)
942 goto out;
943 ssb_pci_get_boardinfo(bus, &iv->boardinfo);
944
945out:
946 return err;
947}
948
Michael Buesch61e115a2007-09-18 15:12:50 -0400949static int ssb_pci_assert_buspower(struct ssb_bus *bus)
950{
951 if (likely(bus->powered_up))
952 return 0;
953
Michael Büschb8b60692018-07-31 21:56:38 +0200954 pr_err("FATAL ERROR: Bus powered down while accessing PCI MMIO space\n");
Michael Buesch61e115a2007-09-18 15:12:50 -0400955 if (bus->power_warn_count <= 10) {
956 bus->power_warn_count++;
957 dump_stack();
958 }
959
960 return -ENODEV;
961}
Michael Buesch61e115a2007-09-18 15:12:50 -0400962
Michael Bueschffc76892008-02-20 19:08:10 +0100963static u8 ssb_pci_read8(struct ssb_device *dev, u16 offset)
964{
965 struct ssb_bus *bus = dev->bus;
966
967 if (unlikely(ssb_pci_assert_buspower(bus)))
968 return 0xFF;
969 if (unlikely(bus->mapped_device != dev)) {
970 if (unlikely(ssb_pci_switch_core(bus, dev)))
971 return 0xFF;
972 }
973 return ioread8(bus->mmio + offset);
974}
975
Michael Buesch61e115a2007-09-18 15:12:50 -0400976static u16 ssb_pci_read16(struct ssb_device *dev, u16 offset)
977{
978 struct ssb_bus *bus = dev->bus;
979
980 if (unlikely(ssb_pci_assert_buspower(bus)))
981 return 0xFFFF;
982 if (unlikely(bus->mapped_device != dev)) {
983 if (unlikely(ssb_pci_switch_core(bus, dev)))
984 return 0xFFFF;
985 }
Michael Buesch4b402c62007-09-19 18:53:44 +0200986 return ioread16(bus->mmio + offset);
Michael Buesch61e115a2007-09-18 15:12:50 -0400987}
988
989static u32 ssb_pci_read32(struct ssb_device *dev, u16 offset)
990{
991 struct ssb_bus *bus = dev->bus;
992
993 if (unlikely(ssb_pci_assert_buspower(bus)))
994 return 0xFFFFFFFF;
995 if (unlikely(bus->mapped_device != dev)) {
996 if (unlikely(ssb_pci_switch_core(bus, dev)))
997 return 0xFFFFFFFF;
998 }
Michael Buesch4b402c62007-09-19 18:53:44 +0200999 return ioread32(bus->mmio + offset);
Michael Buesch61e115a2007-09-18 15:12:50 -04001000}
1001
Michael Bueschd625a292008-04-02 19:46:56 +02001002#ifdef CONFIG_SSB_BLOCKIO
1003static void ssb_pci_block_read(struct ssb_device *dev, void *buffer,
1004 size_t count, u16 offset, u8 reg_width)
1005{
1006 struct ssb_bus *bus = dev->bus;
1007 void __iomem *addr = bus->mmio + offset;
1008
1009 if (unlikely(ssb_pci_assert_buspower(bus)))
1010 goto error;
1011 if (unlikely(bus->mapped_device != dev)) {
1012 if (unlikely(ssb_pci_switch_core(bus, dev)))
1013 goto error;
1014 }
1015 switch (reg_width) {
1016 case sizeof(u8):
1017 ioread8_rep(addr, buffer, count);
1018 break;
1019 case sizeof(u16):
Michael Büsch209b4372018-07-31 22:15:09 +02001020 WARN_ON(count & 1);
Michael Bueschd625a292008-04-02 19:46:56 +02001021 ioread16_rep(addr, buffer, count >> 1);
1022 break;
1023 case sizeof(u32):
Michael Büsch209b4372018-07-31 22:15:09 +02001024 WARN_ON(count & 3);
Michael Bueschd625a292008-04-02 19:46:56 +02001025 ioread32_rep(addr, buffer, count >> 2);
1026 break;
1027 default:
Michael Büsch209b4372018-07-31 22:15:09 +02001028 WARN_ON(1);
Michael Bueschd625a292008-04-02 19:46:56 +02001029 }
1030
1031 return;
1032error:
1033 memset(buffer, 0xFF, count);
1034}
1035#endif /* CONFIG_SSB_BLOCKIO */
1036
Michael Bueschffc76892008-02-20 19:08:10 +01001037static void ssb_pci_write8(struct ssb_device *dev, u16 offset, u8 value)
1038{
1039 struct ssb_bus *bus = dev->bus;
1040
1041 if (unlikely(ssb_pci_assert_buspower(bus)))
1042 return;
1043 if (unlikely(bus->mapped_device != dev)) {
1044 if (unlikely(ssb_pci_switch_core(bus, dev)))
1045 return;
1046 }
1047 iowrite8(value, bus->mmio + offset);
1048}
1049
Michael Buesch61e115a2007-09-18 15:12:50 -04001050static void ssb_pci_write16(struct ssb_device *dev, u16 offset, u16 value)
1051{
1052 struct ssb_bus *bus = dev->bus;
1053
1054 if (unlikely(ssb_pci_assert_buspower(bus)))
1055 return;
1056 if (unlikely(bus->mapped_device != dev)) {
1057 if (unlikely(ssb_pci_switch_core(bus, dev)))
1058 return;
1059 }
Michael Buesch4b402c62007-09-19 18:53:44 +02001060 iowrite16(value, bus->mmio + offset);
Michael Buesch61e115a2007-09-18 15:12:50 -04001061}
1062
1063static void ssb_pci_write32(struct ssb_device *dev, u16 offset, u32 value)
1064{
1065 struct ssb_bus *bus = dev->bus;
1066
1067 if (unlikely(ssb_pci_assert_buspower(bus)))
1068 return;
1069 if (unlikely(bus->mapped_device != dev)) {
1070 if (unlikely(ssb_pci_switch_core(bus, dev)))
1071 return;
1072 }
Michael Buesch4b402c62007-09-19 18:53:44 +02001073 iowrite32(value, bus->mmio + offset);
Michael Buesch61e115a2007-09-18 15:12:50 -04001074}
1075
Michael Bueschd625a292008-04-02 19:46:56 +02001076#ifdef CONFIG_SSB_BLOCKIO
1077static void ssb_pci_block_write(struct ssb_device *dev, const void *buffer,
1078 size_t count, u16 offset, u8 reg_width)
1079{
1080 struct ssb_bus *bus = dev->bus;
1081 void __iomem *addr = bus->mmio + offset;
1082
1083 if (unlikely(ssb_pci_assert_buspower(bus)))
1084 return;
1085 if (unlikely(bus->mapped_device != dev)) {
1086 if (unlikely(ssb_pci_switch_core(bus, dev)))
1087 return;
1088 }
1089 switch (reg_width) {
1090 case sizeof(u8):
1091 iowrite8_rep(addr, buffer, count);
1092 break;
1093 case sizeof(u16):
Michael Büsch209b4372018-07-31 22:15:09 +02001094 WARN_ON(count & 1);
Michael Bueschd625a292008-04-02 19:46:56 +02001095 iowrite16_rep(addr, buffer, count >> 1);
1096 break;
1097 case sizeof(u32):
Michael Büsch209b4372018-07-31 22:15:09 +02001098 WARN_ON(count & 3);
Michael Bueschd625a292008-04-02 19:46:56 +02001099 iowrite32_rep(addr, buffer, count >> 2);
1100 break;
1101 default:
Michael Büsch209b4372018-07-31 22:15:09 +02001102 WARN_ON(1);
Michael Bueschd625a292008-04-02 19:46:56 +02001103 }
1104}
1105#endif /* CONFIG_SSB_BLOCKIO */
1106
Michael Buesch61e115a2007-09-18 15:12:50 -04001107/* Not "static", as it's used in main.c */
1108const struct ssb_bus_ops ssb_pci_ops = {
Michael Bueschffc76892008-02-20 19:08:10 +01001109 .read8 = ssb_pci_read8,
Michael Buesch61e115a2007-09-18 15:12:50 -04001110 .read16 = ssb_pci_read16,
1111 .read32 = ssb_pci_read32,
Michael Bueschffc76892008-02-20 19:08:10 +01001112 .write8 = ssb_pci_write8,
Michael Buesch61e115a2007-09-18 15:12:50 -04001113 .write16 = ssb_pci_write16,
1114 .write32 = ssb_pci_write32,
Michael Bueschd625a292008-04-02 19:46:56 +02001115#ifdef CONFIG_SSB_BLOCKIO
1116 .block_read = ssb_pci_block_read,
1117 .block_write = ssb_pci_block_write,
1118#endif
Michael Buesch61e115a2007-09-18 15:12:50 -04001119};
1120
Michael Buesch61e115a2007-09-18 15:12:50 -04001121static ssize_t ssb_pci_attr_sprom_show(struct device *pcidev,
1122 struct device_attribute *attr,
1123 char *buf)
1124{
1125 struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev);
1126 struct ssb_bus *bus;
Michael Buesch61e115a2007-09-18 15:12:50 -04001127
1128 bus = ssb_pci_dev_to_bus(pdev);
1129 if (!bus)
Michael Buesche7ec2e32008-03-10 17:26:32 +01001130 return -ENODEV;
Michael Buesch61e115a2007-09-18 15:12:50 -04001131
Michael Buesche7ec2e32008-03-10 17:26:32 +01001132 return ssb_attr_sprom_show(bus, buf, sprom_do_read);
Michael Buesch61e115a2007-09-18 15:12:50 -04001133}
1134
1135static ssize_t ssb_pci_attr_sprom_store(struct device *pcidev,
1136 struct device_attribute *attr,
1137 const char *buf, size_t count)
1138{
1139 struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev);
1140 struct ssb_bus *bus;
Michael Buesch61e115a2007-09-18 15:12:50 -04001141
1142 bus = ssb_pci_dev_to_bus(pdev);
1143 if (!bus)
Michael Buesche7ec2e32008-03-10 17:26:32 +01001144 return -ENODEV;
Michael Buesch61e115a2007-09-18 15:12:50 -04001145
Michael Buesche7ec2e32008-03-10 17:26:32 +01001146 return ssb_attr_sprom_store(bus, buf, count,
1147 sprom_check_crc, sprom_do_write);
Michael Buesch61e115a2007-09-18 15:12:50 -04001148}
1149
1150static DEVICE_ATTR(ssb_sprom, 0600,
1151 ssb_pci_attr_sprom_show,
1152 ssb_pci_attr_sprom_store);
1153
1154void ssb_pci_exit(struct ssb_bus *bus)
1155{
1156 struct pci_dev *pdev;
1157
1158 if (bus->bustype != SSB_BUSTYPE_PCI)
1159 return;
1160
1161 pdev = bus->host_pci;
1162 device_remove_file(&pdev->dev, &dev_attr_ssb_sprom);
1163}
1164
1165int ssb_pci_init(struct ssb_bus *bus)
1166{
1167 struct pci_dev *pdev;
1168 int err;
1169
1170 if (bus->bustype != SSB_BUSTYPE_PCI)
1171 return 0;
1172
1173 pdev = bus->host_pci;
Michael Buesche7ec2e32008-03-10 17:26:32 +01001174 mutex_init(&bus->sprom_mutex);
Michael Buesch61e115a2007-09-18 15:12:50 -04001175 err = device_create_file(&pdev->dev, &dev_attr_ssb_sprom);
1176 if (err)
1177 goto out;
1178
1179out:
1180 return err;
1181}