18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: ISC
28c2ecf20Sopenharmony_ci
38c2ecf20Sopenharmony_ci#include <linux/firmware.h>
48c2ecf20Sopenharmony_ci#include "mt7603.h"
58c2ecf20Sopenharmony_ci#include "mcu.h"
68c2ecf20Sopenharmony_ci#include "eeprom.h"
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#define MCU_SKB_RESERVE	8
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_cistruct mt7603_fw_trailer {
118c2ecf20Sopenharmony_ci	char fw_ver[10];
128c2ecf20Sopenharmony_ci	char build_date[15];
138c2ecf20Sopenharmony_ci	__le32 dl_len;
148c2ecf20Sopenharmony_ci} __packed;
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_cistatic int
178c2ecf20Sopenharmony_ci__mt7603_mcu_msg_send(struct mt7603_dev *dev, struct sk_buff *skb,
188c2ecf20Sopenharmony_ci		      int cmd, int *wait_seq)
198c2ecf20Sopenharmony_ci{
208c2ecf20Sopenharmony_ci	int hdrlen = dev->mcu_running ? sizeof(struct mt7603_mcu_txd) : 12;
218c2ecf20Sopenharmony_ci	struct mt76_dev *mdev = &dev->mt76;
228c2ecf20Sopenharmony_ci	struct mt7603_mcu_txd *txd;
238c2ecf20Sopenharmony_ci	u8 seq;
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci	seq = ++mdev->mcu.msg_seq & 0xf;
268c2ecf20Sopenharmony_ci	if (!seq)
278c2ecf20Sopenharmony_ci		seq = ++mdev->mcu.msg_seq & 0xf;
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci	txd = (struct mt7603_mcu_txd *)skb_push(skb, hdrlen);
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci	txd->len = cpu_to_le16(skb->len);
328c2ecf20Sopenharmony_ci	if (cmd == -MCU_CMD_FW_SCATTER)
338c2ecf20Sopenharmony_ci		txd->pq_id = cpu_to_le16(MCU_PORT_QUEUE_FW);
348c2ecf20Sopenharmony_ci	else
358c2ecf20Sopenharmony_ci		txd->pq_id = cpu_to_le16(MCU_PORT_QUEUE);
368c2ecf20Sopenharmony_ci	txd->pkt_type = MCU_PKT_ID;
378c2ecf20Sopenharmony_ci	txd->seq = seq;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	if (cmd < 0) {
408c2ecf20Sopenharmony_ci		txd->cid = -cmd;
418c2ecf20Sopenharmony_ci		txd->set_query = MCU_Q_NA;
428c2ecf20Sopenharmony_ci	} else {
438c2ecf20Sopenharmony_ci		txd->cid = MCU_CMD_EXT_CID;
448c2ecf20Sopenharmony_ci		txd->ext_cid = cmd;
458c2ecf20Sopenharmony_ci		txd->set_query = MCU_Q_SET;
468c2ecf20Sopenharmony_ci		txd->ext_cid_ack = 1;
478c2ecf20Sopenharmony_ci	}
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	if (wait_seq)
508c2ecf20Sopenharmony_ci		*wait_seq = seq;
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	return mt76_tx_queue_skb_raw(dev, MT_TXQ_MCU, skb, 0);
538c2ecf20Sopenharmony_ci}
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_cistatic int
568c2ecf20Sopenharmony_cimt7603_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data,
578c2ecf20Sopenharmony_ci		    int len, bool wait_resp)
588c2ecf20Sopenharmony_ci{
598c2ecf20Sopenharmony_ci	struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76);
608c2ecf20Sopenharmony_ci	unsigned long expires = jiffies + 3 * HZ;
618c2ecf20Sopenharmony_ci	struct mt7603_mcu_rxd *rxd;
628c2ecf20Sopenharmony_ci	struct sk_buff *skb;
638c2ecf20Sopenharmony_ci	int ret, seq;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	skb = mt76_mcu_msg_alloc(mdev, data, len);
668c2ecf20Sopenharmony_ci	if (!skb)
678c2ecf20Sopenharmony_ci		return -ENOMEM;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	mutex_lock(&mdev->mcu.mutex);
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	ret = __mt7603_mcu_msg_send(dev, skb, cmd, &seq);
728c2ecf20Sopenharmony_ci	if (ret)
738c2ecf20Sopenharmony_ci		goto out;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	while (wait_resp) {
768c2ecf20Sopenharmony_ci		bool check_seq = false;
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci		skb = mt76_mcu_get_response(&dev->mt76, expires);
798c2ecf20Sopenharmony_ci		if (!skb) {
808c2ecf20Sopenharmony_ci			dev_err(mdev->dev,
818c2ecf20Sopenharmony_ci				"MCU message %d (seq %d) timed out\n",
828c2ecf20Sopenharmony_ci				cmd, seq);
838c2ecf20Sopenharmony_ci			dev->mcu_hang = MT7603_WATCHDOG_TIMEOUT;
848c2ecf20Sopenharmony_ci			ret = -ETIMEDOUT;
858c2ecf20Sopenharmony_ci			break;
868c2ecf20Sopenharmony_ci		}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci		rxd = (struct mt7603_mcu_rxd *)skb->data;
898c2ecf20Sopenharmony_ci		if (seq == rxd->seq)
908c2ecf20Sopenharmony_ci			check_seq = true;
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci		dev_kfree_skb(skb);
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci		if (check_seq)
958c2ecf20Sopenharmony_ci			break;
968c2ecf20Sopenharmony_ci	}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ciout:
998c2ecf20Sopenharmony_ci	mutex_unlock(&mdev->mcu.mutex);
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	return ret;
1028c2ecf20Sopenharmony_ci}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_cistatic int
1058c2ecf20Sopenharmony_cimt7603_mcu_init_download(struct mt7603_dev *dev, u32 addr, u32 len)
1068c2ecf20Sopenharmony_ci{
1078c2ecf20Sopenharmony_ci	struct {
1088c2ecf20Sopenharmony_ci		__le32 addr;
1098c2ecf20Sopenharmony_ci		__le32 len;
1108c2ecf20Sopenharmony_ci		__le32 mode;
1118c2ecf20Sopenharmony_ci	} req = {
1128c2ecf20Sopenharmony_ci		.addr = cpu_to_le32(addr),
1138c2ecf20Sopenharmony_ci		.len = cpu_to_le32(len),
1148c2ecf20Sopenharmony_ci		.mode = cpu_to_le32(BIT(31)),
1158c2ecf20Sopenharmony_ci	};
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	return __mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_TARGET_ADDRESS_LEN_REQ,
1188c2ecf20Sopenharmony_ci				   &req, sizeof(req), true);
1198c2ecf20Sopenharmony_ci}
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_cistatic int
1228c2ecf20Sopenharmony_cimt7603_mcu_send_firmware(struct mt7603_dev *dev, const void *data, int len)
1238c2ecf20Sopenharmony_ci{
1248c2ecf20Sopenharmony_ci	int cur_len, ret = 0;
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	while (len > 0) {
1278c2ecf20Sopenharmony_ci		cur_len = min_t(int, 4096 - sizeof(struct mt7603_mcu_txd),
1288c2ecf20Sopenharmony_ci				len);
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci		ret = __mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_FW_SCATTER,
1318c2ecf20Sopenharmony_ci					  data, cur_len, false);
1328c2ecf20Sopenharmony_ci		if (ret)
1338c2ecf20Sopenharmony_ci			break;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci		data += cur_len;
1368c2ecf20Sopenharmony_ci		len -= cur_len;
1378c2ecf20Sopenharmony_ci	}
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	return ret;
1408c2ecf20Sopenharmony_ci}
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_cistatic int
1438c2ecf20Sopenharmony_cimt7603_mcu_start_firmware(struct mt7603_dev *dev, u32 addr)
1448c2ecf20Sopenharmony_ci{
1458c2ecf20Sopenharmony_ci	struct {
1468c2ecf20Sopenharmony_ci		__le32 override;
1478c2ecf20Sopenharmony_ci		__le32 addr;
1488c2ecf20Sopenharmony_ci	} req = {
1498c2ecf20Sopenharmony_ci		.override = cpu_to_le32(addr ? 1 : 0),
1508c2ecf20Sopenharmony_ci		.addr = cpu_to_le32(addr),
1518c2ecf20Sopenharmony_ci	};
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	return __mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_FW_START_REQ,
1548c2ecf20Sopenharmony_ci				   &req, sizeof(req), true);
1558c2ecf20Sopenharmony_ci}
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_cistatic int
1588c2ecf20Sopenharmony_cimt7603_mcu_restart(struct mt76_dev *dev)
1598c2ecf20Sopenharmony_ci{
1608c2ecf20Sopenharmony_ci	return __mt76_mcu_send_msg(dev, -MCU_CMD_RESTART_DL_REQ,
1618c2ecf20Sopenharmony_ci				   NULL, 0, true);
1628c2ecf20Sopenharmony_ci}
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_cistatic int mt7603_load_firmware(struct mt7603_dev *dev)
1658c2ecf20Sopenharmony_ci{
1668c2ecf20Sopenharmony_ci	const struct firmware *fw;
1678c2ecf20Sopenharmony_ci	const struct mt7603_fw_trailer *hdr;
1688c2ecf20Sopenharmony_ci	const char *firmware;
1698c2ecf20Sopenharmony_ci	int dl_len;
1708c2ecf20Sopenharmony_ci	u32 addr, val;
1718c2ecf20Sopenharmony_ci	int ret;
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	if (is_mt7628(dev)) {
1748c2ecf20Sopenharmony_ci		if (mt76xx_rev(dev) == MT7628_REV_E1)
1758c2ecf20Sopenharmony_ci			firmware = MT7628_FIRMWARE_E1;
1768c2ecf20Sopenharmony_ci		else
1778c2ecf20Sopenharmony_ci			firmware = MT7628_FIRMWARE_E2;
1788c2ecf20Sopenharmony_ci	} else {
1798c2ecf20Sopenharmony_ci		if (mt76xx_rev(dev) < MT7603_REV_E2)
1808c2ecf20Sopenharmony_ci			firmware = MT7603_FIRMWARE_E1;
1818c2ecf20Sopenharmony_ci		else
1828c2ecf20Sopenharmony_ci			firmware = MT7603_FIRMWARE_E2;
1838c2ecf20Sopenharmony_ci	}
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	ret = request_firmware(&fw, firmware, dev->mt76.dev);
1868c2ecf20Sopenharmony_ci	if (ret)
1878c2ecf20Sopenharmony_ci		return ret;
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	if (!fw || !fw->data || fw->size < sizeof(*hdr)) {
1908c2ecf20Sopenharmony_ci		dev_err(dev->mt76.dev, "Invalid firmware\n");
1918c2ecf20Sopenharmony_ci		ret = -EINVAL;
1928c2ecf20Sopenharmony_ci		goto out;
1938c2ecf20Sopenharmony_ci	}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	hdr = (const struct mt7603_fw_trailer *)(fw->data + fw->size -
1968c2ecf20Sopenharmony_ci						 sizeof(*hdr));
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	dev_info(dev->mt76.dev, "Firmware Version: %.10s\n", hdr->fw_ver);
1998c2ecf20Sopenharmony_ci	dev_info(dev->mt76.dev, "Build Time: %.15s\n", hdr->build_date);
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	addr = mt7603_reg_map(dev, 0x50012498);
2028c2ecf20Sopenharmony_ci	mt76_wr(dev, addr, 0x5);
2038c2ecf20Sopenharmony_ci	mt76_wr(dev, addr, 0x5);
2048c2ecf20Sopenharmony_ci	udelay(1);
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	/* switch to bypass mode */
2078c2ecf20Sopenharmony_ci	mt76_rmw(dev, MT_SCH_4, MT_SCH_4_FORCE_QID,
2088c2ecf20Sopenharmony_ci		 MT_SCH_4_BYPASS | FIELD_PREP(MT_SCH_4_FORCE_QID, 5));
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	val = mt76_rr(dev, MT_TOP_MISC2);
2118c2ecf20Sopenharmony_ci	if (val & BIT(1)) {
2128c2ecf20Sopenharmony_ci		dev_info(dev->mt76.dev, "Firmware already running...\n");
2138c2ecf20Sopenharmony_ci		goto running;
2148c2ecf20Sopenharmony_ci	}
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	if (!mt76_poll_msec(dev, MT_TOP_MISC2, BIT(0) | BIT(1), BIT(0), 500)) {
2178c2ecf20Sopenharmony_ci		dev_err(dev->mt76.dev, "Timeout waiting for ROM code to become ready\n");
2188c2ecf20Sopenharmony_ci		ret = -EIO;
2198c2ecf20Sopenharmony_ci		goto out;
2208c2ecf20Sopenharmony_ci	}
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	dl_len = le32_to_cpu(hdr->dl_len) + 4;
2238c2ecf20Sopenharmony_ci	ret = mt7603_mcu_init_download(dev, MCU_FIRMWARE_ADDRESS, dl_len);
2248c2ecf20Sopenharmony_ci	if (ret) {
2258c2ecf20Sopenharmony_ci		dev_err(dev->mt76.dev, "Download request failed\n");
2268c2ecf20Sopenharmony_ci		goto out;
2278c2ecf20Sopenharmony_ci	}
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	ret = mt7603_mcu_send_firmware(dev, fw->data, dl_len);
2308c2ecf20Sopenharmony_ci	if (ret) {
2318c2ecf20Sopenharmony_ci		dev_err(dev->mt76.dev, "Failed to send firmware to device\n");
2328c2ecf20Sopenharmony_ci		goto out;
2338c2ecf20Sopenharmony_ci	}
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	ret = mt7603_mcu_start_firmware(dev, MCU_FIRMWARE_ADDRESS);
2368c2ecf20Sopenharmony_ci	if (ret) {
2378c2ecf20Sopenharmony_ci		dev_err(dev->mt76.dev, "Failed to start firmware\n");
2388c2ecf20Sopenharmony_ci		goto out;
2398c2ecf20Sopenharmony_ci	}
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	if (!mt76_poll_msec(dev, MT_TOP_MISC2, BIT(1), BIT(1), 500)) {
2428c2ecf20Sopenharmony_ci		dev_err(dev->mt76.dev, "Timeout waiting for firmware to initialize\n");
2438c2ecf20Sopenharmony_ci		ret = -EIO;
2448c2ecf20Sopenharmony_ci		goto out;
2458c2ecf20Sopenharmony_ci	}
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_cirunning:
2488c2ecf20Sopenharmony_ci	mt76_clear(dev, MT_SCH_4, MT_SCH_4_FORCE_QID | MT_SCH_4_BYPASS);
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	mt76_set(dev, MT_SCH_4, BIT(8));
2518c2ecf20Sopenharmony_ci	mt76_clear(dev, MT_SCH_4, BIT(8));
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	dev->mcu_running = true;
2548c2ecf20Sopenharmony_ci	snprintf(dev->mt76.hw->wiphy->fw_version,
2558c2ecf20Sopenharmony_ci		 sizeof(dev->mt76.hw->wiphy->fw_version),
2568c2ecf20Sopenharmony_ci		 "%.10s-%.15s", hdr->fw_ver, hdr->build_date);
2578c2ecf20Sopenharmony_ci	dev_info(dev->mt76.dev, "firmware init done\n");
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ciout:
2608c2ecf20Sopenharmony_ci	release_firmware(fw);
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	return ret;
2638c2ecf20Sopenharmony_ci}
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ciint mt7603_mcu_init(struct mt7603_dev *dev)
2668c2ecf20Sopenharmony_ci{
2678c2ecf20Sopenharmony_ci	static const struct mt76_mcu_ops mt7603_mcu_ops = {
2688c2ecf20Sopenharmony_ci		.headroom = sizeof(struct mt7603_mcu_txd),
2698c2ecf20Sopenharmony_ci		.mcu_send_msg = mt7603_mcu_msg_send,
2708c2ecf20Sopenharmony_ci		.mcu_restart = mt7603_mcu_restart,
2718c2ecf20Sopenharmony_ci	};
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	dev->mt76.mcu_ops = &mt7603_mcu_ops;
2748c2ecf20Sopenharmony_ci	return mt7603_load_firmware(dev);
2758c2ecf20Sopenharmony_ci}
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_civoid mt7603_mcu_exit(struct mt7603_dev *dev)
2788c2ecf20Sopenharmony_ci{
2798c2ecf20Sopenharmony_ci	__mt76_mcu_restart(&dev->mt76);
2808c2ecf20Sopenharmony_ci	skb_queue_purge(&dev->mt76.mcu.res_q);
2818c2ecf20Sopenharmony_ci}
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ciint mt7603_mcu_set_eeprom(struct mt7603_dev *dev)
2848c2ecf20Sopenharmony_ci{
2858c2ecf20Sopenharmony_ci	static const u16 req_fields[] = {
2868c2ecf20Sopenharmony_ci#define WORD(_start)			\
2878c2ecf20Sopenharmony_ci		_start,			\
2888c2ecf20Sopenharmony_ci		_start + 1
2898c2ecf20Sopenharmony_ci#define GROUP_2G(_start)		\
2908c2ecf20Sopenharmony_ci		WORD(_start),		\
2918c2ecf20Sopenharmony_ci		WORD(_start + 2),	\
2928c2ecf20Sopenharmony_ci		WORD(_start + 4)
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci		MT_EE_NIC_CONF_0 + 1,
2958c2ecf20Sopenharmony_ci		WORD(MT_EE_NIC_CONF_1),
2968c2ecf20Sopenharmony_ci		MT_EE_WIFI_RF_SETTING,
2978c2ecf20Sopenharmony_ci		MT_EE_TX_POWER_DELTA_BW40,
2988c2ecf20Sopenharmony_ci		MT_EE_TX_POWER_DELTA_BW80 + 1,
2998c2ecf20Sopenharmony_ci		MT_EE_TX_POWER_EXT_PA_5G,
3008c2ecf20Sopenharmony_ci		MT_EE_TEMP_SENSOR_CAL,
3018c2ecf20Sopenharmony_ci		GROUP_2G(MT_EE_TX_POWER_0_START_2G),
3028c2ecf20Sopenharmony_ci		GROUP_2G(MT_EE_TX_POWER_1_START_2G),
3038c2ecf20Sopenharmony_ci		WORD(MT_EE_TX_POWER_CCK),
3048c2ecf20Sopenharmony_ci		WORD(MT_EE_TX_POWER_OFDM_2G_6M),
3058c2ecf20Sopenharmony_ci		WORD(MT_EE_TX_POWER_OFDM_2G_24M),
3068c2ecf20Sopenharmony_ci		WORD(MT_EE_TX_POWER_OFDM_2G_54M),
3078c2ecf20Sopenharmony_ci		WORD(MT_EE_TX_POWER_HT_BPSK_QPSK),
3088c2ecf20Sopenharmony_ci		WORD(MT_EE_TX_POWER_HT_16_64_QAM),
3098c2ecf20Sopenharmony_ci		WORD(MT_EE_TX_POWER_HT_64_QAM),
3108c2ecf20Sopenharmony_ci		MT_EE_ELAN_RX_MODE_GAIN,
3118c2ecf20Sopenharmony_ci		MT_EE_ELAN_RX_MODE_NF,
3128c2ecf20Sopenharmony_ci		MT_EE_ELAN_RX_MODE_P1DB,
3138c2ecf20Sopenharmony_ci		MT_EE_ELAN_BYPASS_MODE_GAIN,
3148c2ecf20Sopenharmony_ci		MT_EE_ELAN_BYPASS_MODE_NF,
3158c2ecf20Sopenharmony_ci		MT_EE_ELAN_BYPASS_MODE_P1DB,
3168c2ecf20Sopenharmony_ci		WORD(MT_EE_STEP_NUM_NEG_6_7),
3178c2ecf20Sopenharmony_ci		WORD(MT_EE_STEP_NUM_NEG_4_5),
3188c2ecf20Sopenharmony_ci		WORD(MT_EE_STEP_NUM_NEG_2_3),
3198c2ecf20Sopenharmony_ci		WORD(MT_EE_STEP_NUM_NEG_0_1),
3208c2ecf20Sopenharmony_ci		WORD(MT_EE_REF_STEP_24G),
3218c2ecf20Sopenharmony_ci		WORD(MT_EE_STEP_NUM_PLUS_1_2),
3228c2ecf20Sopenharmony_ci		WORD(MT_EE_STEP_NUM_PLUS_3_4),
3238c2ecf20Sopenharmony_ci		WORD(MT_EE_STEP_NUM_PLUS_5_6),
3248c2ecf20Sopenharmony_ci		MT_EE_STEP_NUM_PLUS_7,
3258c2ecf20Sopenharmony_ci		MT_EE_XTAL_FREQ_OFFSET,
3268c2ecf20Sopenharmony_ci		MT_EE_XTAL_TRIM_2_COMP,
3278c2ecf20Sopenharmony_ci		MT_EE_XTAL_TRIM_3_COMP,
3288c2ecf20Sopenharmony_ci		MT_EE_XTAL_WF_RFCAL,
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci		/* unknown fields below */
3318c2ecf20Sopenharmony_ci		WORD(0x24),
3328c2ecf20Sopenharmony_ci		0x34,
3338c2ecf20Sopenharmony_ci		0x39,
3348c2ecf20Sopenharmony_ci		0x3b,
3358c2ecf20Sopenharmony_ci		WORD(0x42),
3368c2ecf20Sopenharmony_ci		WORD(0x9e),
3378c2ecf20Sopenharmony_ci		0xf2,
3388c2ecf20Sopenharmony_ci		WORD(0xf8),
3398c2ecf20Sopenharmony_ci		0xfa,
3408c2ecf20Sopenharmony_ci		0x12e,
3418c2ecf20Sopenharmony_ci		WORD(0x130), WORD(0x132), WORD(0x134), WORD(0x136),
3428c2ecf20Sopenharmony_ci		WORD(0x138), WORD(0x13a), WORD(0x13c), WORD(0x13e),
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci#undef GROUP_2G
3458c2ecf20Sopenharmony_ci#undef WORD
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	};
3488c2ecf20Sopenharmony_ci	struct req_data {
3498c2ecf20Sopenharmony_ci		__le16 addr;
3508c2ecf20Sopenharmony_ci		u8 val;
3518c2ecf20Sopenharmony_ci		u8 pad;
3528c2ecf20Sopenharmony_ci	} __packed;
3538c2ecf20Sopenharmony_ci	struct {
3548c2ecf20Sopenharmony_ci		u8 buffer_mode;
3558c2ecf20Sopenharmony_ci		u8 len;
3568c2ecf20Sopenharmony_ci		u8 pad[2];
3578c2ecf20Sopenharmony_ci	} req_hdr = {
3588c2ecf20Sopenharmony_ci		.buffer_mode = 1,
3598c2ecf20Sopenharmony_ci		.len = ARRAY_SIZE(req_fields) - 1,
3608c2ecf20Sopenharmony_ci	};
3618c2ecf20Sopenharmony_ci	const int size = 0xff * sizeof(struct req_data);
3628c2ecf20Sopenharmony_ci	u8 *req, *eep = (u8 *)dev->mt76.eeprom.data;
3638c2ecf20Sopenharmony_ci	int i, ret, len = sizeof(req_hdr) + size;
3648c2ecf20Sopenharmony_ci	struct req_data *data;
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	BUILD_BUG_ON(ARRAY_SIZE(req_fields) * sizeof(*data) > size);
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	req = kmalloc(len, GFP_KERNEL);
3698c2ecf20Sopenharmony_ci	if (!req)
3708c2ecf20Sopenharmony_ci		return -ENOMEM;
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	memcpy(req, &req_hdr, sizeof(req_hdr));
3738c2ecf20Sopenharmony_ci	data = (struct req_data *)(req + sizeof(req_hdr));
3748c2ecf20Sopenharmony_ci	memset(data, 0, size);
3758c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(req_fields); i++) {
3768c2ecf20Sopenharmony_ci		data[i].addr = cpu_to_le16(req_fields[i]);
3778c2ecf20Sopenharmony_ci		data[i].val = eep[req_fields[i]];
3788c2ecf20Sopenharmony_ci	}
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	ret = __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EFUSE_BUFFER_MODE,
3818c2ecf20Sopenharmony_ci				  req, len, true);
3828c2ecf20Sopenharmony_ci	kfree(req);
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	return ret;
3858c2ecf20Sopenharmony_ci}
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_cistatic int mt7603_mcu_set_tx_power(struct mt7603_dev *dev)
3888c2ecf20Sopenharmony_ci{
3898c2ecf20Sopenharmony_ci	struct {
3908c2ecf20Sopenharmony_ci		u8 center_channel;
3918c2ecf20Sopenharmony_ci		u8 tssi;
3928c2ecf20Sopenharmony_ci		u8 temp_comp;
3938c2ecf20Sopenharmony_ci		u8 target_power[2];
3948c2ecf20Sopenharmony_ci		u8 rate_power_delta[14];
3958c2ecf20Sopenharmony_ci		u8 bw_power_delta;
3968c2ecf20Sopenharmony_ci		u8 ch_power_delta[6];
3978c2ecf20Sopenharmony_ci		u8 temp_comp_power[17];
3988c2ecf20Sopenharmony_ci		u8 reserved;
3998c2ecf20Sopenharmony_ci	} req = {
4008c2ecf20Sopenharmony_ci		.center_channel = dev->mphy.chandef.chan->hw_value,
4018c2ecf20Sopenharmony_ci#define EEP_VAL(n) ((u8 *)dev->mt76.eeprom.data)[n]
4028c2ecf20Sopenharmony_ci		.tssi = EEP_VAL(MT_EE_NIC_CONF_1 + 1),
4038c2ecf20Sopenharmony_ci		.temp_comp = EEP_VAL(MT_EE_NIC_CONF_1),
4048c2ecf20Sopenharmony_ci		.target_power = {
4058c2ecf20Sopenharmony_ci			EEP_VAL(MT_EE_TX_POWER_0_START_2G + 2),
4068c2ecf20Sopenharmony_ci			EEP_VAL(MT_EE_TX_POWER_1_START_2G + 2)
4078c2ecf20Sopenharmony_ci		},
4088c2ecf20Sopenharmony_ci		.bw_power_delta = EEP_VAL(MT_EE_TX_POWER_DELTA_BW40),
4098c2ecf20Sopenharmony_ci		.ch_power_delta = {
4108c2ecf20Sopenharmony_ci			EEP_VAL(MT_EE_TX_POWER_0_START_2G + 3),
4118c2ecf20Sopenharmony_ci			EEP_VAL(MT_EE_TX_POWER_0_START_2G + 4),
4128c2ecf20Sopenharmony_ci			EEP_VAL(MT_EE_TX_POWER_0_START_2G + 5),
4138c2ecf20Sopenharmony_ci			EEP_VAL(MT_EE_TX_POWER_1_START_2G + 3),
4148c2ecf20Sopenharmony_ci			EEP_VAL(MT_EE_TX_POWER_1_START_2G + 4),
4158c2ecf20Sopenharmony_ci			EEP_VAL(MT_EE_TX_POWER_1_START_2G + 5)
4168c2ecf20Sopenharmony_ci		},
4178c2ecf20Sopenharmony_ci#undef EEP_VAL
4188c2ecf20Sopenharmony_ci	};
4198c2ecf20Sopenharmony_ci	u8 *eep = (u8 *)dev->mt76.eeprom.data;
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	memcpy(req.rate_power_delta, eep + MT_EE_TX_POWER_CCK,
4228c2ecf20Sopenharmony_ci	       sizeof(req.rate_power_delta));
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	memcpy(req.temp_comp_power, eep + MT_EE_STEP_NUM_NEG_6_7,
4258c2ecf20Sopenharmony_ci	       sizeof(req.temp_comp_power));
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_TX_POWER_CTRL,
4288c2ecf20Sopenharmony_ci				   &req, sizeof(req), true);
4298c2ecf20Sopenharmony_ci}
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ciint mt7603_mcu_set_channel(struct mt7603_dev *dev)
4328c2ecf20Sopenharmony_ci{
4338c2ecf20Sopenharmony_ci	struct cfg80211_chan_def *chandef = &dev->mphy.chandef;
4348c2ecf20Sopenharmony_ci	struct ieee80211_hw *hw = mt76_hw(dev);
4358c2ecf20Sopenharmony_ci	int n_chains = hweight8(dev->mphy.antenna_mask);
4368c2ecf20Sopenharmony_ci	struct {
4378c2ecf20Sopenharmony_ci		u8 control_chan;
4388c2ecf20Sopenharmony_ci		u8 center_chan;
4398c2ecf20Sopenharmony_ci		u8 bw;
4408c2ecf20Sopenharmony_ci		u8 tx_streams;
4418c2ecf20Sopenharmony_ci		u8 rx_streams;
4428c2ecf20Sopenharmony_ci		u8 _res0[7];
4438c2ecf20Sopenharmony_ci		u8 txpower[21];
4448c2ecf20Sopenharmony_ci		u8 _res1[3];
4458c2ecf20Sopenharmony_ci	} req = {
4468c2ecf20Sopenharmony_ci		.control_chan = chandef->chan->hw_value,
4478c2ecf20Sopenharmony_ci		.center_chan = chandef->chan->hw_value,
4488c2ecf20Sopenharmony_ci		.bw = MT_BW_20,
4498c2ecf20Sopenharmony_ci		.tx_streams = n_chains,
4508c2ecf20Sopenharmony_ci		.rx_streams = n_chains,
4518c2ecf20Sopenharmony_ci	};
4528c2ecf20Sopenharmony_ci	s8 tx_power;
4538c2ecf20Sopenharmony_ci	int i, ret;
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	if (dev->mphy.chandef.width == NL80211_CHAN_WIDTH_40) {
4568c2ecf20Sopenharmony_ci		req.bw = MT_BW_40;
4578c2ecf20Sopenharmony_ci		if (chandef->center_freq1 > chandef->chan->center_freq)
4588c2ecf20Sopenharmony_ci			req.center_chan += 2;
4598c2ecf20Sopenharmony_ci		else
4608c2ecf20Sopenharmony_ci			req.center_chan -= 2;
4618c2ecf20Sopenharmony_ci	}
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	tx_power = hw->conf.power_level * 2;
4648c2ecf20Sopenharmony_ci	if (dev->mphy.antenna_mask == 3)
4658c2ecf20Sopenharmony_ci		tx_power -= 6;
4668c2ecf20Sopenharmony_ci	tx_power = min(tx_power, dev->tx_power_limit);
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	dev->mphy.txpower_cur = tx_power;
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(req.txpower); i++)
4718c2ecf20Sopenharmony_ci		req.txpower[i] = tx_power;
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	ret = __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_CHANNEL_SWITCH,
4748c2ecf20Sopenharmony_ci				  &req, sizeof(req), true);
4758c2ecf20Sopenharmony_ci	if (ret)
4768c2ecf20Sopenharmony_ci		return ret;
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci	return mt7603_mcu_set_tx_power(dev);
4798c2ecf20Sopenharmony_ci}
480