/******************************************************************************
 *
 * Copyright(c) 2007 - 2020  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.
 *
 * The full GNU General Public License is included in this distribution in the
 * file called LICENSE.
 *
 * Contact Information:
 * wlanfae <wlanfae@realtek.com>
 * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
 * Hsinchu 300, Taiwan.
 *
 * Larry Finger <Larry.Finger@lwfinger.net>
 *
 *****************************************************************************/
#include "halbb_precomp.h"

void halbb_cfg_timers(struct bb_info *bb, enum bb_timer_cfg_t cfg,
		      struct halbb_timer_info *timer)
{
	BB_DBG(bb, DBG_INIT, "[%s] %s timer, event=%d\n", __func__, 
	       ((cfg == BB_SET_TIMER) ? "SET" : ((cfg == BB_CANCEL_TIMER) ? "CANCEL" : ("RLS"))),
	       timer->event_idx);

	if (cfg == BB_INIT_TIMER) {
		BB_WARNING("[%s]\n", __func__);
		return;
	}

	if (cfg == BB_SET_TIMER) {
		if (timer->timer_state != BB_TIMER_IDLE) {
			BB_WARNING("[%s] state=%d\n", __func__, timer->timer_state);
			return;
		}

		timer->timer_state = BB_TIMER_RUN;
		halbb_set_timer(bb, &timer->timer_list, timer->cb_time);
	} else if (cfg == BB_CANCEL_TIMER) {
		halbb_cancel_timer(bb, &timer->timer_list);
		timer->timer_state = BB_TIMER_IDLE;
	} else if (cfg == BB_RELEASE_TIMER) {
		halbb_release_timer(bb, &timer->timer_list);
		timer->timer_state = BB_TIMER_RELEASE;
	}
}

u32 halbb_get_sys_time(struct bb_info *bb)
{
	return 0;
}

u32 halbb_phy0_to_phy1_ofst(struct bb_info *bb, u32 addr, enum phl_phy_idx phy_idx)
{
	u32 ofst = 0;

	if (phy_idx == HW_PHY_0)
		return 0;

	if (!bb->bb_cmn_hooker->ic_dual_phy_support && !bb->hal_com->dbcc_en)
		return 0;

	switch (bb->ic_type) {
	#ifdef BB_8852A_2_SUPPORT
	case BB_RTL8852A:
		ofst = halbb_phy0_to_phy1_ofst_8852a_2(bb, addr);
		break;
	#endif
	#ifdef BB_8852C_SUPPORT
	case BB_RTL8852C:
		ofst = halbb_phy0_to_phy1_ofst_8852c(bb, addr);
		break;
	#endif
	#ifdef BB_1115_SUPPORT
	case BB_RLE1115:
		ofst = (addr < 0x10000) ? 0x20000 : 0;
		break;
	#endif
#if (HLABB_CODE_BASE_NUM >= 33) //will be removed when (022+032) branch phase out
	#ifdef BB_8922A_SUPPORT
	case BB_RTL8922A:
		ofst = halbb_phy0_to_phy1_ofst_8922a(bb, addr);
		break;
	#endif
#endif

	default:
		break;
	}

	return ofst;
}

void halbb_delay_us(struct bb_info *bb, u32 us)
{
	bool ret = true;

	#ifdef HALBB_FW_OFLD_SUPPORT
	if (halbb_check_fw_ofld(bb)) {
		if (bb->bb_cmn_hooker->bbcr_fwofld_state || bb->bb_cmn_hooker->bb_fwofld_in_progress) {
			ret = halbb_fw_delay(bb, us);
			BB_DBG(bb, DBG_FW_INFO, "[OK:%d][O:%d,N:%d] halbb fwofld delay = %d\n",
				ret,
				bb->bb_cmn_hooker->bbcr_fwofld_state,
				bb->bb_cmn_hooker->bb_fwofld_in_progress,
				us);
			return;
		}
	}
	#endif

	_os_delay_us(bb->hal_com->drv_priv, us);
}

u32 halbb_set_pwr_reg_cmn(struct bb_info* bb, enum phl_phy_idx bb_phy_idx, u32 addr, u32 val)
{
	if ((!bb->hal_com->dbcc_en) && (bb_phy_idx == HW_PHY_1))
		return -1;
	if (bb->bb_dbg_i.cr_cnt_ctrl)
		bb->bb_dbg_i.wrapcr_recorde_w_cnt++;

	return rtw_hal_mac_set_pwr_reg(bb->hal_com, (u8)bb_phy_idx, addr, val);
}

u32 halbb_write_mask_pwr_reg_cmn(struct bb_info* bb, enum phl_phy_idx bb_phy_idx, u32 addr, u32 mask, u32 val)
{
	if ((!bb->hal_com->dbcc_en) && (bb_phy_idx == HW_PHY_1))
		return -1;
	if (bb->bb_dbg_i.cr_cnt_ctrl)
		bb->bb_dbg_i.wrapcr_recorde_w_cnt++;

	return rtw_hal_mac_write_msk_pwr_reg(bb->hal_com, (u8)bb_phy_idx, addr, mask, val);
}

#define HALBB_RF_IO_API

#ifdef HALBB_RF_IO_API

void halbb_show_rf_cr_cnt(struct bb_info *bb, u8 module_idx)
{
	if (bb->bb_dbg_i.rfcr_cnt_ctrl == BB_CR_CNT_DISABLE)
		return;

	BB_TRACE("[%s][%02d] RF_cnt{R, W} = {%08d, %08d}\n",
		 __func__, module_idx, bb->bb_dbg_i.rfcr_recorde_r_cnt, bb->bb_dbg_i.rfcr_recorde_w_cnt);

	if (bb->bb_dbg_i.rfcr_cnt_ctrl == BB_CR_CNT_ENABLE_RESET) {
		bb->bb_dbg_i.rfcr_recorde_r_cnt = 0;
		bb->bb_dbg_i.rfcr_recorde_w_cnt = 0;
	}
}

u32 halbb_rfio_get_cr(struct bb_info *bb, u32 addr, u32 mask)
{
	u32 val = 0;

	if (bb->bb_dbg_i.rfcr_cnt_ctrl)
		bb->bb_dbg_i.rfcr_recorde_r_cnt++;

	if (mask == MASKDWORD)
		mask = 0; /*prevent compile warning*/
	val = hal_read32(bb->hal_com, (addr + bb->bb0_cr_offset));

	return val;
}

void halbb_rfio_set_cr(struct bb_info *bb, u32 addr, u32 mask, u32 val)
{
	if (bb->bb_dbg_i.rfcr_cnt_ctrl)
		bb->bb_dbg_i.rfcr_recorde_w_cnt++;

	if (mask == MASKDWORD)
		mask = 0; /*prevent compile warning*/
	hal_write32(bb->hal_com, (addr + bb->bb0_cr_offset), val);
}

u32 halbb_rfio_get_reg_cmn(struct bb_info *bb, u32 addr, u32 mask, enum phl_phy_idx phy_idx)
{
	u32 val_0 = 0;
	u32 shift_val = 0;

	addr += halbb_phy0_to_phy1_ofst(bb, addr, phy_idx);

	shift_val = halbb_cal_bit_shift(mask);
	shift_val = (shift_val >= 31) ? 31 : shift_val;

	val_0 = (halbb_rfio_get_cr(bb, addr, mask) & mask) >> shift_val;

	return val_0;
}

void halbb_rfio_set_reg_cmn(struct bb_info *bb, u32 addr, u32 mask, u32 val, enum phl_phy_idx phy_idx)
{
	u32 ori_val, shift;
	u32 val_mod = val;

	addr += halbb_phy0_to_phy1_ofst(bb, addr, phy_idx);

	if (mask != MASKDWORD) {
		shift = halbb_cal_bit_shift(mask);
		
		ori_val = halbb_rfio_get_cr(bb, addr, mask);
		val_mod = ((ori_val) & (~mask)) | (((val << shift)) & mask);
	}

	halbb_rfio_set_cr(bb, addr, mask, val_mod);
}
#endif

void halbb_show_cr_cnt(struct bb_info *bb, u8 module_idx)
{
	if (bb->bb_dbg_i.cr_cnt_ctrl == BB_CR_CNT_DISABLE)
		return;

	BB_TRACE("[%s][%02d] cnt{R, W, P} = {%08d, %08d, %08d}\n",
		 __func__, module_idx, bb->bb_dbg_i.cr_recorde_r_cnt,
		 bb->bb_dbg_i.cr_recorde_w_cnt, bb->bb_dbg_i.wrapcr_recorde_w_cnt);

	if (bb->bb_dbg_i.cr_cnt_ctrl == BB_CR_CNT_ENABLE_RESET) {
		bb->bb_dbg_i.cr_recorde_r_cnt = 0;
		bb->bb_dbg_i.cr_recorde_w_cnt = 0;
		bb->bb_dbg_i.wrapcr_recorde_w_cnt = 0;
	}
}


#ifdef HALBB_BB_WRAP_SUPPORT
u32 halbb_write_bb_wrap_cmn(struct bb_info* bb, u32 addr, u32 val)
{
	return rtw_hal_mac_write_bb_wrapper(bb->hal_com, addr, val);
}

u32 halbb_write_mask_bb_wrap_cmn(struct bb_info* bb, u32 addr, u32 mask, u32 val)
{
	return rtw_hal_mac_write_msk_bb_wrapper(bb->hal_com, addr, mask, val);
}
#endif

void halbb_set_cr(struct bb_info *bb, u32 addr, u32 mask, u32 val)
{
	u8 mask_lsb = 0, mask_msb = 0;

	if (bb->bb_dbg_i.cr_recorder_en) {
		#ifdef HALBB_DV_PXP_DBG_SUPPORT
		if (bb->bb_dv_pxp_dbg_i.is_dv_pxp_dbg && bb->bb_dv_pxp_dbg_i.is_print) {
			BB_TRACE("[DV/PXP]0x3, 0x1862%04x, 0x%08x, 0x%08x\n", addr, mask, val&mask);
			return;
		}
		#endif
		BB_TRACE("[W] 0x%04x = 0x%08x\n", addr, val);
	} else if (bb->bb_dbg_i.cr_mp_recorder_en) {
		if ((addr != 0xF9) && (addr != 0xFA) && (addr != 0xFB) && (addr != 0xFD) && (addr != 0xFE)) {
			mask_lsb = halbb_bitmask_lsb(bb, mask);
			mask_msb = halbb_bitmask_msb(bb, mask);

			if (halbb_ones_num_in_bitmap(mask, 32) == 1)
				BB_TRACE("[MP] op 0x%x[%d] 0x%x\n", addr, mask_lsb, ((val & mask) >> mask_lsb));
			else if (mask == MASKDWORD)
				BB_TRACE("[MP] od 0x%x 0x%x\n", addr, val);
			else
				BB_TRACE("[MP] op 0x%x[%d:%d] 0x%x\n", addr, mask_msb, mask_lsb, ((val & mask) >> mask_lsb));
		} else {
			if ((addr == 0xF9) || (addr == 0xFA) || (addr == 0xFB)) // Delay log (1ms)
				BB_TRACE("[MP] delay 1\n"); // Smallest resolusion of MP script is 1ms
			else if (addr == 0xFD) // Delay log (5ms)
				BB_TRACE("[MP] delay 5\n");
			else if (addr == 0xFE) // Delay log (50ms)
				BB_TRACE("[MP] delay 50\n");
		}
	}

	if (bb->bb_dbg_i.cr_cnt_ctrl)
		bb->bb_dbg_i.cr_recorde_w_cnt++;

	hal_write32(bb->hal_com, (addr + bb->bb0_cr_offset), val);

#if 0
	if (bb->bb0_cr_offset != 0x10000)
		BB_WARNING("[W] bb0_ofst=0x%x, 0x%04x = 0x%08x\n", bb->bb0_cr_offset, addr, val);
#endif
}

u32 halbb_get_cr(struct bb_info *bb, u32 addr, u32 mask)
{
	u32 val = hal_read32(bb->hal_com, (addr + bb->bb0_cr_offset));
	u8 mask_lsb = 0, mask_msb = 0;

	if (bb->bb_dbg_i.cr_recorder_en)
		BB_TRACE("[R] 0x%04x = 0x%08x\n", addr, val);
#if 0
	if (bb->bb_dbg_i.cr_mp_recorder_en) {
		mask_lsb = halbb_bitmask_lsb(bb, mask);
		mask_msb = halbb_bitmask_msb(bb, mask);

		if (mask_lsb == mask_msb)
			BB_TRACE("[MP] id 0x%x[%d]\n", addr, mask_lsb);
		else if ((mask_lsb == 0) && (mask_msb == 31))
			BB_TRACE("[MP] id 0x%x\n", addr);
		else
			BB_TRACE("[MP] id 0x%x[%d:%d]\n", addr, mask_msb, mask_lsb);
	}
#endif
#if 0
	if (bb->bb0_cr_offset != 0x10000)
		BB_WARNING("[R] bb0_ofst=0x%x, 0x%04x = 0x%08x\n", bb->bb0_cr_offset, addr, val);
#endif

	return val;
}

void halbb_set_reg(struct bb_info *bb, u32 addr, u32 mask, u32 val)
{
	u32 ori_val = 0;
	u32 shift;
	#ifdef HALBB_FW_OFLD_SUPPORT
	bool ret = true;
	#endif

#ifdef HALBB_DBCC_SUPPORT
    if (bb->hal_com->dbcc_en && bb->bb_phy_idx == HW_PHY_1)
        addr += halbb_phy0_to_phy1_ofst(bb, addr, HW_PHY_1);
#endif

	#ifdef HALBB_FW_OFLD_SUPPORT
	if (halbb_check_fw_ofld(bb)) {
		if (bb->bb_cmn_hooker->bbcr_fwofld_state || bb->bb_cmn_hooker->bb_fwofld_in_progress) {
			ret = halbb_fw_set_reg(bb, addr, mask, val, 0);
			BB_DBG(bb, DBG_FW_INFO, "[OK:%d][O:%d,N:%d] Reg_0x%08x = 0x%08x\n",
				ret,
				bb->bb_cmn_hooker->bbcr_fwofld_state,
				bb->bb_cmn_hooker->bb_fwofld_in_progress,
				addr, val);
			return;
		}
	}
	#endif

	if (mask != MASKDWORD) {
		ori_val = halbb_get_cr(bb, addr, mask);
		shift = halbb_cal_bit_shift(mask);
		val = ((ori_val) & (~mask)) | (((val << shift)) & mask);
	}

	halbb_set_cr(bb, addr, mask, val);
}

void halbb_set_reg_curr_phy(struct bb_info *bb, u32 addr, u32 mask, u32 val)
{
	enum phl_phy_idx phy_idx = bb->bb_phy_idx;
	/*u32 ori_val, shift;
	u32 val_mod = val;

	addr += halbb_phy0_to_phy1_ofst(bb, addr, phy_idx);

	if (mask != MASKDWORD) {
		shift = halbb_cal_bit_shift(mask);
		
		ori_val = halbb_get_cr(bb, addr, mask);
		val_mod = ((ori_val) & (~mask)) | (((val << shift)) & mask);
	}

	halbb_set_cr(bb, addr, mask, val_mod);*/
	halbb_set_reg_cmn(bb, addr, mask, val, phy_idx);
}

void halbb_set_reg_cmn(struct bb_info *bb, u32 addr, u32 mask, u32 val, enum phl_phy_idx phy_idx)
{
	u32 ori_val, shift;
	u32 val_mod = val;

	#ifdef HALBB_FW_OFLD_SUPPORT
	bool ret = true;

	if (bb->bb_cmn_hooker->bbcr_fwofld_state || bb->bb_cmn_hooker->bb_fwofld_in_progress) {
		ret = halbb_fw_set_reg_cmn(bb, addr, mask, val, phy_idx, 0);
		return;
	}
	#endif

	addr += halbb_phy0_to_phy1_ofst(bb, addr, phy_idx);

	if (mask != MASKDWORD) {
		shift = halbb_cal_bit_shift(mask);
		
		ori_val = halbb_get_cr(bb, addr, mask);
		val_mod = ((ori_val) & (~mask)) | (((val << shift)) & mask);
	}

	halbb_set_cr(bb, addr, mask, val_mod);
}

void halbb_set_reg_phy0_1(struct bb_info *bb, u32 addr, u32 mask, u32 val)
{
	/*u32 ori_val = 0, shift = 0;
	u32 val_mod = val;*/
	u32 ofst_val = 0;

	/*if (mask != MASKDWORD) {
		shift = halbb_cal_bit_shift(mask);
		
		ori_val = halbb_get_cr(bb, addr, mask);
		val_mod = ((ori_val) & (~mask)) | (((val << shift)) & mask);
	}

	halbb_set_cr(bb, addr, mask, val_mod);*/
	halbb_set_reg(bb, addr, mask, val);

	ofst_val = halbb_phy0_to_phy1_ofst(bb, addr, HW_PHY_1);

	if (ofst_val == 0)
		return;

	addr += ofst_val;
	/*if (mask != MASKDWORD) {
		ori_val = halbb_get_cr(bb, addr, mask);
		val_mod = ((ori_val) & (~mask)) | (((val << shift)) & mask);
	}
	halbb_set_cr(bb, addr, mask, val_mod);*/
	halbb_set_reg(bb, addr, mask, val);
}

u32 halbb_get_reg(struct bb_info *bb, u32 addr, u32 mask)
{
	u32 val_0 = 0;

#ifdef HALBB_DBCC_SUPPORT
    if (bb->hal_com->dbcc_en && bb->bb_phy_idx == HW_PHY_1)
        addr += halbb_phy0_to_phy1_ofst(bb, addr, HW_PHY_1);
#endif

	val_0 = (halbb_get_cr(bb, addr, mask) & mask) >> halbb_cal_bit_shift(mask);

	return val_0;
}

u32 halbb_get_reg_curr_phy(struct bb_info *bb, u32 addr, u32 mask)
{
	enum phl_phy_idx phy_idx = bb->bb_phy_idx;
	u32 val_0 = 0;

	addr += halbb_phy0_to_phy1_ofst(bb, addr, phy_idx);
	val_0 = (halbb_get_cr(bb, addr, mask) & mask) >> halbb_cal_bit_shift(mask);

	return val_0;
}

u32 halbb_get_phy0_phy1_reg(struct bb_info *bb, u32 addr, enum phl_phy_idx phy_idx)
{
	addr += halbb_phy0_to_phy1_ofst(bb, addr, phy_idx);

	return addr;
}

u32 halbb_get_reg_cmn(struct bb_info *bb, u32 addr, u32 mask, enum phl_phy_idx phy_idx)
{
	u32 val_0 = 0;
	u32 shift_val = 0;

	addr += halbb_phy0_to_phy1_ofst(bb, addr, phy_idx);

	shift_val = halbb_cal_bit_shift(mask);
	shift_val = (shift_val >= 31) ? 31 : shift_val;

	val_0 = (halbb_get_cr(bb, addr, mask) & mask) >> shift_val;

	return val_0;
}

u32 halbb_get_reg_phy0_1(struct bb_info *bb, u32 addr, u32 mask, u32 *val_1)
{
	u32 val_0 = 0;
	u32 shift = halbb_cal_bit_shift(mask);
	u32 ofst_val;

	val_0 = (halbb_get_cr(bb, addr, mask) & mask) >> shift;

	ofst_val = halbb_phy0_to_phy1_ofst(bb, addr, HW_PHY_1);

	if (ofst_val == 0) {
		*val_1 = val_0;
		return val_0;
	}

	addr += ofst_val;
	*val_1 = (halbb_get_cr(bb, addr, mask) & mask) >> shift;

	return val_0;
}

bool halbb_fill_h2c_cmd(struct bb_info *bb, u16 cmdlen, u8 cmdid,
			u8 classid, u32 *pval)
{
	u32 rt_val = 0;
	struct rtw_g6_h2c_hdr hdr = {0};
	struct rtw_hal_com_t *hal_com = NULL;

	hdr.h2c_class = classid;
	hdr.h2c_func = cmdid;
	hdr.content_len = cmdlen;
	hdr.type = H2CB_TYPE_LONG_DATA;
	hdr.rec_ack = 0;
	hdr.done_ack = 0;
	hal_com = bb->hal_com;
	BB_DBG(bb, DBG_FW_INFO, "H2C: %x %x %x\n", classid, cmdid, cmdlen);
	rt_val =  rtw_hal_mac_send_h2c(hal_com, &hdr, pval);

	if (cmdlen % 4) {
		BB_WARNING("[%s] cmdlen = %d\n", __func__, cmdlen);
	}

	if (rt_val != 0) {
		BB_WARNING("Error H2C CLASS=%d, ID=%d, Rt_v = %d\n", classid, cmdid, rt_val);
		return false;
	} else {
		return true;
	}
}

bool halbb_test_h2c_c2h_flow(struct bb_info *bb)
{
	u32 rt_val = 0;
	u32 *bb_h2c;
	u8 h2ctest[4] = {1, 0, 0, 0};

	bb_h2c = (u32 *) &h2ctest;
	rt_val =  halbb_fill_h2c_cmd(bb, 1, DM_H2C_FW_H2C_TEST, HALBB_H2C_DM, bb_h2c);
	if (rt_val != 0) {
		BB_WARNING("Error H2C TEST\n");
		return false;
	} else {
		return true;
	}
}

u32 halbb_c2h_mu_gptbl_rpt(struct bb_info *bb, u16 len, u8 *c2h)
{
	/* Set MU grouping table and return value */
	u32 val = 0;
	u8 i = 0;
	u8 j = 0;
	u8 k = 0;
	/*u8 mask = 0x03;*/
	struct hal_mu_score_tbl *mu_sc_tbl = &bb->hal_com->bb_mu_score_tbl;
	u16 mu_score = 0;

	/* 
	Need to do MU protect to prevent error c2h sending
	this function will be return to prevent error c2h
	*/
	/*return val;*/

	mu_sc_tbl->mu_ctrl.mu_sc_thr = 1;
	mu_sc_tbl->mu_ctrl.mu_opt = 0;

	for (i = 0; i < HAL_MAX_MU_STA_NUM; i++) {
		k = (i << 1);
		mu_score = (c2h[k] | c2h[k + 1] << 8); /*check endian*/

		for (j = 0; j < (HAL_MAX_MU_STA_NUM - 1); j++) {
			mu_sc_tbl->mu_score[i].score[j] = (mu_score & 3);
			mu_score >>= 2;
		}
	}
#if 0
	for (i = 0; i < HAL_MAX_MU_STA_NUM; i++)
		for (j = 0; j < HAL_MAX_MU_SCORE_SIZE; j++) {
			if (mask == 0x03) {
				mu_sc_tbl->mu_score[i].score[j] = (c2h[k]&mask);
				mask = mask <<2;
			} else if (mask == 0x0c) {
				mu_sc_tbl->mu_score[i].score[j] = (c2h[k]&mask)>>2;
				mask = mask <<2;
			} else if (mask == 0x30) {
				mu_sc_tbl->mu_score[i].score[j] = (c2h[k]&mask)>>4;
				mask = mask <<2;
			} else { /*(mask == 0xc0) */
				mu_sc_tbl->mu_score[i].score[j] = (c2h[k]&mask)>>6;
				mask = 0x03;
				k++;
			}
		}
#endif 

	return val;
}

#ifdef HALBB_DYN_L2H_SUPPORT
u32 halbb_c2h_lowrt_rty(struct bb_info *bb, u16 len, u8 *c2h)
{
	u32 c2h_rty_cnt = 0;
	struct bb_dyn_l2h_info *dyn_l2h_i = &bb->bb_dyn_l2h_i;

	c2h_rty_cnt = (*c2h) + ((*(c2h+1))<<8);
	dyn_l2h_i->low_rate_rty_cnt += c2h_rty_cnt;
	return 0;
}

void halbb_fw_ctrl_rtyrpt(struct bb_info *bb, u8 rpt_rtycnt, u8 en_fw_rpt)
{
	struct bb_fw_dbg_cmn_info *fwmn_i = &bb->bb_fwdbg_i;
	u32 *bb_h2c = (u32 *) fwmn_i;
	u8 cmdlen = sizeof(struct bb_fw_dbg_cmn_info);
	bool ret_val = false;
	
	fwmn_i->fw_cmn_info |= (en_fw_rpt & 0x01);
	fwmn_i->fw_rty_rpt_ctrl = rpt_rtycnt;
	BB_DBG(bb, DBG_FW_INFO, "FW CTRL RTYRPT: %d %d\n", fwmn_i->fw_cmn_info, fwmn_i->fw_rty_rpt_ctrl);
	BB_DBG(bb, DBG_FW_INFO, "FW CMN CTRL: %x %x\n", bb_h2c[0], bb_h2c[1]);
	ret_val = halbb_fill_h2c_cmd(bb, cmdlen, DM_H2C_FWTRACE, HALBB_H2C_DM, bb_h2c);
}

#endif

/* Remove after 8852A B cut */
/*
u32 halbb_c2h_fw_trig_tx_rpt(struct bb_info *bb, u16 len, u8 *c2h)
{
	struct bb_c2h_fw_tx_rpt *fw_tx_i = &bb->bb_fwtx_c2h_i;
	bool tx_stat = c2h[0] & BIT(0);
	u32 val = (u32)false;
	
	if (tx_stat) {
		BB_DBG(bb, DBG_FW_INFO, "[FW][C2H] Tx done\n");
	} else {
		BB_DBG(bb, DBG_FW_INFO, "[FW][C2H] Tx fail\n");
	}

	// PD hit enable 
	halbb_set_reg(bb, 0xa3c, BIT(9), 0);
	halbb_set_reg(bb, 0xabc, BIT(9), 0);
		
	fw_tx_i->tx_done = tx_stat;
	
	val = (u32)true;
	return val;
}*/

u32 halbb_c2h_fw_h2c_test(struct bb_info *bb, u16 len, u8 *c2h)
{
	u16 i;
	u32 val = (u32)false;
	
	for (i = 0; i < len; i++) {
		BB_DBG(bb, DBG_FW_INFO, "FW H2C and C2H test: %d\n", c2h[i]);
	}
	return val;
}

u32 halbb_c2h_ra_parsing(struct bb_info *bb, u8 cmdid, u16 len, u8 *c2h)
{
	u32 val = 0;
	u16 i;

	BB_DBG(bb, DBG_FW_INFO, "FW C2H RA parsing: cmdid:%d len:%d\n", cmdid, len);
	BB_DBG(bb, DBG_FW_INFO, "FW C2H RA parsing: content ==>");

	for (i = 0; i < len; i++)
		BB_DBG(bb, DBG_FW_INFO, "%x", c2h[i]);
	BB_DBG(bb, DBG_FW_INFO, "<== \n ");
	switch(cmdid) {
	case HALBB_C2HRA_STS_RPT:
		val = halbb_get_fw_ra_rpt(bb, len, c2h);
		break;
	case HALBB_C2HRA_MU_GPTBL_RPT:
		val = halbb_c2h_mu_gptbl_rpt(bb, len, c2h);
		break;
	case HALBB_C2HRA_TXSTS:
		val = halbb_get_txsts_rpt(bb, len, c2h);
		break;
	case HALBB_C2HRA_TX_DBG_INFO:
		val = halbb_get_fw_ra_dbgrpt_wifi7(bb, len, c2h);
		break;
	case HALBB_C2HRA_TX_HIST:
		halbb_get_fw_c2h_tx_hist(bb, len, c2h);
		break;
	default:
		break;
	}
	return val;
}

u32 halbb_c2h_dm_parsing(struct bb_info *bb, u8 cmdid, u16 len, u8 *c2h)
{
	u32 val = 0;
	u16 i;

	BB_DBG(bb, DBG_FW_INFO, "FW C2H DM parsing: cmdid:%d len:%d\n", cmdid, len);
	BB_DBG(bb, DBG_FW_INFO, "FW C2H DM parsing: content ==>");
	for (i = 0; i < len; i++)
		BB_DBG(bb, DBG_FW_INFO, "%x", c2h[i]);
	BB_DBG(bb, DBG_FW_INFO, "<== \n ");
	switch(cmdid) {
	case DM_C2H_FW_TEST:
		val = halbb_c2h_fw_h2c_test(bb, len, c2h);
		break;
	case DM_C2H_FW_TRIG_TX_RPT: /* Remove after 8852A B cut */
		break;
	#ifdef HALBB_DYN_L2H_SUPPORT
	case DM_C2H_LOWRT_RTY:
		val = halbb_c2h_lowrt_rty(bb, len, c2h);
		break;
	#endif
	#ifdef HALBB_MCC_SUPPORT
	case DM_C2H_MCC:
		val = halbb_c2h_mccdm_check(bb, len, c2h);
		break;
	#endif
	#ifdef HALBB_PMAC_TX_SUPPORT
	case DM_C2H_EHTSIG:
		val = halbb_c2h_ehtsig_rpt(bb, len, c2h);
		break;
	#endif
	case DM_C2H_DBG:
		val = halbb_c2h_fw_dbg(bb, len, c2h);
	default:
		break;
	}
	return val;
}

u32 halbb_c2h_rua_parsing(struct bb_info *bb, u8 cmdid, u16 len, u8 *c2h)
{
	u32 val = 0;
	u8 *printaddr = c2h;
	int i = 0;
	int len_s = len - 4;
	BB_DBG(bb, DBG_RUA_TBL,"FW C2H RUA parsing: cmdid:%d len:%d\n", cmdid, len);
	BB_DBG(bb, DBG_RUA_TBL,"print len=%x, content==>\n", len);

	for (i = 0; i < len; i = i+4) {
		if(i > len_s)
			break;
        BB_DBG(bb, DBG_RUA_TBL,"%02x: %02x%02x%02x%02x\n", i, printaddr[i+3], printaddr[i+2], printaddr[i+1], printaddr[i]);
	}

	switch(cmdid) {
	case HALBB_C2HRUA_DBG:
		val = 1;
		break;
	default:
		break;
	}
	return val;
}

u32 rtw_halbb_c2h_parsing(struct bb_info *bb, u8 classid, u8 cmdid, u16 len, u8 *c2h)
{
	u32 val = 0;
	switch(classid) {
	case HALBB_C2H_RUA:
		val = halbb_c2h_rua_parsing(bb, cmdid, len, c2h);
		break;
	case HALBB_C2H_RA:
		val = halbb_c2h_ra_parsing(bb, cmdid, len, c2h);
		break;
	case HALBB_C2H_DM:
		val = halbb_c2h_dm_parsing(bb, cmdid, len, c2h);
		break;
	default:
		break;
	}
	return val;
}

enum rf_path halbb_config_path(struct bb_info *bb, enum phl_band_idx band_idx,
			u8 rf_num)
{
	enum rf_path path_set = RF_PATH_A;

	if (bb->num_rf_path == 1)
		path_set = RF_PATH_A;
	else if (bb->num_rf_path == 2)
		path_set = RF_PATH_AB;
	else if (bb->num_rf_path == 3)
		path_set = RF_PATH_ABC;
	else
		path_set = RF_PATH_ABCD;
	if (rf_num == 1) {
		if (bb->ic_type == BB_RTL8851B)
			path_set = RF_PATH_A;
		else
			path_set = RF_PATH_B;
	}
#ifdef HALBB_DBCC_SUPPORT
	/* While DBCC enable, PHY0 should set path_en = 0,
	PHY1 should set path_en = 1, and PHY0 Txpath_map_a should set 0, others
	will be config by HW
	*/

	if (bb->hal_com->dbcc_en) {
		if (band_idx == HW_BAND_0)
			path_set = RF_PATH_A;
		else
			path_set = RF_PATH_B;
	}
#endif
	return path_set;
}

enum rtw_hal_status
halbb_config_cmac_tbl_be(struct bb_info *bb, struct rtw_phl_stainfo_t *phl_sta_i,
			void *cmac_ctrl,
			void *cmac_ctrl_mask)
{
	enum rtw_hal_status ret = RTW_HAL_STATUS_FAILURE;
	/* tbd */
	ret = RTW_HAL_STATUS_SUCCESS;
	return ret;
}

enum rtw_hal_status
halbb_config_cmac_tbl_ax(struct bb_info *bb, struct rtw_phl_stainfo_t *phl_sta_i,
			void *cmac_ctrl,
			void *cmac_ctrl_mask)
{
	struct rtw_hal_mac_ax_cctl_info * cctrl = (struct rtw_hal_mac_ax_cctl_info *)cmac_ctrl;
	struct rtw_hal_mac_ax_cctl_info *cctl_info_mask = (struct rtw_hal_mac_ax_cctl_info *)cmac_ctrl_mask;
	enum rtw_hal_status ret = RTW_HAL_STATUS_FAILURE;
	enum rf_path path_set = RF_PATH_A;
	u16 cfg;
	u16 macid = 0;
	u8 rf_num = 0;
	bool dbcc_en = false;
	enum phl_band_idx band_idx = HW_BAND_0;

	if (NULL == phl_sta_i)
		return ret;
	
	band_idx = phl_sta_i->rlink->hw_band;
	rf_num = bb->phl_com->phy_cap[band_idx].tx_path_num;

	/* BB related mask */
	cctl_info_mask->txpwr_mode = 0x7;
	cctl_info_mask->ntx_path_en = 0xf;
	cctl_info_mask->path_map_a = 0x3;
	cctl_info_mask->path_map_b = 0x3;
	cctl_info_mask->path_map_c = 0x3;
	cctl_info_mask->path_map_d = 0x3;
	cctl_info_mask->antsel_a = 0x1;
	cctl_info_mask->antsel_b = 0x1;
	cctl_info_mask->antsel_c = 0x1;
	cctl_info_mask->antsel_d = 0x1;
	cctl_info_mask->doppler_ctrl = 0x3;
	cctl_info_mask->txpwr_tolerence = 0xf;

	/* BB related cmac tbl */
	path_set = halbb_config_path(bb, band_idx, rf_num);
	cctrl->txpwr_mode = 0; /* txpwr ctrl */
	cfg = halbb_cfg_cmac_tx_ant(bb, path_set);
	cctrl->ntx_path_en = cfg & 0x0f;
	cctrl->path_map_a = ((cfg>>4) & 0x03);
	cctrl->path_map_b = ((cfg>>6) & 0x03);
	cctrl->path_map_c = ((cfg>>8) & 0x03);
	cctrl->path_map_d = ((cfg>>10) & 0x03);
	cctrl->antsel_a = 0x0;
	cctrl->antsel_b = 0x0;
	cctrl->antsel_c = 0x0;
	cctrl->antsel_d = 0x0;
	cctrl->doppler_ctrl = 0;
	cctrl->txpwr_tolerence = 0;
	ret = RTW_HAL_STATUS_SUCCESS;
	BB_DBG(bb, DBG_FW_INFO, "HALBB CMAC tbl config: path = %x\n", cfg);
	return ret;
}



u8 halbb_set_cmac_txpwr_mode(struct bb_info *bb, struct rtw_phl_stainfo_t *phl_sta_i)
{
	/* power by macid */
	return 0;
}

u8 halbb_set_cmac_ntx_en(struct bb_info *bb, struct rtw_phl_stainfo_t *phl_sta_i)
{
	return 1;
}

u8 halbb_set_cmac_path_map_a(struct bb_info *bb, struct rtw_phl_stainfo_t *phl_sta_i)
{
	return 0;
}

u8 halbb_set_cmac_path_map_b(struct bb_info *bb, struct rtw_phl_stainfo_t *phl_sta_i)
{
	return 1;
}

u8 halbb_set_cmac_path_map_c(struct bb_info *bb, struct rtw_phl_stainfo_t *phl_sta_i)
{
	return 2;
}

u8 halbb_set_cmac_path_map_d(struct bb_info *bb, struct rtw_phl_stainfo_t *phl_sta_i)
{
	return 3;
}

u8 halbb_set_cmac_antsel_a(struct bb_info *bb, struct rtw_phl_stainfo_t *phl_sta_i)
{
	/* antenna selection*/
	return 0;
}

u8 halbb_set_cmac_antsel_b(struct bb_info *bb, struct rtw_phl_stainfo_t *phl_sta_i)
{
	return 0;
}

u8 halbb_set_cmac_antsel_c(struct bb_info *bb, struct rtw_phl_stainfo_t *phl_sta_i)
{
	return 0;
}

u8 halbb_set_cmac_antsel_d(struct bb_info *bb, struct rtw_phl_stainfo_t *phl_sta_i)
{
	return 0;
}

u8 halbb_set_cmac_pwr_tol(struct bb_info *bb, struct rtw_phl_stainfo_t *phl_sta_i)
{
	return 0;
}

u8 halbb_set_cmac_databw_er(struct bb_info *bb, struct rtw_phl_stainfo_t *phl_sta_i)
{
	/* 0: RU242, 1:RU106*/
	return 0;
}

bool halbb_set_pwr_by_rate_tbl(struct bb_info *bb, struct rtw_phl_stainfo_t *phl_sta_i)
{
	struct halbb_pwr_by_rate_tbl pwr_t = {{0}};
	u8 i = 0;
	enum rtw_data_rate ru_pwr_rate[PWR_TBL_NUM] = {RTW_DATA_RATE_HE_NSS1_MCS0, 
		RTW_DATA_RATE_HE_NSS1_MCS1, RTW_DATA_RATE_HE_NSS1_MCS2, 
		RTW_DATA_RATE_HE_NSS1_MCS3, RTW_DATA_RATE_HE_NSS1_MCS4, 
		RTW_DATA_RATE_HE_NSS1_MCS5, RTW_DATA_RATE_HE_NSS1_MCS6, 
		RTW_DATA_RATE_HE_NSS1_MCS7, RTW_DATA_RATE_HE_NSS1_MCS8, 
		RTW_DATA_RATE_HE_NSS1_MCS9, RTW_DATA_RATE_HE_NSS1_MCS10, 
		RTW_DATA_RATE_HE_NSS1_MCS11, RTW_DATA_RATE_HE_NSS2_MCS0, 
		RTW_DATA_RATE_HE_NSS2_MCS1, RTW_DATA_RATE_HE_NSS2_MCS2, 
		RTW_DATA_RATE_HE_NSS2_MCS3, RTW_DATA_RATE_HE_NSS2_MCS4, 
		RTW_DATA_RATE_HE_NSS2_MCS5, RTW_DATA_RATE_HE_NSS2_MCS6, 
		RTW_DATA_RATE_HE_NSS2_MCS7, RTW_DATA_RATE_HE_NSS2_MCS8, 
		RTW_DATA_RATE_HE_NSS2_MCS9, RTW_DATA_RATE_HE_NSS2_MCS10, 
		RTW_DATA_RATE_HE_NSS2_MCS11, RTW_DATA_RATE_HE_NSS1_MCS0, 
		RTW_DATA_RATE_HE_NSS1_MCS1, RTW_DATA_RATE_HE_NSS1_MCS3, 
		RTW_DATA_RATE_HE_NSS1_MCS4, RTW_DATA_RATE_HE_NSS2_MCS0, 
		RTW_DATA_RATE_HE_NSS2_MCS1, RTW_DATA_RATE_HE_NSS2_MCS3, 
		RTW_DATA_RATE_HE_NSS2_MCS4};
	u32 *pval = (u32 *)&pwr_t;
	u8 cmdlen = sizeof(pwr_t);
	u8 dcm = 0;
	enum rtw_data_rate rate;
	enum channel_width  bw = phl_sta_i->chandef.bw;
	u8 channel = phl_sta_i->chandef.center_ch;
	s16 pwr_db = 0;

	for (i = 0; i < PWR_TBL_NUM; i++) {
		rate = ru_pwr_rate[i];
		if (i >=24)
			dcm = 1;
		/*rtw_hal_rf_read_pwr_table(bb->hal_com, 0, rate, bw, channel, 0, dcm, 0, &pwr_db);*/
		pwr_t.pwr_by_rate[i*2] = (u8)(pwr_db&0xff);
		pwr_t.pwr_by_rate[i*2+1] = (u8)((pwr_db>>8)&0xff);
	}
	/* Get pwr by rate tbl from halrf */
	return halbb_fill_h2c_cmd(bb, cmdlen, RUA_H2C_PWR_TBL, HALBB_H2C_RUA, pval);
}
