1
2
3
4
5
6
7
8
9
10
11
12
13
14#include "mp_precomp.h"
15#include "phydm_precomp.h"
16
17static void odm_set_crystal_cap(void *dm_void, u8 crystal_cap)
18{
19 struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void;
20 struct cfo_tracking *cfo_track =
21 (struct cfo_tracking *)phydm_get_structure(dm, PHYDM_CFOTRACK);
22
23 if (cfo_track->crystal_cap == crystal_cap)
24 return;
25
26 cfo_track->crystal_cap = crystal_cap;
27
28 if (dm->support_ic_type & (ODM_RTL8188E | ODM_RTL8188F)) {
29
30 crystal_cap = crystal_cap & 0x3F;
31 odm_set_bb_reg(dm, REG_AFE_XTAL_CTRL, 0x007ff800,
32 (crystal_cap | (crystal_cap << 6)));
33 } else if (dm->support_ic_type & ODM_RTL8812) {
34
35 crystal_cap = crystal_cap & 0x3F;
36 odm_set_bb_reg(dm, REG_MAC_PHY_CTRL, 0x7FF80000,
37 (crystal_cap | (crystal_cap << 6)));
38 } else if ((dm->support_ic_type & (ODM_RTL8703B | ODM_RTL8723B |
39 ODM_RTL8192E | ODM_RTL8821))) {
40
41 crystal_cap = crystal_cap & 0x3F;
42 odm_set_bb_reg(dm, REG_MAC_PHY_CTRL, 0x00FFF000,
43 (crystal_cap | (crystal_cap << 6)));
44 } else if (dm->support_ic_type & ODM_RTL8814A) {
45
46 crystal_cap = crystal_cap & 0x3F;
47 odm_set_bb_reg(dm, REG_MAC_PHY_CTRL, 0x07FF8000,
48 (crystal_cap | (crystal_cap << 6)));
49 } else if (dm->support_ic_type & (ODM_RTL8822B | ODM_RTL8821C)) {
50
51 crystal_cap = crystal_cap & 0x3F;
52 odm_set_bb_reg(dm, REG_AFE_XTAL_CTRL, 0x7e000000, crystal_cap);
53 odm_set_bb_reg(dm, REG_AFE_PLL_CTRL, 0x7e, crystal_cap);
54 } else {
55 ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING,
56 "%s(): Use default setting.\n", __func__);
57 odm_set_bb_reg(dm, REG_MAC_PHY_CTRL, 0xFFF000,
58 (crystal_cap | (crystal_cap << 6)));
59 }
60
61 ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING, "%s(): crystal_cap = 0x%x\n",
62 __func__, crystal_cap);
63
64
65}
66
67static u8 odm_get_default_crytaltal_cap(void *dm_void)
68{
69 struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void;
70 u8 crystal_cap = 0x20;
71
72 struct rtl_priv *rtlpriv = (struct rtl_priv *)dm->adapter;
73 struct rtl_efuse *rtlefuse = rtl_efuse(rtlpriv);
74
75 crystal_cap = rtlefuse->crystalcap;
76
77 crystal_cap = crystal_cap & 0x3f;
78
79 return crystal_cap;
80}
81
82static void odm_set_atc_status(void *dm_void, bool atc_status)
83{
84 struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void;
85 struct cfo_tracking *cfo_track =
86 (struct cfo_tracking *)phydm_get_structure(dm, PHYDM_CFOTRACK);
87
88 if (cfo_track->is_atc_status == atc_status)
89 return;
90
91 odm_set_bb_reg(dm, ODM_REG(BB_ATC, dm), ODM_BIT(BB_ATC, dm),
92 atc_status);
93 cfo_track->is_atc_status = atc_status;
94}
95
96static bool odm_get_atc_status(void *dm_void)
97{
98 bool atc_status;
99 struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void;
100
101 atc_status = (bool)odm_get_bb_reg(dm, ODM_REG(BB_ATC, dm),
102 ODM_BIT(BB_ATC, dm));
103 return atc_status;
104}
105
106void odm_cfo_tracking_reset(void *dm_void)
107{
108 struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void;
109 struct cfo_tracking *cfo_track =
110 (struct cfo_tracking *)phydm_get_structure(dm, PHYDM_CFOTRACK);
111
112 cfo_track->def_x_cap = odm_get_default_crytaltal_cap(dm);
113 cfo_track->is_adjust = true;
114
115 if (cfo_track->crystal_cap > cfo_track->def_x_cap) {
116 odm_set_crystal_cap(dm, cfo_track->crystal_cap - 1);
117 ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING,
118 "%s(): approch default value (0x%x)\n", __func__,
119 cfo_track->crystal_cap);
120 } else if (cfo_track->crystal_cap < cfo_track->def_x_cap) {
121 odm_set_crystal_cap(dm, cfo_track->crystal_cap + 1);
122 ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING,
123 "%s(): approch default value (0x%x)\n", __func__,
124 cfo_track->crystal_cap);
125 }
126
127 odm_set_atc_status(dm, true);
128}
129
130void odm_cfo_tracking_init(void *dm_void)
131{
132 struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void;
133 struct cfo_tracking *cfo_track =
134 (struct cfo_tracking *)phydm_get_structure(dm, PHYDM_CFOTRACK);
135
136 cfo_track->crystal_cap = odm_get_default_crytaltal_cap(dm);
137 cfo_track->def_x_cap = cfo_track->crystal_cap;
138 cfo_track->is_atc_status = odm_get_atc_status(dm);
139 cfo_track->is_adjust = true;
140 ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING, "%s()=========>\n", __func__);
141 ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING,
142 "%s(): is_atc_status = %d, crystal_cap = 0x%x\n", __func__,
143 cfo_track->is_atc_status, cfo_track->def_x_cap);
144
145
146 if (dm->support_ic_type & ODM_RTL8822B)
147 odm_set_bb_reg(dm, 0x10, 0x40, 0x1);
148}
149
150void odm_cfo_tracking(void *dm_void)
151{
152 struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void;
153 struct cfo_tracking *cfo_track =
154 (struct cfo_tracking *)phydm_get_structure(dm, PHYDM_CFOTRACK);
155 s32 cfo_ave = 0;
156 u32 cfo_rpt_sum, cfo_khz_avg[4] = {0};
157 s32 cfo_ave_diff;
158 s8 crystal_cap = cfo_track->crystal_cap;
159 u8 adjust_xtal = 1, i, valid_path_cnt = 0;
160
161
162 if (!(dm->support_ability & ODM_BB_CFO_TRACKING)) {
163 ODM_RT_TRACE(
164 dm, ODM_COMP_CFO_TRACKING,
165 "%s(): Return: support_ability ODM_BB_CFO_TRACKING is disabled\n",
166 __func__);
167 return;
168 }
169
170 ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING, "%s()=========>\n", __func__);
171
172 if (!dm->is_linked || !dm->is_one_entry_only) {
173
174 odm_cfo_tracking_reset(dm);
175 ODM_RT_TRACE(
176 dm, ODM_COMP_CFO_TRACKING,
177 "%s(): Reset: is_linked = %d, is_one_entry_only = %d\n",
178 __func__, dm->is_linked, dm->is_one_entry_only);
179 } else {
180
181
182 if (cfo_track->packet_count == cfo_track->packet_count_pre) {
183 ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING,
184 "%s(): packet counter doesn't change\n",
185 __func__);
186 return;
187 }
188 cfo_track->packet_count_pre = cfo_track->packet_count;
189
190
191 for (i = 0; i < dm->num_rf_path; i++) {
192 if (cfo_track->CFO_cnt[i] == 0)
193 continue;
194
195 valid_path_cnt++;
196 cfo_rpt_sum =
197 (u32)((cfo_track->CFO_tail[i] < 0) ?
198 (0 - cfo_track->CFO_tail[i]) :
199 cfo_track->CFO_tail[i]);
200 cfo_khz_avg[i] = CFO_HW_RPT_2_MHZ(cfo_rpt_sum) /
201 cfo_track->CFO_cnt[i];
202
203 ODM_RT_TRACE(
204 dm, ODM_COMP_CFO_TRACKING,
205 "[path %d] cfo_rpt_sum = (( %d )), CFO_cnt = (( %d )) , CFO_avg= (( %s%d )) kHz\n",
206 i, cfo_rpt_sum, cfo_track->CFO_cnt[i],
207 ((cfo_track->CFO_tail[i] < 0) ? "-" : " "),
208 cfo_khz_avg[i]);
209 }
210
211 for (i = 0; i < valid_path_cnt; i++) {
212 if (cfo_track->CFO_tail[i] < 0) {
213
214 cfo_ave += (0 - (s32)cfo_khz_avg[i]);
215 } else {
216 cfo_ave += (s32)cfo_khz_avg[i];
217 }
218 }
219
220 if (valid_path_cnt >= 2)
221 cfo_ave = cfo_ave / valid_path_cnt;
222
223 ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING,
224 "valid_path_cnt = ((%d)), cfo_ave = ((%d kHz))\n",
225 valid_path_cnt, cfo_ave);
226
227
228 for (i = 0; i < dm->num_rf_path; i++) {
229 cfo_track->CFO_tail[i] = 0;
230 cfo_track->CFO_cnt[i] = 0;
231 }
232
233
234 cfo_ave_diff = (cfo_track->CFO_ave_pre >= cfo_ave) ?
235 (cfo_track->CFO_ave_pre - cfo_ave) :
236 (cfo_ave - cfo_track->CFO_ave_pre);
237 if (cfo_ave_diff > 20 && cfo_track->large_cfo_hit == 0 &&
238 !cfo_track->is_adjust) {
239 ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING,
240 "%s(): first large CFO hit\n", __func__);
241 cfo_track->large_cfo_hit = 1;
242 return;
243 }
244
245 cfo_track->large_cfo_hit = 0;
246 cfo_track->CFO_ave_pre = cfo_ave;
247
248
249 if (!cfo_track->is_adjust) {
250 if (cfo_ave > CFO_TH_XTAL_HIGH ||
251 cfo_ave < (-CFO_TH_XTAL_HIGH))
252 cfo_track->is_adjust = true;
253 } else {
254 if (cfo_ave < CFO_TH_XTAL_LOW &&
255 cfo_ave > (-CFO_TH_XTAL_LOW))
256 cfo_track->is_adjust = false;
257 }
258
259
260 if (dm->is_bt_enabled) {
261 cfo_track->is_adjust = false;
262 odm_set_crystal_cap(dm, cfo_track->def_x_cap);
263 ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING,
264 "%s(): Disable CFO tracking for BT!!\n",
265 __func__);
266 }
267
268
269 if (cfo_track->is_adjust) {
270 if (cfo_ave > CFO_TH_XTAL_LOW)
271 crystal_cap = crystal_cap + adjust_xtal;
272 else if (cfo_ave < (-CFO_TH_XTAL_LOW))
273 crystal_cap = crystal_cap - adjust_xtal;
274
275 if (crystal_cap > 0x3f)
276 crystal_cap = 0x3f;
277 else if (crystal_cap < 0)
278 crystal_cap = 0;
279
280 odm_set_crystal_cap(dm, (u8)crystal_cap);
281 }
282 ODM_RT_TRACE(
283 dm, ODM_COMP_CFO_TRACKING,
284 "%s(): Crystal cap = 0x%x, Default Crystal cap = 0x%x\n",
285 __func__, cfo_track->crystal_cap, cfo_track->def_x_cap);
286
287 if (dm->support_ic_type & ODM_IC_11AC_SERIES)
288 return;
289
290
291 if (cfo_ave < CFO_TH_ATC && cfo_ave > -CFO_TH_ATC) {
292 odm_set_atc_status(dm, false);
293 ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING,
294 "%s(): Disable ATC!!\n", __func__);
295 } else {
296 odm_set_atc_status(dm, true);
297 ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING,
298 "%s(): Enable ATC!!\n", __func__);
299 }
300 }
301}
302
303void odm_parsing_cfo(void *dm_void, void *pktinfo_void, s8 *pcfotail, u8 num_ss)
304{
305 struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void;
306 struct dm_per_pkt_info *pktinfo =
307 (struct dm_per_pkt_info *)pktinfo_void;
308 struct cfo_tracking *cfo_track =
309 (struct cfo_tracking *)phydm_get_structure(dm, PHYDM_CFOTRACK);
310 u8 i;
311
312 if (!(dm->support_ability & ODM_BB_CFO_TRACKING))
313 return;
314
315 if (pktinfo->is_packet_match_bssid) {
316 if (num_ss > dm->num_rf_path)
317 num_ss = dm->num_rf_path;
318
319
320
321 for (i = 0; i < num_ss; i++) {
322 cfo_track->CFO_tail[i] += pcfotail[i];
323 cfo_track->CFO_cnt[i]++;
324 }
325
326
327 if (cfo_track->packet_count == 0xffffffff)
328 cfo_track->packet_count = 0;
329 else
330 cfo_track->packet_count++;
331 }
332}
333