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 #include <linux/pci.h>
21423e3ce3SKalle Valo #include <linux/sched.h>
22423e3ce3SKalle Valo #include <linux/slab.h>
23423e3ce3SKalle Valo #include <linux/types.h>
24423e3ce3SKalle Valo 
25423e3ce3SKalle Valo #include "b43legacy.h"
26423e3ce3SKalle Valo #include "phy.h"
27423e3ce3SKalle Valo #include "main.h"
28423e3ce3SKalle Valo #include "radio.h"
29423e3ce3SKalle Valo #include "ilt.h"
30423e3ce3SKalle Valo 
31423e3ce3SKalle Valo 
32423e3ce3SKalle Valo static const s8 b43legacy_tssi2dbm_b_table[] = {
33423e3ce3SKalle Valo 	0x4D, 0x4C, 0x4B, 0x4A,
34423e3ce3SKalle Valo 	0x4A, 0x49, 0x48, 0x47,
35423e3ce3SKalle Valo 	0x47, 0x46, 0x45, 0x45,
36423e3ce3SKalle Valo 	0x44, 0x43, 0x42, 0x42,
37423e3ce3SKalle Valo 	0x41, 0x40, 0x3F, 0x3E,
38423e3ce3SKalle Valo 	0x3D, 0x3C, 0x3B, 0x3A,
39423e3ce3SKalle Valo 	0x39, 0x38, 0x37, 0x36,
40423e3ce3SKalle Valo 	0x35, 0x34, 0x32, 0x31,
41423e3ce3SKalle Valo 	0x30, 0x2F, 0x2D, 0x2C,
42423e3ce3SKalle Valo 	0x2B, 0x29, 0x28, 0x26,
43423e3ce3SKalle Valo 	0x25, 0x23, 0x21, 0x1F,
44423e3ce3SKalle Valo 	0x1D, 0x1A, 0x17, 0x14,
45423e3ce3SKalle Valo 	0x10, 0x0C, 0x06, 0x00,
46423e3ce3SKalle Valo 	  -7,   -7,   -7,   -7,
47423e3ce3SKalle Valo 	  -7,   -7,   -7,   -7,
48423e3ce3SKalle Valo 	  -7,   -7,   -7,   -7,
49423e3ce3SKalle Valo };
50423e3ce3SKalle Valo 
51423e3ce3SKalle Valo static const s8 b43legacy_tssi2dbm_g_table[] = {
52423e3ce3SKalle Valo 	 77,  77,  77,  76,
53423e3ce3SKalle Valo 	 76,  76,  75,  75,
54423e3ce3SKalle Valo 	 74,  74,  73,  73,
55423e3ce3SKalle Valo 	 73,  72,  72,  71,
56423e3ce3SKalle Valo 	 71,  70,  70,  69,
57423e3ce3SKalle Valo 	 68,  68,  67,  67,
58423e3ce3SKalle Valo 	 66,  65,  65,  64,
59423e3ce3SKalle Valo 	 63,  63,  62,  61,
60423e3ce3SKalle Valo 	 60,  59,  58,  57,
61423e3ce3SKalle Valo 	 56,  55,  54,  53,
62423e3ce3SKalle Valo 	 52,  50,  49,  47,
63423e3ce3SKalle Valo 	 45,  43,  40,  37,
64423e3ce3SKalle Valo 	 33,  28,  22,  14,
65423e3ce3SKalle Valo 	  5,  -7, -20, -20,
66423e3ce3SKalle Valo 	-20, -20, -20, -20,
67423e3ce3SKalle Valo 	-20, -20, -20, -20,
68423e3ce3SKalle Valo };
69423e3ce3SKalle Valo 
70423e3ce3SKalle Valo static void b43legacy_phy_initg(struct b43legacy_wldev *dev);
71423e3ce3SKalle Valo 
72423e3ce3SKalle Valo /* Lock the PHY registers against concurrent access from the microcode.
73423e3ce3SKalle Valo  * This lock is nonrecursive. */
b43legacy_phy_lock(struct b43legacy_wldev * dev)74423e3ce3SKalle Valo void b43legacy_phy_lock(struct b43legacy_wldev *dev)
75423e3ce3SKalle Valo {
76423e3ce3SKalle Valo #if B43legacy_DEBUG
77423e3ce3SKalle Valo 	B43legacy_WARN_ON(dev->phy.phy_locked);
78423e3ce3SKalle Valo 	dev->phy.phy_locked = 1;
79423e3ce3SKalle Valo #endif
80423e3ce3SKalle Valo 
81423e3ce3SKalle Valo 	if (dev->dev->id.revision < 3) {
82423e3ce3SKalle Valo 		b43legacy_mac_suspend(dev);
83423e3ce3SKalle Valo 	} else {
84423e3ce3SKalle Valo 		if (!b43legacy_is_mode(dev->wl, NL80211_IFTYPE_AP))
85423e3ce3SKalle Valo 			b43legacy_power_saving_ctl_bits(dev, -1, 1);
86423e3ce3SKalle Valo 	}
87423e3ce3SKalle Valo }
88423e3ce3SKalle Valo 
b43legacy_phy_unlock(struct b43legacy_wldev * dev)89423e3ce3SKalle Valo void b43legacy_phy_unlock(struct b43legacy_wldev *dev)
90423e3ce3SKalle Valo {
91423e3ce3SKalle Valo #if B43legacy_DEBUG
92423e3ce3SKalle Valo 	B43legacy_WARN_ON(!dev->phy.phy_locked);
93423e3ce3SKalle Valo 	dev->phy.phy_locked = 0;
94423e3ce3SKalle Valo #endif
95423e3ce3SKalle Valo 
96423e3ce3SKalle Valo 	if (dev->dev->id.revision < 3) {
97423e3ce3SKalle Valo 		b43legacy_mac_enable(dev);
98423e3ce3SKalle Valo 	} else {
99423e3ce3SKalle Valo 		if (!b43legacy_is_mode(dev->wl, NL80211_IFTYPE_AP))
100423e3ce3SKalle Valo 			b43legacy_power_saving_ctl_bits(dev, -1, -1);
101423e3ce3SKalle Valo 	}
102423e3ce3SKalle Valo }
103423e3ce3SKalle Valo 
b43legacy_phy_read(struct b43legacy_wldev * dev,u16 offset)104423e3ce3SKalle Valo u16 b43legacy_phy_read(struct b43legacy_wldev *dev, u16 offset)
105423e3ce3SKalle Valo {
106423e3ce3SKalle Valo 	b43legacy_write16(dev, B43legacy_MMIO_PHY_CONTROL, offset);
107423e3ce3SKalle Valo 	return b43legacy_read16(dev, B43legacy_MMIO_PHY_DATA);
108423e3ce3SKalle Valo }
109423e3ce3SKalle Valo 
b43legacy_phy_write(struct b43legacy_wldev * dev,u16 offset,u16 val)110423e3ce3SKalle Valo void b43legacy_phy_write(struct b43legacy_wldev *dev, u16 offset, u16 val)
111423e3ce3SKalle Valo {
112423e3ce3SKalle Valo 	b43legacy_write16(dev, B43legacy_MMIO_PHY_CONTROL, offset);
113423e3ce3SKalle Valo 	b43legacy_write16(dev, B43legacy_MMIO_PHY_DATA, val);
114423e3ce3SKalle Valo }
115423e3ce3SKalle Valo 
b43legacy_phy_calibrate(struct b43legacy_wldev * dev)116423e3ce3SKalle Valo void b43legacy_phy_calibrate(struct b43legacy_wldev *dev)
117423e3ce3SKalle Valo {
118423e3ce3SKalle Valo 	struct b43legacy_phy *phy = &dev->phy;
119423e3ce3SKalle Valo 
120423e3ce3SKalle Valo 	b43legacy_read32(dev, B43legacy_MMIO_MACCTL); /* Dummy read. */
121423e3ce3SKalle Valo 	if (phy->calibrated)
122423e3ce3SKalle Valo 		return;
123423e3ce3SKalle Valo 	if (phy->type == B43legacy_PHYTYPE_G && phy->rev == 1) {
124423e3ce3SKalle Valo 		b43legacy_wireless_core_reset(dev, 0);
125423e3ce3SKalle Valo 		b43legacy_phy_initg(dev);
126423e3ce3SKalle Valo 		b43legacy_wireless_core_reset(dev, B43legacy_TMSLOW_GMODE);
127423e3ce3SKalle Valo 	}
128423e3ce3SKalle Valo 	phy->calibrated = 1;
129423e3ce3SKalle Valo }
130423e3ce3SKalle Valo 
131423e3ce3SKalle Valo /* initialize B PHY power control
132140c6026SAlexander A. Klimov  * as described in https://bcm-specs.sipsolutions.net/InitPowerControl
133423e3ce3SKalle Valo  */
b43legacy_phy_init_pctl(struct b43legacy_wldev * dev)134423e3ce3SKalle Valo static void b43legacy_phy_init_pctl(struct b43legacy_wldev *dev)
135423e3ce3SKalle Valo {
136423e3ce3SKalle Valo 	struct b43legacy_phy *phy = &dev->phy;
137423e3ce3SKalle Valo 	u16 saved_batt = 0;
138423e3ce3SKalle Valo 	u16 saved_ratt = 0;
139423e3ce3SKalle Valo 	u16 saved_txctl1 = 0;
140423e3ce3SKalle Valo 	int must_reset_txpower = 0;
141423e3ce3SKalle Valo 
142423e3ce3SKalle Valo 	B43legacy_BUG_ON(!(phy->type == B43legacy_PHYTYPE_B ||
143423e3ce3SKalle Valo 			  phy->type == B43legacy_PHYTYPE_G));
144423e3ce3SKalle Valo 	if (is_bcm_board_vendor(dev) &&
145423e3ce3SKalle Valo 	    (dev->dev->bus->boardinfo.type == 0x0416))
146423e3ce3SKalle Valo 		return;
147423e3ce3SKalle Valo 
148423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0028, 0x8018);
149423e3ce3SKalle Valo 	b43legacy_write16(dev, 0x03E6, b43legacy_read16(dev, 0x03E6) & 0xFFDF);
150423e3ce3SKalle Valo 
151423e3ce3SKalle Valo 	if (phy->type == B43legacy_PHYTYPE_G) {
152423e3ce3SKalle Valo 		if (!phy->gmode)
153423e3ce3SKalle Valo 			return;
154423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x047A, 0xC111);
155423e3ce3SKalle Valo 	}
156423e3ce3SKalle Valo 	if (phy->savedpctlreg != 0xFFFF)
157423e3ce3SKalle Valo 		return;
158423e3ce3SKalle Valo #ifdef CONFIG_B43LEGACY_DEBUG
159423e3ce3SKalle Valo 	if (phy->manual_txpower_control)
160423e3ce3SKalle Valo 		return;
161423e3ce3SKalle Valo #endif
162423e3ce3SKalle Valo 
163423e3ce3SKalle Valo 	if (phy->type == B43legacy_PHYTYPE_B &&
164423e3ce3SKalle Valo 	    phy->rev >= 2 &&
165423e3ce3SKalle Valo 	    phy->radio_ver == 0x2050)
166423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x0076,
167423e3ce3SKalle Valo 					b43legacy_radio_read16(dev, 0x0076)
168423e3ce3SKalle Valo 					| 0x0084);
169423e3ce3SKalle Valo 	else {
170423e3ce3SKalle Valo 		saved_batt = phy->bbatt;
171423e3ce3SKalle Valo 		saved_ratt = phy->rfatt;
172423e3ce3SKalle Valo 		saved_txctl1 = phy->txctl1;
173423e3ce3SKalle Valo 		if ((phy->radio_rev >= 6) && (phy->radio_rev <= 8)
174423e3ce3SKalle Valo 		    && /*FIXME: incomplete specs for 5 < revision < 9 */ 0)
175423e3ce3SKalle Valo 			b43legacy_radio_set_txpower_bg(dev, 0xB, 0x1F, 0);
176423e3ce3SKalle Valo 		else
177423e3ce3SKalle Valo 			b43legacy_radio_set_txpower_bg(dev, 0xB, 9, 0);
178423e3ce3SKalle Valo 		must_reset_txpower = 1;
179423e3ce3SKalle Valo 	}
180423e3ce3SKalle Valo 	b43legacy_dummy_transmission(dev);
181423e3ce3SKalle Valo 
182423e3ce3SKalle Valo 	phy->savedpctlreg = b43legacy_phy_read(dev, B43legacy_PHY_G_PCTL);
183423e3ce3SKalle Valo 
184423e3ce3SKalle Valo 	if (must_reset_txpower)
185423e3ce3SKalle Valo 		b43legacy_radio_set_txpower_bg(dev, saved_batt, saved_ratt,
186423e3ce3SKalle Valo 					       saved_txctl1);
187423e3ce3SKalle Valo 	else
188423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x0076, b43legacy_radio_read16(dev,
189423e3ce3SKalle Valo 					0x0076) & 0xFF7B);
190423e3ce3SKalle Valo 	b43legacy_radio_clear_tssi(dev);
191423e3ce3SKalle Valo }
192423e3ce3SKalle Valo 
b43legacy_phy_agcsetup(struct b43legacy_wldev * dev)193423e3ce3SKalle Valo static void b43legacy_phy_agcsetup(struct b43legacy_wldev *dev)
194423e3ce3SKalle Valo {
195423e3ce3SKalle Valo 	struct b43legacy_phy *phy = &dev->phy;
196423e3ce3SKalle Valo 	u16 offset = 0x0000;
197423e3ce3SKalle Valo 
198423e3ce3SKalle Valo 	if (phy->rev == 1)
199423e3ce3SKalle Valo 		offset = 0x4C00;
200423e3ce3SKalle Valo 
201423e3ce3SKalle Valo 	b43legacy_ilt_write(dev, offset, 0x00FE);
202423e3ce3SKalle Valo 	b43legacy_ilt_write(dev, offset + 1, 0x000D);
203423e3ce3SKalle Valo 	b43legacy_ilt_write(dev, offset + 2, 0x0013);
204423e3ce3SKalle Valo 	b43legacy_ilt_write(dev, offset + 3, 0x0019);
205423e3ce3SKalle Valo 
206423e3ce3SKalle Valo 	if (phy->rev == 1) {
207423e3ce3SKalle Valo 		b43legacy_ilt_write(dev, 0x1800, 0x2710);
208423e3ce3SKalle Valo 		b43legacy_ilt_write(dev, 0x1801, 0x9B83);
209423e3ce3SKalle Valo 		b43legacy_ilt_write(dev, 0x1802, 0x9B83);
210423e3ce3SKalle Valo 		b43legacy_ilt_write(dev, 0x1803, 0x0F8D);
211423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0455, 0x0004);
212423e3ce3SKalle Valo 	}
213423e3ce3SKalle Valo 
214423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x04A5, (b43legacy_phy_read(dev, 0x04A5)
215423e3ce3SKalle Valo 					  & 0x00FF) | 0x5700);
216423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x041A, (b43legacy_phy_read(dev, 0x041A)
217423e3ce3SKalle Valo 					  & 0xFF80) | 0x000F);
218423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x041A, (b43legacy_phy_read(dev, 0x041A)
219423e3ce3SKalle Valo 					  & 0xC07F) | 0x2B80);
220423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x048C, (b43legacy_phy_read(dev, 0x048C)
221423e3ce3SKalle Valo 					  & 0xF0FF) | 0x0300);
222423e3ce3SKalle Valo 
223423e3ce3SKalle Valo 	b43legacy_radio_write16(dev, 0x007A,
224423e3ce3SKalle Valo 				b43legacy_radio_read16(dev, 0x007A)
225423e3ce3SKalle Valo 				| 0x0008);
226423e3ce3SKalle Valo 
227423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x04A0, (b43legacy_phy_read(dev, 0x04A0)
228423e3ce3SKalle Valo 			    & 0xFFF0) | 0x0008);
229423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x04A1, (b43legacy_phy_read(dev, 0x04A1)
230423e3ce3SKalle Valo 			    & 0xF0FF) | 0x0600);
231423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x04A2, (b43legacy_phy_read(dev, 0x04A2)
232423e3ce3SKalle Valo 			    & 0xF0FF) | 0x0700);
233423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x04A0, (b43legacy_phy_read(dev, 0x04A0)
234423e3ce3SKalle Valo 			    & 0xF0FF) | 0x0100);
235423e3ce3SKalle Valo 
236423e3ce3SKalle Valo 	if (phy->rev == 1)
237423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x04A2,
238423e3ce3SKalle Valo 				    (b43legacy_phy_read(dev, 0x04A2)
239423e3ce3SKalle Valo 				    & 0xFFF0) | 0x0007);
240423e3ce3SKalle Valo 
241423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0488, (b43legacy_phy_read(dev, 0x0488)
242423e3ce3SKalle Valo 			    & 0xFF00) | 0x001C);
243423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0488, (b43legacy_phy_read(dev, 0x0488)
244423e3ce3SKalle Valo 			    & 0xC0FF) | 0x0200);
245423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0496, (b43legacy_phy_read(dev, 0x0496)
246423e3ce3SKalle Valo 			    & 0xFF00) | 0x001C);
247423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0489, (b43legacy_phy_read(dev, 0x0489)
248423e3ce3SKalle Valo 			    & 0xFF00) | 0x0020);
249423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0489, (b43legacy_phy_read(dev, 0x0489)
250423e3ce3SKalle Valo 			    & 0xC0FF) | 0x0200);
251423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0482, (b43legacy_phy_read(dev, 0x0482)
252423e3ce3SKalle Valo 			    & 0xFF00) | 0x002E);
253423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0496, (b43legacy_phy_read(dev, 0x0496)
254423e3ce3SKalle Valo 			    & 0x00FF) | 0x1A00);
255423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0481, (b43legacy_phy_read(dev, 0x0481)
256423e3ce3SKalle Valo 			    & 0xFF00) | 0x0028);
257423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0481, (b43legacy_phy_read(dev, 0x0481)
258423e3ce3SKalle Valo 			    & 0x00FF) | 0x2C00);
259423e3ce3SKalle Valo 
260423e3ce3SKalle Valo 	if (phy->rev == 1) {
261423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0430, 0x092B);
262423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x041B,
263423e3ce3SKalle Valo 				    (b43legacy_phy_read(dev, 0x041B)
264423e3ce3SKalle Valo 				    & 0xFFE1) | 0x0002);
265423e3ce3SKalle Valo 	} else {
266423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x041B,
267423e3ce3SKalle Valo 				    b43legacy_phy_read(dev, 0x041B) & 0xFFE1);
268423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x041F, 0x287A);
269423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0420,
270423e3ce3SKalle Valo 				    (b43legacy_phy_read(dev, 0x0420)
271423e3ce3SKalle Valo 				    & 0xFFF0) | 0x0004);
272423e3ce3SKalle Valo 	}
273423e3ce3SKalle Valo 
274423e3ce3SKalle Valo 	if (phy->rev > 2) {
275423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0422, 0x287A);
276423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0420,
277423e3ce3SKalle Valo 				    (b43legacy_phy_read(dev, 0x0420)
278423e3ce3SKalle Valo 				    & 0x0FFF) | 0x3000);
279423e3ce3SKalle Valo 	}
280423e3ce3SKalle Valo 
281423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x04A8, (b43legacy_phy_read(dev, 0x04A8)
282423e3ce3SKalle Valo 			    & 0x8080) | 0x7874);
283423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x048E, 0x1C00);
284423e3ce3SKalle Valo 
285423e3ce3SKalle Valo 	if (phy->rev == 1) {
286423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x04AB,
287423e3ce3SKalle Valo 				    (b43legacy_phy_read(dev, 0x04AB)
288423e3ce3SKalle Valo 				    & 0xF0FF) | 0x0600);
289423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x048B, 0x005E);
290423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x048C,
291423e3ce3SKalle Valo 				    (b43legacy_phy_read(dev, 0x048C) & 0xFF00)
292423e3ce3SKalle Valo 				    | 0x001E);
293423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x048D, 0x0002);
294423e3ce3SKalle Valo 	}
295423e3ce3SKalle Valo 
296423e3ce3SKalle Valo 	b43legacy_ilt_write(dev, offset + 0x0800, 0);
297423e3ce3SKalle Valo 	b43legacy_ilt_write(dev, offset + 0x0801, 7);
298423e3ce3SKalle Valo 	b43legacy_ilt_write(dev, offset + 0x0802, 16);
299423e3ce3SKalle Valo 	b43legacy_ilt_write(dev, offset + 0x0803, 28);
300423e3ce3SKalle Valo 
301423e3ce3SKalle Valo 	if (phy->rev >= 6) {
302423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0426,
303423e3ce3SKalle Valo 				    (b43legacy_phy_read(dev, 0x0426) & 0xFFFC));
304423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0426,
305423e3ce3SKalle Valo 				    (b43legacy_phy_read(dev, 0x0426) & 0xEFFF));
306423e3ce3SKalle Valo 	}
307423e3ce3SKalle Valo }
308423e3ce3SKalle Valo 
b43legacy_phy_setupg(struct b43legacy_wldev * dev)309423e3ce3SKalle Valo static void b43legacy_phy_setupg(struct b43legacy_wldev *dev)
310423e3ce3SKalle Valo {
311423e3ce3SKalle Valo 	struct b43legacy_phy *phy = &dev->phy;
312423e3ce3SKalle Valo 	u16 i;
313423e3ce3SKalle Valo 
314423e3ce3SKalle Valo 	B43legacy_BUG_ON(phy->type != B43legacy_PHYTYPE_G);
315423e3ce3SKalle Valo 	if (phy->rev == 1) {
316423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0406, 0x4F19);
317423e3ce3SKalle Valo 		b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
318423e3ce3SKalle Valo 				    (b43legacy_phy_read(dev,
319423e3ce3SKalle Valo 				    B43legacy_PHY_G_CRS) & 0xFC3F) | 0x0340);
320423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x042C, 0x005A);
321423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0427, 0x001A);
322423e3ce3SKalle Valo 
323423e3ce3SKalle Valo 		for (i = 0; i < B43legacy_ILT_FINEFREQG_SIZE; i++)
324423e3ce3SKalle Valo 			b43legacy_ilt_write(dev, 0x5800 + i,
325423e3ce3SKalle Valo 					    b43legacy_ilt_finefreqg[i]);
326423e3ce3SKalle Valo 		for (i = 0; i < B43legacy_ILT_NOISEG1_SIZE; i++)
327423e3ce3SKalle Valo 			b43legacy_ilt_write(dev, 0x1800 + i,
328423e3ce3SKalle Valo 					    b43legacy_ilt_noiseg1[i]);
329423e3ce3SKalle Valo 		for (i = 0; i < B43legacy_ILT_ROTOR_SIZE; i++)
330423e3ce3SKalle Valo 			b43legacy_ilt_write32(dev, 0x2000 + i,
331423e3ce3SKalle Valo 					      b43legacy_ilt_rotor[i]);
332423e3ce3SKalle Valo 	} else {
333423e3ce3SKalle Valo 		/* nrssi values are signed 6-bit values. Why 0x7654 here? */
334423e3ce3SKalle Valo 		b43legacy_nrssi_hw_write(dev, 0xBA98, (s16)0x7654);
335423e3ce3SKalle Valo 
336423e3ce3SKalle Valo 		if (phy->rev == 2) {
337423e3ce3SKalle Valo 			b43legacy_phy_write(dev, 0x04C0, 0x1861);
338423e3ce3SKalle Valo 			b43legacy_phy_write(dev, 0x04C1, 0x0271);
339423e3ce3SKalle Valo 		} else if (phy->rev > 2) {
340423e3ce3SKalle Valo 			b43legacy_phy_write(dev, 0x04C0, 0x0098);
341423e3ce3SKalle Valo 			b43legacy_phy_write(dev, 0x04C1, 0x0070);
342423e3ce3SKalle Valo 			b43legacy_phy_write(dev, 0x04C9, 0x0080);
343423e3ce3SKalle Valo 		}
344423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x042B, b43legacy_phy_read(dev,
345423e3ce3SKalle Valo 				    0x042B) | 0x800);
346423e3ce3SKalle Valo 
347423e3ce3SKalle Valo 		for (i = 0; i < 64; i++)
348423e3ce3SKalle Valo 			b43legacy_ilt_write(dev, 0x4000 + i, i);
349423e3ce3SKalle Valo 		for (i = 0; i < B43legacy_ILT_NOISEG2_SIZE; i++)
350423e3ce3SKalle Valo 			b43legacy_ilt_write(dev, 0x1800 + i,
351423e3ce3SKalle Valo 					    b43legacy_ilt_noiseg2[i]);
352423e3ce3SKalle Valo 	}
353423e3ce3SKalle Valo 
354423e3ce3SKalle Valo 	if (phy->rev <= 2)
355423e3ce3SKalle Valo 		for (i = 0; i < B43legacy_ILT_NOISESCALEG_SIZE; i++)
356423e3ce3SKalle Valo 			b43legacy_ilt_write(dev, 0x1400 + i,
357423e3ce3SKalle Valo 					    b43legacy_ilt_noisescaleg1[i]);
358423e3ce3SKalle Valo 	else if ((phy->rev >= 7) && (b43legacy_phy_read(dev, 0x0449) & 0x0200))
359423e3ce3SKalle Valo 		for (i = 0; i < B43legacy_ILT_NOISESCALEG_SIZE; i++)
360423e3ce3SKalle Valo 			b43legacy_ilt_write(dev, 0x1400 + i,
361423e3ce3SKalle Valo 					    b43legacy_ilt_noisescaleg3[i]);
362423e3ce3SKalle Valo 	else
363423e3ce3SKalle Valo 		for (i = 0; i < B43legacy_ILT_NOISESCALEG_SIZE; i++)
364423e3ce3SKalle Valo 			b43legacy_ilt_write(dev, 0x1400 + i,
365423e3ce3SKalle Valo 					    b43legacy_ilt_noisescaleg2[i]);
366423e3ce3SKalle Valo 
367423e3ce3SKalle Valo 	if (phy->rev == 2)
368423e3ce3SKalle Valo 		for (i = 0; i < B43legacy_ILT_SIGMASQR_SIZE; i++)
369423e3ce3SKalle Valo 			b43legacy_ilt_write(dev, 0x5000 + i,
370423e3ce3SKalle Valo 					    b43legacy_ilt_sigmasqr1[i]);
371423e3ce3SKalle Valo 	else if ((phy->rev > 2) && (phy->rev <= 8))
372423e3ce3SKalle Valo 		for (i = 0; i < B43legacy_ILT_SIGMASQR_SIZE; i++)
373423e3ce3SKalle Valo 			b43legacy_ilt_write(dev, 0x5000 + i,
374423e3ce3SKalle Valo 					    b43legacy_ilt_sigmasqr2[i]);
375423e3ce3SKalle Valo 
376423e3ce3SKalle Valo 	if (phy->rev == 1) {
377423e3ce3SKalle Valo 		for (i = 0; i < B43legacy_ILT_RETARD_SIZE; i++)
378423e3ce3SKalle Valo 			b43legacy_ilt_write32(dev, 0x2400 + i,
379423e3ce3SKalle Valo 					      b43legacy_ilt_retard[i]);
380423e3ce3SKalle Valo 		for (i = 4; i < 20; i++)
381423e3ce3SKalle Valo 			b43legacy_ilt_write(dev, 0x5400 + i, 0x0020);
382423e3ce3SKalle Valo 		b43legacy_phy_agcsetup(dev);
383423e3ce3SKalle Valo 
384423e3ce3SKalle Valo 		if (is_bcm_board_vendor(dev) &&
385423e3ce3SKalle Valo 		    (dev->dev->bus->boardinfo.type == 0x0416) &&
386423e3ce3SKalle Valo 		    (dev->dev->bus->sprom.board_rev == 0x0017))
387423e3ce3SKalle Valo 			return;
388423e3ce3SKalle Valo 
389423e3ce3SKalle Valo 		b43legacy_ilt_write(dev, 0x5001, 0x0002);
390423e3ce3SKalle Valo 		b43legacy_ilt_write(dev, 0x5002, 0x0001);
391423e3ce3SKalle Valo 	} else {
392423e3ce3SKalle Valo 		for (i = 0; i <= 0x20; i++)
393423e3ce3SKalle Valo 			b43legacy_ilt_write(dev, 0x1000 + i, 0x0820);
394423e3ce3SKalle Valo 		b43legacy_phy_agcsetup(dev);
395423e3ce3SKalle Valo 		b43legacy_phy_read(dev, 0x0400); /* dummy read */
396423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0403, 0x1000);
397423e3ce3SKalle Valo 		b43legacy_ilt_write(dev, 0x3C02, 0x000F);
398423e3ce3SKalle Valo 		b43legacy_ilt_write(dev, 0x3C03, 0x0014);
399423e3ce3SKalle Valo 
400423e3ce3SKalle Valo 		if (is_bcm_board_vendor(dev) &&
401423e3ce3SKalle Valo 		    (dev->dev->bus->boardinfo.type == 0x0416) &&
402423e3ce3SKalle Valo 		    (dev->dev->bus->sprom.board_rev == 0x0017))
403423e3ce3SKalle Valo 			return;
404423e3ce3SKalle Valo 
405423e3ce3SKalle Valo 		b43legacy_ilt_write(dev, 0x0401, 0x0002);
406423e3ce3SKalle Valo 		b43legacy_ilt_write(dev, 0x0402, 0x0001);
407423e3ce3SKalle Valo 	}
408423e3ce3SKalle Valo }
409423e3ce3SKalle Valo 
410423e3ce3SKalle Valo /* Initialize the APHY portion of a GPHY. */
b43legacy_phy_inita(struct b43legacy_wldev * dev)411423e3ce3SKalle Valo static void b43legacy_phy_inita(struct b43legacy_wldev *dev)
412423e3ce3SKalle Valo {
413423e3ce3SKalle Valo 
414423e3ce3SKalle Valo 	might_sleep();
415423e3ce3SKalle Valo 
416423e3ce3SKalle Valo 	b43legacy_phy_setupg(dev);
417423e3ce3SKalle Valo 	if (dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_PACTRL)
418423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x046E, 0x03CF);
419423e3ce3SKalle Valo }
420423e3ce3SKalle Valo 
b43legacy_phy_initb2(struct b43legacy_wldev * dev)421423e3ce3SKalle Valo static void b43legacy_phy_initb2(struct b43legacy_wldev *dev)
422423e3ce3SKalle Valo {
423423e3ce3SKalle Valo 	struct b43legacy_phy *phy = &dev->phy;
424423e3ce3SKalle Valo 	u16 offset;
425423e3ce3SKalle Valo 	int val;
426423e3ce3SKalle Valo 
427423e3ce3SKalle Valo 	b43legacy_write16(dev, 0x03EC, 0x3F22);
428423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0020, 0x301C);
429423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0026, 0x0000);
430423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0030, 0x00C6);
431423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0088, 0x3E00);
432423e3ce3SKalle Valo 	val = 0x3C3D;
433423e3ce3SKalle Valo 	for (offset = 0x0089; offset < 0x00A7; offset++) {
434423e3ce3SKalle Valo 		b43legacy_phy_write(dev, offset, val);
435423e3ce3SKalle Valo 		val -= 0x0202;
436423e3ce3SKalle Valo 	}
437423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x03E4, 0x3000);
438423e3ce3SKalle Valo 	b43legacy_radio_selectchannel(dev, phy->channel, 0);
439423e3ce3SKalle Valo 	if (phy->radio_ver != 0x2050) {
440423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x0075, 0x0080);
441423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x0079, 0x0081);
442423e3ce3SKalle Valo 	}
443423e3ce3SKalle Valo 	b43legacy_radio_write16(dev, 0x0050, 0x0020);
444423e3ce3SKalle Valo 	b43legacy_radio_write16(dev, 0x0050, 0x0023);
445423e3ce3SKalle Valo 	if (phy->radio_ver == 0x2050) {
446423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x0050, 0x0020);
447423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x005A, 0x0070);
448423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x005B, 0x007B);
449423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x005C, 0x00B0);
450423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x007A, 0x000F);
451423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0038, 0x0677);
452423e3ce3SKalle Valo 		b43legacy_radio_init2050(dev);
453423e3ce3SKalle Valo 	}
454423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0014, 0x0080);
455423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0032, 0x00CA);
456423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0032, 0x00CC);
457423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0035, 0x07C2);
458423e3ce3SKalle Valo 	b43legacy_phy_lo_b_measure(dev);
459423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0026, 0xCC00);
460423e3ce3SKalle Valo 	if (phy->radio_ver != 0x2050)
461423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0026, 0xCE00);
462423e3ce3SKalle Valo 	b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, 0x1000);
463423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x002A, 0x88A3);
464423e3ce3SKalle Valo 	if (phy->radio_ver != 0x2050)
465423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x002A, 0x88C2);
466423e3ce3SKalle Valo 	b43legacy_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF);
467423e3ce3SKalle Valo 	b43legacy_phy_init_pctl(dev);
468423e3ce3SKalle Valo }
469423e3ce3SKalle Valo 
b43legacy_phy_initb4(struct b43legacy_wldev * dev)470423e3ce3SKalle Valo static void b43legacy_phy_initb4(struct b43legacy_wldev *dev)
471423e3ce3SKalle Valo {
472423e3ce3SKalle Valo 	struct b43legacy_phy *phy = &dev->phy;
473423e3ce3SKalle Valo 	u16 offset;
474423e3ce3SKalle Valo 	u16 val;
475423e3ce3SKalle Valo 
476423e3ce3SKalle Valo 	b43legacy_write16(dev, 0x03EC, 0x3F22);
477423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0020, 0x301C);
478423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0026, 0x0000);
479423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0030, 0x00C6);
480423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0088, 0x3E00);
481423e3ce3SKalle Valo 	val = 0x3C3D;
482423e3ce3SKalle Valo 	for (offset = 0x0089; offset < 0x00A7; offset++) {
483423e3ce3SKalle Valo 		b43legacy_phy_write(dev, offset, val);
484423e3ce3SKalle Valo 		val -= 0x0202;
485423e3ce3SKalle Valo 	}
486423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x03E4, 0x3000);
487423e3ce3SKalle Valo 	b43legacy_radio_selectchannel(dev, phy->channel, 0);
488423e3ce3SKalle Valo 	if (phy->radio_ver != 0x2050) {
489423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x0075, 0x0080);
490423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x0079, 0x0081);
491423e3ce3SKalle Valo 	}
492423e3ce3SKalle Valo 	b43legacy_radio_write16(dev, 0x0050, 0x0020);
493423e3ce3SKalle Valo 	b43legacy_radio_write16(dev, 0x0050, 0x0023);
494423e3ce3SKalle Valo 	if (phy->radio_ver == 0x2050) {
495423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x0050, 0x0020);
496423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x005A, 0x0070);
497423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x005B, 0x007B);
498423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x005C, 0x00B0);
499423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x007A, 0x000F);
500423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0038, 0x0677);
501423e3ce3SKalle Valo 		b43legacy_radio_init2050(dev);
502423e3ce3SKalle Valo 	}
503423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0014, 0x0080);
504423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0032, 0x00CA);
505423e3ce3SKalle Valo 	if (phy->radio_ver == 0x2050)
506423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0032, 0x00E0);
507423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0035, 0x07C2);
508423e3ce3SKalle Valo 
509423e3ce3SKalle Valo 	b43legacy_phy_lo_b_measure(dev);
510423e3ce3SKalle Valo 
511423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0026, 0xCC00);
512423e3ce3SKalle Valo 	if (phy->radio_ver == 0x2050)
513423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0026, 0xCE00);
514423e3ce3SKalle Valo 	b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, 0x1100);
515423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x002A, 0x88A3);
516423e3ce3SKalle Valo 	if (phy->radio_ver == 0x2050)
517423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x002A, 0x88C2);
518423e3ce3SKalle Valo 	b43legacy_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF);
519423e3ce3SKalle Valo 	if (dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_RSSI) {
520423e3ce3SKalle Valo 		b43legacy_calc_nrssi_slope(dev);
521423e3ce3SKalle Valo 		b43legacy_calc_nrssi_threshold(dev);
522423e3ce3SKalle Valo 	}
523423e3ce3SKalle Valo 	b43legacy_phy_init_pctl(dev);
524423e3ce3SKalle Valo }
525423e3ce3SKalle Valo 
b43legacy_phy_initb5(struct b43legacy_wldev * dev)526423e3ce3SKalle Valo static void b43legacy_phy_initb5(struct b43legacy_wldev *dev)
527423e3ce3SKalle Valo {
528423e3ce3SKalle Valo 	struct b43legacy_phy *phy = &dev->phy;
529423e3ce3SKalle Valo 	u16 offset;
530423e3ce3SKalle Valo 	u16 value;
531423e3ce3SKalle Valo 	u8 old_channel;
532423e3ce3SKalle Valo 
533423e3ce3SKalle Valo 	if (phy->analog == 1)
534423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x007A,
535423e3ce3SKalle Valo 					b43legacy_radio_read16(dev, 0x007A)
536423e3ce3SKalle Valo 					| 0x0050);
537423e3ce3SKalle Valo 	if (!is_bcm_board_vendor(dev) &&
538423e3ce3SKalle Valo 	    (dev->dev->bus->boardinfo.type != 0x0416)) {
539423e3ce3SKalle Valo 		value = 0x2120;
540423e3ce3SKalle Valo 		for (offset = 0x00A8 ; offset < 0x00C7; offset++) {
541423e3ce3SKalle Valo 			b43legacy_phy_write(dev, offset, value);
542423e3ce3SKalle Valo 			value += 0x0202;
543423e3ce3SKalle Valo 		}
544423e3ce3SKalle Valo 	}
545423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0035,
546423e3ce3SKalle Valo 			    (b43legacy_phy_read(dev, 0x0035) & 0xF0FF)
547423e3ce3SKalle Valo 			    | 0x0700);
548423e3ce3SKalle Valo 	if (phy->radio_ver == 0x2050)
549423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0038, 0x0667);
550423e3ce3SKalle Valo 
551423e3ce3SKalle Valo 	if (phy->gmode) {
552423e3ce3SKalle Valo 		if (phy->radio_ver == 0x2050) {
553423e3ce3SKalle Valo 			b43legacy_radio_write16(dev, 0x007A,
554423e3ce3SKalle Valo 					b43legacy_radio_read16(dev, 0x007A)
555423e3ce3SKalle Valo 					| 0x0020);
556423e3ce3SKalle Valo 			b43legacy_radio_write16(dev, 0x0051,
557423e3ce3SKalle Valo 					b43legacy_radio_read16(dev, 0x0051)
558423e3ce3SKalle Valo 					| 0x0004);
559423e3ce3SKalle Valo 		}
560423e3ce3SKalle Valo 		b43legacy_write16(dev, B43legacy_MMIO_PHY_RADIO, 0x0000);
561423e3ce3SKalle Valo 
562423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0802, b43legacy_phy_read(dev, 0x0802)
563423e3ce3SKalle Valo 				    | 0x0100);
564423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x042B, b43legacy_phy_read(dev, 0x042B)
565423e3ce3SKalle Valo 				    | 0x2000);
566423e3ce3SKalle Valo 
567423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x001C, 0x186A);
568423e3ce3SKalle Valo 
569423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0013, (b43legacy_phy_read(dev,
570423e3ce3SKalle Valo 				    0x0013) & 0x00FF) | 0x1900);
571423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0035, (b43legacy_phy_read(dev,
572423e3ce3SKalle Valo 				    0x0035) & 0xFFC0) | 0x0064);
573423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x005D, (b43legacy_phy_read(dev,
574423e3ce3SKalle Valo 				    0x005D) & 0xFF80) | 0x000A);
575423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x5B, 0x0000);
576423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x5C, 0x0000);
577423e3ce3SKalle Valo 	}
578423e3ce3SKalle Valo 
579423e3ce3SKalle Valo 	if (dev->bad_frames_preempt)
580423e3ce3SKalle Valo 		b43legacy_phy_write(dev, B43legacy_PHY_RADIO_BITFIELD,
581423e3ce3SKalle Valo 				    b43legacy_phy_read(dev,
582423e3ce3SKalle Valo 				    B43legacy_PHY_RADIO_BITFIELD) | (1 << 12));
583423e3ce3SKalle Valo 
584423e3ce3SKalle Valo 	if (phy->analog == 1) {
585423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0026, 0xCE00);
586423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0021, 0x3763);
587423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0022, 0x1BC3);
588423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0023, 0x06F9);
589423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0024, 0x037E);
590423e3ce3SKalle Valo 	} else
591423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0026, 0xCC00);
592423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0030, 0x00C6);
593423e3ce3SKalle Valo 	b43legacy_write16(dev, 0x03EC, 0x3F22);
594423e3ce3SKalle Valo 
595423e3ce3SKalle Valo 	if (phy->analog == 1)
596423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0020, 0x3E1C);
597423e3ce3SKalle Valo 	else
598423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0020, 0x301C);
599423e3ce3SKalle Valo 
600423e3ce3SKalle Valo 	if (phy->analog == 0)
601423e3ce3SKalle Valo 		b43legacy_write16(dev, 0x03E4, 0x3000);
602423e3ce3SKalle Valo 
603423e3ce3SKalle Valo 	old_channel = (phy->channel == 0xFF) ? 1 : phy->channel;
604423e3ce3SKalle Valo 	/* Force to channel 7, even if not supported. */
605423e3ce3SKalle Valo 	b43legacy_radio_selectchannel(dev, 7, 0);
606423e3ce3SKalle Valo 
607423e3ce3SKalle Valo 	if (phy->radio_ver != 0x2050) {
608423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x0075, 0x0080);
609423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x0079, 0x0081);
610423e3ce3SKalle Valo 	}
611423e3ce3SKalle Valo 
612423e3ce3SKalle Valo 	b43legacy_radio_write16(dev, 0x0050, 0x0020);
613423e3ce3SKalle Valo 	b43legacy_radio_write16(dev, 0x0050, 0x0023);
614423e3ce3SKalle Valo 
615423e3ce3SKalle Valo 	if (phy->radio_ver == 0x2050) {
616423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x0050, 0x0020);
617423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x005A, 0x0070);
618423e3ce3SKalle Valo 	}
619423e3ce3SKalle Valo 
620423e3ce3SKalle Valo 	b43legacy_radio_write16(dev, 0x005B, 0x007B);
621423e3ce3SKalle Valo 	b43legacy_radio_write16(dev, 0x005C, 0x00B0);
622423e3ce3SKalle Valo 
623423e3ce3SKalle Valo 	b43legacy_radio_write16(dev, 0x007A, b43legacy_radio_read16(dev,
624423e3ce3SKalle Valo 				0x007A) | 0x0007);
625423e3ce3SKalle Valo 
626423e3ce3SKalle Valo 	b43legacy_radio_selectchannel(dev, old_channel, 0);
627423e3ce3SKalle Valo 
628423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0014, 0x0080);
629423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0032, 0x00CA);
630423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x002A, 0x88A3);
631423e3ce3SKalle Valo 
632423e3ce3SKalle Valo 	b43legacy_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF);
633423e3ce3SKalle Valo 
634423e3ce3SKalle Valo 	if (phy->radio_ver == 0x2050)
635423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x005D, 0x000D);
636423e3ce3SKalle Valo 
637423e3ce3SKalle Valo 	b43legacy_write16(dev, 0x03E4, (b43legacy_read16(dev, 0x03E4) &
638423e3ce3SKalle Valo 			  0xFFC0) | 0x0004);
639423e3ce3SKalle Valo }
640423e3ce3SKalle Valo 
b43legacy_phy_initb6(struct b43legacy_wldev * dev)641423e3ce3SKalle Valo static void b43legacy_phy_initb6(struct b43legacy_wldev *dev)
642423e3ce3SKalle Valo {
643423e3ce3SKalle Valo 	struct b43legacy_phy *phy = &dev->phy;
644423e3ce3SKalle Valo 	u16 offset;
645423e3ce3SKalle Valo 	u16 val;
646423e3ce3SKalle Valo 	u8 old_channel;
647423e3ce3SKalle Valo 
648423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x003E, 0x817A);
649423e3ce3SKalle Valo 	b43legacy_radio_write16(dev, 0x007A,
650423e3ce3SKalle Valo 				(b43legacy_radio_read16(dev, 0x007A) | 0x0058));
651423e3ce3SKalle Valo 	if (phy->radio_rev == 4 ||
652423e3ce3SKalle Valo 	     phy->radio_rev == 5) {
653423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x0051, 0x0037);
654423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x0052, 0x0070);
655423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x0053, 0x00B3);
656423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x0054, 0x009B);
657423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x005A, 0x0088);
658423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x005B, 0x0088);
659423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x005D, 0x0088);
660423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x005E, 0x0088);
661423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x007D, 0x0088);
662423e3ce3SKalle Valo 		b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
663423e3ce3SKalle Valo 				      B43legacy_UCODEFLAGS_OFFSET,
664423e3ce3SKalle Valo 				      (b43legacy_shm_read32(dev,
665423e3ce3SKalle Valo 				      B43legacy_SHM_SHARED,
666423e3ce3SKalle Valo 				      B43legacy_UCODEFLAGS_OFFSET)
667423e3ce3SKalle Valo 				      | 0x00000200));
668423e3ce3SKalle Valo 	}
669423e3ce3SKalle Valo 	if (phy->radio_rev == 8) {
670423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x0051, 0x0000);
671423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x0052, 0x0040);
672423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x0053, 0x00B7);
673423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x0054, 0x0098);
674423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x005A, 0x0088);
675423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x005B, 0x006B);
676423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x005C, 0x000F);
677423e3ce3SKalle Valo 		if (dev->dev->bus->sprom.boardflags_lo & 0x8000) {
678423e3ce3SKalle Valo 			b43legacy_radio_write16(dev, 0x005D, 0x00FA);
679423e3ce3SKalle Valo 			b43legacy_radio_write16(dev, 0x005E, 0x00D8);
680423e3ce3SKalle Valo 		} else {
681423e3ce3SKalle Valo 			b43legacy_radio_write16(dev, 0x005D, 0x00F5);
682423e3ce3SKalle Valo 			b43legacy_radio_write16(dev, 0x005E, 0x00B8);
683423e3ce3SKalle Valo 		}
684423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x0073, 0x0003);
685423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x007D, 0x00A8);
686423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x007C, 0x0001);
687423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x007E, 0x0008);
688423e3ce3SKalle Valo 	}
689423e3ce3SKalle Valo 	val = 0x1E1F;
690423e3ce3SKalle Valo 	for (offset = 0x0088; offset < 0x0098; offset++) {
691423e3ce3SKalle Valo 		b43legacy_phy_write(dev, offset, val);
692423e3ce3SKalle Valo 		val -= 0x0202;
693423e3ce3SKalle Valo 	}
694423e3ce3SKalle Valo 	val = 0x3E3F;
695423e3ce3SKalle Valo 	for (offset = 0x0098; offset < 0x00A8; offset++) {
696423e3ce3SKalle Valo 		b43legacy_phy_write(dev, offset, val);
697423e3ce3SKalle Valo 		val -= 0x0202;
698423e3ce3SKalle Valo 	}
699423e3ce3SKalle Valo 	val = 0x2120;
700423e3ce3SKalle Valo 	for (offset = 0x00A8; offset < 0x00C8; offset++) {
701423e3ce3SKalle Valo 		b43legacy_phy_write(dev, offset, (val & 0x3F3F));
702423e3ce3SKalle Valo 		val += 0x0202;
703423e3ce3SKalle Valo 	}
704423e3ce3SKalle Valo 	if (phy->type == B43legacy_PHYTYPE_G) {
705423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x007A,
706423e3ce3SKalle Valo 					b43legacy_radio_read16(dev, 0x007A) |
707423e3ce3SKalle Valo 					0x0020);
708423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x0051,
709423e3ce3SKalle Valo 					b43legacy_radio_read16(dev, 0x0051) |
710423e3ce3SKalle Valo 					0x0004);
711423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0802,
712423e3ce3SKalle Valo 				    b43legacy_phy_read(dev, 0x0802) | 0x0100);
713423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x042B,
714423e3ce3SKalle Valo 				    b43legacy_phy_read(dev, 0x042B) | 0x2000);
715423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x5B, 0x0000);
716423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x5C, 0x0000);
717423e3ce3SKalle Valo 	}
718423e3ce3SKalle Valo 
719423e3ce3SKalle Valo 	old_channel = phy->channel;
720423e3ce3SKalle Valo 	if (old_channel >= 8)
721423e3ce3SKalle Valo 		b43legacy_radio_selectchannel(dev, 1, 0);
722423e3ce3SKalle Valo 	else
723423e3ce3SKalle Valo 		b43legacy_radio_selectchannel(dev, 13, 0);
724423e3ce3SKalle Valo 
725423e3ce3SKalle Valo 	b43legacy_radio_write16(dev, 0x0050, 0x0020);
726423e3ce3SKalle Valo 	b43legacy_radio_write16(dev, 0x0050, 0x0023);
727423e3ce3SKalle Valo 	udelay(40);
728423e3ce3SKalle Valo 	if (phy->radio_rev < 6 || phy->radio_rev == 8) {
729423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x007C,
730423e3ce3SKalle Valo 					(b43legacy_radio_read16(dev, 0x007C)
731423e3ce3SKalle Valo 					| 0x0002));
732423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x0050, 0x0020);
733423e3ce3SKalle Valo 	}
734423e3ce3SKalle Valo 	if (phy->radio_rev <= 2) {
735423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x0050, 0x0020);
736423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x005A, 0x0070);
737423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x005B, 0x007B);
738423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x005C, 0x00B0);
739423e3ce3SKalle Valo 	}
740423e3ce3SKalle Valo 	b43legacy_radio_write16(dev, 0x007A,
741423e3ce3SKalle Valo 				(b43legacy_radio_read16(dev,
742423e3ce3SKalle Valo 				0x007A) & 0x00F8) | 0x0007);
743423e3ce3SKalle Valo 
744423e3ce3SKalle Valo 	b43legacy_radio_selectchannel(dev, old_channel, 0);
745423e3ce3SKalle Valo 
746423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0014, 0x0200);
747423e3ce3SKalle Valo 	if (phy->radio_rev >= 6)
748423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x002A, 0x88C2);
749423e3ce3SKalle Valo 	else
750423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x002A, 0x8AC0);
751423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0038, 0x0668);
752423e3ce3SKalle Valo 	b43legacy_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF);
753423e3ce3SKalle Valo 	if (phy->radio_rev == 4 || phy->radio_rev == 5)
754423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x005D, (b43legacy_phy_read(dev,
755423e3ce3SKalle Valo 				    0x005D) & 0xFF80) | 0x0003);
756423e3ce3SKalle Valo 	if (phy->radio_rev <= 2)
757423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x005D, 0x000D);
758423e3ce3SKalle Valo 
759423e3ce3SKalle Valo 	if (phy->analog == 4) {
760423e3ce3SKalle Valo 		b43legacy_write16(dev, 0x03E4, 0x0009);
761423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x61, b43legacy_phy_read(dev, 0x61)
762423e3ce3SKalle Valo 				    & 0xFFF);
763423e3ce3SKalle Valo 	} else
764423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0002, (b43legacy_phy_read(dev,
765423e3ce3SKalle Valo 				    0x0002) & 0xFFC0) | 0x0004);
766423e3ce3SKalle Valo 	if (phy->type == B43legacy_PHYTYPE_G)
767423e3ce3SKalle Valo 		b43legacy_write16(dev, 0x03E6, 0x0);
768423e3ce3SKalle Valo 	if (phy->type == B43legacy_PHYTYPE_B) {
769423e3ce3SKalle Valo 		b43legacy_write16(dev, 0x03E6, 0x8140);
770423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0016, 0x0410);
771423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0017, 0x0820);
772423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0062, 0x0007);
773423e3ce3SKalle Valo 		b43legacy_radio_init2050(dev);
774423e3ce3SKalle Valo 		b43legacy_phy_lo_g_measure(dev);
775423e3ce3SKalle Valo 		if (dev->dev->bus->sprom.boardflags_lo &
776423e3ce3SKalle Valo 		    B43legacy_BFL_RSSI) {
777423e3ce3SKalle Valo 			b43legacy_calc_nrssi_slope(dev);
778423e3ce3SKalle Valo 			b43legacy_calc_nrssi_threshold(dev);
779423e3ce3SKalle Valo 		}
780423e3ce3SKalle Valo 		b43legacy_phy_init_pctl(dev);
781423e3ce3SKalle Valo 	}
782423e3ce3SKalle Valo }
783423e3ce3SKalle Valo 
b43legacy_calc_loopback_gain(struct b43legacy_wldev * dev)784423e3ce3SKalle Valo static void b43legacy_calc_loopback_gain(struct b43legacy_wldev *dev)
785423e3ce3SKalle Valo {
786423e3ce3SKalle Valo 	struct b43legacy_phy *phy = &dev->phy;
787423e3ce3SKalle Valo 	u16 backup_phy[15] = {0};
788423e3ce3SKalle Valo 	u16 backup_radio[3];
789423e3ce3SKalle Valo 	u16 backup_bband;
790423e3ce3SKalle Valo 	u16 i;
791423e3ce3SKalle Valo 	u16 loop1_cnt;
792423e3ce3SKalle Valo 	u16 loop1_done;
793423e3ce3SKalle Valo 	u16 loop1_omitted;
794423e3ce3SKalle Valo 	u16 loop2_done;
795423e3ce3SKalle Valo 
796423e3ce3SKalle Valo 	backup_phy[0] = b43legacy_phy_read(dev, 0x0429);
797423e3ce3SKalle Valo 	backup_phy[1] = b43legacy_phy_read(dev, 0x0001);
798423e3ce3SKalle Valo 	backup_phy[2] = b43legacy_phy_read(dev, 0x0811);
799423e3ce3SKalle Valo 	backup_phy[3] = b43legacy_phy_read(dev, 0x0812);
800423e3ce3SKalle Valo 	if (phy->rev != 1) {
801423e3ce3SKalle Valo 		backup_phy[4] = b43legacy_phy_read(dev, 0x0814);
802423e3ce3SKalle Valo 		backup_phy[5] = b43legacy_phy_read(dev, 0x0815);
803423e3ce3SKalle Valo 	}
804423e3ce3SKalle Valo 	backup_phy[6] = b43legacy_phy_read(dev, 0x005A);
805423e3ce3SKalle Valo 	backup_phy[7] = b43legacy_phy_read(dev, 0x0059);
806423e3ce3SKalle Valo 	backup_phy[8] = b43legacy_phy_read(dev, 0x0058);
807423e3ce3SKalle Valo 	backup_phy[9] = b43legacy_phy_read(dev, 0x000A);
808423e3ce3SKalle Valo 	backup_phy[10] = b43legacy_phy_read(dev, 0x0003);
809423e3ce3SKalle Valo 	backup_phy[11] = b43legacy_phy_read(dev, 0x080F);
810423e3ce3SKalle Valo 	backup_phy[12] = b43legacy_phy_read(dev, 0x0810);
811423e3ce3SKalle Valo 	backup_phy[13] = b43legacy_phy_read(dev, 0x002B);
812423e3ce3SKalle Valo 	backup_phy[14] = b43legacy_phy_read(dev, 0x0015);
813423e3ce3SKalle Valo 	b43legacy_phy_read(dev, 0x002D); /* dummy read */
814423e3ce3SKalle Valo 	backup_bband = phy->bbatt;
815423e3ce3SKalle Valo 	backup_radio[0] = b43legacy_radio_read16(dev, 0x0052);
816423e3ce3SKalle Valo 	backup_radio[1] = b43legacy_radio_read16(dev, 0x0043);
817423e3ce3SKalle Valo 	backup_radio[2] = b43legacy_radio_read16(dev, 0x007A);
818423e3ce3SKalle Valo 
819423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0429,
820423e3ce3SKalle Valo 			    b43legacy_phy_read(dev, 0x0429) & 0x3FFF);
821423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0001,
822423e3ce3SKalle Valo 			    b43legacy_phy_read(dev, 0x0001) & 0x8000);
823423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0811,
824423e3ce3SKalle Valo 			    b43legacy_phy_read(dev, 0x0811) | 0x0002);
825423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0812,
826423e3ce3SKalle Valo 			    b43legacy_phy_read(dev, 0x0812) & 0xFFFD);
827423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0811,
828423e3ce3SKalle Valo 			    b43legacy_phy_read(dev, 0x0811) | 0x0001);
829423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0812,
830423e3ce3SKalle Valo 			    b43legacy_phy_read(dev, 0x0812) & 0xFFFE);
831423e3ce3SKalle Valo 	if (phy->rev != 1) {
832423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0814,
833423e3ce3SKalle Valo 				    b43legacy_phy_read(dev, 0x0814) | 0x0001);
834423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0815,
835423e3ce3SKalle Valo 				    b43legacy_phy_read(dev, 0x0815) & 0xFFFE);
836423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0814,
837423e3ce3SKalle Valo 				    b43legacy_phy_read(dev, 0x0814) | 0x0002);
838423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0815,
839423e3ce3SKalle Valo 				    b43legacy_phy_read(dev, 0x0815) & 0xFFFD);
840423e3ce3SKalle Valo 	}
841423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0811, b43legacy_phy_read(dev, 0x0811) |
842423e3ce3SKalle Valo 			    0x000C);
843423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0812, b43legacy_phy_read(dev, 0x0812) |
844423e3ce3SKalle Valo 			    0x000C);
845423e3ce3SKalle Valo 
846423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0811, (b43legacy_phy_read(dev, 0x0811)
847423e3ce3SKalle Valo 			    & 0xFFCF) | 0x0030);
848423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0812, (b43legacy_phy_read(dev, 0x0812)
849423e3ce3SKalle Valo 			    & 0xFFCF) | 0x0010);
850423e3ce3SKalle Valo 
851423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x005A, 0x0780);
852423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0059, 0xC810);
853423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0058, 0x000D);
854423e3ce3SKalle Valo 	if (phy->analog == 0)
855423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0003, 0x0122);
856423e3ce3SKalle Valo 	else
857423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x000A,
858423e3ce3SKalle Valo 				    b43legacy_phy_read(dev, 0x000A)
859423e3ce3SKalle Valo 				    | 0x2000);
860423e3ce3SKalle Valo 	if (phy->rev != 1) {
861423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0814,
862423e3ce3SKalle Valo 				    b43legacy_phy_read(dev, 0x0814) | 0x0004);
863423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0815,
864423e3ce3SKalle Valo 				    b43legacy_phy_read(dev, 0x0815) & 0xFFFB);
865423e3ce3SKalle Valo 	}
866423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0003,
867423e3ce3SKalle Valo 			    (b43legacy_phy_read(dev, 0x0003)
868423e3ce3SKalle Valo 			     & 0xFF9F) | 0x0040);
869423e3ce3SKalle Valo 	if (phy->radio_ver == 0x2050 && phy->radio_rev == 2) {
870423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x0052, 0x0000);
871423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x0043,
872423e3ce3SKalle Valo 					(b43legacy_radio_read16(dev, 0x0043)
873423e3ce3SKalle Valo 					 & 0xFFF0) | 0x0009);
874423e3ce3SKalle Valo 		loop1_cnt = 9;
875423e3ce3SKalle Valo 	} else if (phy->radio_rev == 8) {
876423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x0043, 0x000F);
877423e3ce3SKalle Valo 		loop1_cnt = 15;
878423e3ce3SKalle Valo 	} else
879423e3ce3SKalle Valo 		loop1_cnt = 0;
880423e3ce3SKalle Valo 
881423e3ce3SKalle Valo 	b43legacy_phy_set_baseband_attenuation(dev, 11);
882423e3ce3SKalle Valo 
883423e3ce3SKalle Valo 	if (phy->rev >= 3)
884423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x080F, 0xC020);
885423e3ce3SKalle Valo 	else
886423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x080F, 0x8020);
887423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0810, 0x0000);
888423e3ce3SKalle Valo 
889423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x002B,
890423e3ce3SKalle Valo 			    (b43legacy_phy_read(dev, 0x002B)
891423e3ce3SKalle Valo 			     & 0xFFC0) | 0x0001);
892423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x002B,
893423e3ce3SKalle Valo 			    (b43legacy_phy_read(dev, 0x002B)
894423e3ce3SKalle Valo 			     & 0xC0FF) | 0x0800);
895423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0811,
896423e3ce3SKalle Valo 			    b43legacy_phy_read(dev, 0x0811) | 0x0100);
897423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0812,
898423e3ce3SKalle Valo 			    b43legacy_phy_read(dev, 0x0812) & 0xCFFF);
899423e3ce3SKalle Valo 	if (dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_EXTLNA) {
900423e3ce3SKalle Valo 		if (phy->rev >= 7) {
901423e3ce3SKalle Valo 			b43legacy_phy_write(dev, 0x0811,
902423e3ce3SKalle Valo 					    b43legacy_phy_read(dev, 0x0811)
903423e3ce3SKalle Valo 					    | 0x0800);
904423e3ce3SKalle Valo 			b43legacy_phy_write(dev, 0x0812,
905423e3ce3SKalle Valo 					    b43legacy_phy_read(dev, 0x0812)
906423e3ce3SKalle Valo 					    | 0x8000);
907423e3ce3SKalle Valo 		}
908423e3ce3SKalle Valo 	}
909423e3ce3SKalle Valo 	b43legacy_radio_write16(dev, 0x007A,
910423e3ce3SKalle Valo 				b43legacy_radio_read16(dev, 0x007A)
911423e3ce3SKalle Valo 				& 0x00F7);
912423e3ce3SKalle Valo 
913423e3ce3SKalle Valo 	for (i = 0; i < loop1_cnt; i++) {
914423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x0043, loop1_cnt);
915423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0812,
916423e3ce3SKalle Valo 				    (b43legacy_phy_read(dev, 0x0812)
917423e3ce3SKalle Valo 				     & 0xF0FF) | (i << 8));
918423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0015,
919423e3ce3SKalle Valo 				    (b43legacy_phy_read(dev, 0x0015)
920423e3ce3SKalle Valo 				     & 0x0FFF) | 0xA000);
921423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0015,
922423e3ce3SKalle Valo 				    (b43legacy_phy_read(dev, 0x0015)
923423e3ce3SKalle Valo 				     & 0x0FFF) | 0xF000);
924423e3ce3SKalle Valo 		udelay(20);
925423e3ce3SKalle Valo 		if (b43legacy_phy_read(dev, 0x002D) >= 0x0DFC)
926423e3ce3SKalle Valo 			break;
927423e3ce3SKalle Valo 	}
928423e3ce3SKalle Valo 	loop1_done = i;
929423e3ce3SKalle Valo 	loop1_omitted = loop1_cnt - loop1_done;
930423e3ce3SKalle Valo 
931423e3ce3SKalle Valo 	loop2_done = 0;
932423e3ce3SKalle Valo 	if (loop1_done >= 8) {
933423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0812,
934423e3ce3SKalle Valo 				    b43legacy_phy_read(dev, 0x0812)
935423e3ce3SKalle Valo 				    | 0x0030);
936423e3ce3SKalle Valo 		for (i = loop1_done - 8; i < 16; i++) {
937423e3ce3SKalle Valo 			b43legacy_phy_write(dev, 0x0812,
938423e3ce3SKalle Valo 					    (b43legacy_phy_read(dev, 0x0812)
939423e3ce3SKalle Valo 					     & 0xF0FF) | (i << 8));
940423e3ce3SKalle Valo 			b43legacy_phy_write(dev, 0x0015,
941423e3ce3SKalle Valo 					    (b43legacy_phy_read(dev, 0x0015)
942423e3ce3SKalle Valo 					     & 0x0FFF) | 0xA000);
943423e3ce3SKalle Valo 			b43legacy_phy_write(dev, 0x0015,
944423e3ce3SKalle Valo 					    (b43legacy_phy_read(dev, 0x0015)
945423e3ce3SKalle Valo 					     & 0x0FFF) | 0xF000);
946423e3ce3SKalle Valo 			udelay(20);
947423e3ce3SKalle Valo 			if (b43legacy_phy_read(dev, 0x002D) >= 0x0DFC)
948423e3ce3SKalle Valo 				break;
949423e3ce3SKalle Valo 		}
950423e3ce3SKalle Valo 	}
951423e3ce3SKalle Valo 
952423e3ce3SKalle Valo 	if (phy->rev != 1) {
953423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0814, backup_phy[4]);
954423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0815, backup_phy[5]);
955423e3ce3SKalle Valo 	}
956423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x005A, backup_phy[6]);
957423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0059, backup_phy[7]);
958423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0058, backup_phy[8]);
959423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x000A, backup_phy[9]);
960423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0003, backup_phy[10]);
961423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x080F, backup_phy[11]);
962423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0810, backup_phy[12]);
963423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x002B, backup_phy[13]);
964423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0015, backup_phy[14]);
965423e3ce3SKalle Valo 
966423e3ce3SKalle Valo 	b43legacy_phy_set_baseband_attenuation(dev, backup_bband);
967423e3ce3SKalle Valo 
968423e3ce3SKalle Valo 	b43legacy_radio_write16(dev, 0x0052, backup_radio[0]);
969423e3ce3SKalle Valo 	b43legacy_radio_write16(dev, 0x0043, backup_radio[1]);
970423e3ce3SKalle Valo 	b43legacy_radio_write16(dev, 0x007A, backup_radio[2]);
971423e3ce3SKalle Valo 
972423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0811, backup_phy[2] | 0x0003);
973423e3ce3SKalle Valo 	udelay(10);
974423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0811, backup_phy[2]);
975423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0812, backup_phy[3]);
976423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0429, backup_phy[0]);
977423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0001, backup_phy[1]);
978423e3ce3SKalle Valo 
979423e3ce3SKalle Valo 	phy->loopback_gain[0] = ((loop1_done * 6) - (loop1_omitted * 4)) - 11;
980423e3ce3SKalle Valo 	phy->loopback_gain[1] = (24 - (3 * loop2_done)) * 2;
981423e3ce3SKalle Valo }
982423e3ce3SKalle Valo 
b43legacy_phy_initg(struct b43legacy_wldev * dev)983423e3ce3SKalle Valo static void b43legacy_phy_initg(struct b43legacy_wldev *dev)
984423e3ce3SKalle Valo {
985423e3ce3SKalle Valo 	struct b43legacy_phy *phy = &dev->phy;
986423e3ce3SKalle Valo 	u16 tmp;
987423e3ce3SKalle Valo 
988423e3ce3SKalle Valo 	if (phy->rev == 1)
989423e3ce3SKalle Valo 		b43legacy_phy_initb5(dev);
990423e3ce3SKalle Valo 	else
991423e3ce3SKalle Valo 		b43legacy_phy_initb6(dev);
992423e3ce3SKalle Valo 	if (phy->rev >= 2 && phy->gmode)
993423e3ce3SKalle Valo 		b43legacy_phy_inita(dev);
994423e3ce3SKalle Valo 
995423e3ce3SKalle Valo 	if (phy->rev >= 2) {
996423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0814, 0x0000);
997423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0815, 0x0000);
998423e3ce3SKalle Valo 	}
999423e3ce3SKalle Valo 	if (phy->rev == 2) {
1000423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0811, 0x0000);
1001423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0015, 0x00C0);
1002423e3ce3SKalle Valo 	}
1003423e3ce3SKalle Valo 	if (phy->rev > 5) {
1004423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0811, 0x0400);
1005423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0015, 0x00C0);
1006423e3ce3SKalle Valo 	}
1007423e3ce3SKalle Valo 	if (phy->gmode) {
1008423e3ce3SKalle Valo 		tmp = b43legacy_phy_read(dev, 0x0400) & 0xFF;
1009423e3ce3SKalle Valo 		if (tmp == 3) {
1010423e3ce3SKalle Valo 			b43legacy_phy_write(dev, 0x04C2, 0x1816);
1011423e3ce3SKalle Valo 			b43legacy_phy_write(dev, 0x04C3, 0x8606);
1012423e3ce3SKalle Valo 		}
1013423e3ce3SKalle Valo 		if (tmp == 4 || tmp == 5) {
1014423e3ce3SKalle Valo 			b43legacy_phy_write(dev, 0x04C2, 0x1816);
1015423e3ce3SKalle Valo 			b43legacy_phy_write(dev, 0x04C3, 0x8006);
1016423e3ce3SKalle Valo 			b43legacy_phy_write(dev, 0x04CC,
1017423e3ce3SKalle Valo 					    (b43legacy_phy_read(dev,
1018423e3ce3SKalle Valo 					     0x04CC) & 0x00FF) |
1019423e3ce3SKalle Valo 					     0x1F00);
1020423e3ce3SKalle Valo 		}
1021423e3ce3SKalle Valo 		if (phy->rev >= 2)
1022423e3ce3SKalle Valo 			b43legacy_phy_write(dev, 0x047E, 0x0078);
1023423e3ce3SKalle Valo 	}
1024423e3ce3SKalle Valo 	if (phy->radio_rev == 8) {
1025423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0801, b43legacy_phy_read(dev, 0x0801)
1026423e3ce3SKalle Valo 				    | 0x0080);
1027423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x043E, b43legacy_phy_read(dev, 0x043E)
1028423e3ce3SKalle Valo 				    | 0x0004);
1029423e3ce3SKalle Valo 	}
1030423e3ce3SKalle Valo 	if (phy->rev >= 2 && phy->gmode)
1031423e3ce3SKalle Valo 		b43legacy_calc_loopback_gain(dev);
1032423e3ce3SKalle Valo 	if (phy->radio_rev != 8) {
1033423e3ce3SKalle Valo 		if (phy->initval == 0xFFFF)
1034423e3ce3SKalle Valo 			phy->initval = b43legacy_radio_init2050(dev);
1035423e3ce3SKalle Valo 		else
1036423e3ce3SKalle Valo 			b43legacy_radio_write16(dev, 0x0078, phy->initval);
1037423e3ce3SKalle Valo 	}
1038423e3ce3SKalle Valo 	if (phy->txctl2 == 0xFFFF)
1039423e3ce3SKalle Valo 		b43legacy_phy_lo_g_measure(dev);
1040423e3ce3SKalle Valo 	else {
1041423e3ce3SKalle Valo 		if (phy->radio_ver == 0x2050 && phy->radio_rev == 8)
1042423e3ce3SKalle Valo 			b43legacy_radio_write16(dev, 0x0052,
1043423e3ce3SKalle Valo 						(phy->txctl1 << 4) |
1044423e3ce3SKalle Valo 						phy->txctl2);
1045423e3ce3SKalle Valo 		else
1046423e3ce3SKalle Valo 			b43legacy_radio_write16(dev, 0x0052,
1047423e3ce3SKalle Valo 						(b43legacy_radio_read16(dev,
1048423e3ce3SKalle Valo 						 0x0052) & 0xFFF0) |
1049423e3ce3SKalle Valo 						 phy->txctl1);
1050423e3ce3SKalle Valo 		if (phy->rev >= 6)
1051423e3ce3SKalle Valo 			b43legacy_phy_write(dev, 0x0036,
1052423e3ce3SKalle Valo 					    (b43legacy_phy_read(dev, 0x0036)
1053423e3ce3SKalle Valo 					     & 0x0FFF) | (phy->txctl2 << 12));
1054423e3ce3SKalle Valo 		if (dev->dev->bus->sprom.boardflags_lo &
1055423e3ce3SKalle Valo 		    B43legacy_BFL_PACTRL)
1056423e3ce3SKalle Valo 			b43legacy_phy_write(dev, 0x002E, 0x8075);
1057423e3ce3SKalle Valo 		else
1058423e3ce3SKalle Valo 			b43legacy_phy_write(dev, 0x002E, 0x807F);
1059423e3ce3SKalle Valo 		if (phy->rev < 2)
1060423e3ce3SKalle Valo 			b43legacy_phy_write(dev, 0x002F, 0x0101);
1061423e3ce3SKalle Valo 		else
1062423e3ce3SKalle Valo 			b43legacy_phy_write(dev, 0x002F, 0x0202);
1063423e3ce3SKalle Valo 	}
1064423e3ce3SKalle Valo 	if (phy->gmode) {
1065423e3ce3SKalle Valo 		b43legacy_phy_lo_adjust(dev, 0);
1066423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x080F, 0x8078);
1067423e3ce3SKalle Valo 	}
1068423e3ce3SKalle Valo 
1069423e3ce3SKalle Valo 	if (!(dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_RSSI)) {
1070423e3ce3SKalle Valo 		/* The specs state to update the NRSSI LT with
1071423e3ce3SKalle Valo 		 * the value 0x7FFFFFFF here. I think that is some weird
1072423e3ce3SKalle Valo 		 * compiler optimization in the original driver.
1073423e3ce3SKalle Valo 		 * Essentially, what we do here is resetting all NRSSI LT
1074423e3ce3SKalle Valo 		 * entries to -32 (see the clamp_val() in nrssi_hw_update())
1075423e3ce3SKalle Valo 		 */
1076423e3ce3SKalle Valo 		b43legacy_nrssi_hw_update(dev, 0xFFFF);
1077423e3ce3SKalle Valo 		b43legacy_calc_nrssi_threshold(dev);
1078423e3ce3SKalle Valo 	} else if (phy->gmode || phy->rev >= 2) {
1079423e3ce3SKalle Valo 		if (phy->nrssi[0] == -1000) {
1080423e3ce3SKalle Valo 			B43legacy_WARN_ON(phy->nrssi[1] != -1000);
1081423e3ce3SKalle Valo 			b43legacy_calc_nrssi_slope(dev);
1082423e3ce3SKalle Valo 		} else {
1083423e3ce3SKalle Valo 			B43legacy_WARN_ON(phy->nrssi[1] == -1000);
1084423e3ce3SKalle Valo 			b43legacy_calc_nrssi_threshold(dev);
1085423e3ce3SKalle Valo 		}
1086423e3ce3SKalle Valo 	}
1087423e3ce3SKalle Valo 	if (phy->radio_rev == 8)
1088423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0805, 0x3230);
1089423e3ce3SKalle Valo 	b43legacy_phy_init_pctl(dev);
1090423e3ce3SKalle Valo 	if (dev->dev->bus->chip_id == 0x4306
1091423e3ce3SKalle Valo 	    && dev->dev->bus->chip_package == 2) {
1092423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0429,
1093423e3ce3SKalle Valo 				    b43legacy_phy_read(dev, 0x0429) & 0xBFFF);
1094423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x04C3,
1095423e3ce3SKalle Valo 				    b43legacy_phy_read(dev, 0x04C3) & 0x7FFF);
1096423e3ce3SKalle Valo 	}
1097423e3ce3SKalle Valo }
1098423e3ce3SKalle Valo 
b43legacy_phy_lo_b_r15_loop(struct b43legacy_wldev * dev)1099423e3ce3SKalle Valo static u16 b43legacy_phy_lo_b_r15_loop(struct b43legacy_wldev *dev)
1100423e3ce3SKalle Valo {
1101423e3ce3SKalle Valo 	int i;
1102423e3ce3SKalle Valo 	u16 ret = 0;
1103423e3ce3SKalle Valo 	unsigned long flags;
1104423e3ce3SKalle Valo 
1105423e3ce3SKalle Valo 	local_irq_save(flags);
1106423e3ce3SKalle Valo 	for (i = 0; i < 10; i++) {
1107423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0015, 0xAFA0);
1108423e3ce3SKalle Valo 		udelay(1);
1109423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0015, 0xEFA0);
1110423e3ce3SKalle Valo 		udelay(10);
1111423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0015, 0xFFA0);
1112423e3ce3SKalle Valo 		udelay(40);
1113423e3ce3SKalle Valo 		ret += b43legacy_phy_read(dev, 0x002C);
1114423e3ce3SKalle Valo 	}
1115423e3ce3SKalle Valo 	local_irq_restore(flags);
11166004cf29SThomas Gleixner 	cond_resched();
1117423e3ce3SKalle Valo 
1118423e3ce3SKalle Valo 	return ret;
1119423e3ce3SKalle Valo }
1120423e3ce3SKalle Valo 
b43legacy_phy_lo_b_measure(struct b43legacy_wldev * dev)1121423e3ce3SKalle Valo void b43legacy_phy_lo_b_measure(struct b43legacy_wldev *dev)
1122423e3ce3SKalle Valo {
1123423e3ce3SKalle Valo 	struct b43legacy_phy *phy = &dev->phy;
1124423e3ce3SKalle Valo 	u16 regstack[12] = { 0 };
1125423e3ce3SKalle Valo 	u16 mls;
1126e7823a60SHaowen Bai 	s16 fval;
1127423e3ce3SKalle Valo 	int i;
1128423e3ce3SKalle Valo 	int j;
1129423e3ce3SKalle Valo 
1130423e3ce3SKalle Valo 	regstack[0] = b43legacy_phy_read(dev, 0x0015);
1131423e3ce3SKalle Valo 	regstack[1] = b43legacy_radio_read16(dev, 0x0052) & 0xFFF0;
1132423e3ce3SKalle Valo 
1133423e3ce3SKalle Valo 	if (phy->radio_ver == 0x2053) {
1134423e3ce3SKalle Valo 		regstack[2] = b43legacy_phy_read(dev, 0x000A);
1135423e3ce3SKalle Valo 		regstack[3] = b43legacy_phy_read(dev, 0x002A);
1136423e3ce3SKalle Valo 		regstack[4] = b43legacy_phy_read(dev, 0x0035);
1137423e3ce3SKalle Valo 		regstack[5] = b43legacy_phy_read(dev, 0x0003);
1138423e3ce3SKalle Valo 		regstack[6] = b43legacy_phy_read(dev, 0x0001);
1139423e3ce3SKalle Valo 		regstack[7] = b43legacy_phy_read(dev, 0x0030);
1140423e3ce3SKalle Valo 
1141423e3ce3SKalle Valo 		regstack[8] = b43legacy_radio_read16(dev, 0x0043);
1142423e3ce3SKalle Valo 		regstack[9] = b43legacy_radio_read16(dev, 0x007A);
1143423e3ce3SKalle Valo 		regstack[10] = b43legacy_read16(dev, 0x03EC);
1144423e3ce3SKalle Valo 		regstack[11] = b43legacy_radio_read16(dev, 0x0052) & 0x00F0;
1145423e3ce3SKalle Valo 
1146423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0030, 0x00FF);
1147423e3ce3SKalle Valo 		b43legacy_write16(dev, 0x03EC, 0x3F3F);
1148423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0035, regstack[4] & 0xFF7F);
1149423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x007A, regstack[9] & 0xFFF0);
1150423e3ce3SKalle Valo 	}
1151423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0015, 0xB000);
1152423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x002B, 0x0004);
1153423e3ce3SKalle Valo 
1154423e3ce3SKalle Valo 	if (phy->radio_ver == 0x2053) {
1155423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x002B, 0x0203);
1156423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x002A, 0x08A3);
1157423e3ce3SKalle Valo 	}
1158423e3ce3SKalle Valo 
1159423e3ce3SKalle Valo 	phy->minlowsig[0] = 0xFFFF;
1160423e3ce3SKalle Valo 
1161423e3ce3SKalle Valo 	for (i = 0; i < 4; i++) {
1162423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x0052, regstack[1] | i);
1163423e3ce3SKalle Valo 		b43legacy_phy_lo_b_r15_loop(dev);
1164423e3ce3SKalle Valo 	}
1165423e3ce3SKalle Valo 	for (i = 0; i < 10; i++) {
1166423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x0052, regstack[1] | i);
1167423e3ce3SKalle Valo 		mls = b43legacy_phy_lo_b_r15_loop(dev) / 10;
1168423e3ce3SKalle Valo 		if (mls < phy->minlowsig[0]) {
1169423e3ce3SKalle Valo 			phy->minlowsig[0] = mls;
1170423e3ce3SKalle Valo 			phy->minlowsigpos[0] = i;
1171423e3ce3SKalle Valo 		}
1172423e3ce3SKalle Valo 	}
1173423e3ce3SKalle Valo 	b43legacy_radio_write16(dev, 0x0052, regstack[1]
1174423e3ce3SKalle Valo 				| phy->minlowsigpos[0]);
1175423e3ce3SKalle Valo 
1176423e3ce3SKalle Valo 	phy->minlowsig[1] = 0xFFFF;
1177423e3ce3SKalle Valo 
1178423e3ce3SKalle Valo 	for (i = -4; i < 5; i += 2) {
1179423e3ce3SKalle Valo 		for (j = -4; j < 5; j += 2) {
1180423e3ce3SKalle Valo 			if (j < 0)
1181423e3ce3SKalle Valo 				fval = (0x0100 * i) + j + 0x0100;
1182423e3ce3SKalle Valo 			else
1183423e3ce3SKalle Valo 				fval = (0x0100 * i) + j;
1184423e3ce3SKalle Valo 			b43legacy_phy_write(dev, 0x002F, fval);
1185423e3ce3SKalle Valo 			mls = b43legacy_phy_lo_b_r15_loop(dev) / 10;
1186423e3ce3SKalle Valo 			if (mls < phy->minlowsig[1]) {
1187423e3ce3SKalle Valo 				phy->minlowsig[1] = mls;
1188423e3ce3SKalle Valo 				phy->minlowsigpos[1] = fval;
1189423e3ce3SKalle Valo 			}
1190423e3ce3SKalle Valo 		}
1191423e3ce3SKalle Valo 	}
1192423e3ce3SKalle Valo 	phy->minlowsigpos[1] += 0x0101;
1193423e3ce3SKalle Valo 
1194423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x002F, phy->minlowsigpos[1]);
1195423e3ce3SKalle Valo 	if (phy->radio_ver == 0x2053) {
1196423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x000A, regstack[2]);
1197423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x002A, regstack[3]);
1198423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0035, regstack[4]);
1199423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0003, regstack[5]);
1200423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0001, regstack[6]);
1201423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0030, regstack[7]);
1202423e3ce3SKalle Valo 
1203423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x0043, regstack[8]);
1204423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x007A, regstack[9]);
1205423e3ce3SKalle Valo 
1206423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x0052,
1207423e3ce3SKalle Valo 					(b43legacy_radio_read16(dev, 0x0052)
1208423e3ce3SKalle Valo 					& 0x000F) | regstack[11]);
1209423e3ce3SKalle Valo 
1210423e3ce3SKalle Valo 		b43legacy_write16(dev, 0x03EC, regstack[10]);
1211423e3ce3SKalle Valo 	}
1212423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0015, regstack[0]);
1213423e3ce3SKalle Valo }
1214423e3ce3SKalle Valo 
1215423e3ce3SKalle Valo static inline
b43legacy_phy_lo_g_deviation_subval(struct b43legacy_wldev * dev,u16 control)1216423e3ce3SKalle Valo u16 b43legacy_phy_lo_g_deviation_subval(struct b43legacy_wldev *dev,
1217423e3ce3SKalle Valo 					u16 control)
1218423e3ce3SKalle Valo {
1219423e3ce3SKalle Valo 	struct b43legacy_phy *phy = &dev->phy;
1220423e3ce3SKalle Valo 	u16 ret;
1221423e3ce3SKalle Valo 	unsigned long flags;
1222423e3ce3SKalle Valo 
1223423e3ce3SKalle Valo 	local_irq_save(flags);
1224423e3ce3SKalle Valo 	if (phy->gmode) {
1225423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x15, 0xE300);
1226423e3ce3SKalle Valo 		control <<= 8;
1227423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0812, control | 0x00B0);
1228423e3ce3SKalle Valo 		udelay(5);
1229423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0812, control | 0x00B2);
1230423e3ce3SKalle Valo 		udelay(2);
1231423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0812, control | 0x00B3);
1232423e3ce3SKalle Valo 		udelay(4);
1233423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0015, 0xF300);
1234423e3ce3SKalle Valo 		udelay(8);
1235423e3ce3SKalle Valo 	} else {
1236423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0015, control | 0xEFA0);
1237423e3ce3SKalle Valo 		udelay(2);
1238423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0015, control | 0xEFE0);
1239423e3ce3SKalle Valo 		udelay(4);
1240423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0015, control | 0xFFE0);
1241423e3ce3SKalle Valo 		udelay(8);
1242423e3ce3SKalle Valo 	}
1243423e3ce3SKalle Valo 	ret = b43legacy_phy_read(dev, 0x002D);
1244423e3ce3SKalle Valo 	local_irq_restore(flags);
12456004cf29SThomas Gleixner 	cond_resched();
1246423e3ce3SKalle Valo 
1247423e3ce3SKalle Valo 	return ret;
1248423e3ce3SKalle Valo }
1249423e3ce3SKalle Valo 
b43legacy_phy_lo_g_singledeviation(struct b43legacy_wldev * dev,u16 control)1250423e3ce3SKalle Valo static u32 b43legacy_phy_lo_g_singledeviation(struct b43legacy_wldev *dev,
1251423e3ce3SKalle Valo 					      u16 control)
1252423e3ce3SKalle Valo {
1253423e3ce3SKalle Valo 	int i;
1254423e3ce3SKalle Valo 	u32 ret = 0;
1255423e3ce3SKalle Valo 
1256423e3ce3SKalle Valo 	for (i = 0; i < 8; i++)
1257423e3ce3SKalle Valo 		ret += b43legacy_phy_lo_g_deviation_subval(dev, control);
1258423e3ce3SKalle Valo 
1259423e3ce3SKalle Valo 	return ret;
1260423e3ce3SKalle Valo }
1261423e3ce3SKalle Valo 
1262423e3ce3SKalle Valo /* Write the LocalOscillator CONTROL */
1263423e3ce3SKalle Valo static inline
b43legacy_lo_write(struct b43legacy_wldev * dev,struct b43legacy_lopair * pair)1264423e3ce3SKalle Valo void b43legacy_lo_write(struct b43legacy_wldev *dev,
1265423e3ce3SKalle Valo 			struct b43legacy_lopair *pair)
1266423e3ce3SKalle Valo {
1267423e3ce3SKalle Valo 	u16 value;
1268423e3ce3SKalle Valo 
1269423e3ce3SKalle Valo 	value = (u8)(pair->low);
1270423e3ce3SKalle Valo 	value |= ((u8)(pair->high)) << 8;
1271423e3ce3SKalle Valo 
1272423e3ce3SKalle Valo #ifdef CONFIG_B43LEGACY_DEBUG
1273423e3ce3SKalle Valo 	/* Sanity check. */
1274423e3ce3SKalle Valo 	if (pair->low < -8 || pair->low > 8 ||
1275423e3ce3SKalle Valo 	    pair->high < -8 || pair->high > 8) {
1276423e3ce3SKalle Valo 		b43legacydbg(dev->wl,
1277423e3ce3SKalle Valo 		       "WARNING: Writing invalid LOpair "
1278423e3ce3SKalle Valo 		       "(low: %d, high: %d)\n",
1279423e3ce3SKalle Valo 		       pair->low, pair->high);
1280423e3ce3SKalle Valo 		dump_stack();
1281423e3ce3SKalle Valo 	}
1282423e3ce3SKalle Valo #endif
1283423e3ce3SKalle Valo 
1284423e3ce3SKalle Valo 	b43legacy_phy_write(dev, B43legacy_PHY_G_LO_CONTROL, value);
1285423e3ce3SKalle Valo }
1286423e3ce3SKalle Valo 
1287423e3ce3SKalle Valo static inline
b43legacy_find_lopair(struct b43legacy_wldev * dev,u16 bbatt,u16 rfatt,u16 tx)1288423e3ce3SKalle Valo struct b43legacy_lopair *b43legacy_find_lopair(struct b43legacy_wldev *dev,
1289423e3ce3SKalle Valo 					       u16 bbatt,
1290423e3ce3SKalle Valo 					       u16 rfatt,
1291423e3ce3SKalle Valo 					       u16 tx)
1292423e3ce3SKalle Valo {
1293423e3ce3SKalle Valo 	static const u8 dict[10] = { 11, 10, 11, 12, 13, 12, 13, 12, 13, 12 };
1294423e3ce3SKalle Valo 	struct b43legacy_phy *phy = &dev->phy;
1295423e3ce3SKalle Valo 
1296423e3ce3SKalle Valo 	if (bbatt > 6)
1297423e3ce3SKalle Valo 		bbatt = 6;
1298423e3ce3SKalle Valo 	B43legacy_WARN_ON(rfatt >= 10);
1299423e3ce3SKalle Valo 
1300423e3ce3SKalle Valo 	if (tx == 3)
1301423e3ce3SKalle Valo 		return b43legacy_get_lopair(phy, rfatt, bbatt);
1302423e3ce3SKalle Valo 	return b43legacy_get_lopair(phy, dict[rfatt], bbatt);
1303423e3ce3SKalle Valo }
1304423e3ce3SKalle Valo 
1305423e3ce3SKalle Valo static inline
b43legacy_current_lopair(struct b43legacy_wldev * dev)1306423e3ce3SKalle Valo struct b43legacy_lopair *b43legacy_current_lopair(struct b43legacy_wldev *dev)
1307423e3ce3SKalle Valo {
1308423e3ce3SKalle Valo 	struct b43legacy_phy *phy = &dev->phy;
1309423e3ce3SKalle Valo 
1310423e3ce3SKalle Valo 	return b43legacy_find_lopair(dev, phy->bbatt,
1311423e3ce3SKalle Valo 				     phy->rfatt, phy->txctl1);
1312423e3ce3SKalle Valo }
1313423e3ce3SKalle Valo 
1314423e3ce3SKalle Valo /* Adjust B/G LO */
b43legacy_phy_lo_adjust(struct b43legacy_wldev * dev,int fixed)1315423e3ce3SKalle Valo void b43legacy_phy_lo_adjust(struct b43legacy_wldev *dev, int fixed)
1316423e3ce3SKalle Valo {
1317423e3ce3SKalle Valo 	struct b43legacy_lopair *pair;
1318423e3ce3SKalle Valo 
1319423e3ce3SKalle Valo 	if (fixed) {
1320423e3ce3SKalle Valo 		/* Use fixed values. Only for initialization. */
1321423e3ce3SKalle Valo 		pair = b43legacy_find_lopair(dev, 2, 3, 0);
1322423e3ce3SKalle Valo 	} else
1323423e3ce3SKalle Valo 		pair = b43legacy_current_lopair(dev);
1324423e3ce3SKalle Valo 	b43legacy_lo_write(dev, pair);
1325423e3ce3SKalle Valo }
1326423e3ce3SKalle Valo 
b43legacy_phy_lo_g_measure_txctl2(struct b43legacy_wldev * dev)1327423e3ce3SKalle Valo static void b43legacy_phy_lo_g_measure_txctl2(struct b43legacy_wldev *dev)
1328423e3ce3SKalle Valo {
1329423e3ce3SKalle Valo 	struct b43legacy_phy *phy = &dev->phy;
1330423e3ce3SKalle Valo 	u16 txctl2 = 0;
1331423e3ce3SKalle Valo 	u16 i;
1332423e3ce3SKalle Valo 	u32 smallest;
1333423e3ce3SKalle Valo 	u32 tmp;
1334423e3ce3SKalle Valo 
1335423e3ce3SKalle Valo 	b43legacy_radio_write16(dev, 0x0052, 0x0000);
1336423e3ce3SKalle Valo 	udelay(10);
1337423e3ce3SKalle Valo 	smallest = b43legacy_phy_lo_g_singledeviation(dev, 0);
1338423e3ce3SKalle Valo 	for (i = 0; i < 16; i++) {
1339423e3ce3SKalle Valo 		b43legacy_radio_write16(dev, 0x0052, i);
1340423e3ce3SKalle Valo 		udelay(10);
1341423e3ce3SKalle Valo 		tmp = b43legacy_phy_lo_g_singledeviation(dev, 0);
1342423e3ce3SKalle Valo 		if (tmp < smallest) {
1343423e3ce3SKalle Valo 			smallest = tmp;
1344423e3ce3SKalle Valo 			txctl2 = i;
1345423e3ce3SKalle Valo 		}
1346423e3ce3SKalle Valo 	}
1347423e3ce3SKalle Valo 	phy->txctl2 = txctl2;
1348423e3ce3SKalle Valo }
1349423e3ce3SKalle Valo 
1350423e3ce3SKalle Valo static
b43legacy_phy_lo_g_state(struct b43legacy_wldev * dev,const struct b43legacy_lopair * in_pair,struct b43legacy_lopair * out_pair,u16 r27)1351423e3ce3SKalle Valo void b43legacy_phy_lo_g_state(struct b43legacy_wldev *dev,
1352423e3ce3SKalle Valo 			      const struct b43legacy_lopair *in_pair,
1353423e3ce3SKalle Valo 			      struct b43legacy_lopair *out_pair,
1354423e3ce3SKalle Valo 			      u16 r27)
1355423e3ce3SKalle Valo {
1356423e3ce3SKalle Valo 	static const struct b43legacy_lopair transitions[8] = {
1357423e3ce3SKalle Valo 		{ .high =  1,  .low =  1, },
1358423e3ce3SKalle Valo 		{ .high =  1,  .low =  0, },
1359423e3ce3SKalle Valo 		{ .high =  1,  .low = -1, },
1360423e3ce3SKalle Valo 		{ .high =  0,  .low = -1, },
1361423e3ce3SKalle Valo 		{ .high = -1,  .low = -1, },
1362423e3ce3SKalle Valo 		{ .high = -1,  .low =  0, },
1363423e3ce3SKalle Valo 		{ .high = -1,  .low =  1, },
1364423e3ce3SKalle Valo 		{ .high =  0,  .low =  1, },
1365423e3ce3SKalle Valo 	};
1366423e3ce3SKalle Valo 	struct b43legacy_lopair lowest_transition = {
1367423e3ce3SKalle Valo 		.high = in_pair->high,
1368423e3ce3SKalle Valo 		.low = in_pair->low,
1369423e3ce3SKalle Valo 	};
1370423e3ce3SKalle Valo 	struct b43legacy_lopair tmp_pair;
1371423e3ce3SKalle Valo 	struct b43legacy_lopair transition;
1372423e3ce3SKalle Valo 	int i = 12;
1373423e3ce3SKalle Valo 	int state = 0;
1374423e3ce3SKalle Valo 	int found_lower;
1375423e3ce3SKalle Valo 	int j;
1376423e3ce3SKalle Valo 	int begin;
1377423e3ce3SKalle Valo 	int end;
1378423e3ce3SKalle Valo 	u32 lowest_deviation;
1379423e3ce3SKalle Valo 	u32 tmp;
1380423e3ce3SKalle Valo 
1381423e3ce3SKalle Valo 	/* Note that in_pair and out_pair can point to the same pair.
1382423e3ce3SKalle Valo 	 * Be careful. */
1383423e3ce3SKalle Valo 
1384423e3ce3SKalle Valo 	b43legacy_lo_write(dev, &lowest_transition);
1385423e3ce3SKalle Valo 	lowest_deviation = b43legacy_phy_lo_g_singledeviation(dev, r27);
1386423e3ce3SKalle Valo 	do {
1387423e3ce3SKalle Valo 		found_lower = 0;
1388423e3ce3SKalle Valo 		B43legacy_WARN_ON(!(state >= 0 && state <= 8));
1389423e3ce3SKalle Valo 		if (state == 0) {
1390423e3ce3SKalle Valo 			begin = 1;
1391423e3ce3SKalle Valo 			end = 8;
1392423e3ce3SKalle Valo 		} else if (state % 2 == 0) {
1393423e3ce3SKalle Valo 			begin = state - 1;
1394423e3ce3SKalle Valo 			end = state + 1;
1395423e3ce3SKalle Valo 		} else {
1396423e3ce3SKalle Valo 			begin = state - 2;
1397423e3ce3SKalle Valo 			end = state + 2;
1398423e3ce3SKalle Valo 		}
1399423e3ce3SKalle Valo 		if (begin < 1)
1400423e3ce3SKalle Valo 			begin += 8;
1401423e3ce3SKalle Valo 		if (end > 8)
1402423e3ce3SKalle Valo 			end -= 8;
1403423e3ce3SKalle Valo 
1404423e3ce3SKalle Valo 		j = begin;
1405423e3ce3SKalle Valo 		tmp_pair.high = lowest_transition.high;
1406423e3ce3SKalle Valo 		tmp_pair.low = lowest_transition.low;
1407423e3ce3SKalle Valo 		while (1) {
1408423e3ce3SKalle Valo 			B43legacy_WARN_ON(!(j >= 1 && j <= 8));
1409423e3ce3SKalle Valo 			transition.high = tmp_pair.high +
1410423e3ce3SKalle Valo 					  transitions[j - 1].high;
1411423e3ce3SKalle Valo 			transition.low = tmp_pair.low + transitions[j - 1].low;
1412423e3ce3SKalle Valo 			if ((abs(transition.low) < 9)
1413423e3ce3SKalle Valo 			     && (abs(transition.high) < 9)) {
1414423e3ce3SKalle Valo 				b43legacy_lo_write(dev, &transition);
1415423e3ce3SKalle Valo 				tmp = b43legacy_phy_lo_g_singledeviation(dev,
1416423e3ce3SKalle Valo 								       r27);
1417423e3ce3SKalle Valo 				if (tmp < lowest_deviation) {
1418423e3ce3SKalle Valo 					lowest_deviation = tmp;
1419423e3ce3SKalle Valo 					state = j;
1420423e3ce3SKalle Valo 					found_lower = 1;
1421423e3ce3SKalle Valo 
1422423e3ce3SKalle Valo 					lowest_transition.high =
1423423e3ce3SKalle Valo 								transition.high;
1424423e3ce3SKalle Valo 					lowest_transition.low = transition.low;
1425423e3ce3SKalle Valo 				}
1426423e3ce3SKalle Valo 			}
1427423e3ce3SKalle Valo 			if (j == end)
1428423e3ce3SKalle Valo 				break;
1429423e3ce3SKalle Valo 			if (j == 8)
1430423e3ce3SKalle Valo 				j = 1;
1431423e3ce3SKalle Valo 			else
1432423e3ce3SKalle Valo 				j++;
1433423e3ce3SKalle Valo 		}
1434423e3ce3SKalle Valo 	} while (i-- && found_lower);
1435423e3ce3SKalle Valo 
1436423e3ce3SKalle Valo 	out_pair->high = lowest_transition.high;
1437423e3ce3SKalle Valo 	out_pair->low = lowest_transition.low;
1438423e3ce3SKalle Valo }
1439423e3ce3SKalle Valo 
1440423e3ce3SKalle Valo /* Set the baseband attenuation value on chip. */
b43legacy_phy_set_baseband_attenuation(struct b43legacy_wldev * dev,u16 bbatt)1441423e3ce3SKalle Valo void b43legacy_phy_set_baseband_attenuation(struct b43legacy_wldev *dev,
1442423e3ce3SKalle Valo 					    u16 bbatt)
1443423e3ce3SKalle Valo {
1444423e3ce3SKalle Valo 	struct b43legacy_phy *phy = &dev->phy;
1445423e3ce3SKalle Valo 	u16 value;
1446423e3ce3SKalle Valo 
1447423e3ce3SKalle Valo 	if (phy->analog == 0) {
1448423e3ce3SKalle Valo 		value = (b43legacy_read16(dev, 0x03E6) & 0xFFF0);
1449423e3ce3SKalle Valo 		value |= (bbatt & 0x000F);
1450423e3ce3SKalle Valo 		b43legacy_write16(dev, 0x03E6, value);
1451423e3ce3SKalle Valo 		return;
1452423e3ce3SKalle Valo 	}
1453423e3ce3SKalle Valo 
1454423e3ce3SKalle Valo 	if (phy->analog > 1) {
1455423e3ce3SKalle Valo 		value = b43legacy_phy_read(dev, 0x0060) & 0xFFC3;
1456423e3ce3SKalle Valo 		value |= (bbatt << 2) & 0x003C;
1457423e3ce3SKalle Valo 	} else {
1458423e3ce3SKalle Valo 		value = b43legacy_phy_read(dev, 0x0060) & 0xFF87;
1459423e3ce3SKalle Valo 		value |= (bbatt << 3) & 0x0078;
1460423e3ce3SKalle Valo 	}
1461423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0060, value);
1462423e3ce3SKalle Valo }
1463423e3ce3SKalle Valo 
1464140c6026SAlexander A. Klimov /* https://bcm-specs.sipsolutions.net/LocalOscillator/Measure */
b43legacy_phy_lo_g_measure(struct b43legacy_wldev * dev)1465423e3ce3SKalle Valo void b43legacy_phy_lo_g_measure(struct b43legacy_wldev *dev)
1466423e3ce3SKalle Valo {
1467423e3ce3SKalle Valo 	static const u8 pairorder[10] = { 3, 1, 5, 7, 9, 2, 0, 4, 6, 8 };
1468423e3ce3SKalle Valo 	const int is_initializing = (b43legacy_status(dev)
1469423e3ce3SKalle Valo 				     < B43legacy_STAT_STARTED);
1470423e3ce3SKalle Valo 	struct b43legacy_phy *phy = &dev->phy;
1471423e3ce3SKalle Valo 	u16 h;
1472423e3ce3SKalle Valo 	u16 i;
1473423e3ce3SKalle Valo 	u16 oldi = 0;
1474423e3ce3SKalle Valo 	u16 j;
1475423e3ce3SKalle Valo 	struct b43legacy_lopair control;
1476423e3ce3SKalle Valo 	struct b43legacy_lopair *tmp_control;
1477423e3ce3SKalle Valo 	u16 tmp;
1478423e3ce3SKalle Valo 	u16 regstack[16] = { 0 };
1479423e3ce3SKalle Valo 	u8 oldchannel;
1480423e3ce3SKalle Valo 
1481423e3ce3SKalle Valo 	/* XXX: What are these? */
1482423e3ce3SKalle Valo 	u8 r27 = 0;
1483423e3ce3SKalle Valo 	u16 r31;
1484423e3ce3SKalle Valo 
1485423e3ce3SKalle Valo 	oldchannel = phy->channel;
1486423e3ce3SKalle Valo 	/* Setup */
1487423e3ce3SKalle Valo 	if (phy->gmode) {
1488423e3ce3SKalle Valo 		regstack[0] = b43legacy_phy_read(dev, B43legacy_PHY_G_CRS);
1489423e3ce3SKalle Valo 		regstack[1] = b43legacy_phy_read(dev, 0x0802);
1490423e3ce3SKalle Valo 		b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, regstack[0]
1491423e3ce3SKalle Valo 				    & 0x7FFF);
1492423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0802, regstack[1] & 0xFFFC);
1493423e3ce3SKalle Valo 	}
1494423e3ce3SKalle Valo 	regstack[3] = b43legacy_read16(dev, 0x03E2);
1495423e3ce3SKalle Valo 	b43legacy_write16(dev, 0x03E2, regstack[3] | 0x8000);
1496423e3ce3SKalle Valo 	regstack[4] = b43legacy_read16(dev, B43legacy_MMIO_CHANNEL_EXT);
1497423e3ce3SKalle Valo 	regstack[5] = b43legacy_phy_read(dev, 0x15);
1498423e3ce3SKalle Valo 	regstack[6] = b43legacy_phy_read(dev, 0x2A);
1499423e3ce3SKalle Valo 	regstack[7] = b43legacy_phy_read(dev, 0x35);
1500423e3ce3SKalle Valo 	regstack[8] = b43legacy_phy_read(dev, 0x60);
1501423e3ce3SKalle Valo 	regstack[9] = b43legacy_radio_read16(dev, 0x43);
1502423e3ce3SKalle Valo 	regstack[10] = b43legacy_radio_read16(dev, 0x7A);
1503423e3ce3SKalle Valo 	regstack[11] = b43legacy_radio_read16(dev, 0x52);
1504423e3ce3SKalle Valo 	if (phy->gmode) {
1505423e3ce3SKalle Valo 		regstack[12] = b43legacy_phy_read(dev, 0x0811);
1506423e3ce3SKalle Valo 		regstack[13] = b43legacy_phy_read(dev, 0x0812);
1507423e3ce3SKalle Valo 		regstack[14] = b43legacy_phy_read(dev, 0x0814);
1508423e3ce3SKalle Valo 		regstack[15] = b43legacy_phy_read(dev, 0x0815);
1509423e3ce3SKalle Valo 	}
1510423e3ce3SKalle Valo 	b43legacy_radio_selectchannel(dev, 6, 0);
1511423e3ce3SKalle Valo 	if (phy->gmode) {
1512423e3ce3SKalle Valo 		b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, regstack[0]
1513423e3ce3SKalle Valo 				    & 0x7FFF);
1514423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0802, regstack[1] & 0xFFFC);
1515423e3ce3SKalle Valo 		b43legacy_dummy_transmission(dev);
1516423e3ce3SKalle Valo 	}
1517423e3ce3SKalle Valo 	b43legacy_radio_write16(dev, 0x0043, 0x0006);
1518423e3ce3SKalle Valo 
1519423e3ce3SKalle Valo 	b43legacy_phy_set_baseband_attenuation(dev, 2);
1520423e3ce3SKalle Valo 
1521423e3ce3SKalle Valo 	b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, 0x0000);
1522423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x002E, 0x007F);
1523423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x080F, 0x0078);
1524423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0035, regstack[7] & ~(1 << 7));
1525423e3ce3SKalle Valo 	b43legacy_radio_write16(dev, 0x007A, regstack[10] & 0xFFF0);
1526423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x002B, 0x0203);
1527423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x002A, 0x08A3);
1528423e3ce3SKalle Valo 	if (phy->gmode) {
1529423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0814, regstack[14] | 0x0003);
1530423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0815, regstack[15] & 0xFFFC);
1531423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0811, 0x01B3);
1532423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0812, 0x00B2);
1533423e3ce3SKalle Valo 	}
1534423e3ce3SKalle Valo 	if (is_initializing)
1535423e3ce3SKalle Valo 		b43legacy_phy_lo_g_measure_txctl2(dev);
1536423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x080F, 0x8078);
1537423e3ce3SKalle Valo 
1538423e3ce3SKalle Valo 	/* Measure */
1539423e3ce3SKalle Valo 	control.low = 0;
1540423e3ce3SKalle Valo 	control.high = 0;
1541423e3ce3SKalle Valo 	for (h = 0; h < 10; h++) {
1542423e3ce3SKalle Valo 		/* Loop over each possible RadioAttenuation (0-9) */
1543423e3ce3SKalle Valo 		i = pairorder[h];
1544423e3ce3SKalle Valo 		if (is_initializing) {
1545423e3ce3SKalle Valo 			if (i == 3) {
1546423e3ce3SKalle Valo 				control.low = 0;
1547423e3ce3SKalle Valo 				control.high = 0;
1548423e3ce3SKalle Valo 			} else if (((i % 2 == 1) && (oldi % 2 == 1)) ||
1549423e3ce3SKalle Valo 				  ((i % 2 == 0) && (oldi % 2 == 0))) {
1550423e3ce3SKalle Valo 				tmp_control = b43legacy_get_lopair(phy, oldi,
1551423e3ce3SKalle Valo 								   0);
1552423e3ce3SKalle Valo 				memcpy(&control, tmp_control, sizeof(control));
1553423e3ce3SKalle Valo 			} else {
1554423e3ce3SKalle Valo 				tmp_control = b43legacy_get_lopair(phy, 3, 0);
1555423e3ce3SKalle Valo 				memcpy(&control, tmp_control, sizeof(control));
1556423e3ce3SKalle Valo 			}
1557423e3ce3SKalle Valo 		}
1558423e3ce3SKalle Valo 		/* Loop over each possible BasebandAttenuation/2 */
1559423e3ce3SKalle Valo 		for (j = 0; j < 4; j++) {
1560423e3ce3SKalle Valo 			if (is_initializing) {
1561423e3ce3SKalle Valo 				tmp = i * 2 + j;
1562423e3ce3SKalle Valo 				r27 = 0;
1563423e3ce3SKalle Valo 				r31 = 0;
1564423e3ce3SKalle Valo 				if (tmp > 14) {
1565423e3ce3SKalle Valo 					r31 = 1;
1566423e3ce3SKalle Valo 					if (tmp > 17)
1567423e3ce3SKalle Valo 						r27 = 1;
1568423e3ce3SKalle Valo 					if (tmp > 19)
1569423e3ce3SKalle Valo 						r27 = 2;
1570423e3ce3SKalle Valo 				}
1571423e3ce3SKalle Valo 			} else {
1572423e3ce3SKalle Valo 				tmp_control = b43legacy_get_lopair(phy, i,
1573423e3ce3SKalle Valo 								   j * 2);
1574423e3ce3SKalle Valo 				if (!tmp_control->used)
1575423e3ce3SKalle Valo 					continue;
1576423e3ce3SKalle Valo 				memcpy(&control, tmp_control, sizeof(control));
1577423e3ce3SKalle Valo 				r27 = 3;
1578423e3ce3SKalle Valo 				r31 = 0;
1579423e3ce3SKalle Valo 			}
1580423e3ce3SKalle Valo 			b43legacy_radio_write16(dev, 0x43, i);
1581423e3ce3SKalle Valo 			b43legacy_radio_write16(dev, 0x52, phy->txctl2);
1582423e3ce3SKalle Valo 			udelay(10);
15836004cf29SThomas Gleixner 			cond_resched();
1584423e3ce3SKalle Valo 
1585423e3ce3SKalle Valo 			b43legacy_phy_set_baseband_attenuation(dev, j * 2);
1586423e3ce3SKalle Valo 
1587423e3ce3SKalle Valo 			tmp = (regstack[10] & 0xFFF0);
1588423e3ce3SKalle Valo 			if (r31)
1589423e3ce3SKalle Valo 				tmp |= 0x0008;
1590423e3ce3SKalle Valo 			b43legacy_radio_write16(dev, 0x007A, tmp);
1591423e3ce3SKalle Valo 
1592423e3ce3SKalle Valo 			tmp_control = b43legacy_get_lopair(phy, i, j * 2);
1593423e3ce3SKalle Valo 			b43legacy_phy_lo_g_state(dev, &control, tmp_control,
1594423e3ce3SKalle Valo 						 r27);
1595423e3ce3SKalle Valo 		}
1596423e3ce3SKalle Valo 		oldi = i;
1597423e3ce3SKalle Valo 	}
1598423e3ce3SKalle Valo 	/* Loop over each possible RadioAttenuation (10-13) */
1599423e3ce3SKalle Valo 	for (i = 10; i < 14; i++) {
1600423e3ce3SKalle Valo 		/* Loop over each possible BasebandAttenuation/2 */
1601423e3ce3SKalle Valo 		for (j = 0; j < 4; j++) {
1602423e3ce3SKalle Valo 			if (is_initializing) {
1603423e3ce3SKalle Valo 				tmp_control = b43legacy_get_lopair(phy, i - 9,
1604423e3ce3SKalle Valo 								 j * 2);
1605423e3ce3SKalle Valo 				memcpy(&control, tmp_control, sizeof(control));
1606423e3ce3SKalle Valo 				/* FIXME: The next line is wrong, as the
1607423e3ce3SKalle Valo 				 * following if statement can never trigger. */
1608423e3ce3SKalle Valo 				tmp = (i - 9) * 2 + j - 5;
1609423e3ce3SKalle Valo 				r27 = 0;
1610423e3ce3SKalle Valo 				r31 = 0;
1611423e3ce3SKalle Valo 				if (tmp > 14) {
1612423e3ce3SKalle Valo 					r31 = 1;
1613423e3ce3SKalle Valo 					if (tmp > 17)
1614423e3ce3SKalle Valo 						r27 = 1;
1615423e3ce3SKalle Valo 					if (tmp > 19)
1616423e3ce3SKalle Valo 						r27 = 2;
1617423e3ce3SKalle Valo 				}
1618423e3ce3SKalle Valo 			} else {
1619423e3ce3SKalle Valo 				tmp_control = b43legacy_get_lopair(phy, i - 9,
1620423e3ce3SKalle Valo 								   j * 2);
1621423e3ce3SKalle Valo 				if (!tmp_control->used)
1622423e3ce3SKalle Valo 					continue;
1623423e3ce3SKalle Valo 				memcpy(&control, tmp_control, sizeof(control));
1624423e3ce3SKalle Valo 				r27 = 3;
1625423e3ce3SKalle Valo 				r31 = 0;
1626423e3ce3SKalle Valo 			}
1627423e3ce3SKalle Valo 			b43legacy_radio_write16(dev, 0x43, i - 9);
1628423e3ce3SKalle Valo 			/* FIXME: shouldn't txctl1 be zero in the next line
1629423e3ce3SKalle Valo 			 * and 3 in the loop above? */
1630423e3ce3SKalle Valo 			b43legacy_radio_write16(dev, 0x52,
1631423e3ce3SKalle Valo 					      phy->txctl2
1632423e3ce3SKalle Valo 					      | (3/*txctl1*/ << 4));
1633423e3ce3SKalle Valo 			udelay(10);
16346004cf29SThomas Gleixner 			cond_resched();
1635423e3ce3SKalle Valo 
1636423e3ce3SKalle Valo 			b43legacy_phy_set_baseband_attenuation(dev, j * 2);
1637423e3ce3SKalle Valo 
1638423e3ce3SKalle Valo 			tmp = (regstack[10] & 0xFFF0);
1639423e3ce3SKalle Valo 			if (r31)
1640423e3ce3SKalle Valo 				tmp |= 0x0008;
1641423e3ce3SKalle Valo 			b43legacy_radio_write16(dev, 0x7A, tmp);
1642423e3ce3SKalle Valo 
1643423e3ce3SKalle Valo 			tmp_control = b43legacy_get_lopair(phy, i, j * 2);
1644423e3ce3SKalle Valo 			b43legacy_phy_lo_g_state(dev, &control, tmp_control,
1645423e3ce3SKalle Valo 						 r27);
1646423e3ce3SKalle Valo 		}
1647423e3ce3SKalle Valo 	}
1648423e3ce3SKalle Valo 
1649423e3ce3SKalle Valo 	/* Restoration */
1650423e3ce3SKalle Valo 	if (phy->gmode) {
1651423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0015, 0xE300);
1652423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0812, (r27 << 8) | 0xA0);
1653423e3ce3SKalle Valo 		udelay(5);
1654423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0812, (r27 << 8) | 0xA2);
1655423e3ce3SKalle Valo 		udelay(2);
1656423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0812, (r27 << 8) | 0xA3);
16576004cf29SThomas Gleixner 		cond_resched();
1658423e3ce3SKalle Valo 	} else
1659423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0015, r27 | 0xEFA0);
1660423e3ce3SKalle Valo 	b43legacy_phy_lo_adjust(dev, is_initializing);
1661423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x002E, 0x807F);
1662423e3ce3SKalle Valo 	if (phy->gmode)
1663423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x002F, 0x0202);
1664423e3ce3SKalle Valo 	else
1665423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x002F, 0x0101);
1666423e3ce3SKalle Valo 	b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, regstack[4]);
1667423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0015, regstack[5]);
1668423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x002A, regstack[6]);
1669423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0035, regstack[7]);
1670423e3ce3SKalle Valo 	b43legacy_phy_write(dev, 0x0060, regstack[8]);
1671423e3ce3SKalle Valo 	b43legacy_radio_write16(dev, 0x0043, regstack[9]);
1672423e3ce3SKalle Valo 	b43legacy_radio_write16(dev, 0x007A, regstack[10]);
1673423e3ce3SKalle Valo 	regstack[11] &= 0x00F0;
1674423e3ce3SKalle Valo 	regstack[11] |= (b43legacy_radio_read16(dev, 0x52) & 0x000F);
1675423e3ce3SKalle Valo 	b43legacy_radio_write16(dev, 0x52, regstack[11]);
1676423e3ce3SKalle Valo 	b43legacy_write16(dev, 0x03E2, regstack[3]);
1677423e3ce3SKalle Valo 	if (phy->gmode) {
1678423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0811, regstack[12]);
1679423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0812, regstack[13]);
1680423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0814, regstack[14]);
1681423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0815, regstack[15]);
1682423e3ce3SKalle Valo 		b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, regstack[0]);
1683423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x0802, regstack[1]);
1684423e3ce3SKalle Valo 	}
1685423e3ce3SKalle Valo 	b43legacy_radio_selectchannel(dev, oldchannel, 1);
1686423e3ce3SKalle Valo 
1687423e3ce3SKalle Valo #ifdef CONFIG_B43LEGACY_DEBUG
1688423e3ce3SKalle Valo 	{
1689423e3ce3SKalle Valo 		/* Sanity check for all lopairs. */
1690423e3ce3SKalle Valo 		for (i = 0; i < B43legacy_LO_COUNT; i++) {
1691423e3ce3SKalle Valo 			tmp_control = phy->_lo_pairs + i;
1692423e3ce3SKalle Valo 			if (tmp_control->low < -8 || tmp_control->low > 8 ||
1693423e3ce3SKalle Valo 			    tmp_control->high < -8 || tmp_control->high > 8)
1694423e3ce3SKalle Valo 				b43legacywarn(dev->wl,
1695423e3ce3SKalle Valo 				       "WARNING: Invalid LOpair (low: %d, high:"
1696423e3ce3SKalle Valo 				       " %d, index: %d)\n",
1697423e3ce3SKalle Valo 				       tmp_control->low, tmp_control->high, i);
1698423e3ce3SKalle Valo 		}
1699423e3ce3SKalle Valo 	}
1700423e3ce3SKalle Valo #endif /* CONFIG_B43LEGACY_DEBUG */
1701423e3ce3SKalle Valo }
1702423e3ce3SKalle Valo 
1703423e3ce3SKalle Valo static
b43legacy_phy_lo_mark_current_used(struct b43legacy_wldev * dev)1704423e3ce3SKalle Valo void b43legacy_phy_lo_mark_current_used(struct b43legacy_wldev *dev)
1705423e3ce3SKalle Valo {
1706423e3ce3SKalle Valo 	struct b43legacy_lopair *pair;
1707423e3ce3SKalle Valo 
1708423e3ce3SKalle Valo 	pair = b43legacy_current_lopair(dev);
1709423e3ce3SKalle Valo 	pair->used = 1;
1710423e3ce3SKalle Valo }
1711423e3ce3SKalle Valo 
b43legacy_phy_lo_mark_all_unused(struct b43legacy_wldev * dev)1712423e3ce3SKalle Valo void b43legacy_phy_lo_mark_all_unused(struct b43legacy_wldev *dev)
1713423e3ce3SKalle Valo {
1714423e3ce3SKalle Valo 	struct b43legacy_phy *phy = &dev->phy;
1715423e3ce3SKalle Valo 	struct b43legacy_lopair *pair;
1716423e3ce3SKalle Valo 	int i;
1717423e3ce3SKalle Valo 
1718423e3ce3SKalle Valo 	for (i = 0; i < B43legacy_LO_COUNT; i++) {
1719423e3ce3SKalle Valo 		pair = phy->_lo_pairs + i;
1720423e3ce3SKalle Valo 		pair->used = 0;
1721423e3ce3SKalle Valo 	}
1722423e3ce3SKalle Valo }
1723423e3ce3SKalle Valo 
1724140c6026SAlexander A. Klimov /* https://bcm-specs.sipsolutions.net/EstimatePowerOut
1725423e3ce3SKalle Valo  * This function converts a TSSI value to dBm in Q5.2
1726423e3ce3SKalle Valo  */
b43legacy_phy_estimate_power_out(struct b43legacy_wldev * dev,s8 tssi)1727423e3ce3SKalle Valo static s8 b43legacy_phy_estimate_power_out(struct b43legacy_wldev *dev, s8 tssi)
1728423e3ce3SKalle Valo {
1729423e3ce3SKalle Valo 	struct b43legacy_phy *phy = &dev->phy;
1730423e3ce3SKalle Valo 	s8 dbm = 0;
1731423e3ce3SKalle Valo 	s32 tmp;
1732423e3ce3SKalle Valo 
1733423e3ce3SKalle Valo 	tmp = phy->idle_tssi;
1734423e3ce3SKalle Valo 	tmp += tssi;
1735423e3ce3SKalle Valo 	tmp -= phy->savedpctlreg;
1736423e3ce3SKalle Valo 
1737423e3ce3SKalle Valo 	switch (phy->type) {
1738423e3ce3SKalle Valo 	case B43legacy_PHYTYPE_B:
1739423e3ce3SKalle Valo 	case B43legacy_PHYTYPE_G:
1740423e3ce3SKalle Valo 		tmp = clamp_val(tmp, 0x00, 0x3F);
1741423e3ce3SKalle Valo 		dbm = phy->tssi2dbm[tmp];
1742423e3ce3SKalle Valo 		break;
1743423e3ce3SKalle Valo 	default:
1744423e3ce3SKalle Valo 		B43legacy_BUG_ON(1);
1745423e3ce3SKalle Valo 	}
1746423e3ce3SKalle Valo 
1747423e3ce3SKalle Valo 	return dbm;
1748423e3ce3SKalle Valo }
1749423e3ce3SKalle Valo 
1750140c6026SAlexander A. Klimov /* https://bcm-specs.sipsolutions.net/RecalculateTransmissionPower */
b43legacy_phy_xmitpower(struct b43legacy_wldev * dev)1751423e3ce3SKalle Valo void b43legacy_phy_xmitpower(struct b43legacy_wldev *dev)
1752423e3ce3SKalle Valo {
1753423e3ce3SKalle Valo 	struct b43legacy_phy *phy = &dev->phy;
1754423e3ce3SKalle Valo 	u16 tmp;
1755423e3ce3SKalle Valo 	u16 txpower;
1756423e3ce3SKalle Valo 	s8 v0;
1757423e3ce3SKalle Valo 	s8 v1;
1758423e3ce3SKalle Valo 	s8 v2;
1759423e3ce3SKalle Valo 	s8 v3;
1760423e3ce3SKalle Valo 	s8 average;
1761423e3ce3SKalle Valo 	int max_pwr;
1762423e3ce3SKalle Valo 	s16 desired_pwr;
1763423e3ce3SKalle Valo 	s16 estimated_pwr;
1764423e3ce3SKalle Valo 	s16 pwr_adjust;
1765423e3ce3SKalle Valo 	s16 radio_att_delta;
1766423e3ce3SKalle Valo 	s16 baseband_att_delta;
1767423e3ce3SKalle Valo 	s16 radio_attenuation;
1768423e3ce3SKalle Valo 	s16 baseband_attenuation;
1769423e3ce3SKalle Valo 
1770423e3ce3SKalle Valo 	if (phy->savedpctlreg == 0xFFFF)
1771423e3ce3SKalle Valo 		return;
1772423e3ce3SKalle Valo 	if ((dev->dev->bus->boardinfo.type == 0x0416) &&
1773423e3ce3SKalle Valo 	    is_bcm_board_vendor(dev))
1774423e3ce3SKalle Valo 		return;
1775423e3ce3SKalle Valo #ifdef CONFIG_B43LEGACY_DEBUG
1776423e3ce3SKalle Valo 	if (phy->manual_txpower_control)
1777423e3ce3SKalle Valo 		return;
1778423e3ce3SKalle Valo #endif
1779423e3ce3SKalle Valo 
1780423e3ce3SKalle Valo 	B43legacy_BUG_ON(!(phy->type == B43legacy_PHYTYPE_B ||
1781423e3ce3SKalle Valo 			 phy->type == B43legacy_PHYTYPE_G));
1782423e3ce3SKalle Valo 	tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x0058);
1783423e3ce3SKalle Valo 	v0 = (s8)(tmp & 0x00FF);
1784423e3ce3SKalle Valo 	v1 = (s8)((tmp & 0xFF00) >> 8);
1785423e3ce3SKalle Valo 	tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x005A);
1786423e3ce3SKalle Valo 	v2 = (s8)(tmp & 0x00FF);
1787423e3ce3SKalle Valo 	v3 = (s8)((tmp & 0xFF00) >> 8);
1788423e3ce3SKalle Valo 	tmp = 0;
1789423e3ce3SKalle Valo 
1790423e3ce3SKalle Valo 	if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F || v3 == 0x7F) {
1791423e3ce3SKalle Valo 		tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
1792423e3ce3SKalle Valo 					 0x0070);
1793423e3ce3SKalle Valo 		v0 = (s8)(tmp & 0x00FF);
1794423e3ce3SKalle Valo 		v1 = (s8)((tmp & 0xFF00) >> 8);
1795423e3ce3SKalle Valo 		tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
1796423e3ce3SKalle Valo 					 0x0072);
1797423e3ce3SKalle Valo 		v2 = (s8)(tmp & 0x00FF);
1798423e3ce3SKalle Valo 		v3 = (s8)((tmp & 0xFF00) >> 8);
1799423e3ce3SKalle Valo 		if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F || v3 == 0x7F)
1800423e3ce3SKalle Valo 			return;
1801423e3ce3SKalle Valo 		v0 = (v0 + 0x20) & 0x3F;
1802423e3ce3SKalle Valo 		v1 = (v1 + 0x20) & 0x3F;
1803423e3ce3SKalle Valo 		v2 = (v2 + 0x20) & 0x3F;
1804423e3ce3SKalle Valo 		v3 = (v3 + 0x20) & 0x3F;
1805423e3ce3SKalle Valo 		tmp = 1;
1806423e3ce3SKalle Valo 	}
1807423e3ce3SKalle Valo 	b43legacy_radio_clear_tssi(dev);
1808423e3ce3SKalle Valo 
1809423e3ce3SKalle Valo 	average = (v0 + v1 + v2 + v3 + 2) / 4;
1810423e3ce3SKalle Valo 
1811423e3ce3SKalle Valo 	if (tmp && (b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x005E)
1812423e3ce3SKalle Valo 	    & 0x8))
1813423e3ce3SKalle Valo 		average -= 13;
1814423e3ce3SKalle Valo 
1815423e3ce3SKalle Valo 	estimated_pwr = b43legacy_phy_estimate_power_out(dev, average);
1816423e3ce3SKalle Valo 
1817423e3ce3SKalle Valo 	max_pwr = dev->dev->bus->sprom.maxpwr_bg;
1818423e3ce3SKalle Valo 
1819423e3ce3SKalle Valo 	if ((dev->dev->bus->sprom.boardflags_lo
1820423e3ce3SKalle Valo 	     & B43legacy_BFL_PACTRL) &&
1821423e3ce3SKalle Valo 	    (phy->type == B43legacy_PHYTYPE_G))
1822423e3ce3SKalle Valo 		max_pwr -= 0x3;
1823423e3ce3SKalle Valo 	if (unlikely(max_pwr <= 0)) {
1824423e3ce3SKalle Valo 		b43legacywarn(dev->wl, "Invalid max-TX-power value in SPROM."
1825423e3ce3SKalle Valo 			"\n");
1826423e3ce3SKalle Valo 		max_pwr = 74; /* fake it */
1827423e3ce3SKalle Valo 		dev->dev->bus->sprom.maxpwr_bg = max_pwr;
1828423e3ce3SKalle Valo 	}
1829423e3ce3SKalle Valo 
1830423e3ce3SKalle Valo 	/* Use regulatory information to get the maximum power.
1831423e3ce3SKalle Valo 	 * In the absence of such data from mac80211, we will use 20 dBm, which
1832423e3ce3SKalle Valo 	 * is the value for the EU, US, Canada, and most of the world.
1833423e3ce3SKalle Valo 	 * The regulatory maximum is reduced by the antenna gain (from sprom)
1834423e3ce3SKalle Valo 	 * and 1.5 dBm (a safety factor??). The result is in Q5.2 format
1835423e3ce3SKalle Valo 	 * which accounts for the factor of 4 */
1836423e3ce3SKalle Valo #define REG_MAX_PWR 20
1837423e3ce3SKalle Valo 	max_pwr = min(REG_MAX_PWR * 4
1838423e3ce3SKalle Valo 		      - dev->dev->bus->sprom.antenna_gain.a0
1839423e3ce3SKalle Valo 		      - 0x6, max_pwr);
1840423e3ce3SKalle Valo 
1841423e3ce3SKalle Valo 	/* find the desired power in Q5.2 - power_level is in dBm
1842423e3ce3SKalle Valo 	 * and limit it - max_pwr is already in Q5.2 */
1843423e3ce3SKalle Valo 	desired_pwr = clamp_val(phy->power_level << 2, 0, max_pwr);
1844423e3ce3SKalle Valo 	if (b43legacy_debug(dev, B43legacy_DBG_XMITPOWER))
1845423e3ce3SKalle Valo 		b43legacydbg(dev->wl, "Current TX power output: " Q52_FMT
1846423e3ce3SKalle Valo 		       " dBm, Desired TX power output: " Q52_FMT
1847423e3ce3SKalle Valo 		       " dBm\n", Q52_ARG(estimated_pwr),
1848423e3ce3SKalle Valo 		       Q52_ARG(desired_pwr));
1849423e3ce3SKalle Valo 	/* Check if we need to adjust the current power. The factor of 2 is
1850423e3ce3SKalle Valo 	 * for damping */
1851423e3ce3SKalle Valo 	pwr_adjust = (desired_pwr - estimated_pwr) / 2;
1852423e3ce3SKalle Valo 	/* RF attenuation delta
1853423e3ce3SKalle Valo 	 * The minus sign is because lower attenuation => more power */
1854423e3ce3SKalle Valo 	radio_att_delta = -(pwr_adjust + 7) >> 3;
1855423e3ce3SKalle Valo 	/* Baseband attenuation delta */
1856423e3ce3SKalle Valo 	baseband_att_delta = -(pwr_adjust >> 1) - (4 * radio_att_delta);
1857423e3ce3SKalle Valo 	/* Do we need to adjust anything? */
1858423e3ce3SKalle Valo 	if ((radio_att_delta == 0) && (baseband_att_delta == 0)) {
1859423e3ce3SKalle Valo 		b43legacy_phy_lo_mark_current_used(dev);
1860423e3ce3SKalle Valo 		return;
1861423e3ce3SKalle Valo 	}
1862423e3ce3SKalle Valo 
1863423e3ce3SKalle Valo 	/* Calculate the new attenuation values. */
1864423e3ce3SKalle Valo 	baseband_attenuation = phy->bbatt;
1865423e3ce3SKalle Valo 	baseband_attenuation += baseband_att_delta;
1866423e3ce3SKalle Valo 	radio_attenuation = phy->rfatt;
1867423e3ce3SKalle Valo 	radio_attenuation += radio_att_delta;
1868423e3ce3SKalle Valo 
1869423e3ce3SKalle Valo 	/* Get baseband and radio attenuation values into permitted ranges.
1870423e3ce3SKalle Valo 	 * baseband 0-11, radio 0-9.
1871423e3ce3SKalle Valo 	 * Radio attenuation affects power level 4 times as much as baseband.
1872423e3ce3SKalle Valo 	 */
1873423e3ce3SKalle Valo 	if (radio_attenuation < 0) {
1874423e3ce3SKalle Valo 		baseband_attenuation -= (4 * -radio_attenuation);
1875423e3ce3SKalle Valo 		radio_attenuation = 0;
1876423e3ce3SKalle Valo 	} else if (radio_attenuation > 9) {
1877423e3ce3SKalle Valo 		baseband_attenuation += (4 * (radio_attenuation - 9));
1878423e3ce3SKalle Valo 		radio_attenuation = 9;
1879423e3ce3SKalle Valo 	} else {
1880423e3ce3SKalle Valo 		while (baseband_attenuation < 0 && radio_attenuation > 0) {
1881423e3ce3SKalle Valo 			baseband_attenuation += 4;
1882423e3ce3SKalle Valo 			radio_attenuation--;
1883423e3ce3SKalle Valo 		}
1884423e3ce3SKalle Valo 		while (baseband_attenuation > 11 && radio_attenuation < 9) {
1885423e3ce3SKalle Valo 			baseband_attenuation -= 4;
1886423e3ce3SKalle Valo 			radio_attenuation++;
1887423e3ce3SKalle Valo 		}
1888423e3ce3SKalle Valo 	}
1889423e3ce3SKalle Valo 	baseband_attenuation = clamp_val(baseband_attenuation, 0, 11);
1890423e3ce3SKalle Valo 
1891423e3ce3SKalle Valo 	txpower = phy->txctl1;
1892423e3ce3SKalle Valo 	if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 2)) {
1893423e3ce3SKalle Valo 		if (radio_attenuation <= 1) {
1894423e3ce3SKalle Valo 			if (txpower == 0) {
1895423e3ce3SKalle Valo 				txpower = 3;
1896423e3ce3SKalle Valo 				radio_attenuation += 2;
1897423e3ce3SKalle Valo 				baseband_attenuation += 2;
1898423e3ce3SKalle Valo 			} else if (dev->dev->bus->sprom.boardflags_lo
1899423e3ce3SKalle Valo 				   & B43legacy_BFL_PACTRL) {
1900423e3ce3SKalle Valo 				baseband_attenuation += 4 *
1901423e3ce3SKalle Valo 						     (radio_attenuation - 2);
1902423e3ce3SKalle Valo 				radio_attenuation = 2;
1903423e3ce3SKalle Valo 			}
1904423e3ce3SKalle Valo 		} else if (radio_attenuation > 4 && txpower != 0) {
1905423e3ce3SKalle Valo 			txpower = 0;
1906423e3ce3SKalle Valo 			if (baseband_attenuation < 3) {
1907423e3ce3SKalle Valo 				radio_attenuation -= 3;
1908423e3ce3SKalle Valo 				baseband_attenuation += 2;
1909423e3ce3SKalle Valo 			} else {
1910423e3ce3SKalle Valo 				radio_attenuation -= 2;
1911423e3ce3SKalle Valo 				baseband_attenuation -= 2;
1912423e3ce3SKalle Valo 			}
1913423e3ce3SKalle Valo 		}
1914423e3ce3SKalle Valo 	}
1915423e3ce3SKalle Valo 	/* Save the control values */
1916423e3ce3SKalle Valo 	phy->txctl1 = txpower;
1917423e3ce3SKalle Valo 	baseband_attenuation = clamp_val(baseband_attenuation, 0, 11);
1918423e3ce3SKalle Valo 	radio_attenuation = clamp_val(radio_attenuation, 0, 9);
1919423e3ce3SKalle Valo 	phy->rfatt = radio_attenuation;
1920423e3ce3SKalle Valo 	phy->bbatt = baseband_attenuation;
1921423e3ce3SKalle Valo 
1922423e3ce3SKalle Valo 	/* Adjust the hardware */
1923423e3ce3SKalle Valo 	b43legacy_phy_lock(dev);
1924423e3ce3SKalle Valo 	b43legacy_radio_lock(dev);
1925423e3ce3SKalle Valo 	b43legacy_radio_set_txpower_bg(dev, baseband_attenuation,
1926423e3ce3SKalle Valo 				       radio_attenuation, txpower);
1927423e3ce3SKalle Valo 	b43legacy_phy_lo_mark_current_used(dev);
1928423e3ce3SKalle Valo 	b43legacy_radio_unlock(dev);
1929423e3ce3SKalle Valo 	b43legacy_phy_unlock(dev);
1930423e3ce3SKalle Valo }
1931423e3ce3SKalle Valo 
1932423e3ce3SKalle Valo static inline
b43legacy_tssi2dbm_ad(s32 num,s32 den)1933423e3ce3SKalle Valo s32 b43legacy_tssi2dbm_ad(s32 num, s32 den)
1934423e3ce3SKalle Valo {
1935423e3ce3SKalle Valo 	if (num < 0)
1936423e3ce3SKalle Valo 		return num/den;
1937423e3ce3SKalle Valo 	else
1938423e3ce3SKalle Valo 		return (num+den/2)/den;
1939423e3ce3SKalle Valo }
1940423e3ce3SKalle Valo 
1941423e3ce3SKalle Valo static inline
b43legacy_tssi2dbm_entry(s8 entry[],u8 index,s16 pab0,s16 pab1,s16 pab2)1942423e3ce3SKalle Valo s8 b43legacy_tssi2dbm_entry(s8 entry [], u8 index, s16 pab0, s16 pab1, s16 pab2)
1943423e3ce3SKalle Valo {
1944423e3ce3SKalle Valo 	s32 m1;
1945423e3ce3SKalle Valo 	s32 m2;
1946423e3ce3SKalle Valo 	s32 f = 256;
1947423e3ce3SKalle Valo 	s32 q;
1948423e3ce3SKalle Valo 	s32 delta;
1949423e3ce3SKalle Valo 	s8 i = 0;
1950423e3ce3SKalle Valo 
1951423e3ce3SKalle Valo 	m1 = b43legacy_tssi2dbm_ad(16 * pab0 + index * pab1, 32);
1952423e3ce3SKalle Valo 	m2 = max(b43legacy_tssi2dbm_ad(32768 + index * pab2, 256), 1);
1953423e3ce3SKalle Valo 	do {
1954423e3ce3SKalle Valo 		if (i > 15)
1955423e3ce3SKalle Valo 			return -EINVAL;
1956423e3ce3SKalle Valo 		q = b43legacy_tssi2dbm_ad(f * 4096 -
1957423e3ce3SKalle Valo 					  b43legacy_tssi2dbm_ad(m2 * f, 16) *
1958423e3ce3SKalle Valo 					  f, 2048);
1959423e3ce3SKalle Valo 		delta = abs(q - f);
1960423e3ce3SKalle Valo 		f = q;
1961423e3ce3SKalle Valo 		i++;
1962423e3ce3SKalle Valo 	} while (delta >= 2);
1963423e3ce3SKalle Valo 	entry[index] = clamp_val(b43legacy_tssi2dbm_ad(m1 * f, 8192),
1964423e3ce3SKalle Valo 				   -127, 128);
1965423e3ce3SKalle Valo 	return 0;
1966423e3ce3SKalle Valo }
1967423e3ce3SKalle Valo 
1968423e3ce3SKalle Valo /* http://bcm-specs.sipsolutions.net/TSSI_to_DBM_Table */
b43legacy_phy_init_tssi2dbm_table(struct b43legacy_wldev * dev)1969423e3ce3SKalle Valo int b43legacy_phy_init_tssi2dbm_table(struct b43legacy_wldev *dev)
1970423e3ce3SKalle Valo {
1971423e3ce3SKalle Valo 	struct b43legacy_phy *phy = &dev->phy;
1972423e3ce3SKalle Valo 	s16 pab0;
1973423e3ce3SKalle Valo 	s16 pab1;
1974423e3ce3SKalle Valo 	s16 pab2;
1975423e3ce3SKalle Valo 	u8 idx;
1976423e3ce3SKalle Valo 	s8 *dyn_tssi2dbm;
1977423e3ce3SKalle Valo 
1978423e3ce3SKalle Valo 	B43legacy_WARN_ON(!(phy->type == B43legacy_PHYTYPE_B ||
1979423e3ce3SKalle Valo 			  phy->type == B43legacy_PHYTYPE_G));
1980423e3ce3SKalle Valo 	pab0 = (s16)(dev->dev->bus->sprom.pa0b0);
1981423e3ce3SKalle Valo 	pab1 = (s16)(dev->dev->bus->sprom.pa0b1);
1982423e3ce3SKalle Valo 	pab2 = (s16)(dev->dev->bus->sprom.pa0b2);
1983423e3ce3SKalle Valo 
1984423e3ce3SKalle Valo 	if ((dev->dev->bus->chip_id == 0x4301) && (phy->radio_ver != 0x2050)) {
1985423e3ce3SKalle Valo 		phy->idle_tssi = 0x34;
1986423e3ce3SKalle Valo 		phy->tssi2dbm = b43legacy_tssi2dbm_b_table;
1987423e3ce3SKalle Valo 		return 0;
1988423e3ce3SKalle Valo 	}
1989423e3ce3SKalle Valo 
1990423e3ce3SKalle Valo 	if (pab0 != 0 && pab1 != 0 && pab2 != 0 &&
1991423e3ce3SKalle Valo 	    pab0 != -1 && pab1 != -1 && pab2 != -1) {
1992423e3ce3SKalle Valo 		/* The pabX values are set in SPROM. Use them. */
1993423e3ce3SKalle Valo 		if ((s8)dev->dev->bus->sprom.itssi_bg != 0 &&
1994423e3ce3SKalle Valo 		    (s8)dev->dev->bus->sprom.itssi_bg != -1)
1995423e3ce3SKalle Valo 			phy->idle_tssi = (s8)(dev->dev->bus->sprom.
1996423e3ce3SKalle Valo 					  itssi_bg);
1997423e3ce3SKalle Valo 		else
1998423e3ce3SKalle Valo 			phy->idle_tssi = 62;
1999423e3ce3SKalle Valo 		dyn_tssi2dbm = kmalloc(64, GFP_KERNEL);
2000423e3ce3SKalle Valo 		if (dyn_tssi2dbm == NULL) {
2001423e3ce3SKalle Valo 			b43legacyerr(dev->wl, "Could not allocate memory "
2002423e3ce3SKalle Valo 			       "for tssi2dbm table\n");
2003423e3ce3SKalle Valo 			return -ENOMEM;
2004423e3ce3SKalle Valo 		}
2005423e3ce3SKalle Valo 		for (idx = 0; idx < 64; idx++)
2006423e3ce3SKalle Valo 			if (b43legacy_tssi2dbm_entry(dyn_tssi2dbm, idx, pab0,
2007423e3ce3SKalle Valo 						     pab1, pab2)) {
2008423e3ce3SKalle Valo 				phy->tssi2dbm = NULL;
2009423e3ce3SKalle Valo 				b43legacyerr(dev->wl, "Could not generate "
2010423e3ce3SKalle Valo 				       "tssi2dBm table\n");
2011423e3ce3SKalle Valo 				kfree(dyn_tssi2dbm);
2012423e3ce3SKalle Valo 				return -ENODEV;
2013423e3ce3SKalle Valo 			}
2014423e3ce3SKalle Valo 		phy->tssi2dbm = dyn_tssi2dbm;
2015423e3ce3SKalle Valo 		phy->dyn_tssi_tbl = 1;
2016423e3ce3SKalle Valo 	} else {
2017423e3ce3SKalle Valo 		/* pabX values not set in SPROM. */
2018423e3ce3SKalle Valo 		switch (phy->type) {
2019423e3ce3SKalle Valo 		case B43legacy_PHYTYPE_B:
2020423e3ce3SKalle Valo 			phy->idle_tssi = 0x34;
2021423e3ce3SKalle Valo 			phy->tssi2dbm = b43legacy_tssi2dbm_b_table;
2022423e3ce3SKalle Valo 			break;
2023423e3ce3SKalle Valo 		case B43legacy_PHYTYPE_G:
2024423e3ce3SKalle Valo 			phy->idle_tssi = 0x34;
2025423e3ce3SKalle Valo 			phy->tssi2dbm = b43legacy_tssi2dbm_g_table;
2026423e3ce3SKalle Valo 			break;
2027423e3ce3SKalle Valo 		}
2028423e3ce3SKalle Valo 	}
2029423e3ce3SKalle Valo 
2030423e3ce3SKalle Valo 	return 0;
2031423e3ce3SKalle Valo }
2032423e3ce3SKalle Valo 
b43legacy_phy_init(struct b43legacy_wldev * dev)2033423e3ce3SKalle Valo int b43legacy_phy_init(struct b43legacy_wldev *dev)
2034423e3ce3SKalle Valo {
2035423e3ce3SKalle Valo 	struct b43legacy_phy *phy = &dev->phy;
2036423e3ce3SKalle Valo 	int err = -ENODEV;
2037423e3ce3SKalle Valo 
2038423e3ce3SKalle Valo 	switch (phy->type) {
2039423e3ce3SKalle Valo 	case B43legacy_PHYTYPE_B:
2040423e3ce3SKalle Valo 		switch (phy->rev) {
2041423e3ce3SKalle Valo 		case 2:
2042423e3ce3SKalle Valo 			b43legacy_phy_initb2(dev);
2043423e3ce3SKalle Valo 			err = 0;
2044423e3ce3SKalle Valo 			break;
2045423e3ce3SKalle Valo 		case 4:
2046423e3ce3SKalle Valo 			b43legacy_phy_initb4(dev);
2047423e3ce3SKalle Valo 			err = 0;
2048423e3ce3SKalle Valo 			break;
2049423e3ce3SKalle Valo 		case 5:
2050423e3ce3SKalle Valo 			b43legacy_phy_initb5(dev);
2051423e3ce3SKalle Valo 			err = 0;
2052423e3ce3SKalle Valo 			break;
2053423e3ce3SKalle Valo 		case 6:
2054423e3ce3SKalle Valo 			b43legacy_phy_initb6(dev);
2055423e3ce3SKalle Valo 			err = 0;
2056423e3ce3SKalle Valo 			break;
2057423e3ce3SKalle Valo 		}
2058423e3ce3SKalle Valo 		break;
2059423e3ce3SKalle Valo 	case B43legacy_PHYTYPE_G:
2060423e3ce3SKalle Valo 		b43legacy_phy_initg(dev);
2061423e3ce3SKalle Valo 		err = 0;
2062423e3ce3SKalle Valo 		break;
2063423e3ce3SKalle Valo 	}
2064423e3ce3SKalle Valo 	if (err)
2065423e3ce3SKalle Valo 		b43legacyerr(dev->wl, "Unknown PHYTYPE found\n");
2066423e3ce3SKalle Valo 
2067423e3ce3SKalle Valo 	return err;
2068423e3ce3SKalle Valo }
2069423e3ce3SKalle Valo 
b43legacy_phy_set_antenna_diversity(struct b43legacy_wldev * dev)2070423e3ce3SKalle Valo void b43legacy_phy_set_antenna_diversity(struct b43legacy_wldev *dev)
2071423e3ce3SKalle Valo {
2072423e3ce3SKalle Valo 	struct b43legacy_phy *phy = &dev->phy;
2073423e3ce3SKalle Valo 	u16 antennadiv;
2074423e3ce3SKalle Valo 	u16 offset;
2075423e3ce3SKalle Valo 	u16 value;
2076423e3ce3SKalle Valo 	u32 ucodeflags;
2077423e3ce3SKalle Valo 
2078423e3ce3SKalle Valo 	antennadiv = phy->antenna_diversity;
2079423e3ce3SKalle Valo 
2080423e3ce3SKalle Valo 	if (antennadiv == 0xFFFF)
2081423e3ce3SKalle Valo 		antennadiv = 3;
2082423e3ce3SKalle Valo 	B43legacy_WARN_ON(antennadiv > 3);
2083423e3ce3SKalle Valo 
2084423e3ce3SKalle Valo 	ucodeflags = b43legacy_shm_read32(dev, B43legacy_SHM_SHARED,
2085423e3ce3SKalle Valo 					  B43legacy_UCODEFLAGS_OFFSET);
2086423e3ce3SKalle Valo 	b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
2087423e3ce3SKalle Valo 			      B43legacy_UCODEFLAGS_OFFSET,
2088423e3ce3SKalle Valo 			      ucodeflags & ~B43legacy_UCODEFLAG_AUTODIV);
2089423e3ce3SKalle Valo 
2090423e3ce3SKalle Valo 	switch (phy->type) {
2091423e3ce3SKalle Valo 	case B43legacy_PHYTYPE_G:
2092423e3ce3SKalle Valo 		offset = 0x0400;
2093423e3ce3SKalle Valo 
2094423e3ce3SKalle Valo 		if (antennadiv == 2)
2095423e3ce3SKalle Valo 			value = (3/*automatic*/ << 7);
2096423e3ce3SKalle Valo 		else
2097423e3ce3SKalle Valo 			value = (antennadiv << 7);
2098423e3ce3SKalle Valo 		b43legacy_phy_write(dev, offset + 1,
2099423e3ce3SKalle Valo 				    (b43legacy_phy_read(dev, offset + 1)
2100423e3ce3SKalle Valo 				    & 0x7E7F) | value);
2101423e3ce3SKalle Valo 
2102423e3ce3SKalle Valo 		if (antennadiv >= 2) {
2103423e3ce3SKalle Valo 			if (antennadiv == 2)
2104423e3ce3SKalle Valo 				value = (antennadiv << 7);
2105423e3ce3SKalle Valo 			else
2106423e3ce3SKalle Valo 				value = (0/*force0*/ << 7);
2107423e3ce3SKalle Valo 			b43legacy_phy_write(dev, offset + 0x2B,
2108423e3ce3SKalle Valo 					    (b43legacy_phy_read(dev,
2109423e3ce3SKalle Valo 					    offset + 0x2B)
2110423e3ce3SKalle Valo 					    & 0xFEFF) | value);
2111423e3ce3SKalle Valo 		}
2112423e3ce3SKalle Valo 
2113423e3ce3SKalle Valo 		if (phy->type == B43legacy_PHYTYPE_G) {
2114423e3ce3SKalle Valo 			if (antennadiv >= 2)
2115423e3ce3SKalle Valo 				b43legacy_phy_write(dev, 0x048C,
2116423e3ce3SKalle Valo 						    b43legacy_phy_read(dev,
2117423e3ce3SKalle Valo 						    0x048C) | 0x2000);
2118423e3ce3SKalle Valo 			else
2119423e3ce3SKalle Valo 				b43legacy_phy_write(dev, 0x048C,
2120423e3ce3SKalle Valo 						    b43legacy_phy_read(dev,
2121423e3ce3SKalle Valo 						    0x048C) & ~0x2000);
2122423e3ce3SKalle Valo 			if (phy->rev >= 2) {
2123423e3ce3SKalle Valo 				b43legacy_phy_write(dev, 0x0461,
2124423e3ce3SKalle Valo 						    b43legacy_phy_read(dev,
2125423e3ce3SKalle Valo 						    0x0461) | 0x0010);
2126423e3ce3SKalle Valo 				b43legacy_phy_write(dev, 0x04AD,
2127423e3ce3SKalle Valo 						    (b43legacy_phy_read(dev,
2128423e3ce3SKalle Valo 						    0x04AD)
2129423e3ce3SKalle Valo 						    & 0x00FF) | 0x0015);
2130423e3ce3SKalle Valo 				if (phy->rev == 2)
2131423e3ce3SKalle Valo 					b43legacy_phy_write(dev, 0x0427,
2132423e3ce3SKalle Valo 							    0x0008);
2133423e3ce3SKalle Valo 				else
2134423e3ce3SKalle Valo 					b43legacy_phy_write(dev, 0x0427,
2135423e3ce3SKalle Valo 						(b43legacy_phy_read(dev, 0x0427)
2136423e3ce3SKalle Valo 						 & 0x00FF) | 0x0008);
2137423e3ce3SKalle Valo 			} else if (phy->rev >= 6)
2138423e3ce3SKalle Valo 				b43legacy_phy_write(dev, 0x049B, 0x00DC);
2139423e3ce3SKalle Valo 		} else {
2140423e3ce3SKalle Valo 			if (phy->rev < 3)
2141423e3ce3SKalle Valo 				b43legacy_phy_write(dev, 0x002B,
2142423e3ce3SKalle Valo 						    (b43legacy_phy_read(dev,
2143423e3ce3SKalle Valo 						    0x002B) & 0x00FF)
2144423e3ce3SKalle Valo 						    | 0x0024);
2145423e3ce3SKalle Valo 			else {
2146423e3ce3SKalle Valo 				b43legacy_phy_write(dev, 0x0061,
2147423e3ce3SKalle Valo 						    b43legacy_phy_read(dev,
2148423e3ce3SKalle Valo 						    0x0061) | 0x0010);
2149423e3ce3SKalle Valo 				if (phy->rev == 3) {
2150423e3ce3SKalle Valo 					b43legacy_phy_write(dev, 0x0093,
2151423e3ce3SKalle Valo 							    0x001D);
2152423e3ce3SKalle Valo 					b43legacy_phy_write(dev, 0x0027,
2153423e3ce3SKalle Valo 							    0x0008);
2154423e3ce3SKalle Valo 				} else {
2155423e3ce3SKalle Valo 					b43legacy_phy_write(dev, 0x0093,
2156423e3ce3SKalle Valo 							    0x003A);
2157423e3ce3SKalle Valo 					b43legacy_phy_write(dev, 0x0027,
2158423e3ce3SKalle Valo 						(b43legacy_phy_read(dev, 0x0027)
2159423e3ce3SKalle Valo 						 & 0x00FF) | 0x0008);
2160423e3ce3SKalle Valo 				}
2161423e3ce3SKalle Valo 			}
2162423e3ce3SKalle Valo 		}
2163423e3ce3SKalle Valo 		break;
2164423e3ce3SKalle Valo 	case B43legacy_PHYTYPE_B:
2165423e3ce3SKalle Valo 		if (dev->dev->id.revision == 2)
2166423e3ce3SKalle Valo 			value = (3/*automatic*/ << 7);
2167423e3ce3SKalle Valo 		else
2168423e3ce3SKalle Valo 			value = (antennadiv << 7);
2169423e3ce3SKalle Valo 		b43legacy_phy_write(dev, 0x03E2,
2170423e3ce3SKalle Valo 				    (b43legacy_phy_read(dev, 0x03E2)
2171423e3ce3SKalle Valo 				    & 0xFE7F) | value);
2172423e3ce3SKalle Valo 		break;
2173423e3ce3SKalle Valo 	default:
2174423e3ce3SKalle Valo 		B43legacy_WARN_ON(1);
2175423e3ce3SKalle Valo 	}
2176423e3ce3SKalle Valo 
2177423e3ce3SKalle Valo 	if (antennadiv >= 2) {
2178423e3ce3SKalle Valo 		ucodeflags = b43legacy_shm_read32(dev, B43legacy_SHM_SHARED,
2179423e3ce3SKalle Valo 						  B43legacy_UCODEFLAGS_OFFSET);
2180423e3ce3SKalle Valo 		b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
2181423e3ce3SKalle Valo 				      B43legacy_UCODEFLAGS_OFFSET,
2182423e3ce3SKalle Valo 				      ucodeflags | B43legacy_UCODEFLAG_AUTODIV);
2183423e3ce3SKalle Valo 	}
2184423e3ce3SKalle Valo 
2185423e3ce3SKalle Valo 	phy->antenna_diversity = antennadiv;
2186423e3ce3SKalle Valo }
2187423e3ce3SKalle Valo 
2188423e3ce3SKalle Valo /* Set the PowerSavingControlBits.
2189423e3ce3SKalle Valo  * Bitvalues:
2190423e3ce3SKalle Valo  *   0  => unset the bit
2191423e3ce3SKalle Valo  *   1  => set the bit
2192423e3ce3SKalle Valo  *   -1 => calculate the bit
2193423e3ce3SKalle Valo  */
b43legacy_power_saving_ctl_bits(struct b43legacy_wldev * dev,int bit25,int bit26)2194423e3ce3SKalle Valo void b43legacy_power_saving_ctl_bits(struct b43legacy_wldev *dev,
2195423e3ce3SKalle Valo 				     int bit25, int bit26)
2196423e3ce3SKalle Valo {
2197423e3ce3SKalle Valo 	int i;
2198423e3ce3SKalle Valo 	u32 status;
2199423e3ce3SKalle Valo 
2200423e3ce3SKalle Valo /* FIXME: Force 25 to off and 26 to on for now: */
2201423e3ce3SKalle Valo bit25 = 0;
2202423e3ce3SKalle Valo bit26 = 1;
2203423e3ce3SKalle Valo 
2204423e3ce3SKalle Valo 	if (bit25 == -1) {
2205423e3ce3SKalle Valo 		/* TODO: If powersave is not off and FIXME is not set and we
2206423e3ce3SKalle Valo 		 *	are not in adhoc and thus is not an AP and we arei
2207423e3ce3SKalle Valo 		 *	associated, set bit 25 */
2208423e3ce3SKalle Valo 	}
2209423e3ce3SKalle Valo 	if (bit26 == -1) {
2210423e3ce3SKalle Valo 		/* TODO: If the device is awake or this is an AP, or we are
2211423e3ce3SKalle Valo 		 *	scanning, or FIXME, or we are associated, or FIXME,
2212423e3ce3SKalle Valo 		 *	or the latest PS-Poll packet sent was successful,
2213423e3ce3SKalle Valo 		 *	set bit26  */
2214423e3ce3SKalle Valo 	}
2215423e3ce3SKalle Valo 	status = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
2216423e3ce3SKalle Valo 	if (bit25)
2217423e3ce3SKalle Valo 		status |= B43legacy_MACCTL_HWPS;
2218423e3ce3SKalle Valo 	else
2219423e3ce3SKalle Valo 		status &= ~B43legacy_MACCTL_HWPS;
2220423e3ce3SKalle Valo 	if (bit26)
2221423e3ce3SKalle Valo 		status |= B43legacy_MACCTL_AWAKE;
2222423e3ce3SKalle Valo 	else
2223423e3ce3SKalle Valo 		status &= ~B43legacy_MACCTL_AWAKE;
2224423e3ce3SKalle Valo 	b43legacy_write32(dev, B43legacy_MMIO_MACCTL, status);
2225423e3ce3SKalle Valo 	if (bit26 && dev->dev->id.revision >= 5) {
2226423e3ce3SKalle Valo 		for (i = 0; i < 100; i++) {
2227423e3ce3SKalle Valo 			if (b43legacy_shm_read32(dev, B43legacy_SHM_SHARED,
2228423e3ce3SKalle Valo 						 0x0040) != 4)
2229423e3ce3SKalle Valo 				break;
2230423e3ce3SKalle Valo 			udelay(10);
2231423e3ce3SKalle Valo 		}
2232423e3ce3SKalle Valo 	}
2233423e3ce3SKalle Valo }
2234