Path: blob/main/sys/contrib/dev/mediatek/mt76/mt7925/usb.c
48525 views
// SPDX-License-Identifier: ISC1/* 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{ },15};1617static int18mt7925u_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,19int cmd, int *seq)20{21struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);22u32 pad, ep;23int ret;2425ret = mt7925_mcu_fill_message(mdev, skb, cmd, seq);26if (ret)27return ret;2829mdev->mcu.timeout = 3 * HZ;3031if (cmd != MCU_CMD(FW_SCATTER))32ep = MT_EP_OUT_INBAND_CMD;33else34ep = MT_EP_OUT_AC_BE;3536mt792x_skb_add_usb_sdio_hdr(dev, skb, 0);37pad = round_up(skb->len, 4) + 4 - skb->len;38__skb_put_zero(skb, pad);3940ret = mt76u_bulk_msg(&dev->mt76, skb->data, skb->len, NULL,411000, ep);42dev_kfree_skb(skb);4344return ret;45}4647static int mt7925u_mcu_init(struct mt792x_dev *dev)48{49static const struct mt76_mcu_ops mcu_ops = {50.headroom = MT_SDIO_HDR_SIZE +51sizeof(struct mt76_connac2_mcu_txd),52.tailroom = MT_USB_TAIL_SIZE,53.mcu_skb_send_msg = mt7925u_mcu_send_message,54.mcu_parse_response = mt7925_mcu_parse_response,55};56int ret;5758dev->mt76.mcu_ops = &mcu_ops;5960mt76_set(dev, MT_UDMA_TX_QSEL, MT_FW_DL_EN);61ret = mt7925_run_firmware(dev);62if (ret)63return ret;6465set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);66mt76_clear(dev, MT_UDMA_TX_QSEL, MT_FW_DL_EN);6768return 0;69}7071static int mt7925u_mac_reset(struct mt792x_dev *dev)72{73int err;7475mt76_txq_schedule_all(&dev->mphy);76mt76_worker_disable(&dev->mt76.tx_worker);7778set_bit(MT76_RESET, &dev->mphy.state);79set_bit(MT76_MCU_RESET, &dev->mphy.state);8081wake_up(&dev->mt76.mcu.wait);82skb_queue_purge(&dev->mt76.mcu.res_q);8384mt76u_stop_rx(&dev->mt76);85mt76u_stop_tx(&dev->mt76);8687mt792xu_wfsys_reset(dev);8889clear_bit(MT76_MCU_RESET, &dev->mphy.state);90err = mt76u_resume_rx(&dev->mt76);91if (err)92goto out;9394err = mt792xu_mcu_power_on(dev);95if (err)96goto out;9798err = mt792xu_dma_init(dev, false);99if (err)100goto out;101102mt76_wr(dev, MT_SWDEF_MODE, MT_SWDEF_NORMAL_MODE);103mt76_set(dev, MT_UDMA_TX_QSEL, MT_FW_DL_EN);104105err = mt7925_run_firmware(dev);106if (err)107goto out;108109mt76_clear(dev, MT_UDMA_TX_QSEL, MT_FW_DL_EN);110111err = mt7925_mcu_set_eeprom(dev);112if (err)113goto out;114115err = mt7925_mac_init(dev);116if (err)117goto out;118119err = __mt7925_start(&dev->phy);120out:121clear_bit(MT76_RESET, &dev->mphy.state);122123mt76_worker_enable(&dev->mt76.tx_worker);124125return err;126}127128static int mt7925u_probe(struct usb_interface *usb_intf,129const struct usb_device_id *id)130{131static const struct mt76_driver_ops drv_ops = {132.txwi_size = MT_SDIO_TXD_SIZE,133.drv_flags = MT_DRV_RX_DMA_HDR | MT_DRV_HW_MGMT_TXQ |134MT_DRV_AMSDU_OFFLOAD,135.survey_flags = SURVEY_INFO_TIME_TX |136SURVEY_INFO_TIME_RX |137SURVEY_INFO_TIME_BSS_RX,138.tx_prepare_skb = mt7925_usb_sdio_tx_prepare_skb,139.tx_complete_skb = mt7925_usb_sdio_tx_complete_skb,140.tx_status_data = mt7925_usb_sdio_tx_status_data,141.rx_skb = mt7925_queue_rx_skb,142.rx_check = mt7925_rx_check,143.sta_add = mt7925_mac_sta_add,144.sta_event = mt7925_mac_sta_event,145.sta_remove = mt7925_mac_sta_remove,146.update_survey = mt792x_update_channel,147};148static const struct mt792x_hif_ops hif_ops = {149.mcu_init = mt7925u_mcu_init,150.init_reset = mt792xu_init_reset,151.reset = mt7925u_mac_reset,152};153static struct mt76_bus_ops bus_ops = {154.rr = mt792xu_rr,155.wr = mt792xu_wr,156.rmw = mt792xu_rmw,157.read_copy = mt76u_read_copy,158.write_copy = mt792xu_copy,159.type = MT76_BUS_USB,160};161struct usb_device *udev = interface_to_usbdev(usb_intf);162struct ieee80211_ops *ops;163struct ieee80211_hw *hw;164struct mt792x_dev *dev;165struct mt76_dev *mdev;166u8 features;167int ret;168169ops = mt792x_get_mac80211_ops(&usb_intf->dev, &mt7925_ops,170(void *)id->driver_info, &features);171if (!ops)172return -ENOMEM;173174ops->stop = mt792xu_stop;175176mdev = mt76_alloc_device(&usb_intf->dev, sizeof(*dev), ops, &drv_ops);177if (!mdev)178return -ENOMEM;179180dev = container_of(mdev, struct mt792x_dev, mt76);181dev->fw_features = features;182dev->hif_ops = &hif_ops;183184udev = usb_get_dev(udev);185usb_reset_device(udev);186187usb_set_intfdata(usb_intf, dev);188189ret = __mt76u_init(mdev, usb_intf, &bus_ops);190if (ret < 0)191goto error;192193mdev->rev = (mt76_rr(dev, MT_HW_CHIPID) << 16) |194(mt76_rr(dev, MT_HW_REV) & 0xff);195dev_dbg(mdev->dev, "ASIC revision: %04x\n", mdev->rev);196197if (mt76_get_field(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY)) {198ret = mt792xu_wfsys_reset(dev);199if (ret)200goto error;201}202203ret = mt792xu_mcu_power_on(dev);204if (ret)205goto error;206207ret = mt76u_alloc_mcu_queue(&dev->mt76);208if (ret)209goto error;210211ret = mt76u_alloc_queues(&dev->mt76);212if (ret)213goto error;214215ret = mt792xu_dma_init(dev, false);216if (ret)217goto error;218219hw = mt76_hw(dev);220/* check hw sg support in order to enable AMSDU */221hw->max_tx_fragments = mdev->usb.sg_en ? MT_HW_TXP_MAX_BUF_NUM : 1;222223ret = mt7925_register_device(dev);224if (ret)225goto error;226227return 0;228229error:230mt76u_queues_deinit(&dev->mt76);231232usb_set_intfdata(usb_intf, NULL);233usb_put_dev(interface_to_usbdev(usb_intf));234235mt76_free_device(&dev->mt76);236237return ret;238}239240#ifdef CONFIG_PM241static int mt7925u_suspend(struct usb_interface *intf, pm_message_t state)242{243struct mt792x_dev *dev = usb_get_intfdata(intf);244struct mt76_connac_pm *pm = &dev->pm;245int err, ret;246247pm->suspended = true;248dev->hif_resumed = false;249flush_work(&dev->reset_work);250251mt76_connac_mcu_set_hif_suspend(&dev->mt76, true, false);252ret = wait_event_timeout(dev->wait,253dev->hif_idle, 3 * HZ);254if (!ret) {255err = -ETIMEDOUT;256goto failed;257}258259mt76u_stop_rx(&dev->mt76);260mt76u_stop_tx(&dev->mt76);261262return 0;263264failed:265pm->suspended = false;266267if (err < 0)268mt792x_reset(&dev->mt76);269270return err;271}272273static int mt7925u_resume(struct usb_interface *intf)274{275struct mt792x_dev *dev = usb_get_intfdata(intf);276struct mt76_connac_pm *pm = &dev->pm;277bool reinit = true;278int err, i, ret;279280dev->hif_idle = false;281for (i = 0; i < 10; i++) {282u32 val = mt76_rr(dev, MT_WF_SW_DEF_CR_USB_MCU_EVENT);283284if (!(val & MT_WF_SW_SER_TRIGGER_SUSPEND)) {285reinit = false;286break;287}288if (val & MT_WF_SW_SER_DONE_SUSPEND) {289mt76_wr(dev, MT_WF_SW_DEF_CR_USB_MCU_EVENT, 0);290break;291}292293msleep(20);294}295296if (reinit || mt792x_dma_need_reinit(dev)) {297err = mt792xu_dma_init(dev, true);298if (err)299goto failed;300}301302err = mt76u_resume_rx(&dev->mt76);303if (err < 0)304goto failed;305306mt76_connac_mcu_set_hif_suspend(&dev->mt76, false, false);307ret = wait_event_timeout(dev->wait,308dev->hif_resumed, 3 * HZ);309if (!ret)310err = -ETIMEDOUT;311failed:312pm->suspended = false;313314if (err < 0)315mt792x_reset(&dev->mt76);316317return err;318}319#endif /* CONFIG_PM */320321MODULE_DEVICE_TABLE(usb, mt7925u_device_table);322MODULE_FIRMWARE(MT7925_FIRMWARE_WM);323MODULE_FIRMWARE(MT7925_ROM_PATCH);324325static struct usb_driver mt7925u_driver = {326.name = KBUILD_MODNAME,327.id_table = mt7925u_device_table,328.probe = mt7925u_probe,329.disconnect = mt792xu_disconnect,330#ifdef CONFIG_PM331.suspend = mt7925u_suspend,332.resume = mt7925u_resume,333.reset_resume = mt7925u_resume,334#endif /* CONFIG_PM */335.soft_unbind = 1,336.disable_hub_initiated_lpm = 1,337};338module_usb_driver(mt7925u_driver);339340MODULE_AUTHOR("Lorenzo Bianconi <[email protected]>");341MODULE_DESCRIPTION("MediaTek MT7925U (USB) wireless driver");342MODULE_LICENSE("Dual BSD/GPL");343344345