summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/Kconfig2
-rw-r--r--arch/arm/boards/mioa701/gpio0_poweroff.c3
-rw-r--r--arch/arm/mach-highbank/reset.c20
-rw-r--r--arch/arm/mach-pxa/pxa2xx.c15
-rw-r--r--arch/arm/mach-pxa/pxa3xx.c13
-rw-r--r--arch/mips/mach-xburst/Kconfig1
-rw-r--r--arch/mips/mach-xburst/reset-jz4750.c13
-rw-r--r--commands/Kconfig5
-rw-r--r--commands/poweroff.c3
-rw-r--r--common/Makefile1
-rw-r--r--common/poweroff.c114
-rw-r--r--include/common.h3
-rw-r--r--include/poweroff.h21
13 files changed, 186 insertions, 28 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 4d952698fc..47b48308a6 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -93,7 +93,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
@@ -154,7 +153,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 2054548aa6..01a5d0cc6e 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 929ded5951..b60f34452e 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 b712b388c8..e28378e6db 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 86ca63b160..ccfd952b5e 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 fd106fefe0..ee79ff6167 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 25830f130e..1fdcc7b8af 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)
+{
+ poweroff_handler_register_fn(jz4750_poweroff);
+
+ return 0;
+}
+coredevice_initcall(jz4750_init);
diff --git a/commands/Kconfig b/commands/Kconfig
index bc0885c69d..d4ccc299e9 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 e8c726a7f2..bbafa13bd0 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 5f58c81d22..8cd0ab3001 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 0000000000..32a78280d3
--- /dev/null
+++ b/common/poweroff.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2015 Sascha Hauer <s.hauer@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 680a0affb6..dd7445e9b6 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 0000000000..ae9557db5d
--- /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 */