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