]>
Commit | Line | Data |
---|---|---|
38517a78 | 1 | /* |
be5e4bdc | 2 | * drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c |
e179cedd | 3 | * Designware DWC2 on-chip full/high speed USB OTG 2.0 device controllers |
38517a78 ŁM |
4 | * |
5 | * Copyright (C) 2009 for Samsung Electronics | |
6 | * | |
7 | * BSP Support for Samsung's UDC driver | |
8 | * available at: | |
9 | * git://git.kernel.org/pub/scm/linux/kernel/git/kki_ap/linux-2.6-samsung.git | |
10 | * | |
11 | * State machine bugfixes: | |
12 | * Marek Szyprowski <m.szyprowski@samsung.com> | |
13 | * | |
14 | * Ported to u-boot: | |
15 | * Marek Szyprowski <m.szyprowski@samsung.com> | |
16 | * Lukasz Majewski <l.majewski@samsumg.com> | |
17 | * | |
1a459660 | 18 | * SPDX-License-Identifier: GPL-2.0+ |
38517a78 ŁM |
19 | */ |
20 | ||
21 | static u8 clear_feature_num; | |
22 | int clear_feature_flag; | |
23 | ||
24 | /* Bulk-Only Mass Storage Reset (class-specific request) */ | |
25 | #define GET_MAX_LUN_REQUEST 0xFE | |
26 | #define BOT_RESET_REQUEST 0xFF | |
27 | ||
f52dd802 | 28 | static inline void dwc2_udc_ep0_zlp(struct dwc2_udc *dev) |
38517a78 ŁM |
29 | { |
30 | u32 ep_ctrl; | |
31 | ||
38517a78 ŁM |
32 | writel(usb_ctrl_dma_addr, ®->in_endp[EP0_CON].diepdma); |
33 | writel(DIEPT_SIZ_PKT_CNT(1), ®->in_endp[EP0_CON].dieptsiz); | |
34 | ||
35 | ep_ctrl = readl(®->in_endp[EP0_CON].diepctl); | |
36 | writel(ep_ctrl|DEPCTL_EPENA|DEPCTL_CNAK, | |
37 | ®->in_endp[EP0_CON].diepctl); | |
38 | ||
f3b05ca5 | 39 | debug_cond(DEBUG_EP0 != 0, "%s:EP0 ZLP DIEPCTL0 = 0x%x\n", |
38517a78 ŁM |
40 | __func__, readl(®->in_endp[EP0_CON].diepctl)); |
41 | dev->ep0state = WAIT_FOR_IN_COMPLETE; | |
42 | } | |
43 | ||
f52dd802 | 44 | static void dwc2_udc_pre_setup(void) |
38517a78 ŁM |
45 | { |
46 | u32 ep_ctrl; | |
47 | ||
f3b05ca5 ŁM |
48 | debug_cond(DEBUG_IN_EP, |
49 | "%s : Prepare Setup packets.\n", __func__); | |
38517a78 | 50 | |
38517a78 ŁM |
51 | writel(DOEPT_SIZ_PKT_CNT(1) | sizeof(struct usb_ctrlrequest), |
52 | ®->out_endp[EP0_CON].doeptsiz); | |
53 | writel(usb_ctrl_dma_addr, ®->out_endp[EP0_CON].doepdma); | |
54 | ||
55 | ep_ctrl = readl(®->out_endp[EP0_CON].doepctl); | |
56 | writel(ep_ctrl|DEPCTL_EPENA, ®->out_endp[EP0_CON].doepctl); | |
57 | ||
f3b05ca5 | 58 | debug_cond(DEBUG_EP0 != 0, "%s:EP0 ZLP DIEPCTL0 = 0x%x\n", |
38517a78 | 59 | __func__, readl(®->in_endp[EP0_CON].diepctl)); |
f3b05ca5 | 60 | debug_cond(DEBUG_EP0 != 0, "%s:EP0 ZLP DOEPCTL0 = 0x%x\n", |
38517a78 ŁM |
61 | __func__, readl(®->out_endp[EP0_CON].doepctl)); |
62 | ||
63 | } | |
64 | ||
28b97748 | 65 | static inline void dwc2_ep0_complete_out(void) |
38517a78 ŁM |
66 | { |
67 | u32 ep_ctrl; | |
68 | ||
f3b05ca5 | 69 | debug_cond(DEBUG_EP0 != 0, "%s:EP0 ZLP DIEPCTL0 = 0x%x\n", |
38517a78 | 70 | __func__, readl(®->in_endp[EP0_CON].diepctl)); |
f3b05ca5 | 71 | debug_cond(DEBUG_EP0 != 0, "%s:EP0 ZLP DOEPCTL0 = 0x%x\n", |
38517a78 ŁM |
72 | __func__, readl(®->out_endp[EP0_CON].doepctl)); |
73 | ||
ea2d9159 AG |
74 | debug_cond(DEBUG_IN_EP, |
75 | "%s : Prepare Complete Out packet.\n", __func__); | |
38517a78 | 76 | |
38517a78 ŁM |
77 | writel(DOEPT_SIZ_PKT_CNT(1) | sizeof(struct usb_ctrlrequest), |
78 | ®->out_endp[EP0_CON].doeptsiz); | |
79 | writel(usb_ctrl_dma_addr, ®->out_endp[EP0_CON].doepdma); | |
80 | ||
81 | ep_ctrl = readl(®->out_endp[EP0_CON].doepctl); | |
82 | writel(ep_ctrl|DEPCTL_EPENA|DEPCTL_CNAK, | |
83 | ®->out_endp[EP0_CON].doepctl); | |
84 | ||
f3b05ca5 | 85 | debug_cond(DEBUG_EP0 != 0, "%s:EP0 ZLP DIEPCTL0 = 0x%x\n", |
38517a78 | 86 | __func__, readl(®->in_endp[EP0_CON].diepctl)); |
f3b05ca5 | 87 | debug_cond(DEBUG_EP0 != 0, "%s:EP0 ZLP DOEPCTL0 = 0x%x\n", |
38517a78 ŁM |
88 | __func__, readl(®->out_endp[EP0_CON].doepctl)); |
89 | ||
90 | } | |
91 | ||
92 | ||
c056c52b | 93 | static int setdma_rx(struct dwc2_ep *ep, struct dwc2_request *req) |
38517a78 ŁM |
94 | { |
95 | u32 *buf, ctrl; | |
96 | u32 length, pktcnt; | |
97 | u32 ep_num = ep_index(ep); | |
98 | ||
99 | buf = req->req.buf + req->req.actual; | |
b4141195 MY |
100 | length = min_t(u32, req->req.length - req->req.actual, |
101 | ep_num ? DMA_BUFFER_SIZE : ep->ep.maxpacket); | |
38517a78 ŁM |
102 | |
103 | ep->len = length; | |
104 | ep->dma_buf = buf; | |
105 | ||
9c982218 | 106 | if (ep_num == EP0_CON || length == 0) |
38517a78 ŁM |
107 | pktcnt = 1; |
108 | else | |
109 | pktcnt = (length - 1)/(ep->ep.maxpacket) + 1; | |
110 | ||
38517a78 ŁM |
111 | ctrl = readl(®->out_endp[ep_num].doepctl); |
112 | ||
e0059eae | 113 | writel((unsigned int) ep->dma_buf, ®->out_endp[ep_num].doepdma); |
38517a78 ŁM |
114 | writel(DOEPT_SIZ_PKT_CNT(pktcnt) | DOEPT_SIZ_XFER_SIZE(length), |
115 | ®->out_endp[ep_num].doeptsiz); | |
116 | writel(DEPCTL_EPENA|DEPCTL_CNAK|ctrl, ®->out_endp[ep_num].doepctl); | |
117 | ||
f3b05ca5 ŁM |
118 | debug_cond(DEBUG_OUT_EP != 0, |
119 | "%s: EP%d RX DMA start : DOEPDMA = 0x%x," | |
120 | "DOEPTSIZ = 0x%x, DOEPCTL = 0x%x\n" | |
121 | "\tbuf = 0x%p, pktcnt = %d, xfersize = %d\n", | |
122 | __func__, ep_num, | |
123 | readl(®->out_endp[ep_num].doepdma), | |
124 | readl(®->out_endp[ep_num].doeptsiz), | |
125 | readl(®->out_endp[ep_num].doepctl), | |
126 | buf, pktcnt, length); | |
38517a78 ŁM |
127 | return 0; |
128 | ||
129 | } | |
130 | ||
de578e22 | 131 | static int setdma_tx(struct dwc2_ep *ep, struct dwc2_request *req) |
38517a78 ŁM |
132 | { |
133 | u32 *buf, ctrl = 0; | |
134 | u32 length, pktcnt; | |
135 | u32 ep_num = ep_index(ep); | |
38517a78 ŁM |
136 | |
137 | buf = req->req.buf + req->req.actual; | |
138 | length = req->req.length - req->req.actual; | |
139 | ||
140 | if (ep_num == EP0_CON) | |
6777a3cf | 141 | length = min(length, (u32)ep_maxpacket(ep)); |
38517a78 ŁM |
142 | |
143 | ep->len = length; | |
144 | ep->dma_buf = buf; | |
38517a78 | 145 | |
e0059eae ŁM |
146 | flush_dcache_range((unsigned long) ep->dma_buf, |
147 | (unsigned long) ep->dma_buf + | |
148 | ROUND(ep->len, CONFIG_SYS_CACHELINE_SIZE)); | |
38517a78 ŁM |
149 | |
150 | if (length == 0) | |
151 | pktcnt = 1; | |
152 | else | |
153 | pktcnt = (length - 1)/(ep->ep.maxpacket) + 1; | |
154 | ||
155 | /* Flush the endpoint's Tx FIFO */ | |
156 | writel(TX_FIFO_NUMBER(ep->fifo_num), ®->grstctl); | |
157 | writel(TX_FIFO_NUMBER(ep->fifo_num) | TX_FIFO_FLUSH, ®->grstctl); | |
158 | while (readl(®->grstctl) & TX_FIFO_FLUSH) | |
159 | ; | |
160 | ||
e0059eae | 161 | writel((unsigned long) ep->dma_buf, ®->in_endp[ep_num].diepdma); |
38517a78 ŁM |
162 | writel(DIEPT_SIZ_PKT_CNT(pktcnt) | DIEPT_SIZ_XFER_SIZE(length), |
163 | ®->in_endp[ep_num].dieptsiz); | |
164 | ||
165 | ctrl = readl(®->in_endp[ep_num].diepctl); | |
166 | ||
167 | /* Write the FIFO number to be used for this endpoint */ | |
168 | ctrl &= DIEPCTL_TX_FIFO_NUM_MASK; | |
169 | ctrl |= DIEPCTL_TX_FIFO_NUM(ep->fifo_num); | |
170 | ||
171 | /* Clear reserved (Next EP) bits */ | |
172 | ctrl = (ctrl&~(EP_MASK<<DEPCTL_NEXT_EP_BIT)); | |
173 | ||
174 | writel(DEPCTL_EPENA|DEPCTL_CNAK|ctrl, ®->in_endp[ep_num].diepctl); | |
175 | ||
ea2d9159 AG |
176 | debug_cond(DEBUG_IN_EP, |
177 | "%s:EP%d TX DMA start : DIEPDMA0 = 0x%x," | |
178 | "DIEPTSIZ0 = 0x%x, DIEPCTL0 = 0x%x\n" | |
179 | "\tbuf = 0x%p, pktcnt = %d, xfersize = %d\n", | |
180 | __func__, ep_num, | |
181 | readl(®->in_endp[ep_num].diepdma), | |
182 | readl(®->in_endp[ep_num].dieptsiz), | |
183 | readl(®->in_endp[ep_num].diepctl), | |
184 | buf, pktcnt, length); | |
38517a78 ŁM |
185 | |
186 | return length; | |
187 | } | |
188 | ||
b4d5cf0b | 189 | static void complete_rx(struct dwc2_udc *dev, u8 ep_num) |
38517a78 | 190 | { |
627d9298 | 191 | struct dwc2_ep *ep = &dev->ep[ep_num]; |
c056c52b | 192 | struct dwc2_request *req = NULL; |
38517a78 | 193 | u32 ep_tsr = 0, xfer_size = 0, is_short = 0; |
38517a78 ŁM |
194 | |
195 | if (list_empty(&ep->queue)) { | |
f3b05ca5 ŁM |
196 | debug_cond(DEBUG_OUT_EP != 0, |
197 | "%s: RX DMA done : NULL REQ on OUT EP-%d\n", | |
198 | __func__, ep_num); | |
38517a78 ŁM |
199 | return; |
200 | ||
201 | } | |
202 | ||
c056c52b | 203 | req = list_entry(ep->queue.next, struct dwc2_request, queue); |
38517a78 ŁM |
204 | ep_tsr = readl(®->out_endp[ep_num].doeptsiz); |
205 | ||
206 | if (ep_num == EP0_CON) | |
207 | xfer_size = (ep_tsr & DOEPT_SIZ_XFER_SIZE_MAX_EP0); | |
208 | else | |
209 | xfer_size = (ep_tsr & DOEPT_SIZ_XFER_SIZE_MAX_EP); | |
210 | ||
211 | xfer_size = ep->len - xfer_size; | |
212 | ||
e0059eae ŁM |
213 | /* |
214 | * NOTE: | |
215 | * | |
216 | * Please be careful with proper buffer allocation for USB request, | |
217 | * which needs to be aligned to CONFIG_SYS_CACHELINE_SIZE, not only | |
218 | * with starting address, but also its size shall be a cache line | |
219 | * multiplication. | |
220 | * | |
221 | * This will prevent from corruption of data allocated immediatelly | |
222 | * before or after the buffer. | |
223 | * | |
224 | * For armv7, the cache_v7.c provides proper code to emit "ERROR" | |
225 | * message to warn users. | |
226 | */ | |
227 | invalidate_dcache_range((unsigned long) ep->dma_buf, | |
228 | (unsigned long) ep->dma_buf + | |
229 | ROUND(xfer_size, CONFIG_SYS_CACHELINE_SIZE)); | |
38517a78 ŁM |
230 | |
231 | req->req.actual += min(xfer_size, req->req.length - req->req.actual); | |
842769ea | 232 | is_short = !!(xfer_size % ep->ep.maxpacket); |
38517a78 | 233 | |
f3b05ca5 ŁM |
234 | debug_cond(DEBUG_OUT_EP != 0, |
235 | "%s: RX DMA done : ep = %d, rx bytes = %d/%d, " | |
236 | "is_short = %d, DOEPTSIZ = 0x%x, remained bytes = %d\n", | |
237 | __func__, ep_num, req->req.actual, req->req.length, | |
4d5b6378 | 238 | is_short, ep_tsr, req->req.length - req->req.actual); |
38517a78 ŁM |
239 | |
240 | if (is_short || req->req.actual == req->req.length) { | |
241 | if (ep_num == EP0_CON && dev->ep0state == DATA_STATE_RECV) { | |
f3b05ca5 | 242 | debug_cond(DEBUG_OUT_EP != 0, " => Send ZLP\n"); |
f52dd802 | 243 | dwc2_udc_ep0_zlp(dev); |
38517a78 ŁM |
244 | /* packet will be completed in complete_tx() */ |
245 | dev->ep0state = WAIT_FOR_IN_COMPLETE; | |
246 | } else { | |
247 | done(ep, req, 0); | |
248 | ||
249 | if (!list_empty(&ep->queue)) { | |
250 | req = list_entry(ep->queue.next, | |
c056c52b | 251 | struct dwc2_request, queue); |
f3b05ca5 ŁM |
252 | debug_cond(DEBUG_OUT_EP != 0, |
253 | "%s: Next Rx request start...\n", | |
254 | __func__); | |
38517a78 ŁM |
255 | setdma_rx(ep, req); |
256 | } | |
257 | } | |
258 | } else | |
259 | setdma_rx(ep, req); | |
260 | } | |
261 | ||
b4d5cf0b | 262 | static void complete_tx(struct dwc2_udc *dev, u8 ep_num) |
38517a78 | 263 | { |
627d9298 | 264 | struct dwc2_ep *ep = &dev->ep[ep_num]; |
c056c52b | 265 | struct dwc2_request *req; |
38517a78 ŁM |
266 | u32 ep_tsr = 0, xfer_size = 0, is_short = 0; |
267 | u32 last; | |
268 | ||
269 | if (dev->ep0state == WAIT_FOR_NULL_COMPLETE) { | |
270 | dev->ep0state = WAIT_FOR_OUT_COMPLETE; | |
28b97748 | 271 | dwc2_ep0_complete_out(); |
38517a78 ŁM |
272 | return; |
273 | } | |
274 | ||
275 | if (list_empty(&ep->queue)) { | |
ea2d9159 AG |
276 | debug_cond(DEBUG_IN_EP, |
277 | "%s: TX DMA done : NULL REQ on IN EP-%d\n", | |
278 | __func__, ep_num); | |
38517a78 ŁM |
279 | return; |
280 | ||
281 | } | |
282 | ||
c056c52b | 283 | req = list_entry(ep->queue.next, struct dwc2_request, queue); |
38517a78 ŁM |
284 | |
285 | ep_tsr = readl(®->in_endp[ep_num].dieptsiz); | |
286 | ||
287 | xfer_size = ep->len; | |
288 | is_short = (xfer_size < ep->ep.maxpacket); | |
289 | req->req.actual += min(xfer_size, req->req.length - req->req.actual); | |
290 | ||
ea2d9159 AG |
291 | debug_cond(DEBUG_IN_EP, |
292 | "%s: TX DMA done : ep = %d, tx bytes = %d/%d, " | |
293 | "is_short = %d, DIEPTSIZ = 0x%x, remained bytes = %d\n", | |
294 | __func__, ep_num, req->req.actual, req->req.length, | |
4d5b6378 | 295 | is_short, ep_tsr, req->req.length - req->req.actual); |
38517a78 ŁM |
296 | |
297 | if (ep_num == 0) { | |
298 | if (dev->ep0state == DATA_STATE_XMIT) { | |
ea2d9159 AG |
299 | debug_cond(DEBUG_IN_EP, |
300 | "%s: ep_num = %d, ep0stat ==" | |
301 | "DATA_STATE_XMIT\n", | |
302 | __func__, ep_num); | |
38517a78 ŁM |
303 | last = write_fifo_ep0(ep, req); |
304 | if (last) | |
305 | dev->ep0state = WAIT_FOR_COMPLETE; | |
306 | } else if (dev->ep0state == WAIT_FOR_IN_COMPLETE) { | |
ea2d9159 AG |
307 | debug_cond(DEBUG_IN_EP, |
308 | "%s: ep_num = %d, completing request\n", | |
309 | __func__, ep_num); | |
38517a78 ŁM |
310 | done(ep, req, 0); |
311 | dev->ep0state = WAIT_FOR_SETUP; | |
312 | } else if (dev->ep0state == WAIT_FOR_COMPLETE) { | |
ea2d9159 AG |
313 | debug_cond(DEBUG_IN_EP, |
314 | "%s: ep_num = %d, completing request\n", | |
315 | __func__, ep_num); | |
38517a78 ŁM |
316 | done(ep, req, 0); |
317 | dev->ep0state = WAIT_FOR_OUT_COMPLETE; | |
28b97748 | 318 | dwc2_ep0_complete_out(); |
38517a78 | 319 | } else { |
ea2d9159 AG |
320 | debug_cond(DEBUG_IN_EP, |
321 | "%s: ep_num = %d, invalid ep state\n", | |
322 | __func__, ep_num); | |
38517a78 ŁM |
323 | } |
324 | return; | |
325 | } | |
326 | ||
327 | if (req->req.actual == req->req.length) | |
328 | done(ep, req, 0); | |
329 | ||
330 | if (!list_empty(&ep->queue)) { | |
c056c52b | 331 | req = list_entry(ep->queue.next, struct dwc2_request, queue); |
ea2d9159 AG |
332 | debug_cond(DEBUG_IN_EP, |
333 | "%s: Next Tx request start...\n", __func__); | |
38517a78 ŁM |
334 | setdma_tx(ep, req); |
335 | } | |
336 | } | |
337 | ||
f52dd802 | 338 | static inline void dwc2_udc_check_tx_queue(struct dwc2_udc *dev, u8 ep_num) |
38517a78 | 339 | { |
627d9298 | 340 | struct dwc2_ep *ep = &dev->ep[ep_num]; |
c056c52b | 341 | struct dwc2_request *req; |
38517a78 | 342 | |
ea2d9159 AG |
343 | debug_cond(DEBUG_IN_EP, |
344 | "%s: Check queue, ep_num = %d\n", __func__, ep_num); | |
38517a78 ŁM |
345 | |
346 | if (!list_empty(&ep->queue)) { | |
c056c52b | 347 | req = list_entry(ep->queue.next, struct dwc2_request, queue); |
ea2d9159 AG |
348 | debug_cond(DEBUG_IN_EP, |
349 | "%s: Next Tx request(0x%p) start...\n", | |
350 | __func__, req); | |
38517a78 ŁM |
351 | |
352 | if (ep_is_in(ep)) | |
353 | setdma_tx(ep, req); | |
354 | else | |
355 | setdma_rx(ep, req); | |
356 | } else { | |
ea2d9159 AG |
357 | debug_cond(DEBUG_IN_EP, |
358 | "%s: NULL REQ on IN EP-%d\n", __func__, ep_num); | |
38517a78 ŁM |
359 | |
360 | return; | |
361 | } | |
362 | ||
363 | } | |
364 | ||
b4d5cf0b | 365 | static void process_ep_in_intr(struct dwc2_udc *dev) |
38517a78 ŁM |
366 | { |
367 | u32 ep_intr, ep_intr_status; | |
368 | u8 ep_num = 0; | |
369 | ||
370 | ep_intr = readl(®->daint); | |
ea2d9159 AG |
371 | debug_cond(DEBUG_IN_EP, |
372 | "*** %s: EP In interrupt : DAINT = 0x%x\n", __func__, ep_intr); | |
38517a78 ŁM |
373 | |
374 | ep_intr &= DAINT_MASK; | |
375 | ||
376 | while (ep_intr) { | |
377 | if (ep_intr & DAINT_IN_EP_INT(1)) { | |
378 | ep_intr_status = readl(®->in_endp[ep_num].diepint); | |
f3b05ca5 ŁM |
379 | debug_cond(DEBUG_IN_EP, |
380 | "\tEP%d-IN : DIEPINT = 0x%x\n", | |
381 | ep_num, ep_intr_status); | |
38517a78 ŁM |
382 | |
383 | /* Interrupt Clear */ | |
384 | writel(ep_intr_status, ®->in_endp[ep_num].diepint); | |
385 | ||
386 | if (ep_intr_status & TRANSFER_DONE) { | |
387 | complete_tx(dev, ep_num); | |
388 | ||
389 | if (ep_num == 0) { | |
390 | if (dev->ep0state == | |
391 | WAIT_FOR_IN_COMPLETE) | |
392 | dev->ep0state = WAIT_FOR_SETUP; | |
393 | ||
394 | if (dev->ep0state == WAIT_FOR_SETUP) | |
f52dd802 | 395 | dwc2_udc_pre_setup(); |
38517a78 ŁM |
396 | |
397 | /* continue transfer after | |
398 | set_clear_halt for DMA mode */ | |
399 | if (clear_feature_flag == 1) { | |
f52dd802 | 400 | dwc2_udc_check_tx_queue(dev, |
38517a78 ŁM |
401 | clear_feature_num); |
402 | clear_feature_flag = 0; | |
403 | } | |
404 | } | |
405 | } | |
406 | } | |
407 | ep_num++; | |
408 | ep_intr >>= 1; | |
409 | } | |
410 | } | |
411 | ||
b4d5cf0b | 412 | static void process_ep_out_intr(struct dwc2_udc *dev) |
38517a78 ŁM |
413 | { |
414 | u32 ep_intr, ep_intr_status; | |
415 | u8 ep_num = 0; | |
416 | ||
417 | ep_intr = readl(®->daint); | |
f3b05ca5 ŁM |
418 | debug_cond(DEBUG_OUT_EP != 0, |
419 | "*** %s: EP OUT interrupt : DAINT = 0x%x\n", | |
420 | __func__, ep_intr); | |
38517a78 ŁM |
421 | |
422 | ep_intr = (ep_intr >> DAINT_OUT_BIT) & DAINT_MASK; | |
423 | ||
424 | while (ep_intr) { | |
425 | if (ep_intr & 0x1) { | |
426 | ep_intr_status = readl(®->out_endp[ep_num].doepint); | |
f3b05ca5 ŁM |
427 | debug_cond(DEBUG_OUT_EP != 0, |
428 | "\tEP%d-OUT : DOEPINT = 0x%x\n", | |
429 | ep_num, ep_intr_status); | |
38517a78 ŁM |
430 | |
431 | /* Interrupt Clear */ | |
432 | writel(ep_intr_status, ®->out_endp[ep_num].doepint); | |
433 | ||
434 | if (ep_num == 0) { | |
435 | if (ep_intr_status & TRANSFER_DONE) { | |
436 | if (dev->ep0state != | |
437 | WAIT_FOR_OUT_COMPLETE) | |
438 | complete_rx(dev, ep_num); | |
439 | else { | |
440 | dev->ep0state = WAIT_FOR_SETUP; | |
f52dd802 | 441 | dwc2_udc_pre_setup(); |
38517a78 ŁM |
442 | } |
443 | } | |
444 | ||
445 | if (ep_intr_status & | |
446 | CTRL_OUT_EP_SETUP_PHASE_DONE) { | |
f3b05ca5 ŁM |
447 | debug_cond(DEBUG_OUT_EP != 0, |
448 | "SETUP packet arrived\n"); | |
155e740f | 449 | dwc2_handle_ep0(dev); |
38517a78 ŁM |
450 | } |
451 | } else { | |
452 | if (ep_intr_status & TRANSFER_DONE) | |
453 | complete_rx(dev, ep_num); | |
454 | } | |
455 | } | |
456 | ep_num++; | |
457 | ep_intr >>= 1; | |
458 | } | |
459 | } | |
460 | ||
461 | /* | |
462 | * usb client interrupt handler. | |
463 | */ | |
f52dd802 | 464 | static int dwc2_udc_irq(int irq, void *_dev) |
38517a78 | 465 | { |
b4d5cf0b | 466 | struct dwc2_udc *dev = _dev; |
38517a78 ŁM |
467 | u32 intr_status; |
468 | u32 usb_status, gintmsk; | |
06fa91cd | 469 | unsigned long flags = 0; |
38517a78 ŁM |
470 | |
471 | spin_lock_irqsave(&dev->lock, flags); | |
472 | ||
473 | intr_status = readl(®->gintsts); | |
474 | gintmsk = readl(®->gintmsk); | |
475 | ||
ea2d9159 AG |
476 | debug_cond(DEBUG_ISR, |
477 | "\n*** %s : GINTSTS=0x%x(on state %s), GINTMSK : 0x%x," | |
38517a78 ŁM |
478 | "DAINT : 0x%x, DAINTMSK : 0x%x\n", |
479 | __func__, intr_status, state_names[dev->ep0state], gintmsk, | |
480 | readl(®->daint), readl(®->daintmsk)); | |
481 | ||
482 | if (!intr_status) { | |
483 | spin_unlock_irqrestore(&dev->lock, flags); | |
484 | return IRQ_HANDLED; | |
485 | } | |
486 | ||
487 | if (intr_status & INT_ENUMDONE) { | |
ea2d9159 | 488 | debug_cond(DEBUG_ISR, "\tSpeed Detection interrupt\n"); |
38517a78 ŁM |
489 | |
490 | writel(INT_ENUMDONE, ®->gintsts); | |
491 | usb_status = (readl(®->dsts) & 0x6); | |
492 | ||
493 | if (usb_status & (USB_FULL_30_60MHZ | USB_FULL_48MHZ)) { | |
f3b05ca5 ŁM |
494 | debug_cond(DEBUG_ISR, |
495 | "\t\tFull Speed Detection\n"); | |
38517a78 ŁM |
496 | set_max_pktsize(dev, USB_SPEED_FULL); |
497 | ||
498 | } else { | |
ea2d9159 AG |
499 | debug_cond(DEBUG_ISR, |
500 | "\t\tHigh Speed Detection : 0x%x\n", | |
501 | usb_status); | |
38517a78 ŁM |
502 | set_max_pktsize(dev, USB_SPEED_HIGH); |
503 | } | |
504 | } | |
505 | ||
506 | if (intr_status & INT_EARLY_SUSPEND) { | |
ea2d9159 | 507 | debug_cond(DEBUG_ISR, "\tEarly suspend interrupt\n"); |
38517a78 ŁM |
508 | writel(INT_EARLY_SUSPEND, ®->gintsts); |
509 | } | |
510 | ||
511 | if (intr_status & INT_SUSPEND) { | |
512 | usb_status = readl(®->dsts); | |
ea2d9159 AG |
513 | debug_cond(DEBUG_ISR, |
514 | "\tSuspend interrupt :(DSTS):0x%x\n", usb_status); | |
38517a78 ŁM |
515 | writel(INT_SUSPEND, ®->gintsts); |
516 | ||
517 | if (dev->gadget.speed != USB_SPEED_UNKNOWN | |
518 | && dev->driver) { | |
519 | if (dev->driver->suspend) | |
520 | dev->driver->suspend(&dev->gadget); | |
521 | ||
522 | /* HACK to let gadget detect disconnected state */ | |
523 | if (dev->driver->disconnect) { | |
524 | spin_unlock_irqrestore(&dev->lock, flags); | |
525 | dev->driver->disconnect(&dev->gadget); | |
526 | spin_lock_irqsave(&dev->lock, flags); | |
527 | } | |
528 | } | |
529 | } | |
530 | ||
531 | if (intr_status & INT_RESUME) { | |
ea2d9159 | 532 | debug_cond(DEBUG_ISR, "\tResume interrupt\n"); |
38517a78 ŁM |
533 | writel(INT_RESUME, ®->gintsts); |
534 | ||
535 | if (dev->gadget.speed != USB_SPEED_UNKNOWN | |
536 | && dev->driver | |
537 | && dev->driver->resume) { | |
538 | ||
539 | dev->driver->resume(&dev->gadget); | |
540 | } | |
541 | } | |
542 | ||
543 | if (intr_status & INT_RESET) { | |
544 | usb_status = readl(®->gotgctl); | |
ea2d9159 AG |
545 | debug_cond(DEBUG_ISR, |
546 | "\tReset interrupt - (GOTGCTL):0x%x\n", usb_status); | |
38517a78 ŁM |
547 | writel(INT_RESET, ®->gintsts); |
548 | ||
549 | if ((usb_status & 0xc0000) == (0x3 << 18)) { | |
550 | if (reset_available) { | |
ea2d9159 AG |
551 | debug_cond(DEBUG_ISR, |
552 | "\t\tOTG core got reset (%d)!!\n", | |
553 | reset_available); | |
481a11c5 | 554 | reconfig_usbd(dev); |
38517a78 ŁM |
555 | dev->ep0state = WAIT_FOR_SETUP; |
556 | reset_available = 0; | |
f52dd802 | 557 | dwc2_udc_pre_setup(); |
38517a78 ŁM |
558 | } else |
559 | reset_available = 1; | |
560 | ||
561 | } else { | |
562 | reset_available = 1; | |
f3b05ca5 ŁM |
563 | debug_cond(DEBUG_ISR, |
564 | "\t\tRESET handling skipped\n"); | |
38517a78 ŁM |
565 | } |
566 | } | |
567 | ||
568 | if (intr_status & INT_IN_EP) | |
569 | process_ep_in_intr(dev); | |
570 | ||
571 | if (intr_status & INT_OUT_EP) | |
572 | process_ep_out_intr(dev); | |
573 | ||
574 | spin_unlock_irqrestore(&dev->lock, flags); | |
575 | ||
576 | return IRQ_HANDLED; | |
577 | } | |
578 | ||
579 | /** Queue one request | |
580 | * Kickstart transfer if needed | |
581 | */ | |
155e740f | 582 | static int dwc2_queue(struct usb_ep *_ep, struct usb_request *_req, |
38517a78 ŁM |
583 | gfp_t gfp_flags) |
584 | { | |
c056c52b | 585 | struct dwc2_request *req; |
627d9298 | 586 | struct dwc2_ep *ep; |
b4d5cf0b | 587 | struct dwc2_udc *dev; |
06fa91cd | 588 | unsigned long flags = 0; |
38517a78 ŁM |
589 | u32 ep_num, gintsts; |
590 | ||
c056c52b | 591 | req = container_of(_req, struct dwc2_request, req); |
38517a78 ŁM |
592 | if (unlikely(!_req || !_req->complete || !_req->buf |
593 | || !list_empty(&req->queue))) { | |
594 | ||
ea2d9159 | 595 | debug("%s: bad params\n", __func__); |
38517a78 ŁM |
596 | return -EINVAL; |
597 | } | |
598 | ||
627d9298 | 599 | ep = container_of(_ep, struct dwc2_ep, ep); |
38517a78 ŁM |
600 | |
601 | if (unlikely(!_ep || (!ep->desc && ep->ep.name != ep0name))) { | |
602 | ||
ea2d9159 | 603 | debug("%s: bad ep: %s, %d, %p\n", __func__, |
38517a78 ŁM |
604 | ep->ep.name, !ep->desc, _ep); |
605 | return -EINVAL; | |
606 | } | |
607 | ||
608 | ep_num = ep_index(ep); | |
609 | dev = ep->dev; | |
610 | if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) { | |
611 | ||
ea2d9159 | 612 | debug("%s: bogus device state %p\n", __func__, dev->driver); |
38517a78 ŁM |
613 | return -ESHUTDOWN; |
614 | } | |
615 | ||
616 | spin_lock_irqsave(&dev->lock, flags); | |
617 | ||
618 | _req->status = -EINPROGRESS; | |
619 | _req->actual = 0; | |
620 | ||
621 | /* kickstart this i/o queue? */ | |
ea2d9159 | 622 | debug("\n*** %s: %s-%s req = %p, len = %d, buf = %p" |
38517a78 ŁM |
623 | "Q empty = %d, stopped = %d\n", |
624 | __func__, _ep->name, ep_is_in(ep) ? "in" : "out", | |
625 | _req, _req->length, _req->buf, | |
626 | list_empty(&ep->queue), ep->stopped); | |
627 | ||
f3b05ca5 | 628 | #ifdef DEBUG |
38517a78 ŁM |
629 | { |
630 | int i, len = _req->length; | |
631 | ||
632 | printf("pkt = "); | |
633 | if (len > 64) | |
634 | len = 64; | |
635 | for (i = 0; i < len; i++) { | |
636 | printf("%02x", ((u8 *)_req->buf)[i]); | |
637 | if ((i & 7) == 7) | |
638 | printf(" "); | |
639 | } | |
640 | printf("\n"); | |
641 | } | |
642 | #endif | |
643 | ||
644 | if (list_empty(&ep->queue) && !ep->stopped) { | |
645 | ||
646 | if (ep_num == 0) { | |
647 | /* EP0 */ | |
648 | list_add_tail(&req->queue, &ep->queue); | |
28b97748 | 649 | dwc2_ep0_kick(dev, ep); |
38517a78 ŁM |
650 | req = 0; |
651 | ||
652 | } else if (ep_is_in(ep)) { | |
653 | gintsts = readl(®->gintsts); | |
ea2d9159 | 654 | debug_cond(DEBUG_IN_EP, |
507e677b | 655 | "%s: ep_is_in, DWC2_UDC_OTG_GINTSTS=0x%x\n", |
f3b05ca5 | 656 | __func__, gintsts); |
38517a78 ŁM |
657 | |
658 | setdma_tx(ep, req); | |
659 | } else { | |
660 | gintsts = readl(®->gintsts); | |
f3b05ca5 | 661 | debug_cond(DEBUG_OUT_EP != 0, |
507e677b | 662 | "%s:ep_is_out, DWC2_UDC_OTG_GINTSTS=0x%x\n", |
f3b05ca5 | 663 | __func__, gintsts); |
38517a78 ŁM |
664 | |
665 | setdma_rx(ep, req); | |
666 | } | |
667 | } | |
668 | ||
669 | /* pio or dma irq handler advances the queue. */ | |
670 | if (likely(req != 0)) | |
671 | list_add_tail(&req->queue, &ep->queue); | |
672 | ||
673 | spin_unlock_irqrestore(&dev->lock, flags); | |
674 | ||
675 | return 0; | |
676 | } | |
677 | ||
678 | /****************************************************************/ | |
679 | /* End Point 0 related functions */ | |
680 | /****************************************************************/ | |
681 | ||
682 | /* return: 0 = still running, 1 = completed, negative = errno */ | |
c056c52b | 683 | static int write_fifo_ep0(struct dwc2_ep *ep, struct dwc2_request *req) |
38517a78 ŁM |
684 | { |
685 | u32 max; | |
686 | unsigned count; | |
687 | int is_last; | |
688 | ||
689 | max = ep_maxpacket(ep); | |
690 | ||
f3b05ca5 | 691 | debug_cond(DEBUG_EP0 != 0, "%s: max = %d\n", __func__, max); |
38517a78 ŁM |
692 | |
693 | count = setdma_tx(ep, req); | |
694 | ||
695 | /* last packet is usually short (or a zlp) */ | |
696 | if (likely(count != max)) | |
697 | is_last = 1; | |
698 | else { | |
699 | if (likely(req->req.length != req->req.actual + count) | |
700 | || req->req.zero) | |
701 | is_last = 0; | |
702 | else | |
703 | is_last = 1; | |
704 | } | |
705 | ||
f3b05ca5 ŁM |
706 | debug_cond(DEBUG_EP0 != 0, |
707 | "%s: wrote %s %d bytes%s %d left %p\n", __func__, | |
708 | ep->ep.name, count, | |
709 | is_last ? "/L" : "", | |
710 | req->req.length - req->req.actual - count, req); | |
38517a78 ŁM |
711 | |
712 | /* requests complete when all IN data is in the FIFO */ | |
713 | if (is_last) { | |
714 | ep->dev->ep0state = WAIT_FOR_SETUP; | |
715 | return 1; | |
716 | } | |
717 | ||
718 | return 0; | |
719 | } | |
720 | ||
155e740f | 721 | static int dwc2_fifo_read(struct dwc2_ep *ep, u32 *cp, int max) |
38517a78 | 722 | { |
e0059eae ŁM |
723 | invalidate_dcache_range((unsigned long)cp, (unsigned long)cp + |
724 | ROUND(max, CONFIG_SYS_CACHELINE_SIZE)); | |
38517a78 | 725 | |
f3b05ca5 | 726 | debug_cond(DEBUG_EP0 != 0, |
e0059eae ŁM |
727 | "%s: bytes=%d, ep_index=%d 0x%p\n", __func__, |
728 | max, ep_index(ep), cp); | |
38517a78 | 729 | |
e0059eae | 730 | return max; |
38517a78 ŁM |
731 | } |
732 | ||
733 | /** | |
734 | * udc_set_address - set the USB address for this device | |
735 | * @address: | |
736 | * | |
737 | * Called from control endpoint function | |
738 | * after it decodes a set address setup packet. | |
739 | */ | |
b4d5cf0b | 740 | static void udc_set_address(struct dwc2_udc *dev, unsigned char address) |
38517a78 ŁM |
741 | { |
742 | u32 ctrl = readl(®->dcfg); | |
743 | writel(DEVICE_ADDRESS(address) | ctrl, ®->dcfg); | |
744 | ||
f52dd802 | 745 | dwc2_udc_ep0_zlp(dev); |
38517a78 | 746 | |
f3b05ca5 ŁM |
747 | debug_cond(DEBUG_EP0 != 0, |
748 | "%s: USB OTG 2.0 Device address=%d, DCFG=0x%x\n", | |
749 | __func__, address, readl(®->dcfg)); | |
38517a78 ŁM |
750 | |
751 | dev->usb_address = address; | |
752 | } | |
753 | ||
f52dd802 | 754 | static inline void dwc2_udc_ep0_set_stall(struct dwc2_ep *ep) |
38517a78 | 755 | { |
b4d5cf0b | 756 | struct dwc2_udc *dev; |
38517a78 ŁM |
757 | u32 ep_ctrl = 0; |
758 | ||
759 | dev = ep->dev; | |
760 | ep_ctrl = readl(®->in_endp[EP0_CON].diepctl); | |
761 | ||
762 | /* set the disable and stall bits */ | |
763 | if (ep_ctrl & DEPCTL_EPENA) | |
764 | ep_ctrl |= DEPCTL_EPDIS; | |
765 | ||
766 | ep_ctrl |= DEPCTL_STALL; | |
767 | ||
768 | writel(ep_ctrl, ®->in_endp[EP0_CON].diepctl); | |
769 | ||
f3b05ca5 ŁM |
770 | debug_cond(DEBUG_EP0 != 0, |
771 | "%s: set ep%d stall, DIEPCTL0 = 0x%p\n", | |
772 | __func__, ep_index(ep), ®->in_endp[EP0_CON].diepctl); | |
38517a78 ŁM |
773 | /* |
774 | * The application can only set this bit, and the core clears it, | |
775 | * when a SETUP token is received for this endpoint | |
776 | */ | |
777 | dev->ep0state = WAIT_FOR_SETUP; | |
778 | ||
f52dd802 | 779 | dwc2_udc_pre_setup(); |
38517a78 ŁM |
780 | } |
781 | ||
28b97748 | 782 | static void dwc2_ep0_read(struct dwc2_udc *dev) |
38517a78 | 783 | { |
c056c52b | 784 | struct dwc2_request *req; |
627d9298 | 785 | struct dwc2_ep *ep = &dev->ep[0]; |
38517a78 ŁM |
786 | |
787 | if (!list_empty(&ep->queue)) { | |
c056c52b | 788 | req = list_entry(ep->queue.next, struct dwc2_request, queue); |
38517a78 ŁM |
789 | |
790 | } else { | |
ea2d9159 | 791 | debug("%s: ---> BUG\n", __func__); |
38517a78 ŁM |
792 | BUG(); |
793 | return; | |
794 | } | |
795 | ||
f3b05ca5 ŁM |
796 | debug_cond(DEBUG_EP0 != 0, |
797 | "%s: req = %p, req.length = 0x%x, req.actual = 0x%x\n", | |
798 | __func__, req, req->req.length, req->req.actual); | |
38517a78 ŁM |
799 | |
800 | if (req->req.length == 0) { | |
801 | /* zlp for Set_configuration, Set_interface, | |
802 | * or Bulk-Only mass storge reset */ | |
803 | ||
804 | ep->len = 0; | |
f52dd802 | 805 | dwc2_udc_ep0_zlp(dev); |
38517a78 | 806 | |
f3b05ca5 ŁM |
807 | debug_cond(DEBUG_EP0 != 0, |
808 | "%s: req.length = 0, bRequest = %d\n", | |
809 | __func__, usb_ctrl->bRequest); | |
38517a78 ŁM |
810 | return; |
811 | } | |
812 | ||
ea2d9159 | 813 | setdma_rx(ep, req); |
38517a78 ŁM |
814 | } |
815 | ||
816 | /* | |
817 | * DATA_STATE_XMIT | |
818 | */ | |
28b97748 | 819 | static int dwc2_ep0_write(struct dwc2_udc *dev) |
38517a78 | 820 | { |
c056c52b | 821 | struct dwc2_request *req; |
627d9298 | 822 | struct dwc2_ep *ep = &dev->ep[0]; |
38517a78 ŁM |
823 | int ret, need_zlp = 0; |
824 | ||
825 | if (list_empty(&ep->queue)) | |
826 | req = 0; | |
827 | else | |
c056c52b | 828 | req = list_entry(ep->queue.next, struct dwc2_request, queue); |
38517a78 ŁM |
829 | |
830 | if (!req) { | |
f3b05ca5 | 831 | debug_cond(DEBUG_EP0 != 0, "%s: NULL REQ\n", __func__); |
38517a78 ŁM |
832 | return 0; |
833 | } | |
834 | ||
f3b05ca5 ŁM |
835 | debug_cond(DEBUG_EP0 != 0, |
836 | "%s: req = %p, req.length = 0x%x, req.actual = 0x%x\n", | |
837 | __func__, req, req->req.length, req->req.actual); | |
38517a78 ŁM |
838 | |
839 | if (req->req.length - req->req.actual == ep0_fifo_size) { | |
840 | /* Next write will end with the packet size, */ | |
841 | /* so we need Zero-length-packet */ | |
842 | need_zlp = 1; | |
843 | } | |
844 | ||
845 | ret = write_fifo_ep0(ep, req); | |
846 | ||
847 | if ((ret == 1) && !need_zlp) { | |
848 | /* Last packet */ | |
849 | dev->ep0state = WAIT_FOR_COMPLETE; | |
f3b05ca5 ŁM |
850 | debug_cond(DEBUG_EP0 != 0, |
851 | "%s: finished, waiting for status\n", __func__); | |
38517a78 ŁM |
852 | |
853 | } else { | |
854 | dev->ep0state = DATA_STATE_XMIT; | |
f3b05ca5 ŁM |
855 | debug_cond(DEBUG_EP0 != 0, |
856 | "%s: not finished\n", __func__); | |
38517a78 ŁM |
857 | } |
858 | ||
859 | return 1; | |
860 | } | |
861 | ||
f52dd802 | 862 | static int dwc2_udc_get_status(struct dwc2_udc *dev, |
38517a78 ŁM |
863 | struct usb_ctrlrequest *crq) |
864 | { | |
865 | u8 ep_num = crq->wIndex & 0x7F; | |
e0059eae | 866 | u16 g_status = 0; |
38517a78 | 867 | u32 ep_ctrl; |
38517a78 | 868 | |
f3b05ca5 ŁM |
869 | debug_cond(DEBUG_SETUP != 0, |
870 | "%s: *** USB_REQ_GET_STATUS\n", __func__); | |
38517a78 ŁM |
871 | printf("crq->brequest:0x%x\n", crq->bRequestType & USB_RECIP_MASK); |
872 | switch (crq->bRequestType & USB_RECIP_MASK) { | |
873 | case USB_RECIP_INTERFACE: | |
874 | g_status = 0; | |
f3b05ca5 ŁM |
875 | debug_cond(DEBUG_SETUP != 0, |
876 | "\tGET_STATUS:USB_RECIP_INTERFACE, g_stauts = %d\n", | |
877 | g_status); | |
38517a78 ŁM |
878 | break; |
879 | ||
880 | case USB_RECIP_DEVICE: | |
881 | g_status = 0x1; /* Self powered */ | |
f3b05ca5 ŁM |
882 | debug_cond(DEBUG_SETUP != 0, |
883 | "\tGET_STATUS: USB_RECIP_DEVICE, g_stauts = %d\n", | |
884 | g_status); | |
38517a78 ŁM |
885 | break; |
886 | ||
887 | case USB_RECIP_ENDPOINT: | |
888 | if (crq->wLength > 2) { | |
f3b05ca5 ŁM |
889 | debug_cond(DEBUG_SETUP != 0, |
890 | "\tGET_STATUS:Not support EP or wLength\n"); | |
38517a78 ŁM |
891 | return 1; |
892 | } | |
893 | ||
894 | g_status = dev->ep[ep_num].stopped; | |
f3b05ca5 ŁM |
895 | debug_cond(DEBUG_SETUP != 0, |
896 | "\tGET_STATUS: USB_RECIP_ENDPOINT, g_stauts = %d\n", | |
897 | g_status); | |
38517a78 ŁM |
898 | |
899 | break; | |
900 | ||
901 | default: | |
902 | return 1; | |
903 | } | |
904 | ||
e0059eae | 905 | memcpy(usb_ctrl, &g_status, sizeof(g_status)); |
38517a78 | 906 | |
e0059eae ŁM |
907 | flush_dcache_range((unsigned long) usb_ctrl, |
908 | (unsigned long) usb_ctrl + | |
909 | ROUND(sizeof(g_status), CONFIG_SYS_CACHELINE_SIZE)); | |
38517a78 | 910 | |
e0059eae | 911 | writel(usb_ctrl_dma_addr, ®->in_endp[EP0_CON].diepdma); |
38517a78 ŁM |
912 | writel(DIEPT_SIZ_PKT_CNT(1) | DIEPT_SIZ_XFER_SIZE(2), |
913 | ®->in_endp[EP0_CON].dieptsiz); | |
914 | ||
915 | ep_ctrl = readl(®->in_endp[EP0_CON].diepctl); | |
916 | writel(ep_ctrl|DEPCTL_EPENA|DEPCTL_CNAK, | |
917 | ®->in_endp[EP0_CON].diepctl); | |
918 | dev->ep0state = WAIT_FOR_NULL_COMPLETE; | |
919 | ||
920 | return 0; | |
921 | } | |
922 | ||
f52dd802 | 923 | static void dwc2_udc_set_nak(struct dwc2_ep *ep) |
38517a78 ŁM |
924 | { |
925 | u8 ep_num; | |
926 | u32 ep_ctrl = 0; | |
927 | ||
928 | ep_num = ep_index(ep); | |
ea2d9159 | 929 | debug("%s: ep_num = %d, ep_type = %d\n", __func__, ep_num, ep->ep_type); |
38517a78 ŁM |
930 | |
931 | if (ep_is_in(ep)) { | |
932 | ep_ctrl = readl(®->in_endp[ep_num].diepctl); | |
933 | ep_ctrl |= DEPCTL_SNAK; | |
934 | writel(ep_ctrl, ®->in_endp[ep_num].diepctl); | |
ea2d9159 | 935 | debug("%s: set NAK, DIEPCTL%d = 0x%x\n", |
38517a78 ŁM |
936 | __func__, ep_num, readl(®->in_endp[ep_num].diepctl)); |
937 | } else { | |
938 | ep_ctrl = readl(®->out_endp[ep_num].doepctl); | |
939 | ep_ctrl |= DEPCTL_SNAK; | |
940 | writel(ep_ctrl, ®->out_endp[ep_num].doepctl); | |
ea2d9159 | 941 | debug("%s: set NAK, DOEPCTL%d = 0x%x\n", |
38517a78 ŁM |
942 | __func__, ep_num, readl(®->out_endp[ep_num].doepctl)); |
943 | } | |
944 | ||
945 | return; | |
946 | } | |
947 | ||
948 | ||
f52dd802 | 949 | static void dwc2_udc_ep_set_stall(struct dwc2_ep *ep) |
38517a78 ŁM |
950 | { |
951 | u8 ep_num; | |
952 | u32 ep_ctrl = 0; | |
953 | ||
954 | ep_num = ep_index(ep); | |
ea2d9159 | 955 | debug("%s: ep_num = %d, ep_type = %d\n", __func__, ep_num, ep->ep_type); |
38517a78 ŁM |
956 | |
957 | if (ep_is_in(ep)) { | |
958 | ep_ctrl = readl(®->in_endp[ep_num].diepctl); | |
959 | ||
960 | /* set the disable and stall bits */ | |
961 | if (ep_ctrl & DEPCTL_EPENA) | |
962 | ep_ctrl |= DEPCTL_EPDIS; | |
963 | ||
964 | ep_ctrl |= DEPCTL_STALL; | |
965 | ||
966 | writel(ep_ctrl, ®->in_endp[ep_num].diepctl); | |
ea2d9159 | 967 | debug("%s: set stall, DIEPCTL%d = 0x%x\n", |
38517a78 ŁM |
968 | __func__, ep_num, readl(®->in_endp[ep_num].diepctl)); |
969 | ||
970 | } else { | |
971 | ep_ctrl = readl(®->out_endp[ep_num].doepctl); | |
972 | ||
973 | /* set the stall bit */ | |
974 | ep_ctrl |= DEPCTL_STALL; | |
975 | ||
976 | writel(ep_ctrl, ®->out_endp[ep_num].doepctl); | |
ea2d9159 | 977 | debug("%s: set stall, DOEPCTL%d = 0x%x\n", |
38517a78 ŁM |
978 | __func__, ep_num, readl(®->out_endp[ep_num].doepctl)); |
979 | } | |
980 | ||
981 | return; | |
982 | } | |
983 | ||
f52dd802 | 984 | static void dwc2_udc_ep_clear_stall(struct dwc2_ep *ep) |
38517a78 ŁM |
985 | { |
986 | u8 ep_num; | |
987 | u32 ep_ctrl = 0; | |
988 | ||
989 | ep_num = ep_index(ep); | |
ea2d9159 | 990 | debug("%s: ep_num = %d, ep_type = %d\n", __func__, ep_num, ep->ep_type); |
38517a78 ŁM |
991 | |
992 | if (ep_is_in(ep)) { | |
993 | ep_ctrl = readl(®->in_endp[ep_num].diepctl); | |
994 | ||
995 | /* clear stall bit */ | |
996 | ep_ctrl &= ~DEPCTL_STALL; | |
997 | ||
998 | /* | |
999 | * USB Spec 9.4.5: For endpoints using data toggle, regardless | |
1000 | * of whether an endpoint has the Halt feature set, a | |
1001 | * ClearFeature(ENDPOINT_HALT) request always results in the | |
1002 | * data toggle being reinitialized to DATA0. | |
1003 | */ | |
1004 | if (ep->bmAttributes == USB_ENDPOINT_XFER_INT | |
1005 | || ep->bmAttributes == USB_ENDPOINT_XFER_BULK) { | |
1006 | ep_ctrl |= DEPCTL_SETD0PID; /* DATA0 */ | |
1007 | } | |
1008 | ||
1009 | writel(ep_ctrl, ®->in_endp[ep_num].diepctl); | |
ea2d9159 | 1010 | debug("%s: cleared stall, DIEPCTL%d = 0x%x\n", |
38517a78 ŁM |
1011 | __func__, ep_num, readl(®->in_endp[ep_num].diepctl)); |
1012 | ||
1013 | } else { | |
1014 | ep_ctrl = readl(®->out_endp[ep_num].doepctl); | |
1015 | ||
1016 | /* clear stall bit */ | |
1017 | ep_ctrl &= ~DEPCTL_STALL; | |
1018 | ||
1019 | if (ep->bmAttributes == USB_ENDPOINT_XFER_INT | |
1020 | || ep->bmAttributes == USB_ENDPOINT_XFER_BULK) { | |
1021 | ep_ctrl |= DEPCTL_SETD0PID; /* DATA0 */ | |
1022 | } | |
1023 | ||
1024 | writel(ep_ctrl, ®->out_endp[ep_num].doepctl); | |
ea2d9159 | 1025 | debug("%s: cleared stall, DOEPCTL%d = 0x%x\n", |
38517a78 ŁM |
1026 | __func__, ep_num, readl(®->out_endp[ep_num].doepctl)); |
1027 | } | |
1028 | ||
1029 | return; | |
1030 | } | |
1031 | ||
f52dd802 | 1032 | static int dwc2_udc_set_halt(struct usb_ep *_ep, int value) |
38517a78 | 1033 | { |
627d9298 | 1034 | struct dwc2_ep *ep; |
b4d5cf0b | 1035 | struct dwc2_udc *dev; |
06fa91cd | 1036 | unsigned long flags = 0; |
38517a78 ŁM |
1037 | u8 ep_num; |
1038 | ||
627d9298 | 1039 | ep = container_of(_ep, struct dwc2_ep, ep); |
38517a78 ŁM |
1040 | ep_num = ep_index(ep); |
1041 | ||
1042 | if (unlikely(!_ep || !ep->desc || ep_num == EP0_CON || | |
1043 | ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC)) { | |
ea2d9159 | 1044 | debug("%s: %s bad ep or descriptor\n", __func__, ep->ep.name); |
38517a78 ŁM |
1045 | return -EINVAL; |
1046 | } | |
1047 | ||
1048 | /* Attempt to halt IN ep will fail if any transfer requests | |
1049 | * are still queue */ | |
1050 | if (value && ep_is_in(ep) && !list_empty(&ep->queue)) { | |
ea2d9159 | 1051 | debug("%s: %s queue not empty, req = %p\n", |
38517a78 | 1052 | __func__, ep->ep.name, |
c056c52b | 1053 | list_entry(ep->queue.next, struct dwc2_request, queue)); |
38517a78 ŁM |
1054 | |
1055 | return -EAGAIN; | |
1056 | } | |
1057 | ||
1058 | dev = ep->dev; | |
ea2d9159 | 1059 | debug("%s: ep_num = %d, value = %d\n", __func__, ep_num, value); |
38517a78 ŁM |
1060 | |
1061 | spin_lock_irqsave(&dev->lock, flags); | |
1062 | ||
1063 | if (value == 0) { | |
1064 | ep->stopped = 0; | |
f52dd802 | 1065 | dwc2_udc_ep_clear_stall(ep); |
38517a78 ŁM |
1066 | } else { |
1067 | if (ep_num == 0) | |
1068 | dev->ep0state = WAIT_FOR_SETUP; | |
1069 | ||
1070 | ep->stopped = 1; | |
f52dd802 | 1071 | dwc2_udc_ep_set_stall(ep); |
38517a78 ŁM |
1072 | } |
1073 | ||
1074 | spin_unlock_irqrestore(&dev->lock, flags); | |
1075 | ||
1076 | return 0; | |
1077 | } | |
1078 | ||
f52dd802 | 1079 | static void dwc2_udc_ep_activate(struct dwc2_ep *ep) |
38517a78 ŁM |
1080 | { |
1081 | u8 ep_num; | |
1082 | u32 ep_ctrl = 0, daintmsk = 0; | |
1083 | ||
1084 | ep_num = ep_index(ep); | |
1085 | ||
1086 | /* Read DEPCTLn register */ | |
1087 | if (ep_is_in(ep)) { | |
1088 | ep_ctrl = readl(®->in_endp[ep_num].diepctl); | |
1089 | daintmsk = 1 << ep_num; | |
1090 | } else { | |
1091 | ep_ctrl = readl(®->out_endp[ep_num].doepctl); | |
1092 | daintmsk = (1 << ep_num) << DAINT_OUT_BIT; | |
1093 | } | |
1094 | ||
ea2d9159 | 1095 | debug("%s: EPCTRL%d = 0x%x, ep_is_in = %d\n", |
38517a78 ŁM |
1096 | __func__, ep_num, ep_ctrl, ep_is_in(ep)); |
1097 | ||
1098 | /* If the EP is already active don't change the EP Control | |
1099 | * register. */ | |
1100 | if (!(ep_ctrl & DEPCTL_USBACTEP)) { | |
1101 | ep_ctrl = (ep_ctrl & ~DEPCTL_TYPE_MASK) | | |
1102 | (ep->bmAttributes << DEPCTL_TYPE_BIT); | |
1103 | ep_ctrl = (ep_ctrl & ~DEPCTL_MPS_MASK) | | |
1104 | (ep->ep.maxpacket << DEPCTL_MPS_BIT); | |
1105 | ep_ctrl |= (DEPCTL_SETD0PID | DEPCTL_USBACTEP | DEPCTL_SNAK); | |
1106 | ||
1107 | if (ep_is_in(ep)) { | |
1108 | writel(ep_ctrl, ®->in_endp[ep_num].diepctl); | |
ea2d9159 | 1109 | debug("%s: USB Ative EP%d, DIEPCTRL%d = 0x%x\n", |
38517a78 ŁM |
1110 | __func__, ep_num, ep_num, |
1111 | readl(®->in_endp[ep_num].diepctl)); | |
1112 | } else { | |
1113 | writel(ep_ctrl, ®->out_endp[ep_num].doepctl); | |
ea2d9159 | 1114 | debug("%s: USB Ative EP%d, DOEPCTRL%d = 0x%x\n", |
38517a78 ŁM |
1115 | __func__, ep_num, ep_num, |
1116 | readl(®->out_endp[ep_num].doepctl)); | |
1117 | } | |
1118 | } | |
1119 | ||
1120 | /* Unmask EP Interrtupt */ | |
1121 | writel(readl(®->daintmsk)|daintmsk, ®->daintmsk); | |
ea2d9159 | 1122 | debug("%s: DAINTMSK = 0x%x\n", __func__, readl(®->daintmsk)); |
38517a78 ŁM |
1123 | |
1124 | } | |
1125 | ||
f52dd802 | 1126 | static int dwc2_udc_clear_feature(struct usb_ep *_ep) |
38517a78 | 1127 | { |
b4d5cf0b | 1128 | struct dwc2_udc *dev; |
627d9298 | 1129 | struct dwc2_ep *ep; |
38517a78 ŁM |
1130 | u8 ep_num; |
1131 | ||
627d9298 | 1132 | ep = container_of(_ep, struct dwc2_ep, ep); |
38517a78 ŁM |
1133 | ep_num = ep_index(ep); |
1134 | ||
1135 | dev = ep->dev; | |
f3b05ca5 ŁM |
1136 | debug_cond(DEBUG_SETUP != 0, |
1137 | "%s: ep_num = %d, is_in = %d, clear_feature_flag = %d\n", | |
1138 | __func__, ep_num, ep_is_in(ep), clear_feature_flag); | |
38517a78 ŁM |
1139 | |
1140 | if (usb_ctrl->wLength != 0) { | |
f3b05ca5 ŁM |
1141 | debug_cond(DEBUG_SETUP != 0, |
1142 | "\tCLEAR_FEATURE: wLength is not zero.....\n"); | |
38517a78 ŁM |
1143 | return 1; |
1144 | } | |
1145 | ||
1146 | switch (usb_ctrl->bRequestType & USB_RECIP_MASK) { | |
1147 | case USB_RECIP_DEVICE: | |
1148 | switch (usb_ctrl->wValue) { | |
1149 | case USB_DEVICE_REMOTE_WAKEUP: | |
f3b05ca5 ŁM |
1150 | debug_cond(DEBUG_SETUP != 0, |
1151 | "\tOFF:USB_DEVICE_REMOTE_WAKEUP\n"); | |
38517a78 ŁM |
1152 | break; |
1153 | ||
1154 | case USB_DEVICE_TEST_MODE: | |
f3b05ca5 ŁM |
1155 | debug_cond(DEBUG_SETUP != 0, |
1156 | "\tCLEAR_FEATURE: USB_DEVICE_TEST_MODE\n"); | |
38517a78 ŁM |
1157 | /** @todo Add CLEAR_FEATURE for TEST modes. */ |
1158 | break; | |
1159 | } | |
1160 | ||
f52dd802 | 1161 | dwc2_udc_ep0_zlp(dev); |
38517a78 ŁM |
1162 | break; |
1163 | ||
1164 | case USB_RECIP_ENDPOINT: | |
f3b05ca5 ŁM |
1165 | debug_cond(DEBUG_SETUP != 0, |
1166 | "\tCLEAR_FEATURE:USB_RECIP_ENDPOINT, wValue = %d\n", | |
1167 | usb_ctrl->wValue); | |
38517a78 ŁM |
1168 | |
1169 | if (usb_ctrl->wValue == USB_ENDPOINT_HALT) { | |
1170 | if (ep_num == 0) { | |
f52dd802 | 1171 | dwc2_udc_ep0_set_stall(ep); |
38517a78 ŁM |
1172 | return 0; |
1173 | } | |
1174 | ||
f52dd802 | 1175 | dwc2_udc_ep0_zlp(dev); |
38517a78 | 1176 | |
f52dd802 MV |
1177 | dwc2_udc_ep_clear_stall(ep); |
1178 | dwc2_udc_ep_activate(ep); | |
38517a78 ŁM |
1179 | ep->stopped = 0; |
1180 | ||
1181 | clear_feature_num = ep_num; | |
1182 | clear_feature_flag = 1; | |
1183 | } | |
1184 | break; | |
1185 | } | |
1186 | ||
1187 | return 0; | |
1188 | } | |
1189 | ||
f52dd802 | 1190 | static int dwc2_udc_set_feature(struct usb_ep *_ep) |
38517a78 | 1191 | { |
b4d5cf0b | 1192 | struct dwc2_udc *dev; |
627d9298 | 1193 | struct dwc2_ep *ep; |
38517a78 ŁM |
1194 | u8 ep_num; |
1195 | ||
627d9298 | 1196 | ep = container_of(_ep, struct dwc2_ep, ep); |
38517a78 ŁM |
1197 | ep_num = ep_index(ep); |
1198 | dev = ep->dev; | |
1199 | ||
f3b05ca5 ŁM |
1200 | debug_cond(DEBUG_SETUP != 0, |
1201 | "%s: *** USB_REQ_SET_FEATURE , ep_num = %d\n", | |
38517a78 ŁM |
1202 | __func__, ep_num); |
1203 | ||
1204 | if (usb_ctrl->wLength != 0) { | |
f3b05ca5 ŁM |
1205 | debug_cond(DEBUG_SETUP != 0, |
1206 | "\tSET_FEATURE: wLength is not zero.....\n"); | |
38517a78 ŁM |
1207 | return 1; |
1208 | } | |
1209 | ||
1210 | switch (usb_ctrl->bRequestType & USB_RECIP_MASK) { | |
1211 | case USB_RECIP_DEVICE: | |
1212 | switch (usb_ctrl->wValue) { | |
1213 | case USB_DEVICE_REMOTE_WAKEUP: | |
f3b05ca5 ŁM |
1214 | debug_cond(DEBUG_SETUP != 0, |
1215 | "\tSET_FEATURE:USB_DEVICE_REMOTE_WAKEUP\n"); | |
38517a78 ŁM |
1216 | break; |
1217 | case USB_DEVICE_B_HNP_ENABLE: | |
f3b05ca5 ŁM |
1218 | debug_cond(DEBUG_SETUP != 0, |
1219 | "\tSET_FEATURE: USB_DEVICE_B_HNP_ENABLE\n"); | |
38517a78 ŁM |
1220 | break; |
1221 | ||
1222 | case USB_DEVICE_A_HNP_SUPPORT: | |
1223 | /* RH port supports HNP */ | |
f3b05ca5 ŁM |
1224 | debug_cond(DEBUG_SETUP != 0, |
1225 | "\tSET_FEATURE:USB_DEVICE_A_HNP_SUPPORT\n"); | |
38517a78 ŁM |
1226 | break; |
1227 | ||
1228 | case USB_DEVICE_A_ALT_HNP_SUPPORT: | |
1229 | /* other RH port does */ | |
f3b05ca5 ŁM |
1230 | debug_cond(DEBUG_SETUP != 0, |
1231 | "\tSET: USB_DEVICE_A_ALT_HNP_SUPPORT\n"); | |
38517a78 ŁM |
1232 | break; |
1233 | } | |
1234 | ||
f52dd802 | 1235 | dwc2_udc_ep0_zlp(dev); |
38517a78 ŁM |
1236 | return 0; |
1237 | ||
1238 | case USB_RECIP_INTERFACE: | |
f3b05ca5 ŁM |
1239 | debug_cond(DEBUG_SETUP != 0, |
1240 | "\tSET_FEATURE: USB_RECIP_INTERFACE\n"); | |
38517a78 ŁM |
1241 | break; |
1242 | ||
1243 | case USB_RECIP_ENDPOINT: | |
f3b05ca5 ŁM |
1244 | debug_cond(DEBUG_SETUP != 0, |
1245 | "\tSET_FEATURE: USB_RECIP_ENDPOINT\n"); | |
38517a78 ŁM |
1246 | if (usb_ctrl->wValue == USB_ENDPOINT_HALT) { |
1247 | if (ep_num == 0) { | |
f52dd802 | 1248 | dwc2_udc_ep0_set_stall(ep); |
38517a78 ŁM |
1249 | return 0; |
1250 | } | |
1251 | ep->stopped = 1; | |
f52dd802 | 1252 | dwc2_udc_ep_set_stall(ep); |
38517a78 ŁM |
1253 | } |
1254 | ||
f52dd802 | 1255 | dwc2_udc_ep0_zlp(dev); |
38517a78 ŁM |
1256 | return 0; |
1257 | } | |
1258 | ||
1259 | return 1; | |
1260 | } | |
1261 | ||
1262 | /* | |
1263 | * WAIT_FOR_SETUP (OUT_PKT_RDY) | |
1264 | */ | |
28b97748 | 1265 | static void dwc2_ep0_setup(struct dwc2_udc *dev) |
38517a78 | 1266 | { |
627d9298 | 1267 | struct dwc2_ep *ep = &dev->ep[0]; |
ea2d9159 | 1268 | int i; |
38517a78 ŁM |
1269 | u8 ep_num; |
1270 | ||
1271 | /* Nuke all previous transfers */ | |
1272 | nuke(ep, -EPROTO); | |
1273 | ||
1274 | /* read control req from fifo (8 bytes) */ | |
155e740f | 1275 | dwc2_fifo_read(ep, (u32 *)usb_ctrl, 8); |
38517a78 | 1276 | |
f3b05ca5 ŁM |
1277 | debug_cond(DEBUG_SETUP != 0, |
1278 | "%s: bRequestType = 0x%x(%s), bRequest = 0x%x" | |
1279 | "\twLength = 0x%x, wValue = 0x%x, wIndex= 0x%x\n", | |
1280 | __func__, usb_ctrl->bRequestType, | |
1281 | (usb_ctrl->bRequestType & USB_DIR_IN) ? "IN" : "OUT", | |
1282 | usb_ctrl->bRequest, | |
1283 | usb_ctrl->wLength, usb_ctrl->wValue, usb_ctrl->wIndex); | |
38517a78 | 1284 | |
f3b05ca5 | 1285 | #ifdef DEBUG |
38517a78 ŁM |
1286 | { |
1287 | int i, len = sizeof(*usb_ctrl); | |
ea2d9159 | 1288 | char *p = (char *)usb_ctrl; |
38517a78 ŁM |
1289 | |
1290 | printf("pkt = "); | |
1291 | for (i = 0; i < len; i++) { | |
1292 | printf("%02x", ((u8 *)p)[i]); | |
1293 | if ((i & 7) == 7) | |
1294 | printf(" "); | |
1295 | } | |
1296 | printf("\n"); | |
1297 | } | |
1298 | #endif | |
1299 | ||
1300 | if (usb_ctrl->bRequest == GET_MAX_LUN_REQUEST && | |
1301 | usb_ctrl->wLength != 1) { | |
f3b05ca5 ŁM |
1302 | debug_cond(DEBUG_SETUP != 0, |
1303 | "\t%s:GET_MAX_LUN_REQUEST:invalid", | |
1304 | __func__); | |
1305 | debug_cond(DEBUG_SETUP != 0, | |
1306 | "wLength = %d, setup returned\n", | |
1307 | usb_ctrl->wLength); | |
38517a78 | 1308 | |
f52dd802 | 1309 | dwc2_udc_ep0_set_stall(ep); |
38517a78 ŁM |
1310 | dev->ep0state = WAIT_FOR_SETUP; |
1311 | ||
1312 | return; | |
1313 | } else if (usb_ctrl->bRequest == BOT_RESET_REQUEST && | |
1314 | usb_ctrl->wLength != 0) { | |
1315 | /* Bulk-Only *mass storge reset of class-specific request */ | |
f3b05ca5 ŁM |
1316 | debug_cond(DEBUG_SETUP != 0, |
1317 | "%s:BOT Rest:invalid wLength =%d, setup returned\n", | |
1318 | __func__, usb_ctrl->wLength); | |
38517a78 | 1319 | |
f52dd802 | 1320 | dwc2_udc_ep0_set_stall(ep); |
38517a78 ŁM |
1321 | dev->ep0state = WAIT_FOR_SETUP; |
1322 | ||
1323 | return; | |
1324 | } | |
1325 | ||
1326 | /* Set direction of EP0 */ | |
1327 | if (likely(usb_ctrl->bRequestType & USB_DIR_IN)) { | |
1328 | ep->bEndpointAddress |= USB_DIR_IN; | |
38517a78 ŁM |
1329 | } else { |
1330 | ep->bEndpointAddress &= ~USB_DIR_IN; | |
38517a78 ŁM |
1331 | } |
1332 | /* cope with automagic for some standard requests. */ | |
1333 | dev->req_std = (usb_ctrl->bRequestType & USB_TYPE_MASK) | |
1334 | == USB_TYPE_STANDARD; | |
7cf7beff | 1335 | |
38517a78 ŁM |
1336 | dev->req_pending = 1; |
1337 | ||
1338 | /* Handle some SETUP packets ourselves */ | |
1339 | if (dev->req_std) { | |
1340 | switch (usb_ctrl->bRequest) { | |
1341 | case USB_REQ_SET_ADDRESS: | |
f3b05ca5 ŁM |
1342 | debug_cond(DEBUG_SETUP != 0, |
1343 | "%s: *** USB_REQ_SET_ADDRESS (%d)\n", | |
1344 | __func__, usb_ctrl->wValue); | |
38517a78 ŁM |
1345 | if (usb_ctrl->bRequestType |
1346 | != (USB_TYPE_STANDARD | USB_RECIP_DEVICE)) | |
1347 | break; | |
1348 | ||
1349 | udc_set_address(dev, usb_ctrl->wValue); | |
1350 | return; | |
1351 | ||
1352 | case USB_REQ_SET_CONFIGURATION: | |
f3b05ca5 ŁM |
1353 | debug_cond(DEBUG_SETUP != 0, |
1354 | "=====================================\n"); | |
1355 | debug_cond(DEBUG_SETUP != 0, | |
1356 | "%s: USB_REQ_SET_CONFIGURATION (%d)\n", | |
1357 | __func__, usb_ctrl->wValue); | |
38517a78 | 1358 | |
7cf7beff | 1359 | if (usb_ctrl->bRequestType == USB_RECIP_DEVICE) |
38517a78 | 1360 | reset_available = 1; |
7cf7beff | 1361 | |
38517a78 ŁM |
1362 | break; |
1363 | ||
1364 | case USB_REQ_GET_DESCRIPTOR: | |
f3b05ca5 ŁM |
1365 | debug_cond(DEBUG_SETUP != 0, |
1366 | "%s: *** USB_REQ_GET_DESCRIPTOR\n", | |
1367 | __func__); | |
38517a78 ŁM |
1368 | break; |
1369 | ||
1370 | case USB_REQ_SET_INTERFACE: | |
f3b05ca5 ŁM |
1371 | debug_cond(DEBUG_SETUP != 0, |
1372 | "%s: *** USB_REQ_SET_INTERFACE (%d)\n", | |
1373 | __func__, usb_ctrl->wValue); | |
38517a78 | 1374 | |
7cf7beff | 1375 | if (usb_ctrl->bRequestType == USB_RECIP_INTERFACE) |
38517a78 | 1376 | reset_available = 1; |
7cf7beff | 1377 | |
38517a78 ŁM |
1378 | break; |
1379 | ||
1380 | case USB_REQ_GET_CONFIGURATION: | |
f3b05ca5 ŁM |
1381 | debug_cond(DEBUG_SETUP != 0, |
1382 | "%s: *** USB_REQ_GET_CONFIGURATION\n", | |
1383 | __func__); | |
38517a78 ŁM |
1384 | break; |
1385 | ||
1386 | case USB_REQ_GET_STATUS: | |
f52dd802 | 1387 | if (!dwc2_udc_get_status(dev, usb_ctrl)) |
38517a78 ŁM |
1388 | return; |
1389 | ||
1390 | break; | |
1391 | ||
1392 | case USB_REQ_CLEAR_FEATURE: | |
1393 | ep_num = usb_ctrl->wIndex & 0x7f; | |
1394 | ||
f52dd802 | 1395 | if (!dwc2_udc_clear_feature(&dev->ep[ep_num].ep)) |
38517a78 ŁM |
1396 | return; |
1397 | ||
1398 | break; | |
1399 | ||
1400 | case USB_REQ_SET_FEATURE: | |
1401 | ep_num = usb_ctrl->wIndex & 0x7f; | |
1402 | ||
f52dd802 | 1403 | if (!dwc2_udc_set_feature(&dev->ep[ep_num].ep)) |
38517a78 ŁM |
1404 | return; |
1405 | ||
1406 | break; | |
1407 | ||
1408 | default: | |
f3b05ca5 ŁM |
1409 | debug_cond(DEBUG_SETUP != 0, |
1410 | "%s: *** Default of usb_ctrl->bRequest=0x%x" | |
1411 | "happened.\n", __func__, usb_ctrl->bRequest); | |
38517a78 ŁM |
1412 | break; |
1413 | } | |
1414 | } | |
1415 | ||
1416 | ||
1417 | if (likely(dev->driver)) { | |
1418 | /* device-2-host (IN) or no data setup command, | |
1419 | * process immediately */ | |
f3b05ca5 ŁM |
1420 | debug_cond(DEBUG_SETUP != 0, |
1421 | "%s:usb_ctrlreq will be passed to fsg_setup()\n", | |
38517a78 ŁM |
1422 | __func__); |
1423 | ||
1424 | spin_unlock(&dev->lock); | |
1425 | i = dev->driver->setup(&dev->gadget, usb_ctrl); | |
1426 | spin_lock(&dev->lock); | |
1427 | ||
1428 | if (i < 0) { | |
38517a78 | 1429 | /* setup processing failed, force stall */ |
f52dd802 | 1430 | dwc2_udc_ep0_set_stall(ep); |
38517a78 ŁM |
1431 | dev->ep0state = WAIT_FOR_SETUP; |
1432 | ||
f3b05ca5 ŁM |
1433 | debug_cond(DEBUG_SETUP != 0, |
1434 | "\tdev->driver->setup failed (%d)," | |
38517a78 ŁM |
1435 | " bRequest = %d\n", |
1436 | i, usb_ctrl->bRequest); | |
1437 | ||
1438 | ||
1439 | } else if (dev->req_pending) { | |
1440 | dev->req_pending = 0; | |
f3b05ca5 ŁM |
1441 | debug_cond(DEBUG_SETUP != 0, |
1442 | "\tdev->req_pending...\n"); | |
38517a78 ŁM |
1443 | } |
1444 | ||
f3b05ca5 ŁM |
1445 | debug_cond(DEBUG_SETUP != 0, |
1446 | "\tep0state = %s\n", state_names[dev->ep0state]); | |
38517a78 ŁM |
1447 | |
1448 | } | |
1449 | } | |
1450 | ||
1451 | /* | |
1452 | * handle ep0 interrupt | |
1453 | */ | |
155e740f | 1454 | static void dwc2_handle_ep0(struct dwc2_udc *dev) |
38517a78 ŁM |
1455 | { |
1456 | if (dev->ep0state == WAIT_FOR_SETUP) { | |
f3b05ca5 ŁM |
1457 | debug_cond(DEBUG_OUT_EP != 0, |
1458 | "%s: WAIT_FOR_SETUP\n", __func__); | |
28b97748 | 1459 | dwc2_ep0_setup(dev); |
38517a78 ŁM |
1460 | |
1461 | } else { | |
f3b05ca5 ŁM |
1462 | debug_cond(DEBUG_OUT_EP != 0, |
1463 | "%s: strange state!!(state = %s)\n", | |
38517a78 ŁM |
1464 | __func__, state_names[dev->ep0state]); |
1465 | } | |
1466 | } | |
1467 | ||
28b97748 | 1468 | static void dwc2_ep0_kick(struct dwc2_udc *dev, struct dwc2_ep *ep) |
38517a78 | 1469 | { |
f3b05ca5 ŁM |
1470 | debug_cond(DEBUG_EP0 != 0, |
1471 | "%s: ep_is_in = %d\n", __func__, ep_is_in(ep)); | |
38517a78 ŁM |
1472 | if (ep_is_in(ep)) { |
1473 | dev->ep0state = DATA_STATE_XMIT; | |
28b97748 | 1474 | dwc2_ep0_write(dev); |
38517a78 ŁM |
1475 | |
1476 | } else { | |
1477 | dev->ep0state = DATA_STATE_RECV; | |
28b97748 | 1478 | dwc2_ep0_read(dev); |
38517a78 ŁM |
1479 | } |
1480 | } |