Path: blob/main/sys/contrib/dev/mediatek/mt76/mt7615/testmode.c
48525 views
// SPDX-License-Identifier: ISC1/* Copyright (C) 2020 Felix Fietkau <[email protected]> */23#include "mt7615.h"4#include "eeprom.h"5#include "mcu.h"67enum {8TM_CHANGED_TXPOWER_CTRL,9TM_CHANGED_TXPOWER,10TM_CHANGED_FREQ_OFFSET,1112/* must be last */13NUM_TM_CHANGED14};151617static const u8 tm_change_map[] = {18[TM_CHANGED_TXPOWER_CTRL] = MT76_TM_ATTR_TX_POWER_CONTROL,19[TM_CHANGED_TXPOWER] = MT76_TM_ATTR_TX_POWER,20[TM_CHANGED_FREQ_OFFSET] = MT76_TM_ATTR_FREQ_OFFSET,21};2223static const u32 reg_backup_list[] = {24MT_WF_PHY_RFINTF3_0(0),25MT_WF_PHY_RFINTF3_0(1),26MT_WF_PHY_RFINTF3_0(2),27MT_WF_PHY_RFINTF3_0(3),28MT_ANT_SWITCH_CON(2),29MT_ANT_SWITCH_CON(3),30MT_ANT_SWITCH_CON(4),31MT_ANT_SWITCH_CON(6),32MT_ANT_SWITCH_CON(7),33MT_ANT_SWITCH_CON(8),34};3536static const struct {37u16 wf;38u16 reg;39} rf_backup_list[] = {40{ 0, 0x48 },41{ 1, 0x48 },42{ 2, 0x48 },43{ 3, 0x48 },44};4546static int47mt7615_tm_set_tx_power(struct mt7615_phy *phy)48{49struct mt7615_dev *dev = phy->dev;50struct mt76_phy *mphy = phy->mt76;51int i, ret, n_chains = hweight8(mphy->antenna_mask);52struct cfg80211_chan_def *chandef = &mphy->chandef;53int freq = chandef->center_freq1, len, target_chains;54u8 *data, *eep = (u8 *)dev->mt76.eeprom.data;55enum nl80211_band band = chandef->chan->band;56struct sk_buff *skb;57struct {58u8 center_chan;59u8 dbdc_idx;60u8 band;61u8 rsv;62} __packed req_hdr = {63.center_chan = ieee80211_frequency_to_channel(freq),64.band = band,65.dbdc_idx = phy != &dev->phy,66};67u8 *tx_power = NULL;6869if (mphy->test.state != MT76_TM_STATE_OFF)70tx_power = mphy->test.tx_power;7172len = MT7615_EE_MAX - MT_EE_NIC_CONF_0;73skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, sizeof(req_hdr) + len);74if (!skb)75return -ENOMEM;7677skb_put_data(skb, &req_hdr, sizeof(req_hdr));78data = skb_put_data(skb, eep + MT_EE_NIC_CONF_0, len);7980target_chains = mt7615_ext_pa_enabled(dev, band) ? 1 : n_chains;81for (i = 0; i < target_chains; i++) {82ret = mt7615_eeprom_get_target_power_index(dev, chandef->chan, i);83if (ret < 0) {84dev_kfree_skb(skb);85return -EINVAL;86}8788if (tx_power && tx_power[i])89data[ret - MT_EE_NIC_CONF_0] = tx_power[i];90}9192return mt76_mcu_skb_send_msg(&dev->mt76, skb,93MCU_EXT_CMD(SET_TX_POWER_CTRL), false);94}9596static void97mt7615_tm_reg_backup_restore(struct mt7615_phy *phy)98{99struct mt7615_dev *dev = phy->dev;100u32 *b = phy->test.reg_backup;101int n_regs = ARRAY_SIZE(reg_backup_list);102int n_rf_regs = ARRAY_SIZE(rf_backup_list);103int i;104105if (phy->mt76->test.state == MT76_TM_STATE_OFF) {106for (i = 0; i < n_regs; i++)107mt76_wr(dev, reg_backup_list[i], b[i]);108109for (i = 0; i < n_rf_regs; i++)110mt7615_rf_wr(dev, rf_backup_list[i].wf,111rf_backup_list[i].reg, b[n_regs + i]);112return;113}114115if (b)116return;117118b = devm_kzalloc(dev->mt76.dev, 4 * (n_regs + n_rf_regs),119GFP_KERNEL);120if (!b)121return;122123phy->test.reg_backup = b;124for (i = 0; i < n_regs; i++)125b[i] = mt76_rr(dev, reg_backup_list[i]);126for (i = 0; i < n_rf_regs; i++)127b[n_regs + i] = mt7615_rf_rr(dev, rf_backup_list[i].wf,128rf_backup_list[i].reg);129}130131static void132mt7615_tm_init(struct mt7615_phy *phy)133{134struct mt7615_dev *dev = phy->dev;135unsigned int total_flags = ~0;136137if (!test_bit(MT76_STATE_RUNNING, &phy->mt76->state))138return;139140mt7615_mcu_set_sku_en(phy, phy->mt76->test.state == MT76_TM_STATE_OFF);141142mutex_unlock(&dev->mt76.mutex);143mt76_update_channel(phy->mt76);144mt7615_ops.configure_filter(phy->mt76->hw, 0, &total_flags, 0);145mutex_lock(&dev->mt76.mutex);146147mt7615_tm_reg_backup_restore(phy);148}149150static void151mt7615_tm_set_rx_enable(struct mt7615_dev *dev, bool en)152{153u32 rqcr_mask = (MT_ARB_RQCR_RX_START |154MT_ARB_RQCR_RXV_START |155MT_ARB_RQCR_RXV_R_EN |156MT_ARB_RQCR_RXV_T_EN) *157(BIT(0) | BIT(MT_ARB_RQCR_BAND_SHIFT));158159if (en) {160mt76_clear(dev, MT_ARB_SCR,161MT_ARB_SCR_RX0_DISABLE | MT_ARB_SCR_RX1_DISABLE);162mt76_set(dev, MT_ARB_RQCR, rqcr_mask);163} else {164mt76_set(dev, MT_ARB_SCR,165MT_ARB_SCR_RX0_DISABLE | MT_ARB_SCR_RX1_DISABLE);166mt76_clear(dev, MT_ARB_RQCR, rqcr_mask);167}168}169170static void171mt7615_tm_set_tx_antenna(struct mt7615_phy *phy, bool en)172{173struct mt7615_dev *dev = phy->dev;174struct mt76_testmode_data *td = &phy->mt76->test;175u8 mask = td->tx_antenna_mask;176int i;177178if (!mask)179return;180181if (!en)182mask = phy->mt76->chainmask;183184for (i = 0; i < 4; i++) {185mt76_rmw_field(dev, MT_WF_PHY_RFINTF3_0(i),186MT_WF_PHY_RFINTF3_0_ANT,187(mask & BIT(i)) ? 0 : 0xa);188}189190/* 2.4 GHz band */191mt76_rmw_field(dev, MT_ANT_SWITCH_CON(3), MT_ANT_SWITCH_CON_MODE(0),192(mask & BIT(0)) ? 0x8 : 0x1b);193mt76_rmw_field(dev, MT_ANT_SWITCH_CON(4), MT_ANT_SWITCH_CON_MODE(2),194(mask & BIT(1)) ? 0xe : 0x1b);195mt76_rmw_field(dev, MT_ANT_SWITCH_CON(6), MT_ANT_SWITCH_CON_MODE1(0),196(mask & BIT(2)) ? 0x0 : 0xf);197mt76_rmw_field(dev, MT_ANT_SWITCH_CON(7), MT_ANT_SWITCH_CON_MODE1(2),198(mask & BIT(3)) ? 0x6 : 0xf);199200/* 5 GHz band */201mt76_rmw_field(dev, MT_ANT_SWITCH_CON(4), MT_ANT_SWITCH_CON_MODE(1),202(mask & BIT(0)) ? 0xd : 0x1b);203mt76_rmw_field(dev, MT_ANT_SWITCH_CON(2), MT_ANT_SWITCH_CON_MODE(3),204(mask & BIT(1)) ? 0x13 : 0x1b);205mt76_rmw_field(dev, MT_ANT_SWITCH_CON(7), MT_ANT_SWITCH_CON_MODE1(1),206(mask & BIT(2)) ? 0x5 : 0xf);207mt76_rmw_field(dev, MT_ANT_SWITCH_CON(8), MT_ANT_SWITCH_CON_MODE1(3),208(mask & BIT(3)) ? 0xb : 0xf);209210for (i = 0; i < 4; i++) {211u32 val;212213val = mt7615_rf_rr(dev, i, 0x48);214val &= ~(0x3ff << 20);215if (mask & BIT(i))216val |= 3 << 20;217else218val |= (2 << 28) | (2 << 26) | (8 << 20);219mt7615_rf_wr(dev, i, 0x48, val);220}221}222223static void224mt7615_tm_set_tx_frames(struct mt7615_phy *phy, bool en)225{226struct mt7615_dev *dev = phy->dev;227struct ieee80211_tx_info *info;228struct sk_buff *skb = phy->mt76->test.tx_skb;229230mt7615_mcu_set_chan_info(phy, MCU_EXT_CMD(SET_RX_PATH));231mt7615_tm_set_tx_antenna(phy, en);232mt7615_tm_set_rx_enable(dev, !en);233if (!en || !skb)234return;235236info = IEEE80211_SKB_CB(skb);237info->control.vif = phy->monitor_vif;238}239240static void241mt7615_tm_update_params(struct mt7615_phy *phy, u32 changed)242{243struct mt7615_dev *dev = phy->dev;244struct mt76_testmode_data *td = &phy->mt76->test;245bool en = phy->mt76->test.state != MT76_TM_STATE_OFF;246247if (changed & BIT(TM_CHANGED_TXPOWER_CTRL))248mt7615_mcu_set_test_param(dev, MCU_ATE_SET_TX_POWER_CONTROL,249en, en && td->tx_power_control);250if (changed & BIT(TM_CHANGED_FREQ_OFFSET))251mt7615_mcu_set_test_param(dev, MCU_ATE_SET_FREQ_OFFSET,252en, en ? td->freq_offset : 0);253if (changed & BIT(TM_CHANGED_TXPOWER))254mt7615_tm_set_tx_power(phy);255}256257static int258mt7615_tm_set_state(struct mt76_phy *mphy, enum mt76_testmode_state state)259{260struct mt7615_phy *phy = mphy->priv;261struct mt76_testmode_data *td = &mphy->test;262enum mt76_testmode_state prev_state = td->state;263264mphy->test.state = state;265266if (prev_state == MT76_TM_STATE_TX_FRAMES)267mt7615_tm_set_tx_frames(phy, false);268else if (state == MT76_TM_STATE_TX_FRAMES)269mt7615_tm_set_tx_frames(phy, true);270271if (state <= MT76_TM_STATE_IDLE)272mt7615_tm_init(phy);273274if ((state == MT76_TM_STATE_IDLE &&275prev_state == MT76_TM_STATE_OFF) ||276(state == MT76_TM_STATE_OFF &&277prev_state == MT76_TM_STATE_IDLE)) {278u32 changed = 0;279int i;280281for (i = 0; i < ARRAY_SIZE(tm_change_map); i++) {282u16 cur = tm_change_map[i];283284if (td->param_set[cur / 32] & BIT(cur % 32))285changed |= BIT(i);286}287288mt7615_tm_update_params(phy, changed);289}290291return 0;292}293294static int295mt7615_tm_set_params(struct mt76_phy *mphy, struct nlattr **tb,296enum mt76_testmode_state new_state)297{298struct mt76_testmode_data *td = &mphy->test;299struct mt7615_phy *phy = mphy->priv;300u32 changed = 0;301int i;302303BUILD_BUG_ON(NUM_TM_CHANGED >= 32);304305if (new_state == MT76_TM_STATE_OFF ||306td->state == MT76_TM_STATE_OFF)307return 0;308309if (td->tx_antenna_mask & ~mphy->chainmask)310return -EINVAL;311312for (i = 0; i < ARRAY_SIZE(tm_change_map); i++) {313if (tb[tm_change_map[i]])314changed |= BIT(i);315}316317mt7615_tm_update_params(phy, changed);318319return 0;320}321322static int323mt7615_tm_dump_stats(struct mt76_phy *mphy, struct sk_buff *msg)324{325struct mt7615_phy *phy = mphy->priv;326void *rx, *rssi;327int i;328329rx = nla_nest_start(msg, MT76_TM_STATS_ATTR_LAST_RX);330if (!rx)331return -ENOMEM;332333if (nla_put_s32(msg, MT76_TM_RX_ATTR_FREQ_OFFSET, phy->test.last_freq_offset))334return -ENOMEM;335336rssi = nla_nest_start(msg, MT76_TM_RX_ATTR_RCPI);337if (!rssi)338return -ENOMEM;339340for (i = 0; i < ARRAY_SIZE(phy->test.last_rcpi); i++)341if (nla_put_u8(msg, i, phy->test.last_rcpi[i]))342return -ENOMEM;343344nla_nest_end(msg, rssi);345346rssi = nla_nest_start(msg, MT76_TM_RX_ATTR_IB_RSSI);347if (!rssi)348return -ENOMEM;349350for (i = 0; i < ARRAY_SIZE(phy->test.last_ib_rssi); i++)351if (nla_put_s8(msg, i, phy->test.last_ib_rssi[i]))352return -ENOMEM;353354nla_nest_end(msg, rssi);355356rssi = nla_nest_start(msg, MT76_TM_RX_ATTR_WB_RSSI);357if (!rssi)358return -ENOMEM;359360for (i = 0; i < ARRAY_SIZE(phy->test.last_wb_rssi); i++)361if (nla_put_s8(msg, i, phy->test.last_wb_rssi[i]))362return -ENOMEM;363364nla_nest_end(msg, rssi);365366nla_nest_end(msg, rx);367368return 0;369}370371const struct mt76_testmode_ops mt7615_testmode_ops = {372.set_state = mt7615_tm_set_state,373.set_params = mt7615_tm_set_params,374.dump_stats = mt7615_tm_dump_stats,375};376377378