Bluetooth: btmtksdio: add MT7921s Bluetooth support
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>
This commit is contained in:
parent
1705643fae
commit
c603bf1f94
2 changed files with 144 additions and 8 deletions
|
@ -7,6 +7,8 @@
|
||||||
|
|
||||||
#define HCI_WMT_MAX_EVENT_SIZE 64
|
#define HCI_WMT_MAX_EVENT_SIZE 64
|
||||||
|
|
||||||
|
#define BTMTK_WMT_REG_READ 0x2
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
BTMTK_WMT_PATCH_DWNLD = 0x1,
|
BTMTK_WMT_PATCH_DWNLD = 0x1,
|
||||||
BTMTK_WMT_TEST = 0x2,
|
BTMTK_WMT_TEST = 0x2,
|
||||||
|
@ -14,6 +16,7 @@ enum {
|
||||||
BTMTK_WMT_HIF = 0x4,
|
BTMTK_WMT_HIF = 0x4,
|
||||||
BTMTK_WMT_FUNC_CTRL = 0x6,
|
BTMTK_WMT_FUNC_CTRL = 0x6,
|
||||||
BTMTK_WMT_RST = 0x7,
|
BTMTK_WMT_RST = 0x7,
|
||||||
|
BTMTK_WMT_REGISTER = 0x8,
|
||||||
BTMTK_WMT_SEMAPHORE = 0x17,
|
BTMTK_WMT_SEMAPHORE = 0x17,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -49,6 +52,14 @@ struct btmtk_hci_wmt_evt_funcc {
|
||||||
__be16 status;
|
__be16 status;
|
||||||
} __packed;
|
} __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 {
|
struct btmtk_tci_sleep {
|
||||||
u8 mode;
|
u8 mode;
|
||||||
__le16 duration;
|
__le16 duration;
|
||||||
|
|
|
@ -37,14 +37,22 @@ static bool enable_autosuspend;
|
||||||
|
|
||||||
struct btmtksdio_data {
|
struct btmtksdio_data {
|
||||||
const char *fwname;
|
const char *fwname;
|
||||||
|
u16 chipid;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct btmtksdio_data mt7663_data = {
|
static const struct btmtksdio_data mt7663_data = {
|
||||||
.fwname = FIRMWARE_MT7663,
|
.fwname = FIRMWARE_MT7663,
|
||||||
|
.chipid = 0x7663,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct btmtksdio_data mt7668_data = {
|
static const struct btmtksdio_data mt7668_data = {
|
||||||
.fwname = FIRMWARE_MT7668,
|
.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[] = {
|
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 },
|
.driver_data = (kernel_ulong_t)&mt7663_data },
|
||||||
{SDIO_DEVICE(SDIO_VENDOR_ID_MEDIATEK, SDIO_DEVICE_ID_MEDIATEK_MT7668),
|
{SDIO_DEVICE(SDIO_VENDOR_ID_MEDIATEK, SDIO_DEVICE_ID_MEDIATEK_MT7668),
|
||||||
.driver_data = (kernel_ulong_t)&mt7668_data },
|
.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 */
|
{ } /* Terminating entry */
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(sdio, btmtksdio_table);
|
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 btmtksdio_dev *bdev = hci_get_drvdata(hdev);
|
||||||
struct btmtk_hci_wmt_evt_funcc *wmt_evt_funcc;
|
struct btmtk_hci_wmt_evt_funcc *wmt_evt_funcc;
|
||||||
|
struct btmtk_hci_wmt_evt_reg *wmt_evt_reg;
|
||||||
u32 hlen, status = BTMTK_WMT_INVALID;
|
u32 hlen, status = BTMTK_WMT_INVALID;
|
||||||
struct btmtk_hci_wmt_evt *wmt_evt;
|
struct btmtk_hci_wmt_evt *wmt_evt;
|
||||||
struct btmtk_hci_wmt_cmd *wc;
|
struct btmtk_hci_wmt_cmd *wc;
|
||||||
|
@ -194,6 +205,19 @@ static int mtk_hci_wmt_sync(struct hci_dev *hdev,
|
||||||
else
|
else
|
||||||
status = BTMTK_WMT_ON_UNDONE;
|
status = BTMTK_WMT_ON_UNDONE;
|
||||||
break;
|
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)
|
if (wmt_params->status)
|
||||||
|
@ -634,20 +658,14 @@ static int btmtksdio_func_query(struct hci_dev *hdev)
|
||||||
return status;
|
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;
|
struct btmtk_hci_wmt_params wmt_params;
|
||||||
ktime_t calltime, delta, rettime;
|
|
||||||
struct btmtk_tci_sleep tci_sleep;
|
struct btmtk_tci_sleep tci_sleep;
|
||||||
unsigned long long duration;
|
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
int err, status;
|
int err, status;
|
||||||
u8 param = 0x1;
|
u8 param = 0x1;
|
||||||
|
|
||||||
calltime = ktime_get();
|
|
||||||
bdev->hw_tx_ready = true;
|
|
||||||
|
|
||||||
/* Query whether the firmware is already download */
|
/* Query whether the firmware is already download */
|
||||||
wmt_params.op = BTMTK_WMT_SEMAPHORE;
|
wmt_params.op = BTMTK_WMT_SEMAPHORE;
|
||||||
wmt_params.flag = 1;
|
wmt_params.flag = 1;
|
||||||
|
@ -667,7 +685,7 @@ static int btmtksdio_setup(struct hci_dev *hdev)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Setup a firmware which the device definitely requires */
|
/* 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)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
@ -719,6 +737,113 @@ ignore_func_on:
|
||||||
}
|
}
|
||||||
kfree_skb(skb);
|
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 = ¶m;
|
||||||
|
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 = ®_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();
|
rettime = ktime_get();
|
||||||
delta = ktime_sub(rettime, calltime);
|
delta = ktime_sub(rettime, calltime);
|
||||||
duration = (unsigned long long)ktime_to_ns(delta) >> 10;
|
duration = (unsigned long long)ktime_to_ns(delta) >> 10;
|
||||||
|
|
Loading…
Add table
Reference in a new issue