Bluetooth: btusb: Add support Mediatek MT7925
authorPeter Tsao <peter.tsao@mediatek.com>
Tue, 20 Jun 2023 08:27:50 +0000 (16:27 +0800)
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Fri, 11 Aug 2023 18:39:39 +0000 (11:39 -0700)
This patch is added support Mediatek MT7925.
1. The firmware location of MT7925 will set to
/lib/firmware/mediatek/mt7925
2. Add Mediatek private data in hdev
to record the device for handle MT7925 flow.
3. Use the recoreded dev_id to condition chip reset flow.

The information in /sys/kernel/debug/usb/devices about the MT7925U
Bluetooth device is listed as the below

T:  Bus=01 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 27 Spd=480  MxCh= 0
D:  Ver= 2.10 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs=  1
P:  Vendor=0e8d ProdID=7925 Rev= 1.00
S:  Manufacturer=MediaTek Inc.
S:  Product=Wireless_Device
S:  SerialNumber=000000000
C:* #Ifs= 4 Cfg#= 1 Atr=e0 MxPwr=100mA
A:  FirstIf#= 0 IfCount= 3 Cls=e0(wlcon) Sub=01 Prot=01
I:* If#= 0 Alt= 0 #EPs= 5 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=81(I) Atr=03(Int.) MxPS=  16 Ivl=125us
E:  Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E:  Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E:  Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E:  Ad=8f(I) Atr=03(Int.) MxPS=   2 Ivl=125us
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
I:* If#= 3 Alt= 0 #EPs= 9 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none)
E:  Ad=84(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E:  Ad=85(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E:  Ad=08(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E:  Ad=04(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E:  Ad=05(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E:  Ad=06(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E:  Ad=07(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E:  Ad=09(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E:  Ad=86(I) Atr=03(Int.) MxPS=   2 Ivl=125us

Signed-off-by: Peter Tsao <peter.tsao@mediatek.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
drivers/bluetooth/btmtk.c
drivers/bluetooth/btmtk.h
drivers/bluetooth/btusb.c

index 809762d..9482401 100644 (file)
@@ -289,3 +289,4 @@ MODULE_FIRMWARE(FIRMWARE_MT7622);
 MODULE_FIRMWARE(FIRMWARE_MT7663);
 MODULE_FIRMWARE(FIRMWARE_MT7668);
 MODULE_FIRMWARE(FIRMWARE_MT7961);
+MODULE_FIRMWARE(FIRMWARE_MT7925);
index 2a88ea8..fadc1a5 100644 (file)
@@ -5,6 +5,7 @@
 #define FIRMWARE_MT7663                "mediatek/mt7663pr2h.bin"
 #define FIRMWARE_MT7668                "mediatek/mt7668pr2h.bin"
 #define FIRMWARE_MT7961                "mediatek/BT_RAM_CODE_MT7961_1_2_hdr.bin"
+#define FIRMWARE_MT7925                "mediatek/mt7925/BT_RAM_CODE_MT7925_1_1_hdr.bin"
 
 #define HCI_EV_WMT 0xe4
 #define HCI_WMT_MAX_EVENT_SIZE         64
@@ -119,6 +120,10 @@ struct btmtk_hci_wmt_params {
        u32 *status;
 };
 
+struct btmediatek_data {
+       u32 dev_id;
+};
+
 typedef int (*wmt_cmd_sync_func_t)(struct hci_dev *,
                                   struct btmtk_hci_wmt_params *);
 
index f99ce34..e1e271e 100644 (file)
@@ -2659,6 +2659,9 @@ static int btusb_recv_event_realtek(struct hci_dev *hdev, struct sk_buff *skb)
 #define MTK_BT_RST_DONE                0x00000100
 #define MTK_BT_RESET_WAIT_MS   100
 #define MTK_BT_RESET_NUM_TRIES 10
+#define MTK_BT_RESET_REG_CONNV3        0x70028610
+#define MTK_BT_READ_DEV_ID     0x70010200
+
 
 static void btusb_mtk_wmt_recv(struct urb *urb)
 {
@@ -3039,10 +3042,11 @@ static int btusb_mtk_setup(struct hci_dev *hdev)
        struct sk_buff *skb;
        const char *fwname;
        int err, status;
-       u32 dev_id;
+       u32 dev_id = 0;
        char fw_bin_name[64];
        u32 fw_version = 0;
        u8 param;
+       struct btmediatek_data *mediatek;
 
        calltime = ktime_get();
 
@@ -3052,7 +3056,7 @@ static int btusb_mtk_setup(struct hci_dev *hdev)
                return err;
        }
 
-       if (!dev_id) {
+       if (!dev_id || dev_id != 0x7663) {
                err = btusb_mtk_id_get(data, 0x70010200, &dev_id);
                if (err < 0) {
                        bt_dev_err(hdev, "Failed to get device id (%d)", err);
@@ -3065,6 +3069,9 @@ static int btusb_mtk_setup(struct hci_dev *hdev)
                }
        }
 
+       mediatek = hci_get_priv(hdev);
+       mediatek->dev_id = dev_id;
+
        switch (dev_id) {
        case 0x7663:
                fwname = FIRMWARE_MT7663;
@@ -3074,9 +3081,16 @@ static int btusb_mtk_setup(struct hci_dev *hdev)
                break;
        case 0x7922:
        case 0x7961:
-               snprintf(fw_bin_name, sizeof(fw_bin_name),
-                       "mediatek/BT_RAM_CODE_MT%04x_1_%x_hdr.bin",
-                        dev_id & 0xffff, (fw_version & 0xff) + 1);
+       case 0x7925:
+               if (dev_id == 0x7925)
+                       snprintf(fw_bin_name, sizeof(fw_bin_name),
+                                "mediatek/mt%04x/BT_RAM_CODE_MT%04x_1_%x_hdr.bin",
+                                dev_id & 0xffff, dev_id & 0xffff, (fw_version & 0xff) + 1);
+               else
+                       snprintf(fw_bin_name, sizeof(fw_bin_name),
+                                "mediatek/BT_RAM_CODE_MT%04x_1_%x_hdr.bin",
+                                dev_id & 0xffff, (fw_version & 0xff) + 1);
+
                err = btmtk_setup_firmware_79xx(hdev, fw_bin_name,
                                                btusb_mtk_hci_wmt_sync);
                if (err < 0) {
@@ -3219,6 +3233,7 @@ static void btusb_mtk_cmd_timeout(struct hci_dev *hdev)
        struct btusb_data *data = hci_get_drvdata(hdev);
        u32 val;
        int err, retry = 0;
+       struct btmediatek_data *mediatek;
 
        /* It's MediaTek specific bluetooth reset mechanism via USB */
        if (test_and_set_bit(BTUSB_HW_RESET_ACTIVE, &data->flags)) {
@@ -3232,22 +3247,42 @@ static void btusb_mtk_cmd_timeout(struct hci_dev *hdev)
 
        btusb_stop_traffic(data);
        usb_kill_anchored_urbs(&data->tx_anchor);
+       mediatek = hci_get_priv(hdev);
+
+       if (mediatek->dev_id == 0x7925) {
+               btusb_mtk_uhw_reg_read(data, MTK_BT_RESET_REG_CONNV3, &val);
+               val |= (1 << 5);
+               btusb_mtk_uhw_reg_write(data, MTK_BT_RESET_REG_CONNV3, val);
+               btusb_mtk_uhw_reg_read(data, MTK_BT_RESET_REG_CONNV3, &val);
+               val &= 0xFFFF00FF;
+               val |= (1 << 13);
+               btusb_mtk_uhw_reg_write(data, MTK_BT_RESET_REG_CONNV3, val);
+               btusb_mtk_uhw_reg_write(data, MTK_EP_RST_OPT, 0x00010001);
+               btusb_mtk_uhw_reg_read(data, MTK_BT_RESET_REG_CONNV3, &val);
+               val |= (1 << 0);
+               btusb_mtk_uhw_reg_write(data, MTK_BT_RESET_REG_CONNV3, val);
+               btusb_mtk_uhw_reg_write(data, MTK_UDMA_INT_STA_BT, 0x000000FF);
+               btusb_mtk_uhw_reg_read(data, MTK_UDMA_INT_STA_BT, &val);
+               btusb_mtk_uhw_reg_write(data, MTK_UDMA_INT_STA_BT1, 0x000000FF);
+               btusb_mtk_uhw_reg_read(data, MTK_UDMA_INT_STA_BT1, &val);
+               msleep(100);
+       } else {
+               /* It's Device EndPoint Reset Option Register */
+               bt_dev_dbg(hdev, "Initiating reset mechanism via uhw");
+               btusb_mtk_uhw_reg_write(data, MTK_EP_RST_OPT, MTK_EP_RST_IN_OUT_OPT);
+               btusb_mtk_uhw_reg_read(data, MTK_BT_WDT_STATUS, &val);
 
-       /* It's Device EndPoint Reset Option Register */
-       bt_dev_dbg(hdev, "Initiating reset mechanism via uhw");
-       btusb_mtk_uhw_reg_write(data, MTK_EP_RST_OPT, MTK_EP_RST_IN_OUT_OPT);
-       btusb_mtk_uhw_reg_read(data, MTK_BT_WDT_STATUS, &val);
-
-       /* Reset the bluetooth chip via USB interface. */
-       btusb_mtk_uhw_reg_write(data, MTK_BT_SUBSYS_RST, 1);
-       btusb_mtk_uhw_reg_write(data, MTK_UDMA_INT_STA_BT, 0x000000FF);
-       btusb_mtk_uhw_reg_read(data, MTK_UDMA_INT_STA_BT, &val);
-       btusb_mtk_uhw_reg_write(data, MTK_UDMA_INT_STA_BT1, 0x000000FF);
-       btusb_mtk_uhw_reg_read(data, MTK_UDMA_INT_STA_BT1, &val);
-       /* MT7921 need to delay 20ms between toggle reset bit */
-       msleep(20);
-       btusb_mtk_uhw_reg_write(data, MTK_BT_SUBSYS_RST, 0);
-       btusb_mtk_uhw_reg_read(data, MTK_BT_SUBSYS_RST, &val);
+               /* Reset the bluetooth chip via USB interface. */
+               btusb_mtk_uhw_reg_write(data, MTK_BT_SUBSYS_RST, 1);
+               btusb_mtk_uhw_reg_write(data, MTK_UDMA_INT_STA_BT, 0x000000FF);
+               btusb_mtk_uhw_reg_read(data, MTK_UDMA_INT_STA_BT, &val);
+               btusb_mtk_uhw_reg_write(data, MTK_UDMA_INT_STA_BT1, 0x000000FF);
+               btusb_mtk_uhw_reg_read(data, MTK_UDMA_INT_STA_BT1, &val);
+               /* MT7921 need to delay 20ms between toggle reset bit */
+               msleep(20);
+               btusb_mtk_uhw_reg_write(data, MTK_BT_SUBSYS_RST, 0);
+               btusb_mtk_uhw_reg_read(data, MTK_BT_SUBSYS_RST, &val);
+       }
 
        /* Poll the register until reset is completed */
        do {
@@ -4289,6 +4324,9 @@ static int btusb_probe(struct usb_interface *intf,
                priv_size += sizeof(struct btrealtek_data);
 
                data->recv_event = btusb_recv_event_realtek;
+       } else if (id->driver_info & BTUSB_MEDIATEK) {
+               /* Allocate extra space for Mediatek device */
+               priv_size += sizeof(struct btmediatek_data);
        }
 
        data->recv_acl = hci_recv_frame;