cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

radio.c (59112B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3
      4  Broadcom B43legacy wireless driver
      5
      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 ipw2200
     14  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 1011
     38 */
     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 inline
     55u16 channel2freq_bg(u8 channel)
     56{
     57	/* Frequencies are given as frequencies_bg[index] + 2.4GHz
     58	 * Starting with channel 1
     59	 */
     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		else
    113			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	else
    223		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	else
    246		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		else
    466			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		} else
    501			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		else
    583			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		else
    618			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		else
    749			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		} else
    823			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			else
    854				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			else
    876				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			else
    885				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 the
    901 * 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 void
    972b43legacy_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 void
   1218b43legacy_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		} else
   1281			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_stacksave
   1316#undef phy_stackrestore
   1317#undef radio_stacksave
   1318#undef radio_stackrestore
   1319#undef ilt_stacksave
   1320#undef ilt_stackrestore
   1321
   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		else
   1339			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	} else
   1360		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_lo
   1394		    & 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		else
   1425			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_lo
   1447		    & 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				else
   1529					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_lo
   1538			    & B43legacy_BFL_EXTLNA))
   1539				b43legacy_phy_write(dev, 0x0811, 0x01B3);
   1540			else
   1541				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
   1712static inline
   1713u16 freq_r3A_value(u16 frequency)
   1714{
   1715	u16 value;
   1716
   1717	if (frequency < 5091)
   1718		value = 0x0040;
   1719	else if (frequency < 5321)
   1720		value = 0x0000;
   1721	else if (frequency < 5806)
   1722		value = 0x0080;
   1723	else
   1724		value = 0x0040;
   1725
   1726	return value;
   1727}
   1728
   1729int b43legacy_radio_selectchannel(struct b43legacy_wldev *dev,
   1730				  u8 channel,
   1731				  int synthetic_pu_workaround)
   1732{
   1733	struct b43legacy_phy *phy = &dev->phy;
   1734
   1735	if (channel == 0xFF) {
   1736		switch (phy->type) {
   1737		case B43legacy_PHYTYPE_B:
   1738		case B43legacy_PHYTYPE_G:
   1739			channel = B43legacy_RADIO_DEFAULT_CHANNEL_BG;
   1740			break;
   1741		default:
   1742			B43legacy_WARN_ON(1);
   1743		}
   1744	}
   1745
   1746/* TODO: Check if channel is valid - return -EINVAL if not */
   1747	if (synthetic_pu_workaround)
   1748		b43legacy_synth_pu_workaround(dev, channel);
   1749
   1750	b43legacy_write16(dev, B43legacy_MMIO_CHANNEL,
   1751			  channel2freq_bg(channel));
   1752
   1753	if (channel == 14) {
   1754		if (dev->dev->bus->sprom.country_code == 5)   /* JAPAN) */
   1755			b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
   1756					      B43legacy_UCODEFLAGS_OFFSET,
   1757					      b43legacy_shm_read32(dev,
   1758					      B43legacy_SHM_SHARED,
   1759					      B43legacy_UCODEFLAGS_OFFSET)
   1760					      & ~(1 << 7));
   1761		else
   1762			b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
   1763					      B43legacy_UCODEFLAGS_OFFSET,
   1764					      b43legacy_shm_read32(dev,
   1765					      B43legacy_SHM_SHARED,
   1766					      B43legacy_UCODEFLAGS_OFFSET)
   1767					      | (1 << 7));
   1768		b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT,
   1769				  b43legacy_read16(dev,
   1770				  B43legacy_MMIO_CHANNEL_EXT) | (1 << 11));
   1771	} else
   1772		b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT,
   1773				  b43legacy_read16(dev,
   1774				  B43legacy_MMIO_CHANNEL_EXT) & 0xF7BF);
   1775
   1776	phy->channel = channel;
   1777	/*XXX: Using the longer of 2 timeouts (8000 vs 2000 usecs). Specs states
   1778	 *     that 2000 usecs might suffice. */
   1779	msleep(8);
   1780
   1781	return 0;
   1782}
   1783
   1784void b43legacy_radio_set_txantenna(struct b43legacy_wldev *dev, u32 val)
   1785{
   1786	u16 tmp;
   1787
   1788	val <<= 8;
   1789	tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x0022) & 0xFCFF;
   1790	b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0022, tmp | val);
   1791	tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x03A8) & 0xFCFF;
   1792	b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x03A8, tmp | val);
   1793	tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x0054) & 0xFCFF;
   1794	b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0054, tmp | val);
   1795}
   1796
   1797/* http://bcm-specs.sipsolutions.net/TX_Gain_Base_Band */
   1798static u16 b43legacy_get_txgain_base_band(u16 txpower)
   1799{
   1800	u16 ret;
   1801
   1802	B43legacy_WARN_ON(txpower > 63);
   1803
   1804	if (txpower >= 54)
   1805		ret = 2;
   1806	else if (txpower >= 49)
   1807		ret = 4;
   1808	else if (txpower >= 44)
   1809		ret = 5;
   1810	else
   1811		ret = 6;
   1812
   1813	return ret;
   1814}
   1815
   1816/* http://bcm-specs.sipsolutions.net/TX_Gain_Radio_Frequency_Power_Amplifier */
   1817static u16 b43legacy_get_txgain_freq_power_amp(u16 txpower)
   1818{
   1819	u16 ret;
   1820
   1821	B43legacy_WARN_ON(txpower > 63);
   1822
   1823	if (txpower >= 32)
   1824		ret = 0;
   1825	else if (txpower >= 25)
   1826		ret = 1;
   1827	else if (txpower >= 20)
   1828		ret = 2;
   1829	else if (txpower >= 12)
   1830		ret = 3;
   1831	else
   1832		ret = 4;
   1833
   1834	return ret;
   1835}
   1836
   1837/* http://bcm-specs.sipsolutions.net/TX_Gain_Digital_Analog_Converter */
   1838static u16 b43legacy_get_txgain_dac(u16 txpower)
   1839{
   1840	u16 ret;
   1841
   1842	B43legacy_WARN_ON(txpower > 63);
   1843
   1844	if (txpower >= 54)
   1845		ret = txpower - 53;
   1846	else if (txpower >= 49)
   1847		ret = txpower - 42;
   1848	else if (txpower >= 44)
   1849		ret = txpower - 37;
   1850	else if (txpower >= 32)
   1851		ret = txpower - 32;
   1852	else if (txpower >= 25)
   1853		ret = txpower - 20;
   1854	else if (txpower >= 20)
   1855		ret = txpower - 13;
   1856	else if (txpower >= 12)
   1857		ret = txpower - 8;
   1858	else
   1859		ret = txpower;
   1860
   1861	return ret;
   1862}
   1863
   1864void b43legacy_radio_set_txpower_a(struct b43legacy_wldev *dev, u16 txpower)
   1865{
   1866	struct b43legacy_phy *phy = &dev->phy;
   1867	u16 pamp;
   1868	u16 base;
   1869	u16 dac;
   1870	u16 ilt;
   1871
   1872	txpower = clamp_val(txpower, 0, 63);
   1873
   1874	pamp = b43legacy_get_txgain_freq_power_amp(txpower);
   1875	pamp <<= 5;
   1876	pamp &= 0x00E0;
   1877	b43legacy_phy_write(dev, 0x0019, pamp);
   1878
   1879	base = b43legacy_get_txgain_base_band(txpower);
   1880	base &= 0x000F;
   1881	b43legacy_phy_write(dev, 0x0017, base | 0x0020);
   1882
   1883	ilt = b43legacy_ilt_read(dev, 0x3001);
   1884	ilt &= 0x0007;
   1885
   1886	dac = b43legacy_get_txgain_dac(txpower);
   1887	dac <<= 3;
   1888	dac |= ilt;
   1889
   1890	b43legacy_ilt_write(dev, 0x3001, dac);
   1891
   1892	phy->txpwr_offset = txpower;
   1893
   1894	/* TODO: FuncPlaceholder (Adjust BB loft cancel) */
   1895}
   1896
   1897void b43legacy_radio_set_txpower_bg(struct b43legacy_wldev *dev,
   1898				    u16 baseband_attenuation,
   1899				    u16 radio_attenuation,
   1900				    u16 txpower)
   1901{
   1902	struct b43legacy_phy *phy = &dev->phy;
   1903
   1904	if (baseband_attenuation == 0xFFFF)
   1905		baseband_attenuation = phy->bbatt;
   1906	if (radio_attenuation == 0xFFFF)
   1907		radio_attenuation = phy->rfatt;
   1908	if (txpower == 0xFFFF)
   1909		txpower = phy->txctl1;
   1910	phy->bbatt = baseband_attenuation;
   1911	phy->rfatt = radio_attenuation;
   1912	phy->txctl1 = txpower;
   1913
   1914	B43legacy_WARN_ON(baseband_attenuation > 11);
   1915	if (phy->radio_rev < 6)
   1916		B43legacy_WARN_ON(radio_attenuation > 9);
   1917	else
   1918		B43legacy_WARN_ON(radio_attenuation > 31);
   1919	B43legacy_WARN_ON(txpower > 7);
   1920
   1921	b43legacy_phy_set_baseband_attenuation(dev, baseband_attenuation);
   1922	b43legacy_radio_write16(dev, 0x0043, radio_attenuation);
   1923	b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0064,
   1924			      radio_attenuation);
   1925	if (phy->radio_ver == 0x2050)
   1926		b43legacy_radio_write16(dev, 0x0052,
   1927					(b43legacy_radio_read16(dev, 0x0052)
   1928					& ~0x0070) | ((txpower << 4) & 0x0070));
   1929	/* FIXME: The spec is very weird and unclear here. */
   1930	if (phy->type == B43legacy_PHYTYPE_G)
   1931		b43legacy_phy_lo_adjust(dev, 0);
   1932}
   1933
   1934u16 b43legacy_default_baseband_attenuation(struct b43legacy_wldev *dev)
   1935{
   1936	struct b43legacy_phy *phy = &dev->phy;
   1937
   1938	if (phy->radio_ver == 0x2050 && phy->radio_rev < 6)
   1939		return 0;
   1940	return 2;
   1941}
   1942
   1943u16 b43legacy_default_radio_attenuation(struct b43legacy_wldev *dev)
   1944{
   1945	struct b43legacy_phy *phy = &dev->phy;
   1946	u16 att = 0xFFFF;
   1947
   1948	switch (phy->radio_ver) {
   1949	case 0x2053:
   1950		switch (phy->radio_rev) {
   1951		case 1:
   1952			att = 6;
   1953			break;
   1954		}
   1955		break;
   1956	case 0x2050:
   1957		switch (phy->radio_rev) {
   1958		case 0:
   1959			att = 5;
   1960			break;
   1961		case 1:
   1962			if (phy->type == B43legacy_PHYTYPE_G) {
   1963				if (is_bcm_board_vendor(dev) &&
   1964				    dev->dev->bus->boardinfo.type == 0x421 &&
   1965				    dev->dev->bus->sprom.board_rev >= 30)
   1966					att = 3;
   1967				else if (is_bcm_board_vendor(dev) &&
   1968					 dev->dev->bus->boardinfo.type == 0x416)
   1969					att = 3;
   1970				else
   1971					att = 1;
   1972			} else {
   1973				if (is_bcm_board_vendor(dev) &&
   1974				    dev->dev->bus->boardinfo.type == 0x421 &&
   1975				    dev->dev->bus->sprom.board_rev >= 30)
   1976					att = 7;
   1977				else
   1978					att = 6;
   1979			}
   1980			break;
   1981		case 2:
   1982			if (phy->type == B43legacy_PHYTYPE_G) {
   1983				if (is_bcm_board_vendor(dev) &&
   1984				    dev->dev->bus->boardinfo.type == 0x421 &&
   1985				    dev->dev->bus->sprom.board_rev >= 30)
   1986					att = 3;
   1987				else if (is_bcm_board_vendor(dev) &&
   1988					 dev->dev->bus->boardinfo.type ==
   1989					 0x416)
   1990					att = 5;
   1991				else if (dev->dev->bus->chip_id == 0x4320)
   1992					att = 4;
   1993				else
   1994					att = 3;
   1995			} else
   1996				att = 6;
   1997			break;
   1998		case 3:
   1999			att = 5;
   2000			break;
   2001		case 4:
   2002		case 5:
   2003			att = 1;
   2004			break;
   2005		case 6:
   2006		case 7:
   2007			att = 5;
   2008			break;
   2009		case 8:
   2010			att = 0x1A;
   2011			break;
   2012		case 9:
   2013		default:
   2014			att = 5;
   2015		}
   2016	}
   2017	if (is_bcm_board_vendor(dev) &&
   2018	    dev->dev->bus->boardinfo.type == 0x421) {
   2019		if (dev->dev->bus->sprom.board_rev < 0x43)
   2020			att = 2;
   2021		else if (dev->dev->bus->sprom.board_rev < 0x51)
   2022			att = 3;
   2023	}
   2024	if (att == 0xFFFF)
   2025		att = 5;
   2026
   2027	return att;
   2028}
   2029
   2030u16 b43legacy_default_txctl1(struct b43legacy_wldev *dev)
   2031{
   2032	struct b43legacy_phy *phy = &dev->phy;
   2033
   2034	if (phy->radio_ver != 0x2050)
   2035		return 0;
   2036	if (phy->radio_rev == 1)
   2037		return 3;
   2038	if (phy->radio_rev < 6)
   2039		return 2;
   2040	if (phy->radio_rev == 8)
   2041		return 1;
   2042	return 0;
   2043}
   2044
   2045void b43legacy_radio_turn_on(struct b43legacy_wldev *dev)
   2046{
   2047	struct b43legacy_phy *phy = &dev->phy;
   2048	int err;
   2049	u8 channel;
   2050
   2051	might_sleep();
   2052
   2053	if (phy->radio_on)
   2054		return;
   2055
   2056	switch (phy->type) {
   2057	case B43legacy_PHYTYPE_B:
   2058	case B43legacy_PHYTYPE_G:
   2059		b43legacy_phy_write(dev, 0x0015, 0x8000);
   2060		b43legacy_phy_write(dev, 0x0015, 0xCC00);
   2061		b43legacy_phy_write(dev, 0x0015,
   2062				    (phy->gmode ? 0x00C0 : 0x0000));
   2063		if (phy->radio_off_context.valid) {
   2064			/* Restore the RFover values. */
   2065			b43legacy_phy_write(dev, B43legacy_PHY_RFOVER,
   2066					    phy->radio_off_context.rfover);
   2067			b43legacy_phy_write(dev, B43legacy_PHY_RFOVERVAL,
   2068					    phy->radio_off_context.rfoverval);
   2069			phy->radio_off_context.valid = false;
   2070		}
   2071		channel = phy->channel;
   2072		err = b43legacy_radio_selectchannel(dev,
   2073					B43legacy_RADIO_DEFAULT_CHANNEL_BG, 1);
   2074		err |= b43legacy_radio_selectchannel(dev, channel, 0);
   2075		B43legacy_WARN_ON(err);
   2076		break;
   2077	default:
   2078		B43legacy_BUG_ON(1);
   2079	}
   2080	phy->radio_on = true;
   2081}
   2082
   2083void b43legacy_radio_turn_off(struct b43legacy_wldev *dev, bool force)
   2084{
   2085	struct b43legacy_phy *phy = &dev->phy;
   2086
   2087	if (!phy->radio_on && !force)
   2088		return;
   2089
   2090	if (phy->type == B43legacy_PHYTYPE_G && dev->dev->id.revision >= 5) {
   2091		u16 rfover, rfoverval;
   2092
   2093		rfover = b43legacy_phy_read(dev, B43legacy_PHY_RFOVER);
   2094		rfoverval = b43legacy_phy_read(dev, B43legacy_PHY_RFOVERVAL);
   2095		if (!force) {
   2096			phy->radio_off_context.rfover = rfover;
   2097			phy->radio_off_context.rfoverval = rfoverval;
   2098			phy->radio_off_context.valid = true;
   2099		}
   2100		b43legacy_phy_write(dev, B43legacy_PHY_RFOVER, rfover | 0x008C);
   2101		b43legacy_phy_write(dev, B43legacy_PHY_RFOVERVAL,
   2102				    rfoverval & 0xFF73);
   2103	} else
   2104		b43legacy_phy_write(dev, 0x0015, 0xAA00);
   2105	phy->radio_on = false;
   2106	b43legacydbg(dev->wl, "Radio initialized\n");
   2107}
   2108
   2109void b43legacy_radio_clear_tssi(struct b43legacy_wldev *dev)
   2110{
   2111	struct b43legacy_phy *phy = &dev->phy;
   2112
   2113	switch (phy->type) {
   2114	case B43legacy_PHYTYPE_B:
   2115	case B43legacy_PHYTYPE_G:
   2116		b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0058,
   2117				      0x7F7F);
   2118		b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x005a,
   2119				      0x7F7F);
   2120		b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0070,
   2121				      0x7F7F);
   2122		b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0072,
   2123				      0x7F7F);
   2124		break;
   2125	}
   2126}