// SPDX-License-Identifier: GPL-2.0
/* Copyright(c) 2007 - 2017 Realtek Corporation */

/* ************************************************************
 * include files
 * ************************************************************ */

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

void halrf_basic_profile(void *p_dm_void, u32 *_used, char *output,
			 u32 *_out_len)
{
	struct PHY_DM_STRUCT		*p_dm = (struct PHY_DM_STRUCT *)p_dm_void;
	u32 used = *_used;
	u32 out_len = *_out_len;

	/* HAL RF version List */
	PHYDM_SNPRINTF((output + used, out_len - used, "%-35s\n", "% HAL RF version %"));
	PHYDM_SNPRINTF((output + used, out_len - used, "  %-35s: %s\n", "Power Tracking", HALRF_POWRTRACKING_VER));
	PHYDM_SNPRINTF((output + used, out_len - used, "  %-35s: %s\n", "IQK", HALRF_IQK_VER));
	PHYDM_SNPRINTF((output + used, out_len - used, "  %-35s: %s\n", "LCK", HALRF_LCK_VER));
	PHYDM_SNPRINTF((output + used, out_len - used, "  %-35s: %s\n", "DPK", HALRF_DPK_VER));

	*_used = used;
	*_out_len = out_len;
}

void halrf_rf_lna_setting(void *p_dm_void, enum phydm_lna_set type)
{
}

void halrf_support_ability_debug(void *p_dm_void, char input[][16], u32 *_used,
				 char *output, u32 *_out_len)
{
	struct PHY_DM_STRUCT		*p_dm = (struct PHY_DM_STRUCT *)p_dm_void;
	struct _hal_rf_				*p_rf = &(p_dm->rf_table);
	u32	dm_value[10] = {0};
	u32 used = *_used;
	u32 out_len = *_out_len;
	u8	i;

	for (i = 0; i < 5; i++) {
		if (input[i + 1]) {
			PHYDM_SSCANF(input[i + 1], DCMD_DECIMAL, &dm_value[i]);
		}
	}
	
	PHYDM_SNPRINTF((output + used, out_len - used, "\n%s\n", "================================"));
	if (dm_value[0] == 100) {
		PHYDM_SNPRINTF((output + used, out_len - used, "[RF Supportability]\n"));
		PHYDM_SNPRINTF((output + used, out_len - used, "%s\n", "================================"));
		PHYDM_SNPRINTF((output + used, out_len - used, "00. (( %s ))Power Tracking\n", ((p_rf->rf_supportability & HAL_RF_TX_PWR_TRACK) ? ("V") : ("."))));
		PHYDM_SNPRINTF((output + used, out_len - used, "01. (( %s ))IQK\n", ((p_rf->rf_supportability & HAL_RF_IQK) ? ("V") : ("."))));
		PHYDM_SNPRINTF((output + used, out_len - used, "02. (( %s ))LCK\n", ((p_rf->rf_supportability & HAL_RF_LCK) ? ("V") : ("."))));
		PHYDM_SNPRINTF((output + used, out_len - used, "03. (( %s ))DPK\n", ((p_rf->rf_supportability & HAL_RF_DPK) ? ("V") : ("."))));
		PHYDM_SNPRINTF((output + used, out_len - used, "04. (( %s ))HAL_RF_TXGAPK\n", ((p_rf->rf_supportability & HAL_RF_TXGAPK) ? ("V") : ("."))));
		PHYDM_SNPRINTF((output + used, out_len - used, "%s\n", "================================"));		
	} else {
		if (dm_value[1] == 1) { /* enable */
			p_rf->rf_supportability |= BIT(dm_value[0]) ;
		} else if (dm_value[1] == 2) /* disable */
			p_rf->rf_supportability &= ~(BIT(dm_value[0])) ;
		else {
			PHYDM_SNPRINTF((output + used, out_len - used, "%s\n", "[Warning!!!]  1:enable,  2:disable"));
		}
	}
	PHYDM_SNPRINTF((output + used, out_len - used, "Curr-RF_supportability =  0x%x\n", p_rf->rf_supportability));
	PHYDM_SNPRINTF((output + used, out_len - used, "%s\n", "================================"));

	*_used = used;
	*_out_len = out_len;
}

void halrf_cmn_info_init(void *p_dm_void, enum halrf_cmninfo_init_e cmn_info,
			 u32 value)
{
	struct PHY_DM_STRUCT		*p_dm = (struct PHY_DM_STRUCT *)p_dm_void;
	struct _hal_rf_				*p_rf = &(p_dm->rf_table);

	switch	(cmn_info) {
	case	HALRF_CMNINFO_EEPROM_THERMAL_VALUE:
		p_rf->eeprom_thermal = (u8)value;
		break;
	case	HALRF_CMNINFO_FW_VER:
		p_rf->fw_ver = (u32)value;
		break;
	default:
		break;
	}
}


void halrf_cmn_info_hook(void *p_dm_void, enum halrf_cmninfo_hook_e cmn_info,
			 void *p_value)
{
	struct PHY_DM_STRUCT		*p_dm = (struct PHY_DM_STRUCT *)p_dm_void;
	struct _hal_rf_				*p_rf = &(p_dm->rf_table);
	
	switch	(cmn_info) {
	case	HALRF_CMNINFO_CON_TX:
		p_rf->p_is_con_tx = (bool *)p_value;
		break;
	case	HALRF_CMNINFO_SINGLE_TONE:
		p_rf->p_is_single_tone = (bool *)p_value;		
		break;
	case	HALRF_CMNINFO_CARRIER_SUPPRESSION:
		p_rf->p_is_carrier_suppresion = (bool *)p_value;		
		break;
	case	HALRF_CMNINFO_MP_RATE_INDEX:
		p_rf->p_mp_rate_index = (u8 *)p_value;
		break;
	default:
		/*do nothing*/
		break;
	}
}

void halrf_cmn_info_set(void *p_dm_void, u32 cmn_info, u64 value)
{
	/* This init variable may be changed in run time. */
	struct PHY_DM_STRUCT		*p_dm = (struct PHY_DM_STRUCT *)p_dm_void;
	struct _hal_rf_				*p_rf = &(p_dm->rf_table);
	
	switch	(cmn_info) {

		case	HALRF_CMNINFO_ABILITY:
			p_rf->rf_supportability = (u32)value;
			break;

		case	HALRF_CMNINFO_DPK_EN:
			p_rf->dpk_en = (u8)value;
			break;
		case HALRF_CMNINFO_RFK_FORBIDDEN :
			p_dm->IQK_info.rfk_forbidden = (bool)value;
			break;
		case HALRF_CMNINFO_RATE_INDEX:
			p_rf->p_rate_index = (u32)value;
			break;
		default:
			/* do nothing */
			break;
	}
}

u64 halrf_cmn_info_get(void *p_dm_void, u32 cmn_info)
{
	/* This init variable may be changed in run time. */
	struct PHY_DM_STRUCT		*p_dm = (struct PHY_DM_STRUCT *)p_dm_void;
	struct _hal_rf_				*p_rf = &(p_dm->rf_table);
	u64	return_value = 0;
	
	switch	(cmn_info) {
	case	HALRF_CMNINFO_ABILITY:
		return_value = (u32)p_rf->rf_supportability;
		break;
	case HALRF_CMNINFO_RFK_FORBIDDEN :
		return_value = p_dm->IQK_info.rfk_forbidden;
		break;
	default:
		break;
	}
	return	return_value;
}

static void halrf_supportability_init_mp(void *p_dm_void)
{
	struct PHY_DM_STRUCT		*p_dm = (struct PHY_DM_STRUCT *)p_dm_void;
	struct _hal_rf_				*p_rf = &(p_dm->rf_table);

	switch (p_dm->support_ic_type) {
	case ODM_RTL8814B:
		break;
	default:
		p_rf->rf_supportability = 
			HAL_RF_TX_PWR_TRACK	|
			HAL_RF_IQK		|
			HAL_RF_LCK		|
			0;
		break;
	}

	ODM_RT_TRACE(p_dm, ODM_COMP_INIT, ODM_DBG_LOUD, ("IC = ((0x%x)), RF_Supportability Init MP = ((0x%x))\n",
		     p_dm->support_ic_type, p_rf->rf_supportability));
}

void halrf_supportability_init(void *p_dm_void)
{
	struct PHY_DM_STRUCT		*p_dm = (struct PHY_DM_STRUCT *)p_dm_void;
	struct _hal_rf_				*p_rf = &(p_dm->rf_table);

	switch (p_dm->support_ic_type) {
	case ODM_RTL8814B:
		break;
	default:
		p_rf->rf_supportability = 
			HAL_RF_TX_PWR_TRACK	|
			HAL_RF_IQK		|
			HAL_RF_LCK		|
			0;
		break;
	}

	ODM_RT_TRACE(p_dm, ODM_COMP_INIT, ODM_DBG_LOUD, ("IC = ((0x%x)), RF_Supportability Init = ((0x%x))\n",
		     p_dm->support_ic_type, p_rf->rf_supportability));
}

void halrf_watchdog(void *p_dm_void)
{
	struct PHY_DM_STRUCT		*p_dm = (struct PHY_DM_STRUCT *)p_dm_void;
	phydm_rf_watchdog(p_dm);
}

void halrf_iqk_trigger(void *p_dm_void, bool is_recovery)
{
	struct PHY_DM_STRUCT		*p_dm = (struct PHY_DM_STRUCT *)p_dm_void;
	struct _IQK_INFORMATION		*p_iqk_info = &p_dm->IQK_info;
	struct _hal_rf_				*p_rf = &(p_dm->rf_table);
	u64 start_time;

	if ((p_dm->p_mp_mode) && (p_rf->p_is_con_tx) &&
	    (p_rf->p_is_single_tone) && (p_rf->p_is_carrier_suppresion))
		if (*(p_dm->p_mp_mode) && ((*(p_rf->p_is_con_tx) ||
		    *(p_rf->p_is_single_tone) ||
		    *(p_rf->p_is_carrier_suppresion))))
			return;

	if (!(p_rf->rf_supportability & HAL_RF_IQK))
		return;
#if DISABLE_BB_RF
	return;
#endif

	if (p_iqk_info->rfk_forbidden)
		return;

	if (!p_dm->rf_calibrate_info.is_iqk_in_progress) {
		odm_acquire_spin_lock(p_dm, RT_IQK_SPINLOCK);
		p_dm->rf_calibrate_info.is_iqk_in_progress = true;
		odm_release_spin_lock(p_dm, RT_IQK_SPINLOCK);
		start_time = odm_get_current_time(p_dm);
		switch (p_dm->support_ic_type) {
		case ODM_RTL8723D:
			phy_iq_calibrate_8723d(p_dm, is_recovery);
			break;
		default:
			break;
		}
		p_dm->rf_calibrate_info.iqk_progressing_time = odm_get_progressing_time(p_dm, start_time);
		ODM_RT_TRACE(p_dm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
			     ("[IQK]IQK progressing_time = %lld ms\n",
			      p_dm->rf_calibrate_info.iqk_progressing_time));

		odm_acquire_spin_lock(p_dm, RT_IQK_SPINLOCK);
		p_dm->rf_calibrate_info.is_iqk_in_progress = false;
		odm_release_spin_lock(p_dm, RT_IQK_SPINLOCK);
	} else {
		ODM_RT_TRACE(p_dm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
			     ("== Return the IQK CMD, because RFKs in Progress ==\n"));
	}
}

void halrf_lck_trigger(void *p_dm_void)
{
	struct PHY_DM_STRUCT		*p_dm = (struct PHY_DM_STRUCT *)p_dm_void;
	struct _IQK_INFORMATION		*p_iqk_info = &p_dm->IQK_info;
	struct _hal_rf_				*p_rf = &(p_dm->rf_table);
	u64 start_time;
	
	if ((p_dm->p_mp_mode) && (p_rf->p_is_con_tx) &&
	    (p_rf->p_is_single_tone) && (p_rf->p_is_carrier_suppresion))
		if (*(p_dm->p_mp_mode) && ((*(p_rf->p_is_con_tx) ||
		    *(p_rf->p_is_single_tone) ||
		    *(p_rf->p_is_carrier_suppresion))))
			return;
	if (!(p_rf->rf_supportability & HAL_RF_LCK))
		return;
#if DISABLE_BB_RF
		return;
#endif
	if (p_iqk_info->rfk_forbidden)
		return;
	while (*(p_dm->p_is_scan_in_process)) {
	       ODM_RT_TRACE(p_dm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
			    ("[LCK]scan is in process, bypass LCK\n"));
		return;
	}

	if (!p_dm->rf_calibrate_info.is_lck_in_progress) {
		odm_acquire_spin_lock(p_dm, RT_IQK_SPINLOCK);
		p_dm->rf_calibrate_info.is_lck_in_progress = true;
		odm_release_spin_lock(p_dm, RT_IQK_SPINLOCK);
		start_time = odm_get_current_time(p_dm);
		switch (p_dm->support_ic_type) {
		case ODM_RTL8723D:
			phy_lc_calibrate_8723d(p_dm);
			break;
		default:
			break;
		}
		p_dm->rf_calibrate_info.lck_progressing_time =
			 odm_get_progressing_time(p_dm, start_time);
		ODM_RT_TRACE(p_dm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
			     ("[IQK]LCK progressing_time = %lld ms\n",
			      p_dm->rf_calibrate_info.lck_progressing_time));
		odm_acquire_spin_lock(p_dm, RT_IQK_SPINLOCK);
		p_dm->rf_calibrate_info.is_lck_in_progress = false;
		odm_release_spin_lock(p_dm, RT_IQK_SPINLOCK);		
	} else {
		ODM_RT_TRACE(p_dm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
			     ("== Return the LCK CMD, because RFK is in Progress ==\n"));
	}
}

void halrf_init(void *p_dm_void)
{
	struct PHY_DM_STRUCT		*p_dm = (struct PHY_DM_STRUCT *)p_dm_void;
	
	ODM_RT_TRACE(p_dm, ODM_COMP_INIT, ODM_DBG_LOUD, ("HALRF_Init\n"));

	if (*(p_dm->p_mp_mode))
		halrf_supportability_init_mp(p_dm);
	else
		halrf_supportability_init(p_dm);
}
