Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/contrib/dev/mediatek/mt76/mt792x_acpi_sar.c
48378 views
1
// SPDX-License-Identifier: ISC
2
/* Copyright (C) 2023 MediaTek Inc. */
3
4
#include <linux/acpi.h>
5
#include "mt792x.h"
6
7
static const char * const cc_list_all[] = {
8
"00", "EU", "AR", "AU", "AZ", "BY", "BO", "BR",
9
"CA", "CL", "CN", "ID", "JP", "MY", "MX", "ME",
10
"MA", "NZ", "NG", "PH", "RU", "RS", "SG", "KR",
11
"TW", "TH", "UA", "GB", "US", "VN", "KH", "PY",
12
};
13
14
static const char * const cc_list_eu[] = {
15
"AD", "AT", "BE", "BG", "CY", "CZ", "HR", "DK",
16
"EE", "FI", "FR", "DE", "GR", "HU", "IS", "IE",
17
"IT", "LV", "LI", "LT", "LU", "MC", "MT", "NL",
18
"NO", "PL", "PT", "RO", "SK", "SI", "ES", "SE",
19
"CH",
20
};
21
22
static const char * const cc_list_be[] = {
23
"AR", "BR", "BY", "CL", "IQ", "MX", "OM", "RU",
24
"RW", "VN", "KR", "UA", "", "", "", "",
25
"EU", "AT", "CN", "CA", "TW", "NZ", "PH", "UK",
26
"US",
27
};
28
29
static int
30
mt792x_acpi_read(struct mt792x_dev *dev, u8 *method, u8 **tbl, u32 *len)
31
{
32
struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
33
struct mt76_dev *mdev = &dev->mt76;
34
union acpi_object *sar_root;
35
acpi_handle root, handle;
36
acpi_status status;
37
u32 i = 0;
38
int ret;
39
40
root = ACPI_HANDLE(mdev->dev);
41
if (!root)
42
return -EOPNOTSUPP;
43
44
status = acpi_get_handle(root, method, &handle);
45
if (ACPI_FAILURE(status))
46
return -EIO;
47
48
status = acpi_evaluate_object(handle, NULL, NULL, &buf);
49
if (ACPI_FAILURE(status))
50
return -EIO;
51
52
sar_root = buf.pointer;
53
if (sar_root->type != ACPI_TYPE_PACKAGE ||
54
sar_root->package.count < 4 ||
55
sar_root->package.elements[0].type != ACPI_TYPE_INTEGER) {
56
dev_err(mdev->dev, "sar cnt = %d\n",
57
sar_root->package.count);
58
ret = -EINVAL;
59
goto free;
60
}
61
62
if (!*tbl) {
63
*tbl = devm_kzalloc(mdev->dev, sar_root->package.count,
64
GFP_KERNEL);
65
if (!*tbl) {
66
ret = -ENOMEM;
67
goto free;
68
}
69
}
70
71
if (len)
72
*len = sar_root->package.count;
73
74
for (i = 0; i < sar_root->package.count; i++) {
75
union acpi_object *sar_unit = &sar_root->package.elements[i];
76
77
if (sar_unit->type != ACPI_TYPE_INTEGER)
78
break;
79
80
*(*tbl + i) = (u8)sar_unit->integer.value;
81
}
82
83
ret = i == sar_root->package.count ? 0 : -EINVAL;
84
free:
85
kfree(sar_root);
86
87
return ret;
88
}
89
90
/* MTCL : Country List Table for 6G band */
91
/* MTCL : Country List Table for 6G band and 11BE */
92
static int
93
mt792x_asar_acpi_read_mtcl(struct mt792x_dev *dev, u8 **table, u8 *version)
94
{
95
int len, ret;
96
97
ret = mt792x_acpi_read(dev, MT792x_ACPI_MTCL, table, &len);
98
if (ret)
99
return ret;
100
101
if (len == sizeof(struct mt792x_asar_cl))
102
*version = ((struct mt792x_asar_cl *)*table)->version;
103
else if (len == sizeof(struct mt792x_asar_cl_v3))
104
*version = ((struct mt792x_asar_cl_v3 *)*table)->version;
105
else
106
return -EINVAL;
107
108
return ret;
109
}
110
111
/* MTDS : Dynamic SAR Power Table */
112
static int
113
mt792x_asar_acpi_read_mtds(struct mt792x_dev *dev, u8 **table, u8 version)
114
{
115
int len, ret, sarlen, prelen, tblcnt;
116
bool enable;
117
118
ret = mt792x_acpi_read(dev, MT792x_ACPI_MTDS, table, &len);
119
if (ret)
120
return ret;
121
122
/* Table content validation */
123
switch (version) {
124
case 1:
125
enable = ((struct mt792x_asar_dyn *)*table)->enable;
126
sarlen = sizeof(struct mt792x_asar_dyn_limit);
127
prelen = sizeof(struct mt792x_asar_dyn);
128
break;
129
case 2:
130
enable = ((struct mt792x_asar_dyn_v2 *)*table)->enable;
131
sarlen = sizeof(struct mt792x_asar_dyn_limit_v2);
132
prelen = sizeof(struct mt792x_asar_dyn_v2);
133
break;
134
default:
135
return -EINVAL;
136
}
137
138
tblcnt = (len - prelen) / sarlen;
139
if (!enable ||
140
tblcnt > MT792x_ASAR_MAX_DYN || tblcnt < MT792x_ASAR_MIN_DYN)
141
return -EINVAL;
142
143
return 0;
144
}
145
146
/* MTGS : Geo SAR Power Table */
147
static int
148
mt792x_asar_acpi_read_mtgs(struct mt792x_dev *dev, u8 **table, u8 version)
149
{
150
int len, ret, sarlen, prelen, tblcnt;
151
152
ret = mt792x_acpi_read(dev, MT792x_ACPI_MTGS, table, &len);
153
if (ret)
154
return ret;
155
156
/* Table content validation */
157
switch (version) {
158
case 1:
159
sarlen = sizeof(struct mt792x_asar_geo_limit);
160
prelen = sizeof(struct mt792x_asar_geo);
161
break;
162
case 2:
163
sarlen = sizeof(struct mt792x_asar_geo_limit_v2);
164
prelen = sizeof(struct mt792x_asar_geo_v2);
165
break;
166
default:
167
return -EINVAL;
168
}
169
170
tblcnt = (len - prelen) / sarlen;
171
if (tblcnt > MT792x_ASAR_MAX_GEO || tblcnt < MT792x_ASAR_MIN_GEO)
172
return -EINVAL;
173
174
return 0;
175
}
176
177
/* MTFG : Flag Table */
178
static int
179
mt792x_asar_acpi_read_mtfg(struct mt792x_dev *dev, u8 **table)
180
{
181
int len, ret;
182
183
ret = mt792x_acpi_read(dev, MT792x_ACPI_MTFG, table, &len);
184
if (ret)
185
return ret;
186
187
if (len < MT792x_ASAR_MIN_FG)
188
return -EINVAL;
189
190
return 0;
191
}
192
193
int mt792x_init_acpi_sar(struct mt792x_dev *dev)
194
{
195
struct mt792x_acpi_sar *asar;
196
int ret;
197
198
asar = devm_kzalloc(dev->mt76.dev, sizeof(*asar), GFP_KERNEL);
199
if (!asar)
200
return -ENOMEM;
201
202
ret = mt792x_asar_acpi_read_mtcl(dev, (u8 **)&asar->countrylist, &asar->ver);
203
if (ret) {
204
devm_kfree(dev->mt76.dev, asar->countrylist);
205
asar->countrylist = NULL;
206
}
207
208
ret = mt792x_asar_acpi_read_mtds(dev, (u8 **)&asar->dyn, asar->ver);
209
if (ret) {
210
devm_kfree(dev->mt76.dev, asar->dyn);
211
asar->dyn = NULL;
212
}
213
214
/* MTGS is optional */
215
ret = mt792x_asar_acpi_read_mtgs(dev, (u8 **)&asar->geo, asar->ver);
216
if (ret) {
217
devm_kfree(dev->mt76.dev, asar->geo);
218
asar->geo = NULL;
219
}
220
221
/* MTFG is optional */
222
ret = mt792x_asar_acpi_read_mtfg(dev, (u8 **)&asar->fg);
223
if (ret) {
224
devm_kfree(dev->mt76.dev, asar->fg);
225
asar->fg = NULL;
226
}
227
dev->phy.acpisar = asar;
228
229
return 0;
230
}
231
EXPORT_SYMBOL_GPL(mt792x_init_acpi_sar);
232
233
static s8
234
mt792x_asar_get_geo_pwr(struct mt792x_phy *phy,
235
enum nl80211_band band, s8 dyn_power)
236
{
237
struct mt792x_acpi_sar *asar = phy->acpisar;
238
struct mt792x_asar_geo_band *band_pwr;
239
s8 geo_power;
240
u8 idx, max;
241
242
if (!asar->geo)
243
return dyn_power;
244
245
switch (phy->mt76->dev->region) {
246
case NL80211_DFS_FCC:
247
idx = 0;
248
break;
249
case NL80211_DFS_ETSI:
250
idx = 1;
251
break;
252
default: /* WW */
253
idx = 2;
254
break;
255
}
256
257
if (asar->ver == 1) {
258
band_pwr = &asar->geo->tbl[idx].band[0];
259
max = ARRAY_SIZE(asar->geo->tbl[idx].band);
260
} else {
261
band_pwr = &asar->geo_v2->tbl[idx].band[0];
262
max = ARRAY_SIZE(asar->geo_v2->tbl[idx].band);
263
}
264
265
switch (band) {
266
case NL80211_BAND_2GHZ:
267
idx = 0;
268
break;
269
case NL80211_BAND_5GHZ:
270
idx = 1;
271
break;
272
case NL80211_BAND_6GHZ:
273
idx = 2;
274
break;
275
default:
276
return dyn_power;
277
}
278
279
if (idx >= max)
280
return dyn_power;
281
282
geo_power = (band_pwr + idx)->pwr;
283
dyn_power += (band_pwr + idx)->offset;
284
285
return min(geo_power, dyn_power);
286
}
287
288
static s8
289
mt792x_asar_range_pwr(struct mt792x_phy *phy,
290
const struct cfg80211_sar_freq_ranges *range,
291
u8 idx)
292
{
293
const struct cfg80211_sar_capa *capa = phy->mt76->hw->wiphy->sar_capa;
294
struct mt792x_acpi_sar *asar = phy->acpisar;
295
u8 *limit, band, max;
296
297
if (!capa)
298
return 127;
299
300
if (asar->ver == 1) {
301
limit = &asar->dyn->tbl[0].frp[0];
302
max = ARRAY_SIZE(asar->dyn->tbl[0].frp);
303
} else {
304
limit = &asar->dyn_v2->tbl[0].frp[0];
305
max = ARRAY_SIZE(asar->dyn_v2->tbl[0].frp);
306
}
307
308
if (idx >= max)
309
return 127;
310
311
if (range->start_freq >= 5945)
312
band = NL80211_BAND_6GHZ;
313
else if (range->start_freq >= 5150)
314
band = NL80211_BAND_5GHZ;
315
else
316
band = NL80211_BAND_2GHZ;
317
318
return mt792x_asar_get_geo_pwr(phy, band, limit[idx]);
319
}
320
321
int mt792x_init_acpi_sar_power(struct mt792x_phy *phy, bool set_default)
322
{
323
const struct cfg80211_sar_capa *capa = phy->mt76->hw->wiphy->sar_capa;
324
int i;
325
326
if (!phy->acpisar || !((struct mt792x_acpi_sar *)phy->acpisar)->dyn)
327
return 0;
328
329
/* When ACPI SAR enabled in HW, we should apply rules for .frp
330
* 1. w/o .sar_specs : set ACPI SAR power as the defatul value
331
* 2. w/ .sar_specs : set power with min(.sar_specs, ACPI_SAR)
332
*/
333
for (i = 0; i < capa->num_freq_ranges; i++) {
334
struct mt76_freq_range_power *frp = &phy->mt76->frp[i];
335
336
frp->range = set_default ? &capa->freq_ranges[i] : frp->range;
337
if (!frp->range)
338
continue;
339
340
frp->power = min_t(s8, set_default ? 127 : frp->power,
341
mt792x_asar_range_pwr(phy, frp->range, i));
342
}
343
344
return 0;
345
}
346
EXPORT_SYMBOL_GPL(mt792x_init_acpi_sar_power);
347
348
u8 mt792x_acpi_get_flags(struct mt792x_phy *phy)
349
{
350
struct mt792x_acpi_sar *acpisar = phy->acpisar;
351
struct mt792x_asar_fg *fg;
352
struct {
353
u8 acpi_idx;
354
u8 chip_idx;
355
} map[] = {
356
{ 1, 1 },
357
{ 4, 2 },
358
};
359
u8 flags = BIT(0);
360
int i, j;
361
362
if (!acpisar)
363
return 0;
364
365
fg = acpisar->fg;
366
if (!fg)
367
return flags;
368
369
/* pickup necessary settings per device and
370
* translate the index of bitmap for chip command.
371
*/
372
for (i = 0; i < fg->nr_flag; i++) {
373
for (j = 0; j < ARRAY_SIZE(map); j++) {
374
if (fg->flag[i] == map[j].acpi_idx) {
375
flags |= BIT(map[j].chip_idx);
376
break;
377
}
378
}
379
}
380
381
return flags;
382
}
383
EXPORT_SYMBOL_GPL(mt792x_acpi_get_flags);
384
385
static u32
386
mt792x_acpi_get_mtcl_map_v3(int row, int column, struct mt792x_asar_cl_v3 *cl)
387
{
388
u32 config = 0;
389
u8 mode_be = 0;
390
391
mode_be = (cl->mode_be > 0x02) ? 0 : cl->mode_be;
392
393
if (cl->version > 2 && cl->clbe[row] & BIT(column))
394
config |= (mode_be & 0x3) << 4;
395
396
return config;
397
}
398
399
static u32
400
mt792x_acpi_get_mtcl_map(int row, int column, struct mt792x_asar_cl *cl)
401
{
402
u32 config = 0;
403
u8 mode_6g, mode_5g9;
404
405
mode_6g = (cl->mode_6g > 0x02) ? 0 : cl->mode_6g;
406
mode_5g9 = (cl->mode_5g9 > 0x01) ? 0 : cl->mode_5g9;
407
408
if ((cl->cl6g[row] & BIT(column)) || cl->mode_6g == 0x02)
409
config |= (mode_6g & 0x3) << 2;
410
if (cl->version > 1 && cl->cl5g9[row] & BIT(column))
411
config |= (mode_5g9 & 0x3);
412
413
return config;
414
}
415
416
static u32
417
mt792x_acpi_parse_mtcl_tbl_v3(struct mt792x_phy *phy, char *alpha2)
418
{
419
struct mt792x_acpi_sar *sar = phy->acpisar;
420
struct mt792x_asar_cl_v3 *cl = sar->countrylist_v3;
421
int col, row, i;
422
423
if (sar->ver != 3)
424
goto out;
425
426
if (!cl)
427
return MT792X_ACPI_MTCL_INVALID;
428
429
for (i = 0; i < ARRAY_SIZE(cc_list_be); i++) {
430
col = 7 - i % 8;
431
row = i / 8;
432
if (!memcmp(cc_list_be[i], alpha2, 2))
433
return mt792x_acpi_get_mtcl_map_v3(row, col, cl);
434
}
435
for (i = 0; i < ARRAY_SIZE(cc_list_eu); i++) {
436
if (!memcmp(cc_list_eu[i], alpha2, 2))
437
return mt792x_acpi_get_mtcl_map_v3(3, 7, cl);
438
}
439
440
out:
441
/* Depends on driver */
442
return 0x20;
443
}
444
445
static u32
446
mt792x_acpi_parse_mtcl_tbl(struct mt792x_phy *phy, char *alpha2)
447
{
448
struct mt792x_acpi_sar *sar = phy->acpisar;
449
struct mt792x_asar_cl *cl = sar->countrylist;
450
int col, row, i;
451
452
if (!cl)
453
return MT792X_ACPI_MTCL_INVALID;
454
455
for (i = 0; i < ARRAY_SIZE(cc_list_all); i++) {
456
col = 7 - i % 8;
457
row = i / 8;
458
if (!memcmp(cc_list_all[i], alpha2, 2))
459
return mt792x_acpi_get_mtcl_map(row, col, cl);
460
}
461
462
for (i = 0; i < ARRAY_SIZE(cc_list_eu); i++)
463
if (!memcmp(cc_list_eu[i], alpha2, 2))
464
return mt792x_acpi_get_mtcl_map(0, 6, cl);
465
466
return mt792x_acpi_get_mtcl_map(0, 7, cl);
467
}
468
469
u32 mt792x_acpi_get_mtcl_conf(struct mt792x_phy *phy, char *alpha2)
470
{
471
struct mt792x_acpi_sar *sar = phy->acpisar;
472
u32 config = 0;
473
474
if (!sar)
475
return MT792X_ACPI_MTCL_INVALID;
476
477
config = mt792x_acpi_parse_mtcl_tbl_v3(phy, alpha2);
478
479
if (config == MT792X_ACPI_MTCL_INVALID)
480
return MT792X_ACPI_MTCL_INVALID;
481
482
config |= mt792x_acpi_parse_mtcl_tbl(phy, alpha2);
483
484
return config;
485
}
486
EXPORT_SYMBOL_GPL(mt792x_acpi_get_mtcl_conf);
487
488