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