]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_R5_UltraScale_MPSoC/RTOSDemo_R5_bsp/psu_cortexr5_0/libsrc/usbpsu_v1_4/src/xusbpsu_intr.c
Update Zynq, MPSoc Cortex-A53 and MPSoc Cortex-R5 demo projects to build with the...
[freertos] / FreeRTOS / Demo / CORTEX_R5_UltraScale_MPSoC / RTOSDemo_R5_bsp / psu_cortexr5_0 / libsrc / usbpsu_v1_4 / src / xusbpsu_intr.c
1 /******************************************************************************
2 *
3 * Copyright (C) 2016 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_intr.c
36 * @addtogroup usbpsu_v1_3
37 * @{
38 *
39 *
40 * <pre>
41 * MODIFICATION HISTORY:
42 *
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
48 *                      for all USB IPs
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
52 *                    example.
53 *
54 * </pre>
55 *
56 *****************************************************************************/
57
58 /***************************** Include Files ********************************/
59
60 #include "xusb_wrapper.h"
61
62 /************************** Constant Definitions *****************************/
63
64 /**************************** Type Definitions *******************************/
65
66 /***************** Macros (Inline Functions) Definitions *********************/
67
68 /************************** Function Prototypes ******************************/
69
70 /************************** Variable Definitions *****************************/
71
72 /****************************************************************************/
73 /**
74 * Endpoint interrupt handler.
75 *
76 * @param        InstancePtr is a pointer to the XUsbPsu instance.
77 * @param        Event is endpoint Event occured in the core.
78 *
79 * @return       None.
80 *
81 * @note         None.
82 *
83 *****************************************************************************/
84 void XUsbPsu_EpInterrupt(struct XUsbPsu *InstancePtr,
85                 const struct XUsbPsu_Event_Epevt *Event)
86 {
87         struct XUsbPsu_Ep *Ept;
88         u32 Epnum;
89
90         Epnum = Event->Epnumber;
91         Ept = &InstancePtr->eps[Epnum];
92
93         if ((Ept->EpStatus & XUSBPSU_EP_ENABLED) == (u32)0U) {
94                 return;
95         }
96
97         if ((Epnum == (u32)0) || (Epnum == (u32)1)) {
98                 XUsbPsu_Ep0Intr(InstancePtr, Event);
99                 return;
100         }
101
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);
107                         break;
108
109                 case XUSBPSU_DEPEVT_XFERNOTREADY:
110                         XUsbPsu_EpXferNotReady(InstancePtr, Event);
111                         break;
112
113                 default:
114                         /* Made for Misra-C Compliance. */
115                         break;
116         }
117 }
118
119 /****************************************************************************/
120 /**
121 * Disconnect Interrupt handler.
122 *
123 * @param        InstancePtr is a pointer to the XUsbPsu instance.
124 *
125 * @return       None.
126 *
127 * @note         None.
128 *
129 *****************************************************************************/
130 void XUsbPsu_DisconnectIntr(struct XUsbPsu *InstancePtr)
131 {
132         u32 RegVal;
133
134         RegVal = XUsbPsu_ReadReg(InstancePtr, XUSBPSU_DCTL);
135         RegVal &= ~XUSBPSU_DCTL_INITU1ENA;
136         XUsbPsu_WriteReg(InstancePtr, XUSBPSU_DCTL, RegVal);
137
138         RegVal &= ~XUSBPSU_DCTL_INITU2ENA;
139         XUsbPsu_WriteReg(InstancePtr, XUSBPSU_DCTL, RegVal);
140
141         InstancePtr->IsConfigDone = 0U;
142         InstancePtr->AppData->Speed = XUSBPSU_SPEED_UNKNOWN;
143
144 #ifdef XUSBPSU_HIBERNATION_ENABLE
145         /* In USB 2.0, to avoid hibernation interrupt at the time of connection
146          * clear KEEP_CONNECT bit.
147          */
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);
153                 }
154         }
155 #endif
156
157         /* Call the handler if necessary */
158         if (InstancePtr->DisconnectIntrHandler != NULL) {
159                 InstancePtr->DisconnectIntrHandler(InstancePtr->AppData);
160         }
161 }
162
163 /****************************************************************************/
164 /**
165 * Stops any active transfer.
166 *
167 * @param        InstancePtr is a pointer to the XUsbPsu instance.
168 *
169 * @return       None.
170 *
171 * @note         None.
172 *
173 *****************************************************************************/
174 static void XUsbPsu_stop_active_transfers(struct XUsbPsu *InstancePtr)
175 {
176         u32 Epnum;
177
178         for (Epnum = 2; Epnum < XUSBPSU_ENDPOINTS_NUM; Epnum++) {
179                 struct XUsbPsu_Ep *Ept;
180
181                 Ept = &InstancePtr->eps[Epnum];
182                 if (!Ept)
183                         continue;
184
185                 if (!(Ept->EpStatus & XUSBPSU_EP_ENABLED))
186                         continue;
187
188                 XUsbPsu_StopTransfer(InstancePtr, Ept->UsbEpNum,
189                                 Ept->Direction, TRUE);
190         }
191 }
192
193 /****************************************************************************/
194 /**
195 * Clears stall on all stalled Eps.
196 *
197 * @param        InstancePtr is a pointer to the XUsbPsu instance.
198 *
199 * @return       None.
200 *
201 * @note         None.
202 *
203 *****************************************************************************/
204 static void XUsbPsu_clear_stall_all_ep(struct XUsbPsu *InstancePtr)
205 {
206         u32 Epnum;
207
208         for (Epnum = 1; Epnum < XUSBPSU_ENDPOINTS_NUM; Epnum++) {
209                 struct XUsbPsu_Ep *Ept;
210
211                 Ept = &InstancePtr->eps[Epnum];
212                 if (!Ept)
213                         continue;
214
215                 if (!(Ept->EpStatus & XUSBPSU_EP_ENABLED))
216                         continue;
217
218                 if (!(Ept->EpStatus & XUSBPSU_EP_STALL))
219                         continue;
220
221                 XUsbPsu_EpClearStall(InstancePtr, Ept->UsbEpNum, Ept->Direction);
222         }
223 }
224
225 /****************************************************************************/
226 /**
227 * Reset Interrupt handler.
228 *
229 * @param        InstancePtr is a pointer to the XUsbPsu instance.
230 *
231 * @return       None.
232 *
233 * @note         None.
234 *
235 *****************************************************************************/
236 void XUsbPsu_ResetIntr(struct XUsbPsu *InstancePtr)
237 {
238         u32     RegVal;
239         u32     Index;
240
241         InstancePtr->AppData->State = XUSBPSU_STATE_DEFAULT;
242
243         RegVal = XUsbPsu_ReadReg(InstancePtr, XUSBPSU_DCTL);
244         RegVal &= ~XUSBPSU_DCTL_TSTCTRL_MASK;
245         XUsbPsu_WriteReg(InstancePtr, XUSBPSU_DCTL, RegVal);
246         InstancePtr->TestMode = 0U;
247
248         XUsbPsu_stop_active_transfers(InstancePtr);
249         XUsbPsu_clear_stall_all_ep(InstancePtr);
250
251         for (Index = 0U; Index < (InstancePtr->NumInEps + InstancePtr->NumOutEps);
252                         Index++)
253         {
254                 InstancePtr->eps[Index].EpStatus = 0U;
255         }
256
257         InstancePtr->IsConfigDone = 0U;
258
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);
263
264         /* Call the handler if necessary */
265         if (InstancePtr->ResetIntrHandler != NULL) {
266                 InstancePtr->ResetIntrHandler(InstancePtr->AppData);
267         }
268 }
269
270 /****************************************************************************/
271 /**
272 * Connection Done Interrupt handler.
273 *
274 * @param        InstancePtr is a pointer to the XUsbPsu instance.
275 *
276 * @return       None.
277 *
278 * @note         None.
279 *
280 *****************************************************************************/
281 void XUsbPsu_ConnDoneIntr(struct XUsbPsu *InstancePtr)
282 {
283         u32                     RegVal;
284         u16                     Size;
285         u8                      Speed;
286
287         RegVal = XUsbPsu_ReadReg(InstancePtr, XUSBPSU_DSTS);
288         Speed = (u8)(RegVal & XUSBPSU_DSTS_CONNECTSPD);
289         InstancePtr->AppData->Speed = Speed;
290
291         switch (Speed) {
292         case XUSBPSU_DCFG_SUPERSPEED:
293 #ifdef XUSBPSU_DEBUG
294                 xil_printf("Super Speed\r\n");
295 #endif
296                 Size = 512U;
297                 InstancePtr->AppData->Speed = XUSBPSU_SPEED_SUPER;
298                 break;
299
300         case XUSBPSU_DCFG_HIGHSPEED:
301 #ifdef XUSBPSU_DEBUG
302                 xil_printf("High Speed\r\n");
303 #endif
304                 Size = 64U;
305                 InstancePtr->AppData->Speed = XUSBPSU_SPEED_HIGH;
306                 break;
307
308         case XUSBPSU_DCFG_FULLSPEED2:
309         case XUSBPSU_DCFG_FULLSPEED1:
310 #ifdef XUSBPSU_DEBUG
311                 xil_printf("Full Speed\r\n");
312 #endif
313                 Size = 64U;
314                 InstancePtr->AppData->Speed = XUSBPSU_SPEED_FULL;
315                 break;
316
317         case XUSBPSU_DCFG_LOWSPEED:
318 #ifdef XUSBPSU_DEBUG
319                 xil_printf("Low Speed\r\n");
320 #endif
321                 Size = 64U;
322                 InstancePtr->AppData->Speed = XUSBPSU_SPEED_LOW;
323                 break;
324         default :
325                 Size = 64U;
326                 break;
327         }
328
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);
333         }
334
335         (void)XUsbPsu_EnableControlEp(InstancePtr, Size);
336         (void)XUsbPsu_RecvSetup(InstancePtr);
337
338 #ifdef XUSBPSU_HIBERNATION_ENABLE
339         /* In USB 2.0, to avoid hibernation interrupt at the time of connection
340          * clear KEEP_CONNECT bit.
341          */
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);
347                 }
348         }
349 #endif
350 }
351
352 /****************************************************************************/
353 /**
354 * Link Status Change Interrupt handler.
355 *
356 * @param        InstancePtr is a pointer to the XUsbPsu instance.
357 * @param        EvtInfo is Event information.
358 *
359 * @return       None.
360 *
361 * @note         None.
362 *
363 *****************************************************************************/
364 void XUsbPsu_LinkStsChangeIntr(struct XUsbPsu *InstancePtr, u32 EvtInfo)
365 {
366         u32     State = EvtInfo & (u32)XUSBPSU_LINK_STATE_MASK;
367         InstancePtr->LinkState = (u8)State;
368 }
369
370 /****************************************************************************/
371 /**
372 * Interrupt handler for device specific events.
373 *
374 * @param        InstancePtr is a pointer to the XUsbPsu instance.
375 * @param        Event is the Device Event occured in core.
376 *
377 * @return       None.
378 *
379 * @note         None.
380 *
381 *****************************************************************************/
382 void XUsbPsu_DevInterrupt(struct XUsbPsu *InstancePtr,
383                 const struct XUsbPsu_Event_Devt *Event)
384 {
385
386         switch (Event->Type) {
387                 case XUSBPSU_DEVICE_EVENT_DISCONNECT:
388                         XUsbPsu_DisconnectIntr(InstancePtr);
389                         break;
390
391                 case XUSBPSU_DEVICE_EVENT_RESET:
392                         XUsbPsu_ResetIntr(InstancePtr);
393                         break;
394
395                 case XUSBPSU_DEVICE_EVENT_CONNECT_DONE:
396                         XUsbPsu_ConnDoneIntr(InstancePtr);
397                         break;
398
399                 case XUSBPSU_DEVICE_EVENT_WAKEUP:
400                         break;
401
402                 case XUSBPSU_DEVICE_EVENT_HIBER_REQ:
403 #ifdef XUSBPSU_HIBERNATION_ENABLE
404                         if (InstancePtr->HasHibernation)
405                                 Xusbpsu_HibernationIntr(InstancePtr);
406 #endif
407                         break;
408
409                 case XUSBPSU_DEVICE_EVENT_LINK_STATUS_CHANGE:
410                         XUsbPsu_LinkStsChangeIntr(InstancePtr,
411                                         Event->Event_Info);
412                         break;
413
414                 case XUSBPSU_DEVICE_EVENT_EOPF:
415                         break;
416
417                 case XUSBPSU_DEVICE_EVENT_SOF:
418                         break;
419
420                 case XUSBPSU_DEVICE_EVENT_ERRATIC_ERROR:
421                         break;
422
423                 case XUSBPSU_DEVICE_EVENT_CMD_CMPL:
424                         break;
425
426                 case XUSBPSU_DEVICE_EVENT_OVERFLOW:
427                         break;
428
429                 default:
430                         /* Made for Misra-C Compliance. */
431                         break;
432         }
433 }
434
435 /****************************************************************************/
436 /**
437 * Processes an Event entry in Event Buffer.
438 *
439 * @param        InstancePtr is a pointer to the XUsbPsu instance.
440 * @param        Event is the Event entry.
441 *
442 * @return       None.
443 *
444 * @note         None.
445 *
446 *****************************************************************************/
447 void XUsbPsu_EventHandler(struct XUsbPsu *InstancePtr,
448                         const union XUsbPsu_Event *Event)
449 {
450
451         if (Event->Type.Is_DevEvt == 0U) {
452                 /* End point Specific Event */
453                 XUsbPsu_EpInterrupt(InstancePtr, &Event->Epevt);
454                 return;
455         }
456
457         switch (Event->Type.Type) {
458         case XUSBPSU_EVENT_TYPE_DEV:
459                 /* Device Specific Event */
460                 XUsbPsu_DevInterrupt(InstancePtr, &Event->Devt);
461                 break;
462         /* Carkit and I2C events not supported now */
463         default:
464                 /* Made for Misra-C Compliance. */
465                 break;
466         }
467 }
468
469 /****************************************************************************/
470 /**
471 * Processes events in an Event Buffer.
472 *
473 * @param        InstancePtr is a pointer to the XUsbPsu instance.
474 * @bus          Event buffer number.
475 *
476 * @return       None.
477 *
478 * @note         None.
479 *
480 *****************************************************************************/
481 void XUsbPsu_EventBufferHandler(struct XUsbPsu *InstancePtr)
482 {
483         struct XUsbPsu_EvtBuffer *Evt;
484         union XUsbPsu_Event Event = {0};
485         u32 RegVal;
486
487         Evt = &InstancePtr->Evt;
488
489         if (InstancePtr->ConfigPtr->IsCacheCoherent == 0) {
490                 Xil_DCacheInvalidateRange((INTPTR)Evt->BuffAddr,
491                               (u32)XUSBPSU_EVENT_BUFFERS_SIZE);
492         }
493
494         while (Evt->Count > 0) {
495                 Event.Raw = *(UINTPTR *)((UINTPTR)Evt->BuffAddr + Evt->Offset);
496
497                 /*
498                  * Process the event received
499                  */
500                 XUsbPsu_EventHandler(InstancePtr, &Event);
501
502                 /* don't process anymore events if core is hibernated */
503                 if (InstancePtr->IsHibernated)
504                         return;
505
506                 Evt->Offset = (Evt->Offset + 4U) % XUSBPSU_EVENT_BUFFERS_SIZE;
507                 Evt->Count -= 4;
508                 XUsbPsu_WriteReg(InstancePtr, XUSBPSU_GEVNTCOUNT(0), 4U);
509         }
510
511         Evt->Count = 0;
512         Evt->Flags &= ~XUSBPSU_EVENT_PENDING;
513
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);
518 }
519
520 /****************************************************************************/
521 /**
522 * Main Interrupt Handler.
523 *
524 * @return       None.
525 *
526 * @note         None.
527 *
528 *****************************************************************************/
529 void XUsbPsu_IntrHandler(void *XUsbPsuInstancePtr)
530 {
531         struct XUsbPsu  *InstancePtr;
532         struct XUsbPsu_EvtBuffer *Evt;
533         u32 Count;
534         u32 RegVal;
535
536         InstancePtr = XUsbPsuInstancePtr;
537
538         Evt = &InstancePtr->Evt;
539
540         Count = XUsbPsu_ReadReg(InstancePtr, XUSBPSU_GEVNTCOUNT(0));
541         Count &= XUSBPSU_GEVNTCOUNT_MASK;
542         /*
543          * As per data book software should only process Events if Event count
544          * is greater than zero.
545          */
546         if (Count == 0U) {
547                 return;
548         }
549
550         Evt->Count = Count;
551         Evt->Flags |= XUSBPSU_EVENT_PENDING;
552
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);
557
558         /* Processes events in an Event Buffer */
559         XUsbPsu_EventBufferHandler(InstancePtr);
560 }
561
562 #ifdef XUSBPSU_HIBERNATION_ENABLE
563 /****************************************************************************/
564 /**
565 * Wakeup Interrupt Handler.
566 *
567 * @return       None.
568 *
569 * @note         None.
570 *
571 *****************************************************************************/
572 void XUsbPsu_WakeUpIntrHandler(void *XUsbPsuInstancePtr)
573 {
574         struct XUsbPsu  *InstancePtr = (struct XUsbPsu *)XUsbPsuInstancePtr;
575
576         XUsbPsu_WakeupIntr(InstancePtr);
577 }
578 #endif
579
580 /** @} */