18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: ISC 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/kernel.h> 78c2ecf20Sopenharmony_ci#include <linux/module.h> 88c2ecf20Sopenharmony_ci#include <linux/pci.h> 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include "mt76x2.h" 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_cistatic const struct pci_device_id mt76x2e_device_table[] = { 138c2ecf20Sopenharmony_ci { PCI_DEVICE(0x14c3, 0x7662) }, 148c2ecf20Sopenharmony_ci { PCI_DEVICE(0x14c3, 0x7612) }, 158c2ecf20Sopenharmony_ci { PCI_DEVICE(0x14c3, 0x7602) }, 168c2ecf20Sopenharmony_ci { }, 178c2ecf20Sopenharmony_ci}; 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistatic int 208c2ecf20Sopenharmony_cimt76x2e_probe(struct pci_dev *pdev, const struct pci_device_id *id) 218c2ecf20Sopenharmony_ci{ 228c2ecf20Sopenharmony_ci static const struct mt76_driver_ops drv_ops = { 238c2ecf20Sopenharmony_ci .txwi_size = sizeof(struct mt76x02_txwi), 248c2ecf20Sopenharmony_ci .drv_flags = MT_DRV_TX_ALIGNED4_SKBS | 258c2ecf20Sopenharmony_ci MT_DRV_SW_RX_AIRTIME, 268c2ecf20Sopenharmony_ci .survey_flags = SURVEY_INFO_TIME_TX, 278c2ecf20Sopenharmony_ci .update_survey = mt76x02_update_channel, 288c2ecf20Sopenharmony_ci .tx_prepare_skb = mt76x02_tx_prepare_skb, 298c2ecf20Sopenharmony_ci .tx_complete_skb = mt76x02_tx_complete_skb, 308c2ecf20Sopenharmony_ci .rx_skb = mt76x02_queue_rx_skb, 318c2ecf20Sopenharmony_ci .rx_poll_complete = mt76x02_rx_poll_complete, 328c2ecf20Sopenharmony_ci .sta_ps = mt76x02_sta_ps, 338c2ecf20Sopenharmony_ci .sta_add = mt76x02_sta_add, 348c2ecf20Sopenharmony_ci .sta_remove = mt76x02_sta_remove, 358c2ecf20Sopenharmony_ci }; 368c2ecf20Sopenharmony_ci struct mt76x02_dev *dev; 378c2ecf20Sopenharmony_ci struct mt76_dev *mdev; 388c2ecf20Sopenharmony_ci int ret; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci ret = pcim_enable_device(pdev); 418c2ecf20Sopenharmony_ci if (ret) 428c2ecf20Sopenharmony_ci return ret; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci ret = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev)); 458c2ecf20Sopenharmony_ci if (ret) 468c2ecf20Sopenharmony_ci return ret; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci pci_set_master(pdev); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); 518c2ecf20Sopenharmony_ci if (ret) 528c2ecf20Sopenharmony_ci return ret; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci mdev = mt76_alloc_device(&pdev->dev, sizeof(*dev), &mt76x2_ops, 558c2ecf20Sopenharmony_ci &drv_ops); 568c2ecf20Sopenharmony_ci if (!mdev) 578c2ecf20Sopenharmony_ci return -ENOMEM; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci dev = container_of(mdev, struct mt76x02_dev, mt76); 608c2ecf20Sopenharmony_ci mt76_mmio_init(mdev, pcim_iomap_table(pdev)[0]); 618c2ecf20Sopenharmony_ci mt76x2_reset_wlan(dev, false); 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci mdev->rev = mt76_rr(dev, MT_ASIC_VERSION); 648c2ecf20Sopenharmony_ci dev_info(mdev->dev, "ASIC revision: %08x\n", mdev->rev); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci mt76_wr(dev, MT_INT_MASK_CSR, 0); 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci ret = devm_request_irq(mdev->dev, pdev->irq, mt76x02_irq_handler, 698c2ecf20Sopenharmony_ci IRQF_SHARED, KBUILD_MODNAME, dev); 708c2ecf20Sopenharmony_ci if (ret) 718c2ecf20Sopenharmony_ci goto error; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci ret = mt76x2_register_device(dev); 748c2ecf20Sopenharmony_ci if (ret) 758c2ecf20Sopenharmony_ci goto error; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci /* Fix up ASPM configuration */ 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci /* RG_SSUSB_G1_CDR_BIR_LTR = 0x9 */ 808c2ecf20Sopenharmony_ci mt76_rmw_field(dev, 0x15a10, 0x1f << 16, 0x9); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci /* RG_SSUSB_G1_CDR_BIC_LTR = 0xf */ 838c2ecf20Sopenharmony_ci mt76_rmw_field(dev, 0x15a0c, 0xfU << 28, 0xf); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci /* RG_SSUSB_CDR_BR_PE1D = 0x3 */ 868c2ecf20Sopenharmony_ci mt76_rmw_field(dev, 0x15c58, 0x3 << 6, 0x3); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci mt76_pci_disable_aspm(pdev); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci return 0; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cierror: 938c2ecf20Sopenharmony_ci mt76_free_device(&dev->mt76); 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci return ret; 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistatic void 998c2ecf20Sopenharmony_cimt76x2e_remove(struct pci_dev *pdev) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci struct mt76_dev *mdev = pci_get_drvdata(pdev); 1028c2ecf20Sopenharmony_ci struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci mt76_unregister_device(mdev); 1058c2ecf20Sopenharmony_ci mt76x2_cleanup(dev); 1068c2ecf20Sopenharmony_ci mt76_free_device(mdev); 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic int __maybe_unused 1108c2ecf20Sopenharmony_cimt76x2e_suspend(struct pci_dev *pdev, pm_message_t state) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci struct mt76_dev *mdev = pci_get_drvdata(pdev); 1138c2ecf20Sopenharmony_ci int i, err; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci napi_disable(&mdev->tx_napi); 1168c2ecf20Sopenharmony_ci tasklet_kill(&mdev->pre_tbtt_tasklet); 1178c2ecf20Sopenharmony_ci mt76_worker_disable(&mdev->tx_worker); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci mt76_for_each_q_rx(mdev, i) 1208c2ecf20Sopenharmony_ci napi_disable(&mdev->napi[i]); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci pci_enable_wake(pdev, pci_choose_state(pdev, state), true); 1238c2ecf20Sopenharmony_ci pci_save_state(pdev); 1248c2ecf20Sopenharmony_ci err = pci_set_power_state(pdev, pci_choose_state(pdev, state)); 1258c2ecf20Sopenharmony_ci if (err) 1268c2ecf20Sopenharmony_ci goto restore; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci return 0; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cirestore: 1318c2ecf20Sopenharmony_ci mt76_for_each_q_rx(mdev, i) 1328c2ecf20Sopenharmony_ci napi_enable(&mdev->napi[i]); 1338c2ecf20Sopenharmony_ci napi_enable(&mdev->tx_napi); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci return err; 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistatic int __maybe_unused 1398c2ecf20Sopenharmony_cimt76x2e_resume(struct pci_dev *pdev) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci struct mt76_dev *mdev = pci_get_drvdata(pdev); 1428c2ecf20Sopenharmony_ci struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); 1438c2ecf20Sopenharmony_ci int i, err; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci err = pci_set_power_state(pdev, PCI_D0); 1468c2ecf20Sopenharmony_ci if (err) 1478c2ecf20Sopenharmony_ci return err; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci pci_restore_state(pdev); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci mt76_worker_enable(&mdev->tx_worker); 1528c2ecf20Sopenharmony_ci mt76_for_each_q_rx(mdev, i) { 1538c2ecf20Sopenharmony_ci napi_enable(&mdev->napi[i]); 1548c2ecf20Sopenharmony_ci napi_schedule(&mdev->napi[i]); 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci napi_enable(&mdev->tx_napi); 1578c2ecf20Sopenharmony_ci napi_schedule(&mdev->tx_napi); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci return mt76x2_resume_device(dev); 1608c2ecf20Sopenharmony_ci} 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, mt76x2e_device_table); 1638c2ecf20Sopenharmony_ciMODULE_FIRMWARE(MT7662_FIRMWARE); 1648c2ecf20Sopenharmony_ciMODULE_FIRMWARE(MT7662_ROM_PATCH); 1658c2ecf20Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_cistatic struct pci_driver mt76pci_driver = { 1688c2ecf20Sopenharmony_ci .name = KBUILD_MODNAME, 1698c2ecf20Sopenharmony_ci .id_table = mt76x2e_device_table, 1708c2ecf20Sopenharmony_ci .probe = mt76x2e_probe, 1718c2ecf20Sopenharmony_ci .remove = mt76x2e_remove, 1728c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 1738c2ecf20Sopenharmony_ci .suspend = mt76x2e_suspend, 1748c2ecf20Sopenharmony_ci .resume = mt76x2e_resume, 1758c2ecf20Sopenharmony_ci#endif /* CONFIG_PM */ 1768c2ecf20Sopenharmony_ci}; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_cimodule_pci_driver(mt76pci_driver); 179