1 /******************************************************************************
3 * Copyright(c) 2007 - 2016 Realtek Corporation.
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.
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
14 * The full GNU General Public License is included in this distribution in the
15 * file called LICENSE.
17 * Contact Information:
18 * wlanfae <wlanfae@realtek.com>
19 * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
20 * Hsinchu 300, Taiwan.
22 * Larry Finger <Larry.Finger@lwfinger.net>
24 *****************************************************************************/
25 #include "mp_precomp.h"
26 #include "phydm_precomp.h"
28 static void odm_set_crystal_cap(void *dm_void, u8 crystal_cap)
30 struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void;
31 struct cfo_tracking *cfo_track =
32 (struct cfo_tracking *)phydm_get_structure(dm, PHYDM_CFOTRACK);
34 if (cfo_track->crystal_cap == crystal_cap)
37 cfo_track->crystal_cap = crystal_cap;
39 if (dm->support_ic_type & (ODM_RTL8188E | ODM_RTL8188F)) {
40 /* write 0x24[22:17] = 0x24[16:11] = crystal_cap */
41 crystal_cap = crystal_cap & 0x3F;
42 odm_set_bb_reg(dm, REG_AFE_XTAL_CTRL, 0x007ff800,
43 (crystal_cap | (crystal_cap << 6)));
44 } else if (dm->support_ic_type & ODM_RTL8812) {
45 /* write 0x2C[30:25] = 0x2C[24:19] = crystal_cap */
46 crystal_cap = crystal_cap & 0x3F;
47 odm_set_bb_reg(dm, REG_MAC_PHY_CTRL, 0x7FF80000,
48 (crystal_cap | (crystal_cap << 6)));
49 } else if ((dm->support_ic_type & (ODM_RTL8703B | ODM_RTL8723B |
50 ODM_RTL8192E | ODM_RTL8821))) {
51 /* 0x2C[23:18] = 0x2C[17:12] = crystal_cap */
52 crystal_cap = crystal_cap & 0x3F;
53 odm_set_bb_reg(dm, REG_MAC_PHY_CTRL, 0x00FFF000,
54 (crystal_cap | (crystal_cap << 6)));
55 } else if (dm->support_ic_type & ODM_RTL8814A) {
56 /* write 0x2C[26:21] = 0x2C[20:15] = crystal_cap */
57 crystal_cap = crystal_cap & 0x3F;
58 odm_set_bb_reg(dm, REG_MAC_PHY_CTRL, 0x07FF8000,
59 (crystal_cap | (crystal_cap << 6)));
60 } else if (dm->support_ic_type & (ODM_RTL8822B | ODM_RTL8821C)) {
61 /* write 0x24[30:25] = 0x28[6:1] = crystal_cap */
62 crystal_cap = crystal_cap & 0x3F;
63 odm_set_bb_reg(dm, REG_AFE_XTAL_CTRL, 0x7e000000, crystal_cap);
64 odm_set_bb_reg(dm, REG_AFE_PLL_CTRL, 0x7e, crystal_cap);
66 ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING,
67 "%s(): Use default setting.\n", __func__);
68 odm_set_bb_reg(dm, REG_MAC_PHY_CTRL, 0xFFF000,
69 (crystal_cap | (crystal_cap << 6)));
72 ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING, "%s(): crystal_cap = 0x%x\n",
73 __func__, crystal_cap);
75 /* JJ modified 20161115 */
78 static u8 odm_get_default_crytaltal_cap(void *dm_void)
80 struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void;
81 u8 crystal_cap = 0x20;
83 struct rtl_priv *rtlpriv = (struct rtl_priv *)dm->adapter;
84 struct rtl_efuse *rtlefuse = rtl_efuse(rtlpriv);
86 crystal_cap = rtlefuse->crystalcap;
88 crystal_cap = crystal_cap & 0x3f;
93 static void odm_set_atc_status(void *dm_void, bool atc_status)
95 struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void;
96 struct cfo_tracking *cfo_track =
97 (struct cfo_tracking *)phydm_get_structure(dm, PHYDM_CFOTRACK);
99 if (cfo_track->is_atc_status == atc_status)
102 odm_set_bb_reg(dm, ODM_REG(BB_ATC, dm), ODM_BIT(BB_ATC, dm),
104 cfo_track->is_atc_status = atc_status;
107 static bool odm_get_atc_status(void *dm_void)
110 struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void;
112 atc_status = (bool)odm_get_bb_reg(dm, ODM_REG(BB_ATC, dm),
113 ODM_BIT(BB_ATC, dm));
117 void odm_cfo_tracking_reset(void *dm_void)
119 struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void;
120 struct cfo_tracking *cfo_track =
121 (struct cfo_tracking *)phydm_get_structure(dm, PHYDM_CFOTRACK);
123 cfo_track->def_x_cap = odm_get_default_crytaltal_cap(dm);
124 cfo_track->is_adjust = true;
126 if (cfo_track->crystal_cap > cfo_track->def_x_cap) {
127 odm_set_crystal_cap(dm, cfo_track->crystal_cap - 1);
128 ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING,
129 "%s(): approch default value (0x%x)\n", __func__,
130 cfo_track->crystal_cap);
131 } else if (cfo_track->crystal_cap < cfo_track->def_x_cap) {
132 odm_set_crystal_cap(dm, cfo_track->crystal_cap + 1);
133 ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING,
134 "%s(): approch default value (0x%x)\n", __func__,
135 cfo_track->crystal_cap);
138 odm_set_atc_status(dm, true);
141 void odm_cfo_tracking_init(void *dm_void)
143 struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void;
144 struct cfo_tracking *cfo_track =
145 (struct cfo_tracking *)phydm_get_structure(dm, PHYDM_CFOTRACK);
147 cfo_track->crystal_cap = odm_get_default_crytaltal_cap(dm);
148 cfo_track->def_x_cap = cfo_track->crystal_cap;
149 cfo_track->is_atc_status = odm_get_atc_status(dm);
150 cfo_track->is_adjust = true;
151 ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING, "%s()=========>\n", __func__);
152 ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING,
153 "%s(): is_atc_status = %d, crystal_cap = 0x%x\n", __func__,
154 cfo_track->is_atc_status, cfo_track->def_x_cap);
156 /* Crystal cap. control by WiFi */
157 if (dm->support_ic_type & ODM_RTL8822B)
158 odm_set_bb_reg(dm, 0x10, 0x40, 0x1);
161 void odm_cfo_tracking(void *dm_void)
163 struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void;
164 struct cfo_tracking *cfo_track =
165 (struct cfo_tracking *)phydm_get_structure(dm, PHYDM_CFOTRACK);
167 u32 cfo_rpt_sum, cfo_khz_avg[4] = {0};
169 s8 crystal_cap = cfo_track->crystal_cap;
170 u8 adjust_xtal = 1, i, valid_path_cnt = 0;
172 /* 4 Support ability */
173 if (!(dm->support_ability & ODM_BB_CFO_TRACKING)) {
175 dm, ODM_COMP_CFO_TRACKING,
176 "%s(): Return: support_ability ODM_BB_CFO_TRACKING is disabled\n",
181 ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING, "%s()=========>\n", __func__);
183 if (!dm->is_linked || !dm->is_one_entry_only) {
184 /* 4 No link or more than one entry */
185 odm_cfo_tracking_reset(dm);
187 dm, ODM_COMP_CFO_TRACKING,
188 "%s(): Reset: is_linked = %d, is_one_entry_only = %d\n",
189 __func__, dm->is_linked, dm->is_one_entry_only);
191 /* 3 1. CFO Tracking */
192 /* 4 1.1 No new packet */
193 if (cfo_track->packet_count == cfo_track->packet_count_pre) {
194 ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING,
195 "%s(): packet counter doesn't change\n",
199 cfo_track->packet_count_pre = cfo_track->packet_count;
201 /* 4 1.2 Calculate CFO */
202 for (i = 0; i < dm->num_rf_path; i++) {
203 if (cfo_track->CFO_cnt[i] == 0)
208 (u32)((cfo_track->CFO_tail[i] < 0) ?
209 (0 - cfo_track->CFO_tail[i]) :
210 cfo_track->CFO_tail[i]);
211 cfo_khz_avg[i] = CFO_HW_RPT_2_MHZ(cfo_rpt_sum) /
212 cfo_track->CFO_cnt[i];
215 dm, ODM_COMP_CFO_TRACKING,
216 "[path %d] cfo_rpt_sum = (( %d )), CFO_cnt = (( %d )) , CFO_avg= (( %s%d )) kHz\n",
217 i, cfo_rpt_sum, cfo_track->CFO_cnt[i],
218 ((cfo_track->CFO_tail[i] < 0) ? "-" : " "),
222 for (i = 0; i < valid_path_cnt; i++) {
223 if (cfo_track->CFO_tail[i] < 0) {
225 cfo_ave += (0 - (s32)cfo_khz_avg[i]);
227 cfo_ave += (s32)cfo_khz_avg[i];
231 if (valid_path_cnt >= 2)
232 cfo_ave = cfo_ave / valid_path_cnt;
234 ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING,
235 "valid_path_cnt = ((%d)), cfo_ave = ((%d kHz))\n",
236 valid_path_cnt, cfo_ave);
239 for (i = 0; i < dm->num_rf_path; i++) {
240 cfo_track->CFO_tail[i] = 0;
241 cfo_track->CFO_cnt[i] = 0;
244 /* 4 1.3 Avoid abnormal large CFO */
245 cfo_ave_diff = (cfo_track->CFO_ave_pre >= cfo_ave) ?
246 (cfo_track->CFO_ave_pre - cfo_ave) :
247 (cfo_ave - cfo_track->CFO_ave_pre);
248 if (cfo_ave_diff > 20 && cfo_track->large_cfo_hit == 0 &&
249 !cfo_track->is_adjust) {
250 ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING,
251 "%s(): first large CFO hit\n", __func__);
252 cfo_track->large_cfo_hit = 1;
256 cfo_track->large_cfo_hit = 0;
257 cfo_track->CFO_ave_pre = cfo_ave;
259 /* 4 1.4 Dynamic Xtal threshold */
260 if (!cfo_track->is_adjust) {
261 if (cfo_ave > CFO_TH_XTAL_HIGH ||
262 cfo_ave < (-CFO_TH_XTAL_HIGH))
263 cfo_track->is_adjust = true;
265 if (cfo_ave < CFO_TH_XTAL_LOW &&
266 cfo_ave > (-CFO_TH_XTAL_LOW))
267 cfo_track->is_adjust = false;
270 /* 4 1.5 BT case: Disable CFO tracking */
271 if (dm->is_bt_enabled) {
272 cfo_track->is_adjust = false;
273 odm_set_crystal_cap(dm, cfo_track->def_x_cap);
274 ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING,
275 "%s(): Disable CFO tracking for BT!!\n",
279 /* 4 1.7 Adjust Crystal Cap. */
280 if (cfo_track->is_adjust) {
281 if (cfo_ave > CFO_TH_XTAL_LOW)
282 crystal_cap = crystal_cap + adjust_xtal;
283 else if (cfo_ave < (-CFO_TH_XTAL_LOW))
284 crystal_cap = crystal_cap - adjust_xtal;
286 if (crystal_cap > 0x3f)
288 else if (crystal_cap < 0)
291 odm_set_crystal_cap(dm, (u8)crystal_cap);
294 dm, ODM_COMP_CFO_TRACKING,
295 "%s(): Crystal cap = 0x%x, Default Crystal cap = 0x%x\n",
296 __func__, cfo_track->crystal_cap, cfo_track->def_x_cap);
298 if (dm->support_ic_type & ODM_IC_11AC_SERIES)
301 /* 3 2. Dynamic ATC switch */
302 if (cfo_ave < CFO_TH_ATC && cfo_ave > -CFO_TH_ATC) {
303 odm_set_atc_status(dm, false);
304 ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING,
305 "%s(): Disable ATC!!\n", __func__);
307 odm_set_atc_status(dm, true);
308 ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING,
309 "%s(): Enable ATC!!\n", __func__);
314 void odm_parsing_cfo(void *dm_void, void *pktinfo_void, s8 *pcfotail, u8 num_ss)
316 struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void;
317 struct dm_per_pkt_info *pktinfo =
318 (struct dm_per_pkt_info *)pktinfo_void;
319 struct cfo_tracking *cfo_track =
320 (struct cfo_tracking *)phydm_get_structure(dm, PHYDM_CFOTRACK);
323 if (!(dm->support_ability & ODM_BB_CFO_TRACKING))
326 if (pktinfo->is_packet_match_bssid) {
327 if (num_ss > dm->num_rf_path) /*For fool proof*/
328 num_ss = dm->num_rf_path;
330 /* 3 Update CFO report for path-A & path-B */
331 /* Only paht-A and path-B have CFO tail and short CFO */
332 for (i = 0; i < num_ss; i++) {
333 cfo_track->CFO_tail[i] += pcfotail[i];
334 cfo_track->CFO_cnt[i]++;
337 /* 3 Update packet counter */
338 if (cfo_track->packet_count == 0xffffffff)
339 cfo_track->packet_count = 0;
341 cfo_track->packet_count++;