162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci *  Bluetooth support for Intel devices
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci *  Copyright (C) 2015  Intel Corporation
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/module.h>
1062306a36Sopenharmony_ci#include <linux/firmware.h>
1162306a36Sopenharmony_ci#include <linux/regmap.h>
1262306a36Sopenharmony_ci#include <linux/acpi.h>
1362306a36Sopenharmony_ci#include <acpi/acpi_bus.h>
1462306a36Sopenharmony_ci#include <asm/unaligned.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include <net/bluetooth/bluetooth.h>
1762306a36Sopenharmony_ci#include <net/bluetooth/hci_core.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include "btintel.h"
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#define VERSION "0.1"
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#define BDADDR_INTEL		(&(bdaddr_t){{0x00, 0x8b, 0x9e, 0x19, 0x03, 0x00}})
2462306a36Sopenharmony_ci#define RSA_HEADER_LEN		644
2562306a36Sopenharmony_ci#define CSS_HEADER_OFFSET	8
2662306a36Sopenharmony_ci#define ECDSA_OFFSET		644
2762306a36Sopenharmony_ci#define ECDSA_HEADER_LEN	320
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#define BTINTEL_PPAG_NAME   "PPAG"
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cienum {
3262306a36Sopenharmony_ci	DSM_SET_WDISABLE2_DELAY = 1,
3362306a36Sopenharmony_ci	DSM_SET_RESET_METHOD = 3,
3462306a36Sopenharmony_ci};
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci/* structure to store the PPAG data read from ACPI table */
3762306a36Sopenharmony_cistruct btintel_ppag {
3862306a36Sopenharmony_ci	u32	domain;
3962306a36Sopenharmony_ci	u32     mode;
4062306a36Sopenharmony_ci	acpi_status status;
4162306a36Sopenharmony_ci	struct hci_dev *hdev;
4262306a36Sopenharmony_ci};
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci#define CMD_WRITE_BOOT_PARAMS	0xfc0e
4562306a36Sopenharmony_cistruct cmd_write_boot_params {
4662306a36Sopenharmony_ci	__le32 boot_addr;
4762306a36Sopenharmony_ci	u8  fw_build_num;
4862306a36Sopenharmony_ci	u8  fw_build_ww;
4962306a36Sopenharmony_ci	u8  fw_build_yy;
5062306a36Sopenharmony_ci} __packed;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistatic struct {
5362306a36Sopenharmony_ci	const char *driver_name;
5462306a36Sopenharmony_ci	u8         hw_variant;
5562306a36Sopenharmony_ci	u32        fw_build_num;
5662306a36Sopenharmony_ci} coredump_info;
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_cistatic const guid_t btintel_guid_dsm =
5962306a36Sopenharmony_ci	GUID_INIT(0xaa10f4e0, 0x81ac, 0x4233,
6062306a36Sopenharmony_ci		  0xab, 0xf6, 0x3b, 0x2a, 0xc5, 0x0e, 0x28, 0xd9);
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ciint btintel_check_bdaddr(struct hci_dev *hdev)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	struct hci_rp_read_bd_addr *bda;
6562306a36Sopenharmony_ci	struct sk_buff *skb;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	skb = __hci_cmd_sync(hdev, HCI_OP_READ_BD_ADDR, 0, NULL,
6862306a36Sopenharmony_ci			     HCI_INIT_TIMEOUT);
6962306a36Sopenharmony_ci	if (IS_ERR(skb)) {
7062306a36Sopenharmony_ci		int err = PTR_ERR(skb);
7162306a36Sopenharmony_ci		bt_dev_err(hdev, "Reading Intel device address failed (%d)",
7262306a36Sopenharmony_ci			   err);
7362306a36Sopenharmony_ci		return err;
7462306a36Sopenharmony_ci	}
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	if (skb->len != sizeof(*bda)) {
7762306a36Sopenharmony_ci		bt_dev_err(hdev, "Intel device address length mismatch");
7862306a36Sopenharmony_ci		kfree_skb(skb);
7962306a36Sopenharmony_ci		return -EIO;
8062306a36Sopenharmony_ci	}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	bda = (struct hci_rp_read_bd_addr *)skb->data;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	/* For some Intel based controllers, the default Bluetooth device
8562306a36Sopenharmony_ci	 * address 00:03:19:9E:8B:00 can be found. These controllers are
8662306a36Sopenharmony_ci	 * fully operational, but have the danger of duplicate addresses
8762306a36Sopenharmony_ci	 * and that in turn can cause problems with Bluetooth operation.
8862306a36Sopenharmony_ci	 */
8962306a36Sopenharmony_ci	if (!bacmp(&bda->bdaddr, BDADDR_INTEL)) {
9062306a36Sopenharmony_ci		bt_dev_err(hdev, "Found Intel default device address (%pMR)",
9162306a36Sopenharmony_ci			   &bda->bdaddr);
9262306a36Sopenharmony_ci		set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks);
9362306a36Sopenharmony_ci	}
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	kfree_skb(skb);
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	return 0;
9862306a36Sopenharmony_ci}
9962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(btintel_check_bdaddr);
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ciint btintel_enter_mfg(struct hci_dev *hdev)
10262306a36Sopenharmony_ci{
10362306a36Sopenharmony_ci	static const u8 param[] = { 0x01, 0x00 };
10462306a36Sopenharmony_ci	struct sk_buff *skb;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	skb = __hci_cmd_sync(hdev, 0xfc11, 2, param, HCI_CMD_TIMEOUT);
10762306a36Sopenharmony_ci	if (IS_ERR(skb)) {
10862306a36Sopenharmony_ci		bt_dev_err(hdev, "Entering manufacturer mode failed (%ld)",
10962306a36Sopenharmony_ci			   PTR_ERR(skb));
11062306a36Sopenharmony_ci		return PTR_ERR(skb);
11162306a36Sopenharmony_ci	}
11262306a36Sopenharmony_ci	kfree_skb(skb);
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	return 0;
11562306a36Sopenharmony_ci}
11662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(btintel_enter_mfg);
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ciint btintel_exit_mfg(struct hci_dev *hdev, bool reset, bool patched)
11962306a36Sopenharmony_ci{
12062306a36Sopenharmony_ci	u8 param[] = { 0x00, 0x00 };
12162306a36Sopenharmony_ci	struct sk_buff *skb;
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	/* The 2nd command parameter specifies the manufacturing exit method:
12462306a36Sopenharmony_ci	 * 0x00: Just disable the manufacturing mode (0x00).
12562306a36Sopenharmony_ci	 * 0x01: Disable manufacturing mode and reset with patches deactivated.
12662306a36Sopenharmony_ci	 * 0x02: Disable manufacturing mode and reset with patches activated.
12762306a36Sopenharmony_ci	 */
12862306a36Sopenharmony_ci	if (reset)
12962306a36Sopenharmony_ci		param[1] |= patched ? 0x02 : 0x01;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	skb = __hci_cmd_sync(hdev, 0xfc11, 2, param, HCI_CMD_TIMEOUT);
13262306a36Sopenharmony_ci	if (IS_ERR(skb)) {
13362306a36Sopenharmony_ci		bt_dev_err(hdev, "Exiting manufacturer mode failed (%ld)",
13462306a36Sopenharmony_ci			   PTR_ERR(skb));
13562306a36Sopenharmony_ci		return PTR_ERR(skb);
13662306a36Sopenharmony_ci	}
13762306a36Sopenharmony_ci	kfree_skb(skb);
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	return 0;
14062306a36Sopenharmony_ci}
14162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(btintel_exit_mfg);
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ciint btintel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)
14462306a36Sopenharmony_ci{
14562306a36Sopenharmony_ci	struct sk_buff *skb;
14662306a36Sopenharmony_ci	int err;
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	skb = __hci_cmd_sync(hdev, 0xfc31, 6, bdaddr, HCI_INIT_TIMEOUT);
14962306a36Sopenharmony_ci	if (IS_ERR(skb)) {
15062306a36Sopenharmony_ci		err = PTR_ERR(skb);
15162306a36Sopenharmony_ci		bt_dev_err(hdev, "Changing Intel device address failed (%d)",
15262306a36Sopenharmony_ci			   err);
15362306a36Sopenharmony_ci		return err;
15462306a36Sopenharmony_ci	}
15562306a36Sopenharmony_ci	kfree_skb(skb);
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	return 0;
15862306a36Sopenharmony_ci}
15962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(btintel_set_bdaddr);
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_cistatic int btintel_set_event_mask(struct hci_dev *hdev, bool debug)
16262306a36Sopenharmony_ci{
16362306a36Sopenharmony_ci	u8 mask[8] = { 0x87, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
16462306a36Sopenharmony_ci	struct sk_buff *skb;
16562306a36Sopenharmony_ci	int err;
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	if (debug)
16862306a36Sopenharmony_ci		mask[1] |= 0x62;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	skb = __hci_cmd_sync(hdev, 0xfc52, 8, mask, HCI_INIT_TIMEOUT);
17162306a36Sopenharmony_ci	if (IS_ERR(skb)) {
17262306a36Sopenharmony_ci		err = PTR_ERR(skb);
17362306a36Sopenharmony_ci		bt_dev_err(hdev, "Setting Intel event mask failed (%d)", err);
17462306a36Sopenharmony_ci		return err;
17562306a36Sopenharmony_ci	}
17662306a36Sopenharmony_ci	kfree_skb(skb);
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	return 0;
17962306a36Sopenharmony_ci}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ciint btintel_set_diag(struct hci_dev *hdev, bool enable)
18262306a36Sopenharmony_ci{
18362306a36Sopenharmony_ci	struct sk_buff *skb;
18462306a36Sopenharmony_ci	u8 param[3];
18562306a36Sopenharmony_ci	int err;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	if (enable) {
18862306a36Sopenharmony_ci		param[0] = 0x03;
18962306a36Sopenharmony_ci		param[1] = 0x03;
19062306a36Sopenharmony_ci		param[2] = 0x03;
19162306a36Sopenharmony_ci	} else {
19262306a36Sopenharmony_ci		param[0] = 0x00;
19362306a36Sopenharmony_ci		param[1] = 0x00;
19462306a36Sopenharmony_ci		param[2] = 0x00;
19562306a36Sopenharmony_ci	}
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	skb = __hci_cmd_sync(hdev, 0xfc43, 3, param, HCI_INIT_TIMEOUT);
19862306a36Sopenharmony_ci	if (IS_ERR(skb)) {
19962306a36Sopenharmony_ci		err = PTR_ERR(skb);
20062306a36Sopenharmony_ci		if (err == -ENODATA)
20162306a36Sopenharmony_ci			goto done;
20262306a36Sopenharmony_ci		bt_dev_err(hdev, "Changing Intel diagnostic mode failed (%d)",
20362306a36Sopenharmony_ci			   err);
20462306a36Sopenharmony_ci		return err;
20562306a36Sopenharmony_ci	}
20662306a36Sopenharmony_ci	kfree_skb(skb);
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_cidone:
20962306a36Sopenharmony_ci	btintel_set_event_mask(hdev, enable);
21062306a36Sopenharmony_ci	return 0;
21162306a36Sopenharmony_ci}
21262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(btintel_set_diag);
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_cistatic int btintel_set_diag_mfg(struct hci_dev *hdev, bool enable)
21562306a36Sopenharmony_ci{
21662306a36Sopenharmony_ci	int err, ret;
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	err = btintel_enter_mfg(hdev);
21962306a36Sopenharmony_ci	if (err)
22062306a36Sopenharmony_ci		return err;
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	ret = btintel_set_diag(hdev, enable);
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	err = btintel_exit_mfg(hdev, false, false);
22562306a36Sopenharmony_ci	if (err)
22662306a36Sopenharmony_ci		return err;
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	return ret;
22962306a36Sopenharmony_ci}
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_cistatic int btintel_set_diag_combined(struct hci_dev *hdev, bool enable)
23262306a36Sopenharmony_ci{
23362306a36Sopenharmony_ci	int ret;
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	/* Legacy ROM device needs to be in the manufacturer mode to apply
23662306a36Sopenharmony_ci	 * diagnostic setting
23762306a36Sopenharmony_ci	 *
23862306a36Sopenharmony_ci	 * This flag is set after reading the Intel version.
23962306a36Sopenharmony_ci	 */
24062306a36Sopenharmony_ci	if (btintel_test_flag(hdev, INTEL_ROM_LEGACY))
24162306a36Sopenharmony_ci		ret = btintel_set_diag_mfg(hdev, enable);
24262306a36Sopenharmony_ci	else
24362306a36Sopenharmony_ci		ret = btintel_set_diag(hdev, enable);
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	return ret;
24662306a36Sopenharmony_ci}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_cistatic void btintel_hw_error(struct hci_dev *hdev, u8 code)
24962306a36Sopenharmony_ci{
25062306a36Sopenharmony_ci	struct sk_buff *skb;
25162306a36Sopenharmony_ci	u8 type = 0x00;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	bt_dev_err(hdev, "Hardware error 0x%2.2x", code);
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
25662306a36Sopenharmony_ci	if (IS_ERR(skb)) {
25762306a36Sopenharmony_ci		bt_dev_err(hdev, "Reset after hardware error failed (%ld)",
25862306a36Sopenharmony_ci			   PTR_ERR(skb));
25962306a36Sopenharmony_ci		return;
26062306a36Sopenharmony_ci	}
26162306a36Sopenharmony_ci	kfree_skb(skb);
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	skb = __hci_cmd_sync(hdev, 0xfc22, 1, &type, HCI_INIT_TIMEOUT);
26462306a36Sopenharmony_ci	if (IS_ERR(skb)) {
26562306a36Sopenharmony_ci		bt_dev_err(hdev, "Retrieving Intel exception info failed (%ld)",
26662306a36Sopenharmony_ci			   PTR_ERR(skb));
26762306a36Sopenharmony_ci		return;
26862306a36Sopenharmony_ci	}
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	if (skb->len != 13) {
27162306a36Sopenharmony_ci		bt_dev_err(hdev, "Exception info size mismatch");
27262306a36Sopenharmony_ci		kfree_skb(skb);
27362306a36Sopenharmony_ci		return;
27462306a36Sopenharmony_ci	}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	bt_dev_err(hdev, "Exception info %s", (char *)(skb->data + 1));
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	kfree_skb(skb);
27962306a36Sopenharmony_ci}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ciint btintel_version_info(struct hci_dev *hdev, struct intel_version *ver)
28262306a36Sopenharmony_ci{
28362306a36Sopenharmony_ci	const char *variant;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	/* The hardware platform number has a fixed value of 0x37 and
28662306a36Sopenharmony_ci	 * for now only accept this single value.
28762306a36Sopenharmony_ci	 */
28862306a36Sopenharmony_ci	if (ver->hw_platform != 0x37) {
28962306a36Sopenharmony_ci		bt_dev_err(hdev, "Unsupported Intel hardware platform (%u)",
29062306a36Sopenharmony_ci			   ver->hw_platform);
29162306a36Sopenharmony_ci		return -EINVAL;
29262306a36Sopenharmony_ci	}
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	/* Check for supported iBT hardware variants of this firmware
29562306a36Sopenharmony_ci	 * loading method.
29662306a36Sopenharmony_ci	 *
29762306a36Sopenharmony_ci	 * This check has been put in place to ensure correct forward
29862306a36Sopenharmony_ci	 * compatibility options when newer hardware variants come along.
29962306a36Sopenharmony_ci	 */
30062306a36Sopenharmony_ci	switch (ver->hw_variant) {
30162306a36Sopenharmony_ci	case 0x07:	/* WP - Legacy ROM */
30262306a36Sopenharmony_ci	case 0x08:	/* StP - Legacy ROM */
30362306a36Sopenharmony_ci	case 0x0b:      /* SfP */
30462306a36Sopenharmony_ci	case 0x0c:      /* WsP */
30562306a36Sopenharmony_ci	case 0x11:      /* JfP */
30662306a36Sopenharmony_ci	case 0x12:      /* ThP */
30762306a36Sopenharmony_ci	case 0x13:      /* HrP */
30862306a36Sopenharmony_ci	case 0x14:      /* CcP */
30962306a36Sopenharmony_ci		break;
31062306a36Sopenharmony_ci	default:
31162306a36Sopenharmony_ci		bt_dev_err(hdev, "Unsupported Intel hardware variant (%u)",
31262306a36Sopenharmony_ci			   ver->hw_variant);
31362306a36Sopenharmony_ci		return -EINVAL;
31462306a36Sopenharmony_ci	}
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	switch (ver->fw_variant) {
31762306a36Sopenharmony_ci	case 0x01:
31862306a36Sopenharmony_ci		variant = "Legacy ROM 2.5";
31962306a36Sopenharmony_ci		break;
32062306a36Sopenharmony_ci	case 0x06:
32162306a36Sopenharmony_ci		variant = "Bootloader";
32262306a36Sopenharmony_ci		break;
32362306a36Sopenharmony_ci	case 0x22:
32462306a36Sopenharmony_ci		variant = "Legacy ROM 2.x";
32562306a36Sopenharmony_ci		break;
32662306a36Sopenharmony_ci	case 0x23:
32762306a36Sopenharmony_ci		variant = "Firmware";
32862306a36Sopenharmony_ci		break;
32962306a36Sopenharmony_ci	default:
33062306a36Sopenharmony_ci		bt_dev_err(hdev, "Unsupported firmware variant(%02x)", ver->fw_variant);
33162306a36Sopenharmony_ci		return -EINVAL;
33262306a36Sopenharmony_ci	}
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	coredump_info.hw_variant = ver->hw_variant;
33562306a36Sopenharmony_ci	coredump_info.fw_build_num = ver->fw_build_num;
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	bt_dev_info(hdev, "%s revision %u.%u build %u week %u %u",
33862306a36Sopenharmony_ci		    variant, ver->fw_revision >> 4, ver->fw_revision & 0x0f,
33962306a36Sopenharmony_ci		    ver->fw_build_num, ver->fw_build_ww,
34062306a36Sopenharmony_ci		    2000 + ver->fw_build_yy);
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	return 0;
34362306a36Sopenharmony_ci}
34462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(btintel_version_info);
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_cistatic int btintel_secure_send(struct hci_dev *hdev, u8 fragment_type, u32 plen,
34762306a36Sopenharmony_ci			       const void *param)
34862306a36Sopenharmony_ci{
34962306a36Sopenharmony_ci	while (plen > 0) {
35062306a36Sopenharmony_ci		struct sk_buff *skb;
35162306a36Sopenharmony_ci		u8 cmd_param[253], fragment_len = (plen > 252) ? 252 : plen;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci		cmd_param[0] = fragment_type;
35462306a36Sopenharmony_ci		memcpy(cmd_param + 1, param, fragment_len);
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci		skb = __hci_cmd_sync(hdev, 0xfc09, fragment_len + 1,
35762306a36Sopenharmony_ci				     cmd_param, HCI_INIT_TIMEOUT);
35862306a36Sopenharmony_ci		if (IS_ERR(skb))
35962306a36Sopenharmony_ci			return PTR_ERR(skb);
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci		kfree_skb(skb);
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci		plen -= fragment_len;
36462306a36Sopenharmony_ci		param += fragment_len;
36562306a36Sopenharmony_ci	}
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	return 0;
36862306a36Sopenharmony_ci}
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ciint btintel_load_ddc_config(struct hci_dev *hdev, const char *ddc_name)
37162306a36Sopenharmony_ci{
37262306a36Sopenharmony_ci	const struct firmware *fw;
37362306a36Sopenharmony_ci	struct sk_buff *skb;
37462306a36Sopenharmony_ci	const u8 *fw_ptr;
37562306a36Sopenharmony_ci	int err;
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	err = request_firmware_direct(&fw, ddc_name, &hdev->dev);
37862306a36Sopenharmony_ci	if (err < 0) {
37962306a36Sopenharmony_ci		bt_dev_err(hdev, "Failed to load Intel DDC file %s (%d)",
38062306a36Sopenharmony_ci			   ddc_name, err);
38162306a36Sopenharmony_ci		return err;
38262306a36Sopenharmony_ci	}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	bt_dev_info(hdev, "Found Intel DDC parameters: %s", ddc_name);
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	fw_ptr = fw->data;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	/* DDC file contains one or more DDC structure which has
38962306a36Sopenharmony_ci	 * Length (1 byte), DDC ID (2 bytes), and DDC value (Length - 2).
39062306a36Sopenharmony_ci	 */
39162306a36Sopenharmony_ci	while (fw->size > fw_ptr - fw->data) {
39262306a36Sopenharmony_ci		u8 cmd_plen = fw_ptr[0] + sizeof(u8);
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci		skb = __hci_cmd_sync(hdev, 0xfc8b, cmd_plen, fw_ptr,
39562306a36Sopenharmony_ci				     HCI_INIT_TIMEOUT);
39662306a36Sopenharmony_ci		if (IS_ERR(skb)) {
39762306a36Sopenharmony_ci			bt_dev_err(hdev, "Failed to send Intel_Write_DDC (%ld)",
39862306a36Sopenharmony_ci				   PTR_ERR(skb));
39962306a36Sopenharmony_ci			release_firmware(fw);
40062306a36Sopenharmony_ci			return PTR_ERR(skb);
40162306a36Sopenharmony_ci		}
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci		fw_ptr += cmd_plen;
40462306a36Sopenharmony_ci		kfree_skb(skb);
40562306a36Sopenharmony_ci	}
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	release_firmware(fw);
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	bt_dev_info(hdev, "Applying Intel DDC parameters completed");
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	return 0;
41262306a36Sopenharmony_ci}
41362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(btintel_load_ddc_config);
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ciint btintel_set_event_mask_mfg(struct hci_dev *hdev, bool debug)
41662306a36Sopenharmony_ci{
41762306a36Sopenharmony_ci	int err, ret;
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	err = btintel_enter_mfg(hdev);
42062306a36Sopenharmony_ci	if (err)
42162306a36Sopenharmony_ci		return err;
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	ret = btintel_set_event_mask(hdev, debug);
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	err = btintel_exit_mfg(hdev, false, false);
42662306a36Sopenharmony_ci	if (err)
42762306a36Sopenharmony_ci		return err;
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	return ret;
43062306a36Sopenharmony_ci}
43162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(btintel_set_event_mask_mfg);
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ciint btintel_read_version(struct hci_dev *hdev, struct intel_version *ver)
43462306a36Sopenharmony_ci{
43562306a36Sopenharmony_ci	struct sk_buff *skb;
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	skb = __hci_cmd_sync(hdev, 0xfc05, 0, NULL, HCI_CMD_TIMEOUT);
43862306a36Sopenharmony_ci	if (IS_ERR(skb)) {
43962306a36Sopenharmony_ci		bt_dev_err(hdev, "Reading Intel version information failed (%ld)",
44062306a36Sopenharmony_ci			   PTR_ERR(skb));
44162306a36Sopenharmony_ci		return PTR_ERR(skb);
44262306a36Sopenharmony_ci	}
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	if (skb->len != sizeof(*ver)) {
44562306a36Sopenharmony_ci		bt_dev_err(hdev, "Intel version event size mismatch");
44662306a36Sopenharmony_ci		kfree_skb(skb);
44762306a36Sopenharmony_ci		return -EILSEQ;
44862306a36Sopenharmony_ci	}
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	memcpy(ver, skb->data, sizeof(*ver));
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	kfree_skb(skb);
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	return 0;
45562306a36Sopenharmony_ci}
45662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(btintel_read_version);
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_cistatic int btintel_version_info_tlv(struct hci_dev *hdev,
45962306a36Sopenharmony_ci				    struct intel_version_tlv *version)
46062306a36Sopenharmony_ci{
46162306a36Sopenharmony_ci	const char *variant;
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	/* The hardware platform number has a fixed value of 0x37 and
46462306a36Sopenharmony_ci	 * for now only accept this single value.
46562306a36Sopenharmony_ci	 */
46662306a36Sopenharmony_ci	if (INTEL_HW_PLATFORM(version->cnvi_bt) != 0x37) {
46762306a36Sopenharmony_ci		bt_dev_err(hdev, "Unsupported Intel hardware platform (0x%2x)",
46862306a36Sopenharmony_ci			   INTEL_HW_PLATFORM(version->cnvi_bt));
46962306a36Sopenharmony_ci		return -EINVAL;
47062306a36Sopenharmony_ci	}
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	/* Check for supported iBT hardware variants of this firmware
47362306a36Sopenharmony_ci	 * loading method.
47462306a36Sopenharmony_ci	 *
47562306a36Sopenharmony_ci	 * This check has been put in place to ensure correct forward
47662306a36Sopenharmony_ci	 * compatibility options when newer hardware variants come along.
47762306a36Sopenharmony_ci	 */
47862306a36Sopenharmony_ci	switch (INTEL_HW_VARIANT(version->cnvi_bt)) {
47962306a36Sopenharmony_ci	case 0x17:	/* TyP */
48062306a36Sopenharmony_ci	case 0x18:	/* Slr */
48162306a36Sopenharmony_ci	case 0x19:	/* Slr-F */
48262306a36Sopenharmony_ci	case 0x1b:      /* Mgr */
48362306a36Sopenharmony_ci	case 0x1c:	/* Gale Peak (GaP) */
48462306a36Sopenharmony_ci		break;
48562306a36Sopenharmony_ci	default:
48662306a36Sopenharmony_ci		bt_dev_err(hdev, "Unsupported Intel hardware variant (0x%x)",
48762306a36Sopenharmony_ci			   INTEL_HW_VARIANT(version->cnvi_bt));
48862306a36Sopenharmony_ci		return -EINVAL;
48962306a36Sopenharmony_ci	}
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	switch (version->img_type) {
49262306a36Sopenharmony_ci	case 0x01:
49362306a36Sopenharmony_ci		variant = "Bootloader";
49462306a36Sopenharmony_ci		/* It is required that every single firmware fragment is acknowledged
49562306a36Sopenharmony_ci		 * with a command complete event. If the boot parameters indicate
49662306a36Sopenharmony_ci		 * that this bootloader does not send them, then abort the setup.
49762306a36Sopenharmony_ci		 */
49862306a36Sopenharmony_ci		if (version->limited_cce != 0x00) {
49962306a36Sopenharmony_ci			bt_dev_err(hdev, "Unsupported Intel firmware loading method (0x%x)",
50062306a36Sopenharmony_ci				   version->limited_cce);
50162306a36Sopenharmony_ci			return -EINVAL;
50262306a36Sopenharmony_ci		}
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci		/* Secure boot engine type should be either 1 (ECDSA) or 0 (RSA) */
50562306a36Sopenharmony_ci		if (version->sbe_type > 0x01) {
50662306a36Sopenharmony_ci			bt_dev_err(hdev, "Unsupported Intel secure boot engine type (0x%x)",
50762306a36Sopenharmony_ci				   version->sbe_type);
50862306a36Sopenharmony_ci			return -EINVAL;
50962306a36Sopenharmony_ci		}
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci		bt_dev_info(hdev, "Device revision is %u", version->dev_rev_id);
51262306a36Sopenharmony_ci		bt_dev_info(hdev, "Secure boot is %s",
51362306a36Sopenharmony_ci			    version->secure_boot ? "enabled" : "disabled");
51462306a36Sopenharmony_ci		bt_dev_info(hdev, "OTP lock is %s",
51562306a36Sopenharmony_ci			    version->otp_lock ? "enabled" : "disabled");
51662306a36Sopenharmony_ci		bt_dev_info(hdev, "API lock is %s",
51762306a36Sopenharmony_ci			    version->api_lock ? "enabled" : "disabled");
51862306a36Sopenharmony_ci		bt_dev_info(hdev, "Debug lock is %s",
51962306a36Sopenharmony_ci			    version->debug_lock ? "enabled" : "disabled");
52062306a36Sopenharmony_ci		bt_dev_info(hdev, "Minimum firmware build %u week %u %u",
52162306a36Sopenharmony_ci			    version->min_fw_build_nn, version->min_fw_build_cw,
52262306a36Sopenharmony_ci			    2000 + version->min_fw_build_yy);
52362306a36Sopenharmony_ci		break;
52462306a36Sopenharmony_ci	case 0x03:
52562306a36Sopenharmony_ci		variant = "Firmware";
52662306a36Sopenharmony_ci		break;
52762306a36Sopenharmony_ci	default:
52862306a36Sopenharmony_ci		bt_dev_err(hdev, "Unsupported image type(%02x)", version->img_type);
52962306a36Sopenharmony_ci		return -EINVAL;
53062306a36Sopenharmony_ci	}
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	coredump_info.hw_variant = INTEL_HW_VARIANT(version->cnvi_bt);
53362306a36Sopenharmony_ci	coredump_info.fw_build_num = version->build_num;
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	bt_dev_info(hdev, "%s timestamp %u.%u buildtype %u build %u", variant,
53662306a36Sopenharmony_ci		    2000 + (version->timestamp >> 8), version->timestamp & 0xff,
53762306a36Sopenharmony_ci		    version->build_type, version->build_num);
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	return 0;
54062306a36Sopenharmony_ci}
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_cistatic int btintel_parse_version_tlv(struct hci_dev *hdev,
54362306a36Sopenharmony_ci				     struct intel_version_tlv *version,
54462306a36Sopenharmony_ci				     struct sk_buff *skb)
54562306a36Sopenharmony_ci{
54662306a36Sopenharmony_ci	/* Consume Command Complete Status field */
54762306a36Sopenharmony_ci	skb_pull(skb, 1);
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	/* Event parameters contatin multiple TLVs. Read each of them
55062306a36Sopenharmony_ci	 * and only keep the required data. Also, it use existing legacy
55162306a36Sopenharmony_ci	 * version field like hw_platform, hw_variant, and fw_variant
55262306a36Sopenharmony_ci	 * to keep the existing setup flow
55362306a36Sopenharmony_ci	 */
55462306a36Sopenharmony_ci	while (skb->len) {
55562306a36Sopenharmony_ci		struct intel_tlv *tlv;
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci		/* Make sure skb has a minimum length of the header */
55862306a36Sopenharmony_ci		if (skb->len < sizeof(*tlv))
55962306a36Sopenharmony_ci			return -EINVAL;
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci		tlv = (struct intel_tlv *)skb->data;
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci		/* Make sure skb has a enough data */
56462306a36Sopenharmony_ci		if (skb->len < tlv->len + sizeof(*tlv))
56562306a36Sopenharmony_ci			return -EINVAL;
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci		switch (tlv->type) {
56862306a36Sopenharmony_ci		case INTEL_TLV_CNVI_TOP:
56962306a36Sopenharmony_ci			version->cnvi_top = get_unaligned_le32(tlv->val);
57062306a36Sopenharmony_ci			break;
57162306a36Sopenharmony_ci		case INTEL_TLV_CNVR_TOP:
57262306a36Sopenharmony_ci			version->cnvr_top = get_unaligned_le32(tlv->val);
57362306a36Sopenharmony_ci			break;
57462306a36Sopenharmony_ci		case INTEL_TLV_CNVI_BT:
57562306a36Sopenharmony_ci			version->cnvi_bt = get_unaligned_le32(tlv->val);
57662306a36Sopenharmony_ci			break;
57762306a36Sopenharmony_ci		case INTEL_TLV_CNVR_BT:
57862306a36Sopenharmony_ci			version->cnvr_bt = get_unaligned_le32(tlv->val);
57962306a36Sopenharmony_ci			break;
58062306a36Sopenharmony_ci		case INTEL_TLV_DEV_REV_ID:
58162306a36Sopenharmony_ci			version->dev_rev_id = get_unaligned_le16(tlv->val);
58262306a36Sopenharmony_ci			break;
58362306a36Sopenharmony_ci		case INTEL_TLV_IMAGE_TYPE:
58462306a36Sopenharmony_ci			version->img_type = tlv->val[0];
58562306a36Sopenharmony_ci			break;
58662306a36Sopenharmony_ci		case INTEL_TLV_TIME_STAMP:
58762306a36Sopenharmony_ci			/* If image type is Operational firmware (0x03), then
58862306a36Sopenharmony_ci			 * running FW Calendar Week and Year information can
58962306a36Sopenharmony_ci			 * be extracted from Timestamp information
59062306a36Sopenharmony_ci			 */
59162306a36Sopenharmony_ci			version->min_fw_build_cw = tlv->val[0];
59262306a36Sopenharmony_ci			version->min_fw_build_yy = tlv->val[1];
59362306a36Sopenharmony_ci			version->timestamp = get_unaligned_le16(tlv->val);
59462306a36Sopenharmony_ci			break;
59562306a36Sopenharmony_ci		case INTEL_TLV_BUILD_TYPE:
59662306a36Sopenharmony_ci			version->build_type = tlv->val[0];
59762306a36Sopenharmony_ci			break;
59862306a36Sopenharmony_ci		case INTEL_TLV_BUILD_NUM:
59962306a36Sopenharmony_ci			/* If image type is Operational firmware (0x03), then
60062306a36Sopenharmony_ci			 * running FW build number can be extracted from the
60162306a36Sopenharmony_ci			 * Build information
60262306a36Sopenharmony_ci			 */
60362306a36Sopenharmony_ci			version->min_fw_build_nn = tlv->val[0];
60462306a36Sopenharmony_ci			version->build_num = get_unaligned_le32(tlv->val);
60562306a36Sopenharmony_ci			break;
60662306a36Sopenharmony_ci		case INTEL_TLV_SECURE_BOOT:
60762306a36Sopenharmony_ci			version->secure_boot = tlv->val[0];
60862306a36Sopenharmony_ci			break;
60962306a36Sopenharmony_ci		case INTEL_TLV_OTP_LOCK:
61062306a36Sopenharmony_ci			version->otp_lock = tlv->val[0];
61162306a36Sopenharmony_ci			break;
61262306a36Sopenharmony_ci		case INTEL_TLV_API_LOCK:
61362306a36Sopenharmony_ci			version->api_lock = tlv->val[0];
61462306a36Sopenharmony_ci			break;
61562306a36Sopenharmony_ci		case INTEL_TLV_DEBUG_LOCK:
61662306a36Sopenharmony_ci			version->debug_lock = tlv->val[0];
61762306a36Sopenharmony_ci			break;
61862306a36Sopenharmony_ci		case INTEL_TLV_MIN_FW:
61962306a36Sopenharmony_ci			version->min_fw_build_nn = tlv->val[0];
62062306a36Sopenharmony_ci			version->min_fw_build_cw = tlv->val[1];
62162306a36Sopenharmony_ci			version->min_fw_build_yy = tlv->val[2];
62262306a36Sopenharmony_ci			break;
62362306a36Sopenharmony_ci		case INTEL_TLV_LIMITED_CCE:
62462306a36Sopenharmony_ci			version->limited_cce = tlv->val[0];
62562306a36Sopenharmony_ci			break;
62662306a36Sopenharmony_ci		case INTEL_TLV_SBE_TYPE:
62762306a36Sopenharmony_ci			version->sbe_type = tlv->val[0];
62862306a36Sopenharmony_ci			break;
62962306a36Sopenharmony_ci		case INTEL_TLV_OTP_BDADDR:
63062306a36Sopenharmony_ci			memcpy(&version->otp_bd_addr, tlv->val,
63162306a36Sopenharmony_ci							sizeof(bdaddr_t));
63262306a36Sopenharmony_ci			break;
63362306a36Sopenharmony_ci		default:
63462306a36Sopenharmony_ci			/* Ignore rest of information */
63562306a36Sopenharmony_ci			break;
63662306a36Sopenharmony_ci		}
63762306a36Sopenharmony_ci		/* consume the current tlv and move to next*/
63862306a36Sopenharmony_ci		skb_pull(skb, tlv->len + sizeof(*tlv));
63962306a36Sopenharmony_ci	}
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci	return 0;
64262306a36Sopenharmony_ci}
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_cistatic int btintel_read_version_tlv(struct hci_dev *hdev,
64562306a36Sopenharmony_ci				    struct intel_version_tlv *version)
64662306a36Sopenharmony_ci{
64762306a36Sopenharmony_ci	struct sk_buff *skb;
64862306a36Sopenharmony_ci	const u8 param[1] = { 0xFF };
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	if (!version)
65162306a36Sopenharmony_ci		return -EINVAL;
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	skb = __hci_cmd_sync(hdev, 0xfc05, 1, param, HCI_CMD_TIMEOUT);
65462306a36Sopenharmony_ci	if (IS_ERR(skb)) {
65562306a36Sopenharmony_ci		bt_dev_err(hdev, "Reading Intel version information failed (%ld)",
65662306a36Sopenharmony_ci			   PTR_ERR(skb));
65762306a36Sopenharmony_ci		return PTR_ERR(skb);
65862306a36Sopenharmony_ci	}
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	if (skb->data[0]) {
66162306a36Sopenharmony_ci		bt_dev_err(hdev, "Intel Read Version command failed (%02x)",
66262306a36Sopenharmony_ci			   skb->data[0]);
66362306a36Sopenharmony_ci		kfree_skb(skb);
66462306a36Sopenharmony_ci		return -EIO;
66562306a36Sopenharmony_ci	}
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	btintel_parse_version_tlv(hdev, version, skb);
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	kfree_skb(skb);
67062306a36Sopenharmony_ci	return 0;
67162306a36Sopenharmony_ci}
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci/* ------- REGMAP IBT SUPPORT ------- */
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci#define IBT_REG_MODE_8BIT  0x00
67662306a36Sopenharmony_ci#define IBT_REG_MODE_16BIT 0x01
67762306a36Sopenharmony_ci#define IBT_REG_MODE_32BIT 0x02
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_cistruct regmap_ibt_context {
68062306a36Sopenharmony_ci	struct hci_dev *hdev;
68162306a36Sopenharmony_ci	__u16 op_write;
68262306a36Sopenharmony_ci	__u16 op_read;
68362306a36Sopenharmony_ci};
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_cistruct ibt_cp_reg_access {
68662306a36Sopenharmony_ci	__le32  addr;
68762306a36Sopenharmony_ci	__u8    mode;
68862306a36Sopenharmony_ci	__u8    len;
68962306a36Sopenharmony_ci	__u8    data[];
69062306a36Sopenharmony_ci} __packed;
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_cistruct ibt_rp_reg_access {
69362306a36Sopenharmony_ci	__u8    status;
69462306a36Sopenharmony_ci	__le32  addr;
69562306a36Sopenharmony_ci	__u8    data[];
69662306a36Sopenharmony_ci} __packed;
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_cistatic int regmap_ibt_read(void *context, const void *addr, size_t reg_size,
69962306a36Sopenharmony_ci			   void *val, size_t val_size)
70062306a36Sopenharmony_ci{
70162306a36Sopenharmony_ci	struct regmap_ibt_context *ctx = context;
70262306a36Sopenharmony_ci	struct ibt_cp_reg_access cp;
70362306a36Sopenharmony_ci	struct ibt_rp_reg_access *rp;
70462306a36Sopenharmony_ci	struct sk_buff *skb;
70562306a36Sopenharmony_ci	int err = 0;
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci	if (reg_size != sizeof(__le32))
70862306a36Sopenharmony_ci		return -EINVAL;
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci	switch (val_size) {
71162306a36Sopenharmony_ci	case 1:
71262306a36Sopenharmony_ci		cp.mode = IBT_REG_MODE_8BIT;
71362306a36Sopenharmony_ci		break;
71462306a36Sopenharmony_ci	case 2:
71562306a36Sopenharmony_ci		cp.mode = IBT_REG_MODE_16BIT;
71662306a36Sopenharmony_ci		break;
71762306a36Sopenharmony_ci	case 4:
71862306a36Sopenharmony_ci		cp.mode = IBT_REG_MODE_32BIT;
71962306a36Sopenharmony_ci		break;
72062306a36Sopenharmony_ci	default:
72162306a36Sopenharmony_ci		return -EINVAL;
72262306a36Sopenharmony_ci	}
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci	/* regmap provides a little-endian formatted addr */
72562306a36Sopenharmony_ci	cp.addr = *(__le32 *)addr;
72662306a36Sopenharmony_ci	cp.len = val_size;
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	bt_dev_dbg(ctx->hdev, "Register (0x%x) read", le32_to_cpu(cp.addr));
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci	skb = hci_cmd_sync(ctx->hdev, ctx->op_read, sizeof(cp), &cp,
73162306a36Sopenharmony_ci			   HCI_CMD_TIMEOUT);
73262306a36Sopenharmony_ci	if (IS_ERR(skb)) {
73362306a36Sopenharmony_ci		err = PTR_ERR(skb);
73462306a36Sopenharmony_ci		bt_dev_err(ctx->hdev, "regmap: Register (0x%x) read error (%d)",
73562306a36Sopenharmony_ci			   le32_to_cpu(cp.addr), err);
73662306a36Sopenharmony_ci		return err;
73762306a36Sopenharmony_ci	}
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci	if (skb->len != sizeof(*rp) + val_size) {
74062306a36Sopenharmony_ci		bt_dev_err(ctx->hdev, "regmap: Register (0x%x) read error, bad len",
74162306a36Sopenharmony_ci			   le32_to_cpu(cp.addr));
74262306a36Sopenharmony_ci		err = -EINVAL;
74362306a36Sopenharmony_ci		goto done;
74462306a36Sopenharmony_ci	}
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_ci	rp = (struct ibt_rp_reg_access *)skb->data;
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci	if (rp->addr != cp.addr) {
74962306a36Sopenharmony_ci		bt_dev_err(ctx->hdev, "regmap: Register (0x%x) read error, bad addr",
75062306a36Sopenharmony_ci			   le32_to_cpu(rp->addr));
75162306a36Sopenharmony_ci		err = -EINVAL;
75262306a36Sopenharmony_ci		goto done;
75362306a36Sopenharmony_ci	}
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci	memcpy(val, rp->data, val_size);
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_cidone:
75862306a36Sopenharmony_ci	kfree_skb(skb);
75962306a36Sopenharmony_ci	return err;
76062306a36Sopenharmony_ci}
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_cistatic int regmap_ibt_gather_write(void *context,
76362306a36Sopenharmony_ci				   const void *addr, size_t reg_size,
76462306a36Sopenharmony_ci				   const void *val, size_t val_size)
76562306a36Sopenharmony_ci{
76662306a36Sopenharmony_ci	struct regmap_ibt_context *ctx = context;
76762306a36Sopenharmony_ci	struct ibt_cp_reg_access *cp;
76862306a36Sopenharmony_ci	struct sk_buff *skb;
76962306a36Sopenharmony_ci	int plen = sizeof(*cp) + val_size;
77062306a36Sopenharmony_ci	u8 mode;
77162306a36Sopenharmony_ci	int err = 0;
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci	if (reg_size != sizeof(__le32))
77462306a36Sopenharmony_ci		return -EINVAL;
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci	switch (val_size) {
77762306a36Sopenharmony_ci	case 1:
77862306a36Sopenharmony_ci		mode = IBT_REG_MODE_8BIT;
77962306a36Sopenharmony_ci		break;
78062306a36Sopenharmony_ci	case 2:
78162306a36Sopenharmony_ci		mode = IBT_REG_MODE_16BIT;
78262306a36Sopenharmony_ci		break;
78362306a36Sopenharmony_ci	case 4:
78462306a36Sopenharmony_ci		mode = IBT_REG_MODE_32BIT;
78562306a36Sopenharmony_ci		break;
78662306a36Sopenharmony_ci	default:
78762306a36Sopenharmony_ci		return -EINVAL;
78862306a36Sopenharmony_ci	}
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci	cp = kmalloc(plen, GFP_KERNEL);
79162306a36Sopenharmony_ci	if (!cp)
79262306a36Sopenharmony_ci		return -ENOMEM;
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci	/* regmap provides a little-endian formatted addr/value */
79562306a36Sopenharmony_ci	cp->addr = *(__le32 *)addr;
79662306a36Sopenharmony_ci	cp->mode = mode;
79762306a36Sopenharmony_ci	cp->len = val_size;
79862306a36Sopenharmony_ci	memcpy(&cp->data, val, val_size);
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci	bt_dev_dbg(ctx->hdev, "Register (0x%x) write", le32_to_cpu(cp->addr));
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	skb = hci_cmd_sync(ctx->hdev, ctx->op_write, plen, cp, HCI_CMD_TIMEOUT);
80362306a36Sopenharmony_ci	if (IS_ERR(skb)) {
80462306a36Sopenharmony_ci		err = PTR_ERR(skb);
80562306a36Sopenharmony_ci		bt_dev_err(ctx->hdev, "regmap: Register (0x%x) write error (%d)",
80662306a36Sopenharmony_ci			   le32_to_cpu(cp->addr), err);
80762306a36Sopenharmony_ci		goto done;
80862306a36Sopenharmony_ci	}
80962306a36Sopenharmony_ci	kfree_skb(skb);
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_cidone:
81262306a36Sopenharmony_ci	kfree(cp);
81362306a36Sopenharmony_ci	return err;
81462306a36Sopenharmony_ci}
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_cistatic int regmap_ibt_write(void *context, const void *data, size_t count)
81762306a36Sopenharmony_ci{
81862306a36Sopenharmony_ci	/* data contains register+value, since we only support 32bit addr,
81962306a36Sopenharmony_ci	 * minimum data size is 4 bytes.
82062306a36Sopenharmony_ci	 */
82162306a36Sopenharmony_ci	if (WARN_ONCE(count < 4, "Invalid register access"))
82262306a36Sopenharmony_ci		return -EINVAL;
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci	return regmap_ibt_gather_write(context, data, 4, data + 4, count - 4);
82562306a36Sopenharmony_ci}
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_cistatic void regmap_ibt_free_context(void *context)
82862306a36Sopenharmony_ci{
82962306a36Sopenharmony_ci	kfree(context);
83062306a36Sopenharmony_ci}
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_cistatic const struct regmap_bus regmap_ibt = {
83362306a36Sopenharmony_ci	.read = regmap_ibt_read,
83462306a36Sopenharmony_ci	.write = regmap_ibt_write,
83562306a36Sopenharmony_ci	.gather_write = regmap_ibt_gather_write,
83662306a36Sopenharmony_ci	.free_context = regmap_ibt_free_context,
83762306a36Sopenharmony_ci	.reg_format_endian_default = REGMAP_ENDIAN_LITTLE,
83862306a36Sopenharmony_ci	.val_format_endian_default = REGMAP_ENDIAN_LITTLE,
83962306a36Sopenharmony_ci};
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_ci/* Config is the same for all register regions */
84262306a36Sopenharmony_cistatic const struct regmap_config regmap_ibt_cfg = {
84362306a36Sopenharmony_ci	.name      = "btintel_regmap",
84462306a36Sopenharmony_ci	.reg_bits  = 32,
84562306a36Sopenharmony_ci	.val_bits  = 32,
84662306a36Sopenharmony_ci};
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_cistruct regmap *btintel_regmap_init(struct hci_dev *hdev, u16 opcode_read,
84962306a36Sopenharmony_ci				   u16 opcode_write)
85062306a36Sopenharmony_ci{
85162306a36Sopenharmony_ci	struct regmap_ibt_context *ctx;
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	bt_dev_info(hdev, "regmap: Init R%x-W%x region", opcode_read,
85462306a36Sopenharmony_ci		    opcode_write);
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
85762306a36Sopenharmony_ci	if (!ctx)
85862306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci	ctx->op_read = opcode_read;
86162306a36Sopenharmony_ci	ctx->op_write = opcode_write;
86262306a36Sopenharmony_ci	ctx->hdev = hdev;
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci	return regmap_init(&hdev->dev, &regmap_ibt, ctx, &regmap_ibt_cfg);
86562306a36Sopenharmony_ci}
86662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(btintel_regmap_init);
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ciint btintel_send_intel_reset(struct hci_dev *hdev, u32 boot_param)
86962306a36Sopenharmony_ci{
87062306a36Sopenharmony_ci	struct intel_reset params = { 0x00, 0x01, 0x00, 0x01, 0x00000000 };
87162306a36Sopenharmony_ci	struct sk_buff *skb;
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci	params.boot_param = cpu_to_le32(boot_param);
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci	skb = __hci_cmd_sync(hdev, 0xfc01, sizeof(params), &params,
87662306a36Sopenharmony_ci			     HCI_INIT_TIMEOUT);
87762306a36Sopenharmony_ci	if (IS_ERR(skb)) {
87862306a36Sopenharmony_ci		bt_dev_err(hdev, "Failed to send Intel Reset command");
87962306a36Sopenharmony_ci		return PTR_ERR(skb);
88062306a36Sopenharmony_ci	}
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_ci	kfree_skb(skb);
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci	return 0;
88562306a36Sopenharmony_ci}
88662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(btintel_send_intel_reset);
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ciint btintel_read_boot_params(struct hci_dev *hdev,
88962306a36Sopenharmony_ci			     struct intel_boot_params *params)
89062306a36Sopenharmony_ci{
89162306a36Sopenharmony_ci	struct sk_buff *skb;
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci	skb = __hci_cmd_sync(hdev, 0xfc0d, 0, NULL, HCI_INIT_TIMEOUT);
89462306a36Sopenharmony_ci	if (IS_ERR(skb)) {
89562306a36Sopenharmony_ci		bt_dev_err(hdev, "Reading Intel boot parameters failed (%ld)",
89662306a36Sopenharmony_ci			   PTR_ERR(skb));
89762306a36Sopenharmony_ci		return PTR_ERR(skb);
89862306a36Sopenharmony_ci	}
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ci	if (skb->len != sizeof(*params)) {
90162306a36Sopenharmony_ci		bt_dev_err(hdev, "Intel boot parameters size mismatch");
90262306a36Sopenharmony_ci		kfree_skb(skb);
90362306a36Sopenharmony_ci		return -EILSEQ;
90462306a36Sopenharmony_ci	}
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_ci	memcpy(params, skb->data, sizeof(*params));
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci	kfree_skb(skb);
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci	if (params->status) {
91162306a36Sopenharmony_ci		bt_dev_err(hdev, "Intel boot parameters command failed (%02x)",
91262306a36Sopenharmony_ci			   params->status);
91362306a36Sopenharmony_ci		return -bt_to_errno(params->status);
91462306a36Sopenharmony_ci	}
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci	bt_dev_info(hdev, "Device revision is %u",
91762306a36Sopenharmony_ci		    le16_to_cpu(params->dev_revid));
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci	bt_dev_info(hdev, "Secure boot is %s",
92062306a36Sopenharmony_ci		    params->secure_boot ? "enabled" : "disabled");
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci	bt_dev_info(hdev, "OTP lock is %s",
92362306a36Sopenharmony_ci		    params->otp_lock ? "enabled" : "disabled");
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci	bt_dev_info(hdev, "API lock is %s",
92662306a36Sopenharmony_ci		    params->api_lock ? "enabled" : "disabled");
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_ci	bt_dev_info(hdev, "Debug lock is %s",
92962306a36Sopenharmony_ci		    params->debug_lock ? "enabled" : "disabled");
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci	bt_dev_info(hdev, "Minimum firmware build %u week %u %u",
93262306a36Sopenharmony_ci		    params->min_fw_build_nn, params->min_fw_build_cw,
93362306a36Sopenharmony_ci		    2000 + params->min_fw_build_yy);
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci	return 0;
93662306a36Sopenharmony_ci}
93762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(btintel_read_boot_params);
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_cistatic int btintel_sfi_rsa_header_secure_send(struct hci_dev *hdev,
94062306a36Sopenharmony_ci					      const struct firmware *fw)
94162306a36Sopenharmony_ci{
94262306a36Sopenharmony_ci	int err;
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci	/* Start the firmware download transaction with the Init fragment
94562306a36Sopenharmony_ci	 * represented by the 128 bytes of CSS header.
94662306a36Sopenharmony_ci	 */
94762306a36Sopenharmony_ci	err = btintel_secure_send(hdev, 0x00, 128, fw->data);
94862306a36Sopenharmony_ci	if (err < 0) {
94962306a36Sopenharmony_ci		bt_dev_err(hdev, "Failed to send firmware header (%d)", err);
95062306a36Sopenharmony_ci		goto done;
95162306a36Sopenharmony_ci	}
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci	/* Send the 256 bytes of public key information from the firmware
95462306a36Sopenharmony_ci	 * as the PKey fragment.
95562306a36Sopenharmony_ci	 */
95662306a36Sopenharmony_ci	err = btintel_secure_send(hdev, 0x03, 256, fw->data + 128);
95762306a36Sopenharmony_ci	if (err < 0) {
95862306a36Sopenharmony_ci		bt_dev_err(hdev, "Failed to send firmware pkey (%d)", err);
95962306a36Sopenharmony_ci		goto done;
96062306a36Sopenharmony_ci	}
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_ci	/* Send the 256 bytes of signature information from the firmware
96362306a36Sopenharmony_ci	 * as the Sign fragment.
96462306a36Sopenharmony_ci	 */
96562306a36Sopenharmony_ci	err = btintel_secure_send(hdev, 0x02, 256, fw->data + 388);
96662306a36Sopenharmony_ci	if (err < 0) {
96762306a36Sopenharmony_ci		bt_dev_err(hdev, "Failed to send firmware signature (%d)", err);
96862306a36Sopenharmony_ci		goto done;
96962306a36Sopenharmony_ci	}
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_cidone:
97262306a36Sopenharmony_ci	return err;
97362306a36Sopenharmony_ci}
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_cistatic int btintel_sfi_ecdsa_header_secure_send(struct hci_dev *hdev,
97662306a36Sopenharmony_ci						const struct firmware *fw)
97762306a36Sopenharmony_ci{
97862306a36Sopenharmony_ci	int err;
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci	/* Start the firmware download transaction with the Init fragment
98162306a36Sopenharmony_ci	 * represented by the 128 bytes of CSS header.
98262306a36Sopenharmony_ci	 */
98362306a36Sopenharmony_ci	err = btintel_secure_send(hdev, 0x00, 128, fw->data + 644);
98462306a36Sopenharmony_ci	if (err < 0) {
98562306a36Sopenharmony_ci		bt_dev_err(hdev, "Failed to send firmware header (%d)", err);
98662306a36Sopenharmony_ci		return err;
98762306a36Sopenharmony_ci	}
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci	/* Send the 96 bytes of public key information from the firmware
99062306a36Sopenharmony_ci	 * as the PKey fragment.
99162306a36Sopenharmony_ci	 */
99262306a36Sopenharmony_ci	err = btintel_secure_send(hdev, 0x03, 96, fw->data + 644 + 128);
99362306a36Sopenharmony_ci	if (err < 0) {
99462306a36Sopenharmony_ci		bt_dev_err(hdev, "Failed to send firmware pkey (%d)", err);
99562306a36Sopenharmony_ci		return err;
99662306a36Sopenharmony_ci	}
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ci	/* Send the 96 bytes of signature information from the firmware
99962306a36Sopenharmony_ci	 * as the Sign fragment
100062306a36Sopenharmony_ci	 */
100162306a36Sopenharmony_ci	err = btintel_secure_send(hdev, 0x02, 96, fw->data + 644 + 224);
100262306a36Sopenharmony_ci	if (err < 0) {
100362306a36Sopenharmony_ci		bt_dev_err(hdev, "Failed to send firmware signature (%d)",
100462306a36Sopenharmony_ci			   err);
100562306a36Sopenharmony_ci		return err;
100662306a36Sopenharmony_ci	}
100762306a36Sopenharmony_ci	return 0;
100862306a36Sopenharmony_ci}
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_cistatic int btintel_download_firmware_payload(struct hci_dev *hdev,
101162306a36Sopenharmony_ci					     const struct firmware *fw,
101262306a36Sopenharmony_ci					     size_t offset)
101362306a36Sopenharmony_ci{
101462306a36Sopenharmony_ci	int err;
101562306a36Sopenharmony_ci	const u8 *fw_ptr;
101662306a36Sopenharmony_ci	u32 frag_len;
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_ci	fw_ptr = fw->data + offset;
101962306a36Sopenharmony_ci	frag_len = 0;
102062306a36Sopenharmony_ci	err = -EINVAL;
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci	while (fw_ptr - fw->data < fw->size) {
102362306a36Sopenharmony_ci		struct hci_command_hdr *cmd = (void *)(fw_ptr + frag_len);
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_ci		frag_len += sizeof(*cmd) + cmd->plen;
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci		/* The parameter length of the secure send command requires
102862306a36Sopenharmony_ci		 * a 4 byte alignment. It happens so that the firmware file
102962306a36Sopenharmony_ci		 * contains proper Intel_NOP commands to align the fragments
103062306a36Sopenharmony_ci		 * as needed.
103162306a36Sopenharmony_ci		 *
103262306a36Sopenharmony_ci		 * Send set of commands with 4 byte alignment from the
103362306a36Sopenharmony_ci		 * firmware data buffer as a single Data fragement.
103462306a36Sopenharmony_ci		 */
103562306a36Sopenharmony_ci		if (!(frag_len % 4)) {
103662306a36Sopenharmony_ci			err = btintel_secure_send(hdev, 0x01, frag_len, fw_ptr);
103762306a36Sopenharmony_ci			if (err < 0) {
103862306a36Sopenharmony_ci				bt_dev_err(hdev,
103962306a36Sopenharmony_ci					   "Failed to send firmware data (%d)",
104062306a36Sopenharmony_ci					   err);
104162306a36Sopenharmony_ci				goto done;
104262306a36Sopenharmony_ci			}
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_ci			fw_ptr += frag_len;
104562306a36Sopenharmony_ci			frag_len = 0;
104662306a36Sopenharmony_ci		}
104762306a36Sopenharmony_ci	}
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_cidone:
105062306a36Sopenharmony_ci	return err;
105162306a36Sopenharmony_ci}
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_cistatic bool btintel_firmware_version(struct hci_dev *hdev,
105462306a36Sopenharmony_ci				     u8 num, u8 ww, u8 yy,
105562306a36Sopenharmony_ci				     const struct firmware *fw,
105662306a36Sopenharmony_ci				     u32 *boot_addr)
105762306a36Sopenharmony_ci{
105862306a36Sopenharmony_ci	const u8 *fw_ptr;
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci	fw_ptr = fw->data;
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci	while (fw_ptr - fw->data < fw->size) {
106362306a36Sopenharmony_ci		struct hci_command_hdr *cmd = (void *)(fw_ptr);
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci		/* Each SKU has a different reset parameter to use in the
106662306a36Sopenharmony_ci		 * HCI_Intel_Reset command and it is embedded in the firmware
106762306a36Sopenharmony_ci		 * data. So, instead of using static value per SKU, check
106862306a36Sopenharmony_ci		 * the firmware data and save it for later use.
106962306a36Sopenharmony_ci		 */
107062306a36Sopenharmony_ci		if (le16_to_cpu(cmd->opcode) == CMD_WRITE_BOOT_PARAMS) {
107162306a36Sopenharmony_ci			struct cmd_write_boot_params *params;
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci			params = (void *)(fw_ptr + sizeof(*cmd));
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci			*boot_addr = le32_to_cpu(params->boot_addr);
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ci			bt_dev_info(hdev, "Boot Address: 0x%x", *boot_addr);
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci			bt_dev_info(hdev, "Firmware Version: %u-%u.%u",
108062306a36Sopenharmony_ci				    params->fw_build_num, params->fw_build_ww,
108162306a36Sopenharmony_ci				    params->fw_build_yy);
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci			return (num == params->fw_build_num &&
108462306a36Sopenharmony_ci				ww == params->fw_build_ww &&
108562306a36Sopenharmony_ci				yy == params->fw_build_yy);
108662306a36Sopenharmony_ci		}
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci		fw_ptr += sizeof(*cmd) + cmd->plen;
108962306a36Sopenharmony_ci	}
109062306a36Sopenharmony_ci
109162306a36Sopenharmony_ci	return false;
109262306a36Sopenharmony_ci}
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ciint btintel_download_firmware(struct hci_dev *hdev,
109562306a36Sopenharmony_ci			      struct intel_version *ver,
109662306a36Sopenharmony_ci			      const struct firmware *fw,
109762306a36Sopenharmony_ci			      u32 *boot_param)
109862306a36Sopenharmony_ci{
109962306a36Sopenharmony_ci	int err;
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci	/* SfP and WsP don't seem to update the firmware version on file
110262306a36Sopenharmony_ci	 * so version checking is currently not possible.
110362306a36Sopenharmony_ci	 */
110462306a36Sopenharmony_ci	switch (ver->hw_variant) {
110562306a36Sopenharmony_ci	case 0x0b:	/* SfP */
110662306a36Sopenharmony_ci	case 0x0c:	/* WsP */
110762306a36Sopenharmony_ci		/* Skip version checking */
110862306a36Sopenharmony_ci		break;
110962306a36Sopenharmony_ci	default:
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ci		/* Skip download if firmware has the same version */
111262306a36Sopenharmony_ci		if (btintel_firmware_version(hdev, ver->fw_build_num,
111362306a36Sopenharmony_ci					     ver->fw_build_ww, ver->fw_build_yy,
111462306a36Sopenharmony_ci					     fw, boot_param)) {
111562306a36Sopenharmony_ci			bt_dev_info(hdev, "Firmware already loaded");
111662306a36Sopenharmony_ci			/* Return -EALREADY to indicate that the firmware has
111762306a36Sopenharmony_ci			 * already been loaded.
111862306a36Sopenharmony_ci			 */
111962306a36Sopenharmony_ci			return -EALREADY;
112062306a36Sopenharmony_ci		}
112162306a36Sopenharmony_ci	}
112262306a36Sopenharmony_ci
112362306a36Sopenharmony_ci	/* The firmware variant determines if the device is in bootloader
112462306a36Sopenharmony_ci	 * mode or is running operational firmware. The value 0x06 identifies
112562306a36Sopenharmony_ci	 * the bootloader and the value 0x23 identifies the operational
112662306a36Sopenharmony_ci	 * firmware.
112762306a36Sopenharmony_ci	 *
112862306a36Sopenharmony_ci	 * If the firmware version has changed that means it needs to be reset
112962306a36Sopenharmony_ci	 * to bootloader when operational so the new firmware can be loaded.
113062306a36Sopenharmony_ci	 */
113162306a36Sopenharmony_ci	if (ver->fw_variant == 0x23)
113262306a36Sopenharmony_ci		return -EINVAL;
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci	err = btintel_sfi_rsa_header_secure_send(hdev, fw);
113562306a36Sopenharmony_ci	if (err)
113662306a36Sopenharmony_ci		return err;
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci	return btintel_download_firmware_payload(hdev, fw, RSA_HEADER_LEN);
113962306a36Sopenharmony_ci}
114062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(btintel_download_firmware);
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_cistatic int btintel_download_fw_tlv(struct hci_dev *hdev,
114362306a36Sopenharmony_ci				   struct intel_version_tlv *ver,
114462306a36Sopenharmony_ci				   const struct firmware *fw, u32 *boot_param,
114562306a36Sopenharmony_ci				   u8 hw_variant, u8 sbe_type)
114662306a36Sopenharmony_ci{
114762306a36Sopenharmony_ci	int err;
114862306a36Sopenharmony_ci	u32 css_header_ver;
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_ci	/* Skip download if firmware has the same version */
115162306a36Sopenharmony_ci	if (btintel_firmware_version(hdev, ver->min_fw_build_nn,
115262306a36Sopenharmony_ci				     ver->min_fw_build_cw,
115362306a36Sopenharmony_ci				     ver->min_fw_build_yy,
115462306a36Sopenharmony_ci				     fw, boot_param)) {
115562306a36Sopenharmony_ci		bt_dev_info(hdev, "Firmware already loaded");
115662306a36Sopenharmony_ci		/* Return -EALREADY to indicate that firmware has
115762306a36Sopenharmony_ci		 * already been loaded.
115862306a36Sopenharmony_ci		 */
115962306a36Sopenharmony_ci		return -EALREADY;
116062306a36Sopenharmony_ci	}
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_ci	/* The firmware variant determines if the device is in bootloader
116362306a36Sopenharmony_ci	 * mode or is running operational firmware. The value 0x01 identifies
116462306a36Sopenharmony_ci	 * the bootloader and the value 0x03 identifies the operational
116562306a36Sopenharmony_ci	 * firmware.
116662306a36Sopenharmony_ci	 *
116762306a36Sopenharmony_ci	 * If the firmware version has changed that means it needs to be reset
116862306a36Sopenharmony_ci	 * to bootloader when operational so the new firmware can be loaded.
116962306a36Sopenharmony_ci	 */
117062306a36Sopenharmony_ci	if (ver->img_type == 0x03)
117162306a36Sopenharmony_ci		return -EINVAL;
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ci	/* iBT hardware variants 0x0b, 0x0c, 0x11, 0x12, 0x13, 0x14 support
117462306a36Sopenharmony_ci	 * only RSA secure boot engine. Hence, the corresponding sfi file will
117562306a36Sopenharmony_ci	 * have RSA header of 644 bytes followed by Command Buffer.
117662306a36Sopenharmony_ci	 *
117762306a36Sopenharmony_ci	 * iBT hardware variants 0x17, 0x18 onwards support both RSA and ECDSA
117862306a36Sopenharmony_ci	 * secure boot engine. As a result, the corresponding sfi file will
117962306a36Sopenharmony_ci	 * have RSA header of 644, ECDSA header of 320 bytes followed by
118062306a36Sopenharmony_ci	 * Command Buffer.
118162306a36Sopenharmony_ci	 *
118262306a36Sopenharmony_ci	 * CSS Header byte positions 0x08 to 0x0B represent the CSS Header
118362306a36Sopenharmony_ci	 * version: RSA(0x00010000) , ECDSA (0x00020000)
118462306a36Sopenharmony_ci	 */
118562306a36Sopenharmony_ci	css_header_ver = get_unaligned_le32(fw->data + CSS_HEADER_OFFSET);
118662306a36Sopenharmony_ci	if (css_header_ver != 0x00010000) {
118762306a36Sopenharmony_ci		bt_dev_err(hdev, "Invalid CSS Header version");
118862306a36Sopenharmony_ci		return -EINVAL;
118962306a36Sopenharmony_ci	}
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_ci	if (hw_variant <= 0x14) {
119262306a36Sopenharmony_ci		if (sbe_type != 0x00) {
119362306a36Sopenharmony_ci			bt_dev_err(hdev, "Invalid SBE type for hardware variant (%d)",
119462306a36Sopenharmony_ci				   hw_variant);
119562306a36Sopenharmony_ci			return -EINVAL;
119662306a36Sopenharmony_ci		}
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_ci		err = btintel_sfi_rsa_header_secure_send(hdev, fw);
119962306a36Sopenharmony_ci		if (err)
120062306a36Sopenharmony_ci			return err;
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_ci		err = btintel_download_firmware_payload(hdev, fw, RSA_HEADER_LEN);
120362306a36Sopenharmony_ci		if (err)
120462306a36Sopenharmony_ci			return err;
120562306a36Sopenharmony_ci	} else if (hw_variant >= 0x17) {
120662306a36Sopenharmony_ci		/* Check if CSS header for ECDSA follows the RSA header */
120762306a36Sopenharmony_ci		if (fw->data[ECDSA_OFFSET] != 0x06)
120862306a36Sopenharmony_ci			return -EINVAL;
120962306a36Sopenharmony_ci
121062306a36Sopenharmony_ci		/* Check if the CSS Header version is ECDSA(0x00020000) */
121162306a36Sopenharmony_ci		css_header_ver = get_unaligned_le32(fw->data + ECDSA_OFFSET + CSS_HEADER_OFFSET);
121262306a36Sopenharmony_ci		if (css_header_ver != 0x00020000) {
121362306a36Sopenharmony_ci			bt_dev_err(hdev, "Invalid CSS Header version");
121462306a36Sopenharmony_ci			return -EINVAL;
121562306a36Sopenharmony_ci		}
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_ci		if (sbe_type == 0x00) {
121862306a36Sopenharmony_ci			err = btintel_sfi_rsa_header_secure_send(hdev, fw);
121962306a36Sopenharmony_ci			if (err)
122062306a36Sopenharmony_ci				return err;
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_ci			err = btintel_download_firmware_payload(hdev, fw,
122362306a36Sopenharmony_ci								RSA_HEADER_LEN + ECDSA_HEADER_LEN);
122462306a36Sopenharmony_ci			if (err)
122562306a36Sopenharmony_ci				return err;
122662306a36Sopenharmony_ci		} else if (sbe_type == 0x01) {
122762306a36Sopenharmony_ci			err = btintel_sfi_ecdsa_header_secure_send(hdev, fw);
122862306a36Sopenharmony_ci			if (err)
122962306a36Sopenharmony_ci				return err;
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_ci			err = btintel_download_firmware_payload(hdev, fw,
123262306a36Sopenharmony_ci								RSA_HEADER_LEN + ECDSA_HEADER_LEN);
123362306a36Sopenharmony_ci			if (err)
123462306a36Sopenharmony_ci				return err;
123562306a36Sopenharmony_ci		}
123662306a36Sopenharmony_ci	}
123762306a36Sopenharmony_ci	return 0;
123862306a36Sopenharmony_ci}
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_cistatic void btintel_reset_to_bootloader(struct hci_dev *hdev)
124162306a36Sopenharmony_ci{
124262306a36Sopenharmony_ci	struct intel_reset params;
124362306a36Sopenharmony_ci	struct sk_buff *skb;
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci	/* Send Intel Reset command. This will result in
124662306a36Sopenharmony_ci	 * re-enumeration of BT controller.
124762306a36Sopenharmony_ci	 *
124862306a36Sopenharmony_ci	 * Intel Reset parameter description:
124962306a36Sopenharmony_ci	 * reset_type :   0x00 (Soft reset),
125062306a36Sopenharmony_ci	 *		  0x01 (Hard reset)
125162306a36Sopenharmony_ci	 * patch_enable : 0x00 (Do not enable),
125262306a36Sopenharmony_ci	 *		  0x01 (Enable)
125362306a36Sopenharmony_ci	 * ddc_reload :   0x00 (Do not reload),
125462306a36Sopenharmony_ci	 *		  0x01 (Reload)
125562306a36Sopenharmony_ci	 * boot_option:   0x00 (Current image),
125662306a36Sopenharmony_ci	 *                0x01 (Specified boot address)
125762306a36Sopenharmony_ci	 * boot_param:    Boot address
125862306a36Sopenharmony_ci	 *
125962306a36Sopenharmony_ci	 */
126062306a36Sopenharmony_ci	params.reset_type = 0x01;
126162306a36Sopenharmony_ci	params.patch_enable = 0x01;
126262306a36Sopenharmony_ci	params.ddc_reload = 0x01;
126362306a36Sopenharmony_ci	params.boot_option = 0x00;
126462306a36Sopenharmony_ci	params.boot_param = cpu_to_le32(0x00000000);
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci	skb = __hci_cmd_sync(hdev, 0xfc01, sizeof(params),
126762306a36Sopenharmony_ci			     &params, HCI_INIT_TIMEOUT);
126862306a36Sopenharmony_ci	if (IS_ERR(skb)) {
126962306a36Sopenharmony_ci		bt_dev_err(hdev, "FW download error recovery failed (%ld)",
127062306a36Sopenharmony_ci			   PTR_ERR(skb));
127162306a36Sopenharmony_ci		return;
127262306a36Sopenharmony_ci	}
127362306a36Sopenharmony_ci	bt_dev_info(hdev, "Intel reset sent to retry FW download");
127462306a36Sopenharmony_ci	kfree_skb(skb);
127562306a36Sopenharmony_ci
127662306a36Sopenharmony_ci	/* Current Intel BT controllers(ThP/JfP) hold the USB reset
127762306a36Sopenharmony_ci	 * lines for 2ms when it receives Intel Reset in bootloader mode.
127862306a36Sopenharmony_ci	 * Whereas, the upcoming Intel BT controllers will hold USB reset
127962306a36Sopenharmony_ci	 * for 150ms. To keep the delay generic, 150ms is chosen here.
128062306a36Sopenharmony_ci	 */
128162306a36Sopenharmony_ci	msleep(150);
128262306a36Sopenharmony_ci}
128362306a36Sopenharmony_ci
128462306a36Sopenharmony_cistatic int btintel_read_debug_features(struct hci_dev *hdev,
128562306a36Sopenharmony_ci				       struct intel_debug_features *features)
128662306a36Sopenharmony_ci{
128762306a36Sopenharmony_ci	struct sk_buff *skb;
128862306a36Sopenharmony_ci	u8 page_no = 1;
128962306a36Sopenharmony_ci
129062306a36Sopenharmony_ci	/* Intel controller supports two pages, each page is of 128-bit
129162306a36Sopenharmony_ci	 * feature bit mask. And each bit defines specific feature support
129262306a36Sopenharmony_ci	 */
129362306a36Sopenharmony_ci	skb = __hci_cmd_sync(hdev, 0xfca6, sizeof(page_no), &page_no,
129462306a36Sopenharmony_ci			     HCI_INIT_TIMEOUT);
129562306a36Sopenharmony_ci	if (IS_ERR(skb)) {
129662306a36Sopenharmony_ci		bt_dev_err(hdev, "Reading supported features failed (%ld)",
129762306a36Sopenharmony_ci			   PTR_ERR(skb));
129862306a36Sopenharmony_ci		return PTR_ERR(skb);
129962306a36Sopenharmony_ci	}
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ci	if (skb->len != (sizeof(features->page1) + 3)) {
130262306a36Sopenharmony_ci		bt_dev_err(hdev, "Supported features event size mismatch");
130362306a36Sopenharmony_ci		kfree_skb(skb);
130462306a36Sopenharmony_ci		return -EILSEQ;
130562306a36Sopenharmony_ci	}
130662306a36Sopenharmony_ci
130762306a36Sopenharmony_ci	memcpy(features->page1, skb->data + 3, sizeof(features->page1));
130862306a36Sopenharmony_ci
130962306a36Sopenharmony_ci	/* Read the supported features page2 if required in future.
131062306a36Sopenharmony_ci	 */
131162306a36Sopenharmony_ci	kfree_skb(skb);
131262306a36Sopenharmony_ci	return 0;
131362306a36Sopenharmony_ci}
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_cistatic acpi_status btintel_ppag_callback(acpi_handle handle, u32 lvl, void *data,
131662306a36Sopenharmony_ci					 void **ret)
131762306a36Sopenharmony_ci{
131862306a36Sopenharmony_ci	acpi_status status;
131962306a36Sopenharmony_ci	size_t len;
132062306a36Sopenharmony_ci	struct btintel_ppag *ppag = data;
132162306a36Sopenharmony_ci	union acpi_object *p, *elements;
132262306a36Sopenharmony_ci	struct acpi_buffer string = {ACPI_ALLOCATE_BUFFER, NULL};
132362306a36Sopenharmony_ci	struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
132462306a36Sopenharmony_ci	struct hci_dev *hdev = ppag->hdev;
132562306a36Sopenharmony_ci
132662306a36Sopenharmony_ci	status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &string);
132762306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
132862306a36Sopenharmony_ci		bt_dev_warn(hdev, "PPAG-BT: ACPI Failure: %s", acpi_format_exception(status));
132962306a36Sopenharmony_ci		return status;
133062306a36Sopenharmony_ci	}
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_ci	len = strlen(string.pointer);
133362306a36Sopenharmony_ci	if (len < strlen(BTINTEL_PPAG_NAME)) {
133462306a36Sopenharmony_ci		kfree(string.pointer);
133562306a36Sopenharmony_ci		return AE_OK;
133662306a36Sopenharmony_ci	}
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_ci	if (strncmp((char *)string.pointer + len - 4, BTINTEL_PPAG_NAME, 4)) {
133962306a36Sopenharmony_ci		kfree(string.pointer);
134062306a36Sopenharmony_ci		return AE_OK;
134162306a36Sopenharmony_ci	}
134262306a36Sopenharmony_ci	kfree(string.pointer);
134362306a36Sopenharmony_ci
134462306a36Sopenharmony_ci	status = acpi_evaluate_object(handle, NULL, NULL, &buffer);
134562306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
134662306a36Sopenharmony_ci		ppag->status = status;
134762306a36Sopenharmony_ci		bt_dev_warn(hdev, "PPAG-BT: ACPI Failure: %s", acpi_format_exception(status));
134862306a36Sopenharmony_ci		return status;
134962306a36Sopenharmony_ci	}
135062306a36Sopenharmony_ci
135162306a36Sopenharmony_ci	p = buffer.pointer;
135262306a36Sopenharmony_ci	ppag = (struct btintel_ppag *)data;
135362306a36Sopenharmony_ci
135462306a36Sopenharmony_ci	if (p->type != ACPI_TYPE_PACKAGE || p->package.count != 2) {
135562306a36Sopenharmony_ci		kfree(buffer.pointer);
135662306a36Sopenharmony_ci		bt_dev_warn(hdev, "PPAG-BT: Invalid object type: %d or package count: %d",
135762306a36Sopenharmony_ci			    p->type, p->package.count);
135862306a36Sopenharmony_ci		ppag->status = AE_ERROR;
135962306a36Sopenharmony_ci		return AE_ERROR;
136062306a36Sopenharmony_ci	}
136162306a36Sopenharmony_ci
136262306a36Sopenharmony_ci	elements = p->package.elements;
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_ci	/* PPAG table is located at element[1] */
136562306a36Sopenharmony_ci	p = &elements[1];
136662306a36Sopenharmony_ci
136762306a36Sopenharmony_ci	ppag->domain = (u32)p->package.elements[0].integer.value;
136862306a36Sopenharmony_ci	ppag->mode = (u32)p->package.elements[1].integer.value;
136962306a36Sopenharmony_ci	ppag->status = AE_OK;
137062306a36Sopenharmony_ci	kfree(buffer.pointer);
137162306a36Sopenharmony_ci	return AE_CTRL_TERMINATE;
137262306a36Sopenharmony_ci}
137362306a36Sopenharmony_ci
137462306a36Sopenharmony_cistatic int btintel_set_debug_features(struct hci_dev *hdev,
137562306a36Sopenharmony_ci			       const struct intel_debug_features *features)
137662306a36Sopenharmony_ci{
137762306a36Sopenharmony_ci	u8 mask[11] = { 0x0a, 0x92, 0x02, 0x7f, 0x00, 0x00, 0x00, 0x00,
137862306a36Sopenharmony_ci			0x00, 0x00, 0x00 };
137962306a36Sopenharmony_ci	u8 period[5] = { 0x04, 0x91, 0x02, 0x05, 0x00 };
138062306a36Sopenharmony_ci	u8 trace_enable = 0x02;
138162306a36Sopenharmony_ci	struct sk_buff *skb;
138262306a36Sopenharmony_ci
138362306a36Sopenharmony_ci	if (!features) {
138462306a36Sopenharmony_ci		bt_dev_warn(hdev, "Debug features not read");
138562306a36Sopenharmony_ci		return -EINVAL;
138662306a36Sopenharmony_ci	}
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_ci	if (!(features->page1[0] & 0x3f)) {
138962306a36Sopenharmony_ci		bt_dev_info(hdev, "Telemetry exception format not supported");
139062306a36Sopenharmony_ci		return 0;
139162306a36Sopenharmony_ci	}
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci	skb = __hci_cmd_sync(hdev, 0xfc8b, 11, mask, HCI_INIT_TIMEOUT);
139462306a36Sopenharmony_ci	if (IS_ERR(skb)) {
139562306a36Sopenharmony_ci		bt_dev_err(hdev, "Setting Intel telemetry ddc write event mask failed (%ld)",
139662306a36Sopenharmony_ci			   PTR_ERR(skb));
139762306a36Sopenharmony_ci		return PTR_ERR(skb);
139862306a36Sopenharmony_ci	}
139962306a36Sopenharmony_ci	kfree_skb(skb);
140062306a36Sopenharmony_ci
140162306a36Sopenharmony_ci	skb = __hci_cmd_sync(hdev, 0xfc8b, 5, period, HCI_INIT_TIMEOUT);
140262306a36Sopenharmony_ci	if (IS_ERR(skb)) {
140362306a36Sopenharmony_ci		bt_dev_err(hdev, "Setting periodicity for link statistics traces failed (%ld)",
140462306a36Sopenharmony_ci			   PTR_ERR(skb));
140562306a36Sopenharmony_ci		return PTR_ERR(skb);
140662306a36Sopenharmony_ci	}
140762306a36Sopenharmony_ci	kfree_skb(skb);
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci	skb = __hci_cmd_sync(hdev, 0xfca1, 1, &trace_enable, HCI_INIT_TIMEOUT);
141062306a36Sopenharmony_ci	if (IS_ERR(skb)) {
141162306a36Sopenharmony_ci		bt_dev_err(hdev, "Enable tracing of link statistics events failed (%ld)",
141262306a36Sopenharmony_ci			   PTR_ERR(skb));
141362306a36Sopenharmony_ci		return PTR_ERR(skb);
141462306a36Sopenharmony_ci	}
141562306a36Sopenharmony_ci	kfree_skb(skb);
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_ci	bt_dev_info(hdev, "set debug features: trace_enable 0x%02x mask 0x%02x",
141862306a36Sopenharmony_ci		    trace_enable, mask[3]);
141962306a36Sopenharmony_ci
142062306a36Sopenharmony_ci	return 0;
142162306a36Sopenharmony_ci}
142262306a36Sopenharmony_ci
142362306a36Sopenharmony_cistatic int btintel_reset_debug_features(struct hci_dev *hdev,
142462306a36Sopenharmony_ci				 const struct intel_debug_features *features)
142562306a36Sopenharmony_ci{
142662306a36Sopenharmony_ci	u8 mask[11] = { 0x0a, 0x92, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
142762306a36Sopenharmony_ci			0x00, 0x00, 0x00 };
142862306a36Sopenharmony_ci	u8 trace_enable = 0x00;
142962306a36Sopenharmony_ci	struct sk_buff *skb;
143062306a36Sopenharmony_ci
143162306a36Sopenharmony_ci	if (!features) {
143262306a36Sopenharmony_ci		bt_dev_warn(hdev, "Debug features not read");
143362306a36Sopenharmony_ci		return -EINVAL;
143462306a36Sopenharmony_ci	}
143562306a36Sopenharmony_ci
143662306a36Sopenharmony_ci	if (!(features->page1[0] & 0x3f)) {
143762306a36Sopenharmony_ci		bt_dev_info(hdev, "Telemetry exception format not supported");
143862306a36Sopenharmony_ci		return 0;
143962306a36Sopenharmony_ci	}
144062306a36Sopenharmony_ci
144162306a36Sopenharmony_ci	/* Should stop the trace before writing ddc event mask. */
144262306a36Sopenharmony_ci	skb = __hci_cmd_sync(hdev, 0xfca1, 1, &trace_enable, HCI_INIT_TIMEOUT);
144362306a36Sopenharmony_ci	if (IS_ERR(skb)) {
144462306a36Sopenharmony_ci		bt_dev_err(hdev, "Stop tracing of link statistics events failed (%ld)",
144562306a36Sopenharmony_ci			   PTR_ERR(skb));
144662306a36Sopenharmony_ci		return PTR_ERR(skb);
144762306a36Sopenharmony_ci	}
144862306a36Sopenharmony_ci	kfree_skb(skb);
144962306a36Sopenharmony_ci
145062306a36Sopenharmony_ci	skb = __hci_cmd_sync(hdev, 0xfc8b, 11, mask, HCI_INIT_TIMEOUT);
145162306a36Sopenharmony_ci	if (IS_ERR(skb)) {
145262306a36Sopenharmony_ci		bt_dev_err(hdev, "Setting Intel telemetry ddc write event mask failed (%ld)",
145362306a36Sopenharmony_ci			   PTR_ERR(skb));
145462306a36Sopenharmony_ci		return PTR_ERR(skb);
145562306a36Sopenharmony_ci	}
145662306a36Sopenharmony_ci	kfree_skb(skb);
145762306a36Sopenharmony_ci
145862306a36Sopenharmony_ci	bt_dev_info(hdev, "reset debug features: trace_enable 0x%02x mask 0x%02x",
145962306a36Sopenharmony_ci		    trace_enable, mask[3]);
146062306a36Sopenharmony_ci
146162306a36Sopenharmony_ci	return 0;
146262306a36Sopenharmony_ci}
146362306a36Sopenharmony_ci
146462306a36Sopenharmony_ciint btintel_set_quality_report(struct hci_dev *hdev, bool enable)
146562306a36Sopenharmony_ci{
146662306a36Sopenharmony_ci	struct intel_debug_features features;
146762306a36Sopenharmony_ci	int err;
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_ci	bt_dev_dbg(hdev, "enable %d", enable);
147062306a36Sopenharmony_ci
147162306a36Sopenharmony_ci	/* Read the Intel supported features and if new exception formats
147262306a36Sopenharmony_ci	 * supported, need to load the additional DDC config to enable.
147362306a36Sopenharmony_ci	 */
147462306a36Sopenharmony_ci	err = btintel_read_debug_features(hdev, &features);
147562306a36Sopenharmony_ci	if (err)
147662306a36Sopenharmony_ci		return err;
147762306a36Sopenharmony_ci
147862306a36Sopenharmony_ci	/* Set or reset the debug features. */
147962306a36Sopenharmony_ci	if (enable)
148062306a36Sopenharmony_ci		err = btintel_set_debug_features(hdev, &features);
148162306a36Sopenharmony_ci	else
148262306a36Sopenharmony_ci		err = btintel_reset_debug_features(hdev, &features);
148362306a36Sopenharmony_ci
148462306a36Sopenharmony_ci	return err;
148562306a36Sopenharmony_ci}
148662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(btintel_set_quality_report);
148762306a36Sopenharmony_ci
148862306a36Sopenharmony_cistatic void btintel_coredump(struct hci_dev *hdev)
148962306a36Sopenharmony_ci{
149062306a36Sopenharmony_ci	struct sk_buff *skb;
149162306a36Sopenharmony_ci
149262306a36Sopenharmony_ci	skb = __hci_cmd_sync(hdev, 0xfc4e, 0, NULL, HCI_CMD_TIMEOUT);
149362306a36Sopenharmony_ci	if (IS_ERR(skb)) {
149462306a36Sopenharmony_ci		bt_dev_err(hdev, "Coredump failed (%ld)", PTR_ERR(skb));
149562306a36Sopenharmony_ci		return;
149662306a36Sopenharmony_ci	}
149762306a36Sopenharmony_ci
149862306a36Sopenharmony_ci	kfree_skb(skb);
149962306a36Sopenharmony_ci}
150062306a36Sopenharmony_ci
150162306a36Sopenharmony_cistatic void btintel_dmp_hdr(struct hci_dev *hdev, struct sk_buff *skb)
150262306a36Sopenharmony_ci{
150362306a36Sopenharmony_ci	char buf[80];
150462306a36Sopenharmony_ci
150562306a36Sopenharmony_ci	snprintf(buf, sizeof(buf), "Controller Name: 0x%X\n",
150662306a36Sopenharmony_ci		 coredump_info.hw_variant);
150762306a36Sopenharmony_ci	skb_put_data(skb, buf, strlen(buf));
150862306a36Sopenharmony_ci
150962306a36Sopenharmony_ci	snprintf(buf, sizeof(buf), "Firmware Version: 0x%X\n",
151062306a36Sopenharmony_ci		 coredump_info.fw_build_num);
151162306a36Sopenharmony_ci	skb_put_data(skb, buf, strlen(buf));
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_ci	snprintf(buf, sizeof(buf), "Driver: %s\n", coredump_info.driver_name);
151462306a36Sopenharmony_ci	skb_put_data(skb, buf, strlen(buf));
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_ci	snprintf(buf, sizeof(buf), "Vendor: Intel\n");
151762306a36Sopenharmony_ci	skb_put_data(skb, buf, strlen(buf));
151862306a36Sopenharmony_ci}
151962306a36Sopenharmony_ci
152062306a36Sopenharmony_cistatic int btintel_register_devcoredump_support(struct hci_dev *hdev)
152162306a36Sopenharmony_ci{
152262306a36Sopenharmony_ci	struct intel_debug_features features;
152362306a36Sopenharmony_ci	int err;
152462306a36Sopenharmony_ci
152562306a36Sopenharmony_ci	err = btintel_read_debug_features(hdev, &features);
152662306a36Sopenharmony_ci	if (err) {
152762306a36Sopenharmony_ci		bt_dev_info(hdev, "Error reading debug features");
152862306a36Sopenharmony_ci		return err;
152962306a36Sopenharmony_ci	}
153062306a36Sopenharmony_ci
153162306a36Sopenharmony_ci	if (!(features.page1[0] & 0x3f)) {
153262306a36Sopenharmony_ci		bt_dev_dbg(hdev, "Telemetry exception format not supported");
153362306a36Sopenharmony_ci		return -EOPNOTSUPP;
153462306a36Sopenharmony_ci	}
153562306a36Sopenharmony_ci
153662306a36Sopenharmony_ci	hci_devcd_register(hdev, btintel_coredump, btintel_dmp_hdr, NULL);
153762306a36Sopenharmony_ci
153862306a36Sopenharmony_ci	return err;
153962306a36Sopenharmony_ci}
154062306a36Sopenharmony_ci
154162306a36Sopenharmony_cistatic const struct firmware *btintel_legacy_rom_get_fw(struct hci_dev *hdev,
154262306a36Sopenharmony_ci					       struct intel_version *ver)
154362306a36Sopenharmony_ci{
154462306a36Sopenharmony_ci	const struct firmware *fw;
154562306a36Sopenharmony_ci	char fwname[64];
154662306a36Sopenharmony_ci	int ret;
154762306a36Sopenharmony_ci
154862306a36Sopenharmony_ci	snprintf(fwname, sizeof(fwname),
154962306a36Sopenharmony_ci		 "intel/ibt-hw-%x.%x.%x-fw-%x.%x.%x.%x.%x.bseq",
155062306a36Sopenharmony_ci		 ver->hw_platform, ver->hw_variant, ver->hw_revision,
155162306a36Sopenharmony_ci		 ver->fw_variant,  ver->fw_revision, ver->fw_build_num,
155262306a36Sopenharmony_ci		 ver->fw_build_ww, ver->fw_build_yy);
155362306a36Sopenharmony_ci
155462306a36Sopenharmony_ci	ret = request_firmware(&fw, fwname, &hdev->dev);
155562306a36Sopenharmony_ci	if (ret < 0) {
155662306a36Sopenharmony_ci		if (ret == -EINVAL) {
155762306a36Sopenharmony_ci			bt_dev_err(hdev, "Intel firmware file request failed (%d)",
155862306a36Sopenharmony_ci				   ret);
155962306a36Sopenharmony_ci			return NULL;
156062306a36Sopenharmony_ci		}
156162306a36Sopenharmony_ci
156262306a36Sopenharmony_ci		bt_dev_err(hdev, "failed to open Intel firmware file: %s (%d)",
156362306a36Sopenharmony_ci			   fwname, ret);
156462306a36Sopenharmony_ci
156562306a36Sopenharmony_ci		/* If the correct firmware patch file is not found, use the
156662306a36Sopenharmony_ci		 * default firmware patch file instead
156762306a36Sopenharmony_ci		 */
156862306a36Sopenharmony_ci		snprintf(fwname, sizeof(fwname), "intel/ibt-hw-%x.%x.bseq",
156962306a36Sopenharmony_ci			 ver->hw_platform, ver->hw_variant);
157062306a36Sopenharmony_ci		if (request_firmware(&fw, fwname, &hdev->dev) < 0) {
157162306a36Sopenharmony_ci			bt_dev_err(hdev, "failed to open default fw file: %s",
157262306a36Sopenharmony_ci				   fwname);
157362306a36Sopenharmony_ci			return NULL;
157462306a36Sopenharmony_ci		}
157562306a36Sopenharmony_ci	}
157662306a36Sopenharmony_ci
157762306a36Sopenharmony_ci	bt_dev_info(hdev, "Intel Bluetooth firmware file: %s", fwname);
157862306a36Sopenharmony_ci
157962306a36Sopenharmony_ci	return fw;
158062306a36Sopenharmony_ci}
158162306a36Sopenharmony_ci
158262306a36Sopenharmony_cistatic int btintel_legacy_rom_patching(struct hci_dev *hdev,
158362306a36Sopenharmony_ci				      const struct firmware *fw,
158462306a36Sopenharmony_ci				      const u8 **fw_ptr, int *disable_patch)
158562306a36Sopenharmony_ci{
158662306a36Sopenharmony_ci	struct sk_buff *skb;
158762306a36Sopenharmony_ci	struct hci_command_hdr *cmd;
158862306a36Sopenharmony_ci	const u8 *cmd_param;
158962306a36Sopenharmony_ci	struct hci_event_hdr *evt = NULL;
159062306a36Sopenharmony_ci	const u8 *evt_param = NULL;
159162306a36Sopenharmony_ci	int remain = fw->size - (*fw_ptr - fw->data);
159262306a36Sopenharmony_ci
159362306a36Sopenharmony_ci	/* The first byte indicates the types of the patch command or event.
159462306a36Sopenharmony_ci	 * 0x01 means HCI command and 0x02 is HCI event. If the first bytes
159562306a36Sopenharmony_ci	 * in the current firmware buffer doesn't start with 0x01 or
159662306a36Sopenharmony_ci	 * the size of remain buffer is smaller than HCI command header,
159762306a36Sopenharmony_ci	 * the firmware file is corrupted and it should stop the patching
159862306a36Sopenharmony_ci	 * process.
159962306a36Sopenharmony_ci	 */
160062306a36Sopenharmony_ci	if (remain > HCI_COMMAND_HDR_SIZE && *fw_ptr[0] != 0x01) {
160162306a36Sopenharmony_ci		bt_dev_err(hdev, "Intel fw corrupted: invalid cmd read");
160262306a36Sopenharmony_ci		return -EINVAL;
160362306a36Sopenharmony_ci	}
160462306a36Sopenharmony_ci	(*fw_ptr)++;
160562306a36Sopenharmony_ci	remain--;
160662306a36Sopenharmony_ci
160762306a36Sopenharmony_ci	cmd = (struct hci_command_hdr *)(*fw_ptr);
160862306a36Sopenharmony_ci	*fw_ptr += sizeof(*cmd);
160962306a36Sopenharmony_ci	remain -= sizeof(*cmd);
161062306a36Sopenharmony_ci
161162306a36Sopenharmony_ci	/* Ensure that the remain firmware data is long enough than the length
161262306a36Sopenharmony_ci	 * of command parameter. If not, the firmware file is corrupted.
161362306a36Sopenharmony_ci	 */
161462306a36Sopenharmony_ci	if (remain < cmd->plen) {
161562306a36Sopenharmony_ci		bt_dev_err(hdev, "Intel fw corrupted: invalid cmd len");
161662306a36Sopenharmony_ci		return -EFAULT;
161762306a36Sopenharmony_ci	}
161862306a36Sopenharmony_ci
161962306a36Sopenharmony_ci	/* If there is a command that loads a patch in the firmware
162062306a36Sopenharmony_ci	 * file, then enable the patch upon success, otherwise just
162162306a36Sopenharmony_ci	 * disable the manufacturer mode, for example patch activation
162262306a36Sopenharmony_ci	 * is not required when the default firmware patch file is used
162362306a36Sopenharmony_ci	 * because there are no patch data to load.
162462306a36Sopenharmony_ci	 */
162562306a36Sopenharmony_ci	if (*disable_patch && le16_to_cpu(cmd->opcode) == 0xfc8e)
162662306a36Sopenharmony_ci		*disable_patch = 0;
162762306a36Sopenharmony_ci
162862306a36Sopenharmony_ci	cmd_param = *fw_ptr;
162962306a36Sopenharmony_ci	*fw_ptr += cmd->plen;
163062306a36Sopenharmony_ci	remain -= cmd->plen;
163162306a36Sopenharmony_ci
163262306a36Sopenharmony_ci	/* This reads the expected events when the above command is sent to the
163362306a36Sopenharmony_ci	 * device. Some vendor commands expects more than one events, for
163462306a36Sopenharmony_ci	 * example command status event followed by vendor specific event.
163562306a36Sopenharmony_ci	 * For this case, it only keeps the last expected event. so the command
163662306a36Sopenharmony_ci	 * can be sent with __hci_cmd_sync_ev() which returns the sk_buff of
163762306a36Sopenharmony_ci	 * last expected event.
163862306a36Sopenharmony_ci	 */
163962306a36Sopenharmony_ci	while (remain > HCI_EVENT_HDR_SIZE && *fw_ptr[0] == 0x02) {
164062306a36Sopenharmony_ci		(*fw_ptr)++;
164162306a36Sopenharmony_ci		remain--;
164262306a36Sopenharmony_ci
164362306a36Sopenharmony_ci		evt = (struct hci_event_hdr *)(*fw_ptr);
164462306a36Sopenharmony_ci		*fw_ptr += sizeof(*evt);
164562306a36Sopenharmony_ci		remain -= sizeof(*evt);
164662306a36Sopenharmony_ci
164762306a36Sopenharmony_ci		if (remain < evt->plen) {
164862306a36Sopenharmony_ci			bt_dev_err(hdev, "Intel fw corrupted: invalid evt len");
164962306a36Sopenharmony_ci			return -EFAULT;
165062306a36Sopenharmony_ci		}
165162306a36Sopenharmony_ci
165262306a36Sopenharmony_ci		evt_param = *fw_ptr;
165362306a36Sopenharmony_ci		*fw_ptr += evt->plen;
165462306a36Sopenharmony_ci		remain -= evt->plen;
165562306a36Sopenharmony_ci	}
165662306a36Sopenharmony_ci
165762306a36Sopenharmony_ci	/* Every HCI commands in the firmware file has its correspond event.
165862306a36Sopenharmony_ci	 * If event is not found or remain is smaller than zero, the firmware
165962306a36Sopenharmony_ci	 * file is corrupted.
166062306a36Sopenharmony_ci	 */
166162306a36Sopenharmony_ci	if (!evt || !evt_param || remain < 0) {
166262306a36Sopenharmony_ci		bt_dev_err(hdev, "Intel fw corrupted: invalid evt read");
166362306a36Sopenharmony_ci		return -EFAULT;
166462306a36Sopenharmony_ci	}
166562306a36Sopenharmony_ci
166662306a36Sopenharmony_ci	skb = __hci_cmd_sync_ev(hdev, le16_to_cpu(cmd->opcode), cmd->plen,
166762306a36Sopenharmony_ci				cmd_param, evt->evt, HCI_INIT_TIMEOUT);
166862306a36Sopenharmony_ci	if (IS_ERR(skb)) {
166962306a36Sopenharmony_ci		bt_dev_err(hdev, "sending Intel patch command (0x%4.4x) failed (%ld)",
167062306a36Sopenharmony_ci			   cmd->opcode, PTR_ERR(skb));
167162306a36Sopenharmony_ci		return PTR_ERR(skb);
167262306a36Sopenharmony_ci	}
167362306a36Sopenharmony_ci
167462306a36Sopenharmony_ci	/* It ensures that the returned event matches the event data read from
167562306a36Sopenharmony_ci	 * the firmware file. At fist, it checks the length and then
167662306a36Sopenharmony_ci	 * the contents of the event.
167762306a36Sopenharmony_ci	 */
167862306a36Sopenharmony_ci	if (skb->len != evt->plen) {
167962306a36Sopenharmony_ci		bt_dev_err(hdev, "mismatch event length (opcode 0x%4.4x)",
168062306a36Sopenharmony_ci			   le16_to_cpu(cmd->opcode));
168162306a36Sopenharmony_ci		kfree_skb(skb);
168262306a36Sopenharmony_ci		return -EFAULT;
168362306a36Sopenharmony_ci	}
168462306a36Sopenharmony_ci
168562306a36Sopenharmony_ci	if (memcmp(skb->data, evt_param, evt->plen)) {
168662306a36Sopenharmony_ci		bt_dev_err(hdev, "mismatch event parameter (opcode 0x%4.4x)",
168762306a36Sopenharmony_ci			   le16_to_cpu(cmd->opcode));
168862306a36Sopenharmony_ci		kfree_skb(skb);
168962306a36Sopenharmony_ci		return -EFAULT;
169062306a36Sopenharmony_ci	}
169162306a36Sopenharmony_ci	kfree_skb(skb);
169262306a36Sopenharmony_ci
169362306a36Sopenharmony_ci	return 0;
169462306a36Sopenharmony_ci}
169562306a36Sopenharmony_ci
169662306a36Sopenharmony_cistatic int btintel_legacy_rom_setup(struct hci_dev *hdev,
169762306a36Sopenharmony_ci				    struct intel_version *ver)
169862306a36Sopenharmony_ci{
169962306a36Sopenharmony_ci	const struct firmware *fw;
170062306a36Sopenharmony_ci	const u8 *fw_ptr;
170162306a36Sopenharmony_ci	int disable_patch, err;
170262306a36Sopenharmony_ci	struct intel_version new_ver;
170362306a36Sopenharmony_ci
170462306a36Sopenharmony_ci	BT_DBG("%s", hdev->name);
170562306a36Sopenharmony_ci
170662306a36Sopenharmony_ci	/* fw_patch_num indicates the version of patch the device currently
170762306a36Sopenharmony_ci	 * have. If there is no patch data in the device, it is always 0x00.
170862306a36Sopenharmony_ci	 * So, if it is other than 0x00, no need to patch the device again.
170962306a36Sopenharmony_ci	 */
171062306a36Sopenharmony_ci	if (ver->fw_patch_num) {
171162306a36Sopenharmony_ci		bt_dev_info(hdev,
171262306a36Sopenharmony_ci			    "Intel device is already patched. patch num: %02x",
171362306a36Sopenharmony_ci			    ver->fw_patch_num);
171462306a36Sopenharmony_ci		goto complete;
171562306a36Sopenharmony_ci	}
171662306a36Sopenharmony_ci
171762306a36Sopenharmony_ci	/* Opens the firmware patch file based on the firmware version read
171862306a36Sopenharmony_ci	 * from the controller. If it fails to open the matching firmware
171962306a36Sopenharmony_ci	 * patch file, it tries to open the default firmware patch file.
172062306a36Sopenharmony_ci	 * If no patch file is found, allow the device to operate without
172162306a36Sopenharmony_ci	 * a patch.
172262306a36Sopenharmony_ci	 */
172362306a36Sopenharmony_ci	fw = btintel_legacy_rom_get_fw(hdev, ver);
172462306a36Sopenharmony_ci	if (!fw)
172562306a36Sopenharmony_ci		goto complete;
172662306a36Sopenharmony_ci	fw_ptr = fw->data;
172762306a36Sopenharmony_ci
172862306a36Sopenharmony_ci	/* Enable the manufacturer mode of the controller.
172962306a36Sopenharmony_ci	 * Only while this mode is enabled, the driver can download the
173062306a36Sopenharmony_ci	 * firmware patch data and configuration parameters.
173162306a36Sopenharmony_ci	 */
173262306a36Sopenharmony_ci	err = btintel_enter_mfg(hdev);
173362306a36Sopenharmony_ci	if (err) {
173462306a36Sopenharmony_ci		release_firmware(fw);
173562306a36Sopenharmony_ci		return err;
173662306a36Sopenharmony_ci	}
173762306a36Sopenharmony_ci
173862306a36Sopenharmony_ci	disable_patch = 1;
173962306a36Sopenharmony_ci
174062306a36Sopenharmony_ci	/* The firmware data file consists of list of Intel specific HCI
174162306a36Sopenharmony_ci	 * commands and its expected events. The first byte indicates the
174262306a36Sopenharmony_ci	 * type of the message, either HCI command or HCI event.
174362306a36Sopenharmony_ci	 *
174462306a36Sopenharmony_ci	 * It reads the command and its expected event from the firmware file,
174562306a36Sopenharmony_ci	 * and send to the controller. Once __hci_cmd_sync_ev() returns,
174662306a36Sopenharmony_ci	 * the returned event is compared with the event read from the firmware
174762306a36Sopenharmony_ci	 * file and it will continue until all the messages are downloaded to
174862306a36Sopenharmony_ci	 * the controller.
174962306a36Sopenharmony_ci	 *
175062306a36Sopenharmony_ci	 * Once the firmware patching is completed successfully,
175162306a36Sopenharmony_ci	 * the manufacturer mode is disabled with reset and activating the
175262306a36Sopenharmony_ci	 * downloaded patch.
175362306a36Sopenharmony_ci	 *
175462306a36Sopenharmony_ci	 * If the firmware patching fails, the manufacturer mode is
175562306a36Sopenharmony_ci	 * disabled with reset and deactivating the patch.
175662306a36Sopenharmony_ci	 *
175762306a36Sopenharmony_ci	 * If the default patch file is used, no reset is done when disabling
175862306a36Sopenharmony_ci	 * the manufacturer.
175962306a36Sopenharmony_ci	 */
176062306a36Sopenharmony_ci	while (fw->size > fw_ptr - fw->data) {
176162306a36Sopenharmony_ci		int ret;
176262306a36Sopenharmony_ci
176362306a36Sopenharmony_ci		ret = btintel_legacy_rom_patching(hdev, fw, &fw_ptr,
176462306a36Sopenharmony_ci						 &disable_patch);
176562306a36Sopenharmony_ci		if (ret < 0)
176662306a36Sopenharmony_ci			goto exit_mfg_deactivate;
176762306a36Sopenharmony_ci	}
176862306a36Sopenharmony_ci
176962306a36Sopenharmony_ci	release_firmware(fw);
177062306a36Sopenharmony_ci
177162306a36Sopenharmony_ci	if (disable_patch)
177262306a36Sopenharmony_ci		goto exit_mfg_disable;
177362306a36Sopenharmony_ci
177462306a36Sopenharmony_ci	/* Patching completed successfully and disable the manufacturer mode
177562306a36Sopenharmony_ci	 * with reset and activate the downloaded firmware patches.
177662306a36Sopenharmony_ci	 */
177762306a36Sopenharmony_ci	err = btintel_exit_mfg(hdev, true, true);
177862306a36Sopenharmony_ci	if (err)
177962306a36Sopenharmony_ci		return err;
178062306a36Sopenharmony_ci
178162306a36Sopenharmony_ci	/* Need build number for downloaded fw patches in
178262306a36Sopenharmony_ci	 * every power-on boot
178362306a36Sopenharmony_ci	 */
178462306a36Sopenharmony_ci	err = btintel_read_version(hdev, &new_ver);
178562306a36Sopenharmony_ci	if (err)
178662306a36Sopenharmony_ci		return err;
178762306a36Sopenharmony_ci
178862306a36Sopenharmony_ci	bt_dev_info(hdev, "Intel BT fw patch 0x%02x completed & activated",
178962306a36Sopenharmony_ci		    new_ver.fw_patch_num);
179062306a36Sopenharmony_ci
179162306a36Sopenharmony_ci	goto complete;
179262306a36Sopenharmony_ci
179362306a36Sopenharmony_ciexit_mfg_disable:
179462306a36Sopenharmony_ci	/* Disable the manufacturer mode without reset */
179562306a36Sopenharmony_ci	err = btintel_exit_mfg(hdev, false, false);
179662306a36Sopenharmony_ci	if (err)
179762306a36Sopenharmony_ci		return err;
179862306a36Sopenharmony_ci
179962306a36Sopenharmony_ci	bt_dev_info(hdev, "Intel firmware patch completed");
180062306a36Sopenharmony_ci
180162306a36Sopenharmony_ci	goto complete;
180262306a36Sopenharmony_ci
180362306a36Sopenharmony_ciexit_mfg_deactivate:
180462306a36Sopenharmony_ci	release_firmware(fw);
180562306a36Sopenharmony_ci
180662306a36Sopenharmony_ci	/* Patching failed. Disable the manufacturer mode with reset and
180762306a36Sopenharmony_ci	 * deactivate the downloaded firmware patches.
180862306a36Sopenharmony_ci	 */
180962306a36Sopenharmony_ci	err = btintel_exit_mfg(hdev, true, false);
181062306a36Sopenharmony_ci	if (err)
181162306a36Sopenharmony_ci		return err;
181262306a36Sopenharmony_ci
181362306a36Sopenharmony_ci	bt_dev_info(hdev, "Intel firmware patch completed and deactivated");
181462306a36Sopenharmony_ci
181562306a36Sopenharmony_cicomplete:
181662306a36Sopenharmony_ci	/* Set the event mask for Intel specific vendor events. This enables
181762306a36Sopenharmony_ci	 * a few extra events that are useful during general operation.
181862306a36Sopenharmony_ci	 */
181962306a36Sopenharmony_ci	btintel_set_event_mask_mfg(hdev, false);
182062306a36Sopenharmony_ci
182162306a36Sopenharmony_ci	btintel_check_bdaddr(hdev);
182262306a36Sopenharmony_ci
182362306a36Sopenharmony_ci	return 0;
182462306a36Sopenharmony_ci}
182562306a36Sopenharmony_ci
182662306a36Sopenharmony_cistatic int btintel_download_wait(struct hci_dev *hdev, ktime_t calltime, int msec)
182762306a36Sopenharmony_ci{
182862306a36Sopenharmony_ci	ktime_t delta, rettime;
182962306a36Sopenharmony_ci	unsigned long long duration;
183062306a36Sopenharmony_ci	int err;
183162306a36Sopenharmony_ci
183262306a36Sopenharmony_ci	btintel_set_flag(hdev, INTEL_FIRMWARE_LOADED);
183362306a36Sopenharmony_ci
183462306a36Sopenharmony_ci	bt_dev_info(hdev, "Waiting for firmware download to complete");
183562306a36Sopenharmony_ci
183662306a36Sopenharmony_ci	err = btintel_wait_on_flag_timeout(hdev, INTEL_DOWNLOADING,
183762306a36Sopenharmony_ci					   TASK_INTERRUPTIBLE,
183862306a36Sopenharmony_ci					   msecs_to_jiffies(msec));
183962306a36Sopenharmony_ci	if (err == -EINTR) {
184062306a36Sopenharmony_ci		bt_dev_err(hdev, "Firmware loading interrupted");
184162306a36Sopenharmony_ci		return err;
184262306a36Sopenharmony_ci	}
184362306a36Sopenharmony_ci
184462306a36Sopenharmony_ci	if (err) {
184562306a36Sopenharmony_ci		bt_dev_err(hdev, "Firmware loading timeout");
184662306a36Sopenharmony_ci		return -ETIMEDOUT;
184762306a36Sopenharmony_ci	}
184862306a36Sopenharmony_ci
184962306a36Sopenharmony_ci	if (btintel_test_flag(hdev, INTEL_FIRMWARE_FAILED)) {
185062306a36Sopenharmony_ci		bt_dev_err(hdev, "Firmware loading failed");
185162306a36Sopenharmony_ci		return -ENOEXEC;
185262306a36Sopenharmony_ci	}
185362306a36Sopenharmony_ci
185462306a36Sopenharmony_ci	rettime = ktime_get();
185562306a36Sopenharmony_ci	delta = ktime_sub(rettime, calltime);
185662306a36Sopenharmony_ci	duration = (unsigned long long)ktime_to_ns(delta) >> 10;
185762306a36Sopenharmony_ci
185862306a36Sopenharmony_ci	bt_dev_info(hdev, "Firmware loaded in %llu usecs", duration);
185962306a36Sopenharmony_ci
186062306a36Sopenharmony_ci	return 0;
186162306a36Sopenharmony_ci}
186262306a36Sopenharmony_ci
186362306a36Sopenharmony_cistatic int btintel_boot_wait(struct hci_dev *hdev, ktime_t calltime, int msec)
186462306a36Sopenharmony_ci{
186562306a36Sopenharmony_ci	ktime_t delta, rettime;
186662306a36Sopenharmony_ci	unsigned long long duration;
186762306a36Sopenharmony_ci	int err;
186862306a36Sopenharmony_ci
186962306a36Sopenharmony_ci	bt_dev_info(hdev, "Waiting for device to boot");
187062306a36Sopenharmony_ci
187162306a36Sopenharmony_ci	err = btintel_wait_on_flag_timeout(hdev, INTEL_BOOTING,
187262306a36Sopenharmony_ci					   TASK_INTERRUPTIBLE,
187362306a36Sopenharmony_ci					   msecs_to_jiffies(msec));
187462306a36Sopenharmony_ci	if (err == -EINTR) {
187562306a36Sopenharmony_ci		bt_dev_err(hdev, "Device boot interrupted");
187662306a36Sopenharmony_ci		return -EINTR;
187762306a36Sopenharmony_ci	}
187862306a36Sopenharmony_ci
187962306a36Sopenharmony_ci	if (err) {
188062306a36Sopenharmony_ci		bt_dev_err(hdev, "Device boot timeout");
188162306a36Sopenharmony_ci		return -ETIMEDOUT;
188262306a36Sopenharmony_ci	}
188362306a36Sopenharmony_ci
188462306a36Sopenharmony_ci	rettime = ktime_get();
188562306a36Sopenharmony_ci	delta = ktime_sub(rettime, calltime);
188662306a36Sopenharmony_ci	duration = (unsigned long long) ktime_to_ns(delta) >> 10;
188762306a36Sopenharmony_ci
188862306a36Sopenharmony_ci	bt_dev_info(hdev, "Device booted in %llu usecs", duration);
188962306a36Sopenharmony_ci
189062306a36Sopenharmony_ci	return 0;
189162306a36Sopenharmony_ci}
189262306a36Sopenharmony_ci
189362306a36Sopenharmony_cistatic int btintel_boot(struct hci_dev *hdev, u32 boot_addr)
189462306a36Sopenharmony_ci{
189562306a36Sopenharmony_ci	ktime_t calltime;
189662306a36Sopenharmony_ci	int err;
189762306a36Sopenharmony_ci
189862306a36Sopenharmony_ci	calltime = ktime_get();
189962306a36Sopenharmony_ci
190062306a36Sopenharmony_ci	btintel_set_flag(hdev, INTEL_BOOTING);
190162306a36Sopenharmony_ci
190262306a36Sopenharmony_ci	err = btintel_send_intel_reset(hdev, boot_addr);
190362306a36Sopenharmony_ci	if (err) {
190462306a36Sopenharmony_ci		bt_dev_err(hdev, "Intel Soft Reset failed (%d)", err);
190562306a36Sopenharmony_ci		btintel_reset_to_bootloader(hdev);
190662306a36Sopenharmony_ci		return err;
190762306a36Sopenharmony_ci	}
190862306a36Sopenharmony_ci
190962306a36Sopenharmony_ci	/* The bootloader will not indicate when the device is ready. This
191062306a36Sopenharmony_ci	 * is done by the operational firmware sending bootup notification.
191162306a36Sopenharmony_ci	 *
191262306a36Sopenharmony_ci	 * Booting into operational firmware should not take longer than
191362306a36Sopenharmony_ci	 * 1 second. However if that happens, then just fail the setup
191462306a36Sopenharmony_ci	 * since something went wrong.
191562306a36Sopenharmony_ci	 */
191662306a36Sopenharmony_ci	err = btintel_boot_wait(hdev, calltime, 1000);
191762306a36Sopenharmony_ci	if (err == -ETIMEDOUT)
191862306a36Sopenharmony_ci		btintel_reset_to_bootloader(hdev);
191962306a36Sopenharmony_ci
192062306a36Sopenharmony_ci	return err;
192162306a36Sopenharmony_ci}
192262306a36Sopenharmony_ci
192362306a36Sopenharmony_cistatic int btintel_get_fw_name(struct intel_version *ver,
192462306a36Sopenharmony_ci					     struct intel_boot_params *params,
192562306a36Sopenharmony_ci					     char *fw_name, size_t len,
192662306a36Sopenharmony_ci					     const char *suffix)
192762306a36Sopenharmony_ci{
192862306a36Sopenharmony_ci	switch (ver->hw_variant) {
192962306a36Sopenharmony_ci	case 0x0b:	/* SfP */
193062306a36Sopenharmony_ci	case 0x0c:	/* WsP */
193162306a36Sopenharmony_ci		snprintf(fw_name, len, "intel/ibt-%u-%u.%s",
193262306a36Sopenharmony_ci			 ver->hw_variant,
193362306a36Sopenharmony_ci			 le16_to_cpu(params->dev_revid),
193462306a36Sopenharmony_ci			 suffix);
193562306a36Sopenharmony_ci		break;
193662306a36Sopenharmony_ci	case 0x11:	/* JfP */
193762306a36Sopenharmony_ci	case 0x12:	/* ThP */
193862306a36Sopenharmony_ci	case 0x13:	/* HrP */
193962306a36Sopenharmony_ci	case 0x14:	/* CcP */
194062306a36Sopenharmony_ci		snprintf(fw_name, len, "intel/ibt-%u-%u-%u.%s",
194162306a36Sopenharmony_ci			 ver->hw_variant,
194262306a36Sopenharmony_ci			 ver->hw_revision,
194362306a36Sopenharmony_ci			 ver->fw_revision,
194462306a36Sopenharmony_ci			 suffix);
194562306a36Sopenharmony_ci		break;
194662306a36Sopenharmony_ci	default:
194762306a36Sopenharmony_ci		return -EINVAL;
194862306a36Sopenharmony_ci	}
194962306a36Sopenharmony_ci
195062306a36Sopenharmony_ci	return 0;
195162306a36Sopenharmony_ci}
195262306a36Sopenharmony_ci
195362306a36Sopenharmony_cistatic int btintel_download_fw(struct hci_dev *hdev,
195462306a36Sopenharmony_ci					 struct intel_version *ver,
195562306a36Sopenharmony_ci					 struct intel_boot_params *params,
195662306a36Sopenharmony_ci					 u32 *boot_param)
195762306a36Sopenharmony_ci{
195862306a36Sopenharmony_ci	const struct firmware *fw;
195962306a36Sopenharmony_ci	char fwname[64];
196062306a36Sopenharmony_ci	int err;
196162306a36Sopenharmony_ci	ktime_t calltime;
196262306a36Sopenharmony_ci
196362306a36Sopenharmony_ci	if (!ver || !params)
196462306a36Sopenharmony_ci		return -EINVAL;
196562306a36Sopenharmony_ci
196662306a36Sopenharmony_ci	/* The firmware variant determines if the device is in bootloader
196762306a36Sopenharmony_ci	 * mode or is running operational firmware. The value 0x06 identifies
196862306a36Sopenharmony_ci	 * the bootloader and the value 0x23 identifies the operational
196962306a36Sopenharmony_ci	 * firmware.
197062306a36Sopenharmony_ci	 *
197162306a36Sopenharmony_ci	 * When the operational firmware is already present, then only
197262306a36Sopenharmony_ci	 * the check for valid Bluetooth device address is needed. This
197362306a36Sopenharmony_ci	 * determines if the device will be added as configured or
197462306a36Sopenharmony_ci	 * unconfigured controller.
197562306a36Sopenharmony_ci	 *
197662306a36Sopenharmony_ci	 * It is not possible to use the Secure Boot Parameters in this
197762306a36Sopenharmony_ci	 * case since that command is only available in bootloader mode.
197862306a36Sopenharmony_ci	 */
197962306a36Sopenharmony_ci	if (ver->fw_variant == 0x23) {
198062306a36Sopenharmony_ci		btintel_clear_flag(hdev, INTEL_BOOTLOADER);
198162306a36Sopenharmony_ci		btintel_check_bdaddr(hdev);
198262306a36Sopenharmony_ci
198362306a36Sopenharmony_ci		/* SfP and WsP don't seem to update the firmware version on file
198462306a36Sopenharmony_ci		 * so version checking is currently possible.
198562306a36Sopenharmony_ci		 */
198662306a36Sopenharmony_ci		switch (ver->hw_variant) {
198762306a36Sopenharmony_ci		case 0x0b:	/* SfP */
198862306a36Sopenharmony_ci		case 0x0c:	/* WsP */
198962306a36Sopenharmony_ci			return 0;
199062306a36Sopenharmony_ci		}
199162306a36Sopenharmony_ci
199262306a36Sopenharmony_ci		/* Proceed to download to check if the version matches */
199362306a36Sopenharmony_ci		goto download;
199462306a36Sopenharmony_ci	}
199562306a36Sopenharmony_ci
199662306a36Sopenharmony_ci	/* Read the secure boot parameters to identify the operating
199762306a36Sopenharmony_ci	 * details of the bootloader.
199862306a36Sopenharmony_ci	 */
199962306a36Sopenharmony_ci	err = btintel_read_boot_params(hdev, params);
200062306a36Sopenharmony_ci	if (err)
200162306a36Sopenharmony_ci		return err;
200262306a36Sopenharmony_ci
200362306a36Sopenharmony_ci	/* It is required that every single firmware fragment is acknowledged
200462306a36Sopenharmony_ci	 * with a command complete event. If the boot parameters indicate
200562306a36Sopenharmony_ci	 * that this bootloader does not send them, then abort the setup.
200662306a36Sopenharmony_ci	 */
200762306a36Sopenharmony_ci	if (params->limited_cce != 0x00) {
200862306a36Sopenharmony_ci		bt_dev_err(hdev, "Unsupported Intel firmware loading method (%u)",
200962306a36Sopenharmony_ci			   params->limited_cce);
201062306a36Sopenharmony_ci		return -EINVAL;
201162306a36Sopenharmony_ci	}
201262306a36Sopenharmony_ci
201362306a36Sopenharmony_ci	/* If the OTP has no valid Bluetooth device address, then there will
201462306a36Sopenharmony_ci	 * also be no valid address for the operational firmware.
201562306a36Sopenharmony_ci	 */
201662306a36Sopenharmony_ci	if (!bacmp(&params->otp_bdaddr, BDADDR_ANY)) {
201762306a36Sopenharmony_ci		bt_dev_info(hdev, "No device address configured");
201862306a36Sopenharmony_ci		set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks);
201962306a36Sopenharmony_ci	}
202062306a36Sopenharmony_ci
202162306a36Sopenharmony_cidownload:
202262306a36Sopenharmony_ci	/* With this Intel bootloader only the hardware variant and device
202362306a36Sopenharmony_ci	 * revision information are used to select the right firmware for SfP
202462306a36Sopenharmony_ci	 * and WsP.
202562306a36Sopenharmony_ci	 *
202662306a36Sopenharmony_ci	 * The firmware filename is ibt-<hw_variant>-<dev_revid>.sfi.
202762306a36Sopenharmony_ci	 *
202862306a36Sopenharmony_ci	 * Currently the supported hardware variants are:
202962306a36Sopenharmony_ci	 *   11 (0x0b) for iBT3.0 (LnP/SfP)
203062306a36Sopenharmony_ci	 *   12 (0x0c) for iBT3.5 (WsP)
203162306a36Sopenharmony_ci	 *
203262306a36Sopenharmony_ci	 * For ThP/JfP and for future SKU's, the FW name varies based on HW
203362306a36Sopenharmony_ci	 * variant, HW revision and FW revision, as these are dependent on CNVi
203462306a36Sopenharmony_ci	 * and RF Combination.
203562306a36Sopenharmony_ci	 *
203662306a36Sopenharmony_ci	 *   17 (0x11) for iBT3.5 (JfP)
203762306a36Sopenharmony_ci	 *   18 (0x12) for iBT3.5 (ThP)
203862306a36Sopenharmony_ci	 *
203962306a36Sopenharmony_ci	 * The firmware file name for these will be
204062306a36Sopenharmony_ci	 * ibt-<hw_variant>-<hw_revision>-<fw_revision>.sfi.
204162306a36Sopenharmony_ci	 *
204262306a36Sopenharmony_ci	 */
204362306a36Sopenharmony_ci	err = btintel_get_fw_name(ver, params, fwname, sizeof(fwname), "sfi");
204462306a36Sopenharmony_ci	if (err < 0) {
204562306a36Sopenharmony_ci		if (!btintel_test_flag(hdev, INTEL_BOOTLOADER)) {
204662306a36Sopenharmony_ci			/* Firmware has already been loaded */
204762306a36Sopenharmony_ci			btintel_set_flag(hdev, INTEL_FIRMWARE_LOADED);
204862306a36Sopenharmony_ci			return 0;
204962306a36Sopenharmony_ci		}
205062306a36Sopenharmony_ci
205162306a36Sopenharmony_ci		bt_dev_err(hdev, "Unsupported Intel firmware naming");
205262306a36Sopenharmony_ci		return -EINVAL;
205362306a36Sopenharmony_ci	}
205462306a36Sopenharmony_ci
205562306a36Sopenharmony_ci	err = firmware_request_nowarn(&fw, fwname, &hdev->dev);
205662306a36Sopenharmony_ci	if (err < 0) {
205762306a36Sopenharmony_ci		if (!btintel_test_flag(hdev, INTEL_BOOTLOADER)) {
205862306a36Sopenharmony_ci			/* Firmware has already been loaded */
205962306a36Sopenharmony_ci			btintel_set_flag(hdev, INTEL_FIRMWARE_LOADED);
206062306a36Sopenharmony_ci			return 0;
206162306a36Sopenharmony_ci		}
206262306a36Sopenharmony_ci
206362306a36Sopenharmony_ci		bt_dev_err(hdev, "Failed to load Intel firmware file %s (%d)",
206462306a36Sopenharmony_ci			   fwname, err);
206562306a36Sopenharmony_ci		return err;
206662306a36Sopenharmony_ci	}
206762306a36Sopenharmony_ci
206862306a36Sopenharmony_ci	bt_dev_info(hdev, "Found device firmware: %s", fwname);
206962306a36Sopenharmony_ci
207062306a36Sopenharmony_ci	if (fw->size < 644) {
207162306a36Sopenharmony_ci		bt_dev_err(hdev, "Invalid size of firmware file (%zu)",
207262306a36Sopenharmony_ci			   fw->size);
207362306a36Sopenharmony_ci		err = -EBADF;
207462306a36Sopenharmony_ci		goto done;
207562306a36Sopenharmony_ci	}
207662306a36Sopenharmony_ci
207762306a36Sopenharmony_ci	calltime = ktime_get();
207862306a36Sopenharmony_ci
207962306a36Sopenharmony_ci	btintel_set_flag(hdev, INTEL_DOWNLOADING);
208062306a36Sopenharmony_ci
208162306a36Sopenharmony_ci	/* Start firmware downloading and get boot parameter */
208262306a36Sopenharmony_ci	err = btintel_download_firmware(hdev, ver, fw, boot_param);
208362306a36Sopenharmony_ci	if (err < 0) {
208462306a36Sopenharmony_ci		if (err == -EALREADY) {
208562306a36Sopenharmony_ci			/* Firmware has already been loaded */
208662306a36Sopenharmony_ci			btintel_set_flag(hdev, INTEL_FIRMWARE_LOADED);
208762306a36Sopenharmony_ci			err = 0;
208862306a36Sopenharmony_ci			goto done;
208962306a36Sopenharmony_ci		}
209062306a36Sopenharmony_ci
209162306a36Sopenharmony_ci		/* When FW download fails, send Intel Reset to retry
209262306a36Sopenharmony_ci		 * FW download.
209362306a36Sopenharmony_ci		 */
209462306a36Sopenharmony_ci		btintel_reset_to_bootloader(hdev);
209562306a36Sopenharmony_ci		goto done;
209662306a36Sopenharmony_ci	}
209762306a36Sopenharmony_ci
209862306a36Sopenharmony_ci	/* Before switching the device into operational mode and with that
209962306a36Sopenharmony_ci	 * booting the loaded firmware, wait for the bootloader notification
210062306a36Sopenharmony_ci	 * that all fragments have been successfully received.
210162306a36Sopenharmony_ci	 *
210262306a36Sopenharmony_ci	 * When the event processing receives the notification, then the
210362306a36Sopenharmony_ci	 * INTEL_DOWNLOADING flag will be cleared.
210462306a36Sopenharmony_ci	 *
210562306a36Sopenharmony_ci	 * The firmware loading should not take longer than 5 seconds
210662306a36Sopenharmony_ci	 * and thus just timeout if that happens and fail the setup
210762306a36Sopenharmony_ci	 * of this device.
210862306a36Sopenharmony_ci	 */
210962306a36Sopenharmony_ci	err = btintel_download_wait(hdev, calltime, 5000);
211062306a36Sopenharmony_ci	if (err == -ETIMEDOUT)
211162306a36Sopenharmony_ci		btintel_reset_to_bootloader(hdev);
211262306a36Sopenharmony_ci
211362306a36Sopenharmony_cidone:
211462306a36Sopenharmony_ci	release_firmware(fw);
211562306a36Sopenharmony_ci	return err;
211662306a36Sopenharmony_ci}
211762306a36Sopenharmony_ci
211862306a36Sopenharmony_cistatic int btintel_bootloader_setup(struct hci_dev *hdev,
211962306a36Sopenharmony_ci				    struct intel_version *ver)
212062306a36Sopenharmony_ci{
212162306a36Sopenharmony_ci	struct intel_version new_ver;
212262306a36Sopenharmony_ci	struct intel_boot_params params;
212362306a36Sopenharmony_ci	u32 boot_param;
212462306a36Sopenharmony_ci	char ddcname[64];
212562306a36Sopenharmony_ci	int err;
212662306a36Sopenharmony_ci
212762306a36Sopenharmony_ci	BT_DBG("%s", hdev->name);
212862306a36Sopenharmony_ci
212962306a36Sopenharmony_ci	/* Set the default boot parameter to 0x0 and it is updated to
213062306a36Sopenharmony_ci	 * SKU specific boot parameter after reading Intel_Write_Boot_Params
213162306a36Sopenharmony_ci	 * command while downloading the firmware.
213262306a36Sopenharmony_ci	 */
213362306a36Sopenharmony_ci	boot_param = 0x00000000;
213462306a36Sopenharmony_ci
213562306a36Sopenharmony_ci	btintel_set_flag(hdev, INTEL_BOOTLOADER);
213662306a36Sopenharmony_ci
213762306a36Sopenharmony_ci	err = btintel_download_fw(hdev, ver, &params, &boot_param);
213862306a36Sopenharmony_ci	if (err)
213962306a36Sopenharmony_ci		return err;
214062306a36Sopenharmony_ci
214162306a36Sopenharmony_ci	/* controller is already having an operational firmware */
214262306a36Sopenharmony_ci	if (ver->fw_variant == 0x23)
214362306a36Sopenharmony_ci		goto finish;
214462306a36Sopenharmony_ci
214562306a36Sopenharmony_ci	err = btintel_boot(hdev, boot_param);
214662306a36Sopenharmony_ci	if (err)
214762306a36Sopenharmony_ci		return err;
214862306a36Sopenharmony_ci
214962306a36Sopenharmony_ci	btintel_clear_flag(hdev, INTEL_BOOTLOADER);
215062306a36Sopenharmony_ci
215162306a36Sopenharmony_ci	err = btintel_get_fw_name(ver, &params, ddcname,
215262306a36Sopenharmony_ci						sizeof(ddcname), "ddc");
215362306a36Sopenharmony_ci
215462306a36Sopenharmony_ci	if (err < 0) {
215562306a36Sopenharmony_ci		bt_dev_err(hdev, "Unsupported Intel firmware naming");
215662306a36Sopenharmony_ci	} else {
215762306a36Sopenharmony_ci		/* Once the device is running in operational mode, it needs to
215862306a36Sopenharmony_ci		 * apply the device configuration (DDC) parameters.
215962306a36Sopenharmony_ci		 *
216062306a36Sopenharmony_ci		 * The device can work without DDC parameters, so even if it
216162306a36Sopenharmony_ci		 * fails to load the file, no need to fail the setup.
216262306a36Sopenharmony_ci		 */
216362306a36Sopenharmony_ci		btintel_load_ddc_config(hdev, ddcname);
216462306a36Sopenharmony_ci	}
216562306a36Sopenharmony_ci
216662306a36Sopenharmony_ci	hci_dev_clear_flag(hdev, HCI_QUALITY_REPORT);
216762306a36Sopenharmony_ci
216862306a36Sopenharmony_ci	/* Read the Intel version information after loading the FW  */
216962306a36Sopenharmony_ci	err = btintel_read_version(hdev, &new_ver);
217062306a36Sopenharmony_ci	if (err)
217162306a36Sopenharmony_ci		return err;
217262306a36Sopenharmony_ci
217362306a36Sopenharmony_ci	btintel_version_info(hdev, &new_ver);
217462306a36Sopenharmony_ci
217562306a36Sopenharmony_cifinish:
217662306a36Sopenharmony_ci	/* Set the event mask for Intel specific vendor events. This enables
217762306a36Sopenharmony_ci	 * a few extra events that are useful during general operation. It
217862306a36Sopenharmony_ci	 * does not enable any debugging related events.
217962306a36Sopenharmony_ci	 *
218062306a36Sopenharmony_ci	 * The device will function correctly without these events enabled
218162306a36Sopenharmony_ci	 * and thus no need to fail the setup.
218262306a36Sopenharmony_ci	 */
218362306a36Sopenharmony_ci	btintel_set_event_mask(hdev, false);
218462306a36Sopenharmony_ci
218562306a36Sopenharmony_ci	return 0;
218662306a36Sopenharmony_ci}
218762306a36Sopenharmony_ci
218862306a36Sopenharmony_cistatic void btintel_get_fw_name_tlv(const struct intel_version_tlv *ver,
218962306a36Sopenharmony_ci				    char *fw_name, size_t len,
219062306a36Sopenharmony_ci				    const char *suffix)
219162306a36Sopenharmony_ci{
219262306a36Sopenharmony_ci	/* The firmware file name for new generation controllers will be
219362306a36Sopenharmony_ci	 * ibt-<cnvi_top type+cnvi_top step>-<cnvr_top type+cnvr_top step>
219462306a36Sopenharmony_ci	 */
219562306a36Sopenharmony_ci	snprintf(fw_name, len, "intel/ibt-%04x-%04x.%s",
219662306a36Sopenharmony_ci		 INTEL_CNVX_TOP_PACK_SWAB(INTEL_CNVX_TOP_TYPE(ver->cnvi_top),
219762306a36Sopenharmony_ci					  INTEL_CNVX_TOP_STEP(ver->cnvi_top)),
219862306a36Sopenharmony_ci		 INTEL_CNVX_TOP_PACK_SWAB(INTEL_CNVX_TOP_TYPE(ver->cnvr_top),
219962306a36Sopenharmony_ci					  INTEL_CNVX_TOP_STEP(ver->cnvr_top)),
220062306a36Sopenharmony_ci		 suffix);
220162306a36Sopenharmony_ci}
220262306a36Sopenharmony_ci
220362306a36Sopenharmony_cistatic int btintel_prepare_fw_download_tlv(struct hci_dev *hdev,
220462306a36Sopenharmony_ci					   struct intel_version_tlv *ver,
220562306a36Sopenharmony_ci					   u32 *boot_param)
220662306a36Sopenharmony_ci{
220762306a36Sopenharmony_ci	const struct firmware *fw;
220862306a36Sopenharmony_ci	char fwname[64];
220962306a36Sopenharmony_ci	int err;
221062306a36Sopenharmony_ci	ktime_t calltime;
221162306a36Sopenharmony_ci
221262306a36Sopenharmony_ci	if (!ver || !boot_param)
221362306a36Sopenharmony_ci		return -EINVAL;
221462306a36Sopenharmony_ci
221562306a36Sopenharmony_ci	/* The firmware variant determines if the device is in bootloader
221662306a36Sopenharmony_ci	 * mode or is running operational firmware. The value 0x03 identifies
221762306a36Sopenharmony_ci	 * the bootloader and the value 0x23 identifies the operational
221862306a36Sopenharmony_ci	 * firmware.
221962306a36Sopenharmony_ci	 *
222062306a36Sopenharmony_ci	 * When the operational firmware is already present, then only
222162306a36Sopenharmony_ci	 * the check for valid Bluetooth device address is needed. This
222262306a36Sopenharmony_ci	 * determines if the device will be added as configured or
222362306a36Sopenharmony_ci	 * unconfigured controller.
222462306a36Sopenharmony_ci	 *
222562306a36Sopenharmony_ci	 * It is not possible to use the Secure Boot Parameters in this
222662306a36Sopenharmony_ci	 * case since that command is only available in bootloader mode.
222762306a36Sopenharmony_ci	 */
222862306a36Sopenharmony_ci	if (ver->img_type == 0x03) {
222962306a36Sopenharmony_ci		btintel_clear_flag(hdev, INTEL_BOOTLOADER);
223062306a36Sopenharmony_ci		btintel_check_bdaddr(hdev);
223162306a36Sopenharmony_ci	} else {
223262306a36Sopenharmony_ci		/*
223362306a36Sopenharmony_ci		 * Check for valid bd address in boot loader mode. Device
223462306a36Sopenharmony_ci		 * will be marked as unconfigured if empty bd address is
223562306a36Sopenharmony_ci		 * found.
223662306a36Sopenharmony_ci		 */
223762306a36Sopenharmony_ci		if (!bacmp(&ver->otp_bd_addr, BDADDR_ANY)) {
223862306a36Sopenharmony_ci			bt_dev_info(hdev, "No device address configured");
223962306a36Sopenharmony_ci			set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks);
224062306a36Sopenharmony_ci		}
224162306a36Sopenharmony_ci	}
224262306a36Sopenharmony_ci
224362306a36Sopenharmony_ci	btintel_get_fw_name_tlv(ver, fwname, sizeof(fwname), "sfi");
224462306a36Sopenharmony_ci	err = firmware_request_nowarn(&fw, fwname, &hdev->dev);
224562306a36Sopenharmony_ci	if (err < 0) {
224662306a36Sopenharmony_ci		if (!btintel_test_flag(hdev, INTEL_BOOTLOADER)) {
224762306a36Sopenharmony_ci			/* Firmware has already been loaded */
224862306a36Sopenharmony_ci			btintel_set_flag(hdev, INTEL_FIRMWARE_LOADED);
224962306a36Sopenharmony_ci			return 0;
225062306a36Sopenharmony_ci		}
225162306a36Sopenharmony_ci
225262306a36Sopenharmony_ci		bt_dev_err(hdev, "Failed to load Intel firmware file %s (%d)",
225362306a36Sopenharmony_ci			   fwname, err);
225462306a36Sopenharmony_ci
225562306a36Sopenharmony_ci		return err;
225662306a36Sopenharmony_ci	}
225762306a36Sopenharmony_ci
225862306a36Sopenharmony_ci	bt_dev_info(hdev, "Found device firmware: %s", fwname);
225962306a36Sopenharmony_ci
226062306a36Sopenharmony_ci	if (fw->size < 644) {
226162306a36Sopenharmony_ci		bt_dev_err(hdev, "Invalid size of firmware file (%zu)",
226262306a36Sopenharmony_ci			   fw->size);
226362306a36Sopenharmony_ci		err = -EBADF;
226462306a36Sopenharmony_ci		goto done;
226562306a36Sopenharmony_ci	}
226662306a36Sopenharmony_ci
226762306a36Sopenharmony_ci	calltime = ktime_get();
226862306a36Sopenharmony_ci
226962306a36Sopenharmony_ci	btintel_set_flag(hdev, INTEL_DOWNLOADING);
227062306a36Sopenharmony_ci
227162306a36Sopenharmony_ci	/* Start firmware downloading and get boot parameter */
227262306a36Sopenharmony_ci	err = btintel_download_fw_tlv(hdev, ver, fw, boot_param,
227362306a36Sopenharmony_ci					       INTEL_HW_VARIANT(ver->cnvi_bt),
227462306a36Sopenharmony_ci					       ver->sbe_type);
227562306a36Sopenharmony_ci	if (err < 0) {
227662306a36Sopenharmony_ci		if (err == -EALREADY) {
227762306a36Sopenharmony_ci			/* Firmware has already been loaded */
227862306a36Sopenharmony_ci			btintel_set_flag(hdev, INTEL_FIRMWARE_LOADED);
227962306a36Sopenharmony_ci			err = 0;
228062306a36Sopenharmony_ci			goto done;
228162306a36Sopenharmony_ci		}
228262306a36Sopenharmony_ci
228362306a36Sopenharmony_ci		/* When FW download fails, send Intel Reset to retry
228462306a36Sopenharmony_ci		 * FW download.
228562306a36Sopenharmony_ci		 */
228662306a36Sopenharmony_ci		btintel_reset_to_bootloader(hdev);
228762306a36Sopenharmony_ci		goto done;
228862306a36Sopenharmony_ci	}
228962306a36Sopenharmony_ci
229062306a36Sopenharmony_ci	/* Before switching the device into operational mode and with that
229162306a36Sopenharmony_ci	 * booting the loaded firmware, wait for the bootloader notification
229262306a36Sopenharmony_ci	 * that all fragments have been successfully received.
229362306a36Sopenharmony_ci	 *
229462306a36Sopenharmony_ci	 * When the event processing receives the notification, then the
229562306a36Sopenharmony_ci	 * BTUSB_DOWNLOADING flag will be cleared.
229662306a36Sopenharmony_ci	 *
229762306a36Sopenharmony_ci	 * The firmware loading should not take longer than 5 seconds
229862306a36Sopenharmony_ci	 * and thus just timeout if that happens and fail the setup
229962306a36Sopenharmony_ci	 * of this device.
230062306a36Sopenharmony_ci	 */
230162306a36Sopenharmony_ci	err = btintel_download_wait(hdev, calltime, 5000);
230262306a36Sopenharmony_ci	if (err == -ETIMEDOUT)
230362306a36Sopenharmony_ci		btintel_reset_to_bootloader(hdev);
230462306a36Sopenharmony_ci
230562306a36Sopenharmony_cidone:
230662306a36Sopenharmony_ci	release_firmware(fw);
230762306a36Sopenharmony_ci	return err;
230862306a36Sopenharmony_ci}
230962306a36Sopenharmony_ci
231062306a36Sopenharmony_cistatic int btintel_get_codec_config_data(struct hci_dev *hdev,
231162306a36Sopenharmony_ci					 __u8 link, struct bt_codec *codec,
231262306a36Sopenharmony_ci					 __u8 *ven_len, __u8 **ven_data)
231362306a36Sopenharmony_ci{
231462306a36Sopenharmony_ci	int err = 0;
231562306a36Sopenharmony_ci
231662306a36Sopenharmony_ci	if (!ven_data || !ven_len)
231762306a36Sopenharmony_ci		return -EINVAL;
231862306a36Sopenharmony_ci
231962306a36Sopenharmony_ci	*ven_len = 0;
232062306a36Sopenharmony_ci	*ven_data = NULL;
232162306a36Sopenharmony_ci
232262306a36Sopenharmony_ci	if (link != ESCO_LINK) {
232362306a36Sopenharmony_ci		bt_dev_err(hdev, "Invalid link type(%u)", link);
232462306a36Sopenharmony_ci		return -EINVAL;
232562306a36Sopenharmony_ci	}
232662306a36Sopenharmony_ci
232762306a36Sopenharmony_ci	*ven_data = kmalloc(sizeof(__u8), GFP_KERNEL);
232862306a36Sopenharmony_ci	if (!*ven_data) {
232962306a36Sopenharmony_ci		err = -ENOMEM;
233062306a36Sopenharmony_ci		goto error;
233162306a36Sopenharmony_ci	}
233262306a36Sopenharmony_ci
233362306a36Sopenharmony_ci	/* supports only CVSD and mSBC offload codecs */
233462306a36Sopenharmony_ci	switch (codec->id) {
233562306a36Sopenharmony_ci	case 0x02:
233662306a36Sopenharmony_ci		**ven_data = 0x00;
233762306a36Sopenharmony_ci		break;
233862306a36Sopenharmony_ci	case 0x05:
233962306a36Sopenharmony_ci		**ven_data = 0x01;
234062306a36Sopenharmony_ci		break;
234162306a36Sopenharmony_ci	default:
234262306a36Sopenharmony_ci		err = -EINVAL;
234362306a36Sopenharmony_ci		bt_dev_err(hdev, "Invalid codec id(%u)", codec->id);
234462306a36Sopenharmony_ci		goto error;
234562306a36Sopenharmony_ci	}
234662306a36Sopenharmony_ci	/* codec and its capabilities are pre-defined to ids
234762306a36Sopenharmony_ci	 * preset id = 0x00 represents CVSD codec with sampling rate 8K
234862306a36Sopenharmony_ci	 * preset id = 0x01 represents mSBC codec with sampling rate 16K
234962306a36Sopenharmony_ci	 */
235062306a36Sopenharmony_ci	*ven_len = sizeof(__u8);
235162306a36Sopenharmony_ci	return err;
235262306a36Sopenharmony_ci
235362306a36Sopenharmony_cierror:
235462306a36Sopenharmony_ci	kfree(*ven_data);
235562306a36Sopenharmony_ci	*ven_data = NULL;
235662306a36Sopenharmony_ci	return err;
235762306a36Sopenharmony_ci}
235862306a36Sopenharmony_ci
235962306a36Sopenharmony_cistatic int btintel_get_data_path_id(struct hci_dev *hdev, __u8 *data_path_id)
236062306a36Sopenharmony_ci{
236162306a36Sopenharmony_ci	/* Intel uses 1 as data path id for all the usecases */
236262306a36Sopenharmony_ci	*data_path_id = 1;
236362306a36Sopenharmony_ci	return 0;
236462306a36Sopenharmony_ci}
236562306a36Sopenharmony_ci
236662306a36Sopenharmony_cistatic int btintel_configure_offload(struct hci_dev *hdev)
236762306a36Sopenharmony_ci{
236862306a36Sopenharmony_ci	struct sk_buff *skb;
236962306a36Sopenharmony_ci	int err = 0;
237062306a36Sopenharmony_ci	struct intel_offload_use_cases *use_cases;
237162306a36Sopenharmony_ci
237262306a36Sopenharmony_ci	skb = __hci_cmd_sync(hdev, 0xfc86, 0, NULL, HCI_INIT_TIMEOUT);
237362306a36Sopenharmony_ci	if (IS_ERR(skb)) {
237462306a36Sopenharmony_ci		bt_dev_err(hdev, "Reading offload use cases failed (%ld)",
237562306a36Sopenharmony_ci			   PTR_ERR(skb));
237662306a36Sopenharmony_ci		return PTR_ERR(skb);
237762306a36Sopenharmony_ci	}
237862306a36Sopenharmony_ci
237962306a36Sopenharmony_ci	if (skb->len < sizeof(*use_cases)) {
238062306a36Sopenharmony_ci		err = -EIO;
238162306a36Sopenharmony_ci		goto error;
238262306a36Sopenharmony_ci	}
238362306a36Sopenharmony_ci
238462306a36Sopenharmony_ci	use_cases = (void *)skb->data;
238562306a36Sopenharmony_ci
238662306a36Sopenharmony_ci	if (use_cases->status) {
238762306a36Sopenharmony_ci		err = -bt_to_errno(skb->data[0]);
238862306a36Sopenharmony_ci		goto error;
238962306a36Sopenharmony_ci	}
239062306a36Sopenharmony_ci
239162306a36Sopenharmony_ci	if (use_cases->preset[0] & 0x03) {
239262306a36Sopenharmony_ci		hdev->get_data_path_id = btintel_get_data_path_id;
239362306a36Sopenharmony_ci		hdev->get_codec_config_data = btintel_get_codec_config_data;
239462306a36Sopenharmony_ci	}
239562306a36Sopenharmony_cierror:
239662306a36Sopenharmony_ci	kfree_skb(skb);
239762306a36Sopenharmony_ci	return err;
239862306a36Sopenharmony_ci}
239962306a36Sopenharmony_ci
240062306a36Sopenharmony_cistatic void btintel_set_ppag(struct hci_dev *hdev, struct intel_version_tlv *ver)
240162306a36Sopenharmony_ci{
240262306a36Sopenharmony_ci	struct btintel_ppag ppag;
240362306a36Sopenharmony_ci	struct sk_buff *skb;
240462306a36Sopenharmony_ci	struct hci_ppag_enable_cmd ppag_cmd;
240562306a36Sopenharmony_ci	acpi_handle handle;
240662306a36Sopenharmony_ci
240762306a36Sopenharmony_ci	/* PPAG is not supported if CRF is HrP2, Jfp2, JfP1 */
240862306a36Sopenharmony_ci	switch (ver->cnvr_top & 0xFFF) {
240962306a36Sopenharmony_ci	case 0x504:     /* Hrp2 */
241062306a36Sopenharmony_ci	case 0x202:     /* Jfp2 */
241162306a36Sopenharmony_ci	case 0x201:     /* Jfp1 */
241262306a36Sopenharmony_ci		bt_dev_dbg(hdev, "PPAG not supported for Intel CNVr (0x%3x)",
241362306a36Sopenharmony_ci			   ver->cnvr_top & 0xFFF);
241462306a36Sopenharmony_ci		return;
241562306a36Sopenharmony_ci	}
241662306a36Sopenharmony_ci
241762306a36Sopenharmony_ci	handle = ACPI_HANDLE(GET_HCIDEV_DEV(hdev));
241862306a36Sopenharmony_ci	if (!handle) {
241962306a36Sopenharmony_ci		bt_dev_info(hdev, "No support for BT device in ACPI firmware");
242062306a36Sopenharmony_ci		return;
242162306a36Sopenharmony_ci	}
242262306a36Sopenharmony_ci
242362306a36Sopenharmony_ci	memset(&ppag, 0, sizeof(ppag));
242462306a36Sopenharmony_ci
242562306a36Sopenharmony_ci	ppag.hdev = hdev;
242662306a36Sopenharmony_ci	ppag.status = AE_NOT_FOUND;
242762306a36Sopenharmony_ci	acpi_walk_namespace(ACPI_TYPE_PACKAGE, handle, 1, NULL,
242862306a36Sopenharmony_ci			    btintel_ppag_callback, &ppag, NULL);
242962306a36Sopenharmony_ci
243062306a36Sopenharmony_ci	if (ACPI_FAILURE(ppag.status)) {
243162306a36Sopenharmony_ci		if (ppag.status == AE_NOT_FOUND) {
243262306a36Sopenharmony_ci			bt_dev_dbg(hdev, "PPAG-BT: ACPI entry not found");
243362306a36Sopenharmony_ci			return;
243462306a36Sopenharmony_ci		}
243562306a36Sopenharmony_ci		return;
243662306a36Sopenharmony_ci	}
243762306a36Sopenharmony_ci
243862306a36Sopenharmony_ci	if (ppag.domain != 0x12) {
243962306a36Sopenharmony_ci		bt_dev_dbg(hdev, "PPAG-BT: Bluetooth domain is disabled in ACPI firmware");
244062306a36Sopenharmony_ci		return;
244162306a36Sopenharmony_ci	}
244262306a36Sopenharmony_ci
244362306a36Sopenharmony_ci	/* PPAG mode
244462306a36Sopenharmony_ci	 * BIT 0 : 0 Disabled in EU
244562306a36Sopenharmony_ci	 *         1 Enabled in EU
244662306a36Sopenharmony_ci	 * BIT 1 : 0 Disabled in China
244762306a36Sopenharmony_ci	 *         1 Enabled in China
244862306a36Sopenharmony_ci	 */
244962306a36Sopenharmony_ci	if ((ppag.mode & 0x01) != BIT(0) && (ppag.mode & 0x02) != BIT(1)) {
245062306a36Sopenharmony_ci		bt_dev_dbg(hdev, "PPAG-BT: EU, China mode are disabled in CB/BIOS");
245162306a36Sopenharmony_ci		return;
245262306a36Sopenharmony_ci	}
245362306a36Sopenharmony_ci
245462306a36Sopenharmony_ci	ppag_cmd.ppag_enable_flags = cpu_to_le32(ppag.mode);
245562306a36Sopenharmony_ci
245662306a36Sopenharmony_ci	skb = __hci_cmd_sync(hdev, INTEL_OP_PPAG_CMD, sizeof(ppag_cmd), &ppag_cmd, HCI_CMD_TIMEOUT);
245762306a36Sopenharmony_ci	if (IS_ERR(skb)) {
245862306a36Sopenharmony_ci		bt_dev_warn(hdev, "Failed to send PPAG Enable (%ld)", PTR_ERR(skb));
245962306a36Sopenharmony_ci		return;
246062306a36Sopenharmony_ci	}
246162306a36Sopenharmony_ci	bt_dev_info(hdev, "PPAG-BT: Enabled (Mode %d)", ppag.mode);
246262306a36Sopenharmony_ci	kfree_skb(skb);
246362306a36Sopenharmony_ci}
246462306a36Sopenharmony_ci
246562306a36Sopenharmony_cistatic int btintel_acpi_reset_method(struct hci_dev *hdev)
246662306a36Sopenharmony_ci{
246762306a36Sopenharmony_ci	int ret = 0;
246862306a36Sopenharmony_ci	acpi_status status;
246962306a36Sopenharmony_ci	union acpi_object *p, *ref;
247062306a36Sopenharmony_ci	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
247162306a36Sopenharmony_ci
247262306a36Sopenharmony_ci	status = acpi_evaluate_object(ACPI_HANDLE(GET_HCIDEV_DEV(hdev)), "_PRR", NULL, &buffer);
247362306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
247462306a36Sopenharmony_ci		bt_dev_err(hdev, "Failed to run _PRR method");
247562306a36Sopenharmony_ci		ret = -ENODEV;
247662306a36Sopenharmony_ci		return ret;
247762306a36Sopenharmony_ci	}
247862306a36Sopenharmony_ci	p = buffer.pointer;
247962306a36Sopenharmony_ci
248062306a36Sopenharmony_ci	if (p->package.count != 1 || p->type != ACPI_TYPE_PACKAGE) {
248162306a36Sopenharmony_ci		bt_dev_err(hdev, "Invalid arguments");
248262306a36Sopenharmony_ci		ret = -EINVAL;
248362306a36Sopenharmony_ci		goto exit_on_error;
248462306a36Sopenharmony_ci	}
248562306a36Sopenharmony_ci
248662306a36Sopenharmony_ci	ref = &p->package.elements[0];
248762306a36Sopenharmony_ci	if (ref->type != ACPI_TYPE_LOCAL_REFERENCE) {
248862306a36Sopenharmony_ci		bt_dev_err(hdev, "Invalid object type: 0x%x", ref->type);
248962306a36Sopenharmony_ci		ret = -EINVAL;
249062306a36Sopenharmony_ci		goto exit_on_error;
249162306a36Sopenharmony_ci	}
249262306a36Sopenharmony_ci
249362306a36Sopenharmony_ci	status = acpi_evaluate_object(ref->reference.handle, "_RST", NULL, NULL);
249462306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
249562306a36Sopenharmony_ci		bt_dev_err(hdev, "Failed to run_RST method");
249662306a36Sopenharmony_ci		ret = -ENODEV;
249762306a36Sopenharmony_ci		goto exit_on_error;
249862306a36Sopenharmony_ci	}
249962306a36Sopenharmony_ci
250062306a36Sopenharmony_ciexit_on_error:
250162306a36Sopenharmony_ci	kfree(buffer.pointer);
250262306a36Sopenharmony_ci	return ret;
250362306a36Sopenharmony_ci}
250462306a36Sopenharmony_ci
250562306a36Sopenharmony_cistatic void btintel_set_dsm_reset_method(struct hci_dev *hdev,
250662306a36Sopenharmony_ci					 struct intel_version_tlv *ver_tlv)
250762306a36Sopenharmony_ci{
250862306a36Sopenharmony_ci	struct btintel_data *data = hci_get_priv(hdev);
250962306a36Sopenharmony_ci	acpi_handle handle = ACPI_HANDLE(GET_HCIDEV_DEV(hdev));
251062306a36Sopenharmony_ci	u8 reset_payload[4] = {0x01, 0x00, 0x01, 0x00};
251162306a36Sopenharmony_ci	union acpi_object *obj, argv4;
251262306a36Sopenharmony_ci	enum {
251362306a36Sopenharmony_ci		RESET_TYPE_WDISABLE2,
251462306a36Sopenharmony_ci		RESET_TYPE_VSEC
251562306a36Sopenharmony_ci	};
251662306a36Sopenharmony_ci
251762306a36Sopenharmony_ci	handle = ACPI_HANDLE(GET_HCIDEV_DEV(hdev));
251862306a36Sopenharmony_ci
251962306a36Sopenharmony_ci	if (!handle) {
252062306a36Sopenharmony_ci		bt_dev_dbg(hdev, "No support for bluetooth device in ACPI firmware");
252162306a36Sopenharmony_ci		return;
252262306a36Sopenharmony_ci	}
252362306a36Sopenharmony_ci
252462306a36Sopenharmony_ci	if (!acpi_has_method(handle, "_PRR")) {
252562306a36Sopenharmony_ci		bt_dev_err(hdev, "No support for _PRR ACPI method");
252662306a36Sopenharmony_ci		return;
252762306a36Sopenharmony_ci	}
252862306a36Sopenharmony_ci
252962306a36Sopenharmony_ci	switch (ver_tlv->cnvi_top & 0xfff) {
253062306a36Sopenharmony_ci	case 0x910: /* GalePeak2 */
253162306a36Sopenharmony_ci		reset_payload[2] = RESET_TYPE_VSEC;
253262306a36Sopenharmony_ci		break;
253362306a36Sopenharmony_ci	default:
253462306a36Sopenharmony_ci		/* WDISABLE2 is the default reset method */
253562306a36Sopenharmony_ci		reset_payload[2] = RESET_TYPE_WDISABLE2;
253662306a36Sopenharmony_ci
253762306a36Sopenharmony_ci		if (!acpi_check_dsm(handle, &btintel_guid_dsm, 0,
253862306a36Sopenharmony_ci				    BIT(DSM_SET_WDISABLE2_DELAY))) {
253962306a36Sopenharmony_ci			bt_dev_err(hdev, "No dsm support to set reset delay");
254062306a36Sopenharmony_ci			return;
254162306a36Sopenharmony_ci		}
254262306a36Sopenharmony_ci		argv4.integer.type = ACPI_TYPE_INTEGER;
254362306a36Sopenharmony_ci		/* delay required to toggle BT power */
254462306a36Sopenharmony_ci		argv4.integer.value = 160;
254562306a36Sopenharmony_ci		obj = acpi_evaluate_dsm(handle, &btintel_guid_dsm, 0,
254662306a36Sopenharmony_ci					DSM_SET_WDISABLE2_DELAY, &argv4);
254762306a36Sopenharmony_ci		if (!obj) {
254862306a36Sopenharmony_ci			bt_dev_err(hdev, "Failed to call dsm to set reset delay");
254962306a36Sopenharmony_ci			return;
255062306a36Sopenharmony_ci		}
255162306a36Sopenharmony_ci		ACPI_FREE(obj);
255262306a36Sopenharmony_ci	}
255362306a36Sopenharmony_ci
255462306a36Sopenharmony_ci	bt_dev_info(hdev, "DSM reset method type: 0x%02x", reset_payload[2]);
255562306a36Sopenharmony_ci
255662306a36Sopenharmony_ci	if (!acpi_check_dsm(handle, &btintel_guid_dsm, 0,
255762306a36Sopenharmony_ci			    DSM_SET_RESET_METHOD)) {
255862306a36Sopenharmony_ci		bt_dev_warn(hdev, "No support for dsm to set reset method");
255962306a36Sopenharmony_ci		return;
256062306a36Sopenharmony_ci	}
256162306a36Sopenharmony_ci	argv4.buffer.type = ACPI_TYPE_BUFFER;
256262306a36Sopenharmony_ci	argv4.buffer.length = sizeof(reset_payload);
256362306a36Sopenharmony_ci	argv4.buffer.pointer = reset_payload;
256462306a36Sopenharmony_ci
256562306a36Sopenharmony_ci	obj = acpi_evaluate_dsm(handle, &btintel_guid_dsm, 0,
256662306a36Sopenharmony_ci				DSM_SET_RESET_METHOD, &argv4);
256762306a36Sopenharmony_ci	if (!obj) {
256862306a36Sopenharmony_ci		bt_dev_err(hdev, "Failed to call dsm to set reset method");
256962306a36Sopenharmony_ci		return;
257062306a36Sopenharmony_ci	}
257162306a36Sopenharmony_ci	ACPI_FREE(obj);
257262306a36Sopenharmony_ci	data->acpi_reset_method = btintel_acpi_reset_method;
257362306a36Sopenharmony_ci}
257462306a36Sopenharmony_ci
257562306a36Sopenharmony_cistatic int btintel_bootloader_setup_tlv(struct hci_dev *hdev,
257662306a36Sopenharmony_ci					struct intel_version_tlv *ver)
257762306a36Sopenharmony_ci{
257862306a36Sopenharmony_ci	u32 boot_param;
257962306a36Sopenharmony_ci	char ddcname[64];
258062306a36Sopenharmony_ci	int err;
258162306a36Sopenharmony_ci	struct intel_version_tlv new_ver;
258262306a36Sopenharmony_ci
258362306a36Sopenharmony_ci	bt_dev_dbg(hdev, "");
258462306a36Sopenharmony_ci
258562306a36Sopenharmony_ci	/* Set the default boot parameter to 0x0 and it is updated to
258662306a36Sopenharmony_ci	 * SKU specific boot parameter after reading Intel_Write_Boot_Params
258762306a36Sopenharmony_ci	 * command while downloading the firmware.
258862306a36Sopenharmony_ci	 */
258962306a36Sopenharmony_ci	boot_param = 0x00000000;
259062306a36Sopenharmony_ci
259162306a36Sopenharmony_ci	btintel_set_flag(hdev, INTEL_BOOTLOADER);
259262306a36Sopenharmony_ci
259362306a36Sopenharmony_ci	err = btintel_prepare_fw_download_tlv(hdev, ver, &boot_param);
259462306a36Sopenharmony_ci	if (err)
259562306a36Sopenharmony_ci		return err;
259662306a36Sopenharmony_ci
259762306a36Sopenharmony_ci	/* check if controller is already having an operational firmware */
259862306a36Sopenharmony_ci	if (ver->img_type == 0x03)
259962306a36Sopenharmony_ci		goto finish;
260062306a36Sopenharmony_ci
260162306a36Sopenharmony_ci	err = btintel_boot(hdev, boot_param);
260262306a36Sopenharmony_ci	if (err)
260362306a36Sopenharmony_ci		return err;
260462306a36Sopenharmony_ci
260562306a36Sopenharmony_ci	btintel_clear_flag(hdev, INTEL_BOOTLOADER);
260662306a36Sopenharmony_ci
260762306a36Sopenharmony_ci	btintel_get_fw_name_tlv(ver, ddcname, sizeof(ddcname), "ddc");
260862306a36Sopenharmony_ci	/* Once the device is running in operational mode, it needs to
260962306a36Sopenharmony_ci	 * apply the device configuration (DDC) parameters.
261062306a36Sopenharmony_ci	 *
261162306a36Sopenharmony_ci	 * The device can work without DDC parameters, so even if it
261262306a36Sopenharmony_ci	 * fails to load the file, no need to fail the setup.
261362306a36Sopenharmony_ci	 */
261462306a36Sopenharmony_ci	btintel_load_ddc_config(hdev, ddcname);
261562306a36Sopenharmony_ci
261662306a36Sopenharmony_ci	/* Read supported use cases and set callbacks to fetch datapath id */
261762306a36Sopenharmony_ci	btintel_configure_offload(hdev);
261862306a36Sopenharmony_ci
261962306a36Sopenharmony_ci	hci_dev_clear_flag(hdev, HCI_QUALITY_REPORT);
262062306a36Sopenharmony_ci
262162306a36Sopenharmony_ci	/* Set PPAG feature */
262262306a36Sopenharmony_ci	btintel_set_ppag(hdev, ver);
262362306a36Sopenharmony_ci
262462306a36Sopenharmony_ci	/* Read the Intel version information after loading the FW  */
262562306a36Sopenharmony_ci	err = btintel_read_version_tlv(hdev, &new_ver);
262662306a36Sopenharmony_ci	if (err)
262762306a36Sopenharmony_ci		return err;
262862306a36Sopenharmony_ci
262962306a36Sopenharmony_ci	btintel_version_info_tlv(hdev, &new_ver);
263062306a36Sopenharmony_ci
263162306a36Sopenharmony_cifinish:
263262306a36Sopenharmony_ci	/* Set the event mask for Intel specific vendor events. This enables
263362306a36Sopenharmony_ci	 * a few extra events that are useful during general operation. It
263462306a36Sopenharmony_ci	 * does not enable any debugging related events.
263562306a36Sopenharmony_ci	 *
263662306a36Sopenharmony_ci	 * The device will function correctly without these events enabled
263762306a36Sopenharmony_ci	 * and thus no need to fail the setup.
263862306a36Sopenharmony_ci	 */
263962306a36Sopenharmony_ci	btintel_set_event_mask(hdev, false);
264062306a36Sopenharmony_ci
264162306a36Sopenharmony_ci	return 0;
264262306a36Sopenharmony_ci}
264362306a36Sopenharmony_ci
264462306a36Sopenharmony_cistatic void btintel_set_msft_opcode(struct hci_dev *hdev, u8 hw_variant)
264562306a36Sopenharmony_ci{
264662306a36Sopenharmony_ci	switch (hw_variant) {
264762306a36Sopenharmony_ci	/* Legacy bootloader devices that supports MSFT Extension */
264862306a36Sopenharmony_ci	case 0x11:	/* JfP */
264962306a36Sopenharmony_ci	case 0x12:	/* ThP */
265062306a36Sopenharmony_ci	case 0x13:	/* HrP */
265162306a36Sopenharmony_ci	case 0x14:	/* CcP */
265262306a36Sopenharmony_ci	/* All Intel new genration controllers support the Microsoft vendor
265362306a36Sopenharmony_ci	 * extension are using 0xFC1E for VsMsftOpCode.
265462306a36Sopenharmony_ci	 */
265562306a36Sopenharmony_ci	case 0x17:
265662306a36Sopenharmony_ci	case 0x18:
265762306a36Sopenharmony_ci	case 0x19:
265862306a36Sopenharmony_ci	case 0x1b:
265962306a36Sopenharmony_ci	case 0x1c:
266062306a36Sopenharmony_ci		hci_set_msft_opcode(hdev, 0xFC1E);
266162306a36Sopenharmony_ci		break;
266262306a36Sopenharmony_ci	default:
266362306a36Sopenharmony_ci		/* Not supported */
266462306a36Sopenharmony_ci		break;
266562306a36Sopenharmony_ci	}
266662306a36Sopenharmony_ci}
266762306a36Sopenharmony_ci
266862306a36Sopenharmony_cistatic int btintel_setup_combined(struct hci_dev *hdev)
266962306a36Sopenharmony_ci{
267062306a36Sopenharmony_ci	const u8 param[1] = { 0xFF };
267162306a36Sopenharmony_ci	struct intel_version ver;
267262306a36Sopenharmony_ci	struct intel_version_tlv ver_tlv;
267362306a36Sopenharmony_ci	struct sk_buff *skb;
267462306a36Sopenharmony_ci	int err;
267562306a36Sopenharmony_ci
267662306a36Sopenharmony_ci	BT_DBG("%s", hdev->name);
267762306a36Sopenharmony_ci
267862306a36Sopenharmony_ci	/* The some controllers have a bug with the first HCI command sent to it
267962306a36Sopenharmony_ci	 * returning number of completed commands as zero. This would stall the
268062306a36Sopenharmony_ci	 * command processing in the Bluetooth core.
268162306a36Sopenharmony_ci	 *
268262306a36Sopenharmony_ci	 * As a workaround, send HCI Reset command first which will reset the
268362306a36Sopenharmony_ci	 * number of completed commands and allow normal command processing
268462306a36Sopenharmony_ci	 * from now on.
268562306a36Sopenharmony_ci	 *
268662306a36Sopenharmony_ci	 * Regarding the INTEL_BROKEN_SHUTDOWN_LED flag, these devices maybe
268762306a36Sopenharmony_ci	 * in the SW_RFKILL ON state as a workaround of fixing LED issue during
268862306a36Sopenharmony_ci	 * the shutdown() procedure, and once the device is in SW_RFKILL ON
268962306a36Sopenharmony_ci	 * state, the only way to exit out of it is sending the HCI_Reset
269062306a36Sopenharmony_ci	 * command.
269162306a36Sopenharmony_ci	 */
269262306a36Sopenharmony_ci	if (btintel_test_flag(hdev, INTEL_BROKEN_INITIAL_NCMD) ||
269362306a36Sopenharmony_ci	    btintel_test_flag(hdev, INTEL_BROKEN_SHUTDOWN_LED)) {
269462306a36Sopenharmony_ci		skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL,
269562306a36Sopenharmony_ci				     HCI_INIT_TIMEOUT);
269662306a36Sopenharmony_ci		if (IS_ERR(skb)) {
269762306a36Sopenharmony_ci			bt_dev_err(hdev,
269862306a36Sopenharmony_ci				   "sending initial HCI reset failed (%ld)",
269962306a36Sopenharmony_ci				   PTR_ERR(skb));
270062306a36Sopenharmony_ci			return PTR_ERR(skb);
270162306a36Sopenharmony_ci		}
270262306a36Sopenharmony_ci		kfree_skb(skb);
270362306a36Sopenharmony_ci	}
270462306a36Sopenharmony_ci
270562306a36Sopenharmony_ci	/* Starting from TyP device, the command parameter and response are
270662306a36Sopenharmony_ci	 * changed even though the OCF for HCI_Intel_Read_Version command
270762306a36Sopenharmony_ci	 * remains same. The legacy devices can handle even if the
270862306a36Sopenharmony_ci	 * command has a parameter and returns a correct version information.
270962306a36Sopenharmony_ci	 * So, it uses new format to support both legacy and new format.
271062306a36Sopenharmony_ci	 */
271162306a36Sopenharmony_ci	skb = __hci_cmd_sync(hdev, 0xfc05, 1, param, HCI_CMD_TIMEOUT);
271262306a36Sopenharmony_ci	if (IS_ERR(skb)) {
271362306a36Sopenharmony_ci		bt_dev_err(hdev, "Reading Intel version command failed (%ld)",
271462306a36Sopenharmony_ci			   PTR_ERR(skb));
271562306a36Sopenharmony_ci		return PTR_ERR(skb);
271662306a36Sopenharmony_ci	}
271762306a36Sopenharmony_ci
271862306a36Sopenharmony_ci	/* Check the status */
271962306a36Sopenharmony_ci	if (skb->data[0]) {
272062306a36Sopenharmony_ci		bt_dev_err(hdev, "Intel Read Version command failed (%02x)",
272162306a36Sopenharmony_ci			   skb->data[0]);
272262306a36Sopenharmony_ci		err = -EIO;
272362306a36Sopenharmony_ci		goto exit_error;
272462306a36Sopenharmony_ci	}
272562306a36Sopenharmony_ci
272662306a36Sopenharmony_ci	/* Apply the common HCI quirks for Intel device */
272762306a36Sopenharmony_ci	set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
272862306a36Sopenharmony_ci	set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks);
272962306a36Sopenharmony_ci	set_bit(HCI_QUIRK_NON_PERSISTENT_DIAG, &hdev->quirks);
273062306a36Sopenharmony_ci
273162306a36Sopenharmony_ci	/* Set up the quality report callback for Intel devices */
273262306a36Sopenharmony_ci	hdev->set_quality_report = btintel_set_quality_report;
273362306a36Sopenharmony_ci
273462306a36Sopenharmony_ci	/* For Legacy device, check the HW platform value and size */
273562306a36Sopenharmony_ci	if (skb->len == sizeof(ver) && skb->data[1] == 0x37) {
273662306a36Sopenharmony_ci		bt_dev_dbg(hdev, "Read the legacy Intel version information");
273762306a36Sopenharmony_ci
273862306a36Sopenharmony_ci		memcpy(&ver, skb->data, sizeof(ver));
273962306a36Sopenharmony_ci
274062306a36Sopenharmony_ci		/* Display version information */
274162306a36Sopenharmony_ci		btintel_version_info(hdev, &ver);
274262306a36Sopenharmony_ci
274362306a36Sopenharmony_ci		/* Check for supported iBT hardware variants of this firmware
274462306a36Sopenharmony_ci		 * loading method.
274562306a36Sopenharmony_ci		 *
274662306a36Sopenharmony_ci		 * This check has been put in place to ensure correct forward
274762306a36Sopenharmony_ci		 * compatibility options when newer hardware variants come
274862306a36Sopenharmony_ci		 * along.
274962306a36Sopenharmony_ci		 */
275062306a36Sopenharmony_ci		switch (ver.hw_variant) {
275162306a36Sopenharmony_ci		case 0x07:	/* WP */
275262306a36Sopenharmony_ci		case 0x08:	/* StP */
275362306a36Sopenharmony_ci			/* Legacy ROM product */
275462306a36Sopenharmony_ci			btintel_set_flag(hdev, INTEL_ROM_LEGACY);
275562306a36Sopenharmony_ci
275662306a36Sopenharmony_ci			/* Apply the device specific HCI quirks
275762306a36Sopenharmony_ci			 *
275862306a36Sopenharmony_ci			 * WBS for SdP - For the Legacy ROM products, only SdP
275962306a36Sopenharmony_ci			 * supports the WBS. But the version information is not
276062306a36Sopenharmony_ci			 * enough to use here because the StP2 and SdP have same
276162306a36Sopenharmony_ci			 * hw_variant and fw_variant. So, this flag is set by
276262306a36Sopenharmony_ci			 * the transport driver (btusb) based on the HW info
276362306a36Sopenharmony_ci			 * (idProduct)
276462306a36Sopenharmony_ci			 */
276562306a36Sopenharmony_ci			if (!btintel_test_flag(hdev,
276662306a36Sopenharmony_ci					       INTEL_ROM_LEGACY_NO_WBS_SUPPORT))
276762306a36Sopenharmony_ci				set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED,
276862306a36Sopenharmony_ci					&hdev->quirks);
276962306a36Sopenharmony_ci			if (ver.hw_variant == 0x08 && ver.fw_variant == 0x22)
277062306a36Sopenharmony_ci				set_bit(HCI_QUIRK_VALID_LE_STATES,
277162306a36Sopenharmony_ci					&hdev->quirks);
277262306a36Sopenharmony_ci
277362306a36Sopenharmony_ci			err = btintel_legacy_rom_setup(hdev, &ver);
277462306a36Sopenharmony_ci			break;
277562306a36Sopenharmony_ci		case 0x0b:      /* SfP */
277662306a36Sopenharmony_ci		case 0x11:      /* JfP */
277762306a36Sopenharmony_ci		case 0x12:      /* ThP */
277862306a36Sopenharmony_ci		case 0x13:      /* HrP */
277962306a36Sopenharmony_ci		case 0x14:      /* CcP */
278062306a36Sopenharmony_ci			set_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks);
278162306a36Sopenharmony_ci			fallthrough;
278262306a36Sopenharmony_ci		case 0x0c:	/* WsP */
278362306a36Sopenharmony_ci			/* Apply the device specific HCI quirks
278462306a36Sopenharmony_ci			 *
278562306a36Sopenharmony_ci			 * All Legacy bootloader devices support WBS
278662306a36Sopenharmony_ci			 */
278762306a36Sopenharmony_ci			set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED,
278862306a36Sopenharmony_ci				&hdev->quirks);
278962306a36Sopenharmony_ci
279062306a36Sopenharmony_ci			/* These variants don't seem to support LE Coded PHY */
279162306a36Sopenharmony_ci			set_bit(HCI_QUIRK_BROKEN_LE_CODED, &hdev->quirks);
279262306a36Sopenharmony_ci
279362306a36Sopenharmony_ci			/* Setup MSFT Extension support */
279462306a36Sopenharmony_ci			btintel_set_msft_opcode(hdev, ver.hw_variant);
279562306a36Sopenharmony_ci
279662306a36Sopenharmony_ci			err = btintel_bootloader_setup(hdev, &ver);
279762306a36Sopenharmony_ci			btintel_register_devcoredump_support(hdev);
279862306a36Sopenharmony_ci			break;
279962306a36Sopenharmony_ci		default:
280062306a36Sopenharmony_ci			bt_dev_err(hdev, "Unsupported Intel hw variant (%u)",
280162306a36Sopenharmony_ci				   ver.hw_variant);
280262306a36Sopenharmony_ci			err = -EINVAL;
280362306a36Sopenharmony_ci		}
280462306a36Sopenharmony_ci
280562306a36Sopenharmony_ci		goto exit_error;
280662306a36Sopenharmony_ci	}
280762306a36Sopenharmony_ci
280862306a36Sopenharmony_ci	/* memset ver_tlv to start with clean state as few fields are exclusive
280962306a36Sopenharmony_ci	 * to bootloader mode and are not populated in operational mode
281062306a36Sopenharmony_ci	 */
281162306a36Sopenharmony_ci	memset(&ver_tlv, 0, sizeof(ver_tlv));
281262306a36Sopenharmony_ci	/* For TLV type device, parse the tlv data */
281362306a36Sopenharmony_ci	err = btintel_parse_version_tlv(hdev, &ver_tlv, skb);
281462306a36Sopenharmony_ci	if (err) {
281562306a36Sopenharmony_ci		bt_dev_err(hdev, "Failed to parse TLV version information");
281662306a36Sopenharmony_ci		goto exit_error;
281762306a36Sopenharmony_ci	}
281862306a36Sopenharmony_ci
281962306a36Sopenharmony_ci	if (INTEL_HW_PLATFORM(ver_tlv.cnvi_bt) != 0x37) {
282062306a36Sopenharmony_ci		bt_dev_err(hdev, "Unsupported Intel hardware platform (0x%2x)",
282162306a36Sopenharmony_ci			   INTEL_HW_PLATFORM(ver_tlv.cnvi_bt));
282262306a36Sopenharmony_ci		err = -EINVAL;
282362306a36Sopenharmony_ci		goto exit_error;
282462306a36Sopenharmony_ci	}
282562306a36Sopenharmony_ci
282662306a36Sopenharmony_ci	/* Check for supported iBT hardware variants of this firmware
282762306a36Sopenharmony_ci	 * loading method.
282862306a36Sopenharmony_ci	 *
282962306a36Sopenharmony_ci	 * This check has been put in place to ensure correct forward
283062306a36Sopenharmony_ci	 * compatibility options when newer hardware variants come
283162306a36Sopenharmony_ci	 * along.
283262306a36Sopenharmony_ci	 */
283362306a36Sopenharmony_ci	switch (INTEL_HW_VARIANT(ver_tlv.cnvi_bt)) {
283462306a36Sopenharmony_ci	case 0x11:      /* JfP */
283562306a36Sopenharmony_ci	case 0x12:      /* ThP */
283662306a36Sopenharmony_ci	case 0x13:      /* HrP */
283762306a36Sopenharmony_ci	case 0x14:      /* CcP */
283862306a36Sopenharmony_ci		/* Some legacy bootloader devices starting from JfP,
283962306a36Sopenharmony_ci		 * the operational firmware supports both old and TLV based
284062306a36Sopenharmony_ci		 * HCI_Intel_Read_Version command based on the command
284162306a36Sopenharmony_ci		 * parameter.
284262306a36Sopenharmony_ci		 *
284362306a36Sopenharmony_ci		 * For upgrading firmware case, the TLV based version cannot
284462306a36Sopenharmony_ci		 * be used because the firmware filename for legacy bootloader
284562306a36Sopenharmony_ci		 * is based on the old format.
284662306a36Sopenharmony_ci		 *
284762306a36Sopenharmony_ci		 * Also, it is not easy to convert TLV based version from the
284862306a36Sopenharmony_ci		 * legacy version format.
284962306a36Sopenharmony_ci		 *
285062306a36Sopenharmony_ci		 * So, as a workaround for those devices, use the legacy
285162306a36Sopenharmony_ci		 * HCI_Intel_Read_Version to get the version information and
285262306a36Sopenharmony_ci		 * run the legacy bootloader setup.
285362306a36Sopenharmony_ci		 */
285462306a36Sopenharmony_ci		err = btintel_read_version(hdev, &ver);
285562306a36Sopenharmony_ci		if (err)
285662306a36Sopenharmony_ci			break;
285762306a36Sopenharmony_ci
285862306a36Sopenharmony_ci		/* Apply the device specific HCI quirks
285962306a36Sopenharmony_ci		 *
286062306a36Sopenharmony_ci		 * All Legacy bootloader devices support WBS
286162306a36Sopenharmony_ci		 */
286262306a36Sopenharmony_ci		set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks);
286362306a36Sopenharmony_ci
286462306a36Sopenharmony_ci		/* These variants don't seem to support LE Coded PHY */
286562306a36Sopenharmony_ci		set_bit(HCI_QUIRK_BROKEN_LE_CODED, &hdev->quirks);
286662306a36Sopenharmony_ci
286762306a36Sopenharmony_ci		/* Set Valid LE States quirk */
286862306a36Sopenharmony_ci		set_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks);
286962306a36Sopenharmony_ci
287062306a36Sopenharmony_ci		/* Setup MSFT Extension support */
287162306a36Sopenharmony_ci		btintel_set_msft_opcode(hdev, ver.hw_variant);
287262306a36Sopenharmony_ci
287362306a36Sopenharmony_ci		err = btintel_bootloader_setup(hdev, &ver);
287462306a36Sopenharmony_ci		btintel_register_devcoredump_support(hdev);
287562306a36Sopenharmony_ci		break;
287662306a36Sopenharmony_ci	case 0x17:
287762306a36Sopenharmony_ci	case 0x18:
287862306a36Sopenharmony_ci	case 0x19:
287962306a36Sopenharmony_ci	case 0x1b:
288062306a36Sopenharmony_ci	case 0x1c:
288162306a36Sopenharmony_ci		/* Display version information of TLV type */
288262306a36Sopenharmony_ci		btintel_version_info_tlv(hdev, &ver_tlv);
288362306a36Sopenharmony_ci
288462306a36Sopenharmony_ci		/* Apply the device specific HCI quirks for TLV based devices
288562306a36Sopenharmony_ci		 *
288662306a36Sopenharmony_ci		 * All TLV based devices support WBS
288762306a36Sopenharmony_ci		 */
288862306a36Sopenharmony_ci		set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks);
288962306a36Sopenharmony_ci
289062306a36Sopenharmony_ci		/* Apply LE States quirk from solar onwards */
289162306a36Sopenharmony_ci		set_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks);
289262306a36Sopenharmony_ci
289362306a36Sopenharmony_ci		/* Setup MSFT Extension support */
289462306a36Sopenharmony_ci		btintel_set_msft_opcode(hdev,
289562306a36Sopenharmony_ci					INTEL_HW_VARIANT(ver_tlv.cnvi_bt));
289662306a36Sopenharmony_ci		btintel_set_dsm_reset_method(hdev, &ver_tlv);
289762306a36Sopenharmony_ci
289862306a36Sopenharmony_ci		err = btintel_bootloader_setup_tlv(hdev, &ver_tlv);
289962306a36Sopenharmony_ci		btintel_register_devcoredump_support(hdev);
290062306a36Sopenharmony_ci		break;
290162306a36Sopenharmony_ci	default:
290262306a36Sopenharmony_ci		bt_dev_err(hdev, "Unsupported Intel hw variant (%u)",
290362306a36Sopenharmony_ci			   INTEL_HW_VARIANT(ver_tlv.cnvi_bt));
290462306a36Sopenharmony_ci		err = -EINVAL;
290562306a36Sopenharmony_ci		break;
290662306a36Sopenharmony_ci	}
290762306a36Sopenharmony_ci
290862306a36Sopenharmony_ciexit_error:
290962306a36Sopenharmony_ci	kfree_skb(skb);
291062306a36Sopenharmony_ci
291162306a36Sopenharmony_ci	return err;
291262306a36Sopenharmony_ci}
291362306a36Sopenharmony_ci
291462306a36Sopenharmony_cistatic int btintel_shutdown_combined(struct hci_dev *hdev)
291562306a36Sopenharmony_ci{
291662306a36Sopenharmony_ci	struct sk_buff *skb;
291762306a36Sopenharmony_ci	int ret;
291862306a36Sopenharmony_ci
291962306a36Sopenharmony_ci	/* Send HCI Reset to the controller to stop any BT activity which
292062306a36Sopenharmony_ci	 * were triggered. This will help to save power and maintain the
292162306a36Sopenharmony_ci	 * sync b/w Host and controller
292262306a36Sopenharmony_ci	 */
292362306a36Sopenharmony_ci	skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
292462306a36Sopenharmony_ci	if (IS_ERR(skb)) {
292562306a36Sopenharmony_ci		bt_dev_err(hdev, "HCI reset during shutdown failed");
292662306a36Sopenharmony_ci		return PTR_ERR(skb);
292762306a36Sopenharmony_ci	}
292862306a36Sopenharmony_ci	kfree_skb(skb);
292962306a36Sopenharmony_ci
293062306a36Sopenharmony_ci
293162306a36Sopenharmony_ci	/* Some platforms have an issue with BT LED when the interface is
293262306a36Sopenharmony_ci	 * down or BT radio is turned off, which takes 5 seconds to BT LED
293362306a36Sopenharmony_ci	 * goes off. As a workaround, sends HCI_Intel_SW_RFKILL to put the
293462306a36Sopenharmony_ci	 * device in the RFKILL ON state which turns off the BT LED immediately.
293562306a36Sopenharmony_ci	 */
293662306a36Sopenharmony_ci	if (btintel_test_flag(hdev, INTEL_BROKEN_SHUTDOWN_LED)) {
293762306a36Sopenharmony_ci		skb = __hci_cmd_sync(hdev, 0xfc3f, 0, NULL, HCI_INIT_TIMEOUT);
293862306a36Sopenharmony_ci		if (IS_ERR(skb)) {
293962306a36Sopenharmony_ci			ret = PTR_ERR(skb);
294062306a36Sopenharmony_ci			bt_dev_err(hdev, "turning off Intel device LED failed");
294162306a36Sopenharmony_ci			return ret;
294262306a36Sopenharmony_ci		}
294362306a36Sopenharmony_ci		kfree_skb(skb);
294462306a36Sopenharmony_ci	}
294562306a36Sopenharmony_ci
294662306a36Sopenharmony_ci	return 0;
294762306a36Sopenharmony_ci}
294862306a36Sopenharmony_ci
294962306a36Sopenharmony_ciint btintel_configure_setup(struct hci_dev *hdev, const char *driver_name)
295062306a36Sopenharmony_ci{
295162306a36Sopenharmony_ci	hdev->manufacturer = 2;
295262306a36Sopenharmony_ci	hdev->setup = btintel_setup_combined;
295362306a36Sopenharmony_ci	hdev->shutdown = btintel_shutdown_combined;
295462306a36Sopenharmony_ci	hdev->hw_error = btintel_hw_error;
295562306a36Sopenharmony_ci	hdev->set_diag = btintel_set_diag_combined;
295662306a36Sopenharmony_ci	hdev->set_bdaddr = btintel_set_bdaddr;
295762306a36Sopenharmony_ci
295862306a36Sopenharmony_ci	coredump_info.driver_name = driver_name;
295962306a36Sopenharmony_ci
296062306a36Sopenharmony_ci	return 0;
296162306a36Sopenharmony_ci}
296262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(btintel_configure_setup);
296362306a36Sopenharmony_ci
296462306a36Sopenharmony_cistatic int btintel_diagnostics(struct hci_dev *hdev, struct sk_buff *skb)
296562306a36Sopenharmony_ci{
296662306a36Sopenharmony_ci	struct intel_tlv *tlv = (void *)&skb->data[5];
296762306a36Sopenharmony_ci
296862306a36Sopenharmony_ci	/* The first event is always an event type TLV */
296962306a36Sopenharmony_ci	if (tlv->type != INTEL_TLV_TYPE_ID)
297062306a36Sopenharmony_ci		goto recv_frame;
297162306a36Sopenharmony_ci
297262306a36Sopenharmony_ci	switch (tlv->val[0]) {
297362306a36Sopenharmony_ci	case INTEL_TLV_SYSTEM_EXCEPTION:
297462306a36Sopenharmony_ci	case INTEL_TLV_FATAL_EXCEPTION:
297562306a36Sopenharmony_ci	case INTEL_TLV_DEBUG_EXCEPTION:
297662306a36Sopenharmony_ci	case INTEL_TLV_TEST_EXCEPTION:
297762306a36Sopenharmony_ci		/* Generate devcoredump from exception */
297862306a36Sopenharmony_ci		if (!hci_devcd_init(hdev, skb->len)) {
297962306a36Sopenharmony_ci			hci_devcd_append(hdev, skb);
298062306a36Sopenharmony_ci			hci_devcd_complete(hdev);
298162306a36Sopenharmony_ci		} else {
298262306a36Sopenharmony_ci			bt_dev_err(hdev, "Failed to generate devcoredump");
298362306a36Sopenharmony_ci			kfree_skb(skb);
298462306a36Sopenharmony_ci		}
298562306a36Sopenharmony_ci		return 0;
298662306a36Sopenharmony_ci	default:
298762306a36Sopenharmony_ci		bt_dev_err(hdev, "Invalid exception type %02X", tlv->val[0]);
298862306a36Sopenharmony_ci	}
298962306a36Sopenharmony_ci
299062306a36Sopenharmony_cirecv_frame:
299162306a36Sopenharmony_ci	return hci_recv_frame(hdev, skb);
299262306a36Sopenharmony_ci}
299362306a36Sopenharmony_ci
299462306a36Sopenharmony_ciint btintel_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
299562306a36Sopenharmony_ci{
299662306a36Sopenharmony_ci	struct hci_event_hdr *hdr = (void *)skb->data;
299762306a36Sopenharmony_ci	const char diagnostics_hdr[] = { 0x87, 0x80, 0x03 };
299862306a36Sopenharmony_ci
299962306a36Sopenharmony_ci	if (skb->len > HCI_EVENT_HDR_SIZE && hdr->evt == 0xff &&
300062306a36Sopenharmony_ci	    hdr->plen > 0) {
300162306a36Sopenharmony_ci		const void *ptr = skb->data + HCI_EVENT_HDR_SIZE + 1;
300262306a36Sopenharmony_ci		unsigned int len = skb->len - HCI_EVENT_HDR_SIZE - 1;
300362306a36Sopenharmony_ci
300462306a36Sopenharmony_ci		if (btintel_test_flag(hdev, INTEL_BOOTLOADER)) {
300562306a36Sopenharmony_ci			switch (skb->data[2]) {
300662306a36Sopenharmony_ci			case 0x02:
300762306a36Sopenharmony_ci				/* When switching to the operational firmware
300862306a36Sopenharmony_ci				 * the device sends a vendor specific event
300962306a36Sopenharmony_ci				 * indicating that the bootup completed.
301062306a36Sopenharmony_ci				 */
301162306a36Sopenharmony_ci				btintel_bootup(hdev, ptr, len);
301262306a36Sopenharmony_ci				break;
301362306a36Sopenharmony_ci			case 0x06:
301462306a36Sopenharmony_ci				/* When the firmware loading completes the
301562306a36Sopenharmony_ci				 * device sends out a vendor specific event
301662306a36Sopenharmony_ci				 * indicating the result of the firmware
301762306a36Sopenharmony_ci				 * loading.
301862306a36Sopenharmony_ci				 */
301962306a36Sopenharmony_ci				btintel_secure_send_result(hdev, ptr, len);
302062306a36Sopenharmony_ci				break;
302162306a36Sopenharmony_ci			}
302262306a36Sopenharmony_ci		}
302362306a36Sopenharmony_ci
302462306a36Sopenharmony_ci		/* Handle all diagnostics events separately. May still call
302562306a36Sopenharmony_ci		 * hci_recv_frame.
302662306a36Sopenharmony_ci		 */
302762306a36Sopenharmony_ci		if (len >= sizeof(diagnostics_hdr) &&
302862306a36Sopenharmony_ci		    memcmp(&skb->data[2], diagnostics_hdr,
302962306a36Sopenharmony_ci			   sizeof(diagnostics_hdr)) == 0) {
303062306a36Sopenharmony_ci			return btintel_diagnostics(hdev, skb);
303162306a36Sopenharmony_ci		}
303262306a36Sopenharmony_ci	}
303362306a36Sopenharmony_ci
303462306a36Sopenharmony_ci	return hci_recv_frame(hdev, skb);
303562306a36Sopenharmony_ci}
303662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(btintel_recv_event);
303762306a36Sopenharmony_ci
303862306a36Sopenharmony_civoid btintel_bootup(struct hci_dev *hdev, const void *ptr, unsigned int len)
303962306a36Sopenharmony_ci{
304062306a36Sopenharmony_ci	const struct intel_bootup *evt = ptr;
304162306a36Sopenharmony_ci
304262306a36Sopenharmony_ci	if (len != sizeof(*evt))
304362306a36Sopenharmony_ci		return;
304462306a36Sopenharmony_ci
304562306a36Sopenharmony_ci	if (btintel_test_and_clear_flag(hdev, INTEL_BOOTING))
304662306a36Sopenharmony_ci		btintel_wake_up_flag(hdev, INTEL_BOOTING);
304762306a36Sopenharmony_ci}
304862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(btintel_bootup);
304962306a36Sopenharmony_ci
305062306a36Sopenharmony_civoid btintel_secure_send_result(struct hci_dev *hdev,
305162306a36Sopenharmony_ci				const void *ptr, unsigned int len)
305262306a36Sopenharmony_ci{
305362306a36Sopenharmony_ci	const struct intel_secure_send_result *evt = ptr;
305462306a36Sopenharmony_ci
305562306a36Sopenharmony_ci	if (len != sizeof(*evt))
305662306a36Sopenharmony_ci		return;
305762306a36Sopenharmony_ci
305862306a36Sopenharmony_ci	if (evt->result)
305962306a36Sopenharmony_ci		btintel_set_flag(hdev, INTEL_FIRMWARE_FAILED);
306062306a36Sopenharmony_ci
306162306a36Sopenharmony_ci	if (btintel_test_and_clear_flag(hdev, INTEL_DOWNLOADING) &&
306262306a36Sopenharmony_ci	    btintel_test_flag(hdev, INTEL_FIRMWARE_LOADED))
306362306a36Sopenharmony_ci		btintel_wake_up_flag(hdev, INTEL_DOWNLOADING);
306462306a36Sopenharmony_ci}
306562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(btintel_secure_send_result);
306662306a36Sopenharmony_ci
306762306a36Sopenharmony_ciMODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
306862306a36Sopenharmony_ciMODULE_DESCRIPTION("Bluetooth support for Intel devices ver " VERSION);
306962306a36Sopenharmony_ciMODULE_VERSION(VERSION);
307062306a36Sopenharmony_ciMODULE_LICENSE("GPL");
307162306a36Sopenharmony_ciMODULE_FIRMWARE("intel/ibt-11-5.sfi");
307262306a36Sopenharmony_ciMODULE_FIRMWARE("intel/ibt-11-5.ddc");
307362306a36Sopenharmony_ciMODULE_FIRMWARE("intel/ibt-12-16.sfi");
307462306a36Sopenharmony_ciMODULE_FIRMWARE("intel/ibt-12-16.ddc");
3075