Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
/******************************************************************************
 *
 * 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 _PHL_INIT_C_
#include "phl_headers.h"

void _phl_com_init_rssi_stat(struct rtw_phl_com_t *phl_com)
{
	u8 i = 0, j = 0;
	for (i = 0; i < RTW_RSSI_TYPE_MAX; i++) {
		phl_com->rssi_stat.ma_rssi_ele_idx[i] = 0;
		phl_com->rssi_stat.ma_rssi_ele_cnt[i] = 0;
		phl_com->rssi_stat.ma_rssi_ele_sum[i] = 0;
		phl_com->rssi_stat.ma_rssi[i] = 0;
		for (j = 0; j < PHL_RSSI_MAVG_NUM; j++)
			phl_com->rssi_stat.ma_rssi_ele[i][j] = 0;
	}
	_os_spinlock_init(phl_com->drv_priv, &(phl_com->rssi_stat.lock));
}

void _phl_com_deinit_rssi_stat(struct rtw_phl_com_t *phl_com)
{
	_os_spinlock_free(phl_com->drv_priv, &(phl_com->rssi_stat.lock));
}

/**
 * rtw_phl_init_ppdu_sts_para(...)
 * Description:
 * 	1. Do not call this api after rx started.
 * 	2. PPDU Status per PKT settings
 **/
void rtw_phl_init_ppdu_sts_para(struct rtw_phl_com_t *phl_com,
				bool en_psts_per_pkt, bool psts_ampdu,
				u8 rx_fltr)
{
#ifdef CONFIG_PHL_RX_PSTS_PER_PKT
	phl_com->ppdu_sts_info.en_psts_per_pkt = en_psts_per_pkt;
	phl_com->ppdu_sts_info.psts_ampdu = psts_ampdu;
#ifdef RTW_WKARD_DISABLE_PSTS_PER_PKT_DATA
	/* Forced disable PSTS for DATA frame, to avoid unknown performance issue */
	rx_fltr &= (~RTW_PHL_PSTS_FLTR_DATA);
#endif
	phl_com->ppdu_sts_info.ppdu_sts_filter = rx_fltr;
#else
	return;
#endif
}

void _phl_com_deinit_ppdu_sts(struct rtw_phl_com_t *phl_com)
{
#ifdef CONFIG_PHL_RX_PSTS_PER_PKT
	u8 i = 0;
	u8 j = 0;
	for (j = 0; j < HW_BAND_MAX; j++) {
		for (i = 0; i < PHL_MAX_PPDU_CNT; i++) {
			if (phl_com->ppdu_sts_info.sts_ent[j][i].frames.cnt != 0) {
				PHL_INFO("[Error] deinit_ppdu_sts : frame queue is not empty\n");
			}
			pq_deinit(phl_com->drv_priv,
				  &(phl_com->ppdu_sts_info.sts_ent[j][i].frames));
		}
	}
#else
	return;
#endif
}

void _phl_com_init_ppdu_sts(struct rtw_phl_com_t *phl_com)
{
#ifdef CONFIG_PHL_RX_PSTS_PER_PKT
	u8 i = 0;
#endif
	u8 j = 0;
	for (j = 0; j < HW_BAND_MAX; j++) {
		phl_com->ppdu_sts_info.cur_rx_ppdu_cnt[j] = 0xFF;
	}
#ifdef CONFIG_PHL_RX_PSTS_PER_PKT
	/* Default enable when compile flag is set. */
	phl_com->ppdu_sts_info.en_psts_per_pkt = true;
	/**
	 * Filter of buffer pkt for phy status:
	 *	if the correspond bit is set to 1,
	 *	the pkt will be buffer till ppdu sts or next ppdu is processed.
	 **/
	phl_com->ppdu_sts_info.ppdu_sts_filter =
			RTW_PHL_PSTS_FLTR_MGNT | RTW_PHL_PSTS_FLTR_CTRL |
			RTW_PHL_PSTS_FLTR_EXT_RSVD;

	/* if set to false, only the first mpdu in ppdu has phy status */
	phl_com->ppdu_sts_info.psts_ampdu = false;

	phl_com->ppdu_sts_info.en_fake_psts = false;

	for (j = 0; j < HW_BAND_MAX; j++) {
		for (i = 0; i < PHL_MAX_PPDU_CNT; i++) {
			pq_init(phl_com->drv_priv,
				&(phl_com->ppdu_sts_info.sts_ent[j][i].frames));
		}
	}
#endif
#ifdef CONFIG_PHY_INFO_NTFY
	phl_com->ppdu_sts_info.msg_aggr_cnt = 0;
#endif
}

static void phl_msg_entry(void* priv, struct phl_msg *msg)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)priv;
	u8 mdl_id = MSG_MDL_ID_FIELD(msg->msg_id);
	u16 evt_id = MSG_EVT_ID_FIELD(msg->msg_id);

	PHL_DBG("[PHL]%s, mdl_id(%d)\n", __FUNCTION__, mdl_id);

	/* dispatch received PHY msg here */
	switch(mdl_id) {
		case PHL_MDL_PHY_MGNT:
			phl_msg_hub_phy_mgnt_evt_hdlr(phl_info, evt_id);
			break;
		case PHL_MDL_RX:
			phl_msg_hub_rx_evt_hdlr(phl_info, evt_id, msg->inbuf, msg->inlen);
			break;
		case PHL_MDL_BTC:
			rtw_phl_btc_hub_msg_hdl(phl_info, msg);
			break;
		default:
			break;
	}
}

static enum rtw_phl_status phl_register_msg_entry(struct phl_info_t *phl_info)
{
	struct phl_msg_receiver ctx;
	void *d = phl_to_drvpriv(phl_info);
	u8 imr[] = {PHL_MDL_PHY_MGNT, PHL_MDL_RX, PHL_MDL_MRC, PHL_MDL_POWER_MGNT
			, PHL_MDL_BTC};
	_os_mem_set(d, &ctx, 0, sizeof(struct phl_msg_receiver));
	ctx.incoming_evt_notify = phl_msg_entry;
	ctx.priv = (void*)phl_info;
	if( phl_msg_hub_register_recver((void*)phl_info,
				&ctx, MSG_RECV_PHL) == RTW_PHL_STATUS_SUCCESS) {
		/* PHL layer module should set IMR for receiving
		desired PHY msg  and handle it in phl_phy_evt_entry*/
		phl_msg_hub_update_recver_mask((void*)phl_info, MSG_RECV_PHL,
						imr, sizeof(imr), false);
		return RTW_PHL_STATUS_SUCCESS;
	}
	else
		return RTW_PHL_STATUS_FAILURE;

}

static enum rtw_phl_status phl_deregister_msg_entry(
					struct phl_info_t *phl_info)
{
	return phl_msg_hub_deregister_recver((void*)phl_info, MSG_RECV_PHL);
}

static enum rtw_phl_status phl_fw_init(struct phl_info_t *phl_info)
{
	enum rtw_phl_status phl_status = RTW_PHL_STATUS_RESOURCE;
	struct rtw_phl_com_t *phl_com = phl_info->phl_com;
	struct rtw_fw_info_t *fw_info = &phl_com->fw_info;

	FUNCIN_WSTS(phl_status);

	fw_info->rom_buff = _os_mem_alloc(phl_to_drvpriv(phl_info), RTW_MAX_FW_SIZE);

	if (!fw_info->rom_buff) {
		PHL_ERR("%s : rom buff allocate fail!!\n", __func__);
		goto mem_alloc_fail;
	}

	fw_info->ram_buff = _os_mem_alloc(phl_to_drvpriv(phl_info), RTW_MAX_FW_SIZE);

	if (!fw_info->ram_buff) {
		PHL_ERR("%s : ram buff allocate fail!!\n", __func__);
		goto mem_alloc_fail;
	}

#ifdef CONFIG_PHL_REUSED_FWDL_BUF
	fw_info->buf = _os_mem_alloc(phl_to_drvpriv(phl_info), RTW_MAX_FW_SIZE);

	/* if allocating failed, fw bin files will be reading every time */
	if (!fw_info->buf)
		PHL_WARN("%s : buf for fw storage allocate fail!!\n", __func__);

	fw_info->wow_buf = _os_mem_alloc(phl_to_drvpriv(phl_info), RTW_MAX_FW_SIZE);

	/* if allocating failed, fw bin files will be reading every time */
	if (!fw_info->wow_buf)
		PHL_WARN("%s : wow buf for wowlan fw storage allocate fail!!\n", __func__);
#endif

	phl_status = RTW_PHL_STATUS_SUCCESS;

	FUNCOUT_WSTS(phl_status);

mem_alloc_fail:
	return phl_status;
}

static void phl_fw_deinit(struct phl_info_t *phl_info)
{
	struct rtw_fw_info_t *fw_info = &phl_info->phl_com->fw_info;

	if (fw_info->rom_buff)
		_os_mem_free(phl_to_drvpriv(phl_info), fw_info->rom_buff,
			RTW_MAX_FW_SIZE);
	if (fw_info->ram_buff)
		_os_mem_free(phl_to_drvpriv(phl_info), fw_info->ram_buff,
			RTW_MAX_FW_SIZE);

#ifdef CONFIG_REUSED_FWDL_BUF
	if (fw_info->buf)
		_os_mem_free(phl_to_drvpriv(phl_info), fw_info->buf,
			RTW_MAX_FW_SIZE);
	if (fw_info->wow_buf)
		_os_mem_free(phl_to_drvpriv(phl_info), fw_info->wow_buf,
			RTW_MAX_FW_SIZE);
#endif

	/* allocate in rtw_hal_ld_fw_symbol */
	if (fw_info->sym_buf)
		_os_mem_free(phl_to_drvpriv(phl_info), fw_info->sym_buf,
			RTW_MAX_FW_SIZE);
}
static enum rtw_phl_status
phl_register_background_module_entry(struct phl_info_t *phl_info)
{
	enum rtw_phl_status phl_status = RTW_PHL_STATUS_FAILURE;
#ifdef CONFIG_CMD_DISP
	/*
	 * setup struct phl_module_ops & call dispr_register_module
	 * to register background module instance.
	 * call dispr_deregister_module if you need to dynamically
	 * deregister the instance of background module.
	*/

	/* 1,2,3 cmd controller section */


	/* 41 ~ 70 mandatory background module section*/
#ifdef CONFIG_PHL_CMD_SER
	phl_status = phl_register_ser_module(phl_info);
	if (phl_status != RTW_PHL_STATUS_SUCCESS)
		return phl_status;
#endif
#ifdef CONFIG_POWER_SAVE
	phl_status = phl_register_ps_module(phl_info);
	if (phl_status != RTW_PHL_STATUS_SUCCESS)
		return phl_status;
#endif
	/* 70 ~ 127 optional background module section*/
#ifdef CONFIG_PHL_CMD_BTC
	phl_status = phl_register_btc_module(phl_info);
	if (phl_status != RTW_PHL_STATUS_SUCCESS)
		return phl_status;
#endif
	phl_status = phl_register_custom_module(phl_info, HW_BAND_0);
	if (phl_status != RTW_PHL_STATUS_SUCCESS)
		return phl_status;

	phl_status = phl_register_led_module(phl_info);
	if (phl_status != RTW_PHL_STATUS_SUCCESS)
		return phl_status;

	phl_status = phl_register_cmd_general(phl_info);
	if (phl_status != RTW_PHL_STATUS_SUCCESS)
		return phl_status;

	/* 10 ~ 40 protocol, wifi role section*/
	phl_status = phl_register_mrc_module(phl_info);
	if (phl_status != RTW_PHL_STATUS_SUCCESS)
		return phl_status;

	phl_status = phl_snd_cmd_register_module(phl_info);
	if (phl_status != RTW_PHL_STATUS_SUCCESS)
		return phl_status;
#else
	phl_status = RTW_PHL_STATUS_SUCCESS;
#endif
	return phl_status;
}

static enum rtw_phl_status phl_com_init(void *drv_priv,
					struct phl_info_t *phl_info,
					struct rtw_ic_info *ic_info)
{
	enum rtw_phl_status phl_status = RTW_PHL_STATUS_FAILURE;

	phl_info->phl_com = _os_mem_alloc(drv_priv,
						sizeof(struct rtw_phl_com_t));
	if (phl_info->phl_com == NULL) {
		phl_status = RTW_PHL_STATUS_RESOURCE;
		PHL_ERR("alloc phl_com failed\n");
		goto error_phl_com_mem;
	}

	phl_info->phl_com->phl_priv = phl_info;
	phl_info->phl_com->drv_priv = drv_priv;
	phl_info->phl_com->hci_type = ic_info->hci_type;
	phl_info->phl_com->edcca_mode = RTW_EDCCA_NORMAL;

	phl_sw_cap_init(phl_info->phl_com);

	_os_spinlock_init(drv_priv, &phl_info->phl_com->evt_info.evt_lock);

	phl_fw_init(phl_info);
	#ifdef CONFIG_PHL_CHANNEL_INFO
	phl_status = phl_chaninfo_init(phl_info);
	if (phl_status)
		goto error_phl_com_mem;
	#endif /* CONFIG_PHL_CHANNEL_INFO */

	_phl_com_init_rssi_stat(phl_info->phl_com);
	_phl_com_init_ppdu_sts(phl_info->phl_com);

	phl_status = RTW_PHL_STATUS_SUCCESS;
	return phl_status;

error_phl_com_mem:
	return phl_status;
}

static enum rtw_phl_status phl_hci_init(struct phl_info_t *phl_info,
									struct rtw_ic_info *ic_info)
{
	enum rtw_phl_status phl_status = RTW_PHL_STATUS_FAILURE;

	phl_info->hci = _os_mem_alloc(phl_to_drvpriv(phl_info),
					sizeof(struct hci_info_t));
	if (phl_info->hci == NULL) {
		phl_status = RTW_PHL_STATUS_RESOURCE;
		goto error_hci_mem;
	}
#ifdef CONFIG_USB_HCI
	phl_info->hci->usb_bulkout_size = ic_info->usb_info.usb_bulkout_size;
#endif

	/* init variable of hci_info_t struct */

	phl_status = RTW_PHL_STATUS_SUCCESS;

error_hci_mem:
	return phl_status;
}

static void phl_com_deinit(struct phl_info_t *phl_info,
				struct rtw_phl_com_t *phl_com)
{
	void *drv_priv = phl_to_drvpriv(phl_info);

	/* deinit variable or stop mechanism. */
	if (phl_com) {
		phl_sw_cap_deinit(phl_info->phl_com);
		_os_spinlock_free(drv_priv, &phl_com->evt_info.evt_lock);
		_phl_com_deinit_rssi_stat(phl_info->phl_com);
		_phl_com_deinit_ppdu_sts(phl_info->phl_com);
		phl_fw_deinit(phl_info);
		#ifdef CONFIG_PHL_CHANNEL_INFO
		phl_chaninfo_deinit(phl_info);
		#endif /* CONFIG_PHL_CHANNEL_INFO */
		_os_mem_free(drv_priv, phl_com, sizeof(struct rtw_phl_com_t));
	}
}

static void phl_hci_deinit(struct phl_info_t *phl_info, struct hci_info_t *hci)
{

	/* deinit variable or stop mechanism. */
	if (hci)
		_os_mem_free(phl_to_drvpriv(phl_info), hci,
						sizeof(struct hci_info_t));
}

static enum rtw_phl_status _phl_hci_ops_check(struct phl_info_t *phl_info)
{
	enum rtw_phl_status status = RTW_PHL_STATUS_SUCCESS;
	struct phl_hci_trx_ops *trx_ops = phl_info->hci_trx_ops;

	if (!trx_ops->hci_trx_init) {
		phl_ops_error_msg("hci_trx_init");
		status = RTW_PHL_STATUS_FAILURE;
	}
	if (!trx_ops->hci_trx_deinit) {
		phl_ops_error_msg("hci_trx_deinit");
		status = RTW_PHL_STATUS_FAILURE;
	}
	if (!trx_ops->prepare_tx) {
		phl_ops_error_msg("prepare_tx");
		status = RTW_PHL_STATUS_FAILURE;
	}
	if (!trx_ops->recycle_rx_buf) {
		phl_ops_error_msg("recycle_rx_buf");
		status = RTW_PHL_STATUS_FAILURE;
	}
	if (!trx_ops->tx) {
		phl_ops_error_msg("tx");
		status = RTW_PHL_STATUS_FAILURE;
	}
	if (!trx_ops->rx) {
		phl_ops_error_msg("rx");
		status = RTW_PHL_STATUS_FAILURE;
	}
	if (!trx_ops->trx_cfg) {
		phl_ops_error_msg("trx_cfg");
		status = RTW_PHL_STATUS_FAILURE;
	}
	if (!trx_ops->pltfm_tx) {
		phl_ops_error_msg("pltfm_tx");
		status = RTW_PHL_STATUS_FAILURE;
	}
	if (!trx_ops->alloc_h2c_pkt_buf) {
		phl_ops_error_msg("alloc_h2c_pkt_buf");
		status = RTW_PHL_STATUS_FAILURE;
	}
	if (!trx_ops->free_h2c_pkt_buf) {
		phl_ops_error_msg("free_h2c_pkt_buf");
		status = RTW_PHL_STATUS_FAILURE;
	}
	if (!trx_ops->trx_reset) {
		phl_ops_error_msg("trx_reset");
		status = RTW_PHL_STATUS_FAILURE;
	}
	if (!trx_ops->trx_resume) {
		phl_ops_error_msg("trx_resume");
		status = RTW_PHL_STATUS_FAILURE;
	}
	if (!trx_ops->req_tx_stop) {
		phl_ops_error_msg("req_tx_stop");
		status = RTW_PHL_STATUS_FAILURE;
	}
	if (!trx_ops->req_rx_stop) {
		phl_ops_error_msg("req_rx_stop");
		status = RTW_PHL_STATUS_FAILURE;
	}
	if (!trx_ops->is_tx_pause) {
		phl_ops_error_msg("is_tx_pause");
		status = RTW_PHL_STATUS_FAILURE;
	}
	if (!trx_ops->is_rx_pause) {
		phl_ops_error_msg("is_rx_pause");
		status = RTW_PHL_STATUS_FAILURE;
	}
	if (!trx_ops->get_txbd_buf) {
		phl_ops_error_msg("get_txbd_buf");
		status = RTW_PHL_STATUS_FAILURE;
	}
	if (!trx_ops->get_rxbd_buf) {
		phl_ops_error_msg("get_rxbd_buf");
		status = RTW_PHL_STATUS_FAILURE;
	}
	if (!trx_ops->recycle_rx_pkt) {
		phl_ops_error_msg("recycle_rx_pkt");
		status = RTW_PHL_STATUS_FAILURE;
	}
	if (!trx_ops->register_trx_hdlr) {
		phl_ops_error_msg("register_trx_hdlr");
		status = RTW_PHL_STATUS_FAILURE;
	}
	if (!trx_ops->rx_handle_normal) {
		phl_ops_error_msg("rx_handle_normal");
		status = RTW_PHL_STATUS_FAILURE;
	}
	if (!trx_ops->tx_watchdog) {
		phl_ops_error_msg("tx_watchdog");
		status = RTW_PHL_STATUS_FAILURE;
	}

#ifdef CONFIG_PCI_HCI
	if (!trx_ops->recycle_busy_wd) {
		phl_ops_error_msg("recycle_busy_wd");
		status = RTW_PHL_STATUS_FAILURE;
	}
	if (!trx_ops->recycle_busy_h2c) {
		phl_ops_error_msg("recycle_busy_h2c");
		status = RTW_PHL_STATUS_FAILURE;
	}
#endif

#ifdef CONFIG_USB_HCI
	if (!trx_ops->pend_rxbuf) {
		phl_ops_error_msg("pend_rxbuf");
		status = RTW_PHL_STATUS_FAILURE;
	}
	if (!trx_ops->recycle_tx_buf) {
		phl_ops_error_msg("recycle_tx_buf");
		status = RTW_PHL_STATUS_FAILURE;
	}
#endif

	return status;
}

static enum rtw_phl_status phl_set_hci_ops(struct phl_info_t *phl_info)
{
	#ifdef CONFIG_PCI_HCI
	if (phl_get_hci_type(phl_info->phl_com) == RTW_HCI_PCIE)
		phl_hook_trx_ops_pci(phl_info);
	#endif

	#ifdef CONFIG_USB_HCI
	if (phl_get_hci_type(phl_info->phl_com) == RTW_HCI_USB)
		phl_hook_trx_ops_usb(phl_info);
	#endif

	#ifdef CONFIG_SDIO_HCI
	if (phl_get_hci_type(phl_info->phl_com) == RTW_HCI_SDIO)
		phl_hook_trx_ops_sdio(phl_info);
	#endif

	return _phl_hci_ops_check(phl_info);
}

#ifdef CONFIG_FSM
static enum rtw_phl_status phl_cmd_init(struct phl_info_t *phl_info)
{
	if (phl_info->cmd_fsm != NULL)
		return RTW_PHL_STATUS_FAILURE;

	phl_info->cmd_fsm = phl_cmd_new_fsm(phl_info->fsm_root, phl_info);
	if (phl_info->cmd_fsm == NULL)
		return RTW_PHL_STATUS_FAILURE;

	if (phl_info->cmd_obj != NULL)
		goto obj_fail;

	phl_info->cmd_obj = phl_cmd_new_obj(phl_info->cmd_fsm, phl_info);
	if (phl_info->cmd_obj == NULL)
		goto obj_fail;

	return RTW_PHL_STATUS_SUCCESS;

obj_fail:
	phl_fsm_deinit_fsm(phl_info->cmd_fsm);
	phl_info->cmd_fsm = NULL;
	return RTW_PHL_STATUS_FAILURE;
}

static void phl_cmd_deinit(struct phl_info_t *phl_info)
{
	phl_cmd_destory_obj(phl_info->cmd_obj);
	phl_info->cmd_obj = NULL;
	phl_cmd_destory_fsm(phl_info->cmd_fsm);
	phl_info->cmd_fsm = NULL;
}

static enum rtw_phl_status phl_ser_init(struct phl_info_t *phl_info)
{
	if (phl_info->ser_fsm != NULL)
		return RTW_PHL_STATUS_FAILURE;

	phl_info->ser_fsm = phl_ser_new_fsm(phl_info->fsm_root, phl_info);
	if (phl_info->ser_fsm == NULL)
		return RTW_PHL_STATUS_FAILURE;

	if (phl_info->ser_obj != NULL)
		goto obj_fail;

	phl_info->ser_obj = phl_ser_new_obj(phl_info->ser_fsm, phl_info);
	if (phl_info->ser_obj == NULL)
		goto obj_fail;

	return RTW_PHL_STATUS_SUCCESS;

obj_fail:
	phl_ser_destory_fsm(phl_info->ser_fsm);
	phl_info->ser_fsm = NULL;
	return RTW_PHL_STATUS_FAILURE;
}

static void phl_ser_deinit(struct phl_info_t *phl_info)
{
	phl_ser_destory_obj(phl_info->ser_obj);
	phl_info->ser_obj = NULL;

	phl_ser_destory_fsm(phl_info->ser_fsm);
	phl_info->ser_fsm = NULL;
}

static enum rtw_phl_status phl_btc_init(struct phl_info_t *phl_info)
{
	if (phl_info->btc_fsm != NULL)
		return RTW_PHL_STATUS_FAILURE;

	phl_info->btc_fsm = phl_btc_new_fsm(phl_info->fsm_root, phl_info);
	if (phl_info->btc_fsm == NULL)
		return RTW_PHL_STATUS_FAILURE;

	phl_info->btc_obj = phl_btc_new_obj(phl_info->btc_fsm, phl_info);
	if (phl_info->btc_obj == NULL)
		goto obj_fail;

	return RTW_PHL_STATUS_SUCCESS;

obj_fail:
	phl_fsm_deinit_fsm(phl_info->btc_fsm);
	phl_info->btc_fsm = NULL;
	return RTW_PHL_STATUS_FAILURE;

}

static void phl_btc_deinit(struct phl_info_t *phl_info)
{
	phl_btc_destory_obj(phl_info->btc_obj);
	phl_info->btc_obj = NULL;

	phl_btc_destory_fsm(phl_info->btc_fsm);
	phl_info->btc_fsm = NULL;
}

static enum rtw_phl_status phl_scan_init(struct phl_info_t *phl_info)
{
	if (phl_info->scan_fsm != NULL)
		return RTW_PHL_STATUS_FAILURE;

	phl_info->scan_fsm = phl_scan_new_fsm(phl_info->fsm_root, phl_info);
	if (phl_info->scan_fsm == NULL)
		return RTW_PHL_STATUS_FAILURE;

	if (phl_info->scan_obj != NULL)
		goto obj_fail;

	phl_info->scan_obj = phl_scan_new_obj(phl_info->scan_fsm, phl_info);
	if (phl_info->scan_obj == NULL)
		goto obj_fail;

	return RTW_PHL_STATUS_SUCCESS;

obj_fail:
	phl_fsm_deinit_fsm(phl_info->scan_fsm);
	phl_info->scan_fsm = NULL;
	return RTW_PHL_STATUS_FAILURE;
}

static void phl_scan_deinit(struct phl_info_t *phl_info)
{
	phl_scan_destory_obj(phl_info->scan_obj);
	phl_info->scan_obj = NULL;
	phl_scan_destory_fsm(phl_info->scan_fsm);
	phl_info->scan_fsm = NULL;
}

static enum rtw_phl_status phl_sound_init(struct phl_info_t *phl_info)
{
	enum rtw_phl_status pstatus = RTW_PHL_STATUS_SUCCESS;

	if (phl_info->snd_fsm!= NULL)
		return RTW_PHL_STATUS_FAILURE;

	phl_info->snd_fsm = phl_sound_new_fsm(phl_info->fsm_root, phl_info);
	if (phl_info->snd_fsm == NULL)
		return RTW_PHL_STATUS_FAILURE;

	pstatus = phl_snd_new_obj(phl_info->snd_fsm, phl_info);
	if (pstatus != RTW_PHL_STATUS_SUCCESS)
		goto obj_fail;

	return pstatus;

obj_fail:
	phl_fsm_deinit_fsm(phl_info->snd_fsm);
	phl_info->snd_fsm = NULL;
	return RTW_PHL_STATUS_FAILURE;
}

static void phl_sound_deinit(struct phl_info_t *phl_info)
{
	phl_snd_destory_obj(phl_info->snd_obj);
	phl_info->snd_obj = NULL;
	phl_snd_destory_fsm(phl_info->snd_fsm);
	phl_info->snd_fsm = NULL;
}

static enum rtw_phl_status phl_fsm_init(struct phl_info_t *phl_info)
{
	if (phl_info->fsm_root != NULL)
		return RTW_PHL_STATUS_FAILURE;

	/* allocate memory for fsm to do version control */
	phl_info->fsm_root = phl_fsm_init_root(phl_info);
	if (phl_info->fsm_root == NULL)
		return RTW_PHL_STATUS_FAILURE;

	return RTW_PHL_STATUS_SUCCESS;
}

static void phl_fsm_deinit(struct phl_info_t *phl_info)
{
	/* free memory for fsm */
	phl_fsm_deinit_root(phl_info->fsm_root);
	phl_info->fsm_root = NULL;
}

static enum rtw_phl_status phl_fsm_module_init(struct phl_info_t *phl_info)
{
	enum rtw_phl_status phl_status = RTW_PHL_STATUS_SUCCESS;

	phl_status = phl_cmd_init(phl_info);
	if (phl_status != RTW_PHL_STATUS_SUCCESS) {
		PHL_ERR("phl_cmd_init failed\n");
		goto cmd_fail;
	}

	phl_status = phl_ser_init(phl_info);
	if (phl_status != RTW_PHL_STATUS_SUCCESS) {
		PHL_ERR("phl_ser_init failed\n");
		goto ser_fail;
	}

	phl_status = phl_btc_init(phl_info);
	if (phl_status != RTW_PHL_STATUS_SUCCESS) {
		PHL_ERR("phl_btc_init failed\n");
		goto btc_fail;
	}

	phl_status = phl_scan_init(phl_info);
	if (phl_status != RTW_PHL_STATUS_SUCCESS) {
		PHL_ERR("phl_scan_init failed\n");
		goto scan_fail;
	}

	phl_status = phl_sound_init(phl_info);
	if (phl_status != RTW_PHL_STATUS_SUCCESS) {
		PHL_ERR("phl_sound_init failed\n");
		goto sound_fail;
	}

	return phl_status;

sound_fail:
	phl_scan_deinit(phl_info);
scan_fail:
	phl_btc_deinit(phl_info);
btc_fail:
	phl_ser_deinit(phl_info);
ser_fail:
	phl_cmd_deinit(phl_info);
cmd_fail:
	return phl_status;
}

static void phl_fsm_module_deinit(struct phl_info_t *phl_info)
{
	phl_sound_deinit(phl_info);
	phl_scan_deinit(phl_info);
	phl_btc_deinit(phl_info);
	phl_ser_deinit(phl_info);
	phl_cmd_deinit(phl_info);
}

static enum rtw_phl_status phl_fsm_start(struct phl_info_t *phl_info)
{
	return phl_fsm_start_root(phl_info->fsm_root);
}

static enum rtw_phl_status phl_fsm_stop(struct phl_info_t *phl_info)
{
	return phl_fsm_stop_root(phl_info->fsm_root);
}

static enum rtw_phl_status phl_fsm_module_start(struct phl_info_t *phl_info)
{
	enum rtw_phl_status phl_status = RTW_PHL_STATUS_SUCCESS;

	phl_status = phl_fsm_start_fsm(phl_info->ser_fsm);
	if (phl_status != RTW_PHL_STATUS_SUCCESS)
		goto ser_fail;

	phl_status = phl_btc_start(phl_info->btc_obj);
	if (phl_status != RTW_PHL_STATUS_SUCCESS)
		goto btc_fail;

	phl_status = phl_fsm_start_fsm(phl_info->scan_fsm);
	if (phl_status != RTW_PHL_STATUS_SUCCESS)
		goto scan_fail;

	phl_status = phl_cmd_start(phl_info->cmd_obj);
	if (phl_status != RTW_PHL_STATUS_SUCCESS)
		goto cmd_fail;

	phl_status = phl_fsm_start_fsm(phl_info->snd_fsm);
	if (phl_status != RTW_PHL_STATUS_SUCCESS)
		goto snd_fail;

	return phl_status;

snd_fail:
	phl_fsm_stop_fsm(phl_info->cmd_fsm);
	phl_fsm_stop_fsm(phl_info->scan_fsm);
scan_fail:
	phl_fsm_stop_fsm(phl_info->btc_fsm);
btc_fail:
	phl_fsm_stop_fsm(phl_info->ser_fsm);
ser_fail:
	phl_fsm_cmd_stop(phl_info);
cmd_fail:
	return phl_status;
}

static enum rtw_phl_status phl_fsm_module_stop(struct phl_info_t *phl_info)
{
	enum rtw_phl_status phl_status = RTW_PHL_STATUS_SUCCESS;

	phl_fsm_stop_fsm(phl_info->snd_fsm);
	phl_fsm_stop_fsm(phl_info->scan_fsm);
	phl_fsm_stop_fsm(phl_info->btc_fsm);
	phl_fsm_stop_fsm(phl_info->ser_fsm);
	phl_fsm_cmd_stop(phl_info);

	return phl_status;
}

#endif /*CONFIG_FSM*/
static enum rtw_phl_status phl_module_init(struct phl_info_t *phl_info)
{
	enum rtw_phl_status phl_status = RTW_PHL_STATUS_SUCCESS;

	phl_status = phl_msg_hub_init(phl_info);
	if (phl_status != RTW_PHL_STATUS_SUCCESS) {
		PHL_ERR("phl_msg_hub_init failed\n");
		goto msg_hub_fail;
	}

	phl_status = phl_wow_mdl_init(phl_info);
	if (phl_status != RTW_PHL_STATUS_SUCCESS) {
		PHL_ERR("phl_wow_mdl_init failed\n");
		goto wow_init_fail;
	}

	phl_status = phl_pkt_ofld_init(phl_info);
	if (phl_status != RTW_PHL_STATUS_SUCCESS) {
		PHL_ERR("phl_pkt_ofld_init failed\n");
		goto pkt_ofld_init_fail;
	}

	if (!phl_test_module_init(phl_info)) {
		PHL_ERR("phl_test_module_init failed\n");
		phl_status = RTW_PHL_STATUS_FAILURE;
		goto error_test_module_init;
	}

	phl_status = phl_p2pps_init(phl_info);
	if (phl_status != RTW_PHL_STATUS_SUCCESS) {
		PHL_ERR("phl_p2pps_init failed\n");
		goto error_p2pps_init;
	}

	phl_status = phl_disp_eng_init(phl_info, HW_BAND_MAX);
	if (phl_status != RTW_PHL_STATUS_SUCCESS) {
		PHL_ERR("phl_disp_eng_init failed\n");
		goto error_disp_eng_init;
	}

	phl_status = phl_register_background_module_entry(phl_info);
	if (phl_status != RTW_PHL_STATUS_SUCCESS) {
		PHL_ERR("phl_register_disp_eng_module_entry failed\n");
		goto error_disp_eng_reg_init;
	}

	phl_status = phl_ecsa_ctrl_init(phl_info);
	if (phl_status != RTW_PHL_STATUS_SUCCESS) {
		PHL_ERR("phl_ecsa_ctrl_init failed\n");
		goto error_ecsa_ctrl_init;
	}
	return phl_status;

error_ecsa_ctrl_init:
error_disp_eng_reg_init:
	phl_disp_eng_deinit(phl_info);
error_disp_eng_init:
	phl_p2pps_deinit(phl_info);
error_p2pps_init:
	phl_test_module_deinit(phl_info->phl_com);
error_test_module_init:
	phl_pkt_ofld_deinit(phl_info);
pkt_ofld_init_fail:
	phl_wow_mdl_deinit(phl_info);
wow_init_fail:
	phl_msg_hub_deinit(phl_info);
msg_hub_fail:
	return phl_status;
}

static void phl_module_deinit(struct phl_info_t *phl_info)
{
	phl_ecsa_ctrl_deinit(phl_info);
	phl_disp_eng_deinit(phl_info);
	phl_test_module_deinit(phl_info->phl_com);
	phl_pkt_ofld_deinit(phl_info);
	phl_wow_mdl_deinit(phl_info);
	phl_msg_hub_deinit(phl_info);
	phl_p2pps_deinit(phl_info);
}

static enum rtw_phl_status phl_module_start(struct phl_info_t *phl_info)
{
	enum rtw_phl_status phl_status = RTW_PHL_STATUS_SUCCESS;

	if (!phl_test_module_start(phl_info->phl_com)) {
		PHL_ERR("phl_test_module_start failed\n");
		phl_status = RTW_PHL_STATUS_FAILURE;
		goto error_test_mdl_start;
	}

	phl_status = phl_disp_eng_start(phl_info);
	if (phl_status != RTW_PHL_STATUS_SUCCESS) {
		PHL_ERR("phl_disp_eng_start failed\n");
		goto error_disp_eng_start;
	}

	if(phl_info->msg_hub) {
		phl_msg_hub_start(phl_info);
		phl_register_msg_entry(phl_info);
	}

	return phl_status;

error_disp_eng_start:
	phl_test_module_stop(phl_info->phl_com);
error_test_mdl_start:
	return phl_status;
}

static enum rtw_phl_status phl_module_stop(struct phl_info_t *phl_info)
{
	enum rtw_phl_status phl_status = RTW_PHL_STATUS_SUCCESS;

	phl_status = phl_cmd_enqueue(phl_info, HW_BAND_0, MSG_EVT_MDL_CHECK_STOP,
		NULL, 0, NULL, PHL_CMD_WAIT, 500);

	phl_disp_eng_stop(phl_info);
	phl_test_module_stop(phl_info->phl_com);

	if(phl_info->msg_hub) {
		phl_deregister_msg_entry(phl_info);
		phl_msg_hub_stop(phl_info);
	}

	return phl_status;
}

static enum rtw_phl_status phl_var_init(struct phl_info_t *phl_info)
{
	return RTW_PHL_STATUS_SUCCESS;
}

static void phl_var_deinit(struct phl_info_t *phl_info)
{

}

struct rtw_phl_com_t *rtw_phl_get_com(void *phl)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;

	return phl_info->phl_com;
}

static void phl_regulation_init(void *drv_priv, void *phl)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
	struct rtw_regulation *rg = NULL;

	if (!drv_priv || !phl)
		return;

	rg = &phl_info->regulation;

	_os_spinlock_init(drv_priv, &rg->lock);
	rg->init = 1;
	rg->domain.code = INVALID_DOMAIN_CODE;
	rg->domain_6g.code = INVALID_DOMAIN_CODE;
	rg->tpo = TPO_NA;
}

static void phl_regulation_deinit(void *drv_priv, void *phl)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
	struct rtw_regulation *rg = NULL;

	if (!drv_priv || !phl)
		return;

	rg = &phl_info->regulation;

	_os_spinlock_free(drv_priv, &rg->lock);
}

enum rtw_phl_status rtw_phl_init(void *drv_priv, void **phl,
					struct rtw_ic_info *ic_info)
{
	struct phl_info_t *phl_info = NULL;
	enum rtw_phl_status phl_status = RTW_PHL_STATUS_FAILURE;
	enum rtw_hal_status hal_status = RTW_HAL_STATUS_FAILURE;

	FUNCIN();
	phl_info = _os_mem_alloc(drv_priv, sizeof(struct phl_info_t));
	if (phl_info == NULL) {
		phl_status = RTW_PHL_STATUS_RESOURCE;
		PHL_ERR("alloc phl_info failed\n");
		goto error_phl_mem;
	}
	_os_mem_set(drv_priv, phl_info, 0, sizeof(struct phl_info_t));
	*phl = phl_info;

	phl_regulation_init(drv_priv, phl_info);

	phl_status = phl_com_init(drv_priv, phl_info, ic_info);
	if (phl_status != RTW_PHL_STATUS_SUCCESS) {
		phl_status = RTW_PHL_STATUS_RESOURCE;
		PHL_ERR("alloc phl_com failed\n");
		goto error_phl_com_mem;
	}

	phl_status = phl_hci_init(phl_info, ic_info);
	if (phl_status != RTW_PHL_STATUS_SUCCESS) {
		PHL_ERR("phl_hci_init failed\n");
		goto error_hci_init;
	}

	phl_status = phl_set_hci_ops(phl_info);
	if (phl_status != RTW_PHL_STATUS_SUCCESS) {
		PHL_ERR("phl_set_hci_ops failed\n");
		goto error_set_hci_ops;
	}
#ifdef CONFIG_FSM
	phl_status = phl_fsm_init(phl_info);
	if (phl_status != RTW_PHL_STATUS_SUCCESS) {
		PHL_ERR("phl_fsm_init failed\n");
		goto error_fsm_init;
	}

	/* init FSM modules */
	phl_status = phl_fsm_module_init(phl_info);
	if (phl_status != RTW_PHL_STATUS_SUCCESS) {
		PHL_ERR("phl_fsm_module_init failed\n");
		goto error_fsm_module_init;
	}
#endif
	phl_status = phl_twt_init(*phl);
	if (phl_status != RTW_PHL_STATUS_SUCCESS) {
		PHL_ERR("phl_twt_init failed\n");
		goto error_phl_twt_init;
	}
	hal_status = rtw_hal_init(drv_priv, phl_info->phl_com,
					&(phl_info->hal), ic_info->ic_id);
	if ((hal_status != RTW_HAL_STATUS_SUCCESS) || (phl_info->hal == NULL)) {
		phl_status = RTW_PHL_STATUS_HAL_INIT_FAILURE;
		PHL_ERR("rtw_hal_init failed status(%d),phl_info->hal(%p)\n",
			hal_status, phl_info->hal);
		goto error_hal_init;
	}

	/*send bus info to hal*/
	rtw_hal_hci_cfg(phl_info->phl_com, phl_info->hal, ic_info);

	/*get hw capability from mac/bb/rf/btc/efuse/fw-defeature-rpt*/
	hal_status = rtw_hal_read_chip_info(phl_info->phl_com, phl_info->hal);
	if (hal_status != RTW_HAL_STATUS_SUCCESS) {
		phl_status = RTW_PHL_STATUS_HAL_INIT_FAILURE;
		PHL_ERR("rtw_hal_read_chip_info failed\n");
		goto error_hal_read_chip_info;
	}

	hal_status = rtw_hal_var_init(phl_info->phl_com, phl_info->hal);
	if (hal_status != RTW_HAL_STATUS_SUCCESS) {
		phl_status = RTW_PHL_STATUS_HAL_INIT_FAILURE;
		PHL_ERR("rtw_hal_var_init failed\n");
		goto error_hal_var_init;
	}

	phl_status = phl_var_init(phl_info);
	if (phl_status != RTW_PHL_STATUS_SUCCESS) {
		PHL_ERR("phl_var_init failed\n");
		goto error_phl_var_init;
	}

	/* init mr_ctrl, wifi_role[] */
	phl_status = phl_mr_ctrl_init(phl_info);
	if (phl_status != RTW_PHL_STATUS_SUCCESS) {
		PHL_ERR("phl_mr_ctrl_init failed\n");
		goto error_wifi_role_ctrl_init;
	}

	/* init modules */
	phl_status = phl_module_init(phl_info);
	if (phl_status != RTW_PHL_STATUS_SUCCESS) {
		PHL_ERR("phl_module_init failed\n");
		goto error_module_init;
	}

	/* init macid_ctrl , stainfo_ctrl*/
	/* init after get hw cap - macid number*/
	phl_status = phl_macid_ctrl_init(phl_info);
	if (phl_status != RTW_PHL_STATUS_SUCCESS) {
		PHL_ERR("phl_macid_ctrl_init failed\n");
		goto error_macid_ctrl_init;
	}

	/*init after hal_init - hal_sta_info*/
	phl_status = phl_stainfo_ctrl_init(phl_info);
	if (phl_status != RTW_PHL_STATUS_SUCCESS) {
		PHL_ERR("phl_stainfo_ctrl_init failed\n");
		goto error_stainfo_ctrl_init;
	}
	FUNCOUT();

	return phl_status;

error_stainfo_ctrl_init:
	phl_macid_ctrl_deinit(phl_info);
error_macid_ctrl_init:
	phl_module_deinit(phl_info);
error_module_init:
	phl_mr_ctrl_deinit(phl_info);
error_wifi_role_ctrl_init:
	phl_var_deinit(phl_info);
error_phl_var_init:
error_hal_var_init:
error_hal_read_chip_info:
	rtw_hal_deinit(phl_info->phl_com, phl_info->hal);
error_hal_init:
error_phl_twt_init:
	phl_twt_deinit(phl);
#ifdef CONFIG_FSM
	phl_fsm_module_deinit(phl_info);
error_fsm_module_init:
	phl_fsm_deinit(phl_info);
error_fsm_init:
	/* Do nothing */
#endif
error_set_hci_ops:
	phl_hci_deinit(phl_info, phl_info->hci);
error_hci_init:
	phl_com_deinit(phl_info, phl_info->phl_com);
error_phl_com_mem:
	if (phl_info) {
		phl_regulation_deinit(drv_priv, phl_info);
		_os_mem_free(drv_priv, phl_info, sizeof(struct phl_info_t));
		*phl = phl_info = NULL;
	}
error_phl_mem:
	return phl_status;
}

void rtw_phl_deinit(void *phl)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
	void *drv_priv = phl_to_drvpriv(phl_info);

	if (phl_info) {
		phl_twt_deinit(phl);
		phl_stainfo_ctrl_deinie(phl_info);
		phl_macid_ctrl_deinit(phl_info);
		/*deinit mr_ctrl, wifi_role[]*/
		phl_module_deinit(phl_info);
		phl_mr_ctrl_deinit(phl_info);
		rtw_hal_deinit(phl_info->phl_com, phl_info->hal);
		phl_var_deinit(phl_info);
		#ifdef CONFIG_FSM
		phl_fsm_module_deinit(phl_info);
		phl_fsm_deinit(phl_info);
		#endif
		phl_hci_deinit(phl_info, phl_info->hci);
		phl_com_deinit(phl_info, phl_info->phl_com);
		phl_regulation_deinit(drv_priv, phl_info);
		_os_mem_free(drv_priv, phl_info,
					sizeof(struct phl_info_t));
	}
}

enum rtw_phl_status
rtw_phl_trx_alloc(void *phl)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
	enum rtw_phl_status phl_status = RTW_PHL_STATUS_FAILURE;

	phl_status = phl_datapath_init(phl_info);
	if (phl_status != RTW_PHL_STATUS_SUCCESS) {
		PHL_ERR("phl_datapath_init failed\n");
		goto error_datapath;
	}

	phl_status = phl_trx_test_init(phl);
	if (phl_status != RTW_PHL_STATUS_SUCCESS) {
		PHL_ERR("phl_trx_test_init failed\n");
		goto error_trx_test;
	}

	return phl_status;

error_trx_test:
	phl_datapath_deinit(phl_info);
error_datapath:
	return phl_status;
}

void
rtw_phl_trx_free_handler(void *phl)
{
	phl_trx_free_handler(phl);
}

void
rtw_phl_trx_free_sw_rsc(void *phl)
{
	phl_trx_free_sw_rsc(phl);
	phl_trx_test_deinit(phl);
}

void
rtw_phl_trx_free(void *phl)
{
	rtw_phl_trx_free_handler(phl);
	rtw_phl_trx_free_sw_rsc(phl);
}


bool rtw_phl_is_init_completed(void *phl)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;

	return rtw_hal_is_inited(phl_info->phl_com, phl_info->hal);
}

#ifdef RTW_PHL_BCN

enum rtw_phl_status
phl_add_beacon(struct phl_info_t *phl_info, struct rtw_bcn_info_cmn *bcn_cmn)
{
	struct rtw_phl_com_t *phl_com = phl_info->phl_com;
	void *hal = phl_info->hal;

	if(rtw_hal_add_beacon(phl_com, hal, bcn_cmn) == RTW_HAL_STATUS_SUCCESS)
		return RTW_PHL_STATUS_SUCCESS;
	else
		return RTW_PHL_STATUS_FAILURE;
}

enum rtw_phl_status phl_update_beacon(struct phl_info_t *phl_info, u8 bcn_id)
{
	struct rtw_phl_com_t *phl_com = phl_info->phl_com;
	void *hal = phl_info->hal;

	if(rtw_hal_update_beacon(phl_com, hal, bcn_id) == RTW_HAL_STATUS_SUCCESS)
		return RTW_PHL_STATUS_SUCCESS;
	else
		return RTW_PHL_STATUS_FAILURE;
}

enum rtw_phl_status rtw_phl_free_bcn_entry(void *phl, struct rtw_wifi_role_t *wrole)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
	struct rtw_phl_com_t *phl_com = phl_info->phl_com;
	struct rtw_bcn_info_cmn *bcn_cmn = &wrole->bcn_cmn;
	void *hal = phl_info->hal;
	enum rtw_phl_status phl_status = RTW_PHL_STATUS_SUCCESS;

	if (bcn_cmn->bcn_added == 1) {
		if (rtw_hal_free_beacon(phl_com, hal, bcn_cmn->bcn_id) == RTW_HAL_STATUS_SUCCESS) {
			bcn_cmn->bcn_added = 0;
			phl_status = RTW_PHL_STATUS_SUCCESS;
		} else {
			phl_status = RTW_PHL_STATUS_FAILURE;
		}
	}

	return phl_status;
}

enum rtw_phl_status
phl_beacon_stop(struct phl_info_t *phl_info, struct rtw_wifi_role_t *wrole, u8 stop)
{
	enum rtw_phl_status pstatus = RTW_PHL_STATUS_SUCCESS;
	enum rtw_hal_status hstatus = RTW_HAL_STATUS_SUCCESS;

	hstatus = rtw_hal_beacon_stop(phl_info->hal, wrole, stop);
	if (hstatus != RTW_HAL_STATUS_SUCCESS)
		pstatus = RTW_PHL_STATUS_FAILURE;

	return pstatus;
}

enum rtw_phl_status
phl_issue_beacon(struct phl_info_t *phl_info, struct rtw_bcn_info_cmn *bcn_cmn)
{
	struct rtw_phl_com_t *phl_com = phl_info->phl_com;
	struct rtw_bcn_info_cmn *wrole_bcn_cmn;
	struct rtw_wifi_role_t *wifi_role;
	void *drv = phl_com->drv_priv;
	u8 bcn_id, role_idx, bcn_added;

	role_idx = bcn_cmn->role_idx;
	if (role_idx > MAX_WIFI_ROLE_NUMBER) {
		PHL_ERR("%s: role idx err(%d)\n", __func__, role_idx);
		return RTW_PHL_STATUS_FAILURE;
	}

	wifi_role = &phl_com->wifi_roles[role_idx];
	wrole_bcn_cmn = &wifi_role->bcn_cmn;
	bcn_added = wrole_bcn_cmn->bcn_added;
	_os_mem_cpy(drv, wrole_bcn_cmn, bcn_cmn, sizeof(struct rtw_bcn_info_cmn));

	/* BCN add */
	if (!bcn_added) {
		if(phl_add_beacon(phl_info, wrole_bcn_cmn) == RTW_PHL_STATUS_SUCCESS) {
			wrole_bcn_cmn->bcn_added = true;
			return RTW_PHL_STATUS_SUCCESS;
		} else {
			return RTW_PHL_STATUS_FAILURE;
		}
	} else {
		/* BCN update */
		bcn_id = wrole_bcn_cmn->bcn_id;
		if(phl_update_beacon(phl_info, bcn_id) == RTW_PHL_STATUS_SUCCESS)
			return RTW_PHL_STATUS_SUCCESS;
		else
			return RTW_PHL_STATUS_FAILURE;
	}
}
#ifdef CONFIG_CMD_DISP
enum rtw_phl_status
phl_cmd_issue_bcn_hdl(struct phl_info_t *phl_info, u8 *param)
{
	struct rtw_bcn_info_cmn *bcn_cmn = (struct rtw_bcn_info_cmn *)param;

	return phl_issue_beacon(phl_info, bcn_cmn);
}

static void _phl_issue_bcn_done(void *drv_priv, u8 *buf, u32 buf_len,
						enum rtw_phl_status status)
{
	if (buf) {
		_os_kmem_free(drv_priv, buf, buf_len);
		buf = NULL;
		PHL_INFO("%s.....\n", __func__);
	}
}

enum rtw_phl_status
rtw_phl_cmd_issue_beacon(void *phl,
                         struct rtw_wifi_role_t *wifi_role,
                         struct rtw_bcn_info_cmn *bcn_cmn,
                         enum phl_cmd_type cmd_type,
                         u32 cmd_timeout)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
	void *drv = wifi_role->phl_com->drv_priv;
	enum rtw_phl_status psts = RTW_PHL_STATUS_FAILURE;
	struct rtw_bcn_info_cmn *param = NULL;
	u32 param_len;

	if (cmd_type == PHL_CMD_DIRECTLY) {
		psts = phl_issue_beacon(phl_info, bcn_cmn);
		goto _exit;
	}

	param_len = sizeof(struct rtw_bcn_info_cmn);
	param = _os_kmem_alloc(drv, param_len);
	if (param == NULL) {
		PHL_ERR("%s: alloc param failed!\n", __func__);
		goto _exit;
	}

	_os_mem_cpy(drv, param, bcn_cmn, param_len);

	psts = phl_cmd_enqueue(phl_info,
			wifi_role->hw_band,
			MSG_EVT_ISSUE_BCN,
			(u8 *)param, param_len,
			_phl_issue_bcn_done,
			cmd_type, cmd_timeout);

	if (is_cmd_failure(psts)) {
		/* Send cmd success, but wait cmd fail*/
		psts = RTW_PHL_STATUS_FAILURE;
	} else if (psts != RTW_PHL_STATUS_SUCCESS) {
		/* Send cmd fail */
		_os_kmem_free(phl_to_drvpriv(phl_info), param, param_len);
		psts = RTW_PHL_STATUS_FAILURE;
	}

_exit:
	return psts;
}

struct stop_bcn_param {
	struct rtw_wifi_role_t *wrole;
	u8 stop;
};

enum rtw_phl_status
phl_cmd_stop_bcn_hdl(struct phl_info_t *phl_info, u8 *param)
{
	struct stop_bcn_param *bcn_param = (struct stop_bcn_param *)param;

	return phl_beacon_stop(phl_info, bcn_param->wrole, bcn_param->stop);
}


static void _phl_stop_bcn_done(void *drv_priv, u8 *buf, u32 buf_len,
						enum rtw_phl_status status)
{
	if (buf) {
		_os_kmem_free(drv_priv, buf, buf_len);
		buf = NULL;
		PHL_INFO("%s.....\n", __func__);
	}
}


enum rtw_phl_status
rtw_phl_cmd_stop_beacon(void *phl,
                        struct rtw_wifi_role_t *wifi_role,
                        u8 stop,
                        enum phl_cmd_type cmd_type,
                        u32 cmd_timeout)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
	void *drv = wifi_role->phl_com->drv_priv;
	enum rtw_phl_status psts = RTW_PHL_STATUS_FAILURE;
	struct stop_bcn_param *param = NULL;
	u32 param_len;

	if (cmd_type == PHL_CMD_DIRECTLY) {
		psts = phl_beacon_stop(phl_info, wifi_role, stop);
		goto _exit;
	}

	param_len = sizeof(struct stop_bcn_param);
	param = _os_kmem_alloc(drv, param_len);
	if (param == NULL) {
		PHL_ERR("%s: alloc param failed!\n", __func__);
		goto _exit;
	}

	param->wrole = wifi_role;
	param->stop = stop;

	psts = phl_cmd_enqueue(phl_info,
			wifi_role->hw_band,
			MSG_EVT_STOP_BCN,
			(u8 *)param, param_len,
			_phl_stop_bcn_done,
			cmd_type, cmd_timeout);

	if (is_cmd_failure(psts)) {
		/* Send cmd success, but wait cmd fail*/
		psts = RTW_PHL_STATUS_FAILURE;
	} else if (psts != RTW_PHL_STATUS_SUCCESS) {
		/* Send cmd fail */
		_os_kmem_free(phl_to_drvpriv(phl_info), param, param_len);
		psts = RTW_PHL_STATUS_FAILURE;
	}
_exit:
	return psts;
}
#else /*for FSM*/
enum rtw_phl_status
rtw_phl_cmd_stop_beacon(void *phl,
				struct rtw_wifi_role_t *wifi_role,
				u8 stop,
				enum phl_cmd_type cmd_type,
				u32 cmd_timeout)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;

	return phl_beacon_stop(phl_info, wifi_role, stop);
}

enum rtw_phl_status
rtw_phl_cmd_issue_beacon(void *phl,
				struct rtw_wifi_role_t *wifi_role,
				struct rtw_bcn_info_cmn *bcn_cmn,
				enum phl_cmd_type cmd_type,
				u32 cmd_timeout)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;

	return phl_issue_beacon(phl_info, bcn_cmn);
}
#endif /*CONFIG_CMD_DISP*/
#endif /*RTW_PHL_BCN*/

void rtw_phl_cap_pre_config(void *phl)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
	/* FW Pre-config */
	rtw_hal_fw_cap_pre_config(phl_info->phl_com,phl_info->hal);
	/* Bus Pre-config */
	rtw_hal_bus_cap_pre_config(phl_info->phl_com,phl_info->hal);
}

enum rtw_phl_status rtw_phl_preload(void *phl)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
	enum rtw_hal_status hal_status = RTW_HAL_STATUS_SUCCESS;

#ifdef RTW_WKARD_PRELOAD_TRX_RESET
	struct phl_hci_trx_ops *ops = phl_info->hci_trx_ops;
#endif
	FUNCIN();

	hal_status = rtw_hal_preload(phl_info->phl_com, phl_info->hal);

#ifdef RTW_WKARD_PRELOAD_TRX_RESET
	ops->trx_reset(phl_info, PHL_CTRL_TX|PHL_CTRL_RX);
#endif
	if (hal_status != RTW_HAL_STATUS_SUCCESS)
		return RTW_PHL_STATUS_FAILURE;

	return RTW_PHL_STATUS_SUCCESS;
}

enum rtw_phl_status rtw_phl_start(void *phl)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
	enum rtw_phl_status phl_status = RTW_PHL_STATUS_FAILURE;
	enum rtw_hal_status hal_status = RTW_HAL_STATUS_SUCCESS;
#ifdef CONFIG_SYNC_INTERRUPT
	struct rtw_phl_evt_ops *evt_ops = &phl_info->phl_com->evt_ops;
#endif /* CONFIG_SYNC_INTERRUPT */

	hal_status = rtw_hal_start(phl_info->phl_com, phl_info->hal);
	if (hal_status == RTW_HAL_STATUS_MAC_INIT_FAILURE) {
		phl_status = RTW_PHL_STATUS_HAL_INIT_FAILURE;
		goto error_hal_start;
	} else if (hal_status == RTW_HAL_STATUS_BB_INIT_FAILURE) {
		phl_status = RTW_PHL_STATUS_HAL_INIT_FAILURE;
		goto error_hal_start;
	} else if (hal_status == RTW_HAL_STATUS_RF_INIT_FAILURE) {
		phl_status = RTW_PHL_STATUS_HAL_INIT_FAILURE;
		goto error_hal_start;
	} else if (hal_status == RTW_HAL_STATUS_BTC_INIT_FAILURE) {
		phl_status = RTW_PHL_STATUS_HAL_INIT_FAILURE;
		goto error_hal_start;
	} else if (hal_status != RTW_HAL_STATUS_SUCCESS) {
		phl_status = RTW_PHL_STATUS_HAL_INIT_FAILURE;
		goto error_hal_start;
	}

#ifdef CONFIG_LOAD_PHY_PARA_FROM_FILE
	/* if no need keep para buf, phl_com->dev_sw_cap->keep_para_info = false*/
	rtw_phl_init_free_para_buf(phl_info->phl_com);
#endif

#ifdef CONFIG_FSM
	/* start FSM framework */
	phl_status = phl_fsm_start(phl_info);
	if (phl_status != RTW_PHL_STATUS_SUCCESS)
		goto error_phl_fsm_start;

	/* start FSM modules */
	phl_status = phl_fsm_module_start(phl_info);
	if (phl_status != RTW_PHL_STATUS_SUCCESS)
		goto error_phl_fsm_module_start;
#endif
	/* start modules */
	phl_status = phl_module_start(phl_info);
	if (phl_status != RTW_PHL_STATUS_SUCCESS)
		goto error_phl_module_start;

	phl_status = phl_datapath_start(phl_info);
	if (phl_status != RTW_PHL_STATUS_SUCCESS)
		goto error_phl_datapath_start;

#ifdef CONFIG_SYNC_INTERRUPT
	evt_ops->set_interrupt_caps(phl_to_drvpriv(phl_info), true);
#else
	rtw_hal_enable_interrupt(phl_info->phl_com, phl_info->hal);
#endif /* CONFIG_SYNC_INTERRUPT */

	phl_info->phl_com->dev_state = RTW_DEV_WORKING;
	phl_status = RTW_PHL_STATUS_SUCCESS;

	return phl_status;

error_phl_datapath_start:
	phl_module_stop(phl_info);
error_phl_module_start:
#ifdef CONFIG_FSM
	phl_fsm_module_stop(phl_info);
error_phl_fsm_module_start:
	phl_fsm_stop(phl_info);
error_phl_fsm_start:
#endif
	rtw_hal_stop(phl_info->phl_com, phl_info->hal);
error_hal_start:
	return phl_status;
}

static void _phl_interrupt_stop(struct phl_info_t *phl_info)
{
#ifdef CONFIG_SYNC_INTERRUPT
	struct rtw_phl_evt_ops *evt_ops = &phl_info->phl_com->evt_ops;

	do {
		if (false == TEST_STATUS_FLAG(phl_info->phl_com->dev_state,
		                              RTW_DEV_SURPRISE_REMOVAL))
			evt_ops->set_interrupt_caps(phl_to_drvpriv(phl_info), false);
	} while (false);
#else
	do {
		if (false == TEST_STATUS_FLAG(phl_info->phl_com->dev_state,
		                              RTW_DEV_SURPRISE_REMOVAL))
			rtw_hal_disable_interrupt(phl_info->phl_com, phl_info->hal);
	} while (false);
#endif /* CONFIG_SYNC_INTERRUPT */
}

static enum rtw_phl_status _phl_cmd_send_msg_phy_on(struct phl_info_t *phl_info)
{
	enum rtw_phl_status sts = RTW_PHL_STATUS_FAILURE;
#ifdef DBG_PHY_ON_TIME
	u32 phyon_start = 0, phyon_t = 0;
#endif /* DBG_PHY_ON_TIME */

#ifdef DBG_PHY_ON_TIME
	phyon_start = _os_get_cur_time_ms();
#endif /* DBG_PHY_ON_TIME */

	sts = phl_cmd_enqueue(phl_info, HW_BAND_0, MSG_EVT_PHY_ON, NULL, 0, NULL,
			PHL_CMD_WAIT, 3000);

#ifdef DBG_PHY_ON_TIME
	phyon_t = phl_get_passing_time_ms(phyon_start);
	if (phyon_t > 1000) {
		PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_, "%s : phy on takes %u (ms).\n"
			  	, __func__, phyon_t);
	}
#endif /* DBG_PHY_ON_TIME */

	if (is_cmd_failure(sts)) {
		/* send cmd success, but wait cmd fail */
		sts = RTW_PHL_STATUS_FAILURE;
	} else if (sts != RTW_PHL_STATUS_SUCCESS) {
		/* send cmd fail */
		sts = RTW_PHL_STATUS_FAILURE;
	}
	return sts;
}

void rtw_phl_stop(void *phl)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;

	_phl_cmd_send_msg_phy_on(phl_info);

	_phl_interrupt_stop(phl_info);
	phl_module_stop(phl_info);

#ifdef DBG_PHL_MR
	phl_mr_info_dbg(phl_info);
#endif

#ifdef CONFIG_FSM
	phl_fsm_module_stop(phl_info);
	phl_fsm_stop(phl_info);
#endif

	rtw_hal_stop(phl_info->phl_com, phl_info->hal);
	phl_datapath_stop(phl_info);

	phl_info->phl_com->dev_state = 0;
}

enum rtw_phl_status phl_wow_start(struct phl_info_t *phl_info, struct rtw_phl_stainfo_t *sta)
{
#ifdef CONFIG_WOWLAN
	enum rtw_phl_status pstatus = RTW_PHL_STATUS_FAILURE;
	enum rtw_hal_status hstatus = RTW_HAL_STATUS_FAILURE;
	struct phl_wow_info *wow_info = phl_to_wow_info(phl_info);

#ifdef CONFIG_SYNC_INTERRUPT
	struct rtw_phl_evt_ops *evt_ops = &phl_info->phl_com->evt_ops;
#endif /* CONFIG_SYNC_INTERRUPT */

	PHL_TRACE(COMP_PHL_WOW, _PHL_INFO_, "[wow] %s enter with sta state(%d)\n.", __func__, sta->wrole->mstate);

	phl_wow_decide_op_mode(wow_info, sta);

	if (wow_info->op_mode == RTW_WOW_OP_PWR_DOWN) {
		phl_cmd_role_suspend(phl_info);
		rtw_phl_stop(phl_info);
		/* since control path stopped after rtw_phl_stop,
		   below action don't have to migrate to general module */
		hstatus = rtw_hal_set_wowlan(phl_info->phl_com, phl_info->hal, true);
		if (RTW_HAL_STATUS_SUCCESS != hstatus)
			PHL_WARN("[wow] rtw_hal_set_wowlan failed, status(%u)\n", hstatus);
		pstatus = RTW_PHL_STATUS_SUCCESS;
	} else {
		/* stop all active features */
		#ifdef CONFIG_WOW_WITH_SER
		rtw_hal_ser_ctrl(phl_info->hal, false);
		#endif

		pstatus = phl_module_stop(phl_info);
		if (RTW_PHL_STATUS_SUCCESS != pstatus) {
			PHL_ERR("[wow] phl_module_stop failed.\n");
			goto end;
		}
		/* since control path stopped after phl_module_stop,
		   below action don't have to migrate to general module */
#ifdef CONFIG_FSM
		pstatus = phl_fsm_module_stop(phl_info);
		if (RTW_PHL_STATUS_SUCCESS != pstatus) {
			PHL_ERR("[wow] phl_fsm_module_stop failed.\n");
			goto end;
		}

		pstatus = phl_fsm_stop(phl_info);
		if (RTW_PHL_STATUS_SUCCESS != pstatus) {
			PHL_ERR("[wow] phl_fsm_stop failed.\n");
			goto end;
		}
#endif
		hstatus = rtw_hal_set_wowlan(phl_info->phl_com, phl_info->hal, true);
		if (RTW_HAL_STATUS_SUCCESS != hstatus)
			PHL_WARN("[wow] rtw_hal_set_wowlan failed, status(%u)\n", hstatus);
		pstatus = phl_wow_init_precfg(wow_info);
		if (RTW_PHL_STATUS_SUCCESS != pstatus) {
			PHL_ERR("[wow] phl_wow_init_precfg failed.\n");
			goto end;
		}

		hstatus = rtw_hal_wow_init(phl_info->phl_com, phl_info->hal, sta);
		if (RTW_HAL_STATUS_SUCCESS != hstatus) {
			pstatus = RTW_PHL_STATUS_FAILURE;
			goto end;
		}

		pstatus = phl_wow_func_en(wow_info);
		if (RTW_PHL_STATUS_SUCCESS != pstatus)
			goto end;
#ifdef CONFIG_POWER_SAVE
		/* power saving */
		phl_wow_ps_proto_cfg(wow_info, true);

		phl_wow_ps_pwr_ntfy(wow_info, true);
#endif
		pstatus = phl_wow_init_postcfg(wow_info);
		if (RTW_PHL_STATUS_SUCCESS != pstatus) {
			PHL_ERR("[wow] phl_wow_init_postcfg failed.\n");
			goto end;
		}
		#ifdef CONFIG_WOW_WITH_SER
		rtw_hal_ser_ctrl(phl_info->hal, true);
		#endif
#ifdef CONFIG_POWER_SAVE
		/* power saving */
		phl_wow_ps_pwr_cfg(wow_info, true);
#endif
		pstatus = RTW_PHL_STATUS_SUCCESS;
	}

end:
	if (RTW_PHL_STATUS_SUCCESS != pstatus) {
		#ifdef CONFIG_SYNC_INTERRUPT
		evt_ops->set_interrupt_caps(phl_to_drvpriv(phl_info), false);
		#else
		rtw_hal_disable_interrupt(phl_info->phl_com, phl_info->hal);
		#endif /* CONFIG_SYNC_INTERRUPT */
		rtw_hal_stop(phl_info->phl_com, phl_info->hal);
		phl_datapath_stop(phl_info);
		wow_info->op_mode = RTW_WOW_OP_PWR_DOWN;
		PHL_ERR("[wow] %s fail, set op_mode %d!\n", __func__, wow_info->op_mode);
	} else {
		PHL_TRACE(COMP_PHL_WOW, _PHL_INFO_,
			"[wow] %s success, with func_en %d, op_mode %d.\n",
			__func__, wow_info->func_en, wow_info->op_mode);
	}

	return pstatus;
#else
	return RTW_PHL_STATUS_SUCCESS;
#endif /* CONFIG_WOWLAN */
}

static void _wow_stop_reinit(struct phl_info_t *phl_info)
{
	enum rtw_phl_status pstatus = RTW_PHL_STATUS_FAILURE;

	PHL_WARN("%s : reset hw!\n", __func__);
	rtw_hal_hal_deinit(phl_info->phl_com, phl_info->hal);
	phl_datapath_stop(phl_info);
	pstatus = rtw_phl_start(phl_info);
	if (pstatus)
		PHL_ERR("%s : rtw_phl_start fail!\n", __func__);
	phl_cmd_role_recover(phl_info);

}

void phl_wow_stop(struct phl_info_t *phl_info, struct rtw_phl_stainfo_t *sta, u8 *hw_reinit)
{
#ifdef CONFIG_WOWLAN
	enum rtw_phl_status pstatus = RTW_PHL_STATUS_FAILURE;
	enum rtw_hal_status hstatus = RTW_HAL_STATUS_FAILURE;
	struct phl_wow_info *wow_info = phl_to_wow_info(phl_info);
	u8 reset = 0;

	if (rtw_hal_get_pwr_state(phl_info->hal, &wow_info->mac_pwr)
		!= RTW_HAL_STATUS_SUCCESS)
		return;

	PHL_TRACE(COMP_PHL_WOW, _PHL_INFO_, "%s enter with mac power %d\n.",
			  __func__, wow_info->mac_pwr);

	if (wow_info->mac_pwr != RTW_MAC_PWR_OFF) {
		#ifdef CONFIG_WOW_WITH_SER
		rtw_hal_ser_ctrl(phl_info->hal, false);
		#endif
		#ifdef CONFIG_POWER_SAVE
		/* leave clock/power gating */
		pstatus = phl_wow_ps_pwr_cfg(wow_info, false);
		if (RTW_PHL_STATUS_SUCCESS != pstatus) {
			PHL_ERR("[wow] HW leave power saving failed.\n");
			_wow_stop_reinit(phl_info);
			*hw_reinit = true;
			return;
		}
		#endif
	}

	hstatus = rtw_hal_set_wowlan(phl_info->phl_com, phl_info->hal, false);
	if (RTW_HAL_STATUS_SUCCESS != hstatus) {
		PHL_WARN("[wow] rtw_hal_set_wowlan failed, status(%u)\n", hstatus);
	}

	if (wow_info->mac_pwr == RTW_MAC_PWR_OFF) {
		if (wow_info->op_mode == RTW_WOW_OP_PWR_DOWN) {
			pstatus = rtw_phl_start(phl_info);
			phl_role_recover(phl_info);
			*hw_reinit = true;
		} else {
			PHL_WARN("[wow] enter suspend with wow enabled but mac is power down\n");
			_wow_stop_reinit(phl_info);
			*hw_reinit = true;
		}
	} else if (wow_info->mac_pwr == RTW_MAC_PWR_ON ||
			   wow_info->mac_pwr == RTW_MAC_PWR_LPS) {

		phl_wow_handle_wake_rsn(wow_info, &reset);
		if (reset) {
			_wow_stop_reinit(phl_info);
			*hw_reinit = true;
			return;
		}

		phl_wow_deinit_precfg(wow_info);

		rtw_hal_fw_dbg_dump(phl_info->hal, false);
#ifdef CONFIG_POWER_SAVE
		phl_wow_ps_pwr_ntfy(wow_info, false);
		/* leave power saving */
		phl_wow_ps_proto_cfg(wow_info, false);
#endif
		phl_wow_func_dis(wow_info);

		hstatus = rtw_hal_wow_deinit(phl_info->phl_com, phl_info->hal, sta);
		if (hstatus)
			PHL_ERR("%s : rtw_hal_wow_deinit failed.\n", __func__);

		phl_module_start(phl_info);
#ifdef CONFIG_FSM
		phl_fsm_start(phl_info);
		phl_fsm_module_start(phl_info);
#endif
		phl_wow_deinit_postcfg(wow_info);
		#ifdef CONFIG_WOW_WITH_SER
		rtw_hal_ser_ctrl(phl_info->hal, true);
		#endif
		*hw_reinit = false;
	} else {
		PHL_ERR("%s : unexpected mac pwr state %d.\n", __func__, wow_info->mac_pwr);
	}

#endif /* CONFIG_WOWLAN */
}

enum rtw_phl_status rtw_phl_rf_on(void *phl)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
	enum rtw_phl_status phl_status = RTW_PHL_STATUS_FAILURE;
	enum rtw_hal_status hal_status = RTW_HAL_STATUS_SUCCESS;
#ifdef CONFIG_SYNC_INTERRUPT
	struct rtw_phl_evt_ops *evt_ops = &phl_info->phl_com->evt_ops;
#endif /* CONFIG_SYNC_INTERRUPT */
	struct phl_data_ctl_t ctl = {0};

	hal_status = rtw_hal_start(phl_info->phl_com, phl_info->hal);
	if (hal_status == RTW_HAL_STATUS_MAC_INIT_FAILURE) {
		phl_status = RTW_PHL_STATUS_HAL_INIT_FAILURE;
		goto error_hal_start;
	} else if (hal_status == RTW_HAL_STATUS_BB_INIT_FAILURE) {
		phl_status = RTW_PHL_STATUS_HAL_INIT_FAILURE;
		goto error_hal_start;
	} else if (hal_status == RTW_HAL_STATUS_RF_INIT_FAILURE) {
		phl_status = RTW_PHL_STATUS_HAL_INIT_FAILURE;
		goto error_hal_start;
	} else if (hal_status == RTW_HAL_STATUS_BTC_INIT_FAILURE) {
		phl_status = RTW_PHL_STATUS_HAL_INIT_FAILURE;
		goto error_hal_start;
	}

	phl_role_recover(phl_info);
#ifdef CONFIG_SYNC_INTERRUPT
	evt_ops->set_interrupt_caps(phl_to_drvpriv(phl_info), true);
#else
	rtw_hal_enable_interrupt(phl_info->phl_com, phl_info->hal);
#endif /* CONFIG_SYNC_INTERRUPT */

	ctl.id = PHL_MDL_POWER_MGNT;
	ctl.cmd = PHL_DATA_CTL_SW_TX_RESUME;
	if (phl_data_ctrler(phl_info, &ctl, NULL) != RTW_PHL_STATUS_SUCCESS)
		PHL_WARN("%s: tx resume fail!\n", __func__);
	ctl.cmd = PHL_DATA_CTL_SW_RX_RESUME;
	if (phl_data_ctrler(phl_info, &ctl, NULL) != RTW_PHL_STATUS_SUCCESS)
		PHL_WARN("%s: rx resume fail!\n", __func__);

	return RTW_PHL_STATUS_SUCCESS;
error_hal_start:
	PHL_ERR("error_hal_start\n");
	return phl_status;
}

#define MAX_RF_OFF_STOP_TRX_TIME 100 /* ms */
enum rtw_phl_status rtw_phl_rf_off(void *phl)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
#ifdef CONFIG_SYNC_INTERRUPT
	struct rtw_phl_evt_ops *evt_ops = &phl_info->phl_com->evt_ops;
#endif /* CONFIG_SYNC_INTERRUPT */
	struct phl_data_ctl_t ctl = {0};

#ifdef CONFIG_SYNC_INTERRUPT
	evt_ops->set_interrupt_caps(phl_to_drvpriv(phl_info), false);
#else
	rtw_hal_disable_interrupt(phl_info->phl_com, phl_info->hal);
#endif /* CONFIG_SYNC_INTERRUPT */

	ctl.id = PHL_MDL_POWER_MGNT;
	ctl.cmd = PHL_DATA_CTL_SW_TX_PAUSE;
	if (phl_data_ctrler(phl_info, &ctl, NULL) != RTW_PHL_STATUS_SUCCESS)
		PHL_WARN("%s: tx pause fail!\n", __func__);
	ctl.cmd = PHL_DATA_CTL_SW_RX_PAUSE;
	if (phl_data_ctrler(phl_info, &ctl, NULL) != RTW_PHL_STATUS_SUCCESS)
		PHL_WARN("%s: rx pause fail!\n", __func__);

	phl_role_suspend(phl_info);
	rtw_hal_stop(phl_info->phl_com, phl_info->hal);

	ctl.cmd = PHL_DATA_CTL_SW_TX_RESET;
	if (phl_data_ctrler(phl_info, &ctl, NULL) != RTW_PHL_STATUS_SUCCESS)
		PHL_WARN("%s: tx reset fail!\n", __func__);
	ctl.cmd = PHL_DATA_CTL_SW_RX_RESET;
	if (phl_data_ctrler(phl_info, &ctl, NULL) != RTW_PHL_STATUS_SUCCESS)
		PHL_WARN("%s: rx reset fail!\n", __func__);

	return RTW_PHL_STATUS_SUCCESS;
}

enum rtw_phl_status rtw_phl_suspend(void *phl, struct rtw_phl_stainfo_t *sta, u8 wow_en)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
	enum rtw_phl_status pstatus = RTW_PHL_STATUS_SUCCESS;

	PHL_INFO("%s enter with wow_en(%d)\n.", __func__, wow_en);
#ifdef CONFIG_WOWLAN
	pstatus = _phl_cmd_send_msg_phy_on(phl_info);
	if (RTW_PHL_STATUS_SUCCESS != pstatus) {
		PHL_ERR("[wow] _phl_cmd_send_msg_phy_on fail!\n");
		wow_en = false;
	}

	if (wow_en) {
		pstatus = phl_wow_start(phl_info, sta);
	} else {
		phl_cmd_role_suspend(phl_info);
		rtw_phl_stop(phl);
	}
#else
	PHL_INFO("%s enter with wow_en(%d)\n.", __func__, wow_en);

	phl_cmd_role_suspend(phl_info);
	rtw_phl_stop(phl);
#endif

	FUNCOUT_WSTS(pstatus);

	return pstatus;
}

enum rtw_phl_status rtw_phl_resume(void *phl, struct rtw_phl_stainfo_t *sta, u8 *hw_reinit)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
	enum rtw_phl_status pstatus = RTW_PHL_STATUS_SUCCESS;
#ifdef CONFIG_WOWLAN
	struct phl_wow_info *wow_info = phl_to_wow_info(phl_info);
#endif

	/**
	 * Since some platforms require performance when device resuming, we need
	 * to finish "rtw_phl_resume" as fast as possible. In this situation, we
	 * prevent ps module entering any power saving mechanisms and try to do I/O
	 * operations directly without issue commands to cmd dispatcher. Therefore,
	 * ps module will not enter power saving if device state "RTW_DEV_RESUMING"
	 * is set. If device state "RTW_DEV_RESUMING" is set, operations of I/O
	 * should check whether the current power state can perform I/O or not and
	 * perform I/O directly without issuing commands to cmd dispatcher if device
	 * power state is I/O allowable. This kind of flow is only suitable for
	 * "rtw_phl_resume" because core layer will not perform any other tasks when
	 * calling rtw_phl_resume which is relatively simple enough.
	 */
	PHL_INFO("%s enter...\n.", __func__);
	SET_STATUS_FLAG(phl_info->phl_com->dev_state, RTW_DEV_RESUMING);

#ifdef CONFIG_WOWLAN
	if (wow_info->op_mode != RTW_WOW_OP_NONE) {
		phl_wow_stop(phl_info, sta, hw_reinit);
	} else {
		pstatus = rtw_phl_start(phl);
		#ifdef CONFIG_POWER_SAVE
		if (phl_ps_get_cur_pwr_lvl(phl_info) == PS_PWR_LVL_PWRON)
		#endif
			phl_role_recover(phl_info);
		*hw_reinit = true;
	}
	#if defined(RTW_WKARD_WOW_L2_PWR) && defined(CONFIG_PCI_HCI)
	rtw_hal_set_l2_leave(phl_info->hal);
	#endif
	phl_record_wow_stat(wow_info);
	phl_reset_wow_info(wow_info);
#else
	pstatus = rtw_phl_start(phl);
	#ifdef CONFIG_POWER_SAVE
	if (phl_ps_get_cur_pwr_lvl(phl_info) == PS_PWR_LVL_PWRON)
	#endif
		phl_role_recover(phl_info);
	*hw_reinit = true;
#endif

	CLEAR_STATUS_FLAG(phl_info->phl_com->dev_state, RTW_DEV_RESUMING);

	PHL_INFO("%s exit with hw_reinit %d.\n.", __func__, *hw_reinit);

	return pstatus;
}

enum rtw_phl_status rtw_phl_reset(void *phl)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
	struct phl_hci_trx_ops *ops = phl_info->hci_trx_ops;
	enum rtw_phl_status phl_status = RTW_PHL_STATUS_FAILURE;

	if(rtw_phl_is_init_completed(phl_info))
		phl_status = RTW_PHL_STATUS_SUCCESS;

	rtw_hal_stop(phl_info->phl_com, phl_info->hal);

	ops->trx_reset(phl_info, PHL_CTRL_TX|PHL_CTRL_RX);
	ops->trx_resume(phl_info, PHL_CTRL_TX|PHL_CTRL_RX);

	rtw_hal_start(phl_info->phl_com, phl_info->hal);
	/* Leave power save */
	/* scan abort */
	/* STA disconnect/stop AP/Stop p2p function */

	return phl_status;
}

enum rtw_phl_status rtw_phl_restart(void *phl)
{
	enum rtw_phl_status phl_status = RTW_PHL_STATUS_FAILURE;

	phl_status = RTW_PHL_STATUS_SUCCESS;

	return phl_status;
}


/******************* IO  APIs *******************/
u8 rtw_phl_read8(void *phl, u32 addr)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;

	return rtw_hal_read8(phl_info->hal, addr);
}
u16 rtw_phl_read16(void *phl, u32 addr)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;

	return rtw_hal_read16(phl_info->hal, addr);
}
u32 rtw_phl_read32(void *phl, u32 addr)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;

	return rtw_hal_read32(phl_info->hal, addr);
}
void rtw_phl_write8(void *phl, u32 addr, u8 val)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;

	rtw_hal_write8(phl_info->hal, addr, val);
}
void rtw_phl_write16(void *phl, u32 addr, u16 val)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;

	rtw_hal_write16(phl_info->hal, addr, val);
}
void rtw_phl_write32(void *phl, u32 addr, u32 val)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;

	rtw_hal_write32(phl_info->hal, addr, val);
}
u32 rtw_phl_read_macreg(void *phl, u32 offset, u32 bit_mask)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;

	return rtw_hal_read_macreg(phl_info->hal, offset, bit_mask);
}
void rtw_phl_write_macreg(void *phl,
			u32 offset, u32 bit_mask, u32 data)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;

	rtw_hal_write_macreg(phl_info->hal, offset, bit_mask, data);

}
u32 rtw_phl_read_bbreg(void *phl, u32 offset, u32 bit_mask)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;

	return rtw_hal_read_bbreg(phl_info->hal, offset, bit_mask);
}
void rtw_phl_write_bbreg(void *phl,
			u32 offset, u32 bit_mask, u32 data)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;

	rtw_hal_write_bbreg(phl_info->hal, offset, bit_mask, data);

}
u32 rtw_phl_read_rfreg(void *phl,
			enum rf_path path, u32 offset, u32 bit_mask)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;

	return rtw_hal_read_rfreg(phl_info->hal, path, offset, bit_mask);
}
void rtw_phl_write_rfreg(void *phl,
			enum rf_path path, u32 offset, u32 bit_mask, u32 data)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;

	rtw_hal_write_rfreg(phl_info->hal, path, offset, bit_mask, data);

}

void rtw_phl_restore_interrupt(void *phl)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
	rtw_hal_restore_interrupt(phl_info->phl_com, phl_info->hal);
}

enum rtw_phl_status rtw_phl_interrupt_handler(void *phl)
{
	enum rtw_phl_status phl_status = RTW_PHL_STATUS_SUCCESS;
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
	u32 int_hdler_msk = 0x0;
#ifdef CONFIG_SYNC_INTERRUPT
	struct rtw_phl_evt_ops *ops = &phl_info->phl_com->evt_ops;
#endif /* CONFIG_SYNC_INTERRUPT */
	int_hdler_msk = rtw_hal_interrupt_handler(phl_info->hal);

	if (!int_hdler_msk) {
		PHL_WARN("%s : 0x%x\n", __func__, int_hdler_msk);
		phl_status = RTW_PHL_STATUS_FAILURE;
		goto end;
	}

	PHL_DBG("%s : 0x%x\n", __func__, int_hdler_msk);
	/* beacon interrupt */
	if (int_hdler_msk & BIT0)
		;/* todo */

	/* rx interrupt */
	if (int_hdler_msk & BIT1) {
#if defined(CONFIG_SDIO_HCI) && defined(CONFIG_PHL_SDIO_READ_RXFF_IN_INT)
		phl_info->hci_trx_ops->recv_rxfifo(phl);
#else
		phl_status = rtw_phl_start_rx_process(phl);
#endif

#if defined(CONFIG_PCI_HCI) && !defined(CONFIG_DYNAMIC_RX_BUF)
		/* phl_status = hci_trx_ops->recycle_busy_wd(phl); */
#endif
	}

	/* tx interrupt */
	if (int_hdler_msk & BIT2)
		;

	/* cmd interrupt */
	if (int_hdler_msk & BIT3)
		;/* todo */

	/* halt c2h interrupt */
	if (int_hdler_msk & BIT4)
		phl_status = phl_ser_send_msg(phl, RTW_PHL_SER_EVENT_CHK);

	/* halt c2h interrupt */
	if (int_hdler_msk & BIT5)
		phl_status = phl_fw_watchdog_timeout_notify(phl);

	/* halt c2h interrupt - send msg to SER FSM to check ser event */
	if (int_hdler_msk & BIT6)
		phl_status = phl_ser_send_msg(phl, RTW_PHL_SER_EVENT_CHK);

	if (phl_status != RTW_PHL_STATUS_SUCCESS)
		PHL_INFO("rtw_phl_interrupt_handler fail !!\n");

	/* schedule tx process */
	phl_status = phl_schedule_handler(phl_info->phl_com, &phl_info->phl_tx_handler);
end:

#ifdef CONFIG_SYNC_INTERRUPT
	ops->interrupt_restore(phl_to_drvpriv(phl_info), false);
#endif
	return phl_status;
}

void rtw_phl_enable_interrupt(void *phl)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
	rtw_hal_enable_interrupt(phl_info->phl_com, phl_info->hal);
}

void rtw_phl_disable_interrupt(void *phl)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
	rtw_hal_disable_interrupt(phl_info->phl_com, phl_info->hal);
}

bool rtw_phl_recognize_interrupt(void *phl)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;

	return rtw_hal_recognize_interrupt(phl_info->hal);
}

void rtw_phl_clear_interrupt(void *phl)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;

	rtw_hal_clear_interrupt(phl_info->hal);
}

enum rtw_phl_status rtw_phl_msg_hub_register_recver(void* phl,
		struct phl_msg_receiver* ctx, enum phl_msg_recver_layer layer)
{
	return phl_msg_hub_register_recver(phl, ctx, layer);
}
enum rtw_phl_status rtw_phl_msg_hub_update_recver_mask(void* phl,
		enum phl_msg_recver_layer layer, u8* mdl_id, u32 len, u8 clr)
{
	return phl_msg_hub_update_recver_mask(phl, layer, mdl_id, len, clr);
}
enum rtw_phl_status rtw_phl_msg_hub_deregister_recver(void* phl,
					enum phl_msg_recver_layer layer)
{
	return phl_msg_hub_deregister_recver(phl, layer);
}
enum rtw_phl_status rtw_phl_msg_hub_send(void* phl,
			struct phl_msg_attribute* attr, struct phl_msg* msg)
{
	return phl_msg_hub_send((struct phl_info_t*)phl, attr, msg);
}
#ifdef PHL_PLATFORM_LINUX
void rtw_phl_mac_reg_dump(void *sel, void *phl)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;

	rtw_hal_mac_reg_dump(sel, phl_info->hal);
}

void rtw_phl_bb_reg_dump(void *sel, void *phl)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;

	rtw_hal_bb_reg_dump(sel, phl_info->hal);
}

void rtw_phl_bb_reg_dump_ex(void *sel, void *phl)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;

	rtw_hal_bb_reg_dump_ex(sel, phl_info->hal);
}

void rtw_phl_rf_reg_dump(void *sel, void *phl)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;

	rtw_hal_rf_reg_dump(sel, phl_info->hal);
}
#endif

/**
 * rtw_phl_get_sec_cam() - get the security cam raw data from HW
 * @phl:		struct phl_info_t *
 * @num:		How many cam you wnat to dump from the first one.
 * @buf:		ptr to buffer which store the content from HW.
 *			If buf is NULL, use console as debug path.
 * @size		Size of allocated memroy for @buf.
 *			The size should be @num * size of security cam offset(0x20).
 *
 * Return true when function successfully works, otherwise, return fail.
 */
bool rtw_phl_get_sec_cam(void *phl, u16 num, u8 *buf, u16 size)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
	enum rtw_hal_status ret = RTW_HAL_STATUS_SUCCESS;

	ret = rtw_hal_get_sec_cam(phl_info->hal, num, buf, size);
	if (ret != RTW_HAL_STATUS_SUCCESS)
		return false;

	return true;
}

/**
 * rtw_phl_get_addr_cam() - get the address cam raw data from HW
 * @phl:		struct phl_info_t *
 * @num:		How many cam you wnat to dump from the first one.
 * @buf:		ptr to buffer which store the content from HW.
 *			If buf is NULL, use console as debug path.
 * @size		Size of allocated memroy for @buf.
 *			The size should be @num * size of Addr cam offset(0x40).
 *
 * Return true when function successfully works, otherwise, return fail.
 */
bool rtw_phl_get_addr_cam(void *phl, u16 num, u8 *buf, u16 size)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
	enum rtw_hal_status ret = RTW_HAL_STATUS_SUCCESS;

	ret = rtw_hal_get_addr_cam(phl_info->hal, num, buf, size);
	if (ret != RTW_HAL_STATUS_SUCCESS)
		return false;

	return true;
}

void rtw_phl_mac_dbg_status_dump(void *phl, u32 *val, u8 *en)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
	struct hal_mac_dbg_dump_cfg cfg = {0};

	cfg.ss_dbg_0 = val[0];
	cfg.ss_dbg_1 = val[1];

	cfg.ss_dbg = (*en & BIT0);
	cfg.dle_dbg = (*en & BIT1) >> 1;
	cfg.dmac_dbg = (*en & BIT2) >> 2;
	cfg.cmac_dbg = (*en & BIT3) >> 3;
	cfg.mac_dbg_port = (*en & BIT4) >> 4;
	cfg.plersvd_dbg = (*en & BIT5) >> 5;
	cfg.tx_flow_dbg = (*en & BIT6) >> 6;

	rtw_hal_dbg_status_dump(phl_info->hal, &cfg);
}

enum rtw_phl_status rtw_phl_get_mac_addr_efuse(void* phl, u8 *addr)
{
	enum rtw_phl_status pstatus = RTW_PHL_STATUS_SUCCESS;
	enum rtw_hal_status hstatus = RTW_HAL_STATUS_SUCCESS;
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
	void *d = phl_to_drvpriv(phl_info);
	u8 addr_efuse[MAC_ADDRESS_LENGTH] = {0};

	hstatus = rtw_hal_get_efuse_info(phl_info->hal,
			EFUSE_INFO_MAC_ADDR,
			(void *)addr_efuse,
			MAC_ADDRESS_LENGTH);
	if (is_broadcast_mac_addr(addr_efuse)) {
		PHL_INFO("[WARNING] MAC Address from EFUSE is FF:FF:FF:FF:FF:FF\n");
		hstatus = RTW_HAL_STATUS_FAILURE;
	}
	if (RTW_HAL_STATUS_SUCCESS != hstatus) {
		pstatus = RTW_PHL_STATUS_FAILURE;
	} else {
		_os_mem_cpy(d, addr, addr_efuse, MAC_ADDRESS_LENGTH);
		PHL_INFO("%s : 0x%2x - 0x%2x - 0x%2x - 0x%2x - 0x%2x - 0x%2x\n",
			 __func__, addr[0], addr[1], addr[2],
			 addr[3], addr[4], addr[5]);

	}
	return pstatus;
}

enum rtw_phl_status
rtw_phl_cfg_trx_path(void* phl, enum rf_path tx, u8 tx_nss,
		     enum rf_path rx, u8 rx_nss)
{
	enum rtw_phl_status pstatus = RTW_PHL_STATUS_SUCCESS;
	enum rtw_hal_status hstatus = RTW_HAL_STATUS_SUCCESS;
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;

	hstatus = rtw_hal_cfg_trx_path(phl_info->hal, tx, tx_nss, rx, rx_nss);

	if (RTW_HAL_STATUS_SUCCESS != hstatus)
		pstatus = RTW_PHL_STATUS_FAILURE;

	return pstatus;
}


void rtw_phl_reset_stat_ma_rssi(struct rtw_phl_com_t *phl_com)
{
	u8 i = 0, j = 0;
	PHL_INFO("--> %s\n", __func__);
	do{
		if (NULL == phl_com)
			break;

		_os_spinlock(phl_com->drv_priv,
			     &(phl_com->rssi_stat.lock), _bh, NULL);
		for (i = 0; i < RTW_RSSI_TYPE_MAX; i++) {
			phl_com->rssi_stat.ma_rssi_ele_idx[i] = 0;
			phl_com->rssi_stat.ma_rssi_ele_cnt[i] = 0;
			phl_com->rssi_stat.ma_rssi_ele_sum[i] = 0;
			phl_com->rssi_stat.ma_rssi[i] = 0;
			for (j = 0; j < PHL_RSSI_MAVG_NUM; j++)
				phl_com->rssi_stat.ma_rssi_ele[i][j] = 0;
		}
		_os_spinunlock(phl_com->drv_priv,
			       &(phl_com->rssi_stat.lock), _bh, NULL);
	} while (0);

	PHL_INFO("<-- %s\n", __func__);
}

u8
rtw_phl_get_ma_rssi(struct rtw_phl_com_t *phl_com,
		    enum rtw_rssi_type rssi_type)
{

	u8 ret = 0;
	if (NULL == phl_com)
		return ret;

	_os_spinlock(phl_com->drv_priv,
		     &(phl_com->rssi_stat.lock), _bh, NULL);
	ret = phl_com->rssi_stat.ma_rssi[rssi_type];
	_os_spinunlock(phl_com->drv_priv,
		       &(phl_com->rssi_stat.lock), _bh, NULL);

	return ret;
}

#ifdef RTW_WKARD_DYNAMIC_BFEE_CAP
enum rtw_phl_status
rtw_phl_bfee_ctrl(void *phl, struct rtw_wifi_role_t *wrole, bool ctrl)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
	enum rtw_phl_status pstatus = RTW_PHL_STATUS_SUCCESS;
	if (RTW_HAL_STATUS_SUCCESS !=
	    rtw_hal_bf_bfee_ctrl(phl_info->hal, wrole->hw_band, ctrl)) {
		pstatus = RTW_PHL_STATUS_FAILURE;
	}
	return pstatus;
}
#endif

u8
rtw_phl_get_sta_mgnt_rssi(struct rtw_phl_stainfo_t *psta)
{
	u8 ret = PHL_MAX_RSSI;

	if (psta != NULL) {
		ret  = psta->hal_sta->rssi_stat.ma_rssi_mgnt;
	}

	return ret;
}