|
12 | 12 | #include <linux/acpi.h>
|
13 | 13 | #include <acpi/acpi_bus.h>
|
14 | 14 | #include <asm/unaligned.h>
|
| 15 | +#include <linux/efi.h> |
15 | 16 |
|
16 | 17 | #include <net/bluetooth/bluetooth.h>
|
17 | 18 | #include <net/bluetooth/hci_core.h>
|
|
26 | 27 | #define ECDSA_OFFSET 644
|
27 | 28 | #define ECDSA_HEADER_LEN 320
|
28 | 29 |
|
| 30 | +#define BTINTEL_EFI_DSBR L"UefiCnvCommonDSBR" |
| 31 | + |
29 | 32 | enum {
|
30 | 33 | DSM_SET_WDISABLE2_DELAY = 1,
|
31 | 34 | DSM_SET_RESET_METHOD = 3,
|
@@ -2616,6 +2619,120 @@ static u8 btintel_classify_pkt_type(struct hci_dev *hdev, struct sk_buff *skb)
|
2616 | 2619 | return hci_skb_pkt_type(skb);
|
2617 | 2620 | }
|
2618 | 2621 |
|
| 2622 | +/* |
| 2623 | + * UefiCnvCommonDSBR UEFI variable provides information from the OEM platforms |
| 2624 | + * if they have replaced the BRI (Bluetooth Radio Interface) resistor to |
| 2625 | + * overcome the potential STEP errors on their designs. Based on the |
| 2626 | + * configauration, bluetooth firmware shall adjust the BRI response line drive |
| 2627 | + * strength. The below structure represents DSBR data. |
| 2628 | + * struct { |
| 2629 | + * u8 header; |
| 2630 | + * u32 dsbr; |
| 2631 | + * } __packed; |
| 2632 | + * |
| 2633 | + * header - defines revision number of the structure |
| 2634 | + * dsbr - defines drive strength BRI response |
| 2635 | + * bit0 |
| 2636 | + * 0 - instructs bluetooth firmware to use default values |
| 2637 | + * 1 - instructs bluetooth firmware to override default values |
| 2638 | + * bit3:1 |
| 2639 | + * Reserved |
| 2640 | + * bit7:4 |
| 2641 | + * DSBR override values (only if bit0 is set. Default value is 0xF |
| 2642 | + * bit31:7 |
| 2643 | + * Reserved |
| 2644 | + * Expected values for dsbr field: |
| 2645 | + * 1. 0xF1 - indicates that the resistor on board is 33 Ohm |
| 2646 | + * 2. 0x00 or 0xB1 - indicates that the resistor on board is 10 Ohm |
| 2647 | + * 3. Non existing UEFI variable or invalid (none of the above) - indicates |
| 2648 | + * that the resistor on board is 10 Ohm |
| 2649 | + * Even if uefi variable is not present, driver shall send 0xfc0a command to |
| 2650 | + * firmware to use default values. |
| 2651 | + * |
| 2652 | + */ |
| 2653 | +static int btintel_uefi_get_dsbr(u32 *dsbr_var) |
| 2654 | +{ |
| 2655 | + struct btintel_dsbr { |
| 2656 | + u8 header; |
| 2657 | + u32 dsbr; |
| 2658 | + } __packed data; |
| 2659 | + |
| 2660 | + efi_status_t status; |
| 2661 | + unsigned long data_size = 0; |
| 2662 | + efi_guid_t guid = EFI_GUID(0xe65d8884, 0xd4af, 0x4b20, 0x8d, 0x03, |
| 2663 | + 0x77, 0x2e, 0xcc, 0x3d, 0xa5, 0x31); |
| 2664 | + |
| 2665 | + if (!IS_ENABLED(CONFIG_EFI)) |
| 2666 | + return -EOPNOTSUPP; |
| 2667 | + |
| 2668 | + if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE)) |
| 2669 | + return -EOPNOTSUPP; |
| 2670 | + |
| 2671 | + status = efi.get_variable(BTINTEL_EFI_DSBR, &guid, NULL, &data_size, |
| 2672 | + NULL); |
| 2673 | + |
| 2674 | + if (status != EFI_BUFFER_TOO_SMALL || !data_size) |
| 2675 | + return -EIO; |
| 2676 | + |
| 2677 | + status = efi.get_variable(BTINTEL_EFI_DSBR, &guid, NULL, &data_size, |
| 2678 | + &data); |
| 2679 | + |
| 2680 | + if (status != EFI_SUCCESS) |
| 2681 | + return -ENXIO; |
| 2682 | + |
| 2683 | + *dsbr_var = data.dsbr; |
| 2684 | + return 0; |
| 2685 | +} |
| 2686 | + |
| 2687 | +static int btintel_set_dsbr(struct hci_dev *hdev, struct intel_version_tlv *ver) |
| 2688 | +{ |
| 2689 | + struct btintel_dsbr_cmd { |
| 2690 | + u8 enable; |
| 2691 | + u8 dsbr; |
| 2692 | + } __packed; |
| 2693 | + |
| 2694 | + struct btintel_dsbr_cmd cmd; |
| 2695 | + struct sk_buff *skb; |
| 2696 | + u8 status; |
| 2697 | + u32 dsbr; |
| 2698 | + bool apply_dsbr; |
| 2699 | + int err; |
| 2700 | + |
| 2701 | + /* DSBR command needs to be sent for BlazarI + B0 step product after |
| 2702 | + * downloading IML image. |
| 2703 | + */ |
| 2704 | + apply_dsbr = (ver->img_type == BTINTEL_IMG_IML && |
| 2705 | + ((ver->cnvi_top & 0xfff) == BTINTEL_CNVI_BLAZARI) && |
| 2706 | + INTEL_CNVX_TOP_STEP(ver->cnvi_top) == 0x01); |
| 2707 | + |
| 2708 | + if (!apply_dsbr) |
| 2709 | + return 0; |
| 2710 | + |
| 2711 | + dsbr = 0; |
| 2712 | + err = btintel_uefi_get_dsbr(&dsbr); |
| 2713 | + if (err < 0) |
| 2714 | + bt_dev_dbg(hdev, "Error reading efi: %ls (%d)", |
| 2715 | + BTINTEL_EFI_DSBR, err); |
| 2716 | + |
| 2717 | + cmd.enable = dsbr & BIT(0); |
| 2718 | + cmd.dsbr = dsbr >> 4 & 0xF; |
| 2719 | + |
| 2720 | + bt_dev_info(hdev, "dsbr: enable: 0x%2.2x value: 0x%2.2x", cmd.enable, |
| 2721 | + cmd.dsbr); |
| 2722 | + |
| 2723 | + skb = __hci_cmd_sync(hdev, 0xfc0a, sizeof(cmd), &cmd, HCI_CMD_TIMEOUT); |
| 2724 | + if (IS_ERR(skb)) |
| 2725 | + return -bt_to_errno(PTR_ERR(skb)); |
| 2726 | + |
| 2727 | + status = skb->data[0]; |
| 2728 | + kfree_skb(skb); |
| 2729 | + |
| 2730 | + if (status) |
| 2731 | + return -bt_to_errno(status); |
| 2732 | + |
| 2733 | + return 0; |
| 2734 | +} |
| 2735 | + |
2619 | 2736 | int btintel_bootloader_setup_tlv(struct hci_dev *hdev,
|
2620 | 2737 | struct intel_version_tlv *ver)
|
2621 | 2738 | {
|
@@ -2650,6 +2767,13 @@ int btintel_bootloader_setup_tlv(struct hci_dev *hdev,
|
2650 | 2767 | if (err)
|
2651 | 2768 | return err;
|
2652 | 2769 |
|
| 2770 | + /* set drive strength of BRI response */ |
| 2771 | + err = btintel_set_dsbr(hdev, ver); |
| 2772 | + if (err) { |
| 2773 | + bt_dev_err(hdev, "Failed to send dsbr command (%d)", err); |
| 2774 | + return err; |
| 2775 | + } |
| 2776 | + |
2653 | 2777 | /* If image type returned is BTINTEL_IMG_IML, then controller supports
|
2654 | 2778 | * intermediate loader image
|
2655 | 2779 | */
|
|
0 commit comments