/**************************************************************************** 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 "bb_rf_cfg.h" #include "bb_cpu_fsm.h" #include "iot_config.h" #include "iot_utils.h" #include "os_types.h" #include "plc_const.h" #include "plc_protocol.h" #include "iot_errno_api.h" #include "iot_oem_api.h" #include "rf_hw_tonemap.h" #include "bb_rf_hw_tbl.h" #include "hw_reg_api.h" #include "rfplc_reg_base.h" #include "rfplc_general_reg.h" #include "wphy_reg.h" #include "rf_mac_reg.h" #include "iot_clock.h" #include "phy_rf_chn.h" #include "rf_spi_api.h" #include "math_log10.h" #include "iot_io.h" #include "mac_rf_common_hw.h" #include "plc_cert_test.h" #include "hw_war.h" #include "bb_cpu_utils.h" #include "gp_timer.h" #include "iot_clock.h" #include "bb_cpu_config.h" #include "bb_init.h" static uint32_t g_bbcpu_rf_ver = RF_VER_INVAILD; #if RF_VER1_2022_8_15 /* tx global variable name */ static uint32_t tx_switch_step1_us = 0; static uint32_t tx_switch_step2_us = 0; static uint32_t tx_step2_to_aotx_us = 0; /* rx global variable name */ static uint32_t rx_switch_step1_us = 0; #endif static void bb_rf_cfg_base_phr_info(bb_rf_hw_info_t *rf_phr) { IOT_ASSERT(rf_phr); WPHY_WRITE_REG(WPHY_PHR_BASIC_CFG_ADDR, rf_phr->codec_cfg); WPHY_WRITE_REG(WPHY_PHR_CHAN_INTL_ADDR, rf_phr->chan_intl); WPHY_WRITE_REG(WPHY_PHR_ROBO_INTL0_ADDR, rf_phr->robo_intl0); WPHY_WRITE_REG(WPHY_PHR_ROBO_INTL1_ADDR, rf_phr->robo_intl1); WPHY_WRITE_REG(WPHY_PHR_ROBO_INTL2_ADDR, rf_phr->robo_intl2); } void bb_rf_cfg_tx_phr_info(bb_rf_hw_info_t *rf_phr) { IOT_ASSERT(rf_phr); /* config base phy header info */ bb_rf_cfg_base_phr_info(rf_phr); uint32_t tmp = WPHY_READ_REG(WPHY_MLTX_SIG_INFO_ADDR); REG_FIELD_SET(TX_SIG_INFO, tmp, rf_phr->mcs_id); WPHY_WRITE_REG(WPHY_MLTX_SIG_INFO_ADDR, tmp); WPHY_WRITE_REG(WPHY_MLTX_PHR_CFG_ADDR, rf_phr->modem_cfg); } void bb_rf_cfg_rx_phr_info(bb_rf_hw_info_t *rf_phr) { IOT_ASSERT(rf_phr); /* config base phy header info */ bb_rf_cfg_base_phr_info(rf_phr); WPHY_WRITE_REG(WPHY_MLRX_PHR_CFG_ADDR, rf_phr->modem_cfg); } static void bb_rf_cfg_base_pld_info(bb_rf_hw_info_t *rf_pld, uint32_t pb_num) { IOT_ASSERT(rf_pld); uint32_t tmp = WPHY_READ_REG(WPHY_PLD_PB_NUM_ADDR); REG_FIELD_SET(PLD_PB_NUM, tmp, pb_num); WPHY_WRITE_REG(WPHY_PLD_PB_NUM_ADDR, tmp); WPHY_WRITE_REG(WPHY_PLD_BASIC_CFG_ADDR, rf_pld->codec_cfg); WPHY_WRITE_REG(WPHY_PLD_CHAN_INTL_ADDR, rf_pld->chan_intl); WPHY_WRITE_REG(WPHY_PLD_ROBO_INTL0_ADDR, rf_pld->robo_intl0); WPHY_WRITE_REG(WPHY_PLD_ROBO_INTL1_ADDR, rf_pld->robo_intl1); WPHY_WRITE_REG(WPHY_PLD_ROBO_INTL2_ADDR, rf_pld->robo_intl2); } void bb_rf_cfg_tx_pld_info(bb_rf_hw_info_t *rf_pld, uint32_t pb_num) { uint32_t tmp; if (pb_num) { IOT_ASSERT(rf_pld); bb_rf_cfg_base_pld_info(rf_pld, pb_num); WPHY_WRITE_REG(WPHY_MLTX_PLD_CFG_ADDR, rf_pld->modem_cfg); if (pb_num != 1) { tmp = WPHY_READ_REG(WPHY_MLTX_PLD_CFG_ADDR); REG_FIELD_SET(TX_PLD_SYMB_NUM, tmp, rf_pld->fec_nsymb * pb_num); WPHY_WRITE_REG(WPHY_MLTX_PLD_CFG_ADDR, tmp); } } else { WPHY_WRITE_REG(WPHY_MLTX_PLD_CFG_ADDR, 0); WPHY_WRITE_REG(WPHY_PLD_PB_NUM_ADDR, 0); } } void bb_rf_cfg_rx_pld_info(bb_rf_hw_info_t *rf_pld, uint32_t pb_num) { IOT_ASSERT(rf_pld); uint32_t tmp; bb_rf_cfg_base_pld_info(rf_pld, pb_num); WPHY_WRITE_REG(WPHY_MLRX_PLD_CFG_ADDR, rf_pld->modem_cfg); if (pb_num != 1) { tmp = WPHY_READ_REG(WPHY_MLRX_PLD_CFG_ADDR); REG_FIELD_SET(RX_PLD_SYMB_NUM, tmp, rf_pld->fec_nsymb * pb_num); WPHY_WRITE_REG(WPHY_MLRX_PLD_CFG_ADDR, tmp); } } void bb_rf_set_tx_phr(uint32_t *phr) { IOT_ASSERT(phr); WPHY_WRITE_REG(WPHY_PHR_TX_INFO0_ADDR, phr[0]); WPHY_WRITE_REG(WPHY_PHR_TX_INFO1_ADDR, phr[1]); WPHY_WRITE_REG(WPHY_PHR_TX_INFO2_ADDR, phr[2]); WPHY_WRITE_REG(WPHY_PHR_TX_INFO3_ADDR, phr[3]); } void bb_rf_get_tx_phr(uint32_t *phr) { *(phr + 0) = WPHY_READ_REG(WPHY_PHR_TX_INFO0_ADDR); *(phr + 1) = WPHY_READ_REG(WPHY_PHR_TX_INFO1_ADDR); *(phr + 2) = WPHY_READ_REG(WPHY_PHR_TX_INFO2_ADDR); *(phr + 3) = WPHY_READ_REG(WPHY_PHR_TX_INFO3_ADDR); } void bb_rf_get_rx_phr(uint32_t *phr) { *(phr + 0) = WPHY_READ_REG(WPHY_PHR_RX_INFO0_ADDR); *(phr + 1) = WPHY_READ_REG(WPHY_PHR_RX_INFO1_ADDR); *(phr + 2) = WPHY_READ_REG(WPHY_PHR_RX_INFO2_ADDR); *(phr + 3) = WPHY_READ_REG(WPHY_PHR_RX_INFO3_ADDR); } void bb_rf_set_crc32_en(uint32_t enable) { uint32_t tmp = WPHY_READ_REG(WPHY_CRC32_EN_ADDR); REG_FIELD_SET(CRC32_EN, tmp, enable); WPHY_WRITE_REG(WPHY_CRC32_EN_ADDR, tmp); } uint32_t bb_rf_get_pld_crc32_err() { uint32_t tmp = WPHY_READ_REG(WPHY_DEC_CRC_RDY_ADDR); return REG_FIELD_GET(PLD_CRC32_ERR, tmp); } uint32_t bb_rf_get_pld_crc24_err() { uint32_t tmp = WPHY_READ_REG(WPHY_DEC_CRC_RDY_ADDR); return REG_FIELD_GET(PLD_CRC24_ERR, tmp); } uint32_t bb_rf_get_pld_crc_rdy() { uint32_t tmp = WPHY_READ_REG(WPHY_DEC_CRC_RDY_ADDR); return REG_FIELD_GET(PLD_RDY, tmp); } uint32_t bb_rf_get_phr_crc24_err() { uint32_t tmp = WPHY_READ_REG(WPHY_DEC_CRC_RDY_ADDR); return REG_FIELD_GET(PHR_CRC24_ERR, tmp); } uint32_t bb_rf_get_phr_crc_rdy() { uint32_t tmp = WPHY_READ_REG(WPHY_DEC_CRC_RDY_ADDR); return REG_FIELD_GET(PHR_RDY, tmp); } uint32_t bb_rf_get_rx_sig_info() { uint32_t tmp = WPHY_READ_REG(WPHY_MLRX_SIG_INFO_ADDR); return REG_FIELD_GET(RX_SIG_INFO, tmp); } uint32_t bb_rf_get_rx_sig_is_ready() { uint32_t tmp = WPHY_READ_REG(WPHY_MLRX_SIG_INFO_ADDR); return REG_FIELD_GET(RX_SIG_RDY, tmp); } uint32_t bb_rf_get_rx_sig_is_err() { uint32_t tmp = WPHY_READ_REG(WPHY_MLRX_SIG_INFO_ADDR); return REG_FIELD_GET(RX_SIG_ERR, tmp); } void bb_rf_set_rx_state_cont(uint32_t state_cont) { uint32_t tmp = WPHY_READ_REG(WPHY_MLRX_STATE_CTRL_ADDR); REG_FIELD_SET(RX_STATE_CONT, tmp, state_cont); WPHY_WRITE_REG(WPHY_MLRX_STATE_CTRL_ADDR, tmp); } void bb_rf_set_dec_cont(uint32_t state_cont) { uint32_t tmp = WPHY_READ_REG(WPHY_DEC_CTRL_ADDR); REG_FIELD_SET(DEC_CONT, tmp, state_cont); WPHY_WRITE_REG(WPHY_DEC_CTRL_ADDR, tmp); } void bb_rf_clear_tx_info() { WPHY_WRITE_REG(WPHY_AHB_IF_CFG_ADDR, 0x12020); } void bb_rf_clear_rx_info() { WPHY_WRITE_REG(WPHY_AHB_IF_CFG_ADDR, 0x22020); } void bb_rf_tx_timer_en(uint32_t enable) { if (RF_VER_1 == bb_rf_get_ver()) { #if RF_VER1_2022_8_15 if (enable) { /* 100us between bb_rf_tx_switch_step2 and bb_rf_tx_timer_en */ uint32_t tx_dlt = gp_timer_get_current_val(0) - tx_switch_step2_us; if (tx_dlt < tx_step2_to_aotx_us) { tx_dlt = tx_step2_to_aotx_us - tx_dlt; iot_delay_us(tx_dlt); } } #endif } uint32_t tmp; tmp = WPHY_READ_REG(WPHY_MLTX_CTRL_ADDR); REG_FIELD_SET(SOTX_TTMR_EN, tmp, enable); REG_FIELD_SET(AOTX_TTMR_EN, tmp, enable); WPHY_WRITE_REG(WPHY_MLTX_CTRL_ADDR, tmp); if (!enable) { tmp = WPHY_READ_REG(WPHY_MLRX_CTRL_ADDR); REG_FIELD_SET(SOTX_TTMR_CLR, tmp, 1); REG_FIELD_SET(AOTX_TTMR_CLR, tmp, 1); WPHY_WRITE_REG(WPHY_MLRX_CTRL_ADDR, tmp); } } void bb_rf_rx_timer_en(uint32_t enable) { uint32_t tmp; tmp = WPHY_READ_REG(WPHY_MLRX_CTRL_ADDR); REG_FIELD_SET(AOCS_TTMR_EN, tmp, enable); REG_FIELD_SET(SOCS_TTMR_EN, tmp, enable); WPHY_WRITE_REG(WPHY_MLRX_CTRL_ADDR, tmp); if (!enable) { tmp = WPHY_READ_REG(WPHY_MLRX_CTRL_ADDR); REG_FIELD_SET(AOCS_TTMR_CLR, tmp, 1); REG_FIELD_SET(SOCS_TTMR_CLR, tmp, 1); WPHY_WRITE_REG(WPHY_MLRX_CTRL_ADDR, tmp); } } void bb_rf_stop_listen_timer_en(uint32_t enable) { uint32_t tmp; tmp = WPHY_READ_REG(WPHY_MLRX_CTRL_ADDR); REG_FIELD_SET(EOCS_TTMR_EN, tmp, enable); WPHY_WRITE_REG(WPHY_MLRX_CTRL_ADDR, tmp); if (!enable) { tmp = WPHY_READ_REG(WPHY_MLRX_CTRL_ADDR); REG_FIELD_SET(EOCS_TTMR_CLR, tmp, 1); WPHY_WRITE_REG(WPHY_MLRX_CTRL_ADDR, tmp); } } void bb_rf_debug_tx_immd() { uint32_t tmp = WPHY_READ_REG(WPHY_MLTX_CTRL_ADDR); REG_FIELD_SET(AOTX_IMMD, tmp, 1); WPHY_WRITE_REG(WPHY_MLTX_CTRL_ADDR, tmp); iot_delay_us(50); tmp = WPHY_READ_REG(WPHY_MLTX_CTRL_ADDR); REG_FIELD_SET(SOTX_IMMD, tmp, 1); WPHY_WRITE_REG(WPHY_MLTX_CTRL_ADDR, tmp); } void bb_rf_debug_rx_immd() { uint32_t tmp = WPHY_READ_REG(WPHY_MLRX_CTRL_ADDR); REG_FIELD_SET(AOCS_IMMD, tmp, 1); WPHY_WRITE_REG(WPHY_MLRX_CTRL_ADDR, tmp); iot_delay_us(50); tmp = WPHY_READ_REG(WPHY_MLRX_CTRL_ADDR); REG_FIELD_SET(SOCS_IMMD, tmp, 1); WPHY_WRITE_REG(WPHY_MLRX_CTRL_ADDR, tmp); } void bb_rf_debug_stop_listen_immd() { uint32_t tmp = WPHY_READ_REG(WPHY_MLRX_CTRL_ADDR); REG_FIELD_SET(EOCS_IMMD, tmp, 1); WPHY_WRITE_REG(WPHY_MLRX_CTRL_ADDR, tmp); } uint32_t bb_rf_get_rx_is_busy() { uint32_t tmp = WPHY_READ_REG(WPHY_MLRX_STAT_ADDR); return REG_FIELD_GET(ARX_BUSY, tmp); } uint32_t bb_rf_get_tx_is_busy() { uint32_t tmp = WPHY_READ_REG(WPHY_MLTX_STAT_ADDR); return REG_FIELD_GET(ATX_BUSY, tmp); } void bb_rf_set_fchz(uint32_t fchz) { uint32_t mode, reg, val; float tmp; if (fchz < 400000000) { mode = 4; } else { reg = rf_spi_read(17); mode = (reg >> 13); } /* val = fchz * mode / 1000 * 335.54432; */ tmp = fchz * mode; tmp = tmp/1000; tmp = tmp * 335.54432; val = (uint32_t)tmp; rf_spi_write(17, (mode << 13) | ((val >> 16) & 0x1fff)); rf_spi_write(18, val & 0xffff); return; } uint32_t bb_rf_get_fchz(void) { uint32_t fchz; uint16_t reg; uint8_t mode; uint32_t val; float tmp; reg = rf_spi_read(17); mode = (reg >> 13); val = (reg & 0x1fff) << 16; reg = rf_spi_read(18); val |= reg; /* fchz = (val / 335544.32 / mode * 1000000); */ tmp = (float)val; tmp = val / 335544.32; tmp = tmp / mode; tmp = tmp * 1000000; fchz = (uint32_t)tmp; return fchz; } #if HPLC_BBCPU_CALC_SNR_RSSI static float bb_rf_get_snr(uint32_t option, uint16_t *raw_snr) { float snr; float rdata = (float)WPHY_INIT_READ_REG(0xf0102c); float rawdata = (1<<16)*1.0/(rdata*1.0/((option==3) ? 36 : 96)); float tmp = rawdata * 10 + 0.5; *raw_snr = (uint16_t)(min(0xFFFF, (uint32_t)tmp)); if (rawdata >= 1) { snr = 10*mlog10(rawdata); } else { snr = 10*na_mlog10(rawdata); } return snr; } float bb_rf_get_rssi() { float rdata1 = (float)WPHY_INIT_READ_REG(0xf01330); uint32_t rdata2 = WPHY_INIT_READ_REG(0xf01328); float rssi = 10*mlog10(rdata1*1.0) - 70 - (rdata2 & 0xFF) - ((rdata2 >> 8) & 0xFF); return rssi; } void bb_rf_get_snr_rssi(uint32_t option, int8_t *snr, int8_t *rssi, uint8_t *gain, uint16_t *raw_snr) { /* X can be got by calibration */ #define X_CALIBRATION 60 float snr_tmp = bb_rf_get_snr(option, raw_snr); float rdata1 = (float)WPHY_INIT_READ_REG(0xf01330); uint32_t rdata2 = WPHY_INIT_READ_REG(0xf01328); float rssi_tmp = 10*mlog10(rdata1*1.0) - X_CALIBRATION - (rdata2 & 0xFF) - ((rdata2 >> 8) & 0xFF) + ((snr_tmp < 0) ? snr_tmp: 0); /* 13 - 74 */ *gain = (uint8_t)((rdata2 & 0xFF) + ((rdata2 >> 8) & 0xFF)); *snr = (int8_t)snr_tmp; *rssi = (int8_t)rssi_tmp; } #else /* HPLC_BBCPU_CALC_SNR_RSSI */ uint32_t bb_rf_get_raw_snr_rssi_reg1() { /* snr/rssi/rxgain raw data register 1 */ return WPHY_INIT_READ_REG(0xf0102c); } uint32_t bb_rf_get_raw_snr_rssi_reg2() { /* snr/rssi/rxgain raw data register 2 */ return WPHY_INIT_READ_REG(0xf01330); } uint32_t bb_rf_get_raw_snr_rssi_reg3() { /* snr/rssi/rxgain raw data register 3 */ return WPHY_INIT_READ_REG(0xf01328); } #endif /* HPLC_BBCPU_CALC_SNR_RSSI */ uint8_t bb_rf_get_cur_gain() { uint32_t rdata2 = WPHY_INIT_READ_REG(0xf01328); uint8_t gain = (uint8_t)((rdata2 & 0xFF) + ((rdata2 >> 8) & 0xFF)); return gain; } int32_t bb_rf_get_evaluate_ppm_hz() { uint32_t tmp = WPHY_INIT_READ_REG(0xf01448); int32_t ppm_hz; if (tmp & 0x800000) { ppm_hz = (int32_t)(0xFF000000 | (tmp & 0xFFFFFF)); } else { ppm_hz = (int32_t)(tmp & 0xFFFFFF); } return ppm_hz; } uint32_t bb_rf_get_interweave_offset(uint32_t rate, uint8_t blkz) { switch (rate) { case RF_CODING_RATE_1_2: { switch (blkz) { case BLOCK_SIZE_0: return RF_INTERWEAVE_OFFSET_16; case BLOCK_SIZE_1: return RF_INTERWEAVE_OFFSET_40; case BLOCK_SIZE_2: return RF_INTERWEAVE_OFFSET_72; case BLOCK_SIZE_3: return RF_INTERWEAVE_OFFSET_136; case BLOCK_SIZE_4: return RF_INTERWEAVE_OFFSET_264; case BLOCK_SIZE_5: return RF_INTERWEAVE_OFFSET_520; default: IOT_ASSERT(0); break; } break; } case RF_CODING_RATE_4_5: { switch (blkz) { case BLOCK_SIZE_0: return RF_INTERWEAVE_OFFSET_4; case BLOCK_SIZE_1: return RF_INTERWEAVE_OFFSET_10; case BLOCK_SIZE_2: return RF_INTERWEAVE_OFFSET_18; case BLOCK_SIZE_3: return RF_INTERWEAVE_OFFSET_34; case BLOCK_SIZE_4: return RF_INTERWEAVE_OFFSET_66; case BLOCK_SIZE_5: return RF_INTERWEAVE_OFFSET_130; default: IOT_ASSERT(0); break; } break; } default: IOT_ASSERT(0); } return 0; } uint32_t bb_rf_get_interweave_step(uint32_t rate, uint8_t blkz) { switch (rate) { case RF_CODING_RATE_1_2: { switch (blkz) { case BLOCK_SIZE_0: case BLOCK_SIZE_1: return RF_INTERWEAVE_STEP_4; case BLOCK_SIZE_2: case BLOCK_SIZE_3: case BLOCK_SIZE_4: case BLOCK_SIZE_5: return RF_INTERWEAVE_STEP_16; default: IOT_ASSERT(0); break; } break; } case RF_CODING_RATE_4_5: { switch (blkz) { case BLOCK_SIZE_0: return RF_INTERWEAVE_STEP_4; case BLOCK_SIZE_1: return RF_INTERWEAVE_STEP_5; case BLOCK_SIZE_2: return RF_INTERWEAVE_STEP_18; case BLOCK_SIZE_3: return RF_INTERWEAVE_STEP_17; case BLOCK_SIZE_4: return RF_INTERWEAVE_STEP_12; case BLOCK_SIZE_5: return RF_INTERWEAVE_STEP_13; default: IOT_ASSERT(0); break; } break; } default: IOT_ASSERT(0); } return 0; } void bb_rf_write_data_to_bb(uint32_t pb_size, uint8_t *buf) { uint32_t i, j; uint32_t tmp, rawdata, real_num, pb_size_word, num; IOT_ASSERT(buf && (((uint32_t)buf & 0x03) == 0) && ((pb_size & 0x03) == 0)); /* uint word */ pb_size_word = pb_size/4; /* get the number of words at a time */ num = 8; /* use copy replace dma */ for (i = 0; i < pb_size_word; i = i + num) { do { tmp = RFPLC_GENERAL_READ_REG(CFG_RFPLC_STATUS_ADDR); } while(!REG_FIELD_GET(CFG_RFPLC_WPHY_TX_BRDY, tmp)); if (pb_size_word - i <= num) { real_num = pb_size_word - i; } else { real_num = num; } /* put 8 words at a time */ for (j = 0; j < real_num; j++) { rawdata = *(((uint32_t *)buf) + i + j); RF_MAC_TX_DMA_WRITE_REG(((i + j) << 2), rawdata); } } } void bb_rf_read_data_from_bb(uint32_t pb_size, uint8_t *buf) { uint32_t i, j; uint32_t tmp, rawdata, real_num, pb_size_word, num; IOT_ASSERT(buf && (((uint32_t)buf & 0x03) == 0) && ((pb_size & 0x03) == 0)); /* uint word */ pb_size_word = pb_size/4; /* get the number of words at a time */ num = 8; /* use copy replace dma */ for (i = 0; i < pb_size_word; i = i + num) { do { tmp = RFPLC_GENERAL_READ_REG(CFG_RFPLC_STATUS_ADDR); } while(!REG_FIELD_GET(CFG_RFPLC_WPHY_RX_BRDY, tmp)); if (pb_size_word - i <= num) { real_num = pb_size_word - i; } else { real_num = num; } /* get 8 words at a time */ for (j = 0; j < real_num; j++) { rawdata = RF_MAC_RX_DMA_READ_REG(((i + j) << 2)); *(((uint32_t *)buf) + i + j) = rawdata; } } } static uint32_t bb_rf_set_pa_ldovs(uint16_t val) { uint16_t init; init = rf_spi_read(5); init &= 0xf803; init |= (val << 2); if (rf_spi_write(5, init)) { return 1; } return 0; } void bb_rf_set_test_mode(uint32_t rf_outside, uint8_t mode) { uint16_t special_tx_ldovs, special_tx_scale; if (rf_outside) { if (mode == 0) { rf_spi_write(4, 0xFFC6); rf_spi_write(5, 0xA7FE); rf_spi_write(24,0xBF7); bb_rf_set_pa_ldovs(511); WPHY_INIT_WRITE_REG(0xf0101C, 0x30040); } else if (mode == 1) { rf_spi_write(4, 0xFFCF); rf_spi_write(5, 0xA39A); rf_spi_write(24,0xBF7); special_tx_ldovs = mac_rf_get_tx_special_ldovs(); if (special_tx_ldovs == 0) { special_tx_ldovs = 300; } special_tx_scale = mac_rf_get_tx_special_scale(); if (special_tx_scale == 0) { special_tx_scale = 0x80; } bb_rf_set_pa_ldovs(special_tx_ldovs); WPHY_INIT_WRITE_REG(0xf0101C, 0x30000 | special_tx_scale); } else { IOT_ASSERT(0); } } else { if (mode == 0) { rf_spi_write(4, 0xFFC6); rf_spi_write(5, 0xA692); rf_spi_write(24,0xBF7); bb_rf_set_pa_ldovs(420); WPHY_INIT_WRITE_REG(0xf0101C, 0x30040); } else if (mode == 1) { rf_spi_write(4, 0xFFCF); rf_spi_write(5, 0xA322); rf_spi_write(24,0xBF7); bb_rf_set_pa_ldovs(200); WPHY_INIT_WRITE_REG(0xf0101C, 0x30100); } else { IOT_ASSERT(0); } } } static void bb_rf_set_test_mode_v2() { uint32_t user_type, proto; if (!mac_rf_get_cert_16qam_flag()) { proto = mac_rf_get_proto(); if (proto == PLC_PROTO_TYPE_SPG) { bb_rf_set_pa(1, 15); goto out; } else { user_type = mac_rf_get_user_type(); if (user_type == USER_TYPE_STATE_GRID_BJ && mac_rf_is_sta()) { bb_rf_set_pa(1, 10); goto out; } else if (user_type == USER_TYPE_STATE_GRID_XIAN) { rf_spi_write(24, 0xBDF); bb_rf_set_pa_ldovs(250); WPHY_INIT_WRITE_REG(0xf0101C, 0x300A8); goto out; } } } bb_rf_set_pa(1, 5); out: return; } void bb_rf_tx_switch_step1() { if (RF_VER_1 == bb_rf_get_ver()) { #if RF_VER1_2022_8_15 rf_spi_write(0, 0xEBBA); tx_switch_step1_us = gp_timer_get_current_val(0); /* need delay 100us */ #endif } } void bb_rf_tx_switch_step2() { uint8_t ver = bb_rf_get_ver(); if (RF_VER_1 == ver) { /* version 1 */ #if RF_VER1_2022_8_15 /* 100us between bb_rf_tx_switch_step1 and bb_rf_tx_switch_step2 */ uint32_t tx_switch_dlt = gp_timer_get_current_val(0) - tx_switch_step1_us; if (tx_switch_dlt < BB_CPU_TXCFG1_TXCFG2_DELAY_US) { tx_switch_dlt = BB_CPU_TXCFG1_TXCFG2_DELAY_US - tx_switch_dlt; iot_delay_us(tx_switch_dlt); } rf_spi_write(0, 0xFBBB); tx_switch_step2_us = gp_timer_get_current_val(0); /* this position to aotx(bb_cpu_mac_trigger_tx) need some delay time * the time is: * special mode(hplc2rf cert mode) option2 100us * special mode(hplc2rf cert mode) option3 500us * normal mode(10dbm) option2 5us * normal mode(10dbm) option3 150us */ #else bb_rf_pll_cfg(); uint16_t init; init = rf_spi_read(0); init |= 0xf813; init &= 0xfbff; rf_spi_write(0, init); init = rf_spi_read(1); init &= 0xfd3f; init |= 0x800; rf_spi_write(1, init); iot_delay_us(150); init = rf_spi_read(1); init |= 0x2c0; init &= 0xf7ff; rf_spi_write(1, init); #endif } else if (RF_VER_2 == ver || RF_VER_3 == ver) { /* version 2 & 3 */ bb_rf_pll_cfg(); /* set bit[24:23]=2'b10; */ /* improve tx power */ uint32_t rdata = WPHY_INIT_READ_REG(0xf01304); WPHY_INIT_WRITE_REG(0xf01304, (rdata & 0xfe7fffff) | (2 << 23)); uint16_t init; init = rf_spi_read(0); if (RF_VER_2 == ver) { init |= 0x1254; } else { /* tx state config. * R0<12> set to 1, PA ldo enable. * R0<13> set to 1, TRX Bandgap enable. * R0<6> set to 1, GAIN/STOP_AGC switch to STOP_AGC function. * R0<4> set to 1, TRX bias enable. * R0<2> set to 1, TRX ldo enable. */ init |= (1 << 12) | (1 << 13) |(1 << 6) | (1 << 4) | (1 << 2); } rf_spi_write(0, init); iot_delay_us(50); /* R0<1> set to 1, switch tx state */ init |= (1 << 0); rf_spi_write(0, init); if (RF_VER_3 == ver) { init = rf_spi_read(9); rf_spi_write(9, init | 0x1); } } else { IOT_ASSERT(0); } iot_delay_us(5); } static void __bb_rf_tx_set_freq_and_filter(uint32_t option, uint32_t fchz) { uint16_t bw_sel; uint8_t en; uint8_t ver = bb_rf_get_ver(); /* set fchz */ bb_rf_set_fchz(fchz); if (option == PHY_RF_OPTION2_500K || option == PHY_RF_OPTION3_200K) { mac_rf_get_tx_filter_cali(option, &en, &bw_sel); if (!en) { if (option == PHY_RF_OPTION2_500K) { if (ver == RF_VER_3) { bw_sel = 0x53; } else { bw_sel = 0x51; } } else { if (ver == RF_VER_3) { bw_sel = 0x136; } else { bw_sel = 0xD1; } } } bb_rf_set_filter(bw_sel); } } static uint32_t cert_special_cfg = !ENA_RF_CERT_SPECIAL_CFG; void bb_rf_tx_set_freq_and_filter(uint32_t option, uint32_t fchz) { /* set fchz */ __bb_rf_tx_set_freq_and_filter(option, fchz); /* spur and spectrum test */ if (cert_special_cfg == 0 && mac_rf_get_cert_mode() == CERT_TEST_CMD_ENTER_PHY_HPLC2RF_LP) { /* TODO: EVM cert test need use this configuration * need add. */ cert_special_cfg = 1; if (RF_VER_2 == bb_rf_get_ver()) { bb_rf_set_test_mode_v2(); } else if (RF_VER_1 == bb_rf_get_ver()) { bb_rf_set_pa(1, 5); } else if (RF_VER_3 == bb_rf_get_ver()) { bb_rf_set_pa(1, 5); } else { IOT_ASSERT(0); } } else if (cert_special_cfg && mac_rf_get_cert_mode() != CERT_TEST_CMD_ENTER_PHY_HPLC2RF_LP) { cert_special_cfg = 0; bb_rf_set_pa(1, bb_cpu_get_tx_pwr()); } if (RF_VER_1 == bb_rf_get_ver()) { #if RF_VER1_2022_8_15 /* record the time of delay bb_rf_tx_switch_step2 and aotx */ if (cert_special_cfg) { if (option == PHY_RF_OPTION3_200K) { tx_step2_to_aotx_us = BB_CPU_AOTX_TXCFG_SPC_OP3_DELAY_US; } else { /* option2 and option1 */ tx_step2_to_aotx_us = BB_CPU_AOTX_TXCFG_SPC_OP2_DELAY_US; } } else { if (option == PHY_RF_OPTION3_200K) { tx_step2_to_aotx_us = BB_CPU_AOTX_TXCFG_OP3_DELAY_US; } else { tx_step2_to_aotx_us = BB_CPU_AOTX_TXCFG_OP2_DELAY_US; } } #endif } } void bb_rf_tx_cfg(uint32_t option, uint32_t fchz) { bb_rf_tx_switch_step1(); bb_rf_tx_switch_step2(); __bb_rf_tx_set_freq_and_filter(option, fchz); } static void bb_rf_rx_switch_step1() { if (RF_VER_1 == bb_rf_get_ver()) { #if RF_VER1_2022_8_15 rf_spi_write(0, 0xEBBB); rx_switch_step1_us = gp_timer_get_current_val(0); /* need delay 100us */ #endif } } static void bb_rf_rx_switch_step2() { uint8_t ver = bb_rf_get_ver(); if (RF_VER_1 == ver) { /* version 1 */ #if RF_VER1_2022_8_15 /* 100us between bb_rf_rx_switch_step1 and bb_rf_rx_switch_step2 */ uint32_t rx_switch_dlt = gp_timer_get_current_val(0) - rx_switch_step1_us; if (rx_switch_dlt < 105) { rx_switch_dlt = 105 - rx_switch_dlt; iot_delay_us(rx_switch_dlt); } rf_spi_write(0, 0xEBBA); #else bb_rf_pll_cfg(); uint16_t init; init = rf_spi_read(0); init |= 0xe812; init &= 0xebfe; rf_spi_write(0, init); #endif } else if (RF_VER_2 == ver || RF_VER_3 == ver) { /* version 2 & 3 */ bb_rf_pll_cfg(); /* set bit[24:23]=2'b01; */ uint32_t rdata = WPHY_INIT_READ_REG(0xf01304); WPHY_INIT_WRITE_REG(0xf01304, (rdata & 0xfe7fffff) | (1 << 23)); uint16_t init; init = rf_spi_read(0); init |= 0x0014; if (RF_VER_3 == ver) { init |= (1 << 13); } init &= 0xffbf; rf_spi_write(0, init); if (RF_VER_3 == ver) { init = rf_spi_read(9); rf_spi_write(9, init & (~0x1)); } } else { IOT_ASSERT(0); } /* 2us; */ iot_delay_us(5); } static void bb_rf_rx_set_freq_and_filter(uint32_t option, uint32_t fchz) { uint16_t bw_sel; uint8_t ver = bb_rf_get_ver(); uint32_t temp; if (ver == RF_VER_3 && HPLC_RF_RX_BPF_EN) { temp = ((option == PHY_RF_OPTION1_1M) ? 0 : (option == PHY_RF_OPTION2_500K) ? RF_OPT2_RX_BPF_CONSTANT_FREQ_HZ : RF_OPT3_RX_BPF_CONSTANT_FREQ_HZ); } else { temp = ((option == PHY_RF_OPTION1_1M) ? 0 : (option == PHY_RF_OPTION2_500K) ? RF_OPT2_RX_LPF_CONSTANT_FREQ_HZ : RF_OPT3_RX_LPF_CONSTANT_FREQ_HZ); } /* set fchz */ bb_rf_set_fchz(fchz + temp); if (option == PHY_RF_OPTION2_500K) { if (ver == RF_VER_3 && HPLC_RF_RX_BPF_EN) { bw_sel = 0x53; } else { bw_sel = 0x26; } bb_rf_set_filter(bw_sel); } else if (option == PHY_RF_OPTION3_200K) { if (ver == RF_VER_3 && HPLC_RF_RX_BPF_EN) { bw_sel = 0x136; } else { bw_sel = 0x51; } bb_rf_set_filter(bw_sel); } } void bb_rf_rx_cfg(uint32_t option, uint32_t fchz) { bb_rf_rx_switch_step1(); bb_rf_rx_switch_step2(); bb_rf_rx_set_freq_and_filter(option, fchz); } static uint16_t bb_rf_get_pa_ldovs(void) { uint16_t val; val = rf_spi_read(5); return (val & 0x7fc) >> 2; } typedef struct scale_dbm_s { uint32_t ldovs : 9, scale : 12, rsvd : 11; uint16_t r24; int16_t dbm; } scale_dbm_t; #if 0 //rf inside static const scale_dbm_t pa_in[] = { {420, 0x100, 0x0, 0xBFB, 18}, {420, 0x0D0, 0x0, 0xBFB, 17}, {420, 0x0B0, 0x0, 0xBFB, 16}, {420, 0x0A0, 0x0, 0xBFB, 15}, {420, 0x080, 0x0, 0xBFB, 14}, {420, 0x0f8, 0x0, 0xBF7, 13}, {420, 0x0D8, 0x0, 0xBF7, 12}, {420, 0x0C0, 0x0, 0xBF7, 11}, {420, 0x0A8, 0x0, 0xBF7, 10}, {420, 0x098, 0x0, 0xBF7, 9}, {420, 0x088, 0x0, 0xBF7, 8}, {420, 0x078, 0x0, 0xBF7, 7}, {420, 0x068, 0x0, 0xBF7, 6}, {420, 0x058, 0x0, 0xBF7, 5}, {420, 0x050, 0x0, 0xBF7, 4}, {420, 0x045, 0x0, 0xBF7, 3}, {420, 0x080, 0x0, 0xBEF, 2}, {420, 0x070, 0x0, 0xBEF, 1}, {420, 0x060, 0x0, 0xBEF, 0}, {420, 0x058, 0x0, 0xBEF, -1}, {420, 0x048, 0x0, 0xBEF, -2}, {420, 0x040, 0x0, 0xBEF, -3}, {410, 0x040, 0x0, 0xBEF, -4}, {400, 0x040, 0x0, 0xBEF, -5}, {390, 0x040, 0x0, 0xBEF, -6}, {380, 0x040, 0x0, 0xBEF, -7}, {370, 0x040, 0x0, 0xBEF, -8}, {360, 0x040, 0x0, 0xBEF, -9}, {350, 0x040, 0x0, 0xBEF, -10}, {345, 0x040, 0x0, 0xBEF, -11}, {335, 0x040, 0x0, 0xBEF, -12}, {330, 0x040, 0x0, 0xBEF, -13}, {320, 0x040, 0x0, 0xBEF, -14}, {310, 0x040, 0x0, 0xBEF, -15}, {300, 0x040, 0x0, 0xBEF, -17}, {200, 0x041, 0x0, 0xBEF, -35.8} }; #endif //rf outside static const scale_dbm_t pa_out[] = { {511, 0x100, 0x0, 0xBFB, 20}, {511, 0x0C8, 0x0, 0xBFB, 19}, {511, 0x0B0, 0x0, 0xBFB, 18}, {511, 0x098, 0x0, 0xBFB, 17}, {511, 0x088, 0x0, 0xBFB, 16}, {511, 0x0f0, 0x0, 0xBF7, 15}, {511, 0x0E0, 0x0, 0xBF7, 14}, {511, 0x0C8, 0x0, 0xBF7, 13}, {511, 0x0A0, 0x0, 0xBF7, 12}, {511, 0x090, 0x0, 0xBF7, 11}, {511, 0x080, 0x0, 0xBF7, 10}, {511, 0x070, 0x0, 0xBF7, 9}, {511, 0x060, 0x0, 0xBF7, 8}, {511, 0x058, 0x0, 0xBF7, 7}, {511, 0x050, 0x0, 0xBF7, 6}, {511, 0x048, 0x0, 0xBF7, 5}, {420, 0x076, 0x0, 0xBF7, 4}, {420, 0x067, 0x0, 0xBF7, 3}, {420, 0x057, 0x0, 0xBF7, 2}, {420, 0x050, 0x0, 0xBF7, 1}, {420, 0x048, 0x0, 0xBF7, 0}, {420, 0x040, 0x0, 0xBF7, -1}, {470, 0x040, 0x0, 0xBEF, -2}, {450, 0x040, 0x0, 0xBEF, -3}, {430, 0x040, 0x0, 0xBEF, -4}, {420, 0x040, 0x0, 0xBEF, -5}, {400, 0x040, 0x0, 0xBEF, -6}, {390, 0x040, 0x0, 0xBEF, -7}, {380, 0x040, 0x0, 0xBEF, -8}, {370, 0x040, 0x0, 0xBEF, -9}, {360, 0x040, 0x0, 0xBEF, -10}, {350, 0x040, 0x0, 0xBEF, -11}, {340, 0x041, 0x0, 0xBEF, -12}, {330, 0x042, 0x0, 0xBEF, -13}, {320, 0x043, 0x0, 0xBEF, -14}, {310, 0x044, 0x0, 0xBEF, -15}, {300, 0x045, 0x0, 0xBEF, -17}, {200, 0x046, 0x0, 0xBEF, -35} }; static const scale_dbm_t pa_v2[] = { {511, 0x098, 0x0, 0xBFB, 21}, {511, 0x088, 0x0, 0xBFB, 20}, {511, 0x070, 0x0, 0xBFB, 19}, {511, 0x060, 0x0, 0xBFB, 18}, {511, 0x050, 0x0, 0xBFB, 17}, {511, 0x088, 0x0, 0xBF7, 16}, {511, 0x078, 0x0, 0xBF7, 15}, {511, 0x068, 0x0, 0xBF7, 14}, {511, 0x058, 0x0, 0xBF7, 13}, {511, 0x050, 0x0, 0xBF7, 12}, {511, 0x090, 0x0, 0xBEF, 11}, {511, 0x080, 0x0, 0xBEF, 10}, {511, 0x070, 0x0, 0xBEF, 9}, {511, 0x060, 0x0, 0xBEF, 8}, {511, 0x058, 0x0, 0xBEF, 7}, {511, 0x098, 0x0, 0xBDF, 6}, {511, 0x088, 0x0, 0xBDF, 5}, {511, 0x078, 0x0, 0xBDF, 4}, {511, 0x068, 0x0, 0xBDF, 3}, {511, 0x060, 0x0, 0xBDF, 2}, {511, 0x058, 0x0, 0xBDF, 1}, {511, 0x0A0, 0x0, 0xBBF, 0}, {511, 0x090, 0x0, 0xBBF, -1}, {511, 0x080, 0x0, 0xBBF, -2}, {511, 0x070, 0x0, 0xBBF, -3}, {511, 0x068, 0x0, 0xBBF, -4}, {511, 0x060, 0x0, 0xBBF, -5}, {511, 0x050, 0x0, 0xBBF, -6}, {370, 0x090, 0x0, 0xBBF, -7}, {350, 0x090, 0x0, 0xBBF, -8}, {330, 0x090, 0x0, 0xBBF, -9}, {320, 0x090, 0x0, 0xBBF, -10}, {310, 0x090, 0x0, 0xBBF, -11}, {290, 0x090, 0x0, 0xBBF, -12}, {280, 0x090, 0x0, 0xBBF, -13} }; static const scale_dbm_t pa_v3[] = { {511, 0x0a4, 0x0, 0xBFE, 21}, {511, 0x08c, 0x0, 0xBFE, 20}, {511, 0x0ee, 0x0, 0xBFD, 19}, {511, 0x0ce, 0x0, 0xBFD, 18}, {511, 0x0b8, 0x0, 0xBFD, 17}, {511, 0x09e, 0x0, 0xBFD, 16}, {511, 0x08c, 0x0, 0xBFD, 15}, {511, 0x07c, 0x0, 0xBFD, 14}, {511, 0x0d9, 0x0, 0xBFB, 13}, {511, 0x0c5, 0x0, 0xBFB, 12}, {511, 0x0ab, 0x0, 0xBFB, 11}, {511, 0x09d, 0x0, 0xBFB, 10}, {511, 0x089, 0x0, 0xBFB, 9}, {511, 0x0fa, 0x0, 0xBF7, 8}, {511, 0x0de, 0x0, 0xBF7, 7}, {511, 0x0c8, 0x0, 0xBF7, 6}, {511, 0x0b0, 0x0, 0xBF7, 5}, {511, 0x09e, 0x0, 0xBF7, 4}, {511, 0x088, 0x0, 0xBF7, 3}, {511, 0x078, 0x0, 0xBF7, 2}, {511, 0x09f, 0x0, 0xBF7, 1}, {460, 0x071, 0x0, 0xBF7, 0}, {300, 0x054, 0x0, 0xBFB, -1}, {250, 0x064, 0x0, 0xBFB, -2}, {250, 0x05a, 0x0, 0xBFB, -3}, {250, 0x052, 0x0, 0xBFB, -4}, {250, 0x048, 0x0, 0xBFB, -5}, {300, 0x060, 0x0, 0xBF7, -6}, {300, 0x054, 0x0, 0xBF7, -7}, {250, 0x062, 0x0, 0xBF7, -8}, {250, 0x05a, 0x0, 0xBF7, -9}, {250, 0x050, 0x0, 0xBF7, -10}, {250, 0x048, 0x0, 0xBF7, -11}, {250, 0x040, 0x0, 0xBF7, -12}, {250, 0x03a, 0x0, 0xBF7, -13}, {250, 0x064, 0x0, 0xBEF, -14}, {220, 0x032, 0x0, 0xBBF, -35}, }; int32_t bb_rf_get_pa(uint32_t rf_outside) { uint32_t i; float dbm; uint16_t r24; const scale_dbm_t *p = NULL; uint32_t nr = 0; uint8_t ver = bb_rf_get_ver(); int32_t scale = WPHY_INIT_READ_REG(0xf0101C) & 0xfff; uint32_t ldovs = bb_rf_get_pa_ldovs(); if (RF_VER_1 == ver) { if (rf_outside) { p = pa_out; nr = IOT_ARRAY_CNT(pa_out); } else { //p = pa_in; //nr = IOT_ARRAY_CNT(pa_in); p = pa_out; nr = IOT_ARRAY_CNT(pa_out); } } else if (RF_VER_2 == ver) { p = pa_v2; nr = IOT_ARRAY_CNT(pa_v2); } else if (RF_VER_3 == ver) { p = pa_v3; nr = IOT_ARRAY_CNT(pa_v3); } else { IOT_ASSERT(0); } r24 = rf_spi_read(24); for (i = 0; i < nr; i++) { if (scale == p[i].scale && ldovs == p[i].ldovs && r24 == p[i].r24) { dbm = p[i].dbm; return (int32_t)dbm; } } return 0; } uint32_t bb_rf_set_pa(uint32_t rf_outside, int32_t dbm) { int i; const scale_dbm_t *p = NULL; uint32_t nr = 0; uint8_t ver = bb_rf_get_ver(); if (RF_VER_1 == ver) { if (rf_outside) { p = pa_out; nr = IOT_ARRAY_CNT(pa_out); } else { //p = pa_in; //nr = IOT_ARRAY_CNT(pa_in); p = pa_out; nr = IOT_ARRAY_CNT(pa_out); } } else if (RF_VER_2 == ver) { p = pa_v2; nr = IOT_ARRAY_CNT(pa_v2); } else if (RF_VER_3 == ver) { p = pa_v3; nr = IOT_ARRAY_CNT(pa_v3); } else { IOT_ASSERT(0); } for (i = 0; i < nr; i++) { if (dbm >= p[i].dbm) { WPHY_INIT_WRITE_REG(0xf0101C, p[i].scale | 0x30000); if (bb_rf_set_pa_ldovs(p[i].ldovs)) { return 1; } if (rf_spi_write(24, p[i].r24)) { return 1; } return 0; } } return 0; } void bb_rf_set_tx_iq_mag(uint8_t tx_i_m, uint8_t tx_q_m) { uint16_t value; value = rf_spi_read(9); value &= 0xffC3; value |= (tx_i_m << 2); rf_spi_write(9, value); value = rf_spi_read(10); value &= 0xFFF; value |= (tx_q_m << 12); rf_spi_write(10, value); } void bb_rf_set_tx_iq_phase(uint8_t tx_i_p, uint8_t tx_q_p) { uint16_t value = 0; value = rf_spi_read(23); value &= ~(0x03ff); value |= (tx_q_p | tx_i_p << 5); rf_spi_write(23, value); } void bb_rf_set_rx_iq_mag(uint8_t i_mag, uint8_t q_mag) { uint16_t init = rf_spi_read(9); uint16_t i_mag_mask = 0xF000; uint16_t i_mag_shift = 12; uint16_t q_mag_mask = 0x0780; uint16_t q_mag_shift = 7; init &= ~(i_mag_mask | q_mag_mask); init |= ((i_mag << i_mag_shift) & i_mag_mask) | ( (q_mag << q_mag_shift) & q_mag_mask); rf_spi_write(9, init); } void bb_rf_set_tx_dc(int8_t tx_i_dc, int8_t tx_q_dc) { uint16_t value = 0; uint8_t temp1, temp2; temp1 = IOT_ABS(tx_i_dc); temp2 = IOT_ABS(tx_q_dc); if (tx_i_dc < 0) { value |= 0x8000; } if (tx_q_dc < 0) { value |= 0x4000; } value |= (temp2 | temp1 << 7); rf_spi_write(8, value); } void bb_rf_set_filter(uint16_t value) { uint16_t init; init = rf_spi_read(7); init &= 0x7f; init |= (value << 7); rf_spi_write(7, init); } void bb_rf_update_cali(uint8_t option) { uint8_t tx_i_m, tx_q_m, tx_i_p, tx_q_p, tx_i_dc, tx_q_dc; uint8_t bw_en; uint16_t bw_sel; mac_rf_get_tx_iqm_cali(&tx_i_m, &tx_q_m); bb_rf_set_tx_iq_mag(tx_i_m, tx_q_m); mac_rf_get_tx_iqp_cali(&tx_i_p, &tx_q_p); bb_rf_set_tx_iq_phase(tx_i_p, tx_q_p); mac_rf_get_tx_dc_cali(&tx_i_dc, &tx_q_dc); bb_rf_set_tx_dc((int8_t)tx_i_dc, (int8_t)tx_q_dc); mac_rf_get_tx_filter_cali(option, &bw_en, &bw_sel); if (bw_en) { // 0x1087 & 0x7f -> 7 bb_rf_set_filter(bw_sel); } return; } static uint32_t bb_rf_judge_ver() { #define GET_VER_TIMEOUT_100MS 100000 uint32_t cur_time; uint32_t time_span; uint32_t start_us; uint16_t reg0, reg0_tmp; uint16_t val; val = rf_spi_read(22); if ((val & 0xff) == 0x4C) { return RF_VER_3; } reg0 = rf_spi_read(0); reg0_tmp = reg0; reg0 |= 0x4800; reg0 &= 0x7FFF; rf_spi_write(0, reg0); /* bit14 | bit11 */ iot_delay_us(200); val = rf_spi_read(20); if ((val >> 15) == 0) { val = rf_spi_read(12); val &= 0xff7f; if (rf_spi_write(12, val)) { return RF_VER_INVAILD; } iot_delay_us(1); val |= 0x80; if (rf_spi_write(12, val)) { return RF_VER_INVAILD; } } val = rf_spi_read(20); start_us = gp_timer_get_current_val(0); while ((val >> 15) == 0) { cur_time = gp_timer_get_current_val(0); time_span = cur_time - start_us; if (time_span > GET_VER_TIMEOUT_100MS*10) { bb_cpu_printf("rf version detect failed\n"); return RF_VER_INVAILD; } val = rf_spi_read(20); iot_delay_us(5); } rf_spi_write(0, reg0 | 0x8000); val = rf_spi_read(20); start_us = gp_timer_get_current_val(0); while ((val >> 15) == 0) { cur_time = gp_timer_get_current_val(0); time_span = cur_time - start_us; if (time_span > GET_VER_TIMEOUT_100MS) { rf_spi_write(0, reg0_tmp); return RF_VER_2; } val = rf_spi_read(20); iot_delay_us(5); } rf_spi_write(0, reg0_tmp); return RF_VER_1; /* rf v1*/ } uint32_t bb_rf_init_ver() { uint32_t rf_ver, ret = 1; rf_ver = mac_rf_get_rf_ver(); if (phy_rf_check_rf_version(rf_ver)) { ret = 0; } else if (rf_ver == RF_VER_UNKNOWN) { /* if rf ver is unkonw, set default ver(v1) */ rf_ver = RF_VER_1; ret = 0; } if (ret == 0) { g_bbcpu_rf_ver = rf_ver; bb_cpu_printf("get rf ver:%d - %d\n", mac_rf_get_rf_ver(), rf_ver); return 0; } for (uint32_t i = 0; i < 1; i++) { rf_ver = bb_rf_judge_ver(); if (rf_ver != RF_VER_INVAILD) { break; } } /* get rf ver fail, default to use v1 configuration */ if (rf_ver == RF_VER_INVAILD) { rf_ver = RF_VER_1; mac_rf_set_rf_ver(RF_VER_UNKNOWN); } else { mac_rf_set_rf_ver(rf_ver); } g_bbcpu_rf_ver = rf_ver; return 0; } uint32_t bb_rf_get_ver() { return g_bbcpu_rf_ver; } void bb_rf_pll_cfg(void) { uint8_t ver = bb_rf_get_ver(); if (RF_VER_1 == ver) { uint16_t init; init = rf_spi_read(0); init |= 0xe801; init &= 0xebff; rf_spi_write(0, init); } else if (RF_VER_2 == ver || RF_VER_3 == ver) { uint16_t init; init = rf_spi_read(0); uint16_t flag = init & 0x4000; if (RF_VER_3 == ver) { /* PLL state config * R0<15> set to 0, PFD capless LDO enable * R0<14> set to 1, pll ldo enable * R0<11> set to 1, pfd vdd select VDD_capless * R0<13> set to 0, TRX Bnadgap power down. * note:for V1 and V2 chips, TRX Bnadgap is enabled in the PLL * state, which can improve the tx success rate * R0<12> set to 0, PA ldo power down. * R0<2> set to 0, TRX ldo power down. */ init |= (1 << 11); if (!mac_rf_is_rf_in()) { init |= (1 << 14); } init &= ~((1 << 15) | (1 << 13) | (1 << 12) | (1 << 2) | (1 << 0)); } else { init |= 0x6800; init &= 0x6bea; } rf_spi_write(0, init); if (flag == 0) iot_delay_us(200); else iot_delay_us(50); init = rf_spi_read(20); if ((init >> 15) == 0) { init = rf_spi_read(12); init &= 0xff7f; rf_spi_write(12, init); iot_delay_us(1); init |= 0x80; rf_spi_write(12, init); } } else { IOT_ASSERT(0); } } void bb_rf_standby_cfg(void) { uint8_t ver = bb_rf_get_ver(); uint16_t val; if (RF_VER_2 == ver || RF_VER_3 == ver) { val = rf_spi_read(0); /* standby state config * R0<15> set to 1, PFD capless LDO power down * R0<14> set to 0, pll ldo power down * R0<11> set to 1, pfd vdd select VDD_capless * R0<13> set to 0, TRX Bnadgap power down. * note:for V1 and V2 chips, TRX Bnadgap is enabled in the PLL * state, which can improve the tx success rate * R0<12> set to 0, PA ldo power down. * R0<2> set to 0, TRX ldo power down. */ val |= (1 << 15) | (1 << 11); val &= ~((1 << 14) | (1 << 13) | (1 << 12) | (1 << 2) | (1 << 0)); rf_spi_write(0, val); } } static int16_t bb_rf_set_dc_i(uint16_t val) { uint16_t init; init = rf_spi_read(11); init &= 0xc07f; init |= (val << 7); if (rf_spi_write(11, init)) { return -1; } return 0; } static int16_t bb_rf_set_dc_q(uint16_t val) { uint16_t init; init = rf_spi_read(11); init &= 0xff80; init |= val; if (rf_spi_write(11, init)) { return -1; } return 0; } static uint8_t bb_rf_set_lna_pwr(uint8_t mode) { uint16_t val; val = rf_spi_read(1); val &= 0x7fff; val |= (mode << 15); if (rf_spi_write(1, val)) { return -1; } return 0; } static int16_t bb_rf_set_dc_close(void) { uint16_t init; init = rf_spi_read(1); init |= 0x18; if (rf_spi_write(1, init)) { return -1; } return 0; } static void bb_rf_clibr_dcr_v2(void) { uint32_t i, q; uint32_t min_i = 0, min_q = 0; uint32_t thrd; uint32_t gamma; uint32_t power = 0; uint32_t min = 0xffffffff; int16_t im = 0, re = 0; uint8_t step = 2; bb_rf_set_dc_close(); if (mac_rf_get_rx_dc_loopback_clibr_flag()) { uint8_t dc_i, dc_q; mac_rf_get_auto_rxdc_iq_value(&dc_i, &dc_q); bb_rf_set_dc_i(dc_i); bb_rf_set_dc_q(dc_q); return; } /* set flag on first time */ mac_rf_set_rx_dc_loopback_clibr_flag(1); thrd = bb_wphy_read_fld_reg(0xf01400, 0, 31); gamma = bb_wphy_read_fld_reg(0xf01334, 4, 7); bb_rf_set_lna_pwr(1); bb_wphy_write_fld_reg(0xf01334, 0, 0, 1); bb_wphy_write_fld_reg(0xf01334, 4, 7, 6); bb_wphy_write_fld_reg(0xf01400, 0, 31, 0xffffffff); bb_rf_debug_rx_immd(); for (i = 0; i < 128; i += step) { bb_rf_set_dc_i(i); for (q = 0; q < 128; q += step) { bb_rf_set_dc_q(q); iot_delay_us(30); im = ((int16_t)(bb_wphy_read_fld_reg(0xf0133c, 16, 27) << 4) >> 4); re = ((int16_t)(bb_wphy_read_fld_reg(0xf0133c, 0, 11) << 4) >> 4); power = (im * im) + (re * re); if (min > power) { min = power; min_i = i; min_q = q; } } } bb_rf_set_dc_i(min_i); bb_rf_set_dc_q(min_q); mac_rf_set_auto_rxdc_iq_value(min_i, min_q); bb_cpu_printf("rx dc loop cali i/q/power=[%d, %d, %d]\n", min_i, min_q, min); bb_wphy_stop_rx(); bb_wphy_write_fld_reg(0xf01400, 0, 31, thrd); bb_wphy_write_fld_reg(0xf01334, 4, 7, gamma); bb_wphy_write_fld_reg(0xf01334, 0, 0, 0); bb_rf_set_lna_pwr(0); return; } void bb_rf_clibr_dc(uint32_t option) { if (mac_rf_get_rx_dc_loopback_clibr_en() && RF_VER_2 == bb_rf_get_ver()) { bb_wphy_write_fld_reg(0xf01314, 1, 1, 0); bb_wphy_write_fld_reg(0xf01320, 8, 11, 6); bb_wphy_write_fld_reg(0xf01320, 28, 31, 6); bb_wphy_write_fld_reg(0xf01320, 20, 27, 43); bb_wphy_write_fld_reg(0xf01324, 16, 23, 31); bb_rf_clibr_dcr_v2(); bb_wphy_write_fld_reg(0xf01314, 1, 1, 1); } bb_rf_clibr_tx_dcoc(option, RF_CHANNEL_DEF_FREQ_HZ, 1, 2, NULL, NULL); } static int32_t bb_rf_set_tx_pwr_det(uint8_t en) { uint16_t init; init = rf_spi_read(24); if (en) { init |= 1 << 13; } else { init &= ~(1 << 13); } if (rf_spi_write(24, init)) return -1; return 0; } static int32_t bb_rf_set_tx_pwr_adc_det(uint8_t en) { uint16_t init; init = rf_spi_read(24); if (en) { init |= 1 << 12; } else { init &= ~(1 << 12); } if (rf_spi_write(24, init)) return -1; return 0; } static uint16_t bb_rf_get_adc_power(void) { uint16_t init; init = rf_spi_read(33); return init & 0xfff; } static uint8_t bb_rf_wphy_clibr_tx_dcoc(uint32_t option, uint32_t fchz, uint8_t interval, uint8_t step, uint16_t* ldovs, uint8_t* rf_att) { int16_t best_i = 0, best_q = 0; uint32_t min = 0xffffffff, power = 0; int16_t dc_i, dc_q; uint16_t temp, raw_data; if (ldovs != NULL) bb_rf_set_pa_ldovs(*ldovs); if (rf_att != NULL) rf_spi_write(24, 0xB80 | (*rf_att & 0x7f)); bb_rf_jesd_reset(); /* tx config */ bb_rf_tx_cfg(option, fchz); /* clear bit13, set JESD207 ENABLE mode to plus. * set bit14, means set ADC/DAC coder to completion. */ temp = rf_spi_read(30); raw_data = temp; temp &= ~(0x01 << 13); temp |= 0x01 << 14; rf_spi_write(30, temp); /* the actual value is the complement of the set value */ mac_rf_tx_dc(512, 512, 1); bb_rf_set_tx_pwr_det(1); bb_rf_set_tx_pwr_adc_det(1); iot_delay_us(5000); for (dc_i = -127; dc_i <= 127; dc_i += step) { for (dc_q = -127; dc_q <= 127; dc_q += step) { bb_rf_set_tx_dc(dc_i, dc_q); iot_delay_us(interval); power = bb_rf_get_adc_power(); if (min > power) { min = power; best_i = dc_i; best_q = dc_q; } } } bb_rf_set_tx_pwr_det(0); bb_rf_set_tx_pwr_adc_det(0); mac_rf_tx_dc(0, 0, 0); rf_spi_write(30, raw_data); bb_wphy_stop_tx(); bb_rf_set_tx_dc(best_i, best_q); mac_rf_set_tx_dc_cali(best_i, best_q); bb_cpu_printf("tx dc loop cali i/q/power=[%d, %d, %d]\n", best_i, best_q, min); return ERR_OK; } uint8_t bb_rf_clibr_tx_dcoc(uint32_t option, uint32_t fchz, uint8_t interval, uint8_t step, uint16_t* ldovs, uint8_t* rf_att) { if (!mac_rf_get_tx_dc_loopback_clibr_en() || RF_VER_2 != bb_rf_get_ver()) { return ERR_NOSUPP; } return bb_rf_wphy_clibr_tx_dcoc(option, fchz, interval, step, ldovs, rf_att); } void bb_rf_fix_gain(uint8_t en, uint8_t rf_gain, uint8_t if_gain) { uint16_t init; /* R0b8 R0b6 mode * 0 0 RF internal AGC. * 1 0 BB AGC_ GAIN signal configuration gain. * 1 1 R4 register configuration gain. */ init = rf_spi_read(0); if (en) { /* fix gain */ init |= (0x01 << 6) | (0x01 << 8); } else { rf_gain = 15; if_gain = 31; init &= ~(0x01 << 6); } rf_spi_write(0, init); init = rf_spi_read(4); init &= 0x3f; init |= (rf_gain & 0xf) << 12; init |= (if_gain & 0x3f) << 6; rf_spi_write(4, init); }