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