xref: /freebsd/sys/contrib/dev/mediatek/mt76/mt7615/mcu.c (revision cbb3ec25236ba72f91cbdf23f8b78b9d1af0cedf)
16c92544dSBjoern A. Zeeb // SPDX-License-Identifier: ISC
26c92544dSBjoern A. Zeeb /* Copyright (C) 2019 MediaTek Inc.
36c92544dSBjoern A. Zeeb  *
46c92544dSBjoern A. Zeeb  * Author: Roy Luo <royluo@google.com>
56c92544dSBjoern A. Zeeb  *         Ryder Lee <ryder.lee@mediatek.com>
66c92544dSBjoern A. Zeeb  */
76c92544dSBjoern A. Zeeb 
86c92544dSBjoern A. Zeeb #include <linux/firmware.h>
96c92544dSBjoern A. Zeeb #include "mt7615.h"
106c92544dSBjoern A. Zeeb #include "mcu.h"
116c92544dSBjoern A. Zeeb #include "mac.h"
126c92544dSBjoern A. Zeeb #include "eeprom.h"
136c92544dSBjoern A. Zeeb 
146c92544dSBjoern A. Zeeb static bool prefer_offload_fw = true;
156c92544dSBjoern A. Zeeb module_param(prefer_offload_fw, bool, 0644);
166c92544dSBjoern A. Zeeb MODULE_PARM_DESC(prefer_offload_fw,
176c92544dSBjoern A. Zeeb 		 "Prefer client mode offload firmware (MT7663)");
186c92544dSBjoern A. Zeeb 
196c92544dSBjoern A. Zeeb struct mt7615_patch_hdr {
206c92544dSBjoern A. Zeeb 	char build_date[16];
216c92544dSBjoern A. Zeeb 	char platform[4];
226c92544dSBjoern A. Zeeb 	__be32 hw_sw_ver;
236c92544dSBjoern A. Zeeb 	__be32 patch_ver;
246c92544dSBjoern A. Zeeb 	__be16 checksum;
256c92544dSBjoern A. Zeeb } __packed;
266c92544dSBjoern A. Zeeb 
276c92544dSBjoern A. Zeeb struct mt7615_fw_trailer {
286c92544dSBjoern A. Zeeb 	__le32 addr;
296c92544dSBjoern A. Zeeb 	u8 chip_id;
306c92544dSBjoern A. Zeeb 	u8 feature_set;
316c92544dSBjoern A. Zeeb 	u8 eco_code;
326c92544dSBjoern A. Zeeb 	char fw_ver[10];
336c92544dSBjoern A. Zeeb 	char build_date[15];
346c92544dSBjoern A. Zeeb 	__le32 len;
356c92544dSBjoern A. Zeeb } __packed;
366c92544dSBjoern A. Zeeb 
376c92544dSBjoern A. Zeeb #define FW_V3_COMMON_TAILER_SIZE	36
386c92544dSBjoern A. Zeeb #define FW_V3_REGION_TAILER_SIZE	40
396c92544dSBjoern A. Zeeb #define FW_START_OVERRIDE		BIT(0)
406c92544dSBjoern A. Zeeb #define FW_START_DLYCAL                 BIT(1)
416c92544dSBjoern A. Zeeb #define FW_START_WORKING_PDA_CR4	BIT(2)
426c92544dSBjoern A. Zeeb 
436c92544dSBjoern A. Zeeb struct mt7663_fw_buf {
446c92544dSBjoern A. Zeeb 	__le32 crc;
456c92544dSBjoern A. Zeeb 	__le32 d_img_size;
466c92544dSBjoern A. Zeeb 	__le32 block_size;
476c92544dSBjoern A. Zeeb 	u8 rsv[4];
486c92544dSBjoern A. Zeeb 	__le32 img_dest_addr;
496c92544dSBjoern A. Zeeb 	__le32 img_size;
506c92544dSBjoern A. Zeeb 	u8 feature_set;
516c92544dSBjoern A. Zeeb };
526c92544dSBjoern A. Zeeb 
536c92544dSBjoern A. Zeeb #define MT7615_PATCH_ADDRESS		0x80000
546c92544dSBjoern A. Zeeb #define MT7622_PATCH_ADDRESS		0x9c000
556c92544dSBjoern A. Zeeb #define MT7663_PATCH_ADDRESS		0xdc000
566c92544dSBjoern A. Zeeb 
576c92544dSBjoern A. Zeeb #define N9_REGION_NUM			2
586c92544dSBjoern A. Zeeb #define CR4_REGION_NUM			1
596c92544dSBjoern A. Zeeb 
606c92544dSBjoern A. Zeeb #define IMG_CRC_LEN			4
616c92544dSBjoern A. Zeeb 
626c92544dSBjoern A. Zeeb void mt7615_mcu_fill_msg(struct mt7615_dev *dev, struct sk_buff *skb,
636c92544dSBjoern A. Zeeb 			 int cmd, int *wait_seq)
646c92544dSBjoern A. Zeeb {
656c92544dSBjoern A. Zeeb 	int txd_len, mcu_cmd = FIELD_GET(__MCU_CMD_FIELD_ID, cmd);
666c92544dSBjoern A. Zeeb 	struct mt7615_uni_txd *uni_txd;
676c92544dSBjoern A. Zeeb 	struct mt7615_mcu_txd *mcu_txd;
686c92544dSBjoern A. Zeeb 	u8 seq, q_idx, pkt_fmt;
696c92544dSBjoern A. Zeeb 	__le32 *txd;
706c92544dSBjoern A. Zeeb 	u32 val;
716c92544dSBjoern A. Zeeb 
726c92544dSBjoern A. Zeeb 	/* TODO: make dynamic based on msg type */
736c92544dSBjoern A. Zeeb 	dev->mt76.mcu.timeout = 20 * HZ;
746c92544dSBjoern A. Zeeb 
756c92544dSBjoern A. Zeeb 	seq = ++dev->mt76.mcu.msg_seq & 0xf;
766c92544dSBjoern A. Zeeb 	if (!seq)
776c92544dSBjoern A. Zeeb 		seq = ++dev->mt76.mcu.msg_seq & 0xf;
786c92544dSBjoern A. Zeeb 	if (wait_seq)
796c92544dSBjoern A. Zeeb 		*wait_seq = seq;
806c92544dSBjoern A. Zeeb 
816c92544dSBjoern A. Zeeb 	txd_len = cmd & __MCU_CMD_FIELD_UNI ? sizeof(*uni_txd) : sizeof(*mcu_txd);
826c92544dSBjoern A. Zeeb 	txd = (__le32 *)skb_push(skb, txd_len);
836c92544dSBjoern A. Zeeb 
846c92544dSBjoern A. Zeeb 	if (cmd != MCU_CMD(FW_SCATTER)) {
856c92544dSBjoern A. Zeeb 		q_idx = MT_TX_MCU_PORT_RX_Q0;
866c92544dSBjoern A. Zeeb 		pkt_fmt = MT_TX_TYPE_CMD;
876c92544dSBjoern A. Zeeb 	} else {
886c92544dSBjoern A. Zeeb 		q_idx = MT_TX_MCU_PORT_RX_FWDL;
896c92544dSBjoern A. Zeeb 		pkt_fmt = MT_TX_TYPE_FW;
906c92544dSBjoern A. Zeeb 	}
916c92544dSBjoern A. Zeeb 
926c92544dSBjoern A. Zeeb 	val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len) |
936c92544dSBjoern A. Zeeb 	      FIELD_PREP(MT_TXD0_P_IDX, MT_TX_PORT_IDX_MCU) |
946c92544dSBjoern A. Zeeb 	      FIELD_PREP(MT_TXD0_Q_IDX, q_idx);
956c92544dSBjoern A. Zeeb 	txd[0] = cpu_to_le32(val);
966c92544dSBjoern A. Zeeb 
976c92544dSBjoern A. Zeeb 	val = MT_TXD1_LONG_FORMAT |
986c92544dSBjoern A. Zeeb 	      FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_CMD) |
996c92544dSBjoern A. Zeeb 	      FIELD_PREP(MT_TXD1_PKT_FMT, pkt_fmt);
1006c92544dSBjoern A. Zeeb 	txd[1] = cpu_to_le32(val);
1016c92544dSBjoern A. Zeeb 
1026c92544dSBjoern A. Zeeb 	if (cmd & __MCU_CMD_FIELD_UNI) {
1036c92544dSBjoern A. Zeeb 		uni_txd = (struct mt7615_uni_txd *)txd;
1046c92544dSBjoern A. Zeeb 		uni_txd->len = cpu_to_le16(skb->len - sizeof(uni_txd->txd));
1056c92544dSBjoern A. Zeeb 		uni_txd->option = MCU_CMD_UNI_EXT_ACK;
1066c92544dSBjoern A. Zeeb 		uni_txd->cid = cpu_to_le16(mcu_cmd);
1076c92544dSBjoern A. Zeeb 		uni_txd->s2d_index = MCU_S2D_H2N;
1086c92544dSBjoern A. Zeeb 		uni_txd->pkt_type = MCU_PKT_ID;
1096c92544dSBjoern A. Zeeb 		uni_txd->seq = seq;
1106c92544dSBjoern A. Zeeb 
1116c92544dSBjoern A. Zeeb 		return;
1126c92544dSBjoern A. Zeeb 	}
1136c92544dSBjoern A. Zeeb 
1146c92544dSBjoern A. Zeeb 	mcu_txd = (struct mt7615_mcu_txd *)txd;
1156c92544dSBjoern A. Zeeb 	mcu_txd->len = cpu_to_le16(skb->len - sizeof(mcu_txd->txd));
1166c92544dSBjoern A. Zeeb 	mcu_txd->pq_id = cpu_to_le16(MCU_PQ_ID(MT_TX_PORT_IDX_MCU, q_idx));
1176c92544dSBjoern A. Zeeb 	mcu_txd->s2d_index = MCU_S2D_H2N;
1186c92544dSBjoern A. Zeeb 	mcu_txd->pkt_type = MCU_PKT_ID;
1196c92544dSBjoern A. Zeeb 	mcu_txd->seq = seq;
1206c92544dSBjoern A. Zeeb 	mcu_txd->cid = mcu_cmd;
1216c92544dSBjoern A. Zeeb 	mcu_txd->ext_cid = FIELD_GET(__MCU_CMD_FIELD_EXT_ID, cmd);
1226c92544dSBjoern A. Zeeb 
1236c92544dSBjoern A. Zeeb 	if (mcu_txd->ext_cid || (cmd & __MCU_CMD_FIELD_CE)) {
1246c92544dSBjoern A. Zeeb 		if (cmd & __MCU_CMD_FIELD_QUERY)
1256c92544dSBjoern A. Zeeb 			mcu_txd->set_query = MCU_Q_QUERY;
1266c92544dSBjoern A. Zeeb 		else
1276c92544dSBjoern A. Zeeb 			mcu_txd->set_query = MCU_Q_SET;
1286c92544dSBjoern A. Zeeb 		mcu_txd->ext_cid_ack = !!mcu_txd->ext_cid;
1296c92544dSBjoern A. Zeeb 	} else {
1306c92544dSBjoern A. Zeeb 		mcu_txd->set_query = MCU_Q_NA;
1316c92544dSBjoern A. Zeeb 	}
1326c92544dSBjoern A. Zeeb }
1336c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt7615_mcu_fill_msg);
1346c92544dSBjoern A. Zeeb 
1356c92544dSBjoern A. Zeeb int mt7615_mcu_parse_response(struct mt76_dev *mdev, int cmd,
1366c92544dSBjoern A. Zeeb 			      struct sk_buff *skb, int seq)
1376c92544dSBjoern A. Zeeb {
1386c92544dSBjoern A. Zeeb 	struct mt7615_mcu_rxd *rxd;
1396c92544dSBjoern A. Zeeb 	int ret = 0;
1406c92544dSBjoern A. Zeeb 
1416c92544dSBjoern A. Zeeb 	if (!skb) {
1426c92544dSBjoern A. Zeeb 		dev_err(mdev->dev, "Message %08x (seq %d) timeout\n",
1436c92544dSBjoern A. Zeeb 			cmd, seq);
1446c92544dSBjoern A. Zeeb 		return -ETIMEDOUT;
1456c92544dSBjoern A. Zeeb 	}
1466c92544dSBjoern A. Zeeb 
1476c92544dSBjoern A. Zeeb 	rxd = (struct mt7615_mcu_rxd *)skb->data;
1486c92544dSBjoern A. Zeeb 	if (seq != rxd->seq)
1496c92544dSBjoern A. Zeeb 		return -EAGAIN;
1506c92544dSBjoern A. Zeeb 
1516c92544dSBjoern A. Zeeb 	if (cmd == MCU_CMD(PATCH_SEM_CONTROL)) {
1526c92544dSBjoern A. Zeeb 		skb_pull(skb, sizeof(*rxd) - 4);
1536c92544dSBjoern A. Zeeb 		ret = *skb->data;
1546c92544dSBjoern A. Zeeb 	} else if (cmd == MCU_EXT_CMD(THERMAL_CTRL)) {
1556c92544dSBjoern A. Zeeb 		skb_pull(skb, sizeof(*rxd));
1566c92544dSBjoern A. Zeeb 		ret = le32_to_cpu(*(__le32 *)skb->data);
1576c92544dSBjoern A. Zeeb 	} else if (cmd == MCU_EXT_QUERY(RF_REG_ACCESS)) {
1586c92544dSBjoern A. Zeeb 		skb_pull(skb, sizeof(*rxd));
1596c92544dSBjoern A. Zeeb 		ret = le32_to_cpu(*(__le32 *)&skb->data[8]);
1606c92544dSBjoern A. Zeeb 	} else if (cmd == MCU_UNI_CMD(DEV_INFO_UPDATE) ||
1616c92544dSBjoern A. Zeeb 		   cmd == MCU_UNI_CMD(BSS_INFO_UPDATE) ||
1626c92544dSBjoern A. Zeeb 		   cmd == MCU_UNI_CMD(STA_REC_UPDATE) ||
1636c92544dSBjoern A. Zeeb 		   cmd == MCU_UNI_CMD(HIF_CTRL) ||
1646c92544dSBjoern A. Zeeb 		   cmd == MCU_UNI_CMD(OFFLOAD) ||
1656c92544dSBjoern A. Zeeb 		   cmd == MCU_UNI_CMD(SUSPEND)) {
166*cbb3ec25SBjoern A. Zeeb 		struct mt76_connac_mcu_uni_event *event;
1676c92544dSBjoern A. Zeeb 
1686c92544dSBjoern A. Zeeb 		skb_pull(skb, sizeof(*rxd));
169*cbb3ec25SBjoern A. Zeeb 		event = (struct mt76_connac_mcu_uni_event *)skb->data;
1706c92544dSBjoern A. Zeeb 		ret = le32_to_cpu(event->status);
1716c92544dSBjoern A. Zeeb 	} else if (cmd == MCU_CE_QUERY(REG_READ)) {
172*cbb3ec25SBjoern A. Zeeb 		struct mt76_connac_mcu_reg_event *event;
1736c92544dSBjoern A. Zeeb 
1746c92544dSBjoern A. Zeeb 		skb_pull(skb, sizeof(*rxd));
175*cbb3ec25SBjoern A. Zeeb 		event = (struct mt76_connac_mcu_reg_event *)skb->data;
1766c92544dSBjoern A. Zeeb 		ret = (int)le32_to_cpu(event->val);
1776c92544dSBjoern A. Zeeb 	}
1786c92544dSBjoern A. Zeeb 
1796c92544dSBjoern A. Zeeb 	return ret;
1806c92544dSBjoern A. Zeeb }
1816c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt7615_mcu_parse_response);
1826c92544dSBjoern A. Zeeb 
1836c92544dSBjoern A. Zeeb static int
1846c92544dSBjoern A. Zeeb mt7615_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
1856c92544dSBjoern A. Zeeb 			int cmd, int *seq)
1866c92544dSBjoern A. Zeeb {
1876c92544dSBjoern A. Zeeb 	struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);
1886c92544dSBjoern A. Zeeb 	enum mt76_mcuq_id qid;
1896c92544dSBjoern A. Zeeb 
1906c92544dSBjoern A. Zeeb 	mt7615_mcu_fill_msg(dev, skb, cmd, seq);
1916c92544dSBjoern A. Zeeb 	if (test_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state))
1926c92544dSBjoern A. Zeeb 		qid = MT_MCUQ_WM;
1936c92544dSBjoern A. Zeeb 	else
1946c92544dSBjoern A. Zeeb 		qid = MT_MCUQ_FWDL;
1956c92544dSBjoern A. Zeeb 
1966c92544dSBjoern A. Zeeb 	return mt76_tx_queue_skb_raw(dev, dev->mt76.q_mcu[qid], skb, 0);
1976c92544dSBjoern A. Zeeb }
1986c92544dSBjoern A. Zeeb 
1996c92544dSBjoern A. Zeeb u32 mt7615_rf_rr(struct mt7615_dev *dev, u32 wf, u32 reg)
2006c92544dSBjoern A. Zeeb {
2016c92544dSBjoern A. Zeeb 	struct {
2026c92544dSBjoern A. Zeeb 		__le32 wifi_stream;
2036c92544dSBjoern A. Zeeb 		__le32 address;
2046c92544dSBjoern A. Zeeb 		__le32 data;
2056c92544dSBjoern A. Zeeb 	} req = {
2066c92544dSBjoern A. Zeeb 		.wifi_stream = cpu_to_le32(wf),
2076c92544dSBjoern A. Zeeb 		.address = cpu_to_le32(reg),
2086c92544dSBjoern A. Zeeb 	};
2096c92544dSBjoern A. Zeeb 
2106c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_QUERY(RF_REG_ACCESS),
2116c92544dSBjoern A. Zeeb 				 &req, sizeof(req), true);
2126c92544dSBjoern A. Zeeb }
2136c92544dSBjoern A. Zeeb 
2146c92544dSBjoern A. Zeeb int mt7615_rf_wr(struct mt7615_dev *dev, u32 wf, u32 reg, u32 val)
2156c92544dSBjoern A. Zeeb {
2166c92544dSBjoern A. Zeeb 	struct {
2176c92544dSBjoern A. Zeeb 		__le32 wifi_stream;
2186c92544dSBjoern A. Zeeb 		__le32 address;
2196c92544dSBjoern A. Zeeb 		__le32 data;
2206c92544dSBjoern A. Zeeb 	} req = {
2216c92544dSBjoern A. Zeeb 		.wifi_stream = cpu_to_le32(wf),
2226c92544dSBjoern A. Zeeb 		.address = cpu_to_le32(reg),
2236c92544dSBjoern A. Zeeb 		.data = cpu_to_le32(val),
2246c92544dSBjoern A. Zeeb 	};
2256c92544dSBjoern A. Zeeb 
2266c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RF_REG_ACCESS),
2276c92544dSBjoern A. Zeeb 				 &req, sizeof(req), false);
2286c92544dSBjoern A. Zeeb }
2296c92544dSBjoern A. Zeeb 
2306c92544dSBjoern A. Zeeb void mt7622_trigger_hif_int(struct mt7615_dev *dev, bool en)
2316c92544dSBjoern A. Zeeb {
2326c92544dSBjoern A. Zeeb 	if (!is_mt7622(&dev->mt76))
2336c92544dSBjoern A. Zeeb 		return;
2346c92544dSBjoern A. Zeeb 
2356c92544dSBjoern A. Zeeb 	regmap_update_bits(dev->infracfg, MT_INFRACFG_MISC,
2366c92544dSBjoern A. Zeeb 			   MT_INFRACFG_MISC_AP2CONN_WAKE,
2376c92544dSBjoern A. Zeeb 			   !en * MT_INFRACFG_MISC_AP2CONN_WAKE);
2386c92544dSBjoern A. Zeeb }
2396c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt7622_trigger_hif_int);
2406c92544dSBjoern A. Zeeb 
2416c92544dSBjoern A. Zeeb static int mt7615_mcu_drv_pmctrl(struct mt7615_dev *dev)
2426c92544dSBjoern A. Zeeb {
2436c92544dSBjoern A. Zeeb 	struct mt76_phy *mphy = &dev->mt76.phy;
2446c92544dSBjoern A. Zeeb 	struct mt76_connac_pm *pm = &dev->pm;
2456c92544dSBjoern A. Zeeb 	struct mt76_dev *mdev = &dev->mt76;
2466c92544dSBjoern A. Zeeb 	u32 addr;
2476c92544dSBjoern A. Zeeb 	int err;
2486c92544dSBjoern A. Zeeb 
2496c92544dSBjoern A. Zeeb 	if (is_mt7663(mdev)) {
2506c92544dSBjoern A. Zeeb 		/* Clear firmware own via N9 eint */
2516c92544dSBjoern A. Zeeb 		mt76_wr(dev, MT_PCIE_DOORBELL_PUSH, MT_CFG_LPCR_HOST_DRV_OWN);
2526c92544dSBjoern A. Zeeb 		mt76_poll(dev, MT_CONN_ON_MISC, MT_CFG_LPCR_HOST_FW_OWN, 0, 3000);
2536c92544dSBjoern A. Zeeb 
2546c92544dSBjoern A. Zeeb 		addr = MT_CONN_HIF_ON_LPCTL;
2556c92544dSBjoern A. Zeeb 	} else {
2566c92544dSBjoern A. Zeeb 		addr = MT_CFG_LPCR_HOST;
2576c92544dSBjoern A. Zeeb 	}
2586c92544dSBjoern A. Zeeb 
2596c92544dSBjoern A. Zeeb 	mt76_wr(dev, addr, MT_CFG_LPCR_HOST_DRV_OWN);
2606c92544dSBjoern A. Zeeb 
2616c92544dSBjoern A. Zeeb 	mt7622_trigger_hif_int(dev, true);
2626c92544dSBjoern A. Zeeb 
2636c92544dSBjoern A. Zeeb 	err = !mt76_poll_msec(dev, addr, MT_CFG_LPCR_HOST_FW_OWN, 0, 3000);
2646c92544dSBjoern A. Zeeb 
2656c92544dSBjoern A. Zeeb 	mt7622_trigger_hif_int(dev, false);
2666c92544dSBjoern A. Zeeb 
2676c92544dSBjoern A. Zeeb 	if (err) {
2686c92544dSBjoern A. Zeeb 		dev_err(mdev->dev, "driver own failed\n");
2696c92544dSBjoern A. Zeeb 		return -ETIMEDOUT;
2706c92544dSBjoern A. Zeeb 	}
2716c92544dSBjoern A. Zeeb 
2726c92544dSBjoern A. Zeeb 	clear_bit(MT76_STATE_PM, &mphy->state);
2736c92544dSBjoern A. Zeeb 
2746c92544dSBjoern A. Zeeb 	pm->stats.last_wake_event = jiffies;
2756c92544dSBjoern A. Zeeb 	pm->stats.doze_time += pm->stats.last_wake_event -
2766c92544dSBjoern A. Zeeb 			       pm->stats.last_doze_event;
2776c92544dSBjoern A. Zeeb 
2786c92544dSBjoern A. Zeeb 	return 0;
2796c92544dSBjoern A. Zeeb }
2806c92544dSBjoern A. Zeeb 
2816c92544dSBjoern A. Zeeb static int mt7615_mcu_lp_drv_pmctrl(struct mt7615_dev *dev)
2826c92544dSBjoern A. Zeeb {
2836c92544dSBjoern A. Zeeb 	struct mt76_phy *mphy = &dev->mt76.phy;
2846c92544dSBjoern A. Zeeb 	struct mt76_connac_pm *pm = &dev->pm;
2856c92544dSBjoern A. Zeeb 	int i, err = 0;
2866c92544dSBjoern A. Zeeb 
2876c92544dSBjoern A. Zeeb 	mutex_lock(&pm->mutex);
2886c92544dSBjoern A. Zeeb 
2896c92544dSBjoern A. Zeeb 	if (!test_bit(MT76_STATE_PM, &mphy->state))
2906c92544dSBjoern A. Zeeb 		goto out;
2916c92544dSBjoern A. Zeeb 
2926c92544dSBjoern A. Zeeb 	for (i = 0; i < MT7615_DRV_OWN_RETRY_COUNT; i++) {
2936c92544dSBjoern A. Zeeb 		mt76_wr(dev, MT_PCIE_DOORBELL_PUSH, MT_CFG_LPCR_HOST_DRV_OWN);
2946c92544dSBjoern A. Zeeb 		if (mt76_poll_msec(dev, MT_CONN_HIF_ON_LPCTL,
2956c92544dSBjoern A. Zeeb 				   MT_CFG_LPCR_HOST_FW_OWN, 0, 50))
2966c92544dSBjoern A. Zeeb 			break;
2976c92544dSBjoern A. Zeeb 	}
2986c92544dSBjoern A. Zeeb 
2996c92544dSBjoern A. Zeeb 	if (i == MT7615_DRV_OWN_RETRY_COUNT) {
3006c92544dSBjoern A. Zeeb 		dev_err(dev->mt76.dev, "driver own failed\n");
3016c92544dSBjoern A. Zeeb 		err = -EIO;
3026c92544dSBjoern A. Zeeb 		goto out;
3036c92544dSBjoern A. Zeeb 	}
3046c92544dSBjoern A. Zeeb 	clear_bit(MT76_STATE_PM, &mphy->state);
3056c92544dSBjoern A. Zeeb 
3066c92544dSBjoern A. Zeeb 	pm->stats.last_wake_event = jiffies;
3076c92544dSBjoern A. Zeeb 	pm->stats.doze_time += pm->stats.last_wake_event -
3086c92544dSBjoern A. Zeeb 			       pm->stats.last_doze_event;
3096c92544dSBjoern A. Zeeb out:
3106c92544dSBjoern A. Zeeb 	mutex_unlock(&pm->mutex);
3116c92544dSBjoern A. Zeeb 
3126c92544dSBjoern A. Zeeb 	return err;
3136c92544dSBjoern A. Zeeb }
3146c92544dSBjoern A. Zeeb 
3156c92544dSBjoern A. Zeeb static int mt7615_mcu_fw_pmctrl(struct mt7615_dev *dev)
3166c92544dSBjoern A. Zeeb {
3176c92544dSBjoern A. Zeeb 	struct mt76_phy *mphy = &dev->mt76.phy;
3186c92544dSBjoern A. Zeeb 	struct mt76_connac_pm *pm = &dev->pm;
3196c92544dSBjoern A. Zeeb 	int err = 0;
3206c92544dSBjoern A. Zeeb 	u32 addr;
3216c92544dSBjoern A. Zeeb 
3226c92544dSBjoern A. Zeeb 	mutex_lock(&pm->mutex);
3236c92544dSBjoern A. Zeeb 
3246c92544dSBjoern A. Zeeb 	if (mt76_connac_skip_fw_pmctrl(mphy, pm))
3256c92544dSBjoern A. Zeeb 		goto out;
3266c92544dSBjoern A. Zeeb 
3276c92544dSBjoern A. Zeeb 	mt7622_trigger_hif_int(dev, true);
3286c92544dSBjoern A. Zeeb 
3296c92544dSBjoern A. Zeeb 	addr = is_mt7663(&dev->mt76) ? MT_CONN_HIF_ON_LPCTL : MT_CFG_LPCR_HOST;
3306c92544dSBjoern A. Zeeb 	mt76_wr(dev, addr, MT_CFG_LPCR_HOST_FW_OWN);
3316c92544dSBjoern A. Zeeb 
3326c92544dSBjoern A. Zeeb 	if (is_mt7622(&dev->mt76) &&
3336c92544dSBjoern A. Zeeb 	    !mt76_poll_msec(dev, addr, MT_CFG_LPCR_HOST_FW_OWN,
3346c92544dSBjoern A. Zeeb 			    MT_CFG_LPCR_HOST_FW_OWN, 3000)) {
3356c92544dSBjoern A. Zeeb 		dev_err(dev->mt76.dev, "Timeout for firmware own\n");
3366c92544dSBjoern A. Zeeb 		clear_bit(MT76_STATE_PM, &mphy->state);
3376c92544dSBjoern A. Zeeb 		err = -EIO;
3386c92544dSBjoern A. Zeeb 	}
3396c92544dSBjoern A. Zeeb 
3406c92544dSBjoern A. Zeeb 	mt7622_trigger_hif_int(dev, false);
3416c92544dSBjoern A. Zeeb 	if (!err) {
3426c92544dSBjoern A. Zeeb 		pm->stats.last_doze_event = jiffies;
3436c92544dSBjoern A. Zeeb 		pm->stats.awake_time += pm->stats.last_doze_event -
3446c92544dSBjoern A. Zeeb 					pm->stats.last_wake_event;
3456c92544dSBjoern A. Zeeb 	}
3466c92544dSBjoern A. Zeeb out:
3476c92544dSBjoern A. Zeeb 	mutex_unlock(&pm->mutex);
3486c92544dSBjoern A. Zeeb 
3496c92544dSBjoern A. Zeeb 	return err;
3506c92544dSBjoern A. Zeeb }
3516c92544dSBjoern A. Zeeb 
3526c92544dSBjoern A. Zeeb static void
3536c92544dSBjoern A. Zeeb mt7615_mcu_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
3546c92544dSBjoern A. Zeeb {
3556c92544dSBjoern A. Zeeb 	if (vif->bss_conf.csa_active)
3566c92544dSBjoern A. Zeeb 		ieee80211_csa_finish(vif);
3576c92544dSBjoern A. Zeeb }
3586c92544dSBjoern A. Zeeb 
3596c92544dSBjoern A. Zeeb static void
3606c92544dSBjoern A. Zeeb mt7615_mcu_rx_csa_notify(struct mt7615_dev *dev, struct sk_buff *skb)
3616c92544dSBjoern A. Zeeb {
3626c92544dSBjoern A. Zeeb 	struct mt7615_phy *ext_phy = mt7615_ext_phy(dev);
3636c92544dSBjoern A. Zeeb 	struct mt76_phy *mphy = &dev->mt76.phy;
3646c92544dSBjoern A. Zeeb 	struct mt7615_mcu_csa_notify *c;
3656c92544dSBjoern A. Zeeb 
3666c92544dSBjoern A. Zeeb 	c = (struct mt7615_mcu_csa_notify *)skb->data;
3676c92544dSBjoern A. Zeeb 
3686c92544dSBjoern A. Zeeb 	if (c->omac_idx > EXT_BSSID_MAX)
3696c92544dSBjoern A. Zeeb 		return;
3706c92544dSBjoern A. Zeeb 
3716c92544dSBjoern A. Zeeb 	if (ext_phy && ext_phy->omac_mask & BIT_ULL(c->omac_idx))
3726c92544dSBjoern A. Zeeb 		mphy = dev->mt76.phys[MT_BAND1];
3736c92544dSBjoern A. Zeeb 
3746c92544dSBjoern A. Zeeb 	ieee80211_iterate_active_interfaces_atomic(mphy->hw,
3756c92544dSBjoern A. Zeeb 			IEEE80211_IFACE_ITER_RESUME_ALL,
3766c92544dSBjoern A. Zeeb 			mt7615_mcu_csa_finish, mphy->hw);
3776c92544dSBjoern A. Zeeb }
3786c92544dSBjoern A. Zeeb 
3796c92544dSBjoern A. Zeeb static void
3806c92544dSBjoern A. Zeeb mt7615_mcu_rx_radar_detected(struct mt7615_dev *dev, struct sk_buff *skb)
3816c92544dSBjoern A. Zeeb {
3826c92544dSBjoern A. Zeeb 	struct mt76_phy *mphy = &dev->mt76.phy;
3836c92544dSBjoern A. Zeeb 	struct mt7615_mcu_rdd_report *r;
3846c92544dSBjoern A. Zeeb 
3856c92544dSBjoern A. Zeeb 	r = (struct mt7615_mcu_rdd_report *)skb->data;
3866c92544dSBjoern A. Zeeb 
3876c92544dSBjoern A. Zeeb 	if (!dev->radar_pattern.n_pulses && !r->long_detected &&
3886c92544dSBjoern A. Zeeb 	    !r->constant_prf_detected && !r->staggered_prf_detected)
3896c92544dSBjoern A. Zeeb 		return;
3906c92544dSBjoern A. Zeeb 
3916c92544dSBjoern A. Zeeb 	if (r->band_idx && dev->mt76.phys[MT_BAND1])
3926c92544dSBjoern A. Zeeb 		mphy = dev->mt76.phys[MT_BAND1];
3936c92544dSBjoern A. Zeeb 
3946c92544dSBjoern A. Zeeb 	if (mt76_phy_dfs_state(mphy) < MT_DFS_STATE_CAC)
3956c92544dSBjoern A. Zeeb 		return;
3966c92544dSBjoern A. Zeeb 
3976c92544dSBjoern A. Zeeb 	ieee80211_radar_detected(mphy->hw);
3986c92544dSBjoern A. Zeeb 	dev->hw_pattern++;
3996c92544dSBjoern A. Zeeb }
4006c92544dSBjoern A. Zeeb 
4016c92544dSBjoern A. Zeeb static void
4026c92544dSBjoern A. Zeeb mt7615_mcu_rx_log_message(struct mt7615_dev *dev, struct sk_buff *skb)
4036c92544dSBjoern A. Zeeb {
4046c92544dSBjoern A. Zeeb 	struct mt7615_mcu_rxd *rxd = (struct mt7615_mcu_rxd *)skb->data;
4056c92544dSBjoern A. Zeeb 	const char *data = (char *)&rxd[1];
4066c92544dSBjoern A. Zeeb 	const char *type;
4076c92544dSBjoern A. Zeeb 
4086c92544dSBjoern A. Zeeb 	switch (rxd->s2d_index) {
4096c92544dSBjoern A. Zeeb 	case 0:
4106c92544dSBjoern A. Zeeb 		type = "N9";
4116c92544dSBjoern A. Zeeb 		break;
4126c92544dSBjoern A. Zeeb 	case 2:
4136c92544dSBjoern A. Zeeb 		type = "CR4";
4146c92544dSBjoern A. Zeeb 		break;
4156c92544dSBjoern A. Zeeb 	default:
4166c92544dSBjoern A. Zeeb 		type = "unknown";
4176c92544dSBjoern A. Zeeb 		break;
4186c92544dSBjoern A. Zeeb 	}
4196c92544dSBjoern A. Zeeb 
4206c92544dSBjoern A. Zeeb 	wiphy_info(mt76_hw(dev)->wiphy, "%s: %.*s", type,
4216c92544dSBjoern A. Zeeb 		   (int)(skb->len - sizeof(*rxd)), data);
4226c92544dSBjoern A. Zeeb }
4236c92544dSBjoern A. Zeeb 
4246c92544dSBjoern A. Zeeb static void
4256c92544dSBjoern A. Zeeb mt7615_mcu_rx_ext_event(struct mt7615_dev *dev, struct sk_buff *skb)
4266c92544dSBjoern A. Zeeb {
4276c92544dSBjoern A. Zeeb 	struct mt7615_mcu_rxd *rxd = (struct mt7615_mcu_rxd *)skb->data;
4286c92544dSBjoern A. Zeeb 
4296c92544dSBjoern A. Zeeb 	switch (rxd->ext_eid) {
4306c92544dSBjoern A. Zeeb 	case MCU_EXT_EVENT_RDD_REPORT:
4316c92544dSBjoern A. Zeeb 		mt7615_mcu_rx_radar_detected(dev, skb);
4326c92544dSBjoern A. Zeeb 		break;
4336c92544dSBjoern A. Zeeb 	case MCU_EXT_EVENT_CSA_NOTIFY:
4346c92544dSBjoern A. Zeeb 		mt7615_mcu_rx_csa_notify(dev, skb);
4356c92544dSBjoern A. Zeeb 		break;
4366c92544dSBjoern A. Zeeb 	case MCU_EXT_EVENT_FW_LOG_2_HOST:
4376c92544dSBjoern A. Zeeb 		mt7615_mcu_rx_log_message(dev, skb);
4386c92544dSBjoern A. Zeeb 		break;
4396c92544dSBjoern A. Zeeb 	default:
4406c92544dSBjoern A. Zeeb 		break;
4416c92544dSBjoern A. Zeeb 	}
4426c92544dSBjoern A. Zeeb }
4436c92544dSBjoern A. Zeeb 
4446c92544dSBjoern A. Zeeb static void
4456c92544dSBjoern A. Zeeb mt7615_mcu_scan_event(struct mt7615_dev *dev, struct sk_buff *skb)
4466c92544dSBjoern A. Zeeb {
4476c92544dSBjoern A. Zeeb 	u8 *seq_num = skb->data + sizeof(struct mt7615_mcu_rxd);
4486c92544dSBjoern A. Zeeb 	struct mt7615_phy *phy;
4496c92544dSBjoern A. Zeeb 	struct mt76_phy *mphy;
4506c92544dSBjoern A. Zeeb 
4516c92544dSBjoern A. Zeeb 	if (*seq_num & BIT(7) && dev->mt76.phys[MT_BAND1])
4526c92544dSBjoern A. Zeeb 		mphy = dev->mt76.phys[MT_BAND1];
4536c92544dSBjoern A. Zeeb 	else
4546c92544dSBjoern A. Zeeb 		mphy = &dev->mt76.phy;
4556c92544dSBjoern A. Zeeb 
4566c92544dSBjoern A. Zeeb 	phy = (struct mt7615_phy *)mphy->priv;
4576c92544dSBjoern A. Zeeb 
4586c92544dSBjoern A. Zeeb 	spin_lock_bh(&dev->mt76.lock);
4596c92544dSBjoern A. Zeeb 	__skb_queue_tail(&phy->scan_event_list, skb);
4606c92544dSBjoern A. Zeeb 	spin_unlock_bh(&dev->mt76.lock);
4616c92544dSBjoern A. Zeeb 
4626c92544dSBjoern A. Zeeb 	ieee80211_queue_delayed_work(mphy->hw, &phy->scan_work,
4636c92544dSBjoern A. Zeeb 				     MT7615_HW_SCAN_TIMEOUT);
4646c92544dSBjoern A. Zeeb }
4656c92544dSBjoern A. Zeeb 
4666c92544dSBjoern A. Zeeb static void
4676c92544dSBjoern A. Zeeb mt7615_mcu_roc_event(struct mt7615_dev *dev, struct sk_buff *skb)
4686c92544dSBjoern A. Zeeb {
4696c92544dSBjoern A. Zeeb 	struct mt7615_roc_tlv *event;
4706c92544dSBjoern A. Zeeb 	struct mt7615_phy *phy;
4716c92544dSBjoern A. Zeeb 	struct mt76_phy *mphy;
4726c92544dSBjoern A. Zeeb 	int duration;
4736c92544dSBjoern A. Zeeb 
4746c92544dSBjoern A. Zeeb 	skb_pull(skb, sizeof(struct mt7615_mcu_rxd));
4756c92544dSBjoern A. Zeeb 	event = (struct mt7615_roc_tlv *)skb->data;
4766c92544dSBjoern A. Zeeb 
4776c92544dSBjoern A. Zeeb 	if (event->dbdc_band && dev->mt76.phys[MT_BAND1])
4786c92544dSBjoern A. Zeeb 		mphy = dev->mt76.phys[MT_BAND1];
4796c92544dSBjoern A. Zeeb 	else
4806c92544dSBjoern A. Zeeb 		mphy = &dev->mt76.phy;
4816c92544dSBjoern A. Zeeb 
4826c92544dSBjoern A. Zeeb 	ieee80211_ready_on_channel(mphy->hw);
4836c92544dSBjoern A. Zeeb 
4846c92544dSBjoern A. Zeeb 	phy = (struct mt7615_phy *)mphy->priv;
4856c92544dSBjoern A. Zeeb 	phy->roc_grant = true;
4866c92544dSBjoern A. Zeeb 	wake_up(&phy->roc_wait);
4876c92544dSBjoern A. Zeeb 
4886c92544dSBjoern A. Zeeb 	duration = le32_to_cpu(event->max_interval);
4896c92544dSBjoern A. Zeeb 	mod_timer(&phy->roc_timer,
4906c92544dSBjoern A. Zeeb 		  round_jiffies_up(jiffies + msecs_to_jiffies(duration)));
4916c92544dSBjoern A. Zeeb }
4926c92544dSBjoern A. Zeeb 
4936c92544dSBjoern A. Zeeb static void
4946c92544dSBjoern A. Zeeb mt7615_mcu_beacon_loss_event(struct mt7615_dev *dev, struct sk_buff *skb)
4956c92544dSBjoern A. Zeeb {
4966c92544dSBjoern A. Zeeb 	struct mt76_connac_beacon_loss_event *event;
4976c92544dSBjoern A. Zeeb 	struct mt76_phy *mphy;
4986c92544dSBjoern A. Zeeb 	u8 band_idx = 0; /* DBDC support */
4996c92544dSBjoern A. Zeeb 
5006c92544dSBjoern A. Zeeb 	skb_pull(skb, sizeof(struct mt7615_mcu_rxd));
5016c92544dSBjoern A. Zeeb 	event = (struct mt76_connac_beacon_loss_event *)skb->data;
5026c92544dSBjoern A. Zeeb 	if (band_idx && dev->mt76.phys[MT_BAND1])
5036c92544dSBjoern A. Zeeb 		mphy = dev->mt76.phys[MT_BAND1];
5046c92544dSBjoern A. Zeeb 	else
5056c92544dSBjoern A. Zeeb 		mphy = &dev->mt76.phy;
5066c92544dSBjoern A. Zeeb 
5076c92544dSBjoern A. Zeeb 	ieee80211_iterate_active_interfaces_atomic(mphy->hw,
5086c92544dSBjoern A. Zeeb 					IEEE80211_IFACE_ITER_RESUME_ALL,
5096c92544dSBjoern A. Zeeb 					mt76_connac_mcu_beacon_loss_iter,
5106c92544dSBjoern A. Zeeb 					event);
5116c92544dSBjoern A. Zeeb }
5126c92544dSBjoern A. Zeeb 
5136c92544dSBjoern A. Zeeb static void
5146c92544dSBjoern A. Zeeb mt7615_mcu_bss_event(struct mt7615_dev *dev, struct sk_buff *skb)
5156c92544dSBjoern A. Zeeb {
5166c92544dSBjoern A. Zeeb 	struct mt76_connac_mcu_bss_event *event;
5176c92544dSBjoern A. Zeeb 	struct mt76_phy *mphy;
5186c92544dSBjoern A. Zeeb 	u8 band_idx = 0; /* DBDC support */
5196c92544dSBjoern A. Zeeb 
5206c92544dSBjoern A. Zeeb 	skb_pull(skb, sizeof(struct mt7615_mcu_rxd));
5216c92544dSBjoern A. Zeeb 	event = (struct mt76_connac_mcu_bss_event *)skb->data;
5226c92544dSBjoern A. Zeeb 
5236c92544dSBjoern A. Zeeb 	if (band_idx && dev->mt76.phys[MT_BAND1])
5246c92544dSBjoern A. Zeeb 		mphy = dev->mt76.phys[MT_BAND1];
5256c92544dSBjoern A. Zeeb 	else
5266c92544dSBjoern A. Zeeb 		mphy = &dev->mt76.phy;
5276c92544dSBjoern A. Zeeb 
5286c92544dSBjoern A. Zeeb 	if (event->is_absent)
5296c92544dSBjoern A. Zeeb 		ieee80211_stop_queues(mphy->hw);
5306c92544dSBjoern A. Zeeb 	else
5316c92544dSBjoern A. Zeeb 		ieee80211_wake_queues(mphy->hw);
5326c92544dSBjoern A. Zeeb }
5336c92544dSBjoern A. Zeeb 
5346c92544dSBjoern A. Zeeb static void
5356c92544dSBjoern A. Zeeb mt7615_mcu_rx_unsolicited_event(struct mt7615_dev *dev, struct sk_buff *skb)
5366c92544dSBjoern A. Zeeb {
5376c92544dSBjoern A. Zeeb 	struct mt7615_mcu_rxd *rxd = (struct mt7615_mcu_rxd *)skb->data;
5386c92544dSBjoern A. Zeeb 
5396c92544dSBjoern A. Zeeb 	switch (rxd->eid) {
5406c92544dSBjoern A. Zeeb 	case MCU_EVENT_EXT:
5416c92544dSBjoern A. Zeeb 		mt7615_mcu_rx_ext_event(dev, skb);
5426c92544dSBjoern A. Zeeb 		break;
5436c92544dSBjoern A. Zeeb 	case MCU_EVENT_BSS_BEACON_LOSS:
5446c92544dSBjoern A. Zeeb 		mt7615_mcu_beacon_loss_event(dev, skb);
5456c92544dSBjoern A. Zeeb 		break;
5466c92544dSBjoern A. Zeeb 	case MCU_EVENT_ROC:
5476c92544dSBjoern A. Zeeb 		mt7615_mcu_roc_event(dev, skb);
5486c92544dSBjoern A. Zeeb 		break;
5496c92544dSBjoern A. Zeeb 	case MCU_EVENT_SCHED_SCAN_DONE:
5506c92544dSBjoern A. Zeeb 	case MCU_EVENT_SCAN_DONE:
5516c92544dSBjoern A. Zeeb 		mt7615_mcu_scan_event(dev, skb);
5526c92544dSBjoern A. Zeeb 		return;
5536c92544dSBjoern A. Zeeb 	case MCU_EVENT_BSS_ABSENCE:
5546c92544dSBjoern A. Zeeb 		mt7615_mcu_bss_event(dev, skb);
5556c92544dSBjoern A. Zeeb 		break;
5566c92544dSBjoern A. Zeeb 	case MCU_EVENT_COREDUMP:
5576c92544dSBjoern A. Zeeb 		mt76_connac_mcu_coredump_event(&dev->mt76, skb,
5586c92544dSBjoern A. Zeeb 					       &dev->coredump);
5596c92544dSBjoern A. Zeeb 		return;
5606c92544dSBjoern A. Zeeb 	default:
5616c92544dSBjoern A. Zeeb 		break;
5626c92544dSBjoern A. Zeeb 	}
5636c92544dSBjoern A. Zeeb 	dev_kfree_skb(skb);
5646c92544dSBjoern A. Zeeb }
5656c92544dSBjoern A. Zeeb 
5666c92544dSBjoern A. Zeeb void mt7615_mcu_rx_event(struct mt7615_dev *dev, struct sk_buff *skb)
5676c92544dSBjoern A. Zeeb {
5686c92544dSBjoern A. Zeeb 	struct mt7615_mcu_rxd *rxd = (struct mt7615_mcu_rxd *)skb->data;
5696c92544dSBjoern A. Zeeb 
5706c92544dSBjoern A. Zeeb 	if (rxd->ext_eid == MCU_EXT_EVENT_THERMAL_PROTECT ||
5716c92544dSBjoern A. Zeeb 	    rxd->ext_eid == MCU_EXT_EVENT_FW_LOG_2_HOST ||
5726c92544dSBjoern A. Zeeb 	    rxd->ext_eid == MCU_EXT_EVENT_ASSERT_DUMP ||
5736c92544dSBjoern A. Zeeb 	    rxd->ext_eid == MCU_EXT_EVENT_PS_SYNC ||
5746c92544dSBjoern A. Zeeb 	    rxd->eid == MCU_EVENT_BSS_BEACON_LOSS ||
5756c92544dSBjoern A. Zeeb 	    rxd->eid == MCU_EVENT_SCHED_SCAN_DONE ||
5766c92544dSBjoern A. Zeeb 	    rxd->eid == MCU_EVENT_BSS_ABSENCE ||
5776c92544dSBjoern A. Zeeb 	    rxd->eid == MCU_EVENT_SCAN_DONE ||
5786c92544dSBjoern A. Zeeb 	    rxd->eid == MCU_EVENT_COREDUMP ||
5796c92544dSBjoern A. Zeeb 	    rxd->eid == MCU_EVENT_ROC ||
5806c92544dSBjoern A. Zeeb 	    !rxd->seq)
5816c92544dSBjoern A. Zeeb 		mt7615_mcu_rx_unsolicited_event(dev, skb);
5826c92544dSBjoern A. Zeeb 	else
5836c92544dSBjoern A. Zeeb 		mt76_mcu_rx_event(&dev->mt76, skb);
5846c92544dSBjoern A. Zeeb }
5856c92544dSBjoern A. Zeeb 
5866c92544dSBjoern A. Zeeb static int
5876c92544dSBjoern A. Zeeb mt7615_mcu_muar_config(struct mt7615_dev *dev, struct ieee80211_vif *vif,
5886c92544dSBjoern A. Zeeb 		       bool bssid, bool enable)
5896c92544dSBjoern A. Zeeb {
5906c92544dSBjoern A. Zeeb 	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
5916c92544dSBjoern A. Zeeb 	u32 idx = mvif->mt76.omac_idx - REPEATER_BSSID_START;
5926c92544dSBjoern A. Zeeb 	u32 mask = dev->omac_mask >> 32 & ~BIT(idx);
5936c92544dSBjoern A. Zeeb 	const u8 *addr = vif->addr;
5946c92544dSBjoern A. Zeeb 	struct {
5956c92544dSBjoern A. Zeeb 		u8 mode;
5966c92544dSBjoern A. Zeeb 		u8 force_clear;
5976c92544dSBjoern A. Zeeb 		u8 clear_bitmap[8];
5986c92544dSBjoern A. Zeeb 		u8 entry_count;
5996c92544dSBjoern A. Zeeb 		u8 write;
6006c92544dSBjoern A. Zeeb 
6016c92544dSBjoern A. Zeeb 		u8 index;
6026c92544dSBjoern A. Zeeb 		u8 bssid;
6036c92544dSBjoern A. Zeeb 		u8 addr[ETH_ALEN];
6046c92544dSBjoern A. Zeeb 	} __packed req = {
6056c92544dSBjoern A. Zeeb 		.mode = !!mask || enable,
6066c92544dSBjoern A. Zeeb 		.entry_count = 1,
6076c92544dSBjoern A. Zeeb 		.write = 1,
6086c92544dSBjoern A. Zeeb 
6096c92544dSBjoern A. Zeeb 		.index = idx * 2 + bssid,
6106c92544dSBjoern A. Zeeb 	};
6116c92544dSBjoern A. Zeeb 
6126c92544dSBjoern A. Zeeb 	if (bssid)
6136c92544dSBjoern A. Zeeb 		addr = vif->bss_conf.bssid;
6146c92544dSBjoern A. Zeeb 
6156c92544dSBjoern A. Zeeb 	if (enable)
6166c92544dSBjoern A. Zeeb 		ether_addr_copy(req.addr, addr);
6176c92544dSBjoern A. Zeeb 
6186c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(MUAR_UPDATE),
6196c92544dSBjoern A. Zeeb 				 &req, sizeof(req), true);
6206c92544dSBjoern A. Zeeb }
6216c92544dSBjoern A. Zeeb 
6226c92544dSBjoern A. Zeeb static int
6236c92544dSBjoern A. Zeeb mt7615_mcu_add_dev(struct mt7615_phy *phy, struct ieee80211_vif *vif,
6246c92544dSBjoern A. Zeeb 		   bool enable)
6256c92544dSBjoern A. Zeeb {
6266c92544dSBjoern A. Zeeb 	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
6276c92544dSBjoern A. Zeeb 	struct mt7615_dev *dev = phy->dev;
6286c92544dSBjoern A. Zeeb 	struct {
6296c92544dSBjoern A. Zeeb 		struct req_hdr {
6306c92544dSBjoern A. Zeeb 			u8 omac_idx;
6316c92544dSBjoern A. Zeeb 			u8 band_idx;
6326c92544dSBjoern A. Zeeb 			__le16 tlv_num;
6336c92544dSBjoern A. Zeeb 			u8 is_tlv_append;
6346c92544dSBjoern A. Zeeb 			u8 rsv[3];
6356c92544dSBjoern A. Zeeb 		} __packed hdr;
6366c92544dSBjoern A. Zeeb 		struct req_tlv {
6376c92544dSBjoern A. Zeeb 			__le16 tag;
6386c92544dSBjoern A. Zeeb 			__le16 len;
6396c92544dSBjoern A. Zeeb 			u8 active;
6406c92544dSBjoern A. Zeeb 			u8 band_idx;
6416c92544dSBjoern A. Zeeb 			u8 omac_addr[ETH_ALEN];
6426c92544dSBjoern A. Zeeb 		} __packed tlv;
6436c92544dSBjoern A. Zeeb 	} data = {
6446c92544dSBjoern A. Zeeb 		.hdr = {
6456c92544dSBjoern A. Zeeb 			.omac_idx = mvif->mt76.omac_idx,
6466c92544dSBjoern A. Zeeb 			.band_idx = mvif->mt76.band_idx,
6476c92544dSBjoern A. Zeeb 			.tlv_num = cpu_to_le16(1),
6486c92544dSBjoern A. Zeeb 			.is_tlv_append = 1,
6496c92544dSBjoern A. Zeeb 		},
6506c92544dSBjoern A. Zeeb 		.tlv = {
6516c92544dSBjoern A. Zeeb 			.tag = cpu_to_le16(DEV_INFO_ACTIVE),
6526c92544dSBjoern A. Zeeb 			.len = cpu_to_le16(sizeof(struct req_tlv)),
6536c92544dSBjoern A. Zeeb 			.active = enable,
6546c92544dSBjoern A. Zeeb 			.band_idx = mvif->mt76.band_idx,
6556c92544dSBjoern A. Zeeb 		},
6566c92544dSBjoern A. Zeeb 	};
6576c92544dSBjoern A. Zeeb 
6586c92544dSBjoern A. Zeeb 	if (mvif->mt76.omac_idx >= REPEATER_BSSID_START)
6596c92544dSBjoern A. Zeeb 		return mt7615_mcu_muar_config(dev, vif, false, enable);
6606c92544dSBjoern A. Zeeb 
6616c92544dSBjoern A. Zeeb 	memcpy(data.tlv.omac_addr, vif->addr, ETH_ALEN);
6626c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(DEV_INFO_UPDATE),
6636c92544dSBjoern A. Zeeb 				 &data, sizeof(data), true);
6646c92544dSBjoern A. Zeeb }
6656c92544dSBjoern A. Zeeb 
6666c92544dSBjoern A. Zeeb static int
6676c92544dSBjoern A. Zeeb mt7615_mcu_add_beacon_offload(struct mt7615_dev *dev,
6686c92544dSBjoern A. Zeeb 			      struct ieee80211_hw *hw,
6696c92544dSBjoern A. Zeeb 			      struct ieee80211_vif *vif, bool enable)
6706c92544dSBjoern A. Zeeb {
6716c92544dSBjoern A. Zeeb 	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
6726c92544dSBjoern A. Zeeb 	struct mt76_wcid *wcid = &dev->mt76.global_wcid;
6736c92544dSBjoern A. Zeeb 	struct ieee80211_mutable_offsets offs;
6746c92544dSBjoern A. Zeeb 	struct ieee80211_tx_info *info;
6756c92544dSBjoern A. Zeeb 	struct req {
6766c92544dSBjoern A. Zeeb 		u8 omac_idx;
6776c92544dSBjoern A. Zeeb 		u8 enable;
6786c92544dSBjoern A. Zeeb 		u8 wlan_idx;
6796c92544dSBjoern A. Zeeb 		u8 band_idx;
6806c92544dSBjoern A. Zeeb 		u8 pkt_type;
6816c92544dSBjoern A. Zeeb 		u8 need_pre_tbtt_int;
6826c92544dSBjoern A. Zeeb 		__le16 csa_ie_pos;
6836c92544dSBjoern A. Zeeb 		__le16 pkt_len;
6846c92544dSBjoern A. Zeeb 		__le16 tim_ie_pos;
6856c92544dSBjoern A. Zeeb 		u8 pkt[512];
6866c92544dSBjoern A. Zeeb 		u8 csa_cnt;
6876c92544dSBjoern A. Zeeb 		/* bss color change */
6886c92544dSBjoern A. Zeeb 		u8 bcc_cnt;
6896c92544dSBjoern A. Zeeb 		__le16 bcc_ie_pos;
6906c92544dSBjoern A. Zeeb 	} __packed req = {
6916c92544dSBjoern A. Zeeb 		.omac_idx = mvif->mt76.omac_idx,
6926c92544dSBjoern A. Zeeb 		.enable = enable,
6936c92544dSBjoern A. Zeeb 		.wlan_idx = wcid->idx,
6946c92544dSBjoern A. Zeeb 		.band_idx = mvif->mt76.band_idx,
6956c92544dSBjoern A. Zeeb 	};
6966c92544dSBjoern A. Zeeb 	struct sk_buff *skb;
6976c92544dSBjoern A. Zeeb 
6986c92544dSBjoern A. Zeeb 	if (!enable)
6996c92544dSBjoern A. Zeeb 		goto out;
7006c92544dSBjoern A. Zeeb 
7016c92544dSBjoern A. Zeeb 	skb = ieee80211_beacon_get_template(hw, vif, &offs, 0);
7026c92544dSBjoern A. Zeeb 	if (!skb)
7036c92544dSBjoern A. Zeeb 		return -EINVAL;
7046c92544dSBjoern A. Zeeb 
7056c92544dSBjoern A. Zeeb 	if (skb->len > 512 - MT_TXD_SIZE) {
7066c92544dSBjoern A. Zeeb 		dev_err(dev->mt76.dev, "Bcn size limit exceed\n");
7076c92544dSBjoern A. Zeeb 		dev_kfree_skb(skb);
7086c92544dSBjoern A. Zeeb 		return -EINVAL;
7096c92544dSBjoern A. Zeeb 	}
7106c92544dSBjoern A. Zeeb 
7116c92544dSBjoern A. Zeeb 	info = IEEE80211_SKB_CB(skb);
7126c92544dSBjoern A. Zeeb 	info->hw_queue |= FIELD_PREP(MT_TX_HW_QUEUE_PHY, mvif->mt76.band_idx);
7136c92544dSBjoern A. Zeeb 
7146c92544dSBjoern A. Zeeb 	mt7615_mac_write_txwi(dev, (__le32 *)(req.pkt), skb, wcid, NULL,
7156c92544dSBjoern A. Zeeb 			      0, NULL, 0, true);
7166c92544dSBjoern A. Zeeb 	memcpy(req.pkt + MT_TXD_SIZE, skb->data, skb->len);
7176c92544dSBjoern A. Zeeb 	req.pkt_len = cpu_to_le16(MT_TXD_SIZE + skb->len);
7186c92544dSBjoern A. Zeeb 	req.tim_ie_pos = cpu_to_le16(MT_TXD_SIZE + offs.tim_offset);
7196c92544dSBjoern A. Zeeb 	if (offs.cntdwn_counter_offs[0]) {
7206c92544dSBjoern A. Zeeb 		u16 csa_offs;
7216c92544dSBjoern A. Zeeb 
7226c92544dSBjoern A. Zeeb 		csa_offs = MT_TXD_SIZE + offs.cntdwn_counter_offs[0] - 4;
7236c92544dSBjoern A. Zeeb 		req.csa_ie_pos = cpu_to_le16(csa_offs);
7246c92544dSBjoern A. Zeeb 		req.csa_cnt = skb->data[offs.cntdwn_counter_offs[0]];
7256c92544dSBjoern A. Zeeb 	}
7266c92544dSBjoern A. Zeeb 	dev_kfree_skb(skb);
7276c92544dSBjoern A. Zeeb 
7286c92544dSBjoern A. Zeeb out:
7296c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(BCN_OFFLOAD), &req,
7306c92544dSBjoern A. Zeeb 				 sizeof(req), true);
7316c92544dSBjoern A. Zeeb }
7326c92544dSBjoern A. Zeeb 
7336c92544dSBjoern A. Zeeb static int
7346c92544dSBjoern A. Zeeb mt7615_mcu_ctrl_pm_state(struct mt7615_dev *dev, int band, int state)
7356c92544dSBjoern A. Zeeb {
7366c92544dSBjoern A. Zeeb 	return mt76_connac_mcu_set_pm(&dev->mt76, band, state);
7376c92544dSBjoern A. Zeeb }
7386c92544dSBjoern A. Zeeb 
7396c92544dSBjoern A. Zeeb static int
7406c92544dSBjoern A. Zeeb mt7615_mcu_add_bss(struct mt7615_phy *phy, struct ieee80211_vif *vif,
7416c92544dSBjoern A. Zeeb 		   struct ieee80211_sta *sta, bool enable)
7426c92544dSBjoern A. Zeeb {
7436c92544dSBjoern A. Zeeb 	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
7446c92544dSBjoern A. Zeeb 	struct mt7615_dev *dev = phy->dev;
7456c92544dSBjoern A. Zeeb 	struct sk_buff *skb;
7466c92544dSBjoern A. Zeeb 
7476c92544dSBjoern A. Zeeb 	if (mvif->mt76.omac_idx >= REPEATER_BSSID_START)
7486c92544dSBjoern A. Zeeb 		mt7615_mcu_muar_config(dev, vif, true, enable);
7496c92544dSBjoern A. Zeeb 
7506c92544dSBjoern A. Zeeb 	skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, NULL);
7516c92544dSBjoern A. Zeeb 	if (IS_ERR(skb))
7526c92544dSBjoern A. Zeeb 		return PTR_ERR(skb);
7536c92544dSBjoern A. Zeeb 
7546c92544dSBjoern A. Zeeb 	if (enable)
7556c92544dSBjoern A. Zeeb 		mt76_connac_mcu_bss_omac_tlv(skb, vif);
7566c92544dSBjoern A. Zeeb 
7576c92544dSBjoern A. Zeeb 	mt76_connac_mcu_bss_basic_tlv(skb, vif, sta, phy->mt76,
7586c92544dSBjoern A. Zeeb 				      mvif->sta.wcid.idx, enable);
7596c92544dSBjoern A. Zeeb 
7606c92544dSBjoern A. Zeeb 	if (enable && mvif->mt76.omac_idx >= EXT_BSSID_START &&
7616c92544dSBjoern A. Zeeb 	    mvif->mt76.omac_idx < REPEATER_BSSID_START)
7626c92544dSBjoern A. Zeeb 		mt76_connac_mcu_bss_ext_tlv(skb, &mvif->mt76);
7636c92544dSBjoern A. Zeeb 
7646c92544dSBjoern A. Zeeb 	return mt76_mcu_skb_send_msg(&dev->mt76, skb,
7656c92544dSBjoern A. Zeeb 				     MCU_EXT_CMD(BSS_INFO_UPDATE), true);
7666c92544dSBjoern A. Zeeb }
7676c92544dSBjoern A. Zeeb 
7686c92544dSBjoern A. Zeeb static int
7696c92544dSBjoern A. Zeeb mt7615_mcu_wtbl_tx_ba(struct mt7615_dev *dev,
7706c92544dSBjoern A. Zeeb 		      struct ieee80211_ampdu_params *params,
7716c92544dSBjoern A. Zeeb 		      bool enable)
7726c92544dSBjoern A. Zeeb {
7736c92544dSBjoern A. Zeeb 	struct mt7615_sta *msta = (struct mt7615_sta *)params->sta->drv_priv;
7746c92544dSBjoern A. Zeeb 	struct mt7615_vif *mvif = msta->vif;
7756c92544dSBjoern A. Zeeb 	struct wtbl_req_hdr *wtbl_hdr;
7766c92544dSBjoern A. Zeeb 	struct sk_buff *skb = NULL;
7776c92544dSBjoern A. Zeeb 	int err;
7786c92544dSBjoern A. Zeeb 
7796c92544dSBjoern A. Zeeb 	wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(&dev->mt76, &msta->wcid,
7806c92544dSBjoern A. Zeeb 						  WTBL_SET, NULL, &skb);
7816c92544dSBjoern A. Zeeb 	if (IS_ERR(wtbl_hdr))
7826c92544dSBjoern A. Zeeb 		return PTR_ERR(wtbl_hdr);
7836c92544dSBjoern A. Zeeb 
7846c92544dSBjoern A. Zeeb 	mt76_connac_mcu_wtbl_ba_tlv(&dev->mt76, skb, params, enable, true,
7856c92544dSBjoern A. Zeeb 				    NULL, wtbl_hdr);
7866c92544dSBjoern A. Zeeb 
7876c92544dSBjoern A. Zeeb 	err = mt76_mcu_skb_send_msg(&dev->mt76, skb,
7886c92544dSBjoern A. Zeeb 				    MCU_EXT_CMD(WTBL_UPDATE), true);
7896c92544dSBjoern A. Zeeb 	if (err < 0)
7906c92544dSBjoern A. Zeeb 		return err;
7916c92544dSBjoern A. Zeeb 
7926c92544dSBjoern A. Zeeb 	skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
7936c92544dSBjoern A. Zeeb 					    &msta->wcid);
7946c92544dSBjoern A. Zeeb 	if (IS_ERR(skb))
7956c92544dSBjoern A. Zeeb 		return PTR_ERR(skb);
7966c92544dSBjoern A. Zeeb 
7976c92544dSBjoern A. Zeeb 	mt76_connac_mcu_sta_ba_tlv(skb, params, enable, true);
7986c92544dSBjoern A. Zeeb 
7996c92544dSBjoern A. Zeeb 	return mt76_mcu_skb_send_msg(&dev->mt76, skb,
8006c92544dSBjoern A. Zeeb 				     MCU_EXT_CMD(STA_REC_UPDATE), true);
8016c92544dSBjoern A. Zeeb }
8026c92544dSBjoern A. Zeeb 
8036c92544dSBjoern A. Zeeb static int
8046c92544dSBjoern A. Zeeb mt7615_mcu_wtbl_rx_ba(struct mt7615_dev *dev,
8056c92544dSBjoern A. Zeeb 		      struct ieee80211_ampdu_params *params,
8066c92544dSBjoern A. Zeeb 		      bool enable)
8076c92544dSBjoern A. Zeeb {
8086c92544dSBjoern A. Zeeb 	struct mt7615_sta *msta = (struct mt7615_sta *)params->sta->drv_priv;
8096c92544dSBjoern A. Zeeb 	struct mt7615_vif *mvif = msta->vif;
8106c92544dSBjoern A. Zeeb 	struct wtbl_req_hdr *wtbl_hdr;
8116c92544dSBjoern A. Zeeb 	struct sk_buff *skb;
8126c92544dSBjoern A. Zeeb 	int err;
8136c92544dSBjoern A. Zeeb 
8146c92544dSBjoern A. Zeeb 	skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
8156c92544dSBjoern A. Zeeb 					    &msta->wcid);
8166c92544dSBjoern A. Zeeb 	if (IS_ERR(skb))
8176c92544dSBjoern A. Zeeb 		return PTR_ERR(skb);
8186c92544dSBjoern A. Zeeb 
8196c92544dSBjoern A. Zeeb 	mt76_connac_mcu_sta_ba_tlv(skb, params, enable, false);
8206c92544dSBjoern A. Zeeb 
8216c92544dSBjoern A. Zeeb 	err = mt76_mcu_skb_send_msg(&dev->mt76, skb,
8226c92544dSBjoern A. Zeeb 				    MCU_EXT_CMD(STA_REC_UPDATE), true);
8236c92544dSBjoern A. Zeeb 	if (err < 0 || !enable)
8246c92544dSBjoern A. Zeeb 		return err;
8256c92544dSBjoern A. Zeeb 
8266c92544dSBjoern A. Zeeb 	skb = NULL;
8276c92544dSBjoern A. Zeeb 	wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(&dev->mt76, &msta->wcid,
8286c92544dSBjoern A. Zeeb 						  WTBL_SET, NULL, &skb);
8296c92544dSBjoern A. Zeeb 	if (IS_ERR(wtbl_hdr))
8306c92544dSBjoern A. Zeeb 		return PTR_ERR(wtbl_hdr);
8316c92544dSBjoern A. Zeeb 
8326c92544dSBjoern A. Zeeb 	mt76_connac_mcu_wtbl_ba_tlv(&dev->mt76, skb, params, enable, false,
8336c92544dSBjoern A. Zeeb 				    NULL, wtbl_hdr);
8346c92544dSBjoern A. Zeeb 
8356c92544dSBjoern A. Zeeb 	return mt76_mcu_skb_send_msg(&dev->mt76, skb,
8366c92544dSBjoern A. Zeeb 				     MCU_EXT_CMD(WTBL_UPDATE), true);
8376c92544dSBjoern A. Zeeb }
8386c92544dSBjoern A. Zeeb 
8396c92544dSBjoern A. Zeeb static int
8406c92544dSBjoern A. Zeeb mt7615_mcu_wtbl_sta_add(struct mt7615_phy *phy, struct ieee80211_vif *vif,
8416c92544dSBjoern A. Zeeb 			struct ieee80211_sta *sta, bool enable)
8426c92544dSBjoern A. Zeeb {
8436c92544dSBjoern A. Zeeb 	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
8446c92544dSBjoern A. Zeeb 	struct sk_buff *skb, *sskb, *wskb = NULL;
8456c92544dSBjoern A. Zeeb 	struct mt7615_dev *dev = phy->dev;
8466c92544dSBjoern A. Zeeb 	struct wtbl_req_hdr *wtbl_hdr;
8476c92544dSBjoern A. Zeeb 	struct mt7615_sta *msta;
8486c92544dSBjoern A. Zeeb 	bool new_entry = true;
8496c92544dSBjoern A. Zeeb 	int cmd, err;
8506c92544dSBjoern A. Zeeb 
8516c92544dSBjoern A. Zeeb 	msta = sta ? (struct mt7615_sta *)sta->drv_priv : &mvif->sta;
8526c92544dSBjoern A. Zeeb 
8536c92544dSBjoern A. Zeeb 	sskb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
8546c92544dSBjoern A. Zeeb 					     &msta->wcid);
8556c92544dSBjoern A. Zeeb 	if (IS_ERR(sskb))
8566c92544dSBjoern A. Zeeb 		return PTR_ERR(sskb);
8576c92544dSBjoern A. Zeeb 
8586c92544dSBjoern A. Zeeb 	if (!sta) {
8596c92544dSBjoern A. Zeeb 		if (mvif->sta_added)
8606c92544dSBjoern A. Zeeb 			new_entry = false;
8616c92544dSBjoern A. Zeeb 		else
8626c92544dSBjoern A. Zeeb 			mvif->sta_added = true;
8636c92544dSBjoern A. Zeeb 	}
864*cbb3ec25SBjoern A. Zeeb 	mt76_connac_mcu_sta_basic_tlv(&dev->mt76, sskb, vif, sta, enable,
865*cbb3ec25SBjoern A. Zeeb 				      new_entry);
8666c92544dSBjoern A. Zeeb 	if (enable && sta)
8676c92544dSBjoern A. Zeeb 		mt76_connac_mcu_sta_tlv(phy->mt76, sskb, sta, vif, 0,
8686c92544dSBjoern A. Zeeb 					MT76_STA_INFO_STATE_ASSOC);
8696c92544dSBjoern A. Zeeb 
8706c92544dSBjoern A. Zeeb 	wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(&dev->mt76, &msta->wcid,
8716c92544dSBjoern A. Zeeb 						  WTBL_RESET_AND_SET, NULL,
8726c92544dSBjoern A. Zeeb 						  &wskb);
8736c92544dSBjoern A. Zeeb 	if (IS_ERR(wtbl_hdr))
8746c92544dSBjoern A. Zeeb 		return PTR_ERR(wtbl_hdr);
8756c92544dSBjoern A. Zeeb 
8766c92544dSBjoern A. Zeeb 	if (enable) {
8776c92544dSBjoern A. Zeeb 		mt76_connac_mcu_wtbl_generic_tlv(&dev->mt76, wskb, vif, sta,
8786c92544dSBjoern A. Zeeb 						 NULL, wtbl_hdr);
8796c92544dSBjoern A. Zeeb 		if (sta)
8806c92544dSBjoern A. Zeeb 			mt76_connac_mcu_wtbl_ht_tlv(&dev->mt76, wskb, sta,
8816c92544dSBjoern A. Zeeb 						    NULL, wtbl_hdr, true, true);
8826c92544dSBjoern A. Zeeb 		mt76_connac_mcu_wtbl_hdr_trans_tlv(wskb, vif, &msta->wcid,
8836c92544dSBjoern A. Zeeb 						   NULL, wtbl_hdr);
8846c92544dSBjoern A. Zeeb 	}
8856c92544dSBjoern A. Zeeb 
8866c92544dSBjoern A. Zeeb 	cmd = enable ? MCU_EXT_CMD(WTBL_UPDATE) : MCU_EXT_CMD(STA_REC_UPDATE);
8876c92544dSBjoern A. Zeeb 	skb = enable ? wskb : sskb;
8886c92544dSBjoern A. Zeeb 
8896c92544dSBjoern A. Zeeb 	err = mt76_mcu_skb_send_msg(&dev->mt76, skb, cmd, true);
8906c92544dSBjoern A. Zeeb 	if (err < 0) {
8916c92544dSBjoern A. Zeeb 		skb = enable ? sskb : wskb;
8926c92544dSBjoern A. Zeeb 		dev_kfree_skb(skb);
8936c92544dSBjoern A. Zeeb 
8946c92544dSBjoern A. Zeeb 		return err;
8956c92544dSBjoern A. Zeeb 	}
8966c92544dSBjoern A. Zeeb 
8976c92544dSBjoern A. Zeeb 	cmd = enable ? MCU_EXT_CMD(STA_REC_UPDATE) : MCU_EXT_CMD(WTBL_UPDATE);
8986c92544dSBjoern A. Zeeb 	skb = enable ? sskb : wskb;
8996c92544dSBjoern A. Zeeb 
9006c92544dSBjoern A. Zeeb 	return mt76_mcu_skb_send_msg(&dev->mt76, skb, cmd, true);
9016c92544dSBjoern A. Zeeb }
9026c92544dSBjoern A. Zeeb 
9036c92544dSBjoern A. Zeeb static int
9046c92544dSBjoern A. Zeeb mt7615_mcu_wtbl_update_hdr_trans(struct mt7615_dev *dev,
9056c92544dSBjoern A. Zeeb 				 struct ieee80211_vif *vif,
9066c92544dSBjoern A. Zeeb 				 struct ieee80211_sta *sta)
9076c92544dSBjoern A. Zeeb {
9086c92544dSBjoern A. Zeeb 	return mt76_connac_mcu_wtbl_update_hdr_trans(&dev->mt76, vif, sta);
9096c92544dSBjoern A. Zeeb }
9106c92544dSBjoern A. Zeeb 
9116c92544dSBjoern A. Zeeb static const struct mt7615_mcu_ops wtbl_update_ops = {
9126c92544dSBjoern A. Zeeb 	.add_beacon_offload = mt7615_mcu_add_beacon_offload,
9136c92544dSBjoern A. Zeeb 	.set_pm_state = mt7615_mcu_ctrl_pm_state,
9146c92544dSBjoern A. Zeeb 	.add_dev_info = mt7615_mcu_add_dev,
9156c92544dSBjoern A. Zeeb 	.add_bss_info = mt7615_mcu_add_bss,
9166c92544dSBjoern A. Zeeb 	.add_tx_ba = mt7615_mcu_wtbl_tx_ba,
9176c92544dSBjoern A. Zeeb 	.add_rx_ba = mt7615_mcu_wtbl_rx_ba,
9186c92544dSBjoern A. Zeeb 	.sta_add = mt7615_mcu_wtbl_sta_add,
9196c92544dSBjoern A. Zeeb 	.set_drv_ctrl = mt7615_mcu_drv_pmctrl,
9206c92544dSBjoern A. Zeeb 	.set_fw_ctrl = mt7615_mcu_fw_pmctrl,
9216c92544dSBjoern A. Zeeb 	.set_sta_decap_offload = mt7615_mcu_wtbl_update_hdr_trans,
9226c92544dSBjoern A. Zeeb };
9236c92544dSBjoern A. Zeeb 
9246c92544dSBjoern A. Zeeb static int
9256c92544dSBjoern A. Zeeb mt7615_mcu_sta_ba(struct mt7615_dev *dev,
9266c92544dSBjoern A. Zeeb 		  struct ieee80211_ampdu_params *params,
9276c92544dSBjoern A. Zeeb 		  bool enable, bool tx)
9286c92544dSBjoern A. Zeeb {
9296c92544dSBjoern A. Zeeb 	struct mt7615_sta *msta = (struct mt7615_sta *)params->sta->drv_priv;
9306c92544dSBjoern A. Zeeb 	struct mt7615_vif *mvif = msta->vif;
9316c92544dSBjoern A. Zeeb 	struct wtbl_req_hdr *wtbl_hdr;
9326c92544dSBjoern A. Zeeb 	struct tlv *sta_wtbl;
9336c92544dSBjoern A. Zeeb 	struct sk_buff *skb;
9346c92544dSBjoern A. Zeeb 
9356c92544dSBjoern A. Zeeb 	skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
9366c92544dSBjoern A. Zeeb 					    &msta->wcid);
9376c92544dSBjoern A. Zeeb 	if (IS_ERR(skb))
9386c92544dSBjoern A. Zeeb 		return PTR_ERR(skb);
9396c92544dSBjoern A. Zeeb 
9406c92544dSBjoern A. Zeeb 	mt76_connac_mcu_sta_ba_tlv(skb, params, enable, tx);
9416c92544dSBjoern A. Zeeb 
9426c92544dSBjoern A. Zeeb 	sta_wtbl = mt76_connac_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv));
9436c92544dSBjoern A. Zeeb 
9446c92544dSBjoern A. Zeeb 	wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(&dev->mt76, &msta->wcid,
9456c92544dSBjoern A. Zeeb 						  WTBL_SET, sta_wtbl, &skb);
9466c92544dSBjoern A. Zeeb 	if (IS_ERR(wtbl_hdr))
9476c92544dSBjoern A. Zeeb 		return PTR_ERR(wtbl_hdr);
9486c92544dSBjoern A. Zeeb 
9496c92544dSBjoern A. Zeeb 	mt76_connac_mcu_wtbl_ba_tlv(&dev->mt76, skb, params, enable, tx,
9506c92544dSBjoern A. Zeeb 				    sta_wtbl, wtbl_hdr);
9516c92544dSBjoern A. Zeeb 
9526c92544dSBjoern A. Zeeb 	return mt76_mcu_skb_send_msg(&dev->mt76, skb,
9536c92544dSBjoern A. Zeeb 				     MCU_EXT_CMD(STA_REC_UPDATE), true);
9546c92544dSBjoern A. Zeeb }
9556c92544dSBjoern A. Zeeb 
9566c92544dSBjoern A. Zeeb static int
9576c92544dSBjoern A. Zeeb mt7615_mcu_sta_tx_ba(struct mt7615_dev *dev,
9586c92544dSBjoern A. Zeeb 		     struct ieee80211_ampdu_params *params,
9596c92544dSBjoern A. Zeeb 		     bool enable)
9606c92544dSBjoern A. Zeeb {
9616c92544dSBjoern A. Zeeb 	return mt7615_mcu_sta_ba(dev, params, enable, true);
9626c92544dSBjoern A. Zeeb }
9636c92544dSBjoern A. Zeeb 
9646c92544dSBjoern A. Zeeb static int
9656c92544dSBjoern A. Zeeb mt7615_mcu_sta_rx_ba(struct mt7615_dev *dev,
9666c92544dSBjoern A. Zeeb 		     struct ieee80211_ampdu_params *params,
9676c92544dSBjoern A. Zeeb 		     bool enable)
9686c92544dSBjoern A. Zeeb {
9696c92544dSBjoern A. Zeeb 	return mt7615_mcu_sta_ba(dev, params, enable, false);
9706c92544dSBjoern A. Zeeb }
9716c92544dSBjoern A. Zeeb 
9726c92544dSBjoern A. Zeeb static int
9736c92544dSBjoern A. Zeeb __mt7615_mcu_add_sta(struct mt76_phy *phy, struct ieee80211_vif *vif,
9746c92544dSBjoern A. Zeeb 		     struct ieee80211_sta *sta, bool enable, int cmd,
9756c92544dSBjoern A. Zeeb 		     bool offload_fw)
9766c92544dSBjoern A. Zeeb {
9776c92544dSBjoern A. Zeeb 	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
9786c92544dSBjoern A. Zeeb 	struct mt76_sta_cmd_info info = {
9796c92544dSBjoern A. Zeeb 		.sta = sta,
9806c92544dSBjoern A. Zeeb 		.vif = vif,
9816c92544dSBjoern A. Zeeb 		.offload_fw = offload_fw,
9826c92544dSBjoern A. Zeeb 		.enable = enable,
9836c92544dSBjoern A. Zeeb 		.newly = true,
9846c92544dSBjoern A. Zeeb 		.cmd = cmd,
9856c92544dSBjoern A. Zeeb 	};
9866c92544dSBjoern A. Zeeb 
9876c92544dSBjoern A. Zeeb 	info.wcid = sta ? (struct mt76_wcid *)sta->drv_priv : &mvif->sta.wcid;
9886c92544dSBjoern A. Zeeb 	return mt76_connac_mcu_sta_cmd(phy, &info);
9896c92544dSBjoern A. Zeeb }
9906c92544dSBjoern A. Zeeb 
9916c92544dSBjoern A. Zeeb static int
9926c92544dSBjoern A. Zeeb mt7615_mcu_add_sta(struct mt7615_phy *phy, struct ieee80211_vif *vif,
9936c92544dSBjoern A. Zeeb 		   struct ieee80211_sta *sta, bool enable)
9946c92544dSBjoern A. Zeeb {
9956c92544dSBjoern A. Zeeb 	return __mt7615_mcu_add_sta(phy->mt76, vif, sta, enable,
9966c92544dSBjoern A. Zeeb 				    MCU_EXT_CMD(STA_REC_UPDATE), false);
9976c92544dSBjoern A. Zeeb }
9986c92544dSBjoern A. Zeeb 
9996c92544dSBjoern A. Zeeb static int
10006c92544dSBjoern A. Zeeb mt7615_mcu_sta_update_hdr_trans(struct mt7615_dev *dev,
10016c92544dSBjoern A. Zeeb 				struct ieee80211_vif *vif,
10026c92544dSBjoern A. Zeeb 				struct ieee80211_sta *sta)
10036c92544dSBjoern A. Zeeb {
10046c92544dSBjoern A. Zeeb 	struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv;
10056c92544dSBjoern A. Zeeb 
10066c92544dSBjoern A. Zeeb 	return mt76_connac_mcu_sta_update_hdr_trans(&dev->mt76,
10076c92544dSBjoern A. Zeeb 						    vif, &msta->wcid,
10086c92544dSBjoern A. Zeeb 						    MCU_EXT_CMD(STA_REC_UPDATE));
10096c92544dSBjoern A. Zeeb }
10106c92544dSBjoern A. Zeeb 
10116c92544dSBjoern A. Zeeb static const struct mt7615_mcu_ops sta_update_ops = {
10126c92544dSBjoern A. Zeeb 	.add_beacon_offload = mt7615_mcu_add_beacon_offload,
10136c92544dSBjoern A. Zeeb 	.set_pm_state = mt7615_mcu_ctrl_pm_state,
10146c92544dSBjoern A. Zeeb 	.add_dev_info = mt7615_mcu_add_dev,
10156c92544dSBjoern A. Zeeb 	.add_bss_info = mt7615_mcu_add_bss,
10166c92544dSBjoern A. Zeeb 	.add_tx_ba = mt7615_mcu_sta_tx_ba,
10176c92544dSBjoern A. Zeeb 	.add_rx_ba = mt7615_mcu_sta_rx_ba,
10186c92544dSBjoern A. Zeeb 	.sta_add = mt7615_mcu_add_sta,
10196c92544dSBjoern A. Zeeb 	.set_drv_ctrl = mt7615_mcu_drv_pmctrl,
10206c92544dSBjoern A. Zeeb 	.set_fw_ctrl = mt7615_mcu_fw_pmctrl,
10216c92544dSBjoern A. Zeeb 	.set_sta_decap_offload = mt7615_mcu_sta_update_hdr_trans,
10226c92544dSBjoern A. Zeeb };
10236c92544dSBjoern A. Zeeb 
10246c92544dSBjoern A. Zeeb static int
10256c92544dSBjoern A. Zeeb mt7615_mcu_uni_ctrl_pm_state(struct mt7615_dev *dev, int band, int state)
10266c92544dSBjoern A. Zeeb {
10276c92544dSBjoern A. Zeeb 	return 0;
10286c92544dSBjoern A. Zeeb }
10296c92544dSBjoern A. Zeeb 
10306c92544dSBjoern A. Zeeb static int
10316c92544dSBjoern A. Zeeb mt7615_mcu_uni_add_beacon_offload(struct mt7615_dev *dev,
10326c92544dSBjoern A. Zeeb 				  struct ieee80211_hw *hw,
10336c92544dSBjoern A. Zeeb 				  struct ieee80211_vif *vif,
10346c92544dSBjoern A. Zeeb 				  bool enable)
10356c92544dSBjoern A. Zeeb {
10366c92544dSBjoern A. Zeeb 	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
10376c92544dSBjoern A. Zeeb 	struct mt76_wcid *wcid = &dev->mt76.global_wcid;
10386c92544dSBjoern A. Zeeb 	struct ieee80211_mutable_offsets offs;
10396c92544dSBjoern A. Zeeb 	struct {
10406c92544dSBjoern A. Zeeb 		struct req_hdr {
10416c92544dSBjoern A. Zeeb 			u8 bss_idx;
10426c92544dSBjoern A. Zeeb 			u8 pad[3];
10436c92544dSBjoern A. Zeeb 		} __packed hdr;
10446c92544dSBjoern A. Zeeb 		struct bcn_content_tlv {
10456c92544dSBjoern A. Zeeb 			__le16 tag;
10466c92544dSBjoern A. Zeeb 			__le16 len;
10476c92544dSBjoern A. Zeeb 			__le16 tim_ie_pos;
10486c92544dSBjoern A. Zeeb 			__le16 csa_ie_pos;
10496c92544dSBjoern A. Zeeb 			__le16 bcc_ie_pos;
10506c92544dSBjoern A. Zeeb 			/* 0: disable beacon offload
10516c92544dSBjoern A. Zeeb 			 * 1: enable beacon offload
10526c92544dSBjoern A. Zeeb 			 * 2: update probe respond offload
10536c92544dSBjoern A. Zeeb 			 */
10546c92544dSBjoern A. Zeeb 			u8 enable;
10556c92544dSBjoern A. Zeeb 			/* 0: legacy format (TXD + payload)
10566c92544dSBjoern A. Zeeb 			 * 1: only cap field IE
10576c92544dSBjoern A. Zeeb 			 */
10586c92544dSBjoern A. Zeeb 			u8 type;
10596c92544dSBjoern A. Zeeb 			__le16 pkt_len;
10606c92544dSBjoern A. Zeeb 			u8 pkt[512];
10616c92544dSBjoern A. Zeeb 		} __packed beacon_tlv;
10626c92544dSBjoern A. Zeeb 	} req = {
10636c92544dSBjoern A. Zeeb 		.hdr = {
10646c92544dSBjoern A. Zeeb 			.bss_idx = mvif->mt76.idx,
10656c92544dSBjoern A. Zeeb 		},
10666c92544dSBjoern A. Zeeb 		.beacon_tlv = {
10676c92544dSBjoern A. Zeeb 			.tag = cpu_to_le16(UNI_BSS_INFO_BCN_CONTENT),
10686c92544dSBjoern A. Zeeb 			.len = cpu_to_le16(sizeof(struct bcn_content_tlv)),
10696c92544dSBjoern A. Zeeb 			.enable = enable,
10706c92544dSBjoern A. Zeeb 		},
10716c92544dSBjoern A. Zeeb 	};
10726c92544dSBjoern A. Zeeb 	struct sk_buff *skb;
10736c92544dSBjoern A. Zeeb 
10746c92544dSBjoern A. Zeeb 	if (!enable)
10756c92544dSBjoern A. Zeeb 		goto out;
10766c92544dSBjoern A. Zeeb 
10776c92544dSBjoern A. Zeeb 	skb = ieee80211_beacon_get_template(mt76_hw(dev), vif, &offs, 0);
10786c92544dSBjoern A. Zeeb 	if (!skb)
10796c92544dSBjoern A. Zeeb 		return -EINVAL;
10806c92544dSBjoern A. Zeeb 
10816c92544dSBjoern A. Zeeb 	if (skb->len > 512 - MT_TXD_SIZE) {
10826c92544dSBjoern A. Zeeb 		dev_err(dev->mt76.dev, "beacon size limit exceed\n");
10836c92544dSBjoern A. Zeeb 		dev_kfree_skb(skb);
10846c92544dSBjoern A. Zeeb 		return -EINVAL;
10856c92544dSBjoern A. Zeeb 	}
10866c92544dSBjoern A. Zeeb 
10876c92544dSBjoern A. Zeeb 	mt7615_mac_write_txwi(dev, (__le32 *)(req.beacon_tlv.pkt), skb,
10886c92544dSBjoern A. Zeeb 			      wcid, NULL, 0, NULL, 0, true);
10896c92544dSBjoern A. Zeeb 	memcpy(req.beacon_tlv.pkt + MT_TXD_SIZE, skb->data, skb->len);
10906c92544dSBjoern A. Zeeb 	req.beacon_tlv.pkt_len = cpu_to_le16(MT_TXD_SIZE + skb->len);
10916c92544dSBjoern A. Zeeb 	req.beacon_tlv.tim_ie_pos = cpu_to_le16(MT_TXD_SIZE + offs.tim_offset);
10926c92544dSBjoern A. Zeeb 
10936c92544dSBjoern A. Zeeb 	if (offs.cntdwn_counter_offs[0]) {
10946c92544dSBjoern A. Zeeb 		u16 csa_offs;
10956c92544dSBjoern A. Zeeb 
10966c92544dSBjoern A. Zeeb 		csa_offs = MT_TXD_SIZE + offs.cntdwn_counter_offs[0] - 4;
10976c92544dSBjoern A. Zeeb 		req.beacon_tlv.csa_ie_pos = cpu_to_le16(csa_offs);
10986c92544dSBjoern A. Zeeb 	}
10996c92544dSBjoern A. Zeeb 	dev_kfree_skb(skb);
11006c92544dSBjoern A. Zeeb 
11016c92544dSBjoern A. Zeeb out:
11026c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(BSS_INFO_UPDATE),
11036c92544dSBjoern A. Zeeb 				 &req, sizeof(req), true);
11046c92544dSBjoern A. Zeeb }
11056c92544dSBjoern A. Zeeb 
11066c92544dSBjoern A. Zeeb static int
11076c92544dSBjoern A. Zeeb mt7615_mcu_uni_add_dev(struct mt7615_phy *phy, struct ieee80211_vif *vif,
11086c92544dSBjoern A. Zeeb 		       bool enable)
11096c92544dSBjoern A. Zeeb {
11106c92544dSBjoern A. Zeeb 	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
11116c92544dSBjoern A. Zeeb 
11126c92544dSBjoern A. Zeeb 	return mt76_connac_mcu_uni_add_dev(phy->mt76, vif, &mvif->sta.wcid,
11136c92544dSBjoern A. Zeeb 					   enable);
11146c92544dSBjoern A. Zeeb }
11156c92544dSBjoern A. Zeeb 
11166c92544dSBjoern A. Zeeb static int
11176c92544dSBjoern A. Zeeb mt7615_mcu_uni_add_bss(struct mt7615_phy *phy, struct ieee80211_vif *vif,
11186c92544dSBjoern A. Zeeb 		       struct ieee80211_sta *sta, bool enable)
11196c92544dSBjoern A. Zeeb {
11206c92544dSBjoern A. Zeeb 	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
11216c92544dSBjoern A. Zeeb 
11226c92544dSBjoern A. Zeeb 	return mt76_connac_mcu_uni_add_bss(phy->mt76, vif, &mvif->sta.wcid,
1123*cbb3ec25SBjoern A. Zeeb 					   enable, NULL);
11246c92544dSBjoern A. Zeeb }
11256c92544dSBjoern A. Zeeb 
11266c92544dSBjoern A. Zeeb static inline int
11276c92544dSBjoern A. Zeeb mt7615_mcu_uni_add_sta(struct mt7615_phy *phy, struct ieee80211_vif *vif,
11286c92544dSBjoern A. Zeeb 		       struct ieee80211_sta *sta, bool enable)
11296c92544dSBjoern A. Zeeb {
11306c92544dSBjoern A. Zeeb 	return __mt7615_mcu_add_sta(phy->mt76, vif, sta, enable,
11316c92544dSBjoern A. Zeeb 				    MCU_UNI_CMD(STA_REC_UPDATE), true);
11326c92544dSBjoern A. Zeeb }
11336c92544dSBjoern A. Zeeb 
11346c92544dSBjoern A. Zeeb static int
11356c92544dSBjoern A. Zeeb mt7615_mcu_uni_tx_ba(struct mt7615_dev *dev,
11366c92544dSBjoern A. Zeeb 		     struct ieee80211_ampdu_params *params,
11376c92544dSBjoern A. Zeeb 		     bool enable)
11386c92544dSBjoern A. Zeeb {
11396c92544dSBjoern A. Zeeb 	struct mt7615_sta *sta = (struct mt7615_sta *)params->sta->drv_priv;
11406c92544dSBjoern A. Zeeb 
11416c92544dSBjoern A. Zeeb 	return mt76_connac_mcu_sta_ba(&dev->mt76, &sta->vif->mt76, params,
11426c92544dSBjoern A. Zeeb 				      MCU_UNI_CMD(STA_REC_UPDATE), enable,
11436c92544dSBjoern A. Zeeb 				      true);
11446c92544dSBjoern A. Zeeb }
11456c92544dSBjoern A. Zeeb 
11466c92544dSBjoern A. Zeeb static int
11476c92544dSBjoern A. Zeeb mt7615_mcu_uni_rx_ba(struct mt7615_dev *dev,
11486c92544dSBjoern A. Zeeb 		     struct ieee80211_ampdu_params *params,
11496c92544dSBjoern A. Zeeb 		     bool enable)
11506c92544dSBjoern A. Zeeb {
11516c92544dSBjoern A. Zeeb 	struct mt7615_sta *msta = (struct mt7615_sta *)params->sta->drv_priv;
11526c92544dSBjoern A. Zeeb 	struct mt7615_vif *mvif = msta->vif;
11536c92544dSBjoern A. Zeeb 	struct wtbl_req_hdr *wtbl_hdr;
11546c92544dSBjoern A. Zeeb 	struct tlv *sta_wtbl;
11556c92544dSBjoern A. Zeeb 	struct sk_buff *skb;
11566c92544dSBjoern A. Zeeb 	int err;
11576c92544dSBjoern A. Zeeb 
11586c92544dSBjoern A. Zeeb 	skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
11596c92544dSBjoern A. Zeeb 					    &msta->wcid);
11606c92544dSBjoern A. Zeeb 	if (IS_ERR(skb))
11616c92544dSBjoern A. Zeeb 		return PTR_ERR(skb);
11626c92544dSBjoern A. Zeeb 
11636c92544dSBjoern A. Zeeb 	mt76_connac_mcu_sta_ba_tlv(skb, params, enable, false);
11646c92544dSBjoern A. Zeeb 
11656c92544dSBjoern A. Zeeb 	err = mt76_mcu_skb_send_msg(&dev->mt76, skb,
11666c92544dSBjoern A. Zeeb 				    MCU_UNI_CMD(STA_REC_UPDATE), true);
11676c92544dSBjoern A. Zeeb 	if (err < 0 || !enable)
11686c92544dSBjoern A. Zeeb 		return err;
11696c92544dSBjoern A. Zeeb 
11706c92544dSBjoern A. Zeeb 	skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
11716c92544dSBjoern A. Zeeb 					    &msta->wcid);
11726c92544dSBjoern A. Zeeb 	if (IS_ERR(skb))
11736c92544dSBjoern A. Zeeb 		return PTR_ERR(skb);
11746c92544dSBjoern A. Zeeb 
11756c92544dSBjoern A. Zeeb 	sta_wtbl = mt76_connac_mcu_add_tlv(skb, STA_REC_WTBL,
11766c92544dSBjoern A. Zeeb 					   sizeof(struct tlv));
11776c92544dSBjoern A. Zeeb 
11786c92544dSBjoern A. Zeeb 	wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(&dev->mt76, &msta->wcid,
11796c92544dSBjoern A. Zeeb 						  WTBL_SET, sta_wtbl, &skb);
11806c92544dSBjoern A. Zeeb 	if (IS_ERR(wtbl_hdr))
11816c92544dSBjoern A. Zeeb 		return PTR_ERR(wtbl_hdr);
11826c92544dSBjoern A. Zeeb 
11836c92544dSBjoern A. Zeeb 	mt76_connac_mcu_wtbl_ba_tlv(&dev->mt76, skb, params, enable, false,
11846c92544dSBjoern A. Zeeb 				    sta_wtbl, wtbl_hdr);
11856c92544dSBjoern A. Zeeb 
11866c92544dSBjoern A. Zeeb 	return mt76_mcu_skb_send_msg(&dev->mt76, skb,
11876c92544dSBjoern A. Zeeb 				     MCU_UNI_CMD(STA_REC_UPDATE), true);
11886c92544dSBjoern A. Zeeb }
11896c92544dSBjoern A. Zeeb 
11906c92544dSBjoern A. Zeeb static int
11916c92544dSBjoern A. Zeeb mt7615_mcu_sta_uni_update_hdr_trans(struct mt7615_dev *dev,
11926c92544dSBjoern A. Zeeb 				    struct ieee80211_vif *vif,
11936c92544dSBjoern A. Zeeb 				    struct ieee80211_sta *sta)
11946c92544dSBjoern A. Zeeb {
11956c92544dSBjoern A. Zeeb 	struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv;
11966c92544dSBjoern A. Zeeb 
11976c92544dSBjoern A. Zeeb 	return mt76_connac_mcu_sta_update_hdr_trans(&dev->mt76,
11986c92544dSBjoern A. Zeeb 						    vif, &msta->wcid,
11996c92544dSBjoern A. Zeeb 						    MCU_UNI_CMD(STA_REC_UPDATE));
12006c92544dSBjoern A. Zeeb }
12016c92544dSBjoern A. Zeeb 
12026c92544dSBjoern A. Zeeb static const struct mt7615_mcu_ops uni_update_ops = {
12036c92544dSBjoern A. Zeeb 	.add_beacon_offload = mt7615_mcu_uni_add_beacon_offload,
12046c92544dSBjoern A. Zeeb 	.set_pm_state = mt7615_mcu_uni_ctrl_pm_state,
12056c92544dSBjoern A. Zeeb 	.add_dev_info = mt7615_mcu_uni_add_dev,
12066c92544dSBjoern A. Zeeb 	.add_bss_info = mt7615_mcu_uni_add_bss,
12076c92544dSBjoern A. Zeeb 	.add_tx_ba = mt7615_mcu_uni_tx_ba,
12086c92544dSBjoern A. Zeeb 	.add_rx_ba = mt7615_mcu_uni_rx_ba,
12096c92544dSBjoern A. Zeeb 	.sta_add = mt7615_mcu_uni_add_sta,
12106c92544dSBjoern A. Zeeb 	.set_drv_ctrl = mt7615_mcu_lp_drv_pmctrl,
12116c92544dSBjoern A. Zeeb 	.set_fw_ctrl = mt7615_mcu_fw_pmctrl,
12126c92544dSBjoern A. Zeeb 	.set_sta_decap_offload = mt7615_mcu_sta_uni_update_hdr_trans,
12136c92544dSBjoern A. Zeeb };
12146c92544dSBjoern A. Zeeb 
12156c92544dSBjoern A. Zeeb int mt7615_mcu_restart(struct mt76_dev *dev)
12166c92544dSBjoern A. Zeeb {
12176c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(dev, MCU_CMD(RESTART_DL_REQ), NULL, 0, true);
12186c92544dSBjoern A. Zeeb }
12196c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt7615_mcu_restart);
12206c92544dSBjoern A. Zeeb 
12216c92544dSBjoern A. Zeeb static int mt7615_load_patch(struct mt7615_dev *dev, u32 addr, const char *name)
12226c92544dSBjoern A. Zeeb {
12236c92544dSBjoern A. Zeeb 	const struct mt7615_patch_hdr *hdr;
12246c92544dSBjoern A. Zeeb 	const struct firmware *fw = NULL;
12256c92544dSBjoern A. Zeeb 	int len, ret, sem;
12266c92544dSBjoern A. Zeeb 
12276c92544dSBjoern A. Zeeb 	ret = firmware_request_nowarn(&fw, name, dev->mt76.dev);
12286c92544dSBjoern A. Zeeb 	if (ret)
12296c92544dSBjoern A. Zeeb 		return ret;
12306c92544dSBjoern A. Zeeb 
12316c92544dSBjoern A. Zeeb 	if (!fw || !fw->data || fw->size < sizeof(*hdr)) {
12326c92544dSBjoern A. Zeeb 		dev_err(dev->mt76.dev, "Invalid firmware\n");
12336c92544dSBjoern A. Zeeb 		ret = -EINVAL;
12346c92544dSBjoern A. Zeeb 		goto release_fw;
12356c92544dSBjoern A. Zeeb 	}
12366c92544dSBjoern A. Zeeb 
12376c92544dSBjoern A. Zeeb 	sem = mt76_connac_mcu_patch_sem_ctrl(&dev->mt76, true);
12386c92544dSBjoern A. Zeeb 	switch (sem) {
12396c92544dSBjoern A. Zeeb 	case PATCH_IS_DL:
12406c92544dSBjoern A. Zeeb 		goto release_fw;
12416c92544dSBjoern A. Zeeb 	case PATCH_NOT_DL_SEM_SUCCESS:
12426c92544dSBjoern A. Zeeb 		break;
12436c92544dSBjoern A. Zeeb 	default:
12446c92544dSBjoern A. Zeeb 		dev_err(dev->mt76.dev, "Failed to get patch semaphore\n");
12456c92544dSBjoern A. Zeeb 		ret = -EAGAIN;
12466c92544dSBjoern A. Zeeb 		goto release_fw;
12476c92544dSBjoern A. Zeeb 	}
12486c92544dSBjoern A. Zeeb 
12496c92544dSBjoern A. Zeeb 	hdr = (const struct mt7615_patch_hdr *)(fw->data);
12506c92544dSBjoern A. Zeeb 
12516c92544dSBjoern A. Zeeb 	dev_info(dev->mt76.dev, "HW/SW Version: 0x%x, Build Time: %.16s\n",
12526c92544dSBjoern A. Zeeb 		 be32_to_cpu(hdr->hw_sw_ver), hdr->build_date);
12536c92544dSBjoern A. Zeeb 
12546c92544dSBjoern A. Zeeb 	len = fw->size - sizeof(*hdr);
12556c92544dSBjoern A. Zeeb 
12566c92544dSBjoern A. Zeeb 	ret = mt76_connac_mcu_init_download(&dev->mt76, addr, len,
12576c92544dSBjoern A. Zeeb 					    DL_MODE_NEED_RSP);
12586c92544dSBjoern A. Zeeb 	if (ret) {
12596c92544dSBjoern A. Zeeb 		dev_err(dev->mt76.dev, "Download request failed\n");
12606c92544dSBjoern A. Zeeb 		goto out;
12616c92544dSBjoern A. Zeeb 	}
12626c92544dSBjoern A. Zeeb 
12636c92544dSBjoern A. Zeeb 	ret = mt76_mcu_send_firmware(&dev->mt76, MCU_CMD(FW_SCATTER),
12646c92544dSBjoern A. Zeeb 				     fw->data + sizeof(*hdr), len);
12656c92544dSBjoern A. Zeeb 	if (ret) {
12666c92544dSBjoern A. Zeeb 		dev_err(dev->mt76.dev, "Failed to send firmware to device\n");
12676c92544dSBjoern A. Zeeb 		goto out;
12686c92544dSBjoern A. Zeeb 	}
12696c92544dSBjoern A. Zeeb 
12706c92544dSBjoern A. Zeeb 	ret = mt76_connac_mcu_start_patch(&dev->mt76);
12716c92544dSBjoern A. Zeeb 	if (ret)
12726c92544dSBjoern A. Zeeb 		dev_err(dev->mt76.dev, "Failed to start patch\n");
12736c92544dSBjoern A. Zeeb 
12746c92544dSBjoern A. Zeeb out:
12756c92544dSBjoern A. Zeeb 	sem = mt76_connac_mcu_patch_sem_ctrl(&dev->mt76, false);
12766c92544dSBjoern A. Zeeb 	switch (sem) {
12776c92544dSBjoern A. Zeeb 	case PATCH_REL_SEM_SUCCESS:
12786c92544dSBjoern A. Zeeb 		break;
12796c92544dSBjoern A. Zeeb 	default:
12806c92544dSBjoern A. Zeeb 		ret = -EAGAIN;
12816c92544dSBjoern A. Zeeb 		dev_err(dev->mt76.dev, "Failed to release patch semaphore\n");
12826c92544dSBjoern A. Zeeb 		break;
12836c92544dSBjoern A. Zeeb 	}
12846c92544dSBjoern A. Zeeb 
12856c92544dSBjoern A. Zeeb release_fw:
12866c92544dSBjoern A. Zeeb 	release_firmware(fw);
12876c92544dSBjoern A. Zeeb 
12886c92544dSBjoern A. Zeeb 	return ret;
12896c92544dSBjoern A. Zeeb }
12906c92544dSBjoern A. Zeeb 
12916c92544dSBjoern A. Zeeb static int
12926c92544dSBjoern A. Zeeb mt7615_mcu_send_ram_firmware(struct mt7615_dev *dev,
12936c92544dSBjoern A. Zeeb 			     const struct mt7615_fw_trailer *hdr,
12946c92544dSBjoern A. Zeeb 			     const u8 *data, bool is_cr4)
12956c92544dSBjoern A. Zeeb {
12966c92544dSBjoern A. Zeeb 	int n_region = is_cr4 ? CR4_REGION_NUM : N9_REGION_NUM;
12976c92544dSBjoern A. Zeeb 	int err, i, offset = 0;
12986c92544dSBjoern A. Zeeb 	u32 len, addr, mode;
12996c92544dSBjoern A. Zeeb 
13006c92544dSBjoern A. Zeeb 	for (i = 0; i < n_region; i++) {
13016c92544dSBjoern A. Zeeb 		mode = mt76_connac_mcu_gen_dl_mode(&dev->mt76,
13026c92544dSBjoern A. Zeeb 						   hdr[i].feature_set, is_cr4);
13036c92544dSBjoern A. Zeeb 		len = le32_to_cpu(hdr[i].len) + IMG_CRC_LEN;
13046c92544dSBjoern A. Zeeb 		addr = le32_to_cpu(hdr[i].addr);
13056c92544dSBjoern A. Zeeb 
13066c92544dSBjoern A. Zeeb 		err = mt76_connac_mcu_init_download(&dev->mt76, addr, len,
13076c92544dSBjoern A. Zeeb 						    mode);
13086c92544dSBjoern A. Zeeb 		if (err) {
13096c92544dSBjoern A. Zeeb 			dev_err(dev->mt76.dev, "Download request failed\n");
13106c92544dSBjoern A. Zeeb 			return err;
13116c92544dSBjoern A. Zeeb 		}
13126c92544dSBjoern A. Zeeb 
13136c92544dSBjoern A. Zeeb 		err = mt76_mcu_send_firmware(&dev->mt76, MCU_CMD(FW_SCATTER),
13146c92544dSBjoern A. Zeeb 					     data + offset, len);
13156c92544dSBjoern A. Zeeb 		if (err) {
13166c92544dSBjoern A. Zeeb 			dev_err(dev->mt76.dev, "Failed to send firmware to device\n");
13176c92544dSBjoern A. Zeeb 			return err;
13186c92544dSBjoern A. Zeeb 		}
13196c92544dSBjoern A. Zeeb 
13206c92544dSBjoern A. Zeeb 		offset += len;
13216c92544dSBjoern A. Zeeb 	}
13226c92544dSBjoern A. Zeeb 
13236c92544dSBjoern A. Zeeb 	return 0;
13246c92544dSBjoern A. Zeeb }
13256c92544dSBjoern A. Zeeb 
13266c92544dSBjoern A. Zeeb static int mt7615_load_n9(struct mt7615_dev *dev, const char *name)
13276c92544dSBjoern A. Zeeb {
13286c92544dSBjoern A. Zeeb 	const struct mt7615_fw_trailer *hdr;
13296c92544dSBjoern A. Zeeb 	const struct firmware *fw;
13306c92544dSBjoern A. Zeeb 	int ret;
13316c92544dSBjoern A. Zeeb 
13326c92544dSBjoern A. Zeeb 	ret = request_firmware(&fw, name, dev->mt76.dev);
13336c92544dSBjoern A. Zeeb 	if (ret)
13346c92544dSBjoern A. Zeeb 		return ret;
13356c92544dSBjoern A. Zeeb 
13366c92544dSBjoern A. Zeeb 	if (!fw || !fw->data || fw->size < N9_REGION_NUM * sizeof(*hdr)) {
13376c92544dSBjoern A. Zeeb 		dev_err(dev->mt76.dev, "Invalid firmware\n");
13386c92544dSBjoern A. Zeeb 		ret = -EINVAL;
13396c92544dSBjoern A. Zeeb 		goto out;
13406c92544dSBjoern A. Zeeb 	}
13416c92544dSBjoern A. Zeeb 
13426c92544dSBjoern A. Zeeb 	hdr = (const struct mt7615_fw_trailer *)(fw->data + fw->size -
13436c92544dSBjoern A. Zeeb 					N9_REGION_NUM * sizeof(*hdr));
13446c92544dSBjoern A. Zeeb 
13456c92544dSBjoern A. Zeeb 	dev_info(dev->mt76.dev, "N9 Firmware Version: %.10s, Build Time: %.15s\n",
13466c92544dSBjoern A. Zeeb 		 hdr->fw_ver, hdr->build_date);
13476c92544dSBjoern A. Zeeb 
13486c92544dSBjoern A. Zeeb 	ret = mt7615_mcu_send_ram_firmware(dev, hdr, fw->data, false);
13496c92544dSBjoern A. Zeeb 	if (ret)
13506c92544dSBjoern A. Zeeb 		goto out;
13516c92544dSBjoern A. Zeeb 
13526c92544dSBjoern A. Zeeb 	ret = mt76_connac_mcu_start_firmware(&dev->mt76,
13536c92544dSBjoern A. Zeeb 					     le32_to_cpu(hdr->addr),
13546c92544dSBjoern A. Zeeb 					     FW_START_OVERRIDE);
13556c92544dSBjoern A. Zeeb 	if (ret) {
13566c92544dSBjoern A. Zeeb 		dev_err(dev->mt76.dev, "Failed to start N9 firmware\n");
13576c92544dSBjoern A. Zeeb 		goto out;
13586c92544dSBjoern A. Zeeb 	}
13596c92544dSBjoern A. Zeeb 
13606c92544dSBjoern A. Zeeb 	snprintf(dev->mt76.hw->wiphy->fw_version,
13616c92544dSBjoern A. Zeeb 		 sizeof(dev->mt76.hw->wiphy->fw_version),
13626c92544dSBjoern A. Zeeb 		 "%.10s-%.15s", hdr->fw_ver, hdr->build_date);
13636c92544dSBjoern A. Zeeb 
13646c92544dSBjoern A. Zeeb 	if (!is_mt7615(&dev->mt76)) {
13656c92544dSBjoern A. Zeeb 		dev->fw_ver = MT7615_FIRMWARE_V2;
13666c92544dSBjoern A. Zeeb 		dev->mcu_ops = &sta_update_ops;
13676c92544dSBjoern A. Zeeb 	} else {
13686c92544dSBjoern A. Zeeb 		dev->fw_ver = MT7615_FIRMWARE_V1;
13696c92544dSBjoern A. Zeeb 		dev->mcu_ops = &wtbl_update_ops;
13706c92544dSBjoern A. Zeeb 	}
13716c92544dSBjoern A. Zeeb 
13726c92544dSBjoern A. Zeeb out:
13736c92544dSBjoern A. Zeeb 	release_firmware(fw);
13746c92544dSBjoern A. Zeeb 	return ret;
13756c92544dSBjoern A. Zeeb }
13766c92544dSBjoern A. Zeeb 
13776c92544dSBjoern A. Zeeb static int mt7615_load_cr4(struct mt7615_dev *dev, const char *name)
13786c92544dSBjoern A. Zeeb {
13796c92544dSBjoern A. Zeeb 	const struct mt7615_fw_trailer *hdr;
13806c92544dSBjoern A. Zeeb 	const struct firmware *fw;
13816c92544dSBjoern A. Zeeb 	int ret;
13826c92544dSBjoern A. Zeeb 
13836c92544dSBjoern A. Zeeb 	ret = request_firmware(&fw, name, dev->mt76.dev);
13846c92544dSBjoern A. Zeeb 	if (ret)
13856c92544dSBjoern A. Zeeb 		return ret;
13866c92544dSBjoern A. Zeeb 
13876c92544dSBjoern A. Zeeb 	if (!fw || !fw->data || fw->size < CR4_REGION_NUM * sizeof(*hdr)) {
13886c92544dSBjoern A. Zeeb 		dev_err(dev->mt76.dev, "Invalid firmware\n");
13896c92544dSBjoern A. Zeeb 		ret = -EINVAL;
13906c92544dSBjoern A. Zeeb 		goto out;
13916c92544dSBjoern A. Zeeb 	}
13926c92544dSBjoern A. Zeeb 
13936c92544dSBjoern A. Zeeb 	hdr = (const struct mt7615_fw_trailer *)(fw->data + fw->size -
13946c92544dSBjoern A. Zeeb 					CR4_REGION_NUM * sizeof(*hdr));
13956c92544dSBjoern A. Zeeb 
13966c92544dSBjoern A. Zeeb 	dev_info(dev->mt76.dev, "CR4 Firmware Version: %.10s, Build Time: %.15s\n",
13976c92544dSBjoern A. Zeeb 		 hdr->fw_ver, hdr->build_date);
13986c92544dSBjoern A. Zeeb 
13996c92544dSBjoern A. Zeeb 	ret = mt7615_mcu_send_ram_firmware(dev, hdr, fw->data, true);
14006c92544dSBjoern A. Zeeb 	if (ret)
14016c92544dSBjoern A. Zeeb 		goto out;
14026c92544dSBjoern A. Zeeb 
14036c92544dSBjoern A. Zeeb 	ret = mt76_connac_mcu_start_firmware(&dev->mt76, 0,
14046c92544dSBjoern A. Zeeb 					     FW_START_WORKING_PDA_CR4);
14056c92544dSBjoern A. Zeeb 	if (ret) {
14066c92544dSBjoern A. Zeeb 		dev_err(dev->mt76.dev, "Failed to start CR4 firmware\n");
14076c92544dSBjoern A. Zeeb 		goto out;
14086c92544dSBjoern A. Zeeb 	}
14096c92544dSBjoern A. Zeeb 
14106c92544dSBjoern A. Zeeb out:
14116c92544dSBjoern A. Zeeb 	release_firmware(fw);
14126c92544dSBjoern A. Zeeb 
14136c92544dSBjoern A. Zeeb 	return ret;
14146c92544dSBjoern A. Zeeb }
14156c92544dSBjoern A. Zeeb 
14166c92544dSBjoern A. Zeeb static int mt7615_load_ram(struct mt7615_dev *dev)
14176c92544dSBjoern A. Zeeb {
14186c92544dSBjoern A. Zeeb 	int ret;
14196c92544dSBjoern A. Zeeb 
14206c92544dSBjoern A. Zeeb 	ret = mt7615_load_n9(dev, MT7615_FIRMWARE_N9);
14216c92544dSBjoern A. Zeeb 	if (ret)
14226c92544dSBjoern A. Zeeb 		return ret;
14236c92544dSBjoern A. Zeeb 
14246c92544dSBjoern A. Zeeb 	return mt7615_load_cr4(dev, MT7615_FIRMWARE_CR4);
14256c92544dSBjoern A. Zeeb }
14266c92544dSBjoern A. Zeeb 
14276c92544dSBjoern A. Zeeb static int mt7615_load_firmware(struct mt7615_dev *dev)
14286c92544dSBjoern A. Zeeb {
14296c92544dSBjoern A. Zeeb 	int ret;
14306c92544dSBjoern A. Zeeb 	u32 val;
14316c92544dSBjoern A. Zeeb 
14326c92544dSBjoern A. Zeeb 	val = mt76_get_field(dev, MT_TOP_MISC2, MT_TOP_MISC2_FW_STATE);
14336c92544dSBjoern A. Zeeb 
14346c92544dSBjoern A. Zeeb 	if (val != FW_STATE_FW_DOWNLOAD) {
14356c92544dSBjoern A. Zeeb 		dev_err(dev->mt76.dev, "Firmware is not ready for download\n");
14366c92544dSBjoern A. Zeeb 		return -EIO;
14376c92544dSBjoern A. Zeeb 	}
14386c92544dSBjoern A. Zeeb 
14396c92544dSBjoern A. Zeeb 	ret = mt7615_load_patch(dev, MT7615_PATCH_ADDRESS, MT7615_ROM_PATCH);
14406c92544dSBjoern A. Zeeb 	if (ret)
14416c92544dSBjoern A. Zeeb 		return ret;
14426c92544dSBjoern A. Zeeb 
14436c92544dSBjoern A. Zeeb 	ret = mt7615_load_ram(dev);
14446c92544dSBjoern A. Zeeb 	if (ret)
14456c92544dSBjoern A. Zeeb 		return ret;
14466c92544dSBjoern A. Zeeb 
14476c92544dSBjoern A. Zeeb 	if (!mt76_poll_msec(dev, MT_TOP_MISC2, MT_TOP_MISC2_FW_STATE,
14486c92544dSBjoern A. Zeeb 			    FIELD_PREP(MT_TOP_MISC2_FW_STATE,
14496c92544dSBjoern A. Zeeb 				       FW_STATE_RDY), 500)) {
14506c92544dSBjoern A. Zeeb 		dev_err(dev->mt76.dev, "Timeout for initializing firmware\n");
14516c92544dSBjoern A. Zeeb 		return -EIO;
14526c92544dSBjoern A. Zeeb 	}
14536c92544dSBjoern A. Zeeb 
14546c92544dSBjoern A. Zeeb 	return 0;
14556c92544dSBjoern A. Zeeb }
14566c92544dSBjoern A. Zeeb 
14576c92544dSBjoern A. Zeeb static int mt7622_load_firmware(struct mt7615_dev *dev)
14586c92544dSBjoern A. Zeeb {
14596c92544dSBjoern A. Zeeb 	int ret;
14606c92544dSBjoern A. Zeeb 	u32 val;
14616c92544dSBjoern A. Zeeb 
14626c92544dSBjoern A. Zeeb 	mt76_set(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_BYPASS_TX_SCH);
14636c92544dSBjoern A. Zeeb 
14646c92544dSBjoern A. Zeeb 	val = mt76_get_field(dev, MT_TOP_OFF_RSV, MT_TOP_OFF_RSV_FW_STATE);
14656c92544dSBjoern A. Zeeb 	if (val != FW_STATE_FW_DOWNLOAD) {
14666c92544dSBjoern A. Zeeb 		dev_err(dev->mt76.dev, "Firmware is not ready for download\n");
14676c92544dSBjoern A. Zeeb 		return -EIO;
14686c92544dSBjoern A. Zeeb 	}
14696c92544dSBjoern A. Zeeb 
14706c92544dSBjoern A. Zeeb 	ret = mt7615_load_patch(dev, MT7622_PATCH_ADDRESS, MT7622_ROM_PATCH);
14716c92544dSBjoern A. Zeeb 	if (ret)
14726c92544dSBjoern A. Zeeb 		return ret;
14736c92544dSBjoern A. Zeeb 
14746c92544dSBjoern A. Zeeb 	ret = mt7615_load_n9(dev, MT7622_FIRMWARE_N9);
14756c92544dSBjoern A. Zeeb 	if (ret)
14766c92544dSBjoern A. Zeeb 		return ret;
14776c92544dSBjoern A. Zeeb 
14786c92544dSBjoern A. Zeeb 	if (!mt76_poll_msec(dev, MT_TOP_OFF_RSV, MT_TOP_OFF_RSV_FW_STATE,
14796c92544dSBjoern A. Zeeb 			    FIELD_PREP(MT_TOP_OFF_RSV_FW_STATE,
14806c92544dSBjoern A. Zeeb 				       FW_STATE_NORMAL_TRX), 1500)) {
14816c92544dSBjoern A. Zeeb 		dev_err(dev->mt76.dev, "Timeout for initializing firmware\n");
14826c92544dSBjoern A. Zeeb 		return -EIO;
14836c92544dSBjoern A. Zeeb 	}
14846c92544dSBjoern A. Zeeb 
14856c92544dSBjoern A. Zeeb 	mt76_clear(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_BYPASS_TX_SCH);
14866c92544dSBjoern A. Zeeb 
14876c92544dSBjoern A. Zeeb 	return 0;
14886c92544dSBjoern A. Zeeb }
14896c92544dSBjoern A. Zeeb 
14906c92544dSBjoern A. Zeeb int mt7615_mcu_fw_log_2_host(struct mt7615_dev *dev, u8 ctrl)
14916c92544dSBjoern A. Zeeb {
14926c92544dSBjoern A. Zeeb 	struct {
14936c92544dSBjoern A. Zeeb 		u8 ctrl_val;
14946c92544dSBjoern A. Zeeb 		u8 pad[3];
14956c92544dSBjoern A. Zeeb 	} data = {
14966c92544dSBjoern A. Zeeb 		.ctrl_val = ctrl
14976c92544dSBjoern A. Zeeb 	};
14986c92544dSBjoern A. Zeeb 
14996c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(FW_LOG_2_HOST),
15006c92544dSBjoern A. Zeeb 				 &data, sizeof(data), true);
15016c92544dSBjoern A. Zeeb }
15026c92544dSBjoern A. Zeeb 
15036c92544dSBjoern A. Zeeb static int mt7615_mcu_cal_cache_apply(struct mt7615_dev *dev)
15046c92544dSBjoern A. Zeeb {
15056c92544dSBjoern A. Zeeb 	struct {
15066c92544dSBjoern A. Zeeb 		bool cache_enable;
15076c92544dSBjoern A. Zeeb 		u8 pad[3];
15086c92544dSBjoern A. Zeeb 	} data = {
15096c92544dSBjoern A. Zeeb 		.cache_enable = true
15106c92544dSBjoern A. Zeeb 	};
15116c92544dSBjoern A. Zeeb 
15126c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(CAL_CACHE), &data,
15136c92544dSBjoern A. Zeeb 				 sizeof(data), false);
15146c92544dSBjoern A. Zeeb }
15156c92544dSBjoern A. Zeeb 
15166c92544dSBjoern A. Zeeb static int mt7663_load_n9(struct mt7615_dev *dev, const char *name)
15176c92544dSBjoern A. Zeeb {
15186c92544dSBjoern A. Zeeb 	u32 offset = 0, override_addr = 0, flag = FW_START_DLYCAL;
15196c92544dSBjoern A. Zeeb 	const struct mt76_connac2_fw_trailer *hdr;
15206c92544dSBjoern A. Zeeb 	const struct mt7663_fw_buf *buf;
15216c92544dSBjoern A. Zeeb 	const struct firmware *fw;
15226c92544dSBjoern A. Zeeb 	const u8 *base_addr;
15236c92544dSBjoern A. Zeeb 	int i, ret;
15246c92544dSBjoern A. Zeeb 
15256c92544dSBjoern A. Zeeb 	ret = request_firmware(&fw, name, dev->mt76.dev);
15266c92544dSBjoern A. Zeeb 	if (ret)
15276c92544dSBjoern A. Zeeb 		return ret;
15286c92544dSBjoern A. Zeeb 
15296c92544dSBjoern A. Zeeb 	if (!fw || !fw->data || fw->size < FW_V3_COMMON_TAILER_SIZE) {
15306c92544dSBjoern A. Zeeb 		dev_err(dev->mt76.dev, "Invalid firmware\n");
15316c92544dSBjoern A. Zeeb 		ret = -EINVAL;
15326c92544dSBjoern A. Zeeb 		goto out;
15336c92544dSBjoern A. Zeeb 	}
15346c92544dSBjoern A. Zeeb 
15356c92544dSBjoern A. Zeeb 	hdr = (const void *)(fw->data + fw->size - FW_V3_COMMON_TAILER_SIZE);
15366c92544dSBjoern A. Zeeb 	dev_info(dev->mt76.dev, "N9 Firmware Version: %.10s, Build Time: %.15s\n",
15376c92544dSBjoern A. Zeeb 		 hdr->fw_ver, hdr->build_date);
15386c92544dSBjoern A. Zeeb 	dev_info(dev->mt76.dev, "Region number: 0x%x\n", hdr->n_region);
15396c92544dSBjoern A. Zeeb 
15406c92544dSBjoern A. Zeeb 	base_addr = fw->data + fw->size - FW_V3_COMMON_TAILER_SIZE;
15416c92544dSBjoern A. Zeeb 	for (i = 0; i < hdr->n_region; i++) {
15426c92544dSBjoern A. Zeeb 		u32 shift = (hdr->n_region - i) * FW_V3_REGION_TAILER_SIZE;
15436c92544dSBjoern A. Zeeb 		u32 len, addr, mode;
15446c92544dSBjoern A. Zeeb 
15456c92544dSBjoern A. Zeeb 		dev_info(dev->mt76.dev, "Parsing tailer Region: %d\n", i);
15466c92544dSBjoern A. Zeeb 
15476c92544dSBjoern A. Zeeb 		buf = (const struct mt7663_fw_buf *)(base_addr - shift);
15486c92544dSBjoern A. Zeeb 		mode = mt76_connac_mcu_gen_dl_mode(&dev->mt76,
15496c92544dSBjoern A. Zeeb 						   buf->feature_set, false);
15506c92544dSBjoern A. Zeeb 		addr = le32_to_cpu(buf->img_dest_addr);
15516c92544dSBjoern A. Zeeb 		len = le32_to_cpu(buf->img_size);
15526c92544dSBjoern A. Zeeb 
15536c92544dSBjoern A. Zeeb 		ret = mt76_connac_mcu_init_download(&dev->mt76, addr, len,
15546c92544dSBjoern A. Zeeb 						    mode);
15556c92544dSBjoern A. Zeeb 		if (ret) {
15566c92544dSBjoern A. Zeeb 			dev_err(dev->mt76.dev, "Download request failed\n");
15576c92544dSBjoern A. Zeeb 			goto out;
15586c92544dSBjoern A. Zeeb 		}
15596c92544dSBjoern A. Zeeb 
15606c92544dSBjoern A. Zeeb 		ret = mt76_mcu_send_firmware(&dev->mt76, MCU_CMD(FW_SCATTER),
15616c92544dSBjoern A. Zeeb 					     fw->data + offset, len);
15626c92544dSBjoern A. Zeeb 		if (ret) {
15636c92544dSBjoern A. Zeeb 			dev_err(dev->mt76.dev, "Failed to send firmware\n");
15646c92544dSBjoern A. Zeeb 			goto out;
15656c92544dSBjoern A. Zeeb 		}
15666c92544dSBjoern A. Zeeb 
15676c92544dSBjoern A. Zeeb 		offset += le32_to_cpu(buf->img_size);
15686c92544dSBjoern A. Zeeb 		if (buf->feature_set & DL_MODE_VALID_RAM_ENTRY) {
15696c92544dSBjoern A. Zeeb 			override_addr = le32_to_cpu(buf->img_dest_addr);
15706c92544dSBjoern A. Zeeb 			dev_info(dev->mt76.dev, "Region %d, override_addr = 0x%08x\n",
15716c92544dSBjoern A. Zeeb 				 i, override_addr);
15726c92544dSBjoern A. Zeeb 		}
15736c92544dSBjoern A. Zeeb 	}
15746c92544dSBjoern A. Zeeb 
15756c92544dSBjoern A. Zeeb 	if (override_addr)
15766c92544dSBjoern A. Zeeb 		flag |= FW_START_OVERRIDE;
15776c92544dSBjoern A. Zeeb 
15786c92544dSBjoern A. Zeeb 	dev_info(dev->mt76.dev, "override_addr = 0x%08x, option = %d\n",
15796c92544dSBjoern A. Zeeb 		 override_addr, flag);
15806c92544dSBjoern A. Zeeb 
15816c92544dSBjoern A. Zeeb 	ret = mt76_connac_mcu_start_firmware(&dev->mt76, override_addr, flag);
15826c92544dSBjoern A. Zeeb 	if (ret) {
15836c92544dSBjoern A. Zeeb 		dev_err(dev->mt76.dev, "Failed to start N9 firmware\n");
15846c92544dSBjoern A. Zeeb 		goto out;
15856c92544dSBjoern A. Zeeb 	}
15866c92544dSBjoern A. Zeeb 
15876c92544dSBjoern A. Zeeb 	snprintf(dev->mt76.hw->wiphy->fw_version,
15886c92544dSBjoern A. Zeeb 		 sizeof(dev->mt76.hw->wiphy->fw_version),
15896c92544dSBjoern A. Zeeb 		 "%.10s-%.15s", hdr->fw_ver, hdr->build_date);
15906c92544dSBjoern A. Zeeb 
15916c92544dSBjoern A. Zeeb out:
15926c92544dSBjoern A. Zeeb 	release_firmware(fw);
15936c92544dSBjoern A. Zeeb 
15946c92544dSBjoern A. Zeeb 	return ret;
15956c92544dSBjoern A. Zeeb }
15966c92544dSBjoern A. Zeeb 
15976c92544dSBjoern A. Zeeb static int
15986c92544dSBjoern A. Zeeb mt7663_load_rom_patch(struct mt7615_dev *dev, const char **n9_firmware)
15996c92544dSBjoern A. Zeeb {
16006c92544dSBjoern A. Zeeb 	const char *selected_rom, *secondary_rom = MT7663_ROM_PATCH;
16016c92544dSBjoern A. Zeeb 	const char *primary_rom = MT7663_OFFLOAD_ROM_PATCH;
16026c92544dSBjoern A. Zeeb 	int ret;
16036c92544dSBjoern A. Zeeb 
16046c92544dSBjoern A. Zeeb 	if (!prefer_offload_fw) {
16056c92544dSBjoern A. Zeeb 		secondary_rom = MT7663_OFFLOAD_ROM_PATCH;
16066c92544dSBjoern A. Zeeb 		primary_rom = MT7663_ROM_PATCH;
16076c92544dSBjoern A. Zeeb 	}
16086c92544dSBjoern A. Zeeb 	selected_rom = primary_rom;
16096c92544dSBjoern A. Zeeb 
16106c92544dSBjoern A. Zeeb 	ret = mt7615_load_patch(dev, MT7663_PATCH_ADDRESS, primary_rom);
16116c92544dSBjoern A. Zeeb 	if (ret) {
16126c92544dSBjoern A. Zeeb 		dev_info(dev->mt76.dev, "%s not found, switching to %s",
16136c92544dSBjoern A. Zeeb 			 primary_rom, secondary_rom);
16146c92544dSBjoern A. Zeeb 		ret = mt7615_load_patch(dev, MT7663_PATCH_ADDRESS,
16156c92544dSBjoern A. Zeeb 					secondary_rom);
16166c92544dSBjoern A. Zeeb 		if (ret) {
16176c92544dSBjoern A. Zeeb 			dev_err(dev->mt76.dev, "failed to load %s",
16186c92544dSBjoern A. Zeeb 				secondary_rom);
16196c92544dSBjoern A. Zeeb 			return ret;
16206c92544dSBjoern A. Zeeb 		}
16216c92544dSBjoern A. Zeeb 		selected_rom = secondary_rom;
16226c92544dSBjoern A. Zeeb 	}
16236c92544dSBjoern A. Zeeb 
16246c92544dSBjoern A. Zeeb 	if (!strcmp(selected_rom, MT7663_OFFLOAD_ROM_PATCH)) {
16256c92544dSBjoern A. Zeeb 		*n9_firmware = MT7663_OFFLOAD_FIRMWARE_N9;
16266c92544dSBjoern A. Zeeb 		dev->fw_ver = MT7615_FIRMWARE_V3;
16276c92544dSBjoern A. Zeeb 		dev->mcu_ops = &uni_update_ops;
16286c92544dSBjoern A. Zeeb 	} else {
16296c92544dSBjoern A. Zeeb 		*n9_firmware = MT7663_FIRMWARE_N9;
16306c92544dSBjoern A. Zeeb 		dev->fw_ver = MT7615_FIRMWARE_V2;
16316c92544dSBjoern A. Zeeb 		dev->mcu_ops = &sta_update_ops;
16326c92544dSBjoern A. Zeeb 	}
16336c92544dSBjoern A. Zeeb 
16346c92544dSBjoern A. Zeeb 	return 0;
16356c92544dSBjoern A. Zeeb }
16366c92544dSBjoern A. Zeeb 
16376c92544dSBjoern A. Zeeb int __mt7663_load_firmware(struct mt7615_dev *dev)
16386c92544dSBjoern A. Zeeb {
16396c92544dSBjoern A. Zeeb 	const char *n9_firmware;
16406c92544dSBjoern A. Zeeb 	int ret;
16416c92544dSBjoern A. Zeeb 
16426c92544dSBjoern A. Zeeb 	ret = mt76_get_field(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY);
16436c92544dSBjoern A. Zeeb 	if (ret) {
16446c92544dSBjoern A. Zeeb 		dev_dbg(dev->mt76.dev, "Firmware is already download\n");
16456c92544dSBjoern A. Zeeb 		return -EIO;
16466c92544dSBjoern A. Zeeb 	}
16476c92544dSBjoern A. Zeeb 
16486c92544dSBjoern A. Zeeb 	ret = mt7663_load_rom_patch(dev, &n9_firmware);
16496c92544dSBjoern A. Zeeb 	if (ret)
16506c92544dSBjoern A. Zeeb 		return ret;
16516c92544dSBjoern A. Zeeb 
16526c92544dSBjoern A. Zeeb 	ret = mt7663_load_n9(dev, n9_firmware);
16536c92544dSBjoern A. Zeeb 	if (ret)
16546c92544dSBjoern A. Zeeb 		return ret;
16556c92544dSBjoern A. Zeeb 
16566c92544dSBjoern A. Zeeb 	if (!mt76_poll_msec(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY,
16576c92544dSBjoern A. Zeeb 			    MT_TOP_MISC2_FW_N9_RDY, 1500)) {
16586c92544dSBjoern A. Zeeb 		ret = mt76_get_field(dev, MT_CONN_ON_MISC,
16596c92544dSBjoern A. Zeeb 				     MT7663_TOP_MISC2_FW_STATE);
16606c92544dSBjoern A. Zeeb 		dev_err(dev->mt76.dev, "Timeout for initializing firmware\n");
16616c92544dSBjoern A. Zeeb 		return -EIO;
16626c92544dSBjoern A. Zeeb 	}
16636c92544dSBjoern A. Zeeb 
16646c92544dSBjoern A. Zeeb #ifdef CONFIG_PM
16656c92544dSBjoern A. Zeeb 	if (mt7615_firmware_offload(dev))
16666c92544dSBjoern A. Zeeb 		dev->mt76.hw->wiphy->wowlan = &mt76_connac_wowlan_support;
16676c92544dSBjoern A. Zeeb #endif /* CONFIG_PM */
16686c92544dSBjoern A. Zeeb 
16696c92544dSBjoern A. Zeeb 	dev_dbg(dev->mt76.dev, "Firmware init done\n");
16706c92544dSBjoern A. Zeeb 
16716c92544dSBjoern A. Zeeb 	return 0;
16726c92544dSBjoern A. Zeeb }
16736c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(__mt7663_load_firmware);
16746c92544dSBjoern A. Zeeb 
16756c92544dSBjoern A. Zeeb static int mt7663_load_firmware(struct mt7615_dev *dev)
16766c92544dSBjoern A. Zeeb {
16776c92544dSBjoern A. Zeeb 	int ret;
16786c92544dSBjoern A. Zeeb 
16796c92544dSBjoern A. Zeeb 	mt76_set(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_BYPASS_TX_SCH);
16806c92544dSBjoern A. Zeeb 
16816c92544dSBjoern A. Zeeb 	ret = __mt7663_load_firmware(dev);
16826c92544dSBjoern A. Zeeb 	if (ret)
16836c92544dSBjoern A. Zeeb 		return ret;
16846c92544dSBjoern A. Zeeb 
16856c92544dSBjoern A. Zeeb 	mt76_clear(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_BYPASS_TX_SCH);
16866c92544dSBjoern A. Zeeb 
16876c92544dSBjoern A. Zeeb 	return 0;
16886c92544dSBjoern A. Zeeb }
16896c92544dSBjoern A. Zeeb 
16906c92544dSBjoern A. Zeeb int mt7615_mcu_init(struct mt7615_dev *dev)
16916c92544dSBjoern A. Zeeb {
16926c92544dSBjoern A. Zeeb 	static const struct mt76_mcu_ops mt7615_mcu_ops = {
16936c92544dSBjoern A. Zeeb 		.headroom = sizeof(struct mt7615_mcu_txd),
16946c92544dSBjoern A. Zeeb 		.mcu_skb_send_msg = mt7615_mcu_send_message,
16956c92544dSBjoern A. Zeeb 		.mcu_parse_response = mt7615_mcu_parse_response,
16966c92544dSBjoern A. Zeeb 	};
16976c92544dSBjoern A. Zeeb 	int ret;
16986c92544dSBjoern A. Zeeb 
16996c92544dSBjoern A. Zeeb 	dev->mt76.mcu_ops = &mt7615_mcu_ops,
17006c92544dSBjoern A. Zeeb 
17016c92544dSBjoern A. Zeeb 	ret = mt7615_mcu_drv_pmctrl(dev);
17026c92544dSBjoern A. Zeeb 	if (ret)
17036c92544dSBjoern A. Zeeb 		return ret;
17046c92544dSBjoern A. Zeeb 
17056c92544dSBjoern A. Zeeb 	switch (mt76_chip(&dev->mt76)) {
17066c92544dSBjoern A. Zeeb 	case 0x7622:
17076c92544dSBjoern A. Zeeb 		ret = mt7622_load_firmware(dev);
17086c92544dSBjoern A. Zeeb 		break;
17096c92544dSBjoern A. Zeeb 	case 0x7663:
17106c92544dSBjoern A. Zeeb 		ret = mt7663_load_firmware(dev);
17116c92544dSBjoern A. Zeeb 		break;
17126c92544dSBjoern A. Zeeb 	default:
17136c92544dSBjoern A. Zeeb 		ret = mt7615_load_firmware(dev);
17146c92544dSBjoern A. Zeeb 		break;
17156c92544dSBjoern A. Zeeb 	}
17166c92544dSBjoern A. Zeeb 	if (ret)
17176c92544dSBjoern A. Zeeb 		return ret;
17186c92544dSBjoern A. Zeeb 
17196c92544dSBjoern A. Zeeb 	mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_FWDL], false);
17206c92544dSBjoern A. Zeeb 	dev_dbg(dev->mt76.dev, "Firmware init done\n");
17216c92544dSBjoern A. Zeeb 	set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);
17226c92544dSBjoern A. Zeeb 
17236c92544dSBjoern A. Zeeb 	if (dev->dbdc_support) {
17246c92544dSBjoern A. Zeeb 		ret = mt7615_mcu_cal_cache_apply(dev);
17256c92544dSBjoern A. Zeeb 		if (ret)
17266c92544dSBjoern A. Zeeb 			return ret;
17276c92544dSBjoern A. Zeeb 	}
17286c92544dSBjoern A. Zeeb 
17296c92544dSBjoern A. Zeeb 	return mt7615_mcu_fw_log_2_host(dev, 0);
17306c92544dSBjoern A. Zeeb }
17316c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt7615_mcu_init);
17326c92544dSBjoern A. Zeeb 
17336c92544dSBjoern A. Zeeb void mt7615_mcu_exit(struct mt7615_dev *dev)
17346c92544dSBjoern A. Zeeb {
1735*cbb3ec25SBjoern A. Zeeb 	mt7615_mcu_restart(&dev->mt76);
17366c92544dSBjoern A. Zeeb 	mt7615_mcu_set_fw_ctrl(dev);
17376c92544dSBjoern A. Zeeb 	skb_queue_purge(&dev->mt76.mcu.res_q);
17386c92544dSBjoern A. Zeeb }
17396c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt7615_mcu_exit);
17406c92544dSBjoern A. Zeeb 
17416c92544dSBjoern A. Zeeb int mt7615_mcu_set_eeprom(struct mt7615_dev *dev)
17426c92544dSBjoern A. Zeeb {
17436c92544dSBjoern A. Zeeb 	struct {
17446c92544dSBjoern A. Zeeb 		u8 buffer_mode;
17456c92544dSBjoern A. Zeeb 		u8 content_format;
17466c92544dSBjoern A. Zeeb 		__le16 len;
17476c92544dSBjoern A. Zeeb 	} __packed req_hdr = {
17486c92544dSBjoern A. Zeeb 		.buffer_mode = 1,
17496c92544dSBjoern A. Zeeb 	};
17506c92544dSBjoern A. Zeeb 	u8 *eep = (u8 *)dev->mt76.eeprom.data;
17516c92544dSBjoern A. Zeeb 	struct sk_buff *skb;
17526c92544dSBjoern A. Zeeb 	int eep_len, offset;
17536c92544dSBjoern A. Zeeb 
17546c92544dSBjoern A. Zeeb 	switch (mt76_chip(&dev->mt76)) {
17556c92544dSBjoern A. Zeeb 	case 0x7622:
17566c92544dSBjoern A. Zeeb 		eep_len = MT7622_EE_MAX - MT_EE_NIC_CONF_0;
17576c92544dSBjoern A. Zeeb 		offset = MT_EE_NIC_CONF_0;
17586c92544dSBjoern A. Zeeb 		break;
17596c92544dSBjoern A. Zeeb 	case 0x7663:
17606c92544dSBjoern A. Zeeb 		eep_len = MT7663_EE_MAX - MT_EE_CHIP_ID;
17616c92544dSBjoern A. Zeeb 		req_hdr.content_format = 1;
17626c92544dSBjoern A. Zeeb 		offset = MT_EE_CHIP_ID;
17636c92544dSBjoern A. Zeeb 		break;
17646c92544dSBjoern A. Zeeb 	default:
17656c92544dSBjoern A. Zeeb 		eep_len = MT7615_EE_MAX - MT_EE_NIC_CONF_0;
17666c92544dSBjoern A. Zeeb 		offset = MT_EE_NIC_CONF_0;
17676c92544dSBjoern A. Zeeb 		break;
17686c92544dSBjoern A. Zeeb 	}
17696c92544dSBjoern A. Zeeb 
17706c92544dSBjoern A. Zeeb 	req_hdr.len = cpu_to_le16(eep_len);
17716c92544dSBjoern A. Zeeb 
17726c92544dSBjoern A. Zeeb 	skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, sizeof(req_hdr) + eep_len);
17736c92544dSBjoern A. Zeeb 	if (!skb)
17746c92544dSBjoern A. Zeeb 		return -ENOMEM;
17756c92544dSBjoern A. Zeeb 
17766c92544dSBjoern A. Zeeb 	skb_put_data(skb, &req_hdr, sizeof(req_hdr));
17776c92544dSBjoern A. Zeeb 	skb_put_data(skb, eep + offset, eep_len);
17786c92544dSBjoern A. Zeeb 
17796c92544dSBjoern A. Zeeb 	return mt76_mcu_skb_send_msg(&dev->mt76, skb,
17806c92544dSBjoern A. Zeeb 				     MCU_EXT_CMD(EFUSE_BUFFER_MODE), true);
17816c92544dSBjoern A. Zeeb }
17826c92544dSBjoern A. Zeeb 
17836c92544dSBjoern A. Zeeb int mt7615_mcu_set_wmm(struct mt7615_dev *dev, u8 queue,
17846c92544dSBjoern A. Zeeb 		       const struct ieee80211_tx_queue_params *params)
17856c92544dSBjoern A. Zeeb {
17866c92544dSBjoern A. Zeeb #define WMM_AIFS_SET	BIT(0)
17876c92544dSBjoern A. Zeeb #define WMM_CW_MIN_SET	BIT(1)
17886c92544dSBjoern A. Zeeb #define WMM_CW_MAX_SET	BIT(2)
17896c92544dSBjoern A. Zeeb #define WMM_TXOP_SET	BIT(3)
17906c92544dSBjoern A. Zeeb #define WMM_PARAM_SET	(WMM_AIFS_SET | WMM_CW_MIN_SET | \
17916c92544dSBjoern A. Zeeb 			 WMM_CW_MAX_SET | WMM_TXOP_SET)
17926c92544dSBjoern A. Zeeb 	struct req_data {
17936c92544dSBjoern A. Zeeb 		u8 number;
17946c92544dSBjoern A. Zeeb 		u8 rsv[3];
17956c92544dSBjoern A. Zeeb 		u8 queue;
17966c92544dSBjoern A. Zeeb 		u8 valid;
17976c92544dSBjoern A. Zeeb 		u8 aifs;
17986c92544dSBjoern A. Zeeb 		u8 cw_min;
17996c92544dSBjoern A. Zeeb 		__le16 cw_max;
18006c92544dSBjoern A. Zeeb 		__le16 txop;
18016c92544dSBjoern A. Zeeb 	} __packed req = {
18026c92544dSBjoern A. Zeeb 		.number = 1,
18036c92544dSBjoern A. Zeeb 		.queue = queue,
18046c92544dSBjoern A. Zeeb 		.valid = WMM_PARAM_SET,
18056c92544dSBjoern A. Zeeb 		.aifs = params->aifs,
18066c92544dSBjoern A. Zeeb 		.cw_min = 5,
18076c92544dSBjoern A. Zeeb 		.cw_max = cpu_to_le16(10),
18086c92544dSBjoern A. Zeeb 		.txop = cpu_to_le16(params->txop),
18096c92544dSBjoern A. Zeeb 	};
18106c92544dSBjoern A. Zeeb 
18116c92544dSBjoern A. Zeeb 	if (params->cw_min)
18126c92544dSBjoern A. Zeeb 		req.cw_min = fls(params->cw_min);
18136c92544dSBjoern A. Zeeb 	if (params->cw_max)
18146c92544dSBjoern A. Zeeb 		req.cw_max = cpu_to_le16(fls(params->cw_max));
18156c92544dSBjoern A. Zeeb 
18166c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(EDCA_UPDATE),
18176c92544dSBjoern A. Zeeb 				 &req, sizeof(req), true);
18186c92544dSBjoern A. Zeeb }
18196c92544dSBjoern A. Zeeb 
18206c92544dSBjoern A. Zeeb int mt7615_mcu_set_dbdc(struct mt7615_dev *dev)
18216c92544dSBjoern A. Zeeb {
18226c92544dSBjoern A. Zeeb 	struct mt7615_phy *ext_phy = mt7615_ext_phy(dev);
18236c92544dSBjoern A. Zeeb 	struct dbdc_entry {
18246c92544dSBjoern A. Zeeb 		u8 type;
18256c92544dSBjoern A. Zeeb 		u8 index;
18266c92544dSBjoern A. Zeeb 		u8 band;
18276c92544dSBjoern A. Zeeb 		u8 _rsv;
18286c92544dSBjoern A. Zeeb 	};
18296c92544dSBjoern A. Zeeb 	struct {
18306c92544dSBjoern A. Zeeb 		u8 enable;
18316c92544dSBjoern A. Zeeb 		u8 num;
18326c92544dSBjoern A. Zeeb 		u8 _rsv[2];
18336c92544dSBjoern A. Zeeb 		struct dbdc_entry entry[64];
18346c92544dSBjoern A. Zeeb 	} req = {
18356c92544dSBjoern A. Zeeb 		.enable = !!ext_phy,
18366c92544dSBjoern A. Zeeb 	};
18376c92544dSBjoern A. Zeeb 	int i;
18386c92544dSBjoern A. Zeeb 
18396c92544dSBjoern A. Zeeb 	if (!ext_phy)
18406c92544dSBjoern A. Zeeb 		goto out;
18416c92544dSBjoern A. Zeeb 
18426c92544dSBjoern A. Zeeb #define ADD_DBDC_ENTRY(_type, _idx, _band)		\
18436c92544dSBjoern A. Zeeb 	do { \
18446c92544dSBjoern A. Zeeb 		req.entry[req.num].type = _type;		\
18456c92544dSBjoern A. Zeeb 		req.entry[req.num].index = _idx;		\
18466c92544dSBjoern A. Zeeb 		req.entry[req.num++].band = _band;		\
18476c92544dSBjoern A. Zeeb 	} while (0)
18486c92544dSBjoern A. Zeeb 
18496c92544dSBjoern A. Zeeb 	for (i = 0; i < 4; i++) {
18506c92544dSBjoern A. Zeeb 		bool band = !!(ext_phy->omac_mask & BIT_ULL(i));
18516c92544dSBjoern A. Zeeb 
18526c92544dSBjoern A. Zeeb 		ADD_DBDC_ENTRY(DBDC_TYPE_BSS, i, band);
18536c92544dSBjoern A. Zeeb 	}
18546c92544dSBjoern A. Zeeb 
18556c92544dSBjoern A. Zeeb 	for (i = 0; i < 14; i++) {
18566c92544dSBjoern A. Zeeb 		bool band = !!(ext_phy->omac_mask & BIT_ULL(0x11 + i));
18576c92544dSBjoern A. Zeeb 
18586c92544dSBjoern A. Zeeb 		ADD_DBDC_ENTRY(DBDC_TYPE_MBSS, i, band);
18596c92544dSBjoern A. Zeeb 	}
18606c92544dSBjoern A. Zeeb 
18616c92544dSBjoern A. Zeeb 	ADD_DBDC_ENTRY(DBDC_TYPE_MU, 0, 1);
18626c92544dSBjoern A. Zeeb 
18636c92544dSBjoern A. Zeeb 	for (i = 0; i < 3; i++)
18646c92544dSBjoern A. Zeeb 		ADD_DBDC_ENTRY(DBDC_TYPE_BF, i, 1);
18656c92544dSBjoern A. Zeeb 
18666c92544dSBjoern A. Zeeb 	ADD_DBDC_ENTRY(DBDC_TYPE_WMM, 0, 0);
18676c92544dSBjoern A. Zeeb 	ADD_DBDC_ENTRY(DBDC_TYPE_WMM, 1, 0);
18686c92544dSBjoern A. Zeeb 	ADD_DBDC_ENTRY(DBDC_TYPE_WMM, 2, 1);
18696c92544dSBjoern A. Zeeb 	ADD_DBDC_ENTRY(DBDC_TYPE_WMM, 3, 1);
18706c92544dSBjoern A. Zeeb 
18716c92544dSBjoern A. Zeeb 	ADD_DBDC_ENTRY(DBDC_TYPE_MGMT, 0, 0);
18726c92544dSBjoern A. Zeeb 	ADD_DBDC_ENTRY(DBDC_TYPE_MGMT, 1, 1);
18736c92544dSBjoern A. Zeeb 
18746c92544dSBjoern A. Zeeb out:
18756c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(DBDC_CTRL), &req,
18766c92544dSBjoern A. Zeeb 				 sizeof(req), true);
18776c92544dSBjoern A. Zeeb }
18786c92544dSBjoern A. Zeeb 
18796c92544dSBjoern A. Zeeb int mt7615_mcu_del_wtbl_all(struct mt7615_dev *dev)
18806c92544dSBjoern A. Zeeb {
18816c92544dSBjoern A. Zeeb 	struct wtbl_req_hdr req = {
18826c92544dSBjoern A. Zeeb 		.operation = WTBL_RESET_ALL,
18836c92544dSBjoern A. Zeeb 	};
18846c92544dSBjoern A. Zeeb 
18856c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(WTBL_UPDATE),
18866c92544dSBjoern A. Zeeb 				 &req, sizeof(req), true);
18876c92544dSBjoern A. Zeeb }
18886c92544dSBjoern A. Zeeb 
18896c92544dSBjoern A. Zeeb int mt7615_mcu_set_fcc5_lpn(struct mt7615_dev *dev, int val)
18906c92544dSBjoern A. Zeeb {
18916c92544dSBjoern A. Zeeb 	struct {
18926c92544dSBjoern A. Zeeb 		__le16 tag;
18936c92544dSBjoern A. Zeeb 		__le16 min_lpn;
18946c92544dSBjoern A. Zeeb 	} req = {
18956c92544dSBjoern A. Zeeb 		.tag = cpu_to_le16(0x1),
18966c92544dSBjoern A. Zeeb 		.min_lpn = cpu_to_le16(val),
18976c92544dSBjoern A. Zeeb 	};
18986c92544dSBjoern A. Zeeb 
18996c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_RADAR_TH),
19006c92544dSBjoern A. Zeeb 				 &req, sizeof(req), true);
19016c92544dSBjoern A. Zeeb }
19026c92544dSBjoern A. Zeeb 
19036c92544dSBjoern A. Zeeb int mt7615_mcu_set_pulse_th(struct mt7615_dev *dev,
19046c92544dSBjoern A. Zeeb 			    const struct mt7615_dfs_pulse *pulse)
19056c92544dSBjoern A. Zeeb {
19066c92544dSBjoern A. Zeeb 	struct {
19076c92544dSBjoern A. Zeeb 		__le16 tag;
19086c92544dSBjoern A. Zeeb 		__le32 max_width;	/* us */
19096c92544dSBjoern A. Zeeb 		__le32 max_pwr;		/* dbm */
19106c92544dSBjoern A. Zeeb 		__le32 min_pwr;		/* dbm */
19116c92544dSBjoern A. Zeeb 		__le32 min_stgr_pri;	/* us */
19126c92544dSBjoern A. Zeeb 		__le32 max_stgr_pri;	/* us */
19136c92544dSBjoern A. Zeeb 		__le32 min_cr_pri;	/* us */
19146c92544dSBjoern A. Zeeb 		__le32 max_cr_pri;	/* us */
19156c92544dSBjoern A. Zeeb 	} req = {
19166c92544dSBjoern A. Zeeb 		.tag = cpu_to_le16(0x3),
19176c92544dSBjoern A. Zeeb #define __req_field(field) .field = cpu_to_le32(pulse->field)
19186c92544dSBjoern A. Zeeb 		__req_field(max_width),
19196c92544dSBjoern A. Zeeb 		__req_field(max_pwr),
19206c92544dSBjoern A. Zeeb 		__req_field(min_pwr),
19216c92544dSBjoern A. Zeeb 		__req_field(min_stgr_pri),
19226c92544dSBjoern A. Zeeb 		__req_field(max_stgr_pri),
19236c92544dSBjoern A. Zeeb 		__req_field(min_cr_pri),
19246c92544dSBjoern A. Zeeb 		__req_field(max_cr_pri),
19256c92544dSBjoern A. Zeeb #undef  __req_field
19266c92544dSBjoern A. Zeeb 	};
19276c92544dSBjoern A. Zeeb 
19286c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_RADAR_TH),
19296c92544dSBjoern A. Zeeb 				 &req, sizeof(req), true);
19306c92544dSBjoern A. Zeeb }
19316c92544dSBjoern A. Zeeb 
19326c92544dSBjoern A. Zeeb int mt7615_mcu_set_radar_th(struct mt7615_dev *dev, int index,
19336c92544dSBjoern A. Zeeb 			    const struct mt7615_dfs_pattern *pattern)
19346c92544dSBjoern A. Zeeb {
19356c92544dSBjoern A. Zeeb 	struct {
19366c92544dSBjoern A. Zeeb 		__le16 tag;
19376c92544dSBjoern A. Zeeb 		__le16 radar_type;
19386c92544dSBjoern A. Zeeb 		u8 enb;
19396c92544dSBjoern A. Zeeb 		u8 stgr;
19406c92544dSBjoern A. Zeeb 		u8 min_crpn;
19416c92544dSBjoern A. Zeeb 		u8 max_crpn;
19426c92544dSBjoern A. Zeeb 		u8 min_crpr;
19436c92544dSBjoern A. Zeeb 		u8 min_pw;
19446c92544dSBjoern A. Zeeb 		u8 max_pw;
19456c92544dSBjoern A. Zeeb 		__le32 min_pri;
19466c92544dSBjoern A. Zeeb 		__le32 max_pri;
19476c92544dSBjoern A. Zeeb 		u8 min_crbn;
19486c92544dSBjoern A. Zeeb 		u8 max_crbn;
19496c92544dSBjoern A. Zeeb 		u8 min_stgpn;
19506c92544dSBjoern A. Zeeb 		u8 max_stgpn;
19516c92544dSBjoern A. Zeeb 		u8 min_stgpr;
19526c92544dSBjoern A. Zeeb 	} req = {
19536c92544dSBjoern A. Zeeb 		.tag = cpu_to_le16(0x2),
19546c92544dSBjoern A. Zeeb 		.radar_type = cpu_to_le16(index),
19556c92544dSBjoern A. Zeeb #define __req_field_u8(field) .field = pattern->field
19566c92544dSBjoern A. Zeeb #define __req_field_u32(field) .field = cpu_to_le32(pattern->field)
19576c92544dSBjoern A. Zeeb 		__req_field_u8(enb),
19586c92544dSBjoern A. Zeeb 		__req_field_u8(stgr),
19596c92544dSBjoern A. Zeeb 		__req_field_u8(min_crpn),
19606c92544dSBjoern A. Zeeb 		__req_field_u8(max_crpn),
19616c92544dSBjoern A. Zeeb 		__req_field_u8(min_crpr),
19626c92544dSBjoern A. Zeeb 		__req_field_u8(min_pw),
19636c92544dSBjoern A. Zeeb 		__req_field_u8(max_pw),
19646c92544dSBjoern A. Zeeb 		__req_field_u32(min_pri),
19656c92544dSBjoern A. Zeeb 		__req_field_u32(max_pri),
19666c92544dSBjoern A. Zeeb 		__req_field_u8(min_crbn),
19676c92544dSBjoern A. Zeeb 		__req_field_u8(max_crbn),
19686c92544dSBjoern A. Zeeb 		__req_field_u8(min_stgpn),
19696c92544dSBjoern A. Zeeb 		__req_field_u8(max_stgpn),
19706c92544dSBjoern A. Zeeb 		__req_field_u8(min_stgpr),
19716c92544dSBjoern A. Zeeb #undef __req_field_u8
19726c92544dSBjoern A. Zeeb #undef __req_field_u32
19736c92544dSBjoern A. Zeeb 	};
19746c92544dSBjoern A. Zeeb 
19756c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_RADAR_TH),
19766c92544dSBjoern A. Zeeb 				 &req, sizeof(req), true);
19776c92544dSBjoern A. Zeeb }
19786c92544dSBjoern A. Zeeb 
19796c92544dSBjoern A. Zeeb int mt7615_mcu_rdd_send_pattern(struct mt7615_dev *dev)
19806c92544dSBjoern A. Zeeb {
19816c92544dSBjoern A. Zeeb 	struct {
19826c92544dSBjoern A. Zeeb 		u8 pulse_num;
19836c92544dSBjoern A. Zeeb 		u8 rsv[3];
19846c92544dSBjoern A. Zeeb 		struct {
19856c92544dSBjoern A. Zeeb 			__le32 start_time;
19866c92544dSBjoern A. Zeeb 			__le16 width;
19876c92544dSBjoern A. Zeeb 			__le16 power;
19886c92544dSBjoern A. Zeeb 		} pattern[32];
19896c92544dSBjoern A. Zeeb 	} req = {
19906c92544dSBjoern A. Zeeb 		.pulse_num = dev->radar_pattern.n_pulses,
19916c92544dSBjoern A. Zeeb 	};
19926c92544dSBjoern A. Zeeb 	u32 start_time = ktime_to_ms(ktime_get_boottime());
19936c92544dSBjoern A. Zeeb 	int i;
19946c92544dSBjoern A. Zeeb 
19956c92544dSBjoern A. Zeeb 	if (dev->radar_pattern.n_pulses > ARRAY_SIZE(req.pattern))
19966c92544dSBjoern A. Zeeb 		return -EINVAL;
19976c92544dSBjoern A. Zeeb 
19986c92544dSBjoern A. Zeeb 	/* TODO: add some noise here */
19996c92544dSBjoern A. Zeeb 	for (i = 0; i < dev->radar_pattern.n_pulses; i++) {
20006c92544dSBjoern A. Zeeb 		u32 ts = start_time + i * dev->radar_pattern.period;
20016c92544dSBjoern A. Zeeb 
20026c92544dSBjoern A. Zeeb 		req.pattern[i].width = cpu_to_le16(dev->radar_pattern.width);
20036c92544dSBjoern A. Zeeb 		req.pattern[i].power = cpu_to_le16(dev->radar_pattern.power);
20046c92544dSBjoern A. Zeeb 		req.pattern[i].start_time = cpu_to_le32(ts);
20056c92544dSBjoern A. Zeeb 	}
20066c92544dSBjoern A. Zeeb 
20076c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_RDD_PATTERN),
20086c92544dSBjoern A. Zeeb 				 &req, sizeof(req), false);
20096c92544dSBjoern A. Zeeb }
20106c92544dSBjoern A. Zeeb 
20116c92544dSBjoern A. Zeeb static void mt7615_mcu_set_txpower_sku(struct mt7615_phy *phy, u8 *sku)
20126c92544dSBjoern A. Zeeb {
20136c92544dSBjoern A. Zeeb 	struct mt76_phy *mphy = phy->mt76;
20146c92544dSBjoern A. Zeeb 	struct ieee80211_hw *hw = mphy->hw;
20156c92544dSBjoern A. Zeeb 	struct mt76_power_limits limits;
20166c92544dSBjoern A. Zeeb 	s8 *limits_array = (s8 *)&limits;
20176c92544dSBjoern A. Zeeb 	int n_chains = hweight8(mphy->antenna_mask);
20186c92544dSBjoern A. Zeeb 	int tx_power = hw->conf.power_level * 2;
20196c92544dSBjoern A. Zeeb 	int i;
20206c92544dSBjoern A. Zeeb 	static const u8 sku_mapping[] = {
20216c92544dSBjoern A. Zeeb #define SKU_FIELD(_type, _field) \
20226c92544dSBjoern A. Zeeb 		[MT_SKU_##_type] = offsetof(struct mt76_power_limits, _field)
20236c92544dSBjoern A. Zeeb 		SKU_FIELD(CCK_1_2, cck[0]),
20246c92544dSBjoern A. Zeeb 		SKU_FIELD(CCK_55_11, cck[2]),
20256c92544dSBjoern A. Zeeb 		SKU_FIELD(OFDM_6_9, ofdm[0]),
20266c92544dSBjoern A. Zeeb 		SKU_FIELD(OFDM_12_18, ofdm[2]),
20276c92544dSBjoern A. Zeeb 		SKU_FIELD(OFDM_24_36, ofdm[4]),
20286c92544dSBjoern A. Zeeb 		SKU_FIELD(OFDM_48, ofdm[6]),
20296c92544dSBjoern A. Zeeb 		SKU_FIELD(OFDM_54, ofdm[7]),
20306c92544dSBjoern A. Zeeb 		SKU_FIELD(HT20_0_8, mcs[0][0]),
20316c92544dSBjoern A. Zeeb 		SKU_FIELD(HT20_32, ofdm[0]),
20326c92544dSBjoern A. Zeeb 		SKU_FIELD(HT20_1_2_9_10, mcs[0][1]),
20336c92544dSBjoern A. Zeeb 		SKU_FIELD(HT20_3_4_11_12, mcs[0][3]),
20346c92544dSBjoern A. Zeeb 		SKU_FIELD(HT20_5_13, mcs[0][5]),
20356c92544dSBjoern A. Zeeb 		SKU_FIELD(HT20_6_14, mcs[0][6]),
20366c92544dSBjoern A. Zeeb 		SKU_FIELD(HT20_7_15, mcs[0][7]),
20376c92544dSBjoern A. Zeeb 		SKU_FIELD(HT40_0_8, mcs[1][0]),
20386c92544dSBjoern A. Zeeb 		SKU_FIELD(HT40_32, ofdm[0]),
20396c92544dSBjoern A. Zeeb 		SKU_FIELD(HT40_1_2_9_10, mcs[1][1]),
20406c92544dSBjoern A. Zeeb 		SKU_FIELD(HT40_3_4_11_12, mcs[1][3]),
20416c92544dSBjoern A. Zeeb 		SKU_FIELD(HT40_5_13, mcs[1][5]),
20426c92544dSBjoern A. Zeeb 		SKU_FIELD(HT40_6_14, mcs[1][6]),
20436c92544dSBjoern A. Zeeb 		SKU_FIELD(HT40_7_15, mcs[1][7]),
20446c92544dSBjoern A. Zeeb 		SKU_FIELD(VHT20_0, mcs[0][0]),
20456c92544dSBjoern A. Zeeb 		SKU_FIELD(VHT20_1_2, mcs[0][1]),
20466c92544dSBjoern A. Zeeb 		SKU_FIELD(VHT20_3_4, mcs[0][3]),
20476c92544dSBjoern A. Zeeb 		SKU_FIELD(VHT20_5_6, mcs[0][5]),
20486c92544dSBjoern A. Zeeb 		SKU_FIELD(VHT20_7, mcs[0][7]),
20496c92544dSBjoern A. Zeeb 		SKU_FIELD(VHT20_8, mcs[0][8]),
20506c92544dSBjoern A. Zeeb 		SKU_FIELD(VHT20_9, mcs[0][9]),
20516c92544dSBjoern A. Zeeb 		SKU_FIELD(VHT40_0, mcs[1][0]),
20526c92544dSBjoern A. Zeeb 		SKU_FIELD(VHT40_1_2, mcs[1][1]),
20536c92544dSBjoern A. Zeeb 		SKU_FIELD(VHT40_3_4, mcs[1][3]),
20546c92544dSBjoern A. Zeeb 		SKU_FIELD(VHT40_5_6, mcs[1][5]),
20556c92544dSBjoern A. Zeeb 		SKU_FIELD(VHT40_7, mcs[1][7]),
20566c92544dSBjoern A. Zeeb 		SKU_FIELD(VHT40_8, mcs[1][8]),
20576c92544dSBjoern A. Zeeb 		SKU_FIELD(VHT40_9, mcs[1][9]),
20586c92544dSBjoern A. Zeeb 		SKU_FIELD(VHT80_0, mcs[2][0]),
20596c92544dSBjoern A. Zeeb 		SKU_FIELD(VHT80_1_2, mcs[2][1]),
20606c92544dSBjoern A. Zeeb 		SKU_FIELD(VHT80_3_4, mcs[2][3]),
20616c92544dSBjoern A. Zeeb 		SKU_FIELD(VHT80_5_6, mcs[2][5]),
20626c92544dSBjoern A. Zeeb 		SKU_FIELD(VHT80_7, mcs[2][7]),
20636c92544dSBjoern A. Zeeb 		SKU_FIELD(VHT80_8, mcs[2][8]),
20646c92544dSBjoern A. Zeeb 		SKU_FIELD(VHT80_9, mcs[2][9]),
20656c92544dSBjoern A. Zeeb 		SKU_FIELD(VHT160_0, mcs[3][0]),
20666c92544dSBjoern A. Zeeb 		SKU_FIELD(VHT160_1_2, mcs[3][1]),
20676c92544dSBjoern A. Zeeb 		SKU_FIELD(VHT160_3_4, mcs[3][3]),
20686c92544dSBjoern A. Zeeb 		SKU_FIELD(VHT160_5_6, mcs[3][5]),
20696c92544dSBjoern A. Zeeb 		SKU_FIELD(VHT160_7, mcs[3][7]),
20706c92544dSBjoern A. Zeeb 		SKU_FIELD(VHT160_8, mcs[3][8]),
20716c92544dSBjoern A. Zeeb 		SKU_FIELD(VHT160_9, mcs[3][9]),
20726c92544dSBjoern A. Zeeb #undef SKU_FIELD
20736c92544dSBjoern A. Zeeb 	};
20746c92544dSBjoern A. Zeeb 
20756c92544dSBjoern A. Zeeb 	tx_power = mt76_get_sar_power(mphy, mphy->chandef.chan, tx_power);
20766c92544dSBjoern A. Zeeb 	tx_power -= mt76_tx_power_nss_delta(n_chains);
20776c92544dSBjoern A. Zeeb 	tx_power = mt76_get_rate_power_limits(mphy, mphy->chandef.chan,
20786c92544dSBjoern A. Zeeb 					      &limits, tx_power);
20796c92544dSBjoern A. Zeeb 	mphy->txpower_cur = tx_power;
20806c92544dSBjoern A. Zeeb 
20816c92544dSBjoern A. Zeeb 	if (is_mt7663(mphy->dev)) {
20826c92544dSBjoern A. Zeeb 		memset(sku, tx_power, MT_SKU_4SS_DELTA + 1);
20836c92544dSBjoern A. Zeeb 		return;
20846c92544dSBjoern A. Zeeb 	}
20856c92544dSBjoern A. Zeeb 
20866c92544dSBjoern A. Zeeb 	for (i = 0; i < MT_SKU_1SS_DELTA; i++)
20876c92544dSBjoern A. Zeeb 		sku[i] = limits_array[sku_mapping[i]];
20886c92544dSBjoern A. Zeeb 
20896c92544dSBjoern A. Zeeb 	for (i = 0; i < 4; i++) {
20906c92544dSBjoern A. Zeeb 		int delta = 0;
20916c92544dSBjoern A. Zeeb 
20926c92544dSBjoern A. Zeeb 		if (i < n_chains - 1)
20936c92544dSBjoern A. Zeeb 			delta = mt76_tx_power_nss_delta(n_chains) -
20946c92544dSBjoern A. Zeeb 				mt76_tx_power_nss_delta(i + 1);
20956c92544dSBjoern A. Zeeb 		sku[MT_SKU_1SS_DELTA + i] = delta;
20966c92544dSBjoern A. Zeeb 	}
20976c92544dSBjoern A. Zeeb }
20986c92544dSBjoern A. Zeeb 
20996c92544dSBjoern A. Zeeb static u8 mt7615_mcu_chan_bw(struct cfg80211_chan_def *chandef)
21006c92544dSBjoern A. Zeeb {
21016c92544dSBjoern A. Zeeb 	static const u8 width_to_bw[] = {
21026c92544dSBjoern A. Zeeb 		[NL80211_CHAN_WIDTH_40] = CMD_CBW_40MHZ,
21036c92544dSBjoern A. Zeeb 		[NL80211_CHAN_WIDTH_80] = CMD_CBW_80MHZ,
21046c92544dSBjoern A. Zeeb 		[NL80211_CHAN_WIDTH_80P80] = CMD_CBW_8080MHZ,
21056c92544dSBjoern A. Zeeb 		[NL80211_CHAN_WIDTH_160] = CMD_CBW_160MHZ,
21066c92544dSBjoern A. Zeeb 		[NL80211_CHAN_WIDTH_5] = CMD_CBW_5MHZ,
21076c92544dSBjoern A. Zeeb 		[NL80211_CHAN_WIDTH_10] = CMD_CBW_10MHZ,
21086c92544dSBjoern A. Zeeb 		[NL80211_CHAN_WIDTH_20] = CMD_CBW_20MHZ,
21096c92544dSBjoern A. Zeeb 		[NL80211_CHAN_WIDTH_20_NOHT] = CMD_CBW_20MHZ,
21106c92544dSBjoern A. Zeeb 	};
21116c92544dSBjoern A. Zeeb 
21126c92544dSBjoern A. Zeeb 	if (chandef->width >= ARRAY_SIZE(width_to_bw))
21136c92544dSBjoern A. Zeeb 		return 0;
21146c92544dSBjoern A. Zeeb 
21156c92544dSBjoern A. Zeeb 	return width_to_bw[chandef->width];
21166c92544dSBjoern A. Zeeb }
21176c92544dSBjoern A. Zeeb 
21186c92544dSBjoern A. Zeeb int mt7615_mcu_set_chan_info(struct mt7615_phy *phy, int cmd)
21196c92544dSBjoern A. Zeeb {
21206c92544dSBjoern A. Zeeb 	struct mt7615_dev *dev = phy->dev;
21216c92544dSBjoern A. Zeeb 	struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
21226c92544dSBjoern A. Zeeb 	int freq1 = chandef->center_freq1, freq2 = chandef->center_freq2;
21236c92544dSBjoern A. Zeeb 	struct {
21246c92544dSBjoern A. Zeeb 		u8 control_chan;
21256c92544dSBjoern A. Zeeb 		u8 center_chan;
21266c92544dSBjoern A. Zeeb 		u8 bw;
21276c92544dSBjoern A. Zeeb 		u8 tx_streams;
21286c92544dSBjoern A. Zeeb 		u8 rx_streams_mask;
21296c92544dSBjoern A. Zeeb 		u8 switch_reason;
21306c92544dSBjoern A. Zeeb 		u8 band_idx;
21316c92544dSBjoern A. Zeeb 		/* for 80+80 only */
21326c92544dSBjoern A. Zeeb 		u8 center_chan2;
21336c92544dSBjoern A. Zeeb 		__le16 cac_case;
21346c92544dSBjoern A. Zeeb 		u8 channel_band;
21356c92544dSBjoern A. Zeeb 		u8 rsv0;
21366c92544dSBjoern A. Zeeb 		__le32 outband_freq;
21376c92544dSBjoern A. Zeeb 		u8 txpower_drop;
21386c92544dSBjoern A. Zeeb 		u8 rsv1[3];
21396c92544dSBjoern A. Zeeb 		u8 txpower_sku[53];
21406c92544dSBjoern A. Zeeb 		u8 rsv2[3];
21416c92544dSBjoern A. Zeeb 	} req = {
21426c92544dSBjoern A. Zeeb 		.control_chan = chandef->chan->hw_value,
21436c92544dSBjoern A. Zeeb 		.center_chan = ieee80211_frequency_to_channel(freq1),
21446c92544dSBjoern A. Zeeb 		.tx_streams = hweight8(phy->mt76->antenna_mask),
21456c92544dSBjoern A. Zeeb 		.rx_streams_mask = phy->mt76->chainmask,
21466c92544dSBjoern A. Zeeb 		.center_chan2 = ieee80211_frequency_to_channel(freq2),
21476c92544dSBjoern A. Zeeb 	};
21486c92544dSBjoern A. Zeeb 
21496c92544dSBjoern A. Zeeb 	if (cmd == MCU_EXT_CMD(SET_RX_PATH) ||
21506c92544dSBjoern A. Zeeb 	    dev->mt76.hw->conf.flags & IEEE80211_CONF_MONITOR)
21516c92544dSBjoern A. Zeeb 		req.switch_reason = CH_SWITCH_NORMAL;
21526c92544dSBjoern A. Zeeb 	else if (phy->mt76->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)
21536c92544dSBjoern A. Zeeb 		req.switch_reason = CH_SWITCH_SCAN_BYPASS_DPD;
21546c92544dSBjoern A. Zeeb 	else if (!cfg80211_reg_can_beacon(phy->mt76->hw->wiphy, chandef,
21556c92544dSBjoern A. Zeeb 					  NL80211_IFTYPE_AP))
21566c92544dSBjoern A. Zeeb 		req.switch_reason = CH_SWITCH_DFS;
21576c92544dSBjoern A. Zeeb 	else
21586c92544dSBjoern A. Zeeb 		req.switch_reason = CH_SWITCH_NORMAL;
21596c92544dSBjoern A. Zeeb 
21606c92544dSBjoern A. Zeeb 	req.band_idx = phy != &dev->phy;
21616c92544dSBjoern A. Zeeb 	req.bw = mt7615_mcu_chan_bw(chandef);
21626c92544dSBjoern A. Zeeb 
21636c92544dSBjoern A. Zeeb 	if (mt76_testmode_enabled(phy->mt76))
21646c92544dSBjoern A. Zeeb 		memset(req.txpower_sku, 0x3f, 49);
21656c92544dSBjoern A. Zeeb 	else
21666c92544dSBjoern A. Zeeb 		mt7615_mcu_set_txpower_sku(phy, req.txpower_sku);
21676c92544dSBjoern A. Zeeb 
21686c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), true);
21696c92544dSBjoern A. Zeeb }
21706c92544dSBjoern A. Zeeb 
21716c92544dSBjoern A. Zeeb int mt7615_mcu_get_temperature(struct mt7615_dev *dev)
21726c92544dSBjoern A. Zeeb {
21736c92544dSBjoern A. Zeeb 	struct {
21746c92544dSBjoern A. Zeeb 		u8 action;
21756c92544dSBjoern A. Zeeb 		u8 rsv[3];
21766c92544dSBjoern A. Zeeb 	} req = {};
21776c92544dSBjoern A. Zeeb 
21786c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(THERMAL_CTRL),
21796c92544dSBjoern A. Zeeb 				 &req, sizeof(req), true);
21806c92544dSBjoern A. Zeeb }
21816c92544dSBjoern A. Zeeb 
21826c92544dSBjoern A. Zeeb int mt7615_mcu_set_test_param(struct mt7615_dev *dev, u8 param, bool test_mode,
21836c92544dSBjoern A. Zeeb 			      u32 val)
21846c92544dSBjoern A. Zeeb {
21856c92544dSBjoern A. Zeeb 	struct {
21866c92544dSBjoern A. Zeeb 		u8 test_mode_en;
21876c92544dSBjoern A. Zeeb 		u8 param_idx;
21886c92544dSBjoern A. Zeeb 		u8 _rsv[2];
21896c92544dSBjoern A. Zeeb 
21906c92544dSBjoern A. Zeeb 		__le32 value;
21916c92544dSBjoern A. Zeeb 
21926c92544dSBjoern A. Zeeb 		u8 pad[8];
21936c92544dSBjoern A. Zeeb 	} req = {
21946c92544dSBjoern A. Zeeb 		.test_mode_en = test_mode,
21956c92544dSBjoern A. Zeeb 		.param_idx = param,
21966c92544dSBjoern A. Zeeb 		.value = cpu_to_le32(val),
21976c92544dSBjoern A. Zeeb 	};
21986c92544dSBjoern A. Zeeb 
21996c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(ATE_CTRL),
22006c92544dSBjoern A. Zeeb 				 &req, sizeof(req), false);
22016c92544dSBjoern A. Zeeb }
22026c92544dSBjoern A. Zeeb 
22036c92544dSBjoern A. Zeeb int mt7615_mcu_set_sku_en(struct mt7615_phy *phy, bool enable)
22046c92544dSBjoern A. Zeeb {
22056c92544dSBjoern A. Zeeb 	struct mt7615_dev *dev = phy->dev;
22066c92544dSBjoern A. Zeeb 	struct {
22076c92544dSBjoern A. Zeeb 		u8 format_id;
22086c92544dSBjoern A. Zeeb 		u8 sku_enable;
22096c92544dSBjoern A. Zeeb 		u8 band_idx;
22106c92544dSBjoern A. Zeeb 		u8 rsv;
22116c92544dSBjoern A. Zeeb 	} req = {
22126c92544dSBjoern A. Zeeb 		.format_id = 0,
22136c92544dSBjoern A. Zeeb 		.band_idx = phy != &dev->phy,
22146c92544dSBjoern A. Zeeb 		.sku_enable = enable,
22156c92544dSBjoern A. Zeeb 	};
22166c92544dSBjoern A. Zeeb 
22176c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76,
22186c92544dSBjoern A. Zeeb 				 MCU_EXT_CMD(TX_POWER_FEATURE_CTRL),
22196c92544dSBjoern A. Zeeb 				 &req, sizeof(req), true);
22206c92544dSBjoern A. Zeeb }
22216c92544dSBjoern A. Zeeb 
22226c92544dSBjoern A. Zeeb static int mt7615_find_freq_idx(const u16 *freqs, int n_freqs, u16 cur)
22236c92544dSBjoern A. Zeeb {
22246c92544dSBjoern A. Zeeb 	int i;
22256c92544dSBjoern A. Zeeb 
22266c92544dSBjoern A. Zeeb 	for (i = 0; i < n_freqs; i++)
22276c92544dSBjoern A. Zeeb 		if (cur == freqs[i])
22286c92544dSBjoern A. Zeeb 			return i;
22296c92544dSBjoern A. Zeeb 
22306c92544dSBjoern A. Zeeb 	return -1;
22316c92544dSBjoern A. Zeeb }
22326c92544dSBjoern A. Zeeb 
22336c92544dSBjoern A. Zeeb static int mt7615_dcoc_freq_idx(u16 freq, u8 bw)
22346c92544dSBjoern A. Zeeb {
22356c92544dSBjoern A. Zeeb 	static const u16 freq_list[] = {
22366c92544dSBjoern A. Zeeb 		4980, 5805, 5905, 5190,
22376c92544dSBjoern A. Zeeb 		5230, 5270, 5310, 5350,
22386c92544dSBjoern A. Zeeb 		5390, 5430, 5470, 5510,
22396c92544dSBjoern A. Zeeb 		5550, 5590, 5630, 5670,
22406c92544dSBjoern A. Zeeb 		5710, 5755, 5795, 5835,
22416c92544dSBjoern A. Zeeb 		5875, 5210, 5290, 5370,
22426c92544dSBjoern A. Zeeb 		5450, 5530, 5610, 5690,
22436c92544dSBjoern A. Zeeb 		5775, 5855
22446c92544dSBjoern A. Zeeb 	};
22456c92544dSBjoern A. Zeeb 	static const u16 freq_bw40[] = {
22466c92544dSBjoern A. Zeeb 		5190, 5230, 5270, 5310,
22476c92544dSBjoern A. Zeeb 		5350, 5390, 5430, 5470,
22486c92544dSBjoern A. Zeeb 		5510, 5550, 5590, 5630,
22496c92544dSBjoern A. Zeeb 		5670, 5710, 5755, 5795,
22506c92544dSBjoern A. Zeeb 		5835, 5875
22516c92544dSBjoern A. Zeeb 	};
22526c92544dSBjoern A. Zeeb 	int offset_2g = ARRAY_SIZE(freq_list);
22536c92544dSBjoern A. Zeeb 	int idx;
22546c92544dSBjoern A. Zeeb 
22556c92544dSBjoern A. Zeeb 	if (freq < 4000) {
22566c92544dSBjoern A. Zeeb 		if (freq < 2427)
22576c92544dSBjoern A. Zeeb 			return offset_2g;
22586c92544dSBjoern A. Zeeb 		if (freq < 2442)
22596c92544dSBjoern A. Zeeb 			return offset_2g + 1;
22606c92544dSBjoern A. Zeeb 		if (freq < 2457)
22616c92544dSBjoern A. Zeeb 			return offset_2g + 2;
22626c92544dSBjoern A. Zeeb 
22636c92544dSBjoern A. Zeeb 		return offset_2g + 3;
22646c92544dSBjoern A. Zeeb 	}
22656c92544dSBjoern A. Zeeb 
22666c92544dSBjoern A. Zeeb 	switch (bw) {
22676c92544dSBjoern A. Zeeb 	case NL80211_CHAN_WIDTH_80:
22686c92544dSBjoern A. Zeeb 	case NL80211_CHAN_WIDTH_80P80:
22696c92544dSBjoern A. Zeeb 	case NL80211_CHAN_WIDTH_160:
22706c92544dSBjoern A. Zeeb 		break;
22716c92544dSBjoern A. Zeeb 	default:
22726c92544dSBjoern A. Zeeb 		idx = mt7615_find_freq_idx(freq_bw40, ARRAY_SIZE(freq_bw40),
22736c92544dSBjoern A. Zeeb 					   freq + 10);
22746c92544dSBjoern A. Zeeb 		if (idx >= 0) {
22756c92544dSBjoern A. Zeeb 			freq = freq_bw40[idx];
22766c92544dSBjoern A. Zeeb 			break;
22776c92544dSBjoern A. Zeeb 		}
22786c92544dSBjoern A. Zeeb 
22796c92544dSBjoern A. Zeeb 		idx = mt7615_find_freq_idx(freq_bw40, ARRAY_SIZE(freq_bw40),
22806c92544dSBjoern A. Zeeb 					   freq - 10);
22816c92544dSBjoern A. Zeeb 		if (idx >= 0) {
22826c92544dSBjoern A. Zeeb 			freq = freq_bw40[idx];
22836c92544dSBjoern A. Zeeb 			break;
22846c92544dSBjoern A. Zeeb 		}
22856c92544dSBjoern A. Zeeb 		fallthrough;
22866c92544dSBjoern A. Zeeb 	case NL80211_CHAN_WIDTH_40:
22876c92544dSBjoern A. Zeeb 		idx = mt7615_find_freq_idx(freq_bw40, ARRAY_SIZE(freq_bw40),
22886c92544dSBjoern A. Zeeb 					   freq);
22896c92544dSBjoern A. Zeeb 		if (idx >= 0)
22906c92544dSBjoern A. Zeeb 			break;
22916c92544dSBjoern A. Zeeb 
22926c92544dSBjoern A. Zeeb 		return -1;
22936c92544dSBjoern A. Zeeb 
22946c92544dSBjoern A. Zeeb 	}
22956c92544dSBjoern A. Zeeb 
22966c92544dSBjoern A. Zeeb 	return mt7615_find_freq_idx(freq_list, ARRAY_SIZE(freq_list), freq);
22976c92544dSBjoern A. Zeeb }
22986c92544dSBjoern A. Zeeb 
22996c92544dSBjoern A. Zeeb int mt7615_mcu_apply_rx_dcoc(struct mt7615_phy *phy)
23006c92544dSBjoern A. Zeeb {
23016c92544dSBjoern A. Zeeb 	struct mt7615_dev *dev = phy->dev;
23026c92544dSBjoern A. Zeeb 	struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
23036c92544dSBjoern A. Zeeb 	int freq2 = chandef->center_freq2;
23046c92544dSBjoern A. Zeeb 	int ret;
23056c92544dSBjoern A. Zeeb 	struct {
23066c92544dSBjoern A. Zeeb 		u8 direction;
23076c92544dSBjoern A. Zeeb 		u8 runtime_calibration;
23086c92544dSBjoern A. Zeeb 		u8 _rsv[2];
23096c92544dSBjoern A. Zeeb 
23106c92544dSBjoern A. Zeeb 		__le16 center_freq;
23116c92544dSBjoern A. Zeeb 		u8 bw;
23126c92544dSBjoern A. Zeeb 		u8 band;
23136c92544dSBjoern A. Zeeb 		u8 is_freq2;
23146c92544dSBjoern A. Zeeb 		u8 success;
23156c92544dSBjoern A. Zeeb 		u8 dbdc_en;
23166c92544dSBjoern A. Zeeb 
23176c92544dSBjoern A. Zeeb 		u8 _rsv2;
23186c92544dSBjoern A. Zeeb 
23196c92544dSBjoern A. Zeeb 		struct {
23206c92544dSBjoern A. Zeeb 			__le32 sx0_i_lna[4];
23216c92544dSBjoern A. Zeeb 			__le32 sx0_q_lna[4];
23226c92544dSBjoern A. Zeeb 
23236c92544dSBjoern A. Zeeb 			__le32 sx2_i_lna[4];
23246c92544dSBjoern A. Zeeb 			__le32 sx2_q_lna[4];
23256c92544dSBjoern A. Zeeb 		} dcoc_data[4];
23266c92544dSBjoern A. Zeeb 	} req = {
23276c92544dSBjoern A. Zeeb 		.direction = 1,
23286c92544dSBjoern A. Zeeb 
23296c92544dSBjoern A. Zeeb 		.bw = mt7615_mcu_chan_bw(chandef),
23306c92544dSBjoern A. Zeeb 		.band = chandef->center_freq1 > 4000,
23316c92544dSBjoern A. Zeeb 		.dbdc_en = !!dev->mt76.phys[MT_BAND1],
23326c92544dSBjoern A. Zeeb 	};
23336c92544dSBjoern A. Zeeb 	u16 center_freq = chandef->center_freq1;
23346c92544dSBjoern A. Zeeb 	int freq_idx;
23356c92544dSBjoern A. Zeeb 	u8 *eep = dev->mt76.eeprom.data;
23366c92544dSBjoern A. Zeeb 
23376c92544dSBjoern A. Zeeb 	if (!(eep[MT_EE_CALDATA_FLASH] & MT_EE_CALDATA_FLASH_RX_CAL))
23386c92544dSBjoern A. Zeeb 		return 0;
23396c92544dSBjoern A. Zeeb 
23406c92544dSBjoern A. Zeeb 	if (chandef->width == NL80211_CHAN_WIDTH_160) {
23416c92544dSBjoern A. Zeeb 		freq2 = center_freq + 40;
23426c92544dSBjoern A. Zeeb 		center_freq -= 40;
23436c92544dSBjoern A. Zeeb 	}
23446c92544dSBjoern A. Zeeb 
23456c92544dSBjoern A. Zeeb again:
23466c92544dSBjoern A. Zeeb 	req.runtime_calibration = 1;
23476c92544dSBjoern A. Zeeb 	freq_idx = mt7615_dcoc_freq_idx(center_freq, chandef->width);
23486c92544dSBjoern A. Zeeb 	if (freq_idx < 0)
23496c92544dSBjoern A. Zeeb 		goto out;
23506c92544dSBjoern A. Zeeb 
23516c92544dSBjoern A. Zeeb 	memcpy(req.dcoc_data, eep + MT7615_EEPROM_DCOC_OFFSET +
23526c92544dSBjoern A. Zeeb 			      freq_idx * MT7615_EEPROM_DCOC_SIZE,
23536c92544dSBjoern A. Zeeb 	       sizeof(req.dcoc_data));
23546c92544dSBjoern A. Zeeb 	req.runtime_calibration = 0;
23556c92544dSBjoern A. Zeeb 
23566c92544dSBjoern A. Zeeb out:
23576c92544dSBjoern A. Zeeb 	req.center_freq = cpu_to_le16(center_freq);
23586c92544dSBjoern A. Zeeb 	ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RXDCOC_CAL), &req,
23596c92544dSBjoern A. Zeeb 				sizeof(req), true);
23606c92544dSBjoern A. Zeeb 
23616c92544dSBjoern A. Zeeb 	if ((chandef->width == NL80211_CHAN_WIDTH_80P80 ||
23626c92544dSBjoern A. Zeeb 	     chandef->width == NL80211_CHAN_WIDTH_160) && !req.is_freq2) {
23636c92544dSBjoern A. Zeeb 		req.is_freq2 = true;
23646c92544dSBjoern A. Zeeb 		center_freq = freq2;
23656c92544dSBjoern A. Zeeb 		goto again;
23666c92544dSBjoern A. Zeeb 	}
23676c92544dSBjoern A. Zeeb 
23686c92544dSBjoern A. Zeeb 	return ret;
23696c92544dSBjoern A. Zeeb }
23706c92544dSBjoern A. Zeeb 
23716c92544dSBjoern A. Zeeb static int mt7615_dpd_freq_idx(u16 freq, u8 bw)
23726c92544dSBjoern A. Zeeb {
23736c92544dSBjoern A. Zeeb 	static const u16 freq_list[] = {
23746c92544dSBjoern A. Zeeb 		4920, 4940, 4960, 4980,
23756c92544dSBjoern A. Zeeb 		5040, 5060, 5080, 5180,
23766c92544dSBjoern A. Zeeb 		5200, 5220, 5240, 5260,
23776c92544dSBjoern A. Zeeb 		5280, 5300, 5320, 5340,
23786c92544dSBjoern A. Zeeb 		5360, 5380, 5400, 5420,
23796c92544dSBjoern A. Zeeb 		5440, 5460, 5480, 5500,
23806c92544dSBjoern A. Zeeb 		5520, 5540, 5560, 5580,
23816c92544dSBjoern A. Zeeb 		5600, 5620, 5640, 5660,
23826c92544dSBjoern A. Zeeb 		5680, 5700, 5720, 5745,
23836c92544dSBjoern A. Zeeb 		5765, 5785, 5805, 5825,
23846c92544dSBjoern A. Zeeb 		5845, 5865, 5885, 5905
23856c92544dSBjoern A. Zeeb 	};
23866c92544dSBjoern A. Zeeb 	int offset_2g = ARRAY_SIZE(freq_list);
23876c92544dSBjoern A. Zeeb 	int idx;
23886c92544dSBjoern A. Zeeb 
23896c92544dSBjoern A. Zeeb 	if (freq < 4000) {
23906c92544dSBjoern A. Zeeb 		if (freq < 2432)
23916c92544dSBjoern A. Zeeb 			return offset_2g;
23926c92544dSBjoern A. Zeeb 		if (freq < 2457)
23936c92544dSBjoern A. Zeeb 			return offset_2g + 1;
23946c92544dSBjoern A. Zeeb 
23956c92544dSBjoern A. Zeeb 		return offset_2g + 2;
23966c92544dSBjoern A. Zeeb 	}
23976c92544dSBjoern A. Zeeb 
23986c92544dSBjoern A. Zeeb 	if (bw != NL80211_CHAN_WIDTH_20) {
23996c92544dSBjoern A. Zeeb 		idx = mt7615_find_freq_idx(freq_list, ARRAY_SIZE(freq_list),
24006c92544dSBjoern A. Zeeb 					   freq + 10);
24016c92544dSBjoern A. Zeeb 		if (idx >= 0)
24026c92544dSBjoern A. Zeeb 			return idx;
24036c92544dSBjoern A. Zeeb 
24046c92544dSBjoern A. Zeeb 		idx = mt7615_find_freq_idx(freq_list, ARRAY_SIZE(freq_list),
24056c92544dSBjoern A. Zeeb 					   freq - 10);
24066c92544dSBjoern A. Zeeb 		if (idx >= 0)
24076c92544dSBjoern A. Zeeb 			return idx;
24086c92544dSBjoern A. Zeeb 	}
24096c92544dSBjoern A. Zeeb 
24106c92544dSBjoern A. Zeeb 	return mt7615_find_freq_idx(freq_list, ARRAY_SIZE(freq_list), freq);
24116c92544dSBjoern A. Zeeb }
24126c92544dSBjoern A. Zeeb 
24136c92544dSBjoern A. Zeeb 
24146c92544dSBjoern A. Zeeb int mt7615_mcu_apply_tx_dpd(struct mt7615_phy *phy)
24156c92544dSBjoern A. Zeeb {
24166c92544dSBjoern A. Zeeb 	struct mt7615_dev *dev = phy->dev;
24176c92544dSBjoern A. Zeeb 	struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
24186c92544dSBjoern A. Zeeb 	int freq2 = chandef->center_freq2;
24196c92544dSBjoern A. Zeeb 	int ret;
24206c92544dSBjoern A. Zeeb 	struct {
24216c92544dSBjoern A. Zeeb 		u8 direction;
24226c92544dSBjoern A. Zeeb 		u8 runtime_calibration;
24236c92544dSBjoern A. Zeeb 		u8 _rsv[2];
24246c92544dSBjoern A. Zeeb 
24256c92544dSBjoern A. Zeeb 		__le16 center_freq;
24266c92544dSBjoern A. Zeeb 		u8 bw;
24276c92544dSBjoern A. Zeeb 		u8 band;
24286c92544dSBjoern A. Zeeb 		u8 is_freq2;
24296c92544dSBjoern A. Zeeb 		u8 success;
24306c92544dSBjoern A. Zeeb 		u8 dbdc_en;
24316c92544dSBjoern A. Zeeb 
24326c92544dSBjoern A. Zeeb 		u8 _rsv2;
24336c92544dSBjoern A. Zeeb 
24346c92544dSBjoern A. Zeeb 		struct {
24356c92544dSBjoern A. Zeeb 			struct {
24366c92544dSBjoern A. Zeeb 				u32 dpd_g0;
24376c92544dSBjoern A. Zeeb 				u8 data[32];
24386c92544dSBjoern A. Zeeb 			} wf0, wf1;
24396c92544dSBjoern A. Zeeb 
24406c92544dSBjoern A. Zeeb 			struct {
24416c92544dSBjoern A. Zeeb 				u32 dpd_g0_prim;
24426c92544dSBjoern A. Zeeb 				u32 dpd_g0_sec;
24436c92544dSBjoern A. Zeeb 				u8 data_prim[32];
24446c92544dSBjoern A. Zeeb 				u8 data_sec[32];
24456c92544dSBjoern A. Zeeb 			} wf2, wf3;
24466c92544dSBjoern A. Zeeb 		} dpd_data;
24476c92544dSBjoern A. Zeeb 	} req = {
24486c92544dSBjoern A. Zeeb 		.direction = 1,
24496c92544dSBjoern A. Zeeb 
24506c92544dSBjoern A. Zeeb 		.bw = mt7615_mcu_chan_bw(chandef),
24516c92544dSBjoern A. Zeeb 		.band = chandef->center_freq1 > 4000,
24526c92544dSBjoern A. Zeeb 		.dbdc_en = !!dev->mt76.phys[MT_BAND1],
24536c92544dSBjoern A. Zeeb 	};
24546c92544dSBjoern A. Zeeb 	u16 center_freq = chandef->center_freq1;
24556c92544dSBjoern A. Zeeb 	int freq_idx;
24566c92544dSBjoern A. Zeeb 	u8 *eep = dev->mt76.eeprom.data;
24576c92544dSBjoern A. Zeeb 
24586c92544dSBjoern A. Zeeb 	if (!(eep[MT_EE_CALDATA_FLASH] & MT_EE_CALDATA_FLASH_TX_DPD))
24596c92544dSBjoern A. Zeeb 		return 0;
24606c92544dSBjoern A. Zeeb 
24616c92544dSBjoern A. Zeeb 	if (chandef->width == NL80211_CHAN_WIDTH_160) {
24626c92544dSBjoern A. Zeeb 		freq2 = center_freq + 40;
24636c92544dSBjoern A. Zeeb 		center_freq -= 40;
24646c92544dSBjoern A. Zeeb 	}
24656c92544dSBjoern A. Zeeb 
24666c92544dSBjoern A. Zeeb again:
24676c92544dSBjoern A. Zeeb 	req.runtime_calibration = 1;
24686c92544dSBjoern A. Zeeb 	freq_idx = mt7615_dpd_freq_idx(center_freq, chandef->width);
24696c92544dSBjoern A. Zeeb 	if (freq_idx < 0)
24706c92544dSBjoern A. Zeeb 		goto out;
24716c92544dSBjoern A. Zeeb 
24726c92544dSBjoern A. Zeeb 	memcpy(&req.dpd_data, eep + MT7615_EEPROM_TXDPD_OFFSET +
24736c92544dSBjoern A. Zeeb 			      freq_idx * MT7615_EEPROM_TXDPD_SIZE,
24746c92544dSBjoern A. Zeeb 	       sizeof(req.dpd_data));
24756c92544dSBjoern A. Zeeb 	req.runtime_calibration = 0;
24766c92544dSBjoern A. Zeeb 
24776c92544dSBjoern A. Zeeb out:
24786c92544dSBjoern A. Zeeb 	req.center_freq = cpu_to_le16(center_freq);
24796c92544dSBjoern A. Zeeb 	ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(TXDPD_CAL),
24806c92544dSBjoern A. Zeeb 				&req, sizeof(req), true);
24816c92544dSBjoern A. Zeeb 
24826c92544dSBjoern A. Zeeb 	if ((chandef->width == NL80211_CHAN_WIDTH_80P80 ||
24836c92544dSBjoern A. Zeeb 	     chandef->width == NL80211_CHAN_WIDTH_160) && !req.is_freq2) {
24846c92544dSBjoern A. Zeeb 		req.is_freq2 = true;
24856c92544dSBjoern A. Zeeb 		center_freq = freq2;
24866c92544dSBjoern A. Zeeb 		goto again;
24876c92544dSBjoern A. Zeeb 	}
24886c92544dSBjoern A. Zeeb 
24896c92544dSBjoern A. Zeeb 	return ret;
24906c92544dSBjoern A. Zeeb }
24916c92544dSBjoern A. Zeeb 
24926c92544dSBjoern A. Zeeb int mt7615_mcu_set_rx_hdr_trans_blacklist(struct mt7615_dev *dev)
24936c92544dSBjoern A. Zeeb {
24946c92544dSBjoern A. Zeeb 	struct {
24956c92544dSBjoern A. Zeeb 		u8 operation;
24966c92544dSBjoern A. Zeeb 		u8 count;
24976c92544dSBjoern A. Zeeb 		u8 _rsv[2];
24986c92544dSBjoern A. Zeeb 		u8 index;
24996c92544dSBjoern A. Zeeb 		u8 enable;
25006c92544dSBjoern A. Zeeb 		__le16 etype;
25016c92544dSBjoern A. Zeeb 	} req = {
25026c92544dSBjoern A. Zeeb 		.operation = 1,
25036c92544dSBjoern A. Zeeb 		.count = 1,
25046c92544dSBjoern A. Zeeb 		.enable = 1,
25056c92544dSBjoern A. Zeeb 		.etype = cpu_to_le16(ETH_P_PAE),
25066c92544dSBjoern A. Zeeb 	};
25076c92544dSBjoern A. Zeeb 
25086c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RX_HDR_TRANS),
25096c92544dSBjoern A. Zeeb 				 &req, sizeof(req), false);
25106c92544dSBjoern A. Zeeb }
25116c92544dSBjoern A. Zeeb 
25126c92544dSBjoern A. Zeeb int mt7615_mcu_set_bss_pm(struct mt7615_dev *dev, struct ieee80211_vif *vif,
25136c92544dSBjoern A. Zeeb 			  bool enable)
25146c92544dSBjoern A. Zeeb {
25156c92544dSBjoern A. Zeeb 	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
25166c92544dSBjoern A. Zeeb 	struct {
25176c92544dSBjoern A. Zeeb 		u8 bss_idx;
25186c92544dSBjoern A. Zeeb 		u8 dtim_period;
25196c92544dSBjoern A. Zeeb 		__le16 aid;
25206c92544dSBjoern A. Zeeb 		__le16 bcn_interval;
25216c92544dSBjoern A. Zeeb 		__le16 atim_window;
25226c92544dSBjoern A. Zeeb 		u8 uapsd;
25236c92544dSBjoern A. Zeeb 		u8 bmc_delivered_ac;
25246c92544dSBjoern A. Zeeb 		u8 bmc_triggered_ac;
25256c92544dSBjoern A. Zeeb 		u8 pad;
25266c92544dSBjoern A. Zeeb 	} req = {
25276c92544dSBjoern A. Zeeb 		.bss_idx = mvif->mt76.idx,
25286c92544dSBjoern A. Zeeb 		.aid = cpu_to_le16(vif->cfg.aid),
25296c92544dSBjoern A. Zeeb 		.dtim_period = vif->bss_conf.dtim_period,
25306c92544dSBjoern A. Zeeb 		.bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int),
25316c92544dSBjoern A. Zeeb 	};
25326c92544dSBjoern A. Zeeb 	struct {
25336c92544dSBjoern A. Zeeb 		u8 bss_idx;
25346c92544dSBjoern A. Zeeb 		u8 pad[3];
25356c92544dSBjoern A. Zeeb 	} req_hdr = {
25366c92544dSBjoern A. Zeeb 		.bss_idx = mvif->mt76.idx,
25376c92544dSBjoern A. Zeeb 	};
25386c92544dSBjoern A. Zeeb 	int err;
25396c92544dSBjoern A. Zeeb 
25406c92544dSBjoern A. Zeeb 	if (vif->type != NL80211_IFTYPE_STATION)
25416c92544dSBjoern A. Zeeb 		return 0;
25426c92544dSBjoern A. Zeeb 
25436c92544dSBjoern A. Zeeb 	err = mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_BSS_ABORT),
25446c92544dSBjoern A. Zeeb 				&req_hdr, sizeof(req_hdr), false);
25456c92544dSBjoern A. Zeeb 	if (err < 0 || !enable)
25466c92544dSBjoern A. Zeeb 		return err;
25476c92544dSBjoern A. Zeeb 
25486c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_BSS_CONNECTED),
25496c92544dSBjoern A. Zeeb 				 &req, sizeof(req), false);
25506c92544dSBjoern A. Zeeb }
25516c92544dSBjoern A. Zeeb 
25526c92544dSBjoern A. Zeeb int mt7615_mcu_set_roc(struct mt7615_phy *phy, struct ieee80211_vif *vif,
25536c92544dSBjoern A. Zeeb 		       struct ieee80211_channel *chan, int duration)
25546c92544dSBjoern A. Zeeb {
25556c92544dSBjoern A. Zeeb 	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
25566c92544dSBjoern A. Zeeb 	struct mt7615_dev *dev = phy->dev;
25576c92544dSBjoern A. Zeeb 	struct mt7615_roc_tlv req = {
25586c92544dSBjoern A. Zeeb 		.bss_idx = mvif->mt76.idx,
25596c92544dSBjoern A. Zeeb 		.active = !chan,
25606c92544dSBjoern A. Zeeb 		.max_interval = cpu_to_le32(duration),
25616c92544dSBjoern A. Zeeb 		.primary_chan = chan ? chan->hw_value : 0,
25626c92544dSBjoern A. Zeeb 		.band = chan ? chan->band : 0,
25636c92544dSBjoern A. Zeeb 		.req_type = 2,
25646c92544dSBjoern A. Zeeb 	};
25656c92544dSBjoern A. Zeeb 
25666c92544dSBjoern A. Zeeb 	phy->roc_grant = false;
25676c92544dSBjoern A. Zeeb 
25686c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_ROC),
25696c92544dSBjoern A. Zeeb 				 &req, sizeof(req), false);
25706c92544dSBjoern A. Zeeb }
2571