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