/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
 *
 * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
 *
 * 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.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
 *
 *
 ******************************************************************************/

#include "mp_precomp.h"
#include "../phydm_precomp.h"


/* ======================================================================== */
/* These following functions can be used for PHY DM only*/

u32	reg82c_8821c;
u32	reg838_8821c;
u32	reg830_8821c;
u32	rega24_8821c;
u32	rega28_8821c;
u32	regaac_8821c;

enum odm_bw_e	bw_8821c;
u8	central_ch_8821c;

void
phydm_rxdfirpar_by_bw_8821c(
	struct PHY_DM_STRUCT				*p_dm_odm,
	enum odm_bw_e				bandwidth
)
{
	if (bandwidth == ODM_BW40M) {
		/* RX DFIR for BW40 */
		odm_set_bb_reg(p_dm_odm, 0x948, BIT(29) | BIT(28), 0x2);
		odm_set_bb_reg(p_dm_odm, 0x94c, BIT(29) | BIT(28), 0x2);
		odm_set_bb_reg(p_dm_odm, 0xc20, BIT(31), 0x0);
		odm_set_bb_reg(p_dm_odm, 0x8f0, BIT(31), 0x0);
	} else if (bandwidth == ODM_BW80M) {
		/* RX DFIR for BW80 */
		odm_set_bb_reg(p_dm_odm, 0x948, BIT(29) | BIT(28), 0x2);
		odm_set_bb_reg(p_dm_odm, 0x94c, BIT(29) | BIT(28), 0x1);
		odm_set_bb_reg(p_dm_odm, 0xc20, BIT(31), 0x0);
		odm_set_bb_reg(p_dm_odm, 0x8f0, BIT(31), 0x1);
	} else {
		/* RX DFIR for BW20, BW10 and BW5*/
		odm_set_bb_reg(p_dm_odm, 0x948, BIT(29) | BIT(28), 0x2);
		odm_set_bb_reg(p_dm_odm, 0x94c, BIT(29) | BIT(28), 0x2);
		odm_set_bb_reg(p_dm_odm, 0xc20, BIT(31), 0x1);
		odm_set_bb_reg(p_dm_odm, 0x8f0, BIT(31), 0x0);
	}
}

void
phydm_init_hw_info_by_rfe_type_8821c(
	struct PHY_DM_STRUCT				*p_dm_odm
)
{
	p_dm_odm->is_init_hw_info_by_rfe = false;
	/*2.4G default rf set with wlg or btg*/
	if (p_dm_odm->rfe_type == 2 || p_dm_odm->rfe_type == 4 || p_dm_odm->rfe_type == 7)
		p_dm_odm->default_rf_set_8821c = SWITCH_TO_BTG;
	else if (p_dm_odm->rfe_type == 0 || p_dm_odm->rfe_type == 1 || p_dm_odm->rfe_type == 3 || p_dm_odm->rfe_type == 5 || p_dm_odm->rfe_type == 6)
		p_dm_odm->default_rf_set_8821c = SWITCH_TO_WLG;
	else if (p_dm_odm->rfe_type == 0x22 || p_dm_odm->rfe_type == 0x24 || p_dm_odm->rfe_type == 0x27) {
		p_dm_odm->default_rf_set_8821c = SWITCH_TO_BTG;
		odm_cmn_info_init(p_dm_odm, ODM_CMNINFO_PACKAGE_TYPE, 1);
	} else if (p_dm_odm->rfe_type == 0x20 || p_dm_odm->rfe_type == 0x21 || p_dm_odm->rfe_type == 0x23 || p_dm_odm->rfe_type == 0x25 || p_dm_odm->rfe_type == 0x26) {
		p_dm_odm->default_rf_set_8821c = SWITCH_TO_WLG;
		odm_cmn_info_init(p_dm_odm, ODM_CMNINFO_PACKAGE_TYPE, 1);
	}

	if (p_dm_odm->rfe_type == 3 || p_dm_odm->rfe_type == 4 || p_dm_odm->rfe_type == 0x23 || p_dm_odm->rfe_type == 0x24)
		p_dm_odm->default_ant_num_8821c = SWITCH_TO_ANT2;
	else
		p_dm_odm->default_ant_num_8821c = SWITCH_TO_ANT1;

	p_dm_odm->is_init_hw_info_by_rfe = true;
	ODM_RT_TRACE(p_dm_odm, ODM_PHY_CONFIG, ODM_DBG_TRACE, ("%s: RFE type (%d), rf set (%s)\n", __FUNCTION__, p_dm_odm->rfe_type, (p_dm_odm->default_rf_set_8821c == 0 ? "BTG" : "WLG")));
}

void
phydm_set_gnt_state_8821c(
	struct PHY_DM_STRUCT			*p_dm_odm,
	boolean				gnt_wl_state,
	boolean				gnt_bt_state
)
{
	u32		gnt_val = 0;

	odm_set_mac_reg(p_dm_odm, 0x70, BIT(26), 0x1);

	if (gnt_wl_state)
		gnt_val = 0x3300;
	else
		gnt_val = 0x1100;

	if (gnt_bt_state)
		gnt_val = gnt_val | 0xcc00;
	else
		gnt_val = gnt_val | 0x4400;

	odm_set_mac_reg(p_dm_odm, 0x1704, MASKLWORD, gnt_val);
	ODM_delay_us(50); /*waiting before access 0x1700 */
	odm_set_mac_reg(p_dm_odm, 0x1700, MASKDWORD, 0xc00f0038);
}
/* ======================================================================== */

/* ======================================================================== */
/* These following functions can be used by driver*/

u32
config_phydm_read_rf_reg_8821c(
	struct PHY_DM_STRUCT				*p_dm_odm,
	enum odm_rf_radio_path_e		rf_path,
	u32					reg_addr,
	u32					bit_mask
)
{
	u32	readback_value, direct_addr;
	u32	offset_read_rf[2] = {0x2800, 0x2c00};
	u32	power_RF[2] = {0x1c, 0xec};

	/* Error handling.*/
	if (rf_path > ODM_RF_PATH_A) {
		ODM_RT_TRACE(p_dm_odm, ODM_PHY_CONFIG, ODM_DBG_TRACE, ("[%s]: unsupported path (%d)\n", __func__, rf_path));
		return INVALID_RF_DATA;
	}

	/*  Error handling. Check if RF power is enable or not */
	/*  0xffffffff means RF power is disable */
	if (odm_get_mac_reg(p_dm_odm, power_RF[rf_path], MASKBYTE3) != 0x7) {
		ODM_RT_TRACE(p_dm_odm, ODM_PHY_CONFIG, ODM_DBG_TRACE, ("[%s]: Read fail, RF is disabled\n", __func__));
		return INVALID_RF_DATA;
	}

	/* Calculate offset */
	reg_addr &= 0xff;
	direct_addr = offset_read_rf[rf_path] + (reg_addr << 2);

	/* RF register only has 20bits */
	bit_mask &= RFREGOFFSETMASK;

	/* Read RF register directly */
	readback_value = odm_get_bb_reg(p_dm_odm, direct_addr, bit_mask);
	ODM_RT_TRACE(p_dm_odm, ODM_PHY_CONFIG, ODM_DBG_TRACE, ("[%s]: RF-%d 0x%x = 0x%x, bit mask = 0x%x\n",
			__func__, rf_path, reg_addr, readback_value, bit_mask));
	return readback_value;
}

boolean
config_phydm_write_rf_reg_8821c(
	struct PHY_DM_STRUCT				*p_dm_odm,
	enum odm_rf_radio_path_e		rf_path,
	u32					reg_addr,
	u32					bit_mask,
	u32					data
)
{
	u32	data_and_addr = 0, data_original = 0;
	u32	offset_write_rf[2] = {0xc90, 0xe90};
	u32	power_RF[2] = {0x1c, 0xec};
	u8	bit_shift;

	/* Error handling.*/
	if (rf_path > ODM_RF_PATH_A) {
		ODM_RT_TRACE(p_dm_odm, ODM_PHY_CONFIG, ODM_DBG_TRACE, ("[%s]: unsupported path (%d)\n", __func__, rf_path));
		return false;
	}

	/* Read RF register content first */
	reg_addr &= 0xff;
	bit_mask = bit_mask & RFREGOFFSETMASK;

	if (bit_mask != RFREGOFFSETMASK) {
		data_original = config_phydm_read_rf_reg_8821c(p_dm_odm, rf_path, reg_addr, RFREGOFFSETMASK);

		/* Error handling. RF is disabled */
		if (config_phydm_read_rf_check_8821c(data_original) == false) {
			ODM_RT_TRACE(p_dm_odm, ODM_PHY_CONFIG, ODM_DBG_TRACE, ("[%s]: Write fail, RF is disable\n", __func__));
			return false;
		}

		/* check bit mask */
		if (bit_mask != 0xfffff) {
			for (bit_shift = 0; bit_shift <= 19; bit_shift++) {
				if (((bit_mask >> bit_shift) & 0x1) == 1)
					break;
			}
			data = ((data_original)&(~bit_mask)) | (data << bit_shift);
		}
	} else if (odm_get_mac_reg(p_dm_odm, power_RF[rf_path], MASKBYTE3) != 0x7) {
		ODM_RT_TRACE(p_dm_odm, ODM_PHY_CONFIG, ODM_DBG_TRACE, ("[%s]: Write fail, RF is disabled\n", __func__));
		return false;
	}

	/* Put write addr in [27:20]  and write data in [19:00] */
	data_and_addr = ((reg_addr << 20) | (data & 0x000fffff)) & 0x0fffffff;

	/* Write operation */
	odm_set_bb_reg(p_dm_odm, offset_write_rf[rf_path], MASKDWORD, data_and_addr);
	ODM_RT_TRACE(p_dm_odm, ODM_PHY_CONFIG, ODM_DBG_TRACE, ("[%s]: RF-%d 0x%x = 0x%x (original: 0x%x), bit mask = 0x%x\n",
		__func__, rf_path, reg_addr, data, data_original, bit_mask));
	return true;
}

boolean
config_phydm_write_txagc_8821c(
	struct PHY_DM_STRUCT				*p_dm_odm,
	u32					power_index,
	enum odm_rf_radio_path_e		path,
	u8					hw_rate
)
{
	u32	offset_txagc[2] = {0x1d00, 0x1d80};
	u8	rate_idx = (hw_rate & 0xfc);

	/* Input need to be HW rate index, not driver rate index!!!! */

	if (p_dm_odm->is_disable_phy_api) {
		ODM_RT_TRACE(p_dm_odm, ODM_PHY_CONFIG, ODM_DBG_TRACE, ("[%s]: disable PHY API for debug!!\n", __func__));
		return true;
	}

	/* Error handling */
	if ((path > ODM_RF_PATH_A) || (hw_rate > 0x53)) {
		ODM_RT_TRACE(p_dm_odm, ODM_PHY_CONFIG, ODM_DBG_TRACE, ("[%s]: unsupported path (%d)\n", __func__, path));
		return false;
	}

	/* driver need to construct a 4-byte power index */
	odm_set_bb_reg(p_dm_odm, (offset_txagc[path] + rate_idx), MASKDWORD, power_index);

	ODM_RT_TRACE(p_dm_odm, ODM_PHY_CONFIG, ODM_DBG_TRACE, ("[%s]: path-%d rate index 0x%x (0x%x) = 0x%x\n",
		__func__, path, hw_rate, (offset_txagc[path] + hw_rate), power_index));
	return true;
}

u8
config_phydm_read_txagc_8821c(
	struct PHY_DM_STRUCT				*p_dm_odm,
	enum odm_rf_radio_path_e		path,
	u8					hw_rate
)
{
	u8	read_back_data;

	/* Input need to be HW rate index, not driver rate index!!!! */

	/* Error handling */
	if ((path > ODM_RF_PATH_A) || (hw_rate > 0x53)) {
		ODM_RT_TRACE(p_dm_odm, ODM_PHY_CONFIG, ODM_DBG_TRACE, ("[%s]: unsupported path (%d)\n", __func__, path));
		return INVALID_TXAGC_DATA;
	}

	/* Disable TX AGC report */
	odm_set_bb_reg(p_dm_odm, 0x1998, BIT(16), 0x0);							/* need to check */

	/* Set data rate index (bit0~6) and path index (bit7) */
	odm_set_bb_reg(p_dm_odm, 0x1998, MASKBYTE0, (hw_rate | (path << 7)));

	/* Enable TXAGC report */
	odm_set_bb_reg(p_dm_odm, 0x1998, BIT(16), 0x1);

	/* Read TX AGC report */
	read_back_data = (u8)odm_get_bb_reg(p_dm_odm, 0xd30, 0x7f0000);

	/* Driver have to disable TXAGC report after reading TXAGC (ref. user guide v11) */
	odm_set_bb_reg(p_dm_odm, 0x1998, BIT(16), 0x0);

	ODM_RT_TRACE(p_dm_odm, ODM_PHY_CONFIG, ODM_DBG_TRACE, ("[%s]: path-%d rate index 0x%x = 0x%x\n", __func__, path, hw_rate, read_back_data));
	return read_back_data;
}

boolean
config_phydm_switch_band_8821c(
	struct PHY_DM_STRUCT				*p_dm_odm,
	u8					central_ch
)
{
	u32		rf_reg18;
	boolean		rf_reg_status = true;

	ODM_RT_TRACE(p_dm_odm, ODM_PHY_CONFIG, ODM_DBG_TRACE, ("[%s]======================>\n", __func__));

	if (p_dm_odm->is_disable_phy_api) {
		ODM_RT_TRACE(p_dm_odm, ODM_PHY_CONFIG, ODM_DBG_TRACE, ("[%s]: disable PHY API for debug!!\n", __func__));
		return true;
	}

	rf_reg18 = config_phydm_read_rf_reg_8821c(p_dm_odm, ODM_RF_PATH_A, 0x18, RFREGOFFSETMASK);
	rf_reg_status = rf_reg_status & config_phydm_read_rf_check_8821c(rf_reg18);

	if (central_ch <= 14) {
		/* 2.4G */

		/* Enable CCK block */
		odm_set_bb_reg(p_dm_odm, 0x808, BIT(28), 0x1);

		/* Disable MAC CCK check */
		odm_set_bb_reg(p_dm_odm, 0x454, BIT(7), 0x0);

		/* Disable BB CCK check */
		odm_set_bb_reg(p_dm_odm, 0xa80, BIT(18), 0x0);

		/*CCA Mask*/
		odm_set_bb_reg(p_dm_odm, 0x814, 0x0000FC00, 15); /*default value*/

		/* RF band */
		rf_reg18 = (rf_reg18 & (~(BIT(16) | BIT(9) | BIT(8))));

		/* Switch WLG/BTG*/
		if (p_dm_odm->default_rf_set_8821c == SWITCH_TO_BTG)
			config_phydm_switch_rf_set_8821c(p_dm_odm, SWITCH_TO_BTG);
		else if (p_dm_odm->default_rf_set_8821c == SWITCH_TO_WLG)
			config_phydm_switch_rf_set_8821c(p_dm_odm, SWITCH_TO_WLG);

		/*RF TXA_TANK LUT mode*/
		odm_set_rf_reg(p_dm_odm, ODM_RF_PATH_A, 0xdf, BIT(6), 0x1);

		/*RF TXA_PA_TANK*/
		odm_set_rf_reg(p_dm_odm, ODM_RF_PATH_A, 0x64, 0x0000f, 0xf);

	} else if (central_ch > 35) {
		/* 5G */

		/* Enable BB CCK check */
		odm_set_bb_reg(p_dm_odm, 0xa80, BIT(18), 0x1);

		/* Enable CCK check */
		odm_set_bb_reg(p_dm_odm, 0x454, BIT(7), 0x1);

		/* Disable CCK block */
		odm_set_bb_reg(p_dm_odm, 0x808, BIT(28), 0x0);

		/*CCA Mask*/
		odm_set_bb_reg(p_dm_odm, 0x814, 0x0000FC00, 15); /*default value*/
		/*odm_set_bb_reg(p_dm_odm, 0x814, 0x0000FC00, 34); CCA mask = 13.6us*/

		/* RF band */
		rf_reg18 = (rf_reg18 & (~(BIT(16) | BIT(9) | BIT(8))));
		rf_reg18 = (rf_reg18 | BIT(8) | BIT(16));

		/* Switch WLA */
		config_phydm_switch_rf_set_8821c(p_dm_odm, SWITCH_TO_WLA);

		/*RF TXA_TANK LUT mode*/
		odm_set_rf_reg(p_dm_odm, ODM_RF_PATH_A, 0xdf, BIT(6), 0x0);

	} else {
		ODM_RT_TRACE(p_dm_odm, ODM_PHY_CONFIG, ODM_DBG_TRACE, ("[%s]: Fail to switch band (ch: %d)\n", __func__, central_ch));
		return false;
	}

	rf_reg_status = rf_reg_status & config_phydm_write_rf_reg_8821c(p_dm_odm, ODM_RF_PATH_A, 0x18, RFREGOFFSETMASK, rf_reg18);

	if (rf_reg_status == false) {
		ODM_RT_TRACE(p_dm_odm, ODM_PHY_CONFIG, ODM_DBG_TRACE, ("[%s]: Fail to switch band (ch: %d), because writing RF register is fail\n", __func__, central_ch));
		return false;
	}

	ODM_RT_TRACE(p_dm_odm, ODM_PHY_CONFIG, ODM_DBG_TRACE, ("[%s]: Success to switch band (ch: %d)\n", __func__, central_ch));
	return true;
}

boolean
config_phydm_switch_channel_8821c(
	struct PHY_DM_STRUCT				*p_dm_odm,
	u8					central_ch
)
{
	struct _dynamic_initial_gain_threshold_		*p_dm_dig_table = &p_dm_odm->dm_dig_table;
	u32		rf_reg18, rf_reg_b8 = 0;
	boolean		rf_reg_status = true;

	ODM_RT_TRACE(p_dm_odm, ODM_PHY_CONFIG, ODM_DBG_TRACE, ("[%s]====================>\n", __func__));

	if (p_dm_odm->is_disable_phy_api) {
		ODM_RT_TRACE(p_dm_odm, ODM_PHY_CONFIG, ODM_DBG_TRACE, ("[%s]: disable PHY API for debug!!\n", __func__));
		return true;
	}

	central_ch_8821c = central_ch;
	rf_reg18 = config_phydm_read_rf_reg_8821c(p_dm_odm, ODM_RF_PATH_A, 0x18, RFREGOFFSETMASK);
	rf_reg_status = rf_reg_status & config_phydm_read_rf_check_8821c(rf_reg18);

	if (p_dm_odm->cut_version == ODM_CUT_A) {
		rf_reg_b8 = config_phydm_read_rf_reg_8821c(p_dm_odm, ODM_RF_PATH_A, 0xb8, RFREGOFFSETMASK);
		rf_reg_status = rf_reg_status & config_phydm_read_rf_check_8821c(rf_reg_b8);
	}

	/* Switch band and channel */
	if (central_ch <= 14) {
		/* 2.4G */

		/* 1. RF band and channel*/
		rf_reg18 = (rf_reg18 & (~(BIT(18) | BIT(17) | MASKBYTE0)));
		rf_reg18 = (rf_reg18 | central_ch);

		/* 2. AGC table selection */
		odm_set_bb_reg(p_dm_odm, 0xc1c, 0x00000F00, 0x0);
		p_dm_dig_table->agc_table_idx = 0x0;

		/* 3. Set central frequency for clock offset tracking */
		odm_set_bb_reg(p_dm_odm, 0x860, 0x1ffe0000, 0x96a);

		/* Fix A-cut LCK fail issue @ 5285MHz~5375MHz, 0xb8[19]=0x0 */
		if (p_dm_odm->cut_version == ODM_CUT_A)
			rf_reg_b8 = rf_reg_b8 | BIT(19);

		/* CCK TX filter parameters */
		if (central_ch == 14) {
			odm_set_bb_reg(p_dm_odm, 0xa24, MASKDWORD, 0x0000b81c);
			odm_set_bb_reg(p_dm_odm, 0xa28, MASKLWORD, 0x0000);
			odm_set_bb_reg(p_dm_odm, 0xaac, MASKDWORD, 0x00003667);
		} else {
			odm_set_bb_reg(p_dm_odm, 0xa24, MASKDWORD, rega24_8821c);
			odm_set_bb_reg(p_dm_odm, 0xa28, MASKLWORD, (rega28_8821c & MASKLWORD));
			odm_set_bb_reg(p_dm_odm, 0xaac, MASKDWORD, regaac_8821c);
		}

	} else if (central_ch > 35) {
		/* 5G */

		/* 1. RF band and channel*/
		rf_reg18 = (rf_reg18 & (~(BIT(18) | BIT(17) | MASKBYTE0)));
		rf_reg18 = (rf_reg18 | central_ch);

		if (central_ch >= 36 && central_ch <= 64)
			;
		else if ((central_ch >= 100) && (central_ch <= 140))
			rf_reg18 = (rf_reg18 | BIT(17));
		else if (central_ch > 140)
			rf_reg18 = (rf_reg18 | BIT(18));
		else {
			ODM_RT_TRACE(p_dm_odm, ODM_PHY_CONFIG, ODM_DBG_TRACE, ("[%s]: Fail to switch channel (RF18) (ch: %d)\n", __func__, central_ch));
			return false;
		}

		/* 2. AGC table selection */
		if ((central_ch >= 36) && (central_ch <= 64)) {
			odm_set_bb_reg(p_dm_odm, 0xc1c, 0x00000F00, 0x1);
			p_dm_dig_table->agc_table_idx = 0x1;
		} else if ((central_ch >= 100) && (central_ch <= 144)) {
			odm_set_bb_reg(p_dm_odm, 0xc1c, 0x00000F00, 0x2);
			p_dm_dig_table->agc_table_idx = 0x2;
		} else if (central_ch >= 149) {
			odm_set_bb_reg(p_dm_odm, 0xc1c, 0x00000F00, 0x3);
			p_dm_dig_table->agc_table_idx = 0x3;
		} else {
			ODM_RT_TRACE(p_dm_odm, ODM_PHY_CONFIG, ODM_DBG_TRACE, ("[%s]: Fail to switch channel (AGC) (ch: %d)\n", __func__, central_ch));
			return false;
		}

		/* 3. Set central frequency for clock offset tracking */
		if ((central_ch >= 36) && (central_ch <= 48))
			odm_set_bb_reg(p_dm_odm, 0x860, 0x1ffe0000, 0x494);
		else if ((central_ch >= 52) && (central_ch <= 64))
			odm_set_bb_reg(p_dm_odm, 0x860, 0x1ffe0000, 0x453);
		else if ((central_ch >= 100) && (central_ch <= 116))
			odm_set_bb_reg(p_dm_odm, 0x860, 0x1ffe0000, 0x452);
		else if ((central_ch >= 118) && (central_ch <= 177))
			odm_set_bb_reg(p_dm_odm, 0x860, 0x1ffe0000, 0x412);
		else {
			ODM_RT_TRACE(p_dm_odm, ODM_PHY_CONFIG, ODM_DBG_TRACE, ("[%s]: Fail to switch channel (fc_area) (ch: %d)\n", __func__, central_ch));
			return false;
		}

		/* Fix A-cut LCK fail issue @ 5285MHz~5375MHz, 0xb8[19]=0x0 */
		if (p_dm_odm->cut_version == ODM_CUT_A) {
			if ((central_ch >= 57) && (central_ch <= 75))
				rf_reg_b8 = rf_reg_b8 & (~BIT(19));
			else
				rf_reg_b8 = rf_reg_b8 | BIT(19);
		}

	} else {
		ODM_RT_TRACE(p_dm_odm, ODM_PHY_CONFIG, ODM_DBG_TRACE, ("[%s]: Fail to switch band (ch: %d)\n", __func__, central_ch));
		return false;
	}

	rf_reg_status = rf_reg_status & config_phydm_write_rf_reg_8821c(p_dm_odm, ODM_RF_PATH_A, 0x18, RFREGOFFSETMASK, rf_reg18);

	if (p_dm_odm->cut_version == ODM_CUT_A)
		rf_reg_status = rf_reg_status & config_phydm_write_rf_reg_8821c(p_dm_odm, ODM_RF_PATH_A, 0xb8, RFREGOFFSETMASK, rf_reg_b8);

	if (rf_reg_status == false) {
		ODM_RT_TRACE(p_dm_odm, ODM_PHY_CONFIG, ODM_DBG_TRACE, ("[%s]: Fail to switch channel (ch: %d), because writing RF register is fail\n", __func__, central_ch));
		return false;
	}

	ODM_RT_TRACE(p_dm_odm, ODM_PHY_CONFIG, ODM_DBG_TRACE, ("[%s]: Success to switch channel (ch: %d)\n", __func__, central_ch));
	return true;
}

boolean
config_phydm_switch_bandwidth_8821c(
	struct PHY_DM_STRUCT				*p_dm_odm,
	u8					primary_ch_idx,
	enum odm_bw_e				bandwidth
)
{
	u32		rf_reg18;
	boolean		rf_reg_status = true;

	ODM_RT_TRACE(p_dm_odm, ODM_PHY_CONFIG, ODM_DBG_TRACE, ("[%s]===================>\n", __func__));

	if (p_dm_odm->is_disable_phy_api) {
		ODM_RT_TRACE(p_dm_odm, ODM_PHY_CONFIG, ODM_DBG_TRACE, ("[%s]: disable PHY API for debug!!\n", __func__));
		return true;
	}

	/* Error handling */
	if ((bandwidth >= ODM_BW_MAX) || ((bandwidth == ODM_BW40M) && (primary_ch_idx > 2)) || ((bandwidth == ODM_BW80M) && (primary_ch_idx > 4))) {
		ODM_RT_TRACE(p_dm_odm, ODM_PHY_CONFIG, ODM_DBG_TRACE, ("[%s]: Fail to switch bandwidth (bw: %d, primary ch: %d)\n", __func__, bandwidth, primary_ch_idx));
		return false;
	}

	bw_8821c = bandwidth;
	rf_reg18 = config_phydm_read_rf_reg_8821c(p_dm_odm, ODM_RF_PATH_A, 0x18, RFREGOFFSETMASK);
	rf_reg_status = rf_reg_status & config_phydm_read_rf_check_8821c(rf_reg18);

	/* Switch bandwidth */
	switch (bandwidth) {
	case ODM_BW20M:
	{
		/* Small BW([7:6]) = 0, primary channel ([5:2]) = 0, rf mode([1:0]) = 20M */
		odm_set_bb_reg(p_dm_odm, 0x8ac, MASKBYTE0, ODM_BW20M);

		/* ADC clock = 160M clock for BW20 */
		odm_set_bb_reg(p_dm_odm, 0x8ac, (BIT(9) | BIT(8)), 0x0);
		odm_set_bb_reg(p_dm_odm, 0x8ac, BIT(16), 0x1);

		/* DAC clock = 160M clock for BW20 */
		odm_set_bb_reg(p_dm_odm, 0x8ac, (BIT(21) | BIT(20)), 0x0);
		odm_set_bb_reg(p_dm_odm, 0x8ac, BIT(28), 0x1);

		/* ADC buffer clock */
		odm_set_bb_reg(p_dm_odm, 0x8c4, BIT(30), 0x1);

		/* RF bandwidth */
		rf_reg18 = (rf_reg18 | BIT(11) | BIT(10));

		break;
	}
	case ODM_BW40M:
	{
		/* Small BW([7:6]) = 0, primary channel ([5:2]) = sub-channel, rf mode([1:0]) = 40M */
		odm_set_bb_reg(p_dm_odm, 0x8ac, MASKBYTE0, (((primary_ch_idx & 0xf) << 2) | ODM_BW40M));

		/* CCK primary channel */
		if (primary_ch_idx == 1)
			odm_set_bb_reg(p_dm_odm, 0xa00, BIT(4), primary_ch_idx);
		else
			odm_set_bb_reg(p_dm_odm, 0xa00, BIT(4), 0);

		/* ADC clock = 160M clock for BW40 */
		odm_set_bb_reg(p_dm_odm, 0x8ac, (BIT(11) | BIT(10)), 0x0);
		odm_set_bb_reg(p_dm_odm, 0x8ac, BIT(17), 0x1);

		/* DAC clock = 160M clock for BW20 */
		odm_set_bb_reg(p_dm_odm, 0x8ac, (BIT(23) | BIT(22)), 0x0);
		odm_set_bb_reg(p_dm_odm, 0x8ac, BIT(29), 0x1);

		/* ADC buffer clock */
		odm_set_bb_reg(p_dm_odm, 0x8c4, BIT(30), 0x1);

		/* RF bandwidth */
		rf_reg18 = (rf_reg18 & (~(BIT(11) | BIT(10))));
		rf_reg18 = (rf_reg18 | BIT(11));

		break;
	}
	case ODM_BW80M:
	{
		/* Small BW([7:6]) = 0, primary channel ([5:2]) = sub-channel, rf mode([1:0]) = 80M */
		odm_set_bb_reg(p_dm_odm, 0x8ac, MASKBYTE0, (((primary_ch_idx & 0xf) << 2) | ODM_BW80M));

		/* ADC clock = 160M clock for BW80 */
		odm_set_bb_reg(p_dm_odm, 0x8ac, (BIT(13) | BIT(12)), 0x0);
		odm_set_bb_reg(p_dm_odm, 0x8ac, BIT(18), 0x1);

		/* DAC clock = 160M clock for BW20 */
		odm_set_bb_reg(p_dm_odm, 0x8ac, (BIT(25) | BIT(24)), 0x0);
		odm_set_bb_reg(p_dm_odm, 0x8ac, BIT(30), 0x1);

		/* ADC buffer clock */
		odm_set_bb_reg(p_dm_odm, 0x8c4, BIT(30), 0x1);

		/* RF bandwidth */
		rf_reg18 = (rf_reg18 & (~(BIT(11) | BIT(10))));
		rf_reg18 = (rf_reg18 | BIT(10));

		break;
	}
	case ODM_BW5M:
	{
		/* Small BW([7:6]) = 1, primary channel ([5:2]) = 0, rf mode([1:0]) = 20M */
		odm_set_bb_reg(p_dm_odm, 0x8ac, MASKBYTE0, (BIT(6) | ODM_BW20M));

		/* ADC clock = 40M clock */
		odm_set_bb_reg(p_dm_odm, 0x8ac, (BIT(9) | BIT(8)), 0x2);
		odm_set_bb_reg(p_dm_odm, 0x8ac, BIT(16), 0x0);

		/* DAC clock = 160M clock for BW20 */
		odm_set_bb_reg(p_dm_odm, 0x8ac, (BIT(21) | BIT(20)), 0x2);
		odm_set_bb_reg(p_dm_odm, 0x8ac, BIT(28), 0x0);

		/* ADC buffer clock */
		odm_set_bb_reg(p_dm_odm, 0x8c4, BIT(30), 0x0);
		odm_set_bb_reg(p_dm_odm, 0x8c8, BIT(31), 0x1);

		/* RF bandwidth */
		rf_reg18 = (rf_reg18 | BIT(11) | BIT(10));

		break;
	}
	case ODM_BW10M:
	{
		/* Small BW([7:6]) = 1, primary channel ([5:2]) = 0, rf mode([1:0]) = 20M */
		odm_set_bb_reg(p_dm_odm, 0x8ac, MASKBYTE0, (BIT(7) | ODM_BW20M));

		/* ADC clock = 80M clock */
		odm_set_bb_reg(p_dm_odm, 0x8ac, (BIT(9) | BIT(8)), 0x3);
		odm_set_bb_reg(p_dm_odm, 0x8ac, BIT(16), 0x0);

		/* DAC clock = 160M clock for BW20 */
		odm_set_bb_reg(p_dm_odm, 0x8ac, (BIT(21) | BIT(20)), 0x3);
		odm_set_bb_reg(p_dm_odm, 0x8ac, BIT(28), 0x0);

		/* ADC buffer clock */
		odm_set_bb_reg(p_dm_odm, 0x8c4, BIT(30), 0x0);
		odm_set_bb_reg(p_dm_odm, 0x8c8, BIT(31), 0x1);

		/* RF bandwidth */
		rf_reg18 = (rf_reg18 | BIT(11) | BIT(10));

		break;
	}
	default:
		ODM_RT_TRACE(p_dm_odm, ODM_PHY_CONFIG, ODM_DBG_TRACE, ("[%s]: Fail to switch bandwidth (bw: %d, primary ch: %d)\n", __func__, bandwidth, primary_ch_idx));
	}

	/* Write RF register */
	rf_reg_status = rf_reg_status & config_phydm_write_rf_reg_8821c(p_dm_odm, ODM_RF_PATH_A, 0x18, RFREGOFFSETMASK, rf_reg18);

	if (rf_reg_status == false) {
		ODM_RT_TRACE(p_dm_odm, ODM_PHY_CONFIG, ODM_DBG_TRACE, ("[%s]: Fail to switch bandwidth (bw: %d, primary ch: %d), because writing RF register is fail\n", __func__, bandwidth, primary_ch_idx));
		return false;
	}

	/* Modify RX DFIR parameters */
	phydm_rxdfirpar_by_bw_8821c(p_dm_odm, bandwidth);

	ODM_RT_TRACE(p_dm_odm, ODM_PHY_CONFIG, ODM_DBG_TRACE, ("[%s]: Success to switch bandwidth (bw: %d, primary ch: %d)\n", __func__, bandwidth, primary_ch_idx));
	return true;
}

boolean
config_phydm_parameter_init_8821c(
	struct PHY_DM_STRUCT				*p_dm_odm,
	enum odm_parameter_init_e	type
)
{
	if (type == ODM_PRE_SETTING) {
		odm_set_bb_reg(p_dm_odm, 0x808, (BIT(28) | BIT(29)), 0x0);
		ODM_RT_TRACE(p_dm_odm, ODM_PHY_CONFIG, ODM_DBG_TRACE, ("[%s]: Pre setting: disable OFDM and CCK block\n", __func__));
	} else if (type == ODM_POST_SETTING) {
		odm_set_bb_reg(p_dm_odm, 0x808, (BIT(28) | BIT(29)), 0x3);
		ODM_RT_TRACE(p_dm_odm, ODM_PHY_CONFIG, ODM_DBG_TRACE, ("[%s]: Post setting: enable OFDM and CCK block\n", __func__));
		reg82c_8821c = odm_get_bb_reg(p_dm_odm, 0x82c, MASKDWORD);
		reg838_8821c = odm_get_bb_reg(p_dm_odm, 0x838, MASKDWORD);
		reg830_8821c = odm_get_bb_reg(p_dm_odm, 0x830, MASKDWORD);
		rega24_8821c = odm_get_bb_reg(p_dm_odm, 0xa24, MASKDWORD);
		rega28_8821c = odm_get_bb_reg(p_dm_odm, 0xa28, MASKDWORD);
		regaac_8821c = odm_get_bb_reg(p_dm_odm, 0xaac, MASKDWORD);
	} else {
		ODM_RT_TRACE(p_dm_odm, ODM_PHY_CONFIG, ODM_DBG_TRACE, ("[%s]: Wrong type!!\n", __func__));
		return false;
	}

	return true;
}

void
config_phydm_switch_rf_set_8821c(
	struct PHY_DM_STRUCT			*p_dm_odm,
	u8				rf_set
)
{
	u32		bb_reg32;

	odm_set_mac_reg(p_dm_odm, 0x1080, BIT(16), 0x1);
	odm_set_mac_reg(p_dm_odm, 0x00, BIT(26), 0x1);
	/*odm_set_mac_reg(p_dm_odm, 0x70, BIT(26), 0x1);*/
	/*odm_set_mac_reg(p_dm_odm, 0x1704, MASKLWORD, 0x4000);*/
	/*odm_set_mac_reg(p_dm_odm, 0x1700, (BIT(31) | BIT(30)), 0x3); */

	bb_reg32 = odm_get_bb_reg(p_dm_odm, 0xcb8, MASKDWORD);
	switch (rf_set) {

	case SWITCH_TO_BTG:

		p_dm_odm->current_rf_set_8821c = SWITCH_TO_BTG;

		bb_reg32 = (bb_reg32 | BIT(16));
		bb_reg32 &= (~(BIT(18) | BIT(20) | BIT(21) | BIT(22) | BIT(23)));
		if (p_dm_odm->mp_mode == true)
		{
			odm_config_bb_with_header_file(p_dm_odm, CONFIG_BB_AGC_TAB_DIFF);
			/*Toggle initial gain twice for valid gain table*/
			odm_set_bb_reg(p_dm_odm, ODM_REG(IGI_A, p_dm_odm), ODM_BIT(IGI, p_dm_odm), 0x22);
			odm_set_bb_reg(p_dm_odm, ODM_REG(IGI_A, p_dm_odm), ODM_BIT(IGI, p_dm_odm), 0x20);
		}
		break;
	case SWITCH_TO_WLG:

		p_dm_odm->current_rf_set_8821c = SWITCH_TO_WLG;

		bb_reg32 = (bb_reg32 | BIT(20) | BIT(21) | BIT(22));
		bb_reg32 &= (~(BIT(16) | BIT(18) | BIT(23)));
		if (p_dm_odm->mp_mode == true)
		{
			odm_config_bb_with_header_file(p_dm_odm, CONFIG_BB_AGC_TAB_DIFF);
			/*Toggle initial gain twice for valid gain table*/
			odm_set_bb_reg(p_dm_odm, ODM_REG(IGI_A, p_dm_odm), ODM_BIT(IGI, p_dm_odm), 0x22);
			odm_set_bb_reg(p_dm_odm, ODM_REG(IGI_A, p_dm_odm), ODM_BIT(IGI, p_dm_odm), 0x20);
		}
		break;
	case SWITCH_TO_WLA:

		p_dm_odm->current_rf_set_8821c = SWITCH_TO_WLA;

		bb_reg32 = (bb_reg32 | BIT(20) | BIT(22) | BIT(23));
		bb_reg32 &= (~(BIT(16) | BIT(18) | BIT(21)));

		break;
	case SWITCH_TO_BT:

		p_dm_odm->current_rf_set_8821c = SWITCH_TO_BT;

		break;
	default:
		break;

	}

	odm_set_bb_reg(p_dm_odm, 0xcb8, MASKDWORD, bb_reg32);

}

void
config_phydm_set_ant_path(
	struct PHY_DM_STRUCT				*p_dm_odm,
	u8				rf_set,
	u8				ant_num
)
{
	boolean		switch_polarity_inverse = false;
	u8			regval_0xcb7 = 0;

	p_dm_odm->current_ant_num_8821c = ant_num;
	config_phydm_switch_rf_set_8821c(p_dm_odm, rf_set);

	if (rf_set == SWITCH_TO_BT)
		phydm_set_gnt_state_8821c(p_dm_odm, false, true); /* GNT_WL=0, GNT_BT=1 for BT test */
	else
		phydm_set_gnt_state_8821c(p_dm_odm, true, false); /* GNT_WL=1, GNT_BT=0 for WL test */

	if (p_dm_odm->rfe_type == 0x5 || p_dm_odm->rfe_type == 0x6 || p_dm_odm->rfe_type == 0x25 || p_dm_odm->rfe_type == 0x26) /*switch does not exist*/
		return;

	if (p_dm_odm->current_ant_num_8821c) /*Ant1 = 0, Ant2 = 1*/
		switch_polarity_inverse = !switch_polarity_inverse;

	if (rf_set == SWITCH_TO_WLG)
		switch_polarity_inverse = !switch_polarity_inverse;

	/*set antenna control by WL 0xcb4[29:28]*/
	odm_set_mac_reg(p_dm_odm, 0x4c, BIT(24)|BIT(23), 0x2);

	/*set RFE_ctrl8 and RFE_ctrl9 as antenna control pins by software*/
	odm_set_bb_reg(p_dm_odm, 0xcb4, 0x000000ff, 0x77);

	/*0xcb4[29:28] = 2b'01 for no switch_polatiry_inverse, DPDT_SEL_N =1, DPDT_SEL_P =0*/
	regval_0xcb7 = (switch_polarity_inverse == false ? 0x1 : 0x2);

	odm_set_bb_reg(p_dm_odm, 0xcb4, 0x30000000, regval_0xcb7);

}

u32
query_phydm_trx_capability_8821c(
	struct PHY_DM_STRUCT				*p_dm_odm
)
{
	u32 value32 = 0x00000000;

	ODM_RT_TRACE(p_dm_odm, ODM_PHY_CONFIG, ODM_DBG_TRACE, ("[%s]: trx_capability = 0x%x\n", __func__, value32));
	return value32;
}

u32
query_phydm_stbc_capability_8821c(
	struct PHY_DM_STRUCT				*p_dm_odm
)
{
	u32 value32 = 0x00010001;

	ODM_RT_TRACE(p_dm_odm, ODM_PHY_CONFIG, ODM_DBG_TRACE, ("[%s]: stbc_capability = 0x%x\n", __func__, value32));
	return value32;
}

u32
query_phydm_ldpc_capability_8821c(
	struct PHY_DM_STRUCT				*p_dm_odm
)
{
	u32 value32 = 0x01000100;

	ODM_RT_TRACE(p_dm_odm, ODM_PHY_CONFIG, ODM_DBG_TRACE, ("[%s]: ldpc_capability = 0x%x\n", __func__, value32));
	return value32;
}

u32
query_phydm_txbf_parameters_8821c(
	struct PHY_DM_STRUCT				*p_dm_odm
)
{
	u32 value32 = 0x00030003;

	ODM_RT_TRACE(p_dm_odm, ODM_PHY_CONFIG, ODM_DBG_TRACE, ("[%s]: txbf_parameters = 0x%x\n", __func__, value32));
	return value32;
}

u32
query_phydm_txbf_capability_8821c(
	struct PHY_DM_STRUCT				*p_dm_odm
)
{
	u32 value32 = 0x01010001;

	ODM_RT_TRACE(p_dm_odm, ODM_PHY_CONFIG, ODM_DBG_TRACE, ("[%s]: txbf_capability = 0x%x\n", __func__, value32));
	return value32;
}

u8
query_phydm_default_rf_set_8821c(
	struct PHY_DM_STRUCT				*p_dm_odm
)
{
	return p_dm_odm->default_rf_set_8821c;
}

u8
query_phydm_current_ant_num_8821c(
	struct PHY_DM_STRUCT				*p_dm_odm
)
{
	u32				regval_0xcb4 = odm_get_bb_reg(p_dm_odm, 0xcb4, BIT(29)|BIT(28));

	if (p_dm_odm->current_rf_set_8821c == SWITCH_TO_BTG || p_dm_odm->current_rf_set_8821c == SWITCH_TO_WLA || p_dm_odm->current_rf_set_8821c == SWITCH_TO_BT) {
		if (regval_0xcb4 == 1)
			p_dm_odm->current_ant_num_8821c = SWITCH_TO_ANT1;
		else if (regval_0xcb4 == 2)
			p_dm_odm->current_ant_num_8821c = SWITCH_TO_ANT2;
	else
		if (regval_0xcb4 == 1)
			p_dm_odm->current_ant_num_8821c = SWITCH_TO_ANT2;
		else if (regval_0xcb4 == 2)
			p_dm_odm->current_ant_num_8821c = SWITCH_TO_ANT1;
	}

	return p_dm_odm->current_ant_num_8821c;
}
