Files
kunlun/plc/halphy/hw/phy_cal.c

1052 lines
32 KiB
C
Raw Normal View History

2024-09-28 14:24:04 +08:00
/****************************************************************************
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 "os_types.h"
#include "hw_reg_api.h"
#include "plc_fr.h"
#include "phy_cal.h"
#include "phy_bb.h"
#include "phy_phase.h"
#include "granite_reg.h"
#include "phy_rxtd_reg.h"
#include "phy_txrx_pwr.h"
#include "phy_rx_fd_reg.h"
#include "phy_dfe_reg.h"
#include "mac_sys_reg.h"
#include "iot_io.h"
#include "hw_tonemask.h"
#include "iot_config.h"
#include "iot_pib.h"
#include "iot_errno.h"
#include "rx_pb_reorder.h"
#include "ahb.h"
#include "iot_cal_data.h"
#include "phy_ana.h"
#include "ahb.h"
#include "hw_phy_api.h"
#include "iot_oem.h"
#include "clk.h"
#include "iot_clock.h"
#include "iot_system.h"
int16_t int16_abs(int16_t x)
{
if(x<0) x=0-x;
return x;
}
/* Note: wmask is useful for rx0 and top reg only */
#if PHY_CAL_PIB_SUPPORT == 1
uint32_t tx_dc_calibration(int16_t *tx_dc, iot_pib_w_halphy_real_cfg_t *pib_ptr)
#else
uint32_t tx_dc_calibration(uint16_t *tx_dc)
#endif
{
uint8_t reg_id = 0;
uint8_t rodata = 0;
uint32_t rdata = 0;
volatile uint16_t dac_golden = 512;
volatile uint16_t dac_ovr = 0;
volatile uint16_t dac_step = 0;
int16_t dc_offset = 0;
/* force phy in idle state */
phy_txrx_ovr_set(true,0);
/* auto gain */
phy_agc_gain_lvl_set(0,60,-24,0);
/* en analog tx */
phy_ana_tx_set(true, true);
phy_ana_rx_set(false, false);
/* en tx compen */
reg_id = CFG_ANA_TX_REG_ADDR;
phy_ana_i2c_read(reg_id, &rdata, &rodata);
REG_FIELD_SET(TX_COMPEN,rdata,1);
phy_ana_i2c_write(reg_id,rdata,~0);
/* reset the dc correction register */
phy_dfe_dc_comp_set(0,0);
phy_dfe_dc_comp_set(1,0);
phy_dfe_dc_comp_set(2,0);
phy_dfe_dc_comp_set(3,0);
/* dc offset */
for(uint32_t i = 0; i < 4; i++)
{
reg_id = CFG_ANA_TX_REG_ADDR;
phy_ana_i2c_read(reg_id, &rdata, &rodata);
REG_FIELD_SET(TX_GPGA,rdata,i);
phy_ana_i2c_write(reg_id,rdata,~0);
/*
if(phy_dfe_dc_comp_get(i)>>9)
{
dac_golden = PHY_DAC_STEP + phy_dfe_dc_comp_get(i) - 1024;
}
else{
dac_golden = PHY_DAC_STEP + phy_dfe_dc_comp_get(i);
}
*/
dac_golden = 512;
dac_step = dac_golden;
dac_ovr = dac_step;
do{
phy_dac_data_ovr_set(true,dac_ovr);
phy_ana_i2c_read(reg_id, &rdata, &rodata);
rodata = (rodata >> 7) & 0x1;
dac_step = dac_step >> 1;
if(rodata == 1){
dac_ovr += dac_step;
}
else{
dac_ovr -= dac_step;
}
}while(dac_step > 0);
dc_offset = dac_ovr-512;
if(tx_dc != NULL)
{
*tx_dc = dc_offset;
tx_dc++;
#if PHY_CAL_PIB_SUPPORT == 1
/*todo: update pib */
pib_ptr->tx_dc[i] = dc_offset;
#endif
}
else{
IOT_ASSERT(0);
}
if(int16_abs(dc_offset)>TX_DC_THR){
iot_printf("tx dc calibration: i=%d, dac_cal=%d, ###fail###\r\n", \
i, dc_offset);
/* set tx dc compen */
phy_dfe_dc_comp_set(i, 0);
}
else{
iot_printf("tx dc calibration: i=%d, dac_cal=%d, ###success###\r\n", \
i, dc_offset);
/* set tx dc compen */
phy_dfe_dc_comp_set(i, dc_offset);
}
}
/* disable tx compen */
reg_id = CFG_ANA_TX_REG_ADDR;
phy_ana_i2c_read(reg_id, &rdata, &rodata);
REG_FIELD_SET(TX_COMPEN,rdata,0);
phy_ana_i2c_write(reg_id,rdata,~0);
/* disable analog tx */
phy_ana_tx_set(false, false);
/* clear ovr */
phy_dac_data_ovr_set(0,0);
return ERR_OK;
}
/* Note: wmask is useful for rx0 and top reg only */
#if PHY_CAL_PIB_SUPPORT == 1
uint32_t rx_dc_calibration(uint32_t *rx_dc, \
iot_pib_w_halphy_real_cfg_t *pib_ptr)
#else
uint32_t rx_dc_calibration(uint16_t *rx_dc)
#endif
{
uint32_t ret = ERR_OK;
uint32_t tmp = 0;
volatile uint8_t flag = 0;
uint16_t i = 0 ,j = 0;
int16_t dc_offset = 0;
int16_t dc_offset_after_pgf = 0;
uint8_t reg_id = 0;
int8_t gain = 0;
uint32_t wdata = 0;
uint32_t wmask = 0;
volatile uint16_t dc_val = 0;
volatile uint16_t dc_pgf = 0;
volatile uint16_t dc_pga = 0;
volatile uint16_t dc_step = 0;
uint8_t bq_qvalue = 0;
uint8_t pgf = 0, bq = 0, pga = 0;
uint8_t lna = 0, byphpf = 0, enord2 = 0;
uint32_t start_time = 0, end_time = 0;
uint64_t time_span = 0;
phy_add_dc_cal_cnt();
/* disable packet detect timeout */
phy_pkt_time_out_disable(true);
/* CPU switch to 25M */
clk_core_freq_slip_25m_set();
/* disable reset by full */
phy_agc_sat_adj_set(1, 1);
/* disable rx0 overwrite by hw */
PHY_DFE_WRITE_REG(CFG_BB_ANA_RX_ON_CFG_MASK_ADDR, 0x0);
/* turn off adc */
phy_ana_i2c_write(CFG_ANA_TOP_REG_ADDR, \
(0 << TOP_EN_ADC_OFFSET), \
TOP_EN_ADC_MASK);
/* force phy in rx state */
phy_txrx_ovr_set(true,1);
/* diable analog loopen */
phy_ana_i2c_write(CFG_ANA_RX_REG_0_ADDR, \
0 << RX_PGFLOOPEN_OFFSET, \
RX_PGFLOOPEN_MASK);
if(!iot_chip_check_lic()) {
phy_phase_ovr_set(PHY_PHASE_OVR_ALL,true,PHY_TXRX_OVR_IDLE);
}
/* turn off dac/tx/enlic/rx */
phy_ana_i2c_write(CFG_ANA_TOP_REG_ADDR, \
(1 << TOP_EN_RX_OFFSET), \
TOP_EN_DAC_MASK | \
TOP_ENLIC_MASK | \
TOP_EN_TX_MASK | \
TOP_EN_RX_MASK);
/* turn on adc after delay */
phy_ana_i2c_write(CFG_ANA_TOP_REG_ADDR, \
(1 << TOP_EN_ADC_OFFSET), \
TOP_EN_ADC_MASK);
/* CPU switch to 150M */
clk_core_freq_slip_150m_set();
/* check raw_dc start*/
/* granite gain=0, pwdpgfoffset=1, pwdpgaoffset=1, hpfenord2=1 */
wdata = 1 << RX_GPGF_OFFSET | \
1 << RX_GBQ_OFFSET | \
0 << RX_GPGA_OFFSET | \
PHY_RX_PGF_OFFSET_DFT << RX_PGFOFFSET_OFFSET | \
PHY_RX_PGA_OFFSET_DFT << RX_PGAOFFSET_OFFSET | \
1 << RX_HPFENORD2_OFFSET | \
0 << RX_BYPHPF_OFFSET | \
1 << RX_PWDPGFOFFSET_OFFSET | \
1 << RX_PWDPGAOFFSET_OFFSET ;
wmask = RX_GPGF_MASK | \
RX_GBQ_MASK | \
RX_GPGA_MASK | \
RX_PGFOFFSET_MASK | \
RX_PGAOFFSET_MASK | \
RX_HPFENORD2_MASK | \
RX_BYPHPF_MASK | \
RX_PWDPGAOFFSET_MASK | \
RX_PWDPGFOFFSET_MASK ;
phy_ana_i2c_write(CFG_ANA_RX_REG_0_ADDR,wdata,wmask);
/* delay 3us */
start_time = RGF_MAC_READ_REG(CFG_RD_NTB_ADDR);
do{
end_time = RGF_MAC_READ_REG(CFG_RD_NTB_ADDR);
time_span = end_time - start_time;
if (time_span < 0) { // wrap around
time_span = (0x100000000LL) - start_time + end_time;
}
}while(time_span < 3*TICKS_US);
/* get dc est */
dc_offset = 0;
for(j = 0; j< PHY_DC_EST_RETRY_NUM; j++)
{
tmp = PHY_RXTD_READ_REG(CFG_BB_PACKET_INF_2_ADDR);
flag = REG_FIELD_GET(DC_EST_FREE,tmp) >> 9;
if(flag) {
dc_offset += REG_FIELD_GET(DC_EST_FREE,tmp) - 1024;
} else {
dc_offset += REG_FIELD_GET(DC_EST_FREE,tmp);
}
}
dc_offset = dc_offset/PHY_DC_EST_RETRY_NUM;
#if IOT_DTEST_ONLY_SUPPORT == 1
iot_printf("raw_dc with 0db gain and pwd correction dac is %d\r\n", \
dc_offset);
#endif
if(int16_abs(dc_offset)>RX_DC_RAW_THR) {
iot_printf("raw_dc=%d is too large! ###fail###\r\n",dc_offset);
ret = ERR_FAIL;
}
/*write back RX0 register*/
wdata = 1 << RX_GPGF_OFFSET | \
1 << RX_GBQ_OFFSET | \
0 << RX_GPGA_OFFSET | \
PHY_RX_PGF_OFFSET_DFT << RX_PGFOFFSET_OFFSET | \
PHY_RX_PGA_OFFSET_DFT << RX_PGAOFFSET_OFFSET | \
1 << RX_HPFENORD2_OFFSET | \
0 << RX_BYPHPF_OFFSET | \
0 << RX_PWDPGFOFFSET_OFFSET | \
0 << RX_PWDPGAOFFSET_OFFSET ;
wmask = RX_GPGF_MASK | \
RX_GBQ_MASK | \
RX_GPGA_MASK | \
RX_PGFOFFSET_MASK | \
RX_PGAOFFSET_MASK | \
RX_HPFENORD2_MASK | \
RX_BYPHPF_MASK | \
RX_PWDPGAOFFSET_MASK | \
RX_PWDPGFOFFSET_MASK ;
phy_ana_i2c_write(CFG_ANA_RX_REG_0_ADDR,wdata,wmask);
/* check raw_dc end*/
/* scan normal and narrow gain table */
for(i = 0; i < PHY_GAIN_STEP_MAX * 2; i++)
{
/* get current gain info */
if(i < PHY_GAIN_STEP_MAX) {
gain = i - 24;
} else {
gain = i - PHY_GAIN_STEP_MAX - 24;
}
dc_pga = 0;
dc_pgf = 0;
/* fix gain accss from analog */
phy_pgf_bq_pga_gain_get(i, \
&pgf, \
&bq, \
&pga, \
&lna, \
&byphpf, \
&enord2, \
&bq_qvalue);
reg_id = CFG_ANA_RX_REG_0_ADDR;
wdata = (pgf << RX_GPGF_OFFSET) | \
(bq << RX_GBQ_OFFSET) | \
(pga << RX_GPGA_OFFSET) | \
(byphpf << RX_BYPHPF_OFFSET) | \
(enord2 << RX_HPFENORD2_OFFSET);
wmask = RX_GPGF_MASK | \
RX_GBQ_MASK | \
RX_GPGA_MASK | \
RX_BYPHPF_MASK | \
RX_HPFENORD2_MASK;
phy_ana_i2c_write(reg_id,wdata,wmask);
#if PHY_LNA_DC_CALI_EN == 1
/* enable geode */
if(byphpf) {
reg_id = CFG_ANA_TOP_REG_ADDR;
wdata = lna << TOP_GLNA_OFFSET ;
wmask = TOP_GLNA_MASK ;
phy_ana_i2c_write(reg_id,wdata,wmask);
}
#endif
/* step1: pgf cal */
phy_pgf_pga_dc_cal_get(i, &dc_pgf, &dc_pga);
#if PHY_DBG_EN == 1
iot_printf("***** gain=%d calibration start *******\r\n",gain);
#endif
dc_val = PHY_RX_PGF_OFFSET_DFT;
dc_step = PHY_RX_PGF_OFFSET_DFT;
do{
reg_id = CFG_ANA_RX_REG_0_ADDR;
wdata = (dc_val << RX_PGFOFFSET_OFFSET) | \
(PHY_RX_PGA_OFFSET_DFT << RX_PGAOFFSET_OFFSET);
wmask = RX_PGFOFFSET_MASK | RX_PGAOFFSET_MASK;
phy_ana_i2c_write(reg_id,wdata,wmask);
/* delay 3us */
start_time = RGF_MAC_READ_REG(CFG_RD_NTB_ADDR);
do{
end_time = RGF_MAC_READ_REG(CFG_RD_NTB_ADDR);
time_span = end_time - start_time;
if (time_span < 0) { // wrap around
time_span = (0x100000000LL) - start_time + end_time;
}
}while(time_span < 3*TICKS_US);
/* get dc est */
dc_offset = 0;
for(j = 0; j< PHY_DC_EST_RETRY_NUM; j++)
{
tmp = PHY_RXTD_READ_REG(CFG_BB_PACKET_INF_2_ADDR);
flag = REG_FIELD_GET(DC_EST_FREE,tmp) >> 9;
if(flag) {
dc_offset += REG_FIELD_GET(DC_EST_FREE,tmp) - 1024;
} else {
dc_offset += REG_FIELD_GET(DC_EST_FREE,tmp);
}
}
dc_offset = dc_offset/PHY_DC_EST_RETRY_NUM;
#if PHY_DBG_EN == 1
iot_printf("rx pgf dc cali: pgfoffset=%d,dc=%d\r\n", \
dc_val, dc_offset);
#endif
/* PGF thd */
if(dc_offset < PHY_DC_PGF_GOLDEN && \
dc_offset > -PHY_DC_PGF_GOLDEN) {
break;
}
/* check dc result */
if(dc_val > 48 || dc_val < 16) {
break;
}
/* cal step to cal dc */
dc_step = dc_step >> 1;
if(dc_offset > 0) {
dc_val -= dc_step;
} else {
dc_val += dc_step;
}
}while(dc_step > 0);
dc_pgf = dc_val;
#if PHY_DBG_EN == 1
iot_printf("rx pgf cali done: gain=%d, pgfoffset=%d\r\n", \
gain, dc_pgf);
#endif
dc_offset_after_pgf = dc_offset;
/* step2: pga cal */
dc_val = PHY_RX_PGA_OFFSET_DFT;
dc_step = PHY_RX_PGA_OFFSET_DFT;
do{
reg_id = CFG_ANA_RX_REG_0_ADDR;
wdata = (dc_pgf << RX_PGFOFFSET_OFFSET) | \
(dc_val << RX_PGAOFFSET_OFFSET);
wmask = RX_PGFOFFSET_MASK | RX_PGAOFFSET_MASK;
phy_ana_i2c_write(reg_id,wdata,wmask);
/* delay 3us */
start_time = RGF_MAC_READ_REG(CFG_RD_NTB_ADDR);
do{
end_time = RGF_MAC_READ_REG(CFG_RD_NTB_ADDR);
time_span = end_time - start_time;
if (time_span < 0) { // wrap around
time_span = (0x100000000LL) - start_time + end_time;
}
}while(time_span < 3*TICKS_US);
/* get dc est */
dc_offset = 0;
for(j = 0; j< PHY_DC_EST_RETRY_NUM; j++)
{
tmp = PHY_RXTD_READ_REG(CFG_BB_PACKET_INF_2_ADDR);
flag = REG_FIELD_GET(DC_EST_FREE,tmp)>>9;
if(flag) {
dc_offset += REG_FIELD_GET(DC_EST_FREE,tmp) - 1024;
} else {
dc_offset += REG_FIELD_GET(DC_EST_FREE,tmp);
}
}
dc_offset = dc_offset/PHY_DC_EST_RETRY_NUM;
#if PHY_DBG_EN == 1
iot_printf("rx pga dc cali: pgaoffset=%d, dc=%d\r\n", \
dc_val,dc_offset);
#endif
if(dc_offset < PHY_DC_PGA_GOLDEN && \
dc_offset > -PHY_DC_PGA_GOLDEN) {
break;
}
/* cal step to cal dc */
dc_step = dc_step >> 1;
if(dc_offset > 0) {
dc_val -= dc_step;
} else {
dc_val += dc_step;
}
}while(dc_step > 0);
dc_pga = dc_val;
if(int16_abs(dc_offset)>int16_abs(dc_offset_after_pgf)) {
dc_offset = dc_offset_after_pgf;
dc_pga = PHY_RX_PGA_OFFSET_DFT;
}
if(int16_abs(dc_offset)>RX_DC_FINAL_THR) {
#if IOT_DTEST_ONLY_SUPPORT == 1
iot_printf("rx pga dc cali done: gain=%d,pgf=%d,bq=%d,pga=%d,", \
gain, pgf, bq, pga);
#endif
iot_printf("pgfoffset=%d,pgaoffset=%d, final_dc=%0d ###fail###\r\n", \
dc_pgf, dc_pga, dc_offset);
ret = ERR_FAIL;
} else {
#if IOT_DTEST_ONLY_SUPPORT == 1
iot_printf("rx pga dc cali done: gain=%d,pgf=%d,bq=%d,pga=%d,", \
gain, pgf, bq, pga);
#endif
iot_printf("pgfoffset=%d,pgaoffset=%d, final_dc=%0d ###success###\r\n", \
dc_pgf, dc_pga, dc_offset);
}
/* set pgf and pga dc offset to gain table */
phy_pgf_pga_dc_cal(i, dc_pgf, dc_pga);
if(rx_dc != NULL) {
*rx_dc = (dc_pgf & 0x3F) | \
((dc_pga & 0x1F) << 6);
rx_dc++;
#if PHY_CAL_PIB_SUPPORT == 1
//todo: support pib
pib_ptr->rx_dc[i] = dc_pgf | (dc_pga << 6);
#endif
} else {
IOT_ASSERT(0);
}
}
/* CPU switch to 25M */
clk_core_freq_slip_25m_set();
/* disable force tx/rx to avoid mac hang */
phy_txrx_ovr_set(0,0);
/* CPU switch to 150M */
clk_core_freq_slip_150m_set();
/* K68 branch*/
if(!iot_chip_check_lic()) {
phy_phase_ovr_set(PHY_PHASE_OVR_ALL,false,PHY_TXRX_OVR_IDLE);
}
/* disable packet detect timeout */
phy_pkt_time_out_disable(false);
/* disable reset by full */
phy_agc_sat_adj_set(0, 0);
(void)gain;
return ret;
}
void phy_txrx_loop_back_begin(uint32_t phase, TXRX_LOOP_BACK_MODE_ID mode)
{
uint32_t tmp = 0;
/* Must not ovr da data */
phy_dac_data_ovr_set(false,0);
/* CPU switch to 25M */
clk_core_freq_slip_25m_set();
/* disable analog tx and rx */
phy_ana_i2c_write(CFG_ANA_TOP_REG_ADDR, \
(0 << TOP_EN_DAC_OFFSET) | \
(0 << TOP_EN_ADC_OFFSET) | \
(0 << TOP_EN_TX_OFFSET) | \
(0 << TOP_EN_RX_OFFSET), \
TOP_EN_DAC_MASK | \
TOP_EN_ADC_MASK | \
TOP_EN_TX_MASK | \
TOP_EN_RX_MASK);
/* force inte rx state */
phy_txrx_ovr_set(1,1);
/* disable packet detect timeout */
phy_pkt_time_out_disable(true);
/* bypass dc blocker */
tmp = PHY_DFE_READ_REG(CFG_BB_DC_BLK_STAGE_DLY_ADDR);
REG_FIELD_SET(SW_DC_BLK_BYPASS, tmp, 1);
PHY_DFE_WRITE_REG(CFG_BB_DC_BLK_STAGE_DLY_ADDR, tmp);
/* fix gain and disable agc */
phy_agc_gain_lvl_set(1,0,-24,0);
/* disable adj and sat reset */
phy_agc_sat_adj_set(1, 1);
/* disable auto-adjust gain */
phy_agc_gain_adj_dis(0);
/* turn on dac/tx/rx */
phy_ana_i2c_write(CFG_ANA_TOP_REG_ADDR, \
(1 << TOP_EN_DAC_OFFSET) | \
(1 << TOP_EN_TX_OFFSET) | \
(1 << TOP_EN_RX_OFFSET), \
TOP_EN_DAC_MASK | \
TOP_EN_TX_MASK | \
TOP_EN_RX_MASK);
/* turn on adc after delay */
phy_ana_i2c_write(CFG_ANA_TOP_REG_ADDR, \
(1 << TOP_EN_ADC_OFFSET), \
TOP_EN_ADC_MASK);
#if CHIP_BRINGUP_DEBUG == 1
phy_ana_i2c_write(CFG_ANA_TX_REG_ADDR,0x0,0xffffffff);
#endif
tmp = PHY_DFE_READ_REG(CFG_BB_LOOPBACK_TEST_CFG_ADDR);
REG_FIELD_SET(SW_LOOPBACK_EN, tmp, 1);
PHY_DFE_WRITE_REG(CFG_BB_LOOPBACK_TEST_CFG_ADDR, tmp);
if(mode == TXRX_LOOP_BACK_GRANITE) {
/* enable analog loopen */
phy_ana_i2c_write(CFG_ANA_RX_REG_0_ADDR, \
(1 << RX_PGFLOOPEN_OFFSET) | \
(16 << RX_PGAOFFSET_OFFSET) | \
(32 << RX_PGFOFFSET_OFFSET) | \
(0 << RX_GPGA_OFFSET) | \
(1 << RX_GBQ_OFFSET) | \
(1 << RX_GPGF_OFFSET), \
RX_PGFLOOPEN_MASK | \
RX_PGAOFFSET_MASK | \
RX_PGFOFFSET_MASK | \
RX_GPGA_MASK | \
RX_GBQ_MASK | \
RX_GPGF_MASK);
} else if(mode == TXRX_LOOP_BACK_GEODE) {
/* disable analog loopen */
phy_ana_i2c_write(CFG_ANA_RX_REG_0_ADDR, \
0 << RX_PGFLOOPEN_OFFSET, \
RX_PGFLOOPEN_MASK);
/* k48 or k68 */
if(iot_chip_check_lic()) {
phy_ana_i2c_write(CFG_ANA_TOP_REG_ADDR,TOP_ENLIC_MASK,TOP_ENLIC_MASK);
} else {
/* enable a/b/c and tx & rx*/
switch(phase)
{
case 0:
phy_phase_ovr_set(PHY_PHASE_OVR_A,1,3);
break;
case 1:
phy_phase_ovr_set(PHY_PHASE_OVR_B,1,3);
break;
case 2:
phy_phase_ovr_set(PHY_PHASE_OVR_C,1,3);
break;
case 3:
phy_phase_ovr_set(PHY_PHASE_OVR_ALL,1,3);
break;
default:
break;
}
}
}
/* CPU switch to 150M */
clk_core_freq_slip_150m_set();
/* tone */
tmp = PHY_DFE_READ_REG(CFG_BB_TX_TONE_0_CFG_ADDR);
phy_dfe_tone_cfg(1,REG_FIELD_GET(SW_TONE_0_CFG_NUM,tmp), \
REG_FIELD_GET(SW_TONE_1_CFG_NUM,tmp));
/* loopback if < 6, will full */
#if IOT_DTEST_ONLY_SUPPORT == 1
phy_dfe_tone_att_cfg(0,3,3);
#endif
}
void phy_txrx_loop_back_end()
{
uint32_t tmp;
/* fallback:disable tone */
phy_dfe_tone_cfg(0,0,0);
/* en dc blocker */
tmp = PHY_DFE_READ_REG(CFG_BB_DC_BLK_STAGE_DLY_ADDR);
REG_FIELD_SET(SW_DC_BLK_BYPASS, tmp, 0);
PHY_DFE_WRITE_REG(CFG_BB_DC_BLK_STAGE_DLY_ADDR, tmp);
phy_agc_sat_adj_set(0, 0);
tmp = PHY_DFE_READ_REG(CFG_BB_LOOPBACK_TEST_CFG_ADDR);
REG_FIELD_SET(SW_LOOPBACK_EN, tmp, 0);
PHY_DFE_WRITE_REG(CFG_BB_LOOPBACK_TEST_CFG_ADDR, tmp);
/* disable packet detect timeout */
phy_pkt_time_out_disable(false);
/* config regression */
phy_ana_i2c_write(CFG_ANA_RX_REG_0_ADDR,0x0,RX_PGFLOOPEN_MASK);
phy_ana_tx_set(false, false);
}
uint32_t phy_csi_buf_amp_get(uint16_t tone_id)
{
uint32_t tmp = 0;
uint32_t fft_loop = 1;
uint32_t amp_val = 0;
int16_t csi_i = 0, csi_q = 0;
uint32_t *csi_buf = (uint32_t *)BB_CSI_BASEADDR;
/* reset phy */
phy_reset(PHY_RST_REASON_WARM);
/* config det tone */
phy_rxfd_rate0_det(0, 1535);
phy_rxfd_rate1_det(0, 1535);
/* enable ana loopback */
phy_txrx_loop_back_begin(0,TXRX_LOOP_BACK_GRANITE);
/* trig fft */
tmp = PHY_DFE_READ_REG(CFG_BB_LOOPBACK_TEST_CFG_ADDR);
REG_FIELD_SET(SW_LOOP_FFT_CYCLE, tmp, fft_loop);
REG_FIELD_SET(SW_LOOP_FFT_START, tmp, 1);
PHY_DFE_WRITE_REG(CFG_BB_LOOPBACK_TEST_CFG_ADDR, tmp);
/* wait fft done */
do{
tmp = PHY_DFE_READ_REG(CFG_BB_LOOPBACK_TEST_CFG_ADDR);
}while(!REG_FIELD_GET(LOOP_FFT_DONE, tmp));
/* enable sw csi buf access */
enable_sw_access_csi_buf(1);
/* cal csi for appointed tone */
csi_i = (int16_t)(*(csi_buf + tone_id) & 0xFFFF);
csi_q = (int16_t)(*(csi_buf + tone_id) >> 16);
amp_val = csi_i*csi_i + csi_q*csi_q;
/* enable sw csi buf access */
enable_sw_access_csi_buf(0);
/* recover to the state set in ana loopback */
phy_txrx_loop_back_end();
/* update the precise det range */
phy_update_tone_det_range();
return amp_val;
}
/*
* rx bandwidth filter:
* rx_freq LPF(typ) Min Max
* 5.6M 63/5.790M 59 63
* 12M 23/12.129M 18 30
* fix big attenuation:
* 8M 36 29 45
* 15M 19 14 24
* 20M 14 11 18
* X/Y = 10^(3/10) = 1.995
*/
uint16_t phy_rx_bw_filter(RX_BW_LIST_ID freq_id)
{
uint8_t reg_id = 0;
uint32_t wdata = 0;
uint32_t wmask = 0;
uint32_t amp_val = 0;
uint16_t tone_id = 0;
uint16_t cap_id = 0;
uint16_t start_cap = 0, end_cap = 0;
uint32_t golden_data = 0;
uint8_t is_thd_find = false;
/* 1st get 3M amp */
tone_id = 41;
phy_dfe_tone_cfg(1,tone_id,0);
phy_dfe_tone_att_cfg(0,3,3);
golden_data = phy_csi_buf_amp_get(tone_id*3);
/* tx tone is trible than cfg */
switch(freq_id)
{
case RX_BW_LIST_BAND0_20M:
start_cap = 11;
end_cap = 18;
tone_id = PHY_SG_BAND0_TONE_20M/3;
break;
case RX_BW_LIST_BAND0_15M:
start_cap = 14;
end_cap = 24;
tone_id = PHY_SG_BAND0_TONE_15M/3;
break;
case RX_BW_LIST_BAND0_12M:
start_cap = 18;
end_cap = 30;
tone_id = PHY_SG_BAND0_TONE_12M/3;
break;
case RX_BW_LIST_BAND0_8M:
start_cap = 29;
end_cap = 45;
tone_id = PHY_SG_BAND0_TONE_8M/3;
break;
case RX_BW_LIST_BAND1_5P6M:
start_cap = 59;
end_cap = 63;
tone_id = PHY_SG_BAND1_TONE_5P6M/3;
break;
default:
break;
}
/* find the 3dB point */
for(cap_id = start_cap; cap_id <= end_cap; cap_id++)
{
/* update rx_selc*/
reg_id = CFG_ANA_RX_REG_0_ADDR;
wdata = cap_id << RX_SELC_OFFSET;
wmask = RX_SELC_MASK;
phy_ana_i2c_write(reg_id,wdata,wmask);
/* get the amp from the fixed tone */
phy_dfe_tone_cfg(1,tone_id,0);
phy_dfe_tone_att_cfg(0,3,3);
amp_val = phy_csi_buf_amp_get(tone_id*3);
#if CHIP_BRINGUP_DEBUG == 1
iot_printf("csi_buf_amp_val=%d\r\n", amp_val);
#endif
if(golden_data > (amp_val << 1)){
is_thd_find = true;
break;
}
}
if(is_thd_find){
/* update the cap value*/
iot_printf("bw filter cal:band=%d,cap value=%d\r\n",freq_id,cap_id);
}
else if(end_cap == 63){
iot_printf("bw filter cal:band=%d,cap value bigger than 63\r\n",freq_id);
return 63;
}
else{
iot_printf("bw filter cal:band=%d fail \r\n",freq_id);
return 0;
}
return cap_id;
}
/* read ppm, dc cali and update to hw */
void phy_load_cal_cfg(void)
{
uint8_t reg_id = 0;
uint8_t rodata = 0;
uint32_t wdata = 0;
uint32_t wmask = 0;
uint16_t tx_dc[4] = {0};
uint16_t *rx_dc = NULL;
/* alloc rx dc mem */
rx_dc = (uint16_t *)os_mem_malloc( \
PLC_PHY_COMMON_MID, \
PHY_GAIN_STEP_MAX << 2);
if(rx_dc == NULL) {
iot_printf("%s: malloc rx dc fail!\n", __FUNCTION__);
IOT_ASSERT(0);
}
/* bias current:50uA */
reg_id = CFG_ANA_BIAS_REG_2_ADDR;
phy_ana_i2c_read(reg_id, &wdata, &rodata);
wdata |= 1 << 31;
wmask = ~0;
phy_ana_i2c_write(reg_id,wdata,wmask);
#if IOT_DTEST_ONLY_SUPPORT == 0
uint32_t i = 0;
uint32_t ret = ERR_FAIL;
uint8_t *section;
uint8_t pib_type = 0;
uint16_t dc_pgf = 0;
uint16_t dc_pga = 0;
iot_pib_w_halphy_real_cfg_t *phy_cfg;
iot_cal_data_cfg_t *cal_cfg;
/* init perf ppm */
g_phy_ctxt.dep.phy_ppm_pref = PHY_PPM_PREF_DFT;
g_phy_ctxt.dep.phy_ppm_init = PHY_PPM_PREF_DFT;
/* read crystal ppm from oem */
ret = iot_cal_data_get_cfg(&cal_cfg);
if (ret == ERR_OK || ret == ERR_NOSUPP) {
iot_printf("[PHY %d]oem load successfully!\n", ret);
/* check mtd sts */
if (iot_cal_data_get_mtd_sts() != ERR_OK) {
iot_printf("[PHY]oem mtd status check fail!\n");
} else {
/* check mask if valid */
if (iot_cal_data_check_mask(cal_cfg, IOT_PHY_CFG_MASK_PPM)) {
/* disable td and fd comp self */
phy_freq_shift_self_comp(false, false);
/* g_phy_ctxt.phy_ppm_pref = target crystal ppm
* cal_cfg->halphy_cfg.ppm = - local crystal ppm
* ppm of phy_ppm_cal_set(to self):
* + : faster - : more slowly
*/
/* apply ppm to phy register */
g_phy_ctxt.dep.phy_ppm_init =
g_phy_ctxt.dep.phy_ppm_pref +
cal_cfg->halphy_cfg.ppm;
uint32_t ver = cal_cfg->halphy_cfg.pt_fw_ver;
iot_printf("phy oem ver:0x%x\n", ver);
if (ver && 0xFFFFFFFF != ver) {
g_phy_ctxt.dep.phy_cal_ppm_in_oem =
g_phy_ctxt.dep.phy_ppm_init;
} else {
g_phy_ctxt.dep.phy_cal_ppm_in_oem = FORCE_INI_PPM;
}
g_phy_ctxt.dep.phy_ppm_init =
phy_ppm_cal_hw_val(PHY_CAL_UNIT_1_1,
g_phy_ctxt.dep.phy_cal_ppm_in_oem,
IOT_SUPPORT_RATE_SR);
//TODO: maybe phy_ppm_init save to g_phy_cpu_share_ctxt only
g_phy_cpu_share_ctxt.phy_ppm_init =
g_phy_ctxt.dep.phy_ppm_init;
#if PLC_SUPPORT_CCO_ROLE == 0
/* only sta apply this info
* cco just read and save in
* phy_cal_ppm_in_oem
*/
phy_ppm_set(g_phy_ctxt.dep.phy_ppm_init, BB_PPM_TXRX);
#endif
iot_printf("[PHY]config ppm:%d "
"(pref ppm:%d, oem ppm:%d ) to phy_reg.\n",
g_phy_ctxt.dep.phy_ppm_init,
g_phy_ctxt.dep.phy_ppm_pref,
cal_cfg->halphy_cfg.ppm);
} else {
iot_printf("[PHY]oem magic num check fail!\n");
}
}
} else {
iot_printf("[PHY]oem load failed, err code: %d.\n", ret);
}
/* get dc cal from pib */
ret = iot_pib_get_section(IOT_PIB_HALPHY_ID, &section, &pib_type,
IOT_PIB_APP_GET_WRITE_SECTION);
if (ret == ERR_OK) {
phy_cfg = (iot_pib_w_halphy_real_cfg_t *)section;
/* check tx dc if valid */
if (phy_cfg->mask & (1 << IOT_PIB_PHY_MASK_TX_DC)) {
/* apply dc calibration */
for(i = 0; i < TOTAL_TX_DC_NUM; i++)
{
phy_dfe_dc_comp_set(i, phy_cfg->tx_dc[i]);
}
} else {
iot_printf("%s pib have no valid tx dc data.\n", __FUNCTION__);
#if PHY_CAL_PIB_SUPPORT == 1
/* commit pib write if need in the future */
tx_dc_calibration(tx_dc, phy_cfg);
#else
tx_dc_calibration(tx_dc);
#endif
}
/* check rx dc if valid */
if (phy_cfg->mask & (1 << IOT_PIB_PHY_MASK_RX_DC)) {
for(i = 0; i < TOTAL_GAIN_NUM; i++)
{
dc_pgf = phy_cfg->rx_dc[i] & 0x3F;
dc_pga = (phy_cfg->rx_dc[i] & 0xFC0) >> 6;
phy_pgf_pga_dc_cal(i, dc_pgf, dc_pga);
}
} else {
iot_printf("%s pib have no valid rx dc data.\n", __FUNCTION__);
#if PHY_CAL_PIB_SUPPORT == 1
/* commit pib write if need in the future */
rx_dc_calibration(rx_dc, phy_cfg);
#else
rx_dc_calibration(rx_dc);
#endif
}
/* check bandwidth filter calibration */
if (phy_cfg->mask & (1 << IOT_PIB_PHY_MASK_BW_FILTER)) {
/* update global variables for freshing */
g_phy_ctxt.dep.band_15m_cap_set = \
phy_cfg->cap_set[RX_BW_LIST_BAND0_15M];
g_phy_ctxt.dep.band_8m_cap_set = \
phy_cfg->cap_set[RX_BW_LIST_BAND0_8M];
g_phy_ctxt.dep.band_20m_cap_set = \
phy_cfg->cap_set[RX_BW_LIST_BAND0_20M];
} else {
iot_printf("%s pib have no valid bw filter data.\n", __FUNCTION__);
/* cali 15M/band0 and 8M/band1 */
phy_param_init(PHY_PROTO_TYPE_GET());
g_phy_ctxt.dep.band_20m_cap_set = \
phy_rx_bw_filter(RX_BW_LIST_BAND0_20M);
g_phy_ctxt.dep.band_15m_cap_set = \
phy_rx_bw_filter(RX_BW_LIST_BAND0_15M);
g_phy_ctxt.dep.band_8m_cap_set = \
phy_rx_bw_filter(RX_BW_LIST_BAND0_8M);
}
} else {
iot_printf("%s cal load fail, calibrate again!\n", __FUNCTION__);
tx_dc_calibration(tx_dc);
rx_dc_calibration(rx_dc);
/* cali 15M/band0 and 8M/band1 */
phy_param_init(PHY_PROTO_TYPE_GET());
g_phy_ctxt.dep.band_20m_cap_set = \
phy_rx_bw_filter(RX_BW_LIST_BAND0_20M);
g_phy_ctxt.dep.band_15m_cap_set = \
phy_rx_bw_filter(RX_BW_LIST_BAND0_15M);
g_phy_ctxt.dep.band_8m_cap_set = \
phy_rx_bw_filter(RX_BW_LIST_BAND0_8M);
}
/* commit pib write if need in the future */
#if PHY_CAL_PIB_SUPPORT == 1
uint8_t ref = 0;
uint16_t ticket = 0;
iot_pib_acquire_commit_ref(IOT_PIB_HALPHY_ID, &ref);
iot_pib_release_commit_ref(IOT_PIB_HALPHY_ID, &ref);
iot_pib_commit(IOT_PIB_HALPHY_ID, COMMIT_TYPE_WAIT_REFZERO,
&ticket);
#endif
#else
tx_dc_calibration(tx_dc);
rx_dc_calibration(rx_dc);
/* cali 15M/band0 and 8M/band1 */
phy_param_init(PHY_PROTO_TYPE_GET());
g_phy_ctxt.dep.band_20m_cap_set = \
phy_rx_bw_filter(RX_BW_LIST_BAND0_20M);
g_phy_ctxt.dep.band_15m_cap_set = \
phy_rx_bw_filter(RX_BW_LIST_BAND0_15M);
g_phy_ctxt.dep.band_8m_cap_set = \
phy_rx_bw_filter(RX_BW_LIST_BAND0_8M);
#endif
/* release malloc */
os_mem_free(rx_dc);
/* ana reset */
ahb_phy_ana_reset();
/* bias current:50uA after reset */
reg_id = CFG_ANA_BIAS_REG_2_ADDR;
phy_ana_i2c_read(reg_id, &wdata, &rodata);
wdata |= 1 << 31;
wmask = ~0;
phy_ana_i2c_write(reg_id,wdata,wmask);
/* load new dc cali table */
phy_gain_tab_load(all_mask_gain_table);
}