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_intr.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
50 * vak 22/01/18 Added changes for supporting microblaze platform
51 * vak 13/03/18 Moved the setup interrupt system calls from driver to
56 *****************************************************************************/
58 /***************************** Include Files ********************************/
60 #include "xusb_wrapper.h"
62 /************************** Constant Definitions *****************************/
64 /**************************** Type Definitions *******************************/
66 /***************** Macros (Inline Functions) Definitions *********************/
68 /************************** Function Prototypes ******************************/
70 /************************** Variable Definitions *****************************/
72 /****************************************************************************/
74 * Endpoint interrupt handler.
76 * @param InstancePtr is a pointer to the XUsbPsu instance.
77 * @param Event is endpoint Event occured in the core.
83 *****************************************************************************/
84 void XUsbPsu_EpInterrupt(struct XUsbPsu *InstancePtr,
85 const struct XUsbPsu_Event_Epevt *Event)
87 struct XUsbPsu_Ep *Ept;
90 Epnum = Event->Epnumber;
91 Ept = &InstancePtr->eps[Epnum];
93 if ((Ept->EpStatus & XUSBPSU_EP_ENABLED) == (u32)0U) {
97 if ((Epnum == (u32)0) || (Epnum == (u32)1)) {
98 XUsbPsu_Ep0Intr(InstancePtr, Event);
102 /* Handle other end point events */
103 switch (Event->Endpoint_Event) {
104 case XUSBPSU_DEPEVT_XFERCOMPLETE:
105 case XUSBPSU_DEPEVT_XFERINPROGRESS:
106 XUsbPsu_EpXferComplete(InstancePtr, Event);
109 case XUSBPSU_DEPEVT_XFERNOTREADY:
110 XUsbPsu_EpXferNotReady(InstancePtr, Event);
114 /* Made for Misra-C Compliance. */
119 /****************************************************************************/
121 * Disconnect Interrupt handler.
123 * @param InstancePtr is a pointer to the XUsbPsu instance.
129 *****************************************************************************/
130 void XUsbPsu_DisconnectIntr(struct XUsbPsu *InstancePtr)
134 RegVal = XUsbPsu_ReadReg(InstancePtr, XUSBPSU_DCTL);
135 RegVal &= ~XUSBPSU_DCTL_INITU1ENA;
136 XUsbPsu_WriteReg(InstancePtr, XUSBPSU_DCTL, RegVal);
138 RegVal &= ~XUSBPSU_DCTL_INITU2ENA;
139 XUsbPsu_WriteReg(InstancePtr, XUSBPSU_DCTL, RegVal);
141 InstancePtr->IsConfigDone = 0U;
142 InstancePtr->AppData->Speed = XUSBPSU_SPEED_UNKNOWN;
144 #ifdef XUSBPSU_HIBERNATION_ENABLE
145 /* In USB 2.0, to avoid hibernation interrupt at the time of connection
146 * clear KEEP_CONNECT bit.
148 if (InstancePtr->HasHibernation) {
149 RegVal = XUsbPsu_ReadReg(InstancePtr, XUSBPSU_DCTL);
150 if (RegVal & XUSBPSU_DCTL_KEEP_CONNECT) {
151 RegVal &= ~XUSBPSU_DCTL_KEEP_CONNECT;
152 XUsbPsu_WriteReg(InstancePtr, XUSBPSU_DCTL, RegVal);
157 /* Call the handler if necessary */
158 if (InstancePtr->DisconnectIntrHandler != NULL) {
159 InstancePtr->DisconnectIntrHandler(InstancePtr->AppData);
163 /****************************************************************************/
165 * Stops any active transfer.
167 * @param InstancePtr is a pointer to the XUsbPsu instance.
173 *****************************************************************************/
174 static void XUsbPsu_stop_active_transfers(struct XUsbPsu *InstancePtr)
178 for (Epnum = 2; Epnum < XUSBPSU_ENDPOINTS_NUM; Epnum++) {
179 struct XUsbPsu_Ep *Ept;
181 Ept = &InstancePtr->eps[Epnum];
185 if (!(Ept->EpStatus & XUSBPSU_EP_ENABLED))
188 XUsbPsu_StopTransfer(InstancePtr, Ept->UsbEpNum,
189 Ept->Direction, TRUE);
193 /****************************************************************************/
195 * Clears stall on all stalled Eps.
197 * @param InstancePtr is a pointer to the XUsbPsu instance.
203 *****************************************************************************/
204 static void XUsbPsu_clear_stall_all_ep(struct XUsbPsu *InstancePtr)
208 for (Epnum = 1; Epnum < XUSBPSU_ENDPOINTS_NUM; Epnum++) {
209 struct XUsbPsu_Ep *Ept;
211 Ept = &InstancePtr->eps[Epnum];
215 if (!(Ept->EpStatus & XUSBPSU_EP_ENABLED))
218 if (!(Ept->EpStatus & XUSBPSU_EP_STALL))
221 XUsbPsu_EpClearStall(InstancePtr, Ept->UsbEpNum, Ept->Direction);
225 /****************************************************************************/
227 * Reset Interrupt handler.
229 * @param InstancePtr is a pointer to the XUsbPsu instance.
235 *****************************************************************************/
236 void XUsbPsu_ResetIntr(struct XUsbPsu *InstancePtr)
241 InstancePtr->AppData->State = XUSBPSU_STATE_DEFAULT;
243 RegVal = XUsbPsu_ReadReg(InstancePtr, XUSBPSU_DCTL);
244 RegVal &= ~XUSBPSU_DCTL_TSTCTRL_MASK;
245 XUsbPsu_WriteReg(InstancePtr, XUSBPSU_DCTL, RegVal);
246 InstancePtr->TestMode = 0U;
248 XUsbPsu_stop_active_transfers(InstancePtr);
249 XUsbPsu_clear_stall_all_ep(InstancePtr);
251 for (Index = 0U; Index < (InstancePtr->NumInEps + InstancePtr->NumOutEps);
254 InstancePtr->eps[Index].EpStatus = 0U;
257 InstancePtr->IsConfigDone = 0U;
259 /* Reset device address to zero */
260 RegVal = XUsbPsu_ReadReg(InstancePtr, XUSBPSU_DCFG);
261 RegVal &= ~(XUSBPSU_DCFG_DEVADDR_MASK);
262 XUsbPsu_WriteReg(InstancePtr, XUSBPSU_DCFG, RegVal);
264 /* Call the handler if necessary */
265 if (InstancePtr->ResetIntrHandler != NULL) {
266 InstancePtr->ResetIntrHandler(InstancePtr->AppData);
270 /****************************************************************************/
272 * Connection Done Interrupt handler.
274 * @param InstancePtr is a pointer to the XUsbPsu instance.
280 *****************************************************************************/
281 void XUsbPsu_ConnDoneIntr(struct XUsbPsu *InstancePtr)
287 RegVal = XUsbPsu_ReadReg(InstancePtr, XUSBPSU_DSTS);
288 Speed = (u8)(RegVal & XUSBPSU_DSTS_CONNECTSPD);
289 InstancePtr->AppData->Speed = Speed;
292 case XUSBPSU_DCFG_SUPERSPEED:
294 xil_printf("Super Speed\r\n");
297 InstancePtr->AppData->Speed = XUSBPSU_SPEED_SUPER;
300 case XUSBPSU_DCFG_HIGHSPEED:
302 xil_printf("High Speed\r\n");
305 InstancePtr->AppData->Speed = XUSBPSU_SPEED_HIGH;
308 case XUSBPSU_DCFG_FULLSPEED2:
309 case XUSBPSU_DCFG_FULLSPEED1:
311 xil_printf("Full Speed\r\n");
314 InstancePtr->AppData->Speed = XUSBPSU_SPEED_FULL;
317 case XUSBPSU_DCFG_LOWSPEED:
319 xil_printf("Low Speed\r\n");
322 InstancePtr->AppData->Speed = XUSBPSU_SPEED_LOW;
329 if (InstancePtr->AppData->Speed == XUSBPSU_SPEED_SUPER) {
330 RegVal = XUsbPsu_ReadReg(InstancePtr, XUSBPSU_DCTL);
331 RegVal &= ~XUSBPSU_DCTL_HIRD_THRES_MASK;
332 XUsbPsu_WriteReg(InstancePtr, XUSBPSU_DCTL, RegVal);
335 (void)XUsbPsu_EnableControlEp(InstancePtr, Size);
336 (void)XUsbPsu_RecvSetup(InstancePtr);
338 #ifdef XUSBPSU_HIBERNATION_ENABLE
339 /* In USB 2.0, to avoid hibernation interrupt at the time of connection
340 * clear KEEP_CONNECT bit.
342 if (InstancePtr->HasHibernation) {
343 RegVal = XUsbPsu_ReadReg(InstancePtr, XUSBPSU_DCTL);
344 if (!(RegVal & XUSBPSU_DCTL_KEEP_CONNECT)) {
345 RegVal |= XUSBPSU_DCTL_KEEP_CONNECT;
346 XUsbPsu_WriteReg(InstancePtr, XUSBPSU_DCTL, RegVal);
352 /****************************************************************************/
354 * Link Status Change Interrupt handler.
356 * @param InstancePtr is a pointer to the XUsbPsu instance.
357 * @param EvtInfo is Event information.
363 *****************************************************************************/
364 void XUsbPsu_LinkStsChangeIntr(struct XUsbPsu *InstancePtr, u32 EvtInfo)
366 u32 State = EvtInfo & (u32)XUSBPSU_LINK_STATE_MASK;
367 InstancePtr->LinkState = (u8)State;
370 /****************************************************************************/
372 * Interrupt handler for device specific events.
374 * @param InstancePtr is a pointer to the XUsbPsu instance.
375 * @param Event is the Device Event occured in core.
381 *****************************************************************************/
382 void XUsbPsu_DevInterrupt(struct XUsbPsu *InstancePtr,
383 const struct XUsbPsu_Event_Devt *Event)
386 switch (Event->Type) {
387 case XUSBPSU_DEVICE_EVENT_DISCONNECT:
388 XUsbPsu_DisconnectIntr(InstancePtr);
391 case XUSBPSU_DEVICE_EVENT_RESET:
392 XUsbPsu_ResetIntr(InstancePtr);
395 case XUSBPSU_DEVICE_EVENT_CONNECT_DONE:
396 XUsbPsu_ConnDoneIntr(InstancePtr);
399 case XUSBPSU_DEVICE_EVENT_WAKEUP:
402 case XUSBPSU_DEVICE_EVENT_HIBER_REQ:
403 #ifdef XUSBPSU_HIBERNATION_ENABLE
404 if (InstancePtr->HasHibernation)
405 Xusbpsu_HibernationIntr(InstancePtr);
409 case XUSBPSU_DEVICE_EVENT_LINK_STATUS_CHANGE:
410 XUsbPsu_LinkStsChangeIntr(InstancePtr,
414 case XUSBPSU_DEVICE_EVENT_EOPF:
417 case XUSBPSU_DEVICE_EVENT_SOF:
420 case XUSBPSU_DEVICE_EVENT_ERRATIC_ERROR:
423 case XUSBPSU_DEVICE_EVENT_CMD_CMPL:
426 case XUSBPSU_DEVICE_EVENT_OVERFLOW:
430 /* Made for Misra-C Compliance. */
435 /****************************************************************************/
437 * Processes an Event entry in Event Buffer.
439 * @param InstancePtr is a pointer to the XUsbPsu instance.
440 * @param Event is the Event entry.
446 *****************************************************************************/
447 void XUsbPsu_EventHandler(struct XUsbPsu *InstancePtr,
448 const union XUsbPsu_Event *Event)
451 if (Event->Type.Is_DevEvt == 0U) {
452 /* End point Specific Event */
453 XUsbPsu_EpInterrupt(InstancePtr, &Event->Epevt);
457 switch (Event->Type.Type) {
458 case XUSBPSU_EVENT_TYPE_DEV:
459 /* Device Specific Event */
460 XUsbPsu_DevInterrupt(InstancePtr, &Event->Devt);
462 /* Carkit and I2C events not supported now */
464 /* Made for Misra-C Compliance. */
469 /****************************************************************************/
471 * Processes events in an Event Buffer.
473 * @param InstancePtr is a pointer to the XUsbPsu instance.
474 * @bus Event buffer number.
480 *****************************************************************************/
481 void XUsbPsu_EventBufferHandler(struct XUsbPsu *InstancePtr)
483 struct XUsbPsu_EvtBuffer *Evt;
484 union XUsbPsu_Event Event = {0};
487 Evt = &InstancePtr->Evt;
489 if (InstancePtr->ConfigPtr->IsCacheCoherent == 0) {
490 Xil_DCacheInvalidateRange((INTPTR)Evt->BuffAddr,
491 (u32)XUSBPSU_EVENT_BUFFERS_SIZE);
494 while (Evt->Count > 0) {
495 Event.Raw = *(UINTPTR *)((UINTPTR)Evt->BuffAddr + Evt->Offset);
498 * Process the event received
500 XUsbPsu_EventHandler(InstancePtr, &Event);
502 /* don't process anymore events if core is hibernated */
503 if (InstancePtr->IsHibernated)
506 Evt->Offset = (Evt->Offset + 4U) % XUSBPSU_EVENT_BUFFERS_SIZE;
508 XUsbPsu_WriteReg(InstancePtr, XUSBPSU_GEVNTCOUNT(0), 4U);
512 Evt->Flags &= ~XUSBPSU_EVENT_PENDING;
514 /* Unmask event interrupt */
515 RegVal = XUsbPsu_ReadReg(InstancePtr, XUSBPSU_GEVNTSIZ(0));
516 RegVal &= ~XUSBPSU_GEVNTSIZ_INTMASK;
517 XUsbPsu_WriteReg(InstancePtr, XUSBPSU_GEVNTSIZ(0), RegVal);
520 /****************************************************************************/
522 * Main Interrupt Handler.
528 *****************************************************************************/
529 void XUsbPsu_IntrHandler(void *XUsbPsuInstancePtr)
531 struct XUsbPsu *InstancePtr;
532 struct XUsbPsu_EvtBuffer *Evt;
536 InstancePtr = XUsbPsuInstancePtr;
538 Evt = &InstancePtr->Evt;
540 Count = XUsbPsu_ReadReg(InstancePtr, XUSBPSU_GEVNTCOUNT(0));
541 Count &= XUSBPSU_GEVNTCOUNT_MASK;
543 * As per data book software should only process Events if Event count
544 * is greater than zero.
551 Evt->Flags |= XUSBPSU_EVENT_PENDING;
553 /* Mask event interrupt */
554 RegVal = XUsbPsu_ReadReg(InstancePtr, XUSBPSU_GEVNTSIZ(0));
555 RegVal |= XUSBPSU_GEVNTSIZ_INTMASK;
556 XUsbPsu_WriteReg(InstancePtr, XUSBPSU_GEVNTSIZ(0), RegVal);
558 /* Processes events in an Event Buffer */
559 XUsbPsu_EventBufferHandler(InstancePtr);
562 #ifdef XUSBPSU_HIBERNATION_ENABLE
563 /****************************************************************************/
565 * Wakeup Interrupt Handler.
571 *****************************************************************************/
572 void XUsbPsu_WakeUpIntrHandler(void *XUsbPsuInstancePtr)
574 struct XUsbPsu *InstancePtr = (struct XUsbPsu *)XUsbPsuInstancePtr;
576 XUsbPsu_WakeupIntr(InstancePtr);