Add MT7927-specific hardware initialization for the Filogic 380 combo chip, which has an additional CBInfra (ConnectaBus Infrastructure) bus fabric between PCIe and the WiFi subsystem. CBTOP remap: configure PCIe address mapping so MMIO reads to WiFi registers return valid data instead of zero. Chip initialization sequence: 1. WF subsystem reset via CBInfra RGU 2. MCU ownership acquisition 3. Poll ROMCODE_INDEX for MCU idle (0x1D1E) 4. MCIF remap for host DMA 5. PCIe sleep disable Probe flow changes for MT7927: - Skip early CLR_OWN (CBTOP not yet configured) - Force chip ID if CHIPID register returns stale value - Replace wfsys_reset with mt7927_chip_init CLR_OWN skip in mt7925e_mcu_init(): every CLR_OWN triggers the ROM to reinitialize WFDMA, destroying ring configuration set up by DMA init. The controlled SET_OWN/CLR_OWN is already handled in the DMA pre-ring setup hook. DBDC enable: MT7927 firmware defaults to single-band (2.4GHz only). Send explicit SET_DBDC_PARMS to enable dual-band operation. CNM force: MT7927 firmware lacks the connac2 feature trailer, causing channel context ops to be replaced with stubs. Force the CNM flag at probe to preserve ROC support needed for authentication. mac_reset guard: return -EOPNOTSUPP for MT7927 since the reset path performs CLR_OWN and logic reset that destroy DMA configuration. Full reset recovery is follow-up work. Register values derived from Loong0x00's reverse-engineered MT7927 driver. Reported-by: 张旭涵 Closes: https://github.com/openwrt/mt76/issues/927 Tested-by: Marcin FM Tested-by: Cristian-Florin Radoi Tested-by: George Salukvadze Tested-by: Evgeny Kapusta <3193631@gmail.com> Tested-by: Samu Toljamo Tested-by: Ariel Rosenfeld Tested-by: Chapuis Dario Tested-by: Thibaut François Tested-by: 张旭涵 Signed-off-by: Javier Tia --- drivers/net/wireless/mediatek/mt76/mt7925/init.c | 13 +++ drivers/net/wireless/mediatek/mt76/mt7925/pci.c | 103 +++++++++++++++++++-- .../net/wireless/mediatek/mt76/mt7925/pci_mac.c | 9 ++ .../net/wireless/mediatek/mt76/mt7925/pci_mcu.c | 20 ++-- drivers/net/wireless/mediatek/mt76/mt792x_regs.h | 18 ++++ 5 files changed, 149 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/init.c b/drivers/net/wireless/mediatek/mt76/mt7925/init.c index 3ce5d6fcc69d..c4c99380f5b5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/init.c @@ -115,6 +115,19 @@ static int __mt7925_init_hardware(struct mt792x_dev *dev) if (ret) goto out; + /* MT7927: Enable DBDC (dual-band) mode. Without this, firmware + * defaults to 2.4GHz only and ignores 5GHz scan requests. + * MT7925 firmware handles DBDC automatically. + */ + if (is_mt7927(&dev->mt76)) { + ret = mt7925_mcu_set_dbdc(&dev->mphy, true); + if (ret) { + dev_warn(dev->mt76.dev, + "MT7927 DBDC enable failed: %d\n", ret); + ret = 0; + } + } + out: return ret; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c index 415194a440f8..393d9f408b84 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c @@ -400,6 +400,64 @@ static const struct mt792x_irq_map mt7927_irq_map = { .wm2_complete_mask = MT7927_RX_DONE_INT_ENA7, }, }; + +static int mt7927_chip_init(struct mt792x_dev *dev) +{ + struct mt76_dev *mdev = &dev->mt76; + u32 val; + + /* EMI sleep protect */ + mt76_rmw_field(dev, MT_HW_EMI_CTL, MT_HW_EMI_CTL_SLPPROT_EN, 1); + + /* WF subsystem reset via CBInfra RGU */ + mt76_set(dev, MT7927_CBINFRA_RGU_WF_RST, + MT7927_CBINFRA_RGU_WF_RST_WF_SUBSYS); + msleep(1); + mt76_clear(dev, MT7927_CBINFRA_RGU_WF_RST, + MT7927_CBINFRA_RGU_WF_RST_WF_SUBSYS); + msleep(5); + + /* MCU ownership */ + mt76_wr(dev, MT7927_CBINFRA_MCU_OWN_SET, BIT(0)); + + /* Poll ROMCODE_INDEX for MCU idle */ + if (!__mt76_poll_msec(mdev, MT7927_ROMCODE_INDEX, + 0xffff, MT7927_MCU_IDLE_VALUE, 2000)) { + val = mt76_rr(dev, MT7927_ROMCODE_INDEX); + dev_err(mdev->dev, + "MT7927 MCU idle timeout (ROMCODE_INDEX=0x%04x)\n", + val & 0xffff); + return -ETIMEDOUT; + } + + /* MCIF remap - MCU needs this to DMA to host memory */ + mt76_wr(dev, MT7927_MCIF_REMAP_WF_1_BA, + MT7927_MCIF_REMAP_WF_1_BA_VAL); + + /* Disable PCIe sleep */ + mt76_wr(dev, MT7927_CBINFRA_SLP_CTRL, 0xffffffff); + + /* Clear CONNINFRA wakeup */ + mt76_wr(dev, MT7927_CBINFRA_WAKEPU_TOP, 0x0); + + return 0; +} + +static void mt7927_cbtop_remap(struct mt792x_dev *dev) +{ + /* CONNINFRA wakeup - required before CBInfra register access */ + mt76_wr(dev, MT7927_CBINFRA_WAKEPU_TOP, 0x1); + usleep_range(1000, 2000); + + /* Configure CBTOP PCIe address remap for WF and BT */ + mt76_wr(dev, MT7927_CBINFRA_MISC0_REMAP_WF, + MT7927_CBINFRA_REMAP_WF_VAL); + mt76_wr(dev, MT7927_CBINFRA_MISC0_REMAP_BT, + MT7927_CBINFRA_REMAP_BT_VAL); + + /* Readback to push writes */ + mt76_rr(dev, MT7927_CBINFRA_MISC0_REMAP_WF); +} static int mt7925_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { @@ -482,6 +540,17 @@ static int mt7925_pci_probe(struct pci_dev *pdev, goto err_free_pci_vec; } + /* MT7927 firmware lacks the connac2 feature trailer, so + * mt792x_get_mac80211_ops() can't detect CNM support and + * replaces chanctx/ROC/mgd_prepare_tx ops with stubs. + * Force CNM and restore the original mt7925 ops. + */ + if ((pdev->device == 0x6639 || pdev->device == 0x7927) && + !(features & MT792x_FW_CAP_CNM)) { + features |= MT792x_FW_CAP_CNM; + memcpy(ops, &mt7925_ops, sizeof(*ops)); + } + mdev = mt76_alloc_device(&pdev->dev, sizeof(*dev), ops, &drv_ops); if (!mdev) { ret = -ENOMEM; @@ -517,25 +586,43 @@ static int mt7925_pci_probe(struct pci_dev *pdev, if (!mt7925_disable_aspm && mt76_pci_aspm_supported(pdev)) dev->aspm_supported = true; - ret = __mt792x_mcu_fw_pmctrl(dev); if (ret) goto err_free_dev; - ret = __mt792xe_mcu_drv_pmctrl(dev); - if (ret) - goto err_free_dev; + if (!is_mt7927_hw) { + ret = __mt792xe_mcu_drv_pmctrl(dev); + if (ret) + goto err_free_dev; + } + + if (is_mt7927_hw) + mt7927_cbtop_remap(dev); mdev->rev = (mt76_rr(dev, MT_HW_CHIPID) << 16) | (mt76_rr(dev, MT_HW_REV) & 0xff); dev_info(mdev->dev, "ASIC revision: %04x\n", mdev->rev); - mt76_rmw_field(dev, MT_HW_EMI_CTL, MT_HW_EMI_CTL_SLPPROT_EN, 1); + /* Force chip ID for MT7927 hardware if CHIPID read returns garbage */ + if (is_mt7927_hw && (mdev->rev >> 16) != 0x7927) { + dev_info(mdev->dev, + "MT7927 raw CHIPID=0x%04x, forcing chip=0x7927\n", + (u16)(mdev->rev >> 16)); + mdev->rev = (0x7927 << 16) | (mdev->rev & 0xff); + } - ret = mt792x_wfsys_reset(dev); - if (ret) - goto err_free_dev; + if (is_mt7927_hw) { + ret = mt7927_chip_init(dev); + if (ret) + goto err_free_dev; + } else { + mt76_rmw_field(dev, MT_HW_EMI_CTL, + MT_HW_EMI_CTL_SLPPROT_EN, 1); + ret = mt792x_wfsys_reset(dev); + if (ret) + goto err_free_dev; + } mt76_wr(dev, irq_map.host_irq_enable, 0); diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt7925/pci_mac.c index 1626a3684082..9b3eeb1328f6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/pci_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/pci_mac.c @@ -72,6 +72,15 @@ int mt7925e_mac_reset(struct mt792x_dev *dev) const struct mt792x_irq_map *irq_map = dev->irq_map; int i, err; + /* MT7927: CLR_OWN and WPDMA reset destroy DMA ring configuration. + * A full reset requires re-running mt7927_dma_init() which is not + * yet implemented in the recovery path. + */ + if (is_mt7927(&dev->mt76)) { + dev_warn(dev->mt76.dev, "MT7927 mac_reset not supported, reload module to recover\n"); + return -EOPNOTSUPP; + } + mt792xe_mcu_drv_pmctrl(dev); mt76_connac_free_pending_tx_skbs(&dev->pm, NULL); diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/pci_mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/pci_mcu.c index 6cceff88c656..1f50d1ef6fb6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/pci_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/pci_mcu.c @@ -35,13 +35,21 @@ int mt7925e_mcu_init(struct mt792x_dev *dev) dev->mt76.mcu_ops = &mt7925_mcu_ops; - err = mt792xe_mcu_fw_pmctrl(dev); - if (err) - return err; + if (is_mt7927(&dev->mt76)) { + /* MT7927: CLR_OWN was already done in mt7927_dma_init(). + * The ROM re-initializes WFDMA on every CLR_OWN, wiping + * ring and prefetch config. Skip SET_OWN/CLR_OWN here + * to preserve DMA state. + */ + } else { + err = mt792xe_mcu_fw_pmctrl(dev); + if (err) + return err; - err = __mt792xe_mcu_drv_pmctrl(dev); - if (err) - return err; + err = __mt792xe_mcu_drv_pmctrl(dev); + if (err) + return err; + } mt76_rmw_field(dev, MT_PCIE_MAC_PM, MT_PCIE_MAC_PM_L0S_DIS, 1); diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_regs.h b/drivers/net/wireless/mediatek/mt76/mt792x_regs.h index 1b9b51d43f79..9c4bbbe898f3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x_regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt792x_regs.h @@ -499,4 +499,22 @@ #define WFSYS_SW_RST_B BIT(0) #define WFSYS_SW_INIT_DONE BIT(4) +/* CBInfra registers - MT7927 combo chip */ +#define MT7927_CBINFRA_WAKEPU_TOP 0xe01a0 +#define MT7927_CBINFRA_MISC0_REMAP_WF 0x1f6554 +#define MT7927_CBINFRA_MISC0_REMAP_BT 0x1f6558 +#define MT7927_CBINFRA_RGU_WF_RST 0x1f8600 +#define MT7927_CBINFRA_RGU_WF_RST_WF_SUBSYS BIT(4) +#define MT7927_CBINFRA_MCU_OWN_SET 0x1f5034 +#define MT7927_CBINFRA_SLP_CTRL 0x1f5018 +#define MT7927_ROMCODE_INDEX 0xc1604 +#define MT7927_MCU_IDLE_VALUE 0x1d1e +#define MT7927_MCIF_REMAP_WF_1_BA 0xd1034 + +/* CBInfra CBTOP remap values */ +#define MT7927_CBINFRA_REMAP_WF_VAL 0x74037001 +#define MT7927_CBINFRA_REMAP_BT_VAL 0x70007000 + +#define MT7927_MCIF_REMAP_WF_1_BA_VAL 0x18051803 + #endif /* __MT792X_REGS_H */ -- 2.53.0