xref: /freebsd/sys/contrib/dev/mediatek/mt76/mt7615/sdio.c (revision cbb3ec25)
16c92544dSBjoern A. Zeeb // SPDX-License-Identifier: ISC
26c92544dSBjoern A. Zeeb /* Copyright (C) 2020 MediaTek Inc.
36c92544dSBjoern A. Zeeb  *
46c92544dSBjoern A. Zeeb  * Author: Felix Fietkau <nbd@nbd.name>
56c92544dSBjoern A. Zeeb  *	   Lorenzo Bianconi <lorenzo@kernel.org>
66c92544dSBjoern A. Zeeb  *	   Sean Wang <sean.wang@mediatek.com>
76c92544dSBjoern A. Zeeb  */
86c92544dSBjoern A. Zeeb 
96c92544dSBjoern A. Zeeb #include <linux/kernel.h>
106c92544dSBjoern A. Zeeb #include <linux/iopoll.h>
116c92544dSBjoern A. Zeeb #include <linux/module.h>
126c92544dSBjoern A. Zeeb 
136c92544dSBjoern A. Zeeb #include <linux/mmc/host.h>
146c92544dSBjoern A. Zeeb #include <linux/mmc/sdio_ids.h>
156c92544dSBjoern A. Zeeb #include <linux/mmc/sdio_func.h>
166c92544dSBjoern A. Zeeb 
176c92544dSBjoern A. Zeeb #include "../sdio.h"
186c92544dSBjoern A. Zeeb #include "mt7615.h"
196c92544dSBjoern A. Zeeb #include "mac.h"
206c92544dSBjoern A. Zeeb #include "mcu.h"
216c92544dSBjoern A. Zeeb 
226c92544dSBjoern A. Zeeb static const struct sdio_device_id mt7663s_table[] = {
236c92544dSBjoern A. Zeeb 	{ SDIO_DEVICE(SDIO_VENDOR_ID_MEDIATEK, 0x7603) },
246c92544dSBjoern A. Zeeb 	{ }	/* Terminating entry */
256c92544dSBjoern A. Zeeb };
266c92544dSBjoern A. Zeeb 
mt7663s_txrx_worker(struct mt76_worker * w)276c92544dSBjoern A. Zeeb static void mt7663s_txrx_worker(struct mt76_worker *w)
286c92544dSBjoern A. Zeeb {
296c92544dSBjoern A. Zeeb 	struct mt76_sdio *sdio = container_of(w, struct mt76_sdio,
306c92544dSBjoern A. Zeeb 					      txrx_worker);
316c92544dSBjoern A. Zeeb 	struct mt76_dev *mdev = container_of(sdio, struct mt76_dev, sdio);
326c92544dSBjoern A. Zeeb 	struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);
336c92544dSBjoern A. Zeeb 
346c92544dSBjoern A. Zeeb 	if (!mt76_connac_pm_ref(&dev->mphy, &dev->pm)) {
356c92544dSBjoern A. Zeeb 		queue_work(mdev->wq, &dev->pm.wake_work);
366c92544dSBjoern A. Zeeb 		return;
376c92544dSBjoern A. Zeeb 	}
386c92544dSBjoern A. Zeeb 	mt76s_txrx_worker(sdio);
396c92544dSBjoern A. Zeeb 	mt76_connac_pm_unref(&dev->mphy, &dev->pm);
406c92544dSBjoern A. Zeeb }
416c92544dSBjoern A. Zeeb 
mt7663s_init_work(struct work_struct * work)426c92544dSBjoern A. Zeeb static void mt7663s_init_work(struct work_struct *work)
436c92544dSBjoern A. Zeeb {
446c92544dSBjoern A. Zeeb 	struct mt7615_dev *dev;
456c92544dSBjoern A. Zeeb 
466c92544dSBjoern A. Zeeb 	dev = container_of(work, struct mt7615_dev, mcu_work);
476c92544dSBjoern A. Zeeb 	if (mt7663s_mcu_init(dev))
486c92544dSBjoern A. Zeeb 		return;
496c92544dSBjoern A. Zeeb 
506c92544dSBjoern A. Zeeb 	mt7615_init_work(dev);
516c92544dSBjoern A. Zeeb }
526c92544dSBjoern A. Zeeb 
mt7663s_parse_intr(struct mt76_dev * dev,struct mt76s_intr * intr)536c92544dSBjoern A. Zeeb static int mt7663s_parse_intr(struct mt76_dev *dev, struct mt76s_intr *intr)
546c92544dSBjoern A. Zeeb {
556c92544dSBjoern A. Zeeb 	struct mt76_sdio *sdio = &dev->sdio;
566c92544dSBjoern A. Zeeb 	struct mt7663s_intr *irq_data = sdio->intr_data;
576c92544dSBjoern A. Zeeb 	int i, err;
586c92544dSBjoern A. Zeeb 
596c92544dSBjoern A. Zeeb 	sdio_claim_host(sdio->func);
606c92544dSBjoern A. Zeeb 	err = sdio_readsb(sdio->func, irq_data, MCR_WHISR, sizeof(*irq_data));
616c92544dSBjoern A. Zeeb 	sdio_release_host(sdio->func);
626c92544dSBjoern A. Zeeb 
636c92544dSBjoern A. Zeeb 	if (err)
646c92544dSBjoern A. Zeeb 		return err;
656c92544dSBjoern A. Zeeb 
666c92544dSBjoern A. Zeeb 	intr->isr = irq_data->isr;
676c92544dSBjoern A. Zeeb 	intr->rec_mb = irq_data->rec_mb;
686c92544dSBjoern A. Zeeb 	intr->tx.wtqcr = irq_data->tx.wtqcr;
696c92544dSBjoern A. Zeeb 	intr->rx.num = irq_data->rx.num;
706c92544dSBjoern A. Zeeb 	for (i = 0; i < 2 ; i++)
716c92544dSBjoern A. Zeeb 		intr->rx.len[i] = irq_data->rx.len[i];
726c92544dSBjoern A. Zeeb 
736c92544dSBjoern A. Zeeb 	return 0;
746c92544dSBjoern A. Zeeb }
756c92544dSBjoern A. Zeeb 
mt7663s_probe(struct sdio_func * func,const struct sdio_device_id * id)766c92544dSBjoern A. Zeeb static int mt7663s_probe(struct sdio_func *func,
776c92544dSBjoern A. Zeeb 			 const struct sdio_device_id *id)
786c92544dSBjoern A. Zeeb {
796c92544dSBjoern A. Zeeb 	static const struct mt76_driver_ops drv_ops = {
806c92544dSBjoern A. Zeeb 		.txwi_size = MT_USB_TXD_SIZE,
816c92544dSBjoern A. Zeeb 		.drv_flags = MT_DRV_RX_DMA_HDR,
826c92544dSBjoern A. Zeeb 		.tx_prepare_skb = mt7663_usb_sdio_tx_prepare_skb,
836c92544dSBjoern A. Zeeb 		.tx_complete_skb = mt7663_usb_sdio_tx_complete_skb,
846c92544dSBjoern A. Zeeb 		.tx_status_data = mt7663_usb_sdio_tx_status_data,
856c92544dSBjoern A. Zeeb 		.rx_skb = mt7615_queue_rx_skb,
866c92544dSBjoern A. Zeeb 		.rx_check = mt7615_rx_check,
876c92544dSBjoern A. Zeeb 		.sta_add = mt7615_mac_sta_add,
886c92544dSBjoern A. Zeeb 		.sta_remove = mt7615_mac_sta_remove,
896c92544dSBjoern A. Zeeb 		.update_survey = mt7615_update_channel,
906c92544dSBjoern A. Zeeb 	};
916c92544dSBjoern A. Zeeb 	static const struct mt76_bus_ops mt7663s_ops = {
926c92544dSBjoern A. Zeeb 		.rr = mt76s_rr,
936c92544dSBjoern A. Zeeb 		.rmw = mt76s_rmw,
946c92544dSBjoern A. Zeeb 		.wr = mt76s_wr,
956c92544dSBjoern A. Zeeb 		.write_copy = mt76s_write_copy,
966c92544dSBjoern A. Zeeb 		.read_copy = mt76s_read_copy,
976c92544dSBjoern A. Zeeb 		.wr_rp = mt76s_wr_rp,
986c92544dSBjoern A. Zeeb 		.rd_rp = mt76s_rd_rp,
996c92544dSBjoern A. Zeeb 		.type = MT76_BUS_SDIO,
1006c92544dSBjoern A. Zeeb 	};
1016c92544dSBjoern A. Zeeb 	struct ieee80211_ops *ops;
1026c92544dSBjoern A. Zeeb 	struct mt7615_dev *dev;
1036c92544dSBjoern A. Zeeb 	struct mt76_dev *mdev;
1046c92544dSBjoern A. Zeeb 	int ret;
1056c92544dSBjoern A. Zeeb 
1066c92544dSBjoern A. Zeeb 	ops = devm_kmemdup(&func->dev, &mt7615_ops, sizeof(mt7615_ops),
1076c92544dSBjoern A. Zeeb 			   GFP_KERNEL);
1086c92544dSBjoern A. Zeeb 	if (!ops)
1096c92544dSBjoern A. Zeeb 		return -ENOMEM;
1106c92544dSBjoern A. Zeeb 
1116c92544dSBjoern A. Zeeb 	mdev = mt76_alloc_device(&func->dev, sizeof(*dev), ops, &drv_ops);
1126c92544dSBjoern A. Zeeb 	if (!mdev)
1136c92544dSBjoern A. Zeeb 		return -ENOMEM;
1146c92544dSBjoern A. Zeeb 
1156c92544dSBjoern A. Zeeb 	dev = container_of(mdev, struct mt7615_dev, mt76);
1166c92544dSBjoern A. Zeeb 
1176c92544dSBjoern A. Zeeb 	INIT_WORK(&dev->mcu_work, mt7663s_init_work);
1186c92544dSBjoern A. Zeeb 	dev->reg_map = mt7663_usb_sdio_reg_map;
1196c92544dSBjoern A. Zeeb 	dev->ops = ops;
1206c92544dSBjoern A. Zeeb 	sdio_set_drvdata(func, dev);
1216c92544dSBjoern A. Zeeb 
1226c92544dSBjoern A. Zeeb 	ret = mt76s_init(mdev, func, &mt7663s_ops);
1236c92544dSBjoern A. Zeeb 	if (ret < 0)
1246c92544dSBjoern A. Zeeb 		goto error;
1256c92544dSBjoern A. Zeeb 
1266c92544dSBjoern A. Zeeb 	ret = mt76s_hw_init(mdev, func, MT76_CONNAC_SDIO);
1276c92544dSBjoern A. Zeeb 	if (ret)
1286c92544dSBjoern A. Zeeb 		goto error;
1296c92544dSBjoern A. Zeeb 
1306c92544dSBjoern A. Zeeb 	mdev->rev = (mt76_rr(dev, MT_HW_CHIPID) << 16) |
1316c92544dSBjoern A. Zeeb 		    (mt76_rr(dev, MT_HW_REV) & 0xff);
1326c92544dSBjoern A. Zeeb 	dev_dbg(mdev->dev, "ASIC revision: %04x\n", mdev->rev);
1336c92544dSBjoern A. Zeeb 
1346c92544dSBjoern A. Zeeb 	mdev->sdio.parse_irq = mt7663s_parse_intr;
1356c92544dSBjoern A. Zeeb 	mdev->sdio.intr_data = devm_kmalloc(mdev->dev,
1366c92544dSBjoern A. Zeeb 					    sizeof(struct mt7663s_intr),
1376c92544dSBjoern A. Zeeb 					    GFP_KERNEL);
1386c92544dSBjoern A. Zeeb 	if (!mdev->sdio.intr_data) {
1396c92544dSBjoern A. Zeeb 		ret = -ENOMEM;
1406c92544dSBjoern A. Zeeb 		goto error;
1416c92544dSBjoern A. Zeeb 	}
1426c92544dSBjoern A. Zeeb 
1436c92544dSBjoern A. Zeeb 	ret = mt76s_alloc_rx_queue(mdev, MT_RXQ_MAIN);
1446c92544dSBjoern A. Zeeb 	if (ret)
1456c92544dSBjoern A. Zeeb 		goto error;
1466c92544dSBjoern A. Zeeb 
1476c92544dSBjoern A. Zeeb 	ret = mt76s_alloc_tx(mdev);
1486c92544dSBjoern A. Zeeb 	if (ret)
1496c92544dSBjoern A. Zeeb 		goto error;
1506c92544dSBjoern A. Zeeb 
1516c92544dSBjoern A. Zeeb 	ret = mt76_worker_setup(mt76_hw(dev), &mdev->sdio.txrx_worker,
1526c92544dSBjoern A. Zeeb 				mt7663s_txrx_worker, "sdio-txrx");
1536c92544dSBjoern A. Zeeb 	if (ret)
1546c92544dSBjoern A. Zeeb 		goto error;
1556c92544dSBjoern A. Zeeb 
1566c92544dSBjoern A. Zeeb 	sched_set_fifo_low(mdev->sdio.txrx_worker.task);
1576c92544dSBjoern A. Zeeb 
1586c92544dSBjoern A. Zeeb 	ret = mt7663_usb_sdio_register_device(dev);
1596c92544dSBjoern A. Zeeb 	if (ret)
1606c92544dSBjoern A. Zeeb 		goto error;
1616c92544dSBjoern A. Zeeb 
1626c92544dSBjoern A. Zeeb 	return 0;
1636c92544dSBjoern A. Zeeb 
1646c92544dSBjoern A. Zeeb error:
1656c92544dSBjoern A. Zeeb 	mt76s_deinit(&dev->mt76);
1666c92544dSBjoern A. Zeeb 	mt76_free_device(&dev->mt76);
1676c92544dSBjoern A. Zeeb 
1686c92544dSBjoern A. Zeeb 	return ret;
1696c92544dSBjoern A. Zeeb }
1706c92544dSBjoern A. Zeeb 
mt7663s_remove(struct sdio_func * func)1716c92544dSBjoern A. Zeeb static void mt7663s_remove(struct sdio_func *func)
1726c92544dSBjoern A. Zeeb {
1736c92544dSBjoern A. Zeeb 	struct mt7615_dev *dev = sdio_get_drvdata(func);
1746c92544dSBjoern A. Zeeb 
1756c92544dSBjoern A. Zeeb 	if (!test_and_clear_bit(MT76_STATE_INITIALIZED, &dev->mphy.state))
1766c92544dSBjoern A. Zeeb 		return;
1776c92544dSBjoern A. Zeeb 
1786c92544dSBjoern A. Zeeb 	ieee80211_unregister_hw(dev->mt76.hw);
1796c92544dSBjoern A. Zeeb 	mt76s_deinit(&dev->mt76);
1806c92544dSBjoern A. Zeeb 	mt76_free_device(&dev->mt76);
1816c92544dSBjoern A. Zeeb }
1826c92544dSBjoern A. Zeeb 
mt7663s_suspend(struct device * dev)1836c92544dSBjoern A. Zeeb static int mt7663s_suspend(struct device *dev)
1846c92544dSBjoern A. Zeeb {
1856c92544dSBjoern A. Zeeb 	struct sdio_func *func = dev_to_sdio_func(dev);
1866c92544dSBjoern A. Zeeb 	struct mt7615_dev *mdev = sdio_get_drvdata(func);
1876c92544dSBjoern A. Zeeb 	int err;
1886c92544dSBjoern A. Zeeb 
1896c92544dSBjoern A. Zeeb 	if (!test_bit(MT76_STATE_SUSPEND, &mdev->mphy.state) &&
1906c92544dSBjoern A. Zeeb 	    mt7615_firmware_offload(mdev)) {
1916c92544dSBjoern A. Zeeb 		int err;
1926c92544dSBjoern A. Zeeb 
1936c92544dSBjoern A. Zeeb 		err = mt76_connac_mcu_set_hif_suspend(&mdev->mt76, true);
1946c92544dSBjoern A. Zeeb 		if (err < 0)
1956c92544dSBjoern A. Zeeb 			return err;
1966c92544dSBjoern A. Zeeb 	}
1976c92544dSBjoern A. Zeeb 
1986c92544dSBjoern A. Zeeb 	sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
1996c92544dSBjoern A. Zeeb 
2006c92544dSBjoern A. Zeeb 	err = mt7615_mcu_set_fw_ctrl(mdev);
2016c92544dSBjoern A. Zeeb 	if (err)
2026c92544dSBjoern A. Zeeb 		return err;
2036c92544dSBjoern A. Zeeb 
2046c92544dSBjoern A. Zeeb 	mt76_worker_disable(&mdev->mt76.sdio.txrx_worker);
2056c92544dSBjoern A. Zeeb 	mt76_worker_disable(&mdev->mt76.sdio.status_worker);
2066c92544dSBjoern A. Zeeb 	mt76_worker_disable(&mdev->mt76.sdio.net_worker);
2076c92544dSBjoern A. Zeeb 
2086c92544dSBjoern A. Zeeb 	cancel_work_sync(&mdev->mt76.sdio.stat_work);
2096c92544dSBjoern A. Zeeb 	clear_bit(MT76_READING_STATS, &mdev->mphy.state);
2106c92544dSBjoern A. Zeeb 
2116c92544dSBjoern A. Zeeb 	mt76_tx_status_check(&mdev->mt76, true);
2126c92544dSBjoern A. Zeeb 
2136c92544dSBjoern A. Zeeb 	return 0;
2146c92544dSBjoern A. Zeeb }
2156c92544dSBjoern A. Zeeb 
mt7663s_resume(struct device * dev)2166c92544dSBjoern A. Zeeb static int mt7663s_resume(struct device *dev)
2176c92544dSBjoern A. Zeeb {
2186c92544dSBjoern A. Zeeb 	struct sdio_func *func = dev_to_sdio_func(dev);
2196c92544dSBjoern A. Zeeb 	struct mt7615_dev *mdev = sdio_get_drvdata(func);
2206c92544dSBjoern A. Zeeb 	int err;
2216c92544dSBjoern A. Zeeb 
2226c92544dSBjoern A. Zeeb 	mt76_worker_enable(&mdev->mt76.sdio.txrx_worker);
2236c92544dSBjoern A. Zeeb 	mt76_worker_enable(&mdev->mt76.sdio.status_worker);
2246c92544dSBjoern A. Zeeb 	mt76_worker_enable(&mdev->mt76.sdio.net_worker);
2256c92544dSBjoern A. Zeeb 
2266c92544dSBjoern A. Zeeb 	err = mt7615_mcu_set_drv_ctrl(mdev);
2276c92544dSBjoern A. Zeeb 	if (err)
2286c92544dSBjoern A. Zeeb 		return err;
2296c92544dSBjoern A. Zeeb 
2306c92544dSBjoern A. Zeeb 	if (!test_bit(MT76_STATE_SUSPEND, &mdev->mphy.state) &&
2316c92544dSBjoern A. Zeeb 	    mt7615_firmware_offload(mdev))
2326c92544dSBjoern A. Zeeb 		err = mt76_connac_mcu_set_hif_suspend(&mdev->mt76, false);
2336c92544dSBjoern A. Zeeb 
2346c92544dSBjoern A. Zeeb 	return err;
2356c92544dSBjoern A. Zeeb }
2366c92544dSBjoern A. Zeeb 
2376c92544dSBjoern A. Zeeb MODULE_DEVICE_TABLE(sdio, mt7663s_table);
2386c92544dSBjoern A. Zeeb MODULE_FIRMWARE(MT7663_OFFLOAD_FIRMWARE_N9);
2396c92544dSBjoern A. Zeeb MODULE_FIRMWARE(MT7663_OFFLOAD_ROM_PATCH);
2406c92544dSBjoern A. Zeeb MODULE_FIRMWARE(MT7663_FIRMWARE_N9);
2416c92544dSBjoern A. Zeeb MODULE_FIRMWARE(MT7663_ROM_PATCH);
2426c92544dSBjoern A. Zeeb 
2436c92544dSBjoern A. Zeeb static DEFINE_SIMPLE_DEV_PM_OPS(mt7663s_pm_ops, mt7663s_suspend, mt7663s_resume);
2446c92544dSBjoern A. Zeeb 
2456c92544dSBjoern A. Zeeb static struct sdio_driver mt7663s_driver = {
2466c92544dSBjoern A. Zeeb 	.name		= KBUILD_MODNAME,
2476c92544dSBjoern A. Zeeb 	.probe		= mt7663s_probe,
2486c92544dSBjoern A. Zeeb 	.remove		= mt7663s_remove,
2496c92544dSBjoern A. Zeeb 	.id_table	= mt7663s_table,
2506c92544dSBjoern A. Zeeb 	.drv.pm		= pm_sleep_ptr(&mt7663s_pm_ops),
2516c92544dSBjoern A. Zeeb };
2526c92544dSBjoern A. Zeeb module_sdio_driver(mt7663s_driver);
2536c92544dSBjoern A. Zeeb 
2546c92544dSBjoern A. Zeeb MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
2556c92544dSBjoern A. Zeeb MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>");
2566c92544dSBjoern A. Zeeb MODULE_LICENSE("Dual BSD/GPL");
257