/******************************************************************************
 *
 * Copyright(c) 2019 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.
 *
 ******************************************************************************/

#include "twt.h"

u32 mac_twt_info_upd_h2c(struct mac_ax_adapter *adapter,
			 struct mac_ax_twt_para *info)
{
	#if MAC_AX_PHL_H2C
	struct rtw_h2c_pkt *h2cb;
	#else
	struct h2c_buf *h2cb;
	#endif
	struct fwcmd_twtinfo_upd *hdr;
	u32 ret = MACSUCCESS;

	h2cb = h2cb_alloc(adapter, H2CB_CLASS_CMD);
	if (!h2cb)
		return MACNPTR;

	hdr = (struct fwcmd_twtinfo_upd *)
		h2cb_put(h2cb, sizeof(struct fwcmd_twtinfo_upd));
	if (!hdr) {
		ret = MACNOBUF;
		goto fail;
	}

	/* port 4 not support */
	if (info->port >= MAC_AX_PORT_4) {
		PLTFM_MSG_ERR("[ERR] twt info upd h2c port %d\n", info->port);
		return MACFUNCINPUT;
	}

	hdr->dword0 =
		cpu_to_le32(SET_WORD(info->nego_tp,
				     FWCMD_H2C_TWTINFO_UPD_NEGOTYPE) |
			    SET_WORD(info->act, FWCMD_H2C_TWTINFO_UPD_ACT) |
			    (info->trig ? FWCMD_H2C_TWTINFO_UPD_TRIGGER : 0) |
			    (info->flow_tp ?
			     FWCMD_H2C_TWTINFO_UPD_FLOWTYPE : 0) |
			    (info->impt ? FWCMD_H2C_TWTINFO_UPD_IMPT : 0) |
			    (info->wake_unit ?
			     FWCMD_H2C_TWTINFO_UPD_WAKEDURUNIT : 0) |
			    (info->rsp_pm ? FWCMD_H2C_TWTINFO_UPD_RSPPM : 0) |
			    (info->proct ? FWCMD_H2C_TWTINFO_UPD_PROT : 0) |
			    SET_WORD(info->flow_id,
				     FWCMD_H2C_TWTINFO_UPD_FLOWID) |
			    SET_WORD(info->id, FWCMD_H2C_TWTINFO_UPD_ID) |
			    (info->band ? FWCMD_H2C_TWTINFO_UPD_BAND : 0) |
			    SET_WORD(info->port, FWCMD_H2C_TWTINFO_UPD_PORT));

	hdr->dword1 =
		cpu_to_le32(SET_WORD(info->wake_exp,
				     FWCMD_H2C_TWTINFO_UPD_WAKE_EXP) |
			    SET_WORD(info->wake_man,
				     FWCMD_H2C_TWTINFO_UPD_WAKE_MAN) |
			    SET_WORD(info->twtulfixmode,
				     FWCMD_H2C_TWTINFO_UPD_ULFIXMODE) |
			    SET_WORD(info->dur,
				     FWCMD_H2C_TWTINFO_UPD_DUR));

	hdr->dword2 =
		cpu_to_le32(SET_WORD(info->trgt_l,
				     FWCMD_H2C_TWTINFO_UPD_TGT_L));

	hdr->dword3 =
		cpu_to_le32(SET_WORD(info->trgt_h,
				     FWCMD_H2C_TWTINFO_UPD_TGT_H));

	ret = h2c_pkt_set_hdr(adapter, h2cb,
			      FWCMD_TYPE_H2C,
			      FWCMD_H2C_CAT_MAC,
			      FWCMD_H2C_CL_TWT,
			      FWCMD_H2C_FUNC_TWTINFO_UPD,
			      0,
			      1);
	if (ret)
		goto fail;

	ret = h2c_pkt_build_txd(adapter, h2cb);
	if (ret)
		goto fail;

	#if MAC_AX_PHL_H2C
	ret = PLTFM_TX(h2cb);
	#else
	ret = PLTFM_TX(h2cb->data, h2cb->len);
	#endif
	if (ret)
		goto fail;

	h2cb_free(adapter, h2cb);

	h2c_end_flow(adapter);

	return MACSUCCESS;
fail:
	h2cb_free(adapter, h2cb);

	return ret;
}

u32 mac_twt_act_h2c(struct mac_ax_adapter *adapter,
		    struct mac_ax_twtact_para *info)
{
	#if MAC_AX_PHL_H2C
	struct rtw_h2c_pkt *h2cb;
	#else
	struct h2c_buf *h2cb;
	#endif
	struct fwcmd_twt_stansp_upd *hdr;
	u32 ret = MACSUCCESS;

	h2cb = h2cb_alloc(adapter, H2CB_CLASS_CMD);
	if (!h2cb)
		return MACNPTR;

	hdr = (struct fwcmd_twt_stansp_upd *)
		h2cb_put(h2cb, sizeof(struct fwcmd_twt_stansp_upd));
	if (!hdr) {
		ret = MACNOBUF;
		goto fail;
	}

	hdr->dword0 =
		cpu_to_le32(SET_WORD(info->macid,
				     FWCMD_H2C_TWT_STANSP_UPD_MACID) |
			    SET_WORD(info->id,
				     FWCMD_H2C_TWT_STANSP_UPD_ID) |
			    SET_WORD(info->act,
				     FWCMD_H2C_TWT_STANSP_UPD_ACT));

	ret = h2c_pkt_set_hdr(adapter, h2cb,
			      FWCMD_TYPE_H2C,
			      FWCMD_H2C_CAT_MAC,
			      FWCMD_H2C_CL_TWT,
			      FWCMD_H2C_FUNC_TWT_STANSP_UPD,
			      0,
			      1);
	if (ret)
		goto fail;

	ret = h2c_pkt_build_txd(adapter, h2cb);
	if (ret)
		goto fail;

	#if MAC_AX_PHL_H2C
	ret = PLTFM_TX(h2cb);
	#else
	ret = PLTFM_TX(h2cb->data, h2cb->len);
	#endif
	if (ret)
		goto fail;

	h2cb_free(adapter, h2cb);

	h2c_end_flow(adapter);

	return MACSUCCESS;
fail:
	h2cb_free(adapter, h2cb);

	return ret;
}

u32 mac_twt_staanno_h2c(struct mac_ax_adapter *adapter,
			struct mac_ax_twtanno_para *info)
{
	#if MAC_AX_PHL_H2C
		struct rtw_h2c_pkt *h2cb;
	#else
		struct h2c_buf *h2cb;
	#endif
		struct fwcmd_twt_announce_upd *hdr;
		u32 ret = MACSUCCESS;

		h2cb = h2cb_alloc(adapter, H2CB_CLASS_CMD);
		if (!h2cb)
			return MACNPTR;

		hdr = (struct fwcmd_twt_announce_upd *)h2cb_put(h2cb,
			sizeof(struct fwcmd_twt_announce_upd));
		if (!hdr) {
			ret = MACNOBUF;
			goto fail;
		}

		hdr->dword0 =
			cpu_to_le32(SET_WORD(info->macid, FWCMD_H2C_TWT_ANNOUNCE_UPD_MACID));

		ret = h2c_pkt_set_hdr(adapter, h2cb,
				      FWCMD_TYPE_H2C,
				      FWCMD_H2C_CAT_MAC,
				      FWCMD_H2C_CL_TWT,
				      FWCMD_H2C_FUNC_TWT_ANNOUNCE_UPD,
				      1,
				      0);
		if (ret)
			goto fail;

		ret = h2c_pkt_build_txd(adapter, h2cb);
		if (ret)
			goto fail;

	#if MAC_AX_PHL_H2C
		ret = PLTFM_TX(h2cb);
	#else
		ret = PLTFM_TX(h2cb->data, h2cb->len);
	#endif
		if (ret)
			goto fail;

		h2cb_free(adapter, h2cb);

		h2c_end_flow(adapter);

		return MACSUCCESS;
fail:
		h2cb_free(adapter, h2cb);

		return ret;
}

void mac_twt_wait_anno(struct mac_ax_adapter *adapter,
		       u8 *c2h_content, u8 *upd_addr)
{
	u32 plat_c2h_content = *(u32 *)(c2h_content);
	struct mac_ax_twtanno_c2hpara *para =
		(struct mac_ax_twtanno_c2hpara *)upd_addr;

	para->wait_case = GET_FIELD(plat_c2h_content,
				    FWCMD_C2H_WAIT_ANNOUNCE_WAIT_CASE);
	para->macid0 = GET_FIELD(plat_c2h_content,
				 FWCMD_C2H_WAIT_ANNOUNCE_MACID0);
	para->macid1 = GET_FIELD(plat_c2h_content,
				 FWCMD_C2H_WAIT_ANNOUNCE_MACID1);
	para->macid2 = GET_FIELD(plat_c2h_content,
				 FWCMD_C2H_WAIT_ANNOUNCE_MACID2);
}

void mac_get_tsf(struct mac_ax_adapter *adapter,
		 struct mac_ax_port_tsf *tsf)
{
	struct mac_ax_intf_ops *ops = adapter_to_intf_ops(adapter);
	u32 reg_l = 0;
	u32 reg_h = 0;

	switch (tsf->port) {
	case 0:
		reg_h = R_AX_TSFTR_HIGH_P0;
		reg_l = R_AX_TSFTR_LOW_P0;
	break;
	case 1:
		reg_h = R_AX_TSFTR_HIGH_P1;
		reg_l = R_AX_TSFTR_LOW_P1;
	break;
	case 2:
		reg_h = R_AX_TSFTR_HIGH_P2;
		reg_l = R_AX_TSFTR_LOW_P2;
	break;
	case 3:
		reg_h = R_AX_TSFTR_HIGH_P3;
		reg_l = R_AX_TSFTR_LOW_P3;
	break;
	default:
		reg_h = R_AX_TSFTR_HIGH_P0;
		reg_l = R_AX_TSFTR_LOW_P0;
	break;
	}

	tsf->tsf_h = MAC_REG_R32(reg_h);
	tsf->tsf_l = MAC_REG_R32(reg_l);
}

