1c8846e10SFelix Fietkau /* 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
17114fe5e3SLorenzo Bianconi __mt7603_mcu_msg_send(struct mt7603_dev *dev, struct sk_buff *skb,
18114fe5e3SLorenzo Bianconi 		      int cmd, int *wait_seq)
19c8846e10SFelix Fietkau {
20c8846e10SFelix Fietkau 	int hdrlen = dev->mcu_running ? sizeof(struct mt7603_mcu_txd) : 12;
21c8846e10SFelix Fietkau 	struct mt76_dev *mdev = &dev->mt76;
22c8846e10SFelix Fietkau 	struct mt7603_mcu_txd *txd;
23c8846e10SFelix Fietkau 	u8 seq;
24c8846e10SFelix Fietkau 
25c8846e10SFelix Fietkau 	seq = ++mdev->mmio.mcu.msg_seq & 0xf;
26c8846e10SFelix Fietkau 	if (!seq)
27c8846e10SFelix Fietkau 		seq = ++mdev->mmio.mcu.msg_seq & 0xf;
28c8846e10SFelix Fietkau 
29c8846e10SFelix Fietkau 	txd = (struct mt7603_mcu_txd *)skb_push(skb, hdrlen);
30c8846e10SFelix Fietkau 	memset(txd, 0, hdrlen);
31c8846e10SFelix Fietkau 
32c8846e10SFelix Fietkau 	txd->len = cpu_to_le16(skb->len);
33c8846e10SFelix Fietkau 	if (cmd == -MCU_CMD_FW_SCATTER)
34c8846e10SFelix Fietkau 		txd->pq_id = cpu_to_le16(MCU_PORT_QUEUE_FW);
35c8846e10SFelix Fietkau 	else
36c8846e10SFelix Fietkau 		txd->pq_id = cpu_to_le16(MCU_PORT_QUEUE);
37c8846e10SFelix Fietkau 	txd->pkt_type = MCU_PKT_ID;
38c8846e10SFelix Fietkau 	txd->seq = seq;
39c8846e10SFelix Fietkau 
40c8846e10SFelix Fietkau 	if (cmd < 0) {
41c8846e10SFelix Fietkau 		txd->cid = -cmd;
42114fe5e3SLorenzo Bianconi 		txd->set_query = MCU_Q_NA;
43c8846e10SFelix Fietkau 	} else {
44c8846e10SFelix Fietkau 		txd->cid = MCU_CMD_EXT_CID;
45c8846e10SFelix Fietkau 		txd->ext_cid = cmd;
46114fe5e3SLorenzo Bianconi 		txd->set_query = MCU_Q_SET;
47c8846e10SFelix Fietkau 		txd->ext_cid_ack = 1;
48c8846e10SFelix Fietkau 	}
49c8846e10SFelix Fietkau 
50c8846e10SFelix Fietkau 	if (wait_seq)
51c8846e10SFelix Fietkau 		*wait_seq = seq;
52c8846e10SFelix Fietkau 
53c8846e10SFelix Fietkau 	return mt76_tx_queue_skb_raw(dev, MT_TXQ_MCU, skb, 0);
54c8846e10SFelix Fietkau }
55c8846e10SFelix Fietkau 
56c8846e10SFelix Fietkau static int
5711ca82d7SLorenzo Bianconi mt7603_mcu_msg_send(struct mt7603_dev *dev, int cmd, const void *data,
5811ca82d7SLorenzo Bianconi 		    int len, bool wait_resp)
59c8846e10SFelix Fietkau {
60c8846e10SFelix Fietkau 	struct mt76_dev *mdev = &dev->mt76;
61c8846e10SFelix Fietkau 	unsigned long expires = jiffies + 3 * HZ;
62c8846e10SFelix Fietkau 	struct mt7603_mcu_rxd *rxd;
6311ca82d7SLorenzo Bianconi 	struct sk_buff *skb;
64c8846e10SFelix Fietkau 	int ret, seq;
65c8846e10SFelix Fietkau 
6611ca82d7SLorenzo Bianconi 	skb = mt7603_mcu_msg_alloc(data, len);
6711ca82d7SLorenzo Bianconi 	if (!skb)
6811ca82d7SLorenzo Bianconi 		return -ENOMEM;
6911ca82d7SLorenzo Bianconi 
70c8846e10SFelix Fietkau 	mutex_lock(&mdev->mmio.mcu.mutex);
71c8846e10SFelix Fietkau 
72114fe5e3SLorenzo Bianconi 	ret = __mt7603_mcu_msg_send(dev, skb, cmd, &seq);
73c8846e10SFelix Fietkau 	if (ret)
74c8846e10SFelix Fietkau 		goto out;
75c8846e10SFelix Fietkau 
7611ca82d7SLorenzo Bianconi 	while (wait_resp) {
77c8846e10SFelix Fietkau 		bool check_seq = false;
78c8846e10SFelix Fietkau 
79c8846e10SFelix Fietkau 		skb = mt76_mcu_get_response(&dev->mt76, expires);
80c8846e10SFelix Fietkau 		if (!skb) {
81c8846e10SFelix Fietkau 			dev_err(mdev->dev,
82c8846e10SFelix Fietkau 				"MCU message %d (seq %d) timed out\n",
83c8846e10SFelix Fietkau 				cmd, seq);
84c8846e10SFelix Fietkau 			dev->mcu_hang = MT7603_WATCHDOG_TIMEOUT;
85c8846e10SFelix Fietkau 			ret = -ETIMEDOUT;
86c8846e10SFelix Fietkau 			break;
87c8846e10SFelix Fietkau 		}
88c8846e10SFelix Fietkau 
89c8846e10SFelix Fietkau 		rxd = (struct mt7603_mcu_rxd *)skb->data;
90c8846e10SFelix Fietkau 		if (seq == rxd->seq)
91c8846e10SFelix Fietkau 			check_seq = true;
92c8846e10SFelix Fietkau 
93c8846e10SFelix Fietkau 		dev_kfree_skb(skb);
94c8846e10SFelix Fietkau 
95c8846e10SFelix Fietkau 		if (check_seq)
96c8846e10SFelix Fietkau 			break;
97c8846e10SFelix Fietkau 	}
98c8846e10SFelix Fietkau 
99c8846e10SFelix Fietkau out:
100c8846e10SFelix Fietkau 	mutex_unlock(&mdev->mmio.mcu.mutex);
101c8846e10SFelix Fietkau 
102c8846e10SFelix Fietkau 	return ret;
103c8846e10SFelix Fietkau }
104c8846e10SFelix Fietkau 
105c8846e10SFelix Fietkau static int
106c8846e10SFelix Fietkau mt7603_mcu_init_download(struct mt7603_dev *dev, u32 addr, u32 len)
107c8846e10SFelix Fietkau {
108c8846e10SFelix Fietkau 	struct {
109c8846e10SFelix Fietkau 		__le32 addr;
110c8846e10SFelix Fietkau 		__le32 len;
111c8846e10SFelix Fietkau 		__le32 mode;
112c8846e10SFelix Fietkau 	} req = {
113c8846e10SFelix Fietkau 		.addr = cpu_to_le32(addr),
114c8846e10SFelix Fietkau 		.len = cpu_to_le32(len),
115c8846e10SFelix Fietkau 		.mode = cpu_to_le32(BIT(31)),
116c8846e10SFelix Fietkau 	};
117c8846e10SFelix Fietkau 
11811ca82d7SLorenzo Bianconi 	return mt7603_mcu_msg_send(dev, -MCU_CMD_TARGET_ADDRESS_LEN_REQ,
11911ca82d7SLorenzo Bianconi 				   &req, sizeof(req), true);
120c8846e10SFelix Fietkau }
121c8846e10SFelix Fietkau 
122c8846e10SFelix Fietkau static int
123c8846e10SFelix Fietkau mt7603_mcu_send_firmware(struct mt7603_dev *dev, const void *data, int len)
124c8846e10SFelix Fietkau {
125c8846e10SFelix Fietkau 	struct sk_buff *skb;
126c8846e10SFelix Fietkau 	int ret = 0;
127c8846e10SFelix Fietkau 
128c8846e10SFelix Fietkau 	while (len > 0) {
129c8846e10SFelix Fietkau 		int cur_len = min_t(int, 4096 - sizeof(struct mt7603_mcu_txd),
130c8846e10SFelix Fietkau 				    len);
131c8846e10SFelix Fietkau 
132c8846e10SFelix Fietkau 		skb = mt7603_mcu_msg_alloc(data, cur_len);
133c8846e10SFelix Fietkau 		if (!skb)
134c8846e10SFelix Fietkau 			return -ENOMEM;
135c8846e10SFelix Fietkau 
136c8846e10SFelix Fietkau 		ret = __mt7603_mcu_msg_send(dev, skb, -MCU_CMD_FW_SCATTER,
137114fe5e3SLorenzo Bianconi 					    NULL);
138c8846e10SFelix Fietkau 		if (ret)
139c8846e10SFelix Fietkau 			break;
140c8846e10SFelix Fietkau 
141c8846e10SFelix Fietkau 		data += cur_len;
142c8846e10SFelix Fietkau 		len -= cur_len;
143c8846e10SFelix Fietkau 	}
144c8846e10SFelix Fietkau 
145c8846e10SFelix Fietkau 	return ret;
146c8846e10SFelix Fietkau }
147c8846e10SFelix Fietkau 
148c8846e10SFelix Fietkau static int
149c8846e10SFelix Fietkau mt7603_mcu_start_firmware(struct mt7603_dev *dev, u32 addr)
150c8846e10SFelix Fietkau {
151c8846e10SFelix Fietkau 	struct {
152c8846e10SFelix Fietkau 		__le32 override;
153c8846e10SFelix Fietkau 		__le32 addr;
154c8846e10SFelix Fietkau 	} req = {
155c8846e10SFelix Fietkau 		.override = cpu_to_le32(addr ? 1 : 0),
156c8846e10SFelix Fietkau 		.addr = cpu_to_le32(addr),
157c8846e10SFelix Fietkau 	};
158c8846e10SFelix Fietkau 
15911ca82d7SLorenzo Bianconi 	return mt7603_mcu_msg_send(dev, -MCU_CMD_FW_START_REQ,
16011ca82d7SLorenzo Bianconi 				   &req, sizeof(req), true);
161c8846e10SFelix Fietkau }
162c8846e10SFelix Fietkau 
163c8846e10SFelix Fietkau static int
164c8846e10SFelix Fietkau mt7603_mcu_restart(struct mt7603_dev *dev)
165c8846e10SFelix Fietkau {
16611ca82d7SLorenzo Bianconi 	return mt7603_mcu_msg_send(dev, -MCU_CMD_RESTART_DL_REQ,
16711ca82d7SLorenzo Bianconi 				   NULL, 0, true);
168c8846e10SFelix Fietkau }
169c8846e10SFelix Fietkau 
170047348fbSLorenzo Bianconi int mt7603_load_firmware(struct mt7603_dev *dev)
171c8846e10SFelix Fietkau {
172c8846e10SFelix Fietkau 	const struct firmware *fw;
173c8846e10SFelix Fietkau 	const struct mt7603_fw_trailer *hdr;
174c8846e10SFelix Fietkau 	const char *firmware;
175c8846e10SFelix Fietkau 	int dl_len;
176c8846e10SFelix Fietkau 	u32 addr, val;
177c8846e10SFelix Fietkau 	int ret;
178c8846e10SFelix Fietkau 
179c8846e10SFelix Fietkau 	if (is_mt7628(dev)) {
180c8846e10SFelix Fietkau 		if (mt76xx_rev(dev) == MT7628_REV_E1)
181c8846e10SFelix Fietkau 			firmware = MT7628_FIRMWARE_E1;
182c8846e10SFelix Fietkau 		else
183c8846e10SFelix Fietkau 			firmware = MT7628_FIRMWARE_E2;
184c8846e10SFelix Fietkau 	} else {
185c8846e10SFelix Fietkau 		if (mt76xx_rev(dev) < MT7603_REV_E2)
186c8846e10SFelix Fietkau 			firmware = MT7603_FIRMWARE_E1;
187c8846e10SFelix Fietkau 		else
188c8846e10SFelix Fietkau 			firmware = MT7603_FIRMWARE_E2;
189c8846e10SFelix Fietkau 	}
190c8846e10SFelix Fietkau 
191c8846e10SFelix Fietkau 	ret = request_firmware(&fw, firmware, dev->mt76.dev);
192c8846e10SFelix Fietkau 	if (ret)
193c8846e10SFelix Fietkau 		return ret;
194c8846e10SFelix Fietkau 
195c8846e10SFelix Fietkau 	if (!fw || !fw->data || fw->size < sizeof(*hdr)) {
196c8846e10SFelix Fietkau 		dev_err(dev->mt76.dev, "Invalid firmware\n");
197c8846e10SFelix Fietkau 		ret = -EINVAL;
198c8846e10SFelix Fietkau 		goto out;
199c8846e10SFelix Fietkau 	}
200c8846e10SFelix Fietkau 
201c8846e10SFelix Fietkau 	hdr = (const struct mt7603_fw_trailer *)(fw->data + fw->size -
202c8846e10SFelix Fietkau 						 sizeof(*hdr));
203c8846e10SFelix Fietkau 
204c8846e10SFelix Fietkau 	dev_info(dev->mt76.dev, "Firmware Version: %.10s\n", hdr->fw_ver);
205c8846e10SFelix Fietkau 	dev_info(dev->mt76.dev, "Build Time: %.15s\n", hdr->build_date);
206c8846e10SFelix Fietkau 
207c8846e10SFelix Fietkau 	addr = mt7603_reg_map(dev, 0x50012498);
208c8846e10SFelix Fietkau 	mt76_wr(dev, addr, 0x5);
209c8846e10SFelix Fietkau 	mt76_wr(dev, addr, 0x5);
210c8846e10SFelix Fietkau 	udelay(1);
211c8846e10SFelix Fietkau 
212c8846e10SFelix Fietkau 	/* switch to bypass mode */
213c8846e10SFelix Fietkau 	mt76_rmw(dev, MT_SCH_4, MT_SCH_4_FORCE_QID,
214c8846e10SFelix Fietkau 		 MT_SCH_4_BYPASS | FIELD_PREP(MT_SCH_4_FORCE_QID, 5));
215c8846e10SFelix Fietkau 
216c8846e10SFelix Fietkau 	val = mt76_rr(dev, MT_TOP_MISC2);
217c8846e10SFelix Fietkau 	if (val & BIT(1)) {
218c8846e10SFelix Fietkau 		dev_info(dev->mt76.dev, "Firmware already running...\n");
219c8846e10SFelix Fietkau 		goto running;
220c8846e10SFelix Fietkau 	}
221c8846e10SFelix Fietkau 
222c8846e10SFelix Fietkau 	if (!mt76_poll_msec(dev, MT_TOP_MISC2, BIT(0) | BIT(1), BIT(0), 500)) {
223c8846e10SFelix Fietkau 		dev_err(dev->mt76.dev, "Timeout waiting for ROM code to become ready\n");
224c8846e10SFelix Fietkau 		ret = -EIO;
225c8846e10SFelix Fietkau 		goto out;
226c8846e10SFelix Fietkau 	}
227c8846e10SFelix Fietkau 
228c8846e10SFelix Fietkau 	dl_len = le32_to_cpu(hdr->dl_len) + 4;
229c8846e10SFelix Fietkau 	ret = mt7603_mcu_init_download(dev, MCU_FIRMWARE_ADDRESS, dl_len);
230c8846e10SFelix Fietkau 	if (ret) {
231c8846e10SFelix Fietkau 		dev_err(dev->mt76.dev, "Download request failed\n");
232c8846e10SFelix Fietkau 		goto out;
233c8846e10SFelix Fietkau 	}
234c8846e10SFelix Fietkau 
235c8846e10SFelix Fietkau 	ret = mt7603_mcu_send_firmware(dev, fw->data, dl_len);
236c8846e10SFelix Fietkau 	if (ret) {
237c8846e10SFelix Fietkau 		dev_err(dev->mt76.dev, "Failed to send firmware to device\n");
238c8846e10SFelix Fietkau 		goto out;
239c8846e10SFelix Fietkau 	}
240c8846e10SFelix Fietkau 
241c8846e10SFelix Fietkau 	ret = mt7603_mcu_start_firmware(dev, MCU_FIRMWARE_ADDRESS);
242c8846e10SFelix Fietkau 	if (ret) {
243c8846e10SFelix Fietkau 		dev_err(dev->mt76.dev, "Failed to start firmware\n");
244c8846e10SFelix Fietkau 		goto out;
245c8846e10SFelix Fietkau 	}
246c8846e10SFelix Fietkau 
247c8846e10SFelix Fietkau 	if (!mt76_poll_msec(dev, MT_TOP_MISC2, BIT(1), BIT(1), 500)) {
248c8846e10SFelix Fietkau 		dev_err(dev->mt76.dev, "Timeout waiting for firmware to initialize\n");
249c8846e10SFelix Fietkau 		ret = -EIO;
250c8846e10SFelix Fietkau 		goto out;
251c8846e10SFelix Fietkau 	}
252c8846e10SFelix Fietkau 
253c8846e10SFelix Fietkau running:
254c8846e10SFelix Fietkau 	mt76_clear(dev, MT_SCH_4, MT_SCH_4_FORCE_QID | MT_SCH_4_BYPASS);
255c8846e10SFelix Fietkau 
256c8846e10SFelix Fietkau 	mt76_set(dev, MT_SCH_4, BIT(8));
257c8846e10SFelix Fietkau 	mt76_clear(dev, MT_SCH_4, BIT(8));
258c8846e10SFelix Fietkau 
259c8846e10SFelix Fietkau 	dev->mcu_running = true;
260c8846e10SFelix Fietkau 	dev_info(dev->mt76.dev, "firmware init done\n");
261c8846e10SFelix Fietkau 
262c8846e10SFelix Fietkau out:
263c8846e10SFelix Fietkau 	release_firmware(fw);
264c8846e10SFelix Fietkau 
265c8846e10SFelix Fietkau 	return ret;
266c8846e10SFelix Fietkau }
267c8846e10SFelix Fietkau 
268c8846e10SFelix Fietkau void mt7603_mcu_exit(struct mt7603_dev *dev)
269c8846e10SFelix Fietkau {
270c8846e10SFelix Fietkau 	mt7603_mcu_restart(dev);
271c8846e10SFelix Fietkau 	skb_queue_purge(&dev->mt76.mmio.mcu.res_q);
272c8846e10SFelix Fietkau }
273c8846e10SFelix Fietkau 
274c8846e10SFelix Fietkau int mt7603_mcu_set_eeprom(struct mt7603_dev *dev)
275c8846e10SFelix Fietkau {
276c8846e10SFelix Fietkau 	static const u16 req_fields[] = {
277c8846e10SFelix Fietkau #define WORD(_start)			\
278c8846e10SFelix Fietkau 		_start,			\
279c8846e10SFelix Fietkau 		_start + 1
280c8846e10SFelix Fietkau #define GROUP_2G(_start)		\
281c8846e10SFelix Fietkau 		WORD(_start),		\
282c8846e10SFelix Fietkau 		WORD(_start + 2),	\
283c8846e10SFelix Fietkau 		WORD(_start + 4)
284c8846e10SFelix Fietkau 
285c8846e10SFelix Fietkau 		MT_EE_NIC_CONF_0 + 1,
286c8846e10SFelix Fietkau 		WORD(MT_EE_NIC_CONF_1),
287c8846e10SFelix Fietkau 		MT_EE_WIFI_RF_SETTING,
288c8846e10SFelix Fietkau 		MT_EE_TX_POWER_DELTA_BW40,
289c8846e10SFelix Fietkau 		MT_EE_TX_POWER_DELTA_BW80 + 1,
290c8846e10SFelix Fietkau 		MT_EE_TX_POWER_EXT_PA_5G,
291c8846e10SFelix Fietkau 		MT_EE_TEMP_SENSOR_CAL,
292c8846e10SFelix Fietkau 		GROUP_2G(MT_EE_TX_POWER_0_START_2G),
293c8846e10SFelix Fietkau 		GROUP_2G(MT_EE_TX_POWER_1_START_2G),
294c8846e10SFelix Fietkau 		WORD(MT_EE_TX_POWER_CCK),
295c8846e10SFelix Fietkau 		WORD(MT_EE_TX_POWER_OFDM_2G_6M),
296c8846e10SFelix Fietkau 		WORD(MT_EE_TX_POWER_OFDM_2G_24M),
297c8846e10SFelix Fietkau 		WORD(MT_EE_TX_POWER_OFDM_2G_54M),
298c8846e10SFelix Fietkau 		WORD(MT_EE_TX_POWER_HT_BPSK_QPSK),
299c8846e10SFelix Fietkau 		WORD(MT_EE_TX_POWER_HT_16_64_QAM),
300c8846e10SFelix Fietkau 		WORD(MT_EE_TX_POWER_HT_64_QAM),
301c8846e10SFelix Fietkau 		MT_EE_ELAN_RX_MODE_GAIN,
302c8846e10SFelix Fietkau 		MT_EE_ELAN_RX_MODE_NF,
303c8846e10SFelix Fietkau 		MT_EE_ELAN_RX_MODE_P1DB,
304c8846e10SFelix Fietkau 		MT_EE_ELAN_BYPASS_MODE_GAIN,
305c8846e10SFelix Fietkau 		MT_EE_ELAN_BYPASS_MODE_NF,
306c8846e10SFelix Fietkau 		MT_EE_ELAN_BYPASS_MODE_P1DB,
307c8846e10SFelix Fietkau 		WORD(MT_EE_STEP_NUM_NEG_6_7),
308c8846e10SFelix Fietkau 		WORD(MT_EE_STEP_NUM_NEG_4_5),
309c8846e10SFelix Fietkau 		WORD(MT_EE_STEP_NUM_NEG_2_3),
310c8846e10SFelix Fietkau 		WORD(MT_EE_STEP_NUM_NEG_0_1),
311c8846e10SFelix Fietkau 		WORD(MT_EE_REF_STEP_24G),
312c8846e10SFelix Fietkau 		WORD(MT_EE_STEP_NUM_PLUS_1_2),
313c8846e10SFelix Fietkau 		WORD(MT_EE_STEP_NUM_PLUS_3_4),
314c8846e10SFelix Fietkau 		WORD(MT_EE_STEP_NUM_PLUS_5_6),
315c8846e10SFelix Fietkau 		MT_EE_STEP_NUM_PLUS_7,
316c8846e10SFelix Fietkau 		MT_EE_XTAL_FREQ_OFFSET,
317c8846e10SFelix Fietkau 		MT_EE_XTAL_TRIM_2_COMP,
318c8846e10SFelix Fietkau 		MT_EE_XTAL_TRIM_3_COMP,
319c8846e10SFelix Fietkau 		MT_EE_XTAL_WF_RFCAL,
320c8846e10SFelix Fietkau 
321c8846e10SFelix Fietkau 		/* unknown fields below */
322c8846e10SFelix Fietkau 		WORD(0x24),
323c8846e10SFelix Fietkau 		0x34,
324c8846e10SFelix Fietkau 		0x39,
325c8846e10SFelix Fietkau 		0x3b,
326c8846e10SFelix Fietkau 		WORD(0x42),
327c8846e10SFelix Fietkau 		WORD(0x9e),
328c8846e10SFelix Fietkau 		0xf2,
329c8846e10SFelix Fietkau 		WORD(0xf8),
330c8846e10SFelix Fietkau 		0xfa,
331c8846e10SFelix Fietkau 		0x12e,
332c8846e10SFelix Fietkau 		WORD(0x130), WORD(0x132), WORD(0x134), WORD(0x136),
333c8846e10SFelix Fietkau 		WORD(0x138), WORD(0x13a), WORD(0x13c), WORD(0x13e),
334c8846e10SFelix Fietkau 
335c8846e10SFelix Fietkau #undef GROUP_2G
336c8846e10SFelix Fietkau #undef WORD
337c8846e10SFelix Fietkau 
338c8846e10SFelix Fietkau 	};
339c8846e10SFelix Fietkau 	struct req_data {
340c8846e10SFelix Fietkau 		u16 addr;
341c8846e10SFelix Fietkau 		u8 val;
342c8846e10SFelix Fietkau 		u8 pad;
343c8846e10SFelix Fietkau 	} __packed;
344c8846e10SFelix Fietkau 	struct {
345c8846e10SFelix Fietkau 		u8 buffer_mode;
346c8846e10SFelix Fietkau 		u8 len;
347c8846e10SFelix Fietkau 		u8 pad[2];
34811ca82d7SLorenzo Bianconi 		struct req_data data[255];
34911ca82d7SLorenzo Bianconi 	} req = {
350c8846e10SFelix Fietkau 		.buffer_mode = 1,
351c8846e10SFelix Fietkau 		.len = ARRAY_SIZE(req_fields) - 1,
352c8846e10SFelix Fietkau 	};
353c8846e10SFelix Fietkau 	u8 *eep = (u8 *)dev->mt76.eeprom.data;
354c8846e10SFelix Fietkau 	int i;
355c8846e10SFelix Fietkau 
35611ca82d7SLorenzo Bianconi 	BUILD_BUG_ON(ARRAY_SIZE(req_fields) > ARRAY_SIZE(req.data));
357c8846e10SFelix Fietkau 
358c8846e10SFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(req_fields); i++) {
35911ca82d7SLorenzo Bianconi 		req.data[i].addr = cpu_to_le16(req_fields[i]);
36011ca82d7SLorenzo Bianconi 		req.data[i].val = eep[req_fields[i]];
36111ca82d7SLorenzo Bianconi 		req.data[i].pad = 0;
362c8846e10SFelix Fietkau 	}
363c8846e10SFelix Fietkau 
36411ca82d7SLorenzo Bianconi 	return mt7603_mcu_msg_send(dev, MCU_EXT_CMD_EFUSE_BUFFER_MODE,
36511ca82d7SLorenzo Bianconi 				   &req, sizeof(req), true);
366c8846e10SFelix Fietkau }
367c8846e10SFelix Fietkau 
368c8846e10SFelix Fietkau static int mt7603_mcu_set_tx_power(struct mt7603_dev *dev)
369c8846e10SFelix Fietkau {
370c8846e10SFelix Fietkau 	struct {
371c8846e10SFelix Fietkau 		u8 center_channel;
372c8846e10SFelix Fietkau 		u8 tssi;
373c8846e10SFelix Fietkau 		u8 temp_comp;
374c8846e10SFelix Fietkau 		u8 target_power[2];
375c8846e10SFelix Fietkau 		u8 rate_power_delta[14];
376c8846e10SFelix Fietkau 		u8 bw_power_delta;
377c8846e10SFelix Fietkau 		u8 ch_power_delta[6];
378c8846e10SFelix Fietkau 		u8 temp_comp_power[17];
379c8846e10SFelix Fietkau 		u8 reserved;
380c8846e10SFelix Fietkau 	} req = {
381c8846e10SFelix Fietkau 		.center_channel = dev->mt76.chandef.chan->hw_value,
382c8846e10SFelix Fietkau #define EEP_VAL(n) ((u8 *)dev->mt76.eeprom.data)[n]
383c8846e10SFelix Fietkau 		.tssi = EEP_VAL(MT_EE_NIC_CONF_1 + 1),
384c8846e10SFelix Fietkau 		.temp_comp = EEP_VAL(MT_EE_NIC_CONF_1),
385c8846e10SFelix Fietkau 		.target_power = {
386c8846e10SFelix Fietkau 			EEP_VAL(MT_EE_TX_POWER_0_START_2G + 2),
387c8846e10SFelix Fietkau 			EEP_VAL(MT_EE_TX_POWER_1_START_2G + 2)
388c8846e10SFelix Fietkau 		},
389c8846e10SFelix Fietkau 		.bw_power_delta = EEP_VAL(MT_EE_TX_POWER_DELTA_BW40),
390c8846e10SFelix Fietkau 		.ch_power_delta = {
391c8846e10SFelix Fietkau 			EEP_VAL(MT_EE_TX_POWER_0_START_2G + 3),
392c8846e10SFelix Fietkau 			EEP_VAL(MT_EE_TX_POWER_0_START_2G + 4),
393c8846e10SFelix Fietkau 			EEP_VAL(MT_EE_TX_POWER_0_START_2G + 5),
394c8846e10SFelix Fietkau 			EEP_VAL(MT_EE_TX_POWER_1_START_2G + 3),
395c8846e10SFelix Fietkau 			EEP_VAL(MT_EE_TX_POWER_1_START_2G + 4),
396c8846e10SFelix Fietkau 			EEP_VAL(MT_EE_TX_POWER_1_START_2G + 5)
397c8846e10SFelix Fietkau 		},
398c8846e10SFelix Fietkau #undef EEP_VAL
399c8846e10SFelix Fietkau 	};
400c8846e10SFelix Fietkau 	u8 *eep = (u8 *)dev->mt76.eeprom.data;
401c8846e10SFelix Fietkau 
402c8846e10SFelix Fietkau 	memcpy(req.rate_power_delta, eep + MT_EE_TX_POWER_CCK,
403c8846e10SFelix Fietkau 	       sizeof(req.rate_power_delta));
404c8846e10SFelix Fietkau 
405c8846e10SFelix Fietkau 	memcpy(req.temp_comp_power, eep + MT_EE_STEP_NUM_NEG_6_7,
406c8846e10SFelix Fietkau 	       sizeof(req.temp_comp_power));
407c8846e10SFelix Fietkau 
40811ca82d7SLorenzo Bianconi 	return mt7603_mcu_msg_send(dev, MCU_EXT_CMD_SET_TX_POWER_CTRL,
40911ca82d7SLorenzo Bianconi 				   &req, sizeof(req), true);
410c8846e10SFelix Fietkau }
411c8846e10SFelix Fietkau 
412c8846e10SFelix Fietkau int mt7603_mcu_set_channel(struct mt7603_dev *dev)
413c8846e10SFelix Fietkau {
414c8846e10SFelix Fietkau 	struct cfg80211_chan_def *chandef = &dev->mt76.chandef;
415c8846e10SFelix Fietkau 	struct ieee80211_hw *hw = mt76_hw(dev);
416f2a00a82SFelix Fietkau 	int n_chains = hweight8(dev->mt76.antenna_mask);
417c8846e10SFelix Fietkau 	struct {
418c8846e10SFelix Fietkau 		u8 control_chan;
419c8846e10SFelix Fietkau 		u8 center_chan;
420c8846e10SFelix Fietkau 		u8 bw;
421c8846e10SFelix Fietkau 		u8 tx_streams;
422c8846e10SFelix Fietkau 		u8 rx_streams;
423c8846e10SFelix Fietkau 		u8 _res0[7];
424c8846e10SFelix Fietkau 		u8 txpower[21];
425c8846e10SFelix Fietkau 		u8 _res1[3];
426c8846e10SFelix Fietkau 	} req = {
427c8846e10SFelix Fietkau 		.control_chan = chandef->chan->hw_value,
428c8846e10SFelix Fietkau 		.center_chan = chandef->chan->hw_value,
429c8846e10SFelix Fietkau 		.bw = MT_BW_20,
430c8846e10SFelix Fietkau 		.tx_streams = n_chains,
431c8846e10SFelix Fietkau 		.rx_streams = n_chains,
432c8846e10SFelix Fietkau 	};
433c8846e10SFelix Fietkau 	s8 tx_power;
43411ca82d7SLorenzo Bianconi 	int i, ret;
435c8846e10SFelix Fietkau 
436c8846e10SFelix Fietkau 	if (dev->mt76.chandef.width == NL80211_CHAN_WIDTH_40) {
437c8846e10SFelix Fietkau 		req.bw = MT_BW_40;
438c8846e10SFelix Fietkau 		if (chandef->center_freq1 > chandef->chan->center_freq)
439c8846e10SFelix Fietkau 			req.center_chan += 2;
440c8846e10SFelix Fietkau 		else
441c8846e10SFelix Fietkau 			req.center_chan -= 2;
442c8846e10SFelix Fietkau 	}
443c8846e10SFelix Fietkau 
444c8846e10SFelix Fietkau 	tx_power = hw->conf.power_level * 2;
445c8846e10SFelix Fietkau 	if (dev->mt76.antenna_mask == 3)
446c8846e10SFelix Fietkau 		tx_power -= 6;
447c8846e10SFelix Fietkau 	tx_power = min(tx_power, dev->tx_power_limit);
448c8846e10SFelix Fietkau 
449c8846e10SFelix Fietkau 	dev->mt76.txpower_cur = tx_power;
450c8846e10SFelix Fietkau 
451c8846e10SFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(req.txpower); i++)
452c8846e10SFelix Fietkau 		req.txpower[i] = tx_power;
453c8846e10SFelix Fietkau 
45411ca82d7SLorenzo Bianconi 	ret = mt7603_mcu_msg_send(dev, MCU_EXT_CMD_CHANNEL_SWITCH,
45511ca82d7SLorenzo Bianconi 				  &req, sizeof(req), true);
456c8846e10SFelix Fietkau 	if (ret)
457c8846e10SFelix Fietkau 		return ret;
458c8846e10SFelix Fietkau 
459c8846e10SFelix Fietkau 	return mt7603_mcu_set_tx_power(dev);
460c8846e10SFelix Fietkau }
461