2 Copyright © 2017-2018, The AROS Development Team. All rights reserved.
6 #include <aros/asmcall.h>
7 #include <hardware/intbits.h>
8 #include <proto/acpica.h>
9 #include <proto/exec.h>
11 #include <acpica/acnames.h>
12 #include <acpica/accommon.h>
14 #include "kernel_base.h"
15 #include "kernel_debug.h"
16 #include "kernel_globals.h"
17 #include "kernel_intern.h"
18 #include "kernel_intr.h"
25 #define ACPI_MODPRIO_PM 10
27 /************************************************************************************************
28 ACPI PM RELATED FUNCTIONS
29 ************************************************************************************************/
31 const char *ACPI_TABLE_FADT_STR
__attribute__((weak
)) = ACPI_SIG_FADT
;
33 /* Deafult ACPI PM Syscall Handlers */
35 void ACPI_HandleChangePMStateSC(struct ExceptionContext
*regs
)
37 struct KernelBase
*KernelBase
= getKernelBase();
38 struct ACPIData
*acpiData
= KernelBase
->kb_PlatformData
->kb_ACPI
;
47 D(bug("[Kernel:ACPI-PM] %s(0x%02x)\n", __func__
, pmState
));
51 ACPI_GENERIC_ADDRESS tmpReg
;
52 ACPI_TABLE_FADT
*fadt
= (ACPI_TABLE_FADT
*)acpiData
->acpi_fadt
;
54 D(bug("[Kernel:ACPI-PM] %s: STATE 0xFF - Cold Rebooting...\n", __func__
));
55 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
));
56 D(bug("[Kernel:ACPI-PM] %s: FADT Reset Value = 0x%2x\n", __func__
, fadt
->ResetValue
));
58 AcpiWrite (fadt
->ResetValue
, &fadt
->ResetRegister
);
60 // If we got here the reset didn't happen,
61 // check if we are the known "faulty" implementation.
63 if ((fadt
->Header
.Revision
>= 2) &&
64 (fadt
->ResetRegister
.Address
== 0xCF9))
66 D(bug("[Kernel:ACPI-PM] %s: Failed Reset? Using workaround...\n", __func__
));
67 tmpReg
.Address
= 0x64;
68 tmpReg
.BitWidth
= fadt
->ResetRegister
.BitWidth
;
69 tmpReg
.BitOffset
= fadt
->ResetRegister
.BitOffset
;
70 tmpReg
.SpaceId
= fadt
->ResetRegister
.SpaceId
;
72 AcpiWrite (0xFE, &tmpReg
);
74 bug("[Kernel:ACPI-PM] %s: Reset Failed.\n", __func__
);
76 else if (pmState
== 0)
79 ACPI_OBJECT arg
= { ACPI_TYPE_INTEGER
};
80 ACPI_OBJECT_LIST arg_list
= { 1, &arg
};
82 UINT8 acpiSleepTypeA
, acpiSleepTypeB
;
83 ACPI_TABLE_FADT
*fadt
= (ACPI_TABLE_FADT
*)acpiData
->acpi_fadt
;
85 DPOFF(bug("[Kernel:ACPI-PM] %s: STATE 0x00 - Powering Off...\n", __func__
));
87 // we must be in user-mode with interrupts enabled to use AcpiCA
88 krnLeaveSupervisorRing(FLAGS_INTENABLED
);
90 status
= AcpiGetSleepTypeData(ACPI_STATE_S5
,
91 &acpiSleepTypeA
, &acpiSleepTypeB
);
93 if (!ACPI_FAILURE(status
))
95 DPOFF(bug("[Kernel:ACPI-PM] %s: %d:%d\n", __func__
, acpiSleepTypeA
, acpiSleepTypeB
));
97 // call Prepare To Sleep
98 arg
.Integer
.Value
= ACPI_STATE_S5
;
99 pathName
= METHOD_PATHNAME__PTS
;
100 DPOFF(bug("[Kernel:ACPI-PM] %s: > ACPI %s\n", __func__
, &pathName
[1]));
101 status
= AcpiEvaluateObject(NULL
,
108 pathName
= (char *)" ACPI Sleep Type Data";
111 if (!ACPI_FAILURE(status
) || (status
== AE_NOT_FOUND
))
113 // call System State Transition...
114 // N.B. this is an optional method so we ignore the return value
115 arg
.Integer
.Value
= ACPI_SST_INDICATOR_OFF
;
116 pathName
= METHOD_PATHNAME__SST
;
117 DPOFF(bug("[Kernel:ACPI-PM] %s: > ACPI %s\n", __func__
, &pathName
[1]));
118 status
= AcpiEvaluateObject(NULL
,
125 if (!ACPI_FAILURE(status
))
127 if (fadt
->Flags
& ACPI_FADT_HW_REDUCED
)
129 pathName
= (char *)" ACPI Sleep Control";
130 if (!fadt
->SleepControl
.Address
||
131 !fadt
->SleepStatus
.Address
)
133 status
= AE_NOT_EXIST
;
137 acpiSleepTypeB
= ((acpiSleepTypeA
<< ACPI_X_SLEEP_TYPE_POSITION
) & ACPI_X_SLEEP_TYPE_MASK
);
139 DPOFF(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
));
140 DPOFF(bug("[Kernel:ACPI-PM] %s: Sleep Value = 0x%2x\n", __func__
, acpiSleepTypeB
));
142 status
= AcpiWrite ((UINT64
) (acpiSleepTypeB
| ACPI_X_SLEEP_ENABLE
), &fadt
->SleepControl
);
147 ACPI_BIT_REGISTER_INFO
*sleepTypeRegInfo
;
148 ACPI_BIT_REGISTER_INFO
*sleepEnableRegInfo
;
149 UINT32 xpm1aControl
, xpm1bControl
;
151 sleepTypeRegInfo
= AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_TYPE
);
152 sleepEnableRegInfo
= AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_ENABLE
);
154 // Clear ACPI Wake status
155 pathName
= " ACPI Wake Status";
156 status
= AcpiWriteBitRegister (ACPI_BITREG_WAKE_STATUS
, ACPI_CLEAR_STATUS
);
158 // Read the PM1A control value
159 if (!ACPI_FAILURE (status
))
161 pathName
= " PM1A Control Value";
162 status
= AcpiReadBitRegister (ACPI_REGISTER_PM1_CONTROL
, &xpm1aControl
);
165 // First, write only SLP_TYP to PM1
166 if (!ACPI_FAILURE (status
))
168 pathName
= " PM1 SLP_TYP";
169 xpm1aControl
&= ~(sleepTypeRegInfo
->AccessBitMask
|
170 sleepEnableRegInfo
->AccessBitMask
);
171 xpm1bControl
= xpm1aControl
;
173 xpm1aControl
|= (acpiSleepTypeA
<< sleepTypeRegInfo
->BitPosition
);
174 xpm1bControl
|= (acpiSleepTypeB
<< sleepTypeRegInfo
->BitPosition
);
176 DPOFF(bug("[Kernel:ACPI-PM] %s: PM1A = 0xd\n", __func__
, xpm1aControl
));
178 status
= AcpiWrite (xpm1aControl
, &fadt
->XPm1aControlBlock
);
181 if ((!ACPI_FAILURE (status
)) && (fadt
->XPm1bControlBlock
.Address
))
183 status
= AcpiWrite (xpm1bControl
, &fadt
->XPm1bControlBlock
);
186 // Second, write both SLP_TYP and SLP_EN to PM1
187 if (!ACPI_FAILURE (status
))
189 pathName
= " PM1 SLP_TYP|SLP_EN";
190 xpm1aControl
|= sleepEnableRegInfo
->AccessBitMask
;
191 xpm1bControl
|= sleepEnableRegInfo
->AccessBitMask
;
193 DPOFF(bug("[Kernel:ACPI-PM] %s: PM1A = 0xd\n", __func__
, xpm1aControl
));
197 status
= AcpiWrite (xpm1aControl
, &fadt
->XPm1aControlBlock
);
200 if ((!ACPI_FAILURE (status
)) && (fadt
->XPm1bControlBlock
.Address
))
202 status
= AcpiWrite (xpm1bControl
, &fadt
->XPm1bControlBlock
);
207 if (ACPI_FAILURE(status
))
209 bug("[Kernel:ACPI-PM] %s: Error evaluating %s: %s\n", __func__
, &pathName
[1], AcpiFormatException(status
));
212 else if (pmState
== 0x90)
214 #if defined(__AROSEXEC_SMP__)
215 UQUAD timeSleep
= RDTSC();
217 struct APICData
*apicData
= KernelBase
->kb_PlatformData
->kb_APIC
;
218 apicid_t cpunum
= core_APIC_GetNumber(apicData
);
221 asm volatile ("pushfq; sti; hlt; popfq");
223 asm volatile ("pushfl; sti; hlt; popfl");
225 #if defined(__AROSEXEC_SMP__)
227 apicData
->cores
[cpunum
].cpu_SleepTime
+= timeWake
- timeSleep
;
229 if (SysBase
->SysFlags
& SFF_SoftInt
)
230 core_Cause(INTB_SOFTINT
, 1L << INTB_SOFTINT
);
234 // We cant handle any other states atm =/
235 bug("[Kernel:ACPI-PM] %s: UNHANDLED STATE 0x%02x\n", __func__
, pmState
);
239 struct syscallx86_Handler ACPI_SCChangePMStateHandler
=
242 .ln_Name
= (APTR
)SC_X86CHANGEPMSTATE
244 (APTR
)ACPI_HandleChangePMStateSC
248 * Process the FADT Table
250 AROS_UFH3(static IPTR
, ACPI_hook_Table_PM_Probe
,
251 AROS_UFHA(struct Hook
*, table_hook
, A0
),
252 AROS_UFHA(ACPI_TABLE_FADT
*, fadt
, A2
),
253 AROS_UFHA(struct ACPI_TABLESCAN_DATA
*, tsdata
, A1
))
257 struct PlatformData
*pdata
= tsdata
->acpits_UserData
;
259 D(bug("[Kernel:ACPI-IOAPIC] ## %s()\n", __func__
));
261 // cache the FADT pointer ...
262 pdata
->kb_ACPI
->acpi_fadt
= fadt
;
264 if (fadt
->Flags
& ACPI_FADT_RESET_REGISTER
)
266 // register the ACPI ChangePMState SysCall Handler ..
267 krnAddSysCallHandler(pdata
, &ACPI_SCChangePMStateHandler
, TRUE
, FALSE
);
276 void ACPI_PM_SUPPORT(struct PlatformData
*pdata
)
278 struct ACPI_TABLE_HOOK
*scanHook
;
280 scanHook
= (struct ACPI_TABLE_HOOK
*)AllocMem(sizeof(struct ACPI_TABLE_HOOK
), MEMF_CLEAR
);
283 D(bug("[Kernel:ACPI-PM] %s: Registering PM Table Parser...\n", __func__
));
284 D(bug("[Kernel:ACPI-PM] %s: Table Hook @ 0x%p\n", __func__
, scanHook
));
285 scanHook
->acpith_Node
.ln_Name
= (char *)ACPI_TABLE_FADT_STR
;
286 scanHook
->acpith_Node
.ln_Pri
= ACPI_MODPRIO_PM
;
287 scanHook
->acpith_Hook
.h_Entry
= (APTR
)ACPI_hook_Table_PM_Probe
;
288 scanHook
->acpith_HeaderLen
= 0;
289 scanHook
->acpith_EntryType
= 0;
290 scanHook
->acpith_UserData
= pdata
;
291 Enqueue(&pdata
->kb_ACPI
->acpi_tablehooks
, &scanHook
->acpith_Node
);
293 D(bug("[Kernel:ACPI-PM] %s: Registering done\n", __func__
));
296 DECLARESET(KERNEL__ACPISUPPORT
)
297 ADD2SET(ACPI_PM_SUPPORT
, KERNEL__ACPISUPPORT
, 0)