forked from Minki/linux
Bluetooth: btintel: Create common function for firmware download
The firmware download flow for RAM SKU is same for both USB and UART and this patch creates a common function for both driver. Signed-off-by: Tedd Ho-Jeong An <tedd.an@linux.intel.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
This commit is contained in:
parent
faf174d297
commit
fbbe83c52b
@ -24,6 +24,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
#include <net/bluetooth/hci_core.h>
|
||||
@ -640,6 +641,89 @@ int btintel_read_boot_params(struct hci_dev *hdev,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(btintel_read_boot_params);
|
||||
|
||||
int btintel_download_firmware(struct hci_dev *hdev, const struct firmware *fw,
|
||||
u32 *boot_param)
|
||||
{
|
||||
int err;
|
||||
const u8 *fw_ptr;
|
||||
u32 frag_len;
|
||||
|
||||
/* Start the firmware download transaction with the Init fragment
|
||||
* represented by the 128 bytes of CSS header.
|
||||
*/
|
||||
err = btintel_secure_send(hdev, 0x00, 128, fw->data);
|
||||
if (err < 0) {
|
||||
bt_dev_err(hdev, "Failed to send firmware header (%d)", err);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Send the 256 bytes of public key information from the firmware
|
||||
* as the PKey fragment.
|
||||
*/
|
||||
err = btintel_secure_send(hdev, 0x03, 256, fw->data + 128);
|
||||
if (err < 0) {
|
||||
bt_dev_err(hdev, "Failed to send firmware pkey (%d)", err);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Send the 256 bytes of signature information from the firmware
|
||||
* as the Sign fragment.
|
||||
*/
|
||||
err = btintel_secure_send(hdev, 0x02, 256, fw->data + 388);
|
||||
if (err < 0) {
|
||||
bt_dev_err(hdev, "Failed to send firmware signature (%d)", err);
|
||||
goto done;
|
||||
}
|
||||
|
||||
fw_ptr = fw->data + 644;
|
||||
frag_len = 0;
|
||||
|
||||
while (fw_ptr - fw->data < fw->size) {
|
||||
struct hci_command_hdr *cmd = (void *)(fw_ptr + frag_len);
|
||||
|
||||
/* Each SKU has a different reset parameter to use in the
|
||||
* HCI_Intel_Reset command and it is embedded in the firmware
|
||||
* data. So, instead of using static value per SKU, check
|
||||
* the firmware data and save it for later use.
|
||||
*/
|
||||
if (le16_to_cpu(cmd->opcode) == 0xfc0e) {
|
||||
/* The boot parameter is the first 32-bit value
|
||||
* and rest of 3 octets are reserved.
|
||||
*/
|
||||
*boot_param = get_unaligned_le32(fw_ptr + sizeof(*cmd));
|
||||
|
||||
bt_dev_dbg(hdev, "boot_param=0x%x", *boot_param);
|
||||
}
|
||||
|
||||
frag_len += sizeof(*cmd) + cmd->plen;
|
||||
|
||||
/* The parameter length of the secure send command requires
|
||||
* a 4 byte alignment. It happens so that the firmware file
|
||||
* contains proper Intel_NOP commands to align the fragments
|
||||
* as needed.
|
||||
*
|
||||
* Send set of commands with 4 byte alignment from the
|
||||
* firmware data buffer as a single Data fragement.
|
||||
*/
|
||||
if (!(frag_len % 4)) {
|
||||
err = btintel_secure_send(hdev, 0x01, frag_len, fw_ptr);
|
||||
if (err < 0) {
|
||||
bt_dev_err(hdev,
|
||||
"Failed to send firmware data (%d)",
|
||||
err);
|
||||
goto done;
|
||||
}
|
||||
|
||||
fw_ptr += frag_len;
|
||||
frag_len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(btintel_download_firmware);
|
||||
|
||||
MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
|
||||
MODULE_DESCRIPTION("Bluetooth support for Intel devices ver " VERSION);
|
||||
MODULE_VERSION(VERSION);
|
||||
|
@ -100,7 +100,8 @@ struct regmap *btintel_regmap_init(struct hci_dev *hdev, u16 opcode_read,
|
||||
int btintel_send_intel_reset(struct hci_dev *hdev, u32 boot_param);
|
||||
int btintel_read_boot_params(struct hci_dev *hdev,
|
||||
struct intel_boot_params *params);
|
||||
|
||||
int btintel_download_firmware(struct hci_dev *dev, const struct firmware *fw,
|
||||
u32 *boot_param);
|
||||
#else
|
||||
|
||||
static inline int btintel_check_bdaddr(struct hci_dev *hdev)
|
||||
@ -188,4 +189,11 @@ static inline int btintel_read_boot_params(struct hci_dev *hdev,
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int btintel_download_firmware(struct hci_dev *dev,
|
||||
const struct firmware *fw,
|
||||
u32 *boot_param)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
#endif
|
||||
|
@ -2013,8 +2013,6 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
|
||||
struct intel_version ver;
|
||||
struct intel_boot_params params;
|
||||
const struct firmware *fw;
|
||||
const u8 *fw_ptr;
|
||||
u32 frag_len;
|
||||
u32 boot_param;
|
||||
char fwname[64];
|
||||
ktime_t calltime, delta, rettime;
|
||||
@ -2201,78 +2199,10 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
|
||||
|
||||
set_bit(BTUSB_DOWNLOADING, &data->flags);
|
||||
|
||||
/* Start the firmware download transaction with the Init fragment
|
||||
* represented by the 128 bytes of CSS header.
|
||||
*/
|
||||
err = btintel_secure_send(hdev, 0x00, 128, fw->data);
|
||||
if (err < 0) {
|
||||
BT_ERR("%s: Failed to send firmware header (%d)",
|
||||
hdev->name, err);
|
||||
/* Start firmware downloading and get boot parameter */
|
||||
err = btintel_download_firmware(hdev, fw, &boot_param);
|
||||
if (err < 0)
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Send the 256 bytes of public key information from the firmware
|
||||
* as the PKey fragment.
|
||||
*/
|
||||
err = btintel_secure_send(hdev, 0x03, 256, fw->data + 128);
|
||||
if (err < 0) {
|
||||
BT_ERR("%s: Failed to send firmware public key (%d)",
|
||||
hdev->name, err);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Send the 256 bytes of signature information from the firmware
|
||||
* as the Sign fragment.
|
||||
*/
|
||||
err = btintel_secure_send(hdev, 0x02, 256, fw->data + 388);
|
||||
if (err < 0) {
|
||||
BT_ERR("%s: Failed to send firmware signature (%d)",
|
||||
hdev->name, err);
|
||||
goto done;
|
||||
}
|
||||
|
||||
fw_ptr = fw->data + 644;
|
||||
frag_len = 0;
|
||||
|
||||
while (fw_ptr - fw->data < fw->size) {
|
||||
struct hci_command_hdr *cmd = (void *)(fw_ptr + frag_len);
|
||||
|
||||
/* Each SKU has a different reset parameter to use in the
|
||||
* HCI_Intel_Reset command and it is embedded in the firmware
|
||||
* data. So, instead of using static value per SKU, check
|
||||
* the firmware data and save it for later use.
|
||||
*/
|
||||
if (cmd->opcode == 0xfc0e) {
|
||||
/* The boot parameter is the first 32-bit value
|
||||
* and rest of 3 octets are reserved.
|
||||
*/
|
||||
boot_param = get_unaligned_le32(fw_ptr + sizeof(*cmd));
|
||||
|
||||
bt_dev_dbg(hdev, "boot_param=0x%x", boot_param);
|
||||
}
|
||||
|
||||
frag_len += sizeof(*cmd) + cmd->plen;
|
||||
|
||||
/* The parameter length of the secure send command requires
|
||||
* a 4 byte alignment. It happens so that the firmware file
|
||||
* contains proper Intel_NOP commands to align the fragments
|
||||
* as needed.
|
||||
*
|
||||
* Send set of commands with 4 byte alignment from the
|
||||
* firmware data buffer as a single Data fragement.
|
||||
*/
|
||||
if (!(frag_len % 4)) {
|
||||
err = btintel_secure_send(hdev, 0x01, frag_len, fw_ptr);
|
||||
if (err < 0) {
|
||||
BT_ERR("%s: Failed to send firmware data (%d)",
|
||||
hdev->name, err);
|
||||
goto done;
|
||||
}
|
||||
|
||||
fw_ptr += frag_len;
|
||||
frag_len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
set_bit(BTUSB_FIRMWARE_LOADED, &data->flags);
|
||||
|
||||
|
@ -33,7 +33,6 @@
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
#include <net/bluetooth/hci_core.h>
|
||||
@ -548,9 +547,7 @@ static int intel_setup(struct hci_uart *hu)
|
||||
struct intel_boot_params params;
|
||||
struct list_head *p;
|
||||
const struct firmware *fw;
|
||||
const u8 *fw_ptr;
|
||||
char fwname[64];
|
||||
u32 frag_len;
|
||||
u32 boot_param;
|
||||
ktime_t calltime, delta, rettime;
|
||||
unsigned long long duration;
|
||||
@ -761,84 +758,10 @@ static int intel_setup(struct hci_uart *hu)
|
||||
|
||||
set_bit(STATE_DOWNLOADING, &intel->flags);
|
||||
|
||||
/* Start the firmware download transaction with the Init fragment
|
||||
* represented by the 128 bytes of CSS header.
|
||||
*/
|
||||
err = btintel_secure_send(hdev, 0x00, 128, fw->data);
|
||||
if (err < 0) {
|
||||
bt_dev_err(hdev, "Failed to send firmware header (%d)", err);
|
||||
/* Start firmware downloading and get boot parameter */
|
||||
err = btintel_download_firmware(hdev, fw, &boot_param);
|
||||
if (err < 0)
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Send the 256 bytes of public key information from the firmware
|
||||
* as the PKey fragment.
|
||||
*/
|
||||
err = btintel_secure_send(hdev, 0x03, 256, fw->data + 128);
|
||||
if (err < 0) {
|
||||
bt_dev_err(hdev, "Failed to send firmware public key (%d)",
|
||||
err);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Send the 256 bytes of signature information from the firmware
|
||||
* as the Sign fragment.
|
||||
*/
|
||||
err = btintel_secure_send(hdev, 0x02, 256, fw->data + 388);
|
||||
if (err < 0) {
|
||||
bt_dev_err(hdev, "Failed to send firmware signature (%d)",
|
||||
err);
|
||||
goto done;
|
||||
}
|
||||
|
||||
fw_ptr = fw->data + 644;
|
||||
frag_len = 0;
|
||||
|
||||
while (fw_ptr - fw->data < fw->size) {
|
||||
struct hci_command_hdr *cmd = (void *)(fw_ptr + frag_len);
|
||||
|
||||
/* Each SKU has a different reset parameter to use in the
|
||||
* HCI_Intel_Reset command and it is embedded in the firmware
|
||||
* data. So, instead of using static value per SKU, check
|
||||
* the firmware data and save it for later use.
|
||||
*/
|
||||
if (cmd->opcode == 0xfc0e) {
|
||||
/* The boot parameter is the first 32-bit value
|
||||
* and rest of 3 octets are reserved.
|
||||
*/
|
||||
boot_param = get_unaligned_le32(fw_ptr + sizeof(*cmd));
|
||||
|
||||
bt_dev_dbg(hdev, "boot_param=0x%x", boot_param);
|
||||
}
|
||||
|
||||
frag_len += sizeof(*cmd) + cmd->plen;
|
||||
|
||||
bt_dev_dbg(hdev, "Patching %td/%zu", (fw_ptr - fw->data),
|
||||
fw->size);
|
||||
|
||||
/* The parameter length of the secure send command requires
|
||||
* a 4 byte alignment. It happens so that the firmware file
|
||||
* contains proper Intel_NOP commands to align the fragments
|
||||
* as needed.
|
||||
*
|
||||
* Send set of commands with 4 byte alignment from the
|
||||
* firmware data buffer as a single Data fragement.
|
||||
*/
|
||||
if (frag_len % 4)
|
||||
continue;
|
||||
|
||||
/* Send each command from the firmware data buffer as
|
||||
* a single Data fragment.
|
||||
*/
|
||||
err = btintel_secure_send(hdev, 0x01, frag_len, fw_ptr);
|
||||
if (err < 0) {
|
||||
bt_dev_err(hdev, "Failed to send firmware data (%d)",
|
||||
err);
|
||||
goto done;
|
||||
}
|
||||
|
||||
fw_ptr += frag_len;
|
||||
frag_len = 0;
|
||||
}
|
||||
|
||||
set_bit(STATE_FIRMWARE_LOADED, &intel->flags);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user