15c14a5f9SSean Wang // SPDX-License-Identifier: ISC
25c14a5f9SSean Wang /* Copyright (C) 2020 MediaTek Inc.
35c14a5f9SSean Wang *
45c14a5f9SSean Wang */
55c14a5f9SSean Wang
65c14a5f9SSean Wang #include <linux/kernel.h>
75c14a5f9SSean Wang #include <linux/module.h>
85c14a5f9SSean Wang #include <linux/pci.h>
95c14a5f9SSean Wang
105c14a5f9SSean Wang #include "mt7921.h"
11140efef3SLorenzo Bianconi #include "../mt76_connac2_mac.h"
122e7f7a2cSLorenzo Bianconi #include "../dma.h"
1367aa2743SLorenzo Bianconi #include "mcu.h"
145c14a5f9SSean Wang
155c14a5f9SSean Wang static const struct pci_device_id mt7921_pci_device_table[] = {
16034ae28bSSean Wang { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7961),
17034ae28bSSean Wang .driver_data = (kernel_ulong_t)MT7921_FIRMWARE_WM },
18034ae28bSSean Wang { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7922),
19034ae28bSSean Wang .driver_data = (kernel_ulong_t)MT7922_FIRMWARE_WM },
208943a6d1SIngo Rohloff { PCI_DEVICE(PCI_VENDOR_ID_ITTIM, 0x7922),
218943a6d1SIngo Rohloff .driver_data = (kernel_ulong_t)MT7922_FIRMWARE_WM },
22034ae28bSSean Wang { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x0608),
23034ae28bSSean Wang .driver_data = (kernel_ulong_t)MT7921_FIRMWARE_WM },
24034ae28bSSean Wang { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x0616),
25eb85df0aSLorenzo Bianconi .driver_data = (kernel_ulong_t)MT7922_FIRMWARE_WM },
265c14a5f9SSean Wang { },
275c14a5f9SSean Wang };
285c14a5f9SSean Wang
29bf3747aeSSean Wang static bool mt7921_disable_aspm;
30bf3747aeSSean Wang module_param_named(disable_aspm, mt7921_disable_aspm, bool, 0644);
31bf3747aeSSean Wang MODULE_PARM_DESC(disable_aspm, "disable PCI ASPM support");
32bf3747aeSSean Wang
mt7921e_init_reset(struct mt792x_dev * dev)33975e122dSLorenzo Bianconi static int mt7921e_init_reset(struct mt792x_dev *dev)
34033ae79bSSean Wang {
35ff655174SLorenzo Bianconi return mt792x_wpdma_reset(dev, true);
36033ae79bSSean Wang }
37033ae79bSSean Wang
mt7921e_unregister_device(struct mt792x_dev * dev)38975e122dSLorenzo Bianconi static void mt7921e_unregister_device(struct mt792x_dev *dev)
39033ae79bSSean Wang {
40033ae79bSSean Wang int i;
41033ae79bSSean Wang struct mt76_connac_pm *pm = &dev->pm;
42033ae79bSSean Wang
431c71e03aSLorenzo Bianconi cancel_work_sync(&dev->init_work);
44033ae79bSSean Wang mt76_unregister_device(&dev->mt76);
45033ae79bSSean Wang mt76_for_each_q_rx(&dev->mt76, i)
46033ae79bSSean Wang napi_disable(&dev->mt76.napi[i]);
47033ae79bSSean Wang cancel_delayed_work_sync(&pm->ps_work);
48033ae79bSSean Wang cancel_work_sync(&pm->wake_work);
493d78c464SQuan Zhou cancel_work_sync(&dev->reset_work);
50033ae79bSSean Wang
51c8e370feSLorenzo Bianconi mt76_connac2_tx_token_put(&dev->mt76);
525c041325SLorenzo Bianconi __mt792x_mcu_drv_pmctrl(dev);
53c693f2f0SLorenzo Bianconi mt792x_dma_cleanup(dev);
54ff655174SLorenzo Bianconi mt792x_wfsys_reset(dev);
5556054087SLorenzo Bianconi skb_queue_purge(&dev->mt76.mcu.res_q);
56033ae79bSSean Wang
57ec193b41SLorenzo Bianconi tasklet_disable(&dev->mt76.irq_tasklet);
58033ae79bSSean Wang }
59033ae79bSSean Wang
__mt7921_reg_addr(struct mt792x_dev * dev,u32 addr)60975e122dSLorenzo Bianconi static u32 __mt7921_reg_addr(struct mt792x_dev *dev, u32 addr)
61602cc0c9SSean Wang {
62e351f4f0SLorenzo Bianconi static const struct mt76_connac_reg_map fixed_map[] = {
63602cc0c9SSean Wang { 0x820d0000, 0x30000, 0x10000 }, /* WF_LMAC_TOP (WF_WTBLON) */
64e351f4f0SLorenzo Bianconi { 0x820ed000, 0x24800, 0x00800 }, /* WF_LMAC_TOP BN0 (WF_MIB) */
65e351f4f0SLorenzo Bianconi { 0x820e4000, 0x21000, 0x00400 }, /* WF_LMAC_TOP BN0 (WF_TMAC) */
66e351f4f0SLorenzo Bianconi { 0x820e7000, 0x21e00, 0x00200 }, /* WF_LMAC_TOP BN0 (WF_DMA) */
67e351f4f0SLorenzo Bianconi { 0x820eb000, 0x24200, 0x00400 }, /* WF_LMAC_TOP BN0 (WF_LPON) */
68e351f4f0SLorenzo Bianconi { 0x820e2000, 0x20800, 0x00400 }, /* WF_LMAC_TOP BN0 (WF_AGG) */
69e351f4f0SLorenzo Bianconi { 0x820e3000, 0x20c00, 0x00400 }, /* WF_LMAC_TOP BN0 (WF_ARB) */
70e351f4f0SLorenzo Bianconi { 0x820e5000, 0x21400, 0x00800 }, /* WF_LMAC_TOP BN0 (WF_RMAC) */
71602cc0c9SSean Wang { 0x00400000, 0x80000, 0x10000 }, /* WF_MCU_SYSRAM */
72602cc0c9SSean Wang { 0x00410000, 0x90000, 0x10000 }, /* WF_MCU_SYSRAM (configure register) */
73602cc0c9SSean Wang { 0x40000000, 0x70000, 0x10000 }, /* WF_UMAC_SYSRAM */
74e351f4f0SLorenzo Bianconi { 0x54000000, 0x02000, 0x01000 }, /* WFDMA PCIE0 MCU DMA0 */
75e351f4f0SLorenzo Bianconi { 0x55000000, 0x03000, 0x01000 }, /* WFDMA PCIE0 MCU DMA1 */
76e351f4f0SLorenzo Bianconi { 0x58000000, 0x06000, 0x01000 }, /* WFDMA PCIE1 MCU DMA0 (MEM_DMA) */
77e351f4f0SLorenzo Bianconi { 0x59000000, 0x07000, 0x01000 }, /* WFDMA PCIE1 MCU DMA1 */
78602cc0c9SSean Wang { 0x7c000000, 0xf0000, 0x10000 }, /* CONN_INFRA */
79602cc0c9SSean Wang { 0x7c020000, 0xd0000, 0x10000 }, /* CONN_INFRA, WFDMA */
80602cc0c9SSean Wang { 0x7c060000, 0xe0000, 0x10000 }, /* CONN_INFRA, conn_host_csr_top */
81602cc0c9SSean Wang { 0x80020000, 0xb0000, 0x10000 }, /* WF_TOP_MISC_OFF */
82602cc0c9SSean Wang { 0x81020000, 0xc0000, 0x10000 }, /* WF_TOP_MISC_ON */
83e351f4f0SLorenzo Bianconi { 0x820c0000, 0x08000, 0x04000 }, /* WF_UMAC_TOP (PLE) */
84e351f4f0SLorenzo Bianconi { 0x820c8000, 0x0c000, 0x02000 }, /* WF_UMAC_TOP (PSE) */
85e351f4f0SLorenzo Bianconi { 0x820cc000, 0x0e000, 0x01000 }, /* WF_UMAC_TOP (PP) */
86e351f4f0SLorenzo Bianconi { 0x820cd000, 0x0f000, 0x01000 }, /* WF_MDP_TOP */
8729e247ecSDeren Wu { 0x74030000, 0x10000, 0x10000 }, /* PCIE_MAC_IREG */
88e351f4f0SLorenzo Bianconi { 0x820ce000, 0x21c00, 0x00200 }, /* WF_LMAC_TOP (WF_SEC) */
89e351f4f0SLorenzo Bianconi { 0x820cf000, 0x22000, 0x01000 }, /* WF_LMAC_TOP (WF_PF) */
90e351f4f0SLorenzo Bianconi { 0x820e0000, 0x20000, 0x00400 }, /* WF_LMAC_TOP BN0 (WF_CFG) */
91e351f4f0SLorenzo Bianconi { 0x820e1000, 0x20400, 0x00200 }, /* WF_LMAC_TOP BN0 (WF_TRB) */
92e351f4f0SLorenzo Bianconi { 0x820e9000, 0x23400, 0x00200 }, /* WF_LMAC_TOP BN0 (WF_WTBLOFF) */
93e351f4f0SLorenzo Bianconi { 0x820ea000, 0x24000, 0x00200 }, /* WF_LMAC_TOP BN0 (WF_ETBF) */
94e351f4f0SLorenzo Bianconi { 0x820ec000, 0x24600, 0x00200 }, /* WF_LMAC_TOP BN0 (WF_INT) */
95e351f4f0SLorenzo Bianconi { 0x820f0000, 0xa0000, 0x00400 }, /* WF_LMAC_TOP BN1 (WF_CFG) */
96e351f4f0SLorenzo Bianconi { 0x820f1000, 0xa0600, 0x00200 }, /* WF_LMAC_TOP BN1 (WF_TRB) */
97e351f4f0SLorenzo Bianconi { 0x820f2000, 0xa0800, 0x00400 }, /* WF_LMAC_TOP BN1 (WF_AGG) */
98e351f4f0SLorenzo Bianconi { 0x820f3000, 0xa0c00, 0x00400 }, /* WF_LMAC_TOP BN1 (WF_ARB) */
99e351f4f0SLorenzo Bianconi { 0x820f4000, 0xa1000, 0x00400 }, /* WF_LMAC_TOP BN1 (WF_TMAC) */
100e351f4f0SLorenzo Bianconi { 0x820f5000, 0xa1400, 0x00800 }, /* WF_LMAC_TOP BN1 (WF_RMAC) */
101e351f4f0SLorenzo Bianconi { 0x820f7000, 0xa1e00, 0x00200 }, /* WF_LMAC_TOP BN1 (WF_DMA) */
102e351f4f0SLorenzo Bianconi { 0x820f9000, 0xa3400, 0x00200 }, /* WF_LMAC_TOP BN1 (WF_WTBLOFF) */
103e351f4f0SLorenzo Bianconi { 0x820fa000, 0xa4000, 0x00200 }, /* WF_LMAC_TOP BN1 (WF_ETBF) */
104e351f4f0SLorenzo Bianconi { 0x820fb000, 0xa4200, 0x00400 }, /* WF_LMAC_TOP BN1 (WF_LPON) */
105e351f4f0SLorenzo Bianconi { 0x820fc000, 0xa4600, 0x00200 }, /* WF_LMAC_TOP BN1 (WF_INT) */
106e351f4f0SLorenzo Bianconi { 0x820fd000, 0xa4800, 0x00800 }, /* WF_LMAC_TOP BN1 (WF_MIB) */
107602cc0c9SSean Wang };
108602cc0c9SSean Wang int i;
109602cc0c9SSean Wang
110602cc0c9SSean Wang if (addr < 0x100000)
111602cc0c9SSean Wang return addr;
112602cc0c9SSean Wang
113602cc0c9SSean Wang for (i = 0; i < ARRAY_SIZE(fixed_map); i++) {
114602cc0c9SSean Wang u32 ofs;
115602cc0c9SSean Wang
116602cc0c9SSean Wang if (addr < fixed_map[i].phys)
117602cc0c9SSean Wang continue;
118602cc0c9SSean Wang
119602cc0c9SSean Wang ofs = addr - fixed_map[i].phys;
120602cc0c9SSean Wang if (ofs > fixed_map[i].size)
121602cc0c9SSean Wang continue;
122602cc0c9SSean Wang
123e351f4f0SLorenzo Bianconi return fixed_map[i].maps + ofs;
124602cc0c9SSean Wang }
125602cc0c9SSean Wang
126602cc0c9SSean Wang if ((addr >= 0x18000000 && addr < 0x18c00000) ||
127602cc0c9SSean Wang (addr >= 0x70000000 && addr < 0x78000000) ||
128602cc0c9SSean Wang (addr >= 0x7c000000 && addr < 0x7c400000))
129602cc0c9SSean Wang return mt7921_reg_map_l1(dev, addr);
130602cc0c9SSean Wang
131602cc0c9SSean Wang dev_err(dev->mt76.dev, "Access currently unsupported address %08x\n",
132602cc0c9SSean Wang addr);
133602cc0c9SSean Wang
134602cc0c9SSean Wang return 0;
135602cc0c9SSean Wang }
136602cc0c9SSean Wang
mt7921_rr(struct mt76_dev * mdev,u32 offset)137602cc0c9SSean Wang static u32 mt7921_rr(struct mt76_dev *mdev, u32 offset)
138602cc0c9SSean Wang {
139975e122dSLorenzo Bianconi struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);
140602cc0c9SSean Wang u32 addr = __mt7921_reg_addr(dev, offset);
141602cc0c9SSean Wang
142602cc0c9SSean Wang return dev->bus_ops->rr(mdev, addr);
143602cc0c9SSean Wang }
144602cc0c9SSean Wang
mt7921_wr(struct mt76_dev * mdev,u32 offset,u32 val)145602cc0c9SSean Wang static void mt7921_wr(struct mt76_dev *mdev, u32 offset, u32 val)
146602cc0c9SSean Wang {
147975e122dSLorenzo Bianconi struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);
148602cc0c9SSean Wang u32 addr = __mt7921_reg_addr(dev, offset);
149602cc0c9SSean Wang
150602cc0c9SSean Wang dev->bus_ops->wr(mdev, addr, val);
151602cc0c9SSean Wang }
152602cc0c9SSean Wang
mt7921_rmw(struct mt76_dev * mdev,u32 offset,u32 mask,u32 val)153602cc0c9SSean Wang static u32 mt7921_rmw(struct mt76_dev *mdev, u32 offset, u32 mask, u32 val)
154602cc0c9SSean Wang {
155975e122dSLorenzo Bianconi struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);
156602cc0c9SSean Wang u32 addr = __mt7921_reg_addr(dev, offset);
157602cc0c9SSean Wang
158602cc0c9SSean Wang return dev->bus_ops->rmw(mdev, addr, mask, val);
159602cc0c9SSean Wang }
160602cc0c9SSean Wang
mt7921_dma_init(struct mt792x_dev * dev)1612e7f7a2cSLorenzo Bianconi static int mt7921_dma_init(struct mt792x_dev *dev)
1622e7f7a2cSLorenzo Bianconi {
1632e7f7a2cSLorenzo Bianconi int ret;
1642e7f7a2cSLorenzo Bianconi
1652e7f7a2cSLorenzo Bianconi mt76_dma_attach(&dev->mt76);
1662e7f7a2cSLorenzo Bianconi
1672e7f7a2cSLorenzo Bianconi ret = mt792x_dma_disable(dev, true);
1682e7f7a2cSLorenzo Bianconi if (ret)
1692e7f7a2cSLorenzo Bianconi return ret;
1702e7f7a2cSLorenzo Bianconi
1712e7f7a2cSLorenzo Bianconi /* init tx queue */
1722e7f7a2cSLorenzo Bianconi ret = mt76_connac_init_tx_queues(dev->phy.mt76, MT7921_TXQ_BAND0,
1732e7f7a2cSLorenzo Bianconi MT7921_TX_RING_SIZE,
1742e7f7a2cSLorenzo Bianconi MT_TX_RING_BASE, 0);
1752e7f7a2cSLorenzo Bianconi if (ret)
1762e7f7a2cSLorenzo Bianconi return ret;
1772e7f7a2cSLorenzo Bianconi
1782e7f7a2cSLorenzo Bianconi mt76_wr(dev, MT_WFDMA0_TX_RING0_EXT_CTRL, 0x4);
1792e7f7a2cSLorenzo Bianconi
1802e7f7a2cSLorenzo Bianconi /* command to WM */
1812e7f7a2cSLorenzo Bianconi ret = mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_WM, MT7921_TXQ_MCU_WM,
1822e7f7a2cSLorenzo Bianconi MT7921_TX_MCU_RING_SIZE, MT_TX_RING_BASE);
1832e7f7a2cSLorenzo Bianconi if (ret)
1842e7f7a2cSLorenzo Bianconi return ret;
1852e7f7a2cSLorenzo Bianconi
1862e7f7a2cSLorenzo Bianconi /* firmware download */
1872e7f7a2cSLorenzo Bianconi ret = mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_FWDL, MT7921_TXQ_FWDL,
1882e7f7a2cSLorenzo Bianconi MT7921_TX_FWDL_RING_SIZE, MT_TX_RING_BASE);
1892e7f7a2cSLorenzo Bianconi if (ret)
1902e7f7a2cSLorenzo Bianconi return ret;
1912e7f7a2cSLorenzo Bianconi
1922e7f7a2cSLorenzo Bianconi /* event from WM before firmware download */
1932e7f7a2cSLorenzo Bianconi ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU],
1942e7f7a2cSLorenzo Bianconi MT7921_RXQ_MCU_WM,
1952e7f7a2cSLorenzo Bianconi MT7921_RX_MCU_RING_SIZE,
1962e7f7a2cSLorenzo Bianconi MT_RX_BUF_SIZE, MT_RX_EVENT_RING_BASE);
1972e7f7a2cSLorenzo Bianconi if (ret)
1982e7f7a2cSLorenzo Bianconi return ret;
1992e7f7a2cSLorenzo Bianconi
2002e7f7a2cSLorenzo Bianconi /* Change mcu queue after firmware download */
2012e7f7a2cSLorenzo Bianconi ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU_WA],
2022e7f7a2cSLorenzo Bianconi MT7921_RXQ_MCU_WM,
2032e7f7a2cSLorenzo Bianconi MT7921_RX_MCU_RING_SIZE,
2042e7f7a2cSLorenzo Bianconi MT_RX_BUF_SIZE, MT_WFDMA0(0x540));
2052e7f7a2cSLorenzo Bianconi if (ret)
2062e7f7a2cSLorenzo Bianconi return ret;
2072e7f7a2cSLorenzo Bianconi
2082e7f7a2cSLorenzo Bianconi /* rx data */
2092e7f7a2cSLorenzo Bianconi ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN],
2102e7f7a2cSLorenzo Bianconi MT7921_RXQ_BAND0, MT7921_RX_RING_SIZE,
2112e7f7a2cSLorenzo Bianconi MT_RX_BUF_SIZE, MT_RX_DATA_RING_BASE);
2122e7f7a2cSLorenzo Bianconi if (ret)
2132e7f7a2cSLorenzo Bianconi return ret;
2142e7f7a2cSLorenzo Bianconi
2152e7f7a2cSLorenzo Bianconi ret = mt76_init_queues(dev, mt792x_poll_rx);
2162e7f7a2cSLorenzo Bianconi if (ret < 0)
2172e7f7a2cSLorenzo Bianconi return ret;
2182e7f7a2cSLorenzo Bianconi
2192e7f7a2cSLorenzo Bianconi netif_napi_add_tx(&dev->mt76.tx_napi_dev, &dev->mt76.tx_napi,
2202e7f7a2cSLorenzo Bianconi mt792x_poll_tx);
2212e7f7a2cSLorenzo Bianconi napi_enable(&dev->mt76.tx_napi);
2222e7f7a2cSLorenzo Bianconi
2232e7f7a2cSLorenzo Bianconi return mt792x_dma_enable(dev);
2242e7f7a2cSLorenzo Bianconi }
2252e7f7a2cSLorenzo Bianconi
mt7921_pci_probe(struct pci_dev * pdev,const struct pci_device_id * id)2265c14a5f9SSean Wang static int mt7921_pci_probe(struct pci_dev *pdev,
2275c14a5f9SSean Wang const struct pci_device_id *id)
2285c14a5f9SSean Wang {
2295c14a5f9SSean Wang static const struct mt76_driver_ops drv_ops = {
2305c14a5f9SSean Wang /* txwi_size = txd size + txp size */
2314cb4da17SLorenzo Bianconi .txwi_size = MT_TXD_SIZE + sizeof(struct mt76_connac_hw_txp),
2325b0fb852SBen Greear .drv_flags = MT_DRV_TXWI_NO_FREE | MT_DRV_HW_MGMT_TXQ |
2335b0fb852SBen Greear MT_DRV_AMSDU_OFFLOAD,
2345c14a5f9SSean Wang .survey_flags = SURVEY_INFO_TIME_TX |
2355c14a5f9SSean Wang SURVEY_INFO_TIME_RX |
2365c14a5f9SSean Wang SURVEY_INFO_TIME_BSS_RX,
237d089692bSLorenzo Bianconi .token_size = MT7921_TOKEN_SIZE,
238576b4484SSean Wang .tx_prepare_skb = mt7921e_tx_prepare_skb,
2390a178a60SLorenzo Bianconi .tx_complete_skb = mt76_connac_tx_complete_skb,
2400af1ad95SLorenzo Bianconi .rx_check = mt7921_rx_check,
2410af1ad95SLorenzo Bianconi .rx_skb = mt7921_queue_rx_skb,
242ff655174SLorenzo Bianconi .rx_poll_complete = mt792x_rx_poll_complete,
2435c14a5f9SSean Wang .sta_add = mt7921_mac_sta_add,
244f5056657SSean Wang .sta_assoc = mt7921_mac_sta_assoc,
2455c14a5f9SSean Wang .sta_remove = mt7921_mac_sta_remove,
246311f121cSLorenzo Bianconi .update_survey = mt792x_update_channel,
2475c14a5f9SSean Wang };
248838cc667SLorenzo Bianconi static const struct mt792x_hif_ops mt7921_pcie_ops = {
249033ae79bSSean Wang .init_reset = mt7921e_init_reset,
250576b4484SSean Wang .reset = mt7921e_mac_reset,
251dfc7743dSSean Wang .mcu_init = mt7921e_mcu_init,
2521c025496SLorenzo Bianconi .drv_own = mt792xe_mcu_drv_pmctrl,
2531c025496SLorenzo Bianconi .fw_own = mt792xe_mcu_fw_pmctrl,
254576b4484SSean Wang };
255c9072f11SLorenzo Bianconi static const struct mt792x_irq_map irq_map = {
256c9072f11SLorenzo Bianconi .host_irq_enable = MT_WFDMA0_HOST_INT_ENA,
257c9072f11SLorenzo Bianconi .tx = {
258c9072f11SLorenzo Bianconi .all_complete_mask = MT_INT_TX_DONE_ALL,
259c9072f11SLorenzo Bianconi .mcu_complete_mask = MT_INT_TX_DONE_MCU,
260c9072f11SLorenzo Bianconi },
261c9072f11SLorenzo Bianconi .rx = {
262c9072f11SLorenzo Bianconi .data_complete_mask = MT_INT_RX_DONE_DATA,
263c9072f11SLorenzo Bianconi .wm_complete_mask = MT_INT_RX_DONE_WM,
264c9072f11SLorenzo Bianconi .wm2_complete_mask = MT_INT_RX_DONE_WM2,
265c9072f11SLorenzo Bianconi },
266c9072f11SLorenzo Bianconi };
267034ae28bSSean Wang struct ieee80211_ops *ops;
268602cc0c9SSean Wang struct mt76_bus_ops *bus_ops;
269975e122dSLorenzo Bianconi struct mt792x_dev *dev;
2705c14a5f9SSean Wang struct mt76_dev *mdev;
271034ae28bSSean Wang u8 features;
2725c14a5f9SSean Wang int ret;
27309d4d6daSMario Limonciello u16 cmd;
2745c14a5f9SSean Wang
2755c14a5f9SSean Wang ret = pcim_enable_device(pdev);
2765c14a5f9SSean Wang if (ret)
2775c14a5f9SSean Wang return ret;
2785c14a5f9SSean Wang
2795c14a5f9SSean Wang ret = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev));
2805c14a5f9SSean Wang if (ret)
2815c14a5f9SSean Wang return ret;
2825c14a5f9SSean Wang
28309d4d6daSMario Limonciello pci_read_config_word(pdev, PCI_COMMAND, &cmd);
28409d4d6daSMario Limonciello if (!(cmd & PCI_COMMAND_MEMORY)) {
28509d4d6daSMario Limonciello cmd |= PCI_COMMAND_MEMORY;
28609d4d6daSMario Limonciello pci_write_config_word(pdev, PCI_COMMAND, cmd);
28709d4d6daSMario Limonciello }
2885c14a5f9SSean Wang pci_set_master(pdev);
2895c14a5f9SSean Wang
290eaafabd2SLorenzo Bianconi ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
2915c14a5f9SSean Wang if (ret < 0)
2925c14a5f9SSean Wang return ret;
2935c14a5f9SSean Wang
294a2e75961SChristophe JAILLET ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
2955c14a5f9SSean Wang if (ret)
2965c14a5f9SSean Wang goto err_free_pci_vec;
2975c14a5f9SSean Wang
298bf3747aeSSean Wang if (mt7921_disable_aspm)
2995c14a5f9SSean Wang mt76_pci_disable_aspm(pdev);
3005c14a5f9SSean Wang
301e8a264ccSLorenzo Bianconi ops = mt792x_get_mac80211_ops(&pdev->dev, &mt7921_ops,
302e8a264ccSLorenzo Bianconi (void *)id->driver_data, &features);
303034ae28bSSean Wang if (!ops) {
304034ae28bSSean Wang ret = -ENOMEM;
305034ae28bSSean Wang goto err_free_pci_vec;
306034ae28bSSean Wang }
307034ae28bSSean Wang
308034ae28bSSean Wang mdev = mt76_alloc_device(&pdev->dev, sizeof(*dev), ops, &drv_ops);
3095c14a5f9SSean Wang if (!mdev) {
3105c14a5f9SSean Wang ret = -ENOMEM;
3115c14a5f9SSean Wang goto err_free_pci_vec;
3125c14a5f9SSean Wang }
3135c14a5f9SSean Wang
314b5a62d61SDeren Wu pci_set_drvdata(pdev, mdev);
315b5a62d61SDeren Wu
316975e122dSLorenzo Bianconi dev = container_of(mdev, struct mt792x_dev, mt76);
317034ae28bSSean Wang dev->fw_features = features;
318576b4484SSean Wang dev->hif_ops = &mt7921_pcie_ops;
319c9072f11SLorenzo Bianconi dev->irq_map = &irq_map;
3205c14a5f9SSean Wang mt76_mmio_init(&dev->mt76, pcim_iomap_table(pdev)[0]);
321ff655174SLorenzo Bianconi tasklet_init(&mdev->irq_tasklet, mt792x_irq_tasklet, (unsigned long)dev);
322602cc0c9SSean Wang
323602cc0c9SSean Wang dev->phy.dev = dev;
324602cc0c9SSean Wang dev->phy.mt76 = &dev->mt76.phy;
325602cc0c9SSean Wang dev->mt76.phy.priv = &dev->phy;
326602cc0c9SSean Wang dev->bus_ops = dev->mt76.bus;
327602cc0c9SSean Wang bus_ops = devm_kmemdup(dev->mt76.dev, dev->bus_ops, sizeof(*bus_ops),
328602cc0c9SSean Wang GFP_KERNEL);
3294e90db5eSChristophe JAILLET if (!bus_ops) {
3304e90db5eSChristophe JAILLET ret = -ENOMEM;
3314e90db5eSChristophe JAILLET goto err_free_dev;
3324e90db5eSChristophe JAILLET }
333602cc0c9SSean Wang
334602cc0c9SSean Wang bus_ops->rr = mt7921_rr;
335602cc0c9SSean Wang bus_ops->wr = mt7921_wr;
336602cc0c9SSean Wang bus_ops->rmw = mt7921_rmw;
337602cc0c9SSean Wang dev->mt76.bus = bus_ops;
338602cc0c9SSean Wang
3391c025496SLorenzo Bianconi ret = mt792xe_mcu_fw_pmctrl(dev);
340525c469eSQuan Zhou if (ret)
341525c469eSQuan Zhou goto err_free_dev;
342525c469eSQuan Zhou
3431c025496SLorenzo Bianconi ret = __mt792xe_mcu_drv_pmctrl(dev);
344602cc0c9SSean Wang if (ret)
3454e90db5eSChristophe JAILLET goto err_free_dev;
346602cc0c9SSean Wang
3475c14a5f9SSean Wang mdev->rev = (mt7921_l1_rr(dev, MT_HW_CHIPID) << 16) |
3485c14a5f9SSean Wang (mt7921_l1_rr(dev, MT_HW_REV) & 0xff);
34981a88b1eSTzung-Bi Shih dev_info(mdev->dev, "ASIC revision: %04x\n", mdev->rev);
3505c14a5f9SSean Wang
351ff655174SLorenzo Bianconi ret = mt792x_wfsys_reset(dev);
352525c469eSQuan Zhou if (ret)
353525c469eSQuan Zhou goto err_free_dev;
354525c469eSQuan Zhou
355c9072f11SLorenzo Bianconi mt76_wr(dev, irq_map.host_irq_enable, 0);
3565c14a5f9SSean Wang
35723c1d2dcSSean Wang mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff);
3585c14a5f9SSean Wang
359ff655174SLorenzo Bianconi ret = devm_request_irq(mdev->dev, pdev->irq, mt792x_irq_handler,
3605c14a5f9SSean Wang IRQF_SHARED, KBUILD_MODNAME, dev);
3615c14a5f9SSean Wang if (ret)
3625c14a5f9SSean Wang goto err_free_dev;
3635c14a5f9SSean Wang
364033ae79bSSean Wang ret = mt7921_dma_init(dev);
365033ae79bSSean Wang if (ret)
366033ae79bSSean Wang goto err_free_irq;
367033ae79bSSean Wang
3685c14a5f9SSean Wang ret = mt7921_register_device(dev);
3695c14a5f9SSean Wang if (ret)
370e230f0c4SSean Wang goto err_free_irq;
3715c14a5f9SSean Wang
3725c14a5f9SSean Wang return 0;
3735c14a5f9SSean Wang
374e230f0c4SSean Wang err_free_irq:
375e230f0c4SSean Wang devm_free_irq(&pdev->dev, pdev->irq, dev);
3765c14a5f9SSean Wang err_free_dev:
3775c14a5f9SSean Wang mt76_free_device(&dev->mt76);
3785c14a5f9SSean Wang err_free_pci_vec:
3795c14a5f9SSean Wang pci_free_irq_vectors(pdev);
3805c14a5f9SSean Wang
3815c14a5f9SSean Wang return ret;
3825c14a5f9SSean Wang }
3835c14a5f9SSean Wang
mt7921_pci_remove(struct pci_dev * pdev)3845c14a5f9SSean Wang static void mt7921_pci_remove(struct pci_dev *pdev)
3855c14a5f9SSean Wang {
3865c14a5f9SSean Wang struct mt76_dev *mdev = pci_get_drvdata(pdev);
387975e122dSLorenzo Bianconi struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);
3885c14a5f9SSean Wang
389033ae79bSSean Wang mt7921e_unregister_device(dev);
390*c7dd42fbSDeren Wu set_bit(MT76_REMOVED, &mdev->phy.state);
3915c14a5f9SSean Wang devm_free_irq(&pdev->dev, pdev->irq, dev);
392ad483ed9SSean Wang mt76_free_device(&dev->mt76);
3935c14a5f9SSean Wang pci_free_irq_vectors(pdev);
3945c14a5f9SSean Wang }
3955c14a5f9SSean Wang
mt7921_pci_suspend(struct device * device)396454b768fSKai-Heng Feng static int mt7921_pci_suspend(struct device *device)
397ffa1bf97SSean Wang {
398454b768fSKai-Heng Feng struct pci_dev *pdev = to_pci_dev(device);
399ffa1bf97SSean Wang struct mt76_dev *mdev = pci_get_drvdata(pdev);
400975e122dSLorenzo Bianconi struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);
401f86625aeSSean Wang struct mt76_connac_pm *pm = &dev->pm;
402ffa1bf97SSean Wang int i, err;
403ffa1bf97SSean Wang
404f86625aeSSean Wang pm->suspended = true;
405ff6c4a64SSean Wang flush_work(&dev->reset_work);
406f86625aeSSean Wang cancel_delayed_work_sync(&pm->ps_work);
407f86625aeSSean Wang cancel_work_sync(&pm->wake_work);
408f86625aeSSean Wang
409c21a7f9fSLorenzo Bianconi err = mt792x_mcu_drv_pmctrl(dev);
4101d8efc74SSean Wang if (err < 0)
411f86625aeSSean Wang goto restore_suspend;
4121d8efc74SSean Wang
413022159b0SLorenzo Bianconi err = mt76_connac_mcu_set_hif_suspend(mdev, true);
414ffa1bf97SSean Wang if (err)
415f86625aeSSean Wang goto restore_suspend;
416ffa1bf97SSean Wang
417495cd981SLorenzo Bianconi /* always enable deep sleep during suspend to reduce
418495cd981SLorenzo Bianconi * power consumption
419495cd981SLorenzo Bianconi */
4201792eb0eSSean Wang mt76_connac_mcu_set_deep_sleep(&dev->mt76, true);
4211792eb0eSSean Wang
422ffa1bf97SSean Wang napi_disable(&mdev->tx_napi);
423ffa1bf97SSean Wang mt76_worker_disable(&mdev->tx_worker);
424ffa1bf97SSean Wang
425ffa1bf97SSean Wang mt76_for_each_q_rx(mdev, i) {
426ffa1bf97SSean Wang napi_disable(&mdev->napi[i]);
427ffa1bf97SSean Wang }
428ffa1bf97SSean Wang
429ffa1bf97SSean Wang /* wait until dma is idle */
430ffa1bf97SSean Wang mt76_poll(dev, MT_WFDMA0_GLO_CFG,
431ffa1bf97SSean Wang MT_WFDMA0_GLO_CFG_TX_DMA_BUSY |
432ffa1bf97SSean Wang MT_WFDMA0_GLO_CFG_RX_DMA_BUSY, 0, 1000);
433ffa1bf97SSean Wang
434ffa1bf97SSean Wang /* put dma disabled */
435ffa1bf97SSean Wang mt76_clear(dev, MT_WFDMA0_GLO_CFG,
436ffa1bf97SSean Wang MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN);
437ffa1bf97SSean Wang
438ffa1bf97SSean Wang /* disable interrupt */
439c9072f11SLorenzo Bianconi mt76_wr(dev, dev->irq_map->host_irq_enable, 0);
440fe3fccdeSSean Wang mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0x0);
441fe3fccdeSSean Wang synchronize_irq(pdev->irq);
442ec193b41SLorenzo Bianconi tasklet_kill(&mdev->irq_tasklet);
443ffa1bf97SSean Wang
444c21a7f9fSLorenzo Bianconi err = mt792x_mcu_fw_pmctrl(dev);
445ffa1bf97SSean Wang if (err)
446f86625aeSSean Wang goto restore_napi;
447ffa1bf97SSean Wang
448ffa1bf97SSean Wang return 0;
449ffa1bf97SSean Wang
450f86625aeSSean Wang restore_napi:
451ffa1bf97SSean Wang mt76_for_each_q_rx(mdev, i) {
452ffa1bf97SSean Wang napi_enable(&mdev->napi[i]);
453ffa1bf97SSean Wang }
454ffa1bf97SSean Wang napi_enable(&mdev->tx_napi);
4551792eb0eSSean Wang
456495cd981SLorenzo Bianconi if (!pm->ds_enable)
4571792eb0eSSean Wang mt76_connac_mcu_set_deep_sleep(&dev->mt76, false);
4581792eb0eSSean Wang
459022159b0SLorenzo Bianconi mt76_connac_mcu_set_hif_suspend(mdev, false);
460ffa1bf97SSean Wang
461f86625aeSSean Wang restore_suspend:
462f86625aeSSean Wang pm->suspended = false;
463f86625aeSSean Wang
464ff6c4a64SSean Wang if (err < 0)
465311f121cSLorenzo Bianconi mt792x_reset(&dev->mt76);
466ff6c4a64SSean Wang
467ffa1bf97SSean Wang return err;
468ffa1bf97SSean Wang }
469ffa1bf97SSean Wang
mt7921_pci_resume(struct device * device)470454b768fSKai-Heng Feng static int mt7921_pci_resume(struct device *device)
471ffa1bf97SSean Wang {
472454b768fSKai-Heng Feng struct pci_dev *pdev = to_pci_dev(device);
473ffa1bf97SSean Wang struct mt76_dev *mdev = pci_get_drvdata(pdev);
474975e122dSLorenzo Bianconi struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);
475495cd981SLorenzo Bianconi struct mt76_connac_pm *pm = &dev->pm;
476ffa1bf97SSean Wang int i, err;
477ffa1bf97SSean Wang
478c21a7f9fSLorenzo Bianconi err = mt792x_mcu_drv_pmctrl(dev);
4795e309314SSean Wang if (err < 0)
480ff6c4a64SSean Wang goto failed;
4815e309314SSean Wang
482ff655174SLorenzo Bianconi mt792x_wpdma_reinit_cond(dev);
4831792eb0eSSean Wang
484ffa1bf97SSean Wang /* enable interrupt */
48523c1d2dcSSean Wang mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff);
4864fc44156SLorenzo Bianconi mt76_connac_irq_enable(&dev->mt76,
487c9072f11SLorenzo Bianconi dev->irq_map->tx.all_complete_mask |
488c9072f11SLorenzo Bianconi MT_INT_RX_DONE_ALL | MT_INT_MCU_CMD);
489dc5d5f9dSLorenzo Bianconi mt76_set(dev, MT_MCU2HOST_SW_INT_ENA, MT_MCU_CMD_WAKE_RX_PCIE);
490ffa1bf97SSean Wang
491ffa1bf97SSean Wang /* put dma enabled */
492ffa1bf97SSean Wang mt76_set(dev, MT_WFDMA0_GLO_CFG,
493ffa1bf97SSean Wang MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN);
494ffa1bf97SSean Wang
495ffa1bf97SSean Wang mt76_worker_enable(&mdev->tx_worker);
496970be1dfSFelix Fietkau
497970be1dfSFelix Fietkau local_bh_disable();
498ffa1bf97SSean Wang mt76_for_each_q_rx(mdev, i) {
499ffa1bf97SSean Wang napi_enable(&mdev->napi[i]);
500ffa1bf97SSean Wang napi_schedule(&mdev->napi[i]);
501ffa1bf97SSean Wang }
502ffa1bf97SSean Wang napi_enable(&mdev->tx_napi);
503ffa1bf97SSean Wang napi_schedule(&mdev->tx_napi);
504970be1dfSFelix Fietkau local_bh_enable();
505ffa1bf97SSean Wang
506495cd981SLorenzo Bianconi /* restore previous ds setting */
507495cd981SLorenzo Bianconi if (!pm->ds_enable)
5081792eb0eSSean Wang mt76_connac_mcu_set_deep_sleep(&dev->mt76, false);
5091792eb0eSSean Wang
5105375001bSSean Wang err = mt76_connac_mcu_set_hif_suspend(mdev, false);
511ff6c4a64SSean Wang failed:
5125375001bSSean Wang pm->suspended = false;
5135375001bSSean Wang
514ff6c4a64SSean Wang if (err < 0)
515311f121cSLorenzo Bianconi mt792x_reset(&dev->mt76);
516ff6c4a64SSean Wang
5175375001bSSean Wang return err;
518ffa1bf97SSean Wang }
519454b768fSKai-Heng Feng
mt7921_pci_shutdown(struct pci_dev * pdev)520f23a0ceaSLeon Yen static void mt7921_pci_shutdown(struct pci_dev *pdev)
521f23a0ceaSLeon Yen {
5229270270dSDeren Wu mt7921_pci_remove(pdev);
523f23a0ceaSLeon Yen }
524f23a0ceaSLeon Yen
525454b768fSKai-Heng Feng static DEFINE_SIMPLE_DEV_PM_OPS(mt7921_pm_ops, mt7921_pci_suspend, mt7921_pci_resume);
526ffa1bf97SSean Wang
52781f302fdSLorenzo Bianconi static struct pci_driver mt7921_pci_driver = {
5285c14a5f9SSean Wang .name = KBUILD_MODNAME,
5295c14a5f9SSean Wang .id_table = mt7921_pci_device_table,
5305c14a5f9SSean Wang .probe = mt7921_pci_probe,
5315c14a5f9SSean Wang .remove = mt7921_pci_remove,
532f23a0ceaSLeon Yen .shutdown = mt7921_pci_shutdown,
533454b768fSKai-Heng Feng .driver.pm = pm_sleep_ptr(&mt7921_pm_ops),
5345c14a5f9SSean Wang };
5355c14a5f9SSean Wang
5365c14a5f9SSean Wang module_pci_driver(mt7921_pci_driver);
5375c14a5f9SSean Wang
5385c14a5f9SSean Wang MODULE_DEVICE_TABLE(pci, mt7921_pci_device_table);
5395c14a5f9SSean Wang MODULE_FIRMWARE(MT7921_FIRMWARE_WM);
5405c14a5f9SSean Wang MODULE_FIRMWARE(MT7921_ROM_PATCH);
54168808872SDeren Wu MODULE_FIRMWARE(MT7922_FIRMWARE_WM);
54268808872SDeren Wu MODULE_FIRMWARE(MT7922_ROM_PATCH);
5435c14a5f9SSean Wang MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
5445c14a5f9SSean Wang MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>");
5455c14a5f9SSean Wang MODULE_LICENSE("Dual BSD/GPL");
546