linux/drivers/net/wireless/mediatek/mt76/mt76x2/phy.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
   3 * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
   4 *
   5 * Permission to use, copy, modify, and/or distribute this software for any
   6 * purpose with or without fee is hereby granted, provided that the above
   7 * copyright notice and this permission notice appear in all copies.
   8 *
   9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16 */
  17
  18#include "mt76x2.h"
  19#include "eeprom.h"
  20#include "mcu.h"
  21#include "../mt76x02_phy.h"
  22
  23static void
  24mt76x2_adjust_high_lna_gain(struct mt76x02_dev *dev, int reg, s8 offset)
  25{
  26        s8 gain;
  27
  28        gain = FIELD_GET(MT_BBP_AGC_LNA_HIGH_GAIN, mt76_rr(dev, MT_BBP(AGC, reg)));
  29        gain -= offset / 2;
  30        mt76_rmw_field(dev, MT_BBP(AGC, reg), MT_BBP_AGC_LNA_HIGH_GAIN, gain);
  31}
  32
  33static void
  34mt76x2_adjust_agc_gain(struct mt76x02_dev *dev, int reg, s8 offset)
  35{
  36        s8 gain;
  37
  38        gain = FIELD_GET(MT_BBP_AGC_GAIN, mt76_rr(dev, MT_BBP(AGC, reg)));
  39        gain += offset;
  40        mt76_rmw_field(dev, MT_BBP(AGC, reg), MT_BBP_AGC_GAIN, gain);
  41}
  42
  43void mt76x2_apply_gain_adj(struct mt76x02_dev *dev)
  44{
  45        s8 *gain_adj = dev->cal.rx.high_gain;
  46
  47        mt76x2_adjust_high_lna_gain(dev, 4, gain_adj[0]);
  48        mt76x2_adjust_high_lna_gain(dev, 5, gain_adj[1]);
  49
  50        mt76x2_adjust_agc_gain(dev, 8, gain_adj[0]);
  51        mt76x2_adjust_agc_gain(dev, 9, gain_adj[1]);
  52}
  53EXPORT_SYMBOL_GPL(mt76x2_apply_gain_adj);
  54
  55void mt76x2_phy_set_txpower_regs(struct mt76x02_dev *dev,
  56                                 enum nl80211_band band)
  57{
  58        u32 pa_mode[2];
  59        u32 pa_mode_adj;
  60
  61        if (band == NL80211_BAND_2GHZ) {
  62                pa_mode[0] = 0x010055ff;
  63                pa_mode[1] = 0x00550055;
  64
  65                mt76_wr(dev, MT_TX_ALC_CFG_2, 0x35160a00);
  66                mt76_wr(dev, MT_TX_ALC_CFG_3, 0x35160a06);
  67
  68                if (mt76x02_ext_pa_enabled(dev, band)) {
  69                        mt76_wr(dev, MT_RF_PA_MODE_ADJ0, 0x0000ec00);
  70                        mt76_wr(dev, MT_RF_PA_MODE_ADJ1, 0x0000ec00);
  71                } else {
  72                        mt76_wr(dev, MT_RF_PA_MODE_ADJ0, 0xf4000200);
  73                        mt76_wr(dev, MT_RF_PA_MODE_ADJ1, 0xfa000200);
  74                }
  75        } else {
  76                pa_mode[0] = 0x0000ffff;
  77                pa_mode[1] = 0x00ff00ff;
  78
  79                if (mt76x02_ext_pa_enabled(dev, band)) {
  80                        mt76_wr(dev, MT_TX_ALC_CFG_2, 0x2f0f0400);
  81                        mt76_wr(dev, MT_TX_ALC_CFG_3, 0x2f0f0476);
  82                } else {
  83                        mt76_wr(dev, MT_TX_ALC_CFG_2, 0x1b0f0400);
  84                        mt76_wr(dev, MT_TX_ALC_CFG_3, 0x1b0f0476);
  85                }
  86
  87                if (mt76x02_ext_pa_enabled(dev, band))
  88                        pa_mode_adj = 0x04000000;
  89                else
  90                        pa_mode_adj = 0;
  91
  92                mt76_wr(dev, MT_RF_PA_MODE_ADJ0, pa_mode_adj);
  93                mt76_wr(dev, MT_RF_PA_MODE_ADJ1, pa_mode_adj);
  94        }
  95
  96        mt76_wr(dev, MT_BB_PA_MODE_CFG0, pa_mode[0]);
  97        mt76_wr(dev, MT_BB_PA_MODE_CFG1, pa_mode[1]);
  98        mt76_wr(dev, MT_RF_PA_MODE_CFG0, pa_mode[0]);
  99        mt76_wr(dev, MT_RF_PA_MODE_CFG1, pa_mode[1]);
 100
 101        if (mt76x02_ext_pa_enabled(dev, band)) {
 102                u32 val;
 103
 104                if (band == NL80211_BAND_2GHZ)
 105                        val = 0x3c3c023c;
 106                else
 107                        val = 0x363c023c;
 108
 109                mt76_wr(dev, MT_TX0_RF_GAIN_CORR, val);
 110                mt76_wr(dev, MT_TX1_RF_GAIN_CORR, val);
 111                mt76_wr(dev, MT_TX_ALC_CFG_4, 0x00001818);
 112        } else {
 113                if (band == NL80211_BAND_2GHZ) {
 114                        u32 val = 0x0f3c3c3c;
 115
 116                        mt76_wr(dev, MT_TX0_RF_GAIN_CORR, val);
 117                        mt76_wr(dev, MT_TX1_RF_GAIN_CORR, val);
 118                        mt76_wr(dev, MT_TX_ALC_CFG_4, 0x00000606);
 119                } else {
 120                        mt76_wr(dev, MT_TX0_RF_GAIN_CORR, 0x383c023c);
 121                        mt76_wr(dev, MT_TX1_RF_GAIN_CORR, 0x24282e28);
 122                        mt76_wr(dev, MT_TX_ALC_CFG_4, 0);
 123                }
 124        }
 125}
 126EXPORT_SYMBOL_GPL(mt76x2_phy_set_txpower_regs);
 127
 128static int
 129mt76x2_get_min_rate_power(struct mt76_rate_power *r)
 130{
 131        int i;
 132        s8 ret = 0;
 133
 134        for (i = 0; i < sizeof(r->all); i++) {
 135                if (!r->all[i])
 136                        continue;
 137
 138                if (ret)
 139                        ret = min(ret, r->all[i]);
 140                else
 141                        ret = r->all[i];
 142        }
 143
 144        return ret;
 145}
 146
 147void mt76x2_phy_set_txpower(struct mt76x02_dev *dev)
 148{
 149        enum nl80211_chan_width width = dev->mt76.chandef.width;
 150        struct ieee80211_channel *chan = dev->mt76.chandef.chan;
 151        struct mt76x2_tx_power_info txp;
 152        int txp_0, txp_1, delta = 0;
 153        struct mt76_rate_power t = {};
 154        int base_power, gain;
 155
 156        mt76x2_get_power_info(dev, &txp, chan);
 157
 158        if (width == NL80211_CHAN_WIDTH_40)
 159                delta = txp.delta_bw40;
 160        else if (width == NL80211_CHAN_WIDTH_80)
 161                delta = txp.delta_bw80;
 162
 163        mt76x2_get_rate_power(dev, &t, chan);
 164        mt76x02_add_rate_power_offset(&t, txp.chain[0].target_power);
 165        mt76x02_limit_rate_power(&t, dev->mt76.txpower_conf);
 166        dev->mt76.txpower_cur = mt76x02_get_max_rate_power(&t);
 167
 168        base_power = mt76x2_get_min_rate_power(&t);
 169        delta += base_power - txp.chain[0].target_power;
 170        txp_0 = txp.chain[0].target_power + txp.chain[0].delta + delta;
 171        txp_1 = txp.chain[1].target_power + txp.chain[1].delta + delta;
 172
 173        gain = min(txp_0, txp_1);
 174        if (gain < 0) {
 175                base_power -= gain;
 176                txp_0 -= gain;
 177                txp_1 -= gain;
 178        } else if (gain > 0x2f) {
 179                base_power -= gain - 0x2f;
 180                txp_0 = 0x2f;
 181                txp_1 = 0x2f;
 182        }
 183
 184        mt76x02_add_rate_power_offset(&t, -base_power);
 185        dev->target_power = txp.chain[0].target_power;
 186        dev->target_power_delta[0] = txp_0 - txp.chain[0].target_power;
 187        dev->target_power_delta[1] = txp_1 - txp.chain[0].target_power;
 188        dev->mt76.rate_power = t;
 189
 190        mt76x02_phy_set_txpower(dev, txp_0, txp_1);
 191}
 192EXPORT_SYMBOL_GPL(mt76x2_phy_set_txpower);
 193
 194void mt76x2_configure_tx_delay(struct mt76x02_dev *dev,
 195                               enum nl80211_band band, u8 bw)
 196{
 197        u32 cfg0, cfg1;
 198
 199        if (mt76x02_ext_pa_enabled(dev, band)) {
 200                cfg0 = bw ? 0x000b0c01 : 0x00101101;
 201                cfg1 = 0x00011414;
 202        } else {
 203                cfg0 = bw ? 0x000b0b01 : 0x00101001;
 204                cfg1 = 0x00021414;
 205        }
 206        mt76_wr(dev, MT_TX_SW_CFG0, cfg0);
 207        mt76_wr(dev, MT_TX_SW_CFG1, cfg1);
 208
 209        mt76_rmw_field(dev, MT_XIFS_TIME_CFG, MT_XIFS_TIME_CFG_OFDM_SIFS, 15);
 210}
 211EXPORT_SYMBOL_GPL(mt76x2_configure_tx_delay);
 212
 213void mt76x2_phy_tssi_compensate(struct mt76x02_dev *dev)
 214{
 215        struct ieee80211_channel *chan = dev->mt76.chandef.chan;
 216        struct mt76x2_tx_power_info txp;
 217        struct mt76x2_tssi_comp t = {};
 218
 219        if (!dev->cal.tssi_cal_done)
 220                return;
 221
 222        if (!dev->cal.tssi_comp_pending) {
 223                /* TSSI trigger */
 224                t.cal_mode = BIT(0);
 225                mt76x2_mcu_tssi_comp(dev, &t);
 226                dev->cal.tssi_comp_pending = true;
 227        } else {
 228                if (mt76_rr(dev, MT_BBP(CORE, 34)) & BIT(4))
 229                        return;
 230
 231                dev->cal.tssi_comp_pending = false;
 232                mt76x2_get_power_info(dev, &txp, chan);
 233
 234                if (mt76x02_ext_pa_enabled(dev, chan->band))
 235                        t.pa_mode = 1;
 236
 237                t.cal_mode = BIT(1);
 238                t.slope0 = txp.chain[0].tssi_slope;
 239                t.offset0 = txp.chain[0].tssi_offset;
 240                t.slope1 = txp.chain[1].tssi_slope;
 241                t.offset1 = txp.chain[1].tssi_offset;
 242                mt76x2_mcu_tssi_comp(dev, &t);
 243
 244                if (t.pa_mode || dev->cal.dpd_cal_done)
 245                        return;
 246
 247                usleep_range(10000, 20000);
 248                mt76x02_mcu_calibrate(dev, MCU_CAL_DPD, chan->hw_value);
 249                dev->cal.dpd_cal_done = true;
 250        }
 251}
 252EXPORT_SYMBOL_GPL(mt76x2_phy_tssi_compensate);
 253
 254static void
 255mt76x2_phy_set_gain_val(struct mt76x02_dev *dev)
 256{
 257        u32 val;
 258        u8 gain_val[2];
 259
 260        gain_val[0] = dev->cal.agc_gain_cur[0] - dev->cal.agc_gain_adjust;
 261        gain_val[1] = dev->cal.agc_gain_cur[1] - dev->cal.agc_gain_adjust;
 262
 263        if (dev->mt76.chandef.width >= NL80211_CHAN_WIDTH_40)
 264                val = 0x1e42 << 16;
 265        else
 266                val = 0x1836 << 16;
 267
 268        val |= 0xf8;
 269
 270        mt76_wr(dev, MT_BBP(AGC, 8),
 271                val | FIELD_PREP(MT_BBP_AGC_GAIN, gain_val[0]));
 272        mt76_wr(dev, MT_BBP(AGC, 9),
 273                val | FIELD_PREP(MT_BBP_AGC_GAIN, gain_val[1]));
 274
 275        if (dev->mt76.chandef.chan->flags & IEEE80211_CHAN_RADAR)
 276                mt76x02_phy_dfs_adjust_agc(dev);
 277}
 278
 279void mt76x2_phy_update_channel_gain(struct mt76x02_dev *dev)
 280{
 281        u8 *gain = dev->cal.agc_gain_init;
 282        u8 low_gain_delta, gain_delta;
 283        bool gain_change;
 284        int low_gain;
 285        u32 val;
 286
 287        dev->cal.avg_rssi_all = mt76x02_phy_get_min_avg_rssi(dev);
 288
 289        low_gain = (dev->cal.avg_rssi_all > mt76x02_get_rssi_gain_thresh(dev)) +
 290                   (dev->cal.avg_rssi_all > mt76x02_get_low_rssi_gain_thresh(dev));
 291
 292        gain_change = dev->cal.low_gain < 0 ||
 293                      (dev->cal.low_gain & 2) ^ (low_gain & 2);
 294        dev->cal.low_gain = low_gain;
 295
 296        if (!gain_change) {
 297                if (mt76x02_phy_adjust_vga_gain(dev))
 298                        mt76x2_phy_set_gain_val(dev);
 299                return;
 300        }
 301
 302        if (dev->mt76.chandef.width == NL80211_CHAN_WIDTH_80) {
 303                mt76_wr(dev, MT_BBP(RXO, 14), 0x00560211);
 304                val = mt76_rr(dev, MT_BBP(AGC, 26)) & ~0xf;
 305                if (low_gain == 2)
 306                        val |= 0x3;
 307                else
 308                        val |= 0x5;
 309                mt76_wr(dev, MT_BBP(AGC, 26), val);
 310        } else {
 311                mt76_wr(dev, MT_BBP(RXO, 14), 0x00560423);
 312        }
 313
 314        if (mt76x2_has_ext_lna(dev))
 315                low_gain_delta = 10;
 316        else
 317                low_gain_delta = 14;
 318
 319        if (low_gain == 2) {
 320                mt76_wr(dev, MT_BBP(RXO, 18), 0xf000a990);
 321                mt76_wr(dev, MT_BBP(AGC, 35), 0x08080808);
 322                mt76_wr(dev, MT_BBP(AGC, 37), 0x08080808);
 323                gain_delta = low_gain_delta;
 324                dev->cal.agc_gain_adjust = 0;
 325        } else {
 326                mt76_wr(dev, MT_BBP(RXO, 18), 0xf000a991);
 327                if (dev->mt76.chandef.width == NL80211_CHAN_WIDTH_80)
 328                        mt76_wr(dev, MT_BBP(AGC, 35), 0x10101014);
 329                else
 330                        mt76_wr(dev, MT_BBP(AGC, 35), 0x11111116);
 331                mt76_wr(dev, MT_BBP(AGC, 37), 0x2121262C);
 332                gain_delta = 0;
 333                dev->cal.agc_gain_adjust = low_gain_delta;
 334        }
 335
 336        dev->cal.agc_gain_cur[0] = gain[0] - gain_delta;
 337        dev->cal.agc_gain_cur[1] = gain[1] - gain_delta;
 338        mt76x2_phy_set_gain_val(dev);
 339
 340        /* clear false CCA counters */
 341        mt76_rr(dev, MT_RX_STAT_1);
 342}
 343EXPORT_SYMBOL_GPL(mt76x2_phy_update_channel_gain);
 344