xref: /linux/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.c (revision 1a9239bb4253f9076b5b4b2a1a4e8d7defd77a95)
1 // SPDX-License-Identifier: ISC
2 /* Copyright (C) 2023 MediaTek Inc. */
3 
4 #include <linux/acpi.h>
5 #include "mt792x.h"
6 
7 static const char * const cc_list_all[] = {
8 	"00", "EU", "AR", "AU", "AZ", "BY", "BO", "BR",
9 	"CA", "CL", "CN", "ID", "JP", "MY", "MX", "ME",
10 	"MA", "NZ", "NG", "PH", "RU", "RS", "SG", "KR",
11 	"TW", "TH", "UA", "GB", "US", "VN", "KH", "PY",
12 };
13 
14 static const char * const cc_list_eu[] = {
15 	"AD", "AT", "BE", "BG", "CY", "CZ", "HR", "DK",
16 	"EE", "FI", "FR", "DE", "GR", "HU", "IS", "IE",
17 	"IT", "LV", "LI", "LT", "LU", "MC", "MT", "NL",
18 	"NO", "PL", "PT", "RO", "SK", "SI", "ES", "SE",
19 	"CH",
20 };
21 
22 static const char * const cc_list_be[] = {
23 	"AR", "BR", "BY", "CL", "IQ", "MX", "OM", "RU",
24 	"RW", "VN", "KR", "UA", "", "", "", "",
25 	"EU", "AT", "CN", "CA", "TW", "NZ", "PH", "UK",
26 	"US",
27 };
28 
29 static int
mt792x_acpi_read(struct mt792x_dev * dev,u8 * method,u8 ** tbl,u32 * len)30 mt792x_acpi_read(struct mt792x_dev *dev, u8 *method, u8 **tbl, u32 *len)
31 {
32 	struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
33 	struct mt76_dev *mdev = &dev->mt76;
34 	union acpi_object *sar_root;
35 	acpi_handle root, handle;
36 	acpi_status status;
37 	u32 i = 0;
38 	int ret;
39 
40 	root = ACPI_HANDLE(mdev->dev);
41 	if (!root)
42 		return -EOPNOTSUPP;
43 
44 	status = acpi_get_handle(root, method, &handle);
45 	if (ACPI_FAILURE(status))
46 		return -EIO;
47 
48 	status = acpi_evaluate_object(handle, NULL, NULL, &buf);
49 	if (ACPI_FAILURE(status))
50 		return -EIO;
51 
52 	sar_root = buf.pointer;
53 	if (sar_root->type != ACPI_TYPE_PACKAGE ||
54 	    sar_root->package.count < 4 ||
55 	    sar_root->package.elements[0].type != ACPI_TYPE_INTEGER) {
56 		dev_err(mdev->dev, "sar cnt = %d\n",
57 			sar_root->package.count);
58 		ret = -EINVAL;
59 		goto free;
60 	}
61 
62 	if (!*tbl) {
63 		*tbl = devm_kzalloc(mdev->dev, sar_root->package.count,
64 				    GFP_KERNEL);
65 		if (!*tbl) {
66 			ret = -ENOMEM;
67 			goto free;
68 		}
69 	}
70 
71 	if (len)
72 		*len = sar_root->package.count;
73 
74 	for (i = 0; i < sar_root->package.count; i++) {
75 		union acpi_object *sar_unit = &sar_root->package.elements[i];
76 
77 		if (sar_unit->type != ACPI_TYPE_INTEGER)
78 			break;
79 
80 		*(*tbl + i) = (u8)sar_unit->integer.value;
81 	}
82 
83 	ret = i == sar_root->package.count ? 0 : -EINVAL;
84 free:
85 	kfree(sar_root);
86 
87 	return ret;
88 }
89 
90 /* MTCL : Country List Table for 6G band */
91 /* MTCL : Country List Table for 6G band and 11BE */
92 static int
mt792x_asar_acpi_read_mtcl(struct mt792x_dev * dev,u8 ** table,u8 * version)93 mt792x_asar_acpi_read_mtcl(struct mt792x_dev *dev, u8 **table, u8 *version)
94 {
95 	int len, ret;
96 
97 	ret = mt792x_acpi_read(dev, MT792x_ACPI_MTCL, table, &len);
98 	if (ret)
99 		return ret;
100 
101 	if (len == sizeof(struct mt792x_asar_cl))
102 		*version = ((struct mt792x_asar_cl *)*table)->version;
103 	else if (len == sizeof(struct mt792x_asar_cl_v3))
104 		*version = ((struct mt792x_asar_cl_v3 *)*table)->version;
105 	else
106 		return -EINVAL;
107 
108 	return ret;
109 }
110 
111 /* MTDS : Dynamic SAR Power Table */
112 static int
mt792x_asar_acpi_read_mtds(struct mt792x_dev * dev,u8 ** table,u8 version)113 mt792x_asar_acpi_read_mtds(struct mt792x_dev *dev, u8 **table, u8 version)
114 {
115 	int len, ret, sarlen, prelen, tblcnt;
116 	bool enable;
117 
118 	ret = mt792x_acpi_read(dev, MT792x_ACPI_MTDS, table, &len);
119 	if (ret)
120 		return ret;
121 
122 	/* Table content validation */
123 	switch (version) {
124 	case 1:
125 		enable = ((struct mt792x_asar_dyn *)*table)->enable;
126 		sarlen = sizeof(struct mt792x_asar_dyn_limit);
127 		prelen = sizeof(struct mt792x_asar_dyn);
128 		break;
129 	case 2:
130 		enable = ((struct mt792x_asar_dyn_v2 *)*table)->enable;
131 		sarlen = sizeof(struct mt792x_asar_dyn_limit_v2);
132 		prelen = sizeof(struct mt792x_asar_dyn_v2);
133 		break;
134 	default:
135 		return -EINVAL;
136 	}
137 
138 	tblcnt = (len - prelen) / sarlen;
139 	if (!enable ||
140 	    tblcnt > MT792x_ASAR_MAX_DYN || tblcnt < MT792x_ASAR_MIN_DYN)
141 		return -EINVAL;
142 
143 	return 0;
144 }
145 
146 /* MTGS : Geo SAR Power Table */
147 static int
mt792x_asar_acpi_read_mtgs(struct mt792x_dev * dev,u8 ** table,u8 version)148 mt792x_asar_acpi_read_mtgs(struct mt792x_dev *dev, u8 **table, u8 version)
149 {
150 	int len, ret, sarlen, prelen, tblcnt;
151 
152 	ret = mt792x_acpi_read(dev, MT792x_ACPI_MTGS, table, &len);
153 	if (ret)
154 		return ret;
155 
156 	/* Table content validation */
157 	switch (version) {
158 	case 1:
159 		sarlen = sizeof(struct mt792x_asar_geo_limit);
160 		prelen = sizeof(struct mt792x_asar_geo);
161 		break;
162 	case 2:
163 		sarlen = sizeof(struct mt792x_asar_geo_limit_v2);
164 		prelen = sizeof(struct mt792x_asar_geo_v2);
165 		break;
166 	default:
167 		return -EINVAL;
168 	}
169 
170 	tblcnt = (len - prelen) / sarlen;
171 	if (tblcnt > MT792x_ASAR_MAX_GEO || tblcnt < MT792x_ASAR_MIN_GEO)
172 		return -EINVAL;
173 
174 	return 0;
175 }
176 
177 /* MTFG : Flag Table */
178 static int
mt792x_asar_acpi_read_mtfg(struct mt792x_dev * dev,u8 ** table)179 mt792x_asar_acpi_read_mtfg(struct mt792x_dev *dev, u8 **table)
180 {
181 	int len, ret;
182 
183 	ret = mt792x_acpi_read(dev, MT792x_ACPI_MTFG, table, &len);
184 	if (ret)
185 		return ret;
186 
187 	if (len < MT792x_ASAR_MIN_FG)
188 		return -EINVAL;
189 
190 	return 0;
191 }
192 
mt792x_init_acpi_sar(struct mt792x_dev * dev)193 int mt792x_init_acpi_sar(struct mt792x_dev *dev)
194 {
195 	struct mt792x_acpi_sar *asar;
196 	int ret;
197 
198 	asar = devm_kzalloc(dev->mt76.dev, sizeof(*asar), GFP_KERNEL);
199 	if (!asar)
200 		return -ENOMEM;
201 
202 	ret = mt792x_asar_acpi_read_mtcl(dev, (u8 **)&asar->countrylist, &asar->ver);
203 	if (ret) {
204 		devm_kfree(dev->mt76.dev, asar->countrylist);
205 		asar->countrylist = NULL;
206 	}
207 
208 	ret = mt792x_asar_acpi_read_mtds(dev, (u8 **)&asar->dyn, asar->ver);
209 	if (ret) {
210 		devm_kfree(dev->mt76.dev, asar->dyn);
211 		asar->dyn = NULL;
212 	}
213 
214 	/* MTGS is optional */
215 	ret = mt792x_asar_acpi_read_mtgs(dev, (u8 **)&asar->geo, asar->ver);
216 	if (ret) {
217 		devm_kfree(dev->mt76.dev, asar->geo);
218 		asar->geo = NULL;
219 	}
220 
221 	/* MTFG is optional */
222 	ret = mt792x_asar_acpi_read_mtfg(dev, (u8 **)&asar->fg);
223 	if (ret) {
224 		devm_kfree(dev->mt76.dev, asar->fg);
225 		asar->fg = NULL;
226 	}
227 	dev->phy.acpisar = asar;
228 
229 	return 0;
230 }
231 EXPORT_SYMBOL_GPL(mt792x_init_acpi_sar);
232 
233 static s8
mt792x_asar_get_geo_pwr(struct mt792x_phy * phy,enum nl80211_band band,s8 dyn_power)234 mt792x_asar_get_geo_pwr(struct mt792x_phy *phy,
235 			enum nl80211_band band, s8 dyn_power)
236 {
237 	struct mt792x_acpi_sar *asar = phy->acpisar;
238 	struct mt792x_asar_geo_band *band_pwr;
239 	s8 geo_power;
240 	u8 idx, max;
241 
242 	if (!asar->geo)
243 		return dyn_power;
244 
245 	switch (phy->mt76->dev->region) {
246 	case NL80211_DFS_FCC:
247 		idx = 0;
248 		break;
249 	case NL80211_DFS_ETSI:
250 		idx = 1;
251 		break;
252 	default: /* WW */
253 		idx = 2;
254 		break;
255 	}
256 
257 	if (asar->ver == 1) {
258 		band_pwr = &asar->geo->tbl[idx].band[0];
259 		max = ARRAY_SIZE(asar->geo->tbl[idx].band);
260 	} else {
261 		band_pwr = &asar->geo_v2->tbl[idx].band[0];
262 		max = ARRAY_SIZE(asar->geo_v2->tbl[idx].band);
263 	}
264 
265 	switch (band) {
266 	case NL80211_BAND_2GHZ:
267 		idx = 0;
268 		break;
269 	case NL80211_BAND_5GHZ:
270 		idx = 1;
271 		break;
272 	case NL80211_BAND_6GHZ:
273 		idx = 2;
274 		break;
275 	default:
276 		return dyn_power;
277 	}
278 
279 	if (idx >= max)
280 		return dyn_power;
281 
282 	geo_power = (band_pwr + idx)->pwr;
283 	dyn_power += (band_pwr + idx)->offset;
284 
285 	return min(geo_power, dyn_power);
286 }
287 
288 static s8
mt792x_asar_range_pwr(struct mt792x_phy * phy,const struct cfg80211_sar_freq_ranges * range,u8 idx)289 mt792x_asar_range_pwr(struct mt792x_phy *phy,
290 		      const struct cfg80211_sar_freq_ranges *range,
291 		      u8 idx)
292 {
293 	const struct cfg80211_sar_capa *capa = phy->mt76->hw->wiphy->sar_capa;
294 	struct mt792x_acpi_sar *asar = phy->acpisar;
295 	u8 *limit, band, max;
296 
297 	if (!capa)
298 		return 127;
299 
300 	if (asar->ver == 1) {
301 		limit = &asar->dyn->tbl[0].frp[0];
302 		max = ARRAY_SIZE(asar->dyn->tbl[0].frp);
303 	} else {
304 		limit = &asar->dyn_v2->tbl[0].frp[0];
305 		max = ARRAY_SIZE(asar->dyn_v2->tbl[0].frp);
306 	}
307 
308 	if (idx >= max)
309 		return 127;
310 
311 	if (range->start_freq >= 5945)
312 		band = NL80211_BAND_6GHZ;
313 	else if (range->start_freq >= 5150)
314 		band = NL80211_BAND_5GHZ;
315 	else
316 		band = NL80211_BAND_2GHZ;
317 
318 	return mt792x_asar_get_geo_pwr(phy, band, limit[idx]);
319 }
320 
mt792x_init_acpi_sar_power(struct mt792x_phy * phy,bool set_default)321 int mt792x_init_acpi_sar_power(struct mt792x_phy *phy, bool set_default)
322 {
323 	const struct cfg80211_sar_capa *capa = phy->mt76->hw->wiphy->sar_capa;
324 	int i;
325 
326 	if (!phy->acpisar || !((struct mt792x_acpi_sar *)phy->acpisar)->dyn)
327 		return 0;
328 
329 	/* When ACPI SAR enabled in HW, we should apply rules for .frp
330 	 * 1. w/o .sar_specs : set ACPI SAR power as the defatul value
331 	 * 2. w/  .sar_specs : set power with min(.sar_specs, ACPI_SAR)
332 	 */
333 	for (i = 0; i < capa->num_freq_ranges; i++) {
334 		struct mt76_freq_range_power *frp = &phy->mt76->frp[i];
335 
336 		frp->range = set_default ? &capa->freq_ranges[i] : frp->range;
337 		if (!frp->range)
338 			continue;
339 
340 		frp->power = min_t(s8, set_default ? 127 : frp->power,
341 				   mt792x_asar_range_pwr(phy, frp->range, i));
342 	}
343 
344 	return 0;
345 }
346 EXPORT_SYMBOL_GPL(mt792x_init_acpi_sar_power);
347 
mt792x_acpi_get_flags(struct mt792x_phy * phy)348 u8 mt792x_acpi_get_flags(struct mt792x_phy *phy)
349 {
350 	struct mt792x_acpi_sar *acpisar = phy->acpisar;
351 	struct mt792x_asar_fg *fg;
352 	struct {
353 		u8 acpi_idx;
354 		u8 chip_idx;
355 	} map[] = {
356 		{ 1, 1 },
357 		{ 4, 2 },
358 	};
359 	u8 flags = BIT(0);
360 	int i, j;
361 
362 	if (!acpisar)
363 		return 0;
364 
365 	fg = acpisar->fg;
366 	if (!fg)
367 		return flags;
368 
369 	/* pickup necessary settings per device and
370 	 * translate the index of bitmap for chip command.
371 	 */
372 	for (i = 0; i < fg->nr_flag; i++) {
373 		for (j = 0; j < ARRAY_SIZE(map); j++) {
374 			if (fg->flag[i] == map[j].acpi_idx) {
375 				flags |= BIT(map[j].chip_idx);
376 				break;
377 			}
378 		}
379 	}
380 
381 	return flags;
382 }
383 EXPORT_SYMBOL_GPL(mt792x_acpi_get_flags);
384 
385 static u32
mt792x_acpi_get_mtcl_map_v3(int row,int column,struct mt792x_asar_cl_v3 * cl)386 mt792x_acpi_get_mtcl_map_v3(int row, int column, struct mt792x_asar_cl_v3 *cl)
387 {
388 	u32 config = 0;
389 	u8 mode_be = 0;
390 
391 	mode_be = (cl->mode_be > 0x02) ? 0 : cl->mode_be;
392 
393 	if (cl->version > 2 && cl->clbe[row] & BIT(column))
394 		config |= (mode_be & 0x3) << 4;
395 
396 	return config;
397 }
398 
399 static u32
mt792x_acpi_get_mtcl_map(int row,int column,struct mt792x_asar_cl * cl)400 mt792x_acpi_get_mtcl_map(int row, int column, struct mt792x_asar_cl *cl)
401 {
402 	u32 config = 0;
403 	u8 mode_6g, mode_5g9;
404 
405 	mode_6g = (cl->mode_6g > 0x02) ? 0 : cl->mode_6g;
406 	mode_5g9 = (cl->mode_5g9 > 0x01) ? 0 : cl->mode_5g9;
407 
408 	if ((cl->cl6g[row] & BIT(column)) || cl->mode_6g == 0x02)
409 		config |= (mode_6g & 0x3) << 2;
410 	if (cl->version > 1 && cl->cl5g9[row] & BIT(column))
411 		config |= (mode_5g9 & 0x3);
412 
413 	return config;
414 }
415 
416 static u32
mt792x_acpi_parse_mtcl_tbl_v3(struct mt792x_phy * phy,char * alpha2)417 mt792x_acpi_parse_mtcl_tbl_v3(struct mt792x_phy *phy, char *alpha2)
418 {
419 	struct mt792x_acpi_sar *sar = phy->acpisar;
420 	struct mt792x_asar_cl_v3 *cl = sar->countrylist_v3;
421 	int col, row, i;
422 
423 	if (sar->ver != 3)
424 		goto out;
425 
426 	if (!cl)
427 		return MT792X_ACPI_MTCL_INVALID;
428 
429 	for (i = 0; i < ARRAY_SIZE(cc_list_be); i++) {
430 		col = 7 - i % 8;
431 		row = i / 8;
432 		if (!memcmp(cc_list_be[i], alpha2, 2))
433 			return mt792x_acpi_get_mtcl_map_v3(row, col, cl);
434 	}
435 	for (i = 0; i < ARRAY_SIZE(cc_list_eu); i++) {
436 		if (!memcmp(cc_list_eu[i], alpha2, 2))
437 			return mt792x_acpi_get_mtcl_map_v3(3, 7, cl);
438 	}
439 
440 out:
441 	/* Depends on driver */
442 	return 0x20;
443 }
444 
445 static u32
mt792x_acpi_parse_mtcl_tbl(struct mt792x_phy * phy,char * alpha2)446 mt792x_acpi_parse_mtcl_tbl(struct mt792x_phy *phy, char *alpha2)
447 {
448 	struct mt792x_acpi_sar *sar = phy->acpisar;
449 	struct mt792x_asar_cl *cl = sar->countrylist;
450 	int col, row, i;
451 
452 	if (!cl)
453 		return MT792X_ACPI_MTCL_INVALID;
454 
455 	for (i = 0; i < ARRAY_SIZE(cc_list_all); i++) {
456 		col = 7 - i % 8;
457 		row = i / 8;
458 		if (!memcmp(cc_list_all[i], alpha2, 2))
459 			return mt792x_acpi_get_mtcl_map(row, col, cl);
460 	}
461 
462 	for (i = 0; i < ARRAY_SIZE(cc_list_eu); i++)
463 		if (!memcmp(cc_list_eu[i], alpha2, 2))
464 			return mt792x_acpi_get_mtcl_map(0, 6, cl);
465 
466 	return mt792x_acpi_get_mtcl_map(0, 7, cl);
467 }
468 
mt792x_acpi_get_mtcl_conf(struct mt792x_phy * phy,char * alpha2)469 u32 mt792x_acpi_get_mtcl_conf(struct mt792x_phy *phy, char *alpha2)
470 {
471 	struct mt792x_acpi_sar *sar = phy->acpisar;
472 	u32 config = 0;
473 
474 	if (!sar)
475 		return MT792X_ACPI_MTCL_INVALID;
476 
477 	config = mt792x_acpi_parse_mtcl_tbl_v3(phy, alpha2);
478 
479 	if (config == MT792X_ACPI_MTCL_INVALID)
480 		return MT792X_ACPI_MTCL_INVALID;
481 
482 	config |= mt792x_acpi_parse_mtcl_tbl(phy, alpha2);
483 
484 	return config;
485 }
486 EXPORT_SYMBOL_GPL(mt792x_acpi_get_mtcl_conf);
487