GNU Linux-libre 4.14.290-gnu1
[releases.git] / drivers / staging / rtlwifi / phydm / phydm_acs.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 /* ************************************************************
27  * include files
28  * *************************************************************/
29 #include "mp_precomp.h"
30 #include "phydm_precomp.h"
31
32 u8 odm_get_auto_channel_select_result(void *dm_void, u8 band)
33 {
34         struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void;
35         struct acs_info *acs = &dm->dm_acs;
36         u8 result;
37
38         if (band == ODM_BAND_2_4G) {
39                 ODM_RT_TRACE(
40                         dm, ODM_COMP_ACS,
41                         "[struct acs_info] %s(): clean_channel_2g(%d)\n",
42                         __func__, acs->clean_channel_2g);
43                 result = (u8)acs->clean_channel_2g;
44         } else {
45                 ODM_RT_TRACE(
46                         dm, ODM_COMP_ACS,
47                         "[struct acs_info] %s(): clean_channel_5g(%d)\n",
48                         __func__, acs->clean_channel_5g);
49                 result = (u8)acs->clean_channel_5g;
50         }
51
52         return result;
53 }
54
55 static void odm_auto_channel_select_setting(void *dm_void, bool is_enable)
56 {
57         struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void;
58         u16 period = 0x2710; /* 40ms in default */
59         u16 nhm_type = 0x7;
60
61         ODM_RT_TRACE(dm, ODM_COMP_ACS, "%s()=========>\n", __func__);
62
63         if (is_enable) {
64                 /* 20 ms */
65                 period = 0x1388;
66                 nhm_type = 0x1;
67         }
68
69         if (dm->support_ic_type & ODM_IC_11AC_SERIES) {
70                 /* PHY parameters initialize for ac series */
71
72                 /* 0x990[31:16]=0x2710
73                  * Time duration for NHM unit: 4us, 0x2710=40ms
74                  */
75                 odm_write_2byte(dm, ODM_REG_CCX_PERIOD_11AC + 2, period);
76         } else if (dm->support_ic_type & ODM_IC_11N_SERIES) {
77                 /* PHY parameters initialize for n series */
78
79                 /* 0x894[31:16]=0x2710
80                  * Time duration for NHM unit: 4us, 0x2710=40ms
81                  */
82                 odm_write_2byte(dm, ODM_REG_CCX_PERIOD_11N + 2, period);
83         }
84 }
85
86 void odm_auto_channel_select_init(void *dm_void)
87 {
88         struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void;
89         struct acs_info *acs = &dm->dm_acs;
90         u8 i;
91
92         if (!(dm->support_ability & ODM_BB_NHM_CNT))
93                 return;
94
95         if (acs->is_force_acs_result)
96                 return;
97
98         ODM_RT_TRACE(dm, ODM_COMP_ACS, "%s()=========>\n", __func__);
99
100         acs->clean_channel_2g = 1;
101         acs->clean_channel_5g = 36;
102
103         for (i = 0; i < ODM_MAX_CHANNEL_2G; ++i) {
104                 acs->channel_info_2g[0][i] = 0;
105                 acs->channel_info_2g[1][i] = 0;
106         }
107
108         if (dm->support_ic_type & ODM_IC_11AC_SERIES) {
109                 for (i = 0; i < ODM_MAX_CHANNEL_5G; ++i) {
110                         acs->channel_info_5g[0][i] = 0;
111                         acs->channel_info_5g[1][i] = 0;
112                 }
113         }
114 }
115
116 void odm_auto_channel_select_reset(void *dm_void)
117 {
118         struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void;
119         struct acs_info *acs = &dm->dm_acs;
120
121         if (!(dm->support_ability & ODM_BB_NHM_CNT))
122                 return;
123
124         if (acs->is_force_acs_result)
125                 return;
126
127         ODM_RT_TRACE(dm, ODM_COMP_ACS, "%s()=========>\n", __func__);
128
129         odm_auto_channel_select_setting(dm, true); /* for 20ms measurement */
130         phydm_nhm_counter_statistics_reset(dm);
131 }
132
133 void odm_auto_channel_select(void *dm_void, u8 channel)
134 {
135         struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void;
136         struct acs_info *acs = &dm->dm_acs;
137         u8 channel_idx = 0, search_idx = 0;
138         u16 max_score = 0;
139
140         if (!(dm->support_ability & ODM_BB_NHM_CNT)) {
141                 ODM_RT_TRACE(
142                         dm, ODM_COMP_DIG,
143                         "%s(): Return: support_ability ODM_BB_NHM_CNT is disabled\n",
144                         __func__);
145                 return;
146         }
147
148         if (acs->is_force_acs_result) {
149                 ODM_RT_TRACE(
150                         dm, ODM_COMP_DIG,
151                         "%s(): Force 2G clean channel = %d, 5G clean channel = %d\n",
152                         __func__, acs->clean_channel_2g, acs->clean_channel_5g);
153                 return;
154         }
155
156         ODM_RT_TRACE(dm, ODM_COMP_ACS, "%s(): channel = %d=========>\n",
157                      __func__, channel);
158
159         phydm_get_nhm_counter_statistics(dm);
160         odm_auto_channel_select_setting(dm, false);
161
162         if (channel >= 1 && channel <= 14) {
163                 channel_idx = channel - 1;
164                 acs->channel_info_2g[1][channel_idx]++;
165
166                 if (acs->channel_info_2g[1][channel_idx] >= 2)
167                         acs->channel_info_2g[0][channel_idx] =
168                                 (acs->channel_info_2g[0][channel_idx] >> 1) +
169                                 (acs->channel_info_2g[0][channel_idx] >> 2) +
170                                 (dm->nhm_cnt_0 >> 2);
171                 else
172                         acs->channel_info_2g[0][channel_idx] = dm->nhm_cnt_0;
173
174                 ODM_RT_TRACE(dm, ODM_COMP_ACS, "%s(): nhm_cnt_0 = %d\n",
175                              __func__, dm->nhm_cnt_0);
176                 ODM_RT_TRACE(
177                         dm, ODM_COMP_ACS,
178                         "%s(): Channel_Info[0][%d] = %d, Channel_Info[1][%d] = %d\n",
179                         __func__, channel_idx,
180                         acs->channel_info_2g[0][channel_idx], channel_idx,
181                         acs->channel_info_2g[1][channel_idx]);
182
183                 for (search_idx = 0; search_idx < ODM_MAX_CHANNEL_2G;
184                      search_idx++) {
185                         if (acs->channel_info_2g[1][search_idx] != 0 &&
186                             acs->channel_info_2g[0][search_idx] >= max_score) {
187                                 max_score = acs->channel_info_2g[0][search_idx];
188                                 acs->clean_channel_2g = search_idx + 1;
189                         }
190                 }
191                 ODM_RT_TRACE(
192                         dm, ODM_COMP_ACS,
193                         "(1)%s(): 2G: clean_channel_2g = %d, max_score = %d\n",
194                         __func__, acs->clean_channel_2g, max_score);
195
196         } else if (channel >= 36) {
197                 /* Need to do */
198                 acs->clean_channel_5g = channel;
199         }
200 }