int hal_btif_dma_hw_init(P_MTK_DMA_INFO_STR p_dma_info) { int i_ret = 0; unsigned long 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(RX_DMA_RST(base), DMA_HARD_RST); BTIF_SET_BIT(RX_DMA_RST(base), DMA_WARM_RST); while((0x01 & BTIF_READ32(RX_DMA_EN(base)))); /*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)); btif_reg_sync_writel(p_mtk_dma_vfifo->rpt, RX_DMA_VFF_RPT(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); BTIF_SET_BIT(TX_DMA_RST(base), DMA_WARM_RST); while((0x01 & BTIF_READ32(TX_DMA_EN(base)))); /*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)); btif_reg_sync_writel(p_mtk_dma_vfifo->rpt, TX_DMA_VFF_RPT(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; }
static int hal_tx_dma_dump_reg(P_MTK_DMA_INFO_STR p_dma_info, ENUM_BTIF_REG_ID flag) { int i_ret = -1; unsigned int base = p_dma_info->base; unsigned int int_flag = 0; unsigned int enable = 0; unsigned int stop = 0; unsigned int flush = 0; unsigned int wpt = 0; unsigned int rpt = 0; unsigned int int_buf = 0; unsigned int valid_size = 0; /*unsigned long irq_flag = 0;*/ /*spin_lock_irqsave(&(g_clk_cg_spinlock), irq_flag);*/ if (0 == clock_is_on(MTK_BTIF_APDMA_CLK_CG)) { /*spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag);*/ BTIF_ERR_FUNC("%s: clock is off, this should never happen!!!\n", __FILE__); return i_ret; } int_flag = BTIF_READ32(TX_DMA_INT_FLAG(base)); enable = BTIF_READ32(TX_DMA_EN(base)); stop = BTIF_READ32(TX_DMA_STOP(base)); flush = BTIF_READ32(TX_DMA_FLUSH(base)); wpt = BTIF_READ32(TX_DMA_VFF_WPT(base)); rpt = BTIF_READ32(TX_DMA_VFF_RPT(base)); int_buf = BTIF_READ32(TX_DMA_INT_BUF_SIZE(base)); valid_size = BTIF_READ32(TX_DMA_VFF_VALID_SIZE(base)); /*spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag);*/ BTIF_INFO_FUNC("DMA's clock is on\n"); BTIF_INFO_FUNC("Tx DMA's base address: 0x%x\n", base); if (REG_TX_DMA_ALL == flag) { BTIF_INFO_FUNC("TX_EN(:0x%x\n", enable); BTIF_INFO_FUNC("INT_FLAG:0x%x\n", int_flag); BTIF_INFO_FUNC("TX_STOP:0x%x\n", stop); BTIF_INFO_FUNC("TX_FLUSH:0x%x\n", flush); BTIF_INFO_FUNC("TX_WPT:0x%x\n", wpt); BTIF_INFO_FUNC("TX_RPT:0x%x\n", rpt); BTIF_INFO_FUNC("INT_BUF_SIZE:0x%x\n", int_buf); BTIF_INFO_FUNC("VALID_SIZE:0x%x\n", valid_size); BTIF_INFO_FUNC("INT_EN:0x%x\n", BTIF_READ32(TX_DMA_INT_EN(base))); BTIF_INFO_FUNC("TX_RST:0x%x\n", BTIF_READ32(TX_DMA_RST(base))); BTIF_INFO_FUNC("VFF_ADDR:0x%x\n", BTIF_READ32(TX_DMA_VFF_ADDR(base))); BTIF_INFO_FUNC("VFF_LEN:0x%x\n", BTIF_READ32(TX_DMA_VFF_LEN(base))); BTIF_INFO_FUNC("TX_THRE:0x%x\n", BTIF_READ32(TX_DMA_VFF_THRE(base))); BTIF_INFO_FUNC("W_INT_BUF_SIZE:0x%x\n", BTIF_READ32(TX_DMA_W_INT_BUF_SIZE(base))); BTIF_INFO_FUNC("LEFT_SIZE:0x%x\n", BTIF_READ32(TX_DMA_VFF_LEFT_SIZE(base))); BTIF_INFO_FUNC("DBG_STATUS:0x%x\n", BTIF_READ32(TX_DMA_DEBUG_STATUS(base))); i_ret = 0; } else { BTIF_WARN_FUNC("unknown flag:%d\n", flag); } BTIF_INFO_FUNC("tx dma %s\n", (enable & DMA_EN_BIT) && (!(stop && DMA_STOP_BIT)) ? "enabled" : "stoped"); BTIF_INFO_FUNC("data in tx dma is %s sent by HW\n", ((wpt == rpt) && (int_buf == 0)) ? "completely" : "not completely"); return i_ret; }
/***************************************************************************** * 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; }