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