]> git.sur5r.net Git - freertos/blob
5d7d8060a216063db2fdf8eb47f9d6d5e5ef41e3
[freertos] /
1 /******************************************************************************
2 *
3 * Copyright (C) 2015 Xilinx, Inc.  All rights reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * Use of the Software is limited solely to applications:
16 * (a) running on a Xilinx device, or
17 * (b) that interact with a Xilinx device through a bus or interconnect.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * XILINX  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
24 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 * SOFTWARE.
26 *
27 * Except as contained in this notice, the name of the Xilinx shall not be used
28 * in advertising or otherwise to promote the sale, use or other dealings in
29 * this Software without prior written authorization from Xilinx.
30 *
31 ******************************************************************************/
32 /****************************************************************************/
33 /**
34 *
35 * @file xusbpsu_controltransfers.c
36 *
37 * <pre>
38 * MODIFICATION HISTORY:
39 *
40 * Ver   Who  Date     Changes
41 * ----- ---- -------- -------------------------------------------------------
42 * 1.00a bss  01/22/15 First release
43 * 1.00a bss  03/18/15 Modified u32 pointer casts to UINTPTR.
44 *
45 * </pre>
46 *
47 *****************************************************************************/
48
49 /***************************** Include Files *********************************/
50
51 #include "xusbpsu.h"
52
53 /************************** Constant Definitions *****************************/
54
55 #define USB_DIR_OUT                             0               /* to device */
56 #define USB_DIR_IN                              0x80    /* to host */
57
58 /**************************** Type Definitions *******************************/
59
60 /***************** Macros (Inline Functions) Definitions *********************/
61
62 /************************** Function Prototypes ******************************/
63
64
65 /************************** Variable Definitions *****************************/
66
67
68 /****************************************************************************/
69 /**
70 * Initiates DMA on Control Endpoint 0 to receive Setup packet.
71 *
72 * @param        InstancePtr is a pointer to the XUsbPsu instance.
73 *
74 * @return       XST_SUCCESS else XST_FAILURE.
75 *
76 * @note         None.
77 *
78 *****************************************************************************/
79 int XUsbPsu_RecvSetup(struct XUsbPsu *InstancePtr)
80 {
81         struct XUsbPsu_EpParams *Params;
82         struct XUsbPsu_Trb      *TrbPtr;
83         struct XUsbPsu_Ep       *Ept;
84         int     Ret;
85
86         Xil_AssertNonvoid(InstancePtr != NULL);
87
88         Params = XUsbPsu_GetEpParams(InstancePtr);
89         /* Setup packet always on EP0 */
90         Ept = &InstancePtr->eps[0];
91         if (Ept->EpStatus & XUSBPSU_EP_BUSY) {
92                 return XST_FAILURE;
93         }
94
95         TrbPtr = &InstancePtr->Ep0_Trb;
96
97         TrbPtr->BufferPtrLow = (UINTPTR)&InstancePtr->SetupData;
98         TrbPtr->BufferPtrHigh = ((UINTPTR)&InstancePtr->SetupData >> 16) >> 16;
99         TrbPtr->Size = 8;
100         TrbPtr->Ctrl = XUSBPSU_TRBCTL_CONTROL_SETUP;
101
102         TrbPtr->Ctrl |= (XUSBPSU_TRB_CTRL_HWO
103                         | XUSBPSU_TRB_CTRL_LST
104                         | XUSBPSU_TRB_CTRL_IOC
105                         | XUSBPSU_TRB_CTRL_ISP_IMI);
106
107         Xil_DCacheFlushRange(TrbPtr, sizeof(struct XUsbPsu_Trb));
108
109         Params->Param0 = 0;
110         Params->Param1 = (UINTPTR)TrbPtr;
111
112         InstancePtr->Ep0State = XUSBPSU_EP0_SETUP_PHASE;
113
114         Ept->Cmd = XUSBPSU_DEPCMD_STARTTRANSFER;
115         Ret = XUsbPsu_SendEpCmd(InstancePtr, 0, XUSBPSU_EP_DIR_OUT,
116                                 XUSBPSU_DEPCMD_STARTTRANSFER, Params);
117         if (Ret < 0) {
118                 return Ret;
119         }
120
121         Ept->EpStatus |= XUSBPSU_EP_BUSY;
122         Ept->ResourceIndex = XUsbPsu_EpGetTransferIndex(InstancePtr,
123                                                 Ept->UsbEpNum, Ept->Direction);
124
125         return XST_SUCCESS;
126 }
127
128 /****************************************************************************/
129 /**
130 * Stalls Control Endpoint and restarts to receive Setup packet.
131 *
132 * @param        InstancePtr is a pointer to the XUsbPsu instance.
133 *
134 * @return       None
135 *
136 * @note         None.
137 *
138 *****************************************************************************/
139 void XUsbPsu_Ep0StallRestart(struct XUsbPsu *InstancePtr)
140 {
141         struct XUsbPsu_Ep               *Ept;
142
143         Xil_AssertVoid(InstancePtr != NULL);
144
145         /* reinitialize physical ep1 */
146         Ept = &InstancePtr->eps[1];
147         Ept->EpStatus = XUSBPSU_EP_ENABLED;
148
149         /* stall is always issued on EP0 */
150         XUsbPsu_EpSetStall(InstancePtr, 0, XUSBPSU_EP_DIR_OUT);
151
152         Ept = &InstancePtr->eps[0];
153         Ept->EpStatus = XUSBPSU_EP_ENABLED;
154         InstancePtr->Ep0State = XUSBPSU_EP0_SETUP_PHASE;
155         XUsbPsu_RecvSetup(InstancePtr);
156 }
157
158 /****************************************************************************/
159 /**
160 * Changes State of Core to USB configured State.
161 *
162 * @param        InstancePtr is a pointer to the XUsbPsu instance.
163 * @param        Ctrl is a pointer to the Setup packet data.
164 *
165 * @return       XST_SUCCESS else XST_FAILURE
166 *
167 * @note         None.
168 *
169 *****************************************************************************/
170 int XUsbPsu_SetConfiguration(struct XUsbPsu *InstancePtr, SetupPacket *Ctrl)
171 {
172         u8 State;
173         int Ret;
174         u32 RegVal;
175
176         Xil_AssertNonvoid(InstancePtr != NULL);
177         Xil_AssertNonvoid(Ctrl != NULL);
178
179         State = InstancePtr->State;
180         InstancePtr->IsConfigDone = 0;
181
182         switch (State) {
183         case XUSBPSU_STATE_DEFAULT:
184                 return XST_FAILURE;
185                 break;
186
187         case XUSBPSU_STATE_ADDRESS:
188                 InstancePtr->State = XUSBPSU_STATE_CONFIGURED;
189                 break;
190
191         case XUSBPSU_STATE_CONFIGURED:
192                 break;
193
194         default:
195                 Ret = XST_FAILURE;
196                 break;
197         }
198
199         return Ret;
200 }
201
202 /****************************************************************************/
203 /**
204 * Checks the Data Phase and calls user Endpoint handler.
205 *
206 * @param        InstancePtr is a pointer to the XUsbPsu instance.
207 * @param        Event is a pointer to the Endpoint event occured in core.
208 *
209 * @return       None.
210 *
211 * @note         None.
212 *
213 *****************************************************************************/
214 void XUsbPsu_Ep0DataDone(struct XUsbPsu *InstancePtr,
215                                                  const struct XUsbPsu_Event_Epevt *Event)
216 {
217         struct XUsbPsu_Ep       *Ept;
218         struct XUsbPsu_Trb      *TrbPtr;
219         u32     Status;
220         u32     Length;
221         u32     EpNum;
222         u8      Dir;
223
224         Xil_AssertVoid(InstancePtr != NULL);
225         Xil_AssertVoid(Event != NULL);
226
227         EpNum = Event->Epnumber;
228         Dir = !!EpNum;
229         Ept = &InstancePtr->eps[EpNum];
230         TrbPtr = &InstancePtr->Ep0_Trb;
231
232         Xil_DCacheInvalidateRange(TrbPtr, sizeof(struct XUsbPsu_Trb));
233
234         Status = XUSBPSU_TRB_SIZE_TRBSTS(TrbPtr->Size);
235         if (Status == XUSBPSU_TRBSTS_SETUP_PENDING) {
236                 return;
237         }
238
239         Length = TrbPtr->Size & XUSBPSU_TRB_SIZE_MASK;
240
241         if (Length && Dir) { /* IN */
242                 Ept->BytesTxed = Ept->RequestedBytes - Length;
243         }
244
245         if (!Length) {
246                 Ept->BytesTxed = Ept->RequestedBytes;
247         }
248
249         if (Length && !Dir) { /* OUT */
250                 /* may be  wLength < Maxpacketsize */
251                 if (InstancePtr->UnalignedTx) {
252                         Ept->BytesTxed = Ept->RequestedBytes;
253                         InstancePtr->UnalignedTx = 0;
254                 }
255         }
256
257         if (!Dir) {
258                 /* Invalidate Cache */
259                 Xil_DCacheInvalidateRange(Ept->BufferPtr, Ept->BytesTxed);
260         }
261
262         if (Ept->Handler) {
263                 Ept->Handler(InstancePtr, Ept->RequestedBytes, Ept->BytesTxed);
264         }
265 }
266
267 /****************************************************************************/
268 /**
269 * Checks the Status Phase and starts next Control transfer.
270 *
271 * @param        InstancePtr is a pointer to the XUsbPsu instance.
272 * @param        Event is a pointer to the Endpoint event occured in core.
273 *
274 * @return       None.
275 *
276 * @note         None.
277 *
278 *****************************************************************************/
279 void XUsbPsu_Ep0StatusDone(struct XUsbPsu *InstancePtr,
280                 const struct XUsbPsu_Event_Epevt *Event)
281 {
282         struct XUsbPsu_Trb      *TrbPtr;
283         u32     Status;
284
285         Xil_AssertVoid(InstancePtr != NULL);
286         Xil_AssertVoid(Event != NULL);
287
288         TrbPtr = &InstancePtr->Ep0_Trb;
289
290         if (InstancePtr->IsInTestMode) {
291                 int Ret;
292
293                 Ret = XUsbPsu_SetTestMode(InstancePtr,
294                                         InstancePtr->TestMode);
295                 if (Ret < 0) {
296                         XUsbPsu_Ep0StallRestart(InstancePtr);
297                         return;
298                 }
299         }
300         Xil_DCacheInvalidateRange(TrbPtr, sizeof(struct XUsbPsu_Trb));
301         Status = XUSBPSU_TRB_SIZE_TRBSTS(TrbPtr->Size);
302         /* There is nothing driver can do for Setup Pending received */
303
304         XUsbPsu_RecvSetup(InstancePtr);
305 }
306
307 /****************************************************************************/
308 /**
309 * Handles Transfer complete event of Control Endpoints EP0 OUT and EP0 IN.
310 *
311 * @param        InstancePtr is a pointer to the XUsbPsu instance.
312 * @param        Event is a pointer to the Endpoint event occured in core.
313 *
314 * @return       None.
315 *
316 * @note         None.
317 *
318 *****************************************************************************/
319 void XUsbPsu_Ep0XferComplete(struct XUsbPsu *InstancePtr,
320                                                          const struct XUsbPsu_Event_Epevt *Event)
321 {
322         struct XUsbPsu_Ep *Ept;
323         SetupPacket *Ctrl;
324         u16 Length;
325
326         Xil_AssertVoid(InstancePtr != NULL);
327         Xil_AssertVoid(Event != NULL);
328
329         Ept = &InstancePtr->eps[Event->Epnumber];
330         Ctrl = &InstancePtr->SetupData;
331
332         Ept->EpStatus &= ~XUSBPSU_EP_BUSY;
333         Ept->ResourceIndex = 0;
334
335         switch (InstancePtr->Ep0State) {
336         case XUSBPSU_EP0_SETUP_PHASE:
337                 Xil_DCacheInvalidateRange(&InstancePtr->SetupData,
338                                         sizeof(InstancePtr->SetupData));
339                 Length = Ctrl->wLength;
340                 if (!Length) {
341                         InstancePtr->IsThreeStage = 0;
342                         InstancePtr->ControlDir = XUSBPSU_EP_DIR_OUT;
343                 } else {
344                         InstancePtr->IsThreeStage = 1;
345                         InstancePtr->ControlDir = !!(Ctrl->bRequestType &
346                                                         USB_DIR_IN);
347                 }
348
349                 if (InstancePtr->Chapter9 == NULL) {
350                                 /* ? */
351                 } else {
352                         InstancePtr->Chapter9(InstancePtr,
353                                                                         &InstancePtr->SetupData);
354                 }
355                 break;
356
357         case XUSBPSU_EP0_DATA_PHASE:
358                 XUsbPsu_Ep0DataDone(InstancePtr, Event);
359                 break;
360
361         case XUSBPSU_EP0_STATUS_PHASE:
362                 XUsbPsu_Ep0StatusDone(InstancePtr, Event);
363                 break;
364
365         default:
366                 break;
367         }
368 }
369
370 /****************************************************************************/
371 /**
372 * Starts Status Phase of Control Transfer
373 *
374 * @param        InstancePtr is a pointer to the XUsbPsu instance.
375 * @param        Event is a pointer to the Endpoint event occured in core.
376 *
377 * @return       XST_SUCCESS else XST_FAILURE
378 *
379 * @note         None.
380 *
381 *****************************************************************************/
382 int XUsbPsu_Ep0StartStatus(struct XUsbPsu *InstancePtr,
383                                 const struct XUsbPsu_Event_Epevt *Event)
384 {
385         struct XUsbPsu_Ep  *Ept;
386         struct XUsbPsu_EpParams *Params;
387         struct XUsbPsu_Trb *TrbPtr;
388         u32 Type;
389         int Ret;
390         u8 Dir;
391
392         Xil_AssertNonvoid(InstancePtr != NULL);
393         Xil_AssertNonvoid(Event != NULL);
394
395         Ept = &InstancePtr->eps[Event->Epnumber];
396         Params = XUsbPsu_GetEpParams(InstancePtr);
397         if (Ept->EpStatus & XUSBPSU_EP_BUSY) {
398                 return XST_FAILURE;
399         }
400
401         Type = InstancePtr->IsThreeStage ? XUSBPSU_TRBCTL_CONTROL_STATUS3
402                                         : XUSBPSU_TRBCTL_CONTROL_STATUS2;
403         TrbPtr = &InstancePtr->Ep0_Trb;
404         /* we use same TrbPtr for setup packet */
405         TrbPtr->BufferPtrLow = (UINTPTR)&InstancePtr->SetupData;
406         TrbPtr->BufferPtrHigh = ((UINTPTR)&InstancePtr->SetupData >> 16) >> 16;
407         TrbPtr->Size = 0;
408         TrbPtr->Ctrl = Type;
409
410         TrbPtr->Ctrl |= (XUSBPSU_TRB_CTRL_HWO
411                         | XUSBPSU_TRB_CTRL_LST
412                         | XUSBPSU_TRB_CTRL_IOC
413                         | XUSBPSU_TRB_CTRL_ISP_IMI);
414
415         Xil_DCacheFlushRange(TrbPtr, sizeof(struct XUsbPsu_Trb));
416
417         Params->Param0 = 0;
418         Params->Param1 = (UINTPTR)TrbPtr;
419
420         InstancePtr->Ep0State = XUSBPSU_EP0_STATUS_PHASE;
421
422         /*
423          * Control OUT transfer - Status stage happens on EP0 IN - EP1
424          * Control IN transfer - Status stage happens on EP0 OUT - EP0
425          */
426         Dir = !InstancePtr->ControlDir;
427         Ept->Cmd = XUSBPSU_DEPCMD_STARTTRANSFER;
428         Ret = XUsbPsu_SendEpCmd(InstancePtr, 0, Dir,
429                                                         XUSBPSU_DEPCMD_STARTTRANSFER, Params);
430         if (Ret != XST_SUCCESS) {
431                 return XST_FAILURE;
432         }
433
434         Ept->EpStatus |= XUSBPSU_EP_BUSY;
435         Ept->ResourceIndex = XUsbPsu_EpGetTransferIndex(InstancePtr,
436                                                         Ept->UsbEpNum, Ept->Direction);
437
438         return XST_SUCCESS;
439 }
440
441 /****************************************************************************/
442 /**
443 * Ends Data Phase - used incase of error.
444 *
445 * @param        InstancePtr is a pointer to the XUsbPsu instance.
446 * @param        Dep is a pointer to the Endpoint structure.
447 *
448 * @return       None
449 *
450 * @note         None.
451 *
452 *****************************************************************************/
453 void XUsbPsu_Ep0_EndControlData(struct XUsbPsu *InstancePtr,
454                                                                 struct XUsbPsu_Ep *Ept)
455 {
456         struct XUsbPsu_EpParams *Params;
457         u32     Cmd;
458
459         Xil_AssertVoid(InstancePtr != NULL);
460         Xil_AssertVoid(Ept != NULL);
461
462         if (!Ept->ResourceIndex)
463                 return;
464
465         Params = XUsbPsu_GetEpParams(InstancePtr);
466         Cmd = XUSBPSU_DEPCMD_ENDTRANSFER;
467         Cmd |= XUSBPSU_DEPCMD_PARAM(Ept->ResourceIndex);
468         Ept->Cmd = XUSBPSU_DEPCMD_ENDTRANSFER;
469         XUsbPsu_SendEpCmd(InstancePtr, Ept->UsbEpNum, Ept->Direction,
470                                                 Cmd, Params);
471         Ept->ResourceIndex = 0;
472         usleep(200);
473 }
474
475 /****************************************************************************/
476 /**
477 * Handles Transfer Not Ready event of Control Endpoints EP0 OUT and EP0 IN.
478 *
479 * @param        InstancePtr is a pointer to the XUsbPsu instance.
480 * @param        Event is a pointer to the Endpoint event occured in core.
481 *
482 * @return       None.
483 *
484 * @note         None.
485 *
486 *****************************************************************************/
487 void XUsbPsu_Ep0XferNotReady(struct XUsbPsu *InstancePtr,
488                                                          const struct XUsbPsu_Event_Epevt *Event)
489 {
490         struct XUsbPsu_Ep *Ept;
491
492         Xil_AssertVoid(InstancePtr != NULL);
493         Xil_AssertVoid(Event != NULL);
494
495         Ept = &InstancePtr->eps[Event->Epnumber];
496
497         switch (Event->Status) {
498         case DEPEVT_STATUS_CONTROL_DATA:
499                 /*
500                  * We already have a DATA transfer in the controller's cache,
501                  * if we receive a XferNotReady(DATA) we will ignore it, unless
502                  * it's for the wrong direction.
503                  *
504                  * In that case, we must issue END_TRANSFER command to the Data
505                  * Phase we already have started and issue SetStall on the
506                  * control endpoint.
507                  */
508                 if (Event->Epnumber != InstancePtr->ControlDir) {
509                         XUsbPsu_Ep0_EndControlData(InstancePtr, Ept);
510                         XUsbPsu_Ep0StallRestart(InstancePtr);
511                 }
512                 break;
513
514         case DEPEVT_STATUS_CONTROL_STATUS:
515                 XUsbPsu_Ep0StartStatus(InstancePtr, Event);
516                 break;
517         }
518 }
519
520 /****************************************************************************/
521 /**
522 * Handles Interrupts of Control Endpoints EP0 OUT and EP0 IN.
523 *
524 * @param        InstancePtr is a pointer to the XUsbPsu instance.
525 * @param        Event is a pointer to the Endpoint event occured in core.
526 *
527 * @return       None.
528 *
529 * @note         None.
530 *
531 *****************************************************************************/
532 void XUsbPsu_Ep0Intr(struct XUsbPsu *InstancePtr,
533                 const struct XUsbPsu_Event_Epevt *Event)
534 {
535         u32 EpNum;
536
537         Xil_AssertVoid(InstancePtr != NULL);
538         Xil_AssertVoid(Event != NULL);
539
540         EpNum = Event->Epnumber;
541         switch (Event->Endpoint_Event) {
542         case XUSBPSU_DEPEVT_XFERCOMPLETE:
543                 XUsbPsu_Ep0XferComplete(InstancePtr, Event);
544                 break;
545
546         case XUSBPSU_DEPEVT_XFERNOTREADY:
547                 XUsbPsu_Ep0XferNotReady(InstancePtr, Event);
548                 break;
549
550         case XUSBPSU_DEPEVT_XFERINPROGRESS:
551         case XUSBPSU_DEPEVT_STREAMEVT:
552         case XUSBPSU_DEPEVT_EPCMDCMPLT:
553                 break;
554         }
555 }
556
557 /****************************************************************************/
558 /**
559 * Initiates DMA to send data on Control Endpoint EP0 IN to Host.
560 *
561 * @param        InstancePtr is a pointer to the XUsbPsu instance.
562 * @param        BufferPtr is pointer to data.
563 * @param        BufferLen is Length of data buffer.
564 *
565 * @return       XST_SUCCESS else XST_FAILURE
566 *
567 * @note         None.
568 *
569 *****************************************************************************/
570 int XUsbPsu_Ep0Send(struct XUsbPsu *InstancePtr, u8 *BufferPtr, u32 BufferLen)
571 {
572         /* Control IN - EP1 */
573         struct XUsbPsu_EpParams *Params;
574         struct XUsbPsu_Ep       *Ept;
575         struct XUsbPsu_Trb      *TrbPtr;
576         u32 Type;
577         int Ret;
578
579         Xil_AssertNonvoid(InstancePtr != NULL);
580         Xil_AssertNonvoid(BufferPtr != NULL);
581
582         Ept = &InstancePtr->eps[1];
583         Params = XUsbPsu_GetEpParams(InstancePtr);
584         if (Ept->EpStatus & XUSBPSU_EP_BUSY) {
585                 return XST_FAILURE;
586         }
587
588         Ept->RequestedBytes = BufferLen;
589         Ept->BytesTxed = 0;
590         Ept->BufferPtr = BufferPtr;
591
592         TrbPtr = &InstancePtr->Ep0_Trb;
593
594         TrbPtr->BufferPtrLow  = (UINTPTR)BufferPtr;
595         TrbPtr->BufferPtrHigh  = ((UINTPTR)BufferPtr >> 16) >> 16;
596         TrbPtr->Size = BufferLen;
597         TrbPtr->Ctrl = XUSBPSU_TRBCTL_CONTROL_DATA;
598
599         TrbPtr->Ctrl |= (XUSBPSU_TRB_CTRL_HWO
600                         | XUSBPSU_TRB_CTRL_LST
601                         | XUSBPSU_TRB_CTRL_IOC
602                         | XUSBPSU_TRB_CTRL_ISP_IMI);
603
604         Params->Param0 = 0;
605         Params->Param1 = (UINTPTR)TrbPtr;
606
607         Xil_DCacheFlushRange(TrbPtr, sizeof(struct XUsbPsu_Trb));
608         Xil_DCacheFlushRange(BufferPtr, BufferLen);
609
610         InstancePtr->Ep0State = XUSBPSU_EP0_DATA_PHASE;
611
612         Ept->Cmd = XUSBPSU_DEPCMD_STARTTRANSFER;
613         Ret = XUsbPsu_SendEpCmd(InstancePtr, 0, XUSBPSU_EP_DIR_IN,
614                                                         XUSBPSU_DEPCMD_STARTTRANSFER, Params);
615         if (Ret != XST_SUCCESS) {
616                 return XST_FAILURE;
617         }
618
619         Ept->EpStatus |= XUSBPSU_EP_BUSY;
620         Ept->ResourceIndex = XUsbPsu_EpGetTransferIndex(InstancePtr,
621                                                 Ept->UsbEpNum, Ept->Direction);
622
623         return XST_SUCCESS;
624 }
625
626 /****************************************************************************/
627 /**
628 * Initiates DMA to receive data on Control Endpoint EP0 OUT from Host.
629 *
630 * @param        InstancePtr is a pointer to the XUsbPsu instance.
631 * @param        BufferPtr is pointer to data.
632 * @param        Length is Length of data to be received.
633 *
634 * @return       XST_SUCCESS else XST_FAILURE
635 *
636 * @note         None.
637 *
638 *****************************************************************************/
639 int XUsbPsu_Ep0Recv(struct XUsbPsu *InstancePtr, u8 *BufferPtr, u32 Length)
640 {
641         struct XUsbPsu_EpParams *Params;
642         struct XUsbPsu_Ep       *Ept;
643         struct XUsbPsu_Trb      *TrbPtr;
644         u32 Type;
645         u32 Size;
646         int Ret;
647
648         Xil_AssertNonvoid(InstancePtr != NULL);
649         Xil_AssertNonvoid(BufferPtr != NULL);
650
651         Ept = &InstancePtr->eps[0];
652         Params = XUsbPsu_GetEpParams(InstancePtr);
653         if (Ept->EpStatus & XUSBPSU_EP_BUSY) {
654                 return XST_FAILURE;
655         }
656
657         Size = Ept->RequestedBytes = Length;
658         Ept->BytesTxed = 0;
659         Ept->BufferPtr = BufferPtr;
660
661         /*
662          * 8.2.5 - An OUT transfer size (Total TRB buffer allocation)
663          * must be a multiple of MaxPacketSize even if software is expecting a
664          * fixed non-multiple of MaxPacketSize transfer from the Host.
665          */
666         if (!IS_ALIGNED(Length, Ept->MaxSize)) {
667                 Size = roundup(Length, Ept->MaxSize);
668                 InstancePtr->UnalignedTx = 1;
669         }
670
671         TrbPtr = &InstancePtr->Ep0_Trb;
672
673         TrbPtr->BufferPtrLow = (UINTPTR)BufferPtr;
674         TrbPtr->BufferPtrHigh = ((UINTPTR)BufferPtr >> 16) >> 16;
675         TrbPtr->Size = Size;
676         TrbPtr->Ctrl = XUSBPSU_TRBCTL_CONTROL_DATA;
677
678         TrbPtr->Ctrl |= (XUSBPSU_TRB_CTRL_HWO
679                         | XUSBPSU_TRB_CTRL_LST
680                         | XUSBPSU_TRB_CTRL_IOC
681                         | XUSBPSU_TRB_CTRL_ISP_IMI);
682
683         Xil_DCacheFlushRange(TrbPtr, sizeof(struct XUsbPsu_Trb));
684
685         Params->Param0 = 0;
686         Params->Param1 = (UINTPTR)TrbPtr;
687
688         InstancePtr->Ep0State = XUSBPSU_EP0_DATA_PHASE;
689
690         Ept->Cmd = XUSBPSU_DEPCMD_STARTTRANSFER;
691         Ret = XUsbPsu_SendEpCmd(InstancePtr, 0, XUSBPSU_EP_DIR_OUT,
692                                 XUSBPSU_DEPCMD_STARTTRANSFER, Params);
693         if (Ret < 0) {
694                 return Ret;
695         }
696
697         Ept->EpStatus |= XUSBPSU_EP_BUSY;
698         Ept->ResourceIndex = XUsbPsu_EpGetTransferIndex(InstancePtr,
699                                                         Ept->UsbEpNum, Ept->Direction);
700
701         return XST_SUCCESS;
702 }