Commit c603bf1f authored by Sean Wang's avatar Sean Wang Committed by Marcel Holtmann
Browse files

Bluetooth: btmtksdio: add MT7921s Bluetooth support



add MT7921s Bluetooth support

Co-developed-by: default avatarMark-yw Chen <mark-yw.chen@mediatek.com>
Signed-off-by: default avatarMark-yw Chen <mark-yw.chen@mediatek.com>
Signed-off-by: default avatarSean Wang <sean.wang@mediatek.com>
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
parent 1705643f
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -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;
+133 −8
Original line number Diff line number Diff line
@@ -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 @@ static int btmtksdio_setup(struct hci_dev *hdev)
	}
	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;