blob: d965749956686d6a031e184eefe1f89f3583427e [file] [log] [blame]
developera72bbd82024-02-04 18:27:28 +08001From 14733d632430b788c7323b038bd679045a9dba95 Mon Sep 17 00:00:00 2001
developerdab699f2023-12-22 18:29:04 +08002From: Allen Ye <allen.ye@mediatek.com>
3Date: Fri, 15 Dec 2023 14:03:11 +0800
developera72bbd82024-02-04 18:27:28 +08004Subject: [PATCH 1047/1048] wifi: mt76: mt7915: Add support for lpi and
developerdab699f2023-12-22 18:29:04 +08005 duplicate mode
6
7Add support lpi and duplicate mode.
81. lpi_enable: lpi fw cmd and set psd flag to fw by the country setting.
92. txpower_dup: Add bandwidth duplicate mode for 6g band and change power
10value of beacon.
113. mgmt_pwr_enhence: Add mgmt frame power enhencement by fix 6g band
12bandwidth
134. support runtime change sku table by specify sku index (default will
14find the first match country).
153. Add parsing negative txpower stored unsigned in dts.
16
17Signed-off-by: Allen Ye <allen.ye@mediatek.com>
18---
19 eeprom.c | 15 +++++---
20 mt76.h | 5 ++-
21 mt76_connac2_mac.h | 7 ++++
22 mt76_connac_mac.c | 7 +++-
23 mt76_connac_mcu.h | 1 +
24 mt7915/debugfs.c | 3 +-
25 mt7915/init.c | 6 ++-
26 mt7915/mcu.c | 91 +++++++++++++++++++++++++++++++++++++++++---
27 mt7915/mt7915.h | 1 +
28 mt7915/mtk_debugfs.c | 1 +
29 mt7915/vendor.c | 75 ++++++++++++++++++++++++++++++++++++
30 mt7915/vendor.h | 15 ++++++++
31 12 files changed, 210 insertions(+), 17 deletions(-)
32
33diff --git a/eeprom.c b/eeprom.c
34index 4213e44..2ee262a 100644
35--- a/eeprom.c
36+++ b/eeprom.c
37@@ -224,8 +224,9 @@ static bool mt76_string_prop_find(struct property *prop, const char *str)
38 }
39
40 struct device_node *
41-mt76_find_power_limits_node(struct mt76_dev *dev)
42+mt76_find_power_limits_node(struct mt76_phy *phy)
43 {
44+ struct mt76_dev *dev = phy->dev;
45 struct device_node *np = dev->dev->of_node;
46 const char *const region_names[] = {
47 [NL80211_DFS_UNSET] = "ww",
48@@ -235,6 +236,7 @@ mt76_find_power_limits_node(struct mt76_dev *dev)
49 };
50 struct device_node *cur, *fallback = NULL;
51 const char *region_name = NULL;
52+ char index[4] = {0};
53
54 if (dev->region < ARRAY_SIZE(region_names))
55 region_name = region_names[dev->region];
56@@ -243,17 +245,20 @@ mt76_find_power_limits_node(struct mt76_dev *dev)
57 if (!np)
58 return NULL;
59
60+ snprintf(index, sizeof(index), "%d", phy->sku_idx);
61 for_each_child_of_node(np, cur) {
62 struct property *country = of_find_property(cur, "country", NULL);
63 struct property *regd = of_find_property(cur, "regdomain", NULL);
64+ struct property *sku_index = of_find_property(cur, "sku-index", NULL);
65
66 if (!country && !regd) {
67 fallback = cur;
68 continue;
69 }
70
71- if (mt76_string_prop_find(country, dev->alpha2) ||
72- mt76_string_prop_find(regd, region_name)) {
73+ if ((mt76_string_prop_find(country, dev->alpha2) ||
74+ mt76_string_prop_find(regd, region_name)) &&
75+ (!phy->sku_idx || mt76_string_prop_find(sku_index, index))) {
76 of_node_put(np);
77 return cur;
78 }
79@@ -328,7 +333,7 @@ mt76_apply_array_limit(s8 *pwr, size_t pwr_len, const __be32 *data,
80
81 for (i = 0; i < pwr_len; i++) {
82 pwr[i] = min_t(s8, target_power,
83- be32_to_cpu(data[i]) + nss_delta);
84+ (s8)be32_to_cpu(data[i]) + nss_delta);
85 *max_power = max(*max_power, pwr[i]);
86 }
87 }
88@@ -392,7 +397,7 @@ s8 mt76_get_rate_power_limits(struct mt76_phy *phy,
89 if (!IS_ENABLED(CONFIG_OF))
90 return target_power;
91
92- np = mt76_find_power_limits_node(dev);
93+ np = mt76_find_power_limits_node(phy);
94 if (!np)
95 return target_power;
96
97diff --git a/mt76.h b/mt76.h
developera72bbd82024-02-04 18:27:28 +080098index 1aa266f..4291acd 100644
developerdab699f2023-12-22 18:29:04 +080099--- a/mt76.h
100+++ b/mt76.h
developera72bbd82024-02-04 18:27:28 +0800101@@ -852,6 +852,9 @@ struct mt76_phy {
developerdab699f2023-12-22 18:29:04 +0800102 u8 macaddr[ETH_ALEN];
103
104 int txpower_cur;
105+ u8 beacon_dup;
106+ u8 mgmt_pwr_enhance;
107+ u8 sku_idx;
108 u8 antenna_mask;
109 u16 chainmask;
110
developera72bbd82024-02-04 18:27:28 +0800111@@ -1740,7 +1743,7 @@ mt76_mcu_skb_send_msg(struct mt76_dev *dev, struct sk_buff *skb, int cmd,
developerdab699f2023-12-22 18:29:04 +0800112 void mt76_set_irq_mask(struct mt76_dev *dev, u32 addr, u32 clear, u32 set);
113
114 struct device_node *
115-mt76_find_power_limits_node(struct mt76_dev *dev);
116+mt76_find_power_limits_node(struct mt76_phy *phy);
117 struct device_node *
118 mt76_find_channel_node(struct device_node *np, struct ieee80211_channel *chan);
119
120diff --git a/mt76_connac2_mac.h b/mt76_connac2_mac.h
121index 5f13211..c49a330 100644
122--- a/mt76_connac2_mac.h
123+++ b/mt76_connac2_mac.h
124@@ -355,4 +355,11 @@ enum tx_port_idx {
125 MT_TX_PORT_IDX_MCU
126 };
127
128+enum tx_bw_idx {
129+ MT_TX_BW_IDX_20,
130+ MT_TX_BW_IDX_40,
131+ MT_TX_BW_IDX_80,
132+ MT_TX_BW_IDX_160,
133+};
134+
135 #endif /* __MT76_CONNAC2_MAC_H */
136diff --git a/mt76_connac_mac.c b/mt76_connac_mac.c
developera72bbd82024-02-04 18:27:28 +0800137index d036047..d41f004 100644
developerdab699f2023-12-22 18:29:04 +0800138--- a/mt76_connac_mac.c
139+++ b/mt76_connac_mac.c
140@@ -564,7 +564,8 @@ void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi,
141 u16 rate = mt76_connac2_mac_tx_rate_val(mphy, vif, beacon,
142 multicast);
143 u32 val = MT_TXD6_FIXED_BW;
144-
145+ if (dev->phys[band_idx]->beacon_dup)
146+ val |= MT_TX_BW_IDX_80;
147 /* hardware won't add HTC for mgmt/ctrl frame */
148 txwi[2] |= cpu_to_le32(MT_TXD2_HTC_VLD);
149
150@@ -577,7 +578,9 @@ void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi,
151
152 if (!spe_idx)
153 spe_idx = 24 + phy_idx;
154- txwi[7] |= cpu_to_le32(FIELD_PREP(MT_TXD7_SPE_IDX, spe_idx));
155+ txwi[7] |= cpu_to_le32(FIELD_PREP(MT_TXD7_SPE_IDX,
156+ dev->phys[band_idx]->mgmt_pwr_enhance ?
157+ 0 : spe_idx));
158 }
159
160 txwi[7] &= ~cpu_to_le32(MT_TXD7_HW_AMSDU);
161diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
developera72bbd82024-02-04 18:27:28 +0800162index 4e1006d..e581084 100644
developerdab699f2023-12-22 18:29:04 +0800163--- a/mt76_connac_mcu.h
164+++ b/mt76_connac_mcu.h
developera72bbd82024-02-04 18:27:28 +0800165@@ -1249,6 +1249,7 @@ enum {
developerdab699f2023-12-22 18:29:04 +0800166 MCU_EXT_CMD_SWLNA_ACI_CTRL = 0xc0,
167 MCU_EXT_CMD_CSI_CTRL = 0xc2,
168 MCU_EXT_CMD_IPI_HIST_SCAN = 0xc5,
169+ MCU_EXT_CMD_LPI_CTRL = 0xc8,
170 };
171
172 enum {
173diff --git a/mt7915/debugfs.c b/mt7915/debugfs.c
developera72bbd82024-02-04 18:27:28 +0800174index ead0f98..017d43d 100644
developerdab699f2023-12-22 18:29:04 +0800175--- a/mt7915/debugfs.c
176+++ b/mt7915/debugfs.c
177@@ -1296,7 +1296,6 @@ mt7915_txpower_info_show(struct seq_file *file, void *data)
178 {
179 struct mt7915_phy *phy = file->private;
180 struct mt76_phy *mphy = phy->mt76;
181- struct mt76_dev *dev = mphy->dev;
182 struct {
183 u8 category;
184 u8 rsv1;
185@@ -1373,7 +1372,7 @@ mt7915_txpower_info_show(struct seq_file *file, void *data)
186 seq_printf(file, " Theraml Compensation Value: %d\n",
187 basic_info.thermal_compensate_value);
188
189- np = mt76_find_power_limits_node(dev);
190+ np = mt76_find_power_limits_node(mphy);
191 seq_printf(file, " RegDB: %s\n", !np ? "enable" : "disable");
192
193 out:
194diff --git a/mt7915/init.c b/mt7915/init.c
developera72bbd82024-02-04 18:27:28 +0800195index 1a41282..32bbd6c 100644
developerdab699f2023-12-22 18:29:04 +0800196--- a/mt7915/init.c
197+++ b/mt7915/init.c
198@@ -287,7 +287,7 @@ static void __mt7915_init_txpower(struct mt7915_phy *phy,
199
200 phy->sku_limit_en = true;
201 phy->sku_path_en = true;
202- np = mt76_find_power_limits_node(&dev->mt76);
203+ np = mt76_find_power_limits_node(phy->mt76);
204 for (i = 0; i < sband->n_channels; i++) {
205 struct ieee80211_channel *chan = &sband->channels[i];
206 u32 target_power = 0;
207@@ -331,8 +331,10 @@ void mt7915_init_txpower(struct mt7915_phy *phy)
208 __mt7915_init_txpower(phy, &phy->mt76->sband_2g.sband);
209 if (phy->mt76->cap.has_5ghz)
210 __mt7915_init_txpower(phy, &phy->mt76->sband_5g.sband);
211- if (phy->mt76->cap.has_6ghz)
212+ if (phy->mt76->cap.has_6ghz) {
213 __mt7915_init_txpower(phy, &phy->mt76->sband_6g.sband);
214+ phy->mt76->beacon_dup = 1;
215+ }
216 }
217
218 static void
219diff --git a/mt7915/mcu.c b/mt7915/mcu.c
developera72bbd82024-02-04 18:27:28 +0800220index 7e0e277..ba47d0d 100644
developerdab699f2023-12-22 18:29:04 +0800221--- a/mt7915/mcu.c
222+++ b/mt7915/mcu.c
developera72bbd82024-02-04 18:27:28 +0800223@@ -1522,7 +1522,8 @@ mt7915_mcu_set_spe_idx(struct mt7915_dev *dev, struct ieee80211_vif *vif,
developerdab699f2023-12-22 18:29:04 +0800224 {
225 struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
226 struct mt76_phy *mphy = mvif->phy->mt76;
227- u8 spe_idx = mt76_connac_spe_idx(mphy->antenna_mask);
228+ u8 spe_idx = mphy->mgmt_pwr_enhance ?
229+ 0 : mt76_connac_spe_idx(mphy->antenna_mask);
230
231 return mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, &spe_idx,
232 RATE_PARAM_SPE_UPDATE);
developera72bbd82024-02-04 18:27:28 +0800233@@ -3488,6 +3489,22 @@ mt7915_update_txpower(struct mt7915_phy *phy, int tx_power)
developerdab699f2023-12-22 18:29:04 +0800234 mphy->txpower_cur = e2p_power_limit;
235 }
236
237+int mt7915_get_psd_country(char *country)
238+{
239+ char country_list[][3] = {"US", "KR", "BR", "CL", "MY", ""};
240+ int i;
241+
242+ if (strlen(country) != 2)
243+ return 0;
244+
245+ for (i = 0; country_list[i][0] != '\0'; i++) {
246+ if (!strncmp(country, country_list[i], 2))
247+ return 1;
248+ }
249+
250+ return 0;
251+}
252+
253 int mt7915_mcu_set_txpower_sku(struct mt7915_phy *phy)
254 {
255 #define TX_POWER_LIMIT_TABLE_RATE 0
developera72bbd82024-02-04 18:27:28 +0800256@@ -3519,14 +3536,37 @@ int mt7915_mcu_set_txpower_sku(struct mt7915_phy *phy)
developerdab699f2023-12-22 18:29:04 +0800257 mt7915_update_txpower(phy, tx_power);
258 return 0;
259 }
260-
261 skb = mt76_mcu_msg_alloc(&dev->mt76, NULL,
262 sizeof(hdr) + MT7915_SKU_RATE_NUM);
263 if (!skb)
264 return -ENOMEM;
265
266 skb_put_data(skb, &hdr, sizeof(hdr));
267- skb_put_data(skb, &la.cck, len[SKU_CCK] + len[SKU_OFDM]);
268+ skb_put_data(skb, &la.cck, len[SKU_CCK]);
269+
270+ if (phy->mt76->cap.has_6ghz && mphy->beacon_dup &&
271+ !mt7915_get_psd_country(dev->mt76.alpha2)) {
272+ switch (mphy->chandef.width) {
273+ case NL80211_CHAN_WIDTH_20:
274+ skb_put_data(skb, &la.mcs[0], len[SKU_OFDM]);
275+ break;
276+ case NL80211_CHAN_WIDTH_40:
277+ skb_put_data(skb, &la.mcs[1], len[SKU_OFDM]);
278+ break;
279+ case NL80211_CHAN_WIDTH_80:
280+ skb_put_data(skb, &la.mcs[2], len[SKU_OFDM]);
281+ break;
282+ case NL80211_CHAN_WIDTH_160:
283+ skb_put_data(skb, &la.mcs[3], len[SKU_OFDM]);
284+ break;
285+ default:
286+ skb_put_data(skb, &la.ofdm, len[SKU_OFDM]);
287+ break;
288+ }
289+ } else {
290+ skb_put_data(skb, &la.ofdm, len[SKU_OFDM]);
291+ }
292+
293 skb_put_data(skb, &la.mcs[0], len[SKU_HT_BW20]);
294 skb_put_data(skb, &la.mcs[1], len[SKU_HT_BW40]);
295
developera72bbd82024-02-04 18:27:28 +0800296@@ -3556,8 +3596,34 @@ int mt7915_mcu_set_txpower_sku(struct mt7915_phy *phy)
developerdab699f2023-12-22 18:29:04 +0800297 hdr.limit_type = TX_POWER_LIMIT_TABLE_PATH;
298 skb_put_data(skb, &hdr, sizeof(hdr));
299 skb_put_data(skb, &la.path.cck, sizeof(la.path.cck));
300- skb_put_data(skb, &la.path.ofdm, sizeof(la.path.ofdm));
301- skb_put_data(skb, &la.path.ofdm_bf[1], sizeof(la.path.ofdm_bf) - 1);
302+
303+ if (phy->mt76->cap.has_6ghz && mphy->beacon_dup) {
304+ switch (mphy->chandef.width) {
305+ case NL80211_CHAN_WIDTH_20:
306+ skb_put_data(skb, &la.path.ru[3], sizeof(la.path.ofdm));
307+ skb_put_data(skb, &la.path.ru_bf[3][1], sizeof(la.path.ofdm_bf) - 1);
308+ break;
309+ case NL80211_CHAN_WIDTH_40:
310+ skb_put_data(skb, &la.path.ru[4], sizeof(la.path.ofdm));
311+ skb_put_data(skb, &la.path.ru_bf[4][1], sizeof(la.path.ofdm_bf) - 1);
312+ break;
313+ case NL80211_CHAN_WIDTH_80:
314+ skb_put_data(skb, &la.path.ru[5], sizeof(la.path.ofdm));
315+ skb_put_data(skb, &la.path.ru_bf[5][1], sizeof(la.path.ofdm_bf) - 1);
316+ break;
317+ case NL80211_CHAN_WIDTH_160:
318+ skb_put_data(skb, &la.path.ru[6], sizeof(la.path.ofdm));
319+ skb_put_data(skb, &la.path.ru_bf[6][1], sizeof(la.path.ofdm_bf) - 1);
320+ break;
321+ default:
322+ skb_put_data(skb, &la.path.ofdm, sizeof(la.path.ofdm));
323+ skb_put_data(skb, &la.path.ofdm_bf[1], sizeof(la.path.ofdm_bf) - 1);
324+ break;
325+ }
326+ } else {
327+ skb_put_data(skb, &la.path.ofdm, sizeof(la.path.ofdm));
328+ skb_put_data(skb, &la.path.ofdm_bf[1], sizeof(la.path.ofdm_bf) - 1);
329+ }
330
331 /* HT20 and HT40 */
332 skb_put_data(skb, &la.path.ru[3], sizeof(la.path.ru[3]));
developera72bbd82024-02-04 18:27:28 +0800333@@ -3633,6 +3699,21 @@ int mt7915_mcu_get_txpower_sku(struct mt7915_phy *phy, s8 *txpower, int len,
developerdab699f2023-12-22 18:29:04 +0800334 return 0;
335 }
336
337+int mt7915_mcu_set_lpi(struct mt7915_phy *phy, bool en)
338+{
339+ struct mt76_dev *mdev = &(phy->dev->mt76);
340+ struct {
341+ u8 enable;
342+ u8 psd_limit;
343+ u8 _rsv[2];
344+ } __packed req = {
345+ .enable = en,
346+ .psd_limit = en ? mt7915_get_psd_country(mdev->alpha2) : 0,
347+ };
348+ return mt76_mcu_send_msg(mdev, MCU_EXT_CMD(LPI_CTRL), &req,
349+ sizeof(req), false);
350+}
351+
352 int mt7915_mcu_set_test_param(struct mt7915_dev *dev, u8 param, bool test_mode,
353 u8 en)
354 {
355diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
developera72bbd82024-02-04 18:27:28 +0800356index 38a9db4..23ee118 100644
developerdab699f2023-12-22 18:29:04 +0800357--- a/mt7915/mt7915.h
358+++ b/mt7915/mt7915.h
developera72bbd82024-02-04 18:27:28 +0800359@@ -793,6 +793,7 @@ int mt7915_mcu_set_csi(struct mt7915_phy *phy, u8 mode,
developerdab699f2023-12-22 18:29:04 +0800360 void mt7915_vendor_amnt_fill_rx(struct mt7915_phy *phy, struct sk_buff *skb);
361 int mt7915_vendor_amnt_sta_remove(struct mt7915_phy *phy,
362 struct ieee80211_sta *sta);
363+int mt7915_mcu_set_lpi(struct mt7915_phy *phy, bool en);
364 #endif
365 int mt7915_mcu_set_edcca(struct mt7915_phy *phy, int mode, u8 *value, s8 compensation);
366 int mt7915_mcu_get_edcca(struct mt7915_phy *phy, u8 mode, s8 *value);
367diff --git a/mt7915/mtk_debugfs.c b/mt7915/mtk_debugfs.c
368index 9da6328..50e7b6c 100644
369--- a/mt7915/mtk_debugfs.c
370+++ b/mt7915/mtk_debugfs.c
371@@ -3922,6 +3922,7 @@ int mt7915_mtk_init_debugfs(struct mt7915_phy *phy, struct dentry *dir)
372 &fops_txbf_sta_rec);
373
374 debugfs_create_u8("sku_disable", 0600, dir, &dev->dbg.sku_disable);
375+ debugfs_create_u8("mgmt_pwr_enhance", 0600, dir, &phy->mt76->mgmt_pwr_enhance);
376
377 debugfs_create_devm_seqfile(dev->mt76.dev, "eeprom_mode", dir,
378 mt7915_show_eeprom_mode);
379diff --git a/mt7915/vendor.c b/mt7915/vendor.c
380index 432d750..566fec0 100644
381--- a/mt7915/vendor.c
382+++ b/mt7915/vendor.c
383@@ -106,6 +106,13 @@ bss_color_ctrl_policy[NUM_MTK_VENDOR_ATTRS_BSS_COLOR_CTRL] = {
384 [MTK_VENDOR_ATTR_AVAL_BSS_COLOR_BMP] = { .type = NLA_U64 },
385 };
386
387+static struct nla_policy
388+txpower_ctrl_policy[NUM_MTK_VENDOR_ATTRS_TXPOWER_CTRL] = {
389+ [MTK_VENDOR_ATTR_TXPOWER_CTRL_LPI_ENABLE] = { .type = NLA_U8 },
390+ [MTK_VENDOR_ATTR_TXPOWER_CTRL_SKU_IDX] = { .type = NLA_U8 },
391+ [MTK_VENDOR_ATTR_TXPOWER_CTRL_BCN_DUP] = { .type = NLA_U8 },
392+};
393+
394 struct csi_null_tone {
395 u8 start;
396 u8 end;
397@@ -1335,6 +1342,63 @@ mt7915_vendor_bss_color_ctrl_dump(struct wiphy *wiphy, struct wireless_dev *wdev
398 return len;
399 }
400
401+static int mt7915_vendor_txpower_ctrl(struct wiphy *wiphy,
402+ struct wireless_dev *wdev,
403+ const void *data,
404+ int data_len)
405+{
406+ struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
407+ struct mt7915_phy *phy = mt7915_hw_phy(hw);
408+ struct mt76_phy *mphy = phy->mt76;
409+ struct nlattr *tb[NUM_MTK_VENDOR_ATTRS_TXPOWER_CTRL];
410+ struct mt76_power_limits limits;
411+ int err;
412+ u8 val;
413+
414+ err = nla_parse(tb, MTK_VENDOR_ATTR_TXPOWER_CTRL_MAX, data, data_len,
415+ txpower_ctrl_policy, NULL);
416+ if (err)
417+ return err;
418+
419+ if (tb[MTK_VENDOR_ATTR_TXPOWER_CTRL_LPI_ENABLE]) {
420+ val = nla_get_u8(tb[MTK_VENDOR_ATTR_TXPOWER_CTRL_LPI_ENABLE]);
421+
422+ if (mphy->cap.has_6ghz) {
423+ err = mt7915_mcu_set_lpi(phy, val);
424+ if (err)
425+ return err;
426+ }
427+ }
428+
429+ if (tb[MTK_VENDOR_ATTR_TXPOWER_CTRL_SKU_IDX]) {
430+ mphy->sku_idx = nla_get_u8(tb[MTK_VENDOR_ATTR_TXPOWER_CTRL_SKU_IDX]);
431+
432+ if (mt76_find_power_limits_node(mphy) == NULL)
433+ mphy->sku_idx = 0;
434+
435+ phy->sku_path_en = true;
436+ mt76_get_rate_power_limits(mphy, mphy->chandef.chan, &limits, 127);
437+ if (!limits.path.ofdm[0])
438+ phy->sku_path_en = false;
439+
440+ err = mt7915_mcu_set_sku_en(phy);
441+ if (err)
442+ return err;
443+ }
444+
445+ if (tb[MTK_VENDOR_ATTR_TXPOWER_CTRL_BCN_DUP]) {
446+ val = nla_get_u8(tb[MTK_VENDOR_ATTR_TXPOWER_CTRL_BCN_DUP]);
447+ if (mphy->cap.has_6ghz)
448+ mphy->beacon_dup = val;
449+ }
450+
451+ err = mt7915_mcu_set_txpower_sku(phy);
452+ if (err)
453+ return err;
454+
455+ return 0;
456+}
457+
458 static const struct wiphy_vendor_command mt7915_vendor_commands[] = {
459 {
460 .info = {
461@@ -1451,6 +1515,17 @@ static const struct wiphy_vendor_command mt7915_vendor_commands[] = {
462 .dumpit = mt7915_vendor_bss_color_ctrl_dump,
463 .policy = bss_color_ctrl_policy,
464 .maxattr = MTK_VENDOR_ATTR_BSS_COLOR_CTRL_MAX,
465+ },
466+ {
467+ .info = {
468+ .vendor_id = MTK_NL80211_VENDOR_ID,
469+ .subcmd = MTK_NL80211_VENDOR_SUBCMD_TXPOWER_CTRL,
470+ },
471+ .flags = WIPHY_VENDOR_CMD_NEED_NETDEV |
472+ WIPHY_VENDOR_CMD_NEED_RUNNING,
473+ .doit = mt7915_vendor_txpower_ctrl,
474+ .policy = txpower_ctrl_policy,
475+ .maxattr = MTK_VENDOR_ATTR_TXPOWER_CTRL_MAX,
476 }
477 };
478
479diff --git a/mt7915/vendor.h b/mt7915/vendor.h
480index 03d1660..5b8a1fb 100644
481--- a/mt7915/vendor.h
482+++ b/mt7915/vendor.h
483@@ -16,6 +16,7 @@ enum mtk_nl80211_vendor_subcmds {
484 MTK_NL80211_VENDOR_SUBCMD_3WIRE_CTRL = 0xc8,
485 MTK_NL80211_VENDOR_SUBCMD_IBF_CTRL = 0xc9,
486 MTK_NL80211_VENDOR_SUBCMD_BSS_COLOR_CTRL = 0xca,
487+ MTK_NL80211_VENDOR_SUBCMD_TXPOWER_CTRL = 0xce,
488 };
489
490
491@@ -274,4 +275,18 @@ enum mtk_vendor_attr_bss_color_ctrl {
492 MTK_VENDOR_ATTR_BSS_COLOR_CTRL_MAX =
493 NUM_MTK_VENDOR_ATTRS_BSS_COLOR_CTRL - 1
494 };
495+
496+enum mtk_vendor_attr_txpower_ctrl {
497+ MTK_VENDOR_ATTR_TXPOWER_CTRL_UNSPEC,
498+
499+ MTK_VENDOR_ATTR_TXPOWER_CTRL_LPI_ENABLE,
500+ MTK_VENDOR_ATTR_TXPOWER_CTRL_SKU_IDX,
501+ MTK_VENDOR_ATTR_TXPOWER_CTRL_BCN_DUP,
502+
503+ /* keep last */
504+ NUM_MTK_VENDOR_ATTRS_TXPOWER_CTRL,
505+ MTK_VENDOR_ATTR_TXPOWER_CTRL_MAX =
506+ NUM_MTK_VENDOR_ATTRS_TXPOWER_CTRL - 1
507+};
508+
509 #endif
510--
5112.18.0
512