1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * BCMA Fallback SPROM Driver
5 * Copyright (C) 2020 Álvaro Fernández Rojas <noltari@gmail.com>
6 * Copyright (C) 2014 Jonas Gorski <jonas.gorski@gmail.com>
7 * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
8 * Copyright (C) 2008 Florian Fainelli <f.fainelli@gmail.com>
11 #include <linux/bcma/bcma.h>
12 #include <linux/etherdevice.h>
13 #include <linux/firmware.h>
14 #include <linux/init.h>
15 #include <linux/kernel.h>
16 #include <linux/mtd/mtd.h>
17 #include <linux/of_net.h>
18 #include <linux/of_platform.h>
20 #define BCMA_FBS_MAX_SIZE 468
22 /* SPROM Extraction */
23 #define SPOFF(offset) ((offset) / sizeof(u16))
25 #define SPEX(_outvar, _offset, _mask, _shift) \
26 out->_outvar = ((in[SPOFF(_offset)] & (_mask)) >> (_shift))
28 #define SPEX32(_outvar, _offset, _mask, _shift) \
29 out->_outvar = ((((u32)in[SPOFF((_offset)+2)] << 16 | \
30 in[SPOFF(_offset)]) & (_mask)) >> (_shift))
32 #define SPEX_ARRAY8(_field, _offset, _mask, _shift) \
34 SPEX(_field[0], _offset + 0, _mask, _shift); \
35 SPEX(_field[1], _offset + 2, _mask, _shift); \
36 SPEX(_field[2], _offset + 4, _mask, _shift); \
37 SPEX(_field[3], _offset + 6, _mask, _shift); \
38 SPEX(_field[4], _offset + 8, _mask, _shift); \
39 SPEX(_field[5], _offset + 10, _mask, _shift); \
40 SPEX(_field[6], _offset + 12, _mask, _shift); \
41 SPEX(_field[7], _offset + 14, _mask, _shift); \
46 struct list_head list
;
47 struct ssb_sprom sprom
;
53 static DEFINE_SPINLOCK(bcma_fbs_lock
);
54 static struct list_head bcma_fbs_list
= LIST_HEAD_INIT(bcma_fbs_list
);
56 int bcma_get_fallback_sprom(struct bcma_bus
*bus
, struct ssb_sprom
*out
)
58 const u32 pci_bus
= bus
->host_pci
->bus
->number
;
59 const u32 pci_dev
= PCI_SLOT(bus
->host_pci
->devfn
);
62 list_for_each_entry(pos
, &bcma_fbs_list
, list
) {
63 if (pos
->pci_bus
!= pci_bus
||
64 pos
->pci_dev
!= pci_dev
)
67 if (pos
->devid_override
)
68 bus
->host_pci
->device
= pos
->sprom
.dev_id
;
70 memcpy(out
, &pos
->sprom
, sizeof(struct ssb_sprom
));
71 dev_info(pos
->dev
, "requested by [%x:%x]",
72 pos
->pci_bus
, pos
->pci_dev
);
77 pr_err("unable to fill SPROM for [%x:%x]\n", pci_bus
, pci_dev
);
82 static s8
sprom_extract_antgain(const u16
*in
, u16 offset
, u16 mask
, u16 shift
)
87 v
= in
[SPOFF(offset
)];
88 gain
= (v
& mask
) >> shift
;
90 gain
= 8; /* If unset use 2dBm */
92 /* Q5.2 Fractional part is stored in 0xC0 */
93 gain
= ((gain
& 0xC0) >> 6) | ((gain
& 0x3F) << 2);
99 static void sprom_extract_r8(struct ssb_sprom
*out
, const u16
*in
)
101 static const u16 pwr_info_offset
[] = {
102 SSB_SROM8_PWR_INFO_CORE0
, SSB_SROM8_PWR_INFO_CORE1
,
103 SSB_SROM8_PWR_INFO_CORE2
, SSB_SROM8_PWR_INFO_CORE3
108 BUILD_BUG_ON(ARRAY_SIZE(pwr_info_offset
) !=
109 ARRAY_SIZE(out
->core_pwr_info
));
111 SPEX(board_rev
, SSB_SPROM8_BOARDREV
, ~0, 0);
112 SPEX(board_type
, SSB_SPROM1_SPID
, ~0, 0);
114 SPEX(txpid2g
[0], SSB_SPROM4_TXPID2G01
, SSB_SPROM4_TXPID2G0
,
115 SSB_SPROM4_TXPID2G0_SHIFT
);
116 SPEX(txpid2g
[1], SSB_SPROM4_TXPID2G01
, SSB_SPROM4_TXPID2G1
,
117 SSB_SPROM4_TXPID2G1_SHIFT
);
118 SPEX(txpid2g
[2], SSB_SPROM4_TXPID2G23
, SSB_SPROM4_TXPID2G2
,
119 SSB_SPROM4_TXPID2G2_SHIFT
);
120 SPEX(txpid2g
[3], SSB_SPROM4_TXPID2G23
, SSB_SPROM4_TXPID2G3
,
121 SSB_SPROM4_TXPID2G3_SHIFT
);
123 SPEX(txpid5gl
[0], SSB_SPROM4_TXPID5GL01
, SSB_SPROM4_TXPID5GL0
,
124 SSB_SPROM4_TXPID5GL0_SHIFT
);
125 SPEX(txpid5gl
[1], SSB_SPROM4_TXPID5GL01
, SSB_SPROM4_TXPID5GL1
,
126 SSB_SPROM4_TXPID5GL1_SHIFT
);
127 SPEX(txpid5gl
[2], SSB_SPROM4_TXPID5GL23
, SSB_SPROM4_TXPID5GL2
,
128 SSB_SPROM4_TXPID5GL2_SHIFT
);
129 SPEX(txpid5gl
[3], SSB_SPROM4_TXPID5GL23
, SSB_SPROM4_TXPID5GL3
,
130 SSB_SPROM4_TXPID5GL3_SHIFT
);
132 SPEX(txpid5g
[0], SSB_SPROM4_TXPID5G01
, SSB_SPROM4_TXPID5G0
,
133 SSB_SPROM4_TXPID5G0_SHIFT
);
134 SPEX(txpid5g
[1], SSB_SPROM4_TXPID5G01
, SSB_SPROM4_TXPID5G1
,
135 SSB_SPROM4_TXPID5G1_SHIFT
);
136 SPEX(txpid5g
[2], SSB_SPROM4_TXPID5G23
, SSB_SPROM4_TXPID5G2
,
137 SSB_SPROM4_TXPID5G2_SHIFT
);
138 SPEX(txpid5g
[3], SSB_SPROM4_TXPID5G23
, SSB_SPROM4_TXPID5G3
,
139 SSB_SPROM4_TXPID5G3_SHIFT
);
141 SPEX(txpid5gh
[0], SSB_SPROM4_TXPID5GH01
, SSB_SPROM4_TXPID5GH0
,
142 SSB_SPROM4_TXPID5GH0_SHIFT
);
143 SPEX(txpid5gh
[1], SSB_SPROM4_TXPID5GH01
, SSB_SPROM4_TXPID5GH1
,
144 SSB_SPROM4_TXPID5GH1_SHIFT
);
145 SPEX(txpid5gh
[2], SSB_SPROM4_TXPID5GH23
, SSB_SPROM4_TXPID5GH2
,
146 SSB_SPROM4_TXPID5GH2_SHIFT
);
147 SPEX(txpid5gh
[3], SSB_SPROM4_TXPID5GH23
, SSB_SPROM4_TXPID5GH3
,
148 SSB_SPROM4_TXPID5GH3_SHIFT
);
150 SPEX(boardflags_lo
, SSB_SPROM8_BFLLO
, ~0, 0);
151 SPEX(boardflags_hi
, SSB_SPROM8_BFLHI
, ~0, 0);
152 SPEX(boardflags2_lo
, SSB_SPROM8_BFL2LO
, ~0, 0);
153 SPEX(boardflags2_hi
, SSB_SPROM8_BFL2HI
, ~0, 0);
155 SPEX(alpha2
[0], SSB_SPROM8_CCODE
, 0xff00, 8);
156 SPEX(alpha2
[1], SSB_SPROM8_CCODE
, 0x00ff, 0);
158 /* Extract core's power info */
159 for (i
= 0; i
< ARRAY_SIZE(pwr_info_offset
); i
++) {
160 o
= pwr_info_offset
[i
];
161 SPEX(core_pwr_info
[i
].itssi_2g
, o
+ SSB_SROM8_2G_MAXP_ITSSI
,
162 SSB_SPROM8_2G_ITSSI
, SSB_SPROM8_2G_ITSSI_SHIFT
);
163 SPEX(core_pwr_info
[i
].maxpwr_2g
, o
+ SSB_SROM8_2G_MAXP_ITSSI
,
164 SSB_SPROM8_2G_MAXP
, 0);
166 SPEX(core_pwr_info
[i
].pa_2g
[0], o
+ SSB_SROM8_2G_PA_0
, ~0, 0);
167 SPEX(core_pwr_info
[i
].pa_2g
[1], o
+ SSB_SROM8_2G_PA_1
, ~0, 0);
168 SPEX(core_pwr_info
[i
].pa_2g
[2], o
+ SSB_SROM8_2G_PA_2
, ~0, 0);
170 SPEX(core_pwr_info
[i
].itssi_5g
, o
+ SSB_SROM8_5G_MAXP_ITSSI
,
171 SSB_SPROM8_5G_ITSSI
, SSB_SPROM8_5G_ITSSI_SHIFT
);
172 SPEX(core_pwr_info
[i
].maxpwr_5g
, o
+ SSB_SROM8_5G_MAXP_ITSSI
,
173 SSB_SPROM8_5G_MAXP
, 0);
174 SPEX(core_pwr_info
[i
].maxpwr_5gh
, o
+ SSB_SPROM8_5GHL_MAXP
,
175 SSB_SPROM8_5GH_MAXP
, 0);
176 SPEX(core_pwr_info
[i
].maxpwr_5gl
, o
+ SSB_SPROM8_5GHL_MAXP
,
177 SSB_SPROM8_5GL_MAXP
, SSB_SPROM8_5GL_MAXP_SHIFT
);
179 SPEX(core_pwr_info
[i
].pa_5gl
[0], o
+ SSB_SROM8_5GL_PA_0
, ~0, 0);
180 SPEX(core_pwr_info
[i
].pa_5gl
[1], o
+ SSB_SROM8_5GL_PA_1
, ~0, 0);
181 SPEX(core_pwr_info
[i
].pa_5gl
[2], o
+ SSB_SROM8_5GL_PA_2
, ~0, 0);
182 SPEX(core_pwr_info
[i
].pa_5g
[0], o
+ SSB_SROM8_5G_PA_0
, ~0, 0);
183 SPEX(core_pwr_info
[i
].pa_5g
[1], o
+ SSB_SROM8_5G_PA_1
, ~0, 0);
184 SPEX(core_pwr_info
[i
].pa_5g
[2], o
+ SSB_SROM8_5G_PA_2
, ~0, 0);
185 SPEX(core_pwr_info
[i
].pa_5gh
[0], o
+ SSB_SROM8_5GH_PA_0
, ~0, 0);
186 SPEX(core_pwr_info
[i
].pa_5gh
[1], o
+ SSB_SROM8_5GH_PA_1
, ~0, 0);
187 SPEX(core_pwr_info
[i
].pa_5gh
[2], o
+ SSB_SROM8_5GH_PA_2
, ~0, 0);
190 SPEX(fem
.ghz2
.tssipos
, SSB_SPROM8_FEM2G
, SSB_SROM8_FEM_TSSIPOS
,
191 SSB_SROM8_FEM_TSSIPOS_SHIFT
);
192 SPEX(fem
.ghz2
.extpa_gain
, SSB_SPROM8_FEM2G
, SSB_SROM8_FEM_EXTPA_GAIN
,
193 SSB_SROM8_FEM_EXTPA_GAIN_SHIFT
);
194 SPEX(fem
.ghz2
.pdet_range
, SSB_SPROM8_FEM2G
, SSB_SROM8_FEM_PDET_RANGE
,
195 SSB_SROM8_FEM_PDET_RANGE_SHIFT
);
196 SPEX(fem
.ghz2
.tr_iso
, SSB_SPROM8_FEM2G
, SSB_SROM8_FEM_TR_ISO
,
197 SSB_SROM8_FEM_TR_ISO_SHIFT
);
198 SPEX(fem
.ghz2
.antswlut
, SSB_SPROM8_FEM2G
, SSB_SROM8_FEM_ANTSWLUT
,
199 SSB_SROM8_FEM_ANTSWLUT_SHIFT
);
201 SPEX(fem
.ghz5
.tssipos
, SSB_SPROM8_FEM5G
, SSB_SROM8_FEM_TSSIPOS
,
202 SSB_SROM8_FEM_TSSIPOS_SHIFT
);
203 SPEX(fem
.ghz5
.extpa_gain
, SSB_SPROM8_FEM5G
, SSB_SROM8_FEM_EXTPA_GAIN
,
204 SSB_SROM8_FEM_EXTPA_GAIN_SHIFT
);
205 SPEX(fem
.ghz5
.pdet_range
, SSB_SPROM8_FEM5G
, SSB_SROM8_FEM_PDET_RANGE
,
206 SSB_SROM8_FEM_PDET_RANGE_SHIFT
);
207 SPEX(fem
.ghz5
.tr_iso
, SSB_SPROM8_FEM5G
, SSB_SROM8_FEM_TR_ISO
,
208 SSB_SROM8_FEM_TR_ISO_SHIFT
);
209 SPEX(fem
.ghz5
.antswlut
, SSB_SPROM8_FEM5G
, SSB_SROM8_FEM_ANTSWLUT
,
210 SSB_SROM8_FEM_ANTSWLUT_SHIFT
);
212 SPEX(ant_available_a
, SSB_SPROM8_ANTAVAIL
, SSB_SPROM8_ANTAVAIL_A
,
213 SSB_SPROM8_ANTAVAIL_A_SHIFT
);
214 SPEX(ant_available_bg
, SSB_SPROM8_ANTAVAIL
, SSB_SPROM8_ANTAVAIL_BG
,
215 SSB_SPROM8_ANTAVAIL_BG_SHIFT
);
216 SPEX(maxpwr_bg
, SSB_SPROM8_MAXP_BG
, SSB_SPROM8_MAXP_BG_MASK
, 0);
217 SPEX(itssi_bg
, SSB_SPROM8_MAXP_BG
, SSB_SPROM8_ITSSI_BG
,
218 SSB_SPROM8_ITSSI_BG_SHIFT
);
219 SPEX(maxpwr_a
, SSB_SPROM8_MAXP_A
, SSB_SPROM8_MAXP_A_MASK
, 0);
220 SPEX(itssi_a
, SSB_SPROM8_MAXP_A
, SSB_SPROM8_ITSSI_A
,
221 SSB_SPROM8_ITSSI_A_SHIFT
);
222 SPEX(maxpwr_ah
, SSB_SPROM8_MAXP_AHL
, SSB_SPROM8_MAXP_AH_MASK
, 0);
223 SPEX(maxpwr_al
, SSB_SPROM8_MAXP_AHL
, SSB_SPROM8_MAXP_AL_MASK
,
224 SSB_SPROM8_MAXP_AL_SHIFT
);
225 SPEX(gpio0
, SSB_SPROM8_GPIOA
, SSB_SPROM8_GPIOA_P0
, 0);
226 SPEX(gpio1
, SSB_SPROM8_GPIOA
, SSB_SPROM8_GPIOA_P1
,
227 SSB_SPROM8_GPIOA_P1_SHIFT
);
228 SPEX(gpio2
, SSB_SPROM8_GPIOB
, SSB_SPROM8_GPIOB_P2
, 0);
229 SPEX(gpio3
, SSB_SPROM8_GPIOB
, SSB_SPROM8_GPIOB_P3
,
230 SSB_SPROM8_GPIOB_P3_SHIFT
);
231 SPEX(tri2g
, SSB_SPROM8_TRI25G
, SSB_SPROM8_TRI2G
, 0);
232 SPEX(tri5g
, SSB_SPROM8_TRI25G
, SSB_SPROM8_TRI5G
,
233 SSB_SPROM8_TRI5G_SHIFT
);
234 SPEX(tri5gl
, SSB_SPROM8_TRI5GHL
, SSB_SPROM8_TRI5GL
, 0);
235 SPEX(tri5gh
, SSB_SPROM8_TRI5GHL
, SSB_SPROM8_TRI5GH
,
236 SSB_SPROM8_TRI5GH_SHIFT
);
237 SPEX(rxpo2g
, SSB_SPROM8_RXPO
, SSB_SPROM8_RXPO2G
,
238 SSB_SPROM8_RXPO2G_SHIFT
);
239 SPEX(rxpo5g
, SSB_SPROM8_RXPO
, SSB_SPROM8_RXPO5G
,
240 SSB_SPROM8_RXPO5G_SHIFT
);
241 SPEX(rssismf2g
, SSB_SPROM8_RSSIPARM2G
, SSB_SPROM8_RSSISMF2G
, 0);
242 SPEX(rssismc2g
, SSB_SPROM8_RSSIPARM2G
, SSB_SPROM8_RSSISMC2G
,
243 SSB_SPROM8_RSSISMC2G_SHIFT
);
244 SPEX(rssisav2g
, SSB_SPROM8_RSSIPARM2G
, SSB_SPROM8_RSSISAV2G
,
245 SSB_SPROM8_RSSISAV2G_SHIFT
);
246 SPEX(bxa2g
, SSB_SPROM8_RSSIPARM2G
, SSB_SPROM8_BXA2G
,
247 SSB_SPROM8_BXA2G_SHIFT
);
248 SPEX(rssismf5g
, SSB_SPROM8_RSSIPARM5G
, SSB_SPROM8_RSSISMF5G
, 0);
249 SPEX(rssismc5g
, SSB_SPROM8_RSSIPARM5G
, SSB_SPROM8_RSSISMC5G
,
250 SSB_SPROM8_RSSISMC5G_SHIFT
);
251 SPEX(rssisav5g
, SSB_SPROM8_RSSIPARM5G
, SSB_SPROM8_RSSISAV5G
,
252 SSB_SPROM8_RSSISAV5G_SHIFT
);
253 SPEX(bxa5g
, SSB_SPROM8_RSSIPARM5G
, SSB_SPROM8_BXA5G
,
254 SSB_SPROM8_BXA5G_SHIFT
);
256 SPEX(pa0b0
, SSB_SPROM8_PA0B0
, ~0, 0);
257 SPEX(pa0b1
, SSB_SPROM8_PA0B1
, ~0, 0);
258 SPEX(pa0b2
, SSB_SPROM8_PA0B2
, ~0, 0);
259 SPEX(pa1b0
, SSB_SPROM8_PA1B0
, ~0, 0);
260 SPEX(pa1b1
, SSB_SPROM8_PA1B1
, ~0, 0);
261 SPEX(pa1b2
, SSB_SPROM8_PA1B2
, ~0, 0);
262 SPEX(pa1lob0
, SSB_SPROM8_PA1LOB0
, ~0, 0);
263 SPEX(pa1lob1
, SSB_SPROM8_PA1LOB1
, ~0, 0);
264 SPEX(pa1lob2
, SSB_SPROM8_PA1LOB2
, ~0, 0);
265 SPEX(pa1hib0
, SSB_SPROM8_PA1HIB0
, ~0, 0);
266 SPEX(pa1hib1
, SSB_SPROM8_PA1HIB1
, ~0, 0);
267 SPEX(pa1hib2
, SSB_SPROM8_PA1HIB2
, ~0, 0);
268 SPEX(cck2gpo
, SSB_SPROM8_CCK2GPO
, ~0, 0);
269 SPEX32(ofdm2gpo
, SSB_SPROM8_OFDM2GPO
, ~0, 0);
270 SPEX32(ofdm5glpo
, SSB_SPROM8_OFDM5GLPO
, ~0, 0);
271 SPEX32(ofdm5gpo
, SSB_SPROM8_OFDM5GPO
, ~0, 0);
272 SPEX32(ofdm5ghpo
, SSB_SPROM8_OFDM5GHPO
, ~0, 0);
274 /* Extract the antenna gain values. */
275 out
->antenna_gain
.a0
= sprom_extract_antgain(in
,
278 SSB_SPROM8_AGAIN0_SHIFT
);
279 out
->antenna_gain
.a1
= sprom_extract_antgain(in
,
282 SSB_SPROM8_AGAIN1_SHIFT
);
283 out
->antenna_gain
.a2
= sprom_extract_antgain(in
,
286 SSB_SPROM8_AGAIN2_SHIFT
);
287 out
->antenna_gain
.a3
= sprom_extract_antgain(in
,
290 SSB_SPROM8_AGAIN3_SHIFT
);
292 SPEX(leddc_on_time
, SSB_SPROM8_LEDDC
, SSB_SPROM8_LEDDC_ON
,
293 SSB_SPROM8_LEDDC_ON_SHIFT
);
294 SPEX(leddc_off_time
, SSB_SPROM8_LEDDC
, SSB_SPROM8_LEDDC_OFF
,
295 SSB_SPROM8_LEDDC_OFF_SHIFT
);
297 SPEX(txchain
, SSB_SPROM8_TXRXC
, SSB_SPROM8_TXRXC_TXCHAIN
,
298 SSB_SPROM8_TXRXC_TXCHAIN_SHIFT
);
299 SPEX(rxchain
, SSB_SPROM8_TXRXC
, SSB_SPROM8_TXRXC_RXCHAIN
,
300 SSB_SPROM8_TXRXC_RXCHAIN_SHIFT
);
301 SPEX(antswitch
, SSB_SPROM8_TXRXC
, SSB_SPROM8_TXRXC_SWITCH
,
302 SSB_SPROM8_TXRXC_SWITCH_SHIFT
);
304 SPEX(opo
, SSB_SPROM8_OFDM2GPO
, 0x00ff, 0);
306 SPEX_ARRAY8(mcs2gpo
, SSB_SPROM8_2G_MCSPO
, ~0, 0);
307 SPEX_ARRAY8(mcs5gpo
, SSB_SPROM8_5G_MCSPO
, ~0, 0);
308 SPEX_ARRAY8(mcs5glpo
, SSB_SPROM8_5GL_MCSPO
, ~0, 0);
309 SPEX_ARRAY8(mcs5ghpo
, SSB_SPROM8_5GH_MCSPO
, ~0, 0);
311 SPEX(rawtempsense
, SSB_SPROM8_RAWTS
, SSB_SPROM8_RAWTS_RAWTEMP
,
312 SSB_SPROM8_RAWTS_RAWTEMP_SHIFT
);
313 SPEX(measpower
, SSB_SPROM8_RAWTS
, SSB_SPROM8_RAWTS_MEASPOWER
,
314 SSB_SPROM8_RAWTS_MEASPOWER_SHIFT
);
315 SPEX(tempsense_slope
, SSB_SPROM8_OPT_CORRX
,
316 SSB_SPROM8_OPT_CORRX_TEMP_SLOPE
,
317 SSB_SPROM8_OPT_CORRX_TEMP_SLOPE_SHIFT
);
318 SPEX(tempcorrx
, SSB_SPROM8_OPT_CORRX
, SSB_SPROM8_OPT_CORRX_TEMPCORRX
,
319 SSB_SPROM8_OPT_CORRX_TEMPCORRX_SHIFT
);
320 SPEX(tempsense_option
, SSB_SPROM8_OPT_CORRX
,
321 SSB_SPROM8_OPT_CORRX_TEMP_OPTION
,
322 SSB_SPROM8_OPT_CORRX_TEMP_OPTION_SHIFT
);
323 SPEX(freqoffset_corr
, SSB_SPROM8_HWIQ_IQSWP
,
324 SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR
,
325 SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR_SHIFT
);
326 SPEX(iqcal_swp_dis
, SSB_SPROM8_HWIQ_IQSWP
,
327 SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP
,
328 SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP_SHIFT
);
329 SPEX(hw_iqcal_en
, SSB_SPROM8_HWIQ_IQSWP
, SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL
,
330 SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL_SHIFT
);
332 SPEX(bw40po
, SSB_SPROM8_BW40PO
, ~0, 0);
333 SPEX(cddpo
, SSB_SPROM8_CDDPO
, ~0, 0);
334 SPEX(stbcpo
, SSB_SPROM8_STBCPO
, ~0, 0);
335 SPEX(bwduppo
, SSB_SPROM8_BWDUPPO
, ~0, 0);
337 SPEX(tempthresh
, SSB_SPROM8_THERMAL
, SSB_SPROM8_THERMAL_TRESH
,
338 SSB_SPROM8_THERMAL_TRESH_SHIFT
);
339 SPEX(tempoffset
, SSB_SPROM8_THERMAL
, SSB_SPROM8_THERMAL_OFFSET
,
340 SSB_SPROM8_THERMAL_OFFSET_SHIFT
);
341 SPEX(phycal_tempdelta
, SSB_SPROM8_TEMPDELTA
,
342 SSB_SPROM8_TEMPDELTA_PHYCAL
,
343 SSB_SPROM8_TEMPDELTA_PHYCAL_SHIFT
);
344 SPEX(temps_period
, SSB_SPROM8_TEMPDELTA
, SSB_SPROM8_TEMPDELTA_PERIOD
,
345 SSB_SPROM8_TEMPDELTA_PERIOD_SHIFT
);
346 SPEX(temps_hysteresis
, SSB_SPROM8_TEMPDELTA
,
347 SSB_SPROM8_TEMPDELTA_HYSTERESIS
,
348 SSB_SPROM8_TEMPDELTA_HYSTERESIS_SHIFT
);
351 static int sprom_extract(struct bcma_fbs
*priv
, const u16
*in
, u16 size
)
353 struct ssb_sprom
*out
= &priv
->sprom
;
355 memset(out
, 0, sizeof(*out
));
357 out
->revision
= in
[size
- 1] & 0x00FF;
358 if (out
->revision
< 8 || out
->revision
> 11) {
360 "Unsupported SPROM revision %d detected."
361 " Will extract v8\n",
366 sprom_extract_r8(out
, in
);
371 static void bcma_fbs_fixup(struct bcma_fbs
*priv
, u16
*sprom
)
373 struct device_node
*node
= priv
->dev
->of_node
;
374 u32 fixups
, off
, val
;
377 if (!of_get_property(node
, "brcm,sprom-fixups", &fixups
))
380 fixups
/= sizeof(u32
);
382 dev_info(priv
->dev
, "patching SPROM with %u fixups...\n", fixups
>> 1);
385 if (of_property_read_u32_index(node
, "brcm,sprom-fixups",
387 dev_err(priv
->dev
, "error reading fixup[%u] offset\n",
392 if (of_property_read_u32_index(node
, "brcm,sprom-fixups",
394 dev_err(priv
->dev
, "error reading fixup[%u] value\n",
399 dev_dbg(priv
->dev
, "fixup[%d]=0x%04x\n", off
, val
);
405 static bool sprom_override_devid(struct bcma_fbs
*priv
, struct ssb_sprom
*out
,
408 SPEX(dev_id
, 0x0060, 0xFFFF, 0);
409 return !!out
->dev_id
;
412 static void bcma_fbs_set(struct bcma_fbs
*priv
, struct device_node
*node
)
414 struct ssb_sprom
*sprom
= &priv
->sprom
;
415 const struct firmware
*fw
;
416 const char *sprom_name
;
419 if (of_property_read_string(node
, "brcm,sprom", &sprom_name
))
423 err
= request_firmware_direct(&fw
, sprom_name
, priv
->dev
);
425 dev_err(priv
->dev
, "%s load error\n", sprom_name
);
431 sprom
->revision
= 0x02;
432 sprom
->board_rev
= 0x0017;
433 sprom
->country_code
= 0x00;
434 sprom
->ant_available_bg
= 0x03;
435 sprom
->pa0b0
= 0x15ae;
436 sprom
->pa0b1
= 0xfa85;
437 sprom
->pa0b2
= 0xfe8d;
438 sprom
->pa1b0
= 0xffff;
439 sprom
->pa1b1
= 0xffff;
440 sprom
->pa1b2
= 0xffff;
445 sprom
->maxpwr_bg
= 0x4c;
446 sprom
->itssi_bg
= 0x00;
447 sprom
->boardflags_lo
= 0x2848;
448 sprom
->boardflags_hi
= 0x0000;
449 priv
->devid_override
= false;
451 dev_warn(priv
->dev
, "using basic SPROM\n");
453 size_t size
= min(fw
->size
, (size_t) BCMA_FBS_MAX_SIZE
);
454 u16 tmp_sprom
[BCMA_FBS_MAX_SIZE
>> 1];
457 for (i
= 0, j
= 0; i
< size
; i
+= 2, j
++)
458 tmp_sprom
[j
] = (fw
->data
[i
] << 8) | fw
->data
[i
+ 1];
460 release_firmware(fw
);
461 bcma_fbs_fixup(priv
, tmp_sprom
);
462 sprom_extract(priv
, tmp_sprom
, size
>> 1);
464 priv
->devid_override
= sprom_override_devid(priv
, sprom
,
469 static int bcma_fbs_probe(struct platform_device
*pdev
)
471 struct device
*dev
= &pdev
->dev
;
472 struct device_node
*node
= dev
->of_node
;
473 struct bcma_fbs
*priv
;
477 priv
= devm_kzalloc(dev
, sizeof(*priv
), GFP_KERNEL
);
483 bcma_fbs_set(priv
, node
);
485 of_property_read_u32(node
, "pci-bus", &priv
->pci_bus
);
486 of_property_read_u32(node
, "pci-dev", &priv
->pci_dev
);
488 of_get_mac_address(node
, mac
);
489 if (is_valid_ether_addr(mac
)) {
490 dev_info(dev
, "mtd mac %pM\n", mac
);
492 random_ether_addr(mac
);
493 dev_info(dev
, "random mac %pM\n", mac
);
496 memcpy(priv
->sprom
.il0mac
, mac
, ETH_ALEN
);
497 memcpy(priv
->sprom
.et0mac
, mac
, ETH_ALEN
);
498 memcpy(priv
->sprom
.et1mac
, mac
, ETH_ALEN
);
499 memcpy(priv
->sprom
.et2mac
, mac
, ETH_ALEN
);
501 spin_lock_irqsave(&bcma_fbs_lock
, flags
);
502 list_add(&priv
->list
, &bcma_fbs_list
);
503 spin_unlock_irqrestore(&bcma_fbs_lock
, flags
);
505 dev_info(dev
, "registered SPROM for [%x:%x]\n",
506 priv
->pci_bus
, priv
->pci_dev
);
511 static const struct of_device_id bcma_fbs_of_match
[] = {
512 { .compatible
= "brcm,bcma-sprom", },
515 MODULE_DEVICE_TABLE(of
, bcma_fbs_of_match
);
517 static struct platform_driver bcma_fbs_driver
= {
518 .probe
= bcma_fbs_probe
,
520 .name
= "bcma-sprom",
521 .of_match_table
= bcma_fbs_of_match
,
525 int __init
bcma_fbs_register(void)
527 return platform_driver_register(&bcma_fbs_driver
);