xref: /OK3568_Linux_fs/external/rkwifibt/drivers/rtl8852bs/phl/phl_regulation_6g.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /******************************************************************************
2  *
3  * Copyright(c) 2020 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  *****************************************************************************/
15 #include "phl_headers.h"
16 #include "phl_chnlplan.h"
17 #include "phl_chnlplan_6g.h"
18 #include "phl_country.h"
19 
20 extern const struct chdef_6ghz chdef6g[MAX_CHDEF_6GHZ];
21 extern const struct regulatory_domain_mapping_6g rdmap6[MAX_RD_MAP_NUM_6GHZ];
22 
_get_6ghz_ch_info(const struct chdef_6ghz * chdef,u8 group,u32 * ch,u32 * passive,u8 * max_num,u8 * ch_start)23 static void _get_6ghz_ch_info(const struct chdef_6ghz *chdef,
24 	u8 group, u32 *ch, u32 *passive, u8 *max_num, u8 *ch_start)
25 {
26 	switch (group) {
27 	case FREQ_GROUP_6GHZ_UNII5:
28 		*ch = ((chdef->support_ch_u5[2] << 16) |
29 			(chdef->support_ch_u5[1] << 8) |
30 			(chdef->support_ch_u5[0]));
31 		*passive = ((chdef->passive_u5[2] << 16) |
32 			(chdef->passive_u5[1] << 8) |
33 			(chdef->passive_u5[0]));
34 		*max_num = MAX_CH_NUM_UNII5;
35 		*ch_start = 1;
36 		break;
37 	case FREQ_GROUP_6GHZ_UNII6:
38 		*ch = chdef->support_ch_u6;
39 		*passive = chdef->passive_u6;
40 		*max_num = MAX_CH_NUM_UNII6;
41 		*ch_start = 97;
42 		break;
43 	case FREQ_GROUP_6GHZ_UNII7:
44 		*ch = ((chdef->support_ch_u7[2] << 16) |
45 			(chdef->support_ch_u7[1] << 8) |
46 			(chdef->support_ch_u7[0]));
47 		*passive = ((chdef->passive_u7[2] << 16) |
48 			(chdef->passive_u7[1] << 8) |
49 			(chdef->passive_u7[0]));
50 		*max_num = MAX_CH_NUM_UNII7;
51 		*ch_start = 121;
52 		break;
53 	case FREQ_GROUP_6GHZ_UNII8:
54 		*ch = ((chdef->support_ch_u8[1] << 8) |
55 			(chdef->support_ch_u8[0]));
56 		*passive = ((chdef->passive_u8[1] << 8) |
57 			(chdef->passive_u8[0]));
58 		*max_num = MAX_CH_NUM_UNII8;
59 		*ch_start = 193;
60 		break;
61 	default:
62 		*ch = 0;
63 		*passive = 0;
64 		*max_num = 0;
65 		*ch_start = 0;
66 		break;
67 	}
68 }
69 
_convert_ch6g(u8 unii_6g,struct rtw_regulation * rg,u32 * ch_cnt,struct rtw_regulation_channel * rch,u32 ch,u32 passive,u8 max_num,u8 ch_start)70 static void _convert_ch6g(u8 unii_6g, struct rtw_regulation *rg,
71 			u32 *ch_cnt, struct rtw_regulation_channel *rch,
72 			u32 ch, u32 passive, u8 max_num, u8 ch_start)
73 {
74 	u16 i = 0;
75 	u32 shift = 0;
76 	u8 property = 0;
77 	u32 cnt = 0;
78 
79 	PHL_INFO("[REGU], convert 6 ghz unii-%d channels, from %d, ch=0x%x, passive = 0x%x \n",
80 			unii_6g, ch_start, ch, passive);
81 
82 	for (i = 0; i < max_num; i++) {
83 		shift = (1 << i);
84 		if (ch & shift) {
85 			property = 0;
86 			rch[*ch_cnt].band = BAND_ON_6G;
87 			rch[*ch_cnt].channel = (u8)(ch_start + (i * 4));
88 
89 			if (passive & shift)
90 				property |= CH_PASSIVE;
91 			if ((rch[*ch_cnt].channel % 16) == 5)
92 				property |= CH_PSC;
93 
94 			rch[*ch_cnt].property = property;
95 			PHL_INFO("[REGU], ch: %d%s%s \n",
96 				rch[*ch_cnt].channel,
97 				((property & CH_PASSIVE) ? ", passive" : ""),
98 				((property & CH_PSC) ? ", psc" : ""));
99 			(*ch_cnt)++;
100 			cnt++;
101 		}
102 	}
103 
104 	PHL_INFO("[REGU], converted channels : %d\n", cnt);
105 }
106 
_update_psc_group(struct rtw_regulation * rg)107 static void _update_psc_group(struct rtw_regulation *rg)
108 {
109 	u8 group = FREQ_GROUP_6GHZ_UNII5;
110 	struct rtw_regulation_chplan_group *plan =
111 		&rg->chplan[FREQ_GROUP_6GHZ_PSC];
112 	struct rtw_regulation_chplan_group *src = NULL;
113 	u32 i = 0, j = 0;
114 
115 	plan->cnt = 0;
116 	for (i = 0; i < 4; i++) {
117 		group = (u8)(i + FREQ_GROUP_6GHZ_UNII5);
118 		src = &rg->chplan[group];
119 
120 		for (j = 0; j < src->cnt; j++) {
121 			if (src->ch[j].property & CH_PSC) {
122 				plan->ch[plan->cnt].band =
123 					src->ch[j].band;
124 				plan->ch[plan->cnt].channel =
125 					src->ch[j].channel;
126 				plan->ch[plan->cnt].property =
127 					src->ch[j].property;
128 				plan->cnt++;
129 			}
130 		}
131 	}
132 }
133 
_chnlplan_update_6g(struct rtw_regulation * rg,u8 regulation,u8 ch_idx)134 static bool _chnlplan_update_6g(struct rtw_regulation *rg,
135 			u8 regulation, u8 ch_idx)
136 {
137 	const struct chdef_6ghz *chdef = NULL;
138 	struct rtw_regulation_chplan_group *plan = NULL;
139 	u8 group = FREQ_GROUP_6GHZ_UNII5;
140 	u8 max_num = 0, ch_start = 0;
141 	u16 i = 0;
142 	u32 ch = 0, passive = 0;
143 	u32 total = 0;
144 
145 	if (regulation >= REGULATION_MAX)
146 		return false;
147 
148 	for (i = 0; i < MAX_CHDEF_6GHZ; i++) {
149 		if (ch_idx == chdef6g[i].idx) {
150 			chdef = &chdef6g[i];
151 			break;
152 		}
153 	}
154 
155 	if (!chdef)
156 		return false;
157 
158 	rg->ch_idx6g = ch_idx;
159 	rg->regulation_6g = regulation;
160 
161 	for (i = 0; i < 4; i++) {
162 		group = (u8)(i + FREQ_GROUP_6GHZ_UNII5);
163 		plan = &rg->chplan[group];
164 		plan->cnt = 0;
165 		_get_6ghz_ch_info(chdef, group,
166 			&ch, &passive, &max_num, &ch_start);
167 		_convert_ch6g((u8)(i + 5), rg, &plan->cnt, plan->ch,
168 			ch, passive, max_num, ch_start);
169 		total += plan->cnt;
170 	}
171 
172 	_update_psc_group(rg);
173 
174 	PHL_INFO("[REGU], 6 GHz, total channel = %d\n", total);
175 
176 	return true;
177 }
178 
_domain_index_6g(u16 domain)179 static u8 _domain_index_6g(u16 domain)
180 {
181 	u8 i = 0;
182 
183 	for (i = 0; i < MAX_RD_MAP_NUM_6GHZ; i++) {
184 		if (domain == rdmap6[i].domain_code) {
185 			return i;
186 		}
187 	}
188 
189 	return MAX_RD_MAP_NUM_6GHZ;
190 }
191 
_regulatory_domain_update_6g(struct rtw_regulation * rg,u16 domain,enum regulation_rsn reason)192 static bool _regulatory_domain_update_6g(struct rtw_regulation *rg,
193 			u16 domain, enum regulation_rsn reason)
194 {
195 	u8 regulation = REGULATION_NA;
196 	u8 ch_idx = 0, did = 0;
197 
198 	rg->domain_6g.reason = reason;
199 	if (domain == RSVD_DOMAIN) {
200 		rg->domain_6g.code = RSVD_DOMAIN;
201 		return true;
202 	} else {
203 		/* Note: only valid domain index can reach here */
204 		did = _domain_index_6g(domain);
205 		rg->domain_6g.code = rdmap6[did].domain_code;
206 		regulation = rdmap6[did].regulation;
207 		ch_idx = rdmap6[did].ch_idx;
208 		return _chnlplan_update_6g(rg, regulation, ch_idx);
209 	}
210 }
211 
_get_group_chplan_6g(struct rtw_regulation * rg,struct rtw_regulation_chplan_group * group,struct rtw_regulation_chplan * plan)212 static void _get_group_chplan_6g(struct rtw_regulation *rg,
213 			struct rtw_regulation_chplan_group *group,
214 			struct rtw_regulation_chplan *plan)
215 {
216 	u32 i = 0;
217 
218 	for (i = 0; i < group->cnt; i++) {
219 		if (group->ch[i].channel) {
220 			plan->ch[plan->cnt].band =
221 				group->ch[i].band;
222 			plan->ch[plan->cnt].channel =
223 				group->ch[i].channel;
224 			plan->ch[plan->cnt].property =
225 				group->ch[i].property;
226 			plan->cnt++;
227 		}
228 	}
229 }
230 
_history_log_6g(struct rtw_regulation * rg,u16 domain,u8 reason)231 static void _history_log_6g(struct rtw_regulation *rg, u16 domain, u8 reason)
232 {
233 	rg->history_6g[rg->history_cnt_6g].code = domain;
234 	rg->history_6g[rg->history_cnt_6g].reason = reason;
235 	rg->history_cnt_6g++;
236 	if (rg->history_cnt_6g >= MAX_HISTORY_NUM)
237 		rg->history_cnt_6g = 0;
238 }
239 
regu_get_chnlplan_6g(struct rtw_regulation * rg,enum rtw_regulation_query type,struct rtw_regulation_chplan * plan)240 void regu_get_chnlplan_6g(struct rtw_regulation *rg,
241 				enum rtw_regulation_query type,
242 				struct rtw_regulation_chplan *plan)
243 {
244 	struct rtw_regulation_chplan_group *group = NULL;
245 
246 	/* 6ghz */
247 	if (rg->capability & CAPABILITY_6GHZ) {
248 		/* unii5 */
249 		if (type == REGULQ_CHPLAN_6GHZ ||
250 			type == REGULQ_CHPLAN_6GHZ_UNII5) {
251 			group = &rg->chplan[FREQ_GROUP_6GHZ_UNII5];
252 			_get_group_chplan_6g(rg, group, plan);
253 		}
254 		/* unii6 */
255 		if (type == REGULQ_CHPLAN_6GHZ ||
256 			type == REGULQ_CHPLAN_6GHZ_UNII6) {
257 			group = &rg->chplan[FREQ_GROUP_6GHZ_UNII6];
258 			_get_group_chplan_6g(rg, group, plan);
259 		}
260 		/* unii7 */
261 		if (type == REGULQ_CHPLAN_6GHZ ||
262 			type == REGULQ_CHPLAN_6GHZ_UNII7) {
263 			group = &rg->chplan[FREQ_GROUP_6GHZ_UNII7];
264 			_get_group_chplan_6g(rg, group, plan);
265 		}
266 		/* unii8 */
267 		if (type == REGULQ_CHPLAN_6GHZ ||
268 			type == REGULQ_CHPLAN_6GHZ_UNII8) {
269 			group = &rg->chplan[FREQ_GROUP_6GHZ_UNII8];
270 			_get_group_chplan_6g(rg, group, plan);
271 		}
272 		/* psc */
273 		if (type == REGULQ_CHPLAN_FULL ||
274 			type == REGULQ_CHPLAN_6GHZ_PSC) {
275 			group = &rg->chplan[FREQ_GROUP_6GHZ_PSC];
276 			_get_group_chplan_6g(rg, group, plan);
277 		}
278 	}
279 }
280 
regu_valid_domain_6g(u16 domain)281 bool regu_valid_domain_6g(u16 domain)
282 {
283 	if (domain == RSVD_DOMAIN)
284 		return true;
285 
286 	if (_domain_index_6g(domain) >= MAX_RD_MAP_NUM_6GHZ)
287 		return false;
288 
289 	return true;
290 }
291 
regu_set_domain_6g(void * phl,u16 domain,enum regulation_rsn reason)292 bool regu_set_domain_6g(void *phl, u16 domain,
293 				       	enum regulation_rsn reason)
294 {
295 	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
296 	struct rtw_regulation *rg = NULL;
297 	void *d = NULL;
298 
299 	PHL_INFO("[REGU], set 6 ghz domain code = 0x%x, reason = 0x%x\n",
300 			domain, reason);
301 
302 	if (!phl_info)
303 		return false;
304 
305 	rg = &phl_info->regulation;
306 	if (!rg->init)
307 		return false;
308 
309 	if (!regu_valid_domain_6g(domain))
310 		return false;
311 
312 	d = phl_to_drvpriv(phl_info);
313 
314 	_os_spinlock(d, &rg->lock, _bh, NULL);
315 
316 	_history_log_6g(rg, domain, reason);
317 
318 	if (_regulatory_domain_update_6g(rg, domain, reason))
319 		rg->valid_6g = true;
320 	else {
321 		rg->valid_6g = false;
322 		rg->invalid_cnt_6g++;
323 	}
324 	_os_spinunlock(d, &rg->lock, _bh, NULL);
325 
326 	PHL_INFO("[REGU], 6 ghz domain code valid = %d\n", rg->valid_6g);
327 
328 	return rg->valid_6g;
329 }
330 
331 
332