/****************************************************************************** * * Copyright (C) 2019-2021 Aicsemi Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ #define LOG_TAG "bt_hwcfg_uart" #define AICBT_RELEASE_NAME "20220429_BT_ANDROID_1x.0" #include #include #include #include #include #include #include #include #include #include #include #include "bt_hci_bdroid.h" #include "bt_vendor_aic.h" #include "userial.h" #include "userial_vendor.h" #include "upio.h" #include #include #include #include #include "bt_vendor_lib.h" #include "hardware.h" /****************************************************************************** ** Constants & Macros ******************************************************************************/ #define HCI_CMD_MAX_LEN 258 #define HCI_VSC_WRITE_SLEEP_MODE 0xFC27 #define HCI_VSC_WR_AON_PARAM_CMD 0xFC4D #define HCI_VSC_SET_LP_LEVEL_CMD 0xFC50 #define HCI_VSC_SET_PWR_CTRL_SLAVE_CMD 0xFC51 #define HCI_VSC_SET_CPU_POWER_OFF_CMD 0xFC52 #define HCI_VSC_SET_SLEEP_EN_CMD 0xFC47 #define HCI_VSC_WR_AON_PARAM_SIZE 104 #define HCI_VSC_SET_LP_LEVEL_SIZE 1 #define HCI_VSC_SET_PWR_CTRL_SLAVE_SIZE 1 #define HCI_VSC_SET_CPU_POWER_OFF_SIZE 1 #define HCI_VSC_SET_SLEEP_EN_SIZE 8 #define HCI_VSC_CLR_B4_RESET_SIZE 3 #define HCI_EVT_CMD_CMPL_STATUS_RET_BYTE 5 #define HCI_EVT_CMD_CMPL_LOCAL_BDADDR_ARRAY 6 #define HCI_EVT_CMD_CMPL_OPCODE 3 #define LPM_CMD_PARAM_SIZE 12 #define AON_BT_PWR_DLY1 (1 + 5 + 1) #define AON_BT_PWR_DLY2 (10 + 48 + 5 + 1) #define AON_BT_PWR_DLY3 (10 + 48 + 8 + 5 + 1) #define AON_BT_PWR_DLY_AON (10 + 48 + 8 + 5) /****************************************************************************** ** Local type definitions ******************************************************************************/ enum { BT_LP_LEVEL_ACTIVE = 0x00,//BT CORE active, CPUSYS active, VCORE active BT_LP_LEVEL_CLOCK_GATE1 = 0x01,//BT CORE clock gate, CPUSYS active, VCORE active BT_LP_LEVEL_CLOCK_GATE2 = 0x02,//BT CORE clock gate, CPUSYS clock gate, VCORE active BT_LP_LEVEL_CLOCK_GATE3 = 0x03,//BT CORE clock gate, CPUSYS clock gate, VCORE clock gate BT_LP_LEVEL_POWER_OFF1 = 0x04,//BT CORE power off, CPUSYS active, VCORE active BT_LP_LEVEL_POWER_OFF2 = 0x05,//BT CORE power off, CPUSYS clock gate, VCORE active BT_LP_LEVEL_POWER_OFF3 = 0x06,//BT CORE power off, CPUSYS power off, VCORE active BT_LP_LEVEL_HIBERNATE = 0x07,//BT CORE power off, CPUSYS power off, VCORE active BT_LP_LEVEL_MAX = 0x08,// }; enum { AICBT_SLEEP_STATE_IDLE = 0, AICBT_SLEEP_STATE_CONFIG_ING, AICBT_SLEEP_STATE_CONFIG_DONE, }; struct aicbt_hci_set_sleep_en_cmd { ///sleep enable uint8_t sleep_en; ///external warkeup enable uint8_t ext_wakeup_en; ///reserved uint8_t rsvd[6]; }; typedef struct { /// Em save start address uint32_t em_save_start_addr; /// Em save end address uint32_t em_save_end_addr; /// Minimum time that allow power off(in hs) int32_t aon_min_power_off_duration; /// Maximum aon params uint16_t aon_max_nb_params; /// RF config const time on cpus side (in hus) int16_t aon_rf_config_time_cpus; /// RF config const time on aon side (in hus) int16_t aon_rf_config_time_aon; /// Maximun active acl link supported by aon uint16_t aon_max_nb_active_acl; /// Maximun ble activity supported by aon uint16_t aon_ble_activity_max; /// Maximum bt rxdesc field supported by aon uint16_t aon_max_bt_rxdesc_field; /// Maximum bt rxdesc field supported by aon uint16_t aon_max_ble_rxdesc_field; /// Maximum regs supported by aon uint16_t aon_max_nb_regs; /// Maximum length of ke_env supported by aon uint16_t aon_max_ke_env_len; /// Maximum elements of sch_arb_env supported by aon uint16_t aon_max_nb_sc_arb_elt; /// Maximum elements of sch_plan_env supported by aon uint16_t aon_max_nb_sch_plan_elt; /// Maximum elements of sch_alarm_elt_env supported by aon uint16_t aon_max_nb_sch_alarm_elt; /// Minimum advertising interval in slots(625 us) supported by aon uint32_t aon_min_ble_adv_intv; /// Minimum connection inverval in 2-sltos(1.25ms) supported by aon uint32_t aon_min_ble_con_intv; /// Extra sleep duration for cpus(in hs), may be negative int32_t aon_extra_sleep_duration_cpus; /// Extra sleep duration for aon(in hs), may be negative int32_t aon_extra_sleep_duration_aon; /// Minimum time that allow host to power off(in us) int32_t aon_min_power_off_duration_cpup; /// aon debug level for cpus uint32_t aon_debug_level; /// aon debug level for aon uint32_t aon_debug_level_aon; /// Power on delay of bt core on when cpus_sys alive on cpus side(in lp cycles) uint16_t aon_bt_pwr_on_dly1; /// Power on delay of bt core on when cpus_sys clk gate on cpus side(in lp cycles) uint16_t aon_bt_pwr_on_dly2; /// Power on delay of bt core on when cpus_sys power off on cpus side(in lp cycles) uint16_t aon_bt_pwr_on_dly3; /// Power on delay of bt core on on aon side(in lp cycles) uint16_t aon_bt_pwr_on_dly_aon; /// Time to cancle sch arbiter elements in advance when switching to cpus(in hus) uint16_t aon_sch_arb_cancel_in_advance_time; /// Duration of sleep and wake-up algorithm (depends on CPU speed) expressed in half us on cpus side /// should also contain deep_sleep_on rising edge to fimecnt halt (max 4 lp cycles) and finecnt resume to dm_slp_irq(0.5 lp cycles) uint16_t aon_sleep_algo_dur_cpus; /// Duration of sleep and wake-up algorithm (depends on CPU speed) expressed in half us on aon side /// should also contain deep_sleep_on rising edge to fimecnt halt (max 4 lp cycles) and finecnt resume to dm_slp_irq(0.5 lp cycles) uint16_t aon_sleep_algo_dur_aon; /// Threshold that treat fractional part of restore time (in hus) as 1 hs on cpus side uint16_t aon_restore_time_ceil_cpus; /// Threshold that treat fractional part of restore time (in hus) as 1 hs on aon side uint16_t aon_restore_time_ceil_aon; /// Minmum time that allow deep sleep on cpus side (in hs) uint16_t aon_min_sleep_duration_cpus; /// Minmum time that allow deep sleep on aon side (in hs) uint16_t aon_min_sleep_duration_aon; /// Difference of resore time an save time on cpus side (in hus) int16_t aon_restore_save_time_diff_cpus; /// Difference of resore time an save time on aon side (in hus) int16_t aon_restore_save_time_diff_aon; /// Difference of restore time on aon side and save time on cpus side (in hus) int16_t aon_restore_save_time_diff_cpus_aon; /// Minimum time that allow clock gate (in hs) int32_t aon_min_clock_gate_duration; /// Minimum time that allow host to clock gate (in hus) int32_t aon_min_clock_gate_duration_cpup; // Maximum rf & md regs supported by aon uint16_t aon_max_nb_rf_mdm_regs; } bt_drv_wr_aon_param; static const bt_drv_wr_aon_param wr_aon_param = { 0x18D700, 0x18F700, 64, 40, 400, 400, 3, 2, 3, 2, 40, 512, 20, 21, 20, 32, 8, -2, 0, 20000, 0x0, 0x20067302, AON_BT_PWR_DLY1, AON_BT_PWR_DLY2, AON_BT_PWR_DLY3, AON_BT_PWR_DLY_AON, 32, 512, 420, 100, 100, 8, 24, 40, 140, 0, 64, 20000, 50 }; static uint8_t aicbt_lp_level = BT_LP_LEVEL_CLOCK_GATE2; static uint8_t aicbt_sleep_state = false; /****************************************************************************** ** Static variables ******************************************************************************/ static bt_lpm_param_t lpm_param = { LPM_SLEEP_MODE, LPM_IDLE_THRESHOLD, LPM_HC_IDLE_THRESHOLD, LPM_BT_WAKE_POLARITY, LPM_HOST_WAKE_POLARITY, LPM_ALLOW_HOST_SLEEP_DURING_SCO, LPM_COMBINE_SLEEP_MODE_AND_LPM, LPM_ENABLE_UART_TXD_TRI_STATE, 0, /* not applicable */ 0, /* not applicable */ 0, /* not applicable */ LPM_PULSED_HOST_WAKE }; static int local_transtype = 0; static bool hw_aic_bt_set_lp_level(HC_BT_HDR *p_buf); static bool hw_aic_bt_wr_aon_params(HC_BT_HDR *p_buf); static bool hw_aic_bt_set_pwr_ctrl_slave(HC_BT_HDR *p_buf); static bool hw_aic_bt_set_cpu_poweroff_en(HC_BT_HDR *p_buf); static bool hw_aic_bt_set_sleep_en(HC_BT_HDR *p_buf); static void hw_config_pre_start(void); void hw_uart_config_start(char transtype); void hw_uart_config_cback(void *p_evt_buf); /****************************************************************************** ** Controller Initialization Static Functions ******************************************************************************/ /******************************************************************************* ** ** Function hw_uart_config_cback ** ** Description Callback function for controller configuration ** ** Returns None ** *******************************************************************************/ void hw_uart_config_cback(void *p_mem) { HC_BT_HDR *p_evt_buf = (HC_BT_HDR *) p_mem; char *p_name, *p_tmp; uint8_t *p, status; uint16_t opcode; HC_BT_HDR *p_buf=NULL; uint8_t is_proceeding = FALSE; int i; int delay=100; #if (USE_CONTROLLER_BDADDR == TRUE) const uint8_t null_bdaddr[BD_ADDR_LEN] = {0,0,0,0,0,0}; #endif status = *((uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_STATUS_RET_BYTE); p = (uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_OPCODE; STREAM_TO_UINT16(opcode,p); /* Ask a new buffer big enough to hold any HCI commands sent in here */ if ((status == 0) && bt_vendor_cbacks) p_buf = (HC_BT_HDR *) bt_vendor_cbacks->alloc(BT_HC_HDR_SIZE + \ HCI_CMD_MAX_LEN); if (p_buf != NULL) { p_buf->event = MSG_STACK_TO_HC_HCI_CMD; p_buf->offset = 0; p_buf->len = 0; p_buf->layer_specific = 0; p = (uint8_t *) (p_buf + 1); switch (hw_cfg_cb.state) { case HW_CFG_START: ALOGE("HW_CFG_START 11"); is_proceeding = hw_config_set_bdaddr(p_buf); break; case HW_CFG_SET_BD_ADDR: if (bt_rf_need_config == true) { is_proceeding = hw_wr_rf_mdm_regs(p_buf); break; } else { if (1) { //AIC_RF_MODE_BT_COMBO == hw_get_bt_rf_mode()) { is_proceeding = hw_aic_bt_pta_en(p_buf); break; } } is_proceeding = hw_aic_bt_wr_aon_params(p_buf); if (is_proceeding == true) break; ALOGI("vendor lib fwcfg completed"); bt_vendor_cbacks->dealloc(p_buf); bt_vendor_cbacks->fwcfg_cb(BT_VND_OP_RESULT_SUCCESS); hw_cfg_cb.state = 0; if (hw_cfg_cb.fw_fd != -1) { close(hw_cfg_cb.fw_fd); hw_cfg_cb.fw_fd = -1; } is_proceeding = TRUE; break; case HW_CFG_WR_RF_MDM_REGS: is_proceeding = hw_wr_rf_mdm_regs(p_buf); ALOGE("AICHW_CFG %x\n",HW_CFG_WR_RF_MDM_REGS); break; case HW_CFG_WR_RF_MDM_REGS_END: is_proceeding = hw_set_rf_mode(p_buf); break; case HW_CFG_SET_RF_MODE: if (bt_rf_need_calib == true) { ALOGE("AICHW_CFG %x\n",HW_CFG_SET_RF_MODE); is_proceeding = hw_rf_calib_req(p_buf); break; } case HW_CFG_RF_CALIB_REQ: ALOGE("AICHW_CFG %x\n",HW_CFG_RF_CALIB_REQ); if (1) { //AIC_RF_MODE_BT_COMBO == hw_get_bt_rf_mode()) { is_proceeding = hw_aic_bt_pta_en(p_buf); break; } case HW_CFG_UPDATE_CONFIG_INFO: is_proceeding = hw_aic_bt_wr_aon_params(p_buf); if (is_proceeding == true) break; case HW_CFG_WR_AON_PARAM: is_proceeding = hw_aic_bt_set_lp_level(p_buf); if (is_proceeding == true) break; case HW_CFG_SET_LP_LEVEL: aicbt_sleep_state = AICBT_SLEEP_STATE_CONFIG_ING; is_proceeding = hw_aic_bt_set_pwr_ctrl_slave(p_buf); if (is_proceeding == true) break; case HW_CFG_SET_PWR_CTRL_SLAVE: is_proceeding = hw_aic_bt_set_cpu_poweroff_en(p_buf); if (is_proceeding == true) break; case HW_CFG_SET_CPU_POWR_OFF_EN: aicbt_sleep_state = AICBT_SLEEP_STATE_CONFIG_DONE; ALOGI("vendor lib fwcfg completed"); bt_vendor_cbacks->dealloc(p_buf); bt_vendor_cbacks->fwcfg_cb(BT_VND_OP_RESULT_SUCCESS); hw_cfg_cb.state = 0; if (hw_cfg_cb.fw_fd != -1) { close(hw_cfg_cb.fw_fd); hw_cfg_cb.fw_fd = -1; } is_proceeding = TRUE; break; #if (USE_CONTROLLER_BDADDR == TRUE) case HW_CFG_READ_BD_ADDR: p_tmp = (char *) (p_evt_buf + 1) + \ HCI_EVT_CMD_CMPL_LOCAL_BDADDR_ARRAY; if (memcmp(p_tmp, null_bdaddr, BD_ADDR_LEN) == 0) { // Controller does not have a valid OTP BDADDR! // Set the BTIF initial BDADDR instead. if ((is_proceeding = hw_config_set_bdaddr(p_buf)) == TRUE) break; } else { ALOGI("Controller OTP bdaddr %02X:%02X:%02X:%02X:%02X:%02X", *(p_tmp+5), *(p_tmp+4), *(p_tmp+3), *(p_tmp+2), *(p_tmp+1), *p_tmp); } ALOGI("vendor lib fwcfg completed"); bt_vendor_cbacks->dealloc(p_buf); bt_vendor_cbacks->fwcfg_cb(BT_VND_OP_RESULT_SUCCESS); hw_cfg_cb.state = 0; if (hw_cfg_cb.fw_fd != -1) { close(hw_cfg_cb.fw_fd); hw_cfg_cb.fw_fd = -1; } is_proceeding = TRUE; break; #endif // (USE_CONTROLLER_BDADDR == TRUE) } } /* Free the RX event buffer */ if (bt_vendor_cbacks) bt_vendor_cbacks->dealloc(p_evt_buf); if (is_proceeding == FALSE) { ALOGE("vendor lib fwcfg aborted!!!"); if (bt_vendor_cbacks) { if (p_buf != NULL) bt_vendor_cbacks->dealloc(p_buf); bt_vendor_cbacks->fwcfg_cb(BT_VND_OP_RESULT_FAIL); } if (hw_cfg_cb.fw_fd != -1) { close(hw_cfg_cb.fw_fd); hw_cfg_cb.fw_fd = -1; } hw_cfg_cb.state = 0; } } /***************************************************************************** ** Hardware Configuration Interface Functions *****************************************************************************/ /******************************************************************************* ** ** Function hw_uart_config_start ** ** Description Kick off controller initialization process ** ** Returns None ** *******************************************************************************/ void hw_uart_config_start(char transtype) { HC_BT_HDR *p_buf = NULL; uint8_t *p; local_transtype = transtype; BTVNDDBG("AICBT_RELEASE_NAME: %s", AICBT_RELEASE_NAME); BTVNDDBG("\nAicsemi libbt-vendor_uart Version %s \n",AIC_VERSION); BTVNDDBG("hw_uart_config_start, transtype = 0x%x \n", transtype); hw_cfg_cb.state = 0; hw_cfg_cb.fw_fd = -1; hw_cfg_cb.f_set_baud_2 = FALSE; /* Start from sending H5 INIT */ if (bt_vendor_cbacks) { /* Must allocate command buffer via HC's alloc API */ p_buf = (HC_BT_HDR *) bt_vendor_cbacks->alloc(BT_HC_HDR_SIZE + \ HCI_CMD_PREAMBLE_SIZE); } else { ALOGE("%s call back is null", __func__); return; } if (p_buf) { p_buf->event = MSG_STACK_TO_HC_HCI_CMD; p_buf->offset = 0; p_buf->layer_specific = 0; p_buf->len = HCI_CMD_PREAMBLE_SIZE; p = (uint8_t *) (p_buf + 1); if (transtype & AICBT_TRANS_H4) { UINT16_TO_STREAM(p, HCI_RESET); *p = 0; /* parameter length */ hw_cfg_cb.state = HW_CFG_START; bt_vendor_cbacks->xmit_cb(HCI_RESET, p_buf, hw_uart_config_cback); } else { UINT16_TO_STREAM(p, HCI_VSC_H5_INIT); *p = 0; /* parameter length */ hw_cfg_cb.state = HW_CFG_H5_INIT; bt_vendor_cbacks->xmit_cb(HCI_VSC_H5_INIT, p_buf, hw_uart_config_cback); } } else { ALOGE("vendor lib fw conf aborted [no buffer]"); bt_vendor_cbacks->fwcfg_cb(BT_VND_OP_RESULT_FAIL); } } /****************************************************************************** ** LPM Static Functions ******************************************************************************/ /******************************************************************************* ** ** Function hw_lpm_ctrl_cback ** ** Description Callback function for lpm enable/disable rquest ** ** Returns None ** *******************************************************************************/ static void hw_lpm_ctrl_cback(void *p_mem) { HC_BT_HDR *p_evt_buf = (HC_BT_HDR *) p_mem; bt_vendor_op_result_t status = BT_VND_OP_RESULT_FAIL; if (*((uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_STATUS_RET_BYTE) == 0) { status = BT_VND_OP_RESULT_SUCCESS; } ALOGE("hw_lpm_ctrl_cback:%x,%x \n",status,*((uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_STATUS_RET_BYTE)); if (bt_vendor_cbacks) { bt_vendor_cbacks->lpm_cb(status); bt_vendor_cbacks->dealloc(p_evt_buf); } } /******************************************************************************* ** ** Function hw_lpm_enable ** ** Description Enalbe/Disable LPM ** ** Returns TRUE/FALSE ** *******************************************************************************/ uint8_t hw_lpm_enable(uint8_t turn_on) { HC_BT_HDR *p_buf = NULL; uint8_t *p; uint8_t ret = FALSE; if (bt_vendor_cbacks) p_buf = (HC_BT_HDR *) bt_vendor_cbacks->alloc(BT_HC_HDR_SIZE + \ HCI_CMD_PREAMBLE_SIZE + \ LPM_CMD_PARAM_SIZE); if (p_buf) { p_buf->event = MSG_STACK_TO_HC_HCI_CMD; p_buf->offset = 0; p_buf->layer_specific = 0; p_buf->len = HCI_CMD_PREAMBLE_SIZE + LPM_CMD_PARAM_SIZE; p = (uint8_t *) (p_buf + 1); UINT16_TO_STREAM(p, HCI_VSC_WRITE_SLEEP_MODE); *p++ = LPM_CMD_PARAM_SIZE; /* parameter length */ if (turn_on) { memcpy(p, &lpm_param, LPM_CMD_PARAM_SIZE); upio_set(UPIO_LPM_MODE, UPIO_ASSERT, 0); } else { memset(p, 0, LPM_CMD_PARAM_SIZE); upio_set(UPIO_LPM_MODE, UPIO_DEASSERT, 0); } if ((ret = bt_vendor_cbacks->xmit_cb(HCI_VSC_WRITE_SLEEP_MODE, p_buf, \ hw_lpm_ctrl_cback)) == FALSE) { bt_vendor_cbacks->dealloc(p_buf); } } if ((ret == FALSE) && bt_vendor_cbacks) bt_vendor_cbacks->lpm_cb(BT_VND_OP_RESULT_FAIL); return ret; } bool hw_lm_direct_return(uint8_t turn_on) { if (bt_vendor_cbacks) { bt_vendor_cbacks->lpm_cb(BT_VND_OP_RESULT_SUCCESS); } return true; } uint8_t hw_lpm_set_sleep_enable(uint8_t turn_on) { HC_BT_HDR *p_buf = NULL; uint8_t *p; uint8_t ret = FALSE; if (turn_on) { upio_set(UPIO_LPM_MODE, UPIO_ASSERT, 0); } else { upio_set(UPIO_LPM_MODE, UPIO_DEASSERT, 0); } if (bt_vendor_cbacks) { bt_vendor_cbacks->lpm_cb(BT_VND_OP_RESULT_SUCCESS); } return 0; ///hw_lm_direct_return(turn_on); ///return true; if (bt_vendor_cbacks) p_buf = (HC_BT_HDR *) bt_vendor_cbacks->alloc(BT_HC_HDR_SIZE + \ HCI_CMD_PREAMBLE_SIZE + \ HCI_VSC_SET_SLEEP_EN_SIZE); if (p_buf) { p_buf->event = MSG_STACK_TO_HC_HCI_CMD; p_buf->offset = 0; p_buf->layer_specific = 0; p_buf->len = HCI_CMD_PREAMBLE_SIZE + HCI_VSC_SET_SLEEP_EN_SIZE; p = (uint8_t *) (p_buf + 1); UINT16_TO_STREAM(p, HCI_VSC_SET_SLEEP_EN_CMD); *p++ = (uint8_t)HCI_VSC_SET_SLEEP_EN_SIZE; /* parameter length */ ALOGE("hw_lpm_set_sleep_enable:%x \n",turn_on); if (turn_on) { upio_set(UPIO_LPM_MODE, UPIO_ASSERT, 0); UINT8_TO_STREAM(p, 1); UINT8_TO_STREAM(p, 0); } else { UINT8_TO_STREAM(p, 0); UINT8_TO_STREAM(p, 0); upio_set(UPIO_LPM_MODE, UPIO_DEASSERT, 0); } p_buf->len = HCI_CMD_PREAMBLE_SIZE + HCI_VSC_SET_SLEEP_EN_SIZE; if ((ret = bt_vendor_cbacks->xmit_cb(HCI_VSC_SET_SLEEP_EN_CMD, p_buf, \ hw_lpm_ctrl_cback)) == FALSE) { bt_vendor_cbacks->dealloc(p_buf); } } if ((ret == FALSE) && bt_vendor_cbacks) bt_vendor_cbacks->lpm_cb(BT_VND_OP_RESULT_FAIL); return ret; } /******************************************************************************* ** ** Function hw_lpm_get_idle_timeout ** ** Description Calculate idle time based on host stack idle threshold ** ** Returns idle timeout value ** *******************************************************************************/ uint32_t hw_lpm_get_idle_timeout(void) { uint32_t timeout_ms; /* set idle time to be LPM_IDLE_TIMEOUT_MULTIPLE times of * host stack idle threshold (in 300ms/25ms) */ timeout_ms = (uint32_t)lpm_param.host_stack_idle_threshold \ * LPM_IDLE_TIMEOUT_MULTIPLE; if (strstr(hw_cfg_cb.local_chip_name, "AIC8800") != NULL) timeout_ms *= 25; // 12.5 or 25 ? else if (strstr(hw_cfg_cb.local_chip_name, "AIC8800") != NULL) timeout_ms *= 50; else timeout_ms *= 300; return timeout_ms; } /******************************************************************************* ** ** Function hw_lpm_set_wake_state ** ** Description Assert/Deassert BT_WAKE ** ** Returns None ** *******************************************************************************/ void hw_lpm_set_wake_state(uint8_t wake_assert) { uint8_t state = (wake_assert) ? UPIO_ASSERT : UPIO_DEASSERT; if (hw_cfg_cb.state != 0) { upio_set(UPIO_LPM_MODE, UPIO_ASSERT, 0); wake_assert = UPIO_ASSERT; } ALOGE("set_wake_stat %x\n",wake_assert); upio_set(UPIO_BT_WAKE, state, lpm_param.bt_wake_polarity); } bool hw_aic_bt_set_lp_level(HC_BT_HDR *p_buf) { ///HC_BT_HDR *p_buf = NULL; uint8_t *p; bool ret = FALSE; if (p_buf == NULL) { if (bt_vendor_cbacks) p_buf = (HC_BT_HDR *) bt_vendor_cbacks->alloc(BT_HC_HDR_SIZE + \ HCI_CMD_PREAMBLE_SIZE + \ HCI_VSC_SET_LP_LEVEL_SIZE); if (p_buf) { p_buf->event = MSG_STACK_TO_HC_HCI_CMD; p_buf->offset = 0; p_buf->layer_specific = 0; p_buf->len = HCI_CMD_PREAMBLE_SIZE + HCI_VSC_SET_LP_LEVEL_SIZE; } else { return ret; } } if (p_buf) { p = (uint8_t *) (p_buf + 1); UINT16_TO_STREAM(p, HCI_VSC_SET_LP_LEVEL_CMD); *p++ = (uint8_t)HCI_VSC_SET_LP_LEVEL_SIZE; /* parameter length */ UINT8_TO_STREAM(p, aicbt_lp_level); p_buf->len = HCI_CMD_PREAMBLE_SIZE + HCI_VSC_SET_LP_LEVEL_SIZE; hw_cfg_cb.state = HW_CFG_SET_LP_LEVEL; ret = bt_vendor_cbacks->xmit_cb(HCI_VSC_SET_LP_LEVEL_CMD, p_buf, \ hw_uart_config_cback); } return ret; } void hw_set_sleep_en_cback(void *p_mem) { HC_BT_HDR *p_evt_buf = (HC_BT_HDR *) p_mem; ALOGE("hw_set_sleep_en_cback\n"); /* Free the RX event buffer */ if (bt_vendor_cbacks) bt_vendor_cbacks->dealloc(p_evt_buf); } bool hw_aic_bt_set_sleep_en(HC_BT_HDR *p_buf) { ///HC_BT_HDR *p_buf = NULL; uint8_t *p; bool ret = FALSE; if (aicbt_sleep_state == AICBT_SLEEP_STATE_CONFIG_DONE) { if (p_buf == NULL) { if (bt_vendor_cbacks) p_buf = (HC_BT_HDR *) bt_vendor_cbacks->alloc(BT_HC_HDR_SIZE + \ HCI_CMD_PREAMBLE_SIZE + \ HCI_VSC_SET_SLEEP_EN_SIZE); if (p_buf) { p_buf->event = MSG_STACK_TO_HC_HCI_CMD; p_buf->offset = 0; p_buf->layer_specific = 0; p_buf->len = HCI_CMD_PREAMBLE_SIZE + HCI_VSC_SET_SLEEP_EN_SIZE; } else { return ret; } } if (p_buf) { p = (uint8_t *) (p_buf + 1); UINT16_TO_STREAM(p, HCI_VSC_SET_SLEEP_EN_CMD); *p++ = (uint8_t)HCI_VSC_SET_SLEEP_EN_SIZE; /* parameter length */ ALOGE("hw_aic_bt_set_sleep_en \n"); UINT8_TO_STREAM(p, 1); UINT8_TO_STREAM(p, 0); p_buf->len = HCI_CMD_PREAMBLE_SIZE + HCI_VSC_SET_SLEEP_EN_SIZE; if ((ret = bt_vendor_cbacks->xmit_cb(HCI_VSC_SET_SLEEP_EN_CMD, p_buf, \ hw_set_sleep_en_cback)) == FALSE) { bt_vendor_cbacks->dealloc(p_buf); } } } return ret; } bool hw_aic_bt_wr_aon_params(HC_BT_HDR *p_buf) { ///HC_BT_HDR *p_buf = NULL; uint8_t *p; bool ret = FALSE; if (p_buf == NULL) { if (bt_vendor_cbacks) p_buf = (HC_BT_HDR *) bt_vendor_cbacks->alloc(BT_HC_HDR_SIZE + \ HCI_CMD_PREAMBLE_SIZE + \ HCI_VSC_WR_AON_PARAM_SIZE); if (p_buf) { p_buf->event = MSG_STACK_TO_HC_HCI_CMD; p_buf->offset = 0; p_buf->layer_specific = 0; p_buf->len = HCI_CMD_PREAMBLE_SIZE + HCI_VSC_WR_AON_PARAM_SIZE; } else { return ret; } } if (p_buf) { ///p_buf->event = MSG_STACK_TO_HC_HCI_CMD; ///p_buf->offset = 0; ///p_buf->layer_specific = 0; ///p_buf->len = HCI_CMD_PREAMBLE_SIZE + HCI_VSC_SET_RF_MODE_SIZE; p = (uint8_t *) (p_buf + 1); UINT16_TO_STREAM(p, HCI_VSC_WR_AON_PARAM_CMD); *p++ = (uint8_t)HCI_VSC_WR_AON_PARAM_SIZE; /* parameter length */ memcpy(p, &wr_aon_param, HCI_VSC_WR_AON_PARAM_SIZE); ALOGI("HW_CFG_WR_AON_PARAM"); p_buf->len = HCI_CMD_PREAMBLE_SIZE + HCI_VSC_WR_AON_PARAM_SIZE; hw_cfg_cb.state = HW_CFG_WR_AON_PARAM; ret = bt_vendor_cbacks->xmit_cb(HCI_VSC_WR_AON_PARAM_CMD, p_buf, \ hw_uart_config_cback); } return ret; } bool hw_aic_bt_set_pwr_ctrl_slave(HC_BT_HDR *p_buf) { ///HC_BT_HDR *p_buf = NULL; uint8_t *p; bool ret = FALSE; if (p_buf == NULL) { if (bt_vendor_cbacks) p_buf = (HC_BT_HDR *) bt_vendor_cbacks->alloc(BT_HC_HDR_SIZE + \ HCI_CMD_PREAMBLE_SIZE + \ HCI_VSC_SET_PWR_CTRL_SLAVE_SIZE); if (p_buf) { p_buf->event = MSG_STACK_TO_HC_HCI_CMD; p_buf->offset = 0; p_buf->layer_specific = 0; p_buf->len = HCI_CMD_PREAMBLE_SIZE + HCI_VSC_SET_PWR_CTRL_SLAVE_SIZE; } else { return ret; } } if (p_buf) { p = (uint8_t *) (p_buf + 1); UINT16_TO_STREAM(p, HCI_VSC_SET_PWR_CTRL_SLAVE_CMD); *p++ = (uint8_t)HCI_VSC_SET_PWR_CTRL_SLAVE_SIZE; /* parameter length */ *p = 1; ALOGI("HW_CFG_SET_PWR_CTRL_SLAVE"); p_buf->len = HCI_CMD_PREAMBLE_SIZE + HCI_VSC_SET_PWR_CTRL_SLAVE_SIZE; hw_cfg_cb.state = HW_CFG_SET_PWR_CTRL_SLAVE; ret = bt_vendor_cbacks->xmit_cb(HCI_VSC_SET_PWR_CTRL_SLAVE_CMD, p_buf, \ hw_uart_config_cback); } return ret; } bool hw_aic_bt_set_cpu_poweroff_en(HC_BT_HDR *p_buf) { ///HC_BT_HDR *p_buf = NULL; uint8_t *p; bool ret = FALSE; if (p_buf == NULL) { if (bt_vendor_cbacks) p_buf = (HC_BT_HDR *) bt_vendor_cbacks->alloc(BT_HC_HDR_SIZE + \ HCI_CMD_PREAMBLE_SIZE + \ HCI_VSC_SET_CPU_POWER_OFF_SIZE); if (p_buf) { p_buf->event = MSG_STACK_TO_HC_HCI_CMD; p_buf->offset = 0; p_buf->layer_specific = 0; p_buf->len = HCI_CMD_PREAMBLE_SIZE + HCI_VSC_SET_CPU_POWER_OFF_SIZE; } else { return ret; } } if (p_buf) { p = (uint8_t *) (p_buf + 1); UINT16_TO_STREAM(p, HCI_VSC_SET_CPU_POWER_OFF_CMD); *p++ = (uint8_t)HCI_VSC_SET_CPU_POWER_OFF_SIZE; /* parameter length */ *p = 1; ALOGI("HW_CFG_SET_CPU_POWR_OFF_EN"); p_buf->len = HCI_CMD_PREAMBLE_SIZE + HCI_VSC_SET_CPU_POWER_OFF_SIZE; hw_cfg_cb.state = HW_CFG_SET_CPU_POWR_OFF_EN; ret = bt_vendor_cbacks->xmit_cb(HCI_VSC_SET_CPU_POWER_OFF_CMD, p_buf, \ hw_uart_config_cback); } return ret; }