Skip to content
Snippets Groups Projects
phy_n.c 107 KiB
Newer Older
  • Learn to ignore specific revisions
  • 	if (nphy->hang_avoid)
    		b43_nphy_stay_in_carrier_search(dev, 1);
    
    	if (nphy->gain_boost) {
    		if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
    			gain[0] = 6;
    			gain[1] = 6;
    		} else {
    
    			tmp = 40370 - 315 * dev->phy.channel;
    
    			gain[0] = ((tmp >> 13) + ((tmp >> 12) & 1));
    
    			tmp = 23242 - 224 * dev->phy.channel;
    
    			gain[1] = ((tmp >> 13) + ((tmp >> 12) & 1));
    		}
    	} else {
    		gain[0] = 0;
    		gain[1] = 0;
    	}
    
    	for (i = 0; i < 2; i++) {
    		if (nphy->elna_gain_config) {
    			data[0] = 19 + gain[i];
    			data[1] = 25 + gain[i];
    			data[2] = 25 + gain[i];
    			data[3] = 25 + gain[i];
    		} else {
    			data[0] = lna_gain[0] + gain[i];
    			data[1] = lna_gain[1] + gain[i];
    			data[2] = lna_gain[2] + gain[i];
    			data[3] = lna_gain[3] + gain[i];
    		}
    
    		b43_ntab_write_bulk(dev, B43_NTAB16(i, 8), 4, data);
    
    
    		minmax[i] = 23 + gain[i];
    	}
    
    	b43_phy_maskset(dev, B43_NPHY_C1_MINMAX_GAIN, ~B43_NPHY_C1_MINGAIN,
    				minmax[0] << B43_NPHY_C1_MINGAIN_SHIFT);
    	b43_phy_maskset(dev, B43_NPHY_C2_MINMAX_GAIN, ~B43_NPHY_C2_MINGAIN,
    				minmax[1] << B43_NPHY_C2_MINGAIN_SHIFT);
    
    	if (nphy->hang_avoid)
    		b43_nphy_stay_in_carrier_search(dev, 0);
    }
    
    
    /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/WorkaroundsGainCtrl */
    
    static void b43_nphy_gain_ctrl_workarounds(struct b43_wldev *dev)
    
    {
    	struct b43_phy_n *nphy = dev->phy.n;
    	u8 i, j;
    	u8 code;
    
    
    	/* TODO: for PHY >= 3
    	s8 *lna1_gain, *lna2_gain;
    	u8 *gain_db, *gain_bits;
    	u16 *rfseq_init;
    	u8 lpf_gain[6] = { 0x00, 0x06, 0x0C, 0x12, 0x12, 0x12 };
    	u8 lpf_bits[6] = { 0, 1, 2, 3, 3, 3 };
    	*/
    
    	u8 rfseq_events[3] = { 6, 8, 7 };
    	u8 rfseq_delays[3] = { 10, 30, 1 };
    
    	if (dev->phy.rev >= 3) {
    		/* TODO */
    	} else {
    		/* Set Clip 2 detect */
    		b43_phy_set(dev, B43_NPHY_C1_CGAINI,
    				B43_NPHY_C1_CGAINI_CL2DETECT);
    		b43_phy_set(dev, B43_NPHY_C2_CGAINI,
    				B43_NPHY_C2_CGAINI_CL2DETECT);
    
    		/* Set narrowband clip threshold */
    
    		b43_phy_write(dev, B43_NPHY_C1_NBCLIPTHRES, 0x84);
    		b43_phy_write(dev, B43_NPHY_C2_NBCLIPTHRES, 0x84);
    
    
    		if (!dev->phy.is_40mhz) {
    			/* Set dwell lengths */
    
    			b43_phy_write(dev, B43_NPHY_CLIP1_NBDWELL_LEN, 0x002B);
    			b43_phy_write(dev, B43_NPHY_CLIP2_NBDWELL_LEN, 0x002B);
    			b43_phy_write(dev, B43_NPHY_W1CLIP1_DWELL_LEN, 0x0009);
    			b43_phy_write(dev, B43_NPHY_W1CLIP2_DWELL_LEN, 0x0009);
    
    		}
    
    		/* Set wideband clip 2 threshold */
    		b43_phy_maskset(dev, B43_NPHY_C1_CLIPWBTHRES,
    				~B43_NPHY_C1_CLIPWBTHRES_CLIP2,
    				21);
    		b43_phy_maskset(dev, B43_NPHY_C2_CLIPWBTHRES,
    				~B43_NPHY_C2_CLIPWBTHRES_CLIP2,
    				21);
    
    		if (!dev->phy.is_40mhz) {
    			b43_phy_maskset(dev, B43_NPHY_C1_CGAINI,
    				~B43_NPHY_C1_CGAINI_GAINBKOFF, 0x1);
    			b43_phy_maskset(dev, B43_NPHY_C2_CGAINI,
    				~B43_NPHY_C2_CGAINI_GAINBKOFF, 0x1);
    			b43_phy_maskset(dev, B43_NPHY_C1_CCK_CGAINI,
    				~B43_NPHY_C1_CCK_CGAINI_GAINBKOFF, 0x1);
    			b43_phy_maskset(dev, B43_NPHY_C2_CCK_CGAINI,
    				~B43_NPHY_C2_CCK_CGAINI_GAINBKOFF, 0x1);
    		}
    
    
    		b43_phy_write(dev, B43_NPHY_CCK_SHIFTB_REF, 0x809C);
    
    
    		if (nphy->gain_boost) {
    			if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ &&
    			    dev->phy.is_40mhz)
    				code = 4;
    			else
    				code = 5;
    		} else {
    			code = dev->phy.is_40mhz ? 6 : 7;
    		}
    
    		/* Set HPVGA2 index */
    		b43_phy_maskset(dev, B43_NPHY_C1_INITGAIN,
    				~B43_NPHY_C1_INITGAIN_HPVGA2,
    				code << B43_NPHY_C1_INITGAIN_HPVGA2_SHIFT);
    		b43_phy_maskset(dev, B43_NPHY_C2_INITGAIN,
    				~B43_NPHY_C2_INITGAIN_HPVGA2,
    				code << B43_NPHY_C2_INITGAIN_HPVGA2_SHIFT);
    
    		b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x1D06);
    
    		/* specs say about 2 loops, but wl does 4 */
    		for (i = 0; i < 4; i++)
    			b43_phy_write(dev, B43_NPHY_TABLE_DATALO,
    							(code << 8 | 0x7C));
    
    		b43_nphy_adjust_lna_gain_table(dev);
    
    
    		if (nphy->elna_gain_config) {
    			b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x0808);
    			b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x0);
    			b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x1);
    			b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x1);
    			b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x1);
    
    			b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x0C08);
    			b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x0);
    			b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x1);
    			b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x1);
    			b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x1);
    
    			b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x1D06);
    
    			/* specs say about 2 loops, but wl does 4 */
    			for (i = 0; i < 4; i++)
    				b43_phy_write(dev, B43_NPHY_TABLE_DATALO,
    							(code << 8 | 0x74));
    
    		}
    
    		if (dev->phy.rev == 2) {
    			for (i = 0; i < 4; i++) {
    				b43_phy_write(dev, B43_NPHY_TABLE_ADDR,
    						(0x0400 * i) + 0x0020);
    
    				for (j = 0; j < 21; j++) {
    					tmp = j * (i < 2 ? 3 : 1);
    
    					b43_phy_write(dev,
    
    						B43_NPHY_TABLE_DATALO, tmp);
    				}
    
    			b43_nphy_set_rf_sequence(dev, 5,
    					rfseq_events, rfseq_delays, 3);
    
    			b43_phy_maskset(dev, B43_NPHY_OVER_DGAIN1,
    
    				~B43_NPHY_OVER_DGAIN_CCKDGECV & 0xFFFF,
    
    				0x5A << B43_NPHY_OVER_DGAIN_CCKDGECV_SHIFT);
    
    			if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
    				b43_phy_maskset(dev, B43_PHY_N(0xC5D),
    						0xFF80, 4);
    		}
    	}
    }
    
    
    /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/Workarounds */
    static void b43_nphy_workarounds(struct b43_wldev *dev)
    {
    	struct ssb_bus *bus = dev->dev->bus;
    	struct b43_phy *phy = &dev->phy;
    	struct b43_phy_n *nphy = phy->n;
    
    	u8 events1[7] = { 0x0, 0x1, 0x2, 0x8, 0x4, 0x5, 0x3 };
    	u8 delays1[7] = { 0x8, 0x6, 0x6, 0x2, 0x4, 0x3C, 0x1 };
    
    	u8 events2[7] = { 0x0, 0x3, 0x5, 0x4, 0x2, 0x1, 0x8 };
    	u8 delays2[7] = { 0x8, 0x6, 0x2, 0x4, 0x4, 0x6, 0x1 };
    
    
    	if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ)
    
    		b43_nphy_classifier(dev, 1, 0);
    	else
    		b43_nphy_classifier(dev, 1, 1);
    
    	if (nphy->hang_avoid)
    		b43_nphy_stay_in_carrier_search(dev, 1);
    
    	b43_phy_set(dev, B43_NPHY_IQFLIP,
    		    B43_NPHY_IQFLIP_ADC1 | B43_NPHY_IQFLIP_ADC2);
    
    	if (dev->phy.rev >= 3) {
    		/* TODO */
    	} else {
    		if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ &&
    		    nphy->band5g_pwrgain) {
    			b43_radio_mask(dev, B2055_C1_TX_RF_SPARE, ~0x8);
    			b43_radio_mask(dev, B2055_C2_TX_RF_SPARE, ~0x8);
    		} else {
    			b43_radio_set(dev, B2055_C1_TX_RF_SPARE, 0x8);
    			b43_radio_set(dev, B2055_C2_TX_RF_SPARE, 0x8);
    		}
    
    
    		b43_ntab_write(dev, B43_NTAB16(8, 0x00), 0x000A);
    		b43_ntab_write(dev, B43_NTAB16(8, 0x10), 0x000A);
    		b43_ntab_write(dev, B43_NTAB16(8, 0x02), 0xCDAA);
    		b43_ntab_write(dev, B43_NTAB16(8, 0x12), 0xCDAA);
    
    
    		if (dev->phy.rev < 2) {
    
    			b43_ntab_write(dev, B43_NTAB16(8, 0x08), 0x0000);
    			b43_ntab_write(dev, B43_NTAB16(8, 0x18), 0x0000);
    			b43_ntab_write(dev, B43_NTAB16(8, 0x07), 0x7AAB);
    			b43_ntab_write(dev, B43_NTAB16(8, 0x17), 0x7AAB);
    			b43_ntab_write(dev, B43_NTAB16(8, 0x06), 0x0800);
    			b43_ntab_write(dev, B43_NTAB16(8, 0x16), 0x0800);
    
    		}
    
    		b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO1, 0x2D8);
    		b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP1, 0x301);
    		b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO2, 0x2D8);
    		b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP2, 0x301);
    
    		if (bus->sprom.boardflags2_lo & 0x100 &&
    		    bus->boardinfo.type == 0x8B) {
    			delays1[0] = 0x1;
    			delays1[5] = 0x14;
    		}
    
    		b43_nphy_set_rf_sequence(dev, 0, events1, delays1, 7);
    		b43_nphy_set_rf_sequence(dev, 1, events2, delays2, 7);
    
    		b43_nphy_gain_ctrl_workarounds(dev);
    
    
    		if (dev->phy.rev < 2) {
    			if (b43_phy_read(dev, B43_NPHY_RXCTL) & 0x2)
    
    				b43_hf_write(dev, b43_hf_read(dev) |
    						B43_HF_MLADVW);
    
    		} else if (dev->phy.rev == 2) {
    			b43_phy_write(dev, B43_NPHY_CRSCHECK2, 0);
    			b43_phy_write(dev, B43_NPHY_CRSCHECK3, 0);
    		}
    
    		if (dev->phy.rev < 2)
    			b43_phy_mask(dev, B43_NPHY_SCRAM_SIGCTL,
    					~B43_NPHY_SCRAM_SIGCTL_SCM);
    
    		/* Set phase track alpha and beta */
    		b43_phy_write(dev, B43_NPHY_PHASETR_A0, 0x125);
    		b43_phy_write(dev, B43_NPHY_PHASETR_A1, 0x1B3);
    		b43_phy_write(dev, B43_NPHY_PHASETR_A2, 0x105);
    		b43_phy_write(dev, B43_NPHY_PHASETR_B0, 0x16E);
    		b43_phy_write(dev, B43_NPHY_PHASETR_B1, 0xCD);
    		b43_phy_write(dev, B43_NPHY_PHASETR_B2, 0x20);
    
    		b43_phy_mask(dev, B43_NPHY_PIL_DW1,
    
    				~B43_NPHY_PIL_DW_64QAM & 0xFFFF);
    
    		b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B1, 0xB5);
    		b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B2, 0xA4);
    		b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B3, 0x00);
    
    		if (dev->phy.rev == 2)
    			b43_phy_set(dev, B43_NPHY_FINERX2_CGC,
    					B43_NPHY_FINERX2_CGC_DECGC);
    	}
    
    	if (nphy->hang_avoid)
    		b43_nphy_stay_in_carrier_search(dev, 0);
    }
    
    
    /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/LoadSampleTable */
    static int b43_nphy_load_samples(struct b43_wldev *dev,
    					struct b43_c32 *samples, u16 len) {
    	struct b43_phy_n *nphy = dev->phy.n;
    	u16 i;
    	u32 *data;
    
    	data = kzalloc(len * sizeof(u32), GFP_KERNEL);
    	if (!data) {
    		b43err(dev->wl, "allocation for samples loading failed\n");
    		return -ENOMEM;
    	}
    	if (nphy->hang_avoid)
    		b43_nphy_stay_in_carrier_search(dev, 1);
    
    	for (i = 0; i < len; i++) {
    		data[i] = (samples[i].i & 0x3FF << 10);
    		data[i] |= samples[i].q & 0x3FF;
    	}
    	b43_ntab_write_bulk(dev, B43_NTAB32(17, 0), len, data);
    
    	kfree(data);
    	if (nphy->hang_avoid)
    		b43_nphy_stay_in_carrier_search(dev, 0);
    	return 0;
    }
    
    
    Rafał Miłecki's avatar
    Rafał Miłecki committed
    /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/GenLoadSamples */
    static u16 b43_nphy_gen_load_samples(struct b43_wldev *dev, u32 freq, u16 max,
    					bool test)
    {
    	int i;
    
    	u16 bw, len, rot, angle;
    
    Rafał Miłecki's avatar
    Rafał Miłecki committed
    
    	bw = (dev->phy.is_40mhz) ? 40 : 20;
    	len = bw << 3;
    
    	if (test) {
    		if (b43_phy_read(dev, B43_NPHY_BBCFG) & B43_NPHY_BBCFG_RSTRX)
    			bw = 82;
    		else
    			bw = 80;
    
    		if (dev->phy.is_40mhz)
    			bw <<= 1;
    
    		len = bw << 1;
    	}
    
    
    	samples = kcalloc(len, sizeof(struct b43_c32), GFP_KERNEL);
    
    	if (!samples) {
    		b43err(dev->wl, "allocation for samples generation failed\n");
    		return 0;
    	}
    
    Rafał Miłecki's avatar
    Rafał Miłecki committed
    	rot = (((freq * 36) / bw) << 16) / 100;
    	angle = 0;
    
    
    	for (i = 0; i < len; i++) {
    		samples[i] = b43_cordic(angle);
    		angle += rot;
    		samples[i].q = CORDIC_CONVERT(samples[i].q * max);
    		samples[i].i = CORDIC_CONVERT(samples[i].i * max);
    
    	i = b43_nphy_load_samples(dev, samples, len);
    
    	return (i < 0) ? 0 : len;
    
    /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RunSamples */
    static void b43_nphy_run_samples(struct b43_wldev *dev, u16 samps, u16 loops,
    					u16 wait, bool iqmode, bool dac_test)
    {
    	struct b43_phy_n *nphy = dev->phy.n;
    	int i;
    	u16 seq_mode;
    	u32 tmp;
    
    	if (nphy->hang_avoid)
    		b43_nphy_stay_in_carrier_search(dev, true);
    
    	if ((nphy->bb_mult_save & 0x80000000) == 0) {
    		tmp = b43_ntab_read(dev, B43_NTAB16(15, 87));
    		nphy->bb_mult_save = (tmp & 0xFFFF) | 0x80000000;
    	}
    
    	if (!dev->phy.is_40mhz)
    		tmp = 0x6464;
    	else
    		tmp = 0x4747;
    	b43_ntab_write(dev, B43_NTAB16(15, 87), tmp);
    
    	if (nphy->hang_avoid)
    		b43_nphy_stay_in_carrier_search(dev, false);
    
    	b43_phy_write(dev, B43_NPHY_SAMP_DEPCNT, (samps - 1));
    
    	if (loops != 0xFFFF)
    		b43_phy_write(dev, B43_NPHY_SAMP_LOOPCNT, (loops - 1));
    	else
    		b43_phy_write(dev, B43_NPHY_SAMP_LOOPCNT, loops);
    
    	b43_phy_write(dev, B43_NPHY_SAMP_WAITCNT, wait);
    
    	seq_mode = b43_phy_read(dev, B43_NPHY_RFSEQMODE);
    
    	b43_phy_set(dev, B43_NPHY_RFSEQMODE, B43_NPHY_RFSEQMODE_CAOVER);
    	if (iqmode) {
    		b43_phy_mask(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0x7FFF);
    		b43_phy_set(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0x8000);
    	} else {
    		if (dac_test)
    			b43_phy_write(dev, B43_NPHY_SAMP_CMD, 5);
    		else
    			b43_phy_write(dev, B43_NPHY_SAMP_CMD, 1);
    	}
    	for (i = 0; i < 100; i++) {
    		if (b43_phy_read(dev, B43_NPHY_RFSEQST) & 1) {
    			i = 0;
    			break;
    		}
    		udelay(10);
    	}
    	if (i)
    		b43err(dev->wl, "run samples timeout\n");
    
    	b43_phy_write(dev, B43_NPHY_RFSEQMODE, seq_mode);
    }
    
    
    Rafał Miłecki's avatar
    Rafał Miłecki committed
    /*
     * Transmits a known value for LO calibration
     * http://bcm-v4.sipsolutions.net/802.11/PHY/N/TXTone
     */
    static int b43_nphy_tx_tone(struct b43_wldev *dev, u32 freq, u16 max_val,
    				bool iqmode, bool dac_test)
    {
    	u16 samp = b43_nphy_gen_load_samples(dev, freq, max_val, dac_test);
    	if (samp == 0)
    		return -1;
    	b43_nphy_run_samples(dev, samp, 0xFFFF, 0, iqmode, dac_test);
    	return 0;
    }
    
    
    /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrCtrlCoefSetup */
    static void b43_nphy_tx_pwr_ctrl_coef_setup(struct b43_wldev *dev)
    {
    	struct b43_phy_n *nphy = dev->phy.n;
    	int i, j;
    	u32 tmp;
    	u32 cur_real, cur_imag, real_part, imag_part;
    
    	u16 buffer[7];
    
    	if (nphy->hang_avoid)
    		b43_nphy_stay_in_carrier_search(dev, true);
    
    
    	b43_ntab_read_bulk(dev, B43_NTAB16(15, 80), 7, buffer);
    
    
    	for (i = 0; i < 2; i++) {
    		tmp = ((buffer[i * 2] & 0x3FF) << 10) |
    			(buffer[i * 2 + 1] & 0x3FF);
    		b43_phy_write(dev, B43_NPHY_TABLE_ADDR,
    				(((i + 26) << 10) | 320));
    		for (j = 0; j < 128; j++) {
    			b43_phy_write(dev, B43_NPHY_TABLE_DATAHI,
    					((tmp >> 16) & 0xFFFF));
    			b43_phy_write(dev, B43_NPHY_TABLE_DATALO,
    					(tmp & 0xFFFF));
    		}
    	}
    
    	for (i = 0; i < 2; i++) {
    		tmp = buffer[5 + i];
    		real_part = (tmp >> 8) & 0xFF;
    		imag_part = (tmp & 0xFF);
    		b43_phy_write(dev, B43_NPHY_TABLE_ADDR,
    				(((i + 26) << 10) | 448));
    
    		if (dev->phy.rev >= 3) {
    			cur_real = real_part;
    			cur_imag = imag_part;
    			tmp = ((cur_real & 0xFF) << 8) | (cur_imag & 0xFF);
    		}
    
    		for (j = 0; j < 128; j++) {
    			if (dev->phy.rev < 3) {
    				cur_real = (real_part * loscale[j] + 128) >> 8;
    				cur_imag = (imag_part * loscale[j] + 128) >> 8;
    				tmp = ((cur_real & 0xFF) << 8) |
    					(cur_imag & 0xFF);
    			}
    			b43_phy_write(dev, B43_NPHY_TABLE_DATAHI,
    					((tmp >> 16) & 0xFFFF));
    			b43_phy_write(dev, B43_NPHY_TABLE_DATALO,
    					(tmp & 0xFFFF));
    		}
    	}
    
    	if (dev->phy.rev >= 3) {
    		b43_shm_write16(dev, B43_SHM_SHARED,
    				B43_SHM_SH_NPHY_TXPWR_INDX0, 0xFFFF);
    		b43_shm_write16(dev, B43_SHM_SHARED,
    				B43_SHM_SH_NPHY_TXPWR_INDX1, 0xFFFF);
    	}
    
    	if (nphy->hang_avoid)
    		b43_nphy_stay_in_carrier_search(dev, false);
    }
    
    
    /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SetRfSeq */
    static void b43_nphy_set_rf_sequence(struct b43_wldev *dev, u8 cmd,
    					u8 *events, u8 *delays, u8 length)
    {
    	struct b43_phy_n *nphy = dev->phy.n;
    	u8 i;
    	u8 end = (dev->phy.rev >= 3) ? 0x1F : 0x0F;
    	u16 offset1 = cmd << 4;
    	u16 offset2 = offset1 + 0x80;
    
    	if (nphy->hang_avoid)
    		b43_nphy_stay_in_carrier_search(dev, true);
    
    	b43_ntab_write_bulk(dev, B43_NTAB8(7, offset1), length, events);
    	b43_ntab_write_bulk(dev, B43_NTAB8(7, offset2), length, delays);
    
    	for (i = length; i < 16; i++) {
    		b43_ntab_write(dev, B43_NTAB8(7, offset1 + i), end);
    		b43_ntab_write(dev, B43_NTAB8(7, offset2 + i), 1);
    	}
    
    	if (nphy->hang_avoid)
    		b43_nphy_stay_in_carrier_search(dev, false);
    }
    
    
    /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ForceRFSeq */
    
    static void b43_nphy_force_rf_sequence(struct b43_wldev *dev,
    				       enum b43_nphy_rf_sequence seq)
    {
    	static const u16 trigger[] = {
    		[B43_RFSEQ_RX2TX]		= B43_NPHY_RFSEQTR_RX2TX,
    		[B43_RFSEQ_TX2RX]		= B43_NPHY_RFSEQTR_TX2RX,
    		[B43_RFSEQ_RESET2RX]		= B43_NPHY_RFSEQTR_RST2RX,
    		[B43_RFSEQ_UPDATE_GAINH]	= B43_NPHY_RFSEQTR_UPGH,
    		[B43_RFSEQ_UPDATE_GAINL]	= B43_NPHY_RFSEQTR_UPGL,
    		[B43_RFSEQ_UPDATE_GAINU]	= B43_NPHY_RFSEQTR_UPGU,
    	};
    	int i;
    
    	u16 seq_mode = b43_phy_read(dev, B43_NPHY_RFSEQMODE);
    
    
    	B43_WARN_ON(seq >= ARRAY_SIZE(trigger));
    
    	b43_phy_set(dev, B43_NPHY_RFSEQMODE,
    		    B43_NPHY_RFSEQMODE_CAOVER | B43_NPHY_RFSEQMODE_TROVER);
    	b43_phy_set(dev, B43_NPHY_RFSEQTR, trigger[seq]);
    	for (i = 0; i < 200; i++) {
    		if (!(b43_phy_read(dev, B43_NPHY_RFSEQST) & trigger[seq]))
    			goto ok;
    		msleep(1);
    	}
    	b43err(dev->wl, "RF sequence status timeout\n");
    ok:
    
    	b43_phy_write(dev, B43_NPHY_RFSEQMODE, seq_mode);
    
    /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlOverride */
    static void b43_nphy_rf_control_override(struct b43_wldev *dev, u16 field,
    						u16 value, u8 core, bool off)
    {
    	int i;
    	u8 index = fls(field);
    	u8 addr, en_addr, val_addr;
    	/* we expect only one bit set */
    
    	B43_WARN_ON(field & (~(1 << (index - 1))));
    
    
    	if (dev->phy.rev >= 3) {
    		const struct nphy_rf_control_override_rev3 *rf_ctrl;
    		for (i = 0; i < 2; i++) {
    			if (index == 0 || index == 16) {
    				b43err(dev->wl,
    					"Unsupported RF Ctrl Override call\n");
    				return;
    			}
    
    			rf_ctrl = &tbl_rf_control_override_rev3[index - 1];
    			en_addr = B43_PHY_N((i == 0) ?
    				rf_ctrl->en_addr0 : rf_ctrl->en_addr1);
    			val_addr = B43_PHY_N((i == 0) ?
    				rf_ctrl->val_addr0 : rf_ctrl->val_addr1);
    
    			if (off) {
    				b43_phy_mask(dev, en_addr, ~(field));
    				b43_phy_mask(dev, val_addr,
    						~(rf_ctrl->val_mask));
    			} else {
    				if (core == 0 || ((1 << core) & i) != 0) {
    					b43_phy_set(dev, en_addr, field);
    					b43_phy_maskset(dev, val_addr,
    						~(rf_ctrl->val_mask),
    						(value << rf_ctrl->val_shift));
    				}
    			}
    		}
    	} else {
    		const struct nphy_rf_control_override_rev2 *rf_ctrl;
    		if (off) {
    			b43_phy_mask(dev, B43_NPHY_RFCTL_OVER, ~(field));
    			value = 0;
    		} else {
    			b43_phy_set(dev, B43_NPHY_RFCTL_OVER, field);
    		}
    
    		for (i = 0; i < 2; i++) {
    			if (index <= 1 || index == 16) {
    				b43err(dev->wl,
    					"Unsupported RF Ctrl Override call\n");
    				return;
    			}
    
    			if (index == 2 || index == 10 ||
    			    (index >= 13 && index <= 15)) {
    				core = 1;
    			}
    
    			rf_ctrl = &tbl_rf_control_override_rev2[index - 2];
    			addr = B43_PHY_N((i == 0) ?
    				rf_ctrl->addr0 : rf_ctrl->addr1);
    
    			if ((core & (1 << i)) != 0)
    				b43_phy_maskset(dev, addr, ~(rf_ctrl->bmask),
    						(value << rf_ctrl->shift));
    
    			b43_phy_set(dev, B43_NPHY_RFCTL_OVER, 0x1);
    			b43_phy_set(dev, B43_NPHY_RFCTL_CMD,
    					B43_NPHY_RFCTL_CMD_START);
    			udelay(1);
    			b43_phy_mask(dev, B43_NPHY_RFCTL_OVER, 0xFFFE);
    		}
    	}
    }
    
    
    /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlIntcOverride */
    static void b43_nphy_rf_control_intc_override(struct b43_wldev *dev, u8 field,
    						u16 value, u8 core)
    {
    	u8 i, j;
    	u16 reg, tmp, val;
    
    	B43_WARN_ON(dev->phy.rev < 3);
    	B43_WARN_ON(field > 4);
    
    	for (i = 0; i < 2; i++) {
    		if ((core == 1 && i == 1) || (core == 2 && !i))
    			continue;
    
    		reg = (i == 0) ?
    			B43_NPHY_RFCTL_INTC1 : B43_NPHY_RFCTL_INTC2;
    		b43_phy_mask(dev, reg, 0xFBFF);
    
    		switch (field) {
    		case 0:
    			b43_phy_write(dev, reg, 0);
    			b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX);
    			break;
    		case 1:
    			if (!i) {
    				b43_phy_maskset(dev, B43_NPHY_RFCTL_INTC1,
    						0xFC3F, (value << 6));
    				b43_phy_maskset(dev, B43_NPHY_TXF_40CO_B1S1,
    						0xFFFE, 1);
    				b43_phy_set(dev, B43_NPHY_RFCTL_CMD,
    						B43_NPHY_RFCTL_CMD_START);
    				for (j = 0; j < 100; j++) {
    					if (b43_phy_read(dev, B43_NPHY_RFCTL_CMD) & B43_NPHY_RFCTL_CMD_START) {
    						j = 0;
    						break;
    					}
    					udelay(10);
    				}
    				if (j)
    					b43err(dev->wl,
    						"intc override timeout\n");
    				b43_phy_mask(dev, B43_NPHY_TXF_40CO_B1S1,
    						0xFFFE);
    			} else {
    				b43_phy_maskset(dev, B43_NPHY_RFCTL_INTC2,
    						0xFC3F, (value << 6));
    				b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER,
    						0xFFFE, 1);
    				b43_phy_set(dev, B43_NPHY_RFCTL_CMD,
    						B43_NPHY_RFCTL_CMD_RXTX);
    				for (j = 0; j < 100; j++) {
    					if (b43_phy_read(dev, B43_NPHY_RFCTL_CMD) & B43_NPHY_RFCTL_CMD_RXTX) {
    						j = 0;
    						break;
    					}
    					udelay(10);
    				}
    				if (j)
    					b43err(dev->wl,
    						"intc override timeout\n");
    				b43_phy_mask(dev, B43_NPHY_RFCTL_OVER,
    						0xFFFE);
    			}
    			break;
    		case 2:
    			if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) {
    				tmp = 0x0020;
    				val = value << 5;
    			} else {
    				tmp = 0x0010;
    				val = value << 4;
    			}
    			b43_phy_maskset(dev, reg, ~tmp, val);
    			break;
    		case 3:
    			if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) {
    				tmp = 0x0001;
    				val = value;
    			} else {
    				tmp = 0x0004;
    				val = value << 2;
    			}
    			b43_phy_maskset(dev, reg, ~tmp, val);
    			break;
    		case 4:
    			if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) {
    				tmp = 0x0002;
    				val = value << 1;
    			} else {
    				tmp = 0x0008;
    				val = value << 3;
    			}
    			b43_phy_maskset(dev, reg, ~tmp, val);
    			break;
    		}
    	}
    }
    
    
    /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/BPHYInit */
    
    static void b43_nphy_bphy_init(struct b43_wldev *dev)
    {
    	unsigned int i;
    	u16 val;
    
    	val = 0x1E1F;
    
    	for (i = 0; i < 16; i++) {
    
    		b43_phy_write(dev, B43_PHY_N_BMODE(0x88 + i), val);
    		val -= 0x202;
    	}
    	val = 0x3E3F;
    	for (i = 0; i < 16; i++) {
    
    		b43_phy_write(dev, B43_PHY_N_BMODE(0x98 + i), val);
    
    		val -= 0x202;
    	}
    	b43_phy_write(dev, B43_PHY_N_BMODE(0x38), 0x668);
    }
    
    
    /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ScaleOffsetRssi */
    static void b43_nphy_scale_offset_rssi(struct b43_wldev *dev, u16 scale,
    
    					s8 offset, u8 core, u8 rail,
    					enum b43_nphy_rssi_type type)
    
    {
    	u16 tmp;
    	bool core1or5 = (core == 1) || (core == 5);
    	bool core2or5 = (core == 2) || (core == 5);
    
    	offset = clamp_val(offset, -32, 31);
    	tmp = ((scale & 0x3F) << 8) | (offset & 0x3F);
    
    
    	if (core1or5 && (rail == 0) && (type == B43_NPHY_RSSI_Z))
    
    		b43_phy_write(dev, B43_NPHY_RSSIMC_0I_RSSI_Z, tmp);
    
    	if (core1or5 && (rail == 1) && (type == B43_NPHY_RSSI_Z))
    
    		b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_RSSI_Z, tmp);
    
    	if (core2or5 && (rail == 0) && (type == B43_NPHY_RSSI_Z))
    
    		b43_phy_write(dev, B43_NPHY_RSSIMC_1I_RSSI_Z, tmp);
    
    	if (core2or5 && (rail == 1) && (type == B43_NPHY_RSSI_Z))
    
    		b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_Z, tmp);
    
    
    	if (core1or5 && (rail == 0) && (type == B43_NPHY_RSSI_X))
    
    		b43_phy_write(dev, B43_NPHY_RSSIMC_0I_RSSI_X, tmp);
    
    	if (core1or5 && (rail == 1) && (type == B43_NPHY_RSSI_X))
    
    		b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_RSSI_X, tmp);
    
    	if (core2or5 && (rail == 0) && (type == B43_NPHY_RSSI_X))
    
    		b43_phy_write(dev, B43_NPHY_RSSIMC_1I_RSSI_X, tmp);
    
    	if (core2or5 && (rail == 1) && (type == B43_NPHY_RSSI_X))
    
    		b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_X, tmp);
    
    
    	if (core1or5 && (rail == 0) && (type == B43_NPHY_RSSI_Y))
    
    		b43_phy_write(dev, B43_NPHY_RSSIMC_0I_RSSI_Y, tmp);
    
    	if (core1or5 && (rail == 1) && (type == B43_NPHY_RSSI_Y))
    
    		b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_RSSI_Y, tmp);
    
    	if (core2or5 && (rail == 0) && (type == B43_NPHY_RSSI_Y))
    
    		b43_phy_write(dev, B43_NPHY_RSSIMC_1I_RSSI_Y, tmp);
    
    	if (core2or5 && (rail == 1) && (type == B43_NPHY_RSSI_Y))
    
    		b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_Y, tmp);
    
    
    	if (core1or5 && (rail == 0) && (type == B43_NPHY_RSSI_TBD))
    
    		b43_phy_write(dev, B43_NPHY_RSSIMC_0I_TBD, tmp);
    
    	if (core1or5 && (rail == 1) && (type == B43_NPHY_RSSI_TBD))
    
    		b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_TBD, tmp);
    
    	if (core2or5 && (rail == 0) && (type == B43_NPHY_RSSI_TBD))
    
    		b43_phy_write(dev, B43_NPHY_RSSIMC_1I_TBD, tmp);
    
    	if (core2or5 && (rail == 1) && (type == B43_NPHY_RSSI_TBD))
    
    		b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_TBD, tmp);
    
    
    	if (core1or5 && (rail == 0) && (type == B43_NPHY_RSSI_PWRDET))
    
    		b43_phy_write(dev, B43_NPHY_RSSIMC_0I_PWRDET, tmp);
    
    	if (core1or5 && (rail == 1) && (type == B43_NPHY_RSSI_PWRDET))
    
    		b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_PWRDET, tmp);
    
    	if (core2or5 && (rail == 0) && (type == B43_NPHY_RSSI_PWRDET))
    
    		b43_phy_write(dev, B43_NPHY_RSSIMC_1I_PWRDET, tmp);
    
    	if (core2or5 && (rail == 1) && (type == B43_NPHY_RSSI_PWRDET))
    
    		b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_PWRDET, tmp);
    
    
    	if (core1or5 && (type == B43_NPHY_RSSI_TSSI_I))
    
    		b43_phy_write(dev, B43_NPHY_RSSIMC_0I_TSSI, tmp);
    
    	if (core2or5 && (type == B43_NPHY_RSSI_TSSI_I))
    
    		b43_phy_write(dev, B43_NPHY_RSSIMC_1I_TSSI, tmp);
    
    
    	if (core1or5 && (type == B43_NPHY_RSSI_TSSI_Q))
    
    		b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_TSSI, tmp);
    
    	if (core2or5 && (type == B43_NPHY_RSSI_TSSI_Q))
    
    		b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_TSSI, tmp);
    }
    
    
    static void b43_nphy_rev2_rssi_select(struct b43_wldev *dev, u8 code, u8 type)
    
    	if (type < 3)
    		val = 0;
    	else if (type == 6)
    		val = 1;
    	else if (type == 3)
    		val = 2;
    	else
    		val = 3;
    
    	val = (val << 12) | (val << 14);
    	b43_phy_maskset(dev, B43_NPHY_AFECTL_C1, 0x0FFF, val);
    	b43_phy_maskset(dev, B43_NPHY_AFECTL_C2, 0x0FFF, val);
    
    	if (type < 3) {
    		b43_phy_maskset(dev, B43_NPHY_RFCTL_RSSIO1, 0xFFCF,
    				(type + 1) << 4);
    		b43_phy_maskset(dev, B43_NPHY_RFCTL_RSSIO2, 0xFFCF,
    				(type + 1) << 4);
    	}
    
    		b43_phy_mask(dev, B43_NPHY_AFECTL_OVER, ~0x3000);
    
    			b43_phy_mask(dev, B43_NPHY_RFCTL_CMD,
    				~(B43_NPHY_RFCTL_CMD_RXEN |
    				  B43_NPHY_RFCTL_CMD_CORESEL));
    			b43_phy_mask(dev, B43_NPHY_RFCTL_OVER,
    				~(0x1 << 12 |
    				  0x1 << 5 |
    				  0x1 << 1 |
    				  0x1));
    			b43_phy_mask(dev, B43_NPHY_RFCTL_CMD,
    				~B43_NPHY_RFCTL_CMD_START);
    
    			b43_phy_mask(dev, B43_NPHY_RFCTL_OVER, ~0x1);
    
    		b43_phy_set(dev, B43_NPHY_AFECTL_OVER, 0x3000);
    
    		if (type < 3) {
    			b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD,
    
    				~(B43_NPHY_RFCTL_CMD_RXEN |
    				  B43_NPHY_RFCTL_CMD_CORESEL),
    				(B43_NPHY_RFCTL_CMD_RXEN |
    				 code << B43_NPHY_RFCTL_CMD_CORESEL_SHIFT));
    			b43_phy_set(dev, B43_NPHY_RFCTL_OVER,
    				(0x1 << 12 |
    				  0x1 << 5 |
    				  0x1 << 1 |
    				  0x1));
    			b43_phy_set(dev, B43_NPHY_RFCTL_CMD,
    				B43_NPHY_RFCTL_CMD_START);
    
    			b43_phy_mask(dev, B43_NPHY_RFCTL_OVER, ~0x1);
    
    static void b43_nphy_rev3_rssi_select(struct b43_wldev *dev, u8 code, u8 type)
    {
    
    	struct b43_phy_n *nphy = dev->phy.n;
    	u8 i;
    	u16 reg, val;
    
    	if (code == 0) {
    		b43_phy_mask(dev, B43_NPHY_AFECTL_OVER1, 0xFDFF);
    		b43_phy_mask(dev, B43_NPHY_AFECTL_OVER, 0xFDFF);
    		b43_phy_mask(dev, B43_NPHY_AFECTL_C1, 0xFCFF);
    		b43_phy_mask(dev, B43_NPHY_AFECTL_C2, 0xFCFF);
    		b43_phy_mask(dev, B43_NPHY_TXF_40CO_B1S0, 0xFFDF);
    		b43_phy_mask(dev, B43_NPHY_TXF_40CO_B32S1, 0xFFDF);
    		b43_phy_mask(dev, B43_NPHY_RFCTL_LUT_TRSW_UP1, 0xFFC3);
    		b43_phy_mask(dev, B43_NPHY_RFCTL_LUT_TRSW_UP2, 0xFFC3);
    	} else {
    		for (i = 0; i < 2; i++) {
    			if ((code == 1 && i == 1) || (code == 2 && !i))
    				continue;
    
    			reg = (i == 0) ?
    				B43_NPHY_AFECTL_OVER1 : B43_NPHY_AFECTL_OVER;
    			b43_phy_maskset(dev, reg, 0xFDFF, 0x0200);
    
    			if (type < 3) {
    				reg = (i == 0) ?
    					B43_NPHY_AFECTL_C1 :
    					B43_NPHY_AFECTL_C2;
    				b43_phy_maskset(dev, reg, 0xFCFF, 0);
    
    				reg = (i == 0) ?
    					B43_NPHY_RFCTL_LUT_TRSW_UP1 :
    					B43_NPHY_RFCTL_LUT_TRSW_UP2;
    				b43_phy_maskset(dev, reg, 0xFFC3, 0);
    
    				if (type == 0)
    					val = (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) ? 4 : 8;
    				else if (type == 1)
    					val = 16;
    				else
    					val = 32;
    				b43_phy_set(dev, reg, val);
    
    				reg = (i == 0) ?
    					B43_NPHY_TXF_40CO_B1S0 :
    					B43_NPHY_TXF_40CO_B32S1;
    				b43_phy_set(dev, reg, 0x0020);
    			} else {
    				if (type == 6)
    					val = 0x0100;
    				else if (type == 3)
    					val = 0x0200;
    				else
    					val = 0x0300;
    
    				reg = (i == 0) ?
    					B43_NPHY_AFECTL_C1 :
    					B43_NPHY_AFECTL_C2;
    
    				b43_phy_maskset(dev, reg, 0xFCFF, val);
    				b43_phy_maskset(dev, reg, 0xF3FF, val << 2);
    
    				if (type != 3 && type != 6) {
    					enum ieee80211_band band =
    						b43_current_band(dev->wl);
    
    					if ((nphy->ipa2g_on &&
    						band == IEEE80211_BAND_2GHZ) ||
    						(nphy->ipa5g_on &&
    						band == IEEE80211_BAND_5GHZ))
    						val = (band == IEEE80211_BAND_5GHZ) ? 0xC : 0xE;
    					else
    						val = 0x11;
    					reg = (i == 0) ? 0x2000 : 0x3000;
    					reg |= B2055_PADDRV;
    					b43_radio_write16(dev, reg, val);
    
    					reg = (i == 0) ?
    						B43_NPHY_AFECTL_OVER1 :
    						B43_NPHY_AFECTL_OVER;
    					b43_phy_set(dev, reg, 0x0200);
    				}
    			}
    		}
    	}
    
    }
    
    /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSISel */
    static void b43_nphy_rssi_select(struct b43_wldev *dev, u8 code, u8 type)
    {
    	if (dev->phy.rev >= 3)
    		b43_nphy_rev3_rssi_select(dev, code, type);
    	else
    		b43_nphy_rev2_rssi_select(dev, code, type);
    }
    
    
    /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SetRssi2055Vcm */
    static void b43_nphy_set_rssi_2055_vcm(struct b43_wldev *dev, u8 type, u8 *buf)
    {
    	int i;
    	for (i = 0; i < 2; i++) {
    		if (type == 2) {
    			if (i == 0) {
    				b43_radio_maskset(dev, B2055_C1_B0NB_RSSIVCM,
    						  0xFC, buf[0]);
    				b43_radio_maskset(dev, B2055_C1_RX_BB_RSSICTL5,
    						  0xFC, buf[1]);
    			} else {
    				b43_radio_maskset(dev, B2055_C2_B0NB_RSSIVCM,
    						  0xFC, buf[2 * i]);
    				b43_radio_maskset(dev, B2055_C2_RX_BB_RSSICTL5,
    						  0xFC, buf[2 * i + 1]);
    			}
    		} else {
    			if (i == 0)
    				b43_radio_maskset(dev, B2055_C1_RX_BB_RSSICTL5,
    						  0xF3, buf[0] << 2);
    			else
    				b43_radio_maskset(dev, B2055_C2_RX_BB_RSSICTL5,
    						  0xF3, buf[2 * i + 1] << 2);
    		}
    	}
    }
    
    /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/PollRssi */
    static int b43_nphy_poll_rssi(struct b43_wldev *dev, u8 type, s32 *buf,
    				u8 nsamp)
    {
    	int i;
    	int out;
    	u16 save_regs_phy[9];
    	u16 s[2];
    
    	if (dev->phy.rev >= 3) {
    		save_regs_phy[0] = b43_phy_read(dev,
    						B43_NPHY_RFCTL_LUT_TRSW_UP1);