2 Copyright © 2010-2011, The AROS Development Team. All rights reserved
6 #include <proto/exec.h>
10 #include <devices/usb_hub.h>
14 #ifdef AROS_USB30_CODE
16 #undef HiddPCIDeviceAttrBase
17 #define HiddPCIDeviceAttrBase (hd->hd_HiddPCIDeviceAB)
19 #define HiddAttrBase (hd->hd_HiddAB)
22 AROS_UFH3(void, xhciResetHandler
,
23 AROS_UFHA(struct PCIController
*, hc
, A1
),
24 AROS_UFHA(APTR
, unused
, A5
),
25 AROS_UFHA(struct ExecBase
*, SysBase
, A6
))
32 KPRINTF(1000, ("Halting HC failed, reset may result in undefined behavior!\n"));
37 /* Reset controller */
43 void xhciCompleteInt(struct PCIController
*hc
)
45 KPRINTF(1, ("CompleteInt!\n"));
47 KPRINTF(1, ("CompleteDone\n"));
50 void xhciIntCode(HIDDT_IRQ_Handler
*irq
, HIDDT_IRQ_HwInfo
*hw
)
52 struct PCIController
*hc
= (struct PCIController
*) irq
->h_Data
;
53 // struct PCIDevice *base = hc->hc_Device;
54 // struct PCIUnit *unit = hc->hc_Unit;
58 intr
= opreg_readl(XHCI_USBSTS
);
59 if(intr
& XHCF_STS_EINT
) {
60 /* Clear (RW1C) Event Interrupt (EINT) */
61 opreg_writel(XHCI_USBSTS
, XHCF_STS_EINT
);
63 if (hc
->hc_Flags
& HCF_ONLINE
)
65 if(intr
& XHCF_STS_HSE
) {
66 KPRINTF(1000, ("Host System Error (HSE)!\n"));
69 if(intr
& XHCF_STS_PCD
) {
70 /* There are seven status change bits in the PORTSC register,
71 Connect Status Change (CSC)
72 Port Enabled/Disabled Change (PEC)
73 Warm Port Reset Change (WRC)
74 Over-current Change (OCC)
75 Port Reset Change (PRC)
76 Port Link State Change (PLC)
77 Port Config Error Change (CEC)
79 for (portn
= 1; portn
<= hc
->xhc_NumPorts
; portn
++) {
80 if (opreg_readl(XHCI_PORTSC(portn
)) & (XHCF_PS_CSC
|XHCF_PS_PEC
|XHCF_PS_OCC
|XHCF_PS_WRC
|XHCF_PS_PRC
|XHCF_PS_PLC
|XHCF_PS_CEC
)) {
81 KPRINTF(1000,("port %d changed\n", portn
));
86 if(intr
& XHCF_STS_SRE
) {
87 KPRINTF(1000, ("Host Controller Error (HCE)!\n"));
94 IPTR
xhciSearchExtCap(struct PCIController
*hc
, ULONG id
, IPTR extcap
) {
96 IPTR extcapoff
= (IPTR
) 0;
97 ULONG cnt
= XHCI_EXT_CAPS_MAX
;
99 KPRINTF(100,("search for ext cap with id(%ld)\n", id
));
102 KPRINTF(100, ("continue search from %p\n", extcap
));
103 extcap
= (IPTR
) XHCV_EXT_CAPS_NEXT(READMEM32_LE(extcap
));
105 extcap
= (IPTR
) hc
->xhc_capregbase
+ XHCV_xECP(capreg_readl(XHCI_HCCPARAMS
));
106 KPRINTF(100, ("search from the beginning %p\n", extcap
));
111 if((XHCV_EXT_CAPS_ID(READMEM32_LE(extcap
)) == id
)) {
112 KPRINTF(100, ("found matching ext cap %lx\n", extcap
));
113 return (IPTR
) extcap
;
117 KPRINTF(100, ("skipping ext cap with id(%ld)\n", XHCV_EXT_CAPS_ID(READMEM32_LE(extcap
))));
119 extcapoff
= (IPTR
) XHCV_EXT_CAPS_NEXT(READMEM32_LE(extcap
));
121 } while(cnt
& extcapoff
);
123 KPRINTF(100, ("not found!\n"));
127 BOOL
xhciHaltHC(struct PCIController
*hc
) {
129 struct PCIUnit
*hu
= hc
->hc_Unit
;
133 /* Halt the controller by clearing Run/Stop bit */
134 temp
= opreg_readl(XHCI_USBCMD
);
135 opreg_writel(XHCI_USBCMD
, (temp
& ~XHCF_CMD_RS
));
138 The xHC shall halt within 16 ms. after software clears the Run/Stop bit if certain conditions have been met.
139 The HCHalted (HCH) bit in the USBSTS register indicates when the xHC has finished its
140 pending pipelined transactions and has entered the stopped state.
142 timeout
= 250; //FIXME: arbitrary value of 2500ms
144 temp
= opreg_readl(XHCI_USBSTS
);
145 if( (temp
& XHCF_STS_HCH
) ) {
146 KPRINTF(1000, ("controller halted!\n"));
152 KPRINTF(1000, ("halt failed!\n"));
156 BOOL
xhciResetHC(struct PCIController
*hc
) {
158 struct PCIUnit
*hu
= hc
->hc_Unit
;
162 /* Reset controller by setting HCRST-bit */
163 temp
= opreg_readl(XHCI_USBCMD
);
164 opreg_writel(XHCI_USBCMD
, (temp
| XHCF_CMD_HCRST
));
167 Controller clears HCRST bit when reset is done, wait for it and the CNR-bit to be cleared
169 timeout
= 250; //FIXME: arbitrary value of 2500ms
171 temp
= opreg_readl(XHCI_USBCMD
);
172 if( !(temp
& XHCF_CMD_HCRST
) ) {
173 /* Wait for CNR-bit to clear */
174 timeout
= 250; //FIXME: arbitrary value of 2500ms
176 temp
= opreg_readl(XHCI_USBSTS
);
177 if( !(temp
& XHCF_STS_CNR
) ) {
178 KPRINTF(1000, ("reset succeeded!\n"));
188 KPRINTF(1000, ("reset failed!\n"));
192 BOOL
xhciInit(struct PCIController
*hc
, struct PCIUnit
*hu
) {
194 struct PCIDevice
*hd
= hu
->hu_Device
;
196 ULONG cnt
, timeout
, temp
;
200 volatile APTR pciregbase
;
202 struct TagItem pciActivateMemAndBusmaster
[] =
204 { aHidd_PCIDevice_isIO
, FALSE
},
205 { aHidd_PCIDevice_isMEM
, TRUE
},
206 { aHidd_PCIDevice_isMaster
, TRUE
},
210 memptr
= AllocVecAligned(2000, 0x100);
211 KPRINTF(1000,("AllocVedAligned %p\n", memptr
));
212 FreeVecAligned(memptr
);
214 /* Activate Mem and Busmaster as pciFreeUnit will disable them! (along with IO, but we don't have that...) */
215 OOP_SetAttrs(hc
->hc_PCIDeviceObject
, (struct TagItem
*) pciActivateMemAndBusmaster
);
217 OOP_GetAttr(hc
->hc_PCIDeviceObject
, aHidd_PCIDevice_Base0
, (APTR
) &pciregbase
);
218 // KPRINTF(1000, ("XHCI MMIO address space (%p)\n",pciregbase));
220 // Store capregbase in xhc_capregbase
221 hc
->xhc_capregbase
= (APTR
) pciregbase
;
222 KPRINTF(1000, ("xhc_capregbase (%p)\n",hc
->xhc_capregbase
));
224 // Store opregbase in xhc_opregbase
225 hc
->xhc_opregbase
= (APTR
) ((ULONG
) pciregbase
+ capreg_readb(XHCI_CAPLENGTH
));
226 KPRINTF(1000, ("xhc_opregbase (%p)\n",hc
->xhc_opregbase
));
228 // KPRINTF(1000, ("XHCI CAPLENGTH (%02x)\n", capreg_readb(XHCI_CAPLENGTH)));
229 // KPRINTF(1000, ("XHCI Version (%04x)\n", capreg_readw(XHCI_HCIVERSION)));
230 // KPRINTF(1000, ("XHCI HCSPARAMS1 (%08x)\n", capreg_readl(XHCI_HCSPARAMS1)));
231 // KPRINTF(1000, ("XHCI HCSPARAMS2 (%08x)\n", capreg_readl(XHCI_HCSPARAMS2)));
232 // KPRINTF(1000, ("XHCI HCSPARAMS3 (%08x)\n", capreg_readl(XHCI_HCSPARAMS3)));
233 // KPRINTF(1000, ("XHCI HCCPARAMS (%08x)\n", capreg_readl(XHCI_HCCPARAMS)));
236 This field defines the page size supported by the xHC implementation.
237 This xHC supports a page size of 2^(n+12) if bit n is Set. For example,
238 if bit 0 is set, the xHC supports 4k byte page sizes.
241 temp
= opreg_readl(XHCI_PAGESIZE
)&0xffff;
242 while((~temp
&1) & temp
){
246 hc
->xhc_pagesize
= 1<<(cnt
);
247 KPRINTF(1000, ("Pagesize 2^(n+12) = 0x%lx\n", hc
->xhc_pagesize
));
249 /* Testing scratchpad allocations */
250 hc
->xhc_scratchpads
= 4;
251 // hc->xhc_scratchpads = XHCV_SPB_Max(capreg_readl(XHCI_HCSPARAMS2));
252 KPRINTF(1000, ("Max Scratchpad Buffers %lx\n",hc
->xhc_scratchpads
));
254 hc
->xhc_NumPorts
= XHCV_MaxPorts(capreg_readl(XHCI_HCSPARAMS1
));
255 KPRINTF(1000, ("MaxPorts %lx\n",hc
->xhc_NumPorts
));
258 We don't yeat know how many we have each of them, xhciParseSupProtocol takes care of that
260 hc
->xhc_NumPorts20
= 0;
261 hc
->xhc_NumPorts30
= 0;
264 Number of Device Slots (MaxSlots). This field specifies the maximum number of Device
265 Context Structures and Doorbell Array entries this host controller can support. Valid values are
266 in the range of 1 to 255. The value of ‘0’ is reserved, fail gracefully on it
268 hc
->xhc_maxslots
= (XHCV_MaxSlots(capreg_readl(XHCI_HCSPARAMS1
)) & XHCM_CONFIG_MaxSlotsEn
);
269 if(hc
->xhc_maxslots
== 0){
270 KPRINTF(1000, ("MaxSlots count is 0, failing!\n"));
274 KPRINTF(1000, ("MaxSlots %lx\n",hc
->xhc_maxslots
));
276 KPRINTF(1000, ("MaxIntrs %lx\n",XHCV_MaxIntrs(capreg_readl(XHCI_HCSPARAMS1
))));
278 /* 64 byte or 32 byte context data structures? */
279 if(capreg_readl(XHCI_HCCPARAMS
) & XHCF_CSZ
) {
280 hc
->xhc_contextsize64
=TRUE
;
283 /* xHCI Extended Capabilities, search for USB Legacy Support */
284 extcap
= xhciSearchExtCap(hc
, XHCI_EXT_CAPS_LEGACY
, 0);
287 temp
= READMEM32_LE(extcap
);
288 if( (temp
& XHCF_BIOSOWNED
) ){
289 KPRINTF(1000, ("controller owned by BIOS\n"));
291 /* Spec says "no more than a second", we give it a little more */
294 WRITEMEM32_LE(extcap
, (temp
| XHCF_OSOWNED
) );
296 temp
= READMEM32_LE(extcap
);
297 if( !(temp
& XHCF_BIOSOWNED
) ) {
298 KPRINTF(1000, ("BIOS gave up on XHCI. Pwned!\n"));
305 KPRINTF(1000, ("BIOS didn't release XHCI. Forcing and praying...\n"));
306 WRITEMEM32_LE(extcap
, (temp
& ~XHCF_BIOSOWNED
) );
311 /* XHCI spec says that there is at least one "Supported Protocol" capability, fail if none is found as this is used for port logic */
312 extcap
= xhciSearchExtCap(hc
, XHCI_EXT_CAPS_PROTOCOL
, 0);
314 KPRINTF(1000, ("Supported Protocol found!\n"));
315 xhciParseSupProtocol(hc
, extcap
);
317 /* Parse rest, if any...*/
319 extcap
= xhciSearchExtCap(hc
, XHCI_EXT_CAPS_PROTOCOL
, extcap
);
321 KPRINTF(1000, ("More Supported Protocols found!\n"));
322 xhciParseSupProtocol(hc
, extcap
);
326 KPRINTF(1000, ("No Supported Protocol found, failing!\n"));
331 If no USB2.0 ports were found but max port count is greater than USB3.0 count assume the overhead to be USB2.0
333 if( (hc
->xhc_NumPorts
< (hc
->xhc_NumPorts20
+ hc
->xhc_NumPorts30
)) ) {
334 KPRINTF(1000, ("Too many ports in Supported Protocol!\n"));
336 }else if ( (hc
->xhc_NumPorts
> (hc
->xhc_NumPorts20
+ hc
->xhc_NumPorts30
)) ) {
337 hc
->xhc_NumPorts20
= (hc
->xhc_NumPorts
- hc
->xhc_NumPorts30
);
340 KPRINTF(1000, ("Number of USB2.0 ports %ld\n", hc
->xhc_NumPorts20
));
341 KPRINTF(1000, ("Number of USB3.0 ports %ld\n", hc
->xhc_NumPorts30
));
344 if(xhciResetHC(hc
)) {
346 // for(cnt = 1; cnt <=hc->xhc_NumPorts; cnt++) {
347 // temp = opreg_readl(XHCI_PORTSC(cnt));
348 // KPRINTF(1000, ("Attached device's speed on port #%d is %d (PORTSC %lx)\n",cnt, XHCV_PS_SPEED(temp), temp ));
351 hc
->hc_PCIMemSize
= 1024; //Arbitrary number
353 /* CHECKME: Removed this memory allocation as it was not used in any way (at least for now) */
354 // memptr = HIDD_PCIDriver_AllocPCIMem(hc->hc_PCIDriverObject, hc->hc_PCIMemSize);
355 // hc->hc_PCIMem = (APTR) memptr;
356 hc
->hc_PCIMem
= NULL
;
360 // PhysicalAddress - VirtualAdjust = VirtualAddress
361 // VirtualAddress + VirtualAdjust = PhysicalAddress
362 // hc->hc_PCIVirtualAdjust = pciGetPhysical(hc, memptr) - (APTR)memptr;
363 // KPRINTF(10, ("VirtualAdjust 0x%08lx\n", hc->hc_PCIVirtualAdjust));
365 hc
->hc_CompleteInt
.is_Node
.ln_Type
= NT_INTERRUPT
;
366 hc
->hc_CompleteInt
.is_Node
.ln_Name
= "XHCI CompleteInt";
367 hc
->hc_CompleteInt
.is_Node
.ln_Pri
= 0;
368 hc
->hc_CompleteInt
.is_Data
= hc
;
369 hc
->hc_CompleteInt
.is_Code
= (void (*)(void)) &xhciCompleteInt
;
372 hc
->hc_ResetInt
.is_Code
= xhciResetHandler
;
373 hc
->hc_ResetInt
.is_Data
= hc
;
374 AddResetCallback(&hc
->hc_ResetInt
);
376 // add interrupt handler
377 hc
->hc_PCIIntHandler
.h_Node
.ln_Name
= "XHCI PCI (pciusb.device)";
378 hc
->hc_PCIIntHandler
.h_Node
.ln_Pri
= 5;
379 hc
->hc_PCIIntHandler
.h_Code
= xhciIntCode
;
380 hc
->hc_PCIIntHandler
.h_Data
= hc
;
381 HIDD_IRQ_AddHandler(hd
->hd_IRQHidd
, &hc
->hc_PCIIntHandler
, hc
->hc_PCIIntLine
);
383 /* Clears (RW1C) Host System Error(HSE), Event Interrupt(EINT), Port Change Detect(PCD) and Save/Restore Error(SRE) */
384 temp
= opreg_readl(XHCI_USBSTS
);
385 opreg_writel(XHCI_USBSTS
, temp
);
387 /* After reset all notifications should be automatically disabled but ensure anyway */
388 opreg_writel(XHCI_DNCTRL
, 0);
390 /* Program the Max Device Slots Enabled (MaxSlotsEn) field */
392 Max Device Slots Enabled (MaxSlotsEn) – RW. Default = ‘0’. This field specifies the maximum
393 number of enabled Device Slots. Valid values are in the range of 0 to MaxSlots. Enabled Devices
394 Slots are allocated contiguously. e.g. A value of 16 specifies that Device Slots 1 to 16 are active.
395 A value of ‘0’ disables all Device Slots. A disabled Device Slot shall not respond to Doorbell
397 This field shall not be modified by software if the xHC is running (Run/Stop (R/S) = ‘1’).
399 opreg_writel(XHCI_CONFIG
, ((opreg_readl(XHCI_CONFIG
) & ~XHCM_CONFIG_MaxSlotsEn
) | hc
->xhc_maxslots
));
401 if(hc
->xhc_scratchpads
) {
404 Scratchpad array is 64 byte aligned as is Device Context Base array, neither can cross page boundary
406 hc
->xhc_scratchpadarray
= AllocVecAligned( (hc
->xhc_scratchpads
*sizeof(UQUAD
) ), hc
->xhc_pagesize
);
407 if( !(hc
->xhc_scratchpadarray
) ){
408 KPRINTF(1000, ("Unable to allocate scratchpad array, failing!\n"));
412 hc
->xhc_dcbaa
= AllocVecAligned( ((hc
->xhc_maxslots
+ 1)*sizeof(UQUAD
)) , hc
->xhc_pagesize
);
413 if( !(hc
->xhc_scratchpadarray
) ){
414 FreeVecAligned(hc
->xhc_scratchpadarray
);
415 KPRINTF(1000, ("Unable to allocate device context base array, failing!\n"));
419 hc
->xhc_dcbaa
[0] = (UQUAD
) hc
->xhc_scratchpadarray
;
421 KPRINTF(1000, ("Allocated scratchpad buffer array at %p\n", hc
->xhc_scratchpadarray
));
423 for(temp
= 0; temp
<hc
->xhc_scratchpads
; temp
++){
426 We are making a bold assumption that pagesize returned by host controller is the same as system pagesize...
428 memptr
= AllocVecAligned(hc
->xhc_pagesize
, hc
->xhc_pagesize
);
430 hc
->xhc_scratchpadarray
[temp
] = (UQUAD
) (0xDEADBEEF00000000 | (UQUAD
) memptr
);
431 /* CHECKME: Not really sure if the 32(or 64) bit address is stored correctly in the QUAD pointer list */
432 KPRINTF(1000, ("hc->xhc_scratchpadarray[%d] = %0lx:%0lx\n", temp
, (IPTR
) ((UQUAD
)(hc
->xhc_scratchpadarray
[temp
])>>32), (IPTR
) hc
->xhc_scratchpadarray
[temp
]));
434 for(temp
= 0; temp
<hc
->xhc_scratchpads
; temp
++){
435 if(hc
->xhc_scratchpadarray
[temp
]){
436 FreeVecAligned( (APTR
) hc
->xhc_scratchpadarray
[temp
] );
445 Host controller does not use scratchpads (This is the case OnMyHW™)
447 hc
->xhc_scratchpadarray
= NULL
;
450 DCBAA can't cross page boundary, make sure it doesn't. This all adds memory usage.
452 hc
->xhc_dcbaa
= AllocVecAligned( ((hc
->xhc_maxslots
+ 1)*sizeof(UQUAD
)), hc
->xhc_pagesize
);
453 if( !(hc
->xhc_dcbaa
) ){
454 KPRINTF(1000, ("Unable to allocate device context base array, failing!\n"));
459 KPRINTF(1000, ("Device context base array at %p\n", hc
->xhc_dcbaa
));
461 opreg_writeq(XHCI_DCBAAP
, (IPTR
)hc
->xhc_dcbaa
);
463 /* FIXME: Allocate device context data structures and fill rest of the DCBAA array*/
464 /* Define the Command Ring Dequeue Pointer by programming the Command Ring Control Register */
466 /* Set Run/Stop(R/S), Interrupter Enable(INTE) and Host System Error Enable(HSEE) */
467 opreg_writel(XHCI_USBCMD
, (XHCF_CMD_RS
| XHCF_CMD_INTE
| XHCF_CMD_HSEE
) );
469 KPRINTF(1000, ("xhciInit returns TRUE...\n"));
475 KPRINTF(1000, ("xhciInit returns FALSE...\n"));
479 void xhciFree(struct PCIController
*hc
, struct PCIUnit
*hu
) {
481 hc
= (struct PCIController
*) hu
->hu_Controllers
.lh_Head
;
482 while(hc
->hc_Node
.ln_Succ
)
484 switch(hc
->hc_HCIType
)
488 KPRINTF(1000, ("Shutting down XHCI %08lx\n", hc
));
492 KPRINTF(1000, ("Shutting down XHCI done.\n"));
497 hc
= (struct PCIController
*) hc
->hc_Node
.ln_Succ
;
501 void xhciParseSupProtocol(struct PCIController
*hc
, IPTR extcap
) {
505 temp1
= READMEM32_LE(extcap
);
506 KPRINTF(1000, ("Version %l.%l\n", XHCV_SPFD_RMAJOR(temp1
), XHCV_SPFD_RMINOR(temp1
) ));
508 temp2
= READMEM32_LE(extcap
+ XHCI_SPPORT
);
509 // KPRINTF(1000, ("CPO %ld\n", XHCV_SPPORT_CPO(temp2) ));
510 // KPRINTF(1000, ("CPCNT %ld\n", XHCV_SPPORT_CPCNT(temp2) ));
511 // KPRINTF(1000, ("PD %ld\n", XHCV_SPPORT_PD(temp2) ));
512 // KPRINTF(1000, ("PSIC %ld\n", XHCV_SPPORT_PSIC(temp2) ));
516 -We might not get at all "USB2 Supported Protocol", in that case make a wild assumption on # USB2.0 ports
517 -Check if the name string is "USB " (=0x20425355)
518 -Map USB specifications to their respective ports (USB2.0/USB3.0)
521 if(XHCV_SPFD_RMAJOR(temp1
) == 2) {
522 hc
->xhc_NumPorts20
= ((XHCV_SPPORT_CPCNT(temp2
) - XHCV_SPPORT_CPO(temp2
) + 1));
524 if(XHCV_SPFD_RMAJOR(temp1
) == 3) {
525 hc
->xhc_NumPorts30
= ((XHCV_SPPORT_CPCNT(temp2
) - XHCV_SPPORT_CPO(temp2
) + 1));
530 Allocate aligned memory (call with ALIGNMENT = PAGESIZE for onpage memory, will result in PAGESIZE overhead memory usage)
532 APTR
AllocVecAligned(ULONG bytesize
, ULONG alignment
) {
533 // KPRINTF(1000, ("AllocVecAligned %ld, %ld\n", bytesize, alignment ));
538 Allocate aligned memory by ourself as OS doesn't seem to give us any support for aligned allocations (ONPAGE,ALIGNMENT)
539 -We only support alignment of sizeof(IPTR) and up since we store the original ptr, sizeof(IPTR) is platform dependant
541 if(alignment
<sizeof(IPTR
)) {
542 alignment
= sizeof(IPTR
);
545 temp
= (IPTR
)AllocVec( bytesize
+alignment
, (MEMF_PUBLIC
| MEMF_CLEAR
) );
547 // KPRINTF(1000, ("got memory @ %p with alignment %ld\n", temp, alignment ));
550 If by coincidence we get aligned memory, we still add the alignment size to the pointer and align it to the next possible aligned address
551 as we need memory below our allocation.
553 ret
= (APTR
)((IPTR
)(temp
+alignment
) & ~(alignment
-1));
554 // KPRINTF(1000, ("final memory @ %p\n", ret ));
557 Store our original memory pointer below our aligned memory (we have allocated memory there)
565 void FreeVecAligned(APTR memory
) {
567 // KPRINTF(1000, ("FreeVecAligned @ %p\n", ptr[-1] ));
568 FreeVec((APTR
)ptr
[-1]);