2 Copyright © 2013, The AROS Development Team. All rights reserved.
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>
15 #include <asm/bcm2835.h>
16 #include <hardware/usb2otg.h>
18 #include "usb2otg_intern.h"
20 #define DEVNAME "usb2otg.device"
22 const char devname
[] = MOD_NAME_STRING
;
24 AROS_INTP(FNAME_DEV(PendingInt
));
25 AROS_INTP(FNAME_DEV(NakTimeoutInt
));
27 static void GlobalIRQHandler(struct USB2OTGUnit
*USBUnit
, struct ExecBase
*SysBase
)
29 D(bug("[USB2OTG] %s: Received USB interrupt for Unit @ 0x%p\n",
30 __PRETTY_FUNCTION__
, USBUnit
));
34 *===========================================================
36 *===========================================================
38 static int FNAME_DEV(Init
)(LIBBASETYPEPTR USB2OTGBase
)
40 volatile unsigned int *pmmailbox
= (ARM_PERIIOBASE
+ 0xB880);
41 volatile unsigned int otg_RegVal
;
42 unsigned int otg_OperatingMode
= 0, pmres
;
44 D(bug("[USB2OTG] %s: USB2OTGBase @ 0x%p, SysBase @ 0x%p\n",
45 __PRETTY_FUNCTION__
, USB2OTGBase
, SysBase
));
47 otg_RegVal
= *((volatile unsigned int *)USB2OTG_VENDORID
);
49 if ((otg_RegVal
& 0xFFFFF000) != 0x4F542000)
51 bug("[USB2OTG] Unsupported HS OTG USB Core Found\n");
52 bug("[USB2OTG] Hardware: %c%c%x.%x%x%x\n",
53 ((otg_RegVal
>> 24) & 0xFF), ((otg_RegVal
>> 16) & 0xFF),
54 ((otg_RegVal
>> 12) & 0xF), ((otg_RegVal
>> 8) & 0xF), ((otg_RegVal
>> 4) & 0xF), (otg_RegVal
& 0xF)
61 USB2OTGBase
->hd_KernelBase
= OpenResource("kernel.resource");
62 D(bug("[USB2OTG] %s: kernel.resource opened @ 0x%p\n",
63 __PRETTY_FUNCTION__
, USB2OTGBase
->hd_KernelBase
));
65 if((USB2OTGBase
->hd_MsgPort
= CreateMsgPort()))
67 if((USB2OTGBase
->hd_TimerReq
= (struct timerequest
*) CreateIORequest(USB2OTGBase
->hd_MsgPort
, sizeof(struct timerequest
))))
69 if(!OpenDevice("timer.device", UNIT_MICROHZ
, (struct IORequest
*) USB2OTGBase
->hd_TimerReq
, 0))
71 USB2OTGBase
->hd_TimerReq
->tr_node
.io_Message
.mn_Node
.ln_Name
= "USB2OTG Timer";
72 USB2OTGBase
->hd_TimerReq
->tr_node
.io_Command
= TR_ADDREQUEST
;
73 D(bug("[USB2OTG] %s: timer.device opened\n",
74 __PRETTY_FUNCTION__
));
76 bug("[USB2OTG] HS OTG Core Release: %c%c%x.%x%x%x\n",
77 ((otg_RegVal
>> 24) & 0xFF), ((otg_RegVal
>> 16) & 0xFF),
78 ((otg_RegVal
>> 12) & 0xF), ((otg_RegVal
>> 8) & 0xF), ((otg_RegVal
>> 4) & 0xF), (otg_RegVal
& 0xF)
81 otg_RegVal
= *((volatile unsigned int *)USB2OTG_HARDWARE2
);
82 bug("[USB2OTG] Architecture: %d - ", ((otg_RegVal
& (3 << 3)) >> 3));
83 switch (((otg_RegVal
& (3 << 3)) >> 3))
86 bug("Internal DMA\n");
89 bug("External DMA\n");
96 D(bug("[USB2OTG] %s: Disabling USB Interrupts (Globaly)..\n", __PRETTY_FUNCTION__
));
97 otg_RegVal
= *((volatile unsigned int *)USB2OTG_AHB
);
98 otg_RegVal
&= ~USB2OTG_AHB_INTENABLE
;
99 *((volatile unsigned int *)USB2OTG_INTRMASK
) = 0;
100 *((volatile unsigned int *)USB2OTG_AHB
) = otg_RegVal
;
102 while (pmmailbox
[6] & 0x80000000);
105 while (pmmailbox
[6] & 0x40000000);
106 } while (((pmres
= pmmailbox
[0]) & 0xf) != 0);
109 bug("[USB2OTG] Failed to power on controller\n");
110 //USB2OTGBase->hd_TimerReq
111 //USB2OTGBase->hd_MsgPort
116 if ((USB2OTGBase
->hd_UtilityBase
= (APTR
)OpenLibrary("utility.library", 39)) != NULL
)
118 USB2OTGBase
->hd_MemPool
= CreatePool(MEMF_PUBLIC
| MEMF_CLEAR
| MEMF_SEM_PROTECTED
, 16384, 4096);
119 if (USB2OTGBase
->hd_MemPool
)
123 D(bug("[USB2OTG] %s: Allocated MemPool @ 0x%p\n",
124 __PRETTY_FUNCTION__
, USB2OTGBase
->hd_MemPool
));
129 otg_RegVal
= *((volatile unsigned int *)USB2OTG_HARDWARE
);
130 bug("[USB2OTG] %s: HWConfig: %08x-", __PRETTY_FUNCTION__
, otg_RegVal
);
131 otg_RegVal
= *((volatile unsigned int *)USB2OTG_HARDWARE2
);
132 bug("%08x-", otg_RegVal
);
133 otg_RegVal
= *((volatile unsigned int *)USB2OTG_HARDWARE3
);
134 bug("%08x-", otg_RegVal
);
135 otg_RegVal
= *((volatile unsigned int *)USB2OTG_HARDWARE4
);
136 bug("%08x\n", otg_RegVal
);
139 otg_RegVal
= *((volatile unsigned int *)USB2OTG_USB
);
140 otg_RegVal
&= ~(USB2OTG_USB_ULPIDRIVEEXTERNALVBUS
|USB2OTG_USB_TSDLINEPULSEENABLE
);
141 *((volatile unsigned int *)USB2OTG_USB
) = otg_RegVal
;
143 D(bug("[USB2OTG] %s: Reseting Controller ..\n", __PRETTY_FUNCTION__
));
144 *((volatile unsigned int *)USB2OTG_RESET
) = USB2OTG_RESET_CORESOFT
;
145 for (ns
= 0; ns
< 10000; ns
++) { asm volatile("mov r0, r0\n"); } // Wait 10ms
146 if ((*((volatile unsigned int *)USB2OTG_RESET
) & USB2OTG_RESET_CORESOFT
) != 0)
147 bug("[USB2OTG] %s: Reset Timed-Out!\n", __PRETTY_FUNCTION__
);
149 if ((USB2OTGBase
->hd_Unit
= AllocPooled(USB2OTGBase
->hd_MemPool
, sizeof(struct USB2OTGUnit
))) != NULL
)
151 D(bug("[USB2OTG] %s: Unit Allocated at 0x%p\n",
152 __PRETTY_FUNCTION__
, USB2OTGBase
->hd_Unit
));
154 NewList(&USB2OTGBase
->hd_Unit
->hu_IOPendingQueue
);
156 NewList(&USB2OTGBase
->hd_Unit
->hu_CtrlXFerQueue
);
157 NewList(&USB2OTGBase
->hd_Unit
->hu_IntXFerQueue
);
158 NewList(&USB2OTGBase
->hd_Unit
->hu_IsoXFerQueue
);
159 NewList(&USB2OTGBase
->hd_Unit
->hu_BulkXFerQueue
);
160 NewList(&USB2OTGBase
->hd_Unit
->hu_TDQueue
);
161 NewList(&USB2OTGBase
->hd_Unit
->hu_AbortQueue
);
162 NewList(&USB2OTGBase
->hd_Unit
->hu_PeriodicTDQueue
);
164 USB2OTGBase
->hd_Unit
->hu_PendingInt
.is_Node
.ln_Type
= NT_INTERRUPT
;
165 USB2OTGBase
->hd_Unit
->hu_PendingInt
.is_Node
.ln_Name
= "OTG2USB Pending Work Interrupt";
166 USB2OTGBase
->hd_Unit
->hu_PendingInt
.is_Node
.ln_Pri
= 0;
167 USB2OTGBase
->hd_Unit
->hu_PendingInt
.is_Data
= USB2OTGBase
->hd_Unit
;
168 USB2OTGBase
->hd_Unit
->hu_PendingInt
.is_Code
= (VOID_FUNC
)FNAME_DEV(PendingInt
);
170 USB2OTGBase
->hd_Unit
->hu_NakTimeoutInt
.is_Node
.ln_Type
= NT_INTERRUPT
;
171 USB2OTGBase
->hd_Unit
->hu_NakTimeoutInt
.is_Node
.ln_Name
= "OTG2USB NakTimeout Interrupt";
172 USB2OTGBase
->hd_Unit
->hu_NakTimeoutInt
.is_Node
.ln_Pri
= -16;
173 USB2OTGBase
->hd_Unit
->hu_NakTimeoutInt
.is_Data
= USB2OTGBase
->hd_Unit
;
174 USB2OTGBase
->hd_Unit
->hu_NakTimeoutInt
.is_Code
= (VOID_FUNC
)FNAME_DEV(NakTimeoutInt
);
176 USB2OTGBase
->hd_Unit
->hu_NakTimeoutMsgPort
.mp_Node
.ln_Type
= NT_MSGPORT
;
177 USB2OTGBase
->hd_Unit
->hu_NakTimeoutMsgPort
.mp_Flags
= PA_SOFTINT
;
178 USB2OTGBase
->hd_Unit
->hu_NakTimeoutMsgPort
.mp_SigTask
= &USB2OTGBase
->hd_Unit
->hu_NakTimeoutInt
;
179 NewList(&USB2OTGBase
->hd_Unit
->hu_NakTimeoutMsgPort
.mp_MsgList
);
181 CopyMem(USB2OTGBase
->hd_TimerReq
, &USB2OTGBase
->hd_Unit
->hu_NakTimeoutReq
, sizeof(struct timerequest
));
182 USB2OTGBase
->hd_Unit
->hu_NakTimeoutReq
.tr_node
.io_Message
.mn_ReplyPort
= &USB2OTGBase
->hd_Unit
->hu_NakTimeoutMsgPort
;
184 USB2OTGBase
->hd_Unit
->hu_HubPortChanged
= FALSE
;
186 USB2OTGBase
->hd_Unit
->hu_OperatingMode
= (otg_OperatingMode
== (USB2OTG_USBHOSTMODE
|USB2OTG_USBDEVICEMODE
)) ? 0 : otg_OperatingMode
;
189 D(bug("[USB2OTG] %s: Unit Mode %d\n",
190 __PRETTY_FUNCTION__
, USB2OTGBase
->hd_Unit
->hu_OperatingMode
));
192 USB2OTGBase
->hd_Unit
->hu_GlobalIRQHandle
= KrnAddIRQHandler(IRQ_HOSTPORT
, GlobalIRQHandler
, USB2OTGBase
->hd_Unit
, SysBase
);
194 D(bug("[USB2OTG] %s: Installed Global IRQ Handler [handle @ 0x%p] for IRQ #%ld\n",
195 __PRETTY_FUNCTION__
, USB2OTGBase
->hd_Unit
->hu_GlobalIRQHandle
, IRQ_HOSTPORT
));
197 D(bug("[USB2OTG] %s: Initialising PHY ..\n", __PRETTY_FUNCTION__
));
198 otg_RegVal
= *((volatile unsigned int *)USB2OTG_USB
);
199 otg_RegVal
&= ~USB2OTG_USB_PHYINTERFACE
;
200 otg_RegVal
|= USB2OTG_USB_MODESELECT_UTMI
;
201 *((volatile unsigned int *)USB2OTG_USB
) = otg_RegVal
;
203 D(bug("[USB2OTG] %s: Reseting Controller ..\n", __PRETTY_FUNCTION__
));
204 *((volatile unsigned int *)USB2OTG_RESET
) = USB2OTG_RESET_CORESOFT
;
205 for (ns
= 0; ns
< 10000; ns
++) { asm volatile("mov r0, r0\n"); } // Wait 10ms
206 if ((*((volatile unsigned int *)USB2OTG_RESET
) & USB2OTG_RESET_CORESOFT
) != 0)
207 bug("[USB2OTG] %s: Reset Timed-Out!\n", __PRETTY_FUNCTION__
);
209 otg_RegVal
= *((volatile unsigned int *)USB2OTG_HARDWARE2
);
210 if (((otg_RegVal
& (3 << 6) >> 6) == 2) && ((otg_RegVal
& (3 << 8) >> 8) == 1))
212 D(bug("[USB2OTG] %s: ULPI FSLS configuration: enabled.\n", __PRETTY_FUNCTION__
));
213 otg_RegVal
= *((volatile unsigned int *)USB2OTG_USB
);
214 otg_RegVal
|= (USB2OTG_USB_ULPIFSLS
|USB2OTG_USB_ULPI_CLK_SUS_M
);
215 *((volatile unsigned int *)USB2OTG_USB
) = otg_RegVal
;
217 D(bug("[USB2OTG] %s: ULPI FSLS configuration: disabled.\n", __PRETTY_FUNCTION__
));
218 otg_RegVal
= *((volatile unsigned int *)USB2OTG_USB
);
219 otg_RegVal
&= ~(USB2OTG_USB_ULPIFSLS
|USB2OTG_USB_ULPI_CLK_SUS_M
);
220 *((volatile unsigned int *)USB2OTG_USB
) = otg_RegVal
;
223 D(bug("[USB2OTG] %s: Enabling DMA configuration..\n", __PRETTY_FUNCTION__
));
224 otg_RegVal
= *((volatile unsigned int *)USB2OTG_AHB
);
225 otg_RegVal
&= ~(1 << USB2OTG_AHB_DMAREMAINDERMODE
);
226 otg_RegVal
|= (USB2OTG_AHB_DMAENABLE
|USB2OTG_AHB_DMAREMAINDERMODE_INCR
);
227 *((volatile unsigned int *)USB2OTG_AHB
) = otg_RegVal
;
229 D(bug("[USB2OTG] %s: Operating Mode: ", __PRETTY_FUNCTION__
));
230 otg_RegVal
= *((volatile unsigned int *)USB2OTG_HARDWARE2
);
231 switch (otg_RegVal
& 7)
235 otg_RegVal
= *((volatile unsigned int *)USB2OTG_USB
);
236 otg_RegVal
|= (USB2OTG_USB_HNPCAPABLE
|USB2OTG_USB_SRPCAPABLE
);
237 *((volatile unsigned int *)USB2OTG_USB
) = otg_RegVal
;
243 otg_RegVal
= *((volatile unsigned int *)USB2OTG_USB
);
244 otg_RegVal
&= ~USB2OTG_USB_HNPCAPABLE
;
245 otg_RegVal
|= USB2OTG_USB_SRPCAPABLE
;
246 *((volatile unsigned int *)USB2OTG_USB
) = otg_RegVal
;
251 D(bug("No HNP or SRP\n"));
252 otg_RegVal
= *((volatile unsigned int *)USB2OTG_USB
);
253 otg_RegVal
&= ~(USB2OTG_USB_HNPCAPABLE
|USB2OTG_USB_SRPCAPABLE
);
254 *((volatile unsigned int *)USB2OTG_USB
) = otg_RegVal
;
258 bug("[USB2OTG] HS OTG USB Driver Initialised\n");
264 D(bug("[USB2OTG] %s: Failed to Create MemPool\n",
265 __PRETTY_FUNCTION__
));
267 CloseLibrary((struct Library
*) UtilityBase
);
273 D(bug("[USB2OTG] %s: OpenLibrary(\"utility.library\", 39) failed!\n",
274 __PRETTY_FUNCTION__
));
281 D(bug("[USB2OTG] %s: OpenDevice(\"timer.device\") failed!\n",
282 __PRETTY_FUNCTION__
));
289 D(bug("[USB2OTG] %s: Failed to allocate timer IORequest\n",
290 __PRETTY_FUNCTION__
));
297 D(bug("[USB2OTG] %s: Failed to create MsgPort\n",
298 __PRETTY_FUNCTION__
));
304 return USB2OTGBase
? TRUE
: FALSE
;
308 *===========================================================
309 * Open(ioreq, unit, flags, base)
310 *===========================================================
312 * This is the the DEV_OPEN function.
315 static int FNAME_DEV(Open
)(LIBBASETYPEPTR USB2OTGBase
, struct IOUsbHWReq
*ioreq
, ULONG otg_Unit
, ULONG flags
)
317 D(bug("[USB2OTG] %s: IOReq @ 0x%p, unit #%ld, flags = 0x%08lx, USB2OTGBase @ 0x%p\n",
318 __PRETTY_FUNCTION__
, ioreq
, otg_Unit
, flags
, USB2OTGBase
));
320 D(bug("[USB2OTG] %s: openCnt = %ld\n",
321 __PRETTY_FUNCTION__
, USB2OTGBase
->hd_Library
.lib_OpenCnt
));
323 if (ioreq
->iouh_Req
.io_Message
.mn_Length
< sizeof(struct IOUsbHWReq
))
325 D(bug("[USB2OTG] %s: invalid MN_LENGTH!\n",
326 __PRETTY_FUNCTION__
));
328 ioreq
->iouh_Req
.io_Error
= IOERR_BADLENGTH
;
332 ioreq
->iouh_Req
.io_Error
= IOERR_OPENFAIL
;
334 ioreq
->iouh_Req
.io_Unit
= FNAME_DEV(OpenUnit
)(ioreq
, otg_Unit
, USB2OTGBase
);
335 if (!(ioreq
->iouh_Req
.io_Unit
))
337 D(bug("[USB2OTG] %s: could not open unit!\n",
338 __PRETTY_FUNCTION__
));
343 ioreq
->iouh_Req
.io_Message
.mn_Node
.ln_Type
= NT_REPLYMSG
;
344 ioreq
->iouh_Req
.io_Error
= 0;
355 *===========================================================
357 *===========================================================
359 * This is the the DEV_EXPUNGE function.
362 static int FNAME_DEV(Close
)(LIBBASETYPEPTR USB2OTGBase
, struct IOUsbHWReq
*ioreq
)
364 D(bug("[USB2OTG] %s: IOReq @ 0x%p, USB2OTGBase @ 0x%p\n",
365 __PRETTY_FUNCTION__
, ioreq
, USB2OTGBase
));
367 FNAME_DEV(CloseUnit
)(ioreq
, (struct USB2OTGUnit
*) ioreq
->iouh_Req
.io_Unit
, USB2OTGBase
);
369 ioreq
->iouh_Req
.io_Unit
= (APTR
) -1;
370 ioreq
->iouh_Req
.io_Device
= (APTR
) -1;
374 static int FNAME_DEV(Expunge
)(LIBBASETYPEPTR USB2OTGBase
)
376 DeletePool(USB2OTGBase
->hd_MemPool
);
378 D(bug("[USB2OTG] %s: closing utility.library @ 0x%p\n",
379 __PRETTY_FUNCTION__
, UtilityBase
));
381 CloseLibrary((struct Library
*) UtilityBase
);
385 ADD2INITLIB(FNAME_DEV(Init
), 0)
386 ADD2OPENDEV(FNAME_DEV(Open
), 0)
387 ADD2CLOSEDEV(FNAME_DEV(Close
), 0)
388 ADD2EXPUNGELIB(FNAME_DEV(Expunge
), 0)
391 *===========================================================
392 * BeginIO(ioreq, base)
393 *===========================================================
395 * This is the DEV_BEGINIO vector of the device.
398 AROS_LH1(void, FNAME_DEV(BeginIO
),
399 AROS_LHA(struct IOUsbHWReq
*, ioreq
, A1
),
400 LIBBASETYPEPTR
, USB2OTGBase
, 5, usb2otg
)
404 struct USB2OTGUnit
*otg_Unit
= (struct USB2OTGUnit
*) ioreq
->iouh_Req
.io_Unit
;
407 D(bug("[USB2OTG] %s: IOReq @ 0x%08lx, USB2OTGBase @ 0x%08lx [cmd:%lu]\n",
408 __PRETTY_FUNCTION__
, ioreq
, USB2OTGBase
, ioreq
->iouh_Req
.io_Command
));
410 ioreq
->iouh_Req
.io_Message
.mn_Node
.ln_Type
= NT_MESSAGE
;
411 ioreq
->iouh_Req
.io_Error
= UHIOERR_NO_ERROR
;
413 if (ioreq
->iouh_Req
.io_Command
< NSCMD_DEVICEQUERY
)
415 switch (ioreq
->iouh_Req
.io_Command
)
418 ret
= FNAME_DEV(cmdReset
)(ioreq
, otg_Unit
, USB2OTGBase
);
422 ret
= FNAME_DEV(cmdFlush
)(ioreq
, otg_Unit
, USB2OTGBase
);
425 case UHCMD_QUERYDEVICE
:
426 ret
= FNAME_DEV(cmdQueryDevice
)(ioreq
, otg_Unit
, USB2OTGBase
);
430 ret
= FNAME_DEV(cmdUsbReset
)(ioreq
, otg_Unit
, USB2OTGBase
);
433 case UHCMD_USBRESUME
:
434 ret
= FNAME_DEV(cmdUsbResume
)(ioreq
, otg_Unit
, USB2OTGBase
);
437 case UHCMD_USBSUSPEND
:
438 ret
= FNAME_DEV(cmdUsbSuspend
)(ioreq
, otg_Unit
, USB2OTGBase
);
442 ret
= FNAME_DEV(cmdUsbOper
)(ioreq
, otg_Unit
, USB2OTGBase
);
445 case UHCMD_CONTROLXFER
:
446 ret
= FNAME_DEV(cmdControlXFer
)(ioreq
, otg_Unit
, USB2OTGBase
);
450 ret
= FNAME_DEV(cmdBulkXFer
)(ioreq
, otg_Unit
, USB2OTGBase
);
454 ret
= FNAME_DEV(cmdIntXFer
)(ioreq
, otg_Unit
, USB2OTGBase
);
458 ret
= FNAME_DEV(cmdIsoXFer
)(ioreq
, otg_Unit
, USB2OTGBase
);
468 switch(ioreq
->iouh_Req
.io_Command
)
470 case NSCMD_DEVICEQUERY
:
471 ret
= FNAME_DEV(cmdNSDeviceQuery
)((struct IOStdReq
*) ioreq
, otg_Unit
, USB2OTGBase
);
480 if (ret
!= RC_DONTREPLY
)
482 D(bug("[USB2OTG] %s: Terminating I/O..\n",
483 __PRETTY_FUNCTION__
));
487 ioreq
->iouh_Req
.io_Error
= ret
& 0xff;
489 FNAME_DEV(TermIO
)(ioreq
, USB2OTGBase
);
496 *===========================================================
497 * AbortIO(ioreq, base)
498 *===========================================================
500 * This is the DEV_ABORTIO vector of the device. It abort
501 * the given iorequest, and set
504 AROS_LH1(LONG
, FNAME_DEV(AbortIO
),
505 AROS_LHA(struct IOUsbHWReq
*, ioreq
, A1
),
506 LIBBASETYPEPTR
, USB2OTGBase
, 6, usb2otg
)
510 D(bug("[USB2OTG] %s: IOReq @ 0x%p, command %ld, status %ld\n",
511 __PRETTY_FUNCTION__
, ioreq
, ioreq
->iouh_Req
.io_Command
, ioreq
->iouh_Req
.io_Message
.mn_Node
.ln_Type
));
514 if (ioreq
->iouh_Req
.io_Message
.mn_Node
.ln_Type
== NT_MESSAGE
)
516 // if (FNAME_DEV(cmdAbortIO)(ioreq, USB2OTGBase))
526 void FNAME_DEV(Cause
)(LIBBASETYPEPTR USB2OTGBase
, struct Interrupt
*interrupt
)
528 /* this is a workaround for the original Cause() function missing tailed calls */
531 if((interrupt
->is_Node
.ln_Type
== NT_SOFTINT
) || (interrupt
->is_Node
.ln_Type
== NT_USER
))
533 // signal tailed call
534 interrupt
->is_Node
.ln_Type
= NT_USER
;
538 interrupt
->is_Node
.ln_Type
= NT_SOFTINT
;
539 Forbid(); // make sure code is not interrupted by other tasks
541 AROS_INTC1(interrupt
->is_Code
, interrupt
->is_Data
);
544 } while(interrupt
->is_Node
.ln_Type
!= NT_SOFTINT
);
545 interrupt
->is_Node
.ln_Type
= NT_INTERRUPT
;