* [PATCH rtw-next v6 1/3] wifi: rtw88: rtw8822c: Use bitfield macros for DAC IQ sampling
2026-08-15 9:39 [PATCH rtw-next v6 0/3] wifi: rtw88: rtw8822c: refactor DAC IQ calibration to s32 Arsenii Pashchenko
@ 2026-08-15 9:39 ` Arsenii Pashchenko
2026-08-15 9:39 ` [PATCH rtw-next v6 2/3] wifi: rtw88: rtw8822c: Convert DAC IQ calibration path to signed math Arsenii Pashchenko
2026-08-15 9:39 ` [PATCH rtw-next v6 3/3] wifi: rtw88: rtw8822c: Replace custom DAC IQ sorting with kernel sort Arsenii Pashchenko
2 siblings, 0 replies; 4+ messages in thread
From: Arsenii Pashchenko @ 2026-08-15 9:39 UTC (permalink / raw)
To: pkshih; +Cc: linux-wireless, linux-kernel, Arsenii Pashchenko
Define proper GENMASK constants for the In-phase (I) and Quadrature
(Q) components of the DAC IQ data register in the header file.
Replace manual bit shifting, masking, and rtw_read32_mask() with
standard rtw_read32() and the FIELD_GET() macro to improve code
readability.
Signed-off-by: Arsenii Pashchenko <ulijg308@gmail.com>
---
drivers/net/wireless/realtek/rtw88/rtw8822c.c | 18 +++++++++---------
drivers/net/wireless/realtek/rtw88/rtw8822c.h | 3 +++
2 files changed, 12 insertions(+), 9 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.c b/drivers/net/wireless/realtek/rtw88/rtw8822c.c
index 244c80264..137544649 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c
@@ -291,9 +291,9 @@ static void rtw8822c_dac_cal_iq_sample(struct rtw_dev *rtwdev, u32 *iv, u32 *qv)
while (i < DACK_SN_8822C && cnt < 10000) {
cnt++;
- temp = rtw_read32_mask(rtwdev, 0x2dbc, 0x3fffff);
- iv[i] = (temp & 0x3ff000) >> 12;
- qv[i] = temp & 0x3ff;
+ temp = rtw_read32(rtwdev, 0x2dbc);
+ iv[i] = FIELD_GET(RTW8822C_DAC_IV_MASK, temp);
+ qv[i] = FIELD_GET(RTW8822C_DAC_QV_MASK, temp);
if (rtw8822c_dac_iq_check(rtwdev, iv[i]) &&
rtw8822c_dac_iq_check(rtwdev, qv[i]))
@@ -344,12 +344,12 @@ static void rtw8822c_dac_cal_iq_search(struct rtw_dev *rtwdev,
rtw8822c_dac_iq_sort(rtwdev, iv, qv);
if (i_delta > 5 || q_delta > 5) {
- temp = rtw_read32_mask(rtwdev, 0x2dbc, 0x3fffff);
- iv[0] = (temp & 0x3ff000) >> 12;
- qv[0] = temp & 0x3ff;
- temp = rtw_read32_mask(rtwdev, 0x2dbc, 0x3fffff);
- iv[DACK_SN_8822C - 1] = (temp & 0x3ff000) >> 12;
- qv[DACK_SN_8822C - 1] = temp & 0x3ff;
+ temp = rtw_read32(rtwdev, 0x2dbc);
+ iv[0] = FIELD_GET(RTW8822C_DAC_IV_MASK, temp);
+ qv[0] = FIELD_GET(RTW8822C_DAC_QV_MASK, temp);
+ temp = rtw_read32(rtwdev, 0x2dbc);
+ iv[DACK_SN_8822C - 1] = FIELD_GET(RTW8822C_DAC_IV_MASK, temp);
+ qv[DACK_SN_8822C - 1] = FIELD_GET(RTW8822C_DAC_QV_MASK, temp);
} else {
break;
}
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.h b/drivers/net/wireless/realtek/rtw88/rtw8822c.h
index fc62b67a1..7bea99614 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8822c.h
+++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.h
@@ -141,6 +141,9 @@ const struct rtw_table name ## _tbl = { \
#define DACK_RF_8822C 1
#define DACK_SN_8822C 100
+#define RTW8822C_DAC_IV_MASK GENMASK(21, 12)
+#define RTW8822C_DAC_QV_MASK GENMASK(9, 0)
+
/* phy status page0 */
#define GET_PHY_STAT_P0_PWDB_A(phy_stat) \
le32_get_bits(*((__le32 *)(phy_stat) + 0x00), GENMASK(15, 8))
--
2.55.0
^ permalink raw reply related [flat|nested] 4+ messages in thread* [PATCH rtw-next v6 2/3] wifi: rtw88: rtw8822c: Convert DAC IQ calibration path to signed math
2026-08-15 9:39 [PATCH rtw-next v6 0/3] wifi: rtw88: rtw8822c: refactor DAC IQ calibration to s32 Arsenii Pashchenko
2026-08-15 9:39 ` [PATCH rtw-next v6 1/3] wifi: rtw88: rtw8822c: Use bitfield macros for DAC IQ sampling Arsenii Pashchenko
@ 2026-08-15 9:39 ` Arsenii Pashchenko
2026-08-15 9:39 ` [PATCH rtw-next v6 3/3] wifi: rtw88: rtw8822c: Replace custom DAC IQ sorting with kernel sort Arsenii Pashchenko
2 siblings, 0 replies; 4+ messages in thread
From: Arsenii Pashchenko @ 2026-08-15 9:39 UTC (permalink / raw)
To: pkshih; +Cc: linux-wireless, linux-kernel, Arsenii Pashchenko
Convert the temporary stack arrays 'iv' and 'qv' from u32 to s32.
Update all internal function signatures to accept s32 pointers and
handle signed values natively.
Use sign_extend32() combined with FIELD_GET() to properly interpret
the 10-bit hardware values as signed integers. This allows flattening
the complex nested unsigned boundary conditions in
rtw8822c_dac_iq_check() into a simple amplitude boundary check. Ensure
rtw8822c_dac_iq_offset() properly maps the signed average back to a
10-bit unsigned format expected by the hardware registers.
Signed-off-by: Arsenii Pashchenko <ulijg308@gmail.com>
---
drivers/net/wireless/realtek/rtw88/rtw8822c.c | 135 ++++++------------
1 file changed, 40 insertions(+), 95 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.c b/drivers/net/wireless/realtek/rtw88/rtw8822c.c
index 137544649..a10e87d6e 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c
@@ -153,49 +153,14 @@ static void rtw8822c_dac_restore_reg(struct rtw_dev *rtwdev,
}
}
-static void rtw8822c_rf_minmax_cmp(struct rtw_dev *rtwdev, u32 value,
- u32 *min, u32 *max)
+static void __rtw8822c_dac_iq_sort(struct rtw_dev *rtwdev, s32 *v1, s32 *v2)
{
- if (value >= 0x200) {
- if (*min >= 0x200) {
- if (*min > value)
- *min = value;
- } else {
- *min = value;
- }
- if (*max >= 0x200) {
- if (*max < value)
- *max = value;
- }
- } else {
- if (*min < 0x200) {
- if (*min > value)
- *min = value;
- }
-
- if (*max >= 0x200) {
- *max = value;
- } else {
- if (*max < value)
- *max = value;
- }
- }
-}
-
-static void __rtw8822c_dac_iq_sort(struct rtw_dev *rtwdev, u32 *v1, u32 *v2)
-{
- if (*v1 >= 0x200 && *v2 >= 0x200) {
- if (*v1 > *v2)
- swap(*v1, *v2);
- } else if (*v1 < 0x200 && *v2 < 0x200) {
- if (*v1 > *v2)
- swap(*v1, *v2);
- } else if (*v1 < 0x200 && *v2 >= 0x200) {
+ if (*v1 > *v2)
swap(*v1, *v2);
- }
+
}
-static void rtw8822c_dac_iq_sort(struct rtw_dev *rtwdev, u32 *iv, u32 *qv)
+static void rtw8822c_dac_iq_sort(struct rtw_dev *rtwdev, s32 *iv, s32 *qv)
{
u32 i, j;
@@ -207,30 +172,16 @@ static void rtw8822c_dac_iq_sort(struct rtw_dev *rtwdev, u32 *iv, u32 *qv)
}
}
-static void rtw8822c_dac_iq_offset(struct rtw_dev *rtwdev, u32 *vec, u32 *val)
+static u32 rtw8822c_dac_iq_offset(struct rtw_dev *rtwdev, s32 *vec)
{
- u32 p, m, t, i;
+ s32 sum = 0;
- m = 0;
- p = 0;
- for (i = 10; i < DACK_SN_8822C - 10; i++) {
- if (vec[i] > 0x200)
- m = (0x400 - vec[i]) + m;
- else
- p = vec[i] + p;
- }
+ for (u32 i = 10; i < DACK_SN_8822C - 10; i++)
+ sum += vec[i];
- if (p > m) {
- t = p - m;
- t = t / (DACK_SN_8822C - 20);
- } else {
- t = m - p;
- t = t / (DACK_SN_8822C - 20);
- if (t != 0x0)
- t = 0x400 - t;
- }
+ s32 avg = sum / (DACK_SN_8822C - 20);
- *val = t;
+ return avg >= 0 ? (u32)avg : (u32)(0x400 + avg);
}
static u32 rtw8822c_get_path_write_addr(u8 path)
@@ -271,20 +222,18 @@ static u32 rtw8822c_get_path_read_addr(u8 path)
return base_addr;
}
-static bool rtw8822c_dac_iq_check(struct rtw_dev *rtwdev, u32 value)
+static bool rtw8822c_dac_iq_check(struct rtw_dev *rtwdev, s32 value)
{
- bool ret = true;
- if ((value >= 0x200 && (0x400 - value) > 0x64) ||
- (value < 0x200 && value > 0x64)) {
- ret = false;
+ if (value > 100 || value < -100) {
rtw_dbg(rtwdev, RTW_DBG_RFK, "[DACK] Error overflow\n");
+ return false;
}
- return ret;
+ return true;
}
-static void rtw8822c_dac_cal_iq_sample(struct rtw_dev *rtwdev, u32 *iv, u32 *qv)
+static void rtw8822c_dac_cal_iq_sample(struct rtw_dev *rtwdev, s32 *iv, s32 *qv)
{
u32 temp;
int i = 0, cnt = 0;
@@ -292,8 +241,8 @@ static void rtw8822c_dac_cal_iq_sample(struct rtw_dev *rtwdev, u32 *iv, u32 *qv)
while (i < DACK_SN_8822C && cnt < 10000) {
cnt++;
temp = rtw_read32(rtwdev, 0x2dbc);
- iv[i] = FIELD_GET(RTW8822C_DAC_IV_MASK, temp);
- qv[i] = FIELD_GET(RTW8822C_DAC_QV_MASK, temp);
+ iv[i] = FIELD_GET_SIGNED(RTW8822C_DAC_IV_MASK, temp);
+ qv[i] = FIELD_GET_SIGNED(RTW8822C_DAC_QV_MASK, temp);
if (rtw8822c_dac_iq_check(rtwdev, iv[i]) &&
rtw8822c_dac_iq_check(rtwdev, qv[i]))
@@ -302,67 +251,63 @@ static void rtw8822c_dac_cal_iq_sample(struct rtw_dev *rtwdev, u32 *iv, u32 *qv)
}
static void rtw8822c_dac_cal_iq_search(struct rtw_dev *rtwdev,
- u32 *iv, u32 *qv,
+ s32 *iv, s32 *qv,
u32 *i_value, u32 *q_value)
{
- u32 i_max = 0, q_max = 0, i_min = 0, q_min = 0;
+ s32 i_max = 0, q_max = 0, i_min = 0, q_min = 0;
u32 i_delta, q_delta;
u32 temp;
- int i, cnt = 0;
+ u32 i, cnt = 0;
do {
i_min = iv[0];
i_max = iv[0];
q_min = qv[0];
q_max = qv[0];
- for (i = 0; i < DACK_SN_8822C; i++) {
- rtw8822c_rf_minmax_cmp(rtwdev, iv[i], &i_min, &i_max);
- rtw8822c_rf_minmax_cmp(rtwdev, qv[i], &q_min, &q_max);
+ for (i = 1; i < DACK_SN_8822C; i++) {
+ if (iv[i] < i_min)
+ i_min = iv[i];
+ if (iv[i] > i_max)
+ i_max = iv[i];
+ if (qv[i] < q_min)
+ q_min = qv[i];
+ if (qv[i] > q_max)
+ q_max = qv[i];
}
- if (i_max < 0x200 && i_min < 0x200)
- i_delta = i_max - i_min;
- else if (i_max >= 0x200 && i_min >= 0x200)
- i_delta = i_max - i_min;
- else
- i_delta = i_max + (0x400 - i_min);
+ i_delta = i_max - i_min;
+ q_delta = q_max - q_min;
- if (q_max < 0x200 && q_min < 0x200)
- q_delta = q_max - q_min;
- else if (q_max >= 0x200 && q_min >= 0x200)
- q_delta = q_max - q_min;
- else
- q_delta = q_max + (0x400 - q_min);
rtw_dbg(rtwdev, RTW_DBG_RFK,
- "[DACK] i: min=0x%08x, max=0x%08x, delta=0x%08x\n",
+ "[DACK] i: min=%d, max=%d, delta=%d\n",
i_min, i_max, i_delta);
rtw_dbg(rtwdev, RTW_DBG_RFK,
- "[DACK] q: min=0x%08x, max=0x%08x, delta=0x%08x\n",
+ "[DACK] q: min=%d, max=%d, delta=%d",
q_min, q_max, q_delta);
rtw8822c_dac_iq_sort(rtwdev, iv, qv);
if (i_delta > 5 || q_delta > 5) {
temp = rtw_read32(rtwdev, 0x2dbc);
- iv[0] = FIELD_GET(RTW8822C_DAC_IV_MASK, temp);
- qv[0] = FIELD_GET(RTW8822C_DAC_QV_MASK, temp);
+ iv[0] = FIELD_GET_SIGNED(RTW8822C_DAC_IV_MASK, temp);
+ qv[0] = FIELD_GET_SIGNED(RTW8822C_DAC_QV_MASK, temp);
temp = rtw_read32(rtwdev, 0x2dbc);
- iv[DACK_SN_8822C - 1] = FIELD_GET(RTW8822C_DAC_IV_MASK, temp);
- qv[DACK_SN_8822C - 1] = FIELD_GET(RTW8822C_DAC_QV_MASK, temp);
+ iv[DACK_SN_8822C - 1] = FIELD_GET_SIGNED(RTW8822C_DAC_IV_MASK, temp);
+ qv[DACK_SN_8822C - 1] = FIELD_GET_SIGNED(RTW8822C_DAC_QV_MASK, temp);
} else {
break;
}
} while (cnt++ < 100);
- rtw8822c_dac_iq_offset(rtwdev, iv, i_value);
- rtw8822c_dac_iq_offset(rtwdev, qv, q_value);
+ *i_value = rtw8822c_dac_iq_offset(rtwdev, iv);
+ *q_value = rtw8822c_dac_iq_offset(rtwdev, qv);
}
static void rtw8822c_dac_cal_rf_mode(struct rtw_dev *rtwdev,
u32 *i_value, u32 *q_value)
{
- u32 iv[DACK_SN_8822C], qv[DACK_SN_8822C];
+ s32 iv[DACK_SN_8822C], qv[DACK_SN_8822C];
u32 rf_a, rf_b;
rf_a = rtw_read_rf(rtwdev, RF_PATH_A, 0x0, RFREG_MASK);
--
2.55.0
^ permalink raw reply related [flat|nested] 4+ messages in thread* [PATCH rtw-next v6 3/3] wifi: rtw88: rtw8822c: Replace custom DAC IQ sorting with kernel sort
2026-08-15 9:39 [PATCH rtw-next v6 0/3] wifi: rtw88: rtw8822c: refactor DAC IQ calibration to s32 Arsenii Pashchenko
2026-08-15 9:39 ` [PATCH rtw-next v6 1/3] wifi: rtw88: rtw8822c: Use bitfield macros for DAC IQ sampling Arsenii Pashchenko
2026-08-15 9:39 ` [PATCH rtw-next v6 2/3] wifi: rtw88: rtw8822c: Convert DAC IQ calibration path to signed math Arsenii Pashchenko
@ 2026-08-15 9:39 ` Arsenii Pashchenko
2 siblings, 0 replies; 4+ messages in thread
From: Arsenii Pashchenko @ 2026-08-15 9:39 UTC (permalink / raw)
To: pkshih; +Cc: linux-wireless, linux-kernel, Arsenii Pashchenko
Replace the custom, nested bubble-sort logic in the calibration loop
with direct calls to the kernel's optimized heapsort implementation
inside rtw8822c_dac_cal_iq_search().
Implement a safe, overflow-proof s32 comparator using the subtraction
of relationals pattern. Since the input values are already properly
sign-extended into signed arrays, the custom circular index sorting
rules and helper functions completely disappear, reducing lines of code.
Signed-off-by: Arsenii Pashchenko <ulijg308@gmail.com>
---
drivers/net/wireless/realtek/rtw88/rtw8822c.c | 22 ++++++-------------
1 file changed, 7 insertions(+), 15 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.c b/drivers/net/wireless/realtek/rtw88/rtw8822c.c
index a10e87d6e..8a6a8bbf9 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c
@@ -3,6 +3,7 @@
*/
#include <linux/module.h>
+#include <linux/sort.h>
#include "main.h"
#include "coex.h"
#include "fw.h"
@@ -153,24 +154,14 @@ static void rtw8822c_dac_restore_reg(struct rtw_dev *rtwdev,
}
}
-static void __rtw8822c_dac_iq_sort(struct rtw_dev *rtwdev, s32 *v1, s32 *v2)
+static int rtw8822c_dac_iq_cmp_s32(const void *a, const void *b)
{
- if (*v1 > *v2)
- swap(*v1, *v2);
+ s32 val_a = *(const s32 *)a;
+ s32 val_b = *(const s32 *)b;
+ return (val_a > val_b) - (val_a < val_b);
}
-static void rtw8822c_dac_iq_sort(struct rtw_dev *rtwdev, s32 *iv, s32 *qv)
-{
- u32 i, j;
-
- for (i = 0; i < DACK_SN_8822C - 1; i++) {
- for (j = 0; j < (DACK_SN_8822C - 1 - i) ; j++) {
- __rtw8822c_dac_iq_sort(rtwdev, &iv[j], &iv[j + 1]);
- __rtw8822c_dac_iq_sort(rtwdev, &qv[j], &qv[j + 1]);
- }
- }
-}
static u32 rtw8822c_dac_iq_offset(struct rtw_dev *rtwdev, s32 *vec)
{
@@ -286,7 +277,8 @@ static void rtw8822c_dac_cal_iq_search(struct rtw_dev *rtwdev,
"[DACK] q: min=%d, max=%d, delta=%d",
q_min, q_max, q_delta);
- rtw8822c_dac_iq_sort(rtwdev, iv, qv);
+ sort(iv, DACK_SN_8822C, sizeof(s32), rtw8822c_dac_iq_cmp_s32, NULL);
+ sort(qv, DACK_SN_8822C, sizeof(s32), rtw8822c_dac_iq_cmp_s32, NULL);
if (i_delta > 5 || q_delta > 5) {
temp = rtw_read32(rtwdev, 0x2dbc);
--
2.55.0
^ permalink raw reply related [flat|nested] 4+ messages in thread