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
mt792x_acpi_read(struct mt792x_dev * dev,u8 * method,u8 ** tbl,u32 * len)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
mt792x_asar_acpi_read_mtcl(struct mt792x_dev * dev,u8 ** table,u8 * version)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
mt792x_asar_acpi_read_mtds(struct mt792x_dev * dev,u8 ** table,u8 version)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
mt792x_asar_acpi_read_mtgs(struct mt792x_dev * dev,u8 ** table,u8 version)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
mt792x_asar_acpi_read_mtfg(struct mt792x_dev * dev,u8 ** table)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
mt792x_init_acpi_sar(struct mt792x_dev * dev)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
mt792x_asar_get_geo_pwr(struct mt792x_phy * phy,enum nl80211_band band,s8 dyn_power)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
mt792x_asar_range_pwr(struct mt792x_phy * phy,const struct cfg80211_sar_freq_ranges * range,u8 idx)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
mt792x_init_acpi_sar_power(struct mt792x_phy * phy,bool set_default)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
mt792x_acpi_get_flags(struct mt792x_phy * phy)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