u32 ep_tx_normal_queue:1;
        u32 ep_tx_low_queue:1;
        u32 rx_buf_aggregation:1;
+       u32 cck_agc_report_type:1;
        u8 default_crystal_cap;
        unsigned int pipe_interrupt;
        unsigned int pipe_in;
                             bool short_preamble, bool ampdu_enable,
                             u32 rts_rate);
        void (*set_crystal_cap) (struct rtl8xxxu_priv *priv, u8 crystal_cap);
+       s8 (*cck_rssi) (struct rtl8xxxu_priv *priv, u8 cck_agc_rpt);
        int writeN_block_size;
        int rx_agg_buf_size;
        char tx_desc_size;
                           u8 arg1, u8 arg2, u8 arg3, u8 arg4, u8 arg5);
 void rtl8723bu_phy_init_antenna_selection(struct rtl8xxxu_priv *priv);
 void rtl8723a_set_crystal_cap(struct rtl8xxxu_priv *priv, u8 crystal_cap);
+s8 rtl8723a_cck_rssi(struct rtl8xxxu_priv *priv, u8 cck_agc_rpt);
 
 extern struct rtl8xxxu_fileops rtl8188fu_fops;
 extern struct rtl8xxxu_fileops rtl8192cu_fops;
 
        cfo->crystal_cap = crystal_cap;
 }
 
+static s8 rtl8188f_cck_rssi(struct rtl8xxxu_priv *priv, u8 cck_agc_rpt)
+{
+       s8 rx_pwr_all = 0x00;
+       u8 vga_idx, lna_idx;
+
+       lna_idx = (cck_agc_rpt & 0xE0) >> 5;
+       vga_idx = cck_agc_rpt & 0x1F;
+
+       switch (lna_idx) {
+       case 7:
+               if (vga_idx <= 27)
+                       rx_pwr_all = -100 + 2 * (27 - vga_idx);
+               else
+                       rx_pwr_all = -100;
+               break;
+       case 5:
+               rx_pwr_all = -74 + 2 * (21 - vga_idx);
+               break;
+       case 3:
+               rx_pwr_all = -60 + 2 * (20 - vga_idx);
+               break;
+       case 1:
+               rx_pwr_all = -44 + 2 * (19 - vga_idx);
+               break;
+       default:
+               break;
+       }
+
+       return rx_pwr_all;
+}
+
 struct rtl8xxxu_fileops rtl8188fu_fops = {
        .parse_efuse = rtl8188fu_parse_efuse,
        .load_firmware = rtl8188fu_load_firmware,
        .report_connect = rtl8xxxu_gen2_report_connect,
        .fill_txdesc = rtl8xxxu_fill_txdesc_v2,
        .set_crystal_cap = rtl8188f_set_crystal_cap,
+       .cck_rssi = rtl8188f_cck_rssi,
        .writeN_block_size = 128,
        .rx_desc_size = sizeof(struct rtl8xxxu_rxdesc24),
        .tx_desc_size = sizeof(struct rtl8xxxu_txdesc40),
 
        .update_rate_mask = rtl8xxxu_update_rate_mask,
        .report_connect = rtl8xxxu_gen1_report_connect,
        .fill_txdesc = rtl8xxxu_fill_txdesc_v1,
+       .cck_rssi = rtl8723a_cck_rssi,
        .writeN_block_size = 128,
        .rx_agg_buf_size = 16000,
        .tx_desc_size = sizeof(struct rtl8xxxu_txdesc32),
 
        rtl8xxxu_write8(priv, REG_PAD_CTRL1, val8);
 }
 
+static s8 rtl8192e_cck_rssi(struct rtl8xxxu_priv *priv, u8 cck_agc_rpt)
+{
+       static const s8 lna_gain_table_0[8] = {15, 9, -10, -21, -23, -27, -43, -44};
+       static const s8 lna_gain_table_1[8] = {24, 18, 13, -4, -11, -18, -31, -36};
+
+       s8 rx_pwr_all = 0x00;
+       u8 vga_idx, lna_idx;
+       s8 lna_gain = 0;
+
+       lna_idx = (cck_agc_rpt & 0xE0) >> 5;
+       vga_idx = cck_agc_rpt & 0x1F;
+
+       if (priv->cck_agc_report_type == 0)
+               lna_gain = lna_gain_table_0[lna_idx];
+       else
+               lna_gain = lna_gain_table_1[lna_idx];
+
+       rx_pwr_all = lna_gain - (2 * vga_idx);
+
+       return rx_pwr_all;
+}
+
 struct rtl8xxxu_fileops rtl8192eu_fops = {
        .parse_efuse = rtl8192eu_parse_efuse,
        .load_firmware = rtl8192eu_load_firmware,
        .report_connect = rtl8xxxu_gen2_report_connect,
        .fill_txdesc = rtl8xxxu_fill_txdesc_v2,
        .set_crystal_cap = rtl8723a_set_crystal_cap,
+       .cck_rssi = rtl8192e_cck_rssi,
        .writeN_block_size = 128,
        .tx_desc_size = sizeof(struct rtl8xxxu_txdesc40),
        .rx_desc_size = sizeof(struct rtl8xxxu_rxdesc24),
 
        cfo->crystal_cap = crystal_cap;
 }
 
+s8 rtl8723a_cck_rssi(struct rtl8xxxu_priv *priv, u8 cck_agc_rpt)
+{
+       s8 rx_pwr_all = 0x00;
+
+       switch (cck_agc_rpt & 0xc0) {
+       case 0xc0:
+               rx_pwr_all = -46 - (cck_agc_rpt & 0x3e);
+               break;
+       case 0x80:
+               rx_pwr_all = -26 - (cck_agc_rpt & 0x3e);
+               break;
+       case 0x40:
+               rx_pwr_all = -12 - (cck_agc_rpt & 0x3e);
+               break;
+       case 0x00:
+               rx_pwr_all = 16 - (cck_agc_rpt & 0x3e);
+               break;
+       }
+
+       return rx_pwr_all;
+}
+
 struct rtl8xxxu_fileops rtl8723au_fops = {
        .parse_efuse = rtl8723au_parse_efuse,
        .load_firmware = rtl8723au_load_firmware,
        .report_connect = rtl8xxxu_gen1_report_connect,
        .fill_txdesc = rtl8xxxu_fill_txdesc_v1,
        .set_crystal_cap = rtl8723a_set_crystal_cap,
+       .cck_rssi = rtl8723a_cck_rssi,
        .writeN_block_size = 1024,
        .rx_agg_buf_size = 16000,
        .tx_desc_size = sizeof(struct rtl8xxxu_txdesc32),
 
        rtl8xxxu_write32(priv, REG_OFDM0_FA_RSTC, val32);
 }
 
+static s8 rtl8723b_cck_rssi(struct rtl8xxxu_priv *priv, u8 cck_agc_rpt)
+{
+       s8 rx_pwr_all = 0x00;
+       u8 vga_idx, lna_idx;
+
+       lna_idx = (cck_agc_rpt & 0xE0) >> 5;
+       vga_idx = cck_agc_rpt & 0x1F;
+
+       switch (lna_idx) {
+       case 6:
+               rx_pwr_all = -34 - (2 * vga_idx);
+               break;
+       case 4:
+               rx_pwr_all = -14 - (2 * vga_idx);
+               break;
+       case 1:
+               rx_pwr_all = 6 - (2 * vga_idx);
+               break;
+       case 0:
+               rx_pwr_all = 16 - (2 * vga_idx);
+               break;
+       default:
+               break;
+       }
+
+       return rx_pwr_all;
+}
+
 struct rtl8xxxu_fileops rtl8723bu_fops = {
        .parse_efuse = rtl8723bu_parse_efuse,
        .load_firmware = rtl8723bu_load_firmware,
        .report_connect = rtl8xxxu_gen2_report_connect,
        .fill_txdesc = rtl8xxxu_fill_txdesc_v2,
        .set_crystal_cap = rtl8723a_set_crystal_cap,
+       .cck_rssi = rtl8723b_cck_rssi,
        .writeN_block_size = 1024,
        .tx_desc_size = sizeof(struct rtl8xxxu_txdesc40),
        .rx_desc_size = sizeof(struct rtl8xxxu_rxdesc24),
 
                val32 &= 0xfff00fff;
                val32 |= 0x0007e000;
                rtl8xxxu_write32(priv, REG_AFE_MISC, val32);
+
+               /*
+                * 0x824[9] = 0x82C[9] = 0xA80[7] those registers setting
+                * should be equal or CCK RSSI report may be incorrect
+                */
+               val32 = rtl8xxxu_read32(priv, REG_FPGA0_XA_HSSI_PARM2);
+               priv->cck_agc_report_type = val32 & FPGA0_HSSI_PARM2_CCK_HIGH_PWR;
+
+               val32 = rtl8xxxu_read32(priv, REG_FPGA0_XB_HSSI_PARM2);
+               if (priv->cck_agc_report_type != (bool)(val32 & FPGA0_HSSI_PARM2_CCK_HIGH_PWR)) {
+                       if (priv->cck_agc_report_type)
+                               val32 |= FPGA0_HSSI_PARM2_CCK_HIGH_PWR;
+                       else
+                               val32 &= ~FPGA0_HSSI_PARM2_CCK_HIGH_PWR;
+                       rtl8xxxu_write32(priv, REG_FPGA0_XB_HSSI_PARM2, val32);
+               }
+
+               val32 = rtl8xxxu_read32(priv, REG_AGC_RPT);
+               if (priv->cck_agc_report_type)
+                       val32 |= AGC_RPT_CCK;
+               else
+                       val32 &= ~AGC_RPT_CCK;
+               rtl8xxxu_write32(priv, REG_AGC_RPT, val32);
        }
 
        /* Initialise the center frequency offset tracking */
                 */
                u8 cck_agc_rpt = phy_stats->cck_agc_rpt_ofdm_cfosho_a;
 
-               switch (cck_agc_rpt & 0xc0) {
-               case 0xc0:
-                       rx_status->signal = -46 - (cck_agc_rpt & 0x3e);
-                       break;
-               case 0x80:
-                       rx_status->signal = -26 - (cck_agc_rpt & 0x3e);
-                       break;
-               case 0x40:
-                       rx_status->signal = -12 - (cck_agc_rpt & 0x3e);
-                       break;
-               case 0x00:
-                       rx_status->signal = 16 - (cck_agc_rpt & 0x3e);
-                       break;
-               }
+               rx_status->signal = priv->fops->cck_rssi(priv, cck_agc_rpt);
        } else {
                bool parse_cfo = priv->fops->set_crystal_cap &&
                                 priv->vif &&
 
 #define  CCK_PD_TYPE1_LV3_TH           0xdd
 #define  CCK_PD_TYPE1_LV4_TH           0xed
 
+#define REG_AGC_RPT                    0xa80
+#define  AGC_RPT_CCK                   BIT(7)
+
 #define REG_CONFIG_ANT_A               0x0b68
 #define REG_CONFIG_ANT_B               0x0b6c