wifi: rtw88: Add rtw8812a.{c,h}
authorBitterblue Smith <rtl8821cerfe2@gmail.com>
Wed, 30 Oct 2024 18:28:49 +0000 (20:28 +0200)
committerPing-Ke Shih <pkshih@realtek.com>
Wed, 6 Nov 2024 06:30:13 +0000 (14:30 +0800)
These contain code specific to RTL8812AU.

Signed-off-by: Bitterblue Smith <rtl8821cerfe2@gmail.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
Link: https://patch.msgid.link/a0057683-79eb-4ab2-8f74-11a3bc58adfb@gmail.com
drivers/net/wireless/realtek/rtw88/rtw8812a.c [new file with mode: 0644]
drivers/net/wireless/realtek/rtw88/rtw8812a.h [new file with mode: 0644]

diff --git a/drivers/net/wireless/realtek/rtw88/rtw8812a.c b/drivers/net/wireless/realtek/rtw88/rtw8812a.c
new file mode 100644 (file)
index 0000000..482edd3
--- /dev/null
@@ -0,0 +1,1102 @@
+// 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 "rtw8812a.h"
+#include "rtw8812a_table.h"
+#include "tx.h"
+
+static void rtw8812a_power_off(struct rtw_dev *rtwdev)
+{
+       rtw88xxa_power_off(rtwdev, enter_lps_flow_8812a);
+}
+
+static s8 rtw8812a_cck_rx_pwr(u8 lna_idx, u8 vga_idx)
+{
+       s8 rx_pwr_all = 0;
+
+       switch (lna_idx) {
+       case 7:
+               if (vga_idx <= 27)
+                       rx_pwr_all = -94 + 2 * (27 - vga_idx);
+               else
+                       rx_pwr_all = -94;
+               break;
+       case 6:
+               rx_pwr_all = -42 + 2 * (2 - vga_idx);
+               break;
+       case 5:
+               rx_pwr_all = -36 + 2 * (7 - vga_idx);
+               break;
+       case 4:
+               rx_pwr_all = -30 + 2 * (7 - vga_idx);
+               break;
+       case 3:
+               rx_pwr_all = -18 + 2 * (7 - vga_idx);
+               break;
+       case 2:
+               rx_pwr_all = 2 * (5 - vga_idx);
+               break;
+       case 1:
+               rx_pwr_all = 14 - 2 * vga_idx;
+               break;
+       case 0:
+               rx_pwr_all = 20 - 2 * vga_idx;
+               break;
+       default:
+               break;
+       }
+
+       return rx_pwr_all;
+}
+
+static void rtw8812a_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,
+                                 rtw8812a_cck_rx_pwr);
+
+       if (pkt_stat->rate >= DESC_RATE6M)
+               return;
+
+       if (rtwdev->hal.cck_high_power)
+               return;
+
+       if (pkt_stat->rssi >= 80)
+               pkt_stat->rssi = ((pkt_stat->rssi - 80) << 1) +
+                                ((pkt_stat->rssi - 80) >> 1) + 80;
+       else if (pkt_stat->rssi <= 78 && pkt_stat->rssi >= 20)
+               pkt_stat->rssi += 3;
+}
+
+static void rtw8812a_cfg_ldo25(struct rtw_dev *rtwdev, bool enable)
+{
+}
+
+static void rtw8812a_do_lck(struct rtw_dev *rtwdev)
+{
+       u32 cont_tx, lc_cal, i;
+
+       cont_tx = rtw_read32_mask(rtwdev, REG_SINGLE_TONE_CONT_TX, 0x70000);
+
+       lc_cal = rtw_read_rf(rtwdev, RF_PATH_A, RF_CFGCH, RFREG_MASK);
+
+       if (!cont_tx)
+               rtw_write8(rtwdev, REG_TXPAUSE, 0xff);
+
+       rtw_write_rf(rtwdev, RF_PATH_A, RF_LCK, BIT(14), 1);
+
+       rtw_write_rf(rtwdev, RF_PATH_A, RF_CFGCH, 0x08000, 1);
+
+       mdelay(150);
+
+       for (i = 0; i < 5; i++) {
+               if (rtw_read_rf(rtwdev, RF_PATH_A, RF_CFGCH, 0x08000) != 1)
+                       break;
+
+               mdelay(10);
+       }
+
+       if (i == 5)
+               rtw_dbg(rtwdev, RTW_DBG_RFK, "LCK timed out\n");
+
+       rtw_write_rf(rtwdev, RF_PATH_A, RF_CFGCH, RFREG_MASK, lc_cal);
+
+       rtw_write_rf(rtwdev, RF_PATH_A, RF_LCK, BIT(14), 0);
+
+       if (!cont_tx)
+               rtw_write8(rtwdev, REG_TXPAUSE, 0);
+
+       rtw_write_rf(rtwdev, RF_PATH_A, RF_CFGCH, RFREG_MASK, lc_cal);
+}
+
+static void rtw8812a_iqk_backup_rf(struct rtw_dev *rtwdev, u32 *rfa_backup,
+                                  u32 *rfb_backup, const u32 *backup_rf_reg,
+                                  u32 rf_num)
+{
+       u32 i;
+
+       /* [31] = 0 --> Page C */
+       rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0);
+
+       /* 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);
+               rfb_backup[i] = rtw_read_rf(rtwdev, RF_PATH_B,
+                                           backup_rf_reg[i], MASKDWORD);
+       }
+}
+
+static void rtw8812a_iqk_restore_rf(struct rtw_dev *rtwdev,
+                                   enum rtw_rf_path path,
+                                   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), 0x0);
+
+       for (i = 0; i < rf_reg_num; i++)
+               rtw_write_rf(rtwdev, path, backup_rf_reg[i],
+                            RFREG_MASK, RF_backup[i]);
+
+       rtw_write_rf(rtwdev, path, RF_LUTWE, RFREG_MASK, 0);
+}
+
+static void rtw8812a_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), 0x0);
+
+       /* 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), 0x1);
+
+       rtw_write32(rtwdev, REG_OFDM0_XA_TX_IQ_IMBALANCE, 0x0);
+       rtw_write32(rtwdev, REG_OFDM0_A_TX_AFE, 0x0);
+       rtw_write32(rtwdev, REG_OFDM0_XB_TX_IQ_IMBALANCE, 0x0);
+       rtw_write32(rtwdev, REG_TSSI_TRK_SW, 0x3c000000);
+       rtw_write32_mask(rtwdev, REG_LSSI_WRITE_A, BIT(7), 1);
+       rtw_write32_mask(rtwdev, REG_IQK_DPD_CFG, BIT(18), 1);
+       rtw_write32_mask(rtwdev, REG_IQK_DPD_CFG, BIT(29), 1);
+       rtw_write32_mask(rtwdev, REG_CFG_PMPD, BIT(29), 1);
+
+       rtw_write32(rtwdev, REG_TXTONEB, 0x0);
+       rtw_write32(rtwdev, REG_RXTONEB, 0x0);
+       rtw_write32(rtwdev, REG_TXPITMB, 0x0);
+       rtw_write32(rtwdev, REG_RXPITMB, 0x3c000000);
+       rtw_write32_mask(rtwdev, REG_LSSI_WRITE_B, BIT(7), 1);
+       rtw_write32_mask(rtwdev, REG_BPBDB, BIT(18), 1);
+       rtw_write32_mask(rtwdev, REG_BPBDB, BIT(29), 1);
+       rtw_write32_mask(rtwdev, REG_PHYTXONB, BIT(29), 1);
+}
+
+static void rtw8812a_iqk_rx_fill(struct rtw_dev *rtwdev, enum rtw_rf_path path,
+                                unsigned int rx_x, unsigned int rx_y)
+{
+       switch (path) {
+       case RF_PATH_A:
+               /* [31] = 0 --> Page C */
+               rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0);
+               if (rx_x >> 1 >= 0x112 ||
+                   (rx_y >> 1 >= 0x12 && rx_y >> 1 <= 0x3ee)) {
+                       rtw_write32_mask(rtwdev, REG_RX_IQC_AB_A,
+                                        0x000003ff, 0x100);
+                       rtw_write32_mask(rtwdev, REG_RX_IQC_AB_A,
+                                        0x03ff0000, 0);
+               } else {
+                       rtw_write32_mask(rtwdev, REG_RX_IQC_AB_A,
+                                        0x000003ff, rx_x >> 1);
+                       rtw_write32_mask(rtwdev, REG_RX_IQC_AB_A,
+                                        0x03ff0000, rx_y >> 1);
+               }
+               rtw_dbg(rtwdev, RTW_DBG_RFK,
+                       "rx_x = %x;;rx_y = %x ====>fill to IQC\n",
+                       rx_x >> 1 & 0x000003ff, rx_y >> 1 & 0x000003ff);
+               rtw_dbg(rtwdev, RTW_DBG_RFK, "0xc10 = %x ====>fill to IQC\n",
+                       rtw_read32(rtwdev, REG_RX_IQC_AB_A));
+               break;
+       case RF_PATH_B:
+               /* [31] = 0 --> Page C */
+               rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0);
+               if (rx_x >> 1 >= 0x112 ||
+                   (rx_y >> 1 >= 0x12 && rx_y >> 1 <= 0x3ee)) {
+                       rtw_write32_mask(rtwdev, REG_RX_IQC_AB_B,
+                                        0x000003ff, 0x100);
+                       rtw_write32_mask(rtwdev, REG_RX_IQC_AB_B,
+                                        0x03ff0000, 0);
+               } else {
+                       rtw_write32_mask(rtwdev, REG_RX_IQC_AB_B,
+                                        0x000003ff, rx_x >> 1);
+                       rtw_write32_mask(rtwdev, REG_RX_IQC_AB_B,
+                                        0x03ff0000, rx_y >> 1);
+               }
+               rtw_dbg(rtwdev, RTW_DBG_RFK,
+                       "rx_x = %x;;rx_y = %x ====>fill to IQC\n",
+                       rx_x >> 1 & 0x000003ff, rx_y >> 1 & 0x000003ff);
+               rtw_dbg(rtwdev, RTW_DBG_RFK, "0xe10 = %x====>fill to IQC\n",
+                       rtw_read32(rtwdev, REG_RX_IQC_AB_B));
+               break;
+       default:
+               break;
+       }
+}
+
+static void rtw8812a_iqk_tx_fill(struct rtw_dev *rtwdev, enum rtw_rf_path path,
+                                unsigned int tx_x, unsigned int tx_y)
+{
+       switch (path) {
+       case RF_PATH_A:
+               /* [31] = 1 --> Page C1 */
+               rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x1);
+               rtw_write32_mask(rtwdev, REG_PREDISTA, BIT(7), 0x1);
+               rtw_write32_mask(rtwdev, REG_IQK_DPD_CFG, BIT(18), 0x1);
+               rtw_write32_mask(rtwdev, REG_IQK_DPD_CFG, BIT(29), 0x1);
+               rtw_write32_mask(rtwdev, REG_CFG_PMPD, BIT(29), 0x1);
+               rtw_write32_mask(rtwdev, REG_IQC_Y, 0x000007ff, tx_y);
+               rtw_write32_mask(rtwdev, REG_IQC_X, 0x000007ff, tx_x);
+               rtw_dbg(rtwdev, RTW_DBG_RFK,
+                       "tx_x = %x;;tx_y = %x =====> fill to IQC\n",
+                       tx_x & 0x000007ff, tx_y & 0x000007ff);
+               rtw_dbg(rtwdev, RTW_DBG_RFK,
+                       "0xcd4 = %x;;0xccc = %x ====>fill to IQC\n",
+                       rtw_read32_mask(rtwdev, REG_IQC_X, 0x000007ff),
+                       rtw_read32_mask(rtwdev, REG_IQC_Y, 0x000007ff));
+               break;
+       case RF_PATH_B:
+               /* [31] = 1 --> Page C1 */
+               rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x1);
+               rtw_write32_mask(rtwdev, REG_PREDISTB, BIT(7), 0x1);
+               rtw_write32_mask(rtwdev, REG_BPBDB, BIT(18), 0x1);
+               rtw_write32_mask(rtwdev, REG_BPBDB, BIT(29), 0x1);
+               rtw_write32_mask(rtwdev, REG_PHYTXONB, BIT(29), 0x1);
+               rtw_write32_mask(rtwdev, REG_IQKYB, 0x000007ff, tx_y);
+               rtw_write32_mask(rtwdev, REG_IQKXB, 0x000007ff, tx_x);
+               rtw_dbg(rtwdev, RTW_DBG_RFK,
+                       "tx_x = %x;;tx_y = %x =====> fill to IQC\n",
+                       tx_x & 0x000007ff, tx_y & 0x000007ff);
+               rtw_dbg(rtwdev, RTW_DBG_RFK,
+                       "0xed4 = %x;;0xecc = %x ====>fill to IQC\n",
+                       rtw_read32_mask(rtwdev, REG_IQKXB, 0x000007ff),
+                       rtw_read32_mask(rtwdev, REG_IQKYB, 0x000007ff));
+               break;
+       default:
+               break;
+       }
+}
+
+static void rtw8812a_iqk(struct rtw_dev *rtwdev)
+{
+       int tx_x0_temp[10], tx_y0_temp[10], tx_x1_temp[10], tx_y1_temp[10];
+       int rx_x0_temp[10], rx_y0_temp[10], rx_x1_temp[10], rx_y1_temp[10];
+       bool iqk0_ready = false, tx0_finish = false, rx0_finish = false;
+       bool iqk1_ready = false, tx1_finish = false, rx1_finish = false;
+       u8 tx0_avg = 0, tx1_avg = 0, rx0_avg = 0, rx1_avg = 0;
+       int tx_x0 = 0, tx_y0 = 0, tx_x1 = 0, tx_y1 = 0;
+       int rx_x0 = 0, rx_y0 = 0, rx_x1 = 0, rx_y1 = 0;
+       struct rtw_efuse *efuse = &rtwdev->efuse;
+       bool tx0_fail = true, rx0_fail = true;
+       bool tx1_fail = true, rx1_fail = true;
+       u8 cal0_retry, cal1_retry;
+       u8 delay_count;
+
+       /* [31] = 0 --> Page C */
+       rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0);
+
+       /* ========path-A AFE all on======== */
+       /* Port 0 DAC/ADC on */
+       rtw_write32(rtwdev, REG_AFE_PWR1_A, 0x77777777);
+       rtw_write32(rtwdev, REG_AFE_PWR2_A, 0x77777777);
+
+       /* Port 1 DAC/ADC on */
+       rtw_write32(rtwdev, REG_AFE_PWR1_B, 0x77777777);
+       rtw_write32(rtwdev, REG_AFE_PWR2_B, 0x77777777);
+
+       rtw_write32(rtwdev, REG_RX_WAIT_CCA_TX_CCK_RFON_A, 0x19791979);
+       rtw_write32(rtwdev, REG_RX_WAIT_CCA_TX_CCK_RFON_B, 0x19791979);
+
+       /* hardware 3-wire off */
+       rtw_write32_mask(rtwdev, REG_3WIRE_SWA, 0xf, 0x4);
+       rtw_write32_mask(rtwdev, REG_3WIRE_SWB, 0xf, 0x4);
+
+       /* DAC/ADC sampling rate (160 MHz) */
+       rtw_write32_mask(rtwdev, REG_CK_MONHA, GENMASK(26, 24), 0x7);
+       rtw_write32_mask(rtwdev, REG_CK_MONHB, GENMASK(26, 24), 0x7);
+
+       /* [31] = 0 --> Page C */
+       rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0);
+       /* ====== path A TX IQK RF setting ====== */
+       rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWE, RFREG_MASK, 0x80002);
+       rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_ADDR, RFREG_MASK, 0x20000);
+       rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_DATA0, RFREG_MASK, 0x3fffd);
+       rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_DATA1, RFREG_MASK, 0xfe83f);
+       rtw_write_rf(rtwdev, RF_PATH_A, RF_TXA_PREPAD, RFREG_MASK, 0x931d5);
+       rtw_write_rf(rtwdev, RF_PATH_A, RF_RXBB2, RFREG_MASK, 0x8a001);
+
+       /* ====== path B TX IQK RF setting ====== */
+       rtw_write_rf(rtwdev, RF_PATH_B, RF_LUTWE, RFREG_MASK, 0x80002);
+       rtw_write_rf(rtwdev, RF_PATH_B, RF_MODE_TABLE_ADDR, RFREG_MASK, 0x20000);
+       rtw_write_rf(rtwdev, RF_PATH_B, RF_MODE_TABLE_DATA0, RFREG_MASK, 0x3fffd);
+       rtw_write_rf(rtwdev, RF_PATH_B, RF_MODE_TABLE_DATA1, RFREG_MASK, 0xfe83f);
+       rtw_write_rf(rtwdev, RF_PATH_B, RF_TXA_PREPAD, RFREG_MASK, 0x931d5);
+       rtw_write_rf(rtwdev, RF_PATH_B, RF_RXBB2, RFREG_MASK, 0x8a001);
+
+       rtw_write32(rtwdev, REG_DAC_RSTB, 0x00008000);
+       rtw_write32_mask(rtwdev, REG_TXAGCIDX, BIT(0), 0x1);
+       rtw_write32_mask(rtwdev, REG_INIDLYB, BIT(0), 0x1);
+       rtw_write32(rtwdev, REG_IQK_COM00, 0x29002000); /* TX (X,Y) */
+       rtw_write32(rtwdev, REG_IQK_COM32, 0xa9002000); /* RX (X,Y) */
+       rtw_write32(rtwdev, REG_IQK_COM96, 0x00462910); /* [0]:AGC_en, [15]:idac_K_Mask */
+       /* [31] = 1 --> Page C1 */
+       rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x1);
+
+       if (efuse->ext_pa_5g) {
+               if (efuse->rfe_option == 1) {
+                       rtw_write32(rtwdev, REG_OFDM0_XB_TX_IQ_IMBALANCE, 0x821403e3);
+                       rtw_write32(rtwdev, REG_TXPITMB, 0x821403e3);
+               } else {
+                       rtw_write32(rtwdev, REG_OFDM0_XB_TX_IQ_IMBALANCE, 0x821403f7);
+                       rtw_write32(rtwdev, REG_TXPITMB, 0x821403f7);
+               }
+       } else {
+               rtw_write32(rtwdev, REG_OFDM0_XB_TX_IQ_IMBALANCE, 0x821403f1);
+               rtw_write32(rtwdev, REG_TXPITMB, 0x821403f1);
+       }
+
+       if (rtwdev->hal.current_band_type == RTW_BAND_5G) {
+               rtw_write32(rtwdev, REG_TSSI_TRK_SW, 0x68163e96);
+               rtw_write32(rtwdev, REG_RXPITMB, 0x68163e96);
+       } else {
+               rtw_write32(rtwdev, REG_TSSI_TRK_SW, 0x28163e96);
+               rtw_write32(rtwdev, REG_RXPITMB, 0x28163e96);
+
+               if (efuse->rfe_option == 3) {
+                       if (efuse->ext_pa_2g)
+                               rtw_write32(rtwdev, REG_OFDM0_XB_TX_IQ_IMBALANCE,
+                                           0x821403e3);
+                       else
+                               rtw_write32(rtwdev, REG_OFDM0_XB_TX_IQ_IMBALANCE,
+                                           0x821403f7);
+               }
+       }
+
+       /* TX_Tone_idx[9:0], TxK_Mask[29] TX_Tone = 16 */
+       rtw_write32(rtwdev, REG_OFDM0_XA_TX_IQ_IMBALANCE, 0x18008c10);
+       /* RX_Tone_idx[9:0], RxK_Mask[29] */
+       rtw_write32(rtwdev, REG_OFDM0_A_TX_AFE, 0x38008c10);
+       rtw_write32(rtwdev, REG_INTPO_SETA, 0x00000000);
+       /* TX_Tone_idx[9:0], TxK_Mask[29] TX_Tone = 16 */
+       rtw_write32(rtwdev, REG_TXTONEB, 0x18008c10);
+       /* RX_Tone_idx[9:0], RxK_Mask[29] */
+       rtw_write32(rtwdev, REG_RXTONEB, 0x38008c10);
+       rtw_write32(rtwdev, REG_INTPO_SETB, 0x00000000);
+
+       cal0_retry = 0;
+       cal1_retry = 0;
+       while (1) {
+               /* one shot */
+               rtw_write32(rtwdev, REG_RFECTL_A, 0x00100000);
+               rtw_write32(rtwdev, REG_RFECTL_B, 0x00100000);
+               rtw_write32(rtwdev, REG_IQK_COM64, 0xfa000000);
+               rtw_write32(rtwdev, REG_IQK_COM64, 0xf8000000);
+
+               mdelay(10);
+
+               rtw_write32(rtwdev, REG_RFECTL_A, 0x00000000);
+               rtw_write32(rtwdev, REG_RFECTL_B, 0x00000000);
+
+               for (delay_count = 0; delay_count < 20; delay_count++) {
+                       if (!tx0_finish)
+                               iqk0_ready = rtw_read32_mask(rtwdev,
+                                                            REG_IQKA_END,
+                                                            BIT(10));
+                       if (!tx1_finish)
+                               iqk1_ready = rtw_read32_mask(rtwdev,
+                                                            REG_IQKB_END,
+                                                            BIT(10));
+                       if (iqk0_ready && iqk1_ready)
+                               break;
+
+                       mdelay(1);
+               }
+
+               rtw_dbg(rtwdev, RTW_DBG_RFK, "TX delay_count = %d\n",
+                       delay_count);
+
+               if (delay_count < 20) { /* If 20ms No Result, then cal_retry++ */
+                       /* ============TXIQK Check============== */
+                       tx0_fail = rtw_read32_mask(rtwdev, REG_IQKA_END, BIT(12));
+                       tx1_fail = rtw_read32_mask(rtwdev, REG_IQKB_END, BIT(12));
+
+                       if (!(tx0_fail || tx0_finish)) {
+                               rtw_write32(rtwdev, REG_RFECTL_A, 0x02000000);
+                               tx_x0_temp[tx0_avg] = rtw_read32_mask(rtwdev,
+                                                                     REG_IQKA_END,
+                                                                     0x07ff0000);
+                               rtw_write32(rtwdev, REG_RFECTL_A, 0x04000000);
+                               tx_y0_temp[tx0_avg] = rtw_read32_mask(rtwdev,
+                                                                     REG_IQKA_END,
+                                                                     0x07ff0000);
+
+                               rtw_dbg(rtwdev, RTW_DBG_RFK,
+                                       "tx_x0[%d] = %x ;; tx_y0[%d] = %x\n",
+                                       tx0_avg, tx_x0_temp[tx0_avg],
+                                       tx0_avg, tx_y0_temp[tx0_avg]);
+
+                               tx_x0_temp[tx0_avg] <<= 21;
+                               tx_y0_temp[tx0_avg] <<= 21;
+
+                               tx0_avg++;
+                       } else {
+                               cal0_retry++;
+                               if (cal0_retry == 10)
+                                       break;
+                       }
+
+                       if (!(tx1_fail || tx1_finish)) {
+                               rtw_write32(rtwdev, REG_RFECTL_B, 0x02000000);
+                               tx_x1_temp[tx1_avg] = rtw_read32_mask(rtwdev,
+                                                                     REG_IQKB_END,
+                                                                     0x07ff0000);
+                               rtw_write32(rtwdev, REG_RFECTL_B, 0x04000000);
+                               tx_y1_temp[tx1_avg] = rtw_read32_mask(rtwdev,
+                                                                     REG_IQKB_END,
+                                                                     0x07ff0000);
+
+                               rtw_dbg(rtwdev, RTW_DBG_RFK,
+                                       "tx_x1[%d] = %x ;; tx_y1[%d] = %x\n",
+                                       tx1_avg, tx_x1_temp[tx1_avg],
+                                       tx1_avg, tx_y1_temp[tx1_avg]);
+
+                               tx_x1_temp[tx1_avg] <<= 21;
+                               tx_y1_temp[tx1_avg] <<= 21;
+
+                               tx1_avg++;
+                       } else {
+                               cal1_retry++;
+                               if (cal1_retry == 10)
+                                       break;
+                       }
+               } else {
+                       cal0_retry++;
+                       cal1_retry++;
+
+                       rtw_dbg(rtwdev, RTW_DBG_RFK,
+                               "delay 20ms TX IQK Not Ready!!!!!\n");
+
+                       if (cal0_retry == 10)
+                               break;
+               }
+
+               if (tx0_avg >= 2)
+                       tx0_finish = rtw88xxa_iqk_finish(tx0_avg, 4,
+                                                        tx_x0_temp, tx_y0_temp, &tx_x0, &tx_y0,
+                                                        false, false);
+
+               if (tx1_avg >= 2)
+                       tx1_finish = rtw88xxa_iqk_finish(tx1_avg, 4,
+                                                        tx_x1_temp, tx_y1_temp, &tx_x1, &tx_y1,
+                                                        false, false);
+
+               rtw_dbg(rtwdev, RTW_DBG_RFK,
+                       "tx0_average = %d, tx1_average = %d\n",
+                       tx0_avg, tx1_avg);
+               rtw_dbg(rtwdev, RTW_DBG_RFK,
+                       "tx0_finish = %d, tx1_finish = %d\n",
+                       tx0_finish, tx1_finish);
+
+               if (tx0_finish && tx1_finish)
+                       break;
+
+               if ((cal0_retry + tx0_avg) >= 10 ||
+                   (cal1_retry + tx1_avg) >= 10)
+                       break;
+       }
+
+       rtw_dbg(rtwdev, RTW_DBG_RFK, "TXA_cal_retry = %d\n", cal0_retry);
+       rtw_dbg(rtwdev, RTW_DBG_RFK, "TXB_cal_retry = %d\n", cal1_retry);
+
+       /* [31] = 0 --> Page C */
+       rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0);
+       /* Load LOK */
+       rtw_write_rf(rtwdev, RF_PATH_A, RF_TXMOD, 0x7fe00,
+                    rtw_read_rf(rtwdev, RF_PATH_A, RF_DTXLOK, 0xffc00));
+       rtw_write_rf(rtwdev, RF_PATH_B, RF_TXMOD, 0x7fe00,
+                    rtw_read_rf(rtwdev, RF_PATH_B, RF_DTXLOK, 0xffc00));
+       /* [31] = 1 --> Page C1 */
+       rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x1);
+
+       /* [31] = 0 --> Page C */
+       rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0);
+       if (tx0_finish) {
+               /* ====== path A RX IQK RF setting====== */
+               rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWE, RFREG_MASK, 0x80000);
+               rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_ADDR, RFREG_MASK,
+                            0x30000);
+               rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_DATA0, RFREG_MASK,
+                            0x3f7ff);
+               rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_DATA1, RFREG_MASK,
+                            0xfe7bf);
+               rtw_write_rf(rtwdev, RF_PATH_A, RF_RXBB2, RFREG_MASK, 0x88001);
+               rtw_write_rf(rtwdev, RF_PATH_A, RF_TXA_PREPAD, RFREG_MASK, 0x931d1);
+               rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWE, RFREG_MASK, 0x00000);
+       }
+       if (tx1_finish) {
+               /* ====== path B RX IQK RF setting====== */
+               rtw_write_rf(rtwdev, RF_PATH_B, RF_LUTWE, RFREG_MASK, 0x80000);
+               rtw_write_rf(rtwdev, RF_PATH_B, RF_MODE_TABLE_ADDR, RFREG_MASK,
+                            0x30000);
+               rtw_write_rf(rtwdev, RF_PATH_B, RF_MODE_TABLE_DATA0, RFREG_MASK,
+                            0x3f7ff);
+               rtw_write_rf(rtwdev, RF_PATH_B, RF_MODE_TABLE_DATA1, RFREG_MASK,
+                            0xfe7bf);
+               rtw_write_rf(rtwdev, RF_PATH_B, RF_RXBB2, RFREG_MASK, 0x88001);
+               rtw_write_rf(rtwdev, RF_PATH_B, RF_TXA_PREPAD, RFREG_MASK, 0x931d1);
+               rtw_write_rf(rtwdev, RF_PATH_B, RF_LUTWE, RFREG_MASK, 0x00000);
+       }
+
+       rtw_write32_mask(rtwdev, REG_IQK_COM00, BIT(31), 0x1);
+       rtw_write32_mask(rtwdev, REG_IQK_COM00, BIT(31), 0x0);
+       rtw_write32(rtwdev, REG_DAC_RSTB, 0x00008000);
+
+       if (rtwdev->hci.type == RTW_HCI_TYPE_PCIE)
+               rtw_write32(rtwdev, REG_IQK_COM96, 0x0046a911);
+       else
+               rtw_write32(rtwdev, REG_IQK_COM96, 0x0046a890);
+
+       if (efuse->rfe_option == 1) {
+               rtw_write32(rtwdev, REG_RFE_PINMUX_A, 0x77777717);
+               rtw_write32(rtwdev, REG_RFE_INV_A, 0x00000077);
+               rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0x77777717);
+               rtw_write32(rtwdev, REG_RFE_INV_B, 0x00000077);
+       } else {
+               rtw_write32(rtwdev, REG_RFE_PINMUX_A, 0x77777717);
+               rtw_write32(rtwdev, REG_RFE_INV_A, 0x02000077);
+               rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0x77777717);
+               rtw_write32(rtwdev, REG_RFE_INV_B, 0x02000077);
+       }
+
+       /* [31] = 1 --> Page C1 */
+       rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x1);
+
+       if (tx0_finish) {
+               /* TX_Tone_idx[9:0], TxK_Mask[29] TX_Tone = 16 */
+               rtw_write32(rtwdev, REG_OFDM0_XA_TX_IQ_IMBALANCE, 0x38008c10);
+               /* RX_Tone_idx[9:0], RxK_Mask[29] */
+               rtw_write32(rtwdev, REG_OFDM0_A_TX_AFE, 0x18008c10);
+               rtw_write32(rtwdev, REG_OFDM0_XB_TX_IQ_IMBALANCE, 0x82140119);
+       }
+       if (tx1_finish) {
+               /* TX_Tone_idx[9:0], TxK_Mask[29] TX_Tone = 16 */
+               rtw_write32(rtwdev, REG_TXTONEB, 0x38008c10);
+               /* RX_Tone_idx[9:0], RxK_Mask[29] */
+               rtw_write32(rtwdev, REG_RXTONEB, 0x18008c10);
+               rtw_write32(rtwdev, REG_TXPITMB, 0x82140119);
+       }
+
+       cal0_retry = 0;
+       cal1_retry = 0;
+       while (1) {
+               /* one shot */
+               /* [31] = 0 --> Page C */
+               rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0);
+
+               if (tx0_finish) {
+                       rtw_write32_mask(rtwdev, REG_IQK_COM00, 0x03FF8000,
+                                        tx_x0 & 0x000007ff);
+                       rtw_write32_mask(rtwdev, REG_IQK_COM00, 0x000007FF,
+                                        tx_y0 & 0x000007ff);
+                       /* [31] = 1 --> Page C1 */
+                       rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x1);
+                       if (efuse->rfe_option == 1)
+                               rtw_write32(rtwdev, REG_TSSI_TRK_SW, 0x28161500);
+                       else
+                               rtw_write32(rtwdev, REG_TSSI_TRK_SW, 0x28160cc0);
+                       rtw_write32(rtwdev, REG_RFECTL_A, 0x00300000);
+                       rtw_write32(rtwdev, REG_RFECTL_A, 0x00100000);
+                       mdelay(5);
+                       rtw_write32(rtwdev, REG_TSSI_TRK_SW, 0x3c000000);
+                       rtw_write32(rtwdev, REG_RFECTL_A, 0x00000000);
+               }
+
+               if (tx1_finish) {
+                       /* [31] = 0 --> Page C */
+                       rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0);
+                       rtw_write32_mask(rtwdev, REG_IQK_COM00, 0x03FF8000,
+                                        tx_x1 & 0x000007ff);
+                       rtw_write32_mask(rtwdev, REG_IQK_COM00, 0x000007FF,
+                                        tx_y1 & 0x000007ff);
+                       /* [31] = 1 --> Page C1 */
+                       rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x1);
+                       if (efuse->rfe_option == 1)
+                               rtw_write32(rtwdev, REG_RXPITMB, 0x28161500);
+                       else
+                               rtw_write32(rtwdev, REG_RXPITMB, 0x28160ca0);
+                       rtw_write32(rtwdev, REG_RFECTL_B, 0x00300000);
+                       rtw_write32(rtwdev, REG_RFECTL_B, 0x00100000);
+                       mdelay(5);
+                       rtw_write32(rtwdev, REG_RXPITMB, 0x3c000000);
+                       rtw_write32(rtwdev, REG_RFECTL_B, 0x00000000);
+               }
+
+               for (delay_count = 0; delay_count < 20; delay_count++) {
+                       if (!rx0_finish && tx0_finish)
+                               iqk0_ready = rtw_read32_mask(rtwdev,
+                                                            REG_IQKA_END,
+                                                            BIT(10));
+                       if (!rx1_finish && tx1_finish)
+                               iqk1_ready = rtw_read32_mask(rtwdev,
+                                                            REG_IQKB_END,
+                                                            BIT(10));
+                       if (iqk0_ready && iqk1_ready)
+                               break;
+
+                       mdelay(1);
+               }
+
+               rtw_dbg(rtwdev, RTW_DBG_RFK, "RX delay_count = %d\n",
+                       delay_count);
+
+               if (delay_count < 20) { /* If 20ms No Result, then cal_retry++ */
+                       /* ============RXIQK Check============== */
+                       rx0_fail = rtw_read32_mask(rtwdev, REG_IQKA_END, BIT(11));
+                       rx1_fail = rtw_read32_mask(rtwdev, REG_IQKB_END, BIT(11));
+
+                       if (!(rx0_fail || rx0_finish) && tx0_finish) {
+                               rtw_write32(rtwdev, REG_RFECTL_A, 0x06000000);
+                               rx_x0_temp[rx0_avg] = rtw_read32_mask(rtwdev,
+                                                                     REG_IQKA_END,
+                                                                     0x07ff0000);
+                               rtw_write32(rtwdev, REG_RFECTL_A, 0x08000000);
+                               rx_y0_temp[rx0_avg] = rtw_read32_mask(rtwdev,
+                                                                     REG_IQKA_END,
+                                                                     0x07ff0000);
+
+                               rtw_dbg(rtwdev, RTW_DBG_RFK,
+                                       "rx_x0[%d] = %x ;; rx_y0[%d] = %x\n",
+                                       rx0_avg, rx_x0_temp[rx0_avg],
+                                       rx0_avg, rx_y0_temp[rx0_avg]);
+
+                               rx_x0_temp[rx0_avg] <<= 21;
+                               rx_y0_temp[rx0_avg] <<= 21;
+
+                               rx0_avg++;
+                       } else {
+                               rtw_dbg(rtwdev, RTW_DBG_RFK,
+                                       "1. RXA_cal_retry = %d\n", cal0_retry);
+
+                               cal0_retry++;
+                               if (cal0_retry == 10)
+                                       break;
+                       }
+
+                       if (!(rx1_fail || rx1_finish) && tx1_finish) {
+                               rtw_write32(rtwdev, REG_RFECTL_B, 0x06000000);
+                               rx_x1_temp[rx1_avg] = rtw_read32_mask(rtwdev,
+                                                                     REG_IQKB_END,
+                                                                     0x07ff0000);
+                               rtw_write32(rtwdev, REG_RFECTL_B, 0x08000000);
+                               rx_y1_temp[rx1_avg] = rtw_read32_mask(rtwdev,
+                                                                     REG_IQKB_END,
+                                                                     0x07ff0000);
+
+                               rtw_dbg(rtwdev, RTW_DBG_RFK,
+                                       "rx_x1[%d] = %x ;; rx_y1[%d] = %x\n",
+                                       rx1_avg, rx_x1_temp[rx1_avg],
+                                       rx1_avg, rx_y1_temp[rx1_avg]);
+
+                               rx_x1_temp[rx1_avg] <<= 21;
+                               rx_y1_temp[rx1_avg] <<= 21;
+
+                               rx1_avg++;
+                       } else {
+                               cal1_retry++;
+                               if (cal1_retry == 10)
+                                       break;
+                       }
+               } else {
+                       rtw_dbg(rtwdev, RTW_DBG_RFK,
+                               "2. RXA_cal_retry = %d\n", cal0_retry);
+
+                       cal0_retry++;
+                       cal1_retry++;
+
+                       rtw_dbg(rtwdev, RTW_DBG_RFK,
+                               "delay 20ms RX IQK Not Ready!!!!!\n");
+
+                       if (cal0_retry == 10)
+                               break;
+               }
+
+               rtw_dbg(rtwdev, RTW_DBG_RFK, "3. RXA_cal_retry = %d\n",
+                       cal0_retry);
+
+               if (rx0_avg >= 2)
+                       rx0_finish = rtw88xxa_iqk_finish(rx0_avg, 4,
+                                                        rx_x0_temp, rx_y0_temp,
+                                                        &rx_x0, &rx_y0,
+                                                        true, false);
+
+               if (rx1_avg >= 2)
+                       rx1_finish = rtw88xxa_iqk_finish(rx1_avg, 4,
+                                                        rx_x1_temp, rx_y1_temp,
+                                                        &rx_x1, &rx_y1,
+                                                        true, false);
+
+               rtw_dbg(rtwdev, RTW_DBG_RFK,
+                       "rx0_average = %d, rx1_average = %d\n",
+                       rx0_avg, rx1_avg);
+               rtw_dbg(rtwdev, RTW_DBG_RFK,
+                       "rx0_finish = %d, rx1_finish = %d\n",
+                       rx0_finish, rx1_finish);
+
+               if ((rx0_finish || !tx0_finish) && (rx1_finish || !tx1_finish))
+                       break;
+
+               if ((cal0_retry + rx0_avg) >= 10 ||
+                   (cal1_retry + rx1_avg) >= 10 ||
+                   rx0_avg == 3 || rx1_avg == 3)
+                       break;
+       }
+
+       rtw_dbg(rtwdev, RTW_DBG_RFK, "RXA_cal_retry = %d\n", cal0_retry);
+       rtw_dbg(rtwdev, RTW_DBG_RFK, "RXB_cal_retry = %d\n", cal1_retry);
+
+       /* FillIQK Result */
+       rtw_dbg(rtwdev, RTW_DBG_RFK, "========Path_A =======\n");
+
+       if (tx0_finish)
+               rtw8812a_iqk_tx_fill(rtwdev, RF_PATH_A, tx_x0, tx_y0);
+       else
+               rtw8812a_iqk_tx_fill(rtwdev, RF_PATH_A, 0x200, 0x0);
+
+       if (rx0_finish)
+               rtw8812a_iqk_rx_fill(rtwdev, RF_PATH_A, rx_x0, rx_y0);
+       else
+               rtw8812a_iqk_rx_fill(rtwdev, RF_PATH_A, 0x200, 0x0);
+
+       rtw_dbg(rtwdev, RTW_DBG_RFK, "========Path_B =======\n");
+
+       if (tx1_finish)
+               rtw8812a_iqk_tx_fill(rtwdev, RF_PATH_B, tx_x1, tx_y1);
+       else
+               rtw8812a_iqk_tx_fill(rtwdev, RF_PATH_B, 0x200, 0x0);
+
+       if (rx1_finish)
+               rtw8812a_iqk_rx_fill(rtwdev, RF_PATH_B, rx_x1, rx_y1);
+       else
+               rtw8812a_iqk_rx_fill(rtwdev, RF_PATH_B, 0x200, 0x0);
+}
+
+#define MACBB_REG_NUM_8812A 9
+#define AFE_REG_NUM_8812A 12
+#define RF_REG_NUM_8812A 3
+
+static void rtw8812a_do_iqk(struct rtw_dev *rtwdev)
+{
+       static const u32 backup_macbb_reg[MACBB_REG_NUM_8812A] = {
+               0x520, 0x550, 0x808, 0xa04, 0x90c, 0xc00, 0xe00, 0x838, 0x82c
+       };
+       static const u32 backup_afe_reg[AFE_REG_NUM_8812A] = {
+               0xc5c, 0xc60, 0xc64, 0xc68, 0xcb0, 0xcb4,
+               0xe5c, 0xe60, 0xe64, 0xe68, 0xeb0, 0xeb4
+       };
+       static const u32 backup_rf_reg[RF_REG_NUM_8812A] = {
+               0x65, 0x8f, 0x0
+       };
+       u32 macbb_backup[MACBB_REG_NUM_8812A] = {};
+       u32 afe_backup[AFE_REG_NUM_8812A] = {};
+       u32 rfa_backup[RF_REG_NUM_8812A] = {};
+       u32 rfb_backup[RF_REG_NUM_8812A] = {};
+       u32 reg_cb8, reg_eb8;
+
+       rtw88xxa_iqk_backup_mac_bb(rtwdev, macbb_backup,
+                                  backup_macbb_reg, MACBB_REG_NUM_8812A);
+
+       rtw_write32_set(rtwdev, REG_CCASEL, BIT(31));
+       reg_cb8 = rtw_read32(rtwdev, REG_RFECTL_A);
+       reg_eb8 = rtw_read32(rtwdev, REG_RFECTL_B);
+       rtw_write32_clr(rtwdev, REG_CCASEL, BIT(31));
+
+       rtw88xxa_iqk_backup_afe(rtwdev, afe_backup,
+                               backup_afe_reg, AFE_REG_NUM_8812A);
+       rtw8812a_iqk_backup_rf(rtwdev, rfa_backup, rfb_backup,
+                              backup_rf_reg, RF_REG_NUM_8812A);
+
+       rtw88xxa_iqk_configure_mac(rtwdev);
+
+       rtw8812a_iqk(rtwdev);
+
+       rtw8812a_iqk_restore_rf(rtwdev, RF_PATH_A, backup_rf_reg,
+                               rfa_backup, RF_REG_NUM_8812A);
+       rtw8812a_iqk_restore_rf(rtwdev, RF_PATH_B, backup_rf_reg,
+                               rfb_backup, RF_REG_NUM_8812A);
+
+       rtw8812a_iqk_restore_afe(rtwdev, afe_backup,
+                                backup_afe_reg, AFE_REG_NUM_8812A);
+
+       rtw_write32_set(rtwdev, REG_CCASEL, BIT(31));
+       rtw_write32(rtwdev, REG_RFECTL_A, reg_cb8);
+       rtw_write32(rtwdev, REG_RFECTL_B, reg_eb8);
+       rtw_write32_clr(rtwdev, REG_CCASEL, BIT(31));
+
+       rtw88xxa_iqk_restore_mac_bb(rtwdev, macbb_backup,
+                                   backup_macbb_reg, MACBB_REG_NUM_8812A);
+}
+
+static void rtw8812a_phy_calibration(struct rtw_dev *rtwdev)
+{
+       u8 channel = rtwdev->hal.current_channel;
+
+       rtw8812a_do_iqk(rtwdev);
+
+       /* The official driver wants to do this after connecting
+        * but before first writing a new igi (phydm_get_new_igi).
+        * Here seems close enough.
+        */
+       if (channel >= 36 && channel <= 64)
+               rtw_load_table(rtwdev, &rtw8812a_agc_diff_lb_tbl);
+       else if (channel >= 100)
+               rtw_load_table(rtwdev, &rtw8812a_agc_diff_hb_tbl);
+}
+
+static void rtw8812a_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), 0x03);
+               dm_info->pwr_trk_triggered = true;
+               return;
+       }
+
+       rtw88xxa_phy_pwrtrack(rtwdev, rtw8812a_do_lck, rtw8812a_do_iqk);
+       dm_info->pwr_trk_triggered = false;
+}
+
+static void rtw8812a_fill_txdesc_checksum(struct rtw_dev *rtwdev,
+                                         struct rtw_tx_pkt_info *pkt_info,
+                                         u8 *txdesc)
+{
+       fill_txdesc_checksum_common(txdesc, 16);
+}
+
+static void rtw8812a_coex_cfg_init(struct rtw_dev *rtwdev)
+{
+}
+
+static void rtw8812a_coex_cfg_gnt_fix(struct rtw_dev *rtwdev)
+{
+}
+
+static void rtw8821a_coex_cfg_rfe_type(struct rtw_dev *rtwdev)
+{
+}
+
+static void rtw8821a_coex_cfg_wl_tx_power(struct rtw_dev *rtwdev, u8 wl_pwr)
+{
+}
+
+static void rtw8821a_coex_cfg_wl_rx_gain(struct rtw_dev *rtwdev, bool low_gain)
+{
+}
+
+static const struct rtw_chip_ops rtw8812a_ops = {
+       .power_on               = rtw88xxa_power_on,
+       .power_off              = rtw8812a_power_off,
+       .phy_set_param          = NULL,
+       .read_efuse             = rtw88xxa_read_efuse,
+       .query_phy_status       = rtw8812a_query_phy_status,
+       .set_channel            = rtw88xxa_set_channel,
+       .mac_init               = 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              = rtw8812a_cfg_ldo25,
+       .efuse_grant            = rtw88xxa_efuse_grant,
+       .false_alarm_statistics = rtw88xxa_false_alarm_statistics,
+       .phy_calibration        = rtw8812a_phy_calibration,
+       .cck_pd_set             = rtw88xxa_phy_cck_pd_set,
+       .pwr_track              = rtw8812a_pwr_track,
+       .config_bfee            = NULL,
+       .set_gid_table          = NULL,
+       .cfg_csi_rate           = NULL,
+       .fill_txdesc_checksum   = rtw8812a_fill_txdesc_checksum,
+       .coex_set_init          = rtw8812a_coex_cfg_init,
+       .coex_set_ant_switch    = NULL,
+       .coex_set_gnt_fix       = rtw8812a_coex_cfg_gnt_fix,
+       .coex_set_gnt_debug     = NULL,
+       .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_8812a[] = {
+       /* hq_num, nq_num, lq_num, exq_num, gapq_num */
+       {0, 0, 0, 0, 0},        /* SDIO */
+       {0, 0, 0, 0, 0},        /* PCI */
+       {16, 0, 0, 0, 1},       /* 2 bulk out endpoints */
+       {16, 0, 16, 0, 1},      /* 3 bulk out endpoints */
+       {16, 0, 16, 0, 1},      /* 4 bulk out endpoints */
+};
+
+static const struct rtw_rqpn rqpn_table_8812a[] = {
+       {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_8812a = {
+       .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 rtw8812a_dig[] = {
+       [0] = { .addr = REG_RXIGI_A, .mask = 0x7f },
+       [1] = { .addr = REG_RXIGI_B, .mask = 0x7f },
+};
+
+static const struct rtw_rfe_def rtw8812a_rfe_defs[] = {
+       [0] = { .phy_pg_tbl     = &rtw8812a_bb_pg_tbl,
+               .txpwr_lmt_tbl  = &rtw8812a_txpwr_lmt_tbl,
+               .pwr_track_tbl  = &rtw8812a_rtw_pwr_track_tbl, },
+       [1] = { .phy_pg_tbl     = &rtw8812a_bb_pg_tbl,
+               .txpwr_lmt_tbl  = &rtw8812a_txpwr_lmt_tbl,
+               .pwr_track_tbl  = &rtw8812a_rtw_pwr_track_tbl, },
+       [3] = { .phy_pg_tbl     = &rtw8812a_bb_pg_rfe3_tbl,
+               .txpwr_lmt_tbl  = &rtw8812a_txpwr_lmt_tbl,
+               .pwr_track_tbl  = &rtw8812a_rtw_pwr_track_rfe3_tbl, },
+};
+
+static const u8 wl_rssi_step_8812a[] = {101, 45, 101, 40};
+static const u8 bt_rssi_step_8812a[] = {101, 101, 101, 101};
+
+static const struct coex_rf_para rf_para_tx_8812a[] = {
+       {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_8812a[] = {
+       {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_8812a) == ARRAY_SIZE(rf_para_rx_8812a));
+
+const struct rtw_chip_info rtw8812a_hw_spec = {
+       .ops = &rtw8812a_ops,
+       .id = RTW_CHIP_TYPE_8812A,
+       .fw_name = "rtw88/rtw8812a_fw.bin",
+       .wlan_cpu = RTW_WCPU_11N,
+       .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 = 96 + 1, /* TODO or just 18? */
+       .txff_size = 131072,
+       .rxff_size = 16128,
+       .rsvd_drv_pg_num = 9,
+       .txgi_factor = 1,
+       .is_pwr_by_rate_dec = true,
+       .max_power_index = 0x3f,
+       .csi_buf_pg_num = 0,
+       .band = RTW_BAND_2G | RTW_BAND_5G,
+       .page_size = 512,
+       .dig_min = 0x20,
+       .ht_supported = true,
+       .vht_supported = true,
+       .lps_deep_mode_supported = 0,
+       .sys_func_en = 0xFD,
+       .pwr_on_seq = card_enable_flow_8812a,
+       .pwr_off_seq = card_disable_flow_8812a,
+       .page_table = page_table_8812a,
+       .rqpn_table = rqpn_table_8812a,
+       .prioq_addrs = &prioq_addrs_8812a,
+       .intf_table = NULL,
+       .dig = rtw8812a_dig,
+       .rf_sipi_addr = {REG_LSSI_WRITE_A, REG_LSSI_WRITE_B},
+       .ltecoex_addr = NULL,
+       .mac_tbl = &rtw8812a_mac_tbl,
+       .agc_tbl = &rtw8812a_agc_tbl,
+       .bb_tbl = &rtw8812a_bb_tbl,
+       .rf_tbl = {&rtw8812a_rf_a_tbl, &rtw8812a_rf_b_tbl},
+       .rfe_defs = rtw8812a_rfe_defs,
+       .rfe_defs_size = ARRAY_SIZE(rtw8812a_rfe_defs),
+       .rx_ldpc = false,
+       .hw_feature_report = false,
+       .c2h_ra_report_size = 4,
+       .old_datarate_fb_limit = true,
+       .usb_tx_agg_desc_num = 1,
+       .iqk_threshold = 8,
+       .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
+       .max_scan_ie_len = IEEE80211_MAX_DATA_LEN,
+
+       .coex_para_ver = 0, /* no coex code in 8812au driver */
+       .bt_desired_ver = 0,
+       .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 = 15,
+       .rssi_tolerance = 2,
+       .wl_rssi_step = wl_rssi_step_8812a,
+       .bt_rssi_step = bt_rssi_step_8812a,
+       .table_sant_num = 0,
+       .table_sant = NULL,
+       .table_nsant_num = 0,
+       .table_nsant = NULL,
+       .tdma_sant_num = 0,
+       .tdma_sant = NULL,
+       .tdma_nsant_num = 0,
+       .tdma_nsant = NULL,
+       .wl_rf_para_num = ARRAY_SIZE(rf_para_tx_8812a),
+       .wl_rf_para_tx = rf_para_tx_8812a,
+       .wl_rf_para_rx = rf_para_rx_8812a,
+       .bt_afh_span_bw20 = 0x20,
+       .bt_afh_span_bw40 = 0x30,
+       .afh_5g_num = 0,
+       .afh_5g = NULL,
+       .coex_info_hw_regs_num = 0,
+       .coex_info_hw_regs = NULL,
+};
+EXPORT_SYMBOL(rtw8812a_hw_spec);
+
+MODULE_FIRMWARE("rtw88/rtw8812a_fw.bin");
+
+MODULE_AUTHOR("Realtek Corporation");
+MODULE_DESCRIPTION("Realtek 802.11ac wireless 8812a driver");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8812a.h b/drivers/net/wireless/realtek/rtw88/rtw8812a.h
new file mode 100644 (file)
index 0000000..82dab59
--- /dev/null
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
+/* Copyright(c) 2024  Realtek Corporation
+ */
+
+#ifndef __RTW8812A_H__
+#define __RTW8812A_H__
+
+extern const struct rtw_chip_info rtw8812a_hw_spec;
+
+#endif