rtw88: support SAR via kernel common API
Register cfg80211_sar_capa with type NL80211_SAR_TYPE_POWER and four
frequency ranges for configurations in unit of 0.25 dBm. And handle
callback set_sar_specs.
Originally, TX power has three main parameters, i.e. power base,
power by rate, and power limit. The formula can be simply considered
as TX power = power base + min(power by rate, power limit). With the
support of SAR which can be treated as another power limit, there is
one more parameter for TX power. And the formula will evolve into
TX power = power base + min(power by rate, power limit, power sar).
Besides, debugfs tx_pwr_tbl is also refined to show SAR information.
The following is an example for the difference.
Before supporting SAR,
-----------------------------------
...
path rate pwr base (byr lmt ) rem
A CCK_1M 66(0x42) 78 -12 ( 12 -12) 0
A CCK_2M 66(0x42) 78 -12 ( 8 -12) 0
...
-----------------------------------
After supporting SAR and making some configurations,
-----------------------------------
...
path rate pwr base (byr lmt sar ) rem
A CCK_1M 62(0x3e) 78 -16 ( 12 -12 -16) 0
A CCK_2M 62(0x3e) 78 -16 ( 8 -12 -16) 0
...
-----------------------------------
Signed-off-by: Zong-Zhe Yang <kevin_yang@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
Signed-off-by: Kalle Valo <kvalo@kernel.org>
Link: https://lore.kernel.org/r/20211220093656.65312-1-pkshih@realtek.com
2021-12-20 17:36:56 +08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
|
|
|
/* Copyright(c) 2018-2021 Realtek Corporation
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "sar.h"
|
|
|
|
#include "phy.h"
|
|
|
|
#include "debug.h"
|
|
|
|
|
|
|
|
s8 rtw_query_sar(struct rtw_dev *rtwdev, const struct rtw_sar_arg *arg)
|
|
|
|
{
|
|
|
|
const struct rtw_hal *hal = &rtwdev->hal;
|
|
|
|
const struct rtw_sar *sar = &hal->sar;
|
|
|
|
|
|
|
|
switch (sar->src) {
|
|
|
|
default:
|
|
|
|
rtw_warn(rtwdev, "unknown SAR source: %d\n", sar->src);
|
|
|
|
fallthrough;
|
|
|
|
case RTW_SAR_SOURCE_NONE:
|
|
|
|
return (s8)rtwdev->chip->max_power_index;
|
|
|
|
case RTW_SAR_SOURCE_COMMON:
|
|
|
|
return sar->cfg[arg->path][arg->rs].common[arg->sar_band];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int rtw_apply_sar(struct rtw_dev *rtwdev, const struct rtw_sar *new)
|
|
|
|
{
|
|
|
|
struct rtw_hal *hal = &rtwdev->hal;
|
|
|
|
struct rtw_sar *sar = &hal->sar;
|
|
|
|
|
|
|
|
if (sar->src != RTW_SAR_SOURCE_NONE && new->src != sar->src) {
|
|
|
|
rtw_warn(rtwdev, "SAR source: %d is in use\n", sar->src);
|
|
|
|
return -EBUSY;
|
|
|
|
}
|
|
|
|
|
|
|
|
*sar = *new;
|
|
|
|
rtw_phy_set_tx_power_level(rtwdev, hal->current_channel);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static s8 rtw_sar_to_phy(struct rtw_dev *rtwdev, u8 fct, s32 sar,
|
|
|
|
const struct rtw_sar_arg *arg)
|
|
|
|
{
|
|
|
|
struct rtw_hal *hal = &rtwdev->hal;
|
|
|
|
u8 txgi = rtwdev->chip->txgi_factor;
|
|
|
|
u8 max = rtwdev->chip->max_power_index;
|
|
|
|
s32 tmp;
|
|
|
|
s8 base;
|
|
|
|
|
|
|
|
tmp = fct > txgi ? sar >> (fct - txgi) : sar << (txgi - fct);
|
|
|
|
base = arg->sar_band == RTW_SAR_BAND_0 ?
|
|
|
|
hal->tx_pwr_by_rate_base_2g[arg->path][arg->rs] :
|
|
|
|
hal->tx_pwr_by_rate_base_5g[arg->path][arg->rs];
|
|
|
|
|
|
|
|
return (s8)clamp_t(s32, tmp, -max - 1, max) - base;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct cfg80211_sar_freq_ranges rtw_common_sar_freq_ranges[] = {
|
|
|
|
[RTW_SAR_BAND_0] = { .start_freq = 2412, .end_freq = 2484, },
|
|
|
|
[RTW_SAR_BAND_1] = { .start_freq = 5180, .end_freq = 5320, },
|
|
|
|
[RTW_SAR_BAND_3] = { .start_freq = 5500, .end_freq = 5720, },
|
|
|
|
[RTW_SAR_BAND_4] = { .start_freq = 5745, .end_freq = 5825, },
|
|
|
|
};
|
|
|
|
|
|
|
|
static_assert(ARRAY_SIZE(rtw_common_sar_freq_ranges) == RTW_SAR_BAND_NR);
|
|
|
|
|
|
|
|
const struct cfg80211_sar_capa rtw_sar_capa = {
|
|
|
|
.type = NL80211_SAR_TYPE_POWER,
|
|
|
|
.num_freq_ranges = RTW_SAR_BAND_NR,
|
|
|
|
.freq_ranges = rtw_common_sar_freq_ranges,
|
|
|
|
};
|
|
|
|
|
|
|
|
int rtw_set_sar_specs(struct rtw_dev *rtwdev,
|
|
|
|
const struct cfg80211_sar_specs *sar)
|
|
|
|
{
|
|
|
|
struct rtw_sar_arg arg = {0};
|
|
|
|
struct rtw_sar new = {0};
|
|
|
|
u32 idx, i, j, k;
|
|
|
|
s32 power;
|
|
|
|
s8 val;
|
|
|
|
|
|
|
|
if (sar->type != NL80211_SAR_TYPE_POWER)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
memset(&new, rtwdev->chip->max_power_index, sizeof(new));
|
|
|
|
new.src = RTW_SAR_SOURCE_COMMON;
|
|
|
|
|
|
|
|
for (i = 0; i < sar->num_sub_specs; i++) {
|
|
|
|
idx = sar->sub_specs[i].freq_range_index;
|
|
|
|
if (idx >= RTW_SAR_BAND_NR)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
power = sar->sub_specs[i].power;
|
2022-02-18 11:55:27 +08:00
|
|
|
rtw_dbg(rtwdev, RTW_DBG_REGD, "On freq %u to %u, set SAR %d in 1/%lu dBm\n",
|
|
|
|
rtw_common_sar_freq_ranges[idx].start_freq,
|
|
|
|
rtw_common_sar_freq_ranges[idx].end_freq,
|
|
|
|
power, BIT(RTW_COMMON_SAR_FCT));
|
rtw88: support SAR via kernel common API
Register cfg80211_sar_capa with type NL80211_SAR_TYPE_POWER and four
frequency ranges for configurations in unit of 0.25 dBm. And handle
callback set_sar_specs.
Originally, TX power has three main parameters, i.e. power base,
power by rate, and power limit. The formula can be simply considered
as TX power = power base + min(power by rate, power limit). With the
support of SAR which can be treated as another power limit, there is
one more parameter for TX power. And the formula will evolve into
TX power = power base + min(power by rate, power limit, power sar).
Besides, debugfs tx_pwr_tbl is also refined to show SAR information.
The following is an example for the difference.
Before supporting SAR,
-----------------------------------
...
path rate pwr base (byr lmt ) rem
A CCK_1M 66(0x42) 78 -12 ( 12 -12) 0
A CCK_2M 66(0x42) 78 -12 ( 8 -12) 0
...
-----------------------------------
After supporting SAR and making some configurations,
-----------------------------------
...
path rate pwr base (byr lmt sar ) rem
A CCK_1M 62(0x3e) 78 -16 ( 12 -12 -16) 0
A CCK_2M 62(0x3e) 78 -16 ( 8 -12 -16) 0
...
-----------------------------------
Signed-off-by: Zong-Zhe Yang <kevin_yang@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
Signed-off-by: Kalle Valo <kvalo@kernel.org>
Link: https://lore.kernel.org/r/20211220093656.65312-1-pkshih@realtek.com
2021-12-20 17:36:56 +08:00
|
|
|
|
|
|
|
for (j = 0; j < RTW_RF_PATH_MAX; j++) {
|
2025-02-04 20:40:58 +02:00
|
|
|
for (k = 0; k < RTW_RATE_SECTION_NUM; k++) {
|
rtw88: support SAR via kernel common API
Register cfg80211_sar_capa with type NL80211_SAR_TYPE_POWER and four
frequency ranges for configurations in unit of 0.25 dBm. And handle
callback set_sar_specs.
Originally, TX power has three main parameters, i.e. power base,
power by rate, and power limit. The formula can be simply considered
as TX power = power base + min(power by rate, power limit). With the
support of SAR which can be treated as another power limit, there is
one more parameter for TX power. And the formula will evolve into
TX power = power base + min(power by rate, power limit, power sar).
Besides, debugfs tx_pwr_tbl is also refined to show SAR information.
The following is an example for the difference.
Before supporting SAR,
-----------------------------------
...
path rate pwr base (byr lmt ) rem
A CCK_1M 66(0x42) 78 -12 ( 12 -12) 0
A CCK_2M 66(0x42) 78 -12 ( 8 -12) 0
...
-----------------------------------
After supporting SAR and making some configurations,
-----------------------------------
...
path rate pwr base (byr lmt sar ) rem
A CCK_1M 62(0x3e) 78 -16 ( 12 -12 -16) 0
A CCK_2M 62(0x3e) 78 -16 ( 8 -12 -16) 0
...
-----------------------------------
Signed-off-by: Zong-Zhe Yang <kevin_yang@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
Signed-off-by: Kalle Valo <kvalo@kernel.org>
Link: https://lore.kernel.org/r/20211220093656.65312-1-pkshih@realtek.com
2021-12-20 17:36:56 +08:00
|
|
|
arg = (struct rtw_sar_arg){
|
|
|
|
.sar_band = idx,
|
|
|
|
.path = j,
|
|
|
|
.rs = k,
|
|
|
|
};
|
|
|
|
val = rtw_sar_to_phy(rtwdev, RTW_COMMON_SAR_FCT,
|
|
|
|
power, &arg);
|
|
|
|
new.cfg[j][k].common[idx] = val;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return rtw_apply_sar(rtwdev, &new);
|
|
|
|
}
|