* [PATCH rtw-next 0/9] wifi: rtw89: coex: implement components for dual Bluetooth
@ 2026-07-03 11:43 Ping-Ke Shih
2026-07-03 11:43 ` [PATCH rtw-next 1/9] wifi: rtw89: coex: Add Init info version 10 Ping-Ke Shih
` (8 more replies)
0 siblings, 9 replies; 10+ messages in thread
From: Ping-Ke Shih @ 2026-07-03 11:43 UTC (permalink / raw)
To: linux-wireless; +Cc: ku920601
Extend more components of BT-coexitence to support dual Bluetooth,
including TDMA descriptor, TX power, RX gain, scoreboard and etc.
Ching-Te Ku (9):
wifi: rtw89: coex: Add Init info version 10
wifi: rtw89: coex: add rtw89_btc_init() entry for initialization once
wifi: rtw89: coex: Update TDMA descriptor for dual MAC
wifi: rtw89: coex: Add Bluetooth binding for Bluetooth TX power
setting
wifi: rtw89: coex: Add Bluetooth binding for Bluetooth RX gain setting
wifi: rtw89: coex: Add WiFi/Bluetooth adapter binding info
wifi: rtw89: coex: Add TDMA binding for dual MAC
wifi: rtw89: coex: Update scoreboard related logic for dual Bluetooth
wifi: rtw89: coex: Add Co-RX logic
drivers/net/wireless/realtek/rtw89/coex.c | 1493 +++++++++++------
drivers/net/wireless/realtek/rtw89/coex.h | 16 +
drivers/net/wireless/realtek/rtw89/core.c | 5 +-
drivers/net/wireless/realtek/rtw89/core.h | 241 ++-
drivers/net/wireless/realtek/rtw89/fw.c | 41 +
drivers/net/wireless/realtek/rtw89/fw.h | 9 +
drivers/net/wireless/realtek/rtw89/rtw8851b.c | 2 -
drivers/net/wireless/realtek/rtw89/rtw8852a.c | 1 -
.../wireless/realtek/rtw89/rtw8852b_common.c | 1 -
drivers/net/wireless/realtek/rtw89/rtw8852c.c | 1 -
drivers/net/wireless/realtek/rtw89/rtw8922a.c | 1 -
11 files changed, 1298 insertions(+), 513 deletions(-)
base-commit: 2b7858891b100587c10c136cf07205335a897be0
--
2.25.1
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH rtw-next 1/9] wifi: rtw89: coex: Add Init info version 10
2026-07-03 11:43 [PATCH rtw-next 0/9] wifi: rtw89: coex: implement components for dual Bluetooth Ping-Ke Shih
@ 2026-07-03 11:43 ` Ping-Ke Shih
2026-07-03 11:43 ` [PATCH rtw-next 2/9] wifi: rtw89: coex: add rtw89_btc_init() entry for initialization once Ping-Ke Shih
` (7 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Ping-Ke Shih @ 2026-07-03 11:43 UTC (permalink / raw)
To: linux-wireless; +Cc: ku920601
From: Ching-Te Ku <ku920601@realtek.com>
The version 10 Init info add I/O offload type & variable Bluetooth
function (EX: Zigbee/Thread...etc) into the structure definition.
Firmware need to synchronize these information to do corresponding
setting.
Signed-off-by: Ching-Te Ku <ku920601@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/coex.c | 58 +++++++++++++++++--
drivers/net/wireless/realtek/rtw89/coex.h | 6 ++
drivers/net/wireless/realtek/rtw89/core.h | 54 ++++++++++++++++-
drivers/net/wireless/realtek/rtw89/fw.c | 41 +++++++++++++
drivers/net/wireless/realtek/rtw89/fw.h | 6 ++
drivers/net/wireless/realtek/rtw89/rtw8851b.c | 2 -
drivers/net/wireless/realtek/rtw89/rtw8852a.c | 1 -
.../wireless/realtek/rtw89/rtw8852b_common.c | 1 -
drivers/net/wireless/realtek/rtw89/rtw8852c.c | 1 -
drivers/net/wireless/realtek/rtw89/rtw8922a.c | 1 -
10 files changed, 159 insertions(+), 12 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c
index 1361d4d54528..43de238c18f8 100644
--- a/drivers/net/wireless/realtek/rtw89/coex.c
+++ b/drivers/net/wireless/realtek/rtw89/coex.c
@@ -2822,6 +2822,8 @@ static void _fw_set_drv_info(struct rtw89_dev *rtwdev, u8 index)
case CXDRVINFO_INIT:
if (ver->fcxinit == 7)
rtw89_fw_h2c_cxdrv_init_v7(rtwdev, index);
+ else if (ver->fcxinit == 10)
+ rtw89_fw_h2c_cxdrv_init_v10(rtwdev, index);
else
rtw89_fw_h2c_cxdrv_init(rtwdev, index);
break;
@@ -7884,15 +7886,30 @@ void rtw89_btc_ntfy_poweroff(struct rtw89_dev *rtwdev)
btc->cx.wl.status.map.rf_off_pre = btc->cx.wl.status.map.rf_off;
}
+#define BTC_PLATFORM_LITTLE_ENDIAN 0
static void _set_init_info(struct rtw89_dev *rtwdev)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
struct rtw89_btc *btc = &rtwdev->btc;
const struct rtw89_btc_ver *ver = btc->ver;
struct rtw89_btc_dm *dm = &btc->dm;
+ struct rtw89_btc_cx *cx = &btc->cx;
struct rtw89_btc_wl_info *wl = &btc->cx.wl;
- if (ver->fcxinit == 7) {
+ if (ver->fcxinit == 10) {
+ dm->init_info.init_v10.init_mode = wl->coex_mode;
+ dm->init_info.init_v10.wl_init_ok = wl->status.map.init_ok;
+ dm->init_info.init_v10.endian_type = BTC_PLATFORM_LITTLE_ENDIAN;
+
+ dm->init_info.init_v10.module = btc->mdinfo.md_v10;
+
+ dm->init_info.init_v10.bt0_function = cx->bt0.func_type;
+ dm->init_info.init_v10.bt1_function = cx->bt1.func_type;
+ dm->init_info.init_v10.bt2_function = cx->bt_ext.func_type;
+
+ dm->init_info.init_v10.pta_mode = RTW89_MAC_AX_COEX_RTK_MODE;
+ dm->init_info.init_v10.pta_direction = RTW89_MAC_AX_COEX_INNER;
+ } else if (ver->fcxinit == 7) {
dm->init_info.init_v7.wl_only = (u8)dm->wl_only;
dm->init_info.init_v7.bt_only = (u8)dm->bt_only;
dm->init_info.init_v7.wl_init_ok = (u8)wl->status.map.init_ok;
@@ -7908,6 +7925,12 @@ static void _set_init_info(struct rtw89_dev *rtwdev)
dm->init_info.init.wl_guard_ch = chip->afh_guard_ch;
dm->init_info.init.module = btc->mdinfo.md;
}
+
+ _fw_set_drv_info(rtwdev, CXDRVINFO_INIT);
+ _fw_set_drv_info(rtwdev, CXDRVINFO_CTRL);
+ rtw89_btc_fw_set_slots(rtwdev);
+ btc_fw_set_monreg(rtwdev);
+ _set_wl_tx_power(rtwdev, RTW89_BTC_WL_DEF_TX_PWR, RTW89_PHY_0);
}
void rtw89_btc_ntfy_init(struct rtw89_dev *rtwdev, u8 mode)
@@ -7918,13 +7941,18 @@ void rtw89_btc_ntfy_init(struct rtw89_dev *rtwdev, u8 mode)
const struct rtw89_chip_info *chip = rtwdev->chip;
const struct rtw89_btc_ver *ver = btc->ver;
+ rtw89_debug(rtwdev, RTW89_DBG_BTC,
+ "[BTC], %s(): Init %s !!\n", __func__,
+ chip_id_str(chip->chip_id));
+
_reset_btc_var(rtwdev, BTC_RESET_ALL);
btc->dm.run_reason = BTC_RSN_NONE;
btc->dm.run_action = BTC_ACT_NONE;
- if (ver->fcxctrl == 7)
+ if (ver->fcxctrl >= 7)
btc->ctrl.ctrl_v7.igno_bt = true;
else
btc->ctrl.ctrl.igno_bt = true;
+ wl->status.map.init_ok = true;
rtw89_debug(rtwdev, RTW89_DBG_BTC,
"[BTC], %s(): mode=%d\n", __func__, mode);
@@ -7934,9 +7962,11 @@ void rtw89_btc_ntfy_init(struct rtw89_dev *rtwdev, u8 mode)
dm->wl_only = mode == BTC_MODE_WL ? 1 : 0;
dm->bt_only = mode == BTC_MODE_BT ? 1 : 0;
wl->status.map.rf_off = mode == BTC_MODE_WLOFF ? 1 : 0;
-
- chip->ops->btc_set_rfe(rtwdev);
- chip->ops->btc_init_cfg(rtwdev);
+ dm->vid = rtwdev->custid;
+ if (ver->fcxctrl >= 7)
+ btc->ctrl.ctrl_v7.always_freerun = mode == BTC_MODE_COTX;
+ else
+ btc->ctrl.ctrl.always_freerun = mode == BTC_MODE_COTX;
if (!wl->status.map.init_ok) {
rtw89_debug(rtwdev, RTW89_DBG_BTC,
@@ -7946,8 +7976,26 @@ void rtw89_btc_ntfy_init(struct rtw89_dev *rtwdev, u8 mode)
return;
}
+ if (rtwdev->chip->para_ver & BTC_FEAT_DUAL_BT) {
+ btc->cx.bt1.enable.now = 1;
+ btc->cx.bt1.run_patch_code = 1;
+ }
+
+ if (rtwdev->chip->para_ver & BTC_FEAT_H2C_MACRO) {
+ btc->cx.bt0.enable.now = 1;
+ btc->cx.bt0.run_patch_code = 1;
+ btc->io_oflld_type = BTC_IO_OFLD_BTC_H2C;
+ } else {
+ btc->io_oflld_type = BTC_IO_OFLD_NO_SUPPORT;
+ _update_bt_scbd(rtwdev, true);
+ }
+
+ chip->ops->btc_set_rfe(rtwdev);
+ chip->ops->btc_init_cfg(rtwdev);
+
_write_scbd(rtwdev,
BTC_WSCB_ACTIVE | BTC_WSCB_ON | BTC_WSCB_BTLOG, true);
+
if (rtw89_mac_get_ctrl_path(rtwdev)) {
rtw89_debug(rtwdev, RTW89_DBG_BTC,
"[BTC], %s(): PTA owner warning!!\n",
diff --git a/drivers/net/wireless/realtek/rtw89/coex.h b/drivers/net/wireless/realtek/rtw89/coex.h
index 6ac14611607c..259c6e2c0e3c 100644
--- a/drivers/net/wireless/realtek/rtw89/coex.h
+++ b/drivers/net/wireless/realtek/rtw89/coex.h
@@ -16,6 +16,8 @@ enum btc_mode {
BTC_MODE_WL,
BTC_MODE_BT,
BTC_MODE_WLOFF,
+ BTC_MODE_COTX,
+ BTC_MODE_MECHANISM_INIT,
BTC_MODE_MAX
};
@@ -212,6 +214,10 @@ enum btc_chip_feature {
BTC_FEAT_NEW_BBAPI_FLOW = BIT(3), /* new btg_ctrl/pre_agc_ctrl */
BTC_FEAT_MLO_SUPPORT = BIT(4),
BTC_FEAT_H2C_MACRO = BIT(5),
+ BTC_FEAT_DUAL_BT = BIT(6),
+ BTC_FEAT_BT_6G = BIT(7),
+ BTC_FEAT_MULTI_PTA = BIT(8),
+ BTC_FEAT_DUAL_BTGA = BIT(9) /* the future A-Die */
};
enum btc_wl_mode {
diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index 5dde620b1e5e..1e72c9b9f3b7 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -1451,6 +1451,12 @@ enum rtw89_btc_bt_rf_band {
BTC_BT_BMAX = 0x2
};
+enum rtw89_btc_io_offload_type {
+ BTC_IO_OFLD_NO_SUPPORT = 0,
+ BTC_IO_OFLD_MAC_API = 1,
+ BTC_IO_OFLD_BTC_H2C = 2
+};
+
enum rtw89_btc_bt_profile {
BTC_BT_NOPROFILE = 0,
BTC_BT_HFP = BIT(0),
@@ -1483,6 +1489,19 @@ struct rtw89_btc_ant_info_v7 {
u8 rsvd;
} __packed;
+struct rtw89_btc_ant_info_v10 {
+ u8 type; /* shared, dedicated(non-shared) */
+ u8 num; /* antenna count */
+ u8 isolation; /* Ant-Iso between WL/BT */
+ u8 single_pos; /* wifi 1ss-1ant at 0:S0 or 1:S1 */
+
+ u8 stream_cnt; /* spatial_stream count: Tx[7:4], Rx[3:0] */
+ u8 btg_pos; /* BT0 btg-circuit at 0:WL-S0/1:WL-S1 */
+ u8 btg1_pos; /* BT1 btg-circuit at 0:WL-S0/1:WL-S1 */
+ u8 func[5]; /* function at 1~5 Ant refer to enum btc_bt_func_type */
+ u8 ant_xmap[2][4];
+} __packed;
+
enum rtw89_tfc_dir {
RTW89_TFC_UL,
RTW89_TFC_DL,
@@ -2129,9 +2148,24 @@ struct rtw89_btc_module_v7 {
struct rtw89_btc_ant_info_v7 ant;
} __packed;
+struct rtw89_btc_module_v10 {
+ u8 rfe_type;
+ u8 wa_type; /* Refer to enum btc_wa_type */
+ u8 kt_ver;
+ u8 kt_ver_adie;
+
+ u8 bt0_pos; /* wl-end view: get from efuse, must compare bt.btg_type*/
+ u8 bt0_sw_type; /* BT Ant-switch: None(non-share), Int(BTG), Ext(SPDT)*/
+ u8 bt1_pos; /* BTC_BT_ALONE or BTC_BT_BTG */
+ u8 bt1_sw_type;
+
+ struct rtw89_btc_ant_info_v10 ant;
+} __packed;
+
union rtw89_btc_module_info {
struct rtw89_btc_module md;
struct rtw89_btc_module_v7 md_v7;
+ struct rtw89_btc_module_v10 md_v10;
};
#define RTW89_BTC_DM_MAXSTEP 30
@@ -2170,9 +2204,24 @@ struct rtw89_btc_init_info_v7 {
struct rtw89_btc_module_v7 module;
} __packed;
+struct rtw89_btc_init_info_v10 {
+ u8 endian_type; /* 0: little-endian, 1:big-endian */
+ u8 init_mode; /* refer to enum BTC_MODE_xxx */
+ u8 wl_init_ok;
+ u8 bt0_function;
+
+ u8 bt1_function;
+ u8 bt2_function;
+ u8 pta_mode;
+ u8 pta_direction;
+
+ struct rtw89_btc_module_v10 module;
+};
+
union rtw89_btc_init_info_u {
struct rtw89_btc_init_info init;
struct rtw89_btc_init_info_v7 init_v7;
+ struct rtw89_btc_init_info_v10 init_v10;
};
struct rtw89_btc_wl_tx_limit_para {
@@ -2253,6 +2302,7 @@ struct rtw89_btc_bt_info {
u8 raw_info[BTC_BTINFO_MAX]; /* raw bt info from mailbox */
u8 txpwr_info[BTC_BTINFO_MAX];
u8 rssi_level;
+ u8 func_type;
u32 scbd;
u32 feature;
@@ -3173,6 +3223,7 @@ struct rtw89_btc_dm {
u8 run_reason;
u8 run_action;
u8 wl_tx_pwr_phy_map;
+ u8 vid;
u8 wl_pre_agc: 2;
u8 wl_lna2: 1;
@@ -3203,7 +3254,7 @@ struct rtw89_btc_ctrl_v7 {
union rtw89_btc_ctrl_list {
struct rtw89_btc_ctrl ctrl;
- struct rtw89_btc_ctrl_v7 ctrl_v7;
+ struct rtw89_btc_ctrl_v7 ctrl_v7; /* ver 8, 9 is the same */
};
struct rtw89_btc_dbg {
@@ -3425,6 +3476,7 @@ struct rtw89_btc {
u8 policy[RTW89_BTC_POLICY_MAXLEN];
u8 ant_type;
u8 btg_pos;
+ u8 io_oflld_type;
u16 policy_len;
u16 policy_type;
u32 hubmsg_cnt;
diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c
index 9d98805835d6..b97c6e9c18bc 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.c
+++ b/drivers/net/wireless/realtek/rtw89/fw.c
@@ -5863,6 +5863,47 @@ int rtw89_fw_h2c_cxdrv_init_v7(struct rtw89_dev *rtwdev, u8 type)
return ret;
}
+int rtw89_fw_h2c_cxdrv_init_v10(struct rtw89_dev *rtwdev, u8 type)
+{
+ struct rtw89_btc *btc = &rtwdev->btc;
+ struct rtw89_btc_dm *dm = &btc->dm;
+ struct rtw89_btc_init_info_v10 *init_info = &dm->init_info.init_v10;
+ struct rtw89_h2c_cxinit_v10 *h2c;
+ u32 len = sizeof(*h2c);
+ struct sk_buff *skb;
+ int ret;
+
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
+ if (!skb) {
+ rtw89_err(rtwdev, "failed to alloc skb for h2c cxdrv_init_v10\n");
+ return -ENOMEM;
+ }
+ skb_put(skb, len);
+ h2c = (struct rtw89_h2c_cxinit_v10 *)skb->data;
+
+ h2c->hdr.type = type;
+ h2c->hdr.ver = btc->ver->fcxinit;
+ h2c->hdr.len = len - H2C_LEN_CXDRVHDR_V7;
+ h2c->init = *init_info;
+
+ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
+ H2C_CAT_OUTSRC, BTFC_SET,
+ SET_DRV_INFO, 0, 0,
+ len);
+
+ ret = rtw89_h2c_tx(rtwdev, skb, false);
+ if (ret) {
+ rtw89_err(rtwdev, "failed to send h2c\n");
+ goto fail;
+ }
+
+ return 0;
+fail:
+ dev_kfree_skb_any(skb);
+
+ return ret;
+}
+
#define PORT_DATA_OFFSET 4
#define H2C_LEN_CXDRVINFO_ROLE_DBCC_LEN 12
#define H2C_LEN_CXDRVINFO_ROLE_SIZE(max_role_num) \
diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h
index 71e8554a7af7..de8b77de8705 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.h
+++ b/drivers/net/wireless/realtek/rtw89/fw.h
@@ -2592,6 +2592,11 @@ struct rtw89_h2c_cxinit_v7 {
struct rtw89_btc_init_info_v7 init;
} __packed;
+struct rtw89_h2c_cxinit_v10 {
+ struct rtw89_h2c_cxhdr_v7 hdr;
+ struct rtw89_btc_init_info_v10 init;
+} __packed;
+
static inline void RTW89_SET_FWCMD_CXROLE_CONNECT_CNT(void *cmd, u8 val)
{
u8p_replace_bits((u8 *)(cmd) + 2, val, GENMASK(7, 0));
@@ -5380,6 +5385,7 @@ int rtw89_fw_h2c_tx_history(struct rtw89_dev *rtwdev, u16 mac_id);
int rtw89_fw_h2c_drv_ctrl_fw(struct rtw89_dev *rtwdev);
int rtw89_fw_h2c_cxdrv_init(struct rtw89_dev *rtwdev, u8 type);
int rtw89_fw_h2c_cxdrv_init_v7(struct rtw89_dev *rtwdev, u8 type);
+int rtw89_fw_h2c_cxdrv_init_v10(struct rtw89_dev *rtwdev, u8 type);
int rtw89_fw_h2c_cxdrv_role(struct rtw89_dev *rtwdev, u8 type);
int rtw89_fw_h2c_cxdrv_role_v1(struct rtw89_dev *rtwdev, u8 type);
int rtw89_fw_h2c_cxdrv_role_v2(struct rtw89_dev *rtwdev, u8 type);
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c
index 4caf231c6287..a1a63588cb90 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c
@@ -2277,8 +2277,6 @@ static void rtw8851b_btc_init_cfg(struct rtw89_dev *rtwdev)
/* enable BT counter 0xda40[16,2] = 2b'11 */
rtw89_write32_set(rtwdev, R_AX_CSR_MODE, B_AX_BT_CNT_RST | B_AX_STATIS_BT_EN);
-
- btc->cx.wl.status.map.init_ok = true;
}
static
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c
index 78addc0aef69..055c67a07cea 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c
@@ -1945,7 +1945,6 @@ static void rtw8852a_btc_init_cfg(struct rtw89_dev *rtwdev)
/* enable BT counter 0xda40[16,2] = 2b'11 */
rtw89_write32_set(rtwdev,
R_AX_CSR_MODE, B_AX_BT_CNT_RST | B_AX_STATIS_BT_EN);
- btc->cx.wl.status.map.init_ok = true;
}
static
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c b/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c
index df5fbae50ff5..7d409a64869f 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c
@@ -1838,7 +1838,6 @@ static void __rtw8852bx_btc_init_cfg(struct rtw89_dev *rtwdev)
/* enable BT counter 0xda40[16,2] = 2b'11 */
rtw89_write32_set(rtwdev, R_AX_CSR_MODE, B_AX_BT_CNT_RST | B_AX_STATIS_BT_EN);
- btc->cx.wl.status.map.init_ok = true;
}
static
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
index 29a3c90021f3..9e630b897986 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
@@ -2761,7 +2761,6 @@ static void rtw8852c_btc_init_cfg(struct rtw89_dev *rtwdev)
rtw89_write32_set(rtwdev,
R_AX_BT_CNT_CFG, B_AX_BT_CNT_EN |
B_AX_BT_CNT_RST_V1);
- btc->cx.wl.status.map.init_ok = true;
}
static
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c
index 6d4301661b04..382034eb27d0 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c
@@ -2828,7 +2828,6 @@ static void rtw8922a_btc_init_cfg(struct rtw89_dev *rtwdev)
rtw89_write32(rtwdev, R_BTC_ZB_COEX_TBL_1, 0xda5a5a5a);
rtw89_write32(rtwdev, R_BTC_ZB_BREAK_TBL, 0xf0ffffff);
- btc->cx.wl.status.map.init_ok = true;
}
static void
--
2.25.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH rtw-next 2/9] wifi: rtw89: coex: add rtw89_btc_init() entry for initialization once
2026-07-03 11:43 [PATCH rtw-next 0/9] wifi: rtw89: coex: implement components for dual Bluetooth Ping-Ke Shih
2026-07-03 11:43 ` [PATCH rtw-next 1/9] wifi: rtw89: coex: Add Init info version 10 Ping-Ke Shih
@ 2026-07-03 11:43 ` Ping-Ke Shih
2026-07-03 11:43 ` [PATCH rtw-next 3/9] wifi: rtw89: coex: Update TDMA descriptor for dual MAC Ping-Ke Shih
` (6 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Ping-Ke Shih @ 2026-07-03 11:43 UTC (permalink / raw)
To: linux-wireless; +Cc: ku920601
From: Ching-Te Ku <ku920601@realtek.com>
Separate these two type of initialize entry. Because Wi-Fi power save
leaving will also call the initializing, but don't have to reset all the
stored variables.
Signed-off-by: Ching-Te Ku <ku920601@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/coex.c | 35 ++++++++++++++---------
drivers/net/wireless/realtek/rtw89/coex.h | 1 +
drivers/net/wireless/realtek/rtw89/core.c | 1 +
3 files changed, 24 insertions(+), 13 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c
index 43de238c18f8..196bec751070 100644
--- a/drivers/net/wireless/realtek/rtw89/coex.c
+++ b/drivers/net/wireless/realtek/rtw89/coex.c
@@ -7858,6 +7858,28 @@ void _run_coex(struct rtw89_dev *rtwdev, enum btc_reason_and_action reason)
_action_common(rtwdev);
}
+void rtw89_btc_init(struct rtw89_dev *rtwdev)
+{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ struct rtw89_btc *btc = &rtwdev->btc;
+ struct rtw89_btc_wl_info *wl = &btc->cx.wl;
+ const struct rtw89_btc_ver *ver = btc->ver;
+
+ rtw89_debug(rtwdev, RTW89_DBG_BTC,
+ "[BTC], %s(): Init %s !!\n", __func__,
+ chip_id_str(chip->chip_id));
+
+ _reset_btc_var(rtwdev, BTC_RESET_ALL);
+
+ btc->dm.run_reason = BTC_RSN_NONE;
+ btc->dm.run_action = BTC_ACT_NONE;
+ if (ver->fcxctrl >= 7)
+ btc->ctrl.ctrl_v7.igno_bt = true;
+ else
+ btc->ctrl.ctrl.igno_bt = true;
+ wl->status.map.init_ok = true;
+}
+
void rtw89_btc_ntfy_poweron(struct rtw89_dev *rtwdev)
{
struct rtw89_btc *btc = &rtwdev->btc;
@@ -7941,19 +7963,6 @@ void rtw89_btc_ntfy_init(struct rtw89_dev *rtwdev, u8 mode)
const struct rtw89_chip_info *chip = rtwdev->chip;
const struct rtw89_btc_ver *ver = btc->ver;
- rtw89_debug(rtwdev, RTW89_DBG_BTC,
- "[BTC], %s(): Init %s !!\n", __func__,
- chip_id_str(chip->chip_id));
-
- _reset_btc_var(rtwdev, BTC_RESET_ALL);
- btc->dm.run_reason = BTC_RSN_NONE;
- btc->dm.run_action = BTC_ACT_NONE;
- if (ver->fcxctrl >= 7)
- btc->ctrl.ctrl_v7.igno_bt = true;
- else
- btc->ctrl.ctrl.igno_bt = true;
- wl->status.map.init_ok = true;
-
rtw89_debug(rtwdev, RTW89_DBG_BTC,
"[BTC], %s(): mode=%d\n", __func__, mode);
diff --git a/drivers/net/wireless/realtek/rtw89/coex.h b/drivers/net/wireless/realtek/rtw89/coex.h
index 259c6e2c0e3c..fb151f68eb64 100644
--- a/drivers/net/wireless/realtek/rtw89/coex.h
+++ b/drivers/net/wireless/realtek/rtw89/coex.h
@@ -272,6 +272,7 @@ enum btc_wl_gpio_debug {
BTC_DBG_USER_DEF = 31,
};
+void rtw89_btc_init(struct rtw89_dev *rtwdev);
void rtw89_btc_ntfy_poweron(struct rtw89_dev *rtwdev);
void rtw89_btc_ntfy_poweroff(struct rtw89_dev *rtwdev);
void rtw89_btc_ntfy_init(struct rtw89_dev *rtwdev, u8 mode);
diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c
index 26b744dfbcf8..85aeb9e90812 100644
--- a/drivers/net/wireless/realtek/rtw89/core.c
+++ b/drivers/net/wireless/realtek/rtw89/core.c
@@ -7488,6 +7488,7 @@ static int rtw89_core_register_hw(struct rtw89_dev *rtwdev)
}
rtw89_rfkill_polling_init(rtwdev);
+ rtw89_btc_init(rtwdev);
return 0;
--
2.25.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH rtw-next 3/9] wifi: rtw89: coex: Update TDMA descriptor for dual MAC
2026-07-03 11:43 [PATCH rtw-next 0/9] wifi: rtw89: coex: implement components for dual Bluetooth Ping-Ke Shih
2026-07-03 11:43 ` [PATCH rtw-next 1/9] wifi: rtw89: coex: Add Init info version 10 Ping-Ke Shih
2026-07-03 11:43 ` [PATCH rtw-next 2/9] wifi: rtw89: coex: add rtw89_btc_init() entry for initialization once Ping-Ke Shih
@ 2026-07-03 11:43 ` Ping-Ke Shih
2026-07-03 11:43 ` [PATCH rtw-next 4/9] wifi: rtw89: coex: Add Bluetooth binding for Bluetooth TX power setting Ping-Ke Shih
` (5 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Ping-Ke Shih @ 2026-07-03 11:43 UTC (permalink / raw)
To: linux-wireless; +Cc: ku920601
From: Ching-Te Ku <ku920601@realtek.com>
The mechanism needs information to know which MAC is coexisting with which
Bluetooth and when to enable TDMA with which MAC. So change an variable to
describe the binding target.
Signed-off-by: Ching-Te Ku <ku920601@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/coex.c | 15 ++++++++-------
drivers/net/wireless/realtek/rtw89/core.h | 4 ++--
2 files changed, 10 insertions(+), 9 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c
index 196bec751070..14cc62cf399d 100644
--- a/drivers/net/wireless/realtek/rtw89/coex.c
+++ b/drivers/net/wireless/realtek/rtw89/coex.c
@@ -2288,9 +2288,9 @@ static void _append_tdma(struct rtw89_dev *rtwdev)
}
rtw89_debug(rtwdev, RTW89_DBG_BTC,
- "[BTC], %s(): type:%d, rxflctrl=%d, txpause=%d, wtgle_n=%d, leak_n=%d, ext_ctrl=%d\n",
+ "[BTC], %s(): type:%d, rxflctrl=%d, txflctrl=%d, bind=%d, leak_n=%d, ext_ctrl=%d\n",
__func__, dm->tdma.type, dm->tdma.rxflctrl,
- dm->tdma.txpause, dm->tdma.wtgle_n, dm->tdma.leak_n,
+ dm->tdma.txflctrl, dm->tdma.bind, dm->tdma.leak_n,
dm->tdma.ext_ctrl);
}
@@ -3733,7 +3733,8 @@ static bool _check_freerun(struct rtw89_dev *rtwdev)
#define _tdma_set_flctrl(btc, flc) ({(btc)->dm.tdma.rxflctrl = flc; })
#define _tdma_set_flctrl_role(btc, role) ({(btc)->dm.tdma.rxflctrl_role = role; })
-#define _tdma_set_tog(btc, wtg) ({(btc)->dm.tdma.wtgle_n = wtg; })
+#define _tdma_set_rxflctrl(btc, rxflc) ({(btc)->dm.tdma.rxflctrl = rxflc; })
+#define _tdma_set_txflctrl(btc, txflc) ({(btc)->dm.tdma.txflctrl = txflc; })
#define _tdma_set_lek(btc, lek) ({(btc)->dm.tdma.leak_n = lek; })
struct btc_btinfo_lb2 {
@@ -9967,13 +9968,13 @@ static int _show_fbtc_tdma(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
p += scnprintf(p, end - p,
" %-15s : ", "[tdma_policy]");
p += scnprintf(p, end - p,
- "type:%d, rx_flow_ctrl:%d, tx_pause:%d, ",
+ "type:%d, rx_flow_ctrl:%d, txflctrl:%d, ",
(u32)t->type,
- t->rxflctrl, t->txpause);
+ t->rxflctrl, t->txflctrl);
p += scnprintf(p, end - p,
- "wl_toggle_n:%d, leak_n:%d, ext_ctrl:%d, ",
- t->wtgle_n, t->leak_n, t->ext_ctrl);
+ "bind:%d, leak_n:%d, ext_ctrl:%d, ",
+ t->bind, t->leak_n, t->ext_ctrl);
p += scnprintf(p, end - p,
"policy_type:%d",
diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index 1e72c9b9f3b7..a0f6929873ab 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -2354,8 +2354,8 @@ struct rtw89_btc_cx {
struct rtw89_btc_fbtc_tdma {
u8 type; /* btc_ver::fcxtdma */
u8 rxflctrl;
- u8 txpause;
- u8 wtgle_n;
+ u8 txflctrl;
+ u8 bind;
u8 leak_n;
u8 ext_ctrl;
u8 rxflctrl_role;
--
2.25.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH rtw-next 4/9] wifi: rtw89: coex: Add Bluetooth binding for Bluetooth TX power setting
2026-07-03 11:43 [PATCH rtw-next 0/9] wifi: rtw89: coex: implement components for dual Bluetooth Ping-Ke Shih
` (2 preceding siblings ...)
2026-07-03 11:43 ` [PATCH rtw-next 3/9] wifi: rtw89: coex: Update TDMA descriptor for dual MAC Ping-Ke Shih
@ 2026-07-03 11:43 ` Ping-Ke Shih
2026-07-03 11:43 ` [PATCH rtw-next 5/9] wifi: rtw89: coex: Add Bluetooth binding for Bluetooth RX gain setting Ping-Ke Shih
` (4 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Ping-Ke Shih @ 2026-07-03 11:43 UTC (permalink / raw)
To: linux-wireless; +Cc: ku920601
From: Ching-Te Ku <ku920601@realtek.com>
Dual Bluetooth the each of Bluetooth may use different TX power by their
condition.
Signed-off-by: Ching-Te Ku <ku920601@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/coex.c | 65 ++++++++++++++++++-----
drivers/net/wireless/realtek/rtw89/core.h | 15 ++++--
drivers/net/wireless/realtek/rtw89/fw.h | 3 ++
3 files changed, 67 insertions(+), 16 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c
index 14cc62cf399d..2080253559a7 100644
--- a/drivers/net/wireless/realtek/rtw89/coex.c
+++ b/drivers/net/wireless/realtek/rtw89/coex.c
@@ -3078,6 +3078,7 @@ static void _set_bt_ignore_wlan_act(struct rtw89_dev *rtwdev, u8 enable)
#define WL_TX_POWER_FRA_PART GENMASK(1, 0)
#define B_BTC_WL_TX_POWER_SIGN BIT(7)
#define B_TSSI_WL_TX_POWER_SIGN BIT(8)
+#define SET_RF_PARA_AX_LEN 1
static void _set_wl_tx_power(struct rtw89_dev *rtwdev, u32 level, u8 phy_map)
{
@@ -3161,28 +3162,64 @@ static void _set_wl_rx_gain(struct rtw89_dev *rtwdev, u32 level, u8 phy_map)
chip->ops->btc_set_wl_rx_gain(rtwdev, level);
}
-static void _set_bt_tx_power(struct rtw89_dev *rtwdev, u8 level)
+static void _set_bt_tx_power(struct rtw89_dev *rtwdev, bool force_exec, u8 bid,
+ u8 rf_band, u8 level)
{
struct rtw89_btc *btc = &rtwdev->btc;
struct rtw89_btc_bt_info *bt = &btc->cx.bt0;
- int ret;
- u8 buf;
+ u8 h2c_func = SET_BT_TX_PWR;
+ u8 i, id_start, id_stop;
+ u8 buf[2] = {};
+ u8 len = sizeof(*buf);
- if (bt->bcnt[BTC_BCNT_INFOUPDATE] == 0)
+ if (bt->bcnt[BTC_BCNT_INFOUPDATE] == 0 || !rf_band)
return;
if (bt->rf_para.tx_pwr_freerun == level)
return;
- rtw89_debug(rtwdev, RTW89_DBG_BTC,
- "[BTC], %s(): level = %d\n",
- __func__, level);
+ if (bid == BTC_ALL_BT) {
+ id_start = BTC_BT_1ST;
+ id_stop = BTC_BT_2ND;
+ } else {
+ id_start = bid;
+ id_stop = bid;
+ }
- buf = (s8)(-level);
- ret = _send_fw_cmd(rtwdev, BTFC_SET, SET_BT_TX_PWR, &buf, 1);
- if (!ret) {
- bt->rf_para.tx_pwr_freerun = level;
- btc->dm.rf_trx_para.bt_tx_power[BTC_BT_1ST] = level;
+ for (i = id_start; i <= id_stop; i++) {
+ if (i == BTC_BT_2ND) {
+ if (!(rtwdev->chip->para_ver & BTC_FEAT_DUAL_BT))
+ continue;
+
+ bt = &btc->cx.bt1;
+ h2c_func |= BT_H2C_FUNC_BT2ND;
+ }
+
+ buf[0] = (s8)(-level);
+ buf[1] = rf_band; /* bit-map: bit1->5GHz/6Ghz, bit0->2.4GHz */
+
+ if (!force_exec && !btc->cli_h2c_cmd) {
+ if (rf_band == RTW89_BAND_2G &&
+ bt->tx_power_now == level)
+ continue;
+ else if (rf_band != RTW89_BAND_2G &&
+ bt->tx_power_now_6g == level)
+ continue;
+ }
+
+ if (rtwdev->chip->chip_gen == RTW89_CHIP_AX)
+ len = SET_RF_PARA_AX_LEN;
+
+ if (_send_fw_cmd(rtwdev, BTFC_SET, h2c_func, buf, len)) {
+ btc->dm.rf_trx_para.bt_tx_power[i] = level;
+ if (rf_band == RTW89_BAND_2G)
+ bt->tx_power_now = level;
+ else
+ bt->tx_power_now_6g = level;
+ rtw89_debug(rtwdev, RTW89_DBG_BTC,
+ "[BTC], %s(): bt%d_tx_power_level = %d\n",
+ __func__, i, level);
+ }
}
}
@@ -3229,6 +3266,8 @@ static void _set_rf_trx_para(struct rtw89_dev *rtwdev)
struct rtw89_btc_rf_trx_para_v9 para;
u8 lv, link_mode = 0, i, dbcc_2g_phy = 0;
u8 ul_para_num, dl_para_num;
+ u8 rf_band = RTW89_BAND_2G;
+ u8 bid = BTC_BT_1ST;
u32 wl_stb_chg = 0;
if (ver->fwlrole == 0) {
@@ -3321,7 +3360,7 @@ static void _set_rf_trx_para(struct rtw89_dev *rtwdev)
} else {
_set_wl_tx_power(rtwdev, para.wl_tx_power[RTW89_PHY_0], RTW89_PHY_0);
_set_wl_rx_gain(rtwdev, para.wl_rx_gain[RTW89_PHY_0], RTW89_PHY_0);
- _set_bt_tx_power(rtwdev, para.bt_tx_power[BTC_BT_1ST]);
+ _set_bt_tx_power(rtwdev, true, bid, rf_band, para.bt_tx_power[BTC_BT_1ST]);
_set_bt_rx_gain(rtwdev, para.bt_rx_gain[BTC_BT_1ST]);
}
diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index a0f6929873ab..3f77707e2733 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -2302,7 +2302,18 @@ struct rtw89_btc_bt_info {
u8 raw_info[BTC_BTINFO_MAX]; /* raw bt info from mailbox */
u8 txpwr_info[BTC_BTINFO_MAX];
u8 rssi_level;
+ u8 rf_band_map;
u8 func_type;
+ u8 tx_power_now;
+ u8 tx_power_now_6g;
+
+ u8 fw_ver_mismatch: 1;
+ u8 band_56G_support: 1;
+ u8 hi_lna_rx: 1;
+ u8 lna_constrain: 3;
+ u8 hi_lna_rx_6g: 1;
+ u8 lna_constrain_6g: 3;
+ u8 rsvd: 6;
u32 scbd;
u32 feature;
@@ -2316,11 +2327,9 @@ struct rtw89_btc_bt_info {
u32 inq: 1;
u32 pag: 1;
u32 run_patch_code: 1;
- u32 hi_lna_rx: 1;
u32 scan_rx_low_pri: 1;
u32 scan_info_update: 1;
- u32 lna_constrain: 3;
- u32 rsvd: 17;
+ u32 rsvd1: 22;
u32 bcnt[BTC_BCNT_NUM];
};
diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h
index de8b77de8705..a6f3b28b9e33 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.h
+++ b/drivers/net/wireless/realtek/rtw89/fw.h
@@ -2337,6 +2337,9 @@ struct rtw89_h2c_arp_offload {
#define RTW89_H2C_ARP_OFFLOAD_W0_PKT_ID GENMASK(31, 24)
#define RTW89_H2C_ARP_OFFLOAD_W1_CONTENT GENMASK(31, 0)
+#define BT_H2C_FUNC_BT2ND 0x80
+#define BT_C2H_FUNC_BT2ND 0x80
+
enum rtw89_btc_btf_h2c_class {
BTFC_SET = 0x10,
BTFC_GET = 0x11,
--
2.25.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH rtw-next 5/9] wifi: rtw89: coex: Add Bluetooth binding for Bluetooth RX gain setting
2026-07-03 11:43 [PATCH rtw-next 0/9] wifi: rtw89: coex: implement components for dual Bluetooth Ping-Ke Shih
` (3 preceding siblings ...)
2026-07-03 11:43 ` [PATCH rtw-next 4/9] wifi: rtw89: coex: Add Bluetooth binding for Bluetooth TX power setting Ping-Ke Shih
@ 2026-07-03 11:43 ` Ping-Ke Shih
2026-07-03 11:43 ` [PATCH rtw-next 6/9] wifi: rtw89: coex: Add WiFi/Bluetooth adapter binding info Ping-Ke Shih
` (3 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Ping-Ke Shih @ 2026-07-03 11:43 UTC (permalink / raw)
To: linux-wireless; +Cc: ku920601
From: Ching-Te Ku <ku920601@realtek.com>
Dual Bluetooth the each of Bluetooth may use different RX gain by their
condition.
Signed-off-by: Ching-Te Ku <ku920601@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/coex.c | 86 ++++++++++++++++++-----
1 file changed, 68 insertions(+), 18 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c
index 2080253559a7..ff3c05101ab3 100644
--- a/drivers/net/wireless/realtek/rtw89/coex.c
+++ b/drivers/net/wireless/realtek/rtw89/coex.c
@@ -730,6 +730,7 @@ enum btc_w2b_scoreboard {
BTC_WSCB_SCAN = BIT(2),
BTC_WSCB_UNDERTEST = BIT(3),
BTC_WSCB_RXGAIN = BIT(4),
+ BTC_WSCB_5GHICH = BIT(6),
BTC_WSCB_WLBUSY = BIT(7),
BTC_WSCB_EXTFEM = BIT(8),
BTC_WSCB_TDMA = BIT(9),
@@ -738,6 +739,9 @@ enum btc_w2b_scoreboard {
BTC_WSCB_RXSCAN_PRI = BIT(12),
BTC_WSCB_BT_HILNA = BIT(13),
BTC_WSCB_BTLOG = BIT(14),
+ BTC_WSCB_CTCODE = BIT(15),
+ BTC_WSCB_RXGAIN_56G = BIT(16),
+ BTC_WSCB_BT_HILNA_56G = BIT(17),
BTC_WSCB_ALL = GENMASK(23, 0),
};
@@ -3224,33 +3228,79 @@ static void _set_bt_tx_power(struct rtw89_dev *rtwdev, bool force_exec, u8 bid,
}
#define BTC_BT_RX_NORMAL_LVL 7
-
-static void _set_bt_rx_gain(struct rtw89_dev *rtwdev, u8 level)
+static void _set_bt_rx_gain(struct rtw89_dev *rtwdev, bool force_exec, u8 bid,
+ u8 rf_band, u8 level)
{
struct rtw89_btc *btc = &rtwdev->btc;
- struct rtw89_btc_bt_info *bt = &btc->cx.bt0;
+ struct rtw89_btc_cx *cx = &btc->cx;
+ struct rtw89_btc_bt_info *bt = &cx->bt0;
+ u8 h2c_func = SET_BT_LNA_CONSTRAIN;
+ u8 i, id_start, id_stop;
+ bool state = false;
+ u32 scbd_bit = 0;
+ u8 buf[2] = {};
+ u8 len = sizeof(*buf);
- if (bt->bcnt[BTC_BCNT_INFOUPDATE] == 0)
+ if (bt->bcnt[BTC_BCNT_INFOUPDATE] == 0 || !rf_band)
return;
- if ((bt->rf_para.rx_gain_freerun == level ||
- level > BTC_BT_RX_NORMAL_LVL) &&
- (!rtwdev->chip->scbd || bt->lna_constrain == level))
+ if (bt->rf_para.rx_gain_freerun == level ||
+ level > BTC_BT_RX_NORMAL_LVL || !rtwdev->chip->scbd ||
+ bid > BTC_ALL_BT)
return;
- bt->rf_para.rx_gain_freerun = level;
- btc->dm.rf_trx_para.bt_rx_gain[BTC_BT_1ST] = level;
-
- rtw89_debug(rtwdev, RTW89_DBG_BTC,
- "[BTC], %s(): level = %d\n",
- __func__, level);
+ if (bid == BTC_ALL_BT) {
+ id_start = BTC_BT_1ST;
+ id_stop = BTC_BT_2ND;
+ } else {
+ id_start = bid;
+ id_stop = bid;
+ }
- if (level == BTC_BT_RX_NORMAL_LVL)
- _write_scbd(rtwdev, BTC_WSCB_RXGAIN, false);
+ if (rf_band == RTW89_BAND_2G)
+ scbd_bit |= BTC_WSCB_RXGAIN;
else
- _write_scbd(rtwdev, BTC_WSCB_RXGAIN, true);
+ scbd_bit |= BTC_WSCB_RXGAIN_56G;
+
+ for (i = id_start; i <= id_stop; i++) {
+ if (i == BTC_BT_2ND) {
+ if (!(rtwdev->chip->para_ver & BTC_FEAT_DUAL_BT))
+ continue;
+
+ bt = &cx->bt1;
+ h2c_func |= BT_H2C_FUNC_BT2ND;
+ }
+
+ /* return if same setup */
+ if (!force_exec && !btc->cli_h2c_cmd) {
+ if (rf_band == RTW89_BAND_2G &&
+ bt->lna_constrain == level)
+ continue;
+ else if (rf_band != RTW89_BAND_2G &&
+ bt->lna_constrain_6g == level)
+ continue;
+ }
+
+ buf[0] = level;
+ buf[1] = rf_band;
+
+ if (rtwdev->chip->chip_gen == RTW89_CHIP_AX)
+ len = SET_RF_PARA_AX_LEN;
+
+ if (_send_fw_cmd(rtwdev, BTFC_SET, h2c_func, buf, len)) {
+ rtw89_debug(rtwdev, RTW89_DBG_BTC,
+ "[BTC], %s(): bt%d_rx_gain_level = %d\n",
+ __func__, i, level);
+ }
+
+ btc->dm.rf_trx_para.bt_rx_gain[i] = level;
+
+ if (buf[0] != BTC_BT_RX_NORMAL_LVL)
+ state = true;
+
+ _write_scbd(rtwdev, scbd_bit, state);
+ }
- _send_fw_cmd(rtwdev, BTFC_SET, SET_BT_LNA_CONSTRAIN, &level, sizeof(level));
}
static void _set_rf_trx_para(struct rtw89_dev *rtwdev)
@@ -3361,7 +3411,7 @@ static void _set_rf_trx_para(struct rtw89_dev *rtwdev)
_set_wl_tx_power(rtwdev, para.wl_tx_power[RTW89_PHY_0], RTW89_PHY_0);
_set_wl_rx_gain(rtwdev, para.wl_rx_gain[RTW89_PHY_0], RTW89_PHY_0);
_set_bt_tx_power(rtwdev, true, bid, rf_band, para.bt_tx_power[BTC_BT_1ST]);
- _set_bt_rx_gain(rtwdev, para.bt_rx_gain[BTC_BT_1ST]);
+ _set_bt_rx_gain(rtwdev, true, bid, rf_band, para.bt_rx_gain[BTC_BT_1ST]);
}
next:
--
2.25.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH rtw-next 6/9] wifi: rtw89: coex: Add WiFi/Bluetooth adapter binding info
2026-07-03 11:43 [PATCH rtw-next 0/9] wifi: rtw89: coex: implement components for dual Bluetooth Ping-Ke Shih
` (4 preceding siblings ...)
2026-07-03 11:43 ` [PATCH rtw-next 5/9] wifi: rtw89: coex: Add Bluetooth binding for Bluetooth RX gain setting Ping-Ke Shih
@ 2026-07-03 11:43 ` Ping-Ke Shih
2026-07-03 11:43 ` [PATCH rtw-next 7/9] wifi: rtw89: coex: Add TDMA binding for dual MAC Ping-Ke Shih
` (2 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Ping-Ke Shih @ 2026-07-03 11:43 UTC (permalink / raw)
To: linux-wireless; +Cc: ku920601
From: Ching-Te Ku <ku920601@realtek.com>
To bind Wi-Fi/Bluetooth with which adapter, in which band.
Signed-off-by: Ching-Te Ku <ku920601@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/coex.c | 309 ++++++++++++++++++++--
drivers/net/wireless/realtek/rtw89/core.h | 121 ++++++++-
2 files changed, 396 insertions(+), 34 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c
index ff3c05101ab3..435a4a5d2c2d 100644
--- a/drivers/net/wireless/realtek/rtw89/coex.c
+++ b/drivers/net/wireless/realtek/rtw89/coex.c
@@ -3349,7 +3349,7 @@ static void _set_rf_trx_para(struct rtw89_dev *rtwdev)
/* decide trx_para_level */
if (btc->ant_type == BTC_ANT_SHARED) {
/* fix LNA2 + TIA gain not change by GNT_BT */
- if ((btc->dm.wl_btg_rx && b->profile_cnt.now != 0) ||
+ if ((btc->dm.wl_btg_rx && b->link_cnt.now != 0) ||
dm->bt_only == 1)
dm->trx_para_level = 1; /* for better BT ACI issue */
else
@@ -3357,7 +3357,7 @@ static void _set_rf_trx_para(struct rtw89_dev *rtwdev)
} else { /* non-shared antenna */
dm->trx_para_level = 5;
/* modify trx_para if WK 2.4G-STA-DL + bt link */
- if (b->profile_cnt.now != 0 &&
+ if (b->link_cnt.now != 0 &&
link_mode == BTC_WLINK_2G_STA &&
wl->status.map.traffic_dir & BIT(RTW89_TFC_UL)) { /* uplink */
if (wl->rssi_level == 4 && bt->rssi_level > 2)
@@ -3606,7 +3606,7 @@ static void _set_bt_afh_info_v0(struct rtw89_dev *rtwdev)
if (wl->afh_info.en == en &&
wl->afh_info.ch == ch &&
wl->afh_info.bw == bw &&
- b->profile_cnt.last == b->profile_cnt.now) {
+ b->link_cnt.last == b->link_cnt.now) {
rtw89_debug(rtwdev, RTW89_DBG_BTC,
"[BTC], %s(): return because no change!\n",
__func__);
@@ -3777,7 +3777,7 @@ static bool _check_freerun(struct rtw89_dev *rtwdev)
return true;
}
- if (bt_linfo->profile_cnt.now == 0) {
+ if (bt_linfo->link_cnt.now == 0) {
btc->dm.trx_para_level = 5;
return true;
}
@@ -5497,7 +5497,7 @@ static void _set_wl_preagc_ctrl(struct rtw89_dev *rtwdev)
} else if (link_mode == BTC_WLINK_5G) {
is_preagc = BTC_PREAGC_DISABLE;
} else if (link_mode == BTC_WLINK_NOLINK ||
- btc->cx.bt0.link_info.profile_cnt.now == 0) {
+ btc->cx.bt0.link_info.link_cnt.now == 0) {
is_preagc = BTC_PREAGC_DISABLE;
} else if (dm->tdma_now.type != CXTDMA_OFF &&
!bt_linfo->hfp_desc.exist &&
@@ -5683,7 +5683,7 @@ static void _set_wl_tx_limit(struct rtw89_dev *rtwdev)
else
igno_bt = btc->ctrl.ctrl.igno_bt;
- if (btc->dm.freerun || igno_bt || b->profile_cnt.now == 0 ||
+ if (btc->dm.freerun || igno_bt || b->link_cnt.now == 0 ||
mode == BTC_WLINK_5G || mode == BTC_WLINK_NOLINK) {
enable = 0;
tx_time = BTC_MAX_TX_TIME_DEF;
@@ -6003,7 +6003,7 @@ static void _action_wl_2g_mcc(struct rtw89_dev *rtwdev)
_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
if (btc->ant_type == BTC_ANT_SHARED) { /* shared-antenna */
- if (btc->cx.bt0.link_info.profile_cnt.now == 0)
+ if (btc->cx.bt0.link_info.link_cnt.now == 0)
_set_policy(rtwdev, BTC_CXP_OFFE_DEF2,
BTC_ACT_WL_2G_MCC);
else
@@ -6021,7 +6021,7 @@ static void _action_wl_2g_scc(struct rtw89_dev *rtwdev)
_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
if (btc->ant_type == BTC_ANT_SHARED) { /* shared-antenna */
- if (btc->cx.bt0.link_info.profile_cnt.now == 0)
+ if (btc->cx.bt0.link_info.link_cnt.now == 0)
_set_policy(rtwdev,
BTC_CXP_OFFE_DEF2, BTC_ACT_WL_2G_SCC);
else
@@ -6199,7 +6199,7 @@ static void _action_wl_2g_ap(struct rtw89_dev *rtwdev)
_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
if (btc->ant_type == BTC_ANT_SHARED) {
- if (btc->cx.bt0.link_info.profile_cnt.now == 0)
+ if (btc->cx.bt0.link_info.link_cnt.now == 0)
_set_policy(rtwdev, BTC_CXP_OFFE_DEF2,
BTC_ACT_WL_2G_AP);
else
@@ -6216,7 +6216,7 @@ static void _action_wl_2g_go(struct rtw89_dev *rtwdev)
_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
if (btc->ant_type == BTC_ANT_SHARED) { /* shared-antenna */
- if (btc->cx.bt0.link_info.profile_cnt.now == 0)
+ if (btc->cx.bt0.link_info.link_cnt.now == 0)
_set_policy(rtwdev,
BTC_CXP_OFFE_DEF2, BTC_ACT_WL_2G_GO);
else
@@ -6247,7 +6247,7 @@ static void _action_wl_2g_nan(struct rtw89_dev *rtwdev)
_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
if (btc->ant_type == BTC_ANT_SHARED) { /* shared-antenna */
- if (btc->cx.bt0.link_info.profile_cnt.now == 0)
+ if (btc->cx.bt0.link_info.link_cnt.now == 0)
_set_policy(rtwdev,
BTC_CXP_OFFE_DEF2, BTC_ACT_WL_2G_NAN);
else
@@ -7742,6 +7742,273 @@ static bool _chk_wl_rfk_request(struct rtw89_dev *rtwdev)
return false;
}
+static void _set_bind_info(struct rtw89_btc *btc, u8 type)
+{
+ struct rtw89_btc_cx *cx = &btc->cx;
+ struct rtw89_btc_dm *dm = &btc->dm;
+ struct rtw89_btc_wl_info *wl = &cx->wl;
+ struct rtw89_btc_bt_info *bt = &cx->bt0;
+ struct rtw89_btc_bt_link_info *b;
+ struct rtw89_btc_bind_info *bd;
+ u8 path_hwb[BTC_RF_NUM] = {RTW89_PHY_0, RTW89_PHY_1};
+ u8 link_weight[BTC_ALL_BT_EZL][BTC_BT_BMAX];
+ u8 map[BTC_RF_NUM][BTC_ALL_BT_EZL];
+ u8 b2g_score = 0, b5g_score = 0;
+ u8 i, j, rf_band_map, thres;
+ u8 weight[BTC_BT_BMAX] = {};
+
+ if (type == BTC_MECH_TDD) {
+ bd = &dm->tdd_bind;
+ memcpy(map, dm->tdd_map, sizeof(map));
+ thres = 30; /* BT profile score threshold for TDMA */
+ } else {
+ bd = &dm->fdd_bind;
+ memcpy(map, dm->fdd_map, sizeof(map));
+ thres = 5;
+ }
+
+ memset(bd, 0, sizeof(*bd));
+ /* compare BT 2GHz/5GHz profile by link-weighting */
+ for (i = 0; i < BTC_BT_BMAX; i++) {
+ link_weight[BTC_BT_1ST][i] = cx->bt0.link_weight[i];
+ link_weight[BTC_BT_2ND][i] = cx->bt1.link_weight[i];
+ link_weight[BTC_BT_EXT][i] = cx->bt_ext.link_weight[i];
+ }
+
+ /*
+ * get 2GHz/5GHz link weight score by "band-overlap" map
+ * link_weight from _update_bt_link_cnt(),
+ * if link_weight >30 --> TDMA-required
+ */
+ for (j = 0; j < BTC_ALL_BT_EZL; j++) {
+ rf_band_map = map[BTC_RF_S0][j] | map[BTC_RF_S1][j];
+ if (rf_band_map & BIT(RTW89_BAND_2G))
+ b2g_score += link_weight[j][BTC_BT_B2G];
+ if (rf_band_map & BIT(RTW89_BAND_5G))
+ b5g_score += link_weight[j][BTC_BT_B5G];
+ }
+
+ /* rf-band bound by comparing link weight */
+ if (b2g_score == 0 && b5g_score == 0) /* no-rf-band overlap */
+ bd->rf_band = 0;
+ else if (b5g_score > b2g_score)
+ bd->rf_band = BIT(BTC_BT_B5G);
+ else
+ bd->rf_band = BIT(BTC_BT_B2G);
+
+ /*
+ * if MR_WTYPE_MLD2L1R_NONMLD, FW will change 2+0/0+2/1+1
+ * Therefore, BTC_MLO_RF_xxx is not real-time state.
+ * In this case, RF_S0->HWB0, RF_S1->HWB1
+ * If link-mode change by _ntfy_generic(BTC_GNTFY_MRCX_INFO)
+ * HW-Band is decided by wl->mlo_info.mrcx_act_hwb_map
+ */
+ if (wl->mlo_info.wtype == RTW89_MR_WTYPE_MLD2L1R_NONMLD) {
+ /* TODO: Should patched WiFi mode & WiFi role patch */
+ } else {
+ /*
+ * Dual-RF_band(HWB)TDMA if BT-profile is TDMA-type at both
+ * 2GHz and 5GHz.
+ * ex: 1+1: HWB0 5GHz + BT0 5GHz (BIS, HDT)
+ * && HWB1 2.4GHz + BT1 2.4GHz(PAN)
+ * for TDD: the link score must > 30 (from _bt_link_cnt)
+ * for FDD: the link score must > 5 (bt enable)
+ */
+ if ((wl->mlo_info.rf_combination == BTC_MLO_RF_1_PLUS_1 ||
+ wl->mlo_info.rf_combination == BTC_MLO_RF_2_PLUS_2) &&
+ (b2g_score >= thres && b5g_score >= thres)) {
+ bd->rf_band = BIT(BTC_BT_B2G) | BIT(BTC_BT_B5G);
+ }
+
+ if (wl->mlo_info.rf_combination == BTC_MLO_RF_2_PLUS_0)
+ path_hwb[BTC_RF_S1] = RTW89_PHY_0; /* 2+0 RF-S0/1->HWB0 */
+ else if (wl->mlo_info.rf_combination == BTC_MLO_RF_0_PLUS_2)
+ path_hwb[BTC_RF_S0] = RTW89_PHY_1; /* 2+0 RF-S0/1->HWB1 */
+ }
+
+ /* Get HWB-sel and BT-sel by rf-band-binding */
+ for (i = 0; i < BTC_RF_NUM; i++) {
+ for (j = 0; j < BTC_ALL_BT_EZL; j++) {
+ if (!(map[i][j] & bd->rf_band)) /* no-overlap */
+ continue;
+
+ bd->wl_hwb_sel |= BIT(path_hwb[i]);
+ bd->bt_sel |= BIT(j);
+ }
+ }
+
+ /* TODO: Should patched WiFi mode & WiFi role patch */
+
+ /* update Bind-BT status map for BT0/BT1 */
+ for (i = BTC_BT_1ST; i < BTC_ALL_BT_EZL; i++) {
+ if (!(bd->bt_sel & BIT(i)))
+ continue;
+
+ for (j = BTC_BT_B2G; j <= BTC_BT_B5G; j++) {
+ if (!(bd->rf_band & BIT(j)))
+ continue;
+
+ if (i == BTC_BT_EXT) {
+ bd->bt_profile |= cx->bt_ext.profile_map[j];
+ weight[j] = cx->bt_ext.link_weight[j];
+ if (weight[j] > bd->bt_link_weight) /* max */
+ bd->bt_link_weight = weight[j];
+ continue;
+ } else if (i == BTC_BT_1ST) {
+ bt = &cx->bt0;
+ } else {
+ bt = &cx->bt1;
+ }
+
+ if (j == BTC_BT_B2G)
+ b = &bt->link_info;
+ else
+ b = &bt->link_info_56g;
+
+ bd->bt_profile |= b->status.map.profile_map;
+ bd->bt_smap.a2dp_active |= b->a2dp_desc.active;
+ bd->bt_smap.a2dp_sink |= b->a2dp_desc.sink;
+ bd->bt_smap.pan_active |= b->pan_desc.active;
+ bd->bt_smap.connect |= b->status.map.connect;
+ bd->bt_smap.hid_cnt += (u8)b->hid_desc.pair_cnt;
+ bd->bt_smap.hid_type |= b->hid_desc.type;
+ bd->bt_smap.cis_cnt += (u8)b->leaudio_desc.cis_cnt;
+ bd->bt_smap.link_cnt += b->link_cnt.now;
+ bd->bt_smap.inq_page |= b->status.map.inq_pag;
+ bd->bt_smap.page |= b->pag;
+
+ if (bt->link_weight[j] > bd->bt_link_weight) /* max */
+ bd->bt_link_weight = bt->link_weight[j];
+
+ if (b->slave_role)
+ bd->bt_smap.slave_role = b->slave_role;
+
+ if (b->a2dp_desc.vendor_id != 0)
+ bd->bt_smap.a2dp_vendor_id =
+ b->a2dp_desc.vendor_id;
+ }
+ }
+
+ if (bd->bt_profile & BTC_BT_HFP)
+ bd->bt_smap.hfp_exist = 1;
+ if (bd->bt_profile & BTC_BT_HID)
+ bd->bt_smap.hid_exist = 1;
+ if (bd->bt_profile & BTC_BT_A2DP)
+ bd->bt_smap.a2dp_exist = 1;
+ if (bd->bt_profile & BTC_BT_PAN)
+ bd->bt_smap.pan_exist = 1;
+ if (bd->bt_profile & BTC_BT_BIS)
+ bd->bt_smap.bis_exist = 1;
+ if (bd->bt_profile & BTC_BT_CIS)
+ bd->bt_smap.cis_exist = 1;
+ if (bd->bt_profile & BTC_BT_THREAD)
+ bd->bt_smap.thread_exist = 1;
+ if (bd->bt_profile & BTC_BT_ULL)
+ bd->bt_smap.ull_exist = 1;
+}
+
+#define _bind_is_btonly 0x7
+static void _set_coex_binding(struct rtw89_btc *btc)
+{
+ struct rtw89_btc_cx *cx = &btc->cx;
+ struct rtw89_btc_extsoc_info *bt2 = &cx->bt_ext;
+ struct rtw89_btc_bt_info *bt0 = &cx->bt0;
+ struct rtw89_btc_bt_info *bt1 = &cx->bt1;
+ struct rtw89_btc_wl_info *wl = &cx->wl;
+ struct rtw89_btc_dm *dm = &btc->dm;
+ u8 path_hwb[BTC_RF_NUM] = {RTW89_PHY_0, RTW89_PHY_1};
+ u8 wl_rf_band[RTW89_BAND_NUM] = {};
+ u8 i, j, val = 0;
+
+ /*
+ * sit_xmap(Space-Interaction) = ant_xmap | xtk_xmap
+ * 1: WL-BT space-interference, always 1 if BTG/BTA/SPDT = 1
+ * if dedicated-ant, it may be 1 if BT-Tx is bigger than WL-Rx(xtk_xmap)
+ *
+ * ant_xmap(ANT-Division-Multiplexing)
+ * ==> dedicated-ant->0, BTG/BTA/SPDT->1
+ *
+ * xtk_xmap(Cross-talk map)-> calculate WL/BT interference by SIR
+ * ==> 1: interference, 0: no-interference
+ *
+ * fdm_map(Frequency-Division-Multiplexing): WL/BT RF_Band overlap-map
+ * 2bit-map: bit[1]:5GHz/6GHz, bit[0]:2.4GHz
+ */
+ for (i = 0; i < RTW89_PHY_NUM; i++) {
+ if (wl->rf_band_map[i] & BIT(RTW89_BAND_2G))
+ wl_rf_band[i] |= BIT(RTW89_BAND_2G);
+
+ if (wl->rf_band_map[i] & (BIT(RTW89_BAND_5G) | BIT(RTW89_BAND_6G)))
+ wl_rf_band[i] |= BIT(RTW89_BAND_5G);
+
+ dm->fit_xmap[i][BTC_BT_1ST] = wl_rf_band[i] & bt0->rf_band_map;
+ dm->fit_xmap[i][BTC_BT_2ND] = wl_rf_band[i] & bt1->rf_band_map;
+ dm->fit_xmap[i][BTC_BT_EXT] = wl_rf_band[i] & bt2->rf_band_map;
+ }
+
+ /*
+ * if MR_WTYPE_MLD2L1R_NONMLD, FW will change 2+0/0+2/1+1
+ * Therefore, BTC_MLO_RF_xxx is not real-time state.
+ * if link mode change by _ntfy_generic(BTC_GNTFY_MRCX_INFO)
+ * the HW-BAND is decided by wl->mlo_info.mrcx_act_hwb_map
+ * In this case, BTC_RF_S0->HWB0, BTC_RF_S1->HWB1
+ */
+ if (wl->mlo_info.wtype == RTW89_MR_WTYPE_MLD2L1R_NONMLD) {
+ if (wl->role_info.link_mode != BTC_WLINK_2G_MCC ||
+ wl->role_info.link_mode != BTC_WLINK_25G_MCC ||
+ wl->role_info.link_mode != BTC_WLINK_25G_DBCC) {/* mode chg */
+ if (wl->mlo_info.mrcx_act_hwb_map == BIT(RTW89_PHY_1))
+ path_hwb[BTC_RF_S0] = RTW89_PHY_1;/* S0/1->HWB1 */
+ else
+ path_hwb[BTC_RF_S1] = RTW89_PHY_0;/* S0/1->HWB0 */
+ }
+ } else {
+ if (wl->mlo_info.rf_combination == BTC_MLO_RF_2_PLUS_0)
+ path_hwb[BTC_RF_S1] = RTW89_PHY_0; /* 2+0 RF-S0/1->HWB0 */
+ else if (wl->mlo_info.rf_combination == BTC_MLO_RF_0_PLUS_2)
+ path_hwb[BTC_RF_S0] = RTW89_PHY_1; /* 2+0 RF-S0/1->HWB1 */
+ }
+
+ /*
+ * tdd_map = sit_xmap * fdm_map, 1: WL-RF-Sx vs. BTx take TDD-Action
+ * fdd_map =(!sit_xmap) * fdm_map, 1: WL-RF-Sx vs.BTx take FDD-Action
+ * co-rx map = ant_xmap * fdm_map 1:WL/BT co-rx (for halbb-btg-ctrl)
+ * sit_xmap,ant_xmap = 0 or 1, so tdd/fdd use multiplication (*)
+ */
+
+ for (i = 0; i < BTC_RF_NUM; i++)
+ for (j = 0; j < BTC_ALL_BT_EZL; j++) {
+ dm->tdd_map[i][j] = dm->sit_xmap[i][j] *
+ dm->fit_xmap[path_hwb[i]][j];
+ dm->fdd_map[i][j] = !dm->sit_xmap[i][j] *
+ dm->fit_xmap[path_hwb[i]][j];
+ dm->corx_map[i][j] = dm->ant_xmap[i][j] *
+ dm->fit_xmap[path_hwb[i]][j];
+ }
+
+ /* TDD-Binding */
+ _set_bind_info(btc, BTC_MECH_TDD);
+
+ /* FDD-Binding */
+ _set_bind_info(btc, BTC_MECH_FDD);
+
+ dm->out_of_band = !dm->tdd_bind.rf_band && !dm->fdd_bind.rf_band;
+ dm->fdd_en = !!dm->fdd_bind.rf_band;
+ dm->tdd_en = !!dm->tdd_bind.rf_band;
+
+ /* set BT on/off state for GNT_WL Combined-MUX control */
+ if (bt0->enable.now)
+ val |= BIT(0);
+
+ if (bt1->enable.now)
+ val |= BIT(1);
+
+ if (bt2->func_type)
+ val |= BIT(2);
+
+ dm->ost_info.bt_enable_state = dm->bt_only ? _bind_is_btonly : val;
+}
+
static
void _run_coex(struct rtw89_dev *rtwdev, enum btc_reason_and_action reason)
{
@@ -7842,6 +8109,8 @@ void _run_coex(struct rtw89_dev *rtwdev, enum btc_reason_and_action reason)
bt->scan_rx_low_pri = false;
igno_bt = false;
+ _set_coex_binding(btc);
+
dm->freerun_chk = _check_freerun(rtwdev); /* check if meet freerun */
if (always_freerun) {
@@ -8370,8 +8639,8 @@ static void _update_bt_info(struct rtw89_dev *rtwdev, u8 *buf, u32 len)
"[BTC], %s(): bt_info[2]=0x%02x\n",
__func__, bt->raw_info[2]);
- b->profile_cnt.last = b->profile_cnt.now;
- b->profile_cnt.now = 0;
+ b->link_cnt.last = b->link_cnt.now;
+ b->link_cnt.now = 0;
hid->type = 0;
/* parse raw info low-Byte2 */
@@ -8384,13 +8653,13 @@ static void _update_bt_info(struct rtw89_dev *rtwdev, u8 *buf, u32 len)
bt->bcnt[BTC_BCNT_INQPAG] += !!(bt->inq_pag.now && !bt->inq_pag.last);
hfp->exist = btinfo.lb2.hfp;
- b->profile_cnt.now += (u8)hfp->exist;
+ b->link_cnt.now += (u8)hfp->exist;
hid->exist = btinfo.lb2.hid;
- b->profile_cnt.now += (u8)hid->exist;
+ b->link_cnt.now += (u8)hid->exist;
a2dp->exist = btinfo.lb2.a2dp;
- b->profile_cnt.now += (u8)a2dp->exist;
+ b->link_cnt.now += (u8)a2dp->exist;
pan->exist = btinfo.lb2.pan;
- b->profile_cnt.now += (u8)pan->exist;
+ b->link_cnt.now += (u8)pan->exist;
btc->dm.trx_info.bt_profile = u32_get_bits(btinfo.val, BT_PROFILE_PROTOCOL_MASK);
/* parse raw info low-Byte3 */
@@ -9418,7 +9687,7 @@ static int _show_bt_info(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
p += scnprintf(p, end - p, " %-15s : profile:%s%s%s%s%s ",
"[profile]",
- (bt_linfo->profile_cnt.now == 0) ? "None," : "",
+ (bt_linfo->link_cnt.now == 0) ? "None," : "",
bt_linfo->hfp_desc.exist ? "HFP," : "",
bt_linfo->hid_desc.exist ? "HID," : "",
bt_linfo->a2dp_desc.exist ?
@@ -9520,7 +9789,7 @@ static int _show_bt_info(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
p += scnprintf(p, end - p, "\n");
}
- if (ver_main >= 9 && bt_linfo->profile_cnt.now)
+ if (ver_main >= 9 && bt_linfo->link_cnt.now)
rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_TX_PWR_LVL, true);
else
rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_TX_PWR_LVL, false);
@@ -9542,7 +9811,7 @@ static int _show_bt_info(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
}
p += scnprintf(p, end - p, "\n");
- if (bt_linfo->profile_cnt.now || bt_linfo->status.map.ble_connect)
+ if (bt_linfo->link_cnt.now || bt_linfo->status.map.ble_connect)
rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_AFH_MAP, true);
else
rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_AFH_MAP, false);
diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index 3f77707e2733..21bdf229723c 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -1445,6 +1445,11 @@ enum rtw89_btc_bt_state_cnt {
BTC_BCNT_NUM,
};
+enum rtw89_btc_bt_mech_type {
+ BTC_MECH_TDD = 0,
+ BTC_MECH_FDD = 1,
+};
+
enum rtw89_btc_bt_rf_band {
BTC_BT_B2G = 0x0, /* 2.4GHz */
BTC_BT_B5G = 0x1, /* 5GHz or 6GHz */
@@ -1463,6 +1468,12 @@ enum rtw89_btc_bt_profile {
BTC_BT_HID = BIT(1),
BTC_BT_A2DP = BIT(2),
BTC_BT_PAN = BIT(3),
+ BTC_BT_BIS = BIT(4),
+ BTC_BT_CIS = BIT(5),
+ BTC_BT_THREAD = BIT(6),
+ BTC_BT_ULL = BIT(7),
+ BTC_BT_LEGACY = 0xf,
+ BTC_BT_FULL = 0x3f,
BTC_PROFILE_MAX = 4,
};
@@ -1688,16 +1699,16 @@ struct rtw89_btc_bt_ver_info {
};
struct rtw89_btc_bool_sta_chg {
- u32 now: 1;
- u32 last: 1;
- u32 remain: 1;
- u32 srvd: 29;
+ u8 now: 1;
+ u8 last: 1;
+ u8 remain: 1;
+ u8 srvd: 5;
};
struct rtw89_btc_u8_sta_chg {
u8 now;
u8 last;
- u8 remain;
+ u8 chg;
u8 rsvd;
};
@@ -1956,6 +1967,8 @@ struct rtw89_btc_bt_smap {
u32 sco_busy: 1;
u32 mesh_busy: 1;
u32 inq_pag: 1;
+ u32 profile_map: 8;
+ u32 rsvd: 18;
};
union rtw89_btc_bt_state_map {
@@ -1974,14 +1987,30 @@ struct rtw89_btc_bt_txpwr_desc {
u8 le_gain_index;
};
+struct rtw89_btc_bt_leaudio_desc {
+ u32 bis_exist: 1;
+ u32 bis_exist_last: 1;
+ u32 cis_exist: 1;
+ u32 cis_exist_last: 1;
+ u32 bis_cnt: 3;
+ u32 cis_cnt: 3;
+ u32 rssi: 8;
+ u32 bis_cnt_last: 3;
+ u32 cis_cnt_last: 3;
+ u32 rsvd: 8;
+
+ u16 diff_t;
+};
+
struct rtw89_btc_bt_link_info {
- struct rtw89_btc_u8_sta_chg profile_cnt;
+ struct rtw89_btc_u8_sta_chg link_cnt;
struct rtw89_btc_bool_sta_chg multi_link;
struct rtw89_btc_bool_sta_chg relink;
struct rtw89_btc_bt_hfp_desc hfp_desc;
struct rtw89_btc_bt_hid_desc hid_desc;
struct rtw89_btc_bt_a2dp_desc a2dp_desc;
struct rtw89_btc_bt_pan_desc pan_desc;
+ struct rtw89_btc_bt_leaudio_desc leaudio_desc;
union rtw89_btc_bt_state_map status;
struct rtw89_btc_bt_txpwr_desc bt_txpwr_desc;
@@ -1990,14 +2019,59 @@ struct rtw89_btc_bt_link_info {
u8 rssi_state[BTC_BT_RSSI_THMAX];
u8 afh_map[BTC_BT_AFH_GROUP];
u8 afh_map_le[BTC_BT_AFH_LE_GROUP];
+ u8 rssi;
+
+ u8 role_sw: 1;
+ u8 slave_role: 1;
+ u8 afh_update: 1;
+ u8 cqddr: 1;
+ u8 tx_3m: 1;
+ u8 inq: 1;
+ u8 pag: 1;
+ u8 igno_wl: 1;
+
+ u8 ble_scan_en: 1;
+ u8 reinit: 1;
+ u8 rsvd: 6;
+};
- u32 role_sw: 1;
- u32 slave_role: 1;
- u32 afh_update: 1;
- u32 cqddr: 1;
- u32 rssi: 8;
- u32 tx_3m: 1;
- u32 rsvd: 19;
+struct rtw89_btc_bind_bt_status {
+ u8 a2dp_active: 1;
+ u8 a2dp_sink: 1;
+ u8 pan_active: 1;
+ u8 connect: 1;
+ u8 inq_page: 1;
+ u8 multi_link: 1;
+ u8 slave_role: 1;
+ u8 page: 1;
+
+ u8 hfp_exist: 1;
+ u8 hid_exist: 1;
+ u8 a2dp_exist: 1;
+ u8 pan_exist: 1;
+ u8 bis_exist: 1;
+ u8 cis_exist: 1;
+ u8 thread_exist: 1;
+ u8 ull_exist: 1;
+
+ u8 hid_cnt;
+ u8 hid_type;
+ u8 cis_cnt;
+ u8 link_cnt;
+
+ u16 a2dp_vendor_id;
+};
+
+struct rtw89_btc_bind_info {
+ u8 wl_hwb_sel; /* map */
+ u8 wl_link_mode;
+ u8 wl_bg_mode;
+ u8 rf_band; /* map, 0: no any rf-band bind */
+ u8 bt_sel; /* map */
+ u8 bt_link_weight; /* select the highest weight between bt/rf-band */
+
+ u32 bt_profile; /* map */
+ struct rtw89_btc_bind_bt_status bt_smap;
};
struct rtw89_btc_extsoc_info {
@@ -2105,6 +2179,7 @@ struct rtw89_btc_wl_info {
u8 coex_mode;
u8 pta_req_mac;
u8 bt_polut_type[RTW89_PHY_NUM]; /* BT polluted WL-Tx type for phy0/1 */
+ u8 rf_band_map[RTW89_PHY_NUM]; /* rf_band bit-map */
bool is_5g_hi_channel;
bool go_client_exist;
@@ -2291,6 +2366,7 @@ union rtw89_btc_fbtc_btscan {
struct rtw89_btc_bt_info {
struct rtw89_btc_bt_link_info link_info;
+ struct rtw89_btc_bt_link_info link_info_56g;
struct rtw89_btc_bt_scan_info_v1 scan_info_v1[BTC_SCAN_MAX1];
struct rtw89_btc_bt_scan_info_v2 scan_info_v2[CXSCAN_MAX];
struct rtw89_btc_bt_ver_info ver_info;
@@ -2301,6 +2377,7 @@ struct rtw89_btc_bt_info {
u8 raw_info[BTC_BTINFO_MAX]; /* raw bt info from mailbox */
u8 txpwr_info[BTC_BTINFO_MAX];
+ u8 link_weight[BTC_BT_BMAX]; /* Link Weight for RF-band/HWB selection */
u8 rssi_level;
u8 rf_band_map;
u8 func_type;
@@ -3178,6 +3255,7 @@ struct rtw89_btc_fbtc_outsrc_set_info {
u8 pta_req_hw_band;
u8 rf_gbt_source;
+ u8 bt_enable_state;
} __packed;
union rtw89_btc_fbtc_slot_u {
@@ -3200,8 +3278,20 @@ struct rtw89_btc_dm {
struct rtw89_btc_wl_scc_ctrl wl_scc;
struct rtw89_btc_trx_info trx_info;
union rtw89_btc_dm_error_map error;
+ struct rtw89_btc_bind_info tdd_bind;
+ struct rtw89_btc_bind_info fdd_bind;
u32 cnt_dm[BTC_DCNT_NUM];
u32 cnt_notify[BTC_NCNT_NUM];
+ u8 ant_xmap[BTC_RF_NUM][BTC_ALL_BT_EZL]; /* WL-BT ANT interact-map */
+ u8 xtk_xmap[BTC_RF_NUM][BTC_ALL_BT_EZL]; /* 1: If RSSI<(BT-Pin -SIR) */
+ u8 sit_xmap[BTC_RF_NUM][BTC_ALL_BT_EZL]; /* WL-BT space interact-map */
+ u8 fit_xmap[RTW89_PHY_NUM][BTC_ALL_BT_EZL]; /* HWB-BT freq interact-map */
+ u8 tdd_map[BTC_RF_NUM][BTC_ALL_BT_EZL]; /* WL-BT tdd-map */
+ u8 fdd_map[BTC_RF_NUM][BTC_ALL_BT_EZL]; /* WL-BT fdd-map */
+ u8 corx_map[BTC_RF_NUM][BTC_ALL_BT_EZL]; /* WL-BT Co-Rx */
+
+ u8 sit_xmap_last[BTC_RF_NUM][BTC_ALL_BT_EZL];
+ u8 fit_xmap_last[RTW89_PHY_NUM][BTC_ALL_BT_EZL];
u32 update_slot_map;
u32 set_ant_path;
@@ -3239,9 +3329,12 @@ struct rtw89_btc_dm {
u8 freerun_chk: 1;
u8 wl_pre_agc_rb: 2;
u8 bt_select: 2; /* 0:s0, 1:s1, 2:s0 & s1, refer to enum btc_bt_index */
+
u8 slot_req_more: 1;
+ u8 out_of_band: 1;
+ u8 fdd_en: 1;
+ u8 tdd_en: 1;
u8 lps_ctrl_scbd: 1;
-
u8 lps_ctrl_scbd_last: 1;
u8 lps_ctrl_change: 1;
};
--
2.25.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH rtw-next 7/9] wifi: rtw89: coex: Add TDMA binding for dual MAC
2026-07-03 11:43 [PATCH rtw-next 0/9] wifi: rtw89: coex: implement components for dual Bluetooth Ping-Ke Shih
` (5 preceding siblings ...)
2026-07-03 11:43 ` [PATCH rtw-next 6/9] wifi: rtw89: coex: Add WiFi/Bluetooth adapter binding info Ping-Ke Shih
@ 2026-07-03 11:43 ` Ping-Ke Shih
2026-07-03 11:43 ` [PATCH rtw-next 8/9] wifi: rtw89: coex: Update scoreboard related logic for dual Bluetooth Ping-Ke Shih
2026-07-03 11:43 ` [PATCH rtw-next 9/9] wifi: rtw89: coex: Add Co-RX logic Ping-Ke Shih
8 siblings, 0 replies; 10+ messages in thread
From: Ping-Ke Shih @ 2026-07-03 11:43 UTC (permalink / raw)
To: linux-wireless; +Cc: ku920601
From: Ching-Te Ku <ku920601@realtek.com>
Because the two MAC should have their own individual using, they will
need different TDMA mechanism. This patch will bind TDMA with MAC index,
and also the corresponding antenna, hardware grant signal setting.
Signed-off-by: Ching-Te Ku <ku920601@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/coex.c | 381 +++++++++-------------
drivers/net/wireless/realtek/rtw89/core.h | 11 +-
2 files changed, 158 insertions(+), 234 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c
index 435a4a5d2c2d..86833b0cd47c 100644
--- a/drivers/net/wireless/realtek/rtw89/coex.c
+++ b/drivers/net/wireless/realtek/rtw89/coex.c
@@ -494,7 +494,7 @@ enum btc_ant_phase {
BTC_ANT_FREERUN,
BTC_ANT_WRFK,
BTC_ANT_WRFK2,
- BTC_ANT_BRFK,
+ BTC_ANT_PTA, /* for Multi-PTA, each hw-band has its own PTA */
BTC_ANT_MAX
};
@@ -3894,6 +3894,41 @@ static void _set_policy(struct rtw89_dev *rtwdev, u16 policy_type,
_fw_set_policy(rtwdev, policy_type, action);
}
+static void _set_tdma_bind(struct rtw89_dev *rtwdev, bool tdma_on)
+{
+ struct rtw89_btc_dm *dm = &rtwdev->btc.dm;
+ struct rtw89_btc_bind_info *bind;
+ u8 null_role = RTW89_WIFI_ROLE_STATION;
+
+ if (dm->tdd_en)
+ bind = &dm->tdd_bind; /* tdd = 1 && fdd = 0 or 1 */
+ else
+ bind = &dm->fdd_bind; /* tdd = 0 && fdd = 1 */
+
+ /* notify BT TDMA on/off by scoreboard for ACL/Scan schedule */
+ _write_scbd(rtwdev, BTC_WSCB_TDMA, tdma_on);
+
+ /*
+ * set hwb/bt bind to TDMA policy parameter
+ * FW-BTC will setup related hwbx vs. BTx coex tables by slot toggle
+ * ex: HWb0 + BT0 + BT1, HWB0-BT0/HWB0-BT1 coex by WL/BT slot toggle
+ */
+ dm->tdma.bind = ((bind->bt_sel & 0xf) << 4) + (bind->wl_hwb_sel & 0x3);
+ if (dm->tdd_en)
+ dm->tdma.bind |= BIT(2);
+ if (dm->fdd_en)
+ dm->tdma.bind |= BIT(3);
+ if (rtwdev->btc.ver->fcxtdma != 8)
+ dm->tdma.bind |= 0;
+
+ /* set Null-tx role for 2 HW-BAND TDMA (MLMR) */
+ if (!dm->eslot_ctrl.en && dm->tdma.rxflctrl &&
+ (bind->wl_hwb_sel == (BIT(RTW89_PHY_1) | BIT(RTW89_PHY_0)))) {
+ null_role = (null_role << 4) + null_role;
+ _tdma_set_flctrl_role(&rtwdev->btc, null_role);
+ }
+}
+
#define BTC_B1_MAX 250 /* unit ms */
void rtw89_btc_set_policy(struct rtw89_dev *rtwdev, u16 policy_type)
{
@@ -3903,6 +3938,7 @@ void rtw89_btc_set_policy(struct rtw89_dev *rtwdev, u16 policy_type)
struct rtw89_btc_fbtc_slot *s = dm->slot.v1;
u8 type;
u32 tbl_w1, tbl_b1, tbl_b4;
+ bool tdma_on = false;
if (btc->ant_type == BTC_ANT_SHARED) {
if (btc->cx.wl.status.map._4way)
@@ -3928,7 +3964,7 @@ void rtw89_btc_set_policy(struct rtw89_dev *rtwdev, u16 policy_type)
btc->update_policy_force = true;
break;
case BTC_CXP_OFF: /* TDMA off */
- _write_scbd(rtwdev, BTC_WSCB_TDMA, false);
+ tdma_on = false;
*t = t_def[CXTD_OFF];
s[CXST_OFF] = s_def[CXST_OFF];
@@ -3963,7 +3999,7 @@ void rtw89_btc_set_policy(struct rtw89_dev *rtwdev, u16 policy_type)
}
break;
case BTC_CXP_OFFB: /* TDMA off + beacon protect */
- _write_scbd(rtwdev, BTC_WSCB_TDMA, false);
+ tdma_on = false;
*t = t_def[CXTD_OFF_B2];
s[CXST_OFF] = s_def[CXST_OFF];
switch (policy_type) {
@@ -3974,7 +4010,7 @@ void rtw89_btc_set_policy(struct rtw89_dev *rtwdev, u16 policy_type)
break;
case BTC_CXP_OFFE: /* TDMA off + beacon protect + Ext_control */
btc->bt_req_en = true;
- _write_scbd(rtwdev, BTC_WSCB_TDMA, true);
+ tdma_on = true;
*t = t_def[CXTD_OFF_EXT];
switch (policy_type) {
case BTC_CXP_OFFE_DEF:
@@ -3992,7 +4028,7 @@ void rtw89_btc_set_policy(struct rtw89_dev *rtwdev, u16 policy_type)
}
break;
case BTC_CXP_FIX: /* TDMA Fix-Slot */
- _write_scbd(rtwdev, BTC_WSCB_TDMA, true);
+ tdma_on = true;
*t = t_def[CXTD_FIX];
switch (policy_type) {
case BTC_CXP_FIX_TD3030:
@@ -4048,7 +4084,7 @@ void rtw89_btc_set_policy(struct rtw89_dev *rtwdev, u16 policy_type)
}
break;
case BTC_CXP_PFIX: /* PS-TDMA Fix-Slot */
- _write_scbd(rtwdev, BTC_WSCB_TDMA, true);
+ tdma_on = true;
*t = t_def[CXTD_PFIX];
if (btc->cx.wl.role_info.role_map.role.ap)
_tdma_set_flctrl(btc, CXFLC_QOSNULL);
@@ -4081,7 +4117,7 @@ void rtw89_btc_set_policy(struct rtw89_dev *rtwdev, u16 policy_type)
}
break;
case BTC_CXP_AUTO: /* TDMA Auto-Slot */
- _write_scbd(rtwdev, BTC_WSCB_TDMA, true);
+ tdma_on = true;
*t = t_def[CXTD_AUTO];
switch (policy_type) {
case BTC_CXP_AUTO_TD50B1:
@@ -4105,7 +4141,7 @@ void rtw89_btc_set_policy(struct rtw89_dev *rtwdev, u16 policy_type)
}
break;
case BTC_CXP_PAUTO: /* PS-TDMA Auto-Slot */
- _write_scbd(rtwdev, BTC_WSCB_TDMA, true);
+ tdma_on = true;
*t = t_def[CXTD_PAUTO];
switch (policy_type) {
case BTC_CXP_PAUTO_TD50B1:
@@ -4129,7 +4165,7 @@ void rtw89_btc_set_policy(struct rtw89_dev *rtwdev, u16 policy_type)
}
break;
case BTC_CXP_AUTO2: /* TDMA Auto-Slot2 */
- _write_scbd(rtwdev, BTC_WSCB_TDMA, true);
+ tdma_on = true;
*t = t_def[CXTD_AUTO2];
switch (policy_type) {
case BTC_CXP_AUTO2_TD3050:
@@ -4166,7 +4202,7 @@ void rtw89_btc_set_policy(struct rtw89_dev *rtwdev, u16 policy_type)
}
break;
case BTC_CXP_PAUTO2: /* PS-TDMA Auto-Slot2 */
- _write_scbd(rtwdev, BTC_WSCB_TDMA, true);
+ tdma_on = true;
*t = t_def[CXTD_PAUTO2];
switch (policy_type) {
case BTC_CXP_PAUTO2_TD3050:
@@ -4203,6 +4239,7 @@ void rtw89_btc_set_policy(struct rtw89_dev *rtwdev, u16 policy_type)
}
break;
}
+ _set_tdma_bind(rtwdev, tdma_on);
}
EXPORT_SYMBOL(rtw89_btc_set_policy);
@@ -4211,14 +4248,14 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type)
struct rtw89_btc *btc = &rtwdev->btc;
struct rtw89_btc_dm *dm = &btc->dm;
struct rtw89_btc_fbtc_tdma *t = &dm->tdma;
- struct rtw89_btc_wl_role_info_v1 *wl_rinfo = &btc->cx.wl.role_info_v1;
struct rtw89_btc_bt_a2dp_desc *a2dp = &btc->cx.bt0.link_info.a2dp_desc;
struct rtw89_btc_bt_hid_desc *hid = &btc->cx.bt0.link_info.hid_desc;
struct rtw89_btc_bt_hfp_desc *hfp = &btc->cx.bt0.link_info.hfp_desc;
struct rtw89_btc_wl_info *wl = &btc->cx.wl;
u8 type, null_role;
u32 tbl_w1, tbl_b1, tbl_b4;
- u16 dur_2;
+ bool tdma_on = false;
+ u16 dur_1 = 0, dur_2;
if (wl->status.map.lps) {
_slot_set_le(btc, CXST_E2G, s_def[CXST_E2G].dur,
@@ -4272,7 +4309,7 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type)
_slot_set_tbl(btc, CXST_OFF, cxtbl[2]);
break;
case BTC_CXP_OFF: /* TDMA off */
- _write_scbd(rtwdev, BTC_WSCB_TDMA, false);
+ tdma_on = false;
*t = t_def[CXTD_OFF];
_slot_set_le(btc, CXST_OFF, s_def[CXST_OFF].dur,
s_def[CXST_OFF].cxtbl, s_def[CXST_OFF].cxtype);
@@ -4324,7 +4361,7 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type)
}
break;
case BTC_CXP_OFFB: /* TDMA off + beacon protect */
- _write_scbd(rtwdev, BTC_WSCB_TDMA, false);
+ tdma_on = false;
*t = t_def[CXTD_OFF_B2];
_slot_set_le(btc, CXST_OFF, s_def[CXST_OFF].dur,
s_def[CXST_OFF].cxtbl, s_def[CXST_OFF].cxtype);
@@ -4338,24 +4375,35 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type)
}
break;
case BTC_CXP_OFFE: /* TDMA off + beacon protect + Ext_control */
- _write_scbd(rtwdev, BTC_WSCB_TDMA, true);
+ tdma_on = true;
*t = t_def[CXTD_OFF_EXT];
/* To avoid wl-s0 tx break by hid/hfp tx */
if (hid->exist || hfp->exist)
tbl_w1 = cxtbl[16];
+ if (dm->eslot_ctrl.en) {
+ null_role = u8_encode_bits(dm->eslot_ctrl.nulltx_role1, 0x0f) |
+ u8_encode_bits(dm->eslot_ctrl.nulltx_role2, 0xf0);
+ _tdma_set_flctrl_role(btc, null_role);
+ _tdma_set_rxflctrl(btc, 1);
+ _tdma_set_txflctrl(btc, 1);
+ /* Set Null-Tx time-tick by E2G duration */
+ dm->eslot_ctrl.nulltx_pre_time = 5; /* TODO: BIS COEX */
+ dur_1 = dm->eslot_ctrl.nulltx_pre_time;
+ }
+
dur_2 = dm->e2g_slot_limit;
switch (policy_type) {
case BTC_CXP_OFFE_2GBWISOB: /* for normal-case */
- _slot_set(btc, CXST_E2G, 5, tbl_w1, SLOT_ISO);
+ _slot_set(btc, CXST_E2G, dur_1, tbl_w1, SLOT_ISO);
_slot_set_le(btc, CXST_EBT, s_def[CXST_EBT].dur,
s_def[CXST_EBT].cxtbl, s_def[CXST_EBT].cxtype);
_slot_set_dur(btc, CXST_EBT, dur_2);
break;
case BTC_CXP_OFFE_2GISOB: /* for bt no-link */
- _slot_set(btc, CXST_E2G, 5, cxtbl[1], SLOT_ISO);
+ _slot_set(btc, CXST_E2G, dur_1, cxtbl[1], SLOT_ISO);
_slot_set_le(btc, CXST_EBT, s_def[CXST_EBT].dur,
s_def[CXST_EBT].cxtbl, s_def[CXST_EBT].cxtype);
_slot_set_dur(btc, CXST_EBT, dur_2);
@@ -4383,16 +4431,16 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type)
break;
case BTC_CXP_OFFE_2GBWMIXB:
if (a2dp->exist)
- _slot_set(btc, CXST_E2G, 5, cxtbl[2], SLOT_MIX);
+ _slot_set(btc, CXST_E2G, dur_1, cxtbl[2], SLOT_MIX);
else
- _slot_set(btc, CXST_E2G, 5, tbl_w1, SLOT_MIX);
+ _slot_set(btc, CXST_E2G, dur_1, tbl_w1, SLOT_MIX);
_slot_set_le(btc, CXST_EBT, cpu_to_le16(40),
s_def[CXST_EBT].cxtbl, s_def[CXST_EBT].cxtype);
_slot_set_dur(btc, CXST_EBT, dur_2);
break;
case BTC_CXP_OFFE_WL: /* for 4-way */
- _slot_set(btc, CXST_E2G, 5, cxtbl[1], SLOT_MIX);
- _slot_set(btc, CXST_EBT, 5, cxtbl[1], SLOT_MIX);
+ _slot_set(btc, CXST_E2G, dur_1, cxtbl[1], SLOT_MIX);
+ _slot_set(btc, CXST_EBT, dur_1, cxtbl[1], SLOT_MIX);
break;
default:
break;
@@ -4403,7 +4451,7 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type)
s_def[CXST_OFF].cxtbl, s_def[CXST_OFF].cxtype);
break;
case BTC_CXP_FIX: /* TDMA Fix-Slot */
- _write_scbd(rtwdev, BTC_WSCB_TDMA, true);
+ tdma_on = true;
*t = t_def[CXTD_FIX];
switch (policy_type) {
@@ -4462,7 +4510,7 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type)
}
break;
case BTC_CXP_PFIX: /* PS-TDMA Fix-Slot */
- _write_scbd(rtwdev, BTC_WSCB_TDMA, true);
+ tdma_on = true;
*t = t_def[CXTD_PFIX];
switch (policy_type) {
@@ -4501,7 +4549,7 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type)
}
break;
case BTC_CXP_AUTO: /* TDMA Auto-Slot */
- _write_scbd(rtwdev, BTC_WSCB_TDMA, true);
+ tdma_on = true;
*t = t_def[CXTD_AUTO];
switch (policy_type) {
@@ -4528,7 +4576,7 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type)
}
break;
case BTC_CXP_PAUTO: /* PS-TDMA Auto-Slot */
- _write_scbd(rtwdev, BTC_WSCB_TDMA, true);
+ tdma_on = true;
*t = t_def[CXTD_PAUTO];
switch (policy_type) {
@@ -4555,7 +4603,7 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type)
}
break;
case BTC_CXP_AUTO2: /* TDMA Auto-Slot2 */
- _write_scbd(rtwdev, BTC_WSCB_TDMA, true);
+ tdma_on = true;
*t = t_def[CXTD_AUTO2];
switch (policy_type) {
@@ -4597,7 +4645,7 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type)
}
break;
case BTC_CXP_PAUTO2: /* PS-TDMA Auto-Slot2 */
- _write_scbd(rtwdev, BTC_WSCB_TDMA, true);
+ tdma_on = true;
*t = t_def[CXTD_PAUTO2];
switch (policy_type) {
@@ -4640,20 +4688,22 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type)
break;
}
- if (wl_rinfo->link_mode == BTC_WLINK_2G_SCC && dm->tdma.rxflctrl) {
- null_role = FIELD_PREP(0x0f, dm->wl_scc.null_role1) |
- FIELD_PREP(0xf0, dm->wl_scc.null_role2);
- _tdma_set_flctrl_role(btc, null_role);
- }
-
/* enter leak_slot after each null-1 */
if (dm->leak_ap && dm->tdma.leak_n > 1)
_tdma_set_lek(btc, 1);
- if (dm->tdma_instant_excute || dm->lps_ctrl_change) {
+ if (dm->tdma_instant_excute ||
+ dm->error.map.tdma_no_sync ||
+ dm->error.map.slot_no_sync ||
+ dm->lps_ctrl_change) {
btc->dm.tdma.option_ctrl |= BIT(0);
btc->update_policy_force = true;
}
+
+ if (btc->cli_h2c_cmd)
+ btc->update_policy_force = true;
+
+ _set_tdma_bind(rtwdev, tdma_on);
}
EXPORT_SYMBOL(rtw89_btc_set_policy_v1);
@@ -4697,20 +4747,29 @@ static void _set_ant_v0(struct rtw89_dev *rtwdev, bool force_exec,
struct rtw89_btc_wl_info *wl = &btc->cx.wl;
struct rtw89_btc_bt_info *bt = &cx->bt0;
struct rtw89_btc_wl_dbcc_info *wl_dinfo = &wl->dbcc_info;
- u8 gnt_wl_ctrl, gnt_bt_ctrl, plt_ctrl, i, b2g = 0;
- bool dbcc_chg = false;
+ u8 gwl, gwl0, gwl1, gbt, plt_ctrl, i, dbcc_2g_phy, b2g = 0;
+ bool dbcc_chg = false, dbcc_en = false;
u32 ant_path_type;
ant_path_type = ((phy_map << 8) + type);
- if (btc->ver->fwlrole == 1)
+ if (btc->ver->fwlrole == 1) {
dbcc_chg = wl->role_info_v1.dbcc_chg;
- else if (btc->ver->fwlrole == 2)
+ dbcc_en = wl->role_info_v1.dbcc_en;
+ dbcc_2g_phy = wl->role_info_v1.dbcc_2g_phy;
+ } else if (btc->ver->fwlrole == 2) {
dbcc_chg = wl->role_info_v2.dbcc_chg;
- else if (btc->ver->fwlrole == 7)
+ dbcc_en = wl->role_info_v2.dbcc_en;
+ dbcc_2g_phy = wl->role_info_v2.dbcc_2g_phy;
+ } else if (btc->ver->fwlrole == 7) {
dbcc_chg = wl->role_info_v7.dbcc_chg;
- else if (btc->ver->fwlrole == 8)
+ dbcc_en = wl->role_info_v7.dbcc_en;
+ dbcc_2g_phy = wl->role_info_v7.dbcc_2g_phy;
+ } else if (btc->ver->fwlrole == 8) {
dbcc_chg = wl->role_info_v8.dbcc_chg;
+ dbcc_en = wl->role_info_v8.dbcc_en;
+ dbcc_2g_phy = wl->role_info_v8.dbcc_2g_phy;
+ }
if (btc->dm.run_reason == BTC_RSN_NTFY_POWEROFF ||
btc->dm.run_reason == BTC_RSN_NTFY_RADIO_STATE ||
@@ -4768,14 +4827,14 @@ static void _set_ant_v0(struct rtw89_dev *rtwdev, bool force_exec,
for (i = 0; i < RTW89_PHY_NUM; i++) {
b2g = (wl_dinfo->real_band[i] == RTW89_BAND_2G);
- gnt_wl_ctrl = b2g ? BTC_GNT_HW : BTC_GNT_SW_HI;
- gnt_bt_ctrl = b2g ? BTC_GNT_HW : BTC_GNT_SW_HI;
+ gwl = b2g ? BTC_GNT_HW : BTC_GNT_SW_HI;
+ gbt = b2g ? BTC_GNT_HW : BTC_GNT_SW_HI;
/* BT should control by GNT_BT if WL_2G at S0 */
if (i == 1 &&
wl_dinfo->real_band[0] == RTW89_BAND_2G &&
wl_dinfo->real_band[1] == RTW89_BAND_5G)
- gnt_bt_ctrl = BTC_GNT_HW;
- _set_gnt(rtwdev, BIT(i), gnt_wl_ctrl, gnt_bt_ctrl);
+ gbt = BTC_GNT_HW;
+ _set_gnt(rtwdev, BIT(i), gwl, gbt);
plt_ctrl = b2g ? BTC_PLT_BT : BTC_PLT_NONE;
_set_bt_plut(rtwdev, BIT(i),
plt_ctrl, plt_ctrl);
@@ -4808,12 +4867,27 @@ static void _set_ant_v0(struct rtw89_dev *rtwdev, bool force_exec,
_set_gnt(rtwdev, phy_map, BTC_GNT_SW_HI, BTC_GNT_SW_LO);
_set_bt_plut(rtwdev, phy_map, BTC_PLT_NONE, BTC_PLT_NONE);
break;
- case BTC_ANT_BRFK:
- rtw89_chip_cfg_ctrl_path(rtwdev, BTC_CTRL_BY_BT);
- _set_gnt(rtwdev, phy_map, BTC_GNT_SW_LO, BTC_GNT_SW_HI);
- _set_bt_plut(rtwdev, phy_map, BTC_PLT_NONE, BTC_PLT_NONE);
- break;
+ case BTC_ANT_PTA:
default:
+ gbt = BTC_GNT_HW;
+ if ((rtwdev->chip->para_ver & BTC_FEAT_MULTI_PTA) ||
+ !dbcc_en) {
+ gwl = BTC_GNT_HW;
+ _set_gnt(rtwdev, BTC_PHY_ALL, gwl, gbt);
+ } else {
+ /* for DBCC Only-1-PTA */
+ if (dbcc_2g_phy == RTW89_PHY_0) {
+ gwl0 = BTC_GNT_HW;
+ gwl1 = BTC_GNT_SW_HI;
+ } else {
+ gwl0 = BTC_GNT_SW_HI;
+ gwl1 = BTC_GNT_HW;
+ }
+ _set_gnt(rtwdev, BTC_PHY_0, gwl0, gbt);
+ _set_gnt(rtwdev, BTC_PHY_1, gwl1, gbt);
+ }
+ rtw89_chip_cfg_ctrl_path(rtwdev, BTC_CTRL_BY_WL);
+ _set_bt_plut(rtwdev, phy_map, BTC_PLT_NONE, BTC_PLT_NONE);
break;
}
}
@@ -4828,7 +4902,7 @@ static void _set_ant_v1(struct rtw89_dev *rtwdev, bool force_exec,
u32 ant_path_type = rtw89_get_antpath_type(phy_map, type);
struct rtw89_btc_wl_dbcc_info *wl_dinfo = &wl->dbcc_info;
struct rtw89_btc_dm *dm = &btc->dm;
- u8 gwl = BTC_GNT_HW;
+ u8 gwl = BTC_GNT_HW, gwl0, gwl1, gbt;
if (btc->dm.run_reason == BTC_RSN_NTFY_POWEROFF ||
btc->dm.run_reason == BTC_RSN_NTFY_RADIO_STATE ||
@@ -4913,8 +4987,26 @@ static void _set_ant_v1(struct rtw89_dev *rtwdev, bool force_exec,
_set_gnt_v1(rtwdev, phy_map, BTC_GNT_SW_HI, BTC_GNT_SW_LO,
BTC_WLACT_SW_HI); /* no BT-Tx */
break;
+ case BTC_ANT_PTA:
default:
- return;
+ gbt = BTC_GNT_HW;
+ if ((rtwdev->chip->para_ver & BTC_FEAT_MULTI_PTA) ||
+ !wl_rinfo->dbcc_en) {
+ gwl = BTC_GNT_HW;
+ _set_gnt_v1(rtwdev, BTC_PHY_ALL, gwl, gbt, BTC_WLACT_HW);
+ } else {
+ /* for DBCC Only-1-PTA */
+ if (wl_rinfo->dbcc_2g_phy == RTW89_PHY_0) {
+ gwl0 = BTC_GNT_HW;
+ gwl1 = BTC_GNT_SW_HI;
+ } else {
+ gwl0 = BTC_GNT_SW_HI;
+ gwl1 = BTC_GNT_HW;
+ }
+ _set_gnt_v1(rtwdev, BTC_PHY_0, gwl0, gbt, BTC_WLACT_HW);
+ _set_gnt_v1(rtwdev, BTC_PHY_1, gwl1, gbt, BTC_WLACT_HW);
+ }
+ break;
}
_set_bt_plut(rtwdev, phy_map, BTC_PLT_GNT_WL, BTC_PLT_GNT_WL);
@@ -6017,178 +6109,15 @@ static void _action_wl_2g_mcc(struct rtw89_dev *rtwdev)
static void _action_wl_2g_scc(struct rtw89_dev *rtwdev)
{
struct rtw89_btc *btc = &rtwdev->btc;
-
- _set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
-
- if (btc->ant_type == BTC_ANT_SHARED) { /* shared-antenna */
- if (btc->cx.bt0.link_info.link_cnt.now == 0)
- _set_policy(rtwdev,
- BTC_CXP_OFFE_DEF2, BTC_ACT_WL_2G_SCC);
- else
- _set_policy(rtwdev,
- BTC_CXP_OFFE_DEF, BTC_ACT_WL_2G_SCC);
- } else { /* dedicated-antenna */
- _set_policy(rtwdev, BTC_CXP_OFF_EQ0, BTC_ACT_WL_2G_SCC);
- }
-}
-
-static void _action_wl_2g_scc_v1(struct rtw89_dev *rtwdev)
-{
- struct rtw89_btc *btc = &rtwdev->btc;
- struct rtw89_btc_wl_info *wl = &btc->cx.wl;
- struct rtw89_btc_bt_info *bt = &btc->cx.bt0;
struct rtw89_btc_dm *dm = &btc->dm;
- struct rtw89_btc_wl_role_info_v1 *wl_rinfo = &wl->role_info_v1;
- u16 policy_type = BTC_CXP_OFF_BT;
- u32 dur;
+ u16 policy_type;
- if (btc->ant_type == BTC_ANT_DEDICATED) {
- policy_type = BTC_CXP_OFF_EQ0;
- } else {
- /* shared-antenna */
- switch (wl_rinfo->mrole_type) {
- case BTC_WLMROLE_STA_GC:
- dm->wl_scc.null_role1 = RTW89_WIFI_ROLE_STATION;
- dm->wl_scc.null_role2 = RTW89_WIFI_ROLE_P2P_CLIENT;
- dm->wl_scc.ebt_null = 0; /* no ext-slot-control */
- _action_by_bt(rtwdev);
- return;
- case BTC_WLMROLE_STA_STA:
- dm->wl_scc.null_role1 = RTW89_WIFI_ROLE_STATION;
- dm->wl_scc.null_role2 = RTW89_WIFI_ROLE_STATION;
- dm->wl_scc.ebt_null = 0; /* no ext-slot-control */
- _action_by_bt(rtwdev);
- return;
- case BTC_WLMROLE_STA_GC_NOA:
- case BTC_WLMROLE_STA_GO:
- case BTC_WLMROLE_STA_GO_NOA:
- dm->wl_scc.null_role1 = RTW89_WIFI_ROLE_STATION;
- dm->wl_scc.null_role2 = RTW89_WIFI_ROLE_NONE;
- dur = wl_rinfo->mrole_noa_duration;
-
- if (wl->status.map._4way) {
- dm->wl_scc.ebt_null = 0;
- policy_type = BTC_CXP_OFFE_WL;
- } else if (bt->link_info.status.map.connect == 0) {
- dm->wl_scc.ebt_null = 0;
- policy_type = BTC_CXP_OFFE_2GISOB;
- } else if (bt->link_info.a2dp_desc.exist &&
- dur < btc->bt_req_len[RTW89_PHY_0]) {
- dm->wl_scc.ebt_null = 1; /* tx null at EBT */
- policy_type = BTC_CXP_OFFE_2GBWMIXB2;
- } else if (bt->link_info.a2dp_desc.exist ||
- bt->link_info.pan_desc.exist) {
- dm->wl_scc.ebt_null = 1; /* tx null at EBT */
- policy_type = BTC_CXP_OFFE_2GBWISOB;
- } else {
- dm->wl_scc.ebt_null = 0;
- policy_type = BTC_CXP_OFFE_2GBWISOB;
- }
- break;
- default:
- break;
- }
- }
-
- _set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
- _set_policy(rtwdev, policy_type, BTC_ACT_WL_2G_SCC);
-}
-
-static void _action_wl_2g_scc_v2(struct rtw89_dev *rtwdev)
-{
- struct rtw89_btc *btc = &rtwdev->btc;
- struct rtw89_btc_wl_info *wl = &btc->cx.wl;
- struct rtw89_btc_bt_info *bt = &btc->cx.bt0;
- struct rtw89_btc_dm *dm = &btc->dm;
- struct rtw89_btc_wl_role_info_v2 *rinfo_v2 = &wl->role_info_v2;
- struct rtw89_btc_wl_role_info_v7 *rinfo_v7 = &wl->role_info_v7;
- u32 dur, mrole_type, mrole_noa_duration;
- u16 policy_type = BTC_CXP_OFF_BT;
-
- if (btc->ver->fwlrole == 2) {
- mrole_type = rinfo_v2->mrole_type;
- mrole_noa_duration = rinfo_v2->mrole_noa_duration;
- } else if (btc->ver->fwlrole == 7) {
- mrole_type = rinfo_v7->mrole_type;
- mrole_noa_duration = rinfo_v7->mrole_noa_duration;
- } else {
- return;
- }
-
- if (btc->ant_type == BTC_ANT_DEDICATED) {
- policy_type = BTC_CXP_OFF_EQ0;
- } else {
- /* shared-antenna */
- switch (mrole_type) {
- case BTC_WLMROLE_STA_GC:
- dm->wl_scc.null_role1 = RTW89_WIFI_ROLE_STATION;
- dm->wl_scc.null_role2 = RTW89_WIFI_ROLE_P2P_CLIENT;
- dm->wl_scc.ebt_null = 0; /* no ext-slot-control */
- _action_by_bt(rtwdev);
- return;
- case BTC_WLMROLE_STA_STA:
- dm->wl_scc.null_role1 = RTW89_WIFI_ROLE_STATION;
- dm->wl_scc.null_role2 = RTW89_WIFI_ROLE_STATION;
- dm->wl_scc.ebt_null = 0; /* no ext-slot-control */
- _action_by_bt(rtwdev);
- return;
- case BTC_WLMROLE_STA_GC_NOA:
- case BTC_WLMROLE_STA_GO:
- case BTC_WLMROLE_STA_GO_NOA:
- dm->wl_scc.null_role1 = RTW89_WIFI_ROLE_STATION;
- dm->wl_scc.null_role2 = RTW89_WIFI_ROLE_NONE;
- dur = mrole_noa_duration;
-
- if (wl->status.map._4way) {
- dm->wl_scc.ebt_null = 0;
- policy_type = BTC_CXP_OFFE_WL;
- } else if (bt->link_info.status.map.connect == 0) {
- dm->wl_scc.ebt_null = 0;
- policy_type = BTC_CXP_OFFE_2GISOB;
- } else if (bt->link_info.a2dp_desc.exist &&
- dur < btc->bt_req_len[RTW89_PHY_0]) {
- dm->wl_scc.ebt_null = 1; /* tx null at EBT */
- policy_type = BTC_CXP_OFFE_2GBWMIXB2;
- } else if (bt->link_info.a2dp_desc.exist ||
- bt->link_info.pan_desc.exist) {
- dm->wl_scc.ebt_null = 1; /* tx null at EBT */
- policy_type = BTC_CXP_OFFE_2GBWISOB;
- } else {
- dm->wl_scc.ebt_null = 0;
- policy_type = BTC_CXP_OFFE_2GBWISOB;
- }
- break;
- default:
- break;
- }
- }
-
- _set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
- _set_policy(rtwdev, policy_type, BTC_ACT_WL_2G_SCC);
-}
-
-static void _action_wl_2g_scc_v8(struct rtw89_dev *rtwdev)
-{
- struct rtw89_btc *btc = &rtwdev->btc;
- struct rtw89_btc_wl_info *wl = &btc->cx.wl;
- struct rtw89_btc_bt_info *bt = &btc->cx.bt0;
- struct rtw89_btc_dm *dm = &btc->dm;
- u16 policy_type = BTC_CXP_OFF_BT;
-
- if (btc->ant_type == BTC_ANT_SHARED) {
- if (wl->status.map._4way)
- policy_type = BTC_CXP_OFFE_WL;
- else if (bt->link_info.status.map.connect == 0)
- policy_type = BTC_CXP_OFFE_2GISOB;
- else
- policy_type = BTC_CXP_OFFE_2GBWISOB;
- } else {
- policy_type = BTC_CXP_OFF_EQ0;
- }
-
- dm->e2g_slot_limit = BTC_E2G_LIMIT_DEF;
+ if (!dm->tdd_bind.bt_smap.connect)
+ policy_type = BTC_CXP_OFFE_2GISOB;
+ else
+ policy_type = BTC_CXP_OFFE_2GBWISOB;
- _set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
+ _set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_PTA);
_set_policy(rtwdev, policy_type, BTC_ACT_WL_2G_SCC);
}
@@ -8180,14 +8109,7 @@ void _run_coex(struct rtw89_dev *rtwdev, enum btc_reason_and_action reason)
break;
case BTC_WLINK_2G_SCC:
bt->scan_rx_low_pri = true;
- if (ver->fwlrole == 0)
- _action_wl_2g_scc(rtwdev);
- else if (ver->fwlrole == 1)
- _action_wl_2g_scc_v1(rtwdev);
- else if (ver->fwlrole == 2 || ver->fwlrole == 7)
- _action_wl_2g_scc_v2(rtwdev);
- else if (ver->fwlrole == 8)
- _action_wl_2g_scc_v8(rtwdev);
+ _action_wl_2g_scc(rtwdev);
break;
case BTC_WLINK_2G_MCC:
bt->scan_rx_low_pri = true;
@@ -10115,7 +10037,8 @@ static const char *id_to_ant(u32 id)
CASE_BTC_ANTPATH_STR(W25G);
CASE_BTC_ANTPATH_STR(FREERUN);
CASE_BTC_ANTPATH_STR(WRFK);
- CASE_BTC_ANTPATH_STR(BRFK);
+ CASE_BTC_ANTPATH_STR(WRFK2);
+ CASE_BTC_ANTPATH_STR(PTA);
CASE_BTC_ANTPATH_STR(MAX);
default:
return "unknown";
diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index 21bdf229723c..eb814425f536 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -1832,10 +1832,11 @@ struct rtw89_btc_wl_role_info_bpos {
u16 nan: 1;
};
-struct rtw89_btc_wl_scc_ctrl {
- u8 null_role1;
- u8 null_role2;
- u8 ebt_null; /* if tx null at EBT slot */
+struct rtw89_btc_eslot_ctrl {
+ u8 en; /* 1: toggle tx-flow-ctrl (null 0/1), tx-pause by Ext-slot */
+ u8 nulltx_role1;
+ u8 nulltx_role2;
+ u8 nulltx_pre_time; /* null-tx time prior to EBT-start (from E2G-end) */
};
union rtw89_btc_wl_role_info_map {
@@ -3275,7 +3276,7 @@ struct rtw89_btc_dm {
struct rtw89_btc_rf_trx_para_v9 rf_trx_para;
struct rtw89_btc_wl_tx_limit_para wl_tx_limit;
struct rtw89_btc_dm_step dm_step;
- struct rtw89_btc_wl_scc_ctrl wl_scc;
+ struct rtw89_btc_eslot_ctrl eslot_ctrl;
struct rtw89_btc_trx_info trx_info;
union rtw89_btc_dm_error_map error;
struct rtw89_btc_bind_info tdd_bind;
--
2.25.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH rtw-next 8/9] wifi: rtw89: coex: Update scoreboard related logic for dual Bluetooth
2026-07-03 11:43 [PATCH rtw-next 0/9] wifi: rtw89: coex: implement components for dual Bluetooth Ping-Ke Shih
` (6 preceding siblings ...)
2026-07-03 11:43 ` [PATCH rtw-next 7/9] wifi: rtw89: coex: Add TDMA binding for dual MAC Ping-Ke Shih
@ 2026-07-03 11:43 ` Ping-Ke Shih
2026-07-03 11:43 ` [PATCH rtw-next 9/9] wifi: rtw89: coex: Add Co-RX logic Ping-Ke Shih
8 siblings, 0 replies; 10+ messages in thread
From: Ping-Ke Shih @ 2026-07-03 11:43 UTC (permalink / raw)
To: linux-wireless; +Cc: ku920601
From: Ching-Te Ku <ku920601@realtek.com>
Update WiFi status to each Bluetooth & collect status from the two
Bluetooth adapter by non-stop power zone register. To correct the meaning
of variable, redefine the naming for the variables.
Signed-off-by: Ching-Te Ku <ku920601@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/coex.c | 525 ++++++++++++++--------
drivers/net/wireless/realtek/rtw89/coex.h | 9 +
drivers/net/wireless/realtek/rtw89/core.c | 4 +-
drivers/net/wireless/realtek/rtw89/core.h | 33 +-
4 files changed, 370 insertions(+), 201 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c
index 86833b0cd47c..d45fab32ab46 100644
--- a/drivers/net/wireless/realtek/rtw89/coex.c
+++ b/drivers/net/wireless/realtek/rtw89/coex.c
@@ -461,7 +461,14 @@ enum btc_b2w_scoreboard {
BTC_BSCB_BT_LNAB1 = BIT(10),
BTC_BSCB_WLRFK = BIT(11),
BTC_BSCB_BT_HILNA = BIT(13),
+ BTC_BSCB_BT_HILNA_56G = BIT(14),
+ BTC_BSCB_CTCODE = BIT(15),
BTC_BSCB_BT_CONNECT = BIT(16),
+ BTC_BSCB_BT_CONNECT_56G = BIT(17),
+ BTC_BSCB_BT_LNAB0_56G = BIT(18),
+ BTC_BSCB_BT_LNAB1_56G = BIT(19),
+ BTC_BSCB_BT_15DOT4 = BIT(24),
+ BTC_BSCB_BT_PROTECT = BIT(27),
BTC_BSCB_PAN_ACT = BIT(28),
BTC_BSCB_HFP_ACT = BIT(29),
BTC_BSCB_PATCH_CODE = BIT(30),
@@ -808,6 +815,8 @@ enum btc_reset_module {
BTC_RESET_CXDM = BIT(0) | BIT(1),
BTC_RESET_BTINFO = BIT(3),
BTC_RESET_MDINFO = BIT(4),
+ BTC_RESET_BT_PSD_DM = BIT(5),
+ BTC_RESET_BTINFO2 = BIT(6),
BTC_RESET_ALL = GENMASK(7, 0),
};
@@ -905,8 +914,9 @@ enum btc_reason_and_action {
static void _run_coex(struct rtw89_dev *rtwdev,
enum btc_reason_and_action reason);
-static void _write_scbd(struct rtw89_dev *rtwdev, u32 val, bool state);
-static void _update_bt_scbd(struct rtw89_dev *rtwdev, bool only_update);
+static void _write_scbd(struct rtw89_dev *rtwdev, u8 bid, u32 val, bool state);
+static u8 _sned_h2c_w2bscbd(struct rtw89_dev *rtwdev, bool force_exec, u8 bid);
+static void _update_bt_scbd(struct rtw89_dev *rtwdev, u8 bid);
static int _send_fw_cmd(struct rtw89_dev *rtwdev, u8 h2c_class, u8 h2c_func,
void *param, u16 len)
@@ -1272,11 +1282,6 @@ static void _chk_btc_err(struct rtw89_dev *rtwdev, u8 type, u32 cnt)
dm->cnt_dm[BTC_DCNT_BTCNT_HANG]++;
else
dm->cnt_dm[BTC_DCNT_BTCNT_HANG] = 0;
-
- if ((dm->cnt_dm[BTC_DCNT_BTCNT_HANG] >= BTC_CHK_HANG_MAX &&
- bt->enable.now) || (!dm->cnt_dm[BTC_DCNT_BTCNT_HANG] &&
- !bt->enable.now))
- _update_bt_scbd(rtwdev, false);
break;
case BTC_DCNT_WL_SLOT_DRIFT:
if (cnt >= BTC_CHK_WLSLOT_DRIFT_MAX)
@@ -1755,7 +1760,7 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
rtwdev->chip->ops->btc_update_bt_cnt(rtwdev);
_chk_btc_err(rtwdev, BTC_DCNT_BTCNT_HANG, 0);
- bt->bcnt[BTC_BCNT_POLUT] =
+ bt->bcnt[BTC_BCNT_POLLUTED] =
rtw89_mac_get_plt_cnt(rtwdev,
RTW89_MAC_0);
}
@@ -1778,7 +1783,7 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
le32_to_cpu(prpt->v4.bt_cnt[BTC_BCNT_LO_TX]);
bt->bcnt[BTC_BCNT_LOPRI_RX] =
le32_to_cpu(prpt->v4.bt_cnt[BTC_BCNT_LO_RX]);
- bt->bcnt[BTC_BCNT_POLUT] =
+ bt->bcnt[BTC_BCNT_POLLUTED] =
le32_to_cpu(prpt->v4.bt_cnt[BTC_BCNT_POLLUTED]);
_chk_btc_err(rtwdev, BTC_DCNT_BTCNT_HANG, 0);
@@ -1810,7 +1815,7 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
le16_to_cpu(prpt->v5.bt_cnt[BTC_BCNT_LO_TX]);
bt->bcnt[BTC_BCNT_LOPRI_RX] =
le16_to_cpu(prpt->v5.bt_cnt[BTC_BCNT_LO_RX]);
- bt->bcnt[BTC_BCNT_POLUT] =
+ bt->bcnt[BTC_BCNT_POLLUTED] =
le16_to_cpu(prpt->v5.bt_cnt[BTC_BCNT_POLLUTED]);
_chk_btc_err(rtwdev, BTC_DCNT_BTCNT_HANG, 0);
@@ -1837,7 +1842,7 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
le16_to_cpu(prpt->v105.bt_cnt[BTC_BCNT_LO_TX_V105]);
bt->bcnt[BTC_BCNT_LOPRI_RX] =
le16_to_cpu(prpt->v105.bt_cnt[BTC_BCNT_LO_RX_V105]);
- bt->bcnt[BTC_BCNT_POLUT] =
+ bt->bcnt[BTC_BCNT_POLLUTED] =
le16_to_cpu(prpt->v105.bt_cnt[BTC_BCNT_POLLUTED_V105]);
_chk_btc_err(rtwdev, BTC_DCNT_BTCNT_HANG, 0);
@@ -2791,14 +2796,14 @@ static void _fw_set_policy(struct rtw89_dev *rtwdev, u16 policy_type,
if (dm->tdma.rxflctrl == CXFLC_NULLP ||
dm->tdma.rxflctrl == CXFLC_QOSNULL)
- btc->lps = 1;
+ btc->btc_ctrl_lps = 1;
else
- btc->lps = dm->lps_ctrl_scbd;
+ btc->btc_ctrl_lps = dm->lps_ctrl_scbd;
dm->lps_ctrl_scbd_last = dm->lps_ctrl_scbd;
- if (btc->lps == 1)
- rtw89_set_coex_ctrl_lps(rtwdev, btc->lps);
+ if (btc->btc_ctrl_lps == 1)
+ rtw89_set_coex_ctrl_lps(rtwdev, btc->btc_ctrl_lps);
ret = _send_fw_cmd(rtwdev, BTFC_SET, SET_CX_POLICY,
btc->policy, btc->policy_len);
@@ -2813,8 +2818,8 @@ static void _fw_set_policy(struct rtw89_dev *rtwdev, u16 policy_type,
if (btc->update_policy_force)
btc->update_policy_force = false;
- if (btc->lps == 0)
- rtw89_set_coex_ctrl_lps(rtwdev, btc->lps);
+ if (btc->btc_ctrl_lps == 0)
+ rtw89_set_coex_ctrl_lps(rtwdev, btc->btc_ctrl_lps);
}
static void _fw_set_drv_info(struct rtw89_dev *rtwdev, u8 index)
@@ -2913,21 +2918,35 @@ void btc_fw_event(struct rtw89_dev *rtwdev, u8 evt_id, void *data, u32 len)
{
struct rtw89_btc *btc = &rtwdev->btc;
struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
+ struct rtw89_btc_bt_info *bt = &btc->cx.bt0;
+ u8 i;
- rtw89_debug(rtwdev, RTW89_DBG_BTC,
- "[BTC], %s(): evt_id:%d len:%d\n",
- __func__, evt_id, len);
+ _parse_btc_report(rtwdev, pfwinfo, data, len);
- if (!len || !data)
+ if (!rtwdev->chip->scbd)
return;
- switch (evt_id) {
- case BTF_EVNT_RPT:
- _parse_btc_report(rtwdev, pfwinfo, data, len);
- break;
- default:
- break;
+ if (!btc->dm.scbd_b2w_update)
+ return; /* skip if init or no-update */
+
+ for (i = BTC_BT_1ST; i <= BTC_BT_2ND; i++) {
+ bt = (i == BTC_BT_1ST) ? &btc->cx.bt0 : &btc->cx.bt1;
+
+ if (bt->scbd_c2h != bt->scbd_rb) {
+ /* if btx b2w scbd non-sync */
+ rtw89_debug(rtwdev, RTW89_DBG_BTC,
+ "[BTC], %s() bt%d:c2h->0x%08x, rb->0x%08x\n",
+ __func__, i, bt->scbd_c2h, bt->scbd_rb);
+ bt->scbd_c2h = bt->scbd_rb;
+ _update_bt_scbd(rtwdev, i);
+ btc->dm.scbd_b2w_update = false;
+ }
}
+
+ if (!btc->dm.scbd_b2w_update)
+ _run_coex(rtwdev, BTC_RSN_UPDATE_BT_SCBD);
+ else
+ btc->dm.scbd_b2w_update = 0;
}
static void _set_gnt(struct rtw89_dev *rtwdev, u8 phy_map, u8 wl_state, u8 bt_state)
@@ -3298,7 +3317,7 @@ static void _set_bt_rx_gain(struct rtw89_dev *rtwdev, bool force_exec, u8 bid,
if (buf[0] != BTC_BT_RX_NORMAL_LVL)
state = true;
- _write_scbd(rtwdev, scbd_bit, state);
+ _write_scbd(rtwdev, bid, scbd_bit, state);
}
}
@@ -3406,7 +3425,7 @@ static void _set_rf_trx_para(struct rtw89_dev *rtwdev)
if (dm->fddt_train) {
_set_wl_rx_gain(rtwdev, 1, RTW89_PHY_0);
- _write_scbd(rtwdev, BTC_WSCB_RXGAIN, true);
+ _write_scbd(rtwdev, bid, BTC_WSCB_RXGAIN, true);
} else {
_set_wl_tx_power(rtwdev, para.wl_tx_power[RTW89_PHY_0], RTW89_PHY_0);
_set_wl_rx_gain(rtwdev, para.wl_rx_gain[RTW89_PHY_0], RTW89_PHY_0);
@@ -3899,14 +3918,22 @@ static void _set_tdma_bind(struct rtw89_dev *rtwdev, bool tdma_on)
struct rtw89_btc_dm *dm = &rtwdev->btc.dm;
struct rtw89_btc_bind_info *bind;
u8 null_role = RTW89_WIFI_ROLE_STATION;
+ u8 bt_sel;
if (dm->tdd_en)
bind = &dm->tdd_bind; /* tdd = 1 && fdd = 0 or 1 */
else
bind = &dm->fdd_bind; /* tdd = 0 && fdd = 1 */
+ if (bind->bt_sel >= (BIT(BTC_BT_1ST) | BIT(BTC_BT_2ND)))
+ bt_sel = BTC_ALL_BT;
+ else if (bind->bt_sel == BIT(BTC_BT_2ND))
+ bt_sel = BTC_BT_2ND;
+ else
+ bt_sel = BTC_BT_1ST;
+
/* notify BT TDMA on/off by scoreboard for ACL/Scan schedule */
- _write_scbd(rtwdev, BTC_WSCB_TDMA, tdma_on);
+ _write_scbd(rtwdev, bt_sel, BTC_WSCB_TDMA, tdma_on);
/*
* set hwb/bt bind to TDMA policy parameter
@@ -5849,7 +5876,7 @@ static void _set_bt_rx_agc(struct rtw89_dev *rtwdev)
if (bt_hi_lna_rx == bt->hi_lna_rx)
return;
- _write_scbd(rtwdev, BTC_WSCB_BT_HILNA, bt_hi_lna_rx);
+ _write_scbd(rtwdev, BTC_BT_1ST, BTC_WSCB_BT_HILNA, bt_hi_lna_rx);
}
static void _set_bt_rx_scan_pri(struct rtw89_dev *rtwdev)
@@ -5857,7 +5884,8 @@ static void _set_bt_rx_scan_pri(struct rtw89_dev *rtwdev)
struct rtw89_btc *btc = &rtwdev->btc;
struct rtw89_btc_bt_info *bt = &btc->cx.bt0;
- _write_scbd(rtwdev, BTC_WSCB_RXSCAN_PRI, (bool)(!!bt->scan_rx_low_pri));
+ _write_scbd(rtwdev, BTC_ALL_BT, BTC_WSCB_RXSCAN_PRI,
+ (bool)(!!bt->scan_rx_low_pri));
}
static void _wl_req_mac(struct rtw89_dev *rtwdev, u8 mac)
@@ -5897,6 +5925,7 @@ static void _action_common(struct rtw89_dev *rtwdev)
struct rtw89_btc_bt_info *bt = &btc->cx.bt0;
struct rtw89_btc_dm *dm = &btc->dm;
u32 bt_rom_code_id, bt_fw_ver;
+ u8 i;
if (btc->ver->fwlrole == 8)
_wl_req_mac(rtwdev, rinfo_v8->pta_req_band);
@@ -5929,13 +5958,8 @@ static void _action_common(struct rtw89_dev *rtwdev)
rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_MREG, 1);
}
- if (wl->scbd_change) {
- rtw89_mac_cfg_sb(rtwdev, wl->scbd);
- rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], write scbd: 0x%08x\n",
- wl->scbd);
- wl->scbd_change = false;
- wl->wcnt[BTC_WCNT_SCBDUPDATE]++;
- }
+ for (i = BTC_BT_1ST; i <= BTC_BT_2ND; i++)
+ _sned_h2c_w2bscbd(rtwdev, false, i);
if (btc->ver->fcxosi) {
if (memcmp(&dm->ost_info_last, &dm->ost_info,
@@ -6187,42 +6211,97 @@ static void _action_wl_2g_nan(struct rtw89_dev *rtwdev)
}
}
-static u32 _read_scbd(struct rtw89_dev *rtwdev)
+static u8 _sned_h2c_w2bscbd(struct rtw89_dev *rtwdev, bool force_exec, u8 bid)
{
- const struct rtw89_chip_info *chip = rtwdev->chip;
struct rtw89_btc *btc = &rtwdev->btc;
- u32 scbd_val = 0;
+ struct rtw89_btc_cx *cx = &btc->cx;
+ struct rtw89_btc_wl_info *wl = &cx->wl;
+ u8 cnt_idx = BTC_WCNT_SCBDUPDATE;
+ u8 h2c_func = SET_IOFLD_SCBD;
+ u8 buf[4];
- if (!chip->scbd)
- return 0;
+ if (bid == BTC_BT_2ND) {
+ if (!(rtwdev->chip->para_ver & BTC_FEAT_DUAL_BT))
+ return 0;
+
+ h2c_func |= BT_H2C_FUNC_BT2ND;
+ cnt_idx = BTC_WCNT_SCBDUPDATE2;
+ }
- scbd_val = rtw89_mac_get_sb(rtwdev);
- rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], read scbd: 0x%08x\n",
- scbd_val);
+ if (wl->scbd_chg[bid] || force_exec) {
+ /* Add delay to avoid BT FW loss information */
- btc->cx.bt0.bcnt[BTC_BCNT_SCBDREAD]++;
- return scbd_val;
+ btc_dw2b(buf, 0, (wl->scbd[bid] | BIT(31))); /* trig */
+ if (rtwdev->chip->para_ver & BTC_FEAT_H2C_MACRO) {
+ if (!_send_fw_cmd(rtwdev, BTFC_SET,
+ h2c_func, buf, sizeof(buf)))
+ return 0;
+ } else {
+ rtw89_mac_cfg_sb(rtwdev, wl->scbd[bid]);
+ }
+ wl->scbd_chg[bid] = 0;
+ wl->wcnt[cnt_idx]++;
+ rtw89_debug(rtwdev, RTW89_DBG_BTC,
+ "[BTC], %s() write BT%d scbd:0x%08x\n",
+ __func__, bid, wl->scbd[bid]);
+ }
+ return 1;
}
-static void _write_scbd(struct rtw89_dev *rtwdev, u32 val, bool state)
+static void _write_scbd(struct rtw89_dev *rtwdev, u8 bid, u32 val, bool state)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
struct rtw89_btc *btc = &rtwdev->btc;
struct rtw89_btc_wl_info *wl = &btc->cx.wl;
- u32 scbd_val = 0;
- u8 force_exec = false;
+ struct rtw89_btc_dm *dm = &btc->dm;
+ u8 force_exec, id, id_start, id_stop;
+ u32 scbd = 0;
if (!chip->scbd)
return;
- scbd_val = state ? wl->scbd | val : wl->scbd & ~val;
+ if (bid == BTC_ALL_BT) {
+ id_start = BTC_BT_1ST;
+ id_stop = BTC_BT_2ND;
+ } else {
+ id_start = bid;
+ id_stop = bid;
+ }
- if (val & BTC_WSCB_ACTIVE || val & BTC_WSCB_ON)
- force_exec = true;
+ for (id = id_start; id <= id_stop; id++) {
+ force_exec = false;
+ if (!(rtwdev->chip->para_ver & BTC_FEAT_DUAL_BT) &&
+ id == BTC_BT_2ND)
+ continue;
- if (scbd_val != wl->scbd || force_exec) {
- wl->scbd = scbd_val;
- wl->scbd_change = true;
+ if (state)
+ scbd = wl->scbd[id] | val;
+ else
+ scbd = wl->scbd[id] & (~val);
+
+ if (val & BTC_WSCB_CTCODE ||
+ val & BTC_WSCB_RXGAIN ||
+ val & BTC_WSCB_RXGAIN_56G) { /* instant exec */
+ force_exec = true;
+ wl->scbd[id] = scbd;
+ dm->scbd_write_instant = 1;
+ if (rtwdev->chip->para_ver & BTC_FEAT_H2C_MACRO)
+ _sned_h2c_w2bscbd(rtwdev, force_exec, id);
+ else
+ rtw89_mac_cfg_sb(rtwdev, wl->scbd[id]);
+ dm->scbd_write_instant = 0;
+ } else if ((val & BTC_WSCB_ACTIVE ||
+ val & BTC_WSCB_ON ||
+ val & BTC_WSCB_WLRFK) ||
+ scbd != wl->scbd[id]) {
+ /*
+ * Just update wl->scbd[] and set wl->scbd_chg[],
+ * moved "Write scoreboard I/O" to _action_common()
+ * _write_scbd will be executed if run_coex()
+ */
+ wl->scbd[id] = scbd;
+ wl->scbd_chg[id] = 1;
+ }
}
}
@@ -7522,34 +7601,27 @@ void rtw89_coex_rfk_chk_work(struct wiphy *wiphy, struct wiphy_work *work)
wl->wcnt[BTC_WCNT_RFK_TIMEOUT]++;
dm->error.map.wl_rfk_timeout = true;
wl->rfk_info.state = BTC_WRFK_STOP;
- _write_scbd(rtwdev, BTC_WSCB_WLRFK, false);
+ _write_scbd(rtwdev, BTC_ALL_BT, BTC_WSCB_WLRFK, false);
_run_coex(rtwdev, BTC_RSN_RFK_CHK_WORK);
}
}
-static void _update_bt_scbd(struct rtw89_dev *rtwdev, bool only_update)
+static void _update_bt_scbd(struct rtw89_dev *rtwdev, u8 bid)
{
+ struct rtw89_btc_bt_link_info *bt_2g, *bt_56g;
struct rtw89_btc *btc = &rtwdev->btc;
- struct rtw89_btc_bt_info *bt = &btc->cx.bt0;
const struct rtw89_btc_ver *ver = btc->ver;
- struct rtw89_btc_wl_info *wl = &btc->cx.wl;
- struct rtw89_btc_dm *dm = &rtwdev->btc.dm;
- bool bt_link_change = false, lps_ctrl = false;
- u32 val, any_bt_connect;
- u8 mode;
-
- if (rtwdev->chip->scbd)
- return;
-
- rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s\n", __func__);
+ struct rtw89_btc_cx *cx = &btc->cx;
+ struct rtw89_btc_wl_info *wl = &cx->wl;
+ struct rtw89_btc_dm *dm = &btc->dm;
+ struct rtw89_btc_bt_info *bt;
+ u32 val, any_bt_connect, any_bt_6g_connect = 0;
+ u8 id, id_start, id_stop, mode;
+ bool bt_link_change = false;
+ bool lps_ctrl = false;
- val = _read_scbd(rtwdev);
- if (val == BTC_SCB_INV_VALUE) {
- rtw89_debug(rtwdev, RTW89_DBG_BTC,
- "[BTC], %s(): return by invalid scbd value\n",
- __func__);
+ if (!rtwdev->chip->scbd || bid > BTC_ALL_BT)
return;
- }
if (ver->fwlrole == 0)
mode = wl->role_info.link_mode;
@@ -7564,66 +7636,112 @@ static void _update_bt_scbd(struct rtw89_dev *rtwdev, bool only_update)
else
return;
- if (!(val & BTC_BSCB_ON))
- bt->enable.now = 0;
- else
- bt->enable.now = 1;
+ if (bid == BTC_ALL_BT) {
+ id_start = BTC_BT_1ST;
+ id_stop = BTC_BT_2ND;
+ } else {
+ id_start = bid;
+ id_stop = bid;
+ }
+
+ dm->lps_ctrl_change = false;
+ rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s()\n", __func__);
- if (bt->enable.now != bt->enable.last)
- bt_link_change = true;
+ for (id = id_start; id <= id_stop; id++) {
+ bt = (id == BTC_BT_1ST) ? &cx->bt0 : &cx->bt1;
+ bt_2g = &bt->link_info;
+ bt_56g = &bt->link_info_56g;
- /* reset bt info if bt re-enable */
- if (bt->enable.now && !bt->enable.last) {
- _reset_btc_var(rtwdev, BTC_RESET_BTINFO);
- bt->bcnt[BTC_BCNT_REENABLE]++;
- bt->enable.now = 1;
- }
+ if (!(rtwdev->chip->para_ver & BTC_FEAT_DUAL_BT) && id == BTC_BT_2ND)
+ break;
+
+ val = bt->scbd_c2h;
- bt->enable.last = bt->enable.now;
- bt->scbd = val;
- bt->mbx_avl = !!(val & BTC_BSCB_ACT);
+ if (val == 0xffffffff) {
+ rtw89_debug(rtwdev, RTW89_DBG_BTC,
+ "[BTC], %s return by invalid scbd value\n",
+ __func__);
+ return;
+ }
- if (bt->whql_test != !!(val & BTC_BSCB_WHQL))
- bt_link_change = true;
+ if (!(val & BTC_BSCB_ON))
+ bt->enable.now = 0;
+ else
+ bt->enable.now = 1;
- bt->whql_test = !!(val & BTC_BSCB_WHQL);
- bt->btg_type = val & BTC_BSCB_BT_S1 ? BTC_BT_BTG : BTC_BT_ALONE;
- bt->link_info.a2dp_desc.exist = !!(val & BTC_BSCB_A2DP_ACT);
- bt->link_info.pan_desc.exist = !!(val & BTC_BSCB_PAN_ACT);
- bt->link_info.hfp_desc.exist = !!(val & BTC_BSCB_HFP_ACT);
+ if (bt->enable.now != bt->enable.last)
+ bt_link_change = true;
- bt->lna_constrain = !!(val & BTC_BSCB_BT_LNAB0) +
- !!(val & BTC_BSCB_BT_LNAB1) * 2 + 4;
+ /* reset bt info if bt re-enable */
+ if (bt->enable.now && !bt->enable.last) {
+ if (id == BTC_BT_1ST)
+ _reset_btc_var(rtwdev, BTC_RESET_BTINFO);
+ else
+ _reset_btc_var(rtwdev, BTC_RESET_BTINFO2);
- /* if rfk run 1->0 */
- if (bt->rfk_info.map.run && !(val & BTC_BSCB_RFK_RUN))
- bt_link_change = true;
+ bt->bcnt[BTC_BCNT_REENABLE]++;
+ bt->enable.now = 1;
+ bt->rf_band_map = BIT(RTW89_BAND_2G);
+ bt->link_weight[BTC_BT_B2G] = 5; /* no-profile */
+ }
+ bt->enable.last = bt->enable.now;
- bt->rfk_info.map.run = !!(val & BTC_BSCB_RFK_RUN);
- bt->rfk_info.map.req = !!(val & BTC_BSCB_RFK_REQ);
- bt->hi_lna_rx = !!(val & BTC_BSCB_BT_HILNA);
- any_bt_connect = !!(val & BTC_BSCB_BT_CONNECT);
+ /* if BT will disconnect and adopt protect plan */
+ if ((val & BTC_BSCB_BT_PROTECT) &&
+ !(bt->scbd & BTC_BSCB_BT_PROTECT))
+ bt->bcnt[BTC_BCNT_PROTECT]++;
- /* if connect change */
- if (bt->link_info.status.map.connect != any_bt_connect)
- bt_link_change = true;
+ bt->mbx_avl = !!(val & BTC_BSCB_ACT);
+ if (bt->whql_test != !!(val & BTC_BSCB_WHQL))
+ bt_link_change = true;
- /* if specific profile exist */
- if (((bt->link_info.a2dp_desc.exist || bt->link_info.pan_desc.exist ||
- bt->link_info.hfp_desc.exist) && mode == BTC_WLINK_2G_STA) ||
- bt->whql_test)
- lps_ctrl = true;
+ bt->whql_test = !!(val & BTC_BSCB_WHQL);
+ bt->btg_type = (val & BTC_BSCB_BT_S1 ? BTC_BT_BTG : BTC_BT_ALONE);
- if (dm->lps_ctrl_scbd != lps_ctrl) {
- dm->lps_ctrl_scbd = lps_ctrl;
- bt_link_change = true;
- dm->lps_ctrl_change = true;
- } else {
- dm->lps_ctrl_change = false;
- }
+ bt_2g->a2dp_desc.exist = !!(val & BTC_BSCB_A2DP_ACT);
+ bt_2g->pan_desc.exist = !!(val & BTC_BSCB_PAN_ACT);
+ bt_2g->hfp_desc.exist = !!(val & BTC_BSCB_HFP_ACT);
- bt->link_info.status.map.connect = any_bt_connect;
- bt->run_patch_code = !!(val & BTC_BSCB_PATCH_CODE);
+ bt->lna_constrain = 4 + !!(val & BTC_BSCB_BT_LNAB0) +
+ !!(val & BTC_BSCB_BT_LNAB1) * 2;
+
+ if (rtwdev->chip->para_ver & BTC_FEAT_DUAL_BT) {
+ if (val & BTC_BSCB_BT_15DOT4)
+ bt->func_type |= (BTC_BTF_THREAD | BTC_BTF_ZB);
+ else
+ bt->func_type &= ~(BTC_BTF_THREAD | BTC_BTF_ZB);
+ }
+
+ bt->hi_lna_rx = !!(val & BTC_BSCB_BT_HILNA);
+ any_bt_connect = !!(val & BTC_BSCB_BT_CONNECT);
+
+ /* if connect change */
+ if (bt_2g->status.map.connect != any_bt_connect ||
+ bt_56g->status.map.connect != any_bt_6g_connect) {
+ bt_link_change = true;
+ bt_2g->status.map.connect = any_bt_connect;
+ bt_56g->status.map.connect = any_bt_6g_connect;
+ }
+
+ /* if specific profile exist */
+ if (((bt->link_info.a2dp_desc.exist ||
+ bt->link_info.pan_desc.exist ||
+ bt->link_info.hfp_desc.exist) &&
+ mode == BTC_WLINK_2G_STA) ||
+ bt->whql_test)
+ lps_ctrl = true;
+
+ if (dm->lps_ctrl_scbd != lps_ctrl) {
+ dm->lps_ctrl_scbd = lps_ctrl;
+ bt_link_change = true;
+ dm->lps_ctrl_change = true;
+ } else {
+ dm->lps_ctrl_change = false;
+ }
+
+ bt->run_patch_code = !!(val & BTC_BSCB_PATCH_CODE);
+ bt->scbd = val;
+ }
if (bt_link_change) {
rtw89_debug(rtwdev, RTW89_DBG_BTC,
@@ -7651,26 +7769,6 @@ static void _update_bt_txpwr_info(struct rtw89_dev *rtwdev, u8 *buf, u32 len)
memcpy(&b->bt_txpwr_desc, &buf[2], sizeof(b->bt_txpwr_desc));
}
-static bool _chk_wl_rfk_request(struct rtw89_dev *rtwdev)
-{
- struct rtw89_btc *btc = &rtwdev->btc;
- struct rtw89_btc_cx *cx = &btc->cx;
- struct rtw89_btc_bt_info *bt = &cx->bt0;
-
- _update_bt_scbd(rtwdev, true);
-
- cx->wl.wcnt[BTC_WCNT_RFK_REQ]++;
-
- if ((bt->rfk_info.map.run || bt->rfk_info.map.req) &&
- !bt->rfk_info.map.timeout) {
- cx->wl.wcnt[BTC_WCNT_RFK_REJECT]++;
- } else {
- cx->wl.wcnt[BTC_WCNT_RFK_GO]++;
- return true;
- }
- return false;
-}
-
static void _set_bind_info(struct rtw89_btc *btc, u8 type)
{
struct rtw89_btc_cx *cx = &btc->cx;
@@ -8181,7 +8279,7 @@ void rtw89_btc_ntfy_poweroff(struct rtw89_dev *rtwdev)
btc->cx.wl.status.map.busy = 0;
wl->status.map.lps = BTC_LPS_OFF;
- _write_scbd(rtwdev, BTC_WSCB_ALL, false);
+ _write_scbd(rtwdev, BTC_ALL_BT, BTC_WSCB_ALL, false);
_run_coex(rtwdev, BTC_RSN_NTFY_POWEROFF);
rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_ALL, 0);
@@ -8266,24 +8364,22 @@ void rtw89_btc_ntfy_init(struct rtw89_dev *rtwdev, u8 mode)
return;
}
+ btc->cx.bt0.enable.now = 1;
+ btc->cx.bt0.run_patch_code = 1;
if (rtwdev->chip->para_ver & BTC_FEAT_DUAL_BT) {
btc->cx.bt1.enable.now = 1;
btc->cx.bt1.run_patch_code = 1;
}
- if (rtwdev->chip->para_ver & BTC_FEAT_H2C_MACRO) {
- btc->cx.bt0.enable.now = 1;
- btc->cx.bt0.run_patch_code = 1;
+ if (rtwdev->chip->para_ver & BTC_FEAT_H2C_MACRO)
btc->io_oflld_type = BTC_IO_OFLD_BTC_H2C;
- } else {
+ else
btc->io_oflld_type = BTC_IO_OFLD_NO_SUPPORT;
- _update_bt_scbd(rtwdev, true);
- }
chip->ops->btc_set_rfe(rtwdev);
chip->ops->btc_init_cfg(rtwdev);
- _write_scbd(rtwdev,
+ _write_scbd(rtwdev, BTC_ALL_BT,
BTC_WSCB_ACTIVE | BTC_WSCB_ON | BTC_WSCB_BTLOG, true);
if (rtw89_mac_get_ctrl_path(rtwdev)) {
@@ -8842,16 +8938,16 @@ void rtw89_btc_ntfy_radio_state(struct rtw89_dev *rtwdev, enum btc_rfctrl rf_sta
if (rf_state == BTC_RFCTRL_WL_ON) {
rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_MREG, true);
val = BTC_WSCB_ACTIVE | BTC_WSCB_ON | BTC_WSCB_BTLOG;
- _write_scbd(rtwdev, val, true);
+ _write_scbd(rtwdev, BTC_ALL_BT, val, true);
chip->ops->btc_init_cfg(rtwdev);
} else {
rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_ALL, false);
if (rf_state == BTC_RFCTRL_FW_CTRL)
- _write_scbd(rtwdev, BTC_WSCB_ACTIVE, false);
+ _write_scbd(rtwdev, BTC_ALL_BT, BTC_WSCB_ACTIVE, false);
else if (rf_state == BTC_RFCTRL_WL_OFF)
- _write_scbd(rtwdev, BTC_WSCB_ALL, false);
+ _write_scbd(rtwdev, BTC_ALL_BT, BTC_WSCB_ALL, false);
else
- _write_scbd(rtwdev, BTC_WSCB_ACTIVE, false);
+ _write_scbd(rtwdev, BTC_ALL_BT, BTC_WSCB_ACTIVE, false);
}
btc->dm.cnt_dm[BTC_DCNT_BTCNT_HANG] = 0;
@@ -8883,27 +8979,26 @@ static bool _ntfy_wl_rfk(struct rtw89_dev *rtwdev, u8 phy_path,
switch (state) {
case BTC_WRFK_START:
- result = _chk_wl_rfk_request(rtwdev);
- wl->rfk_info.state = result ? BTC_WRFK_START : BTC_WRFK_STOP;
-
- _write_scbd(rtwdev, BTC_WSCB_WLRFK, result);
+ result = BTC_WRFK_ALLOW;
+ wl->rfk_info.state = BTC_WRFK_START;
+ btc->cx.wl.wcnt[BTC_WCNT_RFK_REQ]++;
+ btc->cx.wl.wcnt[BTC_WCNT_RFK_GO]++;
btc->dm.cnt_notify[BTC_NCNT_WL_RFK]++;
+
+ _write_scbd(rtwdev, BTC_ALL_BT, BTC_WSCB_WLRFK, true);
break;
case BTC_WRFK_ONESHOT_START:
case BTC_WRFK_ONESHOT_STOP:
- if (wl->rfk_info.state == BTC_WRFK_STOP) {
- result = BTC_WRFK_REJECT;
- } else {
- result = BTC_WRFK_ALLOW;
- wl->rfk_info.state = state;
- }
+ wl->rfk_info.state = state;
+ if (type != BTC_WRFKT_RXDCK)
+ return BTC_WRFK_ALLOW;
break;
case BTC_WRFK_STOP:
result = BTC_WRFK_ALLOW;
wl->rfk_info.state = BTC_WRFK_STOP;
- _write_scbd(rtwdev, BTC_WSCB_WLRFK, false);
+ _write_scbd(rtwdev, BTC_ALL_BT, BTC_WSCB_WLRFK, false);
wiphy_delayed_work_cancel(rtwdev->hw->wiphy, &rtwdev->coex_rfk_chk_work);
break;
default:
@@ -8927,7 +9022,7 @@ static bool _ntfy_wl_rfk(struct rtw89_dev *rtwdev, u8 phy_path,
"[BTC], %s()_finish: rfk_cnt=%d, result=%d\n",
__func__, btc->dm.cnt_notify[BTC_NCNT_WL_RFK], result);
- return result == BTC_WRFK_ALLOW;
+ return result;
}
void rtw89_btc_ntfy_wl_rfk(struct rtw89_dev *rtwdev, u8 phy_map,
@@ -9160,7 +9255,7 @@ void rtw89_btc_ntfy_wl_sta(struct rtw89_dev *rtwdev)
rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): busy=%d\n",
__func__, !!wl->status.map.busy);
- _write_scbd(rtwdev, BTC_WSCB_WLBUSY, (!!wl->status.map.busy));
+ _write_scbd(rtwdev, BTC_ALL_BT, BTC_WSCB_WLBUSY, (!!wl->status.map.busy));
if (data.is_traffic_change)
_fw_set_drv_info(rtwdev, CXDRVINFO_ROLE);
@@ -9251,6 +9346,7 @@ void rtw89_btc_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb,
struct rtw89_btc_bt_info *bt = &rtwdev->btc.cx.bt0;
struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
u8 *buf = &skb->data[RTW89_C2H_HEADER_LEN];
+ u8 bid = BTC_BT_1ST;
len -= RTW89_C2H_HEADER_LEN;
@@ -9261,6 +9357,12 @@ void rtw89_btc_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb,
if (class != BTFC_FW_EVENT)
return;
+ if (func & BT_C2H_FUNC_BT2ND) {
+ bid = BTC_BT_2ND;
+ func &= ~BT_C2H_FUNC_BT2ND;
+ bt = &btc->cx.bt1;
+ }
+
func = rtw89_btc_c2h_get_index_by_ver(rtwdev, func);
pfwinfo->cnt_c2h++;
@@ -9280,10 +9382,15 @@ void rtw89_btc_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb,
_update_bt_info(rtwdev, buf, len);
break;
case BTF_EVNT_BT_SCBD:
- rtw89_debug(rtwdev, RTW89_DBG_BTC,
- "[BTC], handle C2H BT SCBD with data %8ph\n", buf);
bt->bcnt[BTC_BCNT_SCBDUPDATE]++;
- _update_bt_scbd(rtwdev, false);
+ bt->scbd_c2h = ((buf[3] << 24) | (buf[2] << 16) |
+ (buf[1] << 8) | (buf[0]));
+ bt->scbd_rb = bt->scbd_c2h;
+ rtw89_debug(rtwdev, RTW89_DBG_BTC,
+ "[BTC], handle C2H BT%d SCBD with data 0x%08x\n",
+ bid, bt->scbd_c2h);
+ _update_bt_scbd(rtwdev, bid);
+ _run_coex(rtwdev, BTC_RSN_UPDATE_BT_SCBD);
break;
case BTF_EVNT_BT_PSD:
break;
@@ -9300,7 +9407,7 @@ void rtw89_btc_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb,
btc->dm.cnt_dm[BTC_DCNT_CX_RUNINFO]++;
break;
case BTF_EVNT_BT_QUERY_TXPWR:
- bt->bcnt[BTC_BCNT_BTTXPWR_UPDATE]++;
+ bt->bcnt[BTC_BCNT_TXPWR_UPDATE]++;
_update_bt_txpwr_info(rtwdev, buf, len);
}
}
@@ -9680,7 +9787,7 @@ static int _show_bt_info(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
bt->bcnt[BTC_BCNT_HIPRI_TX],
bt->bcnt[BTC_BCNT_LOPRI_RX],
bt->bcnt[BTC_BCNT_LOPRI_TX],
- bt->bcnt[BTC_BCNT_POLUT]);
+ bt->bcnt[BTC_BCNT_POLLUTED]);
if (!bt->scan_info_update) {
rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_SCAN_INFO, true);
@@ -9716,7 +9823,7 @@ static int _show_bt_info(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
else
rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_TX_PWR_LVL, false);
- if (bt->bcnt[BTC_BCNT_BTTXPWR_UPDATE]) {
+ if (bt->bcnt[BTC_BCNT_TXPWR_UPDATE]) {
p += scnprintf(p, end - p,
" %-15s : br_index:0x%x, le_index:0x%x",
"[bt_txpwr_lvl]",
@@ -10127,7 +10234,7 @@ static int _show_dm_info(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
p += scnprintf(p, end - p,
" %-15s : wl_only:%d, bt_only:%d, igno_bt:%d, free_run:%d, wl_ps_ctrl:%d, wl_mimo_ps:%d, ",
"[dm_flag]", dm->wl_only, dm->bt_only, igno_bt,
- dm->freerun, btc->lps, dm->wl_mimo_ps);
+ dm->freerun, btc->btc_ctrl_lps, dm->wl_mimo_ps);
p += scnprintf(p, end - p, "leak_ap:%d, fw_offload:%s%s\n",
dm->leak_ap,
@@ -11353,10 +11460,11 @@ static int _show_mreg_v1(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
const struct rtw89_chip_info *chip = rtwdev->chip;
struct rtw89_btc *btc = &rtwdev->btc;
struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
- struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
struct rtw89_btc_fbtc_mreg_val_v1 *pmreg = NULL;
+ struct rtw89_btc_bt_info *bt0 = &btc->cx.bt0;
+ struct rtw89_btc_bt_info *bt1 = &btc->cx.bt1;
+ struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
struct rtw89_btc_wl_info *wl = &btc->cx.wl;
- struct rtw89_btc_bt_info *bt = &btc->cx.bt0;
struct rtw89_mac_ax_coex_gnt gnt_cfg = {};
struct rtw89_mac_ax_gnt gnt;
char *p = buf, *end = buf + bufsz;
@@ -11369,11 +11477,20 @@ static int _show_mreg_v1(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
p += scnprintf(p, end - p, "========== [HW Status] ==========\n");
p += scnprintf(p, end - p,
- " %-15s : WL->BT:0x%08x(cnt:%d), BT->WL:0x%08x(total:%d, bt_update:%d)\n",
- "[scoreboard]", wl->scbd,
+ " %-15s : WL->BT0:0x%08x(cnt:%d), BT0->WL:0x%08x(total:%d, bt_update:%d)\n",
+ "[scoreboard]", wl->scbd[BTC_BT_1ST],
wl->wcnt[BTC_WCNT_SCBDUPDATE],
- bt->scbd, bt->bcnt[BTC_BCNT_SCBDREAD],
- bt->bcnt[BTC_BCNT_SCBDUPDATE]);
+ bt0->scbd, bt0->bcnt[BTC_BCNT_SCBDREAD],
+ bt0->bcnt[BTC_BCNT_SCBDUPDATE]);
+
+ if (rtwdev->chip->para_ver & BTC_FEAT_DUAL_BT) {
+ p += scnprintf(p, end - p,
+ " %-15s : WL->BT1:0x%08x(cnt:%d), BT1->WL:0x%08x(total:%d, bt_update:%d)\n",
+ "[scoreboard]", wl->scbd[BTC_BT_2ND],
+ wl->wcnt[BTC_WCNT_SCBDUPDATE2],
+ bt1->scbd, bt1->bcnt[BTC_BCNT_SCBDREAD],
+ bt1->bcnt[BTC_BCNT_SCBDUPDATE]);
+ }
btc->dm.pta_owner = rtw89_mac_get_ctrl_path(rtwdev);
_get_gnt(rtwdev, &gnt_cfg);
@@ -11437,10 +11554,11 @@ static int _show_mreg_v2(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
const struct rtw89_chip_info *chip = rtwdev->chip;
struct rtw89_btc *btc = &rtwdev->btc;
struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
- struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
struct rtw89_btc_fbtc_mreg_val_v2 *pmreg = NULL;
+ struct rtw89_btc_bt_info *bt0 = &btc->cx.bt0;
+ struct rtw89_btc_bt_info *bt1 = &btc->cx.bt1;
+ struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
struct rtw89_btc_wl_info *wl = &btc->cx.wl;
- struct rtw89_btc_bt_info *bt = &btc->cx.bt0;
struct rtw89_mac_ax_coex_gnt gnt_cfg = {};
struct rtw89_mac_ax_gnt gnt;
char *p = buf, *end = buf + bufsz;
@@ -11453,11 +11571,20 @@ static int _show_mreg_v2(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
p += scnprintf(p, end - p, "========== [HW Status] ==========\n");
p += scnprintf(p, end - p,
- " %-15s : WL->BT:0x%08x(cnt:%d), BT->WL:0x%08x(total:%d, bt_update:%d)\n",
- "[scoreboard]", wl->scbd,
+ " %-15s : WL->BT0:0x%08x(cnt:%d), BT0->WL:0x%08x(total:%d, bt_update:%d)\n",
+ "[scoreboard]", wl->scbd[BTC_BT_1ST],
wl->wcnt[BTC_WCNT_SCBDUPDATE],
- bt->scbd, bt->bcnt[BTC_BCNT_SCBDREAD],
- bt->bcnt[BTC_BCNT_SCBDUPDATE]);
+ bt0->scbd, bt0->bcnt[BTC_BCNT_SCBDREAD],
+ bt0->bcnt[BTC_BCNT_SCBDUPDATE]);
+
+ if (rtwdev->chip->para_ver & BTC_FEAT_DUAL_BT) {
+ p += scnprintf(p, end - p,
+ " %-15s : WL->BT1:0x%08x(cnt:%d), BT1->WL:0x%08x(total:%d, bt_update:%d)\n",
+ "[scoreboard]", wl->scbd[BTC_BT_2ND],
+ wl->wcnt[BTC_WCNT_SCBDUPDATE2],
+ bt1->scbd, bt1->bcnt[BTC_BCNT_SCBDREAD],
+ bt1->bcnt[BTC_BCNT_SCBDUPDATE]);
+ }
btc->dm.pta_owner = rtw89_mac_get_ctrl_path(rtwdev);
_get_gnt(rtwdev, &gnt_cfg);
@@ -11524,8 +11651,9 @@ static int _show_mreg_v7(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
struct rtw89_btc_fbtc_mreg_val_v7 *pmreg = NULL;
struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
struct rtw89_btc_cx *cx = &btc->cx;
+ struct rtw89_btc_bt_info *bt0 = &cx->bt0;
+ struct rtw89_btc_bt_info *bt1 = &cx->bt1;
struct rtw89_btc_wl_info *wl = &cx->wl;
- struct rtw89_btc_bt_info *bt = &cx->bt0;
struct rtw89_mac_ax_gnt *gnt = NULL;
struct rtw89_btc_dm *dm = &btc->dm;
char *p = buf, *end = buf + bufsz;
@@ -11538,11 +11666,20 @@ static int _show_mreg_v7(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
p += scnprintf(p, end - p, "\n\r========== [HW Status] ==========");
p += scnprintf(p, end - p,
- "\n\r %-15s : WL->BT:0x%08x(cnt:%d), BT->WL:0x%08x(total:%d, bt_update:%d)",
- "[scoreboard]", wl->scbd,
+ " %-15s : WL->BT0:0x%08x(cnt:%d), BT0->WL:0x%08x(total:%d, bt_update:%d)\n",
+ "[scoreboard]", wl->scbd[BTC_BT_1ST],
wl->wcnt[BTC_WCNT_SCBDUPDATE],
- bt->scbd, bt->bcnt[BTC_BCNT_SCBDREAD],
- bt->bcnt[BTC_BCNT_SCBDUPDATE]);
+ bt0->scbd, bt0->bcnt[BTC_BCNT_SCBDREAD],
+ bt0->bcnt[BTC_BCNT_SCBDUPDATE]);
+
+ if (rtwdev->chip->para_ver & BTC_FEAT_DUAL_BT) {
+ p += scnprintf(p, end - p,
+ " %-15s : WL->BT1:0x%08x(cnt:%d), BT1->WL:0x%08x(total:%d, bt_update:%d)\n",
+ "[scoreboard]", wl->scbd[BTC_BT_2ND],
+ wl->wcnt[BTC_WCNT_SCBDUPDATE2],
+ bt1->scbd, bt1->bcnt[BTC_BCNT_SCBDREAD],
+ bt1->bcnt[BTC_BCNT_SCBDUPDATE]);
+ }
/* To avoid I/O if WL LPS or power-off */
dm->pta_owner = rtw89_mac_get_ctrl_path(rtwdev);
diff --git a/drivers/net/wireless/realtek/rtw89/coex.h b/drivers/net/wireless/realtek/rtw89/coex.h
index fb151f68eb64..74027ca4eccc 100644
--- a/drivers/net/wireless/realtek/rtw89/coex.h
+++ b/drivers/net/wireless/realtek/rtw89/coex.h
@@ -391,4 +391,13 @@ void _slot_set_tbl(struct rtw89_btc *btc, u8 sid, u32 tbl)
btc->dm.slot.v7[sid].cxtbl = cpu_to_le32(tbl);
}
+static inline
+void btc_dw2b(u8 *buf, size_t idx, u32 val)
+{
+ buf[idx] = u32_get_bits(val, MASKBYTE0);
+ buf[idx + 1] = u32_get_bits(val, MASKBYTE1);
+ buf[idx + 2] = u32_get_bits(val, MASKBYTE2);
+ buf[idx + 3] = u32_get_bits(val, MASKBYTE3);
+}
+
#endif
diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c
index 85aeb9e90812..b3376fadf593 100644
--- a/drivers/net/wireless/realtek/rtw89/core.c
+++ b/drivers/net/wireless/realtek/rtw89/core.c
@@ -5417,7 +5417,7 @@ static void rtw89_track_ps_work(struct wiphy *wiphy, struct wiphy_work *work)
if (rtwdev->scanning)
return;
- if (rtwdev->lps_enabled && !rtwdev->btc.lps)
+ if (rtwdev->lps_enabled && !rtwdev->btc.btc_ctrl_lps)
rtw89_enter_lps_track(rtwdev, RTW89_TFC_INTERVAL_100MS);
}
@@ -5465,7 +5465,7 @@ static void rtw89_track_work(struct wiphy *wiphy, struct wiphy_work *work)
rtw89_core_rfkill_poll(rtwdev, false);
rtw89_core_mlo_track(rtwdev);
- if (rtwdev->lps_enabled && !rtwdev->btc.lps)
+ if (rtwdev->lps_enabled && !rtwdev->btc.btc_ctrl_lps)
rtw89_enter_lps_track(rtwdev, RTW89_TFC_INTERVAL_2SEC);
}
diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index eb814425f536..8646a13bfd79 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -1415,6 +1415,7 @@ enum rtw89_btc_wl_state_cnt {
BTC_WCNT_RX_ERR_LAST,
BTC_WCNT_RX_ERR_LAST2S,
BTC_WCNT_RX_LAST,
+ BTC_WCNT_SCBDUPDATE2,
BTC_WCNT_NUM
};
@@ -1431,17 +1432,25 @@ enum rtw89_btc_bt_state_cnt {
BTC_BCNT_ROLESW,
BTC_BCNT_AFH,
BTC_BCNT_INFOUPDATE,
+ BTC_BCNT_LEAUDIO_INFOUPDATE,
BTC_BCNT_INFOSAME,
+ BTC_BCNT_LEAUDIO_INFOSAME,
BTC_BCNT_SCBDUPDATE,
BTC_BCNT_HIPRI_TX,
BTC_BCNT_HIPRI_RX,
BTC_BCNT_LOPRI_TX,
BTC_BCNT_LOPRI_RX,
- BTC_BCNT_POLUT,
BTC_BCNT_POLUT_NOW,
BTC_BCNT_POLUT_DIFF,
BTC_BCNT_RATECHG,
- BTC_BCNT_BTTXPWR_UPDATE,
+ BTC_BCNT_AFH_CONFLICT,
+ BTC_BCNT_AFH_LE_CONFLICT,
+ BTC_BCNT_AFH_UPDATE,
+ BTC_BCNT_AFH_LE_UPDATE,
+ BTC_BCNT_AFH_CHN,
+ BTC_BCNT_AFH_LE_CHN,
+ BTC_BCNT_TXPWR_UPDATE,
+ BTC_BCNT_PROTECT,
BTC_BCNT_NUM,
};
@@ -2188,12 +2197,13 @@ struct rtw89_btc_wl_info {
bool pta_reg_mac_chg;
bool bg_mode;
bool he_mode;
- bool scbd_change;
+ bool scbd_chg[BTC_ALL_BT];
bool fw_ver_mismatch;
bool client_cnt_inc_2g;
bool link_mode_chg;
bool dbcc_chg;
- u32 scbd;
+ u32 scbd[BTC_ALL_BT];
+ u32 scbd_rb[BTC_ALL_BT];
u32 wcnt[BTC_WCNT_NUM];
};
@@ -2323,6 +2333,15 @@ enum rtw89_btc_ble_scan_type {
CXSCAN_MAX
};
+enum rtw89_btc_bt_func_type {
+ BTC_BTF_NONE = 0,
+ BTC_BTF_BT = BIT(0),
+ BTC_BTF_ZB = BIT(1),
+ BTC_BTF_THREAD = BIT(2),
+ BTC_BTF_24GPRO = BIT(3), /* 2.4GHz Proprietary */
+ BTC_BTF_ULL = BIT(4),
+};
+
#define RTW89_BTC_BTC_SCAN_V1_FLAG_ENABLE BIT(0)
#define RTW89_BTC_BTC_SCAN_V1_FLAG_INTERLACE BIT(1)
@@ -2394,6 +2413,8 @@ struct rtw89_btc_bt_info {
u8 rsvd: 6;
u32 scbd;
+ u32 scbd_rb;
+ u32 scbd_c2h;
u32 feature;
u32 mbx_avl: 1;
@@ -3338,6 +3359,8 @@ struct rtw89_btc_dm {
u8 lps_ctrl_scbd: 1;
u8 lps_ctrl_scbd_last: 1;
u8 lps_ctrl_change: 1;
+ u8 scbd_write_instant;
+ bool scbd_b2w_update;
};
struct rtw89_btc_ctrl {
@@ -3585,7 +3608,7 @@ struct rtw89_btc {
u32 hubmsg_cnt;
bool bt_req_en;
bool update_policy_force;
- bool lps;
+ bool btc_ctrl_lps;
bool manual_ctrl;
bool cli_h2c_cmd;
};
--
2.25.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH rtw-next 9/9] wifi: rtw89: coex: Add Co-RX logic
2026-07-03 11:43 [PATCH rtw-next 0/9] wifi: rtw89: coex: implement components for dual Bluetooth Ping-Ke Shih
` (7 preceding siblings ...)
2026-07-03 11:43 ` [PATCH rtw-next 8/9] wifi: rtw89: coex: Update scoreboard related logic for dual Bluetooth Ping-Ke Shih
@ 2026-07-03 11:43 ` Ping-Ke Shih
8 siblings, 0 replies; 10+ messages in thread
From: Ping-Ke Shih @ 2026-07-03 11:43 UTC (permalink / raw)
To: linux-wireless; +Cc: ku920601
From: Ching-Te Ku <ku920601@realtek.com>
Co-RX means Wi-Fi & Bluetooth can be able to RX in the same time. This
patch is for judging the Wi-Fi/Bluetooth condition could be Co-RX or not,
and how to set the gain and power.
Signed-off-by: Ching-Te Ku <ku920601@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/coex.c | 69 +++++++++++++++++++++++
drivers/net/wireless/realtek/rtw89/core.h | 1 +
2 files changed, 70 insertions(+)
diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c
index d45fab32ab46..129b6b7cb634 100644
--- a/drivers/net/wireless/realtek/rtw89/coex.c
+++ b/drivers/net/wireless/realtek/rtw89/coex.c
@@ -3319,7 +3319,74 @@ static void _set_bt_rx_gain(struct rtw89_dev *rtwdev, bool force_exec, u8 bid,
_write_scbd(rtwdev, bid, scbd_bit, state);
}
+}
+
+static void _set_bt_corx_table(struct rtw89_dev *rtwdev, bool en)
+{
+ struct rtw89_btc *btc = &rtwdev->btc;
+ struct rtw89_btc_cx *cx = &btc->cx;
+ struct rtw89_btc_bt_info *bt = &cx->bt0;
+ struct rtw89_btc_dm *dm = &btc->dm;
+ u8 is_24g, is_56g, i;
+ u32 scbd_bit;
+
+ /*
+ * true: bt use Hi-LNA rx gain table (f/e/3/2) in -3x~-9xdBm for co-rx
+ * false: bt use original rx gain table (f/b/7/3/2)
+ */
+
+ if (btc->dm.fdd_bind.bt_sel == BIT(BTC_BT_EXT))
+ return;
+
+ for (i = BTC_BT_1ST; i <= BTC_BT_2ND; i++) {
+ scbd_bit = 0;
+ if (i == BTC_BT_2ND) {
+ if (!(rtwdev->chip->para_ver & BTC_FEAT_DUAL_BT))
+ continue;
+ bt = &cx->bt1;
+ }
+ is_24g = (dm->corx_map[BTC_RF_S0][i] ||
+ dm->corx_map[BTC_RF_S1][i]) & BIT(RTW89_BAND_2G);
+ is_56g = (dm->corx_map[BTC_RF_S0][i] ||
+ dm->corx_map[BTC_RF_S1][i]) & BIT(RTW89_BAND_5G);
+ if (is_24g)
+ scbd_bit |= BTC_WSCB_BT_HILNA;
+ if (is_56g)
+ scbd_bit |= BTC_WSCB_BT_HILNA_56G;
+
+ if ((is_24g && (en != (!!bt->hi_lna_rx))) ||
+ (is_56g && (en != (!!bt->hi_lna_rx_6g))))
+ _write_scbd(rtwdev, i, scbd_bit, en);
+ }
+}
+
+static void _set_rf_trx_para_v9(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_btc *btc = &rtwdev->btc;
+ struct rtw89_btc_cx *cx = &btc->cx;
+ struct rtw89_btc_wl_smap *wl_smap = &cx->wl.status.map;
+ struct rtw89_btc_dm *dm = &btc->dm;
+ bool bt_2r = false;
+ u8 wl_stb_chg = 0;
+
+ if (wl_smap->rf_off || wl_smap->lps == BTC_LPS_RF_OFF)
+ return;
+
+ /* must call after _set_halbb_btg_ctrl() */
+ if (dm->tdd_bind.wl_link_mode != BTC_WLINK_NOLINK) {
+ wl_stb_chg = 1;
+ if (dm->wl_btg_rx)
+ bt_2r = true;
+ }
+
+ _set_bt_corx_table(rtwdev, bt_2r);
+
+ if (wl_stb_chg != dm->wl_stb_chg) {
+ dm->wl_stb_chg = wl_stb_chg;
+ dm->ost_info.wl_btg_standby_chg = wl_stb_chg;
+ rtwdev->chip->ops->btc_wl_s1_standby(rtwdev, dm->wl_stb_chg);
+ }
}
static void _set_rf_trx_para(struct rtw89_dev *rtwdev)
@@ -3356,6 +3423,8 @@ static void _set_rf_trx_para(struct rtw89_dev *rtwdev)
if (ver->fcxtrx == 9 && chip->rf_para_ulink_v9) {
ul_para_num = chip->rf_para_ulink_num_v9;
dl_para_num = chip->rf_para_dlink_num_v9;
+ _set_rf_trx_para_v9(rtwdev);
+ return;
} else if (ver->fcxtrx == 0 && chip->rf_para_ulink_v0) {
ul_para_num = chip->rf_para_ulink_num_v0;
dl_para_num = chip->rf_para_dlink_num_v0;
diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index 8646a13bfd79..524b4974040c 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -3278,6 +3278,7 @@ struct rtw89_btc_fbtc_outsrc_set_info {
u8 pta_req_hw_band;
u8 rf_gbt_source;
u8 bt_enable_state;
+ u8 wl_btg_standby_chg;
} __packed;
union rtw89_btc_fbtc_slot_u {
--
2.25.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
end of thread, other threads:[~2026-07-03 11:44 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-03 11:43 [PATCH rtw-next 0/9] wifi: rtw89: coex: implement components for dual Bluetooth Ping-Ke Shih
2026-07-03 11:43 ` [PATCH rtw-next 1/9] wifi: rtw89: coex: Add Init info version 10 Ping-Ke Shih
2026-07-03 11:43 ` [PATCH rtw-next 2/9] wifi: rtw89: coex: add rtw89_btc_init() entry for initialization once Ping-Ke Shih
2026-07-03 11:43 ` [PATCH rtw-next 3/9] wifi: rtw89: coex: Update TDMA descriptor for dual MAC Ping-Ke Shih
2026-07-03 11:43 ` [PATCH rtw-next 4/9] wifi: rtw89: coex: Add Bluetooth binding for Bluetooth TX power setting Ping-Ke Shih
2026-07-03 11:43 ` [PATCH rtw-next 5/9] wifi: rtw89: coex: Add Bluetooth binding for Bluetooth RX gain setting Ping-Ke Shih
2026-07-03 11:43 ` [PATCH rtw-next 6/9] wifi: rtw89: coex: Add WiFi/Bluetooth adapter binding info Ping-Ke Shih
2026-07-03 11:43 ` [PATCH rtw-next 7/9] wifi: rtw89: coex: Add TDMA binding for dual MAC Ping-Ke Shih
2026-07-03 11:43 ` [PATCH rtw-next 8/9] wifi: rtw89: coex: Update scoreboard related logic for dual Bluetooth Ping-Ke Shih
2026-07-03 11:43 ` [PATCH rtw-next 9/9] wifi: rtw89: coex: Add Co-RX logic Ping-Ke Shih
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox