Commit e07419a7 authored by Ryder Lee's avatar Ryder Lee Committed by Felix Fietkau
Browse files

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: default avatarRyder Lee <ryder.lee@mediatek.com>
Co-developed-by: default avatarFelix Fietkau <nbd@nbd.name>
Signed-off-by: default avatarFelix Fietkau <nbd@nbd.name>
parent ac15f9b6
Loading
Loading
Loading
Loading
+56 −2
Original line number Diff line number Diff line
@@ -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;
@@ -319,9 +367,15 @@ 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) {
		/* 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)
+1 −14
Original line number Diff line number Diff line
@@ -2784,21 +2784,8 @@ static int mt7915_load_ram(struct mt7915_dev *dev)

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)
+13 −0
Original line number Diff line number Diff line
@@ -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))