Commit | Line | Data |
---|---|---|
5c14a5f9 SW |
1 | // SPDX-License-Identifier: ISC |
2 | /* Copyright (C) 2020 MediaTek Inc. | |
3 | * | |
4 | */ | |
5 | ||
6 | #include <linux/kernel.h> | |
7 | #include <linux/module.h> | |
8 | #include <linux/pci.h> | |
9 | ||
10 | #include "mt7921.h" | |
140efef3 | 11 | #include "../mt76_connac2_mac.h" |
2e7f7a2c | 12 | #include "../dma.h" |
67aa2743 | 13 | #include "mcu.h" |
5c14a5f9 SW |
14 | |
15 | static const struct pci_device_id mt7921_pci_device_table[] = { | |
034ae28b SW |
16 | { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7961), |
17 | .driver_data = (kernel_ulong_t)MT7921_FIRMWARE_WM }, | |
18 | { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7922), | |
19 | .driver_data = (kernel_ulong_t)MT7922_FIRMWARE_WM }, | |
fce9c967 IR |
20 | { PCI_DEVICE(PCI_VENDOR_ID_ITTIM, 0x7922), |
21 | .driver_data = (kernel_ulong_t)MT7922_FIRMWARE_WM }, | |
034ae28b SW |
22 | { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x0608), |
23 | .driver_data = (kernel_ulong_t)MT7921_FIRMWARE_WM }, | |
24 | { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x0616), | |
eb85df0a | 25 | .driver_data = (kernel_ulong_t)MT7922_FIRMWARE_WM }, |
5c14a5f9 SW |
26 | { }, |
27 | }; | |
28 | ||
bf3747ae SW |
29 | static bool mt7921_disable_aspm; |
30 | module_param_named(disable_aspm, mt7921_disable_aspm, bool, 0644); | |
31 | MODULE_PARM_DESC(disable_aspm, "disable PCI ASPM support"); | |
32 | ||
975e122d | 33 | static int mt7921e_init_reset(struct mt792x_dev *dev) |
033ae79b | 34 | { |
ff655174 | 35 | return mt792x_wpdma_reset(dev, true); |
033ae79b SW |
36 | } |
37 | ||
975e122d | 38 | static void mt7921e_unregister_device(struct mt792x_dev *dev) |
033ae79b SW |
39 | { |
40 | int i; | |
41 | struct mt76_connac_pm *pm = &dev->pm; | |
42 | ||
1c71e03a | 43 | cancel_work_sync(&dev->init_work); |
033ae79b SW |
44 | mt76_unregister_device(&dev->mt76); |
45 | mt76_for_each_q_rx(&dev->mt76, i) | |
46 | napi_disable(&dev->mt76.napi[i]); | |
47 | cancel_delayed_work_sync(&pm->ps_work); | |
48 | cancel_work_sync(&pm->wake_work); | |
3d78c464 | 49 | cancel_work_sync(&dev->reset_work); |
033ae79b | 50 | |
c8e370fe | 51 | mt76_connac2_tx_token_put(&dev->mt76); |
5c041325 | 52 | __mt792x_mcu_drv_pmctrl(dev); |
c693f2f0 | 53 | mt792x_dma_cleanup(dev); |
ff655174 | 54 | mt792x_wfsys_reset(dev); |
56054087 | 55 | skb_queue_purge(&dev->mt76.mcu.res_q); |
033ae79b | 56 | |
ec193b41 | 57 | tasklet_disable(&dev->mt76.irq_tasklet); |
033ae79b SW |
58 | } |
59 | ||
975e122d | 60 | static u32 __mt7921_reg_addr(struct mt792x_dev *dev, u32 addr) |
602cc0c9 | 61 | { |
e351f4f0 | 62 | static const struct mt76_connac_reg_map fixed_map[] = { |
602cc0c9 | 63 | { 0x820d0000, 0x30000, 0x10000 }, /* WF_LMAC_TOP (WF_WTBLON) */ |
e351f4f0 LB |
64 | { 0x820ed000, 0x24800, 0x00800 }, /* WF_LMAC_TOP BN0 (WF_MIB) */ |
65 | { 0x820e4000, 0x21000, 0x00400 }, /* WF_LMAC_TOP BN0 (WF_TMAC) */ | |
66 | { 0x820e7000, 0x21e00, 0x00200 }, /* WF_LMAC_TOP BN0 (WF_DMA) */ | |
67 | { 0x820eb000, 0x24200, 0x00400 }, /* WF_LMAC_TOP BN0 (WF_LPON) */ | |
68 | { 0x820e2000, 0x20800, 0x00400 }, /* WF_LMAC_TOP BN0 (WF_AGG) */ | |
69 | { 0x820e3000, 0x20c00, 0x00400 }, /* WF_LMAC_TOP BN0 (WF_ARB) */ | |
70 | { 0x820e5000, 0x21400, 0x00800 }, /* WF_LMAC_TOP BN0 (WF_RMAC) */ | |
602cc0c9 SW |
71 | { 0x00400000, 0x80000, 0x10000 }, /* WF_MCU_SYSRAM */ |
72 | { 0x00410000, 0x90000, 0x10000 }, /* WF_MCU_SYSRAM (configure register) */ | |
73 | { 0x40000000, 0x70000, 0x10000 }, /* WF_UMAC_SYSRAM */ | |
e351f4f0 LB |
74 | { 0x54000000, 0x02000, 0x01000 }, /* WFDMA PCIE0 MCU DMA0 */ |
75 | { 0x55000000, 0x03000, 0x01000 }, /* WFDMA PCIE0 MCU DMA1 */ | |
76 | { 0x58000000, 0x06000, 0x01000 }, /* WFDMA PCIE1 MCU DMA0 (MEM_DMA) */ | |
77 | { 0x59000000, 0x07000, 0x01000 }, /* WFDMA PCIE1 MCU DMA1 */ | |
602cc0c9 SW |
78 | { 0x7c000000, 0xf0000, 0x10000 }, /* CONN_INFRA */ |
79 | { 0x7c020000, 0xd0000, 0x10000 }, /* CONN_INFRA, WFDMA */ | |
80 | { 0x7c060000, 0xe0000, 0x10000 }, /* CONN_INFRA, conn_host_csr_top */ | |
81 | { 0x80020000, 0xb0000, 0x10000 }, /* WF_TOP_MISC_OFF */ | |
82 | { 0x81020000, 0xc0000, 0x10000 }, /* WF_TOP_MISC_ON */ | |
e351f4f0 LB |
83 | { 0x820c0000, 0x08000, 0x04000 }, /* WF_UMAC_TOP (PLE) */ |
84 | { 0x820c8000, 0x0c000, 0x02000 }, /* WF_UMAC_TOP (PSE) */ | |
85 | { 0x820cc000, 0x0e000, 0x01000 }, /* WF_UMAC_TOP (PP) */ | |
86 | { 0x820cd000, 0x0f000, 0x01000 }, /* WF_MDP_TOP */ | |
29e247ec | 87 | { 0x74030000, 0x10000, 0x10000 }, /* PCIE_MAC_IREG */ |
e351f4f0 LB |
88 | { 0x820ce000, 0x21c00, 0x00200 }, /* WF_LMAC_TOP (WF_SEC) */ |
89 | { 0x820cf000, 0x22000, 0x01000 }, /* WF_LMAC_TOP (WF_PF) */ | |
90 | { 0x820e0000, 0x20000, 0x00400 }, /* WF_LMAC_TOP BN0 (WF_CFG) */ | |
91 | { 0x820e1000, 0x20400, 0x00200 }, /* WF_LMAC_TOP BN0 (WF_TRB) */ | |
92 | { 0x820e9000, 0x23400, 0x00200 }, /* WF_LMAC_TOP BN0 (WF_WTBLOFF) */ | |
93 | { 0x820ea000, 0x24000, 0x00200 }, /* WF_LMAC_TOP BN0 (WF_ETBF) */ | |
94 | { 0x820ec000, 0x24600, 0x00200 }, /* WF_LMAC_TOP BN0 (WF_INT) */ | |
95 | { 0x820f0000, 0xa0000, 0x00400 }, /* WF_LMAC_TOP BN1 (WF_CFG) */ | |
96 | { 0x820f1000, 0xa0600, 0x00200 }, /* WF_LMAC_TOP BN1 (WF_TRB) */ | |
97 | { 0x820f2000, 0xa0800, 0x00400 }, /* WF_LMAC_TOP BN1 (WF_AGG) */ | |
98 | { 0x820f3000, 0xa0c00, 0x00400 }, /* WF_LMAC_TOP BN1 (WF_ARB) */ | |
99 | { 0x820f4000, 0xa1000, 0x00400 }, /* WF_LMAC_TOP BN1 (WF_TMAC) */ | |
100 | { 0x820f5000, 0xa1400, 0x00800 }, /* WF_LMAC_TOP BN1 (WF_RMAC) */ | |
101 | { 0x820f7000, 0xa1e00, 0x00200 }, /* WF_LMAC_TOP BN1 (WF_DMA) */ | |
102 | { 0x820f9000, 0xa3400, 0x00200 }, /* WF_LMAC_TOP BN1 (WF_WTBLOFF) */ | |
103 | { 0x820fa000, 0xa4000, 0x00200 }, /* WF_LMAC_TOP BN1 (WF_ETBF) */ | |
104 | { 0x820fb000, 0xa4200, 0x00400 }, /* WF_LMAC_TOP BN1 (WF_LPON) */ | |
105 | { 0x820fc000, 0xa4600, 0x00200 }, /* WF_LMAC_TOP BN1 (WF_INT) */ | |
106 | { 0x820fd000, 0xa4800, 0x00800 }, /* WF_LMAC_TOP BN1 (WF_MIB) */ | |
602cc0c9 SW |
107 | }; |
108 | int i; | |
109 | ||
110 | if (addr < 0x100000) | |
111 | return addr; | |
112 | ||
113 | for (i = 0; i < ARRAY_SIZE(fixed_map); i++) { | |
114 | u32 ofs; | |
115 | ||
116 | if (addr < fixed_map[i].phys) | |
117 | continue; | |
118 | ||
119 | ofs = addr - fixed_map[i].phys; | |
120 | if (ofs > fixed_map[i].size) | |
121 | continue; | |
122 | ||
e351f4f0 | 123 | return fixed_map[i].maps + ofs; |
602cc0c9 SW |
124 | } |
125 | ||
126 | if ((addr >= 0x18000000 && addr < 0x18c00000) || | |
127 | (addr >= 0x70000000 && addr < 0x78000000) || | |
128 | (addr >= 0x7c000000 && addr < 0x7c400000)) | |
129 | return mt7921_reg_map_l1(dev, addr); | |
130 | ||
131 | dev_err(dev->mt76.dev, "Access currently unsupported address %08x\n", | |
132 | addr); | |
133 | ||
134 | return 0; | |
135 | } | |
136 | ||
137 | static u32 mt7921_rr(struct mt76_dev *mdev, u32 offset) | |
138 | { | |
975e122d | 139 | struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); |
602cc0c9 SW |
140 | u32 addr = __mt7921_reg_addr(dev, offset); |
141 | ||
142 | return dev->bus_ops->rr(mdev, addr); | |
143 | } | |
144 | ||
145 | static void mt7921_wr(struct mt76_dev *mdev, u32 offset, u32 val) | |
146 | { | |
975e122d | 147 | struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); |
602cc0c9 SW |
148 | u32 addr = __mt7921_reg_addr(dev, offset); |
149 | ||
150 | dev->bus_ops->wr(mdev, addr, val); | |
151 | } | |
152 | ||
153 | static u32 mt7921_rmw(struct mt76_dev *mdev, u32 offset, u32 mask, u32 val) | |
154 | { | |
975e122d | 155 | struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); |
602cc0c9 SW |
156 | u32 addr = __mt7921_reg_addr(dev, offset); |
157 | ||
158 | return dev->bus_ops->rmw(mdev, addr, mask, val); | |
159 | } | |
160 | ||
2e7f7a2c LB |
161 | static int mt7921_dma_init(struct mt792x_dev *dev) |
162 | { | |
163 | int ret; | |
164 | ||
165 | mt76_dma_attach(&dev->mt76); | |
166 | ||
167 | ret = mt792x_dma_disable(dev, true); | |
168 | if (ret) | |
169 | return ret; | |
170 | ||
171 | /* init tx queue */ | |
172 | ret = mt76_connac_init_tx_queues(dev->phy.mt76, MT7921_TXQ_BAND0, | |
173 | MT7921_TX_RING_SIZE, | |
2e420b88 | 174 | MT_TX_RING_BASE, NULL, 0); |
2e7f7a2c LB |
175 | if (ret) |
176 | return ret; | |
177 | ||
178 | mt76_wr(dev, MT_WFDMA0_TX_RING0_EXT_CTRL, 0x4); | |
179 | ||
180 | /* command to WM */ | |
181 | ret = mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_WM, MT7921_TXQ_MCU_WM, | |
182 | MT7921_TX_MCU_RING_SIZE, MT_TX_RING_BASE); | |
183 | if (ret) | |
184 | return ret; | |
185 | ||
186 | /* firmware download */ | |
187 | ret = mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_FWDL, MT7921_TXQ_FWDL, | |
188 | MT7921_TX_FWDL_RING_SIZE, MT_TX_RING_BASE); | |
189 | if (ret) | |
190 | return ret; | |
191 | ||
192 | /* event from WM before firmware download */ | |
193 | ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU], | |
194 | MT7921_RXQ_MCU_WM, | |
195 | MT7921_RX_MCU_RING_SIZE, | |
196 | MT_RX_BUF_SIZE, MT_RX_EVENT_RING_BASE); | |
197 | if (ret) | |
198 | return ret; | |
199 | ||
200 | /* Change mcu queue after firmware download */ | |
201 | ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU_WA], | |
202 | MT7921_RXQ_MCU_WM, | |
4812ba9a | 203 | MT7921_RX_MCU_WA_RING_SIZE, |
2e7f7a2c LB |
204 | MT_RX_BUF_SIZE, MT_WFDMA0(0x540)); |
205 | if (ret) | |
206 | return ret; | |
207 | ||
208 | /* rx data */ | |
209 | ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN], | |
210 | MT7921_RXQ_BAND0, MT7921_RX_RING_SIZE, | |
211 | MT_RX_BUF_SIZE, MT_RX_DATA_RING_BASE); | |
212 | if (ret) | |
213 | return ret; | |
214 | ||
215 | ret = mt76_init_queues(dev, mt792x_poll_rx); | |
216 | if (ret < 0) | |
217 | return ret; | |
218 | ||
219 | netif_napi_add_tx(&dev->mt76.tx_napi_dev, &dev->mt76.tx_napi, | |
220 | mt792x_poll_tx); | |
221 | napi_enable(&dev->mt76.tx_napi); | |
222 | ||
223 | return mt792x_dma_enable(dev); | |
224 | } | |
225 | ||
5c14a5f9 SW |
226 | static int mt7921_pci_probe(struct pci_dev *pdev, |
227 | const struct pci_device_id *id) | |
228 | { | |
229 | static const struct mt76_driver_ops drv_ops = { | |
230 | /* txwi_size = txd size + txp size */ | |
4cb4da17 | 231 | .txwi_size = MT_TXD_SIZE + sizeof(struct mt76_connac_hw_txp), |
5b0fb852 BG |
232 | .drv_flags = MT_DRV_TXWI_NO_FREE | MT_DRV_HW_MGMT_TXQ | |
233 | MT_DRV_AMSDU_OFFLOAD, | |
5c14a5f9 SW |
234 | .survey_flags = SURVEY_INFO_TIME_TX | |
235 | SURVEY_INFO_TIME_RX | | |
236 | SURVEY_INFO_TIME_BSS_RX, | |
d089692b | 237 | .token_size = MT7921_TOKEN_SIZE, |
576b4484 | 238 | .tx_prepare_skb = mt7921e_tx_prepare_skb, |
0a178a60 | 239 | .tx_complete_skb = mt76_connac_tx_complete_skb, |
0af1ad95 LB |
240 | .rx_check = mt7921_rx_check, |
241 | .rx_skb = mt7921_queue_rx_skb, | |
ff655174 | 242 | .rx_poll_complete = mt792x_rx_poll_complete, |
5c14a5f9 | 243 | .sta_add = mt7921_mac_sta_add, |
f5056657 | 244 | .sta_assoc = mt7921_mac_sta_assoc, |
5c14a5f9 | 245 | .sta_remove = mt7921_mac_sta_remove, |
311f121c | 246 | .update_survey = mt792x_update_channel, |
5c14a5f9 | 247 | }; |
838cc667 | 248 | static const struct mt792x_hif_ops mt7921_pcie_ops = { |
033ae79b | 249 | .init_reset = mt7921e_init_reset, |
576b4484 | 250 | .reset = mt7921e_mac_reset, |
dfc7743d | 251 | .mcu_init = mt7921e_mcu_init, |
1c025496 LB |
252 | .drv_own = mt792xe_mcu_drv_pmctrl, |
253 | .fw_own = mt792xe_mcu_fw_pmctrl, | |
576b4484 | 254 | }; |
c9072f11 LB |
255 | static const struct mt792x_irq_map irq_map = { |
256 | .host_irq_enable = MT_WFDMA0_HOST_INT_ENA, | |
257 | .tx = { | |
258 | .all_complete_mask = MT_INT_TX_DONE_ALL, | |
259 | .mcu_complete_mask = MT_INT_TX_DONE_MCU, | |
260 | }, | |
261 | .rx = { | |
262 | .data_complete_mask = MT_INT_RX_DONE_DATA, | |
263 | .wm_complete_mask = MT_INT_RX_DONE_WM, | |
264 | .wm2_complete_mask = MT_INT_RX_DONE_WM2, | |
265 | }, | |
266 | }; | |
034ae28b | 267 | struct ieee80211_ops *ops; |
602cc0c9 | 268 | struct mt76_bus_ops *bus_ops; |
975e122d | 269 | struct mt792x_dev *dev; |
5c14a5f9 | 270 | struct mt76_dev *mdev; |
034ae28b | 271 | u8 features; |
5c14a5f9 | 272 | int ret; |
09d4d6da | 273 | u16 cmd; |
5c14a5f9 SW |
274 | |
275 | ret = pcim_enable_device(pdev); | |
276 | if (ret) | |
277 | return ret; | |
278 | ||
279 | ret = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev)); | |
280 | if (ret) | |
281 | return ret; | |
282 | ||
09d4d6da ML |
283 | pci_read_config_word(pdev, PCI_COMMAND, &cmd); |
284 | if (!(cmd & PCI_COMMAND_MEMORY)) { | |
285 | cmd |= PCI_COMMAND_MEMORY; | |
286 | pci_write_config_word(pdev, PCI_COMMAND, cmd); | |
287 | } | |
5c14a5f9 SW |
288 | pci_set_master(pdev); |
289 | ||
eaafabd2 | 290 | ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); |
5c14a5f9 SW |
291 | if (ret < 0) |
292 | return ret; | |
293 | ||
a2e75961 | 294 | ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); |
5c14a5f9 SW |
295 | if (ret) |
296 | goto err_free_pci_vec; | |
297 | ||
bf3747ae SW |
298 | if (mt7921_disable_aspm) |
299 | mt76_pci_disable_aspm(pdev); | |
5c14a5f9 | 300 | |
e8a264cc LB |
301 | ops = mt792x_get_mac80211_ops(&pdev->dev, &mt7921_ops, |
302 | (void *)id->driver_data, &features); | |
034ae28b SW |
303 | if (!ops) { |
304 | ret = -ENOMEM; | |
305 | goto err_free_pci_vec; | |
306 | } | |
307 | ||
034ae28b | 308 | mdev = mt76_alloc_device(&pdev->dev, sizeof(*dev), ops, &drv_ops); |
5c14a5f9 SW |
309 | if (!mdev) { |
310 | ret = -ENOMEM; | |
311 | goto err_free_pci_vec; | |
312 | } | |
313 | ||
b5a62d61 DW |
314 | pci_set_drvdata(pdev, mdev); |
315 | ||
975e122d | 316 | dev = container_of(mdev, struct mt792x_dev, mt76); |
034ae28b | 317 | dev->fw_features = features; |
576b4484 | 318 | dev->hif_ops = &mt7921_pcie_ops; |
c9072f11 | 319 | dev->irq_map = &irq_map; |
5c14a5f9 | 320 | mt76_mmio_init(&dev->mt76, pcim_iomap_table(pdev)[0]); |
ff655174 | 321 | tasklet_init(&mdev->irq_tasklet, mt792x_irq_tasklet, (unsigned long)dev); |
602cc0c9 SW |
322 | |
323 | dev->phy.dev = dev; | |
324 | dev->phy.mt76 = &dev->mt76.phy; | |
325 | dev->mt76.phy.priv = &dev->phy; | |
326 | dev->bus_ops = dev->mt76.bus; | |
327 | bus_ops = devm_kmemdup(dev->mt76.dev, dev->bus_ops, sizeof(*bus_ops), | |
328 | GFP_KERNEL); | |
4e90db5e CJ |
329 | if (!bus_ops) { |
330 | ret = -ENOMEM; | |
331 | goto err_free_dev; | |
332 | } | |
602cc0c9 SW |
333 | |
334 | bus_ops->rr = mt7921_rr; | |
335 | bus_ops->wr = mt7921_wr; | |
336 | bus_ops->rmw = mt7921_rmw; | |
337 | dev->mt76.bus = bus_ops; | |
338 | ||
1c025496 | 339 | ret = mt792xe_mcu_fw_pmctrl(dev); |
525c469e QZ |
340 | if (ret) |
341 | goto err_free_dev; | |
342 | ||
1c025496 | 343 | ret = __mt792xe_mcu_drv_pmctrl(dev); |
602cc0c9 | 344 | if (ret) |
4e90db5e | 345 | goto err_free_dev; |
602cc0c9 | 346 | |
5c14a5f9 SW |
347 | mdev->rev = (mt7921_l1_rr(dev, MT_HW_CHIPID) << 16) | |
348 | (mt7921_l1_rr(dev, MT_HW_REV) & 0xff); | |
81a88b1e | 349 | dev_info(mdev->dev, "ASIC revision: %04x\n", mdev->rev); |
5c14a5f9 | 350 | |
ff655174 | 351 | ret = mt792x_wfsys_reset(dev); |
525c469e QZ |
352 | if (ret) |
353 | goto err_free_dev; | |
354 | ||
c9072f11 | 355 | mt76_wr(dev, irq_map.host_irq_enable, 0); |
5c14a5f9 | 356 | |
23c1d2dc | 357 | mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff); |
5c14a5f9 | 358 | |
ff655174 | 359 | ret = devm_request_irq(mdev->dev, pdev->irq, mt792x_irq_handler, |
5c14a5f9 SW |
360 | IRQF_SHARED, KBUILD_MODNAME, dev); |
361 | if (ret) | |
362 | goto err_free_dev; | |
363 | ||
033ae79b SW |
364 | ret = mt7921_dma_init(dev); |
365 | if (ret) | |
366 | goto err_free_irq; | |
367 | ||
5c14a5f9 SW |
368 | ret = mt7921_register_device(dev); |
369 | if (ret) | |
e230f0c4 | 370 | goto err_free_irq; |
5c14a5f9 SW |
371 | |
372 | return 0; | |
373 | ||
e230f0c4 SW |
374 | err_free_irq: |
375 | devm_free_irq(&pdev->dev, pdev->irq, dev); | |
5c14a5f9 SW |
376 | err_free_dev: |
377 | mt76_free_device(&dev->mt76); | |
378 | err_free_pci_vec: | |
379 | pci_free_irq_vectors(pdev); | |
380 | ||
381 | return ret; | |
382 | } | |
383 | ||
384 | static void mt7921_pci_remove(struct pci_dev *pdev) | |
385 | { | |
386 | struct mt76_dev *mdev = pci_get_drvdata(pdev); | |
975e122d | 387 | struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); |
5c14a5f9 | 388 | |
033ae79b | 389 | mt7921e_unregister_device(dev); |
5c14a5f9 | 390 | devm_free_irq(&pdev->dev, pdev->irq, dev); |
ad483ed9 | 391 | mt76_free_device(&dev->mt76); |
5c14a5f9 SW |
392 | pci_free_irq_vectors(pdev); |
393 | } | |
394 | ||
454b768f | 395 | static int mt7921_pci_suspend(struct device *device) |
ffa1bf97 | 396 | { |
454b768f | 397 | struct pci_dev *pdev = to_pci_dev(device); |
ffa1bf97 | 398 | struct mt76_dev *mdev = pci_get_drvdata(pdev); |
975e122d | 399 | struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); |
f86625ae | 400 | struct mt76_connac_pm *pm = &dev->pm; |
ffa1bf97 SW |
401 | int i, err; |
402 | ||
f86625ae | 403 | pm->suspended = true; |
ff6c4a64 | 404 | flush_work(&dev->reset_work); |
f86625ae SW |
405 | cancel_delayed_work_sync(&pm->ps_work); |
406 | cancel_work_sync(&pm->wake_work); | |
407 | ||
c21a7f9f | 408 | err = mt792x_mcu_drv_pmctrl(dev); |
1d8efc74 | 409 | if (err < 0) |
f86625ae | 410 | goto restore_suspend; |
1d8efc74 | 411 | |
6906aa93 SW |
412 | err = mt76_connac_mcu_set_hif_suspend(mdev, true); |
413 | if (err) | |
414 | goto restore_suspend; | |
ffa1bf97 | 415 | |
495cd981 LB |
416 | /* always enable deep sleep during suspend to reduce |
417 | * power consumption | |
418 | */ | |
419 | mt76_connac_mcu_set_deep_sleep(&dev->mt76, true); | |
1792eb0e | 420 | |
ffa1bf97 SW |
421 | napi_disable(&mdev->tx_napi); |
422 | mt76_worker_disable(&mdev->tx_worker); | |
423 | ||
424 | mt76_for_each_q_rx(mdev, i) { | |
425 | napi_disable(&mdev->napi[i]); | |
426 | } | |
ffa1bf97 | 427 | |
ffa1bf97 SW |
428 | /* wait until dma is idle */ |
429 | mt76_poll(dev, MT_WFDMA0_GLO_CFG, | |
430 | MT_WFDMA0_GLO_CFG_TX_DMA_BUSY | | |
431 | MT_WFDMA0_GLO_CFG_RX_DMA_BUSY, 0, 1000); | |
432 | ||
433 | /* put dma disabled */ | |
434 | mt76_clear(dev, MT_WFDMA0_GLO_CFG, | |
435 | MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN); | |
436 | ||
437 | /* disable interrupt */ | |
c9072f11 | 438 | mt76_wr(dev, dev->irq_map->host_irq_enable, 0); |
fe3fccde SW |
439 | mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0x0); |
440 | synchronize_irq(pdev->irq); | |
ec193b41 | 441 | tasklet_kill(&mdev->irq_tasklet); |
ffa1bf97 | 442 | |
c21a7f9f | 443 | err = mt792x_mcu_fw_pmctrl(dev); |
ffa1bf97 | 444 | if (err) |
f86625ae | 445 | goto restore_napi; |
ffa1bf97 SW |
446 | |
447 | return 0; | |
448 | ||
f86625ae | 449 | restore_napi: |
ffa1bf97 SW |
450 | mt76_for_each_q_rx(mdev, i) { |
451 | napi_enable(&mdev->napi[i]); | |
452 | } | |
453 | napi_enable(&mdev->tx_napi); | |
1792eb0e | 454 | |
495cd981 | 455 | if (!pm->ds_enable) |
1792eb0e SW |
456 | mt76_connac_mcu_set_deep_sleep(&dev->mt76, false); |
457 | ||
6906aa93 | 458 | mt76_connac_mcu_set_hif_suspend(mdev, false); |
ffa1bf97 | 459 | |
f86625ae SW |
460 | restore_suspend: |
461 | pm->suspended = false; | |
462 | ||
ff6c4a64 | 463 | if (err < 0) |
311f121c | 464 | mt792x_reset(&dev->mt76); |
ff6c4a64 | 465 | |
ffa1bf97 SW |
466 | return err; |
467 | } | |
468 | ||
454b768f | 469 | static int mt7921_pci_resume(struct device *device) |
ffa1bf97 | 470 | { |
454b768f | 471 | struct pci_dev *pdev = to_pci_dev(device); |
ffa1bf97 | 472 | struct mt76_dev *mdev = pci_get_drvdata(pdev); |
975e122d | 473 | struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); |
495cd981 | 474 | struct mt76_connac_pm *pm = &dev->pm; |
ffa1bf97 SW |
475 | int i, err; |
476 | ||
c21a7f9f | 477 | err = mt792x_mcu_drv_pmctrl(dev); |
5e309314 | 478 | if (err < 0) |
ff6c4a64 | 479 | goto failed; |
5e309314 | 480 | |
ff655174 | 481 | mt792x_wpdma_reinit_cond(dev); |
1792eb0e | 482 | |
ffa1bf97 | 483 | /* enable interrupt */ |
23c1d2dc | 484 | mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff); |
4fc44156 | 485 | mt76_connac_irq_enable(&dev->mt76, |
c9072f11 LB |
486 | dev->irq_map->tx.all_complete_mask | |
487 | MT_INT_RX_DONE_ALL | MT_INT_MCU_CMD); | |
dc5d5f9d | 488 | mt76_set(dev, MT_MCU2HOST_SW_INT_ENA, MT_MCU_CMD_WAKE_RX_PCIE); |
ffa1bf97 SW |
489 | |
490 | /* put dma enabled */ | |
491 | mt76_set(dev, MT_WFDMA0_GLO_CFG, | |
492 | MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN); | |
493 | ||
494 | mt76_worker_enable(&mdev->tx_worker); | |
970be1df FF |
495 | |
496 | local_bh_disable(); | |
ffa1bf97 SW |
497 | mt76_for_each_q_rx(mdev, i) { |
498 | napi_enable(&mdev->napi[i]); | |
499 | napi_schedule(&mdev->napi[i]); | |
500 | } | |
501 | napi_enable(&mdev->tx_napi); | |
502 | napi_schedule(&mdev->tx_napi); | |
970be1df | 503 | local_bh_enable(); |
ffa1bf97 | 504 | |
495cd981 LB |
505 | /* restore previous ds setting */ |
506 | if (!pm->ds_enable) | |
1792eb0e SW |
507 | mt76_connac_mcu_set_deep_sleep(&dev->mt76, false); |
508 | ||
5375001b | 509 | err = mt76_connac_mcu_set_hif_suspend(mdev, false); |
d0a2bc5f MYH |
510 | |
511 | mt7921_regd_update(dev); | |
512 | ||
ff6c4a64 | 513 | failed: |
5375001b SW |
514 | pm->suspended = false; |
515 | ||
ff6c4a64 | 516 | if (err < 0) |
311f121c | 517 | mt792x_reset(&dev->mt76); |
ff6c4a64 | 518 | |
5375001b | 519 | return err; |
ffa1bf97 | 520 | } |
454b768f | 521 | |
f23a0cea LY |
522 | static void mt7921_pci_shutdown(struct pci_dev *pdev) |
523 | { | |
9270270d | 524 | mt7921_pci_remove(pdev); |
f23a0cea LY |
525 | } |
526 | ||
454b768f | 527 | static DEFINE_SIMPLE_DEV_PM_OPS(mt7921_pm_ops, mt7921_pci_suspend, mt7921_pci_resume); |
ffa1bf97 | 528 | |
81f302fd | 529 | static struct pci_driver mt7921_pci_driver = { |
5c14a5f9 SW |
530 | .name = KBUILD_MODNAME, |
531 | .id_table = mt7921_pci_device_table, | |
532 | .probe = mt7921_pci_probe, | |
533 | .remove = mt7921_pci_remove, | |
f23a0cea | 534 | .shutdown = mt7921_pci_shutdown, |
454b768f | 535 | .driver.pm = pm_sleep_ptr(&mt7921_pm_ops), |
5c14a5f9 SW |
536 | }; |
537 | ||
538 | module_pci_driver(mt7921_pci_driver); | |
539 | ||
540 | MODULE_DEVICE_TABLE(pci, mt7921_pci_device_table); | |
541 | MODULE_FIRMWARE(MT7921_FIRMWARE_WM); | |
542 | MODULE_FIRMWARE(MT7921_ROM_PATCH); | |
68808872 DW |
543 | MODULE_FIRMWARE(MT7922_FIRMWARE_WM); |
544 | MODULE_FIRMWARE(MT7922_ROM_PATCH); | |
5c14a5f9 SW |
545 | MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>"); |
546 | MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>"); | |
f3f8f050 | 547 | MODULE_DESCRIPTION("MediaTek MT7921E (PCIe) wireless driver"); |
5c14a5f9 | 548 | MODULE_LICENSE("Dual BSD/GPL"); |