162306a36Sopenharmony_ci// SPDX-License-Identifier: ISC
262306a36Sopenharmony_ci
362306a36Sopenharmony_ci#include <linux/firmware.h>
462306a36Sopenharmony_ci#include "mt7603.h"
562306a36Sopenharmony_ci#include "mcu.h"
662306a36Sopenharmony_ci#include "eeprom.h"
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#define MCU_SKB_RESERVE	8
962306a36Sopenharmony_ci
1062306a36Sopenharmony_cistruct mt7603_fw_trailer {
1162306a36Sopenharmony_ci	char fw_ver[10];
1262306a36Sopenharmony_ci	char build_date[15];
1362306a36Sopenharmony_ci	__le32 dl_len;
1462306a36Sopenharmony_ci} __packed;
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_cistatic int
1762306a36Sopenharmony_cimt7603_mcu_parse_response(struct mt76_dev *mdev, int cmd,
1862306a36Sopenharmony_ci			  struct sk_buff *skb, int seq)
1962306a36Sopenharmony_ci{
2062306a36Sopenharmony_ci	struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76);
2162306a36Sopenharmony_ci	struct mt7603_mcu_rxd *rxd;
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci	if (!skb) {
2462306a36Sopenharmony_ci		dev_err(mdev->dev, "MCU message %02x (seq %d) timed out\n",
2562306a36Sopenharmony_ci			abs(cmd), seq);
2662306a36Sopenharmony_ci		dev->mcu_hang = MT7603_WATCHDOG_TIMEOUT;
2762306a36Sopenharmony_ci		return -ETIMEDOUT;
2862306a36Sopenharmony_ci	}
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci	rxd = (struct mt7603_mcu_rxd *)skb->data;
3162306a36Sopenharmony_ci	if (seq != rxd->seq)
3262306a36Sopenharmony_ci		return -EAGAIN;
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	return 0;
3562306a36Sopenharmony_ci}
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistatic int
3862306a36Sopenharmony_cimt7603_mcu_skb_send_msg(struct mt76_dev *mdev, struct sk_buff *skb,
3962306a36Sopenharmony_ci			int cmd, int *wait_seq)
4062306a36Sopenharmony_ci{
4162306a36Sopenharmony_ci	struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76);
4262306a36Sopenharmony_ci	int hdrlen = dev->mcu_running ? sizeof(struct mt7603_mcu_txd) : 12;
4362306a36Sopenharmony_ci	struct mt7603_mcu_txd *txd;
4462306a36Sopenharmony_ci	u8 seq;
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	mdev->mcu.timeout = 3 * HZ;
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	seq = ++mdev->mcu.msg_seq & 0xf;
4962306a36Sopenharmony_ci	if (!seq)
5062306a36Sopenharmony_ci		seq = ++mdev->mcu.msg_seq & 0xf;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	txd = (struct mt7603_mcu_txd *)skb_push(skb, hdrlen);
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	txd->len = cpu_to_le16(skb->len);
5562306a36Sopenharmony_ci	if (cmd == -MCU_CMD_FW_SCATTER)
5662306a36Sopenharmony_ci		txd->pq_id = cpu_to_le16(MCU_PORT_QUEUE_FW);
5762306a36Sopenharmony_ci	else
5862306a36Sopenharmony_ci		txd->pq_id = cpu_to_le16(MCU_PORT_QUEUE);
5962306a36Sopenharmony_ci	txd->pkt_type = MCU_PKT_ID;
6062306a36Sopenharmony_ci	txd->seq = seq;
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	if (cmd < 0) {
6362306a36Sopenharmony_ci		txd->cid = -cmd;
6462306a36Sopenharmony_ci		txd->set_query = MCU_Q_NA;
6562306a36Sopenharmony_ci	} else {
6662306a36Sopenharmony_ci		txd->cid = MCU_CMD_EXT_CID;
6762306a36Sopenharmony_ci		txd->ext_cid = cmd;
6862306a36Sopenharmony_ci		txd->set_query = MCU_Q_SET;
6962306a36Sopenharmony_ci		txd->ext_cid_ack = 1;
7062306a36Sopenharmony_ci	}
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	if (wait_seq)
7362306a36Sopenharmony_ci		*wait_seq = seq;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	return mt76_tx_queue_skb_raw(dev, mdev->q_mcu[MT_MCUQ_WM], skb, 0);
7662306a36Sopenharmony_ci}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cistatic int
7962306a36Sopenharmony_cimt7603_mcu_init_download(struct mt7603_dev *dev, u32 addr, u32 len)
8062306a36Sopenharmony_ci{
8162306a36Sopenharmony_ci	struct {
8262306a36Sopenharmony_ci		__le32 addr;
8362306a36Sopenharmony_ci		__le32 len;
8462306a36Sopenharmony_ci		__le32 mode;
8562306a36Sopenharmony_ci	} req = {
8662306a36Sopenharmony_ci		.addr = cpu_to_le32(addr),
8762306a36Sopenharmony_ci		.len = cpu_to_le32(len),
8862306a36Sopenharmony_ci		.mode = cpu_to_le32(BIT(31)),
8962306a36Sopenharmony_ci	};
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_TARGET_ADDRESS_LEN_REQ,
9262306a36Sopenharmony_ci				 &req, sizeof(req), true);
9362306a36Sopenharmony_ci}
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_cistatic int
9662306a36Sopenharmony_cimt7603_mcu_start_firmware(struct mt7603_dev *dev, u32 addr)
9762306a36Sopenharmony_ci{
9862306a36Sopenharmony_ci	struct {
9962306a36Sopenharmony_ci		__le32 override;
10062306a36Sopenharmony_ci		__le32 addr;
10162306a36Sopenharmony_ci	} req = {
10262306a36Sopenharmony_ci		.override = cpu_to_le32(addr ? 1 : 0),
10362306a36Sopenharmony_ci		.addr = cpu_to_le32(addr),
10462306a36Sopenharmony_ci	};
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_FW_START_REQ, &req,
10762306a36Sopenharmony_ci				 sizeof(req), true);
10862306a36Sopenharmony_ci}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_cistatic int
11162306a36Sopenharmony_cimt7603_mcu_restart(struct mt76_dev *dev)
11262306a36Sopenharmony_ci{
11362306a36Sopenharmony_ci	return mt76_mcu_send_msg(dev, -MCU_CMD_RESTART_DL_REQ, NULL, 0, true);
11462306a36Sopenharmony_ci}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_cistatic int mt7603_load_firmware(struct mt7603_dev *dev)
11762306a36Sopenharmony_ci{
11862306a36Sopenharmony_ci	const struct firmware *fw;
11962306a36Sopenharmony_ci	const struct mt7603_fw_trailer *hdr;
12062306a36Sopenharmony_ci	const char *firmware;
12162306a36Sopenharmony_ci	int dl_len;
12262306a36Sopenharmony_ci	u32 addr, val;
12362306a36Sopenharmony_ci	int ret;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	if (is_mt7628(dev)) {
12662306a36Sopenharmony_ci		if (mt76xx_rev(dev) == MT7628_REV_E1)
12762306a36Sopenharmony_ci			firmware = MT7628_FIRMWARE_E1;
12862306a36Sopenharmony_ci		else
12962306a36Sopenharmony_ci			firmware = MT7628_FIRMWARE_E2;
13062306a36Sopenharmony_ci	} else {
13162306a36Sopenharmony_ci		if (mt76xx_rev(dev) < MT7603_REV_E2)
13262306a36Sopenharmony_ci			firmware = MT7603_FIRMWARE_E1;
13362306a36Sopenharmony_ci		else
13462306a36Sopenharmony_ci			firmware = MT7603_FIRMWARE_E2;
13562306a36Sopenharmony_ci	}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	ret = request_firmware(&fw, firmware, dev->mt76.dev);
13862306a36Sopenharmony_ci	if (ret)
13962306a36Sopenharmony_ci		return ret;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	if (!fw || !fw->data || fw->size < sizeof(*hdr)) {
14262306a36Sopenharmony_ci		dev_err(dev->mt76.dev, "Invalid firmware\n");
14362306a36Sopenharmony_ci		ret = -EINVAL;
14462306a36Sopenharmony_ci		goto out;
14562306a36Sopenharmony_ci	}
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	hdr = (const struct mt7603_fw_trailer *)(fw->data + fw->size -
14862306a36Sopenharmony_ci						 sizeof(*hdr));
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	dev_info(dev->mt76.dev, "Firmware Version: %.10s\n", hdr->fw_ver);
15162306a36Sopenharmony_ci	dev_info(dev->mt76.dev, "Build Time: %.15s\n", hdr->build_date);
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	addr = mt7603_reg_map(dev, 0x50012498);
15462306a36Sopenharmony_ci	mt76_wr(dev, addr, 0x5);
15562306a36Sopenharmony_ci	mt76_wr(dev, addr, 0x5);
15662306a36Sopenharmony_ci	udelay(1);
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	/* switch to bypass mode */
15962306a36Sopenharmony_ci	mt76_rmw(dev, MT_SCH_4, MT_SCH_4_FORCE_QID,
16062306a36Sopenharmony_ci		 MT_SCH_4_BYPASS | FIELD_PREP(MT_SCH_4_FORCE_QID, 5));
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	val = mt76_rr(dev, MT_TOP_MISC2);
16362306a36Sopenharmony_ci	if (val & BIT(1)) {
16462306a36Sopenharmony_ci		dev_info(dev->mt76.dev, "Firmware already running...\n");
16562306a36Sopenharmony_ci		goto running;
16662306a36Sopenharmony_ci	}
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	if (!mt76_poll_msec(dev, MT_TOP_MISC2, BIT(0) | BIT(1), BIT(0), 500)) {
16962306a36Sopenharmony_ci		dev_err(dev->mt76.dev, "Timeout waiting for ROM code to become ready\n");
17062306a36Sopenharmony_ci		ret = -EIO;
17162306a36Sopenharmony_ci		goto out;
17262306a36Sopenharmony_ci	}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	dl_len = le32_to_cpu(hdr->dl_len) + 4;
17562306a36Sopenharmony_ci	ret = mt7603_mcu_init_download(dev, MCU_FIRMWARE_ADDRESS, dl_len);
17662306a36Sopenharmony_ci	if (ret) {
17762306a36Sopenharmony_ci		dev_err(dev->mt76.dev, "Download request failed\n");
17862306a36Sopenharmony_ci		goto out;
17962306a36Sopenharmony_ci	}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	ret = mt76_mcu_send_firmware(&dev->mt76, -MCU_CMD_FW_SCATTER,
18262306a36Sopenharmony_ci				     fw->data, dl_len);
18362306a36Sopenharmony_ci	if (ret) {
18462306a36Sopenharmony_ci		dev_err(dev->mt76.dev, "Failed to send firmware to device\n");
18562306a36Sopenharmony_ci		goto out;
18662306a36Sopenharmony_ci	}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	ret = mt7603_mcu_start_firmware(dev, MCU_FIRMWARE_ADDRESS);
18962306a36Sopenharmony_ci	if (ret) {
19062306a36Sopenharmony_ci		dev_err(dev->mt76.dev, "Failed to start firmware\n");
19162306a36Sopenharmony_ci		goto out;
19262306a36Sopenharmony_ci	}
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	if (!mt76_poll_msec(dev, MT_TOP_MISC2, BIT(1), BIT(1), 500)) {
19562306a36Sopenharmony_ci		dev_err(dev->mt76.dev, "Timeout waiting for firmware to initialize\n");
19662306a36Sopenharmony_ci		ret = -EIO;
19762306a36Sopenharmony_ci		goto out;
19862306a36Sopenharmony_ci	}
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_cirunning:
20162306a36Sopenharmony_ci	mt76_clear(dev, MT_SCH_4, MT_SCH_4_FORCE_QID | MT_SCH_4_BYPASS);
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	mt76_set(dev, MT_SCH_4, BIT(8));
20462306a36Sopenharmony_ci	mt76_clear(dev, MT_SCH_4, BIT(8));
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	dev->mcu_running = true;
20762306a36Sopenharmony_ci	snprintf(dev->mt76.hw->wiphy->fw_version,
20862306a36Sopenharmony_ci		 sizeof(dev->mt76.hw->wiphy->fw_version),
20962306a36Sopenharmony_ci		 "%.10s-%.15s", hdr->fw_ver, hdr->build_date);
21062306a36Sopenharmony_ci	dev_info(dev->mt76.dev, "firmware init done\n");
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ciout:
21362306a36Sopenharmony_ci	release_firmware(fw);
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	return ret;
21662306a36Sopenharmony_ci}
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ciint mt7603_mcu_init(struct mt7603_dev *dev)
21962306a36Sopenharmony_ci{
22062306a36Sopenharmony_ci	static const struct mt76_mcu_ops mt7603_mcu_ops = {
22162306a36Sopenharmony_ci		.headroom = sizeof(struct mt7603_mcu_txd),
22262306a36Sopenharmony_ci		.mcu_skb_send_msg = mt7603_mcu_skb_send_msg,
22362306a36Sopenharmony_ci		.mcu_parse_response = mt7603_mcu_parse_response,
22462306a36Sopenharmony_ci	};
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	dev->mt76.mcu_ops = &mt7603_mcu_ops;
22762306a36Sopenharmony_ci	return mt7603_load_firmware(dev);
22862306a36Sopenharmony_ci}
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_civoid mt7603_mcu_exit(struct mt7603_dev *dev)
23162306a36Sopenharmony_ci{
23262306a36Sopenharmony_ci	mt7603_mcu_restart(&dev->mt76);
23362306a36Sopenharmony_ci	skb_queue_purge(&dev->mt76.mcu.res_q);
23462306a36Sopenharmony_ci}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ciint mt7603_mcu_set_eeprom(struct mt7603_dev *dev)
23762306a36Sopenharmony_ci{
23862306a36Sopenharmony_ci	static const u16 req_fields[] = {
23962306a36Sopenharmony_ci#define WORD(_start)			\
24062306a36Sopenharmony_ci		_start,			\
24162306a36Sopenharmony_ci		_start + 1
24262306a36Sopenharmony_ci#define GROUP_2G(_start)		\
24362306a36Sopenharmony_ci		WORD(_start),		\
24462306a36Sopenharmony_ci		WORD(_start + 2),	\
24562306a36Sopenharmony_ci		WORD(_start + 4)
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci		MT_EE_NIC_CONF_0 + 1,
24862306a36Sopenharmony_ci		WORD(MT_EE_NIC_CONF_1),
24962306a36Sopenharmony_ci		MT_EE_WIFI_RF_SETTING,
25062306a36Sopenharmony_ci		MT_EE_TX_POWER_DELTA_BW40,
25162306a36Sopenharmony_ci		MT_EE_TX_POWER_DELTA_BW80 + 1,
25262306a36Sopenharmony_ci		MT_EE_TX_POWER_EXT_PA_5G,
25362306a36Sopenharmony_ci		MT_EE_TEMP_SENSOR_CAL,
25462306a36Sopenharmony_ci		GROUP_2G(MT_EE_TX_POWER_0_START_2G),
25562306a36Sopenharmony_ci		GROUP_2G(MT_EE_TX_POWER_1_START_2G),
25662306a36Sopenharmony_ci		WORD(MT_EE_TX_POWER_CCK),
25762306a36Sopenharmony_ci		WORD(MT_EE_TX_POWER_OFDM_2G_6M),
25862306a36Sopenharmony_ci		WORD(MT_EE_TX_POWER_OFDM_2G_24M),
25962306a36Sopenharmony_ci		WORD(MT_EE_TX_POWER_OFDM_2G_54M),
26062306a36Sopenharmony_ci		WORD(MT_EE_TX_POWER_HT_BPSK_QPSK),
26162306a36Sopenharmony_ci		WORD(MT_EE_TX_POWER_HT_16_64_QAM),
26262306a36Sopenharmony_ci		WORD(MT_EE_TX_POWER_HT_64_QAM),
26362306a36Sopenharmony_ci		MT_EE_ELAN_RX_MODE_GAIN,
26462306a36Sopenharmony_ci		MT_EE_ELAN_RX_MODE_NF,
26562306a36Sopenharmony_ci		MT_EE_ELAN_RX_MODE_P1DB,
26662306a36Sopenharmony_ci		MT_EE_ELAN_BYPASS_MODE_GAIN,
26762306a36Sopenharmony_ci		MT_EE_ELAN_BYPASS_MODE_NF,
26862306a36Sopenharmony_ci		MT_EE_ELAN_BYPASS_MODE_P1DB,
26962306a36Sopenharmony_ci		WORD(MT_EE_STEP_NUM_NEG_6_7),
27062306a36Sopenharmony_ci		WORD(MT_EE_STEP_NUM_NEG_4_5),
27162306a36Sopenharmony_ci		WORD(MT_EE_STEP_NUM_NEG_2_3),
27262306a36Sopenharmony_ci		WORD(MT_EE_STEP_NUM_NEG_0_1),
27362306a36Sopenharmony_ci		WORD(MT_EE_REF_STEP_24G),
27462306a36Sopenharmony_ci		WORD(MT_EE_STEP_NUM_PLUS_1_2),
27562306a36Sopenharmony_ci		WORD(MT_EE_STEP_NUM_PLUS_3_4),
27662306a36Sopenharmony_ci		WORD(MT_EE_STEP_NUM_PLUS_5_6),
27762306a36Sopenharmony_ci		MT_EE_STEP_NUM_PLUS_7,
27862306a36Sopenharmony_ci		MT_EE_XTAL_FREQ_OFFSET,
27962306a36Sopenharmony_ci		MT_EE_XTAL_TRIM_2_COMP,
28062306a36Sopenharmony_ci		MT_EE_XTAL_TRIM_3_COMP,
28162306a36Sopenharmony_ci		MT_EE_XTAL_WF_RFCAL,
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci		/* unknown fields below */
28462306a36Sopenharmony_ci		WORD(0x24),
28562306a36Sopenharmony_ci		0x34,
28662306a36Sopenharmony_ci		0x39,
28762306a36Sopenharmony_ci		0x3b,
28862306a36Sopenharmony_ci		WORD(0x42),
28962306a36Sopenharmony_ci		WORD(0x9e),
29062306a36Sopenharmony_ci		0xf2,
29162306a36Sopenharmony_ci		WORD(0xf8),
29262306a36Sopenharmony_ci		0xfa,
29362306a36Sopenharmony_ci		0x12e,
29462306a36Sopenharmony_ci		WORD(0x130), WORD(0x132), WORD(0x134), WORD(0x136),
29562306a36Sopenharmony_ci		WORD(0x138), WORD(0x13a), WORD(0x13c), WORD(0x13e),
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci#undef GROUP_2G
29862306a36Sopenharmony_ci#undef WORD
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	};
30162306a36Sopenharmony_ci	struct req_data {
30262306a36Sopenharmony_ci		__le16 addr;
30362306a36Sopenharmony_ci		u8 val;
30462306a36Sopenharmony_ci		u8 pad;
30562306a36Sopenharmony_ci	} __packed;
30662306a36Sopenharmony_ci	struct {
30762306a36Sopenharmony_ci		u8 buffer_mode;
30862306a36Sopenharmony_ci		u8 len;
30962306a36Sopenharmony_ci		u8 pad[2];
31062306a36Sopenharmony_ci	} req_hdr = {
31162306a36Sopenharmony_ci		.buffer_mode = 1,
31262306a36Sopenharmony_ci		.len = ARRAY_SIZE(req_fields) - 1,
31362306a36Sopenharmony_ci	};
31462306a36Sopenharmony_ci	const int size = 0xff * sizeof(struct req_data);
31562306a36Sopenharmony_ci	u8 *req, *eep = (u8 *)dev->mt76.eeprom.data;
31662306a36Sopenharmony_ci	int i, ret, len = sizeof(req_hdr) + size;
31762306a36Sopenharmony_ci	struct req_data *data;
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	BUILD_BUG_ON(ARRAY_SIZE(req_fields) * sizeof(*data) > size);
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	req = kmalloc(len, GFP_KERNEL);
32262306a36Sopenharmony_ci	if (!req)
32362306a36Sopenharmony_ci		return -ENOMEM;
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	memcpy(req, &req_hdr, sizeof(req_hdr));
32662306a36Sopenharmony_ci	data = (struct req_data *)(req + sizeof(req_hdr));
32762306a36Sopenharmony_ci	memset(data, 0, size);
32862306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(req_fields); i++) {
32962306a36Sopenharmony_ci		data[i].addr = cpu_to_le16(req_fields[i]);
33062306a36Sopenharmony_ci		data[i].val = eep[req_fields[i]];
33162306a36Sopenharmony_ci	}
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EFUSE_BUFFER_MODE,
33462306a36Sopenharmony_ci				req, len, true);
33562306a36Sopenharmony_ci	kfree(req);
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	return ret;
33862306a36Sopenharmony_ci}
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_cistatic int mt7603_mcu_set_tx_power(struct mt7603_dev *dev)
34162306a36Sopenharmony_ci{
34262306a36Sopenharmony_ci	struct {
34362306a36Sopenharmony_ci		u8 center_channel;
34462306a36Sopenharmony_ci		u8 tssi;
34562306a36Sopenharmony_ci		u8 temp_comp;
34662306a36Sopenharmony_ci		u8 target_power[2];
34762306a36Sopenharmony_ci		u8 rate_power_delta[14];
34862306a36Sopenharmony_ci		u8 bw_power_delta;
34962306a36Sopenharmony_ci		u8 ch_power_delta[6];
35062306a36Sopenharmony_ci		u8 temp_comp_power[17];
35162306a36Sopenharmony_ci		u8 reserved;
35262306a36Sopenharmony_ci	} req = {
35362306a36Sopenharmony_ci		.center_channel = dev->mphy.chandef.chan->hw_value,
35462306a36Sopenharmony_ci#define EEP_VAL(n) ((u8 *)dev->mt76.eeprom.data)[n]
35562306a36Sopenharmony_ci		.tssi = EEP_VAL(MT_EE_NIC_CONF_1 + 1),
35662306a36Sopenharmony_ci		.temp_comp = EEP_VAL(MT_EE_NIC_CONF_1),
35762306a36Sopenharmony_ci		.target_power = {
35862306a36Sopenharmony_ci			EEP_VAL(MT_EE_TX_POWER_0_START_2G + 2),
35962306a36Sopenharmony_ci			EEP_VAL(MT_EE_TX_POWER_1_START_2G + 2)
36062306a36Sopenharmony_ci		},
36162306a36Sopenharmony_ci		.bw_power_delta = EEP_VAL(MT_EE_TX_POWER_DELTA_BW40),
36262306a36Sopenharmony_ci		.ch_power_delta = {
36362306a36Sopenharmony_ci			EEP_VAL(MT_EE_TX_POWER_0_START_2G + 3),
36462306a36Sopenharmony_ci			EEP_VAL(MT_EE_TX_POWER_0_START_2G + 4),
36562306a36Sopenharmony_ci			EEP_VAL(MT_EE_TX_POWER_0_START_2G + 5),
36662306a36Sopenharmony_ci			EEP_VAL(MT_EE_TX_POWER_1_START_2G + 3),
36762306a36Sopenharmony_ci			EEP_VAL(MT_EE_TX_POWER_1_START_2G + 4),
36862306a36Sopenharmony_ci			EEP_VAL(MT_EE_TX_POWER_1_START_2G + 5)
36962306a36Sopenharmony_ci		},
37062306a36Sopenharmony_ci#undef EEP_VAL
37162306a36Sopenharmony_ci	};
37262306a36Sopenharmony_ci	u8 *eep = (u8 *)dev->mt76.eeprom.data;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	memcpy(req.rate_power_delta, eep + MT_EE_TX_POWER_CCK,
37562306a36Sopenharmony_ci	       sizeof(req.rate_power_delta));
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	memcpy(req.temp_comp_power, eep + MT_EE_STEP_NUM_NEG_6_7,
37862306a36Sopenharmony_ci	       sizeof(req.temp_comp_power));
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_TX_POWER_CTRL,
38162306a36Sopenharmony_ci				 &req, sizeof(req), true);
38262306a36Sopenharmony_ci}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ciint mt7603_mcu_set_channel(struct mt7603_dev *dev)
38562306a36Sopenharmony_ci{
38662306a36Sopenharmony_ci	struct cfg80211_chan_def *chandef = &dev->mphy.chandef;
38762306a36Sopenharmony_ci	struct ieee80211_hw *hw = mt76_hw(dev);
38862306a36Sopenharmony_ci	int n_chains = hweight8(dev->mphy.antenna_mask);
38962306a36Sopenharmony_ci	struct {
39062306a36Sopenharmony_ci		u8 control_chan;
39162306a36Sopenharmony_ci		u8 center_chan;
39262306a36Sopenharmony_ci		u8 bw;
39362306a36Sopenharmony_ci		u8 tx_streams;
39462306a36Sopenharmony_ci		u8 rx_streams;
39562306a36Sopenharmony_ci		u8 _res0[7];
39662306a36Sopenharmony_ci		u8 txpower[21];
39762306a36Sopenharmony_ci		u8 _res1[3];
39862306a36Sopenharmony_ci	} req = {
39962306a36Sopenharmony_ci		.control_chan = chandef->chan->hw_value,
40062306a36Sopenharmony_ci		.center_chan = chandef->chan->hw_value,
40162306a36Sopenharmony_ci		.bw = MT_BW_20,
40262306a36Sopenharmony_ci		.tx_streams = n_chains,
40362306a36Sopenharmony_ci		.rx_streams = n_chains,
40462306a36Sopenharmony_ci	};
40562306a36Sopenharmony_ci	s8 tx_power = hw->conf.power_level * 2;
40662306a36Sopenharmony_ci	int i, ret;
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	if (dev->mphy.chandef.width == NL80211_CHAN_WIDTH_40) {
40962306a36Sopenharmony_ci		req.bw = MT_BW_40;
41062306a36Sopenharmony_ci		if (chandef->center_freq1 > chandef->chan->center_freq)
41162306a36Sopenharmony_ci			req.center_chan += 2;
41262306a36Sopenharmony_ci		else
41362306a36Sopenharmony_ci			req.center_chan -= 2;
41462306a36Sopenharmony_ci	}
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	tx_power = mt76_get_sar_power(&dev->mphy, chandef->chan, tx_power);
41762306a36Sopenharmony_ci	if (dev->mphy.antenna_mask == 3)
41862306a36Sopenharmony_ci		tx_power -= 6;
41962306a36Sopenharmony_ci	tx_power = min(tx_power, dev->tx_power_limit);
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	dev->mphy.txpower_cur = tx_power;
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(req.txpower); i++)
42462306a36Sopenharmony_ci		req.txpower[i] = tx_power;
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_CHANNEL_SWITCH, &req,
42762306a36Sopenharmony_ci				sizeof(req), true);
42862306a36Sopenharmony_ci	if (ret)
42962306a36Sopenharmony_ci		return ret;
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	return mt7603_mcu_set_tx_power(dev);
43262306a36Sopenharmony_ci}
433