1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2 /* Copyright(c) 2018-2021 Realtek Corporation 3 */ 4 5 #include "sar.h" 6 #include "phy.h" 7 #include "debug.h" 8 9 s8 rtw_query_sar(struct rtw_dev *rtwdev, const struct rtw_sar_arg *arg) 10 { 11 const struct rtw_hal *hal = &rtwdev->hal; 12 const struct rtw_sar *sar = &hal->sar; 13 14 switch (sar->src) { 15 default: 16 rtw_warn(rtwdev, "unknown SAR source: %d\n", sar->src); 17 fallthrough; 18 case RTW_SAR_SOURCE_NONE: 19 return (s8)rtwdev->chip->max_power_index; 20 case RTW_SAR_SOURCE_COMMON: 21 return sar->cfg[arg->path][arg->rs].common[arg->sar_band]; 22 } 23 } 24 25 static int rtw_apply_sar(struct rtw_dev *rtwdev, const struct rtw_sar *new) 26 { 27 struct rtw_hal *hal = &rtwdev->hal; 28 struct rtw_sar *sar = &hal->sar; 29 30 if (sar->src != RTW_SAR_SOURCE_NONE && new->src != sar->src) { 31 rtw_warn(rtwdev, "SAR source: %d is in use\n", sar->src); 32 return -EBUSY; 33 } 34 35 *sar = *new; 36 rtw_phy_set_tx_power_level(rtwdev, hal->current_channel); 37 38 return 0; 39 } 40 41 static s8 rtw_sar_to_phy(struct rtw_dev *rtwdev, u8 fct, s32 sar, 42 const struct rtw_sar_arg *arg) 43 { 44 struct rtw_hal *hal = &rtwdev->hal; 45 u8 txgi = rtwdev->chip->txgi_factor; 46 u8 max = rtwdev->chip->max_power_index; 47 s32 tmp; 48 s8 base; 49 50 tmp = fct > txgi ? sar >> (fct - txgi) : sar << (txgi - fct); 51 base = arg->sar_band == RTW_SAR_BAND_0 ? 52 hal->tx_pwr_by_rate_base_2g[arg->path][arg->rs] : 53 hal->tx_pwr_by_rate_base_5g[arg->path][arg->rs]; 54 55 return (s8)clamp_t(s32, tmp, -max - 1, max) - base; 56 } 57 58 static const struct cfg80211_sar_freq_ranges rtw_common_sar_freq_ranges[] = { 59 [RTW_SAR_BAND_0] = { .start_freq = 2412, .end_freq = 2484, }, 60 [RTW_SAR_BAND_1] = { .start_freq = 5180, .end_freq = 5320, }, 61 [RTW_SAR_BAND_3] = { .start_freq = 5500, .end_freq = 5720, }, 62 [RTW_SAR_BAND_4] = { .start_freq = 5745, .end_freq = 5825, }, 63 }; 64 65 rtw88_static_assert(ARRAY_SIZE(rtw_common_sar_freq_ranges) == RTW_SAR_BAND_NR); 66 67 const struct cfg80211_sar_capa rtw_sar_capa = { 68 .type = NL80211_SAR_TYPE_POWER, 69 .num_freq_ranges = RTW_SAR_BAND_NR, 70 .freq_ranges = rtw_common_sar_freq_ranges, 71 }; 72 73 int rtw_set_sar_specs(struct rtw_dev *rtwdev, 74 const struct cfg80211_sar_specs *sar) 75 { 76 struct rtw_sar_arg arg = {0}; 77 struct rtw_sar new = {0}; 78 u32 idx, i, j, k; 79 s32 power; 80 s8 val; 81 82 if (sar->type != NL80211_SAR_TYPE_POWER) 83 return -EINVAL; 84 85 memset(&new, rtwdev->chip->max_power_index, sizeof(new)); 86 new.src = RTW_SAR_SOURCE_COMMON; 87 88 for (i = 0; i < sar->num_sub_specs; i++) { 89 idx = sar->sub_specs[i].freq_range_index; 90 if (idx >= RTW_SAR_BAND_NR) 91 return -EINVAL; 92 93 power = sar->sub_specs[i].power; 94 rtw_dbg(rtwdev, RTW_DBG_REGD, "On freq %u to %u, set SAR %d in 1/%lu dBm\n", 95 rtw_common_sar_freq_ranges[idx].start_freq, 96 rtw_common_sar_freq_ranges[idx].end_freq, 97 power, BIT(RTW_COMMON_SAR_FCT)); 98 99 for (j = 0; j < RTW_RF_PATH_MAX; j++) { 100 for (k = 0; k < RTW_RATE_SECTION_MAX; k++) { 101 arg = (struct rtw_sar_arg){ 102 .sar_band = idx, 103 .path = j, 104 .rs = k, 105 }; 106 val = rtw_sar_to_phy(rtwdev, RTW_COMMON_SAR_FCT, 107 power, &arg); 108 new.cfg[j][k].common[idx] = val; 109 } 110 } 111 } 112 113 return rtw_apply_sar(rtwdev, &new); 114 } 115