mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Bitterblue Smith <rtl8821cerfe2@gmail.com>
To: Luka Gejak <luka.gejak@linux.dev>, Ping-Ke Shih <pkshih@realtek.com>
Cc: linux-wireless@vger.kernel.org, linux-kernel@vger.kernel.org,
	Michael Straube <straube.linux@gmail.com>,
	Peter Robinson <pbrobinson@gmail.com>
Subject: Re: [PATCH v4 3/6] wifi: rtw88: 8723b: add the RTL8723B chip driver
Date: Sun, 27 Sep 2026 18:21:32 +0300	[thread overview]
Message-ID: <6ad11268-9f09-4618-8b44-ab0744cf0a52@gmail.com> (raw)
In-Reply-To: <20260923213557.186205-4-luka.gejak@linux.dev>

On 24/09/2026 00:35, Luka Gejak wrote:
> Add the Realtek RTL8723B 802.11n chip driver: the chip operations, the
> power sequences, the efuse layout, the RF and IQ calibration, and the
> chip specific coexistence handling.
> 
> The RTL8723B chip support is based on the initial work by
> Michael Straube <straube.linux@gmail.com>.
> Link: https://github.com/mistraube/rtw88/tree/rtl8723bs
> 
> Co-developed-by: Michael Straube <straube.linux@gmail.com>
> Signed-off-by: Michael Straube <straube.linux@gmail.com>
> Signed-off-by: Luka Gejak <luka.gejak@linux.dev>
> ---
>  drivers/net/wireless/realtek/rtw88/rtw8723b.c | 2831 +++++++++++++++++
>  drivers/net/wireless/realtek/rtw88/rtw8723b.h |   13 +
>  2 files changed, 2844 insertions(+)
>  create mode 100644 drivers/net/wireless/realtek/rtw88/rtw8723b.c
>  create mode 100644 drivers/net/wireless/realtek/rtw88/rtw8723b.h
> 
> diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723b.c b/drivers/net/wireless/realtek/rtw88/rtw8723b.c
> new file mode 100644
> index 000000000000..a26908bdc989
> --- /dev/null
> +++ b/drivers/net/wireless/realtek/rtw88/rtw8723b.c
> @@ -0,0 +1,2831 @@
> +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
> +/*
> + * Copyright(c) 2026 Realtek Corporation
> + * Copyright(c) Michael Straube <straube.linux@gmail.com>
> + * Copyright(c) 2024-2026 Luka Gejak <luka.gejak@linux.dev>
> + */
> +
> +#include <linux/unaligned.h>
> +#include "main.h"
> +#include "coex.h"
> +#include "fw.h"
> +#include "mac.h"
> +#include "phy.h"
> +/*
> + * Shares the receive PHY status layout, the SDIO aggregation burst fields
> + * and a few baseband registers with the RTL8703B; reuse that header.
> + */
> +#include "rtw8703b.h"
> +#include "rtw8723b.h"
> +#include "rtw8723b_table.h"
> +#include "sdio.h"
> +#include "tx.h"
> +
> +#define TRANS_SEQ_END			\
> +	0xFFFF,				\
> +	RTW_PWR_CUT_ALL_MSK,		\
> +	RTW_PWR_INTF_ALL_MSK,		\
> +	0,				\
> +	RTW_PWR_CMD_END, 0, 0
> +
> +#define TBTT_PROHIBIT_SETUP_TIME		0x04
> +#define TBTT_PROHIBIT_HOLD_TIME_STOP_BCN	0x64
> +#define WLAN_BCN_DMA_TIME			0x02
> +#define WLAN_BAR_VAL				0x0201ffff
> +#define WLAN_SLOT_TIME				0x09
> +#define WLAN_SYS_FUNC_BB_ENABLE			(BIT_FEN_BB_GLB_RST | \
> +						 BIT_FEN_BB_RSTB)
> +#define WLAN_RF_CTRL_ENABLE			(BIT_RF_EN | BIT_RF_RSTB | \
> +						 BIT_RF_SDM_RSTB)
> +/*
> + * 0x03a05611 is the normal RX path (staging and the BB table agree);
> + * 0x03a05600 is only an IQK temporary value and must not be reasserted.
> + */
> +#define WLAN_RX_PATH_A_8723B			0x03a05611
> +
> +#define ADDA_ON_VAL_8723B			0x01c00014
> +
> +#define WLAN_RX_FILTER0			0xFFFF
> +#define WLAN_RX_FILTER1			0x400
> +#define WLAN_RX_FILTER2			0xFFFF
> +/*
> + * Keep BIT_APP_FCS: rtw88 advertises RX_INCLUDES_FCS for every chip, and
> + * without it mac80211 trims four bytes of real frame data.
> + */
> +#define WLAN_RCR_CFG			(BIT_APM | BIT_AM | BIT_AB | \
> +					 BIT_CBSSID_DATA | BIT_CBSSID_BCN | \
> +					 BIT_AMF | BIT_HTC_LOC_CTRL | \
> +					 BIT_APP_PHYSTS | BIT_APP_ICV | \
> +					 BIT_APP_MIC | BIT_APP_FCS)
> +
> +/*
> + * BIT(7) lets the 8051 control antenna selection, BIT(1) is LED2_CM.
> + */
> +#define WLAN_ANT_SEL			(BIT(7) | BIT(1))
> +
> +#define IQK_DELAY_TIME_8723B		20
> +
> +#define BCNQ_PAGE_NUM_8723B	0x08
> +#define BCNQ1_PAGE_NUM_8723B		0x00
> +#define WOWLAN_PAGE_NUM_8723B		0x00
> +#define TX_TOTAL_PAGE_NUMBER_8723B\
> +	(0xFF - BCNQ_PAGE_NUM_8723B - BCNQ1_PAGE_NUM_8723B - \
> +	 WOWLAN_PAGE_NUM_8723B)
> +
> +/* rssi in percent (dbm = % - 100); the values are the vendor driver's. */
> +static const u8 wl_rssi_step_8723b[] = {60, 50, 44, 30};
> +static const u8 bt_rssi_step_8723b[] = {30, 30, 30, 30};
> +static const struct coex_5g_afh_map afh_5g_8723b[] = { {0, 0, 0} };
> +
> +static const struct coex_rf_para rf_para_tx_8723b[] = {
> +	{0, 0, false, 7},  /* for normal */
> +	{0, 10, false, 7}, /* for WL-CPT */
> +	{1, 0, true, 4},
> +	{1, 2, true, 4},
> +	{1, 10, true, 4},
> +	{1, 15, true, 4}
> +};
> +
> +static const struct coex_rf_para rf_para_rx_8723b[] = {
> +	{0, 0, false, 7},  /* for normal */
> +	{0, 10, false, 7}, /* for WL-CPT */
> +	{1, 0, true, 5},
> +	{1, 2, true, 5},
> +	{1, 10, true, 5},
> +	{1, 15, true, 5}
> +};
> +
> +static_assert(ARRAY_SIZE(rf_para_tx_8723b) == ARRAY_SIZE(rf_para_rx_8723b));
> +
> +static const u32 rtw8723b_ofdm_swing_table[] = {
> +	0x0b40002d, /* 0, -15.0dB */
> +	0x0c000030, /* 1, -14.5dB */
> +	0x0cc00033, /* 2, -14.0dB */
> +	0x0d800036, /* 3, -13.5dB */
> +	0x0e400039, /* 4, -13.0dB */
> +	0x0f00003c, /* 5, -12.5dB */
> +	0x10000040, /* 6, -12.0dB */
> +	0x11000044, /* 7, -11.5dB */
> +	0x12000048, /* 8, -11.0dB */
> +	0x1300004c, /* 9, -10.5dB */
> +	0x14400051, /* 10, -10.0dB */
> +	0x15800056, /* 11, -9.5dB */
> +	0x16c0005b, /* 12, -9.0dB */
> +	0x18000060, /* 13, -8.5dB */
> +	0x19800066, /* 14, -8.0dB */
> +	0x1b00006c, /* 15, -7.5dB */
> +	0x1c800072, /* 16, -7.0dB */
> +	0x1e400079, /* 17, -6.5dB */
> +	0x20000080, /* 18, -6.0dB */
> +	0x22000088, /* 19, -5.5dB */
> +	0x24000090, /* 20, -5.0dB */
> +	0x26000098, /* 21, -4.5dB */
> +	0x288000a2, /* 22, -4.0dB */
> +	0x2ac000ab, /* 23, -3.5dB */
> +	0x2d4000b5, /* 24, -3.0dB */
> +	0x300000c0, /* 25, -2.5dB */
> +	0x32c000cb, /* 26, -2.0dB */
> +	0x35c000d7, /* 27, -1.5dB */
> +	0x390000e4, /* 28, -1.0dB */
> +	0x3c8000f2, /* 29, -0.5dB */
> +	0x40000100, /* 30, +0dB */
> +	0x43c0010f, /* 31, +0.5dB */
> +	0x47c0011f, /* 32, +1.0dB */
> +	0x4c000130, /* 33, +1.5dB */
> +	0x50800142, /* 34, +2.0dB */
> +	0x55400155, /* 35, +2.5dB */
> +	0x5a400169, /* 36, +3.0dB */
> +	0x5fc0017f, /* 37, +3.5dB */
> +	0x65400195, /* 38, +4.0dB */
> +	0x6b8001ae, /* 39, +4.5dB */
> +	0x71c001c7, /* 40, +5.0dB */
> +	0x788001e2, /* 41, +5.5dB */
> +	0x7f8001fe, /* 42, +6.0dB */
> +};
> +
> +static const u32 rtw8723b_cck_pwr_regs[] = {
> +	0x0a22, 0x0a23, 0x0a24, 0x0a25, 0x0a26, 0x0a27, 0x0a28, 0x0a29,
> +};
> +
> +/*
> + * Row 20 (-6.0 dB) intentionally does not match the v5.2.17 vendor driver,
> + * which has 0x1c, 0x1a, 0x18, 0x12, 0x0e, 0x08 there. Every other row agrees.
> + * The values below are what rtl8723be, the mainline driver for this same
> + * chip, uses at the same index, and they are also what the vendor's own
> + * cck_swing_table_ch1_ch13_92e and the staging rtl8723bs driver use. They
> + * also track the 0.5 dB step of the surrounding rows: against row 32 as 0 dB,
> + * 0x1b is within 0.06 of the ideal -6.0 dB value while 0x1c is 0.94 away,
> + * the largest error anywhere in the table. Treat the vendor row as the
> + * anomaly and do not "fix" this towards it.
> + */
> +static const u8 rtw8723b_cck_swing_table_ch1_ch13[][8] = {
> +	{0x09, 0x08, 0x07, 0x06, 0x04, 0x03, 0x01, 0x01},	/* 0, -16.0dB */
> +	{0x09, 0x09, 0x08, 0x06, 0x05, 0x03, 0x01, 0x01},	/* 1, -15.5dB */
> +	{0x0a, 0x09, 0x08, 0x07, 0x05, 0x03, 0x02, 0x01},	/* 2, -15.0dB */
> +	{0x0a, 0x0a, 0x09, 0x07, 0x05, 0x03, 0x02, 0x01},	/* 3, -14.5dB */
> +	{0x0b, 0x0a, 0x09, 0x08, 0x06, 0x04, 0x02, 0x01},	/* 4, -14.0dB */
> +	{0x0b, 0x0b, 0x0a, 0x08, 0x06, 0x04, 0x02, 0x01},	/* 5, -13.5dB */
> +	{0x0c, 0x0c, 0x0a, 0x09, 0x06, 0x04, 0x02, 0x01},	/* 6, -13.0dB */
> +	{0x0d, 0x0c, 0x0b, 0x09, 0x07, 0x04, 0x02, 0x01},	/* 7, -12.5dB */
> +	{0x0d, 0x0d, 0x0c, 0x0a, 0x07, 0x05, 0x02, 0x01},	/* 8, -12.0dB */
> +	{0x0e, 0x0e, 0x0c, 0x0a, 0x08, 0x05, 0x02, 0x01},	/* 9, -11.5dB */
> +	{0x0f, 0x0f, 0x0d, 0x0b, 0x08, 0x05, 0x03, 0x01},	/* 10, -11.0dB */
> +	{0x10, 0x10, 0x0e, 0x0b, 0x08, 0x05, 0x03, 0x01},	/* 11, -10.5dB */
> +	{0x11, 0x11, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01},	/* 12, -10.0dB */
> +	{0x12, 0x12, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01},	/* 13, -9.5dB */
> +	{0x13, 0x13, 0x10, 0x0d, 0x0a, 0x06, 0x03, 0x01},	/* 14, -9.0dB */
> +	{0x14, 0x14, 0x11, 0x0e, 0x0b, 0x07, 0x03, 0x02},	/* 15, -8.5dB */
> +	{0x16, 0x15, 0x12, 0x0f, 0x0b, 0x07, 0x04, 0x01},	/* 16, -8.0dB */
> +	{0x17, 0x16, 0x13, 0x10, 0x0c, 0x08, 0x04, 0x02},	/* 17, -7.5dB */
> +	{0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02},	/* 18, -7.0dB */
> +	{0x1a, 0x19, 0x16, 0x12, 0x0d, 0x09, 0x04, 0x02},	/* 19, -6.5dB */
> +	{0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02},	/* 20, -6.0dB */
> +	{0x1d, 0x1c, 0x18, 0x14, 0x0f, 0x0a, 0x05, 0x02},	/* 21, -5.5dB */
> +	{0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02},	/* 22, -5.0dB */
> +	{0x20, 0x20, 0x1b, 0x16, 0x11, 0x08, 0x05, 0x02},	/* 23, -4.5dB */
> +	{0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02},	/* 24, -4.0dB */
> +	{0x24, 0x23, 0x1f, 0x19, 0x13, 0x0c, 0x06, 0x03},	/* 25, -3.5dB */
> +	{0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03},	/* 26, -3.0dB */
> +	{0x28, 0x28, 0x22, 0x1c, 0x15, 0x0d, 0x07, 0x03},	/* 27, -2.5dB */
> +	{0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03},	/* 28, -2.0dB */
> +	{0x2d, 0x2d, 0x27, 0x1f, 0x18, 0x0f, 0x08, 0x03},	/* 29, -1.5dB */
> +	{0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03},	/* 30, -1.0dB */
> +	{0x33, 0x32, 0x2b, 0x23, 0x1a, 0x11, 0x08, 0x04},	/* 31, -0.5dB */
> +	{0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04},	/* 32, +0dB */
> +};
> +
> +static const u8 rtw8723b_cck_swing_table_ch14[][8] = {
> +	{0x09, 0x08, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00},	/* 0, -16.0dB */
> +	{0x09, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00},	/* 1, -15.5dB */
> +	{0x0a, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00},	/* 2, -15.0dB */
> +	{0x0a, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00},	/* 3, -14.5dB */
> +	{0x0b, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00},	/* 4, -14.0dB */
> +	{0x0b, 0x0b, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00},	/* 5, -13.5dB */
> +	{0x0c, 0x0c, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00},	/* 6, -13.0dB */
> +	{0x0d, 0x0c, 0x0b, 0x06, 0x00, 0x00, 0x00, 0x00},	/* 7, -12.5dB */
> +	{0x0d, 0x0d, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00},	/* 8, -12.0dB */
> +	{0x0e, 0x0e, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00},	/* 9, -11.5dB */
> +	{0x0f, 0x0f, 0x0d, 0x08, 0x00, 0x00, 0x00, 0x00},	/* 10, -11.0dB */
> +	{0x10, 0x10, 0x0e, 0x08, 0x00, 0x00, 0x00, 0x00},	/* 11, -10.5dB */
> +	{0x11, 0x11, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00},	/* 12, -10.0dB */
> +	{0x12, 0x12, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00},	/* 13, -9.5dB */
> +	{0x13, 0x13, 0x10, 0x0a, 0x00, 0x00, 0x00, 0x00},	/* 14, -9.0dB */
> +	{0x14, 0x14, 0x11, 0x0a, 0x00, 0x00, 0x00, 0x00},	/* 15, -8.5dB */
> +	{0x16, 0x15, 0x12, 0x0b, 0x00, 0x00, 0x00, 0x00},	/* 16, -8.0dB */
> +	{0x17, 0x16, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x00},	/* 17, -7.5dB */
> +	{0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00},	/* 18, -7.0dB */
> +	{0x1a, 0x19, 0x16, 0x0d, 0x00, 0x00, 0x00, 0x00},	/* 19, -6.5dB */
> +	{0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00},	/* 20, -6.0dB */
> +	{0x1d, 0x1c, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00},	/* 21, -5.5dB */
> +	{0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00},	/* 22, -5.0dB */
> +	{0x20, 0x20, 0x1b, 0x10, 0x00, 0x00, 0x00, 0x00},	/* 23, -4.5dB */
> +	{0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00},	/* 24, -4.0dB */
> +	{0x24, 0x23, 0x1f, 0x12, 0x00, 0x00, 0x00, 0x00},	/* 25, -3.5dB */
> +	{0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00},	/* 26, -3.0dB */
> +	{0x28, 0x28, 0x24, 0x14, 0x00, 0x00, 0x00, 0x00},	/* 27, -2.5dB */
> +	{0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00},	/* 28, -2.0dB */
> +	{0x2d, 0x2d, 0x17, 0x17, 0x00, 0x00, 0x00, 0x00},	/* 29, -1.5dB */
> +	{0x30, 0x2f, 0x29, 0x18, 0x00, 0x00, 0x00, 0x00},	/* 30, -1.0dB */
> +	{0x33, 0x32, 0x2b, 0x19, 0x00, 0x00, 0x00, 0x00},	/* 31, -0.5dB */
> +	{0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00},	/* 32, +0dB */
> +};
> +
> +static_assert(ARRAY_SIZE(rtw8723b_cck_swing_table_ch1_ch13) ==
> +	      ARRAY_SIZE(rtw8723b_cck_swing_table_ch14));
> +
> +#define RTW_OFDM_SWING_TABLE_SIZE	ARRAY_SIZE(rtw8723b_ofdm_swing_table)
> +#define RTW_CCK_SWING_TABLE_SIZE	ARRAY_SIZE(rtw8723b_cck_swing_table_ch14)
> +
> +/*
> + * Swing index field of REG_OFDM_0_XA_TX_IQ_IMBALANCE; the table entries
> + * below hold the full register value, hence the shift by __ffs().
> + */
> +#define OFDM_SWING_MASK			GENMASK(31, 22)
> +
> +static const struct rtw_pwr_seq_cmd trans_pre_enable_8723b[] = {
> +	/* unlock ISO/CLK/power control register */
> +	{REG_RSV_CTRL,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_ALL_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_WRITE, 0xff, 0},
> +	{TRANS_SEQ_END},
> +};
> +
> +static const struct rtw_pwr_seq_cmd trans_carddis_to_cardemu_8723b[] = {
> +	{0x0005,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_ALL_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_WRITE, BIT(3) | BIT(7), 0},
> +	{0x0086,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_SDIO_MSK,
> +	 RTW_PWR_ADDR_SDIO,
> +	 RTW_PWR_CMD_WRITE, BIT(0), 0},
> +	{0x0086,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_SDIO_MSK,
> +	 RTW_PWR_ADDR_SDIO,
> +	 RTW_PWR_CMD_POLLING, BIT(1), BIT(1)},
> +	{0x004A,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_USB_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_WRITE, BIT(0), 0},
> +	{0x0005,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_ALL_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_WRITE, BIT(3) | BIT(4), 0},
> +	{0x0023,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_SDIO_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_WRITE, BIT(4), 0},
> +	{0x0301,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_PCI_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_WRITE, 0xFF, 0},
> +	{TRANS_SEQ_END},
> +};
> +
> +static const struct rtw_pwr_seq_cmd trans_cardemu_to_act_8723b[] = {
> +	{0x0020,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_USB_MSK | RTW_PWR_INTF_SDIO_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_WRITE, BIT(0), BIT(0)},
> +	{0x0067,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_USB_MSK | RTW_PWR_INTF_SDIO_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_WRITE, BIT(4), 0},
> +	{0x0001,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_USB_MSK | RTW_PWR_INTF_SDIO_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_DELAY, 1, RTW_PWR_DELAY_MS},
> +	{0x0000,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_USB_MSK | RTW_PWR_INTF_SDIO_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_WRITE, BIT(5), 0},
> +	{0x0005,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_ALL_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_WRITE, (BIT(4) | BIT(3) | BIT(2)), 0},
> +	{0x0075,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_PCI_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_WRITE, BIT(0), BIT(0)},
> +	{0x0006,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_ALL_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_POLLING, BIT(1), BIT(1)},
> +	{0x0075,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_PCI_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_WRITE, BIT(0), 0},
> +	{0x0006,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_ALL_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_WRITE, BIT(0), BIT(0)},
> +	{0x0005,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_ALL_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_WRITE, BIT(7), 0},
> +	{0x0005,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_ALL_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_WRITE, BIT(4) | BIT(3), 0},
> +	{0x0005,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_ALL_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_WRITE, BIT(0), BIT(0)},
> +	{0x0005,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_ALL_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_POLLING, BIT(0), 0},
> +	{0x0010,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_ALL_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_WRITE, BIT(6), BIT(6)},
> +	{0x0049,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_ALL_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_WRITE, BIT(1), BIT(1)},
> +	{0x0063,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_ALL_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_WRITE, BIT(1), BIT(1)},
> +	{0x0062,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_ALL_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_WRITE, BIT(1), 0},
> +	{0x0058,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_ALL_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_WRITE, BIT(0), BIT(0)},
> +	{0x005A,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_ALL_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_WRITE, BIT(1), BIT(1)},
> +	{0x0068,
> +	 RTW_PWR_CUT_TEST_MSK,
> +	 RTW_PWR_INTF_ALL_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_WRITE, BIT(3), BIT(3)},
> +	{0x0069,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_ALL_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_WRITE, BIT(6), BIT(6)},
> +	 {TRANS_SEQ_END},
> +};
> +
> +static const struct rtw_pwr_seq_cmd trans_act_to_lps_8723b[] = {
> +	{0x0301,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_PCI_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_WRITE, 0xFF, 0xFF},
> +	{0x0522,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_ALL_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_WRITE, 0xFF, 0xFF},
> +	{0x05F8,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_ALL_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_POLLING, 0xFF, 0},
> +	{0x05F9,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_ALL_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_POLLING, 0xFF, 0},
> +	{0x05FA,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_ALL_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_POLLING, 0xFF, 0},
> +	{0x05FB,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_ALL_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_POLLING, 0xFF, 0},
> +	{0x0002,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_ALL_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_WRITE, BIT(0), 0},
> +	{0x0002,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_ALL_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_DELAY, 0, RTW_PWR_DELAY_US},
> +	{0x0002,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_ALL_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_WRITE, BIT(1), 0},
> +	{0x0100,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_ALL_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_WRITE, 0xFF, 0x03},
> +	{0x0101,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_ALL_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_WRITE, BIT(1), 0},
> +	{0x0093,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_SDIO_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_WRITE, 0xFF, 0x00},
> +	{0x0553,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_ALL_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_WRITE, BIT(5), BIT(5)},
> +	{TRANS_SEQ_END},
> +};
> +
> +static const struct rtw_pwr_seq_cmd trans_act_to_reset_mcu_8723b[] = {
> +	{REG_SYS_FUNC_EN + 1,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_SDIO_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_WRITE, BIT_FEN_CPUEN, 0},
> +	/* reset MCU ready */
> +	{REG_MCUFW_CTRL,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_SDIO_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_WRITE, 0xff, 0},
> +	/* reset MCU IO wrapper */
> +	{REG_RSV_CTRL + 1,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_SDIO_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_WRITE, BIT(0), 0},
> +	{REG_RSV_CTRL + 1,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_SDIO_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_WRITE, BIT(0), 1},
> +	{TRANS_SEQ_END},
> +};
> +
> +static const struct rtw_pwr_seq_cmd trans_act_to_cardemu_8723b[] = {
> +	{0x001F,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_ALL_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_WRITE, 0xFF, 0},
> +	{0x0049,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_ALL_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_WRITE, BIT(1), 0},
> +	{0x0006,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_ALL_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_WRITE, BIT(0), BIT(0)},
> +	{0x0005,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_ALL_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_WRITE, BIT(1), BIT(1)},
> +	{0x0005,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_ALL_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_POLLING, BIT(1), 0},
> +	{0x0010,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_ALL_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_WRITE, BIT(6), 0},
> +	{0x0000,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_USB_MSK | RTW_PWR_INTF_SDIO_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_WRITE, BIT(5), BIT(5)},
> +	{0x0020,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_USB_MSK | RTW_PWR_INTF_SDIO_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_WRITE, BIT(0), 0},
> +	{TRANS_SEQ_END},
> +};
> +
> +static const struct rtw_pwr_seq_cmd trans_cardemu_to_carddis_8723b[] = {
> +	{0x0007,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_SDIO_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_WRITE, 0xFF, 0x20},
> +	{0x0005,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_USB_MSK | RTW_PWR_INTF_SDIO_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_WRITE, BIT(3) | BIT(4), BIT(3)},
> +	{0x0005,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_PCI_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_WRITE, BIT(2), BIT(2)},
> +	{0x004A,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_USB_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_WRITE, BIT(0), 1},
> +	{0x0023,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_SDIO_MSK,
> +	 RTW_PWR_ADDR_MAC,
> +	 RTW_PWR_CMD_WRITE, BIT(4), BIT(4)},
> +	{0x0086,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_SDIO_MSK,
> +	 RTW_PWR_ADDR_SDIO,
> +	 RTW_PWR_CMD_WRITE, BIT(0), BIT(0)},
> +	{0x0086,
> +	 RTW_PWR_CUT_ALL_MSK,
> +	 RTW_PWR_INTF_SDIO_MSK,
> +	 RTW_PWR_ADDR_SDIO,
> +	 RTW_PWR_CMD_POLLING, BIT(1), 0},
> +	{TRANS_SEQ_END},
> +};
> +
> +static const struct rtw_pwr_seq_cmd * const card_enable_flow_8723b[] = {
> +	trans_pre_enable_8723b,
> +	trans_carddis_to_cardemu_8723b,
> +	trans_cardemu_to_act_8723b,
> +	NULL
> +};
> +
> +static const struct rtw_pwr_seq_cmd * const card_disable_flow_8723b[] = {
> +	trans_act_to_lps_8723b,
> +	trans_act_to_reset_mcu_8723b,
> +	trans_act_to_cardemu_8723b,
> +	trans_cardemu_to_carddis_8723b,
> +	NULL
> +};
> +
> +static const struct rtw_page_table page_table_8723b[] = {
> +	{12, 2, 2, 0, 1}, /* SDIO */
> +	{12, 2, 2, 0, 1},
> +	{12, 2, 2, 0, 1},
> +	{12, 2, 2, 0, 1},
> +	{12, 2, 2, 0, 1},
> +};
> +
> +static const struct rtw_rqpn rqpn_table_8723b[] = {
> +	/* SDIO maps VO, MGMT and HI to the high queue. */
> +	{RTW_DMA_MAPPING_HIGH, RTW_DMA_MAPPING_NORMAL,
> +	 RTW_DMA_MAPPING_LOW, RTW_DMA_MAPPING_LOW,
> +	 RTW_DMA_MAPPING_HIGH, RTW_DMA_MAPPING_HIGH},
> +	/* PCIE */
> +	{RTW_DMA_MAPPING_NORMAL, RTW_DMA_MAPPING_NORMAL,
> +	 RTW_DMA_MAPPING_LOW, RTW_DMA_MAPPING_LOW,
> +	 RTW_DMA_MAPPING_HIGH, RTW_DMA_MAPPING_HIGH},
> +	/* USB bulkout 2 */
> +	{RTW_DMA_MAPPING_NORMAL, RTW_DMA_MAPPING_NORMAL,
> +	 RTW_DMA_MAPPING_NORMAL, RTW_DMA_MAPPING_HIGH,
> +	 RTW_DMA_MAPPING_HIGH, RTW_DMA_MAPPING_HIGH},
> +	/* USB bulkout 3 */
> +	{RTW_DMA_MAPPING_NORMAL, RTW_DMA_MAPPING_NORMAL,
> +	 RTW_DMA_MAPPING_LOW, RTW_DMA_MAPPING_LOW,
> +	 RTW_DMA_MAPPING_HIGH, RTW_DMA_MAPPING_HIGH},
> +	/* USB bulkout 4 */
> +	{RTW_DMA_MAPPING_NORMAL, RTW_DMA_MAPPING_NORMAL,
> +	 RTW_DMA_MAPPING_LOW, RTW_DMA_MAPPING_LOW,
> +	 RTW_DMA_MAPPING_HIGH, RTW_DMA_MAPPING_HIGH},
> +};
> +
> +static const u8 rtw8723b_pwrtrk_2gb_n[] = {
> +	0, 0, 1, 2, 2, 2, 3, 3, 3, 4, 5, 5, 6, 6, 6, 6,
> +	7, 7, 7, 8, 8, 9, 9, 10, 10, 11, 12, 13, 14, 15
> +};
> +
> +static const u8 rtw8723b_pwrtrk_2gb_p[] = {
> +	0, 0, 1, 2, 2, 3, 3, 4, 5, 5, 6, 6, 7, 7, 8, 8,
> +	9, 9, 10, 10, 10, 11, 11, 12, 12, 13, 13, 14, 15, 15
> +};
> +
> +static const u8 rtw8723b_pwrtrk_2ga_n[] = {
> +	0, 0, 1, 2, 2, 2, 3, 3, 3, 4, 5, 5, 6, 6, 6, 6,
> +	7, 7, 7, 8, 8, 9, 9, 10, 10, 11, 12, 13, 14, 15
> +};
> +
> +static const u8 rtw8723b_pwrtrk_2ga_p[] = {
> +	0, 0, 1, 2, 2, 3, 3, 4, 5, 5, 6, 6, 7, 7, 8, 8,
> +	9, 9, 10, 10, 10, 11, 11, 12, 12, 13, 13, 14, 15, 15
> +};
> +
> +static const u8 rtw8723b_pwrtrk_2g_cck_b_n[] = {
> +	0, 0, 1, 2, 2, 3, 3, 4, 4, 5, 6, 6, 7, 7, 7, 8,
> +	8, 8, 9, 9, 9, 10, 10, 11, 11, 12, 12, 13, 14, 15
> +};
> +
> +static const u8 rtw8723b_pwrtrk_2g_cck_b_p[] = {
> +	0, 0, 1, 2, 2, 2, 3, 3, 3, 4, 5, 5, 6, 6, 7, 7,
> +	8, 8, 9, 9, 9, 10, 10, 11, 11, 12, 12, 13, 14, 15
> +};
> +
> +static const u8 rtw8723b_pwrtrk_2g_cck_a_n[] = {
> +	0, 0, 1, 2, 2, 3, 3, 4, 4, 5, 6, 6, 7, 7, 7, 8,
> +	8, 8, 9, 9, 9, 10, 10, 11, 11, 12, 12, 13, 14, 15
> +};
> +
> +static const u8 rtw8723b_pwrtrk_2g_cck_a_p[] = {
> +	0, 0, 1, 2, 2, 2, 3, 3, 3, 4, 5, 5, 6, 6, 7, 7,
> +	8, 8, 9, 9, 9, 10, 10, 11, 11, 12, 12, 13, 14, 15
> +};
> +
> +static const struct rtw_pwr_track_tbl rtw8723b_rtw_pwr_track_tbl = {
> +	.pwrtrk_2gb_n = rtw8723b_pwrtrk_2gb_n,
> +	.pwrtrk_2gb_p = rtw8723b_pwrtrk_2gb_p,
> +	.pwrtrk_2ga_n = rtw8723b_pwrtrk_2ga_n,
> +	.pwrtrk_2ga_p = rtw8723b_pwrtrk_2ga_p,
> +	.pwrtrk_2g_cckb_n = rtw8723b_pwrtrk_2g_cck_b_n,
> +	.pwrtrk_2g_cckb_p = rtw8723b_pwrtrk_2g_cck_b_p,
> +	.pwrtrk_2g_ccka_n = rtw8723b_pwrtrk_2g_cck_a_n,
> +	.pwrtrk_2g_ccka_p = rtw8723b_pwrtrk_2g_cck_a_p,
> +	/* rtw8723x_pwrtrack_set_xtal() is not used on this chip. */
> +	.pwrtrk_xtal_n = NULL,
> +	.pwrtrk_xtal_p = NULL,
> +};
> +
> +static const struct rtw_rfe_def rtw8723b_rfe_defs[] = {
> +	[0] = { .phy_pg_tbl	= &rtw8723b_bb_pg_tbl,
> +		.txpwr_lmt_tbl	= &rtw8723b_txpwr_lmt_tbl,
> +		.pwr_track_tbl	= &rtw8723b_rtw_pwr_track_tbl, },
> +};
> +
> +/* Shared-Antenna Coex Table */
> +static const struct coex_table_para table_sant_8723b[] = {
> +	{0xffffffff, 0xffffffff}, /* case-0 */
> +	{0x55555555, 0x55555555},
> +	{0x66555555, 0x66555555},
> +	{0xaaaaaaaa, 0xaaaaaaaa},
> +	{0x5a5a5a5a, 0x5a5a5a5a},
> +	{0xfafafafa, 0xfafafafa}, /* case-5 */
> +	{0x6a5a5555, 0xaaaaaaaa},
> +	{0x6a5a56aa, 0x6a5a56aa},
> +	{0x6a5a5a5a, 0x6a5a5a5a},
> +	{0x66555555, 0x5a5a5a5a},
> +	{0x66555555, 0x6a5a5a5a}, /* case-10 */
> +	{0x66555555, 0x6a5a5aaa},
> +	{0x66555555, 0x5a5a5aaa},
> +	{0x66555555, 0x6aaa5aaa},
> +	{0x66555555, 0xaaaa5aaa},
> +	{0x66555555, 0xaaaaaaaa}, /* case-15 */
> +	{0xffff55ff, 0xfafafafa},
> +	{0xffff55ff, 0x6afa5afa},
> +	{0xaaffffaa, 0xfafafafa},
> +	{0xaa5555aa, 0x5a5a5a5a},
> +	{0xaa5555aa, 0x6a5a5a5a}, /* case-20 */
> +	{0xaa5555aa, 0xaaaaaaaa},
> +	{0xffffffff, 0x5a5a5a5a},
> +	{0xffffffff, 0x5a5a5a5a},
> +	{0xffffffff, 0x55555555},
> +	{0xffffffff, 0x5a5a5aaa}, /* case-25 */
> +	{0x55555555, 0x5a5a5a5a},
> +	{0x55555555, 0xaaaaaaaa},
> +	{0x55555555, 0x6a5a6a5a},
> +	{0x66556655, 0x66556655},
> +	{0x66556aaa, 0x6a5a6aaa}, /* case-30 */
> +	{0xffffffff, 0x5aaa5aaa},
> +	{0x56555555, 0x5a5a5aaa},
> +};
> +
> +/* Non-Shared-Antenna Coex Table */
> +static const struct coex_table_para table_nsant_8723b[] = {
> +	{0xffffffff, 0xffffffff}, /* case-100 */
> +	{0x55555555, 0x55555555},
> +	{0x66555555, 0x66555555},
> +	{0xaaaaaaaa, 0xaaaaaaaa},
> +	{0x5a5a5a5a, 0x5a5a5a5a},
> +	{0xfafafafa, 0xfafafafa}, /* case-105 */
> +	{0x5afa5afa, 0x5afa5afa},
> +	{0x55555555, 0xfafafafa},
> +	{0x66555555, 0xfafafafa},
> +	{0x66555555, 0x5a5a5a5a},
> +	{0x66555555, 0x6a5a5a5a}, /* case-110 */
> +	{0x66555555, 0xaaaaaaaa},
> +	{0xffff55ff, 0xfafafafa},
> +	{0xffff55ff, 0x5afa5afa},
> +	{0xffff55ff, 0xaaaaaaaa},
> +	{0xffff55ff, 0xffff55ff}, /* case-115 */
> +	{0xaaffffaa, 0x5afa5afa},
> +	{0xaaffffaa, 0xaaaaaaaa},
> +	{0xffffffff, 0xfafafafa},
> +	{0xffffffff, 0x5afa5afa},
> +	{0xffffffff, 0xaaaaaaaa}, /* case-120 */
> +	{0x55ff55ff, 0x5afa5afa},
> +	{0x55ff55ff, 0xaaaaaaaa},
> +	{0x55ff55ff, 0x55ff55ff}
> +};
> +
> +/* Shared-Antenna TDMA */
> +static const struct coex_tdma_para tdma_sant_8723b[] = {
> +	{ {0x00, 0x00, 0x00, 0x00, 0x00} }, /* case-0 */
> +	{ {0x61, 0x45, 0x03, 0x11, 0x11} }, /* case-1 */
> +	{ {0x61, 0x3a, 0x03, 0x11, 0x11} },
> +	{ {0x61, 0x30, 0x03, 0x11, 0x11} },
> +	{ {0x61, 0x20, 0x03, 0x11, 0x11} },
> +	{ {0x61, 0x10, 0x03, 0x11, 0x11} }, /* case-5 */
> +	{ {0x61, 0x45, 0x03, 0x11, 0x10} },
> +	{ {0x61, 0x3a, 0x03, 0x11, 0x10} },
> +	{ {0x61, 0x30, 0x03, 0x11, 0x10} },
> +	{ {0x61, 0x20, 0x03, 0x11, 0x10} },
> +	{ {0x61, 0x10, 0x03, 0x11, 0x10} }, /* case-10 */
> +	{ {0x61, 0x08, 0x03, 0x11, 0x14} },
> +	{ {0x61, 0x08, 0x03, 0x10, 0x14} },
> +	{ {0x51, 0x08, 0x03, 0x10, 0x54} },
> +	{ {0x51, 0x08, 0x03, 0x10, 0x55} },
> +	{ {0x51, 0x08, 0x07, 0x10, 0x54} }, /* case-15 */
> +	{ {0x51, 0x45, 0x03, 0x10, 0x50} },
> +	{ {0x51, 0x3a, 0x03, 0x10, 0x50} },
> +	{ {0x51, 0x30, 0x03, 0x10, 0x50} },
> +	{ {0x51, 0x20, 0x03, 0x10, 0x50} },
> +	{ {0x51, 0x10, 0x03, 0x10, 0x50} }, /* case-20 */
> +	{ {0x51, 0x4a, 0x03, 0x10, 0x50} },
> +	{ {0x51, 0x0c, 0x03, 0x10, 0x54} },
> +	{ {0x55, 0x08, 0x03, 0x10, 0x54} },
> +	{ {0x65, 0x10, 0x03, 0x11, 0x10} },
> +	{ {0x51, 0x10, 0x03, 0x10, 0x51} }, /* case-25 */
> +	{ {0x51, 0x08, 0x03, 0x10, 0x50} },
> +	{ {0x61, 0x08, 0x03, 0x11, 0x11} }
> +};
> +
> +/* Non-Shared-Antenna TDMA */
> +static const struct coex_tdma_para tdma_nsant_8723b[] = {
> +	{ {0x00, 0x00, 0x00, 0x00, 0x01} }, /* case-100 */
> +	{ {0x61, 0x45, 0x03, 0x11, 0x11} }, /* case-101 */
> +	{ {0x61, 0x3a, 0x03, 0x11, 0x11} },
> +	{ {0x61, 0x30, 0x03, 0x11, 0x11} },
> +	{ {0x61, 0x20, 0x03, 0x11, 0x11} },
> +	{ {0x61, 0x10, 0x03, 0x11, 0x11} }, /* case-105 */
> +	{ {0x61, 0x45, 0x03, 0x11, 0x10} },
> +	{ {0x61, 0x3a, 0x03, 0x11, 0x10} },
> +	{ {0x61, 0x30, 0x03, 0x11, 0x10} },
> +	{ {0x61, 0x20, 0x03, 0x11, 0x10} },
> +	{ {0x61, 0x10, 0x03, 0x11, 0x10} }, /* case-110 */
> +	{ {0x61, 0x08, 0x03, 0x11, 0x14} },
> +	{ {0x61, 0x08, 0x03, 0x10, 0x14} },
> +	{ {0x51, 0x08, 0x03, 0x10, 0x54} },
> +	{ {0x51, 0x08, 0x03, 0x10, 0x55} },
> +	{ {0x51, 0x08, 0x07, 0x10, 0x54} }, /* case-115 */
> +	{ {0x51, 0x45, 0x03, 0x10, 0x50} },
> +	{ {0x51, 0x3a, 0x03, 0x10, 0x50} },
> +	{ {0x51, 0x30, 0x03, 0x10, 0x50} },
> +	{ {0x51, 0x20, 0x03, 0x10, 0x50} },
> +	{ {0x51, 0x10, 0x03, 0x10, 0x50} }, /* case-120 */
> +	{ {0x51, 0x08, 0x03, 0x10, 0x50} }
> +};
> +
> +static void rtw8723b_efuse_grant(struct rtw_dev *rtwdev, bool on)
> +{
> +	rtw_write8_set(rtwdev, REG_BT_EFUSE_CTRL_8723B,
> +		       on ? BIT_BT_PWR_CUT : BIT_BT_OUT_ISO);
> +
> +	rtw8723x_efuse_grant(rtwdev, on);
> +}
> +
> +static u8 rtw8723b_default_ofdm_index(struct rtw_dev *rtwdev)
> +{
> +	u32 val32;
> +	u32 swing;
> +	u8 i;
> +
> +	swing = rtw_read32_mask(rtwdev, REG_OFDM_0_XA_TX_IQ_IMBALANCE,
> +				OFDM_SWING_MASK);
> +
> +	for (i = 0; i < RTW_OFDM_SWING_TABLE_SIZE; i++) {
> +		val32 = rtw8723b_ofdm_swing_table[i];
> +
> +		if (val32 >= 0x100000)
> +			val32 >>= __ffs(OFDM_SWING_MASK);

Isn't this the same as u32_get_bits(val32, OFDM_SWING_MASK) ?

Also, every value in the table is bigger than 0x100000, so no need for if.

> +
> +		if (val32 == swing)
> +			break;
> +	}
> +
> +	if (i >= RTW_OFDM_SWING_TABLE_SIZE)
> +		i = 30; /* 30, +0dB */
> +
> +	return i;
> +}
> +
> +static u8 rtw8723b_default_cck_index(struct rtw_dev *rtwdev)
> +{
> +	u8 i;
> +	u8 swing;
> +
> +	swing = rtw_read8(rtwdev, rtw8723b_cck_pwr_regs[0]);
> +
> +	for (i = 0; i < RTW_CCK_SWING_TABLE_SIZE; i++) {
> +		if (rtw8723b_cck_swing_table_ch1_ch13[i][0] == swing)
> +			break;
> +	}
> +
> +	if (i >= RTW_CCK_SWING_TABLE_SIZE)
> +		i = 20; /* 20, -6.0dB */
> +
> +	return i;
> +}
> +
> +static void rtw8723b_pwrtrack_init(struct rtw_dev *rtwdev)
> +{
> +	struct rtw_dm_info *dm_info = &rtwdev->dm_info;
> +	u8 path;
> +
> +	dm_info->default_ofdm_index = rtw8723b_default_ofdm_index(rtwdev);
> +	dm_info->default_cck_index = rtw8723b_default_cck_index(rtwdev);
> +
> +	/* Clear the OFDM remnant per path: tracking keeps one per path. */
> +	for (path = RF_PATH_A; path < rtwdev->hal.rf_path_num; path++) {
> +		ewma_thermal_init(&dm_info->avg_thermal[path]);
> +		dm_info->delta_power_index[path] = 0;
> +		dm_info->txagc_remnant_ofdm[path] = 0;
> +	}
> +	dm_info->pwr_trk_triggered = false;
> +	dm_info->pwr_trk_init_trigger = true;
> +	dm_info->thermal_meter_k = rtwdev->efuse.thermal_meter_k;
> +	dm_info->txagc_remnant_cck = 0;
> +}
> +
> +static void rtw8723b_sdio_restore_pad_ctrl(struct rtw_dev *rtwdev,
> +					   bool keep_pta_owner)
> +{
> +	u32 before;
> +	u32 after;
> +
> +	if (!rtw_is_8723bs(rtwdev))
> +		return;
> +
> +	before = rtw_read32(rtwdev, REG_PAD_CTRL1);
> +	after = before & ~(BIT_LNAON_WLBT_SEL | BIT_SW_DPDT_SEL_DATA);
> +	if (keep_pta_owner)
> +		after |= BIT_PAPE_WLBT_SEL;
> +	else
> +		after &= ~BIT_PAPE_WLBT_SEL;
> +	if (after == before)
> +		return;
> +
> +	rtw_write32(rtwdev, REG_PAD_CTRL1, after);
> +}
> +
> +static void rtw8723b_post_enable_flow(struct rtw_dev *rtwdev)
> +{
> +	/*
> +	 * Enable falling edge triggered interrupts and GPIO9 interrupt mode.
> +	 * The power-on sequence sets both, but it runs before the firmware is
> +	 * downloaded, so reassert them here as the vendor driver does.
> +	 */
> +	rtw_write8_set(rtwdev, 0x0049, BIT(1));
> +	rtw_write8_set(rtwdev, 0x0063, BIT(1));

This seems like bit 25 of REG_GPIO_PIN_CTRL_2.

> +
> +	rtw_write16_set(rtwdev, REG_APS_FSMCO, BIT_EN_PDN);
> +
> +	/*
> +	 * Only OR in the missing enables: writing CR to zero would reset the
> +	 * hardware free-page counters and leave TX DMA no pages to allocate.
> +	 */
> +	rtw_write16_set(rtwdev, REG_CR, MAC_TRX_ENABLE | BIT_MAC_SEC_EN |
> +				       BIT_32K_CAL_TMR_EN);
> +
> +	if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_SDIO) {
> +		rtw_write16_set(rtwdev, REG_PWR_DATA,
> +				BIT_EEPRPAD_RFE_CTRL_EN);
> +
> +		/*
> +		 * rtw_mac_power_on() sets PAD mux bits this chip must not have;
> +		 * restore the SDIO PAD mux before RF and coex setup.
> +		 */
> +		rtw8723b_sdio_restore_pad_ctrl(rtwdev, false);
> +	}
> +
> +	rtw_write8(rtwdev, REG_EARLY_MODE_CONTROL, 0);
> +
> +	/* Keep every MACID eligible for firmware-scheduled TX at power-on. */
> +	rtw_write32(rtwdev, REG_MACID_PKT_DROP0, 0);
> +	rtw_write32(rtwdev, REG_MACID_PKT_SLEEP, 0);
> +}
> +
> +static void rtw8723b_phy_bb_config(struct rtw_dev *rtwdev)
> +{
> +	u8 xtal_cap;
> +
> +	/* Enable BB and RF */
> +	rtw_write16_set(rtwdev, REG_SYS_FUNC_EN,
> +			BIT_FEN_EN_25_1 | BIT_FEN_BB_GLB_RST | BIT_FEN_BB_RSTB);
> +
> +	if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_USB)
> +		rtw_write32(rtwdev, REG_BB_SEL_BTG, 0x0);
> +	else
> +		rtw_write32(rtwdev, REG_BB_SEL_BTG, 0x280);
> +
> +	/* Full write: preserving spuriously set bits can wedge the RF bus. */
> +	rtw_write8(rtwdev, REG_RF_CTRL, WLAN_RF_CTRL_ENABLE);
> +	fsleep(1000);
> +	rtw_write_rf(rtwdev, RF_PATH_A, RF_WLINT, RFREG_MASK, 0x0780);
> +	rtw_write8(rtwdev, REG_SYS_FUNC_EN,
> +		   BIT_FEN_PPLL | BIT_FEN_PCIEA | BIT_FEN_DIO_PCIE |
> +		   BIT_FEN_BB_GLB_RST | BIT_FEN_BB_RSTB);
> +	rtw_write8(rtwdev, REG_AFE_CTRL1 + 1, 0x80);
> +
> +	xtal_cap = rtwdev->efuse.crystal_cap & 0x3f;
> +	rtw_write32_mask(rtwdev,  REG_AFE_CTRL3, BIT_MASK_XTAL,
> +			 xtal_cap | (xtal_cap << 6));
> +}
> +
> +static void rtw8723b_phy_load_bb_tables(struct rtw_dev *rtwdev)
> +{
> +	const struct rtw_chip_info *chip = rtwdev->chip;
> +	const struct rtw_rfe_def *rfe_def = rtw_get_rfe_def(rtwdev);
> +
> +	rtw_load_table(rtwdev, chip->bb_tbl);
> +	rtw_load_table(rtwdev, chip->agc_tbl);
> +	if (rfe_def && rfe_def->agc_btg_tbl)
> +		rtw_load_table(rtwdev, rfe_def->agc_btg_tbl);
> +}
> +
> +static void rtw8723b_phy_rf6052_config(struct rtw_dev *rtwdev)
> +{
> +	struct rtw_hal *hal = &rtwdev->hal;
> +	u32 intf_s, intf_oe, hssi_2;
> +	u32 val32, mask;
> +	u8 path;
> +
> +	for (path = RF_PATH_A; path < hal->rf_path_num; path++) {
> +		switch (path) {
> +		case RF_PATH_A:
> +			intf_s = REG_FPGA0_XA_RF_SW_CTRL;
> +			intf_oe = REG_FPGA0_XA_RF_INT_OE;
> +			hssi_2 = REG_FPGA0_XA_HSSI_PARM2;
> +			mask = RFSI_RFENV;
> +			break;
> +		case RF_PATH_B:
> +			/*
> +			 * The path B switch control is the upper half of the
> +			 * word at REG_FPGA0_XA_RF_SW_CTRL, which the shifted
> +			 * mask already selects. Addressing 0x0872 directly
> +			 * would be a 32-bit access on a 2-byte boundary and
> +			 * would reach into the register that follows.
> +			 */
> +			intf_s = REG_FPGA0_XA_RF_SW_CTRL;
> +			intf_oe = REG_FPGA0_XB_RF_INT_OE;
> +			hssi_2 = REG_FPGA0_XB_HSSI_PARM2;
> +			mask = RFSI_RFENV << 16;
> +			break;
> +		default:
> +			rtw_err(rtwdev, "invalid rf path %c\n", path + 'A');
> +			return;
> +		}
> +
> +		val32 = rtw_read32_mask(rtwdev, intf_s, mask);
> +
> +		rtw_write32_mask(rtwdev, intf_oe, RFSI_RFENV << 16, 0x1);
> +		udelay(1);
> +
> +		rtw_write32_mask(rtwdev, intf_oe, RFSI_RFENV, 0x1);
> +		udelay(1);
> +
> +		rtw_write32_mask(rtwdev, hssi_2, HSSI_3WIRE_ADDR_LEN, 0x0);
> +		udelay(1);
> +
> +		rtw_write32_mask(rtwdev, hssi_2, HSSI_3WIRE_DATA_LEN, 0x0);
> +		udelay(1);
> +
> +		/* Path B has no table of its own; radio_a serves both paths. */
> +		rtw_load_table(rtwdev, rtwdev->chip->rf_tbl[RF_PATH_A]);
> +
> +		rtw_write32_mask(rtwdev, intf_s, mask, val32);
> +	}
> +}
> +
> +static void rtw8723b_phy_lck(struct rtw_dev *rtwdev)
> +{
> +	rtw_write_rf(rtwdev, RF_PATH_A, 0xb0, RFREG_MASK, 0xdfbe0);

We have a name for 0xb0: RF_SYN_PFD. Not sure if it's the right name here.

> +	rtw_write_rf(rtwdev, RF_PATH_A, RF_CFGCH, RFREG_MASK, 0x8c01);
> +	fsleep(200 * 1000);
> +	rtw_write_rf(rtwdev, RF_PATH_A, 0xb0, RFREG_MASK, 0xdffe0);
> +}
> +
> +static void rtw8723b_phy_rf_config(struct rtw_dev *rtwdev)
> +{
> +	rtw8723b_phy_rf6052_config(rtwdev);
> +
> +	/* LCK must run as part of the RF configuration. */
> +	rtw8723b_phy_lck(rtwdev);
> +}
> +
> +static void rtw8723b_init_tx_buffer_boundary(struct rtw_dev *rtwdev)
> +{
> +	u8 val8 = TX_TOTAL_PAGE_NUMBER_8723B + 1;
> +
> +	rtw_write8(rtwdev, REG_BCNQ_BDNY, val8);
> +	rtw_write8(rtwdev, REG_MGQ_BDNY, val8);
> +	rtw_write8(rtwdev, REG_WMAC_LBK_BF_HD, val8);
> +	rtw_write8(rtwdev, REG_TRXFF_BNDY, val8);
> +	rtw_write8(rtwdev, REG_DWBCN0_CTRL + 1, val8);

__priority_queue_cfg_legacy() already takes care of these. Is it
necessary to set them again here?

> +}
> +
> +static void rtw8723b_init_page_boundary(struct rtw_dev *rtwdev)
> +{
> +	/* Matches the value __priority_queue_cfg_legacy() programs here. */
> +	rtw_write16(rtwdev, REG_TRXFF_BNDY + 2, 0x4000 - REPORT_BUF - 1);
> +}
> +
> +static void rtw8723b_init_transfer_page_size(struct rtw_dev *rtwdev)
> +{
> +	rtw_write8(rtwdev, REG_PBP, 0x11);

We have some macros for this in reg.h right under REG_PBP. You can use
them with u8_encode_bits().

> +}
> +
> +static void rtw8723b_init_driver_info_size(struct rtw_dev *rtwdev)
> +{
> +	/* NOTE: also is done in rtw_drv_info_cfg */

If it's done there do you have to do it again here?

> +	rtw_write8(rtwdev, REG_RX_DRVINFO_SZ, PHY_STATUS_SIZE);
> +}
> +
> +static void rtw8723b_init_wmac_setting(struct rtw_dev *rtwdev)
> +{
> +	/*
> +	 * The vendor's 8723x filter value plus BIT_APP_FCS, which rtw88
> +	 * needs because it advertises RX_INCLUDES_FCS. It is assigned to
> +	 * hal.rcr and not merely written because rtw_core_start()
> +	 * rewrites REG_RCR from hal.rcr after power_on, which would undo
> +	 * a register-only write; fw.c toggles BIT_CBSSID_BCN in it.
> +	 */
> +	rtwdev->hal.rcr = WLAN_RCR_CFG;

Is it necessary to change the default value assigned in rtw_core_init()?

> +	rtw_write32(rtwdev, REG_RCR, rtwdev->hal.rcr);
> +
> +	rtw_write32(rtwdev, REG_MAR, 0xffffffff);
> +	rtw_write32(rtwdev, REG_MAR + 4, 0xffffffff);
> +
> +	rtw_write16(rtwdev, REG_RXFLTMAP2, WLAN_RX_FILTER2);
> +	rtw_write16(rtwdev, REG_RXFLTMAP1, WLAN_RX_FILTER1);

Please also update rtwdev->hal.rxfltmap1 when you change REG_RXFLTMAP1:

https://lore.kernel.org/linux-wireless/2a52d718-9e46-47f2-84a1-d8e7b1ed89a8@gmail.com/

> +	rtw_write16(rtwdev, REG_RXFLTMAP0, WLAN_RX_FILTER0);
> +}
> +
> +static void rtw8723b_init_adaptive_ctrl(struct rtw_dev *rtwdev)
> +{
> +	/*
> +	 * Firmware validates RRSR at init: narrowing it to the mandatory
> +	 * rates makes it drop all management TX, so keep the full set.
> +	 */
> +	rtw_write32_mask(rtwdev, REG_RRSR, 0xfffff, 0xffff1);
> +	rtwdev->dm_info.rrsr_val_init = 0xffff1;
> +	rtw_write16(rtwdev, REG_RETRY_LIMIT, 0x3030);
> +}
> +
> +static void rtw8723b_init_edca(struct rtw_dev *rtwdev)
> +{
> +	rtw_write16(rtwdev, REG_SPEC_SIFS, 0x100a);
> +	rtw_write16(rtwdev, REG_MAC_SPEC_SIFS, 0x100a);
> +	rtw_write16(rtwdev, REG_SIFS, 0x100a);
> +	rtw_write16(rtwdev, REG_SIFS + 2, 0x100a);
> +
> +	/*
> +	 * RESP_SIFS must leave the AP enough slack, or it times out before the
> +	 * ACK reaches the air and the unicast handshake never completes.
> +	 */
> +	rtw_write16(rtwdev, REG_RESP_SIFS_CCK, 0x0808);
> +	rtw_write16(rtwdev, REG_RESP_SIFS_OFDM, 0x0a0a);
> +
> +	/* TXOP */
> +	rtw_write32(rtwdev, REG_EDCA_BE_PARAM, 0x005EA42B);
> +	rtw_write32(rtwdev, REG_EDCA_BK_PARAM, 0x0000A44F);
> +	rtw_write32(rtwdev, REG_EDCA_VI_PARAM, 0x005EA324);
> +	rtw_write32(rtwdev, REG_EDCA_VO_PARAM, 0x002FA226);
> +}
> +
> +static void rtw8723b_init_retry_function(struct rtw_dev *rtwdev)
> +{
> +	rtw_write8_set(rtwdev, REG_FWHW_TXQ_CTRL, BIT(7));
> +	rtw_write8(rtwdev, REG_ACKTO, 0x40);
> +}
> +
> +static void rtw8723b_init_operation_mode(struct rtw_dev *rtwdev)
> +{
> +	rtw_write8(rtwdev, REG_BWOPMODE, BIT_BWOPMODE_20MHZ);

I don't see this in the vendor driver v5.2.17.1.

> +}
> +
> +static void rtw8723b_init_beacon_parameters(struct rtw_dev *rtwdev)
> +{
> +	/*
> +	 * Both ports get DIS_TSF_UDT and EN_BCN_FUNCTION only; DIS_BCNQ_SUB
> +	 * belongs to AP/IBSS and must stay clear for station mode.
> +	 */
> +	rtw_write16(rtwdev, REG_BCN_CTRL,
> +		    (BIT_DIS_TSF_UDT | BIT_EN_BCN_FUNCTION) |
> +		    ((BIT_DIS_TSF_UDT | BIT_EN_BCN_FUNCTION) << 8));
> +	rtw_write8(rtwdev, REG_TBTT_PROHIBIT, TBTT_PROHIBIT_SETUP_TIME);
> +	rtw_write8(rtwdev, REG_TBTT_PROHIBIT + 1,
> +		   TBTT_PROHIBIT_HOLD_TIME_STOP_BCN & 0xff);
> +	rtw_write8(rtwdev, REG_TBTT_PROHIBIT + 2,
> +		   (rtw_read8(rtwdev, REG_TBTT_PROHIBIT + 2) & 0xf0) |
> +		   (TBTT_PROHIBIT_HOLD_TIME_STOP_BCN >> 8));
> +
> +	rtw_write8(rtwdev, REG_BCNDMATIM, WLAN_BCN_DMA_TIME);
> +	/* Largest beacon AIFS: the chip does not contend before beaconing. */
> +	rtw_write16(rtwdev, REG_BCNTCFG, 0x660F);
> +}
> +
> +static void rtw8723b_init_burst_pkt_len(struct rtw_dev *rtwdev)
> +{
> +	rtw_write8_set(rtwdev, REG_SINGLE_AMPDU_CTRL, BIT_EN_SINGLE_APMDU);
> +	rtw_write8(rtwdev, REG_RX_PKT_LIMIT, 0x18);
> +	rtw_write8(rtwdev, REG_MAX_AGGR_NUM, 0x1F);
> +	rtw_write8(rtwdev, REG_PIFS, 0x00);
> +	rtw_write8_clr(rtwdev, REG_FWHW_TXQ_CTRL, BIT(7));
> +	rtw_write8(rtwdev, REG_AMPDU_MAX_TIME, 0x70);
> +}
> +
> +static void rtw8723b_init_antenna_selection(struct rtw_dev *rtwdev)
> +{
> +	rtw_write8(rtwdev, REG_LEDCFG2, WLAN_ANT_SEL);
> +}
> +
> +#define RF_AC	0x00

You can use the existing RF_MODE name for this.

> +
> +static void rtw8723b_lck(struct rtw_dev *rtwdev)
> +{
> +	u32 rf_mode = 0, lc_cal;
> +	int ret;
> +	u8 val_ctx;
> +	u8 rf_val;
> +
> +	val_ctx = rtw_read8(rtwdev, REG_CTX);
> +
> +	if ((val_ctx & BIT_MASK_CTX_TYPE) != 0)

No need to compare.

> +		rtw_write8(rtwdev, REG_CTX, val_ctx & ~BIT_MASK_CTX_TYPE);
> +	else
> +		rtw_write8(rtwdev, REG_TXPAUSE, 0xff);
> +
> +	if ((val_ctx & BIT_MASK_CTX_TYPE) != 0) {
> +		/* 1. Read original RF mode */
> +		rf_mode = rtw_read_rf(rtwdev, RF_PATH_A, RF_AC, MASK12BITS);
> +		/* 2. Set RF mode = standby mode */
> +		rtw_write_rf(rtwdev, RF_PATH_A, RF_AC, MASK12BITS, (rf_mode & 0x8ffff) | 0x10000);
> +	}
> +
> +	/* 3. Read RF reg18 */
> +	lc_cal = rtw_read_rf(rtwdev, RF_PATH_A, RF_CFGCH, MASK12BITS);
> +
> +	/* 4. Set LC calibration begin	bit15 */
> +	rtw_write_rf(rtwdev, RF_PATH_A, 0xb0, RFREG_MASK, 0xdfbe0);
> +	rtw_write_rf(rtwdev, RF_PATH_A, RF_CFGCH, MASK12BITS, lc_cal | BIT_LCK);
> +
> +	ret = read_poll_timeout(rtw_read_rf, rf_val, rf_val != 0x1,
> +				10000, 1000000, false,
> +			 rtwdev, RF_PATH_A, RF_CFGCH, BIT_LCK);

checkpatch should catch alignment issues like this. Please always run it.

> +	if (ret)
> +		rtw_warn(rtwdev, "failed to poll LCK status bit\n");
> +
> +	rtw_write_rf(rtwdev, RF_PATH_A, 0xb0, RFREG_MASK, 0xdffe0);
> +
> +	/* Restore original situation */
> +	if ((val_ctx & BIT_MASK_CTX_TYPE) != 0) {
> +		rtw_write8(rtwdev, REG_CTX, val_ctx);
> +
> +		rtw_write_rf(rtwdev, RF_PATH_A, RF_AC, MASK12BITS, rf_mode);
> +	} else {
> +		rtw_write8(rtwdev, REG_TXPAUSE, 0x00);
> +	}

I think the vendor driver is using MASK12BITS (0xfff) by mistake in
this function. It doesn't make any sense, it should be RFREG_MASK
(0xfffff) instead.

> +}
> +
> +static void rtw8723b_inform_rfk_status(struct rtw_dev *rtwdev, bool start)
> +{
> +	int ret;
> +	u8 val8;
> +
> +	rtw_fw_inform_rfk_status(rtwdev, start);
> +
> +	if (!start)
> +		return;
> +
> +	ret = read_poll_timeout(rtw_read8, val8,
> +				val8 & BIT_RFK_FW_ACK_8723B,
> +				50000, 400000, false,
> +				rtwdev, REG_RFK_FW_ACK_8723B);
> +	if (ret)
> +		rtw_warn(rtwdev, "failed to poll firmware RFK start ack\n");
> +}
> +
> +static int rtw8723b_mac_init(struct rtw_dev *rtwdev)
> +{
> +	rtw_write32(rtwdev, REG_INT_MIG, 0);
> +	rtw_write32(rtwdev, REG_MCUTST_1, 0x0);
> +
> +	rtw_write8(rtwdev, REG_MISC_CTRL, BIT_DIS_SECOND_CCA);
> +	rtw_write8(rtwdev, REG_2ND_CCA_CTRL, 0x0);
> +
> +	return 0;
> +}
> +
> +static void rtw8723b_phy_set_param(struct rtw_dev *rtwdev)
> +{
> +	const struct rtw_chip_info *chip = rtwdev->chip;
> +	u32 val32;
> +
> +	rtw8723b_post_enable_flow(rtwdev);
> +
> +	rtw_load_table(rtwdev, chip->mac_tbl);
> +	rtw8723b_phy_bb_config(rtwdev);
> +	rtw8723b_phy_load_bb_tables(rtwdev);
> +	rtw8723b_phy_rf_config(rtwdev);
> +
> +	/* enable CCK and OFDM block */
> +	rtw_write32_set(rtwdev, REG_FPGA0_RFMOD, BIT_CCKEN | BIT_OFDMEN);
> +
> +	rtw8723b_init_tx_buffer_boundary(rtwdev);
> +	rtw8723b_init_page_boundary(rtwdev);
> +	rtw8723b_init_transfer_page_size(rtwdev);
> +	rtw8723b_init_driver_info_size(rtwdev);
> +
> +	/* The MAC table sets REG_RCR and REG_MAR, so apply ours after it. */
> +	rtw8723b_init_wmac_setting(rtwdev);
> +
> +	rtw8723b_init_adaptive_ctrl(rtwdev);
> +	rtw8723b_init_edca(rtwdev);
> +	rtw8723b_init_retry_function(rtwdev);
> +
> +	/* sdio.c sets the DMA mode, but not the burst parameters. */
> +	rtw_write8(rtwdev, REG_RXDMA_MODE,
> +		   BIT_DMA_MODE |
> +		   FIELD_PREP_CONST(BIT_MASK_AGG_BURST_NUM, AGG_BURST_NUM) |
> +		   FIELD_PREP_CONST(BIT_MASK_AGG_BURST_SIZE, AGG_BURST_SIZE));
> +
> +	rtw8723b_init_operation_mode(rtwdev);
> +	rtw8723b_init_beacon_parameters(rtwdev);
> +	rtw8723b_init_burst_pkt_len(rtwdev);
> +
> +	/*
> +	 * 256 ms per-AC lifetime: the ROM default of ~1 s lets the chip retry
> +	 * data frames past the EAPOL retry window and reorders the connect.
> +	 */
> +	rtw_write16(rtwdev, REG_PKT_VO_VI_LIFE_TIME, 0x0400);
> +	rtw_write16(rtwdev, REG_PKT_BE_BK_LIFE_TIME, 0x0400);
> +
> +	rtw_write8(rtwdev, REG_SLOT, WLAN_SLOT_TIME);
> +
> +	/* disable BAR */
> +	rtw_write32(rtwdev, REG_BAR_MODE_CTRL, WLAN_BAR_VAL);
> +
> +	/* Enable hardware sequence numbering for all queues. */
> +	rtw_write8(rtwdev, REG_HWSEQ_CTRL, 0xff);
> +
> +	/* Enable Rx DMA timer masking: clear 0x0[2:0] and 0x2[15:0] only. */
> +	val32 = rtw_read32(rtwdev, REG_SDIO_TX_CTRL);
> +	val32 &= 0x0000fff8;
> +	rtw_write32(rtwdev, REG_SDIO_TX_CTRL, val32);
> +
> +	rtw_write16(rtwdev, REG_ATIMWND, 0x2);
> +
> +	rtw8723b_init_antenna_selection(rtwdev);
> +
> +	rtw_write8_set(rtwdev, REG_CR, BIT_MACTXEN | BIT_MACRXEN);
> +
> +	rtw_write8(rtwdev, REG_NAV_UPPER, 0xeb); /* ((30000 + 128 - 1) / 128) */
> +
> +	/* ack for xmit mgmt frames */
> +	rtw_write32_set(rtwdev, REG_FWHW_TXQ_CTRL, BIT(12));
> +
> +	rtw_phy_init(rtwdev);
> +
> +	rtw_write32_mask(rtwdev, REG_OFDM0_XAAGC1, MASKBYTE0, 0x50);
> +	rtw_write32_mask(rtwdev, REG_OFDM0_XAAGC1, MASKBYTE0, 0x20);
> +
> +	rtw8723b_pwrtrack_init(rtwdev);
> +}
> +
> +static u32 rtw8723b_iqk_ant_switch_path(struct rtw_dev *rtwdev)
> +{
> +	if (rtw_hci_type(rtwdev) != RTW_HCI_TYPE_SDIO)
> +		return rtw_hci_type(rtwdev) == RTW_HCI_TYPE_USB ? 0x280 : 0x0;
> +
> +	/* Scan and connect use the PTA mux, so calibrate the path they use. */
> +	return (rtwdev->efuse.bt_setting & BIT(6)) ? 0x80 : 0x200;

This function would be clearer if you don't use the ternary
operator at all.

Not sure this logic is correct. The check in the vendor driver is
like this:

bool shared_ant = bt_setting & BIT(0);

if (USB) {
	if (shared_ant)
		ant_path = RF_PATH_B;
	else
		ant_path = RF_PATH_A;
} else {
	if (bt_setting & BIT(6))
		ant_path = RF_PATH_B;
	else
		ant_path = RF_PATH_A;
}

if (!shared_ant || ant_path == RF_PATH_A)
	return 0;
else
	return 0x280;

I didn't see 0x80 and 0x200 in the IQK code.

> +}
> +
> +static void rtw8723b_reassert_rx_path(struct rtw_dev *rtwdev)
> +{
> +	u32 rf_wlint_before;
> +	u32 rx_path_before;
> +	u32 fpga0_before;
> +	u8 sys_func_before;
> +	u8 rf_ctrl_before;
> +
> +	if (!rtw_is_8723bs(rtwdev))
> +		return;
> +
> +	sys_func_before = rtw_read8(rtwdev, REG_SYS_FUNC_EN);
> +	rf_ctrl_before = rtw_read8(rtwdev, REG_RF_CTRL);
> +	fpga0_before = rtw_read32(rtwdev, REG_FPGA0_RFMOD);
> +	rx_path_before = rtw_read32(rtwdev, REG_BB_RX_PATH_11N);
> +	rf_wlint_before = rtw_read_rf(rtwdev, RF_PATH_A, RF_WLINT, RFREG_MASK);
> +
> +	if ((sys_func_before & WLAN_SYS_FUNC_BB_ENABLE) !=
> +	    WLAN_SYS_FUNC_BB_ENABLE)
> +		rtw_write8_set(rtwdev, REG_SYS_FUNC_EN,
> +			       WLAN_SYS_FUNC_BB_ENABLE);
> +
> +	if ((rf_ctrl_before & WLAN_RF_CTRL_ENABLE) != WLAN_RF_CTRL_ENABLE) {
> +		rtw_write8_set(rtwdev, REG_RF_CTRL, WLAN_RF_CTRL_ENABLE);
> +		usleep_range(10, 11);
> +	}
> +
> +	if ((fpga0_before & (BIT_CCKEN | BIT_OFDMEN)) !=
> +	    (BIT_CCKEN | BIT_OFDMEN)) {
> +		rtw_write32_set(rtwdev, REG_FPGA0_RFMOD,
> +				BIT_CCKEN | BIT_OFDMEN);
> +	}
> +
> +	if (rx_path_before != WLAN_RX_PATH_A_8723B) {
> +		rtw_write32(rtwdev, REG_BB_RX_PATH_11N,
> +			    WLAN_RX_PATH_A_8723B);
> +	}
> +
> +	if (rf_wlint_before != 0x0780) {
> +		rtw_write_rf(rtwdev, RF_PATH_A, RF_WLINT, RFREG_MASK,
> +			     0x0780);
> +	}
> +}
> +
> +static void rtw8723b_set_channel_rf(struct rtw_dev *rtwdev, u8 channel, u8 bw)
> +{
> +	u32 rf_cfgch;
> +
> +	rf_cfgch = rtw_read_rf(rtwdev, RF_PATH_A, RF_CFGCH, RFREG_MASK);
> +
> +	rf_cfgch &= ~RFCFGCH_CHANNEL_MASK;
> +	rf_cfgch |= channel & RFCFGCH_CHANNEL_MASK;

This is what u32(p)_replace_bits is for.

> +
> +	rf_cfgch &= ~RFCFGCH_BW_MASK;
> +	switch (bw) {
> +	case RTW_CHANNEL_WIDTH_20:
> +		rf_cfgch |= RFCFGCH_BW_20M;
> +		break;
> +	case RTW_CHANNEL_WIDTH_40:
> +		rf_cfgch |= RFCFGCH_BW_40M;
> +		break;
> +	default:
> +		break;
> +	}

bw is only going to be 20 or 40, so a simple if would be shorter.

> +
> +	/* The vendor driver programs both paths from the path A value. */
> +	rtw_write_rf(rtwdev, RF_PATH_A, RF_CFGCH, RFREG_MASK, rf_cfgch);
> +	if (rtwdev->hal.rf_path_num > 1)
> +		rtw_write_rf(rtwdev, RF_PATH_B, RF_CFGCH, RFREG_MASK, rf_cfgch);
> +}
> +
> +static void rtw8723b_set_channel_bb(struct rtw_dev *rtwdev, u8 bw,
> +				    u8 primary_ch_idx)
> +{
> +	switch (bw) {
> +	case RTW_CHANNEL_WIDTH_20:
> +		rtw_write32_mask(rtwdev, REG_FPGA0_RFMOD, BIT_MASK_RFMOD, 0x0);
> +		rtw_write32_mask(rtwdev, REG_FPGA1_RFMOD, BIT_MASK_RFMOD, 0x0);
> +		rtw_write32_mask(rtwdev, REG_OFDM0_TX_PSD_NOISE,
> +				 GENMASK(31, 30), 0x0);
> +		break;
> +	case RTW_CHANNEL_WIDTH_40:
> +		rtw_write32_mask(rtwdev, REG_FPGA0_RFMOD, BIT_MASK_RFMOD, 0x1);
> +		rtw_write32_mask(rtwdev, REG_FPGA1_RFMOD, BIT_MASK_RFMOD, 0x1);
> +		rtw_write32_mask(rtwdev, REG_CCK0_SYS, BIT_CCK_SIDE_BAND,
> +				 primary_ch_idx == RTW_SC_20_UPPER ? 1 : 0);
> +		rtw_write32_mask(rtwdev, REG_OFDM_FA_RSTD_11N, 0xc00,
> +				 primary_ch_idx == RTW_SC_20_UPPER ? 2 : 1);
> +		rtw_write32_mask(rtwdev, REG_BB_PWR_SAV5_11N, GENMASK(27, 26),
> +				 primary_ch_idx == RTW_SC_20_UPPER ? 1 : 2);
> +		break;
> +	default:
> +		break;
> +	}
> +}
> +
> +static void rtw8723b_set_channel(struct rtw_dev *rtwdev, u8 channel,
> +				 u8 bw, u8 primary_chan_idx)
> +{
> +	rtw8723b_set_channel_rf(rtwdev, channel, bw);
> +	rtw_set_channel_mac(rtwdev, channel, bw, primary_chan_idx);
> +	rtw8723b_set_channel_bb(rtwdev, bw, primary_chan_idx);

I don't think the vendor driver v5.2.17.1 does the stuff below:

> +	rtw8723b_reassert_rx_path(rtwdev);
> +
> +	if (rtw_is_8723bs(rtwdev)) {
> +		bool keep_pta_owner;
> +
> +		keep_pta_owner = test_bit(RTW_FLAG_SCANNING, rtwdev->flags) ||
> +				 (rtw_read32(rtwdev, REG_PAD_CTRL1) &
> +				  BIT_PAPE_WLBT_SEL);
> +		rtw8723b_sdio_restore_pad_ctrl(rtwdev, keep_pta_owner);
> +
> +		rtw_write8(rtwdev, REG_RF_CTRL, WLAN_RF_CTRL_ENABLE);
> +		fsleep(1000);
> +
> +		/*
> +		 * RF_WLINT bits 0-1 gate the data path into the BB and a prior
> +		 * IQK or coex run can leave them blocking TX, so re-arm them.
> +		 */
> +		rtw_write_rf(rtwdev, RF_PATH_A, RF_WLINT, RFREG_MASK,
> +			     0x0780);
> +	}

If this driver doesn't work without it, you probably have a bug
somewhere.

> +}
> +
> +static s8 rtw8723b_cck_rx_power(u8 lna_idx, u8 vga_idx)
> +{
> +	s8 rx_power = 0;
> +
> +	switch (lna_idx) {
> +	case 6:
> +		rx_power = -40 - (2 * vga_idx);
> +		break;
> +	case 4:
> +		rx_power = -20 - (2 * vga_idx);
> +		break;
> +	case 1:
> +		rx_power = 0 - (2 * vga_idx);
> +		break;
> +	case 0:
> +		rx_power = 10 - (2 * vga_idx);
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	return rx_power;
> +}
> +
> +static void rtw8723b_query_phy_status_cck(struct rtw_dev *rtwdev, u8 *phy_raw,
> +					  struct rtw_rx_pkt_stat *pkt_stat)
> +{
> +	struct phy_status_8703b *phy_status = (struct phy_status_8703b *)phy_raw;
> +	u8 lna_idx = (phy_status->cck_agc_rpt_ofdm_cfosho_a & 0xE0) >> 5;
> +	u8 vga_idx = (phy_status->cck_agc_rpt_ofdm_cfosho_a & 0x1F);
> +	s8 rx_power = rtw8723b_cck_rx_power(lna_idx, vga_idx);
> +	s8 min_rx_power = -120;
> +
> +	pkt_stat->bw = RTW_CHANNEL_WIDTH_20;
> +
> +	pkt_stat->rx_power[RF_PATH_A] = rx_power;
> +	pkt_stat->rssi = rtw_phy_rf_power_2_rssi(pkt_stat->rx_power, 1);
> +	pkt_stat->signal_power = max(pkt_stat->rx_power[RF_PATH_A],
> +				     min_rx_power);
> +	rtwdev->dm_info.rssi[RF_PATH_A] = pkt_stat->rssi;
> +}
> +
> +static void rtw8723b_query_phy_status_ofdm(struct rtw_dev *rtwdev, u8 *phy_raw,
> +					   struct rtw_rx_pkt_stat *pkt_stat)
> +{
> +	struct phy_status_8703b *phy_status = (struct phy_status_8703b *)phy_raw;
> +	struct rtw_dm_info *dm_info = &rtwdev->dm_info;
> +	s8 val_s8;
> +
> +	/* pkt_stat->bw comes from the RX descriptor, not the PHY status. */
> +
> +	val_s8 = phy_status->path_agc[RF_PATH_A].gain & 0x3F;
> +	pkt_stat->rx_power[RF_PATH_A] = (val_s8 * 2) - 110;
> +
> +	pkt_stat->rssi = rtw_phy_rf_power_2_rssi(pkt_stat->rx_power, 1);
> +	pkt_stat->rx_snr[RF_PATH_A] = (s8)(phy_status->path_rxsnr[RF_PATH_A] / 2);
> +
> +	/* signal power reported by HW */
> +	val_s8 = phy_status->cck_sig_qual_ofdm_pwdb_all >> 1;
> +	pkt_stat->signal_power = (val_s8 & 0x7f) - 110;
> +
> +	pkt_stat->rx_evm[RF_PATH_A] = phy_status->stream_rxevm[RF_PATH_A];
> +	pkt_stat->cfo_tail[RF_PATH_A] = phy_status->path_cfotail[RF_PATH_A];
> +
> +	dm_info->curr_rx_rate = pkt_stat->rate;
> +	dm_info->rssi[RF_PATH_A] = pkt_stat->rssi;
> +	dm_info->rx_snr[RF_PATH_A] = pkt_stat->rx_snr[RF_PATH_A] >> 1;
> +	dm_info->cfo_tail[RF_PATH_A] = (pkt_stat->cfo_tail[RF_PATH_A] * 5) >> 1;
> +
> +	val_s8 = (s8)pkt_stat->rx_evm[RF_PATH_A];
> +	val_s8 = clamp_t(s8, -val_s8 >> 1, 0, 64);
> +	val_s8 &= 0x3F; /* 64->0: second path of 1SS rate is 64 */
> +	dm_info->rx_evm_dbm[RF_PATH_A] = val_s8;
> +}
> +
> +static void rtw8723b_query_phy_status(struct rtw_dev *rtwdev, u8 *phy_status,
> +				      struct rtw_rx_pkt_stat *pkt_stat)
> +{
> +	/*
> +	 * The 8723B PHY status does not report the channel, so we must
> +	 * mark it invalid to allow mac80211/rtw88 to parse it from the IE
> +	 * during scanning.
> +	 */
> +	pkt_stat->channel_invalid = true;
> +
> +	if (pkt_stat->rate <= DESC_RATE11M)
> +		rtw8723b_query_phy_status_cck(rtwdev, phy_status, pkt_stat);
> +	else
> +		rtw8723b_query_phy_status_ofdm(rtwdev, phy_status, pkt_stat);
> +}
> +
> +static void rtw8723b_set_iqk_matrix_by_result(struct rtw_dev *rtwdev,
> +					      u32 ofdm_swing, u8 path)
> +{
> +	struct rtw_dm_info *dm_info = &rtwdev->dm_info;
> +	s32 ele_A, ele_D, ele_C, ele_A_ext;
> +	s32 iqk_result_x;
> +	s32 iqk_result_y;
> +	s32 value32;
> +
> +	switch (path) {
> +	default:
> +	case RF_PATH_A:
> +		iqk_result_x = dm_info->iqk.result.s1_x;
> +		iqk_result_y = dm_info->iqk.result.s1_y;
> +		break;
> +	case RF_PATH_B:
> +		iqk_result_x = dm_info->iqk.result.s0_x;
> +		iqk_result_y = dm_info->iqk.result.s0_y;
> +		break;
> +	}
> +
> +	/* new element D */
> +	ele_D = OFDM_SWING_D(ofdm_swing);
> +
> +	/* new element A */
> +	iqk_result_x = iqkxy_to_s32(iqk_result_x);
> +	ele_A = iqk_mult(iqk_result_x, ele_D, &ele_A_ext);
> +
> +	/* new element C */
> +	iqk_result_y = iqkxy_to_s32(iqk_result_y);
> +	ele_C = iqk_mult(iqk_result_y, ele_D, NULL);
> +
> +	switch (path) {
> +	case RF_PATH_A:
> +	default:
> +		/* write new elements A, C, D, element B is always 0 */
> +		value32 = BIT_SET_TXIQ_ELM_ACD(ele_A, ele_C, ele_D);
> +		rtw_write32(rtwdev, REG_OFDM_0_XA_TX_IQ_IMBALANCE, value32);
> +		value32 = BIT_SET_TXIQ_ELM_C1(ele_C);
> +		rtw_write32_mask(rtwdev, REG_TXIQK_MATRIXA_LSB2_11N, MASKH4BITS,
> +				 value32);
> +		rtw_write32_mask(rtwdev, REG_OFDM_0_ECCA_THRESHOLD, BIT(24),
> +				 ele_A_ext);
> +		break;
> +
> +	case RF_PATH_B:
> +		/* write new elements A, C, D, element B is always 0 */
> +		value32 = BIT_SET_TXIQ_ELM_ACD(ele_A, ele_C, ele_D);
> +		rtw_write32(rtwdev, REG_OFDM_0_XB_TX_IQ_IMBALANCE, value32);
> +		value32 = BIT_SET_TXIQ_ELM_C1(ele_C);
> +		rtw_write32_mask(rtwdev, REG_TXIQK_MATRIXB_LSB2_11N, MASKH4BITS,
> +				 value32);
> +		rtw_write32_mask(rtwdev, REG_OFDM_0_ECCA_THRESHOLD, BIT(28),
> +				 ele_A_ext);
> +		break;
> +	}
> +}
> +
> +static void rtw8723b_set_iqk_matrix(struct rtw_dev *rtwdev, s8 ofdm_index,
> +				    u8 path)
> +{
> +	struct rtw_dm_info *dm_info = &rtwdev->dm_info;
> +	u32 ofdm_swing;
> +
> +	ofdm_index = clamp_t(s8, ofdm_index, 0, RTW_OFDM_SWING_TABLE_SIZE - 1);
> +
> +	ofdm_swing = rtw8723b_ofdm_swing_table[ofdm_index];
> +
> +	if (dm_info->iqk.done) {
> +		rtw8723b_set_iqk_matrix_by_result(rtwdev, ofdm_swing, path);
> +		return;
> +	}
> +
> +	switch (path) {
> +	case RF_PATH_A:
> +	default:
> +		rtw_write32(rtwdev, REG_OFDM_0_XA_TX_IQ_IMBALANCE, ofdm_swing);
> +		rtw_write32_mask(rtwdev, REG_TXIQK_MATRIXA_LSB2_11N, MASKH4BITS,
> +				 0x00);
> +		rtw_write32_mask(rtwdev, REG_OFDM_0_ECCA_THRESHOLD, BIT(24),
> +				 0x00);
> +		break;
> +
> +	case RF_PATH_B:
> +		rtw_write32(rtwdev, REG_OFDM_0_XB_TX_IQ_IMBALANCE, ofdm_swing);
> +		rtw_write32_mask(rtwdev, REG_TXIQK_MATRIXB_LSB2_11N, MASKH4BITS,
> +				 0x00);
> +		rtw_write32_mask(rtwdev, REG_OFDM_0_ECCA_THRESHOLD, BIT(28),
> +				 0x00);
> +		break;
> +	}
> +}
> +
> +static u8 rtw8723b_iqk_check_tx_failed(struct rtw_dev *rtwdev)
> +{
> +	s32 tx_x, tx_y;
> +	u32 tx_fail;
> +
> +	rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] 0xeac = 0x%x\n",
> +		rtw_read32(rtwdev, REG_IQK_RES_RY));
> +	rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] 0xe94 = 0x%x, 0xe9c = 0x%x\n",
> +		rtw_read32(rtwdev, REG_IQK_RES_TX),
> +		rtw_read32(rtwdev, REG_IQK_RES_TY));
> +	rtw_dbg(rtwdev, RTW_DBG_RFK,
> +		"[IQK] 0xe90(before IQK) = 0x%x, 0xe98(after IQK) = 0x%x\n",
> +		rtw_read32(rtwdev, REG_IQK_RDY),
> +		rtw_read32(rtwdev, 0xe98));
> +
> +	tx_fail = rtw_read32_mask(rtwdev, REG_IQK_RES_RY, BIT_IQK_TX_FAIL);
> +	tx_x = rtw_read32_mask(rtwdev, REG_IQK_RES_TX, BIT_MASK_RES_TX);
> +	tx_y = rtw_read32_mask(rtwdev, REG_IQK_RES_TY, BIT_MASK_RES_TY);
> +
> +	if (!tx_fail && tx_x != IQK_TX_X_ERR && tx_y != IQK_TX_Y_ERR)
> +		return IQK_TX_OK;
> +
> +	rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] A TX IQK failed\n");
> +
> +	return 0;
> +}
> +
> +static u8 rtw8723b_iqk_check_rx_failed(struct rtw_dev *rtwdev)
> +{
> +	s32 rx_x, rx_y;
> +	u32 rx_fail;
> +
> +	rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] 0xea4 = 0x%x, 0xeac = 0x%x\n",
> +		rtw_read32(rtwdev, REG_IQK_RES_RX),
> +		rtw_read32(rtwdev, REG_IQK_RES_RY));
> +	rtw_dbg(rtwdev, RTW_DBG_RFK,
> +		"[IQK] 0xea0(before IQK) = 0x%x, 0xea8(after IQK) = 0x%x\n",
> +		rtw_read32(rtwdev, 0xea0),
> +		rtw_read32(rtwdev, 0xea8));
> +
> +	rx_fail = rtw_read32_mask(rtwdev, REG_IQK_RES_RY, BIT_IQK_RX_FAIL);
> +	rx_x = rtw_read32_mask(rtwdev, REG_IQK_RES_RX, BIT_MASK_RES_RX);
> +	rx_y = rtw_read32_mask(rtwdev, REG_IQK_RES_RY, BIT_MASK_RES_RY);
> +	rx_y = abs(iqkxy_to_s32(rx_y));
> +
> +	if (!rx_fail && rx_x != IQK_RX_X_ERR && rx_y != IQK_RX_Y_ERR &&
> +	    rx_x < IQK_RX_X_UPPER && rx_x > IQK_RX_X_LOWER &&
> +	     rx_y < IQK_RX_Y_LMT)
> +		return IQK_RX_OK;
> +
> +	rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] A RX IQK failed\n");
> +
> +	return 0;
> +}
> +
> +static u8 rtw8723b_iqk_tx_path_a(struct rtw_dev *rtwdev)
> +{
> +	u32 path_sel;
> +	bool sdio_iqk = rtw_is_8723bs(rtwdev);
> +	u8 status;
> +
> +	rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] path A TX IQK!\n");
> +
> +	/* Save RF path */
> +	path_sel = rtw_read32(rtwdev, REG_BB_SEL_BTG);
> +
> +	/* leave IQK mode */
> +	rtw_write32_mask(rtwdev, REG_FPGA0_IQK_11N, MASKH3BYTES, 0x000000);
> +
> +	/* enable path A PA in TX IQK mode */
> +	rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWE, 0x80000, 0x1);
> +	rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_ADDR, RFREG_MASK,
> +		     sdio_iqk ? 0x18000 : 0x20000);

Where does 0x18000 come from? The vendor driver v5.2.17.1 uses 0x20000 here.

> +	rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_DATA0, RFREG_MASK, 0x0003f);
> +	rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_DATA1, RFREG_MASK, 0xc7f87);
> +
> +	/* Tx IQK setting */
> +	rtw_write32(rtwdev, REG_TXIQK_11N, 0x01007c00);
> +	rtw_write32(rtwdev, REG_RXIQK_11N, 0x01004800);
> +
> +	/* path-A IQK setting */
> +	rtw_write32(rtwdev, REG_TXIQK_TONE_A_11N, 0x18008c1c);
> +	rtw_write32(rtwdev, REG_RXIQK_TONE_A_11N, 0x38008c1c);
> +	rtw_write32(rtwdev, REG_TX_IQK_TONE_B, 0x38008c1c);
> +	rtw_write32(rtwdev, REG_RX_IQK_TONE_B, 0x38008c1c);
> +
> +	rtw_write32(rtwdev, REG_TXIQK_PI_A_11N,
> +		    sdio_iqk ? 0x821303ea : 0x821403ea);

Here, too, it uses the second value.

> +	rtw_write32(rtwdev, REG_RXIQK_PI_A_11N, 0x28110000);
> +	rtw_write32(rtwdev, REG_TXIQK_PI_B, 0x82110000);
> +	rtw_write32(rtwdev, REG_RXIQK_PI_B, 0x28110000);
> +
> +	/* LO calibration setting */
> +	rtw_write32(rtwdev, REG_IQK_AGC_RSP_11N, 0x00462911);
> +
> +	/* enter IQK mode */
> +	rtw_write32_mask(rtwdev, REG_FPGA0_IQK_11N, MASKH3BYTES, 0x808000);
> +
> +	/* ant switch */
> +	rtw_write32(rtwdev, REG_BB_SEL_BTG,
> +		    rtw8723b_iqk_ant_switch_path(rtwdev));
> +
> +	/* GNT_BT = 0 */
> +	rtw_write32(rtwdev, REG_BT_CONTROL_8723B, 0x00000800);
> +
> +	/* One shot, path A LOK & IQK */
> +	rtw_write32(rtwdev, REG_IQK_AGC_PTS_11N, 0xf9000000);
> +	rtw_write32(rtwdev, REG_IQK_AGC_PTS_11N, 0xf8000000);
> +
> +	msleep(IQK_DELAY_TIME_8723B);
> +
> +	/* restore ant path */
> +	rtw_write32(rtwdev, REG_BB_SEL_BTG, path_sel);
> +
> +	/* GNT_BT = 1 */
> +	rtw_write32(rtwdev, REG_BT_CONTROL_8723B, 0x00001800);
> +
> +	/* leave IQK mode */
> +	rtw_write32_mask(rtwdev, REG_FPGA0_IQK_11N, MASKH3BYTES, 0x000000);
> +
> +	/* Check failed */
> +	status = rtw8723b_iqk_check_tx_failed(rtwdev);
> +
> +	return status;
> +}
> +
> +static u8 rtw8723b_iqk_rx_path_a(struct rtw_dev *rtwdev)
> +{
> +	u32 reg_e94, reg_e9c, val32, path_sel;
> +	bool sdio_iqk = rtw_is_8723bs(rtwdev);
> +	u8 status;
> +
> +	rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] path A RX IQK step1!\n");
> +
> +	/* Save RF path */
> +	path_sel = rtw_read32(rtwdev, REG_BB_SEL_BTG);
> +
> +	/* leave IQK mode */
> +	rtw_write32_mask(rtwdev, REG_FPGA0_IQK_11N, MASKH3BYTES, 0x000000);
> +
> +	rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWE, 0x80000, 0x1);
> +	rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_ADDR, RFREG_MASK,
> +		     sdio_iqk ? 0x18000 : 0x30000);

Vendor driver uses the second value.

> +	rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_DATA0, RFREG_MASK, 0x0001f);
> +	rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_DATA1, RFREG_MASK, 0xf7fb7);
> +
> +	/* IQK setting */
> +	rtw_write32(rtwdev, REG_TXIQK_11N, 0x01007c00);
> +	rtw_write32(rtwdev, REG_RXIQK_11N, 0x01004800);
> +
> +	/* path-A IQK setting */
> +	rtw_write32(rtwdev, REG_TXIQK_TONE_A_11N, 0x18008c1c);
> +	rtw_write32(rtwdev, REG_RXIQK_TONE_A_11N, 0x38008c1c);
> +	rtw_write32(rtwdev, REG_TX_IQK_TONE_B, 0x38008c1c);
> +	rtw_write32(rtwdev, REG_RX_IQK_TONE_B, 0x38008c1c);
> +
> +	rtw_write32(rtwdev, REG_TXIQK_PI_A_11N,
> +		    sdio_iqk ? 0x82130ff0 : 0x82160ff0);

Here as well.

> +	rtw_write32(rtwdev, REG_RXIQK_PI_A_11N, 0x28110000);
> +	rtw_write32(rtwdev, REG_TXIQK_PI_B, 0x82110000);
> +	rtw_write32(rtwdev, REG_RXIQK_PI_B, 0x28110000);
> +
> +	/* LO calibration setting */
> +	rtw_write32(rtwdev, REG_IQK_AGC_RSP_11N, 0x0046a911);
> +
> +	/* enter IQK mode */
> +	rtw_write32_mask(rtwdev, REG_FPGA0_IQK_11N, MASKH3BYTES, 0x808000);
> +
> +	/* ant switch */
> +	rtw_write32(rtwdev, REG_BB_SEL_BTG,
> +		    rtw8723b_iqk_ant_switch_path(rtwdev));
> +
> +	/* GNT_BT = 0 (disable BT) */
> +	rtw_write32(rtwdev, REG_BT_CONTROL_8723B, 0x00000800);
> +
> +	/* One shot, path A LOK & IQK */
> +	rtw_write32(rtwdev, REG_IQK_AGC_PTS_11N, 0xf9000000);
> +	rtw_write32(rtwdev, REG_IQK_AGC_PTS_11N, 0xf8000000);
> +
> +	msleep(IQK_DELAY_TIME_8723B);
> +
> +	/* restore ant path */
> +	rtw_write32(rtwdev, REG_BB_SEL_BTG, path_sel);
> +
> +	/* GNT_BT = 1 */
> +	rtw_write32(rtwdev, REG_BT_CONTROL_8723B, 0x00001800);
> +
> +	/* leave IQK mode */
> +	rtw_write32_mask(rtwdev, REG_FPGA0_IQK_11N, MASKH3BYTES, 0x000000);
> +
> +	/* Check failed */

No need for a comment that just repeats what the name of the function
already says.

> +	status = rtw8723b_iqk_check_tx_failed(rtwdev);
> +
> +	/* if Tx not OK, ignore Rx */
> +	if (!status)
> +		return status;
> +
> +	reg_e94 = rtw_read32(rtwdev, REG_IQK_RES_TX);
> +	reg_e9c = rtw_read32(rtwdev, REG_IQK_RES_TY);
> +	val32 = 0x80007c00 | (reg_e94 & 0x3ff0000) |
> +	((reg_e9c & 0x3ff0000) >> 16);
> +	rtw_write32(rtwdev, REG_TXIQK_11N, val32);
> +
> +	rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] path A RX IQK step2!\n");
> +
> +	/* modify RX IQK mode */
> +	rtw_write32_mask(rtwdev, REG_FPGA0_IQK_11N, MASKH3BYTES, 0x000000);
> +	rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWE, 0x80000, 0x1);
> +	rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_ADDR, RFREG_MASK,
> +		     sdio_iqk ? 0x18000 : 0x30000);

Here as well.

> +	rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_DATA0, RFREG_MASK, 0x0001f);
> +	rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_DATA1, RFREG_MASK, 0xf7d77);
> +
> +	/* PA, PAD setting */
> +	rtw_write_rf(rtwdev, RF_PATH_A, 0xdf, RFREG_MASK, 0xf80);
> +	rtw_write_rf(rtwdev, RF_PATH_A, 0x55, RFREG_MASK, 0x4021f);
> +
> +	/* IQK setting */
> +	rtw_write32(rtwdev, REG_RXIQK_11N, 0x01004800);
> +
> +	/* path-A IQK setting */
> +	rtw_write32(rtwdev, REG_TXIQK_TONE_A_11N, 0x38008c1c);
> +	rtw_write32(rtwdev, REG_RXIQK_TONE_A_11N, 0x18008c1c);
> +	rtw_write32(rtwdev, REG_TX_IQK_TONE_B, 0x38008c1c);
> +	rtw_write32(rtwdev, REG_RX_IQK_TONE_B, 0x38008c1c);
> +
> +	rtw_write32(rtwdev, REG_TXIQK_PI_A_11N, 0x82110000);
> +	rtw_write32(rtwdev, REG_RXIQK_PI_A_11N,
> +		    sdio_iqk ? 0x2813001f : 0x2816001f);

Here as well.

> +	rtw_write32(rtwdev, REG_TXIQK_PI_B, 0x82110000);
> +	rtw_write32(rtwdev, REG_RXIQK_PI_B, 0x28110000);
> +
> +	/* LO calibration setting */
> +	rtw_write32(rtwdev, REG_IQK_AGC_RSP_11N, 0x0046a8d1);
> +
> +	/* enter IQK mode */
> +	rtw_write32_mask(rtwdev, REG_FPGA0_IQK_11N, MASKH3BYTES, 0x808000);
> +
> +	/* ant switch */
> +	rtw_write32(rtwdev, REG_BB_SEL_BTG,
> +		    rtw8723b_iqk_ant_switch_path(rtwdev));
> +
> +	/* GNT_BT = 0 */
> +	rtw_write32(rtwdev, REG_BT_CONTROL_8723B, 0x00000800);
> +
> +	/* One shot, path A LOK & IQK */
> +	rtw_write32(rtwdev, REG_IQK_AGC_PTS_11N, 0xf9000000);
> +	rtw_write32(rtwdev, REG_IQK_AGC_PTS_11N, 0xf8000000);
> +
> +	msleep(IQK_DELAY_TIME_8723B);
> +
> +	/* restore ant path */
> +	rtw_write32(rtwdev, REG_BB_SEL_BTG, path_sel);
> +
> +	/* GNT_BT = 1 */
> +	rtw_write32(rtwdev, REG_BT_CONTROL_8723B, 0x00001800);
> +
> +	/* leave IQK mode */
> +	rtw_write32_mask(rtwdev, REG_FPGA0_IQK_11N, MASKH3BYTES, 0x000000);
> +
> +	/* Check failed */
> +
> +	rtw_write_rf(rtwdev, RF_PATH_A, 0xdf, RFREG_MASK, 0x780);
> +
> +	status |= rtw8723b_iqk_check_rx_failed(rtwdev);
> +
> +	return status;
> +}
> +
> +static void
> +rtw8723b_iqk_fill_a_matrix(struct rtw_dev *rtwdev, const s32 result[])
> +{
> +	s32 tx1_a, tx1_a_ext;
> +	s32 tx1_c, tx1_c_ext;
> +	s32 oldval_1;
> +	s32 x, y;
> +
> +	if (result[IQK_S1_TX_X] == 0)
> +		return;
> +
> +	oldval_1 = rtw_read32_mask(rtwdev, REG_OFDM_0_XA_TX_IQ_IMBALANCE,
> +				   BIT_MASK_TXIQ_ELM_D);
> +
> +	x = iqkxy_to_s32(result[IQK_S1_TX_X]);
> +	tx1_a = iqk_mult(x, oldval_1, &tx1_a_ext);
> +	rtw_write32_mask(rtwdev, REG_OFDM_0_XA_TX_IQ_IMBALANCE,
> +			 BIT_MASK_TXIQ_ELM_A, tx1_a);
> +	rtw_write32_mask(rtwdev, REG_OFDM_0_ECCA_THRESHOLD,
> +			 BIT_MASK_OFDM0_EXT_A, tx1_a_ext);
> +
> +	y = iqkxy_to_s32(result[IQK_S1_TX_Y]);
> +	tx1_c = iqk_mult(y, oldval_1, &tx1_c_ext);
> +	rtw_write32_mask(rtwdev, REG_TXIQK_MATRIXA_LSB2_11N, MASKH4BITS,
> +			 BIT_SET_TXIQ_ELM_C1(tx1_c));
> +	rtw_write32_mask(rtwdev, REG_OFDM_0_XA_TX_IQ_IMBALANCE,
> +			 BIT_MASK_TXIQ_ELM_C, BIT_SET_TXIQ_ELM_C2(tx1_c));
> +	rtw_write32_mask(rtwdev, REG_OFDM_0_ECCA_THRESHOLD,
> +			 BIT_MASK_OFDM0_EXT_C, tx1_c_ext);
> +
> +	rtw_dbg(rtwdev, RTW_DBG_RFK,
> +		"[IQK] X = 0x%x, TX1_A = 0x%x, oldval_1 0x%x\n",
> +		x, tx1_a, oldval_1);
> +	rtw_dbg(rtwdev, RTW_DBG_RFK,
> +		"[IQK] Y = 0x%x, TX1_C = 0x%x\n", y, tx1_c);
> +
> +	if (result[IQK_S1_RX_X] == 0)
> +		return;
> +
> +	rtw_write32_mask(rtwdev, REG_A_RXIQI, BIT_MASK_RXIQ_S1_X,
> +			 result[IQK_S1_RX_X]);
> +	rtw_write32_mask(rtwdev, REG_A_RXIQI, BIT_MASK_RXIQ_S1_Y1,
> +			 BIT_SET_RXIQ_S1_Y1(result[IQK_S1_RX_Y]));
> +	rtw_write32_mask(rtwdev, REG_RXIQK_MATRIX_LSB_11N, BIT_MASK_RXIQ_S1_Y2,
> +			 BIT_SET_RXIQ_S1_Y2(result[IQK_S1_RX_Y]));
> +}
> +
> +static void
> +rtw8723b_iqk_fill_b_matrix(struct rtw_dev *rtwdev, const s32 result[])
> +{
> +	s32 tx0_a, tx0_a_ext;
> +	s32 tx0_c, tx0_c_ext;
> +	s32 oldval_0;
> +	s32 x, y;
> +
> +	if (result[IQK_S0_TX_X] == 0)
> +		return;
> +
> +	oldval_0 = rtw_read32_mask(rtwdev, REG_OFDM_0_XB_TX_IQ_IMBALANCE,
> +				   BIT_MASK_TXIQ_ELM_D);
> +
> +	x = iqkxy_to_s32(result[IQK_S0_TX_X]);
> +	tx0_a = iqk_mult(x, oldval_0, &tx0_a_ext);
> +
> +	rtw_write32_mask(rtwdev, REG_OFDM_0_XB_TX_IQ_IMBALANCE,
> +			 BIT_MASK_TXIQ_ELM_A, tx0_a);
> +	rtw_write32_mask(rtwdev, REG_OFDM_0_ECCA_THRESHOLD, BIT(27),
> +			 tx0_a_ext);
> +
> +	y = iqkxy_to_s32(result[IQK_S0_TX_Y]);
> +	tx0_c = iqk_mult(y, oldval_0, &tx0_c_ext);
> +
> +	rtw_write32_mask(rtwdev, REG_TXIQK_MATRIXB_LSB2_11N, MASKH4BITS,
> +			 BIT_SET_TXIQ_ELM_C1(tx0_c));
> +	rtw_write32_mask(rtwdev, REG_OFDM_0_XB_TX_IQ_IMBALANCE,
> +			 BIT_MASK_TXIQ_ELM_C, BIT_SET_TXIQ_ELM_C2(tx0_c));
> +	rtw_write32_mask(rtwdev, REG_OFDM_0_ECCA_THRESHOLD, BIT(25),
> +			 tx0_c_ext);
> +
> +	if (result[IQK_S0_RX_X] == 0)
> +		return;
> +
> +	rtw_write32_mask(rtwdev, REG_B_RXIQI, BIT_MASK_RXIQ_X_S0,
> +			 result[IQK_S0_RX_X]);
> +	rtw_write32_mask(rtwdev, REG_B_RXIQI, BIT_MASK_RXIQ_S1_Y1,
> +			 BIT_SET_RXIQ_S1_Y1(result[IQK_S0_RX_Y]));
> +}
> +
> +static void
> +rtw8723b_iqk_config_mac(struct rtw_dev *rtwdev,
> +			const struct rtw8723x_iqk_backup_regs *backup)
> +{
> +	int i;
> +
> +	rtw_write8(rtwdev, rtw8723x_common.iqk_mac8_regs[0], 0x3f);
> +
> +	for (i = 1; i < RTW8723X_IQK_MAC8_REG_NUM; i++)
> +		rtw_write8(rtwdev, rtw8723x_common.iqk_mac8_regs[i],
> +			   backup->mac8[i] & (~BIT(3)));
> +
> +	/* This MAC backup register needs a byte-wide write. */
> +	rtw_write8(rtwdev, rtw8723x_common.iqk_mac32_regs[0],
> +		   backup->mac32[0] & (~BIT(5)));
> +}
> +
> +static void
> +rtw8723b_iqk_one_round(struct rtw_dev *rtwdev, s32 result[][IQK_NR], u8 t,
> +		       const struct rtw8723x_iqk_backup_regs *backup)
> +{
> +	u32 i;
> +	u8 a_ok;
> +
> +	rtw_dbg(rtwdev, RTW_DBG_RFK,
> +		"[IQK] IQ Calibration for 1T1R_S0/S1 for %d times\n", t);
> +
> +	rtw8723x_iqk_path_adda_on(rtwdev, ADDA_ON_VAL_8723B);
> +	rtw8723b_iqk_config_mac(rtwdev, backup);
> +
> +	rtw_write32_mask(rtwdev, REG_CCK_ANT_SEL_11N, 0x0f000000, 0xf);
> +	rtw_write32(rtwdev, REG_BB_RX_PATH_11N, 0x03a05600);
> +	rtw_write32(rtwdev, REG_TRMUX_11N, 0x000800e4);
> +	rtw_write32(rtwdev, REG_BB_PWR_SAV1_11N, 0x22204000);
> +
> +	/*
> +	 * RX IQ calibration setting for 8723B D cut large current issue
> +	 * when leaving IPS
> +	 */
> +	rtw_write32_mask(rtwdev, REG_FPGA0_IQK_11N, MASKH3BYTES, 0x000000);
> +	rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWE, 0x80000, 0x1);
> +	rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_ADDR, RFREG_MASK, 0x30000);
> +	rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_DATA0, RFREG_MASK, 0x0001f);
> +	rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_DATA1, RFREG_MASK, 0xf7fb7);
> +	rtw_write_rf(rtwdev, RF_PATH_A, 0xed, 0x20, 0x1);
> +	rtw_write_rf(rtwdev, RF_PATH_A, 0x43, RFREG_MASK, 0x60fbd);
> +
> +	for (i = 0; i < PATH_IQK_RETRY; i++) {
> +		a_ok = rtw8723b_iqk_tx_path_a(rtwdev);
> +		if (a_ok == IQK_TX_OK) {

If you invert the condition, this block with long lines can be
indented less.

> +			rtw_dbg(rtwdev, RTW_DBG_RFK,
> +				"[IQK] path A TX IQK success!\n");
> +
> +			rtw_write32_mask(rtwdev, REG_FPGA0_IQK_11N,
> +					 MASKH3BYTES, 0x000000);
> +
> +			result[t][IQK_S1_TX_X] =
> +				rtw_read32_mask(rtwdev, REG_IQK_RES_TX,
> +						BIT_MASK_RES_TX);
> +			result[t][IQK_S1_TX_Y] =
> +				rtw_read32_mask(rtwdev, REG_IQK_RES_TY,
> +						BIT_MASK_RES_TY);
> +			break;
> +		}
> +
> +		rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] path A TX IQK fail!\n");
> +		result[t][IQK_S1_TX_X] = 0x100;
> +		result[t][IQK_S1_TX_Y] = 0x0;
> +	}
> +
> +	for (i = 0; i < PATH_IQK_RETRY; i++) {
> +		a_ok = rtw8723b_iqk_rx_path_a(rtwdev);
> +		if (a_ok == (IQK_TX_OK | IQK_RX_OK)) {
> +			rtw_dbg(rtwdev, RTW_DBG_RFK,
> +				"[IQK] path A RX IQK success!\n");
> +			result[t][IQK_S1_RX_X] =
> +				rtw_read32_mask(rtwdev, REG_IQK_RES_RX,
> +						BIT_MASK_RES_RX);
> +			result[t][IQK_S1_RX_Y] =
> +				rtw_read32_mask(rtwdev, REG_IQK_RES_RY,
> +						BIT_MASK_RES_RY);
> +			break;
> +		}
> +
> +		rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] path A RX IQK fail!\n");
> +		result[t][IQK_S1_RX_X] = 0x100;
> +		result[t][IQK_S1_RX_Y] = 0x0;
> +	}
> +
> +	if (a_ok == 0x0)
> +		rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] path A IQK fail!\n");
> +
> +	/* rtl8723b is 1T1R, so path B is not calibrated. */

It looks like the vendor driver is calibrating path B as well
(phy_path_b_iqk_8723b() and phy_path_b_rx_iqk_8723b()) when the device
has two antennas, and only path A when the device has one antenna.

> +
> +	rtw_write32_mask(rtwdev, REG_FPGA0_IQK_11N, MASKH3BYTES, 0x000000);
> +}
> +
> +static void rtw8723b_phy_calibration(struct rtw_dev *rtwdev)
> +{
> +	struct rtw_dm_info *dm_info = &rtwdev->dm_info;
> +	struct rtw8723x_iqk_backup_regs backup;
> +	s32 result[IQK_ROUND_SIZE][IQK_NR];
> +	u32 bt_control;
> +	bool good;
> +	u8 final_candidate = IQK_ROUND_INVALID;
> +	u8 i, j;
> +
> +	rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] Start!\n");
> +	memset(result, 0, sizeof(result));
> +
> +	rtw8723b_lck(rtwdev);
> +	rtw8723b_inform_rfk_status(rtwdev, true);
> +
> +	/* The LTE path GNT backup that 8723d does is not needed on SDIO. */
> +	rtw8723x_iqk_backup_path_ctrl(rtwdev, &backup);
> +	rtw8723x_iqk_backup_regs(rtwdev, &backup);
> +
> +	/* save default GNT_BT */
> +	bt_control = rtw_read32(rtwdev, REG_BT_CONTROL_8723B);
> +
> +	for (i = IQK_ROUND_0; i <= IQK_ROUND_2; i++) {
> +		if (!rtw_is_8723bs(rtwdev))
> +			rtw8723x_iqk_config_path_ctrl(rtwdev);

I didn't see this in the RTL8723BE or RTL8723BU drivers. I guess it was
copied from another chip?

> +
> +		rtw8723b_iqk_one_round(rtwdev, result, i, &backup);
> +
> +		rtw_dbg(rtwdev, RTW_DBG_RFK,
> +			"[IQK] back to BB mode, load original value!\n");
> +
> +		if (i > IQK_ROUND_0) {
> +			rtw8723x_iqk_restore_regs(rtwdev, &backup);
> +
> +			/* Restore RX initial gain */
> +			rtw_write32_mask(rtwdev, REG_OFDM0_XAAGC1, MASKBYTE0, 0x50);
> +			rtw_write32_mask(rtwdev, REG_OFDM0_XAAGC1, MASKBYTE0, backup.igia);
> +
> +			/* load 0xe30 IQC default value */
> +			rtw_write32(rtwdev, REG_TXIQK_TONE_A_11N, 0x01008c00);
> +			rtw_write32(rtwdev, REG_RXIQK_TONE_A_11N, 0x01008c00);
> +		}
> +
> +		if (!rtw_is_8723bs(rtwdev))
> +			rtw8723x_iqk_restore_path_ctrl(rtwdev, &backup);
> +
> +		for (j = IQK_ROUND_0; j < i; j++) {
> +			good = rtw8723x_iqk_similarity_cmp(rtwdev, result, j, i);
> +			if (good) {
> +				final_candidate = j;
> +				rtw_dbg(rtwdev, RTW_DBG_RFK,
> +					"[IQK] cmp %d:%d final_candidate is %x\n",
> +					j, i, final_candidate);
> +				goto iqk_done;
> +			}
> +		}
> +	}
> +
> +	if (final_candidate == IQK_ROUND_INVALID) {
> +		s32 reg_tmp = 0;
> +
> +		for (i = 0; i < IQK_NR; i++)
> +			reg_tmp += result[IQK_ROUND_HYBRID][i];
> +
> +		if (reg_tmp != 0) {
> +			final_candidate = IQK_ROUND_HYBRID;
> +		} else {
> +			rtw_warn(rtwdev, "IQK failed\n");
> +			goto out;
> +		}
> +	}
> +
> +iqk_done:
> +	if (result[final_candidate][IQK_S1_TX_X])
> +		rtw8723b_iqk_fill_a_matrix(rtwdev, result[final_candidate]);
> +	if (result[final_candidate][IQK_S0_TX_X])
> +		rtw8723b_iqk_fill_b_matrix(rtwdev, result[final_candidate]);
> +
> +	dm_info->iqk.result.s1_x = result[final_candidate][IQK_S1_TX_X];
> +	dm_info->iqk.result.s1_y = result[final_candidate][IQK_S1_TX_Y];
> +	dm_info->iqk.result.s0_x = result[final_candidate][IQK_S0_TX_X];
> +	dm_info->iqk.result.s0_y = result[final_candidate][IQK_S0_TX_Y];
> +	dm_info->iqk.done = true;
> +
> +out:
> +	/* restore RF path */
> +	rtw_write32(rtwdev, REG_BB_SEL_BTG, backup.bb_sel_btg);
> +
> +	/* restore GNT_BT */
> +	rtw_write32(rtwdev, REG_BT_CONTROL_8723B, bt_control);
> +
> +	/* Restore RX mode table parameter */
> +	rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWE, 0x80000, 0x1);
> +	rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_ADDR, RFREG_MASK, 0x18000);
> +	rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_DATA0, RFREG_MASK, 0x0001f);
> +	rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_DATA1, RFREG_MASK, 0xe6177);
> +	rtw_write_rf(rtwdev, RF_PATH_A, 0xed, 0x20, 0x1);
> +	rtw_write_rf(rtwdev, RF_PATH_A, 0x43, RFREG_MASK, 0x300bd);
> +
> +	rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] final_candidate is %x\n",
> +		final_candidate);
> +
> +	for (i = IQK_ROUND_0; i < IQK_ROUND_SIZE; i++)
> +		rtw_dbg(rtwdev, RTW_DBG_RFK,
> +			"[IQK] Result %u: rege94_s1=%x rege9c_s1=%x regea4_s1=%x regeac_s1=%x rege94_s0=%x rege9c_s0=%x regea4_s0=%x regeac_s0=%x %s\n",
> +			i,
> +			result[i][0], result[i][1], result[i][2], result[i][3],
> +			result[i][4], result[i][5], result[i][6], result[i][7],
> +			final_candidate == i ? "(final candidate)" : "");

You can make this two calls to rtw_dbg to avoid such a long line.

> +
> +	rtw_dbg(rtwdev, RTW_DBG_RFK,
> +		"[IQK]0xc80 = 0x%x 0xc94 = 0x%x 0xc14 = 0x%x 0xca0 = 0x%x\n",
> +	rtw_read32(rtwdev, REG_OFDM_0_XA_TX_IQ_IMBALANCE),
> +		rtw_read32(rtwdev, REG_TXIQK_MATRIXA_LSB2_11N),
> +		rtw_read32(rtwdev, REG_A_RXIQI),
> +		rtw_read32(rtwdev, REG_RXIQK_MATRIX_LSB_11N));
> +	rtw_dbg(rtwdev, RTW_DBG_RFK,
> +		"[IQK]0xcd0 = 0x%x 0xcd4 = 0x%x 0xcd8 = 0x%x\n",
> +	rtw_read32(rtwdev, REG_TXIQ_AB_S0),
> +		rtw_read32(rtwdev, REG_TXIQ_CD_S0),
> +		rtw_read32(rtwdev, REG_RXIQ_AB_S0));
> +
> +	rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] finished\n");
> +
> +	rtw8723b_inform_rfk_status(rtwdev, false);
> +}
> +
> +static void rtw8723b_pwrtrack_set_ofdm_pwr(struct rtw_dev *rtwdev, u8 path,
> +					   s8 swing_idx, s8 txagc_idx)
> +{
> +	struct rtw_dm_info *dm_info = &rtwdev->dm_info;
> +
> +	dm_info->txagc_remnant_ofdm[path] = txagc_idx;
> +
> +	rtw8723b_set_iqk_matrix(rtwdev, swing_idx, path);
> +}
> +
> +static void rtw8723b_pwrtrack_set_cck_pwr(struct rtw_dev *rtwdev, s8 swing_idx,
> +					  s8 txagc_idx)
> +{
> +	struct rtw_dm_info *dm_info = &rtwdev->dm_info;
> +
> +	dm_info->txagc_remnant_cck = txagc_idx;
> +
> +	swing_idx = clamp_t(s8, swing_idx, 0, RTW_CCK_SWING_TABLE_SIZE - 1);
> +
> +	BUILD_BUG_ON(ARRAY_SIZE(rtw8723b_cck_pwr_regs) !=
> +		     ARRAY_SIZE(rtw8723b_cck_swing_table_ch1_ch13[0]));
> +
> +	/* Only ch1-13 is wired up; channel 14 is Japan-only and unreachable. */

If I change my country code to JP and trigger a scan, rtw88 visits
channel 14.

> +	for (int i = 0; i < ARRAY_SIZE(rtw8723b_cck_pwr_regs); i++)
> +		rtw_write8(rtwdev, rtw8723b_cck_pwr_regs[i],

These register addresses are consecutive values, there is no need
to put them in an array.

> +			   rtw8723b_cck_swing_table_ch1_ch13[swing_idx][i]);
> +}
> +
> +static void rtw8723b_pwrtrack_set(struct rtw_dev *rtwdev, u8 path)
> +{
> +	struct rtw_dm_info *dm_info = &rtwdev->dm_info;
> +	struct rtw_hal *hal = &rtwdev->hal;
> +	u8 limit_ofdm;
> +	/* 8703b and 8723d seem to use RTW_CCK_SWING_TABLE_SIZE */
> +	u8 limit_cck = 28; /* -2dB */
> +	s8 final_ofdm_swing_index;
> +	s8 final_cck_swing_index;
> +
> +	limit_ofdm = rtw8723x_pwrtrack_get_limit_ofdm(rtwdev);
> +
> +	final_ofdm_swing_index = dm_info->default_ofdm_index +
> +				 dm_info->delta_power_index[path];
> +	final_cck_swing_index = dm_info->default_cck_index +
> +				dm_info->delta_power_index[path];
> +
> +	if (final_ofdm_swing_index > limit_ofdm)
> +		rtw8723b_pwrtrack_set_ofdm_pwr(rtwdev, path, limit_ofdm,
> +					       final_ofdm_swing_index - limit_ofdm);
> +	else if (final_ofdm_swing_index < 0)
> +		rtw8723b_pwrtrack_set_ofdm_pwr(rtwdev, path, 0,
> +					       final_ofdm_swing_index);
> +	else
> +		rtw8723b_pwrtrack_set_ofdm_pwr(rtwdev, path, final_ofdm_swing_index, 0);
> +
> +	if (final_cck_swing_index > limit_cck)
> +		rtw8723b_pwrtrack_set_cck_pwr(rtwdev, limit_cck,
> +					      final_cck_swing_index - limit_cck);
> +	else if (final_cck_swing_index < 0)
> +		rtw8723b_pwrtrack_set_cck_pwr(rtwdev, 0,
> +					      final_cck_swing_index);
> +	else
> +		rtw8723b_pwrtrack_set_cck_pwr(rtwdev, final_cck_swing_index, 0);
> +
> +	rtw_phy_set_tx_power_level(rtwdev, hal->current_channel);
> +}
> +
> +static void rtw8723b_phy_pwrtrack(struct rtw_dev *rtwdev)
> +{
> +	struct rtw_dm_info *dm_info = &rtwdev->dm_info;
> +	struct rtw_swing_table swing_table;
> +	u8 thermal_value, delta, path;
> +	bool do_iqk = false;
> +
> +	rtw_phy_config_swing_table(rtwdev, &swing_table);
> +
> +	if (rtwdev->efuse.thermal_meter[0] == 0xff)
> +		return;
> +
> +	thermal_value = rtw_read_rf(rtwdev, RF_PATH_A, RF_T_METER, 0xfc00);
> +
> +	/* Average the thermal meter readings. */
> +	rtw_phy_pwrtrack_avg(rtwdev, thermal_value, RF_PATH_A);
> +
> +	do_iqk = rtw_phy_pwrtrack_need_iqk(rtwdev);
> +
> +	if (do_iqk)
> +		rtw8723x_lck(rtwdev);
> +
> +	if (dm_info->pwr_trk_init_trigger)
> +		dm_info->pwr_trk_init_trigger = false;
> +	else if (!rtw_phy_pwrtrack_thermal_changed(rtwdev, thermal_value,
> +						   RF_PATH_A))
> +		goto iqk;
> +
> +	delta = rtw_phy_pwrtrack_get_delta(rtwdev, RF_PATH_A);
> +
> +	/* NOTE: also done in rtw_phy_pwrtrack_get_delta */

Is it necessary to do it again?

> +	delta = min_t(u8, delta, RTW_PWR_TRK_TBL_SZ - 1);
> +
> +	for (path = 0; path < rtwdev->hal.rf_path_num; path++) {
> +		s8 delta_cur, delta_last;
> +
> +		delta_last = dm_info->delta_power_index[path];
> +		delta_cur = rtw_phy_pwrtrack_get_pwridx(rtwdev, &swing_table,
> +							path, RF_PATH_A, delta);
> +		if (delta_last == delta_cur)
> +			continue;
> +
> +		dm_info->delta_power_index[path] = delta_cur;
> +		rtw8723b_pwrtrack_set(rtwdev, path);
> +	}
> +
> +iqk:
> +	if (do_iqk)
> +		rtw8723b_phy_calibration(rtwdev);

The vendor driver doesn't redo IQK here.

> +}
> +
> +static void rtw8723b_pwr_track(struct rtw_dev *rtwdev)
> +{
> +	struct rtw_efuse *efuse = &rtwdev->efuse;
> +	struct rtw_dm_info *dm_info = &rtwdev->dm_info;
> +
> +	if (efuse->power_track_type != 0) {
> +		rtw_warn(rtwdev, "unsupported power track type\n");

This function runs every two seconds, forever. Please put this
warning elsewhere, like rtw8723b_read_efuse(), to avoid filling
the kernel log. (Or create rtw_warn_once()).

> +		return;
> +	}
> +
> +	if (!dm_info->pwr_trk_triggered) {
> +		rtw_write_rf(rtwdev, RF_PATH_A, RF_T_METER,
> +			     GENMASK(17, 16), 0x03);
> +		dm_info->pwr_trk_triggered = true;
> +		return;
> +	}
> +
> +	rtw8723b_phy_pwrtrack(rtwdev);
> +	dm_info->pwr_trk_triggered = false;
> +}
> +
> +/*
> + * The vendor sequence for this chip differs from rtw8723x_coex_cfg_init():
> + * REG_BT_TDMA_TIME is written whole, PTA pins and REG_QUEUE_CTRL untouched.
> + */
> +static void rtw8723b_coex_cfg_init(struct rtw_dev *rtwdev)
> +{
> +	/* enable TBTT interrupt */
> +	rtw_write8_set(rtwdev, REG_BCN_CTRL, BIT_EN_BCN_FUNCTION);
> +
> +	/* BT report packet sample rate, 0x790[5:0] = 0x5 */
> +	rtw_write8(rtwdev, REG_BT_TDMA_TIME, 0x5);
> +
> +	/* enable BT counter statistics */
> +	rtw_write8(rtwdev, REG_BT_STAT_CTRL, 0x1);
> +
> +	/* enable PTA (3-wire function from BT side) */
> +	rtw_write8_mask(rtwdev, REG_GPIO_MUXCFG, BIT_BT_PTA_EN, 0x1);
> +}
> +
> +static void rtw8723b_coex_set_gnt_fix(struct rtw_dev *rtwdev)
> +{
> +	/* intentionally empty: rtw8723d's coex_set_gnt_fix is empty too */
> +}
> +
> +static void rtw8723b_coex_set_gnt_debug(struct rtw_dev *rtwdev)
> +{
> +	/* GNT_BT debug routing is not implemented; not needed for operation. */
> +}
> +
> +static bool rtw8723b_coex_ant_is_aux(struct rtw_dev *rtwdev)
> +{
> +	return !!(rtwdev->efuse.bt_setting & BIT(6));
> +}
> +
> +static void rtw8723b_coex_write8_verify(struct rtw_dev *rtwdev, u32 addr,
> +					u8 value)
> +{
> +	u8 readback;
> +
> +	rtw_write8(rtwdev, addr, value);
> +	readback = rtw_read8(rtwdev, addr);
> +	if (readback == value)
> +		return;
> +
> +	usleep_range(10, 11);
> +	rtw_write8(rtwdev, addr, value);
> +}
> +
> +static void rtw8723b_coex_set_ant_ctrl_by_wifi(struct rtw_dev *rtwdev)
> +{
> +	/* 0x4c[23] = 1, 0x4c[24] = 0: antenna control by 0x64. */
> +	rtw_write32_clr(rtwdev, REG_LED_CFG, BIT(24));
> +	rtw_write32_set(rtwdev, REG_LED_CFG, BIT(23));
> +}
> +
> +static void rtw8723b_coex_set_ant_ctrl_by_bt(struct rtw_dev *rtwdev)
> +{
> +	/* 0x4c[24:23] = 0: antenna control by BT_RFE_CTRL. */
> +	rtw_write32_clr(rtwdev, REG_LED_CFG, BIT(23) | BIT(24));
> +}
> +
> +static void rtw8723b_coex_cfg_ant_buffer(struct rtw_dev *rtwdev)
> +{
> +	u8 sys_func_before;
> +
> +	sys_func_before = rtw_read8(rtwdev, REG_SYS_FUNC_EN);
> +	if ((sys_func_before & WLAN_SYS_FUNC_BB_ENABLE) !=
> +	    WLAN_SYS_FUNC_BB_ENABLE) {
> +		rtw_write8_set(rtwdev, REG_SYS_FUNC_EN,
> +			       WLAN_SYS_FUNC_BB_ENABLE);
> +		usleep_range(10, 11);
> +	}

Not sure why you need to touch REG_SYS_FUNC_EN here. The vendor
driver doesn't do it.

> +
> +	rtw_write8_set(rtwdev, REG_PWR_DATA + 1,
> +		       BIT_EEPRPAD_RFE_CTRL_EN >> 8);
> +	rtw8723b_coex_write8_verify(rtwdev, REG_RFE_CTRL_E, 0xff);

The vendor driver uses a normal rtw_write8() here.

> +	rtw_write8_mask(rtwdev, REG_RFE_CTRL_ANT_SW, BIT_RFE_CTRL_ANT_SW_SEL, 0x3);
> +	rtw_write8(rtwdev, REG_RFE_CTRL_ANTA_SRC, 0x77);
> +}
> +
> +static u32 rtw8723b_coex_write_bb_sel_btg(struct rtw_dev *rtwdev, u32 value)
> +{
> +	u32 readback;
> +	u8 sys_func_before;
> +
> +	if (rtw_hci_type(rtwdev) != RTW_HCI_TYPE_SDIO) {
> +		rtw_write32(rtwdev, REG_BB_SEL_BTG, value);
> +		return rtw_read32(rtwdev, REG_BB_SEL_BTG);
> +	}
> +
> +	sys_func_before = rtw_read8(rtwdev, REG_SYS_FUNC_EN);
> +	if ((sys_func_before & WLAN_SYS_FUNC_BB_ENABLE) !=
> +	    WLAN_SYS_FUNC_BB_ENABLE) {
> +		rtw_write8_set(rtwdev, REG_SYS_FUNC_EN,
> +			       WLAN_SYS_FUNC_BB_ENABLE);
> +		usleep_range(10, 11);
> +	}
> +
> +	rtw_write32(rtwdev, REG_BB_SEL_BTG, value);
> +	readback = rtw_read32(rtwdev, REG_BB_SEL_BTG);
> +	if (readback == value)
> +		return readback;
> +
> +	rtw_write8_set(rtwdev, REG_SYS_FUNC_EN, WLAN_SYS_FUNC_BB_ENABLE);
> +	usleep_range(10, 11);
> +	rtw_write32(rtwdev, REG_BB_SEL_BTG, value);
> +
> +	return rtw_read32(rtwdev, REG_BB_SEL_BTG);

All this looks strange too. What happens if you eliminate this function
and write REG_BB_SEL_BTG with a simple rtw_write32()?

> +}
> +
> +static u32 rtw8723b_coex_ant_path_value(struct rtw_dev *rtwdev, u8 pos_type)
> +{
> +	bool aux = rtw8723b_coex_ant_is_aux(rtwdev);
> +
> +	switch (pos_type) {
> +	case COEX_SWITCH_TO_BT:
> +		return aux ? 0x0 : 0x280;
> +	case COEX_SWITCH_TO_WLG:
> +	case COEX_SWITCH_TO_WLA:
> +		return aux ? 0x280 : 0x0;
> +	case COEX_SWITCH_TO_WLG_BT:
> +	case COEX_SWITCH_TO_NOCARE:
> +	default:
> +		return aux ? 0x80 : 0x200;
> +	}
> +}
> +
> +static void rtw8723b_coex_cfg_ant_switch(struct rtw_dev *rtwdev,
> +					 u8 ctrl_type, u8 pos_type)
> +{
> +	u32 ant_path;
> +
> +	if (rtw_hci_type(rtwdev) != RTW_HCI_TYPE_SDIO)
> +		return;
> +
> +	if (ctrl_type == COEX_SWITCH_CTRL_BY_BT) {
> +		rtw_write8(rtwdev, REG_GNT_BT, 0x18);
> +		rtw_write8(rtwdev, REG_BT_COEX_ENH_INTR_CTRL, 0x4);
> +		rtw_write8_clr(rtwdev, REG_BT_ANT_SEL_8723B,
> +			       BIT_BT_SEL_BY_WIFI_8723B);
> +		rtw8723b_coex_set_ant_ctrl_by_bt(rtwdev);
> +		ant_path = rtw8723b_coex_ant_path_value(rtwdev,
> +							COEX_SWITCH_TO_BT);
> +		rtw8723b_coex_write_bb_sel_btg(rtwdev, ant_path);
> +
> +		rtw_dbg(rtwdev, RTW_DBG_COEX,
> +			"[BTCoex], 8723bs ant switch by BT BB_SEL_BTG=0x%08x 0x4c=0x%08x 0x67=0x%02x 0x765=0x%02x 0x76e=0x%02x\n",
> +			rtw_read32(rtwdev, REG_BB_SEL_BTG),
> +			rtw_read32(rtwdev, REG_LED_CFG),
> +			rtw_read8(rtwdev, REG_BT_ANT_SEL_8723B),
> +			rtw_read8(rtwdev, REG_GNT_BT),
> +			rtw_read8(rtwdev, REG_BT_COEX_ENH_INTR_CTRL));
> +		return;
> +	}
> +
> +	rtw8723b_coex_set_ant_ctrl_by_wifi(rtwdev);
> +	rtw_write8(rtwdev, REG_BT_ANT_SEL_8723B, 0x20);
> +
> +	if (ctrl_type == COEX_SWITCH_CTRL_BY_BBSW &&
> +	    pos_type == COEX_SWITCH_TO_BT) {
> +		rtw_write8(rtwdev, REG_GNT_BT, 0x18);
> +		rtw_write8(rtwdev, REG_BT_COEX_ENH_INTR_CTRL, 0x4);
> +	} else {
> +		if (rtw_read8(rtwdev, REG_GNT_BT) != 0)
> +			rtw_write8(rtwdev, REG_GNT_BT, 0x0);
> +
> +		if (rtw_read8(rtwdev, REG_BT_COEX_ENH_INTR_CTRL) != 0xc)
> +			rtw_write8(rtwdev, REG_BT_COEX_ENH_INTR_CTRL, 0xc);
> +	}
> +
> +	if (ctrl_type == COEX_SWITCH_CTRL_BY_BBSW)
> +		ant_path = rtw8723b_coex_ant_path_value(rtwdev, pos_type);
> +	else
> +		ant_path = rtw8723b_coex_ant_path_value(rtwdev,
> +							COEX_SWITCH_TO_NOCARE);
> +
> +	rtw8723b_coex_write_bb_sel_btg(rtwdev, ant_path);
> +	rtw8723b_sdio_restore_pad_ctrl(rtwdev,
> +				       ctrl_type == COEX_SWITCH_CTRL_BY_PTA);
> +
> +	rtw_dbg(rtwdev, RTW_DBG_COEX,
> +		"[BTCoex], 8723bs ant switch ctrl=%u pos=%u BB_SEL_BTG=0x%08x 0x4c=0x%08x 0x67=0x%02x 0x765=0x%02x 0x76e=0x%02x\n",
> +		ctrl_type, pos_type, rtw_read32(rtwdev, REG_BB_SEL_BTG),
> +		rtw_read32(rtwdev, REG_LED_CFG),
> +		rtw_read8(rtwdev, REG_BT_ANT_SEL_8723B),
> +		rtw_read8(rtwdev, REG_GNT_BT),
> +		rtw_read8(rtwdev, REG_BT_COEX_ENH_INTR_CTRL));
> +}
> +
> +static void rtw8723b_coex_set_rfe_type(struct rtw_dev *rtwdev)
> +{
> +	struct rtw_coex *coex = &rtwdev->coex;
> +	struct rtw_coex_rfe *coex_rfe = &coex->rfe;
> +	enum rtw_hci_type hci_type = rtw_hci_type(rtwdev);
> +	u32 reg;
> +	bool aux = rtw8723b_coex_ant_is_aux(rtwdev);
> +
> +	coex_rfe->rfe_module_type = rtwdev->efuse.rfe_option;
> +	coex_rfe->ant_switch_polarity = aux ? 1 : 0;
> +	coex_rfe->ant_switch_exist = hci_type == RTW_HCI_TYPE_SDIO;
> +	coex_rfe->ant_switch_with_bt = false;
> +	coex_rfe->ant_switch_diversity = false;
> +	coex_rfe->wlg_at_btg = true;
> +
> +	rtw_write8(rtwdev, REG_BT_ANT_SEL_8723B, 0x20);
> +
> +	/* set GRAN_BT = 1 */
> +	rtw_write8(rtwdev, REG_GNT_BT, 0x18);
> +
> +	/* set WLAN_ACT = 0 */
> +	rtw_write8(rtwdev, REG_BT_COEX_ENH_INTR_CTRL, 0x4);
> +
> +	switch (hci_type) {
> +	case RTW_HCI_TYPE_USB:
> +		rtw8723b_coex_write_bb_sel_btg(rtwdev, 0x0);
> +		rtw_write8(rtwdev, 0xfe08, 0x1);
> +		break;
> +	case RTW_HCI_TYPE_PCIE:
> +		reg = 0x384;
> +		/* 0xc3[6]: 0 = S1 (main, path A), 1 = S0 (aux, path B). */
> +		if (aux) {
> +			rtw8723b_coex_write_bb_sel_btg(rtwdev, 0x0);
> +			rtw_write8(rtwdev, reg, 0x1);
> +		} else {
> +			rtw8723b_coex_write_bb_sel_btg(rtwdev, 0x280);
> +			rtw_write8(rtwdev, reg, 0x0);
> +		}
> +		break;
> +	case RTW_HCI_TYPE_SDIO:
> +		/*
> +		 * Internal switch: WiFi drives S0/S1, firmware gets the
> +		 * inverse hint.
> +		 */
> +		rtw_write_rf(rtwdev, RF_PATH_A, RF_WLINT, RFREG_MASK, 0x0780);
> +
> +		if (aux) {
> +			rtw8723b_coex_write_bb_sel_btg(rtwdev, 0x0);
> +			rtw_write8(rtwdev, REG_SDIO_H2C, 0x1);
> +		} else {
> +			rtw8723b_coex_write_bb_sel_btg(rtwdev, 0x280);
> +			rtw_write8(rtwdev, REG_SDIO_H2C, 0x0);
> +		}
> +
> +		rtw8723b_coex_set_ant_ctrl_by_wifi(rtwdev);
> +		rtw_write8_mask(rtwdev, REG_PAD_CTRL1,
> +				BIT_SW_DPDT_SEL_DATA, 0x0);
> +		rtw8723b_coex_cfg_ant_buffer(rtwdev);
> +		rtw8723b_sdio_restore_pad_ctrl(rtwdev, false);
> +
> +		/* COEX_ANT_SEL_RSV is sent later from rtw_power_on(). */
> +		break;
> +	default:
> +		break;
> +	}
> +}
> +
> +static void rtw8723b_coex_set_wl_tx_power(struct rtw_dev *rtwdev, u8 wl_pwr)
> +{
> +	/* Deferred: 8723d adjusts WL Tx power (0xb2/0x90) with BT on. */
> +}
> +
> +static void rtw8723b_coex_set_wl_rx_gain(struct rtw_dev *rtwdev, bool low_gain)
> +{
> +	/* Deferred: 8723d lowers the WL Rx AGC while BT is active. */
> +}
> +
> +static void rtw8723b_cfg_ldo25(struct rtw_dev *rtwdev, bool enable)
> +{
> +	/* Nothing to do: rtw88 only reads the efuse, it never writes it. */
> +}
> +
> +static void rtw8723b_fill_txdesc_checksum(struct rtw_dev *rtwdev,
> +					  struct rtw_tx_pkt_info *pkt_info,
> +					  u8 *txdesc)
> +{
> +	struct rtw_tx_desc *tx_desc = (struct rtw_tx_desc *)txdesc;
> +	const u8 *data = txdesc;
> +	u16 checksum = 0;
> +	int words = 32 / 2;
> +
> +	/* Unlike the shared 8723x helper, the checksum is not inverted here. */
> +	le32p_replace_bits(&tx_desc->w7, 0, RTW_TX_DESC_W7_TXDESC_CHECKSUM);
> +
> +	while (words--) {
> +		checksum ^= get_unaligned_le16(data);
> +		data += sizeof(__le16);
> +	}
> +
> +	le32p_replace_bits(&tx_desc->w7, checksum,
> +			   RTW_TX_DESC_W7_TXDESC_CHECKSUM);
> +}
> +
> +static int rtw8723b_read_efuse(struct rtw_dev *rtwdev, u8 *log_map)
> +{
> +	struct rtw_efuse *efuse = &rtwdev->efuse;
> +	int ret;
> +
> +	ret = rtw8723x_read_efuse(rtwdev, log_map);
> +	if (ret)
> +		return ret;
> +
> +	/*
> +	 * No firmware hardware feature report exists, so fill the hardware
> +	 * capability here; a zero stream count kills the HT MCS set.
> +	 */
> +	efuse->hw_cap.nss = max_t(u8, rtwdev->hal.rf_path_num, 1);
> +	efuse->hw_cap.ant_num = efuse->hw_cap.nss;
> +	efuse->hw_cap.bw = BIT(RTW_CHANNEL_WIDTH_20) |
> +			   BIT(RTW_CHANNEL_WIDTH_40);
> +
> +	return 0;
> +}
> +
> +static const struct rtw_chip_ops rtw8723b_ops = {
> +	.power_on		= rtw_power_on,
> +	.power_off		= rtw_power_off,
> +
> +	.mac_init		= rtw8723b_mac_init,
> +	.mac_postinit		= rtw8723x_mac_postinit,
> +
> +	.dump_fw_crash		= NULL,
> +	/*
> +	 * 8723d sets REG_HCI_OPT_CTRL BIT_USB_SUS_DIS in its shutdown
> +	 * function; that is USB-only.
> +	 */
> +	.shutdown		= NULL,
> +	.read_efuse		= rtw8723b_read_efuse,
> +	.phy_set_param		= rtw8723b_phy_set_param,
> +
> +	.set_channel		= rtw8723b_set_channel,
> +
> +	.query_phy_status	= rtw8723b_query_phy_status,
> +	.read_rf		= rtw_phy_read_rf_sipi,
> +	.write_rf		= rtw_phy_write_rf_reg_sipi,
> +	.set_tx_power_index	= rtw8723x_set_tx_power_index,
> +	.rsvd_page_dump		= NULL,
> +	.set_antenna		= NULL,
> +	.cfg_ldo25		= rtw8723b_cfg_ldo25,
> +	.efuse_grant		= rtw8723b_efuse_grant,
> +	.set_ampdu_factor	= NULL,
> +	.false_alarm_statistics	= rtw8723x_false_alarm_statistics,
> +	.phy_calibration	= rtw8723b_phy_calibration,
> +	.dpk_track		= NULL,
> +	/* REG_CSRATIO does not exist on this chip generation. */
> +	.cck_pd_set		= NULL,

You can use rtw88xxa_phy_cck_pd_set() from rtw88xxa.c for this
chip too.

> +	.pwr_track		= rtw8723b_pwr_track,
> +	.config_bfee		= NULL,
> +	.set_gid_table		= NULL,
> +	.cfg_csi_rate		= NULL,
> +	.adaptivity_init	= NULL,
> +	.adaptivity		= NULL,
> +	.cfo_init		= NULL,
> +	.cfo_track		= NULL,
> +	.config_tx_path		= NULL,
> +	.config_txrx_mode	= NULL,
> +	.led_set		= NULL,
> +	.fill_txdesc_checksum	= rtw8723b_fill_txdesc_checksum,
> +
> +	.coex_set_init		= rtw8723b_coex_cfg_init,
> +	.coex_set_ant_switch	= rtw8723b_coex_cfg_ant_switch,
> +	.coex_set_gnt_fix	= rtw8723b_coex_set_gnt_fix,
> +	.coex_set_gnt_debug	= rtw8723b_coex_set_gnt_debug,
> +	.coex_set_rfe_type	= rtw8723b_coex_set_rfe_type,
> +	.coex_set_wl_tx_power	= rtw8723b_coex_set_wl_tx_power,
> +	.coex_set_wl_rx_gain	= rtw8723b_coex_set_wl_rx_gain,
> +};
> +
> +const struct rtw_chip_info rtw8723b_hw_spec = {
> +	.ops = &rtw8723b_ops,
> +	.id = RTW_CHIP_TYPE_8723B,
> +	.fw_name = "rtw88/rtw8723b_fw.bin",
> +	.wlan_cpu = RTW_WCPU_8051,
> +	.tx_pkt_desc_sz = 40,
> +	.tx_buf_desc_sz = 16,
> +	.rx_pkt_desc_sz = 24,
> +	.rx_buf_desc_sz = 8,
> +	.phy_efuse_size = 512,
> +	.log_efuse_size = 512,
> +	.ptct_efuse_size = 15,
> +	.txff_size = 32768,
> +	.rxff_size = 16384,
> +	.rsvd_drv_pg_num = 8,
> +	.txgi_factor = 1,
> +	.is_pwr_by_rate_dec = true,
> +	.max_power_index = 0x3f,
> +	.csi_buf_pg_num = 0,
> +	.band = RTW_BAND_2G,
> +	.page_size = TX_PAGE_SIZE,
> +	.dig_min = 0x20,
> +	.usb_tx_agg_desc_num = 1,

The RTL8723BU vendor driver v5.2.17 sets this to 6.

> +	/*
> +	 * The firmware reports id 0xfd instead of C2H_HW_FEATURE_REPORT, so
> +	 * the hardware feature report is not supported on this chip.
> +	 */
> +	.hw_feature_report = false,
> +	.c2h_ra_report_size = 4,
> +	.old_datarate_fb_limit = true,
> +	.path_div_supported = false,
> +	.ht_supported = true,
> +	.vht_supported = false,
> +	.lps_deep_mode_supported = 0,
> +	.sys_func_en = 0xfd,
> +	.pwr_on_seq = card_enable_flow_8723b,
> +	.pwr_off_seq = card_disable_flow_8723b,
> +	.page_table = page_table_8723b,
> +	.rqpn_table = rqpn_table_8723b,
> +	/* same shared table as the sibling rtw8703b and rtw8723d */
> +	.prioq_addrs = &rtw8723x_common.prioq_addrs,
> +	/* used only in pci.c, not needed for SDIO devices */
> +	.intf_table = NULL,
> +	.dig = rtw8723x_common.dig,
> +	.dig_cck = rtw8723x_common.dig_cck,

This chip doesn't have dig_cck.

> +	.rf_sipi_addr = {0x840, 0x844},
> +	.rf_sipi_read_addr = rtw8723x_common.rf_sipi_addr,
> +	.fix_rf_phy_num = 2,
> +	/* This chip has no LTE coex registers. */
> +	.ltecoex_addr = NULL,
> +	.mac_tbl = &rtw8723b_mac_tbl,
> +	.agc_tbl = &rtw8723b_agc_tbl,
> +	.bb_tbl = &rtw8723b_bb_tbl,
> +	.rf_tbl = {&rtw8723b_rf_a_tbl},
> +	.rfe_defs = rtw8723b_rfe_defs,
> +	.rfe_defs_size = ARRAY_SIZE(rtw8723b_rfe_defs),
> +	.iqk_threshold = 8,
> +	.rx_ldpc = false,
> +	.tx_stbc = false,
> +	.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
> +	.max_scan_ie_len = IEEE80211_MAX_DATA_LEN,
> +	.coex_para_ver = 20180201,	/* glcoex_ver_date_8723b_1ant */
> +	.bt_desired_ver = 0x6d,
> +	.scbd_support = false,
> +	.new_scbd10_def = true,
> +	.ble_hid_profile_support = false,
> +	.wl_mimo_ps_support = false,
> +	.pstdma_type = COEX_PSTDMA_FORCE_LPSOFF,
> +	.bt_rssi_type = COEX_BTRSSI_RATIO,
> +	.ant_isolation = 15,
> +	.rssi_tolerance = 2,
> +	.wl_rssi_step = wl_rssi_step_8723b,
> +	.bt_rssi_step = bt_rssi_step_8723b,
> +	.table_sant_num = ARRAY_SIZE(table_sant_8723b),
> +	.table_sant = table_sant_8723b,
> +	.table_nsant_num = ARRAY_SIZE(table_nsant_8723b),
> +	.table_nsant = table_nsant_8723b,
> +	.tdma_sant_num = ARRAY_SIZE(tdma_sant_8723b),
> +	.tdma_sant = tdma_sant_8723b,
> +	.tdma_nsant_num = ARRAY_SIZE(tdma_nsant_8723b),
> +	.tdma_nsant = tdma_nsant_8723b,
> +	.wl_rf_para_num = ARRAY_SIZE(rf_para_tx_8723b),
> +	.wl_rf_para_tx = rf_para_tx_8723b,
> +	.wl_rf_para_rx = rf_para_rx_8723b,
> +	.bt_afh_span_bw20 = 0x20,
> +	.bt_afh_span_bw40 = 0x30,
> +	.afh_5g_num =  ARRAY_SIZE(afh_5g_8723b),
> +	.afh_5g = afh_5g_8723b,
> +	/* BTG_SEL is driven by the cardemu_to_act power sequence instead. */
> +	.btg_reg = NULL,
> +	.coex_info_hw_regs_num = 0,
> +	.coex_info_hw_regs = NULL,
> +};
> +EXPORT_SYMBOL(rtw8723b_hw_spec);
> +
> +MODULE_FIRMWARE("rtw88/rtw8723b_fw.bin");
> +
> +MODULE_AUTHOR("Luka Gejak <luka.gejak@linux.dev>");
> +MODULE_AUTHOR("Michael Straube <straube.linux@gmail.com>");
> +MODULE_DESCRIPTION("Realtek 802.11n wireless 8723b driver");
> +MODULE_LICENSE("Dual BSD/GPL");
> diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723b.h b/drivers/net/wireless/realtek/rtw88/rtw8723b.h
> new file mode 100644
> index 000000000000..181782ec3f1b
> --- /dev/null
> +++ b/drivers/net/wireless/realtek/rtw88/rtw8723b.h
> @@ -0,0 +1,13 @@
> +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
> +/*
> + * Copyright(c) 2026 Realtek Corporation
> + */
> +
> +#ifndef __RTW8723B_H__
> +#define __RTW8723B_H__
> +
> +#include "rtw8723x.h"
> +
> +extern const struct rtw_chip_info rtw8723b_hw_spec;
> +
> +#endif


  reply	other threads:[~2026-09-27 15:21 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-23 21:35 [PATCH v4 0/6] wifi: rtw88: add RTL8723B/RTL8723BS support Luka Gejak
2026-09-23 21:35 ` [PATCH v4 1/6] wifi: rtw88: 8723b: add the RTL8723B register definitions Luka Gejak
2026-09-27 15:20   ` Bitterblue Smith
2026-09-23 21:35 ` [PATCH v4 2/6] wifi: rtw88: 8723b: add the RTL8723B BB, RF and AGC tables Luka Gejak
2026-09-23 21:35 ` [PATCH v4 3/6] wifi: rtw88: 8723b: add the RTL8723B chip driver Luka Gejak
2026-09-27 15:21   ` Bitterblue Smith [this message]
2026-09-27 17:29     ` Bitterblue Smith
2026-09-23 21:35 ` [PATCH v4 4/6] wifi: rtw88: 8723bs: add the RTL8723BS SDIO bind Luka Gejak
2026-09-23 21:35 ` [PATCH v4 5/6] wifi: rtw88: 8723bs: enable building the RTL8723BS driver Luka Gejak
2026-09-23 21:35 ` [PATCH v4 6/6] MAINTAINERS: add entry for the RTL8723B rtw88 driver Luka Gejak
2026-09-24  1:24   ` Ping-Ke Shih
2026-09-24  5:58     ` Luka Gejak
2026-09-29  1:15       ` Ping-Ke Shih
2026-09-25 14:27     ` Bitterblue Smith

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=6ad11268-9f09-4618-8b44-ab0744cf0a52@gmail.com \
    --to=rtl8821cerfe2@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-wireless@vger.kernel.org \
    --cc=luka.gejak@linux.dev \
    --cc=pbrobinson@gmail.com \
    --cc=pkshih@realtek.com \
    --cc=straube.linux@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®