mirror of
https://github.com/torvalds/linux.git
synced 2026-06-02 03:24:19 +02:00
wifi: rtw89: mac: reset power state before switching to power on
To run power on function properly, reset power states (off/on/PS) to initial state. Otherwise, it might be unusable due to fail to power on. Since a USB adapter might play as USB mass storage with driver and then switch to WiFi adapter, causing it stays on power-on state when doing WiFi USB probe. Exclude this case. Signed-off-by: Ping-Ke Shih <pkshih@realtek.com> Link: https://patch.msgid.link/20251223030651.480633-5-pkshih@realtek.com
This commit is contained in:
parent
de1ba591d9
commit
b0f1289fd6
|
|
@ -1478,13 +1478,11 @@ static void rtw89_mac_power_switch_boot_mode(struct rtw89_dev *rtwdev)
|
|||
|
||||
static int rtw89_mac_power_switch(struct rtw89_dev *rtwdev, bool on)
|
||||
{
|
||||
#define PWR_ACT 1
|
||||
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
|
||||
const struct rtw89_chip_info *chip = rtwdev->chip;
|
||||
const struct rtw89_pwr_cfg * const *cfg_seq;
|
||||
int (*cfg_func)(struct rtw89_dev *rtwdev);
|
||||
int ret;
|
||||
u8 val;
|
||||
|
||||
rtw89_mac_power_switch_boot_mode(rtwdev);
|
||||
|
||||
|
|
@ -1499,10 +1497,10 @@ static int rtw89_mac_power_switch(struct rtw89_dev *rtwdev, bool on)
|
|||
if (test_bit(RTW89_FLAG_FW_RDY, rtwdev->flags))
|
||||
__rtw89_leave_ps_mode(rtwdev);
|
||||
|
||||
val = rtw89_read32_mask(rtwdev, R_AX_IC_PWR_STATE, B_AX_WLMAC_PWR_STE_MASK);
|
||||
if (on && val == PWR_ACT) {
|
||||
rtw89_err(rtwdev, "MAC has already powered on\n");
|
||||
return -EBUSY;
|
||||
if (on) {
|
||||
ret = mac->reset_pwr_state(rtwdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = cfg_func ? cfg_func(rtwdev) : rtw89_mac_pwr_seq(rtwdev, cfg_seq);
|
||||
|
|
@ -1529,7 +1527,6 @@ static int rtw89_mac_power_switch(struct rtw89_dev *rtwdev, bool on)
|
|||
}
|
||||
|
||||
return 0;
|
||||
#undef PWR_ACT
|
||||
}
|
||||
|
||||
int rtw89_mac_pwr_on(struct rtw89_dev *rtwdev)
|
||||
|
|
@ -3931,6 +3928,29 @@ static int rtw89_mac_feat_init(struct rtw89_dev *rtwdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int rtw89_mac_reset_pwr_state_ax(struct rtw89_dev *rtwdev)
|
||||
{
|
||||
u8 val;
|
||||
|
||||
val = rtw89_read32_mask(rtwdev, R_AX_IC_PWR_STATE, B_AX_WLMAC_PWR_STE_MASK);
|
||||
if (val == MAC_AX_MAC_ON) {
|
||||
/*
|
||||
* A USB adapter might play as USB mass storage with driver and
|
||||
* then switch to WiFi adapter, causing it stays on power-on
|
||||
* state when doing WiFi USB probe. Return EAGAIN to caller to
|
||||
* power-off and power-on again to reset the state.
|
||||
*/
|
||||
if (rtwdev->hci.type == RTW89_HCI_TYPE_USB &&
|
||||
!test_bit(RTW89_FLAG_PROBE_DONE, rtwdev->flags))
|
||||
return -EAGAIN;
|
||||
|
||||
rtw89_err(rtwdev, "MAC has already powered on\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rtw89_disable_fw_watchdog(struct rtw89_dev *rtwdev)
|
||||
{
|
||||
u32 val32;
|
||||
|
|
@ -7206,6 +7226,7 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_ax = {
|
|||
.set_cpuio = set_cpuio_ax,
|
||||
.dle_quota_change = dle_quota_change_ax,
|
||||
|
||||
.reset_pwr_state = rtw89_mac_reset_pwr_state_ax,
|
||||
.disable_cpu = rtw89_mac_disable_cpu_ax,
|
||||
.fwdl_enable_wcpu = rtw89_mac_enable_cpu_ax,
|
||||
.fwdl_get_status = rtw89_fw_get_rdy_ax,
|
||||
|
|
|
|||
|
|
@ -1052,6 +1052,7 @@ struct rtw89_mac_gen_def {
|
|||
struct rtw89_cpuio_ctrl *ctrl_para, bool wd);
|
||||
int (*dle_quota_change)(struct rtw89_dev *rtwdev, bool band1_en);
|
||||
|
||||
int (*reset_pwr_state)(struct rtw89_dev *rtwdev);
|
||||
void (*disable_cpu)(struct rtw89_dev *rtwdev);
|
||||
int (*fwdl_enable_wcpu)(struct rtw89_dev *rtwdev, u8 boot_reason,
|
||||
bool dlfw, bool include_bb);
|
||||
|
|
|
|||
|
|
@ -425,6 +425,135 @@ int rtw89_mac_read_xtal_si_be(struct rtw89_dev *rtwdev, u8 offset, u8 *val)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int rtw89_mac_reset_pwr_state_be(struct rtw89_dev *rtwdev)
|
||||
{
|
||||
u32 val32;
|
||||
int ret;
|
||||
|
||||
val32 = rtw89_read32(rtwdev, R_BE_SYSON_FSM_MON);
|
||||
val32 &= WLAN_FSM_MASK;
|
||||
val32 |= WLAN_FSM_SET;
|
||||
rtw89_write32(rtwdev, R_BE_SYSON_FSM_MON, val32);
|
||||
|
||||
ret = read_poll_timeout(rtw89_read32_mask, val32, val32 == WLAN_FSM_IDLE,
|
||||
1000, 2000000, false,
|
||||
rtwdev, R_BE_SYSON_FSM_MON, WLAN_FSM_STATE_MASK);
|
||||
if (ret) {
|
||||
rtw89_err(rtwdev, "[ERR]Polling WLAN PMC timeout= %X\n", val32);
|
||||
return ret;
|
||||
}
|
||||
|
||||
val32 = rtw89_read32_mask(rtwdev, R_BE_IC_PWR_STATE, B_BE_WLMAC_PWR_STE_MASK);
|
||||
if (val32 == MAC_AX_MAC_OFF) {
|
||||
rtw89_write32_clr(rtwdev, R_BE_HCI_OPT_CTRL, B_BE_HAXIDMA_IO_EN);
|
||||
|
||||
ret = read_poll_timeout(rtw89_read32_mask, val32, !val32,
|
||||
1000, 2000000, false,
|
||||
rtwdev, R_BE_HCI_OPT_CTRL,
|
||||
B_BE_HAXIDMA_IO_ST | B_BE_HAXIDMA_BACKUP_RESTORE_ST);
|
||||
if (ret) {
|
||||
rtw89_err(rtwdev, "[ERR]Polling HAXI IO timeout= %X\n", val32);
|
||||
return ret;
|
||||
}
|
||||
|
||||
rtw89_write32_clr(rtwdev, R_BE_HCI_OPT_CTRL, B_BE_HCI_WLAN_IO_EN);
|
||||
|
||||
ret = read_poll_timeout(rtw89_read32_mask, val32, !val32,
|
||||
1000, 2000000, false,
|
||||
rtwdev, R_BE_HCI_OPT_CTRL, B_BE_HCI_WLAN_IO_ST);
|
||||
if (ret) {
|
||||
rtw89_err(rtwdev, "[ERR]Polling WLAN IO timeout= %X\n", val32);
|
||||
return ret;
|
||||
}
|
||||
|
||||
rtw89_write32_clr(rtwdev, R_BE_SYS_PW_CTRL, B_BE_EN_WLON);
|
||||
rtw89_write32_clr(rtwdev, R_BE_SYS_PW_CTRL, B_BE_APFM_SWLPS);
|
||||
} else if (val32 == MAC_AX_MAC_ON) {
|
||||
rtw89_write32_clr(rtwdev, R_BE_HCI_OPT_CTRL, B_BE_HAXIDMA_IO_EN);
|
||||
|
||||
ret = read_poll_timeout(rtw89_read32_mask, val32, !val32,
|
||||
1000, 2000000, false,
|
||||
rtwdev, R_BE_HCI_OPT_CTRL,
|
||||
B_BE_HAXIDMA_IO_ST | B_BE_HAXIDMA_BACKUP_RESTORE_ST);
|
||||
if (ret) {
|
||||
rtw89_err(rtwdev, "[ERR]Polling HAXI IO timeout= %X\n", val32);
|
||||
return ret;
|
||||
}
|
||||
|
||||
rtw89_write32_clr(rtwdev, R_BE_HCI_OPT_CTRL, B_BE_HCI_WLAN_IO_EN);
|
||||
|
||||
ret = read_poll_timeout(rtw89_read32_mask, val32, !val32,
|
||||
1000, 2000000, false,
|
||||
rtwdev, R_BE_HCI_OPT_CTRL, B_BE_HCI_WLAN_IO_ST);
|
||||
if (ret) {
|
||||
rtw89_err(rtwdev, "[ERR]Polling WLAN IO timeout= %X\n", val32);
|
||||
return ret;
|
||||
}
|
||||
|
||||
rtw89_write32_set(rtwdev, R_BE_SYS_PW_CTRL, B_BE_EN_WLON);
|
||||
rtw89_write32_set(rtwdev, R_BE_SYS_PW_CTRL, B_BE_APFM_OFFMAC);
|
||||
|
||||
ret = read_poll_timeout(rtw89_read32_mask, val32, val32 == MAC_AX_MAC_OFF,
|
||||
1000, 2000000, false,
|
||||
rtwdev, R_BE_SYS_PW_CTRL, B_BE_APFM_OFFMAC);
|
||||
if (ret) {
|
||||
rtw89_err(rtwdev, "[ERR]Polling MAC state timeout= %X\n", val32);
|
||||
return ret;
|
||||
}
|
||||
|
||||
rtw89_write32_clr(rtwdev, R_BE_SYS_PW_CTRL, B_BE_EN_WLON);
|
||||
rtw89_write32_clr(rtwdev, R_BE_SYS_PW_CTRL, B_BE_APFM_SWLPS);
|
||||
} else if (val32 == MAC_AX_MAC_LPS) {
|
||||
rtw89_write32_clr(rtwdev, R_BE_HCI_OPT_CTRL, B_BE_HAXIDMA_IO_EN);
|
||||
|
||||
ret = read_poll_timeout(rtw89_read32_mask, val32, !val32,
|
||||
1000, 2000000, false,
|
||||
rtwdev, R_BE_HCI_OPT_CTRL,
|
||||
B_BE_HAXIDMA_IO_ST | B_BE_HAXIDMA_BACKUP_RESTORE_ST);
|
||||
if (ret) {
|
||||
rtw89_err(rtwdev, "[ERR]Polling HAXI IO timeout= %X\n", val32);
|
||||
return ret;
|
||||
}
|
||||
|
||||
rtw89_write32_clr(rtwdev, R_BE_HCI_OPT_CTRL, B_BE_HCI_WLAN_IO_EN);
|
||||
|
||||
ret = read_poll_timeout(rtw89_read32_mask, val32, !val32,
|
||||
1000, 2000000, false,
|
||||
rtwdev, R_BE_HCI_OPT_CTRL, B_BE_HCI_WLAN_IO_ST);
|
||||
if (ret) {
|
||||
rtw89_err(rtwdev, "[ERR]Polling WLAN IO timeout= %X\n", val32);
|
||||
return ret;
|
||||
}
|
||||
|
||||
rtw89_write32_set(rtwdev, R_BE_WLLPS_CTRL, B_BE_FORCE_LEAVE_LPS);
|
||||
|
||||
ret = read_poll_timeout(rtw89_read32_mask, val32, val32 == MAC_AX_MAC_ON,
|
||||
1000, 2000000, false,
|
||||
rtwdev, R_BE_IC_PWR_STATE, B_BE_WLMAC_PWR_STE_MASK);
|
||||
if (ret) {
|
||||
rtw89_err(rtwdev, "[ERR]Polling MAC STS timeout= %X\n", val32);
|
||||
return ret;
|
||||
}
|
||||
|
||||
rtw89_write32_set(rtwdev, R_BE_SYS_PW_CTRL, B_BE_EN_WLON);
|
||||
rtw89_write32_set(rtwdev, R_BE_SYS_PW_CTRL, B_BE_APFM_OFFMAC);
|
||||
|
||||
ret = read_poll_timeout(rtw89_read32_mask, val32, val32 == MAC_AX_MAC_OFF,
|
||||
1000, 2000000, false,
|
||||
rtwdev, R_BE_SYS_PW_CTRL, B_BE_APFM_OFFMAC);
|
||||
if (ret) {
|
||||
rtw89_err(rtwdev, "[ERR]Polling MAC state timeout= %X\n", val32);
|
||||
return ret;
|
||||
}
|
||||
|
||||
rtw89_write32_clr(rtwdev, R_BE_WLLPS_CTRL, B_BE_FORCE_LEAVE_LPS);
|
||||
rtw89_write32_clr(rtwdev, R_BE_SYS_PW_CTRL, B_BE_EN_WLON);
|
||||
rtw89_write32_clr(rtwdev, R_BE_SYS_PW_CTRL, B_BE_APFM_SWLPS);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rtw89_mac_disable_cpu_be(struct rtw89_dev *rtwdev)
|
||||
{
|
||||
u32 val32;
|
||||
|
|
@ -2623,6 +2752,7 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_be = {
|
|||
.set_cpuio = set_cpuio_be,
|
||||
.dle_quota_change = dle_quota_change_be,
|
||||
|
||||
.reset_pwr_state = rtw89_mac_reset_pwr_state_be,
|
||||
.disable_cpu = rtw89_mac_disable_cpu_be,
|
||||
.fwdl_enable_wcpu = rtw89_mac_fwdl_enable_wcpu_be,
|
||||
.fwdl_get_status = fwdl_get_status_be,
|
||||
|
|
|
|||
|
|
@ -149,6 +149,7 @@
|
|||
#define R_AX_WLLPS_CTRL 0x0090
|
||||
#define B_AX_LPSOP_ASWRM BIT(17)
|
||||
#define B_AX_LPSOP_DSWRM BIT(9)
|
||||
#define B_AX_FORCE_LEAVE_LPS BIT(3)
|
||||
#define B_AX_DIS_WLBT_LPSEN_LOPC BIT(1)
|
||||
#define SW_LPS_OPTION 0x0001A0B2
|
||||
|
||||
|
|
@ -313,6 +314,9 @@
|
|||
#define R_AX_IC_PWR_STATE 0x03F0
|
||||
#define B_AX_WHOLE_SYS_PWR_STE_MASK GENMASK(25, 16)
|
||||
#define B_AX_WLMAC_PWR_STE_MASK GENMASK(9, 8)
|
||||
#define MAC_AX_MAC_OFF 0
|
||||
#define MAC_AX_MAC_ON 1
|
||||
#define MAC_AX_MAC_LPS 2
|
||||
#define B_AX_UART_HCISYS_PWR_STE_MASK GENMASK(7, 6)
|
||||
#define B_AX_SDIO_HCISYS_PWR_STE_MASK GENMASK(5, 4)
|
||||
#define B_AX_USB_HCISYS_PWR_STE_MASK GENMASK(3, 2)
|
||||
|
|
@ -2094,6 +2098,7 @@
|
|||
#define B_AX_B1_ISR_ERR_USRCTL_REINIT BIT(0)
|
||||
|
||||
#define R_AX_AFE_CTRL1 0x0024
|
||||
#define B_AX_CMAC_CLK_SEL BIT(21)
|
||||
|
||||
#define B_AX_R_SYM_WLCMAC1_P4_PC_EN BIT(4)
|
||||
#define B_AX_R_SYM_WLCMAC1_P3_PC_EN BIT(3)
|
||||
|
|
@ -2107,6 +2112,12 @@
|
|||
#define B_AX_R_SYM_FEN_WLBBFUN_1 BIT(16)
|
||||
#define B_AX_R_SYM_ISO_CMAC12PP BIT(5)
|
||||
|
||||
#define R_AX_SYSON_FSM_MON 0x00A0
|
||||
#define B_AX_FSM_MON_SEL_MASK GENMASK(26, 24)
|
||||
#define B_AX_DOP_ELDO BIT(23)
|
||||
#define B_AX_FSM_MON_UPD BIT(15)
|
||||
#define B_AX_FSM_PAR_MASK GENMASK(14, 0)
|
||||
|
||||
#define R_AX_CMAC_REG_START 0xC000
|
||||
|
||||
#define R_AX_CMAC_FUNC_EN 0xC000
|
||||
|
|
@ -4172,6 +4183,22 @@
|
|||
#define B_BE_LPSROP_LOWPWRPLL BIT(7)
|
||||
#define B_BE_LPSROP_DSWRSD_SEL_MASK GENMASK(5, 4)
|
||||
|
||||
#define R_BE_SYSON_FSM_MON 0x00A0
|
||||
#define B_BE_FSM_MON_SEL_MASK GENMASK(26, 24)
|
||||
#define B_BE_DOP_ELDO BIT(23)
|
||||
#define B_BE_AFE_PLL_BYPASS BIT(22)
|
||||
#define B_BE_PON_SWR_BYPASS BIT(21)
|
||||
#define B_BE_PON_ADIE_BYPASS BIT(20)
|
||||
#define B_BE_AFE_LS_BYPASS BIT(19)
|
||||
#define B_BE_BTPMC_XTAL_SI_BYPASS BIT(17)
|
||||
#define B_BE_WLPMC_XTAL_SI_BYPASS BIT(16)
|
||||
#define B_BE_FSM_MON_UPD BIT(15)
|
||||
#define B_BE_FSM_PAR_MASK GENMASK(14, 0)
|
||||
#define WLAN_FSM_MASK 0xFFFFFF
|
||||
#define WLAN_FSM_SET 0x4000000
|
||||
#define WLAN_FSM_STATE_MASK 0x1FF
|
||||
#define WLAN_FSM_IDLE 0
|
||||
|
||||
#define R_BE_EFUSE_CTRL_2_V1 0x00A4
|
||||
#define B_BE_EF_ENT BIT(31)
|
||||
#define B_BE_EF_TCOLUMN_EN BIT(29)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user