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