18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: ISC 28c2ecf20Sopenharmony_ci/* Copyright (C) 2019 MediaTek Inc. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Author: Ryder Lee <ryder.lee@mediatek.com> 58c2ecf20Sopenharmony_ci * Felix Fietkau <nbd@nbd.name> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/kernel.h> 98c2ecf20Sopenharmony_ci#include <linux/module.h> 108c2ecf20Sopenharmony_ci#include <linux/pci.h> 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include "mt7615.h" 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_cistatic const struct pci_device_id mt7615_pci_device_table[] = { 158c2ecf20Sopenharmony_ci { PCI_DEVICE(0x14c3, 0x7615) }, 168c2ecf20Sopenharmony_ci { PCI_DEVICE(0x14c3, 0x7663) }, 178c2ecf20Sopenharmony_ci { PCI_DEVICE(0x14c3, 0x7611) }, 188c2ecf20Sopenharmony_ci { }, 198c2ecf20Sopenharmony_ci}; 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cistatic int mt7615_pci_probe(struct pci_dev *pdev, 228c2ecf20Sopenharmony_ci const struct pci_device_id *id) 238c2ecf20Sopenharmony_ci{ 248c2ecf20Sopenharmony_ci const u32 *map; 258c2ecf20Sopenharmony_ci int ret; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci ret = pcim_enable_device(pdev); 288c2ecf20Sopenharmony_ci if (ret) 298c2ecf20Sopenharmony_ci return ret; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci ret = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev)); 328c2ecf20Sopenharmony_ci if (ret) 338c2ecf20Sopenharmony_ci return ret; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci pci_set_master(pdev); 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); 388c2ecf20Sopenharmony_ci if (ret < 0) 398c2ecf20Sopenharmony_ci return ret; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); 428c2ecf20Sopenharmony_ci if (ret) 438c2ecf20Sopenharmony_ci goto error; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci mt76_pci_disable_aspm(pdev); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci map = id->device == 0x7663 ? mt7663e_reg_map : mt7615e_reg_map; 488c2ecf20Sopenharmony_ci ret = mt7615_mmio_probe(&pdev->dev, pcim_iomap_table(pdev)[0], 498c2ecf20Sopenharmony_ci pdev->irq, map); 508c2ecf20Sopenharmony_ci if (ret) 518c2ecf20Sopenharmony_ci goto error; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci return 0; 548c2ecf20Sopenharmony_cierror: 558c2ecf20Sopenharmony_ci pci_free_irq_vectors(pdev); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci return ret; 588c2ecf20Sopenharmony_ci} 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistatic void mt7615_pci_remove(struct pci_dev *pdev) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci struct mt76_dev *mdev = pci_get_drvdata(pdev); 638c2ecf20Sopenharmony_ci struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci mt7615_unregister_device(dev); 668c2ecf20Sopenharmony_ci devm_free_irq(&pdev->dev, pdev->irq, dev); 678c2ecf20Sopenharmony_ci pci_free_irq_vectors(pdev); 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 718c2ecf20Sopenharmony_cistatic int mt7615_pci_suspend(struct pci_dev *pdev, pm_message_t state) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci struct mt76_dev *mdev = pci_get_drvdata(pdev); 748c2ecf20Sopenharmony_ci struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); 758c2ecf20Sopenharmony_ci bool hif_suspend; 768c2ecf20Sopenharmony_ci int i, err; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci err = mt7615_pm_wake(dev); 798c2ecf20Sopenharmony_ci if (err < 0) 808c2ecf20Sopenharmony_ci return err; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci hif_suspend = !test_bit(MT76_STATE_SUSPEND, &dev->mphy.state) && 838c2ecf20Sopenharmony_ci mt7615_firmware_offload(dev); 848c2ecf20Sopenharmony_ci if (hif_suspend) { 858c2ecf20Sopenharmony_ci err = mt7615_mcu_set_hif_suspend(dev, true); 868c2ecf20Sopenharmony_ci if (err) 878c2ecf20Sopenharmony_ci return err; 888c2ecf20Sopenharmony_ci } 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci napi_disable(&mdev->tx_napi); 918c2ecf20Sopenharmony_ci mt76_worker_disable(&mdev->tx_worker); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci mt76_for_each_q_rx(mdev, i) { 948c2ecf20Sopenharmony_ci napi_disable(&mdev->napi[i]); 958c2ecf20Sopenharmony_ci } 968c2ecf20Sopenharmony_ci tasklet_kill(&dev->irq_tasklet); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci mt7615_dma_reset(dev); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci err = mt7615_wait_pdma_busy(dev); 1018c2ecf20Sopenharmony_ci if (err) 1028c2ecf20Sopenharmony_ci goto restore; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci if (is_mt7663(mdev)) { 1058c2ecf20Sopenharmony_ci mt76_set(dev, MT_PDMA_SLP_PROT, MT_PDMA_AXI_SLPPROT_ENABLE); 1068c2ecf20Sopenharmony_ci if (!mt76_poll_msec(dev, MT_PDMA_SLP_PROT, 1078c2ecf20Sopenharmony_ci MT_PDMA_AXI_SLPPROT_RDY, 1088c2ecf20Sopenharmony_ci MT_PDMA_AXI_SLPPROT_RDY, 1000)) { 1098c2ecf20Sopenharmony_ci dev_err(mdev->dev, "PDMA sleep protection failed\n"); 1108c2ecf20Sopenharmony_ci err = -EIO; 1118c2ecf20Sopenharmony_ci goto restore; 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci pci_enable_wake(pdev, pci_choose_state(pdev, state), true); 1168c2ecf20Sopenharmony_ci pci_save_state(pdev); 1178c2ecf20Sopenharmony_ci err = pci_set_power_state(pdev, pci_choose_state(pdev, state)); 1188c2ecf20Sopenharmony_ci if (err) 1198c2ecf20Sopenharmony_ci goto restore; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci err = mt7615_mcu_set_fw_ctrl(dev); 1228c2ecf20Sopenharmony_ci if (err) 1238c2ecf20Sopenharmony_ci goto restore; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci return 0; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cirestore: 1288c2ecf20Sopenharmony_ci mt76_for_each_q_rx(mdev, i) { 1298c2ecf20Sopenharmony_ci napi_enable(&mdev->napi[i]); 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci napi_enable(&mdev->tx_napi); 1328c2ecf20Sopenharmony_ci if (hif_suspend) 1338c2ecf20Sopenharmony_ci mt7615_mcu_set_hif_suspend(dev, false); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci return err; 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistatic int mt7615_pci_resume(struct pci_dev *pdev) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci struct mt76_dev *mdev = pci_get_drvdata(pdev); 1418c2ecf20Sopenharmony_ci struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); 1428c2ecf20Sopenharmony_ci bool pdma_reset; 1438c2ecf20Sopenharmony_ci int i, err; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci err = mt7615_mcu_set_drv_ctrl(dev); 1468c2ecf20Sopenharmony_ci if (err < 0) 1478c2ecf20Sopenharmony_ci return err; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci err = pci_set_power_state(pdev, PCI_D0); 1508c2ecf20Sopenharmony_ci if (err) 1518c2ecf20Sopenharmony_ci return err; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci pci_restore_state(pdev); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci if (is_mt7663(&dev->mt76)) { 1568c2ecf20Sopenharmony_ci mt76_clear(dev, MT_PDMA_SLP_PROT, MT_PDMA_AXI_SLPPROT_ENABLE); 1578c2ecf20Sopenharmony_ci mt76_wr(dev, MT_PCIE_IRQ_ENABLE, 1); 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci pdma_reset = !mt76_rr(dev, MT_WPDMA_TX_RING0_CTRL0) && 1618c2ecf20Sopenharmony_ci !mt76_rr(dev, MT_WPDMA_TX_RING0_CTRL1); 1628c2ecf20Sopenharmony_ci if (pdma_reset) 1638c2ecf20Sopenharmony_ci dev_err(mdev->dev, "PDMA engine must be reinitialized\n"); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci mt76_worker_enable(&mdev->tx_worker); 1668c2ecf20Sopenharmony_ci mt76_for_each_q_rx(mdev, i) { 1678c2ecf20Sopenharmony_ci napi_enable(&mdev->napi[i]); 1688c2ecf20Sopenharmony_ci napi_schedule(&mdev->napi[i]); 1698c2ecf20Sopenharmony_ci } 1708c2ecf20Sopenharmony_ci napi_enable(&mdev->tx_napi); 1718c2ecf20Sopenharmony_ci napi_schedule(&mdev->tx_napi); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci if (!test_bit(MT76_STATE_SUSPEND, &dev->mphy.state) && 1748c2ecf20Sopenharmony_ci mt7615_firmware_offload(dev)) 1758c2ecf20Sopenharmony_ci err = mt7615_mcu_set_hif_suspend(dev, false); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci return err; 1788c2ecf20Sopenharmony_ci} 1798c2ecf20Sopenharmony_ci#endif /* CONFIG_PM */ 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistruct pci_driver mt7615_pci_driver = { 1828c2ecf20Sopenharmony_ci .name = KBUILD_MODNAME, 1838c2ecf20Sopenharmony_ci .id_table = mt7615_pci_device_table, 1848c2ecf20Sopenharmony_ci .probe = mt7615_pci_probe, 1858c2ecf20Sopenharmony_ci .remove = mt7615_pci_remove, 1868c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 1878c2ecf20Sopenharmony_ci .suspend = mt7615_pci_suspend, 1888c2ecf20Sopenharmony_ci .resume = mt7615_pci_resume, 1898c2ecf20Sopenharmony_ci#endif /* CONFIG_PM */ 1908c2ecf20Sopenharmony_ci}; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, mt7615_pci_device_table); 1938c2ecf20Sopenharmony_ciMODULE_FIRMWARE(MT7615_FIRMWARE_CR4); 1948c2ecf20Sopenharmony_ciMODULE_FIRMWARE(MT7615_FIRMWARE_N9); 1958c2ecf20Sopenharmony_ciMODULE_FIRMWARE(MT7615_ROM_PATCH); 1968c2ecf20Sopenharmony_ciMODULE_FIRMWARE(MT7663_OFFLOAD_FIRMWARE_N9); 1978c2ecf20Sopenharmony_ciMODULE_FIRMWARE(MT7663_OFFLOAD_ROM_PATCH); 1988c2ecf20Sopenharmony_ciMODULE_FIRMWARE(MT7663_FIRMWARE_N9); 1998c2ecf20Sopenharmony_ciMODULE_FIRMWARE(MT7663_ROM_PATCH); 200