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