.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Bluetooth supports for Qualcomm Atheros chips |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (c) 2015 The Linux Foundation. All rights reserved. |
---|
5 | | - * |
---|
6 | | - * This program is free software; you can redistribute it and/or modify |
---|
7 | | - * it under the terms of the GNU General Public License version 2 |
---|
8 | | - * as published by the Free Software Foundation |
---|
9 | | - * |
---|
10 | | - * This program is distributed in the hope that it will be useful, |
---|
11 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
12 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
13 | | - * GNU General Public License for more details. |
---|
14 | | - * |
---|
15 | | - * You should have received a copy of the GNU General Public License |
---|
16 | | - * along with this program; if not, write to the Free Software |
---|
17 | | - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
---|
18 | | - * |
---|
19 | 6 | */ |
---|
20 | 7 | #include <linux/module.h> |
---|
21 | 8 | #include <linux/firmware.h> |
---|
.. | .. |
---|
27 | 14 | |
---|
28 | 15 | #define VERSION "0.1" |
---|
29 | 16 | |
---|
30 | | -int qca_read_soc_version(struct hci_dev *hdev, u32 *soc_version) |
---|
| 17 | +int qca_read_soc_version(struct hci_dev *hdev, u32 *soc_version, |
---|
| 18 | + enum qca_btsoc_type soc_type) |
---|
31 | 19 | { |
---|
32 | 20 | struct sk_buff *skb; |
---|
33 | 21 | struct edl_event_hdr *edl; |
---|
34 | | - struct rome_version *ver; |
---|
| 22 | + struct qca_btsoc_version *ver; |
---|
35 | 23 | char cmd; |
---|
36 | 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; |
---|
37 | 28 | |
---|
38 | 29 | bt_dev_dbg(hdev, "QCA Version Request"); |
---|
39 | 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 | + |
---|
40 | 41 | cmd = EDL_PATCH_VER_REQ_CMD; |
---|
41 | 42 | skb = __hci_cmd_sync_ev(hdev, EDL_PATCH_CMD_OPCODE, EDL_PATCH_CMD_LEN, |
---|
42 | | - &cmd, HCI_EV_VENDOR, HCI_INIT_TIMEOUT); |
---|
| 43 | + &cmd, event_type, HCI_INIT_TIMEOUT); |
---|
43 | 44 | if (IS_ERR(skb)) { |
---|
44 | 45 | err = PTR_ERR(skb); |
---|
45 | 46 | bt_dev_err(hdev, "Reading QCA version information failed (%d)", |
---|
.. | .. |
---|
47 | 48 | return err; |
---|
48 | 49 | } |
---|
49 | 50 | |
---|
50 | | - if (skb->len != sizeof(*edl) + sizeof(*ver)) { |
---|
| 51 | + if (skb->len != rlen) { |
---|
51 | 52 | bt_dev_err(hdev, "QCA Version size mismatch len %d", skb->len); |
---|
52 | 53 | err = -EILSEQ; |
---|
53 | 54 | goto out; |
---|
.. | .. |
---|
61 | 62 | } |
---|
62 | 63 | |
---|
63 | 64 | if (edl->cresp != EDL_CMD_REQ_RES_EVT || |
---|
64 | | - edl->rtype != EDL_APP_VER_RES_EVT) { |
---|
| 65 | + edl->rtype != rtype) { |
---|
65 | 66 | bt_dev_err(hdev, "QCA Wrong packet received %d %d", edl->cresp, |
---|
66 | 67 | edl->rtype); |
---|
67 | 68 | err = -EIO; |
---|
68 | 69 | goto out; |
---|
69 | 70 | } |
---|
70 | 71 | |
---|
71 | | - ver = (struct rome_version *)(edl->data); |
---|
| 72 | + if (soc_type >= QCA_WCN3991) |
---|
| 73 | + memmove(&edl->data, &edl->data[1], sizeof(*ver)); |
---|
72 | 74 | |
---|
73 | | - BT_DBG("%s: Product:0x%08x", hdev->name, le32_to_cpu(ver->product_id)); |
---|
74 | | - BT_DBG("%s: Patch :0x%08x", hdev->name, le16_to_cpu(ver->patch_ver)); |
---|
75 | | - BT_DBG("%s: ROM :0x%08x", hdev->name, le16_to_cpu(ver->rome_ver)); |
---|
76 | | - BT_DBG("%s: SOC :0x%08x", hdev->name, le32_to_cpu(ver->soc_id)); |
---|
| 75 | + ver = (struct qca_btsoc_version *)(edl->data); |
---|
| 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)); |
---|
77 | 85 | |
---|
78 | 86 | /* QCA chipset version can be decided by patch and SoC |
---|
79 | 87 | * version, combination with upper 2 bytes from SoC |
---|
80 | 88 | * and lower 2 bytes from patch will be used. |
---|
81 | 89 | */ |
---|
82 | 90 | *soc_version = (le32_to_cpu(ver->soc_id) << 16) | |
---|
83 | | - (le16_to_cpu(ver->rome_ver) & 0x0000ffff); |
---|
| 91 | + (le16_to_cpu(ver->rom_ver) & 0x0000ffff); |
---|
84 | 92 | if (*soc_version == 0) |
---|
85 | 93 | err = -EILSEQ; |
---|
86 | 94 | |
---|
.. | .. |
---|
112 | 120 | return 0; |
---|
113 | 121 | } |
---|
114 | 122 | |
---|
115 | | -static void qca_tlv_check_data(struct rome_config *config, |
---|
116 | | - const struct firmware *fw) |
---|
| 123 | +int qca_send_pre_shutdown_cmd(struct hci_dev *hdev) |
---|
| 124 | +{ |
---|
| 125 | + struct sk_buff *skb; |
---|
| 126 | + int err; |
---|
| 127 | + |
---|
| 128 | + bt_dev_dbg(hdev, "QCA pre shutdown cmd"); |
---|
| 129 | + |
---|
| 130 | + skb = __hci_cmd_sync_ev(hdev, QCA_PRE_SHUTDOWN_CMD, 0, |
---|
| 131 | + NULL, HCI_EV_CMD_COMPLETE, HCI_INIT_TIMEOUT); |
---|
| 132 | + |
---|
| 133 | + if (IS_ERR(skb)) { |
---|
| 134 | + err = PTR_ERR(skb); |
---|
| 135 | + bt_dev_err(hdev, "QCA preshutdown_cmd failed (%d)", err); |
---|
| 136 | + return err; |
---|
| 137 | + } |
---|
| 138 | + |
---|
| 139 | + kfree_skb(skb); |
---|
| 140 | + |
---|
| 141 | + return 0; |
---|
| 142 | +} |
---|
| 143 | +EXPORT_SYMBOL_GPL(qca_send_pre_shutdown_cmd); |
---|
| 144 | + |
---|
| 145 | +static void qca_tlv_check_data(struct qca_fw_config *config, |
---|
| 146 | + u8 *fw_data, enum qca_btsoc_type soc_type) |
---|
117 | 147 | { |
---|
118 | 148 | const u8 *data; |
---|
119 | 149 | u32 type_len; |
---|
.. | .. |
---|
122 | 152 | struct tlv_type_hdr *tlv; |
---|
123 | 153 | struct tlv_type_patch *tlv_patch; |
---|
124 | 154 | struct tlv_type_nvm *tlv_nvm; |
---|
| 155 | + uint8_t nvm_baud_rate = config->user_baud_rate; |
---|
125 | 156 | |
---|
126 | | - tlv = (struct tlv_type_hdr *)fw->data; |
---|
| 157 | + tlv = (struct tlv_type_hdr *)fw_data; |
---|
127 | 158 | |
---|
128 | 159 | type_len = le32_to_cpu(tlv->type_len); |
---|
129 | 160 | length = (type_len >> 8) & 0x00ffffff; |
---|
.. | .. |
---|
131 | 162 | BT_DBG("TLV Type\t\t : 0x%x", type_len & 0x000000ff); |
---|
132 | 163 | BT_DBG("Length\t\t : %d bytes", length); |
---|
133 | 164 | |
---|
134 | | - config->dnld_mode = ROME_SKIP_EVT_NONE; |
---|
| 165 | + config->dnld_mode = QCA_SKIP_EVT_NONE; |
---|
| 166 | + config->dnld_type = QCA_SKIP_EVT_NONE; |
---|
135 | 167 | |
---|
136 | 168 | switch (config->type) { |
---|
137 | 169 | case TLV_TYPE_PATCH: |
---|
.. | .. |
---|
144 | 176 | * In case VSE is skipped, only the last segment is acked. |
---|
145 | 177 | */ |
---|
146 | 178 | config->dnld_mode = tlv_patch->download_mode; |
---|
| 179 | + config->dnld_type = config->dnld_mode; |
---|
147 | 180 | |
---|
148 | 181 | BT_DBG("Total Length : %d bytes", |
---|
149 | 182 | le32_to_cpu(tlv_patch->total_size)); |
---|
.. | .. |
---|
188 | 221 | tlv_nvm->data[0] |= 0x80; |
---|
189 | 222 | |
---|
190 | 223 | /* UART Baud Rate */ |
---|
191 | | - tlv_nvm->data[2] = config->user_baud_rate; |
---|
| 224 | + if (soc_type >= QCA_WCN3991) |
---|
| 225 | + tlv_nvm->data[1] = nvm_baud_rate; |
---|
| 226 | + else |
---|
| 227 | + tlv_nvm->data[2] = nvm_baud_rate; |
---|
192 | 228 | |
---|
193 | 229 | break; |
---|
194 | 230 | |
---|
.. | .. |
---|
212 | 248 | } |
---|
213 | 249 | |
---|
214 | 250 | static int qca_tlv_send_segment(struct hci_dev *hdev, int seg_size, |
---|
215 | | - const u8 *data, enum rome_tlv_dnld_mode mode) |
---|
| 251 | + const u8 *data, enum qca_tlv_dnld_mode mode, |
---|
| 252 | + enum qca_btsoc_type soc_type) |
---|
216 | 253 | { |
---|
217 | 254 | struct sk_buff *skb; |
---|
218 | 255 | struct edl_event_hdr *edl; |
---|
219 | 256 | struct tlv_seg_resp *tlv_resp; |
---|
220 | 257 | u8 cmd[MAX_SIZE_PER_TLV_SEGMENT + 2]; |
---|
221 | 258 | int err = 0; |
---|
| 259 | + u8 event_type = HCI_EV_VENDOR; |
---|
| 260 | + u8 rlen = (sizeof(*edl) + sizeof(*tlv_resp)); |
---|
| 261 | + u8 rtype = EDL_TVL_DNLD_RES_EVT; |
---|
222 | 262 | |
---|
223 | 263 | cmd[0] = EDL_PATCH_TLV_REQ_CMD; |
---|
224 | 264 | cmd[1] = seg_size; |
---|
225 | 265 | memcpy(cmd + 2, data, seg_size); |
---|
226 | 266 | |
---|
227 | | - if (mode == ROME_SKIP_EVT_VSE_CC || mode == ROME_SKIP_EVT_VSE) |
---|
| 267 | + if (mode == QCA_SKIP_EVT_VSE_CC || mode == QCA_SKIP_EVT_VSE) |
---|
228 | 268 | return __hci_cmd_send(hdev, EDL_PATCH_CMD_OPCODE, seg_size + 2, |
---|
229 | 269 | cmd); |
---|
230 | 270 | |
---|
| 271 | + /* Unlike other SoC's sending version command response as payload to |
---|
| 272 | + * VSE event. WCN3991 sends version command response as a payload to |
---|
| 273 | + * command complete event. |
---|
| 274 | + */ |
---|
| 275 | + if (soc_type >= QCA_WCN3991) { |
---|
| 276 | + event_type = 0; |
---|
| 277 | + rlen = sizeof(*edl); |
---|
| 278 | + rtype = EDL_PATCH_TLV_REQ_CMD; |
---|
| 279 | + } |
---|
| 280 | + |
---|
231 | 281 | skb = __hci_cmd_sync_ev(hdev, EDL_PATCH_CMD_OPCODE, seg_size + 2, cmd, |
---|
232 | | - HCI_EV_VENDOR, HCI_INIT_TIMEOUT); |
---|
| 282 | + event_type, HCI_INIT_TIMEOUT); |
---|
233 | 283 | if (IS_ERR(skb)) { |
---|
234 | 284 | err = PTR_ERR(skb); |
---|
235 | 285 | bt_dev_err(hdev, "QCA Failed to send TLV segment (%d)", err); |
---|
236 | 286 | return err; |
---|
237 | 287 | } |
---|
238 | 288 | |
---|
239 | | - if (skb->len != sizeof(*edl) + sizeof(*tlv_resp)) { |
---|
| 289 | + if (skb->len != rlen) { |
---|
240 | 290 | bt_dev_err(hdev, "QCA TLV response size mismatch"); |
---|
241 | 291 | err = -EILSEQ; |
---|
242 | 292 | goto out; |
---|
.. | .. |
---|
249 | 299 | goto out; |
---|
250 | 300 | } |
---|
251 | 301 | |
---|
252 | | - tlv_resp = (struct tlv_seg_resp *)(edl->data); |
---|
| 302 | + if (edl->cresp != EDL_CMD_REQ_RES_EVT || edl->rtype != rtype) { |
---|
| 303 | + bt_dev_err(hdev, "QCA TLV with error stat 0x%x rtype 0x%x", |
---|
| 304 | + edl->cresp, edl->rtype); |
---|
| 305 | + err = -EIO; |
---|
| 306 | + } |
---|
253 | 307 | |
---|
254 | | - if (edl->cresp != EDL_CMD_REQ_RES_EVT || |
---|
255 | | - edl->rtype != EDL_TVL_DNLD_RES_EVT || tlv_resp->result != 0x00) { |
---|
| 308 | + if (soc_type >= QCA_WCN3991) |
---|
| 309 | + goto out; |
---|
| 310 | + |
---|
| 311 | + tlv_resp = (struct tlv_seg_resp *)(edl->data); |
---|
| 312 | + if (tlv_resp->result) { |
---|
256 | 313 | bt_dev_err(hdev, "QCA TLV with error stat 0x%x rtype 0x%x (0x%x)", |
---|
257 | 314 | edl->cresp, edl->rtype, tlv_resp->result); |
---|
258 | | - err = -EIO; |
---|
259 | 315 | } |
---|
260 | 316 | |
---|
261 | 317 | out: |
---|
.. | .. |
---|
264 | 320 | return err; |
---|
265 | 321 | } |
---|
266 | 322 | |
---|
| 323 | +static int qca_inject_cmd_complete_event(struct hci_dev *hdev) |
---|
| 324 | +{ |
---|
| 325 | + struct hci_event_hdr *hdr; |
---|
| 326 | + struct hci_ev_cmd_complete *evt; |
---|
| 327 | + struct sk_buff *skb; |
---|
| 328 | + |
---|
| 329 | + skb = bt_skb_alloc(sizeof(*hdr) + sizeof(*evt) + 1, GFP_KERNEL); |
---|
| 330 | + if (!skb) |
---|
| 331 | + return -ENOMEM; |
---|
| 332 | + |
---|
| 333 | + hdr = skb_put(skb, sizeof(*hdr)); |
---|
| 334 | + hdr->evt = HCI_EV_CMD_COMPLETE; |
---|
| 335 | + hdr->plen = sizeof(*evt) + 1; |
---|
| 336 | + |
---|
| 337 | + evt = skb_put(skb, sizeof(*evt)); |
---|
| 338 | + evt->ncmd = 1; |
---|
| 339 | + evt->opcode = cpu_to_le16(QCA_HCI_CC_OPCODE); |
---|
| 340 | + |
---|
| 341 | + skb_put_u8(skb, QCA_HCI_CC_SUCCESS); |
---|
| 342 | + |
---|
| 343 | + hci_skb_pkt_type(skb) = HCI_EVENT_PKT; |
---|
| 344 | + |
---|
| 345 | + return hci_recv_frame(hdev, skb); |
---|
| 346 | +} |
---|
| 347 | + |
---|
267 | 348 | static int qca_download_firmware(struct hci_dev *hdev, |
---|
268 | | - struct rome_config *config) |
---|
| 349 | + struct qca_fw_config *config, |
---|
| 350 | + enum qca_btsoc_type soc_type) |
---|
269 | 351 | { |
---|
270 | 352 | const struct firmware *fw; |
---|
| 353 | + u8 *data; |
---|
271 | 354 | const u8 *segment; |
---|
272 | | - int ret, remain, i = 0; |
---|
| 355 | + int ret, size, remain, i = 0; |
---|
273 | 356 | |
---|
274 | 357 | bt_dev_info(hdev, "QCA Downloading %s", config->fwname); |
---|
275 | 358 | |
---|
.. | .. |
---|
280 | 363 | return ret; |
---|
281 | 364 | } |
---|
282 | 365 | |
---|
283 | | - qca_tlv_check_data(config, fw); |
---|
| 366 | + size = fw->size; |
---|
| 367 | + data = vmalloc(fw->size); |
---|
| 368 | + if (!data) { |
---|
| 369 | + bt_dev_err(hdev, "QCA Failed to allocate memory for file: %s", |
---|
| 370 | + config->fwname); |
---|
| 371 | + release_firmware(fw); |
---|
| 372 | + return -ENOMEM; |
---|
| 373 | + } |
---|
284 | 374 | |
---|
285 | | - segment = fw->data; |
---|
286 | | - remain = fw->size; |
---|
| 375 | + memcpy(data, fw->data, size); |
---|
| 376 | + release_firmware(fw); |
---|
| 377 | + |
---|
| 378 | + qca_tlv_check_data(config, data, soc_type); |
---|
| 379 | + |
---|
| 380 | + segment = data; |
---|
| 381 | + remain = size; |
---|
287 | 382 | while (remain > 0) { |
---|
288 | 383 | int segsize = min(MAX_SIZE_PER_TLV_SEGMENT, remain); |
---|
289 | 384 | |
---|
.. | .. |
---|
292 | 387 | remain -= segsize; |
---|
293 | 388 | /* The last segment is always acked regardless download mode */ |
---|
294 | 389 | if (!remain || segsize < MAX_SIZE_PER_TLV_SEGMENT) |
---|
295 | | - config->dnld_mode = ROME_SKIP_EVT_NONE; |
---|
| 390 | + config->dnld_mode = QCA_SKIP_EVT_NONE; |
---|
296 | 391 | |
---|
297 | 392 | ret = qca_tlv_send_segment(hdev, segsize, segment, |
---|
298 | | - config->dnld_mode); |
---|
| 393 | + config->dnld_mode, soc_type); |
---|
299 | 394 | if (ret) |
---|
300 | | - break; |
---|
| 395 | + goto out; |
---|
301 | 396 | |
---|
302 | 397 | segment += segsize; |
---|
303 | 398 | } |
---|
304 | 399 | |
---|
305 | | - release_firmware(fw); |
---|
| 400 | + /* Latest qualcomm chipsets are not sending a command complete event |
---|
| 401 | + * for every fw packet sent. They only respond with a vendor specific |
---|
| 402 | + * event for the last packet. This optimization in the chip will |
---|
| 403 | + * decrease the BT in initialization time. Here we will inject a command |
---|
| 404 | + * complete event to avoid a command timeout error message. |
---|
| 405 | + */ |
---|
| 406 | + if (config->dnld_type == QCA_SKIP_EVT_VSE_CC || |
---|
| 407 | + config->dnld_type == QCA_SKIP_EVT_VSE) |
---|
| 408 | + ret = qca_inject_cmd_complete_event(hdev); |
---|
| 409 | + |
---|
| 410 | +out: |
---|
| 411 | + vfree(data); |
---|
306 | 412 | |
---|
307 | 413 | return ret; |
---|
| 414 | +} |
---|
| 415 | + |
---|
| 416 | +static int qca_disable_soc_logging(struct hci_dev *hdev) |
---|
| 417 | +{ |
---|
| 418 | + struct sk_buff *skb; |
---|
| 419 | + u8 cmd[2]; |
---|
| 420 | + int err; |
---|
| 421 | + |
---|
| 422 | + cmd[0] = QCA_DISABLE_LOGGING_SUB_OP; |
---|
| 423 | + cmd[1] = 0x00; |
---|
| 424 | + skb = __hci_cmd_sync_ev(hdev, QCA_DISABLE_LOGGING, sizeof(cmd), cmd, |
---|
| 425 | + HCI_EV_CMD_COMPLETE, HCI_INIT_TIMEOUT); |
---|
| 426 | + if (IS_ERR(skb)) { |
---|
| 427 | + err = PTR_ERR(skb); |
---|
| 428 | + bt_dev_err(hdev, "QCA Failed to disable soc logging(%d)", err); |
---|
| 429 | + return err; |
---|
| 430 | + } |
---|
| 431 | + |
---|
| 432 | + kfree_skb(skb); |
---|
| 433 | + |
---|
| 434 | + return 0; |
---|
308 | 435 | } |
---|
309 | 436 | |
---|
310 | 437 | int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr) |
---|
.. | .. |
---|
332 | 459 | EXPORT_SYMBOL_GPL(qca_set_bdaddr_rome); |
---|
333 | 460 | |
---|
334 | 461 | int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, |
---|
335 | | - enum qca_btsoc_type soc_type, u32 soc_ver) |
---|
| 462 | + enum qca_btsoc_type soc_type, u32 soc_ver, |
---|
| 463 | + const char *firmware_name) |
---|
336 | 464 | { |
---|
337 | | - struct rome_config config; |
---|
| 465 | + struct qca_fw_config config; |
---|
338 | 466 | int err; |
---|
339 | | - u8 rom_ver; |
---|
| 467 | + u8 rom_ver = 0; |
---|
340 | 468 | |
---|
341 | 469 | bt_dev_dbg(hdev, "QCA setup on UART"); |
---|
342 | 470 | |
---|
.. | .. |
---|
344 | 472 | |
---|
345 | 473 | /* Download rampatch file */ |
---|
346 | 474 | config.type = TLV_TYPE_PATCH; |
---|
347 | | - if (soc_type == QCA_WCN3990) { |
---|
| 475 | + if (qca_is_wcn399x(soc_type)) { |
---|
348 | 476 | /* Firmware files to download are based on ROM version. |
---|
349 | 477 | * ROM version is derived from last two bytes of soc_ver. |
---|
350 | 478 | */ |
---|
.. | .. |
---|
352 | 480 | (soc_ver & 0x0000000f); |
---|
353 | 481 | snprintf(config.fwname, sizeof(config.fwname), |
---|
354 | 482 | "qca/crbtfw%02x.tlv", rom_ver); |
---|
| 483 | + } else if (soc_type == QCA_QCA6390) { |
---|
| 484 | + rom_ver = ((soc_ver & 0x00000f00) >> 0x04) | |
---|
| 485 | + (soc_ver & 0x0000000f); |
---|
| 486 | + snprintf(config.fwname, sizeof(config.fwname), |
---|
| 487 | + "qca/htbtfw%02x.tlv", rom_ver); |
---|
355 | 488 | } else { |
---|
356 | 489 | snprintf(config.fwname, sizeof(config.fwname), |
---|
357 | 490 | "qca/rampatch_%08x.bin", soc_ver); |
---|
358 | 491 | } |
---|
359 | 492 | |
---|
360 | | - err = qca_download_firmware(hdev, &config); |
---|
| 493 | + err = qca_download_firmware(hdev, &config, soc_type); |
---|
361 | 494 | if (err < 0) { |
---|
362 | 495 | bt_dev_err(hdev, "QCA Failed to download patch (%d)", err); |
---|
363 | 496 | return err; |
---|
.. | .. |
---|
368 | 501 | |
---|
369 | 502 | /* Download NVM configuration */ |
---|
370 | 503 | config.type = TLV_TYPE_NVM; |
---|
371 | | - if (soc_type == QCA_WCN3990) |
---|
| 504 | + if (firmware_name) |
---|
| 505 | + snprintf(config.fwname, sizeof(config.fwname), |
---|
| 506 | + "qca/%s", firmware_name); |
---|
| 507 | + else if (qca_is_wcn399x(soc_type)) |
---|
372 | 508 | snprintf(config.fwname, sizeof(config.fwname), |
---|
373 | 509 | "qca/crnv%02x.bin", rom_ver); |
---|
| 510 | + else if (soc_type == QCA_QCA6390) |
---|
| 511 | + snprintf(config.fwname, sizeof(config.fwname), |
---|
| 512 | + "qca/htnv%02x.bin", rom_ver); |
---|
374 | 513 | else |
---|
375 | 514 | snprintf(config.fwname, sizeof(config.fwname), |
---|
376 | 515 | "qca/nvm_%08x.bin", soc_ver); |
---|
377 | 516 | |
---|
378 | | - err = qca_download_firmware(hdev, &config); |
---|
| 517 | + err = qca_download_firmware(hdev, &config, soc_type); |
---|
379 | 518 | if (err < 0) { |
---|
380 | 519 | bt_dev_err(hdev, "QCA Failed to download NVM (%d)", err); |
---|
381 | 520 | return err; |
---|
| 521 | + } |
---|
| 522 | + |
---|
| 523 | + if (soc_type >= QCA_WCN3991) { |
---|
| 524 | + err = qca_disable_soc_logging(hdev); |
---|
| 525 | + if (err < 0) |
---|
| 526 | + return err; |
---|
382 | 527 | } |
---|
383 | 528 | |
---|
384 | 529 | /* Perform HCI reset */ |
---|
.. | .. |
---|
394 | 539 | } |
---|
395 | 540 | EXPORT_SYMBOL_GPL(qca_uart_setup); |
---|
396 | 541 | |
---|
| 542 | +int qca_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) |
---|
| 543 | +{ |
---|
| 544 | + struct sk_buff *skb; |
---|
| 545 | + int err; |
---|
| 546 | + |
---|
| 547 | + skb = __hci_cmd_sync_ev(hdev, EDL_WRITE_BD_ADDR_OPCODE, 6, bdaddr, |
---|
| 548 | + HCI_EV_VENDOR, HCI_INIT_TIMEOUT); |
---|
| 549 | + if (IS_ERR(skb)) { |
---|
| 550 | + err = PTR_ERR(skb); |
---|
| 551 | + bt_dev_err(hdev, "QCA Change address cmd failed (%d)", err); |
---|
| 552 | + return err; |
---|
| 553 | + } |
---|
| 554 | + |
---|
| 555 | + kfree_skb(skb); |
---|
| 556 | + |
---|
| 557 | + return 0; |
---|
| 558 | +} |
---|
| 559 | +EXPORT_SYMBOL_GPL(qca_set_bdaddr); |
---|
| 560 | + |
---|
| 561 | + |
---|
397 | 562 | MODULE_AUTHOR("Ben Young Tae Kim <ytkim@qca.qualcomm.com>"); |
---|
398 | 563 | MODULE_DESCRIPTION("Bluetooth support for Qualcomm Atheros family ver " VERSION); |
---|
399 | 564 | MODULE_VERSION(VERSION); |
---|