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