GNU Linux-libre 4.19.286-gnu1
[releases.git] / drivers / staging / rtlwifi / phydm / rtl_phydm.c
1 // SPDX-License-Identifier: GPL-2.0
2 /******************************************************************************
3  *
4  * Copyright(c) 2007 - 2016  Realtek Corporation.
5  *
6  * Contact Information:
7  * wlanfae <wlanfae@realtek.com>
8  * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
9  * Hsinchu 300, Taiwan.
10  *
11  * Larry Finger <Larry.Finger@lwfinger.net>
12  *
13  *****************************************************************************/
14 #include "mp_precomp.h"
15 #include "phydm_precomp.h"
16 #include <linux/module.h>
17
18 static int _rtl_phydm_init_com_info(struct rtl_priv *rtlpriv,
19                                     enum odm_ic_type ic_type,
20                                     struct rtl_phydm_params *params)
21 {
22         struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
23         struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
24         struct rtl_phy *rtlphy = &rtlpriv->phy;
25         struct rtl_mac *mac = rtl_mac(rtlpriv);
26         struct rtl_ps_ctl *ppsc = rtl_psc(rtlpriv);
27         struct rtl_efuse *rtlefuse = rtl_efuse(rtlpriv);
28         u8 odm_board_type = ODM_BOARD_DEFAULT;
29         u32 support_ability;
30         int i;
31
32         dm->adapter = (void *)rtlpriv;
33
34         odm_cmn_info_init(dm, ODM_CMNINFO_PLATFORM, ODM_CE);
35
36         odm_cmn_info_init(dm, ODM_CMNINFO_IC_TYPE, ic_type);
37
38         odm_cmn_info_init(dm, ODM_CMNINFO_INTERFACE, ODM_ITRF_PCIE);
39
40         odm_cmn_info_init(dm, ODM_CMNINFO_MP_TEST_CHIP, params->mp_chip);
41
42         odm_cmn_info_init(dm, ODM_CMNINFO_PATCH_ID, rtlhal->oem_id);
43
44         odm_cmn_info_init(dm, ODM_CMNINFO_BWIFI_TEST, 1);
45
46         if (rtlphy->rf_type == RF_1T1R)
47                 odm_cmn_info_init(dm, ODM_CMNINFO_RF_TYPE, ODM_1T1R);
48         else if (rtlphy->rf_type == RF_1T2R)
49                 odm_cmn_info_init(dm, ODM_CMNINFO_RF_TYPE, ODM_1T2R);
50         else if (rtlphy->rf_type == RF_2T2R)
51                 odm_cmn_info_init(dm, ODM_CMNINFO_RF_TYPE, ODM_2T2R);
52         else if (rtlphy->rf_type == RF_2T2R_GREEN)
53                 odm_cmn_info_init(dm, ODM_CMNINFO_RF_TYPE, ODM_2T2R_GREEN);
54         else if (rtlphy->rf_type == RF_2T3R)
55                 odm_cmn_info_init(dm, ODM_CMNINFO_RF_TYPE, ODM_2T3R);
56         else if (rtlphy->rf_type == RF_2T4R)
57                 odm_cmn_info_init(dm, ODM_CMNINFO_RF_TYPE, ODM_2T4R);
58         else if (rtlphy->rf_type == RF_3T3R)
59                 odm_cmn_info_init(dm, ODM_CMNINFO_RF_TYPE, ODM_3T3R);
60         else if (rtlphy->rf_type == RF_3T4R)
61                 odm_cmn_info_init(dm, ODM_CMNINFO_RF_TYPE, ODM_3T4R);
62         else if (rtlphy->rf_type == RF_4T4R)
63                 odm_cmn_info_init(dm, ODM_CMNINFO_RF_TYPE, ODM_4T4R);
64         else
65                 odm_cmn_info_init(dm, ODM_CMNINFO_RF_TYPE, ODM_XTXR);
66
67         /* 1 ======= BoardType: ODM_CMNINFO_BOARD_TYPE ======= */
68         if (rtlhal->external_lna_2g != 0) {
69                 odm_board_type |= ODM_BOARD_EXT_LNA;
70                 odm_cmn_info_init(dm, ODM_CMNINFO_EXT_LNA, 1);
71         }
72         if (rtlhal->external_lna_5g != 0) {
73                 odm_board_type |= ODM_BOARD_EXT_LNA_5G;
74                 odm_cmn_info_init(dm, ODM_CMNINFO_5G_EXT_LNA, 1);
75         }
76         if (rtlhal->external_pa_2g != 0) {
77                 odm_board_type |= ODM_BOARD_EXT_PA;
78                 odm_cmn_info_init(dm, ODM_CMNINFO_EXT_PA, 1);
79         }
80         if (rtlhal->external_pa_5g != 0) {
81                 odm_board_type |= ODM_BOARD_EXT_PA_5G;
82                 odm_cmn_info_init(dm, ODM_CMNINFO_5G_EXT_PA, 1);
83         }
84         if (rtlpriv->cfg->ops->get_btc_status())
85                 odm_board_type |= ODM_BOARD_BT;
86
87         odm_cmn_info_init(dm, ODM_CMNINFO_BOARD_TYPE, odm_board_type);
88         /* 1 ============== End of BoardType ============== */
89
90         odm_cmn_info_init(dm, ODM_CMNINFO_GPA, rtlhal->type_gpa);
91         odm_cmn_info_init(dm, ODM_CMNINFO_APA, rtlhal->type_apa);
92         odm_cmn_info_init(dm, ODM_CMNINFO_GLNA, rtlhal->type_glna);
93         odm_cmn_info_init(dm, ODM_CMNINFO_ALNA, rtlhal->type_alna);
94
95         odm_cmn_info_init(dm, ODM_CMNINFO_RFE_TYPE, rtlhal->rfe_type);
96
97         odm_cmn_info_init(dm, ODM_CMNINFO_EXT_TRSW, 0);
98
99         /*Add by YuChen for kfree init*/
100         odm_cmn_info_init(dm, ODM_CMNINFO_REGRFKFREEENABLE, 2);
101         odm_cmn_info_init(dm, ODM_CMNINFO_RFKFREEENABLE, 0);
102
103         /*Antenna diversity relative parameters*/
104         odm_cmn_info_hook(dm, ODM_CMNINFO_ANT_DIV,
105                           &rtlefuse->antenna_div_cfg);
106         odm_cmn_info_init(dm, ODM_CMNINFO_RF_ANTENNA_TYPE,
107                           rtlefuse->antenna_div_type);
108         odm_cmn_info_init(dm, ODM_CMNINFO_BE_FIX_TX_ANT, 0);
109         odm_cmn_info_init(dm, ODM_CMNINFO_WITH_EXT_ANTENNA_SWITCH, 0);
110
111         /* (8822B) efuse 0x3D7 & 0x3D8 for TX PA bias */
112         odm_cmn_info_init(dm, ODM_CMNINFO_EFUSE0X3D7, params->efuse0x3d7);
113         odm_cmn_info_init(dm, ODM_CMNINFO_EFUSE0X3D8, params->efuse0x3d8);
114
115         /*Add by YuChen for adaptivity init*/
116         odm_cmn_info_hook(dm, ODM_CMNINFO_ADAPTIVITY,
117                           &rtlpriv->phydm.adaptivity_en);
118         phydm_adaptivity_info_init(dm, PHYDM_ADAPINFO_CARRIER_SENSE_ENABLE,
119                                    false);
120         phydm_adaptivity_info_init(dm, PHYDM_ADAPINFO_DCBACKOFF, 0);
121         phydm_adaptivity_info_init(dm, PHYDM_ADAPINFO_DYNAMICLINKADAPTIVITY,
122                                    false);
123         phydm_adaptivity_info_init(dm, PHYDM_ADAPINFO_TH_L2H_INI, 0);
124         phydm_adaptivity_info_init(dm, PHYDM_ADAPINFO_TH_EDCCA_HL_DIFF, 0);
125
126         odm_cmn_info_init(dm, ODM_CMNINFO_IQKFWOFFLOAD, 0);
127
128         /* Pointer reference */
129         odm_cmn_info_hook(dm, ODM_CMNINFO_TX_UNI,
130                           &rtlpriv->stats.txbytesunicast);
131         odm_cmn_info_hook(dm, ODM_CMNINFO_RX_UNI,
132                           &rtlpriv->stats.rxbytesunicast);
133         odm_cmn_info_hook(dm, ODM_CMNINFO_BAND, &rtlhal->current_bandtype);
134         odm_cmn_info_hook(dm, ODM_CMNINFO_FORCED_RATE,
135                           &rtlpriv->phydm.forced_data_rate);
136         odm_cmn_info_hook(dm, ODM_CMNINFO_FORCED_IGI_LB,
137                           &rtlpriv->phydm.forced_igi_lb);
138
139         odm_cmn_info_hook(dm, ODM_CMNINFO_SEC_CHNL_OFFSET,
140                           &mac->cur_40_prime_sc);
141         odm_cmn_info_hook(dm, ODM_CMNINFO_BW, &rtlphy->current_chan_bw);
142         odm_cmn_info_hook(dm, ODM_CMNINFO_CHNL, &rtlphy->current_channel);
143
144         odm_cmn_info_hook(dm, ODM_CMNINFO_SCAN, &mac->act_scanning);
145         odm_cmn_info_hook(dm, ODM_CMNINFO_POWER_SAVING,
146                           &ppsc->dot11_psmode); /* may add new boolean flag */
147         /*Add by Yuchen for phydm beamforming*/
148         odm_cmn_info_hook(dm, ODM_CMNINFO_TX_TP,
149                           &rtlpriv->stats.txbytesunicast_inperiod_tp);
150         odm_cmn_info_hook(dm, ODM_CMNINFO_RX_TP,
151                           &rtlpriv->stats.rxbytesunicast_inperiod_tp);
152         odm_cmn_info_hook(dm, ODM_CMNINFO_ANT_TEST,
153                           &rtlpriv->phydm.antenna_test);
154         for (i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++)
155                 odm_cmn_info_ptr_array_hook(dm, ODM_CMNINFO_STA_STATUS, i,
156                                             NULL);
157
158         phydm_init_debug_setting(dm);
159
160         odm_cmn_info_init(dm, ODM_CMNINFO_FAB_VER, params->fab_ver);
161         odm_cmn_info_init(dm, ODM_CMNINFO_CUT_VER, params->cut_ver);
162
163         /* after ifup, ability is updated again */
164         support_ability = ODM_RF_CALIBRATION | ODM_RF_TX_PWR_TRACK;
165         odm_cmn_info_update(dm, ODM_CMNINFO_ABILITY, support_ability);
166
167         return 0;
168 }
169
170 static int rtl_phydm_init_priv(struct rtl_priv *rtlpriv,
171                                struct rtl_phydm_params *params)
172 {
173         struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
174         enum odm_ic_type ic;
175
176         if (IS_HARDWARE_TYPE_8822B(rtlpriv))
177                 ic = ODM_RTL8822B;
178         else
179                 return 0;
180
181         rtlpriv->phydm.internal =
182                 kzalloc(sizeof(struct phy_dm_struct), GFP_KERNEL);
183         if (!rtlpriv->phydm.internal)
184                 return 0;
185
186         _rtl_phydm_init_com_info(rtlpriv, ic, params);
187
188         odm_init_all_timers(dm);
189
190         return 1;
191 }
192
193 static int rtl_phydm_deinit_priv(struct rtl_priv *rtlpriv)
194 {
195         struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
196
197         odm_cancel_all_timers(dm);
198
199         kfree(rtlpriv->phydm.internal);
200         rtlpriv->phydm.internal = NULL;
201
202         return 0;
203 }
204
205 static bool rtl_phydm_load_txpower_by_rate(struct rtl_priv *rtlpriv)
206 {
207         struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
208         enum hal_status status;
209
210         status = odm_config_bb_with_header_file(dm, CONFIG_BB_PHY_REG_PG);
211         if (status != HAL_STATUS_SUCCESS)
212                 return false;
213
214         return true;
215 }
216
217 static bool rtl_phydm_load_txpower_limit(struct rtl_priv *rtlpriv)
218 {
219         struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
220         enum hal_status status;
221
222         if (IS_HARDWARE_TYPE_8822B(rtlpriv)) {
223                 odm_read_and_config_mp_8822b_txpwr_lmt(dm);
224         } else {
225                 status = odm_config_rf_with_header_file(dm, CONFIG_RF_TXPWR_LMT,
226                                                         0);
227                 if (status != HAL_STATUS_SUCCESS)
228                         return false;
229         }
230
231         return true;
232 }
233
234 static int rtl_phydm_init_dm(struct rtl_priv *rtlpriv)
235 {
236         struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
237         u32 support_ability = 0;
238
239         /* clang-format off */
240         support_ability = 0
241                         | ODM_BB_DIG
242                         | ODM_BB_RA_MASK
243                         | ODM_BB_DYNAMIC_TXPWR
244                         | ODM_BB_FA_CNT
245                         | ODM_BB_RSSI_MONITOR
246                         | ODM_BB_CCK_PD
247         /*              | ODM_BB_PWR_SAVE*/
248                         | ODM_BB_CFO_TRACKING
249                         | ODM_MAC_EDCA_TURBO
250                         | ODM_RF_TX_PWR_TRACK
251                         | ODM_RF_CALIBRATION
252                         | ODM_BB_NHM_CNT
253         /*              | ODM_BB_PWR_TRAIN*/
254                         ;
255         /* clang-format on */
256
257         odm_cmn_info_update(dm, ODM_CMNINFO_ABILITY, support_ability);
258
259         odm_dm_init(dm);
260
261         return 0;
262 }
263
264 static int rtl_phydm_deinit_dm(struct rtl_priv *rtlpriv)
265 {
266         return 0;
267 }
268
269 static int rtl_phydm_reset_dm(struct rtl_priv *rtlpriv)
270 {
271         struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
272
273         odm_dm_reset(dm);
274
275         return 0;
276 }
277
278 static bool rtl_phydm_parameter_init(struct rtl_priv *rtlpriv, bool post)
279 {
280         struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
281
282         if (IS_HARDWARE_TYPE_8822B(rtlpriv))
283                 return config_phydm_parameter_init(dm, post ? ODM_POST_SETTING :
284                                                               ODM_PRE_SETTING);
285
286         return false;
287 }
288
289 static bool rtl_phydm_phy_bb_config(struct rtl_priv *rtlpriv)
290 {
291         struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
292         enum hal_status status;
293
294         status = odm_config_bb_with_header_file(dm, CONFIG_BB_PHY_REG);
295         if (status != HAL_STATUS_SUCCESS)
296                 return false;
297
298         status = odm_config_bb_with_header_file(dm, CONFIG_BB_AGC_TAB);
299         if (status != HAL_STATUS_SUCCESS)
300                 return false;
301
302         return true;
303 }
304
305 static bool rtl_phydm_phy_rf_config(struct rtl_priv *rtlpriv)
306 {
307         struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
308         struct rtl_phy *rtlphy = &rtlpriv->phy;
309         enum hal_status status;
310         enum odm_rf_radio_path rfpath;
311
312         for (rfpath = 0; rfpath < rtlphy->num_total_rfpath; rfpath++) {
313                 status = odm_config_rf_with_header_file(dm, CONFIG_RF_RADIO,
314                                                         rfpath);
315                 if (status != HAL_STATUS_SUCCESS)
316                         return false;
317         }
318
319         status = odm_config_rf_with_tx_pwr_track_header_file(dm);
320         if (status != HAL_STATUS_SUCCESS)
321                 return false;
322
323         return true;
324 }
325
326 static bool rtl_phydm_phy_mac_config(struct rtl_priv *rtlpriv)
327 {
328         struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
329         enum hal_status status;
330
331         status = odm_config_mac_with_header_file(dm);
332         if (status != HAL_STATUS_SUCCESS)
333                 return false;
334
335         return true;
336 }
337
338 static bool rtl_phydm_trx_mode(struct rtl_priv *rtlpriv,
339                                enum radio_mask tx_path, enum radio_mask rx_path,
340                                bool is_tx2_path)
341 {
342         struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
343
344         if (IS_HARDWARE_TYPE_8822B(rtlpriv))
345                 return config_phydm_trx_mode_8822b(dm,
346                                                    (enum odm_rf_path)tx_path,
347                                                    (enum odm_rf_path)rx_path,
348                                                    is_tx2_path);
349
350         return false;
351 }
352
353 static bool rtl_phydm_watchdog(struct rtl_priv *rtlpriv)
354 {
355         struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
356         struct rtl_mac *mac = rtl_mac(rtlpriv);
357         struct rtl_ps_ctl *ppsc = rtl_psc(rtlpriv);
358         bool fw_current_inpsmode = false;
359         bool fw_ps_awake = true;
360         u8 is_linked = false;
361         u8 bsta_state = false;
362         u8 is_bt_enabled = false;
363
364         /* check whether do watchdog */
365         rtlpriv->cfg->ops->get_hw_reg(rtlpriv->hw, HW_VAR_FW_PSMODE_STATUS,
366                                       (u8 *)(&fw_current_inpsmode));
367         rtlpriv->cfg->ops->get_hw_reg(rtlpriv->hw, HW_VAR_FWLPS_RF_ON,
368                                       (u8 *)(&fw_ps_awake));
369         if (ppsc->p2p_ps_info.p2p_ps_mode)
370                 fw_ps_awake = false;
371
372         if ((ppsc->rfpwr_state == ERFON) &&
373             ((!fw_current_inpsmode) && fw_ps_awake) &&
374             (!ppsc->rfchange_inprogress))
375                 ;
376         else
377                 return false;
378
379         /* update common info before doing watchdog */
380         if (mac->link_state >= MAC80211_LINKED) {
381                 is_linked = true;
382                 if (mac->vif && mac->vif->type == NL80211_IFTYPE_STATION)
383                         bsta_state = true;
384         }
385
386         if (rtlpriv->cfg->ops->get_btc_status())
387                 is_bt_enabled = !rtlpriv->btcoexist.btc_ops->btc_is_bt_disabled(
388                         rtlpriv);
389
390         odm_cmn_info_update(dm, ODM_CMNINFO_LINK, is_linked);
391         odm_cmn_info_update(dm, ODM_CMNINFO_STATION_STATE, bsta_state);
392         odm_cmn_info_update(dm, ODM_CMNINFO_BT_ENABLED, is_bt_enabled);
393
394         /* do watchdog */
395         odm_dm_watchdog(dm);
396
397         return true;
398 }
399
400 static bool rtl_phydm_switch_band(struct rtl_priv *rtlpriv, u8 central_ch)
401 {
402         struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
403
404         if (IS_HARDWARE_TYPE_8822B(rtlpriv))
405                 return config_phydm_switch_band_8822b(dm, central_ch);
406
407         return false;
408 }
409
410 static bool rtl_phydm_switch_channel(struct rtl_priv *rtlpriv, u8 central_ch)
411 {
412         struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
413
414         if (IS_HARDWARE_TYPE_8822B(rtlpriv))
415                 return config_phydm_switch_channel_8822b(dm, central_ch);
416
417         return false;
418 }
419
420 static bool rtl_phydm_switch_bandwidth(struct rtl_priv *rtlpriv,
421                                        u8 primary_ch_idx,
422                                        enum ht_channel_width bandwidth)
423 {
424         struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
425         enum odm_bw odm_bw = (enum odm_bw)bandwidth;
426
427         if (IS_HARDWARE_TYPE_8822B(rtlpriv))
428                 return config_phydm_switch_bandwidth_8822b(dm, primary_ch_idx,
429                                                            odm_bw);
430
431         return false;
432 }
433
434 static bool rtl_phydm_iq_calibrate(struct rtl_priv *rtlpriv)
435 {
436         struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
437
438         if (IS_HARDWARE_TYPE_8822B(rtlpriv))
439                 phy_iq_calibrate_8822b(dm, false);
440         else
441                 return false;
442
443         return true;
444 }
445
446 static bool rtl_phydm_clear_txpowertracking_state(struct rtl_priv *rtlpriv)
447 {
448         struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
449
450         odm_clear_txpowertracking_state(dm);
451
452         return true;
453 }
454
455 static bool rtl_phydm_pause_dig(struct rtl_priv *rtlpriv, bool pause)
456 {
457         struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
458
459         if (pause)
460                 odm_pause_dig(dm, PHYDM_PAUSE, PHYDM_PAUSE_LEVEL_0, 0x1e);
461         else /* resume */
462                 odm_pause_dig(dm, PHYDM_RESUME, PHYDM_PAUSE_LEVEL_0, 0xff);
463
464         return true;
465 }
466
467 static u32 rtl_phydm_read_rf_reg(struct rtl_priv *rtlpriv,
468                                  enum radio_path rfpath, u32 addr, u32 mask)
469 {
470         struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
471         enum odm_rf_radio_path odm_rfpath = (enum odm_rf_radio_path)rfpath;
472
473         if (IS_HARDWARE_TYPE_8822B(rtlpriv))
474                 return config_phydm_read_rf_reg_8822b(dm, odm_rfpath, addr,
475                                                       mask);
476
477         return -1;
478 }
479
480 static bool rtl_phydm_write_rf_reg(struct rtl_priv *rtlpriv,
481                                    enum radio_path rfpath, u32 addr, u32 mask,
482                                    u32 data)
483 {
484         struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
485         enum odm_rf_radio_path odm_rfpath = (enum odm_rf_radio_path)rfpath;
486
487         if (IS_HARDWARE_TYPE_8822B(rtlpriv))
488                 return config_phydm_write_rf_reg_8822b(dm, odm_rfpath, addr,
489                                                        mask, data);
490
491         return false;
492 }
493
494 static u8 rtl_phydm_read_txagc(struct rtl_priv *rtlpriv, enum radio_path rfpath,
495                                u8 hw_rate)
496 {
497         struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
498         enum odm_rf_radio_path odm_rfpath = (enum odm_rf_radio_path)rfpath;
499
500         if (IS_HARDWARE_TYPE_8822B(rtlpriv))
501                 return config_phydm_read_txagc_8822b(dm, odm_rfpath, hw_rate);
502
503         return -1;
504 }
505
506 static bool rtl_phydm_write_txagc(struct rtl_priv *rtlpriv, u32 power_index,
507                                   enum radio_path rfpath, u8 hw_rate)
508 {
509         struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
510         enum odm_rf_radio_path odm_rfpath = (enum odm_rf_radio_path)rfpath;
511
512         if (IS_HARDWARE_TYPE_8822B(rtlpriv))
513                 return config_phydm_write_txagc_8822b(dm, power_index,
514                                                       odm_rfpath, hw_rate);
515
516         return false;
517 }
518
519 static bool rtl_phydm_c2h_content_parsing(struct rtl_priv *rtlpriv, u8 cmd_id,
520                                           u8 cmd_len, u8 *content)
521 {
522         struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
523
524         if (phydm_c2H_content_parsing(dm, cmd_id, cmd_len, content))
525                 return true;
526
527         return false;
528 }
529
530 static bool rtl_phydm_query_phy_status(struct rtl_priv *rtlpriv, u8 *phystrpt,
531                                        struct ieee80211_hdr *hdr,
532                                        struct rtl_stats *pstatus)
533 {
534         /* NOTE: phystrpt may be NULL, and need to fill default value */
535
536         struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
537         struct rtl_efuse *rtlefuse = rtl_efuse(rtlpriv);
538         struct rtl_mac *mac = rtl_mac(rtlpriv);
539         struct dm_per_pkt_info pktinfo; /* input of pydm */
540         struct dm_phy_status_info phy_info; /* output of phydm */
541         __le16 fc = hdr->frame_control;
542
543         /* fill driver pstatus */
544         ether_addr_copy(pstatus->psaddr, ieee80211_get_SA(hdr));
545
546         /* fill pktinfo */
547         memset(&pktinfo, 0, sizeof(pktinfo));
548
549         pktinfo.data_rate = pstatus->rate;
550
551         if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_STATION) {
552                 pktinfo.station_id = 0;
553         } else {
554                 /* TODO: use rtl_find_sta() to find ID */
555                 pktinfo.station_id = 0xFF;
556         }
557
558         pktinfo.is_packet_match_bssid =
559                 (!ieee80211_is_ctl(fc) &&
560                  (ether_addr_equal(mac->bssid,
561                                    ieee80211_has_tods(fc) ?
562                                            hdr->addr1 :
563                                            ieee80211_has_fromds(fc) ?
564                                            hdr->addr2 :
565                                            hdr->addr3)) &&
566                  (!pstatus->hwerror) && (!pstatus->crc) && (!pstatus->icv));
567         pktinfo.is_packet_to_self =
568                 pktinfo.is_packet_match_bssid &&
569                 (ether_addr_equal(hdr->addr1, rtlefuse->dev_addr));
570         pktinfo.is_to_self = (!pstatus->icv) && (!pstatus->crc) &&
571                              (ether_addr_equal(hdr->addr1, rtlefuse->dev_addr));
572         pktinfo.is_packet_beacon = (ieee80211_is_beacon(fc) ? true : false);
573
574         /* query phy status */
575         if (phystrpt)
576                 odm_phy_status_query(dm, &phy_info, phystrpt, &pktinfo);
577         else
578                 memset(&phy_info, 0, sizeof(phy_info));
579
580         /* copy phy_info from phydm to driver */
581         pstatus->rx_pwdb_all = phy_info.rx_pwdb_all;
582         pstatus->bt_rx_rssi_percentage = phy_info.bt_rx_rssi_percentage;
583         pstatus->recvsignalpower = phy_info.recv_signal_power;
584         pstatus->signalquality = phy_info.signal_quality;
585         pstatus->rx_mimo_signalquality[0] = phy_info.rx_mimo_signal_quality[0];
586         pstatus->rx_mimo_signalquality[1] = phy_info.rx_mimo_signal_quality[1];
587         pstatus->rx_packet_bw =
588                 phy_info.band_width; /* HT_CHANNEL_WIDTH_20 <- ODM_BW20M */
589
590         /* fill driver pstatus */
591         pstatus->packet_matchbssid = pktinfo.is_packet_match_bssid;
592         pstatus->packet_toself = pktinfo.is_packet_to_self;
593         pstatus->packet_beacon = pktinfo.is_packet_beacon;
594
595         return true;
596 }
597
598 static u8 rtl_phydm_rate_id_mapping(struct rtl_priv *rtlpriv,
599                                     enum wireless_mode wireless_mode,
600                                     enum rf_type rf_type,
601                                     enum ht_channel_width bw)
602 {
603         struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
604
605         return phydm_rate_id_mapping(dm, wireless_mode, rf_type, bw);
606 }
607
608 static bool rtl_phydm_get_ra_bitmap(struct rtl_priv *rtlpriv,
609                                     enum wireless_mode wireless_mode,
610                                     enum rf_type rf_type,
611                                     enum ht_channel_width bw,
612                                     u8 tx_rate_level, /* 0~6 */
613                                     u32 *tx_bitmap_msb,
614                                     u32 *tx_bitmap_lsb)
615 {
616         struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
617         const u8 mimo_ps_enable = 0;
618         const u8 disable_cck_rate = 0;
619
620         phydm_update_hal_ra_mask(dm, wireless_mode, rf_type, bw, mimo_ps_enable,
621                                  disable_cck_rate, tx_bitmap_msb, tx_bitmap_lsb,
622                                  tx_rate_level);
623
624         return true;
625 }
626
627 static u8 _rtl_phydm_get_macid(struct rtl_priv *rtlpriv,
628                                struct ieee80211_sta *sta)
629 {
630         struct rtl_mac *mac = rtl_mac(rtlpriv);
631
632         if (mac->opmode == NL80211_IFTYPE_STATION ||
633             mac->opmode == NL80211_IFTYPE_MESH_POINT) {
634                 return 0;
635         } else if (mac->opmode == NL80211_IFTYPE_AP ||
636                    mac->opmode == NL80211_IFTYPE_ADHOC)
637                 return sta->aid + 1;
638
639         return 0;
640 }
641
642 static bool rtl_phydm_add_sta(struct rtl_priv *rtlpriv,
643                               struct ieee80211_sta *sta)
644 {
645         struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
646         struct rtl_sta_info *sta_entry = (struct rtl_sta_info *)sta->drv_priv;
647         u8 mac_id = _rtl_phydm_get_macid(rtlpriv, sta);
648
649         odm_cmn_info_ptr_array_hook(dm, ODM_CMNINFO_STA_STATUS, mac_id,
650                                     sta_entry);
651
652         return true;
653 }
654
655 static bool rtl_phydm_del_sta(struct rtl_priv *rtlpriv,
656                               struct ieee80211_sta *sta)
657 {
658         struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
659         u8 mac_id = _rtl_phydm_get_macid(rtlpriv, sta);
660
661         odm_cmn_info_ptr_array_hook(dm, ODM_CMNINFO_STA_STATUS, mac_id, NULL);
662
663         return true;
664 }
665
666 static u32 rtl_phydm_get_version(struct rtl_priv *rtlpriv)
667 {
668         u32 ver = 0;
669
670         if (IS_HARDWARE_TYPE_8822B(rtlpriv))
671                 ver = RELEASE_VERSION_8822B;
672
673         return ver;
674 }
675
676 static bool rtl_phydm_modify_ra_pcr_threshold(struct rtl_priv *rtlpriv,
677                                               u8 ra_offset_direction,
678                                               u8 ra_threshold_offset)
679 {
680         struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
681
682         phydm_modify_RA_PCR_threshold(dm, ra_offset_direction,
683                                       ra_threshold_offset);
684
685         return true;
686 }
687
688 static u32 rtl_phydm_query_counter(struct rtl_priv *rtlpriv,
689                                    const char *info_type)
690 {
691         struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
692         static const struct query_entry {
693                 const char *query_name;
694                 enum phydm_info_query query_id;
695         } query_table[] = {
696 #define QUERY_ENTRY(name)       {#name, name}
697                 QUERY_ENTRY(PHYDM_INFO_FA_OFDM),
698                 QUERY_ENTRY(PHYDM_INFO_FA_CCK),
699                 QUERY_ENTRY(PHYDM_INFO_CCA_OFDM),
700                 QUERY_ENTRY(PHYDM_INFO_CCA_CCK),
701                 QUERY_ENTRY(PHYDM_INFO_CRC32_OK_CCK),
702                 QUERY_ENTRY(PHYDM_INFO_CRC32_OK_LEGACY),
703                 QUERY_ENTRY(PHYDM_INFO_CRC32_OK_HT),
704                 QUERY_ENTRY(PHYDM_INFO_CRC32_OK_VHT),
705                 QUERY_ENTRY(PHYDM_INFO_CRC32_ERROR_CCK),
706                 QUERY_ENTRY(PHYDM_INFO_CRC32_ERROR_LEGACY),
707                 QUERY_ENTRY(PHYDM_INFO_CRC32_ERROR_HT),
708                 QUERY_ENTRY(PHYDM_INFO_CRC32_ERROR_VHT),
709         };
710 #define QUERY_TABLE_SIZE        ARRAY_SIZE(query_table)
711
712         int i;
713         const struct query_entry *entry;
714
715         if (!strcmp(info_type, "IQK_TOTAL"))
716                 return dm->n_iqk_cnt;
717
718         if (!strcmp(info_type, "IQK_OK"))
719                 return dm->n_iqk_ok_cnt;
720
721         if (!strcmp(info_type, "IQK_FAIL"))
722                 return dm->n_iqk_fail_cnt;
723
724         for (i = 0; i < QUERY_TABLE_SIZE; i++) {
725                 entry = &query_table[i];
726
727                 if (!strcmp(info_type, entry->query_name))
728                         return phydm_cmn_info_query(dm, entry->query_id);
729         }
730
731         pr_err("Unrecognized info_type:%s!!!!:\n", info_type);
732
733         return 0xDEADDEAD;
734 }
735
736 static bool rtl_phydm_debug_cmd(struct rtl_priv *rtlpriv, char *in, u32 in_len,
737                                 char *out, u32 out_len)
738 {
739         struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
740
741         phydm_cmd(dm, in, in_len, 1, out, out_len);
742
743         return true;
744 }
745
746 static struct rtl_phydm_ops rtl_phydm_operation = {
747         /* init/deinit priv */
748         .phydm_init_priv = rtl_phydm_init_priv,
749         .phydm_deinit_priv = rtl_phydm_deinit_priv,
750         .phydm_load_txpower_by_rate = rtl_phydm_load_txpower_by_rate,
751         .phydm_load_txpower_limit = rtl_phydm_load_txpower_limit,
752
753         /* init hw */
754         .phydm_init_dm = rtl_phydm_init_dm,
755         .phydm_deinit_dm = rtl_phydm_deinit_dm,
756         .phydm_reset_dm = rtl_phydm_reset_dm,
757         .phydm_parameter_init = rtl_phydm_parameter_init,
758         .phydm_phy_bb_config = rtl_phydm_phy_bb_config,
759         .phydm_phy_rf_config = rtl_phydm_phy_rf_config,
760         .phydm_phy_mac_config = rtl_phydm_phy_mac_config,
761         .phydm_trx_mode = rtl_phydm_trx_mode,
762
763         /* watchdog */
764         .phydm_watchdog = rtl_phydm_watchdog,
765
766         /* channel */
767         .phydm_switch_band = rtl_phydm_switch_band,
768         .phydm_switch_channel = rtl_phydm_switch_channel,
769         .phydm_switch_bandwidth = rtl_phydm_switch_bandwidth,
770         .phydm_iq_calibrate = rtl_phydm_iq_calibrate,
771         .phydm_clear_txpowertracking_state =
772                 rtl_phydm_clear_txpowertracking_state,
773         .phydm_pause_dig = rtl_phydm_pause_dig,
774
775         /* read/write reg */
776         .phydm_read_rf_reg = rtl_phydm_read_rf_reg,
777         .phydm_write_rf_reg = rtl_phydm_write_rf_reg,
778         .phydm_read_txagc = rtl_phydm_read_txagc,
779         .phydm_write_txagc = rtl_phydm_write_txagc,
780
781         /* RX */
782         .phydm_c2h_content_parsing = rtl_phydm_c2h_content_parsing,
783         .phydm_query_phy_status = rtl_phydm_query_phy_status,
784
785         /* TX */
786         .phydm_rate_id_mapping = rtl_phydm_rate_id_mapping,
787         .phydm_get_ra_bitmap = rtl_phydm_get_ra_bitmap,
788
789         /* STA */
790         .phydm_add_sta = rtl_phydm_add_sta,
791         .phydm_del_sta = rtl_phydm_del_sta,
792
793         /* BTC */
794         .phydm_get_version = rtl_phydm_get_version,
795         .phydm_modify_ra_pcr_threshold = rtl_phydm_modify_ra_pcr_threshold,
796         .phydm_query_counter = rtl_phydm_query_counter,
797
798         /* debug */
799         .phydm_debug_cmd = rtl_phydm_debug_cmd,
800 };
801
802 struct rtl_phydm_ops *rtl_phydm_get_ops_pointer(void)
803 {
804         return &rtl_phydm_operation;
805 }
806 EXPORT_SYMBOL(rtl_phydm_get_ops_pointer);
807
808 /* ********************************************************
809  * Define phydm callout function in below
810  * ********************************************************
811  */
812
813 u8 phy_get_tx_power_index(void *adapter, u8 rf_path, u8 rate,
814                           enum ht_channel_width bandwidth, u8 channel)
815 {
816         /* rate: DESC_RATE1M */
817         struct rtl_priv *rtlpriv = (struct rtl_priv *)adapter;
818
819         return rtlpriv->cfg->ops->get_txpower_index(rtlpriv->hw, rf_path, rate,
820                                                     bandwidth, channel);
821 }
822
823 void phy_set_tx_power_index_by_rs(void *adapter, u8 ch, u8 path, u8 rs)
824 {
825         struct rtl_priv *rtlpriv = (struct rtl_priv *)adapter;
826
827         return rtlpriv->cfg->ops->set_tx_power_index_by_rs(rtlpriv->hw, ch,
828                                                            path, rs);
829 }
830
831 void phy_store_tx_power_by_rate(void *adapter, u32 band, u32 rfpath, u32 txnum,
832                                 u32 regaddr, u32 bitmask, u32 data)
833 {
834         struct rtl_priv *rtlpriv = (struct rtl_priv *)adapter;
835
836         rtlpriv->cfg->ops->store_tx_power_by_rate(
837                 rtlpriv->hw, band, rfpath, txnum, regaddr, bitmask, data);
838 }
839
840 void phy_set_tx_power_limit(void *dm, u8 *regulation, u8 *band, u8 *bandwidth,
841                             u8 *rate_section, u8 *rf_path, u8 *channel,
842                             u8 *power_limit)
843 {
844         struct rtl_priv *rtlpriv =
845                 (struct rtl_priv *)((struct phy_dm_struct *)dm)->adapter;
846
847         rtlpriv->cfg->ops->phy_set_txpower_limit(rtlpriv->hw, regulation, band,
848                                                  bandwidth, rate_section,
849                                                  rf_path, channel, power_limit);
850 }
851
852 void rtl_hal_update_ra_mask(void *adapter, struct rtl_sta_info *psta,
853                             u8 rssi_level)
854 {
855         struct rtl_priv *rtlpriv = (struct rtl_priv *)adapter;
856         struct ieee80211_sta *sta =
857                 container_of((void *)psta, struct ieee80211_sta, drv_priv);
858
859         rtlpriv->cfg->ops->update_rate_tbl(rtlpriv->hw, sta, rssi_level, false);
860 }
861
862 MODULE_AUTHOR("Realtek WlanFAE  <wlanfae@realtek.com>");
863 MODULE_AUTHOR("Larry Finger     <Larry.FInger@lwfinger.net>");
864 MODULE_LICENSE("GPL");
865 MODULE_DESCRIPTION("Realtek 802.11n PCI wireless core");