arch: x86: add IPC mailbox accessor function and add SoC register access
authorDavid E. Box <david.e.box@linux.intel.com>
Thu, 27 Feb 2025 12:15:19 +0000 (20:15 +0800)
committerJakub Kicinski <kuba@kernel.org>
Thu, 6 Mar 2025 03:02:47 +0000 (19:02 -0800)
- Exports intel_pmc_ipc() for host access to the PMC IPC mailbox
- Enables the host to access specific SoC registers through the PMC
firmware using IPC commands. This access method is necessary for
registers that are not available through direct Memory-Mapped I/O (MMIO),
which is used for other accessible parts of the PMC.

Signed-off-by: David E. Box <david.e.box@linux.intel.com>
Signed-off-by: Chao Qin <chao.qin@intel.com>
Signed-off-by: Choong Yong Liang <yong.liang.choong@linux.intel.com>
Acked-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Link: https://patch.msgid.link/20250227121522.1802832-4-yong.liang.choong@linux.intel.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
MAINTAINERS
include/linux/platform_data/x86/intel_pmc_ipc.h [new file with mode: 0644]

index 7078199fcebf2d22bc722f0f7654e98f7b94fa6c..2eccaff95ca2fe98437d839644927c18f879b145 100644 (file)
@@ -11862,6 +11862,7 @@ L:      platform-driver-x86@vger.kernel.org
 S:     Maintained
 F:     Documentation/ABI/testing/sysfs-platform-intel-pmc
 F:     drivers/platform/x86/intel/pmc/
+F:     linux/platform_data/x86/intel_pmc_ipc.h
 
 INTEL PMIC GPIO DRIVERS
 M:     Andy Shevchenko <andy@kernel.org>
diff --git a/include/linux/platform_data/x86/intel_pmc_ipc.h b/include/linux/platform_data/x86/intel_pmc_ipc.h
new file mode 100644 (file)
index 0000000..6e603a8
--- /dev/null
@@ -0,0 +1,94 @@
+/* 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>
+
+#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)
+{
+       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 };
+       union acpi_object *obj;
+       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;
+
+       obj = 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;
+}
+
+#endif /* INTEL_PMC_IPC_H */