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