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
)
61 if (bus
->hosttype
!= BCMA_HOSTTYPE_PCI
)
64 pci_bus
= bus
->host_pci
->bus
->number
;
65 pci_dev
= PCI_SLOT(bus
->host_pci
->devfn
);
67 list_for_each_entry(pos
, &bcma_fbs_list
, list
) {
68 if (pos
->pci_bus
!= pci_bus
||
69 pos
->pci_dev
!= pci_dev
)
72 if (pos
->devid_override
)
73 bus
->host_pci
->device
= pos
->sprom
.dev_id
;
75 memcpy(out
, &pos
->sprom
, sizeof(struct ssb_sprom
));
76 dev_info(pos
->dev
, "requested by [%x:%x]",
77 pos
->pci_bus
, pos
->pci_dev
);
82 pr_err("unable to fill SPROM for [%x:%x]\n", pci_bus
, pci_dev
);
87 static s8
sprom_extract_antgain(const u16
*in
, u16 offset
, u16 mask
, u16 shift
)
92 v
= in
[SPOFF(offset
)];
93 gain
= (v
& mask
) >> shift
;
95 gain
= 8; /* If unset use 2dBm */
97 /* Q5.2 Fractional part is stored in 0xC0 */
98 gain
= ((gain
& 0xC0) >> 6) | ((gain
& 0x3F) << 2);
104 static void sprom_extract_r8(struct ssb_sprom
*out
, const u16
*in
)
106 static const u16 pwr_info_offset
[] = {
107 SSB_SROM8_PWR_INFO_CORE0
, SSB_SROM8_PWR_INFO_CORE1
,
108 SSB_SROM8_PWR_INFO_CORE2
, SSB_SROM8_PWR_INFO_CORE3
113 BUILD_BUG_ON(ARRAY_SIZE(pwr_info_offset
) !=
114 ARRAY_SIZE(out
->core_pwr_info
));
116 SPEX(board_rev
, SSB_SPROM8_BOARDREV
, ~0, 0);
117 SPEX(board_type
, SSB_SPROM1_SPID
, ~0, 0);
119 SPEX(txpid2g
[0], SSB_SPROM4_TXPID2G01
, SSB_SPROM4_TXPID2G0
,
120 SSB_SPROM4_TXPID2G0_SHIFT
);
121 SPEX(txpid2g
[1], SSB_SPROM4_TXPID2G01
, SSB_SPROM4_TXPID2G1
,
122 SSB_SPROM4_TXPID2G1_SHIFT
);
123 SPEX(txpid2g
[2], SSB_SPROM4_TXPID2G23
, SSB_SPROM4_TXPID2G2
,
124 SSB_SPROM4_TXPID2G2_SHIFT
);
125 SPEX(txpid2g
[3], SSB_SPROM4_TXPID2G23
, SSB_SPROM4_TXPID2G3
,
126 SSB_SPROM4_TXPID2G3_SHIFT
);
128 SPEX(txpid5gl
[0], SSB_SPROM4_TXPID5GL01
, SSB_SPROM4_TXPID5GL0
,
129 SSB_SPROM4_TXPID5GL0_SHIFT
);
130 SPEX(txpid5gl
[1], SSB_SPROM4_TXPID5GL01
, SSB_SPROM4_TXPID5GL1
,
131 SSB_SPROM4_TXPID5GL1_SHIFT
);
132 SPEX(txpid5gl
[2], SSB_SPROM4_TXPID5GL23
, SSB_SPROM4_TXPID5GL2
,
133 SSB_SPROM4_TXPID5GL2_SHIFT
);
134 SPEX(txpid5gl
[3], SSB_SPROM4_TXPID5GL23
, SSB_SPROM4_TXPID5GL3
,
135 SSB_SPROM4_TXPID5GL3_SHIFT
);
137 SPEX(txpid5g
[0], SSB_SPROM4_TXPID5G01
, SSB_SPROM4_TXPID5G0
,
138 SSB_SPROM4_TXPID5G0_SHIFT
);
139 SPEX(txpid5g
[1], SSB_SPROM4_TXPID5G01
, SSB_SPROM4_TXPID5G1
,
140 SSB_SPROM4_TXPID5G1_SHIFT
);
141 SPEX(txpid5g
[2], SSB_SPROM4_TXPID5G23
, SSB_SPROM4_TXPID5G2
,
142 SSB_SPROM4_TXPID5G2_SHIFT
);
143 SPEX(txpid5g
[3], SSB_SPROM4_TXPID5G23
, SSB_SPROM4_TXPID5G3
,
144 SSB_SPROM4_TXPID5G3_SHIFT
);
146 SPEX(txpid5gh
[0], SSB_SPROM4_TXPID5GH01
, SSB_SPROM4_TXPID5GH0
,
147 SSB_SPROM4_TXPID5GH0_SHIFT
);
148 SPEX(txpid5gh
[1], SSB_SPROM4_TXPID5GH01
, SSB_SPROM4_TXPID5GH1
,
149 SSB_SPROM4_TXPID5GH1_SHIFT
);
150 SPEX(txpid5gh
[2], SSB_SPROM4_TXPID5GH23
, SSB_SPROM4_TXPID5GH2
,
151 SSB_SPROM4_TXPID5GH2_SHIFT
);
152 SPEX(txpid5gh
[3], SSB_SPROM4_TXPID5GH23
, SSB_SPROM4_TXPID5GH3
,
153 SSB_SPROM4_TXPID5GH3_SHIFT
);
155 SPEX(boardflags_lo
, SSB_SPROM8_BFLLO
, ~0, 0);
156 SPEX(boardflags_hi
, SSB_SPROM8_BFLHI
, ~0, 0);
157 SPEX(boardflags2_lo
, SSB_SPROM8_BFL2LO
, ~0, 0);
158 SPEX(boardflags2_hi
, SSB_SPROM8_BFL2HI
, ~0, 0);
160 SPEX(alpha2
[0], SSB_SPROM8_CCODE
, 0xff00, 8);
161 SPEX(alpha2
[1], SSB_SPROM8_CCODE
, 0x00ff, 0);
163 /* Extract core's power info */
164 for (i
= 0; i
< ARRAY_SIZE(pwr_info_offset
); i
++) {
165 o
= pwr_info_offset
[i
];
166 SPEX(core_pwr_info
[i
].itssi_2g
, o
+ SSB_SROM8_2G_MAXP_ITSSI
,
167 SSB_SPROM8_2G_ITSSI
, SSB_SPROM8_2G_ITSSI_SHIFT
);
168 SPEX(core_pwr_info
[i
].maxpwr_2g
, o
+ SSB_SROM8_2G_MAXP_ITSSI
,
169 SSB_SPROM8_2G_MAXP
, 0);
171 SPEX(core_pwr_info
[i
].pa_2g
[0], o
+ SSB_SROM8_2G_PA_0
, ~0, 0);
172 SPEX(core_pwr_info
[i
].pa_2g
[1], o
+ SSB_SROM8_2G_PA_1
, ~0, 0);
173 SPEX(core_pwr_info
[i
].pa_2g
[2], o
+ SSB_SROM8_2G_PA_2
, ~0, 0);
175 SPEX(core_pwr_info
[i
].itssi_5g
, o
+ SSB_SROM8_5G_MAXP_ITSSI
,
176 SSB_SPROM8_5G_ITSSI
, SSB_SPROM8_5G_ITSSI_SHIFT
);
177 SPEX(core_pwr_info
[i
].maxpwr_5g
, o
+ SSB_SROM8_5G_MAXP_ITSSI
,
178 SSB_SPROM8_5G_MAXP
, 0);
179 SPEX(core_pwr_info
[i
].maxpwr_5gh
, o
+ SSB_SPROM8_5GHL_MAXP
,
180 SSB_SPROM8_5GH_MAXP
, 0);
181 SPEX(core_pwr_info
[i
].maxpwr_5gl
, o
+ SSB_SPROM8_5GHL_MAXP
,
182 SSB_SPROM8_5GL_MAXP
, SSB_SPROM8_5GL_MAXP_SHIFT
);
184 SPEX(core_pwr_info
[i
].pa_5gl
[0], o
+ SSB_SROM8_5GL_PA_0
, ~0, 0);
185 SPEX(core_pwr_info
[i
].pa_5gl
[1], o
+ SSB_SROM8_5GL_PA_1
, ~0, 0);
186 SPEX(core_pwr_info
[i
].pa_5gl
[2], o
+ SSB_SROM8_5GL_PA_2
, ~0, 0);
187 SPEX(core_pwr_info
[i
].pa_5g
[0], o
+ SSB_SROM8_5G_PA_0
, ~0, 0);
188 SPEX(core_pwr_info
[i
].pa_5g
[1], o
+ SSB_SROM8_5G_PA_1
, ~0, 0);
189 SPEX(core_pwr_info
[i
].pa_5g
[2], o
+ SSB_SROM8_5G_PA_2
, ~0, 0);
190 SPEX(core_pwr_info
[i
].pa_5gh
[0], o
+ SSB_SROM8_5GH_PA_0
, ~0, 0);
191 SPEX(core_pwr_info
[i
].pa_5gh
[1], o
+ SSB_SROM8_5GH_PA_1
, ~0, 0);
192 SPEX(core_pwr_info
[i
].pa_5gh
[2], o
+ SSB_SROM8_5GH_PA_2
, ~0, 0);
195 SPEX(fem
.ghz2
.tssipos
, SSB_SPROM8_FEM2G
, SSB_SROM8_FEM_TSSIPOS
,
196 SSB_SROM8_FEM_TSSIPOS_SHIFT
);
197 SPEX(fem
.ghz2
.extpa_gain
, SSB_SPROM8_FEM2G
, SSB_SROM8_FEM_EXTPA_GAIN
,
198 SSB_SROM8_FEM_EXTPA_GAIN_SHIFT
);
199 SPEX(fem
.ghz2
.pdet_range
, SSB_SPROM8_FEM2G
, SSB_SROM8_FEM_PDET_RANGE
,
200 SSB_SROM8_FEM_PDET_RANGE_SHIFT
);
201 SPEX(fem
.ghz2
.tr_iso
, SSB_SPROM8_FEM2G
, SSB_SROM8_FEM_TR_ISO
,
202 SSB_SROM8_FEM_TR_ISO_SHIFT
);
203 SPEX(fem
.ghz2
.antswlut
, SSB_SPROM8_FEM2G
, SSB_SROM8_FEM_ANTSWLUT
,
204 SSB_SROM8_FEM_ANTSWLUT_SHIFT
);
206 SPEX(fem
.ghz5
.tssipos
, SSB_SPROM8_FEM5G
, SSB_SROM8_FEM_TSSIPOS
,
207 SSB_SROM8_FEM_TSSIPOS_SHIFT
);
208 SPEX(fem
.ghz5
.extpa_gain
, SSB_SPROM8_FEM5G
, SSB_SROM8_FEM_EXTPA_GAIN
,
209 SSB_SROM8_FEM_EXTPA_GAIN_SHIFT
);
210 SPEX(fem
.ghz5
.pdet_range
, SSB_SPROM8_FEM5G
, SSB_SROM8_FEM_PDET_RANGE
,
211 SSB_SROM8_FEM_PDET_RANGE_SHIFT
);
212 SPEX(fem
.ghz5
.tr_iso
, SSB_SPROM8_FEM5G
, SSB_SROM8_FEM_TR_ISO
,
213 SSB_SROM8_FEM_TR_ISO_SHIFT
);
214 SPEX(fem
.ghz5
.antswlut
, SSB_SPROM8_FEM5G
, SSB_SROM8_FEM_ANTSWLUT
,
215 SSB_SROM8_FEM_ANTSWLUT_SHIFT
);
217 SPEX(ant_available_a
, SSB_SPROM8_ANTAVAIL
, SSB_SPROM8_ANTAVAIL_A
,
218 SSB_SPROM8_ANTAVAIL_A_SHIFT
);
219 SPEX(ant_available_bg
, SSB_SPROM8_ANTAVAIL
, SSB_SPROM8_ANTAVAIL_BG
,
220 SSB_SPROM8_ANTAVAIL_BG_SHIFT
);
221 SPEX(maxpwr_bg
, SSB_SPROM8_MAXP_BG
, SSB_SPROM8_MAXP_BG_MASK
, 0);
222 SPEX(itssi_bg
, SSB_SPROM8_MAXP_BG
, SSB_SPROM8_ITSSI_BG
,
223 SSB_SPROM8_ITSSI_BG_SHIFT
);
224 SPEX(maxpwr_a
, SSB_SPROM8_MAXP_A
, SSB_SPROM8_MAXP_A_MASK
, 0);
225 SPEX(itssi_a
, SSB_SPROM8_MAXP_A
, SSB_SPROM8_ITSSI_A
,
226 SSB_SPROM8_ITSSI_A_SHIFT
);
227 SPEX(maxpwr_ah
, SSB_SPROM8_MAXP_AHL
, SSB_SPROM8_MAXP_AH_MASK
, 0);
228 SPEX(maxpwr_al
, SSB_SPROM8_MAXP_AHL
, SSB_SPROM8_MAXP_AL_MASK
,
229 SSB_SPROM8_MAXP_AL_SHIFT
);
230 SPEX(gpio0
, SSB_SPROM8_GPIOA
, SSB_SPROM8_GPIOA_P0
, 0);
231 SPEX(gpio1
, SSB_SPROM8_GPIOA
, SSB_SPROM8_GPIOA_P1
,
232 SSB_SPROM8_GPIOA_P1_SHIFT
);
233 SPEX(gpio2
, SSB_SPROM8_GPIOB
, SSB_SPROM8_GPIOB_P2
, 0);
234 SPEX(gpio3
, SSB_SPROM8_GPIOB
, SSB_SPROM8_GPIOB_P3
,
235 SSB_SPROM8_GPIOB_P3_SHIFT
);
236 SPEX(tri2g
, SSB_SPROM8_TRI25G
, SSB_SPROM8_TRI2G
, 0);
237 SPEX(tri5g
, SSB_SPROM8_TRI25G
, SSB_SPROM8_TRI5G
,
238 SSB_SPROM8_TRI5G_SHIFT
);
239 SPEX(tri5gl
, SSB_SPROM8_TRI5GHL
, SSB_SPROM8_TRI5GL
, 0);
240 SPEX(tri5gh
, SSB_SPROM8_TRI5GHL
, SSB_SPROM8_TRI5GH
,
241 SSB_SPROM8_TRI5GH_SHIFT
);
242 SPEX(rxpo2g
, SSB_SPROM8_RXPO
, SSB_SPROM8_RXPO2G
,
243 SSB_SPROM8_RXPO2G_SHIFT
);
244 SPEX(rxpo5g
, SSB_SPROM8_RXPO
, SSB_SPROM8_RXPO5G
,
245 SSB_SPROM8_RXPO5G_SHIFT
);
246 SPEX(rssismf2g
, SSB_SPROM8_RSSIPARM2G
, SSB_SPROM8_RSSISMF2G
, 0);
247 SPEX(rssismc2g
, SSB_SPROM8_RSSIPARM2G
, SSB_SPROM8_RSSISMC2G
,
248 SSB_SPROM8_RSSISMC2G_SHIFT
);
249 SPEX(rssisav2g
, SSB_SPROM8_RSSIPARM2G
, SSB_SPROM8_RSSISAV2G
,
250 SSB_SPROM8_RSSISAV2G_SHIFT
);
251 SPEX(bxa2g
, SSB_SPROM8_RSSIPARM2G
, SSB_SPROM8_BXA2G
,
252 SSB_SPROM8_BXA2G_SHIFT
);
253 SPEX(rssismf5g
, SSB_SPROM8_RSSIPARM5G
, SSB_SPROM8_RSSISMF5G
, 0);
254 SPEX(rssismc5g
, SSB_SPROM8_RSSIPARM5G
, SSB_SPROM8_RSSISMC5G
,
255 SSB_SPROM8_RSSISMC5G_SHIFT
);
256 SPEX(rssisav5g
, SSB_SPROM8_RSSIPARM5G
, SSB_SPROM8_RSSISAV5G
,
257 SSB_SPROM8_RSSISAV5G_SHIFT
);
258 SPEX(bxa5g
, SSB_SPROM8_RSSIPARM5G
, SSB_SPROM8_BXA5G
,
259 SSB_SPROM8_BXA5G_SHIFT
);
261 SPEX(pa0b0
, SSB_SPROM8_PA0B0
, ~0, 0);
262 SPEX(pa0b1
, SSB_SPROM8_PA0B1
, ~0, 0);
263 SPEX(pa0b2
, SSB_SPROM8_PA0B2
, ~0, 0);
264 SPEX(pa1b0
, SSB_SPROM8_PA1B0
, ~0, 0);
265 SPEX(pa1b1
, SSB_SPROM8_PA1B1
, ~0, 0);
266 SPEX(pa1b2
, SSB_SPROM8_PA1B2
, ~0, 0);
267 SPEX(pa1lob0
, SSB_SPROM8_PA1LOB0
, ~0, 0);
268 SPEX(pa1lob1
, SSB_SPROM8_PA1LOB1
, ~0, 0);
269 SPEX(pa1lob2
, SSB_SPROM8_PA1LOB2
, ~0, 0);
270 SPEX(pa1hib0
, SSB_SPROM8_PA1HIB0
, ~0, 0);
271 SPEX(pa1hib1
, SSB_SPROM8_PA1HIB1
, ~0, 0);
272 SPEX(pa1hib2
, SSB_SPROM8_PA1HIB2
, ~0, 0);
273 SPEX(cck2gpo
, SSB_SPROM8_CCK2GPO
, ~0, 0);
274 SPEX32(ofdm2gpo
, SSB_SPROM8_OFDM2GPO
, ~0, 0);
275 SPEX32(ofdm5glpo
, SSB_SPROM8_OFDM5GLPO
, ~0, 0);
276 SPEX32(ofdm5gpo
, SSB_SPROM8_OFDM5GPO
, ~0, 0);
277 SPEX32(ofdm5ghpo
, SSB_SPROM8_OFDM5GHPO
, ~0, 0);
279 /* Extract the antenna gain values. */
280 out
->antenna_gain
.a0
= sprom_extract_antgain(in
,
283 SSB_SPROM8_AGAIN0_SHIFT
);
284 out
->antenna_gain
.a1
= sprom_extract_antgain(in
,
287 SSB_SPROM8_AGAIN1_SHIFT
);
288 out
->antenna_gain
.a2
= sprom_extract_antgain(in
,
291 SSB_SPROM8_AGAIN2_SHIFT
);
292 out
->antenna_gain
.a3
= sprom_extract_antgain(in
,
295 SSB_SPROM8_AGAIN3_SHIFT
);
297 SPEX(leddc_on_time
, SSB_SPROM8_LEDDC
, SSB_SPROM8_LEDDC_ON
,
298 SSB_SPROM8_LEDDC_ON_SHIFT
);
299 SPEX(leddc_off_time
, SSB_SPROM8_LEDDC
, SSB_SPROM8_LEDDC_OFF
,
300 SSB_SPROM8_LEDDC_OFF_SHIFT
);
302 SPEX(txchain
, SSB_SPROM8_TXRXC
, SSB_SPROM8_TXRXC_TXCHAIN
,
303 SSB_SPROM8_TXRXC_TXCHAIN_SHIFT
);
304 SPEX(rxchain
, SSB_SPROM8_TXRXC
, SSB_SPROM8_TXRXC_RXCHAIN
,
305 SSB_SPROM8_TXRXC_RXCHAIN_SHIFT
);
306 SPEX(antswitch
, SSB_SPROM8_TXRXC
, SSB_SPROM8_TXRXC_SWITCH
,
307 SSB_SPROM8_TXRXC_SWITCH_SHIFT
);
309 SPEX(opo
, SSB_SPROM8_OFDM2GPO
, 0x00ff, 0);
311 SPEX_ARRAY8(mcs2gpo
, SSB_SPROM8_2G_MCSPO
, ~0, 0);
312 SPEX_ARRAY8(mcs5gpo
, SSB_SPROM8_5G_MCSPO
, ~0, 0);
313 SPEX_ARRAY8(mcs5glpo
, SSB_SPROM8_5GL_MCSPO
, ~0, 0);
314 SPEX_ARRAY8(mcs5ghpo
, SSB_SPROM8_5GH_MCSPO
, ~0, 0);
316 SPEX(rawtempsense
, SSB_SPROM8_RAWTS
, SSB_SPROM8_RAWTS_RAWTEMP
,
317 SSB_SPROM8_RAWTS_RAWTEMP_SHIFT
);
318 SPEX(measpower
, SSB_SPROM8_RAWTS
, SSB_SPROM8_RAWTS_MEASPOWER
,
319 SSB_SPROM8_RAWTS_MEASPOWER_SHIFT
);
320 SPEX(tempsense_slope
, SSB_SPROM8_OPT_CORRX
,
321 SSB_SPROM8_OPT_CORRX_TEMP_SLOPE
,
322 SSB_SPROM8_OPT_CORRX_TEMP_SLOPE_SHIFT
);
323 SPEX(tempcorrx
, SSB_SPROM8_OPT_CORRX
, SSB_SPROM8_OPT_CORRX_TEMPCORRX
,
324 SSB_SPROM8_OPT_CORRX_TEMPCORRX_SHIFT
);
325 SPEX(tempsense_option
, SSB_SPROM8_OPT_CORRX
,
326 SSB_SPROM8_OPT_CORRX_TEMP_OPTION
,
327 SSB_SPROM8_OPT_CORRX_TEMP_OPTION_SHIFT
);
328 SPEX(freqoffset_corr
, SSB_SPROM8_HWIQ_IQSWP
,
329 SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR
,
330 SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR_SHIFT
);
331 SPEX(iqcal_swp_dis
, SSB_SPROM8_HWIQ_IQSWP
,
332 SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP
,
333 SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP_SHIFT
);
334 SPEX(hw_iqcal_en
, SSB_SPROM8_HWIQ_IQSWP
, SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL
,
335 SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL_SHIFT
);
337 SPEX(bw40po
, SSB_SPROM8_BW40PO
, ~0, 0);
338 SPEX(cddpo
, SSB_SPROM8_CDDPO
, ~0, 0);
339 SPEX(stbcpo
, SSB_SPROM8_STBCPO
, ~0, 0);
340 SPEX(bwduppo
, SSB_SPROM8_BWDUPPO
, ~0, 0);
342 SPEX(tempthresh
, SSB_SPROM8_THERMAL
, SSB_SPROM8_THERMAL_TRESH
,
343 SSB_SPROM8_THERMAL_TRESH_SHIFT
);
344 SPEX(tempoffset
, SSB_SPROM8_THERMAL
, SSB_SPROM8_THERMAL_OFFSET
,
345 SSB_SPROM8_THERMAL_OFFSET_SHIFT
);
346 SPEX(phycal_tempdelta
, SSB_SPROM8_TEMPDELTA
,
347 SSB_SPROM8_TEMPDELTA_PHYCAL
,
348 SSB_SPROM8_TEMPDELTA_PHYCAL_SHIFT
);
349 SPEX(temps_period
, SSB_SPROM8_TEMPDELTA
, SSB_SPROM8_TEMPDELTA_PERIOD
,
350 SSB_SPROM8_TEMPDELTA_PERIOD_SHIFT
);
351 SPEX(temps_hysteresis
, SSB_SPROM8_TEMPDELTA
,
352 SSB_SPROM8_TEMPDELTA_HYSTERESIS
,
353 SSB_SPROM8_TEMPDELTA_HYSTERESIS_SHIFT
);
356 static int sprom_extract(struct bcma_fbs
*priv
, const u16
*in
, u16 size
)
358 struct ssb_sprom
*out
= &priv
->sprom
;
360 memset(out
, 0, sizeof(*out
));
362 out
->revision
= in
[size
- 1] & 0x00FF;
363 if (out
->revision
< 8 || out
->revision
> 11) {
365 "Unsupported SPROM revision %d detected."
366 " Will extract v8\n",
371 sprom_extract_r8(out
, in
);
376 static void bcma_fbs_fixup(struct bcma_fbs
*priv
, u16
*sprom
)
378 struct device_node
*node
= priv
->dev
->of_node
;
379 u32 fixups
, off
, val
;
382 if (!of_get_property(node
, "brcm,sprom-fixups", &fixups
))
385 fixups
/= sizeof(u32
);
387 dev_info(priv
->dev
, "patching SPROM with %u fixups...\n", fixups
>> 1);
390 if (of_property_read_u32_index(node
, "brcm,sprom-fixups",
392 dev_err(priv
->dev
, "error reading fixup[%u] offset\n",
397 if (of_property_read_u32_index(node
, "brcm,sprom-fixups",
399 dev_err(priv
->dev
, "error reading fixup[%u] value\n",
404 dev_dbg(priv
->dev
, "fixup[%d]=0x%04x\n", off
, val
);
410 static bool sprom_override_devid(struct bcma_fbs
*priv
, struct ssb_sprom
*out
,
413 SPEX(dev_id
, 0x0060, 0xFFFF, 0);
414 return !!out
->dev_id
;
417 static void bcma_fbs_set(struct bcma_fbs
*priv
, struct device_node
*node
)
419 struct ssb_sprom
*sprom
= &priv
->sprom
;
420 const struct firmware
*fw
;
421 const char *sprom_name
;
424 if (of_property_read_string(node
, "brcm,sprom", &sprom_name
))
428 err
= request_firmware_direct(&fw
, sprom_name
, priv
->dev
);
430 dev_err(priv
->dev
, "%s load error\n", sprom_name
);
436 sprom
->revision
= 0x02;
437 sprom
->board_rev
= 0x0017;
438 sprom
->country_code
= 0x00;
439 sprom
->ant_available_bg
= 0x03;
440 sprom
->pa0b0
= 0x15ae;
441 sprom
->pa0b1
= 0xfa85;
442 sprom
->pa0b2
= 0xfe8d;
443 sprom
->pa1b0
= 0xffff;
444 sprom
->pa1b1
= 0xffff;
445 sprom
->pa1b2
= 0xffff;
450 sprom
->maxpwr_bg
= 0x4c;
451 sprom
->itssi_bg
= 0x00;
452 sprom
->boardflags_lo
= 0x2848;
453 sprom
->boardflags_hi
= 0x0000;
454 priv
->devid_override
= false;
456 dev_warn(priv
->dev
, "using basic SPROM\n");
458 size_t size
= min(fw
->size
, (size_t) BCMA_FBS_MAX_SIZE
);
459 u16 tmp_sprom
[BCMA_FBS_MAX_SIZE
>> 1];
462 for (i
= 0, j
= 0; i
< size
; i
+= 2, j
++)
463 tmp_sprom
[j
] = (fw
->data
[i
] << 8) | fw
->data
[i
+ 1];
465 release_firmware(fw
);
466 bcma_fbs_fixup(priv
, tmp_sprom
);
467 sprom_extract(priv
, tmp_sprom
, size
>> 1);
469 priv
->devid_override
= sprom_override_devid(priv
, sprom
,
474 static int bcma_fbs_probe(struct platform_device
*pdev
)
476 struct device
*dev
= &pdev
->dev
;
477 struct device_node
*node
= dev
->of_node
;
478 struct bcma_fbs
*priv
;
482 priv
= devm_kzalloc(dev
, sizeof(*priv
), GFP_KERNEL
);
488 bcma_fbs_set(priv
, node
);
490 of_property_read_u32(node
, "pci-bus", &priv
->pci_bus
);
491 of_property_read_u32(node
, "pci-dev", &priv
->pci_dev
);
493 of_get_mac_address(node
, mac
);
494 if (is_valid_ether_addr(mac
)) {
495 dev_info(dev
, "mtd mac %pM\n", mac
);
497 eth_random_addr(mac
);
498 dev_info(dev
, "random mac %pM\n", mac
);
501 memcpy(priv
->sprom
.il0mac
, mac
, ETH_ALEN
);
502 memcpy(priv
->sprom
.et0mac
, mac
, ETH_ALEN
);
503 memcpy(priv
->sprom
.et1mac
, mac
, ETH_ALEN
);
504 memcpy(priv
->sprom
.et2mac
, mac
, ETH_ALEN
);
506 spin_lock_irqsave(&bcma_fbs_lock
, flags
);
507 list_add(&priv
->list
, &bcma_fbs_list
);
508 spin_unlock_irqrestore(&bcma_fbs_lock
, flags
);
510 dev_info(dev
, "registered SPROM for [%x:%x]\n",
511 priv
->pci_bus
, priv
->pci_dev
);
516 static const struct of_device_id bcma_fbs_of_match
[] = {
517 { .compatible
= "brcm,bcma-sprom", },
520 MODULE_DEVICE_TABLE(of
, bcma_fbs_of_match
);
522 static struct platform_driver bcma_fbs_driver
= {
523 .probe
= bcma_fbs_probe
,
525 .name
= "bcma-sprom",
526 .of_match_table
= bcma_fbs_of_match
,
530 int __init
bcma_fbs_register(void)
532 return platform_driver_register(&bcma_fbs_driver
);