1 /******************************************************************************
3 * Copyright (C) 2016 Xilinx, Inc. All rights reserved.
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:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
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.
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
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.
31 ******************************************************************************/
32 /****************************************************************************/
35 * @file xusbpsu_controltransfers.c
36 * @addtogroup usbpsu_v1_0
40 * MODIFICATION HISTORY:
42 * Ver Who Date Changes
43 * ----- ---- -------- -------------------------------------------------------
44 * 1.0 sg 06/06/16 First release
45 * 1.3 vak 04/03/17 Added CCI support for USB
46 * 1.4 bk 12/01/18 Modify USBPSU driver code to fit USB common example code
51 *****************************************************************************/
53 /***************************** Include Files *********************************/
54 #include "xusbpsu_endpoint.h"
56 #include "xusb_wrapper.h"
58 /************************** Constant Definitions *****************************/
60 /**************************** Type Definitions *******************************/
62 /***************** Macros (Inline Functions) Definitions *********************/
64 /************************** Function Prototypes ******************************/
66 /************************** Variable Definitions *****************************/
68 /****************************************************************************/
70 * Initiates DMA on Control Endpoint 0 to receive Setup packet.
72 * @param InstancePtr is a pointer to the XUsbPsu instance.
74 * @return XST_SUCCESS else XST_FAILURE.
78 *****************************************************************************/
79 s32 XUsbPsu_RecvSetup(struct XUsbPsu *InstancePtr)
81 struct XUsbPsu_EpParams *Params;
82 struct XUsbPsu_Trb *TrbPtr;
83 struct XUsbPsu_Ep *Ept;
86 Xil_AssertNonvoid(InstancePtr != NULL);
88 Params = XUsbPsu_GetEpParams(InstancePtr);
89 Xil_AssertNonvoid(Params != NULL);
91 /* Setup packet always on EP0 */
92 Ept = &InstancePtr->eps[0];
93 if ((Ept->EpStatus & XUSBPSU_EP_BUSY) != 0U) {
94 return (s32)XST_FAILURE;
97 TrbPtr = &InstancePtr->Ep0_Trb;
99 TrbPtr->BufferPtrLow = (UINTPTR)&InstancePtr->SetupData;
100 TrbPtr->BufferPtrHigh = ((UINTPTR)&InstancePtr->SetupData >> 16) >> 16;
102 TrbPtr->Ctrl = XUSBPSU_TRBCTL_CONTROL_SETUP;
104 TrbPtr->Ctrl |= (XUSBPSU_TRB_CTRL_HWO
105 | XUSBPSU_TRB_CTRL_LST
106 | XUSBPSU_TRB_CTRL_IOC
107 | XUSBPSU_TRB_CTRL_ISP_IMI);
109 if (InstancePtr->ConfigPtr->IsCacheCoherent == 0) {
110 Xil_DCacheFlushRange((INTPTR)TrbPtr, sizeof(struct XUsbPsu_Trb));
111 Xil_DCacheFlushRange((UINTPTR)&InstancePtr->SetupData, sizeof(SetupPacket));
115 Params->Param1 = (UINTPTR)TrbPtr;
117 InstancePtr->Ep0State = XUSBPSU_EP0_SETUP_PHASE;
119 Ret = XUsbPsu_SendEpCmd(InstancePtr, 0U, XUSBPSU_EP_DIR_OUT,
120 XUSBPSU_DEPCMD_STARTTRANSFER, Params);
121 if (Ret != XST_SUCCESS) {
122 return (s32)XST_FAILURE;
125 Ept->EpStatus |= XUSBPSU_EP_BUSY;
126 Ept->ResourceIndex = (u8)XUsbPsu_EpGetTransferIndex(InstancePtr,
127 Ept->UsbEpNum, Ept->Direction);
132 /****************************************************************************/
134 * Stalls Control Endpoint and restarts to receive Setup packet.
136 * @param InstancePtr is a pointer to the XUsbPsu instance.
142 *****************************************************************************/
143 void XUsbPsu_Ep0StallRestart(struct XUsbPsu *InstancePtr)
145 struct XUsbPsu_Ep *Ept;
147 Xil_AssertVoid(InstancePtr != NULL);
149 /* reinitialize physical ep1 */
150 Ept = &InstancePtr->eps[1];
151 Ept->EpStatus = XUSBPSU_EP_ENABLED;
153 /* stall is always issued on EP0 */
154 XUsbPsu_EpSetStall(InstancePtr, 0U, XUSBPSU_EP_DIR_OUT);
156 Ept = &InstancePtr->eps[0];
157 Ept->EpStatus = XUSBPSU_EP_ENABLED;
158 InstancePtr->Ep0State = XUSBPSU_EP0_SETUP_PHASE;
159 (void)XUsbPsu_RecvSetup(InstancePtr);
162 /****************************************************************************/
164 * Checks the Data Phase and calls user Endpoint handler.
166 * @param InstancePtr is a pointer to the XUsbPsu instance.
167 * @param Event is a pointer to the Endpoint event occured in core.
173 *****************************************************************************/
174 void XUsbPsu_Ep0DataDone(struct XUsbPsu *InstancePtr,
175 const struct XUsbPsu_Event_Epevt *Event)
177 struct XUsbPsu_Ep *Ept;
178 struct XUsbPsu_Trb *TrbPtr;
184 Xil_AssertVoid(InstancePtr != NULL);
185 Xil_AssertVoid(Event != NULL);
187 Epnum = Event->Epnumber;
189 Ept = &InstancePtr->eps[Epnum];
190 TrbPtr = &InstancePtr->Ep0_Trb;
192 if (InstancePtr->ConfigPtr->IsCacheCoherent == 0)
193 Xil_DCacheInvalidateRange((INTPTR)TrbPtr, sizeof(struct XUsbPsu_Trb));
195 Status = XUSBPSU_TRB_SIZE_TRBSTS(TrbPtr->Size);
196 if (Status == XUSBPSU_TRBSTS_SETUP_PENDING) {
200 Length = TrbPtr->Size & XUSBPSU_TRB_SIZE_MASK;
203 Ept->BytesTxed = Ept->RequestedBytes;
205 if (Dir == XUSBPSU_EP_DIR_IN) {
206 Ept->BytesTxed = Ept->RequestedBytes - Length;
208 if ((Dir == XUSBPSU_EP_DIR_OUT) && (Ept->UnalignedTx == 1U)) {
209 Ept->BytesTxed = Ept->RequestedBytes;
210 Ept->UnalignedTx = 0U;
215 if (Dir == XUSBPSU_EP_DIR_OUT) {
216 /* Invalidate Cache */
217 if (InstancePtr->ConfigPtr->IsCacheCoherent == 0)
218 Xil_DCacheInvalidateRange((INTPTR)Ept->BufferPtr, Ept->BytesTxed);
221 if (Ept->Handler != NULL) {
222 Ept->Handler(InstancePtr->AppData, Ept->RequestedBytes, Ept->BytesTxed);
226 /****************************************************************************/
228 * Checks the Status Phase and starts next Control transfer.
230 * @param InstancePtr is a pointer to the XUsbPsu instance.
231 * @param Event is a pointer to the Endpoint event occured in core.
237 *****************************************************************************/
238 void XUsbPsu_Ep0StatusDone(struct XUsbPsu *InstancePtr,
239 const struct XUsbPsu_Event_Epevt *Event)
241 struct XUsbPsu_Trb *TrbPtr;
243 Xil_AssertVoid(InstancePtr != NULL);
244 Xil_AssertVoid(Event != NULL);
246 TrbPtr = &InstancePtr->Ep0_Trb;
248 if (InstancePtr->IsInTestMode != 0U) {
251 Ret = XUsbPsu_SetTestMode(InstancePtr,
252 InstancePtr->TestMode);
254 XUsbPsu_Ep0StallRestart(InstancePtr);
258 if (InstancePtr->ConfigPtr->IsCacheCoherent == 0)
259 Xil_DCacheInvalidateRange((INTPTR)TrbPtr, sizeof(struct XUsbPsu_Trb));
261 (void)XUsbPsu_RecvSetup(InstancePtr);
264 /****************************************************************************/
266 * Handles Transfer complete event of Control Endpoints EP0 OUT and EP0 IN.
268 * @param InstancePtr is a pointer to the XUsbPsu instance.
269 * @param Event is a pointer to the Endpoint event occured in core.
275 *****************************************************************************/
276 void XUsbPsu_Ep0XferComplete(struct XUsbPsu *InstancePtr,
277 const struct XUsbPsu_Event_Epevt *Event)
279 struct XUsbPsu_Ep *Ept;
283 Xil_AssertVoid(InstancePtr != NULL);
284 Xil_AssertVoid(Event != NULL);
286 Ept = &InstancePtr->eps[Event->Epnumber];
287 Ctrl = &InstancePtr->SetupData;
289 Ept->EpStatus &= ~XUSBPSU_EP_BUSY;
290 Ept->ResourceIndex = 0U;
292 switch (InstancePtr->Ep0State) {
293 case XUSBPSU_EP0_SETUP_PHASE:
294 if (InstancePtr->ConfigPtr->IsCacheCoherent == 0) {
295 Xil_DCacheInvalidateRange((INTPTR)&InstancePtr->SetupData,
296 sizeof(InstancePtr->SetupData));
298 Length = Ctrl->wLength;
300 InstancePtr->IsThreeStage = 0U;
301 InstancePtr->ControlDir = XUSBPSU_EP_DIR_OUT;
303 InstancePtr->IsThreeStage = 1U;
304 InstancePtr->ControlDir = !!(Ctrl->bRequestType &
308 Xil_AssertVoid(InstancePtr->Chapter9 != NULL);
310 InstancePtr->Chapter9(InstancePtr->AppData,
311 &InstancePtr->SetupData);
314 case XUSBPSU_EP0_DATA_PHASE:
315 XUsbPsu_Ep0DataDone(InstancePtr, Event);
318 case XUSBPSU_EP0_STATUS_PHASE:
319 XUsbPsu_Ep0StatusDone(InstancePtr, Event);
323 /* Default case is a required MISRA-C guideline. */
328 /****************************************************************************/
330 * Starts Status Phase of Control Transfer
332 * @param InstancePtr is a pointer to the XUsbPsu instance.
333 * @param Event is a pointer to the Endpoint event occured in core.
335 * @return XST_SUCCESS else XST_FAILURE
339 *****************************************************************************/
340 s32 XUsbPsu_Ep0StartStatus(struct XUsbPsu *InstancePtr,
341 const struct XUsbPsu_Event_Epevt *Event)
343 struct XUsbPsu_Ep *Ept;
344 struct XUsbPsu_EpParams *Params;
345 struct XUsbPsu_Trb *TrbPtr;
350 Xil_AssertNonvoid(InstancePtr != NULL);
351 Xil_AssertNonvoid(Event != NULL);
353 Ept = &InstancePtr->eps[Event->Epnumber];
354 Params = XUsbPsu_GetEpParams(InstancePtr);
355 Xil_AssertNonvoid(Params != NULL);
356 if ((Ept->EpStatus & XUSBPSU_EP_BUSY) != 0U) {
357 return (s32)XST_FAILURE;
360 Type = (InstancePtr->IsThreeStage != 0U) ? XUSBPSU_TRBCTL_CONTROL_STATUS3
361 : XUSBPSU_TRBCTL_CONTROL_STATUS2;
362 TrbPtr = &InstancePtr->Ep0_Trb;
363 /* we use same TrbPtr for setup packet */
364 TrbPtr->BufferPtrLow = (UINTPTR)&InstancePtr->SetupData;
365 TrbPtr->BufferPtrHigh = ((UINTPTR)&InstancePtr->SetupData >> 16) >> 16;
369 TrbPtr->Ctrl |= (XUSBPSU_TRB_CTRL_HWO
370 | XUSBPSU_TRB_CTRL_LST
371 | XUSBPSU_TRB_CTRL_IOC
372 | XUSBPSU_TRB_CTRL_ISP_IMI);
374 if (InstancePtr->ConfigPtr->IsCacheCoherent == 0) {
375 Xil_DCacheFlushRange((INTPTR)TrbPtr, sizeof(struct XUsbPsu_Trb));
379 Params->Param1 = (UINTPTR)TrbPtr;
381 InstancePtr->Ep0State = XUSBPSU_EP0_STATUS_PHASE;
384 * Control OUT transfer - Status stage happens on EP0 IN - EP1
385 * Control IN transfer - Status stage happens on EP0 OUT - EP0
387 Dir = !InstancePtr->ControlDir;
389 Ret = XUsbPsu_SendEpCmd(InstancePtr, 0U, Dir,
390 XUSBPSU_DEPCMD_STARTTRANSFER, Params);
391 if (Ret != XST_SUCCESS) {
392 return (s32)XST_FAILURE;
395 Ept->EpStatus |= XUSBPSU_EP_BUSY;
396 Ept->ResourceIndex = (u8)XUsbPsu_EpGetTransferIndex(InstancePtr,
397 Ept->UsbEpNum, Ept->Direction);
402 /****************************************************************************/
404 * Ends Data Phase - used incase of error.
406 * @param InstancePtr is a pointer to the XUsbPsu instance.
407 * @param Dep is a pointer to the Endpoint structure.
413 *****************************************************************************/
414 void XUsbPsu_Ep0_EndControlData(struct XUsbPsu *InstancePtr,
415 struct XUsbPsu_Ep *Ept)
417 struct XUsbPsu_EpParams *Params;
420 Xil_AssertVoid(InstancePtr != NULL);
421 Xil_AssertVoid(Ept != NULL);
423 if (Ept->ResourceIndex == 0U) {
427 Params = XUsbPsu_GetEpParams(InstancePtr);
428 Xil_AssertVoid(Params != NULL);
430 Cmd = XUSBPSU_DEPCMD_ENDTRANSFER;
431 Cmd |= XUSBPSU_DEPCMD_PARAM(Ept->ResourceIndex);
432 (void)XUsbPsu_SendEpCmd(InstancePtr, Ept->UsbEpNum, Ept->Direction,
434 Ept->ResourceIndex = 0U;
438 /****************************************************************************/
440 * Handles Transfer Not Ready event of Control Endpoints EP0 OUT and EP0 IN.
442 * @param InstancePtr is a pointer to the XUsbPsu instance.
443 * @param Event is a pointer to the Endpoint event occured in core.
449 *****************************************************************************/
450 void XUsbPsu_Ep0XferNotReady(struct XUsbPsu *InstancePtr,
451 const struct XUsbPsu_Event_Epevt *Event)
453 struct XUsbPsu_Ep *Ept;
455 Xil_AssertVoid(InstancePtr != NULL);
456 Xil_AssertVoid(Event != NULL);
458 Ept = &InstancePtr->eps[Event->Epnumber];
460 switch (Event->Status) {
461 case DEPEVT_STATUS_CONTROL_DATA:
463 * We already have a DATA transfer in the controller's cache,
464 * if we receive a XferNotReady(DATA) we will ignore it, unless
465 * it's for the wrong direction.
467 * In that case, we must issue END_TRANSFER command to the Data
468 * Phase we already have started and issue SetStall on the
471 if (Event->Epnumber != InstancePtr->ControlDir) {
472 XUsbPsu_Ep0_EndControlData(InstancePtr, Ept);
473 XUsbPsu_Ep0StallRestart(InstancePtr);
477 case DEPEVT_STATUS_CONTROL_STATUS:
478 (void)XUsbPsu_Ep0StartStatus(InstancePtr, Event);
482 /* Default case is a required MIRSA-C guideline. */
487 /****************************************************************************/
489 * Handles Interrupts of Control Endpoints EP0 OUT and EP0 IN.
491 * @param InstancePtr is a pointer to the XUsbPsu instance.
492 * @param Event is a pointer to the Endpoint event occured in core.
498 *****************************************************************************/
499 void XUsbPsu_Ep0Intr(struct XUsbPsu *InstancePtr,
500 const struct XUsbPsu_Event_Epevt *Event)
503 Xil_AssertVoid(InstancePtr != NULL);
504 Xil_AssertVoid(Event != NULL);
506 switch (Event->Endpoint_Event) {
507 case XUSBPSU_DEPEVT_XFERCOMPLETE:
508 XUsbPsu_Ep0XferComplete(InstancePtr, Event);
511 case XUSBPSU_DEPEVT_XFERNOTREADY:
512 XUsbPsu_Ep0XferNotReady(InstancePtr, Event);
515 case XUSBPSU_DEPEVT_XFERINPROGRESS:
516 case XUSBPSU_DEPEVT_STREAMEVT:
517 case XUSBPSU_DEPEVT_EPCMDCMPLT:
521 /* Default case is a required MIRSA-C guideline. */
526 /****************************************************************************/
528 * Initiates DMA to send data on Control Endpoint EP0 IN to Host.
530 * @param InstancePtr is a pointer to the XUsbPsu instance.
531 * @param BufferPtr is pointer to data.
532 * @param BufferLen is Length of data buffer.
534 * @return XST_SUCCESS else XST_FAILURE
538 *****************************************************************************/
539 s32 XUsbPsu_Ep0Send(struct XUsbPsu *InstancePtr, u8 *BufferPtr, u32 BufferLen)
541 /* Control IN - EP1 */
542 struct XUsbPsu_EpParams *Params;
543 struct XUsbPsu_Ep *Ept;
544 struct XUsbPsu_Trb *TrbPtr;
547 Xil_AssertNonvoid(InstancePtr != NULL);
548 Xil_AssertNonvoid(BufferPtr != NULL);
550 Ept = &InstancePtr->eps[1];
551 Params = XUsbPsu_GetEpParams(InstancePtr);
552 Xil_AssertNonvoid(Params != NULL);
554 if ((Ept->EpStatus & XUSBPSU_EP_BUSY) != 0U) {
555 return (s32)XST_FAILURE;
558 Ept->RequestedBytes = BufferLen;
560 Ept->BufferPtr = BufferPtr;
562 TrbPtr = &InstancePtr->Ep0_Trb;
564 TrbPtr->BufferPtrLow = (UINTPTR)BufferPtr;
565 TrbPtr->BufferPtrHigh = ((UINTPTR)BufferPtr >> 16) >> 16;
566 TrbPtr->Size = BufferLen;
567 TrbPtr->Ctrl = XUSBPSU_TRBCTL_CONTROL_DATA;
569 TrbPtr->Ctrl |= (XUSBPSU_TRB_CTRL_HWO
570 | XUSBPSU_TRB_CTRL_LST
571 | XUSBPSU_TRB_CTRL_IOC
572 | XUSBPSU_TRB_CTRL_ISP_IMI);
575 Params->Param1 = (UINTPTR)TrbPtr;
577 if (InstancePtr->ConfigPtr->IsCacheCoherent == 0) {
578 Xil_DCacheFlushRange((INTPTR)TrbPtr, sizeof(struct XUsbPsu_Trb));
579 Xil_DCacheFlushRange((INTPTR)BufferPtr, BufferLen);
582 InstancePtr->Ep0State = XUSBPSU_EP0_DATA_PHASE;
584 Ret = XUsbPsu_SendEpCmd(InstancePtr, 0U, XUSBPSU_EP_DIR_IN,
585 XUSBPSU_DEPCMD_STARTTRANSFER, Params);
586 if (Ret != XST_SUCCESS) {
587 return (s32)XST_FAILURE;
590 Ept->EpStatus |= XUSBPSU_EP_BUSY;
591 Ept->ResourceIndex = (u8)XUsbPsu_EpGetTransferIndex(InstancePtr,
592 Ept->UsbEpNum, Ept->Direction);
597 /****************************************************************************/
599 * Initiates DMA to receive data on Control Endpoint EP0 OUT from Host.
601 * @param InstancePtr is a pointer to the XUsbPsu instance.
602 * @param BufferPtr is pointer to data.
603 * @param Length is Length of data to be received.
605 * @return XST_SUCCESS else XST_FAILURE
609 *****************************************************************************/
610 s32 XUsbPsu_Ep0Recv(struct XUsbPsu *InstancePtr, u8 *BufferPtr, u32 Length)
612 struct XUsbPsu_EpParams *Params;
613 struct XUsbPsu_Ep *Ept;
614 struct XUsbPsu_Trb *TrbPtr;
618 Xil_AssertNonvoid(InstancePtr != NULL);
619 Xil_AssertNonvoid(BufferPtr != NULL);
621 Ept = &InstancePtr->eps[0];
622 Params = XUsbPsu_GetEpParams(InstancePtr);
623 Xil_AssertNonvoid(Params != NULL);
625 if ((Ept->EpStatus & XUSBPSU_EP_BUSY) != 0U) {
626 return (s32)XST_FAILURE;
629 Ept->RequestedBytes = Length;
632 Ept->BufferPtr = BufferPtr;
635 * 8.2.5 - An OUT transfer size (Total TRB buffer allocation)
636 * must be a multiple of MaxPacketSize even if software is expecting a
637 * fixed non-multiple of MaxPacketSize transfer from the Host.
639 if (!IS_ALIGNED(Length, Ept->MaxSize)) {
640 Size = (u32)roundup(Length, Ept->MaxSize);
641 Ept->UnalignedTx = 1U;
644 TrbPtr = &InstancePtr->Ep0_Trb;
646 TrbPtr->BufferPtrLow = (UINTPTR)BufferPtr;
647 TrbPtr->BufferPtrHigh = ((UINTPTR)BufferPtr >> 16) >> 16;
649 TrbPtr->Ctrl = XUSBPSU_TRBCTL_CONTROL_DATA;
651 TrbPtr->Ctrl |= (XUSBPSU_TRB_CTRL_HWO
652 | XUSBPSU_TRB_CTRL_LST
653 | XUSBPSU_TRB_CTRL_IOC
654 | XUSBPSU_TRB_CTRL_ISP_IMI);
656 if (InstancePtr->ConfigPtr->IsCacheCoherent == 0) {
657 Xil_DCacheFlushRange((INTPTR)TrbPtr, sizeof(struct XUsbPsu_Trb));
658 Xil_DCacheInvalidateRange((INTPTR)BufferPtr, Length);
662 Params->Param1 = (UINTPTR)TrbPtr;
664 InstancePtr->Ep0State = XUSBPSU_EP0_DATA_PHASE;
666 Ret = XUsbPsu_SendEpCmd(InstancePtr, 0U, XUSBPSU_EP_DIR_OUT,
667 XUSBPSU_DEPCMD_STARTTRANSFER, Params);
668 if (Ret != XST_SUCCESS) {
669 return (s32)XST_FAILURE;
672 Ept->EpStatus |= XUSBPSU_EP_BUSY;
673 Ept->ResourceIndex = (u8)XUsbPsu_EpGetTransferIndex(InstancePtr,
674 Ept->UsbEpNum, Ept->Direction);
679 /*****************************************************************************/
682 * API for Sleep routine.
684 * @param USeconds is time in MicroSeconds.
690 ******************************************************************************/
691 void XUsbSleep(u32 USeconds) {
692 (void)usleep(USeconds);