/******************************************************************************
 *
 * 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.
 *
 *****************************************************************************/

 
#include "halrf_precomp.h"

u32 phlrf_psd_log2base(struct rf_info *rf, u32 val)
{
	u32 j;
	u32 tmp, tmp2, val_integerd_b = 0, tindex, shiftcount = 0;
	u32 result, val_fractiond_b = 0;
	u32 table_fraction[21] = {
		0, 432, 332, 274, 232, 200, 174, 151, 132, 115,
		100, 86, 74, 62, 51, 42, 32, 23, 15, 7, 0};

	if (val == 0)
		return 0;

	tmp = val;

	while (1) {
		if (tmp == 1)
			break;

		tmp = (tmp >> 1);
		shiftcount++;
	}

	val_integerd_b = shiftcount + 1;

	tmp2 = 1;
	for (j = 1; j <= val_integerd_b; j++)
		tmp2 = tmp2 * 2;

	tmp = (val * 100) / tmp2;
	tindex = tmp / 5;

	if (tindex > 20)
		tindex = 20;

	val_fractiond_b = table_fraction[tindex];

	result = val_integerd_b * 100 - val_fractiond_b;

	return result;
}

void phlrf_rf_lna_setting(struct rf_info *rf, enum phlrf_lna_set type)
{
	struct rtw_hal_com_t *hal_i = rf->hal_com;

	switch (hal_i->chip_id) {
#ifdef RF_8852A_SUPPORT
			case CHIP_WIFI6_8852A:
				break;
#endif
			default:
				break;
		}

}

void halrf_bkp(struct rf_info *rf, u32 *bp_reg, u32 *bp, u32 reg_num)
{
	u32 i;

	for (i = 0; i < reg_num; i++)
		bp[i] = halrf_rreg(rf, bp_reg[i], MASKDWORD);
}

void halrf_bkprf(struct rf_info *rf, u32 *bp_reg, u32 bp[][4], u32 reg_num, u32 path_num)
{
	u32 i, j;

	for (i = 0; i < reg_num; i++) {
		for (j = 0; j < path_num; j++)
			bp[i][j] = halrf_rrf(rf, j, bp_reg[i], MASKRF);
	}
}

void halrf_reload_bkp(struct rf_info *rf, u32 *bp_reg, u32 *bp, u32 reg_num)
{
	u32 i;

	for (i = 0; i < reg_num; i++)
		halrf_wreg(rf, bp_reg[i], MASKDWORD, bp[i]);
}

void halrf_reload_bkprf(struct rf_info *rf,
		       u32 *bp_reg,
		       u32 bp[][4],
		       u32 reg_num,
		       u8 path_num)
{
	u32 i, path;

	for (i = 0; i < reg_num; i++) {
		for (path = 0; path < path_num; path++)
			halrf_wrf(rf, (enum rf_path)path, bp_reg[i],
				       MASKRF, bp[i][path]);
	}
}

u8 halrf_kpath(struct rf_info *rf, enum phl_phy_idx phy_idx)
{
	struct rtw_hal_com_t *hal_i = rf->hal_com;

u8 path = 0;

	switch (hal_i->chip_id) {
#ifdef RF_8852A_SUPPORT
		case CHIP_WIFI6_8852A:
			path = halrf_kpath_8852a(rf, phy_idx);
			break;
#endif
		default:
			break;
	}
	return path;
}

void halrf_wait_rx_mode(struct rf_info *rf, u8 kpath)
{
	u8 path, rf_mode = 0;
	u16 count = 0;

	for (path = 0; path < 4; path++) {
		if (kpath & BIT(path)) {
			rf_mode = (u8)halrf_rrf(rf, path, 0x00, MASKRFMODE);

			while (rf_mode == 2 && count < 2500) {
				rf_mode = (u8)halrf_rrf(rf, path, 0x00, MASKRFMODE);
				halrf_delay_us(rf, 2);
				count++;
			}
			RF_DBG(rf, DBG_RF_RFK,
			       "[RFK] Wait S%d to Rx mode!! (count = %d)\n", path, count);
		}
	}
}

void halrf_tmac_tx_pause(struct rf_info *rf, enum phl_phy_idx band_idx, bool is_pause)
{
	halrf_tx_pause(rf, band_idx, is_pause, PAUSE_RSON_RFK);

	RF_DBG(rf, DBG_RF_RFK,"[RFK] Band%d Tx Pause %s!!\n",
	       band_idx, is_pause ? "on" : "off");

	if (is_pause)
		halrf_wait_rx_mode(rf, halrf_kpath(rf, band_idx));
}

void halrf_trigger_thermal(struct rf_info *rf)
{
	struct rtw_hal_com_t *hal_i = rf->hal_com;

	switch (hal_i->chip_id) {
#ifdef RF_8852A_SUPPORT
		case CHIP_WIFI6_8852A:
			halrf_trigger_thermal_8852a(rf, RF_PATH_A);
			halrf_trigger_thermal_8852a(rf, RF_PATH_B);
			break;
#endif
		default:
			break;
	}
}

u8 halrf_only_get_thermal(struct rf_info *rf, enum rf_path path)
{
	struct rtw_hal_com_t *hal_i = rf->hal_com;

	switch (hal_i->chip_id) {
#ifdef RF_8852A_SUPPORT
		case CHIP_WIFI6_8852A:
			return halrf_only_get_thermal_8852a(rf, path);
			break;
#endif
		default:
			break;
	}

	return 0;
}

void halrf_btc_rfk_ntfy(struct rf_info *rf, u8 phy_map, enum halrf_rfk_type type,
			enum halrf_rfk_process process)
{
	u32 cnt = 0;
	u8 band;
	/*idx : use BIT mask for RF path PATH A: 1, PATH B:2, PATH AB:3*/

	band = rf->hal_com->band[(phy_map & 0x30) >> 5].cur_chandef.band;

	phy_map = (band << 6) | phy_map;

	RF_DBG(rf, DBG_RF_RFK, "[RFK] RFK notify (%s / PHY%d / K_type = %d / path_idx = %d / process = %s)\n",
		band == 0 ? "2G" : (band == 1 ? "5G" : "6G"), (phy_map & 0x30) >> 5, type,
		phy_map & 0xf, process == 0 ? "RFK_STOP" : (process == 1 ? "RFK_START" :
		(process == 2 ? "ONE-SHOT_START" : "ONE-SHOT_STOP")));
#if 1
	if (process == RFK_START && rf->is_bt_iqk_timeout == false) {
		while (halrf_btc_ntfy(rf, phy_map, type, process) == 0 && cnt < 2500) {
			halrf_delay_us(rf, 40);
			cnt++;
		}
		if (cnt == 2500) {
			RF_DBG(rf, DBG_RF_RFK, "[RFK] Wait BT IQK timeout!!!!\n");
			rf->is_bt_iqk_timeout = true;
		}
	} else
		halrf_btc_ntfy(rf, phy_map, type, process);
#endif
}

void halrf_fcs_init(struct rf_info *rf)
{
	struct rtw_hal_com_t *hal_com = rf->hal_com;

#ifdef RF_8852A_SUPPORT
	if (hal_com->chip_id == CHIP_WIFI6_8852A)
		halrf_fcs_init_8852a(rf);
#endif
}

void halrf_fast_chl_sw_backup(struct rf_info *rf, u8 chl_index, u8 t_index)
{
	u32 t[2];

	t[0] = chl_index;
	t[1] = t_index;

	halrf_fill_h2c_cmd(rf, 8, FWCMD_H2C_BACKUP_RFK, 0xa, H2CB_TYPE_DATA, t);
	RF_DBG(rf, DBG_RF_RFK, "FWCMD_H2C_BACKUP_RFK chl=%d t=%d\n", chl_index, t_index);
}

void halrf_fast_chl_sw_reload(struct rf_info *rf, u8 chl_index, u8 t_index)
{
	u32 t[2];

	t[0] = chl_index;
	t[1] = t_index;

	halrf_fill_h2c_cmd(rf, 8, FWCMD_H2C_RELOAD_RFK, 0xa, H2CB_TYPE_DATA, t);
	RF_DBG(rf, DBG_RF_RFK, "FWCMD_H2C_RELOAD_RFK chl=%d t=%d\n", chl_index, t_index);
}

void  halrf_quick_check_rf(void *rf_void)
{
	struct rf_info *rf = (struct rf_info *)rf_void;
	struct rtw_hal_com_t *hal_com = rf->hal_com;

#ifdef RF_8852A_SUPPORT
	if (hal_com->chip_id == CHIP_WIFI6_8852A)
		halrf_quick_check_rfrx_8852a(rf);
#endif
#ifdef RF_8852B_SUPPORT
	if (hal_com->chip_id == CHIP_WIFI6_8852B)
		halrf_quick_checkrf_8852b(rf);
#endif
}

void halrf_wifi_event_notify(void *rf_void,
			enum phl_msg_evt_id event, enum phl_phy_idx phy_idx)
{
	struct rf_info *rf = (struct rf_info *)rf_void;

	if (event == MSG_EVT_SCAN_START) {
		halrf_tssi_default_txagc(rf, phy_idx, true);
		halrf_tssi_set_avg(rf, phy_idx, true);
		halrf_dpk_track_onoff(rf, false);
	} else if (event == MSG_EVT_SCAN_END) {
		halrf_tssi_default_txagc(rf, phy_idx, false);
		halrf_tssi_set_avg(rf, phy_idx, false);
		halrf_dpk_track_onoff(rf, true);
	} else if (event == MSG_EVT_DBG_RX_DUMP) {
		halrf_quick_check_rf(rf);
	} else if (event == MSG_EVT_SWCH_START) {
		halrf_tssi_backup_txagc(rf, phy_idx, true);
	}
}

void halrf_wreg_fw(struct rf_info *rf, u32 addr, u32 mask, u32 val)
{
#ifdef HALRF_CONFIG_FW_IO_OFLD_SUPPORT
	struct rtw_mac_cmd cmd = {0};
	struct halrf_fw_offload *fwofld_info = &rf->fwofld;
	bool fw_ofld = rf->phl_com->dev_cap.fw_cap.offload_cap & BIT(0);
	u32 rtn;

	RF_DBG(rf, DBG_RF_TX_PWR_TRACK,
		"======>%s addr=0x%x mask=0x%x val=0x%x fw_ofld=%d\n",
		__func__, addr, mask, val, fw_ofld);

	hal_mem_set(rf->hal_com, fwofld_info, 0, sizeof(*fwofld_info));

	if (fw_ofld) {
		cmd.src = RTW_MAC_BB_CMD_OFLD;
		cmd.type = RTW_MAC_WRITE_OFLD;
		cmd.lc = 0;
		cmd.offset = (u16)addr;
		cmd.value = val;
		cmd.mask = mask;

		fwofld_info->src = RTW_MAC_BB_CMD_OFLD;
		fwofld_info->type = RTW_MAC_WRITE_OFLD;
		fwofld_info->lc = 1;
		fwofld_info->offset = (u16)addr;
		fwofld_info->value = val;
		fwofld_info->mask = mask;

		rtn = halrf_mac_add_cmd_ofld(rf, &cmd);
		if (rtn) {
			RF_WARNING("======>%s return fail error code = %d !!!\n",
				__func__, rtn);
		}
	} else
#endif
		halrf_wreg(rf, addr, mask, val);
}

void halrf_wrf_fw(struct rf_info *rf,
			  enum rf_path path, u32 addr, u32 mask, u32 val)
{
#ifdef HALRF_CONFIG_FW_IO_OFLD_SUPPORT
	struct rtw_mac_cmd cmd = {0};
	struct halrf_fw_offload *fwofld_info = &rf->fwofld;
	bool fw_ofld = rf->phl_com->dev_cap.fw_cap.offload_cap & BIT(0);
	u32 rtn;

	RF_DBG(rf, DBG_RF_INIT,
		"======>%s addr=0x%x mask=0x%x val=0x%x fw_ofld=%d path=%d\n",
		__func__, addr, mask, val, fw_ofld, path);

	RF_DBG(rf, DBG_RF_TX_PWR_TRACK,
		"======>%s addr=0x%x mask=0x%x val=0x%x fw_ofld=%d path=%d\n",
		__func__, addr, mask, val, fw_ofld, path);

	hal_mem_set(rf->hal_com, fwofld_info, 0, sizeof(*fwofld_info));

	if (fw_ofld) {
		cmd.src = RTW_MAC_RF_CMD_OFLD;
		cmd.type = RTW_MAC_WRITE_OFLD;
		cmd.lc = 0;
		cmd.rf_path = path;
		cmd.offset = (u16)addr;
		cmd.value = val;
		cmd.mask = mask;

		fwofld_info->src = RTW_MAC_RF_CMD_OFLD;
		fwofld_info->type = RTW_MAC_WRITE_OFLD;
		fwofld_info->lc = 1;
		fwofld_info->rf_path = path;
		fwofld_info->offset = (u16)addr;
		fwofld_info->value = val;
		fwofld_info->mask = mask;

		rtn = halrf_mac_add_cmd_ofld(rf, &cmd);
		if (rtn) {
			RF_WARNING("======>%s return fail error code = %d !!!\n",
				__func__, rtn);
		}
	} else
#endif
		halrf_wrf(rf, path, addr, mask, val);
}

void halrf_wmac_fw(struct rf_info *rf, enum phl_phy_idx phy,
			u32 addr, u32 mask, u32 val)
{
#ifdef HALRF_CONFIG_FW_IO_OFLD_SUPPORT
	struct rtw_mac_cmd cmd = {0};
	struct halrf_fw_offload *fwofld_info = &rf->fwofld;
	bool fw_ofld = rf->phl_com->dev_cap.fw_cap.offload_cap & BIT(0);
	u32 rtn;

	RF_DBG(rf, DBG_RF_POWER,
		"======>%s addr=0x%x mask=0x%x val=0x%x fw_ofld=%d\n",
		__func__, addr, mask, val, fw_ofld);

	hal_mem_set(rf->hal_com, fwofld_info, 0, sizeof(*fwofld_info));

	if (fw_ofld) {
		cmd.src = RTW_MAC_MAC_CMD_OFLD;
		cmd.type = RTW_MAC_WRITE_OFLD;
		cmd.lc = 0;
		cmd.offset = (u16)addr;
		cmd.value = val;
		cmd.mask = mask;

		fwofld_info->src = RTW_MAC_MAC_CMD_OFLD;
		fwofld_info->type = RTW_MAC_WRITE_OFLD;
		fwofld_info->lc = 1;
		fwofld_info->offset = (u16)addr;
		fwofld_info->value = val;
		fwofld_info->mask = mask;

		rtn = halrf_mac_add_cmd_ofld(rf, &cmd);
		if (rtn) {
			RF_WARNING("======>%s return fail error code = %d !!!\n",
				__func__, rtn);
		}
	} else
#endif
		halrf_mac_set_pwr_reg(rf, phy, addr, mask, val);
}

void halrf_write_fw_final(struct rf_info *rf)
{
#ifdef HALRF_CONFIG_FW_IO_OFLD_SUPPORT
	struct rtw_mac_cmd cmd = {0};
	struct halrf_fw_offload *fwofld_info = &rf->fwofld;
	bool fw_ofld = rf->phl_com->dev_cap.fw_cap.offload_cap & BIT(0);
	u32 rtn;

	RF_DBG(rf, DBG_RF_TX_PWR_TRACK | DBG_RF_POWER,
		"======>%s src=%d type=%d lc=%d rf_path=%d\n",
		__func__, fwofld_info->src, fwofld_info->type,
		fwofld_info->lc, fwofld_info->rf_path);

	RF_DBG(rf, DBG_RF_TX_PWR_TRACK | DBG_RF_POWER,
		"======>%s offset=0x%x mask=0x%x value=0x%x fw_ofld=%d\n",
		__func__, fwofld_info->offset, fwofld_info->mask,
		fwofld_info->value, fw_ofld);

	cmd.src = fwofld_info->src;
	cmd.type = fwofld_info->type;
	cmd.lc = 1;
	cmd.rf_path = fwofld_info->rf_path;
	cmd.offset = fwofld_info->offset;
	cmd.value = fwofld_info->value;
	cmd.mask = fwofld_info->mask;

	if (fw_ofld) {
		rtn = halrf_mac_add_cmd_ofld(rf, &cmd);
		if (rtn) {
			RF_WARNING("======>%s return fail error code = %d !!!\n",
				__func__, rtn);
		}
	}
#endif
}

void halrf_ctrl_bw_ch(void *rf_void, enum phl_phy_idx phy, u8 central_ch,
				enum band_type band, enum channel_width bw)
{
	struct rf_info *rf = (struct rf_info *)rf_void;

	halrf_ctl_ch(rf, central_ch);
	halrf_ctl_bw(rf, bw);
	halrf_rxbb_bw(rf, phy, bw);
}

