aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/rtlwifi/phydm/phydm_acs.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/rtlwifi/phydm/phydm_acs.c')
-rw-r--r--drivers/staging/rtlwifi/phydm/phydm_acs.c200
1 files changed, 200 insertions, 0 deletions
diff --git a/drivers/staging/rtlwifi/phydm/phydm_acs.c b/drivers/staging/rtlwifi/phydm/phydm_acs.c
new file mode 100644
index 000000000000..eae5a0a24b9b
--- /dev/null
+++ b/drivers/staging/rtlwifi/phydm/phydm_acs.c
@@ -0,0 +1,200 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2016 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+/* ************************************************************
+ * include files
+ * *************************************************************/
+#include "mp_precomp.h"
+#include "phydm_precomp.h"
+
+u8 odm_get_auto_channel_select_result(void *dm_void, u8 band)
+{
+ struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void;
+ struct acs_info *acs = &dm->dm_acs;
+ u8 result;
+
+ if (band == ODM_BAND_2_4G) {
+ ODM_RT_TRACE(
+ dm, ODM_COMP_ACS,
+ "[struct acs_info] %s(): clean_channel_2g(%d)\n",
+ __func__, acs->clean_channel_2g);
+ result = (u8)acs->clean_channel_2g;
+ } else {
+ ODM_RT_TRACE(
+ dm, ODM_COMP_ACS,
+ "[struct acs_info] %s(): clean_channel_5g(%d)\n",
+ __func__, acs->clean_channel_5g);
+ result = (u8)acs->clean_channel_5g;
+ }
+
+ return result;
+}
+
+static void odm_auto_channel_select_setting(void *dm_void, bool is_enable)
+{
+ struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void;
+ u16 period = 0x2710; /* 40ms in default */
+ u16 nhm_type = 0x7;
+
+ ODM_RT_TRACE(dm, ODM_COMP_ACS, "%s()=========>\n", __func__);
+
+ if (is_enable) {
+ /* 20 ms */
+ period = 0x1388;
+ nhm_type = 0x1;
+ }
+
+ if (dm->support_ic_type & ODM_IC_11AC_SERIES) {
+ /* PHY parameters initialize for ac series */
+
+ /* 0x990[31:16]=0x2710
+ * Time duration for NHM unit: 4us, 0x2710=40ms
+ */
+ odm_write_2byte(dm, ODM_REG_CCX_PERIOD_11AC + 2, period);
+ } else if (dm->support_ic_type & ODM_IC_11N_SERIES) {
+ /* PHY parameters initialize for n series */
+
+ /* 0x894[31:16]=0x2710
+ * Time duration for NHM unit: 4us, 0x2710=40ms
+ */
+ odm_write_2byte(dm, ODM_REG_CCX_PERIOD_11N + 2, period);
+ }
+}
+
+void odm_auto_channel_select_init(void *dm_void)
+{
+ struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void;
+ struct acs_info *acs = &dm->dm_acs;
+ u8 i;
+
+ if (!(dm->support_ability & ODM_BB_NHM_CNT))
+ return;
+
+ if (acs->is_force_acs_result)
+ return;
+
+ ODM_RT_TRACE(dm, ODM_COMP_ACS, "%s()=========>\n", __func__);
+
+ acs->clean_channel_2g = 1;
+ acs->clean_channel_5g = 36;
+
+ for (i = 0; i < ODM_MAX_CHANNEL_2G; ++i) {
+ acs->channel_info_2g[0][i] = 0;
+ acs->channel_info_2g[1][i] = 0;
+ }
+
+ if (dm->support_ic_type & ODM_IC_11AC_SERIES) {
+ for (i = 0; i < ODM_MAX_CHANNEL_5G; ++i) {
+ acs->channel_info_5g[0][i] = 0;
+ acs->channel_info_5g[1][i] = 0;
+ }
+ }
+}
+
+void odm_auto_channel_select_reset(void *dm_void)
+{
+ struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void;
+ struct acs_info *acs = &dm->dm_acs;
+
+ if (!(dm->support_ability & ODM_BB_NHM_CNT))
+ return;
+
+ if (acs->is_force_acs_result)
+ return;
+
+ ODM_RT_TRACE(dm, ODM_COMP_ACS, "%s()=========>\n", __func__);
+
+ odm_auto_channel_select_setting(dm, true); /* for 20ms measurement */
+ phydm_nhm_counter_statistics_reset(dm);
+}
+
+void odm_auto_channel_select(void *dm_void, u8 channel)
+{
+ struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void;
+ struct acs_info *acs = &dm->dm_acs;
+ u8 channel_idx = 0, search_idx = 0;
+ u16 max_score = 0;
+
+ if (!(dm->support_ability & ODM_BB_NHM_CNT)) {
+ ODM_RT_TRACE(
+ dm, ODM_COMP_DIG,
+ "%s(): Return: support_ability ODM_BB_NHM_CNT is disabled\n",
+ __func__);
+ return;
+ }
+
+ if (acs->is_force_acs_result) {
+ ODM_RT_TRACE(
+ dm, ODM_COMP_DIG,
+ "%s(): Force 2G clean channel = %d, 5G clean channel = %d\n",
+ __func__, acs->clean_channel_2g, acs->clean_channel_5g);
+ return;
+ }
+
+ ODM_RT_TRACE(dm, ODM_COMP_ACS, "%s(): channel = %d=========>\n",
+ __func__, channel);
+
+ phydm_get_nhm_counter_statistics(dm);
+ odm_auto_channel_select_setting(dm, false);
+
+ if (channel >= 1 && channel <= 14) {
+ channel_idx = channel - 1;
+ acs->channel_info_2g[1][channel_idx]++;
+
+ if (acs->channel_info_2g[1][channel_idx] >= 2)
+ acs->channel_info_2g[0][channel_idx] =
+ (acs->channel_info_2g[0][channel_idx] >> 1) +
+ (acs->channel_info_2g[0][channel_idx] >> 2) +
+ (dm->nhm_cnt_0 >> 2);
+ else
+ acs->channel_info_2g[0][channel_idx] = dm->nhm_cnt_0;
+
+ ODM_RT_TRACE(dm, ODM_COMP_ACS, "%s(): nhm_cnt_0 = %d\n",
+ __func__, dm->nhm_cnt_0);
+ ODM_RT_TRACE(
+ dm, ODM_COMP_ACS,
+ "%s(): Channel_Info[0][%d] = %d, Channel_Info[1][%d] = %d\n",
+ __func__, channel_idx,
+ acs->channel_info_2g[0][channel_idx], channel_idx,
+ acs->channel_info_2g[1][channel_idx]);
+
+ for (search_idx = 0; search_idx < ODM_MAX_CHANNEL_2G;
+ search_idx++) {
+ if (acs->channel_info_2g[1][search_idx] != 0 &&
+ acs->channel_info_2g[0][search_idx] >= max_score) {
+ max_score = acs->channel_info_2g[0][search_idx];
+ acs->clean_channel_2g = search_idx + 1;
+ }
+ }
+ ODM_RT_TRACE(
+ dm, ODM_COMP_ACS,
+ "(1)%s(): 2G: clean_channel_2g = %d, max_score = %d\n",
+ __func__, acs->clean_channel_2g, max_score);
+
+ } else if (channel >= 36) {
+ /* Need to do */
+ acs->clean_channel_5g = channel;
+ }
+}