wifi: rtw89: 8851b: add set_channel_rf()
authorPing-Ke Shih <pkshih@realtek.com>
Mon, 24 Apr 2023 06:52:38 +0000 (14:52 +0800)
committerKalle Valo <kvalo@kernel.org>
Fri, 5 May 2023 12:01:02 +0000 (15:01 +0300)
Add to set RF registers according to the channel we want to switch. The
callers will be added afterward.

Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
Signed-off-by: Kalle Valo <kvalo@kernel.org>
Link: https://lore.kernel.org/r/20230424065242.17477-2-pkshih@realtek.com
drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c [new file with mode: 0644]
drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.h [new file with mode: 0644]

diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c
new file mode 100644 (file)
index 0000000..9276e85
--- /dev/null
@@ -0,0 +1,239 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/* Copyright(c) 2022-2023  Realtek Corporation
+ */
+
+#include "coex.h"
+#include "debug.h"
+#include "mac.h"
+#include "phy.h"
+#include "reg.h"
+#include "rtw8851b.h"
+#include "rtw8851b_rfk.h"
+#include "rtw8851b_rfk_table.h"
+#include "rtw8851b_table.h"
+
+static u8 _kpath(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx)
+{
+       return RF_A;
+}
+
+static void _bw_setting(struct rtw89_dev *rtwdev, enum rtw89_rf_path path,
+                       enum rtw89_bandwidth bw, bool dav)
+{
+       u32 reg18_addr = dav ? RR_CFGCH : RR_CFGCH_V1;
+       u32 rf_reg18;
+
+       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_A, bw, false);
+}
+
+static bool _set_s0_arfc18(struct rtw89_dev *rtwdev, u32 val)
+{
+       u32 bak;
+       u32 tmp;
+       int ret;
+
+       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);
+       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_LDO, RFREG_MASK, bak);
+
+       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;
+
+       timeout = _set_s0_arfc18(rtwdev, val);
+       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_A, 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_8851B; path++) {
+               if (!(kpath & BIT(path)))
+                       continue;
+
+               _set_rxbb_bw(rtwdev, bw, path);
+       }
+}
+
+static void rtw8851b_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 rtw8851b_set_channel_rf(struct rtw89_dev *rtwdev,
+                            const struct rtw89_chan *chan,
+                            enum rtw89_phy_idx phy_idx)
+{
+       rtw8851b_ctrl_bw_ch(rtwdev, phy_idx, chan->channel, chan->band_type,
+                           chan->band_width);
+}
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.h b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.h
new file mode 100644 (file)
index 0000000..c81eb98
--- /dev/null
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
+/* Copyright(c) 2022-2023  Realtek Corporation
+ */
+
+#ifndef __RTW89_8851B_RFK_H__
+#define __RTW89_8851B_RFK_H__
+
+#include "core.h"
+
+void rtw8851b_set_channel_rf(struct rtw89_dev *rtwdev,
+                            const struct rtw89_chan *chan,
+                            enum rtw89_phy_idx phy_idx);
+
+#endif