1// SPDX-License-Identifier: ISC
2/* Copyright (C) 2023 MediaTek Inc. */
3
4#include <linux/acpi.h>
5#include "mt792x.h"
6
7static int
8mt792x_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;
62free:
63	kfree(sar_root);
64
65	return ret;
66}
67
68/* MTCL : Country List Table for 6G band */
69static int
70mt792x_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 */
81static int
82mt792x_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 */
116static int
117mt792x_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 */
147static int
148mt792x_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
162int 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}
200EXPORT_SYMBOL_GPL(mt792x_init_acpi_sar);
201
202static s8
203mt792x_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
257static s8
258mt792x_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
290int 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}
315EXPORT_SYMBOL_GPL(mt792x_init_acpi_sar_power);
316
317u8 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}
352EXPORT_SYMBOL_GPL(mt792x_acpi_get_flags);
353
354static u8
355mt792x_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
371u8 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}
409EXPORT_SYMBOL_GPL(mt792x_acpi_get_mtcl_conf);
410