blob: 1b3adb3d91e8669cba891e5652025dc52abb58f2 [file] [log] [blame]
developer0f312e82022-11-01 12:31:52 +08001// 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
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 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
74int 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
94int 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);
136out:
137 clear_bit(MT76_RESET, &dev->mphy.state);
138
139 mt76_worker_enable(&dev->mt76.tx_worker);
140
141 return err;
142}