xref: /openbmc/linux/drivers/bluetooth/btbcm.c (revision 192aa65a)
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