1 /*
2  * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 #include <linux/module.h>
18 #include <linux/firmware.h>
19 
20 #include "mt76x02.h"
21 #include "mt76x02_mcu.h"
22 #include "mt76x02_usb.h"
23 
24 #define MT_CMD_HDR_LEN			4
25 
26 #define MT_FCE_DMA_ADDR			0x0230
27 #define MT_FCE_DMA_LEN			0x0234
28 
29 #define MT_TX_CPU_FROM_FCE_CPU_DESC_IDX	0x09a8
30 
31 static void
32 mt76x02u_multiple_mcu_reads(struct mt76_dev *dev, u8 *data, int len)
33 {
34 	struct mt76_usb *usb = &dev->usb;
35 	u32 reg, val;
36 	int i;
37 
38 	if (usb->mcu.burst) {
39 		WARN_ON_ONCE(len / 4 != usb->mcu.rp_len);
40 
41 		reg = usb->mcu.rp[0].reg - usb->mcu.base;
42 		for (i = 0; i < usb->mcu.rp_len; i++) {
43 			val = get_unaligned_le32(data + 4 * i);
44 			usb->mcu.rp[i].reg = reg++;
45 			usb->mcu.rp[i].value = val;
46 		}
47 	} else {
48 		WARN_ON_ONCE(len / 8 != usb->mcu.rp_len);
49 
50 		for (i = 0; i < usb->mcu.rp_len; i++) {
51 			reg = get_unaligned_le32(data + 8 * i) -
52 			      usb->mcu.base;
53 			val = get_unaligned_le32(data + 8 * i + 4);
54 
55 			WARN_ON_ONCE(usb->mcu.rp[i].reg != reg);
56 			usb->mcu.rp[i].value = val;
57 		}
58 	}
59 }
60 
61 static int mt76x02u_mcu_wait_resp(struct mt76_dev *dev, u8 seq)
62 {
63 	struct mt76_usb *usb = &dev->usb;
64 	u8 *data = usb->mcu.data;
65 	int i, len, ret;
66 	u32 rxfce;
67 
68 	for (i = 0; i < 5; i++) {
69 		ret = mt76u_bulk_msg(dev, data, MCU_RESP_URB_SIZE, &len, 300);
70 		if (ret == -ETIMEDOUT)
71 			continue;
72 		if (ret)
73 			goto out;
74 
75 		if (usb->mcu.rp)
76 			mt76x02u_multiple_mcu_reads(dev, data + 4, len - 8);
77 
78 		rxfce = get_unaligned_le32(data);
79 		if (seq == FIELD_GET(MT_RX_FCE_INFO_CMD_SEQ, rxfce) &&
80 		    FIELD_GET(MT_RX_FCE_INFO_EVT_TYPE, rxfce) == EVT_CMD_DONE)
81 			return 0;
82 
83 		dev_err(dev->dev, "error: MCU resp evt:%lx seq:%hhx-%lx\n",
84 			FIELD_GET(MT_RX_FCE_INFO_EVT_TYPE, rxfce),
85 			seq, FIELD_GET(MT_RX_FCE_INFO_CMD_SEQ, rxfce));
86 	}
87 out:
88 	dev_err(dev->dev, "error: %s failed with %d\n", __func__, ret);
89 	return ret;
90 }
91 
92 static int
93 __mt76x02u_mcu_send_msg(struct mt76_dev *dev, struct sk_buff *skb,
94 			int cmd, bool wait_resp)
95 {
96 	struct mt76_usb *usb = &dev->usb;
97 	int ret;
98 	u8 seq = 0;
99 	u32 info;
100 
101 	if (test_bit(MT76_REMOVED, &dev->state))
102 		return 0;
103 
104 	if (wait_resp) {
105 		seq = ++usb->mcu.msg_seq & 0xf;
106 		if (!seq)
107 			seq = ++usb->mcu.msg_seq & 0xf;
108 	}
109 
110 	info = FIELD_PREP(MT_MCU_MSG_CMD_SEQ, seq) |
111 	       FIELD_PREP(MT_MCU_MSG_CMD_TYPE, cmd) |
112 	       MT_MCU_MSG_TYPE_CMD;
113 	ret = mt76x02u_skb_dma_info(skb, CPU_TX_PORT, info);
114 	if (ret)
115 		return ret;
116 
117 	ret = mt76u_bulk_msg(dev, skb->data, skb->len, NULL, 500);
118 	if (ret)
119 		return ret;
120 
121 	if (wait_resp)
122 		ret = mt76x02u_mcu_wait_resp(dev, seq);
123 
124 	consume_skb(skb);
125 
126 	return ret;
127 }
128 
129 static int
130 mt76x02u_mcu_send_msg(struct mt76_dev *dev, int cmd, const void *data,
131 		      int len, bool wait_resp)
132 {
133 	struct mt76_usb *usb = &dev->usb;
134 	struct sk_buff *skb;
135 	int err;
136 
137 	skb = mt76_mcu_msg_alloc(data, MT_CMD_HDR_LEN, len, 8);
138 	if (!skb)
139 		return -ENOMEM;
140 
141 	mutex_lock(&usb->mcu.mutex);
142 	err = __mt76x02u_mcu_send_msg(dev, skb, cmd, wait_resp);
143 	mutex_unlock(&usb->mcu.mutex);
144 
145 	return err;
146 }
147 
148 static inline void skb_put_le32(struct sk_buff *skb, u32 val)
149 {
150 	put_unaligned_le32(val, skb_put(skb, 4));
151 }
152 
153 static int
154 mt76x02u_mcu_wr_rp(struct mt76_dev *dev, u32 base,
155 		   const struct mt76_reg_pair *data, int n)
156 {
157 	const int CMD_RANDOM_WRITE = 12;
158 	const int max_vals_per_cmd = MT_INBAND_PACKET_MAX_LEN / 8;
159 	struct mt76_usb *usb = &dev->usb;
160 	struct sk_buff *skb;
161 	int cnt, i, ret;
162 
163 	if (!n)
164 		return 0;
165 
166 	cnt = min(max_vals_per_cmd, n);
167 
168 	skb = alloc_skb(cnt * 8 + MT_DMA_HDR_LEN + 4, GFP_KERNEL);
169 	if (!skb)
170 		return -ENOMEM;
171 	skb_reserve(skb, MT_DMA_HDR_LEN);
172 
173 	for (i = 0; i < cnt; i++) {
174 		skb_put_le32(skb, base + data[i].reg);
175 		skb_put_le32(skb, data[i].value);
176 	}
177 
178 	mutex_lock(&usb->mcu.mutex);
179 	ret = __mt76x02u_mcu_send_msg(dev, skb, CMD_RANDOM_WRITE, cnt == n);
180 	mutex_unlock(&usb->mcu.mutex);
181 	if (ret)
182 		return ret;
183 
184 	return mt76x02u_mcu_wr_rp(dev, base, data + cnt, n - cnt);
185 }
186 
187 static int
188 mt76x02u_mcu_rd_rp(struct mt76_dev *dev, u32 base,
189 		   struct mt76_reg_pair *data, int n)
190 {
191 	const int CMD_RANDOM_READ = 10;
192 	const int max_vals_per_cmd = MT_INBAND_PACKET_MAX_LEN / 8;
193 	struct mt76_usb *usb = &dev->usb;
194 	struct sk_buff *skb;
195 	int cnt, i, ret;
196 
197 	if (!n)
198 		return 0;
199 
200 	cnt = min(max_vals_per_cmd, n);
201 	if (cnt != n)
202 		return -EINVAL;
203 
204 	skb = alloc_skb(cnt * 8 + MT_DMA_HDR_LEN + 4, GFP_KERNEL);
205 	if (!skb)
206 		return -ENOMEM;
207 	skb_reserve(skb, MT_DMA_HDR_LEN);
208 
209 	for (i = 0; i < cnt; i++) {
210 		skb_put_le32(skb, base + data[i].reg);
211 		skb_put_le32(skb, data[i].value);
212 	}
213 
214 	mutex_lock(&usb->mcu.mutex);
215 
216 	usb->mcu.rp = data;
217 	usb->mcu.rp_len = n;
218 	usb->mcu.base = base;
219 	usb->mcu.burst = false;
220 
221 	ret = __mt76x02u_mcu_send_msg(dev, skb, CMD_RANDOM_READ, true);
222 
223 	usb->mcu.rp = NULL;
224 
225 	mutex_unlock(&usb->mcu.mutex);
226 
227 	return ret;
228 }
229 
230 void mt76x02u_mcu_fw_reset(struct mt76x02_dev *dev)
231 {
232 	mt76u_vendor_request(&dev->mt76, MT_VEND_DEV_MODE,
233 			     USB_DIR_OUT | USB_TYPE_VENDOR,
234 			     0x1, 0, NULL, 0);
235 }
236 EXPORT_SYMBOL_GPL(mt76x02u_mcu_fw_reset);
237 
238 static int
239 __mt76x02u_mcu_fw_send_data(struct mt76x02_dev *dev, u8 *data,
240 			    const void *fw_data, int len, u32 dst_addr)
241 {
242 	__le32 info;
243 	u32 val;
244 	int err, data_len;
245 
246 	info = cpu_to_le32(FIELD_PREP(MT_MCU_MSG_PORT, CPU_TX_PORT) |
247 			   FIELD_PREP(MT_MCU_MSG_LEN, len) |
248 			   MT_MCU_MSG_TYPE_CMD);
249 
250 	memcpy(data, &info, sizeof(info));
251 	memcpy(data + sizeof(info), fw_data, len);
252 	memset(data + sizeof(info) + len, 0, 4);
253 
254 	mt76u_single_wr(&dev->mt76, MT_VEND_WRITE_FCE,
255 			MT_FCE_DMA_ADDR, dst_addr);
256 	len = roundup(len, 4);
257 	mt76u_single_wr(&dev->mt76, MT_VEND_WRITE_FCE,
258 			MT_FCE_DMA_LEN, len << 16);
259 
260 	data_len = MT_CMD_HDR_LEN + len + sizeof(info);
261 
262 	err = mt76u_bulk_msg(&dev->mt76, data, data_len, NULL, 1000);
263 	if (err) {
264 		dev_err(dev->mt76.dev, "firmware upload failed: %d\n", err);
265 		return err;
266 	}
267 
268 	val = mt76_rr(dev, MT_TX_CPU_FROM_FCE_CPU_DESC_IDX);
269 	val++;
270 	mt76_wr(dev, MT_TX_CPU_FROM_FCE_CPU_DESC_IDX, val);
271 
272 	return 0;
273 }
274 
275 int mt76x02u_mcu_fw_send_data(struct mt76x02_dev *dev, const void *data,
276 			      int data_len, u32 max_payload, u32 offset)
277 {
278 	int len, err = 0, pos = 0, max_len = max_payload - 8;
279 	u8 *buf;
280 
281 	buf = kmalloc(max_payload, GFP_KERNEL);
282 	if (!buf)
283 		return -ENOMEM;
284 
285 	while (data_len > 0) {
286 		len = min_t(int, data_len, max_len);
287 		err = __mt76x02u_mcu_fw_send_data(dev, buf, data + pos,
288 						  len, offset + pos);
289 		if (err < 0)
290 			break;
291 
292 		data_len -= len;
293 		pos += len;
294 		usleep_range(5000, 10000);
295 	}
296 	kfree(buf);
297 
298 	return err;
299 }
300 EXPORT_SYMBOL_GPL(mt76x02u_mcu_fw_send_data);
301 
302 void mt76x02u_init_mcu(struct mt76_dev *dev)
303 {
304 	static const struct mt76_mcu_ops mt76x02u_mcu_ops = {
305 		.mcu_send_msg = mt76x02u_mcu_send_msg,
306 		.mcu_wr_rp = mt76x02u_mcu_wr_rp,
307 		.mcu_rd_rp = mt76x02u_mcu_rd_rp,
308 	};
309 
310 	dev->mcu_ops = &mt76x02u_mcu_ops;
311 }
312 EXPORT_SYMBOL_GPL(mt76x02u_init_mcu);
313 
314 MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>");
315 MODULE_LICENSE("Dual BSD/GPL");
316