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

lo.c (26769B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3
      4  Broadcom B43 wireless driver
      5
      6  G PHY LO (LocalOscillator) Measuring and Control routines
      7
      8  Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
      9  Copyright (c) 2005, 2006 Stefano Brivio <stefano.brivio@polimi.it>
     10  Copyright (c) 2005-2007 Michael Buesch <m@bues.ch>
     11  Copyright (c) 2005, 2006 Danny van Dyk <kugelfang@gentoo.org>
     12  Copyright (c) 2005, 2006 Andreas Jaggi <andreas.jaggi@waterwave.ch>
     13
     14
     15*/
     16
     17#include "b43.h"
     18#include "lo.h"
     19#include "phy_g.h"
     20#include "main.h"
     21
     22#include <linux/delay.h>
     23#include <linux/sched.h>
     24#include <linux/slab.h>
     25
     26
     27static struct b43_lo_calib *b43_find_lo_calib(struct b43_txpower_lo_control *lo,
     28					      const struct b43_bbatt *bbatt,
     29					       const struct b43_rfatt *rfatt)
     30{
     31	struct b43_lo_calib *c;
     32
     33	list_for_each_entry(c, &lo->calib_list, list) {
     34		if (!b43_compare_bbatt(&c->bbatt, bbatt))
     35			continue;
     36		if (!b43_compare_rfatt(&c->rfatt, rfatt))
     37			continue;
     38		return c;
     39	}
     40
     41	return NULL;
     42}
     43
     44/* Write the LocalOscillator Control (adjust) value-pair. */
     45static void b43_lo_write(struct b43_wldev *dev, struct b43_loctl *control)
     46{
     47	struct b43_phy *phy = &dev->phy;
     48	u16 value;
     49
     50	if (B43_DEBUG) {
     51		if (unlikely(abs(control->i) > 16 || abs(control->q) > 16)) {
     52			b43dbg(dev->wl, "Invalid LO control pair "
     53			       "(I: %d, Q: %d)\n", control->i, control->q);
     54			dump_stack();
     55			return;
     56		}
     57	}
     58	B43_WARN_ON(phy->type != B43_PHYTYPE_G);
     59
     60	value = (u8) (control->q);
     61	value |= ((u8) (control->i)) << 8;
     62	b43_phy_write(dev, B43_PHY_LO_CTL, value);
     63}
     64
     65static u16 lo_measure_feedthrough(struct b43_wldev *dev,
     66				  u16 lna, u16 pga, u16 trsw_rx)
     67{
     68	struct b43_phy *phy = &dev->phy;
     69	u16 rfover;
     70	u16 feedthrough;
     71
     72	if (phy->gmode) {
     73		lna <<= B43_PHY_RFOVERVAL_LNA_SHIFT;
     74		pga <<= B43_PHY_RFOVERVAL_PGA_SHIFT;
     75
     76		B43_WARN_ON(lna & ~B43_PHY_RFOVERVAL_LNA);
     77		B43_WARN_ON(pga & ~B43_PHY_RFOVERVAL_PGA);
     78/*FIXME This assertion fails		B43_WARN_ON(trsw_rx & ~(B43_PHY_RFOVERVAL_TRSWRX |
     79				    B43_PHY_RFOVERVAL_BW));
     80*/
     81		trsw_rx &= (B43_PHY_RFOVERVAL_TRSWRX | B43_PHY_RFOVERVAL_BW);
     82
     83		/* Construct the RF Override Value */
     84		rfover = B43_PHY_RFOVERVAL_UNK;
     85		rfover |= pga;
     86		rfover |= lna;
     87		rfover |= trsw_rx;
     88		if ((dev->dev->bus_sprom->boardflags_lo & B43_BFL_EXTLNA)
     89		    && phy->rev > 6)
     90			rfover |= B43_PHY_RFOVERVAL_EXTLNA;
     91
     92		b43_phy_write(dev, B43_PHY_PGACTL, 0xE300);
     93		b43_phy_write(dev, B43_PHY_RFOVERVAL, rfover);
     94		udelay(10);
     95		rfover |= B43_PHY_RFOVERVAL_BW_LBW;
     96		b43_phy_write(dev, B43_PHY_RFOVERVAL, rfover);
     97		udelay(10);
     98		rfover |= B43_PHY_RFOVERVAL_BW_LPF;
     99		b43_phy_write(dev, B43_PHY_RFOVERVAL, rfover);
    100		udelay(10);
    101		b43_phy_write(dev, B43_PHY_PGACTL, 0xF300);
    102	} else {
    103		pga |= B43_PHY_PGACTL_UNKNOWN;
    104		b43_phy_write(dev, B43_PHY_PGACTL, pga);
    105		udelay(10);
    106		pga |= B43_PHY_PGACTL_LOWBANDW;
    107		b43_phy_write(dev, B43_PHY_PGACTL, pga);
    108		udelay(10);
    109		pga |= B43_PHY_PGACTL_LPF;
    110		b43_phy_write(dev, B43_PHY_PGACTL, pga);
    111	}
    112	udelay(21);
    113	feedthrough = b43_phy_read(dev, B43_PHY_LO_LEAKAGE);
    114
    115	/* This is a good place to check if we need to relax a bit,
    116	 * as this is the main function called regularly
    117	 * in the LO calibration. */
    118	cond_resched();
    119
    120	return feedthrough;
    121}
    122
    123/* TXCTL Register and Value Table.
    124 * Returns the "TXCTL Register".
    125 * "value" is the "TXCTL Value".
    126 * "pad_mix_gain" is the PAD Mixer Gain.
    127 */
    128static u16 lo_txctl_register_table(struct b43_wldev *dev,
    129				   u16 *value, u16 *pad_mix_gain)
    130{
    131	struct b43_phy *phy = &dev->phy;
    132	u16 reg, v, padmix;
    133
    134	if (phy->type == B43_PHYTYPE_B) {
    135		v = 0x30;
    136		if (phy->radio_rev <= 5) {
    137			reg = 0x43;
    138			padmix = 0;
    139		} else {
    140			reg = 0x52;
    141			padmix = 5;
    142		}
    143	} else {
    144		if (phy->rev >= 2 && phy->radio_rev == 8) {
    145			reg = 0x43;
    146			v = 0x10;
    147			padmix = 2;
    148		} else {
    149			reg = 0x52;
    150			v = 0x30;
    151			padmix = 5;
    152		}
    153	}
    154	if (value)
    155		*value = v;
    156	if (pad_mix_gain)
    157		*pad_mix_gain = padmix;
    158
    159	return reg;
    160}
    161
    162static void lo_measure_txctl_values(struct b43_wldev *dev)
    163{
    164	struct b43_phy *phy = &dev->phy;
    165	struct b43_phy_g *gphy = phy->g;
    166	struct b43_txpower_lo_control *lo = gphy->lo_control;
    167	u16 reg, mask;
    168	u16 trsw_rx, pga;
    169	u16 radio_pctl_reg;
    170
    171	static const u8 tx_bias_values[] = {
    172		0x09, 0x08, 0x0A, 0x01, 0x00,
    173		0x02, 0x05, 0x04, 0x06,
    174	};
    175	static const u8 tx_magn_values[] = {
    176		0x70, 0x40,
    177	};
    178
    179	if (!has_loopback_gain(phy)) {
    180		radio_pctl_reg = 6;
    181		trsw_rx = 2;
    182		pga = 0;
    183	} else {
    184		int lb_gain;	/* Loopback gain (in dB) */
    185
    186		trsw_rx = 0;
    187		lb_gain = gphy->max_lb_gain / 2;
    188		if (lb_gain > 10) {
    189			radio_pctl_reg = 0;
    190			pga = abs(10 - lb_gain) / 6;
    191			pga = clamp_val(pga, 0, 15);
    192		} else {
    193			int cmp_val;
    194			int tmp;
    195
    196			pga = 0;
    197			cmp_val = 0x24;
    198			if ((phy->rev >= 2) &&
    199			    (phy->radio_ver == 0x2050) && (phy->radio_rev == 8))
    200				cmp_val = 0x3C;
    201			tmp = lb_gain;
    202			if ((10 - lb_gain) < cmp_val)
    203				tmp = (10 - lb_gain);
    204			if (tmp < 0)
    205				tmp += 6;
    206			else
    207				tmp += 3;
    208			cmp_val /= 4;
    209			tmp /= 4;
    210			if (tmp >= cmp_val)
    211				radio_pctl_reg = cmp_val;
    212			else
    213				radio_pctl_reg = tmp;
    214		}
    215	}
    216	b43_radio_maskset(dev, 0x43, 0xFFF0, radio_pctl_reg);
    217	b43_gphy_set_baseband_attenuation(dev, 2);
    218
    219	reg = lo_txctl_register_table(dev, &mask, NULL);
    220	mask = ~mask;
    221	b43_radio_mask(dev, reg, mask);
    222
    223	if (has_tx_magnification(phy)) {
    224		int i, j;
    225		int feedthrough;
    226		int min_feedth = 0xFFFF;
    227		u8 tx_magn, tx_bias;
    228
    229		for (i = 0; i < ARRAY_SIZE(tx_magn_values); i++) {
    230			tx_magn = tx_magn_values[i];
    231			b43_radio_maskset(dev, 0x52, 0xFF0F, tx_magn);
    232			for (j = 0; j < ARRAY_SIZE(tx_bias_values); j++) {
    233				tx_bias = tx_bias_values[j];
    234				b43_radio_maskset(dev, 0x52, 0xFFF0, tx_bias);
    235				feedthrough =
    236				    lo_measure_feedthrough(dev, 0, pga,
    237							   trsw_rx);
    238				if (feedthrough < min_feedth) {
    239					lo->tx_bias = tx_bias;
    240					lo->tx_magn = tx_magn;
    241					min_feedth = feedthrough;
    242				}
    243				if (lo->tx_bias == 0)
    244					break;
    245			}
    246			b43_radio_write16(dev, 0x52,
    247					  (b43_radio_read16(dev, 0x52)
    248					   & 0xFF00) | lo->tx_bias | lo->
    249					  tx_magn);
    250		}
    251	} else {
    252		lo->tx_magn = 0;
    253		lo->tx_bias = 0;
    254		b43_radio_mask(dev, 0x52, 0xFFF0);	/* TX bias == 0 */
    255	}
    256	lo->txctl_measured_time = jiffies;
    257}
    258
    259static void lo_read_power_vector(struct b43_wldev *dev)
    260{
    261	struct b43_phy *phy = &dev->phy;
    262	struct b43_phy_g *gphy = phy->g;
    263	struct b43_txpower_lo_control *lo = gphy->lo_control;
    264	int i;
    265	u64 tmp;
    266	u64 power_vector = 0;
    267
    268	for (i = 0; i < 8; i += 2) {
    269		tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x310 + i);
    270		power_vector |= (tmp << (i * 8));
    271		/* Clear the vector on the device. */
    272		b43_shm_write16(dev, B43_SHM_SHARED, 0x310 + i, 0);
    273	}
    274	if (power_vector)
    275		lo->power_vector = power_vector;
    276	lo->pwr_vec_read_time = jiffies;
    277}
    278
    279/* 802.11/LO/GPHY/MeasuringGains */
    280static void lo_measure_gain_values(struct b43_wldev *dev,
    281				   s16 max_rx_gain, int use_trsw_rx)
    282{
    283	struct b43_phy *phy = &dev->phy;
    284	struct b43_phy_g *gphy = phy->g;
    285	u16 tmp;
    286
    287	if (max_rx_gain < 0)
    288		max_rx_gain = 0;
    289
    290	if (has_loopback_gain(phy)) {
    291		int trsw_rx_gain;
    292
    293		if (use_trsw_rx) {
    294			trsw_rx_gain = gphy->trsw_rx_gain / 2;
    295			if (max_rx_gain >= trsw_rx_gain) {
    296				trsw_rx_gain = max_rx_gain - trsw_rx_gain;
    297			}
    298		} else
    299			trsw_rx_gain = max_rx_gain;
    300		if (trsw_rx_gain < 9) {
    301			gphy->lna_lod_gain = 0;
    302		} else {
    303			gphy->lna_lod_gain = 1;
    304			trsw_rx_gain -= 8;
    305		}
    306		trsw_rx_gain = clamp_val(trsw_rx_gain, 0, 0x2D);
    307		gphy->pga_gain = trsw_rx_gain / 3;
    308		if (gphy->pga_gain >= 5) {
    309			gphy->pga_gain -= 5;
    310			gphy->lna_gain = 2;
    311		} else
    312			gphy->lna_gain = 0;
    313	} else {
    314		gphy->lna_gain = 0;
    315		gphy->trsw_rx_gain = 0x20;
    316		if (max_rx_gain >= 0x14) {
    317			gphy->lna_lod_gain = 1;
    318			gphy->pga_gain = 2;
    319		} else if (max_rx_gain >= 0x12) {
    320			gphy->lna_lod_gain = 1;
    321			gphy->pga_gain = 1;
    322		} else if (max_rx_gain >= 0xF) {
    323			gphy->lna_lod_gain = 1;
    324			gphy->pga_gain = 0;
    325		} else {
    326			gphy->lna_lod_gain = 0;
    327			gphy->pga_gain = 0;
    328		}
    329	}
    330
    331	tmp = b43_radio_read16(dev, 0x7A);
    332	if (gphy->lna_lod_gain == 0)
    333		tmp &= ~0x0008;
    334	else
    335		tmp |= 0x0008;
    336	b43_radio_write16(dev, 0x7A, tmp);
    337}
    338
    339struct lo_g_saved_values {
    340	u8 old_channel;
    341
    342	/* Core registers */
    343	u16 reg_3F4;
    344	u16 reg_3E2;
    345
    346	/* PHY registers */
    347	u16 phy_lo_mask;
    348	u16 phy_extg_01;
    349	u16 phy_dacctl_hwpctl;
    350	u16 phy_dacctl;
    351	u16 phy_cck_14;
    352	u16 phy_hpwr_tssictl;
    353	u16 phy_analogover;
    354	u16 phy_analogoverval;
    355	u16 phy_rfover;
    356	u16 phy_rfoverval;
    357	u16 phy_classctl;
    358	u16 phy_cck_3E;
    359	u16 phy_crs0;
    360	u16 phy_pgactl;
    361	u16 phy_cck_2A;
    362	u16 phy_syncctl;
    363	u16 phy_cck_30;
    364	u16 phy_cck_06;
    365
    366	/* Radio registers */
    367	u16 radio_43;
    368	u16 radio_7A;
    369	u16 radio_52;
    370};
    371
    372static void lo_measure_setup(struct b43_wldev *dev,
    373			     struct lo_g_saved_values *sav)
    374{
    375	struct ssb_sprom *sprom = dev->dev->bus_sprom;
    376	struct b43_phy *phy = &dev->phy;
    377	struct b43_phy_g *gphy = phy->g;
    378	struct b43_txpower_lo_control *lo = gphy->lo_control;
    379	u16 tmp;
    380
    381	if (b43_has_hardware_pctl(dev)) {
    382		sav->phy_lo_mask = b43_phy_read(dev, B43_PHY_LO_MASK);
    383		sav->phy_extg_01 = b43_phy_read(dev, B43_PHY_EXTG(0x01));
    384		sav->phy_dacctl_hwpctl = b43_phy_read(dev, B43_PHY_DACCTL);
    385		sav->phy_cck_14 = b43_phy_read(dev, B43_PHY_CCK(0x14));
    386		sav->phy_hpwr_tssictl = b43_phy_read(dev, B43_PHY_HPWR_TSSICTL);
    387
    388		b43_phy_set(dev, B43_PHY_HPWR_TSSICTL, 0x100);
    389		b43_phy_set(dev, B43_PHY_EXTG(0x01), 0x40);
    390		b43_phy_set(dev, B43_PHY_DACCTL, 0x40);
    391		b43_phy_set(dev, B43_PHY_CCK(0x14), 0x200);
    392	}
    393	if (phy->type == B43_PHYTYPE_B &&
    394	    phy->radio_ver == 0x2050 && phy->radio_rev < 6) {
    395		b43_phy_write(dev, B43_PHY_CCK(0x16), 0x410);
    396		b43_phy_write(dev, B43_PHY_CCK(0x17), 0x820);
    397	}
    398	if (phy->rev >= 2) {
    399		sav->phy_analogover = b43_phy_read(dev, B43_PHY_ANALOGOVER);
    400		sav->phy_analogoverval =
    401		    b43_phy_read(dev, B43_PHY_ANALOGOVERVAL);
    402		sav->phy_rfover = b43_phy_read(dev, B43_PHY_RFOVER);
    403		sav->phy_rfoverval = b43_phy_read(dev, B43_PHY_RFOVERVAL);
    404		sav->phy_classctl = b43_phy_read(dev, B43_PHY_CLASSCTL);
    405		sav->phy_cck_3E = b43_phy_read(dev, B43_PHY_CCK(0x3E));
    406		sav->phy_crs0 = b43_phy_read(dev, B43_PHY_CRS0);
    407
    408		b43_phy_mask(dev, B43_PHY_CLASSCTL, 0xFFFC);
    409		b43_phy_mask(dev, B43_PHY_CRS0, 0x7FFF);
    410		b43_phy_set(dev, B43_PHY_ANALOGOVER, 0x0003);
    411		b43_phy_mask(dev, B43_PHY_ANALOGOVERVAL, 0xFFFC);
    412		if (phy->type == B43_PHYTYPE_G) {
    413			if ((phy->rev >= 7) &&
    414			    (sprom->boardflags_lo & B43_BFL_EXTLNA)) {
    415				b43_phy_write(dev, B43_PHY_RFOVER, 0x933);
    416			} else {
    417				b43_phy_write(dev, B43_PHY_RFOVER, 0x133);
    418			}
    419		} else {
    420			b43_phy_write(dev, B43_PHY_RFOVER, 0);
    421		}
    422		b43_phy_write(dev, B43_PHY_CCK(0x3E), 0);
    423	}
    424	sav->reg_3F4 = b43_read16(dev, 0x3F4);
    425	sav->reg_3E2 = b43_read16(dev, 0x3E2);
    426	sav->radio_43 = b43_radio_read16(dev, 0x43);
    427	sav->radio_7A = b43_radio_read16(dev, 0x7A);
    428	sav->phy_pgactl = b43_phy_read(dev, B43_PHY_PGACTL);
    429	sav->phy_cck_2A = b43_phy_read(dev, B43_PHY_CCK(0x2A));
    430	sav->phy_syncctl = b43_phy_read(dev, B43_PHY_SYNCCTL);
    431	sav->phy_dacctl = b43_phy_read(dev, B43_PHY_DACCTL);
    432
    433	if (!has_tx_magnification(phy)) {
    434		sav->radio_52 = b43_radio_read16(dev, 0x52);
    435		sav->radio_52 &= 0x00F0;
    436	}
    437	if (phy->type == B43_PHYTYPE_B) {
    438		sav->phy_cck_30 = b43_phy_read(dev, B43_PHY_CCK(0x30));
    439		sav->phy_cck_06 = b43_phy_read(dev, B43_PHY_CCK(0x06));
    440		b43_phy_write(dev, B43_PHY_CCK(0x30), 0x00FF);
    441		b43_phy_write(dev, B43_PHY_CCK(0x06), 0x3F3F);
    442	} else {
    443		b43_write16(dev, 0x3E2, b43_read16(dev, 0x3E2)
    444			    | 0x8000);
    445	}
    446	b43_write16(dev, 0x3F4, b43_read16(dev, 0x3F4)
    447		    & 0xF000);
    448
    449	tmp =
    450	    (phy->type == B43_PHYTYPE_G) ? B43_PHY_LO_MASK : B43_PHY_CCK(0x2E);
    451	b43_phy_write(dev, tmp, 0x007F);
    452
    453	tmp = sav->phy_syncctl;
    454	b43_phy_write(dev, B43_PHY_SYNCCTL, tmp & 0xFF7F);
    455	tmp = sav->radio_7A;
    456	b43_radio_write16(dev, 0x007A, tmp & 0xFFF0);
    457
    458	b43_phy_write(dev, B43_PHY_CCK(0x2A), 0x8A3);
    459	if (phy->type == B43_PHYTYPE_G ||
    460	    (phy->type == B43_PHYTYPE_B &&
    461	     phy->radio_ver == 0x2050 && phy->radio_rev >= 6)) {
    462		b43_phy_write(dev, B43_PHY_CCK(0x2B), 0x1003);
    463	} else
    464		b43_phy_write(dev, B43_PHY_CCK(0x2B), 0x0802);
    465	if (phy->rev >= 2)
    466		b43_dummy_transmission(dev, false, true);
    467	b43_gphy_channel_switch(dev, 6, 0);
    468	b43_radio_read16(dev, 0x51);	/* dummy read */
    469	if (phy->type == B43_PHYTYPE_G)
    470		b43_phy_write(dev, B43_PHY_CCK(0x2F), 0);
    471
    472	/* Re-measure the txctl values, if needed. */
    473	if (time_before(lo->txctl_measured_time,
    474			jiffies - B43_LO_TXCTL_EXPIRE))
    475		lo_measure_txctl_values(dev);
    476
    477	if (phy->type == B43_PHYTYPE_G && phy->rev >= 3) {
    478		b43_phy_write(dev, B43_PHY_LO_MASK, 0xC078);
    479	} else {
    480		if (phy->type == B43_PHYTYPE_B)
    481			b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8078);
    482		else
    483			b43_phy_write(dev, B43_PHY_LO_MASK, 0x8078);
    484	}
    485}
    486
    487static void lo_measure_restore(struct b43_wldev *dev,
    488			       struct lo_g_saved_values *sav)
    489{
    490	struct b43_phy *phy = &dev->phy;
    491	struct b43_phy_g *gphy = phy->g;
    492	u16 tmp;
    493
    494	if (phy->rev >= 2) {
    495		b43_phy_write(dev, B43_PHY_PGACTL, 0xE300);
    496		tmp = (gphy->pga_gain << 8);
    497		b43_phy_write(dev, B43_PHY_RFOVERVAL, tmp | 0xA0);
    498		udelay(5);
    499		b43_phy_write(dev, B43_PHY_RFOVERVAL, tmp | 0xA2);
    500		udelay(2);
    501		b43_phy_write(dev, B43_PHY_RFOVERVAL, tmp | 0xA3);
    502	} else {
    503		tmp = (gphy->pga_gain | 0xEFA0);
    504		b43_phy_write(dev, B43_PHY_PGACTL, tmp);
    505	}
    506	if (phy->type == B43_PHYTYPE_G) {
    507		if (phy->rev >= 3)
    508			b43_phy_write(dev, B43_PHY_CCK(0x2E), 0xC078);
    509		else
    510			b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8078);
    511		if (phy->rev >= 2)
    512			b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x0202);
    513		else
    514			b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x0101);
    515	}
    516	b43_write16(dev, 0x3F4, sav->reg_3F4);
    517	b43_phy_write(dev, B43_PHY_PGACTL, sav->phy_pgactl);
    518	b43_phy_write(dev, B43_PHY_CCK(0x2A), sav->phy_cck_2A);
    519	b43_phy_write(dev, B43_PHY_SYNCCTL, sav->phy_syncctl);
    520	b43_phy_write(dev, B43_PHY_DACCTL, sav->phy_dacctl);
    521	b43_radio_write16(dev, 0x43, sav->radio_43);
    522	b43_radio_write16(dev, 0x7A, sav->radio_7A);
    523	if (!has_tx_magnification(phy)) {
    524		tmp = sav->radio_52;
    525		b43_radio_maskset(dev, 0x52, 0xFF0F, tmp);
    526	}
    527	b43_write16(dev, 0x3E2, sav->reg_3E2);
    528	if (phy->type == B43_PHYTYPE_B &&
    529	    phy->radio_ver == 0x2050 && phy->radio_rev <= 5) {
    530		b43_phy_write(dev, B43_PHY_CCK(0x30), sav->phy_cck_30);
    531		b43_phy_write(dev, B43_PHY_CCK(0x06), sav->phy_cck_06);
    532	}
    533	if (phy->rev >= 2) {
    534		b43_phy_write(dev, B43_PHY_ANALOGOVER, sav->phy_analogover);
    535		b43_phy_write(dev, B43_PHY_ANALOGOVERVAL,
    536			      sav->phy_analogoverval);
    537		b43_phy_write(dev, B43_PHY_CLASSCTL, sav->phy_classctl);
    538		b43_phy_write(dev, B43_PHY_RFOVER, sav->phy_rfover);
    539		b43_phy_write(dev, B43_PHY_RFOVERVAL, sav->phy_rfoverval);
    540		b43_phy_write(dev, B43_PHY_CCK(0x3E), sav->phy_cck_3E);
    541		b43_phy_write(dev, B43_PHY_CRS0, sav->phy_crs0);
    542	}
    543	if (b43_has_hardware_pctl(dev)) {
    544		tmp = (sav->phy_lo_mask & 0xBFFF);
    545		b43_phy_write(dev, B43_PHY_LO_MASK, tmp);
    546		b43_phy_write(dev, B43_PHY_EXTG(0x01), sav->phy_extg_01);
    547		b43_phy_write(dev, B43_PHY_DACCTL, sav->phy_dacctl_hwpctl);
    548		b43_phy_write(dev, B43_PHY_CCK(0x14), sav->phy_cck_14);
    549		b43_phy_write(dev, B43_PHY_HPWR_TSSICTL, sav->phy_hpwr_tssictl);
    550	}
    551	b43_gphy_channel_switch(dev, sav->old_channel, 1);
    552}
    553
    554struct b43_lo_g_statemachine {
    555	int current_state;
    556	int nr_measured;
    557	int state_val_multiplier;
    558	u16 lowest_feedth;
    559	struct b43_loctl min_loctl;
    560};
    561
    562/* Loop over each possible value in this state. */
    563static int lo_probe_possible_loctls(struct b43_wldev *dev,
    564				    struct b43_loctl *probe_loctl,
    565				    struct b43_lo_g_statemachine *d)
    566{
    567	struct b43_phy *phy = &dev->phy;
    568	struct b43_phy_g *gphy = phy->g;
    569	struct b43_loctl test_loctl;
    570	struct b43_loctl orig_loctl;
    571	struct b43_loctl prev_loctl = {
    572		.i = -100,
    573		.q = -100,
    574	};
    575	int i;
    576	int begin, end;
    577	int found_lower = 0;
    578	u16 feedth;
    579
    580	static const struct b43_loctl modifiers[] = {
    581		{.i = 1,.q = 1,},
    582		{.i = 1,.q = 0,},
    583		{.i = 1,.q = -1,},
    584		{.i = 0,.q = -1,},
    585		{.i = -1,.q = -1,},
    586		{.i = -1,.q = 0,},
    587		{.i = -1,.q = 1,},
    588		{.i = 0,.q = 1,},
    589	};
    590
    591	if (d->current_state == 0) {
    592		begin = 1;
    593		end = 8;
    594	} else if (d->current_state % 2 == 0) {
    595		begin = d->current_state - 1;
    596		end = d->current_state + 1;
    597	} else {
    598		begin = d->current_state - 2;
    599		end = d->current_state + 2;
    600	}
    601	if (begin < 1)
    602		begin += 8;
    603	if (end > 8)
    604		end -= 8;
    605
    606	memcpy(&orig_loctl, probe_loctl, sizeof(struct b43_loctl));
    607	i = begin;
    608	d->current_state = i;
    609	while (1) {
    610		B43_WARN_ON(!(i >= 1 && i <= 8));
    611		memcpy(&test_loctl, &orig_loctl, sizeof(struct b43_loctl));
    612		test_loctl.i += modifiers[i - 1].i * d->state_val_multiplier;
    613		test_loctl.q += modifiers[i - 1].q * d->state_val_multiplier;
    614		if ((test_loctl.i != prev_loctl.i ||
    615		     test_loctl.q != prev_loctl.q) &&
    616		    (abs(test_loctl.i) <= 16 && abs(test_loctl.q) <= 16)) {
    617			b43_lo_write(dev, &test_loctl);
    618			feedth = lo_measure_feedthrough(dev, gphy->lna_gain,
    619							gphy->pga_gain,
    620							gphy->trsw_rx_gain);
    621			if (feedth < d->lowest_feedth) {
    622				memcpy(probe_loctl, &test_loctl,
    623				       sizeof(struct b43_loctl));
    624				found_lower = 1;
    625				d->lowest_feedth = feedth;
    626				if ((d->nr_measured < 2) &&
    627				    !has_loopback_gain(phy))
    628					break;
    629			}
    630		}
    631		memcpy(&prev_loctl, &test_loctl, sizeof(prev_loctl));
    632		if (i == end)
    633			break;
    634		if (i == 8)
    635			i = 1;
    636		else
    637			i++;
    638		d->current_state = i;
    639	}
    640
    641	return found_lower;
    642}
    643
    644static void lo_probe_loctls_statemachine(struct b43_wldev *dev,
    645					 struct b43_loctl *loctl,
    646					 int *max_rx_gain)
    647{
    648	struct b43_phy *phy = &dev->phy;
    649	struct b43_phy_g *gphy = phy->g;
    650	struct b43_lo_g_statemachine d;
    651	u16 feedth;
    652	int found_lower;
    653	struct b43_loctl probe_loctl;
    654	int max_repeat = 1, repeat_cnt = 0;
    655
    656	d.nr_measured = 0;
    657	d.state_val_multiplier = 1;
    658	if (has_loopback_gain(phy))
    659		d.state_val_multiplier = 3;
    660
    661	memcpy(&d.min_loctl, loctl, sizeof(struct b43_loctl));
    662	if (has_loopback_gain(phy))
    663		max_repeat = 4;
    664	do {
    665		b43_lo_write(dev, &d.min_loctl);
    666		feedth = lo_measure_feedthrough(dev, gphy->lna_gain,
    667						gphy->pga_gain,
    668						gphy->trsw_rx_gain);
    669		if (feedth < 0x258) {
    670			if (feedth >= 0x12C)
    671				*max_rx_gain += 6;
    672			else
    673				*max_rx_gain += 3;
    674			feedth = lo_measure_feedthrough(dev, gphy->lna_gain,
    675							gphy->pga_gain,
    676							gphy->trsw_rx_gain);
    677		}
    678		d.lowest_feedth = feedth;
    679
    680		d.current_state = 0;
    681		do {
    682			B43_WARN_ON(!
    683				    (d.current_state >= 0
    684				     && d.current_state <= 8));
    685			memcpy(&probe_loctl, &d.min_loctl,
    686			       sizeof(struct b43_loctl));
    687			found_lower =
    688			    lo_probe_possible_loctls(dev, &probe_loctl, &d);
    689			if (!found_lower)
    690				break;
    691			if ((probe_loctl.i == d.min_loctl.i) &&
    692			    (probe_loctl.q == d.min_loctl.q))
    693				break;
    694			memcpy(&d.min_loctl, &probe_loctl,
    695			       sizeof(struct b43_loctl));
    696			d.nr_measured++;
    697		} while (d.nr_measured < 24);
    698		memcpy(loctl, &d.min_loctl, sizeof(struct b43_loctl));
    699
    700		if (has_loopback_gain(phy)) {
    701			if (d.lowest_feedth > 0x1194)
    702				*max_rx_gain -= 6;
    703			else if (d.lowest_feedth < 0x5DC)
    704				*max_rx_gain += 3;
    705			if (repeat_cnt == 0) {
    706				if (d.lowest_feedth <= 0x5DC) {
    707					d.state_val_multiplier = 1;
    708					repeat_cnt++;
    709				} else
    710					d.state_val_multiplier = 2;
    711			} else if (repeat_cnt == 2)
    712				d.state_val_multiplier = 1;
    713		}
    714		lo_measure_gain_values(dev, *max_rx_gain,
    715				       has_loopback_gain(phy));
    716	} while (++repeat_cnt < max_repeat);
    717}
    718
    719static
    720struct b43_lo_calib *b43_calibrate_lo_setting(struct b43_wldev *dev,
    721					      const struct b43_bbatt *bbatt,
    722					      const struct b43_rfatt *rfatt)
    723{
    724	struct b43_phy *phy = &dev->phy;
    725	struct b43_phy_g *gphy = phy->g;
    726	struct b43_loctl loctl = {
    727		.i = 0,
    728		.q = 0,
    729	};
    730	int max_rx_gain;
    731	struct b43_lo_calib *cal;
    732	struct lo_g_saved_values saved_regs;
    733	/* Values from the "TXCTL Register and Value Table" */
    734	u16 txctl_reg;
    735	u16 txctl_value;
    736	u16 pad_mix_gain;
    737
    738	saved_regs.old_channel = phy->channel;
    739	b43_mac_suspend(dev);
    740	lo_measure_setup(dev, &saved_regs);
    741
    742	txctl_reg = lo_txctl_register_table(dev, &txctl_value, &pad_mix_gain);
    743
    744	b43_radio_maskset(dev, 0x43, 0xFFF0, rfatt->att);
    745	b43_radio_maskset(dev, txctl_reg, ~txctl_value, (rfatt->with_padmix ? txctl_value :0));
    746
    747	max_rx_gain = rfatt->att * 2;
    748	max_rx_gain += bbatt->att / 2;
    749	if (rfatt->with_padmix)
    750		max_rx_gain -= pad_mix_gain;
    751	if (has_loopback_gain(phy))
    752		max_rx_gain += gphy->max_lb_gain;
    753	lo_measure_gain_values(dev, max_rx_gain,
    754			       has_loopback_gain(phy));
    755
    756	b43_gphy_set_baseband_attenuation(dev, bbatt->att);
    757	lo_probe_loctls_statemachine(dev, &loctl, &max_rx_gain);
    758
    759	lo_measure_restore(dev, &saved_regs);
    760	b43_mac_enable(dev);
    761
    762	if (b43_debug(dev, B43_DBG_LO)) {
    763		b43dbg(dev->wl, "LO: Calibrated for BB(%u), RF(%u,%u) "
    764		       "=> I=%d Q=%d\n",
    765		       bbatt->att, rfatt->att, rfatt->with_padmix,
    766		       loctl.i, loctl.q);
    767	}
    768
    769	cal = kmalloc(sizeof(*cal), GFP_KERNEL);
    770	if (!cal) {
    771		b43warn(dev->wl, "LO calib: out of memory\n");
    772		return NULL;
    773	}
    774	memcpy(&cal->bbatt, bbatt, sizeof(*bbatt));
    775	memcpy(&cal->rfatt, rfatt, sizeof(*rfatt));
    776	memcpy(&cal->ctl, &loctl, sizeof(loctl));
    777	cal->calib_time = jiffies;
    778	INIT_LIST_HEAD(&cal->list);
    779
    780	return cal;
    781}
    782
    783/* Get a calibrated LO setting for the given attenuation values.
    784 * Might return a NULL pointer under OOM! */
    785static
    786struct b43_lo_calib *b43_get_calib_lo_settings(struct b43_wldev *dev,
    787					       const struct b43_bbatt *bbatt,
    788					       const struct b43_rfatt *rfatt)
    789{
    790	struct b43_txpower_lo_control *lo = dev->phy.g->lo_control;
    791	struct b43_lo_calib *c;
    792
    793	c = b43_find_lo_calib(lo, bbatt, rfatt);
    794	if (c)
    795		return c;
    796	/* Not in the list of calibrated LO settings.
    797	 * Calibrate it now. */
    798	c = b43_calibrate_lo_setting(dev, bbatt, rfatt);
    799	if (!c)
    800		return NULL;
    801	list_add(&c->list, &lo->calib_list);
    802
    803	return c;
    804}
    805
    806void b43_gphy_dc_lt_init(struct b43_wldev *dev, bool update_all)
    807{
    808	struct b43_phy *phy = &dev->phy;
    809	struct b43_phy_g *gphy = phy->g;
    810	struct b43_txpower_lo_control *lo = gphy->lo_control;
    811	int i;
    812	int rf_offset, bb_offset;
    813	const struct b43_rfatt *rfatt;
    814	const struct b43_bbatt *bbatt;
    815	u64 power_vector;
    816	bool table_changed = false;
    817
    818	BUILD_BUG_ON(B43_DC_LT_SIZE != 32);
    819	B43_WARN_ON(lo->rfatt_list.len * lo->bbatt_list.len > 64);
    820
    821	power_vector = lo->power_vector;
    822	if (!update_all && !power_vector)
    823		return; /* Nothing to do. */
    824
    825	/* Suspend the MAC now to avoid continuous suspend/enable
    826	 * cycles in the loop. */
    827	b43_mac_suspend(dev);
    828
    829	for (i = 0; i < B43_DC_LT_SIZE * 2; i++) {
    830		struct b43_lo_calib *cal;
    831		int idx;
    832		u16 val;
    833
    834		if (!update_all && !(power_vector & (((u64)1ULL) << i)))
    835			continue;
    836		/* Update the table entry for this power_vector bit.
    837		 * The table rows are RFatt entries and columns are BBatt. */
    838		bb_offset = i / lo->rfatt_list.len;
    839		rf_offset = i % lo->rfatt_list.len;
    840		bbatt = &(lo->bbatt_list.list[bb_offset]);
    841		rfatt = &(lo->rfatt_list.list[rf_offset]);
    842
    843		cal = b43_calibrate_lo_setting(dev, bbatt, rfatt);
    844		if (!cal) {
    845			b43warn(dev->wl, "LO: Could not "
    846				"calibrate DC table entry\n");
    847			continue;
    848		}
    849		/*FIXME: Is Q really in the low nibble? */
    850		val = (u8)(cal->ctl.q);
    851		val |= ((u8)(cal->ctl.i)) << 4;
    852		kfree(cal);
    853
    854		/* Get the index into the hardware DC LT. */
    855		idx = i / 2;
    856		/* Change the table in memory. */
    857		if (i % 2) {
    858			/* Change the high byte. */
    859			lo->dc_lt[idx] = (lo->dc_lt[idx] & 0x00FF)
    860					 | ((val & 0x00FF) << 8);
    861		} else {
    862			/* Change the low byte. */
    863			lo->dc_lt[idx] = (lo->dc_lt[idx] & 0xFF00)
    864					 | (val & 0x00FF);
    865		}
    866		table_changed = true;
    867	}
    868	if (table_changed) {
    869		/* The table changed in memory. Update the hardware table. */
    870		for (i = 0; i < B43_DC_LT_SIZE; i++)
    871			b43_phy_write(dev, 0x3A0 + i, lo->dc_lt[i]);
    872	}
    873	b43_mac_enable(dev);
    874}
    875
    876/* Fixup the RF attenuation value for the case where we are
    877 * using the PAD mixer. */
    878static inline void b43_lo_fixup_rfatt(struct b43_rfatt *rf)
    879{
    880	if (!rf->with_padmix)
    881		return;
    882	if ((rf->att != 1) && (rf->att != 2) && (rf->att != 3))
    883		rf->att = 4;
    884}
    885
    886void b43_lo_g_adjust(struct b43_wldev *dev)
    887{
    888	struct b43_phy_g *gphy = dev->phy.g;
    889	struct b43_lo_calib *cal;
    890	struct b43_rfatt rf;
    891
    892	memcpy(&rf, &gphy->rfatt, sizeof(rf));
    893	b43_lo_fixup_rfatt(&rf);
    894
    895	cal = b43_get_calib_lo_settings(dev, &gphy->bbatt, &rf);
    896	if (!cal)
    897		return;
    898	b43_lo_write(dev, &cal->ctl);
    899}
    900
    901void b43_lo_g_adjust_to(struct b43_wldev *dev,
    902			u16 rfatt, u16 bbatt, u16 tx_control)
    903{
    904	struct b43_rfatt rf;
    905	struct b43_bbatt bb;
    906	struct b43_lo_calib *cal;
    907
    908	memset(&rf, 0, sizeof(rf));
    909	memset(&bb, 0, sizeof(bb));
    910	rf.att = rfatt;
    911	bb.att = bbatt;
    912	b43_lo_fixup_rfatt(&rf);
    913	cal = b43_get_calib_lo_settings(dev, &bb, &rf);
    914	if (!cal)
    915		return;
    916	b43_lo_write(dev, &cal->ctl);
    917}
    918
    919/* Periodic LO maintenance work */
    920void b43_lo_g_maintenance_work(struct b43_wldev *dev)
    921{
    922	struct b43_phy *phy = &dev->phy;
    923	struct b43_phy_g *gphy = phy->g;
    924	struct b43_txpower_lo_control *lo = gphy->lo_control;
    925	unsigned long now;
    926	unsigned long expire;
    927	struct b43_lo_calib *cal, *tmp;
    928	bool current_item_expired = false;
    929	bool hwpctl;
    930
    931	if (!lo)
    932		return;
    933	now = jiffies;
    934	hwpctl = b43_has_hardware_pctl(dev);
    935
    936	if (hwpctl) {
    937		/* Read the power vector and update it, if needed. */
    938		expire = now - B43_LO_PWRVEC_EXPIRE;
    939		if (time_before(lo->pwr_vec_read_time, expire)) {
    940			lo_read_power_vector(dev);
    941			b43_gphy_dc_lt_init(dev, 0);
    942		}
    943		//FIXME Recalc the whole DC table from time to time?
    944	}
    945
    946	if (hwpctl)
    947		return;
    948	/* Search for expired LO settings. Remove them.
    949	 * Recalibrate the current setting, if expired. */
    950	expire = now - B43_LO_CALIB_EXPIRE;
    951	list_for_each_entry_safe(cal, tmp, &lo->calib_list, list) {
    952		if (!time_before(cal->calib_time, expire))
    953			continue;
    954		/* This item expired. */
    955		if (b43_compare_bbatt(&cal->bbatt, &gphy->bbatt) &&
    956		    b43_compare_rfatt(&cal->rfatt, &gphy->rfatt)) {
    957			B43_WARN_ON(current_item_expired);
    958			current_item_expired = true;
    959		}
    960		if (b43_debug(dev, B43_DBG_LO)) {
    961			b43dbg(dev->wl, "LO: Item BB(%u), RF(%u,%u), "
    962			       "I=%d, Q=%d expired\n",
    963			       cal->bbatt.att, cal->rfatt.att,
    964			       cal->rfatt.with_padmix,
    965			       cal->ctl.i, cal->ctl.q);
    966		}
    967		list_del(&cal->list);
    968		kfree(cal);
    969	}
    970	if (current_item_expired || unlikely(list_empty(&lo->calib_list))) {
    971		/* Recalibrate currently used LO setting. */
    972		if (b43_debug(dev, B43_DBG_LO))
    973			b43dbg(dev->wl, "LO: Recalibrating current LO setting\n");
    974		cal = b43_calibrate_lo_setting(dev, &gphy->bbatt, &gphy->rfatt);
    975		if (cal) {
    976			list_add(&cal->list, &lo->calib_list);
    977			b43_lo_write(dev, &cal->ctl);
    978		} else
    979			b43warn(dev->wl, "Failed to recalibrate current LO setting\n");
    980	}
    981}
    982
    983void b43_lo_g_cleanup(struct b43_wldev *dev)
    984{
    985	struct b43_txpower_lo_control *lo = dev->phy.g->lo_control;
    986	struct b43_lo_calib *cal, *tmp;
    987
    988	if (!lo)
    989		return;
    990	list_for_each_entry_safe(cal, tmp, &lo->calib_list, list) {
    991		list_del(&cal->list);
    992		kfree(cal);
    993	}
    994}
    995
    996/* LO Initialization */
    997void b43_lo_g_init(struct b43_wldev *dev)
    998{
    999	if (b43_has_hardware_pctl(dev)) {
   1000		lo_read_power_vector(dev);
   1001		b43_gphy_dc_lt_init(dev, 1);
   1002	}
   1003}