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