File Index
Files and directories
Sign in
FILE

sdio_mac.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mac.c C
  1// SPDX-License-Identifier: BSD-3-Clause-Clear
  2/* 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#include <linux/mmc/host.h>
 10#include <linux/kallsyms.h>
 11
 12static void mt7921s_enable_irq(struct mt76_dev *dev)
 13{
 14	struct mt76_sdio *sdio = &dev->sdio;
 15
 16	sdio_claim_host(sdio->func);
 17	sdio_writel(sdio->func, WHLPCR_INT_EN_SET, MCR_WHLPCR, NULL);
 18	sdio_release_host(sdio->func);
 19}
 20
 21static void mt7921s_disable_irq(struct mt76_dev *dev)
 22{
 23	struct mt76_sdio *sdio = &dev->sdio;
 24
 25	sdio_claim_host(sdio->func);
 26	sdio_writel(sdio->func, WHLPCR_INT_EN_CLR, MCR_WHLPCR, NULL);
 27	sdio_release_host(sdio->func);
 28}
 29
 30static u32 mt7921s_read_whcr(struct mt76_dev *dev)
 31{
 32	return sdio_readl(dev->sdio.func, MCR_WHCR, NULL);
 33}
 34
 35int mt7921s_wfsys_reset(struct mt792x_dev *dev)
 36{
 37	struct mt76_sdio *sdio = &dev->mt76.sdio;
 38	u32 val, status;
 39
 40	if (atomic_read(&dev->mt76.bus_hung))
 41		return 0;
 42
 43	mt7921s_mcu_drv_pmctrl(dev);
 44
 45	sdio_claim_host(sdio->func);
 46
 47	val = sdio_readl(sdio->func, MCR_WHCR, NULL);
 48	val &= ~WF_WHOLE_PATH_RSTB;
 49	sdio_writel(sdio->func, val, MCR_WHCR, NULL);
 50
 51	msleep(50);
 52
 53	val = sdio_readl(sdio->func, MCR_WHCR, NULL);
 54	val &= ~WF_SDIO_WF_PATH_RSTB;
 55	sdio_writel(sdio->func, val, MCR_WHCR, NULL);
 56
 57	usleep_range(1000, 2000);
 58
 59	val = sdio_readl(sdio->func, MCR_WHCR, NULL);
 60	val |= WF_WHOLE_PATH_RSTB;
 61	sdio_writel(sdio->func, val, MCR_WHCR, NULL);
 62
 63	readx_poll_timeout(mt7921s_read_whcr, &dev->mt76, status,
 64			   status & WF_RST_DONE, 50000, 2000000);
 65
 66	sdio_release_host(sdio->func);
 67
 68	clear_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);
 69
 70	/* activate mt7921s again */
 71	mt7921s_mcu_drv_pmctrl(dev);
 72	mt76_clear(dev, MT_CONN_STATUS, MT_WIFI_PATCH_DL_STATE);
 73	mt7921s_mcu_fw_pmctrl(dev);
 74	mt7921s_mcu_drv_pmctrl(dev);
 75
 76	return 0;
 77}
 78
 79int mt7921s_init_reset(struct mt792x_dev *dev)
 80{
 81	set_bit(MT76_MCU_RESET, &dev->mphy.state);
 82
 83	wake_up(&dev->mt76.mcu.wait);
 84	skb_queue_purge(&dev->mt76.mcu.res_q);
 85	wait_event_timeout(dev->mt76.sdio.wait,
 86			   mt76s_txqs_empty(&dev->mt76), 5 * HZ);
 87	mt76_worker_disable(&dev->mt76.sdio.txrx_worker);
 88
 89	mt7921s_disable_irq(&dev->mt76);
 90	mt7921s_wfsys_reset(dev);
 91
 92	mt76_worker_enable(&dev->mt76.sdio.txrx_worker);
 93	clear_bit(MT76_MCU_RESET, &dev->mphy.state);
 94	mt7921s_enable_irq(&dev->mt76);
 95
 96	return 0;
 97}
 98
 99static struct mt76_sdio *msdio;
100static void mt7921s_card_reset(struct work_struct *work)
101{
102	struct mmc_host *sdio_host = msdio->func->card->host;
103
104	sdio_claim_host(msdio->func);
105	sdio_release_irq(msdio->func);
106	sdio_release_host(msdio->func);
107
108	mmc_remove_host(sdio_host);
109	msleep(50);
110	mmc_add_host(sdio_host);
111}
112
113static DECLARE_WORK(sdio_reset_work, mt7921s_card_reset);
114static int mt7921s_check_bus(struct mt76_dev *dev)
115{
116	struct mt76_sdio *sdio = &dev->sdio;
117	int err;
118
119	sdio_claim_host(sdio->func);
120	sdio_readl(dev->sdio.func, MCR_WHCR, &err);
121	sdio_release_host(sdio->func);
122
123	return err;
124}
125
126static int mt7921s_host_reset(struct mt792x_dev *dev)
127{
128	struct mt76_dev *mdev = &dev->mt76;
129	int err = -1;
130
131	if (!atomic_read(&mdev->bus_hung))
132		err = mt7921s_check_bus(&dev->mt76);
133
134	if (err) {
135		atomic_set(&mdev->bus_hung, true);
136		msdio = &dev->mt76.sdio;
137		dev_err(mdev->dev, "SDIO bus problem detected(%d), resetting card!!\n", err);
138		schedule_work(&sdio_reset_work);
139		return err;
140	}
141
142	atomic_set(&mdev->bus_hung, false);
143
144	return 0;
145}
146
147int mt7921s_mac_reset(struct mt792x_dev *dev)
148{
149	int err;
150
151	mt76_connac_free_pending_tx_skbs(&dev->pm, NULL);
152
153	mt7921s_host_reset(dev);
154	if (atomic_read(&dev->mt76.bus_hung))
155		return 0;
156
157	mt76_txq_schedule_all(&dev->mphy);
158	mt76_worker_disable(&dev->mt76.tx_worker);
159	set_bit(MT76_MCU_RESET, &dev->mphy.state);
160	wake_up(&dev->mt76.mcu.wait);
161	skb_queue_purge(&dev->mt76.mcu.res_q);
162	wait_event_timeout(dev->mt76.sdio.wait,
163			   mt76s_txqs_empty(&dev->mt76), 5 * HZ);
164	mt76_worker_disable(&dev->mt76.sdio.txrx_worker);
165	mt76_worker_disable(&dev->mt76.sdio.status_worker);
166	mt76_worker_disable(&dev->mt76.sdio.net_worker);
167	mt76_worker_disable(&dev->mt76.sdio.stat_worker);
168
169	mt7921s_disable_irq(&dev->mt76);
170	mt7921s_wfsys_reset(dev);
171
172	mt76_worker_enable(&dev->mt76.sdio.txrx_worker);
173	mt76_worker_enable(&dev->mt76.sdio.status_worker);
174	mt76_worker_enable(&dev->mt76.sdio.net_worker);
175	mt76_worker_enable(&dev->mt76.sdio.stat_worker);
176
177	dev->fw_assert = false;
178	clear_bit(MT76_MCU_RESET, &dev->mphy.state);
179	mt7921s_enable_irq(&dev->mt76);
180
181	err = mt7921_run_firmware(dev);
182	if (err)
183		goto out;
184
185	err = mt7921_mcu_set_eeprom(dev);
186	if (err)
187		goto out;
188
189	err = mt7921_mac_init(dev);
190	if (err)
191		goto out;
192
193	err = __mt7921_start(&dev->phy);
194out:
195
196	mt76_worker_enable(&dev->mt76.tx_worker);
197
198	return err;
199}
~/ Read-only file preview.