Skip to content

Commit

Permalink
arch/x86_64: add poweroff functionality
Browse files Browse the repository at this point in the history
Signed-off-by: liwenxiang1 <[email protected]>
  • Loading branch information
xianglyc authored and xiaoxiang781216 committed Jan 10, 2025
1 parent a0da84f commit 9a91b11
Show file tree
Hide file tree
Showing 6 changed files with 238 additions and 0 deletions.
1 change: 1 addition & 0 deletions arch/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ config ARCH_X86_64
select ARCH_HAVE_FORK
select ARCH_HAVE_SETJMP
select ARCH_HAVE_PERF_EVENTS
select ARCH_HAVE_POWEROFF
---help---
x86-64 architectures.

Expand Down
46 changes: 46 additions & 0 deletions arch/x86_64/include/acpi.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,14 @@
#define ACPI_LAPIC_FLAGS_ONLINECAP (1 << 1)
#define ACPI_LAPIC_FLAGS_RESERVED (0xfffffffc)

/* ACPI Machine Language */

#define ACPI_AML_NAME_OP (0x08)
#define ACPI_AML_PACKAGE_OP (0x12)
#define ACPI_AML_BYTE_PREFIX (0x0A)
#define ACPI_AML_ROOT_PREFIX '\\'
#define ACPI_AML_S5_NAME "_S5_"

/****************************************************************************
* Public Types
****************************************************************************/
Expand Down Expand Up @@ -182,6 +190,33 @@ begin_packed_struct struct acpi_xsdt_s
uint64_t table_ptrs;
} end_packed_struct;

/* Fixed ACPI Description Table */

begin_packed_struct struct acpi_facp_s
{
struct acpi_sdt_s sdt; /* Standard ACPI table header */
uint32_t firmware_ctrl; /* Physical address of FACS table */
uint32_t dsdt; /* Physical address of DSDT table */
uint8_t reserved; /* Reserved field, usually 0 */
uint8_t pre_pm_profile; /* Preferred power management profile */
uint16_t sci_int; /* System Control Interrupt (SCI) number */
uint32_t smi_cmd; /* SMI command port address */
uint8_t acpi_enable; /* Command to enable ACPI */
uint8_t acpi_disable; /* Command to disable ACPI */
uint8_t s4bios_req; /* Command for S4BIOS (hibernate request) */
uint8_t pstate_cnt; /* Processor performance state control */
uint32_t pm1a_evt_blk; /* Address of PM1a event register block */
uint32_t pm1b_evt_blk; /* Address of PM1b event register block */
uint32_t pm1a_cnt_blk; /* Address of PM1a control register block */
uint32_t pm1b_cnt_blk; /* Address of PM1b control register block */
uint32_t pm2_cnt_blk; /* Address of PM2 control register block */
uint32_t pm_tmr_blk; /* Address of power management timer block */
uint32_t gpe0_blk; /* Address of General Purpose Event 0 register block */
uint32_t gpe1_blk; /* Address of General Purpose Event 1 register block */
uint8_t pm1_evt_len; /* Length of PM1 event register block */
uint8_t pm1_cnt_len; /* Length of PM1 control register block */
} end_packed_struct;

/* Common structure for tables entry */

begin_packed_struct struct acpi_entry_s
Expand Down Expand Up @@ -283,6 +318,17 @@ int acpi_madt_get(int type, int n, struct acpi_entry_s **entry);

int acpi_lapic_get(int cpu, struct acpi_lapic_s **lapic);

/****************************************************************************
* Name: acpi_poweroff_param_get
*
* Description:
* Get Poweroff Parm .
*
****************************************************************************/

int acpi_poweroff_param_get(uint32_t *pm1a_cnt, uint32_t *pm1b_cnt,
uint32_t *regvala, uint32_t *regvalb);

#ifdef CONFIG_ARCH_X86_64_ACPI_DUMP
/****************************************************************************
* Name: acpi_dump
Expand Down
116 changes: 116 additions & 0 deletions arch/x86_64/src/common/x86_64_acpi.c
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,122 @@ int acpi_lapic_get(int cpu, struct acpi_lapic_s **lapic)
(struct acpi_entry_s **)lapic);
}

#ifdef CONFIG_BOARDCTL_POWEROFF
/****************************************************************************
* Name: acpi_poweroff_param_get
*
* Description:
* Get Poweroff Parm .
*
****************************************************************************/

int acpi_poweroff_param_get(uint32_t *pm1a_cnt, uint32_t *pm1b_cnt,
uint32_t *regvala, uint32_t *regvalb)
{
void *tps = NULL;
uint32_t *tp32 = NULL;
uint32_t *end32 = NULL;
struct acpi_sdt_s *sdt = NULL;
struct acpi_facp_s *facp = NULL;
struct acpi_sdt_s *dsdt_h = NULL;
char *s5_addr = NULL;
int dsdt_len = 0;

if (g_acpi.rsdt == 0)
{
acpi_info("rsdt is null");
return -EINVAL;
}

tps = &g_acpi.rsdt->table_ptrs;
tp32 = (uint32_t *)tps;
end32 = (uint32_t *)((uintptr_t)g_acpi.rsdt + g_acpi.rsdt->sdt.length);

while (tp32 < end32)
{
sdt = (struct acpi_sdt_s *)(uintptr_t)*tp32;

if (strncmp(sdt->signature, ACPI_SIG_FACP, 4) == 0)
{
facp = (struct acpi_facp_s *)(uintptr_t)*tp32;
dsdt_h = (struct acpi_sdt_s *)(uintptr_t)facp->dsdt;
acpi_map_region((uintptr_t)dsdt_h, sizeof(struct acpi_sdt_s));

if (strncmp(dsdt_h->signature, ACPI_SIG_DSDT, 4) == 0)
{
/* search the _S5_ package in the DSDT, skip header */

s5_addr = (char *)(uintptr_t)facp->dsdt
+ sizeof(struct acpi_sdt_s);
dsdt_len = dsdt_h->length - sizeof(struct acpi_sdt_s);
acpi_map_region((uintptr_t)s5_addr, dsdt_len);

while (dsdt_len-- > 0)
{
if (strncmp(s5_addr, ACPI_AML_S5_NAME, 4) == 0)
{
break;
}

s5_addr++;
}

if (dsdt_len > 0)
{
/* check for valid AML structure */

if ((*(s5_addr - 1) == ACPI_AML_NAME_OP
|| (*(s5_addr - 2) == ACPI_AML_NAME_OP
&& *(s5_addr - 1) == ACPI_AML_ROOT_PREFIX))
&& *(s5_addr + 4) == ACPI_AML_PACKAGE_OP)
{
s5_addr += strlen(ACPI_AML_S5_NAME) + 1;

/* calculate PkgLength size */

s5_addr += ((*s5_addr & 0xc0) >> 6) + 2;

if (*s5_addr == ACPI_AML_BYTE_PREFIX)
{
/* skip byteprefix */

s5_addr++;
}

*regvala = *(s5_addr) << 10;
s5_addr++;

if (*s5_addr == ACPI_AML_BYTE_PREFIX)
{
/* skip byteprefix */

s5_addr++;
}

*regvalb = *(s5_addr) << 10;
*pm1a_cnt = facp->pm1a_cnt_blk;
*pm1b_cnt = facp->pm1b_cnt_blk;

return OK;
}
else
{
acpi_info("\\_S5 parse error");
break;
}
}
}
}

/* Next table */

tp32 += 1;
}

return -ENOENT;
}
#endif

#ifdef CONFIG_ARCH_X86_64_ACPI_DUMP
/****************************************************************************
* Name: acpi_dump
Expand Down
4 changes: 4 additions & 0 deletions arch/x86_64/src/intel64/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ set(SRCS
intel64_check_capability.c
intel64_cpu.c)

if(CONFIG_BOARDCTL_POWEROFF)
list(APPEND SRCS intel64_systempoweroff.c)
endif()

if(CONFIG_X86_64_UNWINDER_FRAME_POINTER)
list(APPEND SRCS intel64_backtrace_fp.c)
endif()
Expand Down
4 changes: 4 additions & 0 deletions arch/x86_64/src/intel64/Make.defs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ CHIP_CSRCS = intel64_start.c intel64_handlers.c intel64_idle.c intel64_lowsetup
CHIP_CSRCS += intel64_serial.c intel64_rng.c intel64_check_capability.c
CHIP_CSRCS += intel64_cpu.c

ifeq ($(CONFIG_BOARDCTL_POWEROFF),y)
CMN_CSRCS += intel64_systempoweroff.c
endif

ifeq ($(CONFIG_X86_64_UNWINDER_FRAME_POINTER),y)
CMN_CSRCS += intel64_backtrace_fp.c
endif
Expand Down
67 changes: 67 additions & 0 deletions arch/x86_64/src/intel64/intel64_systempoweroff.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/****************************************************************************
* arch/x86_64/src/intel64/intel64_systempoweroff.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/

/****************************************************************************
* Included Files
****************************************************************************/

#include <nuttx/config.h>

#include <nuttx/arch.h>
#include <arch/io.h>

#include <stdint.h>
#include <arch/acpi.h>

/****************************************************************************
* Public Data
****************************************************************************/

/****************************************************************************
* Public Functions
****************************************************************************/

/****************************************************************************
* Name: up_systempoweroff
*
* Description:
* Internal, intel64 poweroff logic.
*
****************************************************************************/

void up_systempoweroff(void)
{
uint32_t pm1a_cnt = 0;
uint32_t pm1b_cnt = 0;
uint32_t regvala = 0;
uint32_t regvalb = 0;

acpi_poweroff_param_get(&pm1a_cnt, &pm1b_cnt, &regvala, &regvalb);

/* Write to Poweroff Control Register */

outw(regvala | 0x2000, pm1a_cnt);
if (pm1b_cnt != 0)
{
outw(regvalb | 0x2000, pm1b_cnt);
}

while (1);
}

0 comments on commit 9a91b11

Please sign in to comment.