Path: blob/main/sys/contrib/dev/mediatek/mt76/mt7925/usb.c
105956 views
// SPDX-License-Identifier: BSD-3-Clause-Clear1/* Copyright (C) 2023 MediaTek Inc. */23#include <linux/kernel.h>4#include <linux/module.h>5#include <linux/usb.h>67#include "mt7925.h"8#include "mcu.h"9#include "mac.h"1011static const struct usb_device_id mt7925u_device_table[] = {12{ USB_DEVICE_AND_INTERFACE_INFO(0x0e8d, 0x7925, 0xff, 0xff, 0xff),13.driver_info = (kernel_ulong_t)MT7925_FIRMWARE_WM },14/* Netgear, Inc. A9000 */15{ USB_DEVICE_AND_INTERFACE_INFO(0x0846, 0x9072, 0xff, 0xff, 0xff),16.driver_info = (kernel_ulong_t)MT7925_FIRMWARE_WM },17{ },18};1920static int21mt7925u_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,22int cmd, int *seq)23{24struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);25u32 pad, ep;26int ret;2728ret = mt7925_mcu_fill_message(mdev, skb, cmd, seq);29if (ret)30return ret;3132mdev->mcu.timeout = 3 * HZ;3334if (cmd != MCU_CMD(FW_SCATTER))35ep = MT_EP_OUT_INBAND_CMD;36else37ep = MT_EP_OUT_AC_BE;3839mt792x_skb_add_usb_sdio_hdr(dev, skb, 0);40pad = round_up(skb->len, 4) + 4 - skb->len;41__skb_put_zero(skb, pad);4243ret = mt76u_bulk_msg(&dev->mt76, skb->data, skb->len, NULL,441000, ep);45dev_kfree_skb(skb);4647return ret;48}4950static int mt7925u_mcu_init(struct mt792x_dev *dev)51{52static const struct mt76_mcu_ops mcu_ops = {53.headroom = MT_SDIO_HDR_SIZE +54sizeof(struct mt76_connac2_mcu_txd),55.tailroom = MT_USB_TAIL_SIZE,56.mcu_skb_send_msg = mt7925u_mcu_send_message,57.mcu_parse_response = mt7925_mcu_parse_response,58};59int ret;6061dev->mt76.mcu_ops = &mcu_ops;6263mt76_set(dev, MT_UDMA_TX_QSEL, MT_FW_DL_EN);64ret = mt7925_run_firmware(dev);65if (ret)66return ret;6768set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);69mt76_clear(dev, MT_UDMA_TX_QSEL, MT_FW_DL_EN);7071return 0;72}7374static int mt7925u_mac_reset(struct mt792x_dev *dev)75{76int err;7778mt76_txq_schedule_all(&dev->mphy);79mt76_worker_disable(&dev->mt76.tx_worker);8081set_bit(MT76_RESET, &dev->mphy.state);82set_bit(MT76_MCU_RESET, &dev->mphy.state);8384wake_up(&dev->mt76.mcu.wait);85skb_queue_purge(&dev->mt76.mcu.res_q);8687mt76u_stop_rx(&dev->mt76);88mt76u_stop_tx(&dev->mt76);8990mt792xu_wfsys_reset(dev);9192clear_bit(MT76_MCU_RESET, &dev->mphy.state);93err = mt76u_resume_rx(&dev->mt76);94if (err)95goto out;9697err = mt792xu_mcu_power_on(dev);98if (err)99goto out;100101err = mt792xu_dma_init(dev, false);102if (err)103goto out;104105mt76_wr(dev, MT_SWDEF_MODE, MT_SWDEF_NORMAL_MODE);106mt76_set(dev, MT_UDMA_TX_QSEL, MT_FW_DL_EN);107108err = mt7925_run_firmware(dev);109if (err)110goto out;111112mt76_clear(dev, MT_UDMA_TX_QSEL, MT_FW_DL_EN);113114err = mt7925_mcu_set_eeprom(dev);115if (err)116goto out;117118err = mt7925_mac_init(dev);119if (err)120goto out;121122err = __mt7925_start(&dev->phy);123out:124clear_bit(MT76_RESET, &dev->mphy.state);125126mt76_worker_enable(&dev->mt76.tx_worker);127128return err;129}130131static int mt7925u_probe(struct usb_interface *usb_intf,132const struct usb_device_id *id)133{134static const struct mt76_driver_ops drv_ops = {135.txwi_size = MT_SDIO_TXD_SIZE,136.drv_flags = MT_DRV_RX_DMA_HDR | MT_DRV_HW_MGMT_TXQ |137MT_DRV_AMSDU_OFFLOAD,138.survey_flags = SURVEY_INFO_TIME_TX |139SURVEY_INFO_TIME_RX |140SURVEY_INFO_TIME_BSS_RX,141.tx_prepare_skb = mt7925_usb_sdio_tx_prepare_skb,142.tx_complete_skb = mt7925_usb_sdio_tx_complete_skb,143.tx_status_data = mt7925_usb_sdio_tx_status_data,144.rx_skb = mt7925_queue_rx_skb,145.rx_check = mt7925_rx_check,146.sta_add = mt7925_mac_sta_add,147.sta_event = mt7925_mac_sta_event,148.sta_remove = mt7925_mac_sta_remove,149.update_survey = mt792x_update_channel,150};151static const struct mt792x_hif_ops hif_ops = {152.mcu_init = mt7925u_mcu_init,153.init_reset = mt792xu_init_reset,154.reset = mt7925u_mac_reset,155};156static struct mt76_bus_ops bus_ops = {157.rr = mt792xu_rr,158.wr = mt792xu_wr,159.rmw = mt792xu_rmw,160.read_copy = mt76u_read_copy,161.write_copy = mt792xu_copy,162.type = MT76_BUS_USB,163};164struct usb_device *udev = interface_to_usbdev(usb_intf);165struct ieee80211_ops *ops;166struct ieee80211_hw *hw;167struct mt792x_dev *dev;168struct mt76_dev *mdev;169u8 features;170int ret;171172ops = mt792x_get_mac80211_ops(&usb_intf->dev, &mt7925_ops,173(void *)id->driver_info, &features);174if (!ops)175return -ENOMEM;176177ops->stop = mt792xu_stop;178179mdev = mt76_alloc_device(&usb_intf->dev, sizeof(*dev), ops, &drv_ops);180if (!mdev)181return -ENOMEM;182183dev = container_of(mdev, struct mt792x_dev, mt76);184dev->fw_features = features;185dev->hif_ops = &hif_ops;186187udev = usb_get_dev(udev);188usb_reset_device(udev);189190usb_set_intfdata(usb_intf, dev);191192ret = __mt76u_init(mdev, usb_intf, &bus_ops);193if (ret < 0)194goto error;195196mdev->rev = (mt76_rr(dev, MT_HW_CHIPID) << 16) |197(mt76_rr(dev, MT_HW_REV) & 0xff);198dev_dbg(mdev->dev, "ASIC revision: %04x\n", mdev->rev);199200if (mt76_get_field(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY)) {201ret = mt792xu_wfsys_reset(dev);202if (ret)203goto error;204}205206ret = mt792xu_mcu_power_on(dev);207if (ret)208goto error;209210ret = mt76u_alloc_mcu_queue(&dev->mt76);211if (ret)212goto error;213214ret = mt76u_alloc_queues(&dev->mt76);215if (ret)216goto error;217218ret = mt792xu_dma_init(dev, false);219if (ret)220goto error;221222hw = mt76_hw(dev);223/* check hw sg support in order to enable AMSDU */224hw->max_tx_fragments = mdev->usb.sg_en ? MT_HW_TXP_MAX_BUF_NUM : 1;225226ret = mt7925_register_device(dev);227if (ret)228goto error;229230return 0;231232error:233mt76u_queues_deinit(&dev->mt76);234235usb_set_intfdata(usb_intf, NULL);236usb_put_dev(interface_to_usbdev(usb_intf));237238mt76_free_device(&dev->mt76);239240return ret;241}242243#ifdef CONFIG_PM244static int mt7925u_suspend(struct usb_interface *intf, pm_message_t state)245{246struct mt792x_dev *dev = usb_get_intfdata(intf);247struct mt76_connac_pm *pm = &dev->pm;248int err, ret;249250pm->suspended = true;251dev->hif_resumed = false;252flush_work(&dev->reset_work);253254mt76_connac_mcu_set_hif_suspend(&dev->mt76, true, false);255ret = wait_event_timeout(dev->wait,256dev->hif_idle, 3 * HZ);257if (!ret) {258err = -ETIMEDOUT;259goto failed;260}261262mt76u_stop_rx(&dev->mt76);263mt76u_stop_tx(&dev->mt76);264265return 0;266267failed:268pm->suspended = false;269270if (err < 0)271mt792x_reset(&dev->mt76);272273return err;274}275276static int mt7925u_resume(struct usb_interface *intf)277{278struct mt792x_dev *dev = usb_get_intfdata(intf);279struct mt76_connac_pm *pm = &dev->pm;280bool reinit = true;281int err, i, ret;282283dev->hif_idle = false;284for (i = 0; i < 10; i++) {285u32 val = mt76_rr(dev, MT_WF_SW_DEF_CR_USB_MCU_EVENT);286287if (!(val & MT_WF_SW_SER_TRIGGER_SUSPEND)) {288reinit = false;289break;290}291if (val & MT_WF_SW_SER_DONE_SUSPEND) {292mt76_wr(dev, MT_WF_SW_DEF_CR_USB_MCU_EVENT, 0);293break;294}295296msleep(20);297}298299if (reinit || mt792x_dma_need_reinit(dev)) {300err = mt792xu_dma_init(dev, true);301if (err)302goto failed;303}304305err = mt76u_resume_rx(&dev->mt76);306if (err < 0)307goto failed;308309mt76_connac_mcu_set_hif_suspend(&dev->mt76, false, false);310ret = wait_event_timeout(dev->wait,311dev->hif_resumed, 3 * HZ);312if (!ret)313err = -ETIMEDOUT;314failed:315pm->suspended = false;316317if (err < 0)318mt792x_reset(&dev->mt76);319320return err;321}322#endif /* CONFIG_PM */323324MODULE_DEVICE_TABLE(usb, mt7925u_device_table);325MODULE_FIRMWARE(MT7925_FIRMWARE_WM);326MODULE_FIRMWARE(MT7925_ROM_PATCH);327328static struct usb_driver mt7925u_driver = {329.name = KBUILD_MODNAME,330.id_table = mt7925u_device_table,331.probe = mt7925u_probe,332.disconnect = mt792xu_disconnect,333#ifdef CONFIG_PM334.suspend = mt7925u_suspend,335.resume = mt7925u_resume,336.reset_resume = mt7925u_resume,337#endif /* CONFIG_PM */338.soft_unbind = 1,339.disable_hub_initiated_lpm = 1,340};341module_usb_driver(mt7925u_driver);342343MODULE_AUTHOR("Lorenzo Bianconi <[email protected]>");344MODULE_DESCRIPTION("MediaTek MT7925U (USB) wireless driver");345MODULE_LICENSE("Dual BSD/GPL");346#if defined(__FreeBSD__)347MODULE_VERSION(mt7925_usb, 1);348MODULE_DEPEND(mt7925_usb, mt76_core, 1, 1, 1);349MODULE_DEPEND(mt7925_usb, linuxkpi, 1, 1, 1);350MODULE_DEPEND(mt7925_usb, linuxkpi_wlan, 1, 1, 1);351MODULE_DEPEND(mt7925_usb, linuxkpi_usb, 1, 1, 1);352#endif353354355