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