1023 lines
35 KiB
C
1023 lines
35 KiB
C
/****************************************************************************
|
|
|
|
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 "iot_config.h"
|
|
#include "phy_bbai_calu.h"
|
|
#include "phy_dump.h"
|
|
#include "phy_bb.h"
|
|
#include "os_types.h"
|
|
#include "hw_reg_api.h"
|
|
#include "iot_io.h"
|
|
#include "mac_sys_reg.h"
|
|
#include "iot_errno_api.h"
|
|
#include "hw_tonemask.h"
|
|
#include "phy_ana.h"
|
|
#include "phy_bb.h"
|
|
#include "phy_dfe_reg.h"
|
|
#include "phy_data.h"
|
|
#include "hw_phy_api.h"
|
|
#include "phy_phase.h"
|
|
#include "math.h"
|
|
#include "phy_ana.h"
|
|
#include "math_log10.h"
|
|
#include "hw_phy_api.h"
|
|
#include "phy_dump_hw.h"
|
|
#include "phy_tools.h"
|
|
#include "phy_perf.h"
|
|
#include "phy_math_tb.h"
|
|
|
|
#if PHY_BBAI_ALGORITHM == PHY_BBAI_FIX_WINDOWS
|
|
|
|
#define PHY_CHN_EST_AI_SPUR_LEN 500
|
|
|
|
/* spur array */
|
|
typedef struct _iot_phy_spur{
|
|
/* notch filter enable */
|
|
uint8_t notch_filter_en_cnt;
|
|
/* PHY_BBAI_FIX_WINDOWS :color
|
|
* PHY_BBAI_SLIDE_WINDOWS: is max spur
|
|
*/
|
|
uint8_t color;
|
|
/* tone number */
|
|
uint16_t tone_id;
|
|
/* center/sidelobe */
|
|
uint32_t spur_ratio;
|
|
/* spur occur cnt */
|
|
uint16_t spur_cnt;
|
|
} iot_phy_spur_t;
|
|
|
|
static uint32_t phy_spur_arry_append(iot_phy_spur_t *spur_buf, uint32_t buf_len,
|
|
uint16_t tone_id, uint32_t pwr_ratio, bool_t notch_en)
|
|
{
|
|
uint32_t ret = ERR_OK;
|
|
#if HW_PLATFORM >= HW_PLATFORM_FPGA
|
|
uint32_t i = 0;
|
|
bool_t tone_find_en = false;
|
|
uint32_t spur_buf_size = buf_len/sizeof(iot_phy_spur_t);
|
|
|
|
/* valid check */
|
|
IOT_ASSERT(spur_buf != NULL && buf_len > 0);
|
|
|
|
/*
|
|
* spur mask valid for inband only, notch filter for all.
|
|
*/
|
|
if (spur_buf[spur_buf_size - 1].tone_id != 0) {
|
|
/* check same tone_id */
|
|
for(i = 0; i < spur_buf_size; i++)
|
|
{
|
|
/* tone exist */
|
|
if (spur_buf[i].tone_id == tone_id) {
|
|
spur_buf[i].spur_cnt++;
|
|
spur_buf[i].spur_ratio = (spur_buf[i].spur_ratio > pwr_ratio) ?
|
|
spur_buf[i].spur_ratio :
|
|
pwr_ratio;
|
|
spur_buf[i].notch_filter_en_cnt += notch_en;
|
|
|
|
tone_find_en = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* if not exist */
|
|
if (tone_find_en != true) {
|
|
/* find the minimal spur */
|
|
uint32_t min_spur_idx = 0;
|
|
uint32_t min_spur_ratio = spur_buf[0].spur_ratio;
|
|
for (i = 0; i < spur_buf_size; i++) {
|
|
if (min_spur_ratio > spur_buf[i].spur_ratio) {
|
|
min_spur_ratio = spur_buf[i].spur_ratio;
|
|
min_spur_idx = i;
|
|
}
|
|
}
|
|
|
|
/* fill */
|
|
spur_buf[min_spur_idx].tone_id = tone_id;
|
|
spur_buf[min_spur_idx].spur_cnt = 1;
|
|
spur_buf[min_spur_idx].spur_ratio = pwr_ratio;
|
|
spur_buf[min_spur_idx].notch_filter_en_cnt = notch_en;
|
|
}
|
|
} else {
|
|
for(i = 0; i < spur_buf_size; i++)
|
|
{
|
|
/* tone exist */
|
|
if (spur_buf[i].tone_id == tone_id) {
|
|
spur_buf[i].spur_cnt++;
|
|
spur_buf[i].spur_ratio = (spur_buf[i].spur_ratio > pwr_ratio) ?
|
|
spur_buf[i].spur_ratio :
|
|
pwr_ratio;
|
|
spur_buf[i].notch_filter_en_cnt += notch_en;
|
|
break;
|
|
} else if (spur_buf[i].tone_id == 0) {
|
|
/* add new */
|
|
spur_buf[i].tone_id = tone_id;
|
|
spur_buf[i].spur_cnt++;
|
|
spur_buf[i].spur_ratio = pwr_ratio;
|
|
spur_buf[i].notch_filter_en_cnt += notch_en;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
#else
|
|
(void *)spur_buf;
|
|
(void)buf_len;
|
|
(void)tone_id;
|
|
(void)pwr_ratio;
|
|
(void)notch_en;
|
|
#endif
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void phy_chn_spur_arry_peak_extract(iot_phy_spur_t *spur_buf,
|
|
uint32_t buf_len, uint32_t est_rty_cnt)
|
|
{
|
|
uint32_t i = 0;
|
|
uint16_t spur_idx = 2;
|
|
uint32_t spur_total_len = 0;
|
|
|
|
/* valid check */
|
|
IOT_ASSERT(spur_buf != NULL && buf_len > 0);
|
|
|
|
/* clr current cnt */
|
|
g_phy_ctxt.dep.phy_status.spur_array[1] = 0;
|
|
/* cal total spur len */
|
|
spur_total_len = buf_len/sizeof(iot_phy_spur_t);
|
|
|
|
/* init first color */
|
|
if(spur_buf[0].tone_id == 0) {
|
|
return;
|
|
} else {
|
|
spur_buf[0].color = 1;
|
|
}
|
|
|
|
/* color the neighbouring tone */
|
|
for(i = 1; i < spur_total_len; i++)
|
|
{
|
|
if(spur_buf[i].tone_id == 0) {
|
|
break;
|
|
}
|
|
|
|
if(spur_buf[i].tone_id == (spur_buf[i-1].tone_id + 1)) {
|
|
spur_buf[i].color = spur_buf[i-1].color;
|
|
} else {
|
|
spur_buf[i].color = spur_buf[i-1].color + 1;
|
|
}
|
|
}
|
|
|
|
/* find peak by loop */
|
|
for(i = 0; i < spur_total_len -1; i++)
|
|
{
|
|
if(spur_buf[i].tone_id == 0) {
|
|
break;
|
|
}
|
|
|
|
if(spur_buf[i].color == (spur_buf[i+1].color)){
|
|
if(spur_buf[i].spur_ratio <= spur_buf[i+1].spur_ratio) {
|
|
spur_buf[i].tone_id = 0;
|
|
} else {
|
|
spur_buf[i+1].tone_id = spur_buf[i].tone_id;
|
|
spur_buf[i+1].spur_cnt = spur_buf[i].spur_cnt;
|
|
spur_buf[i+1].spur_ratio = spur_buf[i].spur_ratio;
|
|
spur_buf[i+1].notch_filter_en_cnt = spur_buf[i].notch_filter_en_cnt;
|
|
spur_buf[i].tone_id = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* save peak */
|
|
for(i = 0; i < spur_total_len; i++)
|
|
{
|
|
if(spur_buf[i].spur_cnt > (est_rty_cnt >> 1) &&
|
|
spur_buf[i].tone_id != 0) {
|
|
/* spur total num */
|
|
g_phy_ctxt.dep.phy_status.spur_array[0] += 1;
|
|
/* spur current num */
|
|
g_phy_ctxt.dep.phy_status.spur_array[1] += 1;
|
|
/* spur id */
|
|
if(spur_idx < PHY_LOG_SPUR_MAX_CNT) {
|
|
g_phy_ctxt.dep.phy_status.spur_array[spur_idx++] =
|
|
(uint16_t)(spur_buf[i].tone_id);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void phy_spur_high_pwr_handler(bool_t pulse_flag, uint16_t base_spur_id)
|
|
{
|
|
#if HW_PLATFORM >= HW_PLATFORM_FPGA
|
|
uint16_t notch_alpha = 0;
|
|
uint32_t band_id = phy_band_id_get();
|
|
|
|
/* find harmonic */
|
|
if ((pulse_flag == true) && (band_id == IOT_SUPPORT_TONE_100_230 ||
|
|
base_spur_id < PHY_SPUR_3M_DET_START)) {
|
|
/* dc block hp */
|
|
phy_dc_blk_alpha_step3_set(32);
|
|
iot_printf("dc blk alpha 32!\n");
|
|
|
|
if (band_id == IOT_SUPPORT_TONE_100_230) {
|
|
notch_alpha = phy_alpha_cal(123);
|
|
phy_anf_option_set(PHY_ANF_MODE_FIX, 1, 1, notch_alpha);
|
|
notch_alpha = phy_alpha_cal(164);
|
|
phy_anf_option_set(PHY_ANF_MODE_FIX, 1, 2, notch_alpha);
|
|
} else if (band_id == IOT_SUPPORT_TONE_32_120 ||
|
|
band_id == IOT_SUPPORT_TONE_MULTI_BAND021) {
|
|
notch_alpha = phy_alpha_cal(82);
|
|
phy_anf_option_set(PHY_ANF_MODE_FIX, 1, 1, notch_alpha);
|
|
notch_alpha = phy_alpha_cal(123);
|
|
phy_anf_option_set(PHY_ANF_MODE_FIX, 1, 2, notch_alpha);
|
|
}
|
|
} else {
|
|
/* if nf > 100 shutdown sw-agc */
|
|
if (g_phy_ctxt.dep.nf >= 100) {
|
|
/* 3M special */
|
|
if ((base_spur_id >= PHY_SPUR_3M_DET_START) &&
|
|
(base_spur_id <= PHY_SPUR_3M_DET_END)) {
|
|
/* shut dwon sw-agc */
|
|
phy_swagc_set(false);
|
|
g_phy_ctxt.indep.sw_agc_force_off = true;
|
|
|
|
/* dc block hp */
|
|
phy_dc_blk_alpha_step3_set(253);
|
|
} else if ((band_id == IOT_SUPPORT_TONE_100_230) &&
|
|
(base_spur_id >= PHY_SPUR_6M_DET_START) &&
|
|
(base_spur_id <= PHY_SPUR_6M_DET_END)) {
|
|
/* 6M pulse tgt pwr to 110 */
|
|
g_phy_cpu_share_ctxt.spur_exist = 0;
|
|
}
|
|
}
|
|
notch_alpha = phy_alpha_cal(base_spur_id);
|
|
phy_anf_option_set(PHY_ANF_MODE_FIX, 1, 2, notch_alpha);
|
|
phy_anf_option_set(PHY_ANF_MODE_FIX, 1, 1, notch_alpha);
|
|
}
|
|
|
|
phy_anf_sel_set(2);
|
|
phy_anf2_sel_set(2);
|
|
#else
|
|
(void)pulse_flag;
|
|
(void)base_spur_id;
|
|
#endif
|
|
}
|
|
|
|
static bool_t phy_pulse_check(iot_phy_spur_t *spur_buf,
|
|
uint32_t spur_total_len, uint16_t base_spur_id)
|
|
{
|
|
bool_t pulse_flag = false;
|
|
uint32_t harmonic_cnt = 0, harmonic1_cnt = 0, harmonic2_cnt = 0;
|
|
|
|
if (base_spur_id != 0) {
|
|
for(uint32_t i = 0; i < spur_total_len; i++)
|
|
{
|
|
/* find harmonic */
|
|
if ((spur_buf[i].tone_id / base_spur_id >= 1) &&
|
|
(spur_buf[i].tone_id % base_spur_id == 0)) {
|
|
harmonic_cnt++;
|
|
}
|
|
/* find harmonic1 -1 */
|
|
if ((spur_buf[i].tone_id / (base_spur_id - 1) >= 1) &&
|
|
(spur_buf[i].tone_id % (base_spur_id - 1) == 0)) {
|
|
harmonic1_cnt++;
|
|
}
|
|
/* find harmonic2 +1 */
|
|
if ((spur_buf[i].tone_id / (base_spur_id + 1) >= 1) &&
|
|
(spur_buf[i].tone_id % (base_spur_id + 1) == 0)) {
|
|
harmonic2_cnt++;
|
|
}
|
|
}
|
|
|
|
/* check pulse or spur */
|
|
if (harmonic_cnt >= PHY_PULSE_HARMONIC_THD ||
|
|
harmonic1_cnt >= PHY_PULSE_HARMONIC_THD ||
|
|
harmonic2_cnt >= PHY_PULSE_HARMONIC_THD) {
|
|
pulse_flag = true;
|
|
}
|
|
|
|
iot_printf("tone %d harmonic cnt:%d-%d-%d!\n",
|
|
base_spur_id, harmonic_cnt, harmonic1_cnt, harmonic2_cnt);
|
|
}
|
|
|
|
return pulse_flag;
|
|
}
|
|
|
|
static uint16_t phy_spur_arry_base_id_find(iot_phy_spur_t *spur_buf,
|
|
uint16_t max_spur_id)
|
|
{
|
|
uint32_t base_spur_id = 0;
|
|
|
|
if (max_spur_id != 0) {
|
|
for(uint32_t i = 0; i < max_spur_id; i++)
|
|
{
|
|
/* check */
|
|
if (max_spur_id%spur_buf[i].tone_id == 0 ||
|
|
(max_spur_id + 1)%spur_buf[i].tone_id == 0 ||
|
|
(max_spur_id - 1)%spur_buf[i].tone_id == 0) {
|
|
base_spur_id = spur_buf[i].tone_id;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* if not find */
|
|
if (base_spur_id == 0) {
|
|
base_spur_id = max_spur_id;
|
|
}
|
|
}
|
|
|
|
return (uint16_t)base_spur_id;
|
|
}
|
|
|
|
static uint32_t phy_spur_arry_peak_handler(iot_phy_spur_t *spur_buf,
|
|
uint32_t buf_len, uint32_t est_rty_cnt)
|
|
{
|
|
uint32_t ret = ERR_OK;
|
|
#if HW_PLATFORM >= HW_PLATFORM_FPGA
|
|
uint32_t spur_total_len = 0;
|
|
uint32_t max_ratio = 0;
|
|
uint16_t max_spur_id = 0, base_spur_id = 0;
|
|
uint16_t notch_alpha = 0;
|
|
uint16_t inband_tone_mask_curr = 0;
|
|
uint16_t inband_tone_mask_total = 0;
|
|
uint32_t cmp_thd_cnt = est_rty_cnt >> 1;
|
|
bool_t pulse_flag = false, spur_flag = false, spur6m_flag = false;
|
|
uint32_t band_id = phy_band_id_get();
|
|
uint32_t end_tone;
|
|
|
|
if (g_phy_cpu_share_ctxt.pt_mode_entry == 1) {
|
|
return ERR_NOSUPP;
|
|
}
|
|
|
|
/* valid check */
|
|
IOT_ASSERT(spur_buf != NULL && buf_len > 0);
|
|
|
|
/* first fft pwr full for band narrow */
|
|
if (band_id == IOT_SUPPORT_TONE_32_120 ||
|
|
band_id == IOT_SUPPORT_TONE_MULTI_BAND021) {
|
|
cmp_thd_cnt = (cmp_thd_cnt > 0) ? (cmp_thd_cnt - 1) : 0;
|
|
}
|
|
|
|
/* cal total spur len */
|
|
spur_total_len = buf_len/sizeof(iot_phy_spur_t);
|
|
/* cal max mask tone number */
|
|
inband_tone_mask_total = all_mask_band_table_r0_full.valid_tone_number/3;
|
|
/* scan all spur */
|
|
for (uint32_t i = 0; i < spur_total_len; i++) {
|
|
if (spur_buf[i].tone_id != 0) {
|
|
iot_printf("[BB_AI] spur: %u, cnt: %u!\n",
|
|
spur_buf[i].tone_id, spur_buf[i].spur_cnt);
|
|
|
|
/* check cnt */
|
|
if (spur_buf[i].spur_cnt > cmp_thd_cnt) {
|
|
/* check inband max masked number */
|
|
if (
|
|
(spur_buf[i].tone_id >= all_mask_band_table_r0_full.start_tone &&
|
|
spur_buf[i].tone_id <= all_mask_band_table_r0_full.end_tone) ||
|
|
(spur_buf[i].tone_id >= all_mask_band_table_r1_full.start_tone &&
|
|
spur_buf[i].tone_id <= all_mask_band_table_r1_full.end_tone)) {
|
|
if (inband_tone_mask_curr < inband_tone_mask_total) {
|
|
inband_tone_mask_curr++;
|
|
/* mask spur */
|
|
phy_spur_mask_set(spur_buf[i].tone_id,0);
|
|
iot_printf("[BB_AI] spur tone: %u mask done!\n",
|
|
spur_buf[i].tone_id);
|
|
} else {
|
|
/* do nothing for other inband tone */
|
|
continue;
|
|
}
|
|
} else {
|
|
/* mask spur */
|
|
phy_spur_mask_set(spur_buf[i].tone_id,0);
|
|
iot_printf("[BB_AI] spur tone: %u mask done!\n",
|
|
spur_buf[i].tone_id);
|
|
}
|
|
|
|
/* notch filter set */
|
|
if (spur_buf[i].notch_filter_en_cnt > cmp_thd_cnt) {
|
|
/* find max spur */
|
|
if (!g_phy_ctxt.indep.notch_filter_en) {
|
|
g_phy_ctxt.indep.notch_filter_en = true;
|
|
max_ratio = spur_buf[i].spur_ratio;
|
|
max_spur_id = spur_buf[i].tone_id;
|
|
} else if(max_ratio < spur_buf[i].spur_ratio &&
|
|
spur_buf[i].tone_id < 512) {
|
|
/* compare max */
|
|
max_ratio = spur_buf[i].spur_ratio;
|
|
max_spur_id = spur_buf[i].tone_id;
|
|
}
|
|
}
|
|
|
|
#if PHY_BB_AI_WITH_PULSE_CHECK_EN
|
|
if (spur_buf[i].tone_id == IOT_SPUR_8M_CENTER_TONE) {
|
|
phy_anti_spur_set(IOT_SUPPORT_TONE_80_490);
|
|
} else if(spur_buf[i].tone_id == IOT_SPUR_3M_CENTER_TONE) {
|
|
phy_anti_spur_set(IOT_SUPPORT_TONE_100_230);
|
|
} else if(spur_buf[i].tone_id == IOT_SPUR_2M_CENTER_TONE) {
|
|
phy_anti_spur_set(IOT_SUPPORT_TONE_32_120);
|
|
}
|
|
#endif
|
|
|
|
/* maybe 6M not detect because of notch thd */
|
|
if ((band_id == IOT_SUPPORT_TONE_100_230 ||
|
|
band_id == IOT_SUPPORT_TONE_MULTI_BAND021) &&
|
|
spur_buf[i].tone_id >= PHY_SPUR_6M_DET_START &&
|
|
spur_buf[i].tone_id <= PHY_SPUR_6M_DET_END) {
|
|
spur6m_flag = true;
|
|
}
|
|
|
|
spur_flag = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* not work for cert and other low pwr scenario */
|
|
if (phy_get_nf_of_bbai() >= PHY_CHN_HIGH_NOISE_NF_THD) {
|
|
/* find spur base id */
|
|
base_spur_id = phy_spur_arry_base_id_find(spur_buf, max_spur_id);
|
|
|
|
/* check pulse */
|
|
pulse_flag = phy_pulse_check(spur_buf, spur_total_len, base_spur_id);
|
|
|
|
/* diff noise and spur/pulse */
|
|
if (spur_flag) {
|
|
/* reduce warning */
|
|
if (band_id == IOT_SUPPORT_TONE_MULTI_BAND021) {
|
|
phy_rxfd_pkt_det_thd_set(32, 32);
|
|
} else {
|
|
phy_rxfd_pkt_det_thd_set(16, 32);
|
|
}
|
|
|
|
phy_band_tone_range_get(NULL, &end_tone);
|
|
if (end_tone <= 230) {
|
|
phy_ana_filter_set(63);
|
|
}
|
|
} else {
|
|
/* big nf, but not spur */
|
|
g_phy_ctxt.dep.big_nf_handle = 1;
|
|
if (band_id == IOT_SUPPORT_TONE_MULTI_BAND021) {
|
|
phy_rxfd_pkt_det_thd_set(32, 32);
|
|
} else {
|
|
/* more sensitive */
|
|
phy_rxfd_pkt_det_thd_set(8, 16);
|
|
}
|
|
|
|
/* dc block hp */
|
|
phy_dc_blk_alpha_step3_set(253);
|
|
|
|
/* clean notch filter */
|
|
phy_perf_common_init();
|
|
|
|
/* Must recover 8M high pass filter for att and noise
|
|
if not will worsen performance index */
|
|
phy_ana_filter_set(
|
|
(g_phy_ctxt.dep.band_8m_cap_set > 0) ?
|
|
g_phy_ctxt.dep.band_8m_cap_set : 36);
|
|
|
|
iot_printf("[BB_AI]spur flag:%d, bf 8M\n", spur_flag);
|
|
}
|
|
|
|
/* notch filter set */
|
|
if (max_ratio) {
|
|
g_phy_cpu_share_ctxt.spur_exist = 1;
|
|
|
|
/* spur handler */
|
|
phy_spur_high_pwr_handler(pulse_flag, base_spur_id);
|
|
} else if (spur6m_flag) {
|
|
/* tgt pwr to 110 */
|
|
g_phy_cpu_share_ctxt.spur_exist = 0;
|
|
|
|
/* 6M spur */
|
|
notch_alpha = phy_alpha_cal(246);
|
|
phy_anf_option_set(PHY_ANF_MODE_FIX, 1, 1, notch_alpha);
|
|
}
|
|
/* for kl1 */
|
|
#if !PHY_HW_SPIKE_OPTIMIZATION
|
|
if (band_id == IOT_SUPPORT_TONE_100_230) {
|
|
/* dc block hp */
|
|
phy_dc_blk_alpha_step3_set(32);
|
|
}
|
|
#endif
|
|
|
|
iot_printf("[BB_AI]ratio:%d, 6m:%d, max=%u, base=%u!\n",
|
|
max_ratio, spur6m_flag, max_spur_id, base_spur_id);
|
|
} else {
|
|
/* if big_nf_handle is true,
|
|
* indicates that nf has been recover,
|
|
* and recover threshold
|
|
*/
|
|
if (g_phy_ctxt.dep.big_nf_handle) {
|
|
g_phy_ctxt.dep.big_nf_handle = 0;
|
|
/* reduce warning */
|
|
if (band_id == IOT_SUPPORT_TONE_MULTI_BAND021) {
|
|
phy_rxfd_pkt_det_thd_set(32, 32);
|
|
} else {
|
|
phy_rxfd_pkt_det_thd_set(16, 32);
|
|
}
|
|
|
|
#if PHY_HW_SPIKE_OPTIMIZATION
|
|
if (IOT_SUPPORT_TONE_32_120 == band_id) {
|
|
phy_rxfd_pkt_det_thd_set(8, 16);
|
|
}
|
|
#endif
|
|
/* filter reset */
|
|
phy_ana_set_filter_init(band_id);
|
|
}
|
|
|
|
/* notch filter set */
|
|
if (max_ratio) {
|
|
g_phy_cpu_share_ctxt.spur_exist = 1;
|
|
notch_alpha = phy_alpha_cal(max_spur_id);
|
|
if (PHY_DFE_READ_REG(CFG_BB_ANF_1_ALPHA_BETA_ADDR) &
|
|
SW_ANF_OPTION1_MASK) {
|
|
phy_anf_option_set(PHY_ANF_MODE_FIX, 1, 2, notch_alpha);
|
|
} else {
|
|
phy_anf_option_set(PHY_ANF_MODE_FIX, 1, 1, notch_alpha);
|
|
}
|
|
phy_check_spur_cert_handle(notch_alpha);
|
|
iot_printf("[BB_AI] notch filter: %u enable!\n", max_spur_id);
|
|
}
|
|
}
|
|
|
|
/* find peak and output log */
|
|
phy_chn_spur_arry_peak_extract(spur_buf, buf_len, est_rty_cnt);
|
|
#else
|
|
(void *)spur_buf;
|
|
(void)buf_len;
|
|
(void)est_rty_cnt;
|
|
#endif
|
|
|
|
return ret;
|
|
}
|
|
|
|
static uint32_t phy_chn_est_data_process(uint32_t *csi_buf,
|
|
iot_phy_spur_t *spur_buf, int8_t *current_gain, uint8_t pkt_idx)
|
|
{
|
|
uint32_t ret = ERR_OK;
|
|
#if HW_PLATFORM >= HW_PLATFORM_FPGA
|
|
uint32_t j = 0;
|
|
int16_t csi_i = 0, csi_q = 0;
|
|
uint32_t center_pwr = 0;
|
|
uint32_t sidelobe_pwr = 0;
|
|
uint32_t dump_valid_cnt = 0;
|
|
uint64_t inband_pwr = 0;
|
|
uint64_t outband_pwr = 0;
|
|
uint32_t tone_idx = 0;
|
|
bool_t full_flag = false;
|
|
uint8_t pwr_ratio = 0;
|
|
uint32_t bbai_nf = phy_get_nf_of_bbai();
|
|
bool_t is_w_size_6 = false;
|
|
uint32_t ext_pwr = 0;
|
|
|
|
#if PHY_DEBUG_EN
|
|
/* cal csi for every tone for debug*/
|
|
for (tone_idx = 0; tone_idx < (IOT_PHY_CSI_BUF_LEN >> 2); tone_idx++) {
|
|
csi_i = (int16_t)(*(csi_buf + tone_idx) & 0xFFFF);
|
|
csi_q = (int16_t)(*(csi_buf + tone_idx) >> 16);
|
|
iot_printf("tone:%u, csi_i:%d, csi_q:%d, dB:%u\n",
|
|
tone_idx + pkt_idx * 512,
|
|
csi_i,
|
|
csi_q,
|
|
(uint32_t)(10 * mlog10(csi_i * csi_i + csi_q * csi_q + 1)));
|
|
}
|
|
#endif
|
|
|
|
/* cal outband total pwr */
|
|
outband_pwr = 0;
|
|
for (j = 1; j < PHY_CHN_VALID_TONE_NUM + 1; j++) {
|
|
csi_i = (int16_t)(*(csi_buf +
|
|
g_plc_band_tbl_r0[HW_FULL_BAND]->start_tone - j) & 0xFFFF);
|
|
csi_q = (int16_t)(*(csi_buf +
|
|
g_plc_band_tbl_r0[HW_FULL_BAND]->start_tone - j) >> 16);
|
|
outband_pwr += csi_i * csi_i + csi_q * csi_q;
|
|
}
|
|
/* cal outband average pwr */
|
|
outband_pwr = outband_pwr/PHY_CHN_VALID_TONE_NUM;
|
|
|
|
/* check outband pwr */
|
|
if (!outband_pwr) {
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
/* cal inband pwr */
|
|
for (j = 0; j < PHY_CHN_VALID_TONE_NUM; j++) {
|
|
csi_i = (int16_t)(*(csi_buf +
|
|
g_plc_band_tbl_r0[HW_FULL_BAND]->start_tone + j) & 0xFFFF);
|
|
csi_q = (int16_t)(*(csi_buf +
|
|
g_plc_band_tbl_r0[HW_FULL_BAND]->start_tone + j) >> 16);
|
|
inband_pwr = csi_i * csi_i + csi_q * csi_q;
|
|
/* pkt feature: inband > outband 10dB */
|
|
if (10 * mlog10(inband_pwr/outband_pwr) < PHY_FD_PKT_CHECK_THD) {
|
|
dump_valid_cnt += 1;
|
|
}
|
|
}
|
|
|
|
/* check valid dump */
|
|
if (dump_valid_cnt < (PHY_CHN_VALID_TONE_NUM >> 1)) {
|
|
#if PHY_DEBUG_EN
|
|
iot_printf("[BB_AI] find pkt, valid cnt:%u\n", dump_valid_cnt);
|
|
#endif
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
/* spur check: scan band 0-511 with special point */
|
|
for (j = PHY_CHN_EST_AI_SIDELOBE_NUM + 1;
|
|
j < (IOT_PHY_CSI_BUF_LEN >> 2) - PHY_CHN_EST_AI_SIDELOBE_NUM; j++) {
|
|
|
|
/* zero pwr */
|
|
center_pwr = 0;
|
|
sidelobe_pwr = 0;
|
|
ext_pwr = 0;
|
|
|
|
/* spur find loop */
|
|
for (tone_idx = j - PHY_CHN_EST_AI_SIDELOBE_NUM;
|
|
tone_idx <= j + PHY_CHN_EST_AI_SIDELOBE_NUM; tone_idx++) {
|
|
|
|
csi_i = (int16_t)(*(csi_buf + tone_idx) & 0xFFFF);
|
|
csi_q = (int16_t)(*(csi_buf + tone_idx) >> 16);
|
|
|
|
/* check full */
|
|
if ((csi_i > PHY_CHN_EST_AI_FULL_PWR ||
|
|
csi_i < -PHY_CHN_EST_AI_FULL_PWR) &&
|
|
(csi_q > PHY_CHN_EST_AI_FULL_PWR ||
|
|
csi_q < -PHY_CHN_EST_AI_FULL_PWR)) {
|
|
/* if current gain is not least gain,
|
|
* decrease gain and discard this data.
|
|
* else use this data.
|
|
*/
|
|
if (*current_gain != -PHY_AGC_GAIN_ENTRY_OFFSET) {
|
|
full_flag = true;
|
|
break;
|
|
}
|
|
} else {
|
|
if (tone_idx >= (j - PHY_CHN_EST_AI_W_SIZE_4) &&
|
|
tone_idx <= (j + PHY_CHN_EST_AI_W_SIZE_4)) {
|
|
center_pwr += csi_i * csi_i + csi_q * csi_q;
|
|
} else {
|
|
sidelobe_pwr += csi_i * csi_i + csi_q * csi_q;
|
|
}
|
|
if (tone_idx == j - PHY_CHN_EST_AI_W_SIZE_6 ||
|
|
tone_idx == j + PHY_CHN_EST_AI_W_SIZE_6 ) {
|
|
ext_pwr += csi_i * csi_i + csi_q * csi_q;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (full_flag) {
|
|
/* reint full flag */
|
|
full_flag = false;
|
|
uint8_t gain_step = ((bbai_nf > PHY_CHN_EST_AI_SPUR_NF_THD) ?
|
|
(PHY_CHN_EST_AI_GAIN_STEP << 1) : (PHY_CHN_EST_AI_GAIN_STEP));
|
|
/* decrease gain */
|
|
if ((*current_gain - gain_step + PHY_AGC_GAIN_ENTRY_OFFSET) > 0) {
|
|
*current_gain -= (int8_t)gain_step;
|
|
} else {
|
|
*current_gain = -PHY_AGC_GAIN_ENTRY_OFFSET;
|
|
}
|
|
|
|
iot_printf("[BB_AI] pwr full, decrease gain to:%d\n", *current_gain);
|
|
return ERR_FAIL;
|
|
} else {
|
|
|
|
is_w_size_6 = false;
|
|
windows:
|
|
/* check sidelobe_pwr */
|
|
if (!sidelobe_pwr) {
|
|
continue;
|
|
}
|
|
|
|
/* cal pwr ratio*/
|
|
pwr_ratio = center_pwr/sidelobe_pwr;
|
|
bool_t judge_spur_flag;
|
|
if ((center_pwr > PHY_CHN_EST_AI_SUPR_PWR_THD) &&
|
|
(bbai_nf > PHY_CHN_EST_AI_SPUR_NF_THD)) {
|
|
/* power > 24000000 and nf > 100 */
|
|
judge_spur_flag = true;
|
|
} else {
|
|
judge_spur_flag = (pwr_ratio > PHY_CHN_EST_AI_SPUR_THD);
|
|
}
|
|
|
|
if (judge_spur_flag) {
|
|
#if PHY_DEBUG_EN
|
|
iot_printf("[BB_AI] tone:%u, center_pwr:%u, ext_pwr:%u\n",
|
|
j + pkt_idx * (IOT_PHY_CSI_BUF_LEN >> 2),
|
|
center_pwr, sidelobe_pwr);
|
|
#endif
|
|
/* notch filter thd check */
|
|
bool_t judge_notch_flag;
|
|
if ((center_pwr > PHY_CHN_EST_AI_SUPR_PWR_THD) &&
|
|
(bbai_nf > PHY_CHN_EST_AI_SPUR_NF_THD)) {
|
|
/* power > 24000000 and nf > 100 */
|
|
judge_notch_flag = true;
|
|
} else {
|
|
judge_notch_flag =
|
|
(pwr_ratio > PHY_CHN_EST_AI_SPUR_NOTCH_THD);
|
|
}
|
|
if (judge_notch_flag) {
|
|
/* append to spur array with notch filter */
|
|
phy_spur_arry_append(spur_buf,
|
|
PHY_CHN_EST_AI_SPUR_LEN,
|
|
j + pkt_idx * (IOT_PHY_CSI_BUF_LEN >> 2),
|
|
center_pwr >> 5, true);
|
|
} else {
|
|
/* append to spur array without notch filter */
|
|
phy_spur_arry_append(spur_buf,
|
|
PHY_CHN_EST_AI_SPUR_LEN,
|
|
j + pkt_idx * (IOT_PHY_CSI_BUF_LEN >> 2),
|
|
center_pwr >> 5, false);
|
|
}
|
|
} else {
|
|
/* if find spur fail, adjust main windows form 4 to 6 */
|
|
if (is_w_size_6 == false) {
|
|
is_w_size_6 = true;
|
|
center_pwr += ext_pwr;
|
|
sidelobe_pwr -= ext_pwr;
|
|
goto windows;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#else
|
|
(void)csi_buf;
|
|
(void)spur_buf;
|
|
(void)current_gain;
|
|
(void)pkt_idx;
|
|
#endif
|
|
return ret;
|
|
}
|
|
|
|
static void phy_chn_est_sidelobe_process(uint32_t *csi_buf,
|
|
iot_phy_spur_t *spur_buf, int8_t *current_gain, uint8_t pkt_idx)
|
|
{
|
|
#if HW_PLATFORM >= HW_PLATFORM_FPGA
|
|
uint32_t j = 0;
|
|
int16_t csi_i = 0, csi_q = 0;
|
|
uint32_t center_pwr = 0;
|
|
uint32_t sidelobe_pwr = 0;
|
|
uint32_t tone_idx = 0;
|
|
bool_t full_flag = false;
|
|
#if PHY_DEBUG_EN
|
|
for (tone_idx = 0; tone_idx <= (PHY_CHN_EST_AI_SIDELOBE_NUM << 2);
|
|
tone_idx++) {
|
|
csi_i = (int16_t)(*(csi_buf + tone_idx) & 0xFFFF);
|
|
csi_q = (int16_t)(*(csi_buf + tone_idx) >> 16);
|
|
iot_printf("tone:%u, csi_i:%d, csi_q:%d, dB:%u\n",
|
|
tone_idx + pkt_idx * 512 - (PHY_CHN_EST_AI_SIDELOBE_NUM << 1),
|
|
csi_i, csi_q,
|
|
(uint32_t)(10 * mlog10(csi_i * csi_i + csi_q * csi_q + 1)));
|
|
}
|
|
#endif
|
|
|
|
/* spur check: scan band 0-24 with special point */
|
|
for (j = PHY_CHN_EST_AI_SIDELOBE_NUM;
|
|
j <= (PHY_CHN_EST_AI_SIDELOBE_NUM << 2) - PHY_CHN_EST_AI_SIDELOBE_NUM;
|
|
j++) {
|
|
/* zero pwr */
|
|
center_pwr = 0;
|
|
sidelobe_pwr = 0;
|
|
|
|
/* spur find loop */
|
|
for (tone_idx = j - PHY_CHN_EST_AI_SIDELOBE_NUM;
|
|
tone_idx <= j + PHY_CHN_EST_AI_SIDELOBE_NUM; tone_idx++) {
|
|
csi_i = (int16_t)(*(csi_buf + tone_idx) & 0xFFFF);
|
|
csi_q = (int16_t)(*(csi_buf + tone_idx) >> 16);
|
|
|
|
/* check full */
|
|
if((csi_i == PHY_CHN_EST_AI_FULL_PWR ||
|
|
csi_i == -PHY_CHN_EST_AI_FULL_PWR) &&
|
|
(csi_q == PHY_CHN_EST_AI_FULL_PWR ||
|
|
csi_q == -PHY_CHN_EST_AI_FULL_PWR)) {
|
|
full_flag = true;
|
|
break;
|
|
} else {
|
|
if(tone_idx >= (j - 2) && tone_idx <= (j + 2)) {
|
|
center_pwr += csi_i * csi_i + csi_q * csi_q;
|
|
} else {
|
|
sidelobe_pwr += csi_i * csi_i + csi_q * csi_q;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(full_flag) {
|
|
/* reint full flag */
|
|
full_flag = false;
|
|
/* decrease gain */
|
|
*current_gain -= (int8_t)PHY_CHN_EST_AI_GAIN_STEP;
|
|
iot_printf("[BB_AI] pwr full, decrease gain to:%d\n", *current_gain);
|
|
break;
|
|
} else {
|
|
/* check sidelobe_pwr */
|
|
if(!sidelobe_pwr) {
|
|
continue;
|
|
}
|
|
|
|
if(center_pwr/sidelobe_pwr > PHY_CHN_EST_AI_SPUR_THD) {
|
|
#if PHY_DEBUG_EN
|
|
iot_printf("[BB_AI] tone:%u, center_pwr:%u, ext_pwr:%u\n",
|
|
j + pkt_idx * (IOT_PHY_CSI_BUF_LEN >> 2) -
|
|
(PHY_CHN_EST_AI_SIDELOBE_NUM << 1),
|
|
center_pwr, sidelobe_pwr);
|
|
#endif
|
|
/* notch filter thd check */
|
|
if(center_pwr/sidelobe_pwr > PHY_CHN_EST_AI_SPUR_NOTCH_THD) {
|
|
/* append to spur array with notch filter */
|
|
phy_spur_arry_append(spur_buf,
|
|
PHY_CHN_EST_AI_SPUR_LEN,
|
|
j + pkt_idx * ((IOT_PHY_CSI_BUF_LEN >> 2) -
|
|
(PHY_CHN_EST_AI_SIDELOBE_NUM << 1)),
|
|
10 * mlog10(center_pwr/sidelobe_pwr), true);
|
|
} else {
|
|
/* append to spur array without notch filter */
|
|
phy_spur_arry_append(spur_buf,
|
|
PHY_CHN_EST_AI_SPUR_LEN,
|
|
j + pkt_idx * ((IOT_PHY_CSI_BUF_LEN >> 2) -
|
|
(PHY_CHN_EST_AI_SIDELOBE_NUM << 1)),
|
|
10 * mlog10(center_pwr/sidelobe_pwr), false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#else
|
|
(void)csi_buf;
|
|
(void)spur_buf;
|
|
(void)current_gain;
|
|
(void)pkt_idx;
|
|
#endif
|
|
}
|
|
|
|
uint32_t phy_chn_est_ai(int8_t current_gain, uint32_t est_rty_cnt,
|
|
uint32_t timeout_ms)
|
|
{
|
|
uint32_t success_cnt = 0;
|
|
#if HW_PLATFORM >= HW_PLATFORM_FPGA
|
|
uint32_t i = 0;
|
|
uint32_t ret = ERR_OK;
|
|
uint32_t start_time = 0, end_time = 0;
|
|
int64_t time_span = 0;
|
|
iot_pkt_t *pkt_buf = NULL;
|
|
iot_pkt_t *hash_buf = NULL;
|
|
uint32_t *csi_buf = NULL;
|
|
iot_phy_spur_t *spur_buf = NULL;
|
|
uint32_t *sidelobe_buf = NULL;
|
|
uint8_t pkt_idx = 0;
|
|
|
|
/* check dump busy flag */
|
|
if (phy_busy_get(&g_phy_ctxt, PHY_BUSY_DUMP)) {
|
|
iot_printf("phy dump busy!\n");
|
|
return ERR_BUSY;
|
|
} else {
|
|
phy_dump_busy_set(true);
|
|
}
|
|
|
|
/* get start time */
|
|
start_time = RGF_MAC_READ_REG(CFG_RD_NTB_ADDR);
|
|
|
|
/* get mem from iot_pkt to save csi data */
|
|
IOT_PKT_GET(pkt_buf, IOT_PHY_CSI_BUF_LEN, 0, PLC_PHY_COMMON_MID);
|
|
if(!pkt_buf){
|
|
iot_printf("phy chn est fatal error, iot_pkt_get fail\n");
|
|
phy_dump_busy_set(false);
|
|
return success_cnt;
|
|
}
|
|
csi_buf = (uint32_t *)iot_pkt_put(pkt_buf, IOT_PHY_CSI_BUF_LEN);
|
|
|
|
/* get mem from iot_pkt to save spur data and sidelobe */
|
|
IOT_PKT_GET(hash_buf,
|
|
PHY_CHN_EST_AI_SPUR_LEN + (PHY_CHN_EST_AI_SIDELOBE_NUM << 4) + 4,
|
|
0,
|
|
PLC_PHY_COMMON_MID);
|
|
if(!hash_buf){
|
|
iot_printf("phy chn est spur fatal error, iot_pkt_get fail\n");
|
|
/* free iot pkt */
|
|
iot_pkt_free(pkt_buf);
|
|
phy_dump_busy_set(false);
|
|
return success_cnt;
|
|
}
|
|
spur_buf = (iot_phy_spur_t *)iot_pkt_put(hash_buf, PHY_CHN_EST_AI_SPUR_LEN);
|
|
sidelobe_buf = (uint32_t *)spur_buf + (PHY_CHN_EST_AI_SPUR_LEN >> 2);
|
|
|
|
#if PHY_HW_SPIKE_OPTIMIZATION
|
|
/* NOTE: KL2/3 can not use max gain, need get average gain */
|
|
current_gain = phy_gain_get_from_agc();
|
|
if (current_gain > PHY_BBAI_GAIN_MAX) {
|
|
current_gain = PHY_BBAI_GAIN_MAX;
|
|
}
|
|
#endif
|
|
|
|
/* check csi buf pointer valid and flag */
|
|
if(csi_buf != NULL)
|
|
{
|
|
/* rst to trig enable */
|
|
phy_reset(PHY_RST_REASON_WARM);
|
|
|
|
/* get valid fft dump */
|
|
for(i = 0; i < est_rty_cnt; i++)
|
|
{
|
|
for(pkt_idx = 0; pkt_idx < FFT_DUMP_PKT_MAX; pkt_idx++) {
|
|
/* trig fft to dump */
|
|
ret = phy_rx_fft_dump(csi_buf, current_gain, pkt_idx, FFT_DUMP_PKT_MAX);
|
|
if (ret != ERR_OK) {
|
|
/* clr dump and close current dump */
|
|
phy_rx_fft_dump(csi_buf, current_gain,
|
|
FFT_DUMP_PKT_MAX - 1, FFT_DUMP_PKT_MAX);
|
|
break;
|
|
}
|
|
|
|
/* data process */
|
|
ret = phy_chn_est_data_process(
|
|
csi_buf, spur_buf, ¤t_gain, pkt_idx);
|
|
if(ret != ERR_OK) {
|
|
/* clr dump and close current dump */
|
|
phy_rx_fft_dump(csi_buf, current_gain,
|
|
FFT_DUMP_PKT_MAX - 1, FFT_DUMP_PKT_MAX);
|
|
break;
|
|
}
|
|
|
|
/* sidelobe data like 512-6~512+6 */
|
|
if(pkt_idx > 0) {
|
|
/* copy current pkt sidelobe */
|
|
os_mem_cpy(sidelobe_buf + (PHY_CHN_EST_AI_SIDELOBE_NUM << 1),
|
|
csi_buf,
|
|
(PHY_CHN_EST_AI_SIDELOBE_NUM << 3) + 4);
|
|
/* sidelobe data process */
|
|
phy_chn_est_sidelobe_process(
|
|
sidelobe_buf, spur_buf, ¤t_gain, pkt_idx);
|
|
}
|
|
/* save last pkt sidelobe */
|
|
os_mem_cpy(sidelobe_buf,
|
|
csi_buf + (IOT_PHY_CSI_BUF_LEN >> 2)
|
|
- (PHY_CHN_EST_AI_SIDELOBE_NUM << 1),
|
|
PHY_CHN_EST_AI_SIDELOBE_NUM << 3);
|
|
}
|
|
|
|
/* record successful dump cnt */
|
|
if (ret == ERR_OK) {
|
|
success_cnt++;
|
|
}
|
|
|
|
/* check timeout */
|
|
end_time = RGF_MAC_READ_REG(CFG_RD_NTB_ADDR);
|
|
|
|
/* cal span time */
|
|
time_span = end_time - start_time;
|
|
if (time_span < 0) { // wrap around
|
|
time_span = (0x100000000LL) - start_time + end_time;
|
|
}
|
|
|
|
/* break if timeout */
|
|
if (time_span >= timeout_ms * NTB_TICKS_PER_MS) {
|
|
break;
|
|
}
|
|
}
|
|
#if PHY_DEBUG_EN
|
|
uint32_t spur_buf_size1 = PHY_CHN_EST_AI_SPUR_LEN/sizeof(iot_phy_spur_t);
|
|
for (i = 0; i < spur_buf_size1; i++) {
|
|
iot_printf("B tone:%d, spur_cnt:%d, ratio:%d, notch_cnt:%d\n",
|
|
spur_buf[i].tone_id, spur_buf[i].spur_cnt,
|
|
spur_buf[i].spur_ratio, spur_buf[i].notch_filter_en_cnt);
|
|
}
|
|
#endif
|
|
/* get peak point */
|
|
phy_spur_arry_peak_handler(spur_buf, PHY_CHN_EST_AI_SPUR_LEN, est_rty_cnt);
|
|
}
|
|
else{
|
|
iot_printf("csi buf pointer get fail from iot_pkt!\n");
|
|
}
|
|
/* free iot pkt */
|
|
iot_pkt_free(pkt_buf);
|
|
iot_pkt_free(hash_buf);
|
|
|
|
/* get end time */
|
|
end_time = RGF_MAC_READ_REG(CFG_RD_NTB_ADDR);
|
|
|
|
/* cal span time */
|
|
time_span = end_time - start_time;
|
|
if (time_span < 0) { // wrap around
|
|
time_span = (0x100000000LL) - start_time + end_time;
|
|
}
|
|
|
|
/* clear dump flag */
|
|
phy_dump_busy_set(false);
|
|
|
|
/* for kl3 */
|
|
phy_increase_tgt_pwr(g_phy_cpu_share_ctxt.spur_exist);
|
|
|
|
iot_printf("start_time:%u, end time:%u, bbai success cnt:%d\n",
|
|
start_time, end_time, success_cnt);
|
|
#else
|
|
(void)est_rty_cnt;
|
|
(void)timeout_ms;
|
|
#endif
|
|
return success_cnt;
|
|
}
|
|
|
|
#endif /* PHY_BBAI_ALGORITHM == PHY_BBAI_FIX_WINDOWS */
|