Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/contrib/dev/mediatek/mt76/mt7921/sdio_mac.c
48526 views
1
// SPDX-License-Identifier: ISC
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
12
static 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
21
static 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
30
static u32 mt7921s_read_whcr(struct mt76_dev *dev)
31
{
32
return sdio_readl(dev->sdio.func, MCR_WHCR, NULL);
33
}
34
35
int 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
79
int 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
99
static struct mt76_sdio *msdio;
100
static 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
113
static DECLARE_WORK(sdio_reset_work, mt7921s_card_reset);
114
static 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
126
static 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
147
int 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);
194
out:
195
196
mt76_worker_enable(&dev->mt76.tx_worker);
197
198
return err;
199
}
200
201