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