diff options
Diffstat (limited to 'drivers/net/wireless/b43legacy/phy.c')
-rw-r--r-- | drivers/net/wireless/b43legacy/phy.c | 2265 |
1 files changed, 2265 insertions, 0 deletions
diff --git a/drivers/net/wireless/b43legacy/phy.c b/drivers/net/wireless/b43legacy/phy.c new file mode 100644 index 00000000000..f9edbd5f300 --- /dev/null +++ b/drivers/net/wireless/b43legacy/phy.c | |||
@@ -0,0 +1,2265 @@ | |||
1 | /* | ||
2 | |||
3 | Broadcom B43legacy wireless driver | ||
4 | |||
5 | Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, | ||
6 | Stefano Brivio <st3@riseup.net> | ||
7 | Michael Buesch <mbuesch@freenet.de> | ||
8 | Danny van Dyk <kugelfang@gentoo.org> | ||
9 | Andreas Jaggi <andreas.jaggi@waterwave.ch> | ||
10 | Copyright (c) 2007 Larry Finger <Larry.Finger@lwfinger.net> | ||
11 | |||
12 | Some parts of the code in this file are derived from the ipw2200 | ||
13 | driver Copyright(c) 2003 - 2004 Intel Corporation. | ||
14 | |||
15 | This program is free software; you can redistribute it and/or modify | ||
16 | it under the terms of the GNU General Public License as published by | ||
17 | the Free Software Foundation; either version 2 of the License, or | ||
18 | (at your option) any later version. | ||
19 | |||
20 | This program is distributed in the hope that it will be useful, | ||
21 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
22 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
23 | GNU General Public License for more details. | ||
24 | |||
25 | You should have received a copy of the GNU General Public License | ||
26 | along with this program; see the file COPYING. If not, write to | ||
27 | the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, | ||
28 | Boston, MA 02110-1301, USA. | ||
29 | |||
30 | */ | ||
31 | |||
32 | #include <linux/delay.h> | ||
33 | #include <linux/pci.h> | ||
34 | #include <linux/types.h> | ||
35 | |||
36 | #include "b43legacy.h" | ||
37 | #include "phy.h" | ||
38 | #include "main.h" | ||
39 | #include "radio.h" | ||
40 | #include "ilt.h" | ||
41 | |||
42 | |||
43 | static const s8 b43legacy_tssi2dbm_b_table[] = { | ||
44 | 0x4D, 0x4C, 0x4B, 0x4A, | ||
45 | 0x4A, 0x49, 0x48, 0x47, | ||
46 | 0x47, 0x46, 0x45, 0x45, | ||
47 | 0x44, 0x43, 0x42, 0x42, | ||
48 | 0x41, 0x40, 0x3F, 0x3E, | ||
49 | 0x3D, 0x3C, 0x3B, 0x3A, | ||
50 | 0x39, 0x38, 0x37, 0x36, | ||
51 | 0x35, 0x34, 0x32, 0x31, | ||
52 | 0x30, 0x2F, 0x2D, 0x2C, | ||
53 | 0x2B, 0x29, 0x28, 0x26, | ||
54 | 0x25, 0x23, 0x21, 0x1F, | ||
55 | 0x1D, 0x1A, 0x17, 0x14, | ||
56 | 0x10, 0x0C, 0x06, 0x00, | ||
57 | -7, -7, -7, -7, | ||
58 | -7, -7, -7, -7, | ||
59 | -7, -7, -7, -7, | ||
60 | }; | ||
61 | |||
62 | static const s8 b43legacy_tssi2dbm_g_table[] = { | ||
63 | 77, 77, 77, 76, | ||
64 | 76, 76, 75, 75, | ||
65 | 74, 74, 73, 73, | ||
66 | 73, 72, 72, 71, | ||
67 | 71, 70, 70, 69, | ||
68 | 68, 68, 67, 67, | ||
69 | 66, 65, 65, 64, | ||
70 | 63, 63, 62, 61, | ||
71 | 60, 59, 58, 57, | ||
72 | 56, 55, 54, 53, | ||
73 | 52, 50, 49, 47, | ||
74 | 45, 43, 40, 37, | ||
75 | 33, 28, 22, 14, | ||
76 | 5, -7, -20, -20, | ||
77 | -20, -20, -20, -20, | ||
78 | -20, -20, -20, -20, | ||
79 | }; | ||
80 | |||
81 | static void b43legacy_phy_initg(struct b43legacy_wldev *dev); | ||
82 | |||
83 | |||
84 | static inline | ||
85 | void b43legacy_voluntary_preempt(void) | ||
86 | { | ||
87 | B43legacy_BUG_ON(!(!in_atomic() && !in_irq() && | ||
88 | !in_interrupt() && !irqs_disabled())); | ||
89 | #ifndef CONFIG_PREEMPT | ||
90 | cond_resched(); | ||
91 | #endif /* CONFIG_PREEMPT */ | ||
92 | } | ||
93 | |||
94 | void b43legacy_raw_phy_lock(struct b43legacy_wldev *dev) | ||
95 | { | ||
96 | struct b43legacy_phy *phy = &dev->phy; | ||
97 | |||
98 | B43legacy_WARN_ON(!irqs_disabled()); | ||
99 | if (b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD) == 0) { | ||
100 | phy->locked = 0; | ||
101 | return; | ||
102 | } | ||
103 | if (dev->dev->id.revision < 3) { | ||
104 | b43legacy_mac_suspend(dev); | ||
105 | spin_lock(&phy->lock); | ||
106 | } else { | ||
107 | if (!b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) | ||
108 | b43legacy_power_saving_ctl_bits(dev, -1, 1); | ||
109 | } | ||
110 | phy->locked = 1; | ||
111 | } | ||
112 | |||
113 | void b43legacy_raw_phy_unlock(struct b43legacy_wldev *dev) | ||
114 | { | ||
115 | struct b43legacy_phy *phy = &dev->phy; | ||
116 | |||
117 | B43legacy_WARN_ON(!irqs_disabled()); | ||
118 | if (dev->dev->id.revision < 3) { | ||
119 | if (phy->locked) { | ||
120 | spin_unlock(&phy->lock); | ||
121 | b43legacy_mac_enable(dev); | ||
122 | } | ||
123 | } else { | ||
124 | if (!b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) | ||
125 | b43legacy_power_saving_ctl_bits(dev, -1, -1); | ||
126 | } | ||
127 | phy->locked = 0; | ||
128 | } | ||
129 | |||
130 | u16 b43legacy_phy_read(struct b43legacy_wldev *dev, u16 offset) | ||
131 | { | ||
132 | b43legacy_write16(dev, B43legacy_MMIO_PHY_CONTROL, offset); | ||
133 | return b43legacy_read16(dev, B43legacy_MMIO_PHY_DATA); | ||
134 | } | ||
135 | |||
136 | void b43legacy_phy_write(struct b43legacy_wldev *dev, u16 offset, u16 val) | ||
137 | { | ||
138 | b43legacy_write16(dev, B43legacy_MMIO_PHY_CONTROL, offset); | ||
139 | mmiowb(); | ||
140 | b43legacy_write16(dev, B43legacy_MMIO_PHY_DATA, val); | ||
141 | } | ||
142 | |||
143 | void b43legacy_phy_calibrate(struct b43legacy_wldev *dev) | ||
144 | { | ||
145 | struct b43legacy_phy *phy = &dev->phy; | ||
146 | |||
147 | b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD); /* Dummy read. */ | ||
148 | if (phy->calibrated) | ||
149 | return; | ||
150 | if (phy->type == B43legacy_PHYTYPE_G && phy->rev == 1) { | ||
151 | b43legacy_wireless_core_reset(dev, 0); | ||
152 | b43legacy_phy_initg(dev); | ||
153 | b43legacy_wireless_core_reset(dev, B43legacy_TMSLOW_GMODE); | ||
154 | } | ||
155 | phy->calibrated = 1; | ||
156 | } | ||
157 | |||
158 | /* intialize B PHY power control | ||
159 | * as described in http://bcm-specs.sipsolutions.net/InitPowerControl | ||
160 | */ | ||
161 | static void b43legacy_phy_init_pctl(struct b43legacy_wldev *dev) | ||
162 | { | ||
163 | struct b43legacy_phy *phy = &dev->phy; | ||
164 | u16 saved_batt = 0; | ||
165 | u16 saved_ratt = 0; | ||
166 | u16 saved_txctl1 = 0; | ||
167 | int must_reset_txpower = 0; | ||
168 | |||
169 | B43legacy_BUG_ON(!(phy->type == B43legacy_PHYTYPE_B || | ||
170 | phy->type == B43legacy_PHYTYPE_G)); | ||
171 | if (is_bcm_board_vendor(dev) && | ||
172 | (dev->dev->bus->boardinfo.type == 0x0416)) | ||
173 | return; | ||
174 | |||
175 | b43legacy_phy_write(dev, 0x0028, 0x8018); | ||
176 | b43legacy_write16(dev, 0x03E6, b43legacy_read16(dev, 0x03E6) & 0xFFDF); | ||
177 | |||
178 | if (phy->type == B43legacy_PHYTYPE_G) { | ||
179 | if (!phy->gmode) | ||
180 | return; | ||
181 | b43legacy_phy_write(dev, 0x047A, 0xC111); | ||
182 | } | ||
183 | if (phy->savedpctlreg != 0xFFFF) | ||
184 | return; | ||
185 | #ifdef CONFIG_B43LEGACY_DEBUG | ||
186 | if (phy->manual_txpower_control) | ||
187 | return; | ||
188 | #endif | ||
189 | |||
190 | if (phy->type == B43legacy_PHYTYPE_B && | ||
191 | phy->rev >= 2 && | ||
192 | phy->radio_ver == 0x2050) | ||
193 | b43legacy_radio_write16(dev, 0x0076, | ||
194 | b43legacy_radio_read16(dev, 0x0076) | ||
195 | | 0x0084); | ||
196 | else { | ||
197 | saved_batt = phy->bbatt; | ||
198 | saved_ratt = phy->rfatt; | ||
199 | saved_txctl1 = phy->txctl1; | ||
200 | if ((phy->radio_rev >= 6) && (phy->radio_rev <= 8) | ||
201 | && /*FIXME: incomplete specs for 5 < revision < 9 */ 0) | ||
202 | b43legacy_radio_set_txpower_bg(dev, 0xB, 0x1F, 0); | ||
203 | else | ||
204 | b43legacy_radio_set_txpower_bg(dev, 0xB, 9, 0); | ||
205 | must_reset_txpower = 1; | ||
206 | } | ||
207 | b43legacy_dummy_transmission(dev); | ||
208 | |||
209 | phy->savedpctlreg = b43legacy_phy_read(dev, B43legacy_PHY_G_PCTL); | ||
210 | |||
211 | if (must_reset_txpower) | ||
212 | b43legacy_radio_set_txpower_bg(dev, saved_batt, saved_ratt, | ||
213 | saved_txctl1); | ||
214 | else | ||
215 | b43legacy_radio_write16(dev, 0x0076, b43legacy_radio_read16(dev, | ||
216 | 0x0076) & 0xFF7B); | ||
217 | b43legacy_radio_clear_tssi(dev); | ||
218 | } | ||
219 | |||
220 | static void b43legacy_phy_agcsetup(struct b43legacy_wldev *dev) | ||
221 | { | ||
222 | struct b43legacy_phy *phy = &dev->phy; | ||
223 | u16 offset = 0x0000; | ||
224 | |||
225 | if (phy->rev == 1) | ||
226 | offset = 0x4C00; | ||
227 | |||
228 | b43legacy_ilt_write(dev, offset, 0x00FE); | ||
229 | b43legacy_ilt_write(dev, offset + 1, 0x000D); | ||
230 | b43legacy_ilt_write(dev, offset + 2, 0x0013); | ||
231 | b43legacy_ilt_write(dev, offset + 3, 0x0019); | ||
232 | |||
233 | if (phy->rev == 1) { | ||
234 | b43legacy_ilt_write(dev, 0x1800, 0x2710); | ||
235 | b43legacy_ilt_write(dev, 0x1801, 0x9B83); | ||
236 | b43legacy_ilt_write(dev, 0x1802, 0x9B83); | ||
237 | b43legacy_ilt_write(dev, 0x1803, 0x0F8D); | ||
238 | b43legacy_phy_write(dev, 0x0455, 0x0004); | ||
239 | } | ||
240 | |||
241 | b43legacy_phy_write(dev, 0x04A5, (b43legacy_phy_read(dev, 0x04A5) | ||
242 | & 0x00FF) | 0x5700); | ||
243 | b43legacy_phy_write(dev, 0x041A, (b43legacy_phy_read(dev, 0x041A) | ||
244 | & 0xFF80) | 0x000F); | ||
245 | b43legacy_phy_write(dev, 0x041A, (b43legacy_phy_read(dev, 0x041A) | ||
246 | & 0xC07F) | 0x2B80); | ||
247 | b43legacy_phy_write(dev, 0x048C, (b43legacy_phy_read(dev, 0x048C) | ||
248 | & 0xF0FF) | 0x0300); | ||
249 | |||
250 | b43legacy_radio_write16(dev, 0x007A, | ||
251 | b43legacy_radio_read16(dev, 0x007A) | ||
252 | | 0x0008); | ||
253 | |||
254 | b43legacy_phy_write(dev, 0x04A0, (b43legacy_phy_read(dev, 0x04A0) | ||
255 | & 0xFFF0) | 0x0008); | ||
256 | b43legacy_phy_write(dev, 0x04A1, (b43legacy_phy_read(dev, 0x04A1) | ||
257 | & 0xF0FF) | 0x0600); | ||
258 | b43legacy_phy_write(dev, 0x04A2, (b43legacy_phy_read(dev, 0x04A2) | ||
259 | & 0xF0FF) | 0x0700); | ||
260 | b43legacy_phy_write(dev, 0x04A0, (b43legacy_phy_read(dev, 0x04A0) | ||
261 | & 0xF0FF) | 0x0100); | ||
262 | |||
263 | if (phy->rev == 1) | ||
264 | b43legacy_phy_write(dev, 0x04A2, | ||
265 | (b43legacy_phy_read(dev, 0x04A2) | ||
266 | & 0xFFF0) | 0x0007); | ||
267 | |||
268 | b43legacy_phy_write(dev, 0x0488, (b43legacy_phy_read(dev, 0x0488) | ||
269 | & 0xFF00) | 0x001C); | ||
270 | b43legacy_phy_write(dev, 0x0488, (b43legacy_phy_read(dev, 0x0488) | ||
271 | & 0xC0FF) | 0x0200); | ||
272 | b43legacy_phy_write(dev, 0x0496, (b43legacy_phy_read(dev, 0x0496) | ||
273 | & 0xFF00) | 0x001C); | ||
274 | b43legacy_phy_write(dev, 0x0489, (b43legacy_phy_read(dev, 0x0489) | ||
275 | & 0xFF00) | 0x0020); | ||
276 | b43legacy_phy_write(dev, 0x0489, (b43legacy_phy_read(dev, 0x0489) | ||
277 | & 0xC0FF) | 0x0200); | ||
278 | b43legacy_phy_write(dev, 0x0482, (b43legacy_phy_read(dev, 0x0482) | ||
279 | & 0xFF00) | 0x002E); | ||
280 | b43legacy_phy_write(dev, 0x0496, (b43legacy_phy_read(dev, 0x0496) | ||
281 | & 0x00FF) | 0x1A00); | ||
282 | b43legacy_phy_write(dev, 0x0481, (b43legacy_phy_read(dev, 0x0481) | ||
283 | & 0xFF00) | 0x0028); | ||
284 | b43legacy_phy_write(dev, 0x0481, (b43legacy_phy_read(dev, 0x0481) | ||
285 | & 0x00FF) | 0x2C00); | ||
286 | |||
287 | if (phy->rev == 1) { | ||
288 | b43legacy_phy_write(dev, 0x0430, 0x092B); | ||
289 | b43legacy_phy_write(dev, 0x041B, | ||
290 | (b43legacy_phy_read(dev, 0x041B) | ||
291 | & 0xFFE1) | 0x0002); | ||
292 | } else { | ||
293 | b43legacy_phy_write(dev, 0x041B, | ||
294 | b43legacy_phy_read(dev, 0x041B) & 0xFFE1); | ||
295 | b43legacy_phy_write(dev, 0x041F, 0x287A); | ||
296 | b43legacy_phy_write(dev, 0x0420, | ||
297 | (b43legacy_phy_read(dev, 0x0420) | ||
298 | & 0xFFF0) | 0x0004); | ||
299 | } | ||
300 | |||
301 | if (phy->rev > 2) { | ||
302 | b43legacy_phy_write(dev, 0x0422, 0x287A); | ||
303 | b43legacy_phy_write(dev, 0x0420, | ||
304 | (b43legacy_phy_read(dev, 0x0420) | ||
305 | & 0x0FFF) | 0x3000); | ||
306 | } | ||
307 | |||
308 | b43legacy_phy_write(dev, 0x04A8, (b43legacy_phy_read(dev, 0x04A8) | ||
309 | & 0x8080) | 0x7874); | ||
310 | b43legacy_phy_write(dev, 0x048E, 0x1C00); | ||
311 | |||
312 | if (phy->rev == 1) { | ||
313 | b43legacy_phy_write(dev, 0x04AB, | ||
314 | (b43legacy_phy_read(dev, 0x04AB) | ||
315 | & 0xF0FF) | 0x0600); | ||
316 | b43legacy_phy_write(dev, 0x048B, 0x005E); | ||
317 | b43legacy_phy_write(dev, 0x048C, | ||
318 | (b43legacy_phy_read(dev, 0x048C) & 0xFF00) | ||
319 | | 0x001E); | ||
320 | b43legacy_phy_write(dev, 0x048D, 0x0002); | ||
321 | } | ||
322 | |||
323 | b43legacy_ilt_write(dev, offset + 0x0800, 0); | ||
324 | b43legacy_ilt_write(dev, offset + 0x0801, 7); | ||
325 | b43legacy_ilt_write(dev, offset + 0x0802, 16); | ||
326 | b43legacy_ilt_write(dev, offset + 0x0803, 28); | ||
327 | |||
328 | if (phy->rev >= 6) { | ||
329 | b43legacy_phy_write(dev, 0x0426, | ||
330 | (b43legacy_phy_read(dev, 0x0426) & 0xFFFC)); | ||
331 | b43legacy_phy_write(dev, 0x0426, | ||
332 | (b43legacy_phy_read(dev, 0x0426) & 0xEFFF)); | ||
333 | } | ||
334 | } | ||
335 | |||
336 | static void b43legacy_phy_setupg(struct b43legacy_wldev *dev) | ||
337 | { | ||
338 | struct b43legacy_phy *phy = &dev->phy; | ||
339 | u16 i; | ||
340 | |||
341 | B43legacy_BUG_ON(phy->type != B43legacy_PHYTYPE_G); | ||
342 | if (phy->rev == 1) { | ||
343 | b43legacy_phy_write(dev, 0x0406, 0x4F19); | ||
344 | b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, | ||
345 | (b43legacy_phy_read(dev, | ||
346 | B43legacy_PHY_G_CRS) & 0xFC3F) | 0x0340); | ||
347 | b43legacy_phy_write(dev, 0x042C, 0x005A); | ||
348 | b43legacy_phy_write(dev, 0x0427, 0x001A); | ||
349 | |||
350 | for (i = 0; i < B43legacy_ILT_FINEFREQG_SIZE; i++) | ||
351 | b43legacy_ilt_write(dev, 0x5800 + i, | ||
352 | b43legacy_ilt_finefreqg[i]); | ||
353 | for (i = 0; i < B43legacy_ILT_NOISEG1_SIZE; i++) | ||
354 | b43legacy_ilt_write(dev, 0x1800 + i, | ||
355 | b43legacy_ilt_noiseg1[i]); | ||
356 | for (i = 0; i < B43legacy_ILT_ROTOR_SIZE; i++) | ||
357 | b43legacy_ilt_write32(dev, 0x2000 + i, | ||
358 | b43legacy_ilt_rotor[i]); | ||
359 | } else { | ||
360 | /* nrssi values are signed 6-bit values. Why 0x7654 here? */ | ||
361 | b43legacy_nrssi_hw_write(dev, 0xBA98, (s16)0x7654); | ||
362 | |||
363 | if (phy->rev == 2) { | ||
364 | b43legacy_phy_write(dev, 0x04C0, 0x1861); | ||
365 | b43legacy_phy_write(dev, 0x04C1, 0x0271); | ||
366 | } else if (phy->rev > 2) { | ||
367 | b43legacy_phy_write(dev, 0x04C0, 0x0098); | ||
368 | b43legacy_phy_write(dev, 0x04C1, 0x0070); | ||
369 | b43legacy_phy_write(dev, 0x04C9, 0x0080); | ||
370 | } | ||
371 | b43legacy_phy_write(dev, 0x042B, b43legacy_phy_read(dev, | ||
372 | 0x042B) | 0x800); | ||
373 | |||
374 | for (i = 0; i < 64; i++) | ||
375 | b43legacy_ilt_write(dev, 0x4000 + i, i); | ||
376 | for (i = 0; i < B43legacy_ILT_NOISEG2_SIZE; i++) | ||
377 | b43legacy_ilt_write(dev, 0x1800 + i, | ||
378 | b43legacy_ilt_noiseg2[i]); | ||
379 | } | ||
380 | |||
381 | if (phy->rev <= 2) | ||
382 | for (i = 0; i < B43legacy_ILT_NOISESCALEG_SIZE; i++) | ||
383 | b43legacy_ilt_write(dev, 0x1400 + i, | ||
384 | b43legacy_ilt_noisescaleg1[i]); | ||
385 | else if ((phy->rev >= 7) && (b43legacy_phy_read(dev, 0x0449) & 0x0200)) | ||
386 | for (i = 0; i < B43legacy_ILT_NOISESCALEG_SIZE; i++) | ||
387 | b43legacy_ilt_write(dev, 0x1400 + i, | ||
388 | b43legacy_ilt_noisescaleg3[i]); | ||
389 | else | ||
390 | for (i = 0; i < B43legacy_ILT_NOISESCALEG_SIZE; i++) | ||
391 | b43legacy_ilt_write(dev, 0x1400 + i, | ||
392 | b43legacy_ilt_noisescaleg2[i]); | ||
393 | |||
394 | if (phy->rev == 2) | ||
395 | for (i = 0; i < B43legacy_ILT_SIGMASQR_SIZE; i++) | ||
396 | b43legacy_ilt_write(dev, 0x5000 + i, | ||
397 | b43legacy_ilt_sigmasqr1[i]); | ||
398 | else if ((phy->rev > 2) && (phy->rev <= 8)) | ||
399 | for (i = 0; i < B43legacy_ILT_SIGMASQR_SIZE; i++) | ||
400 | b43legacy_ilt_write(dev, 0x5000 + i, | ||
401 | b43legacy_ilt_sigmasqr2[i]); | ||
402 | |||
403 | if (phy->rev == 1) { | ||
404 | for (i = 0; i < B43legacy_ILT_RETARD_SIZE; i++) | ||
405 | b43legacy_ilt_write32(dev, 0x2400 + i, | ||
406 | b43legacy_ilt_retard[i]); | ||
407 | for (i = 4; i < 20; i++) | ||
408 | b43legacy_ilt_write(dev, 0x5400 + i, 0x0020); | ||
409 | b43legacy_phy_agcsetup(dev); | ||
410 | |||
411 | if (is_bcm_board_vendor(dev) && | ||
412 | (dev->dev->bus->boardinfo.type == 0x0416) && | ||
413 | (dev->dev->bus->boardinfo.rev == 0x0017)) | ||
414 | return; | ||
415 | |||
416 | b43legacy_ilt_write(dev, 0x5001, 0x0002); | ||
417 | b43legacy_ilt_write(dev, 0x5002, 0x0001); | ||
418 | } else { | ||
419 | for (i = 0; i <= 0x20; i++) | ||
420 | b43legacy_ilt_write(dev, 0x1000 + i, 0x0820); | ||
421 | b43legacy_phy_agcsetup(dev); | ||
422 | b43legacy_phy_read(dev, 0x0400); /* dummy read */ | ||
423 | b43legacy_phy_write(dev, 0x0403, 0x1000); | ||
424 | b43legacy_ilt_write(dev, 0x3C02, 0x000F); | ||
425 | b43legacy_ilt_write(dev, 0x3C03, 0x0014); | ||
426 | |||
427 | if (is_bcm_board_vendor(dev) && | ||
428 | (dev->dev->bus->boardinfo.type == 0x0416) && | ||
429 | (dev->dev->bus->boardinfo.rev == 0x0017)) | ||
430 | return; | ||
431 | |||
432 | b43legacy_ilt_write(dev, 0x0401, 0x0002); | ||
433 | b43legacy_ilt_write(dev, 0x0402, 0x0001); | ||
434 | } | ||
435 | } | ||
436 | |||
437 | /* Initialize the APHY portion of a GPHY. */ | ||
438 | static void b43legacy_phy_inita(struct b43legacy_wldev *dev) | ||
439 | { | ||
440 | |||
441 | might_sleep(); | ||
442 | |||
443 | b43legacy_phy_setupg(dev); | ||
444 | if (dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_PACTRL) | ||
445 | b43legacy_phy_write(dev, 0x046E, 0x03CF); | ||
446 | } | ||
447 | |||
448 | static void b43legacy_phy_initb2(struct b43legacy_wldev *dev) | ||
449 | { | ||
450 | struct b43legacy_phy *phy = &dev->phy; | ||
451 | u16 offset; | ||
452 | int val; | ||
453 | |||
454 | b43legacy_write16(dev, 0x03EC, 0x3F22); | ||
455 | b43legacy_phy_write(dev, 0x0020, 0x301C); | ||
456 | b43legacy_phy_write(dev, 0x0026, 0x0000); | ||
457 | b43legacy_phy_write(dev, 0x0030, 0x00C6); | ||
458 | b43legacy_phy_write(dev, 0x0088, 0x3E00); | ||
459 | val = 0x3C3D; | ||
460 | for (offset = 0x0089; offset < 0x00A7; offset++) { | ||
461 | b43legacy_phy_write(dev, offset, val); | ||
462 | val -= 0x0202; | ||
463 | } | ||
464 | b43legacy_phy_write(dev, 0x03E4, 0x3000); | ||
465 | if (phy->channel == 0xFF) | ||
466 | b43legacy_radio_selectchannel(dev, | ||
467 | B43legacy_RADIO_DEFAULT_CHANNEL_BG, | ||
468 | 0); | ||
469 | else | ||
470 | b43legacy_radio_selectchannel(dev, phy->channel, 0); | ||
471 | if (phy->radio_ver != 0x2050) { | ||
472 | b43legacy_radio_write16(dev, 0x0075, 0x0080); | ||
473 | b43legacy_radio_write16(dev, 0x0079, 0x0081); | ||
474 | } | ||
475 | b43legacy_radio_write16(dev, 0x0050, 0x0020); | ||
476 | b43legacy_radio_write16(dev, 0x0050, 0x0023); | ||
477 | if (phy->radio_ver == 0x2050) { | ||
478 | b43legacy_radio_write16(dev, 0x0050, 0x0020); | ||
479 | b43legacy_radio_write16(dev, 0x005A, 0x0070); | ||
480 | b43legacy_radio_write16(dev, 0x005B, 0x007B); | ||
481 | b43legacy_radio_write16(dev, 0x005C, 0x00B0); | ||
482 | b43legacy_radio_write16(dev, 0x007A, 0x000F); | ||
483 | b43legacy_phy_write(dev, 0x0038, 0x0677); | ||
484 | b43legacy_radio_init2050(dev); | ||
485 | } | ||
486 | b43legacy_phy_write(dev, 0x0014, 0x0080); | ||
487 | b43legacy_phy_write(dev, 0x0032, 0x00CA); | ||
488 | b43legacy_phy_write(dev, 0x0032, 0x00CC); | ||
489 | b43legacy_phy_write(dev, 0x0035, 0x07C2); | ||
490 | b43legacy_phy_lo_b_measure(dev); | ||
491 | b43legacy_phy_write(dev, 0x0026, 0xCC00); | ||
492 | if (phy->radio_ver != 0x2050) | ||
493 | b43legacy_phy_write(dev, 0x0026, 0xCE00); | ||
494 | b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, 0x1000); | ||
495 | b43legacy_phy_write(dev, 0x002A, 0x88A3); | ||
496 | if (phy->radio_ver != 0x2050) | ||
497 | b43legacy_phy_write(dev, 0x002A, 0x88C2); | ||
498 | b43legacy_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF); | ||
499 | b43legacy_phy_init_pctl(dev); | ||
500 | } | ||
501 | |||
502 | static void b43legacy_phy_initb4(struct b43legacy_wldev *dev) | ||
503 | { | ||
504 | struct b43legacy_phy *phy = &dev->phy; | ||
505 | u16 offset; | ||
506 | u16 val; | ||
507 | |||
508 | b43legacy_write16(dev, 0x03EC, 0x3F22); | ||
509 | b43legacy_phy_write(dev, 0x0020, 0x301C); | ||
510 | b43legacy_phy_write(dev, 0x0026, 0x0000); | ||
511 | b43legacy_phy_write(dev, 0x0030, 0x00C6); | ||
512 | b43legacy_phy_write(dev, 0x0088, 0x3E00); | ||
513 | val = 0x3C3D; | ||
514 | for (offset = 0x0089; offset < 0x00A7; offset++) { | ||
515 | b43legacy_phy_write(dev, offset, val); | ||
516 | val -= 0x0202; | ||
517 | } | ||
518 | b43legacy_phy_write(dev, 0x03E4, 0x3000); | ||
519 | if (phy->channel == 0xFF) | ||
520 | b43legacy_radio_selectchannel(dev, | ||
521 | B43legacy_RADIO_DEFAULT_CHANNEL_BG, | ||
522 | 0); | ||
523 | else | ||
524 | b43legacy_radio_selectchannel(dev, phy->channel, 0); | ||
525 | if (phy->radio_ver != 0x2050) { | ||
526 | b43legacy_radio_write16(dev, 0x0075, 0x0080); | ||
527 | b43legacy_radio_write16(dev, 0x0079, 0x0081); | ||
528 | } | ||
529 | b43legacy_radio_write16(dev, 0x0050, 0x0020); | ||
530 | b43legacy_radio_write16(dev, 0x0050, 0x0023); | ||
531 | if (phy->radio_ver == 0x2050) { | ||
532 | b43legacy_radio_write16(dev, 0x0050, 0x0020); | ||
533 | b43legacy_radio_write16(dev, 0x005A, 0x0070); | ||
534 | b43legacy_radio_write16(dev, 0x005B, 0x007B); | ||
535 | b43legacy_radio_write16(dev, 0x005C, 0x00B0); | ||
536 | b43legacy_radio_write16(dev, 0x007A, 0x000F); | ||
537 | b43legacy_phy_write(dev, 0x0038, 0x0677); | ||
538 | b43legacy_radio_init2050(dev); | ||
539 | } | ||
540 | b43legacy_phy_write(dev, 0x0014, 0x0080); | ||
541 | b43legacy_phy_write(dev, 0x0032, 0x00CA); | ||
542 | if (phy->radio_ver == 0x2050) | ||
543 | b43legacy_phy_write(dev, 0x0032, 0x00E0); | ||
544 | b43legacy_phy_write(dev, 0x0035, 0x07C2); | ||
545 | |||
546 | b43legacy_phy_lo_b_measure(dev); | ||
547 | |||
548 | b43legacy_phy_write(dev, 0x0026, 0xCC00); | ||
549 | if (phy->radio_ver == 0x2050) | ||
550 | b43legacy_phy_write(dev, 0x0026, 0xCE00); | ||
551 | b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, 0x1100); | ||
552 | b43legacy_phy_write(dev, 0x002A, 0x88A3); | ||
553 | if (phy->radio_ver == 0x2050) | ||
554 | b43legacy_phy_write(dev, 0x002A, 0x88C2); | ||
555 | b43legacy_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF); | ||
556 | if (dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_RSSI) { | ||
557 | b43legacy_calc_nrssi_slope(dev); | ||
558 | b43legacy_calc_nrssi_threshold(dev); | ||
559 | } | ||
560 | b43legacy_phy_init_pctl(dev); | ||
561 | } | ||
562 | |||
563 | static void b43legacy_phy_initb5(struct b43legacy_wldev *dev) | ||
564 | { | ||
565 | struct b43legacy_phy *phy = &dev->phy; | ||
566 | u16 offset; | ||
567 | u16 value; | ||
568 | u8 old_channel; | ||
569 | |||
570 | if (phy->analog == 1) | ||
571 | b43legacy_radio_write16(dev, 0x007A, | ||
572 | b43legacy_radio_read16(dev, 0x007A) | ||
573 | | 0x0050); | ||
574 | if (!is_bcm_board_vendor(dev) && | ||
575 | (dev->dev->bus->boardinfo.type != 0x0416)) { | ||
576 | value = 0x2120; | ||
577 | for (offset = 0x00A8 ; offset < 0x00C7; offset++) { | ||
578 | b43legacy_phy_write(dev, offset, value); | ||
579 | value += 0x0202; | ||
580 | } | ||
581 | } | ||
582 | b43legacy_phy_write(dev, 0x0035, | ||
583 | (b43legacy_phy_read(dev, 0x0035) & 0xF0FF) | ||
584 | | 0x0700); | ||
585 | if (phy->radio_ver == 0x2050) | ||
586 | b43legacy_phy_write(dev, 0x0038, 0x0667); | ||
587 | |||
588 | if (phy->gmode) { | ||
589 | if (phy->radio_ver == 0x2050) { | ||
590 | b43legacy_radio_write16(dev, 0x007A, | ||
591 | b43legacy_radio_read16(dev, 0x007A) | ||
592 | | 0x0020); | ||
593 | b43legacy_radio_write16(dev, 0x0051, | ||
594 | b43legacy_radio_read16(dev, 0x0051) | ||
595 | | 0x0004); | ||
596 | } | ||
597 | b43legacy_write16(dev, B43legacy_MMIO_PHY_RADIO, 0x0000); | ||
598 | |||
599 | b43legacy_phy_write(dev, 0x0802, b43legacy_phy_read(dev, 0x0802) | ||
600 | | 0x0100); | ||
601 | b43legacy_phy_write(dev, 0x042B, b43legacy_phy_read(dev, 0x042B) | ||
602 | | 0x2000); | ||
603 | |||
604 | b43legacy_phy_write(dev, 0x001C, 0x186A); | ||
605 | |||
606 | b43legacy_phy_write(dev, 0x0013, (b43legacy_phy_read(dev, | ||
607 | 0x0013) & 0x00FF) | 0x1900); | ||
608 | b43legacy_phy_write(dev, 0x0035, (b43legacy_phy_read(dev, | ||
609 | 0x0035) & 0xFFC0) | 0x0064); | ||
610 | b43legacy_phy_write(dev, 0x005D, (b43legacy_phy_read(dev, | ||
611 | 0x005D) & 0xFF80) | 0x000A); | ||
612 | } | ||
613 | |||
614 | if (dev->bad_frames_preempt) | ||
615 | b43legacy_phy_write(dev, B43legacy_PHY_RADIO_BITFIELD, | ||
616 | b43legacy_phy_read(dev, | ||
617 | B43legacy_PHY_RADIO_BITFIELD) | (1 << 11)); | ||
618 | |||
619 | if (phy->analog == 1) { | ||
620 | b43legacy_phy_write(dev, 0x0026, 0xCE00); | ||
621 | b43legacy_phy_write(dev, 0x0021, 0x3763); | ||
622 | b43legacy_phy_write(dev, 0x0022, 0x1BC3); | ||
623 | b43legacy_phy_write(dev, 0x0023, 0x06F9); | ||
624 | b43legacy_phy_write(dev, 0x0024, 0x037E); | ||
625 | } else | ||
626 | b43legacy_phy_write(dev, 0x0026, 0xCC00); | ||
627 | b43legacy_phy_write(dev, 0x0030, 0x00C6); | ||
628 | b43legacy_write16(dev, 0x03EC, 0x3F22); | ||
629 | |||
630 | if (phy->analog == 1) | ||
631 | b43legacy_phy_write(dev, 0x0020, 0x3E1C); | ||
632 | else | ||
633 | b43legacy_phy_write(dev, 0x0020, 0x301C); | ||
634 | |||
635 | if (phy->analog == 0) | ||
636 | b43legacy_write16(dev, 0x03E4, 0x3000); | ||
637 | |||
638 | old_channel = (phy->channel == 0xFF) ? 1 : phy->channel; | ||
639 | /* Force to channel 7, even if not supported. */ | ||
640 | b43legacy_radio_selectchannel(dev, 7, 0); | ||
641 | |||
642 | if (phy->radio_ver != 0x2050) { | ||
643 | b43legacy_radio_write16(dev, 0x0075, 0x0080); | ||
644 | b43legacy_radio_write16(dev, 0x0079, 0x0081); | ||
645 | } | ||
646 | |||
647 | b43legacy_radio_write16(dev, 0x0050, 0x0020); | ||
648 | b43legacy_radio_write16(dev, 0x0050, 0x0023); | ||
649 | |||
650 | if (phy->radio_ver == 0x2050) { | ||
651 | b43legacy_radio_write16(dev, 0x0050, 0x0020); | ||
652 | b43legacy_radio_write16(dev, 0x005A, 0x0070); | ||
653 | } | ||
654 | |||
655 | b43legacy_radio_write16(dev, 0x005B, 0x007B); | ||
656 | b43legacy_radio_write16(dev, 0x005C, 0x00B0); | ||
657 | |||
658 | b43legacy_radio_write16(dev, 0x007A, b43legacy_radio_read16(dev, | ||
659 | 0x007A) | 0x0007); | ||
660 | |||
661 | b43legacy_radio_selectchannel(dev, old_channel, 0); | ||
662 | |||
663 | b43legacy_phy_write(dev, 0x0014, 0x0080); | ||
664 | b43legacy_phy_write(dev, 0x0032, 0x00CA); | ||
665 | b43legacy_phy_write(dev, 0x002A, 0x88A3); | ||
666 | |||
667 | b43legacy_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF); | ||
668 | |||
669 | if (phy->radio_ver == 0x2050) | ||
670 | b43legacy_radio_write16(dev, 0x005D, 0x000D); | ||
671 | |||
672 | b43legacy_write16(dev, 0x03E4, (b43legacy_read16(dev, 0x03E4) & | ||
673 | 0xFFC0) | 0x0004); | ||
674 | } | ||
675 | |||
676 | static void b43legacy_phy_initb6(struct b43legacy_wldev *dev) | ||
677 | { | ||
678 | struct b43legacy_phy *phy = &dev->phy; | ||
679 | u16 offset; | ||
680 | u16 val; | ||
681 | u8 old_channel; | ||
682 | |||
683 | b43legacy_phy_write(dev, 0x003E, 0x817A); | ||
684 | b43legacy_radio_write16(dev, 0x007A, | ||
685 | (b43legacy_radio_read16(dev, 0x007A) | 0x0058)); | ||
686 | if (phy->radio_rev == 4 || | ||
687 | phy->radio_rev == 5) { | ||
688 | b43legacy_radio_write16(dev, 0x0051, 0x0037); | ||
689 | b43legacy_radio_write16(dev, 0x0052, 0x0070); | ||
690 | b43legacy_radio_write16(dev, 0x0053, 0x00B3); | ||
691 | b43legacy_radio_write16(dev, 0x0054, 0x009B); | ||
692 | b43legacy_radio_write16(dev, 0x005A, 0x0088); | ||
693 | b43legacy_radio_write16(dev, 0x005B, 0x0088); | ||
694 | b43legacy_radio_write16(dev, 0x005D, 0x0088); | ||
695 | b43legacy_radio_write16(dev, 0x005E, 0x0088); | ||
696 | b43legacy_radio_write16(dev, 0x007D, 0x0088); | ||
697 | b43legacy_shm_write32(dev, B43legacy_SHM_SHARED, | ||
698 | B43legacy_UCODEFLAGS_OFFSET, | ||
699 | (b43legacy_shm_read32(dev, | ||
700 | B43legacy_SHM_SHARED, | ||
701 | B43legacy_UCODEFLAGS_OFFSET) | ||
702 | | 0x00000200)); | ||
703 | } | ||
704 | if (phy->radio_rev == 8) { | ||
705 | b43legacy_radio_write16(dev, 0x0051, 0x0000); | ||
706 | b43legacy_radio_write16(dev, 0x0052, 0x0040); | ||
707 | b43legacy_radio_write16(dev, 0x0053, 0x00B7); | ||
708 | b43legacy_radio_write16(dev, 0x0054, 0x0098); | ||
709 | b43legacy_radio_write16(dev, 0x005A, 0x0088); | ||
710 | b43legacy_radio_write16(dev, 0x005B, 0x006B); | ||
711 | b43legacy_radio_write16(dev, 0x005C, 0x000F); | ||
712 | if (dev->dev->bus->sprom.r1.boardflags_lo & 0x8000) { | ||
713 | b43legacy_radio_write16(dev, 0x005D, 0x00FA); | ||
714 | b43legacy_radio_write16(dev, 0x005E, 0x00D8); | ||
715 | } else { | ||
716 | b43legacy_radio_write16(dev, 0x005D, 0x00F5); | ||
717 | b43legacy_radio_write16(dev, 0x005E, 0x00B8); | ||
718 | } | ||
719 | b43legacy_radio_write16(dev, 0x0073, 0x0003); | ||
720 | b43legacy_radio_write16(dev, 0x007D, 0x00A8); | ||
721 | b43legacy_radio_write16(dev, 0x007C, 0x0001); | ||
722 | b43legacy_radio_write16(dev, 0x007E, 0x0008); | ||
723 | } | ||
724 | val = 0x1E1F; | ||
725 | for (offset = 0x0088; offset < 0x0098; offset++) { | ||
726 | b43legacy_phy_write(dev, offset, val); | ||
727 | val -= 0x0202; | ||
728 | } | ||
729 | val = 0x3E3F; | ||
730 | for (offset = 0x0098; offset < 0x00A8; offset++) { | ||
731 | b43legacy_phy_write(dev, offset, val); | ||
732 | val -= 0x0202; | ||
733 | } | ||
734 | val = 0x2120; | ||
735 | for (offset = 0x00A8; offset < 0x00C8; offset++) { | ||
736 | b43legacy_phy_write(dev, offset, (val & 0x3F3F)); | ||
737 | val += 0x0202; | ||
738 | } | ||
739 | if (phy->type == B43legacy_PHYTYPE_G) { | ||
740 | b43legacy_radio_write16(dev, 0x007A, | ||
741 | b43legacy_radio_read16(dev, 0x007A) | | ||
742 | 0x0020); | ||
743 | b43legacy_radio_write16(dev, 0x0051, | ||
744 | b43legacy_radio_read16(dev, 0x0051) | | ||
745 | 0x0004); | ||
746 | b43legacy_phy_write(dev, 0x0802, | ||
747 | b43legacy_phy_read(dev, 0x0802) | 0x0100); | ||
748 | b43legacy_phy_write(dev, 0x042B, | ||
749 | b43legacy_phy_read(dev, 0x042B) | 0x2000); | ||
750 | b43legacy_phy_write(dev, 0x5B, 0x0000); | ||
751 | b43legacy_phy_write(dev, 0x5C, 0x0000); | ||
752 | } | ||
753 | |||
754 | old_channel = phy->channel; | ||
755 | if (old_channel >= 8) | ||
756 | b43legacy_radio_selectchannel(dev, 1, 0); | ||
757 | else | ||
758 | b43legacy_radio_selectchannel(dev, 13, 0); | ||
759 | |||
760 | b43legacy_radio_write16(dev, 0x0050, 0x0020); | ||
761 | b43legacy_radio_write16(dev, 0x0050, 0x0023); | ||
762 | udelay(40); | ||
763 | if (phy->radio_rev < 6 || phy->radio_rev == 8) { | ||
764 | b43legacy_radio_write16(dev, 0x007C, | ||
765 | (b43legacy_radio_read16(dev, 0x007C) | ||
766 | | 0x0002)); | ||
767 | b43legacy_radio_write16(dev, 0x0050, 0x0020); | ||
768 | } | ||
769 | if (phy->radio_rev <= 2) { | ||
770 | b43legacy_radio_write16(dev, 0x007C, 0x0020); | ||
771 | b43legacy_radio_write16(dev, 0x005A, 0x0070); | ||
772 | b43legacy_radio_write16(dev, 0x005B, 0x007B); | ||
773 | b43legacy_radio_write16(dev, 0x005C, 0x00B0); | ||
774 | } | ||
775 | b43legacy_radio_write16(dev, 0x007A, | ||
776 | (b43legacy_radio_read16(dev, | ||
777 | 0x007A) & 0x00F8) | 0x0007); | ||
778 | |||
779 | b43legacy_radio_selectchannel(dev, old_channel, 0); | ||
780 | |||
781 | b43legacy_phy_write(dev, 0x0014, 0x0200); | ||
782 | if (phy->radio_rev >= 6) | ||
783 | b43legacy_phy_write(dev, 0x002A, 0x88C2); | ||
784 | else | ||
785 | b43legacy_phy_write(dev, 0x002A, 0x8AC0); | ||
786 | b43legacy_phy_write(dev, 0x0038, 0x0668); | ||
787 | b43legacy_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF); | ||
788 | if (phy->radio_rev <= 5) | ||
789 | b43legacy_phy_write(dev, 0x005D, (b43legacy_phy_read(dev, | ||
790 | 0x005D) & 0xFF80) | 0x0003); | ||
791 | if (phy->radio_rev <= 2) | ||
792 | b43legacy_radio_write16(dev, 0x005D, 0x000D); | ||
793 | |||
794 | if (phy->analog == 4) { | ||
795 | b43legacy_write16(dev, 0x03E4, 0x0009); | ||
796 | b43legacy_phy_write(dev, 0x61, b43legacy_phy_read(dev, 0x61) | ||
797 | & 0xFFF); | ||
798 | } else | ||
799 | b43legacy_phy_write(dev, 0x0002, (b43legacy_phy_read(dev, | ||
800 | 0x0002) & 0xFFC0) | 0x0004); | ||
801 | if (phy->type == B43legacy_PHYTYPE_G) | ||
802 | b43legacy_write16(dev, 0x03E6, 0x0); | ||
803 | if (phy->type == B43legacy_PHYTYPE_B) { | ||
804 | b43legacy_write16(dev, 0x03E6, 0x8140); | ||
805 | b43legacy_phy_write(dev, 0x0016, 0x0410); | ||
806 | b43legacy_phy_write(dev, 0x0017, 0x0820); | ||
807 | b43legacy_phy_write(dev, 0x0062, 0x0007); | ||
808 | b43legacy_radio_init2050(dev); | ||
809 | b43legacy_phy_lo_g_measure(dev); | ||
810 | if (dev->dev->bus->sprom.r1.boardflags_lo & | ||
811 | B43legacy_BFL_RSSI) { | ||
812 | b43legacy_calc_nrssi_slope(dev); | ||
813 | b43legacy_calc_nrssi_threshold(dev); | ||
814 | } | ||
815 | b43legacy_phy_init_pctl(dev); | ||
816 | } | ||
817 | } | ||
818 | |||
819 | static void b43legacy_calc_loopback_gain(struct b43legacy_wldev *dev) | ||
820 | { | ||
821 | struct b43legacy_phy *phy = &dev->phy; | ||
822 | u16 backup_phy[15] = {0}; | ||
823 | u16 backup_radio[3]; | ||
824 | u16 backup_bband; | ||
825 | u16 i; | ||
826 | u16 loop1_cnt; | ||
827 | u16 loop1_done; | ||
828 | u16 loop1_omitted; | ||
829 | u16 loop2_done; | ||
830 | |||
831 | backup_phy[0] = b43legacy_phy_read(dev, 0x0429); | ||
832 | backup_phy[1] = b43legacy_phy_read(dev, 0x0001); | ||
833 | backup_phy[2] = b43legacy_phy_read(dev, 0x0811); | ||
834 | backup_phy[3] = b43legacy_phy_read(dev, 0x0812); | ||
835 | if (phy->rev != 1) { | ||
836 | backup_phy[4] = b43legacy_phy_read(dev, 0x0814); | ||
837 | backup_phy[5] = b43legacy_phy_read(dev, 0x0815); | ||
838 | } | ||
839 | backup_phy[6] = b43legacy_phy_read(dev, 0x005A); | ||
840 | backup_phy[7] = b43legacy_phy_read(dev, 0x0059); | ||
841 | backup_phy[8] = b43legacy_phy_read(dev, 0x0058); | ||
842 | backup_phy[9] = b43legacy_phy_read(dev, 0x000A); | ||
843 | backup_phy[10] = b43legacy_phy_read(dev, 0x0003); | ||
844 | backup_phy[11] = b43legacy_phy_read(dev, 0x080F); | ||
845 | backup_phy[12] = b43legacy_phy_read(dev, 0x0810); | ||
846 | backup_phy[13] = b43legacy_phy_read(dev, 0x002B); | ||
847 | backup_phy[14] = b43legacy_phy_read(dev, 0x0015); | ||
848 | b43legacy_phy_read(dev, 0x002D); /* dummy read */ | ||
849 | backup_bband = phy->bbatt; | ||
850 | backup_radio[0] = b43legacy_radio_read16(dev, 0x0052); | ||
851 | backup_radio[1] = b43legacy_radio_read16(dev, 0x0043); | ||
852 | backup_radio[2] = b43legacy_radio_read16(dev, 0x007A); | ||
853 | |||
854 | b43legacy_phy_write(dev, 0x0429, | ||
855 | b43legacy_phy_read(dev, 0x0429) & 0x3FFF); | ||
856 | b43legacy_phy_write(dev, 0x0001, | ||
857 | b43legacy_phy_read(dev, 0x0001) & 0x8000); | ||
858 | b43legacy_phy_write(dev, 0x0811, | ||
859 | b43legacy_phy_read(dev, 0x0811) | 0x0002); | ||
860 | b43legacy_phy_write(dev, 0x0812, | ||
861 | b43legacy_phy_read(dev, 0x0812) & 0xFFFD); | ||
862 | b43legacy_phy_write(dev, 0x0811, | ||
863 | b43legacy_phy_read(dev, 0x0811) | 0x0001); | ||
864 | b43legacy_phy_write(dev, 0x0812, | ||
865 | b43legacy_phy_read(dev, 0x0812) & 0xFFFE); | ||
866 | if (phy->rev != 1) { | ||
867 | b43legacy_phy_write(dev, 0x0814, | ||
868 | b43legacy_phy_read(dev, 0x0814) | 0x0001); | ||
869 | b43legacy_phy_write(dev, 0x0815, | ||
870 | b43legacy_phy_read(dev, 0x0815) & 0xFFFE); | ||
871 | b43legacy_phy_write(dev, 0x0814, | ||
872 | b43legacy_phy_read(dev, 0x0814) | 0x0002); | ||
873 | b43legacy_phy_write(dev, 0x0815, | ||
874 | b43legacy_phy_read(dev, 0x0815) & 0xFFFD); | ||
875 | } | ||
876 | b43legacy_phy_write(dev, 0x0811, b43legacy_phy_read(dev, 0x0811) | | ||
877 | 0x000C); | ||
878 | b43legacy_phy_write(dev, 0x0812, b43legacy_phy_read(dev, 0x0812) | | ||
879 | 0x000C); | ||
880 | |||
881 | b43legacy_phy_write(dev, 0x0811, (b43legacy_phy_read(dev, 0x0811) | ||
882 | & 0xFFCF) | 0x0030); | ||
883 | b43legacy_phy_write(dev, 0x0812, (b43legacy_phy_read(dev, 0x0812) | ||
884 | & 0xFFCF) | 0x0010); | ||
885 | |||
886 | b43legacy_phy_write(dev, 0x005A, 0x0780); | ||
887 | b43legacy_phy_write(dev, 0x0059, 0xC810); | ||
888 | b43legacy_phy_write(dev, 0x0058, 0x000D); | ||
889 | if (phy->analog == 0) | ||
890 | b43legacy_phy_write(dev, 0x0003, 0x0122); | ||
891 | else | ||
892 | b43legacy_phy_write(dev, 0x000A, | ||
893 | b43legacy_phy_read(dev, 0x000A) | ||
894 | | 0x2000); | ||
895 | if (phy->rev != 1) { | ||
896 | b43legacy_phy_write(dev, 0x0814, | ||
897 | b43legacy_phy_read(dev, 0x0814) | 0x0004); | ||
898 | b43legacy_phy_write(dev, 0x0815, | ||
899 | b43legacy_phy_read(dev, 0x0815) & 0xFFFB); | ||
900 | } | ||
901 | b43legacy_phy_write(dev, 0x0003, | ||
902 | (b43legacy_phy_read(dev, 0x0003) | ||
903 | & 0xFF9F) | 0x0040); | ||
904 | if (phy->radio_ver == 0x2050 && phy->radio_rev == 2) { | ||
905 | b43legacy_radio_write16(dev, 0x0052, 0x0000); | ||
906 | b43legacy_radio_write16(dev, 0x0043, | ||
907 | (b43legacy_radio_read16(dev, 0x0043) | ||
908 | & 0xFFF0) | 0x0009); | ||
909 | loop1_cnt = 9; | ||
910 | } else if (phy->radio_rev == 8) { | ||
911 | b43legacy_radio_write16(dev, 0x0043, 0x000F); | ||
912 | loop1_cnt = 15; | ||
913 | } else | ||
914 | loop1_cnt = 0; | ||
915 | |||
916 | b43legacy_phy_set_baseband_attenuation(dev, 11); | ||
917 | |||
918 | if (phy->rev >= 3) | ||
919 | b43legacy_phy_write(dev, 0x080F, 0xC020); | ||
920 | else | ||
921 | b43legacy_phy_write(dev, 0x080F, 0x8020); | ||
922 | b43legacy_phy_write(dev, 0x0810, 0x0000); | ||
923 | |||
924 | b43legacy_phy_write(dev, 0x002B, | ||
925 | (b43legacy_phy_read(dev, 0x002B) | ||
926 | & 0xFFC0) | 0x0001); | ||
927 | b43legacy_phy_write(dev, 0x002B, | ||
928 | (b43legacy_phy_read(dev, 0x002B) | ||
929 | & 0xC0FF) | 0x0800); | ||
930 | b43legacy_phy_write(dev, 0x0811, | ||
931 | b43legacy_phy_read(dev, 0x0811) | 0x0100); | ||
932 | b43legacy_phy_write(dev, 0x0812, | ||
933 | b43legacy_phy_read(dev, 0x0812) & 0xCFFF); | ||
934 | if (dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_EXTLNA) { | ||
935 | if (phy->rev >= 7) { | ||
936 | b43legacy_phy_write(dev, 0x0811, | ||
937 | b43legacy_phy_read(dev, 0x0811) | ||
938 | | 0x0800); | ||
939 | b43legacy_phy_write(dev, 0x0812, | ||
940 | b43legacy_phy_read(dev, 0x0812) | ||
941 | | 0x8000); | ||
942 | } | ||
943 | } | ||
944 | b43legacy_radio_write16(dev, 0x007A, | ||
945 | b43legacy_radio_read16(dev, 0x007A) | ||
946 | & 0x00F7); | ||
947 | |||
948 | for (i = 0; i < loop1_cnt; i++) { | ||
949 | b43legacy_radio_write16(dev, 0x0043, loop1_cnt); | ||
950 | b43legacy_phy_write(dev, 0x0812, | ||
951 | (b43legacy_phy_read(dev, 0x0812) | ||
952 | & 0xF0FF) | (i << 8)); | ||
953 | b43legacy_phy_write(dev, 0x0015, | ||
954 | (b43legacy_phy_read(dev, 0x0015) | ||
955 | & 0x0FFF) | 0xA000); | ||
956 | b43legacy_phy_write(dev, 0x0015, | ||
957 | (b43legacy_phy_read(dev, 0x0015) | ||
958 | & 0x0FFF) | 0xF000); | ||
959 | udelay(20); | ||
960 | if (b43legacy_phy_read(dev, 0x002D) >= 0x0DFC) | ||
961 | break; | ||
962 | } | ||
963 | loop1_done = i; | ||
964 | loop1_omitted = loop1_cnt - loop1_done; | ||
965 | |||
966 | loop2_done = 0; | ||
967 | if (loop1_done >= 8) { | ||
968 | b43legacy_phy_write(dev, 0x0812, | ||
969 | b43legacy_phy_read(dev, 0x0812) | ||
970 | | 0x0030); | ||
971 | for (i = loop1_done - 8; i < 16; i++) { | ||
972 | b43legacy_phy_write(dev, 0x0812, | ||
973 | (b43legacy_phy_read(dev, 0x0812) | ||
974 | & 0xF0FF) | (i << 8)); | ||
975 | b43legacy_phy_write(dev, 0x0015, | ||
976 | (b43legacy_phy_read(dev, 0x0015) | ||
977 | & 0x0FFF) | 0xA000); | ||
978 | b43legacy_phy_write(dev, 0x0015, | ||
979 | (b43legacy_phy_read(dev, 0x0015) | ||
980 | & 0x0FFF) | 0xF000); | ||
981 | udelay(20); | ||
982 | if (b43legacy_phy_read(dev, 0x002D) >= 0x0DFC) | ||
983 | break; | ||
984 | } | ||
985 | } | ||
986 | |||
987 | if (phy->rev != 1) { | ||
988 | b43legacy_phy_write(dev, 0x0814, backup_phy[4]); | ||
989 | b43legacy_phy_write(dev, 0x0815, backup_phy[5]); | ||
990 | } | ||
991 | b43legacy_phy_write(dev, 0x005A, backup_phy[6]); | ||
992 | b43legacy_phy_write(dev, 0x0059, backup_phy[7]); | ||
993 | b43legacy_phy_write(dev, 0x0058, backup_phy[8]); | ||
994 | b43legacy_phy_write(dev, 0x000A, backup_phy[9]); | ||
995 | b43legacy_phy_write(dev, 0x0003, backup_phy[10]); | ||
996 | b43legacy_phy_write(dev, 0x080F, backup_phy[11]); | ||
997 | b43legacy_phy_write(dev, 0x0810, backup_phy[12]); | ||
998 | b43legacy_phy_write(dev, 0x002B, backup_phy[13]); | ||
999 | b43legacy_phy_write(dev, 0x0015, backup_phy[14]); | ||
1000 | |||
1001 | b43legacy_phy_set_baseband_attenuation(dev, backup_bband); | ||
1002 | |||
1003 | b43legacy_radio_write16(dev, 0x0052, backup_radio[0]); | ||
1004 | b43legacy_radio_write16(dev, 0x0043, backup_radio[1]); | ||
1005 | b43legacy_radio_write16(dev, 0x007A, backup_radio[2]); | ||
1006 | |||
1007 | b43legacy_phy_write(dev, 0x0811, backup_phy[2] | 0x0003); | ||
1008 | udelay(10); | ||
1009 | b43legacy_phy_write(dev, 0x0811, backup_phy[2]); | ||
1010 | b43legacy_phy_write(dev, 0x0812, backup_phy[3]); | ||
1011 | b43legacy_phy_write(dev, 0x0429, backup_phy[0]); | ||
1012 | b43legacy_phy_write(dev, 0x0001, backup_phy[1]); | ||
1013 | |||
1014 | phy->loopback_gain[0] = ((loop1_done * 6) - (loop1_omitted * 4)) - 11; | ||
1015 | phy->loopback_gain[1] = (24 - (3 * loop2_done)) * 2; | ||
1016 | } | ||
1017 | |||
1018 | static void b43legacy_phy_initg(struct b43legacy_wldev *dev) | ||
1019 | { | ||
1020 | struct b43legacy_phy *phy = &dev->phy; | ||
1021 | u16 tmp; | ||
1022 | |||
1023 | if (phy->rev == 1) | ||
1024 | b43legacy_phy_initb5(dev); | ||
1025 | else | ||
1026 | b43legacy_phy_initb6(dev); | ||
1027 | if (phy->rev >= 2 || phy->gmode) | ||
1028 | b43legacy_phy_inita(dev); | ||
1029 | |||
1030 | if (phy->rev >= 2) { | ||
1031 | b43legacy_phy_write(dev, 0x0814, 0x0000); | ||
1032 | b43legacy_phy_write(dev, 0x0815, 0x0000); | ||
1033 | } | ||
1034 | if (phy->rev == 2) { | ||
1035 | b43legacy_phy_write(dev, 0x0811, 0x0000); | ||
1036 | b43legacy_phy_write(dev, 0x0015, 0x00C0); | ||
1037 | } | ||
1038 | if (phy->rev > 5) { | ||
1039 | b43legacy_phy_write(dev, 0x0811, 0x0400); | ||
1040 | b43legacy_phy_write(dev, 0x0015, 0x00C0); | ||
1041 | } | ||
1042 | if (phy->rev >= 2 || phy->gmode) { | ||
1043 | tmp = b43legacy_phy_read(dev, 0x0400) & 0xFF; | ||
1044 | if (tmp == 3 || tmp == 5) { | ||
1045 | b43legacy_phy_write(dev, 0x04C2, 0x1816); | ||
1046 | b43legacy_phy_write(dev, 0x04C3, 0x8006); | ||
1047 | if (tmp == 5) | ||
1048 | b43legacy_phy_write(dev, 0x04CC, | ||
1049 | (b43legacy_phy_read(dev, | ||
1050 | 0x04CC) & 0x00FF) | | ||
1051 | 0x1F00); | ||
1052 | } | ||
1053 | b43legacy_phy_write(dev, 0x047E, 0x0078); | ||
1054 | } | ||
1055 | if (phy->radio_rev == 8) { | ||
1056 | b43legacy_phy_write(dev, 0x0801, b43legacy_phy_read(dev, 0x0801) | ||
1057 | | 0x0080); | ||
1058 | b43legacy_phy_write(dev, 0x043E, b43legacy_phy_read(dev, 0x043E) | ||
1059 | | 0x0004); | ||
1060 | } | ||
1061 | if (phy->rev >= 2 && phy->gmode) | ||
1062 | b43legacy_calc_loopback_gain(dev); | ||
1063 | if (phy->radio_rev != 8) { | ||
1064 | if (phy->initval == 0xFFFF) | ||
1065 | phy->initval = b43legacy_radio_init2050(dev); | ||
1066 | else | ||
1067 | b43legacy_radio_write16(dev, 0x0078, phy->initval); | ||
1068 | } | ||
1069 | if (phy->txctl2 == 0xFFFF) | ||
1070 | b43legacy_phy_lo_g_measure(dev); | ||
1071 | else { | ||
1072 | if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) | ||
1073 | b43legacy_radio_write16(dev, 0x0052, | ||
1074 | (phy->txctl1 << 4) | | ||
1075 | phy->txctl2); | ||
1076 | else | ||
1077 | b43legacy_radio_write16(dev, 0x0052, | ||
1078 | (b43legacy_radio_read16(dev, | ||
1079 | 0x0052) & 0xFFF0) | | ||
1080 | phy->txctl1); | ||
1081 | if (phy->rev >= 6) | ||
1082 | b43legacy_phy_write(dev, 0x0036, | ||
1083 | (b43legacy_phy_read(dev, 0x0036) | ||
1084 | & 0x0FFF) | (phy->txctl2 << 12)); | ||
1085 | if (dev->dev->bus->sprom.r1.boardflags_lo & | ||
1086 | B43legacy_BFL_PACTRL) | ||
1087 | b43legacy_phy_write(dev, 0x002E, 0x8075); | ||
1088 | else | ||
1089 | b43legacy_phy_write(dev, 0x002E, 0x807F); | ||
1090 | if (phy->rev < 2) | ||
1091 | b43legacy_phy_write(dev, 0x002F, 0x0101); | ||
1092 | else | ||
1093 | b43legacy_phy_write(dev, 0x002F, 0x0202); | ||
1094 | } | ||
1095 | if (phy->gmode || phy->rev >= 2) { | ||
1096 | b43legacy_phy_lo_adjust(dev, 0); | ||
1097 | b43legacy_phy_write(dev, 0x080F, 0x8078); | ||
1098 | } | ||
1099 | |||
1100 | if (!(dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_RSSI)) { | ||
1101 | /* The specs state to update the NRSSI LT with | ||
1102 | * the value 0x7FFFFFFF here. I think that is some weird | ||
1103 | * compiler optimization in the original driver. | ||
1104 | * Essentially, what we do here is resetting all NRSSI LT | ||
1105 | * entries to -32 (see the limit_value() in nrssi_hw_update()) | ||
1106 | */ | ||
1107 | b43legacy_nrssi_hw_update(dev, 0xFFFF); | ||
1108 | b43legacy_calc_nrssi_threshold(dev); | ||
1109 | } else if (phy->gmode || phy->rev >= 2) { | ||
1110 | if (phy->nrssi[0] == -1000) { | ||
1111 | B43legacy_WARN_ON(phy->nrssi[1] != -1000); | ||
1112 | b43legacy_calc_nrssi_slope(dev); | ||
1113 | } else { | ||
1114 | B43legacy_WARN_ON(phy->nrssi[1] == -1000); | ||
1115 | b43legacy_calc_nrssi_threshold(dev); | ||
1116 | } | ||
1117 | } | ||
1118 | if (phy->radio_rev == 8) | ||
1119 | b43legacy_phy_write(dev, 0x0805, 0x3230); | ||
1120 | b43legacy_phy_init_pctl(dev); | ||
1121 | if (dev->dev->bus->chip_id == 0x4306 | ||
1122 | && dev->dev->bus->chip_package == 2) { | ||
1123 | b43legacy_phy_write(dev, 0x0429, | ||
1124 | b43legacy_phy_read(dev, 0x0429) & 0xBFFF); | ||
1125 | b43legacy_phy_write(dev, 0x04C3, | ||
1126 | b43legacy_phy_read(dev, 0x04C3) & 0x7FFF); | ||
1127 | } | ||
1128 | } | ||
1129 | |||
1130 | static u16 b43legacy_phy_lo_b_r15_loop(struct b43legacy_wldev *dev) | ||
1131 | { | ||
1132 | int i; | ||
1133 | u16 ret = 0; | ||
1134 | unsigned long flags; | ||
1135 | |||
1136 | local_irq_save(flags); | ||
1137 | for (i = 0; i < 10; i++) { | ||
1138 | b43legacy_phy_write(dev, 0x0015, 0xAFA0); | ||
1139 | udelay(1); | ||
1140 | b43legacy_phy_write(dev, 0x0015, 0xEFA0); | ||
1141 | udelay(10); | ||
1142 | b43legacy_phy_write(dev, 0x0015, 0xFFA0); | ||
1143 | udelay(40); | ||
1144 | ret += b43legacy_phy_read(dev, 0x002C); | ||
1145 | } | ||
1146 | local_irq_restore(flags); | ||
1147 | b43legacy_voluntary_preempt(); | ||
1148 | |||
1149 | return ret; | ||
1150 | } | ||
1151 | |||
1152 | void b43legacy_phy_lo_b_measure(struct b43legacy_wldev *dev) | ||
1153 | { | ||
1154 | struct b43legacy_phy *phy = &dev->phy; | ||
1155 | u16 regstack[12] = { 0 }; | ||
1156 | u16 mls; | ||
1157 | u16 fval; | ||
1158 | int i; | ||
1159 | int j; | ||
1160 | |||
1161 | regstack[0] = b43legacy_phy_read(dev, 0x0015); | ||
1162 | regstack[1] = b43legacy_radio_read16(dev, 0x0052) & 0xFFF0; | ||
1163 | |||
1164 | if (phy->radio_ver == 0x2053) { | ||
1165 | regstack[2] = b43legacy_phy_read(dev, 0x000A); | ||
1166 | regstack[3] = b43legacy_phy_read(dev, 0x002A); | ||
1167 | regstack[4] = b43legacy_phy_read(dev, 0x0035); | ||
1168 | regstack[5] = b43legacy_phy_read(dev, 0x0003); | ||
1169 | regstack[6] = b43legacy_phy_read(dev, 0x0001); | ||
1170 | regstack[7] = b43legacy_phy_read(dev, 0x0030); | ||
1171 | |||
1172 | regstack[8] = b43legacy_radio_read16(dev, 0x0043); | ||
1173 | regstack[9] = b43legacy_radio_read16(dev, 0x007A); | ||
1174 | regstack[10] = b43legacy_read16(dev, 0x03EC); | ||
1175 | regstack[11] = b43legacy_radio_read16(dev, 0x0052) & 0x00F0; | ||
1176 | |||
1177 | b43legacy_phy_write(dev, 0x0030, 0x00FF); | ||
1178 | b43legacy_write16(dev, 0x03EC, 0x3F3F); | ||
1179 | b43legacy_phy_write(dev, 0x0035, regstack[4] & 0xFF7F); | ||
1180 | b43legacy_radio_write16(dev, 0x007A, regstack[9] & 0xFFF0); | ||
1181 | } | ||
1182 | b43legacy_phy_write(dev, 0x0015, 0xB000); | ||
1183 | b43legacy_phy_write(dev, 0x002B, 0x0004); | ||
1184 | |||
1185 | if (phy->radio_ver == 0x2053) { | ||
1186 | b43legacy_phy_write(dev, 0x002B, 0x0203); | ||
1187 | b43legacy_phy_write(dev, 0x002A, 0x08A3); | ||
1188 | } | ||
1189 | |||
1190 | phy->minlowsig[0] = 0xFFFF; | ||
1191 | |||
1192 | for (i = 0; i < 4; i++) { | ||
1193 | b43legacy_radio_write16(dev, 0x0052, regstack[1] | i); | ||
1194 | b43legacy_phy_lo_b_r15_loop(dev); | ||
1195 | } | ||
1196 | for (i = 0; i < 10; i++) { | ||
1197 | b43legacy_radio_write16(dev, 0x0052, regstack[1] | i); | ||
1198 | mls = b43legacy_phy_lo_b_r15_loop(dev) / 10; | ||
1199 | if (mls < phy->minlowsig[0]) { | ||
1200 | phy->minlowsig[0] = mls; | ||
1201 | phy->minlowsigpos[0] = i; | ||
1202 | } | ||
1203 | } | ||
1204 | b43legacy_radio_write16(dev, 0x0052, regstack[1] | ||
1205 | | phy->minlowsigpos[0]); | ||
1206 | |||
1207 | phy->minlowsig[1] = 0xFFFF; | ||
1208 | |||
1209 | for (i = -4; i < 5; i += 2) { | ||
1210 | for (j = -4; j < 5; j += 2) { | ||
1211 | if (j < 0) | ||
1212 | fval = (0x0100 * i) + j + 0x0100; | ||
1213 | else | ||
1214 | fval = (0x0100 * i) + j; | ||
1215 | b43legacy_phy_write(dev, 0x002F, fval); | ||
1216 | mls = b43legacy_phy_lo_b_r15_loop(dev) / 10; | ||
1217 | if (mls < phy->minlowsig[1]) { | ||
1218 | phy->minlowsig[1] = mls; | ||
1219 | phy->minlowsigpos[1] = fval; | ||
1220 | } | ||
1221 | } | ||
1222 | } | ||
1223 | phy->minlowsigpos[1] += 0x0101; | ||
1224 | |||
1225 | b43legacy_phy_write(dev, 0x002F, phy->minlowsigpos[1]); | ||
1226 | if (phy->radio_ver == 0x2053) { | ||
1227 | b43legacy_phy_write(dev, 0x000A, regstack[2]); | ||
1228 | b43legacy_phy_write(dev, 0x002A, regstack[3]); | ||
1229 | b43legacy_phy_write(dev, 0x0035, regstack[4]); | ||
1230 | b43legacy_phy_write(dev, 0x0003, regstack[5]); | ||
1231 | b43legacy_phy_write(dev, 0x0001, regstack[6]); | ||
1232 | b43legacy_phy_write(dev, 0x0030, regstack[7]); | ||
1233 | |||
1234 | b43legacy_radio_write16(dev, 0x0043, regstack[8]); | ||
1235 | b43legacy_radio_write16(dev, 0x007A, regstack[9]); | ||
1236 | |||
1237 | b43legacy_radio_write16(dev, 0x0052, | ||
1238 | (b43legacy_radio_read16(dev, 0x0052) | ||
1239 | & 0x000F) | regstack[11]); | ||
1240 | |||
1241 | b43legacy_write16(dev, 0x03EC, regstack[10]); | ||
1242 | } | ||
1243 | b43legacy_phy_write(dev, 0x0015, regstack[0]); | ||
1244 | } | ||
1245 | |||
1246 | static inline | ||
1247 | u16 b43legacy_phy_lo_g_deviation_subval(struct b43legacy_wldev *dev, | ||
1248 | u16 control) | ||
1249 | { | ||
1250 | struct b43legacy_phy *phy = &dev->phy; | ||
1251 | u16 ret; | ||
1252 | unsigned long flags; | ||
1253 | |||
1254 | local_irq_save(flags); | ||
1255 | if (phy->gmode) { | ||
1256 | b43legacy_phy_write(dev, 0x15, 0xE300); | ||
1257 | control <<= 8; | ||
1258 | b43legacy_phy_write(dev, 0x0812, control | 0x00B0); | ||
1259 | udelay(5); | ||
1260 | b43legacy_phy_write(dev, 0x0812, control | 0x00B2); | ||
1261 | udelay(2); | ||
1262 | b43legacy_phy_write(dev, 0x0812, control | 0x00B3); | ||
1263 | udelay(4); | ||
1264 | b43legacy_phy_write(dev, 0x0015, 0xF300); | ||
1265 | udelay(8); | ||
1266 | } else { | ||
1267 | b43legacy_phy_write(dev, 0x0015, control | 0xEFA0); | ||
1268 | udelay(2); | ||
1269 | b43legacy_phy_write(dev, 0x0015, control | 0xEFE0); | ||
1270 | udelay(4); | ||
1271 | b43legacy_phy_write(dev, 0x0015, control | 0xFFE0); | ||
1272 | udelay(8); | ||
1273 | } | ||
1274 | ret = b43legacy_phy_read(dev, 0x002D); | ||
1275 | local_irq_restore(flags); | ||
1276 | b43legacy_voluntary_preempt(); | ||
1277 | |||
1278 | return ret; | ||
1279 | } | ||
1280 | |||
1281 | static u32 b43legacy_phy_lo_g_singledeviation(struct b43legacy_wldev *dev, | ||
1282 | u16 control) | ||
1283 | { | ||
1284 | int i; | ||
1285 | u32 ret = 0; | ||
1286 | |||
1287 | for (i = 0; i < 8; i++) | ||
1288 | ret += b43legacy_phy_lo_g_deviation_subval(dev, control); | ||
1289 | |||
1290 | return ret; | ||
1291 | } | ||
1292 | |||
1293 | /* Write the LocalOscillator CONTROL */ | ||
1294 | static inline | ||
1295 | void b43legacy_lo_write(struct b43legacy_wldev *dev, | ||
1296 | struct b43legacy_lopair *pair) | ||
1297 | { | ||
1298 | u16 value; | ||
1299 | |||
1300 | value = (u8)(pair->low); | ||
1301 | value |= ((u8)(pair->high)) << 8; | ||
1302 | |||
1303 | #ifdef CONFIG_B43LEGACY_DEBUG | ||
1304 | /* Sanity check. */ | ||
1305 | if (pair->low < -8 || pair->low > 8 || | ||
1306 | pair->high < -8 || pair->high > 8) { | ||
1307 | struct b43legacy_phy *phy = &dev->phy; | ||
1308 | b43legacydbg(dev->wl, | ||
1309 | "WARNING: Writing invalid LOpair " | ||
1310 | "(low: %d, high: %d, index: %lu)\n", | ||
1311 | pair->low, pair->high, | ||
1312 | (unsigned long)(pair - phy->_lo_pairs)); | ||
1313 | dump_stack(); | ||
1314 | } | ||
1315 | #endif | ||
1316 | |||
1317 | b43legacy_phy_write(dev, B43legacy_PHY_G_LO_CONTROL, value); | ||
1318 | } | ||
1319 | |||
1320 | static inline | ||
1321 | struct b43legacy_lopair *b43legacy_find_lopair(struct b43legacy_wldev *dev, | ||
1322 | u16 bbatt, | ||
1323 | u16 rfatt, | ||
1324 | u16 tx) | ||
1325 | { | ||
1326 | static const u8 dict[10] = { 11, 10, 11, 12, 13, 12, 13, 12, 13, 12 }; | ||
1327 | struct b43legacy_phy *phy = &dev->phy; | ||
1328 | |||
1329 | if (bbatt > 6) | ||
1330 | bbatt = 6; | ||
1331 | B43legacy_WARN_ON(rfatt >= 10); | ||
1332 | |||
1333 | if (tx == 3) | ||
1334 | return b43legacy_get_lopair(phy, rfatt, bbatt); | ||
1335 | return b43legacy_get_lopair(phy, dict[rfatt], bbatt); | ||
1336 | } | ||
1337 | |||
1338 | static inline | ||
1339 | struct b43legacy_lopair *b43legacy_current_lopair(struct b43legacy_wldev *dev) | ||
1340 | { | ||
1341 | struct b43legacy_phy *phy = &dev->phy; | ||
1342 | |||
1343 | return b43legacy_find_lopair(dev, phy->bbatt, | ||
1344 | phy->rfatt, phy->txctl1); | ||
1345 | } | ||
1346 | |||
1347 | /* Adjust B/G LO */ | ||
1348 | void b43legacy_phy_lo_adjust(struct b43legacy_wldev *dev, int fixed) | ||
1349 | { | ||
1350 | struct b43legacy_lopair *pair; | ||
1351 | |||
1352 | if (fixed) { | ||
1353 | /* Use fixed values. Only for initialization. */ | ||
1354 | pair = b43legacy_find_lopair(dev, 2, 3, 0); | ||
1355 | } else | ||
1356 | pair = b43legacy_current_lopair(dev); | ||
1357 | b43legacy_lo_write(dev, pair); | ||
1358 | } | ||
1359 | |||
1360 | static void b43legacy_phy_lo_g_measure_txctl2(struct b43legacy_wldev *dev) | ||
1361 | { | ||
1362 | struct b43legacy_phy *phy = &dev->phy; | ||
1363 | u16 txctl2 = 0; | ||
1364 | u16 i; | ||
1365 | u32 smallest; | ||
1366 | u32 tmp; | ||
1367 | |||
1368 | b43legacy_radio_write16(dev, 0x0052, 0x0000); | ||
1369 | udelay(10); | ||
1370 | smallest = b43legacy_phy_lo_g_singledeviation(dev, 0); | ||
1371 | for (i = 0; i < 16; i++) { | ||
1372 | b43legacy_radio_write16(dev, 0x0052, i); | ||
1373 | udelay(10); | ||
1374 | tmp = b43legacy_phy_lo_g_singledeviation(dev, 0); | ||
1375 | if (tmp < smallest) { | ||
1376 | smallest = tmp; | ||
1377 | txctl2 = i; | ||
1378 | } | ||
1379 | } | ||
1380 | phy->txctl2 = txctl2; | ||
1381 | } | ||
1382 | |||
1383 | static | ||
1384 | void b43legacy_phy_lo_g_state(struct b43legacy_wldev *dev, | ||
1385 | const struct b43legacy_lopair *in_pair, | ||
1386 | struct b43legacy_lopair *out_pair, | ||
1387 | u16 r27) | ||
1388 | { | ||
1389 | static const struct b43legacy_lopair transitions[8] = { | ||
1390 | { .high = 1, .low = 1, }, | ||
1391 | { .high = 1, .low = 0, }, | ||
1392 | { .high = 1, .low = -1, }, | ||
1393 | { .high = 0, .low = -1, }, | ||
1394 | { .high = -1, .low = -1, }, | ||
1395 | { .high = -1, .low = 0, }, | ||
1396 | { .high = -1, .low = 1, }, | ||
1397 | { .high = 0, .low = 1, }, | ||
1398 | }; | ||
1399 | struct b43legacy_lopair lowest_transition = { | ||
1400 | .high = in_pair->high, | ||
1401 | .low = in_pair->low, | ||
1402 | }; | ||
1403 | struct b43legacy_lopair tmp_pair; | ||
1404 | struct b43legacy_lopair transition; | ||
1405 | int i = 12; | ||
1406 | int state = 0; | ||
1407 | int found_lower; | ||
1408 | int j; | ||
1409 | int begin; | ||
1410 | int end; | ||
1411 | u32 lowest_deviation; | ||
1412 | u32 tmp; | ||
1413 | |||
1414 | /* Note that in_pair and out_pair can point to the same pair. | ||
1415 | * Be careful. */ | ||
1416 | |||
1417 | b43legacy_lo_write(dev, &lowest_transition); | ||
1418 | lowest_deviation = b43legacy_phy_lo_g_singledeviation(dev, r27); | ||
1419 | do { | ||
1420 | found_lower = 0; | ||
1421 | B43legacy_WARN_ON(!(state >= 0 && state <= 8)); | ||
1422 | if (state == 0) { | ||
1423 | begin = 1; | ||
1424 | end = 8; | ||
1425 | } else if (state % 2 == 0) { | ||
1426 | begin = state - 1; | ||
1427 | end = state + 1; | ||
1428 | } else { | ||
1429 | begin = state - 2; | ||
1430 | end = state + 2; | ||
1431 | } | ||
1432 | if (begin < 1) | ||
1433 | begin += 8; | ||
1434 | if (end > 8) | ||
1435 | end -= 8; | ||
1436 | |||
1437 | j = begin; | ||
1438 | tmp_pair.high = lowest_transition.high; | ||
1439 | tmp_pair.low = lowest_transition.low; | ||
1440 | while (1) { | ||
1441 | B43legacy_WARN_ON(!(j >= 1 && j <= 8)); | ||
1442 | transition.high = tmp_pair.high + | ||
1443 | transitions[j - 1].high; | ||
1444 | transition.low = tmp_pair.low + transitions[j - 1].low; | ||
1445 | if ((abs(transition.low) < 9) | ||
1446 | && (abs(transition.high) < 9)) { | ||
1447 | b43legacy_lo_write(dev, &transition); | ||
1448 | tmp = b43legacy_phy_lo_g_singledeviation(dev, | ||
1449 | r27); | ||
1450 | if (tmp < lowest_deviation) { | ||
1451 | lowest_deviation = tmp; | ||
1452 | state = j; | ||
1453 | found_lower = 1; | ||
1454 | |||
1455 | lowest_transition.high = | ||
1456 | transition.high; | ||
1457 | lowest_transition.low = transition.low; | ||
1458 | } | ||
1459 | } | ||
1460 | if (j == end) | ||
1461 | break; | ||
1462 | if (j == 8) | ||
1463 | j = 1; | ||
1464 | else | ||
1465 | j++; | ||
1466 | } | ||
1467 | } while (i-- && found_lower); | ||
1468 | |||
1469 | out_pair->high = lowest_transition.high; | ||
1470 | out_pair->low = lowest_transition.low; | ||
1471 | } | ||
1472 | |||
1473 | /* Set the baseband attenuation value on chip. */ | ||
1474 | void b43legacy_phy_set_baseband_attenuation(struct b43legacy_wldev *dev, | ||
1475 | u16 bbatt) | ||
1476 | { | ||
1477 | struct b43legacy_phy *phy = &dev->phy; | ||
1478 | u16 value; | ||
1479 | |||
1480 | if (phy->analog == 0) { | ||
1481 | value = (b43legacy_read16(dev, 0x03E6) & 0xFFF0); | ||
1482 | value |= (bbatt & 0x000F); | ||
1483 | b43legacy_write16(dev, 0x03E6, value); | ||
1484 | return; | ||
1485 | } | ||
1486 | |||
1487 | if (phy->analog > 1) { | ||
1488 | value = b43legacy_phy_read(dev, 0x0060) & 0xFFC3; | ||
1489 | value |= (bbatt << 2) & 0x003C; | ||
1490 | } else { | ||
1491 | value = b43legacy_phy_read(dev, 0x0060) & 0xFF87; | ||
1492 | value |= (bbatt << 3) & 0x0078; | ||
1493 | } | ||
1494 | b43legacy_phy_write(dev, 0x0060, value); | ||
1495 | } | ||
1496 | |||
1497 | /* http://bcm-specs.sipsolutions.net/LocalOscillator/Measure */ | ||
1498 | void b43legacy_phy_lo_g_measure(struct b43legacy_wldev *dev) | ||
1499 | { | ||
1500 | static const u8 pairorder[10] = { 3, 1, 5, 7, 9, 2, 0, 4, 6, 8 }; | ||
1501 | const int is_initializing = (b43legacy_status(dev) | ||
1502 | < B43legacy_STAT_STARTED); | ||
1503 | struct b43legacy_phy *phy = &dev->phy; | ||
1504 | u16 h; | ||
1505 | u16 i; | ||
1506 | u16 oldi = 0; | ||
1507 | u16 j; | ||
1508 | struct b43legacy_lopair control; | ||
1509 | struct b43legacy_lopair *tmp_control; | ||
1510 | u16 tmp; | ||
1511 | u16 regstack[16] = { 0 }; | ||
1512 | u8 oldchannel; | ||
1513 | |||
1514 | /* XXX: What are these? */ | ||
1515 | u8 r27 = 0; | ||
1516 | u16 r31; | ||
1517 | |||
1518 | oldchannel = phy->channel; | ||
1519 | /* Setup */ | ||
1520 | if (phy->gmode) { | ||
1521 | regstack[0] = b43legacy_phy_read(dev, B43legacy_PHY_G_CRS); | ||
1522 | regstack[1] = b43legacy_phy_read(dev, 0x0802); | ||
1523 | b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, regstack[0] | ||
1524 | & 0x7FFF); | ||
1525 | b43legacy_phy_write(dev, 0x0802, regstack[1] & 0xFFFC); | ||
1526 | } | ||
1527 | regstack[3] = b43legacy_read16(dev, 0x03E2); | ||
1528 | b43legacy_write16(dev, 0x03E2, regstack[3] | 0x8000); | ||
1529 | regstack[4] = b43legacy_read16(dev, B43legacy_MMIO_CHANNEL_EXT); | ||
1530 | regstack[5] = b43legacy_phy_read(dev, 0x15); | ||
1531 | regstack[6] = b43legacy_phy_read(dev, 0x2A); | ||
1532 | regstack[7] = b43legacy_phy_read(dev, 0x35); | ||
1533 | regstack[8] = b43legacy_phy_read(dev, 0x60); | ||
1534 | regstack[9] = b43legacy_radio_read16(dev, 0x43); | ||
1535 | regstack[10] = b43legacy_radio_read16(dev, 0x7A); | ||
1536 | regstack[11] = b43legacy_radio_read16(dev, 0x52); | ||
1537 | if (phy->gmode) { | ||
1538 | regstack[12] = b43legacy_phy_read(dev, 0x0811); | ||
1539 | regstack[13] = b43legacy_phy_read(dev, 0x0812); | ||
1540 | regstack[14] = b43legacy_phy_read(dev, 0x0814); | ||
1541 | regstack[15] = b43legacy_phy_read(dev, 0x0815); | ||
1542 | } | ||
1543 | b43legacy_radio_selectchannel(dev, 6, 0); | ||
1544 | if (phy->gmode) { | ||
1545 | b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, regstack[0] | ||
1546 | & 0x7FFF); | ||
1547 | b43legacy_phy_write(dev, 0x0802, regstack[1] & 0xFFFC); | ||
1548 | b43legacy_dummy_transmission(dev); | ||
1549 | } | ||
1550 | b43legacy_radio_write16(dev, 0x0043, 0x0006); | ||
1551 | |||
1552 | b43legacy_phy_set_baseband_attenuation(dev, 2); | ||
1553 | |||
1554 | b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, 0x0000); | ||
1555 | b43legacy_phy_write(dev, 0x002E, 0x007F); | ||
1556 | b43legacy_phy_write(dev, 0x080F, 0x0078); | ||
1557 | b43legacy_phy_write(dev, 0x0035, regstack[7] & ~(1 << 7)); | ||
1558 | b43legacy_radio_write16(dev, 0x007A, regstack[10] & 0xFFF0); | ||
1559 | b43legacy_phy_write(dev, 0x002B, 0x0203); | ||
1560 | b43legacy_phy_write(dev, 0x002A, 0x08A3); | ||
1561 | if (phy->gmode) { | ||
1562 | b43legacy_phy_write(dev, 0x0814, regstack[14] | 0x0003); | ||
1563 | b43legacy_phy_write(dev, 0x0815, regstack[15] & 0xFFFC); | ||
1564 | b43legacy_phy_write(dev, 0x0811, 0x01B3); | ||
1565 | b43legacy_phy_write(dev, 0x0812, 0x00B2); | ||
1566 | } | ||
1567 | if (is_initializing) | ||
1568 | b43legacy_phy_lo_g_measure_txctl2(dev); | ||
1569 | b43legacy_phy_write(dev, 0x080F, 0x8078); | ||
1570 | |||
1571 | /* Measure */ | ||
1572 | control.low = 0; | ||
1573 | control.high = 0; | ||
1574 | for (h = 0; h < 10; h++) { | ||
1575 | /* Loop over each possible RadioAttenuation (0-9) */ | ||
1576 | i = pairorder[h]; | ||
1577 | if (is_initializing) { | ||
1578 | if (i == 3) { | ||
1579 | control.low = 0; | ||
1580 | control.high = 0; | ||
1581 | } else if (((i % 2 == 1) && (oldi % 2 == 1)) || | ||
1582 | ((i % 2 == 0) && (oldi % 2 == 0))) { | ||
1583 | tmp_control = b43legacy_get_lopair(phy, oldi, | ||
1584 | 0); | ||
1585 | memcpy(&control, tmp_control, sizeof(control)); | ||
1586 | } else { | ||
1587 | tmp_control = b43legacy_get_lopair(phy, 3, 0); | ||
1588 | memcpy(&control, tmp_control, sizeof(control)); | ||
1589 | } | ||
1590 | } | ||
1591 | /* Loop over each possible BasebandAttenuation/2 */ | ||
1592 | for (j = 0; j < 4; j++) { | ||
1593 | if (is_initializing) { | ||
1594 | tmp = i * 2 + j; | ||
1595 | r27 = 0; | ||
1596 | r31 = 0; | ||
1597 | if (tmp > 14) { | ||
1598 | r31 = 1; | ||
1599 | if (tmp > 17) | ||
1600 | r27 = 1; | ||
1601 | if (tmp > 19) | ||
1602 | r27 = 2; | ||
1603 | } | ||
1604 | } else { | ||
1605 | tmp_control = b43legacy_get_lopair(phy, i, | ||
1606 | j * 2); | ||
1607 | if (!tmp_control->used) | ||
1608 | continue; | ||
1609 | memcpy(&control, tmp_control, sizeof(control)); | ||
1610 | r27 = 3; | ||
1611 | r31 = 0; | ||
1612 | } | ||
1613 | b43legacy_radio_write16(dev, 0x43, i); | ||
1614 | b43legacy_radio_write16(dev, 0x52, phy->txctl2); | ||
1615 | udelay(10); | ||
1616 | b43legacy_voluntary_preempt(); | ||
1617 | |||
1618 | b43legacy_phy_set_baseband_attenuation(dev, j * 2); | ||
1619 | |||
1620 | tmp = (regstack[10] & 0xFFF0); | ||
1621 | if (r31) | ||
1622 | tmp |= 0x0008; | ||
1623 | b43legacy_radio_write16(dev, 0x007A, tmp); | ||
1624 | |||
1625 | tmp_control = b43legacy_get_lopair(phy, i, j * 2); | ||
1626 | b43legacy_phy_lo_g_state(dev, &control, tmp_control, | ||
1627 | r27); | ||
1628 | } | ||
1629 | oldi = i; | ||
1630 | } | ||
1631 | /* Loop over each possible RadioAttenuation (10-13) */ | ||
1632 | for (i = 10; i < 14; i++) { | ||
1633 | /* Loop over each possible BasebandAttenuation/2 */ | ||
1634 | for (j = 0; j < 4; j++) { | ||
1635 | if (is_initializing) { | ||
1636 | tmp_control = b43legacy_get_lopair(phy, i - 9, | ||
1637 | j * 2); | ||
1638 | memcpy(&control, tmp_control, sizeof(control)); | ||
1639 | /* FIXME: The next line is wrong, as the | ||
1640 | * following if statement can never trigger. */ | ||
1641 | tmp = (i - 9) * 2 + j - 5; | ||
1642 | r27 = 0; | ||
1643 | r31 = 0; | ||
1644 | if (tmp > 14) { | ||
1645 | r31 = 1; | ||
1646 | if (tmp > 17) | ||
1647 | r27 = 1; | ||
1648 | if (tmp > 19) | ||
1649 | r27 = 2; | ||
1650 | } | ||
1651 | } else { | ||
1652 | tmp_control = b43legacy_get_lopair(phy, i - 9, | ||
1653 | j * 2); | ||
1654 | if (!tmp_control->used) | ||
1655 | continue; | ||
1656 | memcpy(&control, tmp_control, sizeof(control)); | ||
1657 | r27 = 3; | ||
1658 | r31 = 0; | ||
1659 | } | ||
1660 | b43legacy_radio_write16(dev, 0x43, i - 9); | ||
1661 | /* FIXME: shouldn't txctl1 be zero in the next line | ||
1662 | * and 3 in the loop above? */ | ||
1663 | b43legacy_radio_write16(dev, 0x52, | ||
1664 | phy->txctl2 | ||
1665 | | (3/*txctl1*/ << 4)); | ||
1666 | udelay(10); | ||
1667 | b43legacy_voluntary_preempt(); | ||
1668 | |||
1669 | b43legacy_phy_set_baseband_attenuation(dev, j * 2); | ||
1670 | |||
1671 | tmp = (regstack[10] & 0xFFF0); | ||
1672 | if (r31) | ||
1673 | tmp |= 0x0008; | ||
1674 | b43legacy_radio_write16(dev, 0x7A, tmp); | ||
1675 | |||
1676 | tmp_control = b43legacy_get_lopair(phy, i, j * 2); | ||
1677 | b43legacy_phy_lo_g_state(dev, &control, tmp_control, | ||
1678 | r27); | ||
1679 | } | ||
1680 | } | ||
1681 | |||
1682 | /* Restoration */ | ||
1683 | if (phy->gmode) { | ||
1684 | b43legacy_phy_write(dev, 0x0015, 0xE300); | ||
1685 | b43legacy_phy_write(dev, 0x0812, (r27 << 8) | 0xA0); | ||
1686 | udelay(5); | ||
1687 | b43legacy_phy_write(dev, 0x0812, (r27 << 8) | 0xA2); | ||
1688 | udelay(2); | ||
1689 | b43legacy_phy_write(dev, 0x0812, (r27 << 8) | 0xA3); | ||
1690 | b43legacy_voluntary_preempt(); | ||
1691 | } else | ||
1692 | b43legacy_phy_write(dev, 0x0015, r27 | 0xEFA0); | ||
1693 | b43legacy_phy_lo_adjust(dev, is_initializing); | ||
1694 | b43legacy_phy_write(dev, 0x002E, 0x807F); | ||
1695 | if (phy->gmode) | ||
1696 | b43legacy_phy_write(dev, 0x002F, 0x0202); | ||
1697 | else | ||
1698 | b43legacy_phy_write(dev, 0x002F, 0x0101); | ||
1699 | b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, regstack[4]); | ||
1700 | b43legacy_phy_write(dev, 0x0015, regstack[5]); | ||
1701 | b43legacy_phy_write(dev, 0x002A, regstack[6]); | ||
1702 | b43legacy_phy_write(dev, 0x0035, regstack[7]); | ||
1703 | b43legacy_phy_write(dev, 0x0060, regstack[8]); | ||
1704 | b43legacy_radio_write16(dev, 0x0043, regstack[9]); | ||
1705 | b43legacy_radio_write16(dev, 0x007A, regstack[10]); | ||
1706 | regstack[11] &= 0x00F0; | ||
1707 | regstack[11] |= (b43legacy_radio_read16(dev, 0x52) & 0x000F); | ||
1708 | b43legacy_radio_write16(dev, 0x52, regstack[11]); | ||
1709 | b43legacy_write16(dev, 0x03E2, regstack[3]); | ||
1710 | if (phy->gmode) { | ||
1711 | b43legacy_phy_write(dev, 0x0811, regstack[12]); | ||
1712 | b43legacy_phy_write(dev, 0x0812, regstack[13]); | ||
1713 | b43legacy_phy_write(dev, 0x0814, regstack[14]); | ||
1714 | b43legacy_phy_write(dev, 0x0815, regstack[15]); | ||
1715 | b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, regstack[0]); | ||
1716 | b43legacy_phy_write(dev, 0x0802, regstack[1]); | ||
1717 | } | ||
1718 | b43legacy_radio_selectchannel(dev, oldchannel, 1); | ||
1719 | |||
1720 | #ifdef CONFIG_B43LEGACY_DEBUG | ||
1721 | { | ||
1722 | /* Sanity check for all lopairs. */ | ||
1723 | for (i = 0; i < B43legacy_LO_COUNT; i++) { | ||
1724 | tmp_control = phy->_lo_pairs + i; | ||
1725 | if (tmp_control->low < -8 || tmp_control->low > 8 || | ||
1726 | tmp_control->high < -8 || tmp_control->high > 8) | ||
1727 | b43legacywarn(dev->wl, | ||
1728 | "WARNING: Invalid LOpair (low: %d, high:" | ||
1729 | " %d, index: %d)\n", | ||
1730 | tmp_control->low, tmp_control->high, i); | ||
1731 | } | ||
1732 | } | ||
1733 | #endif /* CONFIG_B43LEGACY_DEBUG */ | ||
1734 | } | ||
1735 | |||
1736 | static | ||
1737 | void b43legacy_phy_lo_mark_current_used(struct b43legacy_wldev *dev) | ||
1738 | { | ||
1739 | struct b43legacy_lopair *pair; | ||
1740 | |||
1741 | pair = b43legacy_current_lopair(dev); | ||
1742 | pair->used = 1; | ||
1743 | } | ||
1744 | |||
1745 | void b43legacy_phy_lo_mark_all_unused(struct b43legacy_wldev *dev) | ||
1746 | { | ||
1747 | struct b43legacy_phy *phy = &dev->phy; | ||
1748 | struct b43legacy_lopair *pair; | ||
1749 | int i; | ||
1750 | |||
1751 | for (i = 0; i < B43legacy_LO_COUNT; i++) { | ||
1752 | pair = phy->_lo_pairs + i; | ||
1753 | pair->used = 0; | ||
1754 | } | ||
1755 | } | ||
1756 | |||
1757 | /* http://bcm-specs.sipsolutions.net/EstimatePowerOut | ||
1758 | * This function converts a TSSI value to dBm in Q5.2 | ||
1759 | */ | ||
1760 | static s8 b43legacy_phy_estimate_power_out(struct b43legacy_wldev *dev, s8 tssi) | ||
1761 | { | ||
1762 | struct b43legacy_phy *phy = &dev->phy; | ||
1763 | s8 dbm = 0; | ||
1764 | s32 tmp; | ||
1765 | |||
1766 | tmp = phy->idle_tssi; | ||
1767 | tmp += tssi; | ||
1768 | tmp -= phy->savedpctlreg; | ||
1769 | |||
1770 | switch (phy->type) { | ||
1771 | case B43legacy_PHYTYPE_B: | ||
1772 | case B43legacy_PHYTYPE_G: | ||
1773 | tmp = limit_value(tmp, 0x00, 0x3F); | ||
1774 | dbm = phy->tssi2dbm[tmp]; | ||
1775 | break; | ||
1776 | default: | ||
1777 | B43legacy_BUG_ON(1); | ||
1778 | } | ||
1779 | |||
1780 | return dbm; | ||
1781 | } | ||
1782 | |||
1783 | /* http://bcm-specs.sipsolutions.net/RecalculateTransmissionPower */ | ||
1784 | void b43legacy_phy_xmitpower(struct b43legacy_wldev *dev) | ||
1785 | { | ||
1786 | struct b43legacy_phy *phy = &dev->phy; | ||
1787 | u16 tmp; | ||
1788 | u16 txpower; | ||
1789 | s8 v0; | ||
1790 | s8 v1; | ||
1791 | s8 v2; | ||
1792 | s8 v3; | ||
1793 | s8 average; | ||
1794 | int max_pwr; | ||
1795 | s16 desired_pwr; | ||
1796 | s16 estimated_pwr; | ||
1797 | s16 pwr_adjust; | ||
1798 | s16 radio_att_delta; | ||
1799 | s16 baseband_att_delta; | ||
1800 | s16 radio_attenuation; | ||
1801 | s16 baseband_attenuation; | ||
1802 | unsigned long phylock_flags; | ||
1803 | |||
1804 | if (phy->savedpctlreg == 0xFFFF) | ||
1805 | return; | ||
1806 | if ((dev->dev->bus->boardinfo.type == 0x0416) && | ||
1807 | is_bcm_board_vendor(dev)) | ||
1808 | return; | ||
1809 | #ifdef CONFIG_B43LEGACY_DEBUG | ||
1810 | if (phy->manual_txpower_control) | ||
1811 | return; | ||
1812 | #endif | ||
1813 | |||
1814 | B43legacy_BUG_ON(!(phy->type == B43legacy_PHYTYPE_B || | ||
1815 | phy->type == B43legacy_PHYTYPE_G)); | ||
1816 | tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x0058); | ||
1817 | v0 = (s8)(tmp & 0x00FF); | ||
1818 | v1 = (s8)((tmp & 0xFF00) >> 8); | ||
1819 | tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x005A); | ||
1820 | v2 = (s8)(tmp & 0x00FF); | ||
1821 | v3 = (s8)((tmp & 0xFF00) >> 8); | ||
1822 | tmp = 0; | ||
1823 | |||
1824 | if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F || v3 == 0x7F) { | ||
1825 | tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, | ||
1826 | 0x0070); | ||
1827 | v0 = (s8)(tmp & 0x00FF); | ||
1828 | v1 = (s8)((tmp & 0xFF00) >> 8); | ||
1829 | tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, | ||
1830 | 0x0072); | ||
1831 | v2 = (s8)(tmp & 0x00FF); | ||
1832 | v3 = (s8)((tmp & 0xFF00) >> 8); | ||
1833 | if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F || v3 == 0x7F) | ||
1834 | return; | ||
1835 | v0 = (v0 + 0x20) & 0x3F; | ||
1836 | v1 = (v1 + 0x20) & 0x3F; | ||
1837 | v2 = (v2 + 0x20) & 0x3F; | ||
1838 | v3 = (v3 + 0x20) & 0x3F; | ||
1839 | tmp = 1; | ||
1840 | } | ||
1841 | b43legacy_radio_clear_tssi(dev); | ||
1842 | |||
1843 | average = (v0 + v1 + v2 + v3 + 2) / 4; | ||
1844 | |||
1845 | if (tmp && (b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x005E) | ||
1846 | & 0x8)) | ||
1847 | average -= 13; | ||
1848 | |||
1849 | estimated_pwr = b43legacy_phy_estimate_power_out(dev, average); | ||
1850 | |||
1851 | max_pwr = dev->dev->bus->sprom.r1.maxpwr_bg; | ||
1852 | |||
1853 | if ((dev->dev->bus->sprom.r1.boardflags_lo | ||
1854 | & B43legacy_BFL_PACTRL) && | ||
1855 | (phy->type == B43legacy_PHYTYPE_G)) | ||
1856 | max_pwr -= 0x3; | ||
1857 | if (unlikely(max_pwr <= 0)) { | ||
1858 | b43legacywarn(dev->wl, "Invalid max-TX-power value in SPROM." | ||
1859 | "\n"); | ||
1860 | max_pwr = 74; /* fake it */ | ||
1861 | dev->dev->bus->sprom.r1.maxpwr_bg = max_pwr; | ||
1862 | } | ||
1863 | |||
1864 | /* Use regulatory information to get the maximum power. | ||
1865 | * In the absence of such data from mac80211, we will use 20 dBm, which | ||
1866 | * is the value for the EU, US, Canada, and most of the world. | ||
1867 | * The regulatory maximum is reduced by the antenna gain (from sprom) | ||
1868 | * and 1.5 dBm (a safety factor??). The result is in Q5.2 format | ||
1869 | * which accounts for the factor of 4 */ | ||
1870 | #define REG_MAX_PWR 20 | ||
1871 | max_pwr = min(REG_MAX_PWR * 4 - dev->dev->bus->sprom.r1.antenna_gain_bg | ||
1872 | - 0x6, max_pwr); | ||
1873 | |||
1874 | /* find the desired power in Q5.2 - power_level is in dBm | ||
1875 | * and limit it - max_pwr is already in Q5.2 */ | ||
1876 | desired_pwr = limit_value(phy->power_level << 2, 0, max_pwr); | ||
1877 | if (b43legacy_debug(dev, B43legacy_DBG_XMITPOWER)) | ||
1878 | b43legacydbg(dev->wl, "Current TX power output: " Q52_FMT | ||
1879 | " dBm, Desired TX power output: " Q52_FMT | ||
1880 | " dBm\n", Q52_ARG(estimated_pwr), | ||
1881 | Q52_ARG(desired_pwr)); | ||
1882 | /* Check if we need to adjust the current power. The factor of 2 is | ||
1883 | * for damping */ | ||
1884 | pwr_adjust = (desired_pwr - estimated_pwr) / 2; | ||
1885 | /* RF attenuation delta | ||
1886 | * The minus sign is because lower attenuation => more power */ | ||
1887 | radio_att_delta = -(pwr_adjust + 7) >> 3; | ||
1888 | /* Baseband attenuation delta */ | ||
1889 | baseband_att_delta = -(pwr_adjust >> 1) - (4 * radio_att_delta); | ||
1890 | /* Do we need to adjust anything? */ | ||
1891 | if ((radio_att_delta == 0) && (baseband_att_delta == 0)) { | ||
1892 | b43legacy_phy_lo_mark_current_used(dev); | ||
1893 | return; | ||
1894 | } | ||
1895 | |||
1896 | /* Calculate the new attenuation values. */ | ||
1897 | baseband_attenuation = phy->bbatt; | ||
1898 | baseband_attenuation += baseband_att_delta; | ||
1899 | radio_attenuation = phy->rfatt; | ||
1900 | radio_attenuation += radio_att_delta; | ||
1901 | |||
1902 | /* Get baseband and radio attenuation values into permitted ranges. | ||
1903 | * baseband 0-11, radio 0-9. | ||
1904 | * Radio attenuation affects power level 4 times as much as baseband. | ||
1905 | */ | ||
1906 | if (radio_attenuation < 0) { | ||
1907 | baseband_attenuation -= (4 * -radio_attenuation); | ||
1908 | radio_attenuation = 0; | ||
1909 | } else if (radio_attenuation > 9) { | ||
1910 | baseband_attenuation += (4 * (radio_attenuation - 9)); | ||
1911 | radio_attenuation = 9; | ||
1912 | } else { | ||
1913 | while (baseband_attenuation < 0 && radio_attenuation > 0) { | ||
1914 | baseband_attenuation += 4; | ||
1915 | radio_attenuation--; | ||
1916 | } | ||
1917 | while (baseband_attenuation > 11 && radio_attenuation < 9) { | ||
1918 | baseband_attenuation -= 4; | ||
1919 | radio_attenuation++; | ||
1920 | } | ||
1921 | } | ||
1922 | baseband_attenuation = limit_value(baseband_attenuation, 0, 11); | ||
1923 | |||
1924 | txpower = phy->txctl1; | ||
1925 | if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 2)) { | ||
1926 | if (radio_attenuation <= 1) { | ||
1927 | if (txpower == 0) { | ||
1928 | txpower = 3; | ||
1929 | radio_attenuation += 2; | ||
1930 | baseband_attenuation += 2; | ||
1931 | } else if (dev->dev->bus->sprom.r1.boardflags_lo | ||
1932 | & B43legacy_BFL_PACTRL) { | ||
1933 | baseband_attenuation += 4 * | ||
1934 | (radio_attenuation - 2); | ||
1935 | radio_attenuation = 2; | ||
1936 | } | ||
1937 | } else if (radio_attenuation > 4 && txpower != 0) { | ||
1938 | txpower = 0; | ||
1939 | if (baseband_attenuation < 3) { | ||
1940 | radio_attenuation -= 3; | ||
1941 | baseband_attenuation += 2; | ||
1942 | } else { | ||
1943 | radio_attenuation -= 2; | ||
1944 | baseband_attenuation -= 2; | ||
1945 | } | ||
1946 | } | ||
1947 | } | ||
1948 | /* Save the control values */ | ||
1949 | phy->txctl1 = txpower; | ||
1950 | baseband_attenuation = limit_value(baseband_attenuation, 0, 11); | ||
1951 | radio_attenuation = limit_value(radio_attenuation, 0, 9); | ||
1952 | phy->rfatt = radio_attenuation; | ||
1953 | phy->bbatt = baseband_attenuation; | ||
1954 | |||
1955 | /* Adjust the hardware */ | ||
1956 | b43legacy_phy_lock(dev, phylock_flags); | ||
1957 | b43legacy_radio_lock(dev); | ||
1958 | b43legacy_radio_set_txpower_bg(dev, baseband_attenuation, | ||
1959 | radio_attenuation, txpower); | ||
1960 | b43legacy_phy_lo_mark_current_used(dev); | ||
1961 | b43legacy_radio_unlock(dev); | ||
1962 | b43legacy_phy_unlock(dev, phylock_flags); | ||
1963 | } | ||
1964 | |||
1965 | static inline | ||
1966 | s32 b43legacy_tssi2dbm_ad(s32 num, s32 den) | ||
1967 | { | ||
1968 | if (num < 0) | ||
1969 | return num/den; | ||
1970 | else | ||
1971 | return (num+den/2)/den; | ||
1972 | } | ||
1973 | |||
1974 | static inline | ||
1975 | s8 b43legacy_tssi2dbm_entry(s8 entry [], u8 index, s16 pab0, s16 pab1, s16 pab2) | ||
1976 | { | ||
1977 | s32 m1; | ||
1978 | s32 m2; | ||
1979 | s32 f = 256; | ||
1980 | s32 q; | ||
1981 | s32 delta; | ||
1982 | s8 i = 0; | ||
1983 | |||
1984 | m1 = b43legacy_tssi2dbm_ad(16 * pab0 + index * pab1, 32); | ||
1985 | m2 = max(b43legacy_tssi2dbm_ad(32768 + index * pab2, 256), 1); | ||
1986 | do { | ||
1987 | if (i > 15) | ||
1988 | return -EINVAL; | ||
1989 | q = b43legacy_tssi2dbm_ad(f * 4096 - | ||
1990 | b43legacy_tssi2dbm_ad(m2 * f, 16) * | ||
1991 | f, 2048); | ||
1992 | delta = abs(q - f); | ||
1993 | f = q; | ||
1994 | i++; | ||
1995 | } while (delta >= 2); | ||
1996 | entry[index] = limit_value(b43legacy_tssi2dbm_ad(m1 * f, 8192), | ||
1997 | -127, 128); | ||
1998 | return 0; | ||
1999 | } | ||
2000 | |||
2001 | /* http://bcm-specs.sipsolutions.net/TSSI_to_DBM_Table */ | ||
2002 | int b43legacy_phy_init_tssi2dbm_table(struct b43legacy_wldev *dev) | ||
2003 | { | ||
2004 | struct b43legacy_phy *phy = &dev->phy; | ||
2005 | s16 pab0; | ||
2006 | s16 pab1; | ||
2007 | s16 pab2; | ||
2008 | u8 idx; | ||
2009 | s8 *dyn_tssi2dbm; | ||
2010 | |||
2011 | B43legacy_WARN_ON(!(phy->type == B43legacy_PHYTYPE_B || | ||
2012 | phy->type == B43legacy_PHYTYPE_G)); | ||
2013 | pab0 = (s16)(dev->dev->bus->sprom.r1.pa0b0); | ||
2014 | pab1 = (s16)(dev->dev->bus->sprom.r1.pa0b1); | ||
2015 | pab2 = (s16)(dev->dev->bus->sprom.r1.pa0b2); | ||
2016 | |||
2017 | if ((dev->dev->bus->chip_id == 0x4301) && (phy->radio_ver != 0x2050)) { | ||
2018 | phy->idle_tssi = 0x34; | ||
2019 | phy->tssi2dbm = b43legacy_tssi2dbm_b_table; | ||
2020 | return 0; | ||
2021 | } | ||
2022 | |||
2023 | if (pab0 != 0 && pab1 != 0 && pab2 != 0 && | ||
2024 | pab0 != -1 && pab1 != -1 && pab2 != -1) { | ||
2025 | /* The pabX values are set in SPROM. Use them. */ | ||
2026 | if ((s8)dev->dev->bus->sprom.r1.itssi_bg != 0 && | ||
2027 | (s8)dev->dev->bus->sprom.r1.itssi_bg != -1) | ||
2028 | phy->idle_tssi = (s8)(dev->dev->bus->sprom.r1.itssi_bg); | ||
2029 | else | ||
2030 | phy->idle_tssi = 62; | ||
2031 | dyn_tssi2dbm = kmalloc(64, GFP_KERNEL); | ||
2032 | if (dyn_tssi2dbm == NULL) { | ||
2033 | b43legacyerr(dev->wl, "Could not allocate memory" | ||
2034 | "for tssi2dbm table\n"); | ||
2035 | return -ENOMEM; | ||
2036 | } | ||
2037 | for (idx = 0; idx < 64; idx++) | ||
2038 | if (b43legacy_tssi2dbm_entry(dyn_tssi2dbm, idx, pab0, | ||
2039 | pab1, pab2)) { | ||
2040 | phy->tssi2dbm = NULL; | ||
2041 | b43legacyerr(dev->wl, "Could not generate " | ||
2042 | "tssi2dBm table\n"); | ||
2043 | kfree(dyn_tssi2dbm); | ||
2044 | return -ENODEV; | ||
2045 | } | ||
2046 | phy->tssi2dbm = dyn_tssi2dbm; | ||
2047 | phy->dyn_tssi_tbl = 1; | ||
2048 | } else { | ||
2049 | /* pabX values not set in SPROM. */ | ||
2050 | switch (phy->type) { | ||
2051 | case B43legacy_PHYTYPE_B: | ||
2052 | phy->idle_tssi = 0x34; | ||
2053 | phy->tssi2dbm = b43legacy_tssi2dbm_b_table; | ||
2054 | break; | ||
2055 | case B43legacy_PHYTYPE_G: | ||
2056 | phy->idle_tssi = 0x34; | ||
2057 | phy->tssi2dbm = b43legacy_tssi2dbm_g_table; | ||
2058 | break; | ||
2059 | } | ||
2060 | } | ||
2061 | |||
2062 | return 0; | ||
2063 | } | ||
2064 | |||
2065 | int b43legacy_phy_init(struct b43legacy_wldev *dev) | ||
2066 | { | ||
2067 | struct b43legacy_phy *phy = &dev->phy; | ||
2068 | int err = -ENODEV; | ||
2069 | |||
2070 | switch (phy->type) { | ||
2071 | case B43legacy_PHYTYPE_B: | ||
2072 | switch (phy->rev) { | ||
2073 | case 2: | ||
2074 | b43legacy_phy_initb2(dev); | ||
2075 | err = 0; | ||
2076 | break; | ||
2077 | case 4: | ||
2078 | b43legacy_phy_initb4(dev); | ||
2079 | err = 0; | ||
2080 | break; | ||
2081 | case 5: | ||
2082 | b43legacy_phy_initb5(dev); | ||
2083 | err = 0; | ||
2084 | break; | ||
2085 | case 6: | ||
2086 | b43legacy_phy_initb6(dev); | ||
2087 | err = 0; | ||
2088 | break; | ||
2089 | } | ||
2090 | break; | ||
2091 | case B43legacy_PHYTYPE_G: | ||
2092 | b43legacy_phy_initg(dev); | ||
2093 | err = 0; | ||
2094 | break; | ||
2095 | } | ||
2096 | if (err) | ||
2097 | b43legacyerr(dev->wl, "Unknown PHYTYPE found\n"); | ||
2098 | |||
2099 | return err; | ||
2100 | } | ||
2101 | |||
2102 | void b43legacy_phy_set_antenna_diversity(struct b43legacy_wldev *dev) | ||
2103 | { | ||
2104 | struct b43legacy_phy *phy = &dev->phy; | ||
2105 | u16 antennadiv; | ||
2106 | u16 offset; | ||
2107 | u16 value; | ||
2108 | u32 ucodeflags; | ||
2109 | |||
2110 | antennadiv = phy->antenna_diversity; | ||
2111 | |||
2112 | if (antennadiv == 0xFFFF) | ||
2113 | antennadiv = 3; | ||
2114 | B43legacy_WARN_ON(antennadiv > 3); | ||
2115 | |||
2116 | ucodeflags = b43legacy_shm_read32(dev, B43legacy_SHM_SHARED, | ||
2117 | B43legacy_UCODEFLAGS_OFFSET); | ||
2118 | b43legacy_shm_write32(dev, B43legacy_SHM_SHARED, | ||
2119 | B43legacy_UCODEFLAGS_OFFSET, | ||
2120 | ucodeflags & ~B43legacy_UCODEFLAG_AUTODIV); | ||
2121 | |||
2122 | switch (phy->type) { | ||
2123 | case B43legacy_PHYTYPE_G: | ||
2124 | offset = 0x0400; | ||
2125 | |||
2126 | if (antennadiv == 2) | ||
2127 | value = (3/*automatic*/ << 7); | ||
2128 | else | ||
2129 | value = (antennadiv << 7); | ||
2130 | b43legacy_phy_write(dev, offset + 1, | ||
2131 | (b43legacy_phy_read(dev, offset + 1) | ||
2132 | & 0x7E7F) | value); | ||
2133 | |||
2134 | if (antennadiv >= 2) { | ||
2135 | if (antennadiv == 2) | ||
2136 | value = (antennadiv << 7); | ||
2137 | else | ||
2138 | value = (0/*force0*/ << 7); | ||
2139 | b43legacy_phy_write(dev, offset + 0x2B, | ||
2140 | (b43legacy_phy_read(dev, | ||
2141 | offset + 0x2B) | ||
2142 | & 0xFEFF) | value); | ||
2143 | } | ||
2144 | |||
2145 | if (phy->type == B43legacy_PHYTYPE_G) { | ||
2146 | if (antennadiv >= 2) | ||
2147 | b43legacy_phy_write(dev, 0x048C, | ||
2148 | b43legacy_phy_read(dev, | ||
2149 | 0x048C) | 0x2000); | ||
2150 | else | ||
2151 | b43legacy_phy_write(dev, 0x048C, | ||
2152 | b43legacy_phy_read(dev, | ||
2153 | 0x048C) & ~0x2000); | ||
2154 | if (phy->rev >= 2) { | ||
2155 | b43legacy_phy_write(dev, 0x0461, | ||
2156 | b43legacy_phy_read(dev, | ||
2157 | 0x0461) | 0x0010); | ||
2158 | b43legacy_phy_write(dev, 0x04AD, | ||
2159 | (b43legacy_phy_read(dev, | ||
2160 | 0x04AD) | ||
2161 | & 0x00FF) | 0x0015); | ||
2162 | if (phy->rev == 2) | ||
2163 | b43legacy_phy_write(dev, 0x0427, | ||
2164 | 0x0008); | ||
2165 | else | ||
2166 | b43legacy_phy_write(dev, 0x0427, | ||
2167 | (b43legacy_phy_read(dev, 0x0427) | ||
2168 | & 0x00FF) | 0x0008); | ||
2169 | } else if (phy->rev >= 6) | ||
2170 | b43legacy_phy_write(dev, 0x049B, 0x00DC); | ||
2171 | } else { | ||
2172 | if (phy->rev < 3) | ||
2173 | b43legacy_phy_write(dev, 0x002B, | ||
2174 | (b43legacy_phy_read(dev, | ||
2175 | 0x002B) & 0x00FF) | ||
2176 | | 0x0024); | ||
2177 | else { | ||
2178 | b43legacy_phy_write(dev, 0x0061, | ||
2179 | b43legacy_phy_read(dev, | ||
2180 | 0x0061) | 0x0010); | ||
2181 | if (phy->rev == 3) { | ||
2182 | b43legacy_phy_write(dev, 0x0093, | ||
2183 | 0x001D); | ||
2184 | b43legacy_phy_write(dev, 0x0027, | ||
2185 | 0x0008); | ||
2186 | } else { | ||
2187 | b43legacy_phy_write(dev, 0x0093, | ||
2188 | 0x003A); | ||
2189 | b43legacy_phy_write(dev, 0x0027, | ||
2190 | (b43legacy_phy_read(dev, 0x0027) | ||
2191 | & 0x00FF) | 0x0008); | ||
2192 | } | ||
2193 | } | ||
2194 | } | ||
2195 | break; | ||
2196 | case B43legacy_PHYTYPE_B: | ||
2197 | if (dev->dev->id.revision == 2) | ||
2198 | value = (3/*automatic*/ << 7); | ||
2199 | else | ||
2200 | value = (antennadiv << 7); | ||
2201 | b43legacy_phy_write(dev, 0x03E2, | ||
2202 | (b43legacy_phy_read(dev, 0x03E2) | ||
2203 | & 0xFE7F) | value); | ||
2204 | break; | ||
2205 | default: | ||
2206 | B43legacy_WARN_ON(1); | ||
2207 | } | ||
2208 | |||
2209 | if (antennadiv >= 2) { | ||
2210 | ucodeflags = b43legacy_shm_read32(dev, B43legacy_SHM_SHARED, | ||
2211 | B43legacy_UCODEFLAGS_OFFSET); | ||
2212 | b43legacy_shm_write32(dev, B43legacy_SHM_SHARED, | ||
2213 | B43legacy_UCODEFLAGS_OFFSET, | ||
2214 | ucodeflags | B43legacy_UCODEFLAG_AUTODIV); | ||
2215 | } | ||
2216 | |||
2217 | phy->antenna_diversity = antennadiv; | ||
2218 | } | ||
2219 | |||
2220 | /* Set the PowerSavingControlBits. | ||
2221 | * Bitvalues: | ||
2222 | * 0 => unset the bit | ||
2223 | * 1 => set the bit | ||
2224 | * -1 => calculate the bit | ||
2225 | */ | ||
2226 | void b43legacy_power_saving_ctl_bits(struct b43legacy_wldev *dev, | ||
2227 | int bit25, int bit26) | ||
2228 | { | ||
2229 | int i; | ||
2230 | u32 status; | ||
2231 | |||
2232 | /* FIXME: Force 25 to off and 26 to on for now: */ | ||
2233 | bit25 = 0; | ||
2234 | bit26 = 1; | ||
2235 | |||
2236 | if (bit25 == -1) { | ||
2237 | /* TODO: If powersave is not off and FIXME is not set and we | ||
2238 | * are not in adhoc and thus is not an AP and we arei | ||
2239 | * associated, set bit 25 */ | ||
2240 | } | ||
2241 | if (bit26 == -1) { | ||
2242 | /* TODO: If the device is awake or this is an AP, or we are | ||
2243 | * scanning, or FIXME, or we are associated, or FIXME, | ||
2244 | * or the latest PS-Poll packet sent was successful, | ||
2245 | * set bit26 */ | ||
2246 | } | ||
2247 | status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD); | ||
2248 | if (bit25) | ||
2249 | status |= B43legacy_SBF_PS1; | ||
2250 | else | ||
2251 | status &= ~B43legacy_SBF_PS1; | ||
2252 | if (bit26) | ||
2253 | status |= B43legacy_SBF_PS2; | ||
2254 | else | ||
2255 | status &= ~B43legacy_SBF_PS2; | ||
2256 | b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status); | ||
2257 | if (bit26 && dev->dev->id.revision >= 5) { | ||
2258 | for (i = 0; i < 100; i++) { | ||
2259 | if (b43legacy_shm_read32(dev, B43legacy_SHM_SHARED, | ||
2260 | 0x0040) != 4) | ||
2261 | break; | ||
2262 | udelay(10); | ||
2263 | } | ||
2264 | } | ||
2265 | } | ||