handle split and intr transfers properly
[AROS.git] / arch / arm-native / soc / broadcom / 2708 / usb / usb2otg / usb2otg_device.c
blob966cc019e34a32c1c0d44662fd03f1ca017feb60
1 /*
2 Copyright � 2013-2015, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #define DEBUG 0
7 #include <aros/debug.h>
9 #include <proto/exec.h>
10 #include <proto/kernel.h>
11 #include <proto/utility.h>
13 #include <proto/alib.h>
14 #include <proto/mbox.h>
15 #include <hardware/videocore.h>
17 #include "usb2otg_intern.h"
19 #define DEVNAME "usb2otg.device"
21 const char devname[] = MOD_NAME_STRING;
23 AROS_INTP(FNAME_DEV(PendingInt));
24 AROS_INTP(FNAME_DEV(NakTimeoutInt));
26 IPTR __arm_periiobase __attribute__((used)) = 0 ;
28 ULONG last_frame = 0;
30 static void DumpChannelRegs(int channel)
32 D(bug("CHARBASE=%08x\n", rd32le(USB2OTG_CHANNEL_REG(channel, CHARBASE))));
33 D(bug("SPLITCTRL=%08x\n", rd32le(USB2OTG_CHANNEL_REG(channel, SPLITCTRL))));
34 D(bug("INTR=%08x\n", rd32le(USB2OTG_CHANNEL_REG(channel, INTR))));
35 D(bug("INTRMASK=%08x\n", rd32le(USB2OTG_CHANNEL_REG(channel, INTRMASK))));
36 D(bug("TRANSSIZE=%08x\n", rd32le(USB2OTG_CHANNEL_REG(channel, TRANSSIZE))));
37 D(bug("DMAADR=%08x\n", rd32le(USB2OTG_CHANNEL_REG(channel, DMAADDR))));
40 static void GlobalIRQHandler(struct USB2OTGUnit *USBUnit, struct ExecBase *SysBase)
42 volatile unsigned int otg_RegVal;
43 struct USB2OTGDevice * USB2OTGBase = USBUnit->hu_USB2OTGBase;
44 ULONG frnm = (rd32le(USB2OTG_HOSTFRAMENO) & 0x3fff) >> 3;
46 // D(bug("[USB2OTG] %s: Received USB interrupt for Unit @ 0x%p\n",
47 // __PRETTY_FUNCTION__, USBUnit));
49 otg_RegVal = rd32le(USB2OTG_INTR);
50 wr32le(USB2OTG_INTR, otg_RegVal);
52 if (otg_RegVal & USB2OTG_INTRCORE_DMASTARTOFFRAME)
54 struct IOUsbHWReq *req, *next;
56 wr32le(USB2OTG_INTR, USB2OTG_INTRCORE_DMASTARTOFFRAME);
58 if (frnm < last_frame)
60 D(bug("[USB2OTG] SOF, frame wrap %d %d\n", frnm, last_frame));
63 if (frnm != last_frame)
65 ForeachNodeSafe(&USBUnit->hu_IntXFerQueue, req, next)
67 ULONG last_handled = (ULONG)req->iouh_DriverPrivate1;
68 ULONG next_to_handle = (ULONG)req->iouh_DriverPrivate2;
70 /* Is it time to handle the request? If yes, move it to Scheduled list */
71 if (frnm == next_to_handle)
73 //D(bug("[USB2OTG] schedule INT request on time, last=%d, next=%d, frnm=%d\n", last_handled, next_to_handle, frnm));
74 REMOVE(req);
75 ADDTAIL(&USBUnit->hu_IntXFerScheduled, req);
78 If the request is overdued several scenarios are possible:
79 1. frnm is larger than "last" and "next"
80 0......last....next...frnm....2047
81 2. frnm is smaller than "last" and "next"
82 0..frnm.....last....next......2047
83 3. frnm is bigger than "next" but smaller than "last"
84 0..next....frnm......last.....2047
86 else if (
87 (frnm > next_to_handle && frnm > last_handled) ||
88 (frnm < last_handled && frnm > next_to_handle) ||
89 (frnm > next_to_handle && frnm < last_handled)
92 //D(bug("[USB2OTG] overdued INT request, scheduling. last=%d, next=%d, frnm=%d\n", last_handled, next_to_handle, frnm));
93 REMOVE(req);
94 ADDTAIL(&USBUnit->hu_IntXFerScheduled, req);
98 /* If the Scheduled list is not empty process it now */
99 if (!IsListEmpty(&USBUnit->hu_IntXFerScheduled))
100 FNAME_DEV(ScheduleIntTDs)(USBUnit);
102 last_frame = frnm;
106 if (otg_RegVal & USB2OTG_INTRCORE_HOSTCHANNEL)
108 unsigned int otg_ChanVal;
109 int chan;
111 otg_ChanVal = rd32le(USB2OTG_HOSTINTR);
112 wr32le(USB2OTG_HOSTINTR, otg_ChanVal);
114 //D(bug("[USB2OTG] HOSTCHANNEL %x frnm %d\n", otg_ChanVal, frnm));
116 for (chan = 0; chan < 8; chan++)
118 if (otg_ChanVal & (1 << chan))
120 struct IOUsbHWReq * req = USBUnit->hu_InProgressXFer[chan];
121 uint32_t tmp = rd32le(USB2OTG_CHANNEL_REG(chan, INTR));
123 if (req)
125 int do_split = rd32le(USB2OTG_CHANNEL_REG(chan, SPLITCTRL)) & 0x80010000;
127 Channel closed with ACK but not comleted yet and split is active. Complete split now, do not continue with
128 normal processing of this channel
130 if (tmp == 0x22 && do_split)
133 uint32_t split = rd32le(USB2OTG_CHANNEL_REG(chan, SPLITCTRL));
134 //D(bug("[USB2OTG] Completing split transaction in interrupt. SPLITCTRL=%08x\n", split));
136 split |= 1 << 16; /* Set "do complete split" */
137 wr32le(USB2OTG_CHANNEL_REG(chan, SPLITCTRL), split);
139 /* Clear interrupt flags */
140 wr32le(USB2OTG_CHANNEL_REG(chan, INTR), 0x7ff);
142 /* Enable channel again */
143 tmp = rd32le(USB2OTG_CHANNEL_REG(chan, CHARBASE));
144 tmp |= USB2OTG_HOSTCHAR_ENABLE;
145 wr32le(USB2OTG_CHANNEL_REG(chan, CHARBASE), tmp);
147 else if (tmp == 0x42 && do_split == 0x80010000)
149 ULONG last = (ULONG)req->iouh_DriverPrivate1;
150 ULONG thresh = (last + (ULONG)req->iouh_Interval / 2) % 2047;
152 /* Clear interrupt flags */
153 wr32le(USB2OTG_CHANNEL_REG(chan, INTR), 0x7ff);
155 if ((chan >= CHAN_INT1 && chan <= CHAN_INT3) &&
156 ((frnm > thresh && frnm > last) ||
157 (frnm < thresh && frnm < last) ||
158 (frnm > thresh && frnm < last)))
160 //D(bug("[USB2OTG] restarting transaction... %d, %d, %d\n", frnm, req->iouh_DriverPrivate1, req->iouh_DriverPrivate2));
162 /* Disable channel */
163 wr32le(USB2OTG_CHANNEL_REG(chan, CHARBASE), 0);
165 /* Put transfer back into queue */
166 if (req->iouh_Req.io_Command == UHCMD_CONTROLXFER)
167 ADDHEAD(&USBUnit->hu_CtrlXFerQueue, req);
168 if (req->iouh_Req.io_Command == UHCMD_BULKXFER)
169 ADDHEAD(&USBUnit->hu_BulkXFerQueue, req);
170 if (req->iouh_Req.io_Command == UHCMD_INTXFER)
171 ADDHEAD(&USBUnit->hu_IntXFerQueue, req);
173 /* Mark channel free */
174 USBUnit->hu_InProgressXFer[chan] = NULL;
176 else
178 //D(bug("!!! Channel %d, Restarting CSPLIT phase! %d, %d, %d\n", chan, frnm, req->iouh_DriverPrivate1, req->iouh_DriverPrivate2));
179 /* Enable channel again */
180 tmp = rd32le(USB2OTG_CHANNEL_REG(chan, CHARBASE));
181 tmp |= USB2OTG_HOSTCHAR_ENABLE;
182 wr32le(USB2OTG_CHANNEL_REG(chan, CHARBASE), tmp);
186 else if (tmp == 0x12 && do_split)
187 //&& (chan < CHAN_INT1 || chan > CHAN_INT3))
189 /* NAK response from split transaction. Restart the request from beginning */
190 /* D(bug("[USB2OTG] Restarting split transaction\n"));
192 DumpChannelRegs(chan);*/
194 /* Clear interrupt flags */
195 wr32le(USB2OTG_CHANNEL_REG(chan, INTR), 0x7ff);
197 /* Disable channel */
198 wr32le(USB2OTG_CHANNEL_REG(chan, CHARBASE), 0);
200 /* Put transfer back into queue */
201 if (req->iouh_Req.io_Command == UHCMD_CONTROLXFER)
202 ADDHEAD(&USBUnit->hu_CtrlXFerQueue, req);
203 if (req->iouh_Req.io_Command == UHCMD_BULKXFER)
204 ADDHEAD(&USBUnit->hu_BulkXFerQueue, req);
205 if (req->iouh_Req.io_Command == UHCMD_INTXFER)
206 ADDHEAD(&USBUnit->hu_IntXFerQueue, req);
208 /* Mark channel free */
209 USBUnit->hu_InProgressXFer[chan] = NULL;
211 else
213 /* Ignore NAK on INT channels when reporting closed channel */
214 if (tmp != 0x12 || (chan < CHAN_INT1 && chan > CHAN_INT3))
215 D(bug("[USB2OTG] Channel %d closed. INTR=%08x\n", chan, tmp));
217 if (tmp == 0x23)
219 /* Toggle PID */
220 USBUnit->hu_PIDBits[req->iouh_DevAddr] ^= (2 << (2 * req->iouh_Endpoint));
221 req->iouh_Actual = req->iouh_Length;
222 req->iouh_Req.io_Error = 0;
224 else if (tmp & 0x80)
226 req->iouh_Actual = 0;
227 req->iouh_Req.io_Error = UHIOERR_TIMEOUT;
228 DumpChannelRegs(chan);
230 else if (tmp & 0x08)
232 req->iouh_Actual = 0;
233 req->iouh_Req.io_Error = UHIOERR_STALL;
234 DumpChannelRegs(chan);
236 else if (tmp & 0x10)
238 /* In case of INT requests NAK is silently ignored. Just put the request back to the IntXferQueue */
239 if (chan >= CHAN_INT1 && chan <= CHAN_INT3)
241 ADDTAIL(&USBUnit->hu_IntXFerQueue, req);
242 req = NULL;
244 else
246 req->iouh_Actual = 0;
247 req->iouh_Req.io_Error = UHIOERR_NAK;
248 DumpChannelRegs(chan);
251 else if (tmp & 0x100)
253 req->iouh_Actual = 0;
254 req->iouh_Req.io_Error = UHIOERR_BABBLE;
255 DumpChannelRegs(chan);
257 else if (tmp & 0x400)
259 req->iouh_Actual = 0;
260 req->iouh_Req.io_Error = UHIOERR_HOSTERROR;
261 DumpChannelRegs(chan);
264 USBUnit->hu_InProgressXFer[chan] = NULL;
265 if (req) FNAME_DEV(TermIO)(req, USB2OTGBase);
267 wr32le(USB2OTG_CHANNEL_REG(chan, INTR), tmp);
274 FNAME_DEV(Cause)(USB2OTGBase, &USBUnit->hu_PendingInt);
276 if (USBUnit->hu_CtrlXFerQueue.lh_Head->ln_Succ)
278 D(bug("[USB2OTG] [0x%p:PEND] Process CtrlXFer ..\n", USBUnit));
279 FNAME_DEV(ScheduleCtrlTDs)(USBUnit);
284 *===========================================================
285 * Init(base)
286 *===========================================================
288 static int FNAME_DEV(Init)(LIBBASETYPEPTR USB2OTGBase)
290 void *MBoxBase = NULL;
291 volatile unsigned int otg_RegVal;
292 unsigned int otg_OperatingMode = 0;
293 ULONG *PwrOnMsg, *pwron = NULL;
295 KernelBase = OpenResource("kernel.resource");
296 MBoxBase = OpenResource("mbox.resource");
298 __arm_periiobase = KrnGetSystemAttr(KATTR_PeripheralBase);
300 D(bug("[USB2OTG] %s: USB2OTGBase @ 0x%p, SysBase @ 0x%p\n",
301 __PRETTY_FUNCTION__, USB2OTGBase, SysBase));
303 otg_RegVal = rd32le(USB2OTG_VENDORID);
305 if ((otg_RegVal & 0xFFFFF000) != 0x4F542000)
307 bug("[USB2OTG] Unsupported HS OTG USB Core Found\n");
308 bug("[USB2OTG] Hardware: %c%c%x.%x%x%x\n",
309 ((otg_RegVal >> 24) & 0xFF), ((otg_RegVal >> 16) & 0xFF),
310 ((otg_RegVal >> 12) & 0xF), ((otg_RegVal >> 8) & 0xF), ((otg_RegVal >> 4) & 0xF), (otg_RegVal & 0xF)
313 USB2OTGBase = NULL;
315 else
317 USB2OTGBase->hd_KernelBase = OpenResource("kernel.resource");
318 D(bug("[USB2OTG] %s: kernel.resource opened @ 0x%p\n",
319 __PRETTY_FUNCTION__, USB2OTGBase->hd_KernelBase));
321 if((USB2OTGBase->hd_MsgPort = CreateMsgPort()))
323 if((USB2OTGBase->hd_TimerReq = (struct timerequest *) CreateIORequest(USB2OTGBase->hd_MsgPort, sizeof(struct timerequest))))
325 if(!OpenDevice("timer.device", UNIT_MICROHZ, (struct IORequest *) USB2OTGBase->hd_TimerReq, 0))
327 USB2OTGBase->hd_TimerReq->tr_node.io_Message.mn_Node.ln_Name = "USB2OTG Timer";
328 USB2OTGBase->hd_TimerReq->tr_node.io_Command = TR_ADDREQUEST;
329 D(bug("[USB2OTG] %s: timer.device opened\n",
330 __PRETTY_FUNCTION__));
332 bug("[USB2OTG] HS OTG Core Release: %c%c%x.%x%x%x\n",
333 ((otg_RegVal >> 24) & 0xFF), ((otg_RegVal >> 16) & 0xFF),
334 ((otg_RegVal >> 12) & 0xF), ((otg_RegVal >> 8) & 0xF), ((otg_RegVal >> 4) & 0xF), (otg_RegVal & 0xF)
337 otg_RegVal = rd32le(USB2OTG_HARDWARE2);
338 bug("[USB2OTG] Architecture: %d - ", ((otg_RegVal & (3 << 3)) >> 3));
339 switch (((otg_RegVal & (3 << 3)) >> 3))
341 case 2:
342 bug("Internal DMA\n");
343 break;
344 case 1:
345 bug("External DMA\n");
346 break;
347 default:
348 bug("Slave Only\n");
349 break;
352 D(bug("[USB2OTG] %s: Disabling USB Interrupts (Globaly)..\n", __PRETTY_FUNCTION__));
353 otg_RegVal = rd32le(USB2OTG_AHB);
354 otg_RegVal &= ~USB2OTG_AHB_INTENABLE;
355 wr32le(USB2OTG_INTRMASK, 0);
356 wr32le(USB2OTG_AHB, otg_RegVal);
358 D(bug("[USB2OTG] Powering on USB controller\n"));
359 pwron = AllocVec(9*sizeof(ULONG), MEMF_CLEAR);
360 PwrOnMsg = (ULONG*)(((IPTR)pwron + 15) & ~15);
362 D(bug("[USB2OTG] pwron=%p, PwrOnMsg=%p\n", pwron, PwrOnMsg));
364 PwrOnMsg[0] = AROS_LE2LONG(8 * sizeof(ULONG));
365 PwrOnMsg[1] = AROS_LE2LONG(VCTAG_REQ);
366 PwrOnMsg[2] = AROS_LE2LONG(VCTAG_SETPOWER);
367 PwrOnMsg[3] = AROS_LE2LONG(8);
368 PwrOnMsg[4] = AROS_LE2LONG(0);
369 PwrOnMsg[5] = AROS_LE2LONG(VCPOWER_USBHCD);
370 PwrOnMsg[6] = AROS_LE2LONG(VCPOWER_STATE_ON | VCPOWER_STATE_WAIT);
371 PwrOnMsg[7] = 0;
373 MBoxWrite((void*)VCMB_BASE, VCMB_PROPCHAN, PwrOnMsg);
374 if (MBoxRead((void*)VCMB_BASE, VCMB_PROPCHAN) == PwrOnMsg)
376 D(bug("[USB2OTG] Power on state: %08x\n", AROS_LE2LONG(PwrOnMsg[6])));
377 if ((AROS_LE2LONG(PwrOnMsg[6]) & 1) == 0)
379 bug("[USB2OTG] Failed to power on USB controller\n");
380 USB2OTGBase = NULL;
383 if ((AROS_LE2LONG(PwrOnMsg[6]) & 2) != 0)
385 bug("[USB2OTG] USB HCD does not exist\n");
386 USB2OTGBase = NULL;
389 FreeVec(pwron);
390 PwrOnMsg = NULL;
392 if (!USB2OTGBase)
394 return FALSE;
397 if ((USB2OTGBase->hd_UtilityBase = (APTR)OpenLibrary("utility.library", 39)) != NULL)
399 USB2OTGBase->hd_MemPool = CreatePool(MEMF_PUBLIC | MEMF_CLEAR | MEMF_SEM_PROTECTED, 16384, 4096);
400 if (USB2OTGBase->hd_MemPool)
402 int ns;
404 D(bug("[USB2OTG] %s: Allocated MemPool @ 0x%p\n",
405 __PRETTY_FUNCTION__, USB2OTGBase->hd_MemPool));
407 if (USB2OTGBase)
410 otg_RegVal = rd32le(USB2OTG_HARDWARE);
411 bug("[USB2OTG] %s: HWConfig: %08x-", __PRETTY_FUNCTION__, otg_RegVal);
412 otg_RegVal = rd32le(USB2OTG_HARDWARE2);
413 bug("%08x-", otg_RegVal);
414 otg_RegVal = rd32le(USB2OTG_HARDWARE3);
415 bug("%08x-", otg_RegVal);
416 otg_RegVal = rd32le(USB2OTG_HARDWARE4);
417 bug("%08x\n", otg_RegVal);
420 if ((USB2OTGBase->hd_Unit = AllocPooled(USB2OTGBase->hd_MemPool, sizeof(struct USB2OTGUnit))) != NULL)
422 int i;
424 D(bug("[USB2OTG] %s: Unit Allocated at 0x%p\n",
425 __PRETTY_FUNCTION__, USB2OTGBase->hd_Unit));
427 NewList(&USB2OTGBase->hd_Unit->hu_IOPendingQueue);
429 NewList(&USB2OTGBase->hd_Unit->hu_CtrlXFerQueue);
430 NewList(&USB2OTGBase->hd_Unit->hu_IntXFerQueue);
431 NewList(&USB2OTGBase->hd_Unit->hu_IntXFerScheduled);
432 NewList(&USB2OTGBase->hd_Unit->hu_IsoXFerQueue);
433 NewList(&USB2OTGBase->hd_Unit->hu_BulkXFerQueue);
434 NewList(&USB2OTGBase->hd_Unit->hu_TDQueue);
435 NewList(&USB2OTGBase->hd_Unit->hu_AbortQueue);
436 NewList(&USB2OTGBase->hd_Unit->hu_PeriodicTDQueue);
438 USB2OTGBase->hd_Unit->hu_PendingInt.is_Node.ln_Type = NT_INTERRUPT;
439 USB2OTGBase->hd_Unit->hu_PendingInt.is_Node.ln_Name = "OTG2USB Pending Work Interrupt";
440 USB2OTGBase->hd_Unit->hu_PendingInt.is_Node.ln_Pri = 0;
441 USB2OTGBase->hd_Unit->hu_PendingInt.is_Data = USB2OTGBase->hd_Unit;
442 USB2OTGBase->hd_Unit->hu_PendingInt.is_Code = (VOID_FUNC)FNAME_DEV(PendingInt);
444 USB2OTGBase->hd_Unit->hu_NakTimeoutInt.is_Node.ln_Type = NT_INTERRUPT;
445 USB2OTGBase->hd_Unit->hu_NakTimeoutInt.is_Node.ln_Name = "OTG2USB NakTimeout Interrupt";
446 USB2OTGBase->hd_Unit->hu_NakTimeoutInt.is_Node.ln_Pri = -16;
447 USB2OTGBase->hd_Unit->hu_NakTimeoutInt.is_Data = USB2OTGBase->hd_Unit;
448 USB2OTGBase->hd_Unit->hu_NakTimeoutInt.is_Code = (VOID_FUNC)FNAME_DEV(NakTimeoutInt);
450 USB2OTGBase->hd_Unit->hu_NakTimeoutMsgPort.mp_Node.ln_Type = NT_MSGPORT;
451 USB2OTGBase->hd_Unit->hu_NakTimeoutMsgPort.mp_Flags = PA_SOFTINT;
452 USB2OTGBase->hd_Unit->hu_NakTimeoutMsgPort.mp_SigTask = &USB2OTGBase->hd_Unit->hu_NakTimeoutInt;
453 NewList(&USB2OTGBase->hd_Unit->hu_NakTimeoutMsgPort.mp_MsgList);
455 CopyMem(USB2OTGBase->hd_TimerReq, &USB2OTGBase->hd_Unit->hu_NakTimeoutReq, sizeof(struct timerequest));
456 USB2OTGBase->hd_Unit->hu_NakTimeoutReq.tr_node.io_Message.mn_ReplyPort = &USB2OTGBase->hd_Unit->hu_NakTimeoutMsgPort;
458 USB2OTGBase->hd_Unit->hu_HubPortChanged = FALSE;
460 USB2OTGBase->hd_Unit->hu_OperatingMode = (otg_OperatingMode == (USB2OTG_USBHOSTMODE|USB2OTG_USBDEVICEMODE)) ? 0 : otg_OperatingMode;
462 for (i=0; i < 128; i++)
463 USB2OTGBase->hd_Unit->hu_PIDBits[i] = 0;
465 #if (0)
466 D(bug("[USB2OTG] %s: Unit Mode %d\n",
467 __PRETTY_FUNCTION__, USB2OTGBase->hd_Unit->hu_OperatingMode));
468 #endif
469 USB2OTGBase->hd_Unit->hu_GlobalIRQHandle = KrnAddIRQHandler(IRQ_VC_USB, GlobalIRQHandler, USB2OTGBase->hd_Unit, SysBase);
471 USB2OTGBase->hd_Unit->hu_USB2OTGBase = USB2OTGBase;
473 D(bug("[USB2OTG] %s: Installed Global IRQ Handler [handle @ 0x%p] for IRQ #%ld\n",
474 __PRETTY_FUNCTION__, USB2OTGBase->hd_Unit->hu_GlobalIRQHandle, IRQ_HOSTPORT));
476 otg_RegVal = rd32le(USB2OTG_USB);
477 otg_RegVal &= ~(USB2OTG_USB_ULPIDRIVEEXTERNALVBUS|USB2OTG_USB_TSDLINEPULSEENABLE);
478 wr32le(USB2OTG_USB, otg_RegVal);
480 D(bug("[USB2OTG] %s: Reseting Controller ..\n", __PRETTY_FUNCTION__));
481 wr32le(USB2OTG_RESET, USB2OTG_RESET_CORESOFT);
482 for (ns = 0; ns < 10000; ns++) { asm volatile("mov r0, r0\n"); } // Wait 10ms
483 if ((rd32le(USB2OTG_RESET) & USB2OTG_RESET_CORESOFT) != 0)
484 bug("[USB2OTG] %s: Reset Timed-Out!\n", __PRETTY_FUNCTION__);
486 D(bug("[USB2OTG] %s: Initialising PHY ..\n", __PRETTY_FUNCTION__));
487 otg_RegVal = rd32le(USB2OTG_USB);
488 otg_RegVal &= ~USB2OTG_USB_PHYINTERFACE;
489 otg_RegVal &= ~USB2OTG_USB_MODESELECT_UTMI;
490 wr32le(USB2OTG_USB, otg_RegVal);
492 #if (0)
493 D(bug("[USB2OTG] %s: Reseting Controller ..\n", __PRETTY_FUNCTION__));
494 wr32le(USB2OTG_RESET, USB2OTG_RESET_CORESOFT);
495 for (ns = 0; ns < 10000; ns++) { asm volatile("mov r0, r0\n"); } // Wait 10ms
496 if ((rd32le(USB2OTG_RESET) & USB2OTG_RESET_CORESOFT) != 0)
497 bug("[USB2OTG] %s: Reset Timed-Out!\n", __PRETTY_FUNCTION__);
498 #endif
500 otg_RegVal = rd32le(USB2OTG_HARDWARE2);
501 if (((otg_RegVal & (3 << 6) >> 6) == 2) && ((otg_RegVal & (3 << 8) >> 8) == 1))
503 D(bug("[USB2OTG] %s: ULPI FSLS configuration: enabled.\n", __PRETTY_FUNCTION__));
504 otg_RegVal = rd32le(USB2OTG_USB);
505 otg_RegVal |= (USB2OTG_USB_ULPIFSLS|USB2OTG_USB_ULPI_CLK_SUS_M);
506 wr32le(USB2OTG_USB, otg_RegVal);
507 } else {
508 D(bug("[USB2OTG] %s: ULPI FSLS configuration: disabled.\n", __PRETTY_FUNCTION__));
509 otg_RegVal = rd32le(USB2OTG_USB);
510 otg_RegVal &= ~(USB2OTG_USB_ULPIFSLS|USB2OTG_USB_ULPI_CLK_SUS_M);
511 wr32le(USB2OTG_USB, otg_RegVal);
514 D(bug("[USB2OTG] %s: Enabling DMA configuration..\n", __PRETTY_FUNCTION__));
515 otg_RegVal = rd32le(USB2OTG_AHB);
516 otg_RegVal &= ~(1 << USB2OTG_AHB_DMAREMAINDERMODE);
517 otg_RegVal |= (1 << 4) | (USB2OTG_AHB_DMAENABLE|USB2OTG_AHB_DMAREMAINDERMODE_INCR);
518 D(bug("[USB2OTG] %s: AHB reg: %08x..\n", __PRETTY_FUNCTION__, otg_RegVal));
519 wr32le(USB2OTG_AHB, otg_RegVal);
521 #if (0)
522 D(bug("[USB2OTG] %s: Operating Mode: ", __PRETTY_FUNCTION__));
523 otg_RegVal = rd32le(USB2OTG_HARDWARE2);
524 switch (otg_RegVal & 7)
526 case 0:
527 D(bug("HNP/SRP\n"));
528 otg_RegVal = rd32le(USB2OTG_USB);
529 otg_RegVal |= (USB2OTG_USB_HNPCAPABLE|USB2OTG_USB_SRPCAPABLE);
530 wr32le(USB2OTG_USB, otg_RegVal);
531 break;
532 case 1:
533 case 3:
534 case 5:
535 D(bug("SRP\n"));
536 otg_RegVal = rd32le(USB2OTG_USB);
537 otg_RegVal &= ~USB2OTG_USB_HNPCAPABLE;
538 otg_RegVal |= USB2OTG_USB_SRPCAPABLE;
539 wr32le(USB2OTG_USB, otg_RegVal);
540 break;
541 case 2:
542 case 4:
543 case 6:
544 D(bug("No HNP or SRP\n"));
545 otg_RegVal = rd32le(USB2OTG_USB);
546 otg_RegVal &= ~(USB2OTG_USB_HNPCAPABLE|USB2OTG_USB_SRPCAPABLE);
547 wr32le(USB2OTG_USB, otg_RegVal);
548 break;
550 #else
551 D(bug("[USB2OTG] %s: Disable HNP/SRP\n", __PRETTY_FUNCTION__));
552 otg_RegVal = rd32le(USB2OTG_USB);
553 otg_RegVal &= ~(USB2OTG_USB_HNPCAPABLE|USB2OTG_USB_SRPCAPABLE);
554 wr32le(USB2OTG_USB, otg_RegVal);
555 #endif
557 D(bug("[USB2OTG] %s: Enabling Global Interrupts ...\n", __PRETTY_FUNCTION__));
558 otg_RegVal = rd32le(USB2OTG_INTR);
559 otg_RegVal = ~0UL;
560 wr32le(USB2OTG_INTR, otg_RegVal);
562 otg_RegVal = rd32le(USB2OTG_INTRMASK);
563 otg_RegVal |= USB2OTG_INTRCORE_DMASTARTOFFRAME;
564 wr32le(USB2OTG_INTRMASK, otg_RegVal);
566 otg_RegVal = rd32le(USB2OTG_AHB);
567 otg_RegVal |= USB2OTG_AHB_INTENABLE;
568 wr32le(USB2OTG_AHB, otg_RegVal);
570 bug("[USB2OTG] HS OTG USB Driver Initialised\n");
574 else
576 D(bug("[USB2OTG] %s: Failed to Create MemPool\n",
577 __PRETTY_FUNCTION__));
579 CloseLibrary((struct Library *) UtilityBase);
580 USB2OTGBase = NULL;
583 else
585 D(bug("[USB2OTG] %s: OpenLibrary(\"utility.library\", 39) failed!\n",
586 __PRETTY_FUNCTION__));
588 USB2OTGBase = NULL;
591 else
593 D(bug("[USB2OTG] %s: OpenDevice(\"timer.device\") failed!\n",
594 __PRETTY_FUNCTION__));
596 USB2OTGBase = NULL;
599 else
601 D(bug("[USB2OTG] %s: Failed to allocate timer IORequest\n",
602 __PRETTY_FUNCTION__));
604 USB2OTGBase = NULL;
607 else
609 D(bug("[USB2OTG] %s: Failed to create MsgPort\n",
610 __PRETTY_FUNCTION__));
612 USB2OTGBase = NULL;
616 return USB2OTGBase ? TRUE : FALSE;
620 *===========================================================
621 * Open(ioreq, unit, flags, base)
622 *===========================================================
624 * This is the the DEV_OPEN function.
627 static int FNAME_DEV(Open)(LIBBASETYPEPTR USB2OTGBase, struct IOUsbHWReq *ioreq, ULONG otg_Unit, ULONG flags)
629 D(bug("[USB2OTG] %s: IOReq @ 0x%p, unit #%ld, flags = 0x%08lx, USB2OTGBase @ 0x%p\n",
630 __PRETTY_FUNCTION__, ioreq, otg_Unit, flags, USB2OTGBase));
632 D(bug("[USB2OTG] %s: openCnt = %ld\n",
633 __PRETTY_FUNCTION__, USB2OTGBase->hd_Library.lib_OpenCnt));
635 if (ioreq->iouh_Req.io_Message.mn_Length < sizeof(struct IOUsbHWReq))
637 D(bug("[USB2OTG] %s: invalid MN_LENGTH!\n",
638 __PRETTY_FUNCTION__));
640 ioreq->iouh_Req.io_Error = IOERR_BADLENGTH;
642 else
644 ioreq->iouh_Req.io_Error = IOERR_OPENFAIL;
646 ioreq->iouh_Req.io_Unit = FNAME_DEV(OpenUnit)(ioreq, otg_Unit, USB2OTGBase);
647 if (!(ioreq->iouh_Req.io_Unit))
649 D(bug("[USB2OTG] %s: could not open unit!\n",
650 __PRETTY_FUNCTION__));
653 else
655 ioreq->iouh_Req.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
656 ioreq->iouh_Req.io_Error = 0;
658 return TRUE;
662 return FALSE;
667 *===========================================================
668 * Close(ioreq, base)
669 *===========================================================
671 * This is the the DEV_EXPUNGE function.
674 static int FNAME_DEV(Close)(LIBBASETYPEPTR USB2OTGBase, struct IOUsbHWReq *ioreq)
676 D(bug("[USB2OTG] %s: IOReq @ 0x%p, USB2OTGBase @ 0x%p\n",
677 __PRETTY_FUNCTION__, ioreq, USB2OTGBase));
679 FNAME_DEV(CloseUnit)(ioreq, (struct USB2OTGUnit *) ioreq->iouh_Req.io_Unit, USB2OTGBase);
681 ioreq->iouh_Req.io_Unit = (APTR) -1;
682 ioreq->iouh_Req.io_Device = (APTR) -1;
683 return TRUE;
686 static int FNAME_DEV(Expunge)(LIBBASETYPEPTR USB2OTGBase)
688 DeletePool(USB2OTGBase->hd_MemPool);
690 D(bug("[USB2OTG] %s: closing utility.library @ 0x%p\n",
691 __PRETTY_FUNCTION__, UtilityBase));
693 CloseLibrary((struct Library *) UtilityBase);
694 return TRUE;
697 ADD2INITLIB(FNAME_DEV(Init), 0)
698 ADD2OPENDEV(FNAME_DEV(Open), 0)
699 ADD2CLOSEDEV(FNAME_DEV(Close), 0)
700 ADD2EXPUNGELIB(FNAME_DEV(Expunge), 0)
703 *===========================================================
704 * BeginIO(ioreq, base)
705 *===========================================================
707 * This is the DEV_BEGINIO vector of the device.
710 AROS_LH1(void, FNAME_DEV(BeginIO),
711 AROS_LHA(struct IOUsbHWReq *, ioreq, A1),
712 LIBBASETYPEPTR, USB2OTGBase, 5, usb2otg)
714 AROS_LIBFUNC_INIT
716 struct USB2OTGUnit *otg_Unit = (struct USB2OTGUnit *) ioreq->iouh_Req.io_Unit;
717 WORD ret;
719 D(bug("[USB2OTG] %s: IOReq @ 0x%08lx, USB2OTGBase @ 0x%08lx [cmd:%lu]\n",
720 __PRETTY_FUNCTION__, ioreq, USB2OTGBase, ioreq->iouh_Req.io_Command));
722 ioreq->iouh_Req.io_Message.mn_Node.ln_Type = NT_MESSAGE;
723 ioreq->iouh_Req.io_Error = UHIOERR_NO_ERROR;
725 if (ioreq->iouh_Req.io_Command < NSCMD_DEVICEQUERY)
727 switch (ioreq->iouh_Req.io_Command)
729 case CMD_RESET:
730 ret = FNAME_DEV(cmdReset)(ioreq, otg_Unit, USB2OTGBase);
731 break;
733 case CMD_FLUSH:
734 ret = FNAME_DEV(cmdFlush)(ioreq, otg_Unit, USB2OTGBase);
735 break;
737 case UHCMD_QUERYDEVICE:
738 ret = FNAME_DEV(cmdQueryDevice)(ioreq, otg_Unit, USB2OTGBase);
739 break;
741 case UHCMD_USBRESET:
742 ret = FNAME_DEV(cmdUsbReset)(ioreq, otg_Unit, USB2OTGBase);
743 break;
745 case UHCMD_USBRESUME:
746 ret = FNAME_DEV(cmdUsbResume)(ioreq, otg_Unit, USB2OTGBase);
747 break;
749 case UHCMD_USBSUSPEND:
750 ret = FNAME_DEV(cmdUsbSuspend)(ioreq, otg_Unit, USB2OTGBase);
751 break;
753 case UHCMD_USBOPER:
754 ret = FNAME_DEV(cmdUsbOper)(ioreq, otg_Unit, USB2OTGBase);
755 break;
757 case UHCMD_CONTROLXFER:
758 ret = FNAME_DEV(cmdControlXFer)(ioreq, otg_Unit, USB2OTGBase);
759 break;
761 case UHCMD_BULKXFER:
762 ret = FNAME_DEV(cmdBulkXFer)(ioreq, otg_Unit, USB2OTGBase);
763 break;
765 case UHCMD_INTXFER:
766 ret = FNAME_DEV(cmdIntXFer)(ioreq, otg_Unit, USB2OTGBase);
767 break;
769 case UHCMD_ISOXFER:
770 ret = FNAME_DEV(cmdIsoXFer)(ioreq, otg_Unit, USB2OTGBase);
771 break;
773 default:
774 ret = IOERR_NOCMD;
775 break;
778 else
780 switch(ioreq->iouh_Req.io_Command)
782 case NSCMD_DEVICEQUERY:
783 ret = FNAME_DEV(cmdNSDeviceQuery)((struct IOStdReq *) ioreq, otg_Unit, USB2OTGBase);
784 break;
786 default:
787 ret = IOERR_NOCMD;
788 break;
792 if (ret != RC_DONTREPLY)
794 D(bug("[USB2OTG] %s: Terminating I/O..\n",
795 __PRETTY_FUNCTION__));
797 if (ret != RC_OK)
799 ioreq->iouh_Req.io_Error = ret & 0xff;
801 FNAME_DEV(TermIO)(ioreq, USB2OTGBase);
804 AROS_LIBFUNC_EXIT
808 *===========================================================
809 * AbortIO(ioreq, base)
810 *===========================================================
812 * This is the DEV_ABORTIO vector of the device. It abort
813 * the given iorequest, and set
816 AROS_LH1(LONG, FNAME_DEV(AbortIO),
817 AROS_LHA(struct IOUsbHWReq *, ioreq, A1),
818 LIBBASETYPEPTR, USB2OTGBase, 6, usb2otg)
820 AROS_LIBFUNC_INIT
822 D(bug("[USB2OTG] %s: IOReq @ 0x%p, command %ld, status %ld\n",
823 __PRETTY_FUNCTION__, ioreq, ioreq->iouh_Req.io_Command, ioreq->iouh_Req.io_Message.mn_Node.ln_Type));
825 /* Is it pending? */
826 if (ioreq->iouh_Req.io_Message.mn_Node.ln_Type == NT_MESSAGE)
828 #if (0)
829 if (FNAME_DEV(cmdAbortIO)(ioreq, USB2OTGBase))
831 return(0);
833 #endif
835 return(-1);
837 AROS_LIBFUNC_EXIT
840 void FNAME_DEV(Cause)(LIBBASETYPEPTR USB2OTGBase, struct Interrupt *interrupt)
842 Cause(interrupt);
843 #if 0
844 /* this is a workaround for the original Cause() function missing tailed calls */
845 Disable();
847 if((interrupt->is_Node.ln_Type == NT_SOFTINT) || (interrupt->is_Node.ln_Type == NT_USER))
849 // signal tailed call
850 interrupt->is_Node.ln_Type = NT_USER;
851 } else {
854 interrupt->is_Node.ln_Type = NT_SOFTINT;
855 Forbid(); // make sure code is not interrupted by other tasks
856 Enable();
857 AROS_INTC1(interrupt->is_Code, interrupt->is_Data);
858 Disable();
859 Permit();
860 } while(interrupt->is_Node.ln_Type != NT_SOFTINT);
861 interrupt->is_Node.ln_Type = NT_INTERRUPT;
863 Enable();
864 #endif