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