diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 4d95269..47b4830 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -93,7 +93,6 @@ 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_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 2054548..01a5d0c 100644 --- a/arch/arm/boards/mioa701/gpio0_poweroff.c +++ b/arch/arm/boards/mioa701/gpio0_poweroff.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -45,7 +46,7 @@ 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 929ded5..b60f344 100644 --- a/arch/arm/mach-highbank/reset.c +++ b/arch/arm/mach-highbank/reset.c @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -20,15 +21,7 @@ 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 @@ 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 b712b38..e28378e 100644 --- a/arch/arm/mach-pxa/pxa2xx.c +++ b/arch/arm/mach-pxa/pxa2xx.c @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -46,9 +47,7 @@ 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 @@ 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 86ca63b..ccfd952 100644 --- a/arch/arm/mach-pxa/pxa3xx.c +++ b/arch/arm/mach-pxa/pxa3xx.c @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -48,7 +49,7 @@ 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 @@ 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 fd106fe..ee79ff6 100644 --- a/arch/mips/mach-xburst/Kconfig +++ b/arch/mips/mach-xburst/Kconfig @@ -21,7 +21,6 @@ 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 25830f1..1fdcc7b 100644 --- a/arch/mips/mach-xburst/reset-jz4750.c +++ b/arch/mips/mach-xburst/reset-jz4750.c @@ -22,6 +22,8 @@ #include #include +#include +#include #include static void __noreturn jz4750d_halt(void) @@ -37,7 +39,7 @@ unreachable(); } -void __noreturn poweroff() +static void __noreturn jz4750_poweroff(struct poweroff_handler *handler) { u32 ctrl; @@ -50,4 +52,11 @@ 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 bc0885c..d4ccc29 100644 --- a/commands/Kconfig +++ b/commands/Kconfig @@ -6,10 +6,6 @@ depends on !SHELL_NONE default y -config HAS_POWEROFF - bool - default n - if COMMAND_SUPPORT config COMPILE_HASH @@ -1848,7 +1844,6 @@ 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 e8c726a..bbafa13 100644 --- a/commands/poweroff.c +++ b/commands/poweroff.c @@ -19,10 +19,11 @@ #include #include +#include static int cmd_poweroff(int argc, char *argv[]) { - poweroff(); + poweroff_machine(); /* Not reached */ return 1; diff --git a/common/Makefile b/common/Makefile index 5f58c81..8cd0ab3 100644 --- a/common/Makefile +++ b/common/Makefile @@ -9,6 +9,7 @@ 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 0000000..32a7828 --- /dev/null +++ b/common/poweroff.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2015 Sascha Hauer , 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 +#include +#include +#include + +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 680a0af..dd7445e 100644 --- a/include/common.h +++ b/include/common.h @@ -66,9 +66,6 @@ /* 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 0000000..ae9557d --- /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 */