/**************************************************************************** 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. ****************************************************************************/ /* os shim includes */ #include "iot_config.h" #include "os_types.h" #include "os_utils.h" #include "hw_reg_api.h" #include "iot_errno_api.h" #include "iot_mem.h" /* driver includes */ #include "phy_nf.h" #include "phy_bb.h" #include "os_timer_api.h" #include "phy_rxtd_reg.h" #include "mac_sys_reg.h" #include "iot_io.h" #include "hw_phy_api.h" #include "iot_system.h" #include "phy_ana.h" #include "granite_reg.h" #include "phy_status.h" #include "iot_adc.h" #include "phy_phase.h" #include "os_utils_api.h" #define CAL_NF_INVAILD_PHASE (PLC_PHASE_C + 1) typedef enum{ CAL_NF_PHASE_STATE_IDLE = 0, CAL_NF_PHASE_STATE_ON_GOING = 1, CAL_NF_PHASE_STATE_COMPLETED = 2, CAL_NF_PHASE_STATE_FAIL = 3, } CAL_NF_PHASE_STATE; /* callback for phy call mac dsr function */ phy_call_mac_dsr_cb_t phy_call_mac_dsr_cb = NULL; /* callback for phy call mac spur function */ phy_call_mac_spur_cb_t phy_call_mac_spur_cb = NULL; /* callback for phy call mac scan band function */ phy_call_mac_scan_band_cb_t phy_call_mac_scan_band_cb = NULL; void register_phy_call_mac_dsr_cb(phy_call_mac_dsr_cb_t cb) { phy_call_mac_dsr_cb = cb; } void register_phy_call_mac_spur_cb(phy_call_mac_spur_cb_t cb) { phy_call_mac_spur_cb = cb; } void register_phy_call_mac_scan_band_cb(phy_call_mac_scan_band_cb_t cb) { phy_call_mac_scan_band_cb = cb; } uint8_t IRAM_ATTR phy_agc_acc_dly_get(void) { uint32_t tmp = 0; uint8_t dly_exp = 0; /* * get 20ms dly for different acc step * 192/ 384/ 768/ 1536/ 3072/ 6144/ */ tmp = PHY_RXTD_READ_REG(CFG_BB_AGC_ACC_STEP_ADDR); uint32_t acc_step = REG_FIELD_GET(SW_AGC_ACC_STEP_HS, tmp); if (acc_step == 0) { dly_exp = 13; } else if (acc_step == 1) { dly_exp = 12; } else if (acc_step == 2) { dly_exp = 11; } else if (acc_step == 3) { dly_exp = 10; } else if (acc_step == 4) { dly_exp = 9; } else if (acc_step == 4) { dly_exp = 8; } else { dly_exp = 10; } return dly_exp; } #if PLC_SUPPORT_3PHASE_NF static void IRAM_ATTR phy_cal_nf_start() { /* get dly depend on ACC_STEP */ uint8_t dly_exp = phy_agc_acc_dly_get(); uint32_t tmp = PHY_RXTD_READ_REG(CFG_BB_AGC_NOISE_CAL_ADDR); /* config dly */ REG_FIELD_SET(SW_CAL_NOISE_DLY_EXP, tmp, dly_exp); /* trig again */ REG_FIELD_SET(SW_CAL_NOISE_START, tmp, 1); PHY_RXTD_WRITE_REG(CFG_BB_AGC_NOISE_CAL_ADDR, tmp); /* clear cal nf cnt */ g_phy_ctxt.dep.cal_nf_cnt = 0; } static uint32_t IRAM_ATTR phy_cal_nf_get_nf() { uint32_t tmp = PHY_RXTD_READ_REG(CFG_BB_AGC_NOISE_CAL_ADDR); return REG_FIELD_GET(SW_CAL_NOISE_PWR, tmp); } static uint32_t IRAM_ATTR phy_cal_nf_check_done() { uint32_t tmp = PHY_RXTD_READ_REG(CFG_BB_AGC_NOISE_CAL_ADDR); return REG_FIELD_GET(SW_CAL_NOISE_DONE, tmp); } static uint32_t IRAM_ATTR phy_cal_nf_get_phase() { uint32_t tmp = RGF_MAC_READ_REG(CFG_RD_MACPHY_INTF_0_ADDR); return REG_FIELD_GET(PHY_RX_PHASE_SEL, tmp); } void phy_cal_nf_systick_stop() { #define PHY_CAL_NF_REQUIRE_TIMEOUT 50 if (!g_phy_cpu_share_ctxt.cal_3phase_nf_init) { return; } g_phy_ctxt.dep.cal_nf_stop = 1; uint32_t start_ms = os_boot_time32(); uint32_t span = 0; do { span = os_boot_time32() - start_ms; } while (g_phy_ctxt.dep.cal_nf_stop != 0 && span < PHY_CAL_NF_REQUIRE_TIMEOUT); if (g_phy_ctxt.dep.cal_nf_stop) { IOT_ASSERT(0); } } void phy_cal_nf_systick_start() { g_phy_ctxt.dep.cal_nf_triger = 1; } void phy_cal_nf_init() { g_phy_cpu_share_ctxt.cal_3phase_nf_init = 1; g_phy_ctxt.dep.cal_nf_stop = 0; g_phy_ctxt.dep.cal_nf_triger = 0; g_phy_ctxt.dep.cal_nf_running = 0; g_phy_cpu_share_ctxt.nf_phase[PLC_PHASE_A] = 0; g_phy_cpu_share_ctxt.nf_phase[PLC_PHASE_B] = 0; g_phy_cpu_share_ctxt.nf_phase[PLC_PHASE_C] = 0; g_phy_ctxt.dep.nf_cal_ms[PLC_PHASE_A] = 0; g_phy_ctxt.dep.nf_cal_ms[PLC_PHASE_B] = 0; g_phy_ctxt.dep.nf_cal_ms[PLC_PHASE_C] = 0; g_phy_ctxt.dep.cal_nf_last_phase = CAL_NF_INVAILD_PHASE; g_phy_ctxt.dep.cal_nf_phase_fsm[PLC_PHASE_A] = CAL_NF_PHASE_STATE_IDLE; g_phy_ctxt.dep.cal_nf_phase_fsm[PLC_PHASE_B] = CAL_NF_PHASE_STATE_IDLE; g_phy_ctxt.dep.cal_nf_phase_fsm[PLC_PHASE_C] = CAL_NF_PHASE_STATE_IDLE; } void IRAM_ATTR phy_cal_nf_fsm() { #define CAL_NF_TIMEOUT_MS 150 uint32_t cur_phase, last_phase; uint8_t cal_nf = PHY_NF_RST_VAL; if (g_phy_ctxt.dep.cal_nf_stop) { g_phy_ctxt.dep.cal_nf_stop = 0; /* reset fsm */ g_phy_ctxt.dep.cal_nf_triger = 0; g_phy_ctxt.dep.cal_nf_running = 0; return; } /* recalculate every second */ if (g_phy_ctxt.dep.cal_nf_triger) { g_phy_ctxt.dep.cal_nf_triger = 0; g_phy_ctxt.dep.cal_nf_running = 1; g_phy_ctxt.dep.nf_cal_ms[PLC_PHASE_A] = 0; g_phy_ctxt.dep.nf_cal_ms[PLC_PHASE_B] = 0; g_phy_ctxt.dep.nf_cal_ms[PLC_PHASE_C] = 0; g_phy_ctxt.dep.cal_nf_last_phase = CAL_NF_INVAILD_PHASE; g_phy_ctxt.dep.cal_nf_phase_fsm[PLC_PHASE_A] = CAL_NF_PHASE_STATE_IDLE; g_phy_ctxt.dep.cal_nf_phase_fsm[PLC_PHASE_B] = CAL_NF_PHASE_STATE_IDLE; g_phy_ctxt.dep.cal_nf_phase_fsm[PLC_PHASE_C] = CAL_NF_PHASE_STATE_IDLE; } if (!g_phy_ctxt.dep.cal_nf_running) { return; } cur_phase = phy_cal_nf_get_phase(); if (cur_phase == PLC_PHASE_ALL) { cur_phase = PLC_PHASE_A; } if (cur_phase > PLC_PHASE_C) { /* reset fsm */ g_phy_ctxt.dep.cal_nf_triger = 0; g_phy_ctxt.dep.cal_nf_running = 0; return; } last_phase = g_phy_ctxt.dep.cal_nf_last_phase; if (CAL_NF_INVAILD_PHASE == last_phase) { if (CAL_NF_PHASE_STATE_COMPLETED == g_phy_ctxt.dep.cal_nf_phase_fsm[cur_phase]) { return; } /* restart cal nf */ phy_cal_nf_start(); g_phy_ctxt.dep.cal_nf_phase_fsm[cur_phase] = CAL_NF_PHASE_STATE_ON_GOING; g_phy_ctxt.dep.cal_nf_last_phase = cur_phase; } else { if (last_phase != cur_phase) { g_phy_ctxt.dep.cal_nf_phase_fsm[last_phase] = CAL_NF_PHASE_STATE_FAIL; g_phy_ctxt.dep.cal_nf_last_phase = CAL_NF_INVAILD_PHASE; } else { if (phy_cal_nf_check_done()) { cal_nf = phy_cal_nf_get_nf(); if (cal_nf != PHY_NF_RST_VAL) { g_phy_cpu_share_ctxt.nf_phase[cur_phase] = cal_nf; g_phy_ctxt.dep.nf_cal_ms[cur_phase] = g_phy_ctxt.dep.cal_nf_cnt; g_phy_ctxt.dep.cal_nf_phase_fsm[cur_phase] = CAL_NF_PHASE_STATE_COMPLETED; g_phy_ctxt.dep.cal_nf_last_phase = CAL_NF_INVAILD_PHASE; if (g_phy_ctxt.dep.cal_nf_phase_fsm[PLC_PHASE_A] == CAL_NF_PHASE_STATE_COMPLETED && g_phy_ctxt.dep.cal_nf_phase_fsm[PLC_PHASE_B] == CAL_NF_PHASE_STATE_COMPLETED && g_phy_ctxt.dep.cal_nf_phase_fsm[PLC_PHASE_C] == CAL_NF_PHASE_STATE_COMPLETED) { g_phy_ctxt.dep.cal_nf_running = 0; } } else { /* restart cal nf */ phy_cal_nf_start(); } } else { g_phy_ctxt.dep.cal_nf_cnt++; if (g_phy_ctxt.dep.cal_nf_cnt >= CAL_NF_TIMEOUT_MS) { /* restart cal nf */ phy_cal_nf_start(); } } } } } void phy_cal_nf_on_3phase() { uint32_t tmp; uint8_t origin_hs, phase_idx, tmp_nf_192p; uint8_t rx_phase_force_en, rx_phase_force; /* save force value */ tmp = RGF_MAC_READ_REG(CFG_PHY_FORCE_0_ADDR); rx_phase_force_en = REG_FIELD_GET(CFG_PHY_RX_PHASE_SEL_FORCE_EN, tmp); rx_phase_force = REG_FIELD_GET(CFG_PHY_RX_PHASE_SEL, tmp); /* 192 point */ tmp = PHY_RXTD_READ_REG(CFG_BB_AGC_ACC_STEP_ADDR); /* backup hs */ origin_hs = (uint8_t)REG_FIELD_GET(SW_AGC_ACC_STEP_HS, tmp); REG_FIELD_SET(SW_AGC_ACC_STEP_HS, tmp, PHY_AGC_ACC_STEP_192P); PHY_RXTD_WRITE_REG(CFG_BB_AGC_ACC_STEP_ADDR, tmp); for (phase_idx = PLC_PHASE_A; phase_idx <= PLC_PHASE_C; phase_idx++) { phy_rx_phase_force_set_on_dump(true, phase_idx); tmp_nf_192p = phy_rx_nf_by_rxtd_get(phy_agc_acc_dly_get()); if (tmp_nf_192p != PHY_NF_RST_VAL) { g_phy_cpu_share_ctxt.nf_phase[phase_idx] = tmp_nf_192p; } } g_phy_ctxt.dep.nf = max(g_phy_cpu_share_ctxt.nf_phase[PLC_PHASE_A], max(g_phy_cpu_share_ctxt.nf_phase[PLC_PHASE_B], g_phy_cpu_share_ctxt.nf_phase[PLC_PHASE_C])); /* revert hs */ REG_FIELD_SET(SW_AGC_ACC_STEP_HS, tmp, origin_hs); PHY_RXTD_WRITE_REG(CFG_BB_AGC_ACC_STEP_ADDR, tmp); phy_rx_phase_force_set_on_dump(rx_phase_force_en, rx_phase_force); } #else void phy_cal_nf_systick_stop() { } void IRAM_ATTR phy_cal_nf_fsm() { } void phy_cal_nf_init() { g_phy_cpu_share_ctxt.cal_3phase_nf_init = 0; } void phy_cal_nf_on_3phase() { } void phy_cal_nf_systick_start() { } #endif /* PLC_SUPPORT_3PHASE_NF */ void phy_snr_cal_timer_handler() { #if HW_PLATFORM >= HW_PLATFORM_FPGA static uint8_t cnt = 0; iot_phy_sts_info_t total_sts = {0}; uint8_t rodata = 0; uint32_t phy_status = 0; if (g_phy_cpu_share_ctxt.cal_3phase_nf_init) { g_phy_ctxt.dep.nf = max(g_phy_cpu_share_ctxt.nf_phase[PLC_PHASE_A], max(g_phy_cpu_share_ctxt.nf_phase[PLC_PHASE_B], g_phy_cpu_share_ctxt.nf_phase[PLC_PHASE_C])); /* print current noise floor */ iot_printf("[PHY] a_nf:%d, t_ms:%lu, b_nf:%d, t_ms:%lu, " "c_nf:%d, t_ms:%d\n", g_phy_cpu_share_ctxt.nf_phase[PLC_PHASE_A], g_phy_ctxt.dep.nf_cal_ms[PLC_PHASE_A], g_phy_cpu_share_ctxt.nf_phase[PLC_PHASE_B], g_phy_ctxt.dep.nf_cal_ms[PLC_PHASE_B], g_phy_cpu_share_ctxt.nf_phase[PLC_PHASE_C], g_phy_ctxt.dep.nf_cal_ms[PLC_PHASE_C]); phy_cal_nf_systick_start(); } else { /* check cal noise done */ uint32_t tmp = PHY_RXTD_READ_REG(CFG_BB_AGC_NOISE_CAL_ADDR); if(REG_FIELD_GET(SW_CAL_NOISE_DONE,tmp)) { /*121 is reset value, not valid value*/ if(REG_FIELD_GET(SW_CAL_NOISE_PWR,tmp) != PHY_NF_RST_VAL){ g_phy_ctxt.dep.nf = REG_FIELD_GET(SW_CAL_NOISE_PWR,tmp); } } /* update cpu share nf */ tmp = PHY_RXTD_READ_REG(CFG_BB_AGC_ACC_STEP_ADDR); switch(REG_FIELD_GET(SW_AGC_ACC_STEP_HS, tmp)) { case 0: g_phy_cpu_share_ctxt.nf_192p = g_phy_ctxt.dep.nf; break; case 1: g_phy_cpu_share_ctxt.nf_384p = g_phy_ctxt.dep.nf; break; case 2: g_phy_cpu_share_ctxt.nf_768p = g_phy_ctxt.dep.nf; break; case 3: g_phy_cpu_share_ctxt.nf_1536p = g_phy_ctxt.dep.nf; break; case 4: g_phy_cpu_share_ctxt.nf_3072p = g_phy_ctxt.dep.nf; break; case 5: g_phy_cpu_share_ctxt.nf_6144p = g_phy_ctxt.dep.nf; break; default: break; } /* get dly depend on ACC_STEP */ uint32_t dly_exp = phy_agc_acc_dly_get(); /* config dly */ tmp = PHY_RXTD_READ_REG(CFG_BB_AGC_NOISE_CAL_ADDR); REG_FIELD_SET(SW_CAL_NOISE_DLY_EXP, tmp, dly_exp); PHY_RXTD_WRITE_REG(CFG_BB_AGC_NOISE_CAL_ADDR, tmp); /* trig again */ tmp = PHY_RXTD_READ_REG(CFG_BB_AGC_NOISE_CAL_ADDR); REG_FIELD_SET(SW_CAL_NOISE_START, tmp, 1); PHY_RXTD_WRITE_REG(CFG_BB_AGC_NOISE_CAL_ADDR, tmp); /* print current noise floor */ iot_printf("[PHY] nf:%d, rx_phase:%d\n", g_phy_ctxt.dep.nf, (RGF_MAC_READ_REG(CFG_RD_MACPHY_INTF_0_ADDR) & PHY_RX_PHASE_SEL_MASK) >> PHY_RX_PHASE_SEL_OFFSET); } /* print phy tx/rx cnt for each 4s */ if (phy_get_fw_mode() == MM_MODE && \ cnt >= 3) { phy_sts_get(&total_sts); iot_printf("mac tx ok:%d/4s, fc_ok:%d/4s, fc_err:%d/4s,", \ total_sts.mac_tx_ok_cnt, total_sts.fc_crc_ok_cnt, \ total_sts.fc_crc_fail_cnt); iot_printf("pld_ok:%d/4s, pld fail:%d/4s, sync ok:%d/4s\r\n", \ total_sts.pld_crc_ok_cnt, total_sts.pld_crc_fail_cnt, \ total_sts.sync_ok_cnt); uint8_t thd0_dft, thd1_dft; phy_rxfd_pkt_det_thd_get(&thd0_dft, &thd1_dft); iot_printf("rxfd_thd0:%d, rxfd_thd1:%d,", thd0_dft, thd1_dft); phy_ana_i2c_read(CFG_ANA_TOP_REG_ADDR, &phy_status, &rodata); iot_printf("ANA_TOP:%x ",phy_status); iot_printf("F_0:%x F_1:%x F_2:%x ",\ 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)); extern uint32_t mac_get_tx_rifs(); iot_printf("INTF_0:%x INTF_1:%x, agc_level:0x%x, rifs:%lu\r\n", \ RGF_MAC_READ_REG(CFG_RD_MACPHY_INTF_0_ADDR),\ RGF_MAC_READ_REG(CFG_RD_MACPHY_INTF_1_ADDR),\ PHY_RXTD_READ_REG(CFG_BB_AGC_GAIN_LEVEL_ADDR), mac_get_tx_rifs()); phy_get_granite_reg(); #if IOT_SMART_CONFIG /* just open update tempeerature on IOT preject */ iot_adc_temperature_val_update(); #endif /* update log cnt */ g_phy_ctxt.dep.phy_status.phy_rx_cnt.phy_rx_fc_ok_cnt += \ total_sts.fc_crc_ok_cnt; g_phy_ctxt.dep.phy_status.phy_rx_cnt.phy_rx_fc_fail_cnt += \ total_sts.fc_crc_fail_cnt; g_phy_ctxt.dep.phy_status.phy_rx_cnt.phy_rx_fc_fail_cnt_clr = \ total_sts.fc_crc_fail_cnt; g_phy_ctxt.dep.phy_status.phy_rx_cnt.phy_rx_pld_ok_cnt += \ total_sts.pld_crc_ok_cnt; g_phy_ctxt.dep.phy_status.phy_rx_cnt.phy_rx_pld_fail_cnt += \ total_sts.pld_crc_fail_cnt; g_phy_ctxt.dep.phy_status.phy_rx_cnt.phy_rx_pkt_cnt += \ total_sts.sync_ok_cnt; g_phy_ctxt.dep.phy_status.phy_tx_pkt_cnt += total_sts.mac_tx_ok_cnt; g_phy_ctxt.dep.phy_status.phy_tx_pkt_cnt_clr = total_sts.mac_tx_ok_cnt; cnt = 0; } else { cnt++; } /* overstress handle */ phy_overstress_timer_handler(); if (phy_call_mac_scan_band_cb) { phy_call_mac_scan_band_cb(); } if (phy_call_mac_spur_cb) { phy_call_mac_spur_cb(); } if (os_boot_time32() > 60000) { g_phy_cpu_share_ctxt.sym_num_fix_dis = 1; } #endif } void phy_timer_handle() { if (phy_call_mac_dsr_cb) { phy_call_mac_dsr_cb(); } } uint32_t phy_nf_timer_start() { uint32_t ret = ERR_FAIL; #if HW_PLATFORM >= HW_PLATFORM_FPGA if (g_phy_ctxt.dep.phy_snr_cal_timer == 0) { #if IOT_DTEST_ONLY_SUPPORT == 0 g_phy_ctxt.dep.phy_snr_cal_timer = \ os_create_timer(PLC_PHY_COMMON_MID, true, phy_timer_handle, NULL); #else g_phy_ctxt.dep.phy_snr_cal_timer = \ os_create_timer(PLC_PHY_COMMON_MID, true, phy_snr_cal_timer_handler, NULL); #endif os_start_timer( \ g_phy_ctxt.dep.phy_snr_cal_timer, \ PHY_SNR_CAL_TIMER_PERIOD); } #endif return ret; }