1 | // SPDX-License-Identifier: ISC |
2 | /* Copyright (C) 2021 MediaTek Inc. |
3 | * |
4 | */ |
5 | #include <linux/module.h> |
6 | #include <linux/firmware.h> |
7 | |
8 | #include <net/bluetooth/bluetooth.h> |
9 | #include <net/bluetooth/hci_core.h> |
10 | |
11 | #include "btmtk.h" |
12 | |
13 | #define VERSION "0.1" |
14 | |
15 | /* It is for mt79xx download rom patch*/ |
16 | #define 32 |
17 | #define MTK_FW_ROM_PATCH_GD_SIZE 64 |
18 | #define MTK_FW_ROM_PATCH_SEC_MAP_SIZE 64 |
19 | #define MTK_SEC_MAP_COMMON_SIZE 12 |
20 | #define MTK_SEC_MAP_NEED_SEND_SIZE 52 |
21 | |
22 | struct { |
23 | u8 [16]; |
24 | u8 [4]; |
25 | __le16 ; |
26 | __le16 ; |
27 | __le32 ; |
28 | } __packed; |
29 | |
30 | struct btmtk_global_desc { |
31 | __le32 patch_ver; |
32 | __le32 sub_sys; |
33 | __le32 feature_opt; |
34 | __le32 section_num; |
35 | } __packed; |
36 | |
37 | struct btmtk_section_map { |
38 | __le32 sectype; |
39 | __le32 secoffset; |
40 | __le32 secsize; |
41 | union { |
42 | __le32 u4SecSpec[13]; |
43 | struct { |
44 | __le32 dlAddr; |
45 | __le32 dlsize; |
46 | __le32 seckeyidx; |
47 | __le32 alignlen; |
48 | __le32 sectype; |
49 | __le32 dlmodecrctype; |
50 | __le32 crc; |
51 | __le32 reserved[6]; |
52 | } bin_info_spec; |
53 | }; |
54 | } __packed; |
55 | |
56 | static void btmtk_coredump(struct hci_dev *hdev) |
57 | { |
58 | int err; |
59 | |
60 | err = __hci_cmd_send(hdev, opcode: 0xfd5b, plen: 0, NULL); |
61 | if (err < 0) |
62 | bt_dev_err(hdev, "Coredump failed (%d)" , err); |
63 | } |
64 | |
65 | static void btmtk_coredump_hdr(struct hci_dev *hdev, struct sk_buff *skb) |
66 | { |
67 | struct btmediatek_data *data = hci_get_priv(hdev); |
68 | char buf[80]; |
69 | |
70 | snprintf(buf, size: sizeof(buf), fmt: "Controller Name: 0x%X\n" , |
71 | data->dev_id); |
72 | skb_put_data(skb, data: buf, strlen(buf)); |
73 | |
74 | snprintf(buf, size: sizeof(buf), fmt: "Firmware Version: 0x%X\n" , |
75 | data->cd_info.fw_version); |
76 | skb_put_data(skb, data: buf, strlen(buf)); |
77 | |
78 | snprintf(buf, size: sizeof(buf), fmt: "Driver: %s\n" , |
79 | data->cd_info.driver_name); |
80 | skb_put_data(skb, data: buf, strlen(buf)); |
81 | |
82 | snprintf(buf, size: sizeof(buf), fmt: "Vendor: MediaTek\n" ); |
83 | skb_put_data(skb, data: buf, strlen(buf)); |
84 | } |
85 | |
86 | static void btmtk_coredump_notify(struct hci_dev *hdev, int state) |
87 | { |
88 | struct btmediatek_data *data = hci_get_priv(hdev); |
89 | |
90 | switch (state) { |
91 | case HCI_DEVCOREDUMP_IDLE: |
92 | data->cd_info.state = HCI_DEVCOREDUMP_IDLE; |
93 | break; |
94 | case HCI_DEVCOREDUMP_ACTIVE: |
95 | data->cd_info.state = HCI_DEVCOREDUMP_ACTIVE; |
96 | break; |
97 | case HCI_DEVCOREDUMP_TIMEOUT: |
98 | case HCI_DEVCOREDUMP_ABORT: |
99 | case HCI_DEVCOREDUMP_DONE: |
100 | data->cd_info.state = HCI_DEVCOREDUMP_IDLE; |
101 | btmtk_reset_sync(hdev); |
102 | break; |
103 | } |
104 | } |
105 | |
106 | int btmtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname, |
107 | wmt_cmd_sync_func_t wmt_cmd_sync) |
108 | { |
109 | struct btmtk_hci_wmt_params wmt_params; |
110 | struct btmtk_patch_header *hdr; |
111 | struct btmtk_global_desc *globaldesc = NULL; |
112 | struct btmtk_section_map *sectionmap; |
113 | const struct firmware *fw; |
114 | const u8 *fw_ptr; |
115 | const u8 *fw_bin_ptr; |
116 | int err, dlen, i, status; |
117 | u8 flag, first_block, retry; |
118 | u32 section_num, dl_size, section_offset; |
119 | u8 cmd[64]; |
120 | |
121 | err = request_firmware(fw: &fw, name: fwname, device: &hdev->dev); |
122 | if (err < 0) { |
123 | bt_dev_err(hdev, "Failed to load firmware file (%d)" , err); |
124 | return err; |
125 | } |
126 | |
127 | fw_ptr = fw->data; |
128 | fw_bin_ptr = fw_ptr; |
129 | hdr = (struct btmtk_patch_header *)fw_ptr; |
130 | globaldesc = (struct btmtk_global_desc *)(fw_ptr + MTK_FW_ROM_PATCH_HEADER_SIZE); |
131 | section_num = le32_to_cpu(globaldesc->section_num); |
132 | |
133 | bt_dev_info(hdev, "HW/SW Version: 0x%04x%04x, Build Time: %s" , |
134 | le16_to_cpu(hdr->hwver), le16_to_cpu(hdr->swver), hdr->datetime); |
135 | |
136 | for (i = 0; i < section_num; i++) { |
137 | first_block = 1; |
138 | fw_ptr = fw_bin_ptr; |
139 | sectionmap = (struct btmtk_section_map *)(fw_ptr + MTK_FW_ROM_PATCH_HEADER_SIZE + |
140 | MTK_FW_ROM_PATCH_GD_SIZE + MTK_FW_ROM_PATCH_SEC_MAP_SIZE * i); |
141 | |
142 | section_offset = le32_to_cpu(sectionmap->secoffset); |
143 | dl_size = le32_to_cpu(sectionmap->bin_info_spec.dlsize); |
144 | |
145 | if (dl_size > 0) { |
146 | retry = 20; |
147 | while (retry > 0) { |
148 | cmd[0] = 0; /* 0 means legacy dl mode. */ |
149 | memcpy(cmd + 1, |
150 | fw_ptr + MTK_FW_ROM_PATCH_HEADER_SIZE + |
151 | MTK_FW_ROM_PATCH_GD_SIZE + |
152 | MTK_FW_ROM_PATCH_SEC_MAP_SIZE * i + |
153 | MTK_SEC_MAP_COMMON_SIZE, |
154 | MTK_SEC_MAP_NEED_SEND_SIZE + 1); |
155 | |
156 | wmt_params.op = BTMTK_WMT_PATCH_DWNLD; |
157 | wmt_params.status = &status; |
158 | wmt_params.flag = 0; |
159 | wmt_params.dlen = MTK_SEC_MAP_NEED_SEND_SIZE + 1; |
160 | wmt_params.data = &cmd; |
161 | |
162 | err = wmt_cmd_sync(hdev, &wmt_params); |
163 | if (err < 0) { |
164 | bt_dev_err(hdev, "Failed to send wmt patch dwnld (%d)" , |
165 | err); |
166 | goto err_release_fw; |
167 | } |
168 | |
169 | if (status == BTMTK_WMT_PATCH_UNDONE) { |
170 | break; |
171 | } else if (status == BTMTK_WMT_PATCH_PROGRESS) { |
172 | msleep(msecs: 100); |
173 | retry--; |
174 | } else if (status == BTMTK_WMT_PATCH_DONE) { |
175 | goto next_section; |
176 | } else { |
177 | bt_dev_err(hdev, "Failed wmt patch dwnld status (%d)" , |
178 | status); |
179 | err = -EIO; |
180 | goto err_release_fw; |
181 | } |
182 | } |
183 | |
184 | fw_ptr += section_offset; |
185 | wmt_params.op = BTMTK_WMT_PATCH_DWNLD; |
186 | wmt_params.status = NULL; |
187 | |
188 | while (dl_size > 0) { |
189 | dlen = min_t(int, 250, dl_size); |
190 | if (first_block == 1) { |
191 | flag = 1; |
192 | first_block = 0; |
193 | } else if (dl_size - dlen <= 0) { |
194 | flag = 3; |
195 | } else { |
196 | flag = 2; |
197 | } |
198 | |
199 | wmt_params.flag = flag; |
200 | wmt_params.dlen = dlen; |
201 | wmt_params.data = fw_ptr; |
202 | |
203 | err = wmt_cmd_sync(hdev, &wmt_params); |
204 | if (err < 0) { |
205 | bt_dev_err(hdev, "Failed to send wmt patch dwnld (%d)" , |
206 | err); |
207 | goto err_release_fw; |
208 | } |
209 | |
210 | dl_size -= dlen; |
211 | fw_ptr += dlen; |
212 | } |
213 | } |
214 | next_section: |
215 | continue; |
216 | } |
217 | /* Wait a few moments for firmware activation done */ |
218 | usleep_range(min: 100000, max: 120000); |
219 | |
220 | err_release_fw: |
221 | release_firmware(fw); |
222 | |
223 | return err; |
224 | } |
225 | EXPORT_SYMBOL_GPL(btmtk_setup_firmware_79xx); |
226 | |
227 | int btmtk_setup_firmware(struct hci_dev *hdev, const char *fwname, |
228 | wmt_cmd_sync_func_t wmt_cmd_sync) |
229 | { |
230 | struct btmtk_hci_wmt_params wmt_params; |
231 | const struct firmware *fw; |
232 | const u8 *fw_ptr; |
233 | size_t fw_size; |
234 | int err, dlen; |
235 | u8 flag, param; |
236 | |
237 | err = request_firmware(fw: &fw, name: fwname, device: &hdev->dev); |
238 | if (err < 0) { |
239 | bt_dev_err(hdev, "Failed to load firmware file (%d)" , err); |
240 | return err; |
241 | } |
242 | |
243 | /* Power on data RAM the firmware relies on. */ |
244 | param = 1; |
245 | wmt_params.op = BTMTK_WMT_FUNC_CTRL; |
246 | wmt_params.flag = 3; |
247 | wmt_params.dlen = sizeof(param); |
248 | wmt_params.data = ¶m; |
249 | wmt_params.status = NULL; |
250 | |
251 | err = wmt_cmd_sync(hdev, &wmt_params); |
252 | if (err < 0) { |
253 | bt_dev_err(hdev, "Failed to power on data RAM (%d)" , err); |
254 | goto err_release_fw; |
255 | } |
256 | |
257 | fw_ptr = fw->data; |
258 | fw_size = fw->size; |
259 | |
260 | /* The size of patch header is 30 bytes, should be skip */ |
261 | if (fw_size < 30) { |
262 | err = -EINVAL; |
263 | goto err_release_fw; |
264 | } |
265 | |
266 | fw_size -= 30; |
267 | fw_ptr += 30; |
268 | flag = 1; |
269 | |
270 | wmt_params.op = BTMTK_WMT_PATCH_DWNLD; |
271 | wmt_params.status = NULL; |
272 | |
273 | while (fw_size > 0) { |
274 | dlen = min_t(int, 250, fw_size); |
275 | |
276 | /* Tell device the position in sequence */ |
277 | if (fw_size - dlen <= 0) |
278 | flag = 3; |
279 | else if (fw_size < fw->size - 30) |
280 | flag = 2; |
281 | |
282 | wmt_params.flag = flag; |
283 | wmt_params.dlen = dlen; |
284 | wmt_params.data = fw_ptr; |
285 | |
286 | err = wmt_cmd_sync(hdev, &wmt_params); |
287 | if (err < 0) { |
288 | bt_dev_err(hdev, "Failed to send wmt patch dwnld (%d)" , |
289 | err); |
290 | goto err_release_fw; |
291 | } |
292 | |
293 | fw_size -= dlen; |
294 | fw_ptr += dlen; |
295 | } |
296 | |
297 | wmt_params.op = BTMTK_WMT_RST; |
298 | wmt_params.flag = 4; |
299 | wmt_params.dlen = 0; |
300 | wmt_params.data = NULL; |
301 | wmt_params.status = NULL; |
302 | |
303 | /* Activate funciton the firmware providing to */ |
304 | err = wmt_cmd_sync(hdev, &wmt_params); |
305 | if (err < 0) { |
306 | bt_dev_err(hdev, "Failed to send wmt rst (%d)" , err); |
307 | goto err_release_fw; |
308 | } |
309 | |
310 | /* Wait a few moments for firmware activation done */ |
311 | usleep_range(min: 10000, max: 12000); |
312 | |
313 | err_release_fw: |
314 | release_firmware(fw); |
315 | |
316 | return err; |
317 | } |
318 | EXPORT_SYMBOL_GPL(btmtk_setup_firmware); |
319 | |
320 | int btmtk_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) |
321 | { |
322 | struct sk_buff *skb; |
323 | long ret; |
324 | |
325 | skb = __hci_cmd_sync(hdev, opcode: 0xfc1a, plen: 6, param: bdaddr, HCI_INIT_TIMEOUT); |
326 | if (IS_ERR(ptr: skb)) { |
327 | ret = PTR_ERR(ptr: skb); |
328 | bt_dev_err(hdev, "changing Mediatek device address failed (%ld)" , |
329 | ret); |
330 | return ret; |
331 | } |
332 | kfree_skb(skb); |
333 | |
334 | return 0; |
335 | } |
336 | EXPORT_SYMBOL_GPL(btmtk_set_bdaddr); |
337 | |
338 | void btmtk_reset_sync(struct hci_dev *hdev) |
339 | { |
340 | struct btmediatek_data *reset_work = hci_get_priv(hdev); |
341 | int err; |
342 | |
343 | hci_dev_lock(hdev); |
344 | |
345 | err = hci_cmd_sync_queue(hdev, func: reset_work->reset_sync, NULL, NULL); |
346 | if (err) |
347 | bt_dev_err(hdev, "failed to reset (%d)" , err); |
348 | |
349 | hci_dev_unlock(hdev); |
350 | } |
351 | EXPORT_SYMBOL_GPL(btmtk_reset_sync); |
352 | |
353 | int btmtk_register_coredump(struct hci_dev *hdev, const char *name, |
354 | u32 fw_version) |
355 | { |
356 | struct btmediatek_data *data = hci_get_priv(hdev); |
357 | |
358 | if (!IS_ENABLED(CONFIG_DEV_COREDUMP)) |
359 | return -EOPNOTSUPP; |
360 | |
361 | data->cd_info.fw_version = fw_version; |
362 | data->cd_info.state = HCI_DEVCOREDUMP_IDLE; |
363 | data->cd_info.driver_name = name; |
364 | |
365 | return hci_devcd_register(hdev, coredump: btmtk_coredump, dmp_hdr: btmtk_coredump_hdr, |
366 | notify_change: btmtk_coredump_notify); |
367 | } |
368 | EXPORT_SYMBOL_GPL(btmtk_register_coredump); |
369 | |
370 | int btmtk_process_coredump(struct hci_dev *hdev, struct sk_buff *skb) |
371 | { |
372 | struct btmediatek_data *data = hci_get_priv(hdev); |
373 | int err; |
374 | |
375 | if (!IS_ENABLED(CONFIG_DEV_COREDUMP)) { |
376 | kfree_skb(skb); |
377 | return 0; |
378 | } |
379 | |
380 | switch (data->cd_info.state) { |
381 | case HCI_DEVCOREDUMP_IDLE: |
382 | err = hci_devcd_init(hdev, MTK_COREDUMP_SIZE); |
383 | if (err < 0) |
384 | break; |
385 | data->cd_info.cnt = 0; |
386 | |
387 | /* It is supposed coredump can be done within 5 seconds */ |
388 | schedule_delayed_work(dwork: &hdev->dump.dump_timeout, |
389 | delay: msecs_to_jiffies(m: 5000)); |
390 | fallthrough; |
391 | case HCI_DEVCOREDUMP_ACTIVE: |
392 | default: |
393 | err = hci_devcd_append(hdev, skb); |
394 | if (err < 0) |
395 | break; |
396 | data->cd_info.cnt++; |
397 | |
398 | /* Mediatek coredump data would be more than MTK_COREDUMP_NUM */ |
399 | if (data->cd_info.cnt > MTK_COREDUMP_NUM && |
400 | skb->len > MTK_COREDUMP_END_LEN) |
401 | if (!memcmp(p: (char *)&skb->data[skb->len - MTK_COREDUMP_END_LEN], |
402 | MTK_COREDUMP_END, MTK_COREDUMP_END_LEN - 1)) { |
403 | bt_dev_info(hdev, "Mediatek coredump end" ); |
404 | hci_devcd_complete(hdev); |
405 | } |
406 | |
407 | break; |
408 | } |
409 | |
410 | if (err < 0) |
411 | kfree_skb(skb); |
412 | |
413 | return err; |
414 | } |
415 | EXPORT_SYMBOL_GPL(btmtk_process_coredump); |
416 | |
417 | MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>" ); |
418 | MODULE_AUTHOR("Mark Chen <mark-yw.chen@mediatek.com>" ); |
419 | MODULE_DESCRIPTION("Bluetooth support for MediaTek devices ver " VERSION); |
420 | MODULE_VERSION(VERSION); |
421 | MODULE_LICENSE("GPL" ); |
422 | MODULE_FIRMWARE(FIRMWARE_MT7622); |
423 | MODULE_FIRMWARE(FIRMWARE_MT7663); |
424 | MODULE_FIRMWARE(FIRMWARE_MT7668); |
425 | MODULE_FIRMWARE(FIRMWARE_MT7922); |
426 | MODULE_FIRMWARE(FIRMWARE_MT7961); |
427 | MODULE_FIRMWARE(FIRMWARE_MT7925); |
428 | |