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 "mt76x0.h" 118c2ecf20Sopenharmony_ci#include "mcu.h" 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_cistatic int mt76x0e_start(struct ieee80211_hw *hw) 148c2ecf20Sopenharmony_ci{ 158c2ecf20Sopenharmony_ci struct mt76x02_dev *dev = hw->priv; 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci mt76x02_mac_start(dev); 188c2ecf20Sopenharmony_ci mt76x0_phy_calibrate(dev, true); 198c2ecf20Sopenharmony_ci ieee80211_queue_delayed_work(dev->mt76.hw, &dev->mt76.mac_work, 208c2ecf20Sopenharmony_ci MT_MAC_WORK_INTERVAL); 218c2ecf20Sopenharmony_ci ieee80211_queue_delayed_work(dev->mt76.hw, &dev->cal_work, 228c2ecf20Sopenharmony_ci MT_CALIBRATE_INTERVAL); 238c2ecf20Sopenharmony_ci set_bit(MT76_STATE_RUNNING, &dev->mphy.state); 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci return 0; 268c2ecf20Sopenharmony_ci} 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic void mt76x0e_stop_hw(struct mt76x02_dev *dev) 298c2ecf20Sopenharmony_ci{ 308c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&dev->cal_work); 318c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&dev->mt76.mac_work); 328c2ecf20Sopenharmony_ci clear_bit(MT76_RESTART, &dev->mphy.state); 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci if (!mt76_poll(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_BUSY, 358c2ecf20Sopenharmony_ci 0, 1000)) 368c2ecf20Sopenharmony_ci dev_warn(dev->mt76.dev, "TX DMA did not stop\n"); 378c2ecf20Sopenharmony_ci mt76_clear(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_EN); 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci mt76x0_mac_stop(dev); 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci if (!mt76_poll(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_RX_DMA_BUSY, 428c2ecf20Sopenharmony_ci 0, 1000)) 438c2ecf20Sopenharmony_ci dev_warn(dev->mt76.dev, "TX DMA did not stop\n"); 448c2ecf20Sopenharmony_ci mt76_clear(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_RX_DMA_EN); 458c2ecf20Sopenharmony_ci} 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistatic void mt76x0e_stop(struct ieee80211_hw *hw) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci struct mt76x02_dev *dev = hw->priv; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci clear_bit(MT76_STATE_RUNNING, &dev->mphy.state); 528c2ecf20Sopenharmony_ci mt76x0e_stop_hw(dev); 538c2ecf20Sopenharmony_ci} 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic void 568c2ecf20Sopenharmony_cimt76x0e_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 578c2ecf20Sopenharmony_ci u32 queues, bool drop) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistatic const struct ieee80211_ops mt76x0e_ops = { 628c2ecf20Sopenharmony_ci .tx = mt76x02_tx, 638c2ecf20Sopenharmony_ci .start = mt76x0e_start, 648c2ecf20Sopenharmony_ci .stop = mt76x0e_stop, 658c2ecf20Sopenharmony_ci .add_interface = mt76x02_add_interface, 668c2ecf20Sopenharmony_ci .remove_interface = mt76x02_remove_interface, 678c2ecf20Sopenharmony_ci .config = mt76x0_config, 688c2ecf20Sopenharmony_ci .configure_filter = mt76x02_configure_filter, 698c2ecf20Sopenharmony_ci .bss_info_changed = mt76x02_bss_info_changed, 708c2ecf20Sopenharmony_ci .sta_state = mt76_sta_state, 718c2ecf20Sopenharmony_ci .sta_pre_rcu_remove = mt76_sta_pre_rcu_remove, 728c2ecf20Sopenharmony_ci .set_key = mt76x02_set_key, 738c2ecf20Sopenharmony_ci .conf_tx = mt76x02_conf_tx, 748c2ecf20Sopenharmony_ci .sw_scan_start = mt76_sw_scan, 758c2ecf20Sopenharmony_ci .sw_scan_complete = mt76x02_sw_scan_complete, 768c2ecf20Sopenharmony_ci .ampdu_action = mt76x02_ampdu_action, 778c2ecf20Sopenharmony_ci .sta_rate_tbl_update = mt76x02_sta_rate_tbl_update, 788c2ecf20Sopenharmony_ci .wake_tx_queue = mt76_wake_tx_queue, 798c2ecf20Sopenharmony_ci .get_survey = mt76_get_survey, 808c2ecf20Sopenharmony_ci .get_txpower = mt76_get_txpower, 818c2ecf20Sopenharmony_ci .flush = mt76x0e_flush, 828c2ecf20Sopenharmony_ci .set_tim = mt76_set_tim, 838c2ecf20Sopenharmony_ci .release_buffered_frames = mt76_release_buffered_frames, 848c2ecf20Sopenharmony_ci .set_coverage_class = mt76x02_set_coverage_class, 858c2ecf20Sopenharmony_ci .set_rts_threshold = mt76x02_set_rts_threshold, 868c2ecf20Sopenharmony_ci .get_antenna = mt76_get_antenna, 878c2ecf20Sopenharmony_ci .reconfig_complete = mt76x02_reconfig_complete, 888c2ecf20Sopenharmony_ci}; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistatic int mt76x0e_register_device(struct mt76x02_dev *dev) 918c2ecf20Sopenharmony_ci{ 928c2ecf20Sopenharmony_ci int err; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci mt76x0_chip_onoff(dev, true, false); 958c2ecf20Sopenharmony_ci if (!mt76x02_wait_for_mac(&dev->mt76)) 968c2ecf20Sopenharmony_ci return -ETIMEDOUT; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci mt76x02_dma_disable(dev); 998c2ecf20Sopenharmony_ci err = mt76x0e_mcu_init(dev); 1008c2ecf20Sopenharmony_ci if (err < 0) 1018c2ecf20Sopenharmony_ci return err; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci err = mt76x02_dma_init(dev); 1048c2ecf20Sopenharmony_ci if (err < 0) 1058c2ecf20Sopenharmony_ci return err; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci err = mt76x0_init_hardware(dev); 1088c2ecf20Sopenharmony_ci if (err < 0) 1098c2ecf20Sopenharmony_ci return err; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci mt76x02e_init_beacon_config(dev); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci if (mt76_chip(&dev->mt76) == 0x7610) { 1148c2ecf20Sopenharmony_ci u16 val; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci mt76_clear(dev, MT_COEXCFG0, BIT(0)); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci val = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_0); 1198c2ecf20Sopenharmony_ci if (!(val & MT_EE_NIC_CONF_0_PA_IO_CURRENT)) 1208c2ecf20Sopenharmony_ci mt76_set(dev, MT_XO_CTRL7, 0xc03); 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci mt76_clear(dev, 0x110, BIT(9)); 1248c2ecf20Sopenharmony_ci mt76_set(dev, MT_MAX_LEN_CFG, BIT(13)); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci err = mt76x0_register_device(dev); 1278c2ecf20Sopenharmony_ci if (err < 0) 1288c2ecf20Sopenharmony_ci return err; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci set_bit(MT76_STATE_INITIALIZED, &dev->mphy.state); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci return 0; 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic int 1368c2ecf20Sopenharmony_cimt76x0e_probe(struct pci_dev *pdev, const struct pci_device_id *id) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci static const struct mt76_driver_ops drv_ops = { 1398c2ecf20Sopenharmony_ci .txwi_size = sizeof(struct mt76x02_txwi), 1408c2ecf20Sopenharmony_ci .drv_flags = MT_DRV_TX_ALIGNED4_SKBS | 1418c2ecf20Sopenharmony_ci MT_DRV_SW_RX_AIRTIME, 1428c2ecf20Sopenharmony_ci .survey_flags = SURVEY_INFO_TIME_TX, 1438c2ecf20Sopenharmony_ci .update_survey = mt76x02_update_channel, 1448c2ecf20Sopenharmony_ci .tx_prepare_skb = mt76x02_tx_prepare_skb, 1458c2ecf20Sopenharmony_ci .tx_complete_skb = mt76x02_tx_complete_skb, 1468c2ecf20Sopenharmony_ci .rx_skb = mt76x02_queue_rx_skb, 1478c2ecf20Sopenharmony_ci .rx_poll_complete = mt76x02_rx_poll_complete, 1488c2ecf20Sopenharmony_ci .sta_ps = mt76x02_sta_ps, 1498c2ecf20Sopenharmony_ci .sta_add = mt76x02_sta_add, 1508c2ecf20Sopenharmony_ci .sta_remove = mt76x02_sta_remove, 1518c2ecf20Sopenharmony_ci }; 1528c2ecf20Sopenharmony_ci struct mt76x02_dev *dev; 1538c2ecf20Sopenharmony_ci struct mt76_dev *mdev; 1548c2ecf20Sopenharmony_ci int ret; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci ret = pcim_enable_device(pdev); 1578c2ecf20Sopenharmony_ci if (ret) 1588c2ecf20Sopenharmony_ci return ret; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci ret = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev)); 1618c2ecf20Sopenharmony_ci if (ret) 1628c2ecf20Sopenharmony_ci return ret; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci pci_set_master(pdev); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); 1678c2ecf20Sopenharmony_ci if (ret) 1688c2ecf20Sopenharmony_ci return ret; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci mdev = mt76_alloc_device(&pdev->dev, sizeof(*dev), &mt76x0e_ops, 1718c2ecf20Sopenharmony_ci &drv_ops); 1728c2ecf20Sopenharmony_ci if (!mdev) 1738c2ecf20Sopenharmony_ci return -ENOMEM; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci dev = container_of(mdev, struct mt76x02_dev, mt76); 1768c2ecf20Sopenharmony_ci mutex_init(&dev->phy_mutex); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci mt76_mmio_init(mdev, pcim_iomap_table(pdev)[0]); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci mdev->rev = mt76_rr(dev, MT_ASIC_VERSION); 1818c2ecf20Sopenharmony_ci dev_info(mdev->dev, "ASIC revision: %08x\n", mdev->rev); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci mt76_wr(dev, MT_INT_MASK_CSR, 0); 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci ret = devm_request_irq(mdev->dev, pdev->irq, mt76x02_irq_handler, 1868c2ecf20Sopenharmony_ci IRQF_SHARED, KBUILD_MODNAME, dev); 1878c2ecf20Sopenharmony_ci if (ret) 1888c2ecf20Sopenharmony_ci goto error; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci ret = mt76x0e_register_device(dev); 1918c2ecf20Sopenharmony_ci if (ret < 0) 1928c2ecf20Sopenharmony_ci goto error; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci return 0; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_cierror: 1978c2ecf20Sopenharmony_ci mt76_free_device(&dev->mt76); 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci return ret; 2008c2ecf20Sopenharmony_ci} 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_cistatic void mt76x0e_cleanup(struct mt76x02_dev *dev) 2038c2ecf20Sopenharmony_ci{ 2048c2ecf20Sopenharmony_ci clear_bit(MT76_STATE_INITIALIZED, &dev->mphy.state); 2058c2ecf20Sopenharmony_ci tasklet_disable(&dev->mt76.pre_tbtt_tasklet); 2068c2ecf20Sopenharmony_ci mt76x0_chip_onoff(dev, false, false); 2078c2ecf20Sopenharmony_ci mt76x0e_stop_hw(dev); 2088c2ecf20Sopenharmony_ci mt76_dma_cleanup(&dev->mt76); 2098c2ecf20Sopenharmony_ci mt76x02_mcu_cleanup(dev); 2108c2ecf20Sopenharmony_ci} 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_cistatic void 2138c2ecf20Sopenharmony_cimt76x0e_remove(struct pci_dev *pdev) 2148c2ecf20Sopenharmony_ci{ 2158c2ecf20Sopenharmony_ci struct mt76_dev *mdev = pci_get_drvdata(pdev); 2168c2ecf20Sopenharmony_ci struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci mt76_unregister_device(mdev); 2198c2ecf20Sopenharmony_ci mt76x0e_cleanup(dev); 2208c2ecf20Sopenharmony_ci mt76_free_device(mdev); 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_cistatic const struct pci_device_id mt76x0e_device_table[] = { 2248c2ecf20Sopenharmony_ci { PCI_DEVICE(0x14c3, 0x7610) }, 2258c2ecf20Sopenharmony_ci { PCI_DEVICE(0x14c3, 0x7630) }, 2268c2ecf20Sopenharmony_ci { PCI_DEVICE(0x14c3, 0x7650) }, 2278c2ecf20Sopenharmony_ci { }, 2288c2ecf20Sopenharmony_ci}; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, mt76x0e_device_table); 2318c2ecf20Sopenharmony_ciMODULE_FIRMWARE(MT7610E_FIRMWARE); 2328c2ecf20Sopenharmony_ciMODULE_FIRMWARE(MT7650E_FIRMWARE); 2338c2ecf20Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_cistatic struct pci_driver mt76x0e_driver = { 2368c2ecf20Sopenharmony_ci .name = KBUILD_MODNAME, 2378c2ecf20Sopenharmony_ci .id_table = mt76x0e_device_table, 2388c2ecf20Sopenharmony_ci .probe = mt76x0e_probe, 2398c2ecf20Sopenharmony_ci .remove = mt76x0e_remove, 2408c2ecf20Sopenharmony_ci}; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_cimodule_pci_driver(mt76x0e_driver); 243