]>
Commit | Line | Data |
---|---|---|
5fd54ace | 1 | // SPDX-License-Identifier: GPL-2.0 |
df2069ac CY |
2 | /* |
3 | * mtu3_gadget_ep0.c - MediaTek USB3 DRD peripheral driver ep0 handling | |
4 | * | |
5 | * Copyright (c) 2016 MediaTek Inc. | |
6 | * | |
7 | * Author: Chunfeng.Yun <chunfeng.yun@mediatek.com> | |
df2069ac CY |
8 | */ |
9 | ||
f3b28e5e | 10 | #include <linux/iopoll.h> |
fe7c994a CY |
11 | #include <linux/usb/composite.h> |
12 | ||
df2069ac | 13 | #include "mtu3.h" |
83374e03 CY |
14 | #include "mtu3_debug.h" |
15 | #include "mtu3_trace.h" | |
df2069ac CY |
16 | |
17 | /* ep0 is always mtu3->in_eps[0] */ | |
18 | #define next_ep0_request(mtu) next_request((mtu)->ep0) | |
19 | ||
20 | /* for high speed test mode; see USB 2.0 spec 7.1.20 */ | |
21 | static const u8 mtu3_test_packet[53] = { | |
22 | /* implicit SYNC then DATA0 to start */ | |
23 | ||
24 | /* JKJKJKJK x9 */ | |
25 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
26 | /* JJKKJJKK x8 */ | |
27 | 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, | |
28 | /* JJJJKKKK x8 */ | |
29 | 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, | |
30 | /* JJJJJJJKKKKKKK x8 */ | |
31 | 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | |
32 | /* JJJJJJJK x8 */ | |
33 | 0x7f, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, | |
34 | /* JKKKKKKK x10, JK */ | |
35 | 0xfc, 0x7e, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 0x7e, | |
36 | /* implicit CRC16 then EOP to end */ | |
37 | }; | |
38 | ||
39 | static char *decode_ep0_state(struct mtu3 *mtu) | |
40 | { | |
41 | switch (mtu->ep0_state) { | |
42 | case MU3D_EP0_STATE_SETUP: | |
43 | return "SETUP"; | |
44 | case MU3D_EP0_STATE_TX: | |
45 | return "IN"; | |
46 | case MU3D_EP0_STATE_RX: | |
47 | return "OUT"; | |
48 | case MU3D_EP0_STATE_TX_END: | |
49 | return "TX-END"; | |
50 | case MU3D_EP0_STATE_STALL: | |
51 | return "STALL"; | |
52 | default: | |
53 | return "??"; | |
54 | } | |
55 | } | |
56 | ||
57 | static void ep0_req_giveback(struct mtu3 *mtu, struct usb_request *req) | |
58 | { | |
59 | mtu3_req_complete(mtu->ep0, req, 0); | |
60 | } | |
61 | ||
62 | static int | |
63 | forward_to_driver(struct mtu3 *mtu, const struct usb_ctrlrequest *setup) | |
64 | __releases(mtu->lock) | |
65 | __acquires(mtu->lock) | |
66 | { | |
67 | int ret; | |
68 | ||
69 | if (!mtu->gadget_driver) | |
70 | return -EOPNOTSUPP; | |
71 | ||
72 | spin_unlock(&mtu->lock); | |
73 | ret = mtu->gadget_driver->setup(&mtu->g, setup); | |
74 | spin_lock(&mtu->lock); | |
75 | ||
76 | dev_dbg(mtu->dev, "%s ret %d\n", __func__, ret); | |
77 | return ret; | |
78 | } | |
79 | ||
80 | static void ep0_write_fifo(struct mtu3_ep *mep, const u8 *src, u16 len) | |
81 | { | |
82 | void __iomem *fifo = mep->mtu->mac_base + U3D_FIFO0; | |
83 | u16 index = 0; | |
84 | ||
85 | dev_dbg(mep->mtu->dev, "%s: ep%din, len=%d, buf=%p\n", | |
86 | __func__, mep->epnum, len, src); | |
87 | ||
88 | if (len >= 4) { | |
89 | iowrite32_rep(fifo, src, len >> 2); | |
90 | index = len & ~0x03; | |
91 | } | |
92 | if (len & 0x02) { | |
93 | writew(*(u16 *)&src[index], fifo); | |
94 | index += 2; | |
95 | } | |
96 | if (len & 0x01) | |
97 | writeb(src[index], fifo); | |
98 | } | |
99 | ||
100 | static void ep0_read_fifo(struct mtu3_ep *mep, u8 *dst, u16 len) | |
101 | { | |
102 | void __iomem *fifo = mep->mtu->mac_base + U3D_FIFO0; | |
103 | u32 value; | |
104 | u16 index = 0; | |
105 | ||
106 | dev_dbg(mep->mtu->dev, "%s: ep%dout len=%d buf=%p\n", | |
107 | __func__, mep->epnum, len, dst); | |
108 | ||
109 | if (len >= 4) { | |
110 | ioread32_rep(fifo, dst, len >> 2); | |
111 | index = len & ~0x03; | |
112 | } | |
113 | if (len & 0x3) { | |
114 | value = readl(fifo); | |
115 | memcpy(&dst[index], &value, len & 0x3); | |
116 | } | |
117 | ||
118 | } | |
119 | ||
120 | static void ep0_load_test_packet(struct mtu3 *mtu) | |
121 | { | |
122 | /* | |
123 | * because the length of test packet is less than max packet of HS ep0, | |
124 | * write it into fifo directly. | |
125 | */ | |
126 | ep0_write_fifo(mtu->ep0, mtu3_test_packet, sizeof(mtu3_test_packet)); | |
127 | } | |
128 | ||
129 | /* | |
130 | * A. send STALL for setup transfer without data stage: | |
131 | * set SENDSTALL and SETUPPKTRDY at the same time; | |
132 | * B. send STALL for other cases: | |
133 | * set SENDSTALL only. | |
134 | */ | |
135 | static void ep0_stall_set(struct mtu3_ep *mep0, bool set, u32 pktrdy) | |
136 | { | |
137 | struct mtu3 *mtu = mep0->mtu; | |
138 | void __iomem *mbase = mtu->mac_base; | |
139 | u32 csr; | |
140 | ||
141 | /* EP0_SENTSTALL is W1C */ | |
142 | csr = mtu3_readl(mbase, U3D_EP0CSR) & EP0_W1C_BITS; | |
143 | if (set) | |
144 | csr |= EP0_SENDSTALL | pktrdy; | |
145 | else | |
146 | csr = (csr & ~EP0_SENDSTALL) | EP0_SENTSTALL; | |
147 | mtu3_writel(mtu->mac_base, U3D_EP0CSR, csr); | |
148 | ||
fe7c994a | 149 | mtu->delayed_status = false; |
df2069ac CY |
150 | mtu->ep0_state = MU3D_EP0_STATE_SETUP; |
151 | ||
152 | dev_dbg(mtu->dev, "ep0: %s STALL, ep0_state: %s\n", | |
153 | set ? "SEND" : "CLEAR", decode_ep0_state(mtu)); | |
154 | } | |
155 | ||
156 | static int ep0_queue(struct mtu3_ep *mep0, struct mtu3_request *mreq); | |
157 | ||
158 | static void ep0_dummy_complete(struct usb_ep *ep, struct usb_request *req) | |
159 | {} | |
160 | ||
a29de31b CY |
161 | static void ep0_set_sel_complete(struct usb_ep *ep, struct usb_request *req) |
162 | { | |
163 | struct mtu3_request *mreq; | |
164 | struct mtu3 *mtu; | |
165 | struct usb_set_sel_req sel; | |
166 | ||
167 | memcpy(&sel, req->buf, sizeof(sel)); | |
168 | ||
169 | mreq = to_mtu3_request(req); | |
170 | mtu = mreq->mtu; | |
171 | dev_dbg(mtu->dev, "u1sel:%d, u1pel:%d, u2sel:%d, u2pel:%d\n", | |
172 | sel.u1_sel, sel.u1_pel, sel.u2_sel, sel.u2_pel); | |
173 | } | |
174 | ||
175 | /* queue data stage to handle 6 byte SET_SEL request */ | |
176 | static int ep0_set_sel(struct mtu3 *mtu, struct usb_ctrlrequest *setup) | |
177 | { | |
178 | int ret; | |
179 | u16 length = le16_to_cpu(setup->wLength); | |
180 | ||
181 | if (unlikely(length != 6)) { | |
182 | dev_err(mtu->dev, "%s wrong wLength:%d\n", | |
183 | __func__, length); | |
184 | return -EINVAL; | |
185 | } | |
186 | ||
187 | mtu->ep0_req.mep = mtu->ep0; | |
188 | mtu->ep0_req.request.length = 6; | |
189 | mtu->ep0_req.request.buf = mtu->setup_buf; | |
190 | mtu->ep0_req.request.complete = ep0_set_sel_complete; | |
191 | ret = ep0_queue(mtu->ep0, &mtu->ep0_req); | |
192 | ||
193 | return ret < 0 ? ret : 1; | |
194 | } | |
195 | ||
df2069ac CY |
196 | static int |
197 | ep0_get_status(struct mtu3 *mtu, const struct usb_ctrlrequest *setup) | |
198 | { | |
199 | struct mtu3_ep *mep = NULL; | |
200 | int handled = 1; | |
201 | u8 result[2] = {0, 0}; | |
202 | u8 epnum = 0; | |
203 | int is_in; | |
204 | ||
205 | switch (setup->bRequestType & USB_RECIP_MASK) { | |
206 | case USB_RECIP_DEVICE: | |
207 | result[0] = mtu->is_self_powered << USB_DEVICE_SELF_POWERED; | |
208 | result[0] |= mtu->may_wakeup << USB_DEVICE_REMOTE_WAKEUP; | |
4d79e042 CY |
209 | |
210 | if (mtu->g.speed >= USB_SPEED_SUPER) { | |
a29de31b CY |
211 | result[0] |= mtu->u1_enable << USB_DEV_STAT_U1_ENABLED; |
212 | result[0] |= mtu->u2_enable << USB_DEV_STAT_U2_ENABLED; | |
213 | } | |
214 | ||
215 | dev_dbg(mtu->dev, "%s result=%x, U1=%x, U2=%x\n", __func__, | |
216 | result[0], mtu->u1_enable, mtu->u2_enable); | |
217 | ||
df2069ac CY |
218 | break; |
219 | case USB_RECIP_INTERFACE: | |
220 | break; | |
221 | case USB_RECIP_ENDPOINT: | |
222 | epnum = (u8) le16_to_cpu(setup->wIndex); | |
223 | is_in = epnum & USB_DIR_IN; | |
224 | epnum &= USB_ENDPOINT_NUMBER_MASK; | |
225 | ||
226 | if (epnum >= mtu->num_eps) { | |
227 | handled = -EINVAL; | |
228 | break; | |
229 | } | |
230 | if (!epnum) | |
231 | break; | |
232 | ||
233 | mep = (is_in ? mtu->in_eps : mtu->out_eps) + epnum; | |
234 | if (!mep->desc) { | |
235 | handled = -EINVAL; | |
236 | break; | |
237 | } | |
238 | if (mep->flags & MTU3_EP_STALL) | |
239 | result[0] |= 1 << USB_ENDPOINT_HALT; | |
240 | ||
241 | break; | |
242 | default: | |
243 | /* class, vendor, etc ... delegate */ | |
244 | handled = 0; | |
245 | break; | |
246 | } | |
247 | ||
248 | if (handled > 0) { | |
249 | int ret; | |
250 | ||
251 | /* prepare a data stage for GET_STATUS */ | |
252 | dev_dbg(mtu->dev, "get_status=%x\n", *(u16 *)result); | |
253 | memcpy(mtu->setup_buf, result, sizeof(result)); | |
254 | mtu->ep0_req.mep = mtu->ep0; | |
255 | mtu->ep0_req.request.length = 2; | |
256 | mtu->ep0_req.request.buf = &mtu->setup_buf; | |
257 | mtu->ep0_req.request.complete = ep0_dummy_complete; | |
258 | ret = ep0_queue(mtu->ep0, &mtu->ep0_req); | |
259 | if (ret < 0) | |
260 | handled = ret; | |
261 | } | |
262 | return handled; | |
263 | } | |
264 | ||
265 | static int handle_test_mode(struct mtu3 *mtu, struct usb_ctrlrequest *setup) | |
266 | { | |
267 | void __iomem *mbase = mtu->mac_base; | |
268 | int handled = 1; | |
f3b28e5e | 269 | u32 value; |
df2069ac CY |
270 | |
271 | switch (le16_to_cpu(setup->wIndex) >> 8) { | |
272 | case TEST_J: | |
273 | dev_dbg(mtu->dev, "TEST_J\n"); | |
274 | mtu->test_mode_nr = TEST_J_MODE; | |
275 | break; | |
276 | case TEST_K: | |
277 | dev_dbg(mtu->dev, "TEST_K\n"); | |
278 | mtu->test_mode_nr = TEST_K_MODE; | |
279 | break; | |
280 | case TEST_SE0_NAK: | |
281 | dev_dbg(mtu->dev, "TEST_SE0_NAK\n"); | |
282 | mtu->test_mode_nr = TEST_SE0_NAK_MODE; | |
283 | break; | |
284 | case TEST_PACKET: | |
285 | dev_dbg(mtu->dev, "TEST_PACKET\n"); | |
286 | mtu->test_mode_nr = TEST_PACKET_MODE; | |
287 | break; | |
288 | default: | |
289 | handled = -EINVAL; | |
290 | goto out; | |
291 | } | |
292 | ||
293 | mtu->test_mode = true; | |
294 | ||
295 | /* no TX completion interrupt, and need restart platform after test */ | |
296 | if (mtu->test_mode_nr == TEST_PACKET_MODE) | |
297 | ep0_load_test_packet(mtu); | |
298 | ||
f3b28e5e CY |
299 | /* send status before entering test mode. */ |
300 | value = mtu3_readl(mbase, U3D_EP0CSR) & EP0_W1C_BITS; | |
301 | mtu3_writel(mbase, U3D_EP0CSR, value | EP0_SETUPPKTRDY | EP0_DATAEND); | |
302 | ||
303 | /* wait for ACK status sent by host */ | |
3d7678e2 | 304 | readl_poll_timeout_atomic(mbase + U3D_EP0CSR, value, |
f3b28e5e CY |
305 | !(value & EP0_DATAEND), 100, 5000); |
306 | ||
df2069ac CY |
307 | mtu3_writel(mbase, U3D_USB2_TEST_MODE, mtu->test_mode_nr); |
308 | ||
309 | mtu->ep0_state = MU3D_EP0_STATE_SETUP; | |
310 | ||
311 | out: | |
312 | return handled; | |
313 | } | |
314 | ||
315 | static int ep0_handle_feature_dev(struct mtu3 *mtu, | |
316 | struct usb_ctrlrequest *setup, bool set) | |
317 | { | |
a29de31b | 318 | void __iomem *mbase = mtu->mac_base; |
df2069ac | 319 | int handled = -EINVAL; |
a29de31b | 320 | u32 lpc; |
df2069ac CY |
321 | |
322 | switch (le16_to_cpu(setup->wValue)) { | |
323 | case USB_DEVICE_REMOTE_WAKEUP: | |
324 | mtu->may_wakeup = !!set; | |
325 | handled = 1; | |
326 | break; | |
327 | case USB_DEVICE_TEST_MODE: | |
328 | if (!set || (mtu->g.speed != USB_SPEED_HIGH) || | |
329 | (le16_to_cpu(setup->wIndex) & 0xff)) | |
330 | break; | |
331 | ||
332 | handled = handle_test_mode(mtu, setup); | |
333 | break; | |
a29de31b | 334 | case USB_DEVICE_U1_ENABLE: |
4d79e042 CY |
335 | if (mtu->g.speed < USB_SPEED_SUPER || |
336 | mtu->g.state != USB_STATE_CONFIGURED) | |
a29de31b CY |
337 | break; |
338 | ||
339 | lpc = mtu3_readl(mbase, U3D_LINK_POWER_CONTROL); | |
340 | if (set) | |
e8029724 | 341 | lpc |= SW_U1_REQUEST_ENABLE; |
a29de31b | 342 | else |
e8029724 | 343 | lpc &= ~SW_U1_REQUEST_ENABLE; |
a29de31b CY |
344 | mtu3_writel(mbase, U3D_LINK_POWER_CONTROL, lpc); |
345 | ||
346 | mtu->u1_enable = !!set; | |
347 | handled = 1; | |
348 | break; | |
349 | case USB_DEVICE_U2_ENABLE: | |
4d79e042 CY |
350 | if (mtu->g.speed < USB_SPEED_SUPER || |
351 | mtu->g.state != USB_STATE_CONFIGURED) | |
a29de31b CY |
352 | break; |
353 | ||
354 | lpc = mtu3_readl(mbase, U3D_LINK_POWER_CONTROL); | |
355 | if (set) | |
e8029724 | 356 | lpc |= SW_U2_REQUEST_ENABLE; |
a29de31b | 357 | else |
e8029724 | 358 | lpc &= ~SW_U2_REQUEST_ENABLE; |
a29de31b CY |
359 | mtu3_writel(mbase, U3D_LINK_POWER_CONTROL, lpc); |
360 | ||
361 | mtu->u2_enable = !!set; | |
362 | handled = 1; | |
363 | break; | |
df2069ac CY |
364 | default: |
365 | handled = -EINVAL; | |
366 | break; | |
367 | } | |
368 | return handled; | |
369 | } | |
370 | ||
371 | static int ep0_handle_feature(struct mtu3 *mtu, | |
372 | struct usb_ctrlrequest *setup, bool set) | |
373 | { | |
374 | struct mtu3_ep *mep; | |
375 | int handled = -EINVAL; | |
376 | int is_in; | |
377 | u16 value; | |
378 | u16 index; | |
379 | u8 epnum; | |
380 | ||
381 | value = le16_to_cpu(setup->wValue); | |
382 | index = le16_to_cpu(setup->wIndex); | |
383 | ||
384 | switch (setup->bRequestType & USB_RECIP_MASK) { | |
385 | case USB_RECIP_DEVICE: | |
386 | handled = ep0_handle_feature_dev(mtu, setup, set); | |
387 | break; | |
a29de31b CY |
388 | case USB_RECIP_INTERFACE: |
389 | /* superspeed only */ | |
4d79e042 CY |
390 | if (value == USB_INTRF_FUNC_SUSPEND && |
391 | mtu->g.speed >= USB_SPEED_SUPER) { | |
a29de31b CY |
392 | /* |
393 | * forward the request because function drivers | |
394 | * should handle it | |
395 | */ | |
396 | handled = 0; | |
397 | } | |
398 | break; | |
df2069ac CY |
399 | case USB_RECIP_ENDPOINT: |
400 | epnum = index & USB_ENDPOINT_NUMBER_MASK; | |
401 | if (epnum == 0 || epnum >= mtu->num_eps || | |
402 | value != USB_ENDPOINT_HALT) | |
403 | break; | |
404 | ||
405 | is_in = index & USB_DIR_IN; | |
406 | mep = (is_in ? mtu->in_eps : mtu->out_eps) + epnum; | |
407 | if (!mep->desc) | |
408 | break; | |
409 | ||
410 | handled = 1; | |
411 | /* ignore request if endpoint is wedged */ | |
412 | if (mep->wedged) | |
413 | break; | |
414 | ||
415 | mtu3_ep_stall_set(mep, set); | |
416 | break; | |
417 | default: | |
418 | /* class, vendor, etc ... delegate */ | |
419 | handled = 0; | |
420 | break; | |
421 | } | |
422 | return handled; | |
423 | } | |
424 | ||
425 | /* | |
426 | * handle all control requests can be handled | |
427 | * returns: | |
428 | * negative errno - error happened | |
429 | * zero - need delegate SETUP to gadget driver | |
430 | * positive - already handled | |
431 | */ | |
432 | static int handle_standard_request(struct mtu3 *mtu, | |
433 | struct usb_ctrlrequest *setup) | |
434 | { | |
435 | void __iomem *mbase = mtu->mac_base; | |
436 | enum usb_device_state state = mtu->g.state; | |
437 | int handled = -EINVAL; | |
438 | u32 dev_conf; | |
439 | u16 value; | |
440 | ||
441 | value = le16_to_cpu(setup->wValue); | |
442 | ||
443 | /* the gadget driver handles everything except what we must handle */ | |
444 | switch (setup->bRequest) { | |
445 | case USB_REQ_SET_ADDRESS: | |
446 | /* change it after the status stage */ | |
447 | mtu->address = (u8) (value & 0x7f); | |
448 | dev_dbg(mtu->dev, "set address to 0x%x\n", mtu->address); | |
449 | ||
450 | dev_conf = mtu3_readl(mbase, U3D_DEVICE_CONF); | |
451 | dev_conf &= ~DEV_ADDR_MSK; | |
452 | dev_conf |= DEV_ADDR(mtu->address); | |
453 | mtu3_writel(mbase, U3D_DEVICE_CONF, dev_conf); | |
454 | ||
455 | if (mtu->address) | |
456 | usb_gadget_set_state(&mtu->g, USB_STATE_ADDRESS); | |
457 | else | |
458 | usb_gadget_set_state(&mtu->g, USB_STATE_DEFAULT); | |
459 | ||
460 | handled = 1; | |
461 | break; | |
462 | case USB_REQ_SET_CONFIGURATION: | |
463 | if (state == USB_STATE_ADDRESS) { | |
464 | usb_gadget_set_state(&mtu->g, | |
465 | USB_STATE_CONFIGURED); | |
466 | } else if (state == USB_STATE_CONFIGURED) { | |
467 | /* | |
468 | * USB2 spec sec 9.4.7, if wValue is 0 then dev | |
469 | * is moved to addressed state | |
470 | */ | |
471 | if (!value) | |
472 | usb_gadget_set_state(&mtu->g, | |
473 | USB_STATE_ADDRESS); | |
474 | } | |
475 | handled = 0; | |
476 | break; | |
477 | case USB_REQ_CLEAR_FEATURE: | |
478 | handled = ep0_handle_feature(mtu, setup, 0); | |
479 | break; | |
480 | case USB_REQ_SET_FEATURE: | |
481 | handled = ep0_handle_feature(mtu, setup, 1); | |
482 | break; | |
483 | case USB_REQ_GET_STATUS: | |
484 | handled = ep0_get_status(mtu, setup); | |
485 | break; | |
a29de31b CY |
486 | case USB_REQ_SET_SEL: |
487 | handled = ep0_set_sel(mtu, setup); | |
488 | break; | |
df2069ac CY |
489 | case USB_REQ_SET_ISOCH_DELAY: |
490 | handled = 1; | |
491 | break; | |
492 | default: | |
493 | /* delegate SET_CONFIGURATION, etc */ | |
494 | handled = 0; | |
495 | } | |
496 | ||
497 | return handled; | |
498 | } | |
499 | ||
500 | /* receive an data packet (OUT) */ | |
501 | static void ep0_rx_state(struct mtu3 *mtu) | |
502 | { | |
503 | struct mtu3_request *mreq; | |
504 | struct usb_request *req; | |
505 | void __iomem *mbase = mtu->mac_base; | |
506 | u32 maxp; | |
507 | u32 csr; | |
508 | u16 count = 0; | |
509 | ||
510 | dev_dbg(mtu->dev, "%s\n", __func__); | |
511 | ||
512 | csr = mtu3_readl(mbase, U3D_EP0CSR) & EP0_W1C_BITS; | |
513 | mreq = next_ep0_request(mtu); | |
514 | req = &mreq->request; | |
515 | ||
516 | /* read packet and ack; or stall because of gadget driver bug */ | |
517 | if (req) { | |
518 | void *buf = req->buf + req->actual; | |
519 | unsigned int len = req->length - req->actual; | |
520 | ||
521 | /* read the buffer */ | |
522 | count = mtu3_readl(mbase, U3D_RXCOUNT0); | |
523 | if (count > len) { | |
524 | req->status = -EOVERFLOW; | |
525 | count = len; | |
526 | } | |
527 | ep0_read_fifo(mtu->ep0, buf, count); | |
528 | req->actual += count; | |
529 | csr |= EP0_RXPKTRDY; | |
530 | ||
531 | maxp = mtu->g.ep0->maxpacket; | |
532 | if (count < maxp || req->actual == req->length) { | |
533 | mtu->ep0_state = MU3D_EP0_STATE_SETUP; | |
534 | dev_dbg(mtu->dev, "ep0 state: %s\n", | |
535 | decode_ep0_state(mtu)); | |
536 | ||
537 | csr |= EP0_DATAEND; | |
538 | } else { | |
539 | req = NULL; | |
540 | } | |
541 | } else { | |
542 | csr |= EP0_RXPKTRDY | EP0_SENDSTALL; | |
543 | dev_dbg(mtu->dev, "%s: SENDSTALL\n", __func__); | |
544 | } | |
545 | ||
546 | mtu3_writel(mbase, U3D_EP0CSR, csr); | |
547 | ||
548 | /* give back the request if have received all data */ | |
549 | if (req) | |
550 | ep0_req_giveback(mtu, req); | |
551 | ||
552 | } | |
553 | ||
554 | /* transmitting to the host (IN) */ | |
555 | static void ep0_tx_state(struct mtu3 *mtu) | |
556 | { | |
557 | struct mtu3_request *mreq = next_ep0_request(mtu); | |
558 | struct usb_request *req; | |
559 | u32 csr; | |
560 | u8 *src; | |
288ee3c3 | 561 | u32 count; |
df2069ac CY |
562 | u32 maxp; |
563 | ||
564 | dev_dbg(mtu->dev, "%s\n", __func__); | |
565 | ||
566 | if (!mreq) | |
567 | return; | |
568 | ||
569 | maxp = mtu->g.ep0->maxpacket; | |
570 | req = &mreq->request; | |
571 | ||
572 | /* load the data */ | |
573 | src = (u8 *)req->buf + req->actual; | |
574 | count = min(maxp, req->length - req->actual); | |
575 | if (count) | |
576 | ep0_write_fifo(mtu->ep0, src, count); | |
577 | ||
578 | dev_dbg(mtu->dev, "%s act=%d, len=%d, cnt=%d, maxp=%d zero=%d\n", | |
579 | __func__, req->actual, req->length, count, maxp, req->zero); | |
580 | ||
581 | req->actual += count; | |
582 | ||
583 | if ((count < maxp) | |
584 | || ((req->actual == req->length) && !req->zero)) | |
585 | mtu->ep0_state = MU3D_EP0_STATE_TX_END; | |
586 | ||
587 | /* send it out, triggering a "txpktrdy cleared" irq */ | |
588 | csr = mtu3_readl(mtu->mac_base, U3D_EP0CSR) & EP0_W1C_BITS; | |
589 | mtu3_writel(mtu->mac_base, U3D_EP0CSR, csr | EP0_TXPKTRDY); | |
590 | ||
591 | dev_dbg(mtu->dev, "%s ep0csr=0x%x\n", __func__, | |
592 | mtu3_readl(mtu->mac_base, U3D_EP0CSR)); | |
593 | } | |
594 | ||
595 | static void ep0_read_setup(struct mtu3 *mtu, struct usb_ctrlrequest *setup) | |
596 | { | |
597 | struct mtu3_request *mreq; | |
598 | u32 count; | |
599 | u32 csr; | |
600 | ||
601 | csr = mtu3_readl(mtu->mac_base, U3D_EP0CSR) & EP0_W1C_BITS; | |
602 | count = mtu3_readl(mtu->mac_base, U3D_RXCOUNT0); | |
603 | ||
604 | ep0_read_fifo(mtu->ep0, (u8 *)setup, count); | |
605 | ||
606 | dev_dbg(mtu->dev, "SETUP req%02x.%02x v%04x i%04x l%04x\n", | |
607 | setup->bRequestType, setup->bRequest, | |
608 | le16_to_cpu(setup->wValue), le16_to_cpu(setup->wIndex), | |
609 | le16_to_cpu(setup->wLength)); | |
610 | ||
611 | /* clean up any leftover transfers */ | |
612 | mreq = next_ep0_request(mtu); | |
613 | if (mreq) | |
614 | ep0_req_giveback(mtu, &mreq->request); | |
615 | ||
616 | if (le16_to_cpu(setup->wLength) == 0) { | |
617 | ; /* no data stage, nothing to do */ | |
618 | } else if (setup->bRequestType & USB_DIR_IN) { | |
619 | mtu3_writel(mtu->mac_base, U3D_EP0CSR, | |
620 | csr | EP0_SETUPPKTRDY | EP0_DPHTX); | |
621 | mtu->ep0_state = MU3D_EP0_STATE_TX; | |
622 | } else { | |
623 | mtu3_writel(mtu->mac_base, U3D_EP0CSR, | |
624 | (csr | EP0_SETUPPKTRDY) & (~EP0_DPHTX)); | |
625 | mtu->ep0_state = MU3D_EP0_STATE_RX; | |
626 | } | |
627 | } | |
628 | ||
629 | static int ep0_handle_setup(struct mtu3 *mtu) | |
630 | __releases(mtu->lock) | |
631 | __acquires(mtu->lock) | |
632 | { | |
633 | struct usb_ctrlrequest setup; | |
634 | struct mtu3_request *mreq; | |
635 | void __iomem *mbase = mtu->mac_base; | |
636 | int handled = 0; | |
637 | ||
638 | ep0_read_setup(mtu, &setup); | |
83374e03 | 639 | trace_mtu3_handle_setup(&setup); |
df2069ac CY |
640 | |
641 | if ((setup.bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) | |
642 | handled = handle_standard_request(mtu, &setup); | |
643 | ||
644 | dev_dbg(mtu->dev, "handled %d, ep0_state: %s\n", | |
645 | handled, decode_ep0_state(mtu)); | |
646 | ||
647 | if (handled < 0) | |
648 | goto stall; | |
649 | else if (handled > 0) | |
650 | goto finish; | |
651 | ||
652 | handled = forward_to_driver(mtu, &setup); | |
653 | if (handled < 0) { | |
654 | stall: | |
655 | dev_dbg(mtu->dev, "%s stall (%d)\n", __func__, handled); | |
656 | ||
657 | ep0_stall_set(mtu->ep0, true, | |
658 | le16_to_cpu(setup.wLength) ? 0 : EP0_SETUPPKTRDY); | |
659 | ||
660 | return 0; | |
661 | } | |
662 | ||
663 | finish: | |
664 | if (mtu->test_mode) { | |
665 | ; /* nothing to do */ | |
fe7c994a CY |
666 | } else if (handled == USB_GADGET_DELAYED_STATUS) { |
667 | /* handle the delay STATUS phase till receive ep_queue on ep0 */ | |
668 | mtu->delayed_status = true; | |
df2069ac CY |
669 | } else if (le16_to_cpu(setup.wLength) == 0) { /* no data stage */ |
670 | ||
671 | mtu3_writel(mbase, U3D_EP0CSR, | |
672 | (mtu3_readl(mbase, U3D_EP0CSR) & EP0_W1C_BITS) | |
673 | | EP0_SETUPPKTRDY | EP0_DATAEND); | |
674 | ||
675 | /* complete zlp request directly */ | |
676 | mreq = next_ep0_request(mtu); | |
677 | if (mreq && !mreq->request.length) | |
678 | ep0_req_giveback(mtu, &mreq->request); | |
679 | } | |
680 | ||
681 | return 0; | |
682 | } | |
683 | ||
684 | irqreturn_t mtu3_ep0_isr(struct mtu3 *mtu) | |
685 | { | |
686 | void __iomem *mbase = mtu->mac_base; | |
687 | struct mtu3_request *mreq; | |
688 | u32 int_status; | |
689 | irqreturn_t ret = IRQ_NONE; | |
690 | u32 csr; | |
691 | u32 len; | |
692 | ||
693 | int_status = mtu3_readl(mbase, U3D_EPISR); | |
694 | int_status &= mtu3_readl(mbase, U3D_EPIER); | |
695 | mtu3_writel(mbase, U3D_EPISR, int_status); /* W1C */ | |
696 | ||
697 | /* only handle ep0's */ | |
94552090 | 698 | if (!(int_status & (EP0ISR | SETUPENDISR))) |
df2069ac CY |
699 | return IRQ_NONE; |
700 | ||
94552090 CY |
701 | /* abort current SETUP, and process new one */ |
702 | if (int_status & SETUPENDISR) | |
703 | mtu->ep0_state = MU3D_EP0_STATE_SETUP; | |
704 | ||
df2069ac CY |
705 | csr = mtu3_readl(mbase, U3D_EP0CSR); |
706 | ||
707 | dev_dbg(mtu->dev, "%s csr=0x%x\n", __func__, csr); | |
708 | ||
709 | /* we sent a stall.. need to clear it now.. */ | |
710 | if (csr & EP0_SENTSTALL) { | |
711 | ep0_stall_set(mtu->ep0, false, 0); | |
712 | csr = mtu3_readl(mbase, U3D_EP0CSR); | |
713 | ret = IRQ_HANDLED; | |
714 | } | |
715 | dev_dbg(mtu->dev, "ep0_state: %s\n", decode_ep0_state(mtu)); | |
83374e03 | 716 | mtu3_dbg_trace(mtu->dev, "ep0_state %s", decode_ep0_state(mtu)); |
df2069ac CY |
717 | |
718 | switch (mtu->ep0_state) { | |
719 | case MU3D_EP0_STATE_TX: | |
720 | /* irq on clearing txpktrdy */ | |
721 | if ((csr & EP0_FIFOFULL) == 0) { | |
722 | ep0_tx_state(mtu); | |
723 | ret = IRQ_HANDLED; | |
724 | } | |
725 | break; | |
726 | case MU3D_EP0_STATE_RX: | |
727 | /* irq on set rxpktrdy */ | |
728 | if (csr & EP0_RXPKTRDY) { | |
729 | ep0_rx_state(mtu); | |
730 | ret = IRQ_HANDLED; | |
731 | } | |
732 | break; | |
733 | case MU3D_EP0_STATE_TX_END: | |
734 | mtu3_writel(mbase, U3D_EP0CSR, | |
735 | (csr & EP0_W1C_BITS) | EP0_DATAEND); | |
736 | ||
737 | mreq = next_ep0_request(mtu); | |
738 | if (mreq) | |
739 | ep0_req_giveback(mtu, &mreq->request); | |
740 | ||
741 | mtu->ep0_state = MU3D_EP0_STATE_SETUP; | |
742 | ret = IRQ_HANDLED; | |
743 | dev_dbg(mtu->dev, "ep0_state: %s\n", decode_ep0_state(mtu)); | |
744 | break; | |
745 | case MU3D_EP0_STATE_SETUP: | |
746 | if (!(csr & EP0_SETUPPKTRDY)) | |
747 | break; | |
748 | ||
749 | len = mtu3_readl(mbase, U3D_RXCOUNT0); | |
750 | if (len != 8) { | |
751 | dev_err(mtu->dev, "SETUP packet len %d != 8 ?\n", len); | |
752 | break; | |
753 | } | |
754 | ||
755 | ep0_handle_setup(mtu); | |
756 | ret = IRQ_HANDLED; | |
757 | break; | |
758 | default: | |
759 | /* can't happen */ | |
760 | ep0_stall_set(mtu->ep0, true, 0); | |
761 | WARN_ON(1); | |
762 | break; | |
763 | } | |
764 | ||
765 | return ret; | |
766 | } | |
767 | ||
768 | ||
769 | static int mtu3_ep0_enable(struct usb_ep *ep, | |
770 | const struct usb_endpoint_descriptor *desc) | |
771 | { | |
772 | /* always enabled */ | |
773 | return -EINVAL; | |
774 | } | |
775 | ||
776 | static int mtu3_ep0_disable(struct usb_ep *ep) | |
777 | { | |
778 | /* always enabled */ | |
779 | return -EINVAL; | |
780 | } | |
781 | ||
782 | static int ep0_queue(struct mtu3_ep *mep, struct mtu3_request *mreq) | |
783 | { | |
784 | struct mtu3 *mtu = mep->mtu; | |
785 | ||
786 | mreq->mtu = mtu; | |
787 | mreq->request.actual = 0; | |
788 | mreq->request.status = -EINPROGRESS; | |
789 | ||
790 | dev_dbg(mtu->dev, "%s %s (ep0_state: %s), len#%d\n", __func__, | |
791 | mep->name, decode_ep0_state(mtu), mreq->request.length); | |
792 | ||
df2069ac CY |
793 | switch (mtu->ep0_state) { |
794 | case MU3D_EP0_STATE_SETUP: | |
795 | case MU3D_EP0_STATE_RX: /* control-OUT data */ | |
796 | case MU3D_EP0_STATE_TX: /* control-IN data */ | |
797 | break; | |
798 | default: | |
799 | dev_err(mtu->dev, "%s, error in ep0 state %s\n", __func__, | |
800 | decode_ep0_state(mtu)); | |
801 | return -EINVAL; | |
802 | } | |
803 | ||
fe7c994a CY |
804 | if (mtu->delayed_status) { |
805 | u32 csr; | |
806 | ||
807 | mtu->delayed_status = false; | |
808 | csr = mtu3_readl(mtu->mac_base, U3D_EP0CSR) & EP0_W1C_BITS; | |
809 | csr |= EP0_SETUPPKTRDY | EP0_DATAEND; | |
810 | mtu3_writel(mtu->mac_base, U3D_EP0CSR, csr); | |
811 | /* needn't giveback the request for handling delay STATUS */ | |
812 | return 0; | |
813 | } | |
814 | ||
815 | if (!list_empty(&mep->req_list)) | |
816 | return -EBUSY; | |
817 | ||
df2069ac CY |
818 | list_add_tail(&mreq->list, &mep->req_list); |
819 | ||
820 | /* sequence #1, IN ... start writing the data */ | |
821 | if (mtu->ep0_state == MU3D_EP0_STATE_TX) | |
822 | ep0_tx_state(mtu); | |
823 | ||
824 | return 0; | |
825 | } | |
826 | ||
827 | static int mtu3_ep0_queue(struct usb_ep *ep, | |
828 | struct usb_request *req, gfp_t gfp) | |
829 | { | |
830 | struct mtu3_ep *mep; | |
831 | struct mtu3_request *mreq; | |
832 | struct mtu3 *mtu; | |
833 | unsigned long flags; | |
834 | int ret = 0; | |
835 | ||
836 | if (!ep || !req) | |
837 | return -EINVAL; | |
838 | ||
839 | mep = to_mtu3_ep(ep); | |
840 | mtu = mep->mtu; | |
841 | mreq = to_mtu3_request(req); | |
842 | ||
843 | spin_lock_irqsave(&mtu->lock, flags); | |
844 | ret = ep0_queue(mep, mreq); | |
845 | spin_unlock_irqrestore(&mtu->lock, flags); | |
846 | return ret; | |
847 | } | |
848 | ||
849 | static int mtu3_ep0_dequeue(struct usb_ep *ep, struct usb_request *req) | |
850 | { | |
851 | /* we just won't support this */ | |
852 | return -EINVAL; | |
853 | } | |
854 | ||
855 | static int mtu3_ep0_halt(struct usb_ep *ep, int value) | |
856 | { | |
857 | struct mtu3_ep *mep; | |
858 | struct mtu3 *mtu; | |
859 | unsigned long flags; | |
860 | int ret = 0; | |
861 | ||
862 | if (!ep || !value) | |
863 | return -EINVAL; | |
864 | ||
865 | mep = to_mtu3_ep(ep); | |
866 | mtu = mep->mtu; | |
867 | ||
868 | dev_dbg(mtu->dev, "%s\n", __func__); | |
869 | ||
870 | spin_lock_irqsave(&mtu->lock, flags); | |
871 | ||
872 | if (!list_empty(&mep->req_list)) { | |
873 | ret = -EBUSY; | |
874 | goto cleanup; | |
875 | } | |
876 | ||
877 | switch (mtu->ep0_state) { | |
878 | /* | |
879 | * stalls are usually issued after parsing SETUP packet, either | |
880 | * directly in irq context from setup() or else later. | |
881 | */ | |
882 | case MU3D_EP0_STATE_TX: | |
883 | case MU3D_EP0_STATE_TX_END: | |
884 | case MU3D_EP0_STATE_RX: | |
885 | case MU3D_EP0_STATE_SETUP: | |
886 | ep0_stall_set(mtu->ep0, true, 0); | |
887 | break; | |
888 | default: | |
889 | dev_dbg(mtu->dev, "ep0 can't halt in state %s\n", | |
890 | decode_ep0_state(mtu)); | |
891 | ret = -EINVAL; | |
892 | } | |
893 | ||
894 | cleanup: | |
895 | spin_unlock_irqrestore(&mtu->lock, flags); | |
896 | return ret; | |
897 | } | |
898 | ||
899 | const struct usb_ep_ops mtu3_ep0_ops = { | |
900 | .enable = mtu3_ep0_enable, | |
901 | .disable = mtu3_ep0_disable, | |
902 | .alloc_request = mtu3_alloc_request, | |
903 | .free_request = mtu3_free_request, | |
904 | .queue = mtu3_ep0_queue, | |
905 | .dequeue = mtu3_ep0_dequeue, | |
906 | .set_halt = mtu3_ep0_halt, | |
907 | }; |