* RE: [PATCH rtw-next 05/12] wifi: rtw89: Fix rtw89_usb_ops_mac_post_init() for RTL8922AU
From: Ping-Ke Shih @ 2026-03-30 3:41 UTC (permalink / raw)
To: Bitterblue Smith, linux-wireless@vger.kernel.org
In-Reply-To: <560b65f9-5e60-4a42-8661-fd98eea6e9d7@gmail.com>
Bitterblue Smith <rtl8821cerfe2@gmail.com> wrote:
> Skip most of the function because RTL8922AU only needs to configure the
> RX aggregation here.
>
> Signed-off-by: Bitterblue Smith <rtl8821cerfe2@gmail.com>
Acked-by: Ping-Ke Shih <pkshih@realtek.com>
^ permalink raw reply
* RE: [PATCH rtw-next 06/12] wifi: rtw89: usb: Enable RX aggregation for RTL8922AU
From: Ping-Ke Shih @ 2026-03-30 3:46 UTC (permalink / raw)
To: Bitterblue Smith, linux-wireless@vger.kernel.org
In-Reply-To: <6d7440bc-d463-4d99-af12-181684b87bfa@gmail.com>
Bitterblue Smith <rtl8821cerfe2@gmail.com> wrote:
> It uses the same settings as RTL8852CU.
Though the values are the same, I'd prefer listing them individually, since
naming is different in vendor driver.
#define R_AX_RXAGG_0_V1 0x6000
#define R_BE_RXAGG_0_V1 0x6000
How about you? (I don't strictly request to this change)
^ permalink raw reply
* RE: [PATCH rtw-next 07/12] wifi: rtw89: Fix rtw8922a_pwr_{on,off}_func() for USB
From: Ping-Ke Shih @ 2026-03-30 3:54 UTC (permalink / raw)
To: Bitterblue Smith, linux-wireless@vger.kernel.org
In-Reply-To: <d8a90345-ba4d-49a5-a967-af07e7390aab@gmail.com>
Bitterblue Smith <rtl8821cerfe2@gmail.com> wrote:
> There are a few differences in the power on/off functions between PCIE
> and USB.
>
> Signed-off-by: Bitterblue Smith <rtl8821cerfe2@gmail.com>
Acked-by: Ping-Ke Shih <pkshih@realtek.com>
[...]
> @@ -371,6 +380,10 @@ static int rtw8922a_pwr_on_func(struct rtw89_dev *rtwdev)
> if (ret)
> return ret;
>
> + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_SRAM_CTRL, 0, XTAL_SI_SRAM_DIS);
> + if (ret)
> + return ret;
> +
Thanks for this missed entry.
> if (hal->cv != CHIP_CAV) {
> rtw89_write32_set(rtwdev, R_BE_PMC_DBG_CTRL2, B_BE_SYSON_DIS_PMCR_BE_WRMSK);
> rtw89_write32_set(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_ISO_EB2CORE);
^ permalink raw reply
* RE: [PATCH rtw-next 08/12] wifi: rtw89: Let hfc_param_ini have separate settings for USB 2/3
From: Ping-Ke Shih @ 2026-03-30 3:59 UTC (permalink / raw)
To: Bitterblue Smith, linux-wireless@vger.kernel.org
In-Reply-To: <f6c8001f-caf1-4094-b1c7-c654f205613f@gmail.com>
Bitterblue Smith <rtl8821cerfe2@gmail.com> wrote:
> RTL8912AU needs different settings for USB 2 and USB 3.
>
> Signed-off-by: Bitterblue Smith <rtl8821cerfe2@gmail.com>
Acked-by: Ping-Ke Shih <pkshih@realtek.com>
> ---
> drivers/net/wireless/realtek/rtw89/core.h | 2 +-
> drivers/net/wireless/realtek/rtw89/mac.c | 2 +-
> drivers/net/wireless/realtek/rtw89/rtw8851b.c | 1 +
> drivers/net/wireless/realtek/rtw89/rtw8852a.c | 1 +
> drivers/net/wireless/realtek/rtw89/rtw8852b.c | 1 +
> drivers/net/wireless/realtek/rtw89/rtw8852bt.c | 2 +-
> drivers/net/wireless/realtek/rtw89/rtw8852c.c | 1 +
> drivers/net/wireless/realtek/rtw89/rtw8922a.c | 2 +-
I might miss this change by rtw8922d.c, since we are submitting at the
same time. But no worries, it will be aligned when people are adding
RTL8922DU.
^ permalink raw reply
* RE: [PATCH rtw-next 09/12] wifi: rtw89: Add rtw8922a_hfc_param_ini_usb{2,3}
From: Ping-Ke Shih @ 2026-03-30 4:01 UTC (permalink / raw)
To: Bitterblue Smith, linux-wireless@vger.kernel.org
In-Reply-To: <6a8b746c-f702-4a76-876d-bc39991b3baa@gmail.com>
Bitterblue Smith <rtl8821cerfe2@gmail.com> wrote:
> Sent: Friday, March 27, 2026 1:08 AM
> "hfc" means "hci fc" which is "Host Control Interface Flow Control".
> These are some parameters needed for RTL8922AU.
>
> Signed-off-by: Bitterblue Smith <rtl8821cerfe2@gmail.com>
Acked-by: Ping-Ke Shih <pkshih@realtek.com>
^ permalink raw reply
* [PATCH ath-next] wifi: ath12k: Skip adding inactive partner vdev info
From: Roopni Devanathan @ 2026-03-30 4:07 UTC (permalink / raw)
To: ath12k; +Cc: linux-wireless, Avula Sri Charan, Roopni Devanathan
From: Avula Sri Charan <quic_asrichar@quicinc.com>
Currently, a vdev that is created is considered active for partner link
population. In case of an MLD station, non-associated link vdevs can be
created but not started. Yet, they are added as partner links. This leads
to the creation of stale FW partner entries which accumulate and cause
assertions.
To resolve this issue, check if the vdev is started and operating on a
chosen frequency, i.e., arvif->is_started, instead of checking if the vdev
is created, i.e., arvif->is_created. This determines if the vdev is active
or not and skips adding it as a partner link if it's inactive.
Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.6-01181-QCAHKSWPL_SILICONZ-1
Signed-off-by: Avula Sri Charan <quic_asrichar@quicinc.com>
Signed-off-by: Roopni Devanathan <roopni.devanathan@oss.qualcomm.com>
---
drivers/net/wireless/ath/ath12k/mac.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 553ec28b6aaa..c1a1b220f4dd 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -11131,7 +11131,7 @@ ath12k_mac_mlo_get_vdev_args(struct ath12k_link_vif *arvif,
if (arvif == arvif_p)
continue;
- if (!arvif_p->is_created)
+ if (!arvif_p->is_started)
continue;
link_conf = wiphy_dereference(ahvif->ah->hw->wiphy,
base-commit: 15551ababf6d4e857f2101366a0c3eaa86dd822c
--
2.43.0
^ permalink raw reply related
* RE: [PATCH rtw-next 10/12] wifi: rtw89: Add rtw8922a_dle_mem_usb{2,3}
From: Ping-Ke Shih @ 2026-03-30 4:25 UTC (permalink / raw)
To: Bitterblue Smith, linux-wireless@vger.kernel.org
In-Reply-To: <44678760-ded9-4542-8626-37cd71d30c51@gmail.com>
Bitterblue Smith <rtl8821cerfe2@gmail.com> wrote:
> Add rtw8922a_dle_mem_usb2 and rtw8922a_dle_mem_usb3 and their various
> quotas and sizes in struct rtw89_mac_size_set.
>
> "dle" could be "Data Link Engine" or "Double Link Engine". These are
> some parameters needed for RTL8922AU.
>
> Also rename wde_size4_v1 to wde_size3_v1 because the name seemed
> incorrect.
Not sure if vendor driver did some changes for this, but I checked the
latest version which it looks like as your changes.
>
> Signed-off-by: Bitterblue Smith <rtl8821cerfe2@gmail.com>
Acked-by: Ping-Ke Shih <pkshih@realtek.com>
^ permalink raw reply
* RE: [PATCH rtw-next 11/12] wifi: rtw89: Add rtw8922au.c
From: Ping-Ke Shih @ 2026-03-30 4:27 UTC (permalink / raw)
To: Bitterblue Smith, linux-wireless@vger.kernel.org
In-Reply-To: <c171e4ff-2a84-4c71-9c1c-a485863c1855@gmail.com>
Bitterblue Smith <rtl8821cerfe2@gmail.com> wrote:
> This is the entry point of the new rtw89_8922au module.
>
> Signed-off-by: Bitterblue Smith <rtl8821cerfe2@gmail.com>
Acked-by: Ping-Ke Shih <pkshih@realtek.com>
^ permalink raw reply
* RE: [PATCH rtw-next 12/12] wifi: rtw89: Enable the new rtw89_8922au module
From: Ping-Ke Shih @ 2026-03-30 4:30 UTC (permalink / raw)
To: Bitterblue Smith, linux-wireless@vger.kernel.org
In-Reply-To: <99125850-8dee-4a98-ab68-5d171449a2e0@gmail.com>
Bitterblue Smith <rtl8821cerfe2@gmail.com> wrote:
> Tested without MLO, mostly in station mode and a little in AP mode.
Could you share the result about throughput or data rate?
Since you noted warnings related to RF calibration, I'm very interested
in the number.
>
> Signed-off-by: Bitterblue Smith <rtl8821cerfe2@gmail.com>
Otherwise,
Acked-by: Ping-Ke Shih <pkshih@realtek.com>
^ permalink raw reply
* RE: [PATCH v5] wifi: rtw89: usb: fix TX flow control by tracking in-flight URBs
From: Ping-Ke Shih @ 2026-03-30 5:35 UTC (permalink / raw)
To: Lucid Duck
Cc: linux-wireless@vger.kernel.org, rtl8821cerfe2@gmail.com,
morrownr@gmail.com
In-Reply-To: <20260330025959.399018-1-lucid_duck@justthetip.ca>
Lucid Duck <lucid_duck@justthetip.ca> wrote:
> rtw89_usb_ops_check_and_reclaim_tx_resource() returns a hardcoded
> placeholder value (42) instead of actual TX resource availability.
> This violates mac80211's flow control contract, preventing backpressure
> and causing uncontrolled URB accumulation under sustained TX load.
>
> Fix by adding per-channel atomic counters (tx_inflight[]) that track
> in-flight URBs. Increment before usb_submit_urb() with rollback on
> failure, decrement in the completion callback, and return the
> remaining capacity to mac80211. The firmware command channel (CH12)
> always returns 1 since it has its own flow control.
>
> The pre-increment pattern prevents a race where USB core completes the
> URB on another CPU before the submitting code increments the counter.
>
> 128 URBs per channel provides headroom for RTL8832CU at 160 MHz
> bandwidth. Tested on RTL8852AU (USB3 80 MHz) where 64 and 128 showed
> equivalent throughput, and on RTL8832AU where 128 sustained full
> throughput under 8-stream parallel load.
>
> Tested on D-Link DWA-X1850 (RTL8832AU), kernel 6.19.8, Fedora 43:
>
> Unpatched -> Patched (128 URBs)
> USB3 5GHz UL: 844 -> 837 Mbps (no regression)
> USB3 5GHz retx: 3 -> 0
> USB3 2.4GHz UL: 162 -> 164 Mbps (no regression)
> 4-stream UL: 858 -> 826 Mbps (within variance)
> 8-stream UL: 872 -> 826 Mbps (within variance)
> UDP flood: 0% loss (690K datagrams)
> 60-second soak: 855 Mbps, 0 retransmits
>
> Reported-by: morrownr <morrownr@gmail.com>
> Signed-off-by: Lucid Duck <lucid_duck@justthetip.ca>
Acked-by: Ping-Ke Shih <pkshih@realtek.com>
^ permalink raw reply
* Re: [PATCH v2 02/15] firmware: qcom: Add a generic PAS service
From: Sumit Garg @ 2026-03-30 6:29 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Mukesh Ojha, linux-arm-msm, devicetree, dri-devel, freedreno,
linux-media, netdev, linux-wireless, ath12k, linux-remoteproc,
andersson, konradybcio, robh, krzk+dt, conor+dt, robin.clark,
sean, akhilpo, lumag, abhinav.kumar, jesszhan0024, marijn.suijten,
airlied, simona, vikash.garodia, dikshita.agarwal, bod, mchehab,
elder, andrew+netdev, davem, edumazet, kuba, pabeni, jjohnson,
mathieu.poirier, trilokkumar.soni, pavan.kondeti, jorge.ramirez,
tonyh, vignesh.viswanathan, srinivas.kandagatla, amirreza.zarrabi,
jens.wiklander, op-tee, apurupa, skare, linux-kernel, Sumit Garg
In-Reply-To: <2da6cbcc-677d-4ba8-9762-ecb47b157f21@kernel.org>
On Fri, Mar 27, 2026 at 02:39:24PM +0100, Krzysztof Kozlowski wrote:
> On 23/03/2026 13:50, Sumit Garg wrote:
> >>> +
> >>> +#include <linux/device/devres.h>
> >>> +#include <linux/firmware/qcom/qcom_pas.h>
> >>> +#include <linux/kernel.h>
> >>> +#include <linux/module.h>
> >>> +
> >>> +#include "qcom_pas.h"
> >>> +
> >>> +struct qcom_pas_ops *ops_ptr;
> >>
> >> Should this be static ?
> >
> > It was static earlier in v1. I dropped it based on earlier v1 discussion
> > with Krzysztof. Let me conclude that discussion on the other thread
> > again.
>
> The discussion was whether this should be singleton in the first place,
> not making it a global singleton.
>
> Of course it cannot be anything else than static - nothing should poke here.
Sure, I have put the static back for v3.
-Sumit
^ permalink raw reply
* RE: [PATCH v2 1/2] wifi: iwlwifi: mvm: fix race condition in PTP removal
From: Korenblit, Miriam Rachel @ 2026-03-30 6:43 UTC (permalink / raw)
To: Cao, Junjie, Berg, Johannes, linux-wireless@vger.kernel.org,
richardcochran@gmail.com
Cc: horms@kernel.org, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org, yedidya.ben.shimol@intel.com,
Stern, Avraham, Gabay, Daniel, Prabhu, Krishnanand,
Coelho, Luciano, gregory.greenman@intel.com,
stable@vger.kernel.org, Vadim Fedorenko
In-Reply-To: <20260212125035.1345718-1-junjie.cao@intel.com>
> -----Original Message-----
> From: Cao, Junjie <junjie.cao@intel.com>
> Sent: Thursday, February 12, 2026 2:51 PM
> To: Korenblit, Miriam Rachel <miriam.rachel.korenblit@intel.com>; Berg,
> Johannes <johannes.berg@intel.com>; linux-wireless@vger.kernel.org;
> richardcochran@gmail.com
> Cc: horms@kernel.org; netdev@vger.kernel.org; linux-kernel@vger.kernel.org;
> yedidya.ben.shimol@intel.com; Stern, Avraham <avraham.stern@intel.com>;
> Gabay, Daniel <daniel.gabay@intel.com>; Prabhu, Krishnanand
> <krishnanand.prabhu@intel.com>; Coelho, Luciano <luciano.coelho@intel.com>;
> gregory.greenman@intel.com; stable@vger.kernel.org; Cao, Junjie
> <junjie.cao@intel.com>; Vadim Fedorenko <vadim.fedorenko@linux.dev>
> Subject: [PATCH v2 1/2] wifi: iwlwifi: mvm: fix race condition in PTP removal
>
> iwl_mvm_ptp_remove() calls cancel_delayed_work_sync() only after
> ptp_clock_unregister() and clearing ptp_data state (ptp_clock, ptp_clock_info,
> last_gp2).
>
> This creates a race where the delayed work iwl_mvm_ptp_work() can execute
> between ptp_clock_unregister() and cancel_delayed_work_sync(), observing
> partially cleared PTP state.
But the work runs under the mvm mutex, and so does iwl_mvm_ptp_remove, so not sure how such a race can happen?
>
> Move cancel_delayed_work_sync() before ptp_clock_unregister() to ensure the
> delayed work is fully stopped before any PTP cleanup begins.
>
> Fixes: 1595ecce1cf3 ("wifi: iwlwifi: mvm: add support for PTP HW clock (PHC)")
> Cc: stable@vger.kernel.org
> Reviewed-by: Simon Horman <horms@kernel.org>
> Reviewed-by: Vadim Fedorenko <vadim.fedorenko@linux.dev>
> Signed-off-by: Junjie Cao <junjie.cao@intel.com>
> ---
> drivers/net/wireless/intel/iwlwifi/mvm/ptp.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c
> b/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c
> index ad156b82eaa9..efb291ceb0e5 100644
> --- a/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c
> +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c
> @@ -323,11 +323,11 @@ void iwl_mvm_ptp_remove(struct iwl_mvm *mvm)
> mvm->ptp_data.ptp_clock_info.name,
> ptp_clock_index(mvm->ptp_data.ptp_clock));
>
> + cancel_delayed_work_sync(&mvm->ptp_data.dwork);
> ptp_clock_unregister(mvm->ptp_data.ptp_clock);
> mvm->ptp_data.ptp_clock = NULL;
> memset(&mvm->ptp_data.ptp_clock_info, 0,
> sizeof(mvm->ptp_data.ptp_clock_info));
> mvm->ptp_data.last_gp2 = 0;
> - cancel_delayed_work_sync(&mvm->ptp_data.dwork);
> }
> }
> --
> 2.48.1
^ permalink raw reply
* RE: [PATCH v2 1/2] wifi: iwlwifi: mvm: fix race condition in PTP removal
From: Korenblit, Miriam Rachel @ 2026-03-30 6:49 UTC (permalink / raw)
To: Cao, Junjie, Berg, Johannes, linux-wireless@vger.kernel.org,
richardcochran@gmail.com
Cc: horms@kernel.org, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org, yedidya.ben.shimol@intel.com,
Stern, Avraham, Gabay, Daniel, Prabhu, Krishnanand,
Coelho, Luciano, gregory.greenman@intel.com,
stable@vger.kernel.org, Vadim Fedorenko
In-Reply-To: <DM3PPF63A6024A9E6728A0315DC6653D109A352A@DM3PPF63A6024A9.namprd11.prod.outlook.com>
> -----Original Message-----
> From: Korenblit, Miriam Rachel
> Sent: Monday, March 30, 2026 9:44 AM
> To: Cao, Junjie <junjie.cao@intel.com>; Berg, Johannes
> <johannes.berg@intel.com>; linux-wireless@vger.kernel.org;
> richardcochran@gmail.com
> Cc: horms@kernel.org; netdev@vger.kernel.org; linux-kernel@vger.kernel.org;
> yedidya.ben.shimol@intel.com; Stern, Avraham <avraham.stern@intel.com>;
> Gabay, Daniel <Daniel.Gabay@intel.com>; Prabhu, Krishnanand
> <krishnanand.prabhu@intel.com>; Coelho, Luciano <luciano.coelho@intel.com>;
> gregory.greenman@intel.com; stable@vger.kernel.org; Vadim Fedorenko
> <vadim.fedorenko@linux.dev>
> Subject: RE: [PATCH v2 1/2] wifi: iwlwifi: mvm: fix race condition in PTP removal
>
>
>
> > -----Original Message-----
> > From: Cao, Junjie <junjie.cao@intel.com>
> > Sent: Thursday, February 12, 2026 2:51 PM
> > To: Korenblit, Miriam Rachel <miriam.rachel.korenblit@intel.com>;
> > Berg, Johannes <johannes.berg@intel.com>;
> > linux-wireless@vger.kernel.org; richardcochran@gmail.com
> > Cc: horms@kernel.org; netdev@vger.kernel.org;
> > linux-kernel@vger.kernel.org; yedidya.ben.shimol@intel.com; Stern,
> > Avraham <avraham.stern@intel.com>; Gabay, Daniel
> > <daniel.gabay@intel.com>; Prabhu, Krishnanand
> > <krishnanand.prabhu@intel.com>; Coelho, Luciano
> > <luciano.coelho@intel.com>; gregory.greenman@intel.com;
> > stable@vger.kernel.org; Cao, Junjie <junjie.cao@intel.com>; Vadim
> > Fedorenko <vadim.fedorenko@linux.dev>
> > Subject: [PATCH v2 1/2] wifi: iwlwifi: mvm: fix race condition in PTP
> > removal
> >
> > iwl_mvm_ptp_remove() calls cancel_delayed_work_sync() only after
> > ptp_clock_unregister() and clearing ptp_data state (ptp_clock,
> > ptp_clock_info, last_gp2).
> >
> > This creates a race where the delayed work iwl_mvm_ptp_work() can
> > execute between ptp_clock_unregister() and cancel_delayed_work_sync(),
> > observing partially cleared PTP state.
>
> But the work runs under the mvm mutex, and so does iwl_mvm_ptp_remove, so
> not sure how such a race can happen?
Oops, err. It does not run under the mutex. Sorry.
Still note that even with the zeroed data no harm will be done by the worker.
Will apply the patch.
> >
> > Move cancel_delayed_work_sync() before ptp_clock_unregister() to
> > ensure the delayed work is fully stopped before any PTP cleanup begins.
> >
> > Fixes: 1595ecce1cf3 ("wifi: iwlwifi: mvm: add support for PTP HW clock
> > (PHC)")
> > Cc: stable@vger.kernel.org
> > Reviewed-by: Simon Horman <horms@kernel.org>
> > Reviewed-by: Vadim Fedorenko <vadim.fedorenko@linux.dev>
> > Signed-off-by: Junjie Cao <junjie.cao@intel.com>
> > ---
> > drivers/net/wireless/intel/iwlwifi/mvm/ptp.c | 2 +-
> > 1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c
> > b/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c
> > index ad156b82eaa9..efb291ceb0e5 100644
> > --- a/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c
> > +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c
> > @@ -323,11 +323,11 @@ void iwl_mvm_ptp_remove(struct iwl_mvm *mvm)
> > mvm->ptp_data.ptp_clock_info.name,
> > ptp_clock_index(mvm->ptp_data.ptp_clock));
> >
> > + cancel_delayed_work_sync(&mvm->ptp_data.dwork);
> > ptp_clock_unregister(mvm->ptp_data.ptp_clock);
> > mvm->ptp_data.ptp_clock = NULL;
> > memset(&mvm->ptp_data.ptp_clock_info, 0,
> > sizeof(mvm->ptp_data.ptp_clock_info));
> > mvm->ptp_data.last_gp2 = 0;
> > - cancel_delayed_work_sync(&mvm->ptp_data.dwork);
> > }
> > }
> > --
> > 2.48.1
^ permalink raw reply
* RE: iwlwifi-mld: Fix fw id leak in OOM case
From: Korenblit, Miriam Rachel @ 2026-03-30 6:55 UTC (permalink / raw)
To: Ben Greear, linux-wireless
In-Reply-To: <495b7e8d-454c-4c0f-8976-c31fcee0783d@candelatech.com>
> -----Original Message-----
> From: Ben Greear <greearb@candelatech.com>
> Sent: Tuesday, March 3, 2026 4:21 PM
> To: Korenblit, Miriam Rachel <miriam.rachel.korenblit@intel.com>; linux-wireless
> <linux-wireless@vger.kernel.org>
> Subject: Re: iwlwifi-mld: Fix fw id leak in OOM case
>
> On 3/2/26 23:28, Korenblit, Miriam Rachel wrote:
> >
> >
> >> -----Original Message-----
> >> From: Ben Greear <greearb@candelatech.com>
> >> Sent: Tuesday, March 3, 2026 1:07 AM
> >> To: linux-wireless <linux-wireless@vger.kernel.org>; Korenblit,
> >> Miriam Rachel <miriam.rachel.korenblit@intel.com>
> >> Subject: iwlwifi-mld: Fix fw id leak in OOM case
> >>
> >> Hello Miriam,
> >>
> >> I believe you will want to add something like this to your driver to
> >> clear the fw_id_to_link_sta ID in case you hit the ENOMEM case.
> >>
> >> I have no reason to believe I am actually hitting this error case,
> >> but I saw this questionable code while looking for reasons for the use-after-
> free I am hitting.
> >>
> >> diff --git a/drivers/net/wireless/intel/iwlwifi/mld/sta.c
> >> b/drivers/net/wireless/intel/iwlwifi/mld/sta.c
> >> index 5fb2a46241e4..de9939ad1d58 100644
> >> --- a/drivers/net/wireless/intel/iwlwifi/mld/sta.c
> >> +++ b/drivers/net/wireless/intel/iwlwifi/mld/sta.c
> >> @@ -535,13 +535,19 @@ iwl_mld_add_link_sta(struct iwl_mld *mld,
> >> struct ieee80211_link_sta *link_sta)
> >> ret = iwl_mld_allocate_link_sta_fw_id(mld, &fw_id, link_sta);
> >> if (ret)
> >> return ret;
> >>
> >> if (link_sta == &link_sta->sta->deflink) {
> >> mld_link_sta = &mld_sta->deflink;
> >> } else {
> >> mld_link_sta = kzalloc(sizeof(*mld_link_sta), GFP_KERNEL);
> >> - if (!mld_link_sta)
> >> + if (!mld_link_sta) {
> >> + IWL_ERR(mld, "mld-add-link-sta, OOM, clearing
> >> fw_id_to_link_sta[%d]\n",
> >> + fw_id);
> >> +
> >> + RCU_INIT_POINTER(mld->fw_id_to_link_sta[fw_id],
> >> + NULL);
> >> return -ENOMEM;
> >> + }
> >> }
> >>
> >> Thanks,
> >> Ben
> >>
> >> --
> >> Ben Greear <greearb@candelatech.com>
> >> Candela Technologies Inc http://www.candelatech.com
> >
> > Please send a patch
>
> Are you fine with having IWL_ERR in the patch like I have above?
No need for any message.
And you should have a proper commit message
>
> Thanks,
> Ben
>
> >
>
> --
> Ben Greear <greearb@candelatech.com>
> Candela Technologies Inc http://www.candelatech.com
^ permalink raw reply
* [PATCH rtw-next 0/9] wifi: rtw89: 8922d: add RTL8922DE part 2/2
From: Ping-Ke Shih @ 2026-03-30 6:58 UTC (permalink / raw)
To: linux-wireless
Add part 2/2 of RTL8922DE, but yet enable it by Kconfig/Makefile because
we are still developing and testing BT coexistence mechanism, which is a
shared component and can affect all existing chips. Otherwise, RTL8922DE
can work with the highest rate and STA/AP modes.
Since we are continuously adjusting common flow to support new hardware
settings of RTL8922D, I'd add RTL8922D first followed by patches of new
settings, so people can be easier to understand why/how actually it does.
Ping-Ke Shih (9):
wifi: rtw89: 8922d: BB hardware pre-/post-init, TX/RX path and power
settings
wifi: rtw89: 8922d: add set channel with pre-/post- helpers
wifi: rtw89: 8922d: add RF calibration ops
wifi: rtw89: 8922d: add set TX power callback
wifi: rtw89: 8922d: configure TX/RX path assisting in BT coexistence
wifi: rtw89: 8922d: add RF ops of init hardware and get thermal
wifi: rtw89: 8922d: add ops related to BT coexistence mechanism
wifi: rtw89: 8922d: add chip_info and chip_ops struct
wifi: rtw89: 8922d: add PCI ID of RTL8922DE and RTL8922DE-VS
drivers/net/wireless/realtek/rtw89/core.h | 21 +
drivers/net/wireless/realtek/rtw89/fw.h | 23 +-
drivers/net/wireless/realtek/rtw89/pci.h | 3 +
drivers/net/wireless/realtek/rtw89/reg.h | 127 +-
drivers/net/wireless/realtek/rtw89/rtw8851b.c | 4 +
drivers/net/wireless/realtek/rtw89/rtw8852a.c | 4 +
drivers/net/wireless/realtek/rtw89/rtw8852b.c | 4 +
.../net/wireless/realtek/rtw89/rtw8852bt.c | 4 +
drivers/net/wireless/realtek/rtw89/rtw8852c.c | 4 +
drivers/net/wireless/realtek/rtw89/rtw8922a.c | 4 +
drivers/net/wireless/realtek/rtw89/rtw8922d.c | 1338 +++++++++++++++++
drivers/net/wireless/realtek/rtw89/rtw8922d.h | 3 +
.../net/wireless/realtek/rtw89/rtw8922d_rfk.c | 339 +++++
.../net/wireless/realtek/rtw89/rtw8922d_rfk.h | 8 +
.../net/wireless/realtek/rtw89/rtw8922de.c | 119 ++
15 files changed, 1996 insertions(+), 9 deletions(-)
create mode 100644 drivers/net/wireless/realtek/rtw89/rtw8922de.c
base-commit: 658e3c836969e1624a7572c75684f54ec503c2ed
--
2.25.1
^ permalink raw reply
* [PATCH rtw-next 1/9] wifi: rtw89: 8922d: BB hardware pre-/post-init, TX/RX path and power settings
From: Ping-Ke Shih @ 2026-03-30 6:58 UTC (permalink / raw)
To: linux-wireless
In-Reply-To: <20260330065847.48946-1-pkshih@realtek.com>
More settings related to BB pre-/post-initial settings, the TX/RX path
settings, and digital power compensation.
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/reg.h | 64 ++++
drivers/net/wireless/realtek/rtw89/rtw8922d.c | 318 ++++++++++++++++++
2 files changed, 382 insertions(+)
diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h
index 5d284f310069..e64bd74db83a 100644
--- a/drivers/net/wireless/realtek/rtw89/reg.h
+++ b/drivers/net/wireless/realtek/rtw89/reg.h
@@ -8384,6 +8384,9 @@
#define B_BE_PWR_BT_VAL GENMASK(8, 0)
#define B_BE_PWR_FORCE_COEX_ON GENMASK(29, 27)
+#define R_PWR_BOOST_BE4 0x11A64
+#define B_PWR_BOOST_BE4 BIT(8)
+
#define R_BE_PWR_TH 0x11A78
#define R_BE_PWR_RSSI_TARGET_LMT 0x11A84
@@ -10248,6 +10251,8 @@
#define R_TSSI_K_P1 0xE7A0
#define B_TSSI_K_OFDM_P1 GENMASK(29, 20)
+#define R_BBWRAP_ELMSR_BE4 0x11974
+#define B_BBWRAP_ELMSR_EN_BE4 GENMASK(29, 28)
#define R_COMP_CIM3K_BE4 0x11998
#define B_COMP_CIM3K_OW_BE4 BIT(1)
#define B_COMP_CIM3K_TH_BE4 BIT(2)
@@ -10452,6 +10457,12 @@
#define R_BANDEDGE_DBWY_BE4 0x11AD0
#define B_BANDEDGE_DBW160_BE4 BIT(0)
+#define R_SYS_DBCC_BE4 0x20000
+#define B_SYS_DBCC_BE4 BIT(0)
+#define B_SYS_DBCC_24G_BAND_SEL_BE4 BIT(1)
+#define R_EMLSR_SWITCH_BE4 0x20044
+#define B_EMLSR_SWITCH_BE4 GENMASK(27, 12)
+#define B_EMLSR_BB_CLK_BE4 GENMASK(31, 30)
#define R_CHINFO_SEG_BE4 0x200B4
#define B_CHINFO_SEG_LEN_BE4 GENMASK(12, 10)
#define R_STS_HDR2_PARSING_BE4 0x2070C
@@ -10467,11 +10478,25 @@
#define B_RXBW7_BE4 GENMASK(25, 23)
#define R_RXBW_BE4 0x20410
#define B_RXBW_BE4 GENMASK(29, 27)
+#define R_TXERRCT_EN_BE4 0x20518
+#define B_TXERRCT_EN_BE4 BIT(13)
+#define R_TXERRCT1_EN_BE4 0x2051C
+#define B_TXERRCT1_EN_BE4 BIT(31)
#define R_ENABLE_CCK0_BE4 0x20700
#define B_ENABLE_CCK0_BE4 BIT(5)
+#define R_RSTB_ASYNC_BE4 0x20704
+#define B_RSTB_ASYNC_BE4 BIT(1)
#define R_EDCCA_RPT_SEL_BE4 0x20780
#define R_EDCCA_RPT_SEL_BE4_C1 0x21780
#define B_EDCCA_RPT_SEL_BE4_MSK 0xE0000
+#define R_IMR_TX_ERROR_BE4 0x20920
+#define B_IMR_TX_ERROR_BE4 BIT(30)
+#define R_TXINFO_PATH_BE4 0x209A4
+#define B_TXINFO_PATH_EN_BE4 BIT(17)
+#define B_TXINFO_PATH_MA_BE4 BIT(18)
+#define B_TXINFO_PATH_MB_BE4 BIT(19)
+#define R_SHAPER_COEFF_BE4 0x20CBC
+#define B_SHAPER_COEFF_BE4 BIT(19)
#define R_IFS_T1_AVG_BE4 0x20EDC
#define B_IFS_T1_AVG_BE4 GENMASK(15, 0)
#define B_IFS_T2_AVG_BE4 GENMASK(31, 16)
@@ -10494,6 +10519,12 @@
#define B_IFS_T3_HIS_BE4 GENMASK(15, 0)
#define B_IFS_T4_HIS_BE4 GENMASK(31, 16)
+#define R_TX_ERROR_SEL_BE4 0x21254
+#define B_TX_ERROR_PSDU_BE4 BIT(11)
+#define B_TX_ERROR_NSYM_BE4 BIT(10)
+#define B_TX_ERROR_LSIG_BE4 BIT(9)
+#define B_TX_ERROR_TXINFO_BE4 BIT(8)
+
#define R_TXPWR_RSTB0_BE4 0x2250C
#define B_TXPWR_RSTB0_BE4 BIT(16)
#define R_TXPWR_RSTB1_BE4 0x2260C
@@ -10546,6 +10577,10 @@
#define B_PRISB_BE4 GENMASK(3, 0)
#define R_FC0_BE4 0x24EE8
#define B_FC0_BE4 GENMASK(12, 0)
+#define R_ANT_RX_1RCCA_BE4 0x24EEC
+#define B_ANT_RX_1RCCA_BE4 GENMASK(17, 14)
+#define R_ANT_RX_BE4 0x24EF0
+#define B_ANT_RX_BE4 GENMASK(3, 0)
#define R_FC0_INV_BE4 0x24EF4
#define B_FC0_INV_BE4 GENMASK(15, 0)
@@ -10569,6 +10604,32 @@
#define B_CHINFO_NX_BE4 GENMASK(16, 6)
#define R_CHINFO_ALG_BE4 0x267C8
#define B_CHINFO_ALG_BE4 GENMASK(31, 30)
+#define R_RX_AWGN02_BE4 0x2680C
+#define B_RX_AWGN11_BE4 GENMASK(23, 18)
+#define R_RX_AWGN00_BE4 0x26814
+#define B_RX_AWGN04_BE4 GENMASK(5, 0)
+#define B_RX_AWGN07_BE4 GENMASK(23, 18)
+#define R_RX_AWGN01_BE4 0x26818
+#define B_RX_AWGN09_BE4 GENMASK(5, 0)
+#define R_RXCH_BCC0_BE4 0x26824
+#define B_RXCH_MCS4_BE4 GENMASK(29, 24)
+#define R_RXCH_BCC1_BE4 0x26828
+#define B_RXCH_MCS5_BE4 GENMASK(5, 0)
+#define B_RXCH_MCS6_BE4 GENMASK(11, 6)
+#define B_RXCH_MCS7_BE4 GENMASK(17, 12)
+#define B_RXCH_MCS8_BE4 GENMASK(23, 18)
+#define B_RXCH_MCS9_BE4 GENMASK(29, 24)
+#define R_RX_LDPC02_BE4 0x26834
+#define B_RX_LDPC10_BE4 GENMASK(17, 12)
+#define B_RX_LDPC11_BE4 GENMASK(23, 18)
+#define R_RX_LDPC00_BE4 0x2683C
+#define B_RX_LDPC04_BE4 GENMASK(5, 0)
+#define B_RX_LDPC05_BE4 GENMASK(11, 6)
+#define B_RX_LDPC06_BE4 GENMASK(17, 12)
+#define B_RX_LDPC07_BE4 GENMASK(23, 18)
+#define B_RX_LDPC08_BE4 GENMASK(29, 24)
+#define R_RX_LDPC01_BE4 0x26840
+#define B_RX_LDPC09_BE4 GENMASK(5, 0)
#define R_SW_SI_DATA_BE4 0x2CF4C
#define B_SW_SI_READ_DATA_BE4 GENMASK(19, 0)
@@ -10576,6 +10637,9 @@
#define B_SW_SI_R_BUSY_BE4 BIT(25)
#define B_SW_SI_READ_DATA_DONE_BE4 BIT(26)
+#define R_RX_PATH0_TBL0_BE4 0x2E028
+#define R_RX_PATH1_TBL0_BE4 0x2E128
+
/* WiFi CPU local domain */
#define R_AX_WDT_CTRL 0x0040
#define B_AX_WDT_EN BIT(31)
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922d.c b/drivers/net/wireless/realtek/rtw89/rtw8922d.c
index 1b5fc6c9ea85..51b025d898ff 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922d.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922d.c
@@ -2,6 +2,7 @@
/* Copyright(c) 2026 Realtek Corporation
*/
+#include "chan.h"
#include "debug.h"
#include "efuse.h"
#include "mac.h"
@@ -1690,6 +1691,94 @@ static void rtw8922d_spur_elimination(struct rtw89_dev *rtwdev,
rtw8922d_set_nbi_tone_idx(rtwdev, chan, RF_PATH_B, phy_idx);
}
+static const u32 bbrst_mask[2] = {B_BE_FEN_BBPLAT_RSTB, B_BE_FEN_BB1PLAT_RSTB};
+static const u32 glbrst_mask[2] = {B_BE_FEN_BB_IP_RSTN, B_BE_FEN_BB1_IP_RSTN};
+static const u32 chip_top_bitmask[2] = {0xffff, 0xffff0000};
+
+static void rtw8922d_bb_preinit(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx)
+{
+ rtw89_write32_mask(rtwdev, R_BE_FEN_RST_ENABLE, glbrst_mask[phy_idx], 0x0);
+ rtw89_write32_mask(rtwdev, R_BE_FEN_RST_ENABLE, bbrst_mask[phy_idx], 0x0);
+ rtw89_write32_mask(rtwdev, R_BE_DMAC_SYS_CR32B, chip_top_bitmask[phy_idx], 0x74F9);
+ rtw89_write32_mask(rtwdev, R_BE_FEN_RST_ENABLE, glbrst_mask[phy_idx], 0x1);
+ rtw89_phy_write32_idx(rtwdev, R_RSTB_ASYNC_BE4, B_RSTB_ASYNC_BE4, 0, phy_idx);
+ rtw89_write32_mask(rtwdev, R_BE_FEN_RST_ENABLE, bbrst_mask[phy_idx], 0x1);
+}
+
+static void rtw8922d_bb_postinit(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx)
+{
+ rtw89_phy_write32_idx_clr(rtwdev, R_SHAPER_COEFF_BE4, B_SHAPER_COEFF_BE4, phy_idx);
+ rtw89_phy_write32_idx_set(rtwdev, R_SHAPER_COEFF_BE4, B_SHAPER_COEFF_BE4, phy_idx);
+}
+
+static void rtw8922d_bb_reset_en(struct rtw89_dev *rtwdev, enum rtw89_band band,
+ bool en, enum rtw89_phy_idx phy_idx)
+{
+ if (en)
+ rtw89_phy_write32_idx(rtwdev, R_RSTB_ASYNC_BE4, B_RSTB_ASYNC_BE4, 1, phy_idx);
+ else
+ rtw89_phy_write32_idx(rtwdev, R_RSTB_ASYNC_BE4, B_RSTB_ASYNC_BE4, 0, phy_idx);
+}
+
+static int rtw8922d_ctrl_tx_path_tmac(struct rtw89_dev *rtwdev,
+ enum rtw89_rf_path tx_path,
+ enum rtw89_phy_idx phy_idx)
+{
+ struct rtw89_reg2_def path_com_cr[] = {
+ {0x11A00, 0x21C86900},
+ {0x11A04, 0x00E4E433},
+ {0x11A08, 0x39390CC9},
+ {0x11A10, 0x10CC0000},
+ {0x11A14, 0x00240393},
+ {0x11A18, 0x201C8600},
+ {0x11B38, 0x39393FDB},
+ {0x11B3C, 0x00E4E4FF},
+ };
+ int ret = 0;
+ u32 reg;
+ int i;
+
+ rtw89_phy_write32_idx(rtwdev, R_TXINFO_PATH_BE4, B_TXINFO_PATH_EN_BE4, 0x0, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_TXINFO_PATH_BE4, B_TXINFO_PATH_MA_BE4, 0x0, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_TXINFO_PATH_BE4, B_TXINFO_PATH_MB_BE4, 0x0, phy_idx);
+
+ if (phy_idx == RTW89_PHY_1 && !rtwdev->dbcc_en)
+ return 0;
+
+ if (tx_path == RF_PATH_A) {
+ path_com_cr[1].data = 0x40031;
+ path_com_cr[2].data = 0x1000C48;
+ path_com_cr[5].data = 0x200;
+ path_com_cr[6].data = 0x1000C48;
+ path_com_cr[7].data = 0x40031;
+ } else if (tx_path == RF_PATH_B) {
+ path_com_cr[1].data = 0x40032;
+ path_com_cr[2].data = 0x1000C88;
+ path_com_cr[5].data = 0x400;
+ path_com_cr[6].data = 0x1000C88;
+ path_com_cr[7].data = 0x40032;
+ } else if (tx_path == RF_PATH_AB) {
+ path_com_cr[1].data = 0x00E4E433;
+ path_com_cr[2].data = 0x39390CC9;
+ path_com_cr[5].data = 0x201C8600;
+ path_com_cr[6].data = 0x1010CC9;
+ path_com_cr[7].data = 0x40433;
+ } else {
+ ret = -EINVAL;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(path_com_cr); i++) {
+ reg = rtw89_mac_reg_by_idx(rtwdev, path_com_cr[i].addr, phy_idx);
+ rtw89_write32(rtwdev, reg, path_com_cr[i].data);
+ }
+
+ return ret;
+}
+
+static void rtw8922d_bb_reset(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx)
+{
+}
+
static void rtw8922d_tssi_reset(struct rtw89_dev *rtwdev,
enum rtw89_rf_path path,
enum rtw89_phy_idx phy_idx)
@@ -1714,6 +1803,235 @@ static void rtw8922d_tssi_reset(struct rtw89_dev *rtwdev,
}
}
+static int rtw8922d_ctrl_rx_path_tmac(struct rtw89_dev *rtwdev,
+ enum rtw89_rf_path rx_path,
+ enum rtw89_phy_idx phy_idx)
+{
+ enum rtw89_rf_path_bit path;
+
+ if (rx_path == RF_PATH_A)
+ path = RF_A;
+ else if (rx_path == RF_PATH_B)
+ path = RF_B;
+ else
+ path = RF_AB;
+
+ rtw89_phy_write32_idx(rtwdev, R_ANT_RX_BE4, B_ANT_RX_BE4, path, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_ANT_RX_1RCCA_BE4, B_ANT_RX_1RCCA_BE4,
+ path, phy_idx);
+
+ if (rx_path == RF_PATH_AB) {
+ rtw89_phy_write32_idx(rtwdev, R_RXCH_BCC0_BE4, B_RXCH_MCS4_BE4, 8, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXCH_BCC1_BE4, B_RXCH_MCS5_BE4, 4, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXCH_BCC1_BE4, B_RXCH_MCS6_BE4, 3, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXCH_BCC1_BE4, B_RXCH_MCS7_BE4, 7, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXCH_BCC1_BE4, B_RXCH_MCS8_BE4, 2, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXCH_BCC1_BE4, B_RXCH_MCS9_BE4, 2, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_AWGN00_BE4, B_RX_AWGN04_BE4, 4, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_AWGN00_BE4, B_RX_AWGN07_BE4, 2, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_AWGN01_BE4, B_RX_AWGN09_BE4, 0, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_AWGN02_BE4, B_RX_AWGN11_BE4, 1, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_LDPC00_BE4, B_RX_LDPC04_BE4, 8, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_LDPC00_BE4, B_RX_LDPC05_BE4, 5, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_LDPC00_BE4, B_RX_LDPC06_BE4, 3, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_LDPC00_BE4, B_RX_LDPC07_BE4, 5, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_LDPC00_BE4, B_RX_LDPC08_BE4, 1, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_LDPC01_BE4, B_RX_LDPC09_BE4, 2, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_LDPC02_BE4, B_RX_LDPC10_BE4, 4, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_LDPC02_BE4, B_RX_LDPC11_BE4, 2, phy_idx);
+ } else {
+ rtw89_phy_write32_idx(rtwdev, R_RXCH_BCC0_BE4, B_RXCH_MCS4_BE4, 13, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXCH_BCC1_BE4, B_RXCH_MCS5_BE4, 15, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXCH_BCC1_BE4, B_RXCH_MCS6_BE4, 6, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXCH_BCC1_BE4, B_RXCH_MCS7_BE4, 15, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXCH_BCC1_BE4, B_RXCH_MCS8_BE4, 4, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXCH_BCC1_BE4, B_RXCH_MCS9_BE4, 15, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_AWGN00_BE4, B_RX_AWGN04_BE4, 9, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_AWGN00_BE4, B_RX_AWGN07_BE4, 3, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_AWGN01_BE4, B_RX_AWGN09_BE4, 1, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_AWGN02_BE4, B_RX_AWGN11_BE4, 0, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_LDPC00_BE4, B_RX_LDPC04_BE4, 9, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_LDPC00_BE4, B_RX_LDPC05_BE4, 8, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_LDPC00_BE4, B_RX_LDPC06_BE4, 6, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_LDPC00_BE4, B_RX_LDPC07_BE4, 16, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_LDPC00_BE4, B_RX_LDPC08_BE4, 4, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_LDPC01_BE4, B_RX_LDPC09_BE4, 9, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_LDPC02_BE4, B_RX_LDPC10_BE4, 9, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_LDPC02_BE4, B_RX_LDPC11_BE4, 7, phy_idx);
+ }
+
+ return 0;
+}
+
+static void rtw8922d_set_digital_pwr_comp(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan, u8 nss,
+ enum rtw89_rf_path path,
+ enum rtw89_phy_idx phy_idx)
+{
+#define DIGITAL_PWR_COMP_REG_NUM 22
+ static const u32 pw_comp_cr[2] = {R_RX_PATH0_TBL0_BE4, R_RX_PATH1_TBL0_BE4};
+ const __le32 (*pwr_comp_val)[2][RTW89_TX_COMP_BAND_NR]
+ [BB_PATH_NUM_8922D][DIGITAL_PWR_COMP_REG_NUM];
+ struct rtw89_fw_elm_info *elm_info = &rtwdev->fw.elm_info;
+ const struct rtw89_fw_element_hdr *txcomp_elm = elm_info->tx_comp;
+ const __le32 *digital_pwr_comp;
+ u32 addr, val;
+ u32 i;
+
+ if (sizeof(*pwr_comp_val) != le32_to_cpu(txcomp_elm->size)) {
+ rtw89_debug(rtwdev, RTW89_DBG_UNEXP,
+ "incorrect power comp size %d\n",
+ le32_to_cpu(txcomp_elm->size));
+ return;
+ }
+
+ pwr_comp_val = (const void *)txcomp_elm->u.common.contents;
+ digital_pwr_comp = (*pwr_comp_val)[nss][chan->tx_comp_band][path];
+ addr = pw_comp_cr[path];
+
+ for (i = 0; i < DIGITAL_PWR_COMP_REG_NUM; i++, addr += 4) {
+ val = le32_to_cpu(digital_pwr_comp[i]);
+ rtw89_phy_write32_idx(rtwdev, addr, MASKDWORD, val, phy_idx);
+ }
+}
+
+static void rtw8922d_digital_pwr_comp(struct rtw89_dev *rtwdev,
+ enum rtw89_phy_idx phy_idx)
+{
+ const struct rtw89_chan *chan0 = rtw89_mgnt_chan_get(rtwdev, 0);
+ const struct rtw89_chan *chan1 = rtw89_mgnt_chan_get(rtwdev, 1);
+
+ if (rtwdev->mlo_dbcc_mode == MLO_1_PLUS_1_1RF) {
+ rtw8922d_set_digital_pwr_comp(rtwdev, chan0, 0, RF_PATH_A, RTW89_PHY_0);
+ rtw8922d_set_digital_pwr_comp(rtwdev, chan1, 0, RF_PATH_B, RTW89_PHY_1);
+ } else {
+ rtw8922d_set_digital_pwr_comp(rtwdev, chan0, 1, RF_PATH_A, phy_idx);
+ rtw8922d_set_digital_pwr_comp(rtwdev, chan0, 1, RF_PATH_B, phy_idx);
+ }
+}
+
+static int rtw8922d_ctrl_mlo(struct rtw89_dev *rtwdev, enum rtw89_mlo_dbcc_mode mode,
+ bool pwr_comp)
+{
+ const struct rtw89_chan *chan1;
+ u32 reg0, reg1;
+ u8 cck_phy_idx;
+
+ if (mode == MLO_2_PLUS_0_1RF) {
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xBBBB);
+ udelay(1);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_BB_CLK_BE4, 0x3);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xAFFF);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xEBAD);
+ udelay(1);
+
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_BB_CLK_BE4, 0x0);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xEAAD);
+ } else if (mode == MLO_0_PLUS_2_1RF) {
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xBBBB);
+ udelay(1);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_BB_CLK_BE4, 0x3);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xAFFF);
+ udelay(1);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xEFFF);
+
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_BB_CLK_BE4, 0x0);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xEEFF);
+ } else if ((mode == MLO_1_PLUS_1_1RF) || (mode == DBCC_LEGACY)) {
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xBBBB);
+ udelay(1);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_BB_CLK_BE4, 0x3);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xAFFF);
+ udelay(1);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_BB_CLK_BE4, 0x0);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0x3AAB);
+ } else {
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0x6180);
+ udelay(1);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_BB_CLK_BE4, 0x3);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0x180);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_BB_CLK_BE4, 0x0);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0x0);
+ }
+
+ if (pwr_comp)
+ rtw8922d_digital_pwr_comp(rtwdev, RTW89_PHY_0);
+
+ reg0 = R_BBWRAP_ELMSR_BE4;
+ reg1 = rtw89_mac_reg_by_idx(rtwdev, reg0, 1);
+
+ if (mode == MLO_2_PLUS_0_1RF) {
+ rtw89_phy_write32_mask(rtwdev, R_SYS_DBCC_BE4,
+ B_SYS_DBCC_24G_BAND_SEL_BE4, RTW89_PHY_0);
+ rtw89_write32_mask(rtwdev, reg0, B_BBWRAP_ELMSR_EN_BE4, 0);
+ rtw89_write32_mask(rtwdev, reg1, B_BBWRAP_ELMSR_EN_BE4, 0);
+ } else if (mode == MLO_0_PLUS_2_1RF) {
+ rtw89_phy_write32_mask(rtwdev, R_SYS_DBCC_BE4,
+ B_SYS_DBCC_24G_BAND_SEL_BE4, RTW89_PHY_0);
+ rtw89_write32_mask(rtwdev, reg0, B_BBWRAP_ELMSR_EN_BE4, 0);
+ rtw89_write32_mask(rtwdev, reg1, B_BBWRAP_ELMSR_EN_BE4, 0);
+ } else if ((mode == MLO_1_PLUS_1_1RF) || (mode == DBCC_LEGACY)) {
+ chan1 = rtw89_mgnt_chan_get(rtwdev, 1);
+ cck_phy_idx = chan1->band_type == RTW89_BAND_2G ?
+ RTW89_PHY_1 : RTW89_PHY_0;
+
+ rtw89_phy_write32_mask(rtwdev, R_SYS_DBCC_BE4,
+ B_SYS_DBCC_24G_BAND_SEL_BE4, cck_phy_idx);
+ rtw89_write32_mask(rtwdev, reg0, B_BBWRAP_ELMSR_EN_BE4, 0x3);
+ rtw89_write32_mask(rtwdev, reg1, B_BBWRAP_ELMSR_EN_BE4, 0x3);
+ } else {
+ rtw89_phy_write32_mask(rtwdev, R_SYS_DBCC_BE4,
+ B_SYS_DBCC_24G_BAND_SEL_BE4, RTW89_PHY_0);
+ rtw89_write32_mask(rtwdev, reg0, B_BBWRAP_ELMSR_EN_BE4, 0);
+ rtw89_write32_mask(rtwdev, reg1, B_BBWRAP_ELMSR_EN_BE4, 0);
+ }
+
+ udelay(1);
+
+ return 0;
+}
+
+static void rtw8922d_bb_sethw(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_phy_efuse_gain *gain = &rtwdev->efuse_gain;
+ struct rtw89_hal *hal = &rtwdev->hal;
+ enum rtw89_phy_idx phy_idx;
+ u32 reg;
+
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_PWR_BOOST, RTW89_PHY_0);
+ rtw89_write32_clr(rtwdev, reg, B_BE_PWR_CTRL_SEL);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_PWR_BOOST, RTW89_PHY_1);
+ rtw89_write32_clr(rtwdev, reg, B_BE_PWR_CTRL_SEL);
+
+ if (hal->cid == RTL8922D_CID7090) {
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_PWR_BOOST_BE4, RTW89_PHY_0);
+ rtw89_write32_set(rtwdev, reg, B_PWR_BOOST_BE4);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_PWR_BOOST_BE4, RTW89_PHY_1);
+ rtw89_write32_set(rtwdev, reg, B_PWR_BOOST_BE4);
+ }
+
+ rtw89_phy_write32_mask(rtwdev, R_TX_ERROR_SEL_BE4, B_TX_ERROR_PSDU_BE4, 0);
+ rtw89_phy_write32_mask(rtwdev, R_TX_ERROR_SEL_BE4, B_TX_ERROR_NSYM_BE4, 1);
+ rtw89_phy_write32_mask(rtwdev, R_TX_ERROR_SEL_BE4, B_TX_ERROR_LSIG_BE4, 1);
+ rtw89_phy_write32_mask(rtwdev, R_TX_ERROR_SEL_BE4, B_TX_ERROR_TXINFO_BE4, 1);
+ rtw89_phy_write32_mask(rtwdev, R_TXERRCT_EN_BE4, B_TXERRCT_EN_BE4, 0);
+ rtw89_phy_write32_mask(rtwdev, R_TXERRCT1_EN_BE4, B_TXERRCT1_EN_BE4, 0);
+ rtw89_phy_write32_idx(rtwdev, R_IMR_TX_ERROR_BE4, B_IMR_TX_ERROR_BE4, 1, RTW89_PHY_0);
+ rtw89_phy_write32_idx(rtwdev, R_IMR_TX_ERROR_BE4, B_IMR_TX_ERROR_BE4, 1, RTW89_PHY_1);
+
+ rtw8922d_ctrl_mlo(rtwdev, rtwdev->mlo_dbcc_mode, false);
+
+ /* read these registers after loading BB parameters */
+ for (phy_idx = RTW89_PHY_0; phy_idx < RTW89_PHY_NUM; phy_idx++) {
+ gain->ref_gain_base[phy_idx] =
+ rtw89_phy_read32_idx(rtwdev, R_OFDM_OFST_P0_BE4,
+ B_OFDM_OFST_P0_BE4, phy_idx);
+ gain->cck_rpl_base[phy_idx] =
+ rtw89_phy_read32_idx(rtwdev, R_CCK_RPL_OFST_BE4,
+ B_CCK_RPL_OFST_BE4, phy_idx);
+ }
+}
+
static void rtw8922d_set_channel_bb(struct rtw89_dev *rtwdev,
const struct rtw89_chan *chan,
enum rtw89_phy_idx phy_idx)
--
2.25.1
^ permalink raw reply related
* [PATCH rtw-next 2/9] wifi: rtw89: 8922d: add set channel with pre-/post- helpers
From: Ping-Ke Shih @ 2026-03-30 6:58 UTC (permalink / raw)
To: linux-wireless
In-Reply-To: <20260330065847.48946-1-pkshih@realtek.com>
The main set channel function calls MAC/BB/RF ones, and pre-/post- helpers
are called before/after the main function to backup/restore and
stop/restart circuits, including TX scheduler, PPDU status, DACK and TSSI.
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/reg.h | 14 ++
drivers/net/wireless/realtek/rtw89/rtw8922d.c | 102 ++++++++
.../net/wireless/realtek/rtw89/rtw8922d_rfk.c | 230 ++++++++++++++++++
.../net/wireless/realtek/rtw89/rtw8922d_rfk.h | 4 +
4 files changed, 350 insertions(+)
diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h
index e64bd74db83a..195d4806c4ef 100644
--- a/drivers/net/wireless/realtek/rtw89/reg.h
+++ b/drivers/net/wireless/realtek/rtw89/reg.h
@@ -8445,6 +8445,8 @@
#define RR_MOD_M_RXBB GENMASK(9, 5)
#define RR_MOD_LO_SEL BIT(1)
#define RR_MODOPT 0x01
+#define RR_MODOPT_V1 0x10001
+#define RR_SW_SEL BIT(19)
#define RR_TXG_SEL GENMASK(19, 17)
#define RR_MODOPT_M_TXPWR GENMASK(5, 0)
#define RR_WLSEL 0x02
@@ -10527,6 +10529,8 @@
#define R_TXPWR_RSTB0_BE4 0x2250C
#define B_TXPWR_RSTB0_BE4 BIT(16)
+#define R_TSSI_EN_P0_BE4 0x22510
+#define B_TSSI_EN_P0_BE4 GENMASK(3, 0)
#define R_TXPWR_RSTB1_BE4 0x2260C
#define B_TXPWR_RSTB1_BE4 BIT(16)
@@ -10640,6 +10644,16 @@
#define R_RX_PATH0_TBL0_BE4 0x2E028
#define R_RX_PATH1_TBL0_BE4 0x2E128
+#define R_KTBL0A_BE4 0x38104
+#define R_KTBL0B_BE4 0x38204
+#define B_KTBL0_IDX0 GENMASK(1, 0)
+#define B_KTBL0_IDX1 GENMASK(9, 8)
+#define B_KTBL0_RST BIT(31)
+#define R_KTBL1A_BE4 0x38154
+#define R_KTBL1B_BE4 0x38254
+#define B_KTBL1_TBL0 BIT(3)
+#define B_KTBL1_TBL1 BIT(5)
+
/* WiFi CPU local domain */
#define R_AX_WDT_CTRL 0x0040
#define B_AX_WDT_EN BIT(31)
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922d.c b/drivers/net/wireless/realtek/rtw89/rtw8922d.c
index 51b025d898ff..a2dd504c99ed 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922d.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922d.c
@@ -2066,6 +2066,108 @@ static void rtw8922d_set_channel_bb(struct rtw89_dev *rtwdev,
rtw8922d_tssi_reset(rtwdev, RF_PATH_AB, phy_idx);
}
+static void rtw8922d_pre_set_channel_bb(struct rtw89_dev *rtwdev,
+ enum rtw89_phy_idx phy_idx)
+{
+ if (!rtwdev->dbcc_en)
+ return;
+
+ rtw89_phy_write32_mask(rtwdev, R_SYS_DBCC_BE4, B_SYS_DBCC_BE4, 0x0);
+
+ if (phy_idx == RTW89_PHY_0) {
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xBBBB);
+ fsleep(1);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_BB_CLK_BE4, 0x3);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xAFFF);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xEBAD);
+ fsleep(1);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_BB_CLK_BE4, 0x0);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xEAAD);
+ } else {
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xBBBB);
+ fsleep(1);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_BB_CLK_BE4, 0x3);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xAFFF);
+ fsleep(1);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xEFFF);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_BB_CLK_BE4, 0x0);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xEEFF);
+ }
+
+ fsleep(1);
+}
+
+static void rtw8922d_post_set_channel_bb(struct rtw89_dev *rtwdev,
+ enum rtw89_mlo_dbcc_mode mode,
+ enum rtw89_phy_idx phy_idx)
+{
+ if (!rtwdev->dbcc_en)
+ return;
+
+ rtw8922d_ctrl_mlo(rtwdev, mode, true);
+}
+
+static void rtw8922d_set_channel(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan,
+ enum rtw89_mac_idx mac_idx,
+ enum rtw89_phy_idx phy_idx)
+{
+ rtw8922d_set_channel_mac(rtwdev, chan, mac_idx);
+ rtw8922d_set_channel_bb(rtwdev, chan, phy_idx);
+ rtw8922d_set_channel_rf(rtwdev, chan, phy_idx);
+}
+
+static void __rtw8922d_dack_reset(struct rtw89_dev *rtwdev, enum rtw89_rf_path path)
+{
+ rtw89_phy_write32_mask(rtwdev, 0x3c000 + (path << 8), BIT(17), 0x0);
+ rtw89_phy_write32_mask(rtwdev, 0x3c000 + (path << 8), BIT(17), 0x1);
+}
+
+static void rtw8922d_dack_reset(struct rtw89_dev *rtwdev)
+{
+ __rtw8922d_dack_reset(rtwdev, RF_PATH_A);
+ __rtw8922d_dack_reset(rtwdev, RF_PATH_B);
+}
+
+static
+void rtw8922d_hal_reset(struct rtw89_dev *rtwdev,
+ enum rtw89_phy_idx phy_idx, enum rtw89_mac_idx mac_idx,
+ enum rtw89_band band, u32 *tx_en, bool enter)
+{
+ if (enter) {
+ rtw89_chip_stop_sch_tx(rtwdev, mac_idx, tx_en, RTW89_SCH_TX_SEL_ALL);
+ rtw89_mac_cfg_ppdu_status(rtwdev, mac_idx, false);
+ rtw8922d_dack_reset(rtwdev);
+ rtw8922d_tssi_cont_en_phyidx(rtwdev, false, phy_idx);
+ fsleep(40);
+ rtw8922d_bb_reset_en(rtwdev, band, false, phy_idx);
+ } else {
+ rtw89_mac_cfg_ppdu_status(rtwdev, mac_idx, true);
+ rtw8922d_tssi_cont_en_phyidx(rtwdev, true, phy_idx);
+ rtw8922d_bb_reset_en(rtwdev, band, true, phy_idx);
+ rtw89_chip_resume_sch_tx(rtwdev, mac_idx, *tx_en);
+ }
+}
+
+static void rtw8922d_set_channel_help(struct rtw89_dev *rtwdev, bool enter,
+ struct rtw89_channel_help_params *p,
+ const struct rtw89_chan *chan,
+ enum rtw89_mac_idx mac_idx,
+ enum rtw89_phy_idx phy_idx)
+{
+ if (enter) {
+ rtw8922d_pre_set_channel_bb(rtwdev, phy_idx);
+ rtw8922d_pre_set_channel_rf(rtwdev, phy_idx);
+ }
+
+ rtw8922d_hal_reset(rtwdev, phy_idx, mac_idx, chan->band_type, &p->tx_en, enter);
+
+ if (!enter) {
+ rtw8922d_post_set_channel_bb(rtwdev, rtwdev->mlo_dbcc_mode, phy_idx);
+ rtw8922d_post_set_channel_rf(rtwdev, phy_idx);
+ }
+}
+
MODULE_FIRMWARE(RTW8922D_MODULE_FIRMWARE);
MODULE_FIRMWARE(RTW8922DS_MODULE_FIRMWARE);
MODULE_AUTHOR("Realtek Corporation");
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.c
index 6b35d196cb81..d1eda19a39a9 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.c
@@ -2,11 +2,40 @@
/* Copyright(c) 2026 Realtek Corporation
*/
+#include "chan.h"
+#include "debug.h"
#include "phy.h"
#include "reg.h"
#include "rtw8922d.h"
#include "rtw8922d_rfk.h"
+static void rtw8922d_tssi_cont_en(struct rtw89_dev *rtwdev, bool en,
+ enum rtw89_rf_path path, u8 phy_idx)
+{
+ static const u32 tssi_trk_man[2] = {R_TSSI_EN_P0_BE4,
+ R_TSSI_EN_P0_BE4 + 0x100};
+
+ if (en)
+ rtw89_phy_write32_idx(rtwdev, tssi_trk_man[path],
+ B_TSSI_CONT_EN, 0, phy_idx);
+ else
+ rtw89_phy_write32_idx(rtwdev, tssi_trk_man[path],
+ B_TSSI_CONT_EN, 1, phy_idx);
+}
+
+void rtw8922d_tssi_cont_en_phyidx(struct rtw89_dev *rtwdev, bool en, u8 phy_idx)
+{
+ if (rtwdev->mlo_dbcc_mode == MLO_1_PLUS_1_1RF) {
+ if (phy_idx == RTW89_PHY_0)
+ rtw8922d_tssi_cont_en(rtwdev, en, RF_PATH_A, phy_idx);
+ else
+ rtw8922d_tssi_cont_en(rtwdev, en, RF_PATH_B, phy_idx);
+ } else {
+ rtw8922d_tssi_cont_en(rtwdev, en, RF_PATH_A, phy_idx);
+ rtw8922d_tssi_cont_en(rtwdev, en, RF_PATH_B, phy_idx);
+ }
+}
+
static
void rtw8922d_ctl_band_ch_bw(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy,
const struct rtw89_chan *chan)
@@ -31,3 +60,204 @@ void rtw8922d_set_channel_rf(struct rtw89_dev *rtwdev,
{
rtw8922d_ctl_band_ch_bw(rtwdev, phy_idx, chan);
}
+
+enum _rf_syn_pow {
+ RF_SYN_ON_OFF,
+ RF_SYN_OFF_ON,
+ RF_SYN_ALLON,
+ RF_SYN_ALLOFF,
+};
+
+static void rtw8922d_set_syn01(struct rtw89_dev *rtwdev, enum _rf_syn_pow syn)
+{
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "SYN config=%d\n", syn);
+
+ if (syn == RF_SYN_ALLON) {
+ rtw89_write_rf(rtwdev, RF_PATH_A, RR_MOD, BIT(1), 0x0);
+ rtw89_write_rf(rtwdev, RF_PATH_B, RR_MOD, BIT(1), 0x0);
+ rtw89_write_rf(rtwdev, RF_PATH_A, RR_RSV1, MASKDWORD, 0x0);
+ rtw89_write_rf(rtwdev, RF_PATH_B, RR_RSV1, MASKDWORD, 0x0);
+ rtw89_write_rf(rtwdev, RF_PATH_A, RR_POW, RR_POW_SYN_V1, 0xf);
+ rtw89_write_rf(rtwdev, RF_PATH_B, RR_POW, RR_POW_SYN_V1, 0xf);
+ rtw89_write_rf(rtwdev, RF_PATH_A, RR_RSV1, MASKDWORD, 0x1);
+ rtw89_write_rf(rtwdev, RF_PATH_B, RR_RSV1, MASKDWORD, 0x1);
+ } else if (syn == RF_SYN_ON_OFF) {
+ rtw89_write_rf(rtwdev, RF_PATH_A, RR_MOD, BIT(1), 0x0);
+ rtw89_write_rf(rtwdev, RF_PATH_A, RR_RSV1, MASKDWORD, 0x0);
+ rtw89_write_rf(rtwdev, RF_PATH_A, RR_POW, RR_POW_SYN_V1, 0xf);
+ rtw89_write_rf(rtwdev, RF_PATH_B, RR_POW, RR_POW_SYN_V1, 0x0);
+ rtw89_write_rf(rtwdev, RF_PATH_A, RR_RSV1, MASKDWORD, 0x1);
+ } else if (syn == RF_SYN_OFF_ON) {
+ rtw89_write_rf(rtwdev, RF_PATH_B, RR_MOD, BIT(1), 0x0);
+ rtw89_write_rf(rtwdev, RF_PATH_B, RR_RSV1, MASKDWORD, 0x0);
+ rtw89_write_rf(rtwdev, RF_PATH_A, RR_POW, RR_POW_SYN_V1, 0x0);
+ rtw89_write_rf(rtwdev, RF_PATH_B, RR_POW, RR_POW_SYN_V1, 0xf);
+ rtw89_write_rf(rtwdev, RF_PATH_B, RR_RSV1, MASKDWORD, 0x1);
+ } else if (syn == RF_SYN_ALLOFF) {
+ rtw89_write_rf(rtwdev, RF_PATH_A, RR_POW, RR_POW_SYN_V1, 0x0);
+ rtw89_write_rf(rtwdev, RF_PATH_B, RR_POW, RR_POW_SYN_V1, 0x0);
+ }
+}
+
+static void rtw8922d_chlk_ktbl_sel(struct rtw89_dev *rtwdev, u8 kpath, u8 idx)
+{
+ bool mlo_linking = false;
+
+ if (idx > 2) {
+ rtw89_warn(rtwdev, "[DBCC][ERROR]indx is out of limit!! index(%d)", idx);
+ return;
+ }
+
+ if (mlo_linking) {
+ if (kpath & RF_A) {
+ rtw89_write_rf(rtwdev, RF_PATH_A, RR_MODOPT, RR_SW_SEL, 0x0);
+ rtw89_write_rf(rtwdev, RF_PATH_A, RR_MODOPT_V1, RR_SW_SEL, 0x0);
+ }
+
+ if (kpath & RF_B) {
+ rtw89_write_rf(rtwdev, RF_PATH_B, RR_MODOPT, RR_SW_SEL, 0x0);
+ rtw89_write_rf(rtwdev, RF_PATH_B, RR_MODOPT_V1, RR_SW_SEL, 0x0);
+ }
+
+ return;
+ }
+
+ if (kpath & RF_A) {
+ rtw89_phy_write32_mask(rtwdev, R_KTBL0A_BE4, B_KTBL0_RST, 0x1);
+ rtw89_phy_write32_mask(rtwdev, R_KTBL0A_BE4, B_KTBL0_IDX0, idx);
+ rtw89_phy_write32_mask(rtwdev, R_KTBL0A_BE4, B_KTBL0_IDX1, idx);
+
+ rtw89_write_rf(rtwdev, RF_PATH_A, RR_MODOPT, RR_TXG_SEL, 0x4 | idx);
+ rtw89_write_rf(rtwdev, RF_PATH_A, RR_MODOPT_V1, RR_TXG_SEL, 0x4 | idx);
+
+ rtw89_phy_write32_mask(rtwdev, R_KTBL1A_BE4, B_KTBL1_TBL0, idx & BIT(0));
+ rtw89_phy_write32_mask(rtwdev, R_KTBL1A_BE4, B_KTBL1_TBL1, (idx & BIT(1)) >> 1);
+ }
+
+ if (kpath & RF_B) {
+ rtw89_phy_write32_mask(rtwdev, R_KTBL0B_BE4, B_KTBL0_RST, 0x1);
+ rtw89_phy_write32_mask(rtwdev, R_KTBL0B_BE4, B_KTBL0_IDX0, idx);
+ rtw89_phy_write32_mask(rtwdev, R_KTBL0B_BE4, B_KTBL0_IDX1, idx);
+
+ rtw89_write_rf(rtwdev, RF_PATH_B, RR_MODOPT, RR_TXG_SEL, 0x4 | idx);
+ rtw89_write_rf(rtwdev, RF_PATH_B, RR_MODOPT_V1, RR_TXG_SEL, 0x4 | idx);
+
+ rtw89_phy_write32_mask(rtwdev, R_KTBL1B_BE4, B_KTBL1_TBL0, idx & BIT(0));
+ rtw89_phy_write32_mask(rtwdev, R_KTBL1B_BE4, B_KTBL1_TBL1, (idx & BIT(1)) >> 1);
+ }
+}
+
+static u8 rtw8922d_chlk_reload_sel_tbl(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan, u8 path)
+{
+ struct rtw89_rfk_mcc_info_data *rfk_mcc = rtwdev->rfk_mcc.data;
+ struct rtw89_rfk_chan_desc desc[__RTW89_RFK_CHS_NR_V1] = {};
+ u8 tbl_sel;
+
+ for (tbl_sel = 0; tbl_sel < ARRAY_SIZE(desc); tbl_sel++) {
+ struct rtw89_rfk_chan_desc *p = &desc[tbl_sel];
+
+ p->ch = rfk_mcc->ch[tbl_sel];
+
+ p->has_band = true;
+ p->band = rfk_mcc->band[tbl_sel];
+
+ p->has_bw = true;
+ p->bw = rfk_mcc->bw[tbl_sel];
+ }
+
+ tbl_sel = rtw89_rfk_chan_lookup(rtwdev, desc, ARRAY_SIZE(desc), chan);
+
+ rfk_mcc->ch[tbl_sel] = chan->channel;
+ rfk_mcc->band[tbl_sel] = chan->band_type;
+ rfk_mcc->bw[tbl_sel] = chan->band_width;
+ rfk_mcc->rf18[tbl_sel] = rtw89_chip_chan_to_rf18_val(rtwdev, chan);
+
+ /* shared table array, but tbl_sel can be independent by path */
+ rfk_mcc[path].table_idx = tbl_sel;
+
+ return tbl_sel;
+}
+
+static void rtw8922d_chlk_reload(struct rtw89_dev *rtwdev)
+{
+ const struct rtw89_chan *chan0, *chan1;
+ u8 s0_tbl, s1_tbl;
+
+ switch (rtwdev->mlo_dbcc_mode) {
+ default:
+ case MLO_2_PLUS_0_1RF:
+ chan0 = rtw89_mgnt_chan_get(rtwdev, 0);
+ chan1 = chan0;
+ break;
+ case MLO_0_PLUS_2_1RF:
+ chan1 = rtw89_mgnt_chan_get(rtwdev, 1);
+ chan0 = chan1;
+ break;
+ case MLO_1_PLUS_1_1RF:
+ chan0 = rtw89_mgnt_chan_get(rtwdev, 0);
+ chan1 = rtw89_mgnt_chan_get(rtwdev, 1);
+ break;
+ }
+
+ s0_tbl = rtw8922d_chlk_reload_sel_tbl(rtwdev, chan0, 0);
+ s1_tbl = rtw8922d_chlk_reload_sel_tbl(rtwdev, chan1, 1);
+
+ rtw8922d_chlk_ktbl_sel(rtwdev, RF_A, s0_tbl);
+ rtw8922d_chlk_ktbl_sel(rtwdev, RF_B, s1_tbl);
+}
+
+static enum _rf_syn_pow rtw8922d_get_syn_pow(struct rtw89_dev *rtwdev)
+{
+ switch (rtwdev->mlo_dbcc_mode) {
+ case MLO_0_PLUS_2_1RF:
+ return RF_SYN_OFF_ON;
+ case MLO_0_PLUS_2_2RF:
+ case MLO_1_PLUS_1_2RF:
+ case MLO_2_PLUS_0_1RF:
+ case MLO_2_PLUS_0_2RF:
+ case MLO_2_PLUS_2_2RF:
+ case MLO_DBCC_NOT_SUPPORT:
+ default:
+ return RF_SYN_ON_OFF;
+ case MLO_1_PLUS_1_1RF:
+ case DBCC_LEGACY:
+ return RF_SYN_ALLON;
+ }
+}
+
+void rtw8922d_rfk_mlo_ctrl(struct rtw89_dev *rtwdev)
+{
+ enum _rf_syn_pow syn_pow = rtw8922d_get_syn_pow(rtwdev);
+
+ if (!rtwdev->dbcc_en)
+ goto set_rfk_reload;
+
+ rtw8922d_set_syn01(rtwdev, syn_pow);
+
+set_rfk_reload:
+ rtw8922d_chlk_reload(rtwdev);
+}
+
+void rtw8922d_pre_set_channel_rf(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx)
+{
+ bool mlo_1_1;
+
+ if (!rtwdev->dbcc_en)
+ return;
+
+ mlo_1_1 = rtw89_is_mlo_1_1(rtwdev);
+ if (mlo_1_1)
+ rtw8922d_set_syn01(rtwdev, RF_SYN_ALLON);
+ else if (phy_idx == RTW89_PHY_0)
+ rtw8922d_set_syn01(rtwdev, RF_SYN_ON_OFF);
+ else
+ rtw8922d_set_syn01(rtwdev, RF_SYN_OFF_ON);
+
+ fsleep(1000);
+}
+
+void rtw8922d_post_set_channel_rf(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx)
+{
+ rtw8922d_rfk_mlo_ctrl(rtwdev);
+}
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.h b/drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.h
index 03af1f0497ac..4c505ae24261 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.h
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.h
@@ -7,8 +7,12 @@
#include "core.h"
+void rtw8922d_tssi_cont_en_phyidx(struct rtw89_dev *rtwdev, bool en, u8 phy_idx);
void rtw8922d_set_channel_rf(struct rtw89_dev *rtwdev,
const struct rtw89_chan *chan,
enum rtw89_phy_idx phy_idx);
+void rtw8922d_rfk_mlo_ctrl(struct rtw89_dev *rtwdev);
+void rtw8922d_pre_set_channel_rf(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx);
+void rtw8922d_post_set_channel_rf(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx);
#endif
--
2.25.1
^ permalink raw reply related
* [PATCH rtw-next 3/9] wifi: rtw89: 8922d: add RF calibration ops
From: Ping-Ke Shih @ 2026-03-30 6:58 UTC (permalink / raw)
To: linux-wireless
In-Reply-To: <20260330065847.48946-1-pkshih@realtek.com>
The chips ops related to RF calibration include init, init_late, channel,
band_change, scan, and track. The init_late is similar to init, but HCI
is ready, so receiving C2H event is possible. The ops channel is the main
function that do all RF calibration on operating channel.
The ops band_change and scan are to reset RF calibration because channel is
switching at these moment, we need to reset RF state. The ops track is to
monitor temperature to check if re-calibrate RF again.
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/reg.h | 4 +
drivers/net/wireless/realtek/rtw89/rtw8922d.c | 154 ++++++++++++++++++
.../net/wireless/realtek/rtw89/rtw8922d_rfk.c | 85 ++++++++++
.../net/wireless/realtek/rtw89/rtw8922d_rfk.h | 1 +
4 files changed, 244 insertions(+)
diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h
index 195d4806c4ef..1a5a5b30a28e 100644
--- a/drivers/net/wireless/realtek/rtw89/reg.h
+++ b/drivers/net/wireless/realtek/rtw89/reg.h
@@ -10531,6 +10531,10 @@
#define B_TXPWR_RSTB0_BE4 BIT(16)
#define R_TSSI_EN_P0_BE4 0x22510
#define B_TSSI_EN_P0_BE4 GENMASK(3, 0)
+#define R_USED_TSSI_TRK_ON_P0_BE4 0x22534
+#define B_USED_TSSI_TRK_ON_P0_BE4 BIT(22)
+#define R_TSSI_DCK_MOV_AVG_LEN_P0_BE4 0x225CC
+#define B_TSSI_DCK_MOV_AVG_LEN_P0_BE4 GENMASK(8, 6)
#define R_TXPWR_RSTB1_BE4 0x2260C
#define B_TXPWR_RSTB1_BE4 BIT(16)
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922d.c b/drivers/net/wireless/realtek/rtw89/rtw8922d.c
index a2dd504c99ed..2e6f4504caeb 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922d.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922d.c
@@ -3,6 +3,7 @@
*/
#include "chan.h"
+#include "coex.h"
#include "debug.h"
#include "efuse.h"
#include "mac.h"
@@ -2168,6 +2169,159 @@ static void rtw8922d_set_channel_help(struct rtw89_dev *rtwdev, bool enter,
}
}
+static void rtw8922d_rfk_init(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_rfk_mcc_info *rfk_mcc = &rtwdev->rfk_mcc;
+ struct rtw89_lck_info *lck = &rtwdev->lck;
+
+ rtwdev->is_tssi_mode[RF_PATH_A] = false;
+ rtwdev->is_tssi_mode[RF_PATH_B] = false;
+ memset(rfk_mcc, 0, sizeof(*rfk_mcc));
+ memset(lck, 0, sizeof(*lck));
+}
+
+static void __rtw8922d_rfk_init_late(struct rtw89_dev *rtwdev,
+ enum rtw89_phy_idx phy_idx,
+ const struct rtw89_chan *chan)
+{
+ rtw8922d_rfk_mlo_ctrl(rtwdev);
+
+ rtw89_phy_rfk_pre_ntfy_and_wait(rtwdev, phy_idx, 5);
+ if (!test_bit(RTW89_FLAG_SER_HANDLING, rtwdev->flags))
+ rtw89_phy_rfk_rxdck_and_wait(rtwdev, phy_idx, chan, false, 128);
+ if (phy_idx == RTW89_PHY_0)
+ rtw89_phy_rfk_dack_and_wait(rtwdev, phy_idx, chan, 58);
+}
+
+static void rtw8922d_rfk_init_late(struct rtw89_dev *rtwdev)
+{
+ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_CHANCTX_0);
+
+ __rtw8922d_rfk_init_late(rtwdev, RTW89_PHY_0, chan);
+ if (rtwdev->dbcc_en)
+ __rtw8922d_rfk_init_late(rtwdev, RTW89_PHY_1, chan);
+}
+
+static void _wait_rx_mode(struct rtw89_dev *rtwdev, u8 kpath)
+{
+ u32 rf_mode;
+ u8 path;
+ int ret;
+
+ for (path = 0; path < RF_PATH_NUM_8922D; path++) {
+ if (!(kpath & BIT(path)))
+ continue;
+
+ ret = read_poll_timeout_atomic(rtw89_read_rf, rf_mode, rf_mode != 2,
+ 2, 5000, false, rtwdev, path, 0x00,
+ RR_MOD_MASK);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[RFK] Wait S%d to Rx mode!! (ret = %d)\n",
+ path, ret);
+ }
+}
+
+static void __rtw8922d_tssi_enable(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx)
+{
+ u8 path;
+
+ for (path = RF_PATH_A; path <= RF_PATH_B; path++) {
+ u32 addr_ofst = (phy_idx << 12) + (path << 8);
+
+ rtw89_phy_write32_mask(rtwdev, R_TSSI_DCK_MOV_AVG_LEN_P0_BE4 + addr_ofst,
+ B_TSSI_DCK_MOV_AVG_LEN_P0_BE4, 0x4);
+ rtw89_phy_write32_clr(rtwdev, R_USED_TSSI_TRK_ON_P0_BE4 + addr_ofst,
+ B_USED_TSSI_TRK_ON_P0_BE4);
+ rtw89_phy_write32_set(rtwdev, R_USED_TSSI_TRK_ON_P0_BE4 + addr_ofst,
+ B_USED_TSSI_TRK_ON_P0_BE4);
+ rtw89_phy_write32_clr(rtwdev, R_TSSI_EN_P0_BE4 + addr_ofst,
+ B_TSSI_EN_P0_BE4);
+ rtw89_phy_write32_mask(rtwdev, R_TSSI_EN_P0_BE4 + addr_ofst,
+ B_TSSI_EN_P0_BE4, 0x3);
+ }
+}
+
+static void __rtw8922d_tssi_disable(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx)
+{
+ u8 path;
+
+ for (path = RF_PATH_A; path <= RF_PATH_B; path++) {
+ u32 addr_ofst = (phy_idx << 12) + (path << 8);
+
+ rtw89_phy_write32_clr(rtwdev, R_TSSI_DCK_MOV_AVG_LEN_P0_BE4 + addr_ofst,
+ B_TSSI_DCK_MOV_AVG_LEN_P0_BE4);
+ rtw89_phy_write32_clr(rtwdev, R_USED_TSSI_TRK_ON_P0_BE4 + addr_ofst,
+ B_USED_TSSI_TRK_ON_P0_BE4);
+ rtw89_phy_write32_clr(rtwdev, R_TSSI_EN_P0_BE4 + addr_ofst,
+ B_TSSI_EN_P0_BE4);
+ }
+}
+
+static void rtw8922d_rfk_tssi(struct rtw89_dev *rtwdev,
+ enum rtw89_phy_idx phy_idx,
+ const struct rtw89_chan *chan,
+ enum rtw89_tssi_mode tssi_mode,
+ unsigned int ms)
+{
+ int ret;
+
+ ret = rtw89_phy_rfk_tssi_and_wait(rtwdev, phy_idx, chan, tssi_mode, ms);
+ if (ret) {
+ rtwdev->is_tssi_mode[RF_PATH_A] = false;
+ rtwdev->is_tssi_mode[RF_PATH_B] = false;
+ } else {
+ rtwdev->is_tssi_mode[RF_PATH_A] = true;
+ rtwdev->is_tssi_mode[RF_PATH_B] = true;
+ }
+}
+
+static void rtw8922d_rfk_channel(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link)
+{
+ enum rtw89_chanctx_idx chanctx_idx = rtwvif_link->chanctx_idx;
+ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, chanctx_idx);
+ enum rtw89_phy_idx phy_idx = rtwvif_link->phy_idx;
+ u8 phy_map = rtw89_btc_phymap(rtwdev, phy_idx, RF_AB, chanctx_idx);
+ u32 tx_en;
+
+ rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_CHLK, BTC_WRFK_START);
+ rtw89_chip_stop_sch_tx(rtwdev, phy_idx, &tx_en, RTW89_SCH_TX_SEL_ALL);
+ _wait_rx_mode(rtwdev, RF_AB);
+
+ rtw89_phy_rfk_pre_ntfy_and_wait(rtwdev, phy_idx, 5);
+ rtw89_phy_rfk_txgapk_and_wait(rtwdev, phy_idx, chan, 54);
+ rtw89_phy_rfk_txiqk_and_wait(rtwdev, phy_idx, chan, 45);
+ rtw89_phy_rfk_iqk_and_wait(rtwdev, phy_idx, chan, 84);
+ rtw8922d_rfk_tssi(rtwdev, phy_idx, chan, RTW89_TSSI_NORMAL, 20);
+ rtw89_phy_rfk_cim3k_and_wait(rtwdev, phy_idx, chan, 44);
+ rtw89_phy_rfk_dpk_and_wait(rtwdev, phy_idx, chan, 68);
+ rtw89_phy_rfk_rxdck_and_wait(rtwdev, RTW89_PHY_0, chan, true, 32);
+
+ rtw89_chip_resume_sch_tx(rtwdev, phy_idx, tx_en);
+ rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_CHLK, BTC_WRFK_STOP);
+}
+
+static void rtw8922d_rfk_band_changed(struct rtw89_dev *rtwdev,
+ enum rtw89_phy_idx phy_idx,
+ const struct rtw89_chan *chan)
+{
+}
+
+static void rtw8922d_rfk_scan(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
+ bool start)
+{
+ if (start)
+ __rtw8922d_tssi_disable(rtwdev, rtwvif_link->phy_idx);
+ else
+ __rtw8922d_tssi_enable(rtwdev, rtwvif_link->phy_idx);
+}
+
+static void rtw8922d_rfk_track(struct rtw89_dev *rtwdev)
+{
+ rtw8922d_lck_track(rtwdev);
+}
+
MODULE_FIRMWARE(RTW8922D_MODULE_FIRMWARE);
MODULE_FIRMWARE(RTW8922DS_MODULE_FIRMWARE);
MODULE_AUTHOR("Realtek Corporation");
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.c
index d1eda19a39a9..147cf91d2cb0 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.c
@@ -261,3 +261,88 @@ void rtw8922d_post_set_channel_rf(struct rtw89_dev *rtwdev, enum rtw89_phy_idx p
{
rtw8922d_rfk_mlo_ctrl(rtwdev);
}
+
+static u8 _get_thermal(struct rtw89_dev *rtwdev, enum rtw89_rf_path path)
+{
+ rtw89_write_rf(rtwdev, path, RR_TM, RR_TM_TRI, 0x1);
+ rtw89_write_rf(rtwdev, path, RR_TM, RR_TM_TRI, 0x0);
+ rtw89_write_rf(rtwdev, path, RR_TM, RR_TM_TRI, 0x1);
+
+ fsleep(200);
+
+ return rtw89_read_rf(rtwdev, path, RR_TM, RR_TM_VAL_V1);
+}
+
+static void _lck_keep_thermal(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_lck_info *lck = &rtwdev->lck;
+ int path;
+
+ for (path = 0; path < rtwdev->chip->rf_path_num; path++) {
+ lck->thermal[path] = _get_thermal(rtwdev, path);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK_TRACK,
+ "[LCK] path=%d thermal=0x%x", path, lck->thermal[path]);
+ }
+}
+
+static void _lck(struct rtw89_dev *rtwdev)
+{
+ enum _rf_syn_pow syn_pow = rtw8922d_get_syn_pow(rtwdev);
+ u8 path_mask = 0;
+ u32 tmp18, tmp5;
+ int path;
+
+ rtw89_debug(rtwdev, RTW89_DBG_RFK_TRACK, "[LCK] DO LCK\n");
+
+ if (syn_pow == RF_SYN_ALLON)
+ path_mask = BIT(RF_PATH_A) | BIT(RF_PATH_B);
+ else if (syn_pow == RF_SYN_ON_OFF)
+ path_mask = BIT(RF_PATH_A);
+ else if (syn_pow == RF_SYN_OFF_ON)
+ path_mask = BIT(RF_PATH_B);
+ else
+ return;
+
+ for (path = 0; path < rtwdev->chip->rf_path_num; path++) {
+ if (!(path_mask & BIT(path)))
+ continue;
+
+ tmp18 = rtw89_read_rf(rtwdev, path, RR_CFGCH, MASKDWORD);
+ tmp5 = rtw89_read_rf(rtwdev, path, RR_RSV1, MASKDWORD);
+
+ rtw89_write_rf(rtwdev, path, RR_MOD, MASKDWORD, 0x10000);
+ rtw89_write_rf(rtwdev, path, RR_RSV1, MASKDWORD, 0x0);
+ rtw89_write_rf(rtwdev, path, RR_LCK_TRG, RR_LCK_TRGSEL, 0x1);
+ rtw89_write_rf(rtwdev, path, RR_CFGCH, MASKDWORD, tmp18);
+ rtw89_write_rf(rtwdev, path, RR_LCK_TRG, RR_LCK_TRGSEL, 0x0);
+
+ fsleep(400);
+
+ rtw89_write_rf(rtwdev, path, RR_RSV1, MASKDWORD, tmp5);
+ }
+
+ _lck_keep_thermal(rtwdev);
+}
+
+#define RTW8922D_LCK_TH 16
+void rtw8922d_lck_track(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_lck_info *lck = &rtwdev->lck;
+ u8 cur_thermal;
+ int delta;
+ int path;
+
+ for (path = 0; path < rtwdev->chip->rf_path_num; path++) {
+ cur_thermal = _get_thermal(rtwdev, path);
+ delta = abs((int)cur_thermal - lck->thermal[path]);
+
+ rtw89_debug(rtwdev, RTW89_DBG_RFK_TRACK,
+ "[LCK] path=%d current thermal=0x%x delta=0x%x\n",
+ path, cur_thermal, delta);
+
+ if (delta >= RTW8922D_LCK_TH) {
+ _lck(rtwdev);
+ return;
+ }
+ }
+}
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.h b/drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.h
index 4c505ae24261..8a5f4b56b8ce 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.h
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.h
@@ -14,5 +14,6 @@ void rtw8922d_set_channel_rf(struct rtw89_dev *rtwdev,
void rtw8922d_rfk_mlo_ctrl(struct rtw89_dev *rtwdev);
void rtw8922d_pre_set_channel_rf(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx);
void rtw8922d_post_set_channel_rf(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx);
+void rtw8922d_lck_track(struct rtw89_dev *rtwdev);
#endif
--
2.25.1
^ permalink raw reply related
* [PATCH rtw-next 4/9] wifi: rtw89: 8922d: add set TX power callback
From: Ping-Ke Shih @ 2026-03-30 6:58 UTC (permalink / raw)
To: linux-wireless
In-Reply-To: <20260330065847.48946-1-pkshih@realtek.com>
Set TX power depends on operating channel. The Tx power factors are data
rate, channel, bandwidth and etc. Also, consider SAR as a factor of TX
power limit.
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/reg.h | 13 ++
drivers/net/wireless/realtek/rtw89/rtw8922d.c | 115 ++++++++++++++++++
2 files changed, 128 insertions(+)
diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h
index 1a5a5b30a28e..37de1c827814 100644
--- a/drivers/net/wireless/realtek/rtw89/reg.h
+++ b/drivers/net/wireless/realtek/rtw89/reg.h
@@ -10235,6 +10235,8 @@
#define B_TSSI_CONT_EN BIT(3)
#define R_P0_TXPWRB_BE 0xE61C
#define R_P1_TXPWRB_BE 0xE71C
+#define R_P0_TXPWRB_BE4 0x2251C
+#define R_P1_TXPWRB_BE4 0x2261C
#define B_TXPWRB_MAX_BE GENMASK(20, 12)
#define R_TSSI_MAP_OFST_P0 0xE620
#define R_TSSI_MAP_OFST_P1 0xE720
@@ -10531,13 +10533,24 @@
#define B_TXPWR_RSTB0_BE4 BIT(16)
#define R_TSSI_EN_P0_BE4 0x22510
#define B_TSSI_EN_P0_BE4 GENMASK(3, 0)
+#define R_TXAGC_REF_DBM_PATH0_TBL0_BE4 0x22528
+#define B_TXAGC_OFDM_REF_DBM_PATH0_TBL0_BE4 GENMASK(8, 0)
+#define B_TXAGC_CCK_REF_DBM_PATH0_TBL0_BE4 GENMASK(17, 9)
#define R_USED_TSSI_TRK_ON_P0_BE4 0x22534
#define B_USED_TSSI_TRK_ON_P0_BE4 BIT(22)
+#define R_TSSI_K_OFDM_PATH0_TBL0_BE4 0x225A0
+#define B_TSSI_K_OFDM_PATH0_TBL0_BE4 GENMASK(29, 20)
#define R_TSSI_DCK_MOV_AVG_LEN_P0_BE4 0x225CC
#define B_TSSI_DCK_MOV_AVG_LEN_P0_BE4 GENMASK(8, 6)
#define R_TXPWR_RSTB1_BE4 0x2260C
#define B_TXPWR_RSTB1_BE4 BIT(16)
+#define R_TXAGC_REF_DBM_PATH0_TBL1_BE4 0x23528
+#define B_TXAGC_OFDM_REF_DBM_PATH0_TBL1_BE4 GENMASK(8, 0)
+#define B_TXAGC_CCK_REF_DBM_PATH0_TBL1_BE4 GENMASK(17, 9)
+#define R_TSSI_K_OFDM_PATH0_TBL1_BE4 0x235A0
+#define B_TSSI_K_OFDM_PATH0_TBL1_BE4 GENMASK(29, 20)
+
#define R_OFDM_OFST_P0_BE4 0x240C8
#define B_OFDM_OFST_P0_BE4 GENMASK(31, 24)
#define R_PATH0_RXIDX_INIT_BE4 0x24108
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922d.c b/drivers/net/wireless/realtek/rtw89/rtw8922d.c
index 2e6f4504caeb..9c62a5f12962 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922d.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922d.c
@@ -11,6 +11,7 @@
#include "reg.h"
#include "rtw8922d.h"
#include "rtw8922d_rfk.h"
+#include "sar.h"
#include "util.h"
#define RTW8922D_FW_FORMAT_MAX 0
@@ -2322,6 +2323,120 @@ static void rtw8922d_rfk_track(struct rtw89_dev *rtwdev)
rtw8922d_lck_track(rtwdev);
}
+static const struct rtw89_reg_def rtw8922d_txpwr_ref[][3] = {
+ {{ .addr = R_TXAGC_REF_DBM_PATH0_TBL0_BE4,
+ .mask = B_TXAGC_OFDM_REF_DBM_PATH0_TBL0_BE4 },
+ { .addr = R_TXAGC_REF_DBM_PATH0_TBL0_BE4,
+ .mask = B_TXAGC_CCK_REF_DBM_PATH0_TBL0_BE4 },
+ { .addr = R_TSSI_K_OFDM_PATH0_TBL0_BE4,
+ .mask = B_TSSI_K_OFDM_PATH0_TBL0_BE4 }
+ },
+ {{ .addr = R_TXAGC_REF_DBM_PATH0_TBL1_BE4,
+ .mask = B_TXAGC_OFDM_REF_DBM_PATH0_TBL1_BE4 },
+ { .addr = R_TXAGC_REF_DBM_PATH0_TBL1_BE4,
+ .mask = B_TXAGC_CCK_REF_DBM_PATH0_TBL1_BE4 },
+ { .addr = R_TSSI_K_OFDM_PATH0_TBL1_BE4,
+ .mask = B_TSSI_K_OFDM_PATH0_TBL1_BE4 }
+ },
+};
+
+static void rtw8922d_set_txpwr_diff(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan,
+ enum rtw89_phy_idx phy_idx)
+{
+ s16 pwr_ofst = rtw89_phy_ant_gain_pwr_offset(rtwdev, chan);
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ static const u32 path_ofst[] = {0x0, 0x100};
+ const struct rtw89_reg_def *txpwr_ref;
+ s16 tssi_k_ofst = abs(pwr_ofst);
+ s16 ofst_dec[RF_PATH_NUM_8922D];
+ s16 tssi_k[RF_PATH_NUM_8922D];
+ s16 pwr_ref_ofst;
+ s16 pwr_ref = 16;
+ u8 i;
+
+ pwr_ref <<= chip->txpwr_factor_rf;
+ pwr_ref_ofst = pwr_ref - rtw89_phy_txpwr_bb_to_rf(rtwdev, abs(pwr_ofst));
+
+ ofst_dec[RF_PATH_A] = pwr_ofst > 0 ? pwr_ref : pwr_ref_ofst;
+ ofst_dec[RF_PATH_B] = pwr_ofst > 0 ? pwr_ref_ofst : pwr_ref;
+ tssi_k[RF_PATH_A] = pwr_ofst > 0 ? 0 : tssi_k_ofst;
+ tssi_k[RF_PATH_B] = pwr_ofst > 0 ? tssi_k_ofst : 0;
+
+ for (i = 0; i < RF_PATH_NUM_8922D; i++) {
+ txpwr_ref = rtw8922d_txpwr_ref[phy_idx];
+
+ rtw89_phy_write32_mask(rtwdev, txpwr_ref[0].addr + path_ofst[i],
+ txpwr_ref[0].mask, ofst_dec[i]);
+ rtw89_phy_write32_mask(rtwdev, txpwr_ref[1].addr + path_ofst[i],
+ txpwr_ref[1].mask, ofst_dec[i]);
+ rtw89_phy_write32_mask(rtwdev, txpwr_ref[2].addr + path_ofst[i],
+ txpwr_ref[2].mask, tssi_k[i]);
+ }
+}
+
+static void rtw8922d_set_txpwr_ref(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan,
+ enum rtw89_phy_idx phy_idx)
+{
+ s16 ref_ofdm = 0;
+ s16 ref_cck = 0;
+
+ rtw89_debug(rtwdev, RTW89_DBG_TXPWR, "[TXPWR] set txpwr reference\n");
+
+ rtw8922d_set_txpwr_diff(rtwdev, chan, phy_idx);
+
+ rtw89_mac_txpwr_write32_mask(rtwdev, phy_idx, R_BE_PWR_REF_CTRL,
+ B_BE_PWR_REF_CTRL_OFDM, ref_ofdm);
+ rtw89_mac_txpwr_write32_mask(rtwdev, phy_idx, R_BE_PWR_REF_CTRL,
+ B_BE_PWR_REF_CTRL_CCK, ref_cck);
+}
+
+static void rtw8922d_set_txpwr_sar_diff(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan,
+ enum rtw89_phy_idx phy_idx)
+{
+ struct rtw89_sar_parm sar_parm = {
+ .center_freq = chan->freq,
+ .force_path = true,
+ };
+ s16 sar_rf;
+ s8 sar_mac;
+
+ if (phy_idx != RTW89_PHY_0)
+ return;
+
+ sar_parm.path = RF_PATH_A;
+ sar_mac = rtw89_query_sar(rtwdev, &sar_parm);
+ sar_rf = rtw89_phy_txpwr_mac_to_rf(rtwdev, sar_mac);
+ rtw89_phy_write32_mask(rtwdev, R_P0_TXPWRB_BE4, B_TXPWRB_MAX_BE, sar_rf);
+
+ sar_parm.path = RF_PATH_B;
+ sar_mac = rtw89_query_sar(rtwdev, &sar_parm);
+ sar_rf = rtw89_phy_txpwr_mac_to_rf(rtwdev, sar_mac);
+ rtw89_phy_write32_mask(rtwdev, R_P1_TXPWRB_BE4, B_TXPWRB_MAX_BE, sar_rf);
+}
+
+static void rtw8922d_set_txpwr(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan,
+ enum rtw89_phy_idx phy_idx)
+{
+ rtw89_phy_set_txpwr_byrate(rtwdev, chan, phy_idx);
+ rtw89_phy_set_txpwr_offset(rtwdev, chan, phy_idx);
+ rtw89_phy_set_txpwr_limit(rtwdev, chan, phy_idx);
+ rtw89_phy_set_txpwr_limit_ru(rtwdev, chan, phy_idx);
+ rtw8922d_set_txpwr_ref(rtwdev, chan, phy_idx);
+ rtw8922d_set_txpwr_sar_diff(rtwdev, chan, phy_idx);
+}
+
+static void rtw8922d_set_txpwr_ctrl(struct rtw89_dev *rtwdev,
+ enum rtw89_phy_idx phy_idx)
+{
+ const struct rtw89_chan *chan = rtw89_mgnt_chan_get(rtwdev, phy_idx);
+
+ rtw8922d_set_txpwr_ref(rtwdev, chan, phy_idx);
+}
+
MODULE_FIRMWARE(RTW8922D_MODULE_FIRMWARE);
MODULE_FIRMWARE(RTW8922DS_MODULE_FIRMWARE);
MODULE_AUTHOR("Realtek Corporation");
--
2.25.1
^ permalink raw reply related
* [PATCH rtw-next 5/9] wifi: rtw89: 8922d: configure TX/RX path assisting in BT coexistence
From: Ping-Ke Shih @ 2026-03-30 6:58 UTC (permalink / raw)
To: linux-wireless
In-Reply-To: <20260330065847.48946-1-pkshih@realtek.com>
The BT coexistence mechanism needs to control TX/RX path to co-work with
BT well, and these helpers are provided by BB to configure path.
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/reg.h | 9 +-
drivers/net/wireless/realtek/rtw89/rtw8922d.c | 125 ++++++++++++++++++
2 files changed, 132 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h
index 37de1c827814..78f2cf579fa6 100644
--- a/drivers/net/wireless/realtek/rtw89/reg.h
+++ b/drivers/net/wireless/realtek/rtw89/reg.h
@@ -10469,8 +10469,9 @@
#define B_EMLSR_BB_CLK_BE4 GENMASK(31, 30)
#define R_CHINFO_SEG_BE4 0x200B4
#define B_CHINFO_SEG_LEN_BE4 GENMASK(12, 10)
-#define R_STS_HDR2_PARSING_BE4 0x2070C
-#define B_STS_HDR2_PARSING_BE4 BIT(10)
+#define R_SEL_GNT_BT_RX_BE4 0x2010C
+#define B_SEL_GNT_BT_RX_PATH0_BE4 GENMASK(3, 0)
+#define B_SEL_GNT_BT_RX_PATH1_BE4 GENMASK(11, 8)
#define R_SW_SI_WDATA_BE4 0x20370
#define B_SW_SI_DATA_PATH_BE4 GENMASK(31, 28)
#define B_SW_SI_DATA_ADR_BE4 GENMASK(27, 20)
@@ -10490,9 +10491,13 @@
#define B_ENABLE_CCK0_BE4 BIT(5)
#define R_RSTB_ASYNC_BE4 0x20704
#define B_RSTB_ASYNC_BE4 BIT(1)
+#define R_STS_HDR2_PARSING_BE4 0x2070C
+#define B_STS_HDR2_PARSING_BE4 BIT(10)
#define R_EDCCA_RPT_SEL_BE4 0x20780
#define R_EDCCA_RPT_SEL_BE4_C1 0x21780
#define B_EDCCA_RPT_SEL_BE4_MSK 0xE0000
+#define R_SEL_GNT_BT_RXPHY_BE4 0x2079C
+#define B_SEL_GNT_BT_RXPHY_BE4 GENMASK(11, 8)
#define R_IMR_TX_ERROR_BE4 0x20920
#define B_IMR_TX_ERROR_BE4 BIT(30)
#define R_TXINFO_PATH_BE4 0x209A4
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922d.c b/drivers/net/wireless/realtek/rtw89/rtw8922d.c
index 9c62a5f12962..cfe9752abddc 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922d.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922d.c
@@ -238,6 +238,35 @@ static const struct rtw89_efuse_block_cfg rtw8922d_efuse_blocks[] = {
[RTW89_EFUSE_BLOCK_ADIE] = {.offset = 0x70000, .size = 0x10},
};
+static void rtw8922d_sel_bt_rx_path(struct rtw89_dev *rtwdev, u8 val,
+ enum rtw89_rf_path rx_path)
+{
+ if (rx_path == RF_PATH_A)
+ rtw89_phy_write32_mask(rtwdev, R_SEL_GNT_BT_RX_BE4,
+ B_SEL_GNT_BT_RX_PATH0_BE4, val);
+ else if (rx_path == RF_PATH_B)
+ rtw89_phy_write32_mask(rtwdev, R_SEL_GNT_BT_RX_BE4,
+ B_SEL_GNT_BT_RX_PATH1_BE4, val);
+ else
+ rtw89_warn(rtwdev, "[%s] Not support path = %d\n", __func__, rx_path);
+}
+
+static void rtw8922d_sel_bt_rx_phy(struct rtw89_dev *rtwdev, u8 val,
+ enum rtw89_phy_idx phy_idx)
+{
+ rtw89_phy_write32_idx(rtwdev, R_SEL_GNT_BT_RXPHY_BE4,
+ B_SEL_GNT_BT_RXPHY_BE4, val, phy_idx);
+}
+
+static void rtw8922d_set_gbt_bt_rx_sel(struct rtw89_dev *rtwdev, bool en,
+ enum rtw89_phy_idx phy_idx)
+{
+ rtw8922d_sel_bt_rx_path(rtwdev, 0x3, RF_PATH_A);
+ rtw8922d_sel_bt_rx_phy(rtwdev, 0x0, RTW89_PHY_0);
+ rtw8922d_sel_bt_rx_path(rtwdev, 0x3, RF_PATH_B);
+ rtw8922d_sel_bt_rx_phy(rtwdev, 0x0, RTW89_PHY_1);
+}
+
static int rtw8922d_pwr_on_func(struct rtw89_dev *rtwdev)
{
struct rtw89_hal *hal = &rtwdev->hal;
@@ -2437,6 +2466,102 @@ static void rtw8922d_set_txpwr_ctrl(struct rtw89_dev *rtwdev,
rtw8922d_set_txpwr_ref(rtwdev, chan, phy_idx);
}
+static void rtw8922d_ctrl_trx_path(struct rtw89_dev *rtwdev,
+ enum rtw89_rf_path tx_path, u8 tx_nss,
+ enum rtw89_rf_path rx_path, u8 rx_nss)
+{
+ enum rtw89_phy_idx phy_idx;
+
+ for (phy_idx = RTW89_PHY_0; phy_idx <= RTW89_PHY_1; phy_idx++) {
+ rtw8922d_ctrl_tx_path_tmac(rtwdev, tx_path, phy_idx);
+ rtw8922d_ctrl_rx_path_tmac(rtwdev, rx_path, phy_idx);
+
+ rtw8922d_tssi_reset(rtwdev, rx_path, phy_idx);
+ }
+}
+
+static void rtw8922d_ctrl_nbtg_bt_tx(struct rtw89_dev *rtwdev, bool en,
+ enum rtw89_phy_idx phy_idx)
+{
+ if (en) {
+ rtw89_phy_write32_idx(rtwdev, R_FORCE_FIR_A, B_FORCE_FIR_A, 0x3, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXBY_WBADC_A, B_RXBY_WBADC_A,
+ 0xf, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BT_RXBY_WBADC_A, B_BT_RXBY_WBADC_A,
+ 0x0, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BT_SHARE_A, B_BT_TRK_OFF_A, 0x0, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_OP1DB_A, B_OP1DB_A, 0x80, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_OP1DB1_A, B_TIA10_A, 0x8080, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BACKOFF_A, B_LNA_IBADC_A, 0x34, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BKOFF_A, B_BKOFF_IBADC_A, 0x34, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_FORCE_FIR_B, B_FORCE_FIR_B, 0x3, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXBY_WBADC_B, B_RXBY_WBADC_B,
+ 0xf, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BT_RXBY_WBADC_B, B_BT_RXBY_WBADC_B,
+ 0x0, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BT_SHARE_B, B_BT_TRK_OFF_B, 0x0, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_LNA_TIA, B_TIA1_B, 0x80, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BACKOFF_B, B_LNA_IBADC_B, 0x34, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BKOFF_B, B_BKOFF_IBADC_B, 0x34, phy_idx);
+ } else {
+ rtw89_phy_write32_idx(rtwdev, R_FORCE_FIR_A, B_FORCE_FIR_A, 0x0, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXBY_WBADC_A, B_RXBY_WBADC_A,
+ 0x0, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BT_RXBY_WBADC_A, B_BT_RXBY_WBADC_A,
+ 0x1, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BT_SHARE_A, B_BT_TRK_OFF_A, 0x1, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_OP1DB_A, B_OP1DB_A, 0x1a, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_OP1DB1_A, B_TIA10_A, 0x2a2a, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BACKOFF_A, B_LNA_IBADC_A, 0x7a6, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BKOFF_A, B_BKOFF_IBADC_A, 0x26, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_FORCE_FIR_B, B_FORCE_FIR_B, 0x0, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXBY_WBADC_B, B_RXBY_WBADC_B,
+ 0x0, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BT_RXBY_WBADC_B, B_BT_RXBY_WBADC_B,
+ 0x1, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BT_SHARE_B, B_BT_TRK_OFF_B, 0x1, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_LNA_TIA, B_TIA1_B, 0x2a, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BACKOFF_B, B_LNA_IBADC_B, 0x7a6, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BKOFF_B, B_BKOFF_IBADC_B, 0x26, phy_idx);
+ }
+}
+
+static void rtw8922d_bb_cfg_txrx_path(struct rtw89_dev *rtwdev)
+{
+ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_CHANCTX_0);
+ enum rtw89_band band = chan->band_type;
+ struct rtw89_hal *hal = &rtwdev->hal;
+ u8 ntx_path = RF_PATH_AB;
+ u8 nrx_path = RF_PATH_AB;
+ u32 tx_en0, tx_en1;
+ u8 rx_nss = 2;
+
+ if (hal->antenna_tx == RF_A)
+ ntx_path = RF_PATH_A;
+ else if (hal->antenna_tx == RF_B)
+ ntx_path = RF_PATH_B;
+
+ if (hal->antenna_rx == RF_A)
+ nrx_path = RF_PATH_A;
+ else if (hal->antenna_rx == RF_B)
+ nrx_path = RF_PATH_B;
+
+ if (nrx_path != RF_PATH_AB)
+ rx_nss = 1;
+
+ rtw8922d_hal_reset(rtwdev, RTW89_PHY_0, RTW89_MAC_0, band, &tx_en0, true);
+ if (rtwdev->dbcc_en)
+ rtw8922d_hal_reset(rtwdev, RTW89_PHY_1, RTW89_MAC_1, band,
+ &tx_en1, true);
+
+ rtw8922d_ctrl_trx_path(rtwdev, ntx_path, 2, nrx_path, rx_nss);
+
+ rtw8922d_hal_reset(rtwdev, RTW89_PHY_0, RTW89_MAC_0, band, &tx_en0, false);
+ if (rtwdev->dbcc_en)
+ rtw8922d_hal_reset(rtwdev, RTW89_PHY_1, RTW89_MAC_1, band,
+ &tx_en1, false);
+}
+
MODULE_FIRMWARE(RTW8922D_MODULE_FIRMWARE);
MODULE_FIRMWARE(RTW8922DS_MODULE_FIRMWARE);
MODULE_AUTHOR("Realtek Corporation");
--
2.25.1
^ permalink raw reply related
* [PATCH rtw-next 6/9] wifi: rtw89: 8922d: add RF ops of init hardware and get thermal
From: Ping-Ke Shih @ 2026-03-30 6:58 UTC (permalink / raw)
To: linux-wireless
In-Reply-To: <20260330065847.48946-1-pkshih@realtek.com>
One is to initialize hardware for RF circuit, and the ops of get thermal
is used to monitor temperature to re-calibrate RF or reduce TX duty to
prevent overheating.
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/reg.h | 6 ++
drivers/net/wireless/realtek/rtw89/rtw8922d.c | 57 +++++++++++++++++++
.../net/wireless/realtek/rtw89/rtw8922d_rfk.c | 24 ++++++++
.../net/wireless/realtek/rtw89/rtw8922d_rfk.h | 3 +
4 files changed, 90 insertions(+)
diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h
index 78f2cf579fa6..e5e689f1bfa3 100644
--- a/drivers/net/wireless/realtek/rtw89/reg.h
+++ b/drivers/net/wireless/realtek/rtw89/reg.h
@@ -10676,6 +10676,12 @@
#define B_KTBL1_TBL0 BIT(3)
#define B_KTBL1_TBL1 BIT(5)
+#define R_TC_EN_BE4 0x3c200
+#define B_TC_EN_BE4 BIT(0)
+#define B_TC_TRIG_BE4 BIT(1)
+#define R_TC_VAL_BE4 0x3c208
+#define B_TC_VAL_BE4 GENMASK(7, 0)
+
/* WiFi CPU local domain */
#define R_AX_WDT_CTRL 0x0040
#define B_AX_WDT_EN BIT(31)
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922d.c b/drivers/net/wireless/realtek/rtw89/rtw8922d.c
index cfe9752abddc..49b84d49ccac 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922d.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922d.c
@@ -2562,6 +2562,63 @@ static void rtw8922d_bb_cfg_txrx_path(struct rtw89_dev *rtwdev)
&tx_en1, false);
}
+static u8 rtw8922d_get_thermal(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path)
+{
+ u8 val;
+
+ rtw89_phy_write32_mask(rtwdev, R_TC_EN_BE4, B_TC_EN_BE4, 0x1);
+ rtw89_phy_write32_mask(rtwdev, R_TC_EN_BE4, B_TC_TRIG_BE4, 0x0);
+ rtw89_phy_write32_mask(rtwdev, R_TC_EN_BE4, B_TC_TRIG_BE4, 0x1);
+
+ fsleep(100);
+
+ val = rtw89_phy_read32_mask(rtwdev, R_TC_VAL_BE4, B_TC_VAL_BE4);
+
+ return val;
+}
+
+static u32 rtw8922d_chan_to_rf18_val(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan)
+{
+ u32 val = u32_encode_bits(chan->channel, RR_CFGCH_CH);
+
+ switch (chan->band_type) {
+ case RTW89_BAND_2G:
+ default:
+ break;
+ case RTW89_BAND_5G:
+ val |= u32_encode_bits(CFGCH_BAND1_5G, RR_CFGCH_BAND1) |
+ u32_encode_bits(CFGCH_BAND0_5G, RR_CFGCH_BAND0);
+ break;
+ case RTW89_BAND_6G:
+ val |= u32_encode_bits(CFGCH_BAND1_6G, RR_CFGCH_BAND1) |
+ u32_encode_bits(CFGCH_BAND0_6G, RR_CFGCH_BAND0);
+ break;
+ }
+
+ switch (chan->band_width) {
+ case RTW89_CHANNEL_WIDTH_5:
+ case RTW89_CHANNEL_WIDTH_10:
+ case RTW89_CHANNEL_WIDTH_20:
+ default:
+ break;
+ case RTW89_CHANNEL_WIDTH_40:
+ val |= u32_encode_bits(CFGCH_BW_V2_40M, RR_CFGCH_BW_V2);
+ break;
+ case RTW89_CHANNEL_WIDTH_80:
+ val |= u32_encode_bits(CFGCH_BW_V2_80M, RR_CFGCH_BW_V2);
+ break;
+ case RTW89_CHANNEL_WIDTH_160:
+ val |= u32_encode_bits(CFGCH_BW_V2_160M, RR_CFGCH_BW_V2);
+ break;
+ case RTW89_CHANNEL_WIDTH_320:
+ val |= u32_encode_bits(CFGCH_BW_V2_320M, RR_CFGCH_BW_V2);
+ break;
+ }
+
+ return val;
+}
+
MODULE_FIRMWARE(RTW8922D_MODULE_FIRMWARE);
MODULE_FIRMWARE(RTW8922DS_MODULE_FIRMWARE);
MODULE_AUTHOR("Realtek Corporation");
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.c
index 147cf91d2cb0..4e6a8e88a71e 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.c
@@ -9,6 +9,12 @@
#include "rtw8922d.h"
#include "rtw8922d_rfk.h"
+static const struct rtw89_reg5_def rtw8922d_nctl_post_defs[] = {
+ RTW89_DECL_RFK_WM(0x20c7c, 0x00e00000, 0x1),
+};
+
+RTW89_DECLARE_RFK_TBL(rtw8922d_nctl_post_defs);
+
static void rtw8922d_tssi_cont_en(struct rtw89_dev *rtwdev, bool en,
enum rtw89_rf_path path, u8 phy_idx)
{
@@ -239,6 +245,24 @@ void rtw8922d_rfk_mlo_ctrl(struct rtw89_dev *rtwdev)
rtw8922d_chlk_reload(rtwdev);
}
+static void rtw8922d_x4k_setting(struct rtw89_dev *rtwdev)
+{
+ u32 val;
+
+ val = rtw89_read_rf(rtwdev, RF_PATH_A, 0xB9, 0xF000);
+ rtw89_write_rf(rtwdev, RF_PATH_A, 0xB9, 0xF000, val);
+ val = rtw89_read_rf(rtwdev, RF_PATH_B, 0xB9, 0xF000);
+ rtw89_write_rf(rtwdev, RF_PATH_B, 0xB9, 0xF000, val);
+
+ rtw89_write_rf(rtwdev, RF_PATH_A, 0xC2, BIT(19), 0x1);
+ rtw89_write_rf(rtwdev, RF_PATH_B, 0xC2, BIT(19), 0x1);
+}
+
+void rtw8922d_rfk_hw_init(struct rtw89_dev *rtwdev)
+{
+ rtw8922d_x4k_setting(rtwdev);
+}
+
void rtw8922d_pre_set_channel_rf(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx)
{
bool mlo_1_1;
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.h b/drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.h
index 8a5f4b56b8ce..c5bbe0eb972a 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.h
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.h
@@ -7,10 +7,13 @@
#include "core.h"
+extern const struct rtw89_rfk_tbl rtw8922d_nctl_post_defs_tbl;
+
void rtw8922d_tssi_cont_en_phyidx(struct rtw89_dev *rtwdev, bool en, u8 phy_idx);
void rtw8922d_set_channel_rf(struct rtw89_dev *rtwdev,
const struct rtw89_chan *chan,
enum rtw89_phy_idx phy_idx);
+void rtw8922d_rfk_hw_init(struct rtw89_dev *rtwdev);
void rtw8922d_rfk_mlo_ctrl(struct rtw89_dev *rtwdev);
void rtw8922d_pre_set_channel_rf(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx);
void rtw8922d_post_set_channel_rf(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx);
--
2.25.1
^ permalink raw reply related
* [PATCH rtw-next 7/9] wifi: rtw89: 8922d: add ops related to BT coexistence mechanism
From: Ping-Ke Shih @ 2026-03-30 6:58 UTC (permalink / raw)
To: linux-wireless
In-Reply-To: <20260330065847.48946-1-pkshih@realtek.com>
The ops is used by shared BT coexistence mechanism to set WiFi TX power,
get BT RSSI, and TX/RX parameters.
The RTL8922D uses TX/RX parameter v9, so define it and fill NULL for
other chips.
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/core.h | 21 +++
drivers/net/wireless/realtek/rtw89/rtw8851b.c | 4 +
drivers/net/wireless/realtek/rtw89/rtw8852a.c | 4 +
drivers/net/wireless/realtek/rtw89/rtw8852b.c | 4 +
.../net/wireless/realtek/rtw89/rtw8852bt.c | 4 +
drivers/net/wireless/realtek/rtw89/rtw8852c.c | 4 +
drivers/net/wireless/realtek/rtw89/rtw8922a.c | 4 +
drivers/net/wireless/realtek/rtw89/rtw8922d.c | 123 ++++++++++++++++++
8 files changed, 168 insertions(+)
diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index 696a1d92d62b..5c5bd7d02a62 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -873,6 +873,14 @@ enum rtw89_phy_idx {
RTW89_PHY_NUM,
};
+enum rtw89_fbtc_bt_index {
+ BTC_BT_1ST = 0x0,
+ BTC_BT_2ND = 0x1,
+ BTC_BT_EXT = 0x2,
+ BTC_ALL_BT = 0x2,
+ BTC_ALL_BT_EZL = 0x3 /* BT0+BT1+Ext-ZB(or Thread, or LTE) */
+};
+
#define __RTW89_MLD_MAX_LINK_NUM 2
#define RTW89_MLD_NON_STA_LINK_NUM 1
@@ -2197,6 +2205,15 @@ struct rtw89_btc_bt_info {
u32 rsvd: 17;
};
+struct rtw89_btc_rf_trx_para_v9 {
+ u32 wl_tx_power[RTW89_PHY_NUM]; /* absolute Tx power (dBm), 1's complement -5->0x85 */
+ u32 wl_rx_gain[RTW89_PHY_NUM]; /* rx gain table index (TBD.) */
+ u32 bt_tx_power[BTC_ALL_BT]; /* decrease Tx power (dB) */
+ u32 bt_rx_gain[BTC_ALL_BT]; /* LNA constrain level */
+ u32 zb_tx_power[BTC_ALL_BT]; /* 15.4 devrease Tx power (dB) */
+ u32 zb_rx_gain[BTC_ALL_BT]; /* 15.4 constrain level */
+};
+
struct rtw89_btc_cx {
struct rtw89_btc_wl_info wl;
struct rtw89_btc_bt_info bt;
@@ -4609,6 +4626,10 @@ struct rtw89_chip_info {
const struct rtw89_btc_rf_trx_para *rf_para_ulink;
u8 rf_para_dlink_num;
const struct rtw89_btc_rf_trx_para *rf_para_dlink;
+ const struct rtw89_btc_rf_trx_para_v9 *rf_para_ulink_v9;
+ const struct rtw89_btc_rf_trx_para_v9 *rf_para_dlink_v9;
+ u8 rf_para_ulink_num_v9;
+ u8 rf_para_dlink_num_v9;
u8 ps_mode_supported;
u8 low_power_hci_modes;
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c
index a3a5b6fbe46c..f9eda3f16d32 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c
@@ -2681,6 +2681,10 @@ const struct rtw89_chip_info rtw8851b_chip_info = {
.rf_para_ulink = rtw89_btc_8851b_rf_ul,
.rf_para_dlink_num = ARRAY_SIZE(rtw89_btc_8851b_rf_dl),
.rf_para_dlink = rtw89_btc_8851b_rf_dl,
+ .rf_para_ulink_v9 = NULL,
+ .rf_para_dlink_v9 = NULL,
+ .rf_para_ulink_num_v9 = 0,
+ .rf_para_dlink_num_v9 = 0,
.ps_mode_supported = BIT(RTW89_PS_MODE_RFOFF) |
BIT(RTW89_PS_MODE_CLK_GATED),
.low_power_hci_modes = 0,
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c
index 898c534a5762..c894c31156e4 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c
@@ -2418,6 +2418,10 @@ const struct rtw89_chip_info rtw8852a_chip_info = {
.rf_para_ulink = rtw89_btc_8852a_rf_ul,
.rf_para_dlink_num = ARRAY_SIZE(rtw89_btc_8852a_rf_dl),
.rf_para_dlink = rtw89_btc_8852a_rf_dl,
+ .rf_para_ulink_v9 = NULL,
+ .rf_para_dlink_v9 = NULL,
+ .rf_para_ulink_num_v9 = 0,
+ .rf_para_dlink_num_v9 = 0,
.ps_mode_supported = BIT(RTW89_PS_MODE_RFOFF) |
BIT(RTW89_PS_MODE_CLK_GATED) |
BIT(RTW89_PS_MODE_PWR_GATED),
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c
index 19a9f07e8714..f2e839122194 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c
@@ -1014,6 +1014,10 @@ const struct rtw89_chip_info rtw8852b_chip_info = {
.rf_para_ulink = rtw89_btc_8852b_rf_ul,
.rf_para_dlink_num = ARRAY_SIZE(rtw89_btc_8852b_rf_dl),
.rf_para_dlink = rtw89_btc_8852b_rf_dl,
+ .rf_para_ulink_v9 = NULL,
+ .rf_para_dlink_v9 = NULL,
+ .rf_para_ulink_num_v9 = 0,
+ .rf_para_dlink_num_v9 = 0,
.ps_mode_supported = BIT(RTW89_PS_MODE_RFOFF) |
BIT(RTW89_PS_MODE_CLK_GATED) |
BIT(RTW89_PS_MODE_PWR_GATED),
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c
index c86b995a7cb1..b1eb6fb1ece8 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c
@@ -853,6 +853,10 @@ const struct rtw89_chip_info rtw8852bt_chip_info = {
.rf_para_ulink = rtw89_btc_8852bt_rf_ul,
.rf_para_dlink_num = ARRAY_SIZE(rtw89_btc_8852bt_rf_dl),
.rf_para_dlink = rtw89_btc_8852bt_rf_dl,
+ .rf_para_ulink_v9 = NULL,
+ .rf_para_dlink_v9 = NULL,
+ .rf_para_ulink_num_v9 = 0,
+ .rf_para_dlink_num_v9 = 0,
.ps_mode_supported = BIT(RTW89_PS_MODE_RFOFF) |
BIT(RTW89_PS_MODE_CLK_GATED) |
BIT(RTW89_PS_MODE_PWR_GATED),
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
index 7ea0a8905282..0f2902af1c72 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
@@ -3211,6 +3211,10 @@ const struct rtw89_chip_info rtw8852c_chip_info = {
.rf_para_ulink = rtw89_btc_8852c_rf_ul,
.rf_para_dlink_num = ARRAY_SIZE(rtw89_btc_8852c_rf_dl),
.rf_para_dlink = rtw89_btc_8852c_rf_dl,
+ .rf_para_ulink_v9 = NULL,
+ .rf_para_dlink_v9 = NULL,
+ .rf_para_ulink_num_v9 = 0,
+ .rf_para_dlink_num_v9 = 0,
.ps_mode_supported = BIT(RTW89_PS_MODE_RFOFF) |
BIT(RTW89_PS_MODE_CLK_GATED) |
BIT(RTW89_PS_MODE_PWR_GATED),
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c
index a489aaf90f23..e8731d2f1703 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c
@@ -3015,6 +3015,10 @@ const struct rtw89_chip_info rtw8922a_chip_info = {
.rf_para_ulink = rtw89_btc_8922a_rf_ul,
.rf_para_dlink_num = ARRAY_SIZE(rtw89_btc_8922a_rf_dl),
.rf_para_dlink = rtw89_btc_8922a_rf_dl,
+ .rf_para_ulink_v9 = NULL,
+ .rf_para_dlink_v9 = NULL,
+ .rf_para_ulink_num_v9 = 0,
+ .rf_para_dlink_num_v9 = 0,
.ps_mode_supported = BIT(RTW89_PS_MODE_RFOFF) |
BIT(RTW89_PS_MODE_CLK_GATED) |
BIT(RTW89_PS_MODE_PWR_GATED),
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922d.c b/drivers/net/wireless/realtek/rtw89/rtw8922d.c
index 49b84d49ccac..a9a7ffb5fb58 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922d.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922d.c
@@ -2619,6 +2619,129 @@ static u32 rtw8922d_chan_to_rf18_val(struct rtw89_dev *rtwdev,
return val;
}
+static void rtw8922d_btc_set_rfe(struct rtw89_dev *rtwdev)
+{
+}
+
+static void rtw8922d_btc_init_cfg(struct rtw89_dev *rtwdev)
+{
+ /* offload to firmware */
+}
+
+static void
+rtw8922d_btc_set_wl_txpwr_ctrl(struct rtw89_dev *rtwdev, u32 txpwr_val)
+{
+ u16 ctrl_all_time = u32_get_bits(txpwr_val, GENMASK(15, 0));
+ u16 ctrl_gnt_bt = u32_get_bits(txpwr_val, GENMASK(31, 16));
+
+ switch (ctrl_all_time) {
+ case 0xffff:
+ rtw89_mac_txpwr_write32_mask(rtwdev, RTW89_PHY_0, R_BE_PWR_RATE_CTRL,
+ B_BE_FORCE_PWR_BY_RATE_EN, 0x0);
+ rtw89_mac_txpwr_write32_mask(rtwdev, RTW89_PHY_0, R_BE_PWR_RATE_CTRL,
+ B_BE_FORCE_PWR_BY_RATE_VAL, 0x0);
+ break;
+ default:
+ rtw89_mac_txpwr_write32_mask(rtwdev, RTW89_PHY_0, R_BE_PWR_RATE_CTRL,
+ B_BE_FORCE_PWR_BY_RATE_VAL, ctrl_all_time);
+ rtw89_mac_txpwr_write32_mask(rtwdev, RTW89_PHY_0, R_BE_PWR_RATE_CTRL,
+ B_BE_FORCE_PWR_BY_RATE_EN, 0x1);
+ break;
+ }
+
+ switch (ctrl_gnt_bt) {
+ case 0xffff:
+ rtw89_mac_txpwr_write32_mask(rtwdev, RTW89_PHY_0, R_BE_PWR_REG_CTRL,
+ B_BE_PWR_BT_EN, 0x0);
+ rtw89_mac_txpwr_write32_mask(rtwdev, RTW89_PHY_0, R_BE_PWR_COEX_CTRL,
+ B_BE_PWR_BT_VAL, 0x0);
+ break;
+ default:
+ rtw89_mac_txpwr_write32_mask(rtwdev, RTW89_PHY_0, R_BE_PWR_COEX_CTRL,
+ B_BE_PWR_BT_VAL, ctrl_gnt_bt);
+ rtw89_mac_txpwr_write32_mask(rtwdev, RTW89_PHY_0, R_BE_PWR_REG_CTRL,
+ B_BE_PWR_BT_EN, 0x1);
+ break;
+ }
+}
+
+static
+s8 rtw8922d_btc_get_bt_rssi(struct rtw89_dev *rtwdev, s8 val)
+{
+ return clamp_t(s8, val, -100, 0) + 100;
+}
+
+static const struct rtw89_btc_rf_trx_para_v9 rtw89_btc_8922d_rf_ul_v9[] = {
+ /*
+ * 0 -> original
+ * 1 -> for BT-connected ACI issue && BTG co-rx
+ * 2 ~ 4 ->reserved for shared-antenna
+ * 5 ~ 8 ->for non-shared-antenna free-run
+ */
+ {{15, 15}, {0, 0}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+ {{15, 15}, {2, 2}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+ {{15, 15}, {0, 0}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+ {{15, 15}, {0, 0}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+ {{15, 15}, {0, 0}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+ {{15, 15}, {1, 1}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+ {{ 6, 6}, {1, 1}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+ {{13, 13}, {1, 1}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+ {{13, 13}, {1, 1}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+};
+
+static const struct rtw89_btc_rf_trx_para_v9 rtw89_btc_8922d_rf_dl_v9[] = {
+ /*
+ * 0 -> original
+ * 1 -> for BT-connected ACI issue && BTG co-rx
+ * 2 ~ 4 ->reserved for shared-antenna
+ * 5 ~ 8 ->for non-shared-antenna free-run
+ */
+ {{15, 15}, {0, 0}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+ {{15, 15}, {2, 2}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+ {{15, 15}, {0, 0}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+ {{15, 15}, {0, 0}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+ {{15, 15}, {0, 0}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+ {{15, 15}, {1, 1}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+ {{15, 15}, {1, 1}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+ {{15, 15}, {1, 1}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+ {{15, 15}, {1, 1}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+};
+
+static const u8 rtw89_btc_8922d_wl_rssi_thres[BTC_WL_RSSI_THMAX] = {60, 50, 40, 30};
+static const u8 rtw89_btc_8922d_bt_rssi_thres[BTC_BT_RSSI_THMAX] = {50, 40, 30, 20};
+
+static const struct rtw89_btc_fbtc_mreg rtw89_btc_8922d_mon_reg[] = {
+ RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xe300),
+ RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xe330),
+ RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xe334),
+ RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xe338),
+ RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xe344),
+ RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xe348),
+ RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xe34c),
+ RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xe350),
+ RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xe354),
+ RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xe35c),
+ RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xe370),
+ RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xe380),
+};
+
+static
+void rtw8922d_btc_update_bt_cnt(struct rtw89_dev *rtwdev)
+{
+ /* Feature move to firmware */
+}
+
+static
+void rtw8922d_btc_wl_s1_standby(struct rtw89_dev *rtwdev, bool state)
+{
+ /* Feature move to firmware */
+}
+
+static void rtw8922d_btc_set_wl_rx_gain(struct rtw89_dev *rtwdev, u32 level)
+{
+ /* Feature move to firmware */
+}
+
MODULE_FIRMWARE(RTW8922D_MODULE_FIRMWARE);
MODULE_FIRMWARE(RTW8922DS_MODULE_FIRMWARE);
MODULE_AUTHOR("Realtek Corporation");
--
2.25.1
^ permalink raw reply related
* [PATCH rtw-next 8/9] wifi: rtw89: 8922d: add chip_info and chip_ops struct
From: Ping-Ke Shih @ 2026-03-30 6:58 UTC (permalink / raw)
To: linux-wireless
In-Reply-To: <20260330065847.48946-1-pkshih@realtek.com>
Add remaining functions including calculate RX gain for power saving,
channel frequency and RSSI from PPDU status, and WoWLAN declaration.
Then fill chip_info and chip_ops tables, which RTL8922D has two variants
RTL8922D and RTL8922DS supporting 4096 and 1024 QAM respectively. Other
features, such as support of 2/5/6 GHz and up to 160 MHz bandwidth, for
variants are the same,
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/fw.h | 23 +-
drivers/net/wireless/realtek/rtw89/reg.h | 17 +
drivers/net/wireless/realtek/rtw89/rtw8922d.c | 344 ++++++++++++++++++
drivers/net/wireless/realtek/rtw89/rtw8922d.h | 3 +
4 files changed, 380 insertions(+), 7 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h
index 4574a281d352..db252d45e498 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.h
+++ b/drivers/net/wireless/realtek/rtw89/fw.h
@@ -4298,13 +4298,22 @@ enum rtw89_fw_element_id {
BIT(RTW89_FW_ELEMENT_ID_TXPWR_TRK) | \
BITS_OF_RTW89_TXPWR_FW_ELEMENTS_NO_6GHZ)
-#define RTW89_BE_GEN_DEF_NEEDED_FW_ELEMENTS (BIT(RTW89_FW_ELEMENT_ID_BBMCU0) | \
- BIT(RTW89_FW_ELEMENT_ID_BB_REG) | \
- BIT(RTW89_FW_ELEMENT_ID_RADIO_A) | \
- BIT(RTW89_FW_ELEMENT_ID_RADIO_B) | \
- BIT(RTW89_FW_ELEMENT_ID_RF_NCTL) | \
- BIT(RTW89_FW_ELEMENT_ID_TXPWR_TRK) | \
- BITS_OF_RTW89_TXPWR_FW_ELEMENTS)
+#define RTW89_BE_GEN_DEF_NEEDED_FW_ELEMENTS_BASE \
+ (BIT(RTW89_FW_ELEMENT_ID_BB_REG) | \
+ BIT(RTW89_FW_ELEMENT_ID_RADIO_A) | \
+ BIT(RTW89_FW_ELEMENT_ID_RADIO_B) | \
+ BIT(RTW89_FW_ELEMENT_ID_RF_NCTL) | \
+ BIT(RTW89_FW_ELEMENT_ID_TXPWR_TRK) | \
+ BITS_OF_RTW89_TXPWR_FW_ELEMENTS)
+
+#define RTW89_BE_GEN_DEF_NEEDED_FW_ELEMENTS \
+ (RTW89_BE_GEN_DEF_NEEDED_FW_ELEMENTS_BASE | \
+ BIT(RTW89_FW_ELEMENT_ID_BBMCU0))
+
+#define RTW89_BE_GEN_DEF_NEEDED_FW_ELEMENTS_V1 \
+ (RTW89_BE_GEN_DEF_NEEDED_FW_ELEMENTS_BASE | \
+ BIT(RTW89_FW_ELEMENT_ID_AFE_PWR_SEQ) | \
+ BIT(RTW89_FW_ELEMENT_ID_TX_COMP))
struct __rtw89_fw_txpwr_element {
u8 rsvd0;
diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h
index e5e689f1bfa3..42ffe83931a3 100644
--- a/drivers/net/wireless/realtek/rtw89/reg.h
+++ b/drivers/net/wireless/realtek/rtw89/reg.h
@@ -4291,6 +4291,20 @@
#define B_BE_VERIFY_ENV_MASK GENMASK(9, 8)
#define B_BE_HW_ID_MASK GENMASK(7, 0)
+#define R_BE_SCOREBOARD_0 0x0110
+#define B_BE_SB0_TOGGLE BIT(31)
+#define B_BE_SB0_WL_DATA_LINE_MASK GENMASK(30, 0)
+
+#define R_BE_SCOREBOARD_0_BT_DATA 0x0114
+#define B_BE_SB0_BT_DATA_LINE_MASK GENMASK(30, 0)
+
+#define R_BE_SCOREBOARD_1 0x0118
+#define B_BE_SB1_TOGGLE BIT(31)
+#define B_BE_SB1_WL_DATA_LINE_MASK GENMASK(30, 0)
+
+#define R_BE_SCOREBOARD_1_BT_DATA 0x011C
+#define B_BE_SB1_BT_DATA_LINE_MASK GENMASK(30, 0)
+
#define R_BE_HALT_H2C_CTRL 0x0160
#define B_BE_HALT_H2C_TRIGGER BIT(0)
@@ -10656,6 +10670,9 @@
#define B_RX_LDPC08_BE4 GENMASK(29, 24)
#define R_RX_LDPC01_BE4 0x26840
#define B_RX_LDPC09_BE4 GENMASK(5, 0)
+#define R_BSS_CLR_MAP_BE4 0x26914
+#define R_BSS_CLR_VLD_BE4 0x26920
+#define B_BSS_CLR_VLD_BE4 BIT(2)
#define R_SW_SI_DATA_BE4 0x2CF4C
#define B_SW_SI_READ_DATA_BE4 GENMASK(19, 0)
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922d.c b/drivers/net/wireless/realtek/rtw89/rtw8922d.c
index a9a7ffb5fb58..e3b77cd23514 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922d.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922d.c
@@ -1447,6 +1447,20 @@ static void rtw8922d_set_rx_gain_normal(struct rtw89_dev *rtwdev,
rtw8922d_set_rx_gain_normal_ofdm(rtwdev, chan, path, phy_idx);
}
+static void rtw8922d_calc_rx_gain_normal(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan,
+ enum rtw89_rf_path path,
+ enum rtw89_phy_idx phy_idx,
+ struct rtw89_phy_calc_efuse_gain *calc)
+{
+ rtw8922d_calc_rx_gain_normal_ofdm(rtwdev, chan, path, phy_idx, calc);
+
+ if (chan->band_type != RTW89_BAND_2G)
+ return;
+
+ rtw8922d_calc_rx_gain_normal_cck(rtwdev, chan, path, phy_idx, calc);
+}
+
static void rtw8922d_set_cck_parameters(struct rtw89_dev *rtwdev,
const struct rtw89_chan *chan,
enum rtw89_phy_idx phy_idx)
@@ -2742,6 +2756,336 @@ static void rtw8922d_btc_set_wl_rx_gain(struct rtw89_dev *rtwdev, u32 level)
/* Feature move to firmware */
}
+static void rtw8922d_fill_freq_with_ppdu(struct rtw89_dev *rtwdev,
+ struct rtw89_rx_phy_ppdu *phy_ppdu,
+ struct ieee80211_rx_status *status)
+{
+ u8 chan_idx = phy_ppdu->chan_idx;
+ enum nl80211_band band;
+ u8 ch;
+
+ if (chan_idx == 0)
+ return;
+
+ rtw89_decode_chan_idx(rtwdev, chan_idx, &ch, &band);
+ status->freq = ieee80211_channel_to_frequency(ch, band);
+ status->band = band;
+}
+
+static void rtw8922d_query_ppdu(struct rtw89_dev *rtwdev,
+ struct rtw89_rx_phy_ppdu *phy_ppdu,
+ struct ieee80211_rx_status *status)
+{
+ u8 path;
+ u8 *rx_power = phy_ppdu->rssi;
+
+ if (!status->signal)
+ status->signal = RTW89_RSSI_RAW_TO_DBM(max(rx_power[RF_PATH_A],
+ rx_power[RF_PATH_B]));
+
+ for (path = 0; path < rtwdev->chip->rf_path_num; path++) {
+ status->chains |= BIT(path);
+ status->chain_signal[path] = RTW89_RSSI_RAW_TO_DBM(rx_power[path]);
+ }
+ if (phy_ppdu->valid)
+ rtw8922d_fill_freq_with_ppdu(rtwdev, phy_ppdu, status);
+}
+
+static void rtw8922d_convert_rpl_to_rssi(struct rtw89_dev *rtwdev,
+ struct rtw89_rx_phy_ppdu *phy_ppdu)
+{
+ /* Mapping to BW: 5, 10, 20, 40, 80, 160, 80_80 */
+ static const u8 bw_compensate[] = {0, 0, 0, 6, 12, 18, 0};
+ u8 *rssi = phy_ppdu->rssi;
+ u8 compensate = 0;
+ u8 i;
+
+ if (phy_ppdu->bw_idx < ARRAY_SIZE(bw_compensate))
+ compensate = bw_compensate[phy_ppdu->bw_idx];
+
+ for (i = 0; i < RF_PATH_NUM_8922D; i++) {
+ if (!(phy_ppdu->rx_path_en & BIT(i))) {
+ rssi[i] = 0;
+ phy_ppdu->rpl_path[i] = 0;
+ phy_ppdu->rpl_fd[i] = 0;
+ }
+
+ if (phy_ppdu->ie != RTW89_CCK_PKT && rssi[i])
+ rssi[i] += compensate;
+
+ phy_ppdu->rpl_path[i] = rssi[i];
+ }
+}
+
+static void rtw8922d_phy_rpt_to_rssi(struct rtw89_dev *rtwdev,
+ struct rtw89_rx_desc_info *desc_info,
+ struct ieee80211_rx_status *rx_status)
+{
+ if (desc_info->rssi <= 0x1 || (desc_info->rssi >> 2) > MAX_RSSI)
+ return;
+
+ rx_status->signal = (desc_info->rssi >> 2) - MAX_RSSI;
+}
+
+static int rtw8922d_mac_enable_bb_rf(struct rtw89_dev *rtwdev)
+{
+ return 0;
+}
+
+static int rtw8922d_mac_disable_bb_rf(struct rtw89_dev *rtwdev)
+{
+ return 0;
+}
+
+static const struct rtw89_chanctx_listener rtw8922d_chanctx_listener = {
+ .callbacks[RTW89_CHANCTX_CALLBACK_TAS] = rtw89_tas_chanctx_cb,
+};
+
+#ifdef CONFIG_PM
+static const struct wiphy_wowlan_support rtw_wowlan_stub_8922d = {
+ .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT |
+ WIPHY_WOWLAN_NET_DETECT,
+ .n_patterns = RTW89_MAX_PATTERN_NUM,
+ .pattern_max_len = RTW89_MAX_PATTERN_SIZE,
+ .pattern_min_len = 1,
+ .max_nd_match_sets = RTW89_SCANOFLD_MAX_SSID,
+};
+#endif
+
+static const struct rtw89_chip_ops rtw8922d_chip_ops = {
+ .enable_bb_rf = rtw8922d_mac_enable_bb_rf,
+ .disable_bb_rf = rtw8922d_mac_disable_bb_rf,
+ .bb_preinit = rtw8922d_bb_preinit,
+ .bb_postinit = rtw8922d_bb_postinit,
+ .bb_reset = rtw8922d_bb_reset,
+ .bb_sethw = rtw8922d_bb_sethw,
+ .read_rf = rtw89_phy_read_rf_v3,
+ .write_rf = rtw89_phy_write_rf_v3,
+ .set_channel = rtw8922d_set_channel,
+ .set_channel_help = rtw8922d_set_channel_help,
+ .read_efuse = rtw8922d_read_efuse,
+ .read_phycap = rtw8922d_read_phycap,
+ .fem_setup = NULL,
+ .rfe_gpio = NULL,
+ .rfk_hw_init = rtw8922d_rfk_hw_init,
+ .rfk_init = rtw8922d_rfk_init,
+ .rfk_init_late = rtw8922d_rfk_init_late,
+ .rfk_channel = rtw8922d_rfk_channel,
+ .rfk_band_changed = rtw8922d_rfk_band_changed,
+ .rfk_scan = rtw8922d_rfk_scan,
+ .rfk_track = rtw8922d_rfk_track,
+ .power_trim = rtw8922d_power_trim,
+ .set_txpwr = rtw8922d_set_txpwr,
+ .set_txpwr_ctrl = rtw8922d_set_txpwr_ctrl,
+ .init_txpwr_unit = NULL,
+ .get_thermal = rtw8922d_get_thermal,
+ .chan_to_rf18_val = rtw8922d_chan_to_rf18_val,
+ .ctrl_btg_bt_rx = rtw8922d_set_gbt_bt_rx_sel,
+ .query_ppdu = rtw8922d_query_ppdu,
+ .convert_rpl_to_rssi = rtw8922d_convert_rpl_to_rssi,
+ .phy_rpt_to_rssi = rtw8922d_phy_rpt_to_rssi,
+ .ctrl_nbtg_bt_tx = rtw8922d_ctrl_nbtg_bt_tx,
+ .cfg_txrx_path = rtw8922d_bb_cfg_txrx_path,
+ .set_txpwr_ul_tb_offset = NULL,
+ .digital_pwr_comp = rtw8922d_digital_pwr_comp,
+ .calc_rx_gain_normal = rtw8922d_calc_rx_gain_normal,
+ .pwr_on_func = rtw8922d_pwr_on_func,
+ .pwr_off_func = rtw8922d_pwr_off_func,
+ .query_rxdesc = rtw89_core_query_rxdesc_v3,
+ .fill_txdesc = rtw89_core_fill_txdesc_v3,
+ .fill_txdesc_fwcmd = rtw89_core_fill_txdesc_fwcmd_v2,
+ .get_ch_dma = {rtw89_core_get_ch_dma_v1,
+ NULL,
+ NULL,},
+ .cfg_ctrl_path = rtw89_mac_cfg_ctrl_path_v2,
+ .mac_cfg_gnt = rtw89_mac_cfg_gnt_v3,
+ .stop_sch_tx = rtw89_mac_stop_sch_tx_v2,
+ .resume_sch_tx = rtw89_mac_resume_sch_tx_v2,
+ .h2c_dctl_sec_cam = rtw89_fw_h2c_dctl_sec_cam_v3,
+ .h2c_default_cmac_tbl = rtw89_fw_h2c_default_cmac_tbl_be,
+ .h2c_assoc_cmac_tbl = rtw89_fw_h2c_assoc_cmac_tbl_be,
+ .h2c_ampdu_cmac_tbl = rtw89_fw_h2c_ampdu_cmac_tbl_be,
+ .h2c_txtime_cmac_tbl = rtw89_fw_h2c_txtime_cmac_tbl_be,
+ .h2c_punctured_cmac_tbl = rtw89_fw_h2c_punctured_cmac_tbl_be,
+ .h2c_default_dmac_tbl = rtw89_fw_h2c_default_dmac_tbl_v3,
+ .h2c_update_beacon = rtw89_fw_h2c_update_beacon_be,
+ .h2c_ba_cam = rtw89_fw_h2c_ba_cam_v1,
+ .h2c_wow_cam_update = rtw89_fw_h2c_wow_cam_update_v1,
+
+ .btc_set_rfe = rtw8922d_btc_set_rfe,
+ .btc_init_cfg = rtw8922d_btc_init_cfg,
+ .btc_set_wl_pri = NULL,
+ .btc_set_wl_txpwr_ctrl = rtw8922d_btc_set_wl_txpwr_ctrl,
+ .btc_get_bt_rssi = rtw8922d_btc_get_bt_rssi,
+ .btc_update_bt_cnt = rtw8922d_btc_update_bt_cnt,
+ .btc_wl_s1_standby = rtw8922d_btc_wl_s1_standby,
+ .btc_set_wl_rx_gain = rtw8922d_btc_set_wl_rx_gain,
+ .btc_set_policy = rtw89_btc_set_policy_v1,
+};
+
+const struct rtw89_chip_info rtw8922d_chip_info = {
+ .chip_id = RTL8922D,
+ .chip_gen = RTW89_CHIP_BE,
+ .ops = &rtw8922d_chip_ops,
+ .mac_def = &rtw89_mac_gen_be,
+ .phy_def = &rtw89_phy_gen_be_v1,
+ .fw_def = {
+ .fw_basename = RTW8922D_FW_BASENAME,
+ .fw_format_max = RTW8922D_FW_FORMAT_MAX,
+ .fw_b_aid = RTL8922D_AID7102,
+ },
+ .try_ce_fw = false,
+ .bbmcu_nr = 0,
+ .needed_fw_elms = RTW89_BE_GEN_DEF_NEEDED_FW_ELEMENTS_V1,
+ .fw_blacklist = &rtw89_fw_blacklist_default,
+ .fifo_size = 393216,
+ .small_fifo_size = false,
+ .dle_scc_rsvd_size = 0,
+ .max_amsdu_limit = 11000,
+ .max_vht_mpdu_cap = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991,
+ .max_eht_mpdu_cap = IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_7991,
+ .max_tx_agg_num = 128,
+ .max_rx_agg_num = 256,
+ .dis_2g_40m_ul_ofdma = false,
+ .rsvd_ple_ofst = 0x5f800,
+ .hfc_param_ini = {rtw8922d_hfc_param_ini_pcie, NULL, NULL},
+ .dle_mem = {rtw8922d_dle_mem_pcie, NULL, NULL, NULL},
+ .wde_qempty_acq_grpnum = 8,
+ .wde_qempty_mgq_grpsel = 8,
+ .rf_base_addr = {0x3e000, 0x3f000},
+ .thermal_th = {0xac, 0xad},
+ .pwr_on_seq = NULL,
+ .pwr_off_seq = NULL,
+ .bb_table = NULL,
+ .bb_gain_table = NULL,
+ .rf_table = {},
+ .nctl_table = NULL,
+ .nctl_post_table = &rtw8922d_nctl_post_defs_tbl,
+ .dflt_parms = NULL, /* load parm from fw */
+ .rfe_parms_conf = NULL, /* load parm from fw */
+ .chanctx_listener = &rtw8922d_chanctx_listener,
+ .txpwr_factor_bb = 3,
+ .txpwr_factor_rf = 2,
+ .txpwr_factor_mac = 1,
+ .dig_table = NULL,
+ .dig_regs = &rtw8922d_dig_regs,
+ .tssi_dbw_table = NULL,
+ .support_macid_num = 64,
+ .support_link_num = 2,
+ .support_chanctx_num = 2,
+ .support_rnr = true,
+ .support_bands = BIT(NL80211_BAND_2GHZ) |
+ BIT(NL80211_BAND_5GHZ) |
+ BIT(NL80211_BAND_6GHZ),
+ .support_bandwidths = BIT(NL80211_CHAN_WIDTH_20) |
+ BIT(NL80211_CHAN_WIDTH_40) |
+ BIT(NL80211_CHAN_WIDTH_80) |
+ BIT(NL80211_CHAN_WIDTH_160),
+ .support_unii4 = true,
+ .support_ant_gain = false,
+ .support_tas = false,
+ .support_sar_by_ant = true,
+ .support_noise = false,
+ .ul_tb_waveform_ctrl = false,
+ .ul_tb_pwr_diff = false,
+ .rx_freq_frome_ie = false,
+ .hw_sec_hdr = true,
+ .hw_mgmt_tx_encrypt = true,
+ .hw_tkip_crypto = true,
+ .hw_mlo_bmc_crypto = true,
+ .rf_path_num = 2,
+ .tx_nss = 2,
+ .rx_nss = 2,
+ .acam_num = 128,
+ .bcam_num = 16,
+ .scam_num = 32,
+ .bacam_num = 24,
+ .bacam_dynamic_num = 8,
+ .bacam_ver = RTW89_BACAM_V1,
+ .addrcam_ver = 1,
+ .ppdu_max_usr = 16,
+ .sec_ctrl_efuse_size = 4,
+ .physical_efuse_size = 0x1300,
+ .logical_efuse_size = 0x70000,
+ .limit_efuse_size = 0x40000,
+ .dav_phy_efuse_size = 0,
+ .dav_log_efuse_size = 0,
+ .efuse_blocks = rtw8922d_efuse_blocks,
+ .phycap_addr = 0x1700,
+ .phycap_size = 0x60,
+ .para_ver = 0x3ff,
+ .wlcx_desired = 0x09150000,
+ .scbd = 0x1,
+ .mailbox = 0x1,
+
+ .afh_guard_ch = 6,
+ .wl_rssi_thres = rtw89_btc_8922d_wl_rssi_thres,
+ .bt_rssi_thres = rtw89_btc_8922d_bt_rssi_thres,
+ .rssi_tol = 2,
+ .mon_reg_num = ARRAY_SIZE(rtw89_btc_8922d_mon_reg),
+ .mon_reg = rtw89_btc_8922d_mon_reg,
+ .rf_para_ulink_v9 = rtw89_btc_8922d_rf_ul_v9,
+ .rf_para_dlink_v9 = rtw89_btc_8922d_rf_dl_v9,
+ .rf_para_ulink_num_v9 = ARRAY_SIZE(rtw89_btc_8922d_rf_ul_v9),
+ .rf_para_dlink_num_v9 = ARRAY_SIZE(rtw89_btc_8922d_rf_dl_v9),
+ .ps_mode_supported = BIT(RTW89_PS_MODE_RFOFF) |
+ BIT(RTW89_PS_MODE_CLK_GATED) |
+ BIT(RTW89_PS_MODE_PWR_GATED),
+ .low_power_hci_modes = 0,
+ .h2c_cctl_func_id = H2C_FUNC_MAC_CCTLINFO_UD_G7,
+ .hci_func_en_addr = R_BE_HCI_FUNC_EN,
+ .h2c_desc_size = sizeof(struct rtw89_rxdesc_short_v3),
+ .txwd_body_size = sizeof(struct rtw89_txwd_body_v2),
+ .txwd_info_size = sizeof(struct rtw89_txwd_info_v2),
+ .h2c_ctrl_reg = R_BE_H2CREG_CTRL,
+ .h2c_counter_reg = {R_BE_UDM1 + 1, B_BE_UDM1_HALMAC_H2C_DEQ_CNT_MASK >> 8},
+ .h2c_regs = rtw8922d_h2c_regs,
+ .c2h_ctrl_reg = R_BE_C2HREG_CTRL,
+ .c2h_counter_reg = {R_BE_UDM1 + 1, B_BE_UDM1_HALMAC_C2H_ENQ_CNT_MASK >> 8},
+ .c2h_regs = rtw8922d_c2h_regs,
+ .page_regs = &rtw8922d_page_regs,
+ .wow_reason_reg = rtw8922d_wow_wakeup_regs,
+ .cfo_src_fd = true,
+ .cfo_hw_comp = true,
+ .dcfo_comp = NULL,
+ .dcfo_comp_sft = 0,
+ .nhm_report = NULL,
+ .nhm_th = NULL,
+ .imr_info = NULL,
+ .imr_dmac_table = &rtw8922d_imr_dmac_table,
+ .imr_cmac_table = &rtw8922d_imr_cmac_table,
+ .rrsr_cfgs = &rtw8922d_rrsr_cfgs,
+ .bss_clr_vld = {R_BSS_CLR_VLD_BE4, B_BSS_CLR_VLD_BE4},
+ .bss_clr_map_reg = R_BSS_CLR_MAP_BE4,
+ .rfkill_init = &rtw8922d_rfkill_regs,
+ .rfkill_get = {R_BE_GPIO_EXT_CTRL, B_BE_GPIO_IN_9},
+ .btc_sb = {{{R_BE_SCOREBOARD_0, R_BE_SCOREBOARD_0_BT_DATA},
+ {R_BE_SCOREBOARD_1, R_BE_SCOREBOARD_1_BT_DATA}}},
+ .dma_ch_mask = BIT(RTW89_DMA_ACH1) | BIT(RTW89_DMA_ACH3) |
+ BIT(RTW89_DMA_ACH5) | BIT(RTW89_DMA_ACH7) |
+ BIT(RTW89_DMA_B0HI) | BIT(RTW89_DMA_B1HI),
+ .edcca_regs = &rtw8922d_edcca_regs,
+#ifdef CONFIG_PM
+ .wowlan_stub = &rtw_wowlan_stub_8922d,
+#endif
+ .xtal_info = NULL,
+ .default_quirks = BIT(RTW89_QUIRK_THERMAL_PROT_120C),
+};
+EXPORT_SYMBOL(rtw8922d_chip_info);
+
+static const struct rtw89_fw_def rtw8922de_vs_fw_def = {
+ .fw_basename = RTW8922DS_FW_BASENAME,
+ .fw_format_max = RTW8922DS_FW_FORMAT_MAX,
+ .fw_b_aid = RTL8922D_AID7060,
+};
+
+const struct rtw89_chip_variant rtw8922de_vs_variant = {
+ .no_mcs_12_13 = true,
+ .fw_min_ver_code = RTW89_FW_VER_CODE(0, 0, 0, 0),
+ .fw_def_override = &rtw8922de_vs_fw_def,
+};
+EXPORT_SYMBOL(rtw8922de_vs_variant);
+
MODULE_FIRMWARE(RTW8922D_MODULE_FIRMWARE);
MODULE_FIRMWARE(RTW8922DS_MODULE_FIRMWARE);
MODULE_AUTHOR("Realtek Corporation");
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922d.h b/drivers/net/wireless/realtek/rtw89/rtw8922d.h
index a3b98ad6636c..22a7d1cc244f 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922d.h
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922d.h
@@ -77,4 +77,7 @@ struct rtw8922d_efuse {
struct rtw8922d_rx_gain_6g rx_gain_6g_b_2;
} __packed;
+extern const struct rtw89_chip_info rtw8922d_chip_info;
+extern const struct rtw89_chip_variant rtw8922de_vs_variant;
+
#endif
--
2.25.1
^ permalink raw reply related
* [PATCH rtw-next 9/9] wifi: rtw89: 8922d: add PCI ID of RTL8922DE and RTL8922DE-VS
From: Ping-Ke Shih @ 2026-03-30 6:58 UTC (permalink / raw)
To: linux-wireless
In-Reply-To: <20260330065847.48946-1-pkshih@realtek.com>
Add PCI ID tables with RTL8922DE whose ID is 10EC:895D, and with
RTL8922DE-VS whose ID are 10EC:892D and 10EC:882D. Also, add pci_info
struct to describe the hardware capabilities and registers accordingly.
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/pci.h | 3 +
.../net/wireless/realtek/rtw89/rtw8922de.c | 119 ++++++++++++++++++
2 files changed, 122 insertions(+)
create mode 100644 drivers/net/wireless/realtek/rtw89/rtw8922de.c
diff --git a/drivers/net/wireless/realtek/rtw89/pci.h b/drivers/net/wireless/realtek/rtw89/pci.h
index c7cd34e99349..e7da37b9da7d 100644
--- a/drivers/net/wireless/realtek/rtw89/pci.h
+++ b/drivers/net/wireless/realtek/rtw89/pci.h
@@ -1105,6 +1105,9 @@
B_BE_CH6_BUSY | B_BE_CH7_BUSY | B_BE_CH8_BUSY | \
B_BE_CH9_BUSY | B_BE_CH10_BUSY | B_BE_CH11_BUSY | \
B_BE_CH12_BUSY | B_BE_CH13_BUSY | B_BE_CH14_BUSY)
+#define DMA_BUSY1_CHECK_BE_V1 (B_BE_CH0_BUSY | B_BE_CH2_BUSY | B_BE_CH4_BUSY | \
+ B_BE_CH6_BUSY | B_BE_CH8_BUSY | B_BE_CH10_BUSY | \
+ B_BE_CH12_BUSY)
#define R_BE_HAXI_EXP_CTRL_V1 0xB020
#define B_BE_R_NO_SEC_ACCESS BIT(31)
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922de.c b/drivers/net/wireless/realtek/rtw89/rtw8922de.c
new file mode 100644
index 000000000000..f144e7fc76de
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922de.c
@@ -0,0 +1,119 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/* Copyright(c) 2026 Realtek Corporation
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+
+#include "pci.h"
+#include "reg.h"
+#include "rtw8922d.h"
+
+static const struct rtw89_pci_info rtw8922d_pci_info = {
+ .gen_def = &rtw89_pci_gen_be,
+ .isr_def = &rtw89_pci_isr_be_v1,
+ .txbd_trunc_mode = MAC_AX_BD_TRUNC,
+ .rxbd_trunc_mode = MAC_AX_BD_TRUNC,
+ .rxbd_mode = MAC_AX_RXBD_PKT,
+ .tag_mode = MAC_AX_TAG_MULTI,
+ .tx_burst = MAC_AX_TX_BURST_V1_256B,
+ .rx_burst = MAC_AX_RX_BURST_V1_128B,
+ .wd_dma_idle_intvl = MAC_AX_WD_DMA_INTVL_256NS,
+ .wd_dma_act_intvl = MAC_AX_WD_DMA_INTVL_256NS,
+ .multi_tag_num = MAC_AX_TAG_NUM_8,
+ .lbc_en = MAC_AX_PCIE_ENABLE,
+ .lbc_tmr = MAC_AX_LBC_TMR_2MS,
+ .autok_en = MAC_AX_PCIE_DISABLE,
+ .io_rcy_en = MAC_AX_PCIE_ENABLE,
+ .io_rcy_tmr = MAC_AX_IO_RCY_ANA_TMR_DEF,
+ .rx_ring_eq_is_full = true,
+ .check_rx_tag = true,
+ .no_rxbd_fs = true,
+ .group_bd_addr = true,
+ .rpp_fmt_size = sizeof(struct rtw89_pci_rpp_fmt_v1),
+
+ .init_cfg_reg = R_BE_HAXI_INIT_CFG1,
+ .txhci_en_bit = B_BE_TXDMA_EN,
+ .rxhci_en_bit = B_BE_RXDMA_EN,
+ .rxbd_mode_bit = B_BE_RXQ_RXBD_MODE_MASK,
+ .exp_ctrl_reg = R_BE_HAXI_EXP_CTRL_V1,
+ .max_tag_num_mask = B_BE_MAX_TAG_NUM_MASK,
+ .rxbd_rwptr_clr_reg = R_BE_RXBD_RWPTR_CLR1_V1,
+ .txbd_rwptr_clr2_reg = R_BE_TXBD_RWPTR_CLR1,
+ .dma_io_stop = {R_BE_HAXI_INIT_CFG1, B_BE_STOP_AXI_MST},
+ .dma_stop1 = {R_BE_HAXI_DMA_STOP1, B_BE_TX_STOP1_MASK_V1},
+ .dma_stop2 = {0},
+ .dma_busy1 = {R_BE_HAXI_DMA_BUSY1, DMA_BUSY1_CHECK_BE_V1},
+ .dma_busy2_reg = 0,
+ .dma_busy3_reg = R_BE_HAXI_DMA_BUSY1,
+
+ .rpwm_addr = R_BE_PCIE_HRPWM,
+ .cpwm_addr = R_BE_PCIE_CRPWM,
+ .mit_addr = R_BE_PCIE_MIT_CH_EN,
+ .wp_sel_addr = R_BE_WP_ADDR_H_SEL0_3_V1,
+ .tx_dma_ch_mask = BIT(RTW89_TXCH_ACH1) | BIT(RTW89_TXCH_ACH3) |
+ BIT(RTW89_TXCH_ACH5) | BIT(RTW89_TXCH_ACH7) |
+ BIT(RTW89_TXCH_CH9) | BIT(RTW89_TXCH_CH11),
+ .bd_idx_addr_low_power = NULL,
+ .dma_addr_set = &rtw89_pci_ch_dma_addr_set_be_v1,
+ .bd_ram_table = NULL,
+
+ .ltr_set = rtw89_pci_ltr_set_v2,
+ .fill_txaddr_info = rtw89_pci_fill_txaddr_info_v1,
+ .parse_rpp = rtw89_pci_parse_rpp_v1,
+ .config_intr_mask = rtw89_pci_config_intr_mask_v3,
+ .enable_intr = rtw89_pci_enable_intr_v3,
+ .disable_intr = rtw89_pci_disable_intr_v3,
+ .recognize_intrs = rtw89_pci_recognize_intrs_v3,
+
+ .ssid_quirks = NULL,
+};
+
+static const struct rtw89_driver_info rtw89_8922de_vs_info = {
+ .chip = &rtw8922d_chip_info,
+ .variant = &rtw8922de_vs_variant,
+ .quirks = NULL,
+ .bus = {
+ .pci = &rtw8922d_pci_info,
+ },
+};
+
+static const struct rtw89_driver_info rtw89_8922de_info = {
+ .chip = &rtw8922d_chip_info,
+ .variant = NULL,
+ .quirks = NULL,
+ .bus = {
+ .pci = &rtw8922d_pci_info,
+ },
+};
+
+static const struct pci_device_id rtw89_8922de_id_table[] = {
+ {
+ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x892D),
+ .driver_data = (kernel_ulong_t)&rtw89_8922de_vs_info,
+ },
+ {
+ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x882D),
+ .driver_data = (kernel_ulong_t)&rtw89_8922de_vs_info,
+ },
+ {
+ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x895D),
+ .driver_data = (kernel_ulong_t)&rtw89_8922de_info,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(pci, rtw89_8922de_id_table);
+
+static struct pci_driver rtw89_8922de_driver = {
+ .name = "rtw89_8922de",
+ .id_table = rtw89_8922de_id_table,
+ .probe = rtw89_pci_probe,
+ .remove = rtw89_pci_remove,
+ .driver.pm = &rtw89_pm_ops_be,
+ .err_handler = &rtw89_pci_err_handler,
+};
+module_pci_driver(rtw89_8922de_driver);
+
+MODULE_AUTHOR("Realtek Corporation");
+MODULE_DESCRIPTION("Realtek 802.11be wireless 8922DE/8922DE-VS driver");
+MODULE_LICENSE("Dual BSD/GPL");
--
2.25.1
^ permalink raw reply related
* Re: [PATCH v2 02/15] firmware: qcom: Add a generic PAS service
From: Sumit Garg @ 2026-03-30 7:08 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Konrad Dybcio, linux-arm-msm, devicetree, dri-devel, freedreno,
linux-media, netdev, linux-wireless, ath12k, linux-remoteproc,
andersson, konradybcio, robh, krzk+dt, conor+dt, robin.clark,
sean, akhilpo, lumag, abhinav.kumar, jesszhan0024, marijn.suijten,
airlied, simona, vikash.garodia, dikshita.agarwal, bod, mchehab,
elder, andrew+netdev, davem, edumazet, kuba, pabeni, jjohnson,
mathieu.poirier, trilokkumar.soni, mukesh.ojha, pavan.kondeti,
jorge.ramirez, tonyh, vignesh.viswanathan, srinivas.kandagatla,
amirreza.zarrabi, jens.wiklander, op-tee, apurupa, skare,
linux-kernel, Sumit Garg
In-Reply-To: <a0a7269d-7a09-4a78-a4b0-b39b67bc253b@kernel.org>
On Fri, Mar 27, 2026 at 02:56:40PM +0100, Krzysztof Kozlowski wrote:
> On 23/03/2026 15:26, Konrad Dybcio wrote:
> >>>
> >>> This pattern has been carried from the PAS API contract among kernel
> >>> clients and the SCM PAS service earlier. The clients don't hold a
> >>> reference to the PAS data like underlying platform or TEE device etc.
> >>> Hence the need to have a global data pointer to hold reference to the
> >>> ops data structure registered by drivers having different lifetime of
> >>> devices. Also, the PAS APIs can be called from very different client
> >>> driver contexts.
> >>>
> >>> Surely, avoiding global data is always better given a better alternative
> >>> is there. Do you have any better alternative proposal here?
> >>
> >> Why it cannot be part of the context?
> >>
> >> Look at your API, e.g.:
> >> qcom_pas_init_image(). It takes struct qcom_pas_context which should
> >> contain the ops.
Have a look at all other PAS client APIs, the context isn't something
that each client takes a reference and pass it on for every PAS
invocation. And changing the PAS API contract for kernel clients is out
of scope of this patch-set.
> >
> > This would make the client have to select the ops. The whole point is to
> > avoid that, since the client has no clue (and is supposed not to have any).
>
> Yeah, I see. The problem is that this patchset just keeps growing the
> singletons so except existing 'struct qcom_scm *__scm' in qcom_scm.c,
> this one brings at least three new: 'ops_ptr', 'qcom_pas_ops_scm' and
> 'qcom_pas_ops_tee'.
Not sure how you equate ops structure __pointer__ to the ops structure
itself. Can you enlighten me how in the rest of the kernel ops data
structures are shared among independent modules registering on different
bus types?
>
> I don't think you need all four in total, but only one which will hold
> whatever pointers are necessary.
Your arguments seems to be in favour of the existing monolithic SCM
driver design but you need to understand that's not how underlying TZ
services are implemented. The PAS service in TZ has nothing to do with
the ICE service for inline crypto as an example.
Please go through the motivation of this patch-set and the corresponding
OP-TEE implementation as TZ which is all open source.
-Sumit
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox