1 // SPDX-License-Identifier: ISC
2 /* Copyright (C) 2022 MediaTek Inc. */
3 
4 #include <linux/acpi.h>
5 #include "mt7921.h"
6 
7 static int
mt7921_acpi_read(struct mt7921_dev * dev,u8 * method,u8 ** tbl,u32 * len)8 mt7921_acpi_read(struct mt7921_dev *dev, u8 *method, u8 **tbl, u32 *len)
9 {
10 	struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
11 	union acpi_object *sar_root, *sar_unit;
12 	struct mt76_dev *mdev = &dev->mt76;
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 		goto free;
37 	}
38 
39 	if (!*tbl) {
40 		*tbl = devm_kzalloc(mdev->dev, sar_root->package.count,
41 				    GFP_KERNEL);
42 		if (!*tbl)
43 			goto free;
44 	}
45 	if (len)
46 		*len = sar_root->package.count;
47 
48 	for (i = 0; i < sar_root->package.count; i++) {
49 		sar_unit = &sar_root->package.elements[i];
50 
51 		if (sar_unit->type != ACPI_TYPE_INTEGER)
52 			break;
53 		*(*tbl + i) = (u8)sar_unit->integer.value;
54 	}
55 free:
56 	ret = (i == sar_root->package.count) ? 0 : -EINVAL;
57 
58 	kfree(sar_root);
59 
60 	return ret;
61 }
62 
63 /* MTCL : Country List Table for 6G band */
64 static int
mt7921_asar_acpi_read_mtcl(struct mt7921_dev * dev,u8 ** table,u8 * version)65 mt7921_asar_acpi_read_mtcl(struct mt7921_dev *dev, u8 **table, u8 *version)
66 {
67 	*version = (mt7921_acpi_read(dev, MT7921_ACPI_MTCL, table, NULL) < 0)
68 		   ? 1 : 2;
69 	return 0;
70 }
71 
72 /* MTDS : Dynamic SAR Power Table */
73 static int
mt7921_asar_acpi_read_mtds(struct mt7921_dev * dev,u8 ** table,u8 version)74 mt7921_asar_acpi_read_mtds(struct mt7921_dev *dev, u8 **table, u8 version)
75 {
76 	int len, ret, sarlen, prelen, tblcnt;
77 	bool enable;
78 
79 	ret = mt7921_acpi_read(dev, MT7921_ACPI_MTDS, table, &len);
80 	if (ret)
81 		return ret;
82 
83 	/* Table content validation */
84 	switch (version) {
85 	case 1:
86 		enable = ((struct mt7921_asar_dyn *)*table)->enable;
87 		sarlen = sizeof(struct mt7921_asar_dyn_limit);
88 		prelen = sizeof(struct mt7921_asar_dyn);
89 		break;
90 	case 2:
91 		enable = ((struct mt7921_asar_dyn_v2 *)*table)->enable;
92 		sarlen = sizeof(struct mt7921_asar_dyn_limit_v2);
93 		prelen = sizeof(struct mt7921_asar_dyn_v2);
94 		break;
95 	default:
96 		return -EINVAL;
97 	}
98 
99 	tblcnt = (len - prelen) / sarlen;
100 	if (!enable ||
101 	    tblcnt > MT7921_ASAR_MAX_DYN || tblcnt < MT7921_ASAR_MIN_DYN)
102 		ret = -EINVAL;
103 
104 	return ret;
105 }
106 
107 /* MTGS : Geo SAR Power Table */
108 static int
mt7921_asar_acpi_read_mtgs(struct mt7921_dev * dev,u8 ** table,u8 version)109 mt7921_asar_acpi_read_mtgs(struct mt7921_dev *dev, u8 **table, u8 version)
110 {
111 	int len, ret = 0, sarlen, prelen, tblcnt;
112 
113 	ret = mt7921_acpi_read(dev, MT7921_ACPI_MTGS, table, &len);
114 	if (ret)
115 		return ret;
116 
117 	/* Table content validation */
118 	switch (version) {
119 	case 1:
120 		sarlen = sizeof(struct mt7921_asar_geo_limit);
121 		prelen = sizeof(struct mt7921_asar_geo);
122 		break;
123 	case 2:
124 		sarlen = sizeof(struct mt7921_asar_geo_limit_v2);
125 		prelen = sizeof(struct mt7921_asar_geo_v2);
126 		break;
127 	default:
128 		return -EINVAL;
129 	}
130 
131 	tblcnt = (len - prelen) / sarlen;
132 	if (tblcnt > MT7921_ASAR_MAX_GEO || tblcnt < MT7921_ASAR_MIN_GEO)
133 		ret = -EINVAL;
134 
135 	return ret;
136 }
137 
mt7921_init_acpi_sar(struct mt7921_dev * dev)138 int mt7921_init_acpi_sar(struct mt7921_dev *dev)
139 {
140 	struct mt7921_acpi_sar *asar;
141 	int ret;
142 
143 	asar = devm_kzalloc(dev->mt76.dev, sizeof(*asar), GFP_KERNEL);
144 	if (!asar)
145 		return -ENOMEM;
146 
147 	mt7921_asar_acpi_read_mtcl(dev, (u8 **)&asar->countrylist, &asar->ver);
148 
149 	/* MTDS is mandatory. Return error if table is invalid */
150 	ret = mt7921_asar_acpi_read_mtds(dev, (u8 **)&asar->dyn, asar->ver);
151 	if (ret) {
152 		devm_kfree(dev->mt76.dev, asar->dyn);
153 		devm_kfree(dev->mt76.dev, asar->countrylist);
154 		devm_kfree(dev->mt76.dev, asar);
155 		return ret;
156 	}
157 
158 	/* MTGS is optional */
159 	ret = mt7921_asar_acpi_read_mtgs(dev, (u8 **)&asar->geo, asar->ver);
160 	if (ret) {
161 		devm_kfree(dev->mt76.dev, asar->geo);
162 		asar->geo = NULL;
163 	}
164 
165 	dev->phy.acpisar = asar;
166 
167 	return 0;
168 }
169 
170 static s8
mt7921_asar_get_geo_pwr(struct mt7921_phy * phy,enum nl80211_band band,s8 dyn_power)171 mt7921_asar_get_geo_pwr(struct mt7921_phy *phy,
172 			enum nl80211_band band, s8 dyn_power)
173 {
174 	struct mt7921_acpi_sar *asar = phy->acpisar;
175 	struct mt7921_asar_geo_band *band_pwr;
176 	s8 geo_power;
177 	u8 idx, max;
178 
179 	if (!asar->geo)
180 		return dyn_power;
181 
182 	switch (phy->mt76->dev->region) {
183 	case NL80211_DFS_FCC:
184 		idx = 0;
185 		break;
186 	case NL80211_DFS_ETSI:
187 		idx = 1;
188 		break;
189 	default: /* WW */
190 		idx = 2;
191 		break;
192 	}
193 
194 	if (asar->ver == 1) {
195 		band_pwr = &asar->geo->tbl[idx].band[0];
196 		max = ARRAY_SIZE(asar->geo->tbl[idx].band);
197 	} else {
198 		band_pwr = &asar->geo_v2->tbl[idx].band[0];
199 		max = ARRAY_SIZE(asar->geo_v2->tbl[idx].band);
200 	}
201 
202 	switch (band) {
203 	case NL80211_BAND_2GHZ:
204 		idx = 0;
205 		break;
206 	case NL80211_BAND_5GHZ:
207 		idx = 1;
208 		break;
209 	case NL80211_BAND_6GHZ:
210 		idx = 2;
211 		break;
212 	default:
213 		return dyn_power;
214 	}
215 
216 	if (idx >= max)
217 		return dyn_power;
218 
219 	geo_power = (band_pwr + idx)->pwr;
220 	dyn_power += (band_pwr + idx)->offset;
221 
222 	return min(geo_power, dyn_power);
223 }
224 
225 static s8
mt7921_asar_range_pwr(struct mt7921_phy * phy,const struct cfg80211_sar_freq_ranges * range,u8 idx)226 mt7921_asar_range_pwr(struct mt7921_phy *phy,
227 		      const struct cfg80211_sar_freq_ranges *range,
228 		      u8 idx)
229 {
230 	const struct cfg80211_sar_capa *capa = phy->mt76->hw->wiphy->sar_capa;
231 	struct mt7921_acpi_sar *asar = phy->acpisar;
232 	u8 *limit, band, max;
233 
234 	if (!capa)
235 		return 127;
236 
237 	if (asar->ver == 1) {
238 		limit = &asar->dyn->tbl[0].frp[0];
239 		max = ARRAY_SIZE(asar->dyn->tbl[0].frp);
240 	} else {
241 		limit = &asar->dyn_v2->tbl[0].frp[0];
242 		max = ARRAY_SIZE(asar->dyn_v2->tbl[0].frp);
243 	}
244 
245 	if (idx >= max)
246 		return 127;
247 
248 	if (range->start_freq >= 5945)
249 		band = NL80211_BAND_6GHZ;
250 	else if (range->start_freq >= 5150)
251 		band = NL80211_BAND_5GHZ;
252 	else
253 		band = NL80211_BAND_2GHZ;
254 
255 	return mt7921_asar_get_geo_pwr(phy, band, limit[idx]);
256 }
257 
mt7921_init_acpi_sar_power(struct mt7921_phy * phy,bool set_default)258 int mt7921_init_acpi_sar_power(struct mt7921_phy *phy, bool set_default)
259 {
260 	const struct cfg80211_sar_capa *capa = phy->mt76->hw->wiphy->sar_capa;
261 	int i;
262 
263 	if (!phy->acpisar)
264 		return 0;
265 
266 	/* When ACPI SAR enabled in HW, we should apply rules for .frp
267 	 * 1. w/o .sar_specs : set ACPI SAR power as the defatul value
268 	 * 2. w/  .sar_specs : set power with min(.sar_specs, ACPI_SAR)
269 	 */
270 	for (i = 0; i < capa->num_freq_ranges; i++) {
271 		struct mt76_freq_range_power *frp = &phy->mt76->frp[i];
272 
273 		frp->range = set_default ? &capa->freq_ranges[i] : frp->range;
274 		if (!frp->range)
275 			continue;
276 
277 		frp->power = min_t(s8, set_default ? 127 : frp->power,
278 				   mt7921_asar_range_pwr(phy, frp->range, i));
279 	}
280 
281 	return 0;
282 }
283