Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/contrib/dev/mediatek/mt76/mt76x2/usb_mcu.c
48525 views
1
// SPDX-License-Identifier: ISC
2
/*
3
* Copyright (C) 2018 Lorenzo Bianconi <[email protected]>
4
*/
5
6
#include <linux/firmware.h>
7
8
#include "mt76x2u.h"
9
#include "eeprom.h"
10
#include "../mt76x02_usb.h"
11
12
#define MT_CMD_HDR_LEN 4
13
14
#define MCU_FW_URB_MAX_PAYLOAD 0x3900
15
#define MCU_ROM_PATCH_MAX_PAYLOAD 2048
16
17
#define MT76U_MCU_ILM_OFFSET 0x80000
18
#define MT76U_MCU_DLM_OFFSET 0x110000
19
#define MT76U_MCU_ROM_PATCH_OFFSET 0x90000
20
21
static void mt76x2u_mcu_load_ivb(struct mt76x02_dev *dev)
22
{
23
mt76u_vendor_request(&dev->mt76, MT_VEND_DEV_MODE,
24
USB_DIR_OUT | USB_TYPE_VENDOR,
25
0x12, 0, NULL, 0);
26
}
27
28
static void mt76x2u_mcu_enable_patch(struct mt76x02_dev *dev)
29
{
30
struct mt76_usb *usb = &dev->mt76.usb;
31
static const u8 data[] = {
32
0x6f, 0xfc, 0x08, 0x01,
33
0x20, 0x04, 0x00, 0x00,
34
0x00, 0x09, 0x00,
35
};
36
37
memcpy(usb->data, data, sizeof(data));
38
mt76u_vendor_request(&dev->mt76, MT_VEND_DEV_MODE,
39
USB_DIR_OUT | USB_TYPE_CLASS,
40
0x12, 0, usb->data, sizeof(data));
41
}
42
43
static void mt76x2u_mcu_reset_wmt(struct mt76x02_dev *dev)
44
{
45
struct mt76_usb *usb = &dev->mt76.usb;
46
u8 data[] = {
47
0x6f, 0xfc, 0x05, 0x01,
48
0x07, 0x01, 0x00, 0x04
49
};
50
51
memcpy(usb->data, data, sizeof(data));
52
mt76u_vendor_request(&dev->mt76, MT_VEND_DEV_MODE,
53
USB_DIR_OUT | USB_TYPE_CLASS,
54
0x12, 0, usb->data, sizeof(data));
55
}
56
57
static int mt76x2u_mcu_load_rom_patch(struct mt76x02_dev *dev)
58
{
59
bool rom_protect = !is_mt7612(dev);
60
struct mt76x02_patch_header *hdr;
61
u32 val, patch_mask, patch_reg;
62
const struct firmware *fw;
63
int err;
64
65
if (rom_protect &&
66
!mt76_poll_msec(dev, MT_MCU_SEMAPHORE_03, 1, 1, 600)) {
67
dev_err(dev->mt76.dev,
68
"could not get hardware semaphore for ROM PATCH\n");
69
return -ETIMEDOUT;
70
}
71
72
if (mt76xx_rev(dev) >= MT76XX_REV_E3) {
73
patch_mask = BIT(0);
74
patch_reg = MT_MCU_CLOCK_CTL;
75
} else {
76
patch_mask = BIT(1);
77
patch_reg = MT_MCU_COM_REG0;
78
}
79
80
if (rom_protect && (mt76_rr(dev, patch_reg) & patch_mask)) {
81
dev_info(dev->mt76.dev, "ROM patch already applied\n");
82
return 0;
83
}
84
85
err = request_firmware(&fw, MT7662_ROM_PATCH, dev->mt76.dev);
86
if (err < 0)
87
return err;
88
89
if (!fw || !fw->data || fw->size <= sizeof(*hdr)) {
90
dev_err(dev->mt76.dev, "failed to load firmware\n");
91
err = -EIO;
92
goto out;
93
}
94
95
hdr = (struct mt76x02_patch_header *)fw->data;
96
dev_info(dev->mt76.dev, "ROM patch build: %.15s\n", hdr->build_time);
97
98
/* enable USB_DMA_CFG */
99
val = MT_USB_DMA_CFG_RX_BULK_EN |
100
MT_USB_DMA_CFG_TX_BULK_EN |
101
FIELD_PREP(MT_USB_DMA_CFG_RX_BULK_AGG_TOUT, 0x20);
102
mt76_wr(dev, MT_VEND_ADDR(CFG, MT_USB_U3DMA_CFG), val);
103
104
/* vendor reset */
105
mt76x02u_mcu_fw_reset(dev);
106
usleep_range(5000, 10000);
107
108
/* enable FCE to send in-band cmd */
109
mt76_wr(dev, MT_FCE_PSE_CTRL, 0x1);
110
/* FCE tx_fs_base_ptr */
111
mt76_wr(dev, MT_TX_CPU_FROM_FCE_BASE_PTR, 0x400230);
112
/* FCE tx_fs_max_cnt */
113
mt76_wr(dev, MT_TX_CPU_FROM_FCE_MAX_COUNT, 0x1);
114
/* FCE pdma enable */
115
mt76_wr(dev, MT_FCE_PDMA_GLOBAL_CONF, 0x44);
116
/* FCE skip_fs_en */
117
mt76_wr(dev, MT_FCE_SKIP_FS, 0x3);
118
119
err = mt76x02u_mcu_fw_send_data(dev, fw->data + sizeof(*hdr),
120
fw->size - sizeof(*hdr),
121
MCU_ROM_PATCH_MAX_PAYLOAD,
122
MT76U_MCU_ROM_PATCH_OFFSET);
123
if (err < 0) {
124
err = -EIO;
125
goto out;
126
}
127
128
mt76x2u_mcu_enable_patch(dev);
129
mt76x2u_mcu_reset_wmt(dev);
130
mdelay(20);
131
132
if (!mt76_poll_msec(dev, patch_reg, patch_mask, patch_mask, 100)) {
133
dev_err(dev->mt76.dev, "failed to load ROM patch\n");
134
err = -ETIMEDOUT;
135
}
136
137
out:
138
if (rom_protect)
139
mt76_wr(dev, MT_MCU_SEMAPHORE_03, 1);
140
release_firmware(fw);
141
return err;
142
}
143
144
static int mt76x2u_mcu_load_firmware(struct mt76x02_dev *dev)
145
{
146
u32 val, dlm_offset = MT76U_MCU_DLM_OFFSET;
147
const struct mt76x02_fw_header *hdr;
148
int err, len, ilm_len, dlm_len;
149
const struct firmware *fw;
150
151
err = request_firmware(&fw, MT7662_FIRMWARE, dev->mt76.dev);
152
if (err < 0)
153
return err;
154
155
if (!fw || !fw->data || fw->size < sizeof(*hdr)) {
156
err = -EINVAL;
157
goto out;
158
}
159
160
hdr = (const struct mt76x02_fw_header *)fw->data;
161
ilm_len = le32_to_cpu(hdr->ilm_len);
162
dlm_len = le32_to_cpu(hdr->dlm_len);
163
len = sizeof(*hdr) + ilm_len + dlm_len;
164
if (fw->size != len) {
165
err = -EINVAL;
166
goto out;
167
}
168
169
val = le16_to_cpu(hdr->fw_ver);
170
dev_info(dev->mt76.dev, "Firmware Version: %d.%d.%02d\n",
171
(val >> 12) & 0xf, (val >> 8) & 0xf, val & 0xf);
172
173
val = le16_to_cpu(hdr->build_ver);
174
dev_info(dev->mt76.dev, "Build: %x\n", val);
175
dev_info(dev->mt76.dev, "Build Time: %.16s\n", hdr->build_time);
176
177
/* vendor reset */
178
mt76x02u_mcu_fw_reset(dev);
179
usleep_range(5000, 10000);
180
181
/* enable USB_DMA_CFG */
182
val = MT_USB_DMA_CFG_RX_BULK_EN |
183
MT_USB_DMA_CFG_TX_BULK_EN |
184
FIELD_PREP(MT_USB_DMA_CFG_RX_BULK_AGG_TOUT, 0x20);
185
mt76_wr(dev, MT_VEND_ADDR(CFG, MT_USB_U3DMA_CFG), val);
186
/* enable FCE to send in-band cmd */
187
mt76_wr(dev, MT_FCE_PSE_CTRL, 0x1);
188
/* FCE tx_fs_base_ptr */
189
mt76_wr(dev, MT_TX_CPU_FROM_FCE_BASE_PTR, 0x400230);
190
/* FCE tx_fs_max_cnt */
191
mt76_wr(dev, MT_TX_CPU_FROM_FCE_MAX_COUNT, 0x1);
192
/* FCE pdma enable */
193
mt76_wr(dev, MT_FCE_PDMA_GLOBAL_CONF, 0x44);
194
/* FCE skip_fs_en */
195
mt76_wr(dev, MT_FCE_SKIP_FS, 0x3);
196
197
/* load ILM */
198
err = mt76x02u_mcu_fw_send_data(dev, fw->data + sizeof(*hdr),
199
ilm_len, MCU_FW_URB_MAX_PAYLOAD,
200
MT76U_MCU_ILM_OFFSET);
201
if (err < 0) {
202
err = -EIO;
203
goto out;
204
}
205
206
/* load DLM */
207
if (mt76xx_rev(dev) >= MT76XX_REV_E3)
208
dlm_offset += 0x800;
209
err = mt76x02u_mcu_fw_send_data(dev, fw->data + sizeof(*hdr) + ilm_len,
210
dlm_len, MCU_FW_URB_MAX_PAYLOAD,
211
dlm_offset);
212
if (err < 0) {
213
err = -EIO;
214
goto out;
215
}
216
217
mt76x2u_mcu_load_ivb(dev);
218
if (!mt76_poll_msec(dev, MT_MCU_COM_REG0, 1, 1, 100)) {
219
dev_err(dev->mt76.dev, "firmware failed to start\n");
220
err = -ETIMEDOUT;
221
goto out;
222
}
223
224
mt76_set(dev, MT_MCU_COM_REG0, BIT(1));
225
/* enable FCE to send in-band cmd */
226
mt76_wr(dev, MT_FCE_PSE_CTRL, 0x1);
227
mt76x02_set_ethtool_fwver(dev, hdr);
228
dev_dbg(dev->mt76.dev, "firmware running\n");
229
230
out:
231
release_firmware(fw);
232
return err;
233
}
234
235
int mt76x2u_mcu_fw_init(struct mt76x02_dev *dev)
236
{
237
int err;
238
239
err = mt76x2u_mcu_load_rom_patch(dev);
240
if (err < 0)
241
return err;
242
243
return mt76x2u_mcu_load_firmware(dev);
244
}
245
246
int mt76x2u_mcu_init(struct mt76x02_dev *dev)
247
{
248
int err;
249
250
err = mt76x02_mcu_function_select(dev, Q_SELECT, 1);
251
if (err < 0)
252
return err;
253
254
return mt76x02_mcu_set_radio_state(dev, true);
255
}
256
257