/******************************************************************************
 *
 * 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 "mport.h"
#include "../mac_ax.h"

#define MAX_TSF_SOURCE_PORT 7
#define MAX_TSF_TARGET_PORT 4
#define MAX_TSF_SYNC_OFFSET 0x3FFFF

static u32 cfg_regl[MAC_AX_BAND_NUM][MAC_AX_PORT_NUM] = {
	{R_AX_PORT_CFG_P0, R_AX_PORT_CFG_P1, R_AX_PORT_CFG_P2,
	 R_AX_PORT_CFG_P3, R_AX_PORT_CFG_P4},
	{R_AX_PORT_CFG_P0_C1, R_AX_PORT_CFG_P1_C1, R_AX_PORT_CFG_P2_C1,
	 R_AX_PORT_CFG_P3_C1, R_AX_PORT_CFG_P4_C1}
};

static u32 phb_regl[MAC_AX_BAND_NUM][MAC_AX_PORT_NUM] = {
	{R_AX_TBTT_PROHIB_P0, R_AX_TBTT_PROHIB_P1, R_AX_TBTT_PROHIB_P1,
	 R_AX_TBTT_PROHIB_P1, R_AX_TBTT_PROHIB_P1},
	{R_AX_TBTT_PROHIB_P0_C1, R_AX_TBTT_PROHIB_P1_C1, R_AX_TBTT_PROHIB_P1_C1,
	 R_AX_TBTT_PROHIB_P1_C1, R_AX_TBTT_PROHIB_P1_C1}
};

static u32 ctnarea_regl[MAC_AX_BAND_NUM][MAC_AX_PORT_NUM] = {
	{R_AX_BCN_AREA_P0, R_AX_BCN_AREA_P1, R_AX_BCN_AREA_P1,
	 R_AX_BCN_AREA_P1, R_AX_BCN_AREA_P1},
	{R_AX_BCN_AREA_P0_C1, R_AX_BCN_AREA_P1_C1, R_AX_BCN_AREA_P1_C1,
	 R_AX_BCN_AREA_P1_C1, R_AX_BCN_AREA_P1_C1}
};

static u32 mskarea_regl[MAC_AX_BAND_NUM][MAC_AX_PORT_NUM] = {
	{R_AX_BCN_AREA_P0, R_AX_BCN_AREA_P1, R_AX_BCN_AREA_P2,
	 R_AX_BCN_AREA_P3, R_AX_BCN_AREA_P4},
	{R_AX_BCN_AREA_P0_C1, R_AX_BCN_AREA_P1_C1, R_AX_BCN_AREA_P2_C1,
	 R_AX_BCN_AREA_P3_C1, R_AX_BCN_AREA_P4_C1}
};

static u32 tbttagg_regl[MAC_AX_BAND_NUM][MAC_AX_PORT_NUM] = {
	{R_AX_TBTT_AGG_P0, R_AX_TBTT_AGG_P1, R_AX_TBTT_AGG_P2,
	 R_AX_TBTT_AGG_P3, R_AX_TBTT_AGG_P4},
	{R_AX_TBTT_AGG_P0_C1, R_AX_TBTT_AGG_P1_C1, R_AX_TBTT_AGG_P2_C1,
	 R_AX_TBTT_AGG_P3_C1, R_AX_TBTT_AGG_P4_C1}
};

static u32 tbttery_regl[MAC_AX_BAND_NUM][MAC_AX_PORT_NUM] = {
	{R_AX_TBTTERLYINT_CFG_P0, R_AX_TBTTERLYINT_CFG_P1,
	 R_AX_TBTTERLYINT_CFG_P2, R_AX_TBTTERLYINT_CFG_P3,
	 R_AX_TBTTERLYINT_CFG_P4},
	{R_AX_TBTTERLYINT_CFG_P0_C1, R_AX_TBTTERLYINT_CFG_P1_C1,
	 R_AX_TBTTERLYINT_CFG_P2_C1, R_AX_TBTTERLYINT_CFG_P3_C1,
	 R_AX_TBTTERLYINT_CFG_P4_C1}
};

static u32 bcnspc_regl[MAC_AX_BAND_NUM][MAC_AX_PORT_NUM] = {
	{R_AX_BCN_SPACE_CFG_P0, R_AX_BCN_SPACE_CFG_P1, R_AX_BCN_SPACE_CFG_P2,
	 R_AX_BCN_SPACE_CFG_P3, R_AX_BCN_SPACE_CFG_P4},
	{R_AX_BCN_SPACE_CFG_P0_C1, R_AX_BCN_SPACE_CFG_P1_C1,
	 R_AX_BCN_SPACE_CFG_P2_C1, R_AX_BCN_SPACE_CFG_P3_C1,
	 R_AX_BCN_SPACE_CFG_P4_C1}
};

static u32 tbttsht_regl[MAC_AX_BAND_NUM][MAC_AX_PORT_NUM] = {
	{R_AX_TBTT_SHIFT_P0, R_AX_TBTT_SHIFT_P1, R_AX_TBTT_SHIFT_P2,
	 R_AX_TBTT_SHIFT_P3, R_AX_TBTT_SHIFT_P4},
	{R_AX_TBTT_SHIFT_P0_C1, R_AX_TBTT_SHIFT_P1_C1, R_AX_TBTT_SHIFT_P2_C1,
	 R_AX_TBTT_SHIFT_P3_C1, R_AX_TBTT_SHIFT_P4_C1}
};

static u32 bcndrp_regl[MAC_AX_BAND_NUM] = {
	R_AX_BCN_DROP_ALL0, R_AX_BCN_DROP_ALL0_C1
};

static u32 mbssid_drp_regl[MAC_AX_BAND_NUM] = {
	R_AX_BCN_DROP_ALL0_P0MB, R_AX_BCN_DROP_ALL0_P0MB_C1
};

static u32 bcnpsr_regl[MAC_AX_BAND_NUM][MAC_AX_PORT_NUM] = {
	{R_AX_BCN_PSR_RPT_P0, R_AX_BCN_PSR_RPT_P1, R_AX_BCN_PSR_RPT_P2,
	 R_AX_BCN_PSR_RPT_P3, R_AX_BCN_PSR_RPT_P4},
	{R_AX_BCN_PSR_RPT_P0_C1, R_AX_BCN_PSR_RPT_P1_C1, R_AX_BCN_PSR_RPT_P2_C1,
	 R_AX_BCN_PSR_RPT_P3_C1, R_AX_BCN_PSR_RPT_P4_C1}
};

static u32 cnt_tmr_regl[MAC_AX_BAND_NUM][MAC_AX_PORT_NUM] = {
	{R_AX_BCN_CNT_TMR_P0, R_AX_BCN_CNT_TMR_P1, R_AX_BCN_CNT_TMR_P2,
	 R_AX_BCN_CNT_TMR_P3, R_AX_BCN_CNT_TMR_P4},
	{R_AX_BCN_CNT_TMR_P0_C1, R_AX_BCN_CNT_TMR_P1_C1, R_AX_BCN_CNT_TMR_P2_C1,
	 R_AX_BCN_CNT_TMR_P3_C1, R_AX_BCN_CNT_TMR_P4_C1}
};

static u32 hiq_win_port_regl[MAC_AX_BAND_NUM][MAC_AX_PORT_NUM] = {
	{R_AX_P0MB_HGQ_WINDOW_CFG_0, R_AX_PORT_HGQ_WINDOW_CFG,
	 R_AX_PORT_HGQ_WINDOW_CFG + 1, R_AX_PORT_HGQ_WINDOW_CFG + 2,
	 R_AX_PORT_HGQ_WINDOW_CFG + 3},
	{R_AX_P0MB_HGQ_WINDOW_CFG_0_C1, R_AX_PORT_HGQ_WINDOW_CFG_C1,
	 R_AX_PORT_HGQ_WINDOW_CFG_C1 + 1, R_AX_PORT_HGQ_WINDOW_CFG_C1 + 2,
	 R_AX_PORT_HGQ_WINDOW_CFG_C1 + 3}
};

static u32 hiq_win_mbid_regl[MAC_AX_BAND_NUM][MAC_AX_P0_MBID_MAX] = {
	{R_AX_P0MB_HGQ_WINDOW_CFG_0, R_AX_P0MB_HGQ_WINDOW_CFG_0 + 1,
	 R_AX_P0MB_HGQ_WINDOW_CFG_0 + 2, R_AX_P0MB_HGQ_WINDOW_CFG_0 + 3,
	 R_AX_P0MB_HGQ_WINDOW_CFG_1, R_AX_P0MB_HGQ_WINDOW_CFG_1 + 1,
	 R_AX_P0MB_HGQ_WINDOW_CFG_1 + 2, R_AX_P0MB_HGQ_WINDOW_CFG_1 + 3,
	 R_AX_P0MB_HGQ_WINDOW_CFG_2, R_AX_P0MB_HGQ_WINDOW_CFG_2 + 1,
	 R_AX_P0MB_HGQ_WINDOW_CFG_2 + 2, R_AX_P0MB_HGQ_WINDOW_CFG_2 + 3,
	 R_AX_P0MB_HGQ_WINDOW_CFG_3, R_AX_P0MB_HGQ_WINDOW_CFG_3 + 1,
	 R_AX_P0MB_HGQ_WINDOW_CFG_3 + 2, R_AX_P0MB_HGQ_WINDOW_CFG_3 + 3},
	{R_AX_P0MB_HGQ_WINDOW_CFG_0_C1, R_AX_P0MB_HGQ_WINDOW_CFG_0_C1 + 1,
	 R_AX_P0MB_HGQ_WINDOW_CFG_0_C1 + 2, R_AX_P0MB_HGQ_WINDOW_CFG_0_C1 + 3,
	 R_AX_P0MB_HGQ_WINDOW_CFG_1_C1, R_AX_P0MB_HGQ_WINDOW_CFG_1_C1 + 1,
	 R_AX_P0MB_HGQ_WINDOW_CFG_1_C1 + 2, R_AX_P0MB_HGQ_WINDOW_CFG_1_C1 + 3,
	 R_AX_P0MB_HGQ_WINDOW_CFG_2_C1, R_AX_P0MB_HGQ_WINDOW_CFG_2_C1 + 1,
	 R_AX_P0MB_HGQ_WINDOW_CFG_2_C1 + 2, R_AX_P0MB_HGQ_WINDOW_CFG_2_C1 + 3,
	 R_AX_P0MB_HGQ_WINDOW_CFG_3_C1, R_AX_P0MB_HGQ_WINDOW_CFG_3_C1 + 1,
	 R_AX_P0MB_HGQ_WINDOW_CFG_3_C1 + 2, R_AX_P0MB_HGQ_WINDOW_CFG_3_C1 + 3}
};

static u32 dtim_prd_port_regl[MAC_AX_BAND_NUM][MAC_AX_PORT_NUM] = {
	{R_AX_DTIM_CTRL_P0 + 1, R_AX_DTIM_CTRL_P1 + 1,
	 R_AX_DTIM_CTRL_P2 + 1, R_AX_DTIM_CTRL_P3 + 1,
	 R_AX_DTIM_CTRL_P4 + 1},
	{R_AX_DTIM_CTRL_P0_C1 + 1, R_AX_DTIM_CTRL_P1_C1 + 1,
	 R_AX_DTIM_CTRL_P2_C1 + 1, R_AX_DTIM_CTRL_P3_C1 + 1,
	 R_AX_DTIM_CTRL_P4_C1 + 1}
};

static u32 dtim_prd_mbid_regl[MAC_AX_BAND_NUM][MAC_AX_P0_MBID_MAX] = {
	{R_AX_DTIM_CTRL_P0 + 1, R_AX_DTIM_NUM0 + 1, R_AX_DTIM_NUM0 + 2,
	 R_AX_DTIM_NUM0 + 3, R_AX_DTIM_NUM1, R_AX_DTIM_NUM1 + 1,
	 R_AX_DTIM_NUM1 + 2, R_AX_DTIM_NUM1 + 3, R_AX_DTIM_NUM2,
	 R_AX_DTIM_NUM2 + 1, R_AX_DTIM_NUM2 + 2, R_AX_DTIM_NUM2 + 3,
	 R_AX_DTIM_NUM3, R_AX_DTIM_NUM3 + 1, R_AX_DTIM_NUM3 + 2,
	 R_AX_DTIM_NUM3 + 3},
	{R_AX_DTIM_CTRL_P0_C1 + 1, R_AX_DTIM_NUM0_C1 + 1, R_AX_DTIM_NUM0_C1 + 2,
	 R_AX_DTIM_NUM0_C1 + 3, R_AX_DTIM_NUM1_C1, R_AX_DTIM_NUM1_C1 + 1,
	 R_AX_DTIM_NUM1_C1 + 2, R_AX_DTIM_NUM1_C1 + 3, R_AX_DTIM_NUM2_C1,
	 R_AX_DTIM_NUM2_C1 + 1, R_AX_DTIM_NUM2_C1 + 2, R_AX_DTIM_NUM2_C1 + 3,
	 R_AX_DTIM_NUM3_C1, R_AX_DTIM_NUM3_C1 + 1, R_AX_DTIM_NUM3_C1 + 2,
	 R_AX_DTIM_NUM3_C1 + 3}
};

static u32 dtim_switch[MAC_AX_BAND_NUM] = {
	R_AX_MD_TSFT_STMP_CTL, R_AX_MD_TSFT_STMP_CTL_C1
};

static u32 hiq_nolmt_regl[MAC_AX_BAND_NUM] = {
	R_AX_EN_HGQ_NOLIMIT, R_AX_EN_HGQ_NOLIMIT_C1
};

static u32 mbid_ctrl_regl[MAC_AX_BAND_NUM] = {
	R_AX_MBSSID_CTRL, R_AX_MBSSID_CTRL_C1
};

static u32 bcn_early_regl[MAC_AX_BAND_NUM][MAC_AX_PORT_NUM] = {
	{R_AX_BCNERLYINT_CFG_P0, R_AX_BCNERLYINT_CFG_P1,
	R_AX_BCNERLYINT_CFG_P2, R_AX_BCNERLYINT_CFG_P3,
	R_AX_BCNERLYINT_CFG_P4},
	{R_AX_BCNERLYINT_CFG_P0_C1, R_AX_BCNERLYINT_CFG_P1_C1,
	R_AX_BCNERLYINT_CFG_P2_C1, R_AX_BCNERLYINT_CFG_P3_C1,
	R_AX_BCNERLYINT_CFG_P4_C1}
};

static u32 tsfl_regl[MAC_AX_BAND_NUM][MAC_AX_PORT_NUM] = {
	{R_AX_TSFTR_LOW_P0, R_AX_TSFTR_LOW_P1, R_AX_TSFTR_LOW_P2,
	 R_AX_TSFTR_LOW_P3, R_AX_TSFTR_LOW_P4},
	{R_AX_TSFTR_LOW_P0_C1, R_AX_TSFTR_LOW_P1_C1, R_AX_TSFTR_LOW_P2_C1,
	 R_AX_TSFTR_LOW_P3_C1, R_AX_TSFTR_LOW_P4_C1}
};

static u32 ptcl_dbg_regl[MAC_AX_BAND_NUM] = {
	R_AX_PTCL_DBG, R_AX_PTCL_DBG_C1
};

static u32 bss_color_regl[MAC_AX_BAND_NUM][MAC_AX_PORT_NUM] = {
	{R_AX_PTCL_BSS_COLOR_0,
	R_AX_PTCL_BSS_COLOR_0,
	R_AX_PTCL_BSS_COLOR_0,
	R_AX_PTCL_BSS_COLOR_0,
	R_AX_PTCL_BSS_COLOR_1},
	{R_AX_PTCL_BSS_COLOR_0_C1,
	R_AX_PTCL_BSS_COLOR_0_C1,
	R_AX_PTCL_BSS_COLOR_0_C1,
	R_AX_PTCL_BSS_COLOR_0_C1,
	R_AX_PTCL_BSS_COLOR_1_C1}
};

static u32 ptcl_dbg_info_regl[MAC_AX_BAND_NUM] = {
	R_AX_PTCL_DBG_INFO, R_AX_PTCL_DBG_INFO_C1
};

static u32 b_en_l[MAC_AX_PORT_NUM] = {
	B_AX_PORT_FUNC_EN_P0, B_AX_PORT_FUNC_EN_P1, B_AX_PORT_FUNC_EN_P2,
	B_AX_PORT_FUNC_EN_P3, B_AX_PORT_FUNC_EN_P4
};

static u32 b_txbcnrpt_l[MAC_AX_PORT_NUM] = {
	B_AX_TXBCN_RPT_EN_P0, B_AX_TXBCN_RPT_EN_P1, B_AX_TXBCN_RPT_EN_P2,
	B_AX_TXBCN_RPT_EN_P3, B_AX_TXBCN_RPT_EN_P4
};

static u32 b_rxbcnrpt_l[MAC_AX_PORT_NUM] = {
	B_AX_RXBCN_RPT_EN_P0, B_AX_RXBCN_RPT_EN_P1, B_AX_RXBCN_RPT_EN_P2,
	B_AX_RXBCN_RPT_EN_P3, B_AX_RXBCN_RPT_EN_P4
};

static u32 b_rxupd_l[MAC_AX_PORT_NUM] = {
	B_AX_RX_BSSID_FIT_EN_P0, B_AX_RX_BSSID_FIT_EN_P1,
	B_AX_RX_BSSID_FIT_EN_P2, B_AX_RX_BSSID_FIT_EN_P3,
	B_AX_RX_BSSID_FIT_EN_P4
};

static u32 b_rxtsfupd_l[MAC_AX_PORT_NUM] = {
	B_AX_TSF_UDT_EN_P0, B_AX_TSF_UDT_EN_P1, B_AX_TSF_UDT_EN_P2,
	B_AX_TSF_UDT_EN_P3, B_AX_TSF_UDT_EN_P4
};

static u32 b_bcntxen_l[MAC_AX_PORT_NUM] = {
	B_AX_BCNTX_EN_P0, B_AX_BCNTX_EN_P1, B_AX_BCNTX_EN_P2,
	B_AX_BCNTX_EN_P3, B_AX_BCNTX_EN_P4
};

static u32 b_phben_l[MAC_AX_PORT_NUM] = {
	B_AX_TBTT_PROHIB_EN_P0, B_AX_TBTT_PROHIB_EN_P1, B_AX_TBTT_PROHIB_EN_P2,
	B_AX_TBTT_PROHIB_EN_P3, B_AX_TBTT_PROHIB_EN_P4
};

static u32 b_shten_l[MAC_AX_PORT_NUM] = {
	B_AX_TBTT_UPD_SHIFT_SEL_P0, B_AX_TBTT_UPD_SHIFT_SEL_P1,
	B_AX_TBTT_UPD_SHIFT_SEL_P2, B_AX_TBTT_UPD_SHIFT_SEL_P3,
	B_AX_TBTT_UPD_SHIFT_SEL_P4
};

static u32 b_brken_l[MAC_AX_PORT_NUM] = {
	B_AX_BRK_SETUP_P0, B_AX_BRK_SETUP_P1, B_AX_BRK_SETUP_P2,
	B_AX_BRK_SETUP_P3, B_AX_BRK_SETUP_P4
};

static u32 b_rsttsf_l[MAC_AX_PORT_NUM] = {
	B_AX_TSFTR_RST_P0, B_AX_TSFTR_RST_P1, B_AX_TSFTR_RST_P2,
	B_AX_TSFTR_RST_P3, B_AX_TSFTR_RST_P4
};

static u32 b_drpall_l[MAC_AX_PORT_NUM] = {
	B_AX_BCN_DROP_ALL_P0, B_AX_BCN_DROP_ALL_P1, B_AX_BCN_DROP_ALL_P2,
	B_AX_BCN_DROP_ALL_P3, B_AX_BCN_DROP_ALL_P4
};

static u32 b_rptvld_l[MAC_AX_PORT_NUM] = {
	B_AX_RPT_VALID_P0, B_AX_RPT_VALID_P1, B_AX_RPT_VALID_P2,
	B_AX_RPT_VALID_P3, B_AX_RPT_VALID_P4
};

static u32 b_timerr_l[MAC_AX_PORT_NUM] = {
	B_AX_TIM_ILEGAL_P0, B_AX_TIM_ILEGAL_P1, B_AX_TIM_ILEGAL_P2,
	B_AX_TIM_ILEGAL_P3, B_AX_TIM_ILEGAL_P4
};

static u32 b_mbid_en_l[MAC_AX_P0_MBID_MAX - 1] = {
	B_AX_P0MB1_EN, B_AX_P0MB2_EN, B_AX_P0MB3_EN, B_AX_P0MB4_EN,
	B_AX_P0MB5_EN, B_AX_P0MB6_EN, B_AX_P0MB7_EN, B_AX_P0MB8_EN,
	B_AX_P0MB9_EN, B_AX_P0MB10_EN, B_AX_P0MB11_EN, B_AX_P0MB12_EN,
	B_AX_P0MB13_EN, B_AX_P0MB14_EN, B_AX_P0MB15_EN
};

static u32 b_mbid_drp_l[MAC_AX_P0_MBID_MAX - 1] = {
	B_AX_BCN_DROP_ALL_P0MB1, B_AX_BCN_DROP_ALL_P0MB2,
	B_AX_BCN_DROP_ALL_P0MB3, B_AX_BCN_DROP_ALL_P0MB4,
	B_AX_BCN_DROP_ALL_P0MB5, B_AX_BCN_DROP_ALL_P0MB6,
	B_AX_BCN_DROP_ALL_P0MB7, B_AX_BCN_DROP_ALL_P0MB8,
	B_AX_BCN_DROP_ALL_P0MB9, B_AX_BCN_DROP_ALL_P0MB10,
	B_AX_BCN_DROP_ALL_P0MB11, B_AX_BCN_DROP_ALL_P0MB12,
	B_AX_BCN_DROP_ALL_P0MB13, B_AX_BCN_DROP_ALL_P0MB14,
	B_AX_BCN_DROP_ALL_P0MB15
};

static u32 b_hiq_nolmt_mbid_l[MAC_AX_P0_MBID_MAX - 1] = {
	B_AX_HIQ_NO_LMT_EN_P0_VAP1, B_AX_HIQ_NO_LMT_EN_P0_VAP2,
	B_AX_HIQ_NO_LMT_EN_P0_VAP3, B_AX_HIQ_NO_LMT_EN_P0_VAP4,
	B_AX_HIQ_NO_LMT_EN_P0_VAP5, B_AX_HIQ_NO_LMT_EN_P0_VAP6,
	B_AX_HIQ_NO_LMT_EN_P0_VAP7, B_AX_HIQ_NO_LMT_EN_P0_VAP8,
	B_AX_HIQ_NO_LMT_EN_P0_VAP9, B_AX_HIQ_NO_LMT_EN_P0_VAP10,
	B_AX_HIQ_NO_LMT_EN_P0_VAP11, B_AX_HIQ_NO_LMT_EN_P0_VAP12,
	B_AX_HIQ_NO_LMT_EN_P0_VAP13, B_AX_HIQ_NO_LMT_EN_P0_VAP14,
	B_AX_HIQ_NO_LMT_EN_P0_VAP15
};

static u32 b_hiq_nolmt_port_l[MAC_AX_PORT_NUM] = {
	B_AX_HIQ_NO_LMT_EN_P0_ROOT, B_AX_HIQ_NO_LMT_EN_P1,
	B_AX_HIQ_NO_LMT_EN_P2, B_AX_HIQ_NO_LMT_EN_P3, B_AX_HIQ_NO_LMT_EN_P4
};

static u32 mbid_idx_l[MAC_AX_P0_MBID_MAX] = {
	MAC_AX_P0_ROOT, MAC_AX_P0_MBID1, MAC_AX_P0_MBID2, MAC_AX_P0_MBID3,
	MAC_AX_P0_MBID4, MAC_AX_P0_MBID5, MAC_AX_P0_MBID6, MAC_AX_P0_MBID7,
	MAC_AX_P0_MBID8, MAC_AX_P0_MBID9, MAC_AX_P0_MBID10, MAC_AX_P0_MBID11,
	MAC_AX_P0_MBID12, MAC_AX_P0_MBID13, MAC_AX_P0_MBID14, MAC_AX_P0_MBID15
};

static u32 t32_togl_rpt_size =
	sizeof(struct mac_ax_t32_togl_rpt) * MAC_AX_BAND_NUM * MAC_AX_PORT_NUM;
static u32 port_info_size =
	sizeof(struct mac_ax_port_info) * MAC_AX_BAND_NUM * MAC_AX_PORT_NUM;

static u32 _get_max_mbid(struct mac_ax_adapter *adapter, u8 *mbid_max)
{
	if (is_chip_id(adapter, MAC_AX_CHIP_ID_8852A) ||
	    is_chip_id(adapter, MAC_AX_CHIP_ID_8852C))
		*mbid_max = MAC_AX_P0_MBID15;
	else if (is_chip_id(adapter, MAC_AX_CHIP_ID_8852B))
		*mbid_max = MAC_AX_P0_MBID3;
	else
		return MACCHIPID;

	return MACSUCCESS;
}

u32 get_bp_idx(u8 band, u8 port)
{
	return (band * MAC_AX_BAND_NUM + port);
}

u32 _get_port_cfg(struct mac_ax_adapter *adapter,
		  enum mac_ax_port_cfg_type type,
		  struct mac_ax_port_cfg_para *para)
{
	struct mac_ax_intf_ops *ops = adapter_to_intf_ops(adapter);
	u32 mbssid_idx = para->mbssid_idx;
	u8 port = para->port;
	u8 band = para->band;
	u32 val32;
	u16 val16;
	u8 mbid_max;
	u32 ret;

	if (is_chip_id(adapter, MAC_AX_CHIP_ID_8852B) &&
	    band != MAC_AX_BAND_0) {
		PLTFM_MSG_ERR("[ERR] invalid band idx %d\n", band);
		return MACFUNCINPUT;
	}

	if (port >= MAC_AX_PORT_NUM) {
		PLTFM_MSG_ERR("[ERR] invalid port idx %d\n", port);
		return MACPORTCFGPORT;
	}

	if (mbssid_idx) {
		ret = _get_max_mbid(adapter, &mbid_max);
		if (ret != MACSUCCESS) {
			PLTFM_MSG_ERR("[ERR] get_max_mbid %d\n", ret);
			return MACPORTCFGPORT;
		}

		if (mbssid_idx > (u32)mbid_max) {
			PLTFM_MSG_ERR("[ERR] invalid mbssid %d\n", mbssid_idx);
			return MACFUNCINPUT;
		}
	}

	switch (type) {
	case MAC_AX_PCFG_NET_TYPE:
		val32 = MAC_REG_R32(cfg_regl[band][port]);
		switch (port) {
		case MAC_AX_PORT_0:
			para->val = GET_FIELD(val32, B_AX_NET_TYPE_P0);
			break;
		case MAC_AX_PORT_1:
			para->val = GET_FIELD(val32, B_AX_NET_TYPE_P1);
			break;
		case MAC_AX_PORT_2:
			para->val = GET_FIELD(val32, B_AX_NET_TYPE_P2);
			break;
		case MAC_AX_PORT_3:
			para->val = GET_FIELD(val32, B_AX_NET_TYPE_P3);
			break;
		case MAC_AX_PORT_4:
			para->val = GET_FIELD(val32, B_AX_NET_TYPE_P4);
			break;
		}
		break;

	case MAC_AX_PCFG_FUNC_SW:
		val32 = MAC_REG_R32(cfg_regl[band][port]);
		if (val32 & b_en_l[port])
			para->val = 1;
		else
			para->val = 0;
		break;

	case MAC_AX_PCFG_BCN_INTV:
		val32 = MAC_REG_R32(bcnspc_regl[band][port]);
		switch (port) {
		case MAC_AX_PORT_0:
			para->val = mbssid_idx ?
				    GET_FIELD(val32, B_AX_SUB_BCN_SPACE_P0) :
				    GET_FIELD(val32, B_AX_BCN_SPACE_P0);
			break;
		case MAC_AX_PORT_1:
			para->val = GET_FIELD(val32, B_AX_BCN_SPACE_P1);
			break;
		case MAC_AX_PORT_2:
			para->val = GET_FIELD(val32, B_AX_BCN_SPACE_P2);
			break;
		case MAC_AX_PORT_3:
			para->val = GET_FIELD(val32, B_AX_BCN_SPACE_P3);
			break;
		case MAC_AX_PORT_4:
			para->val = GET_FIELD(val32, B_AX_BCN_SPACE_P4);
			break;
		}
		break;

	case MAC_AX_PCFG_BCN_HOLD_TIME:
		val32 = MAC_REG_R32(phb_regl[band][port]);
		switch (port) {
		case MAC_AX_PORT_0:
			para->val = GET_FIELD(val32, B_AX_TBTT_HOLD_P0);
			break;
		case MAC_AX_PORT_1:
		case MAC_AX_PORT_2:
		case MAC_AX_PORT_3:
		case MAC_AX_PORT_4:
			para->val = GET_FIELD(val32, B_AX_TBTT_HOLD_P1);
			break;
		}
		break;

	case MAC_AX_PCFG_BCN_ERLY:
		val32 = MAC_REG_R32(bcn_early_regl[band][port]);
		switch (port) {
		case MAC_AX_PORT_0:
			para->val = GET_FIELD(val32, B_AX_BCNERLY_P0);
			break;
		case MAC_AX_PORT_1:
			para->val = GET_FIELD(val32, B_AX_BCNERLY_P1);
			break;
		case MAC_AX_PORT_2:
			para->val = GET_FIELD(val32, B_AX_BCNERLY_P2);
			break;
		case MAC_AX_PORT_3:
			para->val = GET_FIELD(val32, B_AX_BCNERLY_P3);
			break;
		case MAC_AX_PORT_4:
			para->val = GET_FIELD(val32, B_AX_BCNERLY_P4);
			break;
		}
		break;

	case MAC_AX_PCFG_BCN_SETUP_TIME:
		val32 = MAC_REG_R32(phb_regl[band][port]);
		switch (port) {
		case MAC_AX_PORT_0:
			para->val = GET_FIELD(val32, B_AX_TBTT_SETUP_P0);
			break;
		case MAC_AX_PORT_1:
		case MAC_AX_PORT_2:
		case MAC_AX_PORT_3:
		case MAC_AX_PORT_4:
			para->val = GET_FIELD(val32, B_AX_TBTT_SETUP_P1);
			break;
		}
		break;

	case MAC_AX_PCFG_TBTT_ERLY:
		val16 = MAC_REG_R16(tbttery_regl[band][port]);
		switch (port) {
		case MAC_AX_PORT_0:
			para->val = GET_FIELD(val16, B_AX_TBTTERLY_P0);
			break;
		case MAC_AX_PORT_1:
			para->val = GET_FIELD(val16, B_AX_TBTTERLY_P1);
			break;
		case MAC_AX_PORT_2:
			para->val = GET_FIELD(val16, B_AX_TBTTERLY_P2);
			break;
		case MAC_AX_PORT_3:
			para->val = GET_FIELD(val16, B_AX_TBTTERLY_P3);
			break;
		case MAC_AX_PORT_4:
			para->val = GET_FIELD(val16, B_AX_TBTTERLY_P4);
			break;
		}
		break;
	case MAC_AX_PCFG_BCN_MASK_AREA:
		val32 = MAC_REG_R32(mskarea_regl[band][port]);
		switch (port) {
		case MAC_AX_PORT_0:
			para->val = GET_FIELD(val32, B_AX_BCN_MSK_AREA_P0);
			break;
		case MAC_AX_PORT_1:
			para->val = GET_FIELD(val32, B_AX_BCN_MSK_AREA_P1);
			break;
		case MAC_AX_PORT_2:
			para->val = GET_FIELD(val32, B_AX_BCN_MSK_AREA_P2);
			break;
		case MAC_AX_PORT_3:
			para->val = GET_FIELD(val32, B_AX_BCN_MSK_AREA_P3);
			break;
		case MAC_AX_PORT_4:
			para->val = GET_FIELD(val32, B_AX_BCN_MSK_AREA_P4);
			break;
		}
		break;
	default:
		PLTFM_MSG_ERR("[ERR] invalid get cfg type %d\n", type);
		return MACPORTCFGTYPE;
	}

	return MACSUCCESS;
}

static u32 _port_cfg(struct mac_ax_adapter *adapter,
		     enum mac_ax_port_cfg_type type,
		     struct mac_ax_port_cfg_para *para)
{
	struct mac_ax_intf_ops *ops = adapter_to_intf_ops(adapter);
	u32 set_val = para->val;
	u8 port = para->port;
	u8 band = para->band;
	u32 val32;
	u32 w_val32 = MAC_AX_R32_DEAD;

	if (is_chip_id(adapter, MAC_AX_CHIP_ID_8852B) &&
	    band != MAC_AX_BAND_0) {
		PLTFM_MSG_ERR("[ERR] invalid band idx %d\n", band);
		return MACFUNCINPUT;
	}

	if (port >= MAC_AX_PORT_NUM) {
		PLTFM_MSG_ERR("[ERR] invalid port idx %d\n", port);
		return MACPORTCFGPORT;
	}

	switch (type) {
	case MAC_AX_PCFG_NET_TYPE:
		val32 = MAC_REG_R32(cfg_regl[band][port]);
		switch (port) {
		case MAC_AX_PORT_0:
			w_val32 = SET_CLR_WORD(val32, set_val,
					       B_AX_NET_TYPE_P0);
			break;
		case MAC_AX_PORT_1:
			w_val32 = SET_CLR_WORD(val32, set_val,
					       B_AX_NET_TYPE_P1);
			break;
		case MAC_AX_PORT_2:
			w_val32 = SET_CLR_WORD(val32, set_val,
					       B_AX_NET_TYPE_P2);
			break;
		case MAC_AX_PORT_3:
			w_val32 = SET_CLR_WORD(val32, set_val,
					       B_AX_NET_TYPE_P3);
			break;
		case MAC_AX_PORT_4:
			w_val32 = SET_CLR_WORD(val32, set_val,
					       B_AX_NET_TYPE_P4);
			break;
		}
		if (w_val32 != val32 && val32 != MAC_AX_R32_DEAD)
			MAC_REG_W32(cfg_regl[band][port], w_val32);
		break;

	default:
		PLTFM_MSG_ERR("[ERR] invalid cfg type %d\n", type);
		return MACPORTCFGTYPE;
	}

	return MACSUCCESS;
}

static u32 _bcn_setup_chk(struct mac_ax_adapter *adapter, u8 band, u8 port,
			  u32 *set_val)
{
	struct mac_ax_port_cfg_para cfg_para;
	struct mac_ax_port_info *pinfo_self, *pinfo_tmp;
	u32 ret;
	u32 up_lmt = 0xFFFFFFFF;
	u8 port_idx;

	pinfo_self = &adapter->port_info[get_bp_idx(band, port)];

	if (port == MAC_AX_PORT_0 && pinfo_self->stat == PORT_ST_DIS)
		return MACSUCCESS;

	if (*set_val > B_AX_TBTT_SETUP_P0_MSK) {
		PLTFM_MSG_ERR("[ERR] illegal bcn setup time %d\n", *set_val);
		return MACFUNCINPUT;
	}

	for (port_idx = MAC_AX_PORT_0; port_idx < MAC_AX_PORT_NUM; port_idx++) {
		pinfo_tmp = &adapter->port_info[get_bp_idx(band, port_idx)];
		if (pinfo_tmp->stat == PORT_ST_DIS)
			continue;
		if (port != MAC_AX_PORT_0 && port_idx == MAC_AX_PORT_0)
			continue;

		cfg_para.band = band;
		cfg_para.port = port_idx;
		cfg_para.mbssid_idx = 0;
		cfg_para.val = 0;
		ret = _get_port_cfg(adapter, MAC_AX_PCFG_BCN_ERLY, &cfg_para);
		if (ret != MACSUCCESS) {
			PLTFM_MSG_ERR("[ERR]get port cfg bcn erly fail %d\n",
				      ret);
			return ret;
		}

		if (cfg_para.val < up_lmt)
			up_lmt = cfg_para.val;

		if (port == MAC_AX_PORT_0)
			break;
	}

	if (*set_val >= up_lmt) {
		PLTFM_MSG_WARN("[WARN]setup time %d over hw limit\n", *set_val);
		*set_val = up_lmt - 1;
		return MACSETVALERR;
	}

	return MACSUCCESS;
}

static u32 _bcn_mask_chk(struct mac_ax_adapter *adapter, u8 band, u8 port,
			 u32 *set_val)
{
	struct mac_ax_port_cfg_para cfg_para;
	struct mac_ax_port_info *pinfo;
	u32 ret;

	pinfo = &adapter->port_info[get_bp_idx(band, port)];

	if (pinfo->stat == PORT_ST_DIS)
		return MACSUCCESS;

	if (*set_val > B_AX_BCN_MSK_AREA_P0_MSK) {
		PLTFM_MSG_ERR("[ERR] illegal mask area %d\n", *set_val);
		return MACFUNCINPUT;
	}

	cfg_para.band = band;
	cfg_para.port = port;
	cfg_para.mbssid_idx = 0;
	cfg_para.val = 0;
	ret = _get_port_cfg(adapter, MAC_AX_PCFG_BCN_HOLD_TIME, &cfg_para);
	if (ret != MACSUCCESS) {
		PLTFM_MSG_ERR("[ERR]get port cfg bcn hold fail %d\n", ret);
		return ret;
	}
	if (*set_val > cfg_para.val) {
		PLTFM_MSG_WARN("[WARN]mask area %d over hw limit\n", *set_val);
		*set_val = cfg_para.val;
		return MACSETVALERR;
	}

	return MACSUCCESS;
}

static u32 _bcn_hold_chk(struct mac_ax_adapter *adapter, u8 band, u8 port,
			 u32 *set_val)
{
	struct mac_ax_intf_ops *ops = adapter_to_intf_ops(adapter);
	struct mac_ax_port_cfg_para cfg_para;
	struct mac_ax_port_info *pinfo_self, *pinfo_tmp;
	u32 ret, bcn_erly, bcn_spc, val32;
	u8 port_idx;
	u32 low_lmt = 0, up_lmt = 0xFFFFFFFF;

	pinfo_self = &adapter->port_info[get_bp_idx(band, port)];

	if (port == MAC_AX_PORT_0 && pinfo_self->stat == PORT_ST_DIS)
		return MACSUCCESS;

	if (*set_val > B_AX_TBTT_HOLD_P0_MSK) {
		PLTFM_MSG_ERR("[ERR] illegal hold time %d\n", *set_val);
		return MACFUNCINPUT;
	}

	for (port_idx = MAC_AX_PORT_0; port_idx < MAC_AX_PORT_NUM; port_idx++) {
		pinfo_tmp = &adapter->port_info[get_bp_idx(band, port_idx)];
		if (pinfo_tmp->stat == PORT_ST_DIS)
			continue;
		if (port != MAC_AX_PORT_0 && port_idx == MAC_AX_PORT_0)
			continue;

		cfg_para.band = band;
		cfg_para.port = port_idx;
		cfg_para.mbssid_idx = 0;
		ret = _get_port_cfg(adapter, MAC_AX_PCFG_BCN_MASK_AREA,
				    &cfg_para);
		if (ret != MACSUCCESS) {
			PLTFM_MSG_ERR("[ERR]get port cfg mask area fail %d\n",
				      ret);
			return ret;
		}

		if (cfg_para.val > low_lmt)
			low_lmt = cfg_para.val;

		ret = _get_port_cfg(adapter, MAC_AX_PCFG_BCN_ERLY, &cfg_para);
		if (ret != MACSUCCESS) {
			PLTFM_MSG_ERR("[ERR]get port cfg bcn erly fail %d\n",
				      ret);
			return ret;
		}
		bcn_erly = cfg_para.val;

		if (port == MAC_AX_PORT_0 &&
		    GET_FIELD(MAC_REG_R32(mbid_ctrl_regl[band]), B_AX_P0MB_NUM))
			cfg_para.mbssid_idx = 1;
		else
			cfg_para.mbssid_idx = 0;
		ret = _get_port_cfg(adapter, MAC_AX_PCFG_BCN_INTV, &cfg_para);
		if (ret != MACSUCCESS) {
			PLTFM_MSG_ERR("[ERR]get port cfg bcn intv fail %d\n",
				      ret);
			return ret;
		}
		bcn_spc = cfg_para.val;

		val32 = bcn_spc * TU_TO_BCN_SET - bcn_erly;
		if (val32 < up_lmt)
			up_lmt = val32;

		if (port == MAC_AX_PORT_0)
			break;
	}

	if (*set_val < low_lmt) {
		PLTFM_MSG_WARN("[WARN]hold time %d below hw limit\n", *set_val);
		*set_val = low_lmt;
		return MACSETVALERR;
	}

	if (*set_val >= up_lmt) {
		PLTFM_MSG_WARN("[WARN]hold time %d over hw limit\n", *set_val);
		*set_val = up_lmt - 1;
		return MACSETVALERR;
	}

	return MACSUCCESS;
}

static u32 _bcn_erly_chk(struct mac_ax_adapter *adapter, u8 band, u8 port,
			 u32 *set_val)
{
	struct mac_ax_intf_ops *ops = adapter_to_intf_ops(adapter);
	struct mac_ax_port_cfg_para cfg_para;
	struct mac_ax_port_info *pinfo;
	u32 ret, bcn_hold, bcn_spc, val32;

	pinfo = &adapter->port_info[get_bp_idx(band, port)];

	if (pinfo->stat == PORT_ST_DIS)
		return MACSUCCESS;

	if (*set_val > B_AX_BCNERLY_P0_MSK || !*set_val) {
		PLTFM_MSG_ERR("[ERR] illegal bcn erly %d\n", *set_val);
		return MACFUNCINPUT;
	}

	cfg_para.band = band;
	cfg_para.port = port;
	cfg_para.mbssid_idx = 0;
	cfg_para.val = 0;
	ret = _get_port_cfg(adapter, MAC_AX_PCFG_BCN_SETUP_TIME, &cfg_para);
	if (ret != MACSUCCESS) {
		PLTFM_MSG_ERR("[ERR]get port cfg bcn setup fail %d\n", ret);
		return ret;
	}
	if (*set_val <= cfg_para.val) {
		PLTFM_MSG_WARN("[WARN]bcn erly %d below hw limit\n", *set_val);
		*set_val = cfg_para.val + 1;
		return MACSETVALERR;
	}

	cfg_para.band = band;
	cfg_para.port = port;
	cfg_para.mbssid_idx = 0;
	cfg_para.val = 0;
	ret = _get_port_cfg(adapter, MAC_AX_PCFG_TBTT_ERLY, &cfg_para);
	if (ret != MACSUCCESS) {
		PLTFM_MSG_ERR("[ERR]get port cfg tbtt erly fail %d\n", ret);
		return ret;
	}
	val32 = cfg_para.val / BCN_SET_TO_US;
	if (*set_val <= val32) {
		PLTFM_MSG_WARN("[WARN]bcn erly %d below hw limit\n", *set_val);
		*set_val = val32 + 1;
		return MACSETVALERR;
	}

	cfg_para.band = band;
	cfg_para.port = port;
	if (port == MAC_AX_PORT_0 &&
	    GET_FIELD(MAC_REG_R32(mbid_ctrl_regl[band]), B_AX_P0MB_NUM))
		cfg_para.mbssid_idx = 1;
	else
		cfg_para.mbssid_idx = 0;
	cfg_para.val = 0;
	ret = _get_port_cfg(adapter, MAC_AX_PCFG_BCN_INTV, &cfg_para);
	if (ret != MACSUCCESS) {
		PLTFM_MSG_ERR("[ERR]get port cfg bcn intv fail %d\n", ret);
		return ret;
	}
	bcn_spc = cfg_para.val;

	cfg_para.band = band;
	cfg_para.port = port;
	cfg_para.mbssid_idx = 0;
	cfg_para.val = 0;
	ret = _get_port_cfg(adapter, MAC_AX_PCFG_BCN_HOLD_TIME, &cfg_para);
	if (ret != MACSUCCESS) {
		PLTFM_MSG_ERR("[ERR] get port cfg bcn hold fail %d\n", ret);
		return ret;
	}
	bcn_hold = cfg_para.val;

	val32 = bcn_spc * TU_TO_BCN_SET - bcn_hold;
	if (*set_val >= val32) {
		PLTFM_MSG_WARN("[WARN]bcn erly %d over hw limit\n", *set_val);
		*set_val = val32 - 1;
		return MACSETVALERR;
	}

	return MACSUCCESS;
}

static u32 _tbtt_erly_chk(struct mac_ax_adapter *adapter, u8 band, u8 port,
			  u32 *set_val)
{
	struct mac_ax_port_cfg_para cfg_para;
	struct mac_ax_port_info *pinfo;
	u32 ret, val32;

	pinfo = &adapter->port_info[get_bp_idx(band, port)];

	if (pinfo->stat == PORT_ST_DIS)
		return MACSUCCESS;

	if (*set_val > B_AX_TBTTERLY_P0_MSK) {
		PLTFM_MSG_ERR("[ERR] illegal tbtt erly %d\n", *set_val);
		return MACFUNCINPUT;
	}

	cfg_para.band = band;
	cfg_para.port = port;
	cfg_para.mbssid_idx = 0;
	cfg_para.val = 0;
	ret = _get_port_cfg(adapter, MAC_AX_PCFG_BCN_ERLY, &cfg_para);
	if (ret != MACSUCCESS) {
		PLTFM_MSG_ERR("[ERR]get port cfg bcn erly fail %d\n", ret);
		return ret;
	}
	val32 = cfg_para.val * BCN_SET_TO_US;
	if (*set_val >= val32) {
		PLTFM_MSG_WARN("[WARN] tbtt erly %d over hw limit\n", *set_val);
		*set_val = val32 - 1;
		return MACSETVALERR;
	}

	return MACSUCCESS;
}

static u32 _set_max_mbid_num(struct mac_ax_adapter *adapter,
			     struct mac_ax_port_cfg_para *para)
{
	struct mac_ax_intf_ops *ops = adapter_to_intf_ops(adapter);
	struct mac_ax_port_cfg_para cfg_para;
	u8 port = para->port;
	u8 band = para->band;
	u32 mbid_num = para->mbssid_idx;
	u32 ret;
	u32 bcn_erly;
	u32 hold_time;
	u32 subspc;
	u32 val32, w_val32;

	if (mbid_num && !(mbid_num % 2))
		mbid_num++;

	cfg_para.band = band;
	cfg_para.port = port;
	cfg_para.mbssid_idx = 0;

	ret = _get_port_cfg(adapter, MAC_AX_PCFG_BCN_ERLY, &cfg_para);
	if (ret != MACSUCCESS) {
		PLTFM_MSG_ERR("[ERR]B%dP%d get cfg bcn_erly fail %d\n",
			      band, port, ret);
		return ret;
	}
	bcn_erly = cfg_para.val;

	ret = _get_port_cfg(adapter, MAC_AX_PCFG_BCN_HOLD_TIME, &cfg_para);
	if (ret != MACSUCCESS) {
		PLTFM_MSG_ERR("[ERR]B%dP%d get cfg hold_time fail %d\n",
			      band, port, ret);
		return ret;
	}
	hold_time = cfg_para.val;

	subspc = para->val / (mbid_num + 1);
	if (bcn_erly + hold_time > subspc * TU_TO_BCN_SET) {
		PLTFM_MSG_ERR("[ERR] BcnSubspc not enough for erly and hold time\n");
		para->val = (bcn_erly + hold_time) / TU_TO_BCN_SET * (mbid_num + 1);
		return MACSUBSPCERR;
	}

	//set interval
	cfg_para.val = para->val;
	ret = mac_port_cfg(adapter, MAC_AX_PCFG_BCN_INTV, &cfg_para);
	if (ret != MACSUCCESS) {
		PLTFM_MSG_ERR("[ERR]B%dP%d cfg bcn intv fail %d\n",
			      band, port, ret);
		return ret;
	}

	//set mbssid num
	val32 = MAC_REG_R32(mbid_ctrl_regl[band]);
	w_val32 = SET_CLR_WORD(val32, mbid_num, B_AX_P0MB_NUM);
	if (val32 != w_val32)
		MAC_REG_W32(mbid_ctrl_regl[band], w_val32);

	//set subspace
	val32 = MAC_REG_R32(bcnspc_regl[band][MAC_AX_PORT_0]);
	if (mbid_num)
		w_val32 = SET_CLR_WORD(val32, subspc, B_AX_SUB_BCN_SPACE_P0);
	else
		w_val32 = SET_CLR_WORD(val32, 0, B_AX_SUB_BCN_SPACE_P0);
	if (w_val32 != val32)
		MAC_REG_W32(bcnspc_regl[band][MAC_AX_PORT_0], w_val32);

	return MACSUCCESS;
}

static u32 port0_mbid_set(struct mac_ax_adapter *adapter, u8 band, u8 mbid_num,
			  u8 mbid_max)
{
	struct mac_ax_intf_ops *ops = adapter_to_intf_ops(adapter);
	u32 val32, w_val32, i;

	val32 = MAC_REG_R32(mbid_ctrl_regl[band]);
	w_val32 = SET_CLR_WORD(val32, mbid_num, B_AX_P0MB_NUM);

	for (i = 0; i < mbid_max; i++) {
		if (i >= (MAC_AX_P0_MBID_MAX - 1)) {
			PLTFM_MSG_ERR("mbid en idx %d over array %d\n", i,
				      MAC_AX_P0_MBID_MAX - 1);
			return MACCMP;
		}
		w_val32 &= ~b_mbid_en_l[i];
	}

	if (w_val32 != val32)
		MAC_REG_W32(mbid_ctrl_regl[band], w_val32);

	return MACSUCCESS;
}

static u32 port0_subspc_set(struct mac_ax_adapter *adapter, u8 band,
			    u8 mbid_num, u32 *bcn_erly, u32 *hold_time)
{
	struct mac_ax_intf_ops *ops = adapter_to_intf_ops(adapter);
	u32 subspc_u32;
	u32 val32, w_val32;
	u32 ret = MACSUCCESS;

	val32 = MAC_REG_R32(bcnspc_regl[band][MAC_AX_PORT_0]);
	subspc_u32 = mbid_num ?
		     (GET_FIELD(val32, B_AX_BCN_SPACE_P0) / (mbid_num + 1)) : 0;
	if (subspc_u32 > B_AX_SUB_BCN_SPACE_P0_MSK) {
		PLTFM_MSG_ERR("[ERR] sub space %d overflow\n", subspc_u32);
		return MACSUBSPCERR;
	}

	w_val32 = SET_CLR_WORD(val32, subspc_u32, B_AX_SUB_BCN_SPACE_P0);
	if (w_val32 != val32)
		MAC_REG_W32(bcnspc_regl[band][MAC_AX_PORT_0], w_val32);

	subspc_u32 *= TU_TO_BCN_SET;
	if (mbid_num && (BCN_HOLD_DEF + BCN_ERLY_DEF) > subspc_u32) {
		*bcn_erly = subspc_u32 * BCN_ERLY_RATIO / BCN_ITVL_RATIO;
		*hold_time = subspc_u32 * BCN_HOLD_RATIO / BCN_ITVL_RATIO;
	}

	return ret;
}

u32 dly_port_tu(struct mac_ax_adapter *adapter, u8 band, u8 port, u32 dly_tu)
{
	struct mac_ax_intf_ops *ops = adapter_to_intf_ops(adapter);
	u32 val32;
	u32 cnt;
	u32 ori_tsf;
	u32 dly_us = dly_tu * TU_UNIT;

	cnt = dly_tu * PORT_DLY_TU_CNT_LMT;
	ori_tsf = MAC_REG_R32(tsfl_regl[band][port]);
	PLTFM_DELAY_US(TU_UNIT);
	do {
		val32 = MAC_REG_R32(tsfl_regl[band][port]);
		if ((val32 >= ori_tsf &&
		     (val32 - ori_tsf) >= dly_us) ||
		    (val32 < ori_tsf &&
		     (ori_tsf - val32 + 1) >= dly_us))
			break;

		if (val32 == ori_tsf) {
			PLTFM_MSG_ERR("B%dP%d tsf not running 0x%X\n",
				      band, port, val32);
			return MACHWERR;
		}

		PLTFM_DELAY_US(TU_UNIT);
		cnt--;
	} while (cnt);

	if (!cnt)
		return MACPOLLTO;

	return MACSUCCESS;
}

u32 dly_port_us(struct mac_ax_adapter *adapter, u8 band, u8 port, u32 dly_us)
{
	struct mac_ax_intf_ops *ops = adapter_to_intf_ops(adapter);
	u32 val32;
	u32 cnt;
	u32 ori_tsf;

	cnt = dly_us * PORT_DLY_US_CNT_LMT;
	ori_tsf = MAC_REG_R32(tsfl_regl[band][port]);
	PLTFM_DELAY_US(10);
	do {
		val32 = MAC_REG_R32(tsfl_regl[band][port]);
		if ((val32 >= ori_tsf &&
		     (val32 - ori_tsf) >= dly_us) ||
		    (val32 < ori_tsf &&
		     (ori_tsf - val32 + 1) >= dly_us))
			break;

		if (val32 == ori_tsf) {
			PLTFM_MSG_ERR("B%dP%d tsf not running 0x%X\n",
				      band, port, val32);
			return MACHWERR;
		}

		PLTFM_DELAY_US(10);
		cnt--;
	} while (cnt);

	if (!cnt)
		return MACPOLLTO;

	return MACSUCCESS;
}

u32 rst_port_info(struct mac_ax_adapter *adapter, u8 band)
{
	u8 p_idx;

	for (p_idx = MAC_AX_PORT_0; p_idx < MAC_AX_PORT_NUM; p_idx++)
		PLTFM_MEMSET(&adapter->port_info[get_bp_idx(band, p_idx)], 0,
			     sizeof(struct mac_ax_port_info));

	return MACSUCCESS;
}

static u32 chk_bcnq_empty(struct mac_ax_adapter *adapter, u8 band, u8 port,
			  u32 bcn_spc, u8 *empty)
{
	struct mac_ax_intf_ops *ops = adapter_to_intf_ops(adapter);
	u32 val32;
	u32 bcnq_num_sh, bcnq_num_msk;
	u32 cnt, emp_cont_cnt;
	u32 ret;

	*empty = 1;

	val32 = MAC_REG_R32(ptcl_dbg_regl[band]);
	val32 = SET_CLR_WORD(val32, PTCL_DBG_BCNQ_NUM0, B_AX_PTCL_DBG_SEL);
	MAC_REG_W32(ptcl_dbg_regl[band], val32);
	PLTFM_DELAY_US(PTCL_DBG_DLY_US);

	cnt = CHK_BCNQ_CNT;
	emp_cont_cnt = 0;
	do {
		val32 = MAC_REG_R32(ptcl_dbg_info_regl[band]);
		bcnq_num_sh = port * 2;
		bcnq_num_msk = 3;
		val32 = GET_FIEL2(val32, bcnq_num_sh, bcnq_num_msk);

		if (val32)
			emp_cont_cnt = 0;
		else
			emp_cont_cnt++;

		if (emp_cont_cnt >= BCNQ_EMP_CONT_CNT) {
			if (port == MAC_AX_PORT_0)
				break;
			return MACSUCCESS;
		}

		ret = dly_port_tu(adapter, band, port, bcn_spc);
		if (ret != MACSUCCESS) {
			PLTFM_MSG_ERR("[ERR] dly B%dP%d %d tu fail %d\n",
				      band, port, bcn_spc, val32);
			return ret;
		}
		cnt--;
	} while (cnt);

	if (!cnt) {
		PLTFM_MSG_ERR("[ERR] chk bcnq empty0 %d timeout\n", val32);
		*empty = 0;
		return MACPOLLTO;
	}

	val32 = MAC_REG_R32(ptcl_dbg_regl[band]);
	val32 = SET_CLR_WORD(val32, PTCL_DBG_BCNQ_NUM1, B_AX_PTCL_DBG_SEL);
	MAC_REG_W32(ptcl_dbg_regl[band], val32);
	PLTFM_DELAY_US(PTCL_DBG_DLY_US);

	cnt = CHK_BCNQ_CNT;
	emp_cont_cnt = 0;
	do {
		val32 = MAC_REG_R32(ptcl_dbg_info_regl[band]);

		if (val32)
			emp_cont_cnt = 0;
		else
			emp_cont_cnt++;

		if (emp_cont_cnt >= BCNQ_EMP_CONT_CNT)
			return MACSUCCESS;

		ret = dly_port_tu(adapter, band, port, bcn_spc);
		if (ret != MACSUCCESS) {
			PLTFM_MSG_ERR("[ERR] dly B%dP%d %d tu fail %d\n",
				      band, port, bcn_spc, val32);
			return ret;
		}
		cnt--;
	} while (cnt);

	PLTFM_MSG_ERR("[ERR] chk bcnq empty1 %d timeout\n", val32);
	*empty = 0;
	return MACPOLLTO;
}

static u32 fast_bcn_drop(struct mac_ax_adapter *adapter, u8 band, u8 port)
{
	struct mac_ax_intf_ops *ops = adapter_to_intf_ops(adapter);
	struct mac_ax_port_cfg_para cfg_para;
	u32 ret = MACSUCCESS;
	u32 port_drp_sel;
	u32 mbid_drp_sel = 0;
	u32 val32;
	u32 bcn_spc;
	u8 mbid_num;
	u8 is_empty;
	u32 i;

	cfg_para.band = band;
	cfg_para.port = port;
	cfg_para.mbssid_idx = 0;

	port_drp_sel = (port == MAC_AX_PORT_0 ? B_AX_BCN_DROP_ALL_P0 : 0) |
		       (port == MAC_AX_PORT_1 ? B_AX_BCN_DROP_ALL_P1 : 0) |
		       (port == MAC_AX_PORT_2 ? B_AX_BCN_DROP_ALL_P2 : 0) |
		       (port == MAC_AX_PORT_3 ? B_AX_BCN_DROP_ALL_P3 : 0) |
		       (port == MAC_AX_PORT_4 ? B_AX_BCN_DROP_ALL_P4 : 0);
	val32 = MAC_REG_R32(bcndrp_regl[band]) | port_drp_sel;
	MAC_REG_W32(bcndrp_regl[band], val32);

	if (port == MAC_AX_PORT_0) {
		mbid_drp_sel = B_AX_BCN_DROP_ALL_P0MB1 |
			       B_AX_BCN_DROP_ALL_P0MB2 |
			       B_AX_BCN_DROP_ALL_P0MB3;
		if (!is_chip_id(adapter, MAC_AX_CHIP_ID_8852B))
			mbid_drp_sel |= B_AX_BCN_DROP_ALL_P0MB4 |
					B_AX_BCN_DROP_ALL_P0MB5 |
					B_AX_BCN_DROP_ALL_P0MB6 |
					B_AX_BCN_DROP_ALL_P0MB7 |
					B_AX_BCN_DROP_ALL_P0MB8 |
					B_AX_BCN_DROP_ALL_P0MB9 |
					B_AX_BCN_DROP_ALL_P0MB10 |
					B_AX_BCN_DROP_ALL_P0MB11 |
					B_AX_BCN_DROP_ALL_P0MB12 |
					B_AX_BCN_DROP_ALL_P0MB13 |
					B_AX_BCN_DROP_ALL_P0MB14 |
					B_AX_BCN_DROP_ALL_P0MB15;
		val32 = MAC_REG_R32(mbssid_drp_regl[band]) | mbid_drp_sel;
		MAC_REG_W32(mbssid_drp_regl[band], val32);
	}

	cfg_para.val = 1;
	ret = mac_port_cfg(adapter, MAC_AX_PCFG_BCN_SETUP_TIME, &cfg_para);
	if (ret != MACSUCCESS) {
		PLTFM_MSG_ERR("[ERR] port cfg func setup time fail %d\n", ret);
		return ret;
	}

	cfg_para.val = 0;
	ret = mac_port_cfg(adapter, MAC_AX_PCFG_BCN_MASK_AREA, &cfg_para);
	if (ret != MACSUCCESS) {
		PLTFM_MSG_ERR("[ERR] port cfg func mask area fail %d\n", ret);
		return ret;
	}

	cfg_para.val = 0;
	ret = mac_port_cfg(adapter, MAC_AX_PCFG_BCN_HOLD_TIME, &cfg_para);
	if (ret != MACSUCCESS) {
		PLTFM_MSG_ERR("[ERR] port cfg func hold time fail %d\n", ret);
		return ret;
	}

	cfg_para.val = 2;
	ret = mac_port_cfg(adapter, MAC_AX_PCFG_BCN_ERLY, &cfg_para);
	if (ret != MACSUCCESS) {
		PLTFM_MSG_ERR("[ERR] port cfg func bcn early fail %d\n", ret);
		return ret;
	}

	cfg_para.val = 1;
	ret = mac_port_cfg(adapter, MAC_AX_PCFG_TBTT_ERLY, &cfg_para);
	if (ret != MACSUCCESS) {
		PLTFM_MSG_ERR("[ERR] port cfg tbtt early fail %d\n", ret);
		return ret;
	}

	if (port == MAC_AX_PORT_0) {
		ret = _get_max_mbid(adapter, &mbid_num);
		if (ret != MACSUCCESS) {
			PLTFM_MSG_ERR("[ERR] get_max_mbid %d\n", ret);
			return MACPORTCFGPORT;
		}
		bcn_spc = (u32)(mbid_num + 1) * BCN_FAST_DRP_TBTT;

		val32 = MAC_REG_R32(bcnspc_regl[band][MAC_AX_PORT_0]);
		val32 = SET_CLR_WORD(val32, BCN_FAST_DRP_TBTT,
				     B_AX_SUB_BCN_SPACE_P0);
		MAC_REG_W32(bcnspc_regl[band][MAC_AX_PORT_0], val32);
		val32 = SET_CLR_WORD(val32, bcn_spc, B_AX_BCN_SPACE_P0);
		MAC_REG_W32(bcnspc_regl[band][MAC_AX_PORT_0], val32);

		val32 = MAC_REG_R32(mbid_ctrl_regl[band]);
		val32 = SET_CLR_WORD(val32, mbid_num, B_AX_P0MB_NUM);
		for (i = 0; i < mbid_num; i++)
			val32 |= b_mbid_en_l[i];
		MAC_REG_W32(mbid_ctrl_regl[band], val32);

	} else {
		bcn_spc = BCN_FAST_DRP_TBTT;
		cfg_para.val = bcn_spc;
		ret = mac_port_cfg(adapter, MAC_AX_PCFG_BCN_INTV, &cfg_para);
		if (ret != MACSUCCESS) {
			PLTFM_MSG_ERR("[ERR] port cfg func bcn intv fail %d\n",
				      ret);
			return ret;
		}
	}

	cfg_para.val = 1;
	ret = mac_port_cfg(adapter, MAC_AX_PCFG_TX_SW, &cfg_para);
	if (ret != MACSUCCESS) {
		PLTFM_MSG_ERR("[ERR] port cfg tx sw fail %d\n", ret);
		return ret;
	}

	ret = chk_bcnq_empty(adapter, band, port, bcn_spc, &is_empty);
	if (ret != MACSUCCESS) {
		PLTFM_MSG_ERR("[ERR] chk bcnq empty fail %d\n", ret);
		return ret;
	}

	val32 = MAC_REG_R32(bcndrp_regl[band]) & ~port_drp_sel;
	MAC_REG_W32(bcndrp_regl[band], val32);

	if (port == MAC_AX_PORT_0) {
		val32 = MAC_REG_R32(mbssid_drp_regl[band]) & ~mbid_drp_sel;
		MAC_REG_W32(mbssid_drp_regl[band], val32);
	}

	val32 = MAC_REG_R32(cfg_regl[band][port]) & ~b_phben_l[port];
	MAC_REG_W32(cfg_regl[band][port], val32);

	ret = dly_port_tu(adapter, band, port, bcn_spc + 1);
	if (ret != MACSUCCESS) {
		PLTFM_MSG_ERR("[ERR]B%dP%d dly %d tu fail %d\n",
			      band, port, bcn_spc + 1, ret);
		return ret;
	}

	return MACSUCCESS;
}

u32 _patch_port_dis_flow(struct mac_ax_adapter *adapter, u8 band, u8 port,
			 struct mac_ax_port_info *pinfo)
{
	struct mac_ax_intf_ops *ops = adapter_to_intf_ops(adapter);
	struct mac_ax_port_cfg_para cfg_para;
	u32 bcn_set_bk = MAC_AX_R32_DEAD;
	u32 bcn_spc;
	u32 val32;
	u32 ret = MACSUCCESS;
	u16 val16;
	u8 patch_flag, phb_bkp_flag;
	u8 mbid_max;

	patch_flag = is_chip_id(adapter, MAC_AX_CHIP_ID_8852A) ? 1 : 0;
	phb_bkp_flag = patch_flag && port != MAC_AX_PORT_0 ? 1 : 0;

	if (phb_bkp_flag)
		bcn_set_bk = MAC_REG_R32(phb_regl[band][port]);

	if (pinfo->stat == PORT_ST_AP || pinfo->stat == PORT_ST_ADHOC) {
		ret = fast_bcn_drop(adapter, band, port);
		if (ret != MACSUCCESS) {
			PLTFM_MSG_ERR("[ERR] fast bcn drop fail %d\n",
				      ret);
			goto end;
		}
	}

	if (patch_flag) {
		cfg_para.band = band;
		cfg_para.port = port;
		cfg_para.mbssid_idx = 0;
		cfg_para.val = 0;
		ret = _get_port_cfg(adapter, MAC_AX_PCFG_BCN_INTV, &cfg_para);
		if (ret != MACSUCCESS) {
			PLTFM_MSG_ERR("[ERR] get port cfg bcn intv fail %d\n",
				      ret);
			goto end;
		}
		bcn_spc = cfg_para.val;

		val32 = MAC_REG_R32(phb_regl[band][port]);
		val32 = SET_CLR_WORD(val32, 0, B_AX_TBTT_SETUP_P0);
		val32 = SET_CLR_WORD(val32, 1, B_AX_TBTT_HOLD_P0);
		MAC_REG_W32(phb_regl[band][port], val32);

		val16 = MAC_REG_R16(tbttery_regl[band][port]);
		val16 = SET_CLR_WORD(val16, 0, B_AX_TBTTERLY_P0);
		MAC_REG_W16(tbttery_regl[band][port], val16);

		val16 = MAC_REG_R16(bcn_early_regl[band][port]);
		val16 = SET_CLR_WORD(val16, 0, B_AX_BCNERLY_P0);
		MAC_REG_W16(bcn_early_regl[band][port], val16);

		ret = dly_port_tu(adapter, band, port, bcn_spc + 1);
		if (ret != MACSUCCESS) {
			PLTFM_MSG_ERR("[ERR]B%dP%d dly %d tu fail %d\n",
				      band, port, bcn_spc, ret);
			goto end;
		}
	}

	if (port == MAC_AX_PORT_0) {
		ret = _get_max_mbid(adapter, &mbid_max);
		if (ret != MACSUCCESS) {
			PLTFM_MSG_ERR("[ERR] get_max_mbid %d\n", ret);
			return MACPORTCFGPORT;
		}

		ret = port0_mbid_set(adapter, band, 0, mbid_max);
		if (ret != MACSUCCESS) {
			PLTFM_MSG_ERR("[ERR]B%dP%d mbid set fail %d\n",
				      band, port, ret);
			return ret;
		}
	}

	val32 = MAC_REG_R32(cfg_regl[band][port]) &
		~(b_en_l[port] | b_brken_l[port]);
	MAC_REG_W32(cfg_regl[band][port], val32);
	val32 |= b_rsttsf_l[port];
	MAC_REG_W32(cfg_regl[band][port], val32);
	MAC_REG_W32(cnt_tmr_regl[band][port], 0);

	pinfo->stat = PORT_ST_DIS;
end:
	if (phb_bkp_flag) {
		if (bcn_set_bk != MAC_AX_R32_DEAD) {
			MAC_REG_W32(phb_regl[band][port], bcn_set_bk);
		} else {
			PLTFM_MSG_ERR("[ERR]prev ret %d\n", ret);
			PLTFM_MSG_ERR("[ERR]B%dP%d phb reg dead\n", band, port);
			ret = MACCMP;
		}
	}

	return ret;
}

u32 _patch_tbtt_shift_setval(struct mac_ax_adapter *adapter, u32 bcnspc,
			     u32 *shift_val)
{
	if (!(is_chip_id(adapter, MAC_AX_CHIP_ID_8852A) ||
	      is_chip_id(adapter, MAC_AX_CHIP_ID_8852B) ||
	      is_chip_id(adapter, MAC_AX_CHIP_ID_8852C) ||
	      is_chip_id(adapter, MAC_AX_CHIP_ID_8192XB)))
		return MACSUCCESS;

	if (!*shift_val)
		return MACSUCCESS;

	if (*shift_val >= bcnspc)
		return MACCMP;

	*shift_val = (bcnspc - *shift_val) | TBTT_SHIFT_OFST_MSB;

	return MACSUCCESS;
}

u32 mac_port_cfg(struct mac_ax_adapter *adapter,
		 enum mac_ax_port_cfg_type type,
		 struct mac_ax_port_cfg_para *para)
{
	struct mac_ax_port_cfg_para cfg_para;
	struct mac_ax_port_info *pinfo;
	u8 band = para->band;
	u8 port = para->port;

#if 0 // MAC_AX_FW_REG_OFLD
	if (adapter->sm.fwdl == MAC_AX_FWDL_INIT_RDY) {
#if MAC_AX_PHL_H2C
		struct rtw_h2c_pkt *h2cb;
#else
		struct h2c_buf *h2cb;
#endif
		struct fwcmd_port_cfg *hdr;
		u32 ret = MACSUCCESS;
		u32 cnt;

		if (para->band >= MAC_AX_BAND_NUM) {
			PLTFM_MSG_ERR("[ERR]invalid band %d\n", para->band);
			return MACFUNCINPUT;
		}

		if (para->port >= MAC_AX_PORT_NUM) {
			PLTFM_MSG_ERR("[ERR]invalid port %d\n", para->port);
			return MACFUNCINPUT;
		}

		pinfo = &adapter->port_info[get_bp_idx(band, port)];

		cnt = PORT_H2C_DLY_CNT;
		while (pinfo->h2c_sm == MAC_AX_PORT_H2C_BUSY) {
			cnt--;
			if (!cnt) {
				PLTFM_MSG_ERR("[ERR]B%dP%d port H2C busy\n",
					      band, port);
				return MACPROCBUSY;
			}
			PLTFM_DELAY_US(PORT_H2C_DLY_US);
		}

		if (pinfo->h2c_sm == MAC_AX_PORT_H2C_FAIL) {
			PLTFM_MSG_ERR("[ERR]prev B%dP%d port H2C fail\n",
				      band, port);
			return MACPROCERR;
		}

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

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

		hdr->dword0 =
			cpu_to_le32(SET_WORD(type, FWCMD_H2C_PORT_CFG_TYPE) |
				    SET_WORD(para->mbssid_idx,
					     FWCMD_H2C_PORT_CFG_MBSSID_IDX) |
				    SET_WORD(port, FWCMD_H2C_PORT_CFG_PORT) |
				    (band ? FWCMD_H2C_PORT_CFG_BAND : 0));

		hdr->dword1 =
			cpu_to_le32(SET_WORD(para->val, FWCMD_H2C_PORT_CFG_VAL));

		ret = h2c_pkt_set_hdr(adapter, h2cb,
				      FWCMD_TYPE_H2C,
				      FWCMD_H2C_CAT_MAC,
				      FWCMD_H2C_CL_MPORT,
				      FWCMD_H2C_FUNC_PORT_CFG,
				      0,
				      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);

		pinfo->h2c_sm = MAC_AX_PORT_H2C_BUSY;

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

		return ret;
	}
#endif

	struct mac_ax_intf_ops *ops = adapter_to_intf_ops(adapter);
	u32 mbssid_idx = para->mbssid_idx;
	u32 set_val = para->val;
	u8 val8, w_val8;
	u16 val16;
	u16 w_val16 = MAC_AX_R16_DEAD;
	u32 val32;
	u32 w_val32 = MAC_AX_R32_DEAD;
	struct mac_ax_pkt_drop_info info;
	u8 mbid_max;
	u32 ret = MACSUCCESS;

	if (is_chip_id(adapter, MAC_AX_CHIP_ID_8852B) &&
	    band != MAC_AX_BAND_0) {
		PLTFM_MSG_ERR("[ERR] invalid band idx %d\n", band);
		return MACFUNCINPUT;
	}

	if (port >= MAC_AX_PORT_NUM) {
		PLTFM_MSG_ERR("[ERR] invalid port idx %d\n", port);
		return MACPORTCFGPORT;
	}

	if (mbssid_idx) {
		ret = _get_max_mbid(adapter, &mbid_max);
		if (ret != MACSUCCESS) {
			PLTFM_MSG_ERR("[ERR] get_max_mbid %d\n", ret);
			return MACPORTCFGPORT;
		}

		if (mbssid_idx > (u32)mbid_max) {
			PLTFM_MSG_ERR("[ERR] invalid MBSSID number %d\n",
				      mbssid_idx);
			return MACFUNCINPUT;
		}
	}

	pinfo = &adapter->port_info[get_bp_idx(band, port)];

	switch (type) {
	case MAC_AX_PCFG_FUNC_SW:
		if (set_val) {
			PLTFM_MSG_ERR("[ERR] use port init to enable port\n");
			return MACFUNCINPUT;
		}

		if (pinfo->stat == PORT_ST_DIS) {
			PLTFM_MSG_WARN("[WARN]B%dP%d stat already disable\n",
				       band, port);
			break;
		}

		ret = _patch_port_dis_flow(adapter, band, port, pinfo);
		break;

	case MAC_AX_PCFG_TX_SW:
		val32 = MAC_REG_R32(cfg_regl[band][port]);
		w_val32 = set_val ? val32 | b_bcntxen_l[port] :
				    val32 & ~b_bcntxen_l[port];
		if (w_val32 != val32)
			MAC_REG_W32(cfg_regl[band][port], w_val32);
		break;

	case MAC_AX_PCFG_TX_RPT:
		val32 = MAC_REG_R32(cfg_regl[band][port]);
		w_val32 = set_val ? val32 | b_txbcnrpt_l[port] :
				    val32 & ~b_txbcnrpt_l[port];
		if (w_val32 != val32)
			MAC_REG_W32(cfg_regl[band][port], w_val32);
		break;

	case MAC_AX_PCFG_RX_SW:
		val32 = MAC_REG_R32(cfg_regl[band][port]);
		w_val32 = set_val ? val32 | b_rxupd_l[port] :
				    val32 & ~b_rxupd_l[port];
		if (w_val32 != val32)
			MAC_REG_W32(cfg_regl[band][port], w_val32);
		break;

	case MAC_AX_PCFG_RX_RPT:
		val32 = MAC_REG_R32(cfg_regl[band][port]);
		w_val32 = set_val ? val32 | b_rxbcnrpt_l[port] :
				    val32 & ~b_rxbcnrpt_l[port];
		if (w_val32 != val32)
			MAC_REG_W32(cfg_regl[band][port], w_val32);
		break;

	case MAC_AX_PCFG_RX_SYNC:
		val32 = MAC_REG_R32(cfg_regl[band][port]);
		w_val32 = set_val ? val32 | b_rxtsfupd_l[port] :
				    val32 & ~b_rxtsfupd_l[port];
		if (w_val32 != val32)
			MAC_REG_W32(cfg_regl[band][port], w_val32);
		break;

	case MAC_AX_PCFG_BCN_PRCT:
		val32 = MAC_REG_R32(cfg_regl[band][port]);
		w_val32 = set_val ? val32 | b_phben_l[port] | b_brken_l[port] :
				    val32 & ~(b_phben_l[port] |
					      b_brken_l[port]);
		if (w_val32 != val32)
			MAC_REG_W32(cfg_regl[band][port], w_val32);
		break;

	case MAC_AX_PCFG_TBTT_AGG:
		if (set_val > B_AX_TBTT_AGG_NUM_P0_MSK) {
			PLTFM_MSG_ERR("[ERR] illegal tbtt agg %d\n", set_val);
			return MACFUNCINPUT;
		}

		val16 = MAC_REG_R16(tbttagg_regl[band][port]);
		switch (port) {
		case MAC_AX_PORT_0:
			w_val16 = SET_CLR_WORD(val16, set_val,
					       B_AX_TBTT_AGG_NUM_P0);
			break;
		case MAC_AX_PORT_1:
			w_val16 = SET_CLR_WORD(val16, set_val,
					       B_AX_TBTT_AGG_NUM_P1);
			break;
		case MAC_AX_PORT_2:
			w_val16 = SET_CLR_WORD(val16, set_val,
					       B_AX_TBTT_AGG_NUM_P2);
			break;
		case MAC_AX_PORT_3:
			w_val16 = SET_CLR_WORD(val16, set_val,
					       B_AX_TBTT_AGG_NUM_P3);
			break;
		case MAC_AX_PORT_4:
			w_val16 = SET_CLR_WORD(val16, set_val,
					       B_AX_TBTT_AGG_NUM_P4);
			break;
		}
		if (w_val16 != val16 && w_val16 != MAC_AX_R16_DEAD)
			MAC_REG_W16(tbttagg_regl[band][port], w_val16);
		break;

	case MAC_AX_PCFG_TBTT_SHIFT:
		if (set_val > B_AX_TBTT_SHIFT_OFST_P0_MSK) {
			PLTFM_MSG_ERR("[ERR] illegal tbtt shift %d\n", set_val);
			return MACFUNCINPUT;
		}

		cfg_para.band = band;
		cfg_para.port = port;
		cfg_para.mbssid_idx = 0;
		cfg_para.val = 0;
		ret = _get_port_cfg(adapter, MAC_AX_PCFG_BCN_INTV, &cfg_para);
		if (ret != MACSUCCESS) {
			PLTFM_MSG_ERR("[ERR]get port cfg bcn intv fail %d\n", ret);
			return ret;
		}
		if (set_val >= cfg_para.val) {
			PLTFM_MSG_ERR("tbtt shift %d over bcn spc %d\n",
				      set_val, cfg_para.val);
			return MACCMP;
		}

		ret = _patch_tbtt_shift_setval(adapter, cfg_para.val, &set_val);
		if (ret != MACSUCCESS) {
			PLTFM_MSG_ERR("patch tbtt shift fail %d\n", ret);
			return ret;
		}

		val32 = MAC_REG_R32(tbttsht_regl[band][port]);
		switch (port) {
		case MAC_AX_PORT_0:
			w_val32 = SET_CLR_WORD(val32, set_val,
					       B_AX_TBTT_SHIFT_OFST_P0);
			break;
		case MAC_AX_PORT_1:
			w_val32 = SET_CLR_WORD(val32, set_val,
					       B_AX_TBTT_SHIFT_OFST_P1);
			break;
		case MAC_AX_PORT_2:
			w_val32 = SET_CLR_WORD(val32, set_val,
					       B_AX_TBTT_SHIFT_OFST_P2);
			break;
		case MAC_AX_PORT_3:
			w_val32 = SET_CLR_WORD(val32, set_val,
					       B_AX_TBTT_SHIFT_OFST_P3);
			break;
		case MAC_AX_PORT_4:
			w_val32 = SET_CLR_WORD(val32, set_val,
					       B_AX_TBTT_SHIFT_OFST_P4);
			break;
		}
		if (w_val32 != val32 && val32 != MAC_AX_R32_DEAD)
			MAC_REG_W32(tbttsht_regl[band][port], w_val32);
		break;

	case MAC_AX_PCFG_RST_TSF:
		val32 = MAC_REG_R32(cfg_regl[band][port]);
		val32 = val32 | b_rsttsf_l[port];
		MAC_REG_W32(cfg_regl[band][port], val32);
		break;

	case MAC_AX_PCFG_RST_TPR:
		val32 = MAC_REG_R32(bcnpsr_regl[band][port]);
		val32 |= b_rptvld_l[port];
		MAC_REG_W32(bcnpsr_regl[band][port], val32);
		break;

	case MAC_AX_PCFG_HIQ_WIN:
		if (set_val > B_AX_HGQWND_0_MSK) {
			PLTFM_MSG_ERR("[ERR] illegal hiq win %d\n", set_val);
			return MACFUNCINPUT;
		}

		if (port == MAC_AX_PORT_0)
			MAC_REG_W8(hiq_win_mbid_regl[band][mbssid_idx],
				   (u8)set_val);
		else
			MAC_REG_W8(hiq_win_port_regl[band][port],
				   (u8)set_val);
		break;

	case MAC_AX_PCFG_HIQ_DTIM:
		if (set_val > B_AX_DTIM_NUM_P0_MSK) {
			PLTFM_MSG_ERR("[ERR] illegal dtim prd %d\n", set_val);
			return MACFUNCINPUT;
		}

		val8 = MAC_REG_R8(dtim_switch[band]);
		w_val8 = val8 | B_AX_UPD_TIMIE | B_AX_UPD_HGQMD;
		if (w_val8 != val8)
			MAC_REG_W8(dtim_switch[band], w_val8);

		if (port == MAC_AX_PORT_0)
			MAC_REG_W8(dtim_prd_mbid_regl[band][mbssid_idx],
				   (u8)set_val);
		else
			MAC_REG_W8(dtim_prd_port_regl[band][port],
				   (u8)set_val);
		break;

	case MAC_AX_PCFG_HIQ_NOLIMIT:
		val32 = MAC_REG_R32(hiq_nolmt_regl[band]);
		if (port == MAC_AX_PORT_0 && mbssid_idx)
			w_val32 = set_val ?
				  val32 | b_hiq_nolmt_mbid_l[mbssid_idx - 1] :
				  val32 & ~b_hiq_nolmt_mbid_l[mbssid_idx - 1];
		else
			w_val32 = set_val ?
				  val32 | b_hiq_nolmt_port_l[port] :
				  val32 & ~b_hiq_nolmt_port_l[port];
		if (w_val32 != val32)
			MAC_REG_W32(hiq_nolmt_regl[band], w_val32);
		break;

	case MAC_AX_PCFG_BCN_SETUP_TIME:
		ret = _bcn_setup_chk(adapter, band, port, &para->val);
		if (ret != MACSUCCESS) {
			PLTFM_MSG_WARN("[WARN]bcn setup chk %d\n", ret);
			return ret;
		}

		val32 = MAC_REG_R32(phb_regl[band][port]);
		switch (port) {
		case MAC_AX_PORT_0:
			w_val32 = SET_CLR_WORD(val32, set_val,
					       B_AX_TBTT_SETUP_P0);
			break;
		case MAC_AX_PORT_1:
		case MAC_AX_PORT_2:
		case MAC_AX_PORT_3:
		case MAC_AX_PORT_4:
			w_val32 = SET_CLR_WORD(val32, set_val,
					       B_AX_TBTT_SETUP_P1);
			break;
		}
		if (w_val32 != val32 && val32 != MAC_AX_R32_DEAD)
			MAC_REG_W32(phb_regl[band][port], w_val32);
		break;

	case MAC_AX_PCFG_BCN_HOLD_TIME:
		ret = _bcn_hold_chk(adapter, band, port, &para->val);
		if (ret != MACSUCCESS) {
			PLTFM_MSG_WARN("[WARN]bcn hold chk %d\n", ret);
			return ret;
		}

		val32 = MAC_REG_R32(phb_regl[band][port]);
		switch (port) {
		case MAC_AX_PORT_0:
			w_val32 = SET_CLR_WORD(val32, set_val,
					       B_AX_TBTT_HOLD_P0);
			break;
		case MAC_AX_PORT_1:
		case MAC_AX_PORT_2:
		case MAC_AX_PORT_3:
		case MAC_AX_PORT_4:
			w_val32 = SET_CLR_WORD(val32, set_val,
					       B_AX_TBTT_HOLD_P1);
			break;
		}

		if (w_val32 != val32 && val32 != MAC_AX_R32_DEAD)
			MAC_REG_W32(phb_regl[band][port], w_val32);
		break;

	case MAC_AX_PCFG_MBSSID_EN:
		if (port != MAC_AX_PORT_0 || !mbssid_idx) {
			PLTFM_MSG_ERR("[ERR] mbssid en invalid for P%d MB%d\n",
				      port, mbssid_idx);
			return MACFUNCINPUT;
		}

		val32 = MAC_REG_R32(mbid_ctrl_regl[band]);
		if (mbssid_idx > GET_FIELD(val32, B_AX_P0MB_NUM)) {
			PLTFM_MSG_ERR("[ERR] mbssid %d over %d\n", set_val,
				      GET_FIELD(val32, B_AX_P0MB_NUM));
			return MACFUNCINPUT;
		}

		w_val32 = set_val ? val32 | b_mbid_en_l[mbssid_idx - 1] :
				    val32 & ~b_mbid_en_l[mbssid_idx - 1];

		if (w_val32 != val32)
			MAC_REG_W32(mbid_ctrl_regl[band], w_val32);

		info.band = band;
		info.port = port;
		info.mbssid = (u8)mbssid_idx;
		info.sel = MAC_AX_PKT_DROP_SEL_REL_HIQ_MBSSID;
		ret = adapter->ops->pkt_drop(adapter, &info);
		if (ret != MACSUCCESS) {
			PLTFM_MSG_ERR("[ERR] B%d P%d MB%d hiq drop %d\n",
				      band, port, mbssid_idx, ret);
			return ret;
		}
		break;

	case MAC_AX_PCFG_BCN_ERLY:
		ret = _bcn_erly_chk(adapter, band, port, &para->val);
		if (ret != MACSUCCESS) {
			PLTFM_MSG_WARN("[WARN]bcn erly chk %d\n", ret);
			return ret;
		}

		val32 = MAC_REG_R32(bcn_early_regl[band][port]);
		switch (port) {
		case MAC_AX_PORT_0:
			w_val32 = SET_CLR_WORD(val32, set_val, B_AX_BCNERLY_P0);
			break;
		case MAC_AX_PORT_1:
			w_val32 = SET_CLR_WORD(val32, set_val, B_AX_BCNERLY_P1);
			break;
		case MAC_AX_PORT_2:
			w_val32 = SET_CLR_WORD(val32, set_val, B_AX_BCNERLY_P2);
			break;
		case MAC_AX_PORT_3:
			w_val32 = SET_CLR_WORD(val32, set_val, B_AX_BCNERLY_P3);
			break;
		case MAC_AX_PORT_4:
			w_val32 = SET_CLR_WORD(val32, set_val, B_AX_BCNERLY_P4);
			break;
		}

		if (w_val32 != val32 && val32 != MAC_AX_R32_DEAD)
			MAC_REG_W32(bcn_early_regl[band][port], w_val32);
		break;

	case MAC_AX_PCFG_BCN_MASK_AREA:
		ret = _bcn_mask_chk(adapter, band, port, &para->val);
		if (ret != MACSUCCESS) {
			PLTFM_MSG_WARN("[WARN]bcn mask chk %d\n", ret);
			return ret;
		}

		val32 = MAC_REG_R32(mskarea_regl[band][port]);
		switch (port) {
		case MAC_AX_PORT_0:
			w_val32 = SET_CLR_WORD(val32, set_val,
					       B_AX_BCN_MSK_AREA_P0);
			break;
		case MAC_AX_PORT_1:
			w_val32 = SET_CLR_WORD(val32, set_val,
					       B_AX_BCN_MSK_AREA_P1);
			break;
		case MAC_AX_PORT_2:
			w_val32 = SET_CLR_WORD(val32, set_val,
					       B_AX_BCN_MSK_AREA_P2);
			break;
		case MAC_AX_PORT_3:
			w_val32 = SET_CLR_WORD(val32, set_val,
					       B_AX_BCN_MSK_AREA_P3);
			break;
		case MAC_AX_PORT_4:
			w_val32 = SET_CLR_WORD(val32, set_val,
					       B_AX_BCN_MSK_AREA_P4);
			break;
		}

		if (w_val32 != val32 && val32 != MAC_AX_R32_DEAD)
			MAC_REG_W32(mskarea_regl[band][port], w_val32);
		break;

	case MAC_AX_PCFG_TBTT_ERLY:
		ret = _tbtt_erly_chk(adapter, band, port, &para->val);
		if (ret != MACSUCCESS) {
			PLTFM_MSG_WARN("[WARN]tbtt erly chk %d\n", ret);
			return ret;
		}

		val16 = MAC_REG_R16(tbttery_regl[band][port]);
		switch (port) {
		case MAC_AX_PORT_0:
			w_val16 = SET_CLR_WORD(val16, set_val,
					       B_AX_TBTTERLY_P0);
			break;
		case MAC_AX_PORT_1:
			w_val16 = SET_CLR_WORD(val16, set_val,
					       B_AX_TBTTERLY_P1);
			break;
		case MAC_AX_PORT_2:
			w_val16 = SET_CLR_WORD(val16, set_val,
					       B_AX_TBTTERLY_P2);
			break;
		case MAC_AX_PORT_3:
			w_val16 = SET_CLR_WORD(val16, set_val,
					       B_AX_TBTTERLY_P3);
			break;
		case MAC_AX_PORT_4:
			w_val16 = SET_CLR_WORD(val16, set_val,
					       B_AX_TBTTERLY_P4);
			break;
		}

		if (w_val16 != val16 && w_val16 != MAC_AX_R16_DEAD)
			MAC_REG_W16(tbttery_regl[band][port], w_val16);
		break;

	case MAC_AX_PCFG_BSS_CLR:
		if (set_val > B_AX_BSS_COLOB_AX_PORT_0_MSK) {
			PLTFM_MSG_ERR("[ERR] illegal bss color %d\n", set_val);
			return MACFUNCINPUT;
		}

		val32 = MAC_REG_R32(bss_color_regl[band][port]);
		switch (port) {
		case MAC_AX_PORT_0:
			w_val32 = SET_CLR_WORD(val32, set_val,
					       B_AX_BSS_COLOB_AX_PORT_0);
			break;
		case MAC_AX_PORT_1:
			w_val32 = SET_CLR_WORD(val32, set_val,
					       B_AX_BSS_COLOB_AX_PORT_1);
			break;
		case MAC_AX_PORT_2:
			w_val32 = SET_CLR_WORD(val32, set_val,
					       B_AX_BSS_COLOB_AX_PORT_2);
			break;
		case MAC_AX_PORT_3:
			w_val32 = SET_CLR_WORD(val32, set_val,
					       B_AX_BSS_COLOB_AX_PORT_3);
			break;
		case MAC_AX_PORT_4:
			w_val32 = SET_CLR_WORD(val32, set_val,
					       B_AX_BSS_COLOB_AX_PORT_4);
			break;
		}

		if (w_val32 != val32 && val32 != MAC_AX_R32_DEAD)
			MAC_REG_W32(bss_color_regl[band][port], w_val32);
		break;

	case MAC_AX_PCFG_BCN_DRP_ALL:
		if (port == MAC_AX_PORT_0 && mbssid_idx) {
			val32 = MAC_REG_R32(mbssid_drp_regl[band]);
			w_val32 = set_val ?
				  val32 | b_mbid_drp_l[mbssid_idx - 1] :
				  val32 & ~b_mbid_drp_l[mbssid_idx - 1];
			if (w_val32 != val32)
				MAC_REG_W32(mbssid_drp_regl[band], w_val32);
		} else {
			val32 = MAC_REG_R32(bcndrp_regl[band]);
			w_val32 = set_val ? val32 | b_drpall_l[port] :
					    val32 & ~b_drpall_l[port];
			if (w_val32 != val32)
				MAC_REG_W32(bcndrp_regl[band], w_val32);
		}
		break;

	case MAC_AX_PCFG_MBSSID_NUM:
		if (port != MAC_AX_PORT_0 || pinfo->stat != PORT_ST_AP) {
			PLTFM_MSG_ERR("[ERR]port is not 0 or is not AP\n");
			return MACPORTCFGPORT;
		}
		_set_max_mbid_num(adapter, para);
		break;

	case MAC_AX_PCFG_BCN_INTV:
		if (set_val > B_AX_BCN_SPACE_P0_MSK || !set_val) {
			PLTFM_MSG_ERR("[ERR] illegal bcn itvl %d\n", set_val);
			return MACFUNCINPUT;
		}

		val32 = MAC_REG_R32(bcnspc_regl[band][port]);
		switch (port) {
		case MAC_AX_PORT_0:
			w_val32 = SET_CLR_WORD(val32, set_val,
					       B_AX_BCN_SPACE_P0);
			break;
		case MAC_AX_PORT_1:
			w_val32 = SET_CLR_WORD(val32, set_val,
					       B_AX_BCN_SPACE_P1);
			break;
		case MAC_AX_PORT_2:
			w_val32 = SET_CLR_WORD(val32, set_val,
					       B_AX_BCN_SPACE_P2);
			break;
		case MAC_AX_PORT_3:
			w_val32 = SET_CLR_WORD(val32, set_val,
					       B_AX_BCN_SPACE_P3);
			break;
		case MAC_AX_PORT_4:
			w_val32 = SET_CLR_WORD(val32, set_val,
					       B_AX_BCN_SPACE_P4);
			break;
		}
		if (w_val32 != val32 && val32 != MAC_AX_R32_DEAD)
			MAC_REG_W32(bcnspc_regl[band][port], w_val32);
		break;

	default:
		PLTFM_MSG_ERR("[ERR] invalid cfg type %d\n", type);
		return MACPORTCFGTYPE;
	}

	return ret;
}

u32 mac_port_init(struct mac_ax_adapter *adapter,
		  struct mac_ax_port_init_para *para)
{
	struct mac_ax_port_info *pinfo;
	u8 band = para->band_idx;
	u8 port = para->port_idx;
	u8 net_type = para->net_type;

#if 0 // MAC_AX_FW_REG_OFLD
	if (adapter->sm.fwdl == MAC_AX_FWDL_INIT_RDY) {
#if MAC_AX_PHL_H2C
		struct rtw_h2c_pkt *h2cb;
#else
		struct h2c_buf *h2cb;
#endif
		struct fwcmd_port_init *hdr;
		u32 ret = MACSUCCESS;
		u32 cnt;

		if (band >= MAC_AX_BAND_NUM) {
			PLTFM_MSG_ERR("[ERR]invalid band %d\n", band);
			return MACFUNCINPUT;
		}

		if (port >= MAC_AX_PORT_NUM) {
			PLTFM_MSG_ERR("[ERR]invalid port %d\n", port);
			return MACFUNCINPUT;
		}

		pinfo = &adapter->port_info[get_bp_idx(band, port)];
		if (pinfo->h2c_sm == MAC_AX_PORT_H2C_FAIL) {
			PLTFM_MSG_ERR("[ERR]prev B%dP%d port H2C fail\n",
				      band, port);
			return MACPROCERR;
		}

		cnt = PORT_H2C_DLY_CNT;
		while (pinfo->h2c_sm == MAC_AX_PORT_H2C_BUSY) {
			cnt--;
			if (!cnt) {
				PLTFM_MSG_ERR("[ERR]B%dP%d port H2C busy\n",
					      band, port);
				return MACPROCBUSY;
			}
			PLTFM_DELAY_US(PORT_H2C_DLY_US);
		}

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

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

		hdr->dword0 =
			cpu_to_le32(SET_WORD(para->bss_color,
					     FWCMD_H2C_PORT_INIT_BSS_COLOR) |
				    SET_WORD(para->mbid_num,
					     FWCMD_H2C_PORT_INIT_MBSSID_NUM) |
				    SET_WORD(para->dtim_period,
					     FWCMD_H2C_PORT_INIT_DTIM_PRD) |
				    SET_WORD(net_type,
					     FWCMD_H2C_PORT_INIT_NET_TYPE) |
				    SET_WORD(port, FWCMD_H2C_PORT_INIT_PORT) |
				    (band ? FWCMD_H2C_PORT_INIT_BAND : 0));

		hdr->dword1 =
			cpu_to_le32(SET_WORD(para->hiq_win,
					     FWCMD_H2C_PORT_INIT_HIQ_WND) |
				    SET_WORD(para->bcn_interval,
					     FWCMD_H2C_PORT_INIT_BCN_ITVL));

		ret = h2c_pkt_set_hdr(adapter, h2cb,
				      FWCMD_TYPE_H2C,
				      FWCMD_H2C_CAT_MAC,
				      FWCMD_H2C_CL_MPORT,
				      FWCMD_H2C_FUNC_PORT_INIT,
				      0,
				      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);

		pinfo->h2c_sm = MAC_AX_PORT_H2C_BUSY;

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

		return ret;
	}
#endif

	struct mac_ax_intf_ops *ops = adapter_to_intf_ops(adapter);
	struct mac_ax_port_cfg_para cfg_para;
	struct mac_ax_pkt_drop_info info;
	u8 mbid_num;
	u8 mbid_max;
	u8 i = 0;
	u32 ret = MACSUCCESS;
	u32 val32;
	u32 bcn_erly = BCN_ERLY_DEF;
	u32 hold_time = BCN_HOLD_DEF;

	if (is_chip_id(adapter, MAC_AX_CHIP_ID_8852B) &&
	    band != MAC_AX_BAND_0) {
		PLTFM_MSG_ERR("[ERR]invalid band idx %d\n", band);
		return MACFUNCINPUT;
	}

	if (port >= MAC_AX_PORT_NUM) {
		PLTFM_MSG_ERR("[ERR]invalid port idx %d\n", port);
		return MACPORTCFGPORT;
	}

	mbid_num = net_type == MAC_AX_NET_TYPE_AP && port == MAC_AX_BAND_0 ?
		   para->mbid_num : 0;

	ret = _get_max_mbid(adapter, &mbid_max);
	if (ret != MACSUCCESS) {
		PLTFM_MSG_ERR("[ERR]get_max_mbid %d\n", ret);
		return MACPORTCFGPORT;
	}

	if (mbid_num > mbid_max) {
		PLTFM_MSG_ERR("[ERR]invalid MBSSID number %d\n", mbid_num);
		return MACFUNCINPUT;
	}
	if (mbid_num && !(mbid_num % 2))
		mbid_num++;

	pinfo = &adapter->port_info[get_bp_idx(band, port)];

	ret = check_mac_en(adapter, band, MAC_AX_CMAC_SEL);
	if (ret != MACSUCCESS) {
		PLTFM_MSG_ERR("[ERR]chk mac en %d\n", ret);
		return ret;
	}

	cfg_para.band = band;
	cfg_para.port = port;
	cfg_para.mbssid_idx = 0;

	if (pinfo->stat != PORT_ST_DIS) {
		cfg_para.val = 0;
		ret = mac_port_cfg(adapter, MAC_AX_PCFG_FUNC_SW, &cfg_para);
		if (ret != MACSUCCESS) {
			PLTFM_MSG_ERR("[ERR]B%dP%d cfg func sw 0 fail %d\n",
				      band, port, ret);
			return ret;
		}
	}

	cfg_para.val = 0;
	ret = mac_port_cfg(adapter, MAC_AX_PCFG_TX_RPT, &cfg_para);
	if (ret != MACSUCCESS) {
		PLTFM_MSG_ERR("[ERR]B%dP%d cfg tx rpt fail %d\n",
			      band, port, ret);
		return ret;
	}

	cfg_para.val = 0;
	ret = mac_port_cfg(adapter, MAC_AX_PCFG_RX_RPT, &cfg_para);
	if (ret != MACSUCCESS) {
		PLTFM_MSG_ERR("[ERR]B%dP%d cfg rx rpt fail %d\n",
			      band, port, ret);
		return ret;
	}

	cfg_para.val = net_type;
	ret = _port_cfg(adapter, MAC_AX_PCFG_NET_TYPE, &cfg_para);
	if (ret != MACSUCCESS) {
		PLTFM_MSG_ERR("[ERR]B%dP%d cfg net type fail %d\n",
			      band, port, ret);
		return ret;
	}

	cfg_para.val = net_type == MAC_AX_NET_TYPE_NO_LINK ? 0 : 1;
	ret = mac_port_cfg(adapter, MAC_AX_PCFG_BCN_PRCT, &cfg_para);
	if (ret != MACSUCCESS) {
		PLTFM_MSG_ERR("[ERR]B%dP%d cfg bcn prct fail %d\n",
			      band, port, ret);
		return ret;
	}

	cfg_para.val = (net_type == MAC_AX_NET_TYPE_INFRA ||
			net_type == MAC_AX_NET_TYPE_ADHOC) ? 1 : 0;
	ret = mac_port_cfg(adapter, MAC_AX_PCFG_RX_SW, &cfg_para);
	if (ret != MACSUCCESS) {
		PLTFM_MSG_ERR("[ERR]B%dP%d cfg rx sw fail %d\n",
			      band, port, ret);
		return ret;
	}

	cfg_para.val = (net_type == MAC_AX_NET_TYPE_INFRA ||
			net_type == MAC_AX_NET_TYPE_ADHOC) ? 1 : 0;
	ret = mac_port_cfg(adapter, MAC_AX_PCFG_RX_SYNC, &cfg_para);
	if (ret != MACSUCCESS) {
		PLTFM_MSG_ERR("[ERR]B%dP%d cfg rx sync fail %d\n",
			      band, port, ret);
		return ret;
	}

	cfg_para.val = (net_type == MAC_AX_NET_TYPE_AP ||
			net_type == MAC_AX_NET_TYPE_ADHOC) ? 1 : 0;
	ret = mac_port_cfg(adapter, MAC_AX_PCFG_TX_SW, &cfg_para);
	if (ret != MACSUCCESS) {
		PLTFM_MSG_ERR("[ERR]B%dP%d cfg tx sw fail %d\n",
			      band, port, ret);
		return ret;
	}

	cfg_para.val = (u32)para->bcn_interval;
	ret = mac_port_cfg(adapter, MAC_AX_PCFG_BCN_INTV, &cfg_para);
	if (ret != MACSUCCESS) {
		PLTFM_MSG_ERR("[ERR]B%dP%d cfg bcn intv fail %d\n",
			      band, port, ret);
		return ret;
	}

	cfg_para.val = (u32)para->bss_color;
	ret = mac_port_cfg(adapter, MAC_AX_PCFG_BSS_CLR, &cfg_para);
	if (ret != MACSUCCESS) {
		PLTFM_MSG_ERR("[ERR]B%dP%d cfg bss_color fail %d\n",
			      band, port, ret);
		return ret;
	}

	cfg_para.val = TBTT_AGG_DEF;
	ret = mac_port_cfg(adapter, MAC_AX_PCFG_TBTT_AGG, &cfg_para);
	if (ret != MACSUCCESS) {
		PLTFM_MSG_ERR("[ERR]B%dP%d cfg tbtt agg fail %d\n",
			      band, port, ret);
		return ret;
	}

	for (i = 0; i <= mbid_num; i++) {
		cfg_para.mbssid_idx = mbid_idx_l[i];
		cfg_para.val = para->hiq_win;
		ret = mac_port_cfg(adapter, MAC_AX_PCFG_HIQ_WIN, &cfg_para);
		if (ret != MACSUCCESS) {
			PLTFM_MSG_ERR("[ERR]B%dP%d mbid%d cfg hiq win %d\n",
				      band, port, cfg_para.mbssid_idx, ret);
			return ret;
		}
		cfg_para.val = (u32)para->dtim_period;
		ret = mac_port_cfg(adapter, MAC_AX_PCFG_HIQ_DTIM, &cfg_para);
		if (ret != MACSUCCESS) {
			PLTFM_MSG_ERR("[ERR]B%dP%d mbid%d cfg hiq dtim %d\n",
				      band, port, cfg_para.mbssid_idx, ret);
			return ret;
		}

		info.band = band;
		info.port = port;
		info.mbssid = (u8)mbid_idx_l[i];
		info.sel = info.mbssid ?
			   MAC_AX_PKT_DROP_SEL_REL_HIQ_MBSSID :
			   MAC_AX_PKT_DROP_SEL_REL_HIQ_PORT;
		ret = adapter->ops->pkt_drop(adapter, &info);
		if (ret != MACSUCCESS) {
			PLTFM_MSG_ERR("[ERR]B%dP%d mbid%d hiq drop %d\n",
				      band, port, info.mbssid, ret);
			return ret;
		}
	}

	cfg_para.val = hold_time;
	ret = mac_port_cfg(adapter, MAC_AX_PCFG_BCN_HOLD_TIME, &cfg_para);
	if (ret == MACSETVALERR)
		ret = mac_port_cfg(adapter, MAC_AX_PCFG_BCN_HOLD_TIME,
				   &cfg_para);
	if (ret != MACSUCCESS) {
		PLTFM_MSG_ERR("[ERR]B%dP%d cfg hold time fail %d\n",
			      band, port, ret);
		return ret;
	}

	cfg_para.val = BCN_MASK_DEF;
	ret = mac_port_cfg(adapter, MAC_AX_PCFG_BCN_MASK_AREA, &cfg_para);
	if (ret == MACSETVALERR)
		ret = mac_port_cfg(adapter, MAC_AX_PCFG_BCN_MASK_AREA,
				   &cfg_para);
	if (ret != MACSUCCESS) {
		PLTFM_MSG_ERR("[ERR]B%dP%d cfg mask area fail %d\n",
			      band, port, ret);
		return ret;
	}

	val32 = MAC_REG_R32(cfg_regl[band][port]) | b_en_l[port];
	MAC_REG_W32(cfg_regl[band][port], val32);

	switch (net_type) {
	case MAC_AX_NET_TYPE_NO_LINK:
		pinfo->stat = PORT_ST_NOLINK;
		break;
	case MAC_AX_NET_TYPE_ADHOC:
		pinfo->stat = PORT_ST_ADHOC;
		break;
	case MAC_AX_NET_TYPE_INFRA:
		pinfo->stat = PORT_ST_INFRA;
		break;
	case MAC_AX_NET_TYPE_AP:
		pinfo->stat = PORT_ST_AP;
		break;
	}

	ret = dly_port_us(adapter, band, port, BCN_ERLY_SET_DLY);
	if (ret != MACSUCCESS) {
		PLTFM_MSG_ERR("[ERR]B%dP%d dly %d us fail %d\n",
			      band, port, BCN_ERLY_SET_DLY, ret);
		return ret;
	}

	cfg_para.val = bcn_erly;
	ret = mac_port_cfg(adapter, MAC_AX_PCFG_BCN_ERLY, &cfg_para);
	if (ret == MACSETVALERR)
		ret = mac_port_cfg(adapter, MAC_AX_PCFG_BCN_ERLY, &cfg_para);
	if (ret != MACSUCCESS) {
		PLTFM_MSG_ERR("[ERR]B%dP%d cfg bcn early fail %d\n",
			      band, port, ret);
		return ret;
	}

	cfg_para.val = BCN_SETUP_DEF;
	ret = mac_port_cfg(adapter, MAC_AX_PCFG_BCN_SETUP_TIME, &cfg_para);
	if (ret == MACSETVALERR)
		ret = mac_port_cfg(adapter, MAC_AX_PCFG_BCN_SETUP_TIME,
				   &cfg_para);
	if (ret != MACSUCCESS) {
		PLTFM_MSG_ERR("[ERR]B%dP%d cfg setup time fail %d\n",
			      band, port, ret);
		return ret;
	}

	cfg_para.val = TBTT_ERLY_DEF;
	ret = mac_port_cfg(adapter, MAC_AX_PCFG_TBTT_ERLY, &cfg_para);
	if (ret == MACSETVALERR)
		ret = mac_port_cfg(adapter, MAC_AX_PCFG_TBTT_ERLY, &cfg_para);
	if (ret != MACSUCCESS) {
		PLTFM_MSG_ERR("[ERR]B%dP%d cfg tbtt early fail %d\n",
			      band, port, ret);
		return ret;
	}

	if (port == MAC_AX_PORT_0) {
		ret = port0_mbid_set(adapter, band, mbid_num, mbid_max);
		if (ret != MACSUCCESS) {
			PLTFM_MSG_ERR("[ERR]B%dP%d mbid set fail %d\n",
				      band, port, ret);
			return ret;
		}

		ret = port0_subspc_set(adapter, band, mbid_num,
				       &bcn_erly, &hold_time);
		if (ret != MACSUCCESS) {
			PLTFM_MSG_ERR("[ERR]B%dP%d subspc set fail %d\n",
				      band, port, ret);
			return ret;
		}
	}

	return ret;
}

u32 mac_tsf_sync(struct mac_ax_adapter *adapter, u8 from_port, u8 to_port,
		 s32 sync_offset, enum mac_ax_tsf_sync_act action)
{
	u32 abs_sync_offset, val32, ret = MACSUCCESS;
	u16 to_port_reg;
	struct mac_ax_intf_ops *ops = adapter_to_intf_ops(adapter);

	if (from_port > MAX_TSF_SOURCE_PORT || to_port > MAX_TSF_TARGET_PORT ||
	    from_port == to_port) {
		PLTFM_MSG_ERR("[ERR] Invalid tsf_sync port.\n");
		return MACFUNCINPUT;
	}

	abs_sync_offset = sync_offset > 0 ? sync_offset : -sync_offset;

	if (abs_sync_offset > MAX_TSF_SYNC_OFFSET) {
		PLTFM_MSG_ERR("[ERR] Invalid tsf_sync offset.\n");
		return MACFUNCINPUT;
	}

	if (sync_offset < 0)
		abs_sync_offset |= BIT18;

	switch (to_port) {
	case MAC_AX_PORT_0:
		to_port_reg = R_AX_PORT_0_TSF_SYNC;
		break;
	case MAC_AX_PORT_1:
		to_port_reg = R_AX_PORT_1_TSF_SYNC;
		break;
	case MAC_AX_PORT_2:
		to_port_reg = R_AX_PORT_2_TSF_SYNC;
		break;
	case MAC_AX_PORT_3:
		to_port_reg = R_AX_PORT_3_TSF_SYNC;
		break;
	case MAC_AX_PORT_4:
		to_port_reg = R_AX_PORT_4_TSF_SYNC;
		break;
	default:
		PLTFM_MSG_ERR("[ERR] Invalid tsf_sync input.\n");
		return MACFUNCINPUT;
	}

#if MAC_AX_FW_REG_OFLD
	if (adapter->sm.fwdl == MAC_AX_FWDL_INIT_RDY) {
		ret = MAC_REG_W_OFLD(to_port_reg,
				     B_AX_P0_TSFTR_SYNC_OFFSET_MSK <<
				     B_AX_P0_TSFTR_SYNC_OFFSET_SH,
				     abs_sync_offset, 0);
		if (ret != MACSUCCESS) {
			PLTFM_MSG_ERR("%s: write offload fail;"
				      "offset: %u, ret: %u\n",
				      __func__, to_port_reg, ret);
			return ret;
		}
		ret = MAC_REG_W_OFLD(to_port_reg,
				     B_AX_P0_SYNC_PORT_SRC_SEL_MSK <<
				     B_AX_P0_SYNC_PORT_SRC_SEL_SH,
				     from_port, 1);
		if (ret != MACSUCCESS) {
			PLTFM_MSG_ERR("%s: write offload fail;"
				      "offset: %u, ret: %u\n",
				      __func__, to_port_reg, ret);
			return ret;
		}

		switch (action) {
		case MAC_AX_TSF_SYNC_NOW_ONCE:
			ret = MAC_REG_W_OFLD(to_port_reg, B_AX_P0_SYNC_NOW_P,
					     1, 1);
			if (ret != MACSUCCESS) {
				PLTFM_MSG_ERR("%s: write offload fail;"
					      "offset: %u, ret: %u\n",
					      __func__, to_port_reg, ret);
				return ret;
			}
			ret = MAC_REG_P_OFLD(to_port_reg, B_AX_P0_SYNC_NOW_P,
					     0, 1);
			break;
		case MAC_AX_TSF_EN_SYNC_AUTO:
			ret = MAC_REG_W_OFLD(to_port_reg, B_AX_P0_AUTO_SYNC,
					     1, 1);
			break;
		case MAC_AX_TSF_DIS_SYNC_AUTO:
			ret = MAC_REG_W_OFLD(to_port_reg, B_AX_P0_AUTO_SYNC,
					     0, 1);
			break;
		default:
			PLTFM_MSG_ERR("[ERR] Invalid tsf_sync input.\n");
			return MACFUNCINPUT;
		}

		if (ret != MACSUCCESS) {
			PLTFM_MSG_ERR("%s: write offload fail;"
				      "offset: %u, ret: %u\n",
				      __func__, to_port_reg, ret);
			return ret;
		}

		return ret;
	}
#endif
	val32 = MAC_REG_R32(to_port_reg);
	val32 = SET_CLR_WORD(val32, abs_sync_offset, B_AX_P0_TSFTR_SYNC_OFFSET);
	val32 = SET_CLR_WORD(val32, from_port, B_AX_P0_SYNC_PORT_SRC_SEL);
	MAC_REG_W32(to_port_reg, val32);

	switch (action) {
	case MAC_AX_TSF_SYNC_NOW_ONCE:
		MAC_REG_W32(to_port_reg, val32 | B_AX_P0_SYNC_NOW_P);
		break;
	case MAC_AX_TSF_EN_SYNC_AUTO:
		MAC_REG_W32(to_port_reg, val32 | B_AX_P0_AUTO_SYNC);
		break;
	case MAC_AX_TSF_DIS_SYNC_AUTO:
		MAC_REG_W32(to_port_reg, val32 & ~B_AX_P0_AUTO_SYNC);
		break;
	default:
		PLTFM_MSG_ERR("[ERR] Invalid tsf_sync input.\n");
		return MACFUNCINPUT;
	}

	return ret;
}

u32 mac_parse_bcn_stats_c2h(struct mac_ax_adapter *adapter,
			    u8 *content, struct mac_ax_bcn_cnt *val)

{
	u32 *pdata, data0, data1;
	u8 port_mbssid;

	pdata = (u32 *)content;
	data0 = le32_to_cpu(*pdata);
	data1 = le32_to_cpu(*(pdata + 1));

	port_mbssid = GET_FIELD(data0, FWCMD_C2H_BCN_CNT_PORT_MBSSID_IDX);
	if (port_mbssid < MAC_AX_P0_MBID_LAST) {
		val->port = 0;
		val->mbssid = port_mbssid;
	} else {
		val->port = port_mbssid -  MAC_AX_P0_MBID_LAST + 1;
		val->mbssid = 0;
	}
	val->band = data0 & FWCMD_C2H_BCN_CNT_BAND_IDX ? 1 : 0;

	val->cca_cnt = GET_FIELD(data0, FWCMD_C2H_BCN_CNT_CCA_FAIL_CNT);
	val->edcca_cnt = GET_FIELD(data0, FWCMD_C2H_BCN_CNT_EDCCA_FAIL_CNT);
	val->nav_cnt = GET_FIELD(data0, FWCMD_C2H_BCN_CNT_NAV_FAIL_CNT);
	val->txon_cnt = GET_FIELD(data0, FWCMD_C2H_BCN_CNT_TXON_FAIL_CNT);
	val->mac_cnt = GET_FIELD(data0, FWCMD_C2H_BCN_CNT_MAC_FAIL_CNT);
	val->others_cnt = GET_FIELD(data0, FWCMD_C2H_BCN_CNT_OTHERS_FAIL_CNT);
	val->lock_cnt = GET_FIELD(data1, FWCMD_C2H_BCN_CNT_LOCK_FAIL_CNT);
	val->cmp_cnt = GET_FIELD(data1, FWCMD_C2H_BCN_CNT_CMP_FAIL_CNT);
	val->invalid_cnt = GET_FIELD(data1, FWCMD_C2H_BCN_CNT_INVALID_FAIL_CNT);
	val->srchend_cnt = GET_FIELD(data1, FWCMD_C2H_BCN_CNT_SRCHEND_FAIL_CNT);
	val->ok_cnt = GET_FIELD(data1, FWCMD_C2H_BCN_CNT_OK_CNT);

	return MACSUCCESS;
}

u32 mac_tsf32_togl_h2c(struct mac_ax_adapter *adapter,
		       struct mac_ax_t32_togl_info *info)
{
	#if MAC_AX_PHL_H2C
	struct rtw_h2c_pkt *h2cb;
	#else
	struct h2c_buf *h2cb;
	#endif
	struct fwcmd_tsf32_togl *hdr;
	u32 ret = MACSUCCESS;

	if (info->band >= MAC_AX_BAND_NUM) {
		PLTFM_MSG_ERR("[ERR]invalid band %d\n", info->band);
		return MACFUNCINPUT;
	}

	if (info->port >= MAC_AX_PORT_NUM) {
		PLTFM_MSG_ERR("[ERR]invalid port %d\n", info->port);
		return MACFUNCINPUT;
	}

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

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

	hdr->dword0 =
		cpu_to_le32(SET_WORD(info->port, FWCMD_H2C_TSF32_TOGL_PORT) |
			    SET_WORD(info->early, FWCMD_H2C_TSF32_TOGL_EARLY) |
			    (info->band ? FWCMD_H2C_TSF32_TOGL_BAND : 0) |
			    (info->en ? FWCMD_H2C_TSF32_TOGL_EN : 0));

	ret = h2c_pkt_set_hdr(adapter, h2cb,
			      FWCMD_TYPE_H2C,
			      FWCMD_H2C_CAT_MAC,
			      FWCMD_H2C_CL_FW_OFLD,
			      FWCMD_H2C_FUNC_TSF32_TOGL,
			      0,
			      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;
}

u32 mac_get_t32_togl_rpt(struct mac_ax_adapter *adapter,
			 struct mac_ax_t32_togl_rpt *ret_rpt)
{
	struct mac_ax_t32_togl_rpt *rpt;
	u8 b_idx, p_idx;

	for (b_idx = MAC_AX_BAND_0; b_idx < MAC_AX_BAND_NUM; b_idx++) {
		for (p_idx = MAC_AX_PORT_0; p_idx < MAC_AX_PORT_NUM; p_idx++) {
			rpt = &adapter->t32_togl_rpt[get_bp_idx(b_idx, p_idx)];
			if (!rpt->valid)
				continue;
			PLTFM_MEMCPY(ret_rpt, rpt,
				     sizeof(struct mac_ax_t32_togl_rpt));
			rpt->valid = 0;
			return MACSUCCESS;
		}
	}

	PLTFM_MSG_WARN("[WARN]no tsf32 togl rpt find\n");
	return MACNOITEM;
}

u32 mport_info_init(struct mac_ax_adapter *adapter)
{
	u8 b_idx, p_idx;
	u32 idx;

	adapter->t32_togl_rpt =
		(struct mac_ax_t32_togl_rpt *)PLTFM_MALLOC(t32_togl_rpt_size);
	adapter->port_info =
		(struct mac_ax_port_info *)PLTFM_MALLOC(port_info_size);
	for (b_idx = MAC_AX_BAND_0; b_idx < MAC_AX_BAND_NUM; b_idx++) {
		for (p_idx = MAC_AX_PORT_0; p_idx < MAC_AX_PORT_NUM; p_idx++) {
			idx = get_bp_idx(b_idx, p_idx);
			PLTFM_MEMSET(&adapter->t32_togl_rpt[idx], 0,
				     sizeof(struct mac_ax_t32_togl_rpt));
			PLTFM_MEMSET(&adapter->port_info[idx], 0,
				     sizeof(struct mac_ax_port_info));
		}
	}

	return MACSUCCESS;
}

u32 mport_info_exit(struct mac_ax_adapter *adapter)
{
	PLTFM_FREE(adapter->t32_togl_rpt, t32_togl_rpt_size);
	PLTFM_FREE(adapter->port_info, port_info_size);

	return MACSUCCESS;
}

