All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ho Jie Feng <hjf3108@gmail.com>
To: Ping-Ke Shih <pkshih@realtek.com>
Cc: linux-wireless@vger.kernel.org, Ho Jie Feng <hjf3108@gmail.com>,
	linux-kernel@vger.kernel.org
Subject: [PATCH 5/6] wifi: rtw88: 88xxa: adapt channel sensing to receiver gain
Date: Thu, 29 Oct 2026 13:52:07 +0800	[thread overview]
Message-ID: <20261029055212.84711-6-hjf3108@gmail.com> (raw)
In-Reply-To: <20261029055212.84711-1-hjf3108@gmail.com>

Implement adaptivity for 88xxa, since they support it in
the hardware.

Signed-off-by: Ho Jie Feng <hjf3108@gmail.com>
---
 drivers/net/wireless/realtek/rtw88/main.h     |   1 +
 drivers/net/wireless/realtek/rtw88/rtw8812a.c |  10 ++
 drivers/net/wireless/realtek/rtw88/rtw8821a.c |  10 ++
 drivers/net/wireless/realtek/rtw88/rtw88xxa.c | 123 ++++++++++++++++++
 drivers/net/wireless/realtek/rtw88/rtw88xxa.h |   5 +
 5 files changed, 149 insertions(+)

diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h
index d59f6e323adf0..796fea308fdf7 100644
--- a/drivers/net/wireless/realtek/rtw88/main.h
+++ b/drivers/net/wireless/realtek/rtw88/main.h
@@ -1787,6 +1787,7 @@ struct rtw_dm_info {
 	bool is_bt_iqk_timeout;
 
 	s8 l2h_th_ini;
+	s8 l2h_th_lb;
 	enum rtw_edcca_mode edcca_mode;
 	u8 scan_density;
 };
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8812a.c b/drivers/net/wireless/realtek/rtw88/rtw8812a.c
index c8008cf43da9d..d93c4776e0303 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8812a.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8812a.c
@@ -945,6 +945,8 @@ static const struct rtw_chip_ops rtw8812a_ops = {
 	.coex_set_wl_rx_gain	= rtw8821a_coex_cfg_wl_rx_gain,
 	.cfo_init		= rtw_phy_cfo_xcap_init,
 	.cfo_track		= rtw88xxa_cfo_track,
+	.adaptivity_init	= rtw88xxa_adaptivity_init,
+	.adaptivity		= rtw88xxa_adaptivity,
 };
 
 static const struct rtw_page_table page_table_8812a[] = {
@@ -999,6 +1001,11 @@ static const struct rtw_hw_reg rtw8812a_dig[] = {
 	[1] = { .addr = REG_RXIGI_B, .mask = 0x7f },
 };
 
+static const struct rtw_hw_reg_offset rtw8812a_edcca_th[] = {
+	[EDCCA_TH_L2H_IDX] = {{.addr = 0x8a4, .mask = MASKBYTE0}, .offset = 0},
+	[EDCCA_TH_H2L_IDX] = {{.addr = 0x8a4, .mask = MASKBYTE1}, .offset = 0},
+};
+
 static const struct rtw_rfe_def rtw8812a_rfe_defs[] = {
 	[0] = { .phy_pg_tbl	= &rtw8812a_bb_pg_tbl,
 		.txpwr_lmt_tbl	= &rtw8812a_txpwr_lmt_tbl,
@@ -1089,6 +1096,9 @@ const struct rtw_chip_info rtw8812a_hw_spec = {
 	.bfer_su_max_num = 2,
 	.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
 	.max_scan_ie_len = IEEE80211_MAX_DATA_LEN,
+	.edcca_th = rtw8812a_edcca_th,
+	.l2h_th_ini_cs = 10,
+	.l2h_th_ini_ad = -17,
 
 	.coex_para_ver = 0, /* no coex code in 8812au driver */
 	.bt_desired_ver = 0,
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821a.c b/drivers/net/wireless/realtek/rtw88/rtw8821a.c
index 17d3677ca463c..f7391f6aa3039 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8821a.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8821a.c
@@ -891,6 +891,8 @@ static const struct rtw_chip_ops rtw8821a_ops = {
 	.coex_set_wl_rx_gain	= rtw8821a_coex_cfg_wl_rx_gain,
 	.cfo_init		= rtw_phy_cfo_xcap_init,
 	.cfo_track		= rtw88xxa_cfo_track,
+	.adaptivity_init	= rtw88xxa_adaptivity_init,
+	.adaptivity		= rtw88xxa_adaptivity,
 };
 
 static const struct rtw_page_table page_table_8821a[] = {
@@ -944,6 +946,11 @@ static const struct rtw_hw_reg rtw8821a_dig[] = {
 	[0] = { .addr = REG_RXIGI_A, .mask = 0x7f },
 };
 
+static const struct rtw_hw_reg_offset rtw8821a_edcca_th[] = {
+	[EDCCA_TH_L2H_IDX] = {{.addr = 0x8a4, .mask = MASKBYTE0}, .offset = 0},
+	[EDCCA_TH_H2L_IDX] = {{.addr = 0x8a4, .mask = MASKBYTE1}, .offset = 0},
+};
+
 static const struct rtw_rfe_def rtw8821a_rfe_defs[] = {
 	[0] = { .phy_pg_tbl	= &rtw8821a_bb_pg_tbl,
 		.txpwr_lmt_tbl	= &rtw8821a_txpwr_lmt_tbl,
@@ -1193,6 +1200,9 @@ const struct rtw_chip_info rtw8821a_hw_spec = {
 	.bfer_su_max_num = 2,
 	.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
 	.max_scan_ie_len = IEEE80211_MAX_DATA_LEN,
+	.edcca_th = rtw8821a_edcca_th,
+	.l2h_th_ini_cs = 10,
+	.l2h_th_ini_ad = -17,
 
 	.coex_para_ver = 20190509, /* glcoex_ver_date_8821a_1ant */
 	.bt_desired_ver = 0x62, /* But for 2 ant it's 0x5c */
diff --git a/drivers/net/wireless/realtek/rtw88/rtw88xxa.c b/drivers/net/wireless/realtek/rtw88/rtw88xxa.c
index 586bb57a10061..aff62d61f4719 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw88xxa.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw88xxa.c
@@ -2040,6 +2040,129 @@ void rtw88xxa_cfo_track(struct rtw_dev *rtwdev)
 }
 EXPORT_SYMBOL(rtw88xxa_cfo_track);
 
+#define EDCCA_TH_MAX_88XXA		0x7f
+#define EDCCA_L2H_CAP_88XXA		10
+#define EDCCA_L2H_INI_NORMAL_88XXA	20
+#define EDCCA_DBG_PORT_88XXA		0x209
+#define EDCCA_DC_BACKOFF_88XXA		2
+#define EDCCA_LB_START_88XXA		(EDCCA_L2H_H2L_DIFF - 30)
+#define EDCCA_LB_RETRY_88XXA		(EDCCA_LB_START_88XXA + 18)
+
+static void rtw88xxa_set_rf_mode_rx(struct rtw_dev *rtwdev, u32 data0,
+				    u32 data1)
+{
+	u8 path;
+
+	for (path = RF_PATH_A; path < rtwdev->hal.rf_path_num; path++) {
+		rtw_write_rf(rtwdev, path, RF_LUTWE, BIT(19), 1);
+		rtw_write_rf(rtwdev, path, RF_MODE_TABLE_ADDR, RFREG_MASK,
+			     0x18000);
+		rtw_write_rf(rtwdev, path, RF_MODE_TABLE_DATA0, RFREG_MASK,
+			     data0);
+		rtw_write_rf(rtwdev, path, RF_MODE_TABLE_DATA1, RFREG_MASK,
+			     data1);
+		rtw_write_rf(rtwdev, path, RF_LUTWE, BIT(19), 0);
+	}
+}
+
+static void rtw88xxa_set_lna(struct rtw_dev *rtwdev, bool enable)
+{
+	if (rtwdev->chip->id == RTW_CHIP_TYPE_8812A)
+		rtw88xxa_set_rf_mode_rx(rtwdev, 0x3f7ff,
+					enable ? 0xc26bf : 0xc22bf);
+	else
+		rtw88xxa_set_rf_mode_rx(rtwdev, 0x0002f,
+					enable ? 0xfb0bb : 0xfb09b);
+}
+
+static u8 rtw88xxa_edcca_count(struct rtw_dev *rtwdev)
+{
+	u8 cnt = 0;
+	int i;
+
+	rtw_write32(rtwdev, REG_DBGSEL, 0);
+	for (i = 0; i < 3 &&
+	     rtw_read32(rtwdev, REG_DBGRPT) & BIT_DBG_CCA_BUSY; i++)
+		usleep_range(3000, 3500);
+
+	rtw_write32(rtwdev, REG_DBGSEL, EDCCA_DBG_PORT_88XXA);
+	for (i = 0; i < 20; i++)
+		if (rtw_read32(rtwdev, REG_DBGRPT) & BIT_DBG_EDCCA_BUSY)
+			cnt++;
+
+	return cnt;
+}
+
+static s8 rtw88xxa_edcca_search_floor(struct rtw_dev *rtwdev)
+{
+	s8 l2h = EDCCA_LB_START_88XXA;
+
+	rtw_phy_set_edcca_th(rtwdev, l2h, l2h - EDCCA_L2H_H2L_DIFF);
+	msleep(30);
+
+	while (l2h < EDCCA_L2H_CAP_88XXA && rtw88xxa_edcca_count(rtwdev) > 1) {
+		l2h++;
+		rtw_phy_set_edcca_th(rtwdev, l2h, l2h - EDCCA_L2H_H2L_DIFF);
+	}
+
+	return l2h;
+}
+
+void rtw88xxa_adaptivity_init(struct rtw_dev *rtwdev)
+{
+	struct rtw_dm_info *dm_info = &rtwdev->dm_info;
+	u32 dbgsel = rtw_read32(rtwdev, REG_DBGSEL);
+	s8 l2h;
+
+	rtw_write32_clr(rtwdev, REG_TX_PTCL_CTRL, BIT_DIS_EDCCA);
+
+	rtw88xxa_set_lna(rtwdev, false);
+	l2h = rtw88xxa_edcca_search_floor(rtwdev);
+	if (l2h >= EDCCA_LB_RETRY_88XXA)
+		l2h = rtw88xxa_edcca_search_floor(rtwdev);
+	rtw88xxa_set_lna(rtwdev, true);
+	rtw_write32(rtwdev, REG_DBGSEL, dbgsel);
+
+	dm_info->l2h_th_lb = l2h + EDCCA_DC_BACKOFF_88XXA;
+	rtw_phy_set_edcca_th(rtwdev, EDCCA_TH_MAX_88XXA, EDCCA_TH_MAX_88XXA);
+
+	rtw_dbg(rtwdev, RTW_DBG_ADAPTIVITY, "EDCCA L2H floor %d\n",
+		dm_info->l2h_th_lb);
+}
+EXPORT_SYMBOL(rtw88xxa_adaptivity_init);
+
+void rtw88xxa_adaptivity(struct rtw_dev *rtwdev)
+{
+	struct rtw_dm_info *dm_info = &rtwdev->dm_info;
+	int igi_diff = EDCCA_IGI_BASE - dm_info->igi_history[0];
+	s8 l2h_lb = dm_info->l2h_th_lb;
+	s8 l2h, h2l;
+
+	/* toggle the ADC mask to work around an EDCCA hang */
+	if (rtwdev->chip->id == RTW_CHIP_TYPE_8812A) {
+		rtw_write32_set(rtwdev, REG_FPGA0_RFMOD, BIT(10));
+		rtw_write32_clr(rtwdev, REG_FPGA0_RFMOD, BIT(10));
+	}
+
+	if (dm_info->edcca_mode == RTW_EDCCA_ADAPTIVITY) {
+		l2h = min(dm_info->l2h_th_ini + igi_diff, EDCCA_L2H_CAP_88XXA);
+		h2l = l2h - EDCCA_L2H_H2L_DIFF;
+	} else {
+		l2h = EDCCA_L2H_INI_NORMAL_88XXA + igi_diff;
+		h2l = l2h - EDCCA_L2H_H2L_DIFF_NORMAL;
+	}
+
+	l2h = max(l2h, l2h_lb);
+	h2l = max_t(s8, h2l, l2h_lb - EDCCA_L2H_H2L_DIFF);
+
+	rtw_phy_set_edcca_th(rtwdev, l2h, h2l);
+
+	rtw_dbg(rtwdev, RTW_DBG_ADAPTIVITY,
+		"EDCCA mode %d, IGI 0x%x, L2H %d, H2L %d\n",
+		dm_info->edcca_mode, dm_info->igi_history[0], l2h, h2l);
+}
+EXPORT_SYMBOL(rtw88xxa_adaptivity);
+
 MODULE_AUTHOR("Realtek Corporation");
 MODULE_DESCRIPTION("Realtek 802.11ac wireless 8821a/8811a/8812a common code");
 MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/realtek/rtw88/rtw88xxa.h b/drivers/net/wireless/realtek/rtw88/rtw88xxa.h
index 09b72d33f62e1..b8719c278df73 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw88xxa.h
+++ b/drivers/net/wireless/realtek/rtw88/rtw88xxa.h
@@ -139,6 +139,9 @@ struct rtw_jaguar_phy_status_rpt {
 
 #define RF18_BW_MASK		(BIT(11) | BIT(10))
 
+#define BIT_DBG_CCA_BUSY	BIT(3)
+#define BIT_DBG_EDCCA_BUSY	BIT(29)
+
 void rtw88xxa_efuse_grant(struct rtw_dev *rtwdev, bool on);
 int rtw88xxa_read_efuse(struct rtw_dev *rtwdev, u8 *log_map);
 void rtw88xxa_power_off(struct rtw_dev *rtwdev,
@@ -173,5 +176,7 @@ void rtw88xxa_phy_pwrtrack(struct rtw_dev *rtwdev,
 void rtw88xxa_bf_config_bfee(struct rtw_dev *rtwdev, struct rtw_vif *vif,
 			     struct rtw_bfee *bfee, bool enable);
 void rtw88xxa_cfo_track(struct rtw_dev *rtwdev);
+void rtw88xxa_adaptivity_init(struct rtw_dev *rtwdev);
+void rtw88xxa_adaptivity(struct rtw_dev *rtwdev);
 
 #endif
-- 
2.55.0


  parent reply	other threads:[~2026-10-29  5:52 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-29  5:52 [PATCH 0/6] wifi: rtw88: extend 88xxA support Ho Jie Feng
2026-10-29  5:52 ` [PATCH 1/6] wifi: rtw88: 8812a, 8814a: enable STBC for HT transmissions Ho Jie Feng
2026-10-29  5:52 ` [PATCH 2/6] wifi: rtw88: 88xxa: receive VHT SU beamformed transmissions Ho Jie Feng
2026-10-29 12:33   ` Bitterblue Smith
2026-10-29 14:13     ` Ho Jie Feng
2026-10-29 21:06       ` Bitterblue Smith
2026-10-29  5:52 ` [PATCH 3/6] wifi: rtw88: prepare frequency-offset correction for more chips Ho Jie Feng
2026-10-29  5:52 ` [PATCH 4/6] wifi: rtw88: 88xxa: correct carrier-frequency offset Ho Jie Feng
2026-10-29  5:52 ` Ho Jie Feng [this message]
2026-10-29  5:52 ` [PATCH 6/6] wifi: rtw88: 8812a, 8821a: respect peer A-MPDU size limits Ho Jie Feng

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=20261029055212.84711-6-hjf3108@gmail.com \
    --to=hjf3108@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-wireless@vger.kernel.org \
    --cc=pkshih@realtek.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.