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 94fba30f0SMarcel Holtmann #include <linux/module.h> 101c8ba6d0SMarcel Holtmann #include <linux/firmware.h> 111c8ba6d0SMarcel Holtmann #include <asm/unaligned.h> 124fba30f0SMarcel Holtmann 134fba30f0SMarcel Holtmann #include <net/bluetooth/bluetooth.h> 144fba30f0SMarcel Holtmann #include <net/bluetooth/hci_core.h> 154fba30f0SMarcel Holtmann 164fba30f0SMarcel Holtmann #include "btbcm.h" 174fba30f0SMarcel Holtmann 184fba30f0SMarcel Holtmann #define VERSION "0.1" 194fba30f0SMarcel Holtmann 204fba30f0SMarcel Holtmann #define BDADDR_BCM20702A0 (&(bdaddr_t) {{0x00, 0xa0, 0x02, 0x70, 0x20, 0x00}}) 2192ffe0dbSMaxime Ripard #define BDADDR_BCM20702A1 (&(bdaddr_t) {{0x00, 0x00, 0xa0, 0x02, 0x70, 0x20}}) 22300926b1SStephan Gerhold #define BDADDR_BCM2076B1 (&(bdaddr_t) {{0x79, 0x56, 0x00, 0xa0, 0x76, 0x20}}) 230697607aSChen-Yu Tsai #define BDADDR_BCM43430A0 (&(bdaddr_t) {{0xac, 0x1f, 0x12, 0xa0, 0x43, 0x43}}) 24a8f3b941SFrederic Danis #define BDADDR_BCM4324B3 (&(bdaddr_t) {{0x00, 0x00, 0x00, 0xb3, 0x24, 0x43}}) 254a546ec3SFrederic Danis #define BDADDR_BCM4330B1 (&(bdaddr_t) {{0x00, 0x00, 0x00, 0xb1, 0x30, 0x43}}) 26b8dc6476SStephan Gerhold #define BDADDR_BCM4334B0 (&(bdaddr_t) {{0x00, 0x00, 0x00, 0xb0, 0x34, 0x43}}) 2752c8c7a7SOndrej Jirman #define BDADDR_BCM4345C5 (&(bdaddr_t) {{0xac, 0x1f, 0x00, 0xc5, 0x45, 0x43}}) 2850357261SFerry Toth #define BDADDR_BCM43341B (&(bdaddr_t) {{0xac, 0x1f, 0x00, 0x1b, 0x34, 0x43}}) 294fba30f0SMarcel Holtmann 300287c5d8SHans de Goede #define BCM_FW_NAME_LEN 64 3174530a63SHans de Goede #define BCM_FW_NAME_COUNT_MAX 2 3274530a63SHans de Goede /* For kmalloc-ing the fw-name array instead of putting it on the stack */ 3374530a63SHans de Goede typedef char bcm_fw_name[BCM_FW_NAME_LEN]; 340287c5d8SHans de Goede 354fba30f0SMarcel Holtmann int btbcm_check_bdaddr(struct hci_dev *hdev) 364fba30f0SMarcel Holtmann { 374fba30f0SMarcel Holtmann struct hci_rp_read_bd_addr *bda; 384fba30f0SMarcel Holtmann struct sk_buff *skb; 394fba30f0SMarcel Holtmann 404fba30f0SMarcel Holtmann skb = __hci_cmd_sync(hdev, HCI_OP_READ_BD_ADDR, 0, NULL, 414fba30f0SMarcel Holtmann HCI_INIT_TIMEOUT); 424fba30f0SMarcel Holtmann if (IS_ERR(skb)) { 434fba30f0SMarcel Holtmann int err = PTR_ERR(skb); 44dde8010bSChangqi Du 452064ee33SMarcel Holtmann bt_dev_err(hdev, "BCM: Reading device address failed (%d)", err); 464fba30f0SMarcel Holtmann return err; 474fba30f0SMarcel Holtmann } 484fba30f0SMarcel Holtmann 494fba30f0SMarcel Holtmann if (skb->len != sizeof(*bda)) { 502064ee33SMarcel Holtmann bt_dev_err(hdev, "BCM: Device address length mismatch"); 514fba30f0SMarcel Holtmann kfree_skb(skb); 524fba30f0SMarcel Holtmann return -EIO; 534fba30f0SMarcel Holtmann } 544fba30f0SMarcel Holtmann 554fba30f0SMarcel Holtmann bda = (struct hci_rp_read_bd_addr *)skb->data; 564fba30f0SMarcel Holtmann 57a8f3b941SFrederic Danis /* Check if the address indicates a controller with either an 58a8f3b941SFrederic Danis * invalid or default address. In both cases the device needs 59a8f3b941SFrederic Danis * to be marked as not having a valid address. 60a8f3b941SFrederic Danis * 61a8f3b941SFrederic Danis * The address 00:20:70:02:A0:00 indicates a BCM20702A0 controller 624fba30f0SMarcel Holtmann * with no configured address. 63a8f3b941SFrederic Danis * 6492ffe0dbSMaxime Ripard * The address 20:70:02:A0:00:00 indicates a BCM20702A1 controller 6592ffe0dbSMaxime Ripard * with no configured address. 6692ffe0dbSMaxime Ripard * 67300926b1SStephan Gerhold * The address 20:76:A0:00:56:79 indicates a BCM2076B1 controller 68300926b1SStephan Gerhold * with no configured address. 69300926b1SStephan Gerhold * 70a8f3b941SFrederic Danis * The address 43:24:B3:00:00:00 indicates a BCM4324B3 controller 71a8f3b941SFrederic Danis * with waiting for configuration state. 724a546ec3SFrederic Danis * 734a546ec3SFrederic Danis * The address 43:30:B1:00:00:00 indicates a BCM4330B1 controller 744a546ec3SFrederic Danis * with waiting for configuration state. 750697607aSChen-Yu Tsai * 760697607aSChen-Yu Tsai * The address 43:43:A0:12:1F:AC indicates a BCM43430A0 controller 770697607aSChen-Yu Tsai * with no configured address. 784fba30f0SMarcel Holtmann */ 79a8f3b941SFrederic Danis if (!bacmp(&bda->bdaddr, BDADDR_BCM20702A0) || 8092ffe0dbSMaxime Ripard !bacmp(&bda->bdaddr, BDADDR_BCM20702A1) || 81300926b1SStephan Gerhold !bacmp(&bda->bdaddr, BDADDR_BCM2076B1) || 824a546ec3SFrederic Danis !bacmp(&bda->bdaddr, BDADDR_BCM4324B3) || 830697607aSChen-Yu Tsai !bacmp(&bda->bdaddr, BDADDR_BCM4330B1) || 84b8dc6476SStephan Gerhold !bacmp(&bda->bdaddr, BDADDR_BCM4334B0) || 8552c8c7a7SOndrej Jirman !bacmp(&bda->bdaddr, BDADDR_BCM4345C5) || 8650357261SFerry Toth !bacmp(&bda->bdaddr, BDADDR_BCM43430A0) || 8750357261SFerry Toth !bacmp(&bda->bdaddr, BDADDR_BCM43341B)) { 882064ee33SMarcel Holtmann bt_dev_info(hdev, "BCM: Using default device address (%pMR)", 892064ee33SMarcel Holtmann &bda->bdaddr); 904fba30f0SMarcel Holtmann set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks); 914fba30f0SMarcel Holtmann } 924fba30f0SMarcel Holtmann 934fba30f0SMarcel Holtmann kfree_skb(skb); 944fba30f0SMarcel Holtmann 954fba30f0SMarcel Holtmann return 0; 964fba30f0SMarcel Holtmann } 974fba30f0SMarcel Holtmann EXPORT_SYMBOL_GPL(btbcm_check_bdaddr); 984fba30f0SMarcel Holtmann 994fba30f0SMarcel Holtmann int btbcm_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) 1004fba30f0SMarcel Holtmann { 1014fba30f0SMarcel Holtmann struct sk_buff *skb; 1024fba30f0SMarcel Holtmann int err; 1034fba30f0SMarcel Holtmann 1044fba30f0SMarcel Holtmann skb = __hci_cmd_sync(hdev, 0xfc01, 6, bdaddr, HCI_INIT_TIMEOUT); 1054fba30f0SMarcel Holtmann if (IS_ERR(skb)) { 1064fba30f0SMarcel Holtmann err = PTR_ERR(skb); 1072064ee33SMarcel Holtmann bt_dev_err(hdev, "BCM: Change address command failed (%d)", err); 1084fba30f0SMarcel Holtmann return err; 1094fba30f0SMarcel Holtmann } 1104fba30f0SMarcel Holtmann kfree_skb(skb); 1114fba30f0SMarcel Holtmann 1124fba30f0SMarcel Holtmann return 0; 1134fba30f0SMarcel Holtmann } 1144fba30f0SMarcel Holtmann EXPORT_SYMBOL_GPL(btbcm_set_bdaddr); 1154fba30f0SMarcel Holtmann 11652837990SAbhishek Pandit-Subedi int btbcm_read_pcm_int_params(struct hci_dev *hdev, 11752837990SAbhishek Pandit-Subedi struct bcm_set_pcm_int_params *params) 11852837990SAbhishek Pandit-Subedi { 11952837990SAbhishek Pandit-Subedi struct sk_buff *skb; 12052837990SAbhishek Pandit-Subedi int err = 0; 12152837990SAbhishek Pandit-Subedi 12252837990SAbhishek Pandit-Subedi skb = __hci_cmd_sync(hdev, 0xfc1d, 0, NULL, HCI_INIT_TIMEOUT); 12352837990SAbhishek Pandit-Subedi if (IS_ERR(skb)) { 12452837990SAbhishek Pandit-Subedi err = PTR_ERR(skb); 12552837990SAbhishek Pandit-Subedi bt_dev_err(hdev, "BCM: Read PCM int params failed (%d)", err); 12652837990SAbhishek Pandit-Subedi return err; 12752837990SAbhishek Pandit-Subedi } 12852837990SAbhishek Pandit-Subedi 12952837990SAbhishek Pandit-Subedi if (skb->len != 6 || skb->data[0]) { 13052837990SAbhishek Pandit-Subedi bt_dev_err(hdev, "BCM: Read PCM int params length mismatch"); 13152837990SAbhishek Pandit-Subedi kfree_skb(skb); 13252837990SAbhishek Pandit-Subedi return -EIO; 13352837990SAbhishek Pandit-Subedi } 13452837990SAbhishek Pandit-Subedi 13552837990SAbhishek Pandit-Subedi if (params) 13652837990SAbhishek Pandit-Subedi memcpy(params, skb->data + 1, 5); 13752837990SAbhishek Pandit-Subedi 13852837990SAbhishek Pandit-Subedi kfree_skb(skb); 13952837990SAbhishek Pandit-Subedi 14052837990SAbhishek Pandit-Subedi return 0; 14152837990SAbhishek Pandit-Subedi } 14252837990SAbhishek Pandit-Subedi EXPORT_SYMBOL_GPL(btbcm_read_pcm_int_params); 14352837990SAbhishek Pandit-Subedi 14452837990SAbhishek Pandit-Subedi int btbcm_write_pcm_int_params(struct hci_dev *hdev, 14552837990SAbhishek Pandit-Subedi const struct bcm_set_pcm_int_params *params) 14652837990SAbhishek Pandit-Subedi { 14752837990SAbhishek Pandit-Subedi struct sk_buff *skb; 14852837990SAbhishek Pandit-Subedi int err; 14952837990SAbhishek Pandit-Subedi 15052837990SAbhishek Pandit-Subedi skb = __hci_cmd_sync(hdev, 0xfc1c, 5, params, HCI_INIT_TIMEOUT); 15152837990SAbhishek Pandit-Subedi if (IS_ERR(skb)) { 15252837990SAbhishek Pandit-Subedi err = PTR_ERR(skb); 15352837990SAbhishek Pandit-Subedi bt_dev_err(hdev, "BCM: Write PCM int params failed (%d)", err); 15452837990SAbhishek Pandit-Subedi return err; 15552837990SAbhishek Pandit-Subedi } 15652837990SAbhishek Pandit-Subedi kfree_skb(skb); 15752837990SAbhishek Pandit-Subedi 15852837990SAbhishek Pandit-Subedi return 0; 15952837990SAbhishek Pandit-Subedi } 16052837990SAbhishek Pandit-Subedi EXPORT_SYMBOL_GPL(btbcm_write_pcm_int_params); 16152837990SAbhishek Pandit-Subedi 16218aeb444SFrederic Danis int btbcm_patchram(struct hci_dev *hdev, const struct firmware *fw) 16350862ee5SMarcel Holtmann { 16450862ee5SMarcel Holtmann const struct hci_command_hdr *cmd; 16550862ee5SMarcel Holtmann const u8 *fw_ptr; 16650862ee5SMarcel Holtmann size_t fw_size; 16750862ee5SMarcel Holtmann struct sk_buff *skb; 16850862ee5SMarcel Holtmann u16 opcode; 16918aeb444SFrederic Danis int err = 0; 17050862ee5SMarcel Holtmann 17150862ee5SMarcel Holtmann /* Start Download */ 17250862ee5SMarcel Holtmann skb = __hci_cmd_sync(hdev, 0xfc2e, 0, NULL, HCI_INIT_TIMEOUT); 17350862ee5SMarcel Holtmann if (IS_ERR(skb)) { 17450862ee5SMarcel Holtmann err = PTR_ERR(skb); 1752064ee33SMarcel Holtmann bt_dev_err(hdev, "BCM: Download Minidrv command failed (%d)", 1762064ee33SMarcel Holtmann err); 17750862ee5SMarcel Holtmann goto done; 17850862ee5SMarcel Holtmann } 17950862ee5SMarcel Holtmann kfree_skb(skb); 18050862ee5SMarcel Holtmann 18150862ee5SMarcel Holtmann /* 50 msec delay after Download Minidrv completes */ 18250862ee5SMarcel Holtmann msleep(50); 18350862ee5SMarcel Holtmann 18450862ee5SMarcel Holtmann fw_ptr = fw->data; 18550862ee5SMarcel Holtmann fw_size = fw->size; 18650862ee5SMarcel Holtmann 18750862ee5SMarcel Holtmann while (fw_size >= sizeof(*cmd)) { 18850862ee5SMarcel Holtmann const u8 *cmd_param; 18950862ee5SMarcel Holtmann 19050862ee5SMarcel Holtmann cmd = (struct hci_command_hdr *)fw_ptr; 19150862ee5SMarcel Holtmann fw_ptr += sizeof(*cmd); 19250862ee5SMarcel Holtmann fw_size -= sizeof(*cmd); 19350862ee5SMarcel Holtmann 19450862ee5SMarcel Holtmann if (fw_size < cmd->plen) { 1952064ee33SMarcel Holtmann bt_dev_err(hdev, "BCM: Patch is corrupted"); 19650862ee5SMarcel Holtmann err = -EINVAL; 19750862ee5SMarcel Holtmann goto done; 19850862ee5SMarcel Holtmann } 19950862ee5SMarcel Holtmann 20050862ee5SMarcel Holtmann cmd_param = fw_ptr; 20150862ee5SMarcel Holtmann fw_ptr += cmd->plen; 20250862ee5SMarcel Holtmann fw_size -= cmd->plen; 20350862ee5SMarcel Holtmann 20450862ee5SMarcel Holtmann opcode = le16_to_cpu(cmd->opcode); 20550862ee5SMarcel Holtmann 20650862ee5SMarcel Holtmann skb = __hci_cmd_sync(hdev, opcode, cmd->plen, cmd_param, 20750862ee5SMarcel Holtmann HCI_INIT_TIMEOUT); 20850862ee5SMarcel Holtmann if (IS_ERR(skb)) { 20950862ee5SMarcel Holtmann err = PTR_ERR(skb); 2102064ee33SMarcel Holtmann bt_dev_err(hdev, "BCM: Patch command %04x failed (%d)", 2112064ee33SMarcel Holtmann opcode, err); 21250862ee5SMarcel Holtmann goto done; 21350862ee5SMarcel Holtmann } 21450862ee5SMarcel Holtmann kfree_skb(skb); 21550862ee5SMarcel Holtmann } 21650862ee5SMarcel Holtmann 21750862ee5SMarcel Holtmann /* 250 msec delay after Launch Ram completes */ 21850862ee5SMarcel Holtmann msleep(250); 21950862ee5SMarcel Holtmann 22050862ee5SMarcel Holtmann done: 22150862ee5SMarcel Holtmann return err; 22250862ee5SMarcel Holtmann } 22350862ee5SMarcel Holtmann EXPORT_SYMBOL(btbcm_patchram); 22450862ee5SMarcel Holtmann 2251c8ba6d0SMarcel Holtmann static int btbcm_reset(struct hci_dev *hdev) 2261c8ba6d0SMarcel Holtmann { 2271c8ba6d0SMarcel Holtmann struct sk_buff *skb; 2281c8ba6d0SMarcel Holtmann 2291c8ba6d0SMarcel Holtmann skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT); 2301c8ba6d0SMarcel Holtmann if (IS_ERR(skb)) { 2311c8ba6d0SMarcel Holtmann int err = PTR_ERR(skb); 232dde8010bSChangqi Du 2332064ee33SMarcel Holtmann bt_dev_err(hdev, "BCM: Reset failed (%d)", err); 2341c8ba6d0SMarcel Holtmann return err; 2351c8ba6d0SMarcel Holtmann } 2361c8ba6d0SMarcel Holtmann kfree_skb(skb); 2371c8ba6d0SMarcel Holtmann 2383af3a594SWen-chien Jesse Sung /* 100 msec delay for module to complete reset process */ 2393af3a594SWen-chien Jesse Sung msleep(100); 2403af3a594SWen-chien Jesse Sung 2411c8ba6d0SMarcel Holtmann return 0; 2421c8ba6d0SMarcel Holtmann } 2431c8ba6d0SMarcel Holtmann 2449bc63ca0SMarcel Holtmann static struct sk_buff *btbcm_read_local_name(struct hci_dev *hdev) 2459bc63ca0SMarcel Holtmann { 2469bc63ca0SMarcel Holtmann struct sk_buff *skb; 2479bc63ca0SMarcel Holtmann 2489bc63ca0SMarcel Holtmann skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_NAME, 0, NULL, 2499bc63ca0SMarcel Holtmann HCI_INIT_TIMEOUT); 2509bc63ca0SMarcel Holtmann if (IS_ERR(skb)) { 2512064ee33SMarcel Holtmann bt_dev_err(hdev, "BCM: Reading local name failed (%ld)", 2522064ee33SMarcel Holtmann PTR_ERR(skb)); 2539bc63ca0SMarcel Holtmann return skb; 2549bc63ca0SMarcel Holtmann } 2559bc63ca0SMarcel Holtmann 2569bc63ca0SMarcel Holtmann if (skb->len != sizeof(struct hci_rp_read_local_name)) { 2572064ee33SMarcel Holtmann bt_dev_err(hdev, "BCM: Local name length mismatch"); 2589bc63ca0SMarcel Holtmann kfree_skb(skb); 2599bc63ca0SMarcel Holtmann return ERR_PTR(-EIO); 2609bc63ca0SMarcel Holtmann } 2619bc63ca0SMarcel Holtmann 2629bc63ca0SMarcel Holtmann return skb; 2639bc63ca0SMarcel Holtmann } 2649bc63ca0SMarcel Holtmann 2651c8ba6d0SMarcel Holtmann static struct sk_buff *btbcm_read_local_version(struct hci_dev *hdev) 2661c8ba6d0SMarcel Holtmann { 2671c8ba6d0SMarcel Holtmann struct sk_buff *skb; 2681c8ba6d0SMarcel Holtmann 2691c8ba6d0SMarcel Holtmann skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL, 2701c8ba6d0SMarcel Holtmann HCI_INIT_TIMEOUT); 2711c8ba6d0SMarcel Holtmann if (IS_ERR(skb)) { 2722064ee33SMarcel Holtmann bt_dev_err(hdev, "BCM: Reading local version info failed (%ld)", 2732064ee33SMarcel Holtmann PTR_ERR(skb)); 2741c8ba6d0SMarcel Holtmann return skb; 2751c8ba6d0SMarcel Holtmann } 2761c8ba6d0SMarcel Holtmann 2771c8ba6d0SMarcel Holtmann if (skb->len != sizeof(struct hci_rp_read_local_version)) { 2782064ee33SMarcel Holtmann bt_dev_err(hdev, "BCM: Local version length mismatch"); 2791c8ba6d0SMarcel Holtmann kfree_skb(skb); 2801c8ba6d0SMarcel Holtmann return ERR_PTR(-EIO); 2811c8ba6d0SMarcel Holtmann } 2821c8ba6d0SMarcel Holtmann 2831c8ba6d0SMarcel Holtmann return skb; 2841c8ba6d0SMarcel Holtmann } 2851c8ba6d0SMarcel Holtmann 2861c8ba6d0SMarcel Holtmann static struct sk_buff *btbcm_read_verbose_config(struct hci_dev *hdev) 2871c8ba6d0SMarcel Holtmann { 2881c8ba6d0SMarcel Holtmann struct sk_buff *skb; 2891c8ba6d0SMarcel Holtmann 2901c8ba6d0SMarcel Holtmann skb = __hci_cmd_sync(hdev, 0xfc79, 0, NULL, HCI_INIT_TIMEOUT); 2911c8ba6d0SMarcel Holtmann if (IS_ERR(skb)) { 2922064ee33SMarcel Holtmann bt_dev_err(hdev, "BCM: Read verbose config info failed (%ld)", 2932064ee33SMarcel Holtmann PTR_ERR(skb)); 2941c8ba6d0SMarcel Holtmann return skb; 2951c8ba6d0SMarcel Holtmann } 2961c8ba6d0SMarcel Holtmann 2971c8ba6d0SMarcel Holtmann if (skb->len != 7) { 2982064ee33SMarcel Holtmann bt_dev_err(hdev, "BCM: Verbose config length mismatch"); 2991c8ba6d0SMarcel Holtmann kfree_skb(skb); 3001c8ba6d0SMarcel Holtmann return ERR_PTR(-EIO); 3011c8ba6d0SMarcel Holtmann } 3021c8ba6d0SMarcel Holtmann 3031c8ba6d0SMarcel Holtmann return skb; 3041c8ba6d0SMarcel Holtmann } 3051c8ba6d0SMarcel Holtmann 3064284ecbeSMarcel Holtmann static struct sk_buff *btbcm_read_controller_features(struct hci_dev *hdev) 3074284ecbeSMarcel Holtmann { 3084284ecbeSMarcel Holtmann struct sk_buff *skb; 3094284ecbeSMarcel Holtmann 3104284ecbeSMarcel Holtmann skb = __hci_cmd_sync(hdev, 0xfc6e, 0, NULL, HCI_INIT_TIMEOUT); 3114284ecbeSMarcel Holtmann if (IS_ERR(skb)) { 3122064ee33SMarcel Holtmann bt_dev_err(hdev, "BCM: Read controller features failed (%ld)", 3132064ee33SMarcel Holtmann PTR_ERR(skb)); 3144284ecbeSMarcel Holtmann return skb; 3154284ecbeSMarcel Holtmann } 3164284ecbeSMarcel Holtmann 3174284ecbeSMarcel Holtmann if (skb->len != 9) { 3182064ee33SMarcel Holtmann bt_dev_err(hdev, "BCM: Controller features length mismatch"); 3194284ecbeSMarcel Holtmann kfree_skb(skb); 3204284ecbeSMarcel Holtmann return ERR_PTR(-EIO); 3214284ecbeSMarcel Holtmann } 3224284ecbeSMarcel Holtmann 3234284ecbeSMarcel Holtmann return skb; 3244284ecbeSMarcel Holtmann } 3254284ecbeSMarcel Holtmann 3261c8ba6d0SMarcel Holtmann static struct sk_buff *btbcm_read_usb_product(struct hci_dev *hdev) 3271c8ba6d0SMarcel Holtmann { 3281c8ba6d0SMarcel Holtmann struct sk_buff *skb; 3291c8ba6d0SMarcel Holtmann 3301c8ba6d0SMarcel Holtmann skb = __hci_cmd_sync(hdev, 0xfc5a, 0, NULL, HCI_INIT_TIMEOUT); 3311c8ba6d0SMarcel Holtmann if (IS_ERR(skb)) { 3322064ee33SMarcel Holtmann bt_dev_err(hdev, "BCM: Read USB product info failed (%ld)", 3332064ee33SMarcel Holtmann PTR_ERR(skb)); 3341c8ba6d0SMarcel Holtmann return skb; 3351c8ba6d0SMarcel Holtmann } 3361c8ba6d0SMarcel Holtmann 3371c8ba6d0SMarcel Holtmann if (skb->len != 5) { 3382064ee33SMarcel Holtmann bt_dev_err(hdev, "BCM: USB product length mismatch"); 3391c8ba6d0SMarcel Holtmann kfree_skb(skb); 3401c8ba6d0SMarcel Holtmann return ERR_PTR(-EIO); 3411c8ba6d0SMarcel Holtmann } 3421c8ba6d0SMarcel Holtmann 3431c8ba6d0SMarcel Holtmann return skb; 3441c8ba6d0SMarcel Holtmann } 3451c8ba6d0SMarcel Holtmann 346e76dc1ddSMarcel Holtmann static int btbcm_read_info(struct hci_dev *hdev) 347e76dc1ddSMarcel Holtmann { 348e76dc1ddSMarcel Holtmann struct sk_buff *skb; 349e76dc1ddSMarcel Holtmann 350e76dc1ddSMarcel Holtmann /* Read Verbose Config Version Info */ 351e76dc1ddSMarcel Holtmann skb = btbcm_read_verbose_config(hdev); 352e76dc1ddSMarcel Holtmann if (IS_ERR(skb)) 353e76dc1ddSMarcel Holtmann return PTR_ERR(skb); 354e76dc1ddSMarcel Holtmann 3552064ee33SMarcel Holtmann bt_dev_info(hdev, "BCM: chip id %u", skb->data[1]); 356e76dc1ddSMarcel Holtmann kfree_skb(skb); 357e76dc1ddSMarcel Holtmann 358e76dc1ddSMarcel Holtmann /* Read Controller Features */ 359e76dc1ddSMarcel Holtmann skb = btbcm_read_controller_features(hdev); 360e76dc1ddSMarcel Holtmann if (IS_ERR(skb)) 361e76dc1ddSMarcel Holtmann return PTR_ERR(skb); 362e76dc1ddSMarcel Holtmann 3632064ee33SMarcel Holtmann bt_dev_info(hdev, "BCM: features 0x%2.2x", skb->data[1]); 364e76dc1ddSMarcel Holtmann kfree_skb(skb); 365e76dc1ddSMarcel Holtmann 3662fcdd562SHans de Goede return 0; 3672fcdd562SHans de Goede } 3682fcdd562SHans de Goede 3692fcdd562SHans de Goede static int btbcm_print_local_name(struct hci_dev *hdev) 3702fcdd562SHans de Goede { 3712fcdd562SHans de Goede struct sk_buff *skb; 3722fcdd562SHans de Goede 373e76dc1ddSMarcel Holtmann /* Read Local Name */ 374e76dc1ddSMarcel Holtmann skb = btbcm_read_local_name(hdev); 375e76dc1ddSMarcel Holtmann if (IS_ERR(skb)) 376e76dc1ddSMarcel Holtmann return PTR_ERR(skb); 377e76dc1ddSMarcel Holtmann 3782064ee33SMarcel Holtmann bt_dev_info(hdev, "%s", (char *)(skb->data + 1)); 379e76dc1ddSMarcel Holtmann kfree_skb(skb); 380e76dc1ddSMarcel Holtmann 381e76dc1ddSMarcel Holtmann return 0; 382e76dc1ddSMarcel Holtmann } 383e76dc1ddSMarcel Holtmann 384f7328381SHans de Goede struct bcm_subver_table { 3851c8ba6d0SMarcel Holtmann u16 subver; 3861c8ba6d0SMarcel Holtmann const char *name; 387f7328381SHans de Goede }; 388f7328381SHans de Goede 389f7328381SHans de Goede static const struct bcm_subver_table bcm_uart_subver_table[] = { 390*192aa65aSAngus Ainslie { 0x1111, "BCM4362A2" }, /* 000.017.017 */ 3914a546ec3SFrederic Danis { 0x4103, "BCM4330B1" }, /* 002.001.003 */ 392b8dc6476SStephan Gerhold { 0x410d, "BCM4334B0" }, /* 002.001.013 */ 3939a0bb57dSMarcel Holtmann { 0x410e, "BCM43341B0" }, /* 002.001.014 */ 394039287aaSStephan Gerhold { 0x4204, "BCM2076B1" }, /* 002.002.004 */ 395a8f3b941SFrederic Danis { 0x4406, "BCM4324B3" }, /* 002.004.006 */ 396c03ee9afSHans de Goede { 0x4606, "BCM4324B5" }, /* 002.006.006 */ 397a357ea09SChristian Hewitt { 0x6109, "BCM4335C0" }, /* 003.001.009 */ 39840db5f0eSIlya Faenson { 0x610c, "BCM4354" }, /* 003.001.012 */ 399d456f678SJörg Krause { 0x2122, "BCM4343A0" }, /* 001.001.034 */ 400feb16722SIan Molton { 0x2209, "BCM43430A1" }, /* 001.002.009 */ 40118a39b9aSIan W MORRISON { 0x6119, "BCM4345C0" }, /* 003.001.025 */ 40252c8c7a7SOndrej Jirman { 0x6606, "BCM4345C5" }, /* 003.006.006 */ 403b133e0c4SHans de Goede { 0x230f, "BCM4356A2" }, /* 001.003.015 */ 40492ffe0dbSMaxime Ripard { 0x220e, "BCM20702A1" }, /* 001.002.014 */ 405e3ca60d0SPaweł Chmiel { 0x4217, "BCM4329B1" }, /* 002.002.023 */ 406f4d297eeSNeil Armstrong { 0x6106, "BCM4359C0" }, /* 003.001.006 */ 4071199ab4cSMohammad Rasim { 0x4106, "BCM4335A0" }, /* 002.001.006 */ 40827f4d1f2SMikhail Rudenko { 0x410c, "BCM43430B0" }, /* 002.001.012 */ 4099a0bb57dSMarcel Holtmann { } 4109a0bb57dSMarcel Holtmann }; 4119a0bb57dSMarcel Holtmann 412fec0de23SHans de Goede static const struct bcm_subver_table bcm_usb_subver_table[] = { 413c03ee9afSHans de Goede { 0x2105, "BCM20703A1" }, /* 001.001.005 */ 414fec0de23SHans de Goede { 0x210b, "BCM43142A0" }, /* 001.001.011 */ 415fec0de23SHans de Goede { 0x2112, "BCM4314A0" }, /* 001.001.018 */ 416fec0de23SHans de Goede { 0x2118, "BCM20702A0" }, /* 001.001.024 */ 417fec0de23SHans de Goede { 0x2126, "BCM4335A0" }, /* 001.001.038 */ 418fec0de23SHans de Goede { 0x220e, "BCM20702A1" }, /* 001.002.014 */ 419bf0ddd10SAzamat H. Hackimov { 0x230f, "BCM4356A2" }, /* 001.003.015 */ 420fec0de23SHans de Goede { 0x4106, "BCM4335B0" }, /* 002.001.006 */ 421fec0de23SHans de Goede { 0x410e, "BCM20702B0" }, /* 002.001.014 */ 422fec0de23SHans de Goede { 0x6109, "BCM4335C0" }, /* 003.001.009 */ 423fec0de23SHans de Goede { 0x610c, "BCM4354" }, /* 003.001.012 */ 424bf0ddd10SAzamat H. Hackimov { 0x6607, "BCM4350C5" }, /* 003.006.007 */ 425fec0de23SHans de Goede { } 426fec0de23SHans de Goede }; 427fec0de23SHans de Goede 4280287c5d8SHans de Goede int btbcm_initialize(struct hci_dev *hdev, bool *fw_load_done) 42975e167e6SFrederic Danis { 430fec0de23SHans de Goede u16 subver, rev, pid, vid; 43175e167e6SFrederic Danis struct sk_buff *skb; 43275e167e6SFrederic Danis struct hci_rp_read_local_version *ver; 433fec0de23SHans de Goede const struct bcm_subver_table *bcm_subver_table; 43474530a63SHans de Goede const char *hw_name = NULL; 43574530a63SHans de Goede char postfix[16] = ""; 43674530a63SHans de Goede int fw_name_count = 0; 43774530a63SHans de Goede bcm_fw_name *fw_name; 4380287c5d8SHans de Goede const struct firmware *fw; 43975e167e6SFrederic Danis int i, err; 44075e167e6SFrederic Danis 44175e167e6SFrederic Danis /* Reset */ 44275e167e6SFrederic Danis err = btbcm_reset(hdev); 44375e167e6SFrederic Danis if (err) 44475e167e6SFrederic Danis return err; 44575e167e6SFrederic Danis 44675e167e6SFrederic Danis /* Read Local Version Info */ 44775e167e6SFrederic Danis skb = btbcm_read_local_version(hdev); 44875e167e6SFrederic Danis if (IS_ERR(skb)) 44975e167e6SFrederic Danis return PTR_ERR(skb); 45075e167e6SFrederic Danis 45175e167e6SFrederic Danis ver = (struct hci_rp_read_local_version *)skb->data; 45275e167e6SFrederic Danis rev = le16_to_cpu(ver->hci_rev); 45375e167e6SFrederic Danis subver = le16_to_cpu(ver->lmp_subver); 45475e167e6SFrederic Danis kfree_skb(skb); 45575e167e6SFrederic Danis 456e76dc1ddSMarcel Holtmann /* Read controller information */ 4570287c5d8SHans de Goede if (!(*fw_load_done)) { 458e76dc1ddSMarcel Holtmann err = btbcm_read_info(hdev); 459e76dc1ddSMarcel Holtmann if (err) 460e76dc1ddSMarcel Holtmann return err; 46122ac1916SHans de Goede } 4622fcdd562SHans de Goede err = btbcm_print_local_name(hdev); 4632fcdd562SHans de Goede if (err) 4642fcdd562SHans de Goede return err; 46575e167e6SFrederic Danis 466fec0de23SHans de Goede bcm_subver_table = (hdev->bus == HCI_USB) ? bcm_usb_subver_table : 467fec0de23SHans de Goede bcm_uart_subver_table; 468fec0de23SHans de Goede 469fec0de23SHans de Goede for (i = 0; bcm_subver_table[i].name; i++) { 470fec0de23SHans de Goede if (subver == bcm_subver_table[i].subver) { 471fec0de23SHans de Goede hw_name = bcm_subver_table[i].name; 47275e167e6SFrederic Danis break; 47375e167e6SFrederic Danis } 47475e167e6SFrederic Danis } 47575e167e6SFrederic Danis 476f53b975cSHans de Goede bt_dev_info(hdev, "%s (%3.3u.%3.3u.%3.3u) build %4.4u", 47774530a63SHans de Goede hw_name ? hw_name : "BCM", (subver & 0xe000) >> 13, 478f53b975cSHans de Goede (subver & 0x1f00) >> 8, (subver & 0x00ff), rev & 0x0fff); 479f53b975cSHans de Goede 480f53b975cSHans de Goede if (*fw_load_done) 481f53b975cSHans de Goede return 0; 482f53b975cSHans de Goede 483fec0de23SHans de Goede if (hdev->bus == HCI_USB) { 484fec0de23SHans de Goede /* Read USB Product Info */ 485fec0de23SHans de Goede skb = btbcm_read_usb_product(hdev); 486fec0de23SHans de Goede if (IS_ERR(skb)) 487fec0de23SHans de Goede return PTR_ERR(skb); 488fec0de23SHans de Goede 489fec0de23SHans de Goede vid = get_unaligned_le16(skb->data + 1); 490fec0de23SHans de Goede pid = get_unaligned_le16(skb->data + 3); 491fec0de23SHans de Goede kfree_skb(skb); 492fec0de23SHans de Goede 49374530a63SHans de Goede snprintf(postfix, sizeof(postfix), "-%4.4x-%4.4x", vid, pid); 49475e167e6SFrederic Danis } 49575e167e6SFrederic Danis 49674530a63SHans de Goede fw_name = kmalloc(BCM_FW_NAME_COUNT_MAX * BCM_FW_NAME_LEN, GFP_KERNEL); 49774530a63SHans de Goede if (!fw_name) 49874530a63SHans de Goede return -ENOMEM; 49974530a63SHans de Goede 50074530a63SHans de Goede if (hw_name) { 50174530a63SHans de Goede snprintf(fw_name[fw_name_count], BCM_FW_NAME_LEN, 50274530a63SHans de Goede "brcm/%s%s.hcd", hw_name, postfix); 50374530a63SHans de Goede fw_name_count++; 5040287c5d8SHans de Goede } 5050287c5d8SHans de Goede 50674530a63SHans de Goede snprintf(fw_name[fw_name_count], BCM_FW_NAME_LEN, 50774530a63SHans de Goede "brcm/BCM%s.hcd", postfix); 50874530a63SHans de Goede fw_name_count++; 50974530a63SHans de Goede 51074530a63SHans de Goede for (i = 0; i < fw_name_count; i++) { 51174530a63SHans de Goede err = firmware_request_nowarn(&fw, fw_name[i], &hdev->dev); 51274530a63SHans de Goede if (err == 0) { 51374530a63SHans de Goede bt_dev_info(hdev, "%s '%s' Patch", 51474530a63SHans de Goede hw_name ? hw_name : "BCM", fw_name[i]); 51574530a63SHans de Goede *fw_load_done = true; 51674530a63SHans de Goede break; 51774530a63SHans de Goede } 51874530a63SHans de Goede } 51974530a63SHans de Goede 52074530a63SHans de Goede if (*fw_load_done) { 5210287c5d8SHans de Goede err = btbcm_patchram(hdev, fw); 5220287c5d8SHans de Goede if (err) 5230287c5d8SHans de Goede bt_dev_info(hdev, "BCM: Patch failed (%d)", err); 5240287c5d8SHans de Goede 5250287c5d8SHans de Goede release_firmware(fw); 52674530a63SHans de Goede } else { 52774530a63SHans de Goede bt_dev_err(hdev, "BCM: firmware Patch file not found, tried:"); 52874530a63SHans de Goede for (i = 0; i < fw_name_count; i++) 52974530a63SHans de Goede bt_dev_err(hdev, "BCM: '%s'", fw_name[i]); 53074530a63SHans de Goede } 53174530a63SHans de Goede 53274530a63SHans de Goede kfree(fw_name); 53375e167e6SFrederic Danis return 0; 53475e167e6SFrederic Danis } 53575e167e6SFrederic Danis EXPORT_SYMBOL_GPL(btbcm_initialize); 53675e167e6SFrederic Danis 5370383f16aSHans de Goede int btbcm_finalize(struct hci_dev *hdev, bool *fw_load_done) 53875e167e6SFrederic Danis { 53975e167e6SFrederic Danis int err; 54075e167e6SFrederic Danis 5410383f16aSHans de Goede /* Re-initialize if necessary */ 5420383f16aSHans de Goede if (*fw_load_done) { 5430383f16aSHans de Goede err = btbcm_initialize(hdev, fw_load_done); 54475e167e6SFrederic Danis if (err) 54575e167e6SFrederic Danis return err; 5460383f16aSHans de Goede } 54775e167e6SFrederic Danis 54875e167e6SFrederic Danis btbcm_check_bdaddr(hdev); 54975e167e6SFrederic Danis 55075e167e6SFrederic Danis set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks); 55175e167e6SFrederic Danis 55275e167e6SFrederic Danis return 0; 55375e167e6SFrederic Danis } 55475e167e6SFrederic Danis EXPORT_SYMBOL_GPL(btbcm_finalize); 55575e167e6SFrederic Danis 5561c8ba6d0SMarcel Holtmann int btbcm_setup_patchram(struct hci_dev *hdev) 5571c8ba6d0SMarcel Holtmann { 5580287c5d8SHans de Goede bool fw_load_done = false; 55959ce5699SHans de Goede int err; 5601c8ba6d0SMarcel Holtmann 56159ce5699SHans de Goede /* Initialize */ 5620287c5d8SHans de Goede err = btbcm_initialize(hdev, &fw_load_done); 5631c8ba6d0SMarcel Holtmann if (err) 5641c8ba6d0SMarcel Holtmann return err; 5651c8ba6d0SMarcel Holtmann 5660287c5d8SHans de Goede /* Re-initialize after loading Patch */ 5670383f16aSHans de Goede return btbcm_finalize(hdev, &fw_load_done); 5681c8ba6d0SMarcel Holtmann } 5691c8ba6d0SMarcel Holtmann EXPORT_SYMBOL_GPL(btbcm_setup_patchram); 5701c8ba6d0SMarcel Holtmann 5711c8ba6d0SMarcel Holtmann int btbcm_setup_apple(struct hci_dev *hdev) 5721c8ba6d0SMarcel Holtmann { 5731c8ba6d0SMarcel Holtmann struct sk_buff *skb; 574b224d3ffSMarcel Holtmann int err; 575b224d3ffSMarcel Holtmann 576b224d3ffSMarcel Holtmann /* Reset */ 577b224d3ffSMarcel Holtmann err = btbcm_reset(hdev); 578b224d3ffSMarcel Holtmann if (err) 579b224d3ffSMarcel Holtmann return err; 5801c8ba6d0SMarcel Holtmann 5811c8ba6d0SMarcel Holtmann /* Read Verbose Config Version Info */ 5821c8ba6d0SMarcel Holtmann skb = btbcm_read_verbose_config(hdev); 5837bee8b08SChris Mason if (!IS_ERR(skb)) { 5842064ee33SMarcel Holtmann bt_dev_info(hdev, "BCM: chip id %u build %4.4u", 585b224d3ffSMarcel Holtmann skb->data[1], get_unaligned_le16(skb->data + 5)); 5861c8ba6d0SMarcel Holtmann kfree_skb(skb); 5877bee8b08SChris Mason } 5881c8ba6d0SMarcel Holtmann 58934cea41eSMarcel Holtmann /* Read USB Product Info */ 59034cea41eSMarcel Holtmann skb = btbcm_read_usb_product(hdev); 59134cea41eSMarcel Holtmann if (!IS_ERR(skb)) { 5922064ee33SMarcel Holtmann bt_dev_info(hdev, "BCM: product %4.4x:%4.4x", 59334cea41eSMarcel Holtmann get_unaligned_le16(skb->data + 1), 59434cea41eSMarcel Holtmann get_unaligned_le16(skb->data + 3)); 59534cea41eSMarcel Holtmann kfree_skb(skb); 59634cea41eSMarcel Holtmann } 59734cea41eSMarcel Holtmann 5984284ecbeSMarcel Holtmann /* Read Controller Features */ 5994284ecbeSMarcel Holtmann skb = btbcm_read_controller_features(hdev); 6004284ecbeSMarcel Holtmann if (!IS_ERR(skb)) { 6012064ee33SMarcel Holtmann bt_dev_info(hdev, "BCM: features 0x%2.2x", skb->data[1]); 6024284ecbeSMarcel Holtmann kfree_skb(skb); 6034284ecbeSMarcel Holtmann } 6044284ecbeSMarcel Holtmann 6059bc63ca0SMarcel Holtmann /* Read Local Name */ 6069bc63ca0SMarcel Holtmann skb = btbcm_read_local_name(hdev); 6079bc63ca0SMarcel Holtmann if (!IS_ERR(skb)) { 6082064ee33SMarcel Holtmann bt_dev_info(hdev, "%s", (char *)(skb->data + 1)); 6099bc63ca0SMarcel Holtmann kfree_skb(skb); 6109bc63ca0SMarcel Holtmann } 6119bc63ca0SMarcel Holtmann 612941521e2SMarcel Holtmann set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks); 613941521e2SMarcel Holtmann 6141c8ba6d0SMarcel Holtmann return 0; 6151c8ba6d0SMarcel Holtmann } 6161c8ba6d0SMarcel Holtmann EXPORT_SYMBOL_GPL(btbcm_setup_apple); 6171c8ba6d0SMarcel Holtmann 6184fba30f0SMarcel Holtmann MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); 6194fba30f0SMarcel Holtmann MODULE_DESCRIPTION("Bluetooth support for Broadcom devices ver " VERSION); 6204fba30f0SMarcel Holtmann MODULE_VERSION(VERSION); 6214fba30f0SMarcel Holtmann MODULE_LICENSE("GPL"); 622