142 lines · c
1// SPDX-License-Identifier: ISC2/* Copyright (C) 2021 MediaTek Inc. */3 4#include <linux/iopoll.h>5#include <linux/mmc/sdio_func.h>6#include "mt7921.h"7#include "../mt76_connac2_mac.h"8#include "../sdio.h"9 10static void mt7921s_enable_irq(struct mt76_dev *dev)11{12 struct mt76_sdio *sdio = &dev->sdio;13 14 sdio_claim_host(sdio->func);15 sdio_writel(sdio->func, WHLPCR_INT_EN_SET, MCR_WHLPCR, NULL);16 sdio_release_host(sdio->func);17}18 19static void mt7921s_disable_irq(struct mt76_dev *dev)20{21 struct mt76_sdio *sdio = &dev->sdio;22 23 sdio_claim_host(sdio->func);24 sdio_writel(sdio->func, WHLPCR_INT_EN_CLR, MCR_WHLPCR, NULL);25 sdio_release_host(sdio->func);26}27 28static u32 mt7921s_read_whcr(struct mt76_dev *dev)29{30 return sdio_readl(dev->sdio.func, MCR_WHCR, NULL);31}32 33int mt7921s_wfsys_reset(struct mt792x_dev *dev)34{35 struct mt76_sdio *sdio = &dev->mt76.sdio;36 u32 val, status;37 38 mt7921s_mcu_drv_pmctrl(dev);39 40 sdio_claim_host(sdio->func);41 42 val = sdio_readl(sdio->func, MCR_WHCR, NULL);43 val &= ~WF_WHOLE_PATH_RSTB;44 sdio_writel(sdio->func, val, MCR_WHCR, NULL);45 46 msleep(50);47 48 val = sdio_readl(sdio->func, MCR_WHCR, NULL);49 val &= ~WF_SDIO_WF_PATH_RSTB;50 sdio_writel(sdio->func, val, MCR_WHCR, NULL);51 52 usleep_range(1000, 2000);53 54 val = sdio_readl(sdio->func, MCR_WHCR, NULL);55 val |= WF_WHOLE_PATH_RSTB;56 sdio_writel(sdio->func, val, MCR_WHCR, NULL);57 58 readx_poll_timeout(mt7921s_read_whcr, &dev->mt76, status,59 status & WF_RST_DONE, 50000, 2000000);60 61 sdio_release_host(sdio->func);62 63 clear_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);64 65 /* activate mt7921s again */66 mt7921s_mcu_drv_pmctrl(dev);67 mt76_clear(dev, MT_CONN_STATUS, MT_WIFI_PATCH_DL_STATE);68 mt7921s_mcu_fw_pmctrl(dev);69 mt7921s_mcu_drv_pmctrl(dev);70 71 return 0;72}73 74int mt7921s_init_reset(struct mt792x_dev *dev)75{76 set_bit(MT76_MCU_RESET, &dev->mphy.state);77 78 wake_up(&dev->mt76.mcu.wait);79 skb_queue_purge(&dev->mt76.mcu.res_q);80 wait_event_timeout(dev->mt76.sdio.wait,81 mt76s_txqs_empty(&dev->mt76), 5 * HZ);82 mt76_worker_disable(&dev->mt76.sdio.txrx_worker);83 84 mt7921s_disable_irq(&dev->mt76);85 mt7921s_wfsys_reset(dev);86 87 mt76_worker_enable(&dev->mt76.sdio.txrx_worker);88 clear_bit(MT76_MCU_RESET, &dev->mphy.state);89 mt7921s_enable_irq(&dev->mt76);90 91 return 0;92}93 94int mt7921s_mac_reset(struct mt792x_dev *dev)95{96 int err;97 98 mt76_connac_free_pending_tx_skbs(&dev->pm, NULL);99 mt76_txq_schedule_all(&dev->mphy);100 mt76_worker_disable(&dev->mt76.tx_worker);101 set_bit(MT76_MCU_RESET, &dev->mphy.state);102 wake_up(&dev->mt76.mcu.wait);103 skb_queue_purge(&dev->mt76.mcu.res_q);104 wait_event_timeout(dev->mt76.sdio.wait,105 mt76s_txqs_empty(&dev->mt76), 5 * HZ);106 mt76_worker_disable(&dev->mt76.sdio.txrx_worker);107 mt76_worker_disable(&dev->mt76.sdio.status_worker);108 mt76_worker_disable(&dev->mt76.sdio.net_worker);109 mt76_worker_disable(&dev->mt76.sdio.stat_worker);110 111 mt7921s_disable_irq(&dev->mt76);112 mt7921s_wfsys_reset(dev);113 114 mt76_worker_enable(&dev->mt76.sdio.txrx_worker);115 mt76_worker_enable(&dev->mt76.sdio.status_worker);116 mt76_worker_enable(&dev->mt76.sdio.net_worker);117 mt76_worker_enable(&dev->mt76.sdio.stat_worker);118 119 dev->fw_assert = false;120 clear_bit(MT76_MCU_RESET, &dev->mphy.state);121 mt7921s_enable_irq(&dev->mt76);122 123 err = mt7921_run_firmware(dev);124 if (err)125 goto out;126 127 err = mt7921_mcu_set_eeprom(dev);128 if (err)129 goto out;130 131 err = mt7921_mac_init(dev);132 if (err)133 goto out;134 135 err = __mt7921_start(&dev->phy);136out:137 138 mt76_worker_enable(&dev->mt76.tx_worker);139 140 return err;141}142