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; }
/***************************************************************************** * FUNCTION * hal_btif_is_tx_complete * DESCRIPTION * get tx complete flag * PARAMETERS * p_base [IN] BTIF module's base address * RETURNS * true means tx complete, false means tx in process *****************************************************************************/ bool hal_btif_is_tx_complete(P_MTK_BTIF_INFO_STR p_btif) { /*Chaozhong: To be implement*/ bool b_ret = false; unsigned int lsr = 0; unsigned long flags = 0; unsigned int base = p_btif->base; unsigned int tx_empty = 0; unsigned int rx_dr = 0; unsigned int tx_irq_disable = 0; /*3 conditions allow clock to be disable 1. if TEMT is set or not 2. if DR is set or not 3. Tx IRQ is disabled or not*/ lsr = BTIF_READ32(BTIF_LSR(base)); tx_empty = lsr & BTIF_LSR_TEMT_BIT; rx_dr = lsr & BTIF_LSR_DR_BIT; tx_irq_disable = BTIF_READ32(BTIF_IER(base)) & BTIF_IER_TXEEN; b_ret = (tx_empty && (0 == tx_irq_disable) && (0 == rx_dr) ) ? true : false; if (!b_ret) { BTIF_DBG_FUNC("BTIF flag, tx_empty:%d, rx_dr:%d, tx_irq_disable:%d\n", tx_empty, rx_dr, tx_irq_disable); } #if NEW_TX_HANDLING_SUPPORT spin_lock_irqsave(&(p_btif->tx_fifo_spinlock), flags); /*clear Tx enable flag if necessary*/ if (!(kfifo_is_empty(p_btif->p_tx_fifo))){ BTIF_DBG_FUNC("BTIF tx FIFO is not empty\n"); b_ret = false; } spin_unlock_irqrestore(&(p_btif->tx_fifo_spinlock), flags); #endif return b_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; }
/***************************************************************************** * FUNCTION * btif_tx_irq_handler * DESCRIPTION * lower level tx interrupt handler * PARAMETERS * p_base [IN] BTIF module's base address * p_buf [IN/OUT] pointer to rx data buffer * max_len [IN] max length of rx buffer * RETURNS * 0 means success, negative means fail *****************************************************************************/ static int btif_tx_irq_handler (P_MTK_BTIF_INFO_STR p_btif) { int i_ret = -1; #if NEW_TX_HANDLING_SUPPORT int how_many = 0; unsigned int lsr; unsigned int ava_len = 0; unsigned int base = p_btif->base; char local_buf[BTIF_TX_FIFO_SIZE]; char *p_data = local_buf; unsigned long flag = 0; struct kfifo *p_tx_fifo = p_btif->p_tx_fifo; /*read LSR and check THER or TEMT, either one is 1 means can accept tx data*/ lsr = BTIF_READ32(BTIF_LSR(base)); if (lsr & BTIF_LSR_TEMT_BIT) { /*Tx Holding Register if empty, which means we can write tx FIFO count to BTIF*/ ava_len = BTIF_TX_FIFO_SIZE; } else if (lsr & BTIF_LSR_THRE_BIT) { /*Tx Holding Register if empty, which means we can write (Tx FIFO count - Tx threshold)to BTIF*/ ava_len = BTIF_TX_FIFO_SIZE - BTIF_TX_FIFO_THRE; }else { /*this means data size in tx FIFO is more than Tx threshold, we will not write data to THR*/ ava_len = 0; goto ret; } spin_lock_irqsave(&(p_btif->tx_fifo_spinlock), flag); how_many = kfifo_out(p_tx_fifo, local_buf, ava_len); spin_unlock_irqrestore(&(p_btif->tx_fifo_spinlock), flag); BTIF_DBG_FUNC("BTIF tx size %d done, left:%d\n", how_many, kfifo_avail(p_tx_fifo)); while (how_many--) { btif_reg_sync_writeb(*(p_data++), BTIF_THR(base)); } spin_lock_irqsave(&(p_btif->tx_fifo_spinlock), flag); /*clear Tx enable flag if necessary*/ if (kfifo_is_empty(p_tx_fifo)){ hal_btif_tx_ier_ctrl(p_btif, false); BTIF_DBG_FUNC("BTIF tx FIFO is empty\n"); } spin_unlock_irqrestore(&(p_btif->tx_fifo_spinlock), flag); ret: #else /*clear Tx enable flag*/ hal_btif_tx_ier_ctrl(p_btif, false); #endif i_ret = 0; return i_ret; }
int hal_btif_pm_ops(P_MTK_BTIF_INFO_STR p_btif_info, MTK_BTIF_PM_OPID opid) { int i_ret = -1; BTIF_DBG_FUNC("op id: %d\n", opid); switch (opid) { case BTIF_PM_DPIDLE_EN: i_ret = 0; break; case BTIF_PM_DPIDLE_DIS: i_ret = 0; break; case BTIF_PM_SUSPEND: i_ret = 0; break; case BTIF_PM_RESUME: i_ret = 0; break; case BTIF_PM_RESTORE_NOIRQ: { unsigned int flag = 0; P_MTK_BTIF_IRQ_STR p_irq = p_btif_info->p_irq; switch (p_irq->sens_type) { case IRQ_SENS_EDGE: if (IRQ_EDGE_FALL == p_irq->edge_type) flag = IRQF_TRIGGER_FALLING; else if (IRQ_EDGE_RAISE == p_irq->edge_type) flag = IRQF_TRIGGER_RISING; else if (IRQ_EDGE_BOTH == p_irq->edge_type) flag = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING; else flag = IRQF_TRIGGER_FALLING; /*make this as default type*/ break; case IRQ_SENS_LVL: if (IRQ_LVL_LOW == p_irq->lvl_type) flag = IRQF_TRIGGER_LOW; else if (IRQ_LVL_HIGH == p_irq->lvl_type) flag = IRQF_TRIGGER_HIGH; else flag = IRQF_TRIGGER_LOW; /*make this as default type*/ break; default: flag = IRQF_TRIGGER_LOW;/*make this as default type*/ break; } //irq_set_irq_type(p_irq->irq_id, flag); i_ret = 0; } break; default: i_ret = ERR_INVALID_PAR; break; } return i_ret; }
/***************************************************************************** * FUNCTION * hal_btif_is_tx_allow * DESCRIPTION * whether tx is allowed * PARAMETERS * p_base [IN] BTIF module's base address * RETURNS * true if tx operation is allowed; false if tx is not allowed *****************************************************************************/ bool hal_btif_is_tx_allow(P_MTK_BTIF_INFO_STR p_btif) { #define MIN_TX_MB ((26 * 1000000 / 13) / 1000000 ) #define AVE_TX_MB ((26 * 1000000 / 8) / 1000000 ) /*Chaozhong: To be implement*/ bool b_ret = false; unsigned int base = p_btif->base; unsigned int lsr = 0; unsigned int wait_us = (BTIF_TX_FIFO_SIZE - BTIF_TX_FIFO_THRE) / MIN_TX_MB ; /*only ava length */ #if NEW_TX_HANDLING_SUPPORT unsigned long flags = 0; spin_lock_irqsave(&(p_btif->tx_fifo_spinlock), flags); /*clear Tx enable flag if necessary*/ if (kfifo_is_full(p_btif->p_tx_fifo)){ BTIF_WARN_FUNC("BTIF tx FIFO is full\n"); b_ret = false; } else { b_ret = true; } spin_unlock_irqrestore(&(p_btif->tx_fifo_spinlock), flags); #else /*read LSR and check THER or TEMT, either one is 1 means can accept tx data*/ lsr = BTIF_READ32(BTIF_LSR(base)); if(!(lsr & (BTIF_LSR_TEMT_BIT | BTIF_LSR_THRE_BIT))) { BTIF_DBG_FUNC("wait for %d ~ %d us\n", wait_us, 3 * wait_us); //usleep_range(wait_us, 3 * 10 * wait_us); usleep_range(wait_us, 3 * wait_us); } lsr = BTIF_READ32(BTIF_LSR(base)); b_ret = (lsr & (BTIF_LSR_TEMT_BIT | BTIF_LSR_THRE_BIT)) ? true : false; if (!b_ret) BTIF_DBG_FUNC(" tx is not allowed for the moment\n"); else BTIF_DBG_FUNC(" tx is allowed\n"); #endif return b_ret; }
/***************************************************************************** * FUNCTION * hal_dma_get_ava_room * DESCRIPTION * get tx available room * PARAMETERS * p_dma_info [IN] pointer to BTIF dma channel's information * RETURNS * available room size *****************************************************************************/ int hal_dma_get_ava_room(P_MTK_DMA_INFO_STR p_dma_info) { int i_ret = -1; unsigned long base = p_dma_info->base; /*read vFIFO's left size*/ i_ret = BTIF_READ32(TX_DMA_VFF_LEFT_SIZE(base)); BTIF_DBG_FUNC("DMA tx ava room (%d).\n", i_ret); if (0 == i_ret) BTIF_INFO_FUNC("DMA tx vfifo is full.\n"); return i_ret; }
static int _get_btif_tx_fifo_room(P_MTK_BTIF_INFO_STR p_btif_info) { int i_ret = 0; unsigned long flag = 0; spin_lock_irqsave(&(p_btif_info->tx_fifo_spinlock), flag); if (NULL == p_btif_info->p_tx_fifo) { i_ret = 0; } else { i_ret = kfifo_avail(p_btif_info->p_tx_fifo); } spin_unlock_irqrestore(&(p_btif_info->tx_fifo_spinlock), flag); BTIF_DBG_FUNC("tx kfifo:0x%x, available room:%d\n", i_ret); return i_ret; }
/***************************************************************************** * FUNCTION * hal_dma_is_tx_complete * DESCRIPTION * get tx complete flag * PARAMETERS * p_dma_info [IN] pointer to BTIF dma channel's information * RETURNS * true means tx complete, false means tx in process *****************************************************************************/ bool hal_dma_is_tx_complete(P_MTK_DMA_INFO_STR p_dma_info) { bool b_ret = -1; unsigned int base = p_dma_info->base; unsigned int valid_size = BTIF_READ32(TX_DMA_VFF_VALID_SIZE(base)); unsigned int inter_size = BTIF_READ32(TX_DMA_INT_BUF_SIZE(base)); unsigned int tx_done = is_tx_dma_irq_finish_done(p_dma_info); /*only when virtual FIFO valid size and Tx channel internal buffer size are both becomes to be 0, we can identify tx operation finished confirmed with DE. */ if ((0 == valid_size) && (0 == inter_size) && (1 == tx_done)) { b_ret = true; BTIF_DBG_FUNC("DMA tx finished.\n"); } else { BTIF_DBG_FUNC ("DMA tx is in process. vfifo valid size(%d), dma internal size (%d), tx_done(%d)\n", valid_size, inter_size, tx_done); b_ret = false; } return b_ret; }
static int _tx_dma_flush(P_MTK_DMA_INFO_STR p_dma_info) { unsigned int i_ret = -1; unsigned long base = p_dma_info->base; unsigned int stop = BTIF_READ32(TX_DMA_STOP(base)); /*in MTK DMA BTIF channel we cannot set STOP and FLUSH bit at the same time*/ if ((DMA_STOP_BIT && stop) != 0) BTIF_ERR_FUNC("BTIF's DMA in stop state, omit flush operation\n"); else { BTIF_DBG_FUNC("flush tx dma\n"); BTIF_SET_BIT(TX_DMA_FLUSH(base), DMA_FLUSH_BIT); i_ret = 0; } return i_ret; }
p_mtk_btif btif_exp_srh_id(unsigned int u_id) { int index = 0; p_mtk_btif p_btif = NULL; struct list_head *p_list = NULL; struct list_head *tmp = NULL; p_mtk_btif_user p_user = NULL; for (index = 0; (index < BTIF_PORT_NR) && (NULL == p_btif); index++) { p_list = &(g_btif[index].user_list); list_for_each(tmp, p_list) { p_user = container_of(tmp, mtk_btif_user, entry); if (u_id == p_user->u_id) { p_btif = p_user->p_btif; BTIF_DBG_FUNC ("BTIF's user id(0x%08x), p_btif(0x%08x)\n", p_user->u_id, p_btif); break; } } }
/***************************************************************************** * FUNCTION * hal_btif_send_data * DESCRIPTION * send data through btif in FIFO mode * PARAMETERS * p_base [IN] BTIF module's base address * p_buf [IN] pointer to rx data buffer * max_len [IN] tx buffer length * RETURNS * positive means number of data sent; 0 means no data put to FIFO; negative means error happens *****************************************************************************/ int hal_btif_send_data(P_MTK_BTIF_INFO_STR p_btif, const unsigned char *p_buf, const unsigned int buf_len) { /*Chaozhong: To be implement*/ int i_ret = -1; unsigned int ava_len = 0; unsigned int sent_len = 0; #if !(NEW_TX_HANDLING_SUPPORT) unsigned int base = p_btif->base; unsigned int lsr = 0; unsigned int left_len = 0; unsigned char *p_data = (unsigned char *)p_buf; #endif /*check parameter valid or not*/ if ((NULL == p_buf) || (buf_len == 0)) { i_ret = ERR_INVALID_PAR; return i_ret; } #if NEW_TX_HANDLING_SUPPORT ava_len = _get_btif_tx_fifo_room(p_btif); sent_len = buf_len <= ava_len ? buf_len : ava_len; if (0 < sent_len) { int enqueue_len = 0; unsigned long flag = 0; spin_lock_irqsave(&(p_btif->tx_fifo_spinlock), flag); enqueue_len = kfifo_in(p_btif->p_tx_fifo, (unsigned char *)p_buf, sent_len); if (sent_len != enqueue_len) { BTIF_ERR_FUNC("target tx len:%d, len sent:%d\n", sent_len, enqueue_len); } i_ret = enqueue_len; dsb(); /*enable BTIF Tx IRQ*/ hal_btif_tx_ier_ctrl(p_btif, true); spin_unlock_irqrestore(&(p_btif->tx_fifo_spinlock), flag); BTIF_DBG_FUNC("enqueue len:%d\n", enqueue_len); } else { i_ret = 0; } #else while ((_btif_is_tx_allow(p_btif)) && (sent_len < buf_len)) { /*read LSR and check THER or TEMT, either one is 1 means can accept tx data*/ lsr = BTIF_READ32(BTIF_LSR(base)); if (lsr & BTIF_LSR_TEMT_BIT) { /*Tx Holding Register if empty, which means we can write tx FIFO count to BTIF*/ ava_len = BTIF_TX_FIFO_SIZE; } else if (lsr & BTIF_LSR_THRE_BIT) { /*Tx Holding Register if empty, which means we can write (Tx FIFO count - Tx threshold)to BTIF*/ ava_len = BTIF_TX_FIFO_SIZE - BTIF_TX_FIFO_THRE; } else { /*this means data size in tx FIFO is more than Tx threshold, we will not write data to THR*/ ava_len = 0; break; } left_len = buf_len - sent_len; /*ava_len will be real length will write to BTIF THR*/ ava_len = ava_len > left_len ? left_len : ava_len; /*update sent length valud after this operation*/ sent_len += ava_len; /*whether we need memory barrier here? Ans: No, no memory ordering issue exist, CPU will make sure logically right */ while (ava_len--) btif_reg_sync_writeb(*(p_data++), BTIF_THR(base)); } /* while ((hal_btif_is_tx_allow()) && (sent_len < buf_len)); */ i_ret = sent_len; /*enable BTIF Tx IRQ*/ hal_btif_tx_ier_ctrl(p_btif, true); #endif return i_ret; }
/***************************************************************************** * FUNCTION * hal_btif_clk_ctrl * DESCRIPTION * control clock output enable/disable of BTIF module * PARAMETERS * p_base [IN] BTIF module's base address * RETURNS * 0 means success, negative means fail *****************************************************************************/ int hal_btif_clk_ctrl(P_MTK_BTIF_INFO_STR p_btif, ENUM_CLOCK_CTRL flag) { /*In MTK BTIF, there's only one global CG on AP_DMA, no sub channel's CG bit*/ /*according to Artis's comment, clock of DMA and BTIF is default off, so we assume it to be off by default*/ int i_ret = 0; unsigned long irq_flag = 0; #if MTK_BTIF_ENABLE_CLK_REF_COUNTER static atomic_t s_clk_ref = ATOMIC_INIT(0); #else static ENUM_CLOCK_CTRL status = CLK_OUT_DISABLE; #endif spin_lock_irqsave(&(g_clk_cg_spinlock), irq_flag); #if MTK_BTIF_ENABLE_CLK_CTL #if MTK_BTIF_ENABLE_CLK_REF_COUNTER if (CLK_OUT_ENABLE == flag) { if (1 == atomic_inc_return(&s_clk_ref)) { i_ret = enable_clock(MTK_BTIF_CG_BIT, BTIF_USER_ID); if (i_ret) { BTIF_WARN_FUNC ("enable_clock for MTK_BTIF_CG_BIT failed, ret:%d", i_ret); } } } else if (CLK_OUT_DISABLE == flag) { if (0 == atomic_dec_return(&s_clk_ref)) { i_ret = disable_clock(MTK_BTIF_CG_BIT, BTIF_USER_ID); if (i_ret) { BTIF_WARN_FUNC ("disable_clock for MTK_BTIF_CG_BIT failed, ret:%d", i_ret); } } } else { i_ret = ERR_INVALID_PAR; BTIF_ERR_FUNC("invalid clock ctrl flag (%d)\n", flag); } #else if (status == flag) { i_ret = 0; BTIF_DBG_FUNC("btif clock already %s\n", CLK_OUT_ENABLE == status ? "enabled" : "disabled"); } else { if (CLK_OUT_ENABLE == flag) { i_ret = enable_clock(MTK_BTIF_CG_BIT, BTIF_USER_ID); status = (0 == i_ret) ? flag : status; if (i_ret) { BTIF_WARN_FUNC ("enable_clock for MTK_BTIF_CG_BIT failed, ret:%d", i_ret); } } else if (CLK_OUT_DISABLE == flag) { i_ret = disable_clock(MTK_BTIF_CG_BIT, BTIF_USER_ID); status = (0 == i_ret) ? flag : status; if (i_ret) { BTIF_WARN_FUNC ("disable_clock for MTK_BTIF_CG_BIT failed, ret:%d", i_ret); } } else { i_ret = ERR_INVALID_PAR; BTIF_ERR_FUNC("invalid clock ctrl flag (%d)\n", flag); } } #endif #else #if MTK_BTIF_ENABLE_CLK_REF_COUNTER #else status = flag; #endif i_ret = 0; #endif spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag); #if MTK_BTIF_ENABLE_CLK_REF_COUNTER if (0 == i_ret) { BTIF_DBG_FUNC("btif clock %s\n", CLK_OUT_ENABLE == flag ? "enabled" : "disabled"); } else { BTIF_ERR_FUNC("%s btif clock failed, ret(%d)\n", CLK_OUT_ENABLE == flag ? "enable" : "disable", i_ret); } #else if (0 == i_ret) { BTIF_DBG_FUNC("btif clock %s\n", CLK_OUT_ENABLE == flag ? "enabled" : "disabled"); } else { BTIF_ERR_FUNC("%s btif clock failed, ret(%d)\n", CLK_OUT_ENABLE == flag ? "enable" : "disable", i_ret); } #endif #if MTK_BTIF_ENABLE_CLK_CTL BTIF_DBG_FUNC("BTIF's clock is %s\n", (0 == clock_is_on(MTK_BTIF_CG_BIT)) ? "off" : "on"); #endif return i_ret; }
/***************************************************************************** * FUNCTION * hal_rx_dma_irq_handler * DESCRIPTION * lower level rx interrupt handler * PARAMETERS * p_dma_info [IN] pointer to BTIF dma channel's information * p_buf [IN/OUT] pointer to rx data buffer * max_len [IN] max length of rx buffer * RETURNS * 0 means success, negative means fail *****************************************************************************/ int hal_rx_dma_irq_handler(P_MTK_DMA_INFO_STR p_dma_info, unsigned char *p_buf, const unsigned int max_len) { int i_ret = -1; unsigned int valid_len = 0; unsigned int wpt_wrap = 0; unsigned int rpt_wrap = 0; unsigned int wpt = 0; unsigned int rpt = 0; unsigned int tail_len = 0; unsigned int real_len = 0; unsigned int base = p_dma_info->base; P_DMA_VFIFO p_vfifo = p_dma_info->p_vfifo; dma_rx_buf_write rx_cb = p_dma_info->rx_cb; unsigned char *p_vff_buf = NULL; unsigned char *vff_base = p_vfifo->p_vir_addr; unsigned int vff_size = p_vfifo->vfifo_size; P_MTK_BTIF_DMA_VFIFO p_mtk_vfifo = container_of(p_vfifo, MTK_BTIF_DMA_VFIFO, vfifo); 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 handle done!!!\n", __FILE__); return i_ret; } /*disable DMA Rx IER*/ hal_btif_dma_ier_ctrl(p_dma_info, false); /*clear Rx DMA's interrupt status*/ BTIF_SET_BIT(RX_DMA_INT_FLAG(base), RX_DMA_INT_DONE | RX_DMA_INT_THRE); valid_len = BTIF_READ32(RX_DMA_VFF_VALID_SIZE(base)); rpt = BTIF_READ32(RX_DMA_VFF_RPT(base)); wpt = BTIF_READ32(RX_DMA_VFF_WPT(base)); if ((0 == valid_len) && (rpt == wpt)) { BTIF_DBG_FUNC ("rx interrupt, no data available in Rx DMA, wpt(0x%08x), rpt(0x%08x)\n", rpt, wpt); } i_ret = 0; while ((0 < valid_len) || (rpt != wpt)) { rpt_wrap = rpt & DMA_RPT_WRAP; wpt_wrap = wpt & DMA_WPT_WRAP; rpt &= DMA_RPT_MASK; wpt &= DMA_WPT_MASK; /*calcaute length of available data in vFIFO*/ if (wpt_wrap != p_mtk_vfifo->last_wpt_wrap) { real_len = wpt + vff_size - rpt; } else { real_len = wpt - rpt; } if (NULL != rx_cb) { tail_len = vff_size - rpt; p_vff_buf = vff_base + rpt; if (tail_len >= real_len) { (*rx_cb) (p_dma_info, p_vff_buf, real_len); } else { (*rx_cb) (p_dma_info, p_vff_buf, tail_len); p_vff_buf = vff_base; (*rx_cb) (p_dma_info, p_vff_buf, real_len - tail_len); } i_ret += real_len; } else { BTIF_ERR_FUNC ("no rx_cb found, please check your init process\n"); } dsb(); rpt += real_len; if (rpt >= vff_size) { /*read wrap bit should be revert*/ rpt_wrap ^= DMA_RPT_WRAP; rpt %= vff_size; } rpt |= rpt_wrap; /*record wpt, last_wpt_wrap, rpt, last_rpt_wrap*/ p_mtk_vfifo->wpt = wpt; p_mtk_vfifo->last_wpt_wrap = wpt_wrap; p_mtk_vfifo->rpt = rpt; p_mtk_vfifo->last_rpt_wrap = rpt_wrap; /*update rpt information to DMA controller*/ btif_reg_sync_writel(rpt, RX_DMA_VFF_RPT(base)); /*get vff valid size again and check if rx data is processed completely*/ valid_len = BTIF_READ32(RX_DMA_VFF_VALID_SIZE(base)); rpt = BTIF_READ32(RX_DMA_VFF_RPT(base)); wpt = BTIF_READ32(RX_DMA_VFF_WPT(base)); } /*enable DMA Rx IER*/ hal_btif_dma_ier_ctrl(p_dma_info, true); spin_unlock_irqrestore(&(g_clk_cg_spinlock), flag); 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; }
/***************************************************************************** * FUNCTION * hal_btif_clk_ctrl * DESCRIPTION * control clock output enable/disable of DMA module * PARAMETERS * p_dma_info [IN] pointer to BTIF dma channel's information * RETURNS * 0 means success, negative means fail *****************************************************************************/ int hal_btif_dma_clk_ctrl(P_MTK_DMA_INFO_STR p_dma_info, ENUM_CLOCK_CTRL flag) { /*In MTK DMA BTIF channel, there's only one global CG on AP_DMA, no sub channel's CG bit*/ /*according to Artis's comment, clock of DMA and BTIF is default off, so we assume it to be off by default*/ int i_ret = 0; unsigned long irq_flag = 0; #if MTK_BTIF_ENABLE_CLK_REF_COUNTER static atomic_t s_clk_ref = ATOMIC_INIT(0); #else static ENUM_CLOCK_CTRL status = CLK_OUT_DISABLE; #endif #if defined(CONFIG_MTK_LEGACY) spin_lock_irqsave(&(g_clk_cg_spinlock), irq_flag); #endif #if MTK_BTIF_ENABLE_CLK_CTL #if MTK_BTIF_ENABLE_CLK_REF_COUNTER if (CLK_OUT_ENABLE == flag) { if (1 == atomic_inc_return(&s_clk_ref)) { #if defined(CONFIG_MTK_LEGACY) i_ret = enable_clock(MTK_BTIF_APDMA_CLK_CG, DMA_USER_ID); if (i_ret) { BTIF_WARN_FUNC ("enable_clock for MTK_BTIF_APDMA_CLK_CG failed, ret:%d", i_ret); } #else clk_prepare(clk_btif_apdma); spin_lock_irqsave(&(g_clk_cg_spinlock), irq_flag); clk_enable(clk_btif_apdma); spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag); BTIF_INFO_FUNC("[CCF]enable clk_btif_apdma\n"); #endif /* defined(CONFIG_MTK_LEGACY) */ } } else if (CLK_OUT_DISABLE == flag) { if (0 == atomic_dec_return(&s_clk_ref)) { #if defined(CONFIG_MTK_LEGACY) i_ret = disable_clock(MTK_BTIF_APDMA_CLK_CG, DMA_USER_ID); if (i_ret) { BTIF_WARN_FUNC ("disable_clock for MTK_BTIF_APDMA_CLK_CG failed, ret:%d", i_ret); } #else spin_lock_irqsave(&(g_clk_cg_spinlock), irq_flag); clk_disable(clk_btif_apdma); spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag); clk_unprepare(clk_btif_apdma); BTIF_INFO_FUNC("[CCF] clk_disable_unprepare(clk_btif_apdma) calling\n"); #endif /* defined(CONFIG_MTK_LEGACY) */ } } else { i_ret = ERR_INVALID_PAR; BTIF_ERR_FUNC("invalid clock ctrl flag (%d)\n", flag); } #else if (status == flag) { i_ret = 0; BTIF_DBG_FUNC("dma clock already %s\n", CLK_OUT_ENABLE == status ? "enabled" : "disabled"); } else { if (CLK_OUT_ENABLE == flag) { #if defined(CONFIG_MTK_LEGACY) i_ret = enable_clock(MTK_BTIF_APDMA_CLK_CG, DMA_USER_ID); status = (0 == i_ret) ? flag : status; if (i_ret) { BTIF_WARN_FUNC ("enable_clock for MTK_BTIF_APDMA_CLK_CG failed, ret:%d", i_ret); } #else clk_prepare(clk_btif_apdma); spin_lock_irqsave(&(g_clk_cg_spinlock), irq_flag); clk_enable(clk_btif_apdma); spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag); BTIF_INFO_FUNC("[CCF]enable clk_btif_apdma\n"); #endif /* defined(CONFIG_MTK_LEGACY) */ } else if (CLK_OUT_DISABLE == flag) { #if defined(CONFIG_MTK_LEGACY) i_ret = disable_clock(MTK_BTIF_APDMA_CLK_CG, DMA_USER_ID); status = (0 == i_ret) ? flag : status; if (i_ret) { BTIF_WARN_FUNC ("disable_clock for MTK_BTIF_APDMA_CLK_CG failed, ret:%d", i_ret); } #else spin_lock_irqsave(&(g_clk_cg_spinlock), irq_flag); clk_disable(clk_btif_apdma); spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag); clk_unprepare(clk_btif_apdma); BTIF_INFO_FUNC("[CCF] clk_disable_unprepare(clk_btif_apdma) calling\n"); #endif /* defined(CONFIG_MTK_LEGACY) */ } else { i_ret = ERR_INVALID_PAR; BTIF_ERR_FUNC("invalid clock ctrl flag (%d)\n", flag); } } #endif #else #if MTK_BTIF_ENABLE_CLK_REF_COUNTER #else status = flag; #endif i_ret = 0; #endif #if defined(CONFIG_MTK_LEGACY) spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag); #endif #if MTK_BTIF_ENABLE_CLK_REF_COUNTER if (0 == i_ret) { BTIF_DBG_FUNC("dma clock %s\n", CLK_OUT_ENABLE == flag ? "enabled" : "disabled"); } else { BTIF_ERR_FUNC("%s dma clock failed, ret(%d)\n", CLK_OUT_ENABLE == flag ? "enable" : "disable", i_ret); } #else if (0 == i_ret) { BTIF_DBG_FUNC("dma clock %s\n", CLK_OUT_ENABLE == flag ? "enabled" : "disabled"); } else { BTIF_ERR_FUNC("%s dma clock failed, ret(%d)\n", CLK_OUT_ENABLE == flag ? "enable" : "disable", i_ret); } #endif #if defined(CONFIG_MTK_LEGACY) BTIF_DBG_FUNC("DMA's clock is %s\n", (0 == clock_is_on(MTK_BTIF_APDMA_CLK_CG)) ? "off" : "on"); #endif return i_ret; }