162306a36Sopenharmony_ci// SPDX-License-Identifier: ISC 262306a36Sopenharmony_ci/* Copyright (C) 2022 MediaTek Inc. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Author: Lorenzo Bianconi <lorenzo@kernel.org> 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/kernel.h> 862306a36Sopenharmony_ci#include <linux/module.h> 962306a36Sopenharmony_ci#include <linux/usb.h> 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include "mt7921.h" 1262306a36Sopenharmony_ci#include "mcu.h" 1362306a36Sopenharmony_ci#include "../mt76_connac2_mac.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_cistatic const struct usb_device_id mt7921u_device_table[] = { 1662306a36Sopenharmony_ci { USB_DEVICE_AND_INTERFACE_INFO(0x0e8d, 0x7961, 0xff, 0xff, 0xff), 1762306a36Sopenharmony_ci .driver_info = (kernel_ulong_t)MT7921_FIRMWARE_WM }, 1862306a36Sopenharmony_ci /* Comfast CF-952AX */ 1962306a36Sopenharmony_ci { USB_DEVICE_AND_INTERFACE_INFO(0x3574, 0x6211, 0xff, 0xff, 0xff), 2062306a36Sopenharmony_ci .driver_info = (kernel_ulong_t)MT7921_FIRMWARE_WM }, 2162306a36Sopenharmony_ci /* Netgear, Inc. [A8000,AXE3000] */ 2262306a36Sopenharmony_ci { USB_DEVICE_AND_INTERFACE_INFO(0x0846, 0x9060, 0xff, 0xff, 0xff), 2362306a36Sopenharmony_ci .driver_info = (kernel_ulong_t)MT7921_FIRMWARE_WM }, 2462306a36Sopenharmony_ci { }, 2562306a36Sopenharmony_ci}; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic int 2862306a36Sopenharmony_cimt7921u_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, 2962306a36Sopenharmony_ci int cmd, int *seq) 3062306a36Sopenharmony_ci{ 3162306a36Sopenharmony_ci struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); 3262306a36Sopenharmony_ci u32 pad, ep; 3362306a36Sopenharmony_ci int ret; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci ret = mt76_connac2_mcu_fill_message(mdev, skb, cmd, seq); 3662306a36Sopenharmony_ci if (ret) 3762306a36Sopenharmony_ci return ret; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci mdev->mcu.timeout = 3 * HZ; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci if (cmd != MCU_CMD(FW_SCATTER)) 4262306a36Sopenharmony_ci ep = MT_EP_OUT_INBAND_CMD; 4362306a36Sopenharmony_ci else 4462306a36Sopenharmony_ci ep = MT_EP_OUT_AC_BE; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci mt7921_skb_add_usb_sdio_hdr(dev, skb, 0); 4762306a36Sopenharmony_ci pad = round_up(skb->len, 4) + 4 - skb->len; 4862306a36Sopenharmony_ci __skb_put_zero(skb, pad); 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci ret = mt76u_bulk_msg(&dev->mt76, skb->data, skb->len, NULL, 5162306a36Sopenharmony_ci 1000, ep); 5262306a36Sopenharmony_ci dev_kfree_skb(skb); 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci return ret; 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cistatic int mt7921u_mcu_init(struct mt792x_dev *dev) 5862306a36Sopenharmony_ci{ 5962306a36Sopenharmony_ci static const struct mt76_mcu_ops mcu_ops = { 6062306a36Sopenharmony_ci .headroom = MT_SDIO_HDR_SIZE + 6162306a36Sopenharmony_ci sizeof(struct mt76_connac2_mcu_txd), 6262306a36Sopenharmony_ci .tailroom = MT_USB_TAIL_SIZE, 6362306a36Sopenharmony_ci .mcu_skb_send_msg = mt7921u_mcu_send_message, 6462306a36Sopenharmony_ci .mcu_parse_response = mt7921_mcu_parse_response, 6562306a36Sopenharmony_ci }; 6662306a36Sopenharmony_ci int ret; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci dev->mt76.mcu_ops = &mcu_ops; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci mt76_set(dev, MT_UDMA_TX_QSEL, MT_FW_DL_EN); 7162306a36Sopenharmony_ci ret = mt7921_run_firmware(dev); 7262306a36Sopenharmony_ci if (ret) 7362306a36Sopenharmony_ci return ret; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); 7662306a36Sopenharmony_ci mt76_clear(dev, MT_UDMA_TX_QSEL, MT_FW_DL_EN); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci return 0; 7962306a36Sopenharmony_ci} 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cistatic int mt7921u_mac_reset(struct mt792x_dev *dev) 8262306a36Sopenharmony_ci{ 8362306a36Sopenharmony_ci int err; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci mt76_txq_schedule_all(&dev->mphy); 8662306a36Sopenharmony_ci mt76_worker_disable(&dev->mt76.tx_worker); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci set_bit(MT76_RESET, &dev->mphy.state); 8962306a36Sopenharmony_ci set_bit(MT76_MCU_RESET, &dev->mphy.state); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci wake_up(&dev->mt76.mcu.wait); 9262306a36Sopenharmony_ci skb_queue_purge(&dev->mt76.mcu.res_q); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci mt76u_stop_rx(&dev->mt76); 9562306a36Sopenharmony_ci mt76u_stop_tx(&dev->mt76); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci mt792xu_wfsys_reset(dev); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci clear_bit(MT76_MCU_RESET, &dev->mphy.state); 10062306a36Sopenharmony_ci err = mt76u_resume_rx(&dev->mt76); 10162306a36Sopenharmony_ci if (err) 10262306a36Sopenharmony_ci goto out; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci err = mt792xu_mcu_power_on(dev); 10562306a36Sopenharmony_ci if (err) 10662306a36Sopenharmony_ci goto out; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci err = mt792xu_dma_init(dev, false); 10962306a36Sopenharmony_ci if (err) 11062306a36Sopenharmony_ci goto out; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci mt76_wr(dev, MT_SWDEF_MODE, MT_SWDEF_NORMAL_MODE); 11362306a36Sopenharmony_ci mt76_set(dev, MT_UDMA_TX_QSEL, MT_FW_DL_EN); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci err = mt7921_run_firmware(dev); 11662306a36Sopenharmony_ci if (err) 11762306a36Sopenharmony_ci goto out; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci mt76_clear(dev, MT_UDMA_TX_QSEL, MT_FW_DL_EN); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci err = mt7921_mcu_set_eeprom(dev); 12262306a36Sopenharmony_ci if (err) 12362306a36Sopenharmony_ci goto out; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci err = mt7921_mac_init(dev); 12662306a36Sopenharmony_ci if (err) 12762306a36Sopenharmony_ci goto out; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci err = __mt7921_start(&dev->phy); 13062306a36Sopenharmony_ciout: 13162306a36Sopenharmony_ci clear_bit(MT76_RESET, &dev->mphy.state); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci mt76_worker_enable(&dev->mt76.tx_worker); 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci return err; 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cistatic void mt7921u_stop(struct ieee80211_hw *hw) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci struct mt792x_dev *dev = mt792x_hw_dev(hw); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci mt76u_stop_tx(&dev->mt76); 14362306a36Sopenharmony_ci mt7921_stop(hw); 14462306a36Sopenharmony_ci} 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_cistatic int mt7921u_probe(struct usb_interface *usb_intf, 14762306a36Sopenharmony_ci const struct usb_device_id *id) 14862306a36Sopenharmony_ci{ 14962306a36Sopenharmony_ci static const struct mt76_driver_ops drv_ops = { 15062306a36Sopenharmony_ci .txwi_size = MT_SDIO_TXD_SIZE, 15162306a36Sopenharmony_ci .drv_flags = MT_DRV_RX_DMA_HDR | MT_DRV_HW_MGMT_TXQ | 15262306a36Sopenharmony_ci MT_DRV_AMSDU_OFFLOAD, 15362306a36Sopenharmony_ci .survey_flags = SURVEY_INFO_TIME_TX | 15462306a36Sopenharmony_ci SURVEY_INFO_TIME_RX | 15562306a36Sopenharmony_ci SURVEY_INFO_TIME_BSS_RX, 15662306a36Sopenharmony_ci .tx_prepare_skb = mt7921_usb_sdio_tx_prepare_skb, 15762306a36Sopenharmony_ci .tx_complete_skb = mt7921_usb_sdio_tx_complete_skb, 15862306a36Sopenharmony_ci .tx_status_data = mt7921_usb_sdio_tx_status_data, 15962306a36Sopenharmony_ci .rx_skb = mt7921_queue_rx_skb, 16062306a36Sopenharmony_ci .rx_check = mt7921_rx_check, 16162306a36Sopenharmony_ci .sta_add = mt7921_mac_sta_add, 16262306a36Sopenharmony_ci .sta_assoc = mt7921_mac_sta_assoc, 16362306a36Sopenharmony_ci .sta_remove = mt7921_mac_sta_remove, 16462306a36Sopenharmony_ci .update_survey = mt792x_update_channel, 16562306a36Sopenharmony_ci }; 16662306a36Sopenharmony_ci static const struct mt792x_hif_ops hif_ops = { 16762306a36Sopenharmony_ci .mcu_init = mt7921u_mcu_init, 16862306a36Sopenharmony_ci .init_reset = mt792xu_init_reset, 16962306a36Sopenharmony_ci .reset = mt7921u_mac_reset, 17062306a36Sopenharmony_ci }; 17162306a36Sopenharmony_ci static struct mt76_bus_ops bus_ops = { 17262306a36Sopenharmony_ci .rr = mt792xu_rr, 17362306a36Sopenharmony_ci .wr = mt792xu_wr, 17462306a36Sopenharmony_ci .rmw = mt792xu_rmw, 17562306a36Sopenharmony_ci .read_copy = mt76u_read_copy, 17662306a36Sopenharmony_ci .write_copy = mt792xu_copy, 17762306a36Sopenharmony_ci .type = MT76_BUS_USB, 17862306a36Sopenharmony_ci }; 17962306a36Sopenharmony_ci struct usb_device *udev = interface_to_usbdev(usb_intf); 18062306a36Sopenharmony_ci struct ieee80211_ops *ops; 18162306a36Sopenharmony_ci struct ieee80211_hw *hw; 18262306a36Sopenharmony_ci struct mt792x_dev *dev; 18362306a36Sopenharmony_ci struct mt76_dev *mdev; 18462306a36Sopenharmony_ci u8 features; 18562306a36Sopenharmony_ci int ret; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci ops = mt792x_get_mac80211_ops(&usb_intf->dev, &mt7921_ops, 18862306a36Sopenharmony_ci (void *)id->driver_info, &features); 18962306a36Sopenharmony_ci if (!ops) 19062306a36Sopenharmony_ci return -ENOMEM; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci ops->stop = mt7921u_stop; 19362306a36Sopenharmony_ci mdev = mt76_alloc_device(&usb_intf->dev, sizeof(*dev), ops, &drv_ops); 19462306a36Sopenharmony_ci if (!mdev) 19562306a36Sopenharmony_ci return -ENOMEM; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci dev = container_of(mdev, struct mt792x_dev, mt76); 19862306a36Sopenharmony_ci dev->fw_features = features; 19962306a36Sopenharmony_ci dev->hif_ops = &hif_ops; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci udev = usb_get_dev(udev); 20262306a36Sopenharmony_ci usb_reset_device(udev); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci usb_set_intfdata(usb_intf, dev); 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci ret = __mt76u_init(mdev, usb_intf, &bus_ops); 20762306a36Sopenharmony_ci if (ret < 0) 20862306a36Sopenharmony_ci goto error; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci mdev->rev = (mt76_rr(dev, MT_HW_CHIPID) << 16) | 21162306a36Sopenharmony_ci (mt76_rr(dev, MT_HW_REV) & 0xff); 21262306a36Sopenharmony_ci dev_dbg(mdev->dev, "ASIC revision: %04x\n", mdev->rev); 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci if (mt76_get_field(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY)) { 21562306a36Sopenharmony_ci ret = mt792xu_wfsys_reset(dev); 21662306a36Sopenharmony_ci if (ret) 21762306a36Sopenharmony_ci goto error; 21862306a36Sopenharmony_ci } 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci ret = mt792xu_mcu_power_on(dev); 22162306a36Sopenharmony_ci if (ret) 22262306a36Sopenharmony_ci goto error; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci ret = mt76u_alloc_mcu_queue(&dev->mt76); 22562306a36Sopenharmony_ci if (ret) 22662306a36Sopenharmony_ci goto error; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci ret = mt76u_alloc_queues(&dev->mt76); 22962306a36Sopenharmony_ci if (ret) 23062306a36Sopenharmony_ci goto error; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci ret = mt792xu_dma_init(dev, false); 23362306a36Sopenharmony_ci if (ret) 23462306a36Sopenharmony_ci goto error; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci hw = mt76_hw(dev); 23762306a36Sopenharmony_ci /* check hw sg support in order to enable AMSDU */ 23862306a36Sopenharmony_ci hw->max_tx_fragments = mdev->usb.sg_en ? MT_HW_TXP_MAX_BUF_NUM : 1; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci ret = mt7921_register_device(dev); 24162306a36Sopenharmony_ci if (ret) 24262306a36Sopenharmony_ci goto error; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci return 0; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_cierror: 24762306a36Sopenharmony_ci mt76u_queues_deinit(&dev->mt76); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci usb_set_intfdata(usb_intf, NULL); 25062306a36Sopenharmony_ci usb_put_dev(interface_to_usbdev(usb_intf)); 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci mt76_free_device(&dev->mt76); 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci return ret; 25562306a36Sopenharmony_ci} 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci#ifdef CONFIG_PM 25862306a36Sopenharmony_cistatic int mt7921u_suspend(struct usb_interface *intf, pm_message_t state) 25962306a36Sopenharmony_ci{ 26062306a36Sopenharmony_ci struct mt792x_dev *dev = usb_get_intfdata(intf); 26162306a36Sopenharmony_ci struct mt76_connac_pm *pm = &dev->pm; 26262306a36Sopenharmony_ci int err; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci pm->suspended = true; 26562306a36Sopenharmony_ci flush_work(&dev->reset_work); 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci err = mt76_connac_mcu_set_hif_suspend(&dev->mt76, true); 26862306a36Sopenharmony_ci if (err) 26962306a36Sopenharmony_ci goto failed; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci mt76u_stop_rx(&dev->mt76); 27262306a36Sopenharmony_ci mt76u_stop_tx(&dev->mt76); 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci return 0; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_cifailed: 27762306a36Sopenharmony_ci pm->suspended = false; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci if (err < 0) 28062306a36Sopenharmony_ci mt792x_reset(&dev->mt76); 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci return err; 28362306a36Sopenharmony_ci} 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_cistatic int mt7921u_resume(struct usb_interface *intf) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci struct mt792x_dev *dev = usb_get_intfdata(intf); 28862306a36Sopenharmony_ci struct mt76_connac_pm *pm = &dev->pm; 28962306a36Sopenharmony_ci bool reinit = true; 29062306a36Sopenharmony_ci int err, i; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci for (i = 0; i < 10; i++) { 29362306a36Sopenharmony_ci u32 val = mt76_rr(dev, MT_WF_SW_DEF_CR_USB_MCU_EVENT); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci if (!(val & MT_WF_SW_SER_TRIGGER_SUSPEND)) { 29662306a36Sopenharmony_ci reinit = false; 29762306a36Sopenharmony_ci break; 29862306a36Sopenharmony_ci } 29962306a36Sopenharmony_ci if (val & MT_WF_SW_SER_DONE_SUSPEND) { 30062306a36Sopenharmony_ci mt76_wr(dev, MT_WF_SW_DEF_CR_USB_MCU_EVENT, 0); 30162306a36Sopenharmony_ci break; 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci msleep(20); 30562306a36Sopenharmony_ci } 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci if (reinit || mt792x_dma_need_reinit(dev)) { 30862306a36Sopenharmony_ci err = mt792xu_dma_init(dev, true); 30962306a36Sopenharmony_ci if (err) 31062306a36Sopenharmony_ci goto failed; 31162306a36Sopenharmony_ci } 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci err = mt76u_resume_rx(&dev->mt76); 31462306a36Sopenharmony_ci if (err < 0) 31562306a36Sopenharmony_ci goto failed; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci err = mt76_connac_mcu_set_hif_suspend(&dev->mt76, false); 31862306a36Sopenharmony_cifailed: 31962306a36Sopenharmony_ci pm->suspended = false; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci if (err < 0) 32262306a36Sopenharmony_ci mt792x_reset(&dev->mt76); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci return err; 32562306a36Sopenharmony_ci} 32662306a36Sopenharmony_ci#endif /* CONFIG_PM */ 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(usb, mt7921u_device_table); 32962306a36Sopenharmony_ciMODULE_FIRMWARE(MT7921_FIRMWARE_WM); 33062306a36Sopenharmony_ciMODULE_FIRMWARE(MT7921_ROM_PATCH); 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_cistatic struct usb_driver mt7921u_driver = { 33362306a36Sopenharmony_ci .name = KBUILD_MODNAME, 33462306a36Sopenharmony_ci .id_table = mt7921u_device_table, 33562306a36Sopenharmony_ci .probe = mt7921u_probe, 33662306a36Sopenharmony_ci .disconnect = mt792xu_disconnect, 33762306a36Sopenharmony_ci#ifdef CONFIG_PM 33862306a36Sopenharmony_ci .suspend = mt7921u_suspend, 33962306a36Sopenharmony_ci .resume = mt7921u_resume, 34062306a36Sopenharmony_ci .reset_resume = mt7921u_resume, 34162306a36Sopenharmony_ci#endif /* CONFIG_PM */ 34262306a36Sopenharmony_ci .soft_unbind = 1, 34362306a36Sopenharmony_ci .disable_hub_initiated_lpm = 1, 34462306a36Sopenharmony_ci}; 34562306a36Sopenharmony_cimodule_usb_driver(mt7921u_driver); 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ciMODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>"); 34862306a36Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 349