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; }
int btif_tx_dma_ctrl(P_MTK_DMA_INFO_STR p_dma_info, ENUM_DMA_CTRL ctrl_id) { unsigned int i_ret = -1; unsigned long base = p_dma_info->base; unsigned int dat; 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(TX_DMA_EN(base), DMA_EN_BIT);*/ BTIF_SET_BIT(TX_DMA_STOP(base), DMA_STOP_BIT); do { dat = BTIF_READ32(TX_DMA_STOP(base)); } while (0x1 & dat); BTIF_DBG_FUNC("BTIF Tx DMA disabled,EN(0x%x),STOP(0x%x)\n", BTIF_READ32(TX_DMA_EN(base)), BTIF_READ32(TX_DMA_STOP(base))); i_ret = 0; } else if (DMA_CTRL_ENABLE == ctrl_id) { BTIF_SET_BIT(TX_DMA_EN(base), DMA_EN_BIT); BTIF_DBG_FUNC("BTIF Tx 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; }
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_tx_vfifo_reset * DESCRIPTION * reset tx virtaul fifo information, except memory information * PARAMETERS * p_dma_info [IN] pointer to BTIF dma channel's information * RETURNS * 0 means success, negative means fail *****************************************************************************/ int hal_btif_vfifo_reset(P_MTK_DMA_INFO_STR p_dma_info) { unsigned int i_ret = -1; 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); BTIF_TRC_FUNC(); p_mtk_dma_vfifo->rpt = 0; p_mtk_dma_vfifo->last_rpt_wrap = 0; p_mtk_dma_vfifo->wpt = 0; p_mtk_dma_vfifo->last_wpt_wrap = 0; BTIF_TRC_FUNC(); 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_info_get * DESCRIPTION * get btif tx dma channel's information * PARAMETERS * dma_dir [IN] DMA's direction * RETURNS * pointer to btif dma's information structure *****************************************************************************/ P_MTK_DMA_INFO_STR hal_btif_dma_info_get(ENUM_DMA_DIR dma_dir) { P_MTK_DMA_INFO_STR p_dma_info = NULL; BTIF_TRC_FUNC(); if (DMA_DIR_RX == dma_dir) { /*Rx DMA*/ p_dma_info = &mtk_btif_rx_dma; } else if (DMA_DIR_TX == dma_dir) { /*Tx DMA*/ p_dma_info = &mtk_btif_tx_dma; } else { /*print error log*/ BTIF_ERR_FUNC("invalid DMA dir (%d)\n", dma_dir); } spin_lock_init(&g_clk_cg_spinlock); BTIF_TRC_FUNC(); return p_dma_info; }
/***************************************************************************** * FUNCTION * hal_tx_dma_info_get * DESCRIPTION * get btif tx dma channel's information * PARAMETERS * dma_dir [IN] DMA's direction * RETURNS * pointer to btif dma's information structure *****************************************************************************/ P_MTK_DMA_INFO_STR hal_btif_dma_info_get(ENUM_DMA_DIR dma_dir) { P_MTK_DMA_INFO_STR p_dma_info = NULL; BTIF_TRC_FUNC(); #ifdef CONFIG_OF hal_dma_set_default_setting(dma_dir); #endif if (DMA_DIR_RX == dma_dir) /*Rx DMA*/ p_dma_info = &mtk_btif_rx_dma; else if (DMA_DIR_TX == dma_dir) /*Tx DMA*/ p_dma_info = &mtk_btif_tx_dma; else /*print error log*/ BTIF_ERR_FUNC("invalid DMA dir (%d)\n", dma_dir); spin_lock_init(&g_clk_cg_spinlock); BTIF_TRC_FUNC(); return p_dma_info; }
/***************************************************************************** * FUNCTION * hal_tx_dma_info_get * DESCRIPTION * get btif tx dma channel's information * PARAMETERS * dma_dir [IN] DMA's direction * RETURNS * pointer to btif dma's information structure *****************************************************************************/ P_MTK_DMA_INFO_STR hal_btif_dma_info_get(ENUM_DMA_DIR dma_dir) { P_MTK_DMA_INFO_STR p_dma_info = NULL; BTIF_TRC_FUNC(); if (DMA_DIR_RX == dma_dir) { /*Rx DMA*/ p_dma_info = &mtk_btif_rx_dma; } else if (DMA_DIR_TX == dma_dir) { /*Tx DMA*/ p_dma_info = &mtk_btif_tx_dma; } else { /*print error log*/ BTIF_ERR_FUNC("invalid DMA dir (%d)\n", dma_dir); } spin_lock_init(&g_clk_cg_spinlock); /*dummy call to prevent build warning*/ hal_dma_receive_data(NULL, NULL, 0); BTIF_TRC_FUNC(); return p_dma_info; }
/***************************************************************************** * FUNCTION * hal_dma_send_data * DESCRIPTION * send data through btif in DMA mode * PARAMETERS * p_dma_info [IN] pointer to BTIF dma channel's information * p_buf [IN] pointer to rx data buffer * max_len [IN] tx buffer length * RETURNS * 0 means success, negative means fail *****************************************************************************/ int hal_dma_send_data(P_MTK_DMA_INFO_STR p_dma_info, const unsigned char *p_buf, const unsigned int buf_len) { unsigned int i_ret = -1; unsigned int base = p_dma_info->base; P_DMA_VFIFO p_vfifo = p_dma_info->p_vfifo; unsigned int len_to_send = buf_len; unsigned int ava_len = 0; unsigned int wpt = 0; unsigned int last_wpt_wrap = 0; unsigned int vff_size = 0; unsigned char *p_data = (unsigned char *)p_buf; P_MTK_BTIF_DMA_VFIFO p_mtk_vfifo = container_of(p_vfifo, MTK_BTIF_DMA_VFIFO, vfifo); BTIF_TRC_FUNC(); if ((NULL == p_buf) || (0 == buf_len)) { i_ret = ERR_INVALID_PAR; BTIF_ERR_FUNC("invalid parameters, p_buf:0x%08x, buf_len:%d\n", p_buf, buf_len); return i_ret; } /*check if tx dma in flush operation? if yes, should wait until DMA finish flush operation*/ /*currently uplayer logic will make sure this pre-condition*/ /*disable Tx IER, in case Tx irq happens, flush bit may be set in irq handler*/ btif_tx_dma_ier_ctrl(p_dma_info, false); vff_size = p_mtk_vfifo->vfifo.vfifo_size; ava_len = BTIF_READ32(TX_DMA_VFF_LEFT_SIZE(base)); wpt = BTIF_READ32(TX_DMA_VFF_WPT(base)) & DMA_WPT_MASK; last_wpt_wrap = BTIF_READ32(TX_DMA_VFF_WPT(base)) & DMA_WPT_WRAP; /*copy data to vFIFO, Note: ava_len should always large than buf_len, otherwise common logic layer will not call hal_dma_send_data*/ if (buf_len > ava_len) { BTIF_ERR_FUNC ("length to send:(%d) < length available(%d), abnormal!!!---!!!\n", buf_len, ava_len); BUG_ON(buf_len > ava_len); /* this will cause kernel panic */ } len_to_send = buf_len < ava_len ? buf_len : ava_len; if (len_to_send + wpt >= vff_size) { unsigned int tail_len = vff_size - wpt; memcpy((p_mtk_vfifo->vfifo.p_vir_addr + wpt), p_data, tail_len); p_data += tail_len; memcpy(p_mtk_vfifo->vfifo.p_vir_addr, p_data, len_to_send - tail_len); /*make sure all data write to memory area tx vfifo locates*/ dsb(); /*calculate WPT*/ wpt = wpt + len_to_send - vff_size; last_wpt_wrap ^= DMA_WPT_WRAP; } else { memcpy((p_mtk_vfifo->vfifo.p_vir_addr + wpt), p_data, len_to_send); /*make sure all data write to memory area tx vfifo locates*/ dsb(); /*calculate WPT*/ wpt += len_to_send; } p_mtk_vfifo->wpt = wpt; p_mtk_vfifo->last_wpt_wrap = last_wpt_wrap; /*make sure tx dma is allowed(tx flush bit is not set) to use before update WPT*/ if (hal_dma_is_tx_allow(p_dma_info)) { /*make sure tx dma enabled*/ hal_btif_dma_ctrl(p_dma_info, DMA_CTRL_ENABLE); /*update WTP to Tx DMA controller's control register*/ btif_reg_sync_writel(wpt | last_wpt_wrap, TX_DMA_VFF_WPT(base)); if ((8 > BTIF_READ32(TX_DMA_VFF_VALID_SIZE(base))) && (0 < BTIF_READ32(TX_DMA_VFF_VALID_SIZE(base)))) { /*0 < valid size in Tx vFIFO < 8 && TX Flush is not in process<should always be done>? if yes, set flush bit to DMA*/ _tx_dma_flush(p_dma_info); } i_ret = len_to_send; } else { /*TODO: print error log*/ BTIF_ERR_FUNC ("Tx DMA flush operation is in process, this case should never happen, please check if tx operation is allowed before call this API\n"); /*if flush operation is in process , we will return 0*/ i_ret = 0; } /*Enable Tx IER*/ btif_tx_dma_ier_ctrl(p_dma_info, true); BTIF_TRC_FUNC(); return i_ret; }