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 {
20*96a607b6SFelix Fietkau 	struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76);
21*96a607b6SFelix Fietkau 	struct mt7603_mcu_rxd *rxd;
22f320d812SFelix Fietkau 
23*96a607b6SFelix Fietkau 	if (!skb) {
24*96a607b6SFelix Fietkau 		dev_err(mdev->dev,
25*96a607b6SFelix Fietkau 			"MCU message %d (seq %d) timed out\n",
26*96a607b6SFelix Fietkau 			cmd, seq);
27*96a607b6SFelix Fietkau 		dev->mcu_hang = MT7603_WATCHDOG_TIMEOUT;
28*96a607b6SFelix Fietkau 		return -ETIMEDOUT;
29*96a607b6SFelix Fietkau 	}
30*96a607b6SFelix Fietkau 
31*96a607b6SFelix 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
39114fe5e3SLorenzo Bianconi __mt7603_mcu_msg_send(struct mt7603_dev *dev, struct sk_buff *skb,
40114fe5e3SLorenzo Bianconi 		      int cmd, int *wait_seq)
41c8846e10SFelix Fietkau {
42c8846e10SFelix Fietkau 	int hdrlen = dev->mcu_running ? sizeof(struct mt7603_mcu_txd) : 12;
43c8846e10SFelix Fietkau 	struct mt76_dev *mdev = &dev->mt76;
44c8846e10SFelix Fietkau 	struct mt7603_mcu_txd *txd;
45c8846e10SFelix Fietkau 	u8 seq;
46c8846e10SFelix Fietkau 
4709872957SLorenzo Bianconi 	seq = ++mdev->mcu.msg_seq & 0xf;
48c8846e10SFelix Fietkau 	if (!seq)
4909872957SLorenzo Bianconi 		seq = ++mdev->mcu.msg_seq & 0xf;
50c8846e10SFelix Fietkau 
51c8846e10SFelix Fietkau 	txd = (struct mt7603_mcu_txd *)skb_push(skb, hdrlen);
52c8846e10SFelix Fietkau 
53c8846e10SFelix Fietkau 	txd->len = cpu_to_le16(skb->len);
54c8846e10SFelix Fietkau 	if (cmd == -MCU_CMD_FW_SCATTER)
55c8846e10SFelix Fietkau 		txd->pq_id = cpu_to_le16(MCU_PORT_QUEUE_FW);
56c8846e10SFelix Fietkau 	else
57c8846e10SFelix Fietkau 		txd->pq_id = cpu_to_le16(MCU_PORT_QUEUE);
58c8846e10SFelix Fietkau 	txd->pkt_type = MCU_PKT_ID;
59c8846e10SFelix Fietkau 	txd->seq = seq;
60c8846e10SFelix Fietkau 
61c8846e10SFelix Fietkau 	if (cmd < 0) {
62c8846e10SFelix Fietkau 		txd->cid = -cmd;
63114fe5e3SLorenzo Bianconi 		txd->set_query = MCU_Q_NA;
64c8846e10SFelix Fietkau 	} else {
65c8846e10SFelix Fietkau 		txd->cid = MCU_CMD_EXT_CID;
66c8846e10SFelix Fietkau 		txd->ext_cid = cmd;
67114fe5e3SLorenzo Bianconi 		txd->set_query = MCU_Q_SET;
68c8846e10SFelix Fietkau 		txd->ext_cid_ack = 1;
69c8846e10SFelix Fietkau 	}
70c8846e10SFelix Fietkau 
71c8846e10SFelix Fietkau 	if (wait_seq)
72c8846e10SFelix Fietkau 		*wait_seq = seq;
73c8846e10SFelix Fietkau 
74c8846e10SFelix Fietkau 	return mt76_tx_queue_skb_raw(dev, MT_TXQ_MCU, skb, 0);
75c8846e10SFelix Fietkau }
76c8846e10SFelix Fietkau 
77c8846e10SFelix Fietkau static int
78cc173875SLorenzo Bianconi mt7603_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data,
7911ca82d7SLorenzo Bianconi 		    int len, bool wait_resp)
80c8846e10SFelix Fietkau {
81cc173875SLorenzo Bianconi 	struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76);
82c8846e10SFelix Fietkau 	unsigned long expires = jiffies + 3 * HZ;
8311ca82d7SLorenzo Bianconi 	struct sk_buff *skb;
84c8846e10SFelix Fietkau 	int ret, seq;
85c8846e10SFelix Fietkau 
86bb31a80eSLorenzo Bianconi 	skb = mt76_mcu_msg_alloc(mdev, data, len);
8711ca82d7SLorenzo Bianconi 	if (!skb)
8811ca82d7SLorenzo Bianconi 		return -ENOMEM;
8911ca82d7SLorenzo Bianconi 
9009872957SLorenzo Bianconi 	mutex_lock(&mdev->mcu.mutex);
91c8846e10SFelix Fietkau 
92114fe5e3SLorenzo Bianconi 	ret = __mt7603_mcu_msg_send(dev, skb, cmd, &seq);
93c8846e10SFelix Fietkau 	if (ret)
94c8846e10SFelix Fietkau 		goto out;
95c8846e10SFelix Fietkau 
9611ca82d7SLorenzo Bianconi 	while (wait_resp) {
97c8846e10SFelix Fietkau 		skb = mt76_mcu_get_response(&dev->mt76, expires);
98f320d812SFelix Fietkau 		ret = mt7603_mcu_parse_response(mdev, cmd, skb, seq);
99c8846e10SFelix Fietkau 		dev_kfree_skb(skb);
100f320d812SFelix Fietkau 		if (ret != -EAGAIN)
101c8846e10SFelix Fietkau 			break;
102c8846e10SFelix Fietkau 	}
103c8846e10SFelix Fietkau 
104c8846e10SFelix Fietkau out:
10509872957SLorenzo Bianconi 	mutex_unlock(&mdev->mcu.mutex);
106c8846e10SFelix Fietkau 
107c8846e10SFelix Fietkau 	return ret;
108c8846e10SFelix Fietkau }
109c8846e10SFelix Fietkau 
110c8846e10SFelix Fietkau static int
111c8846e10SFelix Fietkau mt7603_mcu_init_download(struct mt7603_dev *dev, u32 addr, u32 len)
112c8846e10SFelix Fietkau {
113c8846e10SFelix Fietkau 	struct {
114c8846e10SFelix Fietkau 		__le32 addr;
115c8846e10SFelix Fietkau 		__le32 len;
116c8846e10SFelix Fietkau 		__le32 mode;
117c8846e10SFelix Fietkau 	} req = {
118c8846e10SFelix Fietkau 		.addr = cpu_to_le32(addr),
119c8846e10SFelix Fietkau 		.len = cpu_to_le32(len),
120c8846e10SFelix Fietkau 		.mode = cpu_to_le32(BIT(31)),
121c8846e10SFelix Fietkau 	};
122c8846e10SFelix Fietkau 
123cb5cdd4cSFelix Fietkau 	return mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_TARGET_ADDRESS_LEN_REQ,
12411ca82d7SLorenzo Bianconi 				 &req, sizeof(req), true);
125c8846e10SFelix Fietkau }
126c8846e10SFelix Fietkau 
127c8846e10SFelix Fietkau static int
128c8846e10SFelix Fietkau mt7603_mcu_send_firmware(struct mt7603_dev *dev, const void *data, int len)
129c8846e10SFelix Fietkau {
130d422bb26SLorenzo Bianconi 	int cur_len, ret = 0;
131c8846e10SFelix Fietkau 
132c8846e10SFelix Fietkau 	while (len > 0) {
133d422bb26SLorenzo Bianconi 		cur_len = min_t(int, 4096 - sizeof(struct mt7603_mcu_txd),
134c8846e10SFelix Fietkau 				len);
135c8846e10SFelix Fietkau 
136cb5cdd4cSFelix Fietkau 		ret = mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_FW_SCATTER, data,
137cb5cdd4cSFelix Fietkau 					cur_len, false);
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 
159cb5cdd4cSFelix Fietkau 	return mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_FW_START_REQ, &req,
160cb5cdd4cSFelix Fietkau 				 sizeof(req), true);
161c8846e10SFelix Fietkau }
162c8846e10SFelix Fietkau 
163c8846e10SFelix Fietkau static int
164a4834814SLorenzo Bianconi mt7603_mcu_restart(struct mt76_dev *dev)
165c8846e10SFelix Fietkau {
166cb5cdd4cSFelix Fietkau 	return mt76_mcu_send_msg(dev, -MCU_CMD_RESTART_DL_REQ, NULL, 0, true);
167c8846e10SFelix Fietkau }
168c8846e10SFelix Fietkau 
169cc173875SLorenzo Bianconi static int mt7603_load_firmware(struct mt7603_dev *dev)
170c8846e10SFelix Fietkau {
171c8846e10SFelix Fietkau 	const struct firmware *fw;
172c8846e10SFelix Fietkau 	const struct mt7603_fw_trailer *hdr;
173c8846e10SFelix Fietkau 	const char *firmware;
174c8846e10SFelix Fietkau 	int dl_len;
175c8846e10SFelix Fietkau 	u32 addr, val;
176c8846e10SFelix Fietkau 	int ret;
177c8846e10SFelix Fietkau 
178c8846e10SFelix Fietkau 	if (is_mt7628(dev)) {
179c8846e10SFelix Fietkau 		if (mt76xx_rev(dev) == MT7628_REV_E1)
180c8846e10SFelix Fietkau 			firmware = MT7628_FIRMWARE_E1;
181c8846e10SFelix Fietkau 		else
182c8846e10SFelix Fietkau 			firmware = MT7628_FIRMWARE_E2;
183c8846e10SFelix Fietkau 	} else {
184c8846e10SFelix Fietkau 		if (mt76xx_rev(dev) < MT7603_REV_E2)
185c8846e10SFelix Fietkau 			firmware = MT7603_FIRMWARE_E1;
186c8846e10SFelix Fietkau 		else
187c8846e10SFelix Fietkau 			firmware = MT7603_FIRMWARE_E2;
188c8846e10SFelix Fietkau 	}
189c8846e10SFelix Fietkau 
190c8846e10SFelix Fietkau 	ret = request_firmware(&fw, firmware, dev->mt76.dev);
191c8846e10SFelix Fietkau 	if (ret)
192c8846e10SFelix Fietkau 		return ret;
193c8846e10SFelix Fietkau 
194c8846e10SFelix Fietkau 	if (!fw || !fw->data || fw->size < sizeof(*hdr)) {
195c8846e10SFelix Fietkau 		dev_err(dev->mt76.dev, "Invalid firmware\n");
196c8846e10SFelix Fietkau 		ret = -EINVAL;
197c8846e10SFelix Fietkau 		goto out;
198c8846e10SFelix Fietkau 	}
199c8846e10SFelix Fietkau 
200c8846e10SFelix Fietkau 	hdr = (const struct mt7603_fw_trailer *)(fw->data + fw->size -
201c8846e10SFelix Fietkau 						 sizeof(*hdr));
202c8846e10SFelix Fietkau 
203c8846e10SFelix Fietkau 	dev_info(dev->mt76.dev, "Firmware Version: %.10s\n", hdr->fw_ver);
204c8846e10SFelix Fietkau 	dev_info(dev->mt76.dev, "Build Time: %.15s\n", hdr->build_date);
205c8846e10SFelix Fietkau 
206c8846e10SFelix Fietkau 	addr = mt7603_reg_map(dev, 0x50012498);
207c8846e10SFelix Fietkau 	mt76_wr(dev, addr, 0x5);
208c8846e10SFelix Fietkau 	mt76_wr(dev, addr, 0x5);
209c8846e10SFelix Fietkau 	udelay(1);
210c8846e10SFelix Fietkau 
211c8846e10SFelix Fietkau 	/* switch to bypass mode */
212c8846e10SFelix Fietkau 	mt76_rmw(dev, MT_SCH_4, MT_SCH_4_FORCE_QID,
213c8846e10SFelix Fietkau 		 MT_SCH_4_BYPASS | FIELD_PREP(MT_SCH_4_FORCE_QID, 5));
214c8846e10SFelix Fietkau 
215c8846e10SFelix Fietkau 	val = mt76_rr(dev, MT_TOP_MISC2);
216c8846e10SFelix Fietkau 	if (val & BIT(1)) {
217c8846e10SFelix Fietkau 		dev_info(dev->mt76.dev, "Firmware already running...\n");
218c8846e10SFelix Fietkau 		goto running;
219c8846e10SFelix Fietkau 	}
220c8846e10SFelix Fietkau 
221c8846e10SFelix Fietkau 	if (!mt76_poll_msec(dev, MT_TOP_MISC2, BIT(0) | BIT(1), BIT(0), 500)) {
222c8846e10SFelix Fietkau 		dev_err(dev->mt76.dev, "Timeout waiting for ROM code to become ready\n");
223c8846e10SFelix Fietkau 		ret = -EIO;
224c8846e10SFelix Fietkau 		goto out;
225c8846e10SFelix Fietkau 	}
226c8846e10SFelix Fietkau 
227c8846e10SFelix Fietkau 	dl_len = le32_to_cpu(hdr->dl_len) + 4;
228c8846e10SFelix Fietkau 	ret = mt7603_mcu_init_download(dev, MCU_FIRMWARE_ADDRESS, dl_len);
229c8846e10SFelix Fietkau 	if (ret) {
230c8846e10SFelix Fietkau 		dev_err(dev->mt76.dev, "Download request failed\n");
231c8846e10SFelix Fietkau 		goto out;
232c8846e10SFelix Fietkau 	}
233c8846e10SFelix Fietkau 
234c8846e10SFelix Fietkau 	ret = mt7603_mcu_send_firmware(dev, fw->data, dl_len);
235c8846e10SFelix Fietkau 	if (ret) {
236c8846e10SFelix Fietkau 		dev_err(dev->mt76.dev, "Failed to send firmware to device\n");
237c8846e10SFelix Fietkau 		goto out;
238c8846e10SFelix Fietkau 	}
239c8846e10SFelix Fietkau 
240c8846e10SFelix Fietkau 	ret = mt7603_mcu_start_firmware(dev, MCU_FIRMWARE_ADDRESS);
241c8846e10SFelix Fietkau 	if (ret) {
242c8846e10SFelix Fietkau 		dev_err(dev->mt76.dev, "Failed to start firmware\n");
243c8846e10SFelix Fietkau 		goto out;
244c8846e10SFelix Fietkau 	}
245c8846e10SFelix Fietkau 
246c8846e10SFelix Fietkau 	if (!mt76_poll_msec(dev, MT_TOP_MISC2, BIT(1), BIT(1), 500)) {
247c8846e10SFelix Fietkau 		dev_err(dev->mt76.dev, "Timeout waiting for firmware to initialize\n");
248c8846e10SFelix Fietkau 		ret = -EIO;
249c8846e10SFelix Fietkau 		goto out;
250c8846e10SFelix Fietkau 	}
251c8846e10SFelix Fietkau 
252c8846e10SFelix Fietkau running:
253c8846e10SFelix Fietkau 	mt76_clear(dev, MT_SCH_4, MT_SCH_4_FORCE_QID | MT_SCH_4_BYPASS);
254c8846e10SFelix Fietkau 
255c8846e10SFelix Fietkau 	mt76_set(dev, MT_SCH_4, BIT(8));
256c8846e10SFelix Fietkau 	mt76_clear(dev, MT_SCH_4, BIT(8));
257c8846e10SFelix Fietkau 
258c8846e10SFelix Fietkau 	dev->mcu_running = true;
2594d0fe26fSLorenzo Bianconi 	snprintf(dev->mt76.hw->wiphy->fw_version,
2604d0fe26fSLorenzo Bianconi 		 sizeof(dev->mt76.hw->wiphy->fw_version),
2614d0fe26fSLorenzo Bianconi 		 "%.10s-%.15s", hdr->fw_ver, hdr->build_date);
262c8846e10SFelix Fietkau 	dev_info(dev->mt76.dev, "firmware init done\n");
263c8846e10SFelix Fietkau 
264c8846e10SFelix Fietkau out:
265c8846e10SFelix Fietkau 	release_firmware(fw);
266c8846e10SFelix Fietkau 
267c8846e10SFelix Fietkau 	return ret;
268c8846e10SFelix Fietkau }
269c8846e10SFelix Fietkau 
270cc173875SLorenzo Bianconi int mt7603_mcu_init(struct mt7603_dev *dev)
271cc173875SLorenzo Bianconi {
272cc173875SLorenzo Bianconi 	static const struct mt76_mcu_ops mt7603_mcu_ops = {
273bb31a80eSLorenzo Bianconi 		.headroom = sizeof(struct mt7603_mcu_txd),
274cc173875SLorenzo Bianconi 		.mcu_send_msg = mt7603_mcu_msg_send,
275f320d812SFelix Fietkau 		.mcu_parse_response = mt7603_mcu_parse_response,
276a4834814SLorenzo Bianconi 		.mcu_restart = mt7603_mcu_restart,
277cc173875SLorenzo Bianconi 	};
278cc173875SLorenzo Bianconi 
279cc173875SLorenzo Bianconi 	dev->mt76.mcu_ops = &mt7603_mcu_ops;
280cc173875SLorenzo Bianconi 	return mt7603_load_firmware(dev);
281cc173875SLorenzo Bianconi }
282cc173875SLorenzo Bianconi 
283c8846e10SFelix Fietkau void mt7603_mcu_exit(struct mt7603_dev *dev)
284c8846e10SFelix Fietkau {
285a4834814SLorenzo Bianconi 	__mt76_mcu_restart(&dev->mt76);
28609872957SLorenzo Bianconi 	skb_queue_purge(&dev->mt76.mcu.res_q);
287c8846e10SFelix Fietkau }
288c8846e10SFelix Fietkau 
289c8846e10SFelix Fietkau int mt7603_mcu_set_eeprom(struct mt7603_dev *dev)
290c8846e10SFelix Fietkau {
291c8846e10SFelix Fietkau 	static const u16 req_fields[] = {
292c8846e10SFelix Fietkau #define WORD(_start)			\
293c8846e10SFelix Fietkau 		_start,			\
294c8846e10SFelix Fietkau 		_start + 1
295c8846e10SFelix Fietkau #define GROUP_2G(_start)		\
296c8846e10SFelix Fietkau 		WORD(_start),		\
297c8846e10SFelix Fietkau 		WORD(_start + 2),	\
298c8846e10SFelix Fietkau 		WORD(_start + 4)
299c8846e10SFelix Fietkau 
300c8846e10SFelix Fietkau 		MT_EE_NIC_CONF_0 + 1,
301c8846e10SFelix Fietkau 		WORD(MT_EE_NIC_CONF_1),
302c8846e10SFelix Fietkau 		MT_EE_WIFI_RF_SETTING,
303c8846e10SFelix Fietkau 		MT_EE_TX_POWER_DELTA_BW40,
304c8846e10SFelix Fietkau 		MT_EE_TX_POWER_DELTA_BW80 + 1,
305c8846e10SFelix Fietkau 		MT_EE_TX_POWER_EXT_PA_5G,
306c8846e10SFelix Fietkau 		MT_EE_TEMP_SENSOR_CAL,
307c8846e10SFelix Fietkau 		GROUP_2G(MT_EE_TX_POWER_0_START_2G),
308c8846e10SFelix Fietkau 		GROUP_2G(MT_EE_TX_POWER_1_START_2G),
309c8846e10SFelix Fietkau 		WORD(MT_EE_TX_POWER_CCK),
310c8846e10SFelix Fietkau 		WORD(MT_EE_TX_POWER_OFDM_2G_6M),
311c8846e10SFelix Fietkau 		WORD(MT_EE_TX_POWER_OFDM_2G_24M),
312c8846e10SFelix Fietkau 		WORD(MT_EE_TX_POWER_OFDM_2G_54M),
313c8846e10SFelix Fietkau 		WORD(MT_EE_TX_POWER_HT_BPSK_QPSK),
314c8846e10SFelix Fietkau 		WORD(MT_EE_TX_POWER_HT_16_64_QAM),
315c8846e10SFelix Fietkau 		WORD(MT_EE_TX_POWER_HT_64_QAM),
316c8846e10SFelix Fietkau 		MT_EE_ELAN_RX_MODE_GAIN,
317c8846e10SFelix Fietkau 		MT_EE_ELAN_RX_MODE_NF,
318c8846e10SFelix Fietkau 		MT_EE_ELAN_RX_MODE_P1DB,
319c8846e10SFelix Fietkau 		MT_EE_ELAN_BYPASS_MODE_GAIN,
320c8846e10SFelix Fietkau 		MT_EE_ELAN_BYPASS_MODE_NF,
321c8846e10SFelix Fietkau 		MT_EE_ELAN_BYPASS_MODE_P1DB,
322c8846e10SFelix Fietkau 		WORD(MT_EE_STEP_NUM_NEG_6_7),
323c8846e10SFelix Fietkau 		WORD(MT_EE_STEP_NUM_NEG_4_5),
324c8846e10SFelix Fietkau 		WORD(MT_EE_STEP_NUM_NEG_2_3),
325c8846e10SFelix Fietkau 		WORD(MT_EE_STEP_NUM_NEG_0_1),
326c8846e10SFelix Fietkau 		WORD(MT_EE_REF_STEP_24G),
327c8846e10SFelix Fietkau 		WORD(MT_EE_STEP_NUM_PLUS_1_2),
328c8846e10SFelix Fietkau 		WORD(MT_EE_STEP_NUM_PLUS_3_4),
329c8846e10SFelix Fietkau 		WORD(MT_EE_STEP_NUM_PLUS_5_6),
330c8846e10SFelix Fietkau 		MT_EE_STEP_NUM_PLUS_7,
331c8846e10SFelix Fietkau 		MT_EE_XTAL_FREQ_OFFSET,
332c8846e10SFelix Fietkau 		MT_EE_XTAL_TRIM_2_COMP,
333c8846e10SFelix Fietkau 		MT_EE_XTAL_TRIM_3_COMP,
334c8846e10SFelix Fietkau 		MT_EE_XTAL_WF_RFCAL,
335c8846e10SFelix Fietkau 
336c8846e10SFelix Fietkau 		/* unknown fields below */
337c8846e10SFelix Fietkau 		WORD(0x24),
338c8846e10SFelix Fietkau 		0x34,
339c8846e10SFelix Fietkau 		0x39,
340c8846e10SFelix Fietkau 		0x3b,
341c8846e10SFelix Fietkau 		WORD(0x42),
342c8846e10SFelix Fietkau 		WORD(0x9e),
343c8846e10SFelix Fietkau 		0xf2,
344c8846e10SFelix Fietkau 		WORD(0xf8),
345c8846e10SFelix Fietkau 		0xfa,
346c8846e10SFelix Fietkau 		0x12e,
347c8846e10SFelix Fietkau 		WORD(0x130), WORD(0x132), WORD(0x134), WORD(0x136),
348c8846e10SFelix Fietkau 		WORD(0x138), WORD(0x13a), WORD(0x13c), WORD(0x13e),
349c8846e10SFelix Fietkau 
350c8846e10SFelix Fietkau #undef GROUP_2G
351c8846e10SFelix Fietkau #undef WORD
352c8846e10SFelix Fietkau 
353c8846e10SFelix Fietkau 	};
354c8846e10SFelix Fietkau 	struct req_data {
355676fabd1SLorenzo Bianconi 		__le16 addr;
356c8846e10SFelix Fietkau 		u8 val;
357c8846e10SFelix Fietkau 		u8 pad;
358c8846e10SFelix Fietkau 	} __packed;
359c8846e10SFelix Fietkau 	struct {
360c8846e10SFelix Fietkau 		u8 buffer_mode;
361c8846e10SFelix Fietkau 		u8 len;
362c8846e10SFelix Fietkau 		u8 pad[2];
3634d2a6f7bSLorenzo Bianconi 	} req_hdr = {
364c8846e10SFelix Fietkau 		.buffer_mode = 1,
365c8846e10SFelix Fietkau 		.len = ARRAY_SIZE(req_fields) - 1,
366c8846e10SFelix Fietkau 	};
3674d2a6f7bSLorenzo Bianconi 	const int size = 0xff * sizeof(struct req_data);
3684d2a6f7bSLorenzo Bianconi 	u8 *req, *eep = (u8 *)dev->mt76.eeprom.data;
3694d2a6f7bSLorenzo Bianconi 	int i, ret, len = sizeof(req_hdr) + size;
3704d2a6f7bSLorenzo Bianconi 	struct req_data *data;
371c8846e10SFelix Fietkau 
3724d2a6f7bSLorenzo Bianconi 	BUILD_BUG_ON(ARRAY_SIZE(req_fields) * sizeof(*data) > size);
373c8846e10SFelix Fietkau 
3744d2a6f7bSLorenzo Bianconi 	req = kmalloc(len, GFP_KERNEL);
3754d2a6f7bSLorenzo Bianconi 	if (!req)
3764d2a6f7bSLorenzo Bianconi 		return -ENOMEM;
3774d2a6f7bSLorenzo Bianconi 
3784d2a6f7bSLorenzo Bianconi 	memcpy(req, &req_hdr, sizeof(req_hdr));
3794d2a6f7bSLorenzo Bianconi 	data = (struct req_data *)(req + sizeof(req_hdr));
3804d2a6f7bSLorenzo Bianconi 	memset(data, 0, size);
381c8846e10SFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(req_fields); i++) {
3824d2a6f7bSLorenzo Bianconi 		data[i].addr = cpu_to_le16(req_fields[i]);
3834d2a6f7bSLorenzo Bianconi 		data[i].val = eep[req_fields[i]];
384c8846e10SFelix Fietkau 	}
385c8846e10SFelix Fietkau 
386cb5cdd4cSFelix Fietkau 	ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EFUSE_BUFFER_MODE,
3874d2a6f7bSLorenzo Bianconi 				req, len, true);
3884d2a6f7bSLorenzo Bianconi 	kfree(req);
3894d2a6f7bSLorenzo Bianconi 
3904d2a6f7bSLorenzo Bianconi 	return ret;
391c8846e10SFelix Fietkau }
392c8846e10SFelix Fietkau 
393c8846e10SFelix Fietkau static int mt7603_mcu_set_tx_power(struct mt7603_dev *dev)
394c8846e10SFelix Fietkau {
395c8846e10SFelix Fietkau 	struct {
396c8846e10SFelix Fietkau 		u8 center_channel;
397c8846e10SFelix Fietkau 		u8 tssi;
398c8846e10SFelix Fietkau 		u8 temp_comp;
399c8846e10SFelix Fietkau 		u8 target_power[2];
400c8846e10SFelix Fietkau 		u8 rate_power_delta[14];
401c8846e10SFelix Fietkau 		u8 bw_power_delta;
402c8846e10SFelix Fietkau 		u8 ch_power_delta[6];
403c8846e10SFelix Fietkau 		u8 temp_comp_power[17];
404c8846e10SFelix Fietkau 		u8 reserved;
405c8846e10SFelix Fietkau 	} req = {
40696747a51SFelix Fietkau 		.center_channel = dev->mphy.chandef.chan->hw_value,
407c8846e10SFelix Fietkau #define EEP_VAL(n) ((u8 *)dev->mt76.eeprom.data)[n]
408c8846e10SFelix Fietkau 		.tssi = EEP_VAL(MT_EE_NIC_CONF_1 + 1),
409c8846e10SFelix Fietkau 		.temp_comp = EEP_VAL(MT_EE_NIC_CONF_1),
410c8846e10SFelix Fietkau 		.target_power = {
411c8846e10SFelix Fietkau 			EEP_VAL(MT_EE_TX_POWER_0_START_2G + 2),
412c8846e10SFelix Fietkau 			EEP_VAL(MT_EE_TX_POWER_1_START_2G + 2)
413c8846e10SFelix Fietkau 		},
414c8846e10SFelix Fietkau 		.bw_power_delta = EEP_VAL(MT_EE_TX_POWER_DELTA_BW40),
415c8846e10SFelix Fietkau 		.ch_power_delta = {
416c8846e10SFelix Fietkau 			EEP_VAL(MT_EE_TX_POWER_0_START_2G + 3),
417c8846e10SFelix Fietkau 			EEP_VAL(MT_EE_TX_POWER_0_START_2G + 4),
418c8846e10SFelix Fietkau 			EEP_VAL(MT_EE_TX_POWER_0_START_2G + 5),
419c8846e10SFelix Fietkau 			EEP_VAL(MT_EE_TX_POWER_1_START_2G + 3),
420c8846e10SFelix Fietkau 			EEP_VAL(MT_EE_TX_POWER_1_START_2G + 4),
421c8846e10SFelix Fietkau 			EEP_VAL(MT_EE_TX_POWER_1_START_2G + 5)
422c8846e10SFelix Fietkau 		},
423c8846e10SFelix Fietkau #undef EEP_VAL
424c8846e10SFelix Fietkau 	};
425c8846e10SFelix Fietkau 	u8 *eep = (u8 *)dev->mt76.eeprom.data;
426c8846e10SFelix Fietkau 
427c8846e10SFelix Fietkau 	memcpy(req.rate_power_delta, eep + MT_EE_TX_POWER_CCK,
428c8846e10SFelix Fietkau 	       sizeof(req.rate_power_delta));
429c8846e10SFelix Fietkau 
430c8846e10SFelix Fietkau 	memcpy(req.temp_comp_power, eep + MT_EE_STEP_NUM_NEG_6_7,
431c8846e10SFelix Fietkau 	       sizeof(req.temp_comp_power));
432c8846e10SFelix Fietkau 
433cb5cdd4cSFelix Fietkau 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_TX_POWER_CTRL,
43411ca82d7SLorenzo Bianconi 				 &req, sizeof(req), true);
435c8846e10SFelix Fietkau }
436c8846e10SFelix Fietkau 
437c8846e10SFelix Fietkau int mt7603_mcu_set_channel(struct mt7603_dev *dev)
438c8846e10SFelix Fietkau {
43996747a51SFelix Fietkau 	struct cfg80211_chan_def *chandef = &dev->mphy.chandef;
440c8846e10SFelix Fietkau 	struct ieee80211_hw *hw = mt76_hw(dev);
441beaaeb6bSFelix Fietkau 	int n_chains = hweight8(dev->mphy.antenna_mask);
442c8846e10SFelix Fietkau 	struct {
443c8846e10SFelix Fietkau 		u8 control_chan;
444c8846e10SFelix Fietkau 		u8 center_chan;
445c8846e10SFelix Fietkau 		u8 bw;
446c8846e10SFelix Fietkau 		u8 tx_streams;
447c8846e10SFelix Fietkau 		u8 rx_streams;
448c8846e10SFelix Fietkau 		u8 _res0[7];
449c8846e10SFelix Fietkau 		u8 txpower[21];
450c8846e10SFelix Fietkau 		u8 _res1[3];
451c8846e10SFelix Fietkau 	} req = {
452c8846e10SFelix Fietkau 		.control_chan = chandef->chan->hw_value,
453c8846e10SFelix Fietkau 		.center_chan = chandef->chan->hw_value,
454c8846e10SFelix Fietkau 		.bw = MT_BW_20,
455c8846e10SFelix Fietkau 		.tx_streams = n_chains,
456c8846e10SFelix Fietkau 		.rx_streams = n_chains,
457c8846e10SFelix Fietkau 	};
458c8846e10SFelix Fietkau 	s8 tx_power;
45911ca82d7SLorenzo Bianconi 	int i, ret;
460c8846e10SFelix Fietkau 
46196747a51SFelix Fietkau 	if (dev->mphy.chandef.width == NL80211_CHAN_WIDTH_40) {
462c8846e10SFelix Fietkau 		req.bw = MT_BW_40;
463c8846e10SFelix Fietkau 		if (chandef->center_freq1 > chandef->chan->center_freq)
464c8846e10SFelix Fietkau 			req.center_chan += 2;
465c8846e10SFelix Fietkau 		else
466c8846e10SFelix Fietkau 			req.center_chan -= 2;
467c8846e10SFelix Fietkau 	}
468c8846e10SFelix Fietkau 
469c8846e10SFelix Fietkau 	tx_power = hw->conf.power_level * 2;
470beaaeb6bSFelix Fietkau 	if (dev->mphy.antenna_mask == 3)
471c8846e10SFelix Fietkau 		tx_power -= 6;
472c8846e10SFelix Fietkau 	tx_power = min(tx_power, dev->tx_power_limit);
473c8846e10SFelix Fietkau 
474beaaeb6bSFelix Fietkau 	dev->mphy.txpower_cur = tx_power;
475c8846e10SFelix Fietkau 
476c8846e10SFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(req.txpower); i++)
477c8846e10SFelix Fietkau 		req.txpower[i] = tx_power;
478c8846e10SFelix Fietkau 
479cb5cdd4cSFelix Fietkau 	ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_CHANNEL_SWITCH, &req,
480cb5cdd4cSFelix Fietkau 				sizeof(req), true);
481c8846e10SFelix Fietkau 	if (ret)
482c8846e10SFelix Fietkau 		return ret;
483c8846e10SFelix Fietkau 
484c8846e10SFelix Fietkau 	return mt7603_mcu_set_tx_power(dev);
485c8846e10SFelix Fietkau }
486