blob: 47e034a9b0037a35641fb1b4d2a20c400c873a88 [file] [log] [blame]
developer0f312e82022-11-01 12:31:52 +08001// SPDX-License-Identifier: ISC
2/* Copyright (C) 2022 MediaTek Inc. */
3
4#include <linux/acpi.h>
5#include "mt7921.h"
6
7static int
8mt7921_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 }
55free:
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 */
64static int
65mt7921_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 */
73static int
74mt7921_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 */
108static int
109mt7921_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
138int 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
170static s8
171mt7921_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
225static s8
226mt7921_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
258int 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}