162306a36Sopenharmony_ci// SPDX-License-Identifier: ISC 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2022 MediaTek Inc. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/kernel.h> 762306a36Sopenharmony_ci#include <linux/module.h> 862306a36Sopenharmony_ci#include <linux/pci.h> 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include "mt7996.h" 1162306a36Sopenharmony_ci#include "mac.h" 1262306a36Sopenharmony_ci#include "../trace.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_cistatic const struct __base mt7996_reg_base[] = { 1562306a36Sopenharmony_ci [WF_AGG_BASE] = { { 0x820e2000, 0x820f2000, 0x830e2000 } }, 1662306a36Sopenharmony_ci [WF_ARB_BASE] = { { 0x820e3000, 0x820f3000, 0x830e3000 } }, 1762306a36Sopenharmony_ci [WF_TMAC_BASE] = { { 0x820e4000, 0x820f4000, 0x830e4000 } }, 1862306a36Sopenharmony_ci [WF_RMAC_BASE] = { { 0x820e5000, 0x820f5000, 0x830e5000 } }, 1962306a36Sopenharmony_ci [WF_DMA_BASE] = { { 0x820e7000, 0x820f7000, 0x830e7000 } }, 2062306a36Sopenharmony_ci [WF_WTBLOFF_BASE] = { { 0x820e9000, 0x820f9000, 0x830e9000 } }, 2162306a36Sopenharmony_ci [WF_ETBF_BASE] = { { 0x820ea000, 0x820fa000, 0x830ea000 } }, 2262306a36Sopenharmony_ci [WF_LPON_BASE] = { { 0x820eb000, 0x820fb000, 0x830eb000 } }, 2362306a36Sopenharmony_ci [WF_MIB_BASE] = { { 0x820ed000, 0x820fd000, 0x830ed000 } }, 2462306a36Sopenharmony_ci [WF_RATE_BASE] = { { 0x820ee000, 0x820fe000, 0x830ee000 } }, 2562306a36Sopenharmony_ci}; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic const struct __map mt7996_reg_map[] = { 2862306a36Sopenharmony_ci { 0x54000000, 0x02000, 0x1000 }, /* WFDMA_0 (PCIE0 MCU DMA0) */ 2962306a36Sopenharmony_ci { 0x55000000, 0x03000, 0x1000 }, /* WFDMA_1 (PCIE0 MCU DMA1) */ 3062306a36Sopenharmony_ci { 0x56000000, 0x04000, 0x1000 }, /* WFDMA reserved */ 3162306a36Sopenharmony_ci { 0x57000000, 0x05000, 0x1000 }, /* WFDMA MCU wrap CR */ 3262306a36Sopenharmony_ci { 0x58000000, 0x06000, 0x1000 }, /* WFDMA PCIE1 MCU DMA0 (MEM_DMA) */ 3362306a36Sopenharmony_ci { 0x59000000, 0x07000, 0x1000 }, /* WFDMA PCIE1 MCU DMA1 */ 3462306a36Sopenharmony_ci { 0x820c0000, 0x08000, 0x4000 }, /* WF_UMAC_TOP (PLE) */ 3562306a36Sopenharmony_ci { 0x820c8000, 0x0c000, 0x2000 }, /* WF_UMAC_TOP (PSE) */ 3662306a36Sopenharmony_ci { 0x820cc000, 0x0e000, 0x1000 }, /* WF_UMAC_TOP (PP) */ 3762306a36Sopenharmony_ci { 0x74030000, 0x10000, 0x1000 }, /* PCIe MAC */ 3862306a36Sopenharmony_ci { 0x820e0000, 0x20000, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_CFG) */ 3962306a36Sopenharmony_ci { 0x820e1000, 0x20400, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_TRB) */ 4062306a36Sopenharmony_ci { 0x820e2000, 0x20800, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_AGG) */ 4162306a36Sopenharmony_ci { 0x820e3000, 0x20c00, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_ARB) */ 4262306a36Sopenharmony_ci { 0x820e4000, 0x21000, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_TMAC) */ 4362306a36Sopenharmony_ci { 0x820e5000, 0x21400, 0x0800 }, /* WF_LMAC_TOP BN0 (WF_RMAC) */ 4462306a36Sopenharmony_ci { 0x820ce000, 0x21c00, 0x0200 }, /* WF_LMAC_TOP (WF_SEC) */ 4562306a36Sopenharmony_ci { 0x820e7000, 0x21e00, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_DMA) */ 4662306a36Sopenharmony_ci { 0x820cf000, 0x22000, 0x1000 }, /* WF_LMAC_TOP (WF_PF) */ 4762306a36Sopenharmony_ci { 0x820e9000, 0x23400, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_WTBLOFF) */ 4862306a36Sopenharmony_ci { 0x820ea000, 0x24000, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_ETBF) */ 4962306a36Sopenharmony_ci { 0x820eb000, 0x24200, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_LPON) */ 5062306a36Sopenharmony_ci { 0x820ec000, 0x24600, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_INT) */ 5162306a36Sopenharmony_ci { 0x820ed000, 0x24800, 0x0800 }, /* WF_LMAC_TOP BN0 (WF_MIB) */ 5262306a36Sopenharmony_ci { 0x820ca000, 0x26000, 0x2000 }, /* WF_LMAC_TOP BN0 (WF_MUCOP) */ 5362306a36Sopenharmony_ci { 0x820d0000, 0x30000, 0x10000 }, /* WF_LMAC_TOP (WF_WTBLON) */ 5462306a36Sopenharmony_ci { 0x40000000, 0x70000, 0x10000 }, /* WF_UMAC_SYSRAM */ 5562306a36Sopenharmony_ci { 0x00400000, 0x80000, 0x10000 }, /* WF_MCU_SYSRAM */ 5662306a36Sopenharmony_ci { 0x00410000, 0x90000, 0x10000 }, /* WF_MCU_SYSRAM (configure register) */ 5762306a36Sopenharmony_ci { 0x820f0000, 0xa0000, 0x0400 }, /* WF_LMAC_TOP BN1 (WF_CFG) */ 5862306a36Sopenharmony_ci { 0x820f1000, 0xa0600, 0x0200 }, /* WF_LMAC_TOP BN1 (WF_TRB) */ 5962306a36Sopenharmony_ci { 0x820f2000, 0xa0800, 0x0400 }, /* WF_LMAC_TOP BN1 (WF_AGG) */ 6062306a36Sopenharmony_ci { 0x820f3000, 0xa0c00, 0x0400 }, /* WF_LMAC_TOP BN1 (WF_ARB) */ 6162306a36Sopenharmony_ci { 0x820f4000, 0xa1000, 0x0400 }, /* WF_LMAC_TOP BN1 (WF_TMAC) */ 6262306a36Sopenharmony_ci { 0x820f5000, 0xa1400, 0x0800 }, /* WF_LMAC_TOP BN1 (WF_RMAC) */ 6362306a36Sopenharmony_ci { 0x820f7000, 0xa1e00, 0x0200 }, /* WF_LMAC_TOP BN1 (WF_DMA) */ 6462306a36Sopenharmony_ci { 0x820f9000, 0xa3400, 0x0200 }, /* WF_LMAC_TOP BN1 (WF_WTBLOFF) */ 6562306a36Sopenharmony_ci { 0x820fa000, 0xa4000, 0x0200 }, /* WF_LMAC_TOP BN1 (WF_ETBF) */ 6662306a36Sopenharmony_ci { 0x820fb000, 0xa4200, 0x0400 }, /* WF_LMAC_TOP BN1 (WF_LPON) */ 6762306a36Sopenharmony_ci { 0x820fc000, 0xa4600, 0x0200 }, /* WF_LMAC_TOP BN1 (WF_INT) */ 6862306a36Sopenharmony_ci { 0x820fd000, 0xa4800, 0x0800 }, /* WF_LMAC_TOP BN1 (WF_MIB) */ 6962306a36Sopenharmony_ci { 0x820cc000, 0xa5000, 0x2000 }, /* WF_LMAC_TOP BN1 (WF_MUCOP) */ 7062306a36Sopenharmony_ci { 0x820c4000, 0xa8000, 0x4000 }, /* WF_LMAC_TOP BN1 (WF_MUCOP) */ 7162306a36Sopenharmony_ci { 0x820b0000, 0xae000, 0x1000 }, /* [APB2] WFSYS_ON */ 7262306a36Sopenharmony_ci { 0x80020000, 0xb0000, 0x10000 }, /* WF_TOP_MISC_OFF */ 7362306a36Sopenharmony_ci { 0x81020000, 0xc0000, 0x10000 }, /* WF_TOP_MISC_ON */ 7462306a36Sopenharmony_ci { 0x7c020000, 0xd0000, 0x10000 }, /* CONN_INFRA, wfdma */ 7562306a36Sopenharmony_ci { 0x7c060000, 0xe0000, 0x10000 }, /* CONN_INFRA, conn_host_csr_top */ 7662306a36Sopenharmony_ci { 0x7c000000, 0xf0000, 0x10000 }, /* CONN_INFRA */ 7762306a36Sopenharmony_ci { 0x0, 0x0, 0x0 }, /* imply end of search */ 7862306a36Sopenharmony_ci}; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistatic u32 mt7996_reg_map_l1(struct mt7996_dev *dev, u32 addr) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci u32 offset = FIELD_GET(MT_HIF_REMAP_L1_OFFSET, addr); 8362306a36Sopenharmony_ci u32 base = FIELD_GET(MT_HIF_REMAP_L1_BASE, addr); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci dev->reg_l1_backup = dev->bus_ops->rr(&dev->mt76, MT_HIF_REMAP_L1); 8662306a36Sopenharmony_ci dev->bus_ops->rmw(&dev->mt76, MT_HIF_REMAP_L1, 8762306a36Sopenharmony_ci MT_HIF_REMAP_L1_MASK, 8862306a36Sopenharmony_ci FIELD_PREP(MT_HIF_REMAP_L1_MASK, base)); 8962306a36Sopenharmony_ci /* use read to push write */ 9062306a36Sopenharmony_ci dev->bus_ops->rr(&dev->mt76, MT_HIF_REMAP_L1); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci return MT_HIF_REMAP_BASE_L1 + offset; 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic u32 mt7996_reg_map_l2(struct mt7996_dev *dev, u32 addr) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci u32 offset = FIELD_GET(MT_HIF_REMAP_L2_OFFSET, addr); 9862306a36Sopenharmony_ci u32 base = FIELD_GET(MT_HIF_REMAP_L2_BASE, addr); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci dev->reg_l2_backup = dev->bus_ops->rr(&dev->mt76, MT_HIF_REMAP_L2); 10162306a36Sopenharmony_ci dev->bus_ops->rmw(&dev->mt76, MT_HIF_REMAP_L2, 10262306a36Sopenharmony_ci MT_HIF_REMAP_L2_MASK, 10362306a36Sopenharmony_ci FIELD_PREP(MT_HIF_REMAP_L2_MASK, base)); 10462306a36Sopenharmony_ci /* use read to push write */ 10562306a36Sopenharmony_ci dev->bus_ops->rr(&dev->mt76, MT_HIF_REMAP_L2); 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci return MT_HIF_REMAP_BASE_L2 + offset; 10862306a36Sopenharmony_ci} 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistatic void mt7996_reg_remap_restore(struct mt7996_dev *dev) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci /* remap to ori status */ 11362306a36Sopenharmony_ci if (unlikely(dev->reg_l1_backup)) { 11462306a36Sopenharmony_ci dev->bus_ops->wr(&dev->mt76, MT_HIF_REMAP_L1, dev->reg_l1_backup); 11562306a36Sopenharmony_ci dev->reg_l1_backup = 0; 11662306a36Sopenharmony_ci } 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci if (dev->reg_l2_backup) { 11962306a36Sopenharmony_ci dev->bus_ops->wr(&dev->mt76, MT_HIF_REMAP_L2, dev->reg_l2_backup); 12062306a36Sopenharmony_ci dev->reg_l2_backup = 0; 12162306a36Sopenharmony_ci } 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic u32 __mt7996_reg_addr(struct mt7996_dev *dev, u32 addr) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci int i; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci mt7996_reg_remap_restore(dev); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci if (addr < 0x100000) 13162306a36Sopenharmony_ci return addr; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci for (i = 0; i < dev->reg.map_size; i++) { 13462306a36Sopenharmony_ci u32 ofs; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci if (addr < dev->reg.map[i].phys) 13762306a36Sopenharmony_ci continue; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci ofs = addr - dev->reg.map[i].phys; 14062306a36Sopenharmony_ci if (ofs > dev->reg.map[i].size) 14162306a36Sopenharmony_ci continue; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci return dev->reg.map[i].mapped + ofs; 14462306a36Sopenharmony_ci } 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci if ((addr >= MT_INFRA_BASE && addr < MT_WFSYS0_PHY_START) || 14762306a36Sopenharmony_ci (addr >= MT_WFSYS0_PHY_START && addr < MT_WFSYS1_PHY_START) || 14862306a36Sopenharmony_ci (addr >= MT_WFSYS1_PHY_START && addr <= MT_WFSYS1_PHY_END)) 14962306a36Sopenharmony_ci return mt7996_reg_map_l1(dev, addr); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci if (dev_is_pci(dev->mt76.dev) && 15262306a36Sopenharmony_ci ((addr >= MT_CBTOP1_PHY_START && addr <= MT_CBTOP1_PHY_END) || 15362306a36Sopenharmony_ci addr >= MT_CBTOP2_PHY_START)) 15462306a36Sopenharmony_ci return mt7996_reg_map_l1(dev, addr); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci /* CONN_INFRA: covert to phyiscal addr and use layer 1 remap */ 15762306a36Sopenharmony_ci if (addr >= MT_INFRA_MCU_START && addr <= MT_INFRA_MCU_END) { 15862306a36Sopenharmony_ci addr = addr - MT_INFRA_MCU_START + MT_INFRA_BASE; 15962306a36Sopenharmony_ci return mt7996_reg_map_l1(dev, addr); 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci return mt7996_reg_map_l2(dev, addr); 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_civoid mt7996_memcpy_fromio(struct mt7996_dev *dev, void *buf, u32 offset, 16662306a36Sopenharmony_ci size_t len) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci u32 addr = __mt7996_reg_addr(dev, offset); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci memcpy_fromio(buf, dev->mt76.mmio.regs + addr, len); 17162306a36Sopenharmony_ci} 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_cistatic u32 mt7996_rr(struct mt76_dev *mdev, u32 offset) 17462306a36Sopenharmony_ci{ 17562306a36Sopenharmony_ci struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci return dev->bus_ops->rr(mdev, __mt7996_reg_addr(dev, offset)); 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_cistatic void mt7996_wr(struct mt76_dev *mdev, u32 offset, u32 val) 18162306a36Sopenharmony_ci{ 18262306a36Sopenharmony_ci struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci dev->bus_ops->wr(mdev, __mt7996_reg_addr(dev, offset), val); 18562306a36Sopenharmony_ci} 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_cistatic u32 mt7996_rmw(struct mt76_dev *mdev, u32 offset, u32 mask, u32 val) 18862306a36Sopenharmony_ci{ 18962306a36Sopenharmony_ci struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci return dev->bus_ops->rmw(mdev, __mt7996_reg_addr(dev, offset), mask, val); 19262306a36Sopenharmony_ci} 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_cistatic int mt7996_mmio_init(struct mt76_dev *mdev, 19562306a36Sopenharmony_ci void __iomem *mem_base, 19662306a36Sopenharmony_ci u32 device_id) 19762306a36Sopenharmony_ci{ 19862306a36Sopenharmony_ci struct mt76_bus_ops *bus_ops; 19962306a36Sopenharmony_ci struct mt7996_dev *dev; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci dev = container_of(mdev, struct mt7996_dev, mt76); 20262306a36Sopenharmony_ci mt76_mmio_init(&dev->mt76, mem_base); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci switch (device_id) { 20562306a36Sopenharmony_ci case 0x7990: 20662306a36Sopenharmony_ci dev->reg.base = mt7996_reg_base; 20762306a36Sopenharmony_ci dev->reg.map = mt7996_reg_map; 20862306a36Sopenharmony_ci dev->reg.map_size = ARRAY_SIZE(mt7996_reg_map); 20962306a36Sopenharmony_ci break; 21062306a36Sopenharmony_ci default: 21162306a36Sopenharmony_ci return -EINVAL; 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci dev->bus_ops = dev->mt76.bus; 21562306a36Sopenharmony_ci bus_ops = devm_kmemdup(dev->mt76.dev, dev->bus_ops, sizeof(*bus_ops), 21662306a36Sopenharmony_ci GFP_KERNEL); 21762306a36Sopenharmony_ci if (!bus_ops) 21862306a36Sopenharmony_ci return -ENOMEM; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci bus_ops->rr = mt7996_rr; 22162306a36Sopenharmony_ci bus_ops->wr = mt7996_wr; 22262306a36Sopenharmony_ci bus_ops->rmw = mt7996_rmw; 22362306a36Sopenharmony_ci dev->mt76.bus = bus_ops; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci mdev->rev = (device_id << 16) | (mt76_rr(dev, MT_HW_REV) & 0xff); 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci dev_dbg(mdev->dev, "ASIC revision: %04x\n", mdev->rev); 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci return 0; 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_civoid mt7996_dual_hif_set_irq_mask(struct mt7996_dev *dev, bool write_reg, 23362306a36Sopenharmony_ci u32 clear, u32 set) 23462306a36Sopenharmony_ci{ 23562306a36Sopenharmony_ci struct mt76_dev *mdev = &dev->mt76; 23662306a36Sopenharmony_ci unsigned long flags; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci spin_lock_irqsave(&mdev->mmio.irq_lock, flags); 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci mdev->mmio.irqmask &= ~clear; 24162306a36Sopenharmony_ci mdev->mmio.irqmask |= set; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci if (write_reg) { 24462306a36Sopenharmony_ci mt76_wr(dev, MT_INT_MASK_CSR, mdev->mmio.irqmask); 24562306a36Sopenharmony_ci mt76_wr(dev, MT_INT1_MASK_CSR, mdev->mmio.irqmask); 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci spin_unlock_irqrestore(&mdev->mmio.irq_lock, flags); 24962306a36Sopenharmony_ci} 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_cistatic void mt7996_rx_poll_complete(struct mt76_dev *mdev, 25262306a36Sopenharmony_ci enum mt76_rxq_id q) 25362306a36Sopenharmony_ci{ 25462306a36Sopenharmony_ci struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci mt7996_irq_enable(dev, MT_INT_RX(q)); 25762306a36Sopenharmony_ci} 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci/* TODO: support 2/4/6/8 MSI-X vectors */ 26062306a36Sopenharmony_cistatic void mt7996_irq_tasklet(struct tasklet_struct *t) 26162306a36Sopenharmony_ci{ 26262306a36Sopenharmony_ci struct mt7996_dev *dev = from_tasklet(dev, t, mt76.irq_tasklet); 26362306a36Sopenharmony_ci u32 i, intr, mask, intr1; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci mt76_wr(dev, MT_INT_MASK_CSR, 0); 26662306a36Sopenharmony_ci if (dev->hif2) 26762306a36Sopenharmony_ci mt76_wr(dev, MT_INT1_MASK_CSR, 0); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci intr = mt76_rr(dev, MT_INT_SOURCE_CSR); 27062306a36Sopenharmony_ci intr &= dev->mt76.mmio.irqmask; 27162306a36Sopenharmony_ci mt76_wr(dev, MT_INT_SOURCE_CSR, intr); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci if (dev->hif2) { 27462306a36Sopenharmony_ci intr1 = mt76_rr(dev, MT_INT1_SOURCE_CSR); 27562306a36Sopenharmony_ci intr1 &= dev->mt76.mmio.irqmask; 27662306a36Sopenharmony_ci mt76_wr(dev, MT_INT1_SOURCE_CSR, intr1); 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci intr |= intr1; 27962306a36Sopenharmony_ci } 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci trace_dev_irq(&dev->mt76, intr, dev->mt76.mmio.irqmask); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci mask = intr & MT_INT_RX_DONE_ALL; 28462306a36Sopenharmony_ci if (intr & MT_INT_TX_DONE_MCU) 28562306a36Sopenharmony_ci mask |= MT_INT_TX_DONE_MCU; 28662306a36Sopenharmony_ci mt7996_irq_disable(dev, mask); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci if (intr & MT_INT_TX_DONE_MCU) 28962306a36Sopenharmony_ci napi_schedule(&dev->mt76.tx_napi); 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci for (i = 0; i < __MT_RXQ_MAX; i++) { 29262306a36Sopenharmony_ci if ((intr & MT_INT_RX(i))) 29362306a36Sopenharmony_ci napi_schedule(&dev->mt76.napi[i]); 29462306a36Sopenharmony_ci } 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci if (intr & MT_INT_MCU_CMD) { 29762306a36Sopenharmony_ci u32 val = mt76_rr(dev, MT_MCU_CMD); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci mt76_wr(dev, MT_MCU_CMD, val); 30062306a36Sopenharmony_ci if (val & (MT_MCU_CMD_ERROR_MASK | MT_MCU_CMD_WDT_MASK)) { 30162306a36Sopenharmony_ci dev->recovery.state = val; 30262306a36Sopenharmony_ci mt7996_reset(dev); 30362306a36Sopenharmony_ci } 30462306a36Sopenharmony_ci } 30562306a36Sopenharmony_ci} 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ciirqreturn_t mt7996_irq_handler(int irq, void *dev_instance) 30862306a36Sopenharmony_ci{ 30962306a36Sopenharmony_ci struct mt7996_dev *dev = dev_instance; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci mt76_wr(dev, MT_INT_MASK_CSR, 0); 31262306a36Sopenharmony_ci if (dev->hif2) 31362306a36Sopenharmony_ci mt76_wr(dev, MT_INT1_MASK_CSR, 0); 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state)) 31662306a36Sopenharmony_ci return IRQ_NONE; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci tasklet_schedule(&dev->mt76.irq_tasklet); 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci return IRQ_HANDLED; 32162306a36Sopenharmony_ci} 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_cistruct mt7996_dev *mt7996_mmio_probe(struct device *pdev, 32462306a36Sopenharmony_ci void __iomem *mem_base, u32 device_id) 32562306a36Sopenharmony_ci{ 32662306a36Sopenharmony_ci static const struct mt76_driver_ops drv_ops = { 32762306a36Sopenharmony_ci /* txwi_size = txd size + txp size */ 32862306a36Sopenharmony_ci .txwi_size = MT_TXD_SIZE + sizeof(struct mt76_connac_fw_txp), 32962306a36Sopenharmony_ci .drv_flags = MT_DRV_TXWI_NO_FREE | 33062306a36Sopenharmony_ci MT_DRV_AMSDU_OFFLOAD | 33162306a36Sopenharmony_ci MT_DRV_HW_MGMT_TXQ, 33262306a36Sopenharmony_ci .survey_flags = SURVEY_INFO_TIME_TX | 33362306a36Sopenharmony_ci SURVEY_INFO_TIME_RX | 33462306a36Sopenharmony_ci SURVEY_INFO_TIME_BSS_RX, 33562306a36Sopenharmony_ci .token_size = MT7996_TOKEN_SIZE, 33662306a36Sopenharmony_ci .tx_prepare_skb = mt7996_tx_prepare_skb, 33762306a36Sopenharmony_ci .tx_complete_skb = mt76_connac_tx_complete_skb, 33862306a36Sopenharmony_ci .rx_skb = mt7996_queue_rx_skb, 33962306a36Sopenharmony_ci .rx_check = mt7996_rx_check, 34062306a36Sopenharmony_ci .rx_poll_complete = mt7996_rx_poll_complete, 34162306a36Sopenharmony_ci .sta_add = mt7996_mac_sta_add, 34262306a36Sopenharmony_ci .sta_remove = mt7996_mac_sta_remove, 34362306a36Sopenharmony_ci .update_survey = mt7996_update_channel, 34462306a36Sopenharmony_ci }; 34562306a36Sopenharmony_ci struct mt7996_dev *dev; 34662306a36Sopenharmony_ci struct mt76_dev *mdev; 34762306a36Sopenharmony_ci int ret; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci mdev = mt76_alloc_device(pdev, sizeof(*dev), &mt7996_ops, &drv_ops); 35062306a36Sopenharmony_ci if (!mdev) 35162306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci dev = container_of(mdev, struct mt7996_dev, mt76); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci ret = mt7996_mmio_init(mdev, mem_base, device_id); 35662306a36Sopenharmony_ci if (ret) 35762306a36Sopenharmony_ci goto error; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci tasklet_setup(&mdev->irq_tasklet, mt7996_irq_tasklet); 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci mt76_wr(dev, MT_INT_MASK_CSR, 0); 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci return dev; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_cierror: 36662306a36Sopenharmony_ci mt76_free_device(&dev->mt76); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci return ERR_PTR(ret); 36962306a36Sopenharmony_ci} 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_cistatic int __init mt7996_init(void) 37262306a36Sopenharmony_ci{ 37362306a36Sopenharmony_ci int ret; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci ret = pci_register_driver(&mt7996_hif_driver); 37662306a36Sopenharmony_ci if (ret) 37762306a36Sopenharmony_ci return ret; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci ret = pci_register_driver(&mt7996_pci_driver); 38062306a36Sopenharmony_ci if (ret) 38162306a36Sopenharmony_ci pci_unregister_driver(&mt7996_hif_driver); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci return ret; 38462306a36Sopenharmony_ci} 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_cistatic void __exit mt7996_exit(void) 38762306a36Sopenharmony_ci{ 38862306a36Sopenharmony_ci pci_unregister_driver(&mt7996_pci_driver); 38962306a36Sopenharmony_ci pci_unregister_driver(&mt7996_hif_driver); 39062306a36Sopenharmony_ci} 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_cimodule_init(mt7996_init); 39362306a36Sopenharmony_cimodule_exit(mt7996_exit); 39462306a36Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 395