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