/**************************************************************************** Copyright(c) 2019 by Aerospace C.Power (Chongqing) Microelectronics. ALL RIGHTS RESERVED. This Information is proprietary to Aerospace C.Power (Chongqing) Microelectronics and MAY NOT be copied by any method or incorporated into another program without the express written consent of Aerospace C.Power. This Information or any portion thereof remains the property of Aerospace C.Power. The Information contained herein is believed to be accurate and Aerospace C.Power assumes no responsibility or liability for its use in any way and conveys no license or title under any patent or copyright and makes no representation or warranty that this Information is free from patent or copyright infringement. ****************************************************************************/ #include "chip_reg_base.h" #include "hw_reg_api.h" #include "hw_phy_api.h" #include "iot_errno_api.h" #include "mac_sys_reg.h" #include "phy_dfe_reg.h" #include "iot_io.h" #include "hw_tonemask.h" #include "phy_rxtd_reg.h" #include "phy_txrx_pwr.h" #include "phy_rx_fd_reg.h" #include "phy_tx_reg.h" #include "iot_utils_api.h" #include "iot_share_task.h" #include "plc_mpdu_header.h" #include "iot_module_api.h" #include "iot_pkt_api.h" #include "phy_data_ckb.h" #include "phy_reg.h" #include "phy_ana.h" #include "plc_protocol.h" #include "granite_reg.h" #include "ahb.h" #include "plc_cert_test.h" #include "iot_gpio_api.h" #include "iot_board_api.h" #include "iot_config.h" #include "phy_chn.h" #include "plc_const.h" #include "iot_system.h" #include "phy_perf.h" #include "math.h" #include "phy_dump.h" #include "phy_bbai_calu.h" #include "phy_math_tb.h" #include "phy_nf.h" #include "mp_mode.h" #if HW_PLATFORM >= HW_PLATFORM_FPGA #include "phy_tools.h" #include "phy_ada_dump.h" #endif #include "iot_oem_api.h" #include "os_utils_api.h" #include "clk.h" /* global callback function */ phy_ctxt_t g_phy_ctxt = {0}; /* callback for phy call mac bbai */ phy_call_mac_func_cb_t phy_call_mac_bbai_cb = NULL; /* callback for phy get cert mode */ phy_get_cert_mode_cb_t phy_get_cert_mode_cb = NULL; void register_phy_call_mac_bbai_cb(phy_call_mac_func_cb_t cb) { phy_call_mac_bbai_cb = cb; } void register_phy_get_cert_mode_cb(phy_get_cert_mode_cb_t cb) { phy_get_cert_mode_cb = cb; } void iot_phy_use_mac_func_to_est_chl(uint32_t time_ms) { if (phy_call_mac_bbai_cb == NULL) { iot_printf("%s is not register\n!", __FUNCTION__); return; } uint32_t ret = phy_call_mac_bbai_cb(time_ms); if (ret) { iot_printf("phy use mac api check spur fail:%d\n!", ret); } return; } uint32_t phy_get_cert_mode() { if (phy_get_cert_mode_cb) { return phy_get_cert_mode_cb(); } return 0; } void phy_channel_est_request(void) { uint32_t time_ms = PHY_CHN_EST_NF_UPDATE_PERIOD_MS + phy_chn_est_ai_period_ms_get() * PHY_CHN_EST_AI_CERT_RTY_CNT; iot_phy_use_mac_func_to_est_chl(time_ms); } uint8_t phy_cert_is_hw_agc() { return 1; } uint32_t phy_get_fw_mode(void) { uint32_t ret; #if ((IOT_MP_TX_MODE_ENABLE == 1) \ || (IOT_PT_BOARD_SELECT == 1) \ || (IOT_MP_RX_MODE_ENABLE == 1) \ || (IOT_MP_MODE_DIRECT_ENABLE == 1)) ret = MP_MODE; #else ret = g_fw_mode; #endif return ret; } /* channel pre-detect */ void phy_chn_est_pre_detect(void) { int8_t current_gain = 0; #if HW_PLATFORM == HW_PLATFORM_SILICON /* CPU switch to 25M */ clk_core_freq_slip_25m_set(); #endif /* force enter rx state */ phy_txrx_ovr_set(1,1); /* get rx gain before close swagc */ current_gain = phy_rxtd_gain_get(); /* clear shift en */ PHY_RXTD_WRITE_REG(CFG_BB_RXTD_SPARE2_ADDR, 0); /* not fix gain*/ phy_agc_gain_lvl_set(0,60,-24,0); /* enable power satuation and hw adjust gain req*/ phy_agc_sat_adj_set(0, 0); /* bb nf update */ phy_chn_nf_update(1); /* clear shift */ phy_gain_shift_set(0,0,0,0); #if HW_PLATFORM == HW_PLATFORM_SILICON /* CPU switch to 150M */ clk_core_freq_slip_150m_set(); #endif /* bb nf update again */ if (!phy_spike_shift_en_get()) phy_chn_nf_update(0); /* cal nf on 3phase */ phy_cal_nf_on_3phase(); /* notch filter and gain tbl init */ phy_perf_common_init(); /* delay for boot-hang */ os_delay(CHIP_HANG_DELAY); #if PHY_BB_AI_WITH_PULSE_CHECK_EN /* bb ai */ phy_chn_est_ai(current_gain, \ PHY_CHN_EST_AI_RTY_CNT, PHY_CHN_EST_AI_TIMEOUT); /* spike check */ phy_chn_spike_check(); /* init pulse config */ phy_chan_est_flag_clear(); phy_anti_pulse_set_clr(); /* check cnt */ uint32_t scan_cnt = PHY_CHN_EST_PRE_DET_CNT; while(scan_cnt--) { /* channel estimate start */ phy_chn_est_cb( \ g_phy_ctxt.dep.band_id, \ &g_phy_ctxt.indep.chn_est ); } /* clear flag for next check when receive bcn */ phy_chan_est_flag_clear(); #else if(g_phy_ctxt.indep.work_mode == PHY_MODE_NORMAL) { /* bb ai */ #if HW_PLATFORM == HW_PLATFORM_SILICON phy_anti_spur_set_clr(); /* currently FPGA can't simu this behavior */ phy_chn_est_ai(current_gain, \ PHY_CHN_EST_AI_RTY_CNT, PHY_CHN_EST_AI_TIMEOUT); #else (void)current_gain; #endif /* spike check */ phy_chn_spike_check(); } else if(g_phy_ctxt.indep.work_mode == PHY_MODE_TEST) { /* init flag and spur/pulse config */ phy_chan_est_flag_clear(); phy_anti_spur_set_clr(); phy_anti_pulse_set_clr(); /* check cnt */ uint32_t scan_cnt = PHY_CHN_EST_PRE_DET_CNT; while(scan_cnt--) { /* channel estimate start */ phy_chn_est_cb( \ g_phy_ctxt.indep.chn.band_id, \ &g_phy_ctxt.indep.chn_est ); } /* clear flag for next check when receive bcn */ phy_chan_est_flag_clear(); } #endif if(g_phy_cpu_share_ctxt.high_perf_en){ phy_high_perf_set(1); } #if (PHY_HIGH_PERF_EN == 1) || \ (PHY_CHIP_CERT_EN == 1) phy_high_perf_set(1); #endif #if PHY_CHIP_CERT_EN /*always mask the spur for cert*/ if (g_phy_ctxt.dep.band_id == IOT_SUPPORT_TONE_100_230) { /* mask 1M spur by notch filter */ phy_anf_option_set(PHY_ANF_MODE_FIX,1,1,0x8073); /* mask 6M spur by notch filter */ phy_anf_option_set(PHY_ANF_MODE_FIX,1,2,0x8fd5); /* mask 3M spur by spur mask, [-7,7] */ phy_spur_mask_set(123,15); } else if (g_phy_ctxt.dep.band_id == IOT_SUPPORT_TONE_32_120) { /* mask 2M spur by notch filter */ phy_anf_option_set(PHY_ANF_MODE_FIX,1,1,0x81ca); /* mask 5M spur by notch filter */ phy_anf_option_set(PHY_ANF_MODE_FIX,1,2,0x8b10); /* mask 2M spur by spur mask, [-7,7] */ phy_spur_mask_set(82,15); } #endif /* release force */ phy_txrx_ovr_set(0,0); /* recover force phase */ /* disable irq */ os_disable_irq(); phy_set_rx_abort_rx_phase_force_from_isr(false, g_phy_cpu_share_ctxt.rx_phase_force_en, (uint8_t)g_phy_cpu_share_ctxt.rx_phase_force); /* enable irq */ os_enable_irq(); } uint32_t phy_chn_est_ai_by_time(uint32_t time_ms) { uint32_t est_success_cnt = 0; #if HW_PLATFORM >= HW_PLATFORM_FPGA uint32_t est_rty_cnt = 0; uint32_t band_id = phy_band_id_get(); int8_t current_gain = 0; /* force enter rx state */ phy_txrx_ovr_set(1,1); /* get rx gain before close swagc */ current_gain = phy_rxtd_gain_get(); /* clear shift en */ PHY_RXTD_WRITE_REG(CFG_BB_RXTD_SPARE2_ADDR, 0); /* not fix gain*/ phy_agc_gain_lvl_set(0,60,-24,0); /* cal nf fast */ g_phy_ctxt.dep.cal_nf_fast_flag = 1; #if PHY_HW_SPIKE_OPTIMIZATION /* update nf */ phy_chn_nf_update(1); if (!phy_spike_shift_en_get()) phy_chn_nf_update(0); #else /* must wait for swagc one cycle done, then clr reference config to avoid overwrite */ uint8_t tmp_nf = phy_rx_nf_by_rxtd_get(phy_agc_acc_dly_get()); if (tmp_nf != PHY_NF_RST_VAL) { g_phy_cpu_share_ctxt.nf_192p = tmp_nf; } /* updata current nf */ phy_updata_nf_of_bbai(); #endif /* clear shift */ phy_gain_shift_set(0,0,0,0); /* notch filter and gain tbl init */ phy_perf_common_init(); phy_anti_spur_set_clr(); /* clear to avoid mask over for time-varying spur */ phy_tone_mask_amp_phase_tab_load( \ &all_mask_amp_phase_table, \ phy_mask_id_get(), \ PHY_PROTO_TYPE_GET()); /* init multiband special optimization */ if (band_id == IOT_SUPPORT_TONE_MULTI_BAND021) { phy_multi_band_opt_ena(band_id); } #if PHY_HW_SPIKE_OPTIMIZATION g_phy_ctxt.indep.sw_agc_force_off = 0; #else /* just kl1 need check */ g_phy_ctxt.indep.sw_agc_force_off = (phy_get_cert_mode() > 0); #endif /*clear spur/spike flag */ g_phy_cpu_share_ctxt.spur_exist = 0; g_phy_cpu_share_ctxt.spike_exist = 0; /* get retry cnt */ est_rty_cnt = (time_ms - PHY_CHN_EST_NF_UPDATE_PERIOD_MS) / \ phy_chn_est_ai_period_ms_get(); /* return successful cnt */ est_success_cnt = phy_chn_est_ai(current_gain, \ est_rty_cnt, \ time_ms - phy_chn_est_ai_period_ms_get()); /* spike check */ if (!g_phy_ctxt.indep.sw_agc_force_off){ phy_chn_spike_check(); } #if ((PHY_HIGH_PERF_EN == 1) || (PHY_CHIP_CERT_EN == 1)) if (!g_phy_ctxt.indep.sw_agc_force_off){ phy_high_perf_set(1); } #endif /* release force */ phy_txrx_ovr_set(0,0); /* recover force phase */ /* disable irq */ os_disable_irq(); phy_set_rx_abort_rx_phase_force_from_isr(false, g_phy_cpu_share_ctxt.rx_phase_force_en, g_phy_cpu_share_ctxt.rx_phase_force); /* enable irq */ os_enable_irq(); /* recover cal nf */ g_phy_ctxt.dep.cal_nf_fast_flag = 0; iot_printf("spur check success cnt:%d\n", est_success_cnt); #else (void)time_ms; #endif return est_success_cnt; } static uint8_t phy_rx_get_nf_by_phase(uint8_t phase) { uint8_t nf_phase; #if PLC_SUPPORT_3PHASE_NF if (g_phy_cpu_share_ctxt.cal_3phase_nf_init) { nf_phase = g_phy_cpu_share_ctxt.nf_phase[phase]; } else { nf_phase = g_phy_ctxt.dep.nf; } #else (void)phase; nf_phase = g_phy_ctxt.dep.nf; #endif return nf_phase; } int8_t phy_rx_snr_cal(void *phy_info, uint8_t rx_phase) { /* fd snr */ int8_t fd_snr = 0; int8_t td_snr = 0; iot_phy_info_t *phy_ptr = (iot_phy_info_t *)phy_info; uint8_t nf_phase = phy_rx_get_nf_by_phase(rx_phase); /* cal pkt rssi */ if(phy_ptr) { /* cal fd snr */ fd_snr = (int8_t)PHY_SNR_LINEAR_CAL(phy_ptr->avg_snr); /* get td snr */ if(phy_ptr->agc_tbl_entry >= PHY_AGC_NB_GAIN_ENTRY_START) { td_snr = phy_ptr->adc_power - (phy_ptr->agc_tbl_entry - PHY_AGC_NB_GAIN_ENTRY_START - PHY_AGC_GAIN_ENTRY_OFFSET) - nf_phase - PHY_SNR_CAL_TH; #if PHY_DBG_EN iot_printf("%d,%d,%d,%u,%d\n", (int8_t)fd_snr, phy_ptr->adc_power - (phy_ptr->agc_tbl_entry - PHY_AGC_NB_GAIN_ENTRY_START - PHY_AGC_GAIN_ENTRY_OFFSET), phy_ptr->adc_power, phy_ptr->agc_tbl_entry, nf_phase); #endif } else { td_snr = phy_ptr->adc_power - (phy_ptr->agc_tbl_entry - PHY_AGC_GAIN_ENTRY_OFFSET) - nf_phase - PHY_SNR_CAL_TH; #if PHY_DBG_EN iot_printf("%d,%d,%d,%u,%d\n", (int8_t)fd_snr, phy_ptr->adc_power - (phy_ptr->agc_tbl_entry - PHY_AGC_GAIN_ENTRY_OFFSET), phy_ptr->adc_power, phy_ptr->agc_tbl_entry, nf_phase); #endif } uint32_t judge = 0; #if PHY_CAL_REASONABLE_SNR /* kl2/3 use td snr */ judge = 1; #else /* cal max */ if (fd_snr > td_snr) { judge = 1; } #endif if (judge) { return fd_snr; } else { return td_snr; } } else { #if PHY_DBG_EN iot_printf("[PHY]snr cal fail, phy_info pointer is null!\n"); #endif return ~0; } } int8_t phy_snr_mapping_minus10_90(int8_t raw_snr) { if(raw_snr > 90) { /* clip >90 to 90dB */ return 90; } else if(raw_snr < -10) { /* clip < -10 to -10dB */ return -10; } else { return raw_snr; } } void phy_dbg_sts_print() { iot_phy_sts_info_t total_sts = {0}; /* get rx and tx cnt and clr */ phy_sts_get(&total_sts); iot_printf(\ "[phy][dbg]tx_ok:%d/4s\n"\ "[phy][dbg]reg_tx_abort_cnt:%d/4s\n" #if DEBUG_CANNOT_SENDOUT_PKT "[phy][dbg]intr_tx_abort_cnt:%d\n" #endif "[phy][dbg]fc_ok:%d/4s, fc_err:%d/4s, "\ "pld_ok:%d/4s, pld_fail:%d/4s, sync_ok:%d/4s\n", \ total_sts.mac_tx_ok_cnt, \ total_sts.mac_tx_abort_cnt, #if DEBUG_CANNOT_SENDOUT_PKT g_phy_cpu_share_ctxt.phy_tx_abort_cnt, #endif total_sts.fc_crc_ok_cnt, total_sts.fc_crc_fail_cnt, \ total_sts.pld_crc_ok_cnt, total_sts.pld_crc_fail_cnt, \ total_sts.sync_ok_cnt); #if HW_PLATFORM >= HW_PLATFORM_FPGA /* sts print */ iot_printf( "[phy][dbg]agc_bus:0x%x, td0:0x%x, td1:0x%x, td2:0x%x, tx3:0x%x, "\ "td_fsm:0x%x, fd_fsm:0x%x, force:0x%x\n", \ PHY_RXTD_READ_REG(CFG_AGC_DBG_BUS_ADDR), \ PHY_RXTD_READ_REG(CFG_RX_TD_DBG_BUS0_ADDR), \ PHY_RXTD_READ_REG(CFG_RX_TD_DBG_BUS1_ADDR), \ PHY_RXTD_READ_REG(CFG_RX_TD_DBG_BUS2_ADDR), \ PHY_RXTD_READ_REG(CFG_RX_TD_DBG_BUS3_ADDR), \ PHY_RXTD_READ_REG(CFG_RX_TD_FSM_DBG_BUS_ADDR), \ PHY_RXTD_READ_REG(CFG_RX_FD_FSM_DBG_BUS_ADDR), \ PHY_DFE_READ_REG(CFG_BB_DFE_OPTION_0_ADDR)); /* phy reg */ iot_printf( "[phy][dbg]rxtd_bus0:0x%x, bus1:0x%x, bus2:0x%x, bus3:0x%x\n", \ PHY_RXTD_READ_REG(CFG_RX_TD_DBG_BUS0_ADDR), \ PHY_RXTD_READ_REG(CFG_RX_TD_DBG_BUS1_ADDR), \ PHY_RXTD_READ_REG(CFG_RX_TD_DBG_BUS2_ADDR), \ PHY_RXTD_READ_REG(CFG_RX_TD_DBG_BUS3_ADDR)); iot_printf( "tx_td_bus:0x%x, tx_fd_fsm:0x%x, pld_fec:0x%x, fc_fec:0x%x, "\ "pre_bus:0x%x, agc_bus:0x%x\n", \ PHY_READ_REG(CFG_BB_TX_TD_DBG_BUS_ADDR), \ PHY_READ_REG(CFG_BB_TX_FD_FSM_DBG_BUS_ADDR), \ PHY_READ_REG(CFG_BB_PLD_FEC_DBG_BUS_ADDR), \ PHY_READ_REG(CFG_BB_FC_FEC_DBG_BUS_ADDR), \ PHY_READ_REG(CFG_BB_PRE_DBG_BUS_ADDR), \ PHY_READ_REG(CFG_AGC_DBG_BUS_ADDR)); iot_printf( "rtl_parse3:0x%x, rtl_parse2:0x%x, rtl_parse1:0x%x, rtl_parse0:0x%x\n", \ PHY_READ_REG(CFG_BB_RTL_PARSE_DBG_3_ADDR), \ PHY_READ_REG(CFG_BB_RTL_PARSE_DBG_2_ADDR), \ PHY_READ_REG(CFG_BB_RTL_PARSE_DBG_1_ADDR), \ PHY_READ_REG(CFG_BB_RTL_PARSE_DBG_0_ADDR)); iot_printf( "rx_fc0:0x%x, rx_fc1:0x%x, rx_fc2:0x%x, rx_fc3:0x%x\n", \ PHY_READ_REG(CFG_BB_RX_FC_RAW_0_ADDR), \ PHY_READ_REG(CFG_BB_RX_FC_RAW_1_ADDR), \ PHY_READ_REG(CFG_BB_RX_FC_RAW_2_ADDR), \ PHY_READ_REG(CFG_BB_RX_FC_RAW_3_ADDR)); iot_printf( "raw_intc0:0x%x, intc1:0x%x, intc2:0x%x, intc3:0x%x\n", \ PHY_READ_REG(CFG_BB_INT_RAW_0_ADDR), \ PHY_READ_REG(CFG_BB_INT_RAW_1_ADDR), \ PHY_READ_REG(CFG_BB_INT_RAW_2_ADDR), \ PHY_READ_REG(CFG_BB_INT_RAW_3_ADDR)); /* mac sts */ iot_printf( "force0:0x%x, force1:0x%x, force2:0x%x intf0:0x%x, intf1:0x%x\n", \ RGF_MAC_READ_REG(CFG_PHY_FORCE_0_ADDR), \ RGF_MAC_READ_REG(CFG_PHY_FORCE_1_ADDR), \ RGF_MAC_READ_REG(CFG_PHY_FORCE_2_ADDR), \ RGF_MAC_READ_REG(CFG_RD_MACPHY_INTF_0_ADDR), \ RGF_MAC_READ_REG(CFG_RD_MACPHY_INTF_1_ADDR)); /* analog sts */ phy_ana_dbg_print(); #endif } uint8_t phy_chn_nf_get(void) { return g_phy_ctxt.dep.nf; } uint8_t phy_chn_tx_power_get(void) { return (uint8_t)g_phy_ctxt.dep.sw_set_pwr; } bool_t phy_pkt_found_flag_get(void) { #if IOT_DTEST_ONLY_SUPPORT == 0 if(g_phy_cpu_share_ctxt.pm_status.fc_ok_found) { return true; } else { return false; } #else return true; #endif } void phy_pkt_found_flag_clr(void) { #if IOT_DTEST_ONLY_SUPPORT == 0 g_phy_cpu_share_ctxt.pm_status.fc_ok_found = 0; #endif } uint8_t phy_get_band_filter_gpio() { #if HW_PLATFORM >= HW_PLATFORM_FPGA return iot_board_get_gpio(GPIO_BAND_FILTER); #else return 0xff; #endif } void phy_cfg_band_filter_gpio(uint8_t protocol_band_id) { #if HW_PLATFORM >= HW_PLATFORM_FPGA uint8_t gpio_pin = phy_get_band_filter_gpio(); if (gpio_pin != 0xff) { if (protocol_band_id == IOT_SUPPORT_TONE_80_490 || \ protocol_band_id == IOT_SUPPORT_TONE_100_230 ||\ protocol_band_id == IOT_SUPPORT_TONE_240_370) { /* not keep 700K filter for power saving * cur enable band filter, would increase power */ iot_gpio_value_set((int)gpio_pin, 1); } else { iot_gpio_value_set((int)gpio_pin, 0); } } #else (void)protocol_band_id; #endif } void phy_init_band_filter_gpio() { #if HW_PLATFORM >= HW_PLATFORM_FPGA uint8_t gpio_pin = phy_get_band_filter_gpio(); if (gpio_pin != 0xff) { iot_gpio_open_as_output((int)gpio_pin); } #endif } void phy_det_tone_ext_en_set(bool_t en) { g_phy_ctxt.indep.det_tone_extend_en = en; } bool_t phy_det_tone_ext_en_get() { return (bool_t)(g_phy_ctxt.indep.det_tone_extend_en); } void phy_rise_pwr_flag_set(bool_t en) { g_phy_ctxt.indep.chn.is_pwr_rise = en; } phy_ctxt_t *phy_ctxt_get() { /* plc phy ctxt */ return &g_phy_ctxt; } void phy_updata_nf_of_bbai() { if (g_phy_ctxt.dep.nf) { g_phy_cpu_share_ctxt.nf_for_bbai = g_phy_ctxt.dep.nf; } else { g_phy_cpu_share_ctxt.nf_for_bbai = g_phy_cpu_share_ctxt.nf_768p; } iot_printf("updata bbai nf:%u\n", \ g_phy_cpu_share_ctxt.nf_for_bbai); } uint32_t phy_get_nf_of_bbai() { return g_phy_cpu_share_ctxt.nf_for_bbai; } void phy_cert_check_spike() { extern uint8_t mac_get_cert_test_mode(); extern uint8_t mac_cert_get_spike_pd_detect_en(); uint8_t cert_mode = mac_get_cert_test_mode(); uint8_t cert_spike_detect_en = mac_cert_get_spike_pd_detect_en(); if (g_phy_ctxt.indep.work_mode == PHY_MODE_TEST && cert_mode == CERT_TEST_CMD_ENTER_PHY_T && cert_spike_detect_en && g_phy_ctxt.dep.nf != PHY_NF_RST_VAL && g_phy_ctxt.dep.nf >= 73) { phy_spike_shift_en_set(1); phy_chn_spike_check(); } } uint32_t phy_is_sta_role() { uint32_t client_mode; #if HW_PLATFORM == HW_PLATFORM_SIMU extern uint8_t ucIsClientMode; client_mode = ucIsClientMode; #else /* HW_PLATFORM == HW_PLATFORM_SIMU */ extern uint32_t g_is_sta; client_mode = (uint8_t)g_is_sta; #endif /* HW_PLATFORM == HW_PLATFORM_SIMU */ return client_mode; }