/*************************************************************************** * * 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 "plat_types.h" #include "hal_i2c.h" #include "hal_uart.h" #include "bt_drv.h" #ifdef RTOS #include "cmsis_os.h" #endif #include "cmsis.h" #include "hal_cmu.h" #include "hal_trace.h" #include "hal_timer.h" #include "tgt_hardware.h" #include "bt_drv_internal.h" #include "bt_drv_2300p_internal.h" #include "hal_chipid.h" #include "bt_drv_interface.h" #include "bt_drv_reg_op.h" #include "pmu.h" #include "iqcorrect.h" #include "hal_btdump.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 }