revert between 56095 -> 55830 in arch
[AROS.git] / arch / all-pc / kernel / acpi_pm.c
blob3a76f5caaabbcac39383606c9e79d6fd12860be0
1 /*
2 Copyright © 2017-2018, The AROS Development Team. All rights reserved.
3 $Id$
4 */
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"
20 #include "acpi.h"
22 #define D(x)
23 #define DPOFF(x)
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;
40 UBYTE pmState =
41 #if (__WORDSIZE==64)
42 (UBYTE)regs->rbx;
43 #else
44 (UBYTE)regs->ebx;
45 #endif
47 D(bug("[Kernel:ACPI-PM] %s(0x%02x)\n", __func__, pmState));
49 if (pmState == 0xFF)
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)
78 ACPI_STATUS status;
79 ACPI_OBJECT arg = { ACPI_TYPE_INTEGER };
80 ACPI_OBJECT_LIST arg_list = { 1, &arg };
81 char *pathName;
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,
102 pathName,
103 &arg_list,
104 NULL);
106 else
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,
119 pathName,
120 &arg_list,
121 NULL);
122 status = AE_OK;
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;
135 else
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);
145 else
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));
195 CacheClearU();
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();
216 UQUAD timeWake;
217 struct APICData *apicData = KernelBase->kb_PlatformData->kb_APIC;
218 apicid_t cpunum = core_APIC_GetNumber(apicData);
219 #endif
220 #if (__WORDSIZE==64)
221 asm volatile ("pushfq; sti; hlt; popfq");
222 #else
223 asm volatile ("pushfl; sti; hlt; popfl");
224 #endif
225 #if defined(__AROSEXEC_SMP__)
226 timeWake = RDTSC();
227 apicData->cores[cpunum].cpu_SleepTime += timeWake - timeSleep;
228 #endif
229 if (SysBase->SysFlags & SFF_SoftInt)
230 core_Cause(INTB_SOFTINT, 1L << INTB_SOFTINT);
232 else
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))
255 AROS_USERFUNC_INIT
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);
270 return TRUE;
272 AROS_USERFUNC_EXIT
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);
281 if (scanHook)
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)