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>
12 #include <resources/acpi.h>
14 #include <proto/acpi.h>
15 #include <proto/bootloader.h>
16 #include <proto/oop.h>
17 #include <proto/utility.h>
18 #include <proto/exec.h>
24 #include "ohciproto.h"
33 #define NewList NEWLIST
35 #undef HiddPCIDeviceAttrBase
36 //#undef HiddUSBDeviceAttrBase
37 //#undef HiddUSBHubAttrBase
38 //#undef HiddUSBDrvAttrBase
41 #define HiddPCIDeviceAttrBase (hd->hd_HiddPCIDeviceAB)
42 //#define HiddUSBDeviceAttrBase (hd->hd_HiddUSBDeviceAB)
43 //#define HiddUSBHubAttrBase (hd->hd_HiddUSBHubAB)
44 //#define HiddUSBDrvAttrBase (hd->hd_HiddUSBDrvAB)
45 #define HiddAttrBase (hd->hd_HiddAB)
47 AROS_UFH3(void, pciEnumerator
,
48 AROS_UFHA(struct Hook
*, hook
, A0
),
49 AROS_UFHA(OOP_Object
*, pciDevice
, A2
),
50 AROS_UFHA(APTR
, message
, A1
))
54 struct PCIDevice
*hd
= (struct PCIDevice
*) hook
->h_Data
;
55 struct PCIController
*hc
;
63 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_Interface
, &hcitype
);
64 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_Bus
, &bus
);
65 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_Dev
, &dev
);
66 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_Dev
, &sub
);
67 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_INTLine
, &intline
);
69 devid
= (bus
<<16)|dev
;
71 KPRINTF(10, ("Found PCI device 0x%lx of type %ld, Intline=%ld\n", devid
, hcitype
, intline
));
75 // we can't work without the correct interrupt line
76 // BIOS needs plug & play os option disabled. Alternatively AROS must support APIC reconfiguration
77 KPRINTF(200, ("ERROR: PCI card has no interrupt line assigned by BIOS, disable Plug & Play OS!\n"));
84 #ifndef __powerpc__ /* It was not from me. Perhaps on PPC these drivers suffer from CPU cache problems? (sonic) */
88 #ifdef AROS_USB30_CODE
91 KPRINTF(10, ("Setting up device...\n"));
93 hc
= AllocPooled(hd
->hd_MemPool
, sizeof(struct PCIController
));
98 hc
->hc_FunctionNum
= sub
;
99 hc
->hc_HCIType
= hcitype
;
100 hc
->hc_PCIDeviceObject
= pciDevice
;
101 hc
->hc_PCIIntLine
= intline
;
103 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_Driver
, (IPTR
*) &hc
->hc_PCIDriverObject
);
105 NewList(&hc
->hc_CtrlXFerQueue
);
106 NewList(&hc
->hc_IntXFerQueue
);
107 NewList(&hc
->hc_IsoXFerQueue
);
108 NewList(&hc
->hc_BulkXFerQueue
);
109 NewList(&hc
->hc_TDQueue
);
110 NewList(&hc
->hc_AbortQueue
);
111 NewList(&hc
->hc_PeriodicTDQueue
);
112 NewList(&hc
->hc_OhciRetireQueue
);
113 AddTail(&hd
->hd_TempHCIList
, &hc
->hc_Node
);
118 KPRINTF(10, ("Unsupported HCI type %ld\n", hcitype
));
125 /* /// "pciInit()" */
126 BOOL
pciInit(struct PCIDevice
*hd
)
128 struct PCIController
*hc
;
129 struct PCIController
*nexthc
;
133 KPRINTF(10, ("*** pciInit(%p) ***\n", hd
));
134 /* if(sizeof(IPTR) > 4)
136 KPRINTF(200, ("I said the pciusb.device is not 64bit compatible right now. Go away!\n"));
140 NewList(&hd
->hd_TempHCIList
);
142 if(!(hd
->hd_IRQHidd
= OOP_NewObject(NULL
, (STRPTR
) CLID_Hidd_IRQ
, NULL
)))
144 KPRINTF(20, ("Unable to create IRQHidd object!\n"));
148 if((hd
->hd_PCIHidd
= OOP_NewObject(NULL
, (STRPTR
) CLID_Hidd_PCI
, NULL
)))
150 struct TagItem tags
[] =
152 { tHidd_PCI_Class
, (PCI_CLASS_SERIAL_USB
>>8) & 0xff },
153 { tHidd_PCI_SubClass
, (PCI_CLASS_SERIAL_USB
& 0xff) },
157 struct OOP_ABDescr attrbases
[] =
159 { (STRPTR
) IID_Hidd
, &hd
->hd_HiddAB
},
160 { (STRPTR
) IID_Hidd_PCIDevice
, &hd
->hd_HiddPCIDeviceAB
},
164 struct Hook findHook
=
166 h_Entry
: (IPTR (*)()) pciEnumerator
,
170 OOP_ObtainAttrBases(attrbases
);
172 KPRINTF(20, ("Searching for devices...\n"));
174 HIDD_PCI_EnumDevices(hd
->hd_PCIHidd
, &findHook
, (struct TagItem
*) &tags
);
176 KPRINTF(20, ("Unable to create PCIHidd object!\n"));
177 OOP_DisposeObject(hd
->hd_IRQHidd
);
181 // Create units with a list of host controllers having the same bus and device number.
182 while(hd
->hd_TempHCIList
.lh_Head
->ln_Succ
)
184 hu
= AllocPooled(hd
->hd_MemPool
, sizeof(struct PCIUnit
));
187 // actually, we should get rid of the allocated memory first, but I don't care as DeletePool() will take care of this eventually
191 hu
->hu_UnitNo
= unitno
;
192 hu
->hu_DevID
= ((struct PCIController
*) hd
->hd_TempHCIList
.lh_Head
)->hc_DevID
;
194 NewList(&hu
->hu_Controllers
);
195 NewList(&hu
->hu_RHIOQueue
);
197 hc
= (struct PCIController
*) hd
->hd_TempHCIList
.lh_Head
;
198 while((nexthc
= (struct PCIController
*) hc
->hc_Node
.ln_Succ
))
200 if(hc
->hc_DevID
== hu
->hu_DevID
)
202 Remove(&hc
->hc_Node
);
204 AddTail(&hu
->hu_Controllers
, &hc
->hc_Node
);
208 AddTail(&hd
->hd_Units
, (struct Node
*) hu
);
215 /* /// "PCIXReadConfigByte()" */
216 UBYTE
PCIXReadConfigByte(struct PCIController
*hc
, UBYTE offset
)
218 struct pHidd_PCIDevice_ReadConfigByte msg
;
220 msg
.mID
= OOP_GetMethodID(CLID_Hidd_PCIDevice
, moHidd_PCIDevice_ReadConfigByte
);
223 return OOP_DoMethod(hc
->hc_PCIDeviceObject
, (OOP_Msg
) &msg
);
227 /* /// "PCIXReadConfigWord()" */
228 UWORD
PCIXReadConfigWord(struct PCIController
*hc
, UBYTE offset
)
230 struct pHidd_PCIDevice_ReadConfigWord msg
;
232 msg
.mID
= OOP_GetMethodID(CLID_Hidd_PCIDevice
, moHidd_PCIDevice_ReadConfigWord
);
235 return OOP_DoMethod(hc
->hc_PCIDeviceObject
, (OOP_Msg
) &msg
);
239 /* /// "PCIXReadConfigLong()" */
240 ULONG
PCIXReadConfigLong(struct PCIController
*hc
, UBYTE offset
)
242 struct pHidd_PCIDevice_ReadConfigLong msg
;
244 msg
.mID
= OOP_GetMethodID(CLID_Hidd_PCIDevice
, moHidd_PCIDevice_ReadConfigLong
);
247 return OOP_DoMethod(hc
->hc_PCIDeviceObject
, (OOP_Msg
) &msg
);
251 /* /// "PCIXWriteConfigByte()" */
252 void PCIXWriteConfigByte(struct PCIController
*hc
, ULONG offset
, UBYTE value
)
254 struct pHidd_PCIDevice_WriteConfigByte msg
;
256 msg
.mID
= OOP_GetMethodID(CLID_Hidd_PCIDevice
, moHidd_PCIDevice_WriteConfigByte
);
260 OOP_DoMethod(hc
->hc_PCIDeviceObject
, (OOP_Msg
) &msg
);
264 /* /// "PCIXWriteConfigWord()" */
265 void PCIXWriteConfigWord(struct PCIController
*hc
, ULONG offset
, UWORD value
)
267 struct pHidd_PCIDevice_WriteConfigWord msg
;
269 msg
.mID
= OOP_GetMethodID(CLID_Hidd_PCIDevice
, moHidd_PCIDevice_WriteConfigWord
);
273 OOP_DoMethod(hc
->hc_PCIDeviceObject
, (OOP_Msg
) &msg
);
277 /* /// "PCIXWriteConfigLong()" */
278 void PCIXWriteConfigLong(struct PCIController
*hc
, ULONG offset
, ULONG value
)
280 struct pHidd_PCIDevice_WriteConfigLong msg
;
282 msg
.mID
= OOP_GetMethodID(CLID_Hidd_PCIDevice
, moHidd_PCIDevice_WriteConfigLong
);
286 OOP_DoMethod(hc
->hc_PCIDeviceObject
, (OOP_Msg
) &msg
);
290 /* /// "pciStrcat()" */
291 void pciStrcat(STRPTR d
, STRPTR s
)
294 while((*d
++ = *s
++));
298 /* /// "pciAllocUnit()" */
299 BOOL
pciAllocUnit(struct PCIUnit
*hu
)
302 struct PCIDevice
*hd
= hu
->hu_Device
;
304 struct PCIController
*hc
;
306 BOOL allocgood
= TRUE
;
307 ULONG usb11ports
= 0;
308 ULONG usb20ports
= 0;
309 #ifdef AROS_USB30_CODE
310 ULONG usb30ports
= 0;
317 #ifdef AROS_USB30_CODE
323 KPRINTF(10, ("*** pciAllocUnit(%p) ***\n", hu
));
325 #if 0 // FIXME this needs to be replaced by something AROS supports
326 hc
= (struct PCIController
*) hu
->hu_Controllers
.lh_Head
;
327 while(hc
->hc_Node
.ln_Succ
)
329 PCIXObtainBoard(hc
->hc_BoardObject
);
330 if (PCIXSetBoardAttr(hc
->hc_BoardObject
, PCIXTAG_OWNER
, (ULONG
) hd
->hd_Library
.lib_Node
.ln_Name
))
331 hc
->hc_Flags
|= HCF_BOARD_ALLOCATED
;
334 KPRINTF(20, ("Couldn't allocate board, already allocated by %s\n", PCIXGetBoardAttr(hc
->hc_BoardObject
, PCIXTAG_OWNER
)));
337 PCIXReleaseBoard(hc
->hc_BoardObject
);
339 hc
= (struct PCIController
*) hc
->hc_Node
.ln_Succ
;
345 // allocate necessary memory
346 hc
= (struct PCIController
*) hu
->hu_Controllers
.lh_Head
;
347 while(hc
->hc_Node
.ln_Succ
)
349 switch(hc
->hc_HCIType
)
353 allocgood
= uhciInit(hc
,hu
);
362 allocgood
= ohciInit(hc
,hu
);
371 allocgood
= ehciInit(hc
,hu
);
375 KPRINTF(200, ("WARNING: More than one EHCI controller per board?!?\n"));
377 usb20ports
= hc
->hc_NumPorts
;
379 for(cnt
= 0; cnt
< usb20ports
; cnt
++) {
380 hu
->hu_PortMap20
[cnt
] = hc
;
381 hc
->hc_PortNum20
[cnt
] = cnt
;
386 #ifdef AROS_USB30_CODE
389 allocgood
= xhciInit(hc
,hu
);
393 KPRINTF(200, ("WARNING: More than one XHCI controller per board?!?\n"));
395 usb20ports
= hc
->xhc_NumPorts20
;
396 usb30ports
= hc
->xhc_NumPorts30
;
402 hc
= (struct PCIController
*) hc
->hc_Node
.ln_Succ
;
404 #if 0 // FIXME this needs to be replaced by something AROS supports
409 // free previously allocated boards
410 hc
= (struct PCIController
*) hu
->hu_Controllers
.lh_Head
;
411 while(hc
->hc_Node
.ln_Succ
)
413 PCIXObtainBoard(hc
->hc_BoardObject
);
414 if (hc
->hc_Flags
& HCF_ALLOCATED
)
416 hc
->hc_Flags
&= ~HCF_ALLOCATED
;
417 PCIXSetBoardAttr(hc
->hc_BoardObject
, PCIXTAG_OWNER
, 0);
419 PCIXReleaseBoard(hc
->hc_BoardObject
);
421 hc
= (struct PCIController
*) hc
->hc_Node
.ln_Succ
;
430 hc
= (struct PCIController
*) hu
->hu_Controllers
.lh_Head
;
431 while(hc
->hc_Node
.ln_Succ
)
433 if((hc
->hc_HCIType
== HCITYPE_UHCI
) || (hc
->hc_HCIType
== HCITYPE_OHCI
))
435 if(hc
->hc_complexrouting
)
438 for(cnt
= 0; cnt
< usb20ports
; cnt
++)
440 if(((hc
->hc_portroute
>> (cnt
<<2)) & 0xf) == hc
->hc_FunctionNum
)
442 KPRINTF(10, ("CHC %ld Port %ld assigned to global Port %ld\n", hc
->hc_FunctionNum
, locport
, cnt
));
443 hu
->hu_PortMap11
[cnt
] = hc
;
444 hu
->hu_PortNum11
[cnt
] = locport
;
445 hc
->hc_PortNum20
[locport
] = cnt
;
450 for(cnt
= usb11ports
; cnt
< usb11ports
+ hc
->hc_NumPorts
; cnt
++)
452 hu
->hu_PortMap11
[cnt
] = hc
;
453 hu
->hu_PortNum11
[cnt
] = cnt
- usb11ports
;
454 hc
->hc_PortNum20
[cnt
- usb11ports
] = cnt
;
457 usb11ports
+= hc
->hc_NumPorts
;
459 hc
= (struct PCIController
*) hc
->hc_Node
.ln_Succ
;
461 if((usb11ports
!= usb20ports
) && usb20ports
)
463 KPRINTF(20, ("Warning! #EHCI Ports (%ld) does not match USB 1.1 Ports (%ld)!\n", usb20ports
, usb11ports
));
466 hu
->hu_RootHub11Ports
= usb11ports
;
467 hu
->hu_RootHub20Ports
= usb20ports
;
468 #ifdef AROS_USB30_CODE
469 // FIXME: This is probably wrong as well...
470 hu
->hu_RootHub30Ports
= usb30ports
;
471 hu
->hu_RootHubPorts
= (usb11ports
> usb20ports
) ? ((usb11ports
> usb30ports
) ? usb11ports
: usb30ports
) : ((usb30ports
> usb20ports
) ? usb30ports
: usb20ports
);
473 hu
->hu_RootHubPorts
= (usb11ports
> usb20ports
) ? usb11ports
: usb20ports
;
475 for(cnt
= 0; cnt
< hu
->hu_RootHubPorts
; cnt
++)
477 hu
->hu_EhciOwned
[cnt
] = hu
->hu_PortMap20
[cnt
] ? TRUE
: FALSE
;
480 #ifdef AROS_USB30_CODE
481 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
));
483 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
));
486 hu
->hu_FrameCounter
= 1;
487 hu
->hu_RootHubAddr
= 0;
490 hc
= (struct PCIController
*) hu
->hu_Controllers
.lh_Head
;
491 while(hc
->hc_Node
.ln_Succ
)
493 hc
->hc_Flags
|= HCF_ONLINE
;
494 hc
= (struct PCIController
*) hc
->hc_Node
.ln_Succ
;
497 // create product name of device
498 prodname
= hu
->hu_ProductName
;
500 pciStrcat(prodname
, "PCI ");
501 if(ohcicnt
+ uhcicnt
)
503 if(ohcicnt
+ uhcicnt
>1)
505 prodname
[4] = ohcicnt
+ uhcicnt
+ '0';
509 pciStrcat(prodname
, ohcicnt
? "OHCI" : "UHCI");
512 pciStrcat(prodname
, " +");
514 pciStrcat(prodname
, " USB 1.1");
519 pciStrcat(prodname
, " EHCI USB 2.0");
521 #ifdef AROS_USB30_CODE
526 prodname
[4] = xhcicnt
+ '0';
530 pciStrcat(prodname
, " XHCI USB 3.0");
533 #if 0 // user can use pcitool to check what the chipset is and not guess it from this
534 pciStrcat(prodname
, " Host Controller (");
535 if(ohcicnt
+ uhcicnt
)
537 pciStrcat(prodname
, ohcicnt
? "NEC)" : "VIA, Intel, ALI, etc.)");
539 pciStrcat(prodname
, "Emulated?)");
542 pciStrcat(prodname
, " Host Controller");
544 KPRINTF(10, ("Unit allocated!\n"));
550 /* /// "pciFreeUnit()" */
551 void pciFreeUnit(struct PCIUnit
*hu
)
553 struct PCIDevice
*hd
= hu
->hu_Device
;
554 struct PCIController
*hc
;
556 struct TagItem pciDeactivate
[] =
558 { aHidd_PCIDevice_isIO
, FALSE
},
559 { aHidd_PCIDevice_isMEM
, FALSE
},
560 { aHidd_PCIDevice_isMaster
, FALSE
},
564 KPRINTF(10, ("*** pciFreeUnit(%p) ***\n", hu
));
567 hc
= (struct PCIController
*) hu
->hu_Controllers
.lh_Head
;
568 while(hc
->hc_Node
.ln_Succ
)
570 hc
->hc_Flags
&= ~HCF_ONLINE
;
571 hc
= (struct PCIController
*) hc
->hc_Node
.ln_Succ
;
574 #ifdef AROS_USB30_CODE
577 // doing this in three steps to avoid these damn host errors
582 //FIXME: (x/e/o/u)hciFree routines actually ONLY stops the chip NOT free anything as below...
583 hc
= (struct PCIController
*) hu
->hu_Controllers
.lh_Head
;
584 while(hc
->hc_Node
.ln_Succ
) {
586 HIDD_PCIDriver_FreePCIMem(hc
->hc_PCIDriverObject
, hc
->hc_PCIMem
);
587 hc
->hc_PCIMem
= NULL
;
589 hc
= (struct PCIController
*) hc
->hc_Node
.ln_Succ
;
592 // disable and free board
593 hc
= (struct PCIController
*) hu
->hu_Controllers
.lh_Head
;
594 while(hc
->hc_Node
.ln_Succ
)
596 OOP_SetAttrs(hc
->hc_PCIDeviceObject
, (struct TagItem
*) pciDeactivate
); // deactivate busmaster and IO/Mem
597 if(hc
->hc_PCIIntHandler
.h_Node
.ln_Name
)
599 HIDD_IRQ_RemHandler(hd
->hd_IRQHidd
, &hc
->hc_PCIIntHandler
);
600 hc
->hc_PCIIntHandler
.h_Node
.ln_Name
= NULL
;
604 PCIXObtainBoard(hc
->hc_BoardObject
);
605 hc
->hc_Flags
&= ~HCF_ALLOCATED
;
606 PCIXSetBoardAttr(hc
->hc_BoardObject
, PCIXTAG_OWNER
, 0);
607 PCIXReleaseBoard(hc
->hc_BoardObject
);
609 hc
= (struct PCIController
*) hc
->hc_Node
.ln_Succ
;
614 /* /// "pciExpunge()" */
615 void pciExpunge(struct PCIDevice
*hd
)
617 struct PCIController
*hc
;
620 KPRINTF(10, ("*** pciExpunge(%p) ***\n", hd
));
622 hu
= (struct PCIUnit
*) hd
->hd_Units
.lh_Head
;
623 while(((struct Node
*) hu
)->ln_Succ
)
625 Remove((struct Node
*) hu
);
626 hc
= (struct PCIController
*) hu
->hu_Controllers
.lh_Head
;
627 while(hc
->hc_Node
.ln_Succ
)
629 Remove(&hc
->hc_Node
);
630 FreePooled(hd
->hd_MemPool
, hc
, sizeof(struct PCIController
));
631 hc
= (struct PCIController
*) hu
->hu_Controllers
.lh_Head
;
633 FreePooled(hd
->hd_MemPool
, hu
, sizeof(struct PCIUnit
));
634 hu
= (struct PCIUnit
*) hd
->hd_Units
.lh_Head
;
638 struct OOP_ABDescr attrbases
[] =
640 { (STRPTR
) IID_Hidd
, &hd
->hd_HiddAB
},
641 { (STRPTR
) IID_Hidd_PCIDevice
, &hd
->hd_HiddPCIDeviceAB
},
645 OOP_ReleaseAttrBases(attrbases
);
647 OOP_DisposeObject(hd
->hd_PCIHidd
);
651 OOP_DisposeObject(hd
->hd_IRQHidd
);
656 /* /// "pciGetPhysical()" */
657 APTR
pciGetPhysical(struct PCIController
*hc
, APTR virtaddr
)
659 //struct PCIDevice *hd = hc->hc_Device;
660 return(HIDD_PCIDriver_CPUtoPCI(hc
->hc_PCIDriverObject
, virtaddr
));
665 * Process some AROS-specific arguments.
666 * 'usbpoweron' helps to bring up USB ports on IntelMac,
667 * whose firmware sets them up incorrectly.
669 static int getArguments(struct PCIDevice
*base
)
673 struct ACPIBase
*ACPIBase
;
675 ACPIBase
= OpenResource("acpi.resource");
679 * Use ACPI IDs to identify known machines which need HDF_FORCEPOWER to work.
680 * Currently we know only MacMini.
682 struct ACPI_TABLE_DEF_HEADER
*dsdt
= ACPI_FindSDT(ACPI_MAKE_ID('D','S','D','T'));
686 /* Yes, the last byte in ID is zero */
687 if (strcmp(dsdt
->oem_table_id
, "Macmini") == 0)
689 base
->hd_Flags
= HDF_FORCEPOWER
;
696 BootLoaderBase
= OpenResource("bootloader.resource");
699 struct List
*args
= GetBootInfo(BL_Args
);
705 for (node
= args
->lh_Head
; node
->ln_Succ
; node
= node
->ln_Succ
)
707 if (stricmp(node
->ln_Name
, "forceusbpower") == 0)
709 base
->hd_Flags
= HDF_FORCEPOWER
;
719 ADD2INITLIB(getArguments
, 10)