diff options
Diffstat (limited to 'drivers/net/wireless/mediatek/mt76/mt7915/mcu.c')
-rw-r--r-- | drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 94 |
1 files changed, 88 insertions, 6 deletions
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index f27071f1b777..ed20ffc58877 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -3105,6 +3105,88 @@ out: &req, sizeof(req), false); } +int mt7915_mcu_set_txpower_frame_min(struct mt7915_phy *phy, s8 txpower) +{ + struct mt7915_dev *dev = phy->dev; + struct { + u8 format_id; + u8 rsv; + u8 band_idx; + s8 txpower_min; + } __packed req = { + .format_id = TX_POWER_LIMIT_FRAME_MIN, + .band_idx = phy->band_idx, + .txpower_min = txpower * 2, /* 0.5db */ + }; + + return mt76_mcu_send_msg(&dev->mt76, + MCU_EXT_CMD(TX_POWER_FEATURE_CTRL), &req, + sizeof(req), true); +} + +int mt7915_mcu_set_txpower_frame(struct mt7915_phy *phy, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, s8 txpower) +{ + struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; + struct mt7915_dev *dev = phy->dev; + struct mt76_phy *mphy = phy->mt76; + struct { + u8 format_id; + u8 rsv[3]; + u8 band_idx; + s8 txpower_max; + __le16 wcid; + s8 txpower_offs[48]; + } __packed req = { + .format_id = TX_POWER_LIMIT_FRAME, + .band_idx = phy->band_idx, + .txpower_max = DIV_ROUND_UP(mphy->txpower_cur, 2), + .wcid = cpu_to_le16(msta->wcid.idx), + }; + int ret, n_chains = hweight8(mphy->antenna_mask); + s8 txpower_sku[MT7915_SKU_RATE_NUM]; + + ret = mt7915_mcu_get_txpower_sku(phy, txpower_sku, sizeof(txpower_sku)); + if (ret) + return ret; + + txpower = txpower * 2 - mt76_tx_power_nss_delta(n_chains); + if (txpower > mphy->txpower_cur || txpower < 0) + return -EINVAL; + + if (txpower) { + u32 offs, len, i; + + if (sta->deflink.ht_cap.ht_supported) { + const u8 *sku_len = mt7915_sku_group_len; + + offs = sku_len[SKU_CCK] + sku_len[SKU_OFDM]; + len = sku_len[SKU_HT_BW20] + sku_len[SKU_HT_BW40]; + + if (sta->deflink.vht_cap.vht_supported) { + offs += len; + len = sku_len[SKU_VHT_BW20] * 4; + + if (sta->deflink.he_cap.has_he) { + offs += len + sku_len[SKU_HE_RU26] * 3; + len = sku_len[SKU_HE_RU242] * 4; + } + } + } else { + return -EINVAL; + } + + for (i = 0; i < len; i++, offs++) + req.txpower_offs[i] = + DIV_ROUND_UP(txpower - txpower_sku[offs], 2); + } + + return mt76_mcu_send_msg(&dev->mt76, + MCU_EXT_CMD(TX_POWER_FEATURE_CTRL), &req, + sizeof(req), true); +} + int mt7915_mcu_set_txpower_sku(struct mt7915_phy *phy) { struct mt7915_dev *dev = phy->dev; @@ -3116,7 +3198,7 @@ int mt7915_mcu_set_txpower_sku(struct mt7915_phy *phy) u8 dbdc_idx; s8 val[MT7915_SKU_RATE_NUM]; } __packed req = { - .format_id = 4, + .format_id = TX_POWER_LIMIT_TABLE, .dbdc_idx = phy != &dev->phy, }; struct mt76_power_limits limits_array; @@ -3166,11 +3248,11 @@ int mt7915_mcu_get_txpower_sku(struct mt7915_phy *phy, s8 *txpower, int len) u8 band; u8 _rsv; } __packed req = { - .format_id = 7, + .format_id = TX_POWER_LIMIT_INFO, .category = RATE_POWER_INFO, .band = phy != &dev->phy, }; - s8 res[MT7915_SKU_RATE_NUM][2]; + s8 txpower_sku[MT7915_SKU_RATE_NUM][2]; struct sk_buff *skb; int ret, i; @@ -3180,9 +3262,9 @@ int mt7915_mcu_get_txpower_sku(struct mt7915_phy *phy, s8 *txpower, int len) if (ret) return ret; - memcpy(res, skb->data + 4, sizeof(res)); + memcpy(txpower_sku, skb->data + 4, sizeof(txpower_sku)); for (i = 0; i < len; i++) - txpower[i] = res[i][req.band]; + txpower[i] = txpower_sku[i][req.band_idx]; dev_kfree_skb(skb); @@ -3220,7 +3302,7 @@ int mt7915_mcu_set_sku_en(struct mt7915_phy *phy, bool enable) u8 dbdc_idx; u8 rsv; } __packed req = { - .format_id = 0, + .format_id = TX_POWER_LIMIT_ENABLE, .dbdc_idx = phy != &dev->phy, .sku_enable = enable, }; |