diff options
Diffstat (limited to 'drivers/net/wireless/realtek/rtw89/phy.c')
-rw-r--r-- | drivers/net/wireless/realtek/rtw89/phy.c | 284 |
1 files changed, 276 insertions, 8 deletions
diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index c7e906123416..de0776dfddf7 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -10,6 +10,7 @@ #include "ps.h" #include "reg.h" #include "sar.h" +#include "txrx.h" #include "util.h" static u16 get_max_amsdu_len(struct rtw89_dev *rtwdev, @@ -1400,7 +1401,8 @@ static void rtw89_phy_init_rf_nctl(struct rtw89_dev *rtwdev) rtw89_phy_write32_set(rtwdev, R_IOQ_IQK_DPK, 0x3); rtw89_phy_write32_set(rtwdev, R_GNT_BT_WGT_EN, 0x1); rtw89_phy_write32_set(rtwdev, R_P0_PATH_RST, 0x8000000); - rtw89_phy_write32_set(rtwdev, R_P1_PATH_RST, 0x8000000); + if (chip->chip_id != RTL8851B) + rtw89_phy_write32_set(rtwdev, R_P1_PATH_RST, 0x8000000); if (chip->chip_id == RTL8852B) rtw89_phy_write32_set(rtwdev, R_IOQ_IQK_DPK, 0x2); @@ -1414,6 +1416,9 @@ static void rtw89_phy_init_rf_nctl(struct rtw89_dev *rtwdev) nctl_table = chip->nctl_table; rtw89_phy_init_reg(rtwdev, nctl_table, rtw89_phy_config_bb_reg, NULL); + + if (chip->nctl_post_table) + rtw89_rfk_parser(rtwdev, chip->nctl_post_table); } static u32 rtw89_phy0_phy1_offset(struct rtw89_dev *rtwdev, u32 addr) @@ -2338,27 +2343,29 @@ void rtw89_phy_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb, static u8 rtw89_phy_cfo_get_xcap_reg(struct rtw89_dev *rtwdev, bool sc_xo) { + const struct rtw89_xtal_info *xtal = rtwdev->chip->xtal_info; u32 reg_mask; if (sc_xo) - reg_mask = B_AX_XTAL_SC_XO_MASK; + reg_mask = xtal->sc_xo_mask; else - reg_mask = B_AX_XTAL_SC_XI_MASK; + reg_mask = xtal->sc_xi_mask; - return (u8)rtw89_read32_mask(rtwdev, R_AX_XTAL_ON_CTRL0, reg_mask); + return (u8)rtw89_read32_mask(rtwdev, xtal->xcap_reg, reg_mask); } static void rtw89_phy_cfo_set_xcap_reg(struct rtw89_dev *rtwdev, bool sc_xo, u8 val) { + const struct rtw89_xtal_info *xtal = rtwdev->chip->xtal_info; u32 reg_mask; if (sc_xo) - reg_mask = B_AX_XTAL_SC_XO_MASK; + reg_mask = xtal->sc_xo_mask; else - reg_mask = B_AX_XTAL_SC_XI_MASK; + reg_mask = xtal->sc_xi_mask; - rtw89_write32_mask(rtwdev, R_AX_XTAL_ON_CTRL0, reg_mask, val); + rtw89_write32_mask(rtwdev, xtal->xcap_reg, reg_mask, val); } static void rtw89_phy_cfo_set_crystal_cap(struct rtw89_dev *rtwdev, @@ -2371,7 +2378,7 @@ static void rtw89_phy_cfo_set_crystal_cap(struct rtw89_dev *rtwdev, if (!force && cfo->crystal_cap == crystal_cap) return; crystal_cap = clamp_t(u8, crystal_cap, 0, 127); - if (chip->chip_id == RTL8852A) { + if (chip->chip_id == RTL8852A || chip->chip_id == RTL8851B) { rtw89_phy_cfo_set_xcap_reg(rtwdev, true, crystal_cap); rtw89_phy_cfo_set_xcap_reg(rtwdev, false, crystal_cap); sc_xo_val = rtw89_phy_cfo_get_xcap_reg(rtwdev, true); @@ -2946,6 +2953,126 @@ static void rtw89_phy_ul_tb_info_init(struct rtw89_dev *rtwdev) rtw89_phy_read32_mask(rtwdev, R_BANDEDGE, B_BANDEDGE_EN); } +static +void rtw89_phy_antdiv_sts_instance_reset(struct rtw89_antdiv_stats *antdiv_sts) +{ + ewma_rssi_init(&antdiv_sts->cck_rssi_avg); + ewma_rssi_init(&antdiv_sts->ofdm_rssi_avg); + ewma_rssi_init(&antdiv_sts->non_legacy_rssi_avg); + antdiv_sts->pkt_cnt_cck = 0; + antdiv_sts->pkt_cnt_ofdm = 0; + antdiv_sts->pkt_cnt_non_legacy = 0; + antdiv_sts->evm = 0; +} + +static void rtw89_phy_antdiv_sts_instance_add(struct rtw89_dev *rtwdev, + struct rtw89_rx_phy_ppdu *phy_ppdu, + struct rtw89_antdiv_stats *stats) +{ + if (GET_DATA_RATE_MODE(phy_ppdu->rate) == DATA_RATE_MODE_NON_HT) { + if (phy_ppdu->rate < RTW89_HW_RATE_OFDM6) { + ewma_rssi_add(&stats->cck_rssi_avg, phy_ppdu->rssi_avg); + stats->pkt_cnt_cck++; + } else { + ewma_rssi_add(&stats->ofdm_rssi_avg, phy_ppdu->rssi_avg); + stats->pkt_cnt_ofdm++; + stats->evm += phy_ppdu->ofdm.evm_min; + } + } else { + ewma_rssi_add(&stats->non_legacy_rssi_avg, phy_ppdu->rssi_avg); + stats->pkt_cnt_non_legacy++; + stats->evm += phy_ppdu->ofdm.evm_min; + } +} + +static u8 rtw89_phy_antdiv_sts_instance_get_rssi(struct rtw89_antdiv_stats *stats) +{ + if (stats->pkt_cnt_non_legacy >= stats->pkt_cnt_cck && + stats->pkt_cnt_non_legacy >= stats->pkt_cnt_ofdm) + return ewma_rssi_read(&stats->non_legacy_rssi_avg); + else if (stats->pkt_cnt_ofdm >= stats->pkt_cnt_cck && + stats->pkt_cnt_ofdm >= stats->pkt_cnt_non_legacy) + return ewma_rssi_read(&stats->ofdm_rssi_avg); + else + return ewma_rssi_read(&stats->cck_rssi_avg); +} + +static u8 rtw89_phy_antdiv_sts_instance_get_evm(struct rtw89_antdiv_stats *stats) +{ + return phy_div(stats->evm, stats->pkt_cnt_non_legacy + stats->pkt_cnt_ofdm); +} + +void rtw89_phy_antdiv_parse(struct rtw89_dev *rtwdev, + struct rtw89_rx_phy_ppdu *phy_ppdu) +{ + struct rtw89_antdiv_info *antdiv = &rtwdev->antdiv; + struct rtw89_hal *hal = &rtwdev->hal; + + if (!hal->ant_diversity || hal->ant_diversity_fixed) + return; + + rtw89_phy_antdiv_sts_instance_add(rtwdev, phy_ppdu, &antdiv->target_stats); + + if (!antdiv->get_stats) + return; + + if (hal->antenna_rx == RF_A) + rtw89_phy_antdiv_sts_instance_add(rtwdev, phy_ppdu, &antdiv->main_stats); + else if (hal->antenna_rx == RF_B) + rtw89_phy_antdiv_sts_instance_add(rtwdev, phy_ppdu, &antdiv->aux_stats); +} + +static void rtw89_phy_antdiv_reg_init(struct rtw89_dev *rtwdev) +{ + rtw89_phy_write32_idx(rtwdev, R_P0_TRSW, B_P0_ANT_TRAIN_EN, + 0x0, RTW89_PHY_0); + rtw89_phy_write32_idx(rtwdev, R_P0_TRSW, B_P0_TX_ANT_SEL, + 0x0, RTW89_PHY_0); + + rtw89_phy_write32_idx(rtwdev, R_P0_ANT_SW, B_P0_TRSW_TX_EXTEND, + 0x0, RTW89_PHY_0); + rtw89_phy_write32_idx(rtwdev, R_P0_ANT_SW, B_P0_HW_ANTSW_DIS_BY_GNT_BT, + 0x0, RTW89_PHY_0); + + rtw89_phy_write32_idx(rtwdev, R_P0_TRSW, B_P0_BT_FORCE_ANTIDX_EN, + 0x0, RTW89_PHY_0); + + rtw89_phy_write32_idx(rtwdev, R_RFSW_CTRL_ANT0_BASE, B_RFSW_CTRL_ANT_MAPPING, + 0x0100, RTW89_PHY_0); + + rtw89_phy_write32_idx(rtwdev, R_P0_ANTSEL, B_P0_ANTSEL_BTG_TRX, + 0x1, RTW89_PHY_0); + rtw89_phy_write32_idx(rtwdev, R_P0_ANTSEL, B_P0_ANTSEL_HW_CTRL, + 0x0, RTW89_PHY_0); + rtw89_phy_write32_idx(rtwdev, R_P0_ANTSEL, B_P0_ANTSEL_SW_2G, + 0x0, RTW89_PHY_0); + rtw89_phy_write32_idx(rtwdev, R_P0_ANTSEL, B_P0_ANTSEL_SW_5G, + 0x0, RTW89_PHY_0); +} + +static void rtw89_phy_antdiv_sts_reset(struct rtw89_dev *rtwdev) +{ + struct rtw89_antdiv_info *antdiv = &rtwdev->antdiv; + + rtw89_phy_antdiv_sts_instance_reset(&antdiv->target_stats); + rtw89_phy_antdiv_sts_instance_reset(&antdiv->main_stats); + rtw89_phy_antdiv_sts_instance_reset(&antdiv->aux_stats); +} + +static void rtw89_phy_antdiv_init(struct rtw89_dev *rtwdev) +{ + struct rtw89_antdiv_info *antdiv = &rtwdev->antdiv; + struct rtw89_hal *hal = &rtwdev->hal; + + if (!hal->ant_diversity) + return; + + antdiv->get_stats = false; + antdiv->rssi_pre = 0; + rtw89_phy_antdiv_sts_reset(rtwdev); + rtw89_phy_antdiv_reg_init(rtwdev); +} + static void rtw89_phy_stat_thermal_update(struct rtw89_dev *rtwdev) { struct rtw89_phy_stat *phystat = &rtwdev->phystat; @@ -4114,6 +4241,144 @@ void rtw89_phy_tx_path_div_track(struct rtw89_dev *rtwdev) &done); } +#define ANTDIV_MAIN 0 +#define ANTDIV_AUX 1 + +static void rtw89_phy_antdiv_set_ant(struct rtw89_dev *rtwdev) +{ + struct rtw89_hal *hal = &rtwdev->hal; + u8 default_ant, optional_ant; + + if (!hal->ant_diversity || hal->antenna_tx == 0) + return; + + if (hal->antenna_tx == RF_B) { + default_ant = ANTDIV_AUX; + optional_ant = ANTDIV_MAIN; + } else { + default_ant = ANTDIV_MAIN; + optional_ant = ANTDIV_AUX; + } + + rtw89_phy_write32_idx(rtwdev, R_P0_ANTSEL, B_P0_ANTSEL_CGCS_CTRL, + default_ant, RTW89_PHY_0); + rtw89_phy_write32_idx(rtwdev, R_P0_ANTSEL, B_P0_ANTSEL_RX_ORI, + default_ant, RTW89_PHY_0); + rtw89_phy_write32_idx(rtwdev, R_P0_ANTSEL, B_P0_ANTSEL_RX_ALT, + optional_ant, RTW89_PHY_0); + rtw89_phy_write32_idx(rtwdev, R_P0_ANTSEL, B_P0_ANTSEL_TX_ORI, + default_ant, RTW89_PHY_0); +} + +static void rtw89_phy_swap_hal_antenna(struct rtw89_dev *rtwdev) +{ + struct rtw89_hal *hal = &rtwdev->hal; + + hal->antenna_rx = hal->antenna_rx == RF_A ? RF_B : RF_A; + hal->antenna_tx = hal->antenna_rx; +} + +static void rtw89_phy_antdiv_decision_state(struct rtw89_dev *rtwdev) +{ + struct rtw89_antdiv_info *antdiv = &rtwdev->antdiv; + struct rtw89_hal *hal = &rtwdev->hal; + bool no_change = false; + u8 main_rssi, aux_rssi; + u8 main_evm, aux_evm; + u32 candidate; + + antdiv->get_stats = false; + antdiv->training_count = 0; + + main_rssi = rtw89_phy_antdiv_sts_instance_get_rssi(&antdiv->main_stats); + main_evm = rtw89_phy_antdiv_sts_instance_get_evm(&antdiv->main_stats); + aux_rssi = rtw89_phy_antdiv_sts_instance_get_rssi(&antdiv->aux_stats); + aux_evm = rtw89_phy_antdiv_sts_instance_get_evm(&antdiv->aux_stats); + + if (main_evm > aux_evm + ANTDIV_EVM_DIFF_TH) + candidate = RF_A; + else if (aux_evm > main_evm + ANTDIV_EVM_DIFF_TH) + candidate = RF_B; + else if (main_rssi > aux_rssi + RTW89_TX_DIV_RSSI_RAW_TH) + candidate = RF_A; + else if (aux_rssi > main_rssi + RTW89_TX_DIV_RSSI_RAW_TH) + candidate = RF_B; + else + no_change = true; + + if (no_change) { + /* swap back from training antenna to original */ + rtw89_phy_swap_hal_antenna(rtwdev); + return; + } + + hal->antenna_tx = candidate; + hal->antenna_rx = candidate; +} + +static void rtw89_phy_antdiv_training_state(struct rtw89_dev *rtwdev) +{ + struct rtw89_antdiv_info *antdiv = &rtwdev->antdiv; + u64 state_period; + + if (antdiv->training_count % 2 == 0) { + if (antdiv->training_count == 0) + rtw89_phy_antdiv_sts_reset(rtwdev); + + antdiv->get_stats = true; + state_period = msecs_to_jiffies(ANTDIV_TRAINNING_INTVL); + } else { + antdiv->get_stats = false; + state_period = msecs_to_jiffies(ANTDIV_DELAY); + + rtw89_phy_swap_hal_antenna(rtwdev); + rtw89_phy_antdiv_set_ant(rtwdev); + } + + antdiv->training_count++; + ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->antdiv_work, + state_period); +} + +void rtw89_phy_antdiv_work(struct work_struct *work) +{ + struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev, + antdiv_work.work); + struct rtw89_antdiv_info *antdiv = &rtwdev->antdiv; + + mutex_lock(&rtwdev->mutex); + + if (antdiv->training_count <= ANTDIV_TRAINNING_CNT) { + rtw89_phy_antdiv_training_state(rtwdev); + } else { + rtw89_phy_antdiv_decision_state(rtwdev); + rtw89_phy_antdiv_set_ant(rtwdev); + } + + mutex_unlock(&rtwdev->mutex); +} + +void rtw89_phy_antdiv_track(struct rtw89_dev *rtwdev) +{ + struct rtw89_antdiv_info *antdiv = &rtwdev->antdiv; + struct rtw89_hal *hal = &rtwdev->hal; + u8 rssi, rssi_pre; + + if (!hal->ant_diversity || hal->ant_diversity_fixed) + return; + + rssi = rtw89_phy_antdiv_sts_instance_get_rssi(&antdiv->target_stats); + rssi_pre = antdiv->rssi_pre; + antdiv->rssi_pre = rssi; + rtw89_phy_antdiv_sts_instance_reset(&antdiv->target_stats); + + if (abs((int)rssi - (int)rssi_pre) < ANTDIV_RSSI_DIFF_TH) + return; + + antdiv->training_count = 0; + ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->antdiv_work, 0); +} + static void rtw89_phy_env_monitor_init(struct rtw89_dev *rtwdev) { rtw89_phy_ccx_top_setting_init(rtwdev); @@ -4133,6 +4398,9 @@ void rtw89_phy_dm_init(struct rtw89_dev *rtwdev) rtw89_phy_dig_init(rtwdev); rtw89_phy_cfo_init(rtwdev); rtw89_phy_ul_tb_info_init(rtwdev); + rtw89_phy_antdiv_init(rtwdev); + rtw89_chip_rfe_gpio(rtwdev); + rtw89_phy_antdiv_set_ant(rtwdev); rtw89_phy_init_rf_nctl(rtwdev); rtw89_chip_rfk_init(rtwdev); |