1 /******************************************************************************
2 *
3 * Copyright(c) 2016 - 2019 Realtek Corporation. All rights reserved.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 ******************************************************************************/
15
16 #include "halmac_mimo_88xx.h"
17 #include "halmac_88xx_cfg.h"
18 #include "halmac_common_88xx.h"
19 #include "halmac_init_88xx.h"
20
21 #if HALMAC_88XX_SUPPORT
22
23 #define TXBF_CTRL_CFG (BIT_R_ENABLE_NDPA | BIT_USE_NDPA_PARAMETER | \
24 BIT_R_EN_NDPA_INT | BIT_DIS_NDP_BFEN)
25 #define CSI_RATE_MAP 0x55
26
27 static void
28 cfg_mu_bfee_88xx(struct halmac_adapter *adapter,
29 struct halmac_cfg_mumimo_para *param);
30
31 static void
32 cfg_mu_bfer_88xx(struct halmac_adapter *adapter,
33 struct halmac_cfg_mumimo_para *param);
34
35 static enum halmac_cmd_construct_state
36 fw_snding_cmd_cnstr_state_88xx(struct halmac_adapter *adapter);
37
38 static enum halmac_ret_status
39 cnv_fw_snding_state_88xx(struct halmac_adapter *adapter,
40 enum halmac_cmd_construct_state dest_state);
41
42 static u8
43 snding_pkt_chk_88xx(struct halmac_adapter *adapter, u8 *pkt);
44
45 /**
46 * cfg_txbf_88xx() - enable/disable specific user's txbf
47 * @adapter : the adapter of halmac
48 * @userid : su bfee userid = 0 or 1 to apply TXBF
49 * @bw : the sounding bandwidth
50 * @txbf_en : 0: disable TXBF, 1: enable TXBF
51 * Author : chunchu
52 * Return : enum halmac_ret_status
53 * More details of status code can be found in prototype document
54 */
55 enum halmac_ret_status
cfg_txbf_88xx(struct halmac_adapter * adapter,u8 userid,enum halmac_bw bw,u8 txbf_en)56 cfg_txbf_88xx(struct halmac_adapter *adapter, u8 userid, enum halmac_bw bw,
57 u8 txbf_en)
58 {
59 u16 tmp42c = 0;
60 struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
61
62 if (txbf_en) {
63 switch (bw) {
64 case HALMAC_BW_80:
65 tmp42c |= BIT_R_TXBF0_80M;
66 fallthrough;
67 case HALMAC_BW_40:
68 tmp42c |= BIT_R_TXBF0_40M;
69 fallthrough;
70 case HALMAC_BW_20:
71 tmp42c |= BIT_R_TXBF0_20M;
72 break;
73 default:
74 return HALMAC_RET_INVALID_SOUNDING_SETTING;
75 }
76 }
77
78 switch (userid) {
79 case 0:
80 tmp42c |= HALMAC_REG_R16(REG_TXBF_CTRL) &
81 ~(BIT_R_TXBF0_20M | BIT_R_TXBF0_40M | BIT_R_TXBF0_80M);
82 HALMAC_REG_W16(REG_TXBF_CTRL, tmp42c);
83 break;
84 case 1:
85 tmp42c |= HALMAC_REG_R16(REG_TXBF_CTRL + 2) &
86 ~(BIT_R_TXBF0_20M | BIT_R_TXBF0_40M | BIT_R_TXBF0_80M);
87 HALMAC_REG_W16(REG_TXBF_CTRL + 2, tmp42c);
88 break;
89 default:
90 return HALMAC_RET_INVALID_SOUNDING_SETTING;
91 }
92
93 PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
94
95 return HALMAC_RET_SUCCESS;
96 }
97
98 /**
99 * cfg_mumimo_88xx() -config mumimo
100 * @adapter : the adapter of halmac
101 * @param : parameters to configure MU PPDU Tx/Rx
102 * Author : chunchu
103 * Return : enum halmac_ret_status
104 * More details of status code can be found in prototype document
105 */
106 enum halmac_ret_status
cfg_mumimo_88xx(struct halmac_adapter * adapter,struct halmac_cfg_mumimo_para * param)107 cfg_mumimo_88xx(struct halmac_adapter *adapter,
108 struct halmac_cfg_mumimo_para *param)
109 {
110 if (param->role == HAL_BFEE)
111 cfg_mu_bfee_88xx(adapter, param);
112 else
113 cfg_mu_bfer_88xx(adapter, param);
114
115 PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
116
117 return HALMAC_RET_SUCCESS;
118 }
119
120 static void
cfg_mu_bfee_88xx(struct halmac_adapter * adapter,struct halmac_cfg_mumimo_para * param)121 cfg_mu_bfee_88xx(struct halmac_adapter *adapter,
122 struct halmac_cfg_mumimo_para *param)
123 {
124 u8 mu_tbl_sel;
125 u8 tmp14c0;
126 struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
127
128 tmp14c0 = HALMAC_REG_R8(REG_MU_TX_CTL) & ~BIT_MASK_R_MU_TABLE_VALID;
129 HALMAC_REG_W8(REG_MU_TX_CTL, (tmp14c0 | BIT(0) | BIT(1)) & ~(BIT(7)));
130
131 /*config GID valid table and user position table*/
132 mu_tbl_sel = HALMAC_REG_R8(REG_MU_TX_CTL + 1) & 0xF8;
133
134 HALMAC_REG_W8(REG_MU_TX_CTL + 1, mu_tbl_sel);
135 HALMAC_REG_W32(REG_MU_STA_GID_VLD, param->given_gid_tab[0]);
136 HALMAC_REG_W32(REG_MU_STA_USER_POS_INFO, param->given_user_pos[0]);
137 HALMAC_REG_W32(REG_MU_STA_USER_POS_INFO + 4, param->given_user_pos[1]);
138
139 HALMAC_REG_W8(REG_MU_TX_CTL + 1, mu_tbl_sel | 1);
140 HALMAC_REG_W32(REG_MU_STA_GID_VLD, param->given_gid_tab[1]);
141 HALMAC_REG_W32(REG_MU_STA_USER_POS_INFO, param->given_user_pos[2]);
142 HALMAC_REG_W32(REG_MU_STA_USER_POS_INFO + 4, param->given_user_pos[3]);
143 }
144
145 static void
cfg_mu_bfer_88xx(struct halmac_adapter * adapter,struct halmac_cfg_mumimo_para * param)146 cfg_mu_bfer_88xx(struct halmac_adapter *adapter,
147 struct halmac_cfg_mumimo_para *param)
148 {
149 u8 i;
150 u8 idx;
151 u8 id0;
152 u8 id1;
153 u8 gid;
154 u8 mu_tbl_sel;
155 u8 mu_tbl_valid = 0;
156 u32 gid_valid[6] = {0};
157 struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
158
159 if (param->mu_tx_en == 0) {
160 HALMAC_REG_W8(REG_MU_TX_CTL,
161 HALMAC_REG_R8(REG_MU_TX_CTL) & ~(BIT(7)));
162 return;
163 }
164
165 for (idx = 0; idx < 15; idx++) {
166 if (idx < 5) {
167 /*grouping_bitmap bit0~4, MU_STA0 with MUSTA1~5*/
168 id0 = 0;
169 id1 = (u8)(idx + 1);
170 } else if (idx < 9) {
171 /*grouping_bitmap bit5~8, MU_STA1 with MUSTA2~5*/
172 id0 = 1;
173 id1 = (u8)(idx - 3);
174 } else if (idx < 12) {
175 /*grouping_bitmap bit9~11, MU_STA2 with MUSTA3~5*/
176 id0 = 2;
177 id1 = (u8)(idx - 6);
178 } else if (idx < 14) {
179 /*grouping_bitmap bit12~13, MU_STA3 with MUSTA4~5*/
180 id0 = 3;
181 id1 = (u8)(idx - 8);
182 } else {
183 /*grouping_bitmap bit14, MU_STA4 with MUSTA5*/
184 id0 = 4;
185 id1 = (u8)(idx - 9);
186 }
187 if (param->grouping_bitmap & BIT(idx)) {
188 /*Pair 1*/
189 gid = (idx << 1) + 1;
190 gid_valid[id0] |= (BIT(gid));
191 gid_valid[id1] |= (BIT(gid));
192 /*Pair 2*/
193 gid += 1;
194 gid_valid[id0] |= (BIT(gid));
195 gid_valid[id1] |= (BIT(gid));
196 } else {
197 /*Pair 1*/
198 gid = (idx << 1) + 1;
199 gid_valid[id0] &= ~(BIT(gid));
200 gid_valid[id1] &= ~(BIT(gid));
201 /*Pair 2*/
202 gid += 1;
203 gid_valid[id0] &= ~(BIT(gid));
204 gid_valid[id1] &= ~(BIT(gid));
205 }
206 }
207
208 /*set MU STA GID valid TABLE*/
209 mu_tbl_sel = HALMAC_REG_R8(REG_MU_TX_CTL + 1) & 0xF8;
210 for (idx = 0; idx < 6; idx++) {
211 HALMAC_REG_W8(REG_MU_TX_CTL + 1, idx | mu_tbl_sel);
212 HALMAC_REG_W32(REG_MU_STA_GID_VLD, gid_valid[idx]);
213 }
214
215 /*To validate the sounding successful MU STA and enable MU TX*/
216 for (i = 0; i < 6; i++) {
217 if (param->sounding_sts[i] == 1)
218 mu_tbl_valid |= BIT(i);
219 }
220 HALMAC_REG_W8(REG_MU_TX_CTL, mu_tbl_valid | BIT(7));
221 }
222
223 /**
224 * cfg_sounding_88xx() - configure general sounding
225 * @adapter : the adapter of halmac
226 * @role : driver's role, BFer or BFee
227 * @rate : set ndpa tx rate if driver is BFer,
228 * or set csi response rate if driver is BFee
229 * Author : chunchu
230 * Return : enum halmac_ret_status
231 * More details of status code can be found in prototype document
232 */
233 enum halmac_ret_status
cfg_sounding_88xx(struct halmac_adapter * adapter,enum halmac_snd_role role,enum halmac_data_rate rate)234 cfg_sounding_88xx(struct halmac_adapter *adapter, enum halmac_snd_role role,
235 enum halmac_data_rate rate)
236 {
237 struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
238 u32 tmp6dc = 0;
239 u8 csi_rsc = 0x0;
240
241 /*use ndpa rx rate to decide csi rate*/
242 tmp6dc = HALMAC_REG_R32(REG_BBPSF_CTRL) | BIT_WMAC_USE_NDPARATE
243 | (csi_rsc << 13);
244
245 switch (role) {
246 case HAL_BFER:
247 HALMAC_REG_W32_SET(REG_TXBF_CTRL, TXBF_CTRL_CFG);
248 HALMAC_REG_W8(REG_NDPA_RATE, rate);
249 HALMAC_REG_W8(REG_SND_PTCL_CTRL + 1, 0x2 | BIT(7));
250 HALMAC_REG_W8(REG_SND_PTCL_CTRL + 2, 0x2);
251 break;
252 case HAL_BFEE:
253 HALMAC_REG_W8(REG_SND_PTCL_CTRL, 0xDB);
254 HALMAC_REG_W8(REG_SND_PTCL_CTRL + 3, 0x3A);
255 HALMAC_REG_W8_CLR(REG_RXFLTMAP1, BIT(4));
256 HALMAC_REG_W8_CLR(REG_RXFLTMAP4, BIT(4));
257 #if (HALMAC_8822C_SUPPORT || HALMAC_8812F_SUPPORT)
258 if (adapter->chip_id == HALMAC_CHIP_ID_8822C)
259 HALMAC_REG_W32(REG_CSI_RRSR,
260 BIT_CSI_RRSC_BITMAP(CSI_RATE_MAP) |
261 BIT_OFDM_LEN_TH(0));
262 else if (adapter->chip_id == HALMAC_CHIP_ID_8812F)
263 HALMAC_REG_W32(REG_CSI_RRSR,
264 BIT_CSI_RRSC_BITMAP(CSI_RATE_MAP) |
265 BIT_OFDM_LEN_TH(3));
266 #endif
267 break;
268 default:
269 return HALMAC_RET_INVALID_SOUNDING_SETTING;
270 }
271
272 /*AP mode set tx gid to 63*/
273 /*STA mode set tx gid to 0*/
274 if (BIT_GET_NETYPE0(HALMAC_REG_R32(REG_CR)) == 0x3)
275 HALMAC_REG_W32(REG_BBPSF_CTRL, tmp6dc | BIT(12));
276 else
277 HALMAC_REG_W32(REG_BBPSF_CTRL, tmp6dc & ~(BIT(12)));
278
279 PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
280
281 return HALMAC_RET_SUCCESS;
282 }
283
284 /**
285 * del_sounding_88xx() - reset general sounding
286 * @adapter : the adapter of halmac
287 * @role : driver's role, BFer or BFee
288 * Author : chunchu
289 * Return : enum halmac_ret_status
290 * More details of status code can be found in prototype document
291 */
292 enum halmac_ret_status
del_sounding_88xx(struct halmac_adapter * adapter,enum halmac_snd_role role)293 del_sounding_88xx(struct halmac_adapter *adapter, enum halmac_snd_role role)
294 {
295 struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
296
297 switch (role) {
298 case HAL_BFER:
299 HALMAC_REG_W8(REG_TXBF_CTRL + 3, 0);
300 break;
301 case HAL_BFEE:
302 HALMAC_REG_W8(REG_SND_PTCL_CTRL, 0);
303 break;
304 default:
305 return HALMAC_RET_INVALID_SOUNDING_SETTING;
306 }
307
308 PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
309
310 return HALMAC_RET_SUCCESS;
311 }
312
313 /**
314 * su_bfee_entry_init_88xx() - config SU beamformee's registers
315 * @adapter : the adapter of halmac
316 * @userid : SU bfee userid = 0 or 1 to be added
317 * @paid : partial AID of this bfee
318 * Author : chunchu
319 * Return : enum halmac_ret_status
320 * More details of status code can be found in prototype document
321 */
322 enum halmac_ret_status
su_bfee_entry_init_88xx(struct halmac_adapter * adapter,u8 userid,u16 paid)323 su_bfee_entry_init_88xx(struct halmac_adapter *adapter, u8 userid, u16 paid)
324 {
325 u16 tmp42c = 0;
326 u16 tmp168x = 0;
327 struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
328
329 switch (userid) {
330 case 0:
331 tmp42c = HALMAC_REG_R16(REG_TXBF_CTRL) &
332 ~(BIT_MASK_R_TXBF0_AID | BIT_R_TXBF0_20M |
333 BIT_R_TXBF0_40M | BIT_R_TXBF0_80M);
334 HALMAC_REG_W16(REG_TXBF_CTRL, tmp42c | paid);
335 HALMAC_REG_W16(REG_ASSOCIATED_BFMEE_SEL, paid);
336 #if HALMAC_8822C_SUPPORT
337 if (adapter->chip_id == HALMAC_CHIP_ID_8822C)
338 HALMAC_REG_W16(REG_ASSOCIATED_BFMEE_SEL, paid | BIT(9));
339 #endif
340 break;
341 case 1:
342 tmp42c = HALMAC_REG_R16(REG_TXBF_CTRL + 2) &
343 ~(BIT_MASK_R_TXBF1_AID | BIT_R_TXBF0_20M |
344 BIT_R_TXBF0_40M | BIT_R_TXBF0_80M);
345 HALMAC_REG_W16(REG_TXBF_CTRL + 2, tmp42c | paid);
346 HALMAC_REG_W16(REG_ASSOCIATED_BFMEE_SEL + 2, paid | BIT(9));
347 break;
348 case 2:
349 tmp168x = HALMAC_REG_R16(REG_WMAC_ASSOCIATED_MU_BFMEE2);
350 tmp168x = BIT_CLEAR_WMAC_MU_BFEE2_AID(tmp168x);
351 tmp168x |= (paid | BIT(9));
352 HALMAC_REG_W16(REG_WMAC_ASSOCIATED_MU_BFMEE2, tmp168x);
353 break;
354 case 3:
355 tmp168x = HALMAC_REG_R16(REG_WMAC_ASSOCIATED_MU_BFMEE3);
356 tmp168x = BIT_CLEAR_WMAC_MU_BFEE3_AID(tmp168x);
357 tmp168x |= (paid | BIT(9));
358 HALMAC_REG_W16(REG_WMAC_ASSOCIATED_MU_BFMEE3, tmp168x);
359 break;
360 case 4:
361 tmp168x = HALMAC_REG_R16(REG_WMAC_ASSOCIATED_MU_BFMEE4);
362 tmp168x = BIT_CLEAR_WMAC_MU_BFEE4_AID(tmp168x);
363 tmp168x |= (paid | BIT(9));
364 HALMAC_REG_W16(REG_WMAC_ASSOCIATED_MU_BFMEE4, tmp168x);
365 break;
366 case 5:
367 tmp168x = HALMAC_REG_R16(REG_WMAC_ASSOCIATED_MU_BFMEE5);
368 tmp168x = BIT_CLEAR_WMAC_MU_BFEE5_AID(tmp168x);
369 tmp168x |= (paid | BIT(9));
370 HALMAC_REG_W16(REG_WMAC_ASSOCIATED_MU_BFMEE5, tmp168x);
371 break;
372 default:
373 return HALMAC_RET_INVALID_SOUNDING_SETTING;
374 }
375
376 PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
377
378 return HALMAC_RET_SUCCESS;
379 }
380
381 /**
382 * su_bfee_entry_init_88xx() - config SU beamformer's registers
383 * @adapter : the adapter of halmac
384 * @param : parameters to configure SU BFER entry
385 * Author : chunchu
386 * Return : enum halmac_ret_status
387 * More details of status code can be found in prototype document
388 */
389 enum halmac_ret_status
su_bfer_entry_init_88xx(struct halmac_adapter * adapter,struct halmac_su_bfer_init_para * param)390 su_bfer_entry_init_88xx(struct halmac_adapter *adapter,
391 struct halmac_su_bfer_init_para *param)
392 {
393 u16 mac_addr_h;
394 u32 mac_addr_l;
395 struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
396
397 mac_addr_l = rtk_le32_to_cpu(param->bfer_address.addr_l_h.low);
398 mac_addr_h = rtk_le16_to_cpu(param->bfer_address.addr_l_h.high);
399
400 switch (param->userid) {
401 case 0:
402 HALMAC_REG_W32(REG_ASSOCIATED_BFMER0_INFO, mac_addr_l);
403 HALMAC_REG_W16(REG_ASSOCIATED_BFMER0_INFO + 4, mac_addr_h);
404 HALMAC_REG_W16(REG_ASSOCIATED_BFMER0_INFO + 6, param->paid);
405 HALMAC_REG_W16(REG_TX_CSI_RPT_PARAM_BW20, param->csi_para);
406 break;
407 case 1:
408 HALMAC_REG_W32(REG_ASSOCIATED_BFMER1_INFO, mac_addr_l);
409 HALMAC_REG_W16(REG_ASSOCIATED_BFMER1_INFO + 4, mac_addr_h);
410 HALMAC_REG_W16(REG_ASSOCIATED_BFMER1_INFO + 6, param->paid);
411 HALMAC_REG_W16(REG_TX_CSI_RPT_PARAM_BW20 + 2, param->csi_para);
412 break;
413 default:
414 return HALMAC_RET_INVALID_SOUNDING_SETTING;
415 }
416
417 PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
418
419 return HALMAC_RET_SUCCESS;
420 }
421
422 /**
423 * mu_bfee_entry_init_88xx() - config MU beamformee's registers
424 * @adapter : the adapter of halmac
425 * @param : parameters to configure MU BFEE entry
426 * Author : chunchu
427 * Return : enum halmac_ret_status
428 * More details of status code can be found in prototype document
429 */
430 enum halmac_ret_status
mu_bfee_entry_init_88xx(struct halmac_adapter * adapter,struct halmac_mu_bfee_init_para * param)431 mu_bfee_entry_init_88xx(struct halmac_adapter *adapter,
432 struct halmac_mu_bfee_init_para *param)
433 {
434 u16 tmp168x = 0;
435 u16 tmp14c0;
436 struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
437
438 tmp168x |= param->paid | BIT(9);
439 HALMAC_REG_W16((0x1680 + param->userid * 2), tmp168x);
440
441 tmp14c0 = HALMAC_REG_R16(REG_MU_TX_CTL) & ~(BIT(8) | BIT(9) | BIT(10));
442 HALMAC_REG_W16(REG_MU_TX_CTL, tmp14c0 | ((param->userid - 2) << 8));
443 HALMAC_REG_W32(REG_MU_STA_GID_VLD, 0);
444 HALMAC_REG_W32(REG_MU_STA_USER_POS_INFO, param->user_position_l);
445 HALMAC_REG_W32(REG_MU_STA_USER_POS_INFO + 4, param->user_position_h);
446
447 PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
448
449 return HALMAC_RET_SUCCESS;
450 }
451
452 /**
453 * mu_bfer_entry_init_88xx() - config MU beamformer's registers
454 * @adapter : the adapter of halmac
455 * @param : parameters to configure MU BFER entry
456 * Author : chunchu
457 * Return : enum halmac_ret_status
458 * More details of status code can be found in prototype document
459 */
460 enum halmac_ret_status
mu_bfer_entry_init_88xx(struct halmac_adapter * adapter,struct halmac_mu_bfer_init_para * param)461 mu_bfer_entry_init_88xx(struct halmac_adapter *adapter,
462 struct halmac_mu_bfer_init_para *param)
463 {
464 u16 tmp1680 = 0;
465 u16 mac_addr_h;
466 u32 mac_addr_l;
467 struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
468
469 mac_addr_l = rtk_le32_to_cpu(param->bfer_address.addr_l_h.low);
470 mac_addr_h = rtk_le16_to_cpu(param->bfer_address.addr_l_h.high);
471
472 HALMAC_REG_W32(REG_ASSOCIATED_BFMER0_INFO, mac_addr_l);
473 HALMAC_REG_W16(REG_ASSOCIATED_BFMER0_INFO + 4, mac_addr_h);
474 HALMAC_REG_W16(REG_ASSOCIATED_BFMER0_INFO + 6, param->paid);
475 HALMAC_REG_W16(REG_TX_CSI_RPT_PARAM_BW20, param->csi_para);
476
477 tmp1680 = HALMAC_REG_R16(0x1680) & 0xC000;
478 tmp1680 |= param->my_aid | (param->csi_length_sel << 12);
479 HALMAC_REG_W16(0x1680, tmp1680);
480
481 PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
482
483 return HALMAC_RET_SUCCESS;
484 }
485
486 /**
487 * su_bfee_entry_del_88xx() - reset SU beamformee's registers
488 * @adapter : the adapter of halmac
489 * @userid : the SU BFee userid to be deleted
490 * Author : chunchu
491 * Return : enum halmac_ret_status
492 * More details of status code can be found in prototype document
493 */
494 enum halmac_ret_status
su_bfee_entry_del_88xx(struct halmac_adapter * adapter,u8 userid)495 su_bfee_entry_del_88xx(struct halmac_adapter *adapter, u8 userid)
496 {
497 u16 value16;
498 struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
499
500 switch (userid) {
501 case 0:
502 value16 = HALMAC_REG_R16(REG_TXBF_CTRL);
503 value16 &= ~(BIT_MASK_R_TXBF0_AID | BIT_R_TXBF0_20M |
504 BIT_R_TXBF0_40M | BIT_R_TXBF0_80M);
505 HALMAC_REG_W16(REG_TXBF_CTRL, value16);
506 HALMAC_REG_W16(REG_ASSOCIATED_BFMEE_SEL, 0);
507 break;
508 case 1:
509 value16 = HALMAC_REG_R16(REG_TXBF_CTRL + 2);
510 value16 &= ~(BIT_MASK_R_TXBF1_AID | BIT_R_TXBF0_20M |
511 BIT_R_TXBF0_40M | BIT_R_TXBF0_80M);
512 HALMAC_REG_W16(REG_TXBF_CTRL + 2, value16);
513 HALMAC_REG_W16(REG_ASSOCIATED_BFMEE_SEL + 2, 0);
514 break;
515 case 2:
516 HALMAC_REG_W16(REG_WMAC_ASSOCIATED_MU_BFMEE2, 0);
517 break;
518 case 3:
519 HALMAC_REG_W16(REG_WMAC_ASSOCIATED_MU_BFMEE3, 0);
520 break;
521 case 4:
522 HALMAC_REG_W16(REG_WMAC_ASSOCIATED_MU_BFMEE4, 0);
523 break;
524 case 5:
525 HALMAC_REG_W16(REG_WMAC_ASSOCIATED_MU_BFMEE5, 0);
526 break;
527 default:
528 return HALMAC_RET_INVALID_SOUNDING_SETTING;
529 }
530
531 PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
532
533 return HALMAC_RET_SUCCESS;
534 }
535
536 /**
537 * su_bfee_entry_del_88xx() - reset SU beamformer's registers
538 * @adapter : the adapter of halmac
539 * @userid : the SU BFer userid to be deleted
540 * Author : chunchu
541 * Return : enum halmac_ret_status
542 * More details of status code can be found in prototype document
543 */
544 enum halmac_ret_status
su_bfer_entry_del_88xx(struct halmac_adapter * adapter,u8 userid)545 su_bfer_entry_del_88xx(struct halmac_adapter *adapter, u8 userid)
546 {
547 struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
548
549 switch (userid) {
550 case 0:
551 HALMAC_REG_W32(REG_ASSOCIATED_BFMER0_INFO, 0);
552 HALMAC_REG_W32(REG_ASSOCIATED_BFMER0_INFO + 4, 0);
553 break;
554 case 1:
555 HALMAC_REG_W32(REG_ASSOCIATED_BFMER1_INFO, 0);
556 HALMAC_REG_W32(REG_ASSOCIATED_BFMER1_INFO + 4, 0);
557 break;
558 default:
559 return HALMAC_RET_INVALID_SOUNDING_SETTING;
560 }
561
562 PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
563
564 return HALMAC_RET_SUCCESS;
565 }
566
567 /**
568 * mu_bfee_entry_del_88xx() - reset MU beamformee's registers
569 * @adapter : the adapter of halmac
570 * @userid : the MU STA userid to be deleted
571 * Author : chunchu
572 * Return : enum halmac_ret_status
573 * More details of status code can be found in prototype document
574 */
575 enum halmac_ret_status
mu_bfee_entry_del_88xx(struct halmac_adapter * adapter,u8 userid)576 mu_bfee_entry_del_88xx(struct halmac_adapter *adapter, u8 userid)
577 {
578 struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
579
580 HALMAC_REG_W16(0x1680 + userid * 2, 0);
581 HALMAC_REG_W8_CLR(REG_MU_TX_CTL, BIT(userid - 2));
582
583 PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
584
585 return HALMAC_RET_SUCCESS;
586 }
587
588 /**
589 * mu_bfer_entry_del_88xx() -reset MU beamformer's registers
590 * @adapter : the adapter of halmac
591 * Author : chunchu
592 * Return : enum halmac_ret_status
593 * More details of status code can be found in prototype document
594 */
595 enum halmac_ret_status
mu_bfer_entry_del_88xx(struct halmac_adapter * adapter)596 mu_bfer_entry_del_88xx(struct halmac_adapter *adapter)
597 {
598 struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
599
600 HALMAC_REG_W32(REG_ASSOCIATED_BFMER0_INFO, 0);
601 HALMAC_REG_W32(REG_ASSOCIATED_BFMER0_INFO + 4, 0);
602 HALMAC_REG_W16(0x1680, 0);
603 HALMAC_REG_W8(REG_MU_TX_CTL, 0);
604
605 PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
606
607 return HALMAC_RET_SUCCESS;
608 }
609
610 /**
611 * cfg_csi_rate_88xx() - config CSI frame Tx rate
612 * @adapter : the adapter of halmac
613 * @rssi : rssi in decimal value
614 * @cur_rate : current CSI frame rate
615 * @fixrate_en : enable to fix CSI frame in VHT rate, otherwise legacy OFDM rate
616 * @new_rate : API returns the final CSI frame rate
617 * Author : chunchu
618 * Return : enum halmac_ret_status
619 * More details of status code can be found in prototype document
620 */
621 enum halmac_ret_status
cfg_csi_rate_88xx(struct halmac_adapter * adapter,u8 rssi,u8 cur_rate,u8 fixrate_en,u8 * new_rate,u8 * bmp_ofdm54)622 cfg_csi_rate_88xx(struct halmac_adapter *adapter, u8 rssi, u8 cur_rate,
623 u8 fixrate_en, u8 *new_rate, u8 *bmp_ofdm54)
624 {
625 u32 csi_cfg;
626 struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
627
628 PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
629
630 *bmp_ofdm54 = 0xFF;
631
632 #if HALMAC_8821C_SUPPORT
633 if (adapter->chip_id == HALMAC_CHIP_ID_8821C && fixrate_en) {
634 csi_cfg = HALMAC_REG_R32(REG_BBPSF_CTRL) & ~BITS_WMAC_CSI_RATE;
635 HALMAC_REG_W32(REG_BBPSF_CTRL,
636 csi_cfg | BIT_CSI_FORCE_RATE_EN |
637 BIT_CSI_RSC(1) |
638 BIT_WMAC_CSI_RATE(HALMAC_VHT_NSS1_MCS3));
639 *new_rate = HALMAC_VHT_NSS1_MCS3;
640 return HALMAC_RET_SUCCESS;
641 }
642 csi_cfg = HALMAC_REG_R32(REG_BBPSF_CTRL) & ~BITS_WMAC_CSI_RATE &
643 ~BIT_CSI_FORCE_RATE_EN;
644 #else
645 csi_cfg = HALMAC_REG_R32(REG_BBPSF_CTRL) & ~BITS_WMAC_CSI_RATE;
646 #endif
647
648 #if (HALMAC_8822C_SUPPORT || HALMAC_8812F_SUPPORT)
649 if (adapter->chip_id == HALMAC_CHIP_ID_8822C ||
650 adapter->chip_id == HALMAC_CHIP_ID_8812F)
651 HALMAC_REG_W32_SET(REG_BBPSF_CTRL, BIT(15));
652 #endif
653
654 if (rssi >= 40) {
655 if (cur_rate != HALMAC_OFDM54) {
656 csi_cfg |= BIT_WMAC_CSI_RATE(HALMAC_OFDM54);
657 HALMAC_REG_W32(REG_BBPSF_CTRL, csi_cfg);
658 *bmp_ofdm54 = 1;
659 }
660 *new_rate = HALMAC_OFDM54;
661 } else {
662 if (cur_rate != HALMAC_OFDM24) {
663 csi_cfg |= BIT_WMAC_CSI_RATE(HALMAC_OFDM24);
664 HALMAC_REG_W32(REG_BBPSF_CTRL, csi_cfg);
665 *bmp_ofdm54 = 0;
666 }
667 *new_rate = HALMAC_OFDM24;
668 }
669
670 return HALMAC_RET_SUCCESS;
671 }
672
673 /**
674 * fw_snding_88xx() - fw sounding control
675 * @adapter : the adapter of halmac
676 * @su_info :
677 * su0_en : enable/disable fw sounding
678 * su0_ndpa_pkt : ndpa pkt, shall include txdesc
679 * su0_pkt_sz : ndpa pkt size, shall include txdesc
680 * @mu_info : currently not in use, input NULL is acceptable
681 * @period : sounding period, unit is 5ms
682 * Author : Ivan Lin
683 * Return : enum halmac_ret_status
684 * More details of status code can be found in prototype document
685 */
686 enum halmac_ret_status
fw_snding_88xx(struct halmac_adapter * adapter,struct halmac_su_snding_info * su_info,struct halmac_mu_snding_info * mu_info,u8 period)687 fw_snding_88xx(struct halmac_adapter *adapter,
688 struct halmac_su_snding_info *su_info,
689 struct halmac_mu_snding_info *mu_info, u8 period)
690 {
691 u8 h2c_buf[H2C_PKT_SIZE_88XX] = { 0 };
692 u16 seq_num;
693 u16 snding_info_addr;
694 struct halmac_h2c_header_info hdr_info;
695 enum halmac_cmd_process_status *proc_status;
696 enum halmac_ret_status status;
697
698 proc_status = &adapter->halmac_state.fw_snding_state.proc_status;
699
700 if (adapter->chip_id == HALMAC_CHIP_ID_8821C)
701 return HALMAC_RET_NOT_SUPPORT;
702
703 if (halmac_fw_validate(adapter) != HALMAC_RET_SUCCESS)
704 return HALMAC_RET_NO_DLFW;
705
706 if (adapter->fw_ver.h2c_version < 9)
707 return HALMAC_RET_FW_NO_SUPPORT;
708
709 if (*proc_status == HALMAC_CMD_PROCESS_SENDING) {
710 PLTFM_MSG_TRACE("[TRACE]Wait event(snd)\n");
711 return HALMAC_RET_BUSY_STATE;
712 }
713
714 if (su_info->su0_en == 1) {
715 if (!su_info->su0_ndpa_pkt)
716 return HALMAC_RET_NULL_POINTER;
717
718 if (su_info->su0_pkt_sz > (u32)SU0_SNDING_PKT_RSVDPG_SIZE -
719 adapter->hw_cfg_info.txdesc_size)
720 return HALMAC_RET_DATA_SIZE_INCORRECT;
721
722 if (!snding_pkt_chk_88xx(adapter, su_info->su0_ndpa_pkt))
723 return HALMAC_RET_TXDESC_SET_FAIL;
724
725 if (fw_snding_cmd_cnstr_state_88xx(adapter) !=
726 HALMAC_CMD_CNSTR_IDLE) {
727 PLTFM_MSG_ERR("[ERR]Not idle(snd)\n");
728 return HALMAC_RET_ERROR_STATE;
729 }
730
731 snding_info_addr = adapter->txff_alloc.rsvd_h2c_sta_info_addr +
732 SU0_SNDING_PKT_OFFSET;
733 status = dl_rsvd_page_88xx(adapter, snding_info_addr,
734 su_info->su0_ndpa_pkt,
735 su_info->su0_pkt_sz);
736 if (status != HALMAC_RET_SUCCESS) {
737 PLTFM_MSG_ERR("[ERR]dl rsvd page\n");
738 return status;
739 }
740
741 FW_SNDING_SET_SU0(h2c_buf, 1);
742 FW_SNDING_SET_PERIOD(h2c_buf, period);
743 FW_SNDING_SET_NDPA0_HEAD_PG(h2c_buf, snding_info_addr -
744 adapter->txff_alloc.rsvd_boundary);
745 } else {
746 if (fw_snding_cmd_cnstr_state_88xx(adapter) !=
747 HALMAC_CMD_CNSTR_BUSY) {
748 PLTFM_MSG_ERR("[ERR]Not snd(snd)\n");
749 return HALMAC_RET_ERROR_STATE;
750 }
751 FW_SNDING_SET_SU0(h2c_buf, 0);
752 }
753
754 *proc_status = HALMAC_CMD_PROCESS_SENDING;
755
756 hdr_info.sub_cmd_id = SUB_CMD_ID_FW_SNDING;
757 hdr_info.content_size = 8;
758 hdr_info.ack = 1;
759 set_h2c_pkt_hdr_88xx(adapter, h2c_buf, &hdr_info, &seq_num);
760 adapter->halmac_state.fw_snding_state.seq_num = seq_num;
761
762 status = send_h2c_pkt_88xx(adapter, h2c_buf);
763 if (status != HALMAC_RET_SUCCESS) {
764 PLTFM_MSG_ERR("[ERR]send h2c\n");
765 reset_ofld_feature_88xx(adapter, HALMAC_FEATURE_FW_SNDING);
766 return status;
767 }
768
769 if (cnv_fw_snding_state_88xx(adapter, su_info->su0_en == 1 ?
770 HALMAC_CMD_CNSTR_BUSY :
771 HALMAC_CMD_CNSTR_IDLE)
772 != HALMAC_RET_SUCCESS)
773 return HALMAC_RET_ERROR_STATE;
774
775 return HALMAC_RET_SUCCESS;
776 }
777
778 static u8
snding_pkt_chk_88xx(struct halmac_adapter * adapter,u8 * pkt)779 snding_pkt_chk_88xx(struct halmac_adapter *adapter, u8 *pkt)
780 {
781 u8 data_rate;
782
783 if (GET_TX_DESC_NDPA(pkt) == 0) {
784 PLTFM_MSG_ERR("[ERR]txdesc ndpa = 0\n");
785 return 0;
786 }
787
788 data_rate = (u8)GET_TX_DESC_DATARATE(pkt);
789 if (!(data_rate >= HALMAC_VHT_NSS2_MCS0 &&
790 data_rate <= HALMAC_VHT_NSS2_MCS9)) {
791 if (!(data_rate >= HALMAC_MCS8 && data_rate <= HALMAC_MCS15)) {
792 PLTFM_MSG_ERR("[ERR]txdesc rate\n");
793 return 0;
794 }
795 }
796
797 if (GET_TX_DESC_NAVUSEHDR(pkt) == 0) {
798 PLTFM_MSG_ERR("[ERR]txdesc navusehdr = 0\n");
799 return 0;
800 }
801
802 if (GET_TX_DESC_USE_RATE(pkt) == 0) {
803 PLTFM_MSG_ERR("[ERR]txdesc userate = 0\n");
804 return 0;
805 }
806
807 return 1;
808 }
809
810 static enum halmac_cmd_construct_state
fw_snding_cmd_cnstr_state_88xx(struct halmac_adapter * adapter)811 fw_snding_cmd_cnstr_state_88xx(struct halmac_adapter *adapter)
812 {
813 return adapter->halmac_state.fw_snding_state.cmd_cnstr_state;
814 }
815
816 enum halmac_ret_status
get_h2c_ack_fw_snding_88xx(struct halmac_adapter * adapter,u8 * buf,u32 size)817 get_h2c_ack_fw_snding_88xx(struct halmac_adapter *adapter, u8 *buf, u32 size)
818 {
819 u8 seq_num = 0;
820 u8 fw_rc;
821 struct halmac_fw_snding_state *state;
822 enum halmac_cmd_process_status proc_status;
823
824 state = &adapter->halmac_state.fw_snding_state;
825
826 seq_num = (u8)H2C_ACK_HDR_GET_H2C_SEQ(buf);
827 PLTFM_MSG_TRACE("[TRACE]Seq num:h2c->%d c2h->%d\n",
828 state->seq_num, seq_num);
829 if (seq_num != state->seq_num) {
830 PLTFM_MSG_ERR("[ERR]Seq num mismatch:h2c->%d c2h->%d\n",
831 state->seq_num, seq_num);
832 return HALMAC_RET_SUCCESS;
833 }
834
835 if (state->proc_status != HALMAC_CMD_PROCESS_SENDING) {
836 PLTFM_MSG_ERR("[ERR]not sending(snd)\n");
837 return HALMAC_RET_SUCCESS;
838 }
839
840 fw_rc = (u8)H2C_ACK_HDR_GET_H2C_RETURN_CODE(buf);
841 state->fw_rc = fw_rc;
842
843 if ((enum halmac_h2c_return_code)fw_rc == HALMAC_H2C_RETURN_SUCCESS) {
844 proc_status = HALMAC_CMD_PROCESS_DONE;
845 state->proc_status = proc_status;
846 PLTFM_EVENT_SIG(HALMAC_FEATURE_FW_SNDING, proc_status,
847 NULL, 0);
848 } else {
849 proc_status = HALMAC_CMD_PROCESS_ERROR;
850 state->proc_status = proc_status;
851 PLTFM_EVENT_SIG(HALMAC_FEATURE_FW_SNDING, proc_status,
852 &fw_rc, 1);
853 }
854
855 return HALMAC_RET_SUCCESS;
856 }
857
858 enum halmac_ret_status
get_fw_snding_status_88xx(struct halmac_adapter * adapter,enum halmac_cmd_process_status * proc_status)859 get_fw_snding_status_88xx(struct halmac_adapter *adapter,
860 enum halmac_cmd_process_status *proc_status)
861 {
862 *proc_status = adapter->halmac_state.fw_snding_state.proc_status;
863
864 return HALMAC_RET_SUCCESS;
865 }
866
867 static enum halmac_ret_status
cnv_fw_snding_state_88xx(struct halmac_adapter * adapter,enum halmac_cmd_construct_state dest_state)868 cnv_fw_snding_state_88xx(struct halmac_adapter *adapter,
869 enum halmac_cmd_construct_state dest_state)
870 {
871 struct halmac_fw_snding_state *state;
872
873 state = &adapter->halmac_state.fw_snding_state;
874
875 if (state->cmd_cnstr_state != HALMAC_CMD_CNSTR_IDLE &&
876 state->cmd_cnstr_state != HALMAC_CMD_CNSTR_BUSY)
877 return HALMAC_RET_ERROR_STATE;
878
879 if (dest_state == HALMAC_CMD_CNSTR_IDLE) {
880 if (state->cmd_cnstr_state == HALMAC_CMD_CNSTR_IDLE)
881 return HALMAC_RET_ERROR_STATE;
882 } else if (dest_state == HALMAC_CMD_CNSTR_BUSY) {
883 if (state->cmd_cnstr_state == HALMAC_CMD_CNSTR_BUSY)
884 return HALMAC_RET_ERROR_STATE;
885 }
886
887 state->cmd_cnstr_state = dest_state;
888
889 return HALMAC_RET_SUCCESS;
890 }
891 #endif /* HALMAC_88XX_SUPPORT */
892