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