1ca47d344SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2423e3ce3SKalle Valo /*
3423e3ce3SKalle Valo
4423e3ce3SKalle Valo Broadcom B43legacy wireless driver
5423e3ce3SKalle Valo
6423e3ce3SKalle Valo Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
7423e3ce3SKalle Valo Stefano Brivio <stefano.brivio@polimi.it>
8423e3ce3SKalle Valo Michael Buesch <m@bues.ch>
9423e3ce3SKalle Valo Danny van Dyk <kugelfang@gentoo.org>
10423e3ce3SKalle Valo Andreas Jaggi <andreas.jaggi@waterwave.ch>
11423e3ce3SKalle Valo Copyright (c) 2007 Larry Finger <Larry.Finger@lwfinger.net>
12423e3ce3SKalle Valo
13423e3ce3SKalle Valo Some parts of the code in this file are derived from the ipw2200
14423e3ce3SKalle Valo driver Copyright(c) 2003 - 2004 Intel Corporation.
15423e3ce3SKalle Valo
16423e3ce3SKalle Valo
17423e3ce3SKalle Valo */
18423e3ce3SKalle Valo
19423e3ce3SKalle Valo #include <linux/delay.h>
20423e3ce3SKalle Valo
21423e3ce3SKalle Valo #include "b43legacy.h"
22423e3ce3SKalle Valo #include "main.h"
23423e3ce3SKalle Valo #include "phy.h"
24423e3ce3SKalle Valo #include "radio.h"
25423e3ce3SKalle Valo #include "ilt.h"
26423e3ce3SKalle Valo
27423e3ce3SKalle Valo
28423e3ce3SKalle Valo /* Table for b43legacy_radio_calibrationvalue() */
29423e3ce3SKalle Valo static const u16 rcc_table[16] = {
30423e3ce3SKalle Valo 0x0002, 0x0003, 0x0001, 0x000F,
31423e3ce3SKalle Valo 0x0006, 0x0007, 0x0005, 0x000F,
32423e3ce3SKalle Valo 0x000A, 0x000B, 0x0009, 0x000F,
33423e3ce3SKalle Valo 0x000E, 0x000F, 0x000D, 0x000F,
34423e3ce3SKalle Valo };
35423e3ce3SKalle Valo
36423e3ce3SKalle Valo /* Reverse the bits of a 4bit value.
37423e3ce3SKalle Valo * Example: 1101 is flipped 1011
38423e3ce3SKalle Valo */
flip_4bit(u16 value)39423e3ce3SKalle Valo static u16 flip_4bit(u16 value)
40423e3ce3SKalle Valo {
41423e3ce3SKalle Valo u16 flipped = 0x0000;
42423e3ce3SKalle Valo
43423e3ce3SKalle Valo B43legacy_BUG_ON(!((value & ~0x000F) == 0x0000));
44423e3ce3SKalle Valo
45423e3ce3SKalle Valo flipped |= (value & 0x0001) << 3;
46423e3ce3SKalle Valo flipped |= (value & 0x0002) << 1;
47423e3ce3SKalle Valo flipped |= (value & 0x0004) >> 1;
48423e3ce3SKalle Valo flipped |= (value & 0x0008) >> 3;
49423e3ce3SKalle Valo
50423e3ce3SKalle Valo return flipped;
51423e3ce3SKalle Valo }
52423e3ce3SKalle Valo
53423e3ce3SKalle Valo /* Get the freq, as it has to be written to the device. */
54423e3ce3SKalle Valo static inline
channel2freq_bg(u8 channel)55423e3ce3SKalle Valo u16 channel2freq_bg(u8 channel)
56423e3ce3SKalle Valo {
57423e3ce3SKalle Valo /* Frequencies are given as frequencies_bg[index] + 2.4GHz
58423e3ce3SKalle Valo * Starting with channel 1
59423e3ce3SKalle Valo */
60423e3ce3SKalle Valo static const u16 frequencies_bg[14] = {
61423e3ce3SKalle Valo 12, 17, 22, 27,
62423e3ce3SKalle Valo 32, 37, 42, 47,
63423e3ce3SKalle Valo 52, 57, 62, 67,
64423e3ce3SKalle Valo 72, 84,
65423e3ce3SKalle Valo };
66423e3ce3SKalle Valo
67423e3ce3SKalle Valo if (unlikely(channel < 1 || channel > 14)) {
68423e3ce3SKalle Valo printk(KERN_INFO "b43legacy: Channel %d is out of range\n",
69423e3ce3SKalle Valo channel);
70423e3ce3SKalle Valo dump_stack();
71423e3ce3SKalle Valo return 2412;
72423e3ce3SKalle Valo }
73423e3ce3SKalle Valo
74423e3ce3SKalle Valo return frequencies_bg[channel - 1];
75423e3ce3SKalle Valo }
76423e3ce3SKalle Valo
b43legacy_radio_lock(struct b43legacy_wldev * dev)77423e3ce3SKalle Valo void b43legacy_radio_lock(struct b43legacy_wldev *dev)
78423e3ce3SKalle Valo {
79423e3ce3SKalle Valo u32 status;
80423e3ce3SKalle Valo
81423e3ce3SKalle Valo status = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
82423e3ce3SKalle Valo B43legacy_WARN_ON(status & B43legacy_MACCTL_RADIOLOCK);
83423e3ce3SKalle Valo status |= B43legacy_MACCTL_RADIOLOCK;
84423e3ce3SKalle Valo b43legacy_write32(dev, B43legacy_MMIO_MACCTL, status);
85423e3ce3SKalle Valo udelay(10);
86423e3ce3SKalle Valo }
87423e3ce3SKalle Valo
b43legacy_radio_unlock(struct b43legacy_wldev * dev)88423e3ce3SKalle Valo void b43legacy_radio_unlock(struct b43legacy_wldev *dev)
89423e3ce3SKalle Valo {
90423e3ce3SKalle Valo u32 status;
91423e3ce3SKalle Valo
92423e3ce3SKalle Valo b43legacy_read16(dev, B43legacy_MMIO_PHY_VER); /* dummy read */
93423e3ce3SKalle Valo status = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
94423e3ce3SKalle Valo B43legacy_WARN_ON(!(status & B43legacy_MACCTL_RADIOLOCK));
95423e3ce3SKalle Valo status &= ~B43legacy_MACCTL_RADIOLOCK;
96423e3ce3SKalle Valo b43legacy_write32(dev, B43legacy_MMIO_MACCTL, status);
97423e3ce3SKalle Valo }
98423e3ce3SKalle Valo
b43legacy_radio_read16(struct b43legacy_wldev * dev,u16 offset)99423e3ce3SKalle Valo u16 b43legacy_radio_read16(struct b43legacy_wldev *dev, u16 offset)
100423e3ce3SKalle Valo {
101423e3ce3SKalle Valo struct b43legacy_phy *phy = &dev->phy;
102423e3ce3SKalle Valo
103423e3ce3SKalle Valo switch (phy->type) {
104423e3ce3SKalle Valo case B43legacy_PHYTYPE_B:
105423e3ce3SKalle Valo if (phy->radio_ver == 0x2053) {
106423e3ce3SKalle Valo if (offset < 0x70)
107423e3ce3SKalle Valo offset += 0x80;
108423e3ce3SKalle Valo else if (offset < 0x80)
109423e3ce3SKalle Valo offset += 0x70;
110423e3ce3SKalle Valo } else if (phy->radio_ver == 0x2050)
111423e3ce3SKalle Valo offset |= 0x80;
112423e3ce3SKalle Valo else
113423e3ce3SKalle Valo B43legacy_WARN_ON(1);
114423e3ce3SKalle Valo break;
115423e3ce3SKalle Valo case B43legacy_PHYTYPE_G:
116423e3ce3SKalle Valo offset |= 0x80;
117423e3ce3SKalle Valo break;
118423e3ce3SKalle Valo default:
119423e3ce3SKalle Valo B43legacy_BUG_ON(1);
120423e3ce3SKalle Valo }
121423e3ce3SKalle Valo
122423e3ce3SKalle Valo b43legacy_write16(dev, B43legacy_MMIO_RADIO_CONTROL, offset);
123423e3ce3SKalle Valo return b43legacy_read16(dev, B43legacy_MMIO_RADIO_DATA_LOW);
124423e3ce3SKalle Valo }
125423e3ce3SKalle Valo
b43legacy_radio_write16(struct b43legacy_wldev * dev,u16 offset,u16 val)126423e3ce3SKalle Valo void b43legacy_radio_write16(struct b43legacy_wldev *dev, u16 offset, u16 val)
127423e3ce3SKalle Valo {
128423e3ce3SKalle Valo b43legacy_write16(dev, B43legacy_MMIO_RADIO_CONTROL, offset);
129423e3ce3SKalle Valo b43legacy_write16(dev, B43legacy_MMIO_RADIO_DATA_LOW, val);
130423e3ce3SKalle Valo }
131423e3ce3SKalle Valo
b43legacy_set_all_gains(struct b43legacy_wldev * dev,s16 first,s16 second,s16 third)132423e3ce3SKalle Valo static void b43legacy_set_all_gains(struct b43legacy_wldev *dev,
133423e3ce3SKalle Valo s16 first, s16 second, s16 third)
134423e3ce3SKalle Valo {
135423e3ce3SKalle Valo struct b43legacy_phy *phy = &dev->phy;
136423e3ce3SKalle Valo u16 i;
137423e3ce3SKalle Valo u16 start = 0x08;
138423e3ce3SKalle Valo u16 end = 0x18;
139423e3ce3SKalle Valo u16 offset = 0x0400;
140423e3ce3SKalle Valo u16 tmp;
141423e3ce3SKalle Valo
142423e3ce3SKalle Valo if (phy->rev <= 1) {
143423e3ce3SKalle Valo offset = 0x5000;
144423e3ce3SKalle Valo start = 0x10;
145423e3ce3SKalle Valo end = 0x20;
146423e3ce3SKalle Valo }
147423e3ce3SKalle Valo
148423e3ce3SKalle Valo for (i = 0; i < 4; i++)
149423e3ce3SKalle Valo b43legacy_ilt_write(dev, offset + i, first);
150423e3ce3SKalle Valo
151423e3ce3SKalle Valo for (i = start; i < end; i++)
152423e3ce3SKalle Valo b43legacy_ilt_write(dev, offset + i, second);
153423e3ce3SKalle Valo
154423e3ce3SKalle Valo if (third != -1) {
155423e3ce3SKalle Valo tmp = ((u16)third << 14) | ((u16)third << 6);
156423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x04A0,
157423e3ce3SKalle Valo (b43legacy_phy_read(dev, 0x04A0) & 0xBFBF)
158423e3ce3SKalle Valo | tmp);
159423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x04A1,
160423e3ce3SKalle Valo (b43legacy_phy_read(dev, 0x04A1) & 0xBFBF)
161423e3ce3SKalle Valo | tmp);
162423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x04A2,
163423e3ce3SKalle Valo (b43legacy_phy_read(dev, 0x04A2) & 0xBFBF)
164423e3ce3SKalle Valo | tmp);
165423e3ce3SKalle Valo }
166423e3ce3SKalle Valo b43legacy_dummy_transmission(dev);
167423e3ce3SKalle Valo }
168423e3ce3SKalle Valo
b43legacy_set_original_gains(struct b43legacy_wldev * dev)169423e3ce3SKalle Valo static void b43legacy_set_original_gains(struct b43legacy_wldev *dev)
170423e3ce3SKalle Valo {
171423e3ce3SKalle Valo struct b43legacy_phy *phy = &dev->phy;
172423e3ce3SKalle Valo u16 i;
173423e3ce3SKalle Valo u16 tmp;
174423e3ce3SKalle Valo u16 offset = 0x0400;
175423e3ce3SKalle Valo u16 start = 0x0008;
176423e3ce3SKalle Valo u16 end = 0x0018;
177423e3ce3SKalle Valo
178423e3ce3SKalle Valo if (phy->rev <= 1) {
179423e3ce3SKalle Valo offset = 0x5000;
180423e3ce3SKalle Valo start = 0x0010;
181423e3ce3SKalle Valo end = 0x0020;
182423e3ce3SKalle Valo }
183423e3ce3SKalle Valo
184423e3ce3SKalle Valo for (i = 0; i < 4; i++) {
185423e3ce3SKalle Valo tmp = (i & 0xFFFC);
186423e3ce3SKalle Valo tmp |= (i & 0x0001) << 1;
187423e3ce3SKalle Valo tmp |= (i & 0x0002) >> 1;
188423e3ce3SKalle Valo
189423e3ce3SKalle Valo b43legacy_ilt_write(dev, offset + i, tmp);
190423e3ce3SKalle Valo }
191423e3ce3SKalle Valo
192423e3ce3SKalle Valo for (i = start; i < end; i++)
193423e3ce3SKalle Valo b43legacy_ilt_write(dev, offset + i, i - start);
194423e3ce3SKalle Valo
195423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x04A0,
196423e3ce3SKalle Valo (b43legacy_phy_read(dev, 0x04A0) & 0xBFBF)
197423e3ce3SKalle Valo | 0x4040);
198423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x04A1,
199423e3ce3SKalle Valo (b43legacy_phy_read(dev, 0x04A1) & 0xBFBF)
200423e3ce3SKalle Valo | 0x4040);
201423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x04A2,
202423e3ce3SKalle Valo (b43legacy_phy_read(dev, 0x04A2) & 0xBFBF)
203423e3ce3SKalle Valo | 0x4000);
204423e3ce3SKalle Valo b43legacy_dummy_transmission(dev);
205423e3ce3SKalle Valo }
206423e3ce3SKalle Valo
207423e3ce3SKalle Valo /* Synthetic PU workaround */
b43legacy_synth_pu_workaround(struct b43legacy_wldev * dev,u8 channel)208423e3ce3SKalle Valo static void b43legacy_synth_pu_workaround(struct b43legacy_wldev *dev,
209423e3ce3SKalle Valo u8 channel)
210423e3ce3SKalle Valo {
211423e3ce3SKalle Valo struct b43legacy_phy *phy = &dev->phy;
212423e3ce3SKalle Valo
213423e3ce3SKalle Valo might_sleep();
214423e3ce3SKalle Valo
215423e3ce3SKalle Valo if (phy->radio_ver != 0x2050 || phy->radio_rev >= 6)
216423e3ce3SKalle Valo /* We do not need the workaround. */
217423e3ce3SKalle Valo return;
218423e3ce3SKalle Valo
219423e3ce3SKalle Valo if (channel <= 10)
220423e3ce3SKalle Valo b43legacy_write16(dev, B43legacy_MMIO_CHANNEL,
221423e3ce3SKalle Valo channel2freq_bg(channel + 4));
222423e3ce3SKalle Valo else
223423e3ce3SKalle Valo b43legacy_write16(dev, B43legacy_MMIO_CHANNEL,
224423e3ce3SKalle Valo channel2freq_bg(channel));
225423e3ce3SKalle Valo msleep(1);
226423e3ce3SKalle Valo b43legacy_write16(dev, B43legacy_MMIO_CHANNEL,
227423e3ce3SKalle Valo channel2freq_bg(channel));
228423e3ce3SKalle Valo }
229423e3ce3SKalle Valo
b43legacy_radio_aci_detect(struct b43legacy_wldev * dev,u8 channel)230423e3ce3SKalle Valo u8 b43legacy_radio_aci_detect(struct b43legacy_wldev *dev, u8 channel)
231423e3ce3SKalle Valo {
232423e3ce3SKalle Valo struct b43legacy_phy *phy = &dev->phy;
233423e3ce3SKalle Valo u8 ret = 0;
234423e3ce3SKalle Valo u16 saved;
235423e3ce3SKalle Valo u16 rssi;
236423e3ce3SKalle Valo u16 temp;
237423e3ce3SKalle Valo int i;
238423e3ce3SKalle Valo int j = 0;
239423e3ce3SKalle Valo
240423e3ce3SKalle Valo saved = b43legacy_phy_read(dev, 0x0403);
241423e3ce3SKalle Valo b43legacy_radio_selectchannel(dev, channel, 0);
242423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0403, (saved & 0xFFF8) | 5);
243423e3ce3SKalle Valo if (phy->aci_hw_rssi)
244423e3ce3SKalle Valo rssi = b43legacy_phy_read(dev, 0x048A) & 0x3F;
245423e3ce3SKalle Valo else
246423e3ce3SKalle Valo rssi = saved & 0x3F;
247423e3ce3SKalle Valo /* clamp temp to signed 5bit */
248423e3ce3SKalle Valo if (rssi > 32)
249423e3ce3SKalle Valo rssi -= 64;
250423e3ce3SKalle Valo for (i = 0; i < 100; i++) {
251423e3ce3SKalle Valo temp = (b43legacy_phy_read(dev, 0x047F) >> 8) & 0x3F;
252423e3ce3SKalle Valo if (temp > 32)
253423e3ce3SKalle Valo temp -= 64;
254423e3ce3SKalle Valo if (temp < rssi)
255423e3ce3SKalle Valo j++;
256423e3ce3SKalle Valo if (j >= 20)
257423e3ce3SKalle Valo ret = 1;
258423e3ce3SKalle Valo }
259423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0403, saved);
260423e3ce3SKalle Valo
261423e3ce3SKalle Valo return ret;
262423e3ce3SKalle Valo }
263423e3ce3SKalle Valo
b43legacy_radio_aci_scan(struct b43legacy_wldev * dev)264423e3ce3SKalle Valo u8 b43legacy_radio_aci_scan(struct b43legacy_wldev *dev)
265423e3ce3SKalle Valo {
266423e3ce3SKalle Valo struct b43legacy_phy *phy = &dev->phy;
267e3ae1c77SColin Ian King u8 ret[13] = { 0 };
268423e3ce3SKalle Valo unsigned int channel = phy->channel;
269423e3ce3SKalle Valo unsigned int i;
270423e3ce3SKalle Valo unsigned int j;
271423e3ce3SKalle Valo unsigned int start;
272423e3ce3SKalle Valo unsigned int end;
273423e3ce3SKalle Valo
274423e3ce3SKalle Valo if (!((phy->type == B43legacy_PHYTYPE_G) && (phy->rev > 0)))
275423e3ce3SKalle Valo return 0;
276423e3ce3SKalle Valo
277423e3ce3SKalle Valo b43legacy_phy_lock(dev);
278423e3ce3SKalle Valo b43legacy_radio_lock(dev);
279423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0802,
280423e3ce3SKalle Valo b43legacy_phy_read(dev, 0x0802) & 0xFFFC);
281423e3ce3SKalle Valo b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
282423e3ce3SKalle Valo b43legacy_phy_read(dev, B43legacy_PHY_G_CRS)
283423e3ce3SKalle Valo & 0x7FFF);
284423e3ce3SKalle Valo b43legacy_set_all_gains(dev, 3, 8, 1);
285423e3ce3SKalle Valo
286*c1c8380bSDan Carpenter start = (channel > 5) ? channel - 5 : 1;
287423e3ce3SKalle Valo end = (channel + 5 < 14) ? channel + 5 : 13;
288423e3ce3SKalle Valo
289423e3ce3SKalle Valo for (i = start; i <= end; i++) {
290423e3ce3SKalle Valo if (abs(channel - i) > 2)
291423e3ce3SKalle Valo ret[i-1] = b43legacy_radio_aci_detect(dev, i);
292423e3ce3SKalle Valo }
293423e3ce3SKalle Valo b43legacy_radio_selectchannel(dev, channel, 0);
294423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0802,
295423e3ce3SKalle Valo (b43legacy_phy_read(dev, 0x0802) & 0xFFFC)
296423e3ce3SKalle Valo | 0x0003);
297423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0403,
298423e3ce3SKalle Valo b43legacy_phy_read(dev, 0x0403) & 0xFFF8);
299423e3ce3SKalle Valo b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
300423e3ce3SKalle Valo b43legacy_phy_read(dev, B43legacy_PHY_G_CRS)
301423e3ce3SKalle Valo | 0x8000);
302423e3ce3SKalle Valo b43legacy_set_original_gains(dev);
303423e3ce3SKalle Valo for (i = 0; i < 13; i++) {
304423e3ce3SKalle Valo if (!ret[i])
305423e3ce3SKalle Valo continue;
306423e3ce3SKalle Valo end = (i + 5 < 13) ? i + 5 : 13;
307423e3ce3SKalle Valo for (j = i; j < end; j++)
308423e3ce3SKalle Valo ret[j] = 1;
309423e3ce3SKalle Valo }
310423e3ce3SKalle Valo b43legacy_radio_unlock(dev);
311423e3ce3SKalle Valo b43legacy_phy_unlock(dev);
312423e3ce3SKalle Valo
313423e3ce3SKalle Valo return ret[channel - 1];
314423e3ce3SKalle Valo }
315423e3ce3SKalle Valo
316140c6026SAlexander A. Klimov /* https://bcm-specs.sipsolutions.net/NRSSILookupTable */
b43legacy_nrssi_hw_write(struct b43legacy_wldev * dev,u16 offset,s16 val)317423e3ce3SKalle Valo void b43legacy_nrssi_hw_write(struct b43legacy_wldev *dev, u16 offset, s16 val)
318423e3ce3SKalle Valo {
319423e3ce3SKalle Valo b43legacy_phy_write(dev, B43legacy_PHY_NRSSILT_CTRL, offset);
320423e3ce3SKalle Valo b43legacy_phy_write(dev, B43legacy_PHY_NRSSILT_DATA, (u16)val);
321423e3ce3SKalle Valo }
322423e3ce3SKalle Valo
323140c6026SAlexander A. Klimov /* https://bcm-specs.sipsolutions.net/NRSSILookupTable */
b43legacy_nrssi_hw_read(struct b43legacy_wldev * dev,u16 offset)324423e3ce3SKalle Valo s16 b43legacy_nrssi_hw_read(struct b43legacy_wldev *dev, u16 offset)
325423e3ce3SKalle Valo {
326423e3ce3SKalle Valo u16 val;
327423e3ce3SKalle Valo
328423e3ce3SKalle Valo b43legacy_phy_write(dev, B43legacy_PHY_NRSSILT_CTRL, offset);
329423e3ce3SKalle Valo val = b43legacy_phy_read(dev, B43legacy_PHY_NRSSILT_DATA);
330423e3ce3SKalle Valo
331423e3ce3SKalle Valo return (s16)val;
332423e3ce3SKalle Valo }
333423e3ce3SKalle Valo
334140c6026SAlexander A. Klimov /* https://bcm-specs.sipsolutions.net/NRSSILookupTable */
b43legacy_nrssi_hw_update(struct b43legacy_wldev * dev,u16 val)335423e3ce3SKalle Valo void b43legacy_nrssi_hw_update(struct b43legacy_wldev *dev, u16 val)
336423e3ce3SKalle Valo {
337423e3ce3SKalle Valo u16 i;
338423e3ce3SKalle Valo s16 tmp;
339423e3ce3SKalle Valo
340423e3ce3SKalle Valo for (i = 0; i < 64; i++) {
341423e3ce3SKalle Valo tmp = b43legacy_nrssi_hw_read(dev, i);
342423e3ce3SKalle Valo tmp -= val;
343423e3ce3SKalle Valo tmp = clamp_val(tmp, -32, 31);
344423e3ce3SKalle Valo b43legacy_nrssi_hw_write(dev, i, tmp);
345423e3ce3SKalle Valo }
346423e3ce3SKalle Valo }
347423e3ce3SKalle Valo
348140c6026SAlexander A. Klimov /* https://bcm-specs.sipsolutions.net/NRSSILookupTable */
b43legacy_nrssi_mem_update(struct b43legacy_wldev * dev)349423e3ce3SKalle Valo void b43legacy_nrssi_mem_update(struct b43legacy_wldev *dev)
350423e3ce3SKalle Valo {
351423e3ce3SKalle Valo struct b43legacy_phy *phy = &dev->phy;
352423e3ce3SKalle Valo s16 i;
353423e3ce3SKalle Valo s16 delta;
354423e3ce3SKalle Valo s32 tmp;
355423e3ce3SKalle Valo
356423e3ce3SKalle Valo delta = 0x1F - phy->nrssi[0];
357423e3ce3SKalle Valo for (i = 0; i < 64; i++) {
358423e3ce3SKalle Valo tmp = (i - delta) * phy->nrssislope;
359423e3ce3SKalle Valo tmp /= 0x10000;
360423e3ce3SKalle Valo tmp += 0x3A;
361423e3ce3SKalle Valo tmp = clamp_val(tmp, 0, 0x3F);
362423e3ce3SKalle Valo phy->nrssi_lt[i] = tmp;
363423e3ce3SKalle Valo }
364423e3ce3SKalle Valo }
365423e3ce3SKalle Valo
b43legacy_calc_nrssi_offset(struct b43legacy_wldev * dev)366423e3ce3SKalle Valo static void b43legacy_calc_nrssi_offset(struct b43legacy_wldev *dev)
367423e3ce3SKalle Valo {
368423e3ce3SKalle Valo struct b43legacy_phy *phy = &dev->phy;
369423e3ce3SKalle Valo u16 backup[20] = { 0 };
370423e3ce3SKalle Valo s16 v47F;
371423e3ce3SKalle Valo u16 i;
372423e3ce3SKalle Valo u16 saved = 0xFFFF;
373423e3ce3SKalle Valo
374423e3ce3SKalle Valo backup[0] = b43legacy_phy_read(dev, 0x0001);
375423e3ce3SKalle Valo backup[1] = b43legacy_phy_read(dev, 0x0811);
376423e3ce3SKalle Valo backup[2] = b43legacy_phy_read(dev, 0x0812);
377423e3ce3SKalle Valo backup[3] = b43legacy_phy_read(dev, 0x0814);
378423e3ce3SKalle Valo backup[4] = b43legacy_phy_read(dev, 0x0815);
379423e3ce3SKalle Valo backup[5] = b43legacy_phy_read(dev, 0x005A);
380423e3ce3SKalle Valo backup[6] = b43legacy_phy_read(dev, 0x0059);
381423e3ce3SKalle Valo backup[7] = b43legacy_phy_read(dev, 0x0058);
382423e3ce3SKalle Valo backup[8] = b43legacy_phy_read(dev, 0x000A);
383423e3ce3SKalle Valo backup[9] = b43legacy_phy_read(dev, 0x0003);
384423e3ce3SKalle Valo backup[10] = b43legacy_radio_read16(dev, 0x007A);
385423e3ce3SKalle Valo backup[11] = b43legacy_radio_read16(dev, 0x0043);
386423e3ce3SKalle Valo
387423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0429,
388423e3ce3SKalle Valo b43legacy_phy_read(dev, 0x0429) & 0x7FFF);
389423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0001,
390423e3ce3SKalle Valo (b43legacy_phy_read(dev, 0x0001) & 0x3FFF)
391423e3ce3SKalle Valo | 0x4000);
392423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0811,
393423e3ce3SKalle Valo b43legacy_phy_read(dev, 0x0811) | 0x000C);
394423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0812,
395423e3ce3SKalle Valo (b43legacy_phy_read(dev, 0x0812) & 0xFFF3)
396423e3ce3SKalle Valo | 0x0004);
397423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0802,
398423e3ce3SKalle Valo b43legacy_phy_read(dev, 0x0802) & ~(0x1 | 0x2));
399423e3ce3SKalle Valo if (phy->rev >= 6) {
400423e3ce3SKalle Valo backup[12] = b43legacy_phy_read(dev, 0x002E);
401423e3ce3SKalle Valo backup[13] = b43legacy_phy_read(dev, 0x002F);
402423e3ce3SKalle Valo backup[14] = b43legacy_phy_read(dev, 0x080F);
403423e3ce3SKalle Valo backup[15] = b43legacy_phy_read(dev, 0x0810);
404423e3ce3SKalle Valo backup[16] = b43legacy_phy_read(dev, 0x0801);
405423e3ce3SKalle Valo backup[17] = b43legacy_phy_read(dev, 0x0060);
406423e3ce3SKalle Valo backup[18] = b43legacy_phy_read(dev, 0x0014);
407423e3ce3SKalle Valo backup[19] = b43legacy_phy_read(dev, 0x0478);
408423e3ce3SKalle Valo
409423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x002E, 0);
410423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x002F, 0);
411423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x080F, 0);
412423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0810, 0);
413423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0478,
414423e3ce3SKalle Valo b43legacy_phy_read(dev, 0x0478) | 0x0100);
415423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0801,
416423e3ce3SKalle Valo b43legacy_phy_read(dev, 0x0801) | 0x0040);
417423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0060,
418423e3ce3SKalle Valo b43legacy_phy_read(dev, 0x0060) | 0x0040);
419423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0014,
420423e3ce3SKalle Valo b43legacy_phy_read(dev, 0x0014) | 0x0200);
421423e3ce3SKalle Valo }
422423e3ce3SKalle Valo b43legacy_radio_write16(dev, 0x007A,
423423e3ce3SKalle Valo b43legacy_radio_read16(dev, 0x007A) | 0x0070);
424423e3ce3SKalle Valo b43legacy_radio_write16(dev, 0x007A,
425423e3ce3SKalle Valo b43legacy_radio_read16(dev, 0x007A) | 0x0080);
426423e3ce3SKalle Valo udelay(30);
427423e3ce3SKalle Valo
428423e3ce3SKalle Valo v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) & 0x003F);
429423e3ce3SKalle Valo if (v47F >= 0x20)
430423e3ce3SKalle Valo v47F -= 0x40;
431423e3ce3SKalle Valo if (v47F == 31) {
432423e3ce3SKalle Valo for (i = 7; i >= 4; i--) {
433423e3ce3SKalle Valo b43legacy_radio_write16(dev, 0x007B, i);
434423e3ce3SKalle Valo udelay(20);
435423e3ce3SKalle Valo v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8)
436423e3ce3SKalle Valo & 0x003F);
437423e3ce3SKalle Valo if (v47F >= 0x20)
438423e3ce3SKalle Valo v47F -= 0x40;
439423e3ce3SKalle Valo if (v47F < 31 && saved == 0xFFFF)
440423e3ce3SKalle Valo saved = i;
441423e3ce3SKalle Valo }
442423e3ce3SKalle Valo if (saved == 0xFFFF)
443423e3ce3SKalle Valo saved = 4;
444423e3ce3SKalle Valo } else {
445423e3ce3SKalle Valo b43legacy_radio_write16(dev, 0x007A,
446423e3ce3SKalle Valo b43legacy_radio_read16(dev, 0x007A)
447423e3ce3SKalle Valo & 0x007F);
448423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0814,
449423e3ce3SKalle Valo b43legacy_phy_read(dev, 0x0814) | 0x0001);
450423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0815,
451423e3ce3SKalle Valo b43legacy_phy_read(dev, 0x0815) & 0xFFFE);
452423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0811,
453423e3ce3SKalle Valo b43legacy_phy_read(dev, 0x0811) | 0x000C);
454423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0812,
455423e3ce3SKalle Valo b43legacy_phy_read(dev, 0x0812) | 0x000C);
456423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0811,
457423e3ce3SKalle Valo b43legacy_phy_read(dev, 0x0811) | 0x0030);
458423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0812,
459423e3ce3SKalle Valo b43legacy_phy_read(dev, 0x0812) | 0x0030);
460423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x005A, 0x0480);
461423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0059, 0x0810);
462423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0058, 0x000D);
463423e3ce3SKalle Valo if (phy->analog == 0)
464423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0003, 0x0122);
465423e3ce3SKalle Valo else
466423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x000A,
467423e3ce3SKalle Valo b43legacy_phy_read(dev, 0x000A)
468423e3ce3SKalle Valo | 0x2000);
469423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0814,
470423e3ce3SKalle Valo b43legacy_phy_read(dev, 0x0814) | 0x0004);
471423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0815,
472423e3ce3SKalle Valo b43legacy_phy_read(dev, 0x0815) & 0xFFFB);
473423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0003,
474423e3ce3SKalle Valo (b43legacy_phy_read(dev, 0x0003) & 0xFF9F)
475423e3ce3SKalle Valo | 0x0040);
476423e3ce3SKalle Valo b43legacy_radio_write16(dev, 0x007A,
477423e3ce3SKalle Valo b43legacy_radio_read16(dev, 0x007A)
478423e3ce3SKalle Valo | 0x000F);
479423e3ce3SKalle Valo b43legacy_set_all_gains(dev, 3, 0, 1);
480423e3ce3SKalle Valo b43legacy_radio_write16(dev, 0x0043,
481423e3ce3SKalle Valo (b43legacy_radio_read16(dev, 0x0043)
482423e3ce3SKalle Valo & 0x00F0) | 0x000F);
483423e3ce3SKalle Valo udelay(30);
484423e3ce3SKalle Valo v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) & 0x003F);
485423e3ce3SKalle Valo if (v47F >= 0x20)
486423e3ce3SKalle Valo v47F -= 0x40;
487423e3ce3SKalle Valo if (v47F == -32) {
488423e3ce3SKalle Valo for (i = 0; i < 4; i++) {
489423e3ce3SKalle Valo b43legacy_radio_write16(dev, 0x007B, i);
490423e3ce3SKalle Valo udelay(20);
491423e3ce3SKalle Valo v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >>
492423e3ce3SKalle Valo 8) & 0x003F);
493423e3ce3SKalle Valo if (v47F >= 0x20)
494423e3ce3SKalle Valo v47F -= 0x40;
495423e3ce3SKalle Valo if (v47F > -31 && saved == 0xFFFF)
496423e3ce3SKalle Valo saved = i;
497423e3ce3SKalle Valo }
498423e3ce3SKalle Valo if (saved == 0xFFFF)
499423e3ce3SKalle Valo saved = 3;
500423e3ce3SKalle Valo } else
501423e3ce3SKalle Valo saved = 0;
502423e3ce3SKalle Valo }
503423e3ce3SKalle Valo b43legacy_radio_write16(dev, 0x007B, saved);
504423e3ce3SKalle Valo
505423e3ce3SKalle Valo if (phy->rev >= 6) {
506423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x002E, backup[12]);
507423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x002F, backup[13]);
508423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x080F, backup[14]);
509423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0810, backup[15]);
510423e3ce3SKalle Valo }
511423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0814, backup[3]);
512423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0815, backup[4]);
513423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x005A, backup[5]);
514423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0059, backup[6]);
515423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0058, backup[7]);
516423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x000A, backup[8]);
517423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0003, backup[9]);
518423e3ce3SKalle Valo b43legacy_radio_write16(dev, 0x0043, backup[11]);
519423e3ce3SKalle Valo b43legacy_radio_write16(dev, 0x007A, backup[10]);
520423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0802,
521423e3ce3SKalle Valo b43legacy_phy_read(dev, 0x0802) | 0x1 | 0x2);
522423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0429,
523423e3ce3SKalle Valo b43legacy_phy_read(dev, 0x0429) | 0x8000);
524423e3ce3SKalle Valo b43legacy_set_original_gains(dev);
525423e3ce3SKalle Valo if (phy->rev >= 6) {
526423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0801, backup[16]);
527423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0060, backup[17]);
528423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0014, backup[18]);
529423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0478, backup[19]);
530423e3ce3SKalle Valo }
531423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0001, backup[0]);
532423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0812, backup[2]);
533423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0811, backup[1]);
534423e3ce3SKalle Valo }
535423e3ce3SKalle Valo
b43legacy_calc_nrssi_slope(struct b43legacy_wldev * dev)536423e3ce3SKalle Valo void b43legacy_calc_nrssi_slope(struct b43legacy_wldev *dev)
537423e3ce3SKalle Valo {
538423e3ce3SKalle Valo struct b43legacy_phy *phy = &dev->phy;
539423e3ce3SKalle Valo u16 backup[18] = { 0 };
540423e3ce3SKalle Valo u16 tmp;
541423e3ce3SKalle Valo s16 nrssi0;
542423e3ce3SKalle Valo s16 nrssi1;
543423e3ce3SKalle Valo
544423e3ce3SKalle Valo switch (phy->type) {
545423e3ce3SKalle Valo case B43legacy_PHYTYPE_B:
546423e3ce3SKalle Valo backup[0] = b43legacy_radio_read16(dev, 0x007A);
547423e3ce3SKalle Valo backup[1] = b43legacy_radio_read16(dev, 0x0052);
548423e3ce3SKalle Valo backup[2] = b43legacy_radio_read16(dev, 0x0043);
549423e3ce3SKalle Valo backup[3] = b43legacy_phy_read(dev, 0x0030);
550423e3ce3SKalle Valo backup[4] = b43legacy_phy_read(dev, 0x0026);
551423e3ce3SKalle Valo backup[5] = b43legacy_phy_read(dev, 0x0015);
552423e3ce3SKalle Valo backup[6] = b43legacy_phy_read(dev, 0x002A);
553423e3ce3SKalle Valo backup[7] = b43legacy_phy_read(dev, 0x0020);
554423e3ce3SKalle Valo backup[8] = b43legacy_phy_read(dev, 0x005A);
555423e3ce3SKalle Valo backup[9] = b43legacy_phy_read(dev, 0x0059);
556423e3ce3SKalle Valo backup[10] = b43legacy_phy_read(dev, 0x0058);
557423e3ce3SKalle Valo backup[11] = b43legacy_read16(dev, 0x03E2);
558423e3ce3SKalle Valo backup[12] = b43legacy_read16(dev, 0x03E6);
559423e3ce3SKalle Valo backup[13] = b43legacy_read16(dev, B43legacy_MMIO_CHANNEL_EXT);
560423e3ce3SKalle Valo
561423e3ce3SKalle Valo tmp = b43legacy_radio_read16(dev, 0x007A);
562423e3ce3SKalle Valo tmp &= (phy->rev >= 5) ? 0x007F : 0x000F;
563423e3ce3SKalle Valo b43legacy_radio_write16(dev, 0x007A, tmp);
564423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0030, 0x00FF);
565423e3ce3SKalle Valo b43legacy_write16(dev, 0x03EC, 0x7F7F);
566423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0026, 0x0000);
567423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0015,
568423e3ce3SKalle Valo b43legacy_phy_read(dev, 0x0015) | 0x0020);
569423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x002A, 0x08A3);
570423e3ce3SKalle Valo b43legacy_radio_write16(dev, 0x007A,
571423e3ce3SKalle Valo b43legacy_radio_read16(dev, 0x007A)
572423e3ce3SKalle Valo | 0x0080);
573423e3ce3SKalle Valo
574423e3ce3SKalle Valo nrssi0 = (s16)b43legacy_phy_read(dev, 0x0027);
575423e3ce3SKalle Valo b43legacy_radio_write16(dev, 0x007A,
576423e3ce3SKalle Valo b43legacy_radio_read16(dev, 0x007A)
577423e3ce3SKalle Valo & 0x007F);
578423e3ce3SKalle Valo if (phy->analog >= 2)
579423e3ce3SKalle Valo b43legacy_write16(dev, 0x03E6, 0x0040);
580423e3ce3SKalle Valo else if (phy->analog == 0)
581423e3ce3SKalle Valo b43legacy_write16(dev, 0x03E6, 0x0122);
582423e3ce3SKalle Valo else
583423e3ce3SKalle Valo b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT,
584423e3ce3SKalle Valo b43legacy_read16(dev,
585423e3ce3SKalle Valo B43legacy_MMIO_CHANNEL_EXT) & 0x2000);
586423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0020, 0x3F3F);
587423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0015, 0xF330);
588423e3ce3SKalle Valo b43legacy_radio_write16(dev, 0x005A, 0x0060);
589423e3ce3SKalle Valo b43legacy_radio_write16(dev, 0x0043,
590423e3ce3SKalle Valo b43legacy_radio_read16(dev, 0x0043)
591423e3ce3SKalle Valo & 0x00F0);
592423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x005A, 0x0480);
593423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0059, 0x0810);
594423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0058, 0x000D);
595423e3ce3SKalle Valo udelay(20);
596423e3ce3SKalle Valo
597423e3ce3SKalle Valo nrssi1 = (s16)b43legacy_phy_read(dev, 0x0027);
598423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0030, backup[3]);
599423e3ce3SKalle Valo b43legacy_radio_write16(dev, 0x007A, backup[0]);
600423e3ce3SKalle Valo b43legacy_write16(dev, 0x03E2, backup[11]);
601423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0026, backup[4]);
602423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0015, backup[5]);
603423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x002A, backup[6]);
604423e3ce3SKalle Valo b43legacy_synth_pu_workaround(dev, phy->channel);
605423e3ce3SKalle Valo if (phy->analog != 0)
606423e3ce3SKalle Valo b43legacy_write16(dev, 0x03F4, backup[13]);
607423e3ce3SKalle Valo
608423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0020, backup[7]);
609423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x005A, backup[8]);
610423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0059, backup[9]);
611423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0058, backup[10]);
612423e3ce3SKalle Valo b43legacy_radio_write16(dev, 0x0052, backup[1]);
613423e3ce3SKalle Valo b43legacy_radio_write16(dev, 0x0043, backup[2]);
614423e3ce3SKalle Valo
615423e3ce3SKalle Valo if (nrssi0 == nrssi1)
616423e3ce3SKalle Valo phy->nrssislope = 0x00010000;
617423e3ce3SKalle Valo else
618423e3ce3SKalle Valo phy->nrssislope = 0x00400000 / (nrssi0 - nrssi1);
619423e3ce3SKalle Valo
620423e3ce3SKalle Valo if (nrssi0 <= -4) {
621423e3ce3SKalle Valo phy->nrssi[0] = nrssi0;
622423e3ce3SKalle Valo phy->nrssi[1] = nrssi1;
623423e3ce3SKalle Valo }
624423e3ce3SKalle Valo break;
625423e3ce3SKalle Valo case B43legacy_PHYTYPE_G:
626423e3ce3SKalle Valo if (phy->radio_rev >= 9)
627423e3ce3SKalle Valo return;
628423e3ce3SKalle Valo if (phy->radio_rev == 8)
629423e3ce3SKalle Valo b43legacy_calc_nrssi_offset(dev);
630423e3ce3SKalle Valo
631423e3ce3SKalle Valo b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
632423e3ce3SKalle Valo b43legacy_phy_read(dev, B43legacy_PHY_G_CRS)
633423e3ce3SKalle Valo & 0x7FFF);
634423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0802,
635423e3ce3SKalle Valo b43legacy_phy_read(dev, 0x0802) & 0xFFFC);
636423e3ce3SKalle Valo backup[7] = b43legacy_read16(dev, 0x03E2);
637423e3ce3SKalle Valo b43legacy_write16(dev, 0x03E2,
638423e3ce3SKalle Valo b43legacy_read16(dev, 0x03E2) | 0x8000);
639423e3ce3SKalle Valo backup[0] = b43legacy_radio_read16(dev, 0x007A);
640423e3ce3SKalle Valo backup[1] = b43legacy_radio_read16(dev, 0x0052);
641423e3ce3SKalle Valo backup[2] = b43legacy_radio_read16(dev, 0x0043);
642423e3ce3SKalle Valo backup[3] = b43legacy_phy_read(dev, 0x0015);
643423e3ce3SKalle Valo backup[4] = b43legacy_phy_read(dev, 0x005A);
644423e3ce3SKalle Valo backup[5] = b43legacy_phy_read(dev, 0x0059);
645423e3ce3SKalle Valo backup[6] = b43legacy_phy_read(dev, 0x0058);
646423e3ce3SKalle Valo backup[8] = b43legacy_read16(dev, 0x03E6);
647423e3ce3SKalle Valo backup[9] = b43legacy_read16(dev, B43legacy_MMIO_CHANNEL_EXT);
648423e3ce3SKalle Valo if (phy->rev >= 3) {
649423e3ce3SKalle Valo backup[10] = b43legacy_phy_read(dev, 0x002E);
650423e3ce3SKalle Valo backup[11] = b43legacy_phy_read(dev, 0x002F);
651423e3ce3SKalle Valo backup[12] = b43legacy_phy_read(dev, 0x080F);
652423e3ce3SKalle Valo backup[13] = b43legacy_phy_read(dev,
653423e3ce3SKalle Valo B43legacy_PHY_G_LO_CONTROL);
654423e3ce3SKalle Valo backup[14] = b43legacy_phy_read(dev, 0x0801);
655423e3ce3SKalle Valo backup[15] = b43legacy_phy_read(dev, 0x0060);
656423e3ce3SKalle Valo backup[16] = b43legacy_phy_read(dev, 0x0014);
657423e3ce3SKalle Valo backup[17] = b43legacy_phy_read(dev, 0x0478);
658423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x002E, 0);
659423e3ce3SKalle Valo b43legacy_phy_write(dev, B43legacy_PHY_G_LO_CONTROL, 0);
660423e3ce3SKalle Valo switch (phy->rev) {
661423e3ce3SKalle Valo case 4: case 6: case 7:
662423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0478,
663423e3ce3SKalle Valo b43legacy_phy_read(dev,
664423e3ce3SKalle Valo 0x0478) | 0x0100);
665423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0801,
666423e3ce3SKalle Valo b43legacy_phy_read(dev,
667423e3ce3SKalle Valo 0x0801) | 0x0040);
668423e3ce3SKalle Valo break;
669423e3ce3SKalle Valo case 3: case 5:
670423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0801,
671423e3ce3SKalle Valo b43legacy_phy_read(dev,
672423e3ce3SKalle Valo 0x0801) & 0xFFBF);
673423e3ce3SKalle Valo break;
674423e3ce3SKalle Valo }
675423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0060,
676423e3ce3SKalle Valo b43legacy_phy_read(dev, 0x0060)
677423e3ce3SKalle Valo | 0x0040);
678423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0014,
679423e3ce3SKalle Valo b43legacy_phy_read(dev, 0x0014)
680423e3ce3SKalle Valo | 0x0200);
681423e3ce3SKalle Valo }
682423e3ce3SKalle Valo b43legacy_radio_write16(dev, 0x007A,
683423e3ce3SKalle Valo b43legacy_radio_read16(dev, 0x007A)
684423e3ce3SKalle Valo | 0x0070);
685423e3ce3SKalle Valo b43legacy_set_all_gains(dev, 0, 8, 0);
686423e3ce3SKalle Valo b43legacy_radio_write16(dev, 0x007A,
687423e3ce3SKalle Valo b43legacy_radio_read16(dev, 0x007A)
688423e3ce3SKalle Valo & 0x00F7);
689423e3ce3SKalle Valo if (phy->rev >= 2) {
690423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0811,
691423e3ce3SKalle Valo (b43legacy_phy_read(dev, 0x0811)
692423e3ce3SKalle Valo & 0xFFCF) | 0x0030);
693423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0812,
694423e3ce3SKalle Valo (b43legacy_phy_read(dev, 0x0812)
695423e3ce3SKalle Valo & 0xFFCF) | 0x0010);
696423e3ce3SKalle Valo }
697423e3ce3SKalle Valo b43legacy_radio_write16(dev, 0x007A,
698423e3ce3SKalle Valo b43legacy_radio_read16(dev, 0x007A)
699423e3ce3SKalle Valo | 0x0080);
700423e3ce3SKalle Valo udelay(20);
701423e3ce3SKalle Valo
702423e3ce3SKalle Valo nrssi0 = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) & 0x003F);
703423e3ce3SKalle Valo if (nrssi0 >= 0x0020)
704423e3ce3SKalle Valo nrssi0 -= 0x0040;
705423e3ce3SKalle Valo
706423e3ce3SKalle Valo b43legacy_radio_write16(dev, 0x007A,
707423e3ce3SKalle Valo b43legacy_radio_read16(dev, 0x007A)
708423e3ce3SKalle Valo & 0x007F);
709423e3ce3SKalle Valo if (phy->analog >= 2)
710423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0003,
711423e3ce3SKalle Valo (b43legacy_phy_read(dev, 0x0003)
712423e3ce3SKalle Valo & 0xFF9F) | 0x0040);
713423e3ce3SKalle Valo
714423e3ce3SKalle Valo b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT,
715423e3ce3SKalle Valo b43legacy_read16(dev,
716423e3ce3SKalle Valo B43legacy_MMIO_CHANNEL_EXT) | 0x2000);
717423e3ce3SKalle Valo b43legacy_radio_write16(dev, 0x007A,
718423e3ce3SKalle Valo b43legacy_radio_read16(dev, 0x007A)
719423e3ce3SKalle Valo | 0x000F);
720423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0015, 0xF330);
721423e3ce3SKalle Valo if (phy->rev >= 2) {
722423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0812,
723423e3ce3SKalle Valo (b43legacy_phy_read(dev, 0x0812)
724423e3ce3SKalle Valo & 0xFFCF) | 0x0020);
725423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0811,
726423e3ce3SKalle Valo (b43legacy_phy_read(dev, 0x0811)
727423e3ce3SKalle Valo & 0xFFCF) | 0x0020);
728423e3ce3SKalle Valo }
729423e3ce3SKalle Valo
730423e3ce3SKalle Valo b43legacy_set_all_gains(dev, 3, 0, 1);
731423e3ce3SKalle Valo if (phy->radio_rev == 8)
732423e3ce3SKalle Valo b43legacy_radio_write16(dev, 0x0043, 0x001F);
733423e3ce3SKalle Valo else {
734423e3ce3SKalle Valo tmp = b43legacy_radio_read16(dev, 0x0052) & 0xFF0F;
735423e3ce3SKalle Valo b43legacy_radio_write16(dev, 0x0052, tmp | 0x0060);
736423e3ce3SKalle Valo tmp = b43legacy_radio_read16(dev, 0x0043) & 0xFFF0;
737423e3ce3SKalle Valo b43legacy_radio_write16(dev, 0x0043, tmp | 0x0009);
738423e3ce3SKalle Valo }
739423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x005A, 0x0480);
740423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0059, 0x0810);
741423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0058, 0x000D);
742423e3ce3SKalle Valo udelay(20);
743423e3ce3SKalle Valo nrssi1 = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) & 0x003F);
744423e3ce3SKalle Valo if (nrssi1 >= 0x0020)
745423e3ce3SKalle Valo nrssi1 -= 0x0040;
746423e3ce3SKalle Valo if (nrssi0 == nrssi1)
747423e3ce3SKalle Valo phy->nrssislope = 0x00010000;
748423e3ce3SKalle Valo else
749423e3ce3SKalle Valo phy->nrssislope = 0x00400000 / (nrssi0 - nrssi1);
750423e3ce3SKalle Valo if (nrssi0 >= -4) {
751423e3ce3SKalle Valo phy->nrssi[0] = nrssi1;
752423e3ce3SKalle Valo phy->nrssi[1] = nrssi0;
753423e3ce3SKalle Valo }
754423e3ce3SKalle Valo if (phy->rev >= 3) {
755423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x002E, backup[10]);
756423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x002F, backup[11]);
757423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x080F, backup[12]);
758423e3ce3SKalle Valo b43legacy_phy_write(dev, B43legacy_PHY_G_LO_CONTROL,
759423e3ce3SKalle Valo backup[13]);
760423e3ce3SKalle Valo }
761423e3ce3SKalle Valo if (phy->rev >= 2) {
762423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0812,
763423e3ce3SKalle Valo b43legacy_phy_read(dev, 0x0812)
764423e3ce3SKalle Valo & 0xFFCF);
765423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0811,
766423e3ce3SKalle Valo b43legacy_phy_read(dev, 0x0811)
767423e3ce3SKalle Valo & 0xFFCF);
768423e3ce3SKalle Valo }
769423e3ce3SKalle Valo
770423e3ce3SKalle Valo b43legacy_radio_write16(dev, 0x007A, backup[0]);
771423e3ce3SKalle Valo b43legacy_radio_write16(dev, 0x0052, backup[1]);
772423e3ce3SKalle Valo b43legacy_radio_write16(dev, 0x0043, backup[2]);
773423e3ce3SKalle Valo b43legacy_write16(dev, 0x03E2, backup[7]);
774423e3ce3SKalle Valo b43legacy_write16(dev, 0x03E6, backup[8]);
775423e3ce3SKalle Valo b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, backup[9]);
776423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0015, backup[3]);
777423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x005A, backup[4]);
778423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0059, backup[5]);
779423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0058, backup[6]);
780423e3ce3SKalle Valo b43legacy_synth_pu_workaround(dev, phy->channel);
781423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0802,
782423e3ce3SKalle Valo b43legacy_phy_read(dev, 0x0802) | 0x0003);
783423e3ce3SKalle Valo b43legacy_set_original_gains(dev);
784423e3ce3SKalle Valo b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
785423e3ce3SKalle Valo b43legacy_phy_read(dev, B43legacy_PHY_G_CRS)
786423e3ce3SKalle Valo | 0x8000);
787423e3ce3SKalle Valo if (phy->rev >= 3) {
788423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0801, backup[14]);
789423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0060, backup[15]);
790423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0014, backup[16]);
791423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0478, backup[17]);
792423e3ce3SKalle Valo }
793423e3ce3SKalle Valo b43legacy_nrssi_mem_update(dev);
794423e3ce3SKalle Valo b43legacy_calc_nrssi_threshold(dev);
795423e3ce3SKalle Valo break;
796423e3ce3SKalle Valo default:
797423e3ce3SKalle Valo B43legacy_BUG_ON(1);
798423e3ce3SKalle Valo }
799423e3ce3SKalle Valo }
800423e3ce3SKalle Valo
b43legacy_calc_nrssi_threshold(struct b43legacy_wldev * dev)801423e3ce3SKalle Valo void b43legacy_calc_nrssi_threshold(struct b43legacy_wldev *dev)
802423e3ce3SKalle Valo {
803423e3ce3SKalle Valo struct b43legacy_phy *phy = &dev->phy;
804423e3ce3SKalle Valo s32 threshold;
805423e3ce3SKalle Valo s32 a;
806423e3ce3SKalle Valo s32 b;
807423e3ce3SKalle Valo s16 tmp16;
808423e3ce3SKalle Valo u16 tmp_u16;
809423e3ce3SKalle Valo
810423e3ce3SKalle Valo switch (phy->type) {
811423e3ce3SKalle Valo case B43legacy_PHYTYPE_B: {
812423e3ce3SKalle Valo if (phy->radio_ver != 0x2050)
813423e3ce3SKalle Valo return;
814423e3ce3SKalle Valo if (!(dev->dev->bus->sprom.boardflags_lo &
815423e3ce3SKalle Valo B43legacy_BFL_RSSI))
816423e3ce3SKalle Valo return;
817423e3ce3SKalle Valo
818423e3ce3SKalle Valo if (phy->radio_rev >= 6) {
819423e3ce3SKalle Valo threshold = (phy->nrssi[1] - phy->nrssi[0]) * 32;
820423e3ce3SKalle Valo threshold += 20 * (phy->nrssi[0] + 1);
821423e3ce3SKalle Valo threshold /= 40;
822423e3ce3SKalle Valo } else
823423e3ce3SKalle Valo threshold = phy->nrssi[1] - 5;
824423e3ce3SKalle Valo
825423e3ce3SKalle Valo threshold = clamp_val(threshold, 0, 0x3E);
826423e3ce3SKalle Valo b43legacy_phy_read(dev, 0x0020); /* dummy read */
827423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0020, (((u16)threshold) << 8)
828423e3ce3SKalle Valo | 0x001C);
829423e3ce3SKalle Valo
830423e3ce3SKalle Valo if (phy->radio_rev >= 6) {
831423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0087, 0x0E0D);
832423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0086, 0x0C0B);
833423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0085, 0x0A09);
834423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0084, 0x0808);
835423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0083, 0x0808);
836423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0082, 0x0604);
837423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0081, 0x0302);
838423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0080, 0x0100);
839423e3ce3SKalle Valo }
840423e3ce3SKalle Valo break;
841423e3ce3SKalle Valo }
842423e3ce3SKalle Valo case B43legacy_PHYTYPE_G:
843423e3ce3SKalle Valo if (!phy->gmode ||
844423e3ce3SKalle Valo !(dev->dev->bus->sprom.boardflags_lo &
845423e3ce3SKalle Valo B43legacy_BFL_RSSI)) {
846423e3ce3SKalle Valo tmp16 = b43legacy_nrssi_hw_read(dev, 0x20);
847423e3ce3SKalle Valo if (tmp16 >= 0x20)
848423e3ce3SKalle Valo tmp16 -= 0x40;
849423e3ce3SKalle Valo if (tmp16 < 3)
850423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x048A,
851423e3ce3SKalle Valo (b43legacy_phy_read(dev,
852423e3ce3SKalle Valo 0x048A) & 0xF000) | 0x09EB);
853423e3ce3SKalle Valo else
854423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x048A,
855423e3ce3SKalle Valo (b43legacy_phy_read(dev,
856423e3ce3SKalle Valo 0x048A) & 0xF000) | 0x0AED);
857423e3ce3SKalle Valo } else {
858423e3ce3SKalle Valo if (phy->interfmode ==
859423e3ce3SKalle Valo B43legacy_RADIO_INTERFMODE_NONWLAN) {
860423e3ce3SKalle Valo a = 0xE;
861423e3ce3SKalle Valo b = 0xA;
862423e3ce3SKalle Valo } else if (!phy->aci_wlan_automatic &&
863423e3ce3SKalle Valo phy->aci_enable) {
864423e3ce3SKalle Valo a = 0x13;
865423e3ce3SKalle Valo b = 0x12;
866423e3ce3SKalle Valo } else {
867423e3ce3SKalle Valo a = 0xE;
868423e3ce3SKalle Valo b = 0x11;
869423e3ce3SKalle Valo }
870423e3ce3SKalle Valo
871423e3ce3SKalle Valo a = a * (phy->nrssi[1] - phy->nrssi[0]);
872423e3ce3SKalle Valo a += (phy->nrssi[0] << 6);
873423e3ce3SKalle Valo if (a < 32)
874423e3ce3SKalle Valo a += 31;
875423e3ce3SKalle Valo else
876423e3ce3SKalle Valo a += 32;
877423e3ce3SKalle Valo a = a >> 6;
878423e3ce3SKalle Valo a = clamp_val(a, -31, 31);
879423e3ce3SKalle Valo
880423e3ce3SKalle Valo b = b * (phy->nrssi[1] - phy->nrssi[0]);
881423e3ce3SKalle Valo b += (phy->nrssi[0] << 6);
882423e3ce3SKalle Valo if (b < 32)
883423e3ce3SKalle Valo b += 31;
884423e3ce3SKalle Valo else
885423e3ce3SKalle Valo b += 32;
886423e3ce3SKalle Valo b = b >> 6;
887423e3ce3SKalle Valo b = clamp_val(b, -31, 31);
888423e3ce3SKalle Valo
889423e3ce3SKalle Valo tmp_u16 = b43legacy_phy_read(dev, 0x048A) & 0xF000;
890423e3ce3SKalle Valo tmp_u16 |= ((u32)b & 0x0000003F);
891423e3ce3SKalle Valo tmp_u16 |= (((u32)a & 0x0000003F) << 6);
892423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x048A, tmp_u16);
893423e3ce3SKalle Valo }
894423e3ce3SKalle Valo break;
895423e3ce3SKalle Valo default:
896423e3ce3SKalle Valo B43legacy_BUG_ON(1);
897423e3ce3SKalle Valo }
898423e3ce3SKalle Valo }
899423e3ce3SKalle Valo
900423e3ce3SKalle Valo /* Stack implementation to save/restore values from the
901423e3ce3SKalle Valo * interference mitigation code.
902423e3ce3SKalle Valo * It is save to restore values in random order.
903423e3ce3SKalle Valo */
_stack_save(u32 * _stackptr,size_t * stackidx,u8 id,u16 offset,u16 value)904423e3ce3SKalle Valo static void _stack_save(u32 *_stackptr, size_t *stackidx,
905423e3ce3SKalle Valo u8 id, u16 offset, u16 value)
906423e3ce3SKalle Valo {
907423e3ce3SKalle Valo u32 *stackptr = &(_stackptr[*stackidx]);
908423e3ce3SKalle Valo
909423e3ce3SKalle Valo B43legacy_WARN_ON(!((offset & 0xE000) == 0x0000));
910423e3ce3SKalle Valo B43legacy_WARN_ON(!((id & 0xF8) == 0x00));
911423e3ce3SKalle Valo *stackptr = offset;
912423e3ce3SKalle Valo *stackptr |= ((u32)id) << 13;
913423e3ce3SKalle Valo *stackptr |= ((u32)value) << 16;
914423e3ce3SKalle Valo (*stackidx)++;
915423e3ce3SKalle Valo B43legacy_WARN_ON(!(*stackidx < B43legacy_INTERFSTACK_SIZE));
916423e3ce3SKalle Valo }
917423e3ce3SKalle Valo
_stack_restore(u32 * stackptr,u8 id,u16 offset)918423e3ce3SKalle Valo static u16 _stack_restore(u32 *stackptr,
919423e3ce3SKalle Valo u8 id, u16 offset)
920423e3ce3SKalle Valo {
921423e3ce3SKalle Valo size_t i;
922423e3ce3SKalle Valo
923423e3ce3SKalle Valo B43legacy_WARN_ON(!((offset & 0xE000) == 0x0000));
924423e3ce3SKalle Valo B43legacy_WARN_ON(!((id & 0xF8) == 0x00));
925423e3ce3SKalle Valo for (i = 0; i < B43legacy_INTERFSTACK_SIZE; i++, stackptr++) {
926423e3ce3SKalle Valo if ((*stackptr & 0x00001FFF) != offset)
927423e3ce3SKalle Valo continue;
928423e3ce3SKalle Valo if (((*stackptr & 0x00007000) >> 13) != id)
929423e3ce3SKalle Valo continue;
930423e3ce3SKalle Valo return ((*stackptr & 0xFFFF0000) >> 16);
931423e3ce3SKalle Valo }
932423e3ce3SKalle Valo B43legacy_BUG_ON(1);
933423e3ce3SKalle Valo
934423e3ce3SKalle Valo return 0;
935423e3ce3SKalle Valo }
936423e3ce3SKalle Valo
937423e3ce3SKalle Valo #define phy_stacksave(offset) \
938423e3ce3SKalle Valo do { \
939423e3ce3SKalle Valo _stack_save(stack, &stackidx, 0x1, (offset), \
940423e3ce3SKalle Valo b43legacy_phy_read(dev, (offset))); \
941423e3ce3SKalle Valo } while (0)
942423e3ce3SKalle Valo #define phy_stackrestore(offset) \
943423e3ce3SKalle Valo do { \
944423e3ce3SKalle Valo b43legacy_phy_write(dev, (offset), \
945423e3ce3SKalle Valo _stack_restore(stack, 0x1, \
946423e3ce3SKalle Valo (offset))); \
947423e3ce3SKalle Valo } while (0)
948423e3ce3SKalle Valo #define radio_stacksave(offset) \
949423e3ce3SKalle Valo do { \
950423e3ce3SKalle Valo _stack_save(stack, &stackidx, 0x2, (offset), \
951423e3ce3SKalle Valo b43legacy_radio_read16(dev, (offset))); \
952423e3ce3SKalle Valo } while (0)
953423e3ce3SKalle Valo #define radio_stackrestore(offset) \
954423e3ce3SKalle Valo do { \
955423e3ce3SKalle Valo b43legacy_radio_write16(dev, (offset), \
956423e3ce3SKalle Valo _stack_restore(stack, 0x2, \
957423e3ce3SKalle Valo (offset))); \
958423e3ce3SKalle Valo } while (0)
959423e3ce3SKalle Valo #define ilt_stacksave(offset) \
960423e3ce3SKalle Valo do { \
961423e3ce3SKalle Valo _stack_save(stack, &stackidx, 0x3, (offset), \
962423e3ce3SKalle Valo b43legacy_ilt_read(dev, (offset))); \
963423e3ce3SKalle Valo } while (0)
964423e3ce3SKalle Valo #define ilt_stackrestore(offset) \
965423e3ce3SKalle Valo do { \
966423e3ce3SKalle Valo b43legacy_ilt_write(dev, (offset), \
967423e3ce3SKalle Valo _stack_restore(stack, 0x3, \
968423e3ce3SKalle Valo (offset))); \
969423e3ce3SKalle Valo } while (0)
970423e3ce3SKalle Valo
971423e3ce3SKalle Valo static void
b43legacy_radio_interference_mitigation_enable(struct b43legacy_wldev * dev,int mode)972423e3ce3SKalle Valo b43legacy_radio_interference_mitigation_enable(struct b43legacy_wldev *dev,
973423e3ce3SKalle Valo int mode)
974423e3ce3SKalle Valo {
975423e3ce3SKalle Valo struct b43legacy_phy *phy = &dev->phy;
976423e3ce3SKalle Valo u16 tmp;
977423e3ce3SKalle Valo u16 flipped;
978423e3ce3SKalle Valo u32 tmp32;
979423e3ce3SKalle Valo size_t stackidx = 0;
980423e3ce3SKalle Valo u32 *stack = phy->interfstack;
981423e3ce3SKalle Valo
982423e3ce3SKalle Valo switch (mode) {
983423e3ce3SKalle Valo case B43legacy_RADIO_INTERFMODE_NONWLAN:
984423e3ce3SKalle Valo if (phy->rev != 1) {
985423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x042B,
986423e3ce3SKalle Valo b43legacy_phy_read(dev, 0x042B)
987423e3ce3SKalle Valo | 0x0800);
988423e3ce3SKalle Valo b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
989423e3ce3SKalle Valo b43legacy_phy_read(dev,
990423e3ce3SKalle Valo B43legacy_PHY_G_CRS) & ~0x4000);
991423e3ce3SKalle Valo break;
992423e3ce3SKalle Valo }
993423e3ce3SKalle Valo radio_stacksave(0x0078);
994423e3ce3SKalle Valo tmp = (b43legacy_radio_read16(dev, 0x0078) & 0x001E);
995423e3ce3SKalle Valo flipped = flip_4bit(tmp);
996423e3ce3SKalle Valo if (flipped < 10 && flipped >= 8)
997423e3ce3SKalle Valo flipped = 7;
998423e3ce3SKalle Valo else if (flipped >= 10)
999423e3ce3SKalle Valo flipped -= 3;
1000423e3ce3SKalle Valo flipped = flip_4bit(flipped);
1001423e3ce3SKalle Valo flipped = (flipped << 1) | 0x0020;
1002423e3ce3SKalle Valo b43legacy_radio_write16(dev, 0x0078, flipped);
1003423e3ce3SKalle Valo
1004423e3ce3SKalle Valo b43legacy_calc_nrssi_threshold(dev);
1005423e3ce3SKalle Valo
1006423e3ce3SKalle Valo phy_stacksave(0x0406);
1007423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0406, 0x7E28);
1008423e3ce3SKalle Valo
1009423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x042B,
1010423e3ce3SKalle Valo b43legacy_phy_read(dev, 0x042B) | 0x0800);
1011423e3ce3SKalle Valo b43legacy_phy_write(dev, B43legacy_PHY_RADIO_BITFIELD,
1012423e3ce3SKalle Valo b43legacy_phy_read(dev,
1013423e3ce3SKalle Valo B43legacy_PHY_RADIO_BITFIELD) | 0x1000);
1014423e3ce3SKalle Valo
1015423e3ce3SKalle Valo phy_stacksave(0x04A0);
1016423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x04A0,
1017423e3ce3SKalle Valo (b43legacy_phy_read(dev, 0x04A0) & 0xC0C0)
1018423e3ce3SKalle Valo | 0x0008);
1019423e3ce3SKalle Valo phy_stacksave(0x04A1);
1020423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x04A1,
1021423e3ce3SKalle Valo (b43legacy_phy_read(dev, 0x04A1) & 0xC0C0)
1022423e3ce3SKalle Valo | 0x0605);
1023423e3ce3SKalle Valo phy_stacksave(0x04A2);
1024423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x04A2,
1025423e3ce3SKalle Valo (b43legacy_phy_read(dev, 0x04A2) & 0xC0C0)
1026423e3ce3SKalle Valo | 0x0204);
1027423e3ce3SKalle Valo phy_stacksave(0x04A8);
1028423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x04A8,
1029423e3ce3SKalle Valo (b43legacy_phy_read(dev, 0x04A8) & 0xC0C0)
1030423e3ce3SKalle Valo | 0x0803);
1031423e3ce3SKalle Valo phy_stacksave(0x04AB);
1032423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x04AB,
1033423e3ce3SKalle Valo (b43legacy_phy_read(dev, 0x04AB) & 0xC0C0)
1034423e3ce3SKalle Valo | 0x0605);
1035423e3ce3SKalle Valo
1036423e3ce3SKalle Valo phy_stacksave(0x04A7);
1037423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x04A7, 0x0002);
1038423e3ce3SKalle Valo phy_stacksave(0x04A3);
1039423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x04A3, 0x287A);
1040423e3ce3SKalle Valo phy_stacksave(0x04A9);
1041423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x04A9, 0x2027);
1042423e3ce3SKalle Valo phy_stacksave(0x0493);
1043423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0493, 0x32F5);
1044423e3ce3SKalle Valo phy_stacksave(0x04AA);
1045423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x04AA, 0x2027);
1046423e3ce3SKalle Valo phy_stacksave(0x04AC);
1047423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x04AC, 0x32F5);
1048423e3ce3SKalle Valo break;
1049423e3ce3SKalle Valo case B43legacy_RADIO_INTERFMODE_MANUALWLAN:
1050423e3ce3SKalle Valo if (b43legacy_phy_read(dev, 0x0033) & 0x0800)
1051423e3ce3SKalle Valo break;
1052423e3ce3SKalle Valo
1053423e3ce3SKalle Valo phy->aci_enable = true;
1054423e3ce3SKalle Valo
1055423e3ce3SKalle Valo phy_stacksave(B43legacy_PHY_RADIO_BITFIELD);
1056423e3ce3SKalle Valo phy_stacksave(B43legacy_PHY_G_CRS);
1057423e3ce3SKalle Valo if (phy->rev < 2)
1058423e3ce3SKalle Valo phy_stacksave(0x0406);
1059423e3ce3SKalle Valo else {
1060423e3ce3SKalle Valo phy_stacksave(0x04C0);
1061423e3ce3SKalle Valo phy_stacksave(0x04C1);
1062423e3ce3SKalle Valo }
1063423e3ce3SKalle Valo phy_stacksave(0x0033);
1064423e3ce3SKalle Valo phy_stacksave(0x04A7);
1065423e3ce3SKalle Valo phy_stacksave(0x04A3);
1066423e3ce3SKalle Valo phy_stacksave(0x04A9);
1067423e3ce3SKalle Valo phy_stacksave(0x04AA);
1068423e3ce3SKalle Valo phy_stacksave(0x04AC);
1069423e3ce3SKalle Valo phy_stacksave(0x0493);
1070423e3ce3SKalle Valo phy_stacksave(0x04A1);
1071423e3ce3SKalle Valo phy_stacksave(0x04A0);
1072423e3ce3SKalle Valo phy_stacksave(0x04A2);
1073423e3ce3SKalle Valo phy_stacksave(0x048A);
1074423e3ce3SKalle Valo phy_stacksave(0x04A8);
1075423e3ce3SKalle Valo phy_stacksave(0x04AB);
1076423e3ce3SKalle Valo if (phy->rev == 2) {
1077423e3ce3SKalle Valo phy_stacksave(0x04AD);
1078423e3ce3SKalle Valo phy_stacksave(0x04AE);
1079423e3ce3SKalle Valo } else if (phy->rev >= 3) {
1080423e3ce3SKalle Valo phy_stacksave(0x04AD);
1081423e3ce3SKalle Valo phy_stacksave(0x0415);
1082423e3ce3SKalle Valo phy_stacksave(0x0416);
1083423e3ce3SKalle Valo phy_stacksave(0x0417);
1084423e3ce3SKalle Valo ilt_stacksave(0x1A00 + 0x2);
1085423e3ce3SKalle Valo ilt_stacksave(0x1A00 + 0x3);
1086423e3ce3SKalle Valo }
1087423e3ce3SKalle Valo phy_stacksave(0x042B);
1088423e3ce3SKalle Valo phy_stacksave(0x048C);
1089423e3ce3SKalle Valo
1090423e3ce3SKalle Valo b43legacy_phy_write(dev, B43legacy_PHY_RADIO_BITFIELD,
1091423e3ce3SKalle Valo b43legacy_phy_read(dev,
1092423e3ce3SKalle Valo B43legacy_PHY_RADIO_BITFIELD) & ~0x1000);
1093423e3ce3SKalle Valo b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
1094423e3ce3SKalle Valo (b43legacy_phy_read(dev,
1095423e3ce3SKalle Valo B43legacy_PHY_G_CRS)
1096423e3ce3SKalle Valo & 0xFFFC) | 0x0002);
1097423e3ce3SKalle Valo
1098423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0033, 0x0800);
1099423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x04A3, 0x2027);
1100423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x04A9, 0x1CA8);
1101423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0493, 0x287A);
1102423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x04AA, 0x1CA8);
1103423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x04AC, 0x287A);
1104423e3ce3SKalle Valo
1105423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x04A0,
1106423e3ce3SKalle Valo (b43legacy_phy_read(dev, 0x04A0)
1107423e3ce3SKalle Valo & 0xFFC0) | 0x001A);
1108423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x04A7, 0x000D);
1109423e3ce3SKalle Valo
1110423e3ce3SKalle Valo if (phy->rev < 2)
1111423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0406, 0xFF0D);
1112423e3ce3SKalle Valo else if (phy->rev == 2) {
1113423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x04C0, 0xFFFF);
1114423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x04C1, 0x00A9);
1115423e3ce3SKalle Valo } else {
1116423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x04C0, 0x00C1);
1117423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x04C1, 0x0059);
1118423e3ce3SKalle Valo }
1119423e3ce3SKalle Valo
1120423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x04A1,
1121423e3ce3SKalle Valo (b43legacy_phy_read(dev, 0x04A1)
1122423e3ce3SKalle Valo & 0xC0FF) | 0x1800);
1123423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x04A1,
1124423e3ce3SKalle Valo (b43legacy_phy_read(dev, 0x04A1)
1125423e3ce3SKalle Valo & 0xFFC0) | 0x0015);
1126423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x04A8,
1127423e3ce3SKalle Valo (b43legacy_phy_read(dev, 0x04A8)
1128423e3ce3SKalle Valo & 0xCFFF) | 0x1000);
1129423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x04A8,
1130423e3ce3SKalle Valo (b43legacy_phy_read(dev, 0x04A8)
1131423e3ce3SKalle Valo & 0xF0FF) | 0x0A00);
1132423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x04AB,
1133423e3ce3SKalle Valo (b43legacy_phy_read(dev, 0x04AB)
1134423e3ce3SKalle Valo & 0xCFFF) | 0x1000);
1135423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x04AB,
1136423e3ce3SKalle Valo (b43legacy_phy_read(dev, 0x04AB)
1137423e3ce3SKalle Valo & 0xF0FF) | 0x0800);
1138423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x04AB,
1139423e3ce3SKalle Valo (b43legacy_phy_read(dev, 0x04AB)
1140423e3ce3SKalle Valo & 0xFFCF) | 0x0010);
1141423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x04AB,
1142423e3ce3SKalle Valo (b43legacy_phy_read(dev, 0x04AB)
1143423e3ce3SKalle Valo & 0xFFF0) | 0x0005);
1144423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x04A8,
1145423e3ce3SKalle Valo (b43legacy_phy_read(dev, 0x04A8)
1146423e3ce3SKalle Valo & 0xFFCF) | 0x0010);
1147423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x04A8,
1148423e3ce3SKalle Valo (b43legacy_phy_read(dev, 0x04A8)
1149423e3ce3SKalle Valo & 0xFFF0) | 0x0006);
1150423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x04A2,
1151423e3ce3SKalle Valo (b43legacy_phy_read(dev, 0x04A2)
1152423e3ce3SKalle Valo & 0xF0FF) | 0x0800);
1153423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x04A0,
1154423e3ce3SKalle Valo (b43legacy_phy_read(dev, 0x04A0)
1155423e3ce3SKalle Valo & 0xF0FF) | 0x0500);
1156423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x04A2,
1157423e3ce3SKalle Valo (b43legacy_phy_read(dev, 0x04A2)
1158423e3ce3SKalle Valo & 0xFFF0) | 0x000B);
1159423e3ce3SKalle Valo
1160423e3ce3SKalle Valo if (phy->rev >= 3) {
1161423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x048A,
1162423e3ce3SKalle Valo b43legacy_phy_read(dev, 0x048A)
1163423e3ce3SKalle Valo & ~0x8000);
1164423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0415,
1165423e3ce3SKalle Valo (b43legacy_phy_read(dev, 0x0415)
1166423e3ce3SKalle Valo & 0x8000) | 0x36D8);
1167423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0416,
1168423e3ce3SKalle Valo (b43legacy_phy_read(dev, 0x0416)
1169423e3ce3SKalle Valo & 0x8000) | 0x36D8);
1170423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0417,
1171423e3ce3SKalle Valo (b43legacy_phy_read(dev, 0x0417)
1172423e3ce3SKalle Valo & 0xFE00) | 0x016D);
1173423e3ce3SKalle Valo } else {
1174423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x048A,
1175423e3ce3SKalle Valo b43legacy_phy_read(dev, 0x048A)
1176423e3ce3SKalle Valo | 0x1000);
1177423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x048A,
1178423e3ce3SKalle Valo (b43legacy_phy_read(dev, 0x048A)
1179423e3ce3SKalle Valo & 0x9FFF) | 0x2000);
1180423e3ce3SKalle Valo tmp32 = b43legacy_shm_read32(dev, B43legacy_SHM_SHARED,
1181423e3ce3SKalle Valo B43legacy_UCODEFLAGS_OFFSET);
1182423e3ce3SKalle Valo if (!(tmp32 & 0x800)) {
1183423e3ce3SKalle Valo tmp32 |= 0x800;
1184423e3ce3SKalle Valo b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
1185423e3ce3SKalle Valo B43legacy_UCODEFLAGS_OFFSET,
1186423e3ce3SKalle Valo tmp32);
1187423e3ce3SKalle Valo }
1188423e3ce3SKalle Valo }
1189423e3ce3SKalle Valo if (phy->rev >= 2)
1190423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x042B,
1191423e3ce3SKalle Valo b43legacy_phy_read(dev, 0x042B)
1192423e3ce3SKalle Valo | 0x0800);
1193423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x048C,
1194423e3ce3SKalle Valo (b43legacy_phy_read(dev, 0x048C)
1195423e3ce3SKalle Valo & 0xF0FF) | 0x0200);
1196423e3ce3SKalle Valo if (phy->rev == 2) {
1197423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x04AE,
1198423e3ce3SKalle Valo (b43legacy_phy_read(dev, 0x04AE)
1199423e3ce3SKalle Valo & 0xFF00) | 0x007F);
1200423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x04AD,
1201423e3ce3SKalle Valo (b43legacy_phy_read(dev, 0x04AD)
1202423e3ce3SKalle Valo & 0x00FF) | 0x1300);
1203423e3ce3SKalle Valo } else if (phy->rev >= 6) {
1204423e3ce3SKalle Valo b43legacy_ilt_write(dev, 0x1A00 + 0x3, 0x007F);
1205423e3ce3SKalle Valo b43legacy_ilt_write(dev, 0x1A00 + 0x2, 0x007F);
1206423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x04AD,
1207423e3ce3SKalle Valo b43legacy_phy_read(dev, 0x04AD)
1208423e3ce3SKalle Valo & 0x00FF);
1209423e3ce3SKalle Valo }
1210423e3ce3SKalle Valo b43legacy_calc_nrssi_slope(dev);
1211423e3ce3SKalle Valo break;
1212423e3ce3SKalle Valo default:
1213423e3ce3SKalle Valo B43legacy_BUG_ON(1);
1214423e3ce3SKalle Valo }
1215423e3ce3SKalle Valo }
1216423e3ce3SKalle Valo
1217423e3ce3SKalle Valo static void
b43legacy_radio_interference_mitigation_disable(struct b43legacy_wldev * dev,int mode)1218423e3ce3SKalle Valo b43legacy_radio_interference_mitigation_disable(struct b43legacy_wldev *dev,
1219423e3ce3SKalle Valo int mode)
1220423e3ce3SKalle Valo {
1221423e3ce3SKalle Valo struct b43legacy_phy *phy = &dev->phy;
1222423e3ce3SKalle Valo u32 tmp32;
1223423e3ce3SKalle Valo u32 *stack = phy->interfstack;
1224423e3ce3SKalle Valo
1225423e3ce3SKalle Valo switch (mode) {
1226423e3ce3SKalle Valo case B43legacy_RADIO_INTERFMODE_NONWLAN:
1227423e3ce3SKalle Valo if (phy->rev != 1) {
1228423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x042B,
1229423e3ce3SKalle Valo b43legacy_phy_read(dev, 0x042B)
1230423e3ce3SKalle Valo & ~0x0800);
1231423e3ce3SKalle Valo b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
1232423e3ce3SKalle Valo b43legacy_phy_read(dev,
1233423e3ce3SKalle Valo B43legacy_PHY_G_CRS) | 0x4000);
1234423e3ce3SKalle Valo break;
1235423e3ce3SKalle Valo }
1236423e3ce3SKalle Valo phy_stackrestore(0x0078);
1237423e3ce3SKalle Valo b43legacy_calc_nrssi_threshold(dev);
1238423e3ce3SKalle Valo phy_stackrestore(0x0406);
1239423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x042B,
1240423e3ce3SKalle Valo b43legacy_phy_read(dev, 0x042B) & ~0x0800);
1241423e3ce3SKalle Valo if (!dev->bad_frames_preempt)
1242423e3ce3SKalle Valo b43legacy_phy_write(dev, B43legacy_PHY_RADIO_BITFIELD,
1243423e3ce3SKalle Valo b43legacy_phy_read(dev,
1244423e3ce3SKalle Valo B43legacy_PHY_RADIO_BITFIELD)
1245423e3ce3SKalle Valo & ~(1 << 11));
1246423e3ce3SKalle Valo b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
1247423e3ce3SKalle Valo b43legacy_phy_read(dev, B43legacy_PHY_G_CRS)
1248423e3ce3SKalle Valo | 0x4000);
1249423e3ce3SKalle Valo phy_stackrestore(0x04A0);
1250423e3ce3SKalle Valo phy_stackrestore(0x04A1);
1251423e3ce3SKalle Valo phy_stackrestore(0x04A2);
1252423e3ce3SKalle Valo phy_stackrestore(0x04A8);
1253423e3ce3SKalle Valo phy_stackrestore(0x04AB);
1254423e3ce3SKalle Valo phy_stackrestore(0x04A7);
1255423e3ce3SKalle Valo phy_stackrestore(0x04A3);
1256423e3ce3SKalle Valo phy_stackrestore(0x04A9);
1257423e3ce3SKalle Valo phy_stackrestore(0x0493);
1258423e3ce3SKalle Valo phy_stackrestore(0x04AA);
1259423e3ce3SKalle Valo phy_stackrestore(0x04AC);
1260423e3ce3SKalle Valo break;
1261423e3ce3SKalle Valo case B43legacy_RADIO_INTERFMODE_MANUALWLAN:
1262423e3ce3SKalle Valo if (!(b43legacy_phy_read(dev, 0x0033) & 0x0800))
1263423e3ce3SKalle Valo break;
1264423e3ce3SKalle Valo
1265423e3ce3SKalle Valo phy->aci_enable = false;
1266423e3ce3SKalle Valo
1267423e3ce3SKalle Valo phy_stackrestore(B43legacy_PHY_RADIO_BITFIELD);
1268423e3ce3SKalle Valo phy_stackrestore(B43legacy_PHY_G_CRS);
1269423e3ce3SKalle Valo phy_stackrestore(0x0033);
1270423e3ce3SKalle Valo phy_stackrestore(0x04A3);
1271423e3ce3SKalle Valo phy_stackrestore(0x04A9);
1272423e3ce3SKalle Valo phy_stackrestore(0x0493);
1273423e3ce3SKalle Valo phy_stackrestore(0x04AA);
1274423e3ce3SKalle Valo phy_stackrestore(0x04AC);
1275423e3ce3SKalle Valo phy_stackrestore(0x04A0);
1276423e3ce3SKalle Valo phy_stackrestore(0x04A7);
1277423e3ce3SKalle Valo if (phy->rev >= 2) {
1278423e3ce3SKalle Valo phy_stackrestore(0x04C0);
1279423e3ce3SKalle Valo phy_stackrestore(0x04C1);
1280423e3ce3SKalle Valo } else
1281423e3ce3SKalle Valo phy_stackrestore(0x0406);
1282423e3ce3SKalle Valo phy_stackrestore(0x04A1);
1283423e3ce3SKalle Valo phy_stackrestore(0x04AB);
1284423e3ce3SKalle Valo phy_stackrestore(0x04A8);
1285423e3ce3SKalle Valo if (phy->rev == 2) {
1286423e3ce3SKalle Valo phy_stackrestore(0x04AD);
1287423e3ce3SKalle Valo phy_stackrestore(0x04AE);
1288423e3ce3SKalle Valo } else if (phy->rev >= 3) {
1289423e3ce3SKalle Valo phy_stackrestore(0x04AD);
1290423e3ce3SKalle Valo phy_stackrestore(0x0415);
1291423e3ce3SKalle Valo phy_stackrestore(0x0416);
1292423e3ce3SKalle Valo phy_stackrestore(0x0417);
1293423e3ce3SKalle Valo ilt_stackrestore(0x1A00 + 0x2);
1294423e3ce3SKalle Valo ilt_stackrestore(0x1A00 + 0x3);
1295423e3ce3SKalle Valo }
1296423e3ce3SKalle Valo phy_stackrestore(0x04A2);
1297423e3ce3SKalle Valo phy_stackrestore(0x04A8);
1298423e3ce3SKalle Valo phy_stackrestore(0x042B);
1299423e3ce3SKalle Valo phy_stackrestore(0x048C);
1300423e3ce3SKalle Valo tmp32 = b43legacy_shm_read32(dev, B43legacy_SHM_SHARED,
1301423e3ce3SKalle Valo B43legacy_UCODEFLAGS_OFFSET);
1302423e3ce3SKalle Valo if (tmp32 & 0x800) {
1303423e3ce3SKalle Valo tmp32 &= ~0x800;
1304423e3ce3SKalle Valo b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
1305423e3ce3SKalle Valo B43legacy_UCODEFLAGS_OFFSET,
1306423e3ce3SKalle Valo tmp32);
1307423e3ce3SKalle Valo }
1308423e3ce3SKalle Valo b43legacy_calc_nrssi_slope(dev);
1309423e3ce3SKalle Valo break;
1310423e3ce3SKalle Valo default:
1311423e3ce3SKalle Valo B43legacy_BUG_ON(1);
1312423e3ce3SKalle Valo }
1313423e3ce3SKalle Valo }
1314423e3ce3SKalle Valo
1315423e3ce3SKalle Valo #undef phy_stacksave
1316423e3ce3SKalle Valo #undef phy_stackrestore
1317423e3ce3SKalle Valo #undef radio_stacksave
1318423e3ce3SKalle Valo #undef radio_stackrestore
1319423e3ce3SKalle Valo #undef ilt_stacksave
1320423e3ce3SKalle Valo #undef ilt_stackrestore
1321423e3ce3SKalle Valo
b43legacy_radio_set_interference_mitigation(struct b43legacy_wldev * dev,int mode)1322423e3ce3SKalle Valo int b43legacy_radio_set_interference_mitigation(struct b43legacy_wldev *dev,
1323423e3ce3SKalle Valo int mode)
1324423e3ce3SKalle Valo {
1325423e3ce3SKalle Valo struct b43legacy_phy *phy = &dev->phy;
1326423e3ce3SKalle Valo int currentmode;
1327423e3ce3SKalle Valo
1328423e3ce3SKalle Valo if ((phy->type != B43legacy_PHYTYPE_G) ||
1329423e3ce3SKalle Valo (phy->rev == 0) || (!phy->gmode))
1330423e3ce3SKalle Valo return -ENODEV;
1331423e3ce3SKalle Valo
1332423e3ce3SKalle Valo phy->aci_wlan_automatic = false;
1333423e3ce3SKalle Valo switch (mode) {
1334423e3ce3SKalle Valo case B43legacy_RADIO_INTERFMODE_AUTOWLAN:
1335423e3ce3SKalle Valo phy->aci_wlan_automatic = true;
1336423e3ce3SKalle Valo if (phy->aci_enable)
1337423e3ce3SKalle Valo mode = B43legacy_RADIO_INTERFMODE_MANUALWLAN;
1338423e3ce3SKalle Valo else
1339423e3ce3SKalle Valo mode = B43legacy_RADIO_INTERFMODE_NONE;
1340423e3ce3SKalle Valo break;
1341423e3ce3SKalle Valo case B43legacy_RADIO_INTERFMODE_NONE:
1342423e3ce3SKalle Valo case B43legacy_RADIO_INTERFMODE_NONWLAN:
1343423e3ce3SKalle Valo case B43legacy_RADIO_INTERFMODE_MANUALWLAN:
1344423e3ce3SKalle Valo break;
1345423e3ce3SKalle Valo default:
1346423e3ce3SKalle Valo return -EINVAL;
1347423e3ce3SKalle Valo }
1348423e3ce3SKalle Valo
1349423e3ce3SKalle Valo currentmode = phy->interfmode;
1350423e3ce3SKalle Valo if (currentmode == mode)
1351423e3ce3SKalle Valo return 0;
1352423e3ce3SKalle Valo if (currentmode != B43legacy_RADIO_INTERFMODE_NONE)
1353423e3ce3SKalle Valo b43legacy_radio_interference_mitigation_disable(dev,
1354423e3ce3SKalle Valo currentmode);
1355423e3ce3SKalle Valo
1356423e3ce3SKalle Valo if (mode == B43legacy_RADIO_INTERFMODE_NONE) {
1357423e3ce3SKalle Valo phy->aci_enable = false;
1358423e3ce3SKalle Valo phy->aci_hw_rssi = false;
1359423e3ce3SKalle Valo } else
1360423e3ce3SKalle Valo b43legacy_radio_interference_mitigation_enable(dev, mode);
1361423e3ce3SKalle Valo phy->interfmode = mode;
1362423e3ce3SKalle Valo
1363423e3ce3SKalle Valo return 0;
1364423e3ce3SKalle Valo }
1365423e3ce3SKalle Valo
b43legacy_radio_calibrationvalue(struct b43legacy_wldev * dev)1366423e3ce3SKalle Valo u16 b43legacy_radio_calibrationvalue(struct b43legacy_wldev *dev)
1367423e3ce3SKalle Valo {
1368423e3ce3SKalle Valo u16 reg;
1369423e3ce3SKalle Valo u16 index;
1370423e3ce3SKalle Valo u16 ret;
1371423e3ce3SKalle Valo
1372423e3ce3SKalle Valo reg = b43legacy_radio_read16(dev, 0x0060);
1373423e3ce3SKalle Valo index = (reg & 0x001E) >> 1;
1374423e3ce3SKalle Valo ret = rcc_table[index] << 1;
1375423e3ce3SKalle Valo ret |= (reg & 0x0001);
1376423e3ce3SKalle Valo ret |= 0x0020;
1377423e3ce3SKalle Valo
1378423e3ce3SKalle Valo return ret;
1379423e3ce3SKalle Valo }
1380423e3ce3SKalle Valo
1381423e3ce3SKalle Valo #define LPD(L, P, D) (((L) << 2) | ((P) << 1) | ((D) << 0))
b43legacy_get_812_value(struct b43legacy_wldev * dev,u8 lpd)1382423e3ce3SKalle Valo static u16 b43legacy_get_812_value(struct b43legacy_wldev *dev, u8 lpd)
1383423e3ce3SKalle Valo {
1384423e3ce3SKalle Valo struct b43legacy_phy *phy = &dev->phy;
1385423e3ce3SKalle Valo u16 loop_or = 0;
1386423e3ce3SKalle Valo u16 adj_loopback_gain = phy->loopback_gain[0];
1387423e3ce3SKalle Valo u8 loop;
1388423e3ce3SKalle Valo u16 extern_lna_control;
1389423e3ce3SKalle Valo
1390423e3ce3SKalle Valo if (!phy->gmode)
1391423e3ce3SKalle Valo return 0;
1392423e3ce3SKalle Valo if (!has_loopback_gain(phy)) {
1393423e3ce3SKalle Valo if (phy->rev < 7 || !(dev->dev->bus->sprom.boardflags_lo
1394423e3ce3SKalle Valo & B43legacy_BFL_EXTLNA)) {
1395423e3ce3SKalle Valo switch (lpd) {
1396423e3ce3SKalle Valo case LPD(0, 1, 1):
1397423e3ce3SKalle Valo return 0x0FB2;
1398423e3ce3SKalle Valo case LPD(0, 0, 1):
1399423e3ce3SKalle Valo return 0x00B2;
1400423e3ce3SKalle Valo case LPD(1, 0, 1):
1401423e3ce3SKalle Valo return 0x30B2;
1402423e3ce3SKalle Valo case LPD(1, 0, 0):
1403423e3ce3SKalle Valo return 0x30B3;
1404423e3ce3SKalle Valo default:
1405423e3ce3SKalle Valo B43legacy_BUG_ON(1);
1406423e3ce3SKalle Valo }
1407423e3ce3SKalle Valo } else {
1408423e3ce3SKalle Valo switch (lpd) {
1409423e3ce3SKalle Valo case LPD(0, 1, 1):
1410423e3ce3SKalle Valo return 0x8FB2;
1411423e3ce3SKalle Valo case LPD(0, 0, 1):
1412423e3ce3SKalle Valo return 0x80B2;
1413423e3ce3SKalle Valo case LPD(1, 0, 1):
1414423e3ce3SKalle Valo return 0x20B2;
1415423e3ce3SKalle Valo case LPD(1, 0, 0):
1416423e3ce3SKalle Valo return 0x20B3;
1417423e3ce3SKalle Valo default:
1418423e3ce3SKalle Valo B43legacy_BUG_ON(1);
1419423e3ce3SKalle Valo }
1420423e3ce3SKalle Valo }
1421423e3ce3SKalle Valo } else {
1422423e3ce3SKalle Valo if (phy->radio_rev == 8)
1423423e3ce3SKalle Valo adj_loopback_gain += 0x003E;
1424423e3ce3SKalle Valo else
1425423e3ce3SKalle Valo adj_loopback_gain += 0x0026;
1426423e3ce3SKalle Valo if (adj_loopback_gain >= 0x46) {
1427423e3ce3SKalle Valo adj_loopback_gain -= 0x46;
1428423e3ce3SKalle Valo extern_lna_control = 0x3000;
1429423e3ce3SKalle Valo } else if (adj_loopback_gain >= 0x3A) {
1430423e3ce3SKalle Valo adj_loopback_gain -= 0x3A;
1431423e3ce3SKalle Valo extern_lna_control = 0x2000;
1432423e3ce3SKalle Valo } else if (adj_loopback_gain >= 0x2E) {
1433423e3ce3SKalle Valo adj_loopback_gain -= 0x2E;
1434423e3ce3SKalle Valo extern_lna_control = 0x1000;
1435423e3ce3SKalle Valo } else {
1436423e3ce3SKalle Valo adj_loopback_gain -= 0x10;
1437423e3ce3SKalle Valo extern_lna_control = 0x0000;
1438423e3ce3SKalle Valo }
1439423e3ce3SKalle Valo for (loop = 0; loop < 16; loop++) {
1440423e3ce3SKalle Valo u16 tmp = adj_loopback_gain - 6 * loop;
1441423e3ce3SKalle Valo if (tmp < 6)
1442423e3ce3SKalle Valo break;
1443423e3ce3SKalle Valo }
1444423e3ce3SKalle Valo
1445423e3ce3SKalle Valo loop_or = (loop << 8) | extern_lna_control;
1446423e3ce3SKalle Valo if (phy->rev >= 7 && dev->dev->bus->sprom.boardflags_lo
1447423e3ce3SKalle Valo & B43legacy_BFL_EXTLNA) {
1448423e3ce3SKalle Valo if (extern_lna_control)
1449423e3ce3SKalle Valo loop_or |= 0x8000;
1450423e3ce3SKalle Valo switch (lpd) {
1451423e3ce3SKalle Valo case LPD(0, 1, 1):
1452423e3ce3SKalle Valo return 0x8F92;
1453423e3ce3SKalle Valo case LPD(0, 0, 1):
1454423e3ce3SKalle Valo return (0x8092 | loop_or);
1455423e3ce3SKalle Valo case LPD(1, 0, 1):
1456423e3ce3SKalle Valo return (0x2092 | loop_or);
1457423e3ce3SKalle Valo case LPD(1, 0, 0):
1458423e3ce3SKalle Valo return (0x2093 | loop_or);
1459423e3ce3SKalle Valo default:
1460423e3ce3SKalle Valo B43legacy_BUG_ON(1);
1461423e3ce3SKalle Valo }
1462423e3ce3SKalle Valo } else {
1463423e3ce3SKalle Valo switch (lpd) {
1464423e3ce3SKalle Valo case LPD(0, 1, 1):
1465423e3ce3SKalle Valo return 0x0F92;
1466423e3ce3SKalle Valo case LPD(0, 0, 1):
1467423e3ce3SKalle Valo case LPD(1, 0, 1):
1468423e3ce3SKalle Valo return (0x0092 | loop_or);
1469423e3ce3SKalle Valo case LPD(1, 0, 0):
1470423e3ce3SKalle Valo return (0x0093 | loop_or);
1471423e3ce3SKalle Valo default:
1472423e3ce3SKalle Valo B43legacy_BUG_ON(1);
1473423e3ce3SKalle Valo }
1474423e3ce3SKalle Valo }
1475423e3ce3SKalle Valo }
1476423e3ce3SKalle Valo return 0;
1477423e3ce3SKalle Valo }
1478423e3ce3SKalle Valo
b43legacy_radio_init2050(struct b43legacy_wldev * dev)1479423e3ce3SKalle Valo u16 b43legacy_radio_init2050(struct b43legacy_wldev *dev)
1480423e3ce3SKalle Valo {
1481423e3ce3SKalle Valo struct b43legacy_phy *phy = &dev->phy;
1482423e3ce3SKalle Valo u16 backup[21] = { 0 };
1483423e3ce3SKalle Valo u16 ret;
1484423e3ce3SKalle Valo u16 i;
1485423e3ce3SKalle Valo u16 j;
1486423e3ce3SKalle Valo u32 tmp1 = 0;
1487423e3ce3SKalle Valo u32 tmp2 = 0;
1488423e3ce3SKalle Valo
1489423e3ce3SKalle Valo backup[0] = b43legacy_radio_read16(dev, 0x0043);
1490423e3ce3SKalle Valo backup[14] = b43legacy_radio_read16(dev, 0x0051);
1491423e3ce3SKalle Valo backup[15] = b43legacy_radio_read16(dev, 0x0052);
1492423e3ce3SKalle Valo backup[1] = b43legacy_phy_read(dev, 0x0015);
1493423e3ce3SKalle Valo backup[16] = b43legacy_phy_read(dev, 0x005A);
1494423e3ce3SKalle Valo backup[17] = b43legacy_phy_read(dev, 0x0059);
1495423e3ce3SKalle Valo backup[18] = b43legacy_phy_read(dev, 0x0058);
1496423e3ce3SKalle Valo if (phy->type == B43legacy_PHYTYPE_B) {
1497423e3ce3SKalle Valo backup[2] = b43legacy_phy_read(dev, 0x0030);
1498423e3ce3SKalle Valo backup[3] = b43legacy_read16(dev, 0x03EC);
1499423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0030, 0x00FF);
1500423e3ce3SKalle Valo b43legacy_write16(dev, 0x03EC, 0x3F3F);
1501423e3ce3SKalle Valo } else {
1502423e3ce3SKalle Valo if (phy->gmode) {
1503423e3ce3SKalle Valo backup[4] = b43legacy_phy_read(dev, 0x0811);
1504423e3ce3SKalle Valo backup[5] = b43legacy_phy_read(dev, 0x0812);
1505423e3ce3SKalle Valo backup[6] = b43legacy_phy_read(dev, 0x0814);
1506423e3ce3SKalle Valo backup[7] = b43legacy_phy_read(dev, 0x0815);
1507423e3ce3SKalle Valo backup[8] = b43legacy_phy_read(dev,
1508423e3ce3SKalle Valo B43legacy_PHY_G_CRS);
1509423e3ce3SKalle Valo backup[9] = b43legacy_phy_read(dev, 0x0802);
1510423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0814,
1511423e3ce3SKalle Valo (b43legacy_phy_read(dev, 0x0814)
1512423e3ce3SKalle Valo | 0x0003));
1513423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0815,
1514423e3ce3SKalle Valo (b43legacy_phy_read(dev, 0x0815)
1515423e3ce3SKalle Valo & 0xFFFC));
1516423e3ce3SKalle Valo b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
1517423e3ce3SKalle Valo (b43legacy_phy_read(dev,
1518423e3ce3SKalle Valo B43legacy_PHY_G_CRS) & 0x7FFF));
1519423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0802,
1520423e3ce3SKalle Valo (b43legacy_phy_read(dev, 0x0802)
1521423e3ce3SKalle Valo & 0xFFFC));
1522423e3ce3SKalle Valo if (phy->rev > 1) { /* loopback gain enabled */
1523423e3ce3SKalle Valo backup[19] = b43legacy_phy_read(dev, 0x080F);
1524423e3ce3SKalle Valo backup[20] = b43legacy_phy_read(dev, 0x0810);
1525423e3ce3SKalle Valo if (phy->rev >= 3)
1526423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x080F,
1527423e3ce3SKalle Valo 0xC020);
1528423e3ce3SKalle Valo else
1529423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x080F,
1530423e3ce3SKalle Valo 0x8020);
1531423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0810, 0x0000);
1532423e3ce3SKalle Valo }
1533423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0812,
1534423e3ce3SKalle Valo b43legacy_get_812_value(dev,
1535423e3ce3SKalle Valo LPD(0, 1, 1)));
1536423e3ce3SKalle Valo if (phy->rev < 7 ||
1537423e3ce3SKalle Valo !(dev->dev->bus->sprom.boardflags_lo
1538423e3ce3SKalle Valo & B43legacy_BFL_EXTLNA))
1539423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0811, 0x01B3);
1540423e3ce3SKalle Valo else
1541423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0811, 0x09B3);
1542423e3ce3SKalle Valo }
1543423e3ce3SKalle Valo }
1544423e3ce3SKalle Valo b43legacy_write16(dev, B43legacy_MMIO_PHY_RADIO,
1545423e3ce3SKalle Valo (b43legacy_read16(dev, B43legacy_MMIO_PHY_RADIO)
1546423e3ce3SKalle Valo | 0x8000));
1547423e3ce3SKalle Valo backup[10] = b43legacy_phy_read(dev, 0x0035);
1548423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0035,
1549423e3ce3SKalle Valo (b43legacy_phy_read(dev, 0x0035) & 0xFF7F));
1550423e3ce3SKalle Valo backup[11] = b43legacy_read16(dev, 0x03E6);
1551423e3ce3SKalle Valo backup[12] = b43legacy_read16(dev, B43legacy_MMIO_CHANNEL_EXT);
1552423e3ce3SKalle Valo
1553423e3ce3SKalle Valo /* Initialization */
1554423e3ce3SKalle Valo if (phy->analog == 0)
1555423e3ce3SKalle Valo b43legacy_write16(dev, 0x03E6, 0x0122);
1556423e3ce3SKalle Valo else {
1557423e3ce3SKalle Valo if (phy->analog >= 2)
1558423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0003,
1559423e3ce3SKalle Valo (b43legacy_phy_read(dev, 0x0003)
1560423e3ce3SKalle Valo & 0xFFBF) | 0x0040);
1561423e3ce3SKalle Valo b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT,
1562423e3ce3SKalle Valo (b43legacy_read16(dev,
1563423e3ce3SKalle Valo B43legacy_MMIO_CHANNEL_EXT) | 0x2000));
1564423e3ce3SKalle Valo }
1565423e3ce3SKalle Valo
1566423e3ce3SKalle Valo ret = b43legacy_radio_calibrationvalue(dev);
1567423e3ce3SKalle Valo
1568423e3ce3SKalle Valo if (phy->type == B43legacy_PHYTYPE_B)
1569423e3ce3SKalle Valo b43legacy_radio_write16(dev, 0x0078, 0x0026);
1570423e3ce3SKalle Valo
1571423e3ce3SKalle Valo if (phy->gmode)
1572423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0812,
1573423e3ce3SKalle Valo b43legacy_get_812_value(dev,
1574423e3ce3SKalle Valo LPD(0, 1, 1)));
1575423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0015, 0xBFAF);
1576423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x002B, 0x1403);
1577423e3ce3SKalle Valo if (phy->gmode)
1578423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0812,
1579423e3ce3SKalle Valo b43legacy_get_812_value(dev,
1580423e3ce3SKalle Valo LPD(0, 0, 1)));
1581423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0015, 0xBFA0);
1582423e3ce3SKalle Valo b43legacy_radio_write16(dev, 0x0051,
1583423e3ce3SKalle Valo (b43legacy_radio_read16(dev, 0x0051)
1584423e3ce3SKalle Valo | 0x0004));
1585423e3ce3SKalle Valo if (phy->radio_rev == 8)
1586423e3ce3SKalle Valo b43legacy_radio_write16(dev, 0x0043, 0x001F);
1587423e3ce3SKalle Valo else {
1588423e3ce3SKalle Valo b43legacy_radio_write16(dev, 0x0052, 0x0000);
1589423e3ce3SKalle Valo b43legacy_radio_write16(dev, 0x0043,
1590423e3ce3SKalle Valo (b43legacy_radio_read16(dev, 0x0043)
1591423e3ce3SKalle Valo & 0xFFF0) | 0x0009);
1592423e3ce3SKalle Valo }
1593423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0058, 0x0000);
1594423e3ce3SKalle Valo
1595423e3ce3SKalle Valo for (i = 0; i < 16; i++) {
1596423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x005A, 0x0480);
1597423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0059, 0xC810);
1598423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0058, 0x000D);
1599423e3ce3SKalle Valo if (phy->gmode)
1600423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0812,
1601423e3ce3SKalle Valo b43legacy_get_812_value(dev,
1602423e3ce3SKalle Valo LPD(1, 0, 1)));
1603423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0015, 0xAFB0);
1604423e3ce3SKalle Valo udelay(10);
1605423e3ce3SKalle Valo if (phy->gmode)
1606423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0812,
1607423e3ce3SKalle Valo b43legacy_get_812_value(dev,
1608423e3ce3SKalle Valo LPD(1, 0, 1)));
1609423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0015, 0xEFB0);
1610423e3ce3SKalle Valo udelay(10);
1611423e3ce3SKalle Valo if (phy->gmode)
1612423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0812,
1613423e3ce3SKalle Valo b43legacy_get_812_value(dev,
1614423e3ce3SKalle Valo LPD(1, 0, 0)));
1615423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0015, 0xFFF0);
1616423e3ce3SKalle Valo udelay(20);
1617423e3ce3SKalle Valo tmp1 += b43legacy_phy_read(dev, 0x002D);
1618423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0058, 0x0000);
1619423e3ce3SKalle Valo if (phy->gmode)
1620423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0812,
1621423e3ce3SKalle Valo b43legacy_get_812_value(dev,
1622423e3ce3SKalle Valo LPD(1, 0, 1)));
1623423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0015, 0xAFB0);
1624423e3ce3SKalle Valo }
1625423e3ce3SKalle Valo
1626423e3ce3SKalle Valo tmp1++;
1627423e3ce3SKalle Valo tmp1 >>= 9;
1628423e3ce3SKalle Valo udelay(10);
1629423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0058, 0x0000);
1630423e3ce3SKalle Valo
1631423e3ce3SKalle Valo for (i = 0; i < 16; i++) {
1632423e3ce3SKalle Valo b43legacy_radio_write16(dev, 0x0078, (flip_4bit(i) << 1)
1633423e3ce3SKalle Valo | 0x0020);
1634423e3ce3SKalle Valo backup[13] = b43legacy_radio_read16(dev, 0x0078);
1635423e3ce3SKalle Valo udelay(10);
1636423e3ce3SKalle Valo for (j = 0; j < 16; j++) {
1637423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x005A, 0x0D80);
1638423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0059, 0xC810);
1639423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0058, 0x000D);
1640423e3ce3SKalle Valo if (phy->gmode)
1641423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0812,
1642423e3ce3SKalle Valo b43legacy_get_812_value(dev,
1643423e3ce3SKalle Valo LPD(1, 0, 1)));
1644423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0015, 0xAFB0);
1645423e3ce3SKalle Valo udelay(10);
1646423e3ce3SKalle Valo if (phy->gmode)
1647423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0812,
1648423e3ce3SKalle Valo b43legacy_get_812_value(dev,
1649423e3ce3SKalle Valo LPD(1, 0, 1)));
1650423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0015, 0xEFB0);
1651423e3ce3SKalle Valo udelay(10);
1652423e3ce3SKalle Valo if (phy->gmode)
1653423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0812,
1654423e3ce3SKalle Valo b43legacy_get_812_value(dev,
1655423e3ce3SKalle Valo LPD(1, 0, 0)));
1656423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0015, 0xFFF0);
1657423e3ce3SKalle Valo udelay(10);
1658423e3ce3SKalle Valo tmp2 += b43legacy_phy_read(dev, 0x002D);
1659423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0058, 0x0000);
1660423e3ce3SKalle Valo if (phy->gmode)
1661423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0812,
1662423e3ce3SKalle Valo b43legacy_get_812_value(dev,
1663423e3ce3SKalle Valo LPD(1, 0, 1)));
1664423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0015, 0xAFB0);
1665423e3ce3SKalle Valo }
1666423e3ce3SKalle Valo tmp2++;
1667423e3ce3SKalle Valo tmp2 >>= 8;
1668423e3ce3SKalle Valo if (tmp1 < tmp2)
1669423e3ce3SKalle Valo break;
1670423e3ce3SKalle Valo }
1671423e3ce3SKalle Valo
1672423e3ce3SKalle Valo /* Restore the registers */
1673423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0015, backup[1]);
1674423e3ce3SKalle Valo b43legacy_radio_write16(dev, 0x0051, backup[14]);
1675423e3ce3SKalle Valo b43legacy_radio_write16(dev, 0x0052, backup[15]);
1676423e3ce3SKalle Valo b43legacy_radio_write16(dev, 0x0043, backup[0]);
1677423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x005A, backup[16]);
1678423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0059, backup[17]);
1679423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0058, backup[18]);
1680423e3ce3SKalle Valo b43legacy_write16(dev, 0x03E6, backup[11]);
1681423e3ce3SKalle Valo if (phy->analog != 0)
1682423e3ce3SKalle Valo b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, backup[12]);
1683423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0035, backup[10]);
1684423e3ce3SKalle Valo b43legacy_radio_selectchannel(dev, phy->channel, 1);
1685423e3ce3SKalle Valo if (phy->type == B43legacy_PHYTYPE_B) {
1686423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0030, backup[2]);
1687423e3ce3SKalle Valo b43legacy_write16(dev, 0x03EC, backup[3]);
1688423e3ce3SKalle Valo } else {
1689423e3ce3SKalle Valo if (phy->gmode) {
1690423e3ce3SKalle Valo b43legacy_write16(dev, B43legacy_MMIO_PHY_RADIO,
1691423e3ce3SKalle Valo (b43legacy_read16(dev,
1692423e3ce3SKalle Valo B43legacy_MMIO_PHY_RADIO) & 0x7FFF));
1693423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0811, backup[4]);
1694423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0812, backup[5]);
1695423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0814, backup[6]);
1696423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0815, backup[7]);
1697423e3ce3SKalle Valo b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
1698423e3ce3SKalle Valo backup[8]);
1699423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0802, backup[9]);
1700423e3ce3SKalle Valo if (phy->rev > 1) {
1701423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x080F, backup[19]);
1702423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0810, backup[20]);
1703423e3ce3SKalle Valo }
1704423e3ce3SKalle Valo }
1705423e3ce3SKalle Valo }
1706423e3ce3SKalle Valo if (i >= 15)
1707423e3ce3SKalle Valo ret = backup[13];
1708423e3ce3SKalle Valo
1709423e3ce3SKalle Valo return ret;
1710423e3ce3SKalle Valo }
1711423e3ce3SKalle Valo
b43legacy_radio_selectchannel(struct b43legacy_wldev * dev,u8 channel,int synthetic_pu_workaround)1712423e3ce3SKalle Valo int b43legacy_radio_selectchannel(struct b43legacy_wldev *dev,
1713423e3ce3SKalle Valo u8 channel,
1714423e3ce3SKalle Valo int synthetic_pu_workaround)
1715423e3ce3SKalle Valo {
1716423e3ce3SKalle Valo struct b43legacy_phy *phy = &dev->phy;
1717423e3ce3SKalle Valo
1718423e3ce3SKalle Valo if (channel == 0xFF) {
1719423e3ce3SKalle Valo switch (phy->type) {
1720423e3ce3SKalle Valo case B43legacy_PHYTYPE_B:
1721423e3ce3SKalle Valo case B43legacy_PHYTYPE_G:
1722423e3ce3SKalle Valo channel = B43legacy_RADIO_DEFAULT_CHANNEL_BG;
1723423e3ce3SKalle Valo break;
1724423e3ce3SKalle Valo default:
1725423e3ce3SKalle Valo B43legacy_WARN_ON(1);
1726423e3ce3SKalle Valo }
1727423e3ce3SKalle Valo }
1728423e3ce3SKalle Valo
1729423e3ce3SKalle Valo /* TODO: Check if channel is valid - return -EINVAL if not */
1730423e3ce3SKalle Valo if (synthetic_pu_workaround)
1731423e3ce3SKalle Valo b43legacy_synth_pu_workaround(dev, channel);
1732423e3ce3SKalle Valo
1733423e3ce3SKalle Valo b43legacy_write16(dev, B43legacy_MMIO_CHANNEL,
1734423e3ce3SKalle Valo channel2freq_bg(channel));
1735423e3ce3SKalle Valo
1736423e3ce3SKalle Valo if (channel == 14) {
1737423e3ce3SKalle Valo if (dev->dev->bus->sprom.country_code == 5) /* JAPAN) */
1738423e3ce3SKalle Valo b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
1739423e3ce3SKalle Valo B43legacy_UCODEFLAGS_OFFSET,
1740423e3ce3SKalle Valo b43legacy_shm_read32(dev,
1741423e3ce3SKalle Valo B43legacy_SHM_SHARED,
1742423e3ce3SKalle Valo B43legacy_UCODEFLAGS_OFFSET)
1743423e3ce3SKalle Valo & ~(1 << 7));
1744423e3ce3SKalle Valo else
1745423e3ce3SKalle Valo b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
1746423e3ce3SKalle Valo B43legacy_UCODEFLAGS_OFFSET,
1747423e3ce3SKalle Valo b43legacy_shm_read32(dev,
1748423e3ce3SKalle Valo B43legacy_SHM_SHARED,
1749423e3ce3SKalle Valo B43legacy_UCODEFLAGS_OFFSET)
1750423e3ce3SKalle Valo | (1 << 7));
1751423e3ce3SKalle Valo b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT,
1752423e3ce3SKalle Valo b43legacy_read16(dev,
1753423e3ce3SKalle Valo B43legacy_MMIO_CHANNEL_EXT) | (1 << 11));
1754423e3ce3SKalle Valo } else
1755423e3ce3SKalle Valo b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT,
1756423e3ce3SKalle Valo b43legacy_read16(dev,
1757423e3ce3SKalle Valo B43legacy_MMIO_CHANNEL_EXT) & 0xF7BF);
1758423e3ce3SKalle Valo
1759423e3ce3SKalle Valo phy->channel = channel;
1760423e3ce3SKalle Valo /*XXX: Using the longer of 2 timeouts (8000 vs 2000 usecs). Specs states
1761423e3ce3SKalle Valo * that 2000 usecs might suffice. */
1762423e3ce3SKalle Valo msleep(8);
1763423e3ce3SKalle Valo
1764423e3ce3SKalle Valo return 0;
1765423e3ce3SKalle Valo }
1766423e3ce3SKalle Valo
b43legacy_radio_set_txantenna(struct b43legacy_wldev * dev,u32 val)1767423e3ce3SKalle Valo void b43legacy_radio_set_txantenna(struct b43legacy_wldev *dev, u32 val)
1768423e3ce3SKalle Valo {
1769423e3ce3SKalle Valo u16 tmp;
1770423e3ce3SKalle Valo
1771423e3ce3SKalle Valo val <<= 8;
1772423e3ce3SKalle Valo tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x0022) & 0xFCFF;
1773423e3ce3SKalle Valo b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0022, tmp | val);
1774423e3ce3SKalle Valo tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x03A8) & 0xFCFF;
1775423e3ce3SKalle Valo b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x03A8, tmp | val);
1776423e3ce3SKalle Valo tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x0054) & 0xFCFF;
1777423e3ce3SKalle Valo b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0054, tmp | val);
1778423e3ce3SKalle Valo }
1779423e3ce3SKalle Valo
1780423e3ce3SKalle Valo /* http://bcm-specs.sipsolutions.net/TX_Gain_Base_Band */
b43legacy_get_txgain_base_band(u16 txpower)1781423e3ce3SKalle Valo static u16 b43legacy_get_txgain_base_band(u16 txpower)
1782423e3ce3SKalle Valo {
1783423e3ce3SKalle Valo u16 ret;
1784423e3ce3SKalle Valo
1785423e3ce3SKalle Valo B43legacy_WARN_ON(txpower > 63);
1786423e3ce3SKalle Valo
1787423e3ce3SKalle Valo if (txpower >= 54)
1788423e3ce3SKalle Valo ret = 2;
1789423e3ce3SKalle Valo else if (txpower >= 49)
1790423e3ce3SKalle Valo ret = 4;
1791423e3ce3SKalle Valo else if (txpower >= 44)
1792423e3ce3SKalle Valo ret = 5;
1793423e3ce3SKalle Valo else
1794423e3ce3SKalle Valo ret = 6;
1795423e3ce3SKalle Valo
1796423e3ce3SKalle Valo return ret;
1797423e3ce3SKalle Valo }
1798423e3ce3SKalle Valo
1799423e3ce3SKalle Valo /* http://bcm-specs.sipsolutions.net/TX_Gain_Radio_Frequency_Power_Amplifier */
b43legacy_get_txgain_freq_power_amp(u16 txpower)1800423e3ce3SKalle Valo static u16 b43legacy_get_txgain_freq_power_amp(u16 txpower)
1801423e3ce3SKalle Valo {
1802423e3ce3SKalle Valo u16 ret;
1803423e3ce3SKalle Valo
1804423e3ce3SKalle Valo B43legacy_WARN_ON(txpower > 63);
1805423e3ce3SKalle Valo
1806423e3ce3SKalle Valo if (txpower >= 32)
1807423e3ce3SKalle Valo ret = 0;
1808423e3ce3SKalle Valo else if (txpower >= 25)
1809423e3ce3SKalle Valo ret = 1;
1810423e3ce3SKalle Valo else if (txpower >= 20)
1811423e3ce3SKalle Valo ret = 2;
1812423e3ce3SKalle Valo else if (txpower >= 12)
1813423e3ce3SKalle Valo ret = 3;
1814423e3ce3SKalle Valo else
1815423e3ce3SKalle Valo ret = 4;
1816423e3ce3SKalle Valo
1817423e3ce3SKalle Valo return ret;
1818423e3ce3SKalle Valo }
1819423e3ce3SKalle Valo
1820423e3ce3SKalle Valo /* http://bcm-specs.sipsolutions.net/TX_Gain_Digital_Analog_Converter */
b43legacy_get_txgain_dac(u16 txpower)1821423e3ce3SKalle Valo static u16 b43legacy_get_txgain_dac(u16 txpower)
1822423e3ce3SKalle Valo {
1823423e3ce3SKalle Valo u16 ret;
1824423e3ce3SKalle Valo
1825423e3ce3SKalle Valo B43legacy_WARN_ON(txpower > 63);
1826423e3ce3SKalle Valo
1827423e3ce3SKalle Valo if (txpower >= 54)
1828423e3ce3SKalle Valo ret = txpower - 53;
1829423e3ce3SKalle Valo else if (txpower >= 49)
1830423e3ce3SKalle Valo ret = txpower - 42;
1831423e3ce3SKalle Valo else if (txpower >= 44)
1832423e3ce3SKalle Valo ret = txpower - 37;
1833423e3ce3SKalle Valo else if (txpower >= 32)
1834423e3ce3SKalle Valo ret = txpower - 32;
1835423e3ce3SKalle Valo else if (txpower >= 25)
1836423e3ce3SKalle Valo ret = txpower - 20;
1837423e3ce3SKalle Valo else if (txpower >= 20)
1838423e3ce3SKalle Valo ret = txpower - 13;
1839423e3ce3SKalle Valo else if (txpower >= 12)
1840423e3ce3SKalle Valo ret = txpower - 8;
1841423e3ce3SKalle Valo else
1842423e3ce3SKalle Valo ret = txpower;
1843423e3ce3SKalle Valo
1844423e3ce3SKalle Valo return ret;
1845423e3ce3SKalle Valo }
1846423e3ce3SKalle Valo
b43legacy_radio_set_txpower_a(struct b43legacy_wldev * dev,u16 txpower)1847423e3ce3SKalle Valo void b43legacy_radio_set_txpower_a(struct b43legacy_wldev *dev, u16 txpower)
1848423e3ce3SKalle Valo {
1849423e3ce3SKalle Valo struct b43legacy_phy *phy = &dev->phy;
1850423e3ce3SKalle Valo u16 pamp;
1851423e3ce3SKalle Valo u16 base;
1852423e3ce3SKalle Valo u16 dac;
1853423e3ce3SKalle Valo u16 ilt;
1854423e3ce3SKalle Valo
1855423e3ce3SKalle Valo txpower = clamp_val(txpower, 0, 63);
1856423e3ce3SKalle Valo
1857423e3ce3SKalle Valo pamp = b43legacy_get_txgain_freq_power_amp(txpower);
1858423e3ce3SKalle Valo pamp <<= 5;
1859423e3ce3SKalle Valo pamp &= 0x00E0;
1860423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0019, pamp);
1861423e3ce3SKalle Valo
1862423e3ce3SKalle Valo base = b43legacy_get_txgain_base_band(txpower);
1863423e3ce3SKalle Valo base &= 0x000F;
1864423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0017, base | 0x0020);
1865423e3ce3SKalle Valo
1866423e3ce3SKalle Valo ilt = b43legacy_ilt_read(dev, 0x3001);
1867423e3ce3SKalle Valo ilt &= 0x0007;
1868423e3ce3SKalle Valo
1869423e3ce3SKalle Valo dac = b43legacy_get_txgain_dac(txpower);
1870423e3ce3SKalle Valo dac <<= 3;
1871423e3ce3SKalle Valo dac |= ilt;
1872423e3ce3SKalle Valo
1873423e3ce3SKalle Valo b43legacy_ilt_write(dev, 0x3001, dac);
1874423e3ce3SKalle Valo
1875423e3ce3SKalle Valo phy->txpwr_offset = txpower;
1876423e3ce3SKalle Valo
1877423e3ce3SKalle Valo /* TODO: FuncPlaceholder (Adjust BB loft cancel) */
1878423e3ce3SKalle Valo }
1879423e3ce3SKalle Valo
b43legacy_radio_set_txpower_bg(struct b43legacy_wldev * dev,u16 baseband_attenuation,u16 radio_attenuation,u16 txpower)1880423e3ce3SKalle Valo void b43legacy_radio_set_txpower_bg(struct b43legacy_wldev *dev,
1881423e3ce3SKalle Valo u16 baseband_attenuation,
1882423e3ce3SKalle Valo u16 radio_attenuation,
1883423e3ce3SKalle Valo u16 txpower)
1884423e3ce3SKalle Valo {
1885423e3ce3SKalle Valo struct b43legacy_phy *phy = &dev->phy;
1886423e3ce3SKalle Valo
1887423e3ce3SKalle Valo if (baseband_attenuation == 0xFFFF)
1888423e3ce3SKalle Valo baseband_attenuation = phy->bbatt;
1889423e3ce3SKalle Valo if (radio_attenuation == 0xFFFF)
1890423e3ce3SKalle Valo radio_attenuation = phy->rfatt;
1891423e3ce3SKalle Valo if (txpower == 0xFFFF)
1892423e3ce3SKalle Valo txpower = phy->txctl1;
1893423e3ce3SKalle Valo phy->bbatt = baseband_attenuation;
1894423e3ce3SKalle Valo phy->rfatt = radio_attenuation;
1895423e3ce3SKalle Valo phy->txctl1 = txpower;
1896423e3ce3SKalle Valo
1897423e3ce3SKalle Valo B43legacy_WARN_ON(baseband_attenuation > 11);
1898423e3ce3SKalle Valo if (phy->radio_rev < 6)
1899423e3ce3SKalle Valo B43legacy_WARN_ON(radio_attenuation > 9);
1900423e3ce3SKalle Valo else
1901423e3ce3SKalle Valo B43legacy_WARN_ON(radio_attenuation > 31);
1902423e3ce3SKalle Valo B43legacy_WARN_ON(txpower > 7);
1903423e3ce3SKalle Valo
1904423e3ce3SKalle Valo b43legacy_phy_set_baseband_attenuation(dev, baseband_attenuation);
1905423e3ce3SKalle Valo b43legacy_radio_write16(dev, 0x0043, radio_attenuation);
1906423e3ce3SKalle Valo b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0064,
1907423e3ce3SKalle Valo radio_attenuation);
1908423e3ce3SKalle Valo if (phy->radio_ver == 0x2050)
1909423e3ce3SKalle Valo b43legacy_radio_write16(dev, 0x0052,
1910423e3ce3SKalle Valo (b43legacy_radio_read16(dev, 0x0052)
1911423e3ce3SKalle Valo & ~0x0070) | ((txpower << 4) & 0x0070));
1912423e3ce3SKalle Valo /* FIXME: The spec is very weird and unclear here. */
1913423e3ce3SKalle Valo if (phy->type == B43legacy_PHYTYPE_G)
1914423e3ce3SKalle Valo b43legacy_phy_lo_adjust(dev, 0);
1915423e3ce3SKalle Valo }
1916423e3ce3SKalle Valo
b43legacy_default_baseband_attenuation(struct b43legacy_wldev * dev)1917423e3ce3SKalle Valo u16 b43legacy_default_baseband_attenuation(struct b43legacy_wldev *dev)
1918423e3ce3SKalle Valo {
1919423e3ce3SKalle Valo struct b43legacy_phy *phy = &dev->phy;
1920423e3ce3SKalle Valo
1921423e3ce3SKalle Valo if (phy->radio_ver == 0x2050 && phy->radio_rev < 6)
1922423e3ce3SKalle Valo return 0;
1923423e3ce3SKalle Valo return 2;
1924423e3ce3SKalle Valo }
1925423e3ce3SKalle Valo
b43legacy_default_radio_attenuation(struct b43legacy_wldev * dev)1926423e3ce3SKalle Valo u16 b43legacy_default_radio_attenuation(struct b43legacy_wldev *dev)
1927423e3ce3SKalle Valo {
1928423e3ce3SKalle Valo struct b43legacy_phy *phy = &dev->phy;
1929423e3ce3SKalle Valo u16 att = 0xFFFF;
1930423e3ce3SKalle Valo
1931423e3ce3SKalle Valo switch (phy->radio_ver) {
1932423e3ce3SKalle Valo case 0x2053:
1933423e3ce3SKalle Valo switch (phy->radio_rev) {
1934423e3ce3SKalle Valo case 1:
1935423e3ce3SKalle Valo att = 6;
1936423e3ce3SKalle Valo break;
1937423e3ce3SKalle Valo }
1938423e3ce3SKalle Valo break;
1939423e3ce3SKalle Valo case 0x2050:
1940423e3ce3SKalle Valo switch (phy->radio_rev) {
1941423e3ce3SKalle Valo case 0:
1942423e3ce3SKalle Valo att = 5;
1943423e3ce3SKalle Valo break;
1944423e3ce3SKalle Valo case 1:
1945423e3ce3SKalle Valo if (phy->type == B43legacy_PHYTYPE_G) {
1946423e3ce3SKalle Valo if (is_bcm_board_vendor(dev) &&
1947423e3ce3SKalle Valo dev->dev->bus->boardinfo.type == 0x421 &&
1948423e3ce3SKalle Valo dev->dev->bus->sprom.board_rev >= 30)
1949423e3ce3SKalle Valo att = 3;
1950423e3ce3SKalle Valo else if (is_bcm_board_vendor(dev) &&
1951423e3ce3SKalle Valo dev->dev->bus->boardinfo.type == 0x416)
1952423e3ce3SKalle Valo att = 3;
1953423e3ce3SKalle Valo else
1954423e3ce3SKalle Valo att = 1;
1955423e3ce3SKalle Valo } else {
1956423e3ce3SKalle Valo if (is_bcm_board_vendor(dev) &&
1957423e3ce3SKalle Valo dev->dev->bus->boardinfo.type == 0x421 &&
1958423e3ce3SKalle Valo dev->dev->bus->sprom.board_rev >= 30)
1959423e3ce3SKalle Valo att = 7;
1960423e3ce3SKalle Valo else
1961423e3ce3SKalle Valo att = 6;
1962423e3ce3SKalle Valo }
1963423e3ce3SKalle Valo break;
1964423e3ce3SKalle Valo case 2:
1965423e3ce3SKalle Valo if (phy->type == B43legacy_PHYTYPE_G) {
1966423e3ce3SKalle Valo if (is_bcm_board_vendor(dev) &&
1967423e3ce3SKalle Valo dev->dev->bus->boardinfo.type == 0x421 &&
1968423e3ce3SKalle Valo dev->dev->bus->sprom.board_rev >= 30)
1969423e3ce3SKalle Valo att = 3;
1970423e3ce3SKalle Valo else if (is_bcm_board_vendor(dev) &&
1971423e3ce3SKalle Valo dev->dev->bus->boardinfo.type ==
1972423e3ce3SKalle Valo 0x416)
1973423e3ce3SKalle Valo att = 5;
1974423e3ce3SKalle Valo else if (dev->dev->bus->chip_id == 0x4320)
1975423e3ce3SKalle Valo att = 4;
1976423e3ce3SKalle Valo else
1977423e3ce3SKalle Valo att = 3;
1978423e3ce3SKalle Valo } else
1979423e3ce3SKalle Valo att = 6;
1980423e3ce3SKalle Valo break;
1981423e3ce3SKalle Valo case 3:
1982423e3ce3SKalle Valo att = 5;
1983423e3ce3SKalle Valo break;
1984423e3ce3SKalle Valo case 4:
1985423e3ce3SKalle Valo case 5:
1986423e3ce3SKalle Valo att = 1;
1987423e3ce3SKalle Valo break;
1988423e3ce3SKalle Valo case 6:
1989423e3ce3SKalle Valo case 7:
1990423e3ce3SKalle Valo att = 5;
1991423e3ce3SKalle Valo break;
1992423e3ce3SKalle Valo case 8:
1993423e3ce3SKalle Valo att = 0x1A;
1994423e3ce3SKalle Valo break;
1995423e3ce3SKalle Valo case 9:
1996423e3ce3SKalle Valo default:
1997423e3ce3SKalle Valo att = 5;
1998423e3ce3SKalle Valo }
1999423e3ce3SKalle Valo }
2000423e3ce3SKalle Valo if (is_bcm_board_vendor(dev) &&
2001423e3ce3SKalle Valo dev->dev->bus->boardinfo.type == 0x421) {
2002423e3ce3SKalle Valo if (dev->dev->bus->sprom.board_rev < 0x43)
2003423e3ce3SKalle Valo att = 2;
2004423e3ce3SKalle Valo else if (dev->dev->bus->sprom.board_rev < 0x51)
2005423e3ce3SKalle Valo att = 3;
2006423e3ce3SKalle Valo }
2007423e3ce3SKalle Valo if (att == 0xFFFF)
2008423e3ce3SKalle Valo att = 5;
2009423e3ce3SKalle Valo
2010423e3ce3SKalle Valo return att;
2011423e3ce3SKalle Valo }
2012423e3ce3SKalle Valo
b43legacy_default_txctl1(struct b43legacy_wldev * dev)2013423e3ce3SKalle Valo u16 b43legacy_default_txctl1(struct b43legacy_wldev *dev)
2014423e3ce3SKalle Valo {
2015423e3ce3SKalle Valo struct b43legacy_phy *phy = &dev->phy;
2016423e3ce3SKalle Valo
2017423e3ce3SKalle Valo if (phy->radio_ver != 0x2050)
2018423e3ce3SKalle Valo return 0;
2019423e3ce3SKalle Valo if (phy->radio_rev == 1)
2020423e3ce3SKalle Valo return 3;
2021423e3ce3SKalle Valo if (phy->radio_rev < 6)
2022423e3ce3SKalle Valo return 2;
2023423e3ce3SKalle Valo if (phy->radio_rev == 8)
2024423e3ce3SKalle Valo return 1;
2025423e3ce3SKalle Valo return 0;
2026423e3ce3SKalle Valo }
2027423e3ce3SKalle Valo
b43legacy_radio_turn_on(struct b43legacy_wldev * dev)2028423e3ce3SKalle Valo void b43legacy_radio_turn_on(struct b43legacy_wldev *dev)
2029423e3ce3SKalle Valo {
2030423e3ce3SKalle Valo struct b43legacy_phy *phy = &dev->phy;
2031423e3ce3SKalle Valo int err;
2032423e3ce3SKalle Valo u8 channel;
2033423e3ce3SKalle Valo
2034423e3ce3SKalle Valo might_sleep();
2035423e3ce3SKalle Valo
2036423e3ce3SKalle Valo if (phy->radio_on)
2037423e3ce3SKalle Valo return;
2038423e3ce3SKalle Valo
2039423e3ce3SKalle Valo switch (phy->type) {
2040423e3ce3SKalle Valo case B43legacy_PHYTYPE_B:
2041423e3ce3SKalle Valo case B43legacy_PHYTYPE_G:
2042423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0015, 0x8000);
2043423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0015, 0xCC00);
2044423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0015,
2045423e3ce3SKalle Valo (phy->gmode ? 0x00C0 : 0x0000));
2046423e3ce3SKalle Valo if (phy->radio_off_context.valid) {
2047423e3ce3SKalle Valo /* Restore the RFover values. */
2048423e3ce3SKalle Valo b43legacy_phy_write(dev, B43legacy_PHY_RFOVER,
2049423e3ce3SKalle Valo phy->radio_off_context.rfover);
2050423e3ce3SKalle Valo b43legacy_phy_write(dev, B43legacy_PHY_RFOVERVAL,
2051423e3ce3SKalle Valo phy->radio_off_context.rfoverval);
2052423e3ce3SKalle Valo phy->radio_off_context.valid = false;
2053423e3ce3SKalle Valo }
2054423e3ce3SKalle Valo channel = phy->channel;
2055423e3ce3SKalle Valo err = b43legacy_radio_selectchannel(dev,
2056423e3ce3SKalle Valo B43legacy_RADIO_DEFAULT_CHANNEL_BG, 1);
2057423e3ce3SKalle Valo err |= b43legacy_radio_selectchannel(dev, channel, 0);
2058423e3ce3SKalle Valo B43legacy_WARN_ON(err);
2059423e3ce3SKalle Valo break;
2060423e3ce3SKalle Valo default:
2061423e3ce3SKalle Valo B43legacy_BUG_ON(1);
2062423e3ce3SKalle Valo }
2063423e3ce3SKalle Valo phy->radio_on = true;
2064423e3ce3SKalle Valo }
2065423e3ce3SKalle Valo
b43legacy_radio_turn_off(struct b43legacy_wldev * dev,bool force)2066423e3ce3SKalle Valo void b43legacy_radio_turn_off(struct b43legacy_wldev *dev, bool force)
2067423e3ce3SKalle Valo {
2068423e3ce3SKalle Valo struct b43legacy_phy *phy = &dev->phy;
2069423e3ce3SKalle Valo
2070423e3ce3SKalle Valo if (!phy->radio_on && !force)
2071423e3ce3SKalle Valo return;
2072423e3ce3SKalle Valo
2073423e3ce3SKalle Valo if (phy->type == B43legacy_PHYTYPE_G && dev->dev->id.revision >= 5) {
2074423e3ce3SKalle Valo u16 rfover, rfoverval;
2075423e3ce3SKalle Valo
2076423e3ce3SKalle Valo rfover = b43legacy_phy_read(dev, B43legacy_PHY_RFOVER);
2077423e3ce3SKalle Valo rfoverval = b43legacy_phy_read(dev, B43legacy_PHY_RFOVERVAL);
2078423e3ce3SKalle Valo if (!force) {
2079423e3ce3SKalle Valo phy->radio_off_context.rfover = rfover;
2080423e3ce3SKalle Valo phy->radio_off_context.rfoverval = rfoverval;
2081423e3ce3SKalle Valo phy->radio_off_context.valid = true;
2082423e3ce3SKalle Valo }
2083423e3ce3SKalle Valo b43legacy_phy_write(dev, B43legacy_PHY_RFOVER, rfover | 0x008C);
2084423e3ce3SKalle Valo b43legacy_phy_write(dev, B43legacy_PHY_RFOVERVAL,
2085423e3ce3SKalle Valo rfoverval & 0xFF73);
2086423e3ce3SKalle Valo } else
2087423e3ce3SKalle Valo b43legacy_phy_write(dev, 0x0015, 0xAA00);
2088423e3ce3SKalle Valo phy->radio_on = false;
2089423e3ce3SKalle Valo b43legacydbg(dev->wl, "Radio initialized\n");
2090423e3ce3SKalle Valo }
2091423e3ce3SKalle Valo
b43legacy_radio_clear_tssi(struct b43legacy_wldev * dev)2092423e3ce3SKalle Valo void b43legacy_radio_clear_tssi(struct b43legacy_wldev *dev)
2093423e3ce3SKalle Valo {
2094423e3ce3SKalle Valo struct b43legacy_phy *phy = &dev->phy;
2095423e3ce3SKalle Valo
2096423e3ce3SKalle Valo switch (phy->type) {
2097423e3ce3SKalle Valo case B43legacy_PHYTYPE_B:
2098423e3ce3SKalle Valo case B43legacy_PHYTYPE_G:
2099423e3ce3SKalle Valo b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0058,
2100423e3ce3SKalle Valo 0x7F7F);
2101423e3ce3SKalle Valo b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x005a,
2102423e3ce3SKalle Valo 0x7F7F);
2103423e3ce3SKalle Valo b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0070,
2104423e3ce3SKalle Valo 0x7F7F);
2105423e3ce3SKalle Valo b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0072,
2106423e3ce3SKalle Valo 0x7F7F);
2107423e3ce3SKalle Valo break;
2108423e3ce3SKalle Valo }
2109423e3ce3SKalle Valo }
2110