From: luka.gejak@linux.dev
To: Ping-Ke Shih <pkshih@realtek.com>
Cc: linux-wireless@vger.kernel.org, linux-kernel@vger.kernel.org,
Michael Straube <straube.linux@gmail.com>,
Peter Robinson <pbrobinson@gmail.com>,
Bitterblue Smith <rtl8821cerfe2@gmail.com>,
Luka Gejak <luka.gejak@linux.dev>
Subject: [PATCH 09/19] wifi: rtw88: coex: add the RTL8723BS scan antenna workaround
Date: Fri, 24 Jul 2026 20:18:48 +0200 [thread overview]
Message-ID: <20260724181858.192903-10-luka.gejak@linux.dev> (raw)
In-Reply-To: <20260724181858.192903-1-luka.gejak@linux.dev>
From: Luka Gejak <luka.gejak@linux.dev>
On the RTL8723BS the PTA antenna path has to be programmed directly
during scan. The vendor driver keeps its own scan-time antenna state and
does not run the generic coexistence algorithm on boards where BT is
disabled, and following it is necessary here: without the antenna and
CCK priority setup applied at scan start, the site survey does not hear
the AP reliably.
Detect the BT-disabled case, replay the vendor BT_MP and BT_INFO queries
once the firmware has been up long enough for RX DMA to be stable, then
establish the scan path antenna configuration and skip the generic run.
Signed-off-by: Luka Gejak <luka.gejak@linux.dev>
---
drivers/net/wireless/realtek/rtw88/coex.c | 177 ++++++++++++++++++++++
drivers/net/wireless/realtek/rtw88/coex.h | 2 +
2 files changed, 179 insertions(+)
diff --git a/drivers/net/wireless/realtek/rtw88/coex.c b/drivers/net/wireless/realtek/rtw88/coex.c
index 37c336def419..dbe3842b5f6b 100644
--- a/drivers/net/wireless/realtek/rtw88/coex.c
+++ b/drivers/net/wireless/realtek/rtw88/coex.c
@@ -1443,6 +1443,156 @@ static void rtw_coex_set_ant_path(struct rtw_dev *rtwdev, bool force, u8 phase)
#define case_ALGO(src) \
case COEX_ALGO_##src: return #src
+/* 8723BS SDIO WiFi/BT coexistence antenna handling. On BT-disabled boards the
+ * scan/auth window still routes through the PTA mux; these helpers force the
+ * vendor-shaped WiFi-owned antenna path so directed management TX reaches air.
+ */
+#define REG_8723BS_BT_COEX_CTRL 0x0039
+#define REG_8723BS_BB_ANT_CFG 0x0930
+#define REG_8723BS_BB_ANT_CFG1 0x0944
+#define REG_8723BS_BB_ANT_BUF 0x0974
+#define RTW8723BS_COEX_H_WLAN_ACTIVE 0x1800101b
+
+static bool rtw_coex_8723bs_ant_is_aux(struct rtw_dev *rtwdev)
+{
+ return !!(rtwdev->efuse.bt_setting & BIT(6));
+}
+
+static bool rtw_coex_8723bs_bt_disabled(struct rtw_dev *rtwdev)
+{
+ return rtw_is_8723bs(rtwdev) && rtwdev->coex.stat.bt_disabled;
+}
+
+static u32 rtw_coex_8723bs_pta_ant_path(struct rtw_dev *rtwdev)
+{
+ return rtw_coex_8723bs_ant_is_aux(rtwdev) ? 0x80 : 0x200;
+}
+
+/* Write BB_SEL_BTG (0x948), retrying once with SYS_FUNC BB reset if the first
+ * write does not stick (RF/BB clock may have been gated).
+ */
+static u32 rtw_coex_8723bs_write_bb_sel_btg(struct rtw_dev *rtwdev, u32 value)
+{
+ u8 sys_func_before;
+ u32 readback;
+
+ sys_func_before = rtw_read8(rtwdev, REG_SYS_FUNC_EN);
+ if ((sys_func_before & (BIT(0) | BIT(1))) != (BIT(0) | BIT(1))) {
+ rtw_write8_set(rtwdev, REG_SYS_FUNC_EN, BIT(0) | BIT(1));
+ usleep_range(10, 11);
+ }
+
+ rtw_write32(rtwdev, 0x948, value);
+ readback = rtw_read32(rtwdev, 0x948);
+ if (readback == value)
+ return readback;
+
+ usleep_range(10, 11);
+ rtw_write8_set(rtwdev, REG_SYS_FUNC_EN, BIT(0) | BIT(1));
+ rtw_write32(rtwdev, 0x948, value);
+
+ return rtw_read32(rtwdev, 0x948);
+}
+
+static u32 rtw_coex_8723bs_reassert_pta_ant(struct rtw_dev *rtwdev)
+{
+ return rtw_coex_8723bs_write_bb_sel_btg(rtwdev,
+ rtw_coex_8723bs_pta_ant_path(rtwdev));
+}
+
+static void rtw_coex_8723bs_set_cck_pri(struct rtw_dev *rtwdev, bool high)
+{
+ if (!rtw_coex_8723bs_bt_disabled(rtwdev))
+ return;
+
+ if (high) {
+ rtw_write32(rtwdev, REG_BT_COEX_TABLE_H,
+ RTW8723BS_COEX_H_WLAN_ACTIVE);
+ } else {
+ rtw_coex_set_wl_pri_mask(rtwdev, COEX_WLPRI_TX_CCK, false);
+ rtw_coex_set_wl_pri_mask(rtwdev, COEX_WLPRI_RX_CCK, false);
+ }
+}
+
+static void rtw_coex_8723bs_restore_pad_ctrl(struct rtw_dev *rtwdev,
+ bool keep_pta_owner)
+{
+ u32 before, after;
+
+ before = rtw_read32(rtwdev, REG_PAD_CTRL1);
+ after = before & ~(BIT_LNAON_WLBT_SEL | BIT_SW_DPDT_SEL_DATA);
+ if (keep_pta_owner)
+ after |= BIT_PAPE_WLBT_SEL;
+ else
+ after &= ~BIT_PAPE_WLBT_SEL;
+ if (after != before)
+ rtw_write32(rtwdev, REG_PAD_CTRL1, after);
+}
+
+static void rtw_coex_8723bs_fw_gnt_bt_low(struct rtw_dev *rtwdev)
+{
+ if (!rtw_coex_8723bs_bt_disabled(rtwdev))
+ return;
+
+ if (rtw_read8(rtwdev, 0x765) == 0x00 &&
+ rtw_read8(rtwdev, 0x76e) == 0x0c)
+ return;
+
+ rtw_fw_set_gnt_bt(rtwdev, 0);
+}
+
+static void rtw_coex_8723bs_reassert_ant_buffer(struct rtw_dev *rtwdev)
+{
+ u8 sys_func_before;
+
+ sys_func_before = rtw_read8(rtwdev, REG_SYS_FUNC_EN);
+ if ((sys_func_before & (BIT(0) | BIT(1))) != (BIT(0) | BIT(1))) {
+ rtw_write8_set(rtwdev, REG_SYS_FUNC_EN, BIT(0) | BIT(1));
+ usleep_range(10, 11);
+ }
+
+ rtw_write8_mask(rtwdev, REG_8723BS_BT_COEX_CTRL, BIT(3), 0x1);
+ rtw_write8(rtwdev, REG_8723BS_BB_ANT_BUF, 0xff);
+ rtw_write8_mask(rtwdev, REG_8723BS_BB_ANT_CFG1, 0x3, 0x3);
+ rtw_write8(rtwdev, REG_8723BS_BB_ANT_CFG, 0x77);
+}
+
+static void rtw_coex_8723bs_apply_scan_table(struct rtw_dev *rtwdev)
+{
+ rtwdev->coex.dm.cur_table = 2;
+ rtw_coex_set_table(rtwdev, true, 0x5a5a5a5a, 0x5a5a5a5a);
+}
+
+/* Non-connected scan/auth workaround: PS-TDMA type 8 off, PTA antenna path,
+ * coex table type 2 (matches the vendor non-connected arbitration).
+ */
+void rtw_coex_8723bs_scan_workaround(struct rtw_dev *rtwdev)
+{
+ struct rtw_coex_dm *coex_dm = &rtwdev->coex.dm;
+ struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat;
+
+ if (!rtw_is_8723bs(rtwdev))
+ return;
+
+ coex_dm->cur_ps_tdma_on = false;
+ coex_dm->cur_ps_tdma = 8;
+ coex_dm->ps_tdma_para[0] = 0x08;
+ coex_dm->ps_tdma_para[1] = 0x00;
+ coex_dm->ps_tdma_para[2] = 0x00;
+ coex_dm->ps_tdma_para[3] = 0x00;
+ coex_dm->ps_tdma_para[4] = 0x00;
+
+ rtw_fw_coex_tdma_type(rtwdev, 0x08, 0x00, 0x00, 0x00, 0x00);
+ rtw_coex_8723bs_fw_gnt_bt_low(rtwdev);
+ rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_2G);
+ rtw_coex_8723bs_reassert_ant_buffer(rtwdev);
+ rtw_coex_8723bs_apply_scan_table(rtwdev);
+ if (coex_stat->bt_disabled)
+ rtw_coex_8723bs_set_cck_pri(rtwdev, true);
+ rtw_coex_8723bs_reassert_pta_ant(rtwdev);
+ rtw_coex_8723bs_restore_pad_ctrl(rtwdev, true);
+}
+
static const char *rtw_coex_get_algo_string(u8 algo)
{
switch (algo) {
@@ -2877,6 +3027,33 @@ void rtw_coex_scan_notify(struct rtw_dev *rtwdev, u8 type)
coex->freeze = false;
rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE | COEX_SCBD_ONOFF, true);
+ /* 8723BS SDIO BT-disabled: keep the scan/auth PTA antenna state the
+ * vendor uses and skip the generic coex run. At scan start (firmware
+ * has been up long enough for stable RX DMA) replay the vendor BT_MP /
+ * BT_INFO queries, then re-establish the scan-path PTA setup.
+ */
+ if (rtw_coex_8723bs_bt_disabled(rtwdev)) {
+ if (type == COEX_SCAN_START_2G || type == COEX_SCAN_START) {
+ struct rtw_coex_info_req req = {};
+
+ coex_stat->cnt_wl[COEX_CNT_WL_SCANAP] = 0;
+ coex_stat->wl_hi_pri_task2 = true;
+
+ req.seq = 0x0e;
+ req.op_code = BT_MP_INFO_OP_SUPP_VER;
+ rtw_fw_query_bt_mp_info(rtwdev, &req);
+ req.seq = 0x0f;
+ req.op_code = BT_MP_INFO_OP_PATCH_VER;
+ rtw_fw_query_bt_mp_info(rtwdev, &req);
+ rtw_fw_query_bt_info(rtwdev);
+
+ rtw_coex_8723bs_scan_workaround(rtwdev);
+ } else {
+ coex_stat->wl_hi_pri_task2 = false;
+ }
+ return;
+ }
+
if (type == COEX_SCAN_START_5G) {
rtw_dbg(rtwdev, RTW_DBG_COEX,
"[BTCoex], SCAN START notify (5G)\n");
diff --git a/drivers/net/wireless/realtek/rtw88/coex.h b/drivers/net/wireless/realtek/rtw88/coex.h
index c398be8391f7..72b1353c9313 100644
--- a/drivers/net/wireless/realtek/rtw88/coex.h
+++ b/drivers/net/wireless/realtek/rtw88/coex.h
@@ -430,4 +430,6 @@ static inline void rtw_coex_active_query_bt_info(struct rtw_dev *rtwdev)
rtw_coex_query_bt_info(rtwdev);
}
+void rtw_coex_8723bs_scan_workaround(struct rtw_dev *rtwdev);
+
#endif
--
2.55.0
next prev parent reply other threads:[~2026-07-24 18:19 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-24 18:18 [PATCH 00/19] wifi: rtw88: preparations for RTL8723B/RTL8723BS luka.gejak
2026-07-24 18:18 ` [PATCH 01/19] wifi: rtw88: add the RTL8723B chip type and SDIO helper luka.gejak
2026-07-24 18:18 ` [PATCH 02/19] wifi: rtw88: rx: mark zero length packets on RTL8723B luka.gejak
2026-07-24 18:18 ` [PATCH 03/19] wifi: rtw88: tx: extend the TX report purge timeout to RTL8723BS luka.gejak
2026-07-24 18:18 ` [PATCH 04/19] wifi: rtw88: fw: handle the RTL8723BS management TX reports luka.gejak
2026-07-24 18:18 ` [PATCH 05/19] wifi: rtw88: fw: send rate adaptation and RSSI info in the vendor layout luka.gejak
2026-07-24 18:18 ` [PATCH 06/19] wifi: rtw88: fw: send the media status report " luka.gejak
2026-07-24 18:18 ` [PATCH 07/19] wifi: rtw88: fw: add the vendor firmware commands used by RTL8723BS luka.gejak
2026-07-24 18:18 ` [PATCH 08/19] wifi: rtw88: fw: fix the reserved page upload on RTL8723BS luka.gejak
2026-07-24 18:18 ` luka.gejak [this message]
2026-07-24 18:32 ` [PATCH 10/19] wifi: rtw88: coex: reassert the antenna path when associating luka.gejak
2026-07-24 18:32 ` [PATCH 11/19] wifi: rtw88: sdio: track free TX pages and OQT credits for RTL8723BS luka.gejak
2026-07-24 18:32 ` [PATCH 12/19] wifi: rtw88: sdio: handle the RTL8723BS management TX path luka.gejak
2026-07-24 18:32 ` [PATCH 13/19] wifi: rtw88: sdio: set up RX aggregation and interrupts for RTL8723BS luka.gejak
2026-07-24 18:32 ` [PATCH 14/19] wifi: rtw88: sdio: add TX back-pressure and retry on page starvation luka.gejak
2026-07-24 18:32 ` [PATCH 15/19] wifi: rtw88: record beacons from the target BSSID before authenticating luka.gejak
2026-07-24 18:32 ` [PATCH 16/19] wifi: rtw88: run the RTL8723BS association register sequence luka.gejak
2026-07-24 18:33 ` [PATCH 17/19] wifi: rtw88: calibrate and tune the PHY for RTL8723BS luka.gejak
2026-07-24 18:33 ` [PATCH 18/19] wifi: rtw88: match the RTL8723BS firmware connect and power save behaviour luka.gejak
2026-07-24 18:33 ` [PATCH 19/19] wifi: rtw88: advertise the correct receive capabilities on RTL8723BS luka.gejak
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260724181858.192903-10-luka.gejak@linux.dev \
--to=luka.gejak@linux.dev \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-wireless@vger.kernel.org \
--cc=pbrobinson@gmail.com \
--cc=pkshih@realtek.com \
--cc=rtl8821cerfe2@gmail.com \
--cc=straube.linux@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox