xref: /openbmc/linux/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c (revision b97d6790d03b763eca08847a9a5869a4291b9f9a)
104b8e659SRyder Lee // SPDX-License-Identifier: ISC
204b8e659SRyder Lee /* Copyright (C) 2019 MediaTek Inc.
304b8e659SRyder Lee  *
404b8e659SRyder Lee  * Author: Roy Luo <royluo@google.com>
504b8e659SRyder Lee  *         Ryder Lee <ryder.lee@mediatek.com>
604b8e659SRyder Lee  */
704b8e659SRyder Lee 
804b8e659SRyder Lee #include <linux/firmware.h>
904b8e659SRyder Lee #include "mt7615.h"
1004b8e659SRyder Lee #include "mcu.h"
1104b8e659SRyder Lee #include "mac.h"
1204b8e659SRyder Lee #include "eeprom.h"
1304b8e659SRyder Lee 
14f2dc8ea1SLorenzo Bianconi static bool prefer_offload_fw = true;
15f2dc8ea1SLorenzo Bianconi module_param(prefer_offload_fw, bool, 0644);
16f2dc8ea1SLorenzo Bianconi MODULE_PARM_DESC(prefer_offload_fw,
17f2dc8ea1SLorenzo Bianconi 		 "Prefer client mode offload firmware (MT7663)");
18f2dc8ea1SLorenzo Bianconi 
1904b8e659SRyder Lee struct mt7615_patch_hdr {
2004b8e659SRyder Lee 	char build_date[16];
2104b8e659SRyder Lee 	char platform[4];
2204b8e659SRyder Lee 	__be32 hw_sw_ver;
2304b8e659SRyder Lee 	__be32 patch_ver;
2404b8e659SRyder Lee 	__be16 checksum;
2504b8e659SRyder Lee } __packed;
2604b8e659SRyder Lee 
2704b8e659SRyder Lee struct mt7615_fw_trailer {
2804b8e659SRyder Lee 	__le32 addr;
2904b8e659SRyder Lee 	u8 chip_id;
3004b8e659SRyder Lee 	u8 feature_set;
3104b8e659SRyder Lee 	u8 eco_code;
3204b8e659SRyder Lee 	char fw_ver[10];
3304b8e659SRyder Lee 	char build_date[15];
3404b8e659SRyder Lee 	__le32 len;
3504b8e659SRyder Lee } __packed;
3604b8e659SRyder Lee 
37f40ac0f3SLorenzo Bianconi #define FW_V3_COMMON_TAILER_SIZE	36
38f40ac0f3SLorenzo Bianconi #define FW_V3_REGION_TAILER_SIZE	40
39f40ac0f3SLorenzo Bianconi #define FW_START_OVERRIDE		BIT(0)
40f40ac0f3SLorenzo Bianconi #define FW_START_DLYCAL                 BIT(1)
41f40ac0f3SLorenzo Bianconi #define FW_START_WORKING_PDA_CR4	BIT(2)
42f40ac0f3SLorenzo Bianconi 
43f40ac0f3SLorenzo Bianconi struct mt7663_fw_buf {
4454178cc1SLorenzo Bianconi 	__le32 crc;
4554178cc1SLorenzo Bianconi 	__le32 d_img_size;
4654178cc1SLorenzo Bianconi 	__le32 block_size;
47f40ac0f3SLorenzo Bianconi 	u8 rsv[4];
4854178cc1SLorenzo Bianconi 	__le32 img_dest_addr;
4954178cc1SLorenzo Bianconi 	__le32 img_size;
50f40ac0f3SLorenzo Bianconi 	u8 feature_set;
51f40ac0f3SLorenzo Bianconi };
52f40ac0f3SLorenzo Bianconi 
5335da599fSFelix Fietkau #define MT7615_PATCH_ADDRESS		0x80000
5435da599fSFelix Fietkau #define MT7622_PATCH_ADDRESS		0x9c000
55f40ac0f3SLorenzo Bianconi #define MT7663_PATCH_ADDRESS		0xdc000
5604b8e659SRyder Lee 
5704b8e659SRyder Lee #define N9_REGION_NUM			2
5804b8e659SRyder Lee #define CR4_REGION_NUM			1
5904b8e659SRyder Lee 
6004b8e659SRyder Lee #define IMG_CRC_LEN			4
6104b8e659SRyder Lee 
mt7615_mcu_fill_msg(struct mt7615_dev * dev,struct sk_buff * skb,int cmd,int * wait_seq)6263f09b6bSLorenzo Bianconi void mt7615_mcu_fill_msg(struct mt7615_dev *dev, struct sk_buff *skb,
6333d9ed72SLorenzo Bianconi 			 int cmd, int *wait_seq)
6404b8e659SRyder Lee {
65e6d2070dSLorenzo Bianconi 	int txd_len, mcu_cmd = FIELD_GET(__MCU_CMD_FIELD_ID, cmd);
66323d7daaSLorenzo Bianconi 	struct mt7615_uni_txd *uni_txd;
6704b8e659SRyder Lee 	struct mt7615_mcu_txd *mcu_txd;
6804b8e659SRyder Lee 	u8 seq, q_idx, pkt_fmt;
6904b8e659SRyder Lee 	__le32 *txd;
7063f09b6bSLorenzo Bianconi 	u32 val;
7104b8e659SRyder Lee 
72e452c6ebSFelix Fietkau 	/* TODO: make dynamic based on msg type */
73e452c6ebSFelix Fietkau 	dev->mt76.mcu.timeout = 20 * HZ;
74e452c6ebSFelix Fietkau 
7509872957SLorenzo Bianconi 	seq = ++dev->mt76.mcu.msg_seq & 0xf;
7604b8e659SRyder Lee 	if (!seq)
7709872957SLorenzo Bianconi 		seq = ++dev->mt76.mcu.msg_seq & 0xf;
78323d7daaSLorenzo Bianconi 	if (wait_seq)
79323d7daaSLorenzo Bianconi 		*wait_seq = seq;
8004b8e659SRyder Lee 
8154722402SLorenzo Bianconi 	txd_len = cmd & __MCU_CMD_FIELD_UNI ? sizeof(*uni_txd) : sizeof(*mcu_txd);
82323d7daaSLorenzo Bianconi 	txd = (__le32 *)skb_push(skb, txd_len);
8304b8e659SRyder Lee 
84ffc2198dSLorenzo Bianconi 	if (cmd != MCU_CMD(FW_SCATTER)) {
8504b8e659SRyder Lee 		q_idx = MT_TX_MCU_PORT_RX_Q0;
8604b8e659SRyder Lee 		pkt_fmt = MT_TX_TYPE_CMD;
8704b8e659SRyder Lee 	} else {
8804b8e659SRyder Lee 		q_idx = MT_TX_MCU_PORT_RX_FWDL;
8904b8e659SRyder Lee 		pkt_fmt = MT_TX_TYPE_FW;
9004b8e659SRyder Lee 	}
9104b8e659SRyder Lee 
92132d8da5SLorenzo Bianconi 	val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len) |
9304b8e659SRyder Lee 	      FIELD_PREP(MT_TXD0_P_IDX, MT_TX_PORT_IDX_MCU) |
9404b8e659SRyder Lee 	      FIELD_PREP(MT_TXD0_Q_IDX, q_idx);
9504b8e659SRyder Lee 	txd[0] = cpu_to_le32(val);
9604b8e659SRyder Lee 
9704b8e659SRyder Lee 	val = MT_TXD1_LONG_FORMAT |
9804b8e659SRyder Lee 	      FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_CMD) |
9904b8e659SRyder Lee 	      FIELD_PREP(MT_TXD1_PKT_FMT, pkt_fmt);
10004b8e659SRyder Lee 	txd[1] = cpu_to_le32(val);
10104b8e659SRyder Lee 
10254722402SLorenzo Bianconi 	if (cmd & __MCU_CMD_FIELD_UNI) {
103323d7daaSLorenzo Bianconi 		uni_txd = (struct mt7615_uni_txd *)txd;
104323d7daaSLorenzo Bianconi 		uni_txd->len = cpu_to_le16(skb->len - sizeof(uni_txd->txd));
105323d7daaSLorenzo Bianconi 		uni_txd->option = MCU_CMD_UNI_EXT_ACK;
106d14f0a5cSLorenzo Bianconi 		uni_txd->cid = cpu_to_le16(mcu_cmd);
107323d7daaSLorenzo Bianconi 		uni_txd->s2d_index = MCU_S2D_H2N;
108323d7daaSLorenzo Bianconi 		uni_txd->pkt_type = MCU_PKT_ID;
109323d7daaSLorenzo Bianconi 		uni_txd->seq = seq;
110323d7daaSLorenzo Bianconi 
111323d7daaSLorenzo Bianconi 		return;
112323d7daaSLorenzo Bianconi 	}
113323d7daaSLorenzo Bianconi 
114323d7daaSLorenzo Bianconi 	mcu_txd = (struct mt7615_mcu_txd *)txd;
115b28e22bdSFelix Fietkau 	mcu_txd->len = cpu_to_le16(skb->len - sizeof(mcu_txd->txd));
11604b8e659SRyder Lee 	mcu_txd->pq_id = cpu_to_le16(MCU_PQ_ID(MT_TX_PORT_IDX_MCU, q_idx));
117323d7daaSLorenzo Bianconi 	mcu_txd->s2d_index = MCU_S2D_H2N;
11804b8e659SRyder Lee 	mcu_txd->pkt_type = MCU_PKT_ID;
11904b8e659SRyder Lee 	mcu_txd->seq = seq;
120e6d2070dSLorenzo Bianconi 	mcu_txd->cid = mcu_cmd;
121e6d2070dSLorenzo Bianconi 	mcu_txd->ext_cid = FIELD_GET(__MCU_CMD_FIELD_EXT_ID, cmd);
12204b8e659SRyder Lee 
123680a2eadSLorenzo Bianconi 	if (mcu_txd->ext_cid || (cmd & __MCU_CMD_FIELD_CE)) {
124e6d2070dSLorenzo Bianconi 		if (cmd & __MCU_CMD_FIELD_QUERY)
125e6d2070dSLorenzo Bianconi 			mcu_txd->set_query = MCU_Q_QUERY;
126e6d2070dSLorenzo Bianconi 		else
127e6d2070dSLorenzo Bianconi 			mcu_txd->set_query = MCU_Q_SET;
128e6d2070dSLorenzo Bianconi 		mcu_txd->ext_cid_ack = !!mcu_txd->ext_cid;
129e6d2070dSLorenzo Bianconi 	} else {
13027da3bfdSLorenzo Bianconi 		mcu_txd->set_query = MCU_Q_NA;
13104b8e659SRyder Lee 	}
13263f09b6bSLorenzo Bianconi }
133e90354e0SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt7615_mcu_fill_msg);
13404b8e659SRyder Lee 
mt7615_mcu_parse_response(struct mt76_dev * mdev,int cmd,struct sk_buff * skb,int seq)135f320d812SFelix Fietkau int mt7615_mcu_parse_response(struct mt76_dev *mdev, int cmd,
1360e6a29e4SLorenzo Bianconi 			      struct sk_buff *skb, int seq)
1370e6a29e4SLorenzo Bianconi {
13896a607b6SFelix Fietkau 	struct mt7615_mcu_rxd *rxd;
1390e6a29e4SLorenzo Bianconi 	int ret = 0;
1400e6a29e4SLorenzo Bianconi 
14196a607b6SFelix Fietkau 	if (!skb) {
14253d35b1aSLorenzo Bianconi 		dev_err(mdev->dev, "Message %08x (seq %d) timeout\n",
14353d35b1aSLorenzo Bianconi 			cmd, seq);
14496a607b6SFelix Fietkau 		return -ETIMEDOUT;
14596a607b6SFelix Fietkau 	}
14696a607b6SFelix Fietkau 
14796a607b6SFelix Fietkau 	rxd = (struct mt7615_mcu_rxd *)skb->data;
148f320d812SFelix Fietkau 	if (seq != rxd->seq)
149f320d812SFelix Fietkau 		return -EAGAIN;
1500e6a29e4SLorenzo Bianconi 
151ffc2198dSLorenzo Bianconi 	if (cmd == MCU_CMD(PATCH_SEM_CONTROL)) {
1520e6a29e4SLorenzo Bianconi 		skb_pull(skb, sizeof(*rxd) - 4);
1530e6a29e4SLorenzo Bianconi 		ret = *skb->data;
1549d8d136cSLorenzo Bianconi 	} else if (cmd == MCU_EXT_CMD(THERMAL_CTRL)) {
1550e6a29e4SLorenzo Bianconi 		skb_pull(skb, sizeof(*rxd));
1560e6a29e4SLorenzo Bianconi 		ret = le32_to_cpu(*(__le32 *)skb->data);
157e6d2070dSLorenzo Bianconi 	} else if (cmd == MCU_EXT_QUERY(RF_REG_ACCESS)) {
158dc804058SFelix Fietkau 		skb_pull(skb, sizeof(*rxd));
159dc804058SFelix Fietkau 		ret = le32_to_cpu(*(__le32 *)&skb->data[8]);
16054722402SLorenzo Bianconi 	} else if (cmd == MCU_UNI_CMD(DEV_INFO_UPDATE) ||
16154722402SLorenzo Bianconi 		   cmd == MCU_UNI_CMD(BSS_INFO_UPDATE) ||
16254722402SLorenzo Bianconi 		   cmd == MCU_UNI_CMD(STA_REC_UPDATE) ||
16354722402SLorenzo Bianconi 		   cmd == MCU_UNI_CMD(HIF_CTRL) ||
16454722402SLorenzo Bianconi 		   cmd == MCU_UNI_CMD(OFFLOAD) ||
16554722402SLorenzo Bianconi 		   cmd == MCU_UNI_CMD(SUSPEND)) {
16661d1f545SLorenzo Bianconi 		struct mt76_connac_mcu_uni_event *event;
167df5ab0d5SLorenzo Bianconi 
168df5ab0d5SLorenzo Bianconi 		skb_pull(skb, sizeof(*rxd));
16961d1f545SLorenzo Bianconi 		event = (struct mt76_connac_mcu_uni_event *)skb->data;
170df5ab0d5SLorenzo Bianconi 		ret = le32_to_cpu(event->status);
171680a2eadSLorenzo Bianconi 	} else if (cmd == MCU_CE_QUERY(REG_READ)) {
17261d1f545SLorenzo Bianconi 		struct mt76_connac_mcu_reg_event *event;
173a66cbdd6SSean Wang 
174a66cbdd6SSean Wang 		skb_pull(skb, sizeof(*rxd));
17561d1f545SLorenzo Bianconi 		event = (struct mt76_connac_mcu_reg_event *)skb->data;
176a66cbdd6SSean Wang 		ret = (int)le32_to_cpu(event->val);
1770e6a29e4SLorenzo Bianconi 	}
1780e6a29e4SLorenzo Bianconi 
1790e6a29e4SLorenzo Bianconi 	return ret;
1800e6a29e4SLorenzo Bianconi }
181f320d812SFelix Fietkau EXPORT_SYMBOL_GPL(mt7615_mcu_parse_response);
1820e6a29e4SLorenzo Bianconi 
1830e6a29e4SLorenzo Bianconi static int
mt7615_mcu_send_message(struct mt76_dev * mdev,struct sk_buff * skb,int cmd,int * seq)184f4d45fe2SLorenzo Bianconi mt7615_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
185e452c6ebSFelix Fietkau 			int cmd, int *seq)
18604b8e659SRyder Lee {
187a3a2c2e7SLorenzo Bianconi 	struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);
188b7c56875SNathan Chancellor 	enum mt76_mcuq_id qid;
18904b8e659SRyder Lee 
190e452c6ebSFelix Fietkau 	mt7615_mcu_fill_msg(dev, skb, cmd, seq);
191e452c6ebSFelix Fietkau 	if (test_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state))
192e637763bSLorenzo Bianconi 		qid = MT_MCUQ_WM;
193e452c6ebSFelix Fietkau 	else
194e637763bSLorenzo Bianconi 		qid = MT_MCUQ_FWDL;
19504b8e659SRyder Lee 
196e637763bSLorenzo Bianconi 	return mt76_tx_queue_skb_raw(dev, dev->mt76.q_mcu[qid], skb, 0);
19704b8e659SRyder Lee }
19804b8e659SRyder Lee 
mt7615_rf_rr(struct mt7615_dev * dev,u32 wf,u32 reg)199dc804058SFelix Fietkau u32 mt7615_rf_rr(struct mt7615_dev *dev, u32 wf, u32 reg)
200dc804058SFelix Fietkau {
201dc804058SFelix Fietkau 	struct {
202dc804058SFelix Fietkau 		__le32 wifi_stream;
203dc804058SFelix Fietkau 		__le32 address;
204dc804058SFelix Fietkau 		__le32 data;
205dc804058SFelix Fietkau 	} req = {
206dc804058SFelix Fietkau 		.wifi_stream = cpu_to_le32(wf),
207dc804058SFelix Fietkau 		.address = cpu_to_le32(reg),
208dc804058SFelix Fietkau 	};
209dc804058SFelix Fietkau 
210e6d2070dSLorenzo Bianconi 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_QUERY(RF_REG_ACCESS),
211dc804058SFelix Fietkau 				 &req, sizeof(req), true);
212dc804058SFelix Fietkau }
213dc804058SFelix Fietkau 
mt7615_rf_wr(struct mt7615_dev * dev,u32 wf,u32 reg,u32 val)214dc804058SFelix Fietkau int mt7615_rf_wr(struct mt7615_dev *dev, u32 wf, u32 reg, u32 val)
215dc804058SFelix Fietkau {
216dc804058SFelix Fietkau 	struct {
217dc804058SFelix Fietkau 		__le32 wifi_stream;
218dc804058SFelix Fietkau 		__le32 address;
219dc804058SFelix Fietkau 		__le32 data;
220dc804058SFelix Fietkau 	} req = {
221dc804058SFelix Fietkau 		.wifi_stream = cpu_to_le32(wf),
222dc804058SFelix Fietkau 		.address = cpu_to_le32(reg),
223dc804058SFelix Fietkau 		.data = cpu_to_le32(val),
224dc804058SFelix Fietkau 	};
225dc804058SFelix Fietkau 
226e6d2070dSLorenzo Bianconi 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RF_REG_ACCESS),
227e6d2070dSLorenzo Bianconi 				 &req, sizeof(req), false);
228dc804058SFelix Fietkau }
229dc804058SFelix Fietkau 
mt7622_trigger_hif_int(struct mt7615_dev * dev,bool en)230ad2a1ea4SRyder Lee void mt7622_trigger_hif_int(struct mt7615_dev *dev, bool en)
231186b659cSLorenzo Bianconi {
232186b659cSLorenzo Bianconi 	if (!is_mt7622(&dev->mt76))
233186b659cSLorenzo Bianconi 		return;
234186b659cSLorenzo Bianconi 
235186b659cSLorenzo Bianconi 	regmap_update_bits(dev->infracfg, MT_INFRACFG_MISC,
236186b659cSLorenzo Bianconi 			   MT_INFRACFG_MISC_AP2CONN_WAKE,
237186b659cSLorenzo Bianconi 			   !en * MT_INFRACFG_MISC_AP2CONN_WAKE);
238186b659cSLorenzo Bianconi }
2391cb7ea2aSFelix Fietkau EXPORT_SYMBOL_GPL(mt7622_trigger_hif_int);
240186b659cSLorenzo Bianconi 
mt7615_mcu_drv_pmctrl(struct mt7615_dev * dev)241186b659cSLorenzo Bianconi static int mt7615_mcu_drv_pmctrl(struct mt7615_dev *dev)
242186b659cSLorenzo Bianconi {
243186b659cSLorenzo Bianconi 	struct mt76_phy *mphy = &dev->mt76.phy;
244abe912aeSLorenzo Bianconi 	struct mt76_connac_pm *pm = &dev->pm;
245186b659cSLorenzo Bianconi 	struct mt76_dev *mdev = &dev->mt76;
2466892555dSLorenzo Bianconi 	u32 addr;
2476892555dSLorenzo Bianconi 	int err;
2486892555dSLorenzo Bianconi 
2495c7d3744SFelix Fietkau 	if (is_mt7663(mdev)) {
2505c7d3744SFelix Fietkau 		/* Clear firmware own via N9 eint */
2515c7d3744SFelix Fietkau 		mt76_wr(dev, MT_PCIE_DOORBELL_PUSH, MT_CFG_LPCR_HOST_DRV_OWN);
2525c7d3744SFelix Fietkau 		mt76_poll(dev, MT_CONN_ON_MISC, MT_CFG_LPCR_HOST_FW_OWN, 0, 3000);
2535c7d3744SFelix Fietkau 
2545c7d3744SFelix Fietkau 		addr = MT_CONN_HIF_ON_LPCTL;
2555c7d3744SFelix Fietkau 	} else {
2565c7d3744SFelix Fietkau 		addr = MT_CFG_LPCR_HOST;
2575c7d3744SFelix Fietkau 	}
2585c7d3744SFelix Fietkau 
2596892555dSLorenzo Bianconi 	mt76_wr(dev, addr, MT_CFG_LPCR_HOST_DRV_OWN);
2606892555dSLorenzo Bianconi 
2616892555dSLorenzo Bianconi 	mt7622_trigger_hif_int(dev, true);
2626892555dSLorenzo Bianconi 
2636892555dSLorenzo Bianconi 	err = !mt76_poll_msec(dev, addr, MT_CFG_LPCR_HOST_FW_OWN, 0, 3000);
2646892555dSLorenzo Bianconi 
2656892555dSLorenzo Bianconi 	mt7622_trigger_hif_int(dev, false);
2666892555dSLorenzo Bianconi 
2676892555dSLorenzo Bianconi 	if (err) {
2686892555dSLorenzo Bianconi 		dev_err(mdev->dev, "driver own failed\n");
2696892555dSLorenzo Bianconi 		return -ETIMEDOUT;
2706892555dSLorenzo Bianconi 	}
2716892555dSLorenzo Bianconi 
2726892555dSLorenzo Bianconi 	clear_bit(MT76_STATE_PM, &mphy->state);
2736892555dSLorenzo Bianconi 
274abe912aeSLorenzo Bianconi 	pm->stats.last_wake_event = jiffies;
275abe912aeSLorenzo Bianconi 	pm->stats.doze_time += pm->stats.last_wake_event -
276abe912aeSLorenzo Bianconi 			       pm->stats.last_doze_event;
277abe912aeSLorenzo Bianconi 
2786892555dSLorenzo Bianconi 	return 0;
2796892555dSLorenzo Bianconi }
2806892555dSLorenzo Bianconi 
mt7615_mcu_lp_drv_pmctrl(struct mt7615_dev * dev)2816892555dSLorenzo Bianconi static int mt7615_mcu_lp_drv_pmctrl(struct mt7615_dev *dev)
2826892555dSLorenzo Bianconi {
2836892555dSLorenzo Bianconi 	struct mt76_phy *mphy = &dev->mt76.phy;
284abe912aeSLorenzo Bianconi 	struct mt76_connac_pm *pm = &dev->pm;
2857cd740f0SLorenzo Bianconi 	int i, err = 0;
286186b659cSLorenzo Bianconi 
287abe912aeSLorenzo Bianconi 	mutex_lock(&pm->mutex);
2887cd740f0SLorenzo Bianconi 
2897cd740f0SLorenzo Bianconi 	if (!test_bit(MT76_STATE_PM, &mphy->state))
290186b659cSLorenzo Bianconi 		goto out;
291186b659cSLorenzo Bianconi 
292186b659cSLorenzo Bianconi 	for (i = 0; i < MT7615_DRV_OWN_RETRY_COUNT; i++) {
2936892555dSLorenzo Bianconi 		mt76_wr(dev, MT_PCIE_DOORBELL_PUSH, MT_CFG_LPCR_HOST_DRV_OWN);
2946892555dSLorenzo Bianconi 		if (mt76_poll_msec(dev, MT_CONN_HIF_ON_LPCTL,
2956892555dSLorenzo Bianconi 				   MT_CFG_LPCR_HOST_FW_OWN, 0, 50))
296186b659cSLorenzo Bianconi 			break;
297186b659cSLorenzo Bianconi 	}
298186b659cSLorenzo Bianconi 
299186b659cSLorenzo Bianconi 	if (i == MT7615_DRV_OWN_RETRY_COUNT) {
3006892555dSLorenzo Bianconi 		dev_err(dev->mt76.dev, "driver own failed\n");
3017cd740f0SLorenzo Bianconi 		err = -EIO;
3027cd740f0SLorenzo Bianconi 		goto out;
303186b659cSLorenzo Bianconi 	}
3047cd740f0SLorenzo Bianconi 	clear_bit(MT76_STATE_PM, &mphy->state);
305186b659cSLorenzo Bianconi 
306abe912aeSLorenzo Bianconi 	pm->stats.last_wake_event = jiffies;
307abe912aeSLorenzo Bianconi 	pm->stats.doze_time += pm->stats.last_wake_event -
308abe912aeSLorenzo Bianconi 			       pm->stats.last_doze_event;
309186b659cSLorenzo Bianconi out:
310abe912aeSLorenzo Bianconi 	mutex_unlock(&pm->mutex);
311186b659cSLorenzo Bianconi 
3127cd740f0SLorenzo Bianconi 	return err;
313186b659cSLorenzo Bianconi }
314186b659cSLorenzo Bianconi 
mt7615_mcu_fw_pmctrl(struct mt7615_dev * dev)315186b659cSLorenzo Bianconi static int mt7615_mcu_fw_pmctrl(struct mt7615_dev *dev)
316186b659cSLorenzo Bianconi {
317186b659cSLorenzo Bianconi 	struct mt76_phy *mphy = &dev->mt76.phy;
318abe912aeSLorenzo Bianconi 	struct mt76_connac_pm *pm = &dev->pm;
319186b659cSLorenzo Bianconi 	int err = 0;
320186b659cSLorenzo Bianconi 	u32 addr;
321186b659cSLorenzo Bianconi 
322abe912aeSLorenzo Bianconi 	mutex_lock(&pm->mutex);
3237cd740f0SLorenzo Bianconi 
324abe912aeSLorenzo Bianconi 	if (mt76_connac_skip_fw_pmctrl(mphy, pm))
3257cd740f0SLorenzo Bianconi 		goto out;
326186b659cSLorenzo Bianconi 
327186b659cSLorenzo Bianconi 	mt7622_trigger_hif_int(dev, true);
328186b659cSLorenzo Bianconi 
329186b659cSLorenzo Bianconi 	addr = is_mt7663(&dev->mt76) ? MT_CONN_HIF_ON_LPCTL : MT_CFG_LPCR_HOST;
330186b659cSLorenzo Bianconi 	mt76_wr(dev, addr, MT_CFG_LPCR_HOST_FW_OWN);
331186b659cSLorenzo Bianconi 
332186b659cSLorenzo Bianconi 	if (is_mt7622(&dev->mt76) &&
333186b659cSLorenzo Bianconi 	    !mt76_poll_msec(dev, addr, MT_CFG_LPCR_HOST_FW_OWN,
3346892555dSLorenzo Bianconi 			    MT_CFG_LPCR_HOST_FW_OWN, 3000)) {
335186b659cSLorenzo Bianconi 		dev_err(dev->mt76.dev, "Timeout for firmware own\n");
336186b659cSLorenzo Bianconi 		clear_bit(MT76_STATE_PM, &mphy->state);
337186b659cSLorenzo Bianconi 		err = -EIO;
338186b659cSLorenzo Bianconi 	}
339186b659cSLorenzo Bianconi 
340186b659cSLorenzo Bianconi 	mt7622_trigger_hif_int(dev, false);
34179717c4eSLorenzo Bianconi 	if (!err) {
342abe912aeSLorenzo Bianconi 		pm->stats.last_doze_event = jiffies;
343abe912aeSLorenzo Bianconi 		pm->stats.awake_time += pm->stats.last_doze_event -
344abe912aeSLorenzo Bianconi 					pm->stats.last_wake_event;
34579717c4eSLorenzo Bianconi 	}
3467cd740f0SLorenzo Bianconi out:
347abe912aeSLorenzo Bianconi 	mutex_unlock(&pm->mutex);
348186b659cSLorenzo Bianconi 
349186b659cSLorenzo Bianconi 	return err;
350186b659cSLorenzo Bianconi }
351186b659cSLorenzo Bianconi 
352d67a6646SLorenzo Bianconi static void
mt7615_mcu_csa_finish(void * priv,u8 * mac,struct ieee80211_vif * vif)3535ec87dc8SLorenzo Bianconi mt7615_mcu_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
3545ec87dc8SLorenzo Bianconi {
355d0a9123eSJohannes Berg 	if (vif->bss_conf.csa_active)
3565ec87dc8SLorenzo Bianconi 		ieee80211_csa_finish(vif);
3575ec87dc8SLorenzo Bianconi }
3585ec87dc8SLorenzo Bianconi 
3595ec87dc8SLorenzo Bianconi static void
mt7615_mcu_rx_csa_notify(struct mt7615_dev * dev,struct sk_buff * skb)360402a695bSRyder Lee mt7615_mcu_rx_csa_notify(struct mt7615_dev *dev, struct sk_buff *skb)
361402a695bSRyder Lee {
362402a695bSRyder Lee 	struct mt7615_phy *ext_phy = mt7615_ext_phy(dev);
363402a695bSRyder Lee 	struct mt76_phy *mphy = &dev->mt76.phy;
364402a695bSRyder Lee 	struct mt7615_mcu_csa_notify *c;
365402a695bSRyder Lee 
366402a695bSRyder Lee 	c = (struct mt7615_mcu_csa_notify *)skb->data;
367402a695bSRyder Lee 
3683253f8fdSRyder Lee 	if (c->omac_idx > EXT_BSSID_MAX)
3693253f8fdSRyder Lee 		return;
3703253f8fdSRyder Lee 
371402a695bSRyder Lee 	if (ext_phy && ext_phy->omac_mask & BIT_ULL(c->omac_idx))
372dc44c45cSLorenzo Bianconi 		mphy = dev->mt76.phys[MT_BAND1];
373402a695bSRyder Lee 
374402a695bSRyder Lee 	ieee80211_iterate_active_interfaces_atomic(mphy->hw,
375402a695bSRyder Lee 			IEEE80211_IFACE_ITER_RESUME_ALL,
376402a695bSRyder Lee 			mt7615_mcu_csa_finish, mphy->hw);
377402a695bSRyder Lee }
378402a695bSRyder Lee 
379402a695bSRyder Lee static void
mt7615_mcu_rx_radar_detected(struct mt7615_dev * dev,struct sk_buff * skb)3805dabdf71SFelix Fietkau mt7615_mcu_rx_radar_detected(struct mt7615_dev *dev, struct sk_buff *skb)
3815dabdf71SFelix Fietkau {
3825dabdf71SFelix Fietkau 	struct mt76_phy *mphy = &dev->mt76.phy;
3835dabdf71SFelix Fietkau 	struct mt7615_mcu_rdd_report *r;
3845dabdf71SFelix Fietkau 
3855dabdf71SFelix Fietkau 	r = (struct mt7615_mcu_rdd_report *)skb->data;
3865dabdf71SFelix Fietkau 
387e3343d0fSRyder Lee 	if (!dev->radar_pattern.n_pulses && !r->long_detected &&
388e3343d0fSRyder Lee 	    !r->constant_prf_detected && !r->staggered_prf_detected)
389e3343d0fSRyder Lee 		return;
390e3343d0fSRyder Lee 
391dc44c45cSLorenzo Bianconi 	if (r->band_idx && dev->mt76.phys[MT_BAND1])
392dc44c45cSLorenzo Bianconi 		mphy = dev->mt76.phys[MT_BAND1];
3935dabdf71SFelix Fietkau 
394aac86cebSFelix Fietkau 	if (mt76_phy_dfs_state(mphy) < MT_DFS_STATE_CAC)
395aac86cebSFelix Fietkau 		return;
396aac86cebSFelix Fietkau 
3975dabdf71SFelix Fietkau 	ieee80211_radar_detected(mphy->hw);
3985dabdf71SFelix Fietkau 	dev->hw_pattern++;
3995dabdf71SFelix Fietkau }
4005dabdf71SFelix Fietkau 
4015dabdf71SFelix Fietkau static void
mt7615_mcu_rx_log_message(struct mt7615_dev * dev,struct sk_buff * skb)402f347f81aSFelix Fietkau mt7615_mcu_rx_log_message(struct mt7615_dev *dev, struct sk_buff *skb)
403f347f81aSFelix Fietkau {
404f347f81aSFelix Fietkau 	struct mt7615_mcu_rxd *rxd = (struct mt7615_mcu_rxd *)skb->data;
405f347f81aSFelix Fietkau 	const char *data = (char *)&rxd[1];
406f347f81aSFelix Fietkau 	const char *type;
407f347f81aSFelix Fietkau 
408f347f81aSFelix Fietkau 	switch (rxd->s2d_index) {
409f347f81aSFelix Fietkau 	case 0:
410f347f81aSFelix Fietkau 		type = "N9";
411f347f81aSFelix Fietkau 		break;
412f347f81aSFelix Fietkau 	case 2:
413f347f81aSFelix Fietkau 		type = "CR4";
414f347f81aSFelix Fietkau 		break;
415f347f81aSFelix Fietkau 	default:
416f347f81aSFelix Fietkau 		type = "unknown";
417f347f81aSFelix Fietkau 		break;
418f347f81aSFelix Fietkau 	}
419f347f81aSFelix Fietkau 
420c8131dc3SDan Carpenter 	wiphy_info(mt76_hw(dev)->wiphy, "%s: %.*s", type,
421d76d6c3bSFelix Fietkau 		   (int)(skb->len - sizeof(*rxd)), data);
422f347f81aSFelix Fietkau }
423f347f81aSFelix Fietkau 
424f347f81aSFelix Fietkau static void
mt7615_mcu_rx_ext_event(struct mt7615_dev * dev,struct sk_buff * skb)425d67a6646SLorenzo Bianconi mt7615_mcu_rx_ext_event(struct mt7615_dev *dev, struct sk_buff *skb)
426d67a6646SLorenzo Bianconi {
427d67a6646SLorenzo Bianconi 	struct mt7615_mcu_rxd *rxd = (struct mt7615_mcu_rxd *)skb->data;
428d67a6646SLorenzo Bianconi 
429d67a6646SLorenzo Bianconi 	switch (rxd->ext_eid) {
430d67a6646SLorenzo Bianconi 	case MCU_EXT_EVENT_RDD_REPORT:
4315dabdf71SFelix Fietkau 		mt7615_mcu_rx_radar_detected(dev, skb);
432d67a6646SLorenzo Bianconi 		break;
4335ec87dc8SLorenzo Bianconi 	case MCU_EXT_EVENT_CSA_NOTIFY:
434402a695bSRyder Lee 		mt7615_mcu_rx_csa_notify(dev, skb);
4355ec87dc8SLorenzo Bianconi 		break;
436f347f81aSFelix Fietkau 	case MCU_EXT_EVENT_FW_LOG_2_HOST:
437f347f81aSFelix Fietkau 		mt7615_mcu_rx_log_message(dev, skb);
438f347f81aSFelix Fietkau 		break;
439d67a6646SLorenzo Bianconi 	default:
440d67a6646SLorenzo Bianconi 		break;
441d67a6646SLorenzo Bianconi 	}
442d67a6646SLorenzo Bianconi }
443d67a6646SLorenzo Bianconi 
444d67a6646SLorenzo Bianconi static void
mt7615_mcu_scan_event(struct mt7615_dev * dev,struct sk_buff * skb)44520305f98SLorenzo Bianconi mt7615_mcu_scan_event(struct mt7615_dev *dev, struct sk_buff *skb)
446fcdfc29eSLorenzo Bianconi {
44720305f98SLorenzo Bianconi 	u8 *seq_num = skb->data + sizeof(struct mt7615_mcu_rxd);
448fcdfc29eSLorenzo Bianconi 	struct mt7615_phy *phy;
449fcdfc29eSLorenzo Bianconi 	struct mt76_phy *mphy;
450fcdfc29eSLorenzo Bianconi 
451dc44c45cSLorenzo Bianconi 	if (*seq_num & BIT(7) && dev->mt76.phys[MT_BAND1])
452dc44c45cSLorenzo Bianconi 		mphy = dev->mt76.phys[MT_BAND1];
453fcdfc29eSLorenzo Bianconi 	else
454fcdfc29eSLorenzo Bianconi 		mphy = &dev->mt76.phy;
455fcdfc29eSLorenzo Bianconi 
456fcdfc29eSLorenzo Bianconi 	phy = (struct mt7615_phy *)mphy->priv;
45720305f98SLorenzo Bianconi 
45820305f98SLorenzo Bianconi 	spin_lock_bh(&dev->mt76.lock);
45920305f98SLorenzo Bianconi 	__skb_queue_tail(&phy->scan_event_list, skb);
46020305f98SLorenzo Bianconi 	spin_unlock_bh(&dev->mt76.lock);
46120305f98SLorenzo Bianconi 
462fcdfc29eSLorenzo Bianconi 	ieee80211_queue_delayed_work(mphy->hw, &phy->scan_work,
463fcdfc29eSLorenzo Bianconi 				     MT7615_HW_SCAN_TIMEOUT);
464fcdfc29eSLorenzo Bianconi }
465fcdfc29eSLorenzo Bianconi 
466fcdfc29eSLorenzo Bianconi static void
mt7615_mcu_roc_event(struct mt7615_dev * dev,struct sk_buff * skb)4677307f296SLorenzo Bianconi mt7615_mcu_roc_event(struct mt7615_dev *dev, struct sk_buff *skb)
4687307f296SLorenzo Bianconi {
4697307f296SLorenzo Bianconi 	struct mt7615_roc_tlv *event;
4707307f296SLorenzo Bianconi 	struct mt7615_phy *phy;
4717307f296SLorenzo Bianconi 	struct mt76_phy *mphy;
4727307f296SLorenzo Bianconi 	int duration;
4737307f296SLorenzo Bianconi 
4747307f296SLorenzo Bianconi 	skb_pull(skb, sizeof(struct mt7615_mcu_rxd));
4757307f296SLorenzo Bianconi 	event = (struct mt7615_roc_tlv *)skb->data;
4767307f296SLorenzo Bianconi 
477dc44c45cSLorenzo Bianconi 	if (event->dbdc_band && dev->mt76.phys[MT_BAND1])
478dc44c45cSLorenzo Bianconi 		mphy = dev->mt76.phys[MT_BAND1];
4797307f296SLorenzo Bianconi 	else
4807307f296SLorenzo Bianconi 		mphy = &dev->mt76.phy;
4817307f296SLorenzo Bianconi 
4827307f296SLorenzo Bianconi 	ieee80211_ready_on_channel(mphy->hw);
4837307f296SLorenzo Bianconi 
4847307f296SLorenzo Bianconi 	phy = (struct mt7615_phy *)mphy->priv;
4857307f296SLorenzo Bianconi 	phy->roc_grant = true;
4867307f296SLorenzo Bianconi 	wake_up(&phy->roc_wait);
4877307f296SLorenzo Bianconi 
4887307f296SLorenzo Bianconi 	duration = le32_to_cpu(event->max_interval);
4897307f296SLorenzo Bianconi 	mod_timer(&phy->roc_timer,
4907307f296SLorenzo Bianconi 		  round_jiffies_up(jiffies + msecs_to_jiffies(duration)));
4917307f296SLorenzo Bianconi }
4927307f296SLorenzo Bianconi 
4937307f296SLorenzo Bianconi static void
mt7615_mcu_beacon_loss_event(struct mt7615_dev * dev,struct sk_buff * skb)49486c60179SLorenzo Bianconi mt7615_mcu_beacon_loss_event(struct mt7615_dev *dev, struct sk_buff *skb)
49586c60179SLorenzo Bianconi {
496d0e274afSLorenzo Bianconi 	struct mt76_connac_beacon_loss_event *event;
49786c60179SLorenzo Bianconi 	struct mt76_phy *mphy;
49886c60179SLorenzo Bianconi 	u8 band_idx = 0; /* DBDC support */
49986c60179SLorenzo Bianconi 
50086c60179SLorenzo Bianconi 	skb_pull(skb, sizeof(struct mt7615_mcu_rxd));
501d0e274afSLorenzo Bianconi 	event = (struct mt76_connac_beacon_loss_event *)skb->data;
502dc44c45cSLorenzo Bianconi 	if (band_idx && dev->mt76.phys[MT_BAND1])
503dc44c45cSLorenzo Bianconi 		mphy = dev->mt76.phys[MT_BAND1];
50486c60179SLorenzo Bianconi 	else
50586c60179SLorenzo Bianconi 		mphy = &dev->mt76.phy;
50686c60179SLorenzo Bianconi 
50786c60179SLorenzo Bianconi 	ieee80211_iterate_active_interfaces_atomic(mphy->hw,
50886c60179SLorenzo Bianconi 					IEEE80211_IFACE_ITER_RESUME_ALL,
509d0e274afSLorenzo Bianconi 					mt76_connac_mcu_beacon_loss_iter,
510d0e274afSLorenzo Bianconi 					event);
51186c60179SLorenzo Bianconi }
51286c60179SLorenzo Bianconi 
51386c60179SLorenzo Bianconi static void
mt7615_mcu_bss_event(struct mt7615_dev * dev,struct sk_buff * skb)514bb366c5bSSean Wang mt7615_mcu_bss_event(struct mt7615_dev *dev, struct sk_buff *skb)
515bb366c5bSSean Wang {
516d0e274afSLorenzo Bianconi 	struct mt76_connac_mcu_bss_event *event;
517bb366c5bSSean Wang 	struct mt76_phy *mphy;
518ffc54ee2SLorenzo Bianconi 	u8 band_idx = 0; /* DBDC support */
519bb366c5bSSean Wang 
520d0e274afSLorenzo Bianconi 	skb_pull(skb, sizeof(struct mt7615_mcu_rxd));
521d0e274afSLorenzo Bianconi 	event = (struct mt76_connac_mcu_bss_event *)skb->data;
522bb366c5bSSean Wang 
523dc44c45cSLorenzo Bianconi 	if (band_idx && dev->mt76.phys[MT_BAND1])
524dc44c45cSLorenzo Bianconi 		mphy = dev->mt76.phys[MT_BAND1];
525bb366c5bSSean Wang 	else
526bb366c5bSSean Wang 		mphy = &dev->mt76.phy;
527bb366c5bSSean Wang 
528bb366c5bSSean Wang 	if (event->is_absent)
529bb366c5bSSean Wang 		ieee80211_stop_queues(mphy->hw);
530bb366c5bSSean Wang 	else
531bb366c5bSSean Wang 		ieee80211_wake_queues(mphy->hw);
532bb366c5bSSean Wang }
533bb366c5bSSean Wang 
534bb366c5bSSean Wang static void
mt7615_mcu_rx_unsolicited_event(struct mt7615_dev * dev,struct sk_buff * skb)535d67a6646SLorenzo Bianconi mt7615_mcu_rx_unsolicited_event(struct mt7615_dev *dev, struct sk_buff *skb)
536d67a6646SLorenzo Bianconi {
537d67a6646SLorenzo Bianconi 	struct mt7615_mcu_rxd *rxd = (struct mt7615_mcu_rxd *)skb->data;
538d67a6646SLorenzo Bianconi 
539d67a6646SLorenzo Bianconi 	switch (rxd->eid) {
540d67a6646SLorenzo Bianconi 	case MCU_EVENT_EXT:
541d67a6646SLorenzo Bianconi 		mt7615_mcu_rx_ext_event(dev, skb);
542d67a6646SLorenzo Bianconi 		break;
54386c60179SLorenzo Bianconi 	case MCU_EVENT_BSS_BEACON_LOSS:
54486c60179SLorenzo Bianconi 		mt7615_mcu_beacon_loss_event(dev, skb);
54586c60179SLorenzo Bianconi 		break;
5467307f296SLorenzo Bianconi 	case MCU_EVENT_ROC:
5477307f296SLorenzo Bianconi 		mt7615_mcu_roc_event(dev, skb);
5487307f296SLorenzo Bianconi 		break;
54920305f98SLorenzo Bianconi 	case MCU_EVENT_SCHED_SCAN_DONE:
550fcdfc29eSLorenzo Bianconi 	case MCU_EVENT_SCAN_DONE:
55120305f98SLorenzo Bianconi 		mt7615_mcu_scan_event(dev, skb);
55220305f98SLorenzo Bianconi 		return;
553bb366c5bSSean Wang 	case MCU_EVENT_BSS_ABSENCE:
554bb366c5bSSean Wang 		mt7615_mcu_bss_event(dev, skb);
555bb366c5bSSean Wang 		break;
556d2bf7959SLorenzo Bianconi 	case MCU_EVENT_COREDUMP:
557d2bf7959SLorenzo Bianconi 		mt76_connac_mcu_coredump_event(&dev->mt76, skb,
558d2bf7959SLorenzo Bianconi 					       &dev->coredump);
559d2bf7959SLorenzo Bianconi 		return;
560d67a6646SLorenzo Bianconi 	default:
561d67a6646SLorenzo Bianconi 		break;
562d67a6646SLorenzo Bianconi 	}
563d67a6646SLorenzo Bianconi 	dev_kfree_skb(skb);
564d67a6646SLorenzo Bianconi }
565d67a6646SLorenzo Bianconi 
mt7615_mcu_rx_event(struct mt7615_dev * dev,struct sk_buff * skb)566d67a6646SLorenzo Bianconi void mt7615_mcu_rx_event(struct mt7615_dev *dev, struct sk_buff *skb)
567d67a6646SLorenzo Bianconi {
568d67a6646SLorenzo Bianconi 	struct mt7615_mcu_rxd *rxd = (struct mt7615_mcu_rxd *)skb->data;
569d67a6646SLorenzo Bianconi 
570d67a6646SLorenzo Bianconi 	if (rxd->ext_eid == MCU_EXT_EVENT_THERMAL_PROTECT ||
571d67a6646SLorenzo Bianconi 	    rxd->ext_eid == MCU_EXT_EVENT_FW_LOG_2_HOST ||
572d67a6646SLorenzo Bianconi 	    rxd->ext_eid == MCU_EXT_EVENT_ASSERT_DUMP ||
573d67a6646SLorenzo Bianconi 	    rxd->ext_eid == MCU_EXT_EVENT_PS_SYNC ||
57486c60179SLorenzo Bianconi 	    rxd->eid == MCU_EVENT_BSS_BEACON_LOSS ||
57520305f98SLorenzo Bianconi 	    rxd->eid == MCU_EVENT_SCHED_SCAN_DONE ||
576bb366c5bSSean Wang 	    rxd->eid == MCU_EVENT_BSS_ABSENCE ||
577fcdfc29eSLorenzo Bianconi 	    rxd->eid == MCU_EVENT_SCAN_DONE ||
578d2bf7959SLorenzo Bianconi 	    rxd->eid == MCU_EVENT_COREDUMP ||
5797307f296SLorenzo Bianconi 	    rxd->eid == MCU_EVENT_ROC ||
580d67a6646SLorenzo Bianconi 	    !rxd->seq)
581d67a6646SLorenzo Bianconi 		mt7615_mcu_rx_unsolicited_event(dev, skb);
582d67a6646SLorenzo Bianconi 	else
583d67a6646SLorenzo Bianconi 		mt76_mcu_rx_event(&dev->mt76, skb);
584d67a6646SLorenzo Bianconi }
585d67a6646SLorenzo Bianconi 
586062c3699SLorenzo Bianconi static int
mt7615_mcu_muar_config(struct mt7615_dev * dev,struct ieee80211_vif * vif,bool bssid,bool enable)587d8d59f66SRyder Lee mt7615_mcu_muar_config(struct mt7615_dev *dev, struct ieee80211_vif *vif,
588d8d59f66SRyder Lee 		       bool bssid, bool enable)
589d8d59f66SRyder Lee {
590d8d59f66SRyder Lee 	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
59185d96704SLorenzo Bianconi 	u32 idx = mvif->mt76.omac_idx - REPEATER_BSSID_START;
592d8d59f66SRyder Lee 	u32 mask = dev->omac_mask >> 32 & ~BIT(idx);
593d8d59f66SRyder Lee 	const u8 *addr = vif->addr;
594d8d59f66SRyder Lee 	struct {
595d8d59f66SRyder Lee 		u8 mode;
596d8d59f66SRyder Lee 		u8 force_clear;
597d8d59f66SRyder Lee 		u8 clear_bitmap[8];
598d8d59f66SRyder Lee 		u8 entry_count;
599d8d59f66SRyder Lee 		u8 write;
600d8d59f66SRyder Lee 
601d8d59f66SRyder Lee 		u8 index;
602d8d59f66SRyder Lee 		u8 bssid;
603d8d59f66SRyder Lee 		u8 addr[ETH_ALEN];
604d8d59f66SRyder Lee 	} __packed req = {
605d8d59f66SRyder Lee 		.mode = !!mask || enable,
606d8d59f66SRyder Lee 		.entry_count = 1,
607d8d59f66SRyder Lee 		.write = 1,
608d8d59f66SRyder Lee 
609d8d59f66SRyder Lee 		.index = idx * 2 + bssid,
610d8d59f66SRyder Lee 	};
611d8d59f66SRyder Lee 
612d8d59f66SRyder Lee 	if (bssid)
613d8d59f66SRyder Lee 		addr = vif->bss_conf.bssid;
614d8d59f66SRyder Lee 
615d8d59f66SRyder Lee 	if (enable)
616d8d59f66SRyder Lee 		ether_addr_copy(req.addr, addr);
617d8d59f66SRyder Lee 
618e6d2070dSLorenzo Bianconi 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(MUAR_UPDATE),
619e6d2070dSLorenzo Bianconi 				 &req, sizeof(req), true);
620d8d59f66SRyder Lee }
621d8d59f66SRyder Lee 
622d8d59f66SRyder Lee static int
mt7615_mcu_add_dev(struct mt7615_phy * phy,struct ieee80211_vif * vif,bool enable)623d0e274afSLorenzo Bianconi mt7615_mcu_add_dev(struct mt7615_phy *phy, struct ieee80211_vif *vif,
624062c3699SLorenzo Bianconi 		   bool enable)
625062c3699SLorenzo Bianconi {
626062c3699SLorenzo Bianconi 	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
627d0e274afSLorenzo Bianconi 	struct mt7615_dev *dev = phy->dev;
628062c3699SLorenzo Bianconi 	struct {
629062c3699SLorenzo Bianconi 		struct req_hdr {
630062c3699SLorenzo Bianconi 			u8 omac_idx;
631062c3699SLorenzo Bianconi 			u8 band_idx;
632062c3699SLorenzo Bianconi 			__le16 tlv_num;
633062c3699SLorenzo Bianconi 			u8 is_tlv_append;
634062c3699SLorenzo Bianconi 			u8 rsv[3];
635062c3699SLorenzo Bianconi 		} __packed hdr;
636062c3699SLorenzo Bianconi 		struct req_tlv {
637062c3699SLorenzo Bianconi 			__le16 tag;
638062c3699SLorenzo Bianconi 			__le16 len;
639062c3699SLorenzo Bianconi 			u8 active;
640062c3699SLorenzo Bianconi 			u8 band_idx;
641062c3699SLorenzo Bianconi 			u8 omac_addr[ETH_ALEN];
642062c3699SLorenzo Bianconi 		} __packed tlv;
643062c3699SLorenzo Bianconi 	} data = {
644062c3699SLorenzo Bianconi 		.hdr = {
64585d96704SLorenzo Bianconi 			.omac_idx = mvif->mt76.omac_idx,
64685d96704SLorenzo Bianconi 			.band_idx = mvif->mt76.band_idx,
647062c3699SLorenzo Bianconi 			.tlv_num = cpu_to_le16(1),
648062c3699SLorenzo Bianconi 			.is_tlv_append = 1,
649062c3699SLorenzo Bianconi 		},
650062c3699SLorenzo Bianconi 		.tlv = {
651062c3699SLorenzo Bianconi 			.tag = cpu_to_le16(DEV_INFO_ACTIVE),
652062c3699SLorenzo Bianconi 			.len = cpu_to_le16(sizeof(struct req_tlv)),
653062c3699SLorenzo Bianconi 			.active = enable,
65485d96704SLorenzo Bianconi 			.band_idx = mvif->mt76.band_idx,
655062c3699SLorenzo Bianconi 		},
656062c3699SLorenzo Bianconi 	};
657062c3699SLorenzo Bianconi 
65885d96704SLorenzo Bianconi 	if (mvif->mt76.omac_idx >= REPEATER_BSSID_START)
659d8d59f66SRyder Lee 		return mt7615_mcu_muar_config(dev, vif, false, enable);
660d8d59f66SRyder Lee 
661062c3699SLorenzo Bianconi 	memcpy(data.tlv.omac_addr, vif->addr, ETH_ALEN);
662e6d2070dSLorenzo Bianconi 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(DEV_INFO_UPDATE),
663062c3699SLorenzo Bianconi 				 &data, sizeof(data), true);
664062c3699SLorenzo Bianconi }
665062c3699SLorenzo Bianconi 
666062c3699SLorenzo Bianconi static int
mt7615_mcu_add_beacon_offload(struct mt7615_dev * dev,struct ieee80211_hw * hw,struct ieee80211_vif * vif,bool enable)667062c3699SLorenzo Bianconi mt7615_mcu_add_beacon_offload(struct mt7615_dev *dev,
668062c3699SLorenzo Bianconi 			      struct ieee80211_hw *hw,
669062c3699SLorenzo Bianconi 			      struct ieee80211_vif *vif, bool enable)
670062c3699SLorenzo Bianconi {
671062c3699SLorenzo Bianconi 	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
672062c3699SLorenzo Bianconi 	struct mt76_wcid *wcid = &dev->mt76.global_wcid;
673062c3699SLorenzo Bianconi 	struct ieee80211_mutable_offsets offs;
674062c3699SLorenzo Bianconi 	struct ieee80211_tx_info *info;
675062c3699SLorenzo Bianconi 	struct req {
676062c3699SLorenzo Bianconi 		u8 omac_idx;
677062c3699SLorenzo Bianconi 		u8 enable;
678062c3699SLorenzo Bianconi 		u8 wlan_idx;
679062c3699SLorenzo Bianconi 		u8 band_idx;
680062c3699SLorenzo Bianconi 		u8 pkt_type;
681062c3699SLorenzo Bianconi 		u8 need_pre_tbtt_int;
682062c3699SLorenzo Bianconi 		__le16 csa_ie_pos;
683062c3699SLorenzo Bianconi 		__le16 pkt_len;
684062c3699SLorenzo Bianconi 		__le16 tim_ie_pos;
685062c3699SLorenzo Bianconi 		u8 pkt[512];
686062c3699SLorenzo Bianconi 		u8 csa_cnt;
687062c3699SLorenzo Bianconi 		/* bss color change */
688062c3699SLorenzo Bianconi 		u8 bcc_cnt;
689062c3699SLorenzo Bianconi 		__le16 bcc_ie_pos;
690062c3699SLorenzo Bianconi 	} __packed req = {
69185d96704SLorenzo Bianconi 		.omac_idx = mvif->mt76.omac_idx,
692062c3699SLorenzo Bianconi 		.enable = enable,
693062c3699SLorenzo Bianconi 		.wlan_idx = wcid->idx,
69485d96704SLorenzo Bianconi 		.band_idx = mvif->mt76.band_idx,
695062c3699SLorenzo Bianconi 	};
696062c3699SLorenzo Bianconi 	struct sk_buff *skb;
697062c3699SLorenzo Bianconi 
6988a5a5dbfSRyder Lee 	if (!enable)
6998a5a5dbfSRyder Lee 		goto out;
7008a5a5dbfSRyder Lee 
7016e8912a5SShaul Triebitz 	skb = ieee80211_beacon_get_template(hw, vif, &offs, 0);
702062c3699SLorenzo Bianconi 	if (!skb)
703062c3699SLorenzo Bianconi 		return -EINVAL;
704062c3699SLorenzo Bianconi 
705062c3699SLorenzo Bianconi 	if (skb->len > 512 - MT_TXD_SIZE) {
706062c3699SLorenzo Bianconi 		dev_err(dev->mt76.dev, "Bcn size limit exceed\n");
707062c3699SLorenzo Bianconi 		dev_kfree_skb(skb);
708062c3699SLorenzo Bianconi 		return -EINVAL;
709062c3699SLorenzo Bianconi 	}
710062c3699SLorenzo Bianconi 
711062c3699SLorenzo Bianconi 	info = IEEE80211_SKB_CB(skb);
712a062f001SLorenzo Bianconi 	info->hw_queue |= FIELD_PREP(MT_TX_HW_QUEUE_PHY, mvif->mt76.band_idx);
713062c3699SLorenzo Bianconi 
714062c3699SLorenzo Bianconi 	mt7615_mac_write_txwi(dev, (__le32 *)(req.pkt), skb, wcid, NULL,
7151d5af0acSFelix Fietkau 			      0, NULL, 0, true);
716062c3699SLorenzo Bianconi 	memcpy(req.pkt + MT_TXD_SIZE, skb->data, skb->len);
717062c3699SLorenzo Bianconi 	req.pkt_len = cpu_to_le16(MT_TXD_SIZE + skb->len);
718062c3699SLorenzo Bianconi 	req.tim_ie_pos = cpu_to_le16(MT_TXD_SIZE + offs.tim_offset);
7198552a434SJohn Crispin 	if (offs.cntdwn_counter_offs[0]) {
720062c3699SLorenzo Bianconi 		u16 csa_offs;
721062c3699SLorenzo Bianconi 
7228552a434SJohn Crispin 		csa_offs = MT_TXD_SIZE + offs.cntdwn_counter_offs[0] - 4;
723062c3699SLorenzo Bianconi 		req.csa_ie_pos = cpu_to_le16(csa_offs);
7248552a434SJohn Crispin 		req.csa_cnt = skb->data[offs.cntdwn_counter_offs[0]];
725062c3699SLorenzo Bianconi 	}
726062c3699SLorenzo Bianconi 	dev_kfree_skb(skb);
727062c3699SLorenzo Bianconi 
7288a5a5dbfSRyder Lee out:
729e6d2070dSLorenzo Bianconi 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(BCN_OFFLOAD), &req,
730cb5cdd4cSFelix Fietkau 				 sizeof(req), true);
731062c3699SLorenzo Bianconi }
732062c3699SLorenzo Bianconi 
733062c3699SLorenzo Bianconi static int
mt7615_mcu_ctrl_pm_state(struct mt7615_dev * dev,int band,int state)734062c3699SLorenzo Bianconi mt7615_mcu_ctrl_pm_state(struct mt7615_dev *dev, int band, int state)
735062c3699SLorenzo Bianconi {
73648d743d1SLorenzo Bianconi 	return mt76_connac_mcu_set_pm(&dev->mt76, band, state);
737062c3699SLorenzo Bianconi }
738062c3699SLorenzo Bianconi 
739adb2ed0eSLorenzo Bianconi static int
mt7615_mcu_add_bss(struct mt7615_phy * phy,struct ieee80211_vif * vif,struct ieee80211_sta * sta,bool enable)7405d3a4a4bSLorenzo Bianconi mt7615_mcu_add_bss(struct mt7615_phy *phy, struct ieee80211_vif *vif,
741f5596850SLorenzo Bianconi 		   struct ieee80211_sta *sta, bool enable)
742062c3699SLorenzo Bianconi {
743062c3699SLorenzo Bianconi 	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
7445d3a4a4bSLorenzo Bianconi 	struct mt7615_dev *dev = phy->dev;
745062c3699SLorenzo Bianconi 	struct sk_buff *skb;
746062c3699SLorenzo Bianconi 
74785d96704SLorenzo Bianconi 	if (mvif->mt76.omac_idx >= REPEATER_BSSID_START)
748d8d59f66SRyder Lee 		mt7615_mcu_muar_config(dev, vif, true, enable);
749d8d59f66SRyder Lee 
750d0e274afSLorenzo Bianconi 	skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, NULL);
751062c3699SLorenzo Bianconi 	if (IS_ERR(skb))
752062c3699SLorenzo Bianconi 		return PTR_ERR(skb);
753062c3699SLorenzo Bianconi 
754062c3699SLorenzo Bianconi 	if (enable)
75554735e11SLorenzo Bianconi 		mt76_connac_mcu_bss_omac_tlv(skb, vif);
756062c3699SLorenzo Bianconi 
75749126ac1SLorenzo Bianconi 	mt76_connac_mcu_bss_basic_tlv(skb, vif, sta, phy->mt76,
75849126ac1SLorenzo Bianconi 				      mvif->sta.wcid.idx, enable);
759062c3699SLorenzo Bianconi 
76085d96704SLorenzo Bianconi 	if (enable && mvif->mt76.omac_idx >= EXT_BSSID_START &&
76185d96704SLorenzo Bianconi 	    mvif->mt76.omac_idx < REPEATER_BSSID_START)
76264f4e823SLorenzo Bianconi 		mt76_connac_mcu_bss_ext_tlv(skb, &mvif->mt76);
763062c3699SLorenzo Bianconi 
764fa62d0e0SFelix Fietkau 	return mt76_mcu_skb_send_msg(&dev->mt76, skb,
765e6d2070dSLorenzo Bianconi 				     MCU_EXT_CMD(BSS_INFO_UPDATE), true);
766062c3699SLorenzo Bianconi }
767062c3699SLorenzo Bianconi 
768062c3699SLorenzo Bianconi static int
mt7615_mcu_wtbl_tx_ba(struct mt7615_dev * dev,struct ieee80211_ampdu_params * params,bool enable)7696f4d7cc8SLorenzo Bianconi mt7615_mcu_wtbl_tx_ba(struct mt7615_dev *dev,
7706f4d7cc8SLorenzo Bianconi 		      struct ieee80211_ampdu_params *params,
7716f4d7cc8SLorenzo Bianconi 		      bool enable)
7726f4d7cc8SLorenzo Bianconi {
7736f4d7cc8SLorenzo Bianconi 	struct mt7615_sta *msta = (struct mt7615_sta *)params->sta->drv_priv;
7746f4d7cc8SLorenzo Bianconi 	struct mt7615_vif *mvif = msta->vif;
7756f4d7cc8SLorenzo Bianconi 	struct wtbl_req_hdr *wtbl_hdr;
7766f4d7cc8SLorenzo Bianconi 	struct sk_buff *skb = NULL;
7776f4d7cc8SLorenzo Bianconi 	int err;
7786f4d7cc8SLorenzo Bianconi 
779d0e274afSLorenzo Bianconi 	wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(&dev->mt76, &msta->wcid,
780d0e274afSLorenzo Bianconi 						  WTBL_SET, NULL, &skb);
7816f4d7cc8SLorenzo Bianconi 	if (IS_ERR(wtbl_hdr))
7826f4d7cc8SLorenzo Bianconi 		return PTR_ERR(wtbl_hdr);
7836f4d7cc8SLorenzo Bianconi 
784d0e274afSLorenzo Bianconi 	mt76_connac_mcu_wtbl_ba_tlv(&dev->mt76, skb, params, enable, true,
785d0e274afSLorenzo Bianconi 				    NULL, wtbl_hdr);
7866f4d7cc8SLorenzo Bianconi 
787e6d2070dSLorenzo Bianconi 	err = mt76_mcu_skb_send_msg(&dev->mt76, skb,
788e6d2070dSLorenzo Bianconi 				    MCU_EXT_CMD(WTBL_UPDATE), true);
7896f4d7cc8SLorenzo Bianconi 	if (err < 0)
7906f4d7cc8SLorenzo Bianconi 		return err;
7916f4d7cc8SLorenzo Bianconi 
792d0e274afSLorenzo Bianconi 	skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
793d0e274afSLorenzo Bianconi 					    &msta->wcid);
7946f4d7cc8SLorenzo Bianconi 	if (IS_ERR(skb))
7956f4d7cc8SLorenzo Bianconi 		return PTR_ERR(skb);
7966f4d7cc8SLorenzo Bianconi 
797d0e274afSLorenzo Bianconi 	mt76_connac_mcu_sta_ba_tlv(skb, params, enable, true);
7986f4d7cc8SLorenzo Bianconi 
799fa62d0e0SFelix Fietkau 	return mt76_mcu_skb_send_msg(&dev->mt76, skb,
800e6d2070dSLorenzo Bianconi 				     MCU_EXT_CMD(STA_REC_UPDATE), true);
8016f4d7cc8SLorenzo Bianconi }
8026f4d7cc8SLorenzo Bianconi 
8036f4d7cc8SLorenzo Bianconi static int
mt7615_mcu_wtbl_rx_ba(struct mt7615_dev * dev,struct ieee80211_ampdu_params * params,bool enable)8046f4d7cc8SLorenzo Bianconi mt7615_mcu_wtbl_rx_ba(struct mt7615_dev *dev,
8056f4d7cc8SLorenzo Bianconi 		      struct ieee80211_ampdu_params *params,
8066f4d7cc8SLorenzo Bianconi 		      bool enable)
8076f4d7cc8SLorenzo Bianconi {
8086f4d7cc8SLorenzo Bianconi 	struct mt7615_sta *msta = (struct mt7615_sta *)params->sta->drv_priv;
8096f4d7cc8SLorenzo Bianconi 	struct mt7615_vif *mvif = msta->vif;
8106f4d7cc8SLorenzo Bianconi 	struct wtbl_req_hdr *wtbl_hdr;
8116f4d7cc8SLorenzo Bianconi 	struct sk_buff *skb;
8126f4d7cc8SLorenzo Bianconi 	int err;
8136f4d7cc8SLorenzo Bianconi 
814d0e274afSLorenzo Bianconi 	skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
815d0e274afSLorenzo Bianconi 					    &msta->wcid);
8166f4d7cc8SLorenzo Bianconi 	if (IS_ERR(skb))
8176f4d7cc8SLorenzo Bianconi 		return PTR_ERR(skb);
8186f4d7cc8SLorenzo Bianconi 
819d0e274afSLorenzo Bianconi 	mt76_connac_mcu_sta_ba_tlv(skb, params, enable, false);
8206f4d7cc8SLorenzo Bianconi 
821fa62d0e0SFelix Fietkau 	err = mt76_mcu_skb_send_msg(&dev->mt76, skb,
822e6d2070dSLorenzo Bianconi 				    MCU_EXT_CMD(STA_REC_UPDATE), true);
8236f4d7cc8SLorenzo Bianconi 	if (err < 0 || !enable)
8246f4d7cc8SLorenzo Bianconi 		return err;
8256f4d7cc8SLorenzo Bianconi 
8266f4d7cc8SLorenzo Bianconi 	skb = NULL;
827d0e274afSLorenzo Bianconi 	wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(&dev->mt76, &msta->wcid,
828d0e274afSLorenzo Bianconi 						  WTBL_SET, NULL, &skb);
8296f4d7cc8SLorenzo Bianconi 	if (IS_ERR(wtbl_hdr))
8306f4d7cc8SLorenzo Bianconi 		return PTR_ERR(wtbl_hdr);
8316f4d7cc8SLorenzo Bianconi 
832d0e274afSLorenzo Bianconi 	mt76_connac_mcu_wtbl_ba_tlv(&dev->mt76, skb, params, enable, false,
833d0e274afSLorenzo Bianconi 				    NULL, wtbl_hdr);
8346f4d7cc8SLorenzo Bianconi 
835e6d2070dSLorenzo Bianconi 	return mt76_mcu_skb_send_msg(&dev->mt76, skb,
836e6d2070dSLorenzo Bianconi 				     MCU_EXT_CMD(WTBL_UPDATE), true);
8376f4d7cc8SLorenzo Bianconi }
8386f4d7cc8SLorenzo Bianconi 
83999c457d9SLorenzo Bianconi static int
mt7615_mcu_wtbl_sta_add(struct mt7615_phy * phy,struct ieee80211_vif * vif,struct ieee80211_sta * sta,bool enable)840d0e274afSLorenzo Bianconi mt7615_mcu_wtbl_sta_add(struct mt7615_phy *phy, struct ieee80211_vif *vif,
84199c457d9SLorenzo Bianconi 			struct ieee80211_sta *sta, bool enable)
84299c457d9SLorenzo Bianconi {
84399c457d9SLorenzo Bianconi 	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
84499c457d9SLorenzo Bianconi 	struct sk_buff *skb, *sskb, *wskb = NULL;
845d0e274afSLorenzo Bianconi 	struct mt7615_dev *dev = phy->dev;
84699c457d9SLorenzo Bianconi 	struct wtbl_req_hdr *wtbl_hdr;
847b4985ff1SLorenzo Bianconi 	struct mt7615_sta *msta;
848df6b739fSFelix Fietkau 	bool new_entry = true;
84999c457d9SLorenzo Bianconi 	int cmd, err;
85099c457d9SLorenzo Bianconi 
851b4985ff1SLorenzo Bianconi 	msta = sta ? (struct mt7615_sta *)sta->drv_priv : &mvif->sta;
852b4985ff1SLorenzo Bianconi 
853d0e274afSLorenzo Bianconi 	sskb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
854d0e274afSLorenzo Bianconi 					     &msta->wcid);
85599c457d9SLorenzo Bianconi 	if (IS_ERR(sskb))
85699c457d9SLorenzo Bianconi 		return PTR_ERR(sskb);
85799c457d9SLorenzo Bianconi 
858df6b739fSFelix Fietkau 	if (!sta) {
859df6b739fSFelix Fietkau 		if (mvif->sta_added)
860df6b739fSFelix Fietkau 			new_entry = false;
861df6b739fSFelix Fietkau 		else
862df6b739fSFelix Fietkau 			mvif->sta_added = true;
863df6b739fSFelix Fietkau 	}
8641b83d17cSSean Wang 	mt76_connac_mcu_sta_basic_tlv(&dev->mt76, sskb, vif, sta, enable,
8651b83d17cSSean Wang 				      new_entry);
866d0e274afSLorenzo Bianconi 	if (enable && sta)
867f5056657SSean Wang 		mt76_connac_mcu_sta_tlv(phy->mt76, sskb, sta, vif, 0,
868f5056657SSean Wang 					MT76_STA_INFO_STATE_ASSOC);
86999c457d9SLorenzo Bianconi 
870d0e274afSLorenzo Bianconi 	wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(&dev->mt76, &msta->wcid,
871d0e274afSLorenzo Bianconi 						  WTBL_RESET_AND_SET, NULL,
872d0e274afSLorenzo Bianconi 						  &wskb);
87399c457d9SLorenzo Bianconi 	if (IS_ERR(wtbl_hdr))
87499c457d9SLorenzo Bianconi 		return PTR_ERR(wtbl_hdr);
87599c457d9SLorenzo Bianconi 
876b4985ff1SLorenzo Bianconi 	if (enable) {
877d0e274afSLorenzo Bianconi 		mt76_connac_mcu_wtbl_generic_tlv(&dev->mt76, wskb, vif, sta,
878d0e274afSLorenzo Bianconi 						 NULL, wtbl_hdr);
879b4985ff1SLorenzo Bianconi 		if (sta)
880d0e274afSLorenzo Bianconi 			mt76_connac_mcu_wtbl_ht_tlv(&dev->mt76, wskb, sta,
881499da720SMeiChia Chiu 						    NULL, wtbl_hdr, true, true);
882868fe07eSLorenzo Bianconi 		mt76_connac_mcu_wtbl_hdr_trans_tlv(wskb, vif, &msta->wcid,
883868fe07eSLorenzo Bianconi 						   NULL, wtbl_hdr);
884b4985ff1SLorenzo Bianconi 	}
88599c457d9SLorenzo Bianconi 
886e6d2070dSLorenzo Bianconi 	cmd = enable ? MCU_EXT_CMD(WTBL_UPDATE) : MCU_EXT_CMD(STA_REC_UPDATE);
88799c457d9SLorenzo Bianconi 	skb = enable ? wskb : sskb;
88899c457d9SLorenzo Bianconi 
889fa62d0e0SFelix Fietkau 	err = mt76_mcu_skb_send_msg(&dev->mt76, skb, cmd, true);
8902bccc841SLorenzo Bianconi 	if (err < 0) {
8912bccc841SLorenzo Bianconi 		skb = enable ? sskb : wskb;
8922bccc841SLorenzo Bianconi 		dev_kfree_skb(skb);
8932bccc841SLorenzo Bianconi 
89499c457d9SLorenzo Bianconi 		return err;
8952bccc841SLorenzo Bianconi 	}
89699c457d9SLorenzo Bianconi 
897e6d2070dSLorenzo Bianconi 	cmd = enable ? MCU_EXT_CMD(STA_REC_UPDATE) : MCU_EXT_CMD(WTBL_UPDATE);
89899c457d9SLorenzo Bianconi 	skb = enable ? sskb : wskb;
89999c457d9SLorenzo Bianconi 
900fa62d0e0SFelix Fietkau 	return mt76_mcu_skb_send_msg(&dev->mt76, skb, cmd, true);
90199c457d9SLorenzo Bianconi }
90299c457d9SLorenzo Bianconi 
90354c31b9eSLorenzo Bianconi static int
mt7615_mcu_wtbl_update_hdr_trans(struct mt7615_dev * dev,struct ieee80211_vif * vif,struct ieee80211_sta * sta)90454c31b9eSLorenzo Bianconi mt7615_mcu_wtbl_update_hdr_trans(struct mt7615_dev *dev,
90554c31b9eSLorenzo Bianconi 				 struct ieee80211_vif *vif,
90654c31b9eSLorenzo Bianconi 				 struct ieee80211_sta *sta)
90754c31b9eSLorenzo Bianconi {
9085a521c0fSLorenzo Bianconi 	return mt76_connac_mcu_wtbl_update_hdr_trans(&dev->mt76, vif, sta);
90954c31b9eSLorenzo Bianconi }
91054c31b9eSLorenzo Bianconi 
9116f4d7cc8SLorenzo Bianconi static const struct mt7615_mcu_ops wtbl_update_ops = {
912062c3699SLorenzo Bianconi 	.add_beacon_offload = mt7615_mcu_add_beacon_offload,
913062c3699SLorenzo Bianconi 	.set_pm_state = mt7615_mcu_ctrl_pm_state,
914062c3699SLorenzo Bianconi 	.add_dev_info = mt7615_mcu_add_dev,
915062c3699SLorenzo Bianconi 	.add_bss_info = mt7615_mcu_add_bss,
9166f4d7cc8SLorenzo Bianconi 	.add_tx_ba = mt7615_mcu_wtbl_tx_ba,
9176f4d7cc8SLorenzo Bianconi 	.add_rx_ba = mt7615_mcu_wtbl_rx_ba,
91899c457d9SLorenzo Bianconi 	.sta_add = mt7615_mcu_wtbl_sta_add,
919186b659cSLorenzo Bianconi 	.set_drv_ctrl = mt7615_mcu_drv_pmctrl,
920186b659cSLorenzo Bianconi 	.set_fw_ctrl = mt7615_mcu_fw_pmctrl,
92154c31b9eSLorenzo Bianconi 	.set_sta_decap_offload = mt7615_mcu_wtbl_update_hdr_trans,
9226f4d7cc8SLorenzo Bianconi };
9236f4d7cc8SLorenzo Bianconi 
9246f4d7cc8SLorenzo Bianconi static int
mt7615_mcu_sta_ba(struct mt7615_dev * dev,struct ieee80211_ampdu_params * params,bool enable,bool tx)9256f4d7cc8SLorenzo Bianconi mt7615_mcu_sta_ba(struct mt7615_dev *dev,
9266f4d7cc8SLorenzo Bianconi 		  struct ieee80211_ampdu_params *params,
9276f4d7cc8SLorenzo Bianconi 		  bool enable, bool tx)
9286f4d7cc8SLorenzo Bianconi {
9296f4d7cc8SLorenzo Bianconi 	struct mt7615_sta *msta = (struct mt7615_sta *)params->sta->drv_priv;
9306f4d7cc8SLorenzo Bianconi 	struct mt7615_vif *mvif = msta->vif;
9316f4d7cc8SLorenzo Bianconi 	struct wtbl_req_hdr *wtbl_hdr;
9326f4d7cc8SLorenzo Bianconi 	struct tlv *sta_wtbl;
9336f4d7cc8SLorenzo Bianconi 	struct sk_buff *skb;
9346f4d7cc8SLorenzo Bianconi 
935d0e274afSLorenzo Bianconi 	skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
936d0e274afSLorenzo Bianconi 					    &msta->wcid);
9376f4d7cc8SLorenzo Bianconi 	if (IS_ERR(skb))
9386f4d7cc8SLorenzo Bianconi 		return PTR_ERR(skb);
9396f4d7cc8SLorenzo Bianconi 
940d0e274afSLorenzo Bianconi 	mt76_connac_mcu_sta_ba_tlv(skb, params, enable, tx);
9418327cd82SLorenzo Bianconi 
942d0e274afSLorenzo Bianconi 	sta_wtbl = mt76_connac_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv));
9436f4d7cc8SLorenzo Bianconi 
944d0e274afSLorenzo Bianconi 	wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(&dev->mt76, &msta->wcid,
945d0e274afSLorenzo Bianconi 						  WTBL_SET, sta_wtbl, &skb);
946baa3afb3SLorenzo Bianconi 	if (IS_ERR(wtbl_hdr))
947baa3afb3SLorenzo Bianconi 		return PTR_ERR(wtbl_hdr);
948baa3afb3SLorenzo Bianconi 
949d0e274afSLorenzo Bianconi 	mt76_connac_mcu_wtbl_ba_tlv(&dev->mt76, skb, params, enable, tx,
950d0e274afSLorenzo Bianconi 				    sta_wtbl, wtbl_hdr);
9516f4d7cc8SLorenzo Bianconi 
952fa62d0e0SFelix Fietkau 	return mt76_mcu_skb_send_msg(&dev->mt76, skb,
953e6d2070dSLorenzo Bianconi 				     MCU_EXT_CMD(STA_REC_UPDATE), true);
9546f4d7cc8SLorenzo Bianconi }
9556f4d7cc8SLorenzo Bianconi 
9566f4d7cc8SLorenzo Bianconi static int
mt7615_mcu_sta_tx_ba(struct mt7615_dev * dev,struct ieee80211_ampdu_params * params,bool enable)9576f4d7cc8SLorenzo Bianconi mt7615_mcu_sta_tx_ba(struct mt7615_dev *dev,
9586f4d7cc8SLorenzo Bianconi 		     struct ieee80211_ampdu_params *params,
9596f4d7cc8SLorenzo Bianconi 		     bool enable)
9606f4d7cc8SLorenzo Bianconi {
9616f4d7cc8SLorenzo Bianconi 	return mt7615_mcu_sta_ba(dev, params, enable, true);
9626f4d7cc8SLorenzo Bianconi }
9636f4d7cc8SLorenzo Bianconi 
9646f4d7cc8SLorenzo Bianconi static int
mt7615_mcu_sta_rx_ba(struct mt7615_dev * dev,struct ieee80211_ampdu_params * params,bool enable)9656f4d7cc8SLorenzo Bianconi mt7615_mcu_sta_rx_ba(struct mt7615_dev *dev,
9666f4d7cc8SLorenzo Bianconi 		     struct ieee80211_ampdu_params *params,
9676f4d7cc8SLorenzo Bianconi 		     bool enable)
9686f4d7cc8SLorenzo Bianconi {
9696f4d7cc8SLorenzo Bianconi 	return mt7615_mcu_sta_ba(dev, params, enable, false);
9706f4d7cc8SLorenzo Bianconi }
9716f4d7cc8SLorenzo Bianconi 
97299c457d9SLorenzo Bianconi static int
__mt7615_mcu_add_sta(struct mt76_phy * phy,struct ieee80211_vif * vif,struct ieee80211_sta * sta,bool enable,int cmd,bool offload_fw)973d0e274afSLorenzo Bianconi __mt7615_mcu_add_sta(struct mt76_phy *phy, struct ieee80211_vif *vif,
97482453b1cSLorenzo Bianconi 		     struct ieee80211_sta *sta, bool enable, int cmd,
97582453b1cSLorenzo Bianconi 		     bool offload_fw)
97699c457d9SLorenzo Bianconi {
97799c457d9SLorenzo Bianconi 	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
9785802106fSLorenzo Bianconi 	struct mt76_sta_cmd_info info = {
9795802106fSLorenzo Bianconi 		.sta = sta,
9805802106fSLorenzo Bianconi 		.vif = vif,
98182453b1cSLorenzo Bianconi 		.offload_fw = offload_fw,
9825802106fSLorenzo Bianconi 		.enable = enable,
983f5056657SSean Wang 		.newly = true,
9845802106fSLorenzo Bianconi 		.cmd = cmd,
9855802106fSLorenzo Bianconi 	};
98699c457d9SLorenzo Bianconi 
9875802106fSLorenzo Bianconi 	info.wcid = sta ? (struct mt76_wcid *)sta->drv_priv : &mvif->sta.wcid;
988f5056657SSean Wang 	return mt76_connac_mcu_sta_cmd(phy, &info);
989af44ce4fSLorenzo Bianconi }
990af44ce4fSLorenzo Bianconi 
991af44ce4fSLorenzo Bianconi static int
mt7615_mcu_add_sta(struct mt7615_phy * phy,struct ieee80211_vif * vif,struct ieee80211_sta * sta,bool enable)992d0e274afSLorenzo Bianconi mt7615_mcu_add_sta(struct mt7615_phy *phy, struct ieee80211_vif *vif,
993af44ce4fSLorenzo Bianconi 		   struct ieee80211_sta *sta, bool enable)
994af44ce4fSLorenzo Bianconi {
995d0e274afSLorenzo Bianconi 	return __mt7615_mcu_add_sta(phy->mt76, vif, sta, enable,
996e6d2070dSLorenzo Bianconi 				    MCU_EXT_CMD(STA_REC_UPDATE), false);
99799c457d9SLorenzo Bianconi }
99899c457d9SLorenzo Bianconi 
99954c31b9eSLorenzo Bianconi static int
mt7615_mcu_sta_update_hdr_trans(struct mt7615_dev * dev,struct ieee80211_vif * vif,struct ieee80211_sta * sta)100054c31b9eSLorenzo Bianconi mt7615_mcu_sta_update_hdr_trans(struct mt7615_dev *dev,
100154c31b9eSLorenzo Bianconi 				struct ieee80211_vif *vif,
100254c31b9eSLorenzo Bianconi 				struct ieee80211_sta *sta)
100354c31b9eSLorenzo Bianconi {
100454c31b9eSLorenzo Bianconi 	struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv;
100554c31b9eSLorenzo Bianconi 
100654c31b9eSLorenzo Bianconi 	return mt76_connac_mcu_sta_update_hdr_trans(&dev->mt76,
100754c31b9eSLorenzo Bianconi 						    vif, &msta->wcid,
1008e6d2070dSLorenzo Bianconi 						    MCU_EXT_CMD(STA_REC_UPDATE));
100954c31b9eSLorenzo Bianconi }
101054c31b9eSLorenzo Bianconi 
10116f4d7cc8SLorenzo Bianconi static const struct mt7615_mcu_ops sta_update_ops = {
1012062c3699SLorenzo Bianconi 	.add_beacon_offload = mt7615_mcu_add_beacon_offload,
1013062c3699SLorenzo Bianconi 	.set_pm_state = mt7615_mcu_ctrl_pm_state,
1014062c3699SLorenzo Bianconi 	.add_dev_info = mt7615_mcu_add_dev,
1015062c3699SLorenzo Bianconi 	.add_bss_info = mt7615_mcu_add_bss,
10166f4d7cc8SLorenzo Bianconi 	.add_tx_ba = mt7615_mcu_sta_tx_ba,
10176f4d7cc8SLorenzo Bianconi 	.add_rx_ba = mt7615_mcu_sta_rx_ba,
101899c457d9SLorenzo Bianconi 	.sta_add = mt7615_mcu_add_sta,
1019186b659cSLorenzo Bianconi 	.set_drv_ctrl = mt7615_mcu_drv_pmctrl,
1020186b659cSLorenzo Bianconi 	.set_fw_ctrl = mt7615_mcu_fw_pmctrl,
102154c31b9eSLorenzo Bianconi 	.set_sta_decap_offload = mt7615_mcu_sta_update_hdr_trans,
10226f4d7cc8SLorenzo Bianconi };
10236f4d7cc8SLorenzo Bianconi 
1024af44ce4fSLorenzo Bianconi static int
mt7615_mcu_uni_ctrl_pm_state(struct mt7615_dev * dev,int band,int state)102513886067SSean Wang mt7615_mcu_uni_ctrl_pm_state(struct mt7615_dev *dev, int band, int state)
102613886067SSean Wang {
102713886067SSean Wang 	return 0;
102813886067SSean Wang }
102913886067SSean Wang 
103013886067SSean Wang static int
mt7615_mcu_uni_add_beacon_offload(struct mt7615_dev * dev,struct ieee80211_hw * hw,struct ieee80211_vif * vif,bool enable)103113886067SSean Wang mt7615_mcu_uni_add_beacon_offload(struct mt7615_dev *dev,
103213886067SSean Wang 				  struct ieee80211_hw *hw,
103313886067SSean Wang 				  struct ieee80211_vif *vif,
103413886067SSean Wang 				  bool enable)
103513886067SSean Wang {
103613886067SSean Wang 	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
103713886067SSean Wang 	struct mt76_wcid *wcid = &dev->mt76.global_wcid;
103813886067SSean Wang 	struct ieee80211_mutable_offsets offs;
103913886067SSean Wang 	struct {
104013886067SSean Wang 		struct req_hdr {
104113886067SSean Wang 			u8 bss_idx;
104213886067SSean Wang 			u8 pad[3];
104313886067SSean Wang 		} __packed hdr;
104413886067SSean Wang 		struct bcn_content_tlv {
104513886067SSean Wang 			__le16 tag;
104613886067SSean Wang 			__le16 len;
104713886067SSean Wang 			__le16 tim_ie_pos;
104813886067SSean Wang 			__le16 csa_ie_pos;
104913886067SSean Wang 			__le16 bcc_ie_pos;
10508a5a5dbfSRyder Lee 			/* 0: disable beacon offload
10518a5a5dbfSRyder Lee 			 * 1: enable beacon offload
105213886067SSean Wang 			 * 2: update probe respond offload
105313886067SSean Wang 			 */
105413886067SSean Wang 			u8 enable;
105513886067SSean Wang 			/* 0: legacy format (TXD + payload)
105613886067SSean Wang 			 * 1: only cap field IE
105713886067SSean Wang 			 */
105813886067SSean Wang 			u8 type;
105913886067SSean Wang 			__le16 pkt_len;
106013886067SSean Wang 			u8 pkt[512];
106113886067SSean Wang 		} __packed beacon_tlv;
106213886067SSean Wang 	} req = {
106313886067SSean Wang 		.hdr = {
106485d96704SLorenzo Bianconi 			.bss_idx = mvif->mt76.idx,
106513886067SSean Wang 		},
106613886067SSean Wang 		.beacon_tlv = {
106713886067SSean Wang 			.tag = cpu_to_le16(UNI_BSS_INFO_BCN_CONTENT),
106813886067SSean Wang 			.len = cpu_to_le16(sizeof(struct bcn_content_tlv)),
106913886067SSean Wang 			.enable = enable,
107013886067SSean Wang 		},
107113886067SSean Wang 	};
107213886067SSean Wang 	struct sk_buff *skb;
107313886067SSean Wang 
10748a5a5dbfSRyder Lee 	if (!enable)
10758a5a5dbfSRyder Lee 		goto out;
10768a5a5dbfSRyder Lee 
10776e8912a5SShaul Triebitz 	skb = ieee80211_beacon_get_template(mt76_hw(dev), vif, &offs, 0);
107813886067SSean Wang 	if (!skb)
107913886067SSean Wang 		return -EINVAL;
108013886067SSean Wang 
108113886067SSean Wang 	if (skb->len > 512 - MT_TXD_SIZE) {
108213886067SSean Wang 		dev_err(dev->mt76.dev, "beacon size limit exceed\n");
108313886067SSean Wang 		dev_kfree_skb(skb);
108413886067SSean Wang 		return -EINVAL;
108513886067SSean Wang 	}
108613886067SSean Wang 
108713886067SSean Wang 	mt7615_mac_write_txwi(dev, (__le32 *)(req.beacon_tlv.pkt), skb,
10881d5af0acSFelix Fietkau 			      wcid, NULL, 0, NULL, 0, true);
108913886067SSean Wang 	memcpy(req.beacon_tlv.pkt + MT_TXD_SIZE, skb->data, skb->len);
109013886067SSean Wang 	req.beacon_tlv.pkt_len = cpu_to_le16(MT_TXD_SIZE + skb->len);
109113886067SSean Wang 	req.beacon_tlv.tim_ie_pos = cpu_to_le16(MT_TXD_SIZE + offs.tim_offset);
109213886067SSean Wang 
10938552a434SJohn Crispin 	if (offs.cntdwn_counter_offs[0]) {
109413886067SSean Wang 		u16 csa_offs;
109513886067SSean Wang 
10968552a434SJohn Crispin 		csa_offs = MT_TXD_SIZE + offs.cntdwn_counter_offs[0] - 4;
109713886067SSean Wang 		req.beacon_tlv.csa_ie_pos = cpu_to_le16(csa_offs);
109813886067SSean Wang 	}
109913886067SSean Wang 	dev_kfree_skb(skb);
110013886067SSean Wang 
11018a5a5dbfSRyder Lee out:
110254722402SLorenzo Bianconi 	return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(BSS_INFO_UPDATE),
110313886067SSean Wang 				 &req, sizeof(req), true);
110413886067SSean Wang }
110513886067SSean Wang 
110613886067SSean Wang static int
mt7615_mcu_uni_add_dev(struct mt7615_phy * phy,struct ieee80211_vif * vif,bool enable)1107d0e274afSLorenzo Bianconi mt7615_mcu_uni_add_dev(struct mt7615_phy *phy, struct ieee80211_vif *vif,
1108d0e274afSLorenzo Bianconi 		       bool enable)
1109d0e274afSLorenzo Bianconi {
1110d0e274afSLorenzo Bianconi 	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
1111d0e274afSLorenzo Bianconi 
1112d0e274afSLorenzo Bianconi 	return mt76_connac_mcu_uni_add_dev(phy->mt76, vif, &mvif->sta.wcid,
1113d0e274afSLorenzo Bianconi 					   enable);
1114d0e274afSLorenzo Bianconi }
1115d0e274afSLorenzo Bianconi 
1116d0e274afSLorenzo Bianconi static int
mt7615_mcu_uni_add_bss(struct mt7615_phy * phy,struct ieee80211_vif * vif,struct ieee80211_sta * sta,bool enable)1117d0e274afSLorenzo Bianconi mt7615_mcu_uni_add_bss(struct mt7615_phy *phy, struct ieee80211_vif *vif,
1118d0e274afSLorenzo Bianconi 		       struct ieee80211_sta *sta, bool enable)
1119d0e274afSLorenzo Bianconi {
1120d0e274afSLorenzo Bianconi 	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
1121d0e274afSLorenzo Bianconi 
1122d0e274afSLorenzo Bianconi 	return mt76_connac_mcu_uni_add_bss(phy->mt76, vif, &mvif->sta.wcid,
1123a0ab9c31SSean Wang 					   enable, NULL);
1124d0e274afSLorenzo Bianconi }
1125d0e274afSLorenzo Bianconi 
1126d0e274afSLorenzo Bianconi static inline int
mt7615_mcu_uni_add_sta(struct mt7615_phy * phy,struct ieee80211_vif * vif,struct ieee80211_sta * sta,bool enable)1127d0e274afSLorenzo Bianconi mt7615_mcu_uni_add_sta(struct mt7615_phy *phy, struct ieee80211_vif *vif,
1128d0e274afSLorenzo Bianconi 		       struct ieee80211_sta *sta, bool enable)
1129d0e274afSLorenzo Bianconi {
1130d0e274afSLorenzo Bianconi 	return __mt7615_mcu_add_sta(phy->mt76, vif, sta, enable,
113154722402SLorenzo Bianconi 				    MCU_UNI_CMD(STA_REC_UPDATE), true);
1132d0e274afSLorenzo Bianconi }
1133d0e274afSLorenzo Bianconi 
1134d0e274afSLorenzo Bianconi static int
mt7615_mcu_uni_tx_ba(struct mt7615_dev * dev,struct ieee80211_ampdu_params * params,bool enable)1135c686a35cSLorenzo Bianconi mt7615_mcu_uni_tx_ba(struct mt7615_dev *dev,
1136c686a35cSLorenzo Bianconi 		     struct ieee80211_ampdu_params *params,
1137c686a35cSLorenzo Bianconi 		     bool enable)
1138c686a35cSLorenzo Bianconi {
1139d0e274afSLorenzo Bianconi 	struct mt7615_sta *sta = (struct mt7615_sta *)params->sta->drv_priv;
1140c686a35cSLorenzo Bianconi 
1141d0e274afSLorenzo Bianconi 	return mt76_connac_mcu_sta_ba(&dev->mt76, &sta->vif->mt76, params,
1142b5322e44SLorenzo Bianconi 				      MCU_UNI_CMD(STA_REC_UPDATE), enable,
1143b5322e44SLorenzo Bianconi 				      true);
1144c686a35cSLorenzo Bianconi }
1145c686a35cSLorenzo Bianconi 
1146c686a35cSLorenzo Bianconi static int
mt7615_mcu_uni_rx_ba(struct mt7615_dev * dev,struct ieee80211_ampdu_params * params,bool enable)1147c686a35cSLorenzo Bianconi mt7615_mcu_uni_rx_ba(struct mt7615_dev *dev,
1148c686a35cSLorenzo Bianconi 		     struct ieee80211_ampdu_params *params,
1149c686a35cSLorenzo Bianconi 		     bool enable)
1150c686a35cSLorenzo Bianconi {
1151c686a35cSLorenzo Bianconi 	struct mt7615_sta *msta = (struct mt7615_sta *)params->sta->drv_priv;
1152c686a35cSLorenzo Bianconi 	struct mt7615_vif *mvif = msta->vif;
1153c686a35cSLorenzo Bianconi 	struct wtbl_req_hdr *wtbl_hdr;
1154c686a35cSLorenzo Bianconi 	struct tlv *sta_wtbl;
1155c686a35cSLorenzo Bianconi 	struct sk_buff *skb;
1156c686a35cSLorenzo Bianconi 	int err;
1157c686a35cSLorenzo Bianconi 
1158d0e274afSLorenzo Bianconi 	skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
1159d0e274afSLorenzo Bianconi 					    &msta->wcid);
1160c686a35cSLorenzo Bianconi 	if (IS_ERR(skb))
1161c686a35cSLorenzo Bianconi 		return PTR_ERR(skb);
1162c686a35cSLorenzo Bianconi 
1163d0e274afSLorenzo Bianconi 	mt76_connac_mcu_sta_ba_tlv(skb, params, enable, false);
1164c686a35cSLorenzo Bianconi 
1165fa62d0e0SFelix Fietkau 	err = mt76_mcu_skb_send_msg(&dev->mt76, skb,
116654722402SLorenzo Bianconi 				    MCU_UNI_CMD(STA_REC_UPDATE), true);
1167c686a35cSLorenzo Bianconi 	if (err < 0 || !enable)
1168c686a35cSLorenzo Bianconi 		return err;
1169c686a35cSLorenzo Bianconi 
1170d0e274afSLorenzo Bianconi 	skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
1171d0e274afSLorenzo Bianconi 					    &msta->wcid);
1172c686a35cSLorenzo Bianconi 	if (IS_ERR(skb))
1173c686a35cSLorenzo Bianconi 		return PTR_ERR(skb);
1174c686a35cSLorenzo Bianconi 
1175d0e274afSLorenzo Bianconi 	sta_wtbl = mt76_connac_mcu_add_tlv(skb, STA_REC_WTBL,
1176d0e274afSLorenzo Bianconi 					   sizeof(struct tlv));
1177c686a35cSLorenzo Bianconi 
1178d0e274afSLorenzo Bianconi 	wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(&dev->mt76, &msta->wcid,
1179d0e274afSLorenzo Bianconi 						  WTBL_SET, sta_wtbl, &skb);
1180c686a35cSLorenzo Bianconi 	if (IS_ERR(wtbl_hdr))
1181c686a35cSLorenzo Bianconi 		return PTR_ERR(wtbl_hdr);
1182c686a35cSLorenzo Bianconi 
1183d0e274afSLorenzo Bianconi 	mt76_connac_mcu_wtbl_ba_tlv(&dev->mt76, skb, params, enable, false,
1184d0e274afSLorenzo Bianconi 				    sta_wtbl, wtbl_hdr);
1185c686a35cSLorenzo Bianconi 
1186fa62d0e0SFelix Fietkau 	return mt76_mcu_skb_send_msg(&dev->mt76, skb,
118754722402SLorenzo Bianconi 				     MCU_UNI_CMD(STA_REC_UPDATE), true);
1188c686a35cSLorenzo Bianconi }
1189c686a35cSLorenzo Bianconi 
119054c31b9eSLorenzo Bianconi static int
mt7615_mcu_sta_uni_update_hdr_trans(struct mt7615_dev * dev,struct ieee80211_vif * vif,struct ieee80211_sta * sta)119154c31b9eSLorenzo Bianconi mt7615_mcu_sta_uni_update_hdr_trans(struct mt7615_dev *dev,
119254c31b9eSLorenzo Bianconi 				    struct ieee80211_vif *vif,
119354c31b9eSLorenzo Bianconi 				    struct ieee80211_sta *sta)
119454c31b9eSLorenzo Bianconi {
119554c31b9eSLorenzo Bianconi 	struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv;
119654c31b9eSLorenzo Bianconi 
119754c31b9eSLorenzo Bianconi 	return mt76_connac_mcu_sta_update_hdr_trans(&dev->mt76,
119854c31b9eSLorenzo Bianconi 						    vif, &msta->wcid,
119954722402SLorenzo Bianconi 						    MCU_UNI_CMD(STA_REC_UPDATE));
120054c31b9eSLorenzo Bianconi }
120154c31b9eSLorenzo Bianconi 
1202af44ce4fSLorenzo Bianconi static const struct mt7615_mcu_ops uni_update_ops = {
120313886067SSean Wang 	.add_beacon_offload = mt7615_mcu_uni_add_beacon_offload,
120413886067SSean Wang 	.set_pm_state = mt7615_mcu_uni_ctrl_pm_state,
120513886067SSean Wang 	.add_dev_info = mt7615_mcu_uni_add_dev,
120613886067SSean Wang 	.add_bss_info = mt7615_mcu_uni_add_bss,
1207c686a35cSLorenzo Bianconi 	.add_tx_ba = mt7615_mcu_uni_tx_ba,
1208c686a35cSLorenzo Bianconi 	.add_rx_ba = mt7615_mcu_uni_rx_ba,
1209af44ce4fSLorenzo Bianconi 	.sta_add = mt7615_mcu_uni_add_sta,
12106892555dSLorenzo Bianconi 	.set_drv_ctrl = mt7615_mcu_lp_drv_pmctrl,
1211186b659cSLorenzo Bianconi 	.set_fw_ctrl = mt7615_mcu_fw_pmctrl,
121254c31b9eSLorenzo Bianconi 	.set_sta_decap_offload = mt7615_mcu_sta_uni_update_hdr_trans,
1213af44ce4fSLorenzo Bianconi };
1214af44ce4fSLorenzo Bianconi 
mt7615_mcu_restart(struct mt76_dev * dev)1215e90354e0SLorenzo Bianconi int mt7615_mcu_restart(struct mt76_dev *dev)
121604b8e659SRyder Lee {
1217ffc2198dSLorenzo Bianconi 	return mt76_mcu_send_msg(dev, MCU_CMD(RESTART_DL_REQ), NULL, 0, true);
121804b8e659SRyder Lee }
1219e90354e0SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt7615_mcu_restart);
122004b8e659SRyder Lee 
mt7615_load_patch(struct mt7615_dev * dev,u32 addr,const char * name)122135da599fSFelix Fietkau static int mt7615_load_patch(struct mt7615_dev *dev, u32 addr, const char *name)
122204b8e659SRyder Lee {
12232fc44648SLorenzo Bianconi 	const struct mt7615_patch_hdr *hdr;
12242fc44648SLorenzo Bianconi 	const struct firmware *fw = NULL;
122504b8e659SRyder Lee 	int len, ret, sem;
122604b8e659SRyder Lee 
1227f2dc8ea1SLorenzo Bianconi 	ret = firmware_request_nowarn(&fw, name, dev->mt76.dev);
122804b8e659SRyder Lee 	if (ret)
12294efcfd5cSFelix Fietkau 		return ret;
123004b8e659SRyder Lee 
123104b8e659SRyder Lee 	if (!fw || !fw->data || fw->size < sizeof(*hdr)) {
123204b8e659SRyder Lee 		dev_err(dev->mt76.dev, "Invalid firmware\n");
123304b8e659SRyder Lee 		ret = -EINVAL;
12344efcfd5cSFelix Fietkau 		goto release_fw;
12354efcfd5cSFelix Fietkau 	}
12364efcfd5cSFelix Fietkau 
12374efcfd5cSFelix Fietkau 	sem = mt76_connac_mcu_patch_sem_ctrl(&dev->mt76, true);
12384efcfd5cSFelix Fietkau 	switch (sem) {
12394efcfd5cSFelix Fietkau 	case PATCH_IS_DL:
12404efcfd5cSFelix Fietkau 		goto release_fw;
12414efcfd5cSFelix Fietkau 	case PATCH_NOT_DL_SEM_SUCCESS:
12424efcfd5cSFelix Fietkau 		break;
12434efcfd5cSFelix Fietkau 	default:
12444efcfd5cSFelix Fietkau 		dev_err(dev->mt76.dev, "Failed to get patch semaphore\n");
12454efcfd5cSFelix Fietkau 		ret = -EAGAIN;
12464efcfd5cSFelix Fietkau 		goto release_fw;
124704b8e659SRyder Lee 	}
124804b8e659SRyder Lee 
124904b8e659SRyder Lee 	hdr = (const struct mt7615_patch_hdr *)(fw->data);
125004b8e659SRyder Lee 
125104b8e659SRyder Lee 	dev_info(dev->mt76.dev, "HW/SW Version: 0x%x, Build Time: %.16s\n",
125204b8e659SRyder Lee 		 be32_to_cpu(hdr->hw_sw_ver), hdr->build_date);
125304b8e659SRyder Lee 
125404b8e659SRyder Lee 	len = fw->size - sizeof(*hdr);
125504b8e659SRyder Lee 
1256d0e274afSLorenzo Bianconi 	ret = mt76_connac_mcu_init_download(&dev->mt76, addr, len,
1257d0e274afSLorenzo Bianconi 					    DL_MODE_NEED_RSP);
125804b8e659SRyder Lee 	if (ret) {
125904b8e659SRyder Lee 		dev_err(dev->mt76.dev, "Download request failed\n");
126004b8e659SRyder Lee 		goto out;
126104b8e659SRyder Lee 	}
126204b8e659SRyder Lee 
1263ffc2198dSLorenzo Bianconi 	ret = mt76_mcu_send_firmware(&dev->mt76, MCU_CMD(FW_SCATTER),
12643cb43b66SLorenzo Bianconi 				     fw->data + sizeof(*hdr), len);
126504b8e659SRyder Lee 	if (ret) {
126604b8e659SRyder Lee 		dev_err(dev->mt76.dev, "Failed to send firmware to device\n");
126704b8e659SRyder Lee 		goto out;
126804b8e659SRyder Lee 	}
126904b8e659SRyder Lee 
1270d0e274afSLorenzo Bianconi 	ret = mt76_connac_mcu_start_patch(&dev->mt76);
127104b8e659SRyder Lee 	if (ret)
127204b8e659SRyder Lee 		dev_err(dev->mt76.dev, "Failed to start patch\n");
127304b8e659SRyder Lee 
127404b8e659SRyder Lee out:
1275d0e274afSLorenzo Bianconi 	sem = mt76_connac_mcu_patch_sem_ctrl(&dev->mt76, false);
127604b8e659SRyder Lee 	switch (sem) {
127704b8e659SRyder Lee 	case PATCH_REL_SEM_SUCCESS:
127804b8e659SRyder Lee 		break;
127904b8e659SRyder Lee 	default:
128004b8e659SRyder Lee 		ret = -EAGAIN;
128104b8e659SRyder Lee 		dev_err(dev->mt76.dev, "Failed to release patch semaphore\n");
128204b8e659SRyder Lee 		break;
128304b8e659SRyder Lee 	}
128404b8e659SRyder Lee 
12854efcfd5cSFelix Fietkau release_fw:
12864efcfd5cSFelix Fietkau 	release_firmware(fw);
12874efcfd5cSFelix Fietkau 
128804b8e659SRyder Lee 	return ret;
128904b8e659SRyder Lee }
129004b8e659SRyder Lee 
12916c6a3fe6SLorenzo Bianconi static int
mt7615_mcu_send_ram_firmware(struct mt7615_dev * dev,const struct mt7615_fw_trailer * hdr,const u8 * data,bool is_cr4)12926c6a3fe6SLorenzo Bianconi mt7615_mcu_send_ram_firmware(struct mt7615_dev *dev,
12936c6a3fe6SLorenzo Bianconi 			     const struct mt7615_fw_trailer *hdr,
12946c6a3fe6SLorenzo Bianconi 			     const u8 *data, bool is_cr4)
12956c6a3fe6SLorenzo Bianconi {
12966c6a3fe6SLorenzo Bianconi 	int n_region = is_cr4 ? CR4_REGION_NUM : N9_REGION_NUM;
12976c6a3fe6SLorenzo Bianconi 	int err, i, offset = 0;
12986c6a3fe6SLorenzo Bianconi 	u32 len, addr, mode;
12996c6a3fe6SLorenzo Bianconi 
13006c6a3fe6SLorenzo Bianconi 	for (i = 0; i < n_region; i++) {
13019e90c351SLorenzo Bianconi 		mode = mt76_connac_mcu_gen_dl_mode(&dev->mt76,
13029e90c351SLorenzo Bianconi 						   hdr[i].feature_set, is_cr4);
13036c6a3fe6SLorenzo Bianconi 		len = le32_to_cpu(hdr[i].len) + IMG_CRC_LEN;
13046c6a3fe6SLorenzo Bianconi 		addr = le32_to_cpu(hdr[i].addr);
13056c6a3fe6SLorenzo Bianconi 
1306d0e274afSLorenzo Bianconi 		err = mt76_connac_mcu_init_download(&dev->mt76, addr, len,
1307d0e274afSLorenzo Bianconi 						    mode);
13086c6a3fe6SLorenzo Bianconi 		if (err) {
13096c6a3fe6SLorenzo Bianconi 			dev_err(dev->mt76.dev, "Download request failed\n");
13106c6a3fe6SLorenzo Bianconi 			return err;
13116c6a3fe6SLorenzo Bianconi 		}
13126c6a3fe6SLorenzo Bianconi 
1313ffc2198dSLorenzo Bianconi 		err = mt76_mcu_send_firmware(&dev->mt76, MCU_CMD(FW_SCATTER),
13143cb43b66SLorenzo Bianconi 					     data + offset, len);
13156c6a3fe6SLorenzo Bianconi 		if (err) {
13166c6a3fe6SLorenzo Bianconi 			dev_err(dev->mt76.dev, "Failed to send firmware to device\n");
13176c6a3fe6SLorenzo Bianconi 			return err;
13186c6a3fe6SLorenzo Bianconi 		}
13196c6a3fe6SLorenzo Bianconi 
13206c6a3fe6SLorenzo Bianconi 		offset += len;
13216c6a3fe6SLorenzo Bianconi 	}
13226c6a3fe6SLorenzo Bianconi 
13236c6a3fe6SLorenzo Bianconi 	return 0;
13246c6a3fe6SLorenzo Bianconi }
13256c6a3fe6SLorenzo Bianconi 
mt7615_load_n9(struct mt7615_dev * dev,const char * name)13261c88e7e0SFelix Fietkau static int mt7615_load_n9(struct mt7615_dev *dev, const char *name)
132704b8e659SRyder Lee {
132804b8e659SRyder Lee 	const struct mt7615_fw_trailer *hdr;
13299d4d0d06SLorenzo Bianconi 	const struct firmware *fw;
13306c6a3fe6SLorenzo Bianconi 	int ret;
133104b8e659SRyder Lee 
13321c88e7e0SFelix Fietkau 	ret = request_firmware(&fw, name, dev->mt76.dev);
133304b8e659SRyder Lee 	if (ret)
133404b8e659SRyder Lee 		return ret;
133504b8e659SRyder Lee 
133604b8e659SRyder Lee 	if (!fw || !fw->data || fw->size < N9_REGION_NUM * sizeof(*hdr)) {
133704b8e659SRyder Lee 		dev_err(dev->mt76.dev, "Invalid firmware\n");
133804b8e659SRyder Lee 		ret = -EINVAL;
133904b8e659SRyder Lee 		goto out;
134004b8e659SRyder Lee 	}
134104b8e659SRyder Lee 
134204b8e659SRyder Lee 	hdr = (const struct mt7615_fw_trailer *)(fw->data + fw->size -
134304b8e659SRyder Lee 					N9_REGION_NUM * sizeof(*hdr));
134404b8e659SRyder Lee 
134504b8e659SRyder Lee 	dev_info(dev->mt76.dev, "N9 Firmware Version: %.10s, Build Time: %.15s\n",
134604b8e659SRyder Lee 		 hdr->fw_ver, hdr->build_date);
134704b8e659SRyder Lee 
13486c6a3fe6SLorenzo Bianconi 	ret = mt7615_mcu_send_ram_firmware(dev, hdr, fw->data, false);
13496c6a3fe6SLorenzo Bianconi 	if (ret)
135004b8e659SRyder Lee 		goto out;
135104b8e659SRyder Lee 
1352d0e274afSLorenzo Bianconi 	ret = mt76_connac_mcu_start_firmware(&dev->mt76,
1353d0e274afSLorenzo Bianconi 					     le32_to_cpu(hdr->addr),
13546c6a3fe6SLorenzo Bianconi 					     FW_START_OVERRIDE);
135504b8e659SRyder Lee 	if (ret) {
135604b8e659SRyder Lee 		dev_err(dev->mt76.dev, "Failed to start N9 firmware\n");
135704b8e659SRyder Lee 		goto out;
135804b8e659SRyder Lee 	}
135904b8e659SRyder Lee 
13604e569727SFelix Fietkau 	snprintf(dev->mt76.hw->wiphy->fw_version,
13614e569727SFelix Fietkau 		 sizeof(dev->mt76.hw->wiphy->fw_version),
13624e569727SFelix Fietkau 		 "%.10s-%.15s", hdr->fw_ver, hdr->build_date);
13634e569727SFelix Fietkau 
1364d43c7301SRyder Lee 	if (!is_mt7615(&dev->mt76)) {
13656849e29eSRyder Lee 		dev->fw_ver = MT7615_FIRMWARE_V2;
13666f4d7cc8SLorenzo Bianconi 		dev->mcu_ops = &sta_update_ops;
13676f4d7cc8SLorenzo Bianconi 	} else {
13686849e29eSRyder Lee 		dev->fw_ver = MT7615_FIRMWARE_V1;
13696f4d7cc8SLorenzo Bianconi 		dev->mcu_ops = &wtbl_update_ops;
13706f4d7cc8SLorenzo Bianconi 	}
13716849e29eSRyder Lee 
13721c88e7e0SFelix Fietkau out:
137304b8e659SRyder Lee 	release_firmware(fw);
13741c88e7e0SFelix Fietkau 	return ret;
13751c88e7e0SFelix Fietkau }
137604b8e659SRyder Lee 
mt7615_load_cr4(struct mt7615_dev * dev,const char * name)13771c88e7e0SFelix Fietkau static int mt7615_load_cr4(struct mt7615_dev *dev, const char *name)
13781c88e7e0SFelix Fietkau {
13791c88e7e0SFelix Fietkau 	const struct mt7615_fw_trailer *hdr;
13801c88e7e0SFelix Fietkau 	const struct firmware *fw;
13811c88e7e0SFelix Fietkau 	int ret;
13821c88e7e0SFelix Fietkau 
13831c88e7e0SFelix Fietkau 	ret = request_firmware(&fw, name, dev->mt76.dev);
138404b8e659SRyder Lee 	if (ret)
138504b8e659SRyder Lee 		return ret;
138604b8e659SRyder Lee 
138704b8e659SRyder Lee 	if (!fw || !fw->data || fw->size < CR4_REGION_NUM * sizeof(*hdr)) {
138804b8e659SRyder Lee 		dev_err(dev->mt76.dev, "Invalid firmware\n");
138904b8e659SRyder Lee 		ret = -EINVAL;
139004b8e659SRyder Lee 		goto out;
139104b8e659SRyder Lee 	}
139204b8e659SRyder Lee 
139304b8e659SRyder Lee 	hdr = (const struct mt7615_fw_trailer *)(fw->data + fw->size -
139404b8e659SRyder Lee 					CR4_REGION_NUM * sizeof(*hdr));
139504b8e659SRyder Lee 
139604b8e659SRyder Lee 	dev_info(dev->mt76.dev, "CR4 Firmware Version: %.10s, Build Time: %.15s\n",
139704b8e659SRyder Lee 		 hdr->fw_ver, hdr->build_date);
139804b8e659SRyder Lee 
13996c6a3fe6SLorenzo Bianconi 	ret = mt7615_mcu_send_ram_firmware(dev, hdr, fw->data, true);
14006c6a3fe6SLorenzo Bianconi 	if (ret)
140104b8e659SRyder Lee 		goto out;
140204b8e659SRyder Lee 
1403d0e274afSLorenzo Bianconi 	ret = mt76_connac_mcu_start_firmware(&dev->mt76, 0,
1404d0e274afSLorenzo Bianconi 					     FW_START_WORKING_PDA_CR4);
1405175b4d58SLorenzo Bianconi 	if (ret) {
140604b8e659SRyder Lee 		dev_err(dev->mt76.dev, "Failed to start CR4 firmware\n");
1407175b4d58SLorenzo Bianconi 		goto out;
1408175b4d58SLorenzo Bianconi 	}
1409175b4d58SLorenzo Bianconi 
141004b8e659SRyder Lee out:
141104b8e659SRyder Lee 	release_firmware(fw);
141204b8e659SRyder Lee 
141304b8e659SRyder Lee 	return ret;
141404b8e659SRyder Lee }
141504b8e659SRyder Lee 
mt7615_load_ram(struct mt7615_dev * dev)14161c88e7e0SFelix Fietkau static int mt7615_load_ram(struct mt7615_dev *dev)
14171c88e7e0SFelix Fietkau {
14181c88e7e0SFelix Fietkau 	int ret;
14191c88e7e0SFelix Fietkau 
14201c88e7e0SFelix Fietkau 	ret = mt7615_load_n9(dev, MT7615_FIRMWARE_N9);
14211c88e7e0SFelix Fietkau 	if (ret)
14221c88e7e0SFelix Fietkau 		return ret;
14231c88e7e0SFelix Fietkau 
14241c88e7e0SFelix Fietkau 	return mt7615_load_cr4(dev, MT7615_FIRMWARE_CR4);
14251c88e7e0SFelix Fietkau }
14261c88e7e0SFelix Fietkau 
mt7615_load_firmware(struct mt7615_dev * dev)142704b8e659SRyder Lee static int mt7615_load_firmware(struct mt7615_dev *dev)
142804b8e659SRyder Lee {
142904b8e659SRyder Lee 	int ret;
143004b8e659SRyder Lee 	u32 val;
143104b8e659SRyder Lee 
143204b8e659SRyder Lee 	val = mt76_get_field(dev, MT_TOP_MISC2, MT_TOP_MISC2_FW_STATE);
143304b8e659SRyder Lee 
143404b8e659SRyder Lee 	if (val != FW_STATE_FW_DOWNLOAD) {
143504b8e659SRyder Lee 		dev_err(dev->mt76.dev, "Firmware is not ready for download\n");
143604b8e659SRyder Lee 		return -EIO;
143704b8e659SRyder Lee 	}
143804b8e659SRyder Lee 
143935da599fSFelix Fietkau 	ret = mt7615_load_patch(dev, MT7615_PATCH_ADDRESS, MT7615_ROM_PATCH);
144004b8e659SRyder Lee 	if (ret)
144104b8e659SRyder Lee 		return ret;
144204b8e659SRyder Lee 
144304b8e659SRyder Lee 	ret = mt7615_load_ram(dev);
144404b8e659SRyder Lee 	if (ret)
144504b8e659SRyder Lee 		return ret;
144604b8e659SRyder Lee 
144704b8e659SRyder Lee 	if (!mt76_poll_msec(dev, MT_TOP_MISC2, MT_TOP_MISC2_FW_STATE,
144804b8e659SRyder Lee 			    FIELD_PREP(MT_TOP_MISC2_FW_STATE,
14495562d5f6SLorenzo Bianconi 				       FW_STATE_RDY), 500)) {
145004b8e659SRyder Lee 		dev_err(dev->mt76.dev, "Timeout for initializing firmware\n");
145104b8e659SRyder Lee 		return -EIO;
145204b8e659SRyder Lee 	}
145304b8e659SRyder Lee 
145435da599fSFelix Fietkau 	return 0;
145535da599fSFelix Fietkau }
14565abe8bafSFelix Fietkau 
mt7622_load_firmware(struct mt7615_dev * dev)145735da599fSFelix Fietkau static int mt7622_load_firmware(struct mt7615_dev *dev)
145835da599fSFelix Fietkau {
145935da599fSFelix Fietkau 	int ret;
146035da599fSFelix Fietkau 	u32 val;
146135da599fSFelix Fietkau 
146235da599fSFelix Fietkau 	mt76_set(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_BYPASS_TX_SCH);
146335da599fSFelix Fietkau 
146435da599fSFelix Fietkau 	val = mt76_get_field(dev, MT_TOP_OFF_RSV, MT_TOP_OFF_RSV_FW_STATE);
146535da599fSFelix Fietkau 	if (val != FW_STATE_FW_DOWNLOAD) {
146635da599fSFelix Fietkau 		dev_err(dev->mt76.dev, "Firmware is not ready for download\n");
146735da599fSFelix Fietkau 		return -EIO;
146835da599fSFelix Fietkau 	}
146935da599fSFelix Fietkau 
147035da599fSFelix Fietkau 	ret = mt7615_load_patch(dev, MT7622_PATCH_ADDRESS, MT7622_ROM_PATCH);
147135da599fSFelix Fietkau 	if (ret)
147235da599fSFelix Fietkau 		return ret;
147335da599fSFelix Fietkau 
147435da599fSFelix Fietkau 	ret = mt7615_load_n9(dev, MT7622_FIRMWARE_N9);
147535da599fSFelix Fietkau 	if (ret)
147635da599fSFelix Fietkau 		return ret;
147735da599fSFelix Fietkau 
147835da599fSFelix Fietkau 	if (!mt76_poll_msec(dev, MT_TOP_OFF_RSV, MT_TOP_OFF_RSV_FW_STATE,
147935da599fSFelix Fietkau 			    FIELD_PREP(MT_TOP_OFF_RSV_FW_STATE,
148035da599fSFelix Fietkau 				       FW_STATE_NORMAL_TRX), 1500)) {
148135da599fSFelix Fietkau 		dev_err(dev->mt76.dev, "Timeout for initializing firmware\n");
148235da599fSFelix Fietkau 		return -EIO;
148335da599fSFelix Fietkau 	}
148435da599fSFelix Fietkau 
148535da599fSFelix Fietkau 	mt76_clear(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_BYPASS_TX_SCH);
148604b8e659SRyder Lee 
148704b8e659SRyder Lee 	return 0;
148804b8e659SRyder Lee }
148904b8e659SRyder Lee 
mt7615_mcu_fw_log_2_host(struct mt7615_dev * dev,u8 ctrl)1490f347f81aSFelix Fietkau int mt7615_mcu_fw_log_2_host(struct mt7615_dev *dev, u8 ctrl)
1491f347f81aSFelix Fietkau {
1492f347f81aSFelix Fietkau 	struct {
1493f347f81aSFelix Fietkau 		u8 ctrl_val;
1494f347f81aSFelix Fietkau 		u8 pad[3];
1495f347f81aSFelix Fietkau 	} data = {
1496f347f81aSFelix Fietkau 		.ctrl_val = ctrl
1497f347f81aSFelix Fietkau 	};
1498f347f81aSFelix Fietkau 
1499e6d2070dSLorenzo Bianconi 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(FW_LOG_2_HOST),
1500e6d2070dSLorenzo Bianconi 				 &data, sizeof(data), true);
1501f347f81aSFelix Fietkau }
1502f347f81aSFelix Fietkau 
mt7615_mcu_cal_cache_apply(struct mt7615_dev * dev)150303a25c01SRyder Lee static int mt7615_mcu_cal_cache_apply(struct mt7615_dev *dev)
150403a25c01SRyder Lee {
150503a25c01SRyder Lee 	struct {
150603a25c01SRyder Lee 		bool cache_enable;
150703a25c01SRyder Lee 		u8 pad[3];
150803a25c01SRyder Lee 	} data = {
150903a25c01SRyder Lee 		.cache_enable = true
151003a25c01SRyder Lee 	};
151103a25c01SRyder Lee 
1512e6d2070dSLorenzo Bianconi 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(CAL_CACHE), &data,
151303a25c01SRyder Lee 				 sizeof(data), false);
151403a25c01SRyder Lee }
151503a25c01SRyder Lee 
mt7663_load_n9(struct mt7615_dev * dev,const char * name)1516f40ac0f3SLorenzo Bianconi static int mt7663_load_n9(struct mt7615_dev *dev, const char *name)
1517f40ac0f3SLorenzo Bianconi {
1518404d1cd4SLorenzo Bianconi 	u32 offset = 0, override_addr = 0, flag = FW_START_DLYCAL;
1519049c94f8SLorenzo Bianconi 	const struct mt76_connac2_fw_trailer *hdr;
1520f40ac0f3SLorenzo Bianconi 	const struct mt7663_fw_buf *buf;
1521f40ac0f3SLorenzo Bianconi 	const struct firmware *fw;
1522f40ac0f3SLorenzo Bianconi 	const u8 *base_addr;
1523f40ac0f3SLorenzo Bianconi 	int i, ret;
1524f40ac0f3SLorenzo Bianconi 
1525f40ac0f3SLorenzo Bianconi 	ret = request_firmware(&fw, name, dev->mt76.dev);
1526f40ac0f3SLorenzo Bianconi 	if (ret)
1527f40ac0f3SLorenzo Bianconi 		return ret;
1528f40ac0f3SLorenzo Bianconi 
1529f40ac0f3SLorenzo Bianconi 	if (!fw || !fw->data || fw->size < FW_V3_COMMON_TAILER_SIZE) {
1530f40ac0f3SLorenzo Bianconi 		dev_err(dev->mt76.dev, "Invalid firmware\n");
1531f40ac0f3SLorenzo Bianconi 		ret = -EINVAL;
1532f40ac0f3SLorenzo Bianconi 		goto out;
1533f40ac0f3SLorenzo Bianconi 	}
1534f40ac0f3SLorenzo Bianconi 
1535049c94f8SLorenzo Bianconi 	hdr = (const void *)(fw->data + fw->size - FW_V3_COMMON_TAILER_SIZE);
1536f40ac0f3SLorenzo Bianconi 	dev_info(dev->mt76.dev, "N9 Firmware Version: %.10s, Build Time: %.15s\n",
1537f40ac0f3SLorenzo Bianconi 		 hdr->fw_ver, hdr->build_date);
1538f40ac0f3SLorenzo Bianconi 	dev_info(dev->mt76.dev, "Region number: 0x%x\n", hdr->n_region);
1539f40ac0f3SLorenzo Bianconi 
1540f40ac0f3SLorenzo Bianconi 	base_addr = fw->data + fw->size - FW_V3_COMMON_TAILER_SIZE;
1541f40ac0f3SLorenzo Bianconi 	for (i = 0; i < hdr->n_region; i++) {
1542f40ac0f3SLorenzo Bianconi 		u32 shift = (hdr->n_region - i) * FW_V3_REGION_TAILER_SIZE;
1543f40ac0f3SLorenzo Bianconi 		u32 len, addr, mode;
1544f40ac0f3SLorenzo Bianconi 
1545f40ac0f3SLorenzo Bianconi 		dev_info(dev->mt76.dev, "Parsing tailer Region: %d\n", i);
1546f40ac0f3SLorenzo Bianconi 
1547f40ac0f3SLorenzo Bianconi 		buf = (const struct mt7663_fw_buf *)(base_addr - shift);
15489e90c351SLorenzo Bianconi 		mode = mt76_connac_mcu_gen_dl_mode(&dev->mt76,
15499e90c351SLorenzo Bianconi 						   buf->feature_set, false);
1550f40ac0f3SLorenzo Bianconi 		addr = le32_to_cpu(buf->img_dest_addr);
1551f40ac0f3SLorenzo Bianconi 		len = le32_to_cpu(buf->img_size);
1552f40ac0f3SLorenzo Bianconi 
1553d0e274afSLorenzo Bianconi 		ret = mt76_connac_mcu_init_download(&dev->mt76, addr, len,
1554d0e274afSLorenzo Bianconi 						    mode);
1555f40ac0f3SLorenzo Bianconi 		if (ret) {
1556f40ac0f3SLorenzo Bianconi 			dev_err(dev->mt76.dev, "Download request failed\n");
1557f40ac0f3SLorenzo Bianconi 			goto out;
1558f40ac0f3SLorenzo Bianconi 		}
1559f40ac0f3SLorenzo Bianconi 
1560ffc2198dSLorenzo Bianconi 		ret = mt76_mcu_send_firmware(&dev->mt76, MCU_CMD(FW_SCATTER),
15613cb43b66SLorenzo Bianconi 					     fw->data + offset, len);
1562f40ac0f3SLorenzo Bianconi 		if (ret) {
1563f40ac0f3SLorenzo Bianconi 			dev_err(dev->mt76.dev, "Failed to send firmware\n");
1564f40ac0f3SLorenzo Bianconi 			goto out;
1565f40ac0f3SLorenzo Bianconi 		}
1566f40ac0f3SLorenzo Bianconi 
156754178cc1SLorenzo Bianconi 		offset += le32_to_cpu(buf->img_size);
1568f40ac0f3SLorenzo Bianconi 		if (buf->feature_set & DL_MODE_VALID_RAM_ENTRY) {
1569f40ac0f3SLorenzo Bianconi 			override_addr = le32_to_cpu(buf->img_dest_addr);
1570f40ac0f3SLorenzo Bianconi 			dev_info(dev->mt76.dev, "Region %d, override_addr = 0x%08x\n",
1571f40ac0f3SLorenzo Bianconi 				 i, override_addr);
1572f40ac0f3SLorenzo Bianconi 		}
1573f40ac0f3SLorenzo Bianconi 	}
1574f40ac0f3SLorenzo Bianconi 
1575f40ac0f3SLorenzo Bianconi 	if (override_addr)
1576f40ac0f3SLorenzo Bianconi 		flag |= FW_START_OVERRIDE;
1577f40ac0f3SLorenzo Bianconi 
1578f40ac0f3SLorenzo Bianconi 	dev_info(dev->mt76.dev, "override_addr = 0x%08x, option = %d\n",
1579f40ac0f3SLorenzo Bianconi 		 override_addr, flag);
1580f40ac0f3SLorenzo Bianconi 
1581d0e274afSLorenzo Bianconi 	ret = mt76_connac_mcu_start_firmware(&dev->mt76, override_addr, flag);
1582938d76bbSLorenzo Bianconi 	if (ret) {
1583f40ac0f3SLorenzo Bianconi 		dev_err(dev->mt76.dev, "Failed to start N9 firmware\n");
1584938d76bbSLorenzo Bianconi 		goto out;
1585938d76bbSLorenzo Bianconi 	}
1586938d76bbSLorenzo Bianconi 
1587938d76bbSLorenzo Bianconi 	snprintf(dev->mt76.hw->wiphy->fw_version,
1588938d76bbSLorenzo Bianconi 		 sizeof(dev->mt76.hw->wiphy->fw_version),
1589938d76bbSLorenzo Bianconi 		 "%.10s-%.15s", hdr->fw_ver, hdr->build_date);
1590f40ac0f3SLorenzo Bianconi 
1591f40ac0f3SLorenzo Bianconi out:
1592f40ac0f3SLorenzo Bianconi 	release_firmware(fw);
1593f40ac0f3SLorenzo Bianconi 
1594f40ac0f3SLorenzo Bianconi 	return ret;
1595f40ac0f3SLorenzo Bianconi }
1596f40ac0f3SLorenzo Bianconi 
1597f2dc8ea1SLorenzo Bianconi static int
mt7663_load_rom_patch(struct mt7615_dev * dev,const char ** n9_firmware)1598f2dc8ea1SLorenzo Bianconi mt7663_load_rom_patch(struct mt7615_dev *dev, const char **n9_firmware)
1599f2dc8ea1SLorenzo Bianconi {
1600f2dc8ea1SLorenzo Bianconi 	const char *selected_rom, *secondary_rom = MT7663_ROM_PATCH;
1601f2dc8ea1SLorenzo Bianconi 	const char *primary_rom = MT7663_OFFLOAD_ROM_PATCH;
1602f2dc8ea1SLorenzo Bianconi 	int ret;
1603f2dc8ea1SLorenzo Bianconi 
1604f2dc8ea1SLorenzo Bianconi 	if (!prefer_offload_fw) {
1605f2dc8ea1SLorenzo Bianconi 		secondary_rom = MT7663_OFFLOAD_ROM_PATCH;
1606f2dc8ea1SLorenzo Bianconi 		primary_rom = MT7663_ROM_PATCH;
1607f2dc8ea1SLorenzo Bianconi 	}
1608f2dc8ea1SLorenzo Bianconi 	selected_rom = primary_rom;
1609f2dc8ea1SLorenzo Bianconi 
1610f2dc8ea1SLorenzo Bianconi 	ret = mt7615_load_patch(dev, MT7663_PATCH_ADDRESS, primary_rom);
1611f2dc8ea1SLorenzo Bianconi 	if (ret) {
1612f2dc8ea1SLorenzo Bianconi 		dev_info(dev->mt76.dev, "%s not found, switching to %s",
1613f2dc8ea1SLorenzo Bianconi 			 primary_rom, secondary_rom);
1614f2dc8ea1SLorenzo Bianconi 		ret = mt7615_load_patch(dev, MT7663_PATCH_ADDRESS,
1615f2dc8ea1SLorenzo Bianconi 					secondary_rom);
1616f2dc8ea1SLorenzo Bianconi 		if (ret) {
1617f2dc8ea1SLorenzo Bianconi 			dev_err(dev->mt76.dev, "failed to load %s",
1618f2dc8ea1SLorenzo Bianconi 				secondary_rom);
1619f2dc8ea1SLorenzo Bianconi 			return ret;
1620f2dc8ea1SLorenzo Bianconi 		}
1621f2dc8ea1SLorenzo Bianconi 		selected_rom = secondary_rom;
1622f2dc8ea1SLorenzo Bianconi 	}
1623f2dc8ea1SLorenzo Bianconi 
1624f2dc8ea1SLorenzo Bianconi 	if (!strcmp(selected_rom, MT7663_OFFLOAD_ROM_PATCH)) {
1625f2dc8ea1SLorenzo Bianconi 		*n9_firmware = MT7663_OFFLOAD_FIRMWARE_N9;
1626f2dc8ea1SLorenzo Bianconi 		dev->fw_ver = MT7615_FIRMWARE_V3;
1627f2dc8ea1SLorenzo Bianconi 		dev->mcu_ops = &uni_update_ops;
1628f2dc8ea1SLorenzo Bianconi 	} else {
1629f2dc8ea1SLorenzo Bianconi 		*n9_firmware = MT7663_FIRMWARE_N9;
1630f2dc8ea1SLorenzo Bianconi 		dev->fw_ver = MT7615_FIRMWARE_V2;
1631f2dc8ea1SLorenzo Bianconi 		dev->mcu_ops = &sta_update_ops;
1632f2dc8ea1SLorenzo Bianconi 	}
1633f2dc8ea1SLorenzo Bianconi 
1634f2dc8ea1SLorenzo Bianconi 	return 0;
1635f2dc8ea1SLorenzo Bianconi }
1636f2dc8ea1SLorenzo Bianconi 
__mt7663_load_firmware(struct mt7615_dev * dev)16378915c3ceSLorenzo Bianconi int __mt7663_load_firmware(struct mt7615_dev *dev)
1638f40ac0f3SLorenzo Bianconi {
1639f2dc8ea1SLorenzo Bianconi 	const char *n9_firmware;
1640f40ac0f3SLorenzo Bianconi 	int ret;
1641f40ac0f3SLorenzo Bianconi 
1642f40ac0f3SLorenzo Bianconi 	ret = mt76_get_field(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY);
1643f40ac0f3SLorenzo Bianconi 	if (ret) {
1644f40ac0f3SLorenzo Bianconi 		dev_dbg(dev->mt76.dev, "Firmware is already download\n");
1645f40ac0f3SLorenzo Bianconi 		return -EIO;
1646f40ac0f3SLorenzo Bianconi 	}
1647f40ac0f3SLorenzo Bianconi 
1648f2dc8ea1SLorenzo Bianconi 	ret = mt7663_load_rom_patch(dev, &n9_firmware);
1649f40ac0f3SLorenzo Bianconi 	if (ret)
1650f40ac0f3SLorenzo Bianconi 		return ret;
1651f40ac0f3SLorenzo Bianconi 
1652f2dc8ea1SLorenzo Bianconi 	ret = mt7663_load_n9(dev, n9_firmware);
1653f40ac0f3SLorenzo Bianconi 	if (ret)
1654f40ac0f3SLorenzo Bianconi 		return ret;
1655f40ac0f3SLorenzo Bianconi 
1656f40ac0f3SLorenzo Bianconi 	if (!mt76_poll_msec(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY,
1657f40ac0f3SLorenzo Bianconi 			    MT_TOP_MISC2_FW_N9_RDY, 1500)) {
1658f40ac0f3SLorenzo Bianconi 		ret = mt76_get_field(dev, MT_CONN_ON_MISC,
1659f40ac0f3SLorenzo Bianconi 				     MT7663_TOP_MISC2_FW_STATE);
1660f40ac0f3SLorenzo Bianconi 		dev_err(dev->mt76.dev, "Timeout for initializing firmware\n");
1661f40ac0f3SLorenzo Bianconi 		return -EIO;
1662f40ac0f3SLorenzo Bianconi 	}
1663f40ac0f3SLorenzo Bianconi 
1664c6bf2010SLorenzo Bianconi #ifdef CONFIG_PM
1665c6bf2010SLorenzo Bianconi 	if (mt7615_firmware_offload(dev))
166655d4c19cSLorenzo Bianconi 		dev->mt76.hw->wiphy->wowlan = &mt76_connac_wowlan_support;
1667c6bf2010SLorenzo Bianconi #endif /* CONFIG_PM */
1668c6bf2010SLorenzo Bianconi 
1669f40ac0f3SLorenzo Bianconi 	dev_dbg(dev->mt76.dev, "Firmware init done\n");
1670f40ac0f3SLorenzo Bianconi 
1671f40ac0f3SLorenzo Bianconi 	return 0;
1672f40ac0f3SLorenzo Bianconi }
16738915c3ceSLorenzo Bianconi EXPORT_SYMBOL_GPL(__mt7663_load_firmware);
16748915c3ceSLorenzo Bianconi 
mt7663_load_firmware(struct mt7615_dev * dev)16758915c3ceSLorenzo Bianconi static int mt7663_load_firmware(struct mt7615_dev *dev)
16768915c3ceSLorenzo Bianconi {
16778915c3ceSLorenzo Bianconi 	int ret;
16788915c3ceSLorenzo Bianconi 
16798915c3ceSLorenzo Bianconi 	mt76_set(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_BYPASS_TX_SCH);
16808915c3ceSLorenzo Bianconi 
16818915c3ceSLorenzo Bianconi 	ret = __mt7663_load_firmware(dev);
16828915c3ceSLorenzo Bianconi 	if (ret)
16838915c3ceSLorenzo Bianconi 		return ret;
16848915c3ceSLorenzo Bianconi 
16858915c3ceSLorenzo Bianconi 	mt76_clear(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_BYPASS_TX_SCH);
16868915c3ceSLorenzo Bianconi 
16878915c3ceSLorenzo Bianconi 	return 0;
16888915c3ceSLorenzo Bianconi }
1689f40ac0f3SLorenzo Bianconi 
mt7615_mcu_init(struct mt7615_dev * dev)169004b8e659SRyder Lee int mt7615_mcu_init(struct mt7615_dev *dev)
169104b8e659SRyder Lee {
1692a3a2c2e7SLorenzo Bianconi 	static const struct mt76_mcu_ops mt7615_mcu_ops = {
1693bb31a80eSLorenzo Bianconi 		.headroom = sizeof(struct mt7615_mcu_txd),
1694f4d45fe2SLorenzo Bianconi 		.mcu_skb_send_msg = mt7615_mcu_send_message,
1695f320d812SFelix Fietkau 		.mcu_parse_response = mt7615_mcu_parse_response,
1696a3a2c2e7SLorenzo Bianconi 	};
169704b8e659SRyder Lee 	int ret;
169804b8e659SRyder Lee 
1699a3a2c2e7SLorenzo Bianconi 	dev->mt76.mcu_ops = &mt7615_mcu_ops,
1700a3a2c2e7SLorenzo Bianconi 
1701186b659cSLorenzo Bianconi 	ret = mt7615_mcu_drv_pmctrl(dev);
170204b8e659SRyder Lee 	if (ret)
170304b8e659SRyder Lee 		return ret;
170404b8e659SRyder Lee 
1705f40ac0f3SLorenzo Bianconi 	switch (mt76_chip(&dev->mt76)) {
1706f40ac0f3SLorenzo Bianconi 	case 0x7622:
170735da599fSFelix Fietkau 		ret = mt7622_load_firmware(dev);
1708f40ac0f3SLorenzo Bianconi 		break;
1709f40ac0f3SLorenzo Bianconi 	case 0x7663:
1710f40ac0f3SLorenzo Bianconi 		ret = mt7663_load_firmware(dev);
1711f40ac0f3SLorenzo Bianconi 		break;
1712f40ac0f3SLorenzo Bianconi 	default:
171304b8e659SRyder Lee 		ret = mt7615_load_firmware(dev);
1714f40ac0f3SLorenzo Bianconi 		break;
1715f40ac0f3SLorenzo Bianconi 	}
171604b8e659SRyder Lee 	if (ret)
171704b8e659SRyder Lee 		return ret;
171804b8e659SRyder Lee 
1719e637763bSLorenzo Bianconi 	mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_FWDL], false);
172035da599fSFelix Fietkau 	dev_dbg(dev->mt76.dev, "Firmware init done\n");
1721011849e0SFelix Fietkau 	set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);
172204b8e659SRyder Lee 
172303a25c01SRyder Lee 	if (dev->dbdc_support) {
172403a25c01SRyder Lee 		ret = mt7615_mcu_cal_cache_apply(dev);
172503a25c01SRyder Lee 		if (ret)
172603a25c01SRyder Lee 			return ret;
172703a25c01SRyder Lee 	}
172803a25c01SRyder Lee 
172903a25c01SRyder Lee 	return mt7615_mcu_fw_log_2_host(dev, 0);
173004b8e659SRyder Lee }
1731e90354e0SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt7615_mcu_init);
173204b8e659SRyder Lee 
mt7615_mcu_exit(struct mt7615_dev * dev)173304b8e659SRyder Lee void mt7615_mcu_exit(struct mt7615_dev *dev)
173404b8e659SRyder Lee {
17358e4edae2SLorenzo Bianconi 	mt7615_mcu_restart(&dev->mt76);
1736186b659cSLorenzo Bianconi 	mt7615_mcu_set_fw_ctrl(dev);
173709872957SLorenzo Bianconi 	skb_queue_purge(&dev->mt76.mcu.res_q);
173804b8e659SRyder Lee }
1739e90354e0SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt7615_mcu_exit);
174004b8e659SRyder Lee 
mt7615_mcu_set_eeprom(struct mt7615_dev * dev)174104b8e659SRyder Lee int mt7615_mcu_set_eeprom(struct mt7615_dev *dev)
174204b8e659SRyder Lee {
174304b8e659SRyder Lee 	struct {
174404b8e659SRyder Lee 		u8 buffer_mode;
1745c321a3d7SLorenzo Bianconi 		u8 content_format;
174626b48766SRyder Lee 		__le16 len;
174704b8e659SRyder Lee 	} __packed req_hdr = {
174804b8e659SRyder Lee 		.buffer_mode = 1,
174904b8e659SRyder Lee 	};
1750936fca1fSLorenzo Bianconi 	u8 *eep = (u8 *)dev->mt76.eeprom.data;
1751936fca1fSLorenzo Bianconi 	struct sk_buff *skb;
1752c321a3d7SLorenzo Bianconi 	int eep_len, offset;
175304b8e659SRyder Lee 
1754c321a3d7SLorenzo Bianconi 	switch (mt76_chip(&dev->mt76)) {
1755c321a3d7SLorenzo Bianconi 	case 0x7622:
17565dff21eeSFelix Fietkau 		eep_len = MT7622_EE_MAX - MT_EE_NIC_CONF_0;
1757c321a3d7SLorenzo Bianconi 		offset = MT_EE_NIC_CONF_0;
1758c321a3d7SLorenzo Bianconi 		break;
1759c321a3d7SLorenzo Bianconi 	case 0x7663:
1760c321a3d7SLorenzo Bianconi 		eep_len = MT7663_EE_MAX - MT_EE_CHIP_ID;
1761c321a3d7SLorenzo Bianconi 		req_hdr.content_format = 1;
1762c321a3d7SLorenzo Bianconi 		offset = MT_EE_CHIP_ID;
1763c321a3d7SLorenzo Bianconi 		break;
1764c321a3d7SLorenzo Bianconi 	default:
17655dff21eeSFelix Fietkau 		eep_len = MT7615_EE_MAX - MT_EE_NIC_CONF_0;
1766c321a3d7SLorenzo Bianconi 		offset = MT_EE_NIC_CONF_0;
1767c321a3d7SLorenzo Bianconi 		break;
1768c321a3d7SLorenzo Bianconi 	}
17695dff21eeSFelix Fietkau 
1770936fca1fSLorenzo Bianconi 	req_hdr.len = cpu_to_le16(eep_len);
1771936fca1fSLorenzo Bianconi 
1772bb31a80eSLorenzo Bianconi 	skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, sizeof(req_hdr) + eep_len);
1773936fca1fSLorenzo Bianconi 	if (!skb)
1774516c3e38SLorenzo Bianconi 		return -ENOMEM;
177504b8e659SRyder Lee 
1776936fca1fSLorenzo Bianconi 	skb_put_data(skb, &req_hdr, sizeof(req_hdr));
1777c321a3d7SLorenzo Bianconi 	skb_put_data(skb, eep + offset, eep_len);
177804b8e659SRyder Lee 
1779fa62d0e0SFelix Fietkau 	return mt76_mcu_skb_send_msg(&dev->mt76, skb,
1780e6d2070dSLorenzo Bianconi 				     MCU_EXT_CMD(EFUSE_BUFFER_MODE), true);
178104b8e659SRyder Lee }
178204b8e659SRyder Lee 
mt7615_mcu_set_wmm(struct mt7615_dev * dev,u8 queue,const struct ieee80211_tx_queue_params * params)178304b8e659SRyder Lee int mt7615_mcu_set_wmm(struct mt7615_dev *dev, u8 queue,
178404b8e659SRyder Lee 		       const struct ieee80211_tx_queue_params *params)
178504b8e659SRyder Lee {
178604b8e659SRyder Lee #define WMM_AIFS_SET	BIT(0)
178704b8e659SRyder Lee #define WMM_CW_MIN_SET	BIT(1)
178804b8e659SRyder Lee #define WMM_CW_MAX_SET	BIT(2)
178904b8e659SRyder Lee #define WMM_TXOP_SET	BIT(3)
17904f8a4f17SRyder Lee #define WMM_PARAM_SET	(WMM_AIFS_SET | WMM_CW_MIN_SET | \
17914f8a4f17SRyder Lee 			 WMM_CW_MAX_SET | WMM_TXOP_SET)
179204b8e659SRyder Lee 	struct req_data {
179304b8e659SRyder Lee 		u8 number;
179404b8e659SRyder Lee 		u8 rsv[3];
179504b8e659SRyder Lee 		u8 queue;
179604b8e659SRyder Lee 		u8 valid;
179704b8e659SRyder Lee 		u8 aifs;
179804b8e659SRyder Lee 		u8 cw_min;
179904b8e659SRyder Lee 		__le16 cw_max;
180004b8e659SRyder Lee 		__le16 txop;
180104b8e659SRyder Lee 	} __packed req = {
180204b8e659SRyder Lee 		.number = 1,
180304b8e659SRyder Lee 		.queue = queue,
18044f8a4f17SRyder Lee 		.valid = WMM_PARAM_SET,
180504b8e659SRyder Lee 		.aifs = params->aifs,
18064f8a4f17SRyder Lee 		.cw_min = 5,
18074f8a4f17SRyder Lee 		.cw_max = cpu_to_le16(10),
180804b8e659SRyder Lee 		.txop = cpu_to_le16(params->txop),
180904b8e659SRyder Lee 	};
181004b8e659SRyder Lee 
18114f8a4f17SRyder Lee 	if (params->cw_min)
18124f8a4f17SRyder Lee 		req.cw_min = fls(params->cw_min);
18134f8a4f17SRyder Lee 	if (params->cw_max)
18144f8a4f17SRyder Lee 		req.cw_max = cpu_to_le16(fls(params->cw_max));
181504b8e659SRyder Lee 
1816e6d2070dSLorenzo Bianconi 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(EDCA_UPDATE),
1817e6d2070dSLorenzo Bianconi 				 &req, sizeof(req), true);
181804b8e659SRyder Lee }
181904b8e659SRyder Lee 
mt7615_mcu_set_dbdc(struct mt7615_dev * dev)1820ac3ef85cSFelix Fietkau int mt7615_mcu_set_dbdc(struct mt7615_dev *dev)
1821ac3ef85cSFelix Fietkau {
1822ac3ef85cSFelix Fietkau 	struct mt7615_phy *ext_phy = mt7615_ext_phy(dev);
1823ac3ef85cSFelix Fietkau 	struct dbdc_entry {
1824ac3ef85cSFelix Fietkau 		u8 type;
1825ac3ef85cSFelix Fietkau 		u8 index;
1826ac3ef85cSFelix Fietkau 		u8 band;
1827ac3ef85cSFelix Fietkau 		u8 _rsv;
1828ac3ef85cSFelix Fietkau 	};
1829ac3ef85cSFelix Fietkau 	struct {
1830ac3ef85cSFelix Fietkau 		u8 enable;
1831ac3ef85cSFelix Fietkau 		u8 num;
1832ac3ef85cSFelix Fietkau 		u8 _rsv[2];
1833ac3ef85cSFelix Fietkau 		struct dbdc_entry entry[64];
1834ac3ef85cSFelix Fietkau 	} req = {
1835ac3ef85cSFelix Fietkau 		.enable = !!ext_phy,
1836ac3ef85cSFelix Fietkau 	};
1837ac3ef85cSFelix Fietkau 	int i;
1838ac3ef85cSFelix Fietkau 
1839ac3ef85cSFelix Fietkau 	if (!ext_phy)
1840ac3ef85cSFelix Fietkau 		goto out;
1841ac3ef85cSFelix Fietkau 
1842ac3ef85cSFelix Fietkau #define ADD_DBDC_ENTRY(_type, _idx, _band)		\
1843ac3ef85cSFelix Fietkau 	do { \
1844ac3ef85cSFelix Fietkau 		req.entry[req.num].type = _type;		\
1845ac3ef85cSFelix Fietkau 		req.entry[req.num].index = _idx;		\
1846ac3ef85cSFelix Fietkau 		req.entry[req.num++].band = _band;		\
1847ac3ef85cSFelix Fietkau 	} while (0)
1848ac3ef85cSFelix Fietkau 
1849ac3ef85cSFelix Fietkau 	for (i = 0; i < 4; i++) {
1850d8d59f66SRyder Lee 		bool band = !!(ext_phy->omac_mask & BIT_ULL(i));
1851ac3ef85cSFelix Fietkau 
1852ac3ef85cSFelix Fietkau 		ADD_DBDC_ENTRY(DBDC_TYPE_BSS, i, band);
1853ac3ef85cSFelix Fietkau 	}
1854ac3ef85cSFelix Fietkau 
1855ac3ef85cSFelix Fietkau 	for (i = 0; i < 14; i++) {
1856d8d59f66SRyder Lee 		bool band = !!(ext_phy->omac_mask & BIT_ULL(0x11 + i));
1857ac3ef85cSFelix Fietkau 
1858ac3ef85cSFelix Fietkau 		ADD_DBDC_ENTRY(DBDC_TYPE_MBSS, i, band);
1859ac3ef85cSFelix Fietkau 	}
1860ac3ef85cSFelix Fietkau 
1861ac3ef85cSFelix Fietkau 	ADD_DBDC_ENTRY(DBDC_TYPE_MU, 0, 1);
1862ac3ef85cSFelix Fietkau 
1863ac3ef85cSFelix Fietkau 	for (i = 0; i < 3; i++)
1864ac3ef85cSFelix Fietkau 		ADD_DBDC_ENTRY(DBDC_TYPE_BF, i, 1);
1865ac3ef85cSFelix Fietkau 
1866ac3ef85cSFelix Fietkau 	ADD_DBDC_ENTRY(DBDC_TYPE_WMM, 0, 0);
1867ac3ef85cSFelix Fietkau 	ADD_DBDC_ENTRY(DBDC_TYPE_WMM, 1, 0);
1868ac3ef85cSFelix Fietkau 	ADD_DBDC_ENTRY(DBDC_TYPE_WMM, 2, 1);
1869ac3ef85cSFelix Fietkau 	ADD_DBDC_ENTRY(DBDC_TYPE_WMM, 3, 1);
1870ac3ef85cSFelix Fietkau 
1871ac3ef85cSFelix Fietkau 	ADD_DBDC_ENTRY(DBDC_TYPE_MGMT, 0, 0);
1872ac3ef85cSFelix Fietkau 	ADD_DBDC_ENTRY(DBDC_TYPE_MGMT, 1, 1);
1873ac3ef85cSFelix Fietkau 
1874ac3ef85cSFelix Fietkau out:
1875e6d2070dSLorenzo Bianconi 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(DBDC_CTRL), &req,
1876cb5cdd4cSFelix Fietkau 				 sizeof(req), true);
1877ac3ef85cSFelix Fietkau }
1878ac3ef85cSFelix Fietkau 
mt7615_mcu_del_wtbl_all(struct mt7615_dev * dev)187904b8e659SRyder Lee int mt7615_mcu_del_wtbl_all(struct mt7615_dev *dev)
188004b8e659SRyder Lee {
1881516c3e38SLorenzo Bianconi 	struct wtbl_req_hdr req = {
1882516c3e38SLorenzo Bianconi 		.operation = WTBL_RESET_ALL,
18830467448dSLorenzo Bianconi 	};
188404b8e659SRyder Lee 
1885e6d2070dSLorenzo Bianconi 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(WTBL_UPDATE),
1886e6d2070dSLorenzo Bianconi 				 &req, sizeof(req), true);
188704b8e659SRyder Lee }
188804b8e659SRyder Lee 
mt7615_mcu_set_fcc5_lpn(struct mt7615_dev * dev,int val)18892ce73efeSLorenzo Bianconi int mt7615_mcu_set_fcc5_lpn(struct mt7615_dev *dev, int val)
18902ce73efeSLorenzo Bianconi {
18912ce73efeSLorenzo Bianconi 	struct {
18920211c282SLorenzo Bianconi 		__le16 tag;
18930211c282SLorenzo Bianconi 		__le16 min_lpn;
18942ce73efeSLorenzo Bianconi 	} req = {
18950211c282SLorenzo Bianconi 		.tag = cpu_to_le16(0x1),
18960211c282SLorenzo Bianconi 		.min_lpn = cpu_to_le16(val),
18972ce73efeSLorenzo Bianconi 	};
18982ce73efeSLorenzo Bianconi 
18999d8d136cSLorenzo Bianconi 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_RADAR_TH),
19009d8d136cSLorenzo Bianconi 				 &req, sizeof(req), true);
19012ce73efeSLorenzo Bianconi }
19022ce73efeSLorenzo Bianconi 
mt7615_mcu_set_pulse_th(struct mt7615_dev * dev,const struct mt7615_dfs_pulse * pulse)19032ce73efeSLorenzo Bianconi int mt7615_mcu_set_pulse_th(struct mt7615_dev *dev,
19042ce73efeSLorenzo Bianconi 			    const struct mt7615_dfs_pulse *pulse)
19052ce73efeSLorenzo Bianconi {
19062ce73efeSLorenzo Bianconi 	struct {
19070211c282SLorenzo Bianconi 		__le16 tag;
19080211c282SLorenzo Bianconi 		__le32 max_width;	/* us */
19090211c282SLorenzo Bianconi 		__le32 max_pwr;		/* dbm */
19100211c282SLorenzo Bianconi 		__le32 min_pwr;		/* dbm */
19110211c282SLorenzo Bianconi 		__le32 min_stgr_pri;	/* us */
19120211c282SLorenzo Bianconi 		__le32 max_stgr_pri;	/* us */
19130211c282SLorenzo Bianconi 		__le32 min_cr_pri;	/* us */
19140211c282SLorenzo Bianconi 		__le32 max_cr_pri;	/* us */
19152ce73efeSLorenzo Bianconi 	} req = {
19160211c282SLorenzo Bianconi 		.tag = cpu_to_le16(0x3),
19170211c282SLorenzo Bianconi #define __req_field(field) .field = cpu_to_le32(pulse->field)
19180211c282SLorenzo Bianconi 		__req_field(max_width),
19190211c282SLorenzo Bianconi 		__req_field(max_pwr),
19200211c282SLorenzo Bianconi 		__req_field(min_pwr),
19210211c282SLorenzo Bianconi 		__req_field(min_stgr_pri),
19220211c282SLorenzo Bianconi 		__req_field(max_stgr_pri),
19230211c282SLorenzo Bianconi 		__req_field(min_cr_pri),
19240211c282SLorenzo Bianconi 		__req_field(max_cr_pri),
19250211c282SLorenzo Bianconi #undef  __req_field
19262ce73efeSLorenzo Bianconi 	};
19272ce73efeSLorenzo Bianconi 
19289d8d136cSLorenzo Bianconi 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_RADAR_TH),
19299d8d136cSLorenzo Bianconi 				 &req, sizeof(req), true);
19302ce73efeSLorenzo Bianconi }
19312ce73efeSLorenzo Bianconi 
mt7615_mcu_set_radar_th(struct mt7615_dev * dev,int index,const struct mt7615_dfs_pattern * pattern)19322ce73efeSLorenzo Bianconi int mt7615_mcu_set_radar_th(struct mt7615_dev *dev, int index,
19332ce73efeSLorenzo Bianconi 			    const struct mt7615_dfs_pattern *pattern)
19342ce73efeSLorenzo Bianconi {
19352ce73efeSLorenzo Bianconi 	struct {
19360211c282SLorenzo Bianconi 		__le16 tag;
19370211c282SLorenzo Bianconi 		__le16 radar_type;
19380211c282SLorenzo Bianconi 		u8 enb;
19390211c282SLorenzo Bianconi 		u8 stgr;
19400211c282SLorenzo Bianconi 		u8 min_crpn;
19410211c282SLorenzo Bianconi 		u8 max_crpn;
19420211c282SLorenzo Bianconi 		u8 min_crpr;
19430211c282SLorenzo Bianconi 		u8 min_pw;
19440211c282SLorenzo Bianconi 		u8 max_pw;
19450211c282SLorenzo Bianconi 		__le32 min_pri;
19460211c282SLorenzo Bianconi 		__le32 max_pri;
19470211c282SLorenzo Bianconi 		u8 min_crbn;
19480211c282SLorenzo Bianconi 		u8 max_crbn;
19490211c282SLorenzo Bianconi 		u8 min_stgpn;
19500211c282SLorenzo Bianconi 		u8 max_stgpn;
19510211c282SLorenzo Bianconi 		u8 min_stgpr;
19522ce73efeSLorenzo Bianconi 	} req = {
19530211c282SLorenzo Bianconi 		.tag = cpu_to_le16(0x2),
19540211c282SLorenzo Bianconi 		.radar_type = cpu_to_le16(index),
19550211c282SLorenzo Bianconi #define __req_field_u8(field) .field = pattern->field
19560211c282SLorenzo Bianconi #define __req_field_u32(field) .field = cpu_to_le32(pattern->field)
19570211c282SLorenzo Bianconi 		__req_field_u8(enb),
19580211c282SLorenzo Bianconi 		__req_field_u8(stgr),
19590211c282SLorenzo Bianconi 		__req_field_u8(min_crpn),
19600211c282SLorenzo Bianconi 		__req_field_u8(max_crpn),
19610211c282SLorenzo Bianconi 		__req_field_u8(min_crpr),
19620211c282SLorenzo Bianconi 		__req_field_u8(min_pw),
19630211c282SLorenzo Bianconi 		__req_field_u8(max_pw),
19640211c282SLorenzo Bianconi 		__req_field_u32(min_pri),
19650211c282SLorenzo Bianconi 		__req_field_u32(max_pri),
19660211c282SLorenzo Bianconi 		__req_field_u8(min_crbn),
19670211c282SLorenzo Bianconi 		__req_field_u8(max_crbn),
19680211c282SLorenzo Bianconi 		__req_field_u8(min_stgpn),
19690211c282SLorenzo Bianconi 		__req_field_u8(max_stgpn),
19700211c282SLorenzo Bianconi 		__req_field_u8(min_stgpr),
19710211c282SLorenzo Bianconi #undef __req_field_u8
19720211c282SLorenzo Bianconi #undef __req_field_u32
19732ce73efeSLorenzo Bianconi 	};
19742ce73efeSLorenzo Bianconi 
19759d8d136cSLorenzo Bianconi 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_RADAR_TH),
19769d8d136cSLorenzo Bianconi 				 &req, sizeof(req), true);
19772ce73efeSLorenzo Bianconi }
19782ce73efeSLorenzo Bianconi 
mt7615_mcu_rdd_send_pattern(struct mt7615_dev * dev)197970911d96SLorenzo Bianconi int mt7615_mcu_rdd_send_pattern(struct mt7615_dev *dev)
198070911d96SLorenzo Bianconi {
198170911d96SLorenzo Bianconi 	struct {
198270911d96SLorenzo Bianconi 		u8 pulse_num;
198370911d96SLorenzo Bianconi 		u8 rsv[3];
198470911d96SLorenzo Bianconi 		struct {
19850211c282SLorenzo Bianconi 			__le32 start_time;
19860211c282SLorenzo Bianconi 			__le16 width;
19870211c282SLorenzo Bianconi 			__le16 power;
198870911d96SLorenzo Bianconi 		} pattern[32];
198970911d96SLorenzo Bianconi 	} req = {
199070911d96SLorenzo Bianconi 		.pulse_num = dev->radar_pattern.n_pulses,
199170911d96SLorenzo Bianconi 	};
199270911d96SLorenzo Bianconi 	u32 start_time = ktime_to_ms(ktime_get_boottime());
199370911d96SLorenzo Bianconi 	int i;
199470911d96SLorenzo Bianconi 
199570911d96SLorenzo Bianconi 	if (dev->radar_pattern.n_pulses > ARRAY_SIZE(req.pattern))
199670911d96SLorenzo Bianconi 		return -EINVAL;
199770911d96SLorenzo Bianconi 
199870911d96SLorenzo Bianconi 	/* TODO: add some noise here */
199970911d96SLorenzo Bianconi 	for (i = 0; i < dev->radar_pattern.n_pulses; i++) {
20000211c282SLorenzo Bianconi 		u32 ts = start_time + i * dev->radar_pattern.period;
20010211c282SLorenzo Bianconi 
20020211c282SLorenzo Bianconi 		req.pattern[i].width = cpu_to_le16(dev->radar_pattern.width);
20030211c282SLorenzo Bianconi 		req.pattern[i].power = cpu_to_le16(dev->radar_pattern.power);
20040211c282SLorenzo Bianconi 		req.pattern[i].start_time = cpu_to_le32(ts);
200570911d96SLorenzo Bianconi 	}
200670911d96SLorenzo Bianconi 
2007e6d2070dSLorenzo Bianconi 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_RDD_PATTERN),
200870911d96SLorenzo Bianconi 				 &req, sizeof(req), false);
200970911d96SLorenzo Bianconi }
201070911d96SLorenzo Bianconi 
mt7615_mcu_set_txpower_sku(struct mt7615_phy * phy,u8 * sku)201115d9a5d7SFelix Fietkau static void mt7615_mcu_set_txpower_sku(struct mt7615_phy *phy, u8 *sku)
201215d9a5d7SFelix Fietkau {
201315d9a5d7SFelix Fietkau 	struct mt76_phy *mphy = phy->mt76;
201415d9a5d7SFelix Fietkau 	struct ieee80211_hw *hw = mphy->hw;
2015fb0d9054SFelix Fietkau 	struct mt76_power_limits limits;
2016fb0d9054SFelix Fietkau 	s8 *limits_array = (s8 *)&limits;
201715d9a5d7SFelix Fietkau 	int n_chains = hweight8(mphy->antenna_mask);
2018148950e5SLorenzo Bianconi 	int tx_power = hw->conf.power_level * 2;
201915d9a5d7SFelix Fietkau 	int i;
2020fb0d9054SFelix Fietkau 	static const u8 sku_mapping[] = {
2021fb0d9054SFelix Fietkau #define SKU_FIELD(_type, _field) \
2022fb0d9054SFelix Fietkau 		[MT_SKU_##_type] = offsetof(struct mt76_power_limits, _field)
2023fb0d9054SFelix Fietkau 		SKU_FIELD(CCK_1_2, cck[0]),
2024fb0d9054SFelix Fietkau 		SKU_FIELD(CCK_55_11, cck[2]),
2025fb0d9054SFelix Fietkau 		SKU_FIELD(OFDM_6_9, ofdm[0]),
2026fb0d9054SFelix Fietkau 		SKU_FIELD(OFDM_12_18, ofdm[2]),
2027fb0d9054SFelix Fietkau 		SKU_FIELD(OFDM_24_36, ofdm[4]),
2028fb0d9054SFelix Fietkau 		SKU_FIELD(OFDM_48, ofdm[6]),
2029fb0d9054SFelix Fietkau 		SKU_FIELD(OFDM_54, ofdm[7]),
2030fb0d9054SFelix Fietkau 		SKU_FIELD(HT20_0_8, mcs[0][0]),
2031fb0d9054SFelix Fietkau 		SKU_FIELD(HT20_32, ofdm[0]),
2032fb0d9054SFelix Fietkau 		SKU_FIELD(HT20_1_2_9_10, mcs[0][1]),
2033fb0d9054SFelix Fietkau 		SKU_FIELD(HT20_3_4_11_12, mcs[0][3]),
2034fb0d9054SFelix Fietkau 		SKU_FIELD(HT20_5_13, mcs[0][5]),
2035fb0d9054SFelix Fietkau 		SKU_FIELD(HT20_6_14, mcs[0][6]),
2036fb0d9054SFelix Fietkau 		SKU_FIELD(HT20_7_15, mcs[0][7]),
2037fb0d9054SFelix Fietkau 		SKU_FIELD(HT40_0_8, mcs[1][0]),
2038fb0d9054SFelix Fietkau 		SKU_FIELD(HT40_32, ofdm[0]),
2039fb0d9054SFelix Fietkau 		SKU_FIELD(HT40_1_2_9_10, mcs[1][1]),
2040fb0d9054SFelix Fietkau 		SKU_FIELD(HT40_3_4_11_12, mcs[1][3]),
2041fb0d9054SFelix Fietkau 		SKU_FIELD(HT40_5_13, mcs[1][5]),
2042fb0d9054SFelix Fietkau 		SKU_FIELD(HT40_6_14, mcs[1][6]),
2043fb0d9054SFelix Fietkau 		SKU_FIELD(HT40_7_15, mcs[1][7]),
2044fb0d9054SFelix Fietkau 		SKU_FIELD(VHT20_0, mcs[0][0]),
2045fb0d9054SFelix Fietkau 		SKU_FIELD(VHT20_1_2, mcs[0][1]),
2046fb0d9054SFelix Fietkau 		SKU_FIELD(VHT20_3_4, mcs[0][3]),
2047fb0d9054SFelix Fietkau 		SKU_FIELD(VHT20_5_6, mcs[0][5]),
2048fb0d9054SFelix Fietkau 		SKU_FIELD(VHT20_7, mcs[0][7]),
2049fb0d9054SFelix Fietkau 		SKU_FIELD(VHT20_8, mcs[0][8]),
2050fb0d9054SFelix Fietkau 		SKU_FIELD(VHT20_9, mcs[0][9]),
2051fb0d9054SFelix Fietkau 		SKU_FIELD(VHT40_0, mcs[1][0]),
2052fb0d9054SFelix Fietkau 		SKU_FIELD(VHT40_1_2, mcs[1][1]),
2053fb0d9054SFelix Fietkau 		SKU_FIELD(VHT40_3_4, mcs[1][3]),
2054fb0d9054SFelix Fietkau 		SKU_FIELD(VHT40_5_6, mcs[1][5]),
2055fb0d9054SFelix Fietkau 		SKU_FIELD(VHT40_7, mcs[1][7]),
2056fb0d9054SFelix Fietkau 		SKU_FIELD(VHT40_8, mcs[1][8]),
2057fb0d9054SFelix Fietkau 		SKU_FIELD(VHT40_9, mcs[1][9]),
2058fb0d9054SFelix Fietkau 		SKU_FIELD(VHT80_0, mcs[2][0]),
2059fb0d9054SFelix Fietkau 		SKU_FIELD(VHT80_1_2, mcs[2][1]),
2060fb0d9054SFelix Fietkau 		SKU_FIELD(VHT80_3_4, mcs[2][3]),
2061fb0d9054SFelix Fietkau 		SKU_FIELD(VHT80_5_6, mcs[2][5]),
2062fb0d9054SFelix Fietkau 		SKU_FIELD(VHT80_7, mcs[2][7]),
2063fb0d9054SFelix Fietkau 		SKU_FIELD(VHT80_8, mcs[2][8]),
2064fb0d9054SFelix Fietkau 		SKU_FIELD(VHT80_9, mcs[2][9]),
2065fb0d9054SFelix Fietkau 		SKU_FIELD(VHT160_0, mcs[3][0]),
2066fb0d9054SFelix Fietkau 		SKU_FIELD(VHT160_1_2, mcs[3][1]),
2067fb0d9054SFelix Fietkau 		SKU_FIELD(VHT160_3_4, mcs[3][3]),
2068fb0d9054SFelix Fietkau 		SKU_FIELD(VHT160_5_6, mcs[3][5]),
2069fb0d9054SFelix Fietkau 		SKU_FIELD(VHT160_7, mcs[3][7]),
2070fb0d9054SFelix Fietkau 		SKU_FIELD(VHT160_8, mcs[3][8]),
2071fb0d9054SFelix Fietkau 		SKU_FIELD(VHT160_9, mcs[3][9]),
2072fb0d9054SFelix Fietkau #undef SKU_FIELD
2073fb0d9054SFelix Fietkau 	};
207415d9a5d7SFelix Fietkau 
2075148950e5SLorenzo Bianconi 	tx_power = mt76_get_sar_power(mphy, mphy->chandef.chan, tx_power);
2076148950e5SLorenzo Bianconi 	tx_power -= mt76_tx_power_nss_delta(n_chains);
2077fb0d9054SFelix Fietkau 	tx_power = mt76_get_rate_power_limits(mphy, mphy->chandef.chan,
2078fb0d9054SFelix Fietkau 					      &limits, tx_power);
207915d9a5d7SFelix Fietkau 	mphy->txpower_cur = tx_power;
208015d9a5d7SFelix Fietkau 
2081729d3dbdSLorenzo Bianconi 	if (is_mt7663(mphy->dev)) {
2082729d3dbdSLorenzo Bianconi 		memset(sku, tx_power, MT_SKU_4SS_DELTA + 1);
2083729d3dbdSLorenzo Bianconi 		return;
2084729d3dbdSLorenzo Bianconi 	}
2085729d3dbdSLorenzo Bianconi 
208615d9a5d7SFelix Fietkau 	for (i = 0; i < MT_SKU_1SS_DELTA; i++)
2087fb0d9054SFelix Fietkau 		sku[i] = limits_array[sku_mapping[i]];
208815d9a5d7SFelix Fietkau 
208915d9a5d7SFelix Fietkau 	for (i = 0; i < 4; i++) {
209015d9a5d7SFelix Fietkau 		int delta = 0;
209115d9a5d7SFelix Fietkau 
209215d9a5d7SFelix Fietkau 		if (i < n_chains - 1)
209307cda406SFelix Fietkau 			delta = mt76_tx_power_nss_delta(n_chains) -
209407cda406SFelix Fietkau 				mt76_tx_power_nss_delta(i + 1);
209515d9a5d7SFelix Fietkau 		sku[MT_SKU_1SS_DELTA + i] = delta;
209615d9a5d7SFelix Fietkau 	}
209715d9a5d7SFelix Fietkau }
209815d9a5d7SFelix Fietkau 
mt7615_mcu_chan_bw(struct cfg80211_chan_def * chandef)2099ad380ad1SFelix Fietkau static u8 mt7615_mcu_chan_bw(struct cfg80211_chan_def *chandef)
2100ad380ad1SFelix Fietkau {
2101ad380ad1SFelix Fietkau 	static const u8 width_to_bw[] = {
2102ad380ad1SFelix Fietkau 		[NL80211_CHAN_WIDTH_40] = CMD_CBW_40MHZ,
2103ad380ad1SFelix Fietkau 		[NL80211_CHAN_WIDTH_80] = CMD_CBW_80MHZ,
2104ad380ad1SFelix Fietkau 		[NL80211_CHAN_WIDTH_80P80] = CMD_CBW_8080MHZ,
2105ad380ad1SFelix Fietkau 		[NL80211_CHAN_WIDTH_160] = CMD_CBW_160MHZ,
2106ad380ad1SFelix Fietkau 		[NL80211_CHAN_WIDTH_5] = CMD_CBW_5MHZ,
2107ad380ad1SFelix Fietkau 		[NL80211_CHAN_WIDTH_10] = CMD_CBW_10MHZ,
2108ad380ad1SFelix Fietkau 		[NL80211_CHAN_WIDTH_20] = CMD_CBW_20MHZ,
2109ad380ad1SFelix Fietkau 		[NL80211_CHAN_WIDTH_20_NOHT] = CMD_CBW_20MHZ,
2110ad380ad1SFelix Fietkau 	};
2111ad380ad1SFelix Fietkau 
2112ad380ad1SFelix Fietkau 	if (chandef->width >= ARRAY_SIZE(width_to_bw))
2113ad380ad1SFelix Fietkau 		return 0;
2114ad380ad1SFelix Fietkau 
2115ad380ad1SFelix Fietkau 	return width_to_bw[chandef->width];
2116ad380ad1SFelix Fietkau }
2117ad380ad1SFelix Fietkau 
mt7615_mcu_set_chan_info(struct mt7615_phy * phy,int cmd)21184fe9218cSRyder Lee int mt7615_mcu_set_chan_info(struct mt7615_phy *phy, int cmd)
211904b8e659SRyder Lee {
2120fdd2e570SFelix Fietkau 	struct mt7615_dev *dev = phy->dev;
2121fdd2e570SFelix Fietkau 	struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
212202fc62e3SLorenzo Bianconi 	int freq1 = chandef->center_freq1, freq2 = chandef->center_freq2;
212304b8e659SRyder Lee 	struct {
212404b8e659SRyder Lee 		u8 control_chan;
212504b8e659SRyder Lee 		u8 center_chan;
212604b8e659SRyder Lee 		u8 bw;
212704b8e659SRyder Lee 		u8 tx_streams;
212804b8e659SRyder Lee 		u8 rx_streams_mask;
212904b8e659SRyder Lee 		u8 switch_reason;
213004b8e659SRyder Lee 		u8 band_idx;
213104b8e659SRyder Lee 		/* for 80+80 only */
213204b8e659SRyder Lee 		u8 center_chan2;
213304b8e659SRyder Lee 		__le16 cac_case;
213404b8e659SRyder Lee 		u8 channel_band;
213504b8e659SRyder Lee 		u8 rsv0;
213604b8e659SRyder Lee 		__le32 outband_freq;
213704b8e659SRyder Lee 		u8 txpower_drop;
213804b8e659SRyder Lee 		u8 rsv1[3];
213904b8e659SRyder Lee 		u8 txpower_sku[53];
214004b8e659SRyder Lee 		u8 rsv2[3];
214102fc62e3SLorenzo Bianconi 	} req = {
214202fc62e3SLorenzo Bianconi 		.control_chan = chandef->chan->hw_value,
214302fc62e3SLorenzo Bianconi 		.center_chan = ieee80211_frequency_to_channel(freq1),
21444fe9218cSRyder Lee 		.tx_streams = hweight8(phy->mt76->antenna_mask),
2145b9027e08SLorenzo Bianconi 		.rx_streams_mask = phy->mt76->chainmask,
214602fc62e3SLorenzo Bianconi 		.center_chan2 = ieee80211_frequency_to_channel(freq2),
214702fc62e3SLorenzo Bianconi 	};
214804b8e659SRyder Lee 
214924e69f6bSDeren Wu 	if (cmd == MCU_EXT_CMD(SET_RX_PATH) ||
2150*94ed41a7SShayne Chen 	    phy->mt76->hw->conf.flags & IEEE80211_CONF_MONITOR)
215100a883e6SFelix Fietkau 		req.switch_reason = CH_SWITCH_NORMAL;
215200a883e6SFelix Fietkau 	else if (phy->mt76->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)
21532b5d1b91SLorenzo Bianconi 		req.switch_reason = CH_SWITCH_SCAN_BYPASS_DPD;
215400a883e6SFelix Fietkau 	else if (!cfg80211_reg_can_beacon(phy->mt76->hw->wiphy, chandef,
215500a883e6SFelix Fietkau 					  NL80211_IFTYPE_AP))
215602fc62e3SLorenzo Bianconi 		req.switch_reason = CH_SWITCH_DFS;
215702fc62e3SLorenzo Bianconi 	else
215804b8e659SRyder Lee 		req.switch_reason = CH_SWITCH_NORMAL;
215904b8e659SRyder Lee 
2160fdd2e570SFelix Fietkau 	req.band_idx = phy != &dev->phy;
2161ad380ad1SFelix Fietkau 	req.bw = mt7615_mcu_chan_bw(chandef);
216215d9a5d7SFelix Fietkau 
2163c918c74dSShayne Chen 	if (mt76_testmode_enabled(phy->mt76))
21644f0bce1cSFelix Fietkau 		memset(req.txpower_sku, 0x3f, 49);
21654f0bce1cSFelix Fietkau 	else
216615d9a5d7SFelix Fietkau 		mt7615_mcu_set_txpower_sku(phy, req.txpower_sku);
216704b8e659SRyder Lee 
2168cb5cdd4cSFelix Fietkau 	return mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), true);
216904b8e659SRyder Lee }
217004b8e659SRyder Lee 
mt7615_mcu_get_temperature(struct mt7615_dev * dev)2171109e505aSRyder Lee int mt7615_mcu_get_temperature(struct mt7615_dev *dev)
21720e6a29e4SLorenzo Bianconi {
21730e6a29e4SLorenzo Bianconi 	struct {
21740e6a29e4SLorenzo Bianconi 		u8 action;
21750e6a29e4SLorenzo Bianconi 		u8 rsv[3];
2176109e505aSRyder Lee 	} req = {};
21770e6a29e4SLorenzo Bianconi 
21789d8d136cSLorenzo Bianconi 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(THERMAL_CTRL),
2179e6d2070dSLorenzo Bianconi 				 &req, sizeof(req), true);
21800e6a29e4SLorenzo Bianconi }
218115d9a5d7SFelix Fietkau 
mt7615_mcu_set_test_param(struct mt7615_dev * dev,u8 param,bool test_mode,u32 val)21824f0bce1cSFelix Fietkau int mt7615_mcu_set_test_param(struct mt7615_dev *dev, u8 param, bool test_mode,
21834f0bce1cSFelix Fietkau 			      u32 val)
21844f0bce1cSFelix Fietkau {
21854f0bce1cSFelix Fietkau 	struct {
21864f0bce1cSFelix Fietkau 		u8 test_mode_en;
21874f0bce1cSFelix Fietkau 		u8 param_idx;
21884f0bce1cSFelix Fietkau 		u8 _rsv[2];
21894f0bce1cSFelix Fietkau 
21904f0bce1cSFelix Fietkau 		__le32 value;
21914f0bce1cSFelix Fietkau 
21924f0bce1cSFelix Fietkau 		u8 pad[8];
21934f0bce1cSFelix Fietkau 	} req = {
21944f0bce1cSFelix Fietkau 		.test_mode_en = test_mode,
21954f0bce1cSFelix Fietkau 		.param_idx = param,
21964f0bce1cSFelix Fietkau 		.value = cpu_to_le32(val),
21974f0bce1cSFelix Fietkau 	};
21984f0bce1cSFelix Fietkau 
2199e6d2070dSLorenzo Bianconi 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(ATE_CTRL),
2200e6d2070dSLorenzo Bianconi 				 &req, sizeof(req), false);
22014f0bce1cSFelix Fietkau }
22024f0bce1cSFelix Fietkau 
mt7615_mcu_set_sku_en(struct mt7615_phy * phy,bool enable)220315d9a5d7SFelix Fietkau int mt7615_mcu_set_sku_en(struct mt7615_phy *phy, bool enable)
220415d9a5d7SFelix Fietkau {
220515d9a5d7SFelix Fietkau 	struct mt7615_dev *dev = phy->dev;
220615d9a5d7SFelix Fietkau 	struct {
220715d9a5d7SFelix Fietkau 		u8 format_id;
220815d9a5d7SFelix Fietkau 		u8 sku_enable;
220915d9a5d7SFelix Fietkau 		u8 band_idx;
221015d9a5d7SFelix Fietkau 		u8 rsv;
221115d9a5d7SFelix Fietkau 	} req = {
221215d9a5d7SFelix Fietkau 		.format_id = 0,
221315d9a5d7SFelix Fietkau 		.band_idx = phy != &dev->phy,
221415d9a5d7SFelix Fietkau 		.sku_enable = enable,
221515d9a5d7SFelix Fietkau 	};
221615d9a5d7SFelix Fietkau 
2217cb5cdd4cSFelix Fietkau 	return mt76_mcu_send_msg(&dev->mt76,
2218e6d2070dSLorenzo Bianconi 				 MCU_EXT_CMD(TX_POWER_FEATURE_CTRL),
2219e6d2070dSLorenzo Bianconi 				 &req, sizeof(req), true);
222015d9a5d7SFelix Fietkau }
2221bf18fcdcSLorenzo Bianconi 
mt7615_find_freq_idx(const u16 * freqs,int n_freqs,u16 cur)2222ad380ad1SFelix Fietkau static int mt7615_find_freq_idx(const u16 *freqs, int n_freqs, u16 cur)
2223ad380ad1SFelix Fietkau {
2224ad380ad1SFelix Fietkau 	int i;
2225ad380ad1SFelix Fietkau 
2226ad380ad1SFelix Fietkau 	for (i = 0; i < n_freqs; i++)
2227ad380ad1SFelix Fietkau 		if (cur == freqs[i])
2228ad380ad1SFelix Fietkau 			return i;
2229ad380ad1SFelix Fietkau 
2230ad380ad1SFelix Fietkau 	return -1;
2231ad380ad1SFelix Fietkau }
2232ad380ad1SFelix Fietkau 
mt7615_dcoc_freq_idx(u16 freq,u8 bw)2233ad380ad1SFelix Fietkau static int mt7615_dcoc_freq_idx(u16 freq, u8 bw)
2234ad380ad1SFelix Fietkau {
2235ad380ad1SFelix Fietkau 	static const u16 freq_list[] = {
2236ad380ad1SFelix Fietkau 		4980, 5805, 5905, 5190,
2237ad380ad1SFelix Fietkau 		5230, 5270, 5310, 5350,
2238ad380ad1SFelix Fietkau 		5390, 5430, 5470, 5510,
2239ad380ad1SFelix Fietkau 		5550, 5590, 5630, 5670,
2240ad380ad1SFelix Fietkau 		5710, 5755, 5795, 5835,
2241ad380ad1SFelix Fietkau 		5875, 5210, 5290, 5370,
2242ad380ad1SFelix Fietkau 		5450, 5530, 5610, 5690,
2243ad380ad1SFelix Fietkau 		5775, 5855
2244ad380ad1SFelix Fietkau 	};
2245ad380ad1SFelix Fietkau 	static const u16 freq_bw40[] = {
2246ad380ad1SFelix Fietkau 		5190, 5230, 5270, 5310,
2247ad380ad1SFelix Fietkau 		5350, 5390, 5430, 5470,
2248ad380ad1SFelix Fietkau 		5510, 5550, 5590, 5630,
2249ad380ad1SFelix Fietkau 		5670, 5710, 5755, 5795,
2250ad380ad1SFelix Fietkau 		5835, 5875
2251ad380ad1SFelix Fietkau 	};
2252ad380ad1SFelix Fietkau 	int offset_2g = ARRAY_SIZE(freq_list);
2253ad380ad1SFelix Fietkau 	int idx;
2254ad380ad1SFelix Fietkau 
2255ad380ad1SFelix Fietkau 	if (freq < 4000) {
2256ad380ad1SFelix Fietkau 		if (freq < 2427)
2257ad380ad1SFelix Fietkau 			return offset_2g;
2258ad380ad1SFelix Fietkau 		if (freq < 2442)
2259ad380ad1SFelix Fietkau 			return offset_2g + 1;
2260ad380ad1SFelix Fietkau 		if (freq < 2457)
2261ad380ad1SFelix Fietkau 			return offset_2g + 2;
2262ad380ad1SFelix Fietkau 
2263ad380ad1SFelix Fietkau 		return offset_2g + 3;
2264ad380ad1SFelix Fietkau 	}
2265ad380ad1SFelix Fietkau 
2266ad380ad1SFelix Fietkau 	switch (bw) {
2267ad380ad1SFelix Fietkau 	case NL80211_CHAN_WIDTH_80:
2268ad380ad1SFelix Fietkau 	case NL80211_CHAN_WIDTH_80P80:
2269ad380ad1SFelix Fietkau 	case NL80211_CHAN_WIDTH_160:
2270ad380ad1SFelix Fietkau 		break;
2271ad380ad1SFelix Fietkau 	default:
2272ad380ad1SFelix Fietkau 		idx = mt7615_find_freq_idx(freq_bw40, ARRAY_SIZE(freq_bw40),
2273ad380ad1SFelix Fietkau 					   freq + 10);
2274ad380ad1SFelix Fietkau 		if (idx >= 0) {
2275ad380ad1SFelix Fietkau 			freq = freq_bw40[idx];
2276ad380ad1SFelix Fietkau 			break;
2277ad380ad1SFelix Fietkau 		}
2278ad380ad1SFelix Fietkau 
2279ad380ad1SFelix Fietkau 		idx = mt7615_find_freq_idx(freq_bw40, ARRAY_SIZE(freq_bw40),
2280ad380ad1SFelix Fietkau 					   freq - 10);
2281ad380ad1SFelix Fietkau 		if (idx >= 0) {
2282ad380ad1SFelix Fietkau 			freq = freq_bw40[idx];
2283ad380ad1SFelix Fietkau 			break;
2284ad380ad1SFelix Fietkau 		}
2285aab662ccSGustavo A. R. Silva 		fallthrough;
2286ad380ad1SFelix Fietkau 	case NL80211_CHAN_WIDTH_40:
2287ad380ad1SFelix Fietkau 		idx = mt7615_find_freq_idx(freq_bw40, ARRAY_SIZE(freq_bw40),
2288ad380ad1SFelix Fietkau 					   freq);
2289ad380ad1SFelix Fietkau 		if (idx >= 0)
2290ad380ad1SFelix Fietkau 			break;
2291ad380ad1SFelix Fietkau 
2292ad380ad1SFelix Fietkau 		return -1;
2293ad380ad1SFelix Fietkau 
2294ad380ad1SFelix Fietkau 	}
2295ad380ad1SFelix Fietkau 
2296ad380ad1SFelix Fietkau 	return mt7615_find_freq_idx(freq_list, ARRAY_SIZE(freq_list), freq);
2297ad380ad1SFelix Fietkau }
2298ad380ad1SFelix Fietkau 
mt7615_mcu_apply_rx_dcoc(struct mt7615_phy * phy)2299ad380ad1SFelix Fietkau int mt7615_mcu_apply_rx_dcoc(struct mt7615_phy *phy)
2300ad380ad1SFelix Fietkau {
2301ad380ad1SFelix Fietkau 	struct mt7615_dev *dev = phy->dev;
2302ad380ad1SFelix Fietkau 	struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
2303ad380ad1SFelix Fietkau 	int freq2 = chandef->center_freq2;
2304ad380ad1SFelix Fietkau 	int ret;
2305ad380ad1SFelix Fietkau 	struct {
2306ad380ad1SFelix Fietkau 		u8 direction;
2307ad380ad1SFelix Fietkau 		u8 runtime_calibration;
2308ad380ad1SFelix Fietkau 		u8 _rsv[2];
2309ad380ad1SFelix Fietkau 
2310ad380ad1SFelix Fietkau 		__le16 center_freq;
2311ad380ad1SFelix Fietkau 		u8 bw;
2312ad380ad1SFelix Fietkau 		u8 band;
2313ad380ad1SFelix Fietkau 		u8 is_freq2;
2314ad380ad1SFelix Fietkau 		u8 success;
2315ad380ad1SFelix Fietkau 		u8 dbdc_en;
2316ad380ad1SFelix Fietkau 
2317ad380ad1SFelix Fietkau 		u8 _rsv2;
2318ad380ad1SFelix Fietkau 
2319ad380ad1SFelix Fietkau 		struct {
2320ad380ad1SFelix Fietkau 			__le32 sx0_i_lna[4];
2321ad380ad1SFelix Fietkau 			__le32 sx0_q_lna[4];
2322ad380ad1SFelix Fietkau 
2323ad380ad1SFelix Fietkau 			__le32 sx2_i_lna[4];
2324ad380ad1SFelix Fietkau 			__le32 sx2_q_lna[4];
2325ad380ad1SFelix Fietkau 		} dcoc_data[4];
2326ad380ad1SFelix Fietkau 	} req = {
2327ad380ad1SFelix Fietkau 		.direction = 1,
2328ad380ad1SFelix Fietkau 
2329ad380ad1SFelix Fietkau 		.bw = mt7615_mcu_chan_bw(chandef),
2330ad380ad1SFelix Fietkau 		.band = chandef->center_freq1 > 4000,
2331dc44c45cSLorenzo Bianconi 		.dbdc_en = !!dev->mt76.phys[MT_BAND1],
2332ad380ad1SFelix Fietkau 	};
2333ad380ad1SFelix Fietkau 	u16 center_freq = chandef->center_freq1;
2334ad380ad1SFelix Fietkau 	int freq_idx;
2335ad380ad1SFelix Fietkau 	u8 *eep = dev->mt76.eeprom.data;
2336ad380ad1SFelix Fietkau 
2337ad380ad1SFelix Fietkau 	if (!(eep[MT_EE_CALDATA_FLASH] & MT_EE_CALDATA_FLASH_RX_CAL))
2338ad380ad1SFelix Fietkau 		return 0;
2339ad380ad1SFelix Fietkau 
2340ad380ad1SFelix Fietkau 	if (chandef->width == NL80211_CHAN_WIDTH_160) {
2341ad380ad1SFelix Fietkau 		freq2 = center_freq + 40;
2342ad380ad1SFelix Fietkau 		center_freq -= 40;
2343ad380ad1SFelix Fietkau 	}
2344ad380ad1SFelix Fietkau 
2345ad380ad1SFelix Fietkau again:
2346ad380ad1SFelix Fietkau 	req.runtime_calibration = 1;
2347ad380ad1SFelix Fietkau 	freq_idx = mt7615_dcoc_freq_idx(center_freq, chandef->width);
2348ad380ad1SFelix Fietkau 	if (freq_idx < 0)
2349ad380ad1SFelix Fietkau 		goto out;
2350ad380ad1SFelix Fietkau 
2351ad380ad1SFelix Fietkau 	memcpy(req.dcoc_data, eep + MT7615_EEPROM_DCOC_OFFSET +
2352ad380ad1SFelix Fietkau 			      freq_idx * MT7615_EEPROM_DCOC_SIZE,
2353ad380ad1SFelix Fietkau 	       sizeof(req.dcoc_data));
2354ad380ad1SFelix Fietkau 	req.runtime_calibration = 0;
2355ad380ad1SFelix Fietkau 
2356ad380ad1SFelix Fietkau out:
2357ad380ad1SFelix Fietkau 	req.center_freq = cpu_to_le16(center_freq);
2358e6d2070dSLorenzo Bianconi 	ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RXDCOC_CAL), &req,
2359ad380ad1SFelix Fietkau 				sizeof(req), true);
2360ad380ad1SFelix Fietkau 
2361ad380ad1SFelix Fietkau 	if ((chandef->width == NL80211_CHAN_WIDTH_80P80 ||
2362ad380ad1SFelix Fietkau 	     chandef->width == NL80211_CHAN_WIDTH_160) && !req.is_freq2) {
2363ad380ad1SFelix Fietkau 		req.is_freq2 = true;
2364ad380ad1SFelix Fietkau 		center_freq = freq2;
2365ad380ad1SFelix Fietkau 		goto again;
2366ad380ad1SFelix Fietkau 	}
2367ad380ad1SFelix Fietkau 
2368ad380ad1SFelix Fietkau 	return ret;
2369ad380ad1SFelix Fietkau }
2370371a59d1SFelix Fietkau 
mt7615_dpd_freq_idx(u16 freq,u8 bw)2371371a59d1SFelix Fietkau static int mt7615_dpd_freq_idx(u16 freq, u8 bw)
2372371a59d1SFelix Fietkau {
2373371a59d1SFelix Fietkau 	static const u16 freq_list[] = {
2374371a59d1SFelix Fietkau 		4920, 4940, 4960, 4980,
2375371a59d1SFelix Fietkau 		5040, 5060, 5080, 5180,
2376371a59d1SFelix Fietkau 		5200, 5220, 5240, 5260,
2377371a59d1SFelix Fietkau 		5280, 5300, 5320, 5340,
2378371a59d1SFelix Fietkau 		5360, 5380, 5400, 5420,
2379371a59d1SFelix Fietkau 		5440, 5460, 5480, 5500,
2380371a59d1SFelix Fietkau 		5520, 5540, 5560, 5580,
2381371a59d1SFelix Fietkau 		5600, 5620, 5640, 5660,
2382371a59d1SFelix Fietkau 		5680, 5700, 5720, 5745,
2383371a59d1SFelix Fietkau 		5765, 5785, 5805, 5825,
2384371a59d1SFelix Fietkau 		5845, 5865, 5885, 5905
2385371a59d1SFelix Fietkau 	};
2386371a59d1SFelix Fietkau 	int offset_2g = ARRAY_SIZE(freq_list);
2387371a59d1SFelix Fietkau 	int idx;
2388371a59d1SFelix Fietkau 
2389371a59d1SFelix Fietkau 	if (freq < 4000) {
2390371a59d1SFelix Fietkau 		if (freq < 2432)
2391371a59d1SFelix Fietkau 			return offset_2g;
2392371a59d1SFelix Fietkau 		if (freq < 2457)
2393371a59d1SFelix Fietkau 			return offset_2g + 1;
2394371a59d1SFelix Fietkau 
2395371a59d1SFelix Fietkau 		return offset_2g + 2;
2396371a59d1SFelix Fietkau 	}
2397371a59d1SFelix Fietkau 
2398371a59d1SFelix Fietkau 	if (bw != NL80211_CHAN_WIDTH_20) {
2399371a59d1SFelix Fietkau 		idx = mt7615_find_freq_idx(freq_list, ARRAY_SIZE(freq_list),
2400371a59d1SFelix Fietkau 					   freq + 10);
2401371a59d1SFelix Fietkau 		if (idx >= 0)
2402371a59d1SFelix Fietkau 			return idx;
2403371a59d1SFelix Fietkau 
2404371a59d1SFelix Fietkau 		idx = mt7615_find_freq_idx(freq_list, ARRAY_SIZE(freq_list),
2405371a59d1SFelix Fietkau 					   freq - 10);
2406371a59d1SFelix Fietkau 		if (idx >= 0)
2407371a59d1SFelix Fietkau 			return idx;
2408371a59d1SFelix Fietkau 	}
2409371a59d1SFelix Fietkau 
2410371a59d1SFelix Fietkau 	return mt7615_find_freq_idx(freq_list, ARRAY_SIZE(freq_list), freq);
2411371a59d1SFelix Fietkau }
2412371a59d1SFelix Fietkau 
2413371a59d1SFelix Fietkau 
mt7615_mcu_apply_tx_dpd(struct mt7615_phy * phy)2414371a59d1SFelix Fietkau int mt7615_mcu_apply_tx_dpd(struct mt7615_phy *phy)
2415371a59d1SFelix Fietkau {
2416371a59d1SFelix Fietkau 	struct mt7615_dev *dev = phy->dev;
2417371a59d1SFelix Fietkau 	struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
2418371a59d1SFelix Fietkau 	int freq2 = chandef->center_freq2;
2419371a59d1SFelix Fietkau 	int ret;
2420371a59d1SFelix Fietkau 	struct {
2421371a59d1SFelix Fietkau 		u8 direction;
2422371a59d1SFelix Fietkau 		u8 runtime_calibration;
2423371a59d1SFelix Fietkau 		u8 _rsv[2];
2424371a59d1SFelix Fietkau 
2425371a59d1SFelix Fietkau 		__le16 center_freq;
2426371a59d1SFelix Fietkau 		u8 bw;
2427371a59d1SFelix Fietkau 		u8 band;
2428371a59d1SFelix Fietkau 		u8 is_freq2;
2429371a59d1SFelix Fietkau 		u8 success;
2430371a59d1SFelix Fietkau 		u8 dbdc_en;
2431371a59d1SFelix Fietkau 
2432371a59d1SFelix Fietkau 		u8 _rsv2;
2433371a59d1SFelix Fietkau 
2434371a59d1SFelix Fietkau 		struct {
2435371a59d1SFelix Fietkau 			struct {
2436371a59d1SFelix Fietkau 				u32 dpd_g0;
2437371a59d1SFelix Fietkau 				u8 data[32];
2438371a59d1SFelix Fietkau 			} wf0, wf1;
2439371a59d1SFelix Fietkau 
2440371a59d1SFelix Fietkau 			struct {
2441371a59d1SFelix Fietkau 				u32 dpd_g0_prim;
2442371a59d1SFelix Fietkau 				u32 dpd_g0_sec;
2443371a59d1SFelix Fietkau 				u8 data_prim[32];
2444371a59d1SFelix Fietkau 				u8 data_sec[32];
2445371a59d1SFelix Fietkau 			} wf2, wf3;
2446371a59d1SFelix Fietkau 		} dpd_data;
2447371a59d1SFelix Fietkau 	} req = {
2448371a59d1SFelix Fietkau 		.direction = 1,
2449371a59d1SFelix Fietkau 
2450371a59d1SFelix Fietkau 		.bw = mt7615_mcu_chan_bw(chandef),
2451371a59d1SFelix Fietkau 		.band = chandef->center_freq1 > 4000,
2452dc44c45cSLorenzo Bianconi 		.dbdc_en = !!dev->mt76.phys[MT_BAND1],
2453371a59d1SFelix Fietkau 	};
2454371a59d1SFelix Fietkau 	u16 center_freq = chandef->center_freq1;
2455371a59d1SFelix Fietkau 	int freq_idx;
2456371a59d1SFelix Fietkau 	u8 *eep = dev->mt76.eeprom.data;
2457371a59d1SFelix Fietkau 
2458371a59d1SFelix Fietkau 	if (!(eep[MT_EE_CALDATA_FLASH] & MT_EE_CALDATA_FLASH_TX_DPD))
2459371a59d1SFelix Fietkau 		return 0;
2460371a59d1SFelix Fietkau 
2461371a59d1SFelix Fietkau 	if (chandef->width == NL80211_CHAN_WIDTH_160) {
2462371a59d1SFelix Fietkau 		freq2 = center_freq + 40;
2463371a59d1SFelix Fietkau 		center_freq -= 40;
2464371a59d1SFelix Fietkau 	}
2465371a59d1SFelix Fietkau 
2466371a59d1SFelix Fietkau again:
2467371a59d1SFelix Fietkau 	req.runtime_calibration = 1;
2468371a59d1SFelix Fietkau 	freq_idx = mt7615_dpd_freq_idx(center_freq, chandef->width);
2469371a59d1SFelix Fietkau 	if (freq_idx < 0)
2470371a59d1SFelix Fietkau 		goto out;
2471371a59d1SFelix Fietkau 
2472371a59d1SFelix Fietkau 	memcpy(&req.dpd_data, eep + MT7615_EEPROM_TXDPD_OFFSET +
2473371a59d1SFelix Fietkau 			      freq_idx * MT7615_EEPROM_TXDPD_SIZE,
2474371a59d1SFelix Fietkau 	       sizeof(req.dpd_data));
2475371a59d1SFelix Fietkau 	req.runtime_calibration = 0;
2476371a59d1SFelix Fietkau 
2477371a59d1SFelix Fietkau out:
2478371a59d1SFelix Fietkau 	req.center_freq = cpu_to_le16(center_freq);
2479e6d2070dSLorenzo Bianconi 	ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(TXDPD_CAL),
2480e6d2070dSLorenzo Bianconi 				&req, sizeof(req), true);
2481371a59d1SFelix Fietkau 
2482371a59d1SFelix Fietkau 	if ((chandef->width == NL80211_CHAN_WIDTH_80P80 ||
2483371a59d1SFelix Fietkau 	     chandef->width == NL80211_CHAN_WIDTH_160) && !req.is_freq2) {
2484371a59d1SFelix Fietkau 		req.is_freq2 = true;
2485371a59d1SFelix Fietkau 		center_freq = freq2;
2486371a59d1SFelix Fietkau 		goto again;
2487371a59d1SFelix Fietkau 	}
2488371a59d1SFelix Fietkau 
2489371a59d1SFelix Fietkau 	return ret;
2490371a59d1SFelix Fietkau }
24916f117852SSean Wang 
mt7615_mcu_set_rx_hdr_trans_blacklist(struct mt7615_dev * dev)2492d4b98c63SRyder Lee int mt7615_mcu_set_rx_hdr_trans_blacklist(struct mt7615_dev *dev)
2493d4b98c63SRyder Lee {
2494d4b98c63SRyder Lee 	struct {
2495d4b98c63SRyder Lee 		u8 operation;
2496d4b98c63SRyder Lee 		u8 count;
2497d4b98c63SRyder Lee 		u8 _rsv[2];
2498d4b98c63SRyder Lee 		u8 index;
2499d4b98c63SRyder Lee 		u8 enable;
2500d4b98c63SRyder Lee 		__le16 etype;
2501d4b98c63SRyder Lee 	} req = {
2502d4b98c63SRyder Lee 		.operation = 1,
2503d4b98c63SRyder Lee 		.count = 1,
2504d4b98c63SRyder Lee 		.enable = 1,
2505d4b98c63SRyder Lee 		.etype = cpu_to_le16(ETH_P_PAE),
2506d4b98c63SRyder Lee 	};
2507d4b98c63SRyder Lee 
2508e6d2070dSLorenzo Bianconi 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RX_HDR_TRANS),
2509d4b98c63SRyder Lee 				 &req, sizeof(req), false);
2510d4b98c63SRyder Lee }
2511d4b98c63SRyder Lee 
mt7615_mcu_set_bss_pm(struct mt7615_dev * dev,struct ieee80211_vif * vif,bool enable)251283b9f42aSLorenzo Bianconi int mt7615_mcu_set_bss_pm(struct mt7615_dev *dev, struct ieee80211_vif *vif,
2513c6bf2010SLorenzo Bianconi 			  bool enable)
2514c6bf2010SLorenzo Bianconi {
2515c6bf2010SLorenzo Bianconi 	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
2516c6bf2010SLorenzo Bianconi 	struct {
2517c6bf2010SLorenzo Bianconi 		u8 bss_idx;
2518c6bf2010SLorenzo Bianconi 		u8 dtim_period;
2519c6bf2010SLorenzo Bianconi 		__le16 aid;
2520c6bf2010SLorenzo Bianconi 		__le16 bcn_interval;
2521c6bf2010SLorenzo Bianconi 		__le16 atim_window;
2522c6bf2010SLorenzo Bianconi 		u8 uapsd;
2523c6bf2010SLorenzo Bianconi 		u8 bmc_delivered_ac;
2524c6bf2010SLorenzo Bianconi 		u8 bmc_triggered_ac;
2525c6bf2010SLorenzo Bianconi 		u8 pad;
2526c6bf2010SLorenzo Bianconi 	} req = {
252785d96704SLorenzo Bianconi 		.bss_idx = mvif->mt76.idx,
2528f276e20bSJohannes Berg 		.aid = cpu_to_le16(vif->cfg.aid),
2529c6bf2010SLorenzo Bianconi 		.dtim_period = vif->bss_conf.dtim_period,
2530c6bf2010SLorenzo Bianconi 		.bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int),
2531c6bf2010SLorenzo Bianconi 	};
2532c6bf2010SLorenzo Bianconi 	struct {
2533c6bf2010SLorenzo Bianconi 		u8 bss_idx;
2534c6bf2010SLorenzo Bianconi 		u8 pad[3];
2535c6bf2010SLorenzo Bianconi 	} req_hdr = {
253685d96704SLorenzo Bianconi 		.bss_idx = mvif->mt76.idx,
2537c6bf2010SLorenzo Bianconi 	};
2538c6bf2010SLorenzo Bianconi 	int err;
2539c6bf2010SLorenzo Bianconi 
25407124198aSLorenzo Bianconi 	if (vif->type != NL80211_IFTYPE_STATION)
25417124198aSLorenzo Bianconi 		return 0;
2542c6bf2010SLorenzo Bianconi 
2543680a2eadSLorenzo Bianconi 	err = mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_BSS_ABORT),
2544680a2eadSLorenzo Bianconi 				&req_hdr, sizeof(req_hdr), false);
2545c6bf2010SLorenzo Bianconi 	if (err < 0 || !enable)
2546c6bf2010SLorenzo Bianconi 		return err;
2547c6bf2010SLorenzo Bianconi 
2548680a2eadSLorenzo Bianconi 	return mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_BSS_CONNECTED),
2549680a2eadSLorenzo Bianconi 				 &req, sizeof(req), false);
2550c6bf2010SLorenzo Bianconi }
2551c6bf2010SLorenzo Bianconi 
mt7615_mcu_set_roc(struct mt7615_phy * phy,struct ieee80211_vif * vif,struct ieee80211_channel * chan,int duration)25527307f296SLorenzo Bianconi int mt7615_mcu_set_roc(struct mt7615_phy *phy, struct ieee80211_vif *vif,
25537307f296SLorenzo Bianconi 		       struct ieee80211_channel *chan, int duration)
25547307f296SLorenzo Bianconi {
25557307f296SLorenzo Bianconi 	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
25567307f296SLorenzo Bianconi 	struct mt7615_dev *dev = phy->dev;
25577307f296SLorenzo Bianconi 	struct mt7615_roc_tlv req = {
255885d96704SLorenzo Bianconi 		.bss_idx = mvif->mt76.idx,
25597307f296SLorenzo Bianconi 		.active = !chan,
25607307f296SLorenzo Bianconi 		.max_interval = cpu_to_le32(duration),
25617307f296SLorenzo Bianconi 		.primary_chan = chan ? chan->hw_value : 0,
25627307f296SLorenzo Bianconi 		.band = chan ? chan->band : 0,
25637307f296SLorenzo Bianconi 		.req_type = 2,
25647307f296SLorenzo Bianconi 	};
25657307f296SLorenzo Bianconi 
25667307f296SLorenzo Bianconi 	phy->roc_grant = false;
25677307f296SLorenzo Bianconi 
2568680a2eadSLorenzo Bianconi 	return mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_ROC),
2569680a2eadSLorenzo Bianconi 				 &req, sizeof(req), false);
25707307f296SLorenzo Bianconi }
2571