zephyr/lib/acpi/acpi_shell.c
Najumon Ba f25dfcf88c lib: acpi: added acpi support using acpica lib
Add ACPI support for Zephyr using acpica open source
project. ACPI subsystem use to discover and configure
hardware components, perform power management (e.g. putting
unused hardware components to sleep), auto configuration (e.g.
Plug and Play and hot swapping) etc.

Signed-off-by: Najumon Ba <najumon.ba@intel.com>
2023-06-30 17:53:01 +03:00

282 lines
7.6 KiB
C

/*
* Copyright (c) 2023 Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <stdbool.h>
#include <zephyr/drivers/pcie/pcie.h>
#include <zephyr/acpi/acpi.h>
#include <zephyr/shell/shell.h>
#define MAX_PR_BUFF (4096)
static ACPI_PCI_ROUTING_TABLE irq_prt_table[CONFIG_ACPI_MAX_PRT_ENTRY];
static uint8_t prs_buffer[MAX_PR_BUFF];
static void dump_dev_res(const struct shell *sh, ACPI_RESOURCE *res_lst)
{
ACPI_RESOURCE *res = res_lst;
shell_print(sh, "\n**** ACPI Device Resource Info ****\n");
do {
if (!res->Length) {
shell_error(sh, "Error: zero length found!\n");
break;
}
switch (res->Type) {
case ACPI_RESOURCE_TYPE_IRQ:
shell_print(sh, "\nACPI_RESOURCE_TYPE_IRQ\n\n");
ACPI_RESOURCE_IRQ *irq_res = &res->Data.Irq;
shell_print(sh,
"DescriptorLength: %x, Triggering:%x, Polarity:%x, Shareable:%x,",
irq_res->DescriptorLength, irq_res->Triggering, irq_res->Polarity,
irq_res->Shareable);
shell_print(sh,
"InterruptCount:%d, Interrupts[0]:%x\n", irq_res->InterruptCount,
irq_res->Interrupts[0]);
break;
case ACPI_RESOURCE_TYPE_IO:
ACPI_RESOURCE_IO * io_res = &res->Data.Io;
shell_print(sh, "\n ACPI_RESOURCE_TYPE_IO\n");
shell_print(sh,
"IoDecode: %x, Alignment:%x, AddressLength:%x, Minimum:%x,Maximum:%x\n",
io_res->IoDecode, io_res->Alignment,
io_res->AddressLength, io_res->Minimum,
io_res->Maximum);
break;
case ACPI_RESOURCE_TYPE_DMA:
shell_print(sh, "ACPI_RESOURCE_TYPE_DMA\n\n");
break;
case ACPI_RESOURCE_TYPE_START_DEPENDENT:
shell_print(sh, "ACPI_RESOURCE_TYPE_START_DEPENDENT\n\n");
break;
case ACPI_RESOURCE_TYPE_END_DEPENDENT:
shell_print(sh, "ACPI_RESOURCE_TYPE_END_DEPENDENT\n\n");
break;
case ACPI_RESOURCE_TYPE_FIXED_IO:
shell_print(sh, "ACPI_RESOURCE_TYPE_FIXED_IO\n\n");
break;
case ACPI_RESOURCE_TYPE_VENDOR:
shell_print(sh, "ACPI_RESOURCE_TYPE_VENDOR\n\n");
break;
case ACPI_RESOURCE_TYPE_MEMORY24:
shell_print(sh, "ACPI_RESOURCE_TYPE_MEMORY24\n\n");
break;
case ACPI_RESOURCE_TYPE_MEMORY32:
ACPI_RESOURCE_MEMORY32 * mem_res = &res->Data.Memory32;
shell_print(sh, "\nACPI_RESOURCE_TYPE_MEMORY32\n\n");
shell_print(sh, "Minimum:%x, Maximum:%x\n",
mem_res->Minimum, mem_res->Maximum);
break;
case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
ACPI_RESOURCE_FIXED_MEMORY32 * fix_mem_res = &res->Data.FixedMemory32;
shell_print(sh, "\nACPI_RESOURCE_TYPE_FIXED_MEMORY32\n\n");
shell_print(sh, "Address:%x\n", fix_mem_res->Address);
break;
case ACPI_RESOURCE_TYPE_ADDRESS16:
shell_print(sh, "ACPI_RESOURCE_TYPE_ADDRESS16\n\n");
break;
case ACPI_RESOURCE_TYPE_ADDRESS32:
ACPI_RESOURCE_ADDRESS32 * add_res = &res->Data.Address32;
shell_print(sh, "\nACPI_RESOURCE_TYPE_ADDRESS32\n\n");
shell_print(sh, "Minimum:%x, Maximum:%x\n", add_res->Address.Minimum,
add_res->Address.Maximum);
break;
case ACPI_RESOURCE_TYPE_ADDRESS64:
ACPI_RESOURCE_ADDRESS64 * add_res64 = &res->Data.Address64;
shell_print(sh, "\nACPI_RESOURCE_TYPE_ADDRESS64\n\n");
shell_print(sh,
"Minimum:%llx, Maximum:%llx\n", add_res64->Address.Minimum,
add_res64->Address.Maximum);
break;
case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
shell_print(sh, "ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64\n\n");
break;
case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
shell_print(sh, "ACPI_RESOURCE_TYPE_EXTENDED_IRQ\n\n");
break;
case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
shell_print(sh, "ACPI_RESOURCE_TYPE_GENERIC_REGISTER\n\n");
break;
case ACPI_RESOURCE_TYPE_GPIO:
shell_print(sh, "ACPI_RESOURCE_TYPE_GPIO\n\n");
break;
case ACPI_RESOURCE_TYPE_FIXED_DMA:
shell_print(sh, "ACPI_RESOURCE_TYPE_FIXED_DMA\n\n");
break;
case ACPI_RESOURCE_TYPE_SERIAL_BUS:
shell_print(sh, "ACPI_RESOURCE_TYPE_SERIAL_BUS\n\n");
break;
case ACPI_RESOURCE_TYPE_PIN_FUNCTION:
shell_print(sh, "ACPI_RESOURCE_TYPE_PIN_FUNCTION\n\n");
break;
case ACPI_RESOURCE_TYPE_PIN_CONFIG:
shell_print(sh, "ACPI_RESOURCE_TYPE_PIN_CONFIG\n\n");
break;
case ACPI_RESOURCE_TYPE_PIN_GROUP:
shell_print(sh, "ACPI_RESOURCE_TYPE_PIN_GROUP\n\n");
break;
case ACPI_RESOURCE_TYPE_PIN_GROUP_FUNCTION:
shell_print(sh,
"ACPI_RESOURCE_TYPE_PIN_GROUP_FUNCTION\n\n");
break;
case ACPI_RESOURCE_TYPE_PIN_GROUP_CONFIG:
shell_print(sh, "ACPI_RESOURCE_TYPE_PIN_GROUP_CONFIG\n\n");
break;
default:
}
res = ACPI_NEXT_RESOURCE(res);
} while (res->Type != ACPI_RESOURCE_TYPE_END_TAG);
}
static int dump_dev_crs(const struct shell *sh, size_t argc, char **argv)
{
int status;
ACPI_RESOURCE *res_lst;
if (argc < 2) {
shell_error(sh, "invalid arugment\n");
return -EINVAL;
}
status = acpi_current_resource_get(argv[1], &res_lst);
if (status) {
shell_error(sh, "Error on ACPI _CRS method: %d\n", status);
return status;
}
dump_dev_res(sh, res_lst);
acpi_current_resource_free(res_lst);
return 0;
}
static int dump_dev_prs(const struct shell *sh, size_t argc, char **argv)
{
int status;
ACPI_RESOURCE *res_lst = (ACPI_RESOURCE *)prs_buffer;
if (argc < 2) {
shell_error(sh, "invalid arugment\n");
return -EINVAL;
}
status = acpi_possible_resource_get(argv[1], &res_lst);
if (status) {
shell_error(sh, "Error in on ACPI _PRS method: %d\n", status);
return status;
}
dump_dev_res(sh, res_lst);
return 0;
}
static int dump_prt(const struct shell *sh, size_t argc, char **argv)
{
int status, cnt;
ACPI_PCI_ROUTING_TABLE *prt;
if (argc < 2) {
shell_error(sh, "invalid arugment\n");
return -EINVAL;
}
status = acpi_get_irq_routing_table(argv[1],
irq_prt_table, sizeof(irq_prt_table));
if (status) {
return status;
}
prt = irq_prt_table;
for (cnt = 0; prt->Length; cnt++) {
shell_print(sh, "[%02X] PCI IRQ Routing Table Package\n", cnt);
shell_print(sh,
"DevNum: %lld Pin:%d IRQ: %d\n", (prt->Address >> 16) & 0xFFFF, prt->Pin,
prt->SourceIndex);
prt = ACPI_ADD_PTR(ACPI_PCI_ROUTING_TABLE, prt, prt->Length);
}
return 0;
}
static int enum_dev(const struct shell *sh, size_t argc, char **argv)
{
struct acpi_dev *dev;
if (argc < 2) {
return -EINVAL;
}
dev = acpi_device_get(argv[1], 0);
if (!dev || !dev->res_lst) {
shell_error(sh, "acpi get device failed for HID: %s\n", argv[1]);
return -EIO;
}
shell_print(sh, "\nName:%s\n", dev->path ? dev->path : "Non");
dump_dev_res(sh, dev->res_lst);
return 0;
}
static int read_table(const struct shell *sh, size_t argc, char **argv)
{
int status;
ACPI_TABLE_HEADER *table;
if (argc < 2) {
return -EINVAL;
}
shell_print(sh, "ACPI Table Name: %s\n", argv[1]);
status = acpi_table_get(argv[1], 0, (void **)&table);
if (status) {
shell_error(sh, "ACPI get table failed: %d\n", status);
return status;
}
shell_print(sh, "ACPI Table Info:\n");
shell_print(sh, "Signature: %4s Table Length:%d Revision:%d OemId:%s\n",
table->Signature, table->Length, table->Revision, table->OemId);
return 0;
}
SHELL_STATIC_SUBCMD_SET_CREATE(
sub_acpi,
SHELL_CMD(crs, NULL,
"display device current resource settings (eg:acpi crs _SB.PC00.LPCB.RTC)",
dump_dev_crs),
SHELL_CMD(prs, NULL,
"display device possible resource settings (eg:acpi crs _SB.PC00.LPCB.RTC)",
dump_dev_prs),
SHELL_CMD(prt, NULL, "display PRT details for a given bus (eg:acpi prt _SB.PC00)",
dump_prt),
SHELL_CMD(enum, NULL,
"enumerate device using hid (for enum HPET timer device,eg:acpi enum PNP0103)",
enum_dev),
SHELL_CMD(rd_table, NULL,
"read acpi table (for read mad table, eg:acpi read_table APIC)",
read_table),
SHELL_SUBCMD_SET_END /* Array terminated. */
);
SHELL_CMD_REGISTER(acpi, &sub_acpi, "Demo commands", NULL);