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