332 lines · c
1// SPDX-License-Identifier: ISC2/* Copyright (C) 2021 MediaTek Inc.3 *4 */5 6#include <linux/kernel.h>7#include <linux/iopoll.h>8#include <linux/module.h>9 10#include <linux/mmc/host.h>11#include <linux/mmc/sdio_ids.h>12#include <linux/mmc/sdio_func.h>13 14#include "mt7921.h"15#include "../sdio.h"16#include "../mt76_connac2_mac.h"17#include "mcu.h"18 19static const struct sdio_device_id mt7921s_table[] = {20 { SDIO_DEVICE(SDIO_VENDOR_ID_MEDIATEK, 0x7901),21 .driver_data = (kernel_ulong_t)MT7921_FIRMWARE_WM },22 { } /* Terminating entry */23};24 25static void mt7921s_txrx_worker(struct mt76_worker *w)26{27 struct mt76_sdio *sdio = container_of(w, struct mt76_sdio,28 txrx_worker);29 struct mt76_dev *mdev = container_of(sdio, struct mt76_dev, sdio);30 struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);31 32 if (!mt76_connac_pm_ref(&dev->mphy, &dev->pm)) {33 queue_work(mdev->wq, &dev->pm.wake_work);34 return;35 }36 37 mt76s_txrx_worker(sdio);38 mt76_connac_pm_unref(&dev->mphy, &dev->pm);39}40 41static void mt7921s_unregister_device(struct mt792x_dev *dev)42{43 struct mt76_connac_pm *pm = &dev->pm;44 45 cancel_work_sync(&dev->init_work);46 mt76_unregister_device(&dev->mt76);47 cancel_delayed_work_sync(&pm->ps_work);48 cancel_work_sync(&pm->wake_work);49 50 mt76s_deinit(&dev->mt76);51 mt7921s_wfsys_reset(dev);52 skb_queue_purge(&dev->mt76.mcu.res_q);53 54 mt76_free_device(&dev->mt76);55}56 57static int mt7921s_parse_intr(struct mt76_dev *dev, struct mt76s_intr *intr)58{59 struct mt76_sdio *sdio = &dev->sdio;60 struct mt7921_sdio_intr *irq_data = sdio->intr_data;61 int i, err;62 63 sdio_claim_host(sdio->func);64 err = sdio_readsb(sdio->func, irq_data, MCR_WHISR, sizeof(*irq_data));65 sdio_release_host(sdio->func);66 67 if (err < 0)68 return err;69 70 if (irq_data->rx.num[0] > 16 ||71 irq_data->rx.num[1] > 128)72 return -EINVAL;73 74 intr->isr = irq_data->isr;75 intr->rec_mb = irq_data->rec_mb;76 intr->tx.wtqcr = irq_data->tx.wtqcr;77 intr->rx.num = irq_data->rx.num;78 for (i = 0; i < 2 ; i++) {79 if (!i)80 intr->rx.len[0] = irq_data->rx.len0;81 else82 intr->rx.len[1] = irq_data->rx.len1;83 }84 85 return 0;86}87 88static int mt7921s_probe(struct sdio_func *func,89 const struct sdio_device_id *id)90{91 static const struct mt76_driver_ops drv_ops = {92 .txwi_size = MT_SDIO_TXD_SIZE,93 .drv_flags = MT_DRV_AMSDU_OFFLOAD,94 .survey_flags = SURVEY_INFO_TIME_TX |95 SURVEY_INFO_TIME_RX |96 SURVEY_INFO_TIME_BSS_RX,97 .tx_prepare_skb = mt7921_usb_sdio_tx_prepare_skb,98 .tx_complete_skb = mt7921_usb_sdio_tx_complete_skb,99 .tx_status_data = mt7921_usb_sdio_tx_status_data,100 .rx_skb = mt7921_queue_rx_skb,101 .rx_check = mt7921_rx_check,102 .sta_add = mt7921_mac_sta_add,103 .sta_event = mt7921_mac_sta_event,104 .sta_remove = mt7921_mac_sta_remove,105 .update_survey = mt792x_update_channel,106 .set_channel = mt7921_set_channel,107 };108 static const struct mt76_bus_ops mt7921s_ops = {109 .rr = mt76s_rr,110 .rmw = mt76s_rmw,111 .wr = mt76s_wr,112 .write_copy = mt76s_write_copy,113 .read_copy = mt76s_read_copy,114 .wr_rp = mt76s_wr_rp,115 .rd_rp = mt76s_rd_rp,116 .type = MT76_BUS_SDIO,117 };118 static const struct mt792x_hif_ops mt7921_sdio_ops = {119 .init_reset = mt7921s_init_reset,120 .reset = mt7921s_mac_reset,121 .mcu_init = mt7921s_mcu_init,122 .drv_own = mt7921s_mcu_drv_pmctrl,123 .fw_own = mt7921s_mcu_fw_pmctrl,124 };125 struct ieee80211_ops *ops;126 struct mt792x_dev *dev;127 struct mt76_dev *mdev;128 u8 features;129 int ret;130 131 ops = mt792x_get_mac80211_ops(&func->dev, &mt7921_ops,132 (void *)id->driver_data, &features);133 if (!ops)134 return -ENOMEM;135 136 mdev = mt76_alloc_device(&func->dev, sizeof(*dev), ops, &drv_ops);137 if (!mdev)138 return -ENOMEM;139 140 dev = container_of(mdev, struct mt792x_dev, mt76);141 dev->fw_features = features;142 dev->hif_ops = &mt7921_sdio_ops;143 sdio_set_drvdata(func, dev);144 145 ret = mt76s_init(mdev, func, &mt7921s_ops);146 if (ret < 0)147 goto error;148 149 ret = mt76s_hw_init(mdev, func, MT76_CONNAC2_SDIO);150 if (ret)151 goto error;152 153 mdev->rev = (mt76_rr(dev, MT_HW_CHIPID) << 16) |154 (mt76_rr(dev, MT_HW_REV) & 0xff);155 dev_dbg(mdev->dev, "ASIC revision: %04x\n", mdev->rev);156 157 mdev->sdio.parse_irq = mt7921s_parse_intr;158 mdev->sdio.intr_data = devm_kmalloc(mdev->dev,159 sizeof(struct mt7921_sdio_intr),160 GFP_KERNEL);161 if (!mdev->sdio.intr_data) {162 ret = -ENOMEM;163 goto error;164 }165 166 ret = mt76s_alloc_rx_queue(mdev, MT_RXQ_MAIN);167 if (ret)168 goto error;169 170 ret = mt76s_alloc_rx_queue(mdev, MT_RXQ_MCU);171 if (ret)172 goto error;173 174 ret = mt76s_alloc_tx(mdev);175 if (ret)176 goto error;177 178 ret = mt76_worker_setup(mt76_hw(dev), &mdev->sdio.txrx_worker,179 mt7921s_txrx_worker, "sdio-txrx");180 if (ret)181 goto error;182 183 sched_set_fifo_low(mdev->sdio.txrx_worker.task);184 185 ret = mt7921_register_device(dev);186 if (ret)187 goto error;188 189 return 0;190 191error:192 mt76s_deinit(&dev->mt76);193 mt76_free_device(&dev->mt76);194 195 return ret;196}197 198static void mt7921s_remove(struct sdio_func *func)199{200 struct mt792x_dev *dev = sdio_get_drvdata(func);201 202 mt7921s_unregister_device(dev);203}204 205static int mt7921s_suspend(struct device *__dev)206{207 struct sdio_func *func = dev_to_sdio_func(__dev);208 struct mt792x_dev *dev = sdio_get_drvdata(func);209 struct mt76_connac_pm *pm = &dev->pm;210 struct mt76_dev *mdev = &dev->mt76;211 int err;212 213 pm->suspended = true;214 set_bit(MT76_STATE_SUSPEND, &mdev->phy.state);215 216 flush_work(&dev->reset_work);217 cancel_delayed_work_sync(&pm->ps_work);218 cancel_work_sync(&pm->wake_work);219 220 mt7921_roc_abort_sync(dev);221 222 err = mt792x_mcu_drv_pmctrl(dev);223 if (err < 0)224 goto restore_suspend;225 226 /* always enable deep sleep during suspend to reduce227 * power consumption228 */229 mt76_connac_mcu_set_deep_sleep(mdev, true);230 231 mt76_txq_schedule_all(&dev->mphy);232 mt76_worker_disable(&mdev->tx_worker);233 mt76_worker_disable(&mdev->sdio.status_worker);234 mt76_worker_disable(&mdev->sdio.stat_worker);235 clear_bit(MT76_READING_STATS, &dev->mphy.state);236 mt76_tx_status_check(mdev, true);237 238 mt76_worker_schedule(&mdev->sdio.txrx_worker);239 wait_event_timeout(dev->mt76.sdio.wait,240 mt76s_txqs_empty(&dev->mt76), 5 * HZ);241 242 /* It is supposed that SDIO bus is idle at the point */243 err = mt76_connac_mcu_set_hif_suspend(mdev, true);244 if (err)245 goto restore_worker;246 247 mt76_worker_disable(&mdev->sdio.txrx_worker);248 mt76_worker_disable(&mdev->sdio.net_worker);249 250 err = mt792x_mcu_fw_pmctrl(dev);251 if (err)252 goto restore_txrx_worker;253 254 sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);255 256 return 0;257 258restore_txrx_worker:259 mt76_worker_enable(&mdev->sdio.net_worker);260 mt76_worker_enable(&mdev->sdio.txrx_worker);261 mt76_connac_mcu_set_hif_suspend(mdev, false);262 263restore_worker:264 mt76_worker_enable(&mdev->tx_worker);265 mt76_worker_enable(&mdev->sdio.status_worker);266 mt76_worker_enable(&mdev->sdio.stat_worker);267 268 if (!pm->ds_enable)269 mt76_connac_mcu_set_deep_sleep(mdev, false);270 271restore_suspend:272 clear_bit(MT76_STATE_SUSPEND, &mdev->phy.state);273 pm->suspended = false;274 275 if (err < 0)276 mt792x_reset(&dev->mt76);277 278 return err;279}280 281static int mt7921s_resume(struct device *__dev)282{283 struct sdio_func *func = dev_to_sdio_func(__dev);284 struct mt792x_dev *dev = sdio_get_drvdata(func);285 struct mt76_connac_pm *pm = &dev->pm;286 struct mt76_dev *mdev = &dev->mt76;287 int err;288 289 clear_bit(MT76_STATE_SUSPEND, &mdev->phy.state);290 291 err = mt792x_mcu_drv_pmctrl(dev);292 if (err < 0)293 goto failed;294 295 mt76_worker_enable(&mdev->tx_worker);296 mt76_worker_enable(&mdev->sdio.txrx_worker);297 mt76_worker_enable(&mdev->sdio.status_worker);298 mt76_worker_enable(&mdev->sdio.net_worker);299 mt76_worker_enable(&mdev->sdio.stat_worker);300 301 /* restore previous ds setting */302 if (!pm->ds_enable)303 mt76_connac_mcu_set_deep_sleep(mdev, false);304 305 err = mt76_connac_mcu_set_hif_suspend(mdev, false);306failed:307 pm->suspended = false;308 309 if (err < 0)310 mt792x_reset(&dev->mt76);311 312 return err;313}314 315MODULE_DEVICE_TABLE(sdio, mt7921s_table);316MODULE_FIRMWARE(MT7921_FIRMWARE_WM);317MODULE_FIRMWARE(MT7921_ROM_PATCH);318 319static DEFINE_SIMPLE_DEV_PM_OPS(mt7921s_pm_ops, mt7921s_suspend, mt7921s_resume);320 321static struct sdio_driver mt7921s_driver = {322 .name = KBUILD_MODNAME,323 .probe = mt7921s_probe,324 .remove = mt7921s_remove,325 .id_table = mt7921s_table,326 .drv.pm = pm_sleep_ptr(&mt7921s_pm_ops),327};328module_sdio_driver(mt7921s_driver);329MODULE_DESCRIPTION("MediaTek MT7921S (SDIO) wireless driver");330MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");331MODULE_LICENSE("Dual BSD/GPL");332