Re: [PATCH v5 07/10] power: reset: macsmc-reboot: Add driver for rebooting via Apple SMC

From: Stefan Wahren
Date: Sun May 11 2025 - 06:07:42 EST


Hi Sven,

Am 11.05.25 um 10:18 schrieb Sven Peter via B4 Relay:
From: Hector Martin <marcan@xxxxxxxxx>

This driver implements the reboot/shutdown support exposed by the SMC
on Apple Silicon machines, such as Apple M1 Macs.

Signed-off-by: Hector Martin <marcan@xxxxxxxxx>
Signed-off-by: Sven Peter <sven@xxxxxxxxxxxxx>
---
MAINTAINERS | 1 +
drivers/power/reset/Kconfig | 11 ++
drivers/power/reset/Makefile | 1 +
drivers/power/reset/macsmc-reboot.c | 363 ++++++++++++++++++++++++++++++++++++
4 files changed, 376 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index fa3a5f9ee40446bcc725c9eac2a36651e6bc7553..84f7a730eb2260b7c1e0487d18c8eb3de82f5206 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2303,6 +2303,7 @@ F: drivers/mfd/macsmc.c
F: drivers/nvme/host/apple.c
F: drivers/nvmem/apple-efuses.c
F: drivers/pinctrl/pinctrl-apple-gpio.c
+F: drivers/power/reset/macsmc-reboot.c
F: drivers/pwm/pwm-apple.c
F: drivers/soc/apple/*
F: drivers/spi/spi-apple.c
diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig
index 60bf0ca64cf395cd18238fc626611c74d29844ee..6e8dfff64fdc001d09b6c00630cd8b7e2fafdd8e 100644
--- a/drivers/power/reset/Kconfig
+++ b/drivers/power/reset/Kconfig
@@ -128,6 +128,17 @@ config POWER_RESET_LINKSTATION
Say Y here if you have a Buffalo LinkStation LS421D/E.
+config POWER_RESET_MACSMC
+ tristate "Apple SMC reset/power-off driver"
+ depends on ARCH_APPLE || COMPILE_TEST
+ depends on MFD_MACSMC
+ depends on OF
+ help
+ This driver supports reset and power-off on Apple Mac machines
+ that implement this functionality via the SMC.
+
+ Say Y here if you have an Apple Silicon Mac.
+
config POWER_RESET_MSM
bool "Qualcomm MSM power-off driver"
depends on ARCH_QCOM
diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile
index 10782d32e1da39f4b8b4566e8a885f2e13f65130..887dd9e49b7293b69b9429ddc0c1571194a153cf 100644
--- a/drivers/power/reset/Makefile
+++ b/drivers/power/reset/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o
obj-$(CONFIG_POWER_RESET_GPIO_RESTART) += gpio-restart.o
obj-$(CONFIG_POWER_RESET_HISI) += hisi-reboot.o
obj-$(CONFIG_POWER_RESET_LINKSTATION) += linkstation-poweroff.o
+obj-$(CONFIG_POWER_RESET_MACSMC) += macsmc-reboot.o
obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o
obj-$(CONFIG_POWER_RESET_MT6323) += mt6323-poweroff.o
obj-$(CONFIG_POWER_RESET_QCOM_PON) += qcom-pon.o
diff --git a/drivers/power/reset/macsmc-reboot.c b/drivers/power/reset/macsmc-reboot.c
new file mode 100644
index 0000000000000000000000000000000000000000..d82339e427886667be4ad2de0d1d5c04d2383059
--- /dev/null
+++ b/drivers/power/reset/macsmc-reboot.c
@@ -0,0 +1,363 @@
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
+/*
+ * Apple SMC Reboot/Poweroff Handler
+ * Copyright The Asahi Linux Contributors
+ */
+
+#include <linux/delay.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/macsmc.h>
+#include <linux/module.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/reboot.h>
+#include <linux/slab.h>
+
+struct macsmc_reboot_nvmem {
+ struct nvmem_cell *shutdown_flag;
+ struct nvmem_cell *pm_setting;
+ struct nvmem_cell *boot_stage;
+ struct nvmem_cell *boot_error_count;
+ struct nvmem_cell *panic_count;
+};
+
+static const char * const nvmem_names[] = {
+ "shutdown_flag",
+ "pm_setting",
+ "boot_stage",
+ "boot_error_count",
+ "panic_count",
+};
+
+enum boot_stage {
+ BOOT_STAGE_SHUTDOWN = 0x00, /* Clean shutdown */
+ BOOT_STAGE_IBOOT_DONE = 0x2f, /* Last stage of bootloader */
+ BOOT_STAGE_KERNEL_STARTED = 0x30, /* Normal OS booting */
+};
+
+enum pm_setting {
+ PM_SETTING_AC_POWER_RESTORE = 0x02,
+ PM_SETTING_AC_POWER_OFF = 0x03,
+};
+
+static const char * const ac_power_modes[] = { "off", "restore" };
+
+static int ac_power_mode_map[] = {
+ PM_SETTING_AC_POWER_OFF,
+ PM_SETTING_AC_POWER_RESTORE,
+};
+
+struct macsmc_reboot {
+ struct device *dev;
+ struct apple_smc *smc;
+ struct notifier_block reboot_notify;
+
+ union {
+ struct macsmc_reboot_nvmem nvm;
+ struct nvmem_cell *nvm_cells[ARRAY_SIZE(nvmem_names)];
+ };
+};
+
+/* Helpers to read/write a u8 given a struct nvmem_cell */
+static int nvmem_cell_get_u8(struct nvmem_cell *cell)
+{
+ size_t len;
+ u8 val;
+ void *ret = nvmem_cell_read(cell, &len);
in case this series needs a respin, please rename the pointer (e.g. buf). This is very unusual, because ret is usually of type int.

Regards