xref: /freebsd/sys/contrib/dev/rtw88/sar.c (revision 9c951734)
12774f206SBjoern A. Zeeb // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
22774f206SBjoern A. Zeeb /* Copyright(c) 2018-2021  Realtek Corporation
32774f206SBjoern A. Zeeb  */
42774f206SBjoern A. Zeeb 
52774f206SBjoern A. Zeeb #include "sar.h"
62774f206SBjoern A. Zeeb #include "phy.h"
72774f206SBjoern A. Zeeb #include "debug.h"
82774f206SBjoern A. Zeeb 
rtw_query_sar(struct rtw_dev * rtwdev,const struct rtw_sar_arg * arg)92774f206SBjoern A. Zeeb s8 rtw_query_sar(struct rtw_dev *rtwdev, const struct rtw_sar_arg *arg)
102774f206SBjoern A. Zeeb {
112774f206SBjoern A. Zeeb 	const struct rtw_hal *hal = &rtwdev->hal;
122774f206SBjoern A. Zeeb 	const struct rtw_sar *sar = &hal->sar;
132774f206SBjoern A. Zeeb 
142774f206SBjoern A. Zeeb 	switch (sar->src) {
152774f206SBjoern A. Zeeb 	default:
162774f206SBjoern A. Zeeb 		rtw_warn(rtwdev, "unknown SAR source: %d\n", sar->src);
172774f206SBjoern A. Zeeb 		fallthrough;
182774f206SBjoern A. Zeeb 	case RTW_SAR_SOURCE_NONE:
192774f206SBjoern A. Zeeb 		return (s8)rtwdev->chip->max_power_index;
202774f206SBjoern A. Zeeb 	case RTW_SAR_SOURCE_COMMON:
212774f206SBjoern A. Zeeb 		return sar->cfg[arg->path][arg->rs].common[arg->sar_band];
222774f206SBjoern A. Zeeb 	}
232774f206SBjoern A. Zeeb }
242774f206SBjoern A. Zeeb 
rtw_apply_sar(struct rtw_dev * rtwdev,const struct rtw_sar * new)252774f206SBjoern A. Zeeb static int rtw_apply_sar(struct rtw_dev *rtwdev, const struct rtw_sar *new)
262774f206SBjoern A. Zeeb {
272774f206SBjoern A. Zeeb 	struct rtw_hal *hal = &rtwdev->hal;
282774f206SBjoern A. Zeeb 	struct rtw_sar *sar = &hal->sar;
292774f206SBjoern A. Zeeb 
302774f206SBjoern A. Zeeb 	if (sar->src != RTW_SAR_SOURCE_NONE && new->src != sar->src) {
312774f206SBjoern A. Zeeb 		rtw_warn(rtwdev, "SAR source: %d is in use\n", sar->src);
322774f206SBjoern A. Zeeb 		return -EBUSY;
332774f206SBjoern A. Zeeb 	}
342774f206SBjoern A. Zeeb 
352774f206SBjoern A. Zeeb 	*sar = *new;
362774f206SBjoern A. Zeeb 	rtw_phy_set_tx_power_level(rtwdev, hal->current_channel);
372774f206SBjoern A. Zeeb 
382774f206SBjoern A. Zeeb 	return 0;
392774f206SBjoern A. Zeeb }
402774f206SBjoern A. Zeeb 
rtw_sar_to_phy(struct rtw_dev * rtwdev,u8 fct,s32 sar,const struct rtw_sar_arg * arg)412774f206SBjoern A. Zeeb static s8 rtw_sar_to_phy(struct rtw_dev *rtwdev, u8 fct, s32 sar,
422774f206SBjoern A. Zeeb 			 const struct rtw_sar_arg *arg)
432774f206SBjoern A. Zeeb {
442774f206SBjoern A. Zeeb 	struct rtw_hal *hal = &rtwdev->hal;
452774f206SBjoern A. Zeeb 	u8 txgi = rtwdev->chip->txgi_factor;
462774f206SBjoern A. Zeeb 	u8 max = rtwdev->chip->max_power_index;
472774f206SBjoern A. Zeeb 	s32 tmp;
482774f206SBjoern A. Zeeb 	s8 base;
492774f206SBjoern A. Zeeb 
502774f206SBjoern A. Zeeb 	tmp = fct > txgi ? sar >> (fct - txgi) : sar << (txgi - fct);
512774f206SBjoern A. Zeeb 	base = arg->sar_band == RTW_SAR_BAND_0 ?
522774f206SBjoern A. Zeeb 	       hal->tx_pwr_by_rate_base_2g[arg->path][arg->rs] :
532774f206SBjoern A. Zeeb 	       hal->tx_pwr_by_rate_base_5g[arg->path][arg->rs];
542774f206SBjoern A. Zeeb 
552774f206SBjoern A. Zeeb 	return (s8)clamp_t(s32, tmp, -max - 1, max) - base;
562774f206SBjoern A. Zeeb }
572774f206SBjoern A. Zeeb 
582774f206SBjoern A. Zeeb static const struct cfg80211_sar_freq_ranges rtw_common_sar_freq_ranges[] = {
592774f206SBjoern A. Zeeb 	[RTW_SAR_BAND_0] = { .start_freq = 2412, .end_freq = 2484, },
602774f206SBjoern A. Zeeb 	[RTW_SAR_BAND_1] = { .start_freq = 5180, .end_freq = 5320, },
612774f206SBjoern A. Zeeb 	[RTW_SAR_BAND_3] = { .start_freq = 5500, .end_freq = 5720, },
622774f206SBjoern A. Zeeb 	[RTW_SAR_BAND_4] = { .start_freq = 5745, .end_freq = 5825, },
632774f206SBjoern A. Zeeb };
642774f206SBjoern A. Zeeb 
652774f206SBjoern A. Zeeb rtw88_static_assert(ARRAY_SIZE(rtw_common_sar_freq_ranges) == RTW_SAR_BAND_NR);
662774f206SBjoern A. Zeeb 
672774f206SBjoern A. Zeeb const struct cfg80211_sar_capa rtw_sar_capa = {
682774f206SBjoern A. Zeeb 	.type = NL80211_SAR_TYPE_POWER,
692774f206SBjoern A. Zeeb 	.num_freq_ranges = RTW_SAR_BAND_NR,
702774f206SBjoern A. Zeeb 	.freq_ranges = rtw_common_sar_freq_ranges,
712774f206SBjoern A. Zeeb };
722774f206SBjoern A. Zeeb 
rtw_set_sar_specs(struct rtw_dev * rtwdev,const struct cfg80211_sar_specs * sar)732774f206SBjoern A. Zeeb int rtw_set_sar_specs(struct rtw_dev *rtwdev,
742774f206SBjoern A. Zeeb 		      const struct cfg80211_sar_specs *sar)
752774f206SBjoern A. Zeeb {
762774f206SBjoern A. Zeeb 	struct rtw_sar_arg arg = {0};
772774f206SBjoern A. Zeeb 	struct rtw_sar new = {0};
782774f206SBjoern A. Zeeb 	u32 idx, i, j, k;
792774f206SBjoern A. Zeeb 	s32 power;
802774f206SBjoern A. Zeeb 	s8 val;
812774f206SBjoern A. Zeeb 
822774f206SBjoern A. Zeeb 	if (sar->type != NL80211_SAR_TYPE_POWER)
832774f206SBjoern A. Zeeb 		return -EINVAL;
842774f206SBjoern A. Zeeb 
852774f206SBjoern A. Zeeb 	memset(&new, rtwdev->chip->max_power_index, sizeof(new));
862774f206SBjoern A. Zeeb 	new.src = RTW_SAR_SOURCE_COMMON;
872774f206SBjoern A. Zeeb 
882774f206SBjoern A. Zeeb 	for (i = 0; i < sar->num_sub_specs; i++) {
892774f206SBjoern A. Zeeb 		idx = sar->sub_specs[i].freq_range_index;
902774f206SBjoern A. Zeeb 		if (idx >= RTW_SAR_BAND_NR)
912774f206SBjoern A. Zeeb 			return -EINVAL;
922774f206SBjoern A. Zeeb 
932774f206SBjoern A. Zeeb 		power = sar->sub_specs[i].power;
949c951734SBjoern A. Zeeb 		rtw_dbg(rtwdev, RTW_DBG_REGD, "On freq %u to %u, set SAR %d in 1/%lu dBm\n",
952774f206SBjoern A. Zeeb 			rtw_common_sar_freq_ranges[idx].start_freq,
962774f206SBjoern A. Zeeb 			rtw_common_sar_freq_ranges[idx].end_freq,
972774f206SBjoern A. Zeeb 			power, BIT(RTW_COMMON_SAR_FCT));
982774f206SBjoern A. Zeeb 
992774f206SBjoern A. Zeeb 		for (j = 0; j < RTW_RF_PATH_MAX; j++) {
1002774f206SBjoern A. Zeeb 			for (k = 0; k < RTW_RATE_SECTION_MAX; k++) {
1012774f206SBjoern A. Zeeb 				arg = (struct rtw_sar_arg){
1022774f206SBjoern A. Zeeb 					.sar_band = idx,
1032774f206SBjoern A. Zeeb 					.path = j,
1042774f206SBjoern A. Zeeb 					.rs = k,
1052774f206SBjoern A. Zeeb 				};
1062774f206SBjoern A. Zeeb 				val = rtw_sar_to_phy(rtwdev, RTW_COMMON_SAR_FCT,
1072774f206SBjoern A. Zeeb 						     power, &arg);
1082774f206SBjoern A. Zeeb 				new.cfg[j][k].common[idx] = val;
1092774f206SBjoern A. Zeeb 			}
1102774f206SBjoern A. Zeeb 		}
1112774f206SBjoern A. Zeeb 	}
1122774f206SBjoern A. Zeeb 
1132774f206SBjoern A. Zeeb 	return rtw_apply_sar(rtwdev, &new);
1142774f206SBjoern A. Zeeb }
115