17f17b86aSRyder Lee // SPDX-License-Identifier: ISC
2c8846e10SFelix Fietkau 
3c8846e10SFelix Fietkau #include <linux/firmware.h>
4c8846e10SFelix Fietkau #include "mt7603.h"
5c8846e10SFelix Fietkau #include "mcu.h"
6c8846e10SFelix Fietkau #include "eeprom.h"
7c8846e10SFelix Fietkau 
8c8846e10SFelix Fietkau #define MCU_SKB_RESERVE	8
9c8846e10SFelix Fietkau 
10c8846e10SFelix Fietkau struct mt7603_fw_trailer {
11c8846e10SFelix Fietkau 	char fw_ver[10];
12c8846e10SFelix Fietkau 	char build_date[15];
13c8846e10SFelix Fietkau 	__le32 dl_len;
14c8846e10SFelix Fietkau } __packed;
15c8846e10SFelix Fietkau 
16c8846e10SFelix Fietkau static int
17f320d812SFelix Fietkau mt7603_mcu_parse_response(struct mt76_dev *mdev, int cmd,
18f320d812SFelix Fietkau 			  struct sk_buff *skb, int seq)
19f320d812SFelix Fietkau {
2096a607b6SFelix Fietkau 	struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76);
2196a607b6SFelix Fietkau 	struct mt7603_mcu_rxd *rxd;
22f320d812SFelix Fietkau 
2396a607b6SFelix Fietkau 	if (!skb) {
2496a607b6SFelix Fietkau 		dev_err(mdev->dev,
2596a607b6SFelix Fietkau 			"MCU message %d (seq %d) timed out\n",
2696a607b6SFelix Fietkau 			cmd, seq);
2796a607b6SFelix Fietkau 		dev->mcu_hang = MT7603_WATCHDOG_TIMEOUT;
2896a607b6SFelix Fietkau 		return -ETIMEDOUT;
2996a607b6SFelix Fietkau 	}
3096a607b6SFelix Fietkau 
3196a607b6SFelix Fietkau 	rxd = (struct mt7603_mcu_rxd *)skb->data;
32f320d812SFelix Fietkau 	if (seq != rxd->seq)
33f320d812SFelix Fietkau 		return -EAGAIN;
34f320d812SFelix Fietkau 
35f320d812SFelix Fietkau 	return 0;
36f320d812SFelix Fietkau }
37f320d812SFelix Fietkau 
38f320d812SFelix Fietkau static int
3914b80ba2SFelix Fietkau mt7603_mcu_skb_send_msg(struct mt76_dev *mdev, struct sk_buff *skb,
40114fe5e3SLorenzo Bianconi 			int cmd, int *wait_seq)
41c8846e10SFelix Fietkau {
4214b80ba2SFelix Fietkau 	struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76);
43c8846e10SFelix Fietkau 	int hdrlen = dev->mcu_running ? sizeof(struct mt7603_mcu_txd) : 12;
44c8846e10SFelix Fietkau 	struct mt7603_mcu_txd *txd;
45c8846e10SFelix Fietkau 	u8 seq;
46c8846e10SFelix Fietkau 
4714b80ba2SFelix Fietkau 	mdev->mcu.timeout = 3 * HZ;
4814b80ba2SFelix Fietkau 
4909872957SLorenzo Bianconi 	seq = ++mdev->mcu.msg_seq & 0xf;
50c8846e10SFelix Fietkau 	if (!seq)
5109872957SLorenzo Bianconi 		seq = ++mdev->mcu.msg_seq & 0xf;
52c8846e10SFelix Fietkau 
53c8846e10SFelix Fietkau 	txd = (struct mt7603_mcu_txd *)skb_push(skb, hdrlen);
54c8846e10SFelix Fietkau 
55c8846e10SFelix Fietkau 	txd->len = cpu_to_le16(skb->len);
56c8846e10SFelix Fietkau 	if (cmd == -MCU_CMD_FW_SCATTER)
57c8846e10SFelix Fietkau 		txd->pq_id = cpu_to_le16(MCU_PORT_QUEUE_FW);
58c8846e10SFelix Fietkau 	else
59c8846e10SFelix Fietkau 		txd->pq_id = cpu_to_le16(MCU_PORT_QUEUE);
60c8846e10SFelix Fietkau 	txd->pkt_type = MCU_PKT_ID;
61c8846e10SFelix Fietkau 	txd->seq = seq;
62c8846e10SFelix Fietkau 
63c8846e10SFelix Fietkau 	if (cmd < 0) {
64c8846e10SFelix Fietkau 		txd->cid = -cmd;
65114fe5e3SLorenzo Bianconi 		txd->set_query = MCU_Q_NA;
66c8846e10SFelix Fietkau 	} else {
67c8846e10SFelix Fietkau 		txd->cid = MCU_CMD_EXT_CID;
68c8846e10SFelix Fietkau 		txd->ext_cid = cmd;
69114fe5e3SLorenzo Bianconi 		txd->set_query = MCU_Q_SET;
70c8846e10SFelix Fietkau 		txd->ext_cid_ack = 1;
71c8846e10SFelix Fietkau 	}
72c8846e10SFelix Fietkau 
73c8846e10SFelix Fietkau 	if (wait_seq)
74c8846e10SFelix Fietkau 		*wait_seq = seq;
75c8846e10SFelix Fietkau 
76*e637763bSLorenzo Bianconi 	return mt76_tx_queue_skb_raw(dev, mdev->q_mcu[MT_MCUQ_WM], skb, 0);
77c8846e10SFelix Fietkau }
78c8846e10SFelix Fietkau 
79c8846e10SFelix Fietkau static int
80c8846e10SFelix Fietkau mt7603_mcu_init_download(struct mt7603_dev *dev, u32 addr, u32 len)
81c8846e10SFelix Fietkau {
82c8846e10SFelix Fietkau 	struct {
83c8846e10SFelix Fietkau 		__le32 addr;
84c8846e10SFelix Fietkau 		__le32 len;
85c8846e10SFelix Fietkau 		__le32 mode;
86c8846e10SFelix Fietkau 	} req = {
87c8846e10SFelix Fietkau 		.addr = cpu_to_le32(addr),
88c8846e10SFelix Fietkau 		.len = cpu_to_le32(len),
89c8846e10SFelix Fietkau 		.mode = cpu_to_le32(BIT(31)),
90c8846e10SFelix Fietkau 	};
91c8846e10SFelix Fietkau 
92cb5cdd4cSFelix Fietkau 	return mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_TARGET_ADDRESS_LEN_REQ,
9311ca82d7SLorenzo Bianconi 				 &req, sizeof(req), true);
94c8846e10SFelix Fietkau }
95c8846e10SFelix Fietkau 
96c8846e10SFelix Fietkau static int
97c8846e10SFelix Fietkau mt7603_mcu_start_firmware(struct mt7603_dev *dev, u32 addr)
98c8846e10SFelix Fietkau {
99c8846e10SFelix Fietkau 	struct {
100c8846e10SFelix Fietkau 		__le32 override;
101c8846e10SFelix Fietkau 		__le32 addr;
102c8846e10SFelix Fietkau 	} req = {
103c8846e10SFelix Fietkau 		.override = cpu_to_le32(addr ? 1 : 0),
104c8846e10SFelix Fietkau 		.addr = cpu_to_le32(addr),
105c8846e10SFelix Fietkau 	};
106c8846e10SFelix Fietkau 
107cb5cdd4cSFelix Fietkau 	return mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_FW_START_REQ, &req,
108cb5cdd4cSFelix Fietkau 				 sizeof(req), true);
109c8846e10SFelix Fietkau }
110c8846e10SFelix Fietkau 
111c8846e10SFelix Fietkau static int
112a4834814SLorenzo Bianconi mt7603_mcu_restart(struct mt76_dev *dev)
113c8846e10SFelix Fietkau {
114cb5cdd4cSFelix Fietkau 	return mt76_mcu_send_msg(dev, -MCU_CMD_RESTART_DL_REQ, NULL, 0, true);
115c8846e10SFelix Fietkau }
116c8846e10SFelix Fietkau 
117cc173875SLorenzo Bianconi static int mt7603_load_firmware(struct mt7603_dev *dev)
118c8846e10SFelix Fietkau {
119c8846e10SFelix Fietkau 	const struct firmware *fw;
120c8846e10SFelix Fietkau 	const struct mt7603_fw_trailer *hdr;
121c8846e10SFelix Fietkau 	const char *firmware;
122c8846e10SFelix Fietkau 	int dl_len;
123c8846e10SFelix Fietkau 	u32 addr, val;
124c8846e10SFelix Fietkau 	int ret;
125c8846e10SFelix Fietkau 
126c8846e10SFelix Fietkau 	if (is_mt7628(dev)) {
127c8846e10SFelix Fietkau 		if (mt76xx_rev(dev) == MT7628_REV_E1)
128c8846e10SFelix Fietkau 			firmware = MT7628_FIRMWARE_E1;
129c8846e10SFelix Fietkau 		else
130c8846e10SFelix Fietkau 			firmware = MT7628_FIRMWARE_E2;
131c8846e10SFelix Fietkau 	} else {
132c8846e10SFelix Fietkau 		if (mt76xx_rev(dev) < MT7603_REV_E2)
133c8846e10SFelix Fietkau 			firmware = MT7603_FIRMWARE_E1;
134c8846e10SFelix Fietkau 		else
135c8846e10SFelix Fietkau 			firmware = MT7603_FIRMWARE_E2;
136c8846e10SFelix Fietkau 	}
137c8846e10SFelix Fietkau 
138c8846e10SFelix Fietkau 	ret = request_firmware(&fw, firmware, dev->mt76.dev);
139c8846e10SFelix Fietkau 	if (ret)
140c8846e10SFelix Fietkau 		return ret;
141c8846e10SFelix Fietkau 
142c8846e10SFelix Fietkau 	if (!fw || !fw->data || fw->size < sizeof(*hdr)) {
143c8846e10SFelix Fietkau 		dev_err(dev->mt76.dev, "Invalid firmware\n");
144c8846e10SFelix Fietkau 		ret = -EINVAL;
145c8846e10SFelix Fietkau 		goto out;
146c8846e10SFelix Fietkau 	}
147c8846e10SFelix Fietkau 
148c8846e10SFelix Fietkau 	hdr = (const struct mt7603_fw_trailer *)(fw->data + fw->size -
149c8846e10SFelix Fietkau 						 sizeof(*hdr));
150c8846e10SFelix Fietkau 
151c8846e10SFelix Fietkau 	dev_info(dev->mt76.dev, "Firmware Version: %.10s\n", hdr->fw_ver);
152c8846e10SFelix Fietkau 	dev_info(dev->mt76.dev, "Build Time: %.15s\n", hdr->build_date);
153c8846e10SFelix Fietkau 
154c8846e10SFelix Fietkau 	addr = mt7603_reg_map(dev, 0x50012498);
155c8846e10SFelix Fietkau 	mt76_wr(dev, addr, 0x5);
156c8846e10SFelix Fietkau 	mt76_wr(dev, addr, 0x5);
157c8846e10SFelix Fietkau 	udelay(1);
158c8846e10SFelix Fietkau 
159c8846e10SFelix Fietkau 	/* switch to bypass mode */
160c8846e10SFelix Fietkau 	mt76_rmw(dev, MT_SCH_4, MT_SCH_4_FORCE_QID,
161c8846e10SFelix Fietkau 		 MT_SCH_4_BYPASS | FIELD_PREP(MT_SCH_4_FORCE_QID, 5));
162c8846e10SFelix Fietkau 
163c8846e10SFelix Fietkau 	val = mt76_rr(dev, MT_TOP_MISC2);
164c8846e10SFelix Fietkau 	if (val & BIT(1)) {
165c8846e10SFelix Fietkau 		dev_info(dev->mt76.dev, "Firmware already running...\n");
166c8846e10SFelix Fietkau 		goto running;
167c8846e10SFelix Fietkau 	}
168c8846e10SFelix Fietkau 
169c8846e10SFelix Fietkau 	if (!mt76_poll_msec(dev, MT_TOP_MISC2, BIT(0) | BIT(1), BIT(0), 500)) {
170c8846e10SFelix Fietkau 		dev_err(dev->mt76.dev, "Timeout waiting for ROM code to become ready\n");
171c8846e10SFelix Fietkau 		ret = -EIO;
172c8846e10SFelix Fietkau 		goto out;
173c8846e10SFelix Fietkau 	}
174c8846e10SFelix Fietkau 
175c8846e10SFelix Fietkau 	dl_len = le32_to_cpu(hdr->dl_len) + 4;
176c8846e10SFelix Fietkau 	ret = mt7603_mcu_init_download(dev, MCU_FIRMWARE_ADDRESS, dl_len);
177c8846e10SFelix Fietkau 	if (ret) {
178c8846e10SFelix Fietkau 		dev_err(dev->mt76.dev, "Download request failed\n");
179c8846e10SFelix Fietkau 		goto out;
180c8846e10SFelix Fietkau 	}
181c8846e10SFelix Fietkau 
1823cb43b66SLorenzo Bianconi 	ret = mt76_mcu_send_firmware(&dev->mt76, -MCU_CMD_FW_SCATTER,
1833cb43b66SLorenzo Bianconi 				     fw->data, dl_len);
184c8846e10SFelix Fietkau 	if (ret) {
185c8846e10SFelix Fietkau 		dev_err(dev->mt76.dev, "Failed to send firmware to device\n");
186c8846e10SFelix Fietkau 		goto out;
187c8846e10SFelix Fietkau 	}
188c8846e10SFelix Fietkau 
189c8846e10SFelix Fietkau 	ret = mt7603_mcu_start_firmware(dev, MCU_FIRMWARE_ADDRESS);
190c8846e10SFelix Fietkau 	if (ret) {
191c8846e10SFelix Fietkau 		dev_err(dev->mt76.dev, "Failed to start firmware\n");
192c8846e10SFelix Fietkau 		goto out;
193c8846e10SFelix Fietkau 	}
194c8846e10SFelix Fietkau 
195c8846e10SFelix Fietkau 	if (!mt76_poll_msec(dev, MT_TOP_MISC2, BIT(1), BIT(1), 500)) {
196c8846e10SFelix Fietkau 		dev_err(dev->mt76.dev, "Timeout waiting for firmware to initialize\n");
197c8846e10SFelix Fietkau 		ret = -EIO;
198c8846e10SFelix Fietkau 		goto out;
199c8846e10SFelix Fietkau 	}
200c8846e10SFelix Fietkau 
201c8846e10SFelix Fietkau running:
202c8846e10SFelix Fietkau 	mt76_clear(dev, MT_SCH_4, MT_SCH_4_FORCE_QID | MT_SCH_4_BYPASS);
203c8846e10SFelix Fietkau 
204c8846e10SFelix Fietkau 	mt76_set(dev, MT_SCH_4, BIT(8));
205c8846e10SFelix Fietkau 	mt76_clear(dev, MT_SCH_4, BIT(8));
206c8846e10SFelix Fietkau 
207c8846e10SFelix Fietkau 	dev->mcu_running = true;
2084d0fe26fSLorenzo Bianconi 	snprintf(dev->mt76.hw->wiphy->fw_version,
2094d0fe26fSLorenzo Bianconi 		 sizeof(dev->mt76.hw->wiphy->fw_version),
2104d0fe26fSLorenzo Bianconi 		 "%.10s-%.15s", hdr->fw_ver, hdr->build_date);
211c8846e10SFelix Fietkau 	dev_info(dev->mt76.dev, "firmware init done\n");
212c8846e10SFelix Fietkau 
213c8846e10SFelix Fietkau out:
214c8846e10SFelix Fietkau 	release_firmware(fw);
215c8846e10SFelix Fietkau 
216c8846e10SFelix Fietkau 	return ret;
217c8846e10SFelix Fietkau }
218c8846e10SFelix Fietkau 
219cc173875SLorenzo Bianconi int mt7603_mcu_init(struct mt7603_dev *dev)
220cc173875SLorenzo Bianconi {
221cc173875SLorenzo Bianconi 	static const struct mt76_mcu_ops mt7603_mcu_ops = {
222bb31a80eSLorenzo Bianconi 		.headroom = sizeof(struct mt7603_mcu_txd),
22314b80ba2SFelix Fietkau 		.mcu_skb_send_msg = mt7603_mcu_skb_send_msg,
224f320d812SFelix Fietkau 		.mcu_parse_response = mt7603_mcu_parse_response,
225a4834814SLorenzo Bianconi 		.mcu_restart = mt7603_mcu_restart,
226cc173875SLorenzo Bianconi 	};
227cc173875SLorenzo Bianconi 
228cc173875SLorenzo Bianconi 	dev->mt76.mcu_ops = &mt7603_mcu_ops;
229cc173875SLorenzo Bianconi 	return mt7603_load_firmware(dev);
230cc173875SLorenzo Bianconi }
231cc173875SLorenzo Bianconi 
232c8846e10SFelix Fietkau void mt7603_mcu_exit(struct mt7603_dev *dev)
233c8846e10SFelix Fietkau {
234a4834814SLorenzo Bianconi 	__mt76_mcu_restart(&dev->mt76);
23509872957SLorenzo Bianconi 	skb_queue_purge(&dev->mt76.mcu.res_q);
236c8846e10SFelix Fietkau }
237c8846e10SFelix Fietkau 
238c8846e10SFelix Fietkau int mt7603_mcu_set_eeprom(struct mt7603_dev *dev)
239c8846e10SFelix Fietkau {
240c8846e10SFelix Fietkau 	static const u16 req_fields[] = {
241c8846e10SFelix Fietkau #define WORD(_start)			\
242c8846e10SFelix Fietkau 		_start,			\
243c8846e10SFelix Fietkau 		_start + 1
244c8846e10SFelix Fietkau #define GROUP_2G(_start)		\
245c8846e10SFelix Fietkau 		WORD(_start),		\
246c8846e10SFelix Fietkau 		WORD(_start + 2),	\
247c8846e10SFelix Fietkau 		WORD(_start + 4)
248c8846e10SFelix Fietkau 
249c8846e10SFelix Fietkau 		MT_EE_NIC_CONF_0 + 1,
250c8846e10SFelix Fietkau 		WORD(MT_EE_NIC_CONF_1),
251c8846e10SFelix Fietkau 		MT_EE_WIFI_RF_SETTING,
252c8846e10SFelix Fietkau 		MT_EE_TX_POWER_DELTA_BW40,
253c8846e10SFelix Fietkau 		MT_EE_TX_POWER_DELTA_BW80 + 1,
254c8846e10SFelix Fietkau 		MT_EE_TX_POWER_EXT_PA_5G,
255c8846e10SFelix Fietkau 		MT_EE_TEMP_SENSOR_CAL,
256c8846e10SFelix Fietkau 		GROUP_2G(MT_EE_TX_POWER_0_START_2G),
257c8846e10SFelix Fietkau 		GROUP_2G(MT_EE_TX_POWER_1_START_2G),
258c8846e10SFelix Fietkau 		WORD(MT_EE_TX_POWER_CCK),
259c8846e10SFelix Fietkau 		WORD(MT_EE_TX_POWER_OFDM_2G_6M),
260c8846e10SFelix Fietkau 		WORD(MT_EE_TX_POWER_OFDM_2G_24M),
261c8846e10SFelix Fietkau 		WORD(MT_EE_TX_POWER_OFDM_2G_54M),
262c8846e10SFelix Fietkau 		WORD(MT_EE_TX_POWER_HT_BPSK_QPSK),
263c8846e10SFelix Fietkau 		WORD(MT_EE_TX_POWER_HT_16_64_QAM),
264c8846e10SFelix Fietkau 		WORD(MT_EE_TX_POWER_HT_64_QAM),
265c8846e10SFelix Fietkau 		MT_EE_ELAN_RX_MODE_GAIN,
266c8846e10SFelix Fietkau 		MT_EE_ELAN_RX_MODE_NF,
267c8846e10SFelix Fietkau 		MT_EE_ELAN_RX_MODE_P1DB,
268c8846e10SFelix Fietkau 		MT_EE_ELAN_BYPASS_MODE_GAIN,
269c8846e10SFelix Fietkau 		MT_EE_ELAN_BYPASS_MODE_NF,
270c8846e10SFelix Fietkau 		MT_EE_ELAN_BYPASS_MODE_P1DB,
271c8846e10SFelix Fietkau 		WORD(MT_EE_STEP_NUM_NEG_6_7),
272c8846e10SFelix Fietkau 		WORD(MT_EE_STEP_NUM_NEG_4_5),
273c8846e10SFelix Fietkau 		WORD(MT_EE_STEP_NUM_NEG_2_3),
274c8846e10SFelix Fietkau 		WORD(MT_EE_STEP_NUM_NEG_0_1),
275c8846e10SFelix Fietkau 		WORD(MT_EE_REF_STEP_24G),
276c8846e10SFelix Fietkau 		WORD(MT_EE_STEP_NUM_PLUS_1_2),
277c8846e10SFelix Fietkau 		WORD(MT_EE_STEP_NUM_PLUS_3_4),
278c8846e10SFelix Fietkau 		WORD(MT_EE_STEP_NUM_PLUS_5_6),
279c8846e10SFelix Fietkau 		MT_EE_STEP_NUM_PLUS_7,
280c8846e10SFelix Fietkau 		MT_EE_XTAL_FREQ_OFFSET,
281c8846e10SFelix Fietkau 		MT_EE_XTAL_TRIM_2_COMP,
282c8846e10SFelix Fietkau 		MT_EE_XTAL_TRIM_3_COMP,
283c8846e10SFelix Fietkau 		MT_EE_XTAL_WF_RFCAL,
284c8846e10SFelix Fietkau 
285c8846e10SFelix Fietkau 		/* unknown fields below */
286c8846e10SFelix Fietkau 		WORD(0x24),
287c8846e10SFelix Fietkau 		0x34,
288c8846e10SFelix Fietkau 		0x39,
289c8846e10SFelix Fietkau 		0x3b,
290c8846e10SFelix Fietkau 		WORD(0x42),
291c8846e10SFelix Fietkau 		WORD(0x9e),
292c8846e10SFelix Fietkau 		0xf2,
293c8846e10SFelix Fietkau 		WORD(0xf8),
294c8846e10SFelix Fietkau 		0xfa,
295c8846e10SFelix Fietkau 		0x12e,
296c8846e10SFelix Fietkau 		WORD(0x130), WORD(0x132), WORD(0x134), WORD(0x136),
297c8846e10SFelix Fietkau 		WORD(0x138), WORD(0x13a), WORD(0x13c), WORD(0x13e),
298c8846e10SFelix Fietkau 
299c8846e10SFelix Fietkau #undef GROUP_2G
300c8846e10SFelix Fietkau #undef WORD
301c8846e10SFelix Fietkau 
302c8846e10SFelix Fietkau 	};
303c8846e10SFelix Fietkau 	struct req_data {
304676fabd1SLorenzo Bianconi 		__le16 addr;
305c8846e10SFelix Fietkau 		u8 val;
306c8846e10SFelix Fietkau 		u8 pad;
307c8846e10SFelix Fietkau 	} __packed;
308c8846e10SFelix Fietkau 	struct {
309c8846e10SFelix Fietkau 		u8 buffer_mode;
310c8846e10SFelix Fietkau 		u8 len;
311c8846e10SFelix Fietkau 		u8 pad[2];
3124d2a6f7bSLorenzo Bianconi 	} req_hdr = {
313c8846e10SFelix Fietkau 		.buffer_mode = 1,
314c8846e10SFelix Fietkau 		.len = ARRAY_SIZE(req_fields) - 1,
315c8846e10SFelix Fietkau 	};
3164d2a6f7bSLorenzo Bianconi 	const int size = 0xff * sizeof(struct req_data);
3174d2a6f7bSLorenzo Bianconi 	u8 *req, *eep = (u8 *)dev->mt76.eeprom.data;
3184d2a6f7bSLorenzo Bianconi 	int i, ret, len = sizeof(req_hdr) + size;
3194d2a6f7bSLorenzo Bianconi 	struct req_data *data;
320c8846e10SFelix Fietkau 
3214d2a6f7bSLorenzo Bianconi 	BUILD_BUG_ON(ARRAY_SIZE(req_fields) * sizeof(*data) > size);
322c8846e10SFelix Fietkau 
3234d2a6f7bSLorenzo Bianconi 	req = kmalloc(len, GFP_KERNEL);
3244d2a6f7bSLorenzo Bianconi 	if (!req)
3254d2a6f7bSLorenzo Bianconi 		return -ENOMEM;
3264d2a6f7bSLorenzo Bianconi 
3274d2a6f7bSLorenzo Bianconi 	memcpy(req, &req_hdr, sizeof(req_hdr));
3284d2a6f7bSLorenzo Bianconi 	data = (struct req_data *)(req + sizeof(req_hdr));
3294d2a6f7bSLorenzo Bianconi 	memset(data, 0, size);
330c8846e10SFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(req_fields); i++) {
3314d2a6f7bSLorenzo Bianconi 		data[i].addr = cpu_to_le16(req_fields[i]);
3324d2a6f7bSLorenzo Bianconi 		data[i].val = eep[req_fields[i]];
333c8846e10SFelix Fietkau 	}
334c8846e10SFelix Fietkau 
335cb5cdd4cSFelix Fietkau 	ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EFUSE_BUFFER_MODE,
3364d2a6f7bSLorenzo Bianconi 				req, len, true);
3374d2a6f7bSLorenzo Bianconi 	kfree(req);
3384d2a6f7bSLorenzo Bianconi 
3394d2a6f7bSLorenzo Bianconi 	return ret;
340c8846e10SFelix Fietkau }
341c8846e10SFelix Fietkau 
342c8846e10SFelix Fietkau static int mt7603_mcu_set_tx_power(struct mt7603_dev *dev)
343c8846e10SFelix Fietkau {
344c8846e10SFelix Fietkau 	struct {
345c8846e10SFelix Fietkau 		u8 center_channel;
346c8846e10SFelix Fietkau 		u8 tssi;
347c8846e10SFelix Fietkau 		u8 temp_comp;
348c8846e10SFelix Fietkau 		u8 target_power[2];
349c8846e10SFelix Fietkau 		u8 rate_power_delta[14];
350c8846e10SFelix Fietkau 		u8 bw_power_delta;
351c8846e10SFelix Fietkau 		u8 ch_power_delta[6];
352c8846e10SFelix Fietkau 		u8 temp_comp_power[17];
353c8846e10SFelix Fietkau 		u8 reserved;
354c8846e10SFelix Fietkau 	} req = {
35596747a51SFelix Fietkau 		.center_channel = dev->mphy.chandef.chan->hw_value,
356c8846e10SFelix Fietkau #define EEP_VAL(n) ((u8 *)dev->mt76.eeprom.data)[n]
357c8846e10SFelix Fietkau 		.tssi = EEP_VAL(MT_EE_NIC_CONF_1 + 1),
358c8846e10SFelix Fietkau 		.temp_comp = EEP_VAL(MT_EE_NIC_CONF_1),
359c8846e10SFelix Fietkau 		.target_power = {
360c8846e10SFelix Fietkau 			EEP_VAL(MT_EE_TX_POWER_0_START_2G + 2),
361c8846e10SFelix Fietkau 			EEP_VAL(MT_EE_TX_POWER_1_START_2G + 2)
362c8846e10SFelix Fietkau 		},
363c8846e10SFelix Fietkau 		.bw_power_delta = EEP_VAL(MT_EE_TX_POWER_DELTA_BW40),
364c8846e10SFelix Fietkau 		.ch_power_delta = {
365c8846e10SFelix Fietkau 			EEP_VAL(MT_EE_TX_POWER_0_START_2G + 3),
366c8846e10SFelix Fietkau 			EEP_VAL(MT_EE_TX_POWER_0_START_2G + 4),
367c8846e10SFelix Fietkau 			EEP_VAL(MT_EE_TX_POWER_0_START_2G + 5),
368c8846e10SFelix Fietkau 			EEP_VAL(MT_EE_TX_POWER_1_START_2G + 3),
369c8846e10SFelix Fietkau 			EEP_VAL(MT_EE_TX_POWER_1_START_2G + 4),
370c8846e10SFelix Fietkau 			EEP_VAL(MT_EE_TX_POWER_1_START_2G + 5)
371c8846e10SFelix Fietkau 		},
372c8846e10SFelix Fietkau #undef EEP_VAL
373c8846e10SFelix Fietkau 	};
374c8846e10SFelix Fietkau 	u8 *eep = (u8 *)dev->mt76.eeprom.data;
375c8846e10SFelix Fietkau 
376c8846e10SFelix Fietkau 	memcpy(req.rate_power_delta, eep + MT_EE_TX_POWER_CCK,
377c8846e10SFelix Fietkau 	       sizeof(req.rate_power_delta));
378c8846e10SFelix Fietkau 
379c8846e10SFelix Fietkau 	memcpy(req.temp_comp_power, eep + MT_EE_STEP_NUM_NEG_6_7,
380c8846e10SFelix Fietkau 	       sizeof(req.temp_comp_power));
381c8846e10SFelix Fietkau 
382cb5cdd4cSFelix Fietkau 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_TX_POWER_CTRL,
38311ca82d7SLorenzo Bianconi 				 &req, sizeof(req), true);
384c8846e10SFelix Fietkau }
385c8846e10SFelix Fietkau 
386c8846e10SFelix Fietkau int mt7603_mcu_set_channel(struct mt7603_dev *dev)
387c8846e10SFelix Fietkau {
38896747a51SFelix Fietkau 	struct cfg80211_chan_def *chandef = &dev->mphy.chandef;
389c8846e10SFelix Fietkau 	struct ieee80211_hw *hw = mt76_hw(dev);
390beaaeb6bSFelix Fietkau 	int n_chains = hweight8(dev->mphy.antenna_mask);
391c8846e10SFelix Fietkau 	struct {
392c8846e10SFelix Fietkau 		u8 control_chan;
393c8846e10SFelix Fietkau 		u8 center_chan;
394c8846e10SFelix Fietkau 		u8 bw;
395c8846e10SFelix Fietkau 		u8 tx_streams;
396c8846e10SFelix Fietkau 		u8 rx_streams;
397c8846e10SFelix Fietkau 		u8 _res0[7];
398c8846e10SFelix Fietkau 		u8 txpower[21];
399c8846e10SFelix Fietkau 		u8 _res1[3];
400c8846e10SFelix Fietkau 	} req = {
401c8846e10SFelix Fietkau 		.control_chan = chandef->chan->hw_value,
402c8846e10SFelix Fietkau 		.center_chan = chandef->chan->hw_value,
403c8846e10SFelix Fietkau 		.bw = MT_BW_20,
404c8846e10SFelix Fietkau 		.tx_streams = n_chains,
405c8846e10SFelix Fietkau 		.rx_streams = n_chains,
406c8846e10SFelix Fietkau 	};
407c8846e10SFelix Fietkau 	s8 tx_power;
40811ca82d7SLorenzo Bianconi 	int i, ret;
409c8846e10SFelix Fietkau 
41096747a51SFelix Fietkau 	if (dev->mphy.chandef.width == NL80211_CHAN_WIDTH_40) {
411c8846e10SFelix Fietkau 		req.bw = MT_BW_40;
412c8846e10SFelix Fietkau 		if (chandef->center_freq1 > chandef->chan->center_freq)
413c8846e10SFelix Fietkau 			req.center_chan += 2;
414c8846e10SFelix Fietkau 		else
415c8846e10SFelix Fietkau 			req.center_chan -= 2;
416c8846e10SFelix Fietkau 	}
417c8846e10SFelix Fietkau 
418c8846e10SFelix Fietkau 	tx_power = hw->conf.power_level * 2;
419beaaeb6bSFelix Fietkau 	if (dev->mphy.antenna_mask == 3)
420c8846e10SFelix Fietkau 		tx_power -= 6;
421c8846e10SFelix Fietkau 	tx_power = min(tx_power, dev->tx_power_limit);
422c8846e10SFelix Fietkau 
423beaaeb6bSFelix Fietkau 	dev->mphy.txpower_cur = tx_power;
424c8846e10SFelix Fietkau 
425c8846e10SFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(req.txpower); i++)
426c8846e10SFelix Fietkau 		req.txpower[i] = tx_power;
427c8846e10SFelix Fietkau 
428cb5cdd4cSFelix Fietkau 	ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_CHANNEL_SWITCH, &req,
429cb5cdd4cSFelix Fietkau 				sizeof(req), true);
430c8846e10SFelix Fietkau 	if (ret)
431c8846e10SFelix Fietkau 		return ret;
432c8846e10SFelix Fietkau 
433c8846e10SFelix Fietkau 	return mt7603_mcu_set_tx_power(dev);
434c8846e10SFelix Fietkau }
435