[PATCH v2] poweroff: Allow to register poweroff handlers

Oleksij Rempel o.rempel at pengutronix.de
Mon Mar 13 04:05:23 PDT 2017


From: Sascha Hauer <s.hauer at pengutronix.de>

Allow to register handlers for poweroff. This allows to have multiple
poweroff implementations in a single binary. The implementation is close
to the restart handlers.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
Signed-off-by: Oleksij Rempel <o.rempel at pengutronix.de>
---
 arch/arm/Kconfig                         |   2 -
 arch/arm/boards/mioa701/gpio0_poweroff.c |   3 +-
 arch/arm/mach-highbank/reset.c           |  20 +++---
 arch/arm/mach-pxa/pxa2xx.c               |  15 +++-
 arch/arm/mach-pxa/pxa3xx.c               |  13 +++-
 arch/mips/mach-xburst/Kconfig            |   1 -
 arch/mips/mach-xburst/reset-jz4750.c     |  13 +++-
 commands/Kconfig                         |   5 --
 commands/poweroff.c                      |   3 +-
 common/Makefile                          |   1 +
 common/poweroff.c                        | 114 +++++++++++++++++++++++++++++++
 include/common.h                         |   3 -
 include/poweroff.h                       |  21 ++++++
 13 files changed, 186 insertions(+), 28 deletions(-)
 create mode 100644 common/poweroff.c
 create mode 100644 include/poweroff.h

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 3e8ccf766..eedc2b4e9 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -98,7 +98,6 @@ config ARCH_EP93XX
 config ARCH_HIGHBANK
 	bool "Calxeda Highbank"
 	select HAS_DEBUG_LL
-	select HAS_POWEROFF
 	select ARCH_HAS_L2X0
 	select CPU_V7
 	select ARM_AMBA
@@ -158,7 +157,6 @@ config ARCH_OMAP
 config ARCH_PXA
 	bool "Intel/Marvell PXA based"
 	select GENERIC_GPIO
-	select HAS_POWEROFF
 
 config ARCH_ROCKCHIP
 	bool "Rockchip RX3xxx"
diff --git a/arch/arm/boards/mioa701/gpio0_poweroff.c b/arch/arm/boards/mioa701/gpio0_poweroff.c
index 2054548aa..01a5d0cc6 100644
--- a/arch/arm/boards/mioa701/gpio0_poweroff.c
+++ b/arch/arm/boards/mioa701/gpio0_poweroff.c
@@ -19,6 +19,7 @@
 #include <clock.h>
 #include <common.h>
 #include <init.h>
+#include <poweroff.h>
 #include <gpio.h>
 #include <poller.h>
 
@@ -45,7 +46,7 @@ static void try_poweroff(void)
 
 	gpio_set_value(GPIO115_LED_nKeyboard, 0);
 	mdelay(2000);
-	poweroff();
+	poweroff_machine();
 }
 
 static void gpio0_poller_fn(struct poller_struct *poller)
diff --git a/arch/arm/mach-highbank/reset.c b/arch/arm/mach-highbank/reset.c
index 929ded595..b60f34452 100644
--- a/arch/arm/mach-highbank/reset.c
+++ b/arch/arm/mach-highbank/reset.c
@@ -6,6 +6,7 @@
 
 #include <common.h>
 #include <io.h>
+#include <poweroff.h>
 #include <restart.h>
 #include <init.h>
 
@@ -20,15 +21,7 @@ static void __noreturn highbank_restart_soc(struct restart_handler *rst)
 	hang();
 }
 
-static int restart_register_feature(void)
-{
-	restart_handler_register_fn(highbank_restart_soc);
-
-	return 0;
-}
-coredevice_initcall(restart_register_feature);
-
-void __noreturn poweroff()
+void __noreturn highbank_poweroff(struct poweroff_handler *handler)
 {
 	shutdown_barebox();
 
@@ -37,3 +30,12 @@ void __noreturn poweroff()
 
 	while(1);
 }
+
+static int highbank_init(void)
+{
+	restart_handler_register_fn(highbank_restart_soc);
+	poweroff_handler_register_fn(highbank_poweroff);
+
+	return 0;
+}
+coredevice_initcall(highbank_init);
diff --git a/arch/arm/mach-pxa/pxa2xx.c b/arch/arm/mach-pxa/pxa2xx.c
index b712b388c..e28378e6d 100644
--- a/arch/arm/mach-pxa/pxa2xx.c
+++ b/arch/arm/mach-pxa/pxa2xx.c
@@ -14,6 +14,7 @@
 
 #include <common.h>
 #include <init.h>
+#include <poweroff.h>
 #include <reset_source.h>
 #include <mach/hardware.h>
 #include <mach/pxa-regs.h>
@@ -46,9 +47,7 @@ void pxa_clear_reset_source(void)
 	RCSR = RCSR_GPR | RCSR_SMR | RCSR_WDR | RCSR_HWR;
 }
 
-device_initcall(pxa_detect_reset_source);
-
-void __noreturn poweroff(void)
+static void __noreturn pxa2xx_poweroff(struct poweroff_handler *handler)
 {
 	shutdown_barebox();
 
@@ -57,3 +56,13 @@ void __noreturn poweroff(void)
 	pxa_suspend(PWRMODE_DEEPSLEEP);
 	unreachable();
 }
+
+static int pxa2xx_init(void)
+{
+	poweroff_handler_register_fn(pxa2xx_poweroff);
+
+	pxa_detect_reset_source();
+
+	return 0;
+}
+device_initcall(pxa2xx_init);
diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c
index 86ca63b16..ccfd952b5 100644
--- a/arch/arm/mach-pxa/pxa3xx.c
+++ b/arch/arm/mach-pxa/pxa3xx.c
@@ -14,6 +14,7 @@
 
 #include <common.h>
 #include <init.h>
+#include <poweroff.h>
 #include <reset_source.h>
 #include <mach/hardware.h>
 #include <mach/pxa-regs.h>
@@ -48,7 +49,7 @@ void pxa_clear_reset_source(void)
 
 device_initcall(pxa_detect_reset_source);
 
-void __noreturn poweroff(void)
+static void __noreturn pxa3xx_poweroff(struct poweroff_handler *handler)
 {
 	shutdown_barebox();
 
@@ -57,3 +58,13 @@ void __noreturn poweroff(void)
 	pxa3xx_suspend(PXA3xx_PM_S3D4C4);
 	unreachable();
 }
+
+static int pxa3xx_init(void)
+{
+	poweroff_handler_register_fn(pxa3xx_poweroff);
+
+	pxa_detect_reset_source();
+
+	return 0;
+}
+device_initcall(pxa3xx_init);
diff --git a/arch/mips/mach-xburst/Kconfig b/arch/mips/mach-xburst/Kconfig
index fd106fefe..ee79ff616 100644
--- a/arch/mips/mach-xburst/Kconfig
+++ b/arch/mips/mach-xburst/Kconfig
@@ -21,7 +21,6 @@ choice
 
 config BOARD_RZX50
 	bool "Ritmix RZX-50"
-	select HAS_POWEROFF
 	select CPU_JZ4755
 
 config BOARD_CI20
diff --git a/arch/mips/mach-xburst/reset-jz4750.c b/arch/mips/mach-xburst/reset-jz4750.c
index 25830f130..e1e88e2bf 100644
--- a/arch/mips/mach-xburst/reset-jz4750.c
+++ b/arch/mips/mach-xburst/reset-jz4750.c
@@ -22,6 +22,8 @@
 
 #include <common.h>
 #include <io.h>
+#include <init.h>
+#include <poweroff.h>
 #include <mach/jz4750d_regs.h>
 
 static void __noreturn jz4750d_halt(void)
@@ -37,7 +39,7 @@ static void __noreturn jz4750d_halt(void)
 	unreachable();
 }
 
-void __noreturn poweroff()
+static void __noreturn jz4750_poweroff(struct poweroff_handler *handler)
 {
 	u32 ctrl;
 
@@ -50,4 +52,11 @@ void __noreturn poweroff()
 	writel(RTC_HCR_PD, (u32 *)RTC_HCR);
 	jz4750d_halt();
 }
-EXPORT_SYMBOL(poweroff);
+
+static int jz4750_init(void)
+{
+	restart_handler_register_fn(jz4750_poweroff);
+
+	return 0;
+}
+coredevice_initcall(jz4750_init);
\ No newline at end of file
diff --git a/commands/Kconfig b/commands/Kconfig
index 21d921268..5a709a900 100644
--- a/commands/Kconfig
+++ b/commands/Kconfig
@@ -6,10 +6,6 @@ config COMMAND_SUPPORT
 	depends on !SHELL_NONE
 	default y
 
-config HAS_POWEROFF
-	bool
-	default n
-
 if COMMAND_SUPPORT
 
 config COMPILE_HASH
@@ -1848,7 +1844,6 @@ config CMD_NAND_BITFLIP
 
 config CMD_POWEROFF
 	tristate
-	depends on HAS_POWEROFF
 	prompt "poweroff"
 	help
 	  Turn the power off.
diff --git a/commands/poweroff.c b/commands/poweroff.c
index e8c726a7f..bbafa13bd 100644
--- a/commands/poweroff.c
+++ b/commands/poweroff.c
@@ -19,10 +19,11 @@
 
 #include <common.h>
 #include <command.h>
+#include <poweroff.h>
 
 static int cmd_poweroff(int argc, char *argv[])
 {
-	poweroff();
+	poweroff_machine();
 
 	/* Not reached */
 	return 1;
diff --git a/common/Makefile b/common/Makefile
index 869b15a92..572bf0578 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -9,6 +9,7 @@ obj-pbl-y			+= memsize.o
 obj-y				+= resource.o
 obj-y				+= bootsource.o
 obj-y				+= restart.o
+obj-y				+= poweroff.o
 obj-$(CONFIG_AUTO_COMPLETE)	+= complete.o
 obj-$(CONFIG_BANNER)		+= version.o
 obj-$(CONFIG_BAREBOX_UPDATE)	+= bbu.o
diff --git a/common/poweroff.c b/common/poweroff.c
new file mode 100644
index 000000000..32a78280d
--- /dev/null
+++ b/common/poweroff.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2015 Sascha Hauer <s.hauer at pengutronix.de>, Pengutronix
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#define pr_fmt(fmt) "poweroff: " fmt
+
+#include <common.h>
+#include <poweroff.h>
+#include <malloc.h>
+#include <of.h>
+
+static LIST_HEAD(poweroff_handler_list);
+
+/**
+ * poweroff_handler_register() - register a handler for poweroffing the system
+ * @rst:	The handler struct
+ *
+ * This adds @rst to the list of registered poweroff handlers.
+ *
+ * return: 0 for success or negative error code
+ */
+int poweroff_handler_register(struct poweroff_handler *handler)
+{
+	if (!handler->name)
+		handler->name = POWEROFF_DEFAULT_NAME;
+	if (!handler->priority)
+		handler->priority = POWEROFF_DEFAULT_PRIORITY;
+
+	list_add_tail(&handler->list, &poweroff_handler_list);
+
+	pr_debug("registering poweroff handler \"%s\" with priority %d\n",
+			handler->name, handler->priority);
+
+	return 0;
+}
+
+/**
+ * poweroff_handler_register_fn() - register a handler function
+ * @poweroff_fn:	The poweroff function
+ *
+ * convenience wrapper for poweroff_handler_register() to register a handler
+ * with given function and default values otherwise.
+ *
+ * return: 0 for success or negative error code
+ */
+int poweroff_handler_register_fn(void (*poweroff_fn)(struct poweroff_handler *))
+{
+	struct poweroff_handler *handler;
+	int ret;
+
+	handler = xzalloc(sizeof(*handler));
+
+	handler->poweroff = poweroff_fn;
+
+	ret = poweroff_handler_register(handler);
+
+	if (ret)
+		free(handler);
+
+	return ret;
+}
+
+/**
+ * poweroff_machine() - power off the machine
+ */
+void __noreturn poweroff_machine(void)
+{
+	struct poweroff_handler *handler = NULL, *tmp;
+	unsigned int priority = 0;
+
+	list_for_each_entry(tmp, &poweroff_handler_list, list) {
+		if (tmp->priority > priority) {
+			priority = tmp->priority;
+			handler = tmp;
+		}
+	}
+
+	if (handler) {
+		pr_debug("using poweroff handler %s\n", handler->name);
+		console_flush();
+		handler->poweroff(handler);
+	} else {
+		pr_err("No poweroff handler found!\n");
+	}
+
+	hang();
+}
+
+/**
+ * of_get_poweroff_priority() - get the desired poweroff priority from device tree
+ * @node:	The device_node to read the property from
+ *
+ * return: The priority
+ */
+unsigned int of_get_poweroff_priority(struct device_node *node)
+{
+	unsigned int priority = POWEROFF_DEFAULT_PRIORITY;
+
+	of_property_read_u32(node, "poweroff-priority", &priority);
+
+	return priority;
+}
diff --git a/include/common.h b/include/common.h
index 680a0affb..dd7445e9b 100644
--- a/include/common.h
+++ b/include/common.h
@@ -66,9 +66,6 @@ int	readline	(const char *prompt, char *buf, int len);
 /* common/memsize.c */
 long	get_ram_size  (volatile long *, long);
 
-/* $(CPU)/cpu.c */
-void __noreturn poweroff(void);
-
 /* common/console.c */
 int	ctrlc (void);
 
diff --git a/include/poweroff.h b/include/poweroff.h
new file mode 100644
index 000000000..ae9557db5
--- /dev/null
+++ b/include/poweroff.h
@@ -0,0 +1,21 @@
+#ifndef __INCLUDE_POWEROFF_H
+#define __INCLUDE_POWEROFF_H
+
+void __noreturn poweroff_machine(void);
+
+struct poweroff_handler {
+	void (*poweroff)(struct poweroff_handler *);
+	int priority;
+	const char *name;
+	struct list_head list;
+};
+
+int poweroff_handler_register(struct poweroff_handler *);
+int poweroff_handler_register_fn(void (*poweroff_fn)(struct poweroff_handler *));
+
+#define POWEROFF_DEFAULT_PRIORITY 100
+#define POWEROFF_DEFAULT_NAME "default"
+
+unsigned int of_get_poweroff_priority(struct device_node *node);
+
+#endif /* __INCLUDE_POWEROFF_H */
-- 
2.11.0




More information about the barebox mailing list