/******************************************************************************
|
*
|
* 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 "power_saving.h"
|
#include "coex.h"
|
|
#define RPWM_SEQ_NUM_MAX 3
|
#define CPWM_SEQ_NUM_MAX 3
|
|
//RPWM bit definition
|
#define PS_RPWM_TOGGLE BIT(15)
|
#define PS_RPWM_ACK BIT(14)
|
#define PS_RPWM_SEQ_NUM_SH 12
|
#define PS_RPWM_SEQ_NUM_MSK 0x3
|
#define PS_RPWM_NOTIFY_WAKE BIT(8)
|
#define PS_RPWM_STATE_SH 0
|
#define PS_RPWM_STATE_MSK 0x7
|
|
//CPWM bit definition
|
#define PS_CPWM_TOGGLE BIT(15)
|
#define PS_CPWM_ACK BIT(14)
|
#define PS_CPWM_SEQ_NUM_SH 12
|
#define PS_CPWM_SEQ_NUM_MSK 0x3
|
#define PS_CPWM_RSP_SEQ_NUM_SH 8
|
#define PS_CPWM_RSP_SEQ_NUM_MSK 0x3
|
#define PS_CPWM_STATE_SH 0
|
#define PS_CPWM_STATE_MSK 0x7
|
|
//(workaround) CPWM register is in OFF area
|
//LPS debug message bit definition
|
#define B_PS_LDM_32K_EN BIT(31)
|
#define B_PS_LDM_32K_EN_SH 31
|
|
static u32 lps_status[4] = {0};
|
static u32 ips_status[4] = {0};
|
static u8 rpwm_seq_num = RPWM_SEQ_NUM_MAX;
|
static u8 cpwm_seq_num = CPWM_SEQ_NUM_MAX;
|
|
static u32 send_h2c_lps_parm(struct mac_ax_adapter *adapter,
|
struct lps_parm *parm)
|
{
|
u8 *buf;
|
#if MAC_AX_PHL_H2C
|
struct rtw_h2c_pkt *h2cb;
|
#else
|
struct h2c_buf *h2cb;
|
#endif
|
struct fwcmd_lps_parm *fwcmd_lps;
|
u32 ret = 0;
|
|
h2cb = h2cb_alloc(adapter, H2CB_CLASS_CMD);
|
if (!h2cb)
|
return MACNPTR;
|
|
buf = h2cb_put(h2cb, sizeof(struct fwcmd_lps_parm));
|
if (!buf) {
|
ret = MACNOBUF;
|
goto fail;
|
}
|
|
fwcmd_lps = (struct fwcmd_lps_parm *)buf;
|
fwcmd_lps->dword0 =
|
cpu_to_le32(SET_WORD(parm->macid, FWCMD_H2C_LPS_PARM_MACID) |
|
SET_WORD(parm->psmode, FWCMD_H2C_LPS_PARM_PSMODE) |
|
SET_WORD(parm->rlbm, FWCMD_H2C_LPS_PARM_RLBM) |
|
SET_WORD(parm->smartps, FWCMD_H2C_LPS_PARM_SMARTPS) |
|
SET_WORD(parm->awakeinterval,
|
FWCMD_H2C_LPS_PARM_AWAKEINTERVAL));
|
|
fwcmd_lps->dword1 =
|
cpu_to_le32((parm->vouapsd ? FWCMD_H2C_LPS_PARM_VOUAPSD : 0) |
|
(parm->viuapsd ? FWCMD_H2C_LPS_PARM_VIUAPSD : 0) |
|
(parm->beuapsd ? FWCMD_H2C_LPS_PARM_BEUAPSD : 0) |
|
(parm->bkuapsd ? FWCMD_H2C_LPS_PARM_BKUAPSD : 0) |
|
SET_WORD(parm->lastrpwm, FWCMD_H2C_LPS_PARM_LASTRPWM));
|
|
ret = h2c_pkt_set_hdr(adapter, h2cb,
|
FWCMD_TYPE_H2C,
|
FWCMD_H2C_CAT_MAC,
|
FWCMD_H2C_CL_PS,
|
FWCMD_H2C_FUNC_LPS_PARM,
|
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);
|
|
return MACSUCCESS;
|
fail:
|
h2cb_free(adapter, h2cb);
|
|
return ret;
|
}
|
|
static void send_rpwm(struct mac_ax_adapter *adapter,
|
struct ps_rpwm_parm *parm)
|
{
|
u16 rpwm_value = 0;
|
u8 toggle = 0;
|
struct mac_ax_intf_ops *ops = adapter_to_intf_ops(adapter);
|
|
if (rpwm_seq_num == RPWM_SEQ_NUM_MAX)
|
rpwm_seq_num = 0;
|
else
|
rpwm_seq_num += 1;
|
|
rpwm_value = MAC_REG_R16(R_AX_RPWM);
|
if (0 == (rpwm_value & PS_RPWM_TOGGLE))
|
toggle = 1;
|
|
if (parm->notify_wake) {
|
rpwm_value = (PS_RPWM_NOTIFY_WAKE |
|
SET_CLR_WORD(rpwm_value, rpwm_seq_num, PS_RPWM_SEQ_NUM));
|
} else {
|
rpwm_value = (SET_WORD(parm->req_pwr_state, PS_RPWM_STATE) |
|
SET_WORD(rpwm_seq_num, PS_RPWM_SEQ_NUM));
|
|
if (parm->req_pwr_state == MAC_AX_RPWM_REQ_PWR_STATE_ACTIVE ||
|
parm->req_pwr_state == MAC_AX_RPWM_REQ_PWR_STATE_BAND0_RFON ||
|
parm->req_pwr_state == MAC_AX_RPWM_REQ_PWR_STATE_BAND1_RFON ||
|
parm->req_pwr_state == MAC_AX_RPWM_REQ_PWR_STATE_BAND0_RFOFF ||
|
parm->req_pwr_state == MAC_AX_RPWM_REQ_PWR_STATE_BAND1_RFOFF)
|
rpwm_value |= PS_RPWM_ACK;
|
|
if (parm->req_pwr_state == MAC_AX_RPWM_REQ_PWR_STATE_CLK_GATED ||
|
parm->req_pwr_state == MAC_AX_RPWM_REQ_PWR_STATE_PWR_GATED ||
|
parm->req_pwr_state == MAC_AX_RPWM_REQ_PWR_STATE_HIOE_PWR_GATED) {
|
adapter->mac_pwr_info.pwr_in_lps = 1;
|
}
|
}
|
|
if (toggle == 1)
|
rpwm_value |= PS_RPWM_TOGGLE;
|
else
|
rpwm_value &= ~PS_RPWM_TOGGLE;
|
|
switch (adapter->hw_info->intf) {
|
#if MAC_AX_USB_SUPPORT
|
case MAC_AX_INTF_USB:
|
#if MAC_AX_8852A_SUPPORT || MAC_AX_8852B_SUPPORT
|
if (is_chip_id(adapter, MAC_AX_CHIP_ID_8852A) ||
|
is_chip_id(adapter, MAC_AX_CHIP_ID_8852B))
|
MAC_REG_W16(R_AX_USB_D2F_F2D_INFO + 2, rpwm_value);
|
#endif
|
|
#if MAC_AX_8852C_SUPPORT || MAC_AX_8192XB_SUPPORT
|
if (is_chip_id(adapter, MAC_AX_CHIP_ID_8852C) ||
|
is_chip_id(adapter, MAC_AX_CHIP_ID_8192XB))
|
MAC_REG_W16(R_AX_USB_D2F_F2D_INFO_V1 + 2, rpwm_value);
|
#endif
|
break;
|
#endif //MAC_AX_USB_SUPPORT
|
|
#if MAC_AX_SDIO_SUPPORT
|
case MAC_AX_INTF_SDIO:
|
#if MAC_AX_8852A_SUPPORT || MAC_AX_8852B_SUPPORT
|
if (is_chip_id(adapter, MAC_AX_CHIP_ID_8852A) ||
|
is_chip_id(adapter, MAC_AX_CHIP_ID_8852B))
|
MAC_REG_W16(R_AX_SDIO_HRPWM1 + 2, rpwm_value);
|
#endif
|
|
#if MAC_AX_8852C_SUPPORT || MAC_AX_8192XB_SUPPORT
|
if (is_chip_id(adapter, MAC_AX_CHIP_ID_8852C) ||
|
is_chip_id(adapter, MAC_AX_CHIP_ID_8192XB))
|
MAC_REG_W16(R_AX_SDIO_HRPWM1_V1 + 2, rpwm_value);
|
#endif
|
|
if (parm->req_pwr_state == MAC_AX_RPWM_REQ_PWR_STATE_CLK_GATED ||
|
parm->req_pwr_state == MAC_AX_RPWM_REQ_PWR_STATE_PWR_GATED ||
|
parm->req_pwr_state == MAC_AX_RPWM_REQ_PWR_STATE_HIOE_PWR_GATED)
|
adapter->sdio_info.tx_seq = 1;
|
break;
|
#endif //MAC_AX_SDIO_SUPPORT
|
|
#if MAC_AX_PCIE_SUPPORT
|
case MAC_AX_INTF_PCIE:
|
#if MAC_AX_8852A_SUPPORT || MAC_AX_8852B_SUPPORT
|
if (is_chip_id(adapter, MAC_AX_CHIP_ID_8852A) ||
|
is_chip_id(adapter, MAC_AX_CHIP_ID_8852B))
|
MAC_REG_W16(R_AX_PCIE_HRPWM, rpwm_value);
|
#endif
|
|
#if MAC_AX_8852C_SUPPORT || MAC_AX_8192XB_SUPPORT
|
if (is_chip_id(adapter, MAC_AX_CHIP_ID_8852C) ||
|
is_chip_id(adapter, MAC_AX_CHIP_ID_8192XB))
|
MAC_REG_W16(R_AX_PCIE_HRPWM_V1, rpwm_value);
|
#endif
|
|
break;
|
#endif //MAC_AX_PCIE_SUPPORT
|
default:
|
PLTFM_MSG_ERR("%s: invalid interface = %d!!\n",
|
__func__, adapter->hw_info->intf);
|
|
break;
|
}
|
|
PLTFM_MSG_TRACE("Send RPWM. rpwm_val=0x%x\n", rpwm_value);
|
}
|
|
static u32 leave_lps(struct mac_ax_adapter *adapter, u8 macid)
|
{
|
struct lps_parm h2c_lps_parm;
|
u32 ret;
|
|
PLTFM_MEMSET(&h2c_lps_parm, 0, sizeof(struct lps_parm));
|
|
h2c_lps_parm.macid = macid;
|
h2c_lps_parm.psmode = MAC_AX_PS_MODE_ACTIVE;
|
h2c_lps_parm.lastrpwm = LAST_RPWM_ACTIVE;
|
|
ret = send_h2c_lps_parm(adapter, &h2c_lps_parm);
|
|
if (ret)
|
return ret;
|
|
lps_status[(macid >> 5)] &= ~BIT(macid & 0x1F);
|
|
return MACSUCCESS;
|
}
|
|
static u32 enter_lps(struct mac_ax_adapter *adapter,
|
u8 macid,
|
struct mac_ax_lps_info *lps_info)
|
{
|
struct lps_parm h2c_lps_parm;
|
u32 ret = 0;
|
|
if (!lps_info) {
|
PLTFM_MSG_ERR("[ERR]:LPS info is null\n");
|
return MACNOITEM;
|
}
|
|
if (lps_status[(macid >> 5)] & BIT(macid & 0x1F))
|
ret = leave_lps(adapter, macid);
|
|
if (ret)
|
return ret;
|
|
PLTFM_MEMSET(&h2c_lps_parm, 0, sizeof(struct lps_parm));
|
|
h2c_lps_parm.macid = macid;
|
h2c_lps_parm.psmode = MAC_AX_PS_MODE_LEGACY;
|
|
if (lps_info->listen_bcn_mode > MAC_AX_RLBM_USERDEFINE)
|
lps_info->listen_bcn_mode = MAC_AX_RLBM_MIN;
|
|
if (lps_info->listen_bcn_mode == MAC_AX_RLBM_USERDEFINE) {
|
h2c_lps_parm.rlbm = MAC_AX_RLBM_USERDEFINE;
|
h2c_lps_parm.awakeinterval = lps_info->awake_interval;
|
if (h2c_lps_parm.awakeinterval == 0)
|
h2c_lps_parm.awakeinterval = 1;
|
} else if (lps_info->listen_bcn_mode == MAC_AX_RLBM_MAX) {
|
h2c_lps_parm.rlbm = MAC_AX_RLBM_MAX;
|
h2c_lps_parm.awakeinterval = 1;
|
} else {
|
h2c_lps_parm.rlbm = MAC_AX_RLBM_MIN;
|
h2c_lps_parm.awakeinterval = 1;
|
}
|
|
h2c_lps_parm.smartps = lps_info->smart_ps_mode;
|
h2c_lps_parm.lastrpwm = LAST_RPWM_PS;
|
|
ret = send_h2c_lps_parm(adapter, &h2c_lps_parm);
|
|
if (ret)
|
return ret;
|
|
lps_status[(macid >> 5)] |= BIT(macid & 0x1F);
|
|
return MACSUCCESS;
|
}
|
|
static u32 set_req_pwr_state(struct mac_ax_adapter *adapter,
|
enum mac_ax_rpwm_req_pwr_state req_pwr_state)
|
{
|
struct ps_rpwm_parm parm;
|
|
PLTFM_MEMSET(&parm, 0, sizeof(struct ps_rpwm_parm));
|
|
if (req_pwr_state >= MAC_AX_RPWM_REQ_PWR_STATE_MAX) {
|
PLTFM_MSG_ERR("%s: invalid pwr state:%d\n",
|
__func__, req_pwr_state);
|
return MACNOITEM;
|
}
|
|
parm.req_pwr_state = req_pwr_state;
|
parm.notify_wake = 0;
|
send_rpwm(adapter, &parm);
|
|
return MACSUCCESS;
|
}
|
|
static u32 _chk_cpwm_seq_num(u8 seq_num)
|
{
|
u32 ret;
|
|
if (cpwm_seq_num == CPWM_SEQ_NUM_MAX) {
|
if (seq_num == 0) {
|
cpwm_seq_num = seq_num;
|
ret = MACSUCCESS;
|
} else {
|
ret = MACCPWMSEQERR;
|
}
|
} else {
|
if (seq_num == (cpwm_seq_num + 1)) {
|
cpwm_seq_num = seq_num;
|
ret = MACSUCCESS;
|
} else {
|
ret = MACCPWMSEQERR;
|
}
|
}
|
|
return ret;
|
}
|
|
static u32 chk_cur_pwr_state(struct mac_ax_adapter *adapter,
|
enum mac_ax_rpwm_req_pwr_state req_pwr_state)
|
{
|
u16 cpwm = 0;
|
u32 rpwm_32k;
|
u32 req_32k;
|
struct mac_ax_intf_ops *ops = adapter_to_intf_ops(adapter);
|
|
if (req_pwr_state >= MAC_AX_RPWM_REQ_PWR_STATE_CLK_GATED)
|
req_32k = 1;
|
else
|
req_32k = 0;
|
|
//(workaround) CPWM register is in OFF area
|
//Use LDM to check if FW receives RPWM
|
rpwm_32k = (MAC_REG_R32(R_AX_LDM) & B_PS_LDM_32K_EN) >> B_PS_LDM_32K_EN_SH;
|
if (req_32k != rpwm_32k)
|
return MACCPWMPWRSTATERR;
|
|
//There is no CPWM if 32K state
|
if (req_32k)
|
return MACSUCCESS;
|
|
#if MAC_AX_8852A_SUPPORT || MAC_AX_8852B_SUPPORT
|
if (is_chip_id(adapter, MAC_AX_CHIP_ID_8852A) ||
|
is_chip_id(adapter, MAC_AX_CHIP_ID_8852B))
|
cpwm = MAC_REG_R16(R_AX_CPWM);
|
#endif
|
|
PLTFM_MSG_TRACE("Read CPWM=0x%x\n", cpwm);
|
if (rpwm_seq_num != GET_FIELD(cpwm, PS_CPWM_RSP_SEQ_NUM)) {
|
PLTFM_MSG_TRACE("RPWM seq mismatch!!: expect val:%d, Rx val:%d\n",
|
rpwm_seq_num, GET_FIELD(cpwm, PS_CPWM_RSP_SEQ_NUM));
|
return MACCPWMSEQERR;
|
}
|
|
if (_chk_cpwm_seq_num(GET_FIELD(cpwm, PS_CPWM_SEQ_NUM)) == MACCPWMSEQERR) {
|
PLTFM_MSG_TRACE("CPWM seq mismatch!!: expect val:%d, Rx val:%d\n",
|
cpwm_seq_num, GET_FIELD(cpwm, PS_CPWM_SEQ_NUM));
|
return MACCPWMSEQERR;
|
}
|
|
if (req_pwr_state != GET_FIELD(cpwm, PS_CPWM_STATE))
|
return MACCPWMSTATERR;
|
|
adapter->mac_pwr_info.pwr_in_lps = 0;
|
|
return MACSUCCESS;
|
}
|
|
u32 mac_cfg_lps(struct mac_ax_adapter *adapter, u8 macid,
|
enum mac_ax_ps_mode ps_mode, struct mac_ax_lps_info *lps_info)
|
{
|
u32 ret = 0;
|
struct mac_ax_intf_ops *ops = adapter_to_intf_ops(adapter);
|
|
switch (ps_mode) {
|
case MAC_AX_PS_MODE_ACTIVE:
|
ret = leave_lps(adapter, macid);
|
/* patch form BT BG/LDO issue, ONLY FOR 52B CAV */
|
if (is_chip_id(adapter, MAC_AX_CHIP_ID_8852B) &&
|
is_cv(adapter, CAV))
|
MAC_REG_W8(R_AX_SCOREBOARD + 3, MAC_AX_NOTIFY_TP_MAJOR);
|
break;
|
case MAC_AX_PS_MODE_LEGACY:
|
ret = enter_lps(adapter, macid, lps_info);
|
/* patch form BT BG/LDO issue, ONLY FOR 52B CAV */
|
if (is_chip_id(adapter, MAC_AX_CHIP_ID_8852B) &&
|
is_cv(adapter, CAV))
|
MAC_REG_W8(R_AX_SCOREBOARD + 3, MAC_AX_NOTIFY_PWR_MAJOR);
|
break;
|
case MAC_AX_PS_MODE_WMMPS:
|
// TODO:
|
break;
|
default:
|
return MACNOITEM;
|
}
|
|
if (ret)
|
return ret;
|
|
return MACSUCCESS;
|
}
|
|
u32 mac_ps_pwr_state(struct mac_ax_adapter *adapter,
|
enum mac_ax_pwr_state_action action,
|
enum mac_ax_rpwm_req_pwr_state req_pwr_state)
|
{
|
u32 ret = MACSUCCESS;
|
|
switch (action) {
|
case MAC_AX_PWR_STATE_ACT_REQ:
|
ret = set_req_pwr_state(adapter, req_pwr_state);
|
break;
|
case MAC_AX_PWR_STATE_ACT_CHK:
|
ret = chk_cur_pwr_state(adapter, req_pwr_state);
|
break;
|
default:
|
ret = MACNOITEM;
|
}
|
|
return ret;
|
}
|
|
u32 mac_chk_leave_lps(struct mac_ax_adapter *adapter, u8 macid)
|
{
|
u8 band = 0;
|
u8 port = 0;
|
u32 chk_msk = 0;
|
struct mac_role_tbl *role;
|
u16 pwrbit_set_reg[2] = {R_AX_PPWRBIT_SETTING, R_AX_PPWRBIT_SETTING_C1};
|
u32 pwr_mgt_en_bit = 0xE;
|
struct mac_ax_intf_ops *ops = adapter_to_intf_ops(adapter);
|
u32 reg_pause = 0;
|
u32 reg_sleep = 0;
|
u8 macid_grp = macid >> MACID_GRP_SH;
|
u8 macid_sh = macid & MACID_GRP_MASK;
|
|
role = mac_role_srch(adapter, macid);
|
|
if (!role) {
|
PLTFM_MSG_ERR("[ERR]cannot find macid: %d\n", macid);
|
return MACNOITEM;
|
}
|
|
band = role->info.a_info.bb_sel;
|
port = role->info.a_info.port_int;
|
|
chk_msk = pwr_mgt_en_bit << (PORT_SH * port);
|
switch (macid_grp) {
|
case MACID_GRP_0:
|
reg_sleep = R_AX_MACID_SLEEP_0;
|
reg_pause = R_AX_SS_MACID_PAUSE_0;
|
break;
|
case MACID_GRP_1:
|
reg_sleep = R_AX_MACID_SLEEP_1;
|
reg_pause = R_AX_SS_MACID_PAUSE_1;
|
break;
|
case MACID_GRP_2:
|
reg_sleep = R_AX_MACID_SLEEP_2;
|
reg_pause = R_AX_SS_MACID_PAUSE_2;
|
break;
|
case MACID_GRP_3:
|
reg_sleep = R_AX_MACID_SLEEP_3;
|
reg_pause = R_AX_SS_MACID_PAUSE_3;
|
break;
|
default:
|
return MACPSSTATFAIL;
|
}
|
|
// Bypass Tx pause check during STOP SER period
|
if (adapter->sm.ser_ctrl_st != MAC_AX_SER_CTRL_STOP)
|
if (MAC_REG_R32(reg_pause) & BIT(macid_sh))
|
return MACPSSTATFAIL;
|
|
if ((MAC_REG_R32(pwrbit_set_reg[band]) & chk_msk) ||
|
(MAC_REG_R32(reg_sleep) & BIT(macid_sh)))
|
return MACPSSTATFAIL;
|
|
return MACSUCCESS;
|
}
|
|
u8 _is_in_lps(struct mac_ax_adapter *adapter)
|
{
|
u8 i;
|
|
for (i = 0; i < 4; i++) {
|
if (lps_status[i] != 0)
|
return 1;
|
}
|
|
return 0;
|
}
|
|
void reset_lps_seq_num(struct mac_ax_adapter *adapter)
|
{
|
rpwm_seq_num = RPWM_SEQ_NUM_MAX;
|
cpwm_seq_num = CPWM_SEQ_NUM_MAX;
|
}
|
|
static u32 send_h2c_ips_cfg(struct mac_ax_adapter *adapter,
|
struct ips_cfg *cfg)
|
{
|
u8 *buf;
|
#if MAC_AX_PHL_H2C
|
struct rtw_h2c_pkt *h2cb;
|
#else
|
struct h2c_buf *h2cb;
|
#endif
|
struct fwcmd_ips_cfg *fwcmd_ips;
|
u32 ret;
|
|
h2cb = h2cb_alloc(adapter, H2CB_CLASS_CMD);
|
if (!h2cb)
|
return MACNPTR;
|
|
buf = h2cb_put(h2cb, sizeof(struct fwcmd_ips_cfg));
|
if (!buf) {
|
h2cb_free(adapter, h2cb);
|
return MACNOBUF;
|
}
|
|
fwcmd_ips = (struct fwcmd_ips_cfg *)buf;
|
fwcmd_ips->dword0 =
|
cpu_to_le32(SET_WORD(cfg->macid, FWCMD_H2C_IPS_CFG_MACID) |
|
(cfg->enable ? FWCMD_H2C_IPS_CFG_ENABLE : 0));
|
|
ret = h2c_pkt_set_hdr(adapter, h2cb,
|
FWCMD_TYPE_H2C,
|
FWCMD_H2C_CAT_MAC,
|
FWCMD_H2C_CL_PS,
|
FWCMD_H2C_FUNC_IPS_CFG,
|
0,
|
1);
|
if (ret != MACSUCCESS) {
|
h2cb_free(adapter, h2cb);
|
return ret;
|
}
|
|
ret = h2c_pkt_build_txd(adapter, h2cb);
|
if (ret != MACSUCCESS) {
|
h2cb_free(adapter, h2cb);
|
return ret;
|
}
|
|
#if MAC_AX_PHL_H2C
|
ret = PLTFM_TX(h2cb);
|
#else
|
ret = PLTFM_TX(h2cb->data, h2cb->len);
|
#endif
|
if (ret != MACSUCCESS) {
|
h2cb_free(adapter, h2cb);
|
return ret;
|
}
|
|
h2cb_free(adapter, h2cb);
|
|
return MACSUCCESS;
|
}
|
|
static u32 leave_ips(struct mac_ax_adapter *adapter, u8 macid)
|
{
|
struct ips_cfg h2c_ips_cfg;
|
u32 ret;
|
|
PLTFM_MEMSET(&h2c_ips_cfg, 0, sizeof(struct ips_cfg));
|
|
h2c_ips_cfg.macid = macid;
|
h2c_ips_cfg.enable = 0;
|
|
ret = send_h2c_ips_cfg(adapter, &h2c_ips_cfg);
|
if (ret != MACSUCCESS)
|
return ret;
|
|
ips_status[(macid >> 5)] &= ~BIT(macid & 0x1F);
|
|
return MACSUCCESS;
|
}
|
|
static u32 enter_ips(struct mac_ax_adapter *adapter,
|
u8 macid)
|
{
|
struct ips_cfg h2c_ips_cfg;
|
u32 ret;
|
|
if (ips_status[(macid >> 5)] & BIT(macid & 0x1F)) {
|
PLTFM_MSG_ERR("[ERR]:IPS info is null\n");
|
ret = leave_ips(adapter, macid);
|
if (ret != MACSUCCESS)
|
return ret;
|
}
|
|
PLTFM_MEMSET(&h2c_ips_cfg, 0, sizeof(struct ips_cfg));
|
|
h2c_ips_cfg.macid = macid;
|
h2c_ips_cfg.enable = 1;
|
|
ret = send_h2c_ips_cfg(adapter, &h2c_ips_cfg);
|
if (ret != MACSUCCESS)
|
return ret;
|
|
ips_status[(macid >> 5)] |= BIT(macid & 0x1F);
|
|
return MACSUCCESS;
|
}
|
|
u32 mac_cfg_ips(struct mac_ax_adapter *adapter, u8 macid,
|
u8 enable)
|
{
|
u32 ret;
|
|
if (enable == 1)
|
ret = enter_ips(adapter, macid);
|
else
|
ret = leave_ips(adapter, macid);
|
|
return ret;
|
}
|
|
u32 mac_chk_leave_ips(struct mac_ax_adapter *adapter, u8 macid)
|
{
|
u8 band = 0;
|
u8 port = 0;
|
u32 chk_msk = 0;
|
struct mac_role_tbl *role;
|
u32 pwr_mgt_en_bit = 0xE;
|
struct mac_ax_intf_ops *ops = adapter_to_intf_ops(adapter);
|
u32 reg_pause = 0;
|
u32 reg_sleep = 0;
|
u8 macid_grp = macid >> MACID_GRP_SH;
|
u8 macid_sh = macid & MACID_GRP_MASK;
|
|
role = mac_role_srch(adapter, macid);
|
|
if (!role) {
|
PLTFM_MSG_ERR("[ERR]cannot find macid: %d\n", macid);
|
return MACNOITEM;
|
}
|
|
band = role->info.a_info.bb_sel;
|
port = role->info.a_info.port_int;
|
|
chk_msk = pwr_mgt_en_bit << (PORT_SH * port);
|
switch (macid_grp) {
|
case MACID_GRP_0:
|
reg_sleep = R_AX_MACID_SLEEP_0;
|
reg_pause = R_AX_SS_MACID_PAUSE_0;
|
break;
|
case MACID_GRP_1:
|
reg_sleep = R_AX_MACID_SLEEP_1;
|
reg_pause = R_AX_SS_MACID_PAUSE_1;
|
break;
|
case MACID_GRP_2:
|
reg_sleep = R_AX_MACID_SLEEP_2;
|
reg_pause = R_AX_SS_MACID_PAUSE_2;
|
break;
|
case MACID_GRP_3:
|
reg_sleep = R_AX_MACID_SLEEP_3;
|
reg_pause = R_AX_SS_MACID_PAUSE_3;
|
break;
|
default:
|
return MACPSSTATFAIL;
|
}
|
|
// Bypass Tx pause check during STOP SER period
|
if (adapter->sm.ser_ctrl_st != MAC_AX_SER_CTRL_STOP)
|
if (MAC_REG_R32(reg_pause) & BIT(macid_sh))
|
return MACPSSTATFAIL;
|
|
if (MAC_REG_R32(reg_sleep) & BIT(macid_sh))
|
return MACPSSTATFAIL;
|
|
return MACSUCCESS;
|
}
|
|
u8 _is_in_ips(struct mac_ax_adapter *adapter)
|
{
|
u8 i;
|
|
for (i = 0; i < 4; i++) {
|
if (ips_status[i] != 0)
|
return 1;
|
}
|
|
return 0;
|
}
|
|
u32 mac_ps_notify_wake(struct mac_ax_adapter *adapter)
|
{
|
struct ps_rpwm_parm parm;
|
|
PLTFM_MEMSET(&parm, 0, sizeof(struct ps_rpwm_parm));
|
|
if (adapter->mac_pwr_info.pwr_in_lps == 0) {
|
PLTFM_MSG_ERR("%s: Not in power saving!\n", __func__);
|
return MACPWRSTAT;
|
}
|
|
parm.notify_wake = 1;
|
send_rpwm(adapter, &parm);
|
|
return MACSUCCESS;
|
}
|
|
u32 mac_cfg_ps_advance_parm(struct mac_ax_adapter *adapter,
|
struct mac_ax_ps_adv_parm *parm)
|
{
|
u8 *buf;
|
#if MAC_AX_PHL_H2C
|
struct rtw_h2c_pkt *h2cb;
|
#else
|
struct h2c_buf *h2cb;
|
#endif
|
struct fwcmd_ps_advance_parm *fwcmd_parm;
|
u32 ret;
|
|
if (!parm)
|
return MACBADDR;
|
|
PLTFM_MSG_ALWAYS("%s: MACID(%d), TRXTimeOutTimeSet(%d), TRXTimeOutTimeVal(%d)!\n"
|
, __func__, parm->macid, parm->trxtimeouttimeset, parm->trxtimeouttimeval);
|
|
h2cb = h2cb_alloc(adapter, H2CB_CLASS_CMD);
|
if (!h2cb)
|
return MACNPTR;
|
|
buf = h2cb_put(h2cb, sizeof(struct fwcmd_ps_advance_parm));
|
if (!buf) {
|
h2cb_free(adapter, h2cb);
|
return MACNOBUF;
|
}
|
|
fwcmd_parm = (struct fwcmd_ps_advance_parm *)buf;
|
fwcmd_parm->dword0 =
|
cpu_to_le32(SET_WORD(parm->macid, FWCMD_H2C_PS_ADVANCE_PARM_MACID) |
|
SET_WORD(parm->trxtimeouttimeset, FWCMD_H2C_PS_ADVANCE_PARM_TRXTIMEOUTTIMESET));
|
fwcmd_parm->dword1 =
|
cpu_to_le32(SET_WORD(parm->trxtimeouttimeval, FWCMD_H2C_PS_ADVANCE_PARM_TRXTIMEOUTTIMEVAL));
|
|
ret = h2c_pkt_set_hdr(adapter, h2cb,
|
FWCMD_TYPE_H2C,
|
FWCMD_H2C_CAT_MAC,
|
FWCMD_H2C_CL_PS,
|
FWCMD_H2C_FUNC_PS_ADVANCE_PARM,
|
0,
|
1);
|
if (ret != MACSUCCESS) {
|
h2cb_free(adapter, h2cb);
|
return ret;
|
}
|
|
ret = h2c_pkt_build_txd(adapter, h2cb);
|
if (ret != MACSUCCESS) {
|
h2cb_free(adapter, h2cb);
|
return ret;
|
}
|
|
#if MAC_AX_PHL_H2C
|
ret = PLTFM_TX(h2cb);
|
#else
|
ret = PLTFM_TX(h2cb->data, h2cb->len);
|
#endif
|
if (ret != MACSUCCESS) {
|
h2cb_free(adapter, h2cb);
|
return ret;
|
}
|
|
h2cb_free(adapter, h2cb);
|
|
return MACSUCCESS;
|
}
|