GNU Linux-libre 4.19.264-gnu1
[releases.git] / drivers / staging / rtlwifi / phydm / rtl8822b / phydm_rtl8822b.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
15 #include "../mp_precomp.h"
16 #include "../phydm_precomp.h"
17
18 static void phydm_dynamic_switch_htstf_mumimo_8822b(struct phy_dm_struct *dm)
19 {
20         /*if rssi > 40dBm, enable HT-STF gain controller,
21          *otherwise, if rssi < 40dBm, disable the controller
22          */
23         /*add by Chun-Hung Ho 20160711 */
24         if (dm->rssi_min >= 40)
25                 odm_set_bb_reg(dm, 0x8d8, BIT(17), 0x1);
26         else if (dm->rssi_min < 35)
27                 odm_set_bb_reg(dm, 0x8d8, BIT(17), 0x0);
28
29         ODM_RT_TRACE(dm, ODM_COMP_COMMON, "%s, rssi_min = %d\n", __func__,
30                      dm->rssi_min);
31 }
32
33 static void _set_tx_a_cali_value(struct phy_dm_struct *dm, u8 rf_path,
34                                  u8 offset, u8 tx_a_bias_offset)
35 {
36         u32 modi_tx_a_value = 0;
37         u8 tmp1_byte = 0;
38         bool is_minus = false;
39         u8 comp_value = 0;
40
41         switch (offset) {
42         case 0x0:
43                 odm_set_rf_reg(dm, rf_path, 0x18, 0xFFFFF, 0X10124);
44                 break;
45         case 0x1:
46                 odm_set_rf_reg(dm, rf_path, 0x18, 0xFFFFF, 0X10524);
47                 break;
48         case 0x2:
49                 odm_set_rf_reg(dm, rf_path, 0x18, 0xFFFFF, 0X10924);
50                 break;
51         case 0x3:
52                 odm_set_rf_reg(dm, rf_path, 0x18, 0xFFFFF, 0X10D24);
53                 break;
54         case 0x4:
55                 odm_set_rf_reg(dm, rf_path, 0x18, 0xFFFFF, 0X30164);
56                 break;
57         case 0x5:
58                 odm_set_rf_reg(dm, rf_path, 0x18, 0xFFFFF, 0X30564);
59                 break;
60         case 0x6:
61                 odm_set_rf_reg(dm, rf_path, 0x18, 0xFFFFF, 0X30964);
62                 break;
63         case 0x7:
64                 odm_set_rf_reg(dm, rf_path, 0x18, 0xFFFFF, 0X30D64);
65                 break;
66         case 0x8:
67                 odm_set_rf_reg(dm, rf_path, 0x18, 0xFFFFF, 0X50195);
68                 break;
69         case 0x9:
70                 odm_set_rf_reg(dm, rf_path, 0x18, 0xFFFFF, 0X50595);
71                 break;
72         case 0xa:
73                 odm_set_rf_reg(dm, rf_path, 0x18, 0xFFFFF, 0X50995);
74                 break;
75         case 0xb:
76                 odm_set_rf_reg(dm, rf_path, 0x18, 0xFFFFF, 0X50D95);
77                 break;
78         default:
79                 ODM_RT_TRACE(dm, ODM_COMP_COMMON,
80                              "Invalid TxA band offset...\n");
81                 return;
82         }
83
84         /* Get TxA value */
85         modi_tx_a_value = odm_get_rf_reg(dm, rf_path, 0x61, 0xFFFFF);
86         tmp1_byte = (u8)modi_tx_a_value & (BIT(3) | BIT(2) | BIT(1) | BIT(0));
87
88         /* check how much need to calibration */
89         switch (tx_a_bias_offset) {
90         case 0xF6:
91                 is_minus = true;
92                 comp_value = 3;
93                 break;
94
95         case 0xF4:
96                 is_minus = true;
97                 comp_value = 2;
98                 break;
99
100         case 0xF2:
101                 is_minus = true;
102                 comp_value = 1;
103                 break;
104
105         case 0xF3:
106                 is_minus = false;
107                 comp_value = 1;
108                 break;
109
110         case 0xF5:
111                 is_minus = false;
112                 comp_value = 2;
113                 break;
114
115         case 0xF7:
116                 is_minus = false;
117                 comp_value = 3;
118                 break;
119
120         case 0xF9:
121                 is_minus = false;
122                 comp_value = 4;
123                 break;
124
125         /* do nothing case */
126         case 0xF0:
127         default:
128                 ODM_RT_TRACE(dm, ODM_COMP_COMMON,
129                              "No need to do TxA bias current calibration\n");
130                 return;
131         }
132
133         /* calc correct value to calibrate */
134         if (is_minus) {
135                 if (tmp1_byte >= comp_value) {
136                         tmp1_byte -= comp_value;
137                         /*modi_tx_a_value += tmp1_byte;*/
138                 } else {
139                         tmp1_byte = 0;
140                 }
141         } else {
142                 tmp1_byte += comp_value;
143                 if (tmp1_byte >= 7)
144                         tmp1_byte = 7;
145         }
146
147         /* Write back to RF reg */
148         odm_set_rf_reg(dm, rf_path, 0x30, 0xFFFF,
149                        (offset << 12 | (modi_tx_a_value & 0xFF0) | tmp1_byte));
150 }
151
152 static void _txa_bias_cali_4_each_path(struct phy_dm_struct *dm, u8 rf_path,
153                                        u8 efuse_value)
154 {
155         /* switch on set TxA bias */
156         odm_set_rf_reg(dm, rf_path, 0xEF, 0xFFFFF, 0x200);
157
158         /* Set 12 sets of TxA value */
159         _set_tx_a_cali_value(dm, rf_path, 0x0, efuse_value);
160         _set_tx_a_cali_value(dm, rf_path, 0x1, efuse_value);
161         _set_tx_a_cali_value(dm, rf_path, 0x2, efuse_value);
162         _set_tx_a_cali_value(dm, rf_path, 0x3, efuse_value);
163         _set_tx_a_cali_value(dm, rf_path, 0x4, efuse_value);
164         _set_tx_a_cali_value(dm, rf_path, 0x5, efuse_value);
165         _set_tx_a_cali_value(dm, rf_path, 0x6, efuse_value);
166         _set_tx_a_cali_value(dm, rf_path, 0x7, efuse_value);
167         _set_tx_a_cali_value(dm, rf_path, 0x8, efuse_value);
168         _set_tx_a_cali_value(dm, rf_path, 0x9, efuse_value);
169         _set_tx_a_cali_value(dm, rf_path, 0xa, efuse_value);
170         _set_tx_a_cali_value(dm, rf_path, 0xb, efuse_value);
171
172         /* switch off set TxA bias */
173         odm_set_rf_reg(dm, rf_path, 0xEF, 0xFFFFF, 0x0);
174 }
175
176 /*
177  * for 8822B PCIE D-cut patch only
178  * Normal driver and MP driver need this patch
179  */
180
181 void phydm_txcurrentcalibration(struct phy_dm_struct *dm)
182 {
183         u8 efuse0x3D8, efuse0x3D7;
184         u32 orig_rf0x18_path_a = 0, orig_rf0x18_path_b = 0;
185
186         /* save original 0x18 value */
187         orig_rf0x18_path_a = odm_get_rf_reg(dm, ODM_RF_PATH_A, 0x18, 0xFFFFF);
188         orig_rf0x18_path_b = odm_get_rf_reg(dm, ODM_RF_PATH_B, 0x18, 0xFFFFF);
189
190         /* define efuse content */
191         efuse0x3D8 = dm->efuse0x3d8;
192         efuse0x3D7 = dm->efuse0x3d7;
193
194         /* check efuse content to judge whether need to calibration or not */
195         if (efuse0x3D7 == 0xFF) {
196                 ODM_RT_TRACE(
197                         dm, ODM_COMP_COMMON,
198                         "efuse content 0x3D7 == 0xFF, No need to do TxA cali\n");
199                 return;
200         }
201
202         /* write RF register for calibration */
203         _txa_bias_cali_4_each_path(dm, ODM_RF_PATH_A, efuse0x3D7);
204         _txa_bias_cali_4_each_path(dm, ODM_RF_PATH_B, efuse0x3D8);
205
206         /* restore original 0x18 value */
207         odm_set_rf_reg(dm, ODM_RF_PATH_A, 0x18, 0xFFFFF, orig_rf0x18_path_a);
208         odm_set_rf_reg(dm, ODM_RF_PATH_B, 0x18, 0xFFFFF, orig_rf0x18_path_b);
209 }
210
211 void phydm_hwsetting_8822b(struct phy_dm_struct *dm)
212 {
213         phydm_dynamic_switch_htstf_mumimo_8822b(dm);
214 }