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_endpoint.c
36 * @addtogroup usbpsu_v1_3
41 * MODIFICATION HISTORY:
43 * Ver Who Date Changes
44 * ----- ---- -------- -------------------------------------------------------
45 * 1.0 sg 06/06/16 First release
46 * 1.3 vak 04/03/17 Added CCI support for USB
47 * 1.4 bk 12/01/18 Modify USBPSU driver code to fit USB common example code
49 * myk 12/01/18 Added hibernation support for device mode
52 *****************************************************************************/
54 /***************************** Include Files *********************************/
55 #include "xusbpsu_endpoint.h"
57 /************************** Constant Definitions *****************************/
59 /**************************** Type Definitions *******************************/
61 /***************** Macros (Inline Functions) Definitions *********************/
63 /************************** Function Prototypes ******************************/
65 /************************** Variable Definitions *****************************/
67 /****************************************************************************/
69 * Returns zeroed parameters to be used by Endpoint commands
71 * @param InstancePtr is a pointer to the XUsbPsu instance.
73 * @return Zeroed Params structure pointer.
77 *****************************************************************************/
78 struct XUsbPsu_EpParams *XUsbPsu_GetEpParams(struct XUsbPsu *InstancePtr)
80 if (InstancePtr == NULL) {
84 InstancePtr->EpParams.Param0 = 0x00U;
85 InstancePtr->EpParams.Param1 = 0x00U;
86 InstancePtr->EpParams.Param2 = 0x00U;
88 return &InstancePtr->EpParams;
91 /****************************************************************************/
93 * Returns Transfer Index assigned by Core for an Endpoint transfer.
95 * @param InstancePtr is a pointer to the XUsbPsu instance.
96 * @param UsbEpNum is USB endpoint number.
97 * @param Dir is direction of endpoint - XUSBPSU_EP_DIR_IN/XUSBPSU_EP_DIR_OUT
99 * @return Transfer Resource Index.
103 *****************************************************************************/
104 u32 XUsbPsu_EpGetTransferIndex(struct XUsbPsu *InstancePtr, u8 UsbEpNum,
110 Xil_AssertNonvoid(InstancePtr != NULL);
111 Xil_AssertNonvoid(UsbEpNum <= (u8)16U);
112 Xil_AssertNonvoid((Dir == XUSBPSU_EP_DIR_IN) ||
113 (Dir == XUSBPSU_EP_DIR_OUT));
115 PhyEpNum = (u8)PhysicalEp(UsbEpNum, Dir);
116 ResourceIndex = XUsbPsu_ReadReg(InstancePtr, XUSBPSU_DEPCMD(PhyEpNum));
118 return (u32)XUSBPSU_DEPCMD_GET_RSC_IDX(ResourceIndex);
121 /****************************************************************************/
123 * Sends Endpoint command to Endpoint.
125 * @param InstancePtr is a pointer to the XUsbPsu instance.
126 * @param UsbEpNum is USB endpoint number.
127 * @param Dir is direction of endpoint
128 * - XUSBPSU_EP_DIR_IN/ XUSBPSU_EP_DIR_OUT.
129 * @param Cmd is Endpoint command.
130 * @param Params is Endpoint command parameters.
132 * @return XST_SUCCESS else XST_FAILURE.
136 *****************************************************************************/
137 s32 XUsbPsu_SendEpCmd(struct XUsbPsu *InstancePtr, u8 UsbEpNum, u8 Dir,
138 u32 Cmd, struct XUsbPsu_EpParams *Params)
142 Xil_AssertNonvoid(InstancePtr != NULL);
143 Xil_AssertNonvoid(UsbEpNum <= (u8)16U);
144 Xil_AssertNonvoid((Dir == XUSBPSU_EP_DIR_IN) ||
145 (Dir == XUSBPSU_EP_DIR_OUT));
147 PhyEpNum = PhysicalEp(UsbEpNum, Dir);
149 XUsbPsu_WriteReg(InstancePtr, XUSBPSU_DEPCMDPAR0(PhyEpNum),
151 XUsbPsu_WriteReg(InstancePtr, XUSBPSU_DEPCMDPAR1(PhyEpNum),
153 XUsbPsu_WriteReg(InstancePtr, XUSBPSU_DEPCMDPAR2(PhyEpNum),
156 XUsbPsu_WriteReg(InstancePtr, XUSBPSU_DEPCMD(PhyEpNum),
157 Cmd | XUSBPSU_DEPCMD_CMDACT);
159 if (XUsbPsu_Wait_Clear_Timeout(InstancePtr, XUSBPSU_DEPCMD(PhyEpNum),
160 XUSBPSU_DEPCMD_CMDACT, 500U) == (s32)XST_FAILURE) {
167 /****************************************************************************/
169 * Sends Start New Configuration command to Endpoint.
171 * @param InstancePtr is a pointer to the XUsbPsu instance.
172 * @param UsbEpNum is USB endpoint number.
173 * @param Dir is direction of endpoint
174 * - XUSBPSU_EP_DIR_IN/ XUSBPSU_EP_DIR_OUT.
176 * @return XST_SUCCESS else XST_FAILURE.
179 * As per data book this command should be issued by software
180 * under these conditions:
181 * 1. After power-on-reset with XferRscIdx=0 before starting
182 * to configure Physical Endpoints 0 and 1.
183 * 2. With XferRscIdx=2 before starting to configure
184 * Physical Endpoints > 1
185 * 3. This command should always be issued to
186 * Endpoint 0 (DEPCMD0).
188 *****************************************************************************/
189 s32 XUsbPsu_StartEpConfig(struct XUsbPsu *InstancePtr, u32 UsbEpNum, u8 Dir)
191 struct XUsbPsu_EpParams *Params;
195 Xil_AssertNonvoid(InstancePtr != NULL);
196 Xil_AssertNonvoid(UsbEpNum <= (u32)16U);
197 Xil_AssertNonvoid((Dir == XUSBPSU_EP_DIR_IN) ||
198 (Dir == XUSBPSU_EP_DIR_OUT));
200 PhyEpNum = (u8)PhysicalEp(UsbEpNum, (u32)Dir);
201 Params = XUsbPsu_GetEpParams(InstancePtr);
202 Xil_AssertNonvoid(Params != NULL);
204 if (PhyEpNum != 1U) {
205 Cmd = XUSBPSU_DEPCMD_DEPSTARTCFG;
206 /* XferRscIdx == 0 for EP0 and 2 for the remaining */
208 if (InstancePtr->IsConfigDone != 0U) {
211 InstancePtr->IsConfigDone = 1U;
212 Cmd |= XUSBPSU_DEPCMD_PARAM(2);
215 return XUsbPsu_SendEpCmd(InstancePtr, 0U, XUSBPSU_EP_DIR_OUT,
222 /****************************************************************************/
224 * Sends Set Endpoint Configuration command to Endpoint.
226 * @param InstancePtr is a pointer to the XUsbPsu instance.
227 * @param UsbEpNum is USB endpoint number.
228 * @param Dir is direction of endpoint - XUSBPSU_EP_DIR_IN/XUSBPSU_EP_DIR_OUT.
229 * @param Size is size of Endpoint size.
230 * @param Type is Endpoint type Control/Bulk/Interrupt/Isoc.
231 * @param Restore should be true if saved state should be restored;
232 * typically this would be false
234 * @return XST_SUCCESS else XST_FAILURE.
238 *****************************************************************************/
239 s32 XUsbPsu_SetEpConfig(struct XUsbPsu *InstancePtr, u8 UsbEpNum, u8 Dir,
240 u16 Size, u8 Type, u8 Restore)
242 struct XUsbPsu_Ep *Ept;
243 struct XUsbPsu_EpParams *Params;
246 Xil_AssertNonvoid(InstancePtr != NULL);
247 Xil_AssertNonvoid(UsbEpNum <= (u8)16U);
248 Xil_AssertNonvoid((Dir == XUSBPSU_EP_DIR_IN) ||
249 (Dir == XUSBPSU_EP_DIR_OUT));
250 Xil_AssertNonvoid((Size >= 64U) && (Size <= 1024U));
252 Params = XUsbPsu_GetEpParams(InstancePtr);
253 Xil_AssertNonvoid(Params != NULL);
255 PhyEpNum = PhysicalEp(UsbEpNum , Dir);
256 Ept = &InstancePtr->eps[PhyEpNum];
258 Params->Param0 = XUSBPSU_DEPCFG_EP_TYPE(Type)
259 | XUSBPSU_DEPCFG_MAX_PACKET_SIZE(Size);
262 * Set burst size to 1 as recommended
264 if (InstancePtr->AppData->Speed == XUSBPSU_SPEED_SUPER) {
265 Params->Param0 |= XUSBPSU_DEPCFG_BURST_SIZE(1);
268 Params->Param1 = XUSBPSU_DEPCFG_XFER_COMPLETE_EN
269 | XUSBPSU_DEPCFG_XFER_NOT_READY_EN;
272 Params->Param0 |= XUSBPSU_DEPCFG_ACTION_RESTORE;
273 Params->Param2 = Ept->EpSavedState;
277 * We are doing 1:1 mapping for endpoints, meaning
278 * Physical Endpoints 2 maps to Logical Endpoint 2 and
279 * so on. We consider the direction bit as part of the physical
280 * endpoint number. So USB endpoint 0x81 is 0x03.
282 Params->Param1 |= XUSBPSU_DEPCFG_EP_NUMBER(PhyEpNum);
284 if (Dir != XUSBPSU_EP_DIR_OUT) {
285 Params->Param0 |= XUSBPSU_DEPCFG_FIFO_NUMBER((u32)PhyEpNum >> 1);
288 if (Ept->Type == XUSBPSU_ENDPOINT_XFER_ISOC) {
289 Params->Param1 |= XUSBPSU_DEPCFG_BINTERVAL_M1(Ept->Interval - 1);
290 Params->Param1 |= XUSBPSU_DEPCFG_XFER_IN_PROGRESS_EN;
293 return XUsbPsu_SendEpCmd(InstancePtr, UsbEpNum, Dir,
294 XUSBPSU_DEPCMD_SETEPCONFIG, Params);
297 /****************************************************************************/
299 * Sends Set Transfer Resource command to Endpoint.
301 * @param InstancePtr is a pointer to the XUsbPsu instance.
302 * @param UsbEpNum is USB endpoint number.
303 * @param Dir is direction of endpoint - XUSBPSU_EP_DIR_IN/
304 * XUSBPSU_EP_DIR_OUT.
306 * @return XST_SUCCESS else XST_FAILURE.
310 *****************************************************************************/
311 s32 XUsbPsu_SetXferResource(struct XUsbPsu *InstancePtr, u8 UsbEpNum, u8 Dir)
313 struct XUsbPsu_EpParams *Params;
316 Xil_AssertNonvoid(InstancePtr != NULL);
317 Xil_AssertNonvoid(UsbEpNum <= (u8)16U);
318 Xil_AssertNonvoid((Dir == XUSBPSU_EP_DIR_IN) ||
319 (Dir == XUSBPSU_EP_DIR_OUT));
321 Params = XUsbPsu_GetEpParams(InstancePtr);
322 Xil_AssertNonvoid(Params != NULL);
324 Params->Param0 = XUSBPSU_DEPXFERCFG_NUM_XFER_RES(1);
326 return XUsbPsu_SendEpCmd(InstancePtr, UsbEpNum, Dir,
327 XUSBPSU_DEPCMD_SETTRANSFRESOURCE, Params);
330 /****************************************************************************/
332 * Enables Endpoint for sending/receiving data.
334 * @param InstancePtr is a pointer to the XUsbPsu instance.
335 * @param UsbEpNum is USB endpoint number.
336 * @param Dir is direction of endpoint - XUSBPSU_EP_DIR_IN/XUSBPSU_EP_DIR_OUT.
337 * @param Maxsize is size of Endpoint size.
338 * @param Type is Endpoint type Control/Bulk/Interrupt/Isoc.
339 * @param Restore should be true if saved state should be restored;
340 * typically this would be false
342 * @return XST_SUCCESS else XST_FAILURE.
346 ****************************************************************************/
347 s32 XUsbPsu_EpEnable(struct XUsbPsu *InstancePtr, u8 UsbEpNum, u8 Dir,
348 u16 Maxsize, u8 Type, u8 Restore)
350 struct XUsbPsu_Ep *Ept;
351 struct XUsbPsu_Trb *TrbStHw, *TrbLink;
353 s32 Ret = (s32)XST_FAILURE;
356 Xil_AssertNonvoid(InstancePtr != NULL);
357 Xil_AssertNonvoid(UsbEpNum <= (u8)16U);
358 Xil_AssertNonvoid((Dir == XUSBPSU_EP_DIR_IN) ||
359 (Dir == XUSBPSU_EP_DIR_OUT));
360 Xil_AssertNonvoid((Maxsize >= 64U) && (Maxsize <= 1024U));
362 PhyEpNum = PhysicalEp(UsbEpNum , Dir);
363 Ept = &InstancePtr->eps[PhyEpNum];
365 Ept->UsbEpNum = UsbEpNum;
366 Ept->Direction = Dir;
368 Ept->MaxSize = Maxsize;
369 Ept->PhyEpNum = (u8)PhyEpNum;
371 if (!InstancePtr->IsHibernated) {
376 if (((Ept->EpStatus & XUSBPSU_EP_ENABLED) == 0U)
377 || (InstancePtr->IsHibernated)) {
378 Ret = XUsbPsu_StartEpConfig(InstancePtr, UsbEpNum, Dir);
384 Ret = XUsbPsu_SetEpConfig(InstancePtr, UsbEpNum, Dir, Maxsize,
390 if (((Ept->EpStatus & XUSBPSU_EP_ENABLED) == 0U)
391 || (InstancePtr->IsHibernated)) {
392 Ret = XUsbPsu_SetXferResource(InstancePtr, UsbEpNum, Dir);
397 Ept->EpStatus |= XUSBPSU_EP_ENABLED;
399 RegVal = XUsbPsu_ReadReg(InstancePtr, XUSBPSU_DALEPENA);
400 RegVal |= XUSBPSU_DALEPENA_EP(Ept->PhyEpNum);
401 XUsbPsu_WriteReg(InstancePtr, XUSBPSU_DALEPENA, RegVal);
403 /* Following code is only applicable for ISO XFER */
404 TrbStHw = &Ept->EpTrb[0];
406 /* Link TRB. The HWO bit is never reset */
407 TrbLink = &Ept->EpTrb[NO_OF_TRB_PER_EP];
408 memset(TrbLink, 0x00, sizeof(struct XUsbPsu_Trb));
410 TrbLink->BufferPtrLow = (UINTPTR)TrbStHw;
411 TrbLink->BufferPtrHigh = ((UINTPTR)TrbStHw >> 16) >> 16;
412 TrbLink->Ctrl |= XUSBPSU_TRBCTL_LINK_TRB;
413 TrbLink->Ctrl |= XUSBPSU_TRB_CTRL_HWO;
419 /****************************************************************************/
423 * @param InstancePtr is a pointer to the XUsbPsu instance.
424 * @param UsbEpNum is USB endpoint number.
425 * @param Dir is direction of endpoint
426 * - XUSBPSU_EP_DIR_IN/XUSBPSU_EP_DIR_OUT.
428 * @return XST_SUCCESS else XST_FAILURE.
432 ****************************************************************************/
433 s32 XUsbPsu_EpDisable(struct XUsbPsu *InstancePtr, u8 UsbEpNum, u8 Dir)
437 struct XUsbPsu_Ep *Ept;
439 Xil_AssertNonvoid(InstancePtr != NULL);
440 Xil_AssertNonvoid(UsbEpNum <= (u8)16U);
441 Xil_AssertNonvoid((Dir == XUSBPSU_EP_DIR_IN) ||
442 (Dir == XUSBPSU_EP_DIR_OUT));
444 PhyEpNum = PhysicalEp(UsbEpNum , Dir);
445 Ept = &InstancePtr->eps[PhyEpNum];
447 /* make sure HW endpoint isn't stalled */
448 if (Ept->EpStatus & XUSBPSU_EP_STALL)
449 XUsbPsu_EpClearStall(InstancePtr, Ept->UsbEpNum, Ept->Direction);
451 RegVal = XUsbPsu_ReadReg(InstancePtr, XUSBPSU_DALEPENA);
452 RegVal &= ~XUSBPSU_DALEPENA_EP(PhyEpNum);
453 XUsbPsu_WriteReg(InstancePtr, XUSBPSU_DALEPENA, RegVal);
458 Ept->TrbEnqueue = 0U;
459 Ept->TrbDequeue = 0U;
464 /****************************************************************************/
466 * Enables USB Control Endpoint i.e., EP0OUT and EP0IN of Core.
468 * @param InstancePtr is a pointer to the XUsbPsu instance.
469 * @param Size is control endpoint size.
471 * @return XST_SUCCESS else XST_FAILURE.
475 ****************************************************************************/
476 s32 XUsbPsu_EnableControlEp(struct XUsbPsu *InstancePtr, u16 Size)
480 Xil_AssertNonvoid(InstancePtr != NULL);
481 Xil_AssertNonvoid((Size >= 64U) && (Size <= 512U));
483 RetVal = XUsbPsu_EpEnable(InstancePtr, 0U, XUSBPSU_EP_DIR_OUT, Size,
484 XUSBPSU_ENDPOINT_XFER_CONTROL, FALSE);
489 RetVal = XUsbPsu_EpEnable(InstancePtr, 0U, XUSBPSU_EP_DIR_IN, Size,
490 XUSBPSU_ENDPOINT_XFER_CONTROL, FALSE);
498 /****************************************************************************/
500 * Initializes Endpoints. All OUT endpoints are even numbered and all IN
501 * endpoints are odd numbered. EP0 is for Control OUT and EP1 is for
504 * @param InstancePtr is a pointer to the XUsbPsu instance.
510 ****************************************************************************/
511 void XUsbPsu_InitializeEps(struct XUsbPsu *InstancePtr)
516 Xil_AssertVoid(InstancePtr != NULL);
518 for (i = 0U; i < InstancePtr->NumOutEps; i++) {
519 Epnum = (i << 1U) | XUSBPSU_EP_DIR_OUT;
520 InstancePtr->eps[Epnum].PhyEpNum = Epnum;
521 InstancePtr->eps[Epnum].Direction = XUSBPSU_EP_DIR_OUT;
522 InstancePtr->eps[Epnum].ResourceIndex = 0;
524 for (i = 0U; i < InstancePtr->NumInEps; i++) {
525 Epnum = (i << 1U) | XUSBPSU_EP_DIR_IN;
526 InstancePtr->eps[Epnum].PhyEpNum = Epnum;
527 InstancePtr->eps[Epnum].Direction = XUSBPSU_EP_DIR_IN;
528 InstancePtr->eps[Epnum].ResourceIndex = 0;
532 /****************************************************************************/
534 * Stops transfer on Endpoint.
536 * @param InstancePtr is a pointer to the XUsbPsu instance.
537 * @param UsbEpNum is USB endpoint number.
538 * @param Dir is direction of endpoint - XUSBPSU_EP_DIR_IN/XUSBPSU_EP_DIR_OUT.
539 * @Force Force flag to stop/pause transfer.
545 ****************************************************************************/
546 void XUsbPsu_StopTransfer(struct XUsbPsu *InstancePtr, u8 UsbEpNum,
549 struct XUsbPsu_Ep *Ept;
550 struct XUsbPsu_EpParams *Params;
554 Xil_AssertVoid(InstancePtr != NULL);
555 Xil_AssertVoid(UsbEpNum <= (u8)16U);
556 Xil_AssertVoid((Dir == XUSBPSU_EP_DIR_IN) || (Dir == XUSBPSU_EP_DIR_OUT));
558 PhyEpNum = PhysicalEp(UsbEpNum, Dir);
559 Params = XUsbPsu_GetEpParams(InstancePtr);
560 Xil_AssertVoid(Params != NULL);
562 Ept = &InstancePtr->eps[PhyEpNum];
564 if (Ept->ResourceIndex == 0U) {
569 * - Issue EndTransfer WITH CMDIOC bit set
572 Cmd = XUSBPSU_DEPCMD_ENDTRANSFER;
573 Cmd |= Force ? XUSBPSU_DEPCMD_HIPRI_FORCERM : 0;
574 Cmd |= XUSBPSU_DEPCMD_CMDIOC;
575 Cmd |= XUSBPSU_DEPCMD_PARAM(Ept->ResourceIndex);
576 (void)XUsbPsu_SendEpCmd(InstancePtr, Ept->UsbEpNum, Ept->Direction,
579 Ept->ResourceIndex = 0U;
580 Ept->EpStatus &= ~XUSBPSU_EP_BUSY;
584 /****************************************************************************/
586 * Query endpoint state and save it in EpSavedState
588 * @param InstancePtr is a pointer to the XUsbPsu instance.
589 * @param Ept is a pointer to the XUsbPsu pointer structure.
595 ****************************************************************************/
596 void XUsbPsu_SaveEndpointState(struct XUsbPsu *InstancePtr, struct XUsbPsu_Ep *Ept)
598 struct XUsbPsu_EpParams *Params = XUsbPsu_GetEpParams(InstancePtr);
599 XUsbPsu_SendEpCmd(InstancePtr, Ept->UsbEpNum, Ept->Direction,
600 XUSBPSU_DEPCMD_GETEPSTATE, Params);
601 Ept->EpSavedState = XUsbPsu_ReadReg(InstancePtr, XUSBPSU_DEPCMDPAR2(Ept->PhyEpNum));
604 /****************************************************************************/
606 * Clears Stall on all endpoints.
608 * @param InstancePtr is a pointer to the XUsbPsu instance.
614 ****************************************************************************/
615 void XUsbPsu_ClearStalls(struct XUsbPsu *InstancePtr)
617 struct XUsbPsu_EpParams *Params;
619 struct XUsbPsu_Ep *Ept;
621 Xil_AssertVoid(InstancePtr != NULL);
623 Params = XUsbPsu_GetEpParams(InstancePtr);
624 Xil_AssertVoid(Params != NULL);
626 for (Epnum = 1U; Epnum < XUSBPSU_ENDPOINTS_NUM; Epnum++) {
628 Ept = &InstancePtr->eps[Epnum];
633 if ((Ept->EpStatus & XUSBPSU_EP_STALL) == 0U) {
637 Ept->EpStatus &= ~XUSBPSU_EP_STALL;
639 (void)XUsbPsu_SendEpCmd(InstancePtr, Ept->UsbEpNum,
640 Ept->Direction, XUSBPSU_DEPCMD_CLEARSTALL,
645 /****************************************************************************/
647 * Initiates DMA to send data on endpoint to Host.
649 * @param InstancePtr is a pointer to the XUsbPsu instance.
650 * @param UsbEp is USB endpoint number.
651 * @param BufferPtr is pointer to data.
652 * @param BufferLen is length of data buffer.
654 * @return XST_SUCCESS else XST_FAILURE
658 *****************************************************************************/
659 s32 XUsbPsu_EpBufferSend(struct XUsbPsu *InstancePtr, u8 UsbEp,
660 u8 *BufferPtr, u32 BufferLen)
665 struct XUsbPsu_Trb *TrbPtr;
666 struct XUsbPsu_Ep *Ept;
667 struct XUsbPsu_EpParams *Params;
669 Xil_AssertNonvoid(InstancePtr != NULL);
670 Xil_AssertNonvoid(UsbEp <= (u8)16U);
671 Xil_AssertNonvoid(BufferPtr != NULL);
673 PhyEpNum = PhysicalEp(UsbEp, XUSBPSU_EP_DIR_IN);
674 if (PhyEpNum == 1U) {
675 RetVal = XUsbPsu_Ep0Send(InstancePtr, BufferPtr, BufferLen);
679 Ept = &InstancePtr->eps[PhyEpNum];
681 if (Ept->Direction != XUSBPSU_EP_DIR_IN) {
685 Ept->RequestedBytes = BufferLen;
687 Ept->BufferPtr = BufferPtr;
689 TrbPtr = &Ept->EpTrb[Ept->TrbEnqueue];
690 Xil_AssertNonvoid(TrbPtr != NULL);
693 if (Ept->TrbEnqueue == NO_OF_TRB_PER_EP)
695 TrbPtr->BufferPtrLow = (UINTPTR)BufferPtr;
696 TrbPtr->BufferPtrHigh = ((UINTPTR)BufferPtr >> 16) >> 16;
697 TrbPtr->Size = BufferLen & XUSBPSU_TRB_SIZE_MASK;
700 case XUSBPSU_ENDPOINT_XFER_ISOC:
702 * According to DWC3 datasheet, XUSBPSU_TRBCTL_ISOCHRONOUS and
703 * XUSBPSU_TRBCTL_CHN fields are only set when request has
704 * scattered list so these fields are not set over here.
706 TrbPtr->Ctrl = (XUSBPSU_TRBCTL_ISOCHRONOUS_FIRST
707 | XUSBPSU_TRB_CTRL_CSP);
710 case XUSBPSU_ENDPOINT_XFER_INT:
711 case XUSBPSU_ENDPOINT_XFER_BULK:
712 TrbPtr->Ctrl = (XUSBPSU_TRBCTL_NORMAL
713 | XUSBPSU_TRB_CTRL_LST);
718 TrbPtr->Ctrl |= (XUSBPSU_TRB_CTRL_HWO
719 | XUSBPSU_TRB_CTRL_IOC
720 | XUSBPSU_TRB_CTRL_ISP_IMI);
722 if (InstancePtr->ConfigPtr->IsCacheCoherent == 0) {
723 Xil_DCacheFlushRange((INTPTR)TrbPtr, sizeof(struct XUsbPsu_Trb));
724 Xil_DCacheFlushRange((INTPTR)BufferPtr, BufferLen);
727 Params = XUsbPsu_GetEpParams(InstancePtr);
728 Xil_AssertNonvoid(Params != NULL);
730 Params->Param1 = (UINTPTR)TrbPtr;
732 if (Ept->EpStatus & XUSBPSU_EP_BUSY) {
733 cmd = XUSBPSU_DEPCMD_UPDATETRANSFER;
734 cmd |= XUSBPSU_DEPCMD_PARAM(Ept->ResourceIndex);
736 if (Ept->Type == XUSBPSU_ENDPOINT_XFER_ISOC) {
737 BufferPtr += BufferLen;
738 struct XUsbPsu_Trb *TrbTempNext;
739 TrbTempNext = &Ept->EpTrb[Ept->TrbEnqueue];
740 Xil_AssertNonvoid(TrbTempNext != NULL);
743 if (Ept->TrbEnqueue == NO_OF_TRB_PER_EP)
745 TrbTempNext->BufferPtrLow = (UINTPTR)BufferPtr;
746 TrbTempNext->BufferPtrHigh = ((UINTPTR)BufferPtr >> 16) >> 16;
747 TrbTempNext->Size = BufferLen & XUSBPSU_TRB_SIZE_MASK;
749 TrbTempNext->Ctrl = (XUSBPSU_TRBCTL_ISOCHRONOUS_FIRST
750 | XUSBPSU_TRB_CTRL_CSP
751 | XUSBPSU_TRB_CTRL_HWO
752 | XUSBPSU_TRB_CTRL_IOC
753 | XUSBPSU_TRB_CTRL_ISP_IMI);
755 if (InstancePtr->ConfigPtr->IsCacheCoherent == 0) {
756 Xil_DCacheFlushRange((INTPTR)TrbTempNext,
757 sizeof(struct XUsbPsu_Trb));
758 Xil_DCacheFlushRange((INTPTR)BufferPtr, BufferLen);
763 cmd = XUSBPSU_DEPCMD_STARTTRANSFER;
764 cmd |= XUSBPSU_DEPCMD_PARAM(Ept->CurUf);
767 RetVal = XUsbPsu_SendEpCmd(InstancePtr, UsbEp, Ept->Direction,
769 if (RetVal != XST_SUCCESS) {
773 if (!(Ept->EpStatus & XUSBPSU_EP_BUSY)) {
774 Ept->ResourceIndex = (u8)XUsbPsu_EpGetTransferIndex(InstancePtr,
778 Ept->EpStatus |= XUSBPSU_EP_BUSY;
784 /****************************************************************************/
786 * Initiates DMA to receive data on Endpoint from Host.
788 * @param InstancePtr is a pointer to the XUsbPsu instance.
789 * @param UsbEp is USB endpoint number.
790 * @param BufferPtr is pointer to data.
791 * @param Length is length of data to be received.
793 * @return XST_SUCCESS else XST_FAILURE
797 *****************************************************************************/
798 s32 XUsbPsu_EpBufferRecv(struct XUsbPsu *InstancePtr, u8 UsbEp,
799 u8 *BufferPtr, u32 Length)
805 struct XUsbPsu_Trb *TrbPtr;
806 struct XUsbPsu_Ep *Ept;
807 struct XUsbPsu_EpParams *Params;
809 Xil_AssertNonvoid(InstancePtr != NULL);
810 Xil_AssertNonvoid(UsbEp <= (u8)16U);
811 Xil_AssertNonvoid(BufferPtr != NULL);
813 PhyEpNum = PhysicalEp(UsbEp, XUSBPSU_EP_DIR_OUT);
814 if (PhyEpNum == 0U) {
815 RetVal = XUsbPsu_Ep0Recv(InstancePtr, BufferPtr, Length);
819 Ept = &InstancePtr->eps[PhyEpNum];
821 if (Ept->Direction != XUSBPSU_EP_DIR_OUT) {
825 Ept->RequestedBytes = Length;
828 Ept->BufferPtr = BufferPtr;
831 * 8.2.5 - An OUT transfer size (Total TRB buffer allocation)
832 * must be a multiple of MaxPacketSize even if software is expecting a
833 * fixed non-multiple of MaxPacketSize transfer from the Host.
835 if (!IS_ALIGNED(Length, Ept->MaxSize)) {
836 Size = (u32)roundup(Length, Ept->MaxSize);
837 Ept->UnalignedTx = 1U;
840 TrbPtr = &Ept->EpTrb[Ept->TrbEnqueue];
841 Xil_AssertNonvoid(TrbPtr != NULL);
844 if (Ept->TrbEnqueue == NO_OF_TRB_PER_EP)
847 TrbPtr->BufferPtrLow = (UINTPTR)BufferPtr;
848 TrbPtr->BufferPtrHigh = ((UINTPTR)BufferPtr >> 16) >> 16;
852 case XUSBPSU_ENDPOINT_XFER_ISOC:
854 * According to Linux driver, XUSBPSU_TRBCTL_ISOCHRONOUS and
855 * XUSBPSU_TRBCTL_CHN fields are only set when request has
856 * scattered list so these fields are not set over here.
858 TrbPtr->Ctrl = (XUSBPSU_TRBCTL_ISOCHRONOUS_FIRST
859 | XUSBPSU_TRB_CTRL_CSP);
862 case XUSBPSU_ENDPOINT_XFER_INT:
863 case XUSBPSU_ENDPOINT_XFER_BULK:
864 TrbPtr->Ctrl = (XUSBPSU_TRBCTL_NORMAL
865 | XUSBPSU_TRB_CTRL_LST);
870 TrbPtr->Ctrl |= (XUSBPSU_TRB_CTRL_HWO
871 | XUSBPSU_TRB_CTRL_IOC
872 | XUSBPSU_TRB_CTRL_ISP_IMI);
875 if (InstancePtr->ConfigPtr->IsCacheCoherent == 0) {
876 Xil_DCacheFlushRange((INTPTR)TrbPtr, sizeof(struct XUsbPsu_Trb));
877 Xil_DCacheInvalidateRange((INTPTR)BufferPtr, Length);
880 Params = XUsbPsu_GetEpParams(InstancePtr);
881 Xil_AssertNonvoid(Params != NULL);
883 Params->Param1 = (UINTPTR)TrbPtr;
885 if (Ept->EpStatus & XUSBPSU_EP_BUSY) {
886 cmd = XUSBPSU_DEPCMD_UPDATETRANSFER;
887 cmd |= XUSBPSU_DEPCMD_PARAM(Ept->ResourceIndex);
889 if (Ept->Type == XUSBPSU_ENDPOINT_XFER_ISOC) {
891 struct XUsbPsu_Trb *TrbTempNext;
892 TrbTempNext = &Ept->EpTrb[Ept->TrbEnqueue];
893 Xil_AssertNonvoid(TrbTempNext != NULL);
896 if (Ept->TrbEnqueue == NO_OF_TRB_PER_EP)
898 TrbTempNext->BufferPtrLow = (UINTPTR)BufferPtr;
899 TrbTempNext->BufferPtrHigh = ((UINTPTR)BufferPtr >> 16) >> 16;
900 TrbTempNext->Size = Length & XUSBPSU_TRB_SIZE_MASK;
902 TrbTempNext->Ctrl = (XUSBPSU_TRBCTL_ISOCHRONOUS_FIRST
903 | XUSBPSU_TRB_CTRL_CSP
904 | XUSBPSU_TRB_CTRL_HWO
905 | XUSBPSU_TRB_CTRL_IOC
906 | XUSBPSU_TRB_CTRL_ISP_IMI);
908 if (InstancePtr->ConfigPtr->IsCacheCoherent == 0) {
909 Xil_DCacheFlushRange((INTPTR)TrbTempNext,
910 sizeof(struct XUsbPsu_Trb));
911 Xil_DCacheFlushRange((INTPTR)BufferPtr, Length);
916 cmd = XUSBPSU_DEPCMD_STARTTRANSFER;
917 cmd |= XUSBPSU_DEPCMD_PARAM(Ept->CurUf);
920 RetVal = XUsbPsu_SendEpCmd(InstancePtr, UsbEp, Ept->Direction,
922 if (RetVal != XST_SUCCESS) {
926 if (!(Ept->EpStatus & XUSBPSU_EP_BUSY)) {
927 Ept->ResourceIndex = (u8)XUsbPsu_EpGetTransferIndex(InstancePtr,
931 Ept->EpStatus |= XUSBPSU_EP_BUSY;
937 /****************************************************************************/
939 * Stalls an Endpoint.
941 * @param InstancePtr is a pointer to the XUsbPsu instance.
942 * @param Epnum is USB endpoint number.
943 * @param Dir is direction.
949 *****************************************************************************/
950 void XUsbPsu_EpSetStall(struct XUsbPsu *InstancePtr, u8 Epnum, u8 Dir)
953 struct XUsbPsu_Ep *Ept = NULL;
954 struct XUsbPsu_EpParams *Params;
956 Xil_AssertVoid(InstancePtr != NULL);
957 Xil_AssertVoid(Epnum <= (u8)16U);
958 Xil_AssertVoid((Dir == XUSBPSU_EP_DIR_IN) || (Dir == XUSBPSU_EP_DIR_OUT));
960 PhyEpNum = PhysicalEp(Epnum, Dir);
961 Ept = &InstancePtr->eps[PhyEpNum];
963 Params = XUsbPsu_GetEpParams(InstancePtr);
964 Xil_AssertVoid(Params != NULL);
966 (void)XUsbPsu_SendEpCmd(InstancePtr, Ept->UsbEpNum, Ept->Direction,
967 XUSBPSU_DEPCMD_SETSTALL, Params);
969 Ept->EpStatus |= XUSBPSU_EP_STALL;
972 /****************************************************************************/
974 * Clears Stall on an Endpoint.
976 * @param InstancePtr is a pointer to the XUsbPsu instance.
977 * @param EpNum is USB endpoint number.
978 * @param Dir is direction.
984 *****************************************************************************/
985 void XUsbPsu_EpClearStall(struct XUsbPsu *InstancePtr, u8 Epnum, u8 Dir)
988 struct XUsbPsu_Ep *Ept = NULL;
989 struct XUsbPsu_EpParams *Params;
991 Xil_AssertVoid(InstancePtr != NULL);
992 Xil_AssertVoid(Epnum <= (u8)16U);
993 Xil_AssertVoid((Dir == XUSBPSU_EP_DIR_IN) || (Dir == XUSBPSU_EP_DIR_OUT));
995 PhyEpNum = PhysicalEp(Epnum, Dir);
996 Ept = &InstancePtr->eps[PhyEpNum];
998 Params = XUsbPsu_GetEpParams(InstancePtr);
999 Xil_AssertVoid(Params != NULL);
1001 (void)XUsbPsu_SendEpCmd(InstancePtr, Ept->UsbEpNum, Ept->Direction,
1002 XUSBPSU_DEPCMD_CLEARSTALL, Params);
1004 Ept->EpStatus &= ~XUSBPSU_EP_STALL;
1007 /****************************************************************************/
1009 * Sets an user handler to be called after data is sent/received by an Endpoint
1011 * @param InstancePtr is a pointer to the XUsbPsu instance.
1012 * @param EpNum is USB endpoint number.
1013 * @param Dir is direction of endpoint - XUSBPSU_EP_DIR_IN/XUSBPSU_EP_DIR_OUT.
1014 * @param Handler is user handler to be called.
1020 *****************************************************************************/
1021 void XUsbPsu_SetEpHandler(struct XUsbPsu *InstancePtr, u8 Epnum,
1022 u8 Dir, void (*Handler)(void *, u32, u32))
1025 struct XUsbPsu_Ep *Ept;
1027 Xil_AssertVoid(InstancePtr != NULL);
1028 Xil_AssertVoid(Epnum <= (u8)16U);
1029 Xil_AssertVoid((Dir == XUSBPSU_EP_DIR_IN) || (Dir == XUSBPSU_EP_DIR_OUT));
1031 PhyEpNum = PhysicalEp(Epnum, Dir);
1032 Ept = &InstancePtr->eps[PhyEpNum];
1033 Ept->Handler = Handler;
1036 /****************************************************************************/
1038 * Returns status of endpoint - Stalled or not
1040 * @param InstancePtr is a pointer to the XUsbPsu instance.
1041 * @param EpNum is USB endpoint number.
1042 * @param Dir is direction of endpoint - XUSBPSU_EP_DIR_IN/XUSBPSU_EP_DIR_OUT.
1046 * 0 - if not stalled
1050 *****************************************************************************/
1051 s32 XUsbPsu_IsEpStalled(struct XUsbPsu *InstancePtr, u8 Epnum, u8 Dir)
1054 struct XUsbPsu_Ep *Ept;
1056 Xil_AssertNonvoid(InstancePtr != NULL);
1057 Xil_AssertNonvoid(Epnum <= (u8)16U);
1058 Xil_AssertNonvoid((Dir == XUSBPSU_EP_DIR_IN) || (Dir == XUSBPSU_EP_DIR_OUT));
1060 PhyEpNum = PhysicalEp(Epnum, Dir);
1061 Ept = &InstancePtr->eps[PhyEpNum];
1063 return (s32)(!!(Ept->EpStatus & XUSBPSU_EP_STALL));
1066 /****************************************************************************/
1068 * Checks the Data Phase and calls user Endpoint handler.
1070 * @param InstancePtr is a pointer to the XUsbPsu instance.
1071 * @param Event is a pointer to the Endpoint event occured in core.
1077 *****************************************************************************/
1078 void XUsbPsu_EpXferComplete(struct XUsbPsu *InstancePtr,
1079 const struct XUsbPsu_Event_Epevt *Event)
1081 struct XUsbPsu_Ep *Ept;
1082 struct XUsbPsu_Trb *TrbPtr;
1087 Xil_AssertVoid(InstancePtr != NULL);
1088 Xil_AssertVoid(Event != NULL);
1090 Epnum = Event->Epnumber;
1091 Ept = &InstancePtr->eps[Epnum];
1092 Dir = Ept->Direction;
1093 TrbPtr = &Ept->EpTrb[Ept->TrbDequeue];
1094 Xil_AssertVoid(TrbPtr != NULL);
1097 if (Ept->TrbDequeue == NO_OF_TRB_PER_EP)
1098 Ept->TrbDequeue = 0;
1100 if (InstancePtr->ConfigPtr->IsCacheCoherent == 0)
1101 Xil_DCacheInvalidateRange((INTPTR)TrbPtr, sizeof(struct XUsbPsu_Trb));
1103 if (Event->Endpoint_Event == XUSBPSU_DEPEVT_XFERCOMPLETE) {
1104 Ept->EpStatus &= ~(XUSBPSU_EP_BUSY);
1105 Ept->ResourceIndex = 0;
1108 Length = TrbPtr->Size & XUSBPSU_TRB_SIZE_MASK;
1111 Ept->BytesTxed = Ept->RequestedBytes;
1113 if (Dir == XUSBPSU_EP_DIR_IN) {
1114 Ept->BytesTxed = Ept->RequestedBytes - Length;
1115 } else if (Dir == XUSBPSU_EP_DIR_OUT) {
1116 if (Ept->UnalignedTx == 1U) {
1117 Ept->BytesTxed = (u32)roundup(Ept->RequestedBytes,
1119 Ept->BytesTxed -= Length;
1120 Ept->UnalignedTx = 0U;
1123 * Get the actual number of bytes transmitted
1126 Ept->BytesTxed = Ept->RequestedBytes - Length;
1131 if (Dir == XUSBPSU_EP_DIR_OUT) {
1132 /* Invalidate Cache */
1133 if (InstancePtr->ConfigPtr->IsCacheCoherent == 0)
1134 Xil_DCacheInvalidateRange((INTPTR)Ept->BufferPtr, Ept->BytesTxed);
1137 if (Ept->Handler != NULL) {
1138 Ept->Handler(InstancePtr->AppData, Ept->RequestedBytes, Ept->BytesTxed);
1142 /****************************************************************************/
1144 * For Isochronous transfer, get the microframe time and calls respective Endpoint
1147 * @param InstancePtr is a pointer to the XUsbPsu instance.
1148 * @param Event is a pointer to the Endpoint event occurred in core.
1154 *****************************************************************************/
1155 void XUsbPsu_EpXferNotReady(struct XUsbPsu *InstancePtr,
1156 const struct XUsbPsu_Event_Epevt *Event)
1158 struct XUsbPsu_Ep *Ept;
1162 Xil_AssertVoid(InstancePtr != NULL);
1163 Xil_AssertVoid(Event != NULL);
1165 Epnum = Event->Epnumber;
1166 Ept = &InstancePtr->eps[Epnum];
1168 if (Ept->Type == XUSBPSU_ENDPOINT_XFER_ISOC) {
1169 Mask = ~(1 << (Ept->Interval - 1));
1170 CurUf = Event->Parameters & Mask;
1171 Ept->CurUf = CurUf + (Ept->Interval * 4);
1172 if (Ept->Handler != NULL) {
1173 Ept->Handler(InstancePtr->AppData, 0, 0);