1ca47d344SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
258619b14SKalle Valo /*
358619b14SKalle Valo
458619b14SKalle Valo Broadcom B43 wireless driver
558619b14SKalle Valo IEEE 802.11g PHY driver
658619b14SKalle Valo
758619b14SKalle Valo Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
858619b14SKalle Valo Copyright (c) 2005-2007 Stefano Brivio <stefano.brivio@polimi.it>
958619b14SKalle Valo Copyright (c) 2005-2008 Michael Buesch <m@bues.ch>
1058619b14SKalle Valo Copyright (c) 2005, 2006 Danny van Dyk <kugelfang@gentoo.org>
1158619b14SKalle Valo Copyright (c) 2005, 2006 Andreas Jaggi <andreas.jaggi@waterwave.ch>
1258619b14SKalle Valo
1358619b14SKalle Valo
1458619b14SKalle Valo */
1558619b14SKalle Valo
1658619b14SKalle Valo #include "b43.h"
1758619b14SKalle Valo #include "phy_g.h"
1858619b14SKalle Valo #include "phy_common.h"
1958619b14SKalle Valo #include "lo.h"
2058619b14SKalle Valo #include "main.h"
219791333aSGuenter Roeck #include "wa.h"
2258619b14SKalle Valo
2358619b14SKalle Valo #include <linux/bitrev.h>
2458619b14SKalle Valo #include <linux/slab.h>
2558619b14SKalle Valo
2658619b14SKalle Valo
2758619b14SKalle Valo static const s8 b43_tssi2dbm_g_table[] = {
2858619b14SKalle Valo 77, 77, 77, 76,
2958619b14SKalle Valo 76, 76, 75, 75,
3058619b14SKalle Valo 74, 74, 73, 73,
3158619b14SKalle Valo 73, 72, 72, 71,
3258619b14SKalle Valo 71, 70, 70, 69,
3358619b14SKalle Valo 68, 68, 67, 67,
3458619b14SKalle Valo 66, 65, 65, 64,
3558619b14SKalle Valo 63, 63, 62, 61,
3658619b14SKalle Valo 60, 59, 58, 57,
3758619b14SKalle Valo 56, 55, 54, 53,
3858619b14SKalle Valo 52, 50, 49, 47,
3958619b14SKalle Valo 45, 43, 40, 37,
4058619b14SKalle Valo 33, 28, 22, 14,
4158619b14SKalle Valo 5, -7, -20, -20,
4258619b14SKalle Valo -20, -20, -20, -20,
4358619b14SKalle Valo -20, -20, -20, -20,
4458619b14SKalle Valo };
4558619b14SKalle Valo
4658619b14SKalle Valo static const u8 b43_radio_channel_codes_bg[] = {
4758619b14SKalle Valo 12, 17, 22, 27,
4858619b14SKalle Valo 32, 37, 42, 47,
4958619b14SKalle Valo 52, 57, 62, 67,
5058619b14SKalle Valo 72, 84,
5158619b14SKalle Valo };
5258619b14SKalle Valo
5358619b14SKalle Valo
5458619b14SKalle Valo static void b43_calc_nrssi_threshold(struct b43_wldev *dev);
5558619b14SKalle Valo
5658619b14SKalle Valo
5758619b14SKalle Valo #define bitrev4(tmp) (bitrev8(tmp) >> 4)
5858619b14SKalle Valo
5958619b14SKalle Valo
6058619b14SKalle Valo /* Get the freq, as it has to be written to the device. */
channel2freq_bg(u8 channel)6158619b14SKalle Valo static inline u16 channel2freq_bg(u8 channel)
6258619b14SKalle Valo {
6358619b14SKalle Valo B43_WARN_ON(!(channel >= 1 && channel <= 14));
6458619b14SKalle Valo
6558619b14SKalle Valo return b43_radio_channel_codes_bg[channel - 1];
6658619b14SKalle Valo }
6758619b14SKalle Valo
generate_rfatt_list(struct b43_wldev * dev,struct b43_rfatt_list * list)6858619b14SKalle Valo static void generate_rfatt_list(struct b43_wldev *dev,
6958619b14SKalle Valo struct b43_rfatt_list *list)
7058619b14SKalle Valo {
7158619b14SKalle Valo struct b43_phy *phy = &dev->phy;
7258619b14SKalle Valo
7358619b14SKalle Valo /* APHY.rev < 5 || GPHY.rev < 6 */
7458619b14SKalle Valo static const struct b43_rfatt rfatt_0[] = {
7558619b14SKalle Valo {.att = 3,.with_padmix = 0,},
7658619b14SKalle Valo {.att = 1,.with_padmix = 0,},
7758619b14SKalle Valo {.att = 5,.with_padmix = 0,},
7858619b14SKalle Valo {.att = 7,.with_padmix = 0,},
7958619b14SKalle Valo {.att = 9,.with_padmix = 0,},
8058619b14SKalle Valo {.att = 2,.with_padmix = 0,},
8158619b14SKalle Valo {.att = 0,.with_padmix = 0,},
8258619b14SKalle Valo {.att = 4,.with_padmix = 0,},
8358619b14SKalle Valo {.att = 6,.with_padmix = 0,},
8458619b14SKalle Valo {.att = 8,.with_padmix = 0,},
8558619b14SKalle Valo {.att = 1,.with_padmix = 1,},
8658619b14SKalle Valo {.att = 2,.with_padmix = 1,},
8758619b14SKalle Valo {.att = 3,.with_padmix = 1,},
8858619b14SKalle Valo {.att = 4,.with_padmix = 1,},
8958619b14SKalle Valo };
9058619b14SKalle Valo /* Radio.rev == 8 && Radio.version == 0x2050 */
9158619b14SKalle Valo static const struct b43_rfatt rfatt_1[] = {
9258619b14SKalle Valo {.att = 2,.with_padmix = 1,},
9358619b14SKalle Valo {.att = 4,.with_padmix = 1,},
9458619b14SKalle Valo {.att = 6,.with_padmix = 1,},
9558619b14SKalle Valo {.att = 8,.with_padmix = 1,},
9658619b14SKalle Valo {.att = 10,.with_padmix = 1,},
9758619b14SKalle Valo {.att = 12,.with_padmix = 1,},
9858619b14SKalle Valo {.att = 14,.with_padmix = 1,},
9958619b14SKalle Valo };
10058619b14SKalle Valo /* Otherwise */
10158619b14SKalle Valo static const struct b43_rfatt rfatt_2[] = {
10258619b14SKalle Valo {.att = 0,.with_padmix = 1,},
10358619b14SKalle Valo {.att = 2,.with_padmix = 1,},
10458619b14SKalle Valo {.att = 4,.with_padmix = 1,},
10558619b14SKalle Valo {.att = 6,.with_padmix = 1,},
10658619b14SKalle Valo {.att = 8,.with_padmix = 1,},
10758619b14SKalle Valo {.att = 9,.with_padmix = 1,},
10858619b14SKalle Valo {.att = 9,.with_padmix = 1,},
10958619b14SKalle Valo };
11058619b14SKalle Valo
11158619b14SKalle Valo if (!b43_has_hardware_pctl(dev)) {
11258619b14SKalle Valo /* Software pctl */
11358619b14SKalle Valo list->list = rfatt_0;
11458619b14SKalle Valo list->len = ARRAY_SIZE(rfatt_0);
11558619b14SKalle Valo list->min_val = 0;
11658619b14SKalle Valo list->max_val = 9;
11758619b14SKalle Valo return;
11858619b14SKalle Valo }
11958619b14SKalle Valo if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) {
12058619b14SKalle Valo /* Hardware pctl */
12158619b14SKalle Valo list->list = rfatt_1;
12258619b14SKalle Valo list->len = ARRAY_SIZE(rfatt_1);
12358619b14SKalle Valo list->min_val = 0;
12458619b14SKalle Valo list->max_val = 14;
12558619b14SKalle Valo return;
12658619b14SKalle Valo }
12758619b14SKalle Valo /* Hardware pctl */
12858619b14SKalle Valo list->list = rfatt_2;
12958619b14SKalle Valo list->len = ARRAY_SIZE(rfatt_2);
13058619b14SKalle Valo list->min_val = 0;
13158619b14SKalle Valo list->max_val = 9;
13258619b14SKalle Valo }
13358619b14SKalle Valo
generate_bbatt_list(struct b43_wldev * dev,struct b43_bbatt_list * list)13458619b14SKalle Valo static void generate_bbatt_list(struct b43_wldev *dev,
13558619b14SKalle Valo struct b43_bbatt_list *list)
13658619b14SKalle Valo {
13758619b14SKalle Valo static const struct b43_bbatt bbatt_0[] = {
13858619b14SKalle Valo {.att = 0,},
13958619b14SKalle Valo {.att = 1,},
14058619b14SKalle Valo {.att = 2,},
14158619b14SKalle Valo {.att = 3,},
14258619b14SKalle Valo {.att = 4,},
14358619b14SKalle Valo {.att = 5,},
14458619b14SKalle Valo {.att = 6,},
14558619b14SKalle Valo {.att = 7,},
14658619b14SKalle Valo {.att = 8,},
14758619b14SKalle Valo };
14858619b14SKalle Valo
14958619b14SKalle Valo list->list = bbatt_0;
15058619b14SKalle Valo list->len = ARRAY_SIZE(bbatt_0);
15158619b14SKalle Valo list->min_val = 0;
15258619b14SKalle Valo list->max_val = 8;
15358619b14SKalle Valo }
15458619b14SKalle Valo
b43_shm_clear_tssi(struct b43_wldev * dev)15558619b14SKalle Valo static void b43_shm_clear_tssi(struct b43_wldev *dev)
15658619b14SKalle Valo {
15758619b14SKalle Valo b43_shm_write16(dev, B43_SHM_SHARED, 0x0058, 0x7F7F);
15858619b14SKalle Valo b43_shm_write16(dev, B43_SHM_SHARED, 0x005a, 0x7F7F);
15958619b14SKalle Valo b43_shm_write16(dev, B43_SHM_SHARED, 0x0070, 0x7F7F);
16058619b14SKalle Valo b43_shm_write16(dev, B43_SHM_SHARED, 0x0072, 0x7F7F);
16158619b14SKalle Valo }
16258619b14SKalle Valo
16358619b14SKalle Valo /* Synthetic PU workaround */
b43_synth_pu_workaround(struct b43_wldev * dev,u8 channel)16458619b14SKalle Valo static void b43_synth_pu_workaround(struct b43_wldev *dev, u8 channel)
16558619b14SKalle Valo {
16658619b14SKalle Valo struct b43_phy *phy = &dev->phy;
16758619b14SKalle Valo
16858619b14SKalle Valo might_sleep();
16958619b14SKalle Valo
17058619b14SKalle Valo if (phy->radio_ver != 0x2050 || phy->radio_rev >= 6) {
17158619b14SKalle Valo /* We do not need the workaround. */
17258619b14SKalle Valo return;
17358619b14SKalle Valo }
17458619b14SKalle Valo
17558619b14SKalle Valo if (channel <= 10) {
17658619b14SKalle Valo b43_write16(dev, B43_MMIO_CHANNEL,
17758619b14SKalle Valo channel2freq_bg(channel + 4));
17858619b14SKalle Valo } else {
17958619b14SKalle Valo b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(1));
18058619b14SKalle Valo }
18158619b14SKalle Valo msleep(1);
18258619b14SKalle Valo b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(channel));
18358619b14SKalle Valo }
18458619b14SKalle Valo
18558619b14SKalle Valo /* Set the baseband attenuation value on chip. */
b43_gphy_set_baseband_attenuation(struct b43_wldev * dev,u16 baseband_attenuation)18658619b14SKalle Valo void b43_gphy_set_baseband_attenuation(struct b43_wldev *dev,
18758619b14SKalle Valo u16 baseband_attenuation)
18858619b14SKalle Valo {
18958619b14SKalle Valo struct b43_phy *phy = &dev->phy;
19058619b14SKalle Valo
19158619b14SKalle Valo if (phy->analog == 0) {
19258619b14SKalle Valo b43_write16(dev, B43_MMIO_PHY0, (b43_read16(dev, B43_MMIO_PHY0)
19358619b14SKalle Valo & 0xFFF0) |
19458619b14SKalle Valo baseband_attenuation);
19558619b14SKalle Valo } else if (phy->analog > 1) {
19658619b14SKalle Valo b43_phy_maskset(dev, B43_PHY_DACCTL, 0xFFC3, (baseband_attenuation << 2));
19758619b14SKalle Valo } else {
19858619b14SKalle Valo b43_phy_maskset(dev, B43_PHY_DACCTL, 0xFF87, (baseband_attenuation << 3));
19958619b14SKalle Valo }
20058619b14SKalle Valo }
20158619b14SKalle Valo
20258619b14SKalle Valo /* Adjust the transmission power output (G-PHY) */
b43_set_txpower_g(struct b43_wldev * dev,const struct b43_bbatt * bbatt,const struct b43_rfatt * rfatt,u8 tx_control)20358619b14SKalle Valo static void b43_set_txpower_g(struct b43_wldev *dev,
20458619b14SKalle Valo const struct b43_bbatt *bbatt,
20558619b14SKalle Valo const struct b43_rfatt *rfatt, u8 tx_control)
20658619b14SKalle Valo {
20758619b14SKalle Valo struct b43_phy *phy = &dev->phy;
20858619b14SKalle Valo struct b43_phy_g *gphy = phy->g;
20958619b14SKalle Valo struct b43_txpower_lo_control *lo = gphy->lo_control;
21058619b14SKalle Valo u16 bb, rf;
21158619b14SKalle Valo u16 tx_bias, tx_magn;
21258619b14SKalle Valo
21358619b14SKalle Valo bb = bbatt->att;
21458619b14SKalle Valo rf = rfatt->att;
21558619b14SKalle Valo tx_bias = lo->tx_bias;
21658619b14SKalle Valo tx_magn = lo->tx_magn;
21758619b14SKalle Valo if (unlikely(tx_bias == 0xFF))
21858619b14SKalle Valo tx_bias = 0;
21958619b14SKalle Valo
22058619b14SKalle Valo /* Save the values for later. Use memmove, because it's valid
22158619b14SKalle Valo * to pass &gphy->rfatt as rfatt pointer argument. Same for bbatt. */
22258619b14SKalle Valo gphy->tx_control = tx_control;
22358619b14SKalle Valo memmove(&gphy->rfatt, rfatt, sizeof(*rfatt));
22458619b14SKalle Valo gphy->rfatt.with_padmix = !!(tx_control & B43_TXCTL_TXMIX);
22558619b14SKalle Valo memmove(&gphy->bbatt, bbatt, sizeof(*bbatt));
22658619b14SKalle Valo
22758619b14SKalle Valo if (b43_debug(dev, B43_DBG_XMITPOWER)) {
22858619b14SKalle Valo b43dbg(dev->wl, "Tuning TX-power to bbatt(%u), "
22958619b14SKalle Valo "rfatt(%u), tx_control(0x%02X), "
23058619b14SKalle Valo "tx_bias(0x%02X), tx_magn(0x%02X)\n",
23158619b14SKalle Valo bb, rf, tx_control, tx_bias, tx_magn);
23258619b14SKalle Valo }
23358619b14SKalle Valo
23458619b14SKalle Valo b43_gphy_set_baseband_attenuation(dev, bb);
23558619b14SKalle Valo b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_RFATT, rf);
23658619b14SKalle Valo if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) {
23758619b14SKalle Valo b43_radio_write16(dev, 0x43,
23858619b14SKalle Valo (rf & 0x000F) | (tx_control & 0x0070));
23958619b14SKalle Valo } else {
24058619b14SKalle Valo b43_radio_maskset(dev, 0x43, 0xFFF0, (rf & 0x000F));
24158619b14SKalle Valo b43_radio_maskset(dev, 0x52, ~0x0070, (tx_control & 0x0070));
24258619b14SKalle Valo }
24358619b14SKalle Valo if (has_tx_magnification(phy)) {
24458619b14SKalle Valo b43_radio_write16(dev, 0x52, tx_magn | tx_bias);
24558619b14SKalle Valo } else {
24658619b14SKalle Valo b43_radio_maskset(dev, 0x52, 0xFFF0, (tx_bias & 0x000F));
24758619b14SKalle Valo }
24858619b14SKalle Valo b43_lo_g_adjust(dev);
24958619b14SKalle Valo }
25058619b14SKalle Valo
25158619b14SKalle Valo /* GPHY_TSSI_Power_Lookup_Table_Init */
b43_gphy_tssi_power_lt_init(struct b43_wldev * dev)25258619b14SKalle Valo static void b43_gphy_tssi_power_lt_init(struct b43_wldev *dev)
25358619b14SKalle Valo {
25458619b14SKalle Valo struct b43_phy_g *gphy = dev->phy.g;
25558619b14SKalle Valo int i;
25658619b14SKalle Valo u16 value;
25758619b14SKalle Valo
25858619b14SKalle Valo for (i = 0; i < 32; i++)
25958619b14SKalle Valo b43_ofdmtab_write16(dev, 0x3C20, i, gphy->tssi2dbm[i]);
26058619b14SKalle Valo for (i = 32; i < 64; i++)
26158619b14SKalle Valo b43_ofdmtab_write16(dev, 0x3C00, i - 32, gphy->tssi2dbm[i]);
26258619b14SKalle Valo for (i = 0; i < 64; i += 2) {
26358619b14SKalle Valo value = (u16) gphy->tssi2dbm[i];
26458619b14SKalle Valo value |= ((u16) gphy->tssi2dbm[i + 1]) << 8;
26558619b14SKalle Valo b43_phy_write(dev, 0x380 + (i / 2), value);
26658619b14SKalle Valo }
26758619b14SKalle Valo }
26858619b14SKalle Valo
26958619b14SKalle Valo /* GPHY_Gain_Lookup_Table_Init */
b43_gphy_gain_lt_init(struct b43_wldev * dev)27058619b14SKalle Valo static void b43_gphy_gain_lt_init(struct b43_wldev *dev)
27158619b14SKalle Valo {
27258619b14SKalle Valo struct b43_phy *phy = &dev->phy;
27358619b14SKalle Valo struct b43_phy_g *gphy = phy->g;
27458619b14SKalle Valo struct b43_txpower_lo_control *lo = gphy->lo_control;
27558619b14SKalle Valo u16 nr_written = 0;
27658619b14SKalle Valo u16 tmp;
27758619b14SKalle Valo u8 rf, bb;
27858619b14SKalle Valo
27958619b14SKalle Valo for (rf = 0; rf < lo->rfatt_list.len; rf++) {
28058619b14SKalle Valo for (bb = 0; bb < lo->bbatt_list.len; bb++) {
28158619b14SKalle Valo if (nr_written >= 0x40)
28258619b14SKalle Valo return;
28358619b14SKalle Valo tmp = lo->bbatt_list.list[bb].att;
28458619b14SKalle Valo tmp <<= 8;
28558619b14SKalle Valo if (phy->radio_rev == 8)
28658619b14SKalle Valo tmp |= 0x50;
28758619b14SKalle Valo else
28858619b14SKalle Valo tmp |= 0x40;
28958619b14SKalle Valo tmp |= lo->rfatt_list.list[rf].att;
29058619b14SKalle Valo b43_phy_write(dev, 0x3C0 + nr_written, tmp);
29158619b14SKalle Valo nr_written++;
29258619b14SKalle Valo }
29358619b14SKalle Valo }
29458619b14SKalle Valo }
29558619b14SKalle Valo
b43_set_all_gains(struct b43_wldev * dev,s16 first,s16 second,s16 third)29658619b14SKalle Valo static void b43_set_all_gains(struct b43_wldev *dev,
29758619b14SKalle Valo s16 first, s16 second, s16 third)
29858619b14SKalle Valo {
29958619b14SKalle Valo struct b43_phy *phy = &dev->phy;
30058619b14SKalle Valo u16 i;
30158619b14SKalle Valo u16 start = 0x08, end = 0x18;
30258619b14SKalle Valo u16 tmp;
30358619b14SKalle Valo u16 table;
30458619b14SKalle Valo
30558619b14SKalle Valo if (phy->rev <= 1) {
30658619b14SKalle Valo start = 0x10;
30758619b14SKalle Valo end = 0x20;
30858619b14SKalle Valo }
30958619b14SKalle Valo
31058619b14SKalle Valo table = B43_OFDMTAB_GAINX;
31158619b14SKalle Valo if (phy->rev <= 1)
31258619b14SKalle Valo table = B43_OFDMTAB_GAINX_R1;
31358619b14SKalle Valo for (i = 0; i < 4; i++)
31458619b14SKalle Valo b43_ofdmtab_write16(dev, table, i, first);
31558619b14SKalle Valo
31658619b14SKalle Valo for (i = start; i < end; i++)
31758619b14SKalle Valo b43_ofdmtab_write16(dev, table, i, second);
31858619b14SKalle Valo
31958619b14SKalle Valo if (third != -1) {
32058619b14SKalle Valo tmp = ((u16) third << 14) | ((u16) third << 6);
32158619b14SKalle Valo b43_phy_maskset(dev, 0x04A0, 0xBFBF, tmp);
32258619b14SKalle Valo b43_phy_maskset(dev, 0x04A1, 0xBFBF, tmp);
32358619b14SKalle Valo b43_phy_maskset(dev, 0x04A2, 0xBFBF, tmp);
32458619b14SKalle Valo }
32558619b14SKalle Valo b43_dummy_transmission(dev, false, true);
32658619b14SKalle Valo }
32758619b14SKalle Valo
b43_set_original_gains(struct b43_wldev * dev)32858619b14SKalle Valo static void b43_set_original_gains(struct b43_wldev *dev)
32958619b14SKalle Valo {
33058619b14SKalle Valo struct b43_phy *phy = &dev->phy;
33158619b14SKalle Valo u16 i, tmp;
33258619b14SKalle Valo u16 table;
33358619b14SKalle Valo u16 start = 0x0008, end = 0x0018;
33458619b14SKalle Valo
33558619b14SKalle Valo if (phy->rev <= 1) {
33658619b14SKalle Valo start = 0x0010;
33758619b14SKalle Valo end = 0x0020;
33858619b14SKalle Valo }
33958619b14SKalle Valo
34058619b14SKalle Valo table = B43_OFDMTAB_GAINX;
34158619b14SKalle Valo if (phy->rev <= 1)
34258619b14SKalle Valo table = B43_OFDMTAB_GAINX_R1;
34358619b14SKalle Valo for (i = 0; i < 4; i++) {
34458619b14SKalle Valo tmp = (i & 0xFFFC);
34558619b14SKalle Valo tmp |= (i & 0x0001) << 1;
34658619b14SKalle Valo tmp |= (i & 0x0002) >> 1;
34758619b14SKalle Valo
34858619b14SKalle Valo b43_ofdmtab_write16(dev, table, i, tmp);
34958619b14SKalle Valo }
35058619b14SKalle Valo
35158619b14SKalle Valo for (i = start; i < end; i++)
35258619b14SKalle Valo b43_ofdmtab_write16(dev, table, i, i - start);
35358619b14SKalle Valo
35458619b14SKalle Valo b43_phy_maskset(dev, 0x04A0, 0xBFBF, 0x4040);
35558619b14SKalle Valo b43_phy_maskset(dev, 0x04A1, 0xBFBF, 0x4040);
35658619b14SKalle Valo b43_phy_maskset(dev, 0x04A2, 0xBFBF, 0x4000);
35758619b14SKalle Valo b43_dummy_transmission(dev, false, true);
35858619b14SKalle Valo }
35958619b14SKalle Valo
3602d96c1edSAlexander A. Klimov /* https://bcm-specs.sipsolutions.net/NRSSILookupTable */
b43_nrssi_hw_write(struct b43_wldev * dev,u16 offset,s16 val)36158619b14SKalle Valo static void b43_nrssi_hw_write(struct b43_wldev *dev, u16 offset, s16 val)
36258619b14SKalle Valo {
36358619b14SKalle Valo b43_phy_write(dev, B43_PHY_NRSSILT_CTRL, offset);
36458619b14SKalle Valo b43_phy_write(dev, B43_PHY_NRSSILT_DATA, (u16) val);
36558619b14SKalle Valo }
36658619b14SKalle Valo
3672d96c1edSAlexander A. Klimov /* https://bcm-specs.sipsolutions.net/NRSSILookupTable */
b43_nrssi_hw_read(struct b43_wldev * dev,u16 offset)36858619b14SKalle Valo static s16 b43_nrssi_hw_read(struct b43_wldev *dev, u16 offset)
36958619b14SKalle Valo {
37058619b14SKalle Valo u16 val;
37158619b14SKalle Valo
37258619b14SKalle Valo b43_phy_write(dev, B43_PHY_NRSSILT_CTRL, offset);
37358619b14SKalle Valo val = b43_phy_read(dev, B43_PHY_NRSSILT_DATA);
37458619b14SKalle Valo
37558619b14SKalle Valo return (s16) val;
37658619b14SKalle Valo }
37758619b14SKalle Valo
3782d96c1edSAlexander A. Klimov /* https://bcm-specs.sipsolutions.net/NRSSILookupTable */
b43_nrssi_hw_update(struct b43_wldev * dev,u16 val)37958619b14SKalle Valo static void b43_nrssi_hw_update(struct b43_wldev *dev, u16 val)
38058619b14SKalle Valo {
38158619b14SKalle Valo u16 i;
38258619b14SKalle Valo s16 tmp;
38358619b14SKalle Valo
38458619b14SKalle Valo for (i = 0; i < 64; i++) {
38558619b14SKalle Valo tmp = b43_nrssi_hw_read(dev, i);
38658619b14SKalle Valo tmp -= val;
38758619b14SKalle Valo tmp = clamp_val(tmp, -32, 31);
38858619b14SKalle Valo b43_nrssi_hw_write(dev, i, tmp);
38958619b14SKalle Valo }
39058619b14SKalle Valo }
39158619b14SKalle Valo
3922d96c1edSAlexander A. Klimov /* https://bcm-specs.sipsolutions.net/NRSSILookupTable */
b43_nrssi_mem_update(struct b43_wldev * dev)39358619b14SKalle Valo static void b43_nrssi_mem_update(struct b43_wldev *dev)
39458619b14SKalle Valo {
39558619b14SKalle Valo struct b43_phy_g *gphy = dev->phy.g;
39658619b14SKalle Valo s16 i, delta;
39758619b14SKalle Valo s32 tmp;
39858619b14SKalle Valo
39958619b14SKalle Valo delta = 0x1F - gphy->nrssi[0];
40058619b14SKalle Valo for (i = 0; i < 64; i++) {
40158619b14SKalle Valo tmp = (i - delta) * gphy->nrssislope;
40258619b14SKalle Valo tmp /= 0x10000;
40358619b14SKalle Valo tmp += 0x3A;
40458619b14SKalle Valo tmp = clamp_val(tmp, 0, 0x3F);
40558619b14SKalle Valo gphy->nrssi_lt[i] = tmp;
40658619b14SKalle Valo }
40758619b14SKalle Valo }
40858619b14SKalle Valo
b43_calc_nrssi_offset(struct b43_wldev * dev)40958619b14SKalle Valo static void b43_calc_nrssi_offset(struct b43_wldev *dev)
41058619b14SKalle Valo {
41158619b14SKalle Valo struct b43_phy *phy = &dev->phy;
41258619b14SKalle Valo u16 backup[20] = { 0 };
41358619b14SKalle Valo s16 v47F;
41458619b14SKalle Valo u16 i;
41558619b14SKalle Valo u16 saved = 0xFFFF;
41658619b14SKalle Valo
41758619b14SKalle Valo backup[0] = b43_phy_read(dev, 0x0001);
41858619b14SKalle Valo backup[1] = b43_phy_read(dev, 0x0811);
41958619b14SKalle Valo backup[2] = b43_phy_read(dev, 0x0812);
42058619b14SKalle Valo if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */
42158619b14SKalle Valo backup[3] = b43_phy_read(dev, 0x0814);
42258619b14SKalle Valo backup[4] = b43_phy_read(dev, 0x0815);
42358619b14SKalle Valo }
42458619b14SKalle Valo backup[5] = b43_phy_read(dev, 0x005A);
42558619b14SKalle Valo backup[6] = b43_phy_read(dev, 0x0059);
42658619b14SKalle Valo backup[7] = b43_phy_read(dev, 0x0058);
42758619b14SKalle Valo backup[8] = b43_phy_read(dev, 0x000A);
42858619b14SKalle Valo backup[9] = b43_phy_read(dev, 0x0003);
42958619b14SKalle Valo backup[10] = b43_radio_read16(dev, 0x007A);
43058619b14SKalle Valo backup[11] = b43_radio_read16(dev, 0x0043);
43158619b14SKalle Valo
43258619b14SKalle Valo b43_phy_mask(dev, 0x0429, 0x7FFF);
43358619b14SKalle Valo b43_phy_maskset(dev, 0x0001, 0x3FFF, 0x4000);
43458619b14SKalle Valo b43_phy_set(dev, 0x0811, 0x000C);
43558619b14SKalle Valo b43_phy_maskset(dev, 0x0812, 0xFFF3, 0x0004);
43658619b14SKalle Valo b43_phy_mask(dev, 0x0802, ~(0x1 | 0x2));
43758619b14SKalle Valo if (phy->rev >= 6) {
43858619b14SKalle Valo backup[12] = b43_phy_read(dev, 0x002E);
43958619b14SKalle Valo backup[13] = b43_phy_read(dev, 0x002F);
44058619b14SKalle Valo backup[14] = b43_phy_read(dev, 0x080F);
44158619b14SKalle Valo backup[15] = b43_phy_read(dev, 0x0810);
44258619b14SKalle Valo backup[16] = b43_phy_read(dev, 0x0801);
44358619b14SKalle Valo backup[17] = b43_phy_read(dev, 0x0060);
44458619b14SKalle Valo backup[18] = b43_phy_read(dev, 0x0014);
44558619b14SKalle Valo backup[19] = b43_phy_read(dev, 0x0478);
44658619b14SKalle Valo
44758619b14SKalle Valo b43_phy_write(dev, 0x002E, 0);
44858619b14SKalle Valo b43_phy_write(dev, 0x002F, 0);
44958619b14SKalle Valo b43_phy_write(dev, 0x080F, 0);
45058619b14SKalle Valo b43_phy_write(dev, 0x0810, 0);
45158619b14SKalle Valo b43_phy_set(dev, 0x0478, 0x0100);
45258619b14SKalle Valo b43_phy_set(dev, 0x0801, 0x0040);
45358619b14SKalle Valo b43_phy_set(dev, 0x0060, 0x0040);
45458619b14SKalle Valo b43_phy_set(dev, 0x0014, 0x0200);
45558619b14SKalle Valo }
45658619b14SKalle Valo b43_radio_set(dev, 0x007A, 0x0070);
45758619b14SKalle Valo b43_radio_set(dev, 0x007A, 0x0080);
45858619b14SKalle Valo udelay(30);
45958619b14SKalle Valo
46058619b14SKalle Valo v47F = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F);
46158619b14SKalle Valo if (v47F >= 0x20)
46258619b14SKalle Valo v47F -= 0x40;
46358619b14SKalle Valo if (v47F == 31) {
46458619b14SKalle Valo for (i = 7; i >= 4; i--) {
46558619b14SKalle Valo b43_radio_write16(dev, 0x007B, i);
46658619b14SKalle Valo udelay(20);
46758619b14SKalle Valo v47F =
46858619b14SKalle Valo (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F);
46958619b14SKalle Valo if (v47F >= 0x20)
47058619b14SKalle Valo v47F -= 0x40;
47158619b14SKalle Valo if (v47F < 31 && saved == 0xFFFF)
47258619b14SKalle Valo saved = i;
47358619b14SKalle Valo }
47458619b14SKalle Valo if (saved == 0xFFFF)
47558619b14SKalle Valo saved = 4;
47658619b14SKalle Valo } else {
47758619b14SKalle Valo b43_radio_mask(dev, 0x007A, 0x007F);
47858619b14SKalle Valo if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */
47958619b14SKalle Valo b43_phy_set(dev, 0x0814, 0x0001);
48058619b14SKalle Valo b43_phy_mask(dev, 0x0815, 0xFFFE);
48158619b14SKalle Valo }
48258619b14SKalle Valo b43_phy_set(dev, 0x0811, 0x000C);
48358619b14SKalle Valo b43_phy_set(dev, 0x0812, 0x000C);
48458619b14SKalle Valo b43_phy_set(dev, 0x0811, 0x0030);
48558619b14SKalle Valo b43_phy_set(dev, 0x0812, 0x0030);
48658619b14SKalle Valo b43_phy_write(dev, 0x005A, 0x0480);
48758619b14SKalle Valo b43_phy_write(dev, 0x0059, 0x0810);
48858619b14SKalle Valo b43_phy_write(dev, 0x0058, 0x000D);
48958619b14SKalle Valo if (phy->rev == 0) {
49058619b14SKalle Valo b43_phy_write(dev, 0x0003, 0x0122);
49158619b14SKalle Valo } else {
49258619b14SKalle Valo b43_phy_set(dev, 0x000A, 0x2000);
49358619b14SKalle Valo }
49458619b14SKalle Valo if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */
49558619b14SKalle Valo b43_phy_set(dev, 0x0814, 0x0004);
49658619b14SKalle Valo b43_phy_mask(dev, 0x0815, 0xFFFB);
49758619b14SKalle Valo }
49858619b14SKalle Valo b43_phy_maskset(dev, 0x0003, 0xFF9F, 0x0040);
49958619b14SKalle Valo b43_radio_set(dev, 0x007A, 0x000F);
50058619b14SKalle Valo b43_set_all_gains(dev, 3, 0, 1);
50158619b14SKalle Valo b43_radio_maskset(dev, 0x0043, 0x00F0, 0x000F);
50258619b14SKalle Valo udelay(30);
50358619b14SKalle Valo v47F = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F);
50458619b14SKalle Valo if (v47F >= 0x20)
50558619b14SKalle Valo v47F -= 0x40;
50658619b14SKalle Valo if (v47F == -32) {
50758619b14SKalle Valo for (i = 0; i < 4; i++) {
50858619b14SKalle Valo b43_radio_write16(dev, 0x007B, i);
50958619b14SKalle Valo udelay(20);
51058619b14SKalle Valo v47F =
51158619b14SKalle Valo (s16) ((b43_phy_read(dev, 0x047F) >> 8) &
51258619b14SKalle Valo 0x003F);
51358619b14SKalle Valo if (v47F >= 0x20)
51458619b14SKalle Valo v47F -= 0x40;
51558619b14SKalle Valo if (v47F > -31 && saved == 0xFFFF)
51658619b14SKalle Valo saved = i;
51758619b14SKalle Valo }
51858619b14SKalle Valo if (saved == 0xFFFF)
51958619b14SKalle Valo saved = 3;
52058619b14SKalle Valo } else
52158619b14SKalle Valo saved = 0;
52258619b14SKalle Valo }
52358619b14SKalle Valo b43_radio_write16(dev, 0x007B, saved);
52458619b14SKalle Valo
52558619b14SKalle Valo if (phy->rev >= 6) {
52658619b14SKalle Valo b43_phy_write(dev, 0x002E, backup[12]);
52758619b14SKalle Valo b43_phy_write(dev, 0x002F, backup[13]);
52858619b14SKalle Valo b43_phy_write(dev, 0x080F, backup[14]);
52958619b14SKalle Valo b43_phy_write(dev, 0x0810, backup[15]);
53058619b14SKalle Valo }
53158619b14SKalle Valo if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */
53258619b14SKalle Valo b43_phy_write(dev, 0x0814, backup[3]);
53358619b14SKalle Valo b43_phy_write(dev, 0x0815, backup[4]);
53458619b14SKalle Valo }
53558619b14SKalle Valo b43_phy_write(dev, 0x005A, backup[5]);
53658619b14SKalle Valo b43_phy_write(dev, 0x0059, backup[6]);
53758619b14SKalle Valo b43_phy_write(dev, 0x0058, backup[7]);
53858619b14SKalle Valo b43_phy_write(dev, 0x000A, backup[8]);
53958619b14SKalle Valo b43_phy_write(dev, 0x0003, backup[9]);
54058619b14SKalle Valo b43_radio_write16(dev, 0x0043, backup[11]);
54158619b14SKalle Valo b43_radio_write16(dev, 0x007A, backup[10]);
54258619b14SKalle Valo b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) | 0x1 | 0x2);
54358619b14SKalle Valo b43_phy_set(dev, 0x0429, 0x8000);
54458619b14SKalle Valo b43_set_original_gains(dev);
54558619b14SKalle Valo if (phy->rev >= 6) {
54658619b14SKalle Valo b43_phy_write(dev, 0x0801, backup[16]);
54758619b14SKalle Valo b43_phy_write(dev, 0x0060, backup[17]);
54858619b14SKalle Valo b43_phy_write(dev, 0x0014, backup[18]);
54958619b14SKalle Valo b43_phy_write(dev, 0x0478, backup[19]);
55058619b14SKalle Valo }
55158619b14SKalle Valo b43_phy_write(dev, 0x0001, backup[0]);
55258619b14SKalle Valo b43_phy_write(dev, 0x0812, backup[2]);
55358619b14SKalle Valo b43_phy_write(dev, 0x0811, backup[1]);
55458619b14SKalle Valo }
55558619b14SKalle Valo
b43_calc_nrssi_slope(struct b43_wldev * dev)55658619b14SKalle Valo static void b43_calc_nrssi_slope(struct b43_wldev *dev)
55758619b14SKalle Valo {
55858619b14SKalle Valo struct b43_phy *phy = &dev->phy;
55958619b14SKalle Valo struct b43_phy_g *gphy = phy->g;
56058619b14SKalle Valo u16 backup[18] = { 0 };
56158619b14SKalle Valo u16 tmp;
56258619b14SKalle Valo s16 nrssi0, nrssi1;
56358619b14SKalle Valo
56458619b14SKalle Valo B43_WARN_ON(phy->type != B43_PHYTYPE_G);
56558619b14SKalle Valo
56658619b14SKalle Valo if (phy->radio_rev >= 9)
56758619b14SKalle Valo return;
56858619b14SKalle Valo if (phy->radio_rev == 8)
56958619b14SKalle Valo b43_calc_nrssi_offset(dev);
57058619b14SKalle Valo
57158619b14SKalle Valo b43_phy_mask(dev, B43_PHY_G_CRS, 0x7FFF);
57258619b14SKalle Valo b43_phy_mask(dev, 0x0802, 0xFFFC);
57358619b14SKalle Valo backup[7] = b43_read16(dev, 0x03E2);
57458619b14SKalle Valo b43_write16(dev, 0x03E2, b43_read16(dev, 0x03E2) | 0x8000);
57558619b14SKalle Valo backup[0] = b43_radio_read16(dev, 0x007A);
57658619b14SKalle Valo backup[1] = b43_radio_read16(dev, 0x0052);
57758619b14SKalle Valo backup[2] = b43_radio_read16(dev, 0x0043);
57858619b14SKalle Valo backup[3] = b43_phy_read(dev, 0x0015);
57958619b14SKalle Valo backup[4] = b43_phy_read(dev, 0x005A);
58058619b14SKalle Valo backup[5] = b43_phy_read(dev, 0x0059);
58158619b14SKalle Valo backup[6] = b43_phy_read(dev, 0x0058);
58258619b14SKalle Valo backup[8] = b43_read16(dev, 0x03E6);
58358619b14SKalle Valo backup[9] = b43_read16(dev, B43_MMIO_CHANNEL_EXT);
58458619b14SKalle Valo if (phy->rev >= 3) {
58558619b14SKalle Valo backup[10] = b43_phy_read(dev, 0x002E);
58658619b14SKalle Valo backup[11] = b43_phy_read(dev, 0x002F);
58758619b14SKalle Valo backup[12] = b43_phy_read(dev, 0x080F);
58858619b14SKalle Valo backup[13] = b43_phy_read(dev, B43_PHY_G_LO_CONTROL);
58958619b14SKalle Valo backup[14] = b43_phy_read(dev, 0x0801);
59058619b14SKalle Valo backup[15] = b43_phy_read(dev, 0x0060);
59158619b14SKalle Valo backup[16] = b43_phy_read(dev, 0x0014);
59258619b14SKalle Valo backup[17] = b43_phy_read(dev, 0x0478);
59358619b14SKalle Valo b43_phy_write(dev, 0x002E, 0);
59458619b14SKalle Valo b43_phy_write(dev, B43_PHY_G_LO_CONTROL, 0);
59558619b14SKalle Valo switch (phy->rev) {
59658619b14SKalle Valo case 4:
59758619b14SKalle Valo case 6:
59858619b14SKalle Valo case 7:
59958619b14SKalle Valo b43_phy_set(dev, 0x0478, 0x0100);
60058619b14SKalle Valo b43_phy_set(dev, 0x0801, 0x0040);
60158619b14SKalle Valo break;
60258619b14SKalle Valo case 3:
60358619b14SKalle Valo case 5:
60458619b14SKalle Valo b43_phy_mask(dev, 0x0801, 0xFFBF);
60558619b14SKalle Valo break;
60658619b14SKalle Valo }
60758619b14SKalle Valo b43_phy_set(dev, 0x0060, 0x0040);
60858619b14SKalle Valo b43_phy_set(dev, 0x0014, 0x0200);
60958619b14SKalle Valo }
61058619b14SKalle Valo b43_radio_set(dev, 0x007A, 0x0070);
61158619b14SKalle Valo b43_set_all_gains(dev, 0, 8, 0);
61258619b14SKalle Valo b43_radio_mask(dev, 0x007A, 0x00F7);
61358619b14SKalle Valo if (phy->rev >= 2) {
61458619b14SKalle Valo b43_phy_maskset(dev, 0x0811, 0xFFCF, 0x0030);
61558619b14SKalle Valo b43_phy_maskset(dev, 0x0812, 0xFFCF, 0x0010);
61658619b14SKalle Valo }
61758619b14SKalle Valo b43_radio_set(dev, 0x007A, 0x0080);
61858619b14SKalle Valo udelay(20);
61958619b14SKalle Valo
62058619b14SKalle Valo nrssi0 = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F);
62158619b14SKalle Valo if (nrssi0 >= 0x0020)
62258619b14SKalle Valo nrssi0 -= 0x0040;
62358619b14SKalle Valo
62458619b14SKalle Valo b43_radio_mask(dev, 0x007A, 0x007F);
62558619b14SKalle Valo if (phy->rev >= 2) {
62658619b14SKalle Valo b43_phy_maskset(dev, 0x0003, 0xFF9F, 0x0040);
62758619b14SKalle Valo }
62858619b14SKalle Valo
62958619b14SKalle Valo b43_write16(dev, B43_MMIO_CHANNEL_EXT,
63058619b14SKalle Valo b43_read16(dev, B43_MMIO_CHANNEL_EXT)
63158619b14SKalle Valo | 0x2000);
63258619b14SKalle Valo b43_radio_set(dev, 0x007A, 0x000F);
63358619b14SKalle Valo b43_phy_write(dev, 0x0015, 0xF330);
63458619b14SKalle Valo if (phy->rev >= 2) {
63558619b14SKalle Valo b43_phy_maskset(dev, 0x0812, 0xFFCF, 0x0020);
63658619b14SKalle Valo b43_phy_maskset(dev, 0x0811, 0xFFCF, 0x0020);
63758619b14SKalle Valo }
63858619b14SKalle Valo
63958619b14SKalle Valo b43_set_all_gains(dev, 3, 0, 1);
64058619b14SKalle Valo if (phy->radio_rev == 8) {
64158619b14SKalle Valo b43_radio_write16(dev, 0x0043, 0x001F);
64258619b14SKalle Valo } else {
64358619b14SKalle Valo tmp = b43_radio_read16(dev, 0x0052) & 0xFF0F;
64458619b14SKalle Valo b43_radio_write16(dev, 0x0052, tmp | 0x0060);
64558619b14SKalle Valo tmp = b43_radio_read16(dev, 0x0043) & 0xFFF0;
64658619b14SKalle Valo b43_radio_write16(dev, 0x0043, tmp | 0x0009);
64758619b14SKalle Valo }
64858619b14SKalle Valo b43_phy_write(dev, 0x005A, 0x0480);
64958619b14SKalle Valo b43_phy_write(dev, 0x0059, 0x0810);
65058619b14SKalle Valo b43_phy_write(dev, 0x0058, 0x000D);
65158619b14SKalle Valo udelay(20);
65258619b14SKalle Valo nrssi1 = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F);
65358619b14SKalle Valo if (nrssi1 >= 0x0020)
65458619b14SKalle Valo nrssi1 -= 0x0040;
65558619b14SKalle Valo if (nrssi0 == nrssi1)
65658619b14SKalle Valo gphy->nrssislope = 0x00010000;
65758619b14SKalle Valo else
65858619b14SKalle Valo gphy->nrssislope = 0x00400000 / (nrssi0 - nrssi1);
65958619b14SKalle Valo if (nrssi0 >= -4) {
66058619b14SKalle Valo gphy->nrssi[0] = nrssi1;
66158619b14SKalle Valo gphy->nrssi[1] = nrssi0;
66258619b14SKalle Valo }
66358619b14SKalle Valo if (phy->rev >= 3) {
66458619b14SKalle Valo b43_phy_write(dev, 0x002E, backup[10]);
66558619b14SKalle Valo b43_phy_write(dev, 0x002F, backup[11]);
66658619b14SKalle Valo b43_phy_write(dev, 0x080F, backup[12]);
66758619b14SKalle Valo b43_phy_write(dev, B43_PHY_G_LO_CONTROL, backup[13]);
66858619b14SKalle Valo }
66958619b14SKalle Valo if (phy->rev >= 2) {
67058619b14SKalle Valo b43_phy_mask(dev, 0x0812, 0xFFCF);
67158619b14SKalle Valo b43_phy_mask(dev, 0x0811, 0xFFCF);
67258619b14SKalle Valo }
67358619b14SKalle Valo
67458619b14SKalle Valo b43_radio_write16(dev, 0x007A, backup[0]);
67558619b14SKalle Valo b43_radio_write16(dev, 0x0052, backup[1]);
67658619b14SKalle Valo b43_radio_write16(dev, 0x0043, backup[2]);
67758619b14SKalle Valo b43_write16(dev, 0x03E2, backup[7]);
67858619b14SKalle Valo b43_write16(dev, 0x03E6, backup[8]);
67958619b14SKalle Valo b43_write16(dev, B43_MMIO_CHANNEL_EXT, backup[9]);
68058619b14SKalle Valo b43_phy_write(dev, 0x0015, backup[3]);
68158619b14SKalle Valo b43_phy_write(dev, 0x005A, backup[4]);
68258619b14SKalle Valo b43_phy_write(dev, 0x0059, backup[5]);
68358619b14SKalle Valo b43_phy_write(dev, 0x0058, backup[6]);
68458619b14SKalle Valo b43_synth_pu_workaround(dev, phy->channel);
68558619b14SKalle Valo b43_phy_set(dev, 0x0802, (0x0001 | 0x0002));
68658619b14SKalle Valo b43_set_original_gains(dev);
68758619b14SKalle Valo b43_phy_set(dev, B43_PHY_G_CRS, 0x8000);
68858619b14SKalle Valo if (phy->rev >= 3) {
68958619b14SKalle Valo b43_phy_write(dev, 0x0801, backup[14]);
69058619b14SKalle Valo b43_phy_write(dev, 0x0060, backup[15]);
69158619b14SKalle Valo b43_phy_write(dev, 0x0014, backup[16]);
69258619b14SKalle Valo b43_phy_write(dev, 0x0478, backup[17]);
69358619b14SKalle Valo }
69458619b14SKalle Valo b43_nrssi_mem_update(dev);
69558619b14SKalle Valo b43_calc_nrssi_threshold(dev);
69658619b14SKalle Valo }
69758619b14SKalle Valo
b43_calc_nrssi_threshold(struct b43_wldev * dev)69858619b14SKalle Valo static void b43_calc_nrssi_threshold(struct b43_wldev *dev)
69958619b14SKalle Valo {
70058619b14SKalle Valo struct b43_phy *phy = &dev->phy;
70158619b14SKalle Valo struct b43_phy_g *gphy = phy->g;
70258619b14SKalle Valo s32 a, b;
70358619b14SKalle Valo s16 tmp16;
70458619b14SKalle Valo u16 tmp_u16;
70558619b14SKalle Valo
70658619b14SKalle Valo B43_WARN_ON(phy->type != B43_PHYTYPE_G);
70758619b14SKalle Valo
70858619b14SKalle Valo if (!phy->gmode ||
70958619b14SKalle Valo !(dev->dev->bus_sprom->boardflags_lo & B43_BFL_RSSI)) {
71058619b14SKalle Valo tmp16 = b43_nrssi_hw_read(dev, 0x20);
71158619b14SKalle Valo if (tmp16 >= 0x20)
71258619b14SKalle Valo tmp16 -= 0x40;
71358619b14SKalle Valo if (tmp16 < 3) {
71458619b14SKalle Valo b43_phy_maskset(dev, 0x048A, 0xF000, 0x09EB);
71558619b14SKalle Valo } else {
71658619b14SKalle Valo b43_phy_maskset(dev, 0x048A, 0xF000, 0x0AED);
71758619b14SKalle Valo }
71858619b14SKalle Valo } else {
71958619b14SKalle Valo if (gphy->interfmode == B43_INTERFMODE_NONWLAN) {
72058619b14SKalle Valo a = 0xE;
72158619b14SKalle Valo b = 0xA;
72258619b14SKalle Valo } else if (!gphy->aci_wlan_automatic && gphy->aci_enable) {
72358619b14SKalle Valo a = 0x13;
72458619b14SKalle Valo b = 0x12;
72558619b14SKalle Valo } else {
72658619b14SKalle Valo a = 0xE;
72758619b14SKalle Valo b = 0x11;
72858619b14SKalle Valo }
72958619b14SKalle Valo
73058619b14SKalle Valo a = a * (gphy->nrssi[1] - gphy->nrssi[0]);
73158619b14SKalle Valo a += (gphy->nrssi[0] << 6);
73258619b14SKalle Valo if (a < 32)
73358619b14SKalle Valo a += 31;
73458619b14SKalle Valo else
73558619b14SKalle Valo a += 32;
73658619b14SKalle Valo a = a >> 6;
73758619b14SKalle Valo a = clamp_val(a, -31, 31);
73858619b14SKalle Valo
73958619b14SKalle Valo b = b * (gphy->nrssi[1] - gphy->nrssi[0]);
74058619b14SKalle Valo b += (gphy->nrssi[0] << 6);
74158619b14SKalle Valo if (b < 32)
74258619b14SKalle Valo b += 31;
74358619b14SKalle Valo else
74458619b14SKalle Valo b += 32;
74558619b14SKalle Valo b = b >> 6;
74658619b14SKalle Valo b = clamp_val(b, -31, 31);
74758619b14SKalle Valo
74858619b14SKalle Valo tmp_u16 = b43_phy_read(dev, 0x048A) & 0xF000;
74958619b14SKalle Valo tmp_u16 |= ((u32) b & 0x0000003F);
75058619b14SKalle Valo tmp_u16 |= (((u32) a & 0x0000003F) << 6);
75158619b14SKalle Valo b43_phy_write(dev, 0x048A, tmp_u16);
75258619b14SKalle Valo }
75358619b14SKalle Valo }
75458619b14SKalle Valo
75558619b14SKalle Valo /* Stack implementation to save/restore values from the
75658619b14SKalle Valo * interference mitigation code.
75758619b14SKalle Valo * It is save to restore values in random order.
75858619b14SKalle Valo */
_stack_save(u32 * _stackptr,size_t * stackidx,u8 id,u16 offset,u16 value)75958619b14SKalle Valo static void _stack_save(u32 *_stackptr, size_t *stackidx,
76058619b14SKalle Valo u8 id, u16 offset, u16 value)
76158619b14SKalle Valo {
76258619b14SKalle Valo u32 *stackptr = &(_stackptr[*stackidx]);
76358619b14SKalle Valo
76458619b14SKalle Valo B43_WARN_ON(offset & 0xF000);
76558619b14SKalle Valo B43_WARN_ON(id & 0xF0);
76658619b14SKalle Valo *stackptr = offset;
76758619b14SKalle Valo *stackptr |= ((u32) id) << 12;
76858619b14SKalle Valo *stackptr |= ((u32) value) << 16;
76958619b14SKalle Valo (*stackidx)++;
77058619b14SKalle Valo B43_WARN_ON(*stackidx >= B43_INTERFSTACK_SIZE);
77158619b14SKalle Valo }
77258619b14SKalle Valo
_stack_restore(u32 * stackptr,u8 id,u16 offset)77358619b14SKalle Valo static u16 _stack_restore(u32 *stackptr, u8 id, u16 offset)
77458619b14SKalle Valo {
77558619b14SKalle Valo size_t i;
77658619b14SKalle Valo
77758619b14SKalle Valo B43_WARN_ON(offset & 0xF000);
77858619b14SKalle Valo B43_WARN_ON(id & 0xF0);
77958619b14SKalle Valo for (i = 0; i < B43_INTERFSTACK_SIZE; i++, stackptr++) {
78058619b14SKalle Valo if ((*stackptr & 0x00000FFF) != offset)
78158619b14SKalle Valo continue;
78258619b14SKalle Valo if (((*stackptr & 0x0000F000) >> 12) != id)
78358619b14SKalle Valo continue;
78458619b14SKalle Valo return ((*stackptr & 0xFFFF0000) >> 16);
78558619b14SKalle Valo }
78658619b14SKalle Valo B43_WARN_ON(1);
78758619b14SKalle Valo
78858619b14SKalle Valo return 0;
78958619b14SKalle Valo }
79058619b14SKalle Valo
79158619b14SKalle Valo #define phy_stacksave(offset) \
79258619b14SKalle Valo do { \
79358619b14SKalle Valo _stack_save(stack, &stackidx, 0x1, (offset), \
79458619b14SKalle Valo b43_phy_read(dev, (offset))); \
79558619b14SKalle Valo } while (0)
79658619b14SKalle Valo #define phy_stackrestore(offset) \
79758619b14SKalle Valo do { \
79858619b14SKalle Valo b43_phy_write(dev, (offset), \
79958619b14SKalle Valo _stack_restore(stack, 0x1, \
80058619b14SKalle Valo (offset))); \
80158619b14SKalle Valo } while (0)
80258619b14SKalle Valo #define radio_stacksave(offset) \
80358619b14SKalle Valo do { \
80458619b14SKalle Valo _stack_save(stack, &stackidx, 0x2, (offset), \
80558619b14SKalle Valo b43_radio_read16(dev, (offset))); \
80658619b14SKalle Valo } while (0)
80758619b14SKalle Valo #define radio_stackrestore(offset) \
80858619b14SKalle Valo do { \
80958619b14SKalle Valo b43_radio_write16(dev, (offset), \
81058619b14SKalle Valo _stack_restore(stack, 0x2, \
81158619b14SKalle Valo (offset))); \
81258619b14SKalle Valo } while (0)
81358619b14SKalle Valo #define ofdmtab_stacksave(table, offset) \
81458619b14SKalle Valo do { \
81558619b14SKalle Valo _stack_save(stack, &stackidx, 0x3, (offset)|(table), \
81658619b14SKalle Valo b43_ofdmtab_read16(dev, (table), (offset))); \
81758619b14SKalle Valo } while (0)
81858619b14SKalle Valo #define ofdmtab_stackrestore(table, offset) \
81958619b14SKalle Valo do { \
82058619b14SKalle Valo b43_ofdmtab_write16(dev, (table), (offset), \
82158619b14SKalle Valo _stack_restore(stack, 0x3, \
82258619b14SKalle Valo (offset)|(table))); \
82358619b14SKalle Valo } while (0)
82458619b14SKalle Valo
82558619b14SKalle Valo static void
b43_radio_interference_mitigation_enable(struct b43_wldev * dev,int mode)82658619b14SKalle Valo b43_radio_interference_mitigation_enable(struct b43_wldev *dev, int mode)
82758619b14SKalle Valo {
82858619b14SKalle Valo struct b43_phy *phy = &dev->phy;
82958619b14SKalle Valo struct b43_phy_g *gphy = phy->g;
83058619b14SKalle Valo u16 tmp, flipped;
83158619b14SKalle Valo size_t stackidx = 0;
83258619b14SKalle Valo u32 *stack = gphy->interfstack;
83358619b14SKalle Valo
83458619b14SKalle Valo switch (mode) {
83558619b14SKalle Valo case B43_INTERFMODE_NONWLAN:
83658619b14SKalle Valo if (phy->rev != 1) {
83758619b14SKalle Valo b43_phy_set(dev, 0x042B, 0x0800);
83858619b14SKalle Valo b43_phy_mask(dev, B43_PHY_G_CRS, ~0x4000);
83958619b14SKalle Valo break;
84058619b14SKalle Valo }
84158619b14SKalle Valo radio_stacksave(0x0078);
84258619b14SKalle Valo tmp = (b43_radio_read16(dev, 0x0078) & 0x001E);
84358619b14SKalle Valo B43_WARN_ON(tmp > 15);
84458619b14SKalle Valo flipped = bitrev4(tmp);
84558619b14SKalle Valo if (flipped < 10 && flipped >= 8)
84658619b14SKalle Valo flipped = 7;
84758619b14SKalle Valo else if (flipped >= 10)
84858619b14SKalle Valo flipped -= 3;
84958619b14SKalle Valo flipped = (bitrev4(flipped) << 1) | 0x0020;
85058619b14SKalle Valo b43_radio_write16(dev, 0x0078, flipped);
85158619b14SKalle Valo
85258619b14SKalle Valo b43_calc_nrssi_threshold(dev);
85358619b14SKalle Valo
85458619b14SKalle Valo phy_stacksave(0x0406);
85558619b14SKalle Valo b43_phy_write(dev, 0x0406, 0x7E28);
85658619b14SKalle Valo
85758619b14SKalle Valo b43_phy_set(dev, 0x042B, 0x0800);
85858619b14SKalle Valo b43_phy_set(dev, B43_PHY_RADIO_BITFIELD, 0x1000);
85958619b14SKalle Valo
86058619b14SKalle Valo phy_stacksave(0x04A0);
86158619b14SKalle Valo b43_phy_maskset(dev, 0x04A0, 0xC0C0, 0x0008);
86258619b14SKalle Valo phy_stacksave(0x04A1);
86358619b14SKalle Valo b43_phy_maskset(dev, 0x04A1, 0xC0C0, 0x0605);
86458619b14SKalle Valo phy_stacksave(0x04A2);
86558619b14SKalle Valo b43_phy_maskset(dev, 0x04A2, 0xC0C0, 0x0204);
86658619b14SKalle Valo phy_stacksave(0x04A8);
86758619b14SKalle Valo b43_phy_maskset(dev, 0x04A8, 0xC0C0, 0x0803);
86858619b14SKalle Valo phy_stacksave(0x04AB);
86958619b14SKalle Valo b43_phy_maskset(dev, 0x04AB, 0xC0C0, 0x0605);
87058619b14SKalle Valo
87158619b14SKalle Valo phy_stacksave(0x04A7);
87258619b14SKalle Valo b43_phy_write(dev, 0x04A7, 0x0002);
87358619b14SKalle Valo phy_stacksave(0x04A3);
87458619b14SKalle Valo b43_phy_write(dev, 0x04A3, 0x287A);
87558619b14SKalle Valo phy_stacksave(0x04A9);
87658619b14SKalle Valo b43_phy_write(dev, 0x04A9, 0x2027);
87758619b14SKalle Valo phy_stacksave(0x0493);
87858619b14SKalle Valo b43_phy_write(dev, 0x0493, 0x32F5);
87958619b14SKalle Valo phy_stacksave(0x04AA);
88058619b14SKalle Valo b43_phy_write(dev, 0x04AA, 0x2027);
88158619b14SKalle Valo phy_stacksave(0x04AC);
88258619b14SKalle Valo b43_phy_write(dev, 0x04AC, 0x32F5);
88358619b14SKalle Valo break;
88458619b14SKalle Valo case B43_INTERFMODE_MANUALWLAN:
88558619b14SKalle Valo if (b43_phy_read(dev, 0x0033) & 0x0800)
88658619b14SKalle Valo break;
88758619b14SKalle Valo
88858619b14SKalle Valo gphy->aci_enable = true;
88958619b14SKalle Valo
89058619b14SKalle Valo phy_stacksave(B43_PHY_RADIO_BITFIELD);
89158619b14SKalle Valo phy_stacksave(B43_PHY_G_CRS);
89258619b14SKalle Valo if (phy->rev < 2) {
89358619b14SKalle Valo phy_stacksave(0x0406);
89458619b14SKalle Valo } else {
89558619b14SKalle Valo phy_stacksave(0x04C0);
89658619b14SKalle Valo phy_stacksave(0x04C1);
89758619b14SKalle Valo }
89858619b14SKalle Valo phy_stacksave(0x0033);
89958619b14SKalle Valo phy_stacksave(0x04A7);
90058619b14SKalle Valo phy_stacksave(0x04A3);
90158619b14SKalle Valo phy_stacksave(0x04A9);
90258619b14SKalle Valo phy_stacksave(0x04AA);
90358619b14SKalle Valo phy_stacksave(0x04AC);
90458619b14SKalle Valo phy_stacksave(0x0493);
90558619b14SKalle Valo phy_stacksave(0x04A1);
90658619b14SKalle Valo phy_stacksave(0x04A0);
90758619b14SKalle Valo phy_stacksave(0x04A2);
90858619b14SKalle Valo phy_stacksave(0x048A);
90958619b14SKalle Valo phy_stacksave(0x04A8);
91058619b14SKalle Valo phy_stacksave(0x04AB);
91158619b14SKalle Valo if (phy->rev == 2) {
91258619b14SKalle Valo phy_stacksave(0x04AD);
91358619b14SKalle Valo phy_stacksave(0x04AE);
91458619b14SKalle Valo } else if (phy->rev >= 3) {
91558619b14SKalle Valo phy_stacksave(0x04AD);
91658619b14SKalle Valo phy_stacksave(0x0415);
91758619b14SKalle Valo phy_stacksave(0x0416);
91858619b14SKalle Valo phy_stacksave(0x0417);
91958619b14SKalle Valo ofdmtab_stacksave(0x1A00, 0x2);
92058619b14SKalle Valo ofdmtab_stacksave(0x1A00, 0x3);
92158619b14SKalle Valo }
92258619b14SKalle Valo phy_stacksave(0x042B);
92358619b14SKalle Valo phy_stacksave(0x048C);
92458619b14SKalle Valo
92558619b14SKalle Valo b43_phy_mask(dev, B43_PHY_RADIO_BITFIELD, ~0x1000);
92658619b14SKalle Valo b43_phy_maskset(dev, B43_PHY_G_CRS, 0xFFFC, 0x0002);
92758619b14SKalle Valo
92858619b14SKalle Valo b43_phy_write(dev, 0x0033, 0x0800);
92958619b14SKalle Valo b43_phy_write(dev, 0x04A3, 0x2027);
93058619b14SKalle Valo b43_phy_write(dev, 0x04A9, 0x1CA8);
93158619b14SKalle Valo b43_phy_write(dev, 0x0493, 0x287A);
93258619b14SKalle Valo b43_phy_write(dev, 0x04AA, 0x1CA8);
93358619b14SKalle Valo b43_phy_write(dev, 0x04AC, 0x287A);
93458619b14SKalle Valo
93558619b14SKalle Valo b43_phy_maskset(dev, 0x04A0, 0xFFC0, 0x001A);
93658619b14SKalle Valo b43_phy_write(dev, 0x04A7, 0x000D);
93758619b14SKalle Valo
93858619b14SKalle Valo if (phy->rev < 2) {
93958619b14SKalle Valo b43_phy_write(dev, 0x0406, 0xFF0D);
94058619b14SKalle Valo } else if (phy->rev == 2) {
94158619b14SKalle Valo b43_phy_write(dev, 0x04C0, 0xFFFF);
94258619b14SKalle Valo b43_phy_write(dev, 0x04C1, 0x00A9);
94358619b14SKalle Valo } else {
94458619b14SKalle Valo b43_phy_write(dev, 0x04C0, 0x00C1);
94558619b14SKalle Valo b43_phy_write(dev, 0x04C1, 0x0059);
94658619b14SKalle Valo }
94758619b14SKalle Valo
94858619b14SKalle Valo b43_phy_maskset(dev, 0x04A1, 0xC0FF, 0x1800);
94958619b14SKalle Valo b43_phy_maskset(dev, 0x04A1, 0xFFC0, 0x0015);
95058619b14SKalle Valo b43_phy_maskset(dev, 0x04A8, 0xCFFF, 0x1000);
95158619b14SKalle Valo b43_phy_maskset(dev, 0x04A8, 0xF0FF, 0x0A00);
95258619b14SKalle Valo b43_phy_maskset(dev, 0x04AB, 0xCFFF, 0x1000);
95358619b14SKalle Valo b43_phy_maskset(dev, 0x04AB, 0xF0FF, 0x0800);
95458619b14SKalle Valo b43_phy_maskset(dev, 0x04AB, 0xFFCF, 0x0010);
95558619b14SKalle Valo b43_phy_maskset(dev, 0x04AB, 0xFFF0, 0x0005);
95658619b14SKalle Valo b43_phy_maskset(dev, 0x04A8, 0xFFCF, 0x0010);
95758619b14SKalle Valo b43_phy_maskset(dev, 0x04A8, 0xFFF0, 0x0006);
95858619b14SKalle Valo b43_phy_maskset(dev, 0x04A2, 0xF0FF, 0x0800);
95958619b14SKalle Valo b43_phy_maskset(dev, 0x04A0, 0xF0FF, 0x0500);
96058619b14SKalle Valo b43_phy_maskset(dev, 0x04A2, 0xFFF0, 0x000B);
96158619b14SKalle Valo
96258619b14SKalle Valo if (phy->rev >= 3) {
96358619b14SKalle Valo b43_phy_mask(dev, 0x048A, 0x7FFF);
96458619b14SKalle Valo b43_phy_maskset(dev, 0x0415, 0x8000, 0x36D8);
96558619b14SKalle Valo b43_phy_maskset(dev, 0x0416, 0x8000, 0x36D8);
96658619b14SKalle Valo b43_phy_maskset(dev, 0x0417, 0xFE00, 0x016D);
96758619b14SKalle Valo } else {
96858619b14SKalle Valo b43_phy_set(dev, 0x048A, 0x1000);
96958619b14SKalle Valo b43_phy_maskset(dev, 0x048A, 0x9FFF, 0x2000);
97058619b14SKalle Valo b43_hf_write(dev, b43_hf_read(dev) | B43_HF_ACIW);
97158619b14SKalle Valo }
97258619b14SKalle Valo if (phy->rev >= 2) {
97358619b14SKalle Valo b43_phy_set(dev, 0x042B, 0x0800);
97458619b14SKalle Valo }
97558619b14SKalle Valo b43_phy_maskset(dev, 0x048C, 0xF0FF, 0x0200);
97658619b14SKalle Valo if (phy->rev == 2) {
97758619b14SKalle Valo b43_phy_maskset(dev, 0x04AE, 0xFF00, 0x007F);
97858619b14SKalle Valo b43_phy_maskset(dev, 0x04AD, 0x00FF, 0x1300);
97958619b14SKalle Valo } else if (phy->rev >= 6) {
98058619b14SKalle Valo b43_ofdmtab_write16(dev, 0x1A00, 0x3, 0x007F);
98158619b14SKalle Valo b43_ofdmtab_write16(dev, 0x1A00, 0x2, 0x007F);
98258619b14SKalle Valo b43_phy_mask(dev, 0x04AD, 0x00FF);
98358619b14SKalle Valo }
98458619b14SKalle Valo b43_calc_nrssi_slope(dev);
98558619b14SKalle Valo break;
98658619b14SKalle Valo default:
98758619b14SKalle Valo B43_WARN_ON(1);
98858619b14SKalle Valo }
98958619b14SKalle Valo }
99058619b14SKalle Valo
99158619b14SKalle Valo static void
b43_radio_interference_mitigation_disable(struct b43_wldev * dev,int mode)99258619b14SKalle Valo b43_radio_interference_mitigation_disable(struct b43_wldev *dev, int mode)
99358619b14SKalle Valo {
99458619b14SKalle Valo struct b43_phy *phy = &dev->phy;
99558619b14SKalle Valo struct b43_phy_g *gphy = phy->g;
99658619b14SKalle Valo u32 *stack = gphy->interfstack;
99758619b14SKalle Valo
99858619b14SKalle Valo switch (mode) {
99958619b14SKalle Valo case B43_INTERFMODE_NONWLAN:
100058619b14SKalle Valo if (phy->rev != 1) {
100158619b14SKalle Valo b43_phy_mask(dev, 0x042B, ~0x0800);
100258619b14SKalle Valo b43_phy_set(dev, B43_PHY_G_CRS, 0x4000);
100358619b14SKalle Valo break;
100458619b14SKalle Valo }
100558619b14SKalle Valo radio_stackrestore(0x0078);
100658619b14SKalle Valo b43_calc_nrssi_threshold(dev);
100758619b14SKalle Valo phy_stackrestore(0x0406);
100858619b14SKalle Valo b43_phy_mask(dev, 0x042B, ~0x0800);
100958619b14SKalle Valo if (!dev->bad_frames_preempt) {
101058619b14SKalle Valo b43_phy_mask(dev, B43_PHY_RADIO_BITFIELD, ~(1 << 11));
101158619b14SKalle Valo }
101258619b14SKalle Valo b43_phy_set(dev, B43_PHY_G_CRS, 0x4000);
101358619b14SKalle Valo phy_stackrestore(0x04A0);
101458619b14SKalle Valo phy_stackrestore(0x04A1);
101558619b14SKalle Valo phy_stackrestore(0x04A2);
101658619b14SKalle Valo phy_stackrestore(0x04A8);
101758619b14SKalle Valo phy_stackrestore(0x04AB);
101858619b14SKalle Valo phy_stackrestore(0x04A7);
101958619b14SKalle Valo phy_stackrestore(0x04A3);
102058619b14SKalle Valo phy_stackrestore(0x04A9);
102158619b14SKalle Valo phy_stackrestore(0x0493);
102258619b14SKalle Valo phy_stackrestore(0x04AA);
102358619b14SKalle Valo phy_stackrestore(0x04AC);
102458619b14SKalle Valo break;
102558619b14SKalle Valo case B43_INTERFMODE_MANUALWLAN:
102658619b14SKalle Valo if (!(b43_phy_read(dev, 0x0033) & 0x0800))
102758619b14SKalle Valo break;
102858619b14SKalle Valo
102958619b14SKalle Valo gphy->aci_enable = false;
103058619b14SKalle Valo
103158619b14SKalle Valo phy_stackrestore(B43_PHY_RADIO_BITFIELD);
103258619b14SKalle Valo phy_stackrestore(B43_PHY_G_CRS);
103358619b14SKalle Valo phy_stackrestore(0x0033);
103458619b14SKalle Valo phy_stackrestore(0x04A3);
103558619b14SKalle Valo phy_stackrestore(0x04A9);
103658619b14SKalle Valo phy_stackrestore(0x0493);
103758619b14SKalle Valo phy_stackrestore(0x04AA);
103858619b14SKalle Valo phy_stackrestore(0x04AC);
103958619b14SKalle Valo phy_stackrestore(0x04A0);
104058619b14SKalle Valo phy_stackrestore(0x04A7);
104158619b14SKalle Valo if (phy->rev >= 2) {
104258619b14SKalle Valo phy_stackrestore(0x04C0);
104358619b14SKalle Valo phy_stackrestore(0x04C1);
104458619b14SKalle Valo } else
104558619b14SKalle Valo phy_stackrestore(0x0406);
104658619b14SKalle Valo phy_stackrestore(0x04A1);
104758619b14SKalle Valo phy_stackrestore(0x04AB);
104858619b14SKalle Valo phy_stackrestore(0x04A8);
104958619b14SKalle Valo if (phy->rev == 2) {
105058619b14SKalle Valo phy_stackrestore(0x04AD);
105158619b14SKalle Valo phy_stackrestore(0x04AE);
105258619b14SKalle Valo } else if (phy->rev >= 3) {
105358619b14SKalle Valo phy_stackrestore(0x04AD);
105458619b14SKalle Valo phy_stackrestore(0x0415);
105558619b14SKalle Valo phy_stackrestore(0x0416);
105658619b14SKalle Valo phy_stackrestore(0x0417);
105758619b14SKalle Valo ofdmtab_stackrestore(0x1A00, 0x2);
105858619b14SKalle Valo ofdmtab_stackrestore(0x1A00, 0x3);
105958619b14SKalle Valo }
106058619b14SKalle Valo phy_stackrestore(0x04A2);
106158619b14SKalle Valo phy_stackrestore(0x048A);
106258619b14SKalle Valo phy_stackrestore(0x042B);
106358619b14SKalle Valo phy_stackrestore(0x048C);
106458619b14SKalle Valo b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_ACIW);
106558619b14SKalle Valo b43_calc_nrssi_slope(dev);
106658619b14SKalle Valo break;
106758619b14SKalle Valo default:
106858619b14SKalle Valo B43_WARN_ON(1);
106958619b14SKalle Valo }
107058619b14SKalle Valo }
107158619b14SKalle Valo
107258619b14SKalle Valo #undef phy_stacksave
107358619b14SKalle Valo #undef phy_stackrestore
107458619b14SKalle Valo #undef radio_stacksave
107558619b14SKalle Valo #undef radio_stackrestore
107658619b14SKalle Valo #undef ofdmtab_stacksave
107758619b14SKalle Valo #undef ofdmtab_stackrestore
107858619b14SKalle Valo
b43_radio_core_calibration_value(struct b43_wldev * dev)107958619b14SKalle Valo static u16 b43_radio_core_calibration_value(struct b43_wldev *dev)
108058619b14SKalle Valo {
108158619b14SKalle Valo u16 reg, index, ret;
108258619b14SKalle Valo
108358619b14SKalle Valo static const u8 rcc_table[] = {
108458619b14SKalle Valo 0x02, 0x03, 0x01, 0x0F,
108558619b14SKalle Valo 0x06, 0x07, 0x05, 0x0F,
108658619b14SKalle Valo 0x0A, 0x0B, 0x09, 0x0F,
108758619b14SKalle Valo 0x0E, 0x0F, 0x0D, 0x0F,
108858619b14SKalle Valo };
108958619b14SKalle Valo
109058619b14SKalle Valo reg = b43_radio_read16(dev, 0x60);
109158619b14SKalle Valo index = (reg & 0x001E) >> 1;
109258619b14SKalle Valo ret = rcc_table[index] << 1;
109358619b14SKalle Valo ret |= (reg & 0x0001);
109458619b14SKalle Valo ret |= 0x0020;
109558619b14SKalle Valo
109658619b14SKalle Valo return ret;
109758619b14SKalle Valo }
109858619b14SKalle Valo
109958619b14SKalle Valo #define LPD(L, P, D) (((L) << 2) | ((P) << 1) | ((D) << 0))
radio2050_rfover_val(struct b43_wldev * dev,u16 phy_register,unsigned int lpd)110058619b14SKalle Valo static u16 radio2050_rfover_val(struct b43_wldev *dev,
110158619b14SKalle Valo u16 phy_register, unsigned int lpd)
110258619b14SKalle Valo {
110358619b14SKalle Valo struct b43_phy *phy = &dev->phy;
110458619b14SKalle Valo struct b43_phy_g *gphy = phy->g;
110558619b14SKalle Valo struct ssb_sprom *sprom = dev->dev->bus_sprom;
110658619b14SKalle Valo
110758619b14SKalle Valo if (!phy->gmode)
110858619b14SKalle Valo return 0;
110958619b14SKalle Valo
111058619b14SKalle Valo if (has_loopback_gain(phy)) {
111158619b14SKalle Valo int max_lb_gain = gphy->max_lb_gain;
111258619b14SKalle Valo u16 extlna;
111358619b14SKalle Valo u16 i;
111458619b14SKalle Valo
111558619b14SKalle Valo if (phy->radio_rev == 8)
111658619b14SKalle Valo max_lb_gain += 0x3E;
111758619b14SKalle Valo else
111858619b14SKalle Valo max_lb_gain += 0x26;
111958619b14SKalle Valo if (max_lb_gain >= 0x46) {
112058619b14SKalle Valo extlna = 0x3000;
112158619b14SKalle Valo max_lb_gain -= 0x46;
112258619b14SKalle Valo } else if (max_lb_gain >= 0x3A) {
112358619b14SKalle Valo extlna = 0x1000;
112458619b14SKalle Valo max_lb_gain -= 0x3A;
112558619b14SKalle Valo } else if (max_lb_gain >= 0x2E) {
112658619b14SKalle Valo extlna = 0x2000;
112758619b14SKalle Valo max_lb_gain -= 0x2E;
112858619b14SKalle Valo } else {
112958619b14SKalle Valo extlna = 0;
113058619b14SKalle Valo max_lb_gain -= 0x10;
113158619b14SKalle Valo }
113258619b14SKalle Valo
113358619b14SKalle Valo for (i = 0; i < 16; i++) {
113458619b14SKalle Valo max_lb_gain -= (i * 6);
113558619b14SKalle Valo if (max_lb_gain < 6)
113658619b14SKalle Valo break;
113758619b14SKalle Valo }
113858619b14SKalle Valo
113958619b14SKalle Valo if ((phy->rev < 7) ||
114058619b14SKalle Valo !(sprom->boardflags_lo & B43_BFL_EXTLNA)) {
114158619b14SKalle Valo if (phy_register == B43_PHY_RFOVER) {
114258619b14SKalle Valo return 0x1B3;
114358619b14SKalle Valo } else if (phy_register == B43_PHY_RFOVERVAL) {
114458619b14SKalle Valo extlna |= (i << 8);
114558619b14SKalle Valo switch (lpd) {
114658619b14SKalle Valo case LPD(0, 1, 1):
114758619b14SKalle Valo return 0x0F92;
114858619b14SKalle Valo case LPD(0, 0, 1):
114958619b14SKalle Valo case LPD(1, 0, 1):
115058619b14SKalle Valo return (0x0092 | extlna);
115158619b14SKalle Valo case LPD(1, 0, 0):
115258619b14SKalle Valo return (0x0093 | extlna);
115358619b14SKalle Valo }
115458619b14SKalle Valo B43_WARN_ON(1);
115558619b14SKalle Valo }
115658619b14SKalle Valo B43_WARN_ON(1);
115758619b14SKalle Valo } else {
115858619b14SKalle Valo if (phy_register == B43_PHY_RFOVER) {
115958619b14SKalle Valo return 0x9B3;
116058619b14SKalle Valo } else if (phy_register == B43_PHY_RFOVERVAL) {
116158619b14SKalle Valo if (extlna)
116258619b14SKalle Valo extlna |= 0x8000;
116358619b14SKalle Valo extlna |= (i << 8);
116458619b14SKalle Valo switch (lpd) {
116558619b14SKalle Valo case LPD(0, 1, 1):
116658619b14SKalle Valo return 0x8F92;
116758619b14SKalle Valo case LPD(0, 0, 1):
116858619b14SKalle Valo return (0x8092 | extlna);
116958619b14SKalle Valo case LPD(1, 0, 1):
117058619b14SKalle Valo return (0x2092 | extlna);
117158619b14SKalle Valo case LPD(1, 0, 0):
117258619b14SKalle Valo return (0x2093 | extlna);
117358619b14SKalle Valo }
117458619b14SKalle Valo B43_WARN_ON(1);
117558619b14SKalle Valo }
117658619b14SKalle Valo B43_WARN_ON(1);
117758619b14SKalle Valo }
117858619b14SKalle Valo } else {
117958619b14SKalle Valo if ((phy->rev < 7) ||
118058619b14SKalle Valo !(sprom->boardflags_lo & B43_BFL_EXTLNA)) {
118158619b14SKalle Valo if (phy_register == B43_PHY_RFOVER) {
118258619b14SKalle Valo return 0x1B3;
118358619b14SKalle Valo } else if (phy_register == B43_PHY_RFOVERVAL) {
118458619b14SKalle Valo switch (lpd) {
118558619b14SKalle Valo case LPD(0, 1, 1):
118658619b14SKalle Valo return 0x0FB2;
118758619b14SKalle Valo case LPD(0, 0, 1):
118858619b14SKalle Valo return 0x00B2;
118958619b14SKalle Valo case LPD(1, 0, 1):
119058619b14SKalle Valo return 0x30B2;
119158619b14SKalle Valo case LPD(1, 0, 0):
119258619b14SKalle Valo return 0x30B3;
119358619b14SKalle Valo }
119458619b14SKalle Valo B43_WARN_ON(1);
119558619b14SKalle Valo }
119658619b14SKalle Valo B43_WARN_ON(1);
119758619b14SKalle Valo } else {
119858619b14SKalle Valo if (phy_register == B43_PHY_RFOVER) {
119958619b14SKalle Valo return 0x9B3;
120058619b14SKalle Valo } else if (phy_register == B43_PHY_RFOVERVAL) {
120158619b14SKalle Valo switch (lpd) {
120258619b14SKalle Valo case LPD(0, 1, 1):
120358619b14SKalle Valo return 0x8FB2;
120458619b14SKalle Valo case LPD(0, 0, 1):
120558619b14SKalle Valo return 0x80B2;
120658619b14SKalle Valo case LPD(1, 0, 1):
120758619b14SKalle Valo return 0x20B2;
120858619b14SKalle Valo case LPD(1, 0, 0):
120958619b14SKalle Valo return 0x20B3;
121058619b14SKalle Valo }
121158619b14SKalle Valo B43_WARN_ON(1);
121258619b14SKalle Valo }
121358619b14SKalle Valo B43_WARN_ON(1);
121458619b14SKalle Valo }
121558619b14SKalle Valo }
121658619b14SKalle Valo return 0;
121758619b14SKalle Valo }
121858619b14SKalle Valo
121958619b14SKalle Valo struct init2050_saved_values {
122058619b14SKalle Valo /* Core registers */
122158619b14SKalle Valo u16 reg_3EC;
122258619b14SKalle Valo u16 reg_3E6;
122358619b14SKalle Valo u16 reg_3F4;
122458619b14SKalle Valo /* Radio registers */
122558619b14SKalle Valo u16 radio_43;
122658619b14SKalle Valo u16 radio_51;
122758619b14SKalle Valo u16 radio_52;
122858619b14SKalle Valo /* PHY registers */
122958619b14SKalle Valo u16 phy_pgactl;
123058619b14SKalle Valo u16 phy_cck_5A;
123158619b14SKalle Valo u16 phy_cck_59;
123258619b14SKalle Valo u16 phy_cck_58;
123358619b14SKalle Valo u16 phy_cck_30;
123458619b14SKalle Valo u16 phy_rfover;
123558619b14SKalle Valo u16 phy_rfoverval;
123658619b14SKalle Valo u16 phy_analogover;
123758619b14SKalle Valo u16 phy_analogoverval;
123858619b14SKalle Valo u16 phy_crs0;
123958619b14SKalle Valo u16 phy_classctl;
124058619b14SKalle Valo u16 phy_lo_mask;
124158619b14SKalle Valo u16 phy_lo_ctl;
124258619b14SKalle Valo u16 phy_syncctl;
124358619b14SKalle Valo };
124458619b14SKalle Valo
b43_radio_init2050(struct b43_wldev * dev)124558619b14SKalle Valo static u16 b43_radio_init2050(struct b43_wldev *dev)
124658619b14SKalle Valo {
124758619b14SKalle Valo struct b43_phy *phy = &dev->phy;
124858619b14SKalle Valo struct init2050_saved_values sav;
124958619b14SKalle Valo u16 rcc;
125058619b14SKalle Valo u16 radio78;
125158619b14SKalle Valo u16 ret;
125258619b14SKalle Valo u16 i, j;
125358619b14SKalle Valo u32 tmp1 = 0, tmp2 = 0;
125458619b14SKalle Valo
125558619b14SKalle Valo memset(&sav, 0, sizeof(sav)); /* get rid of "may be used uninitialized..." */
125658619b14SKalle Valo
125758619b14SKalle Valo sav.radio_43 = b43_radio_read16(dev, 0x43);
125858619b14SKalle Valo sav.radio_51 = b43_radio_read16(dev, 0x51);
125958619b14SKalle Valo sav.radio_52 = b43_radio_read16(dev, 0x52);
126058619b14SKalle Valo sav.phy_pgactl = b43_phy_read(dev, B43_PHY_PGACTL);
126158619b14SKalle Valo sav.phy_cck_5A = b43_phy_read(dev, B43_PHY_CCK(0x5A));
126258619b14SKalle Valo sav.phy_cck_59 = b43_phy_read(dev, B43_PHY_CCK(0x59));
126358619b14SKalle Valo sav.phy_cck_58 = b43_phy_read(dev, B43_PHY_CCK(0x58));
126458619b14SKalle Valo
126558619b14SKalle Valo if (phy->type == B43_PHYTYPE_B) {
126658619b14SKalle Valo sav.phy_cck_30 = b43_phy_read(dev, B43_PHY_CCK(0x30));
126758619b14SKalle Valo sav.reg_3EC = b43_read16(dev, 0x3EC);
126858619b14SKalle Valo
126958619b14SKalle Valo b43_phy_write(dev, B43_PHY_CCK(0x30), 0xFF);
127058619b14SKalle Valo b43_write16(dev, 0x3EC, 0x3F3F);
127158619b14SKalle Valo } else if (phy->gmode || phy->rev >= 2) {
127258619b14SKalle Valo sav.phy_rfover = b43_phy_read(dev, B43_PHY_RFOVER);
127358619b14SKalle Valo sav.phy_rfoverval = b43_phy_read(dev, B43_PHY_RFOVERVAL);
127458619b14SKalle Valo sav.phy_analogover = b43_phy_read(dev, B43_PHY_ANALOGOVER);
127558619b14SKalle Valo sav.phy_analogoverval =
127658619b14SKalle Valo b43_phy_read(dev, B43_PHY_ANALOGOVERVAL);
127758619b14SKalle Valo sav.phy_crs0 = b43_phy_read(dev, B43_PHY_CRS0);
127858619b14SKalle Valo sav.phy_classctl = b43_phy_read(dev, B43_PHY_CLASSCTL);
127958619b14SKalle Valo
128058619b14SKalle Valo b43_phy_set(dev, B43_PHY_ANALOGOVER, 0x0003);
128158619b14SKalle Valo b43_phy_mask(dev, B43_PHY_ANALOGOVERVAL, 0xFFFC);
128258619b14SKalle Valo b43_phy_mask(dev, B43_PHY_CRS0, 0x7FFF);
128358619b14SKalle Valo b43_phy_mask(dev, B43_PHY_CLASSCTL, 0xFFFC);
128458619b14SKalle Valo if (has_loopback_gain(phy)) {
128558619b14SKalle Valo sav.phy_lo_mask = b43_phy_read(dev, B43_PHY_LO_MASK);
128658619b14SKalle Valo sav.phy_lo_ctl = b43_phy_read(dev, B43_PHY_LO_CTL);
128758619b14SKalle Valo
128858619b14SKalle Valo if (phy->rev >= 3)
128958619b14SKalle Valo b43_phy_write(dev, B43_PHY_LO_MASK, 0xC020);
129058619b14SKalle Valo else
129158619b14SKalle Valo b43_phy_write(dev, B43_PHY_LO_MASK, 0x8020);
129258619b14SKalle Valo b43_phy_write(dev, B43_PHY_LO_CTL, 0);
129358619b14SKalle Valo }
129458619b14SKalle Valo
129558619b14SKalle Valo b43_phy_write(dev, B43_PHY_RFOVERVAL,
129658619b14SKalle Valo radio2050_rfover_val(dev, B43_PHY_RFOVERVAL,
129758619b14SKalle Valo LPD(0, 1, 1)));
129858619b14SKalle Valo b43_phy_write(dev, B43_PHY_RFOVER,
129958619b14SKalle Valo radio2050_rfover_val(dev, B43_PHY_RFOVER, 0));
130058619b14SKalle Valo }
130158619b14SKalle Valo b43_write16(dev, 0x3E2, b43_read16(dev, 0x3E2) | 0x8000);
130258619b14SKalle Valo
130358619b14SKalle Valo sav.phy_syncctl = b43_phy_read(dev, B43_PHY_SYNCCTL);
130458619b14SKalle Valo b43_phy_mask(dev, B43_PHY_SYNCCTL, 0xFF7F);
130558619b14SKalle Valo sav.reg_3E6 = b43_read16(dev, 0x3E6);
130658619b14SKalle Valo sav.reg_3F4 = b43_read16(dev, 0x3F4);
130758619b14SKalle Valo
130858619b14SKalle Valo if (phy->analog == 0) {
130958619b14SKalle Valo b43_write16(dev, 0x03E6, 0x0122);
131058619b14SKalle Valo } else {
131158619b14SKalle Valo if (phy->analog >= 2) {
131258619b14SKalle Valo b43_phy_maskset(dev, B43_PHY_CCK(0x03), 0xFFBF, 0x40);
131358619b14SKalle Valo }
131458619b14SKalle Valo b43_write16(dev, B43_MMIO_CHANNEL_EXT,
131558619b14SKalle Valo (b43_read16(dev, B43_MMIO_CHANNEL_EXT) | 0x2000));
131658619b14SKalle Valo }
131758619b14SKalle Valo
131858619b14SKalle Valo rcc = b43_radio_core_calibration_value(dev);
131958619b14SKalle Valo
132058619b14SKalle Valo if (phy->type == B43_PHYTYPE_B)
132158619b14SKalle Valo b43_radio_write16(dev, 0x78, 0x26);
132258619b14SKalle Valo if (phy->gmode || phy->rev >= 2) {
132358619b14SKalle Valo b43_phy_write(dev, B43_PHY_RFOVERVAL,
132458619b14SKalle Valo radio2050_rfover_val(dev, B43_PHY_RFOVERVAL,
132558619b14SKalle Valo LPD(0, 1, 1)));
132658619b14SKalle Valo }
132758619b14SKalle Valo b43_phy_write(dev, B43_PHY_PGACTL, 0xBFAF);
132858619b14SKalle Valo b43_phy_write(dev, B43_PHY_CCK(0x2B), 0x1403);
132958619b14SKalle Valo if (phy->gmode || phy->rev >= 2) {
133058619b14SKalle Valo b43_phy_write(dev, B43_PHY_RFOVERVAL,
133158619b14SKalle Valo radio2050_rfover_val(dev, B43_PHY_RFOVERVAL,
133258619b14SKalle Valo LPD(0, 0, 1)));
133358619b14SKalle Valo }
133458619b14SKalle Valo b43_phy_write(dev, B43_PHY_PGACTL, 0xBFA0);
133558619b14SKalle Valo b43_radio_set(dev, 0x51, 0x0004);
133658619b14SKalle Valo if (phy->radio_rev == 8) {
133758619b14SKalle Valo b43_radio_write16(dev, 0x43, 0x1F);
133858619b14SKalle Valo } else {
133958619b14SKalle Valo b43_radio_write16(dev, 0x52, 0);
134058619b14SKalle Valo b43_radio_maskset(dev, 0x43, 0xFFF0, 0x0009);
134158619b14SKalle Valo }
134258619b14SKalle Valo b43_phy_write(dev, B43_PHY_CCK(0x58), 0);
134358619b14SKalle Valo
134458619b14SKalle Valo for (i = 0; i < 16; i++) {
134558619b14SKalle Valo b43_phy_write(dev, B43_PHY_CCK(0x5A), 0x0480);
134658619b14SKalle Valo b43_phy_write(dev, B43_PHY_CCK(0x59), 0xC810);
134758619b14SKalle Valo b43_phy_write(dev, B43_PHY_CCK(0x58), 0x000D);
134858619b14SKalle Valo if (phy->gmode || phy->rev >= 2) {
134958619b14SKalle Valo b43_phy_write(dev, B43_PHY_RFOVERVAL,
135058619b14SKalle Valo radio2050_rfover_val(dev,
135158619b14SKalle Valo B43_PHY_RFOVERVAL,
135258619b14SKalle Valo LPD(1, 0, 1)));
135358619b14SKalle Valo }
135458619b14SKalle Valo b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0);
135558619b14SKalle Valo udelay(10);
135658619b14SKalle Valo if (phy->gmode || phy->rev >= 2) {
135758619b14SKalle Valo b43_phy_write(dev, B43_PHY_RFOVERVAL,
135858619b14SKalle Valo radio2050_rfover_val(dev,
135958619b14SKalle Valo B43_PHY_RFOVERVAL,
136058619b14SKalle Valo LPD(1, 0, 1)));
136158619b14SKalle Valo }
136258619b14SKalle Valo b43_phy_write(dev, B43_PHY_PGACTL, 0xEFB0);
136358619b14SKalle Valo udelay(10);
136458619b14SKalle Valo if (phy->gmode || phy->rev >= 2) {
136558619b14SKalle Valo b43_phy_write(dev, B43_PHY_RFOVERVAL,
136658619b14SKalle Valo radio2050_rfover_val(dev,
136758619b14SKalle Valo B43_PHY_RFOVERVAL,
136858619b14SKalle Valo LPD(1, 0, 0)));
136958619b14SKalle Valo }
137058619b14SKalle Valo b43_phy_write(dev, B43_PHY_PGACTL, 0xFFF0);
137158619b14SKalle Valo udelay(20);
137258619b14SKalle Valo tmp1 += b43_phy_read(dev, B43_PHY_LO_LEAKAGE);
137358619b14SKalle Valo b43_phy_write(dev, B43_PHY_CCK(0x58), 0);
137458619b14SKalle Valo if (phy->gmode || phy->rev >= 2) {
137558619b14SKalle Valo b43_phy_write(dev, B43_PHY_RFOVERVAL,
137658619b14SKalle Valo radio2050_rfover_val(dev,
137758619b14SKalle Valo B43_PHY_RFOVERVAL,
137858619b14SKalle Valo LPD(1, 0, 1)));
137958619b14SKalle Valo }
138058619b14SKalle Valo b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0);
138158619b14SKalle Valo }
138258619b14SKalle Valo udelay(10);
138358619b14SKalle Valo
138458619b14SKalle Valo b43_phy_write(dev, B43_PHY_CCK(0x58), 0);
138558619b14SKalle Valo tmp1++;
138658619b14SKalle Valo tmp1 >>= 9;
138758619b14SKalle Valo
138858619b14SKalle Valo for (i = 0; i < 16; i++) {
138958619b14SKalle Valo radio78 = (bitrev4(i) << 1) | 0x0020;
139058619b14SKalle Valo b43_radio_write16(dev, 0x78, radio78);
139158619b14SKalle Valo udelay(10);
139258619b14SKalle Valo for (j = 0; j < 16; j++) {
139358619b14SKalle Valo b43_phy_write(dev, B43_PHY_CCK(0x5A), 0x0D80);
139458619b14SKalle Valo b43_phy_write(dev, B43_PHY_CCK(0x59), 0xC810);
139558619b14SKalle Valo b43_phy_write(dev, B43_PHY_CCK(0x58), 0x000D);
139658619b14SKalle Valo if (phy->gmode || phy->rev >= 2) {
139758619b14SKalle Valo b43_phy_write(dev, B43_PHY_RFOVERVAL,
139858619b14SKalle Valo radio2050_rfover_val(dev,
139958619b14SKalle Valo B43_PHY_RFOVERVAL,
140058619b14SKalle Valo LPD(1, 0,
140158619b14SKalle Valo 1)));
140258619b14SKalle Valo }
140358619b14SKalle Valo b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0);
140458619b14SKalle Valo udelay(10);
140558619b14SKalle Valo if (phy->gmode || phy->rev >= 2) {
140658619b14SKalle Valo b43_phy_write(dev, B43_PHY_RFOVERVAL,
140758619b14SKalle Valo radio2050_rfover_val(dev,
140858619b14SKalle Valo B43_PHY_RFOVERVAL,
140958619b14SKalle Valo LPD(1, 0,
141058619b14SKalle Valo 1)));
141158619b14SKalle Valo }
141258619b14SKalle Valo b43_phy_write(dev, B43_PHY_PGACTL, 0xEFB0);
141358619b14SKalle Valo udelay(10);
141458619b14SKalle Valo if (phy->gmode || phy->rev >= 2) {
141558619b14SKalle Valo b43_phy_write(dev, B43_PHY_RFOVERVAL,
141658619b14SKalle Valo radio2050_rfover_val(dev,
141758619b14SKalle Valo B43_PHY_RFOVERVAL,
141858619b14SKalle Valo LPD(1, 0,
141958619b14SKalle Valo 0)));
142058619b14SKalle Valo }
142158619b14SKalle Valo b43_phy_write(dev, B43_PHY_PGACTL, 0xFFF0);
142258619b14SKalle Valo udelay(10);
142358619b14SKalle Valo tmp2 += b43_phy_read(dev, B43_PHY_LO_LEAKAGE);
142458619b14SKalle Valo b43_phy_write(dev, B43_PHY_CCK(0x58), 0);
142558619b14SKalle Valo if (phy->gmode || phy->rev >= 2) {
142658619b14SKalle Valo b43_phy_write(dev, B43_PHY_RFOVERVAL,
142758619b14SKalle Valo radio2050_rfover_val(dev,
142858619b14SKalle Valo B43_PHY_RFOVERVAL,
142958619b14SKalle Valo LPD(1, 0,
143058619b14SKalle Valo 1)));
143158619b14SKalle Valo }
143258619b14SKalle Valo b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0);
143358619b14SKalle Valo }
143458619b14SKalle Valo tmp2++;
143558619b14SKalle Valo tmp2 >>= 8;
143658619b14SKalle Valo if (tmp1 < tmp2)
143758619b14SKalle Valo break;
143858619b14SKalle Valo }
143958619b14SKalle Valo
144058619b14SKalle Valo /* Restore the registers */
144158619b14SKalle Valo b43_phy_write(dev, B43_PHY_PGACTL, sav.phy_pgactl);
144258619b14SKalle Valo b43_radio_write16(dev, 0x51, sav.radio_51);
144358619b14SKalle Valo b43_radio_write16(dev, 0x52, sav.radio_52);
144458619b14SKalle Valo b43_radio_write16(dev, 0x43, sav.radio_43);
144558619b14SKalle Valo b43_phy_write(dev, B43_PHY_CCK(0x5A), sav.phy_cck_5A);
144658619b14SKalle Valo b43_phy_write(dev, B43_PHY_CCK(0x59), sav.phy_cck_59);
144758619b14SKalle Valo b43_phy_write(dev, B43_PHY_CCK(0x58), sav.phy_cck_58);
144858619b14SKalle Valo b43_write16(dev, 0x3E6, sav.reg_3E6);
144958619b14SKalle Valo if (phy->analog != 0)
145058619b14SKalle Valo b43_write16(dev, 0x3F4, sav.reg_3F4);
145158619b14SKalle Valo b43_phy_write(dev, B43_PHY_SYNCCTL, sav.phy_syncctl);
145258619b14SKalle Valo b43_synth_pu_workaround(dev, phy->channel);
145358619b14SKalle Valo if (phy->type == B43_PHYTYPE_B) {
145458619b14SKalle Valo b43_phy_write(dev, B43_PHY_CCK(0x30), sav.phy_cck_30);
145558619b14SKalle Valo b43_write16(dev, 0x3EC, sav.reg_3EC);
145658619b14SKalle Valo } else if (phy->gmode) {
145758619b14SKalle Valo b43_write16(dev, B43_MMIO_PHY_RADIO,
145858619b14SKalle Valo b43_read16(dev, B43_MMIO_PHY_RADIO)
145958619b14SKalle Valo & 0x7FFF);
146058619b14SKalle Valo b43_phy_write(dev, B43_PHY_RFOVER, sav.phy_rfover);
146158619b14SKalle Valo b43_phy_write(dev, B43_PHY_RFOVERVAL, sav.phy_rfoverval);
146258619b14SKalle Valo b43_phy_write(dev, B43_PHY_ANALOGOVER, sav.phy_analogover);
146358619b14SKalle Valo b43_phy_write(dev, B43_PHY_ANALOGOVERVAL,
146458619b14SKalle Valo sav.phy_analogoverval);
146558619b14SKalle Valo b43_phy_write(dev, B43_PHY_CRS0, sav.phy_crs0);
146658619b14SKalle Valo b43_phy_write(dev, B43_PHY_CLASSCTL, sav.phy_classctl);
146758619b14SKalle Valo if (has_loopback_gain(phy)) {
146858619b14SKalle Valo b43_phy_write(dev, B43_PHY_LO_MASK, sav.phy_lo_mask);
146958619b14SKalle Valo b43_phy_write(dev, B43_PHY_LO_CTL, sav.phy_lo_ctl);
147058619b14SKalle Valo }
147158619b14SKalle Valo }
147258619b14SKalle Valo if (i > 15)
147358619b14SKalle Valo ret = radio78;
147458619b14SKalle Valo else
147558619b14SKalle Valo ret = rcc;
147658619b14SKalle Valo
147758619b14SKalle Valo return ret;
147858619b14SKalle Valo }
147958619b14SKalle Valo
b43_phy_initb5(struct b43_wldev * dev)148058619b14SKalle Valo static void b43_phy_initb5(struct b43_wldev *dev)
148158619b14SKalle Valo {
148258619b14SKalle Valo struct b43_phy *phy = &dev->phy;
148358619b14SKalle Valo struct b43_phy_g *gphy = phy->g;
148458619b14SKalle Valo u16 offset, value;
148558619b14SKalle Valo u8 old_channel;
148658619b14SKalle Valo
148758619b14SKalle Valo if (phy->analog == 1) {
148858619b14SKalle Valo b43_radio_set(dev, 0x007A, 0x0050);
148958619b14SKalle Valo }
149058619b14SKalle Valo if ((dev->dev->board_vendor != SSB_BOARDVENDOR_BCM) &&
149158619b14SKalle Valo (dev->dev->board_type != SSB_BOARD_BU4306)) {
149258619b14SKalle Valo value = 0x2120;
149358619b14SKalle Valo for (offset = 0x00A8; offset < 0x00C7; offset++) {
149458619b14SKalle Valo b43_phy_write(dev, offset, value);
149558619b14SKalle Valo value += 0x202;
149658619b14SKalle Valo }
149758619b14SKalle Valo }
149858619b14SKalle Valo b43_phy_maskset(dev, 0x0035, 0xF0FF, 0x0700);
149958619b14SKalle Valo if (phy->radio_ver == 0x2050)
150058619b14SKalle Valo b43_phy_write(dev, 0x0038, 0x0667);
150158619b14SKalle Valo
150258619b14SKalle Valo if (phy->gmode || phy->rev >= 2) {
150358619b14SKalle Valo if (phy->radio_ver == 0x2050) {
150458619b14SKalle Valo b43_radio_set(dev, 0x007A, 0x0020);
150558619b14SKalle Valo b43_radio_set(dev, 0x0051, 0x0004);
150658619b14SKalle Valo }
150758619b14SKalle Valo b43_write16(dev, B43_MMIO_PHY_RADIO, 0x0000);
150858619b14SKalle Valo
150958619b14SKalle Valo b43_phy_set(dev, 0x0802, 0x0100);
151058619b14SKalle Valo b43_phy_set(dev, 0x042B, 0x2000);
151158619b14SKalle Valo
151258619b14SKalle Valo b43_phy_write(dev, 0x001C, 0x186A);
151358619b14SKalle Valo
151458619b14SKalle Valo b43_phy_maskset(dev, 0x0013, 0x00FF, 0x1900);
151558619b14SKalle Valo b43_phy_maskset(dev, 0x0035, 0xFFC0, 0x0064);
151658619b14SKalle Valo b43_phy_maskset(dev, 0x005D, 0xFF80, 0x000A);
151758619b14SKalle Valo }
151858619b14SKalle Valo
151958619b14SKalle Valo if (dev->bad_frames_preempt) {
152058619b14SKalle Valo b43_phy_set(dev, B43_PHY_RADIO_BITFIELD, (1 << 11));
152158619b14SKalle Valo }
152258619b14SKalle Valo
152358619b14SKalle Valo if (phy->analog == 1) {
152458619b14SKalle Valo b43_phy_write(dev, 0x0026, 0xCE00);
152558619b14SKalle Valo b43_phy_write(dev, 0x0021, 0x3763);
152658619b14SKalle Valo b43_phy_write(dev, 0x0022, 0x1BC3);
152758619b14SKalle Valo b43_phy_write(dev, 0x0023, 0x06F9);
152858619b14SKalle Valo b43_phy_write(dev, 0x0024, 0x037E);
152958619b14SKalle Valo } else
153058619b14SKalle Valo b43_phy_write(dev, 0x0026, 0xCC00);
153158619b14SKalle Valo b43_phy_write(dev, 0x0030, 0x00C6);
153258619b14SKalle Valo b43_write16(dev, 0x03EC, 0x3F22);
153358619b14SKalle Valo
153458619b14SKalle Valo if (phy->analog == 1)
153558619b14SKalle Valo b43_phy_write(dev, 0x0020, 0x3E1C);
153658619b14SKalle Valo else
153758619b14SKalle Valo b43_phy_write(dev, 0x0020, 0x301C);
153858619b14SKalle Valo
153958619b14SKalle Valo if (phy->analog == 0)
154058619b14SKalle Valo b43_write16(dev, 0x03E4, 0x3000);
154158619b14SKalle Valo
154258619b14SKalle Valo old_channel = phy->channel;
154358619b14SKalle Valo /* Force to channel 7, even if not supported. */
154458619b14SKalle Valo b43_gphy_channel_switch(dev, 7, 0);
154558619b14SKalle Valo
154658619b14SKalle Valo if (phy->radio_ver != 0x2050) {
154758619b14SKalle Valo b43_radio_write16(dev, 0x0075, 0x0080);
154858619b14SKalle Valo b43_radio_write16(dev, 0x0079, 0x0081);
154958619b14SKalle Valo }
155058619b14SKalle Valo
155158619b14SKalle Valo b43_radio_write16(dev, 0x0050, 0x0020);
155258619b14SKalle Valo b43_radio_write16(dev, 0x0050, 0x0023);
155358619b14SKalle Valo
155458619b14SKalle Valo if (phy->radio_ver == 0x2050) {
155558619b14SKalle Valo b43_radio_write16(dev, 0x0050, 0x0020);
155658619b14SKalle Valo b43_radio_write16(dev, 0x005A, 0x0070);
155758619b14SKalle Valo }
155858619b14SKalle Valo
155958619b14SKalle Valo b43_radio_write16(dev, 0x005B, 0x007B);
156058619b14SKalle Valo b43_radio_write16(dev, 0x005C, 0x00B0);
156158619b14SKalle Valo
156258619b14SKalle Valo b43_radio_set(dev, 0x007A, 0x0007);
156358619b14SKalle Valo
156458619b14SKalle Valo b43_gphy_channel_switch(dev, old_channel, 0);
156558619b14SKalle Valo
156658619b14SKalle Valo b43_phy_write(dev, 0x0014, 0x0080);
156758619b14SKalle Valo b43_phy_write(dev, 0x0032, 0x00CA);
156858619b14SKalle Valo b43_phy_write(dev, 0x002A, 0x88A3);
156958619b14SKalle Valo
157058619b14SKalle Valo b43_set_txpower_g(dev, &gphy->bbatt, &gphy->rfatt, gphy->tx_control);
157158619b14SKalle Valo
157258619b14SKalle Valo if (phy->radio_ver == 0x2050)
157358619b14SKalle Valo b43_radio_write16(dev, 0x005D, 0x000D);
157458619b14SKalle Valo
157558619b14SKalle Valo b43_write16(dev, 0x03E4, (b43_read16(dev, 0x03E4) & 0xFFC0) | 0x0004);
157658619b14SKalle Valo }
157758619b14SKalle Valo
15782d96c1edSAlexander A. Klimov /* https://bcm-v4.sipsolutions.net/802.11/PHY/Init/B6 */
b43_phy_initb6(struct b43_wldev * dev)157958619b14SKalle Valo static void b43_phy_initb6(struct b43_wldev *dev)
158058619b14SKalle Valo {
158158619b14SKalle Valo struct b43_phy *phy = &dev->phy;
158258619b14SKalle Valo struct b43_phy_g *gphy = phy->g;
158358619b14SKalle Valo u16 offset, val;
158458619b14SKalle Valo u8 old_channel;
158558619b14SKalle Valo
158658619b14SKalle Valo b43_phy_write(dev, 0x003E, 0x817A);
158758619b14SKalle Valo b43_radio_write16(dev, 0x007A,
158858619b14SKalle Valo (b43_radio_read16(dev, 0x007A) | 0x0058));
158958619b14SKalle Valo if (phy->radio_rev == 4 || phy->radio_rev == 5) {
159058619b14SKalle Valo b43_radio_write16(dev, 0x51, 0x37);
159158619b14SKalle Valo b43_radio_write16(dev, 0x52, 0x70);
159258619b14SKalle Valo b43_radio_write16(dev, 0x53, 0xB3);
159358619b14SKalle Valo b43_radio_write16(dev, 0x54, 0x9B);
159458619b14SKalle Valo b43_radio_write16(dev, 0x5A, 0x88);
159558619b14SKalle Valo b43_radio_write16(dev, 0x5B, 0x88);
159658619b14SKalle Valo b43_radio_write16(dev, 0x5D, 0x88);
159758619b14SKalle Valo b43_radio_write16(dev, 0x5E, 0x88);
159858619b14SKalle Valo b43_radio_write16(dev, 0x7D, 0x88);
159958619b14SKalle Valo b43_hf_write(dev, b43_hf_read(dev)
160058619b14SKalle Valo | B43_HF_TSSIRPSMW);
160158619b14SKalle Valo }
160258619b14SKalle Valo B43_WARN_ON(phy->radio_rev == 6 || phy->radio_rev == 7); /* We had code for these revs here... */
160358619b14SKalle Valo if (phy->radio_rev == 8) {
160458619b14SKalle Valo b43_radio_write16(dev, 0x51, 0);
160558619b14SKalle Valo b43_radio_write16(dev, 0x52, 0x40);
160658619b14SKalle Valo b43_radio_write16(dev, 0x53, 0xB7);
160758619b14SKalle Valo b43_radio_write16(dev, 0x54, 0x98);
160858619b14SKalle Valo b43_radio_write16(dev, 0x5A, 0x88);
160958619b14SKalle Valo b43_radio_write16(dev, 0x5B, 0x6B);
161058619b14SKalle Valo b43_radio_write16(dev, 0x5C, 0x0F);
161158619b14SKalle Valo if (dev->dev->bus_sprom->boardflags_lo & B43_BFL_ALTIQ) {
161258619b14SKalle Valo b43_radio_write16(dev, 0x5D, 0xFA);
161358619b14SKalle Valo b43_radio_write16(dev, 0x5E, 0xD8);
161458619b14SKalle Valo } else {
161558619b14SKalle Valo b43_radio_write16(dev, 0x5D, 0xF5);
161658619b14SKalle Valo b43_radio_write16(dev, 0x5E, 0xB8);
161758619b14SKalle Valo }
161858619b14SKalle Valo b43_radio_write16(dev, 0x0073, 0x0003);
161958619b14SKalle Valo b43_radio_write16(dev, 0x007D, 0x00A8);
162058619b14SKalle Valo b43_radio_write16(dev, 0x007C, 0x0001);
162158619b14SKalle Valo b43_radio_write16(dev, 0x007E, 0x0008);
162258619b14SKalle Valo }
162358619b14SKalle Valo val = 0x1E1F;
162458619b14SKalle Valo for (offset = 0x0088; offset < 0x0098; offset++) {
162558619b14SKalle Valo b43_phy_write(dev, offset, val);
162658619b14SKalle Valo val -= 0x0202;
162758619b14SKalle Valo }
162858619b14SKalle Valo val = 0x3E3F;
162958619b14SKalle Valo for (offset = 0x0098; offset < 0x00A8; offset++) {
163058619b14SKalle Valo b43_phy_write(dev, offset, val);
163158619b14SKalle Valo val -= 0x0202;
163258619b14SKalle Valo }
163358619b14SKalle Valo val = 0x2120;
163458619b14SKalle Valo for (offset = 0x00A8; offset < 0x00C8; offset++) {
163558619b14SKalle Valo b43_phy_write(dev, offset, (val & 0x3F3F));
163658619b14SKalle Valo val += 0x0202;
163758619b14SKalle Valo }
163858619b14SKalle Valo if (phy->type == B43_PHYTYPE_G) {
163958619b14SKalle Valo b43_radio_set(dev, 0x007A, 0x0020);
164058619b14SKalle Valo b43_radio_set(dev, 0x0051, 0x0004);
164158619b14SKalle Valo b43_phy_set(dev, 0x0802, 0x0100);
164258619b14SKalle Valo b43_phy_set(dev, 0x042B, 0x2000);
164358619b14SKalle Valo b43_phy_write(dev, 0x5B, 0);
164458619b14SKalle Valo b43_phy_write(dev, 0x5C, 0);
164558619b14SKalle Valo }
164658619b14SKalle Valo
164758619b14SKalle Valo old_channel = phy->channel;
164858619b14SKalle Valo if (old_channel >= 8)
164958619b14SKalle Valo b43_gphy_channel_switch(dev, 1, 0);
165058619b14SKalle Valo else
165158619b14SKalle Valo b43_gphy_channel_switch(dev, 13, 0);
165258619b14SKalle Valo
165358619b14SKalle Valo b43_radio_write16(dev, 0x0050, 0x0020);
165458619b14SKalle Valo b43_radio_write16(dev, 0x0050, 0x0023);
165558619b14SKalle Valo udelay(40);
165658619b14SKalle Valo if (phy->radio_rev < 6 || phy->radio_rev == 8) {
165758619b14SKalle Valo b43_radio_write16(dev, 0x7C, (b43_radio_read16(dev, 0x7C)
165858619b14SKalle Valo | 0x0002));
165958619b14SKalle Valo b43_radio_write16(dev, 0x50, 0x20);
166058619b14SKalle Valo }
166158619b14SKalle Valo if (phy->radio_rev <= 2) {
166258619b14SKalle Valo b43_radio_write16(dev, 0x50, 0x20);
166358619b14SKalle Valo b43_radio_write16(dev, 0x5A, 0x70);
166458619b14SKalle Valo b43_radio_write16(dev, 0x5B, 0x7B);
166558619b14SKalle Valo b43_radio_write16(dev, 0x5C, 0xB0);
166658619b14SKalle Valo }
166758619b14SKalle Valo b43_radio_maskset(dev, 0x007A, 0x00F8, 0x0007);
166858619b14SKalle Valo
166958619b14SKalle Valo b43_gphy_channel_switch(dev, old_channel, 0);
167058619b14SKalle Valo
167158619b14SKalle Valo b43_phy_write(dev, 0x0014, 0x0200);
167258619b14SKalle Valo if (phy->radio_rev >= 6)
167358619b14SKalle Valo b43_phy_write(dev, 0x2A, 0x88C2);
167458619b14SKalle Valo else
167558619b14SKalle Valo b43_phy_write(dev, 0x2A, 0x8AC0);
167658619b14SKalle Valo b43_phy_write(dev, 0x0038, 0x0668);
167758619b14SKalle Valo b43_set_txpower_g(dev, &gphy->bbatt, &gphy->rfatt, gphy->tx_control);
167858619b14SKalle Valo if (phy->radio_rev == 4 || phy->radio_rev == 5)
167958619b14SKalle Valo b43_phy_maskset(dev, 0x5D, 0xFF80, 0x0003);
168058619b14SKalle Valo if (phy->radio_rev <= 2)
168158619b14SKalle Valo b43_radio_write16(dev, 0x005D, 0x000D);
168258619b14SKalle Valo
168358619b14SKalle Valo if (phy->analog == 4) {
168458619b14SKalle Valo b43_write16(dev, 0x3E4, 9);
168558619b14SKalle Valo b43_phy_mask(dev, 0x61, 0x0FFF);
168658619b14SKalle Valo } else {
168758619b14SKalle Valo b43_phy_maskset(dev, 0x0002, 0xFFC0, 0x0004);
168858619b14SKalle Valo }
168958619b14SKalle Valo if (phy->type == B43_PHYTYPE_B)
169058619b14SKalle Valo B43_WARN_ON(1);
169158619b14SKalle Valo else if (phy->type == B43_PHYTYPE_G)
169258619b14SKalle Valo b43_write16(dev, 0x03E6, 0x0);
169358619b14SKalle Valo }
169458619b14SKalle Valo
b43_calc_loopback_gain(struct b43_wldev * dev)169558619b14SKalle Valo static void b43_calc_loopback_gain(struct b43_wldev *dev)
169658619b14SKalle Valo {
169758619b14SKalle Valo struct b43_phy *phy = &dev->phy;
169858619b14SKalle Valo struct b43_phy_g *gphy = phy->g;
169958619b14SKalle Valo u16 backup_phy[16] = { 0 };
170058619b14SKalle Valo u16 backup_radio[3];
170158619b14SKalle Valo u16 backup_bband;
170258619b14SKalle Valo u16 i, j, loop_i_max;
170358619b14SKalle Valo u16 trsw_rx;
170458619b14SKalle Valo u16 loop1_outer_done, loop1_inner_done;
170558619b14SKalle Valo
170658619b14SKalle Valo backup_phy[0] = b43_phy_read(dev, B43_PHY_CRS0);
170758619b14SKalle Valo backup_phy[1] = b43_phy_read(dev, B43_PHY_CCKBBANDCFG);
170858619b14SKalle Valo backup_phy[2] = b43_phy_read(dev, B43_PHY_RFOVER);
170958619b14SKalle Valo backup_phy[3] = b43_phy_read(dev, B43_PHY_RFOVERVAL);
171058619b14SKalle Valo if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */
171158619b14SKalle Valo backup_phy[4] = b43_phy_read(dev, B43_PHY_ANALOGOVER);
171258619b14SKalle Valo backup_phy[5] = b43_phy_read(dev, B43_PHY_ANALOGOVERVAL);
171358619b14SKalle Valo }
171458619b14SKalle Valo backup_phy[6] = b43_phy_read(dev, B43_PHY_CCK(0x5A));
171558619b14SKalle Valo backup_phy[7] = b43_phy_read(dev, B43_PHY_CCK(0x59));
171658619b14SKalle Valo backup_phy[8] = b43_phy_read(dev, B43_PHY_CCK(0x58));
171758619b14SKalle Valo backup_phy[9] = b43_phy_read(dev, B43_PHY_CCK(0x0A));
171858619b14SKalle Valo backup_phy[10] = b43_phy_read(dev, B43_PHY_CCK(0x03));
171958619b14SKalle Valo backup_phy[11] = b43_phy_read(dev, B43_PHY_LO_MASK);
172058619b14SKalle Valo backup_phy[12] = b43_phy_read(dev, B43_PHY_LO_CTL);
172158619b14SKalle Valo backup_phy[13] = b43_phy_read(dev, B43_PHY_CCK(0x2B));
172258619b14SKalle Valo backup_phy[14] = b43_phy_read(dev, B43_PHY_PGACTL);
172358619b14SKalle Valo backup_phy[15] = b43_phy_read(dev, B43_PHY_LO_LEAKAGE);
172458619b14SKalle Valo backup_bband = gphy->bbatt.att;
172558619b14SKalle Valo backup_radio[0] = b43_radio_read16(dev, 0x52);
172658619b14SKalle Valo backup_radio[1] = b43_radio_read16(dev, 0x43);
172758619b14SKalle Valo backup_radio[2] = b43_radio_read16(dev, 0x7A);
172858619b14SKalle Valo
172958619b14SKalle Valo b43_phy_mask(dev, B43_PHY_CRS0, 0x3FFF);
173058619b14SKalle Valo b43_phy_set(dev, B43_PHY_CCKBBANDCFG, 0x8000);
173158619b14SKalle Valo b43_phy_set(dev, B43_PHY_RFOVER, 0x0002);
173258619b14SKalle Valo b43_phy_mask(dev, B43_PHY_RFOVERVAL, 0xFFFD);
173358619b14SKalle Valo b43_phy_set(dev, B43_PHY_RFOVER, 0x0001);
173458619b14SKalle Valo b43_phy_mask(dev, B43_PHY_RFOVERVAL, 0xFFFE);
173558619b14SKalle Valo if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */
173658619b14SKalle Valo b43_phy_set(dev, B43_PHY_ANALOGOVER, 0x0001);
173758619b14SKalle Valo b43_phy_mask(dev, B43_PHY_ANALOGOVERVAL, 0xFFFE);
173858619b14SKalle Valo b43_phy_set(dev, B43_PHY_ANALOGOVER, 0x0002);
173958619b14SKalle Valo b43_phy_mask(dev, B43_PHY_ANALOGOVERVAL, 0xFFFD);
174058619b14SKalle Valo }
174158619b14SKalle Valo b43_phy_set(dev, B43_PHY_RFOVER, 0x000C);
174258619b14SKalle Valo b43_phy_set(dev, B43_PHY_RFOVERVAL, 0x000C);
174358619b14SKalle Valo b43_phy_set(dev, B43_PHY_RFOVER, 0x0030);
174458619b14SKalle Valo b43_phy_maskset(dev, B43_PHY_RFOVERVAL, 0xFFCF, 0x10);
174558619b14SKalle Valo
174658619b14SKalle Valo b43_phy_write(dev, B43_PHY_CCK(0x5A), 0x0780);
174758619b14SKalle Valo b43_phy_write(dev, B43_PHY_CCK(0x59), 0xC810);
174858619b14SKalle Valo b43_phy_write(dev, B43_PHY_CCK(0x58), 0x000D);
174958619b14SKalle Valo
175058619b14SKalle Valo b43_phy_set(dev, B43_PHY_CCK(0x0A), 0x2000);
175158619b14SKalle Valo if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */
175258619b14SKalle Valo b43_phy_set(dev, B43_PHY_ANALOGOVER, 0x0004);
175358619b14SKalle Valo b43_phy_mask(dev, B43_PHY_ANALOGOVERVAL, 0xFFFB);
175458619b14SKalle Valo }
175558619b14SKalle Valo b43_phy_maskset(dev, B43_PHY_CCK(0x03), 0xFF9F, 0x40);
175658619b14SKalle Valo
175758619b14SKalle Valo if (phy->radio_rev == 8) {
175858619b14SKalle Valo b43_radio_write16(dev, 0x43, 0x000F);
175958619b14SKalle Valo } else {
176058619b14SKalle Valo b43_radio_write16(dev, 0x52, 0);
176158619b14SKalle Valo b43_radio_maskset(dev, 0x43, 0xFFF0, 0x9);
176258619b14SKalle Valo }
176358619b14SKalle Valo b43_gphy_set_baseband_attenuation(dev, 11);
176458619b14SKalle Valo
176558619b14SKalle Valo if (phy->rev >= 3)
176658619b14SKalle Valo b43_phy_write(dev, B43_PHY_LO_MASK, 0xC020);
176758619b14SKalle Valo else
176858619b14SKalle Valo b43_phy_write(dev, B43_PHY_LO_MASK, 0x8020);
176958619b14SKalle Valo b43_phy_write(dev, B43_PHY_LO_CTL, 0);
177058619b14SKalle Valo
177158619b14SKalle Valo b43_phy_maskset(dev, B43_PHY_CCK(0x2B), 0xFFC0, 0x01);
177258619b14SKalle Valo b43_phy_maskset(dev, B43_PHY_CCK(0x2B), 0xC0FF, 0x800);
177358619b14SKalle Valo
177458619b14SKalle Valo b43_phy_set(dev, B43_PHY_RFOVER, 0x0100);
177558619b14SKalle Valo b43_phy_mask(dev, B43_PHY_RFOVERVAL, 0xCFFF);
177658619b14SKalle Valo
177758619b14SKalle Valo if (dev->dev->bus_sprom->boardflags_lo & B43_BFL_EXTLNA) {
177858619b14SKalle Valo if (phy->rev >= 7) {
177958619b14SKalle Valo b43_phy_set(dev, B43_PHY_RFOVER, 0x0800);
178058619b14SKalle Valo b43_phy_set(dev, B43_PHY_RFOVERVAL, 0x8000);
178158619b14SKalle Valo }
178258619b14SKalle Valo }
178358619b14SKalle Valo b43_radio_mask(dev, 0x7A, 0x00F7);
178458619b14SKalle Valo
178558619b14SKalle Valo j = 0;
178658619b14SKalle Valo loop_i_max = (phy->radio_rev == 8) ? 15 : 9;
178758619b14SKalle Valo for (i = 0; i < loop_i_max; i++) {
178858619b14SKalle Valo for (j = 0; j < 16; j++) {
178958619b14SKalle Valo b43_radio_write16(dev, 0x43, i);
179058619b14SKalle Valo b43_phy_maskset(dev, B43_PHY_RFOVERVAL, 0xF0FF, (j << 8));
179158619b14SKalle Valo b43_phy_maskset(dev, B43_PHY_PGACTL, 0x0FFF, 0xA000);
179258619b14SKalle Valo b43_phy_set(dev, B43_PHY_PGACTL, 0xF000);
179358619b14SKalle Valo udelay(20);
179458619b14SKalle Valo if (b43_phy_read(dev, B43_PHY_LO_LEAKAGE) >= 0xDFC)
179558619b14SKalle Valo goto exit_loop1;
179658619b14SKalle Valo }
179758619b14SKalle Valo }
179858619b14SKalle Valo exit_loop1:
179958619b14SKalle Valo loop1_outer_done = i;
180058619b14SKalle Valo loop1_inner_done = j;
180158619b14SKalle Valo if (j >= 8) {
180258619b14SKalle Valo b43_phy_set(dev, B43_PHY_RFOVERVAL, 0x30);
180358619b14SKalle Valo trsw_rx = 0x1B;
180458619b14SKalle Valo for (j = j - 8; j < 16; j++) {
180558619b14SKalle Valo b43_phy_maskset(dev, B43_PHY_RFOVERVAL, 0xF0FF, (j << 8));
180658619b14SKalle Valo b43_phy_maskset(dev, B43_PHY_PGACTL, 0x0FFF, 0xA000);
180758619b14SKalle Valo b43_phy_set(dev, B43_PHY_PGACTL, 0xF000);
180858619b14SKalle Valo udelay(20);
180958619b14SKalle Valo trsw_rx -= 3;
181058619b14SKalle Valo if (b43_phy_read(dev, B43_PHY_LO_LEAKAGE) >= 0xDFC)
181158619b14SKalle Valo goto exit_loop2;
181258619b14SKalle Valo }
181358619b14SKalle Valo } else
181458619b14SKalle Valo trsw_rx = 0x18;
181558619b14SKalle Valo exit_loop2:
181658619b14SKalle Valo
181758619b14SKalle Valo if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */
181858619b14SKalle Valo b43_phy_write(dev, B43_PHY_ANALOGOVER, backup_phy[4]);
181958619b14SKalle Valo b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, backup_phy[5]);
182058619b14SKalle Valo }
182158619b14SKalle Valo b43_phy_write(dev, B43_PHY_CCK(0x5A), backup_phy[6]);
182258619b14SKalle Valo b43_phy_write(dev, B43_PHY_CCK(0x59), backup_phy[7]);
182358619b14SKalle Valo b43_phy_write(dev, B43_PHY_CCK(0x58), backup_phy[8]);
182458619b14SKalle Valo b43_phy_write(dev, B43_PHY_CCK(0x0A), backup_phy[9]);
182558619b14SKalle Valo b43_phy_write(dev, B43_PHY_CCK(0x03), backup_phy[10]);
182658619b14SKalle Valo b43_phy_write(dev, B43_PHY_LO_MASK, backup_phy[11]);
182758619b14SKalle Valo b43_phy_write(dev, B43_PHY_LO_CTL, backup_phy[12]);
182858619b14SKalle Valo b43_phy_write(dev, B43_PHY_CCK(0x2B), backup_phy[13]);
182958619b14SKalle Valo b43_phy_write(dev, B43_PHY_PGACTL, backup_phy[14]);
183058619b14SKalle Valo
183158619b14SKalle Valo b43_gphy_set_baseband_attenuation(dev, backup_bband);
183258619b14SKalle Valo
183358619b14SKalle Valo b43_radio_write16(dev, 0x52, backup_radio[0]);
183458619b14SKalle Valo b43_radio_write16(dev, 0x43, backup_radio[1]);
183558619b14SKalle Valo b43_radio_write16(dev, 0x7A, backup_radio[2]);
183658619b14SKalle Valo
183758619b14SKalle Valo b43_phy_write(dev, B43_PHY_RFOVER, backup_phy[2] | 0x0003);
183858619b14SKalle Valo udelay(10);
183958619b14SKalle Valo b43_phy_write(dev, B43_PHY_RFOVER, backup_phy[2]);
184058619b14SKalle Valo b43_phy_write(dev, B43_PHY_RFOVERVAL, backup_phy[3]);
184158619b14SKalle Valo b43_phy_write(dev, B43_PHY_CRS0, backup_phy[0]);
184258619b14SKalle Valo b43_phy_write(dev, B43_PHY_CCKBBANDCFG, backup_phy[1]);
184358619b14SKalle Valo
184458619b14SKalle Valo gphy->max_lb_gain =
184558619b14SKalle Valo ((loop1_inner_done * 6) - (loop1_outer_done * 4)) - 11;
184658619b14SKalle Valo gphy->trsw_rx_gain = trsw_rx * 2;
184758619b14SKalle Valo }
184858619b14SKalle Valo
b43_hardware_pctl_early_init(struct b43_wldev * dev)184958619b14SKalle Valo static void b43_hardware_pctl_early_init(struct b43_wldev *dev)
185058619b14SKalle Valo {
185158619b14SKalle Valo struct b43_phy *phy = &dev->phy;
185258619b14SKalle Valo
185358619b14SKalle Valo if (!b43_has_hardware_pctl(dev)) {
185458619b14SKalle Valo b43_phy_write(dev, 0x047A, 0xC111);
185558619b14SKalle Valo return;
185658619b14SKalle Valo }
185758619b14SKalle Valo
185858619b14SKalle Valo b43_phy_mask(dev, 0x0036, 0xFEFF);
185958619b14SKalle Valo b43_phy_write(dev, 0x002F, 0x0202);
186058619b14SKalle Valo b43_phy_set(dev, 0x047C, 0x0002);
186158619b14SKalle Valo b43_phy_set(dev, 0x047A, 0xF000);
186258619b14SKalle Valo if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) {
186358619b14SKalle Valo b43_phy_maskset(dev, 0x047A, 0xFF0F, 0x0010);
186458619b14SKalle Valo b43_phy_set(dev, 0x005D, 0x8000);
186558619b14SKalle Valo b43_phy_maskset(dev, 0x004E, 0xFFC0, 0x0010);
186658619b14SKalle Valo b43_phy_write(dev, 0x002E, 0xC07F);
186758619b14SKalle Valo b43_phy_set(dev, 0x0036, 0x0400);
186858619b14SKalle Valo } else {
186958619b14SKalle Valo b43_phy_set(dev, 0x0036, 0x0200);
187058619b14SKalle Valo b43_phy_set(dev, 0x0036, 0x0400);
187158619b14SKalle Valo b43_phy_mask(dev, 0x005D, 0x7FFF);
187258619b14SKalle Valo b43_phy_mask(dev, 0x004F, 0xFFFE);
187358619b14SKalle Valo b43_phy_maskset(dev, 0x004E, 0xFFC0, 0x0010);
187458619b14SKalle Valo b43_phy_write(dev, 0x002E, 0xC07F);
187558619b14SKalle Valo b43_phy_maskset(dev, 0x047A, 0xFF0F, 0x0010);
187658619b14SKalle Valo }
187758619b14SKalle Valo }
187858619b14SKalle Valo
187958619b14SKalle Valo /* Hardware power control for G-PHY */
b43_hardware_pctl_init_gphy(struct b43_wldev * dev)188058619b14SKalle Valo static void b43_hardware_pctl_init_gphy(struct b43_wldev *dev)
188158619b14SKalle Valo {
188258619b14SKalle Valo struct b43_phy *phy = &dev->phy;
188358619b14SKalle Valo struct b43_phy_g *gphy = phy->g;
188458619b14SKalle Valo
188558619b14SKalle Valo if (!b43_has_hardware_pctl(dev)) {
188658619b14SKalle Valo /* No hardware power control */
188758619b14SKalle Valo b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_HWPCTL);
188858619b14SKalle Valo return;
188958619b14SKalle Valo }
189058619b14SKalle Valo
189158619b14SKalle Valo b43_phy_maskset(dev, 0x0036, 0xFFC0, (gphy->tgt_idle_tssi - gphy->cur_idle_tssi));
189258619b14SKalle Valo b43_phy_maskset(dev, 0x0478, 0xFF00, (gphy->tgt_idle_tssi - gphy->cur_idle_tssi));
189358619b14SKalle Valo b43_gphy_tssi_power_lt_init(dev);
189458619b14SKalle Valo b43_gphy_gain_lt_init(dev);
189558619b14SKalle Valo b43_phy_mask(dev, 0x0060, 0xFFBF);
189658619b14SKalle Valo b43_phy_write(dev, 0x0014, 0x0000);
189758619b14SKalle Valo
189858619b14SKalle Valo B43_WARN_ON(phy->rev < 6);
189958619b14SKalle Valo b43_phy_set(dev, 0x0478, 0x0800);
190058619b14SKalle Valo b43_phy_mask(dev, 0x0478, 0xFEFF);
190158619b14SKalle Valo b43_phy_mask(dev, 0x0801, 0xFFBF);
190258619b14SKalle Valo
190358619b14SKalle Valo b43_gphy_dc_lt_init(dev, 1);
190458619b14SKalle Valo
190558619b14SKalle Valo /* Enable hardware pctl in firmware. */
190658619b14SKalle Valo b43_hf_write(dev, b43_hf_read(dev) | B43_HF_HWPCTL);
190758619b14SKalle Valo }
190858619b14SKalle Valo
190958619b14SKalle Valo /* Initialize B/G PHY power control */
b43_phy_init_pctl(struct b43_wldev * dev)191058619b14SKalle Valo static void b43_phy_init_pctl(struct b43_wldev *dev)
191158619b14SKalle Valo {
191258619b14SKalle Valo struct b43_phy *phy = &dev->phy;
191358619b14SKalle Valo struct b43_phy_g *gphy = phy->g;
191458619b14SKalle Valo struct b43_rfatt old_rfatt;
191558619b14SKalle Valo struct b43_bbatt old_bbatt;
191658619b14SKalle Valo u8 old_tx_control = 0;
191758619b14SKalle Valo
191858619b14SKalle Valo B43_WARN_ON(phy->type != B43_PHYTYPE_G);
191958619b14SKalle Valo
192058619b14SKalle Valo if ((dev->dev->board_vendor == SSB_BOARDVENDOR_BCM) &&
192158619b14SKalle Valo (dev->dev->board_type == SSB_BOARD_BU4306))
192258619b14SKalle Valo return;
192358619b14SKalle Valo
192458619b14SKalle Valo b43_phy_write(dev, 0x0028, 0x8018);
192558619b14SKalle Valo
192658619b14SKalle Valo /* This does something with the Analog... */
192758619b14SKalle Valo b43_write16(dev, B43_MMIO_PHY0, b43_read16(dev, B43_MMIO_PHY0)
192858619b14SKalle Valo & 0xFFDF);
192958619b14SKalle Valo
193058619b14SKalle Valo if (!phy->gmode)
193158619b14SKalle Valo return;
193258619b14SKalle Valo b43_hardware_pctl_early_init(dev);
193358619b14SKalle Valo if (gphy->cur_idle_tssi == 0) {
193458619b14SKalle Valo if (phy->radio_ver == 0x2050 && phy->analog == 0) {
193558619b14SKalle Valo b43_radio_maskset(dev, 0x0076, 0x00F7, 0x0084);
193658619b14SKalle Valo } else {
193758619b14SKalle Valo struct b43_rfatt rfatt;
193858619b14SKalle Valo struct b43_bbatt bbatt;
193958619b14SKalle Valo
194058619b14SKalle Valo memcpy(&old_rfatt, &gphy->rfatt, sizeof(old_rfatt));
194158619b14SKalle Valo memcpy(&old_bbatt, &gphy->bbatt, sizeof(old_bbatt));
194258619b14SKalle Valo old_tx_control = gphy->tx_control;
194358619b14SKalle Valo
194458619b14SKalle Valo bbatt.att = 11;
194558619b14SKalle Valo if (phy->radio_rev == 8) {
194658619b14SKalle Valo rfatt.att = 15;
194758619b14SKalle Valo rfatt.with_padmix = true;
194858619b14SKalle Valo } else {
194958619b14SKalle Valo rfatt.att = 9;
195058619b14SKalle Valo rfatt.with_padmix = false;
195158619b14SKalle Valo }
195258619b14SKalle Valo b43_set_txpower_g(dev, &bbatt, &rfatt, 0);
195358619b14SKalle Valo }
195458619b14SKalle Valo b43_dummy_transmission(dev, false, true);
195558619b14SKalle Valo gphy->cur_idle_tssi = b43_phy_read(dev, B43_PHY_ITSSI);
195658619b14SKalle Valo if (B43_DEBUG) {
195758619b14SKalle Valo /* Current-Idle-TSSI sanity check. */
195858619b14SKalle Valo if (abs(gphy->cur_idle_tssi - gphy->tgt_idle_tssi) >= 20) {
195958619b14SKalle Valo b43dbg(dev->wl,
196058619b14SKalle Valo "!WARNING! Idle-TSSI phy->cur_idle_tssi "
196158619b14SKalle Valo "measuring failed. (cur=%d, tgt=%d). Disabling TX power "
196258619b14SKalle Valo "adjustment.\n", gphy->cur_idle_tssi,
196358619b14SKalle Valo gphy->tgt_idle_tssi);
196458619b14SKalle Valo gphy->cur_idle_tssi = 0;
196558619b14SKalle Valo }
196658619b14SKalle Valo }
196758619b14SKalle Valo if (phy->radio_ver == 0x2050 && phy->analog == 0) {
196858619b14SKalle Valo b43_radio_mask(dev, 0x0076, 0xFF7B);
196958619b14SKalle Valo } else {
197058619b14SKalle Valo b43_set_txpower_g(dev, &old_bbatt,
197158619b14SKalle Valo &old_rfatt, old_tx_control);
197258619b14SKalle Valo }
197358619b14SKalle Valo }
197458619b14SKalle Valo b43_hardware_pctl_init_gphy(dev);
197558619b14SKalle Valo b43_shm_clear_tssi(dev);
197658619b14SKalle Valo }
197758619b14SKalle Valo
b43_phy_inita(struct b43_wldev * dev)19789791333aSGuenter Roeck static void b43_phy_inita(struct b43_wldev *dev)
19799791333aSGuenter Roeck {
19809791333aSGuenter Roeck struct b43_phy *phy = &dev->phy;
19819791333aSGuenter Roeck
19829791333aSGuenter Roeck might_sleep();
19839791333aSGuenter Roeck
19849791333aSGuenter Roeck if (phy->rev >= 6) {
19859791333aSGuenter Roeck if (b43_phy_read(dev, B43_PHY_ENCORE) & B43_PHY_ENCORE_EN)
19869791333aSGuenter Roeck b43_phy_set(dev, B43_PHY_ENCORE, 0x0010);
19879791333aSGuenter Roeck else
19889791333aSGuenter Roeck b43_phy_mask(dev, B43_PHY_ENCORE, ~0x1010);
19899791333aSGuenter Roeck }
19909791333aSGuenter Roeck
19919791333aSGuenter Roeck b43_wa_all(dev);
19929791333aSGuenter Roeck
19939791333aSGuenter Roeck if (dev->dev->bus_sprom->boardflags_lo & B43_BFL_PACTRL)
19949791333aSGuenter Roeck b43_phy_maskset(dev, B43_PHY_OFDM(0x6E), 0xE000, 0x3CF);
19959791333aSGuenter Roeck }
19969791333aSGuenter Roeck
b43_phy_initg(struct b43_wldev * dev)199758619b14SKalle Valo static void b43_phy_initg(struct b43_wldev *dev)
199858619b14SKalle Valo {
199958619b14SKalle Valo struct b43_phy *phy = &dev->phy;
200058619b14SKalle Valo struct b43_phy_g *gphy = phy->g;
200158619b14SKalle Valo u16 tmp;
200258619b14SKalle Valo
200358619b14SKalle Valo if (phy->rev == 1)
200458619b14SKalle Valo b43_phy_initb5(dev);
200558619b14SKalle Valo else
200658619b14SKalle Valo b43_phy_initb6(dev);
200758619b14SKalle Valo
200858619b14SKalle Valo if (phy->rev >= 2 || phy->gmode)
200958619b14SKalle Valo b43_phy_inita(dev);
201058619b14SKalle Valo
201158619b14SKalle Valo if (phy->rev >= 2) {
201258619b14SKalle Valo b43_phy_write(dev, B43_PHY_ANALOGOVER, 0);
201358619b14SKalle Valo b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, 0);
201458619b14SKalle Valo }
201558619b14SKalle Valo if (phy->rev == 2) {
201658619b14SKalle Valo b43_phy_write(dev, B43_PHY_RFOVER, 0);
201758619b14SKalle Valo b43_phy_write(dev, B43_PHY_PGACTL, 0xC0);
201858619b14SKalle Valo }
201958619b14SKalle Valo if (phy->rev > 5) {
202058619b14SKalle Valo b43_phy_write(dev, B43_PHY_RFOVER, 0x400);
202158619b14SKalle Valo b43_phy_write(dev, B43_PHY_PGACTL, 0xC0);
202258619b14SKalle Valo }
202358619b14SKalle Valo if (phy->gmode || phy->rev >= 2) {
202458619b14SKalle Valo tmp = b43_phy_read(dev, B43_PHY_VERSION_OFDM);
202558619b14SKalle Valo tmp &= B43_PHYVER_VERSION;
202658619b14SKalle Valo if (tmp == 3 || tmp == 5) {
202758619b14SKalle Valo b43_phy_write(dev, B43_PHY_OFDM(0xC2), 0x1816);
202858619b14SKalle Valo b43_phy_write(dev, B43_PHY_OFDM(0xC3), 0x8006);
202958619b14SKalle Valo }
203058619b14SKalle Valo if (tmp == 5) {
203158619b14SKalle Valo b43_phy_maskset(dev, B43_PHY_OFDM(0xCC), 0x00FF, 0x1F00);
203258619b14SKalle Valo }
203358619b14SKalle Valo }
203458619b14SKalle Valo if ((phy->rev <= 2 && phy->gmode) || phy->rev >= 2)
203558619b14SKalle Valo b43_phy_write(dev, B43_PHY_OFDM(0x7E), 0x78);
203658619b14SKalle Valo if (phy->radio_rev == 8) {
203758619b14SKalle Valo b43_phy_set(dev, B43_PHY_EXTG(0x01), 0x80);
203858619b14SKalle Valo b43_phy_set(dev, B43_PHY_OFDM(0x3E), 0x4);
203958619b14SKalle Valo }
204058619b14SKalle Valo if (has_loopback_gain(phy))
204158619b14SKalle Valo b43_calc_loopback_gain(dev);
204258619b14SKalle Valo
204358619b14SKalle Valo if (phy->radio_rev != 8) {
204458619b14SKalle Valo if (gphy->initval == 0xFFFF)
204558619b14SKalle Valo gphy->initval = b43_radio_init2050(dev);
204658619b14SKalle Valo else
204758619b14SKalle Valo b43_radio_write16(dev, 0x0078, gphy->initval);
204858619b14SKalle Valo }
204958619b14SKalle Valo b43_lo_g_init(dev);
205058619b14SKalle Valo if (has_tx_magnification(phy)) {
205158619b14SKalle Valo b43_radio_write16(dev, 0x52,
205258619b14SKalle Valo (b43_radio_read16(dev, 0x52) & 0xFF00)
205358619b14SKalle Valo | gphy->lo_control->tx_bias | gphy->
205458619b14SKalle Valo lo_control->tx_magn);
205558619b14SKalle Valo } else {
205658619b14SKalle Valo b43_radio_maskset(dev, 0x52, 0xFFF0, gphy->lo_control->tx_bias);
205758619b14SKalle Valo }
205858619b14SKalle Valo if (phy->rev >= 6) {
205958619b14SKalle Valo b43_phy_maskset(dev, B43_PHY_CCK(0x36), 0x0FFF, (gphy->lo_control->tx_bias << 12));
206058619b14SKalle Valo }
206158619b14SKalle Valo if (dev->dev->bus_sprom->boardflags_lo & B43_BFL_PACTRL)
206258619b14SKalle Valo b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8075);
206358619b14SKalle Valo else
206458619b14SKalle Valo b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x807F);
206558619b14SKalle Valo if (phy->rev < 2)
206658619b14SKalle Valo b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x101);
206758619b14SKalle Valo else
206858619b14SKalle Valo b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x202);
206958619b14SKalle Valo if (phy->gmode || phy->rev >= 2) {
207058619b14SKalle Valo b43_lo_g_adjust(dev);
207158619b14SKalle Valo b43_phy_write(dev, B43_PHY_LO_MASK, 0x8078);
207258619b14SKalle Valo }
207358619b14SKalle Valo
207458619b14SKalle Valo if (!(dev->dev->bus_sprom->boardflags_lo & B43_BFL_RSSI)) {
207558619b14SKalle Valo /* The specs state to update the NRSSI LT with
207658619b14SKalle Valo * the value 0x7FFFFFFF here. I think that is some weird
207758619b14SKalle Valo * compiler optimization in the original driver.
207858619b14SKalle Valo * Essentially, what we do here is resetting all NRSSI LT
207958619b14SKalle Valo * entries to -32 (see the clamp_val() in nrssi_hw_update())
208058619b14SKalle Valo */
208158619b14SKalle Valo b43_nrssi_hw_update(dev, 0xFFFF); //FIXME?
208258619b14SKalle Valo b43_calc_nrssi_threshold(dev);
208358619b14SKalle Valo } else if (phy->gmode || phy->rev >= 2) {
208458619b14SKalle Valo if (gphy->nrssi[0] == -1000) {
208558619b14SKalle Valo B43_WARN_ON(gphy->nrssi[1] != -1000);
208658619b14SKalle Valo b43_calc_nrssi_slope(dev);
208758619b14SKalle Valo } else
208858619b14SKalle Valo b43_calc_nrssi_threshold(dev);
208958619b14SKalle Valo }
209058619b14SKalle Valo if (phy->radio_rev == 8)
209158619b14SKalle Valo b43_phy_write(dev, B43_PHY_EXTG(0x05), 0x3230);
209258619b14SKalle Valo b43_phy_init_pctl(dev);
209358619b14SKalle Valo /* FIXME: The spec says in the following if, the 0 should be replaced
209458619b14SKalle Valo 'if OFDM may not be used in the current locale'
209558619b14SKalle Valo but OFDM is legal everywhere */
209658619b14SKalle Valo if ((dev->dev->chip_id == 0x4306
209758619b14SKalle Valo && dev->dev->chip_pkg == 2) || 0) {
209858619b14SKalle Valo b43_phy_mask(dev, B43_PHY_CRS0, 0xBFFF);
209958619b14SKalle Valo b43_phy_mask(dev, B43_PHY_OFDM(0xC3), 0x7FFF);
210058619b14SKalle Valo }
210158619b14SKalle Valo }
210258619b14SKalle Valo
b43_gphy_channel_switch(struct b43_wldev * dev,unsigned int channel,bool synthetic_pu_workaround)210358619b14SKalle Valo void b43_gphy_channel_switch(struct b43_wldev *dev,
210458619b14SKalle Valo unsigned int channel,
210558619b14SKalle Valo bool synthetic_pu_workaround)
210658619b14SKalle Valo {
210758619b14SKalle Valo if (synthetic_pu_workaround)
210858619b14SKalle Valo b43_synth_pu_workaround(dev, channel);
210958619b14SKalle Valo
211058619b14SKalle Valo b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(channel));
211158619b14SKalle Valo
211258619b14SKalle Valo if (channel == 14) {
211358619b14SKalle Valo if (dev->dev->bus_sprom->country_code ==
211458619b14SKalle Valo SSB_SPROM1CCODE_JAPAN)
211558619b14SKalle Valo b43_hf_write(dev,
211658619b14SKalle Valo b43_hf_read(dev) & ~B43_HF_ACPR);
211758619b14SKalle Valo else
211858619b14SKalle Valo b43_hf_write(dev,
211958619b14SKalle Valo b43_hf_read(dev) | B43_HF_ACPR);
212058619b14SKalle Valo b43_write16(dev, B43_MMIO_CHANNEL_EXT,
212158619b14SKalle Valo b43_read16(dev, B43_MMIO_CHANNEL_EXT)
212258619b14SKalle Valo | (1 << 11));
212358619b14SKalle Valo } else {
212458619b14SKalle Valo b43_write16(dev, B43_MMIO_CHANNEL_EXT,
212558619b14SKalle Valo b43_read16(dev, B43_MMIO_CHANNEL_EXT)
212658619b14SKalle Valo & 0xF7BF);
212758619b14SKalle Valo }
212858619b14SKalle Valo }
212958619b14SKalle Valo
default_baseband_attenuation(struct b43_wldev * dev,struct b43_bbatt * bb)213058619b14SKalle Valo static void default_baseband_attenuation(struct b43_wldev *dev,
213158619b14SKalle Valo struct b43_bbatt *bb)
213258619b14SKalle Valo {
213358619b14SKalle Valo struct b43_phy *phy = &dev->phy;
213458619b14SKalle Valo
213558619b14SKalle Valo if (phy->radio_ver == 0x2050 && phy->radio_rev < 6)
213658619b14SKalle Valo bb->att = 0;
213758619b14SKalle Valo else
213858619b14SKalle Valo bb->att = 2;
213958619b14SKalle Valo }
214058619b14SKalle Valo
default_radio_attenuation(struct b43_wldev * dev,struct b43_rfatt * rf)214158619b14SKalle Valo static void default_radio_attenuation(struct b43_wldev *dev,
214258619b14SKalle Valo struct b43_rfatt *rf)
214358619b14SKalle Valo {
214458619b14SKalle Valo struct b43_bus_dev *bdev = dev->dev;
214558619b14SKalle Valo struct b43_phy *phy = &dev->phy;
214658619b14SKalle Valo
214758619b14SKalle Valo rf->with_padmix = false;
214858619b14SKalle Valo
214958619b14SKalle Valo if (dev->dev->board_vendor == SSB_BOARDVENDOR_BCM &&
215058619b14SKalle Valo dev->dev->board_type == SSB_BOARD_BCM4309G) {
215158619b14SKalle Valo if (dev->dev->board_rev < 0x43) {
215258619b14SKalle Valo rf->att = 2;
215358619b14SKalle Valo return;
215458619b14SKalle Valo } else if (dev->dev->board_rev < 0x51) {
215558619b14SKalle Valo rf->att = 3;
215658619b14SKalle Valo return;
215758619b14SKalle Valo }
215858619b14SKalle Valo }
215958619b14SKalle Valo
216058619b14SKalle Valo switch (phy->radio_ver) {
216158619b14SKalle Valo case 0x2053:
216258619b14SKalle Valo switch (phy->radio_rev) {
216358619b14SKalle Valo case 1:
216458619b14SKalle Valo rf->att = 6;
216558619b14SKalle Valo return;
216658619b14SKalle Valo }
216758619b14SKalle Valo break;
216858619b14SKalle Valo case 0x2050:
216958619b14SKalle Valo switch (phy->radio_rev) {
217058619b14SKalle Valo case 0:
217158619b14SKalle Valo rf->att = 5;
217258619b14SKalle Valo return;
217358619b14SKalle Valo case 1:
217458619b14SKalle Valo if (phy->type == B43_PHYTYPE_G) {
217558619b14SKalle Valo if (bdev->board_vendor == SSB_BOARDVENDOR_BCM
217658619b14SKalle Valo && bdev->board_type == SSB_BOARD_BCM4309G
217758619b14SKalle Valo && bdev->board_rev >= 30)
217858619b14SKalle Valo rf->att = 3;
217958619b14SKalle Valo else if (bdev->board_vendor ==
218058619b14SKalle Valo SSB_BOARDVENDOR_BCM
218158619b14SKalle Valo && bdev->board_type ==
218258619b14SKalle Valo SSB_BOARD_BU4306)
218358619b14SKalle Valo rf->att = 3;
218458619b14SKalle Valo else
218558619b14SKalle Valo rf->att = 1;
218658619b14SKalle Valo } else {
218758619b14SKalle Valo if (bdev->board_vendor == SSB_BOARDVENDOR_BCM
218858619b14SKalle Valo && bdev->board_type == SSB_BOARD_BCM4309G
218958619b14SKalle Valo && bdev->board_rev >= 30)
219058619b14SKalle Valo rf->att = 7;
219158619b14SKalle Valo else
219258619b14SKalle Valo rf->att = 6;
219358619b14SKalle Valo }
219458619b14SKalle Valo return;
219558619b14SKalle Valo case 2:
219658619b14SKalle Valo if (phy->type == B43_PHYTYPE_G) {
219758619b14SKalle Valo if (bdev->board_vendor == SSB_BOARDVENDOR_BCM
219858619b14SKalle Valo && bdev->board_type == SSB_BOARD_BCM4309G
219958619b14SKalle Valo && bdev->board_rev >= 30)
220058619b14SKalle Valo rf->att = 3;
220158619b14SKalle Valo else if (bdev->board_vendor ==
220258619b14SKalle Valo SSB_BOARDVENDOR_BCM
220358619b14SKalle Valo && bdev->board_type ==
220458619b14SKalle Valo SSB_BOARD_BU4306)
220558619b14SKalle Valo rf->att = 5;
220658619b14SKalle Valo else if (bdev->chip_id == 0x4320)
220758619b14SKalle Valo rf->att = 4;
220858619b14SKalle Valo else
220958619b14SKalle Valo rf->att = 3;
221058619b14SKalle Valo } else
221158619b14SKalle Valo rf->att = 6;
221258619b14SKalle Valo return;
221358619b14SKalle Valo case 3:
221458619b14SKalle Valo rf->att = 5;
221558619b14SKalle Valo return;
221658619b14SKalle Valo case 4:
221758619b14SKalle Valo case 5:
221858619b14SKalle Valo rf->att = 1;
221958619b14SKalle Valo return;
222058619b14SKalle Valo case 6:
222158619b14SKalle Valo case 7:
222258619b14SKalle Valo rf->att = 5;
222358619b14SKalle Valo return;
222458619b14SKalle Valo case 8:
222558619b14SKalle Valo rf->att = 0xA;
222658619b14SKalle Valo rf->with_padmix = true;
222758619b14SKalle Valo return;
222858619b14SKalle Valo case 9:
222958619b14SKalle Valo default:
223058619b14SKalle Valo rf->att = 5;
223158619b14SKalle Valo return;
223258619b14SKalle Valo }
223358619b14SKalle Valo }
223458619b14SKalle Valo rf->att = 5;
223558619b14SKalle Valo }
223658619b14SKalle Valo
default_tx_control(struct b43_wldev * dev)223758619b14SKalle Valo static u16 default_tx_control(struct b43_wldev *dev)
223858619b14SKalle Valo {
223958619b14SKalle Valo struct b43_phy *phy = &dev->phy;
224058619b14SKalle Valo
224158619b14SKalle Valo if (phy->radio_ver != 0x2050)
224258619b14SKalle Valo return 0;
224358619b14SKalle Valo if (phy->radio_rev == 1)
224458619b14SKalle Valo return B43_TXCTL_PA2DB | B43_TXCTL_TXMIX;
224558619b14SKalle Valo if (phy->radio_rev < 6)
224658619b14SKalle Valo return B43_TXCTL_PA2DB;
224758619b14SKalle Valo if (phy->radio_rev == 8)
224858619b14SKalle Valo return B43_TXCTL_TXMIX;
224958619b14SKalle Valo return 0;
225058619b14SKalle Valo }
225158619b14SKalle Valo
b43_gphy_aci_detect(struct b43_wldev * dev,u8 channel)225258619b14SKalle Valo static u8 b43_gphy_aci_detect(struct b43_wldev *dev, u8 channel)
225358619b14SKalle Valo {
225458619b14SKalle Valo struct b43_phy *phy = &dev->phy;
225558619b14SKalle Valo struct b43_phy_g *gphy = phy->g;
225658619b14SKalle Valo u8 ret = 0;
225758619b14SKalle Valo u16 saved, rssi, temp;
225858619b14SKalle Valo int i, j = 0;
225958619b14SKalle Valo
226058619b14SKalle Valo saved = b43_phy_read(dev, 0x0403);
226158619b14SKalle Valo b43_switch_channel(dev, channel);
226258619b14SKalle Valo b43_phy_write(dev, 0x0403, (saved & 0xFFF8) | 5);
226358619b14SKalle Valo if (gphy->aci_hw_rssi)
226458619b14SKalle Valo rssi = b43_phy_read(dev, 0x048A) & 0x3F;
226558619b14SKalle Valo else
226658619b14SKalle Valo rssi = saved & 0x3F;
226758619b14SKalle Valo /* clamp temp to signed 5bit */
226858619b14SKalle Valo if (rssi > 32)
226958619b14SKalle Valo rssi -= 64;
227058619b14SKalle Valo for (i = 0; i < 100; i++) {
227158619b14SKalle Valo temp = (b43_phy_read(dev, 0x047F) >> 8) & 0x3F;
227258619b14SKalle Valo if (temp > 32)
227358619b14SKalle Valo temp -= 64;
227458619b14SKalle Valo if (temp < rssi)
227558619b14SKalle Valo j++;
227658619b14SKalle Valo if (j >= 20)
227758619b14SKalle Valo ret = 1;
227858619b14SKalle Valo }
227958619b14SKalle Valo b43_phy_write(dev, 0x0403, saved);
228058619b14SKalle Valo
228158619b14SKalle Valo return ret;
228258619b14SKalle Valo }
228358619b14SKalle Valo
b43_gphy_aci_scan(struct b43_wldev * dev)228458619b14SKalle Valo static u8 b43_gphy_aci_scan(struct b43_wldev *dev)
228558619b14SKalle Valo {
228658619b14SKalle Valo struct b43_phy *phy = &dev->phy;
2287e31fbe10SColin Ian King u8 ret[13] = { 0 };
228858619b14SKalle Valo unsigned int channel = phy->channel;
228958619b14SKalle Valo unsigned int i, j, start, end;
229058619b14SKalle Valo
229158619b14SKalle Valo if (!((phy->type == B43_PHYTYPE_G) && (phy->rev > 0)))
229258619b14SKalle Valo return 0;
229358619b14SKalle Valo
229458619b14SKalle Valo b43_phy_lock(dev);
229558619b14SKalle Valo b43_radio_lock(dev);
229658619b14SKalle Valo b43_phy_mask(dev, 0x0802, 0xFFFC);
229758619b14SKalle Valo b43_phy_mask(dev, B43_PHY_G_CRS, 0x7FFF);
229858619b14SKalle Valo b43_set_all_gains(dev, 3, 8, 1);
229958619b14SKalle Valo
2300*9b793db5SDan Carpenter start = (channel > 5) ? channel - 5 : 1;
230158619b14SKalle Valo end = (channel + 5 < 14) ? channel + 5 : 13;
230258619b14SKalle Valo
230358619b14SKalle Valo for (i = start; i <= end; i++) {
230458619b14SKalle Valo if (abs(channel - i) > 2)
230558619b14SKalle Valo ret[i - 1] = b43_gphy_aci_detect(dev, i);
230658619b14SKalle Valo }
230758619b14SKalle Valo b43_switch_channel(dev, channel);
230858619b14SKalle Valo b43_phy_maskset(dev, 0x0802, 0xFFFC, 0x0003);
230958619b14SKalle Valo b43_phy_mask(dev, 0x0403, 0xFFF8);
231058619b14SKalle Valo b43_phy_set(dev, B43_PHY_G_CRS, 0x8000);
231158619b14SKalle Valo b43_set_original_gains(dev);
231258619b14SKalle Valo for (i = 0; i < 13; i++) {
231358619b14SKalle Valo if (!ret[i])
231458619b14SKalle Valo continue;
231558619b14SKalle Valo end = (i + 5 < 13) ? i + 5 : 13;
231658619b14SKalle Valo for (j = i; j < end; j++)
231758619b14SKalle Valo ret[j] = 1;
231858619b14SKalle Valo }
231958619b14SKalle Valo b43_radio_unlock(dev);
232058619b14SKalle Valo b43_phy_unlock(dev);
232158619b14SKalle Valo
232258619b14SKalle Valo return ret[channel - 1];
232358619b14SKalle Valo }
232458619b14SKalle Valo
b43_tssi2dbm_ad(s32 num,s32 den)232558619b14SKalle Valo static s32 b43_tssi2dbm_ad(s32 num, s32 den)
232658619b14SKalle Valo {
232758619b14SKalle Valo if (num < 0)
232858619b14SKalle Valo return num / den;
232958619b14SKalle Valo else
233058619b14SKalle Valo return (num + den / 2) / den;
233158619b14SKalle Valo }
233258619b14SKalle Valo
b43_tssi2dbm_entry(s8 entry[],u8 index,s16 pab0,s16 pab1,s16 pab2)233358619b14SKalle Valo static s8 b43_tssi2dbm_entry(s8 entry[], u8 index,
233458619b14SKalle Valo s16 pab0, s16 pab1, s16 pab2)
233558619b14SKalle Valo {
233658619b14SKalle Valo s32 m1, m2, f = 256, q, delta;
233758619b14SKalle Valo s8 i = 0;
233858619b14SKalle Valo
233958619b14SKalle Valo m1 = b43_tssi2dbm_ad(16 * pab0 + index * pab1, 32);
234058619b14SKalle Valo m2 = max(b43_tssi2dbm_ad(32768 + index * pab2, 256), 1);
234158619b14SKalle Valo do {
234258619b14SKalle Valo if (i > 15)
234358619b14SKalle Valo return -EINVAL;
234458619b14SKalle Valo q = b43_tssi2dbm_ad(f * 4096 -
234558619b14SKalle Valo b43_tssi2dbm_ad(m2 * f, 16) * f, 2048);
234658619b14SKalle Valo delta = abs(q - f);
234758619b14SKalle Valo f = q;
234858619b14SKalle Valo i++;
234958619b14SKalle Valo } while (delta >= 2);
235058619b14SKalle Valo entry[index] = clamp_val(b43_tssi2dbm_ad(m1 * f, 8192), -127, 128);
235158619b14SKalle Valo return 0;
235258619b14SKalle Valo }
235358619b14SKalle Valo
b43_generate_dyn_tssi2dbm_tab(struct b43_wldev * dev,s16 pab0,s16 pab1,s16 pab2)235458619b14SKalle Valo u8 *b43_generate_dyn_tssi2dbm_tab(struct b43_wldev *dev,
235558619b14SKalle Valo s16 pab0, s16 pab1, s16 pab2)
235658619b14SKalle Valo {
235758619b14SKalle Valo unsigned int i;
235858619b14SKalle Valo u8 *tab;
235958619b14SKalle Valo int err;
236058619b14SKalle Valo
236158619b14SKalle Valo tab = kmalloc(64, GFP_KERNEL);
236258619b14SKalle Valo if (!tab) {
236358619b14SKalle Valo b43err(dev->wl, "Could not allocate memory "
236458619b14SKalle Valo "for tssi2dbm table\n");
236558619b14SKalle Valo return NULL;
236658619b14SKalle Valo }
236758619b14SKalle Valo for (i = 0; i < 64; i++) {
236858619b14SKalle Valo err = b43_tssi2dbm_entry(tab, i, pab0, pab1, pab2);
236958619b14SKalle Valo if (err) {
237058619b14SKalle Valo b43err(dev->wl, "Could not generate "
237158619b14SKalle Valo "tssi2dBm table\n");
237258619b14SKalle Valo kfree(tab);
237358619b14SKalle Valo return NULL;
237458619b14SKalle Valo }
237558619b14SKalle Valo }
237658619b14SKalle Valo
237758619b14SKalle Valo return tab;
237858619b14SKalle Valo }
237958619b14SKalle Valo
238058619b14SKalle Valo /* Initialise the TSSI->dBm lookup table */
b43_gphy_init_tssi2dbm_table(struct b43_wldev * dev)238158619b14SKalle Valo static int b43_gphy_init_tssi2dbm_table(struct b43_wldev *dev)
238258619b14SKalle Valo {
238358619b14SKalle Valo struct b43_phy *phy = &dev->phy;
238458619b14SKalle Valo struct b43_phy_g *gphy = phy->g;
238558619b14SKalle Valo s16 pab0, pab1, pab2;
238658619b14SKalle Valo
238758619b14SKalle Valo pab0 = (s16) (dev->dev->bus_sprom->pa0b0);
238858619b14SKalle Valo pab1 = (s16) (dev->dev->bus_sprom->pa0b1);
238958619b14SKalle Valo pab2 = (s16) (dev->dev->bus_sprom->pa0b2);
239058619b14SKalle Valo
239158619b14SKalle Valo B43_WARN_ON((dev->dev->chip_id == 0x4301) &&
239258619b14SKalle Valo (phy->radio_ver != 0x2050)); /* Not supported anymore */
239358619b14SKalle Valo
239458619b14SKalle Valo gphy->dyn_tssi_tbl = false;
239558619b14SKalle Valo
239658619b14SKalle Valo if (pab0 != 0 && pab1 != 0 && pab2 != 0 &&
239758619b14SKalle Valo pab0 != -1 && pab1 != -1 && pab2 != -1) {
239858619b14SKalle Valo /* The pabX values are set in SPROM. Use them. */
239958619b14SKalle Valo if ((s8) dev->dev->bus_sprom->itssi_bg != 0 &&
240058619b14SKalle Valo (s8) dev->dev->bus_sprom->itssi_bg != -1) {
240158619b14SKalle Valo gphy->tgt_idle_tssi =
240258619b14SKalle Valo (s8) (dev->dev->bus_sprom->itssi_bg);
240358619b14SKalle Valo } else
240458619b14SKalle Valo gphy->tgt_idle_tssi = 62;
240558619b14SKalle Valo gphy->tssi2dbm = b43_generate_dyn_tssi2dbm_tab(dev, pab0,
240658619b14SKalle Valo pab1, pab2);
240758619b14SKalle Valo if (!gphy->tssi2dbm)
240858619b14SKalle Valo return -ENOMEM;
240958619b14SKalle Valo gphy->dyn_tssi_tbl = true;
241058619b14SKalle Valo } else {
241158619b14SKalle Valo /* pabX values not set in SPROM. */
241258619b14SKalle Valo gphy->tgt_idle_tssi = 52;
241358619b14SKalle Valo gphy->tssi2dbm = b43_tssi2dbm_g_table;
241458619b14SKalle Valo }
241558619b14SKalle Valo
241658619b14SKalle Valo return 0;
241758619b14SKalle Valo }
241858619b14SKalle Valo
b43_gphy_op_allocate(struct b43_wldev * dev)241958619b14SKalle Valo static int b43_gphy_op_allocate(struct b43_wldev *dev)
242058619b14SKalle Valo {
242158619b14SKalle Valo struct b43_phy_g *gphy;
242258619b14SKalle Valo struct b43_txpower_lo_control *lo;
242358619b14SKalle Valo int err;
242458619b14SKalle Valo
242558619b14SKalle Valo gphy = kzalloc(sizeof(*gphy), GFP_KERNEL);
242658619b14SKalle Valo if (!gphy) {
242758619b14SKalle Valo err = -ENOMEM;
242858619b14SKalle Valo goto error;
242958619b14SKalle Valo }
243058619b14SKalle Valo dev->phy.g = gphy;
243158619b14SKalle Valo
243258619b14SKalle Valo lo = kzalloc(sizeof(*lo), GFP_KERNEL);
243358619b14SKalle Valo if (!lo) {
243458619b14SKalle Valo err = -ENOMEM;
243558619b14SKalle Valo goto err_free_gphy;
243658619b14SKalle Valo }
243758619b14SKalle Valo gphy->lo_control = lo;
243858619b14SKalle Valo
243958619b14SKalle Valo err = b43_gphy_init_tssi2dbm_table(dev);
244058619b14SKalle Valo if (err)
244158619b14SKalle Valo goto err_free_lo;
244258619b14SKalle Valo
244358619b14SKalle Valo return 0;
244458619b14SKalle Valo
244558619b14SKalle Valo err_free_lo:
244658619b14SKalle Valo kfree(lo);
244758619b14SKalle Valo err_free_gphy:
244858619b14SKalle Valo kfree(gphy);
244958619b14SKalle Valo error:
245058619b14SKalle Valo return err;
245158619b14SKalle Valo }
245258619b14SKalle Valo
b43_gphy_op_prepare_structs(struct b43_wldev * dev)245358619b14SKalle Valo static void b43_gphy_op_prepare_structs(struct b43_wldev *dev)
245458619b14SKalle Valo {
245558619b14SKalle Valo struct b43_phy *phy = &dev->phy;
245658619b14SKalle Valo struct b43_phy_g *gphy = phy->g;
245758619b14SKalle Valo const void *tssi2dbm;
245858619b14SKalle Valo int tgt_idle_tssi;
245958619b14SKalle Valo struct b43_txpower_lo_control *lo;
246058619b14SKalle Valo unsigned int i;
246158619b14SKalle Valo
246258619b14SKalle Valo /* tssi2dbm table is constant, so it is initialized at alloc time.
246358619b14SKalle Valo * Save a copy of the pointer. */
246458619b14SKalle Valo tssi2dbm = gphy->tssi2dbm;
246558619b14SKalle Valo tgt_idle_tssi = gphy->tgt_idle_tssi;
246658619b14SKalle Valo /* Save the LO pointer. */
246758619b14SKalle Valo lo = gphy->lo_control;
246858619b14SKalle Valo
246958619b14SKalle Valo /* Zero out the whole PHY structure. */
247058619b14SKalle Valo memset(gphy, 0, sizeof(*gphy));
247158619b14SKalle Valo
247258619b14SKalle Valo /* Restore pointers. */
247358619b14SKalle Valo gphy->tssi2dbm = tssi2dbm;
247458619b14SKalle Valo gphy->tgt_idle_tssi = tgt_idle_tssi;
247558619b14SKalle Valo gphy->lo_control = lo;
247658619b14SKalle Valo
247758619b14SKalle Valo memset(gphy->minlowsig, 0xFF, sizeof(gphy->minlowsig));
247858619b14SKalle Valo
247958619b14SKalle Valo /* NRSSI */
248058619b14SKalle Valo for (i = 0; i < ARRAY_SIZE(gphy->nrssi); i++)
248158619b14SKalle Valo gphy->nrssi[i] = -1000;
248258619b14SKalle Valo for (i = 0; i < ARRAY_SIZE(gphy->nrssi_lt); i++)
248358619b14SKalle Valo gphy->nrssi_lt[i] = i;
248458619b14SKalle Valo
248558619b14SKalle Valo gphy->lofcal = 0xFFFF;
248658619b14SKalle Valo gphy->initval = 0xFFFF;
248758619b14SKalle Valo
248858619b14SKalle Valo gphy->interfmode = B43_INTERFMODE_NONE;
248958619b14SKalle Valo
249058619b14SKalle Valo /* OFDM-table address caching. */
249158619b14SKalle Valo gphy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_UNKNOWN;
249258619b14SKalle Valo
249358619b14SKalle Valo gphy->average_tssi = 0xFF;
249458619b14SKalle Valo
249558619b14SKalle Valo /* Local Osciallator structure */
249658619b14SKalle Valo lo->tx_bias = 0xFF;
249758619b14SKalle Valo INIT_LIST_HEAD(&lo->calib_list);
249858619b14SKalle Valo }
249958619b14SKalle Valo
b43_gphy_op_free(struct b43_wldev * dev)250058619b14SKalle Valo static void b43_gphy_op_free(struct b43_wldev *dev)
250158619b14SKalle Valo {
250258619b14SKalle Valo struct b43_phy *phy = &dev->phy;
250358619b14SKalle Valo struct b43_phy_g *gphy = phy->g;
250458619b14SKalle Valo
250558619b14SKalle Valo kfree(gphy->lo_control);
250658619b14SKalle Valo
250758619b14SKalle Valo if (gphy->dyn_tssi_tbl)
250858619b14SKalle Valo kfree(gphy->tssi2dbm);
250958619b14SKalle Valo gphy->dyn_tssi_tbl = false;
251058619b14SKalle Valo gphy->tssi2dbm = NULL;
251158619b14SKalle Valo
251258619b14SKalle Valo kfree(gphy);
251358619b14SKalle Valo dev->phy.g = NULL;
251458619b14SKalle Valo }
251558619b14SKalle Valo
b43_gphy_op_prepare_hardware(struct b43_wldev * dev)251658619b14SKalle Valo static int b43_gphy_op_prepare_hardware(struct b43_wldev *dev)
251758619b14SKalle Valo {
251858619b14SKalle Valo struct b43_phy *phy = &dev->phy;
251958619b14SKalle Valo struct b43_phy_g *gphy = phy->g;
252058619b14SKalle Valo struct b43_txpower_lo_control *lo = gphy->lo_control;
252158619b14SKalle Valo
252258619b14SKalle Valo B43_WARN_ON(phy->type != B43_PHYTYPE_G);
252358619b14SKalle Valo
252458619b14SKalle Valo default_baseband_attenuation(dev, &gphy->bbatt);
252558619b14SKalle Valo default_radio_attenuation(dev, &gphy->rfatt);
252658619b14SKalle Valo gphy->tx_control = (default_tx_control(dev) << 4);
252758619b14SKalle Valo generate_rfatt_list(dev, &lo->rfatt_list);
252858619b14SKalle Valo generate_bbatt_list(dev, &lo->bbatt_list);
252958619b14SKalle Valo
253058619b14SKalle Valo /* Commit previous writes */
253158619b14SKalle Valo b43_read32(dev, B43_MMIO_MACCTL);
253258619b14SKalle Valo
253358619b14SKalle Valo if (phy->rev == 1) {
253458619b14SKalle Valo /* Workaround: Temporarly disable gmode through the early init
253558619b14SKalle Valo * phase, as the gmode stuff is not needed for phy rev 1 */
253658619b14SKalle Valo phy->gmode = false;
253758619b14SKalle Valo b43_wireless_core_reset(dev, 0);
253858619b14SKalle Valo b43_phy_initg(dev);
253958619b14SKalle Valo phy->gmode = true;
254058619b14SKalle Valo b43_wireless_core_reset(dev, 1);
254158619b14SKalle Valo }
254258619b14SKalle Valo
254358619b14SKalle Valo return 0;
254458619b14SKalle Valo }
254558619b14SKalle Valo
b43_gphy_op_init(struct b43_wldev * dev)254658619b14SKalle Valo static int b43_gphy_op_init(struct b43_wldev *dev)
254758619b14SKalle Valo {
254858619b14SKalle Valo b43_phy_initg(dev);
254958619b14SKalle Valo
255058619b14SKalle Valo return 0;
255158619b14SKalle Valo }
255258619b14SKalle Valo
b43_gphy_op_exit(struct b43_wldev * dev)255358619b14SKalle Valo static void b43_gphy_op_exit(struct b43_wldev *dev)
255458619b14SKalle Valo {
255558619b14SKalle Valo b43_lo_g_cleanup(dev);
255658619b14SKalle Valo }
255758619b14SKalle Valo
b43_gphy_op_read(struct b43_wldev * dev,u16 reg)255858619b14SKalle Valo static u16 b43_gphy_op_read(struct b43_wldev *dev, u16 reg)
255958619b14SKalle Valo {
256058619b14SKalle Valo b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
256158619b14SKalle Valo return b43_read16(dev, B43_MMIO_PHY_DATA);
256258619b14SKalle Valo }
256358619b14SKalle Valo
b43_gphy_op_write(struct b43_wldev * dev,u16 reg,u16 value)256458619b14SKalle Valo static void b43_gphy_op_write(struct b43_wldev *dev, u16 reg, u16 value)
256558619b14SKalle Valo {
256658619b14SKalle Valo b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
256758619b14SKalle Valo b43_write16(dev, B43_MMIO_PHY_DATA, value);
256858619b14SKalle Valo }
256958619b14SKalle Valo
b43_gphy_op_radio_read(struct b43_wldev * dev,u16 reg)257058619b14SKalle Valo static u16 b43_gphy_op_radio_read(struct b43_wldev *dev, u16 reg)
257158619b14SKalle Valo {
257258619b14SKalle Valo /* Register 1 is a 32-bit register. */
257358619b14SKalle Valo B43_WARN_ON(reg == 1);
257458619b14SKalle Valo /* G-PHY needs 0x80 for read access. */
257558619b14SKalle Valo reg |= 0x80;
257658619b14SKalle Valo
257758619b14SKalle Valo b43_write16f(dev, B43_MMIO_RADIO_CONTROL, reg);
257858619b14SKalle Valo return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
257958619b14SKalle Valo }
258058619b14SKalle Valo
b43_gphy_op_radio_write(struct b43_wldev * dev,u16 reg,u16 value)258158619b14SKalle Valo static void b43_gphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
258258619b14SKalle Valo {
258358619b14SKalle Valo /* Register 1 is a 32-bit register. */
258458619b14SKalle Valo B43_WARN_ON(reg == 1);
258558619b14SKalle Valo
258658619b14SKalle Valo b43_write16f(dev, B43_MMIO_RADIO_CONTROL, reg);
258758619b14SKalle Valo b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value);
258858619b14SKalle Valo }
258958619b14SKalle Valo
b43_gphy_op_supports_hwpctl(struct b43_wldev * dev)259058619b14SKalle Valo static bool b43_gphy_op_supports_hwpctl(struct b43_wldev *dev)
259158619b14SKalle Valo {
259258619b14SKalle Valo return (dev->phy.rev >= 6);
259358619b14SKalle Valo }
259458619b14SKalle Valo
b43_gphy_op_software_rfkill(struct b43_wldev * dev,bool blocked)259558619b14SKalle Valo static void b43_gphy_op_software_rfkill(struct b43_wldev *dev,
259658619b14SKalle Valo bool blocked)
259758619b14SKalle Valo {
259858619b14SKalle Valo struct b43_phy *phy = &dev->phy;
259958619b14SKalle Valo struct b43_phy_g *gphy = phy->g;
260058619b14SKalle Valo unsigned int channel;
260158619b14SKalle Valo
260258619b14SKalle Valo might_sleep();
260358619b14SKalle Valo
260458619b14SKalle Valo if (!blocked) {
260558619b14SKalle Valo /* Turn radio ON */
260658619b14SKalle Valo if (phy->radio_on)
260758619b14SKalle Valo return;
260858619b14SKalle Valo
260958619b14SKalle Valo b43_phy_write(dev, 0x0015, 0x8000);
261058619b14SKalle Valo b43_phy_write(dev, 0x0015, 0xCC00);
261158619b14SKalle Valo b43_phy_write(dev, 0x0015, (phy->gmode ? 0x00C0 : 0x0000));
261258619b14SKalle Valo if (gphy->radio_off_context.valid) {
261358619b14SKalle Valo /* Restore the RFover values. */
261458619b14SKalle Valo b43_phy_write(dev, B43_PHY_RFOVER,
261558619b14SKalle Valo gphy->radio_off_context.rfover);
261658619b14SKalle Valo b43_phy_write(dev, B43_PHY_RFOVERVAL,
261758619b14SKalle Valo gphy->radio_off_context.rfoverval);
261858619b14SKalle Valo gphy->radio_off_context.valid = false;
261958619b14SKalle Valo }
262058619b14SKalle Valo channel = phy->channel;
262158619b14SKalle Valo b43_gphy_channel_switch(dev, 6, 1);
262258619b14SKalle Valo b43_gphy_channel_switch(dev, channel, 0);
262358619b14SKalle Valo } else {
262458619b14SKalle Valo /* Turn radio OFF */
262558619b14SKalle Valo u16 rfover, rfoverval;
262658619b14SKalle Valo
262758619b14SKalle Valo rfover = b43_phy_read(dev, B43_PHY_RFOVER);
262858619b14SKalle Valo rfoverval = b43_phy_read(dev, B43_PHY_RFOVERVAL);
262958619b14SKalle Valo gphy->radio_off_context.rfover = rfover;
263058619b14SKalle Valo gphy->radio_off_context.rfoverval = rfoverval;
263158619b14SKalle Valo gphy->radio_off_context.valid = true;
263258619b14SKalle Valo b43_phy_write(dev, B43_PHY_RFOVER, rfover | 0x008C);
263358619b14SKalle Valo b43_phy_write(dev, B43_PHY_RFOVERVAL, rfoverval & 0xFF73);
263458619b14SKalle Valo }
263558619b14SKalle Valo }
263658619b14SKalle Valo
b43_gphy_op_switch_channel(struct b43_wldev * dev,unsigned int new_channel)263758619b14SKalle Valo static int b43_gphy_op_switch_channel(struct b43_wldev *dev,
263858619b14SKalle Valo unsigned int new_channel)
263958619b14SKalle Valo {
264058619b14SKalle Valo if ((new_channel < 1) || (new_channel > 14))
264158619b14SKalle Valo return -EINVAL;
264258619b14SKalle Valo b43_gphy_channel_switch(dev, new_channel, 0);
264358619b14SKalle Valo
264458619b14SKalle Valo return 0;
264558619b14SKalle Valo }
264658619b14SKalle Valo
b43_gphy_op_get_default_chan(struct b43_wldev * dev)264758619b14SKalle Valo static unsigned int b43_gphy_op_get_default_chan(struct b43_wldev *dev)
264858619b14SKalle Valo {
264958619b14SKalle Valo return 1; /* Default to channel 1 */
265058619b14SKalle Valo }
265158619b14SKalle Valo
b43_gphy_op_set_rx_antenna(struct b43_wldev * dev,int antenna)265258619b14SKalle Valo static void b43_gphy_op_set_rx_antenna(struct b43_wldev *dev, int antenna)
265358619b14SKalle Valo {
265458619b14SKalle Valo struct b43_phy *phy = &dev->phy;
265558619b14SKalle Valo u16 tmp;
265658619b14SKalle Valo int autodiv = 0;
265758619b14SKalle Valo
265858619b14SKalle Valo if (antenna == B43_ANTENNA_AUTO0 || antenna == B43_ANTENNA_AUTO1)
265958619b14SKalle Valo autodiv = 1;
266058619b14SKalle Valo
266158619b14SKalle Valo b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_ANTDIVHELP);
266258619b14SKalle Valo
266358619b14SKalle Valo b43_phy_maskset(dev, B43_PHY_BBANDCFG, ~B43_PHY_BBANDCFG_RXANT,
266458619b14SKalle Valo (autodiv ? B43_ANTENNA_AUTO1 : antenna) <<
266558619b14SKalle Valo B43_PHY_BBANDCFG_RXANT_SHIFT);
266658619b14SKalle Valo
266758619b14SKalle Valo if (autodiv) {
266858619b14SKalle Valo tmp = b43_phy_read(dev, B43_PHY_ANTDWELL);
266958619b14SKalle Valo if (antenna == B43_ANTENNA_AUTO1)
267058619b14SKalle Valo tmp &= ~B43_PHY_ANTDWELL_AUTODIV1;
267158619b14SKalle Valo else
267258619b14SKalle Valo tmp |= B43_PHY_ANTDWELL_AUTODIV1;
267358619b14SKalle Valo b43_phy_write(dev, B43_PHY_ANTDWELL, tmp);
267458619b14SKalle Valo }
267558619b14SKalle Valo
267658619b14SKalle Valo tmp = b43_phy_read(dev, B43_PHY_ANTWRSETT);
267758619b14SKalle Valo if (autodiv)
267858619b14SKalle Valo tmp |= B43_PHY_ANTWRSETT_ARXDIV;
267958619b14SKalle Valo else
268058619b14SKalle Valo tmp &= ~B43_PHY_ANTWRSETT_ARXDIV;
268158619b14SKalle Valo b43_phy_write(dev, B43_PHY_ANTWRSETT, tmp);
268258619b14SKalle Valo
268358619b14SKalle Valo if (autodiv)
268458619b14SKalle Valo b43_phy_set(dev, B43_PHY_ANTWRSETT, B43_PHY_ANTWRSETT_ARXDIV);
268558619b14SKalle Valo else {
268658619b14SKalle Valo b43_phy_mask(dev, B43_PHY_ANTWRSETT,
268758619b14SKalle Valo B43_PHY_ANTWRSETT_ARXDIV);
268858619b14SKalle Valo }
268958619b14SKalle Valo
269058619b14SKalle Valo if (phy->rev >= 2) {
269158619b14SKalle Valo b43_phy_set(dev, B43_PHY_OFDM61, B43_PHY_OFDM61_10);
269258619b14SKalle Valo b43_phy_maskset(dev, B43_PHY_DIVSRCHGAINBACK, 0xFF00, 0x15);
269358619b14SKalle Valo
269458619b14SKalle Valo if (phy->rev == 2)
269558619b14SKalle Valo b43_phy_write(dev, B43_PHY_ADIVRELATED, 8);
269658619b14SKalle Valo else
269758619b14SKalle Valo b43_phy_maskset(dev, B43_PHY_ADIVRELATED, 0xFF00, 8);
269858619b14SKalle Valo }
269958619b14SKalle Valo if (phy->rev >= 6)
270058619b14SKalle Valo b43_phy_write(dev, B43_PHY_OFDM9B, 0xDC);
270158619b14SKalle Valo
270258619b14SKalle Valo b43_hf_write(dev, b43_hf_read(dev) | B43_HF_ANTDIVHELP);
270358619b14SKalle Valo }
270458619b14SKalle Valo
b43_gphy_op_interf_mitigation(struct b43_wldev * dev,enum b43_interference_mitigation mode)270558619b14SKalle Valo static int b43_gphy_op_interf_mitigation(struct b43_wldev *dev,
270658619b14SKalle Valo enum b43_interference_mitigation mode)
270758619b14SKalle Valo {
270858619b14SKalle Valo struct b43_phy *phy = &dev->phy;
270958619b14SKalle Valo struct b43_phy_g *gphy = phy->g;
271058619b14SKalle Valo int currentmode;
271158619b14SKalle Valo
271258619b14SKalle Valo B43_WARN_ON(phy->type != B43_PHYTYPE_G);
271358619b14SKalle Valo if ((phy->rev == 0) || (!phy->gmode))
271458619b14SKalle Valo return -ENODEV;
271558619b14SKalle Valo
271658619b14SKalle Valo gphy->aci_wlan_automatic = false;
271758619b14SKalle Valo switch (mode) {
271858619b14SKalle Valo case B43_INTERFMODE_AUTOWLAN:
271958619b14SKalle Valo gphy->aci_wlan_automatic = true;
272058619b14SKalle Valo if (gphy->aci_enable)
272158619b14SKalle Valo mode = B43_INTERFMODE_MANUALWLAN;
272258619b14SKalle Valo else
272358619b14SKalle Valo mode = B43_INTERFMODE_NONE;
272458619b14SKalle Valo break;
272558619b14SKalle Valo case B43_INTERFMODE_NONE:
272658619b14SKalle Valo case B43_INTERFMODE_NONWLAN:
272758619b14SKalle Valo case B43_INTERFMODE_MANUALWLAN:
272858619b14SKalle Valo break;
272958619b14SKalle Valo default:
273058619b14SKalle Valo return -EINVAL;
273158619b14SKalle Valo }
273258619b14SKalle Valo
273358619b14SKalle Valo currentmode = gphy->interfmode;
273458619b14SKalle Valo if (currentmode == mode)
273558619b14SKalle Valo return 0;
273658619b14SKalle Valo if (currentmode != B43_INTERFMODE_NONE)
273758619b14SKalle Valo b43_radio_interference_mitigation_disable(dev, currentmode);
273858619b14SKalle Valo
273958619b14SKalle Valo if (mode == B43_INTERFMODE_NONE) {
274058619b14SKalle Valo gphy->aci_enable = false;
274158619b14SKalle Valo gphy->aci_hw_rssi = false;
274258619b14SKalle Valo } else
274358619b14SKalle Valo b43_radio_interference_mitigation_enable(dev, mode);
274458619b14SKalle Valo gphy->interfmode = mode;
274558619b14SKalle Valo
274658619b14SKalle Valo return 0;
274758619b14SKalle Valo }
274858619b14SKalle Valo
27492d96c1edSAlexander A. Klimov /* https://bcm-specs.sipsolutions.net/EstimatePowerOut
275058619b14SKalle Valo * This function converts a TSSI value to dBm in Q5.2
275158619b14SKalle Valo */
b43_gphy_estimate_power_out(struct b43_wldev * dev,s8 tssi)275258619b14SKalle Valo static s8 b43_gphy_estimate_power_out(struct b43_wldev *dev, s8 tssi)
275358619b14SKalle Valo {
275458619b14SKalle Valo struct b43_phy_g *gphy = dev->phy.g;
275558619b14SKalle Valo s8 dbm;
275658619b14SKalle Valo s32 tmp;
275758619b14SKalle Valo
275858619b14SKalle Valo tmp = (gphy->tgt_idle_tssi - gphy->cur_idle_tssi + tssi);
275958619b14SKalle Valo tmp = clamp_val(tmp, 0x00, 0x3F);
276058619b14SKalle Valo dbm = gphy->tssi2dbm[tmp];
276158619b14SKalle Valo
276258619b14SKalle Valo return dbm;
276358619b14SKalle Valo }
276458619b14SKalle Valo
b43_put_attenuation_into_ranges(struct b43_wldev * dev,int * _bbatt,int * _rfatt)276558619b14SKalle Valo static void b43_put_attenuation_into_ranges(struct b43_wldev *dev,
276658619b14SKalle Valo int *_bbatt, int *_rfatt)
276758619b14SKalle Valo {
276858619b14SKalle Valo int rfatt = *_rfatt;
276958619b14SKalle Valo int bbatt = *_bbatt;
277058619b14SKalle Valo struct b43_txpower_lo_control *lo = dev->phy.g->lo_control;
277158619b14SKalle Valo
277258619b14SKalle Valo /* Get baseband and radio attenuation values into their permitted ranges.
277358619b14SKalle Valo * Radio attenuation affects power level 4 times as much as baseband. */
277458619b14SKalle Valo
277558619b14SKalle Valo /* Range constants */
277658619b14SKalle Valo const int rf_min = lo->rfatt_list.min_val;
277758619b14SKalle Valo const int rf_max = lo->rfatt_list.max_val;
277858619b14SKalle Valo const int bb_min = lo->bbatt_list.min_val;
277958619b14SKalle Valo const int bb_max = lo->bbatt_list.max_val;
278058619b14SKalle Valo
278158619b14SKalle Valo while (1) {
278258619b14SKalle Valo if (rfatt > rf_max && bbatt > bb_max - 4)
278358619b14SKalle Valo break; /* Can not get it into ranges */
278458619b14SKalle Valo if (rfatt < rf_min && bbatt < bb_min + 4)
278558619b14SKalle Valo break; /* Can not get it into ranges */
278658619b14SKalle Valo if (bbatt > bb_max && rfatt > rf_max - 1)
278758619b14SKalle Valo break; /* Can not get it into ranges */
278858619b14SKalle Valo if (bbatt < bb_min && rfatt < rf_min + 1)
278958619b14SKalle Valo break; /* Can not get it into ranges */
279058619b14SKalle Valo
279158619b14SKalle Valo if (bbatt > bb_max) {
279258619b14SKalle Valo bbatt -= 4;
279358619b14SKalle Valo rfatt += 1;
279458619b14SKalle Valo continue;
279558619b14SKalle Valo }
279658619b14SKalle Valo if (bbatt < bb_min) {
279758619b14SKalle Valo bbatt += 4;
279858619b14SKalle Valo rfatt -= 1;
279958619b14SKalle Valo continue;
280058619b14SKalle Valo }
280158619b14SKalle Valo if (rfatt > rf_max) {
280258619b14SKalle Valo rfatt -= 1;
280358619b14SKalle Valo bbatt += 4;
280458619b14SKalle Valo continue;
280558619b14SKalle Valo }
280658619b14SKalle Valo if (rfatt < rf_min) {
280758619b14SKalle Valo rfatt += 1;
280858619b14SKalle Valo bbatt -= 4;
280958619b14SKalle Valo continue;
281058619b14SKalle Valo }
281158619b14SKalle Valo break;
281258619b14SKalle Valo }
281358619b14SKalle Valo
281458619b14SKalle Valo *_rfatt = clamp_val(rfatt, rf_min, rf_max);
281558619b14SKalle Valo *_bbatt = clamp_val(bbatt, bb_min, bb_max);
281658619b14SKalle Valo }
281758619b14SKalle Valo
b43_gphy_op_adjust_txpower(struct b43_wldev * dev)281858619b14SKalle Valo static void b43_gphy_op_adjust_txpower(struct b43_wldev *dev)
281958619b14SKalle Valo {
282058619b14SKalle Valo struct b43_phy *phy = &dev->phy;
282158619b14SKalle Valo struct b43_phy_g *gphy = phy->g;
282258619b14SKalle Valo int rfatt, bbatt;
282358619b14SKalle Valo u8 tx_control;
282458619b14SKalle Valo
282558619b14SKalle Valo b43_mac_suspend(dev);
282658619b14SKalle Valo
282758619b14SKalle Valo /* Calculate the new attenuation values. */
282858619b14SKalle Valo bbatt = gphy->bbatt.att;
282958619b14SKalle Valo bbatt += gphy->bbatt_delta;
283058619b14SKalle Valo rfatt = gphy->rfatt.att;
283158619b14SKalle Valo rfatt += gphy->rfatt_delta;
283258619b14SKalle Valo
283358619b14SKalle Valo b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt);
283458619b14SKalle Valo tx_control = gphy->tx_control;
283558619b14SKalle Valo if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 2)) {
283658619b14SKalle Valo if (rfatt <= 1) {
283758619b14SKalle Valo if (tx_control == 0) {
283858619b14SKalle Valo tx_control =
283958619b14SKalle Valo B43_TXCTL_PA2DB |
284058619b14SKalle Valo B43_TXCTL_TXMIX;
284158619b14SKalle Valo rfatt += 2;
284258619b14SKalle Valo bbatt += 2;
284358619b14SKalle Valo } else if (dev->dev->bus_sprom->
284458619b14SKalle Valo boardflags_lo &
284558619b14SKalle Valo B43_BFL_PACTRL) {
284658619b14SKalle Valo bbatt += 4 * (rfatt - 2);
284758619b14SKalle Valo rfatt = 2;
284858619b14SKalle Valo }
284958619b14SKalle Valo } else if (rfatt > 4 && tx_control) {
285058619b14SKalle Valo tx_control = 0;
285158619b14SKalle Valo if (bbatt < 3) {
285258619b14SKalle Valo rfatt -= 3;
285358619b14SKalle Valo bbatt += 2;
285458619b14SKalle Valo } else {
285558619b14SKalle Valo rfatt -= 2;
285658619b14SKalle Valo bbatt -= 2;
285758619b14SKalle Valo }
285858619b14SKalle Valo }
285958619b14SKalle Valo }
286058619b14SKalle Valo /* Save the control values */
286158619b14SKalle Valo gphy->tx_control = tx_control;
286258619b14SKalle Valo b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt);
286358619b14SKalle Valo gphy->rfatt.att = rfatt;
286458619b14SKalle Valo gphy->bbatt.att = bbatt;
286558619b14SKalle Valo
286658619b14SKalle Valo if (b43_debug(dev, B43_DBG_XMITPOWER))
286758619b14SKalle Valo b43dbg(dev->wl, "Adjusting TX power\n");
286858619b14SKalle Valo
286958619b14SKalle Valo /* Adjust the hardware */
287058619b14SKalle Valo b43_phy_lock(dev);
287158619b14SKalle Valo b43_radio_lock(dev);
287258619b14SKalle Valo b43_set_txpower_g(dev, &gphy->bbatt, &gphy->rfatt,
287358619b14SKalle Valo gphy->tx_control);
287458619b14SKalle Valo b43_radio_unlock(dev);
287558619b14SKalle Valo b43_phy_unlock(dev);
287658619b14SKalle Valo
287758619b14SKalle Valo b43_mac_enable(dev);
287858619b14SKalle Valo }
287958619b14SKalle Valo
b43_gphy_op_recalc_txpower(struct b43_wldev * dev,bool ignore_tssi)288058619b14SKalle Valo static enum b43_txpwr_result b43_gphy_op_recalc_txpower(struct b43_wldev *dev,
288158619b14SKalle Valo bool ignore_tssi)
288258619b14SKalle Valo {
288358619b14SKalle Valo struct b43_phy *phy = &dev->phy;
288458619b14SKalle Valo struct b43_phy_g *gphy = phy->g;
288558619b14SKalle Valo unsigned int average_tssi;
288658619b14SKalle Valo int cck_result, ofdm_result;
288758619b14SKalle Valo int estimated_pwr, desired_pwr, pwr_adjust;
288858619b14SKalle Valo int rfatt_delta, bbatt_delta;
288958619b14SKalle Valo unsigned int max_pwr;
289058619b14SKalle Valo
289158619b14SKalle Valo /* First get the average TSSI */
289258619b14SKalle Valo cck_result = b43_phy_shm_tssi_read(dev, B43_SHM_SH_TSSI_CCK);
289358619b14SKalle Valo ofdm_result = b43_phy_shm_tssi_read(dev, B43_SHM_SH_TSSI_OFDM_G);
289458619b14SKalle Valo if ((cck_result < 0) && (ofdm_result < 0)) {
289558619b14SKalle Valo /* No TSSI information available */
289658619b14SKalle Valo if (!ignore_tssi)
289758619b14SKalle Valo goto no_adjustment_needed;
289858619b14SKalle Valo cck_result = 0;
289958619b14SKalle Valo ofdm_result = 0;
290058619b14SKalle Valo }
290158619b14SKalle Valo if (cck_result < 0)
290258619b14SKalle Valo average_tssi = ofdm_result;
290358619b14SKalle Valo else if (ofdm_result < 0)
290458619b14SKalle Valo average_tssi = cck_result;
290558619b14SKalle Valo else
290658619b14SKalle Valo average_tssi = (cck_result + ofdm_result) / 2;
290758619b14SKalle Valo /* Merge the average with the stored value. */
290858619b14SKalle Valo if (likely(gphy->average_tssi != 0xFF))
290958619b14SKalle Valo average_tssi = (average_tssi + gphy->average_tssi) / 2;
291058619b14SKalle Valo gphy->average_tssi = average_tssi;
291158619b14SKalle Valo B43_WARN_ON(average_tssi >= B43_TSSI_MAX);
291258619b14SKalle Valo
291358619b14SKalle Valo /* Estimate the TX power emission based on the TSSI */
291458619b14SKalle Valo estimated_pwr = b43_gphy_estimate_power_out(dev, average_tssi);
291558619b14SKalle Valo
291658619b14SKalle Valo B43_WARN_ON(phy->type != B43_PHYTYPE_G);
291758619b14SKalle Valo max_pwr = dev->dev->bus_sprom->maxpwr_bg;
291858619b14SKalle Valo if (dev->dev->bus_sprom->boardflags_lo & B43_BFL_PACTRL)
291958619b14SKalle Valo max_pwr -= 3; /* minus 0.75 */
292058619b14SKalle Valo if (unlikely(max_pwr >= INT_TO_Q52(30/*dBm*/))) {
292158619b14SKalle Valo b43warn(dev->wl,
292258619b14SKalle Valo "Invalid max-TX-power value in SPROM.\n");
292358619b14SKalle Valo max_pwr = INT_TO_Q52(20); /* fake it */
292458619b14SKalle Valo dev->dev->bus_sprom->maxpwr_bg = max_pwr;
292558619b14SKalle Valo }
292658619b14SKalle Valo
292758619b14SKalle Valo /* Get desired power (in Q5.2) */
292858619b14SKalle Valo if (phy->desired_txpower < 0)
292958619b14SKalle Valo desired_pwr = INT_TO_Q52(0);
293058619b14SKalle Valo else
293158619b14SKalle Valo desired_pwr = INT_TO_Q52(phy->desired_txpower);
293258619b14SKalle Valo /* And limit it. max_pwr already is Q5.2 */
293358619b14SKalle Valo desired_pwr = clamp_val(desired_pwr, 0, max_pwr);
293458619b14SKalle Valo if (b43_debug(dev, B43_DBG_XMITPOWER)) {
293558619b14SKalle Valo b43dbg(dev->wl,
293658619b14SKalle Valo "[TX power] current = " Q52_FMT
293758619b14SKalle Valo " dBm, desired = " Q52_FMT
293858619b14SKalle Valo " dBm, max = " Q52_FMT "\n",
293958619b14SKalle Valo Q52_ARG(estimated_pwr),
294058619b14SKalle Valo Q52_ARG(desired_pwr),
294158619b14SKalle Valo Q52_ARG(max_pwr));
294258619b14SKalle Valo }
294358619b14SKalle Valo
294458619b14SKalle Valo /* Calculate the adjustment delta. */
294558619b14SKalle Valo pwr_adjust = desired_pwr - estimated_pwr;
294658619b14SKalle Valo if (pwr_adjust == 0)
294758619b14SKalle Valo goto no_adjustment_needed;
294858619b14SKalle Valo
294958619b14SKalle Valo /* RF attenuation delta. */
295058619b14SKalle Valo rfatt_delta = ((pwr_adjust + 7) / 8);
295158619b14SKalle Valo /* Lower attenuation => Bigger power output. Negate it. */
295258619b14SKalle Valo rfatt_delta = -rfatt_delta;
295358619b14SKalle Valo
295458619b14SKalle Valo /* Baseband attenuation delta. */
295558619b14SKalle Valo bbatt_delta = pwr_adjust / 2;
295658619b14SKalle Valo /* Lower attenuation => Bigger power output. Negate it. */
295758619b14SKalle Valo bbatt_delta = -bbatt_delta;
295858619b14SKalle Valo /* RF att affects power level 4 times as much as
295958619b14SKalle Valo * Baseband attennuation. Subtract it. */
296058619b14SKalle Valo bbatt_delta -= 4 * rfatt_delta;
296158619b14SKalle Valo
296258619b14SKalle Valo #if B43_DEBUG
296358619b14SKalle Valo if (b43_debug(dev, B43_DBG_XMITPOWER)) {
296458619b14SKalle Valo int dbm = pwr_adjust < 0 ? -pwr_adjust : pwr_adjust;
296558619b14SKalle Valo b43dbg(dev->wl,
296658619b14SKalle Valo "[TX power deltas] %s" Q52_FMT " dBm => "
296758619b14SKalle Valo "bbatt-delta = %d, rfatt-delta = %d\n",
296858619b14SKalle Valo (pwr_adjust < 0 ? "-" : ""), Q52_ARG(dbm),
296958619b14SKalle Valo bbatt_delta, rfatt_delta);
297058619b14SKalle Valo }
297158619b14SKalle Valo #endif /* DEBUG */
297258619b14SKalle Valo
297358619b14SKalle Valo /* So do we finally need to adjust something in hardware? */
297458619b14SKalle Valo if ((rfatt_delta == 0) && (bbatt_delta == 0))
297558619b14SKalle Valo goto no_adjustment_needed;
297658619b14SKalle Valo
297758619b14SKalle Valo /* Save the deltas for later when we adjust the power. */
297858619b14SKalle Valo gphy->bbatt_delta = bbatt_delta;
297958619b14SKalle Valo gphy->rfatt_delta = rfatt_delta;
298058619b14SKalle Valo
298158619b14SKalle Valo /* We need to adjust the TX power on the device. */
298258619b14SKalle Valo return B43_TXPWR_RES_NEED_ADJUST;
298358619b14SKalle Valo
298458619b14SKalle Valo no_adjustment_needed:
298558619b14SKalle Valo return B43_TXPWR_RES_DONE;
298658619b14SKalle Valo }
298758619b14SKalle Valo
b43_gphy_op_pwork_15sec(struct b43_wldev * dev)298858619b14SKalle Valo static void b43_gphy_op_pwork_15sec(struct b43_wldev *dev)
298958619b14SKalle Valo {
299058619b14SKalle Valo struct b43_phy *phy = &dev->phy;
299158619b14SKalle Valo struct b43_phy_g *gphy = phy->g;
299258619b14SKalle Valo
299358619b14SKalle Valo b43_mac_suspend(dev);
299458619b14SKalle Valo //TODO: update_aci_moving_average
299558619b14SKalle Valo if (gphy->aci_enable && gphy->aci_wlan_automatic) {
299658619b14SKalle Valo if (!gphy->aci_enable && 1 /*TODO: not scanning? */ ) {
299758619b14SKalle Valo if (0 /*TODO: bunch of conditions */ ) {
299858619b14SKalle Valo phy->ops->interf_mitigation(dev,
299958619b14SKalle Valo B43_INTERFMODE_MANUALWLAN);
300058619b14SKalle Valo }
300158619b14SKalle Valo } else if (0 /*TODO*/) {
300258619b14SKalle Valo if (/*(aci_average > 1000) &&*/ !b43_gphy_aci_scan(dev))
300358619b14SKalle Valo phy->ops->interf_mitigation(dev, B43_INTERFMODE_NONE);
300458619b14SKalle Valo }
300558619b14SKalle Valo } else if (gphy->interfmode == B43_INTERFMODE_NONWLAN &&
300658619b14SKalle Valo phy->rev == 1) {
300758619b14SKalle Valo //TODO: implement rev1 workaround
300858619b14SKalle Valo }
300958619b14SKalle Valo b43_lo_g_maintenance_work(dev);
301058619b14SKalle Valo b43_mac_enable(dev);
301158619b14SKalle Valo }
301258619b14SKalle Valo
b43_gphy_op_pwork_60sec(struct b43_wldev * dev)301358619b14SKalle Valo static void b43_gphy_op_pwork_60sec(struct b43_wldev *dev)
301458619b14SKalle Valo {
301558619b14SKalle Valo struct b43_phy *phy = &dev->phy;
301658619b14SKalle Valo
301758619b14SKalle Valo if (!(dev->dev->bus_sprom->boardflags_lo & B43_BFL_RSSI))
301858619b14SKalle Valo return;
301958619b14SKalle Valo
302058619b14SKalle Valo b43_mac_suspend(dev);
302158619b14SKalle Valo b43_calc_nrssi_slope(dev);
302258619b14SKalle Valo if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 8)) {
302358619b14SKalle Valo u8 old_chan = phy->channel;
302458619b14SKalle Valo
302558619b14SKalle Valo /* VCO Calibration */
302658619b14SKalle Valo if (old_chan >= 8)
302758619b14SKalle Valo b43_switch_channel(dev, 1);
302858619b14SKalle Valo else
302958619b14SKalle Valo b43_switch_channel(dev, 13);
303058619b14SKalle Valo b43_switch_channel(dev, old_chan);
303158619b14SKalle Valo }
303258619b14SKalle Valo b43_mac_enable(dev);
303358619b14SKalle Valo }
303458619b14SKalle Valo
303558619b14SKalle Valo const struct b43_phy_operations b43_phyops_g = {
303658619b14SKalle Valo .allocate = b43_gphy_op_allocate,
303758619b14SKalle Valo .free = b43_gphy_op_free,
303858619b14SKalle Valo .prepare_structs = b43_gphy_op_prepare_structs,
303958619b14SKalle Valo .prepare_hardware = b43_gphy_op_prepare_hardware,
304058619b14SKalle Valo .init = b43_gphy_op_init,
304158619b14SKalle Valo .exit = b43_gphy_op_exit,
304258619b14SKalle Valo .phy_read = b43_gphy_op_read,
304358619b14SKalle Valo .phy_write = b43_gphy_op_write,
304458619b14SKalle Valo .radio_read = b43_gphy_op_radio_read,
304558619b14SKalle Valo .radio_write = b43_gphy_op_radio_write,
304658619b14SKalle Valo .supports_hwpctl = b43_gphy_op_supports_hwpctl,
304758619b14SKalle Valo .software_rfkill = b43_gphy_op_software_rfkill,
304858619b14SKalle Valo .switch_analog = b43_phyop_switch_analog_generic,
304958619b14SKalle Valo .switch_channel = b43_gphy_op_switch_channel,
305058619b14SKalle Valo .get_default_chan = b43_gphy_op_get_default_chan,
305158619b14SKalle Valo .set_rx_antenna = b43_gphy_op_set_rx_antenna,
305258619b14SKalle Valo .interf_mitigation = b43_gphy_op_interf_mitigation,
305358619b14SKalle Valo .recalc_txpower = b43_gphy_op_recalc_txpower,
305458619b14SKalle Valo .adjust_txpower = b43_gphy_op_adjust_txpower,
305558619b14SKalle Valo .pwork_15sec = b43_gphy_op_pwork_15sec,
305658619b14SKalle Valo .pwork_60sec = b43_gphy_op_pwork_60sec,
305758619b14SKalle Valo };
3058