xref: /freebsd/sys/contrib/dev/mediatek/mt76/mt7603/mcu.c (revision cbb3ec25236ba72f91cbdf23f8b78b9d1af0cedf)
16c92544dSBjoern A. Zeeb // SPDX-License-Identifier: ISC
26c92544dSBjoern A. Zeeb 
36c92544dSBjoern A. Zeeb #include <linux/firmware.h>
46c92544dSBjoern A. Zeeb #include "mt7603.h"
56c92544dSBjoern A. Zeeb #include "mcu.h"
66c92544dSBjoern A. Zeeb #include "eeprom.h"
76c92544dSBjoern A. Zeeb 
86c92544dSBjoern A. Zeeb #define MCU_SKB_RESERVE	8
96c92544dSBjoern A. Zeeb 
106c92544dSBjoern A. Zeeb struct mt7603_fw_trailer {
116c92544dSBjoern A. Zeeb 	char fw_ver[10];
126c92544dSBjoern A. Zeeb 	char build_date[15];
136c92544dSBjoern A. Zeeb 	__le32 dl_len;
146c92544dSBjoern A. Zeeb } __packed;
156c92544dSBjoern A. Zeeb 
166c92544dSBjoern A. Zeeb static int
mt7603_mcu_parse_response(struct mt76_dev * mdev,int cmd,struct sk_buff * skb,int seq)176c92544dSBjoern A. Zeeb mt7603_mcu_parse_response(struct mt76_dev *mdev, int cmd,
186c92544dSBjoern A. Zeeb 			  struct sk_buff *skb, int seq)
196c92544dSBjoern A. Zeeb {
206c92544dSBjoern A. Zeeb 	struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76);
216c92544dSBjoern A. Zeeb 	struct mt7603_mcu_rxd *rxd;
226c92544dSBjoern A. Zeeb 
236c92544dSBjoern A. Zeeb 	if (!skb) {
246c92544dSBjoern A. Zeeb 		dev_err(mdev->dev, "MCU message %02x (seq %d) timed out\n",
256c92544dSBjoern A. Zeeb 			abs(cmd), seq);
266c92544dSBjoern A. Zeeb 		dev->mcu_hang = MT7603_WATCHDOG_TIMEOUT;
276c92544dSBjoern A. Zeeb 		return -ETIMEDOUT;
286c92544dSBjoern A. Zeeb 	}
296c92544dSBjoern A. Zeeb 
306c92544dSBjoern A. Zeeb 	rxd = (struct mt7603_mcu_rxd *)skb->data;
316c92544dSBjoern A. Zeeb 	if (seq != rxd->seq)
326c92544dSBjoern A. Zeeb 		return -EAGAIN;
336c92544dSBjoern A. Zeeb 
346c92544dSBjoern A. Zeeb 	return 0;
356c92544dSBjoern A. Zeeb }
366c92544dSBjoern A. Zeeb 
376c92544dSBjoern A. Zeeb static int
mt7603_mcu_skb_send_msg(struct mt76_dev * mdev,struct sk_buff * skb,int cmd,int * wait_seq)386c92544dSBjoern A. Zeeb mt7603_mcu_skb_send_msg(struct mt76_dev *mdev, struct sk_buff *skb,
396c92544dSBjoern A. Zeeb 			int cmd, int *wait_seq)
406c92544dSBjoern A. Zeeb {
416c92544dSBjoern A. Zeeb 	struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76);
426c92544dSBjoern A. Zeeb 	int hdrlen = dev->mcu_running ? sizeof(struct mt7603_mcu_txd) : 12;
436c92544dSBjoern A. Zeeb 	struct mt7603_mcu_txd *txd;
446c92544dSBjoern A. Zeeb 	u8 seq;
456c92544dSBjoern A. Zeeb 
466c92544dSBjoern A. Zeeb 	mdev->mcu.timeout = 3 * HZ;
476c92544dSBjoern A. Zeeb 
486c92544dSBjoern A. Zeeb 	seq = ++mdev->mcu.msg_seq & 0xf;
496c92544dSBjoern A. Zeeb 	if (!seq)
506c92544dSBjoern A. Zeeb 		seq = ++mdev->mcu.msg_seq & 0xf;
516c92544dSBjoern A. Zeeb 
526c92544dSBjoern A. Zeeb 	txd = (struct mt7603_mcu_txd *)skb_push(skb, hdrlen);
536c92544dSBjoern A. Zeeb 
546c92544dSBjoern A. Zeeb 	txd->len = cpu_to_le16(skb->len);
556c92544dSBjoern A. Zeeb 	if (cmd == -MCU_CMD_FW_SCATTER)
566c92544dSBjoern A. Zeeb 		txd->pq_id = cpu_to_le16(MCU_PORT_QUEUE_FW);
576c92544dSBjoern A. Zeeb 	else
586c92544dSBjoern A. Zeeb 		txd->pq_id = cpu_to_le16(MCU_PORT_QUEUE);
596c92544dSBjoern A. Zeeb 	txd->pkt_type = MCU_PKT_ID;
606c92544dSBjoern A. Zeeb 	txd->seq = seq;
616c92544dSBjoern A. Zeeb 
626c92544dSBjoern A. Zeeb 	if (cmd < 0) {
636c92544dSBjoern A. Zeeb 		txd->cid = -cmd;
646c92544dSBjoern A. Zeeb 		txd->set_query = MCU_Q_NA;
656c92544dSBjoern A. Zeeb 	} else {
666c92544dSBjoern A. Zeeb 		txd->cid = MCU_CMD_EXT_CID;
676c92544dSBjoern A. Zeeb 		txd->ext_cid = cmd;
686c92544dSBjoern A. Zeeb 		txd->set_query = MCU_Q_SET;
696c92544dSBjoern A. Zeeb 		txd->ext_cid_ack = 1;
706c92544dSBjoern A. Zeeb 	}
716c92544dSBjoern A. Zeeb 
726c92544dSBjoern A. Zeeb 	if (wait_seq)
736c92544dSBjoern A. Zeeb 		*wait_seq = seq;
746c92544dSBjoern A. Zeeb 
756c92544dSBjoern A. Zeeb 	return mt76_tx_queue_skb_raw(dev, mdev->q_mcu[MT_MCUQ_WM], skb, 0);
766c92544dSBjoern A. Zeeb }
776c92544dSBjoern A. Zeeb 
786c92544dSBjoern A. Zeeb static int
mt7603_mcu_init_download(struct mt7603_dev * dev,u32 addr,u32 len)796c92544dSBjoern A. Zeeb mt7603_mcu_init_download(struct mt7603_dev *dev, u32 addr, u32 len)
806c92544dSBjoern A. Zeeb {
816c92544dSBjoern A. Zeeb 	struct {
826c92544dSBjoern A. Zeeb 		__le32 addr;
836c92544dSBjoern A. Zeeb 		__le32 len;
846c92544dSBjoern A. Zeeb 		__le32 mode;
856c92544dSBjoern A. Zeeb 	} req = {
866c92544dSBjoern A. Zeeb 		.addr = cpu_to_le32(addr),
876c92544dSBjoern A. Zeeb 		.len = cpu_to_le32(len),
886c92544dSBjoern A. Zeeb 		.mode = cpu_to_le32(BIT(31)),
896c92544dSBjoern A. Zeeb 	};
906c92544dSBjoern A. Zeeb 
916c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_TARGET_ADDRESS_LEN_REQ,
926c92544dSBjoern A. Zeeb 				 &req, sizeof(req), true);
936c92544dSBjoern A. Zeeb }
946c92544dSBjoern A. Zeeb 
956c92544dSBjoern A. Zeeb static int
mt7603_mcu_start_firmware(struct mt7603_dev * dev,u32 addr)966c92544dSBjoern A. Zeeb mt7603_mcu_start_firmware(struct mt7603_dev *dev, u32 addr)
976c92544dSBjoern A. Zeeb {
986c92544dSBjoern A. Zeeb 	struct {
996c92544dSBjoern A. Zeeb 		__le32 override;
1006c92544dSBjoern A. Zeeb 		__le32 addr;
1016c92544dSBjoern A. Zeeb 	} req = {
1026c92544dSBjoern A. Zeeb 		.override = cpu_to_le32(addr ? 1 : 0),
1036c92544dSBjoern A. Zeeb 		.addr = cpu_to_le32(addr),
1046c92544dSBjoern A. Zeeb 	};
1056c92544dSBjoern A. Zeeb 
1066c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_FW_START_REQ, &req,
1076c92544dSBjoern A. Zeeb 				 sizeof(req), true);
1086c92544dSBjoern A. Zeeb }
1096c92544dSBjoern A. Zeeb 
1106c92544dSBjoern A. Zeeb static int
mt7603_mcu_restart(struct mt76_dev * dev)1116c92544dSBjoern A. Zeeb mt7603_mcu_restart(struct mt76_dev *dev)
1126c92544dSBjoern A. Zeeb {
1136c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(dev, -MCU_CMD_RESTART_DL_REQ, NULL, 0, true);
1146c92544dSBjoern A. Zeeb }
1156c92544dSBjoern A. Zeeb 
mt7603_load_firmware(struct mt7603_dev * dev)1166c92544dSBjoern A. Zeeb static int mt7603_load_firmware(struct mt7603_dev *dev)
1176c92544dSBjoern A. Zeeb {
1186c92544dSBjoern A. Zeeb 	const struct firmware *fw;
1196c92544dSBjoern A. Zeeb 	const struct mt7603_fw_trailer *hdr;
1206c92544dSBjoern A. Zeeb 	const char *firmware;
1216c92544dSBjoern A. Zeeb 	int dl_len;
1226c92544dSBjoern A. Zeeb 	u32 addr, val;
1236c92544dSBjoern A. Zeeb 	int ret;
1246c92544dSBjoern A. Zeeb 
1256c92544dSBjoern A. Zeeb 	if (is_mt7628(dev)) {
1266c92544dSBjoern A. Zeeb 		if (mt76xx_rev(dev) == MT7628_REV_E1)
1276c92544dSBjoern A. Zeeb 			firmware = MT7628_FIRMWARE_E1;
1286c92544dSBjoern A. Zeeb 		else
1296c92544dSBjoern A. Zeeb 			firmware = MT7628_FIRMWARE_E2;
1306c92544dSBjoern A. Zeeb 	} else {
1316c92544dSBjoern A. Zeeb 		if (mt76xx_rev(dev) < MT7603_REV_E2)
1326c92544dSBjoern A. Zeeb 			firmware = MT7603_FIRMWARE_E1;
1336c92544dSBjoern A. Zeeb 		else
1346c92544dSBjoern A. Zeeb 			firmware = MT7603_FIRMWARE_E2;
1356c92544dSBjoern A. Zeeb 	}
1366c92544dSBjoern A. Zeeb 
1376c92544dSBjoern A. Zeeb 	ret = request_firmware(&fw, firmware, dev->mt76.dev);
1386c92544dSBjoern A. Zeeb 	if (ret)
1396c92544dSBjoern A. Zeeb 		return ret;
1406c92544dSBjoern A. Zeeb 
1416c92544dSBjoern A. Zeeb 	if (!fw || !fw->data || fw->size < sizeof(*hdr)) {
1426c92544dSBjoern A. Zeeb 		dev_err(dev->mt76.dev, "Invalid firmware\n");
1436c92544dSBjoern A. Zeeb 		ret = -EINVAL;
1446c92544dSBjoern A. Zeeb 		goto out;
1456c92544dSBjoern A. Zeeb 	}
1466c92544dSBjoern A. Zeeb 
1476c92544dSBjoern A. Zeeb 	hdr = (const struct mt7603_fw_trailer *)(fw->data + fw->size -
1486c92544dSBjoern A. Zeeb 						 sizeof(*hdr));
1496c92544dSBjoern A. Zeeb 
1506c92544dSBjoern A. Zeeb 	dev_info(dev->mt76.dev, "Firmware Version: %.10s\n", hdr->fw_ver);
1516c92544dSBjoern A. Zeeb 	dev_info(dev->mt76.dev, "Build Time: %.15s\n", hdr->build_date);
1526c92544dSBjoern A. Zeeb 
1536c92544dSBjoern A. Zeeb 	addr = mt7603_reg_map(dev, 0x50012498);
1546c92544dSBjoern A. Zeeb 	mt76_wr(dev, addr, 0x5);
1556c92544dSBjoern A. Zeeb 	mt76_wr(dev, addr, 0x5);
1566c92544dSBjoern A. Zeeb 	udelay(1);
1576c92544dSBjoern A. Zeeb 
1586c92544dSBjoern A. Zeeb 	/* switch to bypass mode */
1596c92544dSBjoern A. Zeeb 	mt76_rmw(dev, MT_SCH_4, MT_SCH_4_FORCE_QID,
1606c92544dSBjoern A. Zeeb 		 MT_SCH_4_BYPASS | FIELD_PREP(MT_SCH_4_FORCE_QID, 5));
1616c92544dSBjoern A. Zeeb 
1626c92544dSBjoern A. Zeeb 	val = mt76_rr(dev, MT_TOP_MISC2);
1636c92544dSBjoern A. Zeeb 	if (val & BIT(1)) {
1646c92544dSBjoern A. Zeeb 		dev_info(dev->mt76.dev, "Firmware already running...\n");
1656c92544dSBjoern A. Zeeb 		goto running;
1666c92544dSBjoern A. Zeeb 	}
1676c92544dSBjoern A. Zeeb 
1686c92544dSBjoern A. Zeeb 	if (!mt76_poll_msec(dev, MT_TOP_MISC2, BIT(0) | BIT(1), BIT(0), 500)) {
1696c92544dSBjoern A. Zeeb 		dev_err(dev->mt76.dev, "Timeout waiting for ROM code to become ready\n");
1706c92544dSBjoern A. Zeeb 		ret = -EIO;
1716c92544dSBjoern A. Zeeb 		goto out;
1726c92544dSBjoern A. Zeeb 	}
1736c92544dSBjoern A. Zeeb 
1746c92544dSBjoern A. Zeeb 	dl_len = le32_to_cpu(hdr->dl_len) + 4;
1756c92544dSBjoern A. Zeeb 	ret = mt7603_mcu_init_download(dev, MCU_FIRMWARE_ADDRESS, dl_len);
1766c92544dSBjoern A. Zeeb 	if (ret) {
1776c92544dSBjoern A. Zeeb 		dev_err(dev->mt76.dev, "Download request failed\n");
1786c92544dSBjoern A. Zeeb 		goto out;
1796c92544dSBjoern A. Zeeb 	}
1806c92544dSBjoern A. Zeeb 
1816c92544dSBjoern A. Zeeb 	ret = mt76_mcu_send_firmware(&dev->mt76, -MCU_CMD_FW_SCATTER,
1826c92544dSBjoern A. Zeeb 				     fw->data, dl_len);
1836c92544dSBjoern A. Zeeb 	if (ret) {
1846c92544dSBjoern A. Zeeb 		dev_err(dev->mt76.dev, "Failed to send firmware to device\n");
1856c92544dSBjoern A. Zeeb 		goto out;
1866c92544dSBjoern A. Zeeb 	}
1876c92544dSBjoern A. Zeeb 
1886c92544dSBjoern A. Zeeb 	ret = mt7603_mcu_start_firmware(dev, MCU_FIRMWARE_ADDRESS);
1896c92544dSBjoern A. Zeeb 	if (ret) {
1906c92544dSBjoern A. Zeeb 		dev_err(dev->mt76.dev, "Failed to start firmware\n");
1916c92544dSBjoern A. Zeeb 		goto out;
1926c92544dSBjoern A. Zeeb 	}
1936c92544dSBjoern A. Zeeb 
1946c92544dSBjoern A. Zeeb 	if (!mt76_poll_msec(dev, MT_TOP_MISC2, BIT(1), BIT(1), 500)) {
1956c92544dSBjoern A. Zeeb 		dev_err(dev->mt76.dev, "Timeout waiting for firmware to initialize\n");
1966c92544dSBjoern A. Zeeb 		ret = -EIO;
1976c92544dSBjoern A. Zeeb 		goto out;
1986c92544dSBjoern A. Zeeb 	}
1996c92544dSBjoern A. Zeeb 
2006c92544dSBjoern A. Zeeb running:
2016c92544dSBjoern A. Zeeb 	mt76_clear(dev, MT_SCH_4, MT_SCH_4_FORCE_QID | MT_SCH_4_BYPASS);
2026c92544dSBjoern A. Zeeb 
2036c92544dSBjoern A. Zeeb 	mt76_set(dev, MT_SCH_4, BIT(8));
2046c92544dSBjoern A. Zeeb 	mt76_clear(dev, MT_SCH_4, BIT(8));
2056c92544dSBjoern A. Zeeb 
2066c92544dSBjoern A. Zeeb 	dev->mcu_running = true;
2076c92544dSBjoern A. Zeeb 	snprintf(dev->mt76.hw->wiphy->fw_version,
2086c92544dSBjoern A. Zeeb 		 sizeof(dev->mt76.hw->wiphy->fw_version),
2096c92544dSBjoern A. Zeeb 		 "%.10s-%.15s", hdr->fw_ver, hdr->build_date);
2106c92544dSBjoern A. Zeeb 	dev_info(dev->mt76.dev, "firmware init done\n");
2116c92544dSBjoern A. Zeeb 
2126c92544dSBjoern A. Zeeb out:
2136c92544dSBjoern A. Zeeb 	release_firmware(fw);
2146c92544dSBjoern A. Zeeb 
2156c92544dSBjoern A. Zeeb 	return ret;
2166c92544dSBjoern A. Zeeb }
2176c92544dSBjoern A. Zeeb 
mt7603_mcu_init(struct mt7603_dev * dev)2186c92544dSBjoern A. Zeeb int mt7603_mcu_init(struct mt7603_dev *dev)
2196c92544dSBjoern A. Zeeb {
2206c92544dSBjoern A. Zeeb 	static const struct mt76_mcu_ops mt7603_mcu_ops = {
2216c92544dSBjoern A. Zeeb 		.headroom = sizeof(struct mt7603_mcu_txd),
2226c92544dSBjoern A. Zeeb 		.mcu_skb_send_msg = mt7603_mcu_skb_send_msg,
2236c92544dSBjoern A. Zeeb 		.mcu_parse_response = mt7603_mcu_parse_response,
2246c92544dSBjoern A. Zeeb 	};
2256c92544dSBjoern A. Zeeb 
2266c92544dSBjoern A. Zeeb 	dev->mt76.mcu_ops = &mt7603_mcu_ops;
2276c92544dSBjoern A. Zeeb 	return mt7603_load_firmware(dev);
2286c92544dSBjoern A. Zeeb }
2296c92544dSBjoern A. Zeeb 
mt7603_mcu_exit(struct mt7603_dev * dev)2306c92544dSBjoern A. Zeeb void mt7603_mcu_exit(struct mt7603_dev *dev)
2316c92544dSBjoern A. Zeeb {
232*cbb3ec25SBjoern A. Zeeb 	mt7603_mcu_restart(&dev->mt76);
2336c92544dSBjoern A. Zeeb 	skb_queue_purge(&dev->mt76.mcu.res_q);
2346c92544dSBjoern A. Zeeb }
2356c92544dSBjoern A. Zeeb 
mt7603_mcu_set_eeprom(struct mt7603_dev * dev)2366c92544dSBjoern A. Zeeb int mt7603_mcu_set_eeprom(struct mt7603_dev *dev)
2376c92544dSBjoern A. Zeeb {
2386c92544dSBjoern A. Zeeb 	static const u16 req_fields[] = {
2396c92544dSBjoern A. Zeeb #define WORD(_start)			\
2406c92544dSBjoern A. Zeeb 		_start,			\
2416c92544dSBjoern A. Zeeb 		_start + 1
2426c92544dSBjoern A. Zeeb #define GROUP_2G(_start)		\
2436c92544dSBjoern A. Zeeb 		WORD(_start),		\
2446c92544dSBjoern A. Zeeb 		WORD(_start + 2),	\
2456c92544dSBjoern A. Zeeb 		WORD(_start + 4)
2466c92544dSBjoern A. Zeeb 
2476c92544dSBjoern A. Zeeb 		MT_EE_NIC_CONF_0 + 1,
2486c92544dSBjoern A. Zeeb 		WORD(MT_EE_NIC_CONF_1),
2496c92544dSBjoern A. Zeeb 		MT_EE_WIFI_RF_SETTING,
2506c92544dSBjoern A. Zeeb 		MT_EE_TX_POWER_DELTA_BW40,
2516c92544dSBjoern A. Zeeb 		MT_EE_TX_POWER_DELTA_BW80 + 1,
2526c92544dSBjoern A. Zeeb 		MT_EE_TX_POWER_EXT_PA_5G,
2536c92544dSBjoern A. Zeeb 		MT_EE_TEMP_SENSOR_CAL,
2546c92544dSBjoern A. Zeeb 		GROUP_2G(MT_EE_TX_POWER_0_START_2G),
2556c92544dSBjoern A. Zeeb 		GROUP_2G(MT_EE_TX_POWER_1_START_2G),
2566c92544dSBjoern A. Zeeb 		WORD(MT_EE_TX_POWER_CCK),
2576c92544dSBjoern A. Zeeb 		WORD(MT_EE_TX_POWER_OFDM_2G_6M),
2586c92544dSBjoern A. Zeeb 		WORD(MT_EE_TX_POWER_OFDM_2G_24M),
2596c92544dSBjoern A. Zeeb 		WORD(MT_EE_TX_POWER_OFDM_2G_54M),
2606c92544dSBjoern A. Zeeb 		WORD(MT_EE_TX_POWER_HT_BPSK_QPSK),
2616c92544dSBjoern A. Zeeb 		WORD(MT_EE_TX_POWER_HT_16_64_QAM),
2626c92544dSBjoern A. Zeeb 		WORD(MT_EE_TX_POWER_HT_64_QAM),
2636c92544dSBjoern A. Zeeb 		MT_EE_ELAN_RX_MODE_GAIN,
2646c92544dSBjoern A. Zeeb 		MT_EE_ELAN_RX_MODE_NF,
2656c92544dSBjoern A. Zeeb 		MT_EE_ELAN_RX_MODE_P1DB,
2666c92544dSBjoern A. Zeeb 		MT_EE_ELAN_BYPASS_MODE_GAIN,
2676c92544dSBjoern A. Zeeb 		MT_EE_ELAN_BYPASS_MODE_NF,
2686c92544dSBjoern A. Zeeb 		MT_EE_ELAN_BYPASS_MODE_P1DB,
2696c92544dSBjoern A. Zeeb 		WORD(MT_EE_STEP_NUM_NEG_6_7),
2706c92544dSBjoern A. Zeeb 		WORD(MT_EE_STEP_NUM_NEG_4_5),
2716c92544dSBjoern A. Zeeb 		WORD(MT_EE_STEP_NUM_NEG_2_3),
2726c92544dSBjoern A. Zeeb 		WORD(MT_EE_STEP_NUM_NEG_0_1),
2736c92544dSBjoern A. Zeeb 		WORD(MT_EE_REF_STEP_24G),
2746c92544dSBjoern A. Zeeb 		WORD(MT_EE_STEP_NUM_PLUS_1_2),
2756c92544dSBjoern A. Zeeb 		WORD(MT_EE_STEP_NUM_PLUS_3_4),
2766c92544dSBjoern A. Zeeb 		WORD(MT_EE_STEP_NUM_PLUS_5_6),
2776c92544dSBjoern A. Zeeb 		MT_EE_STEP_NUM_PLUS_7,
2786c92544dSBjoern A. Zeeb 		MT_EE_XTAL_FREQ_OFFSET,
2796c92544dSBjoern A. Zeeb 		MT_EE_XTAL_TRIM_2_COMP,
2806c92544dSBjoern A. Zeeb 		MT_EE_XTAL_TRIM_3_COMP,
2816c92544dSBjoern A. Zeeb 		MT_EE_XTAL_WF_RFCAL,
2826c92544dSBjoern A. Zeeb 
2836c92544dSBjoern A. Zeeb 		/* unknown fields below */
2846c92544dSBjoern A. Zeeb 		WORD(0x24),
2856c92544dSBjoern A. Zeeb 		0x34,
2866c92544dSBjoern A. Zeeb 		0x39,
2876c92544dSBjoern A. Zeeb 		0x3b,
2886c92544dSBjoern A. Zeeb 		WORD(0x42),
2896c92544dSBjoern A. Zeeb 		WORD(0x9e),
2906c92544dSBjoern A. Zeeb 		0xf2,
2916c92544dSBjoern A. Zeeb 		WORD(0xf8),
2926c92544dSBjoern A. Zeeb 		0xfa,
2936c92544dSBjoern A. Zeeb 		0x12e,
2946c92544dSBjoern A. Zeeb 		WORD(0x130), WORD(0x132), WORD(0x134), WORD(0x136),
2956c92544dSBjoern A. Zeeb 		WORD(0x138), WORD(0x13a), WORD(0x13c), WORD(0x13e),
2966c92544dSBjoern A. Zeeb 
2976c92544dSBjoern A. Zeeb #undef GROUP_2G
2986c92544dSBjoern A. Zeeb #undef WORD
2996c92544dSBjoern A. Zeeb 
3006c92544dSBjoern A. Zeeb 	};
3016c92544dSBjoern A. Zeeb 	struct req_data {
3026c92544dSBjoern A. Zeeb 		__le16 addr;
3036c92544dSBjoern A. Zeeb 		u8 val;
3046c92544dSBjoern A. Zeeb 		u8 pad;
3056c92544dSBjoern A. Zeeb 	} __packed;
3066c92544dSBjoern A. Zeeb 	struct {
3076c92544dSBjoern A. Zeeb 		u8 buffer_mode;
3086c92544dSBjoern A. Zeeb 		u8 len;
3096c92544dSBjoern A. Zeeb 		u8 pad[2];
3106c92544dSBjoern A. Zeeb 	} req_hdr = {
3116c92544dSBjoern A. Zeeb 		.buffer_mode = 1,
3126c92544dSBjoern A. Zeeb 		.len = ARRAY_SIZE(req_fields) - 1,
3136c92544dSBjoern A. Zeeb 	};
3146c92544dSBjoern A. Zeeb 	const int size = 0xff * sizeof(struct req_data);
3156c92544dSBjoern A. Zeeb 	u8 *req, *eep = (u8 *)dev->mt76.eeprom.data;
3166c92544dSBjoern A. Zeeb 	int i, ret, len = sizeof(req_hdr) + size;
3176c92544dSBjoern A. Zeeb 	struct req_data *data;
3186c92544dSBjoern A. Zeeb 
3196c92544dSBjoern A. Zeeb 	BUILD_BUG_ON(ARRAY_SIZE(req_fields) * sizeof(*data) > size);
3206c92544dSBjoern A. Zeeb 
3216c92544dSBjoern A. Zeeb 	req = kmalloc(len, GFP_KERNEL);
3226c92544dSBjoern A. Zeeb 	if (!req)
3236c92544dSBjoern A. Zeeb 		return -ENOMEM;
3246c92544dSBjoern A. Zeeb 
3256c92544dSBjoern A. Zeeb 	memcpy(req, &req_hdr, sizeof(req_hdr));
3266c92544dSBjoern A. Zeeb 	data = (struct req_data *)(req + sizeof(req_hdr));
3276c92544dSBjoern A. Zeeb 	memset(data, 0, size);
3286c92544dSBjoern A. Zeeb 	for (i = 0; i < ARRAY_SIZE(req_fields); i++) {
3296c92544dSBjoern A. Zeeb 		data[i].addr = cpu_to_le16(req_fields[i]);
3306c92544dSBjoern A. Zeeb 		data[i].val = eep[req_fields[i]];
3316c92544dSBjoern A. Zeeb 	}
3326c92544dSBjoern A. Zeeb 
3336c92544dSBjoern A. Zeeb 	ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EFUSE_BUFFER_MODE,
3346c92544dSBjoern A. Zeeb 				req, len, true);
3356c92544dSBjoern A. Zeeb 	kfree(req);
3366c92544dSBjoern A. Zeeb 
3376c92544dSBjoern A. Zeeb 	return ret;
3386c92544dSBjoern A. Zeeb }
3396c92544dSBjoern A. Zeeb 
mt7603_mcu_set_tx_power(struct mt7603_dev * dev)3406c92544dSBjoern A. Zeeb static int mt7603_mcu_set_tx_power(struct mt7603_dev *dev)
3416c92544dSBjoern A. Zeeb {
3426c92544dSBjoern A. Zeeb 	struct {
3436c92544dSBjoern A. Zeeb 		u8 center_channel;
3446c92544dSBjoern A. Zeeb 		u8 tssi;
3456c92544dSBjoern A. Zeeb 		u8 temp_comp;
3466c92544dSBjoern A. Zeeb 		u8 target_power[2];
3476c92544dSBjoern A. Zeeb 		u8 rate_power_delta[14];
3486c92544dSBjoern A. Zeeb 		u8 bw_power_delta;
3496c92544dSBjoern A. Zeeb 		u8 ch_power_delta[6];
3506c92544dSBjoern A. Zeeb 		u8 temp_comp_power[17];
3516c92544dSBjoern A. Zeeb 		u8 reserved;
3526c92544dSBjoern A. Zeeb 	} req = {
3536c92544dSBjoern A. Zeeb 		.center_channel = dev->mphy.chandef.chan->hw_value,
3546c92544dSBjoern A. Zeeb #define EEP_VAL(n) ((u8 *)dev->mt76.eeprom.data)[n]
3556c92544dSBjoern A. Zeeb 		.tssi = EEP_VAL(MT_EE_NIC_CONF_1 + 1),
3566c92544dSBjoern A. Zeeb 		.temp_comp = EEP_VAL(MT_EE_NIC_CONF_1),
3576c92544dSBjoern A. Zeeb 		.target_power = {
3586c92544dSBjoern A. Zeeb 			EEP_VAL(MT_EE_TX_POWER_0_START_2G + 2),
3596c92544dSBjoern A. Zeeb 			EEP_VAL(MT_EE_TX_POWER_1_START_2G + 2)
3606c92544dSBjoern A. Zeeb 		},
3616c92544dSBjoern A. Zeeb 		.bw_power_delta = EEP_VAL(MT_EE_TX_POWER_DELTA_BW40),
3626c92544dSBjoern A. Zeeb 		.ch_power_delta = {
3636c92544dSBjoern A. Zeeb 			EEP_VAL(MT_EE_TX_POWER_0_START_2G + 3),
3646c92544dSBjoern A. Zeeb 			EEP_VAL(MT_EE_TX_POWER_0_START_2G + 4),
3656c92544dSBjoern A. Zeeb 			EEP_VAL(MT_EE_TX_POWER_0_START_2G + 5),
3666c92544dSBjoern A. Zeeb 			EEP_VAL(MT_EE_TX_POWER_1_START_2G + 3),
3676c92544dSBjoern A. Zeeb 			EEP_VAL(MT_EE_TX_POWER_1_START_2G + 4),
3686c92544dSBjoern A. Zeeb 			EEP_VAL(MT_EE_TX_POWER_1_START_2G + 5)
3696c92544dSBjoern A. Zeeb 		},
3706c92544dSBjoern A. Zeeb #undef EEP_VAL
3716c92544dSBjoern A. Zeeb 	};
3726c92544dSBjoern A. Zeeb 	u8 *eep = (u8 *)dev->mt76.eeprom.data;
3736c92544dSBjoern A. Zeeb 
3746c92544dSBjoern A. Zeeb 	memcpy(req.rate_power_delta, eep + MT_EE_TX_POWER_CCK,
3756c92544dSBjoern A. Zeeb 	       sizeof(req.rate_power_delta));
3766c92544dSBjoern A. Zeeb 
3776c92544dSBjoern A. Zeeb 	memcpy(req.temp_comp_power, eep + MT_EE_STEP_NUM_NEG_6_7,
3786c92544dSBjoern A. Zeeb 	       sizeof(req.temp_comp_power));
3796c92544dSBjoern A. Zeeb 
3806c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_TX_POWER_CTRL,
3816c92544dSBjoern A. Zeeb 				 &req, sizeof(req), true);
3826c92544dSBjoern A. Zeeb }
3836c92544dSBjoern A. Zeeb 
mt7603_mcu_set_channel(struct mt7603_dev * dev)3846c92544dSBjoern A. Zeeb int mt7603_mcu_set_channel(struct mt7603_dev *dev)
3856c92544dSBjoern A. Zeeb {
3866c92544dSBjoern A. Zeeb 	struct cfg80211_chan_def *chandef = &dev->mphy.chandef;
3876c92544dSBjoern A. Zeeb 	struct ieee80211_hw *hw = mt76_hw(dev);
3886c92544dSBjoern A. Zeeb 	int n_chains = hweight8(dev->mphy.antenna_mask);
3896c92544dSBjoern A. Zeeb 	struct {
3906c92544dSBjoern A. Zeeb 		u8 control_chan;
3916c92544dSBjoern A. Zeeb 		u8 center_chan;
3926c92544dSBjoern A. Zeeb 		u8 bw;
3936c92544dSBjoern A. Zeeb 		u8 tx_streams;
3946c92544dSBjoern A. Zeeb 		u8 rx_streams;
3956c92544dSBjoern A. Zeeb 		u8 _res0[7];
3966c92544dSBjoern A. Zeeb 		u8 txpower[21];
3976c92544dSBjoern A. Zeeb 		u8 _res1[3];
3986c92544dSBjoern A. Zeeb 	} req = {
3996c92544dSBjoern A. Zeeb 		.control_chan = chandef->chan->hw_value,
4006c92544dSBjoern A. Zeeb 		.center_chan = chandef->chan->hw_value,
4016c92544dSBjoern A. Zeeb 		.bw = MT_BW_20,
4026c92544dSBjoern A. Zeeb 		.tx_streams = n_chains,
4036c92544dSBjoern A. Zeeb 		.rx_streams = n_chains,
4046c92544dSBjoern A. Zeeb 	};
4056c92544dSBjoern A. Zeeb 	s8 tx_power = hw->conf.power_level * 2;
4066c92544dSBjoern A. Zeeb 	int i, ret;
4076c92544dSBjoern A. Zeeb 
4086c92544dSBjoern A. Zeeb 	if (dev->mphy.chandef.width == NL80211_CHAN_WIDTH_40) {
4096c92544dSBjoern A. Zeeb 		req.bw = MT_BW_40;
4106c92544dSBjoern A. Zeeb 		if (chandef->center_freq1 > chandef->chan->center_freq)
4116c92544dSBjoern A. Zeeb 			req.center_chan += 2;
4126c92544dSBjoern A. Zeeb 		else
4136c92544dSBjoern A. Zeeb 			req.center_chan -= 2;
4146c92544dSBjoern A. Zeeb 	}
4156c92544dSBjoern A. Zeeb 
4166c92544dSBjoern A. Zeeb 	tx_power = mt76_get_sar_power(&dev->mphy, chandef->chan, tx_power);
4176c92544dSBjoern A. Zeeb 	if (dev->mphy.antenna_mask == 3)
4186c92544dSBjoern A. Zeeb 		tx_power -= 6;
4196c92544dSBjoern A. Zeeb 	tx_power = min(tx_power, dev->tx_power_limit);
4206c92544dSBjoern A. Zeeb 
4216c92544dSBjoern A. Zeeb 	dev->mphy.txpower_cur = tx_power;
4226c92544dSBjoern A. Zeeb 
4236c92544dSBjoern A. Zeeb 	for (i = 0; i < ARRAY_SIZE(req.txpower); i++)
4246c92544dSBjoern A. Zeeb 		req.txpower[i] = tx_power;
4256c92544dSBjoern A. Zeeb 
4266c92544dSBjoern A. Zeeb 	ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_CHANNEL_SWITCH, &req,
4276c92544dSBjoern A. Zeeb 				sizeof(req), true);
4286c92544dSBjoern A. Zeeb 	if (ret)
4296c92544dSBjoern A. Zeeb 		return ret;
4306c92544dSBjoern A. Zeeb 
4316c92544dSBjoern A. Zeeb 	return mt7603_mcu_set_tx_power(dev);
4326c92544dSBjoern A. Zeeb }
433