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 "mac.h"
8 #include "../sdio.h"
9 
mt7921s_enable_irq(struct mt76_dev * dev)10 static 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 
mt7921s_disable_irq(struct mt76_dev * dev)19 static 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 
mt7921s_read_whcr(struct mt76_dev * dev)28 static u32 mt7921s_read_whcr(struct mt76_dev *dev)
29 {
30 	return sdio_readl(dev->sdio.func, MCR_WHCR, NULL);
31 }
32 
mt7921s_wfsys_reset(struct mt7921_dev * dev)33 int mt7921s_wfsys_reset(struct mt7921_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 
mt7921s_init_reset(struct mt7921_dev * dev)74 int mt7921s_init_reset(struct mt7921_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 
mt7921s_mac_reset(struct mt7921_dev * dev)94 int mt7921s_mac_reset(struct mt7921_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_RESET, &dev->mphy.state);
102 	set_bit(MT76_MCU_RESET, &dev->mphy.state);
103 	wake_up(&dev->mt76.mcu.wait);
104 	skb_queue_purge(&dev->mt76.mcu.res_q);
105 	wait_event_timeout(dev->mt76.sdio.wait,
106 			   mt76s_txqs_empty(&dev->mt76), 5 * HZ);
107 	mt76_worker_disable(&dev->mt76.sdio.txrx_worker);
108 	mt76_worker_disable(&dev->mt76.sdio.status_worker);
109 	mt76_worker_disable(&dev->mt76.sdio.net_worker);
110 	cancel_work_sync(&dev->mt76.sdio.stat_work);
111 
112 	mt7921s_disable_irq(&dev->mt76);
113 	mt7921s_wfsys_reset(dev);
114 
115 	mt76_worker_enable(&dev->mt76.sdio.txrx_worker);
116 	mt76_worker_enable(&dev->mt76.sdio.status_worker);
117 	mt76_worker_enable(&dev->mt76.sdio.net_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);
136 out:
137 	clear_bit(MT76_RESET, &dev->mphy.state);
138 
139 	mt76_worker_enable(&dev->mt76.tx_worker);
140 
141 	return err;
142 }
143