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 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 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 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 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 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 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 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 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 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 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 354 static u8 355 mt792x_acpi_get_mtcl_map(int row, int column, struct mt792x_asar_cl *cl) 356 { 357 u8 config = 0; 358 u8 mode_6g, mode_5g9; 359 360 mode_6g = (cl->mode_6g > 0x02) ? 0 : cl->mode_6g; 361 mode_5g9 = (cl->mode_5g9 > 0x01) ? 0 : cl->mode_5g9; 362 363 if ((cl->cl6g[row] & BIT(column)) || cl->mode_6g == 0x02) 364 config |= (mode_6g & 0x3) << 2; 365 if (cl->version > 1 && cl->cl5g9[row] & BIT(column)) 366 config |= (mode_5g9 & 0x3); 367 368 return config; 369 } 370 371 u8 mt792x_acpi_get_mtcl_conf(struct mt792x_phy *phy, char *alpha2) 372 { 373 static const char * const cc_list_all[] = { 374 "00", "EU", "AR", "AU", "AZ", "BY", "BO", "BR", 375 "CA", "CL", "CN", "ID", "JP", "MY", "MX", "ME", 376 "MA", "NZ", "NG", "PH", "RU", "RS", "SG", "KR", 377 "TW", "TH", "UA", "GB", "US", "VN", "KH", "PY", 378 }; 379 static const char * const cc_list_eu[] = { 380 "AT", "BE", "BG", "CY", "CZ", "HR", "DK", "EE", 381 "FI", "FR", "DE", "GR", "HU", "IS", "IE", "IT", 382 "LV", "LI", "LT", "LU", "MT", "NL", "NO", "PL", 383 "PT", "RO", "SK", "SI", "ES", "SE", "CH", 384 }; 385 struct mt792x_acpi_sar *sar = phy->acpisar; 386 struct mt792x_asar_cl *cl; 387 int col, row, i; 388 389 if (!sar) 390 return 0xf; 391 392 cl = sar->countrylist; 393 if (!cl) 394 return 0xc; 395 396 for (i = 0; i < ARRAY_SIZE(cc_list_all); i++) { 397 col = 7 - i % 8; 398 row = i / 8; 399 if (!memcmp(cc_list_all[i], alpha2, 2)) 400 return mt792x_acpi_get_mtcl_map(row, col, cl); 401 } 402 403 for (i = 0; i < ARRAY_SIZE(cc_list_eu); i++) 404 if (!memcmp(cc_list_eu[i], alpha2, 2)) 405 return mt792x_acpi_get_mtcl_map(0, 6, cl); 406 407 return mt792x_acpi_get_mtcl_map(0, 7, cl); 408 } 409 EXPORT_SYMBOL_GPL(mt792x_acpi_get_mtcl_conf); 410