rtw89_phy_ifs_clm_setting_init(rtwdev);
 }
 
+static void rtw89_phy_edcca_init(struct rtw89_dev *rtwdev)
+{
+       const struct rtw89_edcca_regs *edcca_regs = rtwdev->chip->edcca_regs;
+       struct rtw89_edcca_bak *edcca_bak = &rtwdev->hal.edcca_bak;
+
+       memset(edcca_bak, 0, sizeof(*edcca_bak));
+
+       if (rtwdev->chip->chip_id == RTL8922A && rtwdev->hal.cv == CHIP_CAV) {
+               rtw89_phy_set_phy_regs(rtwdev, R_TXGATING, B_TXGATING_EN, 0);
+               rtw89_phy_set_phy_regs(rtwdev, R_CTLTOP, B_CTLTOP_VAL, 2);
+               rtw89_phy_set_phy_regs(rtwdev, R_CTLTOP, B_CTLTOP_ON, 1);
+               rtw89_phy_set_phy_regs(rtwdev, R_SPOOF_CG, B_SPOOF_CG_EN, 0);
+               rtw89_phy_set_phy_regs(rtwdev, R_DFS_FFT_CG, B_DFS_CG_EN, 0);
+               rtw89_phy_set_phy_regs(rtwdev, R_DFS_FFT_CG, B_DFS_FFT_EN, 0);
+               rtw89_phy_set_phy_regs(rtwdev, R_SEGSND, B_SEGSND_EN, 0);
+               rtw89_phy_set_phy_regs(rtwdev, R_SEGSND, B_SEGSND_EN, 1);
+               rtw89_phy_set_phy_regs(rtwdev, R_DFS_FFT_CG, B_DFS_FFT_EN, 1);
+       }
+
+       rtw89_phy_write32_mask(rtwdev, edcca_regs->tx_collision_t2r_st,
+                              edcca_regs->tx_collision_t2r_st_mask, 0x29);
+}
+
 void rtw89_phy_dm_init(struct rtw89_dev *rtwdev)
 {
        rtw89_phy_stat_init(rtwdev);
        rtw89_physts_parsing_init(rtwdev);
        rtw89_phy_dig_init(rtwdev);
        rtw89_phy_cfo_init(rtwdev);
+       rtw89_phy_edcca_init(rtwdev);
        rtw89_phy_ul_tb_info_init(rtwdev);
        rtw89_phy_antdiv_init(rtwdev);
        rtw89_chip_rfe_gpio(rtwdev);
 }
 EXPORT_SYMBOL(rtw89_decode_chan_idx);
 
-#define EDCCA_DEFAULT 249
 void rtw89_phy_config_edcca(struct rtw89_dev *rtwdev, bool scan)
 {
-       u32 reg = rtwdev->chip->edcca_lvl_reg;
-       struct rtw89_hal *hal = &rtwdev->hal;
-       u32 val;
+       const struct rtw89_edcca_regs *edcca_regs = rtwdev->chip->edcca_regs;
+       struct rtw89_edcca_bak *edcca_bak = &rtwdev->hal.edcca_bak;
 
        if (scan) {
-               hal->edcca_bak = rtw89_phy_read32(rtwdev, reg);
-               val = hal->edcca_bak;
-               u32p_replace_bits(&val, EDCCA_DEFAULT, B_SEG0R_EDCCA_LVL_A_MSK);
-               u32p_replace_bits(&val, EDCCA_DEFAULT, B_SEG0R_EDCCA_LVL_P_MSK);
-               u32p_replace_bits(&val, EDCCA_DEFAULT, B_SEG0R_PPDU_LVL_MSK);
-               rtw89_phy_write32(rtwdev, reg, val);
+               edcca_bak->a =
+                       rtw89_phy_read32_mask(rtwdev, edcca_regs->edcca_level,
+                                             edcca_regs->edcca_mask);
+               edcca_bak->p =
+                       rtw89_phy_read32_mask(rtwdev, edcca_regs->edcca_level,
+                                             edcca_regs->edcca_p_mask);
+               edcca_bak->ppdu =
+                       rtw89_phy_read32_mask(rtwdev, edcca_regs->ppdu_level,
+                                             edcca_regs->ppdu_mask);
+
+               rtw89_phy_write32_mask(rtwdev, edcca_regs->edcca_level,
+                                      edcca_regs->edcca_mask, EDCCA_MAX);
+               rtw89_phy_write32_mask(rtwdev, edcca_regs->edcca_level,
+                                      edcca_regs->edcca_p_mask, EDCCA_MAX);
+               rtw89_phy_write32_mask(rtwdev, edcca_regs->ppdu_level,
+                                      edcca_regs->ppdu_mask, EDCCA_MAX);
+       } else {
+               rtw89_phy_write32_mask(rtwdev, edcca_regs->edcca_level,
+                                      edcca_regs->edcca_mask,
+                                      edcca_bak->a);
+               rtw89_phy_write32_mask(rtwdev, edcca_regs->edcca_level,
+                                      edcca_regs->edcca_p_mask,
+                                      edcca_bak->p);
+               rtw89_phy_write32_mask(rtwdev, edcca_regs->ppdu_level,
+                                      edcca_regs->ppdu_mask,
+                                      edcca_bak->ppdu);
+       }
+}
+
+static void rtw89_phy_edcca_log(struct rtw89_dev *rtwdev)
+{
+       const struct rtw89_edcca_regs *edcca_regs = rtwdev->chip->edcca_regs;
+       bool flag_fb, flag_p20, flag_s20, flag_s40, flag_s80;
+       s8 pwdb_fb, pwdb_p20, pwdb_s20, pwdb_s40, pwdb_s80;
+       u8 path, per20_bitmap;
+       u8 pwdb[8];
+       u32 tmp;
+
+       if (!rtw89_debug_is_enabled(rtwdev, RTW89_DBG_EDCCA))
+               return;
+
+       if (rtwdev->chip->chip_id == RTL8922A)
+               rtw89_phy_write32_mask(rtwdev, edcca_regs->rpt_sel_be,
+                                      edcca_regs->rpt_sel_be_mask, 0);
+
+       rtw89_phy_write32_mask(rtwdev, edcca_regs->rpt_sel,
+                              edcca_regs->rpt_sel_mask, 0);
+       tmp = rtw89_phy_read32(rtwdev, edcca_regs->rpt_b);
+       path = u32_get_bits(tmp, B_EDCCA_RPT_B_PATH_MASK);
+       flag_s80 = u32_get_bits(tmp, B_EDCCA_RPT_B_S80);
+       flag_s40 = u32_get_bits(tmp, B_EDCCA_RPT_B_S40);
+       flag_s20 = u32_get_bits(tmp, B_EDCCA_RPT_B_S20);
+       flag_p20 = u32_get_bits(tmp, B_EDCCA_RPT_B_P20);
+       flag_fb = u32_get_bits(tmp, B_EDCCA_RPT_B_FB);
+       pwdb_s20 = u32_get_bits(tmp, MASKBYTE1);
+       pwdb_p20 = u32_get_bits(tmp, MASKBYTE2);
+       pwdb_fb = u32_get_bits(tmp, MASKBYTE3);
+
+       rtw89_phy_write32_mask(rtwdev, edcca_regs->rpt_sel,
+                              edcca_regs->rpt_sel_mask, 4);
+       tmp = rtw89_phy_read32(rtwdev, edcca_regs->rpt_b);
+       pwdb_s80 = u32_get_bits(tmp, MASKBYTE1);
+       pwdb_s40 = u32_get_bits(tmp, MASKBYTE2);
+
+       per20_bitmap = rtw89_phy_read32_mask(rtwdev, edcca_regs->rpt_a,
+                                            MASKBYTE0);
+
+       if (rtwdev->chip->chip_id == RTL8922A) {
+               rtw89_phy_write32_mask(rtwdev, edcca_regs->rpt_sel_be,
+                                      edcca_regs->rpt_sel_be_mask, 4);
+               tmp = rtw89_phy_read32(rtwdev, edcca_regs->rpt_b);
+               pwdb[0] = u32_get_bits(tmp, MASKBYTE3);
+               pwdb[1] = u32_get_bits(tmp, MASKBYTE2);
+               pwdb[2] = u32_get_bits(tmp, MASKBYTE1);
+               pwdb[3] = u32_get_bits(tmp, MASKBYTE0);
+
+               rtw89_phy_write32_mask(rtwdev, edcca_regs->rpt_sel_be,
+                                      edcca_regs->rpt_sel_be_mask, 5);
+               tmp = rtw89_phy_read32(rtwdev, edcca_regs->rpt_b);
+               pwdb[4] = u32_get_bits(tmp, MASKBYTE3);
+               pwdb[5] = u32_get_bits(tmp, MASKBYTE2);
+               pwdb[6] = u32_get_bits(tmp, MASKBYTE1);
+               pwdb[7] = u32_get_bits(tmp, MASKBYTE0);
+       } else {
+               rtw89_phy_write32_mask(rtwdev, edcca_regs->rpt_sel,
+                                      edcca_regs->rpt_sel_mask, 0);
+               tmp = rtw89_phy_read32(rtwdev, edcca_regs->rpt_a);
+               pwdb[0] = u32_get_bits(tmp, MASKBYTE3);
+               pwdb[1] = u32_get_bits(tmp, MASKBYTE2);
+
+               rtw89_phy_write32_mask(rtwdev, edcca_regs->rpt_sel,
+                                      edcca_regs->rpt_sel_mask, 1);
+               tmp = rtw89_phy_read32(rtwdev, edcca_regs->rpt_a);
+               pwdb[2] = u32_get_bits(tmp, MASKBYTE3);
+               pwdb[3] = u32_get_bits(tmp, MASKBYTE2);
+
+               rtw89_phy_write32_mask(rtwdev, edcca_regs->rpt_sel,
+                                      edcca_regs->rpt_sel_mask, 2);
+               tmp = rtw89_phy_read32(rtwdev, edcca_regs->rpt_a);
+               pwdb[4] = u32_get_bits(tmp, MASKBYTE3);
+               pwdb[5] = u32_get_bits(tmp, MASKBYTE2);
+
+               rtw89_phy_write32_mask(rtwdev, edcca_regs->rpt_sel,
+                                      edcca_regs->rpt_sel_mask, 3);
+               tmp = rtw89_phy_read32(rtwdev, edcca_regs->rpt_a);
+               pwdb[6] = u32_get_bits(tmp, MASKBYTE3);
+               pwdb[7] = u32_get_bits(tmp, MASKBYTE2);
+       }
+
+       rtw89_debug(rtwdev, RTW89_DBG_EDCCA,
+                   "[EDCCA]: edcca_bitmap = %04x\n", per20_bitmap);
+
+       rtw89_debug(rtwdev, RTW89_DBG_EDCCA,
+                   "[EDCCA]: pwdb per20{0,1,2,3,4,5,6,7} = {%d,%d,%d,%d,%d,%d,%d,%d}(dBm)\n",
+                   pwdb[0], pwdb[1], pwdb[2], pwdb[3], pwdb[4], pwdb[5],
+                   pwdb[6], pwdb[7]);
+
+       rtw89_debug(rtwdev, RTW89_DBG_EDCCA,
+                   "[EDCCA]: path=%d, flag {FB,p20,s20,s40,s80} = {%d,%d,%d,%d,%d}\n",
+                   path, flag_fb, flag_p20, flag_s20, flag_s40, flag_s80);
+
+       rtw89_debug(rtwdev, RTW89_DBG_EDCCA,
+                   "[EDCCA]: pwdb {FB,p20,s20,s40,s80} = {%d,%d,%d,%d,%d}(dBm)\n",
+                   pwdb_fb, pwdb_p20, pwdb_s20, pwdb_s40, pwdb_s80);
+}
+
+static u8 rtw89_phy_edcca_get_thre_by_rssi(struct rtw89_dev *rtwdev)
+{
+       struct rtw89_phy_ch_info *ch_info = &rtwdev->ch_info;
+       bool is_linked = rtwdev->total_sta_assoc > 0;
+       u8 rssi_min = ch_info->rssi_min >> 1;
+       u8 edcca_thre;
+
+       if (!is_linked) {
+               edcca_thre = EDCCA_MAX;
        } else {
-               rtw89_phy_write32(rtwdev, reg, hal->edcca_bak);
+               edcca_thre = rssi_min - RSSI_UNIT_CONVER + EDCCA_UNIT_CONVER -
+                            EDCCA_TH_REF;
+               edcca_thre = max_t(u8, edcca_thre, EDCCA_TH_L2H_LB);
        }
+
+       return edcca_thre;
+}
+
+void rtw89_phy_edcca_thre_calc(struct rtw89_dev *rtwdev)
+{
+       const struct rtw89_edcca_regs *edcca_regs = rtwdev->chip->edcca_regs;
+       struct rtw89_edcca_bak *edcca_bak = &rtwdev->hal.edcca_bak;
+       u8 th;
+
+       th = rtw89_phy_edcca_get_thre_by_rssi(rtwdev);
+       if (th == edcca_bak->th_old)
+               return;
+
+       edcca_bak->th_old = th;
+
+       rtw89_debug(rtwdev, RTW89_DBG_EDCCA,
+                   "[EDCCA]: Normal Mode, EDCCA_th = %d\n", th);
+
+       rtw89_phy_write32_mask(rtwdev, edcca_regs->edcca_level,
+                              edcca_regs->edcca_mask, th);
+       rtw89_phy_write32_mask(rtwdev, edcca_regs->edcca_level,
+                              edcca_regs->edcca_p_mask, th);
+       rtw89_phy_write32_mask(rtwdev, edcca_regs->ppdu_level,
+                              edcca_regs->ppdu_mask, th);
+}
+
+void rtw89_phy_edcca_track(struct rtw89_dev *rtwdev)
+{
+       rtw89_phy_edcca_thre_calc(rtwdev);
+       rtw89_phy_edcca_log(rtwdev);
 }
 
 static const struct rtw89_ccx_regs rtw89_ccx_regs_ax = {
 
 #define B_P0_RSTB_WATCH_DOG BIT(0)
 #define B_P1_RSTB_WATCH_DOG BIT(1)
 #define B_UPD_P0_EN BIT(31)
+#define R_SPOOF_CG 0x00B4
+#define B_SPOOF_CG_EN BIT(17)
+#define R_DFS_FFT_CG 0x00B8
+#define B_DFS_CG_EN BIT(1)
+#define B_DFS_FFT_EN BIT(0)
 #define R_ANAPAR_PW15 0x030C
 #define B_ANAPAR_PW15 GENMASK(31, 24)
 #define B_ANAPAR_PW15_H GENMASK(27, 24)
 #define R_PHY_STS_BITMAP_HT 0x076C
 #define R_PHY_STS_BITMAP_VHT 0x0770
 #define R_PHY_STS_BITMAP_HE 0x0774
+#define R_EDCCA_RPTREG_SEL_BE 0x078C
+#define B_EDCCA_RPTREG_SEL_BE_MSK GENMASK(22, 20)
 #define R_PMAC_GNT 0x0980
 #define B_PMAC_GNT_TXEN BIT(0)
 #define B_PMAC_GNT_RXEN BIT(16)
 #define B_IOQ_IQK_DPK_EN BIT(1)
 #define R_GNT_BT_WGT_EN 0x0C6C
 #define B_GNT_BT_WGT_EN BIT(21)
+#define R_TX_COLLISION_T2R_ST 0x0C70
+#define B_TX_COLLISION_T2R_ST_M GENMASK(25, 20)
+#define R_TXGATING 0x0C74
+#define B_TXGATING_EN BIT(4)
 #define R_PD_ARBITER_OFF 0x0C80
 #define B_PD_ARBITER_OFF BIT(31)
 #define R_SNDCCA_A1 0x0C9C
 #define B_SNDCCA_A1_EN GENMASK(19, 12)
 #define R_SNDCCA_A2 0x0CA0
 #define B_SNDCCA_A2_VAL GENMASK(19, 12)
+#define R_TX_COLLISION_T2R_ST_BE 0x0CC8
+#define B_TX_COLLISION_T2R_ST_BE_M GENMASK(13, 8)
 #define R_RXHT_MCS_LIMIT 0x0D18
 #define B_RXHT_MCS_LIMIT GENMASK(9, 8)
 #define R_RXVHT_MCS_LIMIT 0x0D18
 #define R_BRK_ASYNC_RST_EN_1 0x0DC0
 #define R_BRK_ASYNC_RST_EN_2 0x0DC4
 #define R_BRK_ASYNC_RST_EN_3 0x0DC8
+#define R_CTLTOP 0x1008
+#define B_CTLTOP_ON BIT(23)
+#define B_CTLTOP_VAL GENMASK(15, 12)
+#define R_EDCCA_RPT_SEL_BE 0x10CC
 #define R_S0_HW_SI_DIS 0x1200
 #define B_S0_HW_SI_DIS_W_R_TRIG GENMASK(30, 28)
 #define R_P0_RXCK 0x12A0
 #define R_CFO_COMP_SEG0_H 0x1388
 #define R_CFO_COMP_SEG0_CTRL 0x138C
 #define R_DBG32_D 0x1730
+#define R_EDCCA_RPT_A 0x1738
+#define R_EDCCA_RPT_B 0x173c
+#define B_EDCCA_RPT_B_FB BIT(7)
+#define B_EDCCA_RPT_B_P20 BIT(6)
+#define B_EDCCA_RPT_B_S20 BIT(5)
+#define B_EDCCA_RPT_B_S40 BIT(4)
+#define B_EDCCA_RPT_B_S80 BIT(3)
+#define B_EDCCA_RPT_B_PATH_MASK GENMASK(2, 1)
 #define R_SWSI_V1 0x174C
 #define B_SWSI_W_BUSY_V1 BIT(24)
 #define B_SWSI_R_BUSY_V1 BIT(25)
 #define R_S0_ADDCK 0x1E00
 #define B_S0_ADDCK_I GENMASK(9, 0)
 #define B_S0_ADDCK_Q GENMASK(19, 10)
+#define R_EDCCA_RPT_SEL 0x20CC
+#define B_EDCCA_RPT_SEL_MSK GENMASK(2, 0)
 #define R_ADC_FIFO 0x20fc
 #define B_ADC_FIFO_RST GENMASK(31, 24)
 #define B_ADC_FIFO_RXK GENMASK(31, 16)
 #define B_DBCC_80P80_SEL_EVM_RPT2_EN BIT(0)
 #define R_P1_EN_SOUND_WO_NDP 0x2D7C
 #define B_P1_EN_SOUND_WO_NDP BIT(1)
+#define R_EDCCA_RPT_A_BE 0x2E38
+#define R_EDCCA_RPT_B_BE 0x2E3C
 #define R_S1_HW_SI_DIS 0x3200
 #define B_S1_HW_SI_DIS_W_R_TRIG GENMASK(30, 28)
 #define R_P1_RXCK 0x32A0
 #define R_SEG0R_PD_V2 0x6A74
 #define R_SEG0R_EDCCA_LVL 0x4840
 #define R_SEG0R_EDCCA_LVL_V1 0x4884
-#define B_SEG0R_PPDU_LVL_MSK GENMASK(31, 24)
-#define B_SEG0R_EDCCA_LVL_P_MSK GENMASK(15, 8)
-#define B_SEG0R_EDCCA_LVL_A_MSK GENMASK(7, 0)
+#define B_EDCCA_LVL_MSK3 GENMASK(31, 24)
+#define B_EDCCA_LVL_MSK1 GENMASK(15, 8)
+#define B_EDCCA_LVL_MSK0 GENMASK(7, 0)
 #define B_SEG0R_PD_SPATIAL_REUSE_EN_MSK_V1 BIT(30)
 #define B_SEG0R_PD_SPATIAL_REUSE_EN_MSK BIT(29)
 #define B_SEG0R_PD_LOWER_BOUND_MSK GENMASK(10, 6)
 #define B_DCFO_WEIGHT_MSK_V1 GENMASK(31, 28)
 #define R_DCFO_OPT_V1 0x6260
 #define B_DCFO_OPT_EN_V1 BIT(17)
+#define R_SEG0R_EDCCA_LVL_BE 0x69EC
+#define R_SEG0R_PPDU_LVL_BE 0x69F0
+#define R_SEGSND 0x6A14
+#define B_SEGSND_EN BIT(31)
 #define R_RPL_BIAS_COMP1 0x6DF0
 #define B_RPL_BIAS_COMP1_MASK GENMASK(7, 0)
 #define R_P1_TSSI_ALIM1 0x7630