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