1 /* pci_aros.c - pci access abstraction for AROS by Chris Hodges
4 #include <aros/bootloader.h>
5 #include <aros/symbolsets.h>
6 #include <exec/types.h>
8 #include <devices/timer.h>
11 #include <resources/acpi.h>
13 #include <proto/acpi.h>
14 #include <proto/bootloader.h>
15 #include <proto/oop.h>
16 #include <proto/utility.h>
17 #include <proto/exec.h>
23 #include "ohciproto.h"
32 #define NewList NEWLIST
34 #undef HiddPCIDeviceAttrBase
35 //#undef HiddUSBDeviceAttrBase
36 //#undef HiddUSBHubAttrBase
37 //#undef HiddUSBDrvAttrBase
40 #define HiddPCIDeviceAttrBase (hd->hd_HiddPCIDeviceAB)
41 //#define HiddUSBDeviceAttrBase (hd->hd_HiddUSBDeviceAB)
42 //#define HiddUSBHubAttrBase (hd->hd_HiddUSBHubAB)
43 //#define HiddUSBDrvAttrBase (hd->hd_HiddUSBDrvAB)
44 #define HiddAttrBase (hd->hd_HiddAB)
46 AROS_UFH3(void, pciEnumerator
,
47 AROS_UFHA(struct Hook
*, hook
, A0
),
48 AROS_UFHA(OOP_Object
*, pciDevice
, A2
),
49 AROS_UFHA(APTR
, message
, A1
))
53 struct PCIDevice
*hd
= (struct PCIDevice
*) hook
->h_Data
;
54 struct PCIController
*hc
;
62 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_Interface
, &hcitype
);
63 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_Bus
, &bus
);
64 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_Dev
, &dev
);
65 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_Sub
, &sub
);
66 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_INTLine
, &intline
);
68 devid
= (bus
<<16)|dev
;
70 KPRINTF(10, ("Found PCI device 0x%lx of type %ld, Intline=%ld\n", devid
, hcitype
, intline
));
74 // we can't work without the correct interrupt line
75 // BIOS needs plug & play os option disabled. Alternatively AROS must support APIC reconfiguration
76 KPRINTF(200, ("ERROR: PCI card has no interrupt line assigned by BIOS, disable Plug & Play OS!\n"));
85 #ifdef AROS_USB30_CODE
88 KPRINTF(10, ("Setting up device...\n"));
90 hc
= AllocPooled(hd
->hd_MemPool
, sizeof(struct PCIController
));
95 hc
->hc_FunctionNum
= sub
;
96 hc
->hc_HCIType
= hcitype
;
97 hc
->hc_PCIDeviceObject
= pciDevice
;
98 hc
->hc_PCIIntLine
= intline
;
100 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_Driver
, (IPTR
*) &hc
->hc_PCIDriverObject
);
102 NewList(&hc
->hc_CtrlXFerQueue
);
103 NewList(&hc
->hc_IntXFerQueue
);
104 NewList(&hc
->hc_IsoXFerQueue
);
105 NewList(&hc
->hc_BulkXFerQueue
);
106 NewList(&hc
->hc_TDQueue
);
107 NewList(&hc
->hc_AbortQueue
);
108 NewList(&hc
->hc_PeriodicTDQueue
);
109 NewList(&hc
->hc_OhciRetireQueue
);
110 AddTail(&hd
->hd_TempHCIList
, &hc
->hc_Node
);
115 KPRINTF(10, ("Unsupported HCI type %ld\n", hcitype
));
122 /* /// "pciInit()" */
123 BOOL
pciInit(struct PCIDevice
*hd
)
125 struct PCIController
*hc
;
126 struct PCIController
*nexthc
;
130 KPRINTF(10, ("*** pciInit(%p) ***\n", hd
));
131 /* if(sizeof(IPTR) > 4)
133 KPRINTF(200, ("I said the pciusb.device is not 64bit compatible right now. Go away!\n"));
137 NewList(&hd
->hd_TempHCIList
);
139 if((hd
->hd_PCIHidd
= OOP_NewObject(NULL
, (STRPTR
) CLID_Hidd_PCI
, NULL
)))
141 struct TagItem tags
[] =
143 { tHidd_PCI_Class
, (PCI_CLASS_SERIAL_USB
>>8) & 0xff },
144 { tHidd_PCI_SubClass
, (PCI_CLASS_SERIAL_USB
& 0xff) },
148 struct OOP_ABDescr attrbases
[] =
150 { (STRPTR
) IID_Hidd
, &hd
->hd_HiddAB
},
151 { (STRPTR
) IID_Hidd_PCIDevice
, &hd
->hd_HiddPCIDeviceAB
},
155 struct Hook findHook
=
157 h_Entry
: (IPTR (*)()) pciEnumerator
,
161 OOP_ObtainAttrBases(attrbases
);
163 KPRINTF(20, ("Searching for devices...\n"));
165 HIDD_PCI_EnumDevices(hd
->hd_PCIHidd
, &findHook
, (struct TagItem
*) &tags
);
167 KPRINTF(20, ("Unable to create PCIHidd object!\n"));
171 // Create units with a list of host controllers having the same bus and device number.
172 while(hd
->hd_TempHCIList
.lh_Head
->ln_Succ
)
174 hu
= AllocPooled(hd
->hd_MemPool
, sizeof(struct PCIUnit
));
177 // actually, we should get rid of the allocated memory first, but I don't care as DeletePool() will take care of this eventually
181 hu
->hu_UnitNo
= unitno
;
182 hu
->hu_DevID
= ((struct PCIController
*) hd
->hd_TempHCIList
.lh_Head
)->hc_DevID
;
184 NewList(&hu
->hu_Controllers
);
185 NewList(&hu
->hu_RHIOQueue
);
187 hc
= (struct PCIController
*) hd
->hd_TempHCIList
.lh_Head
;
188 while((nexthc
= (struct PCIController
*) hc
->hc_Node
.ln_Succ
))
190 if(hc
->hc_DevID
== hu
->hu_DevID
)
192 Remove(&hc
->hc_Node
);
194 AddTail(&hu
->hu_Controllers
, &hc
->hc_Node
);
198 AddTail(&hd
->hd_Units
, (struct Node
*) hu
);
205 /* /// "PCIXReadConfigByte()" */
206 UBYTE
PCIXReadConfigByte(struct PCIController
*hc
, UBYTE offset
)
208 struct pHidd_PCIDevice_ReadConfigByte msg
;
210 msg
.mID
= OOP_GetMethodID(CLID_Hidd_PCIDevice
, moHidd_PCIDevice_ReadConfigByte
);
213 return OOP_DoMethod(hc
->hc_PCIDeviceObject
, (OOP_Msg
) &msg
);
217 /* /// "PCIXReadConfigWord()" */
218 UWORD
PCIXReadConfigWord(struct PCIController
*hc
, UBYTE offset
)
220 struct pHidd_PCIDevice_ReadConfigWord msg
;
222 msg
.mID
= OOP_GetMethodID(CLID_Hidd_PCIDevice
, moHidd_PCIDevice_ReadConfigWord
);
225 return OOP_DoMethod(hc
->hc_PCIDeviceObject
, (OOP_Msg
) &msg
);
229 /* /// "PCIXReadConfigLong()" */
230 ULONG
PCIXReadConfigLong(struct PCIController
*hc
, UBYTE offset
)
232 struct pHidd_PCIDevice_ReadConfigLong msg
;
234 msg
.mID
= OOP_GetMethodID(CLID_Hidd_PCIDevice
, moHidd_PCIDevice_ReadConfigLong
);
237 return OOP_DoMethod(hc
->hc_PCIDeviceObject
, (OOP_Msg
) &msg
);
241 /* /// "PCIXWriteConfigByte()" */
242 void PCIXWriteConfigByte(struct PCIController
*hc
, ULONG offset
, UBYTE value
)
244 struct pHidd_PCIDevice_WriteConfigByte msg
;
246 msg
.mID
= OOP_GetMethodID(CLID_Hidd_PCIDevice
, moHidd_PCIDevice_WriteConfigByte
);
250 OOP_DoMethod(hc
->hc_PCIDeviceObject
, (OOP_Msg
) &msg
);
254 /* /// "PCIXWriteConfigWord()" */
255 void PCIXWriteConfigWord(struct PCIController
*hc
, ULONG offset
, UWORD value
)
257 struct pHidd_PCIDevice_WriteConfigWord msg
;
259 msg
.mID
= OOP_GetMethodID(CLID_Hidd_PCIDevice
, moHidd_PCIDevice_WriteConfigWord
);
263 OOP_DoMethod(hc
->hc_PCIDeviceObject
, (OOP_Msg
) &msg
);
267 /* /// "PCIXWriteConfigLong()" */
268 void PCIXWriteConfigLong(struct PCIController
*hc
, ULONG offset
, ULONG value
)
270 struct pHidd_PCIDevice_WriteConfigLong msg
;
272 msg
.mID
= OOP_GetMethodID(CLID_Hidd_PCIDevice
, moHidd_PCIDevice_WriteConfigLong
);
276 OOP_DoMethod(hc
->hc_PCIDeviceObject
, (OOP_Msg
) &msg
);
280 /* /// "pciStrcat()" */
281 void pciStrcat(STRPTR d
, STRPTR s
)
284 while((*d
++ = *s
++));
288 /* /// "pciAllocUnit()" */
289 BOOL
pciAllocUnit(struct PCIUnit
*hu
)
292 struct PCIDevice
*hd
= hu
->hu_Device
;
294 struct PCIController
*hc
;
296 BOOL allocgood
= TRUE
;
297 ULONG usb11ports
= 0;
298 ULONG usb20ports
= 0;
299 #ifdef AROS_USB30_CODE
300 ULONG usb30ports
= 0;
307 #ifdef AROS_USB30_CODE
313 KPRINTF(10, ("*** pciAllocUnit(%p) ***\n", hu
));
315 #if 0 // FIXME this needs to be replaced by something AROS supports
316 hc
= (struct PCIController
*) hu
->hu_Controllers
.lh_Head
;
317 while(hc
->hc_Node
.ln_Succ
)
319 PCIXObtainBoard(hc
->hc_BoardObject
);
320 if (PCIXSetBoardAttr(hc
->hc_BoardObject
, PCIXTAG_OWNER
, (ULONG
) hd
->hd_Library
.lib_Node
.ln_Name
))
321 hc
->hc_Flags
|= HCF_BOARD_ALLOCATED
;
324 KPRINTF(20, ("Couldn't allocate board, already allocated by %s\n", PCIXGetBoardAttr(hc
->hc_BoardObject
, PCIXTAG_OWNER
)));
327 PCIXReleaseBoard(hc
->hc_BoardObject
);
329 hc
= (struct PCIController
*) hc
->hc_Node
.ln_Succ
;
335 // allocate necessary memory
336 hc
= (struct PCIController
*) hu
->hu_Controllers
.lh_Head
;
337 while(hc
->hc_Node
.ln_Succ
)
339 switch(hc
->hc_HCIType
)
343 allocgood
= uhciInit(hc
,hu
);
352 allocgood
= ohciInit(hc
,hu
);
361 allocgood
= ehciInit(hc
,hu
);
365 KPRINTF(200, ("WARNING: More than one EHCI controller per board?!?\n"));
367 usb20ports
= hc
->hc_NumPorts
;
369 for(cnt
= 0; cnt
< usb20ports
; cnt
++) {
370 hu
->hu_PortMap20
[cnt
] = hc
;
371 hc
->hc_PortNum20
[cnt
] = cnt
;
376 #ifdef AROS_USB30_CODE
379 allocgood
= xhciInit(hc
,hu
);
383 KPRINTF(200, ("WARNING: More than one XHCI controller per board?!?\n"));
385 usb20ports
= hc
->xhc_NumPorts20
;
386 usb30ports
= hc
->xhc_NumPorts30
;
392 hc
= (struct PCIController
*) hc
->hc_Node
.ln_Succ
;
394 #if 0 // FIXME this needs to be replaced by something AROS supports
399 // free previously allocated boards
400 hc
= (struct PCIController
*) hu
->hu_Controllers
.lh_Head
;
401 while(hc
->hc_Node
.ln_Succ
)
403 PCIXObtainBoard(hc
->hc_BoardObject
);
404 if (hc
->hc_Flags
& HCF_ALLOCATED
)
406 hc
->hc_Flags
&= ~HCF_ALLOCATED
;
407 PCIXSetBoardAttr(hc
->hc_BoardObject
, PCIXTAG_OWNER
, 0);
409 PCIXReleaseBoard(hc
->hc_BoardObject
);
411 hc
= (struct PCIController
*) hc
->hc_Node
.ln_Succ
;
420 hc
= (struct PCIController
*) hu
->hu_Controllers
.lh_Head
;
421 while(hc
->hc_Node
.ln_Succ
)
423 if((hc
->hc_HCIType
== HCITYPE_UHCI
) || (hc
->hc_HCIType
== HCITYPE_OHCI
))
425 if(hc
->hc_complexrouting
)
428 for(cnt
= 0; cnt
< usb20ports
; cnt
++)
430 if(((hc
->hc_portroute
>> (cnt
<<2)) & 0xf) == hc
->hc_FunctionNum
)
432 KPRINTF(10, ("CHC %ld Port %ld assigned to global Port %ld\n", hc
->hc_FunctionNum
, locport
, cnt
));
433 hu
->hu_PortMap11
[cnt
] = hc
;
434 hu
->hu_PortNum11
[cnt
] = locport
;
435 hc
->hc_PortNum20
[locport
] = cnt
;
440 for(cnt
= usb11ports
; cnt
< usb11ports
+ hc
->hc_NumPorts
; cnt
++)
442 hu
->hu_PortMap11
[cnt
] = hc
;
443 hu
->hu_PortNum11
[cnt
] = cnt
- usb11ports
;
444 hc
->hc_PortNum20
[cnt
- usb11ports
] = cnt
;
447 usb11ports
+= hc
->hc_NumPorts
;
449 hc
= (struct PCIController
*) hc
->hc_Node
.ln_Succ
;
451 if((usb11ports
!= usb20ports
) && usb20ports
)
453 KPRINTF(20, ("Warning! #EHCI Ports (%ld) does not match USB 1.1 Ports (%ld)!\n", usb20ports
, usb11ports
));
456 hu
->hu_RootHub11Ports
= usb11ports
;
457 hu
->hu_RootHub20Ports
= usb20ports
;
458 #ifdef AROS_USB30_CODE
459 // FIXME: This is probably wrong as well...
460 hu
->hu_RootHub30Ports
= usb30ports
;
461 hu
->hu_RootHubPorts
= (usb11ports
> usb20ports
) ? ((usb11ports
> usb30ports
) ? usb11ports
: usb30ports
) : ((usb30ports
> usb20ports
) ? usb30ports
: usb20ports
);
463 hu
->hu_RootHubPorts
= (usb11ports
> usb20ports
) ? usb11ports
: usb20ports
;
465 for(cnt
= 0; cnt
< hu
->hu_RootHubPorts
; cnt
++)
467 hu
->hu_EhciOwned
[cnt
] = hu
->hu_PortMap20
[cnt
] ? TRUE
: FALSE
;
470 #ifdef AROS_USB30_CODE
471 KPRINTF(1000, ("Unit %ld: USB Board %08lx has %ld USB1.1, %ld USB2.0 and %ld USB3.0 ports!\n", hu
->hu_UnitNo
, hu
->hu_DevID
, hu
->hu_RootHub11Ports
, hu
->hu_RootHub20Ports
, hu
->hu_RootHub30Ports
));
473 KPRINTF(10, ("Unit %ld: USB Board %08lx has %ld USB1.1 and %ld USB2.0 ports!\n", hu
->hu_UnitNo
, hu
->hu_DevID
, hu
->hu_RootHub11Ports
, hu
->hu_RootHub20Ports
));
476 hu
->hu_FrameCounter
= 1;
477 hu
->hu_RootHubAddr
= 0;
480 hc
= (struct PCIController
*) hu
->hu_Controllers
.lh_Head
;
481 while(hc
->hc_Node
.ln_Succ
)
483 hc
->hc_Flags
|= HCF_ONLINE
;
484 hc
= (struct PCIController
*) hc
->hc_Node
.ln_Succ
;
487 // create product name of device
488 prodname
= hu
->hu_ProductName
;
490 pciStrcat(prodname
, "PCI ");
491 if(ohcicnt
+ uhcicnt
)
493 if(ohcicnt
+ uhcicnt
>1)
495 prodname
[4] = ohcicnt
+ uhcicnt
+ '0';
499 pciStrcat(prodname
, ohcicnt
? "OHCI" : "UHCI");
502 pciStrcat(prodname
, " +");
504 pciStrcat(prodname
, " USB 1.1");
509 pciStrcat(prodname
, " EHCI USB 2.0");
511 #ifdef AROS_USB30_CODE
516 prodname
[4] = xhcicnt
+ '0';
520 pciStrcat(prodname
, " XHCI USB 3.0");
523 #if 0 // user can use pcitool to check what the chipset is and not guess it from this
524 pciStrcat(prodname
, " Host Controller (");
525 if(ohcicnt
+ uhcicnt
)
527 pciStrcat(prodname
, ohcicnt
? "NEC)" : "VIA, Intel, ALI, etc.)");
529 pciStrcat(prodname
, "Emulated?)");
532 pciStrcat(prodname
, " Host Controller");
534 KPRINTF(10, ("Unit allocated!\n"));
540 /* /// "pciFreeUnit()" */
541 void pciFreeUnit(struct PCIUnit
*hu
)
543 struct PCIDevice
*hd
= hu
->hu_Device
;
544 struct PCIController
*hc
;
546 struct TagItem pciDeactivate
[] =
548 { aHidd_PCIDevice_isIO
, FALSE
},
549 { aHidd_PCIDevice_isMEM
, FALSE
},
550 { aHidd_PCIDevice_isMaster
, FALSE
},
554 KPRINTF(10, ("*** pciFreeUnit(%p) ***\n", hu
));
557 hc
= (struct PCIController
*) hu
->hu_Controllers
.lh_Head
;
558 while(hc
->hc_Node
.ln_Succ
)
560 hc
->hc_Flags
&= ~HCF_ONLINE
;
561 hc
= (struct PCIController
*) hc
->hc_Node
.ln_Succ
;
564 #ifdef AROS_USB30_CODE
567 // doing this in three steps to avoid these damn host errors
572 //FIXME: (x/e/o/u)hciFree routines actually ONLY stops the chip NOT free anything as below...
573 hc
= (struct PCIController
*) hu
->hu_Controllers
.lh_Head
;
574 while(hc
->hc_Node
.ln_Succ
) {
576 HIDD_PCIDriver_FreePCIMem(hc
->hc_PCIDriverObject
, hc
->hc_PCIMem
);
577 hc
->hc_PCIMem
= NULL
;
579 hc
= (struct PCIController
*) hc
->hc_Node
.ln_Succ
;
582 // disable and free board
583 hc
= (struct PCIController
*) hu
->hu_Controllers
.lh_Head
;
584 while(hc
->hc_Node
.ln_Succ
)
586 OOP_SetAttrs(hc
->hc_PCIDeviceObject
, (struct TagItem
*) pciDeactivate
); // deactivate busmaster and IO/Mem
587 if(hc
->hc_PCIIntHandler
.is_Node
.ln_Name
)
589 RemIntServer(INTB_KERNEL
+ hc
->hc_PCIIntLine
, &hc
->hc_PCIIntHandler
);
590 hc
->hc_PCIIntHandler
.is_Node
.ln_Name
= NULL
;
594 PCIXObtainBoard(hc
->hc_BoardObject
);
595 hc
->hc_Flags
&= ~HCF_ALLOCATED
;
596 PCIXSetBoardAttr(hc
->hc_BoardObject
, PCIXTAG_OWNER
, 0);
597 PCIXReleaseBoard(hc
->hc_BoardObject
);
599 hc
= (struct PCIController
*) hc
->hc_Node
.ln_Succ
;
604 /* /// "pciExpunge()" */
605 void pciExpunge(struct PCIDevice
*hd
)
607 struct PCIController
*hc
;
610 KPRINTF(10, ("*** pciExpunge(%p) ***\n", hd
));
612 hu
= (struct PCIUnit
*) hd
->hd_Units
.lh_Head
;
613 while(((struct Node
*) hu
)->ln_Succ
)
615 Remove((struct Node
*) hu
);
616 hc
= (struct PCIController
*) hu
->hu_Controllers
.lh_Head
;
617 while(hc
->hc_Node
.ln_Succ
)
619 Remove(&hc
->hc_Node
);
620 FreePooled(hd
->hd_MemPool
, hc
, sizeof(struct PCIController
));
621 hc
= (struct PCIController
*) hu
->hu_Controllers
.lh_Head
;
623 FreePooled(hd
->hd_MemPool
, hu
, sizeof(struct PCIUnit
));
624 hu
= (struct PCIUnit
*) hd
->hd_Units
.lh_Head
;
628 struct OOP_ABDescr attrbases
[] =
630 { (STRPTR
) IID_Hidd
, &hd
->hd_HiddAB
},
631 { (STRPTR
) IID_Hidd_PCIDevice
, &hd
->hd_HiddPCIDeviceAB
},
635 OOP_ReleaseAttrBases(attrbases
);
637 OOP_DisposeObject(hd
->hd_PCIHidd
);
642 /* /// "pciGetPhysical()" */
643 APTR
pciGetPhysical(struct PCIController
*hc
, APTR virtaddr
)
645 //struct PCIDevice *hd = hc->hc_Device;
646 return(HIDD_PCIDriver_CPUtoPCI(hc
->hc_PCIDriverObject
, virtaddr
));
651 * Process some AROS-specific arguments.
652 * 'usbpoweron' helps to bring up USB ports on IntelMac,
653 * whose firmware sets them up incorrectly.
655 static int getArguments(struct PCIDevice
*base
)
659 struct ACPIBase
*ACPIBase
;
661 ACPIBase
= OpenResource("acpi.resource");
665 * Use ACPI IDs to identify known machines which need HDF_FORCEPOWER to work.
666 * Currently we know only MacMini.
668 struct ACPI_TABLE_DEF_HEADER
*dsdt
= ACPI_FindSDT(ACPI_MAKE_ID('D','S','D','T'));
672 /* Yes, the last byte in ID is zero */
673 if (strcmp(dsdt
->oem_table_id
, "Macmini") == 0)
675 base
->hd_Flags
= HDF_FORCEPOWER
;
682 BootLoaderBase
= OpenResource("bootloader.resource");
685 struct List
*args
= GetBootInfo(BL_Args
);
691 for (node
= args
->lh_Head
; node
->ln_Succ
; node
= node
->ln_Succ
)
693 if (stricmp(node
->ln_Name
, "forceusbpower") == 0)
695 base
->hd_Flags
= HDF_FORCEPOWER
;
705 ADD2INITLIB(getArguments
, 10)