Linux wireless drivers development
 help / color / mirror / Atom feed
* Re: [PATCH v8 4/9] nvmem: layouts: Support fixed-layout as the nvmem device node itself
From: Bartosz Golaszewski @ 2026-07-17  8:29 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: linux-mmc, devicetree, linux-kernel, linux-arm-msm, linux-block,
	linux-wireless, ath10k, linux-bluetooth, netdev, daniel,
	Loic Poulain, Ulf Hansson, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Bjorn Andersson, Konrad Dybcio, Jens Axboe,
	Johannes Berg, Jeff Johnson, Marcel Holtmann,
	Luiz Augusto von Dentz, Balakrishna Godavarthi, Rocky Liao,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Srinivas Kandagatla, Andrew Lunn, Heiner Kallweit,
	Russell King, Saravana Kannan, Christian Marangi
In-Reply-To: <CAMRc=MdNehSRQT3MUs+QtbZsHcUCS8YjyZchTgHCVv-HaLQkeA@mail.gmail.com>

On Wed, 15 Jul 2026 14:07:24 +0200, Bartosz Golaszewski <brgl@kernel.org> said:
> On Fri, 3 Jul 2026 15:45:17 +0200, Loic Poulain <loic.poulain@oss.qualcomm.com> said:
>> of_nvmem_layout_get_container() only looks for a child node named
>> "nvmem-layout" to locate the cell definitions. This does not cover
>> providers whose device tree node is itself the fixed-layout container,
>> such as an eMMC boot partition block device whose fwnode points directly
>> at a "fixed-layout" compatible partitions node.
>>
>> When no "nvmem-layout" child is present, fall back to returning the nvmem
>> device node itself if it is compatible with "fixed-layout", so that its
>> cells are parsed by nvmem_add_cells_from_fixed_layout().
>>
>> Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
>> ---
>>  drivers/nvmem/layouts.c | 13 ++++++++++++-
>>  1 file changed, 12 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/nvmem/layouts.c b/drivers/nvmem/layouts.c
>> index b90584e1b99eab4217cbe7ec48373e18a7caf0dc..efa631ce7283bdd6c8ecda75915911b5e3a33c99 100644
>> --- a/drivers/nvmem/layouts.c
>> +++ b/drivers/nvmem/layouts.c
>> @@ -167,7 +167,18 @@ static int nvmem_layout_bus_populate(struct nvmem_device *nvmem,
>>
>>  struct device_node *of_nvmem_layout_get_container(struct nvmem_device *nvmem)
>>  {
>> -	return of_get_child_by_name(nvmem->dev.of_node, "nvmem-layout");
>> +	struct device_node *np;
>> +
>> +	/* Search for nvmem-layout child */
>> +	np = of_get_child_by_name(nvmem->dev.of_node, "nvmem-layout");
>> +	if (np)
>> +		return np;
>> +
>> +	/* The nvmem of_node is itself a fixed-layout node */
>> +	if (of_device_is_compatible(nvmem->dev.of_node, "fixed-layout"))
>> +		return of_node_get(nvmem->dev.of_node);
>> +
>> +	return NULL;
>>  }
>>  EXPORT_SYMBOL_GPL(of_nvmem_layout_get_container);
>>
>>
>> --
>> 2.34.1
>>
>>
>
> I have it on my TODO list to convert nvmem layouts to be fwnode-agnostic. While
> I'm not sure when I'll have the time to look into it, I think it makes sense
> to not introduce any new OF-specific interfaces. Can you make it into:
>
>   struct fwnode_handle *nvmem_layout_get_container_node(struct nvmem_device *nvmem);
>
> by replacing of_get_child_by_name() with fwnode_get_name_child_node() and
> of_device_is_compatible() with device_is_compatible()? That would mean less
> churn in the future.
>
> Other than that, it looks good.
>
> Bart
>

Scratch that, I didn't realize this isn't a new function but a rework of an
existing one.

Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>

Bart

^ permalink raw reply

* Re: [RFC PATCH v3 0/4] wifi: rtl8xxxu: implement AP mode for 8188EU
From: Mehmet Fide @ 2026-07-17  8:02 UTC (permalink / raw)
  To: Georg Müller
  Cc: Jes.Sorensen, rtl8821cerfe2, linux-wireless, linux-kernel
In-Reply-To: <20260313131849.3148013-1-georgmueller@gmx.net>

Hi Georg,

Is there any progress on this series since v3? We are very interested in
seeing AP mode land for the 8188EU and can offer testing and debugging
help.

Our situation: we ship embedded ARM devices (i.MX/Vybrid based) that use
the Edimax EW-7811Un V2 (USB 7392:b811, RTL8188EU) as a WiFi AP dongle
with hostapd. On our older kernel we run the out-of-tree vendor rtl8188eu
driver, where multi-client AP mode works reliably with its per-MACID rate
adaptation. On recent kernels we had to drop this dongle because rtl8xxxu
has no AP support for this chip, so your series is exactly what we are
missing.

What we can offer:
- Testing on the exact hardware (EW-7811Un V2), both single and
  multi-client scenarios, with iOS/Windows/Linux clients.
- A/B comparison against the working vendor driver on the same board
  (register-level or behavioral differences, e.g. beacon/rsvd page setup,
  RA behavior), which may help pinpoint why clients fail to associate in
  your setup.
- Over-the-air sniffer captures and hostapd/driver debug logs from both
  drivers.

If you share your current WIP branch (or v4 draft) and describe how the
connection failure manifests on your side (no auth response? assoc
timeout? works open but fails WPA2?), we can try to reproduce it here and
compare against the vendor driver behavior.

Happy to provide Tested-by tags once it works.

Best regards,
Mehmet Fide
Screening Eagle Technologies

^ permalink raw reply

* Re: ath12k: WCN785x firmware resets regulatory domain on resume causing ~7s reconnect delay
From: Baochen Qiang @ 2026-07-17  7:44 UTC (permalink / raw)
  To: Stian Knudsen, ath12k; +Cc: linux-wireless, linux-kernel
In-Reply-To: <-_iDJ_M5RrqACWB0qmtleg@pokerfj.es>



On 7/17/2026 6:35 AM, Stian Knudsen wrote:
> After resume from suspend, the WCN785x firmware resets its regulatory state to
> WORLD and takes approximately 7 seconds to re-discover the country code from AP
> beacons. This causes a consistent ~16 second total delay before wifi reconnects
> after resume.
> 
> This is an improvement request rather than a crash bug: the driver currently
> contains no WMI code for saving or restoring regulatory state across
> suspend/resume, and I would like to ask whether this is feasible.
> 
> Hardware:
> Lenovo ThinkPad T14 Gen 5 (BIOS: R2LET40W 1.21)
> Wifi: Qualcomm WCN785x Wi-Fi 7 FastConnect 7800 [17cb:1107]
> Subsystem: Lenovo [17aa:e0e6]
> Kernel: 7.1.3-arch2-1 (Arch Linux, close to vanilla)
> Firmware: WLAN.HMT.1.1.c7-00108-QCAHMTSWPL_V1.0_V2.0_SILICONZ_UPSTREAM-3
> Kernel taint: 0 (untainted)
> 
> Observed behavior:
> On every resume from suspend, the following sequence is observed in dmesg and wpa_supplicant logs:
> kernel: ath12k_wifi7_pci 0000:02:00.0: chip_id 0x2 chip_family 0x4 board_id 0xff soc_id 0x40170200
> kernel: ath12k_wifi7_pci 0000:02:00.0: fw_version 0x1103006c fw_build_timestamp 2026-03-06 09:10 ...
> wpa_supplicant: wlp2s0: CTRL-EVENT-REGDOM-CHANGE init=DRIVER type=WORLD
> [ ~7 seconds pass ]
> wpa_supplicant: wlp2s0: CTRL-EVENT-REGDOM-CHANGE init=DRIVER type=COUNTRY alpha2=DE
> [ ~9 seconds pass ]
> NetworkManager: policy: auto-activating connection 'SSID'
> NetworkManager: device (wlp2s0): Activation: successful, device activated.
> 
> Total delay from resume to connected: ~16 seconds, 100% reproducible on every
> resume.
> 
> The device advertises itself as self-managed (phy#0 (self-managed) in iw reg
> get). All standard userspace methods of setting the regulatory domain are
> ignored by the firmware -- iw reg set, wireless-regdb, cfg80211
> ieee80211_regdom modprobe option -- and i found this blog which documents this:
> https://www.julienturbide.com/blog/wifi-7-linux-ath12k-wcn785x-regulatory-domain
> 
> Grepping the ath12k driver source (7.1.3) reveals no WMI code for saving or
> restoring regulatory state across suspend/resume:
>  $ grep -r "regdom|regulatory|country.*suspend|suspend.*country" drivers/net/wireless/ath/ath12k/
> (no output)
> 
> The firmware resets to WORLD on every resume and must re-discover the country
> code from AP beacons, taking ~7 seconds.
> 
> Is there a WMI command available in the WCN785x firmware to cache and restore
> the last known country code on resume, avoiding the need to re-discover it from AP beacons? If so, would it be feasible to add this to the driver's suspend/resume path to reduce the post-resume reconnect delay?
> Full dmesg output and wpa_supplicant logs are available on request.

ath11k has the same issue and there is a commit fixing it

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=7f0343b7b8710436c1e6355c71782d32ada47e0c

in ath12k, the same command/function (ath12k_wmi_send_set_current_country_cmd()) can do
this for you.

> 
> 
> 


^ permalink raw reply

* [PATCH rtw-next 13/13] wifi: rtw89: coex: Add firmware 0.27.97.X support for RTL8852C
From: Ping-Ke Shih @ 2026-07-17  6:57 UTC (permalink / raw)
  To: linux-wireless; +Cc: ku920601
In-Reply-To: <20260717065739.64124-1-pkshih@realtek.com>

From: Ching-Te Ku <ku920601@realtek.com>

Newer firmware is using the new TLV-Header format, without this patch
it will lead driver run into length mismatch state.

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 | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c
index b95e34cb1567..6a1888d8c476 100644
--- a/drivers/net/wireless/realtek/rtw89/coex.c
+++ b/drivers/net/wireless/realtek/rtw89/coex.c
@@ -214,6 +214,15 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = {
 	 .max_role_num = 6, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 7,
 	 .fcxtrx = 0,
 	},
+	{RTL8852C, RTW89_FW_VER_CODE(0, 27, 97, 0),
+	 .fcxbtcrpt = 4, .fcxtdma = 4,    .fcxslots = 2, .fcxcysta = 105,
+	 .fcxstep = 3,   .fcxnullsta = 2, .fcxmreg = 2,  .fcxgpiodbg = 1,
+	 .fcxbtver = 1,  .fcxbtscan = 2,  .fcxbtafh = 2, .fcxbtdevinfo = 1,
+	 .fwlrole = 101, .frptmap = 3,    .fcxctrl = 1,  .fcxinit = 0,
+	 .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_ver = 0, .info_buf = 1280,
+	 .max_role_num = 5, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 7,
+	 .fcxtrx = 107,
+	},
 	{RTL8852C, RTW89_FW_VER_CODE(0, 27, 57, 0),
 	 .fcxbtcrpt = 4, .fcxtdma = 3,    .fcxslots = 1, .fcxcysta = 3,
 	 .fcxstep = 3,   .fcxnullsta = 2, .fcxmreg = 1,  .fcxgpiodbg = 1,
-- 
2.25.1


^ permalink raw reply related

* [PATCH rtw-next 12/13] wifi: rtw89: coex: Add wifi role info version 101
From: Ping-Ke Shih @ 2026-07-17  6:57 UTC (permalink / raw)
  To: linux-wireless; +Cc: ku920601
In-Reply-To: <20260717065739.64124-1-pkshih@realtek.com>

From: Ching-Te Ku <ku920601@realtek.com>

The structure active_role which describes the using Wi-Fi role format is
different with the exist v1. Add branch to cover the difference.

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 | 13 ++--
 drivers/net/wireless/realtek/rtw89/fw.c   | 82 +++++++++++++++++++++++
 drivers/net/wireless/realtek/rtw89/fw.h   | 35 ++++++++++
 3 files changed, 125 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c
index 54c11af46f8d..b95e34cb1567 100644
--- a/drivers/net/wireless/realtek/rtw89/coex.c
+++ b/drivers/net/wireless/realtek/rtw89/coex.c
@@ -3198,6 +3198,8 @@ static void _fw_set_drv_info(struct rtw89_dev *rtwdev, u8 index)
 			rtw89_fw_h2c_cxdrv_role(rtwdev, index);
 		else if (ver->fwlrole == 1)
 			rtw89_fw_h2c_cxdrv_role_v1(rtwdev, index);
+		else if (ver->fwlrole == 101)
+			rtw89_fw_h2c_cxdrv_role_v101(rtwdev, index);
 		else if (ver->fwlrole == 2)
 			rtw89_fw_h2c_cxdrv_role_v2(rtwdev, index);
 		else if (ver->fwlrole == 7)
@@ -6873,6 +6875,7 @@ static void _update_wl_link_mode(struct rtw89_dev *rtwdev, u8 hw_band, u8 type)
 	struct rtw89_btc_wl_mlo_info *mlo_info = &wl->mlo_info;
 	struct rtw89_btc_wl_role_info *r = &wl->role_info;
 	u8 p2p_exist = wl->role_info.p2p_exist;
+	u8 rver = ver->fwlrole;
 
 	if (hw_band == RTW89_PHY_1)
 		p2p_exist = wl->role_info.p2p_exist_hb1;
@@ -6893,7 +6896,7 @@ static void _update_wl_link_mode(struct rtw89_dev *rtwdev, u8 hw_band, u8 type)
 			r->link_mode = BTC_WLINK_STA;
 		}
 
-		if (ver->fwlrole >= 10)
+		if (rver >= 10 && rver < 100)
 			break;
 
 		if (mlo_info->hwb_rf_band[hw_band] != RTW89_BAND_2G) {
@@ -6921,7 +6924,7 @@ static void _update_wl_link_mode(struct rtw89_dev *rtwdev, u8 hw_band, u8 type)
 			r->link_mode = BTC_WLINK_SCC;
 		}
 
-		if (ver->fwlrole >= 10)
+		if (rver >= 10 && rver < 100)
 			break;
 
 		if (mlo_info->hwb_rf_band[hw_band] != RTW89_BAND_2G) {
@@ -6941,7 +6944,7 @@ static void _update_wl_link_mode(struct rtw89_dev *rtwdev, u8 hw_band, u8 type)
 		else
 			r->link_mode = BTC_WLINK_STA;
 
-		if (ver->fwlrole >= 10)
+		if (rver >= 10 && rver < 100)
 			break;
 
 		if (mlo_info->hwb_rf_band[hw_band] != RTW89_BAND_2G)
@@ -6959,7 +6962,7 @@ static void _update_wl_link_mode(struct rtw89_dev *rtwdev, u8 hw_band, u8 type)
 		 */
 		r->link_mode = BTC_WLINK_DB_MCC;
 
-		if (ver->fwlrole >= 10)
+		if (rver >= 10 && rver < 100)
 			break;
 
 		r->link_mode_v0 = BTC_WLINK_V0_25G_MCC;
@@ -6968,7 +6971,7 @@ static void _update_wl_link_mode(struct rtw89_dev *rtwdev, u8 hw_band, u8 type)
 		/* MLMR only support STA now (2024) */
 		r->link_mode = BTC_WLINK_STA;
 
-		if (ver->fwlrole >= 10)
+		if (rver >= 10 && rver < 100)
 			break;
 
 		if (mlo_info->hwb_rf_band[hw_band] != RTW89_BAND_2G) {
diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c
index 34bc52519ea2..a9308f9486ae 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.c
+++ b/drivers/net/wireless/realtek/rtw89/fw.c
@@ -6148,6 +6148,88 @@ int rtw89_fw_h2c_cxdrv_role_v1(struct rtw89_dev *rtwdev, u8 type)
 	return ret;
 }
 
+int rtw89_fw_h2c_cxdrv_role_v101(struct rtw89_dev *rtwdev, u8 type)
+{
+	struct rtw89_btc *btc = &rtwdev->btc;
+	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
+	struct rtw89_btc_wl_role_info *role_info = &wl->role_info;
+	struct rtw89_btc_wl_rlink *active;
+	struct rtw89_h2c_cxrole_v101 *h2c;
+	u32 len = sizeof(*h2c);
+	struct sk_buff *skb;
+	int ret;
+	u8 i;
+
+	skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
+	if (!skb) {
+		rtw89_err(rtwdev, "failed to alloc skb for h2c cxdrv_role_v101\n");
+		return -ENOMEM;
+	}
+	skb_put(skb, len);
+	h2c = (struct rtw89_h2c_cxrole_v101 *)skb->data;
+
+	h2c->hdr.type = type;
+	h2c->hdr.len = len - H2C_LEN_CXDRVHDR;
+
+	h2c->connect_cnt = role_info->connect_cnt;
+	h2c->link_mode = role_info->link_mode;
+	h2c->role_map = cpu_to_le16(role_info->role_map);
+
+	for (i = 0; i < RTW89_PORT_NUM; i++) {
+		active = &role_info->rlink[i][0];
+		h2c->act_role[i].map_role_status =
+			u8_encode_bits(active->connected,
+				       RTW89_H2C_CXROLE_V101_ROLE_STAT_CONNTECTED) |
+			u8_encode_bits(active->pid,
+				       RTW89_H2C_CXROLE_V101_ROLE_STAT_PID) |
+			u8_encode_bits(active->phy,
+				       RTW89_H2C_CXROLE_V101_ROLE_STAT_PHY) |
+			u8_encode_bits(active->noa,
+				       RTW89_H2C_CXROLE_V101_ROLE_STAT_NOA) |
+			u8_encode_bits(active->rf_band,
+				       RTW89_H2C_CXROLE_V101_ROLE_STAT_BADN);
+		h2c->act_role[i].map_clips_bw =
+			u8_encode_bits(active->client_ps,
+				       RTW89_H2C_CXROLE_V101_CLIPS_BW_CLIENTPS) |
+			u8_encode_bits(active->bw,
+				       RTW89_H2C_CXROLE_V101_CLIPS_BW_BW);
+		h2c->act_role[i].role = active->role;
+		h2c->act_role[i].ch = active->ch;
+		h2c->act_role[i].noa_duration = cpu_to_le32(active->noa_dur);
+	}
+
+	h2c->mrole_type = cpu_to_le32(role_info->mrole_type);
+	h2c->mrole_noa_duration = cpu_to_le32(role_info->mrole_noa_duration);
+	h2c->map_dbcc_linkmode_chg =
+		le32_encode_bits(role_info->dbcc_en,
+				 RTW89_H2C_CXROLE_V101_DBCC_EN) |
+		le32_encode_bits(role_info->dbcc_chg,
+				 RTW89_H2C_CXROLE_V101_DBCC_CHG) |
+		le32_encode_bits(role_info->dbcc_2g_phy,
+				 RTW89_H2C_CXROLE_V101_DBCC_2G_PHY) |
+		le32_encode_bits(role_info->link_mode_chg,
+				 RTW89_H2C_CXROLE_V101_DBCC_LINKMODE_CHG) |
+		le32_encode_bits(role_info->rsvd,
+				 RTW89_H2C_CXROLE_V101_DBCC_RSVD);
+
+	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 H2C_LEN_CXDRVINFO_ROLE_SIZE_V2(max_role_num) \
 	(4 + 8 * (max_role_num) + H2C_LEN_CXDRVINFO_ROLE_DBCC_LEN + H2C_LEN_CXDRVHDR)
 
diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h
index 16e173c5d1bb..53b5695f9070 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.h
+++ b/drivers/net/wireless/realtek/rtw89/fw.h
@@ -2603,6 +2603,40 @@ struct rtw89_h2c_cxinit_v10 {
 	struct rtw89_btc_init_info_v10 init;
 } __packed;
 
+#define RTW89_H2C_CXROLE_V101_ROLE_STAT_CONNTECTED BIT(0)
+#define RTW89_H2C_CXROLE_V101_ROLE_STAT_PID GENMASK(3, 1)
+#define RTW89_H2C_CXROLE_V101_ROLE_STAT_PHY BIT(4)
+#define RTW89_H2C_CXROLE_V101_ROLE_STAT_NOA BIT(5)
+#define RTW89_H2C_CXROLE_V101_ROLE_STAT_BADN GENMASK(7, 6)
+
+#define RTW89_H2C_CXROLE_V101_CLIPS_BW_CLIENTPS BIT(0)
+#define RTW89_H2C_CXROLE_V101_CLIPS_BW_BW GENMASK(7, 1)
+
+#define RTW89_H2C_CXROLE_V101_DBCC_EN BIT(0)
+#define RTW89_H2C_CXROLE_V101_DBCC_CHG BIT(1)
+#define RTW89_H2C_CXROLE_V101_DBCC_2G_PHY GENMASK(3, 2)
+#define RTW89_H2C_CXROLE_V101_DBCC_LINKMODE_CHG BIT(4)
+#define RTW89_H2C_CXROLE_V101_DBCC_RSVD GENMASK(31, 5)
+
+struct rtw89_btc_wl_active_role_v101 {
+	u8 map_role_status;
+	u8 map_clips_bw;
+	u8 role;
+	u8 ch;
+	__le32 noa_duration;
+} __packed;
+
+struct rtw89_h2c_cxrole_v101 {
+	struct rtw89_h2c_cxhdr hdr;
+	u8 connect_cnt;
+	u8 link_mode;
+	__le16 role_map;
+	struct rtw89_btc_wl_active_role_v101 act_role[RTW89_PORT_NUM];
+	__le32 mrole_type;
+	__le32 mrole_noa_duration;
+	__le32 map_dbcc_linkmode_chg;
+} __packed;
+
 static inline void RTW89_SET_FWCMD_CXROLE_CONNECT_CNT(void *cmd, u8 val)
 {
 	u8p_replace_bits((u8 *)(cmd) + 2, val, GENMASK(7, 0));
@@ -5412,6 +5446,7 @@ 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_v101(struct rtw89_dev *rtwdev, u8 type);
 int rtw89_fw_h2c_cxdrv_role_v2(struct rtw89_dev *rtwdev, u8 type);
 int rtw89_fw_h2c_cxdrv_role_v7(struct rtw89_dev *rtwdev, u8 type);
 int rtw89_fw_h2c_cxdrv_role_v8(struct rtw89_dev *rtwdev, u8 type);
-- 
2.25.1


^ permalink raw reply related

* [PATCH rtw-next 11/13] wifi: rtw89: coex: Add cycle status report version 105
From: Ping-Ke Shih @ 2026-07-17  6:57 UTC (permalink / raw)
  To: linux-wireless; +Cc: ku920601
In-Reply-To: <20260717065739.64124-1-pkshih@realtek.com>

From: Ching-Te Ku <ku920601@realtek.com>

The exists version 5 format has FDDT(frequency divided training) related
information. But the feature wasn't support for RTL8852C now, so firmware
will not send the related reference value.

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 | 197 ++++++++++++++++++++++
 drivers/net/wireless/realtek/rtw89/core.h |  21 +++
 2 files changed, 218 insertions(+)

diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c
index 65d4e9139342..54c11af46f8d 100644
--- a/drivers/net/wireless/realtek/rtw89/coex.c
+++ b/drivers/net/wireless/realtek/rtw89/coex.c
@@ -1757,6 +1757,11 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
 			pcysta->v5 = pfwinfo->rpt_fbtc_cysta.finfo.v5;
 			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_cysta.finfo.v5);
 			fwsubver->fcxcysta = pfwinfo->rpt_fbtc_cysta.finfo.v5.fver;
+		} else if (ver->fcxcysta == 105) {
+			pfinfo = &pfwinfo->rpt_fbtc_cysta.finfo.v105;
+			pcysta->v105 = pfwinfo->rpt_fbtc_cysta.finfo.v105;
+			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_cysta.finfo.v105);
+			fwsubver->fcxcysta = pfwinfo->rpt_fbtc_cysta.finfo.v105.fver;
 		} else if (ver->fcxcysta == 7) {
 			pfinfo = &pfwinfo->rpt_fbtc_cysta.finfo.v7;
 			pcysta->v7 = pfwinfo->rpt_fbtc_cysta.finfo.v7;
@@ -2434,6 +2439,58 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
 				     le16_to_cpu(pcysta->v5.slot_cnt[CXST_B1]));
 			_chk_btc_err(rtwdev, BTC_DCNT_CYCLE_HANG,
 				     le16_to_cpu(pcysta->v5.cycles));
+		} else if (ver->fcxcysta == 105) {
+			if (dm->fddt_train == BTC_FDDT_ENABLE)
+				break;
+
+			cnt_leak_slot = le16_to_cpu(pcysta->v105.slot_cnt[CXST_LK]);
+			cnt_rx_imr = le32_to_cpu(pcysta->v105.leak_slot.cnt_rximr);
+
+			/* Check Leak-AP */
+			if (cnt_leak_slot != 0 && cnt_rx_imr != 0 &&
+			    dm->tdma_now.rxflctrl) {
+				if (le16_to_cpu(pcysta->v5.cycles) >= BTC_CYSTA_CHK_PERIOD &&
+				    cnt_leak_slot < BTC_LEAK_AP_TH * cnt_rx_imr)
+					dm->leak_ap = 1;
+			}
+
+			/* Check diff time between real WL slot and W1 slot */
+			if (dm->tdma_now.type == CXTDMA_OFF) {
+				if (ver->fcxslots == 1)
+					wl_slot_set = le16_to_cpu(dm->slot_now.v1[CXST_W1].dur);
+				else if (ver->fcxslots == 7)
+					wl_slot_set = le16_to_cpu(dm->slot_now.v7[CXST_W1].dur);
+				wl_slot_real = le16_to_cpu(pcysta->v105.cycle_time.tavg[CXT_WL]);
+
+				if (wl_slot_real > wl_slot_set)
+					diff_t = wl_slot_real - wl_slot_set;
+				else
+					diff_t = wl_slot_set - wl_slot_real;
+			}
+			_chk_btc_err(rtwdev, BTC_DCNT_WL_SLOT_DRIFT, diff_t);
+
+			/* Check diff time between real BT slot and EBT/E5G slot */
+			bt_slot_set = btc->bt_req_len[RTW89_PHY_0];
+			bt_slot_real = le16_to_cpu(pcysta->v105.cycle_time.tavg[CXT_BT]);
+			diff_t = 0;
+			if (dm->tdma_now.type == CXTDMA_OFF &&
+			    dm->tdma_now.ext_ctrl == CXECTL_EXT &&
+			    bt_slot_set != 0) {
+				if (bt_slot_set > bt_slot_real)
+					diff_t = bt_slot_set - bt_slot_real;
+				else
+					diff_t = bt_slot_real - bt_slot_set;
+			}
+
+			_chk_btc_err(rtwdev, BTC_DCNT_BT_SLOT_DRIFT, diff_t);
+			_chk_btc_err(rtwdev, BTC_DCNT_E2G_HANG,
+				     le16_to_cpu(pcysta->v105.slot_cnt[CXST_E2G]));
+			_chk_btc_err(rtwdev, BTC_DCNT_W1_HANG,
+				     le16_to_cpu(pcysta->v105.slot_cnt[CXST_W1]));
+			_chk_btc_err(rtwdev, BTC_DCNT_B1_HANG,
+				     le16_to_cpu(pcysta->v105.slot_cnt[CXST_B1]));
+			_chk_btc_err(rtwdev, BTC_DCNT_CYCLE_HANG,
+				     le16_to_cpu(pcysta->v105.cycles));
 		} else if (ver->fcxcysta == 7) {
 			if (dm->fddt_train == BTC_FDDT_ENABLE)
 				break;
@@ -10690,6 +10747,144 @@ static int _show_fbtc_cysta_v5(struct rtw89_dev *rtwdev, char *buf, size_t bufsz
 	return p - buf;
 }
 
+static int _show_fbtc_cysta_v105(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
+{
+	struct rtw89_btc *btc = &rtwdev->btc;
+	struct rtw89_btc_bt_a2dp_desc *a2dp = &btc->cx.bt0.link_info.a2dp_desc;
+	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
+	struct rtw89_btc_dm *dm = &btc->dm;
+	struct rtw89_btc_fbtc_a2dp_trx_stat_v4 *a2dp_trx;
+	struct rtw89_btc_fbtc_cysta_v105 *pcysta;
+	struct rtw89_btc_rpt_cmn_info *pcinfo;
+	u8 i, cnt = 0, slot_pair, divide_cnt;
+	u16 cycle, c_begin, c_end, store_index;
+	char *p = buf, *end = buf + bufsz;
+
+	pcinfo = &pfwinfo->rpt_fbtc_cysta.cinfo;
+	if (!pcinfo->valid)
+		return 0;
+
+	pcysta = &pfwinfo->rpt_fbtc_cysta.finfo.v105;
+	p += scnprintf(p, end - p,
+		       " %-15s : cycle:%d, bcn[all:%d/all_ok:%d/bt:%d/bt_ok:%d]",
+		       "[cycle_cnt]",
+		       le16_to_cpu(pcysta->cycles),
+		       le16_to_cpu(pcysta->bcn_cnt[CXBCN_ALL]),
+		       le16_to_cpu(pcysta->bcn_cnt[CXBCN_ALL_OK]),
+		       le16_to_cpu(pcysta->bcn_cnt[CXBCN_BT_SLOT]),
+		       le16_to_cpu(pcysta->bcn_cnt[CXBCN_BT_OK]));
+
+	for (i = 0; i < CXST_MAX; i++) {
+		if (!le16_to_cpu(pcysta->slot_cnt[i]))
+			continue;
+
+		p += scnprintf(p, end - p, ", %s:%d", id_to_slot(i),
+			       le16_to_cpu(pcysta->slot_cnt[i]));
+	}
+
+	if (dm->tdma_now.rxflctrl)
+		p += scnprintf(p, end - p, ", leak_rx:%d",
+			       le32_to_cpu(pcysta->leak_slot.cnt_rximr));
+
+	if (pcysta->collision_cnt)
+		p += scnprintf(p, end - p, ", collision:%d",
+			       pcysta->collision_cnt);
+
+	if (le16_to_cpu(pcysta->skip_cnt))
+		p += scnprintf(p, end - p, ", skip:%d",
+			       le16_to_cpu(pcysta->skip_cnt));
+
+	p += scnprintf(p, end - p, "\n");
+
+	p += scnprintf(p, end - p, " %-15s : avg_t[wl:%d/bt:%d/lk:%d.%03d]",
+		       "[cycle_time]",
+		       le16_to_cpu(pcysta->cycle_time.tavg[CXT_WL]),
+		       le16_to_cpu(pcysta->cycle_time.tavg[CXT_BT]),
+		       le16_to_cpu(pcysta->leak_slot.tavg) / 1000,
+		       le16_to_cpu(pcysta->leak_slot.tavg) % 1000);
+	p += scnprintf(p, end - p,
+		       ", max_t[wl:%d/bt:%d/lk:%d.%03d]\n",
+		       le16_to_cpu(pcysta->cycle_time.tmax[CXT_WL]),
+		       le16_to_cpu(pcysta->cycle_time.tmax[CXT_BT]),
+		       le16_to_cpu(pcysta->leak_slot.tmax) / 1000,
+		       le16_to_cpu(pcysta->leak_slot.tmax) % 1000);
+
+	cycle = le16_to_cpu(pcysta->cycles);
+	if (cycle <= 1)
+		goto out;
+
+	/* 1 cycle record 1 wl-slot and 1 bt-slot */
+	slot_pair = BTC_CYCLE_SLOT_MAX / 2;
+
+	if (cycle <= slot_pair)
+		c_begin = 1;
+	else
+		c_begin = cycle - slot_pair + 1;
+
+	c_end = cycle;
+
+	if (a2dp->exist)
+		divide_cnt = 3;
+	else
+		divide_cnt = BTC_CYCLE_SLOT_MAX / 4;
+
+	if (c_begin > c_end)
+		goto out;
+
+	for (cycle = c_begin; cycle <= c_end; cycle++) {
+		cnt++;
+		store_index = ((cycle - 1) % slot_pair) * 2;
+
+		if (cnt % divide_cnt == 1)
+			p += scnprintf(p, end - p, " %-15s : ",
+				       "[cycle_step]");
+
+		p += scnprintf(p, end - p, "->b%02d",
+			       le16_to_cpu(pcysta->slot_step_time[store_index]));
+		if (a2dp->exist) {
+			a2dp_trx = &pcysta->a2dp_trx[store_index];
+			p += scnprintf(p, end - p, "(%d/%d/%dM/%d/%d/%d)",
+				       a2dp_trx->empty_cnt,
+				       a2dp_trx->retry_cnt,
+				       a2dp_trx->tx_rate ? 3 : 2,
+				       a2dp_trx->tx_cnt,
+				       a2dp_trx->ack_cnt,
+				       a2dp_trx->nack_cnt);
+		}
+		p += scnprintf(p, end - p, "->w%02d",
+			       le16_to_cpu(pcysta->slot_step_time[store_index + 1]));
+		if (a2dp->exist) {
+			a2dp_trx = &pcysta->a2dp_trx[store_index + 1];
+			p += scnprintf(p, end - p, "(%d/%d/%dM/%d/%d/%d)",
+				       a2dp_trx->empty_cnt,
+				       a2dp_trx->retry_cnt,
+				       a2dp_trx->tx_rate ? 3 : 2,
+				       a2dp_trx->tx_cnt,
+				       a2dp_trx->ack_cnt,
+				       a2dp_trx->nack_cnt);
+		}
+		if (cnt % divide_cnt == 0 || cnt == c_end)
+			p += scnprintf(p, end - p, "\n");
+	}
+
+	if (a2dp->exist) {
+		p += scnprintf(p, end - p,
+			       " %-15s : a2dp_ept:%d, a2dp_late:%d",
+			       "[a2dp_t_sta]",
+			       le16_to_cpu(pcysta->a2dp_ept.cnt),
+			       le16_to_cpu(pcysta->a2dp_ept.cnt_timeout));
+
+		p += scnprintf(p, end - p, ", avg_t:%d, max_t:%d",
+			       le16_to_cpu(pcysta->a2dp_ept.tavg),
+			       le16_to_cpu(pcysta->a2dp_ept.tmax));
+
+		p += scnprintf(p, end - p, "\n");
+	}
+
+out:
+	return p - buf;
+}
+
 static int _show_fbtc_cysta_v7(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
 {
 	struct rtw89_btc_bt_info *bt = &rtwdev->btc.cx.bt0;
@@ -11081,6 +11276,8 @@ static int _show_fw_dm_msg(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
 		p += _show_fbtc_cysta_v4(rtwdev, p, end - p);
 	else if (ver->fcxcysta == 5)
 		p += _show_fbtc_cysta_v5(rtwdev, p, end - p);
+	else if (ver->fcxcysta == 105)
+		p += _show_fbtc_cysta_v105(rtwdev, p, end - p);
 	else if (ver->fcxcysta == 7)
 		p += _show_fbtc_cysta_v7(rtwdev, p, end - p);
 
diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index 5018c642dba0..7627b5ebabda 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -3352,6 +3352,26 @@ struct rtw89_btc_fbtc_cysta_v5 { /* statistics for cycles */
 	__le32 except_map;
 } __packed;
 
+struct rtw89_btc_fbtc_cysta_v105 {
+	u8 fver;
+	u8 rsvd;
+	u8 collision_cnt;
+	u8 except_cnt;
+	u8 wl_rx_err_ratio[BTC_CYCLE_SLOT_MAX];
+
+	__le16 skip_cnt;
+	__le16 cycles;
+
+	__le16 slot_step_time[BTC_CYCLE_SLOT_MAX];
+	__le16 slot_cnt[CXST_MAX];
+	__le16 bcn_cnt[CXBCN_MAX];
+	struct rtw89_btc_fbtc_cycle_time_info_v5 cycle_time;
+	struct rtw89_btc_fbtc_cycle_leak_info leak_slot;
+	struct rtw89_btc_fbtc_cycle_a2dp_empty_info a2dp_ept;
+	struct rtw89_btc_fbtc_a2dp_trx_stat_v4 a2dp_trx[BTC_CYCLE_SLOT_MAX];
+	__le32 except_map;
+} __packed;
+
 struct rtw89_btc_fbtc_cysta_v7 { /* statistics for cycles */
 	u8 fver;
 	u8 rsvd;
@@ -3381,6 +3401,7 @@ union rtw89_btc_fbtc_cysta_info {
 	struct rtw89_btc_fbtc_cysta_v3 v3;
 	struct rtw89_btc_fbtc_cysta_v4 v4;
 	struct rtw89_btc_fbtc_cysta_v5 v5;
+	struct rtw89_btc_fbtc_cysta_v105 v105;
 	struct rtw89_btc_fbtc_cysta_v7 v7;
 };
 
-- 
2.25.1


^ permalink raw reply related

* [PATCH rtw-next 10/13] wifi: rtw89: coex: Add slots version 2
From: Ping-Ke Shih @ 2026-07-17  6:57 UTC (permalink / raw)
  To: linux-wireless; +Cc: ku920601
In-Reply-To: <20260717065739.64124-1-pkshih@realtek.com>

From: Ching-Te Ku <ku920601@realtek.com>

Slots structure version 2 uses new TLV-Header to package slots information,
patch related entry for version 2.

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 | 54 ++++++++++++++++-------
 drivers/net/wireless/realtek/rtw89/coex.h |  8 ++--
 drivers/net/wireless/realtek/rtw89/core.h |  9 ++++
 3 files changed, 51 insertions(+), 20 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c
index 51108ce5ce31..65d4e9139342 100644
--- a/drivers/net/wireless/realtek/rtw89/coex.c
+++ b/drivers/net/wireless/realtek/rtw89/coex.c
@@ -1133,7 +1133,7 @@ static void _reset_btc_var(struct rtw89_dev *rtwdev, u8 type)
 		/* set the slot_now table to original */
 		btc->dm.tdma_now = t_def[CXTD_OFF];
 		btc->dm.tdma = t_def[CXTD_OFF];
-		if (ver->fcxslots >= 7) {
+		if (ver->fcxslots >= 2) {
 			for (i = 0; i < ARRAY_SIZE(s_def); i++) {
 				btc->dm.slot.v7[i].dur = s_def[i].dur;
 				btc->dm.slot.v7[i].cxtype = s_def[i].cxtype;
@@ -1721,6 +1721,10 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
 			pfinfo = &pfwinfo->rpt_fbtc_slots.finfo.v1;
 			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_slots.finfo.v1);
 			fwsubver->fcxslots = pfwinfo->rpt_fbtc_slots.finfo.v1.fver;
+		} else if (ver->fcxslots == 2) {
+			pfinfo = &pfwinfo->rpt_fbtc_slots.finfo.v2;
+			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_slots.finfo.v2);
+			fwsubver->fcxslots = pfwinfo->rpt_fbtc_slots.finfo.v2.fver;
 		} else if (ver->fcxslots == 7) {
 			pfinfo = &pfwinfo->rpt_fbtc_slots.finfo.v7;
 			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_slots.finfo.v7);
@@ -2232,6 +2236,15 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
 				     memcmp(dm->slot_now.v7,
 					    pfwinfo->rpt_fbtc_slots.finfo.v7.slot,
 					    sizeof(dm->slot_now.v7)));
+		} else if (ver->fcxslots == 2) {
+			rtw89_debug(rtwdev, RTW89_DBG_BTC,
+				    "[BTC], %s(): check %d %zu\n",
+				    __func__, BTC_DCNT_SLOT_NONSYNC,
+				    sizeof(dm->slot_now.v7));
+			_chk_btc_err(rtwdev, BTC_DCNT_SLOT_NONSYNC,
+				     memcmp(dm->slot_now.v7,
+					    pfwinfo->rpt_fbtc_slots.finfo.v2.slot,
+					    sizeof(dm->slot_now.v7)));
 		} else if (ver->fcxslots == 1) {
 			rtw89_debug(rtwdev, RTW89_DBG_BTC,
 				    "[BTC], %s(): check %d %zu\n",
@@ -2687,7 +2700,7 @@ static void _append_slot(struct rtw89_dev *rtwdev)
 {
 	struct rtw89_btc *btc = &rtwdev->btc;
 
-	if (btc->ver->fcxslots == 7)
+	if (btc->ver->fcxslots == 2 || btc->ver->fcxslots == 7)
 		_append_slot_v7(rtwdev);
 	else
 		_append_slot_v1(rtwdev);
@@ -2902,7 +2915,7 @@ static void rtw89_btc_fw_set_slots(struct rtw89_dev *rtwdev)
 	struct rtw89_btc_dm *dm = &btc->dm;
 	u16 n, len;
 
-	if (ver->fcxslots == 7) {
+	if (ver->fcxslots == 2 || ver->fcxslots == 7) {
 		len = sizeof(*tlv_v7) + sizeof(dm->slot.v7);
 		tlv_v7 = kmalloc(len, GFP_KERNEL);
 		if (!tlv_v7)
@@ -3096,7 +3109,7 @@ static void _fw_set_policy(struct rtw89_dev *rtwdev, u16 policy_type,
 			   btc->policy, btc->policy_len);
 	if (!ret) {
 		memcpy(&dm->tdma_now, &dm->tdma, sizeof(dm->tdma_now));
-		if (btc->ver->fcxslots == 7)
+		if (btc->ver->fcxslots == 2 || btc->ver->fcxslots == 7)
 			memcpy(&dm->slot_now.v7, &dm->slot.v7, sizeof(dm->slot_now.v7));
 		else
 			memcpy(&dm->slot_now.v1, &dm->slot.v1, sizeof(dm->slot_now.v1));
@@ -4404,7 +4417,6 @@ void rtw89_btc_set_policy(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_fbtc_slot *s = dm->slot.v1;
 	u8 type;
 	u32 tbl_w1, tbl_b1, tbl_b4;
 	bool tdma_on = false;
@@ -4428,14 +4440,16 @@ void rtw89_btc_set_policy(struct rtw89_dev *rtwdev, u16 policy_type)
 	switch (type) {
 	case BTC_CXP_USERDEF0:
 		*t = t_def[CXTD_OFF];
-		s[CXST_OFF] = s_def[CXST_OFF];
+		_slot_set_le(btc, CXST_OFF, s_def[CXST_OFF].dur,
+			     s_def[CXST_OFF].cxtbl, s_def[CXST_OFF].cxtype);
 		_slot_set_tbl(btc, CXST_OFF, cxtbl[2]);
 		btc->update_policy_force = true;
 		break;
 	case BTC_CXP_OFF: /* TDMA off */
 		tdma_on = false;
 		*t = t_def[CXTD_OFF];
-		s[CXST_OFF] = s_def[CXST_OFF];
+		_slot_set_le(btc, CXST_OFF, s_def[CXST_OFF].dur,
+			     s_def[CXST_OFF].cxtbl, s_def[CXST_OFF].cxtype);
 
 		switch (policy_type) {
 		case BTC_CXP_OFF_BT:
@@ -4498,16 +4512,23 @@ void rtw89_btc_set_policy(struct rtw89_dev *rtwdev, u16 policy_type)
 		*t = t_def[CXTD_OFF_EXT];
 		switch (policy_type) {
 		case BTC_CXP_OFFE_DEF:
-			s[CXST_E2G] = s_def[CXST_E2G];
-			s[CXST_E5G] = s_def[CXST_E5G];
-			s[CXST_EBT] = s_def[CXST_EBT];
-			s[CXST_ENULL] = s_def[CXST_ENULL];
+			_slot_set_le(btc, CXST_E2G, s_def[CXST_E2G].dur,
+				     s_def[CXST_E2G].cxtbl, s_def[CXST_E2G].cxtype);
+			_slot_set_le(btc, CXST_E5G, s_def[CXST_E5G].dur,
+				     s_def[CXST_E5G].cxtbl, s_def[CXST_E5G].cxtype);
+			_slot_set_le(btc, CXST_EBT, s_def[CXST_EBT].dur,
+				     s_def[CXST_EBT].cxtbl, s_def[CXST_EBT].cxtype);
+			_slot_set_le(btc, CXST_ENULL, s_def[CXST_ENULL].dur,
+				     s_def[CXST_ENULL].cxtbl, s_def[CXST_ENULL].cxtype);
 			break;
 		case BTC_CXP_OFFE_DEF2:
 			_slot_set(btc, CXST_E2G, 20, cxtbl[1], SLOT_ISO);
-			s[CXST_E5G] = s_def[CXST_E5G];
-			s[CXST_EBT] = s_def[CXST_EBT];
-			s[CXST_ENULL] = s_def[CXST_ENULL];
+			_slot_set_le(btc, CXST_E5G, s_def[CXST_E5G].dur,
+				     s_def[CXST_E5G].cxtbl, s_def[CXST_E5G].cxtype);
+			_slot_set_le(btc, CXST_EBT, s_def[CXST_EBT].dur,
+				     s_def[CXST_EBT].cxtbl, s_def[CXST_EBT].cxtype);
+			_slot_set_le(btc, CXST_ENULL, s_def[CXST_ENULL].dur,
+				     s_def[CXST_ENULL].cxtbl, s_def[CXST_ENULL].cxtype);
 			break;
 		}
 		break;
@@ -10081,6 +10102,7 @@ static int _show_fbtc_tdma(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
 static int _show_fbtc_slots(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
 {
 	struct rtw89_btc *btc = &rtwdev->btc;
+	const struct rtw89_btc_ver *ver = btc->ver;
 	struct rtw89_btc_dm *dm = &btc->dm;
 	char *p = buf, *end = buf + bufsz;
 	u16 dur, cxtype;
@@ -10088,11 +10110,11 @@ static int _show_fbtc_slots(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
 	u8 i = 0;
 
 	for (i = 0; i < CXST_MAX; i++) {
-		if (btc->ver->fcxslots == 1) {
+		if (ver->fcxslots == 1) {
 			dur = le16_to_cpu(dm->slot_now.v1[i].dur);
 			tbl = le32_to_cpu(dm->slot_now.v1[i].cxtbl);
 			cxtype = le16_to_cpu(dm->slot_now.v1[i].cxtype);
-		} else if (btc->ver->fcxslots == 7) {
+		} else if (ver->fcxslots == 2 || ver->fcxslots == 7) {
 			dur = le16_to_cpu(dm->slot_now.v7[i].dur);
 			tbl = le32_to_cpu(dm->slot_now.v7[i].cxtbl);
 			cxtype = le16_to_cpu(dm->slot_now.v7[i].cxtype);
diff --git a/drivers/net/wireless/realtek/rtw89/coex.h b/drivers/net/wireless/realtek/rtw89/coex.h
index e17407696d8a..3238c44429a9 100644
--- a/drivers/net/wireless/realtek/rtw89/coex.h
+++ b/drivers/net/wireless/realtek/rtw89/coex.h
@@ -424,7 +424,7 @@ void _slot_set_le(struct rtw89_btc *btc, u8 sid, __le16 dura, __le32 tbl, __le16
 		btc->dm.slot.v1[sid].dur = dura;
 		btc->dm.slot.v1[sid].cxtbl = tbl;
 		btc->dm.slot.v1[sid].cxtype = type;
-	} else if (btc->ver->fcxslots == 7) {
+	} else if (btc->ver->fcxslots == 2 || btc->ver->fcxslots == 7) {
 		btc->dm.slot.v7[sid].dur = dura;
 		btc->dm.slot.v7[sid].cxtype = type;
 		btc->dm.slot.v7[sid].cxtbl = tbl;
@@ -442,7 +442,7 @@ void _slot_set_dur(struct rtw89_btc *btc, u8 sid, u16 dura)
 {
 	if (btc->ver->fcxslots == 1)
 		btc->dm.slot.v1[sid].dur = cpu_to_le16(dura);
-	else if (btc->ver->fcxslots == 7)
+	else if (btc->ver->fcxslots == 2 || btc->ver->fcxslots == 7)
 		btc->dm.slot.v7[sid].dur = cpu_to_le16(dura);
 }
 
@@ -451,7 +451,7 @@ void _slot_set_type(struct rtw89_btc *btc, u8 sid, u16 type)
 {
 	if (btc->ver->fcxslots == 1)
 		btc->dm.slot.v1[sid].cxtype = cpu_to_le16(type);
-	else if (btc->ver->fcxslots == 7)
+	else if (btc->ver->fcxslots == 2 || btc->ver->fcxslots == 7)
 		btc->dm.slot.v7[sid].cxtype = cpu_to_le16(type);
 }
 
@@ -460,7 +460,7 @@ void _slot_set_tbl(struct rtw89_btc *btc, u8 sid, u32 tbl)
 {
 	if (btc->ver->fcxslots == 1)
 		btc->dm.slot.v1[sid].cxtbl = cpu_to_le32(tbl);
-	else if (btc->ver->fcxslots == 7)
+	else if (btc->ver->fcxslots == 2 || btc->ver->fcxslots == 7)
 		btc->dm.slot.v7[sid].cxtbl = cpu_to_le32(tbl);
 }
 
diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index 110549b268d4..5018c642dba0 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -3091,6 +3091,14 @@ struct rtw89_btc_fbtc_slot_v7 {
 	__le32 cxtbl;
 } __packed;
 
+struct rtw89_btc_fbtc_slots_v2 {
+	u8 fver; /* btc_ver::fcxslots */
+	u8 tbl_num;
+	__le16 rsvd;
+	__le32 update_map;
+	struct rtw89_btc_fbtc_slot_v7 slot[CXST_MAX];
+} __packed;
+
 struct rtw89_btc_fbtc_slot_u16 {
 	__le16 dur; /* slot duration */
 	__le16 cxtype;
@@ -3116,6 +3124,7 @@ struct rtw89_btc_fbtc_slots_v7 {
 
 union rtw89_btc_fbtc_slots_info {
 	struct rtw89_btc_fbtc_slots v1;
+	struct rtw89_btc_fbtc_slots_v2 v2;
 	struct rtw89_btc_fbtc_slots_v7 v7;
 } __packed;
 
-- 
2.25.1


^ permalink raw reply related

* [PATCH rtw-next 09/13] wifi: rtw89: coex: Add TDMA version 4
From: Ping-Ke Shih @ 2026-07-17  6:57 UTC (permalink / raw)
  To: linux-wireless; +Cc: ku920601
In-Reply-To: <20260717065739.64124-1-pkshih@realtek.com>

From: Ching-Te Ku <ku920601@realtek.com>

TDMA version 4 uses new TLV-Header to package TDMA information,
patch related entry for version 4.

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 | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c
index 6bbcc6cd5dae..51108ce5ce31 100644
--- a/drivers/net/wireless/realtek/rtw89/coex.c
+++ b/drivers/net/wireless/realtek/rtw89/coex.c
@@ -1705,7 +1705,8 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
 			pfinfo = &pfwinfo->rpt_fbtc_tdma.finfo.v1;
 			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_tdma.finfo.v1);
 			fwsubver->fcxtdma = 0;
-		} else if (ver->fcxtdma == 3 || ver->fcxtdma == 7) {
+		} else if (ver->fcxtdma == 3 || ver->fcxtdma == 4 ||
+			   ver->fcxtdma == 7) {
 			pfinfo = &pfwinfo->rpt_fbtc_tdma.finfo.v3;
 			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_tdma.finfo.v3);
 			fwsubver->fcxtdma = pfwinfo->rpt_fbtc_tdma.finfo.v3.fver;
@@ -2212,7 +2213,8 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
 				     memcmp(&dm->tdma_now,
 					    &pfwinfo->rpt_fbtc_tdma.finfo.v1,
 					    sizeof(dm->tdma_now)));
-		else if (ver->fcxtdma == 3 || ver->fcxtdma == 7)
+		else if (ver->fcxtdma == 3 || ver->fcxtdma == 4 ||
+			 ver->fcxtdma == 7)
 			_chk_btc_err(rtwdev, BTC_DCNT_TDMA_NONSYNC,
 				     memcmp(&dm->tdma_now,
 					    &pfwinfo->rpt_fbtc_tdma.finfo.v3.tdma,
@@ -2559,7 +2561,7 @@ static void _append_tdma(struct rtw89_dev *rtwdev)
 		tlv->len = sizeof(*v);
 		*v = dm->tdma;
 		btc->policy_len += BTC_TLV_HDR_LEN + sizeof(*v);
-	} else if (ver->fcxtdma == 7) {
+	} else if (ver->fcxtdma == 7 || ver->fcxtdma == 4) {
 		tlv_v7 = (struct rtw89_btc_btf_tlv_v7 *)&btc->policy[len];
 		tlv_v7->len = sizeof(dm->tdma);
 		tlv_v7->ver = ver->fcxtdma;
-- 
2.25.1


^ permalink raw reply related

* [PATCH rtw-next 08/13] wifi: rtw89: coex: Add firmware 0.29.133.X support for RTL8852B family
From: Ping-Ke Shih @ 2026-07-17  6:57 UTC (permalink / raw)
  To: linux-wireless; +Cc: ku920601
In-Reply-To: <20260717065739.64124-1-pkshih@realtek.com>

From: Ching-Te Ku <ku920601@realtek.com>

The new firmware modified GPIO setup structure format for third party
chip set I/O control & offloaded Wi-Fi TRX status to firmware for training
traffic RF-Parameters & TDMA mechanism.

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 | 27 +++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c
index 10699c92273a..6bbcc6cd5dae 100644
--- a/drivers/net/wireless/realtek/rtw89/coex.c
+++ b/drivers/net/wireless/realtek/rtw89/coex.c
@@ -142,6 +142,15 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = {
 	 .max_role_num = 6, .fcxosi = 6,   .fcxmlo = 2,   .bt_desired = 8,
 	 .fcxtrx = 9,
 	},
+	{RTL8852BT, RTW89_FW_VER_CODE(0, 29, 133, 0),
+	 .fcxbtcrpt = 9, .fcxtdma = 7,    .fcxslots = 7, .fcxcysta = 7,
+	 .fcxstep = 7,   .fcxnullsta = 7, .fcxmreg = 7,  .fcxgpiodbg = 8,
+	 .fcxbtver = 7,  .fcxbtscan = 7,  .fcxbtafh = 7, .fcxbtdevinfo = 7,
+	 .fwlrole = 7,   .frptmap = 5,    .fcxctrl = 7,  .fcxinit = 107,
+	 .fwevntrptl = 1, .fwc2hfunc = 2, .drvinfo_ver = 103, .info_buf = 1800,
+	 .max_role_num = 6, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 8,
+	 .fcxtrx = 107,
+	},
 	{RTL8852BT, RTW89_FW_VER_CODE(0, 29, 122, 0),
 	 .fcxbtcrpt = 8, .fcxtdma = 7,    .fcxslots = 7, .fcxcysta = 7,
 	 .fcxstep = 7,   .fcxnullsta = 7, .fcxmreg = 7,  .fcxgpiodbg = 7,
@@ -187,6 +196,15 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = {
 	 .max_role_num = 6, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 7,
 	 .fcxtrx = 0,
 	},
+	{RTL8851B, RTW89_FW_VER_CODE(0, 29, 133, 0),
+	 .fcxbtcrpt = 9, .fcxtdma = 7,    .fcxslots = 7, .fcxcysta = 7,
+	 .fcxstep = 7,   .fcxnullsta = 7, .fcxmreg = 7,  .fcxgpiodbg = 8,
+	 .fcxbtver = 7,  .fcxbtscan = 7,  .fcxbtafh = 7, .fcxbtdevinfo = 7,
+	 .fwlrole = 7,   .frptmap = 5,    .fcxctrl = 7,  .fcxinit = 107,
+	 .fwevntrptl = 1, .fwc2hfunc = 2, .drvinfo_ver = 103, .info_buf = 1800,
+	 .max_role_num = 6, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 8,
+	 .fcxtrx = 107,
+	},
 	{RTL8851B, RTW89_FW_VER_CODE(0, 29, 29, 0),
 	 .fcxbtcrpt = 105, .fcxtdma = 3,    .fcxslots = 1, .fcxcysta = 5,
 	 .fcxstep = 3,   .fcxnullsta = 2, .fcxmreg = 2,  .fcxgpiodbg = 1,
@@ -223,6 +241,15 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = {
 	 .max_role_num = 5, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 7,
 	 .fcxtrx = 0,
 	},
+	{RTL8852B, RTW89_FW_VER_CODE(0, 29, 133, 0),
+	 .fcxbtcrpt = 9, .fcxtdma = 7,    .fcxslots = 7, .fcxcysta = 7,
+	 .fcxstep = 7,   .fcxnullsta = 7, .fcxmreg = 7,  .fcxgpiodbg = 8,
+	 .fcxbtver = 7,  .fcxbtscan = 7,  .fcxbtafh = 7, .fcxbtdevinfo = 7,
+	 .fwlrole = 7,   .frptmap = 105,  .fcxctrl = 7,  .fcxinit = 107,
+	 .fwevntrptl = 1, .fwc2hfunc = 2, .drvinfo_ver = 103, .info_buf = 1800,
+	 .max_role_num = 6, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 8,
+	 .fcxtrx = 107,
+	},
 	{RTL8852B, RTW89_FW_VER_CODE(0, 29, 122, 0),
 	 .fcxbtcrpt = 8, .fcxtdma = 7,    .fcxslots = 7, .fcxcysta = 7,
 	 .fcxstep = 7,   .fcxnullsta = 7, .fcxmreg = 7,  .fcxgpiodbg = 7,
-- 
2.25.1


^ permalink raw reply related

* [PATCH rtw-next 07/13] wifi: rtw89: coex: Fix Wi-Fi role info H2C command header issue
From: Ping-Ke Shih @ 2026-07-17  6:57 UTC (permalink / raw)
  To: linux-wireless; +Cc: ku920601
In-Reply-To: <20260717065739.64124-1-pkshih@realtek.com>

From: Ching-Te Ku <ku920601@realtek.com>

The function to filled up H2C command data is the last step in the driver,
the next step is going to firmware. So the structure version number should
not included driver local branch number (like firmware is v5, but driver
branch to v105), it should be assigned as a explicit version number which
paired with firmware.

Signed-off-by: Ching-Te Ku <ku920601@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
 drivers/net/wireless/realtek/rtw89/fw.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c
index 53ec6efb1cb2..34bc52519ea2 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.c
+++ b/drivers/net/wireless/realtek/rtw89/fw.c
@@ -6255,6 +6255,10 @@ int rtw89_fw_h2c_cxdrv_role_v7(struct rtw89_dev *rtwdev, u8 type)
 	skb_put(skb, len);
 	h2c = (struct rtw89_h2c_cxrole_v7 *)skb->data;
 
+	h2c->hdr.type = type;
+	h2c->hdr.ver = 7;
+	h2c->hdr.len = len - H2C_LEN_CXDRVHDR_V7;
+
 	h2c->r.connect_cnt = r->connect_cnt;
 	h2c->r.link_mode = r->link_mode;
 	h2c->r.link_mode_chg = r->link_mode_chg;
@@ -6323,7 +6327,7 @@ int rtw89_fw_h2c_cxdrv_role_v8(struct rtw89_dev *rtwdev, u8 type)
 	h2c = (struct rtw89_h2c_cxrole_v8 *)skb->data;
 
 	h2c->hdr.type = type;
-	h2c->hdr.ver = rtwdev->btc.ver->fwlrole;
+	h2c->hdr.ver = 8;
 	h2c->hdr.len = len - H2C_LEN_CXDRVHDR_V7;
 	h2c->r.connect_cnt = r->connect_cnt;
 	h2c->r.link_mode = r->link_mode;
@@ -6397,7 +6401,7 @@ int rtw89_fw_h2c_cxdrv_role_v10(struct rtw89_dev *rtwdev, u8 type)
 	h2c = (struct rtw89_h2c_cxrole_v10 *)skb->data;
 
 	h2c->hdr.type = type;
-	h2c->hdr.ver = rtwdev->btc.ver->fwlrole;
+	h2c->hdr.ver = 10;
 	h2c->hdr.len = len - H2C_LEN_CXDRVHDR_V7;
 
 	for (j = RTW89_MAC_0; j <= RTW89_MAC_1; j++) {
-- 
2.25.1


^ permalink raw reply related

* [PATCH rtw-next 06/13] wifi: rtw89: coex: Add driver info H2C command index version 103
From: Ping-Ke Shih @ 2026-07-17  6:57 UTC (permalink / raw)
  To: linux-wireless; +Cc: ku920601
In-Reply-To: <20260717065739.64124-1-pkshih@realtek.com>

From: Ching-Te Ku <ku920601@realtek.com>

The 0.29.133.X firmware driver info H2C index maximum is 5, to prevent
switch case fall through and send unexpected H2C commands, add version
code 103 as judgment.

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 | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c
index ad52274a3979..10699c92273a 100644
--- a/drivers/net/wireless/realtek/rtw89/coex.c
+++ b/drivers/net/wireless/realtek/rtw89/coex.c
@@ -3138,7 +3138,7 @@ static void _fw_set_drv_info(struct rtw89_dev *rtwdev, u8 index)
 		rtw89_fw_h2c_cxdrv_rfk(rtwdev, index);
 		break;
 	case CXDRVINFO_TXPWR:
-		if (ver->drvinfo_ver == 3)
+		if (ver->drvinfo_ver == 3 || ver->drvinfo_ver == 103)
 			index = 4;
 
 		if (ver->fcxtrx == 7 || ver->fcxtrx == 107)
@@ -3147,26 +3147,27 @@ static void _fw_set_drv_info(struct rtw89_dev *rtwdev, u8 index)
 			rtw89_fw_h2c_cxtxpwr_v9(rtwdev, index);
 		break;
 	case CXDRVINFO_FDDT:
-		if (ver->drvinfo_ver == 3)
+		if (ver->drvinfo_ver == 3 || ver->drvinfo_ver == 103)
 			index = 5;
 		else
 			return;
 
-		rtw89_debug(rtwdev, RTW89_DBG_BTC, "drv_info FDDT index=%d\n", index);
 		break;
 	case CXDRVINFO_MLO:
+		if (!ver->fcxmlo || ver->drvinfo_ver == 103)
+			return;
+
 		if (ver->drvinfo_ver == 3)
 			index = 6;
 		else
 			return;
 
-		rtw89_debug(rtwdev, RTW89_DBG_BTC, "drv_info MLO index=%d\n", index);
 		break;
 	case CXDRVINFO_OSI:
-		if (!ver->fcxosi)
+		if (!ver->fcxosi || ver->drvinfo_ver == 103)
 			return;
 
-		if (ver->drvinfo_ver > 1)
+		if (ver->drvinfo_ver == 3)
 			index = 7;
 		else
 			return;
-- 
2.25.1


^ permalink raw reply related

* [PATCH rtw-next 05/13] wifi: rtw89: coex: Refine chip initial related structure
From: Ping-Ke Shih @ 2026-07-17  6:57 UTC (permalink / raw)
  To: linux-wireless; +Cc: ku920601
In-Reply-To: <20260717065739.64124-1-pkshih@realtek.com>

From: Ching-Te Ku <ku920601@realtek.com>

Due to the firmware version become more and more, the version divided
branch coding method make the related code scattered everywhere, and
too much version macro, rearrange the code, assign the value to version
format only when H2C commands.

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     | 123 ++++-----------
 drivers/net/wireless/realtek/rtw89/core.h     |  89 +++++++++--
 drivers/net/wireless/realtek/rtw89/fw.c       | 101 +++++++++---
 drivers/net/wireless/realtek/rtw89/fw.h       |   5 +
 drivers/net/wireless/realtek/rtw89/rtw8851b.c | 128 +++++----------
 drivers/net/wireless/realtek/rtw89/rtw8852a.c |  62 +++-----
 drivers/net/wireless/realtek/rtw89/rtw8852b.c |  66 +++-----
 .../net/wireless/realtek/rtw89/rtw8852bt.c    |  71 ++++-----
 drivers/net/wireless/realtek/rtw89/rtw8852c.c |  62 +++-----
 drivers/net/wireless/realtek/rtw89/rtw8922a.c |  53 +++----
 drivers/net/wireless/realtek/rtw89/rtw8922d.c | 149 +++++++++---------
 11 files changed, 423 insertions(+), 486 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c
index b73040428c58..ad52274a3979 100644
--- a/drivers/net/wireless/realtek/rtw89/coex.c
+++ b/drivers/net/wireless/realtek/rtw89/coex.c
@@ -1142,13 +1142,7 @@ static void _reset_btc_var(struct rtw89_dev *rtwdev, u8 type)
 
 	if (type & BTC_RESET_MDINFO) {
 		memset(&btc->mdinfo, 0, sizeof(btc->mdinfo));
-
-		if (ver->fcxinit == 10)
-			btc->mdinfo.md_v10.ant.isolation = RTW89_BTC_DEFAULT_ANISO;
-		else if (ver->fcxinit == 7)
-			btc->mdinfo.md_v7.ant.isolation = RTW89_BTC_DEFAULT_ANISO;
-		else
-			btc->mdinfo.md.ant.isolation = RTW89_BTC_DEFAULT_ANISO;
+		btc->mdinfo.ant.isolation = RTW89_BTC_DEFAULT_ANISO;
 	}
 }
 
@@ -1169,27 +1163,22 @@ static void _get_reg_status(struct rtw89_dev *rtwdev, u8 type, u8 *val)
 {
 	struct rtw89_btc *btc = &rtwdev->btc;
 	const struct rtw89_btc_ver *ver = btc->ver;
-	union rtw89_btc_module_info *md = &btc->mdinfo;
+	struct rtw89_btc_module *md = &btc->mdinfo;
 	union rtw89_btc_fbtc_mreg_val *pmreg;
 	u32 pre_agc_addr = R_BTC_BB_PRE_AGC_S1;
 	u32 reg_val;
-	u8 idx, switch_type;
-
-	if (ver->fcxinit == 7)
-		switch_type = md->md_v7.switch_type;
-	else
-		switch_type = md->md.switch_type;
+	u8 idx;
 
 	if (btc->btg_pos == RF_PATH_A)
 		pre_agc_addr = R_BTC_BB_PRE_AGC_S0;
 
 	switch (type) {
 	case BTC_CSTATUS_TXDIV_POS:
-		if (switch_type == BTC_SWITCH_INTERNAL)
+		if (md->bt0_sw_type == BTC_SWITCH_INTERNAL)
 			*val = BTC_ANT_DIV_MAIN;
 		break;
 	case BTC_CSTATUS_RXDIV_POS:
-		if (switch_type == BTC_SWITCH_INTERNAL)
+		if (md->bt0_sw_type == BTC_SWITCH_INTERNAL)
 			*val = BTC_ANT_DIV_MAIN;
 		break;
 	case BTC_CSTATUS_BB_GNT_MUX:
@@ -3098,7 +3087,7 @@ static void _fw_set_drv_info(struct rtw89_dev *rtwdev, u8 index)
 
 	switch (index) {
 	case CXDRVINFO_INIT:
-		if (ver->fcxinit == 7)
+		if (ver->fcxinit == 7 || ver->fcxinit == 107)
 			rtw89_fw_h2c_cxdrv_init_v7(rtwdev, index);
 		else if (ver->fcxinit == 10)
 			rtw89_fw_h2c_cxdrv_init_v10(rtwdev, index);
@@ -4206,14 +4195,7 @@ static bool _check_freerun(struct rtw89_dev *rtwdev)
 	struct rtw89_btc_wl_role_info *wl_rinfo = &wl->role_info;
 	struct rtw89_btc_bt_link_info *bt_linfo = &bt->link_info;
 	struct rtw89_btc_bt_hid_desc *hid = &bt_linfo->hid_desc;
-	union rtw89_btc_module_info *md = &btc->mdinfo;
-	const struct rtw89_btc_ver *ver = btc->ver;
-	u8 isolation;
-
-	if (ver->fcxinit == 7)
-		isolation = md->md_v7.ant.isolation;
-	else
-		isolation = md->md.ant.isolation;
+	struct rtw89_btc_module *md = &btc->mdinfo;
 
 	if (btc->ant_type == BTC_ANT_SHARED) {
 		btc->dm.trx_para_level = 0;
@@ -4237,7 +4219,7 @@ static bool _check_freerun(struct rtw89_dev *rtwdev)
 	}
 
 	/* TODO get isolation by BT psd */
-	if (isolation >= BTC_FREERUN_ANTISO_MIN) {
+	if (md->ant.isolation >= BTC_FREERUN_ANTISO_MIN) {
 		btc->dm.trx_para_level = 5;
 		return true;
 	}
@@ -6177,21 +6159,14 @@ static void _wl_req_mac(struct rtw89_dev *rtwdev, u8 mac)
 static void _update_zb_coex_tbl(struct rtw89_dev *rtwdev)
 {
 	struct rtw89_btc *btc = &rtwdev->btc;
-	const struct rtw89_btc_ver *ver = btc->ver;
 	u32 zb_tbl0 = 0xda5a5a5a, zb_tbl1 = 0xda5a5a5a;
 	u8 link_mode_chg = btc->cx.wl.link_mode_chg;
 	u8 mode = btc->cx.wl.role_info.link_mode;
-	u8 wa_type;
 
 	if (btc->dm.run_reason != BTC_RSN_NTFY_INIT && !link_mode_chg)
 		return;
 
-	if (ver->fcxinit == 7)
-		wa_type = btc->mdinfo.md_v7.wa_type;
-	else
-		wa_type = btc->mdinfo.md.wa_type;
-
-	if (!(wa_type & BTC_WA_HFP_ZB))
+	if (!(btc->mdinfo.wa_type & BTC_WA_HFP_ZB))
 		return;
 
 	if (btc->dm.tdd_bind.rf_band == BIT(RTW89_BAND_5G) ||
@@ -8106,40 +8081,26 @@ 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 == 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;
-		dm->init_info.init_v7.cx_other = btc->cx.bt_ext.func_type;
-		dm->init_info.init_v7.wl_guard_ch = chip->afh_guard_ch;
-		dm->init_info.init_v7.module = btc->mdinfo.md_v7;
-	} else {
-		dm->init_info.init.wl_only = (u8)dm->wl_only;
-		dm->init_info.init.bt_only = (u8)dm->bt_only;
-		dm->init_info.init.wl_init_ok = (u8)wl->status.map.init_ok;
-		dm->init_info.init.dbcc_en = rtwdev->dbcc_en;
-		dm->init_info.init.cx_other = btc->cx.bt_ext.func_type;
-		dm->init_info.init.wl_guard_ch = chip->afh_guard_ch;
-		dm->init_info.init.module = btc->mdinfo.md;
-	}
+	dm->init_info.init_mode = wl->coex_mode;
+	dm->init_info.wl_init_ok = wl->status.map.init_ok;
+	dm->init_info.endian_type = BTC_PLATFORM_LITTLE_ENDIAN;
+	dm->init_info.bt0_function = cx->bt0.func_type;
+	dm->init_info.bt1_function = cx->bt1.func_type;
+	dm->init_info.bt2_function = cx->bt_ext.func_type;
+	dm->init_info.pta_mode = RTW89_MAC_AX_COEX_RTK_MODE;
+	dm->init_info.pta_direction = RTW89_MAC_AX_COEX_INNER;
+	dm->init_info.wl_only = dm->wl_only;
+	dm->init_info.bt_only = dm->bt_only;
+	dm->init_info.wl_init_ok = wl->status.map.init_ok;
+	dm->init_info.cx_other = btc->cx.bt_ext.func_type;
+	dm->init_info.wl_guard_ch = chip->afh_guard_ch;
+	dm->init_info.dbcc_en = rtwdev->dbcc_en;
+
+	dm->init_info.module = btc->mdinfo;
 
 	_fw_set_drv_info(rtwdev, CXDRVINFO_INIT);
 	_fw_set_drv_info(rtwdev, CXDRVINFO_CTRL);
@@ -9175,7 +9136,7 @@ void rtw89_btc_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb,
 
 static int _show_cx_info(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
 {
-	union rtw89_btc_module_info *md = &rtwdev->btc.mdinfo;
+	struct rtw89_btc_module *md = &rtwdev->btc.mdinfo;
 	const struct rtw89_chip_info *chip = rtwdev->chip;
 	const struct rtw89_btc_ver *ver = rtwdev->btc.ver;
 	struct rtw89_hal *hal = &rtwdev->hal;
@@ -9184,7 +9145,6 @@ static int _show_cx_info(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
 	struct rtw89_btc_bt_info *bt = &btc->cx.bt0;
 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
 	u32 ver_main = 0, ver_sub = 0, ver_hotfix = 0, id_branch = 0;
-	u8 cv, rfe, iso, ant_num, ant_single_pos;
 	char *p = buf, *end = buf + bufsz;
 
 	if (!(dm->coex_info_map & BTC_COEX_INFO_CX))
@@ -9232,25 +9192,12 @@ static int _show_cx_info(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
 		       wl->ver_info.build_time, wl->ver_info.build_date,
 		       bt->ver_info.fw, bt->run_patch_code ? "patch" : "ROM");
 
-	if (ver->fcxinit == 7) {
-		cv = md->md_v7.kt_ver;
-		rfe = md->md_v7.rfe_type;
-		iso = md->md_v7.ant.isolation;
-		ant_num = md->md_v7.ant.num;
-		ant_single_pos = md->md_v7.ant.single_pos;
-	} else {
-		cv = md->md.cv;
-		rfe = md->md.rfe_type;
-		iso = md->md.ant.isolation;
-		ant_num = md->md.ant.num;
-		ant_single_pos = md->md.ant.single_pos;
-	}
-
 	p += scnprintf(p, end - p,
 		       " %-15s : cv:%x, rfe_type:0x%x, ant_iso:%d, ant_pg:%d, %s",
-		       "[hw_info]", cv, rfe, iso, ant_num,
-		       ant_num > 1 ? "" :
-		       ant_single_pos ? "1Ant_Pos:S1, " : "1Ant_Pos:S0, ");
+		       "[hw_info]",
+		       md->kt_ver, md->rfe_type, md->ant.isolation,
+		       md->ant.num, md->ant.num > 1 ? "" :
+		       md->ant.single_pos ? "1Ant_Pos:S1, " : "1Ant_Pos:S0, ");
 
 	p += scnprintf(p, end - p,
 		       "3rd_coex:%d, dbcc:%d, tx_num:%d, rx_num:%d\n",
@@ -9417,7 +9364,7 @@ static int _show_bt_info(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
 	struct rtw89_btc_bt_info *bt = &cx->bt0;
 	struct rtw89_btc_wl_info *wl = &cx->wl;
 	struct rtw89_btc_bt_link_info *bt_linfo = &bt->link_info;
-	union rtw89_btc_module_info *md = &btc->mdinfo;
+	struct rtw89_btc_module *md = &btc->mdinfo;
 	s8 br_dbm = bt->link_info.bt_txpwr_desc.br_dbm;
 	s8 le_dbm = bt->link_info.bt_txpwr_desc.le_dbm;
 	u8 hw_band = wl->role_info.pta_req_band;
@@ -9425,23 +9372,17 @@ static int _show_bt_info(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
 	char *p = buf, *end = buf + bufsz;
 	u8 *afh = bt_linfo->afh_map;
 	u8 *afh_le = bt_linfo->afh_map_le;
-	u8 bt_pos;
 
 	if (!(btc->dm.coex_info_map & BTC_COEX_INFO_BT))
 		return 0;
 
-	if (ver->fcxinit == 7)
-		bt_pos = md->md_v7.bt_pos;
-	else
-		bt_pos = md->md.bt_pos;
-
 	p += scnprintf(p, end - p, "========== [BT Status] ==========\n");
 
 	p += scnprintf(p, end - p,
 		       " %-15s : enable:%s, btg:%s%s, connect:%s, ",
 		       "[status]", bt->enable.now ? "Y" : "N",
 		       bt->btg_type ? "Y" : "N",
-		       (bt->enable.now && (bt->btg_type != bt_pos) ?
+		       (bt->enable.now && (bt->btg_type != md->bt0_pos) ?
 			"(efuse-mismatch!!)" : ""),
 		       (bt_linfo->status.map.connect ? "Y" : "N"));
 
diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index 0ec582e86b5b..110549b268d4 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -1499,7 +1499,7 @@ enum rtw89_btc_bt_profile {
 	BTC_PROFILE_MAX = 4,
 };
 
-struct rtw89_btc_ant_info {
+struct rtw89_btc_ant_info_v0 {
 	u8 type;  /* shared, dedicated */
 	u8 num;
 	u8 isolation;
@@ -1535,6 +1535,21 @@ struct rtw89_btc_ant_info_v10 {
 	u8 ant_xmap[2][4];
 } __packed;
 
+struct rtw89_btc_ant_info {
+	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];
+
+	u8 diversity; /* only for wifi use 1-antenna */
+};
+
 enum rtw89_tfc_dir {
 	RTW89_TFC_UL,
 	RTW89_TFC_DL,
@@ -2329,8 +2344,8 @@ struct rtw89_btc_wl_info {
 	u32 wcnt[BTC_WCNT_NUM];
 };
 
-struct rtw89_btc_module {
-	struct rtw89_btc_ant_info ant;
+struct rtw89_btc_module_v0 {
+	struct rtw89_btc_ant_info_v0 ant;
 	u8 rfe_type;
 	u8 cv;
 
@@ -2371,11 +2386,27 @@ struct rtw89_btc_module_v10 {
 } __packed;
 
 union rtw89_btc_module_info {
-	struct rtw89_btc_module md;
+	struct rtw89_btc_module_v0 md_v0;
 	struct rtw89_btc_module_v7 md_v7;
 	struct rtw89_btc_module_v10 md_v10;
 };
 
+struct rtw89_btc_module {
+	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;
+
+	u8 bt_solo;
+
+	struct rtw89_btc_ant_info ant;
+};
+
 #define RTW89_BTC_DM_MAXSTEP 30
 #define RTW89_BTC_DM_CNT_MAX (RTW89_BTC_DM_MAXSTEP * 8)
 
@@ -2385,8 +2416,8 @@ struct rtw89_btc_dm_step {
 	bool step_ov;
 };
 
-struct rtw89_btc_init_info {
-	struct rtw89_btc_module module;
+struct rtw89_btc_init_info_v0 {
+	struct rtw89_btc_module_v0 module;
 	u8 wl_guard_ch;
 
 	u8 wl_only: 1;
@@ -2396,7 +2427,7 @@ struct rtw89_btc_init_info {
 	u8 bt_only: 1;
 
 	u16 rsvd;
-};
+} __packed;
 
 struct rtw89_btc_init_info_v7 {
 	u8 wl_guard_ch;
@@ -2412,6 +2443,20 @@ struct rtw89_btc_init_info_v7 {
 	struct rtw89_btc_module_v7 module;
 } __packed;
 
+struct rtw89_btc_init_info_v107 {
+	u8 wl_guard_ch;
+	u8 wl_only;
+	u8 wl_init_ok;
+	u8 dbcc_en;
+
+	u8 cx_other;
+	u8 bt_only;
+	u8 rsvd;
+	u8 rsvd1;
+
+	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  */
@@ -2424,12 +2469,34 @@ struct rtw89_btc_init_info_v10 {
 	u8 pta_direction;
 
 	struct rtw89_btc_module_v10 module;
-};
+} __packed;
 
 union rtw89_btc_init_info_u {
-	struct rtw89_btc_init_info init;
+	struct rtw89_btc_init_info_v0 init_v0;
 	struct rtw89_btc_init_info_v7 init_v7;
 	struct rtw89_btc_init_info_v10 init_v10;
+	struct rtw89_btc_init_info_v107 init_v107;
+};
+
+struct rtw89_btc_init_info {
+	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;
+
+	u8 dbcc_en;
+	u8 cx_other;
+	u8 bt_only;
+	u8 wl_only;
+
+	u8 wl_guard_ch;
+
+	struct rtw89_btc_module module;
 };
 
 struct rtw89_btc_wl_tx_limit_para {
@@ -3657,7 +3724,7 @@ struct rtw89_btc_dm {
 	struct rtw89_btc_gnt_ctrl gnt_set[RTW89_MAC_AX_COEX_GNT_NR];
 	struct rtw89_btc_gnt_ctrl gnt_val[RTW89_MAC_AX_COEX_GNT_NR];
 	struct rtw89_mac_ax_wl_act wlact_set[BTC_ALL_BT_EZL];
-	union rtw89_btc_init_info_u init_info; /* pass to wl_fw if offload */
+	struct rtw89_btc_init_info init_info; /* pass to wl_fw if offload */
 	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;
@@ -4010,7 +4077,7 @@ struct rtw89_btc {
 	struct rtw89_btc_cx cx;
 	struct rtw89_btc_dm dm;
 	struct rtw89_btc_ctrl ctrl;
-	union rtw89_btc_module_info mdinfo;
+	struct rtw89_btc_module mdinfo;
 	struct rtw89_btc_btf_fwinfo fwinfo;
 	struct rtw89_btc_dbg dbg;
 
diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c
index 33303c097f47..53ec6efb1cb2 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.c
+++ b/drivers/net/wireless/realtek/rtw89/fw.c
@@ -5770,9 +5770,9 @@ int rtw89_fw_h2c_cxdrv_init(struct rtw89_dev *rtwdev, u8 type)
 {
 	struct rtw89_btc *btc = &rtwdev->btc;
 	struct rtw89_btc_dm *dm = &btc->dm;
-	struct rtw89_btc_init_info *init_info = &dm->init_info.init;
-	struct rtw89_btc_module *module = &init_info->module;
-	struct rtw89_btc_ant_info *ant = &module->ant;
+	struct rtw89_btc_init_info *init = &dm->init_info;
+	struct rtw89_btc_module *md = &init->module;
+	struct rtw89_btc_ant_info *ant = &md->ant;
 	struct rtw89_h2c_cxinit *h2c;
 	u32 len = sizeof(*h2c);
 	struct sk_buff *skb;
@@ -5798,22 +5798,22 @@ int rtw89_fw_h2c_cxdrv_init(struct rtw89_dev *rtwdev, u8 type)
 		u8_encode_bits(ant->btg_pos, RTW89_H2C_CXINIT_ANT_INFO_BTG_POS) |
 		u8_encode_bits(ant->stream_cnt, RTW89_H2C_CXINIT_ANT_INFO_STREAM_CNT);
 
-	h2c->mod_rfe = module->rfe_type;
-	h2c->mod_cv = module->cv;
+	h2c->mod_rfe = md->rfe_type;
+	h2c->mod_cv = md->kt_ver;
 	h2c->mod_info =
-		u8_encode_bits(module->bt_solo, RTW89_H2C_CXINIT_MOD_INFO_BT_SOLO) |
-		u8_encode_bits(module->bt_pos, RTW89_H2C_CXINIT_MOD_INFO_BT_POS) |
-		u8_encode_bits(module->switch_type, RTW89_H2C_CXINIT_MOD_INFO_SW_TYPE) |
-		u8_encode_bits(module->wa_type, RTW89_H2C_CXINIT_MOD_INFO_WA_TYPE);
-	h2c->mod_adie_kt = module->kt_ver_adie;
-	h2c->wl_gch = init_info->wl_guard_ch;
+		u8_encode_bits(md->bt_solo, RTW89_H2C_CXINIT_MOD_INFO_BT_SOLO) |
+		u8_encode_bits(md->bt0_pos, RTW89_H2C_CXINIT_MOD_INFO_BT_POS) |
+		u8_encode_bits(md->bt0_sw_type, RTW89_H2C_CXINIT_MOD_INFO_SW_TYPE) |
+		u8_encode_bits(md->wa_type, RTW89_H2C_CXINIT_MOD_INFO_WA_TYPE);
+	h2c->mod_adie_kt = md->kt_ver_adie;
+	h2c->wl_gch = init->wl_guard_ch;
 
 	h2c->info =
-		u8_encode_bits(init_info->wl_only, RTW89_H2C_CXINIT_INFO_WL_ONLY) |
-		u8_encode_bits(init_info->wl_init_ok, RTW89_H2C_CXINIT_INFO_WL_INITOK) |
-		u8_encode_bits(init_info->dbcc_en, RTW89_H2C_CXINIT_INFO_DBCC_EN) |
-		u8_encode_bits(init_info->cx_other, RTW89_H2C_CXINIT_INFO_CX_OTHER) |
-		u8_encode_bits(init_info->bt_only, RTW89_H2C_CXINIT_INFO_BT_ONLY);
+		u8_encode_bits(init->wl_only, RTW89_H2C_CXINIT_INFO_WL_ONLY) |
+		u8_encode_bits(init->wl_init_ok, RTW89_H2C_CXINIT_INFO_WL_INITOK) |
+		u8_encode_bits(init->dbcc_en, RTW89_H2C_CXINIT_INFO_DBCC_EN) |
+		u8_encode_bits(init->cx_other, RTW89_H2C_CXINIT_INFO_CX_OTHER) |
+		u8_encode_bits(init->bt_only, RTW89_H2C_CXINIT_INFO_BT_ONLY);
 
 	rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
 			      H2C_CAT_OUTSRC, BTFC_SET,
@@ -5837,7 +5837,9 @@ int rtw89_fw_h2c_cxdrv_init_v7(struct rtw89_dev *rtwdev, u8 type)
 {
 	struct rtw89_btc *btc = &rtwdev->btc;
 	struct rtw89_btc_dm *dm = &btc->dm;
-	struct rtw89_btc_init_info_v7 *init_info = &dm->init_info.init_v7;
+	struct rtw89_btc_init_info *init = &dm->init_info;
+	struct rtw89_btc_module *md = &init->module;
+	struct rtw89_btc_ant_info *ant = &md->ant;
 	struct rtw89_h2c_cxinit_v7 *h2c;
 	u32 len = sizeof(*h2c);
 	struct sk_buff *skb;
@@ -5852,9 +5854,33 @@ int rtw89_fw_h2c_cxdrv_init_v7(struct rtw89_dev *rtwdev, u8 type)
 	h2c = (struct rtw89_h2c_cxinit_v7 *)skb->data;
 
 	h2c->hdr.type = type;
-	h2c->hdr.ver = btc->ver->fcxinit;
+	h2c->hdr.ver = 7;
 	h2c->hdr.len = len - H2C_LEN_CXDRVHDR_V7;
-	h2c->init = *init_info;
+
+	h2c->init.wl_guard_ch = init->wl_guard_ch;
+	h2c->init.wl_only = init->wl_only;
+	h2c->init.wl_init_ok = init->wl_init_ok;
+	h2c->init.cx_other = init->cx_other;
+	h2c->init.bt_only = init->bt_only;
+	h2c->init.pta_mode = init->pta_mode;
+	h2c->init.pta_direction = init->pta_direction;
+	h2c->init.rsvd3 = init->dbcc_en; /* available at v107 */
+
+	h2c->init.module.rfe_type = md->rfe_type;
+	h2c->init.module.kt_ver = md->kt_ver;
+	h2c->init.module.bt_solo = md->bt_solo;
+	h2c->init.module.bt_pos = md->bt0_pos;
+	h2c->init.module.switch_type = md->bt0_sw_type;
+	h2c->init.module.wa_type = md->wa_type;
+	h2c->init.module.kt_ver_adie = md->kt_ver_adie;
+
+	h2c->init.module.ant.type = ant->type;
+	h2c->init.module.ant.num = ant->num;
+	h2c->init.module.ant.isolation = ant->isolation;
+	h2c->init.module.ant.single_pos = ant->single_pos;
+	h2c->init.module.ant.diversity = ant->diversity;
+	h2c->init.module.ant.btg_pos = ant->btg_pos;
+	h2c->init.module.ant.stream_cnt = ant->stream_cnt;
 
 	rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
 			      H2C_CAT_OUTSRC, BTFC_SET,
@@ -5878,7 +5904,9 @@ 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_btc_init_info *init = &dm->init_info;
+	struct rtw89_btc_module *md = &init->module;
+	struct rtw89_btc_ant_info *ant = &md->ant;
 	struct rtw89_h2c_cxinit_v10 *h2c;
 	u32 len = sizeof(*h2c);
 	struct sk_buff *skb;
@@ -5893,9 +5921,38 @@ int rtw89_fw_h2c_cxdrv_init_v10(struct rtw89_dev *rtwdev, u8 type)
 	h2c = (struct rtw89_h2c_cxinit_v10 *)skb->data;
 
 	h2c->hdr.type = type;
-	h2c->hdr.ver = btc->ver->fcxinit;
+	h2c->hdr.ver = 10;
 	h2c->hdr.len = len - H2C_LEN_CXDRVHDR_V7;
-	h2c->init = *init_info;
+
+	h2c->init.endian_type = init->endian_type;
+	h2c->init.init_mode = init->init_mode;
+	h2c->init.wl_init_ok = init->wl_init_ok;
+	h2c->init.bt0_function = init->bt0_function;
+	h2c->init.bt1_function = init->bt1_function;
+	h2c->init.bt2_function = init->bt2_function;
+	h2c->init.pta_mode = init->pta_mode;
+	h2c->init.pta_direction = init->pta_direction;
+
+	h2c->init.module.rfe_type = md->rfe_type;
+	h2c->init.module.wa_type = md->wa_type;
+	h2c->init.module.kt_ver = md->kt_ver;
+	h2c->init.module.kt_ver_adie = md->kt_ver_adie;
+	h2c->init.module.bt0_pos = md->bt0_pos;
+	h2c->init.module.bt0_sw_type = md->bt0_sw_type;
+	h2c->init.module.bt1_pos = md->bt1_pos;
+	h2c->init.module.bt1_sw_type = md->bt1_sw_type;
+
+	h2c->init.module.ant.type = ant->type;
+	h2c->init.module.ant.num = ant->num;
+	h2c->init.module.ant.isolation = ant->isolation;
+	h2c->init.module.ant.single_pos = ant->single_pos;
+	h2c->init.module.ant.stream_cnt = ant->stream_cnt;
+	h2c->init.module.ant.btg_pos = ant->btg_pos;
+	h2c->init.module.ant.btg1_pos = ant->btg1_pos;
+
+	memcpy(h2c->init.module.ant.func, ant->func,  sizeof(ant->func));
+	memcpy(h2c->init.module.ant.ant_xmap, ant->ant_xmap,
+	       sizeof(ant->ant_xmap));
 
 	rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
 			      H2C_CAT_OUTSRC, BTFC_SET,
diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h
index a36bb9f024ba..16e173c5d1bb 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.h
+++ b/drivers/net/wireless/realtek/rtw89/fw.h
@@ -2593,6 +2593,11 @@ struct rtw89_h2c_cxinit_v7 {
 	struct rtw89_btc_init_info_v7 init;
 } __packed;
 
+struct rtw89_h2c_cxinit_v107 {
+	struct rtw89_h2c_cxhdr_v7 hdr;
+	struct rtw89_btc_init_info_v107 init;
+} __packed;
+
 struct rtw89_h2c_cxinit_v10 {
 	struct rtw89_h2c_cxhdr_v7 hdr;
 	struct rtw89_btc_init_info_v10 init;
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c
index e3a17f539ad6..db37ad6653bc 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c
@@ -2118,82 +2118,43 @@ static u8 rtw8851b_get_thermal(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_p
 
 static void rtw8851b_btc_set_rfe(struct rtw89_dev *rtwdev)
 {
-	const struct rtw89_btc_ver *ver = rtwdev->btc.ver;
-	union rtw89_btc_module_info *md = &rtwdev->btc.mdinfo;
-
-	if  (ver->fcxinit == 7) {
-		md->md_v7.rfe_type = rtwdev->efuse.rfe_type;
-		md->md_v7.kt_ver = rtwdev->hal.cv;
-		md->md_v7.bt_solo = 0;
-		md->md_v7.switch_type = BTC_SWITCH_INTERNAL;
-		md->md_v7.ant.isolation = 10;
-		md->md_v7.kt_ver_adie = rtwdev->hal.acv;
-
-		if (md->md_v7.rfe_type == 0)
-			return;
-
-		/* rfe_type 3*n+1: 1-Ant(shared),
-		 *	    3*n+2: 2-Ant+Div(non-shared),
-		 *	    3*n+3: 2-Ant+no-Div(non-shared)
-		 */
-		md->md_v7.ant.num = (md->md_v7.rfe_type % 3 == 1) ? 1 : 2;
-		/* WL-1ss at S0, btg at s0 (On 1 WL RF) */
-		md->md_v7.ant.single_pos = RF_PATH_A;
-		md->md_v7.ant.btg_pos = RF_PATH_A;
-		md->md_v7.ant.stream_cnt = 1;
-
-		if (md->md_v7.ant.num == 1) {
-			md->md_v7.ant.type = BTC_ANT_SHARED;
-			md->md_v7.bt_pos = BTC_BT_BTG;
-			md->md_v7.wa_type = 1;
-			md->md_v7.ant.diversity = 0;
-		} else { /* ant.num == 2 */
-			md->md_v7.ant.type = BTC_ANT_DEDICATED;
-			md->md_v7.bt_pos = BTC_BT_ALONE;
-			md->md_v7.switch_type = BTC_SWITCH_EXTERNAL;
-			md->md_v7.wa_type = 0;
-			if (md->md_v7.rfe_type % 3 == 2)
-				md->md_v7.ant.diversity = 1;
-		}
-		rtwdev->btc.btg_pos = md->md_v7.ant.btg_pos;
-		rtwdev->btc.ant_type = md->md_v7.ant.type;
-	} else {
-		md->md.rfe_type = rtwdev->efuse.rfe_type;
-		md->md.cv = rtwdev->hal.cv;
-		md->md.bt_solo = 0;
-		md->md.switch_type = BTC_SWITCH_INTERNAL;
-		md->md.ant.isolation = 10;
-		md->md.kt_ver_adie = rtwdev->hal.acv;
-
-		if (md->md.rfe_type == 0)
-			return;
-
-		/* rfe_type 3*n+1: 1-Ant(shared),
-		 *	    3*n+2: 2-Ant+Div(non-shared),
-		 *	    3*n+3: 2-Ant+no-Div(non-shared)
-		 */
-		md->md.ant.num = (md->md.rfe_type % 3 == 1) ? 1 : 2;
-		/* WL-1ss at S0, btg at s0 (On 1 WL RF) */
-		md->md.ant.single_pos = RF_PATH_A;
-		md->md.ant.btg_pos = RF_PATH_A;
-		md->md.ant.stream_cnt = 1;
-
-		if (md->md.ant.num == 1) {
-			md->md.ant.type = BTC_ANT_SHARED;
-			md->md.bt_pos = BTC_BT_BTG;
-			md->md.wa_type = 1;
-			md->md.ant.diversity = 0;
-		} else { /* ant.num == 2 */
-			md->md.ant.type = BTC_ANT_DEDICATED;
-			md->md.bt_pos = BTC_BT_ALONE;
-			md->md.switch_type = BTC_SWITCH_EXTERNAL;
-			md->md.wa_type = 0;
-			if (md->md.rfe_type % 3 == 2)
-				md->md.ant.diversity = 1;
-		}
-		rtwdev->btc.btg_pos = md->md.ant.btg_pos;
-		rtwdev->btc.ant_type = md->md.ant.type;
+	struct rtw89_btc_module *md = &rtwdev->btc.mdinfo;
+
+	md->rfe_type = rtwdev->efuse.rfe_type;
+	md->kt_ver = rtwdev->hal.cv;
+	md->bt_solo = 0;
+	md->bt0_sw_type = BTC_SWITCH_INTERNAL;
+	md->ant.isolation = 10;
+	md->kt_ver_adie = rtwdev->hal.acv;
+
+	if (md->rfe_type == 0)
+		return;
+
+	/* rfe_type 3*n+1: 1-Ant(shared),
+	 *	    3*n+2: 2-Ant+Div(non-shared),
+	 *	    3*n+3: 2-Ant+no-Div(non-shared)
+	 */
+	md->ant.num = (md->rfe_type % 3 == 1) ? 1 : 2;
+	/* WL-1ss at S0, btg at s0 (On 1 WL RF) */
+	md->ant.single_pos = RF_PATH_A;
+	md->ant.btg_pos = RF_PATH_A;
+	md->ant.stream_cnt = 1;
+
+	if (md->ant.num == 1) {
+		md->ant.type = BTC_ANT_SHARED;
+		md->bt0_pos = BTC_BT_BTG;
+		md->wa_type = 1;
+		md->ant.diversity = 0;
+	} else { /* ant.num == 2 */
+		md->ant.type = BTC_ANT_DEDICATED;
+		md->bt0_pos = BTC_BT_ALONE;
+		md->bt0_sw_type = BTC_SWITCH_EXTERNAL;
+		md->wa_type = 0;
+		if (md->rfe_type % 3 == 2)
+			md->ant.diversity = 1;
 	}
+	rtwdev->btc.btg_pos = md->ant.btg_pos;
+	rtwdev->btc.ant_type = md->ant.type;
 }
 
 static
@@ -2217,9 +2178,8 @@ static void rtw8851b_btc_init_cfg(struct rtw89_dev *rtwdev)
 	};
 	const struct rtw89_chip_info *chip = rtwdev->chip;
 	struct rtw89_btc *btc = &rtwdev->btc;
-	union rtw89_btc_module_info *md = &btc->mdinfo;
-	const struct rtw89_btc_ver *ver = btc->ver;
-	u8 path, path_min, path_max, str_cnt, ant_sing_pos;
+	struct rtw89_btc_module *md = &btc->mdinfo;
+	u8 path, path_min, path_max;
 
 	/* PTA init  */
 	rtw89_mac_coex_init(rtwdev, &coex_params);
@@ -2228,17 +2188,9 @@ static void rtw8851b_btc_init_cfg(struct rtw89_dev *rtwdev)
 	chip->ops->btc_set_wl_pri(rtwdev, BTC_PRI_MASK_TX_RESP, true);
 	chip->ops->btc_set_wl_pri(rtwdev, BTC_PRI_MASK_BEACON, true);
 
-	if (ver->fcxinit == 7) {
-		str_cnt = md->md_v7.ant.stream_cnt;
-		ant_sing_pos = md->md_v7.ant.single_pos;
-	} else {
-		str_cnt = md->md.ant.stream_cnt;
-		ant_sing_pos = md->md.ant.single_pos;
-	}
-
 	/* for 1-Ant && 1-ss case: only 1-path */
-	if (str_cnt == 1) {
-		path_min = ant_sing_pos;
+	if (md->ant.stream_cnt == 1) {
+		path_min = md->ant.single_pos;
 		path_max = path_min;
 	} else {
 		path_min = RF_PATH_A;
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c
index f32c7c6a4075..5d7b5d1a24b1 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c
@@ -1827,56 +1827,30 @@ static u8 rtw8852a_get_thermal(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_p
 
 static void rtw8852a_btc_set_rfe(struct rtw89_dev *rtwdev)
 {
-	const struct rtw89_btc_ver *ver = rtwdev->btc.ver;
-	union rtw89_btc_module_info *md = &rtwdev->btc.mdinfo;
+	struct rtw89_btc_module *md = &rtwdev->btc.mdinfo;
 
-	if (ver->fcxinit == 7) {
-		md->md_v7.rfe_type = rtwdev->efuse.rfe_type;
-		md->md_v7.kt_ver = rtwdev->hal.cv;
-		md->md_v7.bt_solo = 0;
-		md->md_v7.switch_type = BTC_SWITCH_INTERNAL;
+	md->rfe_type = rtwdev->efuse.rfe_type;
+	md->kt_ver = rtwdev->hal.cv;
+	md->bt_solo = 0;
+	md->bt0_sw_type = BTC_SWITCH_INTERNAL;
 
-		if (md->md_v7.rfe_type > 0)
-			md->md_v7.ant.num = (md->md_v7.rfe_type % 2 ? 2 : 3);
-		else
-			md->md_v7.ant.num = 2;
+	if (md->rfe_type > 0)
+		md->ant.num = (md->rfe_type % 2 ? 2 : 3);
+	else
+		md->ant.num = 2;
 
-		md->md_v7.ant.diversity = 0;
-		md->md_v7.ant.isolation = 10;
+	md->ant.diversity = 0;
+	md->ant.isolation = 10;
 
-		if (md->md_v7.ant.num == 3) {
-			md->md_v7.ant.type = BTC_ANT_DEDICATED;
-			md->md_v7.bt_pos = BTC_BT_ALONE;
-		} else {
-			md->md_v7.ant.type = BTC_ANT_SHARED;
-			md->md_v7.bt_pos = BTC_BT_BTG;
-		}
-		rtwdev->btc.btg_pos = md->md_v7.ant.btg_pos;
-		rtwdev->btc.ant_type = md->md_v7.ant.type;
+	if (md->ant.num == 3) {
+		md->ant.type = BTC_ANT_DEDICATED;
+		md->bt0_pos = BTC_BT_ALONE;
 	} else {
-		md->md.rfe_type = rtwdev->efuse.rfe_type;
-		md->md.cv = rtwdev->hal.cv;
-		md->md.bt_solo = 0;
-		md->md.switch_type = BTC_SWITCH_INTERNAL;
-
-		if (md->md.rfe_type > 0)
-			md->md.ant.num = (md->md.rfe_type % 2 ? 2 : 3);
-		else
-			md->md.ant.num = 2;
-
-		md->md.ant.diversity = 0;
-		md->md.ant.isolation = 10;
-
-		if (md->md.ant.num == 3) {
-			md->md.ant.type = BTC_ANT_DEDICATED;
-			md->md.bt_pos = BTC_BT_ALONE;
-		} else {
-			md->md.ant.type = BTC_ANT_SHARED;
-			md->md.bt_pos = BTC_BT_BTG;
-		}
-		rtwdev->btc.btg_pos = md->md.ant.btg_pos;
-		rtwdev->btc.ant_type = md->md.ant.type;
+		md->ant.type = BTC_ANT_SHARED;
+		md->bt0_pos = BTC_BT_BTG;
 	}
+	rtwdev->btc.btg_pos = md->ant.btg_pos;
+	rtwdev->btc.ant_type = md->ant.type;
 }
 
 static
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c
index a45f05309af8..356623341f65 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c
@@ -750,56 +750,30 @@ static void rtw8852b_rfk_track(struct rtw89_dev *rtwdev)
 
 static void rtw8852b_btc_set_rfe(struct rtw89_dev *rtwdev)
 {
-	const struct rtw89_btc_ver *ver = rtwdev->btc.ver;
-	union rtw89_btc_module_info *md = &rtwdev->btc.mdinfo;
+	struct rtw89_btc_module *md = &rtwdev->btc.mdinfo;
 
-	if (ver->fcxinit == 7) {
-		md->md_v7.rfe_type = rtwdev->efuse.rfe_type;
-		md->md_v7.kt_ver = rtwdev->hal.cv;
-		md->md_v7.bt_solo = 0;
-		md->md_v7.switch_type = BTC_SWITCH_INTERNAL;
+	md->rfe_type = rtwdev->efuse.rfe_type;
+	md->kt_ver = rtwdev->hal.cv;
+	md->bt_solo = 0;
+	md->bt0_sw_type = BTC_SWITCH_INTERNAL;
 
-		if (md->md_v7.rfe_type > 0)
-			md->md_v7.ant.num = (md->md_v7.rfe_type % 2 ? 2 : 3);
-		else
-			md->md_v7.ant.num = 2;
-
-		md->md_v7.ant.diversity = 0;
-		md->md_v7.ant.isolation = 10;
-
-		if (md->md_v7.ant.num == 3) {
-			md->md_v7.ant.type = BTC_ANT_DEDICATED;
-			md->md_v7.bt_pos = BTC_BT_ALONE;
-		} else {
-			md->md_v7.ant.type = BTC_ANT_SHARED;
-			md->md_v7.bt_pos = BTC_BT_BTG;
-		}
-		rtwdev->btc.btg_pos = md->md_v7.ant.btg_pos;
-		rtwdev->btc.ant_type = md->md_v7.ant.type;
-	} else {
-		md->md.rfe_type = rtwdev->efuse.rfe_type;
-		md->md.cv = rtwdev->hal.cv;
-		md->md.bt_solo = 0;
-		md->md.switch_type = BTC_SWITCH_INTERNAL;
+	if (md->rfe_type > 0)
+		md->ant.num = (md->rfe_type % 2 ? 2 : 3);
+	else
+		md->ant.num = 2;
 
-		if (md->md.rfe_type > 0)
-			md->md.ant.num = (md->md.rfe_type % 2 ? 2 : 3);
-		else
-			md->md.ant.num = 2;
-
-		md->md.ant.diversity = 0;
-		md->md.ant.isolation = 10;
-
-		if (md->md.ant.num == 3) {
-			md->md.ant.type = BTC_ANT_DEDICATED;
-			md->md.bt_pos = BTC_BT_ALONE;
-		} else {
-			md->md.ant.type = BTC_ANT_SHARED;
-			md->md.bt_pos = BTC_BT_BTG;
-		}
-		rtwdev->btc.btg_pos = md->md.ant.btg_pos;
-		rtwdev->btc.ant_type = md->md.ant.type;
+	md->ant.diversity = 0;
+	md->ant.isolation = 10;
+
+	if (md->ant.num == 3) {
+		md->ant.type = BTC_ANT_DEDICATED;
+		md->bt0_pos = BTC_BT_ALONE;
+	} else {
+		md->ant.type = BTC_ANT_SHARED;
+		md->bt0_pos = BTC_BT_BTG;
 	}
+	rtwdev->btc.btg_pos = md->ant.btg_pos;
+	rtwdev->btc.ant_type = md->ant.type;
 }
 
 union rtw8852b_btc_wl_txpwr_ctrl {
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c
index 8d5dd93626b3..3d93cee562c2 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c
@@ -635,46 +635,41 @@ static void rtw8852bt_rfk_track(struct rtw89_dev *rtwdev)
 
 static void rtw8852bt_btc_set_rfe(struct rtw89_dev *rtwdev)
 {
-	const struct rtw89_btc_ver *ver = rtwdev->btc.ver;
-	union rtw89_btc_module_info *md = &rtwdev->btc.mdinfo;
-
-	if (ver->fcxinit == 7) {
-		md->md_v7.rfe_type = rtwdev->efuse.rfe_type;
-		md->md_v7.kt_ver = rtwdev->hal.cv;
-		md->md_v7.kt_ver_adie = rtwdev->hal.acv;
-		md->md_v7.bt_solo = 0;
-		md->md_v7.bt_pos = BTC_BT_BTG;
-		md->md_v7.switch_type = BTC_SWITCH_INTERNAL;
-		md->md_v7.wa_type = 0;
-
-		md->md_v7.ant.type = BTC_ANT_SHARED;
-		md->md_v7.ant.num = 2;
-		md->md_v7.ant.isolation = 10;
-		md->md_v7.ant.diversity = 0;
-		/* WL 1-stream+1-Ant is located at 0:s0(path-A) or 1:s1(path-B) */
-		md->md_v7.ant.single_pos = RF_PATH_A;
-		md->md_v7.ant.btg_pos = RF_PATH_B;
-
-		if (md->md_v7.rfe_type == 0) {
-			rtwdev->btc.dm.error.map.rfe_type0 = true;
-			return;
-		}
-
-		md->md_v7.ant.num = (md->md_v7.rfe_type % 2) ? 2 : 3;
-		md->md_v7.ant.stream_cnt = 2;
-		md->md_v7.wa_type |= BTC_WA_INIT_SCAN;
-
-		if (md->md_v7.ant.num == 2) {
-			md->md_v7.ant.type = BTC_ANT_SHARED;
-			md->md_v7.bt_pos = BTC_BT_BTG;
-			md->md_v7.wa_type |= BTC_WA_HFP_LAG;
-		} else {
-			md->md_v7.ant.type = BTC_ANT_DEDICATED;
-			md->md_v7.bt_pos = BTC_BT_ALONE;
-		}
-	} else {
+	struct rtw89_btc_module *md = &rtwdev->btc.mdinfo;
+
+	md->rfe_type = rtwdev->efuse.rfe_type;
+	md->kt_ver = rtwdev->hal.cv;
+	md->kt_ver_adie = rtwdev->hal.acv;
+	md->bt_solo = 0;
+	md->bt0_pos = BTC_BT_BTG;
+	md->bt0_sw_type = BTC_SWITCH_INTERNAL;
+	md->wa_type = 0;
+
+	md->ant.type = BTC_ANT_SHARED;
+	md->ant.num = 2;
+	md->ant.isolation = 10;
+	md->ant.diversity = 0;
+	/* WL 1-stream+1-Ant is located at 0:s0(path-A) or 1:s1(path-B) */
+	md->ant.single_pos = RF_PATH_A;
+	md->ant.btg_pos = RF_PATH_B;
+
+	if (md->rfe_type == 0) {
+		rtwdev->btc.dm.error.map.rfe_type0 = true;
 		return;
 	}
+
+	md->ant.num = (md->rfe_type % 2) ? 2 : 3;
+	md->ant.stream_cnt = 2;
+	md->wa_type |= BTC_WA_INIT_SCAN;
+
+	if (md->ant.num == 2) {
+		md->ant.type = BTC_ANT_SHARED;
+		md->bt0_pos = BTC_BT_BTG;
+		md->wa_type |= BTC_WA_HFP_LAG;
+	} else {
+		md->ant.type = BTC_ANT_DEDICATED;
+		md->bt0_pos = BTC_BT_ALONE;
+	}
 }
 
 static void
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
index 3dc6dfce082a..c68959b63a01 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
@@ -2608,56 +2608,30 @@ static u8 rtw8852c_get_thermal(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_p
 
 static void rtw8852c_btc_set_rfe(struct rtw89_dev *rtwdev)
 {
-	const struct rtw89_btc_ver *ver = rtwdev->btc.ver;
-	union rtw89_btc_module_info *md = &rtwdev->btc.mdinfo;
+	struct rtw89_btc_module *md = &rtwdev->btc.mdinfo;
 
-	if (ver->fcxinit == 7) {
-		md->md_v7.rfe_type = rtwdev->efuse.rfe_type;
-		md->md_v7.kt_ver = rtwdev->hal.cv;
-		md->md_v7.bt_solo = 0;
-		md->md_v7.switch_type = BTC_SWITCH_INTERNAL;
+	md->rfe_type = rtwdev->efuse.rfe_type;
+	md->kt_ver = rtwdev->hal.cv;
+	md->bt_solo = 0;
+	md->bt0_sw_type = BTC_SWITCH_INTERNAL;
 
-		if (md->md_v7.rfe_type > 0)
-			md->md_v7.ant.num = (md->md_v7.rfe_type % 2 ? 2 : 3);
-		else
-			md->md_v7.ant.num = 2;
+	if (md->rfe_type > 0)
+		md->ant.num = (md->rfe_type % 2 ? 2 : 3);
+	else
+		md->ant.num = 2;
 
-		md->md_v7.ant.diversity = 0;
-		md->md_v7.ant.isolation = 10;
+	md->ant.diversity = 0;
+	md->ant.isolation = 10;
 
-		if (md->md_v7.ant.num == 3) {
-			md->md_v7.ant.type = BTC_ANT_DEDICATED;
-			md->md_v7.bt_pos = BTC_BT_ALONE;
-		} else {
-			md->md_v7.ant.type = BTC_ANT_SHARED;
-			md->md_v7.bt_pos = BTC_BT_BTG;
-		}
-		rtwdev->btc.btg_pos = md->md_v7.ant.btg_pos;
-		rtwdev->btc.ant_type = md->md_v7.ant.type;
+	if (md->ant.num == 3) {
+		md->ant.type = BTC_ANT_DEDICATED;
+		md->bt0_pos = BTC_BT_ALONE;
 	} else {
-		md->md.rfe_type = rtwdev->efuse.rfe_type;
-		md->md.cv = rtwdev->hal.cv;
-		md->md.bt_solo = 0;
-		md->md.switch_type = BTC_SWITCH_INTERNAL;
-
-		if (md->md.rfe_type > 0)
-			md->md.ant.num = (md->md.rfe_type % 2 ? 2 : 3);
-		else
-			md->md.ant.num = 2;
-
-		md->md.ant.diversity = 0;
-		md->md.ant.isolation = 10;
-
-		if (md->md.ant.num == 3) {
-			md->md.ant.type = BTC_ANT_DEDICATED;
-			md->md.bt_pos = BTC_BT_ALONE;
-		} else {
-			md->md.ant.type = BTC_ANT_SHARED;
-			md->md.bt_pos = BTC_BT_BTG;
-		}
-		rtwdev->btc.btg_pos = md->md.ant.btg_pos;
-		rtwdev->btc.ant_type = md->md.ant.type;
+		md->ant.type = BTC_ANT_SHARED;
+		md->bt0_pos = BTC_BT_BTG;
 	}
+	rtwdev->btc.btg_pos = md->ant.btg_pos;
+	rtwdev->btc.ant_type = md->ant.type;
 }
 
 static void rtw8852c_ctrl_btg_bt_rx(struct rtw89_dev *rtwdev, bool en,
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c
index 854ef9a980bd..2586fd2df8ab 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c
@@ -2721,46 +2721,45 @@ static u32 rtw8922a_chan_to_rf18_val(struct rtw89_dev *rtwdev,
 
 static void rtw8922a_btc_set_rfe(struct rtw89_dev *rtwdev)
 {
-	union rtw89_btc_module_info *md = &rtwdev->btc.mdinfo;
-	struct rtw89_btc_module_v7 *module = &md->md_v7;
+	struct rtw89_btc_module *md = &rtwdev->btc.mdinfo;
 
-	module->rfe_type = rtwdev->efuse.rfe_type;
-	module->kt_ver = rtwdev->hal.cv;
-	module->bt_solo = 0;
-	module->switch_type = BTC_SWITCH_INTERNAL;
-	module->wa_type = 0;
+	md->rfe_type = rtwdev->efuse.rfe_type;
+	md->kt_ver = rtwdev->hal.cv;
+	md->bt_solo = 0;
+	md->bt0_sw_type = BTC_SWITCH_INTERNAL;
+	md->wa_type = 0;
 
-	module->ant.type = BTC_ANT_SHARED;
-	module->ant.num = 2;
-	module->ant.isolation = 10;
-	module->ant.diversity = 0;
-	module->ant.single_pos = RF_PATH_A;
-	module->ant.btg_pos = RF_PATH_B;
+	md->ant.type = BTC_ANT_SHARED;
+	md->ant.num = 2;
+	md->ant.isolation = 10;
+	md->ant.diversity = 0;
+	md->ant.single_pos = RF_PATH_A;
+	md->ant.btg_pos = RF_PATH_B;
 
-	if (module->kt_ver <= 1)
-		module->wa_type |= BTC_WA_HFP_ZB;
+	if (md->kt_ver <= 1)
+		md->wa_type |= BTC_WA_HFP_ZB;
 
 	rtwdev->btc.cx.bt_ext.func_type = BTC_3CX_NONE;
 
-	if (module->rfe_type == 0) {
+	if (md->rfe_type == 0) {
 		rtwdev->btc.dm.error.map.rfe_type0 = true;
 		return;
 	}
 
-	module->ant.num = (module->rfe_type % 2) ?  2 : 3;
+	md->ant.num = (md->rfe_type % 2) ?  2 : 3;
 
-	if (module->kt_ver == 0)
-		module->ant.num = 2;
+	if (md->kt_ver == 0)
+		md->ant.num = 2;
 
-	if (module->ant.num == 3) {
-		module->ant.type = BTC_ANT_DEDICATED;
-		module->bt_pos = BTC_BT_ALONE;
+	if (md->ant.num == 3) {
+		md->ant.type = BTC_ANT_DEDICATED;
+		md->bt0_pos = BTC_BT_ALONE;
 	} else {
-		module->ant.type = BTC_ANT_SHARED;
-		module->bt_pos = BTC_BT_BTG;
+		md->ant.type = BTC_ANT_SHARED;
+		md->bt0_pos = BTC_BT_BTG;
 	}
-	rtwdev->btc.btg_pos = module->ant.btg_pos;
-	rtwdev->btc.ant_type = module->ant.type;
+	rtwdev->btc.btg_pos = md->ant.btg_pos;
+	rtwdev->btc.ant_type = md->ant.type;
 }
 
 static
@@ -2773,7 +2772,7 @@ void rtw8922a_set_trx_mask(struct rtw89_dev *rtwdev, u8 path, u8 group, u32 val)
 static void rtw8922a_btc_init_cfg(struct rtw89_dev *rtwdev)
 {
 	struct rtw89_btc *btc = &rtwdev->btc;
-	struct rtw89_btc_ant_info_v7 *ant = &btc->mdinfo.md_v7.ant;
+	struct rtw89_btc_ant_info *ant = &btc->mdinfo.ant;
 	u32 wl_pri, path_min, path_max;
 	u8 path;
 
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922d.c b/drivers/net/wireless/realtek/rtw89/rtw8922d.c
index 929bcfc8089d..326c52e1e8f2 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922d.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922d.c
@@ -3110,32 +3110,31 @@ static u32 rtw8922d_chan_to_rf18_val(struct rtw89_dev *rtwdev,
 static void rtw8922d_btc_set_rfe(struct rtw89_dev *rtwdev)
 {
 	struct rtw89_btc *btc = &rtwdev->btc;
+	struct rtw89_btc_module *md = &btc->mdinfo;
 	struct rtw89_btc_dm *dm = &btc->dm;
 	struct rtw89_btc_cx *cx = &btc->cx;
-	union rtw89_btc_module_info *md = &rtwdev->btc.mdinfo;
-	struct rtw89_btc_module_v10 *module = &md->md_v10;
 	u8 efuse_bt_func, efuse_ant_info, bt_sw_gpio_pos;
 	u8 is_combo, is_bt_share;
 
 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s !!\n", __func__);
 
 	/* get from final capability of device */
-	module->rfe_type = rtwdev->efuse.rfe_type;
-	module->kt_ver = rtwdev->hal.cv;
-	module->kt_ver_adie = rtwdev->hal.acv;
-	module->wa_type = 0;
+	md->rfe_type = rtwdev->efuse.rfe_type;
+	md->kt_ver = rtwdev->hal.cv;
+	md->kt_ver_adie = rtwdev->hal.acv;
+	md->wa_type = 0;
 	dm->wl_trx_nss_en = 0;
 
-	module->ant.num = 2;
-	module->ant.single_pos = BTC_RF_S0; /* WL 1ss+1Ant 0:s0(A)/ 1:s1(B) */
+	md->ant.num = 2;
+	md->ant.single_pos = BTC_RF_S0; /* WL 1ss+1Ant 0:s0(A)/ 1:s1(B) */
 
 	/* set default antenna isolation */
-	cx->bt0.ant_iso_to_wl = module->ant.isolation;
-	cx->bt1.ant_iso_to_wl = module->ant.isolation;
+	cx->bt0.ant_iso_to_wl = md->ant.isolation;
+	cx->bt1.ant_iso_to_wl = md->ant.isolation;
 
-	module->ant.stream_cnt = 2;
-	module->ant.btg_pos = BTC_RF_S1; /* BTG0 at WL-S1 */
-	module->ant.btg1_pos = BTC_RF_S0; /* BTG1 at WL-S0 if Dual-BTGA */
+	md->ant.stream_cnt = 2;
+	md->ant.btg_pos = BTC_RF_S1; /* BTG0 at WL-S1 */
+	md->ant.btg1_pos = BTC_RF_S0; /* BTG1 at WL-S0 if Dual-BTGA */
 
 	cx->bt0.band_56G_support = 1;
 	cx->bt1.band_56G_support = 1;
@@ -3163,21 +3162,21 @@ static void rtw8922d_btc_set_rfe(struct rtw89_dev *rtwdev)
 
 	efuse_bt_func &= 0x1f; /* 0xcd[4:0] */
 	efuse_ant_info = rtwdev->efuse.bt_setting_3;
-	module->ant.num = (efuse_ant_info & 0xe0) >> 5; /* 0xCE[7:5] */
+	md->ant.num = (efuse_ant_info & 0xe0) >> 5; /* 0xCE[7:5] */
 	is_combo = (efuse_ant_info & 0xe) >> 1; /* 0xCE[3:1] */
 	is_bt_share = efuse_ant_info & BIT(0); /* 0xCE[0] */
 
 	memset(dm->ant_xmap, 0, sizeof(dm->ant_xmap));
 
 	/* To-Do: "RFE_TYpe" to "ant.num" translation */
-	switch (module->ant.num) {
+	switch (md->ant.num) {
 	case 1: /* 1-Ant WL-S0 only & BT0 only */
-		module->ant.type = BTC_ANT_SHARED;
-		module->bt0_pos = BTC_BT_BTG;
-		module->bt0_sw_type = BTC_SWITCH_INTERNAL;
-		module->ant.btg_pos = BTC_RF_S0; /* BTG0 at WL-S0 */
-		module->ant.stream_cnt = 1;
-		module->ant.func[0] = BTC_EFMAP_BT0;
+		md->ant.type = BTC_ANT_SHARED;
+		md->bt0_pos = BTC_BT_BTG;
+		md->bt0_sw_type = BTC_SWITCH_INTERNAL;
+		md->ant.btg_pos = BTC_RF_S0; /* BTG0 at WL-S0 */
+		md->ant.stream_cnt = 1;
+		md->ant.func[0] = BTC_EFMAP_BT0;
 		dm->ant_xmap[BTC_RF_S0][BTC_BT_1ST] = 1; /* BT0 shared with S0*/
 		dm->ant_xmap[BTC_RF_S1][BTC_BT_1ST] = 0; /* WL 1T1R no RF-S1 */
 		break;
@@ -3185,34 +3184,34 @@ static void rtw8922d_btc_set_rfe(struct rtw89_dev *rtwdev)
 	default:
 		if (is_combo) {
 			if (efuse_bt_func == (BTC_EFMAP_BT0 | BTC_EFMAP_BT1))
-				module->ant.func[0] = BTC_EFMAP_BT1;
+				md->ant.func[0] = BTC_EFMAP_BT1;
 
-			module->ant.func[1] = BTC_EFMAP_BT0;
+			md->ant.func[1] = BTC_EFMAP_BT0;
 		} else {
-			module->ant.func[0] = BTC_EFMAP_NONE;
-			module->ant.func[1] = BTC_EFMAP_NONE;
+			md->ant.func[0] = BTC_EFMAP_NONE;
+			md->ant.func[1] = BTC_EFMAP_NONE;
 		}
 
 		if (is_bt_share) { /* WL-S0 + (WL-S1 & BT0-S1) */
-			module->ant.type = BTC_ANT_SHARED;
-			module->bt0_pos = BTC_BT_BTG;
-			module->bt0_sw_type = BTC_SWITCH_INTERNAL;
+			md->ant.type = BTC_ANT_SHARED;
+			md->bt0_pos = BTC_BT_BTG;
+			md->bt0_sw_type = BTC_SWITCH_INTERNAL;
 			dm->ant_xmap[BTC_RF_S1][BTC_BT_1ST] = 1;
 		} else { /* WL-S0 + BT0-S1 */
-			module->ant.type = BTC_ANT_DEDICATED;
-			module->bt0_pos = BTC_BT_ALONE;
-			module->bt0_sw_type = BTC_SWITCH_V1_NONE;
+			md->ant.type = BTC_ANT_DEDICATED;
+			md->bt0_pos = BTC_BT_ALONE;
+			md->bt0_sw_type = BTC_SWITCH_V1_NONE;
 		}
 
-		if (module->ant.func[0] == BTC_EFMAP_BT1) { /* if 2nd BT exist */
+		if (md->ant.func[0] == BTC_EFMAP_BT1) { /* if 2nd BT exist */
 			dm->ant_xmap[BTC_RF_S0][BTC_BT_2ND] = 1;
-			if (module->rfe_type == 12) { /* WL-S0 & BT1 by SPDT */
-				module->bt1_pos = BTC_BT_ALONE;
+			if (md->rfe_type == 12) { /* WL-S0 & BT1 by SPDT */
+				md->bt1_pos = BTC_BT_ALONE;
 				/* Todo: set SPDT GPIO-ctrl */
-				module->bt1_sw_type = bt_sw_gpio_pos;
+				md->bt1_sw_type = bt_sw_gpio_pos;
 			} else { /* WL-S0 & BT1-S1 by BTGA */
-				module->bt1_pos = BTC_BT_BTG;
-				module->bt1_sw_type = BTC_SWITCH_INTERNAL;
+				md->bt1_pos = BTC_BT_BTG;
+				md->bt1_sw_type = BTC_SWITCH_INTERNAL;
 			}
 		}
 
@@ -3220,48 +3219,48 @@ static void rtw8922d_btc_set_rfe(struct rtw89_dev *rtwdev)
 		break;
 	case 3: /* 3-Ant, 3 different BT-configuration */
 		if (is_bt_share) {
-			module->ant.func[0] = BTC_EFMAP_NONE;
-			module->ant.func[1] = BTC_EFMAP_BT0;
-			module->ant.func[2] = efuse_bt_func & (~BTC_EFMAP_BT0);
-			module->ant.type = BTC_ANT_SHARED;
-			module->bt0_pos = BTC_BT_BTG;
-			module->bt0_sw_type = BTC_SWITCH_INTERNAL;
+			md->ant.func[0] = BTC_EFMAP_NONE;
+			md->ant.func[1] = BTC_EFMAP_BT0;
+			md->ant.func[2] = efuse_bt_func & (~BTC_EFMAP_BT0);
+			md->ant.type = BTC_ANT_SHARED;
+			md->bt0_pos = BTC_BT_BTG;
+			md->bt0_sw_type = BTC_SWITCH_INTERNAL;
 			dm->ant_xmap[BTC_RF_S1][BTC_BT_1ST] = 1;
 			dm->wl_trx_nss_en = 1; /* 1ss MIMO-PS capability */
 		} else {
-			module->ant.func[0] = BTC_EFMAP_NONE;
-			module->ant.func[1] = BTC_EFMAP_NONE;
-			module->ant.func[2] = efuse_bt_func;
-			module->ant.type = BTC_ANT_DEDICATED;
-			module->bt0_pos = BTC_BT_ALONE;
-			module->bt0_sw_type = BTC_SWITCH_V1_NONE;
+			md->ant.func[0] = BTC_EFMAP_NONE;
+			md->ant.func[1] = BTC_EFMAP_NONE;
+			md->ant.func[2] = efuse_bt_func;
+			md->ant.type = BTC_ANT_DEDICATED;
+			md->bt0_pos = BTC_BT_ALONE;
+			md->bt0_sw_type = BTC_SWITCH_V1_NONE;
 		}
 
-		module->bt1_pos = BTC_BT_ALONE; /* BT1 may exist or not */
-		module->bt1_sw_type = BTC_SWITCH_V1_NONE;
+		md->bt1_pos = BTC_BT_ALONE; /* BT1 may exist or not */
+		md->bt1_sw_type = BTC_SWITCH_V1_NONE;
 		break;
 	case 4: /* 4-Ant,  WL-S0 + WL-S1 + BT0 + BT1 */
-		module->ant.func[0] = BTC_EFMAP_NONE;
-		module->ant.func[1] = BTC_EFMAP_NONE;
-		module->ant.func[2] = BTC_EFMAP_BT0;
-		module->ant.func[3] = efuse_bt_func & (~BTC_EFMAP_BT0);
-		module->ant.type = BTC_ANT_DEDICATED;
-		module->bt0_pos = BTC_BT_ALONE;
-		module->bt0_sw_type = BTC_SWITCH_V1_NONE;
-		module->bt1_pos = BTC_BT_ALONE;
-		module->bt1_sw_type = BTC_SWITCH_V1_NONE;
+		md->ant.func[0] = BTC_EFMAP_NONE;
+		md->ant.func[1] = BTC_EFMAP_NONE;
+		md->ant.func[2] = BTC_EFMAP_BT0;
+		md->ant.func[3] = efuse_bt_func & (~BTC_EFMAP_BT0);
+		md->ant.type = BTC_ANT_DEDICATED;
+		md->bt0_pos = BTC_BT_ALONE;
+		md->bt0_sw_type = BTC_SWITCH_V1_NONE;
+		md->bt1_pos = BTC_BT_ALONE;
+		md->bt1_sw_type = BTC_SWITCH_V1_NONE;
 		break;
 	case 5:
-		module->ant.func[0] = BTC_EFMAP_NONE;
-		module->ant.func[1] = BTC_EFMAP_NONE;
-		module->ant.func[2] = BTC_EFMAP_BT0;
-		module->ant.func[3] = BTC_EFMAP_BT1;
-		module->ant.func[4] = BTC_EFMAP_ZB;
-		module->ant.type = BTC_ANT_DEDICATED;
-		module->bt0_pos = BTC_BT_ALONE;
-		module->bt0_sw_type = BTC_SWITCH_V1_NONE;
-		module->bt1_pos = BTC_BT_ALONE;
-		module->bt1_sw_type = BTC_SWITCH_V1_NONE;
+		md->ant.func[0] = BTC_EFMAP_NONE;
+		md->ant.func[1] = BTC_EFMAP_NONE;
+		md->ant.func[2] = BTC_EFMAP_BT0;
+		md->ant.func[3] = BTC_EFMAP_BT1;
+		md->ant.func[4] = BTC_EFMAP_ZB;
+		md->ant.type = BTC_ANT_DEDICATED;
+		md->bt0_pos = BTC_BT_ALONE;
+		md->bt0_sw_type = BTC_SWITCH_V1_NONE;
+		md->bt1_pos = BTC_BT_ALONE;
+		md->bt1_sw_type = BTC_SWITCH_V1_NONE;
 		break;
 	}
 
@@ -3273,8 +3272,8 @@ static void rtw8922d_btc_set_rfe(struct rtw89_dev *rtwdev)
 	 */
 	if (dm->wl_trx_nss_en &&
 	    (dm->wl_trx_nss.tx_limit && dm->wl_trx_nss.rx_limit)) {
-		module->ant.type = BTC_ANT_DEDICATED;
-		module->ant.stream_cnt = 1;
+		md->ant.type = BTC_ANT_DEDICATED;
+		md->ant.stream_cnt = 1;
 		dm->ant_xmap[BTC_RF_S0][BTC_BT_1ST] = 0; /* wl 1ss-> RF-S0 */
 		dm->ant_xmap[BTC_RF_S1][BTC_BT_1ST] = 0; /* BT0-> RF-S1 */
 		dm->ant_xmap[BTC_RF_S0][BTC_BT_2ND] = 0;
@@ -3305,10 +3304,10 @@ static void rtw8922d_btc_set_rfe(struct rtw89_dev *rtwdev)
 		/* use GPIO 12~15 for Ext-4-wire-PTA */
 		cx->bt_ext.hpta_cfg = BIT(12) | BIT(13) | BIT(14) | BIT(15);
 		/* for Ext-SOC locate at Ant-2 */
-		if (module->ant.num >= 5)
-			module->ant.func[4] = BTC_EFMAP_ZB;
+		if (md->ant.num >= 5)
+			md->ant.func[4] = BTC_EFMAP_ZB;
 		else
-			module->ant.func[module->ant.num - 1] = BTC_EFMAP_ZB;
+			md->ant.func[md->ant.num - 1] = BTC_EFMAP_ZB;
 		break;
 	}
 
-- 
2.25.1


^ permalink raw reply related

* [PATCH rtw-next 04/13] wifi: rtw89: coex: Branch out version 105 firmware report map index
From: Ping-Ke Shih @ 2026-07-17  6:57 UTC (permalink / raw)
  To: linux-wireless; +Cc: ku920601
In-Reply-To: <20260717065739.64124-1-pkshih@realtek.com>

From: Ching-Te Ku <ku920601@realtek.com>

RTL8852B in firmware 0.29.133.X do not support BT-TX-PWR report, re-index
and branch out to version 105.

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 | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c
index 5f2658eb516c..b73040428c58 100644
--- a/drivers/net/wireless/realtek/rtw89/coex.c
+++ b/drivers/net/wireless/realtek/rtw89/coex.c
@@ -2707,6 +2707,7 @@ static u32 rtw89_btc_fw_rpt_ver(struct rtw89_dev *rtwdev, u32 rpt_map)
 		case 3:
 		case 4:
 		case 5:
+		case 105:
 			bit_map = BIT(5);
 			break;
 		default:
@@ -2723,6 +2724,7 @@ static u32 rtw89_btc_fw_rpt_ver(struct rtw89_dev *rtwdev, u32 rpt_map)
 		case 3:
 		case 4:
 		case 5:
+		case 105:
 			bit_map = BIT(6);
 			break;
 		default:
@@ -2737,6 +2739,7 @@ static u32 rtw89_btc_fw_rpt_ver(struct rtw89_dev *rtwdev, u32 rpt_map)
 		case 3:
 		case 4:
 		case 5:
+		case 105:
 			bit_map = BIT(7);
 			break;
 		default:
@@ -2749,6 +2752,7 @@ static u32 rtw89_btc_fw_rpt_ver(struct rtw89_dev *rtwdev, u32 rpt_map)
 		case 1:
 		case 2:
 		case 3:
+		case 105:
 			break;
 		case 4:
 		case 5:
@@ -2765,6 +2769,7 @@ static u32 rtw89_btc_fw_rpt_ver(struct rtw89_dev *rtwdev, u32 rpt_map)
 			bit_map = BIT(7);
 			break;
 		case 3:
+		case 105:
 			bit_map = BIT(8);
 			break;
 		case 4:
@@ -2778,6 +2783,8 @@ static u32 rtw89_btc_fw_rpt_ver(struct rtw89_dev *rtwdev, u32 rpt_map)
 	case RPT_EN_TEST:
 		if (ver->frptmap == 5)
 			bit_map = BIT(10);
+		else if (ver->frptmap == 105)
+			bit_map = BIT(9);
 		else
 			bit_map = BIT(31);
 		break;
@@ -2789,6 +2796,7 @@ static u32 rtw89_btc_fw_rpt_ver(struct rtw89_dev *rtwdev, u32 rpt_map)
 			bit_map = GENMASK(2, 0);
 			break;
 		case 3:
+		case 105:
 			bit_map = GENMASK(2, 0) | BIT(8);
 			break;
 		case 4:
@@ -2809,6 +2817,7 @@ static u32 rtw89_btc_fw_rpt_ver(struct rtw89_dev *rtwdev, u32 rpt_map)
 			bit_map = GENMASK(6, 3) | BIT(8);
 			break;
 		case 3:
+		case 105:
 			bit_map = GENMASK(7, 3);
 			break;
 		case 4:
@@ -2833,6 +2842,7 @@ static u32 rtw89_btc_fw_rpt_ver(struct rtw89_dev *rtwdev, u32 rpt_map)
 			break;
 		case 4:
 		case 5:
+		case 105:
 			bit_map = GENMASK(9, 0);
 			break;
 		default:
@@ -2849,6 +2859,7 @@ static u32 rtw89_btc_fw_rpt_ver(struct rtw89_dev *rtwdev, u32 rpt_map)
 			bit_map = GENMASK(6, 2) | BIT(8);
 			break;
 		case 3:
+		case 105:
 			bit_map = GENMASK(8, 2);
 			break;
 		case 4:
-- 
2.25.1


^ permalink raw reply related

* [PATCH rtw-next 03/13] wifi: rtw89: coex: Fix unexpected grant-signal assignee
From: Ping-Ke Shih @ 2026-07-17  6:57 UTC (permalink / raw)
  To: linux-wireless; +Cc: ku920601
In-Reply-To: <20260717065739.64124-1-pkshih@realtek.com>

From: Ching-Te Ku <ku920601@realtek.com>

The C2H report is for knowing what the grant-signal setting is now,
not for applying new 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 | 24 +++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c
index 1bfd3f3d67de..5f2658eb516c 100644
--- a/drivers/net/wireless/realtek/rtw89/coex.c
+++ b/drivers/net/wireless/realtek/rtw89/coex.c
@@ -1935,8 +1935,8 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
 			dm->wl_fw_cx_offload = !!le32_to_cpu(prpt->v4.wl_fw_info.cx_offload);
 
 			for (i = RTW89_PHY_0; i < RTW89_PHY_NUM; i++)
-				memcpy(&dm->gnt_set[i], &prpt->v4.gnt_val[i],
-				       sizeof(dm->gnt_set[i]));
+				memcpy(&dm->gnt_val[i], &prpt->v4.gnt_val[i],
+				       sizeof(dm->gnt_val[i]));
 
 			bt->bcnt[BTC_BCNT_HIPRI_TX] =
 				le32_to_cpu(prpt->v4.bt_cnt[BTC_BCNT_HI_TX]);
@@ -1967,8 +1967,8 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
 			dm->wl_fw_cx_offload = 0;
 
 			for (i = RTW89_PHY_0; i < RTW89_PHY_NUM; i++)
-				memcpy(&dm->gnt_set[i], &prpt->v5.gnt_val[i],
-				       sizeof(dm->gnt_set[i]));
+				memcpy(&dm->gnt_val[i], &prpt->v5.gnt_val[i],
+				       sizeof(dm->gnt_val[i]));
 
 			bt->bcnt[BTC_BCNT_HIPRI_TX] =
 				le16_to_cpu(prpt->v5.bt_cnt[BTC_BCNT_HI_TX]);
@@ -1994,8 +1994,8 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
 			dm->wl_fw_cx_offload = 0;
 
 			for (i = RTW89_PHY_0; i < RTW89_PHY_NUM; i++)
-				memcpy(&dm->gnt_set[i], &prpt->v105.gnt_val[i],
-				       sizeof(dm->gnt_set[i]));
+				memcpy(&dm->gnt_val[i], &prpt->v105.gnt_val[i],
+				       sizeof(dm->gnt_val[i]));
 
 			bt->bcnt[BTC_BCNT_HIPRI_TX] =
 				le16_to_cpu(prpt->v105.bt_cnt[BTC_BCNT_HI_TX_V105]);
@@ -2020,8 +2020,8 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
 			wl->ver_info.fw = le32_to_cpu(prpt->v7.rpt_info.fw_ver);
 
 			for (i = RTW89_PHY_0; i < RTW89_PHY_NUM; i++)
-				memcpy(&dm->gnt_set[i], &prpt->v7.gnt_val[i],
-				       sizeof(dm->gnt_set[i]));
+				memcpy(&dm->gnt_val[i], &prpt->v7.gnt_val[i],
+				       sizeof(dm->gnt_val[i]));
 
 			bt->bcnt[BTC_BCNT_HIPRI_TX] =
 				le16_to_cpu(prpt->v7.bt_cnt[BTC_BCNT_HI_TX_V105]);
@@ -2052,8 +2052,8 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
 			wl->ver_info.fw = le32_to_cpu(prpt->v8.rpt_info.fw_ver);
 
 			for (i = RTW89_PHY_0; i < RTW89_PHY_NUM; i++)
-				memcpy(&dm->gnt_set[i], &prpt->v8.gnt_val[i],
-				       sizeof(dm->gnt_set[i]));
+				memcpy(&dm->gnt_val[i], &prpt->v8.gnt_val[i],
+				       sizeof(dm->gnt_val[i]));
 
 			bt->bcnt[BTC_BCNT_HIPRI_TX] =
 				le16_to_cpu(prpt->v8.bt_cnt[BTC_BCNT_HI_TX_V105]);
@@ -2137,8 +2137,8 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
 			       sizeof(wl->ver_info.build_date));
 
 			for (i = RTW89_PHY_0; i < RTW89_PHY_NUM; i++)
-				memcpy(&dm->gnt_set[i], &prpt->v11.gnt_val[i][0],
-				       sizeof(dm->gnt_set[i]));
+				memcpy(&dm->gnt_val[i], &prpt->v11.gnt_val[i][0],
+				       sizeof(dm->gnt_val[i]));
 
 			for (i = BTC_BT_1ST; i <= BTC_BT_EXT; i++) {
 				if (i == BTC_BT_EXT) {
-- 
2.25.1


^ permalink raw reply related

* [PATCH rtw-next 02/13] wifi: rtw89: coex: Add version 9 report control info
From: Ping-Ke Shih @ 2026-07-17  6:57 UTC (permalink / raw)
  To: linux-wireless; +Cc: ku920601
In-Reply-To: <20260717065739.64124-1-pkshih@realtek.com>

From: Ching-Te Ku <ku920601@realtek.com>

WiFi firmware will save its build date/time and package into C2H event then
send to driver. It helps to analyze what kind of firmware was loaded now.
Remove unnecessary memory set.

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 | 166 +++++++++++++++++++++-
 drivers/net/wireless/realtek/rtw89/core.h |  18 +++
 2 files changed, 178 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c
index 3addcdfd89eb..1bfd3f3d67de 100644
--- a/drivers/net/wireless/realtek/rtw89/coex.c
+++ b/drivers/net/wireless/realtek/rtw89/coex.c
@@ -1670,6 +1670,10 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
 			pfinfo = &pfwinfo->rpt_ctrl.finfo.v7;
 			pcinfo->req_len = sizeof(pfwinfo->rpt_ctrl.finfo.v7);
 			fwsubver->fcxbtcrpt = pfwinfo->rpt_ctrl.finfo.v7.fver;
+		} else if (ver->fcxbtcrpt == 9) {
+			pfinfo = &pfwinfo->rpt_ctrl.finfo.v9;
+			pcinfo->req_len = sizeof(pfwinfo->rpt_ctrl.finfo.v9);
+			fwsubver->fcxbtcrpt = pfwinfo->rpt_ctrl.finfo.v9.fver;
 		} else if (ver->fcxbtcrpt == 11) {
 			pfinfo = &pfwinfo->rpt_ctrl.finfo.v11;
 			pcinfo->req_len = sizeof(pfwinfo->rpt_ctrl.finfo.v11);
@@ -2075,6 +2079,46 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
 			else
 				dm->error.map.h2c_c2h_buffer_mismatch = false;
 
+			_chk_btc_err(rtwdev, BTC_DCNT_BTCNT_HANG, 0);
+			_chk_btc_err(rtwdev, BTC_DCNT_RPT_HANG, val1);
+			_chk_btc_err(rtwdev, BTC_DCNT_WL_FW_VER_MATCH, 0);
+			_chk_btc_err(rtwdev, BTC_DCNT_BTTX_HANG, 0);
+		}  else if (ver->fcxbtcrpt == 9) {
+			prpt->v9 = pfwinfo->rpt_ctrl.finfo.v9;
+			pfwinfo->rpt_en_map = le32_to_cpu(prpt->v9.rpt_info.en);
+			wl->ver_info.fw_coex = le32_to_cpu(prpt->v9.rpt_info.cx_ver);
+			wl->ver_info.fw = le32_to_cpu(prpt->v9.rpt_info.fw_ver);
+
+			memcpy(wl->ver_info.build_time,
+			       prpt->v9.build_time,
+			       sizeof(wl->ver_info.build_time));
+			memcpy(wl->ver_info.build_date,
+			       prpt->v9.build_date,
+			       sizeof(wl->ver_info.build_date));
+
+			for (i = RTW89_PHY_0; i < RTW89_PHY_NUM; i++)
+				memcpy(&dm->gnt_val[i], &prpt->v9.gnt_val[i],
+				       sizeof(dm->gnt_val[i]));
+
+			bt->bcnt[BTC_BCNT_HIPRI_TX] =
+				le16_to_cpu(prpt->v9.bt_cnt[BTC_BCNT_HI_TX_V105]);
+			bt->bcnt[BTC_BCNT_HIPRI_RX] =
+				le16_to_cpu(prpt->v9.bt_cnt[BTC_BCNT_HI_RX_V105]);
+			bt->bcnt[BTC_BCNT_LOPRI_TX] =
+				le16_to_cpu(prpt->v9.bt_cnt[BTC_BCNT_LO_TX_V105]);
+			bt->bcnt[BTC_BCNT_LOPRI_RX] =
+				le16_to_cpu(prpt->v9.bt_cnt[BTC_BCNT_LO_RX_V105]);
+
+			val1 = le16_to_cpu(prpt->v9.bt_cnt[BTC_BCNT_POLLUTED_V105]);
+			if (val1 > bt->bcnt[BTC_BCNT_POLUT_NOW])
+				val1 -= bt->bcnt[BTC_BCNT_POLUT_NOW]; /* diff */
+
+			bt->bcnt[BTC_BCNT_POLUT_DIFF] = val1;
+			bt->bcnt[BTC_BCNT_POLUT_NOW] =
+				le16_to_cpu(prpt->v9.bt_cnt[BTC_BCNT_POLLUTED_V105]);
+
+			dm->pta_owner = prpt->v9.pta_owner;
+
 			_chk_btc_err(rtwdev, BTC_DCNT_BTCNT_HANG, 0);
 			_chk_btc_err(rtwdev, BTC_DCNT_RPT_HANG, val1);
 			_chk_btc_err(rtwdev, BTC_DCNT_WL_FW_VER_MATCH, 0);
@@ -2085,14 +2129,9 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
 			wl->ver_info.fw_coex = le32_to_cpu(prpt->v11.rpt_info.cx_ver);
 			wl->ver_info.fw = le32_to_cpu(prpt->v11.rpt_info.fw_ver);
 
-			memset(wl->ver_info.build_time, 0,
-			       sizeof(wl->ver_info.build_time));
 			memcpy(wl->ver_info.build_time,
 			       prpt->v11.build_time,
 			       sizeof(wl->ver_info.build_time));
-
-			memset(wl->ver_info.build_date, 0,
-			       sizeof(wl->ver_info.build_date));
 			memcpy(wl->ver_info.build_date,
 			       prpt->v11.build_date,
 			       sizeof(wl->ver_info.build_date));
@@ -2881,6 +2920,7 @@ static void rtw89_btc_fw_en_rpt(struct rtw89_dev *rtwdev,
 
 	if (btc->ver->fcxbtcrpt == 7 ||
 	    btc->ver->fcxbtcrpt == 8 ||
+	    btc->ver->fcxbtcrpt == 9 ||
 	    btc->ver->fcxbtcrpt == 11) {
 		r.v8.type = SET_REPORT_EN;
 		r.v8.fver = btc->ver->fcxbtcrpt;
@@ -9175,9 +9215,10 @@ static int _show_cx_info(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
 	ver_hotfix = FIELD_GET(GENMASK(15, 8), wl->ver_info.fw);
 	id_branch = FIELD_GET(GENMASK(7, 0), wl->ver_info.fw);
 	p += scnprintf(p, end - p,
-		       " %-15s : WL_FW:%d.%d.%d.%d, BT_FW:0x%x(%s)\n",
+		       " %-15s : WL_FW:%d.%d.%d.%d(built:%.12s-%.12s), BT_FW:0x%x(%s)\n",
 		       "[sub_module]",
 		       ver_main, ver_sub, ver_hotfix, id_branch,
+		       wl->ver_info.build_time, wl->ver_info.build_date,
 		       bt->ver_info.fw, bt->run_patch_code ? "patch" : "ROM");
 
 	if (ver->fcxinit == 7) {
@@ -12138,6 +12179,117 @@ static int _show_summary_v8(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
 	return p - buf;
 }
 
+static int _show_summary_v9(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
+{
+	struct rtw89_btc_btf_fwinfo *pfwinfo = &rtwdev->btc.fwinfo;
+	struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
+	struct rtw89_btc_fbtc_rpt_ctrl_v9 *prptctrl = NULL;
+	struct rtw89_btc_cx *cx = &rtwdev->btc.cx;
+	struct rtw89_btc_dm *dm = &rtwdev->btc.dm;
+	struct rtw89_btc_wl_info *wl = &cx->wl;
+	u32 *cnt = rtwdev->btc.dm.cnt_notify;
+	char *p = buf, *end = buf + bufsz;
+	u32 cnt_sum = 0;
+	u8 i;
+
+	if (!(dm->coex_info_map & BTC_COEX_INFO_SUMMARY))
+		return 0;
+
+	p += scnprintf(p, end - p, "%s",
+		       "\n\r========== [Statistics] ==========");
+
+	pcinfo = &pfwinfo->rpt_ctrl.cinfo;
+	if (pcinfo->valid && wl->status.map.lps != BTC_LPS_RF_OFF &&
+	    !wl->status.map.rf_off) {
+		prptctrl = &pfwinfo->rpt_ctrl.finfo.v9;
+
+		p += scnprintf(p, end - p,
+			       "\n\r %-15s : h2c_cnt=%d(fail:%d, fw_recv:%d), c2h_cnt=%d(fw_send:%d, len:%d, ",
+			       "[summary]", pfwinfo->cnt_h2c,
+			       pfwinfo->cnt_h2c_fail,
+			       le16_to_cpu(prptctrl->rpt_info.cnt_h2c),
+			       pfwinfo->cnt_c2h,
+			       le16_to_cpu(prptctrl->rpt_info.cnt_c2h),
+			       le16_to_cpu(prptctrl->rpt_info.len_c2h));
+
+		p += scnprintf(p, end - p,
+			       "rpt_cnt=%d(fw_send:%d), rpt_map=0x%x",
+			       pfwinfo->event[BTF_EVNT_RPT],
+			       le16_to_cpu(prptctrl->rpt_info.cnt),
+			       le32_to_cpu(prptctrl->rpt_info.en));
+
+		if (dm->error.map.wl_fw_hang)
+			p += scnprintf(p, end - p, " (WL FW Hang!!)");
+
+		p += scnprintf(p, end - p,
+			       "\n\r %-15s : send_ok:%d, send_fail:%d, recv:%d, ",
+			       "[mailbox]",
+			       le32_to_cpu(prptctrl->bt_mbx_info.cnt_send_ok),
+			       le32_to_cpu(prptctrl->bt_mbx_info.cnt_send_fail),
+			       le32_to_cpu(prptctrl->bt_mbx_info.cnt_recv));
+
+		p += scnprintf(p, end - p,
+			       "A2DP_empty:%d(stop:%d/tx:%d/ack:%d/nack:%d)",
+			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_empty),
+			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_flowctrl),
+			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_tx),
+			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_ack),
+			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_nack));
+
+		p += scnprintf(p, end - p,
+			       "\n\r %-15s : wl_rfk[req:%d/go:%d/reject:%d/tout:%d/time:%dms]",
+			       "[RFK/LPS]", wl->wcnt[BTC_WCNT_RFK_REQ],
+			       wl->wcnt[BTC_WCNT_RFK_GO],
+			       wl->wcnt[BTC_WCNT_RFK_REJECT],
+			       wl->wcnt[BTC_WCNT_RFK_TIMEOUT],
+			       wl->rfk_info.proc_time);
+
+		p += scnprintf(p, end - p, ", bt_rfk[req:%d]",
+			       le16_to_cpu(prptctrl->bt_cnt[BTC_BCNT_RFK_REQ]));
+
+		p += scnprintf(p, end - p, ", AOAC[RF_on:%d/RF_off:%d]",
+			       le16_to_cpu(prptctrl->rpt_info.cnt_aoac_rf_on),
+			       le16_to_cpu(prptctrl->rpt_info.cnt_aoac_rf_off));
+	} else {
+		p += scnprintf(p, end - p,
+			       "\n\r %-15s : h2c_cnt=%d(fail:%d), c2h_cnt=%d (lps=%d/rf_off=%d)",
+			       "[summary]",
+			       pfwinfo->cnt_h2c, pfwinfo->cnt_h2c_fail,
+			       pfwinfo->cnt_c2h,
+			       wl->status.map.lps, wl->status.map.rf_off);
+	}
+
+	for (i = 0; i < BTC_NCNT_NUM; i++)
+		cnt_sum += dm->cnt_notify[i];
+
+	p += scnprintf(p, end - p,
+		       "\n\r %-15s : total=%d, show_coex_info=%d, power_on=%d, init_coex=%d, ",
+		       "[notify_cnt]",
+		       cnt_sum, cnt[BTC_NCNT_SHOW_COEX_INFO],
+		       cnt[BTC_NCNT_POWER_ON], cnt[BTC_NCNT_INIT_COEX]);
+
+	p += scnprintf(p, end - p,
+		       "power_off=%d, radio_state=%d, role_info=%d, wl_rfk=%d, wl_sta=%d",
+		       cnt[BTC_NCNT_POWER_OFF], cnt[BTC_NCNT_RADIO_STATE],
+		       cnt[BTC_NCNT_ROLE_INFO], cnt[BTC_NCNT_WL_RFK],
+		       cnt[BTC_NCNT_WL_STA]);
+
+	p += scnprintf(p, end - p,
+		       "\n\r %-15s : scan_start=%d, scan_finish=%d, switch_band=%d, switch_chbw=%d, special_pkt=%d, ",
+		       "[notify_cnt]",
+		       cnt[BTC_NCNT_SCAN_START], cnt[BTC_NCNT_SCAN_FINISH],
+		       cnt[BTC_NCNT_SWITCH_BAND], cnt[BTC_NCNT_SWITCH_CHBW],
+		       cnt[BTC_NCNT_SPECIAL_PACKET]);
+
+	p += scnprintf(p, end - p,
+		       "timer=%d, customerize=%d, hub_msg=%d, chg_fw=%d, send_cc=%d",
+		       cnt[BTC_NCNT_TIMER], cnt[BTC_NCNT_CUSTOMERIZE],
+		       rtwdev->btc.hubmsg_cnt, cnt[BTC_NCNT_RESUME_DL_FW],
+		       cnt[BTC_NCNT_COUNTRYCODE]);
+
+	return p - buf;
+}
+
 static int _show_summary_v11(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
 {
 	struct rtw89_btc_btf_fwinfo *pfwinfo = &rtwdev->btc.fwinfo;
@@ -12311,6 +12463,8 @@ ssize_t rtw89_btc_dump_info(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
 		p += _show_summary_v7(rtwdev, p, end - p);
 	else if (ver->fcxbtcrpt == 8)
 		p += _show_summary_v8(rtwdev, p, end - p);
+	else if (ver->fcxbtcrpt == 9)
+		p += _show_summary_v9(rtwdev, p, end - p);
 	else if (ver->fcxbtcrpt == 11)
 		p += _show_summary_v11(rtwdev, p, end - p);
 
diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index c0795e0d10cd..0ec582e86b5b 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -2788,6 +2788,23 @@ struct rtw89_btc_fbtc_rpt_ctrl_v8 {
 	struct rtw89_btc_fbtc_rpt_ctrl_bt_mailbox bt_mbx_info;
 } __packed;
 
+#define RTW89_BTC_TIME_DATE_FMT 12
+struct rtw89_btc_fbtc_rpt_ctrl_v9 {
+	u8 fver;
+	u8 ext_req_exist;
+	u8 pta_owner;
+	u8 rsvd;
+
+	u8 build_time[RTW89_BTC_TIME_DATE_FMT];
+	u8 build_date[RTW89_BTC_TIME_DATE_FMT];
+
+	u8 gnt_val[RTW89_PHY_NUM][4]; /* gwl/gbt012 refer to struct btc_gnt_ctrl */
+	__le16 bt_cnt[BTC_BCNT_STA_MAX_V105];
+
+	struct rtw89_btc_fbtc_rpt_ctrl_info_v8 rpt_info;
+	struct rtw89_btc_fbtc_rpt_ctrl_bt_mailbox bt_mbx_info;
+} __packed;
+
 struct rtw89_btc_fbtc_rpt_ctrl_v11 {
 	u8 fver;
 	u8 rsvd0;
@@ -2815,6 +2832,7 @@ union rtw89_btc_fbtc_rpt_ctrl_ver_info {
 	struct rtw89_btc_fbtc_rpt_ctrl_v105 v105;
 	struct rtw89_btc_fbtc_rpt_ctrl_v7 v7;
 	struct rtw89_btc_fbtc_rpt_ctrl_v8 v8;
+	struct rtw89_btc_fbtc_rpt_ctrl_v9 v9;
 	struct rtw89_btc_fbtc_rpt_ctrl_v11 v11;
 };
 
-- 
2.25.1


^ permalink raw reply related

* [PATCH rtw-next 01/13] wifi: rtw89: coex: Add version 107 TX/RX info for firmware feature
From: Ping-Ke Shih @ 2026-07-17  6:57 UTC (permalink / raw)
  To: linux-wireless; +Cc: ku920601
In-Reply-To: <20260717065739.64124-1-pkshih@realtek.com>

From: Ching-Te Ku <ku920601@realtek.com>

The previous version 7 format is for Dual-Bluetooth using. This patch
is for single Bluetooth solution using. Driver will summary Wi-Fi now
status for firmware to train RF parameters & TDMA mechanism.

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 |  27 ++++--
 drivers/net/wireless/realtek/rtw89/fw.c   | 112 ++++++++++++++++------
 drivers/net/wireless/realtek/rtw89/fw.h   |  24 +++++
 3 files changed, 126 insertions(+), 37 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c
index b044b25aeade..3addcdfd89eb 100644
--- a/drivers/net/wireless/realtek/rtw89/coex.c
+++ b/drivers/net/wireless/realtek/rtw89/coex.c
@@ -3081,10 +3081,15 @@ static void _fw_set_drv_info(struct rtw89_dev *rtwdev, u8 index)
 		if (ver->drvinfo_ver > 1)
 			index = 3;
 
+		if (ver->fcxtrx == 0)
+			return;
+
 		if (ver->fcxtrx == 7)
 			rtw89_fw_h2c_cxdrv_trx_v7(rtwdev, index);
 		else if (ver->fcxtrx == 9)
 			rtw89_fw_h2c_cxdrv_trx_v9(rtwdev, index);
+		else if (ver->fcxtrx == 107)
+			rtw89_fw_h2c_cxdrv_trx_v107(rtwdev, index);
 		break;
 	case CXDRVINFO_RFK:
 		if (ver->drvinfo_ver != 0)
@@ -3096,7 +3101,7 @@ static void _fw_set_drv_info(struct rtw89_dev *rtwdev, u8 index)
 		if (ver->drvinfo_ver == 3)
 			index = 4;
 
-		if (ver->fcxtrx == 7)
+		if (ver->fcxtrx == 7 || ver->fcxtrx == 107)
 			rtw89_fw_h2c_cxtxpwr_v7(rtwdev, index);
 		else if (ver->fcxtrx == 9)
 			rtw89_fw_h2c_cxtxpwr_v9(rtwdev, index);
@@ -3358,7 +3363,8 @@ static void _set_wl_tx_power(struct rtw89_dev *rtwdev, u32 level, u8 phy_map)
 		    dm->rf_trx_para.wl_tx_power[RTW89_PHY_0],
 		    dm->rf_trx_para.wl_tx_power[RTW89_PHY_1]);
 
-	if (ver->fcxtrx == 7 && chip->chip_id == RTL8922A) {
+	if ((ver->fcxtrx == 7 && chip->chip_id == RTL8922A) ||
+	    ver->fcxtrx == 107) {
 		_fw_set_drv_info(rtwdev, CXDRVINFO_TXPWR);
 	} else if (ver->fcxtrx == 9) {
 		_fw_set_drv_info(rtwdev, CXDRVINFO_TXPWR);
@@ -3632,12 +3638,17 @@ static void _set_rf_trx_para(struct rtw89_dev *rtwdev)
 	u8 bid = BTC_BT_1ST, lv;
 	u32 wl_stb_chg;
 
-	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) {
+	if (ver->fcxtrx == 9) {
+		/* Early v9 need to assign UL/DL RF para at driver */
+		if (chip->rf_para_ulink_v9) {
+			ul_para_num = chip->rf_para_ulink_num_v9;
+			dl_para_num = chip->rf_para_dlink_num_v9;
+		} else {
+			_set_rf_trx_para_v9(rtwdev);
+			return;
+		}
+	} else if ((ver->fcxtrx == 0 || ver->fcxtrx == 7 || ver->fcxtrx == 107) &&
+		   chip->rf_para_ulink_v0) {
 		ul_para_num = chip->rf_para_ulink_num_v0;
 		dl_para_num = chip->rf_para_dlink_num_v0;
 	} else {
diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c
index 0db77120298f..33303c097f47 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.c
+++ b/drivers/net/wireless/realtek/rtw89/fw.c
@@ -6677,16 +6677,12 @@ int rtw89_fw_h2c_cxdrv_ctrl_v9(struct rtw89_dev *rtwdev, u8 type)
 	return ret;
 }
 
-int rtw89_fw_h2c_cxdrv_trx_v7(struct rtw89_dev *rtwdev, u8 type)
+static void rtw89_btc_load_trx_para(struct rtw89_dev *rtwdev)
 {
 	struct rtw89_btc *btc = &rtwdev->btc;
 	struct rtw89_btc_rf_trx_para_v9 rf_para = btc->dm.rf_trx_para;
 	struct rtw89_btc_trx_info *trx = &btc->dm.trx_info;
 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
-	struct rtw89_h2c_cxtrx_v7 *h2c;
-	u32 len = sizeof(*h2c);
-	struct sk_buff *skb;
-	int ret;
 	u8 i;
 
 	for (i = 0; i < RTW89_PHY_NUM; i++) {
@@ -6694,19 +6690,38 @@ int rtw89_fw_h2c_cxdrv_trx_v7(struct rtw89_dev *rtwdev, u8 type)
 						   RTW89_BTC_WL_DEF_TX_PWR);
 		trx->wl_rx_gain[i] = u32_get_bits(rf_para.wl_rx_gain[i],
 						  RTW89_BTC_WL_DEF_TX_PWR);
+		if (btc->ver->fcxtrx == 107)
+			break;
 	}
+
 	for (i = 0; i < BTC_ALL_BT; i++) {
 		trx->bt_tx_power[i] = u32_get_bits(rf_para.bt_tx_power[i],
 						   RTW89_BTC_WL_DEF_TX_PWR);
 		trx->bt_rx_gain[i] = u32_get_bits(rf_para.bt_rx_gain[i],
 						  RTW89_BTC_WL_DEF_TX_PWR);
+		if (btc->ver->fcxtrx == 107)
+			break;
+
 		trx->zb_tx_power[i] = u32_get_bits(rf_para.zb_tx_power[i],
 						   RTW89_BTC_WL_DEF_TX_PWR);
 		trx->zb_rx_gain[i] = u32_get_bits(rf_para.zb_rx_gain[i],
 						  RTW89_BTC_WL_DEF_TX_PWR);
 	}
+
 	trx->cn = wl->cn_report;
 	trx->nhm = wl->nhm.pwr;
+}
+
+int rtw89_fw_h2c_cxdrv_trx_v7(struct rtw89_dev *rtwdev, u8 type)
+{
+	struct rtw89_btc *btc = &rtwdev->btc;
+	struct rtw89_btc_trx_info *trx = &btc->dm.trx_info;
+	struct rtw89_h2c_cxtrx_v7 *h2c;
+	u32 len = sizeof(*h2c);
+	struct sk_buff *skb;
+	int ret;
+
+	rtw89_btc_load_trx_para(rtwdev);
 
 	skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
 	if (!skb) {
@@ -6717,7 +6732,7 @@ int rtw89_fw_h2c_cxdrv_trx_v7(struct rtw89_dev *rtwdev, u8 type)
 	h2c = (struct rtw89_h2c_cxtrx_v7 *)skb->data;
 
 	h2c->hdr.type = type;
-	h2c->hdr.ver = btc->ver->fcxtrx;
+	h2c->hdr.ver = 7;
 	h2c->hdr.len = sizeof(*h2c) - H2C_LEN_CXDRVHDR_V7;
 
 	h2c->v7_u8.tx_lvl = trx->tx_lvl;
@@ -6760,33 +6775,14 @@ int rtw89_fw_h2c_cxdrv_trx_v7(struct rtw89_dev *rtwdev, u8 type)
 int rtw89_fw_h2c_cxdrv_trx_v9(struct rtw89_dev *rtwdev, u8 type)
 {
 	struct rtw89_btc *btc = &rtwdev->btc;
-	struct rtw89_btc_rf_trx_para_v9 rf_para = btc->dm.rf_trx_para;
 	struct rtw89_btc_trx_info *trx = &btc->dm.trx_info;
-	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
 	struct rtw89_h2c_cxtrx_v9 *h2c;
 	u32 len = sizeof(*h2c);
 	struct sk_buff *skb;
 	int ret;
 	u8 i;
 
-	for (i = 0; i < RTW89_PHY_NUM; i++) {
-		trx->wl_tx_power[i] = u32_get_bits(rf_para.wl_tx_power[i],
-						   RTW89_BTC_WL_DEF_TX_PWR);
-		trx->wl_rx_gain[i] = u32_get_bits(rf_para.wl_rx_gain[i],
-						  RTW89_BTC_WL_DEF_TX_PWR);
-	}
-	for (i = 0; i < BTC_ALL_BT; i++) {
-		trx->bt_tx_power[i] = u32_get_bits(rf_para.bt_tx_power[i],
-						   RTW89_BTC_WL_DEF_TX_PWR);
-		trx->bt_rx_gain[i] = u32_get_bits(rf_para.bt_rx_gain[i],
-						  RTW89_BTC_WL_DEF_TX_PWR);
-		trx->zb_tx_power[i] = u32_get_bits(rf_para.zb_tx_power[i],
-						   RTW89_BTC_WL_DEF_TX_PWR);
-		trx->zb_rx_gain[i] = u32_get_bits(rf_para.zb_rx_gain[i],
-						  RTW89_BTC_WL_DEF_TX_PWR);
-	}
-	trx->cn = wl->cn_report;
-	trx->nhm = wl->nhm.pwr;
+	rtw89_btc_load_trx_para(rtwdev);
 
 	skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
 	if (!skb) {
@@ -6797,7 +6793,7 @@ int rtw89_fw_h2c_cxdrv_trx_v9(struct rtw89_dev *rtwdev, u8 type)
 	h2c = (struct rtw89_h2c_cxtrx_v9 *)skb->data;
 
 	h2c->hdr.type = type;
-	h2c->hdr.ver = btc->ver->fcxtrx;
+	h2c->hdr.ver = 9;
 	h2c->hdr.len = sizeof(*h2c) - H2C_LEN_CXDRVHDR_V7;
 
 	h2c->v9_u8.tx_lvl = trx->tx_lvl;
@@ -6843,6 +6839,64 @@ int rtw89_fw_h2c_cxdrv_trx_v9(struct rtw89_dev *rtwdev, u8 type)
 	return ret;
 }
 
+int rtw89_fw_h2c_cxdrv_trx_v107(struct rtw89_dev *rtwdev, u8 type)
+{
+	struct rtw89_btc *btc = &rtwdev->btc;
+	struct rtw89_btc_trx_info *trx = &btc->dm.trx_info;
+	struct rtw89_h2c_cxtrx_v107 *h2c;
+	u32 len = sizeof(*h2c);
+	struct sk_buff *skb;
+	int ret;
+
+	rtw89_btc_load_trx_para(rtwdev);
+
+	skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
+	if (!skb) {
+		rtw89_err(rtwdev, "failed to alloc skb for h2c cxtrx_v107\n");
+		return -ENOMEM;
+	}
+	skb_put(skb, len);
+	h2c = (struct rtw89_h2c_cxtrx_v107 *)skb->data;
+
+	h2c->hdr.type = type;
+	h2c->hdr.ver = 7;
+	h2c->hdr.len = sizeof(*h2c) - H2C_LEN_CXDRVHDR_V7;
+
+	h2c->v107_u8.tx_lvl = trx->tx_lvl;
+	h2c->v107_u8.rx_lvl = trx->rx_lvl;
+	h2c->v107_u8.wl_rssi = trx->wl_rssi;
+	h2c->v107_u8.bt_rssi = trx->bt_rssi;
+	h2c->v107_u8.wl_tx_power = trx->bt_tx_power[RTW89_PHY_0];
+	h2c->v107_u8.wl_rx_gain = trx->wl_rx_gain[RTW89_PHY_0];
+	h2c->v107_u8.bt_tx_power = trx->bt_tx_power[BTC_BT_1ST];
+	h2c->v107_u8.bt_rx_gain = trx->bt_rx_gain[BTC_BT_1ST];
+	h2c->v107_u8.cn = trx->cn;
+	h2c->v107_u8.nhm = trx->nhm;
+	h2c->v107_u8.bt_profile = trx->bt_profile;
+	h2c->v107_u8.rsvd2 = trx->rsvd2;
+	h2c->v7_le.tx_rate = cpu_to_le16(trx->tx_rate);
+	h2c->v7_le.rx_rate = cpu_to_le16(trx->rx_rate);
+	h2c->v7_le.tx_tp = cpu_to_le32(trx->tx_tp);
+	h2c->v7_le.rx_tp = cpu_to_le32(trx->rx_tp);
+	h2c->v7_le.rx_err_ratio = cpu_to_le32(trx->rx_err_ratio);
+
+	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 H2C_LEN_CXDRVINFO_RFK (4 + H2C_LEN_CXDRVHDR)
 int rtw89_fw_h2c_cxdrv_rfk(struct rtw89_dev *rtwdev, u8 type)
 {
@@ -6907,7 +6961,7 @@ int rtw89_fw_h2c_cxtxpwr_v7(struct rtw89_dev *rtwdev, u8 type)
 	h2c = (struct rtw89_h2c_cxtxpwr_v7 *)skb->data;
 
 	h2c->hdr.type = type;
-	h2c->hdr.ver = btc->ver->fcxtrx;
+	h2c->hdr.ver = 7;
 	h2c->hdr.len = sizeof(*h2c) - H2C_LEN_CXDRVHDR_V7;
 	h2c->pwr = rp.wl_tx_power[RTW89_PHY_0] & 0xff;
 
@@ -6947,7 +7001,7 @@ int rtw89_fw_h2c_cxtxpwr_v9(struct rtw89_dev *rtwdev, u8 type)
 	h2c = (struct rtw89_h2c_cxtxpwr_v9 *)skb->data;
 
 	h2c->hdr.type = type;
-	h2c->hdr.ver = btc->ver->fcxtrx;
+	h2c->hdr.ver = 9;
 	h2c->hdr.len = sizeof(*h2c) - H2C_LEN_CXDRVHDR_V7;
 	if (dm->wl_tx_pwr_phy_map == BIT(RTW89_PHY_1))
 		h2c->pwr = rp.wl_tx_power[RTW89_PHY_1] & 0xff;
diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h
index a1aab8293c14..a36bb9f024ba 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.h
+++ b/drivers/net/wireless/realtek/rtw89/fw.h
@@ -2517,6 +2517,23 @@ struct rtw89_btc_trx_info_v7_u8 {
 	u8 rsvd2;
 } __packed;
 
+struct rtw89_btc_trx_info_v107_u8 {
+	u8 tx_lvl;
+	u8 rx_lvl;
+	u8 wl_rssi;
+	u8 bt_rssi;
+
+	s8 wl_tx_power;
+	s8 wl_rx_gain;
+	s8 bt_tx_power;
+	s8 bt_rx_gain;
+
+	u8 cn;
+	s8 nhm;
+	u8 bt_profile;
+	u8 rsvd2;
+} __packed;
+
 struct rtw89_btc_trx_info_le {
 	__le16 tx_rate;
 	__le16 rx_rate;
@@ -2538,6 +2555,12 @@ struct rtw89_h2c_cxtrx_v7 {
 	struct rtw89_btc_trx_info_le v7_le;
 } __packed;
 
+struct rtw89_h2c_cxtrx_v107 {
+	struct rtw89_h2c_cxhdr_v7 hdr;
+	struct rtw89_btc_trx_info_v107_u8 v107_u8;
+	struct rtw89_btc_trx_info_le v7_le;
+} __packed;
+
 struct rtw89_h2c_cxtxpwr_v7 {
 	struct rtw89_h2c_cxhdr_v7 hdr;
 	u8 pwr;
@@ -5395,6 +5418,7 @@ int rtw89_fw_h2c_cxdrv_ctrl_v7(struct rtw89_dev *rtwdev, u8 type);
 int rtw89_fw_h2c_cxdrv_ctrl_v9(struct rtw89_dev *rtwdev, u8 type);
 int rtw89_fw_h2c_cxdrv_trx_v7(struct rtw89_dev *rtwdev, u8 type);
 int rtw89_fw_h2c_cxdrv_trx_v9(struct rtw89_dev *rtwdev, u8 type);
+int rtw89_fw_h2c_cxdrv_trx_v107(struct rtw89_dev *rtwdev, u8 type);
 int rtw89_fw_h2c_cxdrv_rfk(struct rtw89_dev *rtwdev, u8 type);
 int rtw89_fw_h2c_cxtxpwr_v7(struct rtw89_dev *rtwdev, u8 type);
 int rtw89_fw_h2c_cxtxpwr_v9(struct rtw89_dev *rtwdev, u8 type);
-- 
2.25.1


^ permalink raw reply related

* [PATCH rtw-next 00/13] wifi: rtw89: coex: add more firmware command and event formats for newer version
From: Ping-Ke Shih @ 2026-07-17  6:57 UTC (permalink / raw)
  To: linux-wireless; +Cc: ku920601

In order to support newer firmware including WiFi 6 chips, add necessary
firmware command and events formats, and define needed version by
chip and firmware version.

Ching-Te Ku (13):
  wifi: rtw89: coex: Add version 107 TX/RX info for firmware feature
  wifi: rtw89: coex: Add version 9 report control info
  wifi: rtw89: coex: Fix unexpected grant-signal assignee
  wifi: rtw89: coex: Branch out version 105 firmware report map index
  wifi: rtw89: coex: Refine chip initial related structure
  wifi: rtw89: coex: Add driver info H2C command index version 103
  wifi: rtw89: coex: Fix Wi-Fi role info H2C command header issue
  wifi: rtw89: coex: Add firmware 0.29.133.X support for RTL8852B family
  wifi: rtw89: coex: Add TDMA version 4
  wifi: rtw89: coex: Add slots version 2
  wifi: rtw89: coex: Add cycle status report version 105
  wifi: rtw89: coex: Add wifi role info version 101
  wifi: rtw89: coex: Add firmware 0.27.97.X support for RTL8852C

 drivers/net/wireless/realtek/rtw89/coex.c     | 672 ++++++++++++++----
 drivers/net/wireless/realtek/rtw89/coex.h     |   8 +-
 drivers/net/wireless/realtek/rtw89/core.h     | 137 +++-
 drivers/net/wireless/realtek/rtw89/fw.c       | 303 ++++++--
 drivers/net/wireless/realtek/rtw89/fw.h       |  64 ++
 drivers/net/wireless/realtek/rtw89/rtw8851b.c | 128 ++--
 drivers/net/wireless/realtek/rtw89/rtw8852a.c |  62 +-
 drivers/net/wireless/realtek/rtw89/rtw8852b.c |  66 +-
 .../net/wireless/realtek/rtw89/rtw8852bt.c    |  71 +-
 drivers/net/wireless/realtek/rtw89/rtw8852c.c |  62 +-
 drivers/net/wireless/realtek/rtw89/rtw8922a.c |  53 +-
 drivers/net/wireless/realtek/rtw89/rtw8922d.c | 149 ++--
 12 files changed, 1198 insertions(+), 577 deletions(-)


base-commit: 730dbda6dc70d29180eb2a7e9fa36823838bb042
-- 
2.25.1


^ permalink raw reply

* [PATCH rtw-next 9/9] wifi: rtw89: phy: set CFR to manual mode for some 2GHz channels
From: Ping-Ke Shih @ 2026-07-17  6:19 UTC (permalink / raw)
  To: linux-wireless; +Cc: gary.chang, sc.lee, wenjie.tsai
In-Reply-To: <20260717061910.54466-1-pkshih@realtek.com>

The CFR (Channel Frequency Response) manual mode condition for 2GHz is
missing to limit on bandwidth for specific channels, which are channel
13 with 20MHz bandwidth and channel 11 with 40MHz bandwidth. Also add
a band check to avoid affecting 5GHz/6GHz bands.

Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
 drivers/net/wireless/realtek/rtw89/phy_be.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/realtek/rtw89/phy_be.c b/drivers/net/wireless/realtek/rtw89/phy_be.c
index e471409a4b8f..c06927d1dc78 100644
--- a/drivers/net/wireless/realtek/rtw89/phy_be.c
+++ b/drivers/net/wireless/realtek/rtw89/phy_be.c
@@ -707,13 +707,19 @@ void rtw89_phy_bb_wrap_set_rfsi_bandedge_ch(struct rtw89_dev *rtwdev,
 					    const struct rtw89_chan *chan,
 					    enum rtw89_phy_idx phy_idx)
 {
+	bool cfr_manual_en = false;
 	u32 reg;
 	u32 val;
 
 	val = rtw89_phy_bb_wrap_be_bandedge_decision(rtwdev, chan);
 
+	if (chan->band_type == RTW89_BAND_2G &&
+	    ((chan->primary_channel == 13 && chan->band_width == RTW89_CHANNEL_WIDTH_20) ||
+	     (chan->primary_channel == 11 && chan->band_width == RTW89_CHANNEL_WIDTH_40)))
+		cfr_manual_en = true;
+
 	rtw89_phy_write32_idx(rtwdev, R_TX_CFR_MANUAL_EN_BE4, B_TX_CFR_MANUAL_EN_BE4_M,
-			      chan->primary_channel == 13, phy_idx);
+			      cfr_manual_en, phy_idx);
 
 	reg = rtw89_mac_reg_by_idx(rtwdev, R_BANDEDGE_DBWX_BE4, phy_idx);
 	rtw89_write32_mask(rtwdev, reg, B_BANDEDGE_DBW20_BE4, val & BIT(0));
-- 
2.25.1


^ permalink raw reply related

* [PATCH rtw-next 8/9] wifi: rtw89: 8922d: reduce IO in power-on function
From: Ping-Ke Shih @ 2026-07-17  6:19 UTC (permalink / raw)
  To: linux-wireless; +Cc: gary.chang, sc.lee, wenjie.tsai
In-Reply-To: <20260717061910.54466-1-pkshih@realtek.com>

To improve initial time, merge some IO to reduce IO times. Two registers
are:
 1. R_BE_SYS_PW_CTRL: 0x4[12:11]=0, 0x4[18]=1, 0x4[15]=0, and 0x4[10]=0
 2. R_BE_SYS_ADIE_PAD_PWR_CTRL: Merge 0x18[6] and 0x18[5]

Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
 drivers/net/wireless/realtek/rtw89/rtw8922d.c | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922d.c b/drivers/net/wireless/realtek/rtw89/rtw8922d.c
index fde4117bcd49..fd4c92ba3f7b 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922d.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922d.c
@@ -518,14 +518,15 @@ static int rtw8922d_pwr_on_func(struct rtw89_dev *rtwdev)
 	}
 
 begin:
-	rtw89_write32_clr(rtwdev, R_BE_SYS_PW_CTRL, B_BE_AFSM_WLSUS_EN |
-						    B_BE_AFSM_PCIE_SUS_EN);
-	rtw89_write32_set(rtwdev, R_BE_SYS_PW_CTRL, B_BE_DIS_WLBT_PDNSUSEN_SOPC);
-	rtw89_write32_set(rtwdev, R_BE_WLLPS_CTRL, B_BE_DIS_WLBT_LPSEN_LOPC);
+	val32 = rtw89_read32(rtwdev, R_BE_SYS_PW_CTRL);
+	val32 &= ~(B_BE_AFSM_WLSUS_EN | B_BE_AFSM_PCIE_SUS_EN | B_BE_APFM_SWLPS);
+	val32 |= B_BE_DIS_WLBT_PDNSUSEN_SOPC;
 	if (hal->cid != RTL8922D_CID7090)
-		rtw89_write32_clr(rtwdev, R_BE_SYS_PW_CTRL, B_BE_APDM_HPDN);
+		val32 &= ~B_BE_APDM_HPDN;
+	rtw89_write32(rtwdev, R_BE_SYS_PW_CTRL, val32);
+
+	rtw89_write32_set(rtwdev, R_BE_WLLPS_CTRL, B_BE_DIS_WLBT_LPSEN_LOPC);
 	rtw89_write32_clr(rtwdev, R_BE_FWS1ISR, B_BE_FS_WL_HW_RADIO_OFF_INT);
-	rtw89_write32_clr(rtwdev, R_BE_SYS_PW_CTRL, B_BE_APFM_SWLPS);
 
 	ret = read_poll_timeout(rtw89_read32, val32, val32 & B_BE_RDY_SYSPWR,
 				1000, 3000000, false, rtwdev, R_BE_SYS_PW_CTRL);
@@ -581,14 +582,13 @@ static int rtw8922d_pwr_on_func(struct rtw89_dev *rtwdev)
 	if (ret)
 		return ret;
 
-	rtw89_write32_set(rtwdev, R_BE_SYS_ADIE_PAD_PWR_CTRL, B_BE_SYM_PADPDN_WL_RFC1_1P3);
+	rtw89_write32_set(rtwdev, R_BE_SYS_ADIE_PAD_PWR_CTRL,
+			  B_BE_SYM_PADPDN_WL_RFC1_1P3 | B_BE_SYM_PADPDN_WL_RFC0_1P3);
 
 	ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0x40, 0x40);
 	if (ret)
 		return ret;
 
-	rtw89_write32_set(rtwdev, R_BE_SYS_ADIE_PAD_PWR_CTRL, B_BE_SYM_PADPDN_WL_RFC0_1P3);
-
 	ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0x20, 0x20);
 	if (ret)
 		return ret;
-- 
2.25.1


^ permalink raw reply related

* [PATCH rtw-next 7/9] wifi: rtw89: pci: set PCIe maximum TS1 for RTL8922DE
From: Ping-Ke Shih @ 2026-07-17  6:19 UTC (permalink / raw)
  To: linux-wireless; +Cc: gary.chang, sc.lee, wenjie.tsai
In-Reply-To: <20260717061910.54466-1-pkshih@realtek.com>

Set TS1 (training sequence 1) to 1024 when PCIe enters recovery state to
improve RF interference while entering and leaving L1ss.

Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
 drivers/net/wireless/realtek/rtw89/pci.h    |  1 +
 drivers/net/wireless/realtek/rtw89/pci_be.c | 11 ++++++++++-
 2 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/realtek/rtw89/pci.h b/drivers/net/wireless/realtek/rtw89/pci.h
index 339706d99f6c..0e1557cedd20 100644
--- a/drivers/net/wireless/realtek/rtw89/pci.h
+++ b/drivers/net/wireless/realtek/rtw89/pci.h
@@ -1138,6 +1138,7 @@
 #define RTW89_PCIE_GEN1_SPEED		0x01
 #define RTW89_PCIE_GEN2_SPEED		0x02
 #define RTW89_PCIE_PHY_RATE		0x82
+#define RTW89_PCIE_EXTENDED_SYNCH	BIT(7)
 #define RTW89_PCIE_PHY_RATE_MASK	GENMASK(1, 0)
 #define RTW89_PCIE_LINK_CHANGE_SPEED	0xA0
 #define RTW89_PCIE_L1SS_STS_V1		0x0168
diff --git a/drivers/net/wireless/realtek/rtw89/pci_be.c b/drivers/net/wireless/realtek/rtw89/pci_be.c
index 6390980b8ee0..d338bf633272 100644
--- a/drivers/net/wireless/realtek/rtw89/pci_be.c
+++ b/drivers/net/wireless/realtek/rtw89/pci_be.c
@@ -85,13 +85,22 @@ static void _patch_pcie_power_wake_be(struct rtw89_dev *rtwdev, bool power_up)
 
 static void _patch_pre_init_be(struct rtw89_dev *rtwdev)
 {
+	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
 	struct rtw89_hal *hal = &rtwdev->hal;
+	struct pci_dev *pdev = rtwpci->pdev;
 
-	if (!(rtwdev->chip->chip_id == RTL8922D && hal->cid == RTL8922D_CID7090))
+	if (rtwdev->chip->chip_id != RTL8922D)
 		return;
 
+	if (hal->cid != RTL8922D_CID7090)
+		goto set_ts1;
+
 	rtw89_write16_clr(rtwdev, R_RAC_DIRECT_OFFSET_BE_LANE0_G2 +
 				  RAC_ANA14 * RAC_MULT, EIEOS_L1SS_WAIT_CLKRDY);
+
+set_ts1:
+	pci_clear_and_set_config_dword(pdev, RTW89_PCIE_L1_STS_V1,
+				       0, RTW89_PCIE_EXTENDED_SYNCH);
 }
 
 static void rtw89_pci_set_io_rcy_be(struct rtw89_dev *rtwdev)
-- 
2.25.1


^ permalink raw reply related

* [PATCH rtw-next 6/9] wifi: rtw89: wow: extend timeout unit to avoid SER false alarm
From: Ping-Ke Shih @ 2026-07-17  6:19 UTC (permalink / raw)
  To: linux-wireless; +Cc: gary.chang, sc.lee, wenjie.tsai
In-Reply-To: <20260717061910.54466-1-pkshih@realtek.com>

With original timeout unit, it might trigger SER false alarm causing
WiFi card lost. Extend timeout unit to avoid wrong SER.

Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
 drivers/net/wireless/realtek/rtw89/pci.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/realtek/rtw89/pci.h b/drivers/net/wireless/realtek/rtw89/pci.h
index 92c30c7f9fb2..339706d99f6c 100644
--- a/drivers/net/wireless/realtek/rtw89/pci.h
+++ b/drivers/net/wireless/realtek/rtw89/pci.h
@@ -1022,7 +1022,7 @@
 #define B_BE_PL1_IGNORE_HOT_RST BIT(30)
 #define B_BE_PL1_TIMER_UNIT_MASK GENMASK(19, 17)
 #define PCIE_SER_TIMER_UNIT 0x2
-#define PCIE_SER_WOW_TIMER_UNIT 0x4
+#define PCIE_SER_WOW_TIMER_UNIT 0x7
 #define B_BE_PL1_TIMER_CLEAR BIT(0)
 
 #define R_BE_REG_PL1_MASK 0x34B0
-- 
2.25.1


^ permalink raw reply related

* [PATCH rtw-next 5/9] wifi: rtw89: 8922d: bypass TXIQK when scan
From: Ping-Ke Shih @ 2026-07-17  6:19 UTC (permalink / raw)
  To: linux-wireless; +Cc: gary.chang, sc.lee, wenjie.tsai
In-Reply-To: <20260717061910.54466-1-pkshih@realtek.com>

From: Chih-Kang Chang <gary.chang@realtek.com>

When connected to an AP and a scan is triggered, the FW may fail to
transmit probe request because switching channels may load an
uninitialized TXIQK table. Therefore, bypass TXIQK during scanning
to avoid using invalid calibration values.

Signed-off-by: Chih-Kang Chang <gary.chang@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
 drivers/net/wireless/realtek/rtw89/core.h     |  1 +
 drivers/net/wireless/realtek/rtw89/reg.h      | 10 +++
 drivers/net/wireless/realtek/rtw89/rtw8922d.c | 64 ++++++++++++++++++-
 3 files changed, 73 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index 9b7f197a3af2..2d9113cb43f9 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -6284,6 +6284,7 @@ struct rtw89_iqk_info {
 	u8 iqk_table_idx[RTW89_IQK_PATH_NR];
 	u32 lok_idac[RTW89_IQK_CHS_NR][RTW89_IQK_PATH_NR];
 	u32 lok_vbuf[RTW89_IQK_CHS_NR][RTW89_IQK_PATH_NR];
+	u32 iqc_bak[2];
 };
 
 #define RTW89_DPK_RF_PATH 2
diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h
index 053028b9ef16..756b94dcd475 100644
--- a/drivers/net/wireless/realtek/rtw89/reg.h
+++ b/drivers/net/wireless/realtek/rtw89/reg.h
@@ -10121,6 +10121,7 @@
 #define B_S1_DACKQ8_K GENMASK(15, 8)
 #define R_NCTL_CFG 0x8000
 #define R_NCTL_CFG_BE4 0x38000
+#define B_NCTL_CFG_BE4_SPAGE GENMASK(25, 24)
 #define B_NCTL_CHK_EN BIT(3)
 #define B_NCTL_CFG_SPAGE GENMASK(2, 1)
 #define R_NCTL_RPT 0x8008
@@ -11061,6 +11062,15 @@
 #define B_KTBL0_MLD_IDX0 GENMASK(25, 24)
 #define B_KTBL0_MLD_IDX1 GENMASK(27, 26)
 #define B_KTBL0_RST BIT(31)
+#define R_CFIR_CTRL_A_BE4 0x38124
+#define R_CFIR_CTRL_B_BE4 0x38224
+#define B_CFIR_CTRL_KIDX0_EN BIT(8)
+#define B_CFIR_CTRL_KIDX1_EN BIT(24)
+#define R_TX_IQC_A_BE4 0x38138
+#define R_TX_IQC_B_BE4 0x38238
+#define B_TX_IQC_X GENMASK(31, 20)
+#define B_TX_IQC_Y GENMASK(19, 8)
+#define B_TX_IQC_DPK BIT(3)
 #define R_KTBL1A_BE4 0x38154
 #define R_KTBL1B_BE4 0x38254
 #define B_KTBL1_TBL0 BIT(3)
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922d.c b/drivers/net/wireless/realtek/rtw89/rtw8922d.c
index 929bcfc8089d..fde4117bcd49 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922d.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922d.c
@@ -2765,14 +2765,74 @@ static void rtw8922d_rfk_band_changed(struct rtw89_dev *rtwdev,
 {
 }
 
+static void __rtw8922d_txiqk_disable(struct rtw89_dev *rtwdev)
+{
+	struct rtw89_iqk_info *iqk_info = &rtwdev->iqk;
+	u8 path, kidx;
+
+	for (path = RF_PATH_A; path <= RF_PATH_B; path++) {
+		kidx = rtw89_phy_read32_mask(rtwdev, R_KTBL0A_BE4 + (path << 8),
+					     B_KTBL0_IDX0);
+		if (kidx == 0) {
+			rtw89_phy_write32_clr(rtwdev, R_CFIR_CTRL_A_BE4 + (path << 8),
+					      B_CFIR_CTRL_KIDX0_EN);
+		} else if (kidx == 1) {
+			rtw89_phy_write32_clr(rtwdev, R_CFIR_CTRL_A_BE4 + (path << 8),
+					      B_CFIR_CTRL_KIDX1_EN);
+		} else {
+			rtw89_phy_write32_mask(rtwdev, R_NCTL_CFG_BE4,
+					       B_NCTL_CFG_BE4_SPAGE, 0x1);
+			rtw89_phy_write32_clr(rtwdev, R_CFIR_CTRL_A_BE4 + (path << 8),
+					      B_CFIR_CTRL_KIDX0_EN);
+			rtw89_phy_write32_mask(rtwdev, R_NCTL_CFG_BE4,
+					       B_NCTL_CFG_BE4_SPAGE, 0x0);
+		}
+
+		iqk_info->iqc_bak[path] =
+			rtw89_phy_read32(rtwdev, R_TX_IQC_A_BE4 + (path << 8));
+		rtw89_phy_write32(rtwdev, R_TX_IQC_A_BE4 + (path << 8), 0x40000002);
+	}
+}
+
+static void __rtw8922d_txiqk_enable(struct rtw89_dev *rtwdev)
+{
+	struct rtw89_iqk_info *iqk_info = &rtwdev->iqk;
+	u8 path, kidx;
+
+	for (path = RF_PATH_A; path <= RF_PATH_B; path++) {
+		kidx = rtw89_phy_read32_mask(rtwdev, R_KTBL0A_BE4 + (path << 8),
+					     B_KTBL0_IDX0);
+		if (kidx == 0) {
+			rtw89_phy_write32_set(rtwdev, R_CFIR_CTRL_A_BE4 + (path << 8),
+					      B_CFIR_CTRL_KIDX0_EN);
+		} else if (kidx == 1) {
+			rtw89_phy_write32_set(rtwdev, R_CFIR_CTRL_A_BE4 + (path << 8),
+					      B_CFIR_CTRL_KIDX1_EN);
+		} else {
+			rtw89_phy_write32_mask(rtwdev, R_NCTL_CFG_BE4,
+					       B_NCTL_CFG_BE4_SPAGE, 0x1);
+			rtw89_phy_write32_set(rtwdev, R_CFIR_CTRL_A_BE4 + (path << 8),
+					      B_CFIR_CTRL_KIDX0_EN);
+			rtw89_phy_write32_mask(rtwdev, R_NCTL_CFG_BE4,
+					       B_NCTL_CFG_BE4_SPAGE, 0x0);
+		}
+
+		rtw89_phy_write32(rtwdev, R_TX_IQC_A_BE4 + (path << 8),
+				  iqk_info->iqc_bak[path]);
+	}
+}
+
 static void rtw8922d_rfk_scan(struct rtw89_dev *rtwdev,
 			      struct rtw89_vif_link *rtwvif_link,
 			      bool start)
 {
-	if (start)
+	if (start) {
 		__rtw8922d_tssi_disable(rtwdev, rtwvif_link->phy_idx);
-	else
+		__rtw8922d_txiqk_disable(rtwdev);
+	} else {
 		__rtw8922d_tssi_enable(rtwdev, rtwvif_link->phy_idx);
+		__rtw8922d_txiqk_enable(rtwdev);
+	}
 }
 
 static void rtw8922d_rfk_track(struct rtw89_dev *rtwdev)
-- 
2.25.1


^ permalink raw reply related

* [PATCH rtw-next 4/9] wifi: rtw89: rfk: update TXIQK H2C command format to v1
From: Ping-Ke Shih @ 2026-07-17  6:19 UTC (permalink / raw)
  To: linux-wireless; +Cc: gary.chang, sc.lee, wenjie.tsai
In-Reply-To: <20260717061910.54466-1-pkshih@realtek.com>

From: Chih-Kang Chang <gary.chang@realtek.com>

TX IQK is a RF calibration, the v1 format adds a field for the thermal
re-calibration parameter for RTL8922D after FW 0.35.113.0. Update the
format accordingly.

Signed-off-by: Chih-Kang Chang <gary.chang@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
 drivers/net/wireless/realtek/rtw89/core.h |  1 +
 drivers/net/wireless/realtek/rtw89/fw.c   | 35 ++++++++++++++++-------
 drivers/net/wireless/realtek/rtw89/fw.h   |  7 ++++-
 3 files changed, 32 insertions(+), 11 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index 9d782cbfee70..9b7f197a3af2 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -5599,6 +5599,7 @@ enum rtw89_fw_feature {
 	),
 	RTW89_FW_FEATURE_RFK_RXDCK_V0,
 	RTW89_FW_FEATURE_RFK_IQK_V0,
+	RTW89_FW_FEATURE_RFK_TXIQK_V0,
 	RTW89_FW_FEATURE_NO_WOW_CPU_IO_RX,
 	RTW89_FW_FEATURE_NOTIFY_AP_INFO,
 	RTW89_FW_FEATURE_CH_INFO_BE_V0,
diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c
index 0db77120298f..ad87484f51a7 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.c
+++ b/drivers/net/wireless/realtek/rtw89/fw.c
@@ -948,6 +948,7 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = {
 	__CFG_FW_FEAT(RTL8922D, ge, 0, 35, 104, 0, TX_HISTORY_V1),
 	__CFG_FW_FEAT(RTL8922D, ge, 0, 35, 108, 0, SIM_SER_L0L1_BY_HALT_H2C),
 	__CFG_FW_FEAT(RTL8922D, lt, 0, 35, 109, 1, SCAN_OFFLOAD_BE_V1),
+	__CFG_FW_FEAT(RTL8922D, lt, 0, 35, 113, 0, RFK_TXIQK_V0),
 };
 
 static void rtw89_fw_iterate_feature_cfg(struct rtw89_fw_info *fw,
@@ -8464,29 +8465,43 @@ int rtw89_fw_h2c_rf_tas_trigger(struct rtw89_dev *rtwdev, bool enable)
 int rtw89_fw_h2c_rf_txiqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx,
 			  const struct rtw89_chan *chan)
 {
+	struct rtw89_h2c_rf_txiqk_v0 *h2c_v0;
 	struct rtw89_h2c_rf_txiqk *h2c;
 	u32 len = sizeof(*h2c);
 	struct sk_buff *skb;
+	u8 ver = U8_MAX;
 	int ret;
 
+	if (RTW89_CHK_FW_FEATURE(RFK_TXIQK_V0, &rtwdev->fw)) {
+		len = sizeof(*h2c_v0);
+		ver = 0;
+	}
+
 	skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
 	if (!skb) {
 		rtw89_err(rtwdev, "failed to alloc skb for h2c RF TXIQK\n");
 		return -ENOMEM;
 	}
 	skb_put(skb, len);
-	h2c = (struct rtw89_h2c_rf_txiqk *)skb->data;
+	h2c_v0 = (struct rtw89_h2c_rf_txiqk_v0 *)skb->data;
+
+	h2c_v0->len = len;
+	h2c_v0->phy = phy_idx;
+	h2c_v0->txiqk_enable = true;
+	h2c_v0->is_wb_txiqk = true;
+	h2c_v0->kpath = RF_AB;
+	h2c_v0->cur_band = chan->band_type;
+	h2c_v0->cur_bw = chan->band_width;
+	h2c_v0->cur_ch = chan->channel;
+	h2c_v0->txiqk_dbg_en = rtw89_debug_is_enabled(rtwdev, RTW89_DBG_RFK);
 
-	h2c->len = len;
-	h2c->phy = phy_idx;
-	h2c->txiqk_enable = true;
-	h2c->is_wb_txiqk = true;
-	h2c->kpath = RF_AB;
-	h2c->cur_band = chan->band_type;
-	h2c->cur_bw = chan->band_width;
-	h2c->cur_ch = chan->channel;
-	h2c->txiqk_dbg_en = rtw89_debug_is_enabled(rtwdev, RTW89_DBG_RFK);
+	if (ver == 0)
+		goto hdr;
+
+	h2c = (struct rtw89_h2c_rf_txiqk *)skb->data;
+	h2c->is_ther_rek = false;
 
+hdr:
 	rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
 			      H2C_CAT_OUTSRC, H2C_CL_OUTSRC_RF_FW_RFK,
 			      H2C_FUNC_RFK_TXIQK_OFFOAD, 0, 0, len);
diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h
index a1aab8293c14..2654f8fd0e51 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.h
+++ b/drivers/net/wireless/realtek/rtw89/fw.h
@@ -5042,7 +5042,7 @@ struct rtw89_h2c_rf_rxdck {
 	u8 is_chl_k;
 } __packed;
 
-struct rtw89_h2c_rf_txiqk {
+struct rtw89_h2c_rf_txiqk_v0 {
 	u8 len;
 	u8 phy;
 	u8 txiqk_enable;
@@ -5054,6 +5054,11 @@ struct rtw89_h2c_rf_txiqk {
 	u8 txiqk_dbg_en;
 } __packed;
 
+struct rtw89_h2c_rf_txiqk {
+	struct rtw89_h2c_rf_txiqk_v0 v0;
+	u8 is_ther_rek;
+} __packed;
+
 struct rtw89_h2c_rf_cim3k {
 	u8 len;
 	u8 phy;
-- 
2.25.1


^ permalink raw reply related

* [PATCH rtw-next 3/9] wifi: rtw89: 8852cu: add quirk to disable 2.4 GHz band
From: Ping-Ke Shih @ 2026-07-17  6:19 UTC (permalink / raw)
  To: linux-wireless; +Cc: gary.chang, sc.lee, wenjie.tsai
In-Reply-To: <20260717061910.54466-1-pkshih@realtek.com>

From: David Lee <sc.lee@realtek.com>

Add RTW89_QUIRK_DISABLE_2GHZ to the rtw89_quirks enum to allow
per-device suppression of the 2.4 GHz band.

Apply the quirk only for the 0x28de:0x2432 (VID:PID) USB device,
which operates only in 5/6 GHz bands.

Signed-off-by: David Lee <sc.lee@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
 drivers/net/wireless/realtek/rtw89/core.c      | 3 +++
 drivers/net/wireless/realtek/rtw89/core.h      | 1 +
 drivers/net/wireless/realtek/rtw89/rtw8852cu.c | 3 ++-
 3 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c
index b87a72700b99..77a0e2582dbe 100644
--- a/drivers/net/wireless/realtek/rtw89/core.c
+++ b/drivers/net/wireless/realtek/rtw89/core.c
@@ -6418,6 +6418,9 @@ static int rtw89_core_set_supported_band(struct rtw89_dev *rtwdev)
 	u8 support_bands = rtwdev->chip->support_bands;
 	int ret;
 
+	if (test_bit(RTW89_QUIRK_DISABLE_2GHZ, rtwdev->quirks))
+		support_bands &= ~BIT(NL80211_BAND_2GHZ);
+
 	if (support_bands & BIT(NL80211_BAND_2GHZ)) {
 		sband = rtw89_core_sband_dup(rtwdev, &rtw89_sband_2ghz);
 		if (!sband)
diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index 70cf6cbf4e8a..9d782cbfee70 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -6057,6 +6057,7 @@ enum rtw89_quirks {
 	RTW89_QUIRK_THERMAL_PROT_120C,
 	RTW89_QUIRK_THERMAL_PROT_110C,
 	RTW89_QUIRK_HW_INFO_SYSFS,
+	RTW89_QUIRK_DISABLE_2GHZ,
 
 	NUM_OF_RTW89_QUIRKS,
 };
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852cu.c b/drivers/net/wireless/realtek/rtw89/rtw8852cu.c
index 51dd8fb05366..2dec9b845481 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852cu.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852cu.c
@@ -97,7 +97,8 @@ static const struct rtw89_driver_info rtw89_8852cu_valve_info = {
 	.variant = NULL,
 	.board = &rtw89_8852cu_valve_board,
 	.quirks = NULL,
-	.dev_id_quirks = BIT(RTW89_QUIRK_HW_INFO_SYSFS),
+	.dev_id_quirks = BIT(RTW89_QUIRK_HW_INFO_SYSFS) |
+			 BIT(RTW89_QUIRK_DISABLE_2GHZ),
 	.bus = {
 		.usb = &rtw8852c_usb_info,
 	},
-- 
2.25.1


^ permalink raw reply related

* [PATCH rtw-next 2/9] wifi: rtw89: add multicolor LED support for RTL8852CU valve board
From: Ping-Ke Shih @ 2026-07-17  6:19 UTC (permalink / raw)
  To: linux-wireless; +Cc: gary.chang, sc.lee, wenjie.tsai
In-Reply-To: <20260717061910.54466-1-pkshih@realtek.com>

From: Johnson Tsai <wenjie.tsai@realtek.com>

Add multicolor LED support for the RTL8852CU valve board to reflect
wireless connection status (by default, green LED is ON when associated
and OFF when disconnected).

Extend the rtw89 LED subsystem with a multicolor path via led_classdev_mc,
for board-level variants with more than one LED GPIO channel.

Add a new RTW89_LEDS_MC Kconfig option and support multicolor LEDs
through led_classdev_mc, with per-channel caching to minimize
redundant register writes. The RTL8852CU valve board is wired up as
the first user, driving a multicolor WRGB LED over four GPIO channels
(8, 18, 16, and 17) that map to LED_COLOR_ID_WHITE/RED/GREEN/BLUE.

Usage:
- Auto-triggered (default):
  Green LED ON when connected, OFF when disconnected

- Manual override (e.g., set red; channel order: WHITE RED GREEN BLUE):
    echo "0 1 0 0" > /sys/class/leds/rtw89-phyX-multicolor/multi_intensity
    echo 1         > /sys/class/leds/rtw89-phyX-multicolor/brightness

Signed-off-by: Johnson Tsai <wenjie.tsai@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
 drivers/net/wireless/realtek/rtw89/Kconfig    |  7 ++
 drivers/net/wireless/realtek/rtw89/Makefile   |  1 +
 drivers/net/wireless/realtek/rtw89/core.c     |  1 +
 drivers/net/wireless/realtek/rtw89/core.h     | 15 +++-
 drivers/net/wireless/realtek/rtw89/led.c      | 26 ++++--
 drivers/net/wireless/realtek/rtw89/led.h      | 13 +++
 drivers/net/wireless/realtek/rtw89/led_mc.c   | 81 +++++++++++++++++++
 drivers/net/wireless/realtek/rtw89/reg.h      |  2 +
 .../net/wireless/realtek/rtw89/rtw8851be.c    |  1 +
 .../net/wireless/realtek/rtw89/rtw8851bu.c    |  1 +
 .../net/wireless/realtek/rtw89/rtw8852ae.c    |  1 +
 .../net/wireless/realtek/rtw89/rtw8852au.c    |  1 +
 .../net/wireless/realtek/rtw89/rtw8852be.c    |  1 +
 .../net/wireless/realtek/rtw89/rtw8852bte.c   |  1 +
 .../net/wireless/realtek/rtw89/rtw8852bu.c    |  1 +
 .../net/wireless/realtek/rtw89/rtw8852ce.c    |  1 +
 .../net/wireless/realtek/rtw89/rtw8852cu.c    | 54 +++++++++++++
 .../net/wireless/realtek/rtw89/rtw8922ae.c    |  2 +
 .../net/wireless/realtek/rtw89/rtw8922au.c    |  1 +
 .../net/wireless/realtek/rtw89/rtw8922de.c    |  2 +
 20 files changed, 207 insertions(+), 6 deletions(-)
 create mode 100644 drivers/net/wireless/realtek/rtw89/led_mc.c

diff --git a/drivers/net/wireless/realtek/rtw89/Kconfig b/drivers/net/wireless/realtek/rtw89/Kconfig
index be31eaab7621..7200a944260f 100644
--- a/drivers/net/wireless/realtek/rtw89/Kconfig
+++ b/drivers/net/wireless/realtek/rtw89/Kconfig
@@ -197,4 +197,11 @@ config RTW89_LEDS
 	imply MAC80211_LEDS
 	default y
 
+config RTW89_LEDS_MC
+	bool
+	depends on RTW89_LEDS
+	depends on LEDS_CLASS_MULTICOLOR
+	imply LEDS_TRIGGER_TIMER
+	default y
+
 endif
diff --git a/drivers/net/wireless/realtek/rtw89/Makefile b/drivers/net/wireless/realtek/rtw89/Makefile
index 3d47f13d1e66..5536714e0268 100644
--- a/drivers/net/wireless/realtek/rtw89/Makefile
+++ b/drivers/net/wireless/realtek/rtw89/Makefile
@@ -93,6 +93,7 @@ rtw89_8922au-objs := rtw8922au.o
 
 rtw89_core-$(CONFIG_RTW89_DEBUG) += debug.o
 rtw89_core-$(CONFIG_RTW89_LEDS) += led.o
+rtw89_core-$(CONFIG_RTW89_LEDS_MC) += led_mc.o
 
 obj-$(CONFIG_RTW89_PCI) += rtw89_pci.o
 rtw89_pci-y := pci.o pci_be.o
diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c
index bb04f649bfb0..b87a72700b99 100644
--- a/drivers/net/wireless/realtek/rtw89/core.c
+++ b/drivers/net/wireless/realtek/rtw89/core.c
@@ -7701,6 +7701,7 @@ struct rtw89_dev *rtw89_alloc_ieee80211_hw(struct device *device,
 	rtwdev->ops = ops;
 	rtwdev->chip = chip;
 	rtwdev->variant = variant;
+	rtwdev->board = info->board;
 	rtwdev->fw.req.firmware = firmware;
 	rtwdev->fw.fw_format = fw_format;
 	rtwdev->support_mlo = support_mlo;
diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index 41cc519317c9..70cf6cbf4e8a 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -11,6 +11,7 @@
 #include <linux/firmware.h>
 #include <linux/iopoll.h>
 #include <linux/leds.h>
+#include <linux/led-class-multicolor.h>
 #include <linux/workqueue.h>
 #include <net/mac80211.h>
 
@@ -5279,8 +5280,12 @@ struct rtw89_chanctx_listener {
 #define RTW89_NHM_TH_NUM 11
 #define RTW89_NHM_RPT_NUM 12
 
+#define RTW89_LED_MAX_NUM  4
+
 struct rtw89_led_gpio_entry {
 	u8 pin;
+	unsigned int color;
+	u8 intensity;
 	struct rtw89_reg3_def pinmux;
 	struct rtw89_reg2_def mode;
 	struct rtw89_reg2_def out;
@@ -5295,7 +5300,9 @@ struct rtw89_led {
 	bool registered;
 	const struct rtw89_led_desc *desc;
 	struct led_classdev led;
-	enum led_brightness brightness_cache;
+	struct led_classdev_mc led_mc;
+	struct mc_subled subled[RTW89_LED_MAX_NUM];
+	enum led_brightness brightness_cache[RTW89_LED_MAX_NUM];
 	char name[32];
 };
 
@@ -5454,6 +5461,10 @@ struct rtw89_chip_variant {
 	const struct rtw89_qta_def *qta_def_override;
 };
 
+struct rtw89_board_variant {
+	const struct rtw89_led_desc *led_desc;
+};
+
 union rtw89_bus_info {
 	const struct rtw89_pci_info *pci;
 	const struct rtw89_usb_info *usb;
@@ -5462,6 +5473,7 @@ union rtw89_bus_info {
 struct rtw89_driver_info {
 	const struct rtw89_chip_info *chip;
 	const struct rtw89_chip_variant *variant;
+	const struct rtw89_board_variant *board;
 	const struct dmi_system_id *quirks;
 	unsigned long dev_id_quirks; /* bitmap of rtw89_quirks */
 	union rtw89_bus_info bus;
@@ -7136,6 +7148,7 @@ struct rtw89_dev {
 	struct rtw89_hw_scan_info scan_info;
 	const struct rtw89_chip_info *chip;
 	const struct rtw89_chip_variant *variant;
+	const struct rtw89_board_variant *board;
 	const struct rtw89_pci_info *pci_info;
 	const struct rtw89_rfe_parms *rfe_parms;
 	struct rtw89_hal hal;
diff --git a/drivers/net/wireless/realtek/rtw89/led.c b/drivers/net/wireless/realtek/rtw89/led.c
index 64e7eaa7ee39..ae74b7075d7c 100644
--- a/drivers/net/wireless/realtek/rtw89/led.c
+++ b/drivers/net/wireless/realtek/rtw89/led.c
@@ -45,7 +45,7 @@ static int rtw89_led_set(struct led_classdev *led, enum led_brightness brightnes
 	const struct rtw89_led_desc *desc = rtw_led->desc;
 	const struct rtw89_led_gpio_entry *e = &desc->gpios[0];
 
-	if (rtw_led->brightness_cache == brightness) {
+	if (rtw_led->brightness_cache[0] == brightness) {
 		rtw89_debug(rtwdev, RTW89_DBG_LED, "led_set: pin=%u skip (no change)\n",
 			    e->pin);
 		return 0;
@@ -56,7 +56,7 @@ static int rtw89_led_set(struct led_classdev *led, enum led_brightness brightnes
 	rtw89_debug(rtwdev, RTW89_DBG_LED, "led_set: pin=%u brightness=%u\n",
 		    e->pin, brightness);
 	rtw89_led_gpio_set(rtwdev, e, brightness);
-	rtw_led->brightness_cache = brightness;
+	rtw_led->brightness_cache[0] = brightness;
 
 	wiphy_unlock(rtwdev->hw->wiphy);
 
@@ -97,15 +97,27 @@ void rtw89_led_init(struct rtw89_dev *rtwdev)
 {
 	const struct rtw89_led_desc *desc = &rtw89_common_led_desc;
 	struct rtw89_led *rtw_led = &rtwdev->led;
+	const struct rtw89_board_variant *board = rtwdev->board;
 	int ret;
+	int i;
 
 	/* single-GPIO monochrome LED is the only supported layout */
 	BUILD_BUG_ON(ARRAY_SIZE(rtw89_common_led_gpios) != 1);
 
+	if (board)
+		desc = board->led_desc;
+	if (!desc->n_gpio || desc->n_gpio > RTW89_LED_MAX_NUM)
+		return;
+
 	rtw_led->desc = desc;
-	rtw_led->brightness_cache = LED_OFF;
+	for (i = 0; i < ARRAY_SIZE(rtw_led->brightness_cache); i++)
+		rtw_led->brightness_cache[i] = LED_OFF;
+
+	if (desc->n_gpio == 1)
+		ret = rtw89_led_sc_init(rtwdev, desc);
+	else
+		ret = rtw89_led_mc_init(rtwdev, desc);
 
-	ret = rtw89_led_sc_init(rtwdev, desc);
 	if (ret)
 		return;
 
@@ -115,9 +127,13 @@ void rtw89_led_init(struct rtw89_dev *rtwdev)
 void rtw89_led_deinit(struct rtw89_dev *rtwdev)
 {
 	struct rtw89_led *rtw_led = &rtwdev->led;
+	const struct rtw89_led_desc *desc = rtw_led->desc;
 
 	if (!rtw_led->registered)
 		return;
 
-	rtw89_led_sc_deinit(rtwdev);
+	if (desc->n_gpio == 1)
+		rtw89_led_sc_deinit(rtwdev);
+	else
+		rtw89_led_mc_deinit(rtwdev);
 }
diff --git a/drivers/net/wireless/realtek/rtw89/led.h b/drivers/net/wireless/realtek/rtw89/led.h
index 27e782cff7c7..f5ccfe1d1752 100644
--- a/drivers/net/wireless/realtek/rtw89/led.h
+++ b/drivers/net/wireless/realtek/rtw89/led.h
@@ -21,4 +21,17 @@ static inline void rtw89_led_init(struct rtw89_dev *rtwdev) {}
 static inline void rtw89_led_deinit(struct rtw89_dev *rtwdev) {}
 #endif
 
+#ifdef CONFIG_RTW89_LEDS_MC
+int rtw89_led_mc_init(struct rtw89_dev *rtwdev, const struct rtw89_led_desc *desc);
+void rtw89_led_mc_deinit(struct rtw89_dev *rtwdev);
+#else
+static inline int rtw89_led_mc_init(struct rtw89_dev *rtwdev,
+				    const struct rtw89_led_desc *desc)
+{
+	return -EOPNOTSUPP;
+}
+
+static inline void rtw89_led_mc_deinit(struct rtw89_dev *rtwdev) {}
+#endif
+
 #endif
diff --git a/drivers/net/wireless/realtek/rtw89/led_mc.c b/drivers/net/wireless/realtek/rtw89/led_mc.c
new file mode 100644
index 000000000000..7e9243baef68
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw89/led_mc.c
@@ -0,0 +1,81 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/* Copyright(c) 2026 Realtek Corporation
+ */
+
+#include "core.h"
+#include "debug.h"
+#include "led.h"
+
+static int rtw89_led_mc_brightness_set(struct led_classdev *led,
+				       enum led_brightness brightness)
+{
+	struct led_classdev_mc *mcdev = lcdev_to_mccdev(led);
+	struct rtw89_led *rtw_led = container_of(mcdev, struct rtw89_led, led_mc);
+	struct rtw89_dev *rtwdev = container_of(rtw_led, struct rtw89_dev, led);
+	const struct rtw89_led_desc *desc = rtw_led->desc;
+	const struct rtw89_led_gpio_entry *e;
+	unsigned int i;
+
+	led_mc_calc_color_components(mcdev, brightness);
+
+	wiphy_lock(rtwdev->hw->wiphy);
+
+	for (i = 0; i < mcdev->num_colors; i++) {
+		e = &desc->gpios[i];
+		if (rtw_led->brightness_cache[i] == mcdev->subled_info[i].brightness) {
+			rtw89_debug(rtwdev, RTW89_DBG_LED,
+				    "led_mc_set: pin=%u skip (no change)\n", e->pin);
+			continue;
+		}
+
+		rtw89_debug(rtwdev, RTW89_DBG_LED, "led_mc_set: pin=%u brightness=%u\n",
+			    e->pin, mcdev->subled_info[i].brightness);
+		rtw89_led_gpio_set(rtwdev, e, mcdev->subled_info[i].brightness);
+		rtw_led->brightness_cache[i] = mcdev->subled_info[i].brightness;
+	}
+
+	wiphy_unlock(rtwdev->hw->wiphy);
+
+	return 0;
+}
+
+int rtw89_led_mc_init(struct rtw89_dev *rtwdev, const struct rtw89_led_desc *desc)
+{
+	struct rtw89_led *rtw_led = &rtwdev->led;
+	struct led_classdev_mc *led_mc = &rtw_led->led_mc;
+	int i, ret;
+
+	led_mc->num_colors = desc->n_gpio;
+	led_mc->subled_info = rtw_led->subled;
+
+	for (i = 0; i < desc->n_gpio; i++) {
+		const struct rtw89_led_gpio_entry *e = &desc->gpios[i];
+
+		rtw_led->subled[i].color_index = e->color;
+		rtw_led->subled[i].intensity = e->intensity;
+		rtw_led->subled[i].brightness = 0;
+		rtw_led->subled[i].channel = i;
+
+		rtw89_led_gpio_config(rtwdev, e);
+	}
+
+	snprintf(rtw_led->name, sizeof(rtw_led->name), "rtw89-%s-multicolor",
+		 wiphy_name(rtwdev->hw->wiphy));
+	led_mc->led_cdev.name = rtw_led->name;
+	led_mc->led_cdev.brightness_set_blocking = rtw89_led_mc_brightness_set;
+	led_mc->led_cdev.max_brightness = LED_ON;
+	led_mc->led_cdev.default_trigger = ieee80211_get_assoc_led_name(rtwdev->hw);
+
+	ret = led_classdev_multicolor_register(rtwdev->dev, led_mc);
+	if (ret)
+		rtw89_warn(rtwdev, "failed to register multicolor LED, ret=%d\n", ret);
+
+	return ret;
+}
+
+void rtw89_led_mc_deinit(struct rtw89_dev *rtwdev)
+{
+	struct rtw89_led *rtw_led = &rtwdev->led;
+
+	led_classdev_multicolor_unregister(&rtw_led->led_mc);
+}
diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h
index 3bf2865b81ab..053028b9ef16 100644
--- a/drivers/net/wireless/realtek/rtw89/reg.h
+++ b/drivers/net/wireless/realtek/rtw89/reg.h
@@ -205,6 +205,8 @@
 #define MAC_AX_HCI_SEL_PCIE_USB 3
 #define MAC_AX_HCI_SEL_MULTI_SDIO 4
 
+#define R_AX_GPIO_16_TO_18_EXT_CTRL 0x0150
+
 #define R_AX_HALT_H2C_CTRL 0x0160
 #define R_AX_HALT_H2C 0x0168
 #define B_AX_HALT_H2C_TRIGGER BIT(0)
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851be.c b/drivers/net/wireless/realtek/rtw89/rtw8851be.c
index 640672eb0d26..459d2e778b83 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8851be.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8851be.c
@@ -72,6 +72,7 @@ static const struct rtw89_pci_info rtw8851b_pci_info = {
 static const struct rtw89_driver_info rtw89_8851be_info = {
 	.chip = &rtw8851b_chip_info,
 	.variant = NULL,
+	.board = NULL,
 	.quirks = NULL,
 	.dev_id_quirks = 0,
 	.bus = {
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851bu.c b/drivers/net/wireless/realtek/rtw89/rtw8851bu.c
index 34ba5661d771..1e827205f254 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8851bu.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8851bu.c
@@ -30,6 +30,7 @@ static const struct rtw89_usb_info rtw8851b_usb_info = {
 static const struct rtw89_driver_info rtw89_8851bu_info = {
 	.chip = &rtw8851b_chip_info,
 	.variant = NULL,
+	.board = NULL,
 	.quirks = NULL,
 	.dev_id_quirks = 0,
 	.bus = {
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852ae.c b/drivers/net/wireless/realtek/rtw89/rtw8852ae.c
index 64306cdc1ee4..142a45a2e718 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852ae.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852ae.c
@@ -70,6 +70,7 @@ static const struct rtw89_pci_info rtw8852a_pci_info = {
 static const struct rtw89_driver_info rtw89_8852ae_info = {
 	.chip = &rtw8852a_chip_info,
 	.variant = NULL,
+	.board = NULL,
 	.quirks = NULL,
 	.dev_id_quirks = 0,
 	.bus = {
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852au.c b/drivers/net/wireless/realtek/rtw89/rtw8852au.c
index 29b7f7769370..065f4e5b17af 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852au.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852au.c
@@ -32,6 +32,7 @@ static const struct rtw89_usb_info rtw8852a_usb_info = {
 static const struct rtw89_driver_info rtw89_8852au_info = {
 	.chip = &rtw8852a_chip_info,
 	.variant = NULL,
+	.board = NULL,
 	.quirks = NULL,
 	.dev_id_quirks = 0,
 	.bus = {
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852be.c b/drivers/net/wireless/realtek/rtw89/rtw8852be.c
index 5bc0a6a99d1d..1c622a99c070 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852be.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852be.c
@@ -72,6 +72,7 @@ static const struct rtw89_pci_info rtw8852b_pci_info = {
 static const struct rtw89_driver_info rtw89_8852be_info = {
 	.chip = &rtw8852b_chip_info,
 	.variant = NULL,
+	.board = NULL,
 	.quirks = NULL,
 	.dev_id_quirks = 0,
 	.bus = {
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bte.c b/drivers/net/wireless/realtek/rtw89/rtw8852bte.c
index 49a72ca835ac..73c7ebd33ab4 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852bte.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852bte.c
@@ -78,6 +78,7 @@ static const struct rtw89_pci_info rtw8852bt_pci_info = {
 static const struct rtw89_driver_info rtw89_8852bte_info = {
 	.chip = &rtw8852bt_chip_info,
 	.variant = NULL,
+	.board = NULL,
 	.quirks = NULL,
 	.dev_id_quirks = 0,
 	.bus = {
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bu.c b/drivers/net/wireless/realtek/rtw89/rtw8852bu.c
index 308d3d570ff3..de79a19a2824 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852bu.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852bu.c
@@ -30,6 +30,7 @@ static const struct rtw89_usb_info rtw8852b_usb_info = {
 static const struct rtw89_driver_info rtw89_8852bu_info = {
 	.chip = &rtw8852b_chip_info,
 	.variant = NULL,
+	.board = NULL,
 	.quirks = NULL,
 	.dev_id_quirks = 0,
 	.bus = {
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852ce.c b/drivers/net/wireless/realtek/rtw89/rtw8852ce.c
index 3c64c0539205..bb5d5745aa62 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852ce.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852ce.c
@@ -101,6 +101,7 @@ static const struct dmi_system_id rtw8852c_pci_quirks[] = {
 static const struct rtw89_driver_info rtw89_8852ce_info = {
 	.chip = &rtw8852c_chip_info,
 	.variant = NULL,
+	.board = NULL,
 	.quirks = rtw8852c_pci_quirks,
 	.dev_id_quirks = 0,
 	.bus = {
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852cu.c b/drivers/net/wireless/realtek/rtw89/rtw8852cu.c
index 81ee96b0a048..51dd8fb05366 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852cu.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852cu.c
@@ -32,6 +32,7 @@ static const struct rtw89_usb_info rtw8852c_usb_info = {
 static const struct rtw89_driver_info rtw89_8852cu_info = {
 	.chip = &rtw8852c_chip_info,
 	.variant = NULL,
+	.board = NULL,
 	.quirks = NULL,
 	.dev_id_quirks = 0,
 	.bus = {
@@ -39,9 +40,62 @@ static const struct rtw89_driver_info rtw89_8852cu_info = {
 	},
 };
 
+static const struct rtw89_led_gpio_entry rtw8852cu_valve_led_gpios[] = {
+	{
+		.pin = 8,
+		.color = LED_COLOR_ID_WHITE,
+		.intensity = 0,
+		.pinmux = {.addr = R_AX_GPIO8_15_FUNC_SEL,
+			   .mask = GENMASK(3, 0),
+			   .data = 0xf},
+		.mode = {.addr = R_AX_GPIO_EXT_CTRL + 2, .data = BIT(0) | BIT(8)},
+		.out = {.addr = R_AX_GPIO_EXT_CTRL + 1, .data = BIT(0)},
+	}, {
+		.pin = 18,
+		.color = LED_COLOR_ID_RED,
+		.intensity = 0,
+		.pinmux = {.addr = R_AX_GPIO16_23_FUNC_SEL,
+			   .mask = GENMASK(11, 8),
+			   .data = 0xf},
+		.mode = {.addr = R_AX_GPIO_16_TO_18_EXT_CTRL + 2,
+			 .data = BIT(2) | BIT(10)},
+		.out = {.addr = R_AX_GPIO_16_TO_18_EXT_CTRL + 1, .data = BIT(2)},
+	}, {
+		.pin = 16,
+		.color = LED_COLOR_ID_GREEN,
+		.intensity = 1,
+		.pinmux = {.addr = R_AX_GPIO16_23_FUNC_SEL,
+			   .mask = GENMASK(3, 0),
+			   .data = 0xf},
+		.mode = {.addr = R_AX_GPIO_16_TO_18_EXT_CTRL + 2,
+			 .data = BIT(0) | BIT(8)},
+		.out = {.addr = R_AX_GPIO_16_TO_18_EXT_CTRL + 1, .data = BIT(0)},
+	}, {
+		.pin = 17,
+		.color = LED_COLOR_ID_BLUE,
+		.intensity = 0,
+		.pinmux = {.addr = R_AX_GPIO16_23_FUNC_SEL,
+			   .mask = GENMASK(7, 4),
+			   .data = 0xf},
+		.mode = {.addr = R_AX_GPIO_16_TO_18_EXT_CTRL + 2,
+			 .data = BIT(1) | BIT(9)},
+		.out = {.addr = R_AX_GPIO_16_TO_18_EXT_CTRL + 1, .data = BIT(1)},
+	},
+};
+
+static const struct rtw89_led_desc rtw8852cu_valve_led_desc = {
+	.gpios = rtw8852cu_valve_led_gpios,
+	.n_gpio = ARRAY_SIZE(rtw8852cu_valve_led_gpios),
+};
+
+static const struct rtw89_board_variant rtw89_8852cu_valve_board = {
+	.led_desc = &rtw8852cu_valve_led_desc,
+};
+
 static const struct rtw89_driver_info rtw89_8852cu_valve_info = {
 	.chip = &rtw8852c_chip_info,
 	.variant = NULL,
+	.board = &rtw89_8852cu_valve_board,
 	.quirks = NULL,
 	.dev_id_quirks = BIT(RTW89_QUIRK_HW_INFO_SYSFS),
 	.bus = {
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922ae.c b/drivers/net/wireless/realtek/rtw89/rtw8922ae.c
index 5527a8db393b..8f3a1cd463d9 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922ae.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922ae.c
@@ -76,6 +76,7 @@ static const struct rtw89_pci_info rtw8922a_pci_info = {
 static const struct rtw89_driver_info rtw89_8922ae_info = {
 	.chip = &rtw8922a_chip_info,
 	.variant = NULL,
+	.board = NULL,
 	.quirks = NULL,
 	.dev_id_quirks = 0,
 	.bus = {
@@ -86,6 +87,7 @@ static const struct rtw89_driver_info rtw89_8922ae_info = {
 static const struct rtw89_driver_info rtw89_8922ae_vs_info = {
 	.chip = &rtw8922a_chip_info,
 	.variant = &rtw8922ae_vs_variant,
+	.board = NULL,
 	.quirks = NULL,
 	.dev_id_quirks = 0,
 	.bus = {
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922au.c b/drivers/net/wireless/realtek/rtw89/rtw8922au.c
index 2b81de501d62..56c79b1ec865 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922au.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922au.c
@@ -31,6 +31,7 @@ static const struct rtw89_usb_info rtw8922a_usb_info = {
 static const struct rtw89_driver_info rtw89_8922au_info = {
 	.chip = &rtw8922a_chip_info,
 	.variant = NULL,
+	.board = NULL,
 	.quirks = NULL,
 	.dev_id_quirks = 0,
 	.bus = {
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922de.c b/drivers/net/wireless/realtek/rtw89/rtw8922de.c
index a1a81c338be3..09400a0efcfd 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922de.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922de.c
@@ -72,6 +72,7 @@ static const struct rtw89_pci_info rtw8922d_pci_info = {
 static const struct rtw89_driver_info rtw89_8922de_vs_info = {
 	.chip = &rtw8922d_chip_info,
 	.variant = &rtw8922de_vs_variant,
+	.board = NULL,
 	.quirks = NULL,
 	.dev_id_quirks = 0,
 	.bus = {
@@ -82,6 +83,7 @@ static const struct rtw89_driver_info rtw89_8922de_vs_info = {
 static const struct rtw89_driver_info rtw89_8922de_info = {
 	.chip = &rtw8922d_chip_info,
 	.variant = NULL,
+	.board = NULL,
 	.quirks = NULL,
 	.dev_id_quirks = 0,
 	.bus = {
-- 
2.25.1


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox