mt76: mt7915: add wifi subsystem reset

Reset wifi subsystem when MCU is already running.
Fixes firmware download failure after soft reboot on systems where the PCIe
reset could not be performed properly.

Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
Co-developed-by: Felix Fietkau <nbd@nbd.name>
Signed-off-by: Felix Fietkau <nbd@nbd.name>
This commit is contained in:
Ryder Lee 2021-04-06 12:46:09 +08:00 committed by Felix Fietkau
parent ac15f9b6da
commit e07419a7dc
3 changed files with 70 additions and 16 deletions

View File

@ -4,6 +4,7 @@
#include <linux/etherdevice.h>
#include "mt7915.h"
#include "mac.h"
#include "mcu.h"
#include "eeprom.h"
#define CCK_RATE(_idx, _rate) { \
@ -295,9 +296,50 @@ static void mt7915_init_work(struct work_struct *work)
mt7915_txbf_init(dev);
}
static void mt7915_wfsys_reset(struct mt7915_dev *dev)
{
u32 val = MT_TOP_PWR_KEY | MT_TOP_PWR_SW_PWR_ON | MT_TOP_PWR_PWR_ON;
u32 reg = mt7915_reg_map_l1(dev, MT_TOP_MISC);
#define MT_MCU_DUMMY_RANDOM GENMASK(15, 0)
#define MT_MCU_DUMMY_DEFAULT GENMASK(31, 16)
mt76_wr(dev, MT_MCU_WFDMA0_DUMMY_CR, MT_MCU_DUMMY_RANDOM);
/* change to software control */
val |= MT_TOP_PWR_SW_RST;
mt76_wr(dev, MT_TOP_PWR_CTRL, val);
/* reset wfsys */
val &= ~MT_TOP_PWR_SW_RST;
mt76_wr(dev, MT_TOP_PWR_CTRL, val);
/* release wfsys then mcu re-excutes romcode */
val |= MT_TOP_PWR_SW_RST;
mt76_wr(dev, MT_TOP_PWR_CTRL, val);
/* switch to hw control */
val &= ~MT_TOP_PWR_SW_RST;
val |= MT_TOP_PWR_HW_CTRL;
mt76_wr(dev, MT_TOP_PWR_CTRL, val);
/* check whether mcu resets to default */
if (!mt76_poll_msec(dev, MT_MCU_WFDMA0_DUMMY_CR, MT_MCU_DUMMY_DEFAULT,
MT_MCU_DUMMY_DEFAULT, 1000)) {
dev_err(dev->mt76.dev, "wifi subsystem reset failure\n");
return;
}
/* wfsys reset won't clear host registers */
mt76_clear(dev, reg, MT_TOP_MISC_FW_STATE);
msleep(100);
}
static int mt7915_init_hardware(struct mt7915_dev *dev)
{
int ret, idx;
u32 val;
mt76_wr(dev, MT_INT_SOURCE_CSR, ~0);
@ -307,6 +349,12 @@ static int mt7915_init_hardware(struct mt7915_dev *dev)
dev->dbdc_support = !!(mt7915_l1_rr(dev, MT_HW_BOUND) & BIT(5));
val = mt76_rr(dev, mt7915_reg_map_l1(dev, MT_TOP_MISC));
/* If MCU was already running, it is likely in a bad state */
if (FIELD_GET(MT_TOP_MISC_FW_STATE, val) > FW_STATE_FW_DOWNLOAD)
mt7915_wfsys_reset(dev);
ret = mt7915_dma_init(dev);
if (ret)
return ret;
@ -320,8 +368,14 @@ static int mt7915_init_hardware(struct mt7915_dev *dev)
mt76_wr(dev, MT_SWDEF_MODE, MT_SWDEF_NORMAL_MODE);
ret = mt7915_mcu_init(dev);
if (ret)
return ret;
if (ret) {
/* Reset and try again */
mt7915_wfsys_reset(dev);
ret = mt7915_mcu_init(dev);
if (ret)
return ret;
}
ret = mt7915_eeprom_init(dev);
if (ret < 0)

View File

@ -2784,21 +2784,8 @@ out:
static int mt7915_load_firmware(struct mt7915_dev *dev)
{
u32 reg = mt7915_reg_map_l1(dev, MT_TOP_MISC);
int ret;
u32 val, reg = mt7915_reg_map_l1(dev, MT_TOP_MISC);
val = FIELD_PREP(MT_TOP_MISC_FW_STATE, FW_STATE_FW_DOWNLOAD);
if (!mt76_poll_msec(dev, reg, MT_TOP_MISC_FW_STATE, val, 1000)) {
/* restart firmware once */
__mt76_mcu_restart(&dev->mt76);
if (!mt76_poll_msec(dev, reg, MT_TOP_MISC_FW_STATE,
val, 1000)) {
dev_err(dev->mt76.dev,
"Firmware is not ready for download\n");
return -EIO;
}
}
ret = mt7915_load_patch(dev);
if (ret)

View File

@ -4,6 +4,11 @@
#ifndef __MT7915_REGS_H
#define __MT7915_REGS_H
/* MCU WFDMA0 */
#define MT_MCU_WFDMA0_BASE 0x2000
#define MT_MCU_WFDMA0(ofs) (MT_MCU_WFDMA0_BASE + (ofs))
#define MT_MCU_WFDMA0_DUMMY_CR MT_MCU_WFDMA0(0x120)
/* MCU WFDMA1 */
#define MT_MCU_WFDMA1_BASE 0x3000
#define MT_MCU_WFDMA1(ofs) (MT_MCU_WFDMA1_BASE + (ofs))
@ -396,6 +401,14 @@
#define MT_WFDMA1_PCIE1_BUSY_ENA_TX_FIFO1 BIT(1)
#define MT_WFDMA1_PCIE1_BUSY_ENA_RX_FIFO BIT(2)
#define MT_TOP_RGU_BASE 0xf0000
#define MT_TOP_PWR_CTRL (MT_TOP_RGU_BASE + (0x0))
#define MT_TOP_PWR_KEY (0x5746 << 16)
#define MT_TOP_PWR_SW_RST BIT(0)
#define MT_TOP_PWR_SW_PWR_ON GENMASK(3, 2)
#define MT_TOP_PWR_HW_CTRL BIT(4)
#define MT_TOP_PWR_PWR_ON BIT(7)
#define MT_INFRA_CFG_BASE 0xf1000
#define MT_INFRA(ofs) (MT_INFRA_CFG_BASE + (ofs))