| /* SPDX-License-Identifier: GPL-2.0 */ | |
| /* | |
| * Intel Core SoC Power Management Controller Header File | |
| * | |
| * Copyright (c) 2025, Intel Corporation. | |
| * All Rights Reserved. | |
| * | |
| */ | |
| #ifndef INTEL_PMC_IPC_H | |
| #define INTEL_PMC_IPC_H | |
| #include <linux/acpi.h> | |
| #include <linux/cleanup.h> | |
| #define IPC_SOC_REGISTER_ACCESS 0xAA | |
| #define IPC_SOC_SUB_CMD_READ 0x00 | |
| #define IPC_SOC_SUB_CMD_WRITE 0x01 | |
| #define PMC_IPCS_PARAM_COUNT 7 | |
| #define VALID_IPC_RESPONSE 5 | |
| struct pmc_ipc_cmd { | |
| u32 cmd; | |
| u32 sub_cmd; | |
| u32 size; | |
| u32 wbuf[4]; | |
| }; | |
| struct pmc_ipc_rbuf { | |
| u32 buf[4]; | |
| }; | |
| /** | |
| * intel_pmc_ipc() - PMC IPC Mailbox accessor | |
| * @ipc_cmd: Prepared input command to send | |
| * @rbuf: Allocated array for returned IPC data | |
| * | |
| * Return: 0 on success. Non-zero on mailbox error | |
| */ | |
| static inline int intel_pmc_ipc(struct pmc_ipc_cmd *ipc_cmd, struct pmc_ipc_rbuf *rbuf) | |
| { | |
| #ifdef CONFIG_ACPI | |
| struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | |
| union acpi_object params[PMC_IPCS_PARAM_COUNT] = { | |
| {.type = ACPI_TYPE_INTEGER,}, | |
| {.type = ACPI_TYPE_INTEGER,}, | |
| {.type = ACPI_TYPE_INTEGER,}, | |
| {.type = ACPI_TYPE_INTEGER,}, | |
| {.type = ACPI_TYPE_INTEGER,}, | |
| {.type = ACPI_TYPE_INTEGER,}, | |
| {.type = ACPI_TYPE_INTEGER,}, | |
| }; | |
| struct acpi_object_list arg_list = { PMC_IPCS_PARAM_COUNT, params }; | |
| int status; | |
| if (!ipc_cmd || !rbuf) | |
| return -EINVAL; | |
| /* | |
| * 0: IPC Command | |
| * 1: IPC Sub Command | |
| * 2: Size | |
| * 3-6: Write Buffer for offset | |
| */ | |
| params[0].integer.value = ipc_cmd->cmd; | |
| params[1].integer.value = ipc_cmd->sub_cmd; | |
| params[2].integer.value = ipc_cmd->size; | |
| params[3].integer.value = ipc_cmd->wbuf[0]; | |
| params[4].integer.value = ipc_cmd->wbuf[1]; | |
| params[5].integer.value = ipc_cmd->wbuf[2]; | |
| params[6].integer.value = ipc_cmd->wbuf[3]; | |
| status = acpi_evaluate_object(NULL, "\\IPCS", &arg_list, &buffer); | |
| if (ACPI_FAILURE(status)) | |
| return -ENODEV; | |
| union acpi_object *obj __free(kfree) = buffer.pointer; | |
| if (obj && obj->type == ACPI_TYPE_PACKAGE && | |
| obj->package.count == VALID_IPC_RESPONSE) { | |
| const union acpi_object *objs = obj->package.elements; | |
| if ((u8)objs[0].integer.value != 0) | |
| return -EINVAL; | |
| rbuf->buf[0] = objs[1].integer.value; | |
| rbuf->buf[1] = objs[2].integer.value; | |
| rbuf->buf[2] = objs[3].integer.value; | |
| rbuf->buf[3] = objs[4].integer.value; | |
| } else { | |
| return -EINVAL; | |
| } | |
| return 0; | |
| #else | |
| return -ENODEV; | |
| #endif /* CONFIG_ACPI */ | |
| } | |
| #endif /* INTEL_PMC_IPC_H */ |