linux/drivers/staging/rtlwifi/phydm/phydm_cfotracking.c
<<
>>
Prefs
   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
  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                /* write 0x24[22:17] = 0x24[16:11] = crystal_cap */
  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                /* write 0x2C[30:25] = 0x2C[24:19] = crystal_cap */
  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                /* 0x2C[23:18] = 0x2C[17:12] = crystal_cap */
  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                /* write 0x2C[26:21] = 0x2C[20:15] = crystal_cap */
  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                /* write 0x24[30:25] = 0x28[6:1] = crystal_cap */
  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        /* JJ modified 20161115 */
  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        /* Crystal cap. control by WiFi */
 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        /* 4 Support ability */
 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                /* 4 No link or more than one entry */
 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                /* 3 1. CFO Tracking */
 181                /* 4 1.1 No new packet */
 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                /* 4 1.2 Calculate CFO */
 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                /*reset counter*/
 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                /* 4 1.3 Avoid abnormal large CFO */
 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                /* 4 1.4 Dynamic Xtal threshold */
 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                /* 4 1.5 BT case: Disable CFO tracking */
 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                /* 4 1.7 Adjust Crystal Cap. */
 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                /* 3 2. Dynamic ATC switch */
 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) /*For fool proof*/
 317                        num_ss = dm->num_rf_path;
 318
 319                /* 3 Update CFO report for path-A & path-B */
 320                /* Only paht-A and path-B have CFO tail and short CFO */
 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                /* 3 Update packet counter */
 327                if (cfo_track->packet_count == 0xffffffff)
 328                        cfo_track->packet_count = 0;
 329                else
 330                        cfo_track->packet_count++;
 331        }
 332}
 333