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 
odm_get_auto_channel_select_result(void * dm_void,u8 band)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 
odm_auto_channel_select_setting(void * dm_void,bool is_enable)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 
odm_auto_channel_select_init(void * dm_void)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 
odm_auto_channel_select_reset(void * dm_void)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 
odm_auto_channel_select(void * dm_void,u8 channel)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 }
190