11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
24fba30f0SMarcel Holtmann /*
34fba30f0SMarcel Holtmann *
44fba30f0SMarcel Holtmann * Bluetooth support for Broadcom devices
54fba30f0SMarcel Holtmann *
64fba30f0SMarcel Holtmann * Copyright (C) 2015 Intel Corporation
74fba30f0SMarcel Holtmann */
84fba30f0SMarcel Holtmann
90d218c36SHans de Goede #include <linux/efi.h>
104fba30f0SMarcel Holtmann #include <linux/module.h>
111c8ba6d0SMarcel Holtmann #include <linux/firmware.h>
12801b4c02SAditya Garg #include <linux/dmi.h>
1363fac334SLinus Walleij #include <linux/of.h>
141c8ba6d0SMarcel Holtmann #include <asm/unaligned.h>
154fba30f0SMarcel Holtmann
164fba30f0SMarcel Holtmann #include <net/bluetooth/bluetooth.h>
174fba30f0SMarcel Holtmann #include <net/bluetooth/hci_core.h>
184fba30f0SMarcel Holtmann
194fba30f0SMarcel Holtmann #include "btbcm.h"
204fba30f0SMarcel Holtmann
214fba30f0SMarcel Holtmann #define VERSION "0.1"
224fba30f0SMarcel Holtmann
234fba30f0SMarcel Holtmann #define BDADDR_BCM20702A0 (&(bdaddr_t) {{0x00, 0xa0, 0x02, 0x70, 0x20, 0x00}})
2492ffe0dbSMaxime Ripard #define BDADDR_BCM20702A1 (&(bdaddr_t) {{0x00, 0x00, 0xa0, 0x02, 0x70, 0x20}})
25300926b1SStephan Gerhold #define BDADDR_BCM2076B1 (&(bdaddr_t) {{0x79, 0x56, 0x00, 0xa0, 0x76, 0x20}})
260697607aSChen-Yu Tsai #define BDADDR_BCM43430A0 (&(bdaddr_t) {{0xac, 0x1f, 0x12, 0xa0, 0x43, 0x43}})
27*47e90f6bSMans Rullgard #define BDADDR_BCM43430A1 (&(bdaddr_t) {{0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa}})
28a8f3b941SFrederic Danis #define BDADDR_BCM4324B3 (&(bdaddr_t) {{0x00, 0x00, 0x00, 0xb3, 0x24, 0x43}})
294a546ec3SFrederic Danis #define BDADDR_BCM4330B1 (&(bdaddr_t) {{0x00, 0x00, 0x00, 0xb1, 0x30, 0x43}})
30b8dc6476SStephan Gerhold #define BDADDR_BCM4334B0 (&(bdaddr_t) {{0x00, 0x00, 0x00, 0xb0, 0x34, 0x43}})
3152c8c7a7SOndrej Jirman #define BDADDR_BCM4345C5 (&(bdaddr_t) {{0xac, 0x1f, 0x00, 0xc5, 0x45, 0x43}})
3250357261SFerry Toth #define BDADDR_BCM43341B (&(bdaddr_t) {{0xac, 0x1f, 0x00, 0x1b, 0x34, 0x43}})
334fba30f0SMarcel Holtmann
340287c5d8SHans de Goede #define BCM_FW_NAME_LEN 64
3563fac334SLinus Walleij #define BCM_FW_NAME_COUNT_MAX 4
3674530a63SHans de Goede /* For kmalloc-ing the fw-name array instead of putting it on the stack */
3774530a63SHans de Goede typedef char bcm_fw_name[BCM_FW_NAME_LEN];
380287c5d8SHans de Goede
390d218c36SHans de Goede #ifdef CONFIG_EFI
btbcm_set_bdaddr_from_efi(struct hci_dev * hdev)400d218c36SHans de Goede static int btbcm_set_bdaddr_from_efi(struct hci_dev *hdev)
410d218c36SHans de Goede {
420d218c36SHans de Goede efi_guid_t guid = EFI_GUID(0x74b00bd9, 0x805a, 0x4d61, 0xb5, 0x1f,
430d218c36SHans de Goede 0x43, 0x26, 0x81, 0x23, 0xd1, 0x13);
440d218c36SHans de Goede bdaddr_t efi_bdaddr, bdaddr;
450d218c36SHans de Goede efi_status_t status;
460d218c36SHans de Goede unsigned long len;
470d218c36SHans de Goede int ret;
480d218c36SHans de Goede
490d218c36SHans de Goede if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE))
500d218c36SHans de Goede return -EOPNOTSUPP;
510d218c36SHans de Goede
520d218c36SHans de Goede len = sizeof(efi_bdaddr);
530d218c36SHans de Goede status = efi.get_variable(L"BDADDR", &guid, NULL, &len, &efi_bdaddr);
540d218c36SHans de Goede if (status != EFI_SUCCESS)
550d218c36SHans de Goede return -ENXIO;
560d218c36SHans de Goede
570d218c36SHans de Goede if (len != sizeof(efi_bdaddr))
580d218c36SHans de Goede return -EIO;
590d218c36SHans de Goede
600d218c36SHans de Goede baswap(&bdaddr, &efi_bdaddr);
610d218c36SHans de Goede
620d218c36SHans de Goede ret = btbcm_set_bdaddr(hdev, &bdaddr);
630d218c36SHans de Goede if (ret)
640d218c36SHans de Goede return ret;
650d218c36SHans de Goede
660d218c36SHans de Goede bt_dev_info(hdev, "BCM: Using EFI device address (%pMR)", &bdaddr);
670d218c36SHans de Goede return 0;
680d218c36SHans de Goede }
690d218c36SHans de Goede #else
btbcm_set_bdaddr_from_efi(struct hci_dev * hdev)700d218c36SHans de Goede static int btbcm_set_bdaddr_from_efi(struct hci_dev *hdev)
710d218c36SHans de Goede {
720d218c36SHans de Goede return -EOPNOTSUPP;
730d218c36SHans de Goede }
740d218c36SHans de Goede #endif
750d218c36SHans de Goede
btbcm_check_bdaddr(struct hci_dev * hdev)764fba30f0SMarcel Holtmann int btbcm_check_bdaddr(struct hci_dev *hdev)
774fba30f0SMarcel Holtmann {
784fba30f0SMarcel Holtmann struct hci_rp_read_bd_addr *bda;
794fba30f0SMarcel Holtmann struct sk_buff *skb;
804fba30f0SMarcel Holtmann
814fba30f0SMarcel Holtmann skb = __hci_cmd_sync(hdev, HCI_OP_READ_BD_ADDR, 0, NULL,
824fba30f0SMarcel Holtmann HCI_INIT_TIMEOUT);
834fba30f0SMarcel Holtmann if (IS_ERR(skb)) {
844fba30f0SMarcel Holtmann int err = PTR_ERR(skb);
85dde8010bSChangqi Du
862064ee33SMarcel Holtmann bt_dev_err(hdev, "BCM: Reading device address failed (%d)", err);
874fba30f0SMarcel Holtmann return err;
884fba30f0SMarcel Holtmann }
894fba30f0SMarcel Holtmann
904fba30f0SMarcel Holtmann if (skb->len != sizeof(*bda)) {
912064ee33SMarcel Holtmann bt_dev_err(hdev, "BCM: Device address length mismatch");
924fba30f0SMarcel Holtmann kfree_skb(skb);
934fba30f0SMarcel Holtmann return -EIO;
944fba30f0SMarcel Holtmann }
954fba30f0SMarcel Holtmann
964fba30f0SMarcel Holtmann bda = (struct hci_rp_read_bd_addr *)skb->data;
974fba30f0SMarcel Holtmann
98a8f3b941SFrederic Danis /* Check if the address indicates a controller with either an
99a8f3b941SFrederic Danis * invalid or default address. In both cases the device needs
100a8f3b941SFrederic Danis * to be marked as not having a valid address.
101a8f3b941SFrederic Danis *
102a8f3b941SFrederic Danis * The address 00:20:70:02:A0:00 indicates a BCM20702A0 controller
1034fba30f0SMarcel Holtmann * with no configured address.
104a8f3b941SFrederic Danis *
10592ffe0dbSMaxime Ripard * The address 20:70:02:A0:00:00 indicates a BCM20702A1 controller
10692ffe0dbSMaxime Ripard * with no configured address.
10792ffe0dbSMaxime Ripard *
108300926b1SStephan Gerhold * The address 20:76:A0:00:56:79 indicates a BCM2076B1 controller
109300926b1SStephan Gerhold * with no configured address.
110300926b1SStephan Gerhold *
111a8f3b941SFrederic Danis * The address 43:24:B3:00:00:00 indicates a BCM4324B3 controller
112a8f3b941SFrederic Danis * with waiting for configuration state.
1134a546ec3SFrederic Danis *
1144a546ec3SFrederic Danis * The address 43:30:B1:00:00:00 indicates a BCM4330B1 controller
1154a546ec3SFrederic Danis * with waiting for configuration state.
1160697607aSChen-Yu Tsai *
1170697607aSChen-Yu Tsai * The address 43:43:A0:12:1F:AC indicates a BCM43430A0 controller
1180697607aSChen-Yu Tsai * with no configured address.
119*47e90f6bSMans Rullgard *
120*47e90f6bSMans Rullgard * The address AA:AA:AA:AA:AA:AA indicates a BCM43430A1 controller
121*47e90f6bSMans Rullgard * with no configured address.
1224fba30f0SMarcel Holtmann */
123a8f3b941SFrederic Danis if (!bacmp(&bda->bdaddr, BDADDR_BCM20702A0) ||
12492ffe0dbSMaxime Ripard !bacmp(&bda->bdaddr, BDADDR_BCM20702A1) ||
125300926b1SStephan Gerhold !bacmp(&bda->bdaddr, BDADDR_BCM2076B1) ||
1264a546ec3SFrederic Danis !bacmp(&bda->bdaddr, BDADDR_BCM4324B3) ||
1270697607aSChen-Yu Tsai !bacmp(&bda->bdaddr, BDADDR_BCM4330B1) ||
128b8dc6476SStephan Gerhold !bacmp(&bda->bdaddr, BDADDR_BCM4334B0) ||
12952c8c7a7SOndrej Jirman !bacmp(&bda->bdaddr, BDADDR_BCM4345C5) ||
13050357261SFerry Toth !bacmp(&bda->bdaddr, BDADDR_BCM43430A0) ||
131*47e90f6bSMans Rullgard !bacmp(&bda->bdaddr, BDADDR_BCM43430A1) ||
13250357261SFerry Toth !bacmp(&bda->bdaddr, BDADDR_BCM43341B)) {
1330d218c36SHans de Goede /* Try falling back to BDADDR EFI variable */
1340d218c36SHans de Goede if (btbcm_set_bdaddr_from_efi(hdev) != 0) {
1352064ee33SMarcel Holtmann bt_dev_info(hdev, "BCM: Using default device address (%pMR)",
1362064ee33SMarcel Holtmann &bda->bdaddr);
1374fba30f0SMarcel Holtmann set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks);
1384fba30f0SMarcel Holtmann }
1390d218c36SHans de Goede }
1404fba30f0SMarcel Holtmann
1414fba30f0SMarcel Holtmann kfree_skb(skb);
1424fba30f0SMarcel Holtmann
1434fba30f0SMarcel Holtmann return 0;
1444fba30f0SMarcel Holtmann }
1454fba30f0SMarcel Holtmann EXPORT_SYMBOL_GPL(btbcm_check_bdaddr);
1464fba30f0SMarcel Holtmann
btbcm_set_bdaddr(struct hci_dev * hdev,const bdaddr_t * bdaddr)1474fba30f0SMarcel Holtmann int btbcm_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)
1484fba30f0SMarcel Holtmann {
1494fba30f0SMarcel Holtmann struct sk_buff *skb;
1504fba30f0SMarcel Holtmann int err;
1514fba30f0SMarcel Holtmann
1524fba30f0SMarcel Holtmann skb = __hci_cmd_sync(hdev, 0xfc01, 6, bdaddr, HCI_INIT_TIMEOUT);
1534fba30f0SMarcel Holtmann if (IS_ERR(skb)) {
1544fba30f0SMarcel Holtmann err = PTR_ERR(skb);
1552064ee33SMarcel Holtmann bt_dev_err(hdev, "BCM: Change address command failed (%d)", err);
1564fba30f0SMarcel Holtmann return err;
1574fba30f0SMarcel Holtmann }
1584fba30f0SMarcel Holtmann kfree_skb(skb);
1594fba30f0SMarcel Holtmann
1604fba30f0SMarcel Holtmann return 0;
1614fba30f0SMarcel Holtmann }
1624fba30f0SMarcel Holtmann EXPORT_SYMBOL_GPL(btbcm_set_bdaddr);
1634fba30f0SMarcel Holtmann
btbcm_read_pcm_int_params(struct hci_dev * hdev,struct bcm_set_pcm_int_params * params)16452837990SAbhishek Pandit-Subedi int btbcm_read_pcm_int_params(struct hci_dev *hdev,
16552837990SAbhishek Pandit-Subedi struct bcm_set_pcm_int_params *params)
16652837990SAbhishek Pandit-Subedi {
16752837990SAbhishek Pandit-Subedi struct sk_buff *skb;
16852837990SAbhishek Pandit-Subedi int err = 0;
16952837990SAbhishek Pandit-Subedi
17052837990SAbhishek Pandit-Subedi skb = __hci_cmd_sync(hdev, 0xfc1d, 0, NULL, HCI_INIT_TIMEOUT);
17152837990SAbhishek Pandit-Subedi if (IS_ERR(skb)) {
17252837990SAbhishek Pandit-Subedi err = PTR_ERR(skb);
17352837990SAbhishek Pandit-Subedi bt_dev_err(hdev, "BCM: Read PCM int params failed (%d)", err);
17452837990SAbhishek Pandit-Subedi return err;
17552837990SAbhishek Pandit-Subedi }
17652837990SAbhishek Pandit-Subedi
17752837990SAbhishek Pandit-Subedi if (skb->len != 6 || skb->data[0]) {
17852837990SAbhishek Pandit-Subedi bt_dev_err(hdev, "BCM: Read PCM int params length mismatch");
17952837990SAbhishek Pandit-Subedi kfree_skb(skb);
18052837990SAbhishek Pandit-Subedi return -EIO;
18152837990SAbhishek Pandit-Subedi }
18252837990SAbhishek Pandit-Subedi
18352837990SAbhishek Pandit-Subedi if (params)
18452837990SAbhishek Pandit-Subedi memcpy(params, skb->data + 1, 5);
18552837990SAbhishek Pandit-Subedi
18652837990SAbhishek Pandit-Subedi kfree_skb(skb);
18752837990SAbhishek Pandit-Subedi
18852837990SAbhishek Pandit-Subedi return 0;
18952837990SAbhishek Pandit-Subedi }
19052837990SAbhishek Pandit-Subedi EXPORT_SYMBOL_GPL(btbcm_read_pcm_int_params);
19152837990SAbhishek Pandit-Subedi
btbcm_write_pcm_int_params(struct hci_dev * hdev,const struct bcm_set_pcm_int_params * params)19252837990SAbhishek Pandit-Subedi int btbcm_write_pcm_int_params(struct hci_dev *hdev,
19352837990SAbhishek Pandit-Subedi const struct bcm_set_pcm_int_params *params)
19452837990SAbhishek Pandit-Subedi {
19552837990SAbhishek Pandit-Subedi struct sk_buff *skb;
19652837990SAbhishek Pandit-Subedi int err;
19752837990SAbhishek Pandit-Subedi
19852837990SAbhishek Pandit-Subedi skb = __hci_cmd_sync(hdev, 0xfc1c, 5, params, HCI_INIT_TIMEOUT);
19952837990SAbhishek Pandit-Subedi if (IS_ERR(skb)) {
20052837990SAbhishek Pandit-Subedi err = PTR_ERR(skb);
20152837990SAbhishek Pandit-Subedi bt_dev_err(hdev, "BCM: Write PCM int params failed (%d)", err);
20252837990SAbhishek Pandit-Subedi return err;
20352837990SAbhishek Pandit-Subedi }
20452837990SAbhishek Pandit-Subedi kfree_skb(skb);
20552837990SAbhishek Pandit-Subedi
20652837990SAbhishek Pandit-Subedi return 0;
20752837990SAbhishek Pandit-Subedi }
20852837990SAbhishek Pandit-Subedi EXPORT_SYMBOL_GPL(btbcm_write_pcm_int_params);
20952837990SAbhishek Pandit-Subedi
btbcm_patchram(struct hci_dev * hdev,const struct firmware * fw)21018aeb444SFrederic Danis int btbcm_patchram(struct hci_dev *hdev, const struct firmware *fw)
21150862ee5SMarcel Holtmann {
21250862ee5SMarcel Holtmann const struct hci_command_hdr *cmd;
21350862ee5SMarcel Holtmann const u8 *fw_ptr;
21450862ee5SMarcel Holtmann size_t fw_size;
21550862ee5SMarcel Holtmann struct sk_buff *skb;
21650862ee5SMarcel Holtmann u16 opcode;
21718aeb444SFrederic Danis int err = 0;
21850862ee5SMarcel Holtmann
21950862ee5SMarcel Holtmann /* Start Download */
22050862ee5SMarcel Holtmann skb = __hci_cmd_sync(hdev, 0xfc2e, 0, NULL, HCI_INIT_TIMEOUT);
22150862ee5SMarcel Holtmann if (IS_ERR(skb)) {
22250862ee5SMarcel Holtmann err = PTR_ERR(skb);
2232064ee33SMarcel Holtmann bt_dev_err(hdev, "BCM: Download Minidrv command failed (%d)",
2242064ee33SMarcel Holtmann err);
22550862ee5SMarcel Holtmann goto done;
22650862ee5SMarcel Holtmann }
22750862ee5SMarcel Holtmann kfree_skb(skb);
22850862ee5SMarcel Holtmann
22950862ee5SMarcel Holtmann /* 50 msec delay after Download Minidrv completes */
23050862ee5SMarcel Holtmann msleep(50);
23150862ee5SMarcel Holtmann
23250862ee5SMarcel Holtmann fw_ptr = fw->data;
23350862ee5SMarcel Holtmann fw_size = fw->size;
23450862ee5SMarcel Holtmann
23550862ee5SMarcel Holtmann while (fw_size >= sizeof(*cmd)) {
23650862ee5SMarcel Holtmann const u8 *cmd_param;
23750862ee5SMarcel Holtmann
23850862ee5SMarcel Holtmann cmd = (struct hci_command_hdr *)fw_ptr;
23950862ee5SMarcel Holtmann fw_ptr += sizeof(*cmd);
24050862ee5SMarcel Holtmann fw_size -= sizeof(*cmd);
24150862ee5SMarcel Holtmann
24250862ee5SMarcel Holtmann if (fw_size < cmd->plen) {
2432064ee33SMarcel Holtmann bt_dev_err(hdev, "BCM: Patch is corrupted");
24450862ee5SMarcel Holtmann err = -EINVAL;
24550862ee5SMarcel Holtmann goto done;
24650862ee5SMarcel Holtmann }
24750862ee5SMarcel Holtmann
24850862ee5SMarcel Holtmann cmd_param = fw_ptr;
24950862ee5SMarcel Holtmann fw_ptr += cmd->plen;
25050862ee5SMarcel Holtmann fw_size -= cmd->plen;
25150862ee5SMarcel Holtmann
25250862ee5SMarcel Holtmann opcode = le16_to_cpu(cmd->opcode);
25350862ee5SMarcel Holtmann
25450862ee5SMarcel Holtmann skb = __hci_cmd_sync(hdev, opcode, cmd->plen, cmd_param,
25550862ee5SMarcel Holtmann HCI_INIT_TIMEOUT);
25650862ee5SMarcel Holtmann if (IS_ERR(skb)) {
25750862ee5SMarcel Holtmann err = PTR_ERR(skb);
2582064ee33SMarcel Holtmann bt_dev_err(hdev, "BCM: Patch command %04x failed (%d)",
2592064ee33SMarcel Holtmann opcode, err);
26050862ee5SMarcel Holtmann goto done;
26150862ee5SMarcel Holtmann }
26250862ee5SMarcel Holtmann kfree_skb(skb);
26350862ee5SMarcel Holtmann }
26450862ee5SMarcel Holtmann
26550862ee5SMarcel Holtmann /* 250 msec delay after Launch Ram completes */
26650862ee5SMarcel Holtmann msleep(250);
26750862ee5SMarcel Holtmann
26850862ee5SMarcel Holtmann done:
26950862ee5SMarcel Holtmann return err;
27050862ee5SMarcel Holtmann }
27150862ee5SMarcel Holtmann EXPORT_SYMBOL(btbcm_patchram);
27250862ee5SMarcel Holtmann
btbcm_reset(struct hci_dev * hdev)2731c8ba6d0SMarcel Holtmann static int btbcm_reset(struct hci_dev *hdev)
2741c8ba6d0SMarcel Holtmann {
2751c8ba6d0SMarcel Holtmann struct sk_buff *skb;
2761c8ba6d0SMarcel Holtmann
2771c8ba6d0SMarcel Holtmann skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
2781c8ba6d0SMarcel Holtmann if (IS_ERR(skb)) {
2791c8ba6d0SMarcel Holtmann int err = PTR_ERR(skb);
280dde8010bSChangqi Du
2812064ee33SMarcel Holtmann bt_dev_err(hdev, "BCM: Reset failed (%d)", err);
2821c8ba6d0SMarcel Holtmann return err;
2831c8ba6d0SMarcel Holtmann }
2841c8ba6d0SMarcel Holtmann kfree_skb(skb);
2851c8ba6d0SMarcel Holtmann
2863af3a594SWen-chien Jesse Sung /* 100 msec delay for module to complete reset process */
2873af3a594SWen-chien Jesse Sung msleep(100);
2883af3a594SWen-chien Jesse Sung
2891c8ba6d0SMarcel Holtmann return 0;
2901c8ba6d0SMarcel Holtmann }
2911c8ba6d0SMarcel Holtmann
btbcm_read_local_name(struct hci_dev * hdev)2929bc63ca0SMarcel Holtmann static struct sk_buff *btbcm_read_local_name(struct hci_dev *hdev)
2939bc63ca0SMarcel Holtmann {
2949bc63ca0SMarcel Holtmann struct sk_buff *skb;
2959bc63ca0SMarcel Holtmann
2969bc63ca0SMarcel Holtmann skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_NAME, 0, NULL,
2979bc63ca0SMarcel Holtmann HCI_INIT_TIMEOUT);
2989bc63ca0SMarcel Holtmann if (IS_ERR(skb)) {
2992064ee33SMarcel Holtmann bt_dev_err(hdev, "BCM: Reading local name failed (%ld)",
3002064ee33SMarcel Holtmann PTR_ERR(skb));
3019bc63ca0SMarcel Holtmann return skb;
3029bc63ca0SMarcel Holtmann }
3039bc63ca0SMarcel Holtmann
3049bc63ca0SMarcel Holtmann if (skb->len != sizeof(struct hci_rp_read_local_name)) {
3052064ee33SMarcel Holtmann bt_dev_err(hdev, "BCM: Local name length mismatch");
3069bc63ca0SMarcel Holtmann kfree_skb(skb);
3079bc63ca0SMarcel Holtmann return ERR_PTR(-EIO);
3089bc63ca0SMarcel Holtmann }
3099bc63ca0SMarcel Holtmann
3109bc63ca0SMarcel Holtmann return skb;
3119bc63ca0SMarcel Holtmann }
3129bc63ca0SMarcel Holtmann
btbcm_read_local_version(struct hci_dev * hdev)3131c8ba6d0SMarcel Holtmann static struct sk_buff *btbcm_read_local_version(struct hci_dev *hdev)
3141c8ba6d0SMarcel Holtmann {
3151c8ba6d0SMarcel Holtmann struct sk_buff *skb;
3161c8ba6d0SMarcel Holtmann
3171c8ba6d0SMarcel Holtmann skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL,
3181c8ba6d0SMarcel Holtmann HCI_INIT_TIMEOUT);
3191c8ba6d0SMarcel Holtmann if (IS_ERR(skb)) {
3202064ee33SMarcel Holtmann bt_dev_err(hdev, "BCM: Reading local version info failed (%ld)",
3212064ee33SMarcel Holtmann PTR_ERR(skb));
3221c8ba6d0SMarcel Holtmann return skb;
3231c8ba6d0SMarcel Holtmann }
3241c8ba6d0SMarcel Holtmann
3251c8ba6d0SMarcel Holtmann if (skb->len != sizeof(struct hci_rp_read_local_version)) {
3262064ee33SMarcel Holtmann bt_dev_err(hdev, "BCM: Local version length mismatch");
3271c8ba6d0SMarcel Holtmann kfree_skb(skb);
3281c8ba6d0SMarcel Holtmann return ERR_PTR(-EIO);
3291c8ba6d0SMarcel Holtmann }
3301c8ba6d0SMarcel Holtmann
3311c8ba6d0SMarcel Holtmann return skb;
3321c8ba6d0SMarcel Holtmann }
3331c8ba6d0SMarcel Holtmann
btbcm_read_verbose_config(struct hci_dev * hdev)3341c8ba6d0SMarcel Holtmann static struct sk_buff *btbcm_read_verbose_config(struct hci_dev *hdev)
3351c8ba6d0SMarcel Holtmann {
3361c8ba6d0SMarcel Holtmann struct sk_buff *skb;
3371c8ba6d0SMarcel Holtmann
3381c8ba6d0SMarcel Holtmann skb = __hci_cmd_sync(hdev, 0xfc79, 0, NULL, HCI_INIT_TIMEOUT);
3391c8ba6d0SMarcel Holtmann if (IS_ERR(skb)) {
3402064ee33SMarcel Holtmann bt_dev_err(hdev, "BCM: Read verbose config info failed (%ld)",
3412064ee33SMarcel Holtmann PTR_ERR(skb));
3421c8ba6d0SMarcel Holtmann return skb;
3431c8ba6d0SMarcel Holtmann }
3441c8ba6d0SMarcel Holtmann
3451c8ba6d0SMarcel Holtmann if (skb->len != 7) {
3462064ee33SMarcel Holtmann bt_dev_err(hdev, "BCM: Verbose config length mismatch");
3471c8ba6d0SMarcel Holtmann kfree_skb(skb);
3481c8ba6d0SMarcel Holtmann return ERR_PTR(-EIO);
3491c8ba6d0SMarcel Holtmann }
3501c8ba6d0SMarcel Holtmann
3511c8ba6d0SMarcel Holtmann return skb;
3521c8ba6d0SMarcel Holtmann }
3531c8ba6d0SMarcel Holtmann
btbcm_read_controller_features(struct hci_dev * hdev)3544284ecbeSMarcel Holtmann static struct sk_buff *btbcm_read_controller_features(struct hci_dev *hdev)
3554284ecbeSMarcel Holtmann {
3564284ecbeSMarcel Holtmann struct sk_buff *skb;
3574284ecbeSMarcel Holtmann
3584284ecbeSMarcel Holtmann skb = __hci_cmd_sync(hdev, 0xfc6e, 0, NULL, HCI_INIT_TIMEOUT);
3594284ecbeSMarcel Holtmann if (IS_ERR(skb)) {
3602064ee33SMarcel Holtmann bt_dev_err(hdev, "BCM: Read controller features failed (%ld)",
3612064ee33SMarcel Holtmann PTR_ERR(skb));
3624284ecbeSMarcel Holtmann return skb;
3634284ecbeSMarcel Holtmann }
3644284ecbeSMarcel Holtmann
3654284ecbeSMarcel Holtmann if (skb->len != 9) {
3662064ee33SMarcel Holtmann bt_dev_err(hdev, "BCM: Controller features length mismatch");
3674284ecbeSMarcel Holtmann kfree_skb(skb);
3684284ecbeSMarcel Holtmann return ERR_PTR(-EIO);
3694284ecbeSMarcel Holtmann }
3704284ecbeSMarcel Holtmann
3714284ecbeSMarcel Holtmann return skb;
3724284ecbeSMarcel Holtmann }
3734284ecbeSMarcel Holtmann
btbcm_read_usb_product(struct hci_dev * hdev)3741c8ba6d0SMarcel Holtmann static struct sk_buff *btbcm_read_usb_product(struct hci_dev *hdev)
3751c8ba6d0SMarcel Holtmann {
3761c8ba6d0SMarcel Holtmann struct sk_buff *skb;
3771c8ba6d0SMarcel Holtmann
3781c8ba6d0SMarcel Holtmann skb = __hci_cmd_sync(hdev, 0xfc5a, 0, NULL, HCI_INIT_TIMEOUT);
3791c8ba6d0SMarcel Holtmann if (IS_ERR(skb)) {
3802064ee33SMarcel Holtmann bt_dev_err(hdev, "BCM: Read USB product info failed (%ld)",
3812064ee33SMarcel Holtmann PTR_ERR(skb));
3821c8ba6d0SMarcel Holtmann return skb;
3831c8ba6d0SMarcel Holtmann }
3841c8ba6d0SMarcel Holtmann
3851c8ba6d0SMarcel Holtmann if (skb->len != 5) {
3862064ee33SMarcel Holtmann bt_dev_err(hdev, "BCM: USB product length mismatch");
3871c8ba6d0SMarcel Holtmann kfree_skb(skb);
3881c8ba6d0SMarcel Holtmann return ERR_PTR(-EIO);
3891c8ba6d0SMarcel Holtmann }
3901c8ba6d0SMarcel Holtmann
3911c8ba6d0SMarcel Holtmann return skb;
3921c8ba6d0SMarcel Holtmann }
3931c8ba6d0SMarcel Holtmann
394801b4c02SAditya Garg static const struct dmi_system_id disable_broken_read_transmit_power[] = {
395801b4c02SAditya Garg {
396801b4c02SAditya Garg .matches = {
397801b4c02SAditya Garg DMI_MATCH(DMI_BOARD_VENDOR, "Apple Inc."),
398801b4c02SAditya Garg DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro16,1"),
399801b4c02SAditya Garg },
400801b4c02SAditya Garg },
401801b4c02SAditya Garg {
402801b4c02SAditya Garg .matches = {
403801b4c02SAditya Garg DMI_MATCH(DMI_BOARD_VENDOR, "Apple Inc."),
404801b4c02SAditya Garg DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro16,2"),
405801b4c02SAditya Garg },
406801b4c02SAditya Garg },
407801b4c02SAditya Garg {
408801b4c02SAditya Garg .matches = {
409801b4c02SAditya Garg DMI_MATCH(DMI_BOARD_VENDOR, "Apple Inc."),
410801b4c02SAditya Garg DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro16,4"),
411801b4c02SAditya Garg },
412801b4c02SAditya Garg },
413801b4c02SAditya Garg {
414801b4c02SAditya Garg .matches = {
415801b4c02SAditya Garg DMI_MATCH(DMI_BOARD_VENDOR, "Apple Inc."),
4163318ae23SAditya Garg DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir8,1"),
4173318ae23SAditya Garg },
4183318ae23SAditya Garg },
4193318ae23SAditya Garg {
4203318ae23SAditya Garg .matches = {
4213318ae23SAditya Garg DMI_MATCH(DMI_BOARD_VENDOR, "Apple Inc."),
4223318ae23SAditya Garg DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir8,2"),
4233318ae23SAditya Garg },
4243318ae23SAditya Garg },
4253318ae23SAditya Garg {
4263318ae23SAditya Garg .matches = {
4273318ae23SAditya Garg DMI_MATCH(DMI_BOARD_VENDOR, "Apple Inc."),
428801b4c02SAditya Garg DMI_MATCH(DMI_PRODUCT_NAME, "iMac20,1"),
429801b4c02SAditya Garg },
430801b4c02SAditya Garg },
431801b4c02SAditya Garg {
432801b4c02SAditya Garg .matches = {
433801b4c02SAditya Garg DMI_MATCH(DMI_BOARD_VENDOR, "Apple Inc."),
434801b4c02SAditya Garg DMI_MATCH(DMI_PRODUCT_NAME, "iMac20,2"),
435801b4c02SAditya Garg },
436801b4c02SAditya Garg },
437801b4c02SAditya Garg { }
438801b4c02SAditya Garg };
439801b4c02SAditya Garg
btbcm_read_info(struct hci_dev * hdev)440e76dc1ddSMarcel Holtmann static int btbcm_read_info(struct hci_dev *hdev)
441e76dc1ddSMarcel Holtmann {
442e76dc1ddSMarcel Holtmann struct sk_buff *skb;
443e76dc1ddSMarcel Holtmann
444e76dc1ddSMarcel Holtmann /* Read Verbose Config Version Info */
445e76dc1ddSMarcel Holtmann skb = btbcm_read_verbose_config(hdev);
446e76dc1ddSMarcel Holtmann if (IS_ERR(skb))
447e76dc1ddSMarcel Holtmann return PTR_ERR(skb);
448e76dc1ddSMarcel Holtmann
4492064ee33SMarcel Holtmann bt_dev_info(hdev, "BCM: chip id %u", skb->data[1]);
450e76dc1ddSMarcel Holtmann kfree_skb(skb);
451e76dc1ddSMarcel Holtmann
452af35e28fSHakan Jansson return 0;
453af35e28fSHakan Jansson }
454af35e28fSHakan Jansson
btbcm_print_controller_features(struct hci_dev * hdev)455af35e28fSHakan Jansson static int btbcm_print_controller_features(struct hci_dev *hdev)
456af35e28fSHakan Jansson {
457af35e28fSHakan Jansson struct sk_buff *skb;
458af35e28fSHakan Jansson
459e76dc1ddSMarcel Holtmann /* Read Controller Features */
460e76dc1ddSMarcel Holtmann skb = btbcm_read_controller_features(hdev);
461e76dc1ddSMarcel Holtmann if (IS_ERR(skb))
462e76dc1ddSMarcel Holtmann return PTR_ERR(skb);
463e76dc1ddSMarcel Holtmann
4642064ee33SMarcel Holtmann bt_dev_info(hdev, "BCM: features 0x%2.2x", skb->data[1]);
465e76dc1ddSMarcel Holtmann kfree_skb(skb);
466e76dc1ddSMarcel Holtmann
467801b4c02SAditya Garg /* Read DMI and disable broken Read LE Min/Max Tx Power */
468801b4c02SAditya Garg if (dmi_first_match(disable_broken_read_transmit_power))
469801b4c02SAditya Garg set_bit(HCI_QUIRK_BROKEN_READ_TRANSMIT_POWER, &hdev->quirks);
470801b4c02SAditya Garg
4712fcdd562SHans de Goede return 0;
4722fcdd562SHans de Goede }
4732fcdd562SHans de Goede
btbcm_print_local_name(struct hci_dev * hdev)4742fcdd562SHans de Goede static int btbcm_print_local_name(struct hci_dev *hdev)
4752fcdd562SHans de Goede {
4762fcdd562SHans de Goede struct sk_buff *skb;
4772fcdd562SHans de Goede
478e76dc1ddSMarcel Holtmann /* Read Local Name */
479e76dc1ddSMarcel Holtmann skb = btbcm_read_local_name(hdev);
480e76dc1ddSMarcel Holtmann if (IS_ERR(skb))
481e76dc1ddSMarcel Holtmann return PTR_ERR(skb);
482e76dc1ddSMarcel Holtmann
4832064ee33SMarcel Holtmann bt_dev_info(hdev, "%s", (char *)(skb->data + 1));
484e76dc1ddSMarcel Holtmann kfree_skb(skb);
485e76dc1ddSMarcel Holtmann
486e76dc1ddSMarcel Holtmann return 0;
487e76dc1ddSMarcel Holtmann }
488e76dc1ddSMarcel Holtmann
489f7328381SHans de Goede struct bcm_subver_table {
4901c8ba6d0SMarcel Holtmann u16 subver;
4911c8ba6d0SMarcel Holtmann const char *name;
492f7328381SHans de Goede };
493f7328381SHans de Goede
494f7328381SHans de Goede static const struct bcm_subver_table bcm_uart_subver_table[] = {
495192aa65aSAngus Ainslie { 0x1111, "BCM4362A2" }, /* 000.017.017 */
4964a546ec3SFrederic Danis { 0x4103, "BCM4330B1" }, /* 002.001.003 */
497b8dc6476SStephan Gerhold { 0x410d, "BCM4334B0" }, /* 002.001.013 */
4989a0bb57dSMarcel Holtmann { 0x410e, "BCM43341B0" }, /* 002.001.014 */
499039287aaSStephan Gerhold { 0x4204, "BCM2076B1" }, /* 002.002.004 */
500a8f3b941SFrederic Danis { 0x4406, "BCM4324B3" }, /* 002.004.006 */
501c03ee9afSHans de Goede { 0x4606, "BCM4324B5" }, /* 002.006.006 */
502a357ea09SChristian Hewitt { 0x6109, "BCM4335C0" }, /* 003.001.009 */
50340db5f0eSIlya Faenson { 0x610c, "BCM4354" }, /* 003.001.012 */
504d456f678SJörg Krause { 0x2122, "BCM4343A0" }, /* 001.001.034 */
505feb16722SIan Molton { 0x2209, "BCM43430A1" }, /* 001.002.009 */
50618a39b9aSIan W MORRISON { 0x6119, "BCM4345C0" }, /* 003.001.025 */
50752c8c7a7SOndrej Jirman { 0x6606, "BCM4345C5" }, /* 003.006.006 */
508b133e0c4SHans de Goede { 0x230f, "BCM4356A2" }, /* 001.003.015 */
50992ffe0dbSMaxime Ripard { 0x220e, "BCM20702A1" }, /* 001.002.014 */
5104f17c2b6SAhmad Fatoum { 0x420d, "BCM4349B1" }, /* 002.002.013 */
5114f17c2b6SAhmad Fatoum { 0x420e, "BCM4349B1" }, /* 002.002.014 */
512e3ca60d0SPaweł Chmiel { 0x4217, "BCM4329B1" }, /* 002.002.023 */
513f4d297eeSNeil Armstrong { 0x6106, "BCM4359C0" }, /* 003.001.006 */
5141199ab4cSMohammad Rasim { 0x4106, "BCM4335A0" }, /* 002.001.006 */
51527f4d1f2SMikhail Rudenko { 0x410c, "BCM43430B0" }, /* 002.001.012 */
5160d37ddfcSTim Harvey { 0x2119, "BCM4373A0" }, /* 001.001.025 */
5179a0bb57dSMarcel Holtmann { }
5189a0bb57dSMarcel Holtmann };
5199a0bb57dSMarcel Holtmann
520fec0de23SHans de Goede static const struct bcm_subver_table bcm_usb_subver_table[] = {
521c03ee9afSHans de Goede { 0x2105, "BCM20703A1" }, /* 001.001.005 */
522fec0de23SHans de Goede { 0x210b, "BCM43142A0" }, /* 001.001.011 */
523fec0de23SHans de Goede { 0x2112, "BCM4314A0" }, /* 001.001.018 */
524fec0de23SHans de Goede { 0x2118, "BCM20702A0" }, /* 001.001.024 */
525fec0de23SHans de Goede { 0x2126, "BCM4335A0" }, /* 001.001.038 */
526fec0de23SHans de Goede { 0x220e, "BCM20702A1" }, /* 001.002.014 */
527bf0ddd10SAzamat H. Hackimov { 0x230f, "BCM4356A2" }, /* 001.003.015 */
528fec0de23SHans de Goede { 0x4106, "BCM4335B0" }, /* 002.001.006 */
529fec0de23SHans de Goede { 0x410e, "BCM20702B0" }, /* 002.001.014 */
530fec0de23SHans de Goede { 0x6109, "BCM4335C0" }, /* 003.001.009 */
531fec0de23SHans de Goede { 0x610c, "BCM4354" }, /* 003.001.012 */
532bf0ddd10SAzamat H. Hackimov { 0x6607, "BCM4350C5" }, /* 003.006.007 */
533fec0de23SHans de Goede { }
534fec0de23SHans de Goede };
535fec0de23SHans de Goede
53663fac334SLinus Walleij /*
53763fac334SLinus Walleij * This currently only looks up the device tree board appendix,
53863fac334SLinus Walleij * but can be expanded to other mechanisms.
53963fac334SLinus Walleij */
btbcm_get_board_name(struct device * dev)54063fac334SLinus Walleij static const char *btbcm_get_board_name(struct device *dev)
54163fac334SLinus Walleij {
54263fac334SLinus Walleij #ifdef CONFIG_OF
54363fac334SLinus Walleij struct device_node *root;
54463fac334SLinus Walleij char *board_type;
54563fac334SLinus Walleij const char *tmp;
54663fac334SLinus Walleij int len;
54763fac334SLinus Walleij int i;
54863fac334SLinus Walleij
54963fac334SLinus Walleij root = of_find_node_by_path("/");
55063fac334SLinus Walleij if (!root)
55163fac334SLinus Walleij return NULL;
55263fac334SLinus Walleij
55363fac334SLinus Walleij if (of_property_read_string_index(root, "compatible", 0, &tmp))
55463fac334SLinus Walleij return NULL;
55563fac334SLinus Walleij
55663fac334SLinus Walleij /* get rid of any '/' in the compatible string */
55763fac334SLinus Walleij len = strlen(tmp) + 1;
55863fac334SLinus Walleij board_type = devm_kzalloc(dev, len, GFP_KERNEL);
55963fac334SLinus Walleij strscpy(board_type, tmp, len);
560b76abe46SSasha Finkelstein for (i = 0; i < len; i++) {
56163fac334SLinus Walleij if (board_type[i] == '/')
56263fac334SLinus Walleij board_type[i] = '-';
56363fac334SLinus Walleij }
56463fac334SLinus Walleij of_node_put(root);
56563fac334SLinus Walleij
56663fac334SLinus Walleij return board_type;
56763fac334SLinus Walleij #else
56863fac334SLinus Walleij return NULL;
56963fac334SLinus Walleij #endif
57063fac334SLinus Walleij }
57163fac334SLinus Walleij
btbcm_initialize(struct hci_dev * hdev,bool * fw_load_done,bool use_autobaud_mode)572af35e28fSHakan Jansson int btbcm_initialize(struct hci_dev *hdev, bool *fw_load_done, bool use_autobaud_mode)
57375e167e6SFrederic Danis {
574fec0de23SHans de Goede u16 subver, rev, pid, vid;
57575e167e6SFrederic Danis struct sk_buff *skb;
57675e167e6SFrederic Danis struct hci_rp_read_local_version *ver;
577fec0de23SHans de Goede const struct bcm_subver_table *bcm_subver_table;
57874530a63SHans de Goede const char *hw_name = NULL;
57963fac334SLinus Walleij const char *board_name;
58074530a63SHans de Goede char postfix[16] = "";
58174530a63SHans de Goede int fw_name_count = 0;
58274530a63SHans de Goede bcm_fw_name *fw_name;
5830287c5d8SHans de Goede const struct firmware *fw;
58475e167e6SFrederic Danis int i, err;
58575e167e6SFrederic Danis
58663fac334SLinus Walleij board_name = btbcm_get_board_name(&hdev->dev);
58763fac334SLinus Walleij
58875e167e6SFrederic Danis /* Reset */
58975e167e6SFrederic Danis err = btbcm_reset(hdev);
59075e167e6SFrederic Danis if (err)
59175e167e6SFrederic Danis return err;
59275e167e6SFrederic Danis
59375e167e6SFrederic Danis /* Read Local Version Info */
59475e167e6SFrederic Danis skb = btbcm_read_local_version(hdev);
59575e167e6SFrederic Danis if (IS_ERR(skb))
59675e167e6SFrederic Danis return PTR_ERR(skb);
59775e167e6SFrederic Danis
59875e167e6SFrederic Danis ver = (struct hci_rp_read_local_version *)skb->data;
59975e167e6SFrederic Danis rev = le16_to_cpu(ver->hci_rev);
60075e167e6SFrederic Danis subver = le16_to_cpu(ver->lmp_subver);
60175e167e6SFrederic Danis kfree_skb(skb);
60275e167e6SFrederic Danis
603e76dc1ddSMarcel Holtmann /* Read controller information */
6040287c5d8SHans de Goede if (!(*fw_load_done)) {
605e76dc1ddSMarcel Holtmann err = btbcm_read_info(hdev);
606e76dc1ddSMarcel Holtmann if (err)
607e76dc1ddSMarcel Holtmann return err;
60822ac1916SHans de Goede }
609af35e28fSHakan Jansson
610af35e28fSHakan Jansson if (!use_autobaud_mode) {
611af35e28fSHakan Jansson err = btbcm_print_controller_features(hdev);
612af35e28fSHakan Jansson if (err)
613af35e28fSHakan Jansson return err;
614af35e28fSHakan Jansson
6152fcdd562SHans de Goede err = btbcm_print_local_name(hdev);
6162fcdd562SHans de Goede if (err)
6172fcdd562SHans de Goede return err;
618af35e28fSHakan Jansson }
61975e167e6SFrederic Danis
620fec0de23SHans de Goede bcm_subver_table = (hdev->bus == HCI_USB) ? bcm_usb_subver_table :
621fec0de23SHans de Goede bcm_uart_subver_table;
622fec0de23SHans de Goede
623fec0de23SHans de Goede for (i = 0; bcm_subver_table[i].name; i++) {
624fec0de23SHans de Goede if (subver == bcm_subver_table[i].subver) {
625fec0de23SHans de Goede hw_name = bcm_subver_table[i].name;
62675e167e6SFrederic Danis break;
62775e167e6SFrederic Danis }
62875e167e6SFrederic Danis }
62975e167e6SFrederic Danis
630f53b975cSHans de Goede bt_dev_info(hdev, "%s (%3.3u.%3.3u.%3.3u) build %4.4u",
63174530a63SHans de Goede hw_name ? hw_name : "BCM", (subver & 0xe000) >> 13,
632f53b975cSHans de Goede (subver & 0x1f00) >> 8, (subver & 0x00ff), rev & 0x0fff);
633f53b975cSHans de Goede
634f53b975cSHans de Goede if (*fw_load_done)
635f53b975cSHans de Goede return 0;
636f53b975cSHans de Goede
637fec0de23SHans de Goede if (hdev->bus == HCI_USB) {
638fec0de23SHans de Goede /* Read USB Product Info */
639fec0de23SHans de Goede skb = btbcm_read_usb_product(hdev);
640fec0de23SHans de Goede if (IS_ERR(skb))
641fec0de23SHans de Goede return PTR_ERR(skb);
642fec0de23SHans de Goede
643fec0de23SHans de Goede vid = get_unaligned_le16(skb->data + 1);
644fec0de23SHans de Goede pid = get_unaligned_le16(skb->data + 3);
645fec0de23SHans de Goede kfree_skb(skb);
646fec0de23SHans de Goede
64774530a63SHans de Goede snprintf(postfix, sizeof(postfix), "-%4.4x-%4.4x", vid, pid);
64875e167e6SFrederic Danis }
64975e167e6SFrederic Danis
65074530a63SHans de Goede fw_name = kmalloc(BCM_FW_NAME_COUNT_MAX * BCM_FW_NAME_LEN, GFP_KERNEL);
65174530a63SHans de Goede if (!fw_name)
65274530a63SHans de Goede return -ENOMEM;
65374530a63SHans de Goede
65474530a63SHans de Goede if (hw_name) {
65563fac334SLinus Walleij if (board_name) {
65663fac334SLinus Walleij snprintf(fw_name[fw_name_count], BCM_FW_NAME_LEN,
65763fac334SLinus Walleij "brcm/%s%s.%s.hcd", hw_name, postfix, board_name);
65863fac334SLinus Walleij fw_name_count++;
65963fac334SLinus Walleij }
66074530a63SHans de Goede snprintf(fw_name[fw_name_count], BCM_FW_NAME_LEN,
66174530a63SHans de Goede "brcm/%s%s.hcd", hw_name, postfix);
66274530a63SHans de Goede fw_name_count++;
6630287c5d8SHans de Goede }
6640287c5d8SHans de Goede
66563fac334SLinus Walleij if (board_name) {
66663fac334SLinus Walleij snprintf(fw_name[fw_name_count], BCM_FW_NAME_LEN,
66763fac334SLinus Walleij "brcm/BCM%s.%s.hcd", postfix, board_name);
66863fac334SLinus Walleij fw_name_count++;
66963fac334SLinus Walleij }
67074530a63SHans de Goede snprintf(fw_name[fw_name_count], BCM_FW_NAME_LEN,
67174530a63SHans de Goede "brcm/BCM%s.hcd", postfix);
67274530a63SHans de Goede fw_name_count++;
67374530a63SHans de Goede
67474530a63SHans de Goede for (i = 0; i < fw_name_count; i++) {
67574530a63SHans de Goede err = firmware_request_nowarn(&fw, fw_name[i], &hdev->dev);
67674530a63SHans de Goede if (err == 0) {
67774530a63SHans de Goede bt_dev_info(hdev, "%s '%s' Patch",
67874530a63SHans de Goede hw_name ? hw_name : "BCM", fw_name[i]);
67974530a63SHans de Goede *fw_load_done = true;
68074530a63SHans de Goede break;
68174530a63SHans de Goede }
68274530a63SHans de Goede }
68374530a63SHans de Goede
68474530a63SHans de Goede if (*fw_load_done) {
6850287c5d8SHans de Goede err = btbcm_patchram(hdev, fw);
6860287c5d8SHans de Goede if (err)
6870287c5d8SHans de Goede bt_dev_info(hdev, "BCM: Patch failed (%d)", err);
6880287c5d8SHans de Goede
6890287c5d8SHans de Goede release_firmware(fw);
69074530a63SHans de Goede } else {
69174530a63SHans de Goede bt_dev_err(hdev, "BCM: firmware Patch file not found, tried:");
69274530a63SHans de Goede for (i = 0; i < fw_name_count; i++)
69374530a63SHans de Goede bt_dev_err(hdev, "BCM: '%s'", fw_name[i]);
69474530a63SHans de Goede }
69574530a63SHans de Goede
69674530a63SHans de Goede kfree(fw_name);
69775e167e6SFrederic Danis return 0;
69875e167e6SFrederic Danis }
69975e167e6SFrederic Danis EXPORT_SYMBOL_GPL(btbcm_initialize);
70075e167e6SFrederic Danis
btbcm_finalize(struct hci_dev * hdev,bool * fw_load_done,bool use_autobaud_mode)701af35e28fSHakan Jansson int btbcm_finalize(struct hci_dev *hdev, bool *fw_load_done, bool use_autobaud_mode)
70275e167e6SFrederic Danis {
70375e167e6SFrederic Danis int err;
70475e167e6SFrederic Danis
7050383f16aSHans de Goede /* Re-initialize if necessary */
7060383f16aSHans de Goede if (*fw_load_done) {
707af35e28fSHakan Jansson err = btbcm_initialize(hdev, fw_load_done, use_autobaud_mode);
70875e167e6SFrederic Danis if (err)
70975e167e6SFrederic Danis return err;
7100383f16aSHans de Goede }
71175e167e6SFrederic Danis
71275e167e6SFrederic Danis btbcm_check_bdaddr(hdev);
71375e167e6SFrederic Danis
71475e167e6SFrederic Danis set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
71575e167e6SFrederic Danis
71675e167e6SFrederic Danis return 0;
71775e167e6SFrederic Danis }
71875e167e6SFrederic Danis EXPORT_SYMBOL_GPL(btbcm_finalize);
71975e167e6SFrederic Danis
btbcm_setup_patchram(struct hci_dev * hdev)7201c8ba6d0SMarcel Holtmann int btbcm_setup_patchram(struct hci_dev *hdev)
7211c8ba6d0SMarcel Holtmann {
7220287c5d8SHans de Goede bool fw_load_done = false;
723af35e28fSHakan Jansson bool use_autobaud_mode = false;
72459ce5699SHans de Goede int err;
7251c8ba6d0SMarcel Holtmann
72659ce5699SHans de Goede /* Initialize */
727af35e28fSHakan Jansson err = btbcm_initialize(hdev, &fw_load_done, use_autobaud_mode);
7281c8ba6d0SMarcel Holtmann if (err)
7291c8ba6d0SMarcel Holtmann return err;
7301c8ba6d0SMarcel Holtmann
7310287c5d8SHans de Goede /* Re-initialize after loading Patch */
732af35e28fSHakan Jansson return btbcm_finalize(hdev, &fw_load_done, use_autobaud_mode);
7331c8ba6d0SMarcel Holtmann }
7341c8ba6d0SMarcel Holtmann EXPORT_SYMBOL_GPL(btbcm_setup_patchram);
7351c8ba6d0SMarcel Holtmann
btbcm_setup_apple(struct hci_dev * hdev)7361c8ba6d0SMarcel Holtmann int btbcm_setup_apple(struct hci_dev *hdev)
7371c8ba6d0SMarcel Holtmann {
7381c8ba6d0SMarcel Holtmann struct sk_buff *skb;
739b224d3ffSMarcel Holtmann int err;
740b224d3ffSMarcel Holtmann
741b224d3ffSMarcel Holtmann /* Reset */
742b224d3ffSMarcel Holtmann err = btbcm_reset(hdev);
743b224d3ffSMarcel Holtmann if (err)
744b224d3ffSMarcel Holtmann return err;
7451c8ba6d0SMarcel Holtmann
7461c8ba6d0SMarcel Holtmann /* Read Verbose Config Version Info */
7471c8ba6d0SMarcel Holtmann skb = btbcm_read_verbose_config(hdev);
7487bee8b08SChris Mason if (!IS_ERR(skb)) {
7492064ee33SMarcel Holtmann bt_dev_info(hdev, "BCM: chip id %u build %4.4u",
750b224d3ffSMarcel Holtmann skb->data[1], get_unaligned_le16(skb->data + 5));
7511c8ba6d0SMarcel Holtmann kfree_skb(skb);
7527bee8b08SChris Mason }
7531c8ba6d0SMarcel Holtmann
75434cea41eSMarcel Holtmann /* Read USB Product Info */
75534cea41eSMarcel Holtmann skb = btbcm_read_usb_product(hdev);
75634cea41eSMarcel Holtmann if (!IS_ERR(skb)) {
7572064ee33SMarcel Holtmann bt_dev_info(hdev, "BCM: product %4.4x:%4.4x",
75834cea41eSMarcel Holtmann get_unaligned_le16(skb->data + 1),
75934cea41eSMarcel Holtmann get_unaligned_le16(skb->data + 3));
76034cea41eSMarcel Holtmann kfree_skb(skb);
76134cea41eSMarcel Holtmann }
76234cea41eSMarcel Holtmann
7634284ecbeSMarcel Holtmann /* Read Controller Features */
7644284ecbeSMarcel Holtmann skb = btbcm_read_controller_features(hdev);
7654284ecbeSMarcel Holtmann if (!IS_ERR(skb)) {
7662064ee33SMarcel Holtmann bt_dev_info(hdev, "BCM: features 0x%2.2x", skb->data[1]);
7674284ecbeSMarcel Holtmann kfree_skb(skb);
7684284ecbeSMarcel Holtmann }
7694284ecbeSMarcel Holtmann
7709bc63ca0SMarcel Holtmann /* Read Local Name */
7719bc63ca0SMarcel Holtmann skb = btbcm_read_local_name(hdev);
7729bc63ca0SMarcel Holtmann if (!IS_ERR(skb)) {
7732064ee33SMarcel Holtmann bt_dev_info(hdev, "%s", (char *)(skb->data + 1));
7749bc63ca0SMarcel Holtmann kfree_skb(skb);
7759bc63ca0SMarcel Holtmann }
7769bc63ca0SMarcel Holtmann
777941521e2SMarcel Holtmann set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
778941521e2SMarcel Holtmann
7791c8ba6d0SMarcel Holtmann return 0;
7801c8ba6d0SMarcel Holtmann }
7811c8ba6d0SMarcel Holtmann EXPORT_SYMBOL_GPL(btbcm_setup_apple);
7821c8ba6d0SMarcel Holtmann
7834fba30f0SMarcel Holtmann MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
7844fba30f0SMarcel Holtmann MODULE_DESCRIPTION("Bluetooth support for Broadcom devices ver " VERSION);
7854fba30f0SMarcel Holtmann MODULE_VERSION(VERSION);
7864fba30f0SMarcel Holtmann MODULE_LICENSE("GPL");
787