2 * Copyright (C) 2012, The AROS Development Team
4 * Author: Jason S. McMullan <jason.mcmullan@gmail.com>
6 * Licensed under the AROS PUBLIC LICENSE (APL) Version 1.1
8 #define __ACPICA_NOLIBBASE__
10 #include <aros/debug.h>
12 #include "acpica_intern.h"
14 #include <hardware/efi/config.h>
16 #include <proto/exec.h>
17 #include <proto/timer.h>
18 #include <proto/efi.h>
19 #include <proto/kernel.h>
21 #include <proto/acpica.h>
25 #include <devices/timer.h>
27 #define _COMPONENT ACPI_OS_SERVICES
28 ACPI_MODULE_NAME ("osarosxf")
30 /* FIXME: __aros_getbase_ACPICABase() for internal use should be handled
33 #undef __aros_getbase_ACPICABase
34 struct Library
*__aros_getbase_ACPICABase(void);
36 ACPI_STATUS
AcpiOsInitialize (void)
38 struct ACPICABase
*ACPICABase
= (struct ACPICABase
*)__aros_getbase_ACPICABase();
40 D(bug("[ACPI]AcpiOsInitialize(): ACPICABase=0x%x\n", ACPICABase
));
42 if ((ACPICABase
->ab_TimeMsgPort
= CreateMsgPort())) {
43 if ((ACPICABase
->ab_TimeRequest
= CreateIORequest(ACPICABase
->ab_TimeMsgPort
, sizeof(*ACPICABase
->ab_TimeRequest
)))) {
44 ACPICABase
->ab_TimerBase
= (struct Library
*)ACPICABase
->ab_TimeRequest
->tr_node
.io_Device
;
47 DeleteMsgPort(ACPICABase
->ab_TimeMsgPort
);
53 ACPI_STATUS
AcpiOsTerminate (void)
55 struct ACPICABase
*ACPICABase
= (struct ACPICABase
*)__aros_getbase_ACPICABase();
57 D(bug("[ACPI]AcpiOsTerminate(): ACPICABase=0x%x\n", ACPICABase
));
59 DeleteIORequest(ACPICABase
->ab_TimeRequest
);
60 DeleteMsgPort(ACPICABase
->ab_TimeMsgPort
);
65 ACPI_PHYSICAL_ADDRESS
AcpiOsGetRootPointer(void)
67 struct ACPICABase
*ACPICABase
= (struct ACPICABase
*)__aros_getbase_ACPICABase();
69 D(bug("[ACPI]AcpiOsGetRootPointer(): ACPICABase=0x%x\n", ACPICABase
));
71 if (ACPICABase
->ab_RootPointer
== 0) {
72 struct Library
*EFIBase
= OpenResource("efi.resource");
74 const uuid_t acpi_20_guid
= ACPI_20_TABLE_GUID
;
75 const uuid_t acpi_10_guid
= ACPI_TABLE_GUID
;
76 ACPICABase
->ab_RootPointer
= (ACPI_PHYSICAL_ADDRESS
)EFI_FindConfigTable(&acpi_20_guid
);
78 /* No ACPI 2.0 table? */
79 if (ACPICABase
->ab_RootPointer
== 0) {
80 ACPICABase
->ab_RootPointer
= (ACPI_PHYSICAL_ADDRESS
)EFI_FindConfigTable(&acpi_10_guid
);
85 /* Nope, no EFI available... Scan the ROM area
87 if (ACPICABase
->ab_RootPointer
== 0) {
88 AcpiFindRootPointer(&ACPICABase
->ab_RootPointer
);
91 return ACPICABase
->ab_RootPointer
;
94 ACPI_STATUS
AcpiOsPredefinedOverride(const ACPI_PREDEFINED_NAMES
*PredefinedObject
, ACPI_STRING
*NewValue
)
100 ACPI_STATUS
AcpiOsTableOverride(ACPI_TABLE_HEADER
*ExistingTable
, ACPI_TABLE_HEADER
**NewTable
)
106 ACPI_STATUS
AcpiOsPhysicalTableOverride(ACPI_TABLE_HEADER
*ExistingTable
, ACPI_PHYSICAL_ADDRESS
*NewAddress
, UINT32
*NewTableLength
)
112 void *AcpiOsMapMemory (ACPI_PHYSICAL_ADDRESS PhysicalAddress
, ACPI_SIZE Length
)
114 return (void *)PhysicalAddress
;
117 void AcpiOsUnmapMemory(void *LogicalAddress
, ACPI_SIZE Length
)
122 ACPI_STATUS
AcpiOsGetPhysicalAddress(void *LogicalAddress
, ACPI_PHYSICAL_ADDRESS
*PhysicalAddress
)
124 *PhysicalAddress
= (IPTR
)LogicalAddress
;
128 void *AcpiOsAllocate(ACPI_SIZE Size
)
130 return AllocVec(Size
, MEMF_PUBLIC
);
133 void AcpiOsFree(void *Memory
)
138 BOOLEAN
AcpiOsReadable(void *Memory
, ACPI_SIZE Length
)
143 BOOLEAN
AcpiOsWritable(void *Memory
, ACPI_SIZE Length
)
145 /* First 4K page is not writable on any AROS architecture */
146 return ((IPTR
)Memory
< 4096) ? FALSE
: TRUE
;
149 ACPI_THREAD_ID
AcpiOsGetThreadId(void)
153 tid
= (ACPI_THREAD_ID
)(ACPI_PHYSICAL_ADDRESS
)FindTask(NULL
);
155 /* If we are running during kernel bring-up, return
164 ACPI_STATUS
AcpiOsExecute(ACPI_EXECUTE_TYPE Type
, ACPI_OSD_EXEC_CALLBACK Function
, void *Context
)
166 /* TODO: Create a thread */
167 bug("FIXME: %s\n", __func__
);
168 return AE_NOT_IMPLEMENTED
;
171 void AcpiOsSleep(UINT64 Milliseconds
)
173 struct ACPICABase
*ACPICABase
= (struct ACPICABase
*)__aros_getbase_ACPICABase();
175 D(bug("[ACPI]AcpiOsSleep(): ACPICABase=0x%x\n", ACPICABase
));
177 ACPICABase
->ab_TimeRequest
->tr_node
.io_Command
= TR_ADDREQUEST
;
178 ACPICABase
->ab_TimeRequest
->tr_time
.tv_secs
= Milliseconds
/ 1000;
179 ACPICABase
->ab_TimeRequest
->tr_time
.tv_micro
= (Milliseconds
% 1000) * 1000;
180 DoIO((struct IORequest
*)ACPICABase
->ab_TimeRequest
);
183 void AcpiOsStall(UINT32 Microseconds
)
185 struct ACPICABase
*ACPICABase
= (struct ACPICABase
*)__aros_getbase_ACPICABase();
187 D(bug("[ACPI]AcpiOsStall(): ACPICABase=0x%x\n", ACPICABase
));
189 ACPICABase
->ab_TimeRequest
->tr_node
.io_Command
= TR_ADDREQUEST
;
190 ACPICABase
->ab_TimeRequest
->tr_time
.tv_secs
= Microseconds
/ 1000000;
191 ACPICABase
->ab_TimeRequest
->tr_time
.tv_micro
= (Microseconds
% 1000000);
192 DoIO((struct IORequest
*)ACPICABase
->ab_TimeRequest
);
195 void AcpiOsWaitEventsComplete(void)
197 bug("FIXME: %s\n", __func__
);
200 ACPI_STATUS
AcpiOsCreateSemaphore(UINT32 MaxUnits
, UINT32 InitialUnits
, ACPI_SEMAPHORE
*OutHandle
)
202 struct SignalSemaphore
*Handle
;
204 Handle
= ACPI_ALLOCATE(sizeof(*Handle
));
206 InitSemaphore(Handle
);
213 ACPI_STATUS
AcpiOsDeleteSemaphore(ACPI_SEMAPHORE Handle
)
219 ACPI_STATUS
AcpiOsWaitSemaphore(ACPI_SEMAPHORE Handle
, UINT32 Units
, UINT16 Timeout
)
221 if (Timeout
!= 0xffff)
222 bug("FIXME: %s, Timeout=0x%04x\n", __func__
, Timeout
);
225 if (AttemptSemaphore(Handle
)) {
233 ObtainSemaphore(Handle
);
238 ACPI_STATUS
AcpiOsSignalSemaphore(ACPI_SEMAPHORE Handle
, UINT32 Units
)
240 ReleaseSemaphore(Handle
);
244 /* FIXME: Use SpinLock primitives once they exist in kernel.resource! */
247 volatile ULONG sl_Lock
;
250 static inline struct SpinLock
*CreateSpin(VOID
)
252 return AllocVec(sizeof(struct SpinLock
), MEMF_ANY
| MEMF_CLEAR
);
255 static inline void DeleteSpin(struct SpinLock
*sl
)
258 while (sl
->sl_Lock
> 0) {
267 static inline VOID
LockSpin(struct SpinLock
*sl
)
270 struct Task
*task
= FindTask(NULL
);
272 pri
= task
->tc_Node
.ln_Pri
;
277 if (sl
->sl_Lock
== 0) {
279 if (pri_lower
!= pri
)
280 SetTaskPri(task
, pri
);
284 if (pri_lower
> MIN_PRI
)
286 SetTaskPri(task
, pri_lower
);
290 static inline void UnlockSpin(struct SpinLock
*sl
)
296 ACPI_STATUS
AcpiOsCreateLock(ACPI_SPINLOCK
*OutHandle
)
298 *OutHandle
= CreateSpin();
300 return (*OutHandle
== NULL
) ? AE_NO_MEMORY
: AE_OK
;
303 void AcpiOsDeleteLock(ACPI_SPINLOCK Handle
)
308 ACPI_CPU_FLAGS
AcpiOsAcquireLock(ACPI_SPINLOCK Handle
)
314 void AcpiOsReleaseLock(ACPI_SPINLOCK Handle
, ACPI_CPU_FLAGS Flags
)
321 struct Interrupt ai_Interrupt
;
322 ACPI_OSD_HANDLER ai_Handler
;
326 static AROS_INTH1(AcpiOsIntServer
, struct AcpiOsInt
*, ai
)
332 ret
= ai
->ai_Handler(ai
->ai_Context
);
334 return (ret
== ACPI_INTERRUPT_HANDLED
) ? TRUE
: FALSE
;
339 ACPI_STATUS
AcpiOsInstallInterruptHandler(UINT32 InterruptLevel
, ACPI_OSD_HANDLER Handler
, void *Context
)
341 struct AcpiOsInt
*ai
;
343 if ((ai
= ACPI_ALLOCATE(sizeof(*ai
)))) {
344 ai
->ai_Interrupt
.is_Node
.ln_Name
= "ACPI";
345 ai
->ai_Interrupt
.is_Code
= (APTR
)AcpiOsIntServer
;
346 ai
->ai_Interrupt
.is_Data
= (APTR
)ai
;
347 ai
->ai_Handler
= Handler
;
348 ai
->ai_Context
= Context
;
349 AddIntServer(INTB_KERNEL
+ InterruptLevel
, &ai
->ai_Interrupt
);
356 ACPI_STATUS
AcpiOsRemoveInterruptHandler(UINT32 InterruptNumber
, ACPI_OSD_HANDLER Handler
)
358 bug("FIXME: %s (InterruptLevel=%d)\n", __func__
, InterruptNumber
);
359 return AE_NOT_IMPLEMENTED
;
362 ACPI_STATUS
AcpiOsReadMemory(ACPI_PHYSICAL_ADDRESS Address
, UINT64
*Value
, UINT32 Width
)
365 case 8: *Value
= *(UINT8
*)Address
; break;
366 case 16: *Value
= *(UINT16
*)Address
; break;
367 case 32: *Value
= *(UINT32
*)Address
; break;
368 case 64: *Value
= *(UINT64
*)Address
; break;
369 default: *Value
= ~0; break;
375 ACPI_STATUS
AcpiOsWriteMemory(ACPI_PHYSICAL_ADDRESS Address
, UINT64 Value
, UINT32 Width
)
378 case 8: *(UINT8
*)Address
= (UINT8
)Value
; break;
379 case 16: *(UINT16
*)Address
= (UINT16
)Value
; break;
380 case 32: *(UINT32
*)Address
= (UINT32
)Value
; break;
381 case 64: *(UINT64
*)Address
= (UINT64
)Value
; break;
388 ACPI_STATUS
AcpiOsReadPort(ACPI_IO_ADDRESS Address
, UINT32
*Value
, UINT32 Width
)
391 case 8: *Value
= inb(Address
); break;
392 case 16: *Value
= inw(Address
); break;
393 case 32: *Value
= inl(Address
); break;
394 default: *Value
= ~0; break;
399 ACPI_STATUS
AcpiOsWritePort(ACPI_IO_ADDRESS Address
, UINT32 Value
, UINT32 Width
)
402 case 8: outb(Value
,Address
); break;
403 case 16: outw(Value
,Address
); break;
404 case 32: outl(Value
,Address
); break;
410 static UINT8
*find_pci(struct ACPICABase
*ACPICABase
, ACPI_PCI_ID
*PciId
)
414 for (i
= 0; i
< ACPICABase
->ab_PCIs
; i
++) {
415 ACPI_MCFG_ALLOCATION
*ma
= &ACPICABase
->ab_PCI
[i
];
416 if (PciId
->Segment
!= ma
->PciSegment
)
418 if (PciId
->Bus
< ma
->StartBusNumber
||
419 PciId
->Bus
> ma
->EndBusNumber
)
422 return (UINT8
*)(ACPI_PHYSICAL_ADDRESS
)ma
->Address
;
428 ACPI_STATUS
AcpiOsReadPciConfiguration(ACPI_PCI_ID
*PciId
, UINT32 Register
, UINT64
*Value
, UINT32 Width
)
430 struct ACPICABase
*ACPICABase
= (struct ACPICABase
*)__aros_getbase_ACPICABase();
433 D(bug("[ACPI]AcpiOsReadPciConfiguration(): ACPICABase=0x%x\n", ACPICABase
));
435 if ((ecam
= find_pci(ACPICABase
, PciId
))) {
436 UINT32 offset
= (PciId
->Bus
<< 20) | (PciId
->Device
<< 15) | (PciId
->Function
<< 12) | Register
;
438 case 8: *Value
= *(volatile UINT8
*)(ecam
+ offset
); break;
439 case 16: *Value
= *(volatile UINT16
*)(ecam
+ offset
); break;
440 case 32: *Value
= *(volatile UINT32
*)(ecam
+ offset
); break;
441 case 64: *Value
= *(volatile UINT64
*)(ecam
+ offset
); break;
442 default: *Value
= 0; break;
451 ACPI_STATUS
AcpiOsWritePciConfiguration(ACPI_PCI_ID
*PciId
, UINT32 Register
, UINT64 Value
, UINT32 Width
)
453 struct ACPICABase
*ACPICABase
= (struct ACPICABase
*)__aros_getbase_ACPICABase();
456 D(bug("[ACPI]AcpiOsWritePciConfiguration(): ACPICABase=0x%x\n", ACPICABase
));
458 if ((ecam
= find_pci(ACPICABase
, PciId
))) {
459 UINT32 offset
= (PciId
->Bus
<< 20) | (PciId
->Device
<< 15) | (PciId
->Function
<< 12) | Register
;
461 case 8: *(volatile UINT8
*)(ecam
+ offset
) = Value
& 0xff; break;
462 case 16: *(volatile UINT16
*)(ecam
+ offset
) = Value
& 0xffff; break;
463 case 32: *(volatile UINT32
*)(ecam
+ offset
) = Value
& 0xffffffff; break;
464 case 64: *(volatile UINT64
*)(ecam
+ offset
) = Value
; break;
474 void AcpiOsPrintf(const char *Fmt
, ...)
478 va_start (Args
, Fmt
);
479 AcpiOsVprintf (Fmt
, Args
);
483 void AcpiOsVprintf(const char *Format
, va_list Args
)
485 vkprintf(Format
, Args
);
488 /* Return current time in 100ns units
490 UINT64
AcpiOsGetTimer(void)
492 struct ACPICABase
*ACPICABase
= (struct ACPICABase
*)__aros_getbase_ACPICABase();
493 struct Library
*TimerBase
;
496 D(bug("[ACPI]AcpiOsGetTimer(): ACPICABase=0x%x\n", ACPICABase
));
498 TimerBase
= ACPICABase
->ab_TimerBase
;
502 return (tv
.tv_secs
*1000000ULL + tv
.tv_micro
)*10;
505 ACPI_STATUS
AcpiOsSignal(UINT32 Function
, void *Info
)
507 bug("FIXME: %s\n", __func__
);
508 return AE_NOT_IMPLEMENTED
;
511 ACPI_STATUS
AcpiOsGetLine(char *Buffer
, UINT32 BufferLength
, UINT32
*BytesRead
)
513 bug("FIXME: %s\n", __func__
);
514 return AE_NOT_IMPLEMENTED
;
520 LONG
AcpiScanTables(const char *Signature
, const struct Hook
*Hook
, APTR UserData
)
525 for (count
= 0, i
= 1; ; i
++) {
527 ACPI_TABLE_HEADER
*hdr
;
530 err
= AcpiGetTable((ACPI_STRING
)Signature
, i
, &hdr
);
535 ok
= CALLHOOKPKT((struct Hook
*)Hook
, hdr
, UserData
);
546 #define ACPI_MAX_INIT_TABLES 64
548 static int ACPICA_InitTask(struct ACPICABase
*ACPICABase
)
551 const UINT8 initlevel
= ACPI_FULL_INITIALIZATION
;
553 err
= AcpiInitializeSubsystem();
554 if (ACPI_FAILURE(err
)) {
555 D(bug("%s: AcpiInitializeSubsystem() = %d\n", __func__
, err
));
559 err
= AcpiLoadTables();
560 if (ACPI_FAILURE(err
)) {
561 D(bug("%s: AcpiLoadTables() = %d\n", __func__
, err
));
565 err
= AcpiEnableSubsystem(initlevel
);
566 if (ACPI_FAILURE(err
)) {
567 D(bug("%s: AcpiEnableSubsystem(0x%02x) = %d\n", __func__
, initlevel
, err
));
571 err
= AcpiInitializeObjects(initlevel
);
572 if (ACPI_FAILURE(err
)) {
573 D(bug("%s: AcpiInitializeObjects(0x%02x) = %d\n", __func__
, initlevel
, err
));
577 D(bug("[ACPI] Full initialization complete\n"));
582 int ACPICA_init(struct ACPICABase
*ACPICABase
)
584 ACPI_TABLE_MCFG
*mcfg
;
586 struct Library
*KernelBase
;
588 D(bug("[ACPI]ACPICA_init(ACPICABase=0x%x)\n", ACPICABase
));
590 if ((KernelBase
= OpenResource("kernel.resource"))) {
591 struct TagItem
*cmdline
= LibFindTagItem(KRN_CmdLine
, KrnGetBootInfo());
593 if (cmdline
&& strcasestr((char *)cmdline
->ti_Data
, "noacpi")) {
594 D(bug("[ACPI] Disabled from command line\n"));
601 ACPICABase
->ab_RootPointer
= 0;
603 err
= AcpiInitializeTables(NULL
, ACPI_MAX_INIT_TABLES
, TRUE
);
604 if (ACPI_FAILURE(err
)) {
605 D(bug("%s: AcpiInitializeTables() = %d\n", __func__
, err
));
609 if (AcpiGetTable("MCFG", 1, (ACPI_TABLE_HEADER
**)&mcfg
) == AE_OK
) {
610 ACPICABase
->ab_PCIs
= (mcfg
->Header
.Length
- sizeof(*mcfg
)) / sizeof(ACPI_MCFG_ALLOCATION
);
611 ACPICABase
->ab_PCI
= (ACPI_MCFG_ALLOCATION
*)&mcfg
[1];
613 ACPICABase
->ab_PCIs
= 0;
616 /* Everything else is in the late initialization thread,
617 * which will start at the highest priority once mulitasking begins
619 if (NewCreateTask(TASKTAG_PC
, ACPICA_InitTask
, TASKTAG_NAME
, "ACPICA_InitTask", TASKTAG_PRI
, 127, TASKTAG_ARG1
, ACPICABase
, TAG_DONE
) == NULL
) {
626 ADD2INITLIB(ACPICA_init
,0)
628 int ACPICA_expunge(struct ACPICABase
*ACPICABase
)
634 ADD2EXPUNGELIB(ACPICA_expunge
, 0)