int hal_btif_dma_hw_init(P_MTK_DMA_INFO_STR p_dma_info) { int i_ret = 0; unsigned int base = p_dma_info->base; P_DMA_VFIFO p_vfifo = p_dma_info->p_vfifo; P_MTK_BTIF_DMA_VFIFO p_mtk_dma_vfifo = container_of(p_vfifo, MTK_BTIF_DMA_VFIFO, vfifo); if (DMA_DIR_RX == p_dma_info->dir) { /*Rx DMA*/ /*do hardware reset*/ BTIF_SET_BIT(RX_DMA_RST(base), DMA_HARD_RST); BTIF_CLR_BIT(TX_DMA_RST(base), DMA_HARD_RST); /*write vfifo base address to VFF_ADDR*/ btif_reg_sync_writel(p_vfifo->phy_addr, RX_DMA_VFF_ADDR(base)); /*write vfifo length to VFF_LEN*/ btif_reg_sync_writel(p_vfifo->vfifo_size, RX_DMA_VFF_LEN(base)); /*write wpt to VFF_WPT*/ btif_reg_sync_writel(p_mtk_dma_vfifo->wpt, RX_DMA_VFF_WPT(base)); /*write vff_thre to VFF_THRESHOLD*/ btif_reg_sync_writel(p_vfifo->thre, RX_DMA_VFF_THRE(base)); /*clear Rx DMA's interrupt status*/ BTIF_SET_BIT(RX_DMA_INT_FLAG(base), RX_DMA_INT_DONE | RX_DMA_INT_THRE); /*enable Rx IER by default*/ btif_rx_dma_ier_ctrl(p_dma_info, true); } else { /*Tx DMA*/ /*do hardware reset*/ BTIF_SET_BIT(TX_DMA_RST(base), DMA_HARD_RST); BTIF_CLR_BIT(TX_DMA_RST(base), DMA_HARD_RST); /*write vfifo base address to VFF_ADDR*/ btif_reg_sync_writel(p_vfifo->phy_addr, TX_DMA_VFF_ADDR(base)); /*write vfifo length to VFF_LEN*/ btif_reg_sync_writel(p_vfifo->vfifo_size, TX_DMA_VFF_LEN(base)); /*write wpt to VFF_WPT*/ btif_reg_sync_writel(p_mtk_dma_vfifo->wpt, TX_DMA_VFF_WPT(base)); /*write vff_thre to VFF_THRESHOLD*/ btif_reg_sync_writel(p_vfifo->thre, TX_DMA_VFF_THRE(base)); BTIF_CLR_BIT(TX_DMA_INT_FLAG(base), TX_DMA_INT_FLAG_MASK); hal_btif_dma_ier_ctrl(p_dma_info, false); } return i_ret; }
/***************************************************************************** * FUNCTION * hal_btif_raise_wak_sig * DESCRIPTION * raise wakeup signal to counterpart * PARAMETERS * p_base [IN] BTIF module's base address * RETURNS * 0 means success, negative means fail *****************************************************************************/ int hal_btif_raise_wak_sig(P_MTK_BTIF_INFO_STR p_btif) { int i_ret = -1; unsigned int base = p_btif->base; #if MTK_BTIF_ENABLE_CLK_CTL if (0 == clock_is_on(MTK_BTIF_CG_BIT)) { BTIF_ERR_FUNC("%s: clock is off before send wakeup signal!!!\n", __FILE__); return i_ret; } #endif /*write 0 to BTIF_WAK to pull ap_wakeup_consyss low */ BTIF_CLR_BIT(BTIF_WAK(base), BTIF_WAK_BIT); /*wait for a period for longer than 1/32k period, here we use 40us*/ set_current_state(TASK_UNINTERRUPTIBLE); usleep_range(64, 96); /*according to linux/documentation/timers/timers-how-to, we choose usleep_range SLEEPING FOR ~USECS OR SMALL MSECS ( 10us - 20ms): * Use usleep_range */ /*write 1 to pull ap_wakeup_consyss high*/ BTIF_SET_BIT(BTIF_WAK(base), BTIF_WAK_BIT); i_ret = 0; return i_ret; }
int btif_rx_dma_ctrl(P_MTK_DMA_INFO_STR p_dma_info, ENUM_DMA_CTRL ctrl_id) { unsigned int i_ret = -1; unsigned int base = p_dma_info->base; BTIF_TRC_FUNC(); if (DMA_CTRL_DISABLE == ctrl_id) { /*if write 0 to EN bit, DMA will be stoped imediately*/ /*if write 1 to STOP bit, DMA will be stoped after current transaction finished*/ BTIF_CLR_BIT(RX_DMA_EN(base), DMA_EN_BIT); BTIF_DBG_FUNC("BTIF Rx DMA disabled\n"); i_ret = 0; } else if (DMA_CTRL_ENABLE == ctrl_id) { BTIF_SET_BIT(RX_DMA_EN(base), DMA_EN_BIT); BTIF_DBG_FUNC("BTIF Rx DMA enabled\n"); i_ret = 0; } else { /*TODO: print error log*/ BTIF_ERR_FUNC("invalid DMA ctrl_id (%d)\n", ctrl_id); i_ret = ERR_INVALID_PAR; } BTIF_TRC_FUNC(); return i_ret; }
static int btif_new_handshake_ctrl(P_MTK_BTIF_INFO_STR p_btif, bool enable) { unsigned int base = p_btif->base; if (true == enable) { BTIF_SET_BIT(BTIF_HANDSHAKE(base), BTIF_HANDSHAKE_EN_HANDSHAKE); } else { BTIF_CLR_BIT(BTIF_HANDSHAKE(base), BTIF_HANDSHAKE_EN_HANDSHAKE); } return true; }
/***************************************************************************** * FUNCTION * hal_btif_rx_ier_ctrl * DESCRIPTION * BTIF Rx interrupt enable/disable * PARAMETERS * p_base [IN] BTIF module's base address * enable [IN] control if rx interrupt enabled or not * RETURNS * 0 means success, negative means fail *****************************************************************************/ int hal_btif_rx_ier_ctrl(P_MTK_BTIF_INFO_STR p_btif, bool en) { int i_ret = -1; unsigned int base = p_btif->base; if (false == en) { BTIF_CLR_BIT(BTIF_IER(base), BTIF_IER_RXFEN); } else { BTIF_SET_BIT(BTIF_IER(base), BTIF_IER_RXFEN); } /*TODO:do we need to read back ? Answer: no*/ i_ret = 0; return i_ret; }
int btif_tx_dma_ier_ctrl(P_MTK_DMA_INFO_STR p_dma_info, bool en) { unsigned int i_ret = -1; unsigned long base = p_dma_info->base; BTIF_TRC_FUNC(); if (!en) BTIF_CLR_BIT(TX_DMA_INT_EN(base), TX_DMA_INTEN_BIT); else BTIF_SET_BIT(TX_DMA_INT_EN(base), TX_DMA_INTEN_BIT); i_ret = 0; BTIF_TRC_FUNC(); return i_ret; }
/***************************************************************************** * FUNCTION * hal_btif_tx_mode_ctrl * DESCRIPTION * set BTIF tx to corresponding mode (PIO/DMA) * PARAMETERS * p_base [IN] BTIF module's base address * mode [IN] rx mode <PIO/DMA> * RETURNS * 0 means success, negative means fail *****************************************************************************/ int hal_btif_tx_mode_ctrl(P_MTK_BTIF_INFO_STR p_btif, ENUM_BTIF_MODE mode) { int i_ret = -1; unsigned int base = p_btif->base; if (BTIF_MODE_DMA == mode) { /*set to DMA mode*/ BTIF_SET_BIT(BTIF_DMA_EN(base), BTIF_DMA_EN_TX); } else { /*set to PIO mode*/ BTIF_CLR_BIT(BTIF_DMA_EN(base), BTIF_DMA_EN_TX); } i_ret = 0; return i_ret; }
/***************************************************************************** * FUNCTION * hal_btif_loopback_ctrl * DESCRIPTION * BTIF Tx/Rx loopback mode set, this operation can only be done after set BTIF to normal mode * PARAMETERS * RETURNS * 0 means success, negative means fail *****************************************************************************/ int hal_btif_loopback_ctrl(P_MTK_BTIF_INFO_STR p_btif, bool en) { int i_ret = -1; unsigned int base = p_btif->base; if (false == en) { BTIF_CLR_BIT(BTIF_TRI_LVL(base), BTIF_TRI_LOOP_EN); } else { BTIF_SET_BIT(BTIF_TRI_LVL(base), BTIF_TRI_LOOP_EN); } /*TODO:do we need to read back ? Answer: no*/ /*TODO:do we need to dsb?*/ i_ret = 0; return i_ret; }
/***************************************************************************** * FUNCTION * btif_tx_fifo_reset * DESCRIPTION * reset BTIF's tx fifo * PARAMETERS * p_base [IN] BTIF module's base address * RETURNS * 0 means success, negative means fail *****************************************************************************/ static int btif_tx_fifo_reset(P_MTK_BTIF_INFO_STR p_btif) { int i_ret = -1; unsigned int base = p_btif->base; /*set Tx FIFO clear bit to 1*/ BTIF_SET_BIT(BTIF_FIFOCTRL(base), BTIF_FIFOCTRL_CLR_TX); /*clear Tx FIFO clear bit to 0*/ BTIF_CLR_BIT(BTIF_FIFOCTRL(base), BTIF_FIFOCTRL_CLR_TX); /*TODO:do we need to read back ? Answer: no*/ /*TODO:do we need to dsb?*/ i_ret = 0; return i_ret; }
/***************************************************************************** * FUNCTION * btif_rx_fifo_reset * DESCRIPTION * reset BTIF's rx fifo * PARAMETERS * p_base [IN] BTIF module's base address * ec [IN] control if loopback mode is enabled or not * RETURNS * 0 means success, negative means fail *****************************************************************************/ static int btif_rx_fifo_reset(P_MTK_BTIF_INFO_STR p_btif) { /*Chaozhong: To be implement*/ int i_ret = -1; unsigned int base = p_btif->base; /*set Rx FIFO clear bit to 1*/ BTIF_SET_BIT(BTIF_FIFOCTRL(base), BTIF_FIFOCTRL_CLR_RX); /*clear Rx FIFO clear bit to 0*/ BTIF_CLR_BIT(BTIF_FIFOCTRL(base), BTIF_FIFOCTRL_CLR_RX); /*TODO:do we need to read back ? Answer: no*/ /*TODO:do we need to dsb?*/ i_ret = 0; return i_ret; }
int btif_sleep_ctrl(P_MTK_BTIF_INFO_STR p_btif, bool en) { int i_ret = -1; unsigned int base = p_btif->base; if (false == en) { BTIF_CLR_BIT(BTIF_SLEEP_EN(base), BTIF_SLEEP_EN_BIT); } else { BTIF_SET_BIT(BTIF_SLEEP_EN(base), BTIF_SLEEP_EN_BIT); } /*TODO:do we need to read back ? Answer: no*/ /*TODO:do we need to dsb?*/ i_ret = 0; return i_ret; }
int btif_rx_dma_ier_ctrl(P_MTK_DMA_INFO_STR p_dma_info, bool en) { unsigned int i_ret = -1; unsigned int base = p_dma_info->base; BTIF_TRC_FUNC(); if (!en) { BTIF_CLR_BIT(RX_DMA_INT_EN(base), (RX_DMA_INT_THRE_EN | RX_DMA_INT_DONE_EN)); } else { BTIF_SET_BIT(RX_DMA_INT_EN(base), (RX_DMA_INT_THRE_EN | RX_DMA_INT_DONE_EN)); } i_ret = 0; BTIF_TRC_FUNC(); return i_ret; }
/***************************************************************************** * FUNCTION * hal_tx_dma_irq_handler * DESCRIPTION * lower level tx interrupt handler * PARAMETERS * p_dma_info [IN] pointer to BTIF dma channel's information * RETURNS * 0 means success, negative means fail *****************************************************************************/ int hal_tx_dma_irq_handler(P_MTK_DMA_INFO_STR p_dma_info) { #define MAX_CONTINIOUS_TIMES 512 unsigned int i_ret = -1; unsigned int valid_size = 0; unsigned int vff_len = 0; unsigned int left_len = 0; unsigned int base = p_dma_info->base; static int flush_irq_counter; static struct timeval start_timer; static struct timeval end_timer; unsigned long flag = 0; spin_lock_irqsave(&(g_clk_cg_spinlock), flag); if (0 == clock_is_on(MTK_BTIF_APDMA_CLK_CG)) { spin_unlock_irqrestore(&(g_clk_cg_spinlock), flag); BTIF_ERR_FUNC ("%s: clock is off before irq status clear done!!!\n", __FILE__); return i_ret; } /*check if Tx VFF Left Size equal to VFIFO size or not*/ vff_len = BTIF_READ32(TX_DMA_VFF_LEN(base)); valid_size = BTIF_READ32(TX_DMA_VFF_VALID_SIZE(base)); left_len = BTIF_READ32(TX_DMA_VFF_LEFT_SIZE(base)); if (0 == flush_irq_counter) { do_gettimeofday(&start_timer); } if ((0 < valid_size) && (8 > valid_size)) { i_ret = _tx_dma_flush(p_dma_info); flush_irq_counter++; if (MAX_CONTINIOUS_TIMES <= flush_irq_counter) { do_gettimeofday(&end_timer); /*when btif tx fifo cannot accept any data and counts of bytes left in tx vfifo < 8 for a while we assume that btif cannot send data for a long time in order not to generate interrupt continiously, which may effect system's performance. we clear tx flag and disable btif tx interrupt */ /*clear interrupt flag*/ BTIF_CLR_BIT(TX_DMA_INT_FLAG(base), TX_DMA_INT_FLAG_MASK); /*vFIFO data has been read by DMA controller, just disable tx dma's irq*/ i_ret = hal_btif_dma_ier_ctrl(p_dma_info, false); BTIF_ERR_FUNC ("**********************ERROR, ERROR, ERROR**************************\n"); BTIF_ERR_FUNC ("BTIF Tx IRQ happened %d times (continiously), between %d.%d and %d.%d\n", MAX_CONTINIOUS_TIMES, start_timer.tv_sec, start_timer.tv_usec, end_timer.tv_usec, end_timer.tv_usec); } } else if (vff_len == left_len) { flush_irq_counter = 0; /*clear interrupt flag*/ BTIF_CLR_BIT(TX_DMA_INT_FLAG(base), TX_DMA_INT_FLAG_MASK); /*vFIFO data has been read by DMA controller, just disable tx dma's irq*/ i_ret = hal_btif_dma_ier_ctrl(p_dma_info, false); } else { #if 0 BTIF_ERR_FUNC ("**********************WARNING**************************\n"); BTIF_ERR_FUNC("invalid irq condition, dump register\n"); hal_dma_dump_reg(p_dma_info, REG_TX_DMA_ALL); #endif BTIF_DBG_FUNC ("superious IRQ occurs, vff_len(%d), valid_size(%d), left_len(%d)\n", vff_len, valid_size, left_len); } spin_unlock_irqrestore(&(g_clk_cg_spinlock), flag); return i_ret; }