1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2 /* Copyright(c) 2019-2020 Realtek Corporation 3 */ 4 5 #include "acpi.h" 6 #include "debug.h" 7 #include "phy.h" 8 #include "reg.h" 9 #include "sar.h" 10 #include "util.h" 11 12 #define RTW89_TAS_FACTOR 2 /* unit: 0.25 dBm */ 13 #define RTW89_TAS_SAR_GAP (1 << RTW89_TAS_FACTOR) 14 #define RTW89_TAS_DPR_GAP (1 << RTW89_TAS_FACTOR) 15 #define RTW89_TAS_DELTA (2 << RTW89_TAS_FACTOR) 16 #define RTW89_TAS_TX_RATIO_THRESHOLD 70 17 #define RTW89_TAS_DFLT_TX_RATIO 80 18 #define RTW89_TAS_DPR_ON_OFFSET (RTW89_TAS_DELTA + RTW89_TAS_SAR_GAP) 19 #define RTW89_TAS_DPR_OFF_OFFSET (4 << RTW89_TAS_FACTOR) 20 21 static enum rtw89_sar_subband rtw89_sar_get_subband(struct rtw89_dev *rtwdev, 22 u32 center_freq) 23 { 24 switch (center_freq) { 25 default: 26 rtw89_debug(rtwdev, RTW89_DBG_SAR, 27 "center freq: %u to SAR subband is unhandled\n", 28 center_freq); 29 fallthrough; 30 case 2412 ... 2484: 31 return RTW89_SAR_2GHZ_SUBBAND; 32 case 5180 ... 5320: 33 return RTW89_SAR_5GHZ_SUBBAND_1_2; 34 case 5500 ... 5720: 35 return RTW89_SAR_5GHZ_SUBBAND_2_E; 36 case 5745 ... 5885: 37 return RTW89_SAR_5GHZ_SUBBAND_3_4; 38 case 5955 ... 6155: 39 return RTW89_SAR_6GHZ_SUBBAND_5_L; 40 case 6175 ... 6415: 41 return RTW89_SAR_6GHZ_SUBBAND_5_H; 42 case 6435 ... 6515: 43 return RTW89_SAR_6GHZ_SUBBAND_6; 44 case 6535 ... 6695: 45 return RTW89_SAR_6GHZ_SUBBAND_7_L; 46 case 6715 ... 6855: 47 return RTW89_SAR_6GHZ_SUBBAND_7_H; 48 49 /* freq 6875 (ch 185, 20MHz) spans RTW89_SAR_6GHZ_SUBBAND_7_H 50 * and RTW89_SAR_6GHZ_SUBBAND_8, so directly describe it with 51 * struct rtw89_6ghz_span. 52 */ 53 54 case 6895 ... 7115: 55 return RTW89_SAR_6GHZ_SUBBAND_8; 56 } 57 } 58 59 static int rtw89_query_sar_config_common(struct rtw89_dev *rtwdev, 60 u32 center_freq, s32 *cfg) 61 { 62 struct rtw89_sar_cfg_common *rtwsar = &rtwdev->sar.cfg_common; 63 enum rtw89_sar_subband subband_l, subband_h; 64 const struct rtw89_6ghz_span *span; 65 66 span = rtw89_get_6ghz_span(rtwdev, center_freq); 67 68 if (span && RTW89_SAR_SPAN_VALID(span)) { 69 subband_l = span->sar_subband_low; 70 subband_h = span->sar_subband_high; 71 } else { 72 subband_l = rtw89_sar_get_subband(rtwdev, center_freq); 73 subband_h = subband_l; 74 } 75 76 rtw89_debug(rtwdev, RTW89_DBG_SAR, 77 "center_freq %u: SAR subband {%u, %u}\n", 78 center_freq, subband_l, subband_h); 79 80 if (!rtwsar->set[subband_l] && !rtwsar->set[subband_h]) 81 return -ENODATA; 82 83 if (!rtwsar->set[subband_l]) 84 *cfg = rtwsar->cfg[subband_h]; 85 else if (!rtwsar->set[subband_h]) 86 *cfg = rtwsar->cfg[subband_l]; 87 else 88 *cfg = min(rtwsar->cfg[subband_l], rtwsar->cfg[subband_h]); 89 90 return 0; 91 } 92 93 static const 94 struct rtw89_sar_handler rtw89_sar_handlers[RTW89_SAR_SOURCE_NR] = { 95 [RTW89_SAR_SOURCE_COMMON] = { 96 .descr_sar_source = "RTW89_SAR_SOURCE_COMMON", 97 .txpwr_factor_sar = 2, 98 .query_sar_config = rtw89_query_sar_config_common, 99 }, 100 }; 101 102 #define rtw89_sar_set_src(_dev, _src, _cfg_name, _cfg_data) \ 103 do { \ 104 typeof(_src) _s = (_src); \ 105 typeof(_dev) _d = (_dev); \ 106 BUILD_BUG_ON(!rtw89_sar_handlers[_s].descr_sar_source); \ 107 BUILD_BUG_ON(!rtw89_sar_handlers[_s].query_sar_config); \ 108 lockdep_assert_wiphy(_d->hw->wiphy); \ 109 _d->sar._cfg_name = *(_cfg_data); \ 110 _d->sar.src = _s; \ 111 } while (0) 112 113 static s8 rtw89_txpwr_sar_to_mac(struct rtw89_dev *rtwdev, u8 fct, s32 cfg) 114 { 115 const u8 fct_mac = rtwdev->chip->txpwr_factor_mac; 116 s32 cfg_mac; 117 118 cfg_mac = fct > fct_mac ? 119 cfg >> (fct - fct_mac) : cfg << (fct_mac - fct); 120 121 return (s8)clamp_t(s32, cfg_mac, 122 RTW89_SAR_TXPWR_MAC_MIN, 123 RTW89_SAR_TXPWR_MAC_MAX); 124 } 125 126 static s32 rtw89_txpwr_tas_to_sar(const struct rtw89_sar_handler *sar_hdl, 127 s32 cfg) 128 { 129 const u8 fct = sar_hdl->txpwr_factor_sar; 130 131 if (fct > RTW89_TAS_FACTOR) 132 return cfg << (fct - RTW89_TAS_FACTOR); 133 else 134 return cfg >> (RTW89_TAS_FACTOR - fct); 135 } 136 137 static s32 rtw89_txpwr_sar_to_tas(const struct rtw89_sar_handler *sar_hdl, 138 s32 cfg) 139 { 140 const u8 fct = sar_hdl->txpwr_factor_sar; 141 142 if (fct > RTW89_TAS_FACTOR) 143 return cfg >> (fct - RTW89_TAS_FACTOR); 144 else 145 return cfg << (RTW89_TAS_FACTOR - fct); 146 } 147 148 static bool rtw89_tas_is_active(struct rtw89_dev *rtwdev) 149 { 150 struct rtw89_tas_info *tas = &rtwdev->tas; 151 struct rtw89_vif *rtwvif; 152 153 if (!tas->enable) 154 return false; 155 156 rtw89_for_each_rtwvif(rtwdev, rtwvif) { 157 if (ieee80211_vif_is_mld(rtwvif_to_vif(rtwvif))) 158 return false; 159 } 160 161 return true; 162 } 163 164 static const char *rtw89_tas_state_str(enum rtw89_tas_state state) 165 { 166 switch (state) { 167 case RTW89_TAS_STATE_DPR_OFF: 168 return "DPR OFF"; 169 case RTW89_TAS_STATE_DPR_ON: 170 return "DPR ON"; 171 case RTW89_TAS_STATE_STATIC_SAR: 172 return "STATIC SAR"; 173 default: 174 return NULL; 175 } 176 } 177 178 s8 rtw89_query_sar(struct rtw89_dev *rtwdev, u32 center_freq) 179 { 180 const enum rtw89_sar_sources src = rtwdev->sar.src; 181 /* its members are protected by rtw89_sar_set_src() */ 182 const struct rtw89_sar_handler *sar_hdl = &rtw89_sar_handlers[src]; 183 struct rtw89_tas_info *tas = &rtwdev->tas; 184 s32 offset; 185 int ret; 186 s32 cfg; 187 u8 fct; 188 189 lockdep_assert_wiphy(rtwdev->hw->wiphy); 190 191 if (src == RTW89_SAR_SOURCE_NONE) 192 return RTW89_SAR_TXPWR_MAC_MAX; 193 194 ret = sar_hdl->query_sar_config(rtwdev, center_freq, &cfg); 195 if (ret) 196 return RTW89_SAR_TXPWR_MAC_MAX; 197 198 if (rtw89_tas_is_active(rtwdev)) { 199 switch (tas->state) { 200 case RTW89_TAS_STATE_DPR_OFF: 201 offset = rtw89_txpwr_tas_to_sar(sar_hdl, RTW89_TAS_DPR_OFF_OFFSET); 202 cfg += offset; 203 break; 204 case RTW89_TAS_STATE_DPR_ON: 205 offset = rtw89_txpwr_tas_to_sar(sar_hdl, RTW89_TAS_DPR_ON_OFFSET); 206 cfg -= offset; 207 break; 208 case RTW89_TAS_STATE_STATIC_SAR: 209 default: 210 break; 211 } 212 } 213 214 fct = sar_hdl->txpwr_factor_sar; 215 216 return rtw89_txpwr_sar_to_mac(rtwdev, fct, cfg); 217 } 218 219 int rtw89_print_sar(struct rtw89_dev *rtwdev, char *buf, size_t bufsz, 220 u32 center_freq) 221 { 222 const enum rtw89_sar_sources src = rtwdev->sar.src; 223 /* its members are protected by rtw89_sar_set_src() */ 224 const struct rtw89_sar_handler *sar_hdl = &rtw89_sar_handlers[src]; 225 const u8 fct_mac = rtwdev->chip->txpwr_factor_mac; 226 char *p = buf, *end = buf + bufsz; 227 int ret; 228 s32 cfg; 229 u8 fct; 230 231 lockdep_assert_wiphy(rtwdev->hw->wiphy); 232 233 if (src == RTW89_SAR_SOURCE_NONE) { 234 p += scnprintf(p, end - p, "no SAR is applied\n"); 235 goto out; 236 } 237 238 p += scnprintf(p, end - p, "source: %d (%s)\n", src, 239 sar_hdl->descr_sar_source); 240 241 ret = sar_hdl->query_sar_config(rtwdev, center_freq, &cfg); 242 if (ret) { 243 p += scnprintf(p, end - p, "config: return code: %d\n", ret); 244 p += scnprintf(p, end - p, 245 "assign: max setting: %d (unit: 1/%lu dBm)\n", 246 RTW89_SAR_TXPWR_MAC_MAX, BIT(fct_mac)); 247 goto out; 248 } 249 250 fct = sar_hdl->txpwr_factor_sar; 251 252 p += scnprintf(p, end - p, "config: %d (unit: 1/%lu dBm)\n", cfg, 253 BIT(fct)); 254 255 out: 256 return p - buf; 257 } 258 259 int rtw89_print_tas(struct rtw89_dev *rtwdev, char *buf, size_t bufsz) 260 { 261 struct rtw89_tas_info *tas = &rtwdev->tas; 262 char *p = buf, *end = buf + bufsz; 263 264 if (!rtw89_tas_is_active(rtwdev)) { 265 p += scnprintf(p, end - p, "no TAS is applied\n"); 266 goto out; 267 } 268 269 p += scnprintf(p, end - p, "State: %s\n", 270 rtw89_tas_state_str(tas->state)); 271 p += scnprintf(p, end - p, "Average time: %d\n", 272 tas->window_size * 2); 273 p += scnprintf(p, end - p, "SAR gap: %d dBm\n", 274 RTW89_TAS_SAR_GAP >> RTW89_TAS_FACTOR); 275 p += scnprintf(p, end - p, "DPR gap: %d dBm\n", 276 RTW89_TAS_DPR_GAP >> RTW89_TAS_FACTOR); 277 p += scnprintf(p, end - p, "DPR ON offset: %d dBm\n", 278 RTW89_TAS_DPR_ON_OFFSET >> RTW89_TAS_FACTOR); 279 p += scnprintf(p, end - p, "DPR OFF offset: %d dBm\n", 280 RTW89_TAS_DPR_OFF_OFFSET >> RTW89_TAS_FACTOR); 281 282 out: 283 return p - buf; 284 } 285 286 static int rtw89_apply_sar_common(struct rtw89_dev *rtwdev, 287 const struct rtw89_sar_cfg_common *sar) 288 { 289 enum rtw89_sar_sources src; 290 291 lockdep_assert_wiphy(rtwdev->hw->wiphy); 292 293 src = rtwdev->sar.src; 294 if (src != RTW89_SAR_SOURCE_NONE && src != RTW89_SAR_SOURCE_COMMON) { 295 rtw89_warn(rtwdev, "SAR source: %d is in use", src); 296 return -EBUSY; 297 } 298 299 rtw89_sar_set_src(rtwdev, RTW89_SAR_SOURCE_COMMON, cfg_common, sar); 300 rtw89_core_set_chip_txpwr(rtwdev); 301 rtw89_tas_reset(rtwdev, false); 302 303 return 0; 304 } 305 306 static const struct cfg80211_sar_freq_ranges rtw89_common_sar_freq_ranges[] = { 307 { .start_freq = 2412, .end_freq = 2484, }, 308 { .start_freq = 5180, .end_freq = 5320, }, 309 { .start_freq = 5500, .end_freq = 5720, }, 310 { .start_freq = 5745, .end_freq = 5885, }, 311 { .start_freq = 5955, .end_freq = 6155, }, 312 { .start_freq = 6175, .end_freq = 6415, }, 313 { .start_freq = 6435, .end_freq = 6515, }, 314 { .start_freq = 6535, .end_freq = 6695, }, 315 { .start_freq = 6715, .end_freq = 6875, }, 316 { .start_freq = 6875, .end_freq = 7115, }, 317 }; 318 319 static_assert(RTW89_SAR_SUBBAND_NR == 320 ARRAY_SIZE(rtw89_common_sar_freq_ranges)); 321 322 const struct cfg80211_sar_capa rtw89_sar_capa = { 323 .type = NL80211_SAR_TYPE_POWER, 324 .num_freq_ranges = ARRAY_SIZE(rtw89_common_sar_freq_ranges), 325 .freq_ranges = rtw89_common_sar_freq_ranges, 326 }; 327 328 int rtw89_ops_set_sar_specs(struct ieee80211_hw *hw, 329 const struct cfg80211_sar_specs *sar) 330 { 331 struct rtw89_dev *rtwdev = hw->priv; 332 struct rtw89_sar_cfg_common sar_common = {0}; 333 u8 fct; 334 u32 freq_start; 335 u32 freq_end; 336 s32 power; 337 u32 i, idx; 338 339 lockdep_assert_wiphy(rtwdev->hw->wiphy); 340 341 if (sar->type != NL80211_SAR_TYPE_POWER) 342 return -EINVAL; 343 344 fct = rtw89_sar_handlers[RTW89_SAR_SOURCE_COMMON].txpwr_factor_sar; 345 346 for (i = 0; i < sar->num_sub_specs; i++) { 347 idx = sar->sub_specs[i].freq_range_index; 348 if (idx >= ARRAY_SIZE(rtw89_common_sar_freq_ranges)) 349 return -EINVAL; 350 351 freq_start = rtw89_common_sar_freq_ranges[idx].start_freq; 352 freq_end = rtw89_common_sar_freq_ranges[idx].end_freq; 353 power = sar->sub_specs[i].power; 354 355 rtw89_debug(rtwdev, RTW89_DBG_SAR, 356 "On freq %u to %u, set SAR limit %d (unit: 1/%lu dBm)\n", 357 freq_start, freq_end, power, BIT(fct)); 358 359 sar_common.set[idx] = true; 360 sar_common.cfg[idx] = power; 361 } 362 363 return rtw89_apply_sar_common(rtwdev, &sar_common); 364 } 365 366 static bool rtw89_tas_query_sar_config(struct rtw89_dev *rtwdev, s32 *cfg) 367 { 368 const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_CHANCTX_0); 369 const enum rtw89_sar_sources src = rtwdev->sar.src; 370 /* its members are protected by rtw89_sar_set_src() */ 371 const struct rtw89_sar_handler *sar_hdl = &rtw89_sar_handlers[src]; 372 int ret; 373 374 if (src == RTW89_SAR_SOURCE_NONE) 375 return false; 376 377 ret = sar_hdl->query_sar_config(rtwdev, chan->freq, cfg); 378 if (ret) 379 return false; 380 381 *cfg = rtw89_txpwr_sar_to_tas(sar_hdl, *cfg); 382 383 return true; 384 } 385 386 static void rtw89_tas_state_update(struct rtw89_dev *rtwdev, 387 enum rtw89_tas_state state) 388 { 389 struct rtw89_tas_info *tas = &rtwdev->tas; 390 391 if (tas->state == state) 392 return; 393 394 rtw89_debug(rtwdev, RTW89_DBG_SAR, "tas: switch state: %s -> %s\n", 395 rtw89_tas_state_str(tas->state), rtw89_tas_state_str(state)); 396 397 tas->state = state; 398 rtw89_core_set_chip_txpwr(rtwdev); 399 } 400 401 static u32 rtw89_tas_get_window_size(struct rtw89_dev *rtwdev) 402 { 403 const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_CHANCTX_0); 404 u8 band = chan->band_type; 405 u8 regd = rtw89_regd_get(rtwdev, band); 406 407 switch (regd) { 408 default: 409 rtw89_debug(rtwdev, RTW89_DBG_SAR, 410 "tas: regd: %u is unhandled\n", regd); 411 fallthrough; 412 case RTW89_IC: 413 case RTW89_KCC: 414 return 180; 415 case RTW89_FCC: 416 switch (band) { 417 case RTW89_BAND_2G: 418 return 50; 419 case RTW89_BAND_5G: 420 return 30; 421 case RTW89_BAND_6G: 422 default: 423 return 15; 424 } 425 break; 426 } 427 } 428 429 static void rtw89_tas_window_update(struct rtw89_dev *rtwdev) 430 { 431 u32 window_size = rtw89_tas_get_window_size(rtwdev); 432 struct rtw89_tas_info *tas = &rtwdev->tas; 433 u64 total_txpwr = 0; 434 u8 head_idx; 435 u32 i, j; 436 437 WARN_ON_ONCE(tas->window_size > RTW89_TAS_TXPWR_WINDOW); 438 439 if (tas->window_size == window_size) 440 return; 441 442 rtw89_debug(rtwdev, RTW89_DBG_SAR, "tas: window update: %u -> %u\n", 443 tas->window_size, window_size); 444 445 head_idx = (tas->txpwr_tail_idx - window_size + 1 + RTW89_TAS_TXPWR_WINDOW) % 446 RTW89_TAS_TXPWR_WINDOW; 447 for (i = 0; i < window_size; i++) { 448 j = (head_idx + i) % RTW89_TAS_TXPWR_WINDOW; 449 total_txpwr += tas->txpwr_history[j]; 450 } 451 452 tas->window_size = window_size; 453 tas->total_txpwr = total_txpwr; 454 tas->txpwr_head_idx = head_idx; 455 } 456 457 static void rtw89_tas_history_update(struct rtw89_dev *rtwdev) 458 { 459 struct rtw89_bb_ctx *bb = rtw89_get_bb_ctx(rtwdev, RTW89_PHY_0); 460 struct rtw89_env_monitor_info *env = &bb->env_monitor; 461 struct rtw89_tas_info *tas = &rtwdev->tas; 462 u8 tx_ratio = env->ifs_clm_tx_ratio; 463 u64 instant_txpwr, txpwr; 464 465 /* txpwr in unit of linear(mW) multiply by percentage */ 466 if (tx_ratio == 0) { 467 /* special case: idle tx power 468 * use -40 dBm * 100 tx ratio 469 */ 470 instant_txpwr = rtw89_db_to_linear(-40); 471 txpwr = instant_txpwr * 100; 472 } else { 473 instant_txpwr = tas->instant_txpwr; 474 txpwr = instant_txpwr * tx_ratio; 475 } 476 477 tas->total_txpwr += txpwr - tas->txpwr_history[tas->txpwr_head_idx]; 478 tas->total_tx_ratio += tx_ratio - tas->tx_ratio_history[tas->tx_ratio_idx]; 479 tas->tx_ratio_history[tas->tx_ratio_idx] = tx_ratio; 480 481 tas->txpwr_head_idx = (tas->txpwr_head_idx + 1) % RTW89_TAS_TXPWR_WINDOW; 482 tas->txpwr_tail_idx = (tas->txpwr_tail_idx + 1) % RTW89_TAS_TXPWR_WINDOW; 483 tas->tx_ratio_idx = (tas->tx_ratio_idx + 1) % RTW89_TAS_TX_RATIO_WINDOW; 484 tas->txpwr_history[tas->txpwr_tail_idx] = txpwr; 485 486 rtw89_debug(rtwdev, RTW89_DBG_SAR, 487 "tas: instant_txpwr: %d, tx_ratio: %u, txpwr: %d\n", 488 rtw89_linear_to_db_quarter(instant_txpwr), tx_ratio, 489 rtw89_linear_to_db_quarter(div_u64(txpwr, PERCENT))); 490 } 491 492 static void rtw89_tas_rolling_average(struct rtw89_dev *rtwdev) 493 { 494 struct rtw89_tas_info *tas = &rtwdev->tas; 495 s32 dpr_on_threshold, dpr_off_threshold; 496 enum rtw89_tas_state state; 497 u16 tx_ratio_avg; 498 s32 txpwr_avg; 499 u64 linear; 500 501 linear = DIV_ROUND_DOWN_ULL(tas->total_txpwr, tas->window_size * PERCENT); 502 txpwr_avg = rtw89_linear_to_db_quarter(linear); 503 tx_ratio_avg = tas->total_tx_ratio / RTW89_TAS_TX_RATIO_WINDOW; 504 dpr_on_threshold = tas->dpr_on_threshold; 505 dpr_off_threshold = tas->dpr_off_threshold; 506 507 rtw89_debug(rtwdev, RTW89_DBG_SAR, 508 "tas: DPR_ON: %d, DPR_OFF: %d, txpwr_avg: %d, tx_ratio_avg: %u\n", 509 dpr_on_threshold, dpr_off_threshold, txpwr_avg, tx_ratio_avg); 510 511 if (tx_ratio_avg >= RTW89_TAS_TX_RATIO_THRESHOLD) 512 state = RTW89_TAS_STATE_STATIC_SAR; 513 else if (txpwr_avg >= dpr_on_threshold) 514 state = RTW89_TAS_STATE_DPR_ON; 515 else if (txpwr_avg < dpr_off_threshold) 516 state = RTW89_TAS_STATE_DPR_OFF; 517 else 518 return; 519 520 rtw89_tas_state_update(rtwdev, state); 521 } 522 523 void rtw89_tas_init(struct rtw89_dev *rtwdev) 524 { 525 const struct rtw89_chip_info *chip = rtwdev->chip; 526 struct rtw89_tas_info *tas = &rtwdev->tas; 527 struct rtw89_acpi_dsm_result res = {}; 528 int ret; 529 u8 val; 530 531 if (!chip->support_tas) 532 return; 533 534 ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_TAS_EN, &res); 535 if (ret) { 536 rtw89_debug(rtwdev, RTW89_DBG_SAR, 537 "acpi: cannot get TAS: %d\n", ret); 538 return; 539 } 540 541 val = res.u.value; 542 switch (val) { 543 case 0: 544 tas->enable = false; 545 break; 546 case 1: 547 tas->enable = true; 548 break; 549 default: 550 break; 551 } 552 553 if (!tas->enable) { 554 rtw89_debug(rtwdev, RTW89_DBG_SAR, "TAS not enable\n"); 555 return; 556 } 557 } 558 559 void rtw89_tas_reset(struct rtw89_dev *rtwdev, bool force) 560 { 561 const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_CHANCTX_0); 562 struct rtw89_tas_info *tas = &rtwdev->tas; 563 u64 linear; 564 s32 cfg; 565 int i; 566 567 if (!rtw89_tas_is_active(rtwdev)) 568 return; 569 570 if (!rtw89_tas_query_sar_config(rtwdev, &cfg)) 571 return; 572 573 tas->dpr_on_threshold = cfg - RTW89_TAS_SAR_GAP; 574 tas->dpr_off_threshold = cfg - RTW89_TAS_SAR_GAP - RTW89_TAS_DPR_GAP; 575 576 /* avoid history reset after new SAR apply */ 577 if (!force && tas->keep_history) 578 return; 579 580 linear = rtw89_db_quarter_to_linear(cfg) * RTW89_TAS_DFLT_TX_RATIO; 581 for (i = 0; i < RTW89_TAS_TXPWR_WINDOW; i++) 582 tas->txpwr_history[i] = linear; 583 584 for (i = 0; i < RTW89_TAS_TX_RATIO_WINDOW; i++) 585 tas->tx_ratio_history[i] = RTW89_TAS_DFLT_TX_RATIO; 586 587 tas->total_tx_ratio = RTW89_TAS_DFLT_TX_RATIO * RTW89_TAS_TX_RATIO_WINDOW; 588 tas->total_txpwr = linear * RTW89_TAS_TXPWR_WINDOW; 589 tas->window_size = RTW89_TAS_TXPWR_WINDOW; 590 tas->txpwr_head_idx = 0; 591 tas->txpwr_tail_idx = RTW89_TAS_TXPWR_WINDOW - 1; 592 tas->tx_ratio_idx = 0; 593 tas->state = RTW89_TAS_STATE_DPR_OFF; 594 tas->backup_state = RTW89_TAS_STATE_DPR_OFF; 595 tas->keep_history = true; 596 597 rtw89_debug(rtwdev, RTW89_DBG_SAR, 598 "tas: band: %u, freq: %u\n", chan->band_type, chan->freq); 599 } 600 601 void rtw89_tas_track(struct rtw89_dev *rtwdev) 602 { 603 struct rtw89_tas_info *tas = &rtwdev->tas; 604 struct rtw89_hal *hal = &rtwdev->hal; 605 s32 cfg; 606 607 if (hal->disabled_dm_bitmap & BIT(RTW89_DM_TAS)) 608 return; 609 610 if (!rtw89_tas_is_active(rtwdev)) 611 return; 612 613 if (!rtw89_tas_query_sar_config(rtwdev, &cfg) || tas->block_regd) { 614 rtw89_tas_state_update(rtwdev, RTW89_TAS_STATE_STATIC_SAR); 615 return; 616 } 617 618 if (tas->pause) 619 return; 620 621 rtw89_tas_window_update(rtwdev); 622 rtw89_tas_history_update(rtwdev); 623 rtw89_tas_rolling_average(rtwdev); 624 } 625 626 void rtw89_tas_scan(struct rtw89_dev *rtwdev, bool start) 627 { 628 struct rtw89_tas_info *tas = &rtwdev->tas; 629 s32 cfg; 630 631 if (!rtw89_tas_is_active(rtwdev)) 632 return; 633 634 if (!rtw89_tas_query_sar_config(rtwdev, &cfg)) 635 return; 636 637 if (start) { 638 tas->backup_state = tas->state; 639 rtw89_tas_state_update(rtwdev, RTW89_TAS_STATE_STATIC_SAR); 640 } else { 641 rtw89_tas_state_update(rtwdev, tas->backup_state); 642 } 643 } 644 645 void rtw89_tas_chanctx_cb(struct rtw89_dev *rtwdev, 646 enum rtw89_chanctx_state state) 647 { 648 struct rtw89_tas_info *tas = &rtwdev->tas; 649 s32 cfg; 650 651 if (!rtw89_tas_is_active(rtwdev)) 652 return; 653 654 if (!rtw89_tas_query_sar_config(rtwdev, &cfg)) 655 return; 656 657 switch (state) { 658 case RTW89_CHANCTX_STATE_MCC_START: 659 tas->pause = true; 660 rtw89_tas_state_update(rtwdev, RTW89_TAS_STATE_STATIC_SAR); 661 break; 662 case RTW89_CHANCTX_STATE_MCC_STOP: 663 tas->pause = false; 664 break; 665 default: 666 break; 667 } 668 } 669 EXPORT_SYMBOL(rtw89_tas_chanctx_cb); 670