1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Bluetooth supports for Qualcomm Atheros chips |
4 | * |
5 | * Copyright (c) 2015 The Linux Foundation. All rights reserved. |
6 | */ |
7 | #include <linux/module.h> |
8 | #include <linux/firmware.h> |
9 | #include <linux/vmalloc.h> |
10 | |
11 | #include <net/bluetooth/bluetooth.h> |
12 | #include <net/bluetooth/hci_core.h> |
13 | |
14 | #include "btqca.h" |
15 | |
16 | #define VERSION "0.1" |
17 | |
18 | int qca_read_soc_version(struct hci_dev *hdev, struct qca_btsoc_version *ver, |
19 | enum qca_btsoc_type soc_type) |
20 | { |
21 | struct sk_buff *skb; |
22 | struct edl_event_hdr *edl; |
23 | char cmd; |
24 | int err = 0; |
25 | u8 event_type = HCI_EV_VENDOR; |
26 | u8 rlen = sizeof(*edl) + sizeof(*ver); |
27 | u8 rtype = EDL_APP_VER_RES_EVT; |
28 | |
29 | bt_dev_dbg(hdev, "QCA Version Request" ); |
30 | |
31 | /* Unlike other SoC's sending version command response as payload to |
32 | * VSE event. WCN3991 sends version command response as a payload to |
33 | * command complete event. |
34 | */ |
35 | if (soc_type >= QCA_WCN3991) { |
36 | event_type = 0; |
37 | rlen += 1; |
38 | rtype = EDL_PATCH_VER_REQ_CMD; |
39 | } |
40 | |
41 | cmd = EDL_PATCH_VER_REQ_CMD; |
42 | skb = __hci_cmd_sync_ev(hdev, EDL_PATCH_CMD_OPCODE, EDL_PATCH_CMD_LEN, |
43 | param: &cmd, event: event_type, HCI_INIT_TIMEOUT); |
44 | if (IS_ERR(ptr: skb)) { |
45 | err = PTR_ERR(ptr: skb); |
46 | bt_dev_err(hdev, "Reading QCA version information failed (%d)" , |
47 | err); |
48 | return err; |
49 | } |
50 | |
51 | if (skb->len != rlen) { |
52 | bt_dev_err(hdev, "QCA Version size mismatch len %d" , skb->len); |
53 | err = -EILSEQ; |
54 | goto out; |
55 | } |
56 | |
57 | edl = (struct edl_event_hdr *)(skb->data); |
58 | if (!edl) { |
59 | bt_dev_err(hdev, "QCA TLV with no header" ); |
60 | err = -EILSEQ; |
61 | goto out; |
62 | } |
63 | |
64 | if (edl->cresp != EDL_CMD_REQ_RES_EVT || |
65 | edl->rtype != rtype) { |
66 | bt_dev_err(hdev, "QCA Wrong packet received %d %d" , edl->cresp, |
67 | edl->rtype); |
68 | err = -EIO; |
69 | goto out; |
70 | } |
71 | |
72 | if (soc_type >= QCA_WCN3991) |
73 | memcpy(ver, edl->data + 1, sizeof(*ver)); |
74 | else |
75 | memcpy(ver, &edl->data, sizeof(*ver)); |
76 | |
77 | bt_dev_info(hdev, "QCA Product ID :0x%08x" , |
78 | le32_to_cpu(ver->product_id)); |
79 | bt_dev_info(hdev, "QCA SOC Version :0x%08x" , |
80 | le32_to_cpu(ver->soc_id)); |
81 | bt_dev_info(hdev, "QCA ROM Version :0x%08x" , |
82 | le16_to_cpu(ver->rom_ver)); |
83 | bt_dev_info(hdev, "QCA Patch Version:0x%08x" , |
84 | le16_to_cpu(ver->patch_ver)); |
85 | |
86 | if (ver->soc_id == 0 || ver->rom_ver == 0) |
87 | err = -EILSEQ; |
88 | |
89 | out: |
90 | kfree_skb(skb); |
91 | if (err) |
92 | bt_dev_err(hdev, "QCA Failed to get version (%d)" , err); |
93 | |
94 | return err; |
95 | } |
96 | EXPORT_SYMBOL_GPL(qca_read_soc_version); |
97 | |
98 | static int qca_read_fw_build_info(struct hci_dev *hdev) |
99 | { |
100 | struct sk_buff *skb; |
101 | struct edl_event_hdr *edl; |
102 | char cmd, build_label[QCA_FW_BUILD_VER_LEN]; |
103 | int build_lbl_len, err = 0; |
104 | |
105 | bt_dev_dbg(hdev, "QCA read fw build info" ); |
106 | |
107 | cmd = EDL_GET_BUILD_INFO_CMD; |
108 | skb = __hci_cmd_sync_ev(hdev, EDL_PATCH_CMD_OPCODE, EDL_PATCH_CMD_LEN, |
109 | param: &cmd, event: 0, HCI_INIT_TIMEOUT); |
110 | if (IS_ERR(ptr: skb)) { |
111 | err = PTR_ERR(ptr: skb); |
112 | bt_dev_err(hdev, "Reading QCA fw build info failed (%d)" , |
113 | err); |
114 | return err; |
115 | } |
116 | |
117 | edl = (struct edl_event_hdr *)(skb->data); |
118 | if (!edl) { |
119 | bt_dev_err(hdev, "QCA read fw build info with no header" ); |
120 | err = -EILSEQ; |
121 | goto out; |
122 | } |
123 | |
124 | if (edl->cresp != EDL_CMD_REQ_RES_EVT || |
125 | edl->rtype != EDL_GET_BUILD_INFO_CMD) { |
126 | bt_dev_err(hdev, "QCA Wrong packet received %d %d" , edl->cresp, |
127 | edl->rtype); |
128 | err = -EIO; |
129 | goto out; |
130 | } |
131 | |
132 | build_lbl_len = edl->data[0]; |
133 | if (build_lbl_len <= QCA_FW_BUILD_VER_LEN - 1) { |
134 | memcpy(build_label, edl->data + 1, build_lbl_len); |
135 | *(build_label + build_lbl_len) = '\0'; |
136 | } |
137 | |
138 | hci_set_fw_info(hdev, fmt: "%s" , build_label); |
139 | |
140 | out: |
141 | kfree_skb(skb); |
142 | return err; |
143 | } |
144 | |
145 | static int qca_send_patch_config_cmd(struct hci_dev *hdev) |
146 | { |
147 | const u8 cmd[] = { EDL_PATCH_CONFIG_CMD, 0x01, 0, 0, 0 }; |
148 | struct sk_buff *skb; |
149 | struct edl_event_hdr *edl; |
150 | int err; |
151 | |
152 | bt_dev_dbg(hdev, "QCA Patch config" ); |
153 | |
154 | skb = __hci_cmd_sync_ev(hdev, EDL_PATCH_CMD_OPCODE, plen: sizeof(cmd), |
155 | param: cmd, HCI_EV_VENDOR, HCI_INIT_TIMEOUT); |
156 | if (IS_ERR(ptr: skb)) { |
157 | err = PTR_ERR(ptr: skb); |
158 | bt_dev_err(hdev, "Sending QCA Patch config failed (%d)" , err); |
159 | return err; |
160 | } |
161 | |
162 | if (skb->len != 2) { |
163 | bt_dev_err(hdev, "QCA Patch config cmd size mismatch len %d" , skb->len); |
164 | err = -EILSEQ; |
165 | goto out; |
166 | } |
167 | |
168 | edl = (struct edl_event_hdr *)(skb->data); |
169 | if (!edl) { |
170 | bt_dev_err(hdev, "QCA Patch config with no header" ); |
171 | err = -EILSEQ; |
172 | goto out; |
173 | } |
174 | |
175 | if (edl->cresp != EDL_PATCH_CONFIG_RES_EVT || edl->rtype != EDL_PATCH_CONFIG_CMD) { |
176 | bt_dev_err(hdev, "QCA Wrong packet received %d %d" , edl->cresp, |
177 | edl->rtype); |
178 | err = -EIO; |
179 | goto out; |
180 | } |
181 | |
182 | err = 0; |
183 | |
184 | out: |
185 | kfree_skb(skb); |
186 | return err; |
187 | } |
188 | |
189 | static int qca_send_reset(struct hci_dev *hdev) |
190 | { |
191 | struct sk_buff *skb; |
192 | int err; |
193 | |
194 | bt_dev_dbg(hdev, "QCA HCI_RESET" ); |
195 | |
196 | skb = __hci_cmd_sync(hdev, HCI_OP_RESET, plen: 0, NULL, HCI_INIT_TIMEOUT); |
197 | if (IS_ERR(ptr: skb)) { |
198 | err = PTR_ERR(ptr: skb); |
199 | bt_dev_err(hdev, "QCA Reset failed (%d)" , err); |
200 | return err; |
201 | } |
202 | |
203 | kfree_skb(skb); |
204 | |
205 | return 0; |
206 | } |
207 | |
208 | static int qca_read_fw_board_id(struct hci_dev *hdev, u16 *bid) |
209 | { |
210 | u8 cmd; |
211 | struct sk_buff *skb; |
212 | struct edl_event_hdr *edl; |
213 | int err = 0; |
214 | |
215 | cmd = EDL_GET_BID_REQ_CMD; |
216 | skb = __hci_cmd_sync_ev(hdev, EDL_PATCH_CMD_OPCODE, EDL_PATCH_CMD_LEN, |
217 | param: &cmd, event: 0, HCI_INIT_TIMEOUT); |
218 | if (IS_ERR(ptr: skb)) { |
219 | err = PTR_ERR(ptr: skb); |
220 | bt_dev_err(hdev, "Reading QCA board ID failed (%d)" , err); |
221 | return err; |
222 | } |
223 | |
224 | edl = skb_pull_data(skb, len: sizeof(*edl)); |
225 | if (!edl) { |
226 | bt_dev_err(hdev, "QCA read board ID with no header" ); |
227 | err = -EILSEQ; |
228 | goto out; |
229 | } |
230 | |
231 | if (edl->cresp != EDL_CMD_REQ_RES_EVT || |
232 | edl->rtype != EDL_GET_BID_REQ_CMD) { |
233 | bt_dev_err(hdev, "QCA Wrong packet: %d %d" , edl->cresp, edl->rtype); |
234 | err = -EIO; |
235 | goto out; |
236 | } |
237 | |
238 | *bid = (edl->data[1] << 8) + edl->data[2]; |
239 | bt_dev_dbg(hdev, "%s: bid = %x" , __func__, *bid); |
240 | |
241 | out: |
242 | kfree_skb(skb); |
243 | return err; |
244 | } |
245 | |
246 | int qca_send_pre_shutdown_cmd(struct hci_dev *hdev) |
247 | { |
248 | struct sk_buff *skb; |
249 | int err; |
250 | |
251 | bt_dev_dbg(hdev, "QCA pre shutdown cmd" ); |
252 | |
253 | skb = __hci_cmd_sync_ev(hdev, QCA_PRE_SHUTDOWN_CMD, plen: 0, |
254 | NULL, HCI_EV_CMD_COMPLETE, HCI_INIT_TIMEOUT); |
255 | |
256 | if (IS_ERR(ptr: skb)) { |
257 | err = PTR_ERR(ptr: skb); |
258 | bt_dev_err(hdev, "QCA preshutdown_cmd failed (%d)" , err); |
259 | return err; |
260 | } |
261 | |
262 | kfree_skb(skb); |
263 | |
264 | return 0; |
265 | } |
266 | EXPORT_SYMBOL_GPL(qca_send_pre_shutdown_cmd); |
267 | |
268 | static void qca_tlv_check_data(struct hci_dev *hdev, |
269 | struct qca_fw_config *config, |
270 | u8 *fw_data, enum qca_btsoc_type soc_type) |
271 | { |
272 | const u8 *data; |
273 | u32 type_len; |
274 | u16 tag_id, tag_len; |
275 | int idx, length; |
276 | struct tlv_type_hdr *tlv; |
277 | struct tlv_type_patch *tlv_patch; |
278 | struct tlv_type_nvm *tlv_nvm; |
279 | uint8_t nvm_baud_rate = config->user_baud_rate; |
280 | |
281 | config->dnld_mode = QCA_SKIP_EVT_NONE; |
282 | config->dnld_type = QCA_SKIP_EVT_NONE; |
283 | |
284 | switch (config->type) { |
285 | case ELF_TYPE_PATCH: |
286 | config->dnld_mode = QCA_SKIP_EVT_VSE_CC; |
287 | config->dnld_type = QCA_SKIP_EVT_VSE_CC; |
288 | |
289 | bt_dev_dbg(hdev, "File Class : 0x%x" , fw_data[4]); |
290 | bt_dev_dbg(hdev, "Data Encoding : 0x%x" , fw_data[5]); |
291 | bt_dev_dbg(hdev, "File version : 0x%x" , fw_data[6]); |
292 | break; |
293 | case TLV_TYPE_PATCH: |
294 | tlv = (struct tlv_type_hdr *)fw_data; |
295 | type_len = le32_to_cpu(tlv->type_len); |
296 | tlv_patch = (struct tlv_type_patch *)tlv->data; |
297 | |
298 | /* For Rome version 1.1 to 3.1, all segment commands |
299 | * are acked by a vendor specific event (VSE). |
300 | * For Rome >= 3.2, the download mode field indicates |
301 | * if VSE is skipped by the controller. |
302 | * In case VSE is skipped, only the last segment is acked. |
303 | */ |
304 | config->dnld_mode = tlv_patch->download_mode; |
305 | config->dnld_type = config->dnld_mode; |
306 | |
307 | BT_DBG("TLV Type\t\t : 0x%x" , type_len & 0x000000ff); |
308 | BT_DBG("Total Length : %d bytes" , |
309 | le32_to_cpu(tlv_patch->total_size)); |
310 | BT_DBG("Patch Data Length : %d bytes" , |
311 | le32_to_cpu(tlv_patch->data_length)); |
312 | BT_DBG("Signing Format Version : 0x%x" , |
313 | tlv_patch->format_version); |
314 | BT_DBG("Signature Algorithm : 0x%x" , |
315 | tlv_patch->signature); |
316 | BT_DBG("Download mode : 0x%x" , |
317 | tlv_patch->download_mode); |
318 | BT_DBG("Reserved : 0x%x" , |
319 | tlv_patch->reserved1); |
320 | BT_DBG("Product ID : 0x%04x" , |
321 | le16_to_cpu(tlv_patch->product_id)); |
322 | BT_DBG("Rom Build Version : 0x%04x" , |
323 | le16_to_cpu(tlv_patch->rom_build)); |
324 | BT_DBG("Patch Version : 0x%04x" , |
325 | le16_to_cpu(tlv_patch->patch_version)); |
326 | BT_DBG("Reserved : 0x%x" , |
327 | le16_to_cpu(tlv_patch->reserved2)); |
328 | BT_DBG("Patch Entry Address : 0x%x" , |
329 | le32_to_cpu(tlv_patch->entry)); |
330 | break; |
331 | |
332 | case TLV_TYPE_NVM: |
333 | tlv = (struct tlv_type_hdr *)fw_data; |
334 | |
335 | type_len = le32_to_cpu(tlv->type_len); |
336 | length = (type_len >> 8) & 0x00ffffff; |
337 | |
338 | BT_DBG("TLV Type\t\t : 0x%x" , type_len & 0x000000ff); |
339 | BT_DBG("Length\t\t : %d bytes" , length); |
340 | |
341 | idx = 0; |
342 | data = tlv->data; |
343 | while (idx < length) { |
344 | tlv_nvm = (struct tlv_type_nvm *)(data + idx); |
345 | |
346 | tag_id = le16_to_cpu(tlv_nvm->tag_id); |
347 | tag_len = le16_to_cpu(tlv_nvm->tag_len); |
348 | |
349 | /* Update NVM tags as needed */ |
350 | switch (tag_id) { |
351 | case EDL_TAG_ID_HCI: |
352 | /* HCI transport layer parameters |
353 | * enabling software inband sleep |
354 | * onto controller side. |
355 | */ |
356 | tlv_nvm->data[0] |= 0x80; |
357 | |
358 | /* UART Baud Rate */ |
359 | if (soc_type >= QCA_WCN3991) |
360 | tlv_nvm->data[1] = nvm_baud_rate; |
361 | else |
362 | tlv_nvm->data[2] = nvm_baud_rate; |
363 | |
364 | break; |
365 | |
366 | case EDL_TAG_ID_DEEP_SLEEP: |
367 | /* Sleep enable mask |
368 | * enabling deep sleep feature on controller. |
369 | */ |
370 | tlv_nvm->data[0] |= 0x01; |
371 | |
372 | break; |
373 | } |
374 | |
375 | idx += (sizeof(u16) + sizeof(u16) + 8 + tag_len); |
376 | } |
377 | break; |
378 | |
379 | default: |
380 | BT_ERR("Unknown TLV type %d" , config->type); |
381 | break; |
382 | } |
383 | } |
384 | |
385 | static int qca_tlv_send_segment(struct hci_dev *hdev, int seg_size, |
386 | const u8 *data, enum qca_tlv_dnld_mode mode, |
387 | enum qca_btsoc_type soc_type) |
388 | { |
389 | struct sk_buff *skb; |
390 | struct edl_event_hdr *edl; |
391 | struct tlv_seg_resp *tlv_resp; |
392 | u8 cmd[MAX_SIZE_PER_TLV_SEGMENT + 2]; |
393 | int err = 0; |
394 | u8 event_type = HCI_EV_VENDOR; |
395 | u8 rlen = (sizeof(*edl) + sizeof(*tlv_resp)); |
396 | u8 rtype = EDL_TVL_DNLD_RES_EVT; |
397 | |
398 | cmd[0] = EDL_PATCH_TLV_REQ_CMD; |
399 | cmd[1] = seg_size; |
400 | memcpy(cmd + 2, data, seg_size); |
401 | |
402 | if (mode == QCA_SKIP_EVT_VSE_CC || mode == QCA_SKIP_EVT_VSE) |
403 | return __hci_cmd_send(hdev, EDL_PATCH_CMD_OPCODE, plen: seg_size + 2, |
404 | param: cmd); |
405 | |
406 | /* Unlike other SoC's sending version command response as payload to |
407 | * VSE event. WCN3991 sends version command response as a payload to |
408 | * command complete event. |
409 | */ |
410 | if (soc_type >= QCA_WCN3991) { |
411 | event_type = 0; |
412 | rlen = sizeof(*edl); |
413 | rtype = EDL_PATCH_TLV_REQ_CMD; |
414 | } |
415 | |
416 | skb = __hci_cmd_sync_ev(hdev, EDL_PATCH_CMD_OPCODE, plen: seg_size + 2, param: cmd, |
417 | event: event_type, HCI_INIT_TIMEOUT); |
418 | if (IS_ERR(ptr: skb)) { |
419 | err = PTR_ERR(ptr: skb); |
420 | bt_dev_err(hdev, "QCA Failed to send TLV segment (%d)" , err); |
421 | return err; |
422 | } |
423 | |
424 | if (skb->len != rlen) { |
425 | bt_dev_err(hdev, "QCA TLV response size mismatch" ); |
426 | err = -EILSEQ; |
427 | goto out; |
428 | } |
429 | |
430 | edl = (struct edl_event_hdr *)(skb->data); |
431 | if (!edl) { |
432 | bt_dev_err(hdev, "TLV with no header" ); |
433 | err = -EILSEQ; |
434 | goto out; |
435 | } |
436 | |
437 | if (edl->cresp != EDL_CMD_REQ_RES_EVT || edl->rtype != rtype) { |
438 | bt_dev_err(hdev, "QCA TLV with error stat 0x%x rtype 0x%x" , |
439 | edl->cresp, edl->rtype); |
440 | err = -EIO; |
441 | } |
442 | |
443 | if (soc_type >= QCA_WCN3991) |
444 | goto out; |
445 | |
446 | tlv_resp = (struct tlv_seg_resp *)(edl->data); |
447 | if (tlv_resp->result) { |
448 | bt_dev_err(hdev, "QCA TLV with error stat 0x%x rtype 0x%x (0x%x)" , |
449 | edl->cresp, edl->rtype, tlv_resp->result); |
450 | } |
451 | |
452 | out: |
453 | kfree_skb(skb); |
454 | |
455 | return err; |
456 | } |
457 | |
458 | static int qca_inject_cmd_complete_event(struct hci_dev *hdev) |
459 | { |
460 | struct hci_event_hdr *hdr; |
461 | struct hci_ev_cmd_complete *evt; |
462 | struct sk_buff *skb; |
463 | |
464 | skb = bt_skb_alloc(len: sizeof(*hdr) + sizeof(*evt) + 1, GFP_KERNEL); |
465 | if (!skb) |
466 | return -ENOMEM; |
467 | |
468 | hdr = skb_put(skb, len: sizeof(*hdr)); |
469 | hdr->evt = HCI_EV_CMD_COMPLETE; |
470 | hdr->plen = sizeof(*evt) + 1; |
471 | |
472 | evt = skb_put(skb, len: sizeof(*evt)); |
473 | evt->ncmd = 1; |
474 | evt->opcode = cpu_to_le16(QCA_HCI_CC_OPCODE); |
475 | |
476 | skb_put_u8(skb, QCA_HCI_CC_SUCCESS); |
477 | |
478 | hci_skb_pkt_type(skb) = HCI_EVENT_PKT; |
479 | |
480 | return hci_recv_frame(hdev, skb); |
481 | } |
482 | |
483 | static int qca_download_firmware(struct hci_dev *hdev, |
484 | struct qca_fw_config *config, |
485 | enum qca_btsoc_type soc_type, |
486 | u8 rom_ver) |
487 | { |
488 | const struct firmware *fw; |
489 | u8 *data; |
490 | const u8 *segment; |
491 | int ret, size, remain, i = 0; |
492 | |
493 | bt_dev_info(hdev, "QCA Downloading %s" , config->fwname); |
494 | |
495 | ret = request_firmware(fw: &fw, name: config->fwname, device: &hdev->dev); |
496 | if (ret) { |
497 | /* For WCN6750, if mbn file is not present then check for |
498 | * tlv file. |
499 | */ |
500 | if (soc_type == QCA_WCN6750 && config->type == ELF_TYPE_PATCH) { |
501 | bt_dev_dbg(hdev, "QCA Failed to request file: %s (%d)" , |
502 | config->fwname, ret); |
503 | config->type = TLV_TYPE_PATCH; |
504 | snprintf(buf: config->fwname, size: sizeof(config->fwname), |
505 | fmt: "qca/msbtfw%02x.tlv" , rom_ver); |
506 | bt_dev_info(hdev, "QCA Downloading %s" , config->fwname); |
507 | ret = request_firmware(fw: &fw, name: config->fwname, device: &hdev->dev); |
508 | if (ret) { |
509 | bt_dev_err(hdev, "QCA Failed to request file: %s (%d)" , |
510 | config->fwname, ret); |
511 | return ret; |
512 | } |
513 | } else { |
514 | bt_dev_err(hdev, "QCA Failed to request file: %s (%d)" , |
515 | config->fwname, ret); |
516 | return ret; |
517 | } |
518 | } |
519 | |
520 | size = fw->size; |
521 | data = vmalloc(size: fw->size); |
522 | if (!data) { |
523 | bt_dev_err(hdev, "QCA Failed to allocate memory for file: %s" , |
524 | config->fwname); |
525 | release_firmware(fw); |
526 | return -ENOMEM; |
527 | } |
528 | |
529 | memcpy(data, fw->data, size); |
530 | release_firmware(fw); |
531 | |
532 | qca_tlv_check_data(hdev, config, fw_data: data, soc_type); |
533 | |
534 | segment = data; |
535 | remain = size; |
536 | while (remain > 0) { |
537 | int segsize = min(MAX_SIZE_PER_TLV_SEGMENT, remain); |
538 | |
539 | bt_dev_dbg(hdev, "Send segment %d, size %d" , i++, segsize); |
540 | |
541 | remain -= segsize; |
542 | /* The last segment is always acked regardless download mode */ |
543 | if (!remain || segsize < MAX_SIZE_PER_TLV_SEGMENT) |
544 | config->dnld_mode = QCA_SKIP_EVT_NONE; |
545 | |
546 | ret = qca_tlv_send_segment(hdev, seg_size: segsize, data: segment, |
547 | mode: config->dnld_mode, soc_type); |
548 | if (ret) |
549 | goto out; |
550 | |
551 | segment += segsize; |
552 | } |
553 | |
554 | /* Latest qualcomm chipsets are not sending a command complete event |
555 | * for every fw packet sent. They only respond with a vendor specific |
556 | * event for the last packet. This optimization in the chip will |
557 | * decrease the BT in initialization time. Here we will inject a command |
558 | * complete event to avoid a command timeout error message. |
559 | */ |
560 | if (config->dnld_type == QCA_SKIP_EVT_VSE_CC || |
561 | config->dnld_type == QCA_SKIP_EVT_VSE) |
562 | ret = qca_inject_cmd_complete_event(hdev); |
563 | |
564 | out: |
565 | vfree(addr: data); |
566 | |
567 | return ret; |
568 | } |
569 | |
570 | static int qca_disable_soc_logging(struct hci_dev *hdev) |
571 | { |
572 | struct sk_buff *skb; |
573 | u8 cmd[2]; |
574 | int err; |
575 | |
576 | cmd[0] = QCA_DISABLE_LOGGING_SUB_OP; |
577 | cmd[1] = 0x00; |
578 | skb = __hci_cmd_sync_ev(hdev, QCA_DISABLE_LOGGING, plen: sizeof(cmd), param: cmd, |
579 | HCI_EV_CMD_COMPLETE, HCI_INIT_TIMEOUT); |
580 | if (IS_ERR(ptr: skb)) { |
581 | err = PTR_ERR(ptr: skb); |
582 | bt_dev_err(hdev, "QCA Failed to disable soc logging(%d)" , err); |
583 | return err; |
584 | } |
585 | |
586 | kfree_skb(skb); |
587 | |
588 | return 0; |
589 | } |
590 | |
591 | int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr) |
592 | { |
593 | struct sk_buff *skb; |
594 | u8 cmd[9]; |
595 | int err; |
596 | |
597 | cmd[0] = EDL_NVM_ACCESS_SET_REQ_CMD; |
598 | cmd[1] = 0x02; /* TAG ID */ |
599 | cmd[2] = sizeof(bdaddr_t); /* size */ |
600 | memcpy(cmd + 3, bdaddr, sizeof(bdaddr_t)); |
601 | skb = __hci_cmd_sync_ev(hdev, EDL_NVM_ACCESS_OPCODE, plen: sizeof(cmd), param: cmd, |
602 | HCI_EV_VENDOR, HCI_INIT_TIMEOUT); |
603 | if (IS_ERR(ptr: skb)) { |
604 | err = PTR_ERR(ptr: skb); |
605 | bt_dev_err(hdev, "QCA Change address command failed (%d)" , err); |
606 | return err; |
607 | } |
608 | |
609 | kfree_skb(skb); |
610 | |
611 | return 0; |
612 | } |
613 | EXPORT_SYMBOL_GPL(qca_set_bdaddr_rome); |
614 | |
615 | static void qca_generate_hsp_nvm_name(char *fwname, size_t max_size, |
616 | struct qca_btsoc_version ver, u8 rom_ver, u16 bid) |
617 | { |
618 | const char *variant; |
619 | |
620 | /* hsp gf chip */ |
621 | if ((le32_to_cpu(ver.soc_id) & QCA_HSP_GF_SOC_MASK) == QCA_HSP_GF_SOC_ID) |
622 | variant = "g" ; |
623 | else |
624 | variant = "" ; |
625 | |
626 | if (bid == 0x0) |
627 | snprintf(buf: fwname, size: max_size, fmt: "qca/hpnv%02x%s.bin" , rom_ver, variant); |
628 | else |
629 | snprintf(buf: fwname, size: max_size, fmt: "qca/hpnv%02x%s.%x" , rom_ver, variant, bid); |
630 | } |
631 | |
632 | int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, |
633 | enum qca_btsoc_type soc_type, struct qca_btsoc_version ver, |
634 | const char *firmware_name) |
635 | { |
636 | struct qca_fw_config config; |
637 | int err; |
638 | u8 rom_ver = 0; |
639 | u32 soc_ver; |
640 | u16 boardid = 0; |
641 | |
642 | bt_dev_dbg(hdev, "QCA setup on UART" ); |
643 | |
644 | soc_ver = get_soc_ver(ver.soc_id, ver.rom_ver); |
645 | |
646 | bt_dev_info(hdev, "QCA controller version 0x%08x" , soc_ver); |
647 | |
648 | config.user_baud_rate = baudrate; |
649 | |
650 | /* Firmware files to download are based on ROM version. |
651 | * ROM version is derived from last two bytes of soc_ver. |
652 | */ |
653 | if (soc_type == QCA_WCN3988) |
654 | rom_ver = ((soc_ver & 0x00000f00) >> 0x05) | (soc_ver & 0x0000000f); |
655 | else |
656 | rom_ver = ((soc_ver & 0x00000f00) >> 0x04) | (soc_ver & 0x0000000f); |
657 | |
658 | if (soc_type == QCA_WCN6750) |
659 | qca_send_patch_config_cmd(hdev); |
660 | |
661 | /* Download rampatch file */ |
662 | config.type = TLV_TYPE_PATCH; |
663 | switch (soc_type) { |
664 | case QCA_WCN3990: |
665 | case QCA_WCN3991: |
666 | case QCA_WCN3998: |
667 | snprintf(buf: config.fwname, size: sizeof(config.fwname), |
668 | fmt: "qca/crbtfw%02x.tlv" , rom_ver); |
669 | break; |
670 | case QCA_WCN3988: |
671 | snprintf(buf: config.fwname, size: sizeof(config.fwname), |
672 | fmt: "qca/apbtfw%02x.tlv" , rom_ver); |
673 | break; |
674 | case QCA_QCA2066: |
675 | snprintf(buf: config.fwname, size: sizeof(config.fwname), |
676 | fmt: "qca/hpbtfw%02x.tlv" , rom_ver); |
677 | break; |
678 | case QCA_QCA6390: |
679 | snprintf(buf: config.fwname, size: sizeof(config.fwname), |
680 | fmt: "qca/htbtfw%02x.tlv" , rom_ver); |
681 | break; |
682 | case QCA_WCN6750: |
683 | /* Choose mbn file by default.If mbn file is not found |
684 | * then choose tlv file |
685 | */ |
686 | config.type = ELF_TYPE_PATCH; |
687 | snprintf(buf: config.fwname, size: sizeof(config.fwname), |
688 | fmt: "qca/msbtfw%02x.mbn" , rom_ver); |
689 | break; |
690 | case QCA_WCN6855: |
691 | snprintf(buf: config.fwname, size: sizeof(config.fwname), |
692 | fmt: "qca/hpbtfw%02x.tlv" , rom_ver); |
693 | break; |
694 | case QCA_WCN7850: |
695 | snprintf(buf: config.fwname, size: sizeof(config.fwname), |
696 | fmt: "qca/hmtbtfw%02x.tlv" , rom_ver); |
697 | break; |
698 | default: |
699 | snprintf(buf: config.fwname, size: sizeof(config.fwname), |
700 | fmt: "qca/rampatch_%08x.bin" , soc_ver); |
701 | } |
702 | |
703 | err = qca_download_firmware(hdev, config: &config, soc_type, rom_ver); |
704 | if (err < 0) { |
705 | bt_dev_err(hdev, "QCA Failed to download patch (%d)" , err); |
706 | return err; |
707 | } |
708 | |
709 | /* Give the controller some time to get ready to receive the NVM */ |
710 | msleep(msecs: 10); |
711 | |
712 | if (soc_type == QCA_QCA2066) |
713 | qca_read_fw_board_id(hdev, bid: &boardid); |
714 | |
715 | /* Download NVM configuration */ |
716 | config.type = TLV_TYPE_NVM; |
717 | if (firmware_name) { |
718 | snprintf(buf: config.fwname, size: sizeof(config.fwname), |
719 | fmt: "qca/%s" , firmware_name); |
720 | } else { |
721 | switch (soc_type) { |
722 | case QCA_WCN3990: |
723 | case QCA_WCN3991: |
724 | case QCA_WCN3998: |
725 | if (le32_to_cpu(ver.soc_id) == QCA_WCN3991_SOC_ID) { |
726 | snprintf(buf: config.fwname, size: sizeof(config.fwname), |
727 | fmt: "qca/crnv%02xu.bin" , rom_ver); |
728 | } else { |
729 | snprintf(buf: config.fwname, size: sizeof(config.fwname), |
730 | fmt: "qca/crnv%02x.bin" , rom_ver); |
731 | } |
732 | break; |
733 | case QCA_WCN3988: |
734 | snprintf(buf: config.fwname, size: sizeof(config.fwname), |
735 | fmt: "qca/apnv%02x.bin" , rom_ver); |
736 | break; |
737 | case QCA_QCA2066: |
738 | qca_generate_hsp_nvm_name(fwname: config.fwname, |
739 | max_size: sizeof(config.fwname), ver, rom_ver, bid: boardid); |
740 | break; |
741 | case QCA_QCA6390: |
742 | snprintf(buf: config.fwname, size: sizeof(config.fwname), |
743 | fmt: "qca/htnv%02x.bin" , rom_ver); |
744 | break; |
745 | case QCA_WCN6750: |
746 | snprintf(buf: config.fwname, size: sizeof(config.fwname), |
747 | fmt: "qca/msnv%02x.bin" , rom_ver); |
748 | break; |
749 | case QCA_WCN6855: |
750 | snprintf(buf: config.fwname, size: sizeof(config.fwname), |
751 | fmt: "qca/hpnv%02x.bin" , rom_ver); |
752 | break; |
753 | case QCA_WCN7850: |
754 | snprintf(buf: config.fwname, size: sizeof(config.fwname), |
755 | fmt: "qca/hmtnv%02x.bin" , rom_ver); |
756 | break; |
757 | |
758 | default: |
759 | snprintf(buf: config.fwname, size: sizeof(config.fwname), |
760 | fmt: "qca/nvm_%08x.bin" , soc_ver); |
761 | } |
762 | } |
763 | |
764 | err = qca_download_firmware(hdev, config: &config, soc_type, rom_ver); |
765 | if (err < 0) { |
766 | bt_dev_err(hdev, "QCA Failed to download NVM (%d)" , err); |
767 | return err; |
768 | } |
769 | |
770 | switch (soc_type) { |
771 | case QCA_WCN3991: |
772 | case QCA_QCA2066: |
773 | case QCA_QCA6390: |
774 | case QCA_WCN6750: |
775 | case QCA_WCN6855: |
776 | case QCA_WCN7850: |
777 | err = qca_disable_soc_logging(hdev); |
778 | if (err < 0) |
779 | return err; |
780 | break; |
781 | default: |
782 | break; |
783 | } |
784 | |
785 | /* WCN399x and WCN6750 supports the Microsoft vendor extension with 0xFD70 as the |
786 | * VsMsftOpCode. |
787 | */ |
788 | switch (soc_type) { |
789 | case QCA_WCN3988: |
790 | case QCA_WCN3990: |
791 | case QCA_WCN3991: |
792 | case QCA_WCN3998: |
793 | case QCA_WCN6750: |
794 | hci_set_msft_opcode(hdev, opcode: 0xFD70); |
795 | break; |
796 | default: |
797 | break; |
798 | } |
799 | |
800 | /* Perform HCI reset */ |
801 | err = qca_send_reset(hdev); |
802 | if (err < 0) { |
803 | bt_dev_err(hdev, "QCA Failed to run HCI_RESET (%d)" , err); |
804 | return err; |
805 | } |
806 | |
807 | switch (soc_type) { |
808 | case QCA_WCN3991: |
809 | case QCA_WCN6750: |
810 | case QCA_WCN6855: |
811 | case QCA_WCN7850: |
812 | /* get fw build info */ |
813 | err = qca_read_fw_build_info(hdev); |
814 | if (err < 0) |
815 | return err; |
816 | break; |
817 | default: |
818 | break; |
819 | } |
820 | |
821 | bt_dev_info(hdev, "QCA setup on UART is completed" ); |
822 | |
823 | return 0; |
824 | } |
825 | EXPORT_SYMBOL_GPL(qca_uart_setup); |
826 | |
827 | int qca_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) |
828 | { |
829 | struct sk_buff *skb; |
830 | int err; |
831 | |
832 | skb = __hci_cmd_sync_ev(hdev, EDL_WRITE_BD_ADDR_OPCODE, plen: 6, param: bdaddr, |
833 | HCI_EV_VENDOR, HCI_INIT_TIMEOUT); |
834 | if (IS_ERR(ptr: skb)) { |
835 | err = PTR_ERR(ptr: skb); |
836 | bt_dev_err(hdev, "QCA Change address cmd failed (%d)" , err); |
837 | return err; |
838 | } |
839 | |
840 | kfree_skb(skb); |
841 | |
842 | return 0; |
843 | } |
844 | EXPORT_SYMBOL_GPL(qca_set_bdaddr); |
845 | |
846 | |
847 | MODULE_AUTHOR("Ben Young Tae Kim <ytkim@qca.qualcomm.com>" ); |
848 | MODULE_DESCRIPTION("Bluetooth support for Qualcomm Atheros family ver " VERSION); |
849 | MODULE_VERSION(VERSION); |
850 | MODULE_LICENSE("GPL" ); |
851 | |