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