/*************************************************************************** * * Copyright 2015-2019 BES. * All rights reserved. All unpublished rights reserved. * * No part of this work may be used or reproduced in any form or by any * means, or stored in a database or retrieval system, without prior written * permission of BES. * * Use of this work is governed by a license granted by BES. * This work contains confidential and proprietary information of * BES. which is protected by copyright, trade secret, * trademark and other intellectual property rights. * ****************************************************************************/ #include "bt_drv.h" #include "hal_i2c.h" #include "hal_uart.h" #include "plat_types.h" #ifdef RTOS #include "cmsis_os.h" #endif #include "bt_drv_2300p_internal.h" #include "bt_drv_interface.h" #include "bt_drv_internal.h" #include "bt_drv_reg_op.h" #include "cmsis.h" #include "hal_btdump.h" #include "hal_chipid.h" #include "hal_cmu.h" #include "hal_timer.h" #include "hal_trace.h" #include "iqcorrect.h" #include "pmu.h" #include "tgt_hardware.h" #define AUTO_CAL 0 #ifndef BT_RF_MAX_XTAL_TUNE_PPB // Default 10 ppm/bit or 10000 ppb/bit #define BT_RF_MAX_XTAL_TUNE_PPB 10000 #endif #ifndef BT_RF_XTAL_TUNE_FACTOR // Default 0.2 ppm/bit or 200 ppb/bit #define BT_RF_XTAL_TUNE_FACTOR 200 #endif #define DEFAULT_XTAL_FCAP 0x8080 #define XTAL_FCAP_NORMAL_SHIFT 0 #define XTAL_FCAP_NORMAL_MASK (0xFF << XTAL_FCAP_NORMAL_SHIFT) #define XTAL_FCAP_NORMAL(n) BITFIELD_VAL(XTAL_FCAP_NORMAL, n) #define BT_XTAL_CMOM_DR (1 << 13) #define RF_REG_XTAL_FCAP 0xE9 #define RF_REG_XTAL_CMOM_DR 0xE8 /* ljh add for sync modify rf RF_REG_XTAL_FCAP value*/ #define SPI_TRIG_RX_NEG_TIMEOUT MS_TO_TICKS(3) #define SPI_TRIG_NEG_TIMEOUT SPI_TRIG_RX_NEG_TIMEOUT enum BIT_OFFSET_CMD_TYPE_T { BIT_OFFSET_CMD_STOP = 0, BIT_OFFSET_CMD_START, BIT_OFFSET_CMD_ACK, }; static uint16_t xtal_fcap = DEFAULT_XTAL_FCAP; static uint16_t init_xtal_fcap = DEFAULT_XTAL_FCAP; // rampup start 1--->2->3 rampup ok // rampdown start 3-->2-->1-->0 rampdown ok // 3a06=3b3f // for pa@1.8v struct bt_drv_tx_table_t { uint16_t tbl[16][3]; }; struct RF_SYS_INIT_ITEM { uint16_t reg; uint16_t set; uint16_t mask; uint16_t delay; }; static const struct RF_SYS_INIT_ITEM rf_sys_init_tbl[] = { {0xb5, 0x8000, 0x8000, 0}, {0xc2, 0x7188, 0x7fff, 0}, #ifdef LBRT {0xc4, 0x0043, 0x0043, 0}, // enable lbrt adc clk[6] #else {0xc4, 0x0003, 0x0003, 0}, #endif }; // zhangzhd agc config use default 1216 #define REG_EB_VAL 0x000c #define REG_181_VAL (0x00bf) #define REG_EC_VAL 0x000d #define REG_182_VAL 0x00bf #define REG_ED_VAL 0x000e #define REG_183_VAL 0x00bf #define REG_EE_VAL 0x000b #define REG_184_VAL 0x00bf #define REG_EF_VAL 0x0007 #define REG_185_VAL 0x00bf #define REG_F0_VAL 0x0007 #define REG_186_VAL 0x00af #define REG_F1_VAL 0x0007 #define REG_187_VAL 0x009f #define REG_F2_VAL 0x0007 #define REG_188_VAL 0x008f // zhangzhd agc config end const uint16_t rf_init_tbl_1[][3] = { {0x88, 0x8640, 0}, {0x8b, 0x8a4a, 0}, // set rx flt cap,filter start up #if defined(__FANG_HW_AGC_CFG_ADC__) {0xd1, 0x8401, 0}, // set ra adc gain -3db {0x8e, 0x0D28, 0}, // adc noise reduction #else {0xd1, 0x8403, 0}, // set gain {0x8e, 0x0128, 0}, // adc noise reduction #endif {0x90, 0x8e1f, 0}, // enlarge txflt BW {0x91, 0x05c0, 0}, // by walker 20180427 {0x92, 0x668e, 0}, // update by luobin 2019/3/22 {0x97, 0x2523, 0}, // update by luobin 2019.0523 {0x98, 0x1324, 0}, // update by walker 2019.01.14, modify for yield {0x9a, 0x4470, 0}, // div2 rc {0x9b, 0xfd52, 0}, // update by walker 2018.10.24 {0x9c, 0x180f, 0}, /////////luobin {0xa3, 0x0789, 0}, {0xb0, 0x0000, 0}, {0xb1, 0x0000, 0}, {0xb3, 0x31f3, 0}, // {0xb4, 0x883c, 0}, {0xb6, 0x3156, 0}, {0xb7, 0x183f, 0}, // update by walker 2018.07.30 {0xb9, 0x8000, 0}, // cap3g6 off {0xba, 0x104e, 0}, #if defined(__FANG_LNA_CFG__) {0xac, 0x080e, 0}, // pre-charge set to 5us {0x85, 0x7f00, 0}, // NFMI RXADC LDO rise up // {0xc3,0x0068,0},//add by xrz increase pll cal time 2018/10/20 {0xc3, 0x0044, 0}, #else {0xc3, 0x0050, 0}, #endif {0xc5, 0x4b50, 0}, // vco ictrl dr {0xc9, 0x3a08, 0}, // vco ictrl {0xd3, 0xc1c1, 0}, {0xd4, 0x000f, 0}, {0xd5, 0x4000, 0}, {0xd6, 0x7980, 0}, {0xe8, 0xe000, 0}, {0xf3, 0x0c41, 0}, // by fang {0x1a6, 0x0600, 0}, {0x1ae, 0x6a00, 0}, // fastlock en {0x1d4, 0x0000, 0}, {0x1d7, 0xc4ff, 0}, // update by walker 2018.10.10 {0x1de, 0x2000, 0}, {0x1df, 0x2087, 0}, {0x1f4, 0x2241, 0}, // by walker 20180427 {0x1fa, 0x03df, 0}, // rst needed {0x1fa, 0x83df, 0}, {0xeb, REG_EB_VAL, 0}, // gain_idx:0 {0x181, REG_181_VAL, 0}, {0xec, REG_EC_VAL, 0}, // gain_idx:1 {0x182, REG_182_VAL, 0}, {0xed, REG_ED_VAL, 0}, // gain_idx:2 {0x183, REG_183_VAL, 0}, {0xee, REG_EE_VAL, 0}, // gain_idx:3 {0x184, REG_184_VAL, 0}, {0xef, REG_EF_VAL, 0}, // gain_idx:4 {0x185, REG_185_VAL, 0}, {0xf0, REG_F0_VAL, 0}, // gain_idx:5 {0x186, REG_186_VAL, 0}, {0xf1, REG_F1_VAL, 0}, // gain_idx:6 {0x187, REG_187_VAL, 0}, {0xf2, REG_F2_VAL, 0}, // gain_idx:7 {0x188, REG_188_VAL, 0}, {0x1d6, 0x7e58, 0}, // set lbrt rxflt dccal_ready=1 {0x1c8, 0xdfc0, 0}, // en rfpll bias in lbrt mode {0x1c9, 0xa0cf, 0}, // en log bias {0x82, 0x0caa, 0}, // select rfpll and cplx_dir=0 and en rxflt test {0xf4, 0x2181, 0}, // set flt_cap to match flt_gain {0x86, 0xdc99, 0}, // set nfmi tmix {0xdf, 0x2006, 0}, // set nfmi tmix vcm #ifdef __HW_AGC__ {0x1c7, 0x007d, 0}, // open lbrt adc and vcm bias current #endif {0x18c, 0x0000, 0}, // max tx gain lbrt // air @ LBRT 31.5m {0x1d8, 0x9162, 0}, // lbrt tx freqword {0x1d9, 0x9162, 0}, // lbrt tx freqword {0x1da, 0x9162, 0}, // lbrt tx freqword {0x1db, 0x9162, 0}, // lbrt tx freqword {0x1dc, 0x0000, 0}, // txlccap {0x1dd, 0x0000, 0}, // txlccap {0x1ed, 0x0000, 0}, // rxlccap {0x1ee, 0x0000, 0}, // rxlccap {0x1e9, 0x0a0a, 0}, // set rfpll divn in lbrt tx mode {0x1ea, 0x0a0a, 0}, {0x1eb, 0x0a0a, 0}, // set rfpll divn in lbrt rx mode {0x1ec, 0x0a0a, 0}, {0x1ef, 0x8a76, 0}, // lbrt rx freqword {0x1f0, 0x8a76, 0}, // lbrt rx freqword {0x1f1, 0x8a76, 0}, // lbrt rx freqword {0x1f2, 0x8a76, 0}, // lbrt rx freqword {0x87, 0x9f00, 0}, //{0x87,0x9f40,0} {0x81, 0x9207, 0}, {0xce, 0xfc08, 0}, {0x8A, 0x4EA4, 0}, // use rfpll for nfmi adclk //[below for ibrt] {0x8c, 0x9100, 0}, {0xab, 0x1c0c, 0}, // 2019.05.08 by luofei {0xa5, 0x0404, 0}, // rfpll pu time {0xa6, 0x2D20, 0}, // 2019.05.23 by luobin {0xa8, 0x2D22, 0}, // 2019.05.23 by luobin {0x1b7, 0x2c00, 0}, // 2019.05.08 by luofei {0x1ad, 0x9000, 0}, // 2M tx filter baseband {0xdc, 0x8820, 0}, // fa pa pwrup time {0x8f, 0x71b8, 0}, // tx dac by luobin }; #ifdef __HW_AGC__ const uint16_t rf_init_tbl_1_hw_agc[][3] = // hw agc table { {0xad, 0xa04a, 1}, // hwagc en=1 {0xCD, 0x0040, 0}, // default 0x0000 {0xcf, 0x7f32, 0}, // lna gain dr=0 //default 0x0000 {0xd0, 0xe91f, 0}, // i2v flt gain dr=0 //default 0x0000 {0xeb, 0x0007, 0}, // gain_idx:0 {0xec, 0x0007, 0}, // gain_idx:1 {0xed, 0x0007, 0}, // gain_idx:2 {0xee, 0x000d, 0}, // gain_idx:3 {0xef, 0x000d, 0}, // gain_idx:4 {0xf0, 0x000d, 0}, // gain_idx:5 {0xf1, 0x000d, 0}, // gain_idx:6 {0xf2, 0x000c, 0}, // gain_idx:7 }; #endif //__HW_AGC__ const uint16_t rf_init_tbl_1_sw_agc[][3] = // sw agc table { {0xad, 0xa00a, 1}, // hwagc en=0 {0xCD, 0x0000, 0}, // default 0x0000 {0xcf, 0x0000, 0}, // lna gain dr=0 //default 0x0000 {0xd0, 0x0000, 0}, // i2v flt gain dr=0 //default 0x0000 {0xeb, REG_EB_VAL, 0}, // gain_idx:0 {0xec, REG_EC_VAL, 0}, // gain_idx:1 {0xed, REG_ED_VAL, 0}, // gain_idx:2 {0xee, REG_EE_VAL, 0}, // gain_idx:3 {0xef, REG_EF_VAL, 0}, // gain_idx:4 {0xf0, REG_F0_VAL, 0}, // gain_idx:5 {0xf1, REG_F1_VAL, 0}, // gain_idx:6 {0xf2, REG_F2_VAL, 0}, // gain_idx:7 }; uint32_t btdrv_rf_get_max_xtal_tune_ppb(void) { return BT_RF_MAX_XTAL_TUNE_PPB; } uint32_t btdrv_rf_get_xtal_tune_factor(void) { return BT_RF_XTAL_TUNE_FACTOR; } void btdrv_rf_init_xtal_fcap(uint32_t fcap) { xtal_fcap = SET_BITFIELD(xtal_fcap, XTAL_FCAP_NORMAL, fcap); btdrv_write_rf_reg(RF_REG_XTAL_FCAP, xtal_fcap); init_xtal_fcap = xtal_fcap; } uint32_t btdrv_rf_get_init_xtal_fcap(void) { return GET_BITFIELD(init_xtal_fcap, XTAL_FCAP_NORMAL); } uint32_t btdrv_rf_get_xtal_fcap(void) { return GET_BITFIELD(xtal_fcap, XTAL_FCAP_NORMAL); } void btdrv_rf_set_xtal_fcap(uint32_t fcap, uint8_t is_direct) { xtal_fcap = SET_BITFIELD(xtal_fcap, XTAL_FCAP_NORMAL, fcap); btdrv_write_rf_reg(RF_REG_XTAL_FCAP, xtal_fcap); } int btdrv_rf_xtal_fcap_busy(uint8_t is_direct) { return 0; } void btdrv_rf_bit_offset_track_enable(bool enable) { return; } uint32_t btdrv_rf_bit_offset_get(void) { return 0; } uint16_t btdrv_rf_bitoffset_get(uint8_t conidx) { uint16_t bitoffset; bitoffset = BTDIGITAL_REG(EM_BT_BITOFF_ADDR + conidx * BT_EM_SIZE) & 0x3ff; return bitoffset; } void btdrv_rf_log_delay_cal(void) { unsigned short read_value; unsigned short write_value; BT_DRV_TRACE(0, "btdrv_rf_log_delay_cal\n"); btdrv_write_rf_reg(0xa7, 0x0028); btdrv_write_rf_reg(0xd4, 0x0000); btdrv_write_rf_reg(0xd5, 0x4002); // *(volatile uint32_t*)(0xd02201e4) = 0x000a00b0; *(volatile uint32_t *)(0xd0340020) = 0x030e01c1; BT_DRV_TRACE(1, "0xd0340020 =%x\n", *(volatile uint32_t *)(0xd0340020)); btdrv_delay(1); btdrv_write_rf_reg(0xd2, 0x5003); btdrv_delay(1); btdrv_read_rf_reg(0x1e2, &read_value); BT_DRV_TRACE(1, "0x1e2 read_value:%x\n", read_value); if (read_value == 0xff80) { btdrv_write_rf_reg(0xd3, 0xffff); } else { write_value = ((read_value >> 7) & 0x0001) | ((read_value & 0x007f) << 1) | ((read_value & 0x8000) >> 7) | ((read_value & 0x7f00) << 1); BT_DRV_TRACE(1, "d3 write_value:%x\n", write_value); btdrv_write_rf_reg(0xd3, write_value); } btdrv_delay(1); // *(volatile uint32_t*)(0xd02201e4) = 0x00000000; *(volatile uint32_t *)(0xd0340020) = 0x010e01c0; BT_DRV_TRACE(1, "0xd0340020 =%x\n", *(volatile uint32_t *)(0xd0340020)); btdrv_write_rf_reg(0xd4, 0x000f); btdrv_write_rf_reg(0xd2, 0x1003); btdrv_write_rf_reg(0xd5, 0x4000); } void btdrv_rf_rx_gain_adjust_req(uint32_t user, bool lowgain) { return; } // rf Image calib void btdtv_rf_image_calib(void) { uint16_t read_val; // read calibrated val from efuse 0x05 register pmu_get_efuse(PMU_EFUSE_PAGE_SW_CFG, &read_val); // check if bit 11 has been set uint8_t calb_done_flag = ((read_val & 0x800) >> 11); if (calb_done_flag) { BT_DRV_TRACE(1, "EFUSE REG[5]=%x", read_val); } else { BT_DRV_TRACE(0, "EFUSE REG[5] rf image has not been calibrated!"); return; } //[bit 12] calib flag uint8_t calib_val = ((read_val & 0x1000) >> 12); btdrv_read_rf_reg(0x9b, &read_val); read_val &= 0xfcff; if (calib_val == 0) { read_val |= 1 << 8; } else if (calib_val == 1) { read_val |= 1 << 9; } BT_DRV_TRACE(1, "write rf image calib val=%x in REG[0x9b]", read_val); btdrv_write_rf_reg(0x9b, read_val); } #ifdef TX_IQ_CAL const uint16_t tx_cal_rfreg_set[][3] = { // iq cal path {0x1c4, 0xffcf, 0}, {0x1c5, 0xf8ff, 0}, {0x1c6, 0x007f, 0}, {0x1c7, 0x03ff, 0}, {0x1d6, 0x7a58, 0}, {0x1d7, 0xc0f7, 0}, {0x1f4, 0x2481, 0}, {0x94, 0x11c3, 0}, {0x95, 0xe5c0, 0}, {0xd1, 0x846b, 0}, {0xae, 0x0403, 0}, {0x86, 0xccd9, 0}, {0xf3, 0x0c75, 0}, {0xf4, 0x0309, 0}, {0xcf, 0x8090, 0}, {0x82, 0x2cab, 0}, // nfmi adc {0xc4, 0x00c3, 0}, {0xae, 0x07ff, 0}, {0x85, 0x470f, 0}, {0x82, 0x4aab, 0}, {0x82, 0xecab, 0}, {0x87, 0xa211, 0}, {0x87, 0xe211, 0}, {0x84, 0xfff8, 0}, }; const uint16_t tx_cal_rfreg_store[][1] = { {0x1c4}, {0x1c5}, {0x1c6}, {0x1c7}, {0x1d6}, {0x1d7}, {0x1f4}, {0x94}, {0x95}, {0xd1}, {0xae}, {0x86}, {0xf3}, {0xf4}, {0xcf}, {0x82}, {0xc4}, {0x85}, {0x87}, {0x84}, }; int bt_iqimb_ini(); int bt_iqimb_test_ex(int mismatch_type); void btdrv_tx_iq_cal(void) { uint8_t i; const uint16_t(*tx_cal_rfreg_set_p)[3]; const uint16_t(*tx_cal_rfreg_store_p)[1]; uint32_t reg_set_tbl_size; uint32_t reg_store_tbl_size; uint16_t value; uint32_t tx_cal_digreg_store[5]; tx_cal_rfreg_store_p = &tx_cal_rfreg_store[0]; reg_store_tbl_size = sizeof(tx_cal_rfreg_store) / sizeof(tx_cal_rfreg_store[0]); uint16_t tx_cal_rfreg_store[reg_store_tbl_size]; BT_DRV_TRACE(0, "reg_store:\n"); for (i = 0; i < reg_store_tbl_size; i++) { btdrv_read_rf_reg(tx_cal_rfreg_store_p[i][0], &value); tx_cal_rfreg_store[i] = value; BT_DRV_TRACE(2, "reg=%x,v=%x", tx_cal_rfreg_store_p[i][0], value); } tx_cal_digreg_store[0] = *(volatile uint32_t *)(0xd0330038); tx_cal_digreg_store[1] = *(volatile uint32_t *)(0xd0350364); tx_cal_digreg_store[2] = *(volatile uint32_t *)(0xd0350360); tx_cal_digreg_store[3] = *(volatile uint32_t *)(0xd035037c); tx_cal_digreg_store[4] = *(volatile uint32_t *)(0xd02201e4); BT_DRV_TRACE(1, "0xd0330038:%x\n", tx_cal_digreg_store[0]); BT_DRV_TRACE(1, "0xd0350364:%x\n", tx_cal_digreg_store[1]); BT_DRV_TRACE(1, "0xd0350360:%x\n", tx_cal_digreg_store[2]); BT_DRV_TRACE(1, "0xd035037c:%x\n", tx_cal_digreg_store[3]); BT_DRV_TRACE(1, "0xd02201e4:%x\n", tx_cal_digreg_store[4]); tx_cal_rfreg_set_p = &tx_cal_rfreg_set[0]; reg_set_tbl_size = sizeof(tx_cal_rfreg_set) / sizeof(tx_cal_rfreg_set[0]); BT_DRV_TRACE(0, "reg_set:\n"); for (i = 0; i < reg_set_tbl_size; i++) { btdrv_write_rf_reg(tx_cal_rfreg_set_p[i][0], tx_cal_rfreg_set_p[i][1]); if (tx_cal_rfreg_set_p[i][2] != 0) btdrv_delay(tx_cal_rfreg_set_p[i][2]); // delay btdrv_read_rf_reg(tx_cal_rfreg_set_p[i][0], &value); BT_DRV_TRACE(2, "reg=%x,v=%x", tx_cal_rfreg_set_p[i][0], value); } // iq cal cordic *(volatile uint32_t *)(0xd0330038) = 0x0020010d; btdrv_delay(1); *(volatile uint32_t *)(0xd0350364) = 0x002eb948; *(volatile uint32_t *)(0xd0350360) = 0x007fc240; *(volatile uint32_t *)(0xd035037c) = 0x00020405; *(volatile uint32_t *)(0xd02201e4) = 0x000a0000; BT_DRV_TRACE(1, "0xd0330038:%x\n", *(volatile uint32_t *)(0xd0330038)); BT_DRV_TRACE(1, "0xd0350364:%x\n", *(volatile uint32_t *)(0xd0350364)); BT_DRV_TRACE(1, "0xd0350360:%x\n", *(volatile uint32_t *)(0xd0350360)); BT_DRV_TRACE(1, "0xd035037c:%x\n", *(volatile uint32_t *)(0xd035037c)); BT_DRV_TRACE(1, "0xd02201e4:%x\n", *(volatile uint32_t *)(0xd02201e4)); bt_iqimb_ini(); bt_iqimb_test_ex(1); BT_DRV_TRACE(0, "reg_reset:\n"); for (i = 0; i < reg_store_tbl_size; i++) { btdrv_write_rf_reg(tx_cal_rfreg_store_p[i][0], tx_cal_rfreg_store[i]); btdrv_read_rf_reg(tx_cal_rfreg_store_p[i][0], &value); BT_DRV_TRACE(2, "reg=%x,v=%x", tx_cal_rfreg_store_p[i][0], value); } *(volatile uint32_t *)(0xd0330038) = tx_cal_digreg_store[0]; *(volatile uint32_t *)(0xd0350364) = tx_cal_digreg_store[1]; *(volatile uint32_t *)(0xd0350360) = tx_cal_digreg_store[2]; *(volatile uint32_t *)(0xd035037c) = tx_cal_digreg_store[3]; *(volatile uint32_t *)(0xd02201e4) = tx_cal_digreg_store[4]; BT_DRV_TRACE(1, "0xd0330038:%x\n", *(volatile uint32_t *)(0xd0330038)); BT_DRV_TRACE(1, "0xd0350364:%x\n", *(volatile uint32_t *)(0xd0350364)); BT_DRV_TRACE(1, "0xd0350360:%x\n", *(volatile uint32_t *)(0xd0350360)); BT_DRV_TRACE(1, "0xd035037c:%x\n", *(volatile uint32_t *)(0xd035037c)); BT_DRV_TRACE(1, "0xd02201e4:%x\n", *(volatile uint32_t *)(0xd02201e4)); } #endif uint8_t btdrv_rf_init(void) { uint16_t value; const uint16_t(*rf_init_tbl_p)[3]; uint32_t tbl_size; // uint8_t ret; uint8_t i; for (i = 0; i < ARRAY_SIZE(rf_sys_init_tbl); i++) { btdrv_read_rf_reg(rf_sys_init_tbl[i].reg, &value); value = (value & ~rf_sys_init_tbl[i].mask) | (rf_sys_init_tbl[i].set & rf_sys_init_tbl[i].mask); if (rf_sys_init_tbl[i].delay) { btdrv_delay(rf_sys_init_tbl[i].delay); } btdrv_write_rf_reg(rf_sys_init_tbl[i].reg, value); } rf_init_tbl_p = &rf_init_tbl_1[0]; tbl_size = sizeof(rf_init_tbl_1) / sizeof(rf_init_tbl_1[0]); for (i = 0; i < tbl_size; i++) { btdrv_write_rf_reg(rf_init_tbl_p[i][0], rf_init_tbl_p[i][1]); if (rf_init_tbl_p[i][2] != 0) btdrv_delay(rf_init_tbl_p[i][2]); // delay } bt_drv_tx_pwr_init(); #ifdef __HW_AGC__ for (i = 0; i < sizeof(rf_init_tbl_1_hw_agc) / sizeof(rf_init_tbl_1_hw_agc[0]); i++) { btdrv_write_rf_reg(rf_init_tbl_1_hw_agc[i][0], rf_init_tbl_1_hw_agc[i][1]); if (rf_init_tbl_1_hw_agc[i][2] != 0) btdrv_delay(rf_init_tbl_1_hw_agc[i][2]); // delay } #endif // need before rf log delay cal btdtv_rf_image_calib(); btdrv_rf_log_delay_cal(); btdrv_spi_trig_init(); #ifdef TX_IQ_CAL hal_btdump_clk_enable(); bt_iq_calibration_setup(); hal_btdump_clk_disable(); #endif return 1; } void bt_drv_rf_reset(void) { btdrv_write_rf_reg(0x80, 0xcafe); btdrv_write_rf_reg(0x80, 0x5fee); } static void bt_drv_switch_hw_sw_agc(enum BT_AGC_MODE_T agc_mode) { static enum BT_AGC_MODE_T agc_mode_bak = BT_AGC_MODE_NONE; uint16_t i = 0; if (agc_mode_bak != agc_mode) { agc_mode_bak = agc_mode; BT_DRV_TRACE(1, "BT_DRV:use AGC mode=%d[1:HW,0:SW]", agc_mode); uint32_t lock = int_lock_global(); if (agc_mode == BT_AGC_MODE_HW) { #ifdef __HW_AGC__ bt_drv_reg_op_hw_sw_agc_select(BT_AGC_MODE_HW); for (i = 0; i < sizeof(rf_init_tbl_1_hw_agc) / sizeof(rf_init_tbl_1_hw_agc[0]); i++) { btdrv_write_rf_reg(rf_init_tbl_1_hw_agc[i][0], rf_init_tbl_1_hw_agc[i][1]); if (rf_init_tbl_1_hw_agc[i][2] != 0) btdrv_delay(rf_init_tbl_1_hw_agc[i][2]); // delay } #endif } else { bt_drv_reg_op_hw_sw_agc_select(BT_AGC_MODE_SW); for (i = 0; i < sizeof(rf_init_tbl_1_sw_agc) / sizeof(rf_init_tbl_1_sw_agc[0]); i++) { btdrv_write_rf_reg(rf_init_tbl_1_sw_agc[i][0], rf_init_tbl_1_sw_agc[i][1]); if (rf_init_tbl_1_sw_agc[i][2] != 0) btdrv_delay(rf_init_tbl_1_sw_agc[i][2]); // delay } } int_unlock_global(lock); } } void bt_drv_select_agc_mode(enum BT_WORK_MODE_T mode) { #ifdef __HYBIRD_AGC__ enum BT_AGC_MODE_T agc_mode = BT_AGC_MODE_SW; switch (mode) { case BT_IDLE_MODE: agc_mode = BT_AGC_MODE_HW; break; case BT_A2DP_WORK_MODE: case BT_HFP_WORK_MODE: agc_mode = BT_AGC_MODE_SW; break; default: BT_DRV_TRACE(1, "BT_DRV:set error mork mode=%d", mode); break; } bt_drv_switch_hw_sw_agc(agc_mode); #endif } static uint16_t efuse; static int16_t rf18b_6_4, rf18b_10_8, rf18b_14_12; #define TX_POWET_CALIB_FACTOR 0x2 static int check_btpower_efuse_invalid(void) { pmu_get_efuse(PMU_EFUSE_PAGE_BT_POWER, &efuse); BT_DRV_TRACE(1, "efuse_8=0x%x", efuse); rf18b_6_4 = (efuse & 0x70) >> 4; // address_8 [6:4] rf18b_10_8 = (efuse & 0x700) >> 8; // address_8 [10:8] rf18b_14_12 = (efuse & 0x7000) >> 12; // address_8 [14:12] if ((0 == efuse) || (rf18b_6_4 > 5) || (rf18b_10_8 > 5) || (rf18b_14_12 > 5)) { BT_DRV_TRACE(0, "invalid efuse value."); return 0; } return 1; } void bt_drv_tx_pwr_init(void) { // ble txpower need modify ble tx idx @ bt_drv_config.c // modify bit4~7 to change ble tx gain btdrv_write_rf_reg(0x189, 0x0071); // min tx gain 2019.02.26 btdrv_write_rf_reg(0x18a, 0x0071); // mid tx gain 2019.02.26 if (0 == check_btpower_efuse_invalid()) btdrv_write_rf_reg(0x18b, 0x0071); // max tx gain 2019.02.26 } void bt_drv_tx_pwr_init_for_testmode(void) { // ble txpower need modify ble tx idx @ bt_drv_config.c // modify bit4~7 to change ble tx gain btdrv_write_rf_reg(0x189, 0x007a); // min tx gain 2019.02.26 btdrv_write_rf_reg(0x18a, 0x0076); // mid tx gain 2019.02.26 if (0 == check_btpower_efuse_invalid()) btdrv_write_rf_reg(0x18b, 0x0071); // max tx gain 2019.02.26 } void btdrv_txpower_calib(void) { uint16_t rf92_11_8; uint16_t tmp_val; int16_t average_value; // may be negative, so use signed numbers uint16_t read_value; uint16_t bit7_symbol, bit11_symbol, bit15_symbol; if (0 == check_btpower_efuse_invalid()) return; bit7_symbol = (efuse & 0x80) >> 4; bit11_symbol = (efuse & 0x800) >> 8; bit15_symbol = (efuse & 0x8000) >> 12; rf92_11_8 = efuse & 0xf; // address_8 [3:0] BT_DRV_TRACE(3, "bit7_symbol=%d, bit11_symbol=%d, bit15_symbol=%d", bit7_symbol, bit11_symbol, bit15_symbol); BT_DRV_TRACE(4, "rf92_11_8=%x, rf18b_6_4=%x, rf18b_10_8=%x, rf18b_14_12=%x", rf92_11_8, rf18b_6_4, rf18b_10_8, rf18b_14_12); rf18b_6_4 = (bit7_symbol == 0) ? rf18b_6_4 : -rf18b_6_4; rf18b_10_8 = (bit11_symbol == 0) ? rf18b_10_8 : -rf18b_10_8; rf18b_14_12 = (bit15_symbol == 0) ? rf18b_14_12 : -rf18b_14_12; // set 0x92[11:8] begin btdrv_read_rf_reg(0x92, &tmp_val); BT_DRV_TRACE(1, "read reg 0x92 val=%x", tmp_val); tmp_val &= 0xf0ff; // clear [11:8] tmp_val |= ((rf92_11_8 & 0xffff) << 8); // set efuse[3:0] to rf_92 [11:8] BT_DRV_TRACE(2, "%d write reg 0x92 val=%x", __LINE__, tmp_val); btdrv_write_rf_reg(0x92, tmp_val); // set 0x92[11:8] end // set 0x18b[3:0] begin btdrv_read_rf_reg(0x18b, &read_value); // 0x18b average_value = (int16_t)(((float)(rf18b_6_4 + rf18b_10_8 + rf18b_14_12) / 6.f) + 0.5f); BT_DRV_TRACE(2, "calc average_value=0x%x, dec:%d", average_value, average_value); if (0 < average_value) { btdrv_read_rf_reg(0x92, &tmp_val); tmp_val &= 0x0fff; // clear [15:12] if (1 == average_value) { tmp_val |= ((0x8 & 0xffff) << 12); } else // average_value [2,~] { tmp_val |= ((0xA & 0xffff) << 12); } BT_DRV_TRACE(2, "%d write reg 0x92 val=%x", __LINE__, tmp_val); btdrv_write_rf_reg(0x92, tmp_val); } tmp_val = TX_POWET_CALIB_FACTOR - average_value; if (average_value > TX_POWET_CALIB_FACTOR) tmp_val = 0; BT_DRV_TRACE(1, "finally tmp_val=%x", tmp_val); read_value &= 0xff00; // clear [3:0] & [7:4] read_value |= (tmp_val | (0x7 << 4)); // get 0x18b [3:0] & [7:4] btdrv_write_rf_reg(0x18b, read_value); BT_DRV_TRACE(1, "write reg 0x18b val=0x%x", read_value); // set 0x18b[3:0] end }