blob: fc0ff2ec951b83da87c61f81dd9b2c22fc65f5c0 [file] [log] [blame]
developer9237f442024-06-14 17:13:04 +08001From 822d3687ba4c131b1850a06116ee39e5ebc3767c Mon Sep 17 00:00:00 2001
developer66e89bc2024-04-23 14:50:01 +08002From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
3Date: Thu, 6 Apr 2023 16:40:28 +0800
developer9237f442024-06-14 17:13:04 +08004Subject: [PATCH 045/116] mtk: wifi: mt76: testmode: add testmode bf support
developer66e89bc2024-04-23 14:50:01 +08005
6Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
7
8Add iTest additional bf command
9
10Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
11
12fw return Gx (5g band) ibf cal struct for both 2G and 5G ibf.
13Therefore, memcpy cannot be used for 2G ibf cal.
14https://gerrit.mediatek.inc/c/neptune/wlan_driver/logan/+/8206056
15
16Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
17
18mtk: wifi: mt76: testmode: add testmode ibf ver2 support
19
20Add ibf ver2 support for chips after Kite
21
22Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
23
24mtk: wifi: mt76: testmode: add testmode ibf 5T5R support
25
26Add testmode ibf 5T5R support for Kite BE7200 2i5i
27
28Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
29---
30 mt76.h | 5 +
31 mt76_connac_mcu.h | 4 +-
32 mt7996/mcu.c | 8 +-
33 mt7996/mcu.h | 46 ++-
34 mt7996/mt7996.h | 12 +-
35 mt7996/mtk_debugfs.c | 6 +-
36 mt7996/mtk_mcu.c | 143 +++++++-
37 mt7996/mtk_mcu.h | 441 +++++++++++++++++++++++-
38 mt7996/regs.h | 3 +
39 mt7996/testmode.c | 796 +++++++++++++++++++++++++++++++++++++++++--
40 mt7996/testmode.h | 19 ++
41 testmode.c | 62 ++++
42 testmode.h | 53 +++
43 tools/fields.c | 37 ++
44 14 files changed, 1576 insertions(+), 59 deletions(-)
45
46diff --git a/mt76.h b/mt76.h
developer9237f442024-06-14 17:13:04 +080047index 0cc6e53..8b17dfb 100644
developer66e89bc2024-04-23 14:50:01 +080048--- a/mt76.h
49+++ b/mt76.h
50@@ -757,6 +757,11 @@ struct mt76_testmode_data {
51 u32 tx_time;
52 u32 tx_ipg;
53
54+ u8 txbf_act;
55+ u16 txbf_param[8];
56+ bool is_txbf_dut;
57+ bool bf_en;
58+ bool bf_ever_en;
59 bool ibf;
60 bool ebf;
61
62diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
developer9237f442024-06-14 17:13:04 +080063index 7f2daf7..61a14a8 100644
developer66e89bc2024-04-23 14:50:01 +080064--- a/mt76_connac_mcu.h
65+++ b/mt76_connac_mcu.h
66@@ -488,7 +488,8 @@ struct sta_rec_bf {
67 bool codebook75_mu;
68
69 u8 he_ltf;
70- u8 rsv[3];
71+ u8 pp_fd_val;
72+ u8 rsv[2];
73 } __packed;
74
75 struct sta_rec_bfee {
developer9237f442024-06-14 17:13:04 +080076@@ -1281,6 +1282,7 @@ enum {
developer66e89bc2024-04-23 14:50:01 +080077 MCU_UNI_CMD_VOW = 0x37,
78 MCU_UNI_CMD_PP = 0x38,
79 MCU_UNI_CMD_FIXED_RATE_TABLE = 0x40,
80+ MCU_UNI_CMD_TESTMODE_TRX_PARAM = 0x42,
81 MCU_UNI_CMD_TESTMODE_CTRL = 0x46,
82 MCU_UNI_CMD_PRECAL_RESULT = 0x47,
83 MCU_UNI_CMD_RRO = 0x57,
84diff --git a/mt7996/mcu.c b/mt7996/mcu.c
developer9237f442024-06-14 17:13:04 +080085index 423d918..18d8f4d 100644
developer66e89bc2024-04-23 14:50:01 +080086--- a/mt7996/mcu.c
87+++ b/mt7996/mcu.c
88@@ -1073,7 +1073,12 @@ mt7996_mcu_bss_basic_tlv(struct sk_buff *skb,
89 bss->hw_bss_idx = idx;
90
91 if (vif->type == NL80211_IFTYPE_MONITOR) {
92- memcpy(bss->bssid, phy->macaddr, ETH_ALEN);
93+ struct mt76_testmode_data *td = &phy->test;
94+
95+ if (!td->bf_en)
96+ memcpy(bss->bssid, phy->macaddr, ETH_ALEN);
97+ else
98+ memcpy(bss->bssid, td->addr[2], ETH_ALEN);
99 return 0;
100 }
101
102@@ -4097,7 +4102,6 @@ int mt7996_mcu_set_ser(struct mt7996_dev *dev, u8 action, u8 val, u8 band)
103 int mt7996_mcu_set_txbf(struct mt7996_dev *dev, u8 action)
104 {
105 #define MT7996_BF_MAX_SIZE sizeof(union bf_tag_tlv)
106-#define BF_PROCESSING 4
107 struct uni_header hdr;
108 struct sk_buff *skb;
109 struct tlv *tlv;
110diff --git a/mt7996/mcu.h b/mt7996/mcu.h
developer9237f442024-06-14 17:13:04 +0800111index 8061638..6631281 100644
developer66e89bc2024-04-23 14:50:01 +0800112--- a/mt7996/mcu.h
113+++ b/mt7996/mcu.h
114@@ -685,6 +685,22 @@ struct bf_sounding_on {
115 __le32 snd_period;
116 } __packed;
117
118+enum sounding_mode {
119+ SU_SOUNDING,
120+ MU_SOUNDING,
121+ SU_PERIODIC_SOUNDING,
122+ MU_PERIODIC_SOUNDING,
123+ BF_PROCESSING,
124+ TXCMD_NONTB_SU_SOUNDING,
125+ TXCMD_VHT_MU_SOUNDING,
126+ TXCMD_TB_PER_BRP_SOUNDING,
127+ TXCMD_TB_SOUNDING,
128+
129+ /* keep last */
130+ NUM_SOUNDING_MODE,
131+ SOUNDING_MODE_MAX = NUM_SOUNDING_MODE - 1,
132+};
133+
134 struct bf_hw_en_status_update {
135 __le16 tag;
136 __le16 len;
137@@ -710,6 +726,25 @@ union bf_tag_tlv {
138 struct bf_mod_en_ctrl bf_mod_en;
139 };
140
141+enum {
142+ BF_SOUNDING_OFF = 0,
143+ BF_SOUNDING_ON = 1,
144+ BF_DATA_PACKET_APPLY = 2,
145+ BF_PFMU_TAG_READ = 5,
146+ BF_PFMU_TAG_WRITE = 6,
147+ BF_STA_REC_READ = 11,
148+ BF_PHASE_CALIBRATION = 12,
149+ BF_IBF_PHASE_COMP = 13,
150+ BF_PROFILE_WRITE_20M_ALL = 15,
151+ BF_HW_EN_UPDATE = 17,
152+ BF_MOD_EN_CTRL = 20,
153+ BF_FBRPT_DBG_INFO_READ = 23,
154+ BF_TXSND_INFO = 24,
155+ BF_CMD_TXCMD = 27,
156+ BF_CFG_PHY = 28,
157+ BF_PROFILE_WRITE_20M_ALL_5X5 = 30,
158+};
159+
160 struct ra_rate {
161 __le16 wlan_idx;
162 u8 mode;
163@@ -771,17 +806,6 @@ enum {
164 #define MUMIMO_UL BIT(3)
165 #define MUMIMO_DL_CERT BIT(4)
166
167-enum {
168- BF_SOUNDING_ON = 1,
169- BF_PFMU_TAG_READ = 5,
170- BF_STA_REC_READ = 11,
171- BF_HW_EN_UPDATE = 17,
172- BF_MOD_EN_CTRL = 20,
173- BF_FBRPT_DBG_INFO_READ = 23,
174- BF_TXSND_INFO = 24,
175- BF_CFG_PHY = 28,
176-};
177-
178 enum {
179 CMD_BAND_NONE,
180 CMD_BAND_24G,
181diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
developer9237f442024-06-14 17:13:04 +0800182index 30ceb00..84fbd0f 100644
developer66e89bc2024-04-23 14:50:01 +0800183--- a/mt7996/mt7996.h
184+++ b/mt7996/mt7996.h
185@@ -486,6 +486,14 @@ struct mt7996_dev {
186 #ifdef CONFIG_MTK_VENDOR
187 bool cert_mode;
188 #endif
189+
190+#if defined CONFIG_NL80211_TESTMODE || defined CONFIG_MTK_DEBUG
191+ struct {
192+ void *txbf_phase_cal;
193+ void *txbf_pfmu_data;
194+ void *txbf_pfmu_tag;
195+ } test;
196+#endif
197 };
198
199 enum {
200@@ -825,7 +833,7 @@ int mt7996_mcu_muru_dbg_info(struct mt7996_dev *dev, u16 item, u8 val);
201 int mt7996_mcu_set_sr_enable(struct mt7996_phy *phy, u8 action, u64 val, bool set);
202 void mt7996_mcu_rx_sr_event(struct mt7996_dev *dev, struct sk_buff *skb);
203 int mt7996_mcu_set_dup_wtbl(struct mt7996_dev *dev);
204-int mt7996_mcu_set_txbf_internal(struct mt7996_phy *phy, u8 action, int idx);
205+int mt7996_mcu_set_txbf_internal(struct mt7996_phy *phy, u8 action, int idx, bool bfer);
206 void mt7996_mcu_rx_bf_event(struct mt7996_dev *dev, struct sk_buff *skb);
207 int mt7996_mcu_set_muru_fixed_rate_enable(struct mt7996_dev *dev, u8 action, int val);
208 int mt7996_mcu_set_muru_fixed_rate_parameter(struct mt7996_dev *dev, u8 action, void *para);
209@@ -837,10 +845,12 @@ int mt7996_mcu_set_rfeature_trig_type(struct mt7996_phy *phy, u8 enable, u8 trig
210 void mt7996_mcu_set_ppdu_tx_type(struct mt7996_phy *phy, u8 ppdu_type);
211 void mt7996_mcu_set_nusers_ofdma(struct mt7996_phy *phy, u8 type, u8 ofdma_user_cnt);
212 void mt7996_mcu_set_cert(struct mt7996_phy *phy, u8 type);
213+void mt7996_tm_update_channel(struct mt7996_phy *phy);
214 #endif
215
216 #ifdef CONFIG_NET_MEDIATEK_SOC_WED
217 int mt7996_dma_rro_init(struct mt7996_dev *dev);
218 #endif /* CONFIG_NET_MEDIATEK_SOC_WED */
219
220+
221 #endif
222diff --git a/mt7996/mtk_debugfs.c b/mt7996/mtk_debugfs.c
developer9237f442024-06-14 17:13:04 +0800223index b7fef1b..c1b665f 100644
developer66e89bc2024-04-23 14:50:01 +0800224--- a/mt7996/mtk_debugfs.c
225+++ b/mt7996/mtk_debugfs.c
226@@ -2958,7 +2958,7 @@ mt7996_starec_bf_read_set(void *data, u64 wlan_idx)
227 {
228 struct mt7996_phy *phy = data;
229
230- return mt7996_mcu_set_txbf_internal(phy, BF_STA_REC_READ, wlan_idx);
231+ return mt7996_mcu_set_txbf_internal(phy, BF_STA_REC_READ, wlan_idx, 0);
232 }
233 DEFINE_DEBUGFS_ATTRIBUTE(fops_starec_bf_read, NULL,
234 mt7996_starec_bf_read_set, "%lld\n");
235@@ -3002,7 +3002,7 @@ mt7996_bf_fbk_rpt_set(void *data, u64 wlan_idx)
236 {
237 struct mt7996_phy *phy = data;
238
239- return mt7996_mcu_set_txbf_internal(phy, BF_FBRPT_DBG_INFO_READ, wlan_idx);
240+ return mt7996_mcu_set_txbf_internal(phy, BF_FBRPT_DBG_INFO_READ, wlan_idx, 0);
241 }
242 DEFINE_DEBUGFS_ATTRIBUTE(fops_bf_fbk_rpt, NULL,
243 mt7996_bf_fbk_rpt_set, "%lld\n");
244@@ -3012,7 +3012,7 @@ mt7996_bf_pfmu_tag_read_set(void *data, u64 wlan_idx)
245 {
246 struct mt7996_phy *phy = data;
247
248- return mt7996_mcu_set_txbf_internal(phy, BF_PFMU_TAG_READ, wlan_idx);
249+ return mt7996_mcu_set_txbf_internal(phy, BF_PFMU_TAG_READ, wlan_idx, 1);
250 }
251 DEFINE_DEBUGFS_ATTRIBUTE(fops_bf_pfmu_tag_read, NULL,
252 mt7996_bf_pfmu_tag_read_set, "%lld\n");
253diff --git a/mt7996/mtk_mcu.c b/mt7996/mtk_mcu.c
developer9237f442024-06-14 17:13:04 +0800254index b67d366..a9a7db1 100644
developer66e89bc2024-04-23 14:50:01 +0800255--- a/mt7996/mtk_mcu.c
256+++ b/mt7996/mtk_mcu.c
257@@ -295,7 +295,7 @@ __mt7996_mcu_add_uni_tlv(struct sk_buff *skb, u16 tag, u16 len)
258 return ptlv;
259 }
260
261-int mt7996_mcu_set_txbf_internal(struct mt7996_phy *phy, u8 action, int idx)
262+int mt7996_mcu_set_txbf_internal(struct mt7996_phy *phy, u8 action, int idx, bool bfer)
263 {
264 struct mt7996_dev *dev = phy->dev;
265 #define MT7996_MTK_BF_MAX_SIZE sizeof(struct bf_starec_read)
266@@ -318,9 +318,8 @@ int mt7996_mcu_set_txbf_internal(struct mt7996_phy *phy, u8 action, int idx)
267
268 tlv = __mt7996_mcu_add_uni_tlv(skb, action, sizeof(*req));
269 req = (struct bf_pfmu_tag *)tlv;
270-#define BFER 1
271 req->pfmu_id = idx;
272- req->bfer = BFER;
273+ req->bfer = bfer;
274 req->band_idx = phy->mt76->band_idx;
275 break;
276 }
277@@ -432,10 +431,61 @@ int mt7996_mcu_set_txbf_snd_info(struct mt7996_phy *phy, void *para)
278 return mt76_mcu_skb_send_msg(&phy->dev->mt76, skb, MCU_WM_UNI_CMD(BF), false);
279 }
280
281+static inline void
282+mt7996_ibf_phase_assign(struct mt7996_dev *dev,
283+ struct mt7996_ibf_cal_info *cal,
284+ struct mt7996_txbf_phase *phase)
285+{
286+ /* fw return ibf calibrated data with
287+ * the mt7996_txbf_phase_info_5g struct for both 2G and 5G.
288+ * (return struct mt7992_txbf_phase_info_5g for ibf 2.0)
289+ * Therefore, memcpy cannot be used here.
290+ */
291+ if (get_ibf_version(dev) != IBF_VER_2) {
292+ phase_assign(cal->group, v1, m_t0_h, true);
293+ phase_assign(cal->group, v1, m_t1_h, true);
294+ phase_assign(cal->group, v1, m_t2_h, true);
295+ phase_assign(cal->group, v1, m_t2_h_sx2, false);
296+ phase_assign_rx_v1(cal->group, v1, r0);
297+ phase_assign_rx_v1(cal->group, v1, r1);
298+ phase_assign_rx_v1(cal->group, v1, r2);
299+ phase_assign_rx_v1(cal->group, v1, r3);
300+ phase_assign_rx(cal->group, v1, r2_sx2, false);
301+ phase_assign_rx(cal->group, v1, r3_sx2, false);
302+ phase_assign(cal->group, v1, r0_reserved, false);
303+ phase_assign(cal->group, v1, r1_reserved, false);
304+ phase_assign(cal->group, v1, r2_reserved, false);
305+ phase_assign(cal->group, v1, r3_reserved, false);
306+ phase_assign(cal->group, v1, r2_sx2_reserved, false);
307+ phase_assign(cal->group, v1, r3_sx2_reserved, false);
308+ } else {
309+ phase_assign(cal->group, v2, m_t0_h, true);
310+ phase_assign(cal->group, v2, m_t1_h, true);
311+ phase_assign(cal->group, v2, m_t2_h, true);
312+ if (cal->group) {
313+ phase->v2.phase_5g.m_t3_h = cal->v2.phase_5g.m_t3_h;
314+ dev_info(dev->mt76.dev, "m_t3_h = %d\n", phase->v2.phase_5g.m_t3_h);
315+ }
316+ phase_assign_rx_ext(cal->group, v2, r0, true);
317+ phase_assign_rx_ext(cal->group, v2, r1, true);
318+ phase_assign_rx_ext(cal->group, v2, r2, true);
319+ phase_assign_rx_ext(cal->group, v2, r3, true);
320+ if (cal->group) {
321+ memcpy(&phase->v2.phase_5g.r4, &cal->v2.phase_5g.r4,
322+ sizeof(struct txbf_rx_phase_ext));
323+ dev_info(dev->mt76.dev, "r4.rx_uh = %d\n", phase->v2.phase_5g.r4.rx_uh);
324+ dev_info(dev->mt76.dev, "r4.rx_h = %d\n", phase->v2.phase_5g.r4.rx_h);
325+ dev_info(dev->mt76.dev, "r4.rx_mh = %d\n", phase->v2.phase_5g.r4.rx_mh);
326+ dev_info(dev->mt76.dev, "r4.rx_m = %d\n", phase->v2.phase_5g.r4.rx_m);
327+ dev_info(dev->mt76.dev, "r4.rx_l = %d\n", phase->v2.phase_5g.r4.rx_l);
328+ dev_info(dev->mt76.dev, "r4.rx_ul = %d\n", phase->v2.phase_5g.r4.rx_ul);
329+ }
330+ }
331+}
332+
333 void
334 mt7996_mcu_rx_bf_event(struct mt7996_dev *dev, struct sk_buff *skb)
335 {
336-#define HE_MODE 3
337 struct mt7996_mcu_bf_basic_event *event;
338
339 event = (struct mt7996_mcu_bf_basic_event *)skb->data;
340@@ -470,13 +520,12 @@ mt7996_mcu_rx_bf_event(struct mt7996_dev *dev, struct sk_buff *skb)
341 tag->t1.nr, tag->t1.nc, tag->t1.ngroup, tag->t1.lm, tag->t1.codebook,
342 tag->t1.mob_cal_en);
343
344- if (tag->t1.lm <= HE_MODE) {
345+ if (tag->t1.lm <= BF_LM_HE)
346 dev_info(dev->mt76.dev, "RU start = %d, RU end = %d\n",
347 tag->t1.field.ru_start_id, tag->t1.field.ru_end_id);
348- } else {
349+ else
350 dev_info(dev->mt76.dev, "PartialBW = %d\n",
351 tag->t1.bw_info.partial_bw_info);
352- }
353
354 dev_info(dev->mt76.dev, "Mem Col1 = %d, Mem Row1 = %d, Mem Col2 = %d, Mem Row2 = %d\n",
355 tag->t1.col_id1, tag->t1.row_id1, tag->t1.col_id2, tag->t1.row_id2);
356@@ -728,6 +777,86 @@ mt7996_mcu_rx_bf_event(struct mt7996_dev *dev, struct sk_buff *skb)
357
358 break;
359 }
360+ case UNI_EVENT_BF_CAL_PHASE: {
361+ struct mt7996_ibf_cal_info *cal;
362+ struct mt7996_txbf_phase *phase;
363+ union {
364+ struct mt7996_txbf_phase_out v1;
365+ struct mt7992_txbf_phase_out v2;
366+ } phase_out;
367+ int phase_out_size = sizeof(struct mt7996_txbf_phase_out);
368+
369+ cal = (struct mt7996_ibf_cal_info *)skb->data;
370+ phase = (struct mt7996_txbf_phase *)dev->test.txbf_phase_cal;
371+ if (get_ibf_version(dev) == IBF_VER_2)
372+ phase_out_size = sizeof(struct mt7992_txbf_phase_out);
373+ memcpy(&phase_out, &cal->buf, phase_out_size);
374+ switch (cal->cal_type) {
375+ case IBF_PHASE_CAL_NORMAL:
376+ case IBF_PHASE_CAL_NORMAL_INSTRUMENT:
377+ /* Only calibrate group M */
378+ if (cal->group_l_m_n != GROUP_M)
379+ break;
380+ phase = &phase[cal->group];
381+ phase->status = cal->status;
382+ dev_info(dev->mt76.dev, "Calibrated result = %d\n", phase->status);
383+ dev_info(dev->mt76.dev, "Group %d and Group M\n", cal->group);
384+ mt7996_ibf_phase_assign(dev, cal, phase);
385+ break;
386+ case IBF_PHASE_CAL_VERIFY:
387+ case IBF_PHASE_CAL_VERIFY_INSTRUMENT:
388+ dev_info(dev->mt76.dev, "Verification result = %d\n", cal->status);
389+ break;
390+ default:
391+ break;
392+ }
393+
394+ if (get_ibf_version(dev) == IBF_VER_2) {
395+ dev_info(dev->mt76.dev,
396+ "c0_uh = %d, c1_uh = %d, c2_uh = %d, c3_uh = %d c4_uh = %d\n",
397+ phase_out.v2.c0_uh, phase_out.v2.c1_uh, phase_out.v2.c2_uh,
398+ phase_out.v2.c3_uh, phase_out.v2.c4_uh);
399+ dev_info(dev->mt76.dev,
400+ "c0_h = %d, c1_h = %d, c2_h = %d, c3_h = %d c4_h = %d\n",
401+ phase_out.v2.c0_h, phase_out.v2.c1_h, phase_out.v2.c2_h,
402+ phase_out.v2.c3_h, phase_out.v2.c4_h);
403+ dev_info(dev->mt76.dev,
404+ "c0_mh = %d, c1_mh = %d, c2_mh = %d, c3_mh = %d c4_mh = %d\n",
405+ phase_out.v2.c0_mh, phase_out.v2.c1_mh, phase_out.v2.c2_mh,
406+ phase_out.v2.c3_mh, phase_out.v2.c4_mh);
407+ dev_info(dev->mt76.dev,
408+ "c0_m = %d, c1_m = %d, c2_m = %d, c3_m = %d c4_m = %d\n",
409+ phase_out.v2.c0_m, phase_out.v2.c1_m, phase_out.v2.c2_m,
410+ phase_out.v2.c3_m, phase_out.v2.c4_m);
411+ dev_info(dev->mt76.dev,
412+ "c0_l = %d, c1_l = %d, c2_l = %d, c3_l = %d c4_l = %d\n",
413+ phase_out.v2.c0_l, phase_out.v2.c1_l, phase_out.v2.c2_l,
414+ phase_out.v2.c3_l, phase_out.v2.c4_l);
415+ } else {
416+ dev_info(dev->mt76.dev,
417+ "c0_uh = %d, c1_uh = %d, c2_uh = %d, c3_uh = %d\n",
418+ phase_out.v1.c0_uh, phase_out.v1.c1_uh,
419+ phase_out.v1.c2_uh, phase_out.v1.c3_uh);
420+ dev_info(dev->mt76.dev,
421+ "c0_h = %d, c1_h = %d, c2_h = %d, c3_h = %d\n",
422+ phase_out.v1.c0_h, phase_out.v1.c1_h,
423+ phase_out.v1.c2_h, phase_out.v1.c3_h);
424+ dev_info(dev->mt76.dev,
425+ "c0_mh = %d, c1_mh = %d, c2_mh = %d, c3_mh = %d\n",
426+ phase_out.v1.c0_mh, phase_out.v1.c1_mh,
427+ phase_out.v1.c2_mh, phase_out.v1.c3_mh);
428+ dev_info(dev->mt76.dev,
429+ "c0_m = %d, c1_m = %d, c2_m = %d, c3_m = %d\n",
430+ phase_out.v1.c0_m, phase_out.v1.c1_m,
431+ phase_out.v1.c2_m, phase_out.v1.c3_m);
432+ dev_info(dev->mt76.dev,
433+ "c0_l = %d, c1_l = %d, c2_l = %d, c3_l = %d\n",
434+ phase_out.v1.c0_l, phase_out.v1.c1_l,
435+ phase_out.v1.c2_l, phase_out.v1.c3_l);
436+ }
437+
438+ break;
439+ }
440 default:
441 dev_info(dev->mt76.dev, "%s: unknown bf event tag %d\n",
442 __func__, event->tag);
443diff --git a/mt7996/mtk_mcu.h b/mt7996/mtk_mcu.h
developer9237f442024-06-14 17:13:04 +0800444index 7a4140b..58d61c5 100644
developer66e89bc2024-04-23 14:50:01 +0800445--- a/mt7996/mtk_mcu.h
446+++ b/mt7996/mtk_mcu.h
447@@ -189,6 +189,165 @@ struct bf_txsnd_info {
448 u8 __rsv[2];
449 } __packed;
450
451+#define MAX_PHASE_GROUP_NUM 13
452+
453+struct bf_phase_comp {
454+ __le16 tag;
455+ __le16 len;
456+
457+ u8 bw;
458+ u8 jp_band;
459+ u8 band_idx;
460+ bool read_from_e2p;
461+ bool disable;
462+ u8 group;
463+ u8 rsv[2];
464+ u8 buf[44];
465+} __packed;
466+
467+struct bf_tx_apply {
468+ __le16 tag;
469+ __le16 len;
470+
471+ __le16 wlan_idx;
472+ bool ebf;
473+ bool ibf;
474+ bool mu_txbf;
475+ bool phase_cal;
476+ u8 rsv[2];
477+} __packed;
478+
479+struct bf_phase_cal {
480+ __le16 tag;
481+ __le16 len;
482+
483+ u8 group_l_m_n;
484+ u8 group;
485+ u8 sx2;
486+ u8 cal_type;
487+ u8 lna_gain_level;
488+ u8 band_idx;
489+ u8 version;
490+ u8 rsv[1];
491+} __packed;
492+
493+struct bf_txcmd {
494+ __le16 tag;
495+ __le16 len;
496+
497+ u8 action;
498+ u8 bf_manual;
499+ u8 bf_bit;
500+ u8 rsv[5];
501+} __packed;
502+
503+struct bf_pfmu_data_all {
504+ __le16 tag;
505+ __le16 len;
506+
507+ u8 pfmu_id;
508+ u8 band_idx;
509+ u8 rsv[2];
510+
511+ u8 buf[640];
512+} __packed;
513+
514+#define TXBF_DUT_MAC_SUBADDR 0x22
515+#define TXBF_GOLDEN_MAC_SUBADDR 0x11
516+
517+struct mt7996_tm_bf_req {
518+ u8 _rsv[4];
519+
520+ union {
521+ struct bf_sounding_on sounding;
522+ struct bf_tx_apply tx_apply;
523+ struct bf_pfmu_tag pfmu_tag;
524+ struct bf_pfmu_data_all pfmu_data_all;
525+ struct bf_phase_cal phase_cal;
526+ struct bf_phase_comp phase_comp;
527+ struct bf_txcmd txcmd;
528+ };
529+} __packed;
530+
531+enum tm_trx_mac_type {
532+ TM_TRX_MAC_TX = 1,
533+ TM_TRX_MAC_RX,
534+ TM_TRX_MAC_TXRX,
535+ TM_TRX_MAC_TXRX_RXV,
536+ TM_TRX_MAC_RXV,
537+ TM_TRX_MAC_RX_RXV,
538+};
539+
540+enum tm_trx_param_idx {
541+ TM_TRX_PARAM_RSV,
542+ /* MAC */
543+ TM_TRX_PARAM_SET_TRX,
544+ TM_TRX_PARAM_RX_FILTER,
545+ TM_TRX_PARAM_RX_FILTER_PKT_LEN,
546+ TM_TRX_PARAM_SLOT_TIME,
547+ TM_TRX_PARAM_CLEAN_PERSTA_TXQUEUE,
548+ TM_TRX_PARAM_AMPDU_WTBL,
549+ TM_TRX_PARAM_MU_RX_AID,
550+ TM_TRX_PARAM_PHY_MANUAL_TX,
551+
552+ /* PHY */
553+ TM_TRX_PARAM_RX_PATH,
554+ TM_TRX_PARAM_TX_STREAM,
555+ TM_TRX_PARAM_TSSI_STATUS,
556+ TM_TRX_PARAM_DPD_STATUS,
557+ TM_TRX_PARAM_RATE_POWER_OFFSET_ON_OFF,
558+ TM_TRX_PARAM_THERMO_COMP_STATUS,
559+ TM_TRX_PARAM_FREQ_OFFSET,
560+ TM_TRX_PARAM_FAGC_RSSI_PATH,
561+ TM_TRX_PARAM_PHY_STATUS_COUNT,
562+ TM_TRX_PARAM_RXV_INDEX,
563+
564+ TM_TRX_PARAM_ANTENNA_PORT,
565+ TM_TRX_PARAM_THERMAL_ONOFF,
566+ TM_TRX_PARAM_TX_POWER_CONTROL_ALL_RF,
567+ TM_TRX_PARAM_RATE_POWER_OFFSET,
568+ TM_TRX_PARAM_SLT_CMD_TEST,
569+ TM_TRX_PARAM_SKU,
570+ TM_TRX_PARAM_POWER_PERCENTAGE_ON_OFF,
571+ TM_TRX_PARAM_BF_BACKOFF_ON_OFF,
572+ TM_TRX_PARAM_POWER_PERCENTAGE_LEVEL,
573+ TM_TRX_PARAM_FRTBL_CFG,
574+ TM_TRX_PARAM_PREAMBLE_PUNC_ON_OFF,
575+
576+ TM_TRX_PARAM_MAX_NUM,
577+};
578+
579+enum trx_action {
580+ TM_TRX_ACTION_SET,
581+ TM_TRX_ACTION_GET,
582+};
583+
584+struct tm_trx_set {
585+ u8 type;
586+ u8 enable;
587+ u8 band_idx;
588+ u8 rsv;
589+} __packed;
590+
591+struct mt7996_tm_trx_req {
592+ u8 param_num;
593+ u8 _rsv[3];
594+
595+ __le16 tag;
596+ __le16 len;
597+
598+ __le16 param_idx;
599+ u8 band_idx;
600+ u8 testmode_en;
601+ u8 action;
602+ u8 rsv[3];
603+
604+ u32 data;
605+ struct tm_trx_set set_trx;
606+
607+ u8 buf[220];
608+} __packed;
609+
610 struct mt7996_mcu_bf_basic_event {
611 struct mt7996_mcu_rxd rxd;
612
613@@ -394,6 +553,283 @@ struct mt7996_pfmu_tag_event {
614 struct mt7996_pfmu_tag2 t2;
615 };
616
617+struct mt7996_pfmu_tag {
618+ struct mt7996_pfmu_tag1 t1;
619+ struct mt7996_pfmu_tag2 t2;
620+};
621+
622+enum bf_lm_type {
623+ BF_LM_LEGACY,
624+ BF_LM_HT,
625+ BF_LM_VHT,
626+ BF_LM_HE,
627+ BF_LM_EHT,
628+};
629+
630+struct mt7996_txbf_phase_out {
631+ u8 c0_l;
632+ u8 c1_l;
633+ u8 c2_l;
634+ u8 c3_l;
635+ u8 c0_m;
636+ u8 c1_m;
637+ u8 c2_m;
638+ u8 c3_m;
639+ u8 c0_mh;
640+ u8 c1_mh;
641+ u8 c2_mh;
642+ u8 c3_mh;
643+ u8 c0_h;
644+ u8 c1_h;
645+ u8 c2_h;
646+ u8 c3_h;
647+ u8 c0_uh;
648+ u8 c1_uh;
649+ u8 c2_uh;
650+ u8 c3_uh;
651+};
652+
653+struct mt7992_txbf_phase_out {
654+ u8 c0_l;
655+ u8 c1_l;
656+ u8 c2_l;
657+ u8 c3_l;
658+ u8 c4_l;
659+ u8 c0_m;
660+ u8 c1_m;
661+ u8 c2_m;
662+ u8 c3_m;
663+ u8 c4_m;
664+ u8 c0_mh;
665+ u8 c1_mh;
666+ u8 c2_mh;
667+ u8 c3_mh;
668+ u8 c4_mh;
669+ u8 c0_h;
670+ u8 c1_h;
671+ u8 c2_h;
672+ u8 c3_h;
673+ u8 c4_h;
674+ u8 c0_uh;
675+ u8 c1_uh;
676+ u8 c2_uh;
677+ u8 c3_uh;
678+ u8 c4_uh;
679+};
680+
681+struct txbf_rx_phase {
682+ u8 rx_uh;
683+ u8 rx_h;
684+ u8 rx_m;
685+ u8 rx_l;
686+ u8 rx_ul;
687+};
688+
689+struct txbf_rx_phase_ext {
690+ u8 rx_uh;
691+ u8 rx_h;
692+ u8 rx_mh;
693+ u8 rx_m;
694+ u8 rx_l;
695+ u8 rx_ul;
696+};
697+
698+struct mt7996_txbf_phase_info_2g {
699+ struct txbf_rx_phase r0;
700+ struct txbf_rx_phase r1;
701+ struct txbf_rx_phase r2;
702+ struct txbf_rx_phase r3;
703+ struct txbf_rx_phase r2_sx2;
704+ struct txbf_rx_phase r3_sx2;
705+ u8 m_t0_h;
706+ u8 m_t1_h;
707+ u8 m_t2_h;
708+ u8 m_t2_h_sx2;
709+ u8 r0_reserved;
710+ u8 r1_reserved;
711+ u8 r2_reserved;
712+ u8 r3_reserved;
713+ u8 r2_sx2_reserved;
714+ u8 r3_sx2_reserved;
715+};
716+
717+struct mt7996_txbf_phase_info_5g {
718+ struct txbf_rx_phase_ext r0;
719+ struct txbf_rx_phase_ext r1;
720+ struct txbf_rx_phase_ext r2;
721+ struct txbf_rx_phase_ext r3;
722+ struct txbf_rx_phase r2_sx2; /* no middle-high in r2_sx2 */
723+ struct txbf_rx_phase r3_sx2; /* no middle-high in r3_sx2 */
724+ u8 m_t0_h;
725+ u8 m_t1_h;
726+ u8 m_t2_h;
727+ u8 m_t2_h_sx2;
728+ u8 r0_reserved;
729+ u8 r1_reserved;
730+ u8 r2_reserved;
731+ u8 r3_reserved;
732+ u8 r2_sx2_reserved;
733+ u8 r3_sx2_reserved;
734+};
735+
736+struct mt7992_txbf_phase_info_2g {
737+ struct txbf_rx_phase_ext r0;
738+ struct txbf_rx_phase_ext r1;
739+ struct txbf_rx_phase_ext r2;
740+ struct txbf_rx_phase_ext r3;
741+ u8 m_t0_h;
742+ u8 m_t1_h;
743+ u8 m_t2_h;
744+};
745+
746+struct mt7992_txbf_phase_info_5g {
747+ struct txbf_rx_phase_ext r0;
748+ struct txbf_rx_phase_ext r1;
749+ struct txbf_rx_phase_ext r2;
750+ struct txbf_rx_phase_ext r3;
751+ struct txbf_rx_phase_ext r4;
752+ u8 m_t0_h;
753+ u8 m_t1_h;
754+ u8 m_t2_h;
755+ u8 m_t3_h;
756+};
757+
758+struct mt7996_txbf_phase {
759+ u8 status;
760+ union {
761+ union {
762+ struct mt7996_txbf_phase_info_2g phase_2g;
763+ struct mt7996_txbf_phase_info_5g phase_5g;
764+ } v1;
765+ union {
766+ struct mt7992_txbf_phase_info_2g phase_2g;
767+ struct mt7992_txbf_phase_info_5g phase_5g;
768+ } v2;
769+ u8 buf[44];
770+ };
771+};
772+
773+#define phase_assign(group, v, field, dump, ...) ({ \
774+ if (group) { \
775+ phase->v.phase_5g.field = cal->v.phase_5g.field; \
776+ if (dump) \
777+ dev_info(dev->mt76.dev, "%s = %d\n", #field, phase->v.phase_5g.field); \
778+ } else { \
779+ phase->v.phase_2g.field = cal->v.phase_5g.field; \
780+ if (dump) \
781+ dev_info(dev->mt76.dev, "%s = %d\n", #field, phase->v.phase_2g.field); \
782+ } \
783+})
784+
785+#define phase_assign_rx(group, v, rx, dump, ...) ({ \
786+ phase_assign(group, v, rx.rx_uh, dump); \
787+ phase_assign(group, v, rx.rx_h, dump); \
788+ phase_assign(group, v, rx.rx_m, dump); \
789+ phase_assign(group, v, rx.rx_l, dump); \
790+ phase_assign(group, v, rx.rx_ul, dump); \
791+})
792+
793+#define phase_assign_rx_ext(group, v, rx, dump, ...) ({ \
794+ phase_assign(group, v, rx.rx_uh, dump); \
795+ phase_assign(group, v, rx.rx_h, dump); \
796+ phase_assign(group, v, rx.rx_mh, dump); \
797+ phase_assign(group, v, rx.rx_m, dump); \
798+ phase_assign(group, v, rx.rx_l, dump); \
799+ phase_assign(group, v, rx.rx_ul, dump); \
800+})
801+
802+#define phase_assign_rx_v1(group, v, rx, ...) ({ \
803+ if (group) { \
804+ phase_assign(group, v, rx.rx_uh, true); \
805+ phase_assign(group, v, rx.rx_h, true); \
806+ phase->v.phase_5g.rx.rx_mh = cal->v.phase_5g.rx.rx_mh; \
807+ dev_info(dev->mt76.dev, "%s.rx_mh = %d\n", #rx, phase->v.phase_5g.rx.rx_mh); \
808+ phase_assign(group, v, rx.rx_m, true); \
809+ phase_assign(group, v, rx.rx_l, true); \
810+ phase_assign(group, v, rx.rx_ul, true); \
811+ } else { \
812+ phase_assign_rx(group, v, rx, true, ...); \
813+ } \
814+})
815+
816+#define GROUP_L 0
817+#define GROUP_M 1
818+#define GROUP_H 2
819+
820+struct mt7996_pfmu_data {
821+ __le16 subc_idx;
822+ __le16 phi11;
823+ __le16 phi21;
824+ __le16 phi31;
825+};
826+
827+struct mt7996_pfmu_data_5x5 {
828+ __le16 subc_idx;
829+ __le16 phi11;
830+ __le16 phi21;
831+ __le16 phi31;
832+ __le16 phi41;
833+};
834+
835+struct mt7996_ibf_cal_info {
836+ struct mt7996_mcu_bf_basic_event event;
837+
838+ u8 category_id;
839+ u8 group_l_m_n;
840+ u8 group;
841+ bool sx2;
842+ u8 status;
843+ u8 cal_type;
844+ u8 nsts;
845+ u8 version;
846+ union {
847+ struct {
848+ struct mt7996_txbf_phase_out phase_out;
849+ union {
850+ struct mt7996_txbf_phase_info_2g phase_2g;
851+ struct mt7996_txbf_phase_info_5g phase_5g;
852+ };
853+ } v1;
854+ struct {
855+ struct mt7992_txbf_phase_out phase_out;
856+ union {
857+ struct mt7992_txbf_phase_info_2g phase_2g;
858+ struct mt7992_txbf_phase_info_5g phase_5g;
859+ };
860+ } v2;
861+ u8 buf[64];
862+ };
863+} __packed;
864+
865+enum {
866+ IBF_PHASE_CAL_UNSPEC,
867+ IBF_PHASE_CAL_NORMAL,
868+ IBF_PHASE_CAL_VERIFY,
869+ IBF_PHASE_CAL_NORMAL_INSTRUMENT,
870+ IBF_PHASE_CAL_VERIFY_INSTRUMENT,
871+};
872+
873+enum ibf_version {
874+ IBF_VER_1,
875+ IBF_VER_2 = 3,
876+};
877+
878+static inline int get_ibf_version(struct mt7996_dev *dev)
879+{
880+ switch (mt76_chip(&dev->mt76)) {
881+ case 0x7990:
882+ return IBF_VER_1;
883+ case 0x7992:
884+ default:
885+ return IBF_VER_2;
886+ }
887+}
888+
889+#define MT7996_TXBF_SUBCAR_NUM 64
890+#define MT7996_TXBF_PFMU_DATA_LEN (MT7996_TXBF_SUBCAR_NUM * sizeof(struct mt7996_pfmu_data))
891+#define MT7996_TXBF_PFMU_DATA_LEN_5X5 (MT7996_TXBF_SUBCAR_NUM * \
892+ sizeof(struct mt7996_pfmu_data_5x5))
893+
894 enum {
895 UNI_EVENT_BF_PFMU_TAG = 0x5,
896 UNI_EVENT_BF_PFMU_DATA = 0x7,
897@@ -408,11 +844,6 @@ enum {
898 UNI_EVENT_BF_MAX_NUM
899 };
900
901-enum {
902- UNI_CMD_MURU_FIXED_RATE_CTRL = 0x11,
903- UNI_CMD_MURU_FIXED_GROUP_RATE_CTRL,
904-};
905-
906 struct uni_muru_mum_set_group_tbl_entry {
907 __le16 wlan_idx0;
908 __le16 wlan_idx1;
909diff --git a/mt7996/regs.h b/mt7996/regs.h
developer9237f442024-06-14 17:13:04 +0800910index 8ec1dc1..263737c 100644
developer66e89bc2024-04-23 14:50:01 +0800911--- a/mt7996/regs.h
912+++ b/mt7996/regs.h
913@@ -326,6 +326,9 @@ enum offs_rev {
914 #define MT_ARB_SCR_TX_DISABLE BIT(8)
915 #define MT_ARB_SCR_RX_DISABLE BIT(9)
916
917+#define MT_ARB_TQSAXM0(_band) MT_WF_ARB(_band, 0x180)
918+#define MT_ARB_TQSAXM_ALTX_START_MASK GENMASK(12, 8)
919+
920 /* RMAC: band 0(0x820e5000), band 1(0x820f5000), band 2(0x830e5000), */
921 #define MT_WF_RMAC_BASE(_band) __BASE(WF_RMAC_BASE, (_band))
922 #define MT_WF_RMAC(_band, ofs) (MT_WF_RMAC_BASE(_band) + (ofs))
923diff --git a/mt7996/testmode.c b/mt7996/testmode.c
developer9237f442024-06-14 17:13:04 +0800924index 836211f..5cec1ee 100644
developer66e89bc2024-04-23 14:50:01 +0800925--- a/mt7996/testmode.c
926+++ b/mt7996/testmode.c
927@@ -23,6 +23,7 @@ enum {
928 TM_CHANGED_IPI_THRESHOLD,
929 TM_CHANGED_IPI_PERIOD,
930 TM_CHANGED_IPI_RESET,
931+ TM_CHANGED_TXBF_ACT,
932
933 /* must be last */
934 NUM_TM_CHANGED
935@@ -41,25 +42,31 @@ static const u8 tm_change_map[] = {
936 [TM_CHANGED_IPI_THRESHOLD] = MT76_TM_ATTR_IPI_THRESHOLD,
937 [TM_CHANGED_IPI_PERIOD] = MT76_TM_ATTR_IPI_PERIOD,
938 [TM_CHANGED_IPI_RESET] = MT76_TM_ATTR_IPI_RESET,
939+ [TM_CHANGED_TXBF_ACT] = MT76_TM_ATTR_TXBF_ACT,
940 };
941
942 static void mt7996_tm_ipi_work(struct work_struct *work);
943+static int mt7996_tm_txbf_apply_tx(struct mt7996_phy *phy, u16 wlan_idx,
944+ bool ebf, bool ibf, bool phase_cal);
945
946 static u32 mt7996_tm_bw_mapping(enum nl80211_chan_width width, enum bw_mapping_method method)
947 {
948 static const u32 width_to_bw[][NUM_BW_MAP] = {
949- [NL80211_CHAN_WIDTH_40] = {FW_CDBW_40MHZ, TM_CBW_40MHZ, 40,
950+ [NL80211_CHAN_WIDTH_40] = {FW_CDBW_40MHZ, TM_CBW_40MHZ, BF_CDBW_40MHZ, 40,
951 FIRST_CONTROL_CHAN_BITMAP_BW40},
952- [NL80211_CHAN_WIDTH_80] = {FW_CDBW_80MHZ, TM_CBW_80MHZ, 80,
953+ [NL80211_CHAN_WIDTH_80] = {FW_CDBW_80MHZ, TM_CBW_80MHZ, BF_CDBW_80MHZ, 80,
954 FIRST_CONTROL_CHAN_BITMAP_BW80},
955- [NL80211_CHAN_WIDTH_80P80] = {FW_CDBW_8080MHZ, TM_CBW_8080MHZ, 80, 0x0},
956- [NL80211_CHAN_WIDTH_160] = {FW_CDBW_160MHZ, TM_CBW_160MHZ, 160,
957+ [NL80211_CHAN_WIDTH_80P80] = {FW_CDBW_8080MHZ, TM_CBW_8080MHZ, BF_CDBW_8080MHZ,
958+ 80, 0x0},
959+ [NL80211_CHAN_WIDTH_160] = {FW_CDBW_160MHZ, TM_CBW_160MHZ, BF_CDBW_160MHZ, 160,
960 FIRST_CONTROL_CHAN_BITMAP_BW160},
961- [NL80211_CHAN_WIDTH_5] = {FW_CDBW_5MHZ, TM_CBW_5MHZ, 5, 0x0},
962- [NL80211_CHAN_WIDTH_10] = {FW_CDBW_10MHZ, TM_CBW_10MHZ, 10, 0x0},
963- [NL80211_CHAN_WIDTH_20] = {FW_CDBW_20MHZ, TM_CBW_20MHZ, 20, 0x0},
964- [NL80211_CHAN_WIDTH_20_NOHT] = {FW_CDBW_20MHZ, TM_CBW_20MHZ, 20, 0x0},
965- [NL80211_CHAN_WIDTH_320] = {FW_CDBW_320MHZ, TM_CBW_320MHZ, 320, 0x0},
966+ [NL80211_CHAN_WIDTH_5] = {FW_CDBW_5MHZ, TM_CBW_5MHZ, BF_CDBW_5MHZ, 5, 0x0},
967+ [NL80211_CHAN_WIDTH_10] = {FW_CDBW_10MHZ, TM_CBW_10MHZ, BF_CDBW_10MHZ, 10, 0x0},
968+ [NL80211_CHAN_WIDTH_20] = {FW_CDBW_20MHZ, TM_CBW_20MHZ, BF_CDBW_20MHZ, 20, 0x0},
969+ [NL80211_CHAN_WIDTH_20_NOHT] = {FW_CDBW_20MHZ, TM_CBW_20MHZ, BF_CDBW_20MHZ,
970+ 20, 0x0},
971+ [NL80211_CHAN_WIDTH_320] = {FW_CDBW_320MHZ, TM_CBW_320MHZ, BF_CDBW_320MHZ,
972+ 320, 0x0},
973 };
974
975 if (width >= ARRAY_SIZE(width_to_bw))
976@@ -68,26 +75,26 @@ static u32 mt7996_tm_bw_mapping(enum nl80211_chan_width width, enum bw_mapping_m
977 return width_to_bw[width][method];
978 }
979
980-static u8 mt7996_tm_rate_to_phy(u8 tx_rate_mode)
981+static u8 mt7996_tm_rate_mapping(u8 tx_rate_mode, enum rate_mapping_type type)
982 {
983- static const u8 rate_to_phy[] = {
984- [MT76_TM_TX_MODE_CCK] = MT_PHY_TYPE_CCK,
985- [MT76_TM_TX_MODE_OFDM] = MT_PHY_TYPE_OFDM,
986- [MT76_TM_TX_MODE_HT] = MT_PHY_TYPE_HT,
987- [MT76_TM_TX_MODE_VHT] = MT_PHY_TYPE_VHT,
988- [MT76_TM_TX_MODE_HE_SU] = MT_PHY_TYPE_HE_SU,
989- [MT76_TM_TX_MODE_HE_EXT_SU] = MT_PHY_TYPE_HE_EXT_SU,
990- [MT76_TM_TX_MODE_HE_TB] = MT_PHY_TYPE_HE_TB,
991- [MT76_TM_TX_MODE_HE_MU] = MT_PHY_TYPE_HE_MU,
992- [MT76_TM_TX_MODE_EHT_SU] = MT_PHY_TYPE_EHT_SU,
993- [MT76_TM_TX_MODE_EHT_TRIG] = MT_PHY_TYPE_EHT_TRIG,
994- [MT76_TM_TX_MODE_EHT_MU] = MT_PHY_TYPE_EHT_MU,
995+ static const u8 rate_to_phy[][NUM_RATE_MAP] = {
996+ [MT76_TM_TX_MODE_CCK] = {MT_PHY_TYPE_CCK, BF_LM_LEGACY},
997+ [MT76_TM_TX_MODE_OFDM] = {MT_PHY_TYPE_OFDM, BF_LM_LEGACY},
998+ [MT76_TM_TX_MODE_HT] = {MT_PHY_TYPE_HT, BF_LM_HT},
999+ [MT76_TM_TX_MODE_VHT] = {MT_PHY_TYPE_VHT, BF_LM_VHT},
1000+ [MT76_TM_TX_MODE_HE_SU] = {MT_PHY_TYPE_HE_SU, BF_LM_HE},
1001+ [MT76_TM_TX_MODE_HE_EXT_SU] = {MT_PHY_TYPE_HE_EXT_SU, BF_LM_HE},
1002+ [MT76_TM_TX_MODE_HE_TB] = {MT_PHY_TYPE_HE_TB, BF_LM_HE},
1003+ [MT76_TM_TX_MODE_HE_MU] = {MT_PHY_TYPE_HE_MU, BF_LM_HE},
1004+ [MT76_TM_TX_MODE_EHT_SU] = {MT_PHY_TYPE_EHT_SU, BF_LM_EHT},
1005+ [MT76_TM_TX_MODE_EHT_TRIG] = {MT_PHY_TYPE_EHT_TRIG, BF_LM_EHT},
1006+ [MT76_TM_TX_MODE_EHT_MU] = {MT_PHY_TYPE_EHT_MU, BF_LM_EHT},
1007 };
1008
1009 if (tx_rate_mode > MT76_TM_TX_MODE_MAX)
1010 return -EINVAL;
1011
1012- return rate_to_phy[tx_rate_mode];
1013+ return rate_to_phy[tx_rate_mode][type];
1014 }
1015
1016 static int
1017@@ -239,7 +246,7 @@ mt7996_tm_init(struct mt7996_phy *phy, bool en)
1018 INIT_DELAYED_WORK(&phy->ipi_work, mt7996_tm_ipi_work);
1019 }
1020
1021-static void
1022+void
1023 mt7996_tm_update_channel(struct mt7996_phy *phy)
1024 {
1025 #define CHAN_FREQ_BW_80P80_TAG (SET_ID(CHAN_FREQ) | BIT(16))
1026@@ -303,7 +310,8 @@ mt7996_tm_set_tx_frames(struct mt7996_phy *phy, bool en)
1027 mt7996_tm_set(dev, SET_ID(MAC_HEADER), FRAME_CONTROL);
1028 mt7996_tm_set(dev, SET_ID(SEQ_CTRL), 0);
1029 mt7996_tm_set(dev, SET_ID(TX_COUNT), td->tx_count);
1030- mt7996_tm_set(dev, SET_ID(TX_MODE), mt7996_tm_rate_to_phy(td->tx_rate_mode));
1031+ mt7996_tm_set(dev, SET_ID(TX_MODE),
1032+ mt7996_tm_rate_mapping(td->tx_rate_mode, RATE_MODE_TO_PHY));
1033 mt7996_tm_set(dev, SET_ID(TX_RATE), td->tx_rate_idx);
1034
1035 if (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_POWER))
1036@@ -331,7 +339,8 @@ mt7996_tm_set_tx_frames(struct mt7996_phy *phy, bool en)
1037
1038 mt7996_tm_set(dev, SET_ID(MAX_PE), 2);
1039 mt7996_tm_set(dev, SET_ID(HW_TX_MODE), 0);
1040- mt7996_tm_update_channel(phy);
1041+ if (!td->bf_en)
1042+ mt7996_tm_update_channel(phy);
1043
1044 /* trigger firmware to start TX */
1045 mt7996_tm_set(dev, SET_ID(COMMAND), RF_CMD(START_TX));
1046@@ -373,7 +382,8 @@ mt7996_tm_set_rx_frames(struct mt7996_phy *phy, bool en)
1047 return;
1048 }
1049
1050- mt7996_tm_update_channel(phy);
1051+ if (!td->bf_en)
1052+ mt7996_tm_update_channel(phy);
1053
1054 if (td->tx_rate_mode >= MT76_TM_TX_MODE_HE_MU) {
1055 if (td->aid)
1056@@ -381,7 +391,8 @@ mt7996_tm_set_rx_frames(struct mt7996_phy *phy, bool en)
1057 else
1058 ret = mt7996_tm_set(dev, SET_ID(RX_MU_AID), RX_MU_DISABLE);
1059 }
1060- mt7996_tm_set(dev, SET_ID(TX_MODE), mt7996_tm_rate_to_phy(td->tx_rate_mode));
1061+ mt7996_tm_set(dev, SET_ID(TX_MODE),
1062+ mt7996_tm_rate_mapping(td->tx_rate_mode, RATE_MODE_TO_PHY));
1063 mt7996_tm_set(dev, SET_ID(GI), td->tx_rate_sgi);
1064 mt7996_tm_set_antenna(phy, SET_ID(RX_PATH));
1065 mt7996_tm_set(dev, SET_ID(MAX_PE), 2);
1066@@ -405,7 +416,8 @@ mt7996_tm_set_tx_cont(struct mt7996_phy *phy, bool en)
1067
1068 if (en) {
1069 mt7996_tm_update_channel(phy);
1070- mt7996_tm_set(dev, SET_ID(TX_MODE), mt7996_tm_rate_to_phy(td->tx_rate_mode));
1071+ mt7996_tm_set(dev, SET_ID(TX_MODE),
1072+ mt7996_tm_rate_mapping(td->tx_rate_mode, RATE_MODE_TO_PHY));
1073 mt7996_tm_set(dev, SET_ID(TX_RATE), td->tx_rate_idx);
1074 /* fix payload is OFDM */
1075 mt7996_tm_set(dev, SET_ID(CONT_WAVE_MODE), CONT_WAVE_MODE_OFDM);
1076@@ -1047,6 +1059,730 @@ mt7996_tm_set_ipi(struct mt7996_phy *phy)
1077 return 0;
1078 }
1079
1080+static int
1081+mt7996_tm_set_trx_mac(struct mt7996_phy *phy, u8 type, bool en)
1082+{
1083+#define UNI_TM_TRX_CTRL 0
1084+ struct mt7996_dev *dev = phy->dev;
1085+ struct mt7996_tm_trx_req req = {
1086+ .param_num = 1,
1087+ .tag = cpu_to_le16(UNI_TM_TRX_CTRL),
1088+ .len = cpu_to_le16(sizeof(req) - 4),
1089+ .param_idx = cpu_to_le16(TM_TRX_PARAM_SET_TRX),
1090+ .band_idx = phy->mt76->band_idx,
1091+ .testmode_en = 1,
1092+ .action = TM_TRX_ACTION_SET,
1093+ .set_trx = {
1094+ .type = type,
1095+ .enable = en,
1096+ .band_idx = phy->mt76->band_idx,
1097+ }
1098+ };
1099+
1100+ return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(TESTMODE_TRX_PARAM),
1101+ &req, sizeof(req), false);
1102+}
1103+
1104+static int
1105+mt7996_tm_txbf_init(struct mt7996_phy *phy, u16 *val)
1106+{
1107+#define EBF_BBP_RX_OFFSET 0x10280
1108+#define EBF_BBP_RX_ENABLE (BIT(0) | BIT(15))
1109+ struct mt7996_dev *dev = phy->dev;
1110+ struct mt76_testmode_data *td = &phy->mt76->test;
1111+ bool enable = val[0];
1112+ void *phase_cal, *pfmu_data, *pfmu_tag;
1113+ u8 nss, band_idx = phy->mt76->band_idx;
1114+ enum nl80211_chan_width width = NL80211_CHAN_WIDTH_20;
1115+ u8 sub_addr = td->is_txbf_dut ? TXBF_DUT_MAC_SUBADDR : TXBF_GOLDEN_MAC_SUBADDR;
1116+ u8 peer_addr = td->is_txbf_dut ? TXBF_GOLDEN_MAC_SUBADDR : TXBF_DUT_MAC_SUBADDR;
1117+ u8 bss_addr = TXBF_DUT_MAC_SUBADDR;
1118+ u8 addr[ETH_ALEN] = {0x00, sub_addr, sub_addr, sub_addr, sub_addr, sub_addr};
1119+ u8 bssid[ETH_ALEN] = {0x00, bss_addr, bss_addr, bss_addr, bss_addr, bss_addr};
1120+ u8 peer_addrs[ETH_ALEN] = {0x00, peer_addr, peer_addr, peer_addr, peer_addr, peer_addr};
1121+ struct mt7996_vif *mvif = (struct mt7996_vif *)phy->monitor_vif->drv_priv;
1122+
1123+ if (!enable) {
1124+ td->bf_en = false;
1125+ return 0;
1126+ }
1127+
1128+ if (!dev->test.txbf_phase_cal) {
1129+ phase_cal = devm_kzalloc(dev->mt76.dev,
1130+ sizeof(struct mt7996_txbf_phase) *
1131+ MAX_PHASE_GROUP_NUM,
1132+ GFP_KERNEL);
1133+ if (!phase_cal)
1134+ return -ENOMEM;
1135+
1136+ dev->test.txbf_phase_cal = phase_cal;
1137+ }
1138+
1139+ if (!dev->test.txbf_pfmu_data) {
1140+ /* allocate max size for 5x5 pfmu data */
1141+ pfmu_data = devm_kzalloc(dev->mt76.dev,
1142+ MT7996_TXBF_PFMU_DATA_LEN_5X5,
1143+ GFP_KERNEL);
1144+ if (!pfmu_data)
1145+ return -ENOMEM;
1146+
1147+ dev->test.txbf_pfmu_data = pfmu_data;
1148+ }
1149+
1150+ if (!dev->test.txbf_pfmu_tag) {
1151+ pfmu_tag = devm_kzalloc(dev->mt76.dev,
1152+ sizeof(struct mt7996_pfmu_tag), GFP_KERNEL);
1153+ if (!pfmu_tag)
1154+ return -ENOMEM;
1155+
1156+ dev->test.txbf_pfmu_tag = pfmu_tag;
1157+ }
1158+
1159+ td->bf_en = true;
1160+ dev->ibf = td->ibf;
1161+ memcpy(td->addr[0], peer_addrs, ETH_ALEN);
1162+ memcpy(td->addr[1], addr, ETH_ALEN);
1163+ memcpy(td->addr[2], bssid, ETH_ALEN);
1164+ memcpy(phy->monitor_vif->addr, addr, ETH_ALEN);
1165+ mt7996_tm_set_mac_addr(dev, td->addr[0], SET_ID(DA));
1166+ mt7996_tm_set_mac_addr(dev, td->addr[1], SET_ID(SA));
1167+ mt7996_tm_set_mac_addr(dev, td->addr[2], SET_ID(BSSID));
1168+
1169+ /* bss idx & omac idx should be set to band idx for ibf cal */
1170+ mvif->mt76.idx = band_idx;
1171+ dev->mt76.vif_mask |= BIT_ULL(mvif->mt76.idx);
1172+ mvif->mt76.omac_idx = band_idx;
1173+ phy->omac_mask |= BIT_ULL(mvif->mt76.omac_idx);
1174+
1175+ mt7996_mcu_add_dev_info(phy, phy->monitor_vif, true);
1176+ mt7996_mcu_add_bss_info(phy, phy->monitor_vif, true);
1177+
1178+ if (td->ibf) {
1179+ if (td->is_txbf_dut) {
1180+ /* Enable ITxBF Capability */
1181+ mt7996_mcu_set_txbf(dev, BF_HW_EN_UPDATE);
1182+ mt7996_tm_set_trx_mac(phy, TM_TRX_MAC_TX, true);
1183+
1184+ td->tx_ipg = 999;
1185+ td->tx_mpdu_len = 1024;
1186+ td->tx_antenna_mask = phy->mt76->chainmask >> dev->chainshift[band_idx];
1187+ nss = hweight8(td->tx_antenna_mask);
1188+ if (nss > 1 && nss <= 4)
1189+ td->tx_rate_idx = 15 + 8 * (nss - 2);
1190+ else
1191+ td->tx_rate_idx = 31;
1192+ } else {
1193+ td->tx_antenna_mask = 1;
1194+ td->tx_mpdu_len = 1024;
1195+ td->tx_rate_idx = 0;
1196+ mt76_set(dev, EBF_BBP_RX_OFFSET, EBF_BBP_RX_ENABLE);
1197+ dev_info(dev->mt76.dev, "Set BBP RX CR = %x\n",
1198+ mt76_rr(dev, EBF_BBP_RX_OFFSET));
1199+ }
1200+
1201+ td->tx_rate_mode = MT76_TM_TX_MODE_HT;
1202+ td->tx_rate_sgi = 0;
1203+ /* 5T5R ibf */
1204+ if (nss == 5) {
1205+ td->tx_rate_mode = MT76_TM_TX_MODE_VHT;
1206+ td->tx_rate_idx = 7;
1207+ }
1208+ } else {
1209+ if (td->is_txbf_dut) {
1210+ /* Enable ETxBF Capability */
1211+ mt7996_mcu_set_txbf(dev, BF_HW_EN_UPDATE);
1212+ td->tx_antenna_mask = phy->mt76->chainmask >> dev->chainshift[band_idx];
1213+ td->tx_spe_idx = 24 + phy->mt76->band_idx;
1214+ if (td->tx_rate_mode == MT76_TM_TX_MODE_VHT ||
1215+ td->tx_rate_mode == MT76_TM_TX_MODE_HE_SU)
1216+ mt7996_tm_set(dev, SET_ID(NSS), td->tx_rate_nss);
1217+
1218+ mt7996_tm_set(dev, SET_ID(ENCODE_MODE), td->tx_rate_ldpc);
1219+ mt7996_tm_set(dev, SET_ID(TX_COUNT), td->tx_count);
1220+ } else {
1221+ /* Turn On BBP CR for RX */
1222+ mt76_set(dev, EBF_BBP_RX_OFFSET, EBF_BBP_RX_ENABLE);
1223+ dev_info(dev->mt76.dev, "Set BBP RX CR = %x\n",
1224+ mt76_rr(dev, EBF_BBP_RX_OFFSET));
1225+
1226+ td->tx_antenna_mask = 1;
1227+ }
1228+ width = phy->mt76->chandef.width;
1229+
1230+ if (td->tx_rate_mode == MT76_TM_TX_MODE_EHT_MU)
1231+ td->tx_rate_mode = MT76_TM_TX_MODE_EHT_SU;
1232+ }
1233+ mt76_testmode_param_set(td, MT76_TM_ATTR_TX_ANTENNA);
1234+
1235+ mt7996_tm_set(dev, SET_ID(TX_MODE),
1236+ mt7996_tm_rate_mapping(td->tx_rate_mode, RATE_MODE_TO_PHY));
1237+ mt7996_tm_set(dev, SET_ID(TX_RATE), td->tx_rate_idx);
1238+ mt7996_tm_set(dev, SET_ID(GI), td->tx_rate_sgi);
1239+ mt7996_tm_set(dev, SET_ID(CBW),
1240+ mt7996_tm_bw_mapping(width, BW_MAP_NL_TO_FW));
1241+ mt7996_tm_set(dev, SET_ID(DBW),
1242+ mt7996_tm_bw_mapping(width, BW_MAP_NL_TO_FW));
1243+ mt7996_tm_set_antenna(phy, SET_ID(TX_PATH));
1244+ mt7996_tm_set_antenna(phy, SET_ID(RX_PATH));
1245+ mt7996_tm_set(dev, SET_ID(IPG), td->tx_ipg);
1246+ mt7996_tm_set(dev, SET_ID(TX_LEN), td->tx_mpdu_len);
1247+ mt7996_tm_set(dev, SET_ID(TX_TIME), 0);
1248+ mt7996_tm_set(dev, SET_ID(COMMAND), RF_CMD(TX_COMMIT));
1249+
1250+ return 0;
1251+}
1252+
1253+static inline void
1254+mt7996_tm_txbf_phase_copy(struct mt7996_dev *dev, void *des, void *src, int group)
1255+{
1256+ int phase_size;
1257+
1258+ if (group && get_ibf_version(dev) == IBF_VER_1)
1259+ phase_size = sizeof(struct mt7996_txbf_phase_info_5g);
1260+ else if (get_ibf_version(dev) == IBF_VER_1)
1261+ phase_size = sizeof(struct mt7996_txbf_phase_info_2g);
1262+ else if (group)
1263+ phase_size = sizeof(struct mt7992_txbf_phase_info_5g);
1264+ else
1265+ phase_size = sizeof(struct mt7992_txbf_phase_info_2g);
1266+
1267+ memcpy(des, src, phase_size);
1268+}
1269+
1270+static int
1271+mt7996_tm_txbf_phase_comp(struct mt7996_phy *phy, u16 *val)
1272+{
1273+ struct mt7996_dev *dev = phy->dev;
1274+ struct mt7996_tm_bf_req req = {
1275+ .phase_comp = {
1276+ .tag = cpu_to_le16(BF_IBF_PHASE_COMP),
1277+ .len = cpu_to_le16(sizeof(req.phase_comp)),
1278+ .bw = val[0],
1279+ .jp_band = (val[2] == 1) ? 1 : 0,
1280+ .band_idx = phy->mt76->band_idx,
1281+ .read_from_e2p = val[3],
1282+ .disable = val[4],
1283+ .group = val[2],
1284+ }
1285+ };
1286+ struct mt7996_txbf_phase *phase = (struct mt7996_txbf_phase *)dev->test.txbf_phase_cal;
1287+ int group = val[2];
1288+
1289+ wait_event_timeout(dev->mt76.tx_wait, phase[group].status != 0, HZ);
1290+ mt7996_tm_txbf_phase_copy(dev, req.phase_comp.buf, phase[group].buf, group);
1291+
1292+ pr_info("ibf cal process: phase comp info\n");
1293+ print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1,
1294+ &req, sizeof(req), 0);
1295+
1296+ return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(BF), &req,
1297+ sizeof(req), false);
1298+}
1299+
1300+static int
1301+mt7996_tm_txbf_profile_tag_write(struct mt7996_phy *phy, u8 pfmu_idx, struct mt7996_pfmu_tag *tag)
1302+{
1303+ struct mt7996_dev *dev = phy->dev;
1304+ struct mt7996_tm_bf_req req = {
1305+ .pfmu_tag = {
1306+ .tag = cpu_to_le16(BF_PFMU_TAG_WRITE),
1307+ .len = cpu_to_le16(sizeof(req.pfmu_tag)),
1308+ .pfmu_id = pfmu_idx,
1309+ .bfer = true,
1310+ .band_idx = phy->mt76->band_idx,
1311+ }
1312+ };
1313+
1314+ memcpy(req.pfmu_tag.buf, tag, sizeof(*tag));
1315+ wait_event_timeout(dev->mt76.tx_wait, tag->t1.pfmu_idx != 0, HZ);
1316+
1317+ return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(BF), &req,
1318+ sizeof(req), false);
1319+}
1320+
1321+static int
1322+mt7996_tm_add_txbf_sta(struct mt7996_phy *phy, u8 pfmu_idx, u8 nr, u8 nc, bool ebf)
1323+{
1324+ struct mt7996_dev *dev = phy->dev;
1325+ struct mt76_testmode_data *td = &phy->mt76->test;
1326+ struct {
1327+ struct sta_req_hdr hdr;
1328+ struct sta_rec_bf bf;
1329+ } __packed req = {
1330+ .hdr = {
1331+ .bss_idx = phy->mt76->band_idx,
1332+ .wlan_idx_lo = to_wcid_lo(phy->mt76->band_idx + 1),
1333+ .tlv_num = 1,
1334+ .is_tlv_append = 1,
1335+ .muar_idx = 0,
1336+ .wlan_idx_hi = to_wcid_hi(phy->mt76->band_idx + 1),
1337+ },
1338+ .bf = {
1339+ .tag = cpu_to_le16(STA_REC_BF),
1340+ .len = cpu_to_le16(sizeof(req.bf)),
1341+ .pfmu = cpu_to_le16(pfmu_idx),
1342+ .sounding_phy = 1,
1343+ .bf_cap = ebf,
1344+ .ncol = nc,
1345+ .nrow = nr,
1346+ .ibf_timeout = 0xff,
1347+ .tx_mode = mt7996_tm_rate_mapping(td->tx_rate_mode, RATE_MODE_TO_PHY),
1348+ },
1349+ };
1350+ u8 ndp_rate, ndpa_rate, rept_poll_rate, bf_bw;
1351+
1352+ if ((td->tx_rate_mode == MT76_TM_TX_MODE_HE_SU ||
1353+ td->tx_rate_mode == MT76_TM_TX_MODE_EHT_SU) && !td->ibf) {
1354+ rept_poll_rate = 0x49;
1355+ ndpa_rate = 0x49;
1356+ ndp_rate = 0;
1357+ } else if (td->tx_rate_mode == MT76_TM_TX_MODE_VHT && !td->ibf) {
1358+ rept_poll_rate = 0x9;
1359+ ndpa_rate = 0x9;
1360+ ndp_rate = 0;
1361+ } else {
1362+ rept_poll_rate = 0;
1363+ ndpa_rate = 0;
1364+ if (nr == 1)
1365+ ndp_rate = 8;
1366+ else if (nr == 2)
1367+ ndp_rate = 16;
1368+ else if (nr == 4)
1369+ ndp_rate = 32;
1370+ else
1371+ ndp_rate = 24;
1372+
1373+ /* 5T5R ebf profile for ibf cal */
1374+ if (nr == 4 && td->ibf && ebf) {
1375+ ndp_rate = 0;
1376+ ndpa_rate = 11;
1377+ }
1378+ }
1379+
1380+ bf_bw = mt7996_tm_bw_mapping(phy->mt76->chandef.width, BW_MAP_NL_TO_BF);
1381+ req.bf.ndp_rate = ndp_rate;
1382+ req.bf.ndpa_rate = ndpa_rate;
1383+ req.bf.rept_poll_rate = rept_poll_rate;
1384+ req.bf.bw = bf_bw;
1385+ req.bf.tx_mode = (td->tx_rate_mode == MT76_TM_TX_MODE_EHT_SU) ? 0xf : req.bf.tx_mode;
1386+
1387+ if (ebf) {
1388+ req.bf.mem[0].row = 0;
1389+ req.bf.mem[1].row = 1;
1390+ req.bf.mem[2].row = 2;
1391+ req.bf.mem[3].row = 3;
1392+ } else {
1393+ req.bf.mem[0].row = 4;
1394+ req.bf.mem[1].row = 5;
1395+ req.bf.mem[2].row = 6;
1396+ req.bf.mem[3].row = 7;
1397+ }
1398+
1399+ return mt76_mcu_send_msg(&dev->mt76, MCU_WMWA_UNI_CMD(STA_REC_UPDATE), &req,
1400+ sizeof(req), true);
1401+}
1402+
1403+static int
1404+mt7996_tm_txbf_profile_update(struct mt7996_phy *phy, u16 *val, bool ebf)
1405+{
1406+#define MT_ARB_IBF_ENABLE (BIT(0) | GENMASK(9, 8))
1407+ struct mt76_testmode_data *td = &phy->mt76->test;
1408+ struct mt7996_dev *dev = phy->dev;
1409+ struct mt7996_pfmu_tag *tag = dev->test.txbf_pfmu_tag;
1410+ u8 rate, pfmu_idx = val[0], nc = val[2], nr;
1411+ int ret;
1412+ bool is_atenl = val[5];
1413+
1414+ if (td->tx_antenna_mask == 3)
1415+ nr = 1;
1416+ else if (td->tx_antenna_mask == 7)
1417+ nr = 2;
1418+ else if (td->tx_antenna_mask == 31)
1419+ nr = 4;
1420+ else
1421+ nr = 3;
1422+
1423+ memset(tag, 0, sizeof(*tag));
1424+ tag->t1.pfmu_idx = pfmu_idx;
1425+ tag->t1.ebf = ebf;
1426+ tag->t1.nr = nr;
1427+ tag->t1.nc = nc;
1428+ tag->t1.invalid_prof = true;
1429+ tag->t1.data_bw = mt7996_tm_bw_mapping(phy->mt76->chandef.width, BW_MAP_NL_TO_BF);
1430+ tag->t2.se_idx = td->tx_spe_idx;
1431+
1432+ if (ebf) {
1433+ tag->t1.row_id1 = 0;
1434+ tag->t1.row_id2 = 1;
1435+ tag->t1.row_id3 = 2;
1436+ tag->t1.row_id4 = 3;
1437+ tag->t1.lm = mt7996_tm_rate_mapping(td->tx_rate_mode, RATE_MODE_TO_LM);
1438+ } else {
1439+ tag->t1.row_id1 = 4;
1440+ tag->t1.row_id2 = 5;
1441+ tag->t1.row_id3 = 6;
1442+ tag->t1.row_id4 = 7;
1443+ rate = nr == 4 ? td->tx_rate_mode : MT76_TM_TX_MODE_OFDM;
1444+ tag->t1.lm = mt7996_tm_rate_mapping(rate, RATE_MODE_TO_LM);
1445+
1446+ tag->t2.ibf_timeout = 0xff;
1447+ tag->t2.ibf_nr = nr;
1448+ tag->t2.ibf_nc = nc;
1449+ }
1450+
1451+ ret = mt7996_tm_txbf_profile_tag_write(phy, pfmu_idx, tag);
1452+ if (ret)
1453+ return ret;
1454+
1455+ ret = mt7996_tm_add_txbf_sta(phy, pfmu_idx, nr, nc, ebf);
1456+ if (ret)
1457+ return ret;
1458+
1459+ if (!is_atenl && !td->ibf) {
1460+ mt76_set(dev, MT_ARB_TQSAXM0(phy->mt76->band_idx), MT_ARB_TQSAXM_ALTX_START_MASK);
1461+ dev_info(dev->mt76.dev, "Set TX queue start CR for AX management (0x%x) = 0x%x\n",
1462+ MT_ARB_TQSAXM0(phy->mt76->band_idx),
1463+ mt76_rr(dev, MT_ARB_TQSAXM0(phy->mt76->band_idx)));
1464+ } else if (!is_atenl && td->ibf && ebf) {
1465+ /* iBF's ebf profile update */
1466+ mt76_set(dev, MT_ARB_TQSAXM0(phy->mt76->band_idx), MT_ARB_IBF_ENABLE);
1467+ dev_info(dev->mt76.dev, "Set TX queue start CR for AX management (0x%x) = 0x%x\n",
1468+ MT_ARB_TQSAXM0(phy->mt76->band_idx),
1469+ mt76_rr(dev, MT_ARB_TQSAXM0(phy->mt76->band_idx)));
1470+ }
1471+
1472+ if (!ebf && is_atenl)
1473+ return mt7996_tm_txbf_apply_tx(phy, 1, false, true, true);
1474+
1475+ return 0;
1476+}
1477+
1478+static int
1479+mt7996_tm_txbf_phase_cal(struct mt7996_phy *phy, u16 *val)
1480+{
1481+ struct mt7996_dev *dev = phy->dev;
1482+ struct mt7996_tm_bf_req req = {
1483+ .phase_cal = {
1484+ .tag = cpu_to_le16(BF_PHASE_CALIBRATION),
1485+ .len = cpu_to_le16(sizeof(req.phase_cal)),
1486+ .group = val[0],
1487+ .group_l_m_n = val[1],
1488+ .sx2 = val[2],
1489+ .cal_type = val[3],
1490+ .lna_gain_level = val[4],
1491+ .band_idx = phy->mt76->band_idx,
1492+ .version = val[5],
1493+ },
1494+ };
1495+ struct mt7996_txbf_phase *phase = (struct mt7996_txbf_phase *)dev->test.txbf_phase_cal;
1496+
1497+ /* reset phase status before update phase cal data */
1498+ phase[req.phase_cal.group].status = 0;
1499+
1500+ return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(BF), &req,
1501+ sizeof(req), false);
1502+}
1503+
1504+static int
1505+mt7996_tm_txbf_profile_update_all(struct mt7996_phy *phy, u16 *val)
1506+{
1507+ struct mt76_testmode_data *td = &phy->mt76->test;
1508+ u8 nss = hweight8(td->tx_antenna_mask);
1509+ u16 pfmu_idx = val[0];
1510+ u16 subc_id = val[1];
1511+ u16 angle11 = val[2];
1512+ u16 angle21 = val[3];
1513+ u16 angle31 = val[4];
1514+ u16 angle41 = val[5];
1515+ u16 angle51 = val[6];
1516+ s16 phi11 = 0, phi21 = 0, phi31 = 0, phi41 = 0;
1517+ s16 *pfmu_data;
1518+ int offs = subc_id * sizeof(struct mt7996_pfmu_data) / sizeof(*pfmu_data);
1519+
1520+ if (subc_id > MT7996_TXBF_SUBCAR_NUM - 1)
1521+ return -EINVAL;
1522+
1523+ if (nss == 2) {
1524+ phi11 = (s16)(angle21 - angle11);
1525+ } else if (nss == 3) {
1526+ phi11 = (s16)(angle31 - angle11);
1527+ phi21 = (s16)(angle31 - angle21);
1528+ } else if (nss == 5) {
1529+ phi11 = (s16)(angle51 - angle11);
1530+ phi21 = (s16)(angle51 - angle21);
1531+ phi31 = (s16)(angle51 - angle31);
1532+ phi41 = (s16)(angle51 - angle41);
1533+ offs = subc_id * sizeof(struct mt7996_pfmu_data_5x5) / sizeof(*pfmu_data);
1534+ } else {
1535+ phi11 = (s16)(angle41 - angle11);
1536+ phi21 = (s16)(angle41 - angle21);
1537+ phi31 = (s16)(angle41 - angle31);
1538+ }
1539+
1540+ pfmu_data = (s16 *)phy->dev->test.txbf_pfmu_data;
1541+ pfmu_data += offs;
1542+
1543+ if (subc_id < 32)
1544+ pfmu_data[0] = cpu_to_le16(subc_id + 224);
1545+ else
1546+ pfmu_data[0] = cpu_to_le16(subc_id - 32);
1547+
1548+ pfmu_data[1] = cpu_to_le16(phi11);
1549+ pfmu_data[2] = cpu_to_le16(phi21);
1550+ pfmu_data[3] = cpu_to_le16(phi31);
1551+ if (nss == 5)
1552+ pfmu_data[4] = cpu_to_le16(phi41);
1553+
1554+ if (subc_id == MT7996_TXBF_SUBCAR_NUM - 1) {
1555+ struct mt7996_dev *dev = phy->dev;
1556+ struct mt7996_tm_bf_req req = {
1557+ .pfmu_data_all = {
1558+ .tag = cpu_to_le16(BF_PROFILE_WRITE_20M_ALL_5X5),
1559+ .len = cpu_to_le16(sizeof(req.pfmu_data_all)),
1560+ .pfmu_id = pfmu_idx,
1561+ .band_idx = phy->mt76->band_idx,
1562+ },
1563+ };
1564+ int size = MT7996_TXBF_PFMU_DATA_LEN_5X5;
1565+
1566+ if (nss != 5) {
1567+ size = MT7996_TXBF_PFMU_DATA_LEN;
1568+ req.pfmu_data_all.tag = cpu_to_le16(BF_PROFILE_WRITE_20M_ALL);
1569+ req.pfmu_data_all.len = cpu_to_le16(sizeof(req.pfmu_data_all) -
1570+ MT7996_TXBF_PFMU_DATA_LEN_5X5 + size);
1571+ }
1572+ memcpy(req.pfmu_data_all.buf, dev->test.txbf_pfmu_data, size);
1573+
1574+ return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(BF),
1575+ &req, sizeof(req), true);
1576+ }
1577+
1578+ return 0;
1579+}
1580+
1581+static int
1582+mt7996_tm_txbf_e2p_update(struct mt7996_phy *phy)
1583+{
1584+#define TXBF_PHASE_EEPROM_START_OFFSET 0xc00
1585+#define TXBF_PHASE_GROUP_EEPROM_OFFSET_VER_1 46
1586+#define TXBF_PHASE_G0_EEPROM_OFFSET_VER_2 sizeof(struct mt7992_txbf_phase_info_2g)
1587+#define TXBF_PHASE_GX_EEPROM_OFFSET_VER_2 sizeof(struct mt7992_txbf_phase_info_5g)
1588+ struct mt7996_txbf_phase *phase, *p;
1589+ struct mt7996_dev *dev = phy->dev;
1590+ u8 *eeprom = dev->mt76.eeprom.data;
1591+ u16 offset;
1592+ int i;
1593+
1594+ offset = TXBF_PHASE_EEPROM_START_OFFSET;
1595+ phase = (struct mt7996_txbf_phase *)dev->test.txbf_phase_cal;
1596+ for (i = 0; i < MAX_PHASE_GROUP_NUM; i++) {
1597+ p = &phase[i];
1598+
1599+ if (!p->status)
1600+ continue;
1601+
1602+ /* copy phase cal data to eeprom */
1603+ mt7996_tm_txbf_phase_copy(dev, eeprom + offset, p->buf, i);
1604+ if (get_ibf_version(dev) == IBF_VER_1)
1605+ offset += TXBF_PHASE_GROUP_EEPROM_OFFSET_VER_1;
1606+ else
1607+ offset += i ? TXBF_PHASE_GX_EEPROM_OFFSET_VER_2 :
1608+ TXBF_PHASE_G0_EEPROM_OFFSET_VER_2;
1609+ }
1610+
1611+ return 0;
1612+}
1613+
1614+static int
1615+mt7996_tm_txbf_apply_tx(struct mt7996_phy *phy, u16 wlan_idx, bool ebf,
1616+ bool ibf, bool phase_cal)
1617+{
1618+ struct mt7996_dev *dev = phy->dev;
1619+ struct mt7996_tm_bf_req req = {
1620+ .tx_apply = {
1621+ .tag = cpu_to_le16(BF_DATA_PACKET_APPLY),
1622+ .len = cpu_to_le16(sizeof(req.tx_apply)),
1623+ .wlan_idx = cpu_to_le16(wlan_idx),
1624+ .ebf = ebf,
1625+ .ibf = ibf,
1626+ .phase_cal = phase_cal,
1627+ },
1628+ };
1629+
1630+ return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(BF), &req, sizeof(req), false);
1631+}
1632+
1633+static int
1634+mt7996_tm_txbf_set_tx(struct mt7996_phy *phy, u16 *val)
1635+{
1636+ bool bf_on = val[0], update = val[3];
1637+ struct mt7996_dev *dev = phy->dev;
1638+ struct mt7996_pfmu_tag *tag = dev->test.txbf_pfmu_tag;
1639+ struct mt76_testmode_data *td = &phy->mt76->test;
1640+
1641+ if (bf_on) {
1642+ mt7996_tm_set_rx_frames(phy, false);
1643+ mt7996_tm_set_tx_frames(phy, false);
1644+ mt7996_mcu_set_txbf_internal(phy, BF_PFMU_TAG_READ, 2, true);
1645+ tag->t1.invalid_prof = false;
1646+ mt7996_tm_txbf_profile_tag_write(phy, 2, tag);
1647+ td->bf_ever_en = true;
1648+
1649+ if (update)
1650+ mt7996_tm_txbf_apply_tx(phy, 1, 0, 1, 1);
1651+ } else {
1652+ if (!td->bf_ever_en) {
1653+ mt7996_tm_set_rx_frames(phy, false);
1654+ mt7996_tm_set_tx_frames(phy, false);
1655+ td->ibf = false;
1656+ td->ebf = false;
1657+
1658+ if (update)
1659+ mt7996_tm_txbf_apply_tx(phy, 1, 0, 0, 0);
1660+ } else {
1661+ td->bf_ever_en = false;
1662+
1663+ mt7996_mcu_set_txbf_internal(phy, BF_PFMU_TAG_READ, 2, true);
1664+ tag->t1.invalid_prof = true;
1665+ mt7996_tm_txbf_profile_tag_write(phy, 2, tag);
1666+ }
1667+ }
1668+
1669+ return 0;
1670+}
1671+
1672+static int
1673+mt7996_tm_trigger_sounding(struct mt7996_phy *phy, u16 *val, bool en)
1674+{
1675+ struct mt7996_dev *dev = phy->dev;
1676+ u8 sounding_mode = val[0];
1677+ u8 sta_num = val[1];
1678+ u32 sounding_interval = (u32)val[2] << 2; /* input unit: 4ms */
1679+ u16 tag = en ? BF_SOUNDING_ON : BF_SOUNDING_OFF;
1680+ struct mt7996_tm_bf_req req = {
1681+ .sounding = {
1682+ .tag = cpu_to_le16(tag),
1683+ .len = cpu_to_le16(sizeof(req.sounding)),
1684+ .snd_mode = sounding_mode,
1685+ .sta_num = sta_num,
1686+ .wlan_id = {
1687+ cpu_to_le16(val[3]),
1688+ cpu_to_le16(val[4]),
1689+ cpu_to_le16(val[5]),
1690+ cpu_to_le16(val[6])
1691+ },
1692+ .snd_period = cpu_to_le32(sounding_interval),
1693+ },
1694+ };
1695+
1696+ if (sounding_mode > SOUNDING_MODE_MAX)
1697+ return -EINVAL;
1698+
1699+ return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(BF),
1700+ &req, sizeof(req), false);
1701+}
1702+
1703+static int
1704+mt7996_tm_txbf_txcmd(struct mt7996_phy *phy, u16 *val)
1705+{
1706+ struct mt7996_dev *dev = phy->dev;
1707+ struct mt7996_tm_bf_req req = {
1708+ .txcmd = {
1709+ .tag = cpu_to_le16(BF_CMD_TXCMD),
1710+ .len = cpu_to_le16(sizeof(req.txcmd)),
1711+ .action = val[0],
1712+ .bf_manual = val[1],
1713+ .bf_bit = val[2],
1714+ },
1715+ };
1716+
1717+ return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(BF), &req, sizeof(req), false);
1718+}
1719+
1720+static int
1721+mt7996_tm_set_txbf(struct mt7996_phy *phy)
1722+{
1723+#define TXBF_IS_DUT_MASK BIT(0)
1724+#define TXBF_IBF_MASK BIT(1)
1725+ struct mt76_testmode_data *td = &phy->mt76->test;
1726+ u16 *val = td->txbf_param;
1727+
1728+ dev_info(phy->dev->mt76.dev,
1729+ "ibf cal process: act = %u, val = %u, %u, %u, %u, %u, %u, %u, %u\n",
1730+ td->txbf_act, val[0], val[1], val[2], val[3], val[4], val[5], val[6], val[7]);
1731+
1732+ switch (td->txbf_act) {
1733+ case MT76_TM_TXBF_ACT_GOLDEN_INIT:
1734+ case MT76_TM_TXBF_ACT_INIT:
1735+ case MT76_TM_TX_EBF_ACT_GOLDEN_INIT:
1736+ case MT76_TM_TX_EBF_ACT_INIT:
1737+ td->ibf = !u32_get_bits(td->txbf_act, TXBF_IBF_MASK);
1738+ td->ebf = true;
1739+ td->is_txbf_dut = !!u32_get_bits(td->txbf_act, TXBF_IS_DUT_MASK);
1740+ return mt7996_tm_txbf_init(phy, val);
1741+ case MT76_TM_TXBF_ACT_UPDATE_CH:
1742+ mt7996_tm_update_channel(phy);
1743+ break;
1744+ case MT76_TM_TXBF_ACT_PHASE_COMP:
1745+ return mt7996_tm_txbf_phase_comp(phy, val);
1746+ case MT76_TM_TXBF_ACT_TX_PREP:
1747+ return mt7996_tm_txbf_set_tx(phy, val);
1748+ case MT76_TM_TXBF_ACT_IBF_PROF_UPDATE:
1749+ return mt7996_tm_txbf_profile_update(phy, val, false);
1750+ case MT76_TM_TXBF_ACT_EBF_PROF_UPDATE:
1751+ return mt7996_tm_txbf_profile_update(phy, val, true);
1752+ case MT76_TM_TXBF_ACT_PHASE_CAL:
1753+ return mt7996_tm_txbf_phase_cal(phy, val);
1754+ case MT76_TM_TXBF_ACT_PROF_UPDATE_ALL_CMD:
1755+ case MT76_TM_TXBF_ACT_PROF_UPDATE_ALL:
1756+ return mt7996_tm_txbf_profile_update_all(phy, val);
1757+ case MT76_TM_TXBF_ACT_E2P_UPDATE:
1758+ return mt7996_tm_txbf_e2p_update(phy);
1759+ case MT76_TM_TXBF_ACT_APPLY_TX: {
1760+ u16 wlan_idx = val[0];
1761+ bool ebf = !!val[1], ibf = !!val[2], phase_cal = !!val[4];
1762+
1763+ return mt7996_tm_txbf_apply_tx(phy, wlan_idx, ebf, ibf, phase_cal);
1764+ }
1765+ case MT76_TM_TXBF_ACT_TRIGGER_SOUNDING:
1766+ return mt7996_tm_trigger_sounding(phy, val, true);
1767+ case MT76_TM_TXBF_ACT_STOP_SOUNDING:
1768+ memset(val, 0, sizeof(td->txbf_param));
1769+ return mt7996_tm_trigger_sounding(phy, val, false);
1770+ case MT76_TM_TXBF_ACT_PROFILE_TAG_READ:
1771+ case MT76_TM_TXBF_ACT_PROFILE_TAG_WRITE:
1772+ case MT76_TM_TXBF_ACT_PROFILE_TAG_INVALID: {
1773+ u8 pfmu_idx = val[0];
1774+ bool bfer = !!val[1];
1775+ struct mt7996_dev *dev = phy->dev;
1776+ struct mt7996_pfmu_tag *tag = dev->test.txbf_pfmu_tag;
1777+
1778+ if (!tag) {
1779+ dev_err(dev->mt76.dev,
1780+ "pfmu tag is not initialized!\n");
1781+ return 0;
1782+ }
1783+
1784+ if (td->txbf_act == MT76_TM_TXBF_ACT_PROFILE_TAG_WRITE)
1785+ return mt7996_tm_txbf_profile_tag_write(phy, pfmu_idx, tag);
1786+ else if (td->txbf_act == MT76_TM_TXBF_ACT_PROFILE_TAG_READ)
1787+ return mt7996_mcu_set_txbf_internal(phy, BF_PFMU_TAG_READ, pfmu_idx, bfer);
1788+
1789+ tag->t1.invalid_prof = !!val[0];
1790+
1791+ return 0;
1792+ }
1793+ case MT76_TM_TXBF_ACT_STA_REC_READ:
1794+ return mt7996_mcu_set_txbf_internal(phy, BF_STA_REC_READ, val[0], 0);
1795+ case MT76_TM_TXBF_ACT_TXCMD:
1796+ return mt7996_tm_txbf_txcmd(phy, val);
1797+ default:
1798+ break;
1799+ };
1800+
1801+ return 0;
1802+}
1803+
1804 static void
1805 mt7996_tm_update_params(struct mt7996_phy *phy, u32 changed)
1806 {
1807@@ -1086,6 +1822,8 @@ mt7996_tm_update_params(struct mt7996_phy *phy, u32 changed)
1808 mt7996_tm_set_ipi(phy);
1809 if (changed & BIT(TM_CHANGED_IPI_RESET))
1810 mt7996_tm_ipi_hist_ctrl(phy, NULL, RDD_SET_IPI_HIST_RESET);
1811+ if (changed & BIT(TM_CHANGED_TXBF_ACT))
1812+ mt7996_tm_set_txbf(phy);
1813 }
1814
1815 static int
1816diff --git a/mt7996/testmode.h b/mt7996/testmode.h
developer9237f442024-06-14 17:13:04 +08001817index 78662b2..f97ccb2 100644
developer66e89bc2024-04-23 14:50:01 +08001818--- a/mt7996/testmode.h
1819+++ b/mt7996/testmode.h
1820@@ -27,6 +27,17 @@ enum {
1821 FW_CDBW_8080MHZ,
1822 };
1823
1824+enum {
1825+ BF_CDBW_20MHZ,
1826+ BF_CDBW_40MHZ,
1827+ BF_CDBW_80MHZ,
1828+ BF_CDBW_160MHZ,
1829+ BF_CDBW_320MHZ,
1830+ BF_CDBW_10MHZ = BF_CDBW_320MHZ,
1831+ BF_CDBW_5MHZ,
1832+ BF_CDBW_8080MHZ,
1833+};
1834+
1835 #define FIRST_CONTROL_CHAN_BITMAP_BW40 0x5555555
1836 #define FIRST_CONTROL_CHAN_BITMAP_BW80 0x111111
1837 #define FIRST_CONTROL_CHAN_BITMAP_BW160 0x100101
1838@@ -34,12 +45,20 @@ enum {
1839 enum bw_mapping_method {
1840 BW_MAP_NL_TO_FW,
1841 BW_MAP_NL_TO_TM,
1842+ BW_MAP_NL_TO_BF,
1843 BW_MAP_NL_TO_MHZ,
1844 BW_MAP_NL_TO_CONTROL_BITMAP_5G,
1845
1846 NUM_BW_MAP,
1847 };
1848
1849+enum rate_mapping_type {
1850+ RATE_MODE_TO_PHY,
1851+ RATE_MODE_TO_LM,
1852+
1853+ NUM_RATE_MAP,
1854+};
1855+
1856 struct tm_cal_param {
1857 __le32 func_data;
1858 u8 band_idx;
1859diff --git a/testmode.c b/testmode.c
developer9237f442024-06-14 17:13:04 +08001860index 69147f8..b9f7109 100644
developer66e89bc2024-04-23 14:50:01 +08001861--- a/testmode.c
1862+++ b/testmode.c
1863@@ -462,6 +462,44 @@ out:
1864 return err;
1865 }
1866
1867+static int
1868+mt76_testmode_txbf_profile_update_all_cmd(struct mt76_phy *phy, struct nlattr **tb, u32 state)
1869+{
1870+#define PARAM_UNIT 5
1871+#define PARAM_UNIT_5X5 6
1872+ static u8 pfmu_idx;
1873+ struct mt76_testmode_data *td = &phy->test;
1874+ struct mt76_dev *dev = phy->dev;
1875+ struct nlattr *cur;
1876+ u16 tmp_val[PARAM_UNIT_5X5], *val = td->txbf_param;
1877+ int idx, rem, ret, i = 0;
1878+ int param_len = td->tx_antenna_mask == 31 ? PARAM_UNIT_5X5 : PARAM_UNIT;
1879+
1880+ memset(td->txbf_param, 0, sizeof(td->txbf_param));
1881+ nla_for_each_nested(cur, tb[MT76_TM_ATTR_TXBF_PARAM], rem) {
1882+ if (nla_len(cur) != 2)
1883+ return -EINVAL;
1884+ idx = i % param_len;
1885+ tmp_val[idx] = nla_get_u16(cur);
1886+ if (idx == 1 && (tmp_val[idx] == 0xf0 || tmp_val[idx] == 0xff)) {
1887+ pfmu_idx = tmp_val[0];
1888+ return 0;
1889+ }
1890+ if (idx == param_len - 1) {
1891+ val[0] = pfmu_idx;
1892+ memcpy(val + 1, tmp_val, param_len * sizeof(u16));
1893+ if (dev->test_ops->set_params) {
1894+ ret = dev->test_ops->set_params(phy, tb, state);
1895+ if (ret)
1896+ return ret;
1897+ }
1898+ }
1899+ i++;
1900+ }
1901+
1902+ return 0;
1903+}
1904+
1905 int mt76_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
1906 void *data, int len)
1907 {
1908@@ -607,6 +645,30 @@ int mt76_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
1909 }
1910 }
1911
1912+ if (tb[MT76_TM_ATTR_TXBF_ACT]) {
1913+ struct nlattr *cur;
1914+ int rem, idx = 0;
1915+
1916+ if (!tb[MT76_TM_ATTR_TXBF_PARAM] ||
1917+ mt76_tm_get_u8(tb[MT76_TM_ATTR_TXBF_ACT], &td->txbf_act,
1918+ 0, MT76_TM_TXBF_ACT_MAX))
1919+ goto out;
1920+
1921+ if (td->txbf_act == MT76_TM_TXBF_ACT_PROF_UPDATE_ALL_CMD) {
1922+ err = mt76_testmode_txbf_profile_update_all_cmd(phy, tb, state);
1923+ goto out;
1924+ }
1925+
1926+ memset(td->txbf_param, 0, sizeof(td->txbf_param));
1927+ nla_for_each_nested(cur, tb[MT76_TM_ATTR_TXBF_PARAM], rem) {
1928+ if (nla_len(cur) != 2 ||
1929+ idx >= ARRAY_SIZE(td->txbf_param))
1930+ goto out;
1931+
1932+ td->txbf_param[idx++] = nla_get_u16(cur);
1933+ }
1934+ }
1935+
1936 if (dev->test_ops->set_params) {
1937 err = dev->test_ops->set_params(phy, tb, state);
1938 if (err)
1939diff --git a/testmode.h b/testmode.h
developer9237f442024-06-14 17:13:04 +08001940index 5d677f8..bda7624 100644
developer66e89bc2024-04-23 14:50:01 +08001941--- a/testmode.h
1942+++ b/testmode.h
1943@@ -286,6 +286,59 @@ enum mt76_testmode_eeprom_action {
1944 MT76_TM_EEPROM_ACTION_MAX = NUM_MT76_TM_EEPROM_ACTION - 1,
1945 };
1946
1947+/**
1948+ * enum mt76_testmode_txbf_act - txbf action
1949+ *
1950+ * @MT76_TM_TXBF_ACT_GOLDEN_INIT: init ibf setting for golden device
1951+ * @MT76_TM_TXBF_ACT_INIT: init ibf setting for DUT
1952+ * @MT76_TM_TX_EBF_ACT_GOLDEN_INIT: init ebf setting for golden device
1953+ * @MT76_TM_TX_EBF_ACT_INIT: init ebf setting for DUT
1954+ * @MT76_TM_TXBF_ACT_UPDATE_CH: update channel info
1955+ * @MT76_TM_TXBF_ACT_PHASE_COMP: txbf phase compensation
1956+ * @MT76_TM_TXBF_ACT_TX_PREP: TX preparation for txbf
1957+ * @MT76_TM_TXBF_ACT_IBF_PROF_UPDATE: update ibf profile (pfmu tag, bf sta record)
1958+ * @MT76_TM_TXBF_ACT_EBF_PROF_UPDATE: update ebf profile
1959+ * @MT76_TM_TXBF_ACT_APPLY_TX: apply TX setting for txbf
1960+ * @MT76_TM_TXBF_ACT_PHASE_CAL: perform txbf phase calibration
1961+ * @MT76_TM_TXBF_ACT_PROF_UPDATE_ALL: update bf profile via instrument
1962+ * @MT76_TM_TXBF_ACT_PROF_UPDATE_ALL_CMD: update bf profile via instrument
1963+ * @MT76_TM_TXBF_ACT_E2P_UPDATE: write back txbf calibration result to eeprom
1964+ * @MT76_TM_TXBF_ACT_TRIGGER_SOUNDING: trigger beamformer to send sounding packet
1965+ * @MT76_TM_TXBF_ACT_STOP_SOUNDING: stop sending sounding packet
1966+ * @MT76_TM_TXBF_ACT_PROFILE_TAG_READ: read pfmu tag
1967+ * @MT76_TM_TXBF_ACT_PROFILE_TAG_WRITE: update pfmu tag
1968+ * @MT76_TM_TXBF_ACT_PROFILE_TAG_INVALID: invalidate pfmu tag
1969+ * @MT76_TM_TXBF_ACT_STA_REC_READ: read bf sta record
1970+ * @MT76_TM_TXBF_ACT_TXCMD: configure txcmd bf bit manually
1971+ */
1972+enum mt76_testmode_txbf_act {
1973+ MT76_TM_TXBF_ACT_GOLDEN_INIT,
1974+ MT76_TM_TXBF_ACT_INIT,
1975+ MT76_TM_TX_EBF_ACT_GOLDEN_INIT,
1976+ MT76_TM_TX_EBF_ACT_INIT,
1977+ MT76_TM_TXBF_ACT_UPDATE_CH,
1978+ MT76_TM_TXBF_ACT_PHASE_COMP,
1979+ MT76_TM_TXBF_ACT_TX_PREP,
1980+ MT76_TM_TXBF_ACT_IBF_PROF_UPDATE,
1981+ MT76_TM_TXBF_ACT_EBF_PROF_UPDATE,
1982+ MT76_TM_TXBF_ACT_APPLY_TX,
1983+ MT76_TM_TXBF_ACT_PHASE_CAL,
1984+ MT76_TM_TXBF_ACT_PROF_UPDATE_ALL,
1985+ MT76_TM_TXBF_ACT_PROF_UPDATE_ALL_CMD,
1986+ MT76_TM_TXBF_ACT_E2P_UPDATE,
1987+ MT76_TM_TXBF_ACT_TRIGGER_SOUNDING,
1988+ MT76_TM_TXBF_ACT_STOP_SOUNDING,
1989+ MT76_TM_TXBF_ACT_PROFILE_TAG_READ,
1990+ MT76_TM_TXBF_ACT_PROFILE_TAG_WRITE,
1991+ MT76_TM_TXBF_ACT_PROFILE_TAG_INVALID,
1992+ MT76_TM_TXBF_ACT_STA_REC_READ,
1993+ MT76_TM_TXBF_ACT_TXCMD,
1994+
1995+ /* keep last */
1996+ NUM_MT76_TM_TXBF_ACT,
1997+ MT76_TM_TXBF_ACT_MAX = NUM_MT76_TM_TXBF_ACT - 1,
1998+};
1999+
2000 extern const struct nla_policy mt76_tm_policy[NUM_MT76_TM_ATTRS];
2001
2002 #endif
2003diff --git a/tools/fields.c b/tools/fields.c
developer9237f442024-06-14 17:13:04 +08002004index 77696ce..f793d1a 100644
developer66e89bc2024-04-23 14:50:01 +08002005--- a/tools/fields.c
2006+++ b/tools/fields.c
2007@@ -44,6 +44,30 @@ static const char * const testmode_offchan_bw[] = {
2008 [NL80211_CHAN_WIDTH_160] = "160",
2009 };
2010
2011+static const char * const testmode_txbf_act[] = {
2012+ [MT76_TM_TXBF_ACT_GOLDEN_INIT] = "golden_init",
2013+ [MT76_TM_TXBF_ACT_INIT] = "init",
2014+ [MT76_TM_TX_EBF_ACT_GOLDEN_INIT] = "ebf_golden_init",
2015+ [MT76_TM_TX_EBF_ACT_INIT] = "ebf_init",
2016+ [MT76_TM_TXBF_ACT_UPDATE_CH] = "update_ch",
2017+ [MT76_TM_TXBF_ACT_PHASE_COMP] = "phase_comp",
2018+ [MT76_TM_TXBF_ACT_TX_PREP] = "tx_prep",
2019+ [MT76_TM_TXBF_ACT_IBF_PROF_UPDATE] = "ibf_prof_update",
2020+ [MT76_TM_TXBF_ACT_EBF_PROF_UPDATE] = "ebf_prof_update",
2021+ [MT76_TM_TXBF_ACT_APPLY_TX] = "apply_tx",
2022+ [MT76_TM_TXBF_ACT_PHASE_CAL] = "phase_cal",
2023+ [MT76_TM_TXBF_ACT_PROF_UPDATE_ALL] = "prof_update",
2024+ [MT76_TM_TXBF_ACT_PROF_UPDATE_ALL_CMD] = "prof_update_all",
2025+ [MT76_TM_TXBF_ACT_E2P_UPDATE] = "e2p_update",
2026+ [MT76_TM_TXBF_ACT_TRIGGER_SOUNDING] = "trigger_sounding",
2027+ [MT76_TM_TXBF_ACT_STOP_SOUNDING] = "stop_sounding",
2028+ [MT76_TM_TXBF_ACT_PROFILE_TAG_READ] = "pfmu_tag_read",
2029+ [MT76_TM_TXBF_ACT_PROFILE_TAG_WRITE] = "pfmu_tag_write",
2030+ [MT76_TM_TXBF_ACT_PROFILE_TAG_INVALID] = "set_invalid_prof",
2031+ [MT76_TM_TXBF_ACT_STA_REC_READ] = "sta_rec_read",
2032+ [MT76_TM_TXBF_ACT_TXCMD] = "txcmd",
2033+};
2034+
2035 static void print_enum(const struct tm_field *field, struct nlattr *attr)
2036 {
2037 unsigned int i = nla_get_u8(attr);
2038@@ -94,6 +118,17 @@ static void print_s8(const struct tm_field *field, struct nlattr *attr)
2039 printf("%d", (int8_t)nla_get_u8(attr));
2040 }
2041
2042+static bool parse_u16_hex(const struct tm_field *field, int idx,
2043+ struct nl_msg *msg, const char *val)
2044+{
2045+ return !nla_put_u16(msg, idx, strtoul(val, NULL, 16));
2046+}
2047+
2048+static void print_u16_hex(const struct tm_field *field, struct nlattr *attr)
2049+{
2050+ printf("%d", nla_get_u16(attr));
2051+}
2052+
2053 static bool parse_u32(const struct tm_field *field, int idx,
2054 struct nl_msg *msg, const char *val)
2055 {
2056@@ -399,6 +434,8 @@ static const struct tm_field testdata_fields[NUM_MT76_TM_ATTRS] = {
2057 FIELD(u8, AID, "aid"),
2058 FIELD(u8, RU_ALLOC, "ru_alloc"),
2059 FIELD(u8, RU_IDX, "ru_idx"),
2060+ FIELD_ENUM(TXBF_ACT, "txbf_act", testmode_txbf_act),
2061+ FIELD_ARRAY(u16_hex, TXBF_PARAM, "txbf_param"),
2062 FIELD(u8, OFF_CH_SCAN_CH, "offchan_ch"),
2063 FIELD(u8, OFF_CH_SCAN_CENTER_CH, "offchan_center_ch"),
2064 FIELD_ENUM(OFF_CH_SCAN_BW, "offchan_bw", testmode_offchan_bw),
2065--
developer9237f442024-06-14 17:13:04 +080020662.18.0
developer66e89bc2024-04-23 14:50:01 +08002067