OSDN Git Service

Bluetooth: btmtksdio: add MT7921s Bluetooth support
authorSean Wang <sean.wang@mediatek.com>
Mon, 18 Oct 2021 21:30:21 +0000 (05:30 +0800)
committerMarcel Holtmann <marcel@holtmann.org>
Mon, 25 Oct 2021 13:36:24 +0000 (15:36 +0200)
add MT7921s Bluetooth support

Co-developed-by: Mark-yw Chen <mark-yw.chen@mediatek.com>
Signed-off-by: Mark-yw Chen <mark-yw.chen@mediatek.com>
Signed-off-by: Sean Wang <sean.wang@mediatek.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
drivers/bluetooth/btmtk.h
drivers/bluetooth/btmtksdio.c

index 18f43c6..6e7b0c7 100644 (file)
@@ -7,6 +7,8 @@
 
 #define HCI_WMT_MAX_EVENT_SIZE         64
 
+#define BTMTK_WMT_REG_READ 0x2
+
 enum {
        BTMTK_WMT_PATCH_DWNLD = 0x1,
        BTMTK_WMT_TEST = 0x2,
@@ -14,6 +16,7 @@ enum {
        BTMTK_WMT_HIF = 0x4,
        BTMTK_WMT_FUNC_CTRL = 0x6,
        BTMTK_WMT_RST = 0x7,
+       BTMTK_WMT_REGISTER = 0x8,
        BTMTK_WMT_SEMAPHORE = 0x17,
 };
 
@@ -49,6 +52,14 @@ struct btmtk_hci_wmt_evt_funcc {
        __be16 status;
 } __packed;
 
+struct btmtk_hci_wmt_evt_reg {
+       struct btmtk_hci_wmt_evt hwhdr;
+       u8 rsv[2];
+       u8 num;
+       __le32 addr;
+       __le32 val;
+} __packed;
+
 struct btmtk_tci_sleep {
        u8 mode;
        __le16 duration;
index 3266c5d..ce6a6c0 100644 (file)
@@ -37,14 +37,22 @@ static bool enable_autosuspend;
 
 struct btmtksdio_data {
        const char *fwname;
+       u16 chipid;
 };
 
 static const struct btmtksdio_data mt7663_data = {
        .fwname = FIRMWARE_MT7663,
+       .chipid = 0x7663,
 };
 
 static const struct btmtksdio_data mt7668_data = {
        .fwname = FIRMWARE_MT7668,
+       .chipid = 0x7668,
+};
+
+static const struct btmtksdio_data mt7921_data = {
+       .fwname = FIRMWARE_MT7961,
+       .chipid = 0x7921,
 };
 
 static const struct sdio_device_id btmtksdio_table[] = {
@@ -52,6 +60,8 @@ static const struct sdio_device_id btmtksdio_table[] = {
         .driver_data = (kernel_ulong_t)&mt7663_data },
        {SDIO_DEVICE(SDIO_VENDOR_ID_MEDIATEK, SDIO_DEVICE_ID_MEDIATEK_MT7668),
         .driver_data = (kernel_ulong_t)&mt7668_data },
+       {SDIO_DEVICE(SDIO_VENDOR_ID_MEDIATEK, SDIO_DEVICE_ID_MEDIATEK_MT7961),
+        .driver_data = (kernel_ulong_t)&mt7921_data },
        { }     /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(sdio, btmtksdio_table);
@@ -115,6 +125,7 @@ static int mtk_hci_wmt_sync(struct hci_dev *hdev,
 {
        struct btmtksdio_dev *bdev = hci_get_drvdata(hdev);
        struct btmtk_hci_wmt_evt_funcc *wmt_evt_funcc;
+       struct btmtk_hci_wmt_evt_reg *wmt_evt_reg;
        u32 hlen, status = BTMTK_WMT_INVALID;
        struct btmtk_hci_wmt_evt *wmt_evt;
        struct btmtk_hci_wmt_cmd *wc;
@@ -194,6 +205,19 @@ static int mtk_hci_wmt_sync(struct hci_dev *hdev,
                else
                        status = BTMTK_WMT_ON_UNDONE;
                break;
+       case BTMTK_WMT_PATCH_DWNLD:
+               if (wmt_evt->whdr.flag == 2)
+                       status = BTMTK_WMT_PATCH_DONE;
+               else if (wmt_evt->whdr.flag == 1)
+                       status = BTMTK_WMT_PATCH_PROGRESS;
+               else
+                       status = BTMTK_WMT_PATCH_UNDONE;
+               break;
+       case BTMTK_WMT_REGISTER:
+               wmt_evt_reg = (struct btmtk_hci_wmt_evt_reg *)wmt_evt;
+               if (le16_to_cpu(wmt_evt->whdr.dlen) == 12)
+                       status = le32_to_cpu(wmt_evt_reg->val);
+               break;
        }
 
        if (wmt_params->status)
@@ -634,20 +658,14 @@ static int btmtksdio_func_query(struct hci_dev *hdev)
        return status;
 }
 
-static int btmtksdio_setup(struct hci_dev *hdev)
+static int mt76xx_setup(struct hci_dev *hdev, const char *fwname)
 {
-       struct btmtksdio_dev *bdev = hci_get_drvdata(hdev);
        struct btmtk_hci_wmt_params wmt_params;
-       ktime_t calltime, delta, rettime;
        struct btmtk_tci_sleep tci_sleep;
-       unsigned long long duration;
        struct sk_buff *skb;
        int err, status;
        u8 param = 0x1;
 
-       calltime = ktime_get();
-       bdev->hw_tx_ready = true;
-
        /* Query whether the firmware is already download */
        wmt_params.op = BTMTK_WMT_SEMAPHORE;
        wmt_params.flag = 1;
@@ -667,7 +685,7 @@ static int btmtksdio_setup(struct hci_dev *hdev)
        }
 
        /* Setup a firmware which the device definitely requires */
-       err = btmtk_setup_firmware(hdev, bdev->data->fwname, mtk_hci_wmt_sync);
+       err = btmtk_setup_firmware(hdev, fwname, mtk_hci_wmt_sync);
        if (err < 0)
                return err;
 
@@ -719,6 +737,113 @@ ignore_func_on:
        }
        kfree_skb(skb);
 
+       return 0;
+}
+
+static int mt79xx_setup(struct hci_dev *hdev, const char *fwname)
+{
+       struct btmtk_hci_wmt_params wmt_params;
+       u8 param = 0x1;
+       int err;
+
+       err = btmtk_setup_firmware_79xx(hdev, fwname, mtk_hci_wmt_sync);
+       if (err < 0) {
+               bt_dev_err(hdev, "Failed to setup 79xx firmware (%d)", err);
+               return err;
+       }
+
+       /* Enable Bluetooth protocol */
+       wmt_params.op = BTMTK_WMT_FUNC_CTRL;
+       wmt_params.flag = 0;
+       wmt_params.dlen = sizeof(param);
+       wmt_params.data = &param;
+       wmt_params.status = NULL;
+
+       err = mtk_hci_wmt_sync(hdev, &wmt_params);
+       if (err < 0) {
+               bt_dev_err(hdev, "Failed to send wmt func ctrl (%d)", err);
+               return err;
+       }
+
+       return err;
+}
+
+static int btsdio_mtk_reg_read(struct hci_dev *hdev, u32 reg, u32 *val)
+{
+       struct btmtk_hci_wmt_params wmt_params;
+       struct reg_read_cmd {
+               u8 type;
+               u8 rsv;
+               u8 num;
+               __le32 addr;
+       } __packed reg_read = {
+               .type = 1,
+               .num = 1,
+       };
+       u32 status;
+       int err;
+
+       reg_read.addr = cpu_to_le32(reg);
+       wmt_params.op = BTMTK_WMT_REGISTER;
+       wmt_params.flag = BTMTK_WMT_REG_READ;
+       wmt_params.dlen = sizeof(reg_read);
+       wmt_params.data = &reg_read;
+       wmt_params.status = &status;
+
+       err = mtk_hci_wmt_sync(hdev, &wmt_params);
+       if (err < 0) {
+               bt_dev_err(hdev, "Failed to read reg(%d)", err);
+               return err;
+       }
+
+       *val = status;
+
+       return err;
+}
+
+static int btmtksdio_setup(struct hci_dev *hdev)
+{
+       struct btmtksdio_dev *bdev = hci_get_drvdata(hdev);
+       ktime_t calltime, delta, rettime;
+       unsigned long long duration;
+       char fwname[64];
+       int err, dev_id;
+       u32 fw_version = 0;
+
+       calltime = ktime_get();
+       bdev->hw_tx_ready = true;
+
+       switch (bdev->data->chipid) {
+       case 0x7921:
+               err = btsdio_mtk_reg_read(hdev, 0x70010200, &dev_id);
+               if (err < 0) {
+                       bt_dev_err(hdev, "Failed to get device id (%d)", err);
+                       return err;
+               }
+
+               err = btsdio_mtk_reg_read(hdev, 0x80021004, &fw_version);
+               if (err < 0) {
+                       bt_dev_err(hdev, "Failed to get fw version (%d)", err);
+                       return err;
+               }
+
+               snprintf(fwname, sizeof(fwname),
+                        "mediatek/BT_RAM_CODE_MT%04x_1_%x_hdr.bin",
+                        dev_id & 0xffff, (fw_version & 0xff) + 1);
+               err = mt79xx_setup(hdev, fwname);
+               if (err < 0)
+                       return err;
+               break;
+       case 0x7663:
+       case 0x7668:
+               err = mt76xx_setup(hdev, bdev->data->fwname);
+               if (err < 0)
+                       return err;
+               break;
+       default:
+               return -ENODEV;
+       }
+
        rettime = ktime_get();
        delta = ktime_sub(rettime, calltime);
        duration = (unsigned long long)ktime_to_ns(delta) >> 10;