Typo fix
[AROS.git] / rom / usb / pciusb / xhcichip.c
blob011d0854f527d1a265e31183a285f43e9c64e4f7
1 /*
2 Copyright © 2010-2013, The AROS Development Team. All rights reserved
3 $Id$
4 */
6 #include <proto/exec.h>
7 #include <proto/oop.h>
8 #include <hidd/pci.h>
10 #include <devices/usb_hub.h>
12 #include "uhwcmd.h"
14 #ifdef AROS_USB30_CODE
16 #undef HiddPCIDeviceAttrBase
17 #define HiddPCIDeviceAttrBase (hd->hd_HiddPCIDeviceAB)
18 #undef HiddAttrBase
19 #define HiddAttrBase (hd->hd_HiddAB)
21 static AROS_INTH1(xhciResetHandler, struct PCIController *, hc)
23 AROS_INTFUNC_INIT
25 /* Halt controller */
26 #ifdef DEBUG
27 if(!xhciHaltHC(hc))
28 KPRINTF(1000, ("Halting HC failed, reset may result in undefined behavior!\n"));
29 #else
30 xhciHaltHC(hc);
31 #endif
33 /* Reset controller */
34 xhciResetHC(hc);
36 return 0;
38 AROS_INTFUNC_EXIT
41 static AROS_INTH1(xhciCompleteInt, struct PCIController *, hc)
43 AROS_INTFUNC_INIT
45 KPRINTF(1, ("CompleteInt!\n"));
47 KPRINTF(1, ("CompleteDone\n"));
49 return 0;
51 AROS_INTFUNC_EXIT
54 static AROS_INTH1(xhciIntCode, struct PCIController *, hc)
56 AROS_INTFUNC_INIT
58 // struct PCIDevice *base = hc->hc_Device;
59 // struct PCIUnit *unit = hc->hc_Unit;
61 ULONG intr, portn;
63 intr = opreg_readl(XHCI_USBSTS);
64 if(intr & XHCF_STS_EINT) {
65 /* Clear (RW1C) Event Interrupt (EINT) */
66 opreg_writel(XHCI_USBSTS, XHCF_STS_EINT);
68 if (hc->hc_Flags & HCF_ONLINE)
70 if(intr & XHCF_STS_HSE) {
71 KPRINTF(1000, ("Host System Error (HSE)!\n"));
74 if(intr & XHCF_STS_PCD) {
75 /* There are seven status change bits in the PORTSC register,
76 Connect Status Change (CSC)
77 Port Enabled/Disabled Change (PEC)
78 Warm Port Reset Change (WRC)
79 Over-current Change (OCC)
80 Port Reset Change (PRC)
81 Port Link State Change (PLC)
82 Port Config Error Change (CEC)
84 for (portn = 1; portn <= hc->xhc_NumPorts; portn++) {
85 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)) {
86 KPRINTF(1000,("port %d changed\n", portn));
91 if(intr & XHCF_STS_SRE) {
92 KPRINTF(1000, ("Host Controller Error (HCE)!\n"));
95 } // not online
98 return FALSE;
100 AROS_INTFUNC_EXIT
103 IPTR xhciSearchExtCap(struct PCIController *hc, ULONG id, IPTR extcap) {
105 IPTR extcapoff = (IPTR) 0;
106 ULONG cnt = XHCI_EXT_CAPS_MAX;
108 KPRINTF(100,("search for ext cap with id(%ld)\n", id));
110 if(extcap) {
111 KPRINTF(100, ("continue search from %p\n", extcap));
112 extcap = (IPTR) XHCV_EXT_CAPS_NEXT(READMEM32_LE(extcap));
113 } else {
114 extcap = (IPTR) hc->xhc_capregbase + XHCV_xECP(capreg_readl(XHCI_HCCPARAMS));
115 KPRINTF(100, ("search from the beginning %p\n", extcap));
118 do {
119 extcap += extcapoff;
120 if((XHCV_EXT_CAPS_ID(READMEM32_LE(extcap)) == id)) {
121 KPRINTF(100, ("found matching ext cap %lx\n", extcap));
122 return (IPTR) extcap;
124 #if DEBUG
125 if(extcap)
126 KPRINTF(100, ("skipping ext cap with id(%ld)\n", XHCV_EXT_CAPS_ID(READMEM32_LE(extcap))));
127 #endif
128 extcapoff = (IPTR) XHCV_EXT_CAPS_NEXT(READMEM32_LE(extcap));
129 cnt--;
130 } while(cnt & extcapoff);
132 KPRINTF(100, ("not found!\n"));
133 return (IPTR) 0;
136 BOOL xhciHaltHC(struct PCIController *hc) {
138 struct PCIUnit *hu = hc->hc_Unit;
140 ULONG timeout, temp;
142 /* Halt the controller by clearing Run/Stop bit */
143 temp = opreg_readl(XHCI_USBCMD);
144 opreg_writel(XHCI_USBCMD, (temp & ~XHCF_CMD_RS));
147 The xHC shall halt within 16 ms. after software clears the Run/Stop bit if certain conditions have been met.
148 The HCHalted (HCH) bit in the USBSTS register indicates when the xHC has finished its
149 pending pipelined transactions and has entered the stopped state.
151 timeout = 250; //FIXME: arbitrary value of 2500ms
152 do {
153 temp = opreg_readl(XHCI_USBSTS);
154 if( (temp & XHCF_STS_HCH) ) {
155 KPRINTF(1000, ("controller halted!\n"));
156 return TRUE;
158 uhwDelayMS(10, hu);
159 } while(--timeout);
161 KPRINTF(1000, ("halt failed!\n"));
162 return FALSE;
165 BOOL xhciResetHC(struct PCIController *hc) {
167 struct PCIUnit *hu = hc->hc_Unit;
169 ULONG timeout, temp;
171 /* Reset controller by setting HCRST-bit */
172 temp = opreg_readl(XHCI_USBCMD);
173 opreg_writel(XHCI_USBCMD, (temp | XHCF_CMD_HCRST));
176 Controller clears HCRST bit when reset is done, wait for it and the CNR-bit to be cleared
178 timeout = 250; //FIXME: arbitrary value of 2500ms
179 do {
180 temp = opreg_readl(XHCI_USBCMD);
181 if( !(temp & XHCF_CMD_HCRST) ) {
182 /* Wait for CNR-bit to clear */
183 timeout = 250; //FIXME: arbitrary value of 2500ms
184 do {
185 temp = opreg_readl(XHCI_USBSTS);
186 if( !(temp & XHCF_STS_CNR) ) {
187 KPRINTF(1000, ("reset succeeded!\n"));
188 return TRUE;
190 uhwDelayMS(10, hu);
191 } while(--timeout);
192 return FALSE;
194 uhwDelayMS(10, hu);
195 } while(--timeout);
197 KPRINTF(1000, ("reset failed!\n"));
198 return FALSE;
201 BOOL xhciInit(struct PCIController *hc, struct PCIUnit *hu) {
203 struct PCIDevice *hd = hu->hu_Device;
205 ULONG timeout, temp;
206 IPTR extcap;
207 APTR memptr = NULL;
209 volatile APTR pciregbase;
211 struct TagItem pciActivateMemAndBusmaster[] =
213 { aHidd_PCIDevice_isIO, FALSE },
214 { aHidd_PCIDevice_isMEM, TRUE },
215 { aHidd_PCIDevice_isMaster, TRUE },
216 { TAG_DONE, 0UL },
219 APTR T0 = AllocVecAligned(100,128,0);
220 FreeVecAligned(T0);
221 //while(1);
223 /* Activate Mem and Busmaster as pciFreeUnit will disable them! (along with IO, but we don't have that...) */
224 OOP_SetAttrs(hc->hc_PCIDeviceObject, (struct TagItem *) pciActivateMemAndBusmaster);
226 OOP_GetAttr(hc->hc_PCIDeviceObject, aHidd_PCIDevice_Base0, (APTR) &pciregbase);
227 // KPRINTF(1000, ("XHCI MMIO address space (%p)\n",pciregbase));
229 // Store capregbase in xhc_capregbase
230 hc->xhc_capregbase = (APTR) pciregbase;
231 KPRINTF(1000, ("xhc_capregbase (%p)\n",hc->xhc_capregbase));
233 // Store opregbase in xhc_opregbase
234 hc->xhc_opregbase = (APTR) ((ULONG) pciregbase + capreg_readb(XHCI_CAPLENGTH));
235 KPRINTF(1000, ("xhc_opregbase (%p)\n",hc->xhc_opregbase));
237 // KPRINTF(1000, ("XHCI CAPLENGTH (%02x)\n", capreg_readb(XHCI_CAPLENGTH)));
238 // KPRINTF(1000, ("XHCI Version (%04x)\n", capreg_readw(XHCI_HCIVERSION)));
239 // KPRINTF(1000, ("XHCI HCSPARAMS1 (%08x)\n", capreg_readl(XHCI_HCSPARAMS1)));
240 // KPRINTF(1000, ("XHCI HCSPARAMS2 (%08x)\n", capreg_readl(XHCI_HCSPARAMS2)));
241 // KPRINTF(1000, ("XHCI HCSPARAMS3 (%08x)\n", capreg_readl(XHCI_HCSPARAMS3)));
242 // KPRINTF(1000, ("XHCI HCCPARAMS (%08x)\n", capreg_readl(XHCI_HCCPARAMS)));
245 This field defines the page size supported by the xHC implementation.
246 This xHC supports a page size of 2^(n+12) if bit n is Set. For example,
247 if bit 0 is set, the xHC supports 4k byte page sizes.
249 hc->xhc_pagesize = 1<<(AROS_LEAST_BIT_POS(opreg_readl(XHCI_PAGESIZE)&0xffff)+12);
250 KPRINTF(1000, ("Pagesize = 0x%lx\n", hc->xhc_pagesize));
252 /* Testing scratchpad allocations */
253 //hc->xhc_scratchpads = 4;
254 hc->xhc_scratchpads = XHCV_SPB_Max(capreg_readl(XHCI_HCSPARAMS2));
255 KPRINTF(1000, ("Max Scratchpad Buffers %lx\n",hc->xhc_scratchpads));
257 hc->xhc_NumPorts = XHCV_MaxPorts(capreg_readl(XHCI_HCSPARAMS1));
258 KPRINTF(1000, ("MaxPorts %lx\n",hc->xhc_NumPorts));
261 We don't yeat know how many we have each of them, xhciParseSupProtocol takes care of that
263 hc->xhc_NumPorts20 = 0;
264 hc->xhc_NumPorts30 = 0;
267 Number of Device Slots (MaxSlots). This field specifies the maximum number of Device
268 Context Structures and Doorbell Array entries this host controller can support. Valid values are
269 in the range of 1 to 255. The value of ‘0’ is reserved, fail gracefully on it
271 hc->xhc_maxslots = (XHCV_MaxSlots(capreg_readl(XHCI_HCSPARAMS1)) & XHCM_CONFIG_MaxSlotsEn);
272 if(hc->xhc_maxslots == 0){
273 KPRINTF(1000, ("MaxSlots count is 0, failing!\n"));
274 return FALSE;
277 KPRINTF(1000, ("MaxSlots %lx\n",hc->xhc_maxslots));
279 KPRINTF(1000, ("MaxIntrs %lx\n",XHCV_MaxIntrs(capreg_readl(XHCI_HCSPARAMS1))));
281 /* 64 byte or 32 byte context data structures? */
282 if(capreg_readl(XHCI_HCCPARAMS) & XHCF_CSZ) {
283 hc->xhc_contextsize64=TRUE;
286 /* xHCI Extended Capabilities, search for USB Legacy Support */
287 extcap = xhciSearchExtCap(hc, XHCI_EXT_CAPS_LEGACY, 0);
288 if(extcap) {
290 temp = READMEM32_LE(extcap);
291 if( (temp & XHCF_BIOSOWNED) ){
292 KPRINTF(1000, ("controller owned by BIOS\n"));
294 /* Spec says "no more than a second", we give it a little more */
295 timeout = 250;
297 WRITEMEM32_LE(extcap, (temp | XHCF_OSOWNED) );
298 do {
299 temp = READMEM32_LE(extcap);
300 if( !(temp & XHCF_BIOSOWNED) ) {
301 KPRINTF(1000, ("BIOS gave up on XHCI. Pwned!\n"));
302 break;
304 uhwDelayMS(10, hu);
305 } while(--timeout);
307 if(!timeout) {
308 KPRINTF(1000, ("BIOS didn't release XHCI. Forcing and praying...\n"));
309 WRITEMEM32_LE(extcap, (temp & ~XHCF_BIOSOWNED) );
314 /* XHCI spec says that there is at least one "Supported Protocol" capability, fail if none is found as this is used for port logic */
315 extcap = xhciSearchExtCap(hc, XHCI_EXT_CAPS_PROTOCOL, 0);
316 if(extcap) {
317 KPRINTF(1000, ("Supported Protocol found!\n"));
318 xhciParseSupProtocol(hc, extcap);
320 /* Parse rest, if any...*/
321 do {
322 extcap = xhciSearchExtCap(hc, XHCI_EXT_CAPS_PROTOCOL, extcap);
323 if(extcap) {
324 KPRINTF(1000, ("More Supported Protocols found!\n"));
325 xhciParseSupProtocol(hc, extcap);
327 }while(extcap);
328 }else{
329 KPRINTF(1000, ("No Supported Protocol found, failing!\n"));
330 return FALSE;
334 If no USB2.0 ports were found but max port count is greater than USB3.0 count assume the overhead to be USB2.0
336 if( (hc->xhc_NumPorts < (hc->xhc_NumPorts20 + hc->xhc_NumPorts30)) ) {
337 KPRINTF(1000, ("Too many ports in Supported Protocol!\n"));
338 return FALSE;
339 }else if ( (hc->xhc_NumPorts > (hc->xhc_NumPorts20 + hc->xhc_NumPorts30)) ) {
340 hc->xhc_NumPorts20 = (hc->xhc_NumPorts - hc->xhc_NumPorts30);
343 KPRINTF(1000, ("Number of USB2.0 ports %ld\n", hc->xhc_NumPorts20 ));
344 KPRINTF(1000, ("Number of USB3.0 ports %ld\n", hc->xhc_NumPorts30 ));
346 if(xhciHaltHC(hc)) {
347 if(xhciResetHC(hc)) {
349 // for(cnt = 1; cnt <=hc->xhc_NumPorts; cnt++) {
350 // temp = opreg_readl(XHCI_PORTSC(cnt));
351 // KPRINTF(1000, ("Attached device's speed on port #%d is %d (PORTSC %lx)\n",cnt, XHCV_PS_SPEED(temp), temp ));
352 // }
354 hc->hc_PCIMemSize = 1024; //Arbitrary number
356 /* CHECKME: Removed this memory allocation as it was not used in any way (at least for now) */
357 // memptr = HIDD_PCIDriver_AllocPCIMem(hc->hc_PCIDriverObject, hc->hc_PCIMemSize);
358 // hc->hc_PCIMem = (APTR) memptr;
359 hc->hc_PCIMem = NULL;
361 // if(memptr) {
363 // PhysicalAddress - VirtualAdjust = VirtualAddress
364 // VirtualAddress + VirtualAdjust = PhysicalAddress
365 // hc->hc_PCIVirtualAdjust = pciGetPhysical(hc, memptr) - (APTR)memptr;
366 // KPRINTF(10, ("VirtualAdjust 0x%08lx\n", hc->hc_PCIVirtualAdjust));
368 hc->hc_CompleteInt.is_Node.ln_Type = NT_INTERRUPT;
369 hc->hc_CompleteInt.is_Node.ln_Name = "XHCI CompleteInt";
370 hc->hc_CompleteInt.is_Node.ln_Pri = 0;
371 hc->hc_CompleteInt.is_Data = hc;
372 hc->hc_CompleteInt.is_Code = (VOID_FUNC)xhciCompleteInt;
374 // add reset handler
375 hc->hc_ResetInt.is_Code = (VOID_FUNC)xhciResetHandler;
376 hc->hc_ResetInt.is_Data = hc;
377 AddResetCallback(&hc->hc_ResetInt);
379 // add interrupt handler
380 hc->hc_PCIIntHandler.is_Node.ln_Name = "XHCI PCI (pciusb.device)";
381 hc->hc_PCIIntHandler.is_Node.ln_Pri = 5;
382 hc->hc_PCIIntHandler.is_Node.ln_Type = NT_INTERRUPT;
383 hc->hc_PCIIntHandler.is_Code = (VOID_FUNC)xhciIntCode;
384 hc->hc_PCIIntHandler.is_Data = hc;
385 PCIXAddInterrupt(hc, &hc->hc_PCIIntHandler);
387 /* Clears (RW1C) Host System Error(HSE), Event Interrupt(EINT), Port Change Detect(PCD) and Save/Restore Error(SRE) */
388 temp = opreg_readl(XHCI_USBSTS);
389 opreg_writel(XHCI_USBSTS, temp);
391 /* After reset all notifications should be automatically disabled but ensure anyway */
392 opreg_writel(XHCI_DNCTRL, 0);
394 /* Program the Max Device Slots Enabled (MaxSlotsEn) field */
396 Max Device Slots Enabled (MaxSlotsEn) – RW. Default = ‘0’. This field specifies the maximum
397 number of enabled Device Slots. Valid values are in the range of 0 to MaxSlots. Enabled Devices
398 Slots are allocated contiguously. e.g. A value of 16 specifies that Device Slots 1 to 16 are active.
399 A value of ‘0’ disables all Device Slots. A disabled Device Slot shall not respond to Doorbell
400 Register references.
401 This field shall not be modified by software if the xHC is running (Run/Stop (R/S) = ‘1’).
403 opreg_writel(XHCI_CONFIG, ((opreg_readl(XHCI_CONFIG) & ~XHCM_CONFIG_MaxSlotsEn) | hc->xhc_maxslots));
406 Device Context Base Address Array 2048, PAGESIZE, 64
408 hc->xhc_dcbaa = AllocVecAligned( ((hc->xhc_maxslots + 1)*sizeof(UQUAD)), 64, hc->xhc_pagesize);
409 if( !(hc->xhc_dcbaa) ){
410 KPRINTF(1000, ("Unable to allocate device context base array, failing!\n"));
411 return FALSE;
412 }else{
414 if(hc->xhc_scratchpads) {
417 Scratchpad array is 64 byte aligned and can not cross page boundary
418 Scratchpad Buffer Array 248, PAGESIZE, 64
420 hc->xhc_scratchpadarray = AllocVecAligned( (hc->xhc_scratchpads*sizeof(UQUAD) ), 64, hc->xhc_pagesize);
421 if( !(hc->xhc_scratchpadarray) ){
422 FreeVecAligned(hc->xhc_dcbaa);
423 KPRINTF(1000, ("Unable to allocate scratchpad buffer array, failing!\n"));
424 return FALSE;
427 KPRINTF(1000, ("Allocated scratchpad buffer array at %p\n", hc->xhc_scratchpadarray));
429 for(temp = 0; temp<hc->xhc_scratchpads; temp++){
432 A Scratchpad Buffer is a PAGESIZE block of system memory located on a PAGESIZE boundary
434 memptr = AllocVecAligned(hc->xhc_pagesize, hc->xhc_pagesize, hc->xhc_pagesize);
435 if(memptr){
436 //hc->xhc_scratchpadarray[temp] = (UQUAD) (0xDEADBEEF00000000 | (UQUAD) memptr);
437 hc->xhc_scratchpadarray[temp] = (UQUAD) memptr;
438 /* CHECKME: Not really sure if the 32(or 64) bit address is stored correctly in the QUAD pointer list */
439 KPRINTF(1000, ("hc->xhc_scratchpadarray[%d] = %0lx:%0lx\n", temp, (ULONG) ((UQUAD)(hc->xhc_scratchpadarray[temp])>>32), (ULONG) hc->xhc_scratchpadarray[temp]));
440 }else{
441 for(temp = 0; temp<hc->xhc_scratchpads; temp++){
442 if(hc->xhc_scratchpadarray[temp]){
443 FreeVecAligned( (APTR) hc->xhc_scratchpadarray[temp] );
446 return FALSE;
450 }else{
452 Host controller does not use scratchpads (This is the case OnMyHW™)
454 hc->xhc_scratchpadarray = NULL;
458 KPRINTF(1000, ("Device context base array at %p\n", hc->xhc_dcbaa));
460 opreg_writeq(XHCI_DCBAAP, (UQUAD)hc->xhc_dcbaa );
462 /* FIXME: Allocate device context data structures and fill rest of the DCBAA array*/
464 hc->xhc_dcbaa[0] = (UQUAD) hc->xhc_scratchpadarray;
466 /* Define the Command Ring Dequeue Pointer by programming the Command Ring Control Register */
468 /* Set Run/Stop(R/S), Interrupter Enable(INTE) and Host System Error Enable(HSEE) */
469 // opreg_writel(XHCI_USBCMD, (XHCF_CMD_RS | XHCF_CMD_INTE | XHCF_CMD_HSEE) );
471 KPRINTF(1000, ("xhciInit returns TRUE...\n"));
472 return TRUE;
477 KPRINTF(1000, ("xhciInit returns FALSE...\n"));
478 return FALSE;
481 void xhciFree(struct PCIController *hc, struct PCIUnit *hu) {
483 hc = (struct PCIController *) hu->hu_Controllers.lh_Head;
484 while(hc->hc_Node.ln_Succ)
486 switch(hc->hc_HCIType)
488 case HCITYPE_XHCI:
490 KPRINTF(1000, ("Shutting down XHCI %08lx\n", hc));
491 xhciHaltHC(hc);
492 uhwDelayMS(50, hu);
493 SYNC;
494 KPRINTF(1000, ("Shutting down XHCI done.\n"));
495 break;
499 hc = (struct PCIController *) hc->hc_Node.ln_Succ;
503 void xhciParseSupProtocol(struct PCIController *hc, IPTR extcap) {
505 ULONG temp1, temp2;
507 temp1 = READMEM32_LE(extcap);
508 KPRINTF(1000, ("Version %l.%l\n", XHCV_SPFD_RMAJOR(temp1), XHCV_SPFD_RMINOR(temp1) ));
510 temp2 = READMEM32_LE(extcap + XHCI_SPPORT);
511 // KPRINTF(1000, ("CPO %ld\n", XHCV_SPPORT_CPO(temp2) ));
512 // KPRINTF(1000, ("CPCNT %ld\n", XHCV_SPPORT_CPCNT(temp2) ));
513 // KPRINTF(1000, ("PD %ld\n", XHCV_SPPORT_PD(temp2) ));
514 // KPRINTF(1000, ("PSIC %ld\n", XHCV_SPPORT_PSIC(temp2) ));
517 FIXME:
518 -We might not get at all "USB2 Supported Protocol", in that case make a wild assumption on # USB2.0 ports
519 -Check if the name string is "USB " (=0x20425355)
520 -Map USB specifications to their respective ports (USB2.0/USB3.0)
523 if(XHCV_SPFD_RMAJOR(temp1) == 2) {
524 hc->xhc_NumPorts20 = ((XHCV_SPPORT_CPCNT(temp2) - XHCV_SPPORT_CPO(temp2) + 1));
526 if(XHCV_SPFD_RMAJOR(temp1) == 3) {
527 hc->xhc_NumPorts30 = ((XHCV_SPPORT_CPCNT(temp2) - XHCV_SPPORT_CPO(temp2) + 1));
531 #endif