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