wifi: rtw89: 8852bt: add set_channel_rf

Add RF part of set_channel() is to configure RF registers, and then
hardware can TX/RX on specified frequency and bandwidth.

Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
Link: https://patch.msgid.link/20240720021340.12102-2-pkshih@realtek.com
This commit is contained in:
Ping-Ke Shih
2024-07-20 10:13:34 +08:00
parent d523dc49d1
commit 6bd63e44e9
2 changed files with 229 additions and 0 deletions
@@ -4017,3 +4017,229 @@ void rtw8852bt_wifi_scan_notify(struct rtw89_dev *rtwdev, bool scan_start,
else
rtw8852bt_tssi_default_txagc(rtwdev, phy_idx, false);
}
static void _bw_setting(struct rtw89_dev *rtwdev, enum rtw89_rf_path path,
enum rtw89_bandwidth bw, bool dav)
{
u32 rf_reg18;
u32 reg18_addr = dav ? RR_CFGCH : RR_CFGCH_V1;
rtw89_debug(rtwdev, RTW89_DBG_RFK, "[RFK]===> %s\n", __func__);
rf_reg18 = rtw89_read_rf(rtwdev, path, reg18_addr, RFREG_MASK);
if (rf_reg18 == INV_RF_DATA) {
rtw89_debug(rtwdev, RTW89_DBG_RFK,
"[RFK]Invalid RF_0x18 for Path-%d\n", path);
return;
}
rf_reg18 &= ~RR_CFGCH_BW;
switch (bw) {
case RTW89_CHANNEL_WIDTH_5:
case RTW89_CHANNEL_WIDTH_10:
case RTW89_CHANNEL_WIDTH_20:
rf_reg18 |= FIELD_PREP(RR_CFGCH_BW, CFGCH_BW_20M);
break;
case RTW89_CHANNEL_WIDTH_40:
rf_reg18 |= FIELD_PREP(RR_CFGCH_BW, CFGCH_BW_40M);
break;
case RTW89_CHANNEL_WIDTH_80:
rf_reg18 |= FIELD_PREP(RR_CFGCH_BW, CFGCH_BW_80M);
break;
default:
rtw89_debug(rtwdev, RTW89_DBG_RFK, "[RFK]Fail to set CH\n");
}
rf_reg18 &= ~(RR_CFGCH_POW_LCK | RR_CFGCH_TRX_AH | RR_CFGCH_BCN |
RR_CFGCH_BW2) & RFREG_MASK;
rf_reg18 |= RR_CFGCH_BW2;
rtw89_write_rf(rtwdev, path, reg18_addr, RFREG_MASK, rf_reg18);
rtw89_debug(rtwdev, RTW89_DBG_RFK, "[RFK] set %x at path%d, %x =0x%x\n",
bw, path, reg18_addr,
rtw89_read_rf(rtwdev, path, reg18_addr, RFREG_MASK));
}
static void _ctrl_bw(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy,
enum rtw89_bandwidth bw)
{
_bw_setting(rtwdev, RF_PATH_A, bw, true);
_bw_setting(rtwdev, RF_PATH_B, bw, true);
_bw_setting(rtwdev, RF_PATH_A, bw, false);
_bw_setting(rtwdev, RF_PATH_B, bw, false);
}
static bool _set_s0_arfc18(struct rtw89_dev *rtwdev, u32 val)
{
u32 tmp;
int ret;
rtw89_write_rf(rtwdev, RF_PATH_A, RR_LCK_TRG, RR_LCK_TRGSEL, 0x1);
rtw89_write_rf(rtwdev, RF_PATH_A, RR_CFGCH, RFREG_MASK, val);
ret = read_poll_timeout_atomic(rtw89_read_rf, tmp, tmp == 0, 1, 1000,
false, rtwdev, RF_PATH_A, RR_LPF, RR_LPF_BUSY);
if (ret)
rtw89_debug(rtwdev, RTW89_DBG_RFK, "[LCK]LCK timeout\n");
rtw89_write_rf(rtwdev, RF_PATH_A, RR_LCK_TRG, RR_LCK_TRGSEL, 0x0);
return !!ret;
}
static void _lck_check(struct rtw89_dev *rtwdev)
{
u32 tmp;
if (rtw89_read_rf(rtwdev, RF_PATH_A, RR_SYNFB, RR_SYNFB_LK) == 0) {
rtw89_debug(rtwdev, RTW89_DBG_RFK, "[LCK]SYN MMD reset\n");
rtw89_write_rf(rtwdev, RF_PATH_A, RR_MMD, RR_MMD_RST_EN, 0x1);
rtw89_write_rf(rtwdev, RF_PATH_A, RR_MMD, RR_MMD_RST_SYN, 0x0);
rtw89_write_rf(rtwdev, RF_PATH_A, RR_MMD, RR_MMD_RST_SYN, 0x1);
rtw89_write_rf(rtwdev, RF_PATH_A, RR_MMD, RR_MMD_RST_EN, 0x0);
}
udelay(10);
if (rtw89_read_rf(rtwdev, RF_PATH_A, RR_SYNFB, RR_SYNFB_LK) == 0) {
rtw89_debug(rtwdev, RTW89_DBG_RFK, "[LCK]re-set RF 0x18\n");
rtw89_write_rf(rtwdev, RF_PATH_A, RR_LCK_TRG, RR_LCK_TRGSEL, 0x1);
tmp = rtw89_read_rf(rtwdev, RF_PATH_A, RR_CFGCH, RFREG_MASK);
_set_s0_arfc18(rtwdev, tmp);
rtw89_write_rf(rtwdev, RF_PATH_A, RR_LCK_TRG, RR_LCK_TRGSEL, 0x0);
}
if (rtw89_read_rf(rtwdev, RF_PATH_A, RR_SYNFB, RR_SYNFB_LK) == 0) {
rtw89_debug(rtwdev, RTW89_DBG_RFK, "[LCK]SYN off/on\n");
tmp = rtw89_read_rf(rtwdev, RF_PATH_A, RR_POW, RFREG_MASK);
rtw89_write_rf(rtwdev, RF_PATH_A, RR_POW, RFREG_MASK, tmp);
tmp = rtw89_read_rf(rtwdev, RF_PATH_A, RR_SX, RFREG_MASK);
rtw89_write_rf(rtwdev, RF_PATH_A, RR_SX, RFREG_MASK, tmp);
rtw89_write_rf(rtwdev, RF_PATH_A, RR_SYNLUT, RR_SYNLUT_MOD, 0x1);
rtw89_write_rf(rtwdev, RF_PATH_A, RR_POW, RR_POW_SYN, 0x0);
rtw89_write_rf(rtwdev, RF_PATH_A, RR_POW, RR_POW_SYN, 0x3);
rtw89_write_rf(rtwdev, RF_PATH_A, RR_SYNLUT, RR_SYNLUT_MOD, 0x0);
rtw89_write_rf(rtwdev, RF_PATH_A, RR_LCK_TRG, RR_LCK_TRGSEL, 0x1);
tmp = rtw89_read_rf(rtwdev, RF_PATH_A, RR_CFGCH, RFREG_MASK);
_set_s0_arfc18(rtwdev, tmp);
rtw89_write_rf(rtwdev, RF_PATH_A, RR_LCK_TRG, RR_LCK_TRGSEL, 0x0);
rtw89_debug(rtwdev, RTW89_DBG_RFK, "[LCK]0xb2=%x, 0xc5=%x\n",
rtw89_read_rf(rtwdev, RF_PATH_A, RR_VCO, RFREG_MASK),
rtw89_read_rf(rtwdev, RF_PATH_A, RR_SYNFB, RFREG_MASK));
}
}
static void _set_ch(struct rtw89_dev *rtwdev, u32 val)
{
bool timeout;
u32 bak;
bak = rtw89_read_rf(rtwdev, RF_PATH_A, RR_LDO, RFREG_MASK);
rtw89_write_rf(rtwdev, RF_PATH_A, RR_LDO, RR_LDO_SEL, 0x1);
timeout = _set_s0_arfc18(rtwdev, val);
rtw89_write_rf(rtwdev, RF_PATH_A, RR_LDO, RFREG_MASK, bak);
if (!timeout)
_lck_check(rtwdev);
}
static void _ch_setting(struct rtw89_dev *rtwdev, enum rtw89_rf_path path,
u8 central_ch, bool dav)
{
u32 reg18_addr = dav ? RR_CFGCH : RR_CFGCH_V1;
bool is_2g_ch = central_ch <= 14;
u32 rf_reg18;
rtw89_debug(rtwdev, RTW89_DBG_RFK, "[RFK]===> %s\n", __func__);
rf_reg18 = rtw89_read_rf(rtwdev, path, reg18_addr, RFREG_MASK);
rf_reg18 &= ~(RR_CFGCH_BAND1 | RR_CFGCH_POW_LCK | RR_CFGCH_TRX_AH |
RR_CFGCH_BCN | RR_CFGCH_BAND0 | RR_CFGCH_CH);
rf_reg18 |= FIELD_PREP(RR_CFGCH_CH, central_ch);
if (!is_2g_ch)
rf_reg18 |= FIELD_PREP(RR_CFGCH_BAND1, CFGCH_BAND1_5G) |
FIELD_PREP(RR_CFGCH_BAND0, CFGCH_BAND0_5G);
rf_reg18 &= ~(RR_CFGCH_POW_LCK | RR_CFGCH_TRX_AH | RR_CFGCH_BCN |
RR_CFGCH_BW2) & RFREG_MASK;
rf_reg18 |= RR_CFGCH_BW2;
if (path == RF_PATH_A && dav)
_set_ch(rtwdev, rf_reg18);
else
rtw89_write_rf(rtwdev, path, reg18_addr, RFREG_MASK, rf_reg18);
rtw89_write_rf(rtwdev, path, RR_LCKST, RR_LCKST_BIN, 0);
rtw89_write_rf(rtwdev, path, RR_LCKST, RR_LCKST_BIN, 1);
rtw89_debug(rtwdev, RTW89_DBG_RFK,
"[RFK]CH: %d for Path-%d, reg0x%x = 0x%x\n",
central_ch, path, reg18_addr,
rtw89_read_rf(rtwdev, path, reg18_addr, RFREG_MASK));
}
static void _ctrl_ch(struct rtw89_dev *rtwdev, u8 central_ch)
{
_ch_setting(rtwdev, RF_PATH_A, central_ch, true);
_ch_setting(rtwdev, RF_PATH_B, central_ch, true);
_ch_setting(rtwdev, RF_PATH_A, central_ch, false);
_ch_setting(rtwdev, RF_PATH_B, central_ch, false);
}
static void _set_rxbb_bw(struct rtw89_dev *rtwdev, enum rtw89_bandwidth bw,
enum rtw89_rf_path path)
{
rtw89_write_rf(rtwdev, path, RR_LUTWE2, RR_LUTWE2_RTXBW, 0x1);
rtw89_write_rf(rtwdev, path, RR_LUTWA, RR_LUTWA_M2, 0x12);
if (bw == RTW89_CHANNEL_WIDTH_20)
rtw89_write_rf(rtwdev, path, RR_LUTWD0, RR_LUTWD0_LB, 0x1b);
else if (bw == RTW89_CHANNEL_WIDTH_40)
rtw89_write_rf(rtwdev, path, RR_LUTWD0, RR_LUTWD0_LB, 0x13);
else if (bw == RTW89_CHANNEL_WIDTH_80)
rtw89_write_rf(rtwdev, path, RR_LUTWD0, RR_LUTWD0_LB, 0xb);
else
rtw89_write_rf(rtwdev, path, RR_LUTWD0, RR_LUTWD0_LB, 0x3);
rtw89_debug(rtwdev, RTW89_DBG_RFK, "[RFK] set S%d RXBB BW 0x3F = 0x%x\n",
path, rtw89_read_rf(rtwdev, path, RR_LUTWD0, RR_LUTWD0_LB));
rtw89_write_rf(rtwdev, path, RR_LUTWE2, RR_LUTWE2_RTXBW, 0x0);
}
static void _rxbb_bw(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy,
enum rtw89_bandwidth bw)
{
u8 kpath, path;
kpath = _kpath(rtwdev, phy);
for (path = 0; path < RF_PATH_NUM_8852BT; path++) {
if (!(kpath & BIT(path)))
continue;
_set_rxbb_bw(rtwdev, bw, path);
}
}
static void rtw8852bt_ctrl_bw_ch(struct rtw89_dev *rtwdev,
enum rtw89_phy_idx phy, u8 central_ch,
enum rtw89_band band, enum rtw89_bandwidth bw)
{
_ctrl_ch(rtwdev, central_ch);
_ctrl_bw(rtwdev, phy, bw);
_rxbb_bw(rtwdev, phy, bw);
}
void rtw8852bt_set_channel_rf(struct rtw89_dev *rtwdev,
const struct rtw89_chan *chan,
enum rtw89_phy_idx phy_idx)
{
rtw8852bt_ctrl_bw_ch(rtwdev, phy_idx, chan->channel, chan->band_type,
chan->band_width);
}
@@ -18,5 +18,8 @@ void rtw8852bt_tssi(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, bool hwtx_
void rtw8852bt_tssi_scan(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy);
void rtw8852bt_wifi_scan_notify(struct rtw89_dev *rtwdev, bool scan_start,
enum rtw89_phy_idx phy_idx);
void rtw8852bt_set_channel_rf(struct rtw89_dev *rtwdev,
const struct rtw89_chan *chan,
enum rtw89_phy_idx phy_idx);
#endif