2 Copyright © 2017, The AROS Development Team. All rights reserved.
6 #include <aros/asmcall.h>
7 #include <proto/acpica.h>
8 #include <proto/exec.h>
10 #include <acpica/acnames.h>
11 #include <acpica/accommon.h>
13 #include "kernel_base.h"
14 #include "kernel_debug.h"
15 #include "kernel_globals.h"
16 #include "kernel_intern.h"
22 #define ACPI_MODPRIO_PM 10
24 /************************************************************************************************
25 ACPI PM RELATED FUNCTIONS
26 ************************************************************************************************/
28 const char *ACPI_TABLE_FADT_STR
__attribute__((weak
)) = ACPI_SIG_FADT
;
30 /* Deafult ACPI PM Syscall Handlers */
32 void ACPI_HandleChangePMStateSC(struct ExceptionContext
*regs
)
34 struct KernelBase
*KernelBase
= getKernelBase();
35 struct ACPIData
*acpiData
= KernelBase
->kb_PlatformData
->kb_ACPI
;
44 D(bug("[Kernel:ACPI-PM] %s(0x%02x)\n", __func__
, pmState
));
48 ACPI_GENERIC_ADDRESS tmpReg
;
49 ACPI_TABLE_FADT
*fadt
= (ACPI_TABLE_FADT
*)acpiData
->acpi_fadt
;
51 D(bug("[Kernel:ACPI-PM] %s: STATE 0xFF - Cold Rebooting...\n", __func__
));
52 D(bug("[Kernel:ACPI-PM] %s: FADT Reset Register @ 0x%p, Width %d, Offset %d, MemSpace %d\n", __func__
, (IPTR
)fadt
->ResetRegister
.Address
, fadt
->ResetRegister
.BitWidth
, fadt
->ResetRegister
.BitOffset
, fadt
->ResetRegister
.SpaceId
));
53 D(bug("[Kernel:ACPI-PM] %s: FADT Reset Value = 0x%2x\n", __func__
, fadt
->ResetValue
));
55 AcpiWrite (fadt
->ResetValue
, &fadt
->ResetRegister
);
57 // If we got here the reset didnt happen,
58 // check if we are the known "faulty" implementation.
60 if ((fadt
->Header
.Revision
>= 2) &&
61 (fadt
->ResetRegister
.Address
== 0xCF9))
63 D(bug("[Kernel:ACPI-PM] %s: Failed Reset? Using workaround...\n", __func__
));
64 tmpReg
.Address
= 0x64;
65 tmpReg
.BitWidth
= fadt
->ResetRegister
.BitWidth
;
66 tmpReg
.BitOffset
= fadt
->ResetRegister
.BitOffset
;
67 tmpReg
.SpaceId
= fadt
->ResetRegister
.SpaceId
;
69 AcpiWrite (0xFE, &tmpReg
);
71 bug("[Kernel:ACPI-PM] %s: Reset Failed.\n", __func__
);
73 else if (pmState
== 0)
76 ACPI_OBJECT arg
= { ACPI_TYPE_INTEGER
};
77 ACPI_OBJECT_LIST arg_list
= { 1, &arg
};
79 UINT8 acpiSleepTypeA
, acpiSleepTypeB
;
80 ACPI_TABLE_FADT
*fadt
= (ACPI_TABLE_FADT
*)acpiData
->acpi_fadt
;
82 D(bug("[Kernel:ACPI-PM] %s: STATE 0x00 - Powering Off...\n", __func__
));
84 // we must be in user-mode with interrupts enabled to use AcpiCA
85 krnLeaveSupervisorRing(FLAGS_INTENABLED
);
87 status
= AcpiGetSleepTypeData(ACPI_STATE_S5
,
88 &acpiSleepTypeA
, &acpiSleepTypeB
);
90 if (!ACPI_FAILURE(status
))
92 D(bug("[Kernel:ACPI-PM] %s: %d:%d\n", __func__
, acpiSleepTypeA
, acpiSleepTypeB
));
94 // call Prepare To Sleep
95 arg
.Integer
.Value
= ACPI_STATE_S5
;
96 pathName
= METHOD_PATHNAME__PTS
;
97 D(bug("[Kernel:ACPI-PM] %s: > ACPI %s\n", __func__
, &pathName
[1]));
98 status
= AcpiEvaluateObject(NULL
,
105 pathName
= (char *)" ACPI Sleep Type Data";
108 if (!ACPI_FAILURE(status
) || (status
== AE_NOT_FOUND
))
110 // call System State Transition...
111 // n.b: this is an optional method so we
112 // ignore the return value
113 arg
.Integer
.Value
= ACPI_SST_INDICATOR_OFF
;
114 pathName
= METHOD_PATHNAME__SST
;
115 D(bug("[Kernel:ACPI-PM] %s: > ACPI %s\n", __func__
, &pathName
[1]));
116 status
= AcpiEvaluateObject(NULL
,
123 if (!ACPI_FAILURE(status
))
125 if (fadt
->Flags
& ACPI_FADT_HW_REDUCED
)
127 pathName
= (char *)" ACPI Sleep Control";
128 if (!fadt
->SleepControl
.Address
||
129 !fadt
->SleepStatus
.Address
)
131 status
= AE_NOT_EXIST
;
135 acpiSleepTypeB
= ((acpiSleepTypeA
<< ACPI_X_SLEEP_TYPE_POSITION
) & ACPI_X_SLEEP_TYPE_MASK
);
137 D(bug("[Kernel:ACPI-PM] %s: Sleep Control Register @ 0x%p, Width %d, Offset %d, MemSpace %d\n", __func__
, (IPTR
)fadt
->SleepControl
.Address
, fadt
->SleepControl
.BitWidth
, fadt
->SleepControl
.BitOffset
, fadt
->SleepControl
.SpaceId
));
138 D(bug("[Kernel:ACPI-PM] %s: Sleep Value = 0x%2x\n", __func__
, acpiSleepTypeB
));
140 status
= AcpiWrite ((UINT64
) (acpiSleepTypeB
| ACPI_X_SLEEP_ENABLE
), &fadt
->SleepControl
);
145 ACPI_BIT_REGISTER_INFO
*sleepTypeRegInfo
;
146 ACPI_BIT_REGISTER_INFO
*sleepEnableRegInfo
;
147 UINT32 xpm1aControl
, xpm1bControl
;
149 sleepTypeRegInfo
= AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_TYPE
);
150 sleepEnableRegInfo
= AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_ENABLE
);
152 // Clear ACPI Wake status */
153 pathName
= " ACPI Wake Status";
154 status
= AcpiWriteBitRegister (ACPI_BITREG_WAKE_STATUS
, ACPI_CLEAR_STATUS
);
156 // Read the PM1A control value
157 if (!ACPI_FAILURE (status
))
159 pathName
= " PM1A Control Value";
160 status
= AcpiReadBitRegister (ACPI_REGISTER_PM1_CONTROL
, &xpm1aControl
);
163 // First, write only SLP_TYP to PM1
164 if (!ACPI_FAILURE (status
))
166 pathName
= " PM1 SLP_TYP";
167 xpm1aControl
&= ~(sleepTypeRegInfo
->AccessBitMask
|
168 sleepEnableRegInfo
->AccessBitMask
);
169 xpm1bControl
= xpm1aControl
;
171 xpm1aControl
|= (acpiSleepTypeA
<< sleepTypeRegInfo
->BitPosition
);
172 xpm1bControl
|= (acpiSleepTypeB
<< sleepTypeRegInfo
->BitPosition
);
174 D(bug("[Kernel:ACPI-PM] %s: PM1A = 0xd\n", __func__
, xpm1aControl
));
176 status
= AcpiWrite (xpm1aControl
, &fadt
->XPm1aControlBlock
);
179 if ((!ACPI_FAILURE (status
)) && (fadt
->XPm1bControlBlock
.Address
))
181 status
= AcpiWrite (xpm1bControl
, &fadt
->XPm1bControlBlock
);
184 // Second, write both SLP_TYP and SLP_EN to PM1
185 if (!ACPI_FAILURE (status
))
187 pathName
= " PM1 SLP_TYP|SLP_EN";
188 xpm1aControl
|= sleepEnableRegInfo
->AccessBitMask
;
189 xpm1bControl
|= sleepEnableRegInfo
->AccessBitMask
;
191 D(bug("[Kernel:ACPI-PM] %s: PM1A = 0xd\n", __func__
, xpm1aControl
));
195 status
= AcpiWrite (xpm1aControl
, &fadt
->XPm1aControlBlock
);
198 if ((!ACPI_FAILURE (status
)) && (fadt
->XPm1bControlBlock
.Address
))
200 status
= AcpiWrite (xpm1bControl
, &fadt
->XPm1bControlBlock
);
205 if (ACPI_FAILURE(status
))
207 bug("[Kernel:ACPI-PM] %s: Error evaluating %s: %s\n", __func__
, &pathName
[1], AcpiFormatException(status
));
210 else if (pmState
== 0x90)
212 #if defined(__AROSEXEC_SMP__)
213 UQUAD timeSleep
= RDTSC();
215 struct APICData
*apicData
= KernelBase
->kb_PlatformData
->kb_APIC
;
216 apicid_t cpunum
= core_APIC_GetNumber(apicData
);
219 asm volatile ("pushfq; sti; hlt; popfq");
221 asm volatile ("pushfl; sti; hlt; popfl");
223 #if defined(__AROSEXEC_SMP__)
225 apicData
->cores
[cpunum
].cpu_SleepTime
+= timeWake
- timeSleep
;
230 // We cant handle any other states atm =/
231 D(bug("[Kernel:ACPI-PM] %s: UNHANDLED STATE 0x%02x\n", __func__
, pmState
));
235 struct syscallx86_Handler ACPI_SCChangePMStateHandler
=
238 .ln_Name
= (APTR
)SC_X86CHANGEPMSTATE
240 (APTR
)ACPI_HandleChangePMStateSC
244 * Process the FADT Table
246 AROS_UFH3(static IPTR
, ACPI_hook_Table_PM_Probe
,
247 AROS_UFHA(struct Hook
*, table_hook
, A0
),
248 AROS_UFHA(ACPI_TABLE_FADT
*, fadt
, A2
),
249 AROS_UFHA(struct ACPI_TABLESCAN_DATA
*, tsdata
, A1
))
253 struct PlatformData
*pdata
= tsdata
->acpits_UserData
;
255 D(bug("[Kernel:ACPI-IOAPIC] ## %s()\n", __func__
));
257 // cache the FADT pointer ...
258 pdata
->kb_ACPI
->acpi_fadt
= fadt
;
260 if (fadt
->Flags
& ACPI_FADT_RESET_REGISTER
)
262 // register the ACPI ChangePMState SysCall Handler ..
263 krnAddSysCallHandler(pdata
, &ACPI_SCChangePMStateHandler
, TRUE
, FALSE
);
272 void ACPI_PM_SUPPORT(struct PlatformData
*pdata
)
274 struct ACPI_TABLE_HOOK
*scanHook
;
276 scanHook
= (struct ACPI_TABLE_HOOK
*)AllocMem(sizeof(struct ACPI_TABLE_HOOK
), MEMF_CLEAR
);
279 D(bug("[Kernel:ACPI-PM] %s: Registering PM Table Parser...\n", __func__
));
280 D(bug("[Kernel:ACPI-PM] %s: Table Hook @ 0x%p\n", __func__
, scanHook
));
281 scanHook
->acpith_Node
.ln_Name
= (char *)ACPI_TABLE_FADT_STR
;
282 scanHook
->acpith_Node
.ln_Pri
= ACPI_MODPRIO_PM
;
283 scanHook
->acpith_Hook
.h_Entry
= (APTR
)ACPI_hook_Table_PM_Probe
;
284 scanHook
->acpith_HeaderLen
= 0;
285 scanHook
->acpith_EntryType
= 0;
286 scanHook
->acpith_UserData
= pdata
;
287 Enqueue(&pdata
->kb_ACPI
->acpi_tablehooks
, &scanHook
->acpith_Node
);
289 D(bug("[Kernel:ACPI-PM] %s: Registering done\n", __func__
));
292 DECLARESET(KERNEL__ACPISUPPORT
)
293 ADD2SET(ACPI_PM_SUPPORT
, KERNEL__ACPISUPPORT
, 0)