// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* Copyright(c) 2024 Realtek Corporation
*/
#include "main.h"
#include "coex.h"
#include "phy.h"
#include "reg.h"
#include "rtw88xxa.h"
#include "rtw8821a.h"
#include "rtw8821a_table.h"
#include "tx.h"
static void rtw8821a_power_off(struct rtw_dev *rtwdev)
{
rtw88xxa_power_off(rtwdev, enter_lps_flow_8821a);
}
static s8 rtw8821a_cck_rx_pwr(u8 lna_idx, u8 vga_idx)
{
static const s8 lna_gain_table[] = {15 , -1 , -17 , 0 , -30 , -38 };
s8 rx_pwr_all = 0 ;
s8 lna_gain;
switch (lna_idx) {
case 5 :
case 4 :
case 2 :
case 1 :
case 0 :
lna_gain = lna_gain_table[lna_idx];
rx_pwr_all = lna_gain - 2 * vga_idx;
break ;
default :
break ;
}
return rx_pwr_all;
}
static void rtw8821a_query_phy_status(struct rtw_dev *rtwdev, u8 *phy_status,
struct rtw_rx_pkt_stat *pkt_stat)
{
rtw88xxa_query_phy_status(rtwdev, phy_status, pkt_stat,
rtw8821a_cck_rx_pwr);
}
static void rtw8821a_cfg_ldo25(struct rtw_dev *rtwdev, bool enable)
{
}
#define CAL_NUM_8821A 3
#define MACBB_REG_NUM_8821A 8
#define AFE_REG_NUM_8821A 4
#define RF_REG_NUM_8821A 3
static void rtw8821a_iqk_backup_rf(struct rtw_dev *rtwdev, u32 *rfa_backup,
const u32 *backup_rf_reg, u32 rf_num)
{
u32 i;
/* [31] = 0 --> Page C */
rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31 ), 0 x0);
/* Save RF Parameters */
for (i = 0 ; i < rf_num; i++)
rfa_backup[i] = rtw_read_rf(rtwdev, RF_PATH_A,
backup_rf_reg[i], MASKDWORD);
}
static void rtw8821a_iqk_restore_rf(struct rtw_dev *rtwdev,
const u32 *backup_rf_reg,
u32 *RF_backup, u32 rf_reg_num)
{
u32 i;
/* [31] = 0 --> Page C */
rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31 ), 0 x0);
for (i = 0 ; i < rf_reg_num; i++)
rtw_write_rf(rtwdev, RF_PATH_A, backup_rf_reg[i],
RFREG_MASK, RF_backup[i]);
}
static void rtw8821a_iqk_restore_afe(struct rtw_dev *rtwdev, u32 *afe_backup,
const u32 *backup_afe_reg, u32 afe_num)
{
u32 i;
/* [31] = 0 --> Page C */
rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31 ), 0 x0);
/* Reload AFE Parameters */
for (i = 0 ; i < afe_num; i++)
rtw_write32(rtwdev, backup_afe_reg[i], afe_backup[i]);
/* [31] = 1 --> Page C1 */
rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31 ), 0 x1);
rtw_write32(rtwdev, REG_OFDM0_XA_TX_IQ_IMBALANCE, 0 x0);
rtw_write32(rtwdev, REG_OFDM0_A_TX_AFE, 0 x0);
rtw_write32(rtwdev, REG_OFDM0_XB_TX_IQ_IMBALANCE, 0 x0);
rtw_write32(rtwdev, REG_TSSI_TRK_SW, 0 x3c000000);
rtw_write32(rtwdev, REG_LSSI_WRITE_A, 0 x00000080);
rtw_write32(rtwdev, REG_TXAGCIDX, 0 x00000000);
rtw_write32(rtwdev, REG_IQK_DPD_CFG, 0 x20040000);
rtw_write32(rtwdev, REG_CFG_PMPD, 0 x20000000);
rtw_write32(rtwdev, REG_RFECTL_A, 0 x0);
}
static void rtw8821a_iqk_rx_fill(struct rtw_dev *rtwdev,
unsigned int rx_x, unsigned int rx_y)
{
/* [31] = 0 --> Page C */
rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31 ), 0 x0);
rtw_write32_mask(rtwdev, REG_RX_IQC_AB_A,
0 x000003ff, rx_x >> 1 );
rtw_write32_mask(rtwdev, REG_RX_IQC_AB_A,
0 x03ff0000, (rx_y >> 1 ) & 0 x3ff);
}
static void rtw8821a_iqk_tx_fill(struct rtw_dev *rtwdev,
unsigned int tx_x, unsigned int tx_y)
{
/* [31] = 1 --> Page C1 */
rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31 ), 0 x1);
rtw_write32(rtwdev, REG_LSSI_WRITE_A, 0 x00000080);
rtw_write32(rtwdev, REG_IQK_DPD_CFG, 0 x20040000);
rtw_write32(rtwdev, REG_CFG_PMPD, 0 x20000000);
rtw_write32_mask(rtwdev, REG_IQC_Y, 0 x000007ff, tx_y);
rtw_write32_mask(rtwdev, REG_IQC_X, 0 x000007ff, tx_x);
}
static void rtw8821a_iqk_tx_vdf_true(struct rtw_dev *rtwdev, u32 cal,
bool *tx0iqkok,
int tx_x0[CAL_NUM_8821A],
int tx_y0[CAL_NUM_8821A])
{
u32 cal_retry, delay_count, iqk_ready, tx_fail;
int tx_dt[3 ], vdf_y[3 ], vdf_x[3 ];
int k;
for (k = 0 ; k < 3 ; k++) {
switch (k) {
case 0 :
/* TX_Tone_idx[9:0], TxK_Mask[29] TX_Tone = 16 */
rtw_write32(rtwdev, REG_OFDM0_XA_TX_IQ_IMBALANCE,
0 x18008c38);
/* RX_Tone_idx[9:0], RxK_Mask[29] */
rtw_write32(rtwdev, REG_OFDM0_A_TX_AFE, 0 x38008c38);
rtw_write32_mask(rtwdev, REG_INTPO_SETA, BIT(31 ), 0 x0);
break ;
case 1 :
rtw_write32_mask(rtwdev, REG_OFDM0_XA_TX_IQ_IMBALANCE,
BIT(28 ), 0 x0);
rtw_write32_mask(rtwdev, REG_OFDM0_A_TX_AFE,
BIT(28 ), 0 x0);
rtw_write32_mask(rtwdev, REG_INTPO_SETA, BIT(31 ), 0 x0);
break ;
case 2 :
rtw_dbg(rtwdev, RTW_DBG_RFK,
"vdf_y[1] = %x vdf_y[0] = %x\n" ,
vdf_y[1 ] >> 21 & 0 x00007ff,
vdf_y[0 ] >> 21 & 0 x00007ff);
rtw_dbg(rtwdev, RTW_DBG_RFK,
"vdf_x[1] = %x vdf_x[0] = %x\n" ,
vdf_x[1 ] >> 21 & 0 x00007ff,
vdf_x[0 ] >> 21 & 0 x00007ff);
tx_dt[cal] = (vdf_y[1 ] >> 20 ) - (vdf_y[0 ] >> 20 );
tx_dt[cal] = (16 * tx_dt[cal]) * 10000 / 15708 ;
tx_dt[cal] = (tx_dt[cal] >> 1 ) + (tx_dt[cal] & BIT(0 ));
/* TX_Tone_idx[9:0], TxK_Mask[29] TX_Tone = 16 */
rtw_write32(rtwdev, REG_OFDM0_XA_TX_IQ_IMBALANCE,
0 x18008c20);
/* RX_Tone_idx[9:0], RxK_Mask[29] */
rtw_write32(rtwdev, REG_OFDM0_A_TX_AFE, 0 x38008c20);
rtw_write32_mask(rtwdev, REG_INTPO_SETA, BIT(31 ), 0 x1);
rtw_write32_mask(rtwdev, REG_INTPO_SETA, 0 x3fff0000,
tx_dt[cal] & 0 x00003fff);
break ;
}
rtw_write32(rtwdev, REG_RFECTL_A, 0 x00100000);
for (cal_retry = 0 ; cal_retry < 10 ; cal_retry++) {
/* one shot */
rtw_write32(rtwdev, REG_IQK_COM64, 0 xfa000000);
rtw_write32(rtwdev, REG_IQK_COM64, 0 xf8000000);
mdelay(10 );
rtw_write32(rtwdev, REG_RFECTL_A, 0 x00000000);
for (delay_count = 0 ; delay_count < 20 ; delay_count++) {
iqk_ready = rtw_read32_mask(rtwdev,
REG_IQKA_END,
BIT(10 ));
/* Originally: if (~iqk_ready || delay_count > 20)
* that looks like a typo so make it more explicit
*/
iqk_ready = true ;
if (iqk_ready)
break ;
mdelay(1 );
}
if (delay_count < 20 ) {
/* ============TXIQK Check============== */
tx_fail = rtw_read32_mask(rtwdev,
REG_IQKA_END,
BIT(12 ));
/* Originally: if (~tx_fail) {
* It looks like a typo, so make it more explicit.
*/
tx_fail = false ;
if (!tx_fail) {
rtw_write32(rtwdev, REG_RFECTL_A,
0 x02000000);
vdf_x[k] = rtw_read32_mask(rtwdev,
REG_IQKA_END,
0 x07ff0000);
vdf_x[k] <<= 21 ;
rtw_write32(rtwdev, REG_RFECTL_A,
0 x04000000);
vdf_y[k] = rtw_read32_mask(rtwdev,
REG_IQKA_END,
0 x07ff0000);
vdf_y[k] <<= 21 ;
*tx0iqkok = true ;
break ;
}
rtw_write32_mask(rtwdev, REG_IQC_Y,
0 x000007ff, 0 x0);
rtw_write32_mask(rtwdev, REG_IQC_X,
0 x000007ff, 0 x200);
}
*tx0iqkok = false ;
}
}
if (k == 3 ) {
tx_x0[cal] = vdf_x[k - 1 ];
tx_y0[cal] = vdf_y[k - 1 ];
}
}
static void rtw8821a_iqk_tx_vdf_false(struct rtw_dev *rtwdev, u32 cal,
bool *tx0iqkok,
int tx_x0[CAL_NUM_8821A],
int tx_y0[CAL_NUM_8821A])
{
u32 cal_retry, delay_count, iqk_ready, tx_fail;
/* TX_Tone_idx[9:0], TxK_Mask[29] TX_Tone = 16 */
rtw_write32(rtwdev, REG_OFDM0_XA_TX_IQ_IMBALANCE, 0 x18008c10);
/* RX_Tone_idx[9:0], RxK_Mask[29] */
rtw_write32(rtwdev, REG_OFDM0_A_TX_AFE, 0 x38008c10);
rtw_write32(rtwdev, REG_RFECTL_A, 0 x00100000);
for (cal_retry = 0 ; cal_retry < 10 ; cal_retry++) {
/* one shot */
rtw_write32(rtwdev, REG_IQK_COM64, 0 xfa000000);
rtw_write32(rtwdev, REG_IQK_COM64, 0 xf8000000);
mdelay(10 );
rtw_write32(rtwdev, REG_RFECTL_A, 0 x00000000);
for (delay_count = 0 ; delay_count < 20 ; delay_count++) {
iqk_ready = rtw_read32_mask(rtwdev, REG_IQKA_END, BIT(10 ));
/* Originally: if (~iqk_ready || delay_count > 20)
* that looks like a typo so make it more explicit
*/
iqk_ready = true ;
if (iqk_ready)
break ;
mdelay(1 );
}
if (delay_count < 20 ) {
/* ============TXIQK Check============== */
tx_fail = rtw_read32_mask(rtwdev, REG_IQKA_END, BIT(12 ));
/* Originally: if (~tx_fail) {
* It looks like a typo, so make it more explicit.
*/
tx_fail = false ;
if (!tx_fail) {
rtw_write32(rtwdev, REG_RFECTL_A, 0 x02000000);
tx_x0[cal] = rtw_read32_mask(rtwdev, REG_IQKA_END,
0 x07ff0000);
tx_x0[cal] <<= 21 ;
rtw_write32(rtwdev, REG_RFECTL_A, 0 x04000000);
tx_y0[cal] = rtw_read32_mask(rtwdev, REG_IQKA_END,
0 x07ff0000);
tx_y0[cal] <<= 21 ;
*tx0iqkok = true ;
break ;
}
rtw_write32_mask(rtwdev, REG_IQC_Y, 0 x000007ff, 0 x0);
rtw_write32_mask(rtwdev, REG_IQC_X, 0 x000007ff, 0 x200);
}
*tx0iqkok = false ;
}
}
static void rtw8821a_iqk_rx(struct rtw_dev *rtwdev, u32 cal, bool *rx0iqkok,
int rx_x0[CAL_NUM_8821A],
int rx_y0[CAL_NUM_8821A])
{
u32 cal_retry, delay_count, iqk_ready, rx_fail;
rtw_write32(rtwdev, REG_RFECTL_A, 0 x00100000);
for (cal_retry = 0 ; cal_retry < 10 ; cal_retry++) {
/* one shot */
rtw_write32(rtwdev, REG_IQK_COM64, 0 xfa000000);
rtw_write32(rtwdev, REG_IQK_COM64, 0 xf8000000);
mdelay(10 );
rtw_write32(rtwdev, REG_RFECTL_A, 0 x00000000);
for (delay_count = 0 ; delay_count < 20 ; delay_count++) {
iqk_ready = rtw_read32_mask(rtwdev, REG_IQKA_END, BIT(10 ));
/* Originally: if (~iqk_ready || delay_count > 20)
* that looks like a typo so make it more explicit
*/
iqk_ready = true ;
if (iqk_ready)
break ;
mdelay(1 );
}
if (delay_count < 20 ) {
/* ============RXIQK Check============== */
rx_fail = rtw_read32_mask(rtwdev, REG_IQKA_END, BIT(11 ));
if (!rx_fail) {
rtw_write32(rtwdev, REG_RFECTL_A, 0 x06000000);
rx_x0[cal] = rtw_read32_mask(rtwdev, REG_IQKA_END,
0 x07ff0000);
rx_x0[cal] <<= 21 ;
rtw_write32(rtwdev, REG_RFECTL_A, 0 x08000000);
rx_y0[cal] = rtw_read32_mask(rtwdev, REG_IQKA_END,
0 x07ff0000);
rx_y0[cal] <<= 21 ;
*rx0iqkok = true ;
break ;
}
rtw_write32_mask(rtwdev, REG_RX_IQC_AB_A,
0 x000003ff, 0 x200 >> 1 );
rtw_write32_mask(rtwdev, REG_RX_IQC_AB_A,
0 x03ff0000, 0 x0 >> 1 );
}
*rx0iqkok = false ;
}
}
static void rtw8821a_iqk(struct rtw_dev *rtwdev)
{
int tx_average = 0 , rx_average = 0 , rx_iqk_loop = 0 ;
const struct rtw_efuse *efuse = &rtwdev->efuse;
int tx_x = 0 , tx_y = 0 , rx_x = 0 , rx_y = 0 ;
const struct rtw_hal *hal = &rtwdev->hal;
bool tx0iqkok = false , rx0iqkok = false ;
int rx_x_temp = 0 , rx_y_temp = 0 ;
int rx_x0[2 ][CAL_NUM_8821A];
int rx_y0[2 ][CAL_NUM_8821A];
int tx_x0[CAL_NUM_8821A];
int tx_y0[CAL_NUM_8821A];
bool rx_finish1 = false ;
bool rx_finish2 = false ;
bool vdf_enable;
u32 cal;
int i;
rtw_dbg(rtwdev, RTW_DBG_RFK,
"band_width = %d, ext_pa = %d, ext_pa_5g = %d\n" ,
hal->current_band_width, efuse->ext_pa_2g, efuse->ext_pa_5g);
vdf_enable = hal->current_band_width == RTW_CHANNEL_WIDTH_80;
for (cal = 0 ; cal < CAL_NUM_8821A; cal++) {
/* path-A LOK */
/* [31] = 0 --> Page C */
rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31 ), 0 x0);
/* ========path-A AFE all on======== */
/* Port 0 DAC/ADC on */
rtw_write32(rtwdev, REG_AFE_PWR1_A, 0 x77777777);
rtw_write32(rtwdev, REG_AFE_PWR2_A, 0 x77777777);
rtw_write32(rtwdev, REG_RX_WAIT_CCA_TX_CCK_RFON_A, 0 x19791979);
/* hardware 3-wire off */
rtw_write32_mask(rtwdev, REG_3WIRE_SWA, 0 xf, 0 x4);
/* LOK setting */
/* 1. DAC/ADC sampling rate (160 MHz) */
rtw_write32_mask(rtwdev, REG_CK_MONHA, GENMASK(26 , 24 ), 0 x7);
/* 2. LoK RF setting (at BW = 20M) */
rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWE, RFREG_MASK, 0 x80002);
rtw_write_rf(rtwdev, RF_PATH_A, RF_CFGCH, 0 x00c00, 0 x3);
rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_ADDR, RFREG_MASK,
0 x20000);
rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_DATA0, RFREG_MASK,
0 x0003f);
rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_DATA1, RFREG_MASK,
0 xf3fc3);
rtw_write_rf(rtwdev, RF_PATH_A, RF_TXA_PREPAD, RFREG_MASK,
0 x931d5);
rtw_write_rf(rtwdev, RF_PATH_A, RF_RXBB2, RFREG_MASK, 0 x8a001);
rtw_write32(rtwdev, REG_DAC_RSTB, 0 x00008000);
rtw_write32_mask(rtwdev, REG_TXAGCIDX, BIT(0 ), 0 x1);
/* TX (X,Y) */
rtw_write32(rtwdev, REG_IQK_COM00, 0 x29002000);
/* RX (X,Y) */
rtw_write32(rtwdev, REG_IQK_COM32, 0 xa9002000);
/* [0]:AGC_en, [15]:idac_K_Mask */
rtw_write32(rtwdev, REG_IQK_COM96, 0 x00462910);
/* [31] = 1 --> Page C1 */
rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31 ), 0 x1);
if (efuse->ext_pa_5g)
rtw_write32(rtwdev, REG_OFDM0_XB_TX_IQ_IMBALANCE,
0 x821403f7);
else
rtw_write32(rtwdev, REG_OFDM0_XB_TX_IQ_IMBALANCE,
0 x821403f4);
if (hal->current_band_type == RTW_BAND_5G)
rtw_write32(rtwdev, REG_TSSI_TRK_SW, 0 x68163e96);
else
rtw_write32(rtwdev, REG_TSSI_TRK_SW, 0 x28163e96);
/* TX_Tone_idx[9:0], TxK_Mask[29] TX_Tone = 16 */
rtw_write32(rtwdev, REG_OFDM0_XA_TX_IQ_IMBALANCE, 0 x18008c10);
/* RX_Tone_idx[9:0], RxK_Mask[29] */
rtw_write32(rtwdev, REG_OFDM0_A_TX_AFE, 0 x38008c10);
rtw_write32(rtwdev, REG_RFECTL_A, 0 x00100000);
rtw_write32(rtwdev, REG_IQK_COM64, 0 xfa000000);
rtw_write32(rtwdev, REG_IQK_COM64, 0 xf8000000);
mdelay(10 );
rtw_write32(rtwdev, REG_RFECTL_A, 0 x00000000);
/* [31] = 0 --> Page C */
rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31 ), 0 x0);
rtw_write_rf(rtwdev, RF_PATH_A, RF_TXMOD, 0 x7fe00,
rtw_read_rf(rtwdev, RF_PATH_A, RF_DTXLOK, 0 xffc00));
if (hal->current_band_width == RTW_CHANNEL_WIDTH_40)
rtw_write_rf(rtwdev, RF_PATH_A, RF_CFGCH,
RF18_BW_MASK, 0 x1);
else if (hal->current_band_width == RTW_CHANNEL_WIDTH_80)
rtw_write_rf(rtwdev, RF_PATH_A, RF_CFGCH,
RF18_BW_MASK, 0 x0);
/* [31] = 1 --> Page C1 */
rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31 ), 0 x1);
/* 3. TX RF setting */
/* [31] = 0 --> Page C */
rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31 ), 0 x0);
rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWE, RFREG_MASK, 0 x80000);
rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_ADDR, RFREG_MASK,
0 x20000);
rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_DATA0, RFREG_MASK,
0 x0003f);
rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_DATA1, RFREG_MASK,
0 xf3fc3);
rtw_write_rf(rtwdev, RF_PATH_A, RF_TXA_PREPAD, RFREG_MASK, 0 x931d5);
rtw_write_rf(rtwdev, RF_PATH_A, RF_RXBB2, RFREG_MASK, 0 x8a001);
rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWE, RFREG_MASK, 0 x00000);
rtw_write32(rtwdev, REG_DAC_RSTB, 0 x00008000);
rtw_write32_mask(rtwdev, REG_TXAGCIDX, BIT(0 ), 0 x1);
/* TX (X,Y) */
rtw_write32(rtwdev, REG_IQK_COM00, 0 x29002000);
/* RX (X,Y) */
rtw_write32(rtwdev, REG_IQK_COM32, 0 xa9002000);
/* [0]:AGC_en, [15]:idac_K_Mask */
rtw_write32(rtwdev, REG_IQK_COM96, 0 x0046a910);
/* [31] = 1 --> Page C1 */
rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31 ), 0 x1);
if (efuse->ext_pa_5g)
rtw_write32(rtwdev, REG_OFDM0_XB_TX_IQ_IMBALANCE,
0 x821403f7);
else
rtw_write32(rtwdev, REG_OFDM0_XB_TX_IQ_IMBALANCE,
0 x821403e3);
if (hal->current_band_type == RTW_BAND_5G)
rtw_write32(rtwdev, REG_TSSI_TRK_SW, 0 x40163e96);
else
rtw_write32(rtwdev, REG_TSSI_TRK_SW, 0 x00163e96);
if (vdf_enable)
rtw8821a_iqk_tx_vdf_true(rtwdev, cal, &tx0iqkok,
tx_x0, tx_y0);
else
rtw8821a_iqk_tx_vdf_false(rtwdev, cal, &tx0iqkok,
tx_x0, tx_y0);
if (!tx0iqkok)
break ; /* TXK fail, Don't do RXK */
/* ====== RX IQK ====== */
/* [31] = 0 --> Page C */
rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31 ), 0 x0);
/* 1. RX RF setting */
rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWE, RFREG_MASK, 0 x80000);
rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_ADDR, RFREG_MASK,
0 x30000);
rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_DATA0, RFREG_MASK,
0 x0002f);
rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_DATA1, RFREG_MASK,
0 xfffbb);
rtw_write_rf(rtwdev, RF_PATH_A, RF_RXBB2, RFREG_MASK, 0 x88001);
rtw_write_rf(rtwdev, RF_PATH_A, RF_TXA_PREPAD, RFREG_MASK, 0 x931d8);
rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWE, RFREG_MASK, 0 x00000);
rtw_write32_mask(rtwdev, REG_IQK_COM00, 0 x03FF8000,
(tx_x0[cal] >> 21 ) & 0 x000007ff);
rtw_write32_mask(rtwdev, REG_IQK_COM00, 0 x000007FF,
(tx_y0[cal] >> 21 ) & 0 x000007ff);
rtw_write32_mask(rtwdev, REG_IQK_COM00, BIT(31 ), 0 x1);
rtw_write32_mask(rtwdev, REG_IQK_COM00, BIT(31 ), 0 x0);
rtw_write32(rtwdev, REG_DAC_RSTB, 0 x00008000);
rtw_write32(rtwdev, REG_IQK_COM96, 0 x0046a911);
/* [31] = 1 --> Page C1 */
rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31 ), 0 x1);
/* TX_Tone_idx[9:0], TxK_Mask[29] TX_Tone = 16 */
rtw_write32(rtwdev, REG_OFDM0_XA_TX_IQ_IMBALANCE, 0 x38008c10);
/* RX_Tone_idx[9:0], RxK_Mask[29] */
rtw_write32(rtwdev, REG_OFDM0_A_TX_AFE, 0 x18008c10);
rtw_write32(rtwdev, REG_OFDM0_XB_TX_IQ_IMBALANCE, 0 x02140119);
if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_PCIE)
rx_iqk_loop = 2 ; /* for 2% fail; */
else
rx_iqk_loop = 1 ;
for (i = 0 ; i < rx_iqk_loop; i++) {
if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_PCIE && i == 0 )
rtw_write32(rtwdev, REG_TSSI_TRK_SW, 0 x28161100); /* Good */
else
rtw_write32(rtwdev, REG_TSSI_TRK_SW, 0 x28160d00);
rtw8821a_iqk_rx(rtwdev, cal, &rx0iqkok,
rx_x0[i], rx_y0[i]);
}
if (tx0iqkok)
tx_average++;
if (rx0iqkok)
rx_average++;
}
/* FillIQK Result */
if (tx_average == 0 )
return ;
for (i = 0 ; i < tx_average; i++)
rtw_dbg(rtwdev, RTW_DBG_RFK,
"tx_x0[%d] = %x ;; tx_y0[%d] = %x\n" ,
i, (tx_x0[i] >> 21 ) & 0 x000007ff,
i, (tx_y0[i] >> 21 ) & 0 x000007ff);
if (rtw88xxa_iqk_finish(tx_average, 3 , tx_x0, tx_y0,
&tx_x, &tx_y, true , true ))
rtw8821a_iqk_tx_fill(rtwdev, tx_x, tx_y);
else
rtw8821a_iqk_tx_fill(rtwdev, 0 x200, 0 x0);
if (rx_average == 0 )
return ;
for (i = 0 ; i < rx_average; i++) {
rtw_dbg(rtwdev, RTW_DBG_RFK,
"rx_x0[0][%d] = %x ;; rx_y0[0][%d] = %x\n" ,
i, (rx_x0[0 ][i] >> 21 ) & 0 x000007ff,
i, (rx_y0[0 ][i] >> 21 ) & 0 x000007ff);
if (rx_iqk_loop == 2 )
rtw_dbg(rtwdev, RTW_DBG_RFK,
"rx_x0[1][%d] = %x ;; rx_y0[1][%d] = %x\n" ,
i, (rx_x0[1 ][i] >> 21 ) & 0 x000007ff,
i, (rx_y0[1 ][i] >> 21 ) & 0 x000007ff);
}
rx_finish1 = rtw88xxa_iqk_finish(rx_average, 4 , rx_x0[0 ], rx_y0[0 ],
&rx_x_temp, &rx_y_temp, true , true );
if (rx_finish1) {
rx_x = rx_x_temp;
rx_y = rx_y_temp;
}
if (rx_iqk_loop == 2 ) {
rx_finish2 = rtw88xxa_iqk_finish(rx_average, 4 ,
rx_x0[1 ], rx_y0[1 ],
&rx_x, &rx_y, true , true );
if (rx_finish1 && rx_finish2) {
rx_x = (rx_x + rx_x_temp) / 2 ;
rx_y = (rx_y + rx_y_temp) / 2 ;
}
}
if (rx_finish1 || rx_finish2)
rtw8821a_iqk_rx_fill(rtwdev, rx_x, rx_y);
else
rtw8821a_iqk_rx_fill(rtwdev, 0 x200, 0 x0);
}
static void rtw8821a_do_iqk(struct rtw_dev *rtwdev)
{
static const u32 backup_macbb_reg[MACBB_REG_NUM_8821A] = {
0 x520, 0 x550, 0 x808, 0 xa04, 0 x90c, 0 xc00, 0 x838, 0 x82c
};
static const u32 backup_afe_reg[AFE_REG_NUM_8821A] = {
0 xc5c, 0 xc60, 0 xc64, 0 xc68
};
static const u32 backup_rf_reg[RF_REG_NUM_8821A] = {
0 x65, 0 x8f, 0 x0
};
u32 macbb_backup[MACBB_REG_NUM_8821A];
u32 afe_backup[AFE_REG_NUM_8821A];
u32 rfa_backup[RF_REG_NUM_8821A];
rtw88xxa_iqk_backup_mac_bb(rtwdev, macbb_backup,
backup_macbb_reg, MACBB_REG_NUM_8821A);
rtw88xxa_iqk_backup_afe(rtwdev, afe_backup,
backup_afe_reg, AFE_REG_NUM_8821A);
rtw8821a_iqk_backup_rf(rtwdev, rfa_backup,
backup_rf_reg, RF_REG_NUM_8821A);
rtw88xxa_iqk_configure_mac(rtwdev);
rtw8821a_iqk(rtwdev);
rtw8821a_iqk_restore_rf(rtwdev, backup_rf_reg,
rfa_backup, RF_REG_NUM_8821A);
rtw8821a_iqk_restore_afe(rtwdev, afe_backup,
backup_afe_reg, AFE_REG_NUM_8821A);
rtw88xxa_iqk_restore_mac_bb(rtwdev, macbb_backup,
backup_macbb_reg, MACBB_REG_NUM_8821A);
}
static void rtw8821a_phy_calibration(struct rtw_dev *rtwdev)
{
rtw8821a_do_iqk(rtwdev);
}
static void rtw8821a_pwr_track(struct rtw_dev *rtwdev)
{
struct rtw_dm_info *dm_info = &rtwdev->dm_info;
if (!dm_info->pwr_trk_triggered) {
rtw_write_rf(rtwdev, RF_PATH_A, RF_T_METER,
GENMASK(17 , 16 ), 0 x03);
dm_info->pwr_trk_triggered = true ;
return ;
}
rtw88xxa_phy_pwrtrack(rtwdev, NULL, rtw8821a_do_iqk);
dm_info->pwr_trk_triggered = false ;
}
static void rtw8821a_led_set(struct led_classdev *led,
enum led_brightness brightness)
{
struct rtw_dev *rtwdev = container_of(led, struct rtw_dev, led_cdev);
u32 gpio8_cfg;
u8 ledcfg;
if (brightness == LED_OFF) {
gpio8_cfg = rtw_read32(rtwdev, REG_GPIO_PIN_CTRL_2);
gpio8_cfg &= ~BIT(24 );
gpio8_cfg |= BIT(16 ) | BIT(8 );
rtw_write32(rtwdev, REG_GPIO_PIN_CTRL_2, gpio8_cfg);
} else {
ledcfg = rtw_read8(rtwdev, REG_LED_CFG + 2 );
gpio8_cfg = rtw_read32(rtwdev, REG_GPIO_PIN_CTRL_2);
ledcfg &= BIT(7 ) | BIT(6 );
rtw_write8(rtwdev, REG_LED_CFG + 2 , ledcfg);
gpio8_cfg &= ~(BIT(24 ) | BIT(8 ));
gpio8_cfg |= BIT(16 );
rtw_write32(rtwdev, REG_GPIO_PIN_CTRL_2, gpio8_cfg);
}
}
static void rtw8821a_fill_txdesc_checksum(struct rtw_dev *rtwdev,
struct rtw_tx_pkt_info *pkt_info,
u8 *txdesc)
{
fill_txdesc_checksum_common(txdesc, 16 );
}
static void rtw8821a_coex_cfg_init(struct rtw_dev *rtwdev)
{
u8 val8;
/* BT report packet sample rate */
rtw_write8_mask(rtwdev, REG_BT_TDMA_TIME, BIT_MASK_SAMPLE_RATE, 0 x5);
val8 = BIT_STATIS_BT_EN;
if (rtwdev->efuse.share_ant)
val8 |= BIT_R_GRANTALL_WLMASK;
rtw_write8(rtwdev, REG_BT_COEX_ENH_INTR_CTRL, val8);
/* enable BT counter statistics */
rtw_write8(rtwdev, REG_BT_STAT_CTRL, 0 x3);
/* enable PTA */
rtw_write32_set(rtwdev, REG_GPIO_MUXCFG, BIT_BT_PTA_EN);
}
static void rtw8821a_coex_cfg_ant_switch(struct rtw_dev *rtwdev, u8 ctrl_type,
u8 pos_type)
{
bool share_ant = rtwdev->efuse.share_ant;
struct rtw_coex *coex = &rtwdev->coex;
struct rtw_coex_dm *coex_dm = &coex->dm;
u32 phase = coex_dm->cur_ant_pos_type;
if (!rtwdev->efuse.btcoex)
return ;
switch (phase) {
case COEX_SET_ANT_POWERON:
case COEX_SET_ANT_INIT:
rtw_write32_clr(rtwdev, REG_LED_CFG, BIT_DPDT_SEL_EN);
rtw_write32_set(rtwdev, REG_LED_CFG, BIT_DPDT_WL_SEL);
rtw_write8_set(rtwdev, REG_GNT_BT, BIT_PTA_SW_CTL);
rtw_write8(rtwdev, REG_RFE_CTRL8,
share_ant ? PTA_CTRL_PIN : DPDT_CTRL_PIN);
rtw_write32_mask(rtwdev, REG_RFE_CTRL8, 0 x30000000, 0 x1);
break ;
case COEX_SET_ANT_WONLY:
rtw_write32_clr(rtwdev, REG_LED_CFG, BIT_DPDT_SEL_EN);
rtw_write32_set(rtwdev, REG_LED_CFG, BIT_DPDT_WL_SEL);
rtw_write8_clr(rtwdev, REG_GNT_BT, BIT_PTA_SW_CTL);
rtw_write8(rtwdev, REG_RFE_CTRL8, DPDT_CTRL_PIN);
rtw_write32_mask(rtwdev, REG_RFE_CTRL8, 0 x30000000, 0 x1);
break ;
case COEX_SET_ANT_2G:
rtw_write32_clr(rtwdev, REG_LED_CFG, BIT_DPDT_SEL_EN);
rtw_write32_set(rtwdev, REG_LED_CFG, BIT_DPDT_WL_SEL);
rtw_write8_clr(rtwdev, REG_GNT_BT, BIT_PTA_SW_CTL);
rtw_write8(rtwdev, REG_RFE_CTRL8,
share_ant ? PTA_CTRL_PIN : DPDT_CTRL_PIN);
rtw_write32_mask(rtwdev, REG_RFE_CTRL8, 0 x30000000, 0 x1);
break ;
case COEX_SET_ANT_5G:
rtw_write32_clr(rtwdev, REG_LED_CFG, BIT_DPDT_SEL_EN);
rtw_write32_set(rtwdev, REG_LED_CFG, BIT_DPDT_WL_SEL);
rtw_write8_set(rtwdev, REG_GNT_BT, BIT_PTA_SW_CTL);
rtw_write8(rtwdev, REG_RFE_CTRL8, DPDT_CTRL_PIN);
rtw_write32_mask(rtwdev, REG_RFE_CTRL8, 0 x30000000,
share_ant ? 0 x2 : 0 x1);
break ;
case COEX_SET_ANT_WOFF:
rtw_write32_clr(rtwdev, REG_LED_CFG, BIT_DPDT_SEL_EN);
rtw_write32_clr(rtwdev, REG_LED_CFG, BIT_DPDT_WL_SEL);
rtw_write8_set(rtwdev, REG_GNT_BT, BIT_PTA_SW_CTL);
rtw_write8(rtwdev, REG_RFE_CTRL8, DPDT_CTRL_PIN);
rtw_write32_mask(rtwdev, REG_RFE_CTRL8, 0 x30000000,
share_ant ? 0 x2 : 0 x1);
break ;
default :
rtw_warn(rtwdev, "%s: not handling phase %d\n" ,
__func__, phase);
break ;
}
}
static void rtw8821a_coex_cfg_gnt_fix(struct rtw_dev *rtwdev)
{
}
static void rtw8821a_coex_cfg_gnt_debug(struct rtw_dev *rtwdev)
{
}
static void rtw8821a_coex_cfg_rfe_type(struct rtw_dev *rtwdev)
{
struct rtw_coex *coex = &rtwdev->coex;
struct rtw_coex_rfe *coex_rfe = &coex->rfe;
coex_rfe->ant_switch_exist = true ;
}
static void rtw8821a_coex_cfg_wl_tx_power(struct rtw_dev *rtwdev, u8 wl_pwr)
{
struct rtw_coex *coex = &rtwdev->coex;
struct rtw_coex_dm *coex_dm = &coex->dm;
struct rtw_efuse *efuse = &rtwdev->efuse;
bool share_ant = efuse->share_ant;
if (share_ant)
return ;
if (wl_pwr == coex_dm->cur_wl_pwr_lvl)
return ;
coex_dm->cur_wl_pwr_lvl = wl_pwr;
}
static void rtw8821a_coex_cfg_wl_rx_gain(struct rtw_dev *rtwdev, bool low_gain)
{
}
static const struct rtw_chip_ops rtw8821a_ops = {
.power_on = rtw88xxa_power_on,
.power_off = rtw8821a_power_off,
.phy_set_param = NULL,
.read_efuse = rtw88xxa_read_efuse,
.query_phy_status = rtw8821a_query_phy_status,
.set_channel = rtw88xxa_set_channel,
.mac_init = NULL,
.mac_postinit = NULL,
.read_rf = rtw88xxa_phy_read_rf,
.write_rf = rtw_phy_write_rf_reg_sipi,
.set_antenna = NULL,
.set_tx_power_index = rtw88xxa_set_tx_power_index,
.cfg_ldo25 = rtw8821a_cfg_ldo25,
.efuse_grant = rtw88xxa_efuse_grant,
.set_ampdu_factor = NULL,
.false_alarm_statistics = rtw88xxa_false_alarm_statistics,
.phy_calibration = rtw8821a_phy_calibration,
.cck_pd_set = rtw88xxa_phy_cck_pd_set,
.pwr_track = rtw8821a_pwr_track,
.config_bfee = NULL,
.set_gid_table = NULL,
.cfg_csi_rate = NULL,
.led_set = rtw8821a_led_set,
.fill_txdesc_checksum = rtw8821a_fill_txdesc_checksum,
.coex_set_init = rtw8821a_coex_cfg_init,
.coex_set_ant_switch = rtw8821a_coex_cfg_ant_switch,
.coex_set_gnt_fix = rtw8821a_coex_cfg_gnt_fix,
.coex_set_gnt_debug = rtw8821a_coex_cfg_gnt_debug,
.coex_set_rfe_type = rtw8821a_coex_cfg_rfe_type,
.coex_set_wl_tx_power = rtw8821a_coex_cfg_wl_tx_power,
.coex_set_wl_rx_gain = rtw8821a_coex_cfg_wl_rx_gain,
};
static const struct rtw_page_table page_table_8821a[] = {
/* hq_num, nq_num, lq_num, exq_num, gapq_num */
{0 , 0 , 0 , 0 , 0 }, /* SDIO */
{0 , 0 , 0 , 0 , 0 }, /* PCI */
{8 , 0 , 0 , 0 , 1 }, /* 2 bulk out endpoints */
{8 , 0 , 8 , 0 , 1 }, /* 3 bulk out endpoints */
{8 , 0 , 8 , 4 , 1 }, /* 4 bulk out endpoints */
};
static const struct rtw_rqpn rqpn_table_8821a[] = {
{RTW_DMA_MAPPING_NORMAL, RTW_DMA_MAPPING_NORMAL,
RTW_DMA_MAPPING_LOW, RTW_DMA_MAPPING_LOW,
RTW_DMA_MAPPING_EXTRA, RTW_DMA_MAPPING_HIGH},
{RTW_DMA_MAPPING_NORMAL, RTW_DMA_MAPPING_NORMAL,
RTW_DMA_MAPPING_LOW, RTW_DMA_MAPPING_LOW,
RTW_DMA_MAPPING_EXTRA, RTW_DMA_MAPPING_HIGH},
{RTW_DMA_MAPPING_HIGH, RTW_DMA_MAPPING_HIGH,
RTW_DMA_MAPPING_NORMAL, RTW_DMA_MAPPING_NORMAL,
RTW_DMA_MAPPING_HIGH, RTW_DMA_MAPPING_HIGH},
{RTW_DMA_MAPPING_HIGH, RTW_DMA_MAPPING_NORMAL,
RTW_DMA_MAPPING_LOW, RTW_DMA_MAPPING_LOW,
RTW_DMA_MAPPING_HIGH, RTW_DMA_MAPPING_HIGH},
{RTW_DMA_MAPPING_NORMAL, RTW_DMA_MAPPING_NORMAL,
RTW_DMA_MAPPING_LOW, RTW_DMA_MAPPING_LOW,
RTW_DMA_MAPPING_EXTRA, RTW_DMA_MAPPING_HIGH},
};
static const struct rtw_prioq_addrs prioq_addrs_8821a = {
.prio[RTW_DMA_MAPPING_EXTRA] = {
.rsvd = REG_RQPN_NPQ + 2 , .avail = REG_RQPN_NPQ + 3 ,
},
.prio[RTW_DMA_MAPPING_LOW] = {
.rsvd = REG_RQPN + 1 , .avail = REG_FIFOPAGE_CTRL_2 + 1 ,
},
.prio[RTW_DMA_MAPPING_NORMAL] = {
.rsvd = REG_RQPN_NPQ, .avail = REG_RQPN_NPQ + 1 ,
},
.prio[RTW_DMA_MAPPING_HIGH] = {
.rsvd = REG_RQPN, .avail = REG_FIFOPAGE_CTRL_2,
},
.wsize = false ,
};
static const struct rtw_hw_reg rtw8821a_dig[] = {
[0 ] = { .addr = REG_RXIGI_A, .mask = 0 x7f },
};
static const struct rtw_rfe_def rtw8821a_rfe_defs[] = {
[0 ] = { .phy_pg_tbl = &rtw8821a_bb_pg_tbl,
.txpwr_lmt_tbl = &rtw8821a_txpwr_lmt_tbl,
.pwr_track_tbl = &rtw8821a_rtw_pwr_track_tbl, },
};
/* TODO */
/* rssi in percentage % (dbm = % - 100) */
static const u8 wl_rssi_step_8821a[] = {101 , 45 , 101 , 40 };
static const u8 bt_rssi_step_8821a[] = {101 , 101 , 101 , 101 };
/* table_sant_8821a, table_nsant_8821a, tdma_sant_8821a, and tdma_nsant_8821a
* are copied from rtw8821c.c because the 8821au driver's tables are not
* compatible with the coex code in rtw88.
*
* tdma case 112 (A2DP) byte 0 had to be modified from 0x61 to 0x51,
* otherwise the firmware gets confused after pausing the music:
* rtw_8821au 1-2:1.2: [BTCoex], Bt_info[1], len=7, data=[81 00 0a 01 00 00]
* - 81 means PAN (personal area network) when it should be 4x (A2DP)
* The music is not smooth with the PAN algorithm.
*/
/* Shared-Antenna Coex Table */
static const struct coex_table_para table_sant_8821a[] = {
{0 x55555555, 0 x55555555}, /* case-0 */
{0 x55555555, 0 x55555555},
{0 x66555555, 0 x66555555},
{0 xaaaaaaaa, 0 xaaaaaaaa},
{0 x5a5a5a5a, 0 x5a5a5a5a},
{0 xfafafafa, 0 xfafafafa}, /* case-5 */
{0 x6a5a5555, 0 xaaaaaaaa},
{0 x6a5a56aa, 0 x6a5a56aa},
{0 x6a5a5a5a, 0 x6a5a5a5a},
{0 x66555555, 0 x5a5a5a5a},
{0 x66555555, 0 x6a5a5a5a}, /* case-10 */
{0 x66555555, 0 xaaaaaaaa},
{0 x66555555, 0 x6a5a5aaa},
{0 x66555555, 0 x6aaa6aaa},
{0 x66555555, 0 x6a5a5aaa},
{0 x66555555, 0 xaaaaaaaa}, /* case-15 */
{0 xffff55ff, 0 xfafafafa},
{0 xffff55ff, 0 x6afa5afa},
{0 xaaffffaa, 0 xfafafafa},
{0 xaa5555aa, 0 x5a5a5a5a},
{0 xaa5555aa, 0 x6a5a5a5a}, /* case-20 */
{0 xaa5555aa, 0 xaaaaaaaa},
{0 xffffffff, 0 x55555555},
{0 xffffffff, 0 x5a5a5a5a},
{0 xffffffff, 0 x5a5a5a5a},
{0 xffffffff, 0 x5a5a5aaa}, /* case-25 */
{0 x55555555, 0 x5a5a5a5a},
{0 x55555555, 0 xaaaaaaaa},
{0 x66555555, 0 x6a5a6a5a},
{0 x66556655, 0 x66556655},
{0 x66556aaa, 0 x6a5a6aaa}, /* case-30 */
{0 xffffffff, 0 x5aaa5aaa},
{0 x56555555, 0 x5a5a5aaa}
};
/* Non-Shared-Antenna Coex Table */
static const struct coex_table_para table_nsant_8821a[] = {
{0 xffffffff, 0 xffffffff}, /* case-100 */
{0 xffff55ff, 0 xfafafafa},
{0 x66555555, 0 x66555555},
{0 xaaaaaaaa, 0 xaaaaaaaa},
{0 x5a5a5a5a, 0 x5a5a5a5a},
{0 xffffffff, 0 xffffffff}, /* case-105 */
{0 x5afa5afa, 0 x5afa5afa},
{0 x55555555, 0 xfafafafa},
{0 x66555555, 0 xfafafafa},
{0 x66555555, 0 x5a5a5a5a},
{0 x66555555, 0 x6a5a5a5a}, /* case-110 */
{0 x66555555, 0 xaaaaaaaa},
{0 xffff55ff, 0 xfafafafa},
{0 xffff55ff, 0 x5afa5afa},
{0 xffff55ff, 0 xaaaaaaaa},
{0 xffff55ff, 0 xffff55ff}, /* case-115 */
{0 xaaffffaa, 0 x5afa5afa},
{0 xaaffffaa, 0 xaaaaaaaa},
{0 xffffffff, 0 xfafafafa},
{0 xffff55ff, 0 xfafafafa},
{0 xffffffff, 0 xaaaaaaaa}, /* case-120 */
{0 xffff55ff, 0 x5afa5afa},
{0 xffff55ff, 0 x5afa5afa},
{0 x55ff55ff, 0 x55ff55ff}
};
/* Shared-Antenna TDMA */
static const struct coex_tdma_para tdma_sant_8821a[] = {
{ {0 x00, 0 x00, 0 x00, 0 x00, 0 x00} }, /* case-0 */
{ {0 x61, 0 x45, 0 x03, 0 x11, 0 x11} }, /* case-1 */
{ {0 x61, 0 x3a, 0 x03, 0 x11, 0 x11} },
{ {0 x61, 0 x35, 0 x03, 0 x11, 0 x11} },
{ {0 x61, 0 x20, 0 x03, 0 x11, 0 x11} },
{ {0 x61, 0 x3a, 0 x03, 0 x11, 0 x11} }, /* case-5 */
{ {0 x61, 0 x45, 0 x03, 0 x11, 0 x10} },
{ {0 x61, 0 x35, 0 x03, 0 x11, 0 x10} },
{ {0 x61, 0 x30, 0 x03, 0 x11, 0 x10} },
{ {0 x61, 0 x20, 0 x03, 0 x11, 0 x10} },
{ {0 x61, 0 x10, 0 x03, 0 x11, 0 x10} }, /* case-10 */
{ {0 x61, 0 x08, 0 x03, 0 x11, 0 x15} },
{ {0 x61, 0 x08, 0 x03, 0 x10, 0 x14} },
{ {0 x51, 0 x08, 0 x03, 0 x10, 0 x54} },
{ {0 x51, 0 x08, 0 x03, 0 x10, 0 x55} },
{ {0 x51, 0 x08, 0 x07, 0 x10, 0 x54} }, /* case-15 */
{ {0 x51, 0 x45, 0 x03, 0 x10, 0 x50} },
{ {0 x51, 0 x3a, 0 x03, 0 x11, 0 x50} },
{ {0 x51, 0 x30, 0 x03, 0 x10, 0 x50} },
{ {0 x51, 0 x21, 0 x03, 0 x10, 0 x50} },
{ {0 x51, 0 x10, 0 x03, 0 x10, 0 x50} }, /* case-20 */
{ {0 x51, 0 x4a, 0 x03, 0 x10, 0 x50} },
{ {0 x51, 0 x08, 0 x03, 0 x30, 0 x54} },
{ {0 x55, 0 x08, 0 x03, 0 x10, 0 x54} },
{ {0 x65, 0 x10, 0 x03, 0 x11, 0 x10} },
{ {0 x51, 0 x10, 0 x03, 0 x10, 0 x51} }, /* case-25 */
{ {0 x51, 0 x21, 0 x03, 0 x10, 0 x50} },
{ {0 x61, 0 x08, 0 x03, 0 x11, 0 x11} }
};
/* Non-Shared-Antenna TDMA */
static const struct coex_tdma_para tdma_nsant_8821a[] = {
{ {0 x00, 0 x00, 0 x00, 0 x40, 0 x00} }, /* case-100 */
{ {0 x61, 0 x45, 0 x03, 0 x11, 0 x11} },
{ {0 x61, 0 x25, 0 x03, 0 x11, 0 x11} },
{ {0 x61, 0 x35, 0 x03, 0 x11, 0 x11} },
{ {0 x61, 0 x20, 0 x03, 0 x11, 0 x11} },
{ {0 x61, 0 x10, 0 x03, 0 x11, 0 x11} }, /* case-105 */
{ {0 x61, 0 x45, 0 x03, 0 x11, 0 x10} },
{ {0 x61, 0 x30, 0 x03, 0 x11, 0 x10} },
{ {0 x61, 0 x30, 0 x03, 0 x11, 0 x10} },
{ {0 x61, 0 x20, 0 x03, 0 x11, 0 x10} },
{ {0 x61, 0 x10, 0 x03, 0 x11, 0 x10} }, /* case-110 */
{ {0 x61, 0 x10, 0 x03, 0 x11, 0 x11} },
{ {0 x51, 0 x08, 0 x03, 0 x10, 0 x14} }, /* a2dp high rssi */
{ {0 x51, 0 x08, 0 x03, 0 x10, 0 x54} }, /* a2dp not high rssi */
{ {0 x51, 0 x08, 0 x03, 0 x10, 0 x55} },
{ {0 x51, 0 x08, 0 x07, 0 x10, 0 x54} }, /* case-115 */
{ {0 x51, 0 x45, 0 x03, 0 x10, 0 x50} },
{ {0 x51, 0 x3a, 0 x03, 0 x10, 0 x50} },
{ {0 x51, 0 x30, 0 x03, 0 x10, 0 x50} },
{ {0 x51, 0 x21, 0 x03, 0 x10, 0 x50} },
{ {0 x51, 0 x21, 0 x03, 0 x10, 0 x50} }, /* case-120 */
{ {0 x51, 0 x10, 0 x03, 0 x10, 0 x50} }
};
/* TODO */
static const struct coex_rf_para rf_para_tx_8821a[] = {
{0 , 0 , false , 7 }, /* for normal */
{0 , 20 , false , 7 }, /* for WL-CPT */
{8 , 17 , true , 4 },
{7 , 18 , true , 4 },
{6 , 19 , true , 4 },
{5 , 20 , true , 4 }
};
static const struct coex_rf_para rf_para_rx_8821a[] = {
{0 , 0 , false , 7 }, /* for normal */
{0 , 20 , false , 7 }, /* for WL-CPT */
{3 , 24 , true , 5 },
{2 , 26 , true , 5 },
{1 , 27 , true , 5 },
{0 , 28 , true , 5 }
};
static_assert(ARRAY_SIZE(rf_para_tx_8821a) == ARRAY_SIZE(rf_para_rx_8821a));
static const struct coex_5g_afh_map afh_5g_8821a[] = { {0 , 0 , 0 } };
static const struct rtw_reg_domain coex_info_hw_regs_8821a[] = {
{0 xCB0, MASKDWORD, RTW_REG_DOMAIN_MAC32},
{0 xCB4, MASKDWORD, RTW_REG_DOMAIN_MAC32},
{0 xCBA, MASKBYTE0, RTW_REG_DOMAIN_MAC8},
{0 , 0 , RTW_REG_DOMAIN_NL},
{0 x430, MASKDWORD, RTW_REG_DOMAIN_MAC32},
{0 x434, MASKDWORD, RTW_REG_DOMAIN_MAC32},
{0 x42a, MASKLWORD, RTW_REG_DOMAIN_MAC16},
{0 x426, MASKBYTE0, RTW_REG_DOMAIN_MAC8},
{0 x45e, BIT(3 ), RTW_REG_DOMAIN_MAC8},
{0 x454, MASKLWORD, RTW_REG_DOMAIN_MAC16},
{0 , 0 , RTW_REG_DOMAIN_NL},
{0 x4c, BIT(24 ) | BIT(23 ), RTW_REG_DOMAIN_MAC32},
{0 x64, BIT(0 ), RTW_REG_DOMAIN_MAC8},
{0 x4c6, BIT(4 ), RTW_REG_DOMAIN_MAC8},
{0 x40, BIT(5 ), RTW_REG_DOMAIN_MAC8},
{0 x1, RFREG_MASK, RTW_REG_DOMAIN_RF_A},
{0 , 0 , RTW_REG_DOMAIN_NL},
{0 x550, MASKDWORD, RTW_REG_DOMAIN_MAC32},
{0 x522, MASKBYTE0, RTW_REG_DOMAIN_MAC8},
{0 x953, BIT(1 ), RTW_REG_DOMAIN_MAC8},
{0 xc50, MASKBYTE0, RTW_REG_DOMAIN_MAC8},
{0 x60A, MASKBYTE0, RTW_REG_DOMAIN_MAC8},
};
const struct rtw_chip_info rtw8821a_hw_spec = {
.ops = &rtw8821a_ops,
.id = RTW_CHIP_TYPE_8821A,
.fw_name = "rtw88/rtw8821a_fw.bin" ,
.wlan_cpu = RTW_WCPU_8051,
.tx_pkt_desc_sz = 40 ,
.tx_buf_desc_sz = 16 ,
.rx_pkt_desc_sz = 24 ,
.rx_buf_desc_sz = 8 ,
.phy_efuse_size = 512 ,
.log_efuse_size = 512 ,
.ptct_efuse_size = 0 ,
.txff_size = 65536 ,
.rxff_size = 16128 ,
.rsvd_drv_pg_num = 8 ,
.txgi_factor = 1 ,
.is_pwr_by_rate_dec = true ,
.max_power_index = 0 x3f,
.csi_buf_pg_num = 0 ,
.band = RTW_BAND_2G | RTW_BAND_5G,
.page_size = 256 ,
.dig_min = 0 x20,
.ht_supported = true ,
.vht_supported = true ,
.lps_deep_mode_supported = 0 ,
.sys_func_en = 0 xFD,
.pwr_on_seq = card_enable_flow_8821a,
.pwr_off_seq = card_disable_flow_8821a,
.page_table = page_table_8821a,
.rqpn_table = rqpn_table_8821a,
.prioq_addrs = &prioq_addrs_8821a,
.intf_table = NULL,
.dig = rtw8821a_dig,
.rf_sipi_addr = {REG_LSSI_WRITE_A, REG_LSSI_WRITE_B},
.ltecoex_addr = NULL,
.mac_tbl = &rtw8821a_mac_tbl,
.agc_tbl = &rtw8821a_agc_tbl,
.bb_tbl = &rtw8821a_bb_tbl,
.rf_tbl = {&rtw8821a_rf_a_tbl},
.rfe_defs = rtw8821a_rfe_defs,
.rfe_defs_size = ARRAY_SIZE(rtw8821a_rfe_defs),
.rx_ldpc = false ,
.amsdu_in_ampdu = true ,
.hw_feature_report = false ,
.c2h_ra_report_size = 4 ,
.old_datarate_fb_limit = true ,
.usb_tx_agg_desc_num = 6 ,
.iqk_threshold = 8 ,
.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
.max_scan_ie_len = IEEE80211_MAX_DATA_LEN,
.coex_para_ver = 20190509 , /* glcoex_ver_date_8821a_1ant */
.bt_desired_ver = 0 x62, /* But for 2 ant it's 0x5c */
.scbd_support = false ,
.new_scbd10_def = false ,
.ble_hid_profile_support = false ,
.wl_mimo_ps_support = false ,
.pstdma_type = COEX_PSTDMA_FORCE_LPSOFF,
.bt_rssi_type = COEX_BTRSSI_RATIO,
.ant_isolation = 10 ,
.rssi_tolerance = 2 ,
.wl_rssi_step = wl_rssi_step_8821a,
.bt_rssi_step = bt_rssi_step_8821a,
.table_sant_num = ARRAY_SIZE(table_sant_8821a),
.table_sant = table_sant_8821a,
.table_nsant_num = ARRAY_SIZE(table_nsant_8821a),
.table_nsant = table_nsant_8821a,
.tdma_sant_num = ARRAY_SIZE(tdma_sant_8821a),
.tdma_sant = tdma_sant_8821a,
.tdma_nsant_num = ARRAY_SIZE(tdma_nsant_8821a),
.tdma_nsant = tdma_nsant_8821a,
.wl_rf_para_num = ARRAY_SIZE(rf_para_tx_8821a),
.wl_rf_para_tx = rf_para_tx_8821a,
.wl_rf_para_rx = rf_para_rx_8821a,
.bt_afh_span_bw20 = 0 x20,
.bt_afh_span_bw40 = 0 x30,
.afh_5g_num = ARRAY_SIZE(afh_5g_8821a),
.afh_5g = afh_5g_8821a,
.coex_info_hw_regs_num = ARRAY_SIZE(coex_info_hw_regs_8821a),
.coex_info_hw_regs = coex_info_hw_regs_8821a,
};
EXPORT_SYMBOL(rtw8821a_hw_spec);
MODULE_FIRMWARE("rtw88/rtw8821a_fw.bin" );
MODULE_AUTHOR("Realtek Corporation" );
MODULE_DESCRIPTION("Realtek 802.11ac wireless 8821a/8811a driver" );
MODULE_LICENSE("Dual BSD/GPL" );
Messung V0.5 in Prozent C=100 H=95 G=97
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet am 2026-06-07)
¤
*© Formatika GbR, Deutschland