brintos

brintos / linux-shallow public Read only

0
0
Text · 57.5 KiB · 8d7eb89 Raw
2110 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 4  Broadcom B43legacy wireless driver5 6  Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,7		     Stefano Brivio <stefano.brivio@polimi.it>8		     Michael Buesch <m@bues.ch>9		     Danny van Dyk <kugelfang@gentoo.org>10		     Andreas Jaggi <andreas.jaggi@waterwave.ch>11  Copyright (c) 2007 Larry Finger <Larry.Finger@lwfinger.net>12 13  Some parts of the code in this file are derived from the ipw220014  driver  Copyright(c) 2003 - 2004 Intel Corporation.15 16 17*/18 19#include <linux/delay.h>20 21#include "b43legacy.h"22#include "main.h"23#include "phy.h"24#include "radio.h"25#include "ilt.h"26 27 28/* Table for b43legacy_radio_calibrationvalue() */29static const u16 rcc_table[16] = {30	0x0002, 0x0003, 0x0001, 0x000F,31	0x0006, 0x0007, 0x0005, 0x000F,32	0x000A, 0x000B, 0x0009, 0x000F,33	0x000E, 0x000F, 0x000D, 0x000F,34};35 36/* Reverse the bits of a 4bit value.37 * Example:  1101 is flipped 101138 */39static u16 flip_4bit(u16 value)40{41	u16 flipped = 0x0000;42 43	B43legacy_BUG_ON(!((value & ~0x000F) == 0x0000));44 45	flipped |= (value & 0x0001) << 3;46	flipped |= (value & 0x0002) << 1;47	flipped |= (value & 0x0004) >> 1;48	flipped |= (value & 0x0008) >> 3;49 50	return flipped;51}52 53/* Get the freq, as it has to be written to the device. */54static inline55u16 channel2freq_bg(u8 channel)56{57	/* Frequencies are given as frequencies_bg[index] + 2.4GHz58	 * Starting with channel 159	 */60	static const u16 frequencies_bg[14] = {61		12, 17, 22, 27,62		32, 37, 42, 47,63		52, 57, 62, 67,64		72, 84,65	};66 67	if (unlikely(channel < 1 || channel > 14)) {68		printk(KERN_INFO "b43legacy: Channel %d is out of range\n",69				  channel);70		dump_stack();71		return 2412;72	}73 74	return frequencies_bg[channel - 1];75}76 77void b43legacy_radio_lock(struct b43legacy_wldev *dev)78{79	u32 status;80 81	status = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);82	B43legacy_WARN_ON(status & B43legacy_MACCTL_RADIOLOCK);83	status |= B43legacy_MACCTL_RADIOLOCK;84	b43legacy_write32(dev, B43legacy_MMIO_MACCTL, status);85	udelay(10);86}87 88void b43legacy_radio_unlock(struct b43legacy_wldev *dev)89{90	u32 status;91 92	b43legacy_read16(dev, B43legacy_MMIO_PHY_VER); /* dummy read */93	status = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);94	B43legacy_WARN_ON(!(status & B43legacy_MACCTL_RADIOLOCK));95	status &= ~B43legacy_MACCTL_RADIOLOCK;96	b43legacy_write32(dev, B43legacy_MMIO_MACCTL, status);97}98 99u16 b43legacy_radio_read16(struct b43legacy_wldev *dev, u16 offset)100{101	struct b43legacy_phy *phy = &dev->phy;102 103	switch (phy->type) {104	case B43legacy_PHYTYPE_B:105		if (phy->radio_ver == 0x2053) {106			if (offset < 0x70)107				offset += 0x80;108			else if (offset < 0x80)109				offset += 0x70;110		} else if (phy->radio_ver == 0x2050)111			offset |= 0x80;112		else113			B43legacy_WARN_ON(1);114		break;115	case B43legacy_PHYTYPE_G:116		offset |= 0x80;117		break;118	default:119		B43legacy_BUG_ON(1);120	}121 122	b43legacy_write16(dev, B43legacy_MMIO_RADIO_CONTROL, offset);123	return b43legacy_read16(dev, B43legacy_MMIO_RADIO_DATA_LOW);124}125 126void b43legacy_radio_write16(struct b43legacy_wldev *dev, u16 offset, u16 val)127{128	b43legacy_write16(dev, B43legacy_MMIO_RADIO_CONTROL, offset);129	b43legacy_write16(dev, B43legacy_MMIO_RADIO_DATA_LOW, val);130}131 132static void b43legacy_set_all_gains(struct b43legacy_wldev *dev,133				  s16 first, s16 second, s16 third)134{135	struct b43legacy_phy *phy = &dev->phy;136	u16 i;137	u16 start = 0x08;138	u16 end = 0x18;139	u16 offset = 0x0400;140	u16 tmp;141 142	if (phy->rev <= 1) {143		offset = 0x5000;144		start = 0x10;145		end = 0x20;146	}147 148	for (i = 0; i < 4; i++)149		b43legacy_ilt_write(dev, offset + i, first);150 151	for (i = start; i < end; i++)152		b43legacy_ilt_write(dev, offset + i, second);153 154	if (third != -1) {155		tmp = ((u16)third << 14) | ((u16)third << 6);156		b43legacy_phy_write(dev, 0x04A0,157				    (b43legacy_phy_read(dev, 0x04A0) & 0xBFBF)158				    | tmp);159		b43legacy_phy_write(dev, 0x04A1,160				    (b43legacy_phy_read(dev, 0x04A1) & 0xBFBF)161				    | tmp);162		b43legacy_phy_write(dev, 0x04A2,163				    (b43legacy_phy_read(dev, 0x04A2) & 0xBFBF)164				    | tmp);165	}166	b43legacy_dummy_transmission(dev);167}168 169static void b43legacy_set_original_gains(struct b43legacy_wldev *dev)170{171	struct b43legacy_phy *phy = &dev->phy;172	u16 i;173	u16 tmp;174	u16 offset = 0x0400;175	u16 start = 0x0008;176	u16 end = 0x0018;177 178	if (phy->rev <= 1) {179		offset = 0x5000;180		start = 0x0010;181		end = 0x0020;182	}183 184	for (i = 0; i < 4; i++) {185		tmp = (i & 0xFFFC);186		tmp |= (i & 0x0001) << 1;187		tmp |= (i & 0x0002) >> 1;188 189		b43legacy_ilt_write(dev, offset + i, tmp);190	}191 192	for (i = start; i < end; i++)193		b43legacy_ilt_write(dev, offset + i, i - start);194 195	b43legacy_phy_write(dev, 0x04A0,196			    (b43legacy_phy_read(dev, 0x04A0) & 0xBFBF)197			    | 0x4040);198	b43legacy_phy_write(dev, 0x04A1,199			    (b43legacy_phy_read(dev, 0x04A1) & 0xBFBF)200			    | 0x4040);201	b43legacy_phy_write(dev, 0x04A2,202			    (b43legacy_phy_read(dev, 0x04A2) & 0xBFBF)203			    | 0x4000);204	b43legacy_dummy_transmission(dev);205}206 207/* Synthetic PU workaround */208static void b43legacy_synth_pu_workaround(struct b43legacy_wldev *dev,209					  u8 channel)210{211	struct b43legacy_phy *phy = &dev->phy;212 213	might_sleep();214 215	if (phy->radio_ver != 0x2050 || phy->radio_rev >= 6)216		/* We do not need the workaround. */217		return;218 219	if (channel <= 10)220		b43legacy_write16(dev, B43legacy_MMIO_CHANNEL,221				  channel2freq_bg(channel + 4));222	else223		b43legacy_write16(dev, B43legacy_MMIO_CHANNEL,224				  channel2freq_bg(channel));225	msleep(1);226	b43legacy_write16(dev, B43legacy_MMIO_CHANNEL,227			  channel2freq_bg(channel));228}229 230u8 b43legacy_radio_aci_detect(struct b43legacy_wldev *dev, u8 channel)231{232	struct b43legacy_phy *phy = &dev->phy;233	u8 ret = 0;234	u16 saved;235	u16 rssi;236	u16 temp;237	int i;238	int j = 0;239 240	saved = b43legacy_phy_read(dev, 0x0403);241	b43legacy_radio_selectchannel(dev, channel, 0);242	b43legacy_phy_write(dev, 0x0403, (saved & 0xFFF8) | 5);243	if (phy->aci_hw_rssi)244		rssi = b43legacy_phy_read(dev, 0x048A) & 0x3F;245	else246		rssi = saved & 0x3F;247	/* clamp temp to signed 5bit */248	if (rssi > 32)249		rssi -= 64;250	for (i = 0; i < 100; i++) {251		temp = (b43legacy_phy_read(dev, 0x047F) >> 8) & 0x3F;252		if (temp > 32)253			temp -= 64;254		if (temp < rssi)255			j++;256		if (j >= 20)257			ret = 1;258	}259	b43legacy_phy_write(dev, 0x0403, saved);260 261	return ret;262}263 264u8 b43legacy_radio_aci_scan(struct b43legacy_wldev *dev)265{266	struct b43legacy_phy *phy = &dev->phy;267	u8 ret[13] = { 0 };268	unsigned int channel = phy->channel;269	unsigned int i;270	unsigned int j;271	unsigned int start;272	unsigned int end;273 274	if (!((phy->type == B43legacy_PHYTYPE_G) && (phy->rev > 0)))275		return 0;276 277	b43legacy_phy_lock(dev);278	b43legacy_radio_lock(dev);279	b43legacy_phy_write(dev, 0x0802,280			    b43legacy_phy_read(dev, 0x0802) & 0xFFFC);281	b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,282			    b43legacy_phy_read(dev, B43legacy_PHY_G_CRS)283			    & 0x7FFF);284	b43legacy_set_all_gains(dev, 3, 8, 1);285 286	start = (channel > 5) ? channel - 5 : 1;287	end = (channel + 5 < 14) ? channel + 5 : 13;288 289	for (i = start; i <= end; i++) {290		if (abs(channel - i) > 2)291			ret[i-1] = b43legacy_radio_aci_detect(dev, i);292	}293	b43legacy_radio_selectchannel(dev, channel, 0);294	b43legacy_phy_write(dev, 0x0802,295			    (b43legacy_phy_read(dev, 0x0802) & 0xFFFC)296			    | 0x0003);297	b43legacy_phy_write(dev, 0x0403,298			    b43legacy_phy_read(dev, 0x0403) & 0xFFF8);299	b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,300			    b43legacy_phy_read(dev, B43legacy_PHY_G_CRS)301			    | 0x8000);302	b43legacy_set_original_gains(dev);303	for (i = 0; i < 13; i++) {304		if (!ret[i])305			continue;306		end = (i + 5 < 13) ? i + 5 : 13;307		for (j = i; j < end; j++)308			ret[j] = 1;309	}310	b43legacy_radio_unlock(dev);311	b43legacy_phy_unlock(dev);312 313	return ret[channel - 1];314}315 316/* https://bcm-specs.sipsolutions.net/NRSSILookupTable */317void b43legacy_nrssi_hw_write(struct b43legacy_wldev *dev, u16 offset, s16 val)318{319	b43legacy_phy_write(dev, B43legacy_PHY_NRSSILT_CTRL, offset);320	b43legacy_phy_write(dev, B43legacy_PHY_NRSSILT_DATA, (u16)val);321}322 323/* https://bcm-specs.sipsolutions.net/NRSSILookupTable */324s16 b43legacy_nrssi_hw_read(struct b43legacy_wldev *dev, u16 offset)325{326	u16 val;327 328	b43legacy_phy_write(dev, B43legacy_PHY_NRSSILT_CTRL, offset);329	val = b43legacy_phy_read(dev, B43legacy_PHY_NRSSILT_DATA);330 331	return (s16)val;332}333 334/* https://bcm-specs.sipsolutions.net/NRSSILookupTable */335void b43legacy_nrssi_hw_update(struct b43legacy_wldev *dev, u16 val)336{337	u16 i;338	s16 tmp;339 340	for (i = 0; i < 64; i++) {341		tmp = b43legacy_nrssi_hw_read(dev, i);342		tmp -= val;343		tmp = clamp_val(tmp, -32, 31);344		b43legacy_nrssi_hw_write(dev, i, tmp);345	}346}347 348/* https://bcm-specs.sipsolutions.net/NRSSILookupTable */349void b43legacy_nrssi_mem_update(struct b43legacy_wldev *dev)350{351	struct b43legacy_phy *phy = &dev->phy;352	s16 i;353	s16 delta;354	s32 tmp;355 356	delta = 0x1F - phy->nrssi[0];357	for (i = 0; i < 64; i++) {358		tmp = (i - delta) * phy->nrssislope;359		tmp /= 0x10000;360		tmp += 0x3A;361		tmp = clamp_val(tmp, 0, 0x3F);362		phy->nrssi_lt[i] = tmp;363	}364}365 366static void b43legacy_calc_nrssi_offset(struct b43legacy_wldev *dev)367{368	struct b43legacy_phy *phy = &dev->phy;369	u16 backup[20] = { 0 };370	s16 v47F;371	u16 i;372	u16 saved = 0xFFFF;373 374	backup[0] = b43legacy_phy_read(dev, 0x0001);375	backup[1] = b43legacy_phy_read(dev, 0x0811);376	backup[2] = b43legacy_phy_read(dev, 0x0812);377	backup[3] = b43legacy_phy_read(dev, 0x0814);378	backup[4] = b43legacy_phy_read(dev, 0x0815);379	backup[5] = b43legacy_phy_read(dev, 0x005A);380	backup[6] = b43legacy_phy_read(dev, 0x0059);381	backup[7] = b43legacy_phy_read(dev, 0x0058);382	backup[8] = b43legacy_phy_read(dev, 0x000A);383	backup[9] = b43legacy_phy_read(dev, 0x0003);384	backup[10] = b43legacy_radio_read16(dev, 0x007A);385	backup[11] = b43legacy_radio_read16(dev, 0x0043);386 387	b43legacy_phy_write(dev, 0x0429,388			    b43legacy_phy_read(dev, 0x0429) & 0x7FFF);389	b43legacy_phy_write(dev, 0x0001,390			    (b43legacy_phy_read(dev, 0x0001) & 0x3FFF)391			    | 0x4000);392	b43legacy_phy_write(dev, 0x0811,393			    b43legacy_phy_read(dev, 0x0811) | 0x000C);394	b43legacy_phy_write(dev, 0x0812,395			    (b43legacy_phy_read(dev, 0x0812) & 0xFFF3)396			    | 0x0004);397	b43legacy_phy_write(dev, 0x0802,398			    b43legacy_phy_read(dev, 0x0802) & ~(0x1 | 0x2));399	if (phy->rev >= 6) {400		backup[12] = b43legacy_phy_read(dev, 0x002E);401		backup[13] = b43legacy_phy_read(dev, 0x002F);402		backup[14] = b43legacy_phy_read(dev, 0x080F);403		backup[15] = b43legacy_phy_read(dev, 0x0810);404		backup[16] = b43legacy_phy_read(dev, 0x0801);405		backup[17] = b43legacy_phy_read(dev, 0x0060);406		backup[18] = b43legacy_phy_read(dev, 0x0014);407		backup[19] = b43legacy_phy_read(dev, 0x0478);408 409		b43legacy_phy_write(dev, 0x002E, 0);410		b43legacy_phy_write(dev, 0x002F, 0);411		b43legacy_phy_write(dev, 0x080F, 0);412		b43legacy_phy_write(dev, 0x0810, 0);413		b43legacy_phy_write(dev, 0x0478,414				    b43legacy_phy_read(dev, 0x0478) | 0x0100);415		b43legacy_phy_write(dev, 0x0801,416				    b43legacy_phy_read(dev, 0x0801) | 0x0040);417		b43legacy_phy_write(dev, 0x0060,418				    b43legacy_phy_read(dev, 0x0060) | 0x0040);419		b43legacy_phy_write(dev, 0x0014,420				    b43legacy_phy_read(dev, 0x0014) | 0x0200);421	}422	b43legacy_radio_write16(dev, 0x007A,423				b43legacy_radio_read16(dev, 0x007A) | 0x0070);424	b43legacy_radio_write16(dev, 0x007A,425				b43legacy_radio_read16(dev, 0x007A) | 0x0080);426	udelay(30);427 428	v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) & 0x003F);429	if (v47F >= 0x20)430		v47F -= 0x40;431	if (v47F == 31) {432		for (i = 7; i >= 4; i--) {433			b43legacy_radio_write16(dev, 0x007B, i);434			udelay(20);435			v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8)436							 & 0x003F);437			if (v47F >= 0x20)438				v47F -= 0x40;439			if (v47F < 31 && saved == 0xFFFF)440				saved = i;441		}442		if (saved == 0xFFFF)443			saved = 4;444	} else {445		b43legacy_radio_write16(dev, 0x007A,446					b43legacy_radio_read16(dev, 0x007A)447					& 0x007F);448		b43legacy_phy_write(dev, 0x0814,449				    b43legacy_phy_read(dev, 0x0814) | 0x0001);450		b43legacy_phy_write(dev, 0x0815,451				    b43legacy_phy_read(dev, 0x0815) & 0xFFFE);452		b43legacy_phy_write(dev, 0x0811,453				    b43legacy_phy_read(dev, 0x0811) | 0x000C);454		b43legacy_phy_write(dev, 0x0812,455				    b43legacy_phy_read(dev, 0x0812) | 0x000C);456		b43legacy_phy_write(dev, 0x0811,457				    b43legacy_phy_read(dev, 0x0811) | 0x0030);458		b43legacy_phy_write(dev, 0x0812,459				    b43legacy_phy_read(dev, 0x0812) | 0x0030);460		b43legacy_phy_write(dev, 0x005A, 0x0480);461		b43legacy_phy_write(dev, 0x0059, 0x0810);462		b43legacy_phy_write(dev, 0x0058, 0x000D);463		if (phy->analog == 0)464			b43legacy_phy_write(dev, 0x0003, 0x0122);465		else466			b43legacy_phy_write(dev, 0x000A,467					    b43legacy_phy_read(dev, 0x000A)468					    | 0x2000);469		b43legacy_phy_write(dev, 0x0814,470				    b43legacy_phy_read(dev, 0x0814) | 0x0004);471		b43legacy_phy_write(dev, 0x0815,472				    b43legacy_phy_read(dev, 0x0815) & 0xFFFB);473		b43legacy_phy_write(dev, 0x0003,474				    (b43legacy_phy_read(dev, 0x0003) & 0xFF9F)475				    | 0x0040);476		b43legacy_radio_write16(dev, 0x007A,477					b43legacy_radio_read16(dev, 0x007A)478					| 0x000F);479		b43legacy_set_all_gains(dev, 3, 0, 1);480		b43legacy_radio_write16(dev, 0x0043,481					(b43legacy_radio_read16(dev, 0x0043)482					& 0x00F0) | 0x000F);483		udelay(30);484		v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) & 0x003F);485		if (v47F >= 0x20)486			v47F -= 0x40;487		if (v47F == -32) {488			for (i = 0; i < 4; i++) {489				b43legacy_radio_write16(dev, 0x007B, i);490				udelay(20);491				v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >>492								 8) & 0x003F);493				if (v47F >= 0x20)494					v47F -= 0x40;495				if (v47F > -31 && saved == 0xFFFF)496					saved = i;497			}498			if (saved == 0xFFFF)499				saved = 3;500		} else501			saved = 0;502	}503	b43legacy_radio_write16(dev, 0x007B, saved);504 505	if (phy->rev >= 6) {506		b43legacy_phy_write(dev, 0x002E, backup[12]);507		b43legacy_phy_write(dev, 0x002F, backup[13]);508		b43legacy_phy_write(dev, 0x080F, backup[14]);509		b43legacy_phy_write(dev, 0x0810, backup[15]);510	}511	b43legacy_phy_write(dev, 0x0814, backup[3]);512	b43legacy_phy_write(dev, 0x0815, backup[4]);513	b43legacy_phy_write(dev, 0x005A, backup[5]);514	b43legacy_phy_write(dev, 0x0059, backup[6]);515	b43legacy_phy_write(dev, 0x0058, backup[7]);516	b43legacy_phy_write(dev, 0x000A, backup[8]);517	b43legacy_phy_write(dev, 0x0003, backup[9]);518	b43legacy_radio_write16(dev, 0x0043, backup[11]);519	b43legacy_radio_write16(dev, 0x007A, backup[10]);520	b43legacy_phy_write(dev, 0x0802,521			    b43legacy_phy_read(dev, 0x0802) | 0x1 | 0x2);522	b43legacy_phy_write(dev, 0x0429,523			    b43legacy_phy_read(dev, 0x0429) | 0x8000);524	b43legacy_set_original_gains(dev);525	if (phy->rev >= 6) {526		b43legacy_phy_write(dev, 0x0801, backup[16]);527		b43legacy_phy_write(dev, 0x0060, backup[17]);528		b43legacy_phy_write(dev, 0x0014, backup[18]);529		b43legacy_phy_write(dev, 0x0478, backup[19]);530	}531	b43legacy_phy_write(dev, 0x0001, backup[0]);532	b43legacy_phy_write(dev, 0x0812, backup[2]);533	b43legacy_phy_write(dev, 0x0811, backup[1]);534}535 536void b43legacy_calc_nrssi_slope(struct b43legacy_wldev *dev)537{538	struct b43legacy_phy *phy = &dev->phy;539	u16 backup[18] = { 0 };540	u16 tmp;541	s16 nrssi0;542	s16 nrssi1;543 544	switch (phy->type) {545	case B43legacy_PHYTYPE_B:546		backup[0] = b43legacy_radio_read16(dev, 0x007A);547		backup[1] = b43legacy_radio_read16(dev, 0x0052);548		backup[2] = b43legacy_radio_read16(dev, 0x0043);549		backup[3] = b43legacy_phy_read(dev, 0x0030);550		backup[4] = b43legacy_phy_read(dev, 0x0026);551		backup[5] = b43legacy_phy_read(dev, 0x0015);552		backup[6] = b43legacy_phy_read(dev, 0x002A);553		backup[7] = b43legacy_phy_read(dev, 0x0020);554		backup[8] = b43legacy_phy_read(dev, 0x005A);555		backup[9] = b43legacy_phy_read(dev, 0x0059);556		backup[10] = b43legacy_phy_read(dev, 0x0058);557		backup[11] = b43legacy_read16(dev, 0x03E2);558		backup[12] = b43legacy_read16(dev, 0x03E6);559		backup[13] = b43legacy_read16(dev, B43legacy_MMIO_CHANNEL_EXT);560 561		tmp  = b43legacy_radio_read16(dev, 0x007A);562		tmp &= (phy->rev >= 5) ? 0x007F : 0x000F;563		b43legacy_radio_write16(dev, 0x007A, tmp);564		b43legacy_phy_write(dev, 0x0030, 0x00FF);565		b43legacy_write16(dev, 0x03EC, 0x7F7F);566		b43legacy_phy_write(dev, 0x0026, 0x0000);567		b43legacy_phy_write(dev, 0x0015,568				    b43legacy_phy_read(dev, 0x0015) | 0x0020);569		b43legacy_phy_write(dev, 0x002A, 0x08A3);570		b43legacy_radio_write16(dev, 0x007A,571					b43legacy_radio_read16(dev, 0x007A)572					| 0x0080);573 574		nrssi0 = (s16)b43legacy_phy_read(dev, 0x0027);575		b43legacy_radio_write16(dev, 0x007A,576					b43legacy_radio_read16(dev, 0x007A)577					& 0x007F);578		if (phy->analog >= 2)579			b43legacy_write16(dev, 0x03E6, 0x0040);580		else if (phy->analog == 0)581			b43legacy_write16(dev, 0x03E6, 0x0122);582		else583			b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT,584					  b43legacy_read16(dev,585					  B43legacy_MMIO_CHANNEL_EXT) & 0x2000);586		b43legacy_phy_write(dev, 0x0020, 0x3F3F);587		b43legacy_phy_write(dev, 0x0015, 0xF330);588		b43legacy_radio_write16(dev, 0x005A, 0x0060);589		b43legacy_radio_write16(dev, 0x0043,590					b43legacy_radio_read16(dev, 0x0043)591					& 0x00F0);592		b43legacy_phy_write(dev, 0x005A, 0x0480);593		b43legacy_phy_write(dev, 0x0059, 0x0810);594		b43legacy_phy_write(dev, 0x0058, 0x000D);595		udelay(20);596 597		nrssi1 = (s16)b43legacy_phy_read(dev, 0x0027);598		b43legacy_phy_write(dev, 0x0030, backup[3]);599		b43legacy_radio_write16(dev, 0x007A, backup[0]);600		b43legacy_write16(dev, 0x03E2, backup[11]);601		b43legacy_phy_write(dev, 0x0026, backup[4]);602		b43legacy_phy_write(dev, 0x0015, backup[5]);603		b43legacy_phy_write(dev, 0x002A, backup[6]);604		b43legacy_synth_pu_workaround(dev, phy->channel);605		if (phy->analog != 0)606			b43legacy_write16(dev, 0x03F4, backup[13]);607 608		b43legacy_phy_write(dev, 0x0020, backup[7]);609		b43legacy_phy_write(dev, 0x005A, backup[8]);610		b43legacy_phy_write(dev, 0x0059, backup[9]);611		b43legacy_phy_write(dev, 0x0058, backup[10]);612		b43legacy_radio_write16(dev, 0x0052, backup[1]);613		b43legacy_radio_write16(dev, 0x0043, backup[2]);614 615		if (nrssi0 == nrssi1)616			phy->nrssislope = 0x00010000;617		else618			phy->nrssislope = 0x00400000 / (nrssi0 - nrssi1);619 620		if (nrssi0 <= -4) {621			phy->nrssi[0] = nrssi0;622			phy->nrssi[1] = nrssi1;623		}624		break;625	case B43legacy_PHYTYPE_G:626		if (phy->radio_rev >= 9)627			return;628		if (phy->radio_rev == 8)629			b43legacy_calc_nrssi_offset(dev);630 631		b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,632				    b43legacy_phy_read(dev, B43legacy_PHY_G_CRS)633				    & 0x7FFF);634		b43legacy_phy_write(dev, 0x0802,635				    b43legacy_phy_read(dev, 0x0802) & 0xFFFC);636		backup[7] = b43legacy_read16(dev, 0x03E2);637		b43legacy_write16(dev, 0x03E2,638				  b43legacy_read16(dev, 0x03E2) | 0x8000);639		backup[0] = b43legacy_radio_read16(dev, 0x007A);640		backup[1] = b43legacy_radio_read16(dev, 0x0052);641		backup[2] = b43legacy_radio_read16(dev, 0x0043);642		backup[3] = b43legacy_phy_read(dev, 0x0015);643		backup[4] = b43legacy_phy_read(dev, 0x005A);644		backup[5] = b43legacy_phy_read(dev, 0x0059);645		backup[6] = b43legacy_phy_read(dev, 0x0058);646		backup[8] = b43legacy_read16(dev, 0x03E6);647		backup[9] = b43legacy_read16(dev, B43legacy_MMIO_CHANNEL_EXT);648		if (phy->rev >= 3) {649			backup[10] = b43legacy_phy_read(dev, 0x002E);650			backup[11] = b43legacy_phy_read(dev, 0x002F);651			backup[12] = b43legacy_phy_read(dev, 0x080F);652			backup[13] = b43legacy_phy_read(dev,653						B43legacy_PHY_G_LO_CONTROL);654			backup[14] = b43legacy_phy_read(dev, 0x0801);655			backup[15] = b43legacy_phy_read(dev, 0x0060);656			backup[16] = b43legacy_phy_read(dev, 0x0014);657			backup[17] = b43legacy_phy_read(dev, 0x0478);658			b43legacy_phy_write(dev, 0x002E, 0);659			b43legacy_phy_write(dev, B43legacy_PHY_G_LO_CONTROL, 0);660			switch (phy->rev) {661			case 4: case 6: case 7:662				b43legacy_phy_write(dev, 0x0478,663						    b43legacy_phy_read(dev,664						    0x0478) | 0x0100);665				b43legacy_phy_write(dev, 0x0801,666						    b43legacy_phy_read(dev,667						    0x0801) | 0x0040);668				break;669			case 3: case 5:670				b43legacy_phy_write(dev, 0x0801,671						    b43legacy_phy_read(dev,672						    0x0801) & 0xFFBF);673				break;674			}675			b43legacy_phy_write(dev, 0x0060,676					    b43legacy_phy_read(dev, 0x0060)677					    | 0x0040);678			b43legacy_phy_write(dev, 0x0014,679					    b43legacy_phy_read(dev, 0x0014)680					    | 0x0200);681		}682		b43legacy_radio_write16(dev, 0x007A,683					b43legacy_radio_read16(dev, 0x007A)684					| 0x0070);685		b43legacy_set_all_gains(dev, 0, 8, 0);686		b43legacy_radio_write16(dev, 0x007A,687					b43legacy_radio_read16(dev, 0x007A)688					& 0x00F7);689		if (phy->rev >= 2) {690			b43legacy_phy_write(dev, 0x0811,691					    (b43legacy_phy_read(dev, 0x0811)692					    & 0xFFCF) | 0x0030);693			b43legacy_phy_write(dev, 0x0812,694					    (b43legacy_phy_read(dev, 0x0812)695					    & 0xFFCF) | 0x0010);696		}697		b43legacy_radio_write16(dev, 0x007A,698					b43legacy_radio_read16(dev, 0x007A)699					| 0x0080);700		udelay(20);701 702		nrssi0 = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) & 0x003F);703		if (nrssi0 >= 0x0020)704			nrssi0 -= 0x0040;705 706		b43legacy_radio_write16(dev, 0x007A,707					b43legacy_radio_read16(dev, 0x007A)708					& 0x007F);709		if (phy->analog >= 2)710			b43legacy_phy_write(dev, 0x0003,711					    (b43legacy_phy_read(dev, 0x0003)712					    & 0xFF9F) | 0x0040);713 714		b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT,715				  b43legacy_read16(dev,716				  B43legacy_MMIO_CHANNEL_EXT) | 0x2000);717		b43legacy_radio_write16(dev, 0x007A,718					b43legacy_radio_read16(dev, 0x007A)719					| 0x000F);720		b43legacy_phy_write(dev, 0x0015, 0xF330);721		if (phy->rev >= 2) {722			b43legacy_phy_write(dev, 0x0812,723					    (b43legacy_phy_read(dev, 0x0812)724					    & 0xFFCF) | 0x0020);725			b43legacy_phy_write(dev, 0x0811,726					    (b43legacy_phy_read(dev, 0x0811)727					    & 0xFFCF) | 0x0020);728		}729 730		b43legacy_set_all_gains(dev, 3, 0, 1);731		if (phy->radio_rev == 8)732			b43legacy_radio_write16(dev, 0x0043, 0x001F);733		else {734			tmp = b43legacy_radio_read16(dev, 0x0052) & 0xFF0F;735			b43legacy_radio_write16(dev, 0x0052, tmp | 0x0060);736			tmp = b43legacy_radio_read16(dev, 0x0043) & 0xFFF0;737			b43legacy_radio_write16(dev, 0x0043, tmp | 0x0009);738		}739		b43legacy_phy_write(dev, 0x005A, 0x0480);740		b43legacy_phy_write(dev, 0x0059, 0x0810);741		b43legacy_phy_write(dev, 0x0058, 0x000D);742		udelay(20);743		nrssi1 = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) & 0x003F);744		if (nrssi1 >= 0x0020)745			nrssi1 -= 0x0040;746		if (nrssi0 == nrssi1)747			phy->nrssislope = 0x00010000;748		else749			phy->nrssislope = 0x00400000 / (nrssi0 - nrssi1);750		if (nrssi0 >= -4) {751			phy->nrssi[0] = nrssi1;752			phy->nrssi[1] = nrssi0;753		}754		if (phy->rev >= 3) {755			b43legacy_phy_write(dev, 0x002E, backup[10]);756			b43legacy_phy_write(dev, 0x002F, backup[11]);757			b43legacy_phy_write(dev, 0x080F, backup[12]);758			b43legacy_phy_write(dev, B43legacy_PHY_G_LO_CONTROL,759					    backup[13]);760		}761		if (phy->rev >= 2) {762			b43legacy_phy_write(dev, 0x0812,763					    b43legacy_phy_read(dev, 0x0812)764					    & 0xFFCF);765			b43legacy_phy_write(dev, 0x0811,766					    b43legacy_phy_read(dev, 0x0811)767					    & 0xFFCF);768		}769 770		b43legacy_radio_write16(dev, 0x007A, backup[0]);771		b43legacy_radio_write16(dev, 0x0052, backup[1]);772		b43legacy_radio_write16(dev, 0x0043, backup[2]);773		b43legacy_write16(dev, 0x03E2, backup[7]);774		b43legacy_write16(dev, 0x03E6, backup[8]);775		b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, backup[9]);776		b43legacy_phy_write(dev, 0x0015, backup[3]);777		b43legacy_phy_write(dev, 0x005A, backup[4]);778		b43legacy_phy_write(dev, 0x0059, backup[5]);779		b43legacy_phy_write(dev, 0x0058, backup[6]);780		b43legacy_synth_pu_workaround(dev, phy->channel);781		b43legacy_phy_write(dev, 0x0802,782				    b43legacy_phy_read(dev, 0x0802) | 0x0003);783		b43legacy_set_original_gains(dev);784		b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,785				    b43legacy_phy_read(dev, B43legacy_PHY_G_CRS)786				    | 0x8000);787		if (phy->rev >= 3) {788			b43legacy_phy_write(dev, 0x0801, backup[14]);789			b43legacy_phy_write(dev, 0x0060, backup[15]);790			b43legacy_phy_write(dev, 0x0014, backup[16]);791			b43legacy_phy_write(dev, 0x0478, backup[17]);792		}793		b43legacy_nrssi_mem_update(dev);794		b43legacy_calc_nrssi_threshold(dev);795		break;796	default:797		B43legacy_BUG_ON(1);798	}799}800 801void b43legacy_calc_nrssi_threshold(struct b43legacy_wldev *dev)802{803	struct b43legacy_phy *phy = &dev->phy;804	s32 threshold;805	s32 a;806	s32 b;807	s16 tmp16;808	u16 tmp_u16;809 810	switch (phy->type) {811	case B43legacy_PHYTYPE_B: {812		if (phy->radio_ver != 0x2050)813			return;814		if (!(dev->dev->bus->sprom.boardflags_lo &815		    B43legacy_BFL_RSSI))816			return;817 818		if (phy->radio_rev >= 6) {819			threshold = (phy->nrssi[1] - phy->nrssi[0]) * 32;820			threshold += 20 * (phy->nrssi[0] + 1);821			threshold /= 40;822		} else823			threshold = phy->nrssi[1] - 5;824 825		threshold = clamp_val(threshold, 0, 0x3E);826		b43legacy_phy_read(dev, 0x0020); /* dummy read */827		b43legacy_phy_write(dev, 0x0020, (((u16)threshold) << 8)828				    | 0x001C);829 830		if (phy->radio_rev >= 6) {831			b43legacy_phy_write(dev, 0x0087, 0x0E0D);832			b43legacy_phy_write(dev, 0x0086, 0x0C0B);833			b43legacy_phy_write(dev, 0x0085, 0x0A09);834			b43legacy_phy_write(dev, 0x0084, 0x0808);835			b43legacy_phy_write(dev, 0x0083, 0x0808);836			b43legacy_phy_write(dev, 0x0082, 0x0604);837			b43legacy_phy_write(dev, 0x0081, 0x0302);838			b43legacy_phy_write(dev, 0x0080, 0x0100);839		}840		break;841	}842	case B43legacy_PHYTYPE_G:843		if (!phy->gmode ||844		    !(dev->dev->bus->sprom.boardflags_lo &845		    B43legacy_BFL_RSSI)) {846			tmp16 = b43legacy_nrssi_hw_read(dev, 0x20);847			if (tmp16 >= 0x20)848				tmp16 -= 0x40;849			if (tmp16 < 3)850				b43legacy_phy_write(dev, 0x048A,851						    (b43legacy_phy_read(dev,852						    0x048A) & 0xF000) | 0x09EB);853			else854				b43legacy_phy_write(dev, 0x048A,855						    (b43legacy_phy_read(dev,856						    0x048A) & 0xF000) | 0x0AED);857		} else {858			if (phy->interfmode ==859			    B43legacy_RADIO_INTERFMODE_NONWLAN) {860				a = 0xE;861				b = 0xA;862			} else if (!phy->aci_wlan_automatic &&863				    phy->aci_enable) {864				a = 0x13;865				b = 0x12;866			} else {867				a = 0xE;868				b = 0x11;869			}870 871			a = a * (phy->nrssi[1] - phy->nrssi[0]);872			a += (phy->nrssi[0] << 6);873			if (a < 32)874				a += 31;875			else876				a += 32;877			a = a >> 6;878			a = clamp_val(a, -31, 31);879 880			b = b * (phy->nrssi[1] - phy->nrssi[0]);881			b += (phy->nrssi[0] << 6);882			if (b < 32)883				b += 31;884			else885				b += 32;886			b = b >> 6;887			b = clamp_val(b, -31, 31);888 889			tmp_u16 = b43legacy_phy_read(dev, 0x048A) & 0xF000;890			tmp_u16 |= ((u32)b & 0x0000003F);891			tmp_u16 |= (((u32)a & 0x0000003F) << 6);892			b43legacy_phy_write(dev, 0x048A, tmp_u16);893		}894		break;895	default:896		B43legacy_BUG_ON(1);897	}898}899 900/* Stack implementation to save/restore values from the901 * interference mitigation code.902 * It is save to restore values in random order.903 */904static void _stack_save(u32 *_stackptr, size_t *stackidx,905			u8 id, u16 offset, u16 value)906{907	u32 *stackptr = &(_stackptr[*stackidx]);908 909	B43legacy_WARN_ON(!((offset & 0xE000) == 0x0000));910	B43legacy_WARN_ON(!((id & 0xF8) == 0x00));911	*stackptr = offset;912	*stackptr |= ((u32)id) << 13;913	*stackptr |= ((u32)value) << 16;914	(*stackidx)++;915	B43legacy_WARN_ON(!(*stackidx < B43legacy_INTERFSTACK_SIZE));916}917 918static u16 _stack_restore(u32 *stackptr,919			  u8 id, u16 offset)920{921	size_t i;922 923	B43legacy_WARN_ON(!((offset & 0xE000) == 0x0000));924	B43legacy_WARN_ON(!((id & 0xF8) == 0x00));925	for (i = 0; i < B43legacy_INTERFSTACK_SIZE; i++, stackptr++) {926		if ((*stackptr & 0x00001FFF) != offset)927			continue;928		if (((*stackptr & 0x00007000) >> 13) != id)929			continue;930		return ((*stackptr & 0xFFFF0000) >> 16);931	}932	B43legacy_BUG_ON(1);933 934	return 0;935}936 937#define phy_stacksave(offset)					\938	do {							\939		_stack_save(stack, &stackidx, 0x1, (offset),	\940			    b43legacy_phy_read(dev, (offset)));	\941	} while (0)942#define phy_stackrestore(offset)				\943	do {							\944		b43legacy_phy_write(dev, (offset),		\945				    _stack_restore(stack, 0x1,	\946				    (offset)));			\947	} while (0)948#define radio_stacksave(offset)						\949	do {								\950		_stack_save(stack, &stackidx, 0x2, (offset),		\951			    b43legacy_radio_read16(dev, (offset)));	\952	} while (0)953#define radio_stackrestore(offset)					\954	do {								\955		b43legacy_radio_write16(dev, (offset),			\956					_stack_restore(stack, 0x2,	\957					(offset)));			\958	} while (0)959#define ilt_stacksave(offset)					\960	do {							\961		_stack_save(stack, &stackidx, 0x3, (offset),	\962			    b43legacy_ilt_read(dev, (offset)));	\963	} while (0)964#define ilt_stackrestore(offset)				\965	do {							\966		b43legacy_ilt_write(dev, (offset),		\967				  _stack_restore(stack, 0x3,	\968						 (offset)));	\969	} while (0)970 971static void972b43legacy_radio_interference_mitigation_enable(struct b43legacy_wldev *dev,973					       int mode)974{975	struct b43legacy_phy *phy = &dev->phy;976	u16 tmp;977	u16 flipped;978	u32 tmp32;979	size_t stackidx = 0;980	u32 *stack = phy->interfstack;981 982	switch (mode) {983	case B43legacy_RADIO_INTERFMODE_NONWLAN:984		if (phy->rev != 1) {985			b43legacy_phy_write(dev, 0x042B,986					    b43legacy_phy_read(dev, 0x042B)987					    | 0x0800);988			b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,989					    b43legacy_phy_read(dev,990					    B43legacy_PHY_G_CRS) & ~0x4000);991			break;992		}993		radio_stacksave(0x0078);994		tmp = (b43legacy_radio_read16(dev, 0x0078) & 0x001E);995		flipped = flip_4bit(tmp);996		if (flipped < 10 && flipped >= 8)997			flipped = 7;998		else if (flipped >= 10)999			flipped -= 3;1000		flipped = flip_4bit(flipped);1001		flipped = (flipped << 1) | 0x0020;1002		b43legacy_radio_write16(dev, 0x0078, flipped);1003 1004		b43legacy_calc_nrssi_threshold(dev);1005 1006		phy_stacksave(0x0406);1007		b43legacy_phy_write(dev, 0x0406, 0x7E28);1008 1009		b43legacy_phy_write(dev, 0x042B,1010				    b43legacy_phy_read(dev, 0x042B) | 0x0800);1011		b43legacy_phy_write(dev, B43legacy_PHY_RADIO_BITFIELD,1012				    b43legacy_phy_read(dev,1013				    B43legacy_PHY_RADIO_BITFIELD) | 0x1000);1014 1015		phy_stacksave(0x04A0);1016		b43legacy_phy_write(dev, 0x04A0,1017				    (b43legacy_phy_read(dev, 0x04A0) & 0xC0C0)1018				    | 0x0008);1019		phy_stacksave(0x04A1);1020		b43legacy_phy_write(dev, 0x04A1,1021				    (b43legacy_phy_read(dev, 0x04A1) & 0xC0C0)1022				    | 0x0605);1023		phy_stacksave(0x04A2);1024		b43legacy_phy_write(dev, 0x04A2,1025				    (b43legacy_phy_read(dev, 0x04A2) & 0xC0C0)1026				    | 0x0204);1027		phy_stacksave(0x04A8);1028		b43legacy_phy_write(dev, 0x04A8,1029				    (b43legacy_phy_read(dev, 0x04A8) & 0xC0C0)1030				    | 0x0803);1031		phy_stacksave(0x04AB);1032		b43legacy_phy_write(dev, 0x04AB,1033				    (b43legacy_phy_read(dev, 0x04AB) & 0xC0C0)1034				    | 0x0605);1035 1036		phy_stacksave(0x04A7);1037		b43legacy_phy_write(dev, 0x04A7, 0x0002);1038		phy_stacksave(0x04A3);1039		b43legacy_phy_write(dev, 0x04A3, 0x287A);1040		phy_stacksave(0x04A9);1041		b43legacy_phy_write(dev, 0x04A9, 0x2027);1042		phy_stacksave(0x0493);1043		b43legacy_phy_write(dev, 0x0493, 0x32F5);1044		phy_stacksave(0x04AA);1045		b43legacy_phy_write(dev, 0x04AA, 0x2027);1046		phy_stacksave(0x04AC);1047		b43legacy_phy_write(dev, 0x04AC, 0x32F5);1048		break;1049	case B43legacy_RADIO_INTERFMODE_MANUALWLAN:1050		if (b43legacy_phy_read(dev, 0x0033) & 0x0800)1051			break;1052 1053		phy->aci_enable = true;1054 1055		phy_stacksave(B43legacy_PHY_RADIO_BITFIELD);1056		phy_stacksave(B43legacy_PHY_G_CRS);1057		if (phy->rev < 2)1058			phy_stacksave(0x0406);1059		else {1060			phy_stacksave(0x04C0);1061			phy_stacksave(0x04C1);1062		}1063		phy_stacksave(0x0033);1064		phy_stacksave(0x04A7);1065		phy_stacksave(0x04A3);1066		phy_stacksave(0x04A9);1067		phy_stacksave(0x04AA);1068		phy_stacksave(0x04AC);1069		phy_stacksave(0x0493);1070		phy_stacksave(0x04A1);1071		phy_stacksave(0x04A0);1072		phy_stacksave(0x04A2);1073		phy_stacksave(0x048A);1074		phy_stacksave(0x04A8);1075		phy_stacksave(0x04AB);1076		if (phy->rev == 2) {1077			phy_stacksave(0x04AD);1078			phy_stacksave(0x04AE);1079		} else if (phy->rev >= 3) {1080			phy_stacksave(0x04AD);1081			phy_stacksave(0x0415);1082			phy_stacksave(0x0416);1083			phy_stacksave(0x0417);1084			ilt_stacksave(0x1A00 + 0x2);1085			ilt_stacksave(0x1A00 + 0x3);1086		}1087		phy_stacksave(0x042B);1088		phy_stacksave(0x048C);1089 1090		b43legacy_phy_write(dev, B43legacy_PHY_RADIO_BITFIELD,1091				    b43legacy_phy_read(dev,1092				    B43legacy_PHY_RADIO_BITFIELD) & ~0x1000);1093		b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,1094				    (b43legacy_phy_read(dev,1095				    B43legacy_PHY_G_CRS)1096				    & 0xFFFC) | 0x0002);1097 1098		b43legacy_phy_write(dev, 0x0033, 0x0800);1099		b43legacy_phy_write(dev, 0x04A3, 0x2027);1100		b43legacy_phy_write(dev, 0x04A9, 0x1CA8);1101		b43legacy_phy_write(dev, 0x0493, 0x287A);1102		b43legacy_phy_write(dev, 0x04AA, 0x1CA8);1103		b43legacy_phy_write(dev, 0x04AC, 0x287A);1104 1105		b43legacy_phy_write(dev, 0x04A0,1106				    (b43legacy_phy_read(dev, 0x04A0)1107				    & 0xFFC0) | 0x001A);1108		b43legacy_phy_write(dev, 0x04A7, 0x000D);1109 1110		if (phy->rev < 2)1111			b43legacy_phy_write(dev, 0x0406, 0xFF0D);1112		else if (phy->rev == 2) {1113			b43legacy_phy_write(dev, 0x04C0, 0xFFFF);1114			b43legacy_phy_write(dev, 0x04C1, 0x00A9);1115		} else {1116			b43legacy_phy_write(dev, 0x04C0, 0x00C1);1117			b43legacy_phy_write(dev, 0x04C1, 0x0059);1118		}1119 1120		b43legacy_phy_write(dev, 0x04A1,1121				    (b43legacy_phy_read(dev, 0x04A1)1122				    & 0xC0FF) | 0x1800);1123		b43legacy_phy_write(dev, 0x04A1,1124				    (b43legacy_phy_read(dev, 0x04A1)1125				    & 0xFFC0) | 0x0015);1126		b43legacy_phy_write(dev, 0x04A8,1127				    (b43legacy_phy_read(dev, 0x04A8)1128				    & 0xCFFF) | 0x1000);1129		b43legacy_phy_write(dev, 0x04A8,1130				    (b43legacy_phy_read(dev, 0x04A8)1131				    & 0xF0FF) | 0x0A00);1132		b43legacy_phy_write(dev, 0x04AB,1133				    (b43legacy_phy_read(dev, 0x04AB)1134				    & 0xCFFF) | 0x1000);1135		b43legacy_phy_write(dev, 0x04AB,1136				    (b43legacy_phy_read(dev, 0x04AB)1137				    & 0xF0FF) | 0x0800);1138		b43legacy_phy_write(dev, 0x04AB,1139				    (b43legacy_phy_read(dev, 0x04AB)1140				    & 0xFFCF) | 0x0010);1141		b43legacy_phy_write(dev, 0x04AB,1142				    (b43legacy_phy_read(dev, 0x04AB)1143				    & 0xFFF0) | 0x0005);1144		b43legacy_phy_write(dev, 0x04A8,1145				    (b43legacy_phy_read(dev, 0x04A8)1146				    & 0xFFCF) | 0x0010);1147		b43legacy_phy_write(dev, 0x04A8,1148				    (b43legacy_phy_read(dev, 0x04A8)1149				    & 0xFFF0) | 0x0006);1150		b43legacy_phy_write(dev, 0x04A2,1151				    (b43legacy_phy_read(dev, 0x04A2)1152				    & 0xF0FF) | 0x0800);1153		b43legacy_phy_write(dev, 0x04A0,1154				    (b43legacy_phy_read(dev, 0x04A0)1155				    & 0xF0FF) | 0x0500);1156		b43legacy_phy_write(dev, 0x04A2,1157				    (b43legacy_phy_read(dev, 0x04A2)1158				    & 0xFFF0) | 0x000B);1159 1160		if (phy->rev >= 3) {1161			b43legacy_phy_write(dev, 0x048A,1162					    b43legacy_phy_read(dev, 0x048A)1163					    & ~0x8000);1164			b43legacy_phy_write(dev, 0x0415,1165					    (b43legacy_phy_read(dev, 0x0415)1166					    & 0x8000) | 0x36D8);1167			b43legacy_phy_write(dev, 0x0416,1168					    (b43legacy_phy_read(dev, 0x0416)1169					    & 0x8000) | 0x36D8);1170			b43legacy_phy_write(dev, 0x0417,1171					    (b43legacy_phy_read(dev, 0x0417)1172					    & 0xFE00) | 0x016D);1173		} else {1174			b43legacy_phy_write(dev, 0x048A,1175					    b43legacy_phy_read(dev, 0x048A)1176					    | 0x1000);1177			b43legacy_phy_write(dev, 0x048A,1178					    (b43legacy_phy_read(dev, 0x048A)1179					    & 0x9FFF) | 0x2000);1180			tmp32 = b43legacy_shm_read32(dev, B43legacy_SHM_SHARED,1181					    B43legacy_UCODEFLAGS_OFFSET);1182			if (!(tmp32 & 0x800)) {1183				tmp32 |= 0x800;1184				b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,1185					    B43legacy_UCODEFLAGS_OFFSET,1186					    tmp32);1187			}1188		}1189		if (phy->rev >= 2)1190			b43legacy_phy_write(dev, 0x042B,1191					    b43legacy_phy_read(dev, 0x042B)1192					    | 0x0800);1193		b43legacy_phy_write(dev, 0x048C,1194				    (b43legacy_phy_read(dev, 0x048C)1195				    & 0xF0FF) | 0x0200);1196		if (phy->rev == 2) {1197			b43legacy_phy_write(dev, 0x04AE,1198					    (b43legacy_phy_read(dev, 0x04AE)1199					    & 0xFF00) | 0x007F);1200			b43legacy_phy_write(dev, 0x04AD,1201					    (b43legacy_phy_read(dev, 0x04AD)1202					    & 0x00FF) | 0x1300);1203		} else if (phy->rev >= 6) {1204			b43legacy_ilt_write(dev, 0x1A00 + 0x3, 0x007F);1205			b43legacy_ilt_write(dev, 0x1A00 + 0x2, 0x007F);1206			b43legacy_phy_write(dev, 0x04AD,1207					    b43legacy_phy_read(dev, 0x04AD)1208					    & 0x00FF);1209		}1210		b43legacy_calc_nrssi_slope(dev);1211		break;1212	default:1213		B43legacy_BUG_ON(1);1214	}1215}1216 1217static void1218b43legacy_radio_interference_mitigation_disable(struct b43legacy_wldev *dev,1219						int mode)1220{1221	struct b43legacy_phy *phy = &dev->phy;1222	u32 tmp32;1223	u32 *stack = phy->interfstack;1224 1225	switch (mode) {1226	case B43legacy_RADIO_INTERFMODE_NONWLAN:1227		if (phy->rev != 1) {1228			b43legacy_phy_write(dev, 0x042B,1229					    b43legacy_phy_read(dev, 0x042B)1230					    & ~0x0800);1231			b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,1232					    b43legacy_phy_read(dev,1233					    B43legacy_PHY_G_CRS) | 0x4000);1234			break;1235		}1236		phy_stackrestore(0x0078);1237		b43legacy_calc_nrssi_threshold(dev);1238		phy_stackrestore(0x0406);1239		b43legacy_phy_write(dev, 0x042B,1240				    b43legacy_phy_read(dev, 0x042B) & ~0x0800);1241		if (!dev->bad_frames_preempt)1242			b43legacy_phy_write(dev, B43legacy_PHY_RADIO_BITFIELD,1243					    b43legacy_phy_read(dev,1244					    B43legacy_PHY_RADIO_BITFIELD)1245					    & ~(1 << 11));1246		b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,1247				    b43legacy_phy_read(dev, B43legacy_PHY_G_CRS)1248				    | 0x4000);1249		phy_stackrestore(0x04A0);1250		phy_stackrestore(0x04A1);1251		phy_stackrestore(0x04A2);1252		phy_stackrestore(0x04A8);1253		phy_stackrestore(0x04AB);1254		phy_stackrestore(0x04A7);1255		phy_stackrestore(0x04A3);1256		phy_stackrestore(0x04A9);1257		phy_stackrestore(0x0493);1258		phy_stackrestore(0x04AA);1259		phy_stackrestore(0x04AC);1260		break;1261	case B43legacy_RADIO_INTERFMODE_MANUALWLAN:1262		if (!(b43legacy_phy_read(dev, 0x0033) & 0x0800))1263			break;1264 1265		phy->aci_enable = false;1266 1267		phy_stackrestore(B43legacy_PHY_RADIO_BITFIELD);1268		phy_stackrestore(B43legacy_PHY_G_CRS);1269		phy_stackrestore(0x0033);1270		phy_stackrestore(0x04A3);1271		phy_stackrestore(0x04A9);1272		phy_stackrestore(0x0493);1273		phy_stackrestore(0x04AA);1274		phy_stackrestore(0x04AC);1275		phy_stackrestore(0x04A0);1276		phy_stackrestore(0x04A7);1277		if (phy->rev >= 2) {1278			phy_stackrestore(0x04C0);1279			phy_stackrestore(0x04C1);1280		} else1281			phy_stackrestore(0x0406);1282		phy_stackrestore(0x04A1);1283		phy_stackrestore(0x04AB);1284		phy_stackrestore(0x04A8);1285		if (phy->rev == 2) {1286			phy_stackrestore(0x04AD);1287			phy_stackrestore(0x04AE);1288		} else if (phy->rev >= 3) {1289			phy_stackrestore(0x04AD);1290			phy_stackrestore(0x0415);1291			phy_stackrestore(0x0416);1292			phy_stackrestore(0x0417);1293			ilt_stackrestore(0x1A00 + 0x2);1294			ilt_stackrestore(0x1A00 + 0x3);1295		}1296		phy_stackrestore(0x04A2);1297		phy_stackrestore(0x04A8);1298		phy_stackrestore(0x042B);1299		phy_stackrestore(0x048C);1300		tmp32 = b43legacy_shm_read32(dev, B43legacy_SHM_SHARED,1301					     B43legacy_UCODEFLAGS_OFFSET);1302		if (tmp32 & 0x800) {1303			tmp32 &= ~0x800;1304			b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,1305					      B43legacy_UCODEFLAGS_OFFSET,1306					      tmp32);1307		}1308		b43legacy_calc_nrssi_slope(dev);1309		break;1310	default:1311		B43legacy_BUG_ON(1);1312	}1313}1314 1315#undef phy_stacksave1316#undef phy_stackrestore1317#undef radio_stacksave1318#undef radio_stackrestore1319#undef ilt_stacksave1320#undef ilt_stackrestore1321 1322int b43legacy_radio_set_interference_mitigation(struct b43legacy_wldev *dev,1323						int mode)1324{1325	struct b43legacy_phy *phy = &dev->phy;1326	int currentmode;1327 1328	if ((phy->type != B43legacy_PHYTYPE_G) ||1329	    (phy->rev == 0) || (!phy->gmode))1330		return -ENODEV;1331 1332	phy->aci_wlan_automatic = false;1333	switch (mode) {1334	case B43legacy_RADIO_INTERFMODE_AUTOWLAN:1335		phy->aci_wlan_automatic = true;1336		if (phy->aci_enable)1337			mode = B43legacy_RADIO_INTERFMODE_MANUALWLAN;1338		else1339			mode = B43legacy_RADIO_INTERFMODE_NONE;1340		break;1341	case B43legacy_RADIO_INTERFMODE_NONE:1342	case B43legacy_RADIO_INTERFMODE_NONWLAN:1343	case B43legacy_RADIO_INTERFMODE_MANUALWLAN:1344		break;1345	default:1346		return -EINVAL;1347	}1348 1349	currentmode = phy->interfmode;1350	if (currentmode == mode)1351		return 0;1352	if (currentmode != B43legacy_RADIO_INTERFMODE_NONE)1353		b43legacy_radio_interference_mitigation_disable(dev,1354								currentmode);1355 1356	if (mode == B43legacy_RADIO_INTERFMODE_NONE) {1357		phy->aci_enable = false;1358		phy->aci_hw_rssi = false;1359	} else1360		b43legacy_radio_interference_mitigation_enable(dev, mode);1361	phy->interfmode = mode;1362 1363	return 0;1364}1365 1366u16 b43legacy_radio_calibrationvalue(struct b43legacy_wldev *dev)1367{1368	u16 reg;1369	u16 index;1370	u16 ret;1371 1372	reg = b43legacy_radio_read16(dev, 0x0060);1373	index = (reg & 0x001E) >> 1;1374	ret = rcc_table[index] << 1;1375	ret |= (reg & 0x0001);1376	ret |= 0x0020;1377 1378	return ret;1379}1380 1381#define LPD(L, P, D)    (((L) << 2) | ((P) << 1) | ((D) << 0))1382static u16 b43legacy_get_812_value(struct b43legacy_wldev *dev, u8 lpd)1383{1384	struct b43legacy_phy *phy = &dev->phy;1385	u16 loop_or = 0;1386	u16 adj_loopback_gain = phy->loopback_gain[0];1387	u8 loop;1388	u16 extern_lna_control;1389 1390	if (!phy->gmode)1391		return 0;1392	if (!has_loopback_gain(phy)) {1393		if (phy->rev < 7 || !(dev->dev->bus->sprom.boardflags_lo1394		    & B43legacy_BFL_EXTLNA)) {1395			switch (lpd) {1396			case LPD(0, 1, 1):1397				return 0x0FB2;1398			case LPD(0, 0, 1):1399				return 0x00B2;1400			case LPD(1, 0, 1):1401				return 0x30B2;1402			case LPD(1, 0, 0):1403				return 0x30B3;1404			default:1405				B43legacy_BUG_ON(1);1406			}1407		} else {1408			switch (lpd) {1409			case LPD(0, 1, 1):1410				return 0x8FB2;1411			case LPD(0, 0, 1):1412				return 0x80B2;1413			case LPD(1, 0, 1):1414				return 0x20B2;1415			case LPD(1, 0, 0):1416				return 0x20B3;1417			default:1418				B43legacy_BUG_ON(1);1419			}1420		}1421	} else {1422		if (phy->radio_rev == 8)1423			adj_loopback_gain += 0x003E;1424		else1425			adj_loopback_gain += 0x0026;1426		if (adj_loopback_gain >= 0x46) {1427			adj_loopback_gain -= 0x46;1428			extern_lna_control = 0x3000;1429		} else if (adj_loopback_gain >= 0x3A) {1430			adj_loopback_gain -= 0x3A;1431			extern_lna_control = 0x2000;1432		} else if (adj_loopback_gain >= 0x2E) {1433			adj_loopback_gain -= 0x2E;1434			extern_lna_control = 0x1000;1435		} else {1436			adj_loopback_gain -= 0x10;1437			extern_lna_control = 0x0000;1438		}1439		for (loop = 0; loop < 16; loop++) {1440			u16 tmp = adj_loopback_gain - 6 * loop;1441			if (tmp < 6)1442				break;1443		}1444 1445		loop_or = (loop << 8) | extern_lna_control;1446		if (phy->rev >= 7 && dev->dev->bus->sprom.boardflags_lo1447		    & B43legacy_BFL_EXTLNA) {1448			if (extern_lna_control)1449				loop_or |= 0x8000;1450			switch (lpd) {1451			case LPD(0, 1, 1):1452				return 0x8F92;1453			case LPD(0, 0, 1):1454				return (0x8092 | loop_or);1455			case LPD(1, 0, 1):1456				return (0x2092 | loop_or);1457			case LPD(1, 0, 0):1458				return (0x2093 | loop_or);1459			default:1460				B43legacy_BUG_ON(1);1461			}1462		} else {1463			switch (lpd) {1464			case LPD(0, 1, 1):1465				return 0x0F92;1466			case LPD(0, 0, 1):1467			case LPD(1, 0, 1):1468				return (0x0092 | loop_or);1469			case LPD(1, 0, 0):1470				return (0x0093 | loop_or);1471			default:1472				B43legacy_BUG_ON(1);1473			}1474		}1475	}1476	return 0;1477}1478 1479u16 b43legacy_radio_init2050(struct b43legacy_wldev *dev)1480{1481	struct b43legacy_phy *phy = &dev->phy;1482	u16 backup[21] = { 0 };1483	u16 ret;1484	u16 i;1485	u16 j;1486	u32 tmp1 = 0;1487	u32 tmp2 = 0;1488 1489	backup[0] = b43legacy_radio_read16(dev, 0x0043);1490	backup[14] = b43legacy_radio_read16(dev, 0x0051);1491	backup[15] = b43legacy_radio_read16(dev, 0x0052);1492	backup[1] = b43legacy_phy_read(dev, 0x0015);1493	backup[16] = b43legacy_phy_read(dev, 0x005A);1494	backup[17] = b43legacy_phy_read(dev, 0x0059);1495	backup[18] = b43legacy_phy_read(dev, 0x0058);1496	if (phy->type == B43legacy_PHYTYPE_B) {1497		backup[2] = b43legacy_phy_read(dev, 0x0030);1498		backup[3] = b43legacy_read16(dev, 0x03EC);1499		b43legacy_phy_write(dev, 0x0030, 0x00FF);1500		b43legacy_write16(dev, 0x03EC, 0x3F3F);1501	} else {1502		if (phy->gmode) {1503			backup[4] = b43legacy_phy_read(dev, 0x0811);1504			backup[5] = b43legacy_phy_read(dev, 0x0812);1505			backup[6] = b43legacy_phy_read(dev, 0x0814);1506			backup[7] = b43legacy_phy_read(dev, 0x0815);1507			backup[8] = b43legacy_phy_read(dev,1508						       B43legacy_PHY_G_CRS);1509			backup[9] = b43legacy_phy_read(dev, 0x0802);1510			b43legacy_phy_write(dev, 0x0814,1511					    (b43legacy_phy_read(dev, 0x0814)1512					    | 0x0003));1513			b43legacy_phy_write(dev, 0x0815,1514					    (b43legacy_phy_read(dev, 0x0815)1515					    & 0xFFFC));1516			b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,1517					    (b43legacy_phy_read(dev,1518					    B43legacy_PHY_G_CRS) & 0x7FFF));1519			b43legacy_phy_write(dev, 0x0802,1520					    (b43legacy_phy_read(dev, 0x0802)1521					    & 0xFFFC));1522			if (phy->rev > 1) { /* loopback gain enabled */1523				backup[19] = b43legacy_phy_read(dev, 0x080F);1524				backup[20] = b43legacy_phy_read(dev, 0x0810);1525				if (phy->rev >= 3)1526					b43legacy_phy_write(dev, 0x080F,1527							    0xC020);1528				else1529					b43legacy_phy_write(dev, 0x080F,1530							    0x8020);1531				b43legacy_phy_write(dev, 0x0810, 0x0000);1532			}1533			b43legacy_phy_write(dev, 0x0812,1534					    b43legacy_get_812_value(dev,1535					    LPD(0, 1, 1)));1536			if (phy->rev < 7 ||1537			    !(dev->dev->bus->sprom.boardflags_lo1538			    & B43legacy_BFL_EXTLNA))1539				b43legacy_phy_write(dev, 0x0811, 0x01B3);1540			else1541				b43legacy_phy_write(dev, 0x0811, 0x09B3);1542		}1543	}1544	b43legacy_write16(dev, B43legacy_MMIO_PHY_RADIO,1545			(b43legacy_read16(dev, B43legacy_MMIO_PHY_RADIO)1546					  | 0x8000));1547	backup[10] = b43legacy_phy_read(dev, 0x0035);1548	b43legacy_phy_write(dev, 0x0035,1549			    (b43legacy_phy_read(dev, 0x0035) & 0xFF7F));1550	backup[11] = b43legacy_read16(dev, 0x03E6);1551	backup[12] = b43legacy_read16(dev, B43legacy_MMIO_CHANNEL_EXT);1552 1553	/* Initialization */1554	if (phy->analog == 0)1555		b43legacy_write16(dev, 0x03E6, 0x0122);1556	else {1557		if (phy->analog >= 2)1558			b43legacy_phy_write(dev, 0x0003,1559					    (b43legacy_phy_read(dev, 0x0003)1560					    & 0xFFBF) | 0x0040);1561		b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT,1562				  (b43legacy_read16(dev,1563				  B43legacy_MMIO_CHANNEL_EXT) | 0x2000));1564	}1565 1566	ret = b43legacy_radio_calibrationvalue(dev);1567 1568	if (phy->type == B43legacy_PHYTYPE_B)1569		b43legacy_radio_write16(dev, 0x0078, 0x0026);1570 1571	if (phy->gmode)1572		b43legacy_phy_write(dev, 0x0812,1573				    b43legacy_get_812_value(dev,1574				    LPD(0, 1, 1)));1575	b43legacy_phy_write(dev, 0x0015, 0xBFAF);1576	b43legacy_phy_write(dev, 0x002B, 0x1403);1577	if (phy->gmode)1578		b43legacy_phy_write(dev, 0x0812,1579				    b43legacy_get_812_value(dev,1580				    LPD(0, 0, 1)));1581	b43legacy_phy_write(dev, 0x0015, 0xBFA0);1582	b43legacy_radio_write16(dev, 0x0051,1583				(b43legacy_radio_read16(dev, 0x0051)1584				| 0x0004));1585	if (phy->radio_rev == 8)1586		b43legacy_radio_write16(dev, 0x0043, 0x001F);1587	else {1588		b43legacy_radio_write16(dev, 0x0052, 0x0000);1589		b43legacy_radio_write16(dev, 0x0043,1590					(b43legacy_radio_read16(dev, 0x0043)1591					& 0xFFF0) | 0x0009);1592	}1593	b43legacy_phy_write(dev, 0x0058, 0x0000);1594 1595	for (i = 0; i < 16; i++) {1596		b43legacy_phy_write(dev, 0x005A, 0x0480);1597		b43legacy_phy_write(dev, 0x0059, 0xC810);1598		b43legacy_phy_write(dev, 0x0058, 0x000D);1599		if (phy->gmode)1600			b43legacy_phy_write(dev, 0x0812,1601					    b43legacy_get_812_value(dev,1602					    LPD(1, 0, 1)));1603		b43legacy_phy_write(dev, 0x0015, 0xAFB0);1604		udelay(10);1605		if (phy->gmode)1606			b43legacy_phy_write(dev, 0x0812,1607					    b43legacy_get_812_value(dev,1608					    LPD(1, 0, 1)));1609		b43legacy_phy_write(dev, 0x0015, 0xEFB0);1610		udelay(10);1611		if (phy->gmode)1612			b43legacy_phy_write(dev, 0x0812,1613					    b43legacy_get_812_value(dev,1614					    LPD(1, 0, 0)));1615		b43legacy_phy_write(dev, 0x0015, 0xFFF0);1616		udelay(20);1617		tmp1 += b43legacy_phy_read(dev, 0x002D);1618		b43legacy_phy_write(dev, 0x0058, 0x0000);1619		if (phy->gmode)1620			b43legacy_phy_write(dev, 0x0812,1621					    b43legacy_get_812_value(dev,1622					    LPD(1, 0, 1)));1623		b43legacy_phy_write(dev, 0x0015, 0xAFB0);1624	}1625 1626	tmp1++;1627	tmp1 >>= 9;1628	udelay(10);1629	b43legacy_phy_write(dev, 0x0058, 0x0000);1630 1631	for (i = 0; i < 16; i++) {1632		b43legacy_radio_write16(dev, 0x0078, (flip_4bit(i) << 1)1633					| 0x0020);1634		backup[13] = b43legacy_radio_read16(dev, 0x0078);1635		udelay(10);1636		for (j = 0; j < 16; j++) {1637			b43legacy_phy_write(dev, 0x005A, 0x0D80);1638			b43legacy_phy_write(dev, 0x0059, 0xC810);1639			b43legacy_phy_write(dev, 0x0058, 0x000D);1640			if (phy->gmode)1641				b43legacy_phy_write(dev, 0x0812,1642						    b43legacy_get_812_value(dev,1643						    LPD(1, 0, 1)));1644			b43legacy_phy_write(dev, 0x0015, 0xAFB0);1645			udelay(10);1646			if (phy->gmode)1647				b43legacy_phy_write(dev, 0x0812,1648						    b43legacy_get_812_value(dev,1649						    LPD(1, 0, 1)));1650			b43legacy_phy_write(dev, 0x0015, 0xEFB0);1651			udelay(10);1652			if (phy->gmode)1653				b43legacy_phy_write(dev, 0x0812,1654						    b43legacy_get_812_value(dev,1655						    LPD(1, 0, 0)));1656			b43legacy_phy_write(dev, 0x0015, 0xFFF0);1657			udelay(10);1658			tmp2 += b43legacy_phy_read(dev, 0x002D);1659			b43legacy_phy_write(dev, 0x0058, 0x0000);1660			if (phy->gmode)1661				b43legacy_phy_write(dev, 0x0812,1662						    b43legacy_get_812_value(dev,1663						    LPD(1, 0, 1)));1664			b43legacy_phy_write(dev, 0x0015, 0xAFB0);1665		}1666		tmp2++;1667		tmp2 >>= 8;1668		if (tmp1 < tmp2)1669			break;1670	}1671 1672	/* Restore the registers */1673	b43legacy_phy_write(dev, 0x0015, backup[1]);1674	b43legacy_radio_write16(dev, 0x0051, backup[14]);1675	b43legacy_radio_write16(dev, 0x0052, backup[15]);1676	b43legacy_radio_write16(dev, 0x0043, backup[0]);1677	b43legacy_phy_write(dev, 0x005A, backup[16]);1678	b43legacy_phy_write(dev, 0x0059, backup[17]);1679	b43legacy_phy_write(dev, 0x0058, backup[18]);1680	b43legacy_write16(dev, 0x03E6, backup[11]);1681	if (phy->analog != 0)1682		b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, backup[12]);1683	b43legacy_phy_write(dev, 0x0035, backup[10]);1684	b43legacy_radio_selectchannel(dev, phy->channel, 1);1685	if (phy->type == B43legacy_PHYTYPE_B) {1686		b43legacy_phy_write(dev, 0x0030, backup[2]);1687		b43legacy_write16(dev, 0x03EC, backup[3]);1688	} else {1689		if (phy->gmode) {1690			b43legacy_write16(dev, B43legacy_MMIO_PHY_RADIO,1691					  (b43legacy_read16(dev,1692					  B43legacy_MMIO_PHY_RADIO) & 0x7FFF));1693			b43legacy_phy_write(dev, 0x0811, backup[4]);1694			b43legacy_phy_write(dev, 0x0812, backup[5]);1695			b43legacy_phy_write(dev, 0x0814, backup[6]);1696			b43legacy_phy_write(dev, 0x0815, backup[7]);1697			b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,1698					    backup[8]);1699			b43legacy_phy_write(dev, 0x0802, backup[9]);1700			if (phy->rev > 1) {1701				b43legacy_phy_write(dev, 0x080F, backup[19]);1702				b43legacy_phy_write(dev, 0x0810, backup[20]);1703			}1704		}1705	}1706	if (i >= 15)1707		ret = backup[13];1708 1709	return ret;1710}1711 1712int b43legacy_radio_selectchannel(struct b43legacy_wldev *dev,1713				  u8 channel,1714				  int synthetic_pu_workaround)1715{1716	struct b43legacy_phy *phy = &dev->phy;1717 1718	if (channel == 0xFF) {1719		switch (phy->type) {1720		case B43legacy_PHYTYPE_B:1721		case B43legacy_PHYTYPE_G:1722			channel = B43legacy_RADIO_DEFAULT_CHANNEL_BG;1723			break;1724		default:1725			B43legacy_WARN_ON(1);1726		}1727	}1728 1729/* TODO: Check if channel is valid - return -EINVAL if not */1730	if (synthetic_pu_workaround)1731		b43legacy_synth_pu_workaround(dev, channel);1732 1733	b43legacy_write16(dev, B43legacy_MMIO_CHANNEL,1734			  channel2freq_bg(channel));1735 1736	if (channel == 14) {1737		if (dev->dev->bus->sprom.country_code == 5)   /* JAPAN) */1738			b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,1739					      B43legacy_UCODEFLAGS_OFFSET,1740					      b43legacy_shm_read32(dev,1741					      B43legacy_SHM_SHARED,1742					      B43legacy_UCODEFLAGS_OFFSET)1743					      & ~(1 << 7));1744		else1745			b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,1746					      B43legacy_UCODEFLAGS_OFFSET,1747					      b43legacy_shm_read32(dev,1748					      B43legacy_SHM_SHARED,1749					      B43legacy_UCODEFLAGS_OFFSET)1750					      | (1 << 7));1751		b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT,1752				  b43legacy_read16(dev,1753				  B43legacy_MMIO_CHANNEL_EXT) | (1 << 11));1754	} else1755		b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT,1756				  b43legacy_read16(dev,1757				  B43legacy_MMIO_CHANNEL_EXT) & 0xF7BF);1758 1759	phy->channel = channel;1760	/*XXX: Using the longer of 2 timeouts (8000 vs 2000 usecs). Specs states1761	 *     that 2000 usecs might suffice. */1762	msleep(8);1763 1764	return 0;1765}1766 1767void b43legacy_radio_set_txantenna(struct b43legacy_wldev *dev, u32 val)1768{1769	u16 tmp;1770 1771	val <<= 8;1772	tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x0022) & 0xFCFF;1773	b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0022, tmp | val);1774	tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x03A8) & 0xFCFF;1775	b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x03A8, tmp | val);1776	tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x0054) & 0xFCFF;1777	b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0054, tmp | val);1778}1779 1780/* http://bcm-specs.sipsolutions.net/TX_Gain_Base_Band */1781static u16 b43legacy_get_txgain_base_band(u16 txpower)1782{1783	u16 ret;1784 1785	B43legacy_WARN_ON(txpower > 63);1786 1787	if (txpower >= 54)1788		ret = 2;1789	else if (txpower >= 49)1790		ret = 4;1791	else if (txpower >= 44)1792		ret = 5;1793	else1794		ret = 6;1795 1796	return ret;1797}1798 1799/* http://bcm-specs.sipsolutions.net/TX_Gain_Radio_Frequency_Power_Amplifier */1800static u16 b43legacy_get_txgain_freq_power_amp(u16 txpower)1801{1802	u16 ret;1803 1804	B43legacy_WARN_ON(txpower > 63);1805 1806	if (txpower >= 32)1807		ret = 0;1808	else if (txpower >= 25)1809		ret = 1;1810	else if (txpower >= 20)1811		ret = 2;1812	else if (txpower >= 12)1813		ret = 3;1814	else1815		ret = 4;1816 1817	return ret;1818}1819 1820/* http://bcm-specs.sipsolutions.net/TX_Gain_Digital_Analog_Converter */1821static u16 b43legacy_get_txgain_dac(u16 txpower)1822{1823	u16 ret;1824 1825	B43legacy_WARN_ON(txpower > 63);1826 1827	if (txpower >= 54)1828		ret = txpower - 53;1829	else if (txpower >= 49)1830		ret = txpower - 42;1831	else if (txpower >= 44)1832		ret = txpower - 37;1833	else if (txpower >= 32)1834		ret = txpower - 32;1835	else if (txpower >= 25)1836		ret = txpower - 20;1837	else if (txpower >= 20)1838		ret = txpower - 13;1839	else if (txpower >= 12)1840		ret = txpower - 8;1841	else1842		ret = txpower;1843 1844	return ret;1845}1846 1847void b43legacy_radio_set_txpower_a(struct b43legacy_wldev *dev, u16 txpower)1848{1849	struct b43legacy_phy *phy = &dev->phy;1850	u16 pamp;1851	u16 base;1852	u16 dac;1853	u16 ilt;1854 1855	txpower = clamp_val(txpower, 0, 63);1856 1857	pamp = b43legacy_get_txgain_freq_power_amp(txpower);1858	pamp <<= 5;1859	pamp &= 0x00E0;1860	b43legacy_phy_write(dev, 0x0019, pamp);1861 1862	base = b43legacy_get_txgain_base_band(txpower);1863	base &= 0x000F;1864	b43legacy_phy_write(dev, 0x0017, base | 0x0020);1865 1866	ilt = b43legacy_ilt_read(dev, 0x3001);1867	ilt &= 0x0007;1868 1869	dac = b43legacy_get_txgain_dac(txpower);1870	dac <<= 3;1871	dac |= ilt;1872 1873	b43legacy_ilt_write(dev, 0x3001, dac);1874 1875	phy->txpwr_offset = txpower;1876 1877	/* TODO: FuncPlaceholder (Adjust BB loft cancel) */1878}1879 1880void b43legacy_radio_set_txpower_bg(struct b43legacy_wldev *dev,1881				    u16 baseband_attenuation,1882				    u16 radio_attenuation,1883				    u16 txpower)1884{1885	struct b43legacy_phy *phy = &dev->phy;1886 1887	if (baseband_attenuation == 0xFFFF)1888		baseband_attenuation = phy->bbatt;1889	if (radio_attenuation == 0xFFFF)1890		radio_attenuation = phy->rfatt;1891	if (txpower == 0xFFFF)1892		txpower = phy->txctl1;1893	phy->bbatt = baseband_attenuation;1894	phy->rfatt = radio_attenuation;1895	phy->txctl1 = txpower;1896 1897	B43legacy_WARN_ON(baseband_attenuation > 11);1898	if (phy->radio_rev < 6)1899		B43legacy_WARN_ON(radio_attenuation > 9);1900	else1901		B43legacy_WARN_ON(radio_attenuation > 31);1902	B43legacy_WARN_ON(txpower > 7);1903 1904	b43legacy_phy_set_baseband_attenuation(dev, baseband_attenuation);1905	b43legacy_radio_write16(dev, 0x0043, radio_attenuation);1906	b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0064,1907			      radio_attenuation);1908	if (phy->radio_ver == 0x2050)1909		b43legacy_radio_write16(dev, 0x0052,1910					(b43legacy_radio_read16(dev, 0x0052)1911					& ~0x0070) | ((txpower << 4) & 0x0070));1912	/* FIXME: The spec is very weird and unclear here. */1913	if (phy->type == B43legacy_PHYTYPE_G)1914		b43legacy_phy_lo_adjust(dev, 0);1915}1916 1917u16 b43legacy_default_baseband_attenuation(struct b43legacy_wldev *dev)1918{1919	struct b43legacy_phy *phy = &dev->phy;1920 1921	if (phy->radio_ver == 0x2050 && phy->radio_rev < 6)1922		return 0;1923	return 2;1924}1925 1926u16 b43legacy_default_radio_attenuation(struct b43legacy_wldev *dev)1927{1928	struct b43legacy_phy *phy = &dev->phy;1929	u16 att = 0xFFFF;1930 1931	switch (phy->radio_ver) {1932	case 0x2053:1933		switch (phy->radio_rev) {1934		case 1:1935			att = 6;1936			break;1937		}1938		break;1939	case 0x2050:1940		switch (phy->radio_rev) {1941		case 0:1942			att = 5;1943			break;1944		case 1:1945			if (phy->type == B43legacy_PHYTYPE_G) {1946				if (is_bcm_board_vendor(dev) &&1947				    dev->dev->bus->boardinfo.type == 0x421 &&1948				    dev->dev->bus->sprom.board_rev >= 30)1949					att = 3;1950				else if (is_bcm_board_vendor(dev) &&1951					 dev->dev->bus->boardinfo.type == 0x416)1952					att = 3;1953				else1954					att = 1;1955			} else {1956				if (is_bcm_board_vendor(dev) &&1957				    dev->dev->bus->boardinfo.type == 0x421 &&1958				    dev->dev->bus->sprom.board_rev >= 30)1959					att = 7;1960				else1961					att = 6;1962			}1963			break;1964		case 2:1965			if (phy->type == B43legacy_PHYTYPE_G) {1966				if (is_bcm_board_vendor(dev) &&1967				    dev->dev->bus->boardinfo.type == 0x421 &&1968				    dev->dev->bus->sprom.board_rev >= 30)1969					att = 3;1970				else if (is_bcm_board_vendor(dev) &&1971					 dev->dev->bus->boardinfo.type ==1972					 0x416)1973					att = 5;1974				else if (dev->dev->bus->chip_id == 0x4320)1975					att = 4;1976				else1977					att = 3;1978			} else1979				att = 6;1980			break;1981		case 3:1982			att = 5;1983			break;1984		case 4:1985		case 5:1986			att = 1;1987			break;1988		case 6:1989		case 7:1990			att = 5;1991			break;1992		case 8:1993			att = 0x1A;1994			break;1995		case 9:1996		default:1997			att = 5;1998		}1999	}2000	if (is_bcm_board_vendor(dev) &&2001	    dev->dev->bus->boardinfo.type == 0x421) {2002		if (dev->dev->bus->sprom.board_rev < 0x43)2003			att = 2;2004		else if (dev->dev->bus->sprom.board_rev < 0x51)2005			att = 3;2006	}2007	if (att == 0xFFFF)2008		att = 5;2009 2010	return att;2011}2012 2013u16 b43legacy_default_txctl1(struct b43legacy_wldev *dev)2014{2015	struct b43legacy_phy *phy = &dev->phy;2016 2017	if (phy->radio_ver != 0x2050)2018		return 0;2019	if (phy->radio_rev == 1)2020		return 3;2021	if (phy->radio_rev < 6)2022		return 2;2023	if (phy->radio_rev == 8)2024		return 1;2025	return 0;2026}2027 2028void b43legacy_radio_turn_on(struct b43legacy_wldev *dev)2029{2030	struct b43legacy_phy *phy = &dev->phy;2031	int err;2032	u8 channel;2033 2034	might_sleep();2035 2036	if (phy->radio_on)2037		return;2038 2039	switch (phy->type) {2040	case B43legacy_PHYTYPE_B:2041	case B43legacy_PHYTYPE_G:2042		b43legacy_phy_write(dev, 0x0015, 0x8000);2043		b43legacy_phy_write(dev, 0x0015, 0xCC00);2044		b43legacy_phy_write(dev, 0x0015,2045				    (phy->gmode ? 0x00C0 : 0x0000));2046		if (phy->radio_off_context.valid) {2047			/* Restore the RFover values. */2048			b43legacy_phy_write(dev, B43legacy_PHY_RFOVER,2049					    phy->radio_off_context.rfover);2050			b43legacy_phy_write(dev, B43legacy_PHY_RFOVERVAL,2051					    phy->radio_off_context.rfoverval);2052			phy->radio_off_context.valid = false;2053		}2054		channel = phy->channel;2055		err = b43legacy_radio_selectchannel(dev,2056					B43legacy_RADIO_DEFAULT_CHANNEL_BG, 1);2057		err |= b43legacy_radio_selectchannel(dev, channel, 0);2058		B43legacy_WARN_ON(err);2059		break;2060	default:2061		B43legacy_BUG_ON(1);2062	}2063	phy->radio_on = true;2064}2065 2066void b43legacy_radio_turn_off(struct b43legacy_wldev *dev, bool force)2067{2068	struct b43legacy_phy *phy = &dev->phy;2069 2070	if (!phy->radio_on && !force)2071		return;2072 2073	if (phy->type == B43legacy_PHYTYPE_G && dev->dev->id.revision >= 5) {2074		u16 rfover, rfoverval;2075 2076		rfover = b43legacy_phy_read(dev, B43legacy_PHY_RFOVER);2077		rfoverval = b43legacy_phy_read(dev, B43legacy_PHY_RFOVERVAL);2078		if (!force) {2079			phy->radio_off_context.rfover = rfover;2080			phy->radio_off_context.rfoverval = rfoverval;2081			phy->radio_off_context.valid = true;2082		}2083		b43legacy_phy_write(dev, B43legacy_PHY_RFOVER, rfover | 0x008C);2084		b43legacy_phy_write(dev, B43legacy_PHY_RFOVERVAL,2085				    rfoverval & 0xFF73);2086	} else2087		b43legacy_phy_write(dev, 0x0015, 0xAA00);2088	phy->radio_on = false;2089	b43legacydbg(dev->wl, "Radio initialized\n");2090}2091 2092void b43legacy_radio_clear_tssi(struct b43legacy_wldev *dev)2093{2094	struct b43legacy_phy *phy = &dev->phy;2095 2096	switch (phy->type) {2097	case B43legacy_PHYTYPE_B:2098	case B43legacy_PHYTYPE_G:2099		b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0058,2100				      0x7F7F);2101		b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x005a,2102				      0x7F7F);2103		b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0070,2104				      0x7F7F);2105		b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0072,2106				      0x7F7F);2107		break;2108	}2109}2110