/******************************************************************************
 *
 * Copyright(c) 2019 Realtek Corporation.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of version 2 of the GNU General Public License as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 *****************************************************************************/
#define _HAL_TRX_8852BE_C_
#include "../../hal_headers.h"
#include "../rtl8852b_hal.h"
#include "hal_trx_8852be.h"

/**
 * this function will query total hw tx dma channels number
 *
 * returns the number of hw tx dma channel
 */
static u8 hal_query_txch_num_8852be(void)
{
	u8 ch_num = 0;

	ch_num = TX_DMA_CHANNEL_ENTRY_8852BE;

	return ch_num;
}

/**
 * this function will query total hw rx dma channels number
 *
 * returns the number of hw rx dma channel
 */
static u8 hal_query_rxch_num_8852be(void)
{
	u8 ch_num = 0;

	ch_num = RX_DMA_CHANNEL_ENTRY_8852BE;

	return ch_num;
}
static u8 hal_qsel_to_tid_8852be(struct hal_info_t *hal, u8 qsel_id, u8 tid_indic)
{
	u8 tid = 0;

	switch (qsel_id) {
		case RTW_TXDESC_QSEL_BE_0:
		case RTW_TXDESC_QSEL_BE_1:
		case RTW_TXDESC_QSEL_BE_2:
		case RTW_TXDESC_QSEL_BE_3:
			tid = (1 == tid_indic) ? RTW_PHL_RING_CAT_TID3 : RTW_PHL_RING_CAT_TID0;
			break;
		case RTW_TXDESC_QSEL_BK_0:
		case RTW_TXDESC_QSEL_BK_1:
		case RTW_TXDESC_QSEL_BK_2:
		case RTW_TXDESC_QSEL_BK_3:
			tid = (1 == tid_indic) ? RTW_PHL_RING_CAT_TID2 : RTW_PHL_RING_CAT_TID1;
			break;
		case RTW_TXDESC_QSEL_VI_0:
		case RTW_TXDESC_QSEL_VI_1:
		case RTW_TXDESC_QSEL_VI_2:
		case RTW_TXDESC_QSEL_VI_3:
			tid = (1 == tid_indic) ? RTW_PHL_RING_CAT_TID5 : RTW_PHL_RING_CAT_TID4;
			break;
		case RTW_TXDESC_QSEL_VO_0:
		case RTW_TXDESC_QSEL_VO_1:
		case RTW_TXDESC_QSEL_VO_2:
		case RTW_TXDESC_QSEL_VO_3:
			tid = (1 == tid_indic) ? RTW_PHL_RING_CAT_TID7 : RTW_PHL_RING_CAT_TID6;
			break;
		case RTW_TXDESC_QSEL_MGT_0:
		case RTW_TXDESC_QSEL_MGT_1:
			tid = RTW_PHL_RING_CAT_MGNT;
			break;
		case RTW_TXDESC_QSEL_HIGH_0:
		case RTW_TXDESC_QSEL_HIGH_1:
			tid = RTW_PHL_RING_CAT_HIQ;
 			break;
		default :
			PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_, "[WARNING]unknown qsel_id (%d)\n",
					qsel_id);
			tid = 0;
			break;
	}

	return tid;
}

/**
 * Get target DMA channel's BD ram hw register of rtl8852b
 * @dma_ch: input target dma channel with the hw definition of rtl8852BE
 * return the BD ram hw register
 */
static u32 _hal_get_bd_ram_reg_8852be(u8 dma_ch)
{
	u32 reg = 0;

	switch (dma_ch) {
	case ACH0_QUEUE_IDX_8852BE:
		reg = R_AX_ACH0_BDRAM_CTRL;
		break;
	case ACH1_QUEUE_IDX_8852BE:
		reg = R_AX_ACH1_BDRAM_CTRL;
		break;
	case ACH2_QUEUE_IDX_8852BE:
		reg = R_AX_ACH2_BDRAM_CTRL;
		break;
	case ACH3_QUEUE_IDX_8852BE:
		reg = R_AX_ACH3_BDRAM_CTRL;
		break;
	case ACH4_QUEUE_IDX_8852BE:
		reg = R_AX_ACH4_BDRAM_CTRL;
		break;
	case ACH5_QUEUE_IDX_8852BE:
		reg = R_AX_ACH5_BDRAM_CTRL;
		break;
	case ACH6_QUEUE_IDX_8852BE:
		reg = R_AX_ACH6_BDRAM_CTRL;
		break;
	case ACH7_QUEUE_IDX_8852BE:
		reg = R_AX_ACH7_BDRAM_CTRL;
		break;
	case MGQ_B0_QUEUE_IDX_8852BE:
		reg = R_AX_CH8_BDRAM_CTRL;
		break;
	case HIQ_B0_QUEUE_IDX_8852BE:
		reg = R_AX_CH9_BDRAM_CTRL;
		break;
	case MGQ_B1_QUEUE_IDX_8852BE:
		reg = R_AX_CH10_BDRAM_CTRL;
		break;
	case HIQ_B1_QUEUE_IDX_8852BE:
		reg = R_AX_CH11_BDRAM_CTRL;
		break;
	case FWCMD_QUEUE_IDX_8852BE:
		reg = R_AX_CH12_BDRAM_CTRL;
		break;
	default :
		PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_, "[WARNING]unknown channel (%d)\n",
				dma_ch);
		reg = 0xFFFF;
		break;
	}

	return reg;
}



/**
 * Get target DMA channel's BD num hw register of rtl8852b
 * @dma_ch: input target dma channel with the hw definition of rtl8852BE
 * return the BD num hw register
 */
static u32 _hal_get_bd_num_reg_8852be(u8 dma_ch)
{
	u32 reg = 0;

	switch (dma_ch) {
	case ACH0_QUEUE_IDX_8852BE:
		reg = R_AX_ACH0_TXBD_NUM;
		break;
	case ACH1_QUEUE_IDX_8852BE:
		reg = R_AX_ACH1_TXBD_NUM;
		break;
	case ACH2_QUEUE_IDX_8852BE:
		reg = R_AX_ACH2_TXBD_NUM;
		break;
	case ACH3_QUEUE_IDX_8852BE:
		reg = R_AX_ACH3_TXBD_NUM;
		break;
	case ACH4_QUEUE_IDX_8852BE:
		reg = R_AX_ACH4_TXBD_NUM;
		break;
	case ACH5_QUEUE_IDX_8852BE:
		reg = R_AX_ACH5_TXBD_NUM;
		break;
	case ACH6_QUEUE_IDX_8852BE:
		reg = R_AX_ACH6_TXBD_NUM;
		break;
	case ACH7_QUEUE_IDX_8852BE:
		reg = R_AX_ACH7_TXBD_NUM;
		break;
	case MGQ_B0_QUEUE_IDX_8852BE:
		reg = R_AX_CH8_TXBD_NUM;
		break;
	case HIQ_B0_QUEUE_IDX_8852BE:
		reg = R_AX_CH9_TXBD_NUM;
		break;
	case MGQ_B1_QUEUE_IDX_8852BE:
		reg = R_AX_CH10_TXBD_NUM;
		break;
	case HIQ_B1_QUEUE_IDX_8852BE:
		reg = R_AX_CH11_TXBD_NUM;
		break;
	case FWCMD_QUEUE_IDX_8852BE:
		reg = R_AX_CH12_TXBD_NUM;
		break;
	case RX_QUEUE_IDX_8852BE:
		reg = R_AX_RXQ_RXBD_NUM;
		break;
	case RP_QUEUE_IDX_8852BE:
		reg = R_AX_RPQ_RXBD_NUM;
		break;
	default :
		PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_, "[WARNING]unknown channel (%d)\n",
				dma_ch);
		reg = 0xFFFF;
		break;
	}

	return reg;
}


/**
 * Get target DMA channel's BD Desc hw register of rtl8852b
 * @dma_ch: input target dma channel with the hw definition of rtl8852BE
 * return the BD Desc hw register
 */
static void _hal_get_bd_desc_reg_8852be(u8 dma_ch, u32 *addr_l, u32 *addr_h)
{
	u32 reg = 0;

	switch (dma_ch) {
	case ACH0_QUEUE_IDX_8852BE:
		*addr_l = R_AX_ACH0_TXBD_DESA_L;
		*addr_h = R_AX_ACH0_TXBD_DESA_H;
		break;
	case ACH1_QUEUE_IDX_8852BE:
		*addr_l = R_AX_ACH1_TXBD_DESA_L;
		*addr_h = R_AX_ACH1_TXBD_DESA_H;
		break;
	case ACH2_QUEUE_IDX_8852BE:
		*addr_l = R_AX_ACH2_TXBD_DESA_L;
		*addr_h = R_AX_ACH2_TXBD_DESA_H;
		break;
	case ACH3_QUEUE_IDX_8852BE:
		*addr_l = R_AX_ACH3_TXBD_DESA_L;
		*addr_h = R_AX_ACH3_TXBD_DESA_H;
		break;
	case ACH4_QUEUE_IDX_8852BE:
		*addr_l = R_AX_ACH4_TXBD_DESA_L;
		*addr_h = R_AX_ACH4_TXBD_DESA_H;
		break;
	case ACH5_QUEUE_IDX_8852BE:
		*addr_l = R_AX_ACH5_TXBD_DESA_L;
		*addr_h = R_AX_ACH5_TXBD_DESA_H;
		break;
	case ACH6_QUEUE_IDX_8852BE:
		*addr_l = R_AX_ACH6_TXBD_DESA_L;
		*addr_h = R_AX_ACH6_TXBD_DESA_H;
		break;
	case ACH7_QUEUE_IDX_8852BE:
		*addr_l = R_AX_ACH7_TXBD_DESA_L;
		*addr_h = R_AX_ACH7_TXBD_DESA_H;
		break;
	case MGQ_B0_QUEUE_IDX_8852BE:
		*addr_l = R_AX_CH8_TXBD_DESA_L;
		*addr_h = R_AX_CH8_TXBD_DESA_H;
		break;
	case HIQ_B0_QUEUE_IDX_8852BE:
		*addr_l = R_AX_CH9_TXBD_DESA_L;
		*addr_h = R_AX_CH9_TXBD_DESA_H;
		break;
	case MGQ_B1_QUEUE_IDX_8852BE:
		*addr_l = R_AX_CH10_TXBD_DESA_L;
		*addr_h = R_AX_CH10_TXBD_DESA_H;
		break;
	case HIQ_B1_QUEUE_IDX_8852BE:
		*addr_l = R_AX_CH11_TXBD_DESA_L;
		*addr_h = R_AX_CH11_TXBD_DESA_H;
		break;
	case FWCMD_QUEUE_IDX_8852BE:
		*addr_l = R_AX_CH12_TXBD_DESA_L;
		*addr_h = R_AX_CH12_TXBD_DESA_H;
		break;
	case RX_QUEUE_IDX_8852BE:
		*addr_l = R_AX_RXQ_RXBD_DESA_L;
		*addr_h = R_AX_RXQ_RXBD_DESA_H;
		break;
	case RP_QUEUE_IDX_8852BE:
		*addr_l = R_AX_RPQ_RXBD_DESA_L;
		*addr_h = R_AX_RPQ_RXBD_DESA_H;
		break;
	default :
		PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_, "[WARNING]unknown channel (%d)\n",
				dma_ch);
		reg = 0xFFFF;
		break;
	}

}



/**
 * Get target DMA channel's BD Index hw register of rtl8852b
 * @dma_ch: input target dma channel with the hw definition of rtl8852BE
 * return the BD Index hw register
 */
static u32 _hal_get_bd_idx_reg_8852be(u8 dma_ch)
{
	u32 reg = 0;

	switch (dma_ch) {
	case ACH0_QUEUE_IDX_8852BE:
		reg = R_AX_ACH0_TXBD_IDX;
		break;
	case ACH1_QUEUE_IDX_8852BE:
		reg = R_AX_ACH1_TXBD_IDX;
		break;
	case ACH2_QUEUE_IDX_8852BE:
		reg = R_AX_ACH2_TXBD_IDX;
		break;
	case ACH3_QUEUE_IDX_8852BE:
		reg = R_AX_ACH3_TXBD_IDX;
		break;
	case ACH4_QUEUE_IDX_8852BE:
		reg = R_AX_ACH4_TXBD_IDX;
		break;
	case ACH5_QUEUE_IDX_8852BE:
		reg = R_AX_ACH5_TXBD_IDX;
		break;
	case ACH6_QUEUE_IDX_8852BE:
		reg = R_AX_ACH6_TXBD_IDX;
		break;
	case ACH7_QUEUE_IDX_8852BE:
		reg = R_AX_ACH7_TXBD_IDX;
		break;
	case MGQ_B0_QUEUE_IDX_8852BE:
		reg = R_AX_CH8_TXBD_IDX;
		break;
	case HIQ_B0_QUEUE_IDX_8852BE:
		reg = R_AX_CH9_TXBD_IDX;
		break;
	case MGQ_B1_QUEUE_IDX_8852BE:
		reg = R_AX_CH10_TXBD_IDX;
		break;
	case HIQ_B1_QUEUE_IDX_8852BE:
		reg = R_AX_CH11_TXBD_IDX;
		break;
	case FWCMD_QUEUE_IDX_8852BE:
		reg = R_AX_CH12_TXBD_IDX;
		break;
	case RX_QUEUE_IDX_8852BE:
		reg = R_AX_RXQ_RXBD_IDX;
		break;
	case RP_QUEUE_IDX_8852BE:
		reg = R_AX_RPQ_RXBD_IDX;
		break;
	default :
		PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_, "[WARNING]unknown channel (%d)\n",
				dma_ch);
		reg = 0xFFFF;
		break;
	}

	return reg;
}


/**
 * this function maps the sw xmit ring identified by macid, tid and band
 * to rtl8852BE hw tx dma channel
 * @macid: input target macid range is 0 ~ 127
 * @cat: input target packet category, see enum rtw_phl_ring_cat
 * @band: input target band, 0 for band 0 / 1 for band 1
 *
 * returns the mapping hw dma channel defined by XXX_QUEUE_IDX_8852BE
 * if the input parameter is unknown value, returns ACH0_QUEUE_IDX_8852BE
 */
static u8 hal_mapping_hw_tx_chnl_8852be(u16 macid, enum rtw_phl_ring_cat cat,
					u8 band)
{
	u8 dma_ch = 0;

	/* hana_todo, decided by tid only currently,
		we should consider more situation later */

	if (0 == band) {
		switch (cat) {
		case RTW_PHL_RING_CAT_TID0:
		case RTW_PHL_RING_CAT_TID3:
			dma_ch = ACH0_QUEUE_IDX_8852BE;
			break;
		case RTW_PHL_RING_CAT_TID1:
		case RTW_PHL_RING_CAT_TID2:
			dma_ch = ACH1_QUEUE_IDX_8852BE;
			break;
		case RTW_PHL_RING_CAT_TID4:
		case RTW_PHL_RING_CAT_TID5:
			dma_ch = ACH2_QUEUE_IDX_8852BE;
			break;
		case RTW_PHL_RING_CAT_TID6:
		case RTW_PHL_RING_CAT_TID7:
			dma_ch = ACH3_QUEUE_IDX_8852BE;
			break;
		case RTW_PHL_RING_CAT_MGNT:
			dma_ch = MGQ_B0_QUEUE_IDX_8852BE;
			break;
		case RTW_PHL_RING_CAT_HIQ:
			dma_ch = HIQ_B0_QUEUE_IDX_8852BE;
			break;
		default:
			dma_ch = ACH0_QUEUE_IDX_8852BE;
			PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_, "[WARNING]unknown category (%d)\n",
					cat);
			break;
		}
	} else {
		dma_ch = ACH0_QUEUE_IDX_8852BE;
		PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_, "[WARNING]unknown band (%d)\n",
				band);
	}

	return dma_ch;
}


/**
 * this function will return available txbd number of target dma channel
 * @ch_idx: input, target dma channel index
 * @host_idx: the ptr of current host index of this channel
 * @hw_idx: the ptr of current hw index of this channel
 *
 * NOTE, input host_idx and hw_idx ptr shall NOT be NULL
 */
static u16 hal_get_avail_txbd_8852be(struct rtw_hal_com_t *hal_com, u8 ch_idx,
				     u16 *host_idx, u16 *hw_idx)
{
	struct bus_cap_t *bus_cap = &hal_com->bus_cap;
	u16 avail_txbd = 0;
	u32 tmp32 = 0, reg = 0;
	u8 tx_dma_ch = 0;

	tx_dma_ch = ACH0_QUEUE_IDX_8852BE + ch_idx;

	reg = _hal_get_bd_idx_reg_8852be(tx_dma_ch);
	if (0xFFFF == reg) {
		PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
			"[WARNING]get dma channel register fail\n");
		avail_txbd = 0;
	} else {
		tmp32 = hal_read32(hal_com, reg);

		*host_idx = (u16)(tmp32 & 0x0FFF);
		*hw_idx = (u16)((tmp32 >> 16) & 0x0FFF);

		avail_txbd = hal_calc_avail_wptr(*hw_idx, *host_idx,
						 (u16)bus_cap->txbd_num);
		PHL_TRACE(COMP_PHL_XMIT, _PHL_DEBUG_,
			  "hal_get_avail_txbd_8852be => dma_ch %d, host_idx %d, "
			  "hw_idx %d, avail_txbd %d\n",
			  ch_idx, *host_idx, *hw_idx, avail_txbd);
	}

	return avail_txbd;
}

/**
 * this function will return available txbd number of target dma channel
 * @ch_idx: input, target dma channel index
 * @host_idx: the ptr of current host index of this channel
 * @hw_idx: the ptr of current hw index of this channel
 *
 * NOTE, input host_idx and hw_idx ptr shall NOT be NULL
 */
static u16 hal_get_avail_rxbd_8852be(struct rtw_hal_com_t *hal_com, u8 ch_idx,
				     u16 *host_idx, u16 *hw_idx)
{
 	struct bus_cap_t *bus_cap = &hal_com->bus_cap;
	u16 avail_rxbd = 0;
	u32 tmp32 = 0, reg = 0;
	u8 rx_dma_ch = 0;

	rx_dma_ch = RX_QUEUE_IDX_8852BE + ch_idx;

	reg = _hal_get_bd_idx_reg_8852be(rx_dma_ch);
	if (0xFFFF == reg) {
		PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_, "[WARNING]get dma channel register fail\n");
		avail_rxbd = 0;
	} else {
		tmp32 = hal_read32(hal_com, reg);

		*host_idx = (u16)(tmp32 & 0x0FFF);
		*hw_idx = (u16)((tmp32 >> 16) & 0x0FFF);

		avail_rxbd = hal_calc_avail_rptr(*host_idx, *hw_idx,
						 (u16)bus_cap->rxbd_num);
	}

	return avail_rxbd;
}


void _hal_fill_wp_seq_field_8852be(u8 *seq_info, u16 wp_seq)
{
	/* update sw wp seq */
	SET_PCIE_SEQ_INFO_0(seq_info, wp_seq);
	SET_PCIE_SEQ_INFO_0_VALID(seq_info, 1);
}

void _hal_fill_wp_addr_info_8852be(struct rtw_hal_com_t *hal_com,
				   u8 *addr_info, struct rtw_pkt_buf_list *pkt,
					u8 num, u8 mpdu_ls, u8 msdu_ls)
{
	SET_ADDR_INFO_LEN(addr_info, pkt->length);
	SET_ADDR_INFO_NUM(addr_info, num);
	SET_ADDR_INFO_MSDU_LS(addr_info, msdu_ls);
	SET_ADDR_INFO_ADDR_LOW(addr_info, pkt->phy_addr_l);
	SET_ADDR_INFO_ADDR_HIGH(addr_info, pkt->phy_addr_h);
}

u8 _hal_get_tid_indic_8852be(u8 tid)
{
	u8 tid_indic = 0;
	switch (tid) {
		case RTW_PHL_RING_CAT_TID0:
		case RTW_PHL_RING_CAT_TID1:
		case RTW_PHL_RING_CAT_TID4:
		case RTW_PHL_RING_CAT_TID6:
		case RTW_PHL_RING_CAT_MGNT:
		case RTW_PHL_RING_CAT_HIQ:
			tid_indic = 0;
			break;
		case RTW_PHL_RING_CAT_TID3:
		case RTW_PHL_RING_CAT_TID2:
		case RTW_PHL_RING_CAT_TID5:
		case RTW_PHL_RING_CAT_TID7:
			tid_indic = 1;
			break;
		default:
			PHL_ERR("unknown tid %d\n", tid);
			break;
	}

	return tid_indic;
}

#ifdef CONFIG_PHL_TXSC
static u8 qsel_tbl[] = {
	TID_0_QSEL/*0*/, TID_1_QSEL/*1*/, TID_2_QSEL/*1*/, TID_3_QSEL/*0*/,
	TID_4_QSEL/*2*/, TID_5_QSEL/*2*/, TID_6_QSEL/*3*/, TID_7_QSEL/*2*/
};

static u8 tid_ind[] = {
	TID_0_IND, TID_1_IND, TID_2_IND, TID_3_IND,
	TID_4_IND, TID_5_IND, TID_6_IND, TID_7_IND
};

static enum rtw_hal_status
_hal_txsc_update_wd(struct hal_info_t *hal,
						struct rtw_phl_pkt_req *req, u32 *wd_len)
{
	struct rtw_xmit_req *tx_req = req ? req->tx_req : NULL;
	struct rtw_t_meta_data	*mdata;
	u32 *wd_words;
	u32 w0, w2, w3;

	if (NULL == tx_req)
		return RTW_HAL_STATUS_FAILURE;

	if (req->wd_len == 0) {
		rtw_hal_mac_ax_fill_txdesc(hal->mac, tx_req, req->wd_page,
								   wd_len);
		req->wd_len = (u8)*wd_len;
	} else {
		mdata = &tx_req->mdata;
		mdata->dma_ch = hal_mapping_hw_tx_chnl_8852be(mdata->macid, mdata->tid, mdata->band);

		wd_words = (u32 *)req->wd_page;
		w0 = le32_to_cpu(wd_words[0])
				 & ~((AX_TXD_HW_SSN_SEL_MSK << AX_TXD_HW_SSN_SEL_SH)
					 | (AX_TXD_CH_DMA_MSK << AX_TXD_CH_DMA_SH));
		w2 = le32_to_cpu(wd_words[2])
				 & ~(AX_TXD_TID_IND
					 | (AX_TXD_QSEL_MSK << AX_TXD_QSEL_SH)
					 | (AX_TXD_TXPKTSIZE_MSK << AX_TXD_TXPKTSIZE_SH));

		/* Update SSN SEL, DMA CH, QSEL, and TID indicator in WD cache */
		w0 |= (((mdata->hw_ssn_sel & AX_TXD_HW_SSN_SEL_MSK) << AX_TXD_HW_SSN_SEL_SH)
			   | ((mdata->dma_ch & AX_TXD_CH_DMA_MSK) << AX_TXD_CH_DMA_SH));
		wd_words[0] = cpu_to_le32(w0);

		if (mdata->hw_seq_mode == 0) {
			w3 = cpu_to_le32((mdata->sw_seq & 0xFFF) |
				(mdata->ampdu_en ? BIT(12) : 0) |
				((mdata->bk || mdata->ack_ch_info) ? BIT(13) : 0));
			wd_words[3] = w3;
		}

		if (tid_ind[mdata->tid])
			w2 |= AX_TXD_TID_IND;

		w2 |= (qsel_tbl[mdata->tid] & AX_TXD_QSEL_MSK) << AX_TXD_QSEL_SH;
		w2 |= (mdata->pktlen & AX_TXD_TXPKTSIZE_MSK) << AX_TXD_TXPKTSIZE_SH;
		wd_words[2] = cpu_to_le32(w2);

		*wd_len = req->wd_len;
	}

	return RTW_HAL_STATUS_SUCCESS;
}
#endif

/**
 * the function update wd page, including wd info, wd body, seq info, addr info
 * @hal: see struct hal_info_t
 * @phl_pkt_req: see struct rtw_phl_pkt_req
 */
static enum rtw_hal_status
hal_update_wd_8852be(struct hal_info_t *hal,
                     struct rtw_phl_pkt_req *req)
{
	enum rtw_hal_status hstatus = RTW_HAL_STATUS_SUCCESS;
	struct rtw_hal_com_t *hal_com = hal->hal_com;
	struct bus_hw_cap_t *bus_hw_cap = &hal_com->bus_hw_cap;
	struct rtw_xmit_req *tx_req = NULL;
	struct rtw_pkt_buf_list *pkt_list = NULL;
	u32 wd_len = 0, seq_ofst = 0, addr_info_ofst = 0;
	u16 wp_seq = 0;
	u8 i = 0, wp_num = 0, mpdu_ls = 0, msdu_ls = 0, tid_indic = 0;
	FUNCIN_WSTS(hstatus);
	do {
		if (NULL == req)
			break;

		tx_req = req->tx_req;
		pkt_list = (struct rtw_pkt_buf_list *)tx_req->pkt_list;

#ifdef CONFIG_PHL_TXSC
		_hal_txsc_update_wd(hal, req, &wd_len);
#else
		/* connect with halmac */
		rtw_hal_mac_ax_fill_txdesc(hal->mac, tx_req, req->wd_page,
						&wd_len);
#endif
		tid_indic = _hal_get_tid_indic_8852be(tx_req->mdata.tid);

		seq_ofst = wd_len;
		wp_seq = (1 == tid_indic) ?
				(req->wp_seq | WP_TID_INDIC_RESERVED_BIT) : req->wp_seq;
		_hal_fill_wp_seq_field_8852be(req->wd_page + seq_ofst, wp_seq);

		addr_info_ofst = seq_ofst + bus_hw_cap->seq_info_size;
		for (i = 0; i < tx_req->mdata.addr_info_num; i++) {
			if (0 == i)
				wp_num = tx_req->mdata.addr_info_num;
			else
				wp_num = 0;

			if ((tx_req->mdata.addr_info_num - 1) == i)
				msdu_ls = 1;
			else
				msdu_ls = 0;

			_hal_fill_wp_addr_info_8852be(hal_com,
				req->wd_page + addr_info_ofst,
				&pkt_list[i], wp_num, mpdu_ls, msdu_ls);

			addr_info_ofst += bus_hw_cap->addr_info_size;

			//debug_dump_data(pkt_list[i].vir_addr, pkt_list[i].length, "dump wp");
		}

		/* 8852BE length in txbd(wd_len) should be fix to 128 */
		if (addr_info_ofst != bus_hw_cap->max_wd_page_size)
    			req->wd_len = bus_hw_cap->max_wd_page_size;

	} while (false);

	#if 0 /* remove this for saving cpu cycle */
	if (RTW_HAL_STATUS_SUCCESS == hstatus) {
		debug_dump_data(req->wd_page, (u16)addr_info_ofst, "dump wd page");
	}
	#endif
	FUNCOUT_WSTS(hstatus);
	return hstatus;
}

/**
 * the function update txbd
 * @hal: see struct hal_info_t
 * @txbd_ring: the target txbd ring buffer going to update, see struct tx_base_desc
 * @wd: the wd page going to be filled in txbd, see struct rtw_wd_page
 */
static enum rtw_hal_status
hal_update_txbd_8852be(struct hal_info_t *hal,
			struct tx_base_desc *txbd_ring,
			struct rtw_wd_page *wd_page,
		       u8 ch_idx, u16 wd_num)
{
	enum rtw_hal_status hstatus = RTW_HAL_STATUS_SUCCESS;
	struct rtw_hal_com_t *hal_com = hal->hal_com;
	struct bus_hw_cap_t *bus_hw_cap = &hal_com->bus_hw_cap;
	u8 *ring_head = 0;
	u8 *target_txbd = 0;
	u16 host_idx = 0, txbd_host_idx = 0, hw_idx = 0;
	u16 avail_txbd = 0, wcnt = 0;
	u16 txbd_num = (u16)hal_com->bus_cap.txbd_num;

	do {
		if (NULL == wd_page)
			break;
		if (NULL == txbd_ring)
			break;

		/* connect with halmac */
		host_idx = txbd_ring[ch_idx].host_idx;
		avail_txbd = hal_get_avail_txbd_8852be(hal->hal_com, ch_idx,
							&txbd_host_idx, &hw_idx);

		wcnt = (wd_num > avail_txbd) ? avail_txbd : wd_num;

		PHL_TRACE(COMP_PHL_XMIT, _PHL_DEBUG_,
			  "hal_update_txbd_8852be => ch_idx %d, host_idx %d, "
			  "hw_idx %d, avail_txbd %d, wcnt %d\n",
			  ch_idx, txbd_host_idx, hw_idx, avail_txbd, wcnt);

		while (wcnt > 0) {

			ring_head = txbd_ring[ch_idx].vir_addr;
			target_txbd = ring_head + (host_idx *
						   bus_hw_cap->txbd_len);

			SET_TXBUFFER_DESC_LEN(target_txbd, wd_page->buf_len);
			SET_TXBUFFER_DESC_LS(target_txbd, wd_page->ls);
			SET_TXBUFFER_DESC_ADD_LOW(target_txbd,
							wd_page->phy_addr_l);
			SET_TXBUFFER_DESC_ADD_HIGH(target_txbd,
							wd_page->phy_addr_h);
			host_idx = (host_idx + 1) % txbd_num;
			wd_page->host_idx = host_idx;
			wcnt--;

			//multi wd page in one update txbd
			#if 0//S_TODO
			if(wcnt > 0){
				wd_page = list_first_entry(wd_page->list,
								struct rtw_wd_page,
								wd_page->list);
				if(NULL == wd_page)
					break;
			}
			#endif
		}

		txbd_ring[ch_idx].host_idx = host_idx;
	} while (false);

	return hstatus;
}

/**
 * the function trigger tx start
 * @hal: see struct hal_info_t
 * @txbd_ring: the target txbd ring buffer going to update, see struct tx_base_desc
 * @ch_idx: the dma channel index of this txbd_ring
 */
static enum rtw_hal_status
hal_trigger_txdma_8852be(struct hal_info_t *hal,
			struct tx_base_desc *txbd_ring, u8 ch_idx)
{
	enum rtw_hal_status hstatus = RTW_HAL_STATUS_FAILURE;
	u8 tx_dma_ch;
	u32 txbd_reg;

	do {
		/* connect with halmac */
		tx_dma_ch = ACH0_QUEUE_IDX_8852BE + ch_idx;
		txbd_reg = _hal_get_bd_idx_reg_8852be(tx_dma_ch);
		if (0xFFFF == txbd_reg)
			break;
		PHL_TRACE(COMP_PHL_XMIT, _PHL_DEBUG_,
			  "hal_trigger_txdma_8852be => dma_ch %d, host_idx %d.\n",
			  ch_idx, txbd_ring[ch_idx].host_idx);
		hal_write16(hal->hal_com, txbd_reg, txbd_ring[ch_idx].host_idx);
		#ifdef CONFIG_DBG_H2C_TX
		if (tx_dma_ch == FWCMD_QUEUE_IDX_8852BE)
			PHL_INFO("%s: 0x%x -> 0x%x\n", __func__,
					_hal_get_bd_idx_reg_8852be(FWCMD_QUEUE_IDX_8852BE),
					hal_read32(hal->hal_com, _hal_get_bd_idx_reg_8852be(FWCMD_QUEUE_IDX_8852BE)));
		#endif /* CONFIG_DBG_H2C_TX */
		hstatus = RTW_HAL_STATUS_SUCCESS;
	} while (false);

	return hstatus;
}


static enum rtw_hal_status hal_pltfm_tx_8852be(void *hal, struct rtw_h2c_pkt *h2c_pkt)
{
	enum rtw_hal_status hstatus = RTW_HAL_STATUS_SUCCESS;
#if 0

	struct hal_info_t *hal_info = (struct hal_info_t *)hal;
	struct rtw_wd_page wd_page;
	struct tx_base_desc *txbd_ring = NULL;

	_os_mem_set(hal_to_drvpriv(hal_info), &wd_page, 0, sizeof(wd_page));

	txbd_ring = (struct tx_base_desc *)hal_info->hal_com->fw_txbd;
	wd_page.vir_addr = h2c_pkt->vir_addr;
	wd_page.phy_addr_l = h2c_pkt->phy_addr_l;
	wd_page.phy_addr_h= h2c_pkt->phy_addr_h;
	wd_page.buf_len = h2c_pkt->buf_len;
	wd_page.cache = 1;

	_os_spinlock(hal_to_drvpriv(hal_info), &txbd_ring[FWCMD_QUEUE_IDX_8852BE].txbd_lock, _ps, NULL);
	hstatus = hal_update_txbd_8852BE(hal_info, txbd_ring, &wd_page,
							FWCMD_QUEUE_IDX_8852BE, 1);
	_os_spinunlock(hal_to_drvpriv(hal_info), &txbd_ring[FWCMD_QUEUE_IDX_8852BE].txbd_lock, _ps, NULL);

	/* enqueue busy queue */

	hstatus = hal_trigger_txdma_8852BE(hal_info, txbd_ring, FWCMD_QUEUE_IDX_8852BE);
#endif
	return hstatus;
}

u8 hal_get_fwcmd_queue_idx_8852be(void)
{
	return FWCMD_QUEUE_IDX_8852BE;
}

static u8 hal_check_rxrdy_8852be(struct rtw_phl_com_t *phl_com, u8 *rxbd_info,
				 u8 ch_idx)
{
	struct hal_spec_t *hal_spec = &phl_com->hal_spec;
	u8 res = false;
	u16 tag = 0, target_tag = 0;
	u16 read_cnt = 0;

	do {
		if (rxbd_info == NULL) {
			PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
					"[WARNING] input rx bd info is NULL!\n");
			res = false;
			break;
		}

		tag = (u16)GET_RX_BD_INFO_TAG(rxbd_info);

		if (hal_spec->rx_tag[ch_idx] == 0x1fff ||
			hal_spec->rx_tag[ch_idx] == 0)
			target_tag = 1;
		else
			target_tag = hal_spec->rx_tag[ch_idx] + 1;

		while (read_cnt < 10000) {

			read_cnt++;

			tag = (u16)GET_RX_BD_INFO_TAG(rxbd_info);

			if (tag == target_tag) {
				res = true;
				break;
			}
		}

		if (true == res) {
			hal_spec->rx_tag[ch_idx] = tag;
		} else {
			PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_, "[WARNING] polling Rx Tag fail, tag = %d, target_tag = %d\n",
					tag, target_tag);
#ifdef RTW_WKARD_98D_RXTAG
			if (tag) {
				hal_spec->rx_tag[ch_idx] = tag;
				res = true;
			}
#endif
		}

	} while (false);

	return res;
}



u16 hal_handle_rx_report_8852be(struct hal_info_t *hal, u8 *rp, u16 len,
				u8 *sw_retry, u8 *dma_ch, u16 *wp_seq,
				u8 *txsts)
{
	u8 polluted = false;
	u16 rsize = 0;
	u16 macid = 0;
	u8 tid = 0, qsel_value = 0, band = 0, tid_indic = 0;

	do {
		if (len < RX_RP_PACKET_SIZE)
			break;

		macid = (u8)GET_RX_RP_PKT_MAC_ID(rp);
		qsel_value = (u8)GET_RX_RP_PKT_QSEL(rp);
		*txsts = (u8)GET_RX_RP_PKT_TX_STS(rp);
		*wp_seq = (u16)GET_RX_RP_PKT_PCIE_SEQ(rp);
		polluted = (u8)GET_RX_RP_PKT_POLLUTED(rp);


		band = (qsel_value & BIT3) ? 1 : 0;
		tid_indic = (*wp_seq & WP_TID_INDIC_RESERVED_BIT) ? 1 : 0;
		*wp_seq &= (WP_RESERVED_SEQ);
		tid = hal_qsel_to_tid_8852be(hal, qsel_value, tid_indic);
		*dma_ch = hal_mapping_hw_tx_chnl_8852be(macid, tid, band);

		PHL_TRACE(COMP_PHL_DBG, _PHL_DEBUG_, "Get recycle report: qsel = %d, macid = %d, wp_seq = 0x%x, tid_indic = %d,"
			" tid = %d, band = %d, dma_ch = %d\n",
			qsel_value, macid, *wp_seq, tid_indic, tid, band, *dma_ch);

		if (TX_STATUS_TX_DONE != *txsts) {
			*sw_retry = true;
			/* hana_todo handle sw retry */
		} else if (true == polluted) {
			PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_, "this wp is polluted\n");
			*sw_retry = true;
			/* hana_todo handle sw retry */
		} else {
			*sw_retry = false;
		}

		rsize = RX_RP_PACKET_SIZE;
	} while (false);

	return rsize;
}


/**
 * Process Rx PPDU Status with HALMAC API and PHYDM API
 */
static enum rtw_hal_status
hal_handle_ppdusts_8852be(void *hal, u8 *psbuf, u16 sz,
			struct rtw_r_meta_data *mdata, struct rx_ppdu_status *rxps)
{
	enum rtw_hal_status hstatus = RTW_HAL_STATUS_FAILURE;

	if (mdata->mac_info_vld) {
		/*Call HALMAC API HALMAC API*/
		rxps->mac_info_length = 4; //To DO
	}

	rxps->phy_info_length = sz - rxps->mac_info_length;
	if (rxps->phy_info_length > 0) {
		/* the remaining length > 4  the phy info is valid */
		/* CALL PHYDM API Here*/
		//rx_desc->mac_id

	}
	hstatus = RTW_HAL_STATUS_SUCCESS;
	return hstatus;
}

/**
 * SW Parsing Rx Desc
 **/
static enum rtw_hal_status
_hal_parsing_rx_wd_8852be(struct hal_info_t *hal, u8 *desc,
						struct rtw_r_meta_data *mdata)
{
	enum rtw_hal_status hstatus = RTW_HAL_STATUS_FAILURE;

	mdata->pktlen = GET_RX_AX_DESC_PKT_LEN_8852B(desc);
	mdata->shift = GET_RX_AX_DESC_SHIFT_8852B(desc);
	mdata->wl_hd_iv_len = GET_RX_AX_DESC_HDR_IV_L_8852B(desc);
	mdata->bb_sel = GET_RX_AX_DESC_BB_SEL_8852B(desc);
	mdata->mac_info_vld = GET_RX_AX_DESC_MAC_INFO_VLD_8852B(desc);
	mdata->rpkt_type = GET_RX_AX_DESC_RPKT_TYPE_8852B(desc);
	mdata->drv_info_size = GET_RX_AX_DESC_DRV_INFO_SIZE_8852B(desc);
	mdata->long_rxd = GET_RX_AX_DESC_LONG_RXD_8852B(desc);

	mdata->ppdu_type = GET_RX_AX_DESC_PPDU_TYPE_8852B(desc);
	mdata->ppdu_cnt = GET_RX_AX_DESC_PPDU_CNT_8852B(desc);
	mdata->sr_en = GET_RX_AX_DESC_SR_EN_8852B(desc);
	mdata->user_id = GET_RX_AX_DESC_USER_ID_8852B(desc);
	mdata->rx_rate = GET_RX_AX_DESC_RX_DATARATE_8852B(desc);
	mdata->rx_gi_ltf = GET_RX_AX_DESC_RX_GI_LTF_8852B(desc);
	mdata->non_srg_ppdu = GET_RX_AX_DESC_NON_SRG_PPDU_8852B(desc);
	mdata->inter_ppdu = GET_RX_AX_DESC_INTER_PPDU_8852B(desc);
	mdata->bw = GET_RX_AX_DESC_BW_8852B(desc);

	mdata->freerun_cnt = GET_RX_AX_DESC_FREERUN_CNT_8852B(desc);

	mdata->a1_match = GET_RX_AX_DESC_A1_MATCH_8852B(desc);
	mdata->sw_dec = GET_RX_AX_DESC_SW_DEC_8852B(desc);
	mdata->hw_dec = GET_RX_AX_DESC_HW_DEC_8852B(desc);
	mdata->ampdu = GET_RX_AX_DESC_AMPDU_8852B(desc);
	mdata->ampdu_end_pkt = GET_RX_AX_DESC_AMPDU_EDN_PKT_8852B(desc);
	mdata->amsdu = GET_RX_AX_DESC_AMSDU_8852B(desc);
	mdata->amsdu_cut = GET_RX_AX_DESC_AMSDU_CUT_8852B(desc);
	mdata->last_msdu = GET_RX_AX_DESC_LAST_MSDU_8852B(desc);
	mdata->bypass = GET_RX_AX_DESC_BYPASS_8852B(desc);
	mdata->crc32 = GET_RX_AX_DESC_CRC32_8852B(desc);
	mdata->icverr = GET_RX_AX_DESC_ICVERR_8852B(desc);
	mdata->magic_wake = GET_RX_AX_DESC_MAGIC_WAKE_8852B(desc);
	mdata->unicast_wake = GET_RX_AX_DESC_UNICAST_WAKE_8852B(desc);
	mdata->pattern_wake = GET_RX_AX_DESC_PATTERN_WAKE_8852B(desc);

	if (mdata->long_rxd==1) {
		mdata->macid = GET_RX_AX_DESC_MACID_8852B(desc);
	}

	hstatus = RTW_HAL_STATUS_SUCCESS;
	return hstatus;
}

static u8 hal_handle_rxbd_info_8852be(struct hal_info_t *hal,
						u8 *rxbd_info, u16 *size)
{
	u8 res = false;
	u16 pld_size = 0;
	u8 fs = 0, ls = 0;
	u8 pkt_rdy = false;

	do {
		if (NULL == rxbd_info)
			break;
		if (NULL == size)
			break;

	fs = (u8)GET_RX_BD_INFO_FS(rxbd_info);
	ls = (u8)GET_RX_BD_INFO_LS(rxbd_info);
	pld_size = (u16)GET_RX_BD_INFO_HW_W_SIZE(rxbd_info);

	if (fs == 1) {
		if (ls == 1)
			pkt_rdy = true;
		else
			pkt_rdy = false;

	} else if (fs == 0) {
		if (ls == 1)
			pkt_rdy = false;
		else
			pkt_rdy = false;
	}

	if (pkt_rdy) {
		*size = pld_size;
		res = true;
	} else {
		*size = 0;
		PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_, "[WARNING] need to handle RX FS/LS\n");
		res = false;
	}
	}while(false);
	return res;
}



/**
 * the function update rxbd
 */
static enum rtw_hal_status
hal_update_rxbd_8852be(struct hal_info_t *hal, struct rx_base_desc *rxbd,
		       struct rtw_rx_buf *rx_buf)
{
	enum rtw_hal_status hstatus = RTW_HAL_STATUS_SUCCESS;
	struct rtw_hal_com_t *hal_com = hal->hal_com;
	struct bus_hw_cap_t *bus_hw_cap = &hal_com->bus_hw_cap;
	u8 *ring_head = NULL;
	u8 *target_rxbd = NULL;
	u16 rxbd_num = (u16)hal_com->bus_cap.rxbd_num;

	do {
		if (NULL == rxbd)
			break;
		if (NULL == rx_buf)
			break;

		ring_head = rxbd->vir_addr;
		target_rxbd = ring_head + (rxbd->host_idx *
					   bus_hw_cap->rxbd_len);
		/* connect with halmac */
		SET_RX_BD_RXBUFFSIZE(target_rxbd, rx_buf->buf_len);
		SET_RX_BD_PHYSICAL_ADDR_LOW(target_rxbd,
					    (u32)rx_buf->phy_addr_l);
		SET_RX_BD_PHYSICAL_ADDR_HIGH(target_rxbd,
					     (u32)rx_buf->phy_addr_h);
		rxbd->host_idx = (rxbd->host_idx + 1) % rxbd_num;
	} while (false);

	return hstatus;
}


/**
 * the function notify rx done
 */
static enum rtw_hal_status
hal_notify_rxdone_8852be(struct hal_info_t *hal,
		struct rx_base_desc *rxbd, u8 ch, u16 rxcnt)
{
	enum rtw_hal_status hstatus = RTW_HAL_STATUS_FAILURE;
	u32 reg = 0;
	u8 rx_dma_ch = 0;

	do {
		rx_dma_ch = RX_QUEUE_IDX_8852BE + ch;
		reg = _hal_get_bd_idx_reg_8852be(rx_dma_ch);
		/* connect with halmac */
		if (0xFFFF == reg)
			break;
		hal_write16(hal->hal_com, reg, rxbd->host_idx);
		hstatus = RTW_HAL_STATUS_SUCCESS;
	} while (false);

	return hstatus;
}


struct bd_ram bdram_table_8852b[] = {
		/* ACH0_QUEUE_IDX_8852BE */ {0, 25, 4},
		/* ACH1_QUEUE_IDX_8852BE */ {25, 25, 4},
		/* ACH2_QUEUE_IDX_8852BE */ {50, 25, 4},
		/* ACH3_QUEUE_IDX_8852BE */ {75, 25, 4},
		/* ACH4_QUEUE_IDX_8852BE */ {100, 25, 4},
		/* ACH5_QUEUE_IDX_8852BE */ {125, 25, 4},
		/* ACH6_QUEUE_IDX_8852BE */ {150, 25, 4},
		/* ACH7_QUEUE_IDX_8852BE */ {175, 25, 4},
		/* MGQ_B0_QUEUE_IDX_8852BE */ {185, 10, 4},
		/* HIQ_B0_QUEUE_IDX_8852BE */ {195, 10, 4},
		/* MGQ_B1_QUEUE_IDX_8852BE */ {205, 10, 4},
		/* HIQ_B1_QUEUE_IDX_8852BE */ {215, 10, 4},
		/* FWCMD_QUEUE_IDX_8852BE */ {225, 10, 4}
};

static void _hal_tx_init_bd_ram_8852be(struct hal_info_t *hal)
{
	u32 reg = 0;
	u32 value = 0;
	u8 i = 0;

	for (i = 0; i < TX_DMA_CHANNEL_ENTRY_8852BE; i++) {
		/*if (FWCMD_QUEUE_IDX_8852BE == i)
			continue;*/
		value = 0;
		value = bdram_table_8852b[i].sidx +
			((bdram_table_8852b[i].max << 8) & 0xFF00) +
			((bdram_table_8852b[i].min << 16) & 0xFF0000);

		reg = _hal_get_bd_ram_reg_8852be(i);
		if (0 != reg)
			hal_write32(hal->hal_com, reg, value);
		else
			PHL_ERR("query txbd num reg fail (ch_idx = %d)\n", i);
	}

	value = hal_read32(hal->hal_com, R_AX_PCIE_INIT_CFG1);
	value |= (B_AX_RST_BDRAM);
	hal_write32(hal->hal_com, R_AX_PCIE_INIT_CFG1, value);

}
static void _hal_trx_init_bd_num_8852be(struct hal_info_t *hal)
{
	struct rtw_hal_com_t *hal_com = hal->hal_com;
	u16 txbd_num = (u16)hal_com->bus_cap.txbd_num;
	u16 rxbd_num = (u16)hal_com->bus_cap.rxbd_num;
	u32 reg = 0;
	u16 value = 0;
	u8 i = 0;

	for (i = 0; i < TX_DMA_CHANNEL_ENTRY_8852BE; i++) {
		/*if (FWCMD_QUEUE_IDX_8852BE == i)
			continue;*/

		value = txbd_num & B_AX_DESC_NUM_MSK;

		reg = _hal_get_bd_num_reg_8852be(i);
		if (0 != reg)
			hal_write16(hal->hal_com, reg, value);
		else
			PHL_ERR("query txbd num reg fail (ch_idx = %d)\n", i);
	}

	for (i = RX_QUEUE_IDX_8852BE;
		 i < RX_QUEUE_IDX_8852BE + RX_DMA_CHANNEL_ENTRY_8852BE; i++) {
		 /*if (FWCMD_QUEUE_IDX_8852BE == i)
			 continue;*/

		 value = rxbd_num & B_AX_DESC_NUM_MSK;

		 reg = _hal_get_bd_num_reg_8852be(i);
		 if (0 != reg)
			 hal_write16(hal->hal_com, reg, value);
		 else
			 PHL_ERR("query rxbd num reg fail (ch_idx = %d)\n", i);
	}
}


static void _hal_trx_init_bd_8852be(struct hal_info_t *hal, u8 *txbd_buf, u8 *rxbd_buf)
{
	struct tx_base_desc *txbd = NULL;
	struct rx_base_desc *rxbd = NULL;
	u32 reg_addr_l = 0, reg_addr_h = 0;
	u8 i = 0, rxch_idx = 0;

	if (NULL != txbd_buf && NULL != rxbd_buf) {
		txbd = (struct tx_base_desc *)txbd_buf;
		rxbd = (struct rx_base_desc *)rxbd_buf;

		for (i = 0; i < TX_DMA_CHANNEL_ENTRY_8852BE; i++) {
			/*if (FWCMD_QUEUE_IDX_8852BE == i)
				continue;*/

			_hal_get_bd_desc_reg_8852be(i, &reg_addr_l, &reg_addr_h);
			if (0 != reg_addr_l)
				hal_write32(hal->hal_com, reg_addr_l, txbd[i].phy_addr_l);
			else
				PHL_ERR("query txbd desc reg_addr_l fail (ch_idx = %d)\n", i);

			if (0 != reg_addr_h)
				hal_write32(hal->hal_com, reg_addr_h, txbd[i].phy_addr_h);
			else
				PHL_ERR("query txbd desc reg_addr_h fail (ch_idx = %d)\n", i);
		}

		for (i = 0; i < RX_DMA_CHANNEL_ENTRY_8852BE; i++) {
			 rxch_idx = i + RX_QUEUE_IDX_8852BE;
			_hal_get_bd_desc_reg_8852be(rxch_idx, &reg_addr_l, &reg_addr_h);
			if (0 != reg_addr_l)
				hal_write32(hal->hal_com, reg_addr_l, rxbd[i].phy_addr_l);
			else
				PHL_ERR("query rxbd desc reg_addr_l fail (ch_idx = %d)\n", i);
			if (0 != reg_addr_h)
				hal_write32(hal->hal_com, reg_addr_h, rxbd[i].phy_addr_h);
			else
				PHL_ERR("query rxbd desc reg_addr_h fail (ch_idx = %d)\n", i);
		}

	}
}

static void _hal_tx_enable_truncate_mode(struct hal_info_t *hal, u8 *txbd_buf,
					 u8 *rxbd_buf)
{
	struct tx_base_desc *txbd = NULL;
	struct rx_base_desc *rxbd = NULL;
	u32 value = 0;

	txbd = (struct tx_base_desc *)txbd_buf;
	rxbd = (struct rx_base_desc *)rxbd_buf;

	value = hal_read32(hal->hal_com, R_AX_PCIE_INIT_CFG1);
	value |= (B_AX_TX_TRUNC_MODE | B_AX_RX_TRUNC_MODE);
	hal_write32(hal->hal_com, R_AX_PCIE_INIT_CFG1, value);

	hal_write32(hal->hal_com, R_AX_TXDMA_ADDR_H, txbd->phy_addr_h);
	hal_write32(hal->hal_com, R_AX_RXDMA_ADDR_H, rxbd->phy_addr_h);
}

static void _hal_tx_disable_truncate_mode(struct hal_info_t *hal)
{
	u32 value = 0;

	value = hal_read32(hal->hal_com, R_AX_TX_ADDRESS_INFO_MODE_SETTING);
	value &= ~(B_AX_HOST_ADDR_INFO_8B_SEL);
	hal_write32(hal->hal_com, R_AX_TX_ADDRESS_INFO_MODE_SETTING, value);

	value = hal_read32(hal->hal_com, R_AX_PKTIN_SETTING);
	value |= (B_AX_WD_ADDR_INFO_LENGTH);
	hal_write32(hal->hal_com, R_AX_PKTIN_SETTING, value);
}


static void _hal_select_rxbd_mode(struct hal_info_t *hal,
					enum rxbd_mode_8852BE mode)
{
	u32 value = 0;

	if (RXBD_MODE_PACKET == mode) {
		value = hal_read32(hal->hal_com, R_AX_PCIE_INIT_CFG1);
		value &= ~(B_AX_RXBD_MODE);
		hal_write32(hal->hal_com, R_AX_PCIE_INIT_CFG1, value);
	} else if (RXBD_MODE_SEPARATION == mode) {
/*
		value = hal_read32(hal->hal_com, R_AX_PCIE_INIT_CFG1);
		value |= (B_AX_RXBD_MODE);
		hal_write32(hal->hal_com, R_AX_PCIE_INIT_CFG1, value);
*/
		/* hana_todo, append length setting */
	} else {
		PHL_WARN("Unknown Rx BD mode (%d)\n", mode);
	}
}

static void hal_cfg_wow_txdma_8852be(struct hal_info_t *hal, u8 en)
{
	struct mac_ax_txdma_ch_map ch_map;

	ch_map.ch0 = en ? MAC_AX_PCIE_ENABLE : MAC_AX_PCIE_DISABLE;
	ch_map.ch1 = en ? MAC_AX_PCIE_ENABLE : MAC_AX_PCIE_DISABLE;
	ch_map.ch2 = en ? MAC_AX_PCIE_ENABLE : MAC_AX_PCIE_DISABLE;
	ch_map.ch3 = en ? MAC_AX_PCIE_ENABLE : MAC_AX_PCIE_DISABLE;
	ch_map.ch4 = MAC_AX_PCIE_IGNORE;
	ch_map.ch5 = MAC_AX_PCIE_IGNORE;
	ch_map.ch6 = MAC_AX_PCIE_IGNORE;
	ch_map.ch7 = MAC_AX_PCIE_IGNORE;
	ch_map.ch8 = en ? MAC_AX_PCIE_ENABLE : MAC_AX_PCIE_DISABLE;
	ch_map.ch9 = en ? MAC_AX_PCIE_ENABLE : MAC_AX_PCIE_DISABLE;
	ch_map.ch10 = MAC_AX_PCIE_IGNORE;
	ch_map.ch11 = MAC_AX_PCIE_IGNORE;
	ch_map.ch12 = MAC_AX_PCIE_IGNORE;

	if (RTW_HAL_STATUS_SUCCESS != rtw_hal_mac_cfg_txdma(hal, &ch_map))
		PHL_ERR("%s failure \n", __func__);

}

static u8 hal_poll_txdma_idle_8852be(struct hal_info_t *hal)
{
	struct mac_ax_txdma_ch_map ch_map;

	ch_map.ch0 = MAC_AX_PCIE_ENABLE;
	ch_map.ch1 = MAC_AX_PCIE_ENABLE;
	ch_map.ch2 = MAC_AX_PCIE_ENABLE;
	ch_map.ch3 = MAC_AX_PCIE_ENABLE;
	ch_map.ch4 = MAC_AX_PCIE_IGNORE;
	ch_map.ch5 = MAC_AX_PCIE_IGNORE;
	ch_map.ch6 = MAC_AX_PCIE_IGNORE;
	ch_map.ch7 = MAC_AX_PCIE_IGNORE;
	ch_map.ch8 = MAC_AX_PCIE_ENABLE;
	ch_map.ch9 = MAC_AX_PCIE_ENABLE;
	ch_map.ch10 = MAC_AX_PCIE_IGNORE;
	ch_map.ch11 = MAC_AX_PCIE_IGNORE;
	ch_map.ch12 = MAC_AX_PCIE_ENABLE;


	if (RTW_HAL_STATUS_SUCCESS != rtw_hal_mac_poll_txdma_idle(hal, &ch_map)) {

		PHL_ERR("%s failure \n", __func__);

		return false;
	}
	return true;
}
static void _hal_clear_trx_state(struct hal_info_t *hal)
{
	u32 value = 0;

	/* disable hci */
	value = hal_read32(hal->hal_com, R_AX_PCIE_INIT_CFG1);
	value &= ~(B_AX_RXHCI_EN | B_AX_TXHCI_EN);
	hal_write32(hal->hal_com, R_AX_PCIE_INIT_CFG1, value);

	/* check mac power on status */

	/* clear hci idx */
	value = hal_read32(hal->hal_com, R_AX_TXBD_RWPTR_CLR1);
	value |= (B_AX_CLR_ACH0_IDX | B_AX_CLR_ACH1_IDX | B_AX_CLR_ACH2_IDX |
				B_AX_CLR_ACH3_IDX | B_AX_CLR_ACH4_IDX | B_AX_CLR_ACH5_IDX |
				B_AX_CLR_ACH6_IDX | B_AX_CLR_ACH7_IDX | B_AX_CLR_CH8_IDX |
				B_AX_CLR_CH9_IDX | B_AX_CLR_CH12_IDX);
	hal_write32(hal->hal_com, R_AX_TXBD_RWPTR_CLR1, value);

	value = hal_read32(hal->hal_com, R_AX_TXBD_RWPTR_CLR2);
	value |= (B_AX_CLR_CH10_IDX | B_AX_CLR_CH11_IDX);
	hal_write32(hal->hal_com, R_AX_TXBD_RWPTR_CLR2, value);

	value = hal_read32(hal->hal_com, R_AX_RXBD_RWPTR_CLR);
	value |= (B_AX_CLR_RXQ_IDX | B_AX_CLR_RPQ_IDX);
	hal_write32(hal->hal_com, R_AX_RXBD_RWPTR_CLR, value);
}

/**
 * the function will deinitializing 8852BE specific data and hw configuration
 */
static void hal_trx_deinit_8852be(struct hal_info_t *hal)
{
	/*struct rtw_hal_com_t *hal_com = hal->hal_com;*/
}

/**
 * the function will initializing 8852BE specific data and hw configuration
 */
static enum rtw_hal_status hal_trx_init_8852be(struct hal_info_t *hal, u8 *txbd_buf, u8 *rxbd_buf)
{
	enum rtw_hal_status hstatus = RTW_HAL_STATUS_SUCCESS;
	/* Set AMPDU max agg number to 128 */
	/* CR setting*/
	rtw_hal_mac_set_hw_ampdu_cfg(hal, 0, 0x7F, 0xAB);
	return hstatus;
}

static struct hal_trx_ops ops = {0};
void hal_trx_ops_init_8852be(void)
{
	ops.init = hal_trx_init_8852be;
	ops.deinit = hal_trx_deinit_8852be;
	ops.query_tx_res = hal_get_avail_txbd_8852be;
	ops.query_rx_res = hal_get_avail_rxbd_8852be;
	ops.cfg_wow_txdma = hal_cfg_wow_txdma_8852be;
	ops.poll_txdma_idle = hal_poll_txdma_idle_8852be;
	ops.map_hw_tx_chnl = hal_mapping_hw_tx_chnl_8852be;
	ops.qsel_to_tid = hal_qsel_to_tid_8852be;
	ops.query_txch_num = hal_query_txch_num_8852be;
	ops.query_rxch_num = hal_query_rxch_num_8852be;
	ops.update_wd = hal_update_wd_8852be;
	ops.update_txbd = hal_update_txbd_8852be;
	ops.tx_start = hal_trigger_txdma_8852be;
	ops.check_rxrdy = hal_check_rxrdy_8852be;
	ops.handle_rxbd_info = hal_handle_rxbd_info_8852be;
	ops.handle_rx_buffer = hal_handle_rx_buffer_8852b;
	ops.update_rxbd = hal_update_rxbd_8852be;
	ops.notify_rxdone = hal_notify_rxdone_8852be;
	ops.handle_wp_rpt = hal_handle_rx_report_8852be;
	ops.get_fwcmd_queue_idx = hal_get_fwcmd_queue_idx_8852be;
}



u32 hal_hook_trx_ops_8852be(struct rtw_phl_com_t *phl_com,
					struct hal_info_t *hal_info)
{
	enum rtw_hal_status hstatus = RTW_HAL_STATUS_FAILURE;

	if (NULL != hal_info) {
		hal_trx_ops_init_8852be();
		hal_info->trx_ops = &ops;
		hstatus = RTW_HAL_STATUS_SUCCESS;
	}

	return hstatus;
}
