Skip to content

Commit fc342c4

Browse files
Mark Chenholtmann
authored andcommitted
Bluetooth: btusb: Add protocol support for MediaTek MT7921U USB devices
There is mt7921 firmware download mechanism 1. Read Chip id from MT7921. 2. Download firmware by endpoint 0, it's the same mechanism with mt7663/mt7668. (it's medaitek specific header format for downloading firmware.) 3. Enabling Bluetooth function. The information in /sys/kernel/debug/usb/devices about the MT7921U Bluetooth device is listed as the below. T: Bus=01 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 40 Spd=480 MxCh= 0 D: Ver= 2.10 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0e8d ProdID=7961 Rev= 1.00 S: Manufacturer=MediaTek Inc. S: Product=Wireless_Device S: SerialNumber=000000000 C:* #Ifs= 3 Cfg#= 1 Atr=e0 MxPwr=100mA A: FirstIf#= 0 IfCount= 3 Cls=e0(wlcon) Sub=01 Prot=01 I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=125us E: Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms I: If#= 1 Alt= 6 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 63 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 63 Ivl=1ms I:* If#= 2 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none) E: Ad=8a(I) Atr=03(Int.) MxPS= 64 Ivl=125us E: Ad=0a(O) Atr=03(Int.) MxPS= 64 Ivl=125us I: If#= 2 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none) E: Ad=8a(I) Atr=03(Int.) MxPS= 512 Ivl=125us E: Ad=0a(O) Atr=03(Int.) MxPS= 512 Ivl=125us Signed-off-by: Mark Chen <Mark-YW.Chen@mediatek.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
1 parent 48c1330 commit fc342c4

File tree

1 file changed

+200
-0
lines changed

1 file changed

+200
-0
lines changed

drivers/bluetooth/btusb.c

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3128,6 +3128,12 @@ static int btusb_shutdown_intel_new(struct hci_dev *hdev)
31283128
#define FIRMWARE_MT7668 "mediatek/mt7668pr2h.bin"
31293129

31303130
#define HCI_WMT_MAX_EVENT_SIZE 64
3131+
/* It is for mt79xx download rom patch*/
3132+
#define MTK_FW_ROM_PATCH_HEADER_SIZE 32
3133+
#define MTK_FW_ROM_PATCH_GD_SIZE 64
3134+
#define MTK_FW_ROM_PATCH_SEC_MAP_SIZE 64
3135+
#define MTK_SEC_MAP_COMMON_SIZE 12
3136+
#define MTK_SEC_MAP_NEED_SEND_SIZE 52
31313137

31323138
enum {
31333139
BTMTK_WMT_PATCH_DWNLD = 0x1,
@@ -3184,6 +3190,40 @@ struct btmtk_hci_wmt_params {
31843190
u32 *status;
31853191
};
31863192

3193+
struct btmtk_patch_header {
3194+
u8 datetime[16];
3195+
u8 platform[4];
3196+
__le16 hwver;
3197+
__le16 swver;
3198+
__le32 magicnum;
3199+
} __packed;
3200+
3201+
struct btmtk_global_desc {
3202+
__le32 patch_ver;
3203+
__le32 sub_sys;
3204+
__le32 feature_opt;
3205+
__le32 section_num;
3206+
} __packed;
3207+
3208+
struct btmtk_section_map {
3209+
__le32 sectype;
3210+
__le32 secoffset;
3211+
__le32 secsize;
3212+
union {
3213+
__le32 u4SecSpec[13];
3214+
struct {
3215+
__le32 dlAddr;
3216+
__le32 dlsize;
3217+
__le32 seckeyidx;
3218+
__le32 alignlen;
3219+
__le32 sectype;
3220+
__le32 dlmodecrctype;
3221+
__le32 crc;
3222+
__le32 reserved[6];
3223+
} bin_info_spec;
3224+
};
3225+
} __packed;
3226+
31873227
static void btusb_mtk_wmt_recv(struct urb *urb)
31883228
{
31893229
struct hci_dev *hdev = urb->context;
@@ -3407,6 +3447,14 @@ static int btusb_mtk_hci_wmt_sync(struct hci_dev *hdev,
34073447
else
34083448
status = BTMTK_WMT_ON_UNDONE;
34093449
break;
3450+
case BTMTK_WMT_PATCH_DWNLD:
3451+
if (wmt_evt->whdr.flag == 2)
3452+
status = BTMTK_WMT_PATCH_DONE;
3453+
else if (wmt_evt->whdr.flag == 1)
3454+
status = BTMTK_WMT_PATCH_PROGRESS;
3455+
else
3456+
status = BTMTK_WMT_PATCH_UNDONE;
3457+
break;
34103458
}
34113459

34123460
if (wmt_params->status)
@@ -3419,6 +3467,122 @@ static int btusb_mtk_hci_wmt_sync(struct hci_dev *hdev,
34193467
return err;
34203468
}
34213469

3470+
static int btusb_mtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname)
3471+
{
3472+
struct btmtk_hci_wmt_params wmt_params;
3473+
struct btmtk_patch_header *patchhdr = NULL;
3474+
struct btmtk_global_desc *globaldesc = NULL;
3475+
struct btmtk_section_map *sectionmap;
3476+
const struct firmware *fw;
3477+
const u8 *fw_ptr;
3478+
const u8 *fw_bin_ptr;
3479+
size_t fw_size;
3480+
int err, dlen, i, status;
3481+
u8 flag, first_block, retry;
3482+
u32 section_num, dl_size, section_offset;
3483+
u8 cmd[64];
3484+
3485+
err = request_firmware(&fw, fwname, &hdev->dev);
3486+
if (err < 0) {
3487+
bt_dev_err(hdev, "Failed to load firmware file (%d)", err);
3488+
return err;
3489+
}
3490+
3491+
fw_ptr = fw->data;
3492+
fw_bin_ptr = fw_ptr;
3493+
fw_size = fw->size;
3494+
patchhdr = (struct btmtk_patch_header *)fw_ptr;
3495+
globaldesc = (struct btmtk_global_desc *)(fw_ptr + MTK_FW_ROM_PATCH_HEADER_SIZE);
3496+
section_num = globaldesc->section_num;
3497+
3498+
for (i = 0; i < section_num; i++) {
3499+
first_block = 1;
3500+
fw_ptr = fw_bin_ptr;
3501+
sectionmap = (struct btmtk_section_map *)(fw_ptr + MTK_FW_ROM_PATCH_HEADER_SIZE +
3502+
MTK_FW_ROM_PATCH_GD_SIZE + MTK_FW_ROM_PATCH_SEC_MAP_SIZE * i);
3503+
3504+
section_offset = sectionmap->secoffset;
3505+
dl_size = sectionmap->bin_info_spec.dlsize;
3506+
3507+
if (dl_size > 0) {
3508+
retry = 20;
3509+
while (retry > 0) {
3510+
cmd[0] = 0; /* 0 means legacy dl mode. */
3511+
memcpy(cmd + 1,
3512+
fw_ptr + MTK_FW_ROM_PATCH_HEADER_SIZE +
3513+
MTK_FW_ROM_PATCH_GD_SIZE + MTK_FW_ROM_PATCH_SEC_MAP_SIZE * i +
3514+
MTK_SEC_MAP_COMMON_SIZE,
3515+
MTK_SEC_MAP_NEED_SEND_SIZE + 1);
3516+
3517+
wmt_params.op = BTMTK_WMT_PATCH_DWNLD;
3518+
wmt_params.status = &status;
3519+
wmt_params.flag = 0;
3520+
wmt_params.dlen = MTK_SEC_MAP_NEED_SEND_SIZE + 1;
3521+
wmt_params.data = &cmd;
3522+
3523+
err = btusb_mtk_hci_wmt_sync(hdev, &wmt_params);
3524+
if (err < 0) {
3525+
bt_dev_err(hdev, "Failed to send wmt patch dwnld (%d)",
3526+
err);
3527+
goto err_release_fw;
3528+
}
3529+
3530+
if (status == BTMTK_WMT_PATCH_UNDONE) {
3531+
break;
3532+
} else if (status == BTMTK_WMT_PATCH_PROGRESS) {
3533+
msleep(100);
3534+
retry--;
3535+
} else if (status == BTMTK_WMT_PATCH_DONE) {
3536+
goto next_section;
3537+
} else {
3538+
bt_dev_err(hdev, "Failed wmt patch dwnld status (%d)",
3539+
status);
3540+
goto err_release_fw;
3541+
}
3542+
}
3543+
3544+
fw_ptr += section_offset;
3545+
wmt_params.op = BTMTK_WMT_PATCH_DWNLD;
3546+
wmt_params.status = NULL;
3547+
3548+
while (dl_size > 0) {
3549+
dlen = min_t(int, 250, dl_size);
3550+
if (first_block == 1) {
3551+
flag = 1;
3552+
first_block = 0;
3553+
} else if (dl_size - dlen <= 0) {
3554+
flag = 3;
3555+
} else {
3556+
flag = 2;
3557+
}
3558+
3559+
wmt_params.flag = flag;
3560+
wmt_params.dlen = dlen;
3561+
wmt_params.data = fw_ptr;
3562+
3563+
err = btusb_mtk_hci_wmt_sync(hdev, &wmt_params);
3564+
if (err < 0) {
3565+
bt_dev_err(hdev, "Failed to send wmt patch dwnld (%d)",
3566+
err);
3567+
goto err_release_fw;
3568+
}
3569+
3570+
dl_size -= dlen;
3571+
fw_ptr += dlen;
3572+
}
3573+
}
3574+
next_section:
3575+
continue;
3576+
}
3577+
/* Wait a few moments for firmware activation done */
3578+
usleep_range(100000, 120000);
3579+
3580+
err_release_fw:
3581+
release_firmware(fw);
3582+
3583+
return err;
3584+
}
3585+
34223586
static int btusb_mtk_setup_firmware(struct hci_dev *hdev, const char *fwname)
34233587
{
34243588
struct btmtk_hci_wmt_params wmt_params;
@@ -3573,6 +3737,8 @@ static int btusb_mtk_setup(struct hci_dev *hdev)
35733737
const char *fwname;
35743738
int err, status;
35753739
u32 dev_id;
3740+
char fw_bin_name[64];
3741+
u32 fw_version;
35763742
u8 param;
35773743

35783744
calltime = ktime_get();
@@ -3583,13 +3749,46 @@ static int btusb_mtk_setup(struct hci_dev *hdev)
35833749
return err;
35843750
}
35853751

3752+
if (!dev_id) {
3753+
err = btusb_mtk_id_get(data, 0x70010200, &dev_id);
3754+
if (err < 0) {
3755+
bt_dev_err(hdev, "Failed to get device id (%d)", err);
3756+
return err;
3757+
}
3758+
err = btusb_mtk_id_get(data, 0x80021004, &fw_version);
3759+
if (err < 0) {
3760+
bt_dev_err(hdev, "Failed to get fw version (%d)", err);
3761+
return err;
3762+
}
3763+
}
3764+
35863765
switch (dev_id) {
35873766
case 0x7663:
35883767
fwname = FIRMWARE_MT7663;
35893768
break;
35903769
case 0x7668:
35913770
fwname = FIRMWARE_MT7668;
35923771
break;
3772+
case 0x7961:
3773+
snprintf(fw_bin_name, sizeof(fw_bin_name),
3774+
"mediatek/BT_RAM_CODE_MT%04x_1_%x_hdr.bin",
3775+
dev_id & 0xffff, (fw_version & 0xff) + 1);
3776+
err = btusb_mtk_setup_firmware_79xx(hdev, fw_bin_name);
3777+
3778+
/* Enable Bluetooth protocol */
3779+
param = 1;
3780+
wmt_params.op = BTMTK_WMT_FUNC_CTRL;
3781+
wmt_params.flag = 0;
3782+
wmt_params.dlen = sizeof(param);
3783+
wmt_params.data = &param;
3784+
wmt_params.status = NULL;
3785+
3786+
err = btusb_mtk_hci_wmt_sync(hdev, &wmt_params);
3787+
if (err < 0) {
3788+
bt_dev_err(hdev, "Failed to send wmt func ctrl (%d)", err);
3789+
return err;
3790+
}
3791+
goto done;
35933792
default:
35943793
bt_dev_err(hdev, "Unsupported support hardware variant (%08x)",
35953794
dev_id);
@@ -3667,6 +3866,7 @@ static int btusb_mtk_setup(struct hci_dev *hdev)
36673866
}
36683867
kfree_skb(skb);
36693868

3869+
done:
36703870
rettime = ktime_get();
36713871
delta = ktime_sub(rettime, calltime);
36723872
duration = (unsigned long long)ktime_to_ns(delta) >> 10;

0 commit comments

Comments
 (0)