162306a36Sopenharmony_ci// SPDX-License-Identifier: ISC
262306a36Sopenharmony_ci/* Copyright (C) 2019 MediaTek Inc.
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Author: Roy Luo <royluo@google.com>
562306a36Sopenharmony_ci *         Ryder Lee <ryder.lee@mediatek.com>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/firmware.h>
962306a36Sopenharmony_ci#include "mt7615.h"
1062306a36Sopenharmony_ci#include "mcu.h"
1162306a36Sopenharmony_ci#include "mac.h"
1262306a36Sopenharmony_ci#include "eeprom.h"
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_cistatic bool prefer_offload_fw = true;
1562306a36Sopenharmony_cimodule_param(prefer_offload_fw, bool, 0644);
1662306a36Sopenharmony_ciMODULE_PARM_DESC(prefer_offload_fw,
1762306a36Sopenharmony_ci		 "Prefer client mode offload firmware (MT7663)");
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_cistruct mt7615_patch_hdr {
2062306a36Sopenharmony_ci	char build_date[16];
2162306a36Sopenharmony_ci	char platform[4];
2262306a36Sopenharmony_ci	__be32 hw_sw_ver;
2362306a36Sopenharmony_ci	__be32 patch_ver;
2462306a36Sopenharmony_ci	__be16 checksum;
2562306a36Sopenharmony_ci} __packed;
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistruct mt7615_fw_trailer {
2862306a36Sopenharmony_ci	__le32 addr;
2962306a36Sopenharmony_ci	u8 chip_id;
3062306a36Sopenharmony_ci	u8 feature_set;
3162306a36Sopenharmony_ci	u8 eco_code;
3262306a36Sopenharmony_ci	char fw_ver[10];
3362306a36Sopenharmony_ci	char build_date[15];
3462306a36Sopenharmony_ci	__le32 len;
3562306a36Sopenharmony_ci} __packed;
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci#define FW_V3_COMMON_TAILER_SIZE	36
3862306a36Sopenharmony_ci#define FW_V3_REGION_TAILER_SIZE	40
3962306a36Sopenharmony_ci#define FW_START_OVERRIDE		BIT(0)
4062306a36Sopenharmony_ci#define FW_START_DLYCAL                 BIT(1)
4162306a36Sopenharmony_ci#define FW_START_WORKING_PDA_CR4	BIT(2)
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistruct mt7663_fw_buf {
4462306a36Sopenharmony_ci	__le32 crc;
4562306a36Sopenharmony_ci	__le32 d_img_size;
4662306a36Sopenharmony_ci	__le32 block_size;
4762306a36Sopenharmony_ci	u8 rsv[4];
4862306a36Sopenharmony_ci	__le32 img_dest_addr;
4962306a36Sopenharmony_ci	__le32 img_size;
5062306a36Sopenharmony_ci	u8 feature_set;
5162306a36Sopenharmony_ci};
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci#define MT7615_PATCH_ADDRESS		0x80000
5462306a36Sopenharmony_ci#define MT7622_PATCH_ADDRESS		0x9c000
5562306a36Sopenharmony_ci#define MT7663_PATCH_ADDRESS		0xdc000
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci#define N9_REGION_NUM			2
5862306a36Sopenharmony_ci#define CR4_REGION_NUM			1
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci#define IMG_CRC_LEN			4
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_civoid mt7615_mcu_fill_msg(struct mt7615_dev *dev, struct sk_buff *skb,
6362306a36Sopenharmony_ci			 int cmd, int *wait_seq)
6462306a36Sopenharmony_ci{
6562306a36Sopenharmony_ci	int txd_len, mcu_cmd = FIELD_GET(__MCU_CMD_FIELD_ID, cmd);
6662306a36Sopenharmony_ci	struct mt7615_uni_txd *uni_txd;
6762306a36Sopenharmony_ci	struct mt7615_mcu_txd *mcu_txd;
6862306a36Sopenharmony_ci	u8 seq, q_idx, pkt_fmt;
6962306a36Sopenharmony_ci	__le32 *txd;
7062306a36Sopenharmony_ci	u32 val;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	/* TODO: make dynamic based on msg type */
7362306a36Sopenharmony_ci	dev->mt76.mcu.timeout = 20 * HZ;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	seq = ++dev->mt76.mcu.msg_seq & 0xf;
7662306a36Sopenharmony_ci	if (!seq)
7762306a36Sopenharmony_ci		seq = ++dev->mt76.mcu.msg_seq & 0xf;
7862306a36Sopenharmony_ci	if (wait_seq)
7962306a36Sopenharmony_ci		*wait_seq = seq;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	txd_len = cmd & __MCU_CMD_FIELD_UNI ? sizeof(*uni_txd) : sizeof(*mcu_txd);
8262306a36Sopenharmony_ci	txd = (__le32 *)skb_push(skb, txd_len);
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	if (cmd != MCU_CMD(FW_SCATTER)) {
8562306a36Sopenharmony_ci		q_idx = MT_TX_MCU_PORT_RX_Q0;
8662306a36Sopenharmony_ci		pkt_fmt = MT_TX_TYPE_CMD;
8762306a36Sopenharmony_ci	} else {
8862306a36Sopenharmony_ci		q_idx = MT_TX_MCU_PORT_RX_FWDL;
8962306a36Sopenharmony_ci		pkt_fmt = MT_TX_TYPE_FW;
9062306a36Sopenharmony_ci	}
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len) |
9362306a36Sopenharmony_ci	      FIELD_PREP(MT_TXD0_P_IDX, MT_TX_PORT_IDX_MCU) |
9462306a36Sopenharmony_ci	      FIELD_PREP(MT_TXD0_Q_IDX, q_idx);
9562306a36Sopenharmony_ci	txd[0] = cpu_to_le32(val);
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	val = MT_TXD1_LONG_FORMAT |
9862306a36Sopenharmony_ci	      FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_CMD) |
9962306a36Sopenharmony_ci	      FIELD_PREP(MT_TXD1_PKT_FMT, pkt_fmt);
10062306a36Sopenharmony_ci	txd[1] = cpu_to_le32(val);
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	if (cmd & __MCU_CMD_FIELD_UNI) {
10362306a36Sopenharmony_ci		uni_txd = (struct mt7615_uni_txd *)txd;
10462306a36Sopenharmony_ci		uni_txd->len = cpu_to_le16(skb->len - sizeof(uni_txd->txd));
10562306a36Sopenharmony_ci		uni_txd->option = MCU_CMD_UNI_EXT_ACK;
10662306a36Sopenharmony_ci		uni_txd->cid = cpu_to_le16(mcu_cmd);
10762306a36Sopenharmony_ci		uni_txd->s2d_index = MCU_S2D_H2N;
10862306a36Sopenharmony_ci		uni_txd->pkt_type = MCU_PKT_ID;
10962306a36Sopenharmony_ci		uni_txd->seq = seq;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci		return;
11262306a36Sopenharmony_ci	}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	mcu_txd = (struct mt7615_mcu_txd *)txd;
11562306a36Sopenharmony_ci	mcu_txd->len = cpu_to_le16(skb->len - sizeof(mcu_txd->txd));
11662306a36Sopenharmony_ci	mcu_txd->pq_id = cpu_to_le16(MCU_PQ_ID(MT_TX_PORT_IDX_MCU, q_idx));
11762306a36Sopenharmony_ci	mcu_txd->s2d_index = MCU_S2D_H2N;
11862306a36Sopenharmony_ci	mcu_txd->pkt_type = MCU_PKT_ID;
11962306a36Sopenharmony_ci	mcu_txd->seq = seq;
12062306a36Sopenharmony_ci	mcu_txd->cid = mcu_cmd;
12162306a36Sopenharmony_ci	mcu_txd->ext_cid = FIELD_GET(__MCU_CMD_FIELD_EXT_ID, cmd);
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	if (mcu_txd->ext_cid || (cmd & __MCU_CMD_FIELD_CE)) {
12462306a36Sopenharmony_ci		if (cmd & __MCU_CMD_FIELD_QUERY)
12562306a36Sopenharmony_ci			mcu_txd->set_query = MCU_Q_QUERY;
12662306a36Sopenharmony_ci		else
12762306a36Sopenharmony_ci			mcu_txd->set_query = MCU_Q_SET;
12862306a36Sopenharmony_ci		mcu_txd->ext_cid_ack = !!mcu_txd->ext_cid;
12962306a36Sopenharmony_ci	} else {
13062306a36Sopenharmony_ci		mcu_txd->set_query = MCU_Q_NA;
13162306a36Sopenharmony_ci	}
13262306a36Sopenharmony_ci}
13362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mt7615_mcu_fill_msg);
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ciint mt7615_mcu_parse_response(struct mt76_dev *mdev, int cmd,
13662306a36Sopenharmony_ci			      struct sk_buff *skb, int seq)
13762306a36Sopenharmony_ci{
13862306a36Sopenharmony_ci	struct mt7615_mcu_rxd *rxd;
13962306a36Sopenharmony_ci	int ret = 0;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	if (!skb) {
14262306a36Sopenharmony_ci		dev_err(mdev->dev, "Message %08x (seq %d) timeout\n",
14362306a36Sopenharmony_ci			cmd, seq);
14462306a36Sopenharmony_ci		return -ETIMEDOUT;
14562306a36Sopenharmony_ci	}
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	rxd = (struct mt7615_mcu_rxd *)skb->data;
14862306a36Sopenharmony_ci	if (seq != rxd->seq)
14962306a36Sopenharmony_ci		return -EAGAIN;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	if (cmd == MCU_CMD(PATCH_SEM_CONTROL)) {
15262306a36Sopenharmony_ci		skb_pull(skb, sizeof(*rxd) - 4);
15362306a36Sopenharmony_ci		ret = *skb->data;
15462306a36Sopenharmony_ci	} else if (cmd == MCU_EXT_CMD(THERMAL_CTRL)) {
15562306a36Sopenharmony_ci		skb_pull(skb, sizeof(*rxd));
15662306a36Sopenharmony_ci		ret = le32_to_cpu(*(__le32 *)skb->data);
15762306a36Sopenharmony_ci	} else if (cmd == MCU_EXT_QUERY(RF_REG_ACCESS)) {
15862306a36Sopenharmony_ci		skb_pull(skb, sizeof(*rxd));
15962306a36Sopenharmony_ci		ret = le32_to_cpu(*(__le32 *)&skb->data[8]);
16062306a36Sopenharmony_ci	} else if (cmd == MCU_UNI_CMD(DEV_INFO_UPDATE) ||
16162306a36Sopenharmony_ci		   cmd == MCU_UNI_CMD(BSS_INFO_UPDATE) ||
16262306a36Sopenharmony_ci		   cmd == MCU_UNI_CMD(STA_REC_UPDATE) ||
16362306a36Sopenharmony_ci		   cmd == MCU_UNI_CMD(HIF_CTRL) ||
16462306a36Sopenharmony_ci		   cmd == MCU_UNI_CMD(OFFLOAD) ||
16562306a36Sopenharmony_ci		   cmd == MCU_UNI_CMD(SUSPEND)) {
16662306a36Sopenharmony_ci		struct mt76_connac_mcu_uni_event *event;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci		skb_pull(skb, sizeof(*rxd));
16962306a36Sopenharmony_ci		event = (struct mt76_connac_mcu_uni_event *)skb->data;
17062306a36Sopenharmony_ci		ret = le32_to_cpu(event->status);
17162306a36Sopenharmony_ci	} else if (cmd == MCU_CE_QUERY(REG_READ)) {
17262306a36Sopenharmony_ci		struct mt76_connac_mcu_reg_event *event;
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci		skb_pull(skb, sizeof(*rxd));
17562306a36Sopenharmony_ci		event = (struct mt76_connac_mcu_reg_event *)skb->data;
17662306a36Sopenharmony_ci		ret = (int)le32_to_cpu(event->val);
17762306a36Sopenharmony_ci	}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	return ret;
18062306a36Sopenharmony_ci}
18162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mt7615_mcu_parse_response);
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_cistatic int
18462306a36Sopenharmony_cimt7615_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
18562306a36Sopenharmony_ci			int cmd, int *seq)
18662306a36Sopenharmony_ci{
18762306a36Sopenharmony_ci	struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);
18862306a36Sopenharmony_ci	enum mt76_mcuq_id qid;
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	mt7615_mcu_fill_msg(dev, skb, cmd, seq);
19162306a36Sopenharmony_ci	if (test_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state))
19262306a36Sopenharmony_ci		qid = MT_MCUQ_WM;
19362306a36Sopenharmony_ci	else
19462306a36Sopenharmony_ci		qid = MT_MCUQ_FWDL;
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	return mt76_tx_queue_skb_raw(dev, dev->mt76.q_mcu[qid], skb, 0);
19762306a36Sopenharmony_ci}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ciu32 mt7615_rf_rr(struct mt7615_dev *dev, u32 wf, u32 reg)
20062306a36Sopenharmony_ci{
20162306a36Sopenharmony_ci	struct {
20262306a36Sopenharmony_ci		__le32 wifi_stream;
20362306a36Sopenharmony_ci		__le32 address;
20462306a36Sopenharmony_ci		__le32 data;
20562306a36Sopenharmony_ci	} req = {
20662306a36Sopenharmony_ci		.wifi_stream = cpu_to_le32(wf),
20762306a36Sopenharmony_ci		.address = cpu_to_le32(reg),
20862306a36Sopenharmony_ci	};
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_QUERY(RF_REG_ACCESS),
21162306a36Sopenharmony_ci				 &req, sizeof(req), true);
21262306a36Sopenharmony_ci}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ciint mt7615_rf_wr(struct mt7615_dev *dev, u32 wf, u32 reg, u32 val)
21562306a36Sopenharmony_ci{
21662306a36Sopenharmony_ci	struct {
21762306a36Sopenharmony_ci		__le32 wifi_stream;
21862306a36Sopenharmony_ci		__le32 address;
21962306a36Sopenharmony_ci		__le32 data;
22062306a36Sopenharmony_ci	} req = {
22162306a36Sopenharmony_ci		.wifi_stream = cpu_to_le32(wf),
22262306a36Sopenharmony_ci		.address = cpu_to_le32(reg),
22362306a36Sopenharmony_ci		.data = cpu_to_le32(val),
22462306a36Sopenharmony_ci	};
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RF_REG_ACCESS),
22762306a36Sopenharmony_ci				 &req, sizeof(req), false);
22862306a36Sopenharmony_ci}
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_civoid mt7622_trigger_hif_int(struct mt7615_dev *dev, bool en)
23162306a36Sopenharmony_ci{
23262306a36Sopenharmony_ci	if (!is_mt7622(&dev->mt76))
23362306a36Sopenharmony_ci		return;
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	regmap_update_bits(dev->infracfg, MT_INFRACFG_MISC,
23662306a36Sopenharmony_ci			   MT_INFRACFG_MISC_AP2CONN_WAKE,
23762306a36Sopenharmony_ci			   !en * MT_INFRACFG_MISC_AP2CONN_WAKE);
23862306a36Sopenharmony_ci}
23962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mt7622_trigger_hif_int);
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_cistatic int mt7615_mcu_drv_pmctrl(struct mt7615_dev *dev)
24262306a36Sopenharmony_ci{
24362306a36Sopenharmony_ci	struct mt76_phy *mphy = &dev->mt76.phy;
24462306a36Sopenharmony_ci	struct mt76_connac_pm *pm = &dev->pm;
24562306a36Sopenharmony_ci	struct mt76_dev *mdev = &dev->mt76;
24662306a36Sopenharmony_ci	u32 addr;
24762306a36Sopenharmony_ci	int err;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	if (is_mt7663(mdev)) {
25062306a36Sopenharmony_ci		/* Clear firmware own via N9 eint */
25162306a36Sopenharmony_ci		mt76_wr(dev, MT_PCIE_DOORBELL_PUSH, MT_CFG_LPCR_HOST_DRV_OWN);
25262306a36Sopenharmony_ci		mt76_poll(dev, MT_CONN_ON_MISC, MT_CFG_LPCR_HOST_FW_OWN, 0, 3000);
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci		addr = MT_CONN_HIF_ON_LPCTL;
25562306a36Sopenharmony_ci	} else {
25662306a36Sopenharmony_ci		addr = MT_CFG_LPCR_HOST;
25762306a36Sopenharmony_ci	}
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	mt76_wr(dev, addr, MT_CFG_LPCR_HOST_DRV_OWN);
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	mt7622_trigger_hif_int(dev, true);
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	err = !mt76_poll_msec(dev, addr, MT_CFG_LPCR_HOST_FW_OWN, 0, 3000);
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	mt7622_trigger_hif_int(dev, false);
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	if (err) {
26862306a36Sopenharmony_ci		dev_err(mdev->dev, "driver own failed\n");
26962306a36Sopenharmony_ci		return -ETIMEDOUT;
27062306a36Sopenharmony_ci	}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	clear_bit(MT76_STATE_PM, &mphy->state);
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	pm->stats.last_wake_event = jiffies;
27562306a36Sopenharmony_ci	pm->stats.doze_time += pm->stats.last_wake_event -
27662306a36Sopenharmony_ci			       pm->stats.last_doze_event;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	return 0;
27962306a36Sopenharmony_ci}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_cistatic int mt7615_mcu_lp_drv_pmctrl(struct mt7615_dev *dev)
28262306a36Sopenharmony_ci{
28362306a36Sopenharmony_ci	struct mt76_phy *mphy = &dev->mt76.phy;
28462306a36Sopenharmony_ci	struct mt76_connac_pm *pm = &dev->pm;
28562306a36Sopenharmony_ci	int i, err = 0;
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	mutex_lock(&pm->mutex);
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	if (!test_bit(MT76_STATE_PM, &mphy->state))
29062306a36Sopenharmony_ci		goto out;
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	for (i = 0; i < MT7615_DRV_OWN_RETRY_COUNT; i++) {
29362306a36Sopenharmony_ci		mt76_wr(dev, MT_PCIE_DOORBELL_PUSH, MT_CFG_LPCR_HOST_DRV_OWN);
29462306a36Sopenharmony_ci		if (mt76_poll_msec(dev, MT_CONN_HIF_ON_LPCTL,
29562306a36Sopenharmony_ci				   MT_CFG_LPCR_HOST_FW_OWN, 0, 50))
29662306a36Sopenharmony_ci			break;
29762306a36Sopenharmony_ci	}
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	if (i == MT7615_DRV_OWN_RETRY_COUNT) {
30062306a36Sopenharmony_ci		dev_err(dev->mt76.dev, "driver own failed\n");
30162306a36Sopenharmony_ci		err = -EIO;
30262306a36Sopenharmony_ci		goto out;
30362306a36Sopenharmony_ci	}
30462306a36Sopenharmony_ci	clear_bit(MT76_STATE_PM, &mphy->state);
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	pm->stats.last_wake_event = jiffies;
30762306a36Sopenharmony_ci	pm->stats.doze_time += pm->stats.last_wake_event -
30862306a36Sopenharmony_ci			       pm->stats.last_doze_event;
30962306a36Sopenharmony_ciout:
31062306a36Sopenharmony_ci	mutex_unlock(&pm->mutex);
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	return err;
31362306a36Sopenharmony_ci}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_cistatic int mt7615_mcu_fw_pmctrl(struct mt7615_dev *dev)
31662306a36Sopenharmony_ci{
31762306a36Sopenharmony_ci	struct mt76_phy *mphy = &dev->mt76.phy;
31862306a36Sopenharmony_ci	struct mt76_connac_pm *pm = &dev->pm;
31962306a36Sopenharmony_ci	int err = 0;
32062306a36Sopenharmony_ci	u32 addr;
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	mutex_lock(&pm->mutex);
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	if (mt76_connac_skip_fw_pmctrl(mphy, pm))
32562306a36Sopenharmony_ci		goto out;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	mt7622_trigger_hif_int(dev, true);
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	addr = is_mt7663(&dev->mt76) ? MT_CONN_HIF_ON_LPCTL : MT_CFG_LPCR_HOST;
33062306a36Sopenharmony_ci	mt76_wr(dev, addr, MT_CFG_LPCR_HOST_FW_OWN);
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	if (is_mt7622(&dev->mt76) &&
33362306a36Sopenharmony_ci	    !mt76_poll_msec(dev, addr, MT_CFG_LPCR_HOST_FW_OWN,
33462306a36Sopenharmony_ci			    MT_CFG_LPCR_HOST_FW_OWN, 3000)) {
33562306a36Sopenharmony_ci		dev_err(dev->mt76.dev, "Timeout for firmware own\n");
33662306a36Sopenharmony_ci		clear_bit(MT76_STATE_PM, &mphy->state);
33762306a36Sopenharmony_ci		err = -EIO;
33862306a36Sopenharmony_ci	}
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	mt7622_trigger_hif_int(dev, false);
34162306a36Sopenharmony_ci	if (!err) {
34262306a36Sopenharmony_ci		pm->stats.last_doze_event = jiffies;
34362306a36Sopenharmony_ci		pm->stats.awake_time += pm->stats.last_doze_event -
34462306a36Sopenharmony_ci					pm->stats.last_wake_event;
34562306a36Sopenharmony_ci	}
34662306a36Sopenharmony_ciout:
34762306a36Sopenharmony_ci	mutex_unlock(&pm->mutex);
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	return err;
35062306a36Sopenharmony_ci}
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_cistatic void
35362306a36Sopenharmony_cimt7615_mcu_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
35462306a36Sopenharmony_ci{
35562306a36Sopenharmony_ci	if (vif->bss_conf.csa_active)
35662306a36Sopenharmony_ci		ieee80211_csa_finish(vif);
35762306a36Sopenharmony_ci}
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_cistatic void
36062306a36Sopenharmony_cimt7615_mcu_rx_csa_notify(struct mt7615_dev *dev, struct sk_buff *skb)
36162306a36Sopenharmony_ci{
36262306a36Sopenharmony_ci	struct mt7615_phy *ext_phy = mt7615_ext_phy(dev);
36362306a36Sopenharmony_ci	struct mt76_phy *mphy = &dev->mt76.phy;
36462306a36Sopenharmony_ci	struct mt7615_mcu_csa_notify *c;
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	c = (struct mt7615_mcu_csa_notify *)skb->data;
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	if (c->omac_idx > EXT_BSSID_MAX)
36962306a36Sopenharmony_ci		return;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	if (ext_phy && ext_phy->omac_mask & BIT_ULL(c->omac_idx))
37262306a36Sopenharmony_ci		mphy = dev->mt76.phys[MT_BAND1];
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	ieee80211_iterate_active_interfaces_atomic(mphy->hw,
37562306a36Sopenharmony_ci			IEEE80211_IFACE_ITER_RESUME_ALL,
37662306a36Sopenharmony_ci			mt7615_mcu_csa_finish, mphy->hw);
37762306a36Sopenharmony_ci}
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_cistatic void
38062306a36Sopenharmony_cimt7615_mcu_rx_radar_detected(struct mt7615_dev *dev, struct sk_buff *skb)
38162306a36Sopenharmony_ci{
38262306a36Sopenharmony_ci	struct mt76_phy *mphy = &dev->mt76.phy;
38362306a36Sopenharmony_ci	struct mt7615_mcu_rdd_report *r;
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	r = (struct mt7615_mcu_rdd_report *)skb->data;
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	if (!dev->radar_pattern.n_pulses && !r->long_detected &&
38862306a36Sopenharmony_ci	    !r->constant_prf_detected && !r->staggered_prf_detected)
38962306a36Sopenharmony_ci		return;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	if (r->band_idx && dev->mt76.phys[MT_BAND1])
39262306a36Sopenharmony_ci		mphy = dev->mt76.phys[MT_BAND1];
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	if (mt76_phy_dfs_state(mphy) < MT_DFS_STATE_CAC)
39562306a36Sopenharmony_ci		return;
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	ieee80211_radar_detected(mphy->hw);
39862306a36Sopenharmony_ci	dev->hw_pattern++;
39962306a36Sopenharmony_ci}
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_cistatic void
40262306a36Sopenharmony_cimt7615_mcu_rx_log_message(struct mt7615_dev *dev, struct sk_buff *skb)
40362306a36Sopenharmony_ci{
40462306a36Sopenharmony_ci	struct mt7615_mcu_rxd *rxd = (struct mt7615_mcu_rxd *)skb->data;
40562306a36Sopenharmony_ci	const char *data = (char *)&rxd[1];
40662306a36Sopenharmony_ci	const char *type;
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	switch (rxd->s2d_index) {
40962306a36Sopenharmony_ci	case 0:
41062306a36Sopenharmony_ci		type = "N9";
41162306a36Sopenharmony_ci		break;
41262306a36Sopenharmony_ci	case 2:
41362306a36Sopenharmony_ci		type = "CR4";
41462306a36Sopenharmony_ci		break;
41562306a36Sopenharmony_ci	default:
41662306a36Sopenharmony_ci		type = "unknown";
41762306a36Sopenharmony_ci		break;
41862306a36Sopenharmony_ci	}
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	wiphy_info(mt76_hw(dev)->wiphy, "%s: %.*s", type,
42162306a36Sopenharmony_ci		   (int)(skb->len - sizeof(*rxd)), data);
42262306a36Sopenharmony_ci}
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_cistatic void
42562306a36Sopenharmony_cimt7615_mcu_rx_ext_event(struct mt7615_dev *dev, struct sk_buff *skb)
42662306a36Sopenharmony_ci{
42762306a36Sopenharmony_ci	struct mt7615_mcu_rxd *rxd = (struct mt7615_mcu_rxd *)skb->data;
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	switch (rxd->ext_eid) {
43062306a36Sopenharmony_ci	case MCU_EXT_EVENT_RDD_REPORT:
43162306a36Sopenharmony_ci		mt7615_mcu_rx_radar_detected(dev, skb);
43262306a36Sopenharmony_ci		break;
43362306a36Sopenharmony_ci	case MCU_EXT_EVENT_CSA_NOTIFY:
43462306a36Sopenharmony_ci		mt7615_mcu_rx_csa_notify(dev, skb);
43562306a36Sopenharmony_ci		break;
43662306a36Sopenharmony_ci	case MCU_EXT_EVENT_FW_LOG_2_HOST:
43762306a36Sopenharmony_ci		mt7615_mcu_rx_log_message(dev, skb);
43862306a36Sopenharmony_ci		break;
43962306a36Sopenharmony_ci	default:
44062306a36Sopenharmony_ci		break;
44162306a36Sopenharmony_ci	}
44262306a36Sopenharmony_ci}
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_cistatic void
44562306a36Sopenharmony_cimt7615_mcu_scan_event(struct mt7615_dev *dev, struct sk_buff *skb)
44662306a36Sopenharmony_ci{
44762306a36Sopenharmony_ci	u8 *seq_num = skb->data + sizeof(struct mt7615_mcu_rxd);
44862306a36Sopenharmony_ci	struct mt7615_phy *phy;
44962306a36Sopenharmony_ci	struct mt76_phy *mphy;
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	if (*seq_num & BIT(7) && dev->mt76.phys[MT_BAND1])
45262306a36Sopenharmony_ci		mphy = dev->mt76.phys[MT_BAND1];
45362306a36Sopenharmony_ci	else
45462306a36Sopenharmony_ci		mphy = &dev->mt76.phy;
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	phy = (struct mt7615_phy *)mphy->priv;
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	spin_lock_bh(&dev->mt76.lock);
45962306a36Sopenharmony_ci	__skb_queue_tail(&phy->scan_event_list, skb);
46062306a36Sopenharmony_ci	spin_unlock_bh(&dev->mt76.lock);
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	ieee80211_queue_delayed_work(mphy->hw, &phy->scan_work,
46362306a36Sopenharmony_ci				     MT7615_HW_SCAN_TIMEOUT);
46462306a36Sopenharmony_ci}
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_cistatic void
46762306a36Sopenharmony_cimt7615_mcu_roc_event(struct mt7615_dev *dev, struct sk_buff *skb)
46862306a36Sopenharmony_ci{
46962306a36Sopenharmony_ci	struct mt7615_roc_tlv *event;
47062306a36Sopenharmony_ci	struct mt7615_phy *phy;
47162306a36Sopenharmony_ci	struct mt76_phy *mphy;
47262306a36Sopenharmony_ci	int duration;
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	skb_pull(skb, sizeof(struct mt7615_mcu_rxd));
47562306a36Sopenharmony_ci	event = (struct mt7615_roc_tlv *)skb->data;
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	if (event->dbdc_band && dev->mt76.phys[MT_BAND1])
47862306a36Sopenharmony_ci		mphy = dev->mt76.phys[MT_BAND1];
47962306a36Sopenharmony_ci	else
48062306a36Sopenharmony_ci		mphy = &dev->mt76.phy;
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	ieee80211_ready_on_channel(mphy->hw);
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	phy = (struct mt7615_phy *)mphy->priv;
48562306a36Sopenharmony_ci	phy->roc_grant = true;
48662306a36Sopenharmony_ci	wake_up(&phy->roc_wait);
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	duration = le32_to_cpu(event->max_interval);
48962306a36Sopenharmony_ci	mod_timer(&phy->roc_timer,
49062306a36Sopenharmony_ci		  round_jiffies_up(jiffies + msecs_to_jiffies(duration)));
49162306a36Sopenharmony_ci}
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_cistatic void
49462306a36Sopenharmony_cimt7615_mcu_beacon_loss_event(struct mt7615_dev *dev, struct sk_buff *skb)
49562306a36Sopenharmony_ci{
49662306a36Sopenharmony_ci	struct mt76_connac_beacon_loss_event *event;
49762306a36Sopenharmony_ci	struct mt76_phy *mphy;
49862306a36Sopenharmony_ci	u8 band_idx = 0; /* DBDC support */
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	skb_pull(skb, sizeof(struct mt7615_mcu_rxd));
50162306a36Sopenharmony_ci	event = (struct mt76_connac_beacon_loss_event *)skb->data;
50262306a36Sopenharmony_ci	if (band_idx && dev->mt76.phys[MT_BAND1])
50362306a36Sopenharmony_ci		mphy = dev->mt76.phys[MT_BAND1];
50462306a36Sopenharmony_ci	else
50562306a36Sopenharmony_ci		mphy = &dev->mt76.phy;
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	ieee80211_iterate_active_interfaces_atomic(mphy->hw,
50862306a36Sopenharmony_ci					IEEE80211_IFACE_ITER_RESUME_ALL,
50962306a36Sopenharmony_ci					mt76_connac_mcu_beacon_loss_iter,
51062306a36Sopenharmony_ci					event);
51162306a36Sopenharmony_ci}
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_cistatic void
51462306a36Sopenharmony_cimt7615_mcu_bss_event(struct mt7615_dev *dev, struct sk_buff *skb)
51562306a36Sopenharmony_ci{
51662306a36Sopenharmony_ci	struct mt76_connac_mcu_bss_event *event;
51762306a36Sopenharmony_ci	struct mt76_phy *mphy;
51862306a36Sopenharmony_ci	u8 band_idx = 0; /* DBDC support */
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	skb_pull(skb, sizeof(struct mt7615_mcu_rxd));
52162306a36Sopenharmony_ci	event = (struct mt76_connac_mcu_bss_event *)skb->data;
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	if (band_idx && dev->mt76.phys[MT_BAND1])
52462306a36Sopenharmony_ci		mphy = dev->mt76.phys[MT_BAND1];
52562306a36Sopenharmony_ci	else
52662306a36Sopenharmony_ci		mphy = &dev->mt76.phy;
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	if (event->is_absent)
52962306a36Sopenharmony_ci		ieee80211_stop_queues(mphy->hw);
53062306a36Sopenharmony_ci	else
53162306a36Sopenharmony_ci		ieee80211_wake_queues(mphy->hw);
53262306a36Sopenharmony_ci}
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_cistatic void
53562306a36Sopenharmony_cimt7615_mcu_rx_unsolicited_event(struct mt7615_dev *dev, struct sk_buff *skb)
53662306a36Sopenharmony_ci{
53762306a36Sopenharmony_ci	struct mt7615_mcu_rxd *rxd = (struct mt7615_mcu_rxd *)skb->data;
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	switch (rxd->eid) {
54062306a36Sopenharmony_ci	case MCU_EVENT_EXT:
54162306a36Sopenharmony_ci		mt7615_mcu_rx_ext_event(dev, skb);
54262306a36Sopenharmony_ci		break;
54362306a36Sopenharmony_ci	case MCU_EVENT_BSS_BEACON_LOSS:
54462306a36Sopenharmony_ci		mt7615_mcu_beacon_loss_event(dev, skb);
54562306a36Sopenharmony_ci		break;
54662306a36Sopenharmony_ci	case MCU_EVENT_ROC:
54762306a36Sopenharmony_ci		mt7615_mcu_roc_event(dev, skb);
54862306a36Sopenharmony_ci		break;
54962306a36Sopenharmony_ci	case MCU_EVENT_SCHED_SCAN_DONE:
55062306a36Sopenharmony_ci	case MCU_EVENT_SCAN_DONE:
55162306a36Sopenharmony_ci		mt7615_mcu_scan_event(dev, skb);
55262306a36Sopenharmony_ci		return;
55362306a36Sopenharmony_ci	case MCU_EVENT_BSS_ABSENCE:
55462306a36Sopenharmony_ci		mt7615_mcu_bss_event(dev, skb);
55562306a36Sopenharmony_ci		break;
55662306a36Sopenharmony_ci	case MCU_EVENT_COREDUMP:
55762306a36Sopenharmony_ci		mt76_connac_mcu_coredump_event(&dev->mt76, skb,
55862306a36Sopenharmony_ci					       &dev->coredump);
55962306a36Sopenharmony_ci		return;
56062306a36Sopenharmony_ci	default:
56162306a36Sopenharmony_ci		break;
56262306a36Sopenharmony_ci	}
56362306a36Sopenharmony_ci	dev_kfree_skb(skb);
56462306a36Sopenharmony_ci}
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_civoid mt7615_mcu_rx_event(struct mt7615_dev *dev, struct sk_buff *skb)
56762306a36Sopenharmony_ci{
56862306a36Sopenharmony_ci	struct mt7615_mcu_rxd *rxd = (struct mt7615_mcu_rxd *)skb->data;
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	if (rxd->ext_eid == MCU_EXT_EVENT_THERMAL_PROTECT ||
57162306a36Sopenharmony_ci	    rxd->ext_eid == MCU_EXT_EVENT_FW_LOG_2_HOST ||
57262306a36Sopenharmony_ci	    rxd->ext_eid == MCU_EXT_EVENT_ASSERT_DUMP ||
57362306a36Sopenharmony_ci	    rxd->ext_eid == MCU_EXT_EVENT_PS_SYNC ||
57462306a36Sopenharmony_ci	    rxd->eid == MCU_EVENT_BSS_BEACON_LOSS ||
57562306a36Sopenharmony_ci	    rxd->eid == MCU_EVENT_SCHED_SCAN_DONE ||
57662306a36Sopenharmony_ci	    rxd->eid == MCU_EVENT_BSS_ABSENCE ||
57762306a36Sopenharmony_ci	    rxd->eid == MCU_EVENT_SCAN_DONE ||
57862306a36Sopenharmony_ci	    rxd->eid == MCU_EVENT_COREDUMP ||
57962306a36Sopenharmony_ci	    rxd->eid == MCU_EVENT_ROC ||
58062306a36Sopenharmony_ci	    !rxd->seq)
58162306a36Sopenharmony_ci		mt7615_mcu_rx_unsolicited_event(dev, skb);
58262306a36Sopenharmony_ci	else
58362306a36Sopenharmony_ci		mt76_mcu_rx_event(&dev->mt76, skb);
58462306a36Sopenharmony_ci}
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_cistatic int
58762306a36Sopenharmony_cimt7615_mcu_muar_config(struct mt7615_dev *dev, struct ieee80211_vif *vif,
58862306a36Sopenharmony_ci		       bool bssid, bool enable)
58962306a36Sopenharmony_ci{
59062306a36Sopenharmony_ci	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
59162306a36Sopenharmony_ci	u32 idx = mvif->mt76.omac_idx - REPEATER_BSSID_START;
59262306a36Sopenharmony_ci	u32 mask = dev->omac_mask >> 32 & ~BIT(idx);
59362306a36Sopenharmony_ci	const u8 *addr = vif->addr;
59462306a36Sopenharmony_ci	struct {
59562306a36Sopenharmony_ci		u8 mode;
59662306a36Sopenharmony_ci		u8 force_clear;
59762306a36Sopenharmony_ci		u8 clear_bitmap[8];
59862306a36Sopenharmony_ci		u8 entry_count;
59962306a36Sopenharmony_ci		u8 write;
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci		u8 index;
60262306a36Sopenharmony_ci		u8 bssid;
60362306a36Sopenharmony_ci		u8 addr[ETH_ALEN];
60462306a36Sopenharmony_ci	} __packed req = {
60562306a36Sopenharmony_ci		.mode = !!mask || enable,
60662306a36Sopenharmony_ci		.entry_count = 1,
60762306a36Sopenharmony_ci		.write = 1,
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci		.index = idx * 2 + bssid,
61062306a36Sopenharmony_ci	};
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	if (bssid)
61362306a36Sopenharmony_ci		addr = vif->bss_conf.bssid;
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	if (enable)
61662306a36Sopenharmony_ci		ether_addr_copy(req.addr, addr);
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(MUAR_UPDATE),
61962306a36Sopenharmony_ci				 &req, sizeof(req), true);
62062306a36Sopenharmony_ci}
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_cistatic int
62362306a36Sopenharmony_cimt7615_mcu_add_dev(struct mt7615_phy *phy, struct ieee80211_vif *vif,
62462306a36Sopenharmony_ci		   bool enable)
62562306a36Sopenharmony_ci{
62662306a36Sopenharmony_ci	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
62762306a36Sopenharmony_ci	struct mt7615_dev *dev = phy->dev;
62862306a36Sopenharmony_ci	struct {
62962306a36Sopenharmony_ci		struct req_hdr {
63062306a36Sopenharmony_ci			u8 omac_idx;
63162306a36Sopenharmony_ci			u8 band_idx;
63262306a36Sopenharmony_ci			__le16 tlv_num;
63362306a36Sopenharmony_ci			u8 is_tlv_append;
63462306a36Sopenharmony_ci			u8 rsv[3];
63562306a36Sopenharmony_ci		} __packed hdr;
63662306a36Sopenharmony_ci		struct req_tlv {
63762306a36Sopenharmony_ci			__le16 tag;
63862306a36Sopenharmony_ci			__le16 len;
63962306a36Sopenharmony_ci			u8 active;
64062306a36Sopenharmony_ci			u8 band_idx;
64162306a36Sopenharmony_ci			u8 omac_addr[ETH_ALEN];
64262306a36Sopenharmony_ci		} __packed tlv;
64362306a36Sopenharmony_ci	} data = {
64462306a36Sopenharmony_ci		.hdr = {
64562306a36Sopenharmony_ci			.omac_idx = mvif->mt76.omac_idx,
64662306a36Sopenharmony_ci			.band_idx = mvif->mt76.band_idx,
64762306a36Sopenharmony_ci			.tlv_num = cpu_to_le16(1),
64862306a36Sopenharmony_ci			.is_tlv_append = 1,
64962306a36Sopenharmony_ci		},
65062306a36Sopenharmony_ci		.tlv = {
65162306a36Sopenharmony_ci			.tag = cpu_to_le16(DEV_INFO_ACTIVE),
65262306a36Sopenharmony_ci			.len = cpu_to_le16(sizeof(struct req_tlv)),
65362306a36Sopenharmony_ci			.active = enable,
65462306a36Sopenharmony_ci			.band_idx = mvif->mt76.band_idx,
65562306a36Sopenharmony_ci		},
65662306a36Sopenharmony_ci	};
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	if (mvif->mt76.omac_idx >= REPEATER_BSSID_START)
65962306a36Sopenharmony_ci		return mt7615_mcu_muar_config(dev, vif, false, enable);
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	memcpy(data.tlv.omac_addr, vif->addr, ETH_ALEN);
66262306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(DEV_INFO_UPDATE),
66362306a36Sopenharmony_ci				 &data, sizeof(data), true);
66462306a36Sopenharmony_ci}
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_cistatic int
66762306a36Sopenharmony_cimt7615_mcu_add_beacon_offload(struct mt7615_dev *dev,
66862306a36Sopenharmony_ci			      struct ieee80211_hw *hw,
66962306a36Sopenharmony_ci			      struct ieee80211_vif *vif, bool enable)
67062306a36Sopenharmony_ci{
67162306a36Sopenharmony_ci	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
67262306a36Sopenharmony_ci	struct mt76_wcid *wcid = &dev->mt76.global_wcid;
67362306a36Sopenharmony_ci	struct ieee80211_mutable_offsets offs;
67462306a36Sopenharmony_ci	struct ieee80211_tx_info *info;
67562306a36Sopenharmony_ci	struct req {
67662306a36Sopenharmony_ci		u8 omac_idx;
67762306a36Sopenharmony_ci		u8 enable;
67862306a36Sopenharmony_ci		u8 wlan_idx;
67962306a36Sopenharmony_ci		u8 band_idx;
68062306a36Sopenharmony_ci		u8 pkt_type;
68162306a36Sopenharmony_ci		u8 need_pre_tbtt_int;
68262306a36Sopenharmony_ci		__le16 csa_ie_pos;
68362306a36Sopenharmony_ci		__le16 pkt_len;
68462306a36Sopenharmony_ci		__le16 tim_ie_pos;
68562306a36Sopenharmony_ci		u8 pkt[512];
68662306a36Sopenharmony_ci		u8 csa_cnt;
68762306a36Sopenharmony_ci		/* bss color change */
68862306a36Sopenharmony_ci		u8 bcc_cnt;
68962306a36Sopenharmony_ci		__le16 bcc_ie_pos;
69062306a36Sopenharmony_ci	} __packed req = {
69162306a36Sopenharmony_ci		.omac_idx = mvif->mt76.omac_idx,
69262306a36Sopenharmony_ci		.enable = enable,
69362306a36Sopenharmony_ci		.wlan_idx = wcid->idx,
69462306a36Sopenharmony_ci		.band_idx = mvif->mt76.band_idx,
69562306a36Sopenharmony_ci	};
69662306a36Sopenharmony_ci	struct sk_buff *skb;
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	if (!enable)
69962306a36Sopenharmony_ci		goto out;
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci	skb = ieee80211_beacon_get_template(hw, vif, &offs, 0);
70262306a36Sopenharmony_ci	if (!skb)
70362306a36Sopenharmony_ci		return -EINVAL;
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	if (skb->len > 512 - MT_TXD_SIZE) {
70662306a36Sopenharmony_ci		dev_err(dev->mt76.dev, "Bcn size limit exceed\n");
70762306a36Sopenharmony_ci		dev_kfree_skb(skb);
70862306a36Sopenharmony_ci		return -EINVAL;
70962306a36Sopenharmony_ci	}
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	info = IEEE80211_SKB_CB(skb);
71262306a36Sopenharmony_ci	info->hw_queue |= FIELD_PREP(MT_TX_HW_QUEUE_PHY, mvif->mt76.band_idx);
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	mt7615_mac_write_txwi(dev, (__le32 *)(req.pkt), skb, wcid, NULL,
71562306a36Sopenharmony_ci			      0, NULL, 0, true);
71662306a36Sopenharmony_ci	memcpy(req.pkt + MT_TXD_SIZE, skb->data, skb->len);
71762306a36Sopenharmony_ci	req.pkt_len = cpu_to_le16(MT_TXD_SIZE + skb->len);
71862306a36Sopenharmony_ci	req.tim_ie_pos = cpu_to_le16(MT_TXD_SIZE + offs.tim_offset);
71962306a36Sopenharmony_ci	if (offs.cntdwn_counter_offs[0]) {
72062306a36Sopenharmony_ci		u16 csa_offs;
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci		csa_offs = MT_TXD_SIZE + offs.cntdwn_counter_offs[0] - 4;
72362306a36Sopenharmony_ci		req.csa_ie_pos = cpu_to_le16(csa_offs);
72462306a36Sopenharmony_ci		req.csa_cnt = skb->data[offs.cntdwn_counter_offs[0]];
72562306a36Sopenharmony_ci	}
72662306a36Sopenharmony_ci	dev_kfree_skb(skb);
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ciout:
72962306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(BCN_OFFLOAD), &req,
73062306a36Sopenharmony_ci				 sizeof(req), true);
73162306a36Sopenharmony_ci}
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_cistatic int
73462306a36Sopenharmony_cimt7615_mcu_ctrl_pm_state(struct mt7615_dev *dev, int band, int state)
73562306a36Sopenharmony_ci{
73662306a36Sopenharmony_ci	return mt76_connac_mcu_set_pm(&dev->mt76, band, state);
73762306a36Sopenharmony_ci}
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_cistatic int
74062306a36Sopenharmony_cimt7615_mcu_add_bss(struct mt7615_phy *phy, struct ieee80211_vif *vif,
74162306a36Sopenharmony_ci		   struct ieee80211_sta *sta, bool enable)
74262306a36Sopenharmony_ci{
74362306a36Sopenharmony_ci	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
74462306a36Sopenharmony_ci	struct mt7615_dev *dev = phy->dev;
74562306a36Sopenharmony_ci	struct sk_buff *skb;
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	if (mvif->mt76.omac_idx >= REPEATER_BSSID_START)
74862306a36Sopenharmony_ci		mt7615_mcu_muar_config(dev, vif, true, enable);
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, NULL);
75162306a36Sopenharmony_ci	if (IS_ERR(skb))
75262306a36Sopenharmony_ci		return PTR_ERR(skb);
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci	if (enable)
75562306a36Sopenharmony_ci		mt76_connac_mcu_bss_omac_tlv(skb, vif);
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	mt76_connac_mcu_bss_basic_tlv(skb, vif, sta, phy->mt76,
75862306a36Sopenharmony_ci				      mvif->sta.wcid.idx, enable);
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci	if (enable && mvif->mt76.omac_idx >= EXT_BSSID_START &&
76162306a36Sopenharmony_ci	    mvif->mt76.omac_idx < REPEATER_BSSID_START)
76262306a36Sopenharmony_ci		mt76_connac_mcu_bss_ext_tlv(skb, &mvif->mt76);
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci	return mt76_mcu_skb_send_msg(&dev->mt76, skb,
76562306a36Sopenharmony_ci				     MCU_EXT_CMD(BSS_INFO_UPDATE), true);
76662306a36Sopenharmony_ci}
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_cistatic int
76962306a36Sopenharmony_cimt7615_mcu_wtbl_tx_ba(struct mt7615_dev *dev,
77062306a36Sopenharmony_ci		      struct ieee80211_ampdu_params *params,
77162306a36Sopenharmony_ci		      bool enable)
77262306a36Sopenharmony_ci{
77362306a36Sopenharmony_ci	struct mt7615_sta *msta = (struct mt7615_sta *)params->sta->drv_priv;
77462306a36Sopenharmony_ci	struct mt7615_vif *mvif = msta->vif;
77562306a36Sopenharmony_ci	struct wtbl_req_hdr *wtbl_hdr;
77662306a36Sopenharmony_ci	struct sk_buff *skb = NULL;
77762306a36Sopenharmony_ci	int err;
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci	wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(&dev->mt76, &msta->wcid,
78062306a36Sopenharmony_ci						  WTBL_SET, NULL, &skb);
78162306a36Sopenharmony_ci	if (IS_ERR(wtbl_hdr))
78262306a36Sopenharmony_ci		return PTR_ERR(wtbl_hdr);
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci	mt76_connac_mcu_wtbl_ba_tlv(&dev->mt76, skb, params, enable, true,
78562306a36Sopenharmony_ci				    NULL, wtbl_hdr);
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci	err = mt76_mcu_skb_send_msg(&dev->mt76, skb,
78862306a36Sopenharmony_ci				    MCU_EXT_CMD(WTBL_UPDATE), true);
78962306a36Sopenharmony_ci	if (err < 0)
79062306a36Sopenharmony_ci		return err;
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci	skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
79362306a36Sopenharmony_ci					    &msta->wcid);
79462306a36Sopenharmony_ci	if (IS_ERR(skb))
79562306a36Sopenharmony_ci		return PTR_ERR(skb);
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci	mt76_connac_mcu_sta_ba_tlv(skb, params, enable, true);
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci	return mt76_mcu_skb_send_msg(&dev->mt76, skb,
80062306a36Sopenharmony_ci				     MCU_EXT_CMD(STA_REC_UPDATE), true);
80162306a36Sopenharmony_ci}
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_cistatic int
80462306a36Sopenharmony_cimt7615_mcu_wtbl_rx_ba(struct mt7615_dev *dev,
80562306a36Sopenharmony_ci		      struct ieee80211_ampdu_params *params,
80662306a36Sopenharmony_ci		      bool enable)
80762306a36Sopenharmony_ci{
80862306a36Sopenharmony_ci	struct mt7615_sta *msta = (struct mt7615_sta *)params->sta->drv_priv;
80962306a36Sopenharmony_ci	struct mt7615_vif *mvif = msta->vif;
81062306a36Sopenharmony_ci	struct wtbl_req_hdr *wtbl_hdr;
81162306a36Sopenharmony_ci	struct sk_buff *skb;
81262306a36Sopenharmony_ci	int err;
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
81562306a36Sopenharmony_ci					    &msta->wcid);
81662306a36Sopenharmony_ci	if (IS_ERR(skb))
81762306a36Sopenharmony_ci		return PTR_ERR(skb);
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci	mt76_connac_mcu_sta_ba_tlv(skb, params, enable, false);
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci	err = mt76_mcu_skb_send_msg(&dev->mt76, skb,
82262306a36Sopenharmony_ci				    MCU_EXT_CMD(STA_REC_UPDATE), true);
82362306a36Sopenharmony_ci	if (err < 0 || !enable)
82462306a36Sopenharmony_ci		return err;
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci	skb = NULL;
82762306a36Sopenharmony_ci	wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(&dev->mt76, &msta->wcid,
82862306a36Sopenharmony_ci						  WTBL_SET, NULL, &skb);
82962306a36Sopenharmony_ci	if (IS_ERR(wtbl_hdr))
83062306a36Sopenharmony_ci		return PTR_ERR(wtbl_hdr);
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci	mt76_connac_mcu_wtbl_ba_tlv(&dev->mt76, skb, params, enable, false,
83362306a36Sopenharmony_ci				    NULL, wtbl_hdr);
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci	return mt76_mcu_skb_send_msg(&dev->mt76, skb,
83662306a36Sopenharmony_ci				     MCU_EXT_CMD(WTBL_UPDATE), true);
83762306a36Sopenharmony_ci}
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_cistatic int
84062306a36Sopenharmony_cimt7615_mcu_wtbl_sta_add(struct mt7615_phy *phy, struct ieee80211_vif *vif,
84162306a36Sopenharmony_ci			struct ieee80211_sta *sta, bool enable)
84262306a36Sopenharmony_ci{
84362306a36Sopenharmony_ci	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
84462306a36Sopenharmony_ci	struct sk_buff *skb, *sskb, *wskb = NULL;
84562306a36Sopenharmony_ci	struct mt7615_dev *dev = phy->dev;
84662306a36Sopenharmony_ci	struct wtbl_req_hdr *wtbl_hdr;
84762306a36Sopenharmony_ci	struct mt7615_sta *msta;
84862306a36Sopenharmony_ci	bool new_entry = true;
84962306a36Sopenharmony_ci	int cmd, err;
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	msta = sta ? (struct mt7615_sta *)sta->drv_priv : &mvif->sta;
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	sskb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
85462306a36Sopenharmony_ci					     &msta->wcid);
85562306a36Sopenharmony_ci	if (IS_ERR(sskb))
85662306a36Sopenharmony_ci		return PTR_ERR(sskb);
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci	if (!sta) {
85962306a36Sopenharmony_ci		if (mvif->sta_added)
86062306a36Sopenharmony_ci			new_entry = false;
86162306a36Sopenharmony_ci		else
86262306a36Sopenharmony_ci			mvif->sta_added = true;
86362306a36Sopenharmony_ci	}
86462306a36Sopenharmony_ci	mt76_connac_mcu_sta_basic_tlv(&dev->mt76, sskb, vif, sta, enable,
86562306a36Sopenharmony_ci				      new_entry);
86662306a36Sopenharmony_ci	if (enable && sta)
86762306a36Sopenharmony_ci		mt76_connac_mcu_sta_tlv(phy->mt76, sskb, sta, vif, 0,
86862306a36Sopenharmony_ci					MT76_STA_INFO_STATE_ASSOC);
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci	wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(&dev->mt76, &msta->wcid,
87162306a36Sopenharmony_ci						  WTBL_RESET_AND_SET, NULL,
87262306a36Sopenharmony_ci						  &wskb);
87362306a36Sopenharmony_ci	if (IS_ERR(wtbl_hdr))
87462306a36Sopenharmony_ci		return PTR_ERR(wtbl_hdr);
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci	if (enable) {
87762306a36Sopenharmony_ci		mt76_connac_mcu_wtbl_generic_tlv(&dev->mt76, wskb, vif, sta,
87862306a36Sopenharmony_ci						 NULL, wtbl_hdr);
87962306a36Sopenharmony_ci		if (sta)
88062306a36Sopenharmony_ci			mt76_connac_mcu_wtbl_ht_tlv(&dev->mt76, wskb, sta,
88162306a36Sopenharmony_ci						    NULL, wtbl_hdr, true, true);
88262306a36Sopenharmony_ci		mt76_connac_mcu_wtbl_hdr_trans_tlv(wskb, vif, &msta->wcid,
88362306a36Sopenharmony_ci						   NULL, wtbl_hdr);
88462306a36Sopenharmony_ci	}
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci	cmd = enable ? MCU_EXT_CMD(WTBL_UPDATE) : MCU_EXT_CMD(STA_REC_UPDATE);
88762306a36Sopenharmony_ci	skb = enable ? wskb : sskb;
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci	err = mt76_mcu_skb_send_msg(&dev->mt76, skb, cmd, true);
89062306a36Sopenharmony_ci	if (err < 0) {
89162306a36Sopenharmony_ci		skb = enable ? sskb : wskb;
89262306a36Sopenharmony_ci		dev_kfree_skb(skb);
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci		return err;
89562306a36Sopenharmony_ci	}
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci	cmd = enable ? MCU_EXT_CMD(STA_REC_UPDATE) : MCU_EXT_CMD(WTBL_UPDATE);
89862306a36Sopenharmony_ci	skb = enable ? sskb : wskb;
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ci	return mt76_mcu_skb_send_msg(&dev->mt76, skb, cmd, true);
90162306a36Sopenharmony_ci}
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_cistatic int
90462306a36Sopenharmony_cimt7615_mcu_wtbl_update_hdr_trans(struct mt7615_dev *dev,
90562306a36Sopenharmony_ci				 struct ieee80211_vif *vif,
90662306a36Sopenharmony_ci				 struct ieee80211_sta *sta)
90762306a36Sopenharmony_ci{
90862306a36Sopenharmony_ci	return mt76_connac_mcu_wtbl_update_hdr_trans(&dev->mt76, vif, sta);
90962306a36Sopenharmony_ci}
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_cistatic const struct mt7615_mcu_ops wtbl_update_ops = {
91262306a36Sopenharmony_ci	.add_beacon_offload = mt7615_mcu_add_beacon_offload,
91362306a36Sopenharmony_ci	.set_pm_state = mt7615_mcu_ctrl_pm_state,
91462306a36Sopenharmony_ci	.add_dev_info = mt7615_mcu_add_dev,
91562306a36Sopenharmony_ci	.add_bss_info = mt7615_mcu_add_bss,
91662306a36Sopenharmony_ci	.add_tx_ba = mt7615_mcu_wtbl_tx_ba,
91762306a36Sopenharmony_ci	.add_rx_ba = mt7615_mcu_wtbl_rx_ba,
91862306a36Sopenharmony_ci	.sta_add = mt7615_mcu_wtbl_sta_add,
91962306a36Sopenharmony_ci	.set_drv_ctrl = mt7615_mcu_drv_pmctrl,
92062306a36Sopenharmony_ci	.set_fw_ctrl = mt7615_mcu_fw_pmctrl,
92162306a36Sopenharmony_ci	.set_sta_decap_offload = mt7615_mcu_wtbl_update_hdr_trans,
92262306a36Sopenharmony_ci};
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_cistatic int
92562306a36Sopenharmony_cimt7615_mcu_sta_ba(struct mt7615_dev *dev,
92662306a36Sopenharmony_ci		  struct ieee80211_ampdu_params *params,
92762306a36Sopenharmony_ci		  bool enable, bool tx)
92862306a36Sopenharmony_ci{
92962306a36Sopenharmony_ci	struct mt7615_sta *msta = (struct mt7615_sta *)params->sta->drv_priv;
93062306a36Sopenharmony_ci	struct mt7615_vif *mvif = msta->vif;
93162306a36Sopenharmony_ci	struct wtbl_req_hdr *wtbl_hdr;
93262306a36Sopenharmony_ci	struct tlv *sta_wtbl;
93362306a36Sopenharmony_ci	struct sk_buff *skb;
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci	skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
93662306a36Sopenharmony_ci					    &msta->wcid);
93762306a36Sopenharmony_ci	if (IS_ERR(skb))
93862306a36Sopenharmony_ci		return PTR_ERR(skb);
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_ci	mt76_connac_mcu_sta_ba_tlv(skb, params, enable, tx);
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci	sta_wtbl = mt76_connac_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv));
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci	wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(&dev->mt76, &msta->wcid,
94562306a36Sopenharmony_ci						  WTBL_SET, sta_wtbl, &skb);
94662306a36Sopenharmony_ci	if (IS_ERR(wtbl_hdr))
94762306a36Sopenharmony_ci		return PTR_ERR(wtbl_hdr);
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci	mt76_connac_mcu_wtbl_ba_tlv(&dev->mt76, skb, params, enable, tx,
95062306a36Sopenharmony_ci				    sta_wtbl, wtbl_hdr);
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci	return mt76_mcu_skb_send_msg(&dev->mt76, skb,
95362306a36Sopenharmony_ci				     MCU_EXT_CMD(STA_REC_UPDATE), true);
95462306a36Sopenharmony_ci}
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_cistatic int
95762306a36Sopenharmony_cimt7615_mcu_sta_tx_ba(struct mt7615_dev *dev,
95862306a36Sopenharmony_ci		     struct ieee80211_ampdu_params *params,
95962306a36Sopenharmony_ci		     bool enable)
96062306a36Sopenharmony_ci{
96162306a36Sopenharmony_ci	return mt7615_mcu_sta_ba(dev, params, enable, true);
96262306a36Sopenharmony_ci}
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_cistatic int
96562306a36Sopenharmony_cimt7615_mcu_sta_rx_ba(struct mt7615_dev *dev,
96662306a36Sopenharmony_ci		     struct ieee80211_ampdu_params *params,
96762306a36Sopenharmony_ci		     bool enable)
96862306a36Sopenharmony_ci{
96962306a36Sopenharmony_ci	return mt7615_mcu_sta_ba(dev, params, enable, false);
97062306a36Sopenharmony_ci}
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_cistatic int
97362306a36Sopenharmony_ci__mt7615_mcu_add_sta(struct mt76_phy *phy, struct ieee80211_vif *vif,
97462306a36Sopenharmony_ci		     struct ieee80211_sta *sta, bool enable, int cmd,
97562306a36Sopenharmony_ci		     bool offload_fw)
97662306a36Sopenharmony_ci{
97762306a36Sopenharmony_ci	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
97862306a36Sopenharmony_ci	struct mt76_sta_cmd_info info = {
97962306a36Sopenharmony_ci		.sta = sta,
98062306a36Sopenharmony_ci		.vif = vif,
98162306a36Sopenharmony_ci		.offload_fw = offload_fw,
98262306a36Sopenharmony_ci		.enable = enable,
98362306a36Sopenharmony_ci		.newly = true,
98462306a36Sopenharmony_ci		.cmd = cmd,
98562306a36Sopenharmony_ci	};
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci	info.wcid = sta ? (struct mt76_wcid *)sta->drv_priv : &mvif->sta.wcid;
98862306a36Sopenharmony_ci	return mt76_connac_mcu_sta_cmd(phy, &info);
98962306a36Sopenharmony_ci}
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_cistatic int
99262306a36Sopenharmony_cimt7615_mcu_add_sta(struct mt7615_phy *phy, struct ieee80211_vif *vif,
99362306a36Sopenharmony_ci		   struct ieee80211_sta *sta, bool enable)
99462306a36Sopenharmony_ci{
99562306a36Sopenharmony_ci	return __mt7615_mcu_add_sta(phy->mt76, vif, sta, enable,
99662306a36Sopenharmony_ci				    MCU_EXT_CMD(STA_REC_UPDATE), false);
99762306a36Sopenharmony_ci}
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_cistatic int
100062306a36Sopenharmony_cimt7615_mcu_sta_update_hdr_trans(struct mt7615_dev *dev,
100162306a36Sopenharmony_ci				struct ieee80211_vif *vif,
100262306a36Sopenharmony_ci				struct ieee80211_sta *sta)
100362306a36Sopenharmony_ci{
100462306a36Sopenharmony_ci	struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv;
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_ci	return mt76_connac_mcu_sta_update_hdr_trans(&dev->mt76,
100762306a36Sopenharmony_ci						    vif, &msta->wcid,
100862306a36Sopenharmony_ci						    MCU_EXT_CMD(STA_REC_UPDATE));
100962306a36Sopenharmony_ci}
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_cistatic const struct mt7615_mcu_ops sta_update_ops = {
101262306a36Sopenharmony_ci	.add_beacon_offload = mt7615_mcu_add_beacon_offload,
101362306a36Sopenharmony_ci	.set_pm_state = mt7615_mcu_ctrl_pm_state,
101462306a36Sopenharmony_ci	.add_dev_info = mt7615_mcu_add_dev,
101562306a36Sopenharmony_ci	.add_bss_info = mt7615_mcu_add_bss,
101662306a36Sopenharmony_ci	.add_tx_ba = mt7615_mcu_sta_tx_ba,
101762306a36Sopenharmony_ci	.add_rx_ba = mt7615_mcu_sta_rx_ba,
101862306a36Sopenharmony_ci	.sta_add = mt7615_mcu_add_sta,
101962306a36Sopenharmony_ci	.set_drv_ctrl = mt7615_mcu_drv_pmctrl,
102062306a36Sopenharmony_ci	.set_fw_ctrl = mt7615_mcu_fw_pmctrl,
102162306a36Sopenharmony_ci	.set_sta_decap_offload = mt7615_mcu_sta_update_hdr_trans,
102262306a36Sopenharmony_ci};
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_cistatic int
102562306a36Sopenharmony_cimt7615_mcu_uni_ctrl_pm_state(struct mt7615_dev *dev, int band, int state)
102662306a36Sopenharmony_ci{
102762306a36Sopenharmony_ci	return 0;
102862306a36Sopenharmony_ci}
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_cistatic int
103162306a36Sopenharmony_cimt7615_mcu_uni_add_beacon_offload(struct mt7615_dev *dev,
103262306a36Sopenharmony_ci				  struct ieee80211_hw *hw,
103362306a36Sopenharmony_ci				  struct ieee80211_vif *vif,
103462306a36Sopenharmony_ci				  bool enable)
103562306a36Sopenharmony_ci{
103662306a36Sopenharmony_ci	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
103762306a36Sopenharmony_ci	struct mt76_wcid *wcid = &dev->mt76.global_wcid;
103862306a36Sopenharmony_ci	struct ieee80211_mutable_offsets offs;
103962306a36Sopenharmony_ci	struct {
104062306a36Sopenharmony_ci		struct req_hdr {
104162306a36Sopenharmony_ci			u8 bss_idx;
104262306a36Sopenharmony_ci			u8 pad[3];
104362306a36Sopenharmony_ci		} __packed hdr;
104462306a36Sopenharmony_ci		struct bcn_content_tlv {
104562306a36Sopenharmony_ci			__le16 tag;
104662306a36Sopenharmony_ci			__le16 len;
104762306a36Sopenharmony_ci			__le16 tim_ie_pos;
104862306a36Sopenharmony_ci			__le16 csa_ie_pos;
104962306a36Sopenharmony_ci			__le16 bcc_ie_pos;
105062306a36Sopenharmony_ci			/* 0: disable beacon offload
105162306a36Sopenharmony_ci			 * 1: enable beacon offload
105262306a36Sopenharmony_ci			 * 2: update probe respond offload
105362306a36Sopenharmony_ci			 */
105462306a36Sopenharmony_ci			u8 enable;
105562306a36Sopenharmony_ci			/* 0: legacy format (TXD + payload)
105662306a36Sopenharmony_ci			 * 1: only cap field IE
105762306a36Sopenharmony_ci			 */
105862306a36Sopenharmony_ci			u8 type;
105962306a36Sopenharmony_ci			__le16 pkt_len;
106062306a36Sopenharmony_ci			u8 pkt[512];
106162306a36Sopenharmony_ci		} __packed beacon_tlv;
106262306a36Sopenharmony_ci	} req = {
106362306a36Sopenharmony_ci		.hdr = {
106462306a36Sopenharmony_ci			.bss_idx = mvif->mt76.idx,
106562306a36Sopenharmony_ci		},
106662306a36Sopenharmony_ci		.beacon_tlv = {
106762306a36Sopenharmony_ci			.tag = cpu_to_le16(UNI_BSS_INFO_BCN_CONTENT),
106862306a36Sopenharmony_ci			.len = cpu_to_le16(sizeof(struct bcn_content_tlv)),
106962306a36Sopenharmony_ci			.enable = enable,
107062306a36Sopenharmony_ci		},
107162306a36Sopenharmony_ci	};
107262306a36Sopenharmony_ci	struct sk_buff *skb;
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_ci	if (!enable)
107562306a36Sopenharmony_ci		goto out;
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ci	skb = ieee80211_beacon_get_template(mt76_hw(dev), vif, &offs, 0);
107862306a36Sopenharmony_ci	if (!skb)
107962306a36Sopenharmony_ci		return -EINVAL;
108062306a36Sopenharmony_ci
108162306a36Sopenharmony_ci	if (skb->len > 512 - MT_TXD_SIZE) {
108262306a36Sopenharmony_ci		dev_err(dev->mt76.dev, "beacon size limit exceed\n");
108362306a36Sopenharmony_ci		dev_kfree_skb(skb);
108462306a36Sopenharmony_ci		return -EINVAL;
108562306a36Sopenharmony_ci	}
108662306a36Sopenharmony_ci
108762306a36Sopenharmony_ci	mt7615_mac_write_txwi(dev, (__le32 *)(req.beacon_tlv.pkt), skb,
108862306a36Sopenharmony_ci			      wcid, NULL, 0, NULL, 0, true);
108962306a36Sopenharmony_ci	memcpy(req.beacon_tlv.pkt + MT_TXD_SIZE, skb->data, skb->len);
109062306a36Sopenharmony_ci	req.beacon_tlv.pkt_len = cpu_to_le16(MT_TXD_SIZE + skb->len);
109162306a36Sopenharmony_ci	req.beacon_tlv.tim_ie_pos = cpu_to_le16(MT_TXD_SIZE + offs.tim_offset);
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_ci	if (offs.cntdwn_counter_offs[0]) {
109462306a36Sopenharmony_ci		u16 csa_offs;
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci		csa_offs = MT_TXD_SIZE + offs.cntdwn_counter_offs[0] - 4;
109762306a36Sopenharmony_ci		req.beacon_tlv.csa_ie_pos = cpu_to_le16(csa_offs);
109862306a36Sopenharmony_ci	}
109962306a36Sopenharmony_ci	dev_kfree_skb(skb);
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ciout:
110262306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(BSS_INFO_UPDATE),
110362306a36Sopenharmony_ci				 &req, sizeof(req), true);
110462306a36Sopenharmony_ci}
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_cistatic int
110762306a36Sopenharmony_cimt7615_mcu_uni_add_dev(struct mt7615_phy *phy, struct ieee80211_vif *vif,
110862306a36Sopenharmony_ci		       bool enable)
110962306a36Sopenharmony_ci{
111062306a36Sopenharmony_ci	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_ci	return mt76_connac_mcu_uni_add_dev(phy->mt76, vif, &mvif->sta.wcid,
111362306a36Sopenharmony_ci					   enable);
111462306a36Sopenharmony_ci}
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_cistatic int
111762306a36Sopenharmony_cimt7615_mcu_uni_add_bss(struct mt7615_phy *phy, struct ieee80211_vif *vif,
111862306a36Sopenharmony_ci		       struct ieee80211_sta *sta, bool enable)
111962306a36Sopenharmony_ci{
112062306a36Sopenharmony_ci	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_ci	return mt76_connac_mcu_uni_add_bss(phy->mt76, vif, &mvif->sta.wcid,
112362306a36Sopenharmony_ci					   enable, NULL);
112462306a36Sopenharmony_ci}
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_cistatic inline int
112762306a36Sopenharmony_cimt7615_mcu_uni_add_sta(struct mt7615_phy *phy, struct ieee80211_vif *vif,
112862306a36Sopenharmony_ci		       struct ieee80211_sta *sta, bool enable)
112962306a36Sopenharmony_ci{
113062306a36Sopenharmony_ci	return __mt7615_mcu_add_sta(phy->mt76, vif, sta, enable,
113162306a36Sopenharmony_ci				    MCU_UNI_CMD(STA_REC_UPDATE), true);
113262306a36Sopenharmony_ci}
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_cistatic int
113562306a36Sopenharmony_cimt7615_mcu_uni_tx_ba(struct mt7615_dev *dev,
113662306a36Sopenharmony_ci		     struct ieee80211_ampdu_params *params,
113762306a36Sopenharmony_ci		     bool enable)
113862306a36Sopenharmony_ci{
113962306a36Sopenharmony_ci	struct mt7615_sta *sta = (struct mt7615_sta *)params->sta->drv_priv;
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_ci	return mt76_connac_mcu_sta_ba(&dev->mt76, &sta->vif->mt76, params,
114262306a36Sopenharmony_ci				      MCU_UNI_CMD(STA_REC_UPDATE), enable,
114362306a36Sopenharmony_ci				      true);
114462306a36Sopenharmony_ci}
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_cistatic int
114762306a36Sopenharmony_cimt7615_mcu_uni_rx_ba(struct mt7615_dev *dev,
114862306a36Sopenharmony_ci		     struct ieee80211_ampdu_params *params,
114962306a36Sopenharmony_ci		     bool enable)
115062306a36Sopenharmony_ci{
115162306a36Sopenharmony_ci	struct mt7615_sta *msta = (struct mt7615_sta *)params->sta->drv_priv;
115262306a36Sopenharmony_ci	struct mt7615_vif *mvif = msta->vif;
115362306a36Sopenharmony_ci	struct wtbl_req_hdr *wtbl_hdr;
115462306a36Sopenharmony_ci	struct tlv *sta_wtbl;
115562306a36Sopenharmony_ci	struct sk_buff *skb;
115662306a36Sopenharmony_ci	int err;
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_ci	skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
115962306a36Sopenharmony_ci					    &msta->wcid);
116062306a36Sopenharmony_ci	if (IS_ERR(skb))
116162306a36Sopenharmony_ci		return PTR_ERR(skb);
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_ci	mt76_connac_mcu_sta_ba_tlv(skb, params, enable, false);
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci	err = mt76_mcu_skb_send_msg(&dev->mt76, skb,
116662306a36Sopenharmony_ci				    MCU_UNI_CMD(STA_REC_UPDATE), true);
116762306a36Sopenharmony_ci	if (err < 0 || !enable)
116862306a36Sopenharmony_ci		return err;
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_ci	skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
117162306a36Sopenharmony_ci					    &msta->wcid);
117262306a36Sopenharmony_ci	if (IS_ERR(skb))
117362306a36Sopenharmony_ci		return PTR_ERR(skb);
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_ci	sta_wtbl = mt76_connac_mcu_add_tlv(skb, STA_REC_WTBL,
117662306a36Sopenharmony_ci					   sizeof(struct tlv));
117762306a36Sopenharmony_ci
117862306a36Sopenharmony_ci	wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(&dev->mt76, &msta->wcid,
117962306a36Sopenharmony_ci						  WTBL_SET, sta_wtbl, &skb);
118062306a36Sopenharmony_ci	if (IS_ERR(wtbl_hdr))
118162306a36Sopenharmony_ci		return PTR_ERR(wtbl_hdr);
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci	mt76_connac_mcu_wtbl_ba_tlv(&dev->mt76, skb, params, enable, false,
118462306a36Sopenharmony_ci				    sta_wtbl, wtbl_hdr);
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ci	return mt76_mcu_skb_send_msg(&dev->mt76, skb,
118762306a36Sopenharmony_ci				     MCU_UNI_CMD(STA_REC_UPDATE), true);
118862306a36Sopenharmony_ci}
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_cistatic int
119162306a36Sopenharmony_cimt7615_mcu_sta_uni_update_hdr_trans(struct mt7615_dev *dev,
119262306a36Sopenharmony_ci				    struct ieee80211_vif *vif,
119362306a36Sopenharmony_ci				    struct ieee80211_sta *sta)
119462306a36Sopenharmony_ci{
119562306a36Sopenharmony_ci	struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv;
119662306a36Sopenharmony_ci
119762306a36Sopenharmony_ci	return mt76_connac_mcu_sta_update_hdr_trans(&dev->mt76,
119862306a36Sopenharmony_ci						    vif, &msta->wcid,
119962306a36Sopenharmony_ci						    MCU_UNI_CMD(STA_REC_UPDATE));
120062306a36Sopenharmony_ci}
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_cistatic const struct mt7615_mcu_ops uni_update_ops = {
120362306a36Sopenharmony_ci	.add_beacon_offload = mt7615_mcu_uni_add_beacon_offload,
120462306a36Sopenharmony_ci	.set_pm_state = mt7615_mcu_uni_ctrl_pm_state,
120562306a36Sopenharmony_ci	.add_dev_info = mt7615_mcu_uni_add_dev,
120662306a36Sopenharmony_ci	.add_bss_info = mt7615_mcu_uni_add_bss,
120762306a36Sopenharmony_ci	.add_tx_ba = mt7615_mcu_uni_tx_ba,
120862306a36Sopenharmony_ci	.add_rx_ba = mt7615_mcu_uni_rx_ba,
120962306a36Sopenharmony_ci	.sta_add = mt7615_mcu_uni_add_sta,
121062306a36Sopenharmony_ci	.set_drv_ctrl = mt7615_mcu_lp_drv_pmctrl,
121162306a36Sopenharmony_ci	.set_fw_ctrl = mt7615_mcu_fw_pmctrl,
121262306a36Sopenharmony_ci	.set_sta_decap_offload = mt7615_mcu_sta_uni_update_hdr_trans,
121362306a36Sopenharmony_ci};
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_ciint mt7615_mcu_restart(struct mt76_dev *dev)
121662306a36Sopenharmony_ci{
121762306a36Sopenharmony_ci	return mt76_mcu_send_msg(dev, MCU_CMD(RESTART_DL_REQ), NULL, 0, true);
121862306a36Sopenharmony_ci}
121962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mt7615_mcu_restart);
122062306a36Sopenharmony_ci
122162306a36Sopenharmony_cistatic int mt7615_load_patch(struct mt7615_dev *dev, u32 addr, const char *name)
122262306a36Sopenharmony_ci{
122362306a36Sopenharmony_ci	const struct mt7615_patch_hdr *hdr;
122462306a36Sopenharmony_ci	const struct firmware *fw = NULL;
122562306a36Sopenharmony_ci	int len, ret, sem;
122662306a36Sopenharmony_ci
122762306a36Sopenharmony_ci	ret = firmware_request_nowarn(&fw, name, dev->mt76.dev);
122862306a36Sopenharmony_ci	if (ret)
122962306a36Sopenharmony_ci		return ret;
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_ci	if (!fw || !fw->data || fw->size < sizeof(*hdr)) {
123262306a36Sopenharmony_ci		dev_err(dev->mt76.dev, "Invalid firmware\n");
123362306a36Sopenharmony_ci		ret = -EINVAL;
123462306a36Sopenharmony_ci		goto release_fw;
123562306a36Sopenharmony_ci	}
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_ci	sem = mt76_connac_mcu_patch_sem_ctrl(&dev->mt76, true);
123862306a36Sopenharmony_ci	switch (sem) {
123962306a36Sopenharmony_ci	case PATCH_IS_DL:
124062306a36Sopenharmony_ci		goto release_fw;
124162306a36Sopenharmony_ci	case PATCH_NOT_DL_SEM_SUCCESS:
124262306a36Sopenharmony_ci		break;
124362306a36Sopenharmony_ci	default:
124462306a36Sopenharmony_ci		dev_err(dev->mt76.dev, "Failed to get patch semaphore\n");
124562306a36Sopenharmony_ci		ret = -EAGAIN;
124662306a36Sopenharmony_ci		goto release_fw;
124762306a36Sopenharmony_ci	}
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_ci	hdr = (const struct mt7615_patch_hdr *)(fw->data);
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_ci	dev_info(dev->mt76.dev, "HW/SW Version: 0x%x, Build Time: %.16s\n",
125262306a36Sopenharmony_ci		 be32_to_cpu(hdr->hw_sw_ver), hdr->build_date);
125362306a36Sopenharmony_ci
125462306a36Sopenharmony_ci	len = fw->size - sizeof(*hdr);
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_ci	ret = mt76_connac_mcu_init_download(&dev->mt76, addr, len,
125762306a36Sopenharmony_ci					    DL_MODE_NEED_RSP);
125862306a36Sopenharmony_ci	if (ret) {
125962306a36Sopenharmony_ci		dev_err(dev->mt76.dev, "Download request failed\n");
126062306a36Sopenharmony_ci		goto out;
126162306a36Sopenharmony_ci	}
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_ci	ret = mt76_mcu_send_firmware(&dev->mt76, MCU_CMD(FW_SCATTER),
126462306a36Sopenharmony_ci				     fw->data + sizeof(*hdr), len);
126562306a36Sopenharmony_ci	if (ret) {
126662306a36Sopenharmony_ci		dev_err(dev->mt76.dev, "Failed to send firmware to device\n");
126762306a36Sopenharmony_ci		goto out;
126862306a36Sopenharmony_ci	}
126962306a36Sopenharmony_ci
127062306a36Sopenharmony_ci	ret = mt76_connac_mcu_start_patch(&dev->mt76);
127162306a36Sopenharmony_ci	if (ret)
127262306a36Sopenharmony_ci		dev_err(dev->mt76.dev, "Failed to start patch\n");
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_ciout:
127562306a36Sopenharmony_ci	sem = mt76_connac_mcu_patch_sem_ctrl(&dev->mt76, false);
127662306a36Sopenharmony_ci	switch (sem) {
127762306a36Sopenharmony_ci	case PATCH_REL_SEM_SUCCESS:
127862306a36Sopenharmony_ci		break;
127962306a36Sopenharmony_ci	default:
128062306a36Sopenharmony_ci		ret = -EAGAIN;
128162306a36Sopenharmony_ci		dev_err(dev->mt76.dev, "Failed to release patch semaphore\n");
128262306a36Sopenharmony_ci		break;
128362306a36Sopenharmony_ci	}
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_cirelease_fw:
128662306a36Sopenharmony_ci	release_firmware(fw);
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci	return ret;
128962306a36Sopenharmony_ci}
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_cistatic int
129262306a36Sopenharmony_cimt7615_mcu_send_ram_firmware(struct mt7615_dev *dev,
129362306a36Sopenharmony_ci			     const struct mt7615_fw_trailer *hdr,
129462306a36Sopenharmony_ci			     const u8 *data, bool is_cr4)
129562306a36Sopenharmony_ci{
129662306a36Sopenharmony_ci	int n_region = is_cr4 ? CR4_REGION_NUM : N9_REGION_NUM;
129762306a36Sopenharmony_ci	int err, i, offset = 0;
129862306a36Sopenharmony_ci	u32 len, addr, mode;
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_ci	for (i = 0; i < n_region; i++) {
130162306a36Sopenharmony_ci		mode = mt76_connac_mcu_gen_dl_mode(&dev->mt76,
130262306a36Sopenharmony_ci						   hdr[i].feature_set, is_cr4);
130362306a36Sopenharmony_ci		len = le32_to_cpu(hdr[i].len) + IMG_CRC_LEN;
130462306a36Sopenharmony_ci		addr = le32_to_cpu(hdr[i].addr);
130562306a36Sopenharmony_ci
130662306a36Sopenharmony_ci		err = mt76_connac_mcu_init_download(&dev->mt76, addr, len,
130762306a36Sopenharmony_ci						    mode);
130862306a36Sopenharmony_ci		if (err) {
130962306a36Sopenharmony_ci			dev_err(dev->mt76.dev, "Download request failed\n");
131062306a36Sopenharmony_ci			return err;
131162306a36Sopenharmony_ci		}
131262306a36Sopenharmony_ci
131362306a36Sopenharmony_ci		err = mt76_mcu_send_firmware(&dev->mt76, MCU_CMD(FW_SCATTER),
131462306a36Sopenharmony_ci					     data + offset, len);
131562306a36Sopenharmony_ci		if (err) {
131662306a36Sopenharmony_ci			dev_err(dev->mt76.dev, "Failed to send firmware to device\n");
131762306a36Sopenharmony_ci			return err;
131862306a36Sopenharmony_ci		}
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_ci		offset += len;
132162306a36Sopenharmony_ci	}
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_ci	return 0;
132462306a36Sopenharmony_ci}
132562306a36Sopenharmony_ci
132662306a36Sopenharmony_cistatic int mt7615_load_n9(struct mt7615_dev *dev, const char *name)
132762306a36Sopenharmony_ci{
132862306a36Sopenharmony_ci	const struct mt7615_fw_trailer *hdr;
132962306a36Sopenharmony_ci	const struct firmware *fw;
133062306a36Sopenharmony_ci	int ret;
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_ci	ret = request_firmware(&fw, name, dev->mt76.dev);
133362306a36Sopenharmony_ci	if (ret)
133462306a36Sopenharmony_ci		return ret;
133562306a36Sopenharmony_ci
133662306a36Sopenharmony_ci	if (!fw || !fw->data || fw->size < N9_REGION_NUM * sizeof(*hdr)) {
133762306a36Sopenharmony_ci		dev_err(dev->mt76.dev, "Invalid firmware\n");
133862306a36Sopenharmony_ci		ret = -EINVAL;
133962306a36Sopenharmony_ci		goto out;
134062306a36Sopenharmony_ci	}
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_ci	hdr = (const struct mt7615_fw_trailer *)(fw->data + fw->size -
134362306a36Sopenharmony_ci					N9_REGION_NUM * sizeof(*hdr));
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_ci	dev_info(dev->mt76.dev, "N9 Firmware Version: %.10s, Build Time: %.15s\n",
134662306a36Sopenharmony_ci		 hdr->fw_ver, hdr->build_date);
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_ci	ret = mt7615_mcu_send_ram_firmware(dev, hdr, fw->data, false);
134962306a36Sopenharmony_ci	if (ret)
135062306a36Sopenharmony_ci		goto out;
135162306a36Sopenharmony_ci
135262306a36Sopenharmony_ci	ret = mt76_connac_mcu_start_firmware(&dev->mt76,
135362306a36Sopenharmony_ci					     le32_to_cpu(hdr->addr),
135462306a36Sopenharmony_ci					     FW_START_OVERRIDE);
135562306a36Sopenharmony_ci	if (ret) {
135662306a36Sopenharmony_ci		dev_err(dev->mt76.dev, "Failed to start N9 firmware\n");
135762306a36Sopenharmony_ci		goto out;
135862306a36Sopenharmony_ci	}
135962306a36Sopenharmony_ci
136062306a36Sopenharmony_ci	snprintf(dev->mt76.hw->wiphy->fw_version,
136162306a36Sopenharmony_ci		 sizeof(dev->mt76.hw->wiphy->fw_version),
136262306a36Sopenharmony_ci		 "%.10s-%.15s", hdr->fw_ver, hdr->build_date);
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_ci	if (!is_mt7615(&dev->mt76)) {
136562306a36Sopenharmony_ci		dev->fw_ver = MT7615_FIRMWARE_V2;
136662306a36Sopenharmony_ci		dev->mcu_ops = &sta_update_ops;
136762306a36Sopenharmony_ci	} else {
136862306a36Sopenharmony_ci		dev->fw_ver = MT7615_FIRMWARE_V1;
136962306a36Sopenharmony_ci		dev->mcu_ops = &wtbl_update_ops;
137062306a36Sopenharmony_ci	}
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_ciout:
137362306a36Sopenharmony_ci	release_firmware(fw);
137462306a36Sopenharmony_ci	return ret;
137562306a36Sopenharmony_ci}
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_cistatic int mt7615_load_cr4(struct mt7615_dev *dev, const char *name)
137862306a36Sopenharmony_ci{
137962306a36Sopenharmony_ci	const struct mt7615_fw_trailer *hdr;
138062306a36Sopenharmony_ci	const struct firmware *fw;
138162306a36Sopenharmony_ci	int ret;
138262306a36Sopenharmony_ci
138362306a36Sopenharmony_ci	ret = request_firmware(&fw, name, dev->mt76.dev);
138462306a36Sopenharmony_ci	if (ret)
138562306a36Sopenharmony_ci		return ret;
138662306a36Sopenharmony_ci
138762306a36Sopenharmony_ci	if (!fw || !fw->data || fw->size < CR4_REGION_NUM * sizeof(*hdr)) {
138862306a36Sopenharmony_ci		dev_err(dev->mt76.dev, "Invalid firmware\n");
138962306a36Sopenharmony_ci		ret = -EINVAL;
139062306a36Sopenharmony_ci		goto out;
139162306a36Sopenharmony_ci	}
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci	hdr = (const struct mt7615_fw_trailer *)(fw->data + fw->size -
139462306a36Sopenharmony_ci					CR4_REGION_NUM * sizeof(*hdr));
139562306a36Sopenharmony_ci
139662306a36Sopenharmony_ci	dev_info(dev->mt76.dev, "CR4 Firmware Version: %.10s, Build Time: %.15s\n",
139762306a36Sopenharmony_ci		 hdr->fw_ver, hdr->build_date);
139862306a36Sopenharmony_ci
139962306a36Sopenharmony_ci	ret = mt7615_mcu_send_ram_firmware(dev, hdr, fw->data, true);
140062306a36Sopenharmony_ci	if (ret)
140162306a36Sopenharmony_ci		goto out;
140262306a36Sopenharmony_ci
140362306a36Sopenharmony_ci	ret = mt76_connac_mcu_start_firmware(&dev->mt76, 0,
140462306a36Sopenharmony_ci					     FW_START_WORKING_PDA_CR4);
140562306a36Sopenharmony_ci	if (ret) {
140662306a36Sopenharmony_ci		dev_err(dev->mt76.dev, "Failed to start CR4 firmware\n");
140762306a36Sopenharmony_ci		goto out;
140862306a36Sopenharmony_ci	}
140962306a36Sopenharmony_ci
141062306a36Sopenharmony_ciout:
141162306a36Sopenharmony_ci	release_firmware(fw);
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_ci	return ret;
141462306a36Sopenharmony_ci}
141562306a36Sopenharmony_ci
141662306a36Sopenharmony_cistatic int mt7615_load_ram(struct mt7615_dev *dev)
141762306a36Sopenharmony_ci{
141862306a36Sopenharmony_ci	int ret;
141962306a36Sopenharmony_ci
142062306a36Sopenharmony_ci	ret = mt7615_load_n9(dev, MT7615_FIRMWARE_N9);
142162306a36Sopenharmony_ci	if (ret)
142262306a36Sopenharmony_ci		return ret;
142362306a36Sopenharmony_ci
142462306a36Sopenharmony_ci	return mt7615_load_cr4(dev, MT7615_FIRMWARE_CR4);
142562306a36Sopenharmony_ci}
142662306a36Sopenharmony_ci
142762306a36Sopenharmony_cistatic int mt7615_load_firmware(struct mt7615_dev *dev)
142862306a36Sopenharmony_ci{
142962306a36Sopenharmony_ci	int ret;
143062306a36Sopenharmony_ci	u32 val;
143162306a36Sopenharmony_ci
143262306a36Sopenharmony_ci	val = mt76_get_field(dev, MT_TOP_MISC2, MT_TOP_MISC2_FW_STATE);
143362306a36Sopenharmony_ci
143462306a36Sopenharmony_ci	if (val != FW_STATE_FW_DOWNLOAD) {
143562306a36Sopenharmony_ci		dev_err(dev->mt76.dev, "Firmware is not ready for download\n");
143662306a36Sopenharmony_ci		return -EIO;
143762306a36Sopenharmony_ci	}
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_ci	ret = mt7615_load_patch(dev, MT7615_PATCH_ADDRESS, MT7615_ROM_PATCH);
144062306a36Sopenharmony_ci	if (ret)
144162306a36Sopenharmony_ci		return ret;
144262306a36Sopenharmony_ci
144362306a36Sopenharmony_ci	ret = mt7615_load_ram(dev);
144462306a36Sopenharmony_ci	if (ret)
144562306a36Sopenharmony_ci		return ret;
144662306a36Sopenharmony_ci
144762306a36Sopenharmony_ci	if (!mt76_poll_msec(dev, MT_TOP_MISC2, MT_TOP_MISC2_FW_STATE,
144862306a36Sopenharmony_ci			    FIELD_PREP(MT_TOP_MISC2_FW_STATE,
144962306a36Sopenharmony_ci				       FW_STATE_RDY), 500)) {
145062306a36Sopenharmony_ci		dev_err(dev->mt76.dev, "Timeout for initializing firmware\n");
145162306a36Sopenharmony_ci		return -EIO;
145262306a36Sopenharmony_ci	}
145362306a36Sopenharmony_ci
145462306a36Sopenharmony_ci	return 0;
145562306a36Sopenharmony_ci}
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_cistatic int mt7622_load_firmware(struct mt7615_dev *dev)
145862306a36Sopenharmony_ci{
145962306a36Sopenharmony_ci	int ret;
146062306a36Sopenharmony_ci	u32 val;
146162306a36Sopenharmony_ci
146262306a36Sopenharmony_ci	mt76_set(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_BYPASS_TX_SCH);
146362306a36Sopenharmony_ci
146462306a36Sopenharmony_ci	val = mt76_get_field(dev, MT_TOP_OFF_RSV, MT_TOP_OFF_RSV_FW_STATE);
146562306a36Sopenharmony_ci	if (val != FW_STATE_FW_DOWNLOAD) {
146662306a36Sopenharmony_ci		dev_err(dev->mt76.dev, "Firmware is not ready for download\n");
146762306a36Sopenharmony_ci		return -EIO;
146862306a36Sopenharmony_ci	}
146962306a36Sopenharmony_ci
147062306a36Sopenharmony_ci	ret = mt7615_load_patch(dev, MT7622_PATCH_ADDRESS, MT7622_ROM_PATCH);
147162306a36Sopenharmony_ci	if (ret)
147262306a36Sopenharmony_ci		return ret;
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_ci	ret = mt7615_load_n9(dev, MT7622_FIRMWARE_N9);
147562306a36Sopenharmony_ci	if (ret)
147662306a36Sopenharmony_ci		return ret;
147762306a36Sopenharmony_ci
147862306a36Sopenharmony_ci	if (!mt76_poll_msec(dev, MT_TOP_OFF_RSV, MT_TOP_OFF_RSV_FW_STATE,
147962306a36Sopenharmony_ci			    FIELD_PREP(MT_TOP_OFF_RSV_FW_STATE,
148062306a36Sopenharmony_ci				       FW_STATE_NORMAL_TRX), 1500)) {
148162306a36Sopenharmony_ci		dev_err(dev->mt76.dev, "Timeout for initializing firmware\n");
148262306a36Sopenharmony_ci		return -EIO;
148362306a36Sopenharmony_ci	}
148462306a36Sopenharmony_ci
148562306a36Sopenharmony_ci	mt76_clear(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_BYPASS_TX_SCH);
148662306a36Sopenharmony_ci
148762306a36Sopenharmony_ci	return 0;
148862306a36Sopenharmony_ci}
148962306a36Sopenharmony_ci
149062306a36Sopenharmony_ciint mt7615_mcu_fw_log_2_host(struct mt7615_dev *dev, u8 ctrl)
149162306a36Sopenharmony_ci{
149262306a36Sopenharmony_ci	struct {
149362306a36Sopenharmony_ci		u8 ctrl_val;
149462306a36Sopenharmony_ci		u8 pad[3];
149562306a36Sopenharmony_ci	} data = {
149662306a36Sopenharmony_ci		.ctrl_val = ctrl
149762306a36Sopenharmony_ci	};
149862306a36Sopenharmony_ci
149962306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(FW_LOG_2_HOST),
150062306a36Sopenharmony_ci				 &data, sizeof(data), true);
150162306a36Sopenharmony_ci}
150262306a36Sopenharmony_ci
150362306a36Sopenharmony_cistatic int mt7615_mcu_cal_cache_apply(struct mt7615_dev *dev)
150462306a36Sopenharmony_ci{
150562306a36Sopenharmony_ci	struct {
150662306a36Sopenharmony_ci		bool cache_enable;
150762306a36Sopenharmony_ci		u8 pad[3];
150862306a36Sopenharmony_ci	} data = {
150962306a36Sopenharmony_ci		.cache_enable = true
151062306a36Sopenharmony_ci	};
151162306a36Sopenharmony_ci
151262306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(CAL_CACHE), &data,
151362306a36Sopenharmony_ci				 sizeof(data), false);
151462306a36Sopenharmony_ci}
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_cistatic int mt7663_load_n9(struct mt7615_dev *dev, const char *name)
151762306a36Sopenharmony_ci{
151862306a36Sopenharmony_ci	u32 offset = 0, override_addr = 0, flag = FW_START_DLYCAL;
151962306a36Sopenharmony_ci	const struct mt76_connac2_fw_trailer *hdr;
152062306a36Sopenharmony_ci	const struct mt7663_fw_buf *buf;
152162306a36Sopenharmony_ci	const struct firmware *fw;
152262306a36Sopenharmony_ci	const u8 *base_addr;
152362306a36Sopenharmony_ci	int i, ret;
152462306a36Sopenharmony_ci
152562306a36Sopenharmony_ci	ret = request_firmware(&fw, name, dev->mt76.dev);
152662306a36Sopenharmony_ci	if (ret)
152762306a36Sopenharmony_ci		return ret;
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_ci	if (!fw || !fw->data || fw->size < FW_V3_COMMON_TAILER_SIZE) {
153062306a36Sopenharmony_ci		dev_err(dev->mt76.dev, "Invalid firmware\n");
153162306a36Sopenharmony_ci		ret = -EINVAL;
153262306a36Sopenharmony_ci		goto out;
153362306a36Sopenharmony_ci	}
153462306a36Sopenharmony_ci
153562306a36Sopenharmony_ci	hdr = (const void *)(fw->data + fw->size - FW_V3_COMMON_TAILER_SIZE);
153662306a36Sopenharmony_ci	dev_info(dev->mt76.dev, "N9 Firmware Version: %.10s, Build Time: %.15s\n",
153762306a36Sopenharmony_ci		 hdr->fw_ver, hdr->build_date);
153862306a36Sopenharmony_ci	dev_info(dev->mt76.dev, "Region number: 0x%x\n", hdr->n_region);
153962306a36Sopenharmony_ci
154062306a36Sopenharmony_ci	base_addr = fw->data + fw->size - FW_V3_COMMON_TAILER_SIZE;
154162306a36Sopenharmony_ci	for (i = 0; i < hdr->n_region; i++) {
154262306a36Sopenharmony_ci		u32 shift = (hdr->n_region - i) * FW_V3_REGION_TAILER_SIZE;
154362306a36Sopenharmony_ci		u32 len, addr, mode;
154462306a36Sopenharmony_ci
154562306a36Sopenharmony_ci		dev_info(dev->mt76.dev, "Parsing tailer Region: %d\n", i);
154662306a36Sopenharmony_ci
154762306a36Sopenharmony_ci		buf = (const struct mt7663_fw_buf *)(base_addr - shift);
154862306a36Sopenharmony_ci		mode = mt76_connac_mcu_gen_dl_mode(&dev->mt76,
154962306a36Sopenharmony_ci						   buf->feature_set, false);
155062306a36Sopenharmony_ci		addr = le32_to_cpu(buf->img_dest_addr);
155162306a36Sopenharmony_ci		len = le32_to_cpu(buf->img_size);
155262306a36Sopenharmony_ci
155362306a36Sopenharmony_ci		ret = mt76_connac_mcu_init_download(&dev->mt76, addr, len,
155462306a36Sopenharmony_ci						    mode);
155562306a36Sopenharmony_ci		if (ret) {
155662306a36Sopenharmony_ci			dev_err(dev->mt76.dev, "Download request failed\n");
155762306a36Sopenharmony_ci			goto out;
155862306a36Sopenharmony_ci		}
155962306a36Sopenharmony_ci
156062306a36Sopenharmony_ci		ret = mt76_mcu_send_firmware(&dev->mt76, MCU_CMD(FW_SCATTER),
156162306a36Sopenharmony_ci					     fw->data + offset, len);
156262306a36Sopenharmony_ci		if (ret) {
156362306a36Sopenharmony_ci			dev_err(dev->mt76.dev, "Failed to send firmware\n");
156462306a36Sopenharmony_ci			goto out;
156562306a36Sopenharmony_ci		}
156662306a36Sopenharmony_ci
156762306a36Sopenharmony_ci		offset += le32_to_cpu(buf->img_size);
156862306a36Sopenharmony_ci		if (buf->feature_set & DL_MODE_VALID_RAM_ENTRY) {
156962306a36Sopenharmony_ci			override_addr = le32_to_cpu(buf->img_dest_addr);
157062306a36Sopenharmony_ci			dev_info(dev->mt76.dev, "Region %d, override_addr = 0x%08x\n",
157162306a36Sopenharmony_ci				 i, override_addr);
157262306a36Sopenharmony_ci		}
157362306a36Sopenharmony_ci	}
157462306a36Sopenharmony_ci
157562306a36Sopenharmony_ci	if (override_addr)
157662306a36Sopenharmony_ci		flag |= FW_START_OVERRIDE;
157762306a36Sopenharmony_ci
157862306a36Sopenharmony_ci	dev_info(dev->mt76.dev, "override_addr = 0x%08x, option = %d\n",
157962306a36Sopenharmony_ci		 override_addr, flag);
158062306a36Sopenharmony_ci
158162306a36Sopenharmony_ci	ret = mt76_connac_mcu_start_firmware(&dev->mt76, override_addr, flag);
158262306a36Sopenharmony_ci	if (ret) {
158362306a36Sopenharmony_ci		dev_err(dev->mt76.dev, "Failed to start N9 firmware\n");
158462306a36Sopenharmony_ci		goto out;
158562306a36Sopenharmony_ci	}
158662306a36Sopenharmony_ci
158762306a36Sopenharmony_ci	snprintf(dev->mt76.hw->wiphy->fw_version,
158862306a36Sopenharmony_ci		 sizeof(dev->mt76.hw->wiphy->fw_version),
158962306a36Sopenharmony_ci		 "%.10s-%.15s", hdr->fw_ver, hdr->build_date);
159062306a36Sopenharmony_ci
159162306a36Sopenharmony_ciout:
159262306a36Sopenharmony_ci	release_firmware(fw);
159362306a36Sopenharmony_ci
159462306a36Sopenharmony_ci	return ret;
159562306a36Sopenharmony_ci}
159662306a36Sopenharmony_ci
159762306a36Sopenharmony_cistatic int
159862306a36Sopenharmony_cimt7663_load_rom_patch(struct mt7615_dev *dev, const char **n9_firmware)
159962306a36Sopenharmony_ci{
160062306a36Sopenharmony_ci	const char *selected_rom, *secondary_rom = MT7663_ROM_PATCH;
160162306a36Sopenharmony_ci	const char *primary_rom = MT7663_OFFLOAD_ROM_PATCH;
160262306a36Sopenharmony_ci	int ret;
160362306a36Sopenharmony_ci
160462306a36Sopenharmony_ci	if (!prefer_offload_fw) {
160562306a36Sopenharmony_ci		secondary_rom = MT7663_OFFLOAD_ROM_PATCH;
160662306a36Sopenharmony_ci		primary_rom = MT7663_ROM_PATCH;
160762306a36Sopenharmony_ci	}
160862306a36Sopenharmony_ci	selected_rom = primary_rom;
160962306a36Sopenharmony_ci
161062306a36Sopenharmony_ci	ret = mt7615_load_patch(dev, MT7663_PATCH_ADDRESS, primary_rom);
161162306a36Sopenharmony_ci	if (ret) {
161262306a36Sopenharmony_ci		dev_info(dev->mt76.dev, "%s not found, switching to %s",
161362306a36Sopenharmony_ci			 primary_rom, secondary_rom);
161462306a36Sopenharmony_ci		ret = mt7615_load_patch(dev, MT7663_PATCH_ADDRESS,
161562306a36Sopenharmony_ci					secondary_rom);
161662306a36Sopenharmony_ci		if (ret) {
161762306a36Sopenharmony_ci			dev_err(dev->mt76.dev, "failed to load %s",
161862306a36Sopenharmony_ci				secondary_rom);
161962306a36Sopenharmony_ci			return ret;
162062306a36Sopenharmony_ci		}
162162306a36Sopenharmony_ci		selected_rom = secondary_rom;
162262306a36Sopenharmony_ci	}
162362306a36Sopenharmony_ci
162462306a36Sopenharmony_ci	if (!strcmp(selected_rom, MT7663_OFFLOAD_ROM_PATCH)) {
162562306a36Sopenharmony_ci		*n9_firmware = MT7663_OFFLOAD_FIRMWARE_N9;
162662306a36Sopenharmony_ci		dev->fw_ver = MT7615_FIRMWARE_V3;
162762306a36Sopenharmony_ci		dev->mcu_ops = &uni_update_ops;
162862306a36Sopenharmony_ci	} else {
162962306a36Sopenharmony_ci		*n9_firmware = MT7663_FIRMWARE_N9;
163062306a36Sopenharmony_ci		dev->fw_ver = MT7615_FIRMWARE_V2;
163162306a36Sopenharmony_ci		dev->mcu_ops = &sta_update_ops;
163262306a36Sopenharmony_ci	}
163362306a36Sopenharmony_ci
163462306a36Sopenharmony_ci	return 0;
163562306a36Sopenharmony_ci}
163662306a36Sopenharmony_ci
163762306a36Sopenharmony_ciint __mt7663_load_firmware(struct mt7615_dev *dev)
163862306a36Sopenharmony_ci{
163962306a36Sopenharmony_ci	const char *n9_firmware;
164062306a36Sopenharmony_ci	int ret;
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_ci	ret = mt76_get_field(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY);
164362306a36Sopenharmony_ci	if (ret) {
164462306a36Sopenharmony_ci		dev_dbg(dev->mt76.dev, "Firmware is already download\n");
164562306a36Sopenharmony_ci		return -EIO;
164662306a36Sopenharmony_ci	}
164762306a36Sopenharmony_ci
164862306a36Sopenharmony_ci	ret = mt7663_load_rom_patch(dev, &n9_firmware);
164962306a36Sopenharmony_ci	if (ret)
165062306a36Sopenharmony_ci		return ret;
165162306a36Sopenharmony_ci
165262306a36Sopenharmony_ci	ret = mt7663_load_n9(dev, n9_firmware);
165362306a36Sopenharmony_ci	if (ret)
165462306a36Sopenharmony_ci		return ret;
165562306a36Sopenharmony_ci
165662306a36Sopenharmony_ci	if (!mt76_poll_msec(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY,
165762306a36Sopenharmony_ci			    MT_TOP_MISC2_FW_N9_RDY, 1500)) {
165862306a36Sopenharmony_ci		ret = mt76_get_field(dev, MT_CONN_ON_MISC,
165962306a36Sopenharmony_ci				     MT7663_TOP_MISC2_FW_STATE);
166062306a36Sopenharmony_ci		dev_err(dev->mt76.dev, "Timeout for initializing firmware\n");
166162306a36Sopenharmony_ci		return -EIO;
166262306a36Sopenharmony_ci	}
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_ci#ifdef CONFIG_PM
166562306a36Sopenharmony_ci	if (mt7615_firmware_offload(dev))
166662306a36Sopenharmony_ci		dev->mt76.hw->wiphy->wowlan = &mt76_connac_wowlan_support;
166762306a36Sopenharmony_ci#endif /* CONFIG_PM */
166862306a36Sopenharmony_ci
166962306a36Sopenharmony_ci	dev_dbg(dev->mt76.dev, "Firmware init done\n");
167062306a36Sopenharmony_ci
167162306a36Sopenharmony_ci	return 0;
167262306a36Sopenharmony_ci}
167362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(__mt7663_load_firmware);
167462306a36Sopenharmony_ci
167562306a36Sopenharmony_cistatic int mt7663_load_firmware(struct mt7615_dev *dev)
167662306a36Sopenharmony_ci{
167762306a36Sopenharmony_ci	int ret;
167862306a36Sopenharmony_ci
167962306a36Sopenharmony_ci	mt76_set(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_BYPASS_TX_SCH);
168062306a36Sopenharmony_ci
168162306a36Sopenharmony_ci	ret = __mt7663_load_firmware(dev);
168262306a36Sopenharmony_ci	if (ret)
168362306a36Sopenharmony_ci		return ret;
168462306a36Sopenharmony_ci
168562306a36Sopenharmony_ci	mt76_clear(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_BYPASS_TX_SCH);
168662306a36Sopenharmony_ci
168762306a36Sopenharmony_ci	return 0;
168862306a36Sopenharmony_ci}
168962306a36Sopenharmony_ci
169062306a36Sopenharmony_ciint mt7615_mcu_init(struct mt7615_dev *dev)
169162306a36Sopenharmony_ci{
169262306a36Sopenharmony_ci	static const struct mt76_mcu_ops mt7615_mcu_ops = {
169362306a36Sopenharmony_ci		.headroom = sizeof(struct mt7615_mcu_txd),
169462306a36Sopenharmony_ci		.mcu_skb_send_msg = mt7615_mcu_send_message,
169562306a36Sopenharmony_ci		.mcu_parse_response = mt7615_mcu_parse_response,
169662306a36Sopenharmony_ci	};
169762306a36Sopenharmony_ci	int ret;
169862306a36Sopenharmony_ci
169962306a36Sopenharmony_ci	dev->mt76.mcu_ops = &mt7615_mcu_ops,
170062306a36Sopenharmony_ci
170162306a36Sopenharmony_ci	ret = mt7615_mcu_drv_pmctrl(dev);
170262306a36Sopenharmony_ci	if (ret)
170362306a36Sopenharmony_ci		return ret;
170462306a36Sopenharmony_ci
170562306a36Sopenharmony_ci	switch (mt76_chip(&dev->mt76)) {
170662306a36Sopenharmony_ci	case 0x7622:
170762306a36Sopenharmony_ci		ret = mt7622_load_firmware(dev);
170862306a36Sopenharmony_ci		break;
170962306a36Sopenharmony_ci	case 0x7663:
171062306a36Sopenharmony_ci		ret = mt7663_load_firmware(dev);
171162306a36Sopenharmony_ci		break;
171262306a36Sopenharmony_ci	default:
171362306a36Sopenharmony_ci		ret = mt7615_load_firmware(dev);
171462306a36Sopenharmony_ci		break;
171562306a36Sopenharmony_ci	}
171662306a36Sopenharmony_ci	if (ret)
171762306a36Sopenharmony_ci		return ret;
171862306a36Sopenharmony_ci
171962306a36Sopenharmony_ci	mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_FWDL], false);
172062306a36Sopenharmony_ci	dev_dbg(dev->mt76.dev, "Firmware init done\n");
172162306a36Sopenharmony_ci	set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);
172262306a36Sopenharmony_ci
172362306a36Sopenharmony_ci	if (dev->dbdc_support) {
172462306a36Sopenharmony_ci		ret = mt7615_mcu_cal_cache_apply(dev);
172562306a36Sopenharmony_ci		if (ret)
172662306a36Sopenharmony_ci			return ret;
172762306a36Sopenharmony_ci	}
172862306a36Sopenharmony_ci
172962306a36Sopenharmony_ci	return mt7615_mcu_fw_log_2_host(dev, 0);
173062306a36Sopenharmony_ci}
173162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mt7615_mcu_init);
173262306a36Sopenharmony_ci
173362306a36Sopenharmony_civoid mt7615_mcu_exit(struct mt7615_dev *dev)
173462306a36Sopenharmony_ci{
173562306a36Sopenharmony_ci	mt7615_mcu_restart(&dev->mt76);
173662306a36Sopenharmony_ci	mt7615_mcu_set_fw_ctrl(dev);
173762306a36Sopenharmony_ci	skb_queue_purge(&dev->mt76.mcu.res_q);
173862306a36Sopenharmony_ci}
173962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mt7615_mcu_exit);
174062306a36Sopenharmony_ci
174162306a36Sopenharmony_ciint mt7615_mcu_set_eeprom(struct mt7615_dev *dev)
174262306a36Sopenharmony_ci{
174362306a36Sopenharmony_ci	struct {
174462306a36Sopenharmony_ci		u8 buffer_mode;
174562306a36Sopenharmony_ci		u8 content_format;
174662306a36Sopenharmony_ci		__le16 len;
174762306a36Sopenharmony_ci	} __packed req_hdr = {
174862306a36Sopenharmony_ci		.buffer_mode = 1,
174962306a36Sopenharmony_ci	};
175062306a36Sopenharmony_ci	u8 *eep = (u8 *)dev->mt76.eeprom.data;
175162306a36Sopenharmony_ci	struct sk_buff *skb;
175262306a36Sopenharmony_ci	int eep_len, offset;
175362306a36Sopenharmony_ci
175462306a36Sopenharmony_ci	switch (mt76_chip(&dev->mt76)) {
175562306a36Sopenharmony_ci	case 0x7622:
175662306a36Sopenharmony_ci		eep_len = MT7622_EE_MAX - MT_EE_NIC_CONF_0;
175762306a36Sopenharmony_ci		offset = MT_EE_NIC_CONF_0;
175862306a36Sopenharmony_ci		break;
175962306a36Sopenharmony_ci	case 0x7663:
176062306a36Sopenharmony_ci		eep_len = MT7663_EE_MAX - MT_EE_CHIP_ID;
176162306a36Sopenharmony_ci		req_hdr.content_format = 1;
176262306a36Sopenharmony_ci		offset = MT_EE_CHIP_ID;
176362306a36Sopenharmony_ci		break;
176462306a36Sopenharmony_ci	default:
176562306a36Sopenharmony_ci		eep_len = MT7615_EE_MAX - MT_EE_NIC_CONF_0;
176662306a36Sopenharmony_ci		offset = MT_EE_NIC_CONF_0;
176762306a36Sopenharmony_ci		break;
176862306a36Sopenharmony_ci	}
176962306a36Sopenharmony_ci
177062306a36Sopenharmony_ci	req_hdr.len = cpu_to_le16(eep_len);
177162306a36Sopenharmony_ci
177262306a36Sopenharmony_ci	skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, sizeof(req_hdr) + eep_len);
177362306a36Sopenharmony_ci	if (!skb)
177462306a36Sopenharmony_ci		return -ENOMEM;
177562306a36Sopenharmony_ci
177662306a36Sopenharmony_ci	skb_put_data(skb, &req_hdr, sizeof(req_hdr));
177762306a36Sopenharmony_ci	skb_put_data(skb, eep + offset, eep_len);
177862306a36Sopenharmony_ci
177962306a36Sopenharmony_ci	return mt76_mcu_skb_send_msg(&dev->mt76, skb,
178062306a36Sopenharmony_ci				     MCU_EXT_CMD(EFUSE_BUFFER_MODE), true);
178162306a36Sopenharmony_ci}
178262306a36Sopenharmony_ci
178362306a36Sopenharmony_ciint mt7615_mcu_set_wmm(struct mt7615_dev *dev, u8 queue,
178462306a36Sopenharmony_ci		       const struct ieee80211_tx_queue_params *params)
178562306a36Sopenharmony_ci{
178662306a36Sopenharmony_ci#define WMM_AIFS_SET	BIT(0)
178762306a36Sopenharmony_ci#define WMM_CW_MIN_SET	BIT(1)
178862306a36Sopenharmony_ci#define WMM_CW_MAX_SET	BIT(2)
178962306a36Sopenharmony_ci#define WMM_TXOP_SET	BIT(3)
179062306a36Sopenharmony_ci#define WMM_PARAM_SET	(WMM_AIFS_SET | WMM_CW_MIN_SET | \
179162306a36Sopenharmony_ci			 WMM_CW_MAX_SET | WMM_TXOP_SET)
179262306a36Sopenharmony_ci	struct req_data {
179362306a36Sopenharmony_ci		u8 number;
179462306a36Sopenharmony_ci		u8 rsv[3];
179562306a36Sopenharmony_ci		u8 queue;
179662306a36Sopenharmony_ci		u8 valid;
179762306a36Sopenharmony_ci		u8 aifs;
179862306a36Sopenharmony_ci		u8 cw_min;
179962306a36Sopenharmony_ci		__le16 cw_max;
180062306a36Sopenharmony_ci		__le16 txop;
180162306a36Sopenharmony_ci	} __packed req = {
180262306a36Sopenharmony_ci		.number = 1,
180362306a36Sopenharmony_ci		.queue = queue,
180462306a36Sopenharmony_ci		.valid = WMM_PARAM_SET,
180562306a36Sopenharmony_ci		.aifs = params->aifs,
180662306a36Sopenharmony_ci		.cw_min = 5,
180762306a36Sopenharmony_ci		.cw_max = cpu_to_le16(10),
180862306a36Sopenharmony_ci		.txop = cpu_to_le16(params->txop),
180962306a36Sopenharmony_ci	};
181062306a36Sopenharmony_ci
181162306a36Sopenharmony_ci	if (params->cw_min)
181262306a36Sopenharmony_ci		req.cw_min = fls(params->cw_min);
181362306a36Sopenharmony_ci	if (params->cw_max)
181462306a36Sopenharmony_ci		req.cw_max = cpu_to_le16(fls(params->cw_max));
181562306a36Sopenharmony_ci
181662306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(EDCA_UPDATE),
181762306a36Sopenharmony_ci				 &req, sizeof(req), true);
181862306a36Sopenharmony_ci}
181962306a36Sopenharmony_ci
182062306a36Sopenharmony_ciint mt7615_mcu_set_dbdc(struct mt7615_dev *dev)
182162306a36Sopenharmony_ci{
182262306a36Sopenharmony_ci	struct mt7615_phy *ext_phy = mt7615_ext_phy(dev);
182362306a36Sopenharmony_ci	struct dbdc_entry {
182462306a36Sopenharmony_ci		u8 type;
182562306a36Sopenharmony_ci		u8 index;
182662306a36Sopenharmony_ci		u8 band;
182762306a36Sopenharmony_ci		u8 _rsv;
182862306a36Sopenharmony_ci	};
182962306a36Sopenharmony_ci	struct {
183062306a36Sopenharmony_ci		u8 enable;
183162306a36Sopenharmony_ci		u8 num;
183262306a36Sopenharmony_ci		u8 _rsv[2];
183362306a36Sopenharmony_ci		struct dbdc_entry entry[64];
183462306a36Sopenharmony_ci	} req = {
183562306a36Sopenharmony_ci		.enable = !!ext_phy,
183662306a36Sopenharmony_ci	};
183762306a36Sopenharmony_ci	int i;
183862306a36Sopenharmony_ci
183962306a36Sopenharmony_ci	if (!ext_phy)
184062306a36Sopenharmony_ci		goto out;
184162306a36Sopenharmony_ci
184262306a36Sopenharmony_ci#define ADD_DBDC_ENTRY(_type, _idx, _band)		\
184362306a36Sopenharmony_ci	do { \
184462306a36Sopenharmony_ci		req.entry[req.num].type = _type;		\
184562306a36Sopenharmony_ci		req.entry[req.num].index = _idx;		\
184662306a36Sopenharmony_ci		req.entry[req.num++].band = _band;		\
184762306a36Sopenharmony_ci	} while (0)
184862306a36Sopenharmony_ci
184962306a36Sopenharmony_ci	for (i = 0; i < 4; i++) {
185062306a36Sopenharmony_ci		bool band = !!(ext_phy->omac_mask & BIT_ULL(i));
185162306a36Sopenharmony_ci
185262306a36Sopenharmony_ci		ADD_DBDC_ENTRY(DBDC_TYPE_BSS, i, band);
185362306a36Sopenharmony_ci	}
185462306a36Sopenharmony_ci
185562306a36Sopenharmony_ci	for (i = 0; i < 14; i++) {
185662306a36Sopenharmony_ci		bool band = !!(ext_phy->omac_mask & BIT_ULL(0x11 + i));
185762306a36Sopenharmony_ci
185862306a36Sopenharmony_ci		ADD_DBDC_ENTRY(DBDC_TYPE_MBSS, i, band);
185962306a36Sopenharmony_ci	}
186062306a36Sopenharmony_ci
186162306a36Sopenharmony_ci	ADD_DBDC_ENTRY(DBDC_TYPE_MU, 0, 1);
186262306a36Sopenharmony_ci
186362306a36Sopenharmony_ci	for (i = 0; i < 3; i++)
186462306a36Sopenharmony_ci		ADD_DBDC_ENTRY(DBDC_TYPE_BF, i, 1);
186562306a36Sopenharmony_ci
186662306a36Sopenharmony_ci	ADD_DBDC_ENTRY(DBDC_TYPE_WMM, 0, 0);
186762306a36Sopenharmony_ci	ADD_DBDC_ENTRY(DBDC_TYPE_WMM, 1, 0);
186862306a36Sopenharmony_ci	ADD_DBDC_ENTRY(DBDC_TYPE_WMM, 2, 1);
186962306a36Sopenharmony_ci	ADD_DBDC_ENTRY(DBDC_TYPE_WMM, 3, 1);
187062306a36Sopenharmony_ci
187162306a36Sopenharmony_ci	ADD_DBDC_ENTRY(DBDC_TYPE_MGMT, 0, 0);
187262306a36Sopenharmony_ci	ADD_DBDC_ENTRY(DBDC_TYPE_MGMT, 1, 1);
187362306a36Sopenharmony_ci
187462306a36Sopenharmony_ciout:
187562306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(DBDC_CTRL), &req,
187662306a36Sopenharmony_ci				 sizeof(req), true);
187762306a36Sopenharmony_ci}
187862306a36Sopenharmony_ci
187962306a36Sopenharmony_ciint mt7615_mcu_del_wtbl_all(struct mt7615_dev *dev)
188062306a36Sopenharmony_ci{
188162306a36Sopenharmony_ci	struct wtbl_req_hdr req = {
188262306a36Sopenharmony_ci		.operation = WTBL_RESET_ALL,
188362306a36Sopenharmony_ci	};
188462306a36Sopenharmony_ci
188562306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(WTBL_UPDATE),
188662306a36Sopenharmony_ci				 &req, sizeof(req), true);
188762306a36Sopenharmony_ci}
188862306a36Sopenharmony_ci
188962306a36Sopenharmony_ciint mt7615_mcu_set_fcc5_lpn(struct mt7615_dev *dev, int val)
189062306a36Sopenharmony_ci{
189162306a36Sopenharmony_ci	struct {
189262306a36Sopenharmony_ci		__le16 tag;
189362306a36Sopenharmony_ci		__le16 min_lpn;
189462306a36Sopenharmony_ci	} req = {
189562306a36Sopenharmony_ci		.tag = cpu_to_le16(0x1),
189662306a36Sopenharmony_ci		.min_lpn = cpu_to_le16(val),
189762306a36Sopenharmony_ci	};
189862306a36Sopenharmony_ci
189962306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_RADAR_TH),
190062306a36Sopenharmony_ci				 &req, sizeof(req), true);
190162306a36Sopenharmony_ci}
190262306a36Sopenharmony_ci
190362306a36Sopenharmony_ciint mt7615_mcu_set_pulse_th(struct mt7615_dev *dev,
190462306a36Sopenharmony_ci			    const struct mt7615_dfs_pulse *pulse)
190562306a36Sopenharmony_ci{
190662306a36Sopenharmony_ci	struct {
190762306a36Sopenharmony_ci		__le16 tag;
190862306a36Sopenharmony_ci		__le32 max_width;	/* us */
190962306a36Sopenharmony_ci		__le32 max_pwr;		/* dbm */
191062306a36Sopenharmony_ci		__le32 min_pwr;		/* dbm */
191162306a36Sopenharmony_ci		__le32 min_stgr_pri;	/* us */
191262306a36Sopenharmony_ci		__le32 max_stgr_pri;	/* us */
191362306a36Sopenharmony_ci		__le32 min_cr_pri;	/* us */
191462306a36Sopenharmony_ci		__le32 max_cr_pri;	/* us */
191562306a36Sopenharmony_ci	} req = {
191662306a36Sopenharmony_ci		.tag = cpu_to_le16(0x3),
191762306a36Sopenharmony_ci#define __req_field(field) .field = cpu_to_le32(pulse->field)
191862306a36Sopenharmony_ci		__req_field(max_width),
191962306a36Sopenharmony_ci		__req_field(max_pwr),
192062306a36Sopenharmony_ci		__req_field(min_pwr),
192162306a36Sopenharmony_ci		__req_field(min_stgr_pri),
192262306a36Sopenharmony_ci		__req_field(max_stgr_pri),
192362306a36Sopenharmony_ci		__req_field(min_cr_pri),
192462306a36Sopenharmony_ci		__req_field(max_cr_pri),
192562306a36Sopenharmony_ci#undef  __req_field
192662306a36Sopenharmony_ci	};
192762306a36Sopenharmony_ci
192862306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_RADAR_TH),
192962306a36Sopenharmony_ci				 &req, sizeof(req), true);
193062306a36Sopenharmony_ci}
193162306a36Sopenharmony_ci
193262306a36Sopenharmony_ciint mt7615_mcu_set_radar_th(struct mt7615_dev *dev, int index,
193362306a36Sopenharmony_ci			    const struct mt7615_dfs_pattern *pattern)
193462306a36Sopenharmony_ci{
193562306a36Sopenharmony_ci	struct {
193662306a36Sopenharmony_ci		__le16 tag;
193762306a36Sopenharmony_ci		__le16 radar_type;
193862306a36Sopenharmony_ci		u8 enb;
193962306a36Sopenharmony_ci		u8 stgr;
194062306a36Sopenharmony_ci		u8 min_crpn;
194162306a36Sopenharmony_ci		u8 max_crpn;
194262306a36Sopenharmony_ci		u8 min_crpr;
194362306a36Sopenharmony_ci		u8 min_pw;
194462306a36Sopenharmony_ci		u8 max_pw;
194562306a36Sopenharmony_ci		__le32 min_pri;
194662306a36Sopenharmony_ci		__le32 max_pri;
194762306a36Sopenharmony_ci		u8 min_crbn;
194862306a36Sopenharmony_ci		u8 max_crbn;
194962306a36Sopenharmony_ci		u8 min_stgpn;
195062306a36Sopenharmony_ci		u8 max_stgpn;
195162306a36Sopenharmony_ci		u8 min_stgpr;
195262306a36Sopenharmony_ci	} req = {
195362306a36Sopenharmony_ci		.tag = cpu_to_le16(0x2),
195462306a36Sopenharmony_ci		.radar_type = cpu_to_le16(index),
195562306a36Sopenharmony_ci#define __req_field_u8(field) .field = pattern->field
195662306a36Sopenharmony_ci#define __req_field_u32(field) .field = cpu_to_le32(pattern->field)
195762306a36Sopenharmony_ci		__req_field_u8(enb),
195862306a36Sopenharmony_ci		__req_field_u8(stgr),
195962306a36Sopenharmony_ci		__req_field_u8(min_crpn),
196062306a36Sopenharmony_ci		__req_field_u8(max_crpn),
196162306a36Sopenharmony_ci		__req_field_u8(min_crpr),
196262306a36Sopenharmony_ci		__req_field_u8(min_pw),
196362306a36Sopenharmony_ci		__req_field_u8(max_pw),
196462306a36Sopenharmony_ci		__req_field_u32(min_pri),
196562306a36Sopenharmony_ci		__req_field_u32(max_pri),
196662306a36Sopenharmony_ci		__req_field_u8(min_crbn),
196762306a36Sopenharmony_ci		__req_field_u8(max_crbn),
196862306a36Sopenharmony_ci		__req_field_u8(min_stgpn),
196962306a36Sopenharmony_ci		__req_field_u8(max_stgpn),
197062306a36Sopenharmony_ci		__req_field_u8(min_stgpr),
197162306a36Sopenharmony_ci#undef __req_field_u8
197262306a36Sopenharmony_ci#undef __req_field_u32
197362306a36Sopenharmony_ci	};
197462306a36Sopenharmony_ci
197562306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_RADAR_TH),
197662306a36Sopenharmony_ci				 &req, sizeof(req), true);
197762306a36Sopenharmony_ci}
197862306a36Sopenharmony_ci
197962306a36Sopenharmony_ciint mt7615_mcu_rdd_send_pattern(struct mt7615_dev *dev)
198062306a36Sopenharmony_ci{
198162306a36Sopenharmony_ci	struct {
198262306a36Sopenharmony_ci		u8 pulse_num;
198362306a36Sopenharmony_ci		u8 rsv[3];
198462306a36Sopenharmony_ci		struct {
198562306a36Sopenharmony_ci			__le32 start_time;
198662306a36Sopenharmony_ci			__le16 width;
198762306a36Sopenharmony_ci			__le16 power;
198862306a36Sopenharmony_ci		} pattern[32];
198962306a36Sopenharmony_ci	} req = {
199062306a36Sopenharmony_ci		.pulse_num = dev->radar_pattern.n_pulses,
199162306a36Sopenharmony_ci	};
199262306a36Sopenharmony_ci	u32 start_time = ktime_to_ms(ktime_get_boottime());
199362306a36Sopenharmony_ci	int i;
199462306a36Sopenharmony_ci
199562306a36Sopenharmony_ci	if (dev->radar_pattern.n_pulses > ARRAY_SIZE(req.pattern))
199662306a36Sopenharmony_ci		return -EINVAL;
199762306a36Sopenharmony_ci
199862306a36Sopenharmony_ci	/* TODO: add some noise here */
199962306a36Sopenharmony_ci	for (i = 0; i < dev->radar_pattern.n_pulses; i++) {
200062306a36Sopenharmony_ci		u32 ts = start_time + i * dev->radar_pattern.period;
200162306a36Sopenharmony_ci
200262306a36Sopenharmony_ci		req.pattern[i].width = cpu_to_le16(dev->radar_pattern.width);
200362306a36Sopenharmony_ci		req.pattern[i].power = cpu_to_le16(dev->radar_pattern.power);
200462306a36Sopenharmony_ci		req.pattern[i].start_time = cpu_to_le32(ts);
200562306a36Sopenharmony_ci	}
200662306a36Sopenharmony_ci
200762306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_RDD_PATTERN),
200862306a36Sopenharmony_ci				 &req, sizeof(req), false);
200962306a36Sopenharmony_ci}
201062306a36Sopenharmony_ci
201162306a36Sopenharmony_cistatic void mt7615_mcu_set_txpower_sku(struct mt7615_phy *phy, u8 *sku)
201262306a36Sopenharmony_ci{
201362306a36Sopenharmony_ci	struct mt76_phy *mphy = phy->mt76;
201462306a36Sopenharmony_ci	struct ieee80211_hw *hw = mphy->hw;
201562306a36Sopenharmony_ci	struct mt76_power_limits limits;
201662306a36Sopenharmony_ci	s8 *limits_array = (s8 *)&limits;
201762306a36Sopenharmony_ci	int n_chains = hweight8(mphy->antenna_mask);
201862306a36Sopenharmony_ci	int tx_power = hw->conf.power_level * 2;
201962306a36Sopenharmony_ci	int i;
202062306a36Sopenharmony_ci	static const u8 sku_mapping[] = {
202162306a36Sopenharmony_ci#define SKU_FIELD(_type, _field) \
202262306a36Sopenharmony_ci		[MT_SKU_##_type] = offsetof(struct mt76_power_limits, _field)
202362306a36Sopenharmony_ci		SKU_FIELD(CCK_1_2, cck[0]),
202462306a36Sopenharmony_ci		SKU_FIELD(CCK_55_11, cck[2]),
202562306a36Sopenharmony_ci		SKU_FIELD(OFDM_6_9, ofdm[0]),
202662306a36Sopenharmony_ci		SKU_FIELD(OFDM_12_18, ofdm[2]),
202762306a36Sopenharmony_ci		SKU_FIELD(OFDM_24_36, ofdm[4]),
202862306a36Sopenharmony_ci		SKU_FIELD(OFDM_48, ofdm[6]),
202962306a36Sopenharmony_ci		SKU_FIELD(OFDM_54, ofdm[7]),
203062306a36Sopenharmony_ci		SKU_FIELD(HT20_0_8, mcs[0][0]),
203162306a36Sopenharmony_ci		SKU_FIELD(HT20_32, ofdm[0]),
203262306a36Sopenharmony_ci		SKU_FIELD(HT20_1_2_9_10, mcs[0][1]),
203362306a36Sopenharmony_ci		SKU_FIELD(HT20_3_4_11_12, mcs[0][3]),
203462306a36Sopenharmony_ci		SKU_FIELD(HT20_5_13, mcs[0][5]),
203562306a36Sopenharmony_ci		SKU_FIELD(HT20_6_14, mcs[0][6]),
203662306a36Sopenharmony_ci		SKU_FIELD(HT20_7_15, mcs[0][7]),
203762306a36Sopenharmony_ci		SKU_FIELD(HT40_0_8, mcs[1][0]),
203862306a36Sopenharmony_ci		SKU_FIELD(HT40_32, ofdm[0]),
203962306a36Sopenharmony_ci		SKU_FIELD(HT40_1_2_9_10, mcs[1][1]),
204062306a36Sopenharmony_ci		SKU_FIELD(HT40_3_4_11_12, mcs[1][3]),
204162306a36Sopenharmony_ci		SKU_FIELD(HT40_5_13, mcs[1][5]),
204262306a36Sopenharmony_ci		SKU_FIELD(HT40_6_14, mcs[1][6]),
204362306a36Sopenharmony_ci		SKU_FIELD(HT40_7_15, mcs[1][7]),
204462306a36Sopenharmony_ci		SKU_FIELD(VHT20_0, mcs[0][0]),
204562306a36Sopenharmony_ci		SKU_FIELD(VHT20_1_2, mcs[0][1]),
204662306a36Sopenharmony_ci		SKU_FIELD(VHT20_3_4, mcs[0][3]),
204762306a36Sopenharmony_ci		SKU_FIELD(VHT20_5_6, mcs[0][5]),
204862306a36Sopenharmony_ci		SKU_FIELD(VHT20_7, mcs[0][7]),
204962306a36Sopenharmony_ci		SKU_FIELD(VHT20_8, mcs[0][8]),
205062306a36Sopenharmony_ci		SKU_FIELD(VHT20_9, mcs[0][9]),
205162306a36Sopenharmony_ci		SKU_FIELD(VHT40_0, mcs[1][0]),
205262306a36Sopenharmony_ci		SKU_FIELD(VHT40_1_2, mcs[1][1]),
205362306a36Sopenharmony_ci		SKU_FIELD(VHT40_3_4, mcs[1][3]),
205462306a36Sopenharmony_ci		SKU_FIELD(VHT40_5_6, mcs[1][5]),
205562306a36Sopenharmony_ci		SKU_FIELD(VHT40_7, mcs[1][7]),
205662306a36Sopenharmony_ci		SKU_FIELD(VHT40_8, mcs[1][8]),
205762306a36Sopenharmony_ci		SKU_FIELD(VHT40_9, mcs[1][9]),
205862306a36Sopenharmony_ci		SKU_FIELD(VHT80_0, mcs[2][0]),
205962306a36Sopenharmony_ci		SKU_FIELD(VHT80_1_2, mcs[2][1]),
206062306a36Sopenharmony_ci		SKU_FIELD(VHT80_3_4, mcs[2][3]),
206162306a36Sopenharmony_ci		SKU_FIELD(VHT80_5_6, mcs[2][5]),
206262306a36Sopenharmony_ci		SKU_FIELD(VHT80_7, mcs[2][7]),
206362306a36Sopenharmony_ci		SKU_FIELD(VHT80_8, mcs[2][8]),
206462306a36Sopenharmony_ci		SKU_FIELD(VHT80_9, mcs[2][9]),
206562306a36Sopenharmony_ci		SKU_FIELD(VHT160_0, mcs[3][0]),
206662306a36Sopenharmony_ci		SKU_FIELD(VHT160_1_2, mcs[3][1]),
206762306a36Sopenharmony_ci		SKU_FIELD(VHT160_3_4, mcs[3][3]),
206862306a36Sopenharmony_ci		SKU_FIELD(VHT160_5_6, mcs[3][5]),
206962306a36Sopenharmony_ci		SKU_FIELD(VHT160_7, mcs[3][7]),
207062306a36Sopenharmony_ci		SKU_FIELD(VHT160_8, mcs[3][8]),
207162306a36Sopenharmony_ci		SKU_FIELD(VHT160_9, mcs[3][9]),
207262306a36Sopenharmony_ci#undef SKU_FIELD
207362306a36Sopenharmony_ci	};
207462306a36Sopenharmony_ci
207562306a36Sopenharmony_ci	tx_power = mt76_get_sar_power(mphy, mphy->chandef.chan, tx_power);
207662306a36Sopenharmony_ci	tx_power -= mt76_tx_power_nss_delta(n_chains);
207762306a36Sopenharmony_ci	tx_power = mt76_get_rate_power_limits(mphy, mphy->chandef.chan,
207862306a36Sopenharmony_ci					      &limits, tx_power);
207962306a36Sopenharmony_ci	mphy->txpower_cur = tx_power;
208062306a36Sopenharmony_ci
208162306a36Sopenharmony_ci	if (is_mt7663(mphy->dev)) {
208262306a36Sopenharmony_ci		memset(sku, tx_power, MT_SKU_4SS_DELTA + 1);
208362306a36Sopenharmony_ci		return;
208462306a36Sopenharmony_ci	}
208562306a36Sopenharmony_ci
208662306a36Sopenharmony_ci	for (i = 0; i < MT_SKU_1SS_DELTA; i++)
208762306a36Sopenharmony_ci		sku[i] = limits_array[sku_mapping[i]];
208862306a36Sopenharmony_ci
208962306a36Sopenharmony_ci	for (i = 0; i < 4; i++) {
209062306a36Sopenharmony_ci		int delta = 0;
209162306a36Sopenharmony_ci
209262306a36Sopenharmony_ci		if (i < n_chains - 1)
209362306a36Sopenharmony_ci			delta = mt76_tx_power_nss_delta(n_chains) -
209462306a36Sopenharmony_ci				mt76_tx_power_nss_delta(i + 1);
209562306a36Sopenharmony_ci		sku[MT_SKU_1SS_DELTA + i] = delta;
209662306a36Sopenharmony_ci	}
209762306a36Sopenharmony_ci}
209862306a36Sopenharmony_ci
209962306a36Sopenharmony_cistatic u8 mt7615_mcu_chan_bw(struct cfg80211_chan_def *chandef)
210062306a36Sopenharmony_ci{
210162306a36Sopenharmony_ci	static const u8 width_to_bw[] = {
210262306a36Sopenharmony_ci		[NL80211_CHAN_WIDTH_40] = CMD_CBW_40MHZ,
210362306a36Sopenharmony_ci		[NL80211_CHAN_WIDTH_80] = CMD_CBW_80MHZ,
210462306a36Sopenharmony_ci		[NL80211_CHAN_WIDTH_80P80] = CMD_CBW_8080MHZ,
210562306a36Sopenharmony_ci		[NL80211_CHAN_WIDTH_160] = CMD_CBW_160MHZ,
210662306a36Sopenharmony_ci		[NL80211_CHAN_WIDTH_5] = CMD_CBW_5MHZ,
210762306a36Sopenharmony_ci		[NL80211_CHAN_WIDTH_10] = CMD_CBW_10MHZ,
210862306a36Sopenharmony_ci		[NL80211_CHAN_WIDTH_20] = CMD_CBW_20MHZ,
210962306a36Sopenharmony_ci		[NL80211_CHAN_WIDTH_20_NOHT] = CMD_CBW_20MHZ,
211062306a36Sopenharmony_ci	};
211162306a36Sopenharmony_ci
211262306a36Sopenharmony_ci	if (chandef->width >= ARRAY_SIZE(width_to_bw))
211362306a36Sopenharmony_ci		return 0;
211462306a36Sopenharmony_ci
211562306a36Sopenharmony_ci	return width_to_bw[chandef->width];
211662306a36Sopenharmony_ci}
211762306a36Sopenharmony_ci
211862306a36Sopenharmony_ciint mt7615_mcu_set_chan_info(struct mt7615_phy *phy, int cmd)
211962306a36Sopenharmony_ci{
212062306a36Sopenharmony_ci	struct mt7615_dev *dev = phy->dev;
212162306a36Sopenharmony_ci	struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
212262306a36Sopenharmony_ci	int freq1 = chandef->center_freq1, freq2 = chandef->center_freq2;
212362306a36Sopenharmony_ci	struct {
212462306a36Sopenharmony_ci		u8 control_chan;
212562306a36Sopenharmony_ci		u8 center_chan;
212662306a36Sopenharmony_ci		u8 bw;
212762306a36Sopenharmony_ci		u8 tx_streams;
212862306a36Sopenharmony_ci		u8 rx_streams_mask;
212962306a36Sopenharmony_ci		u8 switch_reason;
213062306a36Sopenharmony_ci		u8 band_idx;
213162306a36Sopenharmony_ci		/* for 80+80 only */
213262306a36Sopenharmony_ci		u8 center_chan2;
213362306a36Sopenharmony_ci		__le16 cac_case;
213462306a36Sopenharmony_ci		u8 channel_band;
213562306a36Sopenharmony_ci		u8 rsv0;
213662306a36Sopenharmony_ci		__le32 outband_freq;
213762306a36Sopenharmony_ci		u8 txpower_drop;
213862306a36Sopenharmony_ci		u8 rsv1[3];
213962306a36Sopenharmony_ci		u8 txpower_sku[53];
214062306a36Sopenharmony_ci		u8 rsv2[3];
214162306a36Sopenharmony_ci	} req = {
214262306a36Sopenharmony_ci		.control_chan = chandef->chan->hw_value,
214362306a36Sopenharmony_ci		.center_chan = ieee80211_frequency_to_channel(freq1),
214462306a36Sopenharmony_ci		.tx_streams = hweight8(phy->mt76->antenna_mask),
214562306a36Sopenharmony_ci		.rx_streams_mask = phy->mt76->chainmask,
214662306a36Sopenharmony_ci		.center_chan2 = ieee80211_frequency_to_channel(freq2),
214762306a36Sopenharmony_ci	};
214862306a36Sopenharmony_ci
214962306a36Sopenharmony_ci	if (cmd == MCU_EXT_CMD(SET_RX_PATH) ||
215062306a36Sopenharmony_ci	    phy->mt76->hw->conf.flags & IEEE80211_CONF_MONITOR)
215162306a36Sopenharmony_ci		req.switch_reason = CH_SWITCH_NORMAL;
215262306a36Sopenharmony_ci	else if (phy->mt76->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)
215362306a36Sopenharmony_ci		req.switch_reason = CH_SWITCH_SCAN_BYPASS_DPD;
215462306a36Sopenharmony_ci	else if (!cfg80211_reg_can_beacon(phy->mt76->hw->wiphy, chandef,
215562306a36Sopenharmony_ci					  NL80211_IFTYPE_AP))
215662306a36Sopenharmony_ci		req.switch_reason = CH_SWITCH_DFS;
215762306a36Sopenharmony_ci	else
215862306a36Sopenharmony_ci		req.switch_reason = CH_SWITCH_NORMAL;
215962306a36Sopenharmony_ci
216062306a36Sopenharmony_ci	req.band_idx = phy != &dev->phy;
216162306a36Sopenharmony_ci	req.bw = mt7615_mcu_chan_bw(chandef);
216262306a36Sopenharmony_ci
216362306a36Sopenharmony_ci	if (mt76_testmode_enabled(phy->mt76))
216462306a36Sopenharmony_ci		memset(req.txpower_sku, 0x3f, 49);
216562306a36Sopenharmony_ci	else
216662306a36Sopenharmony_ci		mt7615_mcu_set_txpower_sku(phy, req.txpower_sku);
216762306a36Sopenharmony_ci
216862306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), true);
216962306a36Sopenharmony_ci}
217062306a36Sopenharmony_ci
217162306a36Sopenharmony_ciint mt7615_mcu_get_temperature(struct mt7615_dev *dev)
217262306a36Sopenharmony_ci{
217362306a36Sopenharmony_ci	struct {
217462306a36Sopenharmony_ci		u8 action;
217562306a36Sopenharmony_ci		u8 rsv[3];
217662306a36Sopenharmony_ci	} req = {};
217762306a36Sopenharmony_ci
217862306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(THERMAL_CTRL),
217962306a36Sopenharmony_ci				 &req, sizeof(req), true);
218062306a36Sopenharmony_ci}
218162306a36Sopenharmony_ci
218262306a36Sopenharmony_ciint mt7615_mcu_set_test_param(struct mt7615_dev *dev, u8 param, bool test_mode,
218362306a36Sopenharmony_ci			      u32 val)
218462306a36Sopenharmony_ci{
218562306a36Sopenharmony_ci	struct {
218662306a36Sopenharmony_ci		u8 test_mode_en;
218762306a36Sopenharmony_ci		u8 param_idx;
218862306a36Sopenharmony_ci		u8 _rsv[2];
218962306a36Sopenharmony_ci
219062306a36Sopenharmony_ci		__le32 value;
219162306a36Sopenharmony_ci
219262306a36Sopenharmony_ci		u8 pad[8];
219362306a36Sopenharmony_ci	} req = {
219462306a36Sopenharmony_ci		.test_mode_en = test_mode,
219562306a36Sopenharmony_ci		.param_idx = param,
219662306a36Sopenharmony_ci		.value = cpu_to_le32(val),
219762306a36Sopenharmony_ci	};
219862306a36Sopenharmony_ci
219962306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(ATE_CTRL),
220062306a36Sopenharmony_ci				 &req, sizeof(req), false);
220162306a36Sopenharmony_ci}
220262306a36Sopenharmony_ci
220362306a36Sopenharmony_ciint mt7615_mcu_set_sku_en(struct mt7615_phy *phy, bool enable)
220462306a36Sopenharmony_ci{
220562306a36Sopenharmony_ci	struct mt7615_dev *dev = phy->dev;
220662306a36Sopenharmony_ci	struct {
220762306a36Sopenharmony_ci		u8 format_id;
220862306a36Sopenharmony_ci		u8 sku_enable;
220962306a36Sopenharmony_ci		u8 band_idx;
221062306a36Sopenharmony_ci		u8 rsv;
221162306a36Sopenharmony_ci	} req = {
221262306a36Sopenharmony_ci		.format_id = 0,
221362306a36Sopenharmony_ci		.band_idx = phy != &dev->phy,
221462306a36Sopenharmony_ci		.sku_enable = enable,
221562306a36Sopenharmony_ci	};
221662306a36Sopenharmony_ci
221762306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76,
221862306a36Sopenharmony_ci				 MCU_EXT_CMD(TX_POWER_FEATURE_CTRL),
221962306a36Sopenharmony_ci				 &req, sizeof(req), true);
222062306a36Sopenharmony_ci}
222162306a36Sopenharmony_ci
222262306a36Sopenharmony_cistatic int mt7615_find_freq_idx(const u16 *freqs, int n_freqs, u16 cur)
222362306a36Sopenharmony_ci{
222462306a36Sopenharmony_ci	int i;
222562306a36Sopenharmony_ci
222662306a36Sopenharmony_ci	for (i = 0; i < n_freqs; i++)
222762306a36Sopenharmony_ci		if (cur == freqs[i])
222862306a36Sopenharmony_ci			return i;
222962306a36Sopenharmony_ci
223062306a36Sopenharmony_ci	return -1;
223162306a36Sopenharmony_ci}
223262306a36Sopenharmony_ci
223362306a36Sopenharmony_cistatic int mt7615_dcoc_freq_idx(u16 freq, u8 bw)
223462306a36Sopenharmony_ci{
223562306a36Sopenharmony_ci	static const u16 freq_list[] = {
223662306a36Sopenharmony_ci		4980, 5805, 5905, 5190,
223762306a36Sopenharmony_ci		5230, 5270, 5310, 5350,
223862306a36Sopenharmony_ci		5390, 5430, 5470, 5510,
223962306a36Sopenharmony_ci		5550, 5590, 5630, 5670,
224062306a36Sopenharmony_ci		5710, 5755, 5795, 5835,
224162306a36Sopenharmony_ci		5875, 5210, 5290, 5370,
224262306a36Sopenharmony_ci		5450, 5530, 5610, 5690,
224362306a36Sopenharmony_ci		5775, 5855
224462306a36Sopenharmony_ci	};
224562306a36Sopenharmony_ci	static const u16 freq_bw40[] = {
224662306a36Sopenharmony_ci		5190, 5230, 5270, 5310,
224762306a36Sopenharmony_ci		5350, 5390, 5430, 5470,
224862306a36Sopenharmony_ci		5510, 5550, 5590, 5630,
224962306a36Sopenharmony_ci		5670, 5710, 5755, 5795,
225062306a36Sopenharmony_ci		5835, 5875
225162306a36Sopenharmony_ci	};
225262306a36Sopenharmony_ci	int offset_2g = ARRAY_SIZE(freq_list);
225362306a36Sopenharmony_ci	int idx;
225462306a36Sopenharmony_ci
225562306a36Sopenharmony_ci	if (freq < 4000) {
225662306a36Sopenharmony_ci		if (freq < 2427)
225762306a36Sopenharmony_ci			return offset_2g;
225862306a36Sopenharmony_ci		if (freq < 2442)
225962306a36Sopenharmony_ci			return offset_2g + 1;
226062306a36Sopenharmony_ci		if (freq < 2457)
226162306a36Sopenharmony_ci			return offset_2g + 2;
226262306a36Sopenharmony_ci
226362306a36Sopenharmony_ci		return offset_2g + 3;
226462306a36Sopenharmony_ci	}
226562306a36Sopenharmony_ci
226662306a36Sopenharmony_ci	switch (bw) {
226762306a36Sopenharmony_ci	case NL80211_CHAN_WIDTH_80:
226862306a36Sopenharmony_ci	case NL80211_CHAN_WIDTH_80P80:
226962306a36Sopenharmony_ci	case NL80211_CHAN_WIDTH_160:
227062306a36Sopenharmony_ci		break;
227162306a36Sopenharmony_ci	default:
227262306a36Sopenharmony_ci		idx = mt7615_find_freq_idx(freq_bw40, ARRAY_SIZE(freq_bw40),
227362306a36Sopenharmony_ci					   freq + 10);
227462306a36Sopenharmony_ci		if (idx >= 0) {
227562306a36Sopenharmony_ci			freq = freq_bw40[idx];
227662306a36Sopenharmony_ci			break;
227762306a36Sopenharmony_ci		}
227862306a36Sopenharmony_ci
227962306a36Sopenharmony_ci		idx = mt7615_find_freq_idx(freq_bw40, ARRAY_SIZE(freq_bw40),
228062306a36Sopenharmony_ci					   freq - 10);
228162306a36Sopenharmony_ci		if (idx >= 0) {
228262306a36Sopenharmony_ci			freq = freq_bw40[idx];
228362306a36Sopenharmony_ci			break;
228462306a36Sopenharmony_ci		}
228562306a36Sopenharmony_ci		fallthrough;
228662306a36Sopenharmony_ci	case NL80211_CHAN_WIDTH_40:
228762306a36Sopenharmony_ci		idx = mt7615_find_freq_idx(freq_bw40, ARRAY_SIZE(freq_bw40),
228862306a36Sopenharmony_ci					   freq);
228962306a36Sopenharmony_ci		if (idx >= 0)
229062306a36Sopenharmony_ci			break;
229162306a36Sopenharmony_ci
229262306a36Sopenharmony_ci		return -1;
229362306a36Sopenharmony_ci
229462306a36Sopenharmony_ci	}
229562306a36Sopenharmony_ci
229662306a36Sopenharmony_ci	return mt7615_find_freq_idx(freq_list, ARRAY_SIZE(freq_list), freq);
229762306a36Sopenharmony_ci}
229862306a36Sopenharmony_ci
229962306a36Sopenharmony_ciint mt7615_mcu_apply_rx_dcoc(struct mt7615_phy *phy)
230062306a36Sopenharmony_ci{
230162306a36Sopenharmony_ci	struct mt7615_dev *dev = phy->dev;
230262306a36Sopenharmony_ci	struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
230362306a36Sopenharmony_ci	int freq2 = chandef->center_freq2;
230462306a36Sopenharmony_ci	int ret;
230562306a36Sopenharmony_ci	struct {
230662306a36Sopenharmony_ci		u8 direction;
230762306a36Sopenharmony_ci		u8 runtime_calibration;
230862306a36Sopenharmony_ci		u8 _rsv[2];
230962306a36Sopenharmony_ci
231062306a36Sopenharmony_ci		__le16 center_freq;
231162306a36Sopenharmony_ci		u8 bw;
231262306a36Sopenharmony_ci		u8 band;
231362306a36Sopenharmony_ci		u8 is_freq2;
231462306a36Sopenharmony_ci		u8 success;
231562306a36Sopenharmony_ci		u8 dbdc_en;
231662306a36Sopenharmony_ci
231762306a36Sopenharmony_ci		u8 _rsv2;
231862306a36Sopenharmony_ci
231962306a36Sopenharmony_ci		struct {
232062306a36Sopenharmony_ci			__le32 sx0_i_lna[4];
232162306a36Sopenharmony_ci			__le32 sx0_q_lna[4];
232262306a36Sopenharmony_ci
232362306a36Sopenharmony_ci			__le32 sx2_i_lna[4];
232462306a36Sopenharmony_ci			__le32 sx2_q_lna[4];
232562306a36Sopenharmony_ci		} dcoc_data[4];
232662306a36Sopenharmony_ci	} req = {
232762306a36Sopenharmony_ci		.direction = 1,
232862306a36Sopenharmony_ci
232962306a36Sopenharmony_ci		.bw = mt7615_mcu_chan_bw(chandef),
233062306a36Sopenharmony_ci		.band = chandef->center_freq1 > 4000,
233162306a36Sopenharmony_ci		.dbdc_en = !!dev->mt76.phys[MT_BAND1],
233262306a36Sopenharmony_ci	};
233362306a36Sopenharmony_ci	u16 center_freq = chandef->center_freq1;
233462306a36Sopenharmony_ci	int freq_idx;
233562306a36Sopenharmony_ci	u8 *eep = dev->mt76.eeprom.data;
233662306a36Sopenharmony_ci
233762306a36Sopenharmony_ci	if (!(eep[MT_EE_CALDATA_FLASH] & MT_EE_CALDATA_FLASH_RX_CAL))
233862306a36Sopenharmony_ci		return 0;
233962306a36Sopenharmony_ci
234062306a36Sopenharmony_ci	if (chandef->width == NL80211_CHAN_WIDTH_160) {
234162306a36Sopenharmony_ci		freq2 = center_freq + 40;
234262306a36Sopenharmony_ci		center_freq -= 40;
234362306a36Sopenharmony_ci	}
234462306a36Sopenharmony_ci
234562306a36Sopenharmony_ciagain:
234662306a36Sopenharmony_ci	req.runtime_calibration = 1;
234762306a36Sopenharmony_ci	freq_idx = mt7615_dcoc_freq_idx(center_freq, chandef->width);
234862306a36Sopenharmony_ci	if (freq_idx < 0)
234962306a36Sopenharmony_ci		goto out;
235062306a36Sopenharmony_ci
235162306a36Sopenharmony_ci	memcpy(req.dcoc_data, eep + MT7615_EEPROM_DCOC_OFFSET +
235262306a36Sopenharmony_ci			      freq_idx * MT7615_EEPROM_DCOC_SIZE,
235362306a36Sopenharmony_ci	       sizeof(req.dcoc_data));
235462306a36Sopenharmony_ci	req.runtime_calibration = 0;
235562306a36Sopenharmony_ci
235662306a36Sopenharmony_ciout:
235762306a36Sopenharmony_ci	req.center_freq = cpu_to_le16(center_freq);
235862306a36Sopenharmony_ci	ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RXDCOC_CAL), &req,
235962306a36Sopenharmony_ci				sizeof(req), true);
236062306a36Sopenharmony_ci
236162306a36Sopenharmony_ci	if ((chandef->width == NL80211_CHAN_WIDTH_80P80 ||
236262306a36Sopenharmony_ci	     chandef->width == NL80211_CHAN_WIDTH_160) && !req.is_freq2) {
236362306a36Sopenharmony_ci		req.is_freq2 = true;
236462306a36Sopenharmony_ci		center_freq = freq2;
236562306a36Sopenharmony_ci		goto again;
236662306a36Sopenharmony_ci	}
236762306a36Sopenharmony_ci
236862306a36Sopenharmony_ci	return ret;
236962306a36Sopenharmony_ci}
237062306a36Sopenharmony_ci
237162306a36Sopenharmony_cistatic int mt7615_dpd_freq_idx(u16 freq, u8 bw)
237262306a36Sopenharmony_ci{
237362306a36Sopenharmony_ci	static const u16 freq_list[] = {
237462306a36Sopenharmony_ci		4920, 4940, 4960, 4980,
237562306a36Sopenharmony_ci		5040, 5060, 5080, 5180,
237662306a36Sopenharmony_ci		5200, 5220, 5240, 5260,
237762306a36Sopenharmony_ci		5280, 5300, 5320, 5340,
237862306a36Sopenharmony_ci		5360, 5380, 5400, 5420,
237962306a36Sopenharmony_ci		5440, 5460, 5480, 5500,
238062306a36Sopenharmony_ci		5520, 5540, 5560, 5580,
238162306a36Sopenharmony_ci		5600, 5620, 5640, 5660,
238262306a36Sopenharmony_ci		5680, 5700, 5720, 5745,
238362306a36Sopenharmony_ci		5765, 5785, 5805, 5825,
238462306a36Sopenharmony_ci		5845, 5865, 5885, 5905
238562306a36Sopenharmony_ci	};
238662306a36Sopenharmony_ci	int offset_2g = ARRAY_SIZE(freq_list);
238762306a36Sopenharmony_ci	int idx;
238862306a36Sopenharmony_ci
238962306a36Sopenharmony_ci	if (freq < 4000) {
239062306a36Sopenharmony_ci		if (freq < 2432)
239162306a36Sopenharmony_ci			return offset_2g;
239262306a36Sopenharmony_ci		if (freq < 2457)
239362306a36Sopenharmony_ci			return offset_2g + 1;
239462306a36Sopenharmony_ci
239562306a36Sopenharmony_ci		return offset_2g + 2;
239662306a36Sopenharmony_ci	}
239762306a36Sopenharmony_ci
239862306a36Sopenharmony_ci	if (bw != NL80211_CHAN_WIDTH_20) {
239962306a36Sopenharmony_ci		idx = mt7615_find_freq_idx(freq_list, ARRAY_SIZE(freq_list),
240062306a36Sopenharmony_ci					   freq + 10);
240162306a36Sopenharmony_ci		if (idx >= 0)
240262306a36Sopenharmony_ci			return idx;
240362306a36Sopenharmony_ci
240462306a36Sopenharmony_ci		idx = mt7615_find_freq_idx(freq_list, ARRAY_SIZE(freq_list),
240562306a36Sopenharmony_ci					   freq - 10);
240662306a36Sopenharmony_ci		if (idx >= 0)
240762306a36Sopenharmony_ci			return idx;
240862306a36Sopenharmony_ci	}
240962306a36Sopenharmony_ci
241062306a36Sopenharmony_ci	return mt7615_find_freq_idx(freq_list, ARRAY_SIZE(freq_list), freq);
241162306a36Sopenharmony_ci}
241262306a36Sopenharmony_ci
241362306a36Sopenharmony_ci
241462306a36Sopenharmony_ciint mt7615_mcu_apply_tx_dpd(struct mt7615_phy *phy)
241562306a36Sopenharmony_ci{
241662306a36Sopenharmony_ci	struct mt7615_dev *dev = phy->dev;
241762306a36Sopenharmony_ci	struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
241862306a36Sopenharmony_ci	int freq2 = chandef->center_freq2;
241962306a36Sopenharmony_ci	int ret;
242062306a36Sopenharmony_ci	struct {
242162306a36Sopenharmony_ci		u8 direction;
242262306a36Sopenharmony_ci		u8 runtime_calibration;
242362306a36Sopenharmony_ci		u8 _rsv[2];
242462306a36Sopenharmony_ci
242562306a36Sopenharmony_ci		__le16 center_freq;
242662306a36Sopenharmony_ci		u8 bw;
242762306a36Sopenharmony_ci		u8 band;
242862306a36Sopenharmony_ci		u8 is_freq2;
242962306a36Sopenharmony_ci		u8 success;
243062306a36Sopenharmony_ci		u8 dbdc_en;
243162306a36Sopenharmony_ci
243262306a36Sopenharmony_ci		u8 _rsv2;
243362306a36Sopenharmony_ci
243462306a36Sopenharmony_ci		struct {
243562306a36Sopenharmony_ci			struct {
243662306a36Sopenharmony_ci				u32 dpd_g0;
243762306a36Sopenharmony_ci				u8 data[32];
243862306a36Sopenharmony_ci			} wf0, wf1;
243962306a36Sopenharmony_ci
244062306a36Sopenharmony_ci			struct {
244162306a36Sopenharmony_ci				u32 dpd_g0_prim;
244262306a36Sopenharmony_ci				u32 dpd_g0_sec;
244362306a36Sopenharmony_ci				u8 data_prim[32];
244462306a36Sopenharmony_ci				u8 data_sec[32];
244562306a36Sopenharmony_ci			} wf2, wf3;
244662306a36Sopenharmony_ci		} dpd_data;
244762306a36Sopenharmony_ci	} req = {
244862306a36Sopenharmony_ci		.direction = 1,
244962306a36Sopenharmony_ci
245062306a36Sopenharmony_ci		.bw = mt7615_mcu_chan_bw(chandef),
245162306a36Sopenharmony_ci		.band = chandef->center_freq1 > 4000,
245262306a36Sopenharmony_ci		.dbdc_en = !!dev->mt76.phys[MT_BAND1],
245362306a36Sopenharmony_ci	};
245462306a36Sopenharmony_ci	u16 center_freq = chandef->center_freq1;
245562306a36Sopenharmony_ci	int freq_idx;
245662306a36Sopenharmony_ci	u8 *eep = dev->mt76.eeprom.data;
245762306a36Sopenharmony_ci
245862306a36Sopenharmony_ci	if (!(eep[MT_EE_CALDATA_FLASH] & MT_EE_CALDATA_FLASH_TX_DPD))
245962306a36Sopenharmony_ci		return 0;
246062306a36Sopenharmony_ci
246162306a36Sopenharmony_ci	if (chandef->width == NL80211_CHAN_WIDTH_160) {
246262306a36Sopenharmony_ci		freq2 = center_freq + 40;
246362306a36Sopenharmony_ci		center_freq -= 40;
246462306a36Sopenharmony_ci	}
246562306a36Sopenharmony_ci
246662306a36Sopenharmony_ciagain:
246762306a36Sopenharmony_ci	req.runtime_calibration = 1;
246862306a36Sopenharmony_ci	freq_idx = mt7615_dpd_freq_idx(center_freq, chandef->width);
246962306a36Sopenharmony_ci	if (freq_idx < 0)
247062306a36Sopenharmony_ci		goto out;
247162306a36Sopenharmony_ci
247262306a36Sopenharmony_ci	memcpy(&req.dpd_data, eep + MT7615_EEPROM_TXDPD_OFFSET +
247362306a36Sopenharmony_ci			      freq_idx * MT7615_EEPROM_TXDPD_SIZE,
247462306a36Sopenharmony_ci	       sizeof(req.dpd_data));
247562306a36Sopenharmony_ci	req.runtime_calibration = 0;
247662306a36Sopenharmony_ci
247762306a36Sopenharmony_ciout:
247862306a36Sopenharmony_ci	req.center_freq = cpu_to_le16(center_freq);
247962306a36Sopenharmony_ci	ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(TXDPD_CAL),
248062306a36Sopenharmony_ci				&req, sizeof(req), true);
248162306a36Sopenharmony_ci
248262306a36Sopenharmony_ci	if ((chandef->width == NL80211_CHAN_WIDTH_80P80 ||
248362306a36Sopenharmony_ci	     chandef->width == NL80211_CHAN_WIDTH_160) && !req.is_freq2) {
248462306a36Sopenharmony_ci		req.is_freq2 = true;
248562306a36Sopenharmony_ci		center_freq = freq2;
248662306a36Sopenharmony_ci		goto again;
248762306a36Sopenharmony_ci	}
248862306a36Sopenharmony_ci
248962306a36Sopenharmony_ci	return ret;
249062306a36Sopenharmony_ci}
249162306a36Sopenharmony_ci
249262306a36Sopenharmony_ciint mt7615_mcu_set_rx_hdr_trans_blacklist(struct mt7615_dev *dev)
249362306a36Sopenharmony_ci{
249462306a36Sopenharmony_ci	struct {
249562306a36Sopenharmony_ci		u8 operation;
249662306a36Sopenharmony_ci		u8 count;
249762306a36Sopenharmony_ci		u8 _rsv[2];
249862306a36Sopenharmony_ci		u8 index;
249962306a36Sopenharmony_ci		u8 enable;
250062306a36Sopenharmony_ci		__le16 etype;
250162306a36Sopenharmony_ci	} req = {
250262306a36Sopenharmony_ci		.operation = 1,
250362306a36Sopenharmony_ci		.count = 1,
250462306a36Sopenharmony_ci		.enable = 1,
250562306a36Sopenharmony_ci		.etype = cpu_to_le16(ETH_P_PAE),
250662306a36Sopenharmony_ci	};
250762306a36Sopenharmony_ci
250862306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RX_HDR_TRANS),
250962306a36Sopenharmony_ci				 &req, sizeof(req), false);
251062306a36Sopenharmony_ci}
251162306a36Sopenharmony_ci
251262306a36Sopenharmony_ciint mt7615_mcu_set_bss_pm(struct mt7615_dev *dev, struct ieee80211_vif *vif,
251362306a36Sopenharmony_ci			  bool enable)
251462306a36Sopenharmony_ci{
251562306a36Sopenharmony_ci	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
251662306a36Sopenharmony_ci	struct {
251762306a36Sopenharmony_ci		u8 bss_idx;
251862306a36Sopenharmony_ci		u8 dtim_period;
251962306a36Sopenharmony_ci		__le16 aid;
252062306a36Sopenharmony_ci		__le16 bcn_interval;
252162306a36Sopenharmony_ci		__le16 atim_window;
252262306a36Sopenharmony_ci		u8 uapsd;
252362306a36Sopenharmony_ci		u8 bmc_delivered_ac;
252462306a36Sopenharmony_ci		u8 bmc_triggered_ac;
252562306a36Sopenharmony_ci		u8 pad;
252662306a36Sopenharmony_ci	} req = {
252762306a36Sopenharmony_ci		.bss_idx = mvif->mt76.idx,
252862306a36Sopenharmony_ci		.aid = cpu_to_le16(vif->cfg.aid),
252962306a36Sopenharmony_ci		.dtim_period = vif->bss_conf.dtim_period,
253062306a36Sopenharmony_ci		.bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int),
253162306a36Sopenharmony_ci	};
253262306a36Sopenharmony_ci	struct {
253362306a36Sopenharmony_ci		u8 bss_idx;
253462306a36Sopenharmony_ci		u8 pad[3];
253562306a36Sopenharmony_ci	} req_hdr = {
253662306a36Sopenharmony_ci		.bss_idx = mvif->mt76.idx,
253762306a36Sopenharmony_ci	};
253862306a36Sopenharmony_ci	int err;
253962306a36Sopenharmony_ci
254062306a36Sopenharmony_ci	if (vif->type != NL80211_IFTYPE_STATION)
254162306a36Sopenharmony_ci		return 0;
254262306a36Sopenharmony_ci
254362306a36Sopenharmony_ci	err = mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_BSS_ABORT),
254462306a36Sopenharmony_ci				&req_hdr, sizeof(req_hdr), false);
254562306a36Sopenharmony_ci	if (err < 0 || !enable)
254662306a36Sopenharmony_ci		return err;
254762306a36Sopenharmony_ci
254862306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_BSS_CONNECTED),
254962306a36Sopenharmony_ci				 &req, sizeof(req), false);
255062306a36Sopenharmony_ci}
255162306a36Sopenharmony_ci
255262306a36Sopenharmony_ciint mt7615_mcu_set_roc(struct mt7615_phy *phy, struct ieee80211_vif *vif,
255362306a36Sopenharmony_ci		       struct ieee80211_channel *chan, int duration)
255462306a36Sopenharmony_ci{
255562306a36Sopenharmony_ci	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
255662306a36Sopenharmony_ci	struct mt7615_dev *dev = phy->dev;
255762306a36Sopenharmony_ci	struct mt7615_roc_tlv req = {
255862306a36Sopenharmony_ci		.bss_idx = mvif->mt76.idx,
255962306a36Sopenharmony_ci		.active = !chan,
256062306a36Sopenharmony_ci		.max_interval = cpu_to_le32(duration),
256162306a36Sopenharmony_ci		.primary_chan = chan ? chan->hw_value : 0,
256262306a36Sopenharmony_ci		.band = chan ? chan->band : 0,
256362306a36Sopenharmony_ci		.req_type = 2,
256462306a36Sopenharmony_ci	};
256562306a36Sopenharmony_ci
256662306a36Sopenharmony_ci	phy->roc_grant = false;
256762306a36Sopenharmony_ci
256862306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_ROC),
256962306a36Sopenharmony_ci				 &req, sizeof(req), false);
257062306a36Sopenharmony_ci}
2571