1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | |
4 | Broadcom B43 wireless driver |
5 | |
6 | PHY workarounds. |
7 | |
8 | Copyright (c) 2005-2007 Stefano Brivio <stefano.brivio@polimi.it> |
9 | Copyright (c) 2005-2007 Michael Buesch <m@bues.ch> |
10 | |
11 | |
12 | */ |
13 | |
14 | #include "b43.h" |
15 | #include "main.h" |
16 | #include "tables.h" |
17 | #include "phy_common.h" |
18 | #include "wa.h" |
19 | |
20 | void b43_wa_initgains(struct b43_wldev *dev) |
21 | { |
22 | struct b43_phy *phy = &dev->phy; |
23 | |
24 | b43_phy_write(dev, B43_PHY_LNAHPFCTL, value: 0x1FF9); |
25 | b43_phy_mask(dev, B43_PHY_LPFGAINCTL, mask: 0xFF0F); |
26 | if (phy->rev <= 2) |
27 | b43_ofdmtab_write16(dev, B43_OFDMTAB_LPFGAIN, offset: 0, value: 0x1FBF); |
28 | b43_radio_write16(dev, reg: 0x0002, value: 0x1FBF); |
29 | |
30 | b43_phy_write(dev, reg: 0x0024, value: 0x4680); |
31 | b43_phy_write(dev, reg: 0x0020, value: 0x0003); |
32 | b43_phy_write(dev, reg: 0x001D, value: 0x0F40); |
33 | b43_phy_write(dev, reg: 0x001F, value: 0x1C00); |
34 | if (phy->rev <= 3) |
35 | b43_phy_maskset(dev, offset: 0x002A, mask: 0x00FF, set: 0x0400); |
36 | else if (phy->rev == 5) { |
37 | b43_phy_maskset(dev, offset: 0x002A, mask: 0x00FF, set: 0x1A00); |
38 | b43_phy_write(dev, reg: 0x00CC, value: 0x2121); |
39 | } |
40 | if (phy->rev >= 3) |
41 | b43_phy_write(dev, reg: 0x00BA, value: 0x3ED5); |
42 | } |
43 | |
44 | static void (struct b43_wldev *dev) /* RSSI lookup table */ |
45 | { |
46 | int i; |
47 | |
48 | if (0 /* FIXME: For APHY.rev=2 this might be needed */) { |
49 | for (i = 0; i < 8; i++) |
50 | b43_ofdmtab_write16(dev, B43_OFDMTAB_RSSI, offset: i, value: i + 8); |
51 | for (i = 8; i < 16; i++) |
52 | b43_ofdmtab_write16(dev, B43_OFDMTAB_RSSI, offset: i, value: i - 8); |
53 | } else { |
54 | for (i = 0; i < 64; i++) |
55 | b43_ofdmtab_write16(dev, B43_OFDMTAB_RSSI, offset: i, value: i); |
56 | } |
57 | } |
58 | |
59 | static void b43_wa_analog(struct b43_wldev *dev) |
60 | { |
61 | u16 ofdmrev; |
62 | |
63 | ofdmrev = b43_phy_read(dev, B43_PHY_VERSION_OFDM) & B43_PHYVER_VERSION; |
64 | if (ofdmrev > 2) { |
65 | b43_phy_write(dev, B43_PHY_PWRDOWN, value: 0x1000); |
66 | } else { |
67 | b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, offset: 3, value: 0x1044); |
68 | b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, offset: 4, value: 0x7201); |
69 | b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, offset: 6, value: 0x0040); |
70 | } |
71 | } |
72 | |
73 | static void b43_wa_fft(struct b43_wldev *dev) /* Fine frequency table */ |
74 | { |
75 | int i; |
76 | |
77 | for (i = 0; i < B43_TAB_FINEFREQG_SIZE; i++) |
78 | b43_ofdmtab_write16(dev, B43_OFDMTAB_DACRFPABB, offset: i, |
79 | value: b43_tab_finefreqg[i]); |
80 | } |
81 | |
82 | static void b43_wa_nft(struct b43_wldev *dev) /* Noise figure table */ |
83 | { |
84 | struct b43_phy *phy = &dev->phy; |
85 | int i; |
86 | |
87 | if (phy->rev == 1) |
88 | for (i = 0; i < B43_TAB_NOISEG1_SIZE; i++) |
89 | b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, offset: i, |
90 | value: b43_tab_noiseg1[i]); |
91 | else |
92 | for (i = 0; i < B43_TAB_NOISEG2_SIZE; i++) |
93 | b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, offset: i, |
94 | value: b43_tab_noiseg2[i]); |
95 | } |
96 | |
97 | static void b43_wa_rt(struct b43_wldev *dev) /* Rotor table */ |
98 | { |
99 | int i; |
100 | |
101 | for (i = 0; i < B43_TAB_ROTOR_SIZE; i++) |
102 | b43_ofdmtab_write32(dev, B43_OFDMTAB_ROTOR, offset: i, value: b43_tab_rotor[i]); |
103 | } |
104 | |
105 | static void b43_write_nst(struct b43_wldev *dev, const u16 *nst) |
106 | { |
107 | int i; |
108 | |
109 | for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++) |
110 | b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE, offset: i, value: nst[i]); |
111 | } |
112 | |
113 | static void b43_wa_nst(struct b43_wldev *dev) /* Noise scale table */ |
114 | { |
115 | struct b43_phy *phy = &dev->phy; |
116 | |
117 | if (phy->rev >= 6) { |
118 | if (b43_phy_read(dev, B43_PHY_ENCORE) & B43_PHY_ENCORE_EN) |
119 | b43_write_nst(dev, nst: b43_tab_noisescaleg3); |
120 | else |
121 | b43_write_nst(dev, nst: b43_tab_noisescaleg2); |
122 | } else { |
123 | b43_write_nst(dev, nst: b43_tab_noisescaleg1); |
124 | } |
125 | } |
126 | |
127 | static void b43_wa_art(struct b43_wldev *dev) /* ADV retard table */ |
128 | { |
129 | int i; |
130 | |
131 | for (i = 0; i < B43_TAB_RETARD_SIZE; i++) |
132 | b43_ofdmtab_write32(dev, B43_OFDMTAB_ADVRETARD, |
133 | offset: i, value: b43_tab_retard[i]); |
134 | } |
135 | |
136 | static void b43_wa_msst(struct b43_wldev *dev) /* Min sigma square table */ |
137 | { |
138 | struct b43_phy *phy = &dev->phy; |
139 | int i; |
140 | const u16 *tab; |
141 | |
142 | if (phy->type == B43_PHYTYPE_G) { |
143 | tab = b43_tab_sigmasqr2; |
144 | } else { |
145 | B43_WARN_ON(1); |
146 | return; |
147 | } |
148 | |
149 | for (i = 0; i < B43_TAB_SIGMASQR_SIZE; i++) { |
150 | b43_ofdmtab_write16(dev, B43_OFDMTAB_MINSIGSQ, |
151 | offset: i, value: tab[i]); |
152 | } |
153 | } |
154 | |
155 | static void b43_wa_crs_ed(struct b43_wldev *dev) |
156 | { |
157 | struct b43_phy *phy = &dev->phy; |
158 | |
159 | if (phy->rev == 1) { |
160 | b43_phy_write(dev, B43_PHY_CRSTHRES1_R1, value: 0x4F19); |
161 | } else if (phy->rev == 2) { |
162 | b43_phy_write(dev, B43_PHY_CRSTHRES1, value: 0x1861); |
163 | b43_phy_write(dev, B43_PHY_CRSTHRES2, value: 0x0271); |
164 | b43_phy_set(dev, B43_PHY_ANTDWELL, set: 0x0800); |
165 | } else { |
166 | b43_phy_write(dev, B43_PHY_CRSTHRES1, value: 0x0098); |
167 | b43_phy_write(dev, B43_PHY_CRSTHRES2, value: 0x0070); |
168 | b43_phy_write(dev, B43_PHY_OFDM(0xC9), value: 0x0080); |
169 | b43_phy_set(dev, B43_PHY_ANTDWELL, set: 0x0800); |
170 | } |
171 | } |
172 | |
173 | static void b43_wa_crs_thr(struct b43_wldev *dev) |
174 | { |
175 | b43_phy_maskset(dev, B43_PHY_CRS0, mask: ~0x03C0, set: 0xD000); |
176 | } |
177 | |
178 | static void b43_wa_crs_blank(struct b43_wldev *dev) |
179 | { |
180 | b43_phy_write(dev, B43_PHY_OFDM(0x2C), value: 0x005A); |
181 | } |
182 | |
183 | static void b43_wa_cck_shiftbits(struct b43_wldev *dev) |
184 | { |
185 | b43_phy_write(dev, B43_PHY_CCKSHIFTBITS, value: 0x0026); |
186 | } |
187 | |
188 | static void (struct b43_wldev *dev) |
189 | { |
190 | int i; |
191 | |
192 | if (dev->phy.rev == 1) { |
193 | for (i = 0; i < 16; i++) { |
194 | b43_ofdmtab_write16(dev, B43_OFDMTAB_WRSSI_R1, |
195 | offset: i, value: 0x0020); |
196 | } |
197 | } else { |
198 | for (i = 0; i < 32; i++) { |
199 | b43_ofdmtab_write16(dev, B43_OFDMTAB_WRSSI, |
200 | offset: i, value: 0x0820); |
201 | } |
202 | } |
203 | } |
204 | |
205 | static void b43_wa_txpuoff_rxpuon(struct b43_wldev *dev) |
206 | { |
207 | b43_ofdmtab_write16(dev, B43_OFDMTAB_UNKNOWN_0F, offset: 2, value: 15); |
208 | b43_ofdmtab_write16(dev, B43_OFDMTAB_UNKNOWN_0F, offset: 3, value: 20); |
209 | } |
210 | |
211 | static void b43_wa_altagc(struct b43_wldev *dev) |
212 | { |
213 | struct b43_phy *phy = &dev->phy; |
214 | |
215 | if (phy->rev == 1) { |
216 | b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1_R1, offset: 0, value: 254); |
217 | b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1_R1, offset: 1, value: 13); |
218 | b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1_R1, offset: 2, value: 19); |
219 | b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1_R1, offset: 3, value: 25); |
220 | b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, offset: 0, value: 0x2710); |
221 | b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, offset: 1, value: 0x9B83); |
222 | b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, offset: 2, value: 0x9B83); |
223 | b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, offset: 3, value: 0x0F8D); |
224 | b43_phy_write(dev, B43_PHY_LMS, value: 4); |
225 | } else { |
226 | b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, offset: 0, value: 254); |
227 | b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, offset: 1, value: 13); |
228 | b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, offset: 2, value: 19); |
229 | b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, offset: 3, value: 25); |
230 | } |
231 | |
232 | b43_phy_maskset(dev, B43_PHY_CCKSHIFTBITS_WA, mask: 0x00FF, set: 0x5700); |
233 | b43_phy_maskset(dev, B43_PHY_OFDM(0x1A), mask: ~0x007F, set: 0x000F); |
234 | b43_phy_maskset(dev, B43_PHY_OFDM(0x1A), mask: ~0x3F80, set: 0x2B80); |
235 | b43_phy_maskset(dev, B43_PHY_ANTWRSETT, mask: 0xF0FF, set: 0x0300); |
236 | b43_radio_set(dev, offset: 0x7A, set: 0x0008); |
237 | b43_phy_maskset(dev, B43_PHY_N1P1GAIN, mask: ~0x000F, set: 0x0008); |
238 | b43_phy_maskset(dev, B43_PHY_P1P2GAIN, mask: ~0x0F00, set: 0x0600); |
239 | b43_phy_maskset(dev, B43_PHY_N1N2GAIN, mask: ~0x0F00, set: 0x0700); |
240 | b43_phy_maskset(dev, B43_PHY_N1P1GAIN, mask: ~0x0F00, set: 0x0100); |
241 | if (phy->rev == 1) { |
242 | b43_phy_maskset(dev, B43_PHY_N1N2GAIN, mask: ~0x000F, set: 0x0007); |
243 | } |
244 | b43_phy_maskset(dev, B43_PHY_OFDM(0x88), mask: ~0x00FF, set: 0x001C); |
245 | b43_phy_maskset(dev, B43_PHY_OFDM(0x88), mask: ~0x3F00, set: 0x0200); |
246 | b43_phy_maskset(dev, B43_PHY_OFDM(0x96), mask: ~0x00FF, set: 0x001C); |
247 | b43_phy_maskset(dev, B43_PHY_OFDM(0x89), mask: ~0x00FF, set: 0x0020); |
248 | b43_phy_maskset(dev, B43_PHY_OFDM(0x89), mask: ~0x3F00, set: 0x0200); |
249 | b43_phy_maskset(dev, B43_PHY_OFDM(0x82), mask: ~0x00FF, set: 0x002E); |
250 | b43_phy_maskset(dev, B43_PHY_OFDM(0x96), mask: 0x00FF, set: 0x1A00); |
251 | b43_phy_maskset(dev, B43_PHY_OFDM(0x81), mask: ~0x00FF, set: 0x0028); |
252 | b43_phy_maskset(dev, B43_PHY_OFDM(0x81), mask: 0x00FF, set: 0x2C00); |
253 | if (phy->rev == 1) { |
254 | b43_phy_write(dev, B43_PHY_PEAK_COUNT, value: 0x092B); |
255 | b43_phy_maskset(dev, B43_PHY_OFDM(0x1B), mask: ~0x001E, set: 0x0002); |
256 | } else { |
257 | b43_phy_mask(dev, B43_PHY_OFDM(0x1B), mask: ~0x001E); |
258 | b43_phy_write(dev, B43_PHY_OFDM(0x1F), value: 0x287A); |
259 | b43_phy_maskset(dev, B43_PHY_LPFGAINCTL, mask: ~0x000F, set: 0x0004); |
260 | if (phy->rev >= 6) { |
261 | b43_phy_write(dev, B43_PHY_OFDM(0x22), value: 0x287A); |
262 | b43_phy_maskset(dev, B43_PHY_LPFGAINCTL, mask: 0x0FFF, set: 0x3000); |
263 | } |
264 | } |
265 | b43_phy_maskset(dev, B43_PHY_DIVSRCHIDX, mask: 0x8080, set: 0x7874); |
266 | b43_phy_write(dev, B43_PHY_OFDM(0x8E), value: 0x1C00); |
267 | if (phy->rev == 1) { |
268 | b43_phy_maskset(dev, B43_PHY_DIVP1P2GAIN, mask: ~0x0F00, set: 0x0600); |
269 | b43_phy_write(dev, B43_PHY_OFDM(0x8B), value: 0x005E); |
270 | b43_phy_maskset(dev, B43_PHY_ANTWRSETT, mask: ~0x00FF, set: 0x001E); |
271 | b43_phy_write(dev, B43_PHY_OFDM(0x8D), value: 0x0002); |
272 | b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3_R1, offset: 0, value: 0); |
273 | b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3_R1, offset: 1, value: 7); |
274 | b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3_R1, offset: 2, value: 16); |
275 | b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3_R1, offset: 3, value: 28); |
276 | } else { |
277 | b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3, offset: 0, value: 0); |
278 | b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3, offset: 1, value: 7); |
279 | b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3, offset: 2, value: 16); |
280 | b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3, offset: 3, value: 28); |
281 | } |
282 | if (phy->rev >= 6) { |
283 | b43_phy_mask(dev, B43_PHY_OFDM(0x26), mask: ~0x0003); |
284 | b43_phy_mask(dev, B43_PHY_OFDM(0x26), mask: ~0x1000); |
285 | } |
286 | b43_phy_read(dev, B43_PHY_VERSION_OFDM); /* Dummy read */ |
287 | } |
288 | |
289 | static void b43_wa_tr_ltov(struct b43_wldev *dev) /* TR Lookup Table Original Values */ |
290 | { |
291 | b43_gtab_write(dev, B43_GTAB_ORIGTR, offset: 0, value: 0x7654); |
292 | } |
293 | |
294 | static void b43_wa_cpll_nonpilot(struct b43_wldev *dev) |
295 | { |
296 | b43_ofdmtab_write16(dev, B43_OFDMTAB_UNKNOWN_11, offset: 0, value: 0); |
297 | b43_ofdmtab_write16(dev, B43_OFDMTAB_UNKNOWN_11, offset: 1, value: 0); |
298 | } |
299 | |
300 | static void b43_wa_boards_g(struct b43_wldev *dev) |
301 | { |
302 | struct ssb_sprom *sprom = dev->dev->bus_sprom; |
303 | struct b43_phy *phy = &dev->phy; |
304 | |
305 | if (dev->dev->board_vendor != SSB_BOARDVENDOR_BCM || |
306 | dev->dev->board_type != SSB_BOARD_BU4306 || |
307 | dev->dev->board_rev != 0x17) { |
308 | if (phy->rev < 2) { |
309 | b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX_R1, offset: 1, value: 0x0002); |
310 | b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX_R1, offset: 2, value: 0x0001); |
311 | } else { |
312 | b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, offset: 1, value: 0x0002); |
313 | b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, offset: 2, value: 0x0001); |
314 | if ((sprom->boardflags_lo & B43_BFL_EXTLNA) && |
315 | (phy->rev >= 7)) { |
316 | b43_phy_mask(dev, B43_PHY_EXTG(0x11), mask: 0xF7FF); |
317 | b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, offset: 0x0020, value: 0x0001); |
318 | b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, offset: 0x0021, value: 0x0001); |
319 | b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, offset: 0x0022, value: 0x0001); |
320 | b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, offset: 0x0023, value: 0x0000); |
321 | b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, offset: 0x0000, value: 0x0000); |
322 | b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, offset: 0x0003, value: 0x0002); |
323 | } |
324 | } |
325 | } |
326 | if (sprom->boardflags_lo & B43_BFL_FEM) { |
327 | b43_phy_write(dev, B43_PHY_GTABCTL, value: 0x3120); |
328 | b43_phy_write(dev, B43_PHY_GTABDATA, value: 0xC480); |
329 | } |
330 | } |
331 | |
332 | void b43_wa_all(struct b43_wldev *dev) |
333 | { |
334 | struct b43_phy *phy = &dev->phy; |
335 | |
336 | if (phy->type == B43_PHYTYPE_G) { |
337 | switch (phy->rev) { |
338 | case 1://XXX review rev1 |
339 | b43_wa_crs_ed(dev); |
340 | b43_wa_crs_thr(dev); |
341 | b43_wa_crs_blank(dev); |
342 | b43_wa_cck_shiftbits(dev); |
343 | b43_wa_fft(dev); |
344 | b43_wa_nft(dev); |
345 | b43_wa_rt(dev); |
346 | b43_wa_nst(dev); |
347 | b43_wa_art(dev); |
348 | b43_wa_wrssi_offset(dev); |
349 | b43_wa_altagc(dev); |
350 | break; |
351 | case 2: |
352 | case 6: |
353 | case 7: |
354 | case 8: |
355 | case 9: |
356 | b43_wa_tr_ltov(dev); |
357 | b43_wa_crs_ed(dev); |
358 | b43_wa_rssi_lt(dev); |
359 | b43_wa_nft(dev); |
360 | b43_wa_nst(dev); |
361 | b43_wa_msst(dev); |
362 | b43_wa_wrssi_offset(dev); |
363 | b43_wa_altagc(dev); |
364 | b43_wa_analog(dev); |
365 | b43_wa_txpuoff_rxpuon(dev); |
366 | break; |
367 | default: |
368 | B43_WARN_ON(1); |
369 | } |
370 | b43_wa_boards_g(dev); |
371 | } else { /* No N PHY support so far, LP PHY is in phy_lp.c */ |
372 | B43_WARN_ON(1); |
373 | } |
374 | |
375 | b43_wa_cpll_nonpilot(dev); |
376 | } |
377 | |