From 167e93947e9b755b54900ae9870dbcc089f8d6c9 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Tue, 25 Aug 2015 16:11:08 +0200 Subject: watchdog: imxwd: remove remove callback The imxwd is for resetting the system, so we should not unregister it during shutdown_barebox() as it may leave us without a restart handler. Only a bug (not setting reset_wd to NULL in remove()) made the whole thing work. Signed-off-by: Sascha Hauer --- drivers/watchdog/imxwd.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/drivers/watchdog/imxwd.c b/drivers/watchdog/imxwd.c index 5ffbac7cdd..9f09f6ecd0 100644 --- a/drivers/watchdog/imxwd.c +++ b/drivers/watchdog/imxwd.c @@ -217,17 +217,6 @@ on_error: return ret; } -static void imx_wd_remove(struct device_d *dev) -{ - struct imx_wd *priv = dev->priv; - - if (IS_ENABLED(CONFIG_WATCHDOG_IMX)) - watchdog_deregister(&priv->wd); - - if (reset_wd && reset_wd != priv) - free(priv); -} - static const struct imx_wd_ops imx21_wd_ops = { .set_timeout = imx21_watchdog_set_timeout, .init = imx21_wd_init, @@ -264,7 +253,6 @@ static struct platform_device_id imx_wdt_ids[] = { static struct driver_d imx_wd_driver = { .name = "imx-watchdog", .probe = imx_wd_probe, - .remove = imx_wd_remove, .of_compatible = DRV_OF_COMPAT(imx_wdt_dt_ids), .id_table = imx_wdt_ids, }; -- cgit v1.2.3 From 83b0a5ae055bc084938dac96b3ea1c796d99d86c Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 26 Aug 2015 09:04:45 +0200 Subject: restart: replace reset_cpu with registered restart handlers This replaces the reset_cpu() function which every SoC or board must provide with registered handlers. This makes it possible to have multiple reset functions for boards which have multiple ways to reset the machine. Also boards which have no way at all to reset the machine no longer have to provide a dummy reset_cpu() function. The problem this solves is that some machines have external PMICs or similar to reset the system which have to be preferred over the internal SoC reset, because the PMIC can reset not only the SoC but also the external devices. To pick the right way to reset a machine each handler has a priority. The default priority is 100 and all currently existing restart handlers are registered with this priority. of_get_restart_priority() allows to retrieve the priority from the device tree which makes it possible for boards to give certain restart handlers a higher priority in order to use this one instead of the default one. Signed-off-by: Sascha Hauer --- arch/arm/lib/bootm.c | 7 +- arch/arm/mach-at91/at91rm9200_time.c | 14 ++- arch/arm/mach-at91/at91sam9_reset.S | 4 +- arch/arm/mach-at91/at91sam9g45_reset.S | 4 +- arch/arm/mach-at91/bootstrap.c | 3 +- arch/arm/mach-at91/setup.c | 9 ++ arch/arm/mach-bcm2835/core.c | 21 +++-- arch/arm/mach-clps711x/reset.c | 12 ++- arch/arm/mach-davinci/time.c | 14 ++- arch/arm/mach-digic/Makefile | 2 +- arch/arm/mach-digic/core.c | 25 ----- arch/arm/mach-ep93xx/clocksource.c | 19 ++-- arch/arm/mach-highbank/reset.c | 14 ++- arch/arm/mach-mvebu/armada-370-xp.c | 9 +- arch/arm/mach-mvebu/common.c | 13 --- arch/arm/mach-mvebu/dove.c | 9 +- arch/arm/mach-mvebu/include/mach/common.h | 1 - arch/arm/mach-mvebu/kirkwood.c | 9 +- arch/arm/mach-mxs/soc-imx23.c | 8 +- arch/arm/mach-mxs/soc-imx28.c | 9 +- arch/arm/mach-netx/generic.c | 23 +++-- arch/arm/mach-nomadik/reset.c | 15 ++- arch/arm/mach-omap/am33xx_generic.c | 7 +- arch/arm/mach-omap/include/mach/am33xx-generic.h | 2 - arch/arm/mach-omap/include/mach/omap3-generic.h | 2 - arch/arm/mach-omap/include/mach/omap4-generic.h | 2 - arch/arm/mach-omap/omap3_generic.c | 8 +- arch/arm/mach-omap/omap4_generic.c | 7 +- arch/arm/mach-omap/omap_generic.c | 11 --- arch/arm/mach-pxa/common.c | 14 ++- arch/arm/mach-rockchip/core.c | 16 +++- arch/arm/mach-samsung/generic.c | 15 ++- arch/arm/mach-socfpga/reset-manager.c | 14 ++- arch/arm/mach-tegra/tegra20-pmc.c | 9 +- arch/arm/mach-uemd/Makefile | 2 +- arch/arm/mach-uemd/reset.c | 24 ----- arch/arm/mach-versatile/core.c | 7 +- arch/arm/mach-vexpress/reset.c | 15 ++- arch/arm/mach-zynq/zynq.c | 24 ++--- arch/blackfin/lib/cpu.c | 13 ++- arch/blackfin/lib/traps.c | 5 +- arch/efi/efi/efi.c | 13 ++- arch/mips/lib/bootm.c | 3 +- arch/mips/mach-ar231x/ar231x_reset.c | 8 +- arch/mips/mach-ath79/reset.c | 15 ++- arch/mips/mach-bcm47xx/reset.c | 16 +++- arch/mips/mach-loongson/loongson1_reset.c | 15 ++- arch/mips/mach-malta/reset.c | 16 +++- arch/nios2/cpu/cpu.c | 12 ++- arch/openrisc/cpu/cpu.c | 11 ++- arch/ppc/lib/ppclinux.c | 3 +- arch/ppc/mach-mpc5xxx/cpu.c | 11 ++- arch/ppc/mach-mpc85xx/cpu.c | 14 ++- arch/sandbox/board/Makefile | 1 + arch/sandbox/board/restart.c | 17 ++++ arch/sandbox/mach-sandbox/include/mach/linux.h | 1 + arch/sandbox/os/common.c | 6 +- arch/x86/mach-i386/Makefile | 2 - arch/x86/mach-i386/reset.c | 30 ------ commands/reset.c | 3 +- common/Makefile | 1 + common/misc.c | 3 +- common/restart.c | 112 +++++++++++++++++++++++ drivers/usb/gadget/f_fastboot.c | 3 +- drivers/watchdog/imxwd.c | 22 +++-- drivers/watchdog/jz4740.c | 37 ++++---- include/common.h | 1 - include/restart.h | 21 +++++ 68 files changed, 552 insertions(+), 286 deletions(-) delete mode 100644 arch/arm/mach-digic/core.c delete mode 100644 arch/arm/mach-uemd/reset.c create mode 100644 arch/sandbox/board/restart.c delete mode 100644 arch/x86/mach-i386/reset.c create mode 100644 common/restart.c create mode 100644 include/restart.h diff --git a/arch/arm/lib/bootm.c b/arch/arm/lib/bootm.c index 8327c3f560..7bb9b43656 100644 --- a/arch/arm/lib/bootm.c +++ b/arch/arm/lib/bootm.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -111,7 +112,7 @@ static int __do_bootm_linux(struct image_data *data, unsigned long free_mem, int start_linux((void *)kernel, swap, initrd_start, initrd_size, data->oftree); - reset_cpu(0); + restart_machine(); return -ERESTARTSYS; } @@ -378,7 +379,7 @@ static int do_bootm_barebox(struct image_data *data) start_linux(barebox, 0, 0, 0, data->oftree); - reset_cpu(0); + restart_machine(); } static struct image_handler barebox_handler = { @@ -518,7 +519,7 @@ static int do_bootm_aimage(struct image_data *data) second(); - reset_cpu(0); + restart_machine(); } close(fd); diff --git a/arch/arm/mach-at91/at91rm9200_time.c b/arch/arm/mach-at91/at91rm9200_time.c index ae0172b4f4..fd11223b6f 100644 --- a/arch/arm/mach-at91/at91rm9200_time.c +++ b/arch/arm/mach-at91/at91rm9200_time.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -77,7 +78,7 @@ core_initcall(clocksource_init); /* * Reset the cpu through the reset controller */ -void __noreturn reset_cpu (unsigned long ignored) +static void __noreturn at91rm9200_restart_soc(struct restart_handler *rst) { /* * Perform a hardware reset with the use of the Watchdog timer. @@ -86,6 +87,13 @@ void __noreturn reset_cpu (unsigned long ignored) at91_sys_write(AT91_ST_CR, AT91_ST_WDRST); /* Not reached */ - while (1); + hang(); } -EXPORT_SYMBOL(reset_cpu); + +static int restart_register_feature(void) +{ + restart_handler_register_fn(at91rm9200_restart_soc); + + return 0; +} +coredevice_initcall(restart_register_feature); diff --git a/arch/arm/mach-at91/at91sam9_reset.S b/arch/arm/mach-at91/at91sam9_reset.S index 3a3e77aaa5..890545edbf 100644 --- a/arch/arm/mach-at91/at91sam9_reset.S +++ b/arch/arm/mach-at91/at91sam9_reset.S @@ -20,9 +20,9 @@ .arm - .globl reset_cpu + .globl restart_sam9 -reset_cpu: ldr r0, .at91_va_base_sdramc @ preload constants +restart_sam9: ldr r0, .at91_va_base_sdramc @ preload constants ldr r1, .at91_va_base_rstc_cr mov r2, #1 diff --git a/arch/arm/mach-at91/at91sam9g45_reset.S b/arch/arm/mach-at91/at91sam9g45_reset.S index e70d733ac8..2cb113cdb4 100644 --- a/arch/arm/mach-at91/at91sam9g45_reset.S +++ b/arch/arm/mach-at91/at91sam9g45_reset.S @@ -17,9 +17,9 @@ .arm - .globl reset_cpu + .globl restart_sam9g45 -reset_cpu: ldr r0, .at91_va_base_sdramc @ preload constants +restart_sam9g45: ldr r0, .at91_va_base_sdramc @ preload constants ldr r1, .at91_va_base_rstc_cr mov r2, #1 diff --git a/arch/arm/mach-at91/bootstrap.c b/arch/arm/mach-at91/bootstrap.c index 2d18dd6b32..1baf7323fe 100644 --- a/arch/arm/mach-at91/bootstrap.c +++ b/arch/arm/mach-at91/bootstrap.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -145,7 +146,7 @@ static void boot_mmc_disk_action(struct menu *m, struct menu_entry *me) static void boot_reset_action(struct menu *m, struct menu_entry *me) { - reset_cpu(0); + restart_machine(); } void at91_bootstrap_menu(void) diff --git a/arch/arm/mach-at91/setup.c b/arch/arm/mach-at91/setup.c index 341979ae89..1fa50ac054 100644 --- a/arch/arm/mach-at91/setup.c +++ b/arch/arm/mach-at91/setup.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -296,6 +297,9 @@ static int at91_detect(void) } postcore_initcall(at91_detect); +void restart_sam9(struct restart_handler *rst); +void restart_sam9g45(struct restart_handler *rst); + static int at91_soc_device(void) { struct device_d *dev; @@ -304,6 +308,11 @@ static int at91_soc_device(void) dev_add_param_fixed(dev, "name", (char*)at91_get_soc_type(&at91_soc_initdata)); dev_add_param_fixed(dev, "subname", (char*)at91_get_soc_subtype(&at91_soc_initdata)); + if (IS_ENABLED(CONFIG_AT91SAM9_RESET)) + restart_handler_register_fn(restart_sam9); + if (IS_ENABLED(CONFIG_AT91SAM9G45_RESET)) + restart_handler_register_fn(restart_sam9g45); + return 0; } coredevice_initcall(at91_soc_device); diff --git a/arch/arm/mach-bcm2835/core.c b/arch/arm/mach-bcm2835/core.c index 5d08012f8b..64f3781388 100644 --- a/arch/arm/mach-bcm2835/core.c +++ b/arch/arm/mach-bcm2835/core.c @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -51,13 +52,6 @@ static int bcm2835_clk_init(void) } postcore_initcall(bcm2835_clk_init); -static int bcm2835_dev_init(void) -{ - add_generic_device("bcm2835-gpio", 0, NULL, BCM2835_GPIO_BASE, 0xB0, IORESOURCE_MEM, NULL); - return 0; -} -coredevice_initcall(bcm2835_dev_init); - void bcm2835_register_uart(void) { amba_apb_device_add(NULL, "uart0-pl011", 0, BCM2835_UART0_BASE, 4096, NULL, 0); @@ -72,7 +66,7 @@ void bcm2835_add_device_sdram(u32 size) } #define RESET_TIMEOUT 10 -void __noreturn reset_cpu(unsigned long addr) +static void __noreturn bcm2835_restart_soc(struct restart_handler *rst) { uint32_t rstc; @@ -82,6 +76,13 @@ void __noreturn reset_cpu(unsigned long addr) writel(PM_PASSWORD | RESET_TIMEOUT, PM_WDOG); writel(PM_PASSWORD | rstc, PM_RSTC); - while (1); + hang(); } -EXPORT_SYMBOL(reset_cpu); + +static int bcm2835_dev_init(void) +{ + add_generic_device("bcm2835-gpio", 0, NULL, BCM2835_GPIO_BASE, 0xB0, IORESOURCE_MEM, NULL); + restart_handler_register_fn(bcm2835_restart_soc); + return 0; +} +coredevice_initcall(bcm2835_dev_init); diff --git a/arch/arm/mach-clps711x/reset.c b/arch/arm/mach-clps711x/reset.c index 859d8ae574..03f40b73fa 100644 --- a/arch/arm/mach-clps711x/reset.c +++ b/arch/arm/mach-clps711x/reset.c @@ -8,8 +8,10 @@ */ #include +#include +#include -void __noreturn reset_cpu(unsigned long addr) +static void __noreturn clps711x_restart_soc(struct restart_handler *rst) { shutdown_barebox(); @@ -17,3 +19,11 @@ void __noreturn reset_cpu(unsigned long addr) hang(); } + +static int restart_register_feature(void) +{ + restart_handler_register_fn(clps711x_restart_soc); + + return 0; +} +coredevice_initcall(restart_register_feature); diff --git a/arch/arm/mach-davinci/time.c b/arch/arm/mach-davinci/time.c index 60f0d192a3..4d1b570aa0 100644 --- a/arch/arm/mach-davinci/time.c +++ b/arch/arm/mach-davinci/time.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -164,7 +165,7 @@ static int clocksource_init(void) core_initcall(clocksource_init); /* reset board using watchdog timer */ -void __noreturn reset_cpu(ulong addr) +static void __noreturn davinci_restart_soc(struct restart_handler *rst) { u32 tgcr, wdtcr; void __iomem *base; @@ -204,6 +205,13 @@ void __noreturn reset_cpu(ulong addr) wdtcr = 0x00004000; __raw_writel(wdtcr, base + WDTCR); - unreachable(); + hang(); } -EXPORT_SYMBOL(reset_cpu); + +static int restart_register_feature(void) +{ + restart_handler_register_fn(davinci_restart_soc); + + return 0; +} +coredevice_initcall(restart_register_feature); diff --git a/arch/arm/mach-digic/Makefile b/arch/arm/mach-digic/Makefile index 820eb10ac2..16a218658a 100644 --- a/arch/arm/mach-digic/Makefile +++ b/arch/arm/mach-digic/Makefile @@ -1 +1 @@ -obj-y += core.o +obj- := __dummy__.o diff --git a/arch/arm/mach-digic/core.c b/arch/arm/mach-digic/core.c deleted file mode 100644 index b1caec0bc8..0000000000 --- a/arch/arm/mach-digic/core.c +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2013 Antony Pavlov - * - * This file is part of barebox. - * 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. - * - */ - -#include - -void __noreturn reset_cpu(unsigned long ignored) -{ - pr_err("%s: unimplemented\n", __func__); - hang(); -} -EXPORT_SYMBOL(reset_cpu); diff --git a/arch/arm/mach-ep93xx/clocksource.c b/arch/arm/mach-ep93xx/clocksource.c index f396d0a0a2..83c05cea00 100644 --- a/arch/arm/mach-ep93xx/clocksource.c +++ b/arch/arm/mach-ep93xx/clocksource.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #define TIMER_CLKSEL (1 << 3) @@ -63,10 +64,8 @@ static int clocksource_init(void) core_initcall(clocksource_init); -/* - * Reset the cpu - */ -void __noreturn reset_cpu(unsigned long addr) +/* Reset the SoC */ +static void __noreturn ep92xx_restart_soc(struct restart_handler *rst) { struct syscon_regs *syscon = (struct syscon_regs *)SYSCON_BASE; uint32_t value; @@ -84,7 +83,13 @@ void __noreturn reset_cpu(unsigned long addr) writel(value, &syscon->devicecfg); /* Dying... */ - while (1) - ; /* noop */ + hang(); +} + +static int restart_register_feature(void) +{ + restart_handler_register_fn(ep92xx_restart_soc); + + return 0; } -EXPORT_SYMBOL(reset_cpu); +coredevice_initcall(restart_register_feature); diff --git a/arch/arm/mach-highbank/reset.c b/arch/arm/mach-highbank/reset.c index b9664e41bb..929ded5951 100644 --- a/arch/arm/mach-highbank/reset.c +++ b/arch/arm/mach-highbank/reset.c @@ -6,17 +6,27 @@ #include #include +#include +#include #include #include -void __noreturn reset_cpu(ulong addr) +static void __noreturn highbank_restart_soc(struct restart_handler *rst) { hingbank_set_pwr_hard_reset(); asm(" wfi"); - while(1); + hang(); +} + +static int restart_register_feature(void) +{ + restart_handler_register_fn(highbank_restart_soc); + + return 0; } +coredevice_initcall(restart_register_feature); void __noreturn poweroff() { diff --git a/arch/arm/mach-mvebu/armada-370-xp.c b/arch/arm/mach-mvebu/armada-370-xp.c index 2405629526..c362cfdabe 100644 --- a/arch/arm/mach-mvebu/armada-370-xp.c +++ b/arch/arm/mach-mvebu/armada-370-xp.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -104,12 +105,12 @@ static int armada_370_xp_soc_id_fixup(void) return 0; } -static void __noreturn armada_370_xp_reset_cpu(unsigned long addr) +static void __noreturn armada_370_xp_restart_soc(struct restart_handler *rst) { writel(0x1, ARMADA_370_XP_SYSCTL_BASE + 0x60); writel(0x1, ARMADA_370_XP_SYSCTL_BASE + 0x64); - while (1) - ; + + hang(); } static int armada_xp_init_soc(struct device_node *root) @@ -132,7 +133,7 @@ static int armada_370_xp_init_soc(struct device_node *root, void *context) if (!of_machine_is_compatible("marvell,armada-370-xp")) return 0; - mvebu_set_reset(armada_370_xp_reset_cpu); + restart_handler_register_fn(armada_370_xp_restart_soc); barebox_set_model("Marvell Armada 370/XP"); barebox_set_hostname("armada"); diff --git a/arch/arm/mach-mvebu/common.c b/arch/arm/mach-mvebu/common.c index 7d28d9c45a..cb40d0cb6f 100644 --- a/arch/arm/mach-mvebu/common.c +++ b/arch/arm/mach-mvebu/common.c @@ -123,16 +123,3 @@ int mvebu_set_memory(u64 phys_base, u64 phys_size) return 0; } - -static __noreturn void (*mvebu_reset_cpu)(unsigned long addr); - -void __noreturn reset_cpu(unsigned long addr) -{ - mvebu_reset_cpu(addr); -} -EXPORT_SYMBOL(reset_cpu); - -void mvebu_set_reset(void __noreturn (*reset)(unsigned long addr)) -{ - mvebu_reset_cpu = reset; -} diff --git a/arch/arm/mach-mvebu/dove.c b/arch/arm/mach-mvebu/dove.c index a7284fd33a..ba4af3aae9 100644 --- a/arch/arm/mach-mvebu/dove.c +++ b/arch/arm/mach-mvebu/dove.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -68,13 +69,13 @@ static inline void dove_memory_find(unsigned long *phys_base, } } -static void __noreturn dove_reset_cpu(unsigned long addr) +static void __noreturn dove_restart_soc(struct restart_handler *rst) { /* enable and assert RSTOUTn */ writel(SOFT_RESET_OUT_EN, DOVE_BRIDGE_BASE + BRIDGE_RSTOUT_MASK); writel(SOFT_RESET_EN, DOVE_BRIDGE_BASE + BRIDGE_SYS_SOFT_RESET); - while (1) - ; + + hang(); } static int dove_init_soc(struct device_node *root, void *context) @@ -84,7 +85,7 @@ static int dove_init_soc(struct device_node *root, void *context) if (!of_machine_is_compatible("marvell,dove")) return 0; - mvebu_set_reset(dove_reset_cpu); + restart_handler_register_fn(dove_restart_soc); barebox_set_model("Marvell Dove"); barebox_set_hostname("dove"); diff --git a/arch/arm/mach-mvebu/include/mach/common.h b/arch/arm/mach-mvebu/include/mach/common.h index 5ce33fd882..602af8f28f 100644 --- a/arch/arm/mach-mvebu/include/mach/common.h +++ b/arch/arm/mach-mvebu/include/mach/common.h @@ -21,6 +21,5 @@ #define MVEBU_REMAP_INT_REG_BASE 0xf1000000 int mvebu_set_memory(u64 phys_base, u64 phys_size); -void mvebu_set_reset(void __noreturn (*reset)(unsigned long addr)); #endif diff --git a/arch/arm/mach-mvebu/kirkwood.c b/arch/arm/mach-mvebu/kirkwood.c index 19c6f07303..72a6b0db3c 100644 --- a/arch/arm/mach-mvebu/kirkwood.c +++ b/arch/arm/mach-mvebu/kirkwood.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -43,12 +44,12 @@ static inline void kirkwood_memory_find(unsigned long *phys_base, } } -static void __noreturn kirkwood_reset_cpu(unsigned long addr) +static void __noreturn kirkwood_restart_soc(struct restart_handler *rst) { writel(SOFT_RESET_OUT_EN, KIRKWOOD_BRIDGE_BASE + BRIDGE_RSTOUT_MASK); writel(SOFT_RESET_EN, KIRKWOOD_BRIDGE_BASE + BRIDGE_SYS_SOFT_RESET); - for(;;) - ; + + hang(); } static int kirkwood_init_soc(struct device_node *root, void *context) @@ -58,7 +59,7 @@ static int kirkwood_init_soc(struct device_node *root, void *context) if (!of_machine_is_compatible("marvell,kirkwood")) return 0; - mvebu_set_reset(kirkwood_reset_cpu); + restart_handler_register_fn(kirkwood_restart_soc); barebox_set_model("Marvell Kirkwood"); barebox_set_hostname("kirkwood"); diff --git a/arch/arm/mach-mxs/soc-imx23.c b/arch/arm/mach-mxs/soc-imx23.c index 339c57748f..d471c8eb5c 100644 --- a/arch/arm/mach-mxs/soc-imx23.c +++ b/arch/arm/mach-mxs/soc-imx23.c @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -23,18 +24,16 @@ # define HW_CLKCTRL_RESET_CHIP (1 << 1) /* Reset the full i.MX23 SoC via a chipset feature */ -void __noreturn reset_cpu(unsigned long addr) +static void __noreturn imx23_restart_soc(struct restart_handler *rst) { u32 reg; reg = readl(IMX_CCM_BASE + HW_CLKCTRL_RESET); writel(reg | HW_CLKCTRL_RESET_CHIP, IMX_CCM_BASE + HW_CLKCTRL_RESET); - while (1) - ; + hang(); /*NOTREACHED*/ } -EXPORT_SYMBOL(reset_cpu); static int imx23_devices_init(void) { @@ -46,6 +45,7 @@ static int imx23_devices_init(void) add_generic_device("imx23-gpio", 0, NULL, IMX_IOMUXC_BASE, 0x2000, IORESOURCE_MEM, NULL); add_generic_device("imx23-gpio", 1, NULL, IMX_IOMUXC_BASE, 0x2000, IORESOURCE_MEM, NULL); add_generic_device("imx23-gpio", 2, NULL, IMX_IOMUXC_BASE, 0x2000, IORESOURCE_MEM, NULL); + restart_handler_register_fn(imx23_restart_soc); return 0; } diff --git a/arch/arm/mach-mxs/soc-imx28.c b/arch/arm/mach-mxs/soc-imx28.c index b4ec38d912..dc6020aa36 100644 --- a/arch/arm/mach-mxs/soc-imx28.c +++ b/arch/arm/mach-mxs/soc-imx28.c @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -24,18 +25,16 @@ #define HW_CLKCTRL_WDOG_POR_DISABLE (1 << 5) /* Reset the full i.MX28 SoC via a chipset feature */ -void __noreturn reset_cpu(unsigned long addr) +static void __noreturn imx28_restart_soc(struct restart_handler *rst) { u32 reg; reg = readl(IMX_CCM_BASE + HW_CLKCTRL_RESET); writel(reg | HW_CLKCTRL_RESET_CHIP, IMX_CCM_BASE + HW_CLKCTRL_RESET); - while (1) - ; + hang(); /*NOTREACHED*/ } -EXPORT_SYMBOL(reset_cpu); static int imx28_init(void) { @@ -50,6 +49,8 @@ static int imx28_init(void) HW_CLKCTRL_WDOG_POR_DISABLE; writel(reg, IMX_CCM_BASE + HW_CLKCTRL_RESET); + restart_handler_register_fn(imx28_restart_soc); + return 0; } postcore_initcall(imx28_init); diff --git a/arch/arm/mach-netx/generic.c b/arch/arm/mach-netx/generic.c index 6127dde868..6c3b953d1f 100644 --- a/arch/arm/mach-netx/generic.c +++ b/arch/arm/mach-netx/generic.c @@ -15,8 +15,10 @@ */ #include +#include #include #include +#include #include #include "eth_firmware.h" @@ -134,17 +136,24 @@ failure: return COMMAND_ERROR_USAGE; } -void __noreturn reset_cpu(unsigned long addr) +BAREBOX_CMD_START(loadxc) + .cmd = do_loadxc, + BAREBOX_CMD_DESC("load XMAC/XPEC engine with ethernet firmware") + BAREBOX_CMD_GROUP(CMD_GRP_NET) +BAREBOX_CMD_END + +static void __noreturn netx_restart_soc(struct restart_handler *rst) { SYSTEM_REG(SYSTEM_RES_CR) = 0x01000008; /* Not reached */ - while (1); + hang(); } +static int restart_register_feature(void) +{ + restart_handler_register_fn(netx_restart_soc); -BAREBOX_CMD_START(loadxc) - .cmd = do_loadxc, - BAREBOX_CMD_DESC("load XMAC/XPEC engine with ethernet firmware") - BAREBOX_CMD_GROUP(CMD_GRP_NET) -BAREBOX_CMD_END + return 0; +} +coredevice_initcall(restart_register_feature); diff --git a/arch/arm/mach-nomadik/reset.c b/arch/arm/mach-nomadik/reset.c index bb5696a345..8bdaada8a1 100644 --- a/arch/arm/mach-nomadik/reset.c +++ b/arch/arm/mach-nomadik/reset.c @@ -15,10 +15,12 @@ */ #include +#include #include +#include #include -void __noreturn reset_cpu(unsigned long addr) +static void __noreturn nomadik_restart_soc(struct restart_handler *rst) { void __iomem *src_rstsr = (void *)(NOMADIK_SRC_BASE + 0x18); @@ -28,6 +30,13 @@ void __noreturn reset_cpu(unsigned long addr) writel(1, src_rstsr); /* Not reached */ - while (1); + hang(); } -EXPORT_SYMBOL(reset_cpu); + +static int restart_register_feature(void) +{ + restart_handler_register_fn(nomadik_restart_soc); + + return 0; +} +coredevice_initcall(restart_register_feature); diff --git a/arch/arm/mach-omap/am33xx_generic.c b/arch/arm/mach-omap/am33xx_generic.c index 7ce32f01e1..ae0ee585a8 100644 --- a/arch/arm/mach-omap/am33xx_generic.c +++ b/arch/arm/mach-omap/am33xx_generic.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -28,11 +29,11 @@ #include #include -void __noreturn am33xx_reset_cpu(unsigned long addr) +static void __noreturn am33xx_restart_soc(struct restart_handler *rst) { writel(AM33XX_PRM_RSTCTRL_RESET, AM33XX_PRM_RSTCTRL); - while (1); + hang(); } /** @@ -243,6 +244,8 @@ int am33xx_init(void) { omap_gpmc_base = (void *)AM33XX_GPMC_BASE; + restart_handler_register_fn(am33xx_restart_soc); + am33xx_enable_per_clocks(); if (IS_ENABLED(CONFIG_RESET_SOURCE)) diff --git a/arch/arm/mach-omap/include/mach/am33xx-generic.h b/arch/arm/mach-omap/include/mach/am33xx-generic.h index 03418b053b..7e64e74d5c 100644 --- a/arch/arm/mach-omap/include/mach/am33xx-generic.h +++ b/arch/arm/mach-omap/include/mach/am33xx-generic.h @@ -28,8 +28,6 @@ u32 am33xx_running_in_flash(void); u32 am33xx_running_in_sram(void); u32 am33xx_running_in_sdram(void); -void __noreturn am33xx_reset_cpu(unsigned long addr); - void am33xx_enable_per_clocks(void); int am33xx_init(void); int am33xx_devices_init(void); diff --git a/arch/arm/mach-omap/include/mach/omap3-generic.h b/arch/arm/mach-omap/include/mach/omap3-generic.h index ab53b98971..177862e4b1 100644 --- a/arch/arm/mach-omap/include/mach/omap3-generic.h +++ b/arch/arm/mach-omap/include/mach/omap3-generic.h @@ -24,8 +24,6 @@ u32 omap3_running_in_flash(void); u32 omap3_running_in_sram(void); u32 omap3_running_in_sdram(void); -void __noreturn omap3_reset_cpu(unsigned long addr); - int omap3_init(void); int omap3_devices_init(void); diff --git a/arch/arm/mach-omap/include/mach/omap4-generic.h b/arch/arm/mach-omap/include/mach/omap4-generic.h index e246e360e5..7ec41d880b 100644 --- a/arch/arm/mach-omap/include/mach/omap4-generic.h +++ b/arch/arm/mach-omap/include/mach/omap4-generic.h @@ -18,8 +18,6 @@ static inline void omap4_save_bootinfo(uint32_t *info) memcpy((void *)OMAP44XX_SRAM_SCRATCH_SPACE, info, 3 * sizeof(uint32_t)); } -void __noreturn omap4_reset_cpu(unsigned long addr); - int omap4_init(void); int omap4_devices_init(void); diff --git a/arch/arm/mach-omap/omap3_generic.c b/arch/arm/mach-omap/omap3_generic.c index 0f2e9ce6b7..5c29feaeb4 100644 --- a/arch/arm/mach-omap/omap3_generic.c +++ b/arch/arm/mach-omap/omap3_generic.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -52,13 +53,12 @@ * * @return void */ -void __noreturn omap3_reset_cpu(unsigned long addr) +static void __noreturn omap3_restart_soc(struct restart_handler *rst) { writel(OMAP3_PRM_RSTCTRL_RESET, OMAP3_PRM_REG(RSTCTRL)); - while (1); + hang(); } -EXPORT_SYMBOL(reset_cpu); /** * @brief Low level CPU type @@ -490,6 +490,8 @@ int omap3_init(void) { omap_gpmc_base = (void *)OMAP3_GPMC_BASE; + restart_handler_register_fn(omap3_restart_soc); + return omap3_bootsource(); } diff --git a/arch/arm/mach-omap/omap4_generic.c b/arch/arm/mach-omap/omap4_generic.c index 0b683da181..a3f370df8f 100644 --- a/arch/arm/mach-omap/omap4_generic.c +++ b/arch/arm/mach-omap/omap4_generic.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -34,11 +35,11 @@ #define EMIF_L3_CONFIG_VAL_SYS_10_LL_0 0x0A0000FF #define EMIF_L3_CONFIG_VAL_SYS_10_MPU_3_LL_0 0x0A300000 -void __noreturn omap4_reset_cpu(unsigned long addr) +static void __noreturn omap4_restart_soc(struct restart_handler *rst) { writel(OMAP44XX_PRM_RSTCTRL_RESET, OMAP44XX_PRM_RSTCTRL); - while (1); + hang(); } void omap4_set_warmboot_order(u32 *device_list) @@ -533,6 +534,8 @@ int omap4_init(void) { omap_gpmc_base = (void *)OMAP44XX_GPMC_BASE; + restart_handler_register_fn(omap4_restart_soc); + return omap4_bootsource(); } diff --git a/arch/arm/mach-omap/omap_generic.c b/arch/arm/mach-omap/omap_generic.c index 334cf8db56..165487c645 100644 --- a/arch/arm/mach-omap/omap_generic.c +++ b/arch/arm/mach-omap/omap_generic.c @@ -150,17 +150,6 @@ static int omap_env_init(void) late_initcall(omap_env_init); #endif -void __noreturn reset_cpu(unsigned long addr) -{ - if (cpu_is_omap3()) - omap3_reset_cpu(addr); - if (cpu_is_omap4()) - omap4_reset_cpu(addr); - if (cpu_is_am33xx()) - am33xx_reset_cpu(addr); - while (1); -} - static int omap_soc_from_dt(void) { if (of_machine_is_compatible("ti,am33xx")) diff --git a/arch/arm/mach-pxa/common.c b/arch/arm/mach-pxa/common.c index 2c27d812fc..c0281d69ef 100644 --- a/arch/arm/mach-pxa/common.c +++ b/arch/arm/mach-pxa/common.c @@ -16,6 +16,8 @@ */ #include +#include +#include #include #include @@ -29,7 +31,7 @@ extern void pxa_clear_reset_source(void); -void reset_cpu(ulong addr) +static void __noreturn pxa_restart_soc(struct restart_handler *rst) { /* Clear last reset source */ pxa_clear_reset_source(); @@ -39,5 +41,13 @@ void reset_cpu(ulong addr) writel(OSSR_M3, OSSR); writel(readl(OSCR) + 368640, OSMR3); /* ... in 100 ms */ - while (1); + hang(); } + +static int restart_register_feature(void) +{ + restart_handler_register_fn(pxa_restart_soc); + + return 0; +} +coredevice_initcall(restart_register_feature); diff --git a/arch/arm/mach-rockchip/core.c b/arch/arm/mach-rockchip/core.c index bab06df63c..2428fee349 100644 --- a/arch/arm/mach-rockchip/core.c +++ b/arch/arm/mach-rockchip/core.c @@ -13,16 +13,24 @@ #include #include +#include +#include #include -void __noreturn reset_cpu(unsigned long addr) +static void __noreturn rockchip_restart_soc(struct restart_handler *rst) { /* Map bootrom from address 0 */ writel(RK_SOC_CON0_REMAP << 16, RK_GRF_BASE + RK_GRF_SOC_CON0); /* Reset */ writel(0xeca8, RK_CRU_BASE + RK_CRU_GLB_SRST_SND); - while (1) - ; + hang(); } -EXPORT_SYMBOL(reset_cpu); + +static int restart_register_feature(void) +{ + restart_handler_register_fn(rockchip_restart_soc); + + return 0; +} +coredevice_initcall(restart_register_feature); diff --git a/arch/arm/mach-samsung/generic.c b/arch/arm/mach-samsung/generic.c index 75965d7826..4f13fce13b 100644 --- a/arch/arm/mach-samsung/generic.c +++ b/arch/arm/mach-samsung/generic.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -29,7 +30,7 @@ #define S3C_WTDAT (S3C_WATCHDOG_BASE + 0x04) #define S3C_WTCNT (S3C_WATCHDOG_BASE + 0x08) -void __noreturn reset_cpu(unsigned long addr) +static void __noreturn samsung_restart_soc(struct restart_handler *rst) { /* Disable watchdog */ writew(0x0000, S3C_WTCON); @@ -41,7 +42,13 @@ void __noreturn reset_cpu(unsigned long addr) writew(0x0021, S3C_WTCON); /* loop forever and wait for reset to happen */ - while(1) - ; + hang(); } -EXPORT_SYMBOL(reset_cpu); + +static int restart_register_feature(void) +{ + restart_handler_register_fn(samsung_restart_soc); + + return 0; +} +coredevice_initcall(restart_register_feature); diff --git a/arch/arm/mach-socfpga/reset-manager.c b/arch/arm/mach-socfpga/reset-manager.c index a9e7e1448f..04522da4d1 100644 --- a/arch/arm/mach-socfpga/reset-manager.c +++ b/arch/arm/mach-socfpga/reset-manager.c @@ -17,6 +17,8 @@ #include #include +#include +#include #include #include @@ -38,7 +40,7 @@ void watchdog_disable(void) } /* Write the reset manager register to cause reset */ -void reset_cpu(ulong addr) +static void __noreturn socfpga_restart_soc(struct restart_handler *rst) { /* request a warm reset */ writel((1 << RSTMGR_CTRL_SWWARMRSTREQ_LSB), @@ -47,5 +49,13 @@ void reset_cpu(ulong addr) * infinite loop here as watchdog will trigger and reset * the processor */ - while (1); + hang(); } + +static int restart_register_feature(void) +{ + restart_handler_register_fn(socfpga_restart_soc); + + return 0; +} +coredevice_initcall(restart_register_feature); diff --git a/arch/arm/mach-tegra/tegra20-pmc.c b/arch/arm/mach-tegra/tegra20-pmc.c index eaa5ac73ff..02f0bf7499 100644 --- a/arch/arm/mach-tegra/tegra20-pmc.c +++ b/arch/arm/mach-tegra/tegra20-pmc.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -36,13 +37,12 @@ static void __iomem *pmc_base; static int tegra_num_powerdomains; /* main SoC reset trigger */ -void __noreturn reset_cpu(ulong addr) +static void __noreturn tegra20_restart_soc(struct restart_handler *rst) { writel(PMC_CNTRL_MAIN_RST, pmc_base + PMC_CNTRL); - unreachable(); + hang(); } -EXPORT_SYMBOL(reset_cpu); static int tegra_powergate_set(int id, bool new_state) { @@ -219,7 +219,7 @@ static int tegra20_pmc_probe(struct device_d *dev) static int do_tegrarcm(int argc, char *argv[]) { writel(2, pmc_base + PMC_SCRATCH(0)); - reset_cpu(0); + restart_machine(); return 0; } @@ -244,6 +244,7 @@ static struct driver_d tegra20_pmc_driver = { static int tegra20_pmc_init(void) { + restart_handler_register_fn(tegra20_restart_soc); return platform_driver_register(&tegra20_pmc_driver); } coredevice_initcall(tegra20_pmc_init); diff --git a/arch/arm/mach-uemd/Makefile b/arch/arm/mach-uemd/Makefile index f3cc6684b8..16a218658a 100644 --- a/arch/arm/mach-uemd/Makefile +++ b/arch/arm/mach-uemd/Makefile @@ -1 +1 @@ -obj-y += reset.o +obj- := __dummy__.o diff --git a/arch/arm/mach-uemd/reset.c b/arch/arm/mach-uemd/reset.c deleted file mode 100644 index 00ae0be0b3..0000000000 --- a/arch/arm/mach-uemd/reset.c +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (C) 2014 Antony Pavlov - * - * This file is part of barebox. - * 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. - * - */ - -#include - -void __noreturn reset_cpu(ulong addr) -{ - hang(); -} -EXPORT_SYMBOL(reset_cpu); diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c index c671aa6173..7c6e9523a2 100644 --- a/arch/arm/mach-versatile/core.c +++ b/arch/arm/mach-versatile/core.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -184,7 +185,7 @@ void versatile_register_uart(unsigned id) amba_apb_device_add(NULL, "uart-pl011", id, start, 4096, NULL, 0); } -void __noreturn reset_cpu (unsigned long ignored) +static void versatile_reset_soc(struct restart_handler *rst) { u32 val; @@ -195,9 +196,8 @@ void __noreturn reset_cpu (unsigned long ignored) __raw_writel(val, VERSATILE_SYS_RESETCTL); __raw_writel(0, VERSATILE_SYS_LOCK); - while(1); + hang(); } -EXPORT_SYMBOL(reset_cpu); static int versatile_init(void) { @@ -205,6 +205,7 @@ static int versatile_init(void) amba_apb_device_add(NULL, "pl061_gpio", 1, 0x101e5000, 4096, NULL, 0); amba_apb_device_add(NULL, "pl061_gpio", 2, 0x101e6000, 4096, NULL, 0); amba_apb_device_add(NULL, "pl061_gpio", 3, 0x101e7000, 4096, NULL, 0); + restart_handler_register_fn(versatile_reset_soc); return 0; } coredevice_initcall(versatile_init); diff --git a/arch/arm/mach-vexpress/reset.c b/arch/arm/mach-vexpress/reset.c index ad6e06fe5f..3164ae3079 100644 --- a/arch/arm/mach-vexpress/reset.c +++ b/arch/arm/mach-vexpress/reset.c @@ -6,17 +6,26 @@ #include #include +#include +#include #include #include void __iomem *v2m_wdt_base; -void reset_cpu(ulong addr) +static void vexpress_reset_soc(struct restart_handler *rst) { writel(LOAD_MIN, v2m_wdt_base + WDTLOAD); writeb(RESET_ENABLE, v2m_wdt_base + WDTCONTROL); - while (1) - ; + hang(); } + +static int restart_register_feature(void) +{ + restart_handler_register_fn(vexpress_reset_soc); + + return 0; +} +coredevice_initcall(restart_register_feature); diff --git a/arch/arm/mach-zynq/zynq.c b/arch/arm/mach-zynq/zynq.c index bd29e13377..a0a8d0d249 100644 --- a/arch/arm/mach-zynq/zynq.c +++ b/arch/arm/mach-zynq/zynq.c @@ -17,8 +17,19 @@ #include #include #include +#include #include +static void __noreturn zynq_restart_soc(struct restart_handler *rst) +{ + /* write unlock key to slcr */ + writel(0xDF0D, ZYNQ_SLCR_UNLOCK); + /* reset */ + writel(0x1, ZYNQ_PSS_RST_CTRL); + + hang(); +} + static int zynq_init(void) { u32 val; @@ -40,17 +51,8 @@ static int zynq_init(void) add_generic_device("zynq-clock", 0, NULL, ZYNQ_SLCR_BASE, 0x4000, IORESOURCE_MEM, NULL); add_generic_device("smp_twd", 0, NULL, CORTEXA9_SCU_TIMER_BASE_ADDR, 0x4000, IORESOURCE_MEM, NULL); + restart_handler_register_fn(zynq_restart_soc); + return 0; } postcore_initcall(zynq_init); - -void __noreturn reset_cpu(unsigned long addr) -{ - /* write unlock key to slcr */ - writel(0xDF0D, ZYNQ_SLCR_UNLOCK); - /* reset */ - writel(0x1, ZYNQ_PSS_RST_CTRL); - - while (1) - ; -} diff --git a/arch/blackfin/lib/cpu.c b/arch/blackfin/lib/cpu.c index 9d4c6e3e89..34b93e78ac 100644 --- a/arch/blackfin/lib/cpu.c +++ b/arch/blackfin/lib/cpu.c @@ -27,8 +27,9 @@ #include #include #include +#include -void __noreturn reset_cpu(unsigned long addr) +static void __noreturn blackfin_restart_cpu(struct restart_handler *rst) { icache_disable(); @@ -41,9 +42,17 @@ void __noreturn reset_cpu(unsigned long addr) ); /* Not reached */ - while (1); + hang(); } +static int restart_register_feature(void) +{ + restart_handler_register_fn(blackfin_restart_cpu); + + return 0; +} +coredevice_initcall(restart_register_feature); + void icache_disable(void) { #ifdef __ADSPBF537__ diff --git a/arch/blackfin/lib/traps.c b/arch/blackfin/lib/traps.c index c2dda73465..2111d255fd 100644 --- a/arch/blackfin/lib/traps.c +++ b/arch/blackfin/lib/traps.c @@ -30,6 +30,7 @@ */ #include +#include #include #include #include @@ -91,7 +92,7 @@ void trap_c (struct pt_regs *regs) printf("\nPlease reset the board\n"); - reset_cpu(0); + restart_machine(); } void blackfin_irq_panic(int reason, struct pt_regs *regs) @@ -101,6 +102,6 @@ void blackfin_irq_panic(int reason, struct pt_regs *regs) printf("Unhandled IRQ or exceptions!\n"); printf("Please reset the board \n"); - reset_cpu(0); + restart_machine(); } diff --git a/arch/efi/efi/efi.c b/arch/efi/efi/efi.c index d3f520f60f..ed449dc8db 100644 --- a/arch/efi/efi/efi.c +++ b/arch/efi/efi/efi.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -273,13 +274,21 @@ static int efi_console_init(void) } console_initcall(efi_console_init); -void reset_cpu(unsigned long addr) +static void __noreturn efi_restart_system(struct restart_handler *rst) { RT->reset_system(EFI_RESET_WARM, EFI_SUCCESS, 0, NULL); - while(1); + hang(); } +static int restart_register_feature(void) +{ + restart_handler_register_fn(efi_restart_system); + + return 0; +} +coredevice_initcall(restart_register_feature); + extern char image_base[]; extern initcall_t __barebox_initcalls_start[], __barebox_early_initcalls_end[], __barebox_initcalls_end[]; diff --git a/arch/mips/lib/bootm.c b/arch/mips/lib/bootm.c index 0e03aa9bcb..84f72f5ac0 100644 --- a/arch/mips/lib/bootm.c +++ b/arch/mips/lib/bootm.c @@ -5,6 +5,7 @@ #include #include #include +#include #include @@ -20,7 +21,7 @@ static int do_bootm_barebox(struct image_data *data) barebox(); - reset_cpu(0); + restart_machine(); } static struct image_handler barebox_handler = { diff --git a/arch/mips/mach-ar231x/ar231x_reset.c b/arch/mips/mach-ar231x/ar231x_reset.c index 0788add164..318f772108 100644 --- a/arch/mips/mach-ar231x/ar231x_reset.c +++ b/arch/mips/mach-ar231x/ar231x_reset.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -17,16 +18,16 @@ static void __iomem *reset_base; -void __noreturn reset_cpu(ulong addr) +static void __noreturn ar2312x_restart_soc(struct restart_handler *rst) { printf("reseting cpu\n"); __raw_writel(0x10000, (char *)KSEG1ADDR(AR2312_WD_TIMER)); __raw_writel(AR2312_WD_CTRL_RESET, (char *)KSEG1ADDR(AR2312_WD_CTRL)); - unreachable(); + + hang(); } -EXPORT_SYMBOL(reset_cpu); static u32 ar231x_reset_readl(void) { @@ -69,6 +70,7 @@ static struct driver_d ar231x_reset_driver = { static int ar231x_reset_init(void) { + restart_handler_register_fn(ar2312x_restart_soc); return platform_driver_register(&ar231x_reset_driver); } coredevice_initcall(ar231x_reset_init); diff --git a/arch/mips/mach-ath79/reset.c b/arch/mips/mach-ath79/reset.c index a0e9b349ca..0665788227 100644 --- a/arch/mips/mach-ath79/reset.c +++ b/arch/mips/mach-ath79/reset.c @@ -16,9 +16,11 @@ */ #include +#include +#include #include -void __noreturn reset_cpu(ulong addr) +static void __noreturn ath79_restart_soc(struct restart_handler *rst) { ath79_reset_wr(AR933X_RESET_REG_RESET_MODULE, AR71XX_RESET_FULL_CHIP); /* @@ -26,7 +28,14 @@ void __noreturn reset_cpu(ulong addr) * pulling the reset pin. The system will reboot with PLL disabled. * Always zero when read. */ - unreachable(); + hang(); /*NOTREACHED*/ } -EXPORT_SYMBOL(reset_cpu); + +static int restart_register_feature(void) +{ + restart_handler_register_fn(ath79_restart_soc); + + return 0; +} +coredevice_initcall(restart_register_feature); diff --git a/arch/mips/mach-bcm47xx/reset.c b/arch/mips/mach-bcm47xx/reset.c index 00aee190fe..6287adb374 100644 --- a/arch/mips/mach-bcm47xx/reset.c +++ b/arch/mips/mach-bcm47xx/reset.c @@ -17,12 +17,22 @@ #include #include +#include +#include #include -void __noreturn reset_cpu(ulong addr) +static void __noreturn bcm47xx_restart_soc(struct restart_handler *rst) { __raw_writel(GORESET, (char *)SOFTRES_REG); - while (1); + + hang(); /*NOTREACHED*/ } -EXPORT_SYMBOL(reset_cpu); + +static int restart_register_feature(void) +{ + restart_handler_register_fn(bcm47xx_restart_soc); + + return 0; +} +coredevice_initcall(restart_register_feature); diff --git a/arch/mips/mach-loongson/loongson1_reset.c b/arch/mips/mach-loongson/loongson1_reset.c index 8975392ca6..7a8f1d6836 100644 --- a/arch/mips/mach-loongson/loongson1_reset.c +++ b/arch/mips/mach-loongson/loongson1_reset.c @@ -14,14 +14,23 @@ #include #include +#include +#include #include -void __noreturn reset_cpu(ulong addr) +static void __noreturn longhorn_restart_soc(struct restart_handler *rst) { __raw_writel(0x1, LS1X_WDT_EN); __raw_writel(0x1, LS1X_WDT_SET); __raw_writel(0x1, LS1X_WDT_TIMER); - unreachable(); + hang(); } -EXPORT_SYMBOL(reset_cpu); + +static int restart_register_feature(void) +{ + restart_handler_register_fn(longhorn_restart_soc); + + return 0; +} +coredevice_initcall(restart_register_feature); diff --git a/arch/mips/mach-malta/reset.c b/arch/mips/mach-malta/reset.c index f1dc68afb5..ff29cd5e9b 100644 --- a/arch/mips/mach-malta/reset.c +++ b/arch/mips/mach-malta/reset.c @@ -22,12 +22,22 @@ #include #include +#include +#include #include -void __noreturn reset_cpu(ulong addr) +static void __noreturn malta_restart_soc(struct restart_handler *rst) { __raw_writel(GORESET, (char *)SOFTRES_REG); - while (1); + + hang(); /*NOTREACHED*/ } -EXPORT_SYMBOL(reset_cpu); + +static int restart_register_feature(void) +{ + restart_handler_register_fn(malta_restart_soc); + + return 0; +} +coredevice_initcall(restart_register_feature); diff --git a/arch/nios2/cpu/cpu.c b/arch/nios2/cpu/cpu.c index fdbe9f9dad..b2164af812 100644 --- a/arch/nios2/cpu/cpu.c +++ b/arch/nios2/cpu/cpu.c @@ -18,14 +18,22 @@ */ #include +#include +#include #include -void __noreturn reset_cpu(ulong ignored) +static void __noreturn nios2_restart_soc(struct restart_handler *rst) { /* indirect call to go beyond 256MB limitation of toolchain */ nios2_callr(RESET_ADDR); /* Not reached */ - while (1); + hang(); } +static int restart_register_feature(void) +{ + restart_handler_register_fn(nios2_restart_soc); +} +coredevice_initcall(restart_register_feature); + diff --git a/arch/openrisc/cpu/cpu.c b/arch/openrisc/cpu/cpu.c index d73a418f93..d52b021029 100644 --- a/arch/openrisc/cpu/cpu.c +++ b/arch/openrisc/cpu/cpu.c @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -29,11 +30,17 @@ int cleanup_before_linux(void) extern void __reset(void); -void __noreturn reset_cpu(ulong ignored) +static void __noreturn openrisc_restart_cpu(struct restart_handler *rst) { __reset(); /* not reached, __reset does not return */ /* Not reached */ - while (1); + hang(); } + +static int restart_register_feature(void) +{ + restart_handler_register_fn(openrisc_restart_cpu, NULL, RESET_SCOPE_CPU); +} +coredevice_initcall(restart_register_feature); diff --git a/arch/ppc/lib/ppclinux.c b/arch/ppc/lib/ppclinux.c index e25efecd43..409c0cf261 100644 --- a/arch/ppc/lib/ppclinux.c +++ b/arch/ppc/lib/ppclinux.c @@ -10,6 +10,7 @@ #include #include #include +#include #include static int bootm_relocate_fdt(void *addr, struct image_data *data) @@ -87,7 +88,7 @@ static int do_bootm_linux(struct image_data *data) */ kernel(data->oftree, kernel, 0, 0, 0); - reset_cpu(0); + restart_machine(); error: return -1; diff --git a/arch/ppc/mach-mpc5xxx/cpu.c b/arch/ppc/mach-mpc5xxx/cpu.c index 3f826e4994..33835e7060 100644 --- a/arch/ppc/mach-mpc5xxx/cpu.c +++ b/arch/ppc/mach-mpc5xxx/cpu.c @@ -31,6 +31,7 @@ #include #include #include +#include #include int checkcpu (void) @@ -59,7 +60,7 @@ int checkcpu (void) /* ------------------------------------------------------------------------- */ -void __noreturn reset_cpu (unsigned long addr) +static void __noreturn mpc5xxx_restart_soc(struct restart_handler *rst) { ulong msr; /* Interrupts and MMU off */ @@ -71,9 +72,15 @@ void __noreturn reset_cpu (unsigned long addr) /* Charge the watchdog timer */ *(vu_long *)(MPC5XXX_GPT0_COUNTER) = 0x0001000f; *(vu_long *)(MPC5XXX_GPT0_ENABLE) = 0x9004; /* wden|ce|timer_ms */ - while(1); + hang(); } +static int restart_register_feature(void) +{ + restart_handler_register_fn(mpc5xxx_restart_soc); +} +coredevice_initcall(restart_register_feature); + /* ------------------------------------------------------------------------- */ #ifdef CONFIG_OFTREE diff --git a/arch/ppc/mach-mpc85xx/cpu.c b/arch/ppc/mach-mpc85xx/cpu.c index 7c183c1b5e..42464e810c 100644 --- a/arch/ppc/mach-mpc85xx/cpu.c +++ b/arch/ppc/mach-mpc85xx/cpu.c @@ -26,12 +26,13 @@ #include #include #include +#include #include #include #include #include -void __noreturn reset_cpu(unsigned long addr) +static void __noreturn mpc85xx_restart_soc(struct restart_handler *rst) { void __iomem *regs = (void __iomem *)MPC85xx_GUTS_ADDR; @@ -39,10 +40,17 @@ void __noreturn reset_cpu(unsigned long addr) out_be32(regs + MPC85xx_GUTS_RSTCR_OFFSET, 0x2); /* HRESET_REQ */ udelay(100); - while (1) - ; + hang(); } +static int restart_register_feature(void) +{ + restart_handler_register_fn(mpc85xx_restart_soc); + + return 0; +} +coredevice_initcall(restart_register_feature); + long int initdram(int board_type) { phys_size_t dram_size = 0; diff --git a/arch/sandbox/board/Makefile b/arch/sandbox/board/Makefile index 460116332d..333638ced6 100644 --- a/arch/sandbox/board/Makefile +++ b/arch/sandbox/board/Makefile @@ -4,5 +4,6 @@ obj-y += hostfile.o obj-y += console.o obj-y += devices.o obj-y += dtb.o +obj-y += restart.o extra-y += barebox.lds diff --git a/arch/sandbox/board/restart.c b/arch/sandbox/board/restart.c new file mode 100644 index 0000000000..79bf79a556 --- /dev/null +++ b/arch/sandbox/board/restart.c @@ -0,0 +1,17 @@ +#include +#include +#include +#include + +static void sandbox_restart_cpu(struct restart_handler *restart) +{ + linux_exit(); +} + +static int restart_register_feature(void) +{ + restart_handler_register_fn(sandbox_restart_cpu); + + return 0; +} +coredevice_initcall(restart_register_feature); diff --git a/arch/sandbox/mach-sandbox/include/mach/linux.h b/arch/sandbox/mach-sandbox/include/mach/linux.h index 990173e10b..1e53f69ad7 100644 --- a/arch/sandbox/mach-sandbox/include/mach/linux.h +++ b/arch/sandbox/mach-sandbox/include/mach/linux.h @@ -15,6 +15,7 @@ int linux_read_nonblock(int fd, void *buf, size_t count); ssize_t linux_write(int fd, const void *buf, size_t count); off_t linux_lseek(int fildes, off_t offset); int linux_tstc(int fd); +void __attribute__((noreturn)) linux_exit(void); int linux_execve(const char * filename, char *const argv[], char *const envp[]); diff --git a/arch/sandbox/os/common.c b/arch/sandbox/os/common.c index d627391890..67667d40da 100644 --- a/arch/sandbox/os/common.c +++ b/arch/sandbox/os/common.c @@ -115,7 +115,7 @@ uint64_t linux_get_time(void) return now; } -void __attribute__((noreturn)) reset_cpu(unsigned long addr) +void __attribute__((noreturn)) linux_exit(void) { cookmode(); exit(0); @@ -133,7 +133,7 @@ int linux_read(int fd, void *buf, size_t count) if (ret == 0) { printf("read on fd %d returned 0, device gone? - exiting\n", fd); - reset_cpu(0); + linux_exit(); } else if (ret == -1) { if (errno == EAGAIN) return -errno; @@ -141,7 +141,7 @@ int linux_read(int fd, void *buf, size_t count) continue; else { printf("read on fd %d returned -1, errno %d - exiting\n", fd, errno); - reset_cpu(0); + linux_exit(); } } } while (ret <= 0); diff --git a/arch/x86/mach-i386/Makefile b/arch/x86/mach-i386/Makefile index e46aa5b5ee..225b4811c5 100644 --- a/arch/x86/mach-i386/Makefile +++ b/arch/x86/mach-i386/Makefile @@ -1,4 +1,2 @@ -obj-y += reset.o - # reference clocksource obj-y += pit_timer.o diff --git a/arch/x86/mach-i386/reset.c b/arch/x86/mach-i386/reset.c deleted file mode 100644 index 65f7d35537..0000000000 --- a/arch/x86/mach-i386/reset.c +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2009 Juergen Beisert, Pengutronix - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * 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. - * - * - */ - -/** - * @file - * @brief Resetting an x86 CPU - */ - -#include - -void __noreturn reset_cpu(unsigned long addr) -{ - /** How to reset the machine? */ - while(1) - ; -} -EXPORT_SYMBOL(reset_cpu); diff --git a/commands/reset.c b/commands/reset.c index 4f42b91e0f..830048049a 100644 --- a/commands/reset.c +++ b/commands/reset.c @@ -21,6 +21,7 @@ #include #include #include +#include static int cmd_reset(int argc, char *argv[]) { @@ -39,7 +40,7 @@ static int cmd_reset(int argc, char *argv[]) if (shutdown_flag) shutdown_barebox(); - reset_cpu(0); + restart_machine(); /* Not reached */ return 1; diff --git a/common/Makefile b/common/Makefile index ed131c8c56..1e7a08190c 100644 --- a/common/Makefile +++ b/common/Makefile @@ -8,6 +8,7 @@ obj-y += misc.o obj-pbl-y += memsize.o obj-y += resource.o obj-y += bootsource.o +obj-y += restart.o obj-$(CONFIG_AUTO_COMPLETE) += complete.o obj-$(CONFIG_BANNER) += version.o obj-$(CONFIG_BAREBOX_UPDATE) += bbu.o diff --git a/common/misc.c b/common/misc.c index 6da71c7ab7..5532349e43 100644 --- a/common/misc.c +++ b/common/misc.c @@ -24,6 +24,7 @@ #include #include #include +#include int errno; EXPORT_SYMBOL(errno); @@ -206,7 +207,7 @@ void __noreturn panic(const char *fmt, ...) hang(); } else { udelay(100000); /* allow messages to go out */ - reset_cpu(0); + restart_machine(); } } EXPORT_SYMBOL(panic); diff --git a/common/restart.c b/common/restart.c new file mode 100644 index 0000000000..8fd5ffd1a2 --- /dev/null +++ b/common/restart.c @@ -0,0 +1,112 @@ +/* + * 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) "restart: " fmt + +#include +#include +#include +#include + +static LIST_HEAD(restart_handler_list); + +/** + * restart_handler_register() - register a handler for restarting the system + * @rst: The handler struct + * + * This adds @rst to the list of registered restart handlers. + * + * return: 0 for success or negative error code + */ +int restart_handler_register(struct restart_handler *rst) +{ + if (!rst->name) + rst->name = RESTART_DEFAULT_NAME; + if (!rst->priority) + rst->priority = RESTART_DEFAULT_PRIORITY; + + list_add_tail(&rst->list, &restart_handler_list); + + pr_debug("registering restart handler \"%s\" with priority %d\n", + rst->name, rst->priority); + + return 0; +} + +/** + * restart_handler_register_fn() - register a handler function + * @restart_fn: The restart function + * + * convenience wrapper for restart_handler_register() to register a handler + * with given function and default values otherwise. + * + * return: 0 for success or negative error code + */ +int restart_handler_register_fn(void (*restart_fn)(struct restart_handler *)) +{ + struct restart_handler *rst; + int ret; + + rst = xzalloc(sizeof(*rst)); + + rst->restart = restart_fn; + + ret = restart_handler_register(rst); + + if (ret) + free(rst); + + return ret; +} + +/** + * restart_machine() - reset the whole system + */ +void __noreturn restart_machine(void) +{ + struct restart_handler *rst = NULL, *tmp; + unsigned int priority = 0; + + list_for_each_entry(tmp, &restart_handler_list, list) { + if (tmp->priority > priority) { + priority = tmp->priority; + rst = tmp; + } + } + + if (rst) { + pr_debug("%s: using restart handler %s\n", __func__, rst->name); + console_flush(); + rst->restart(rst); + } + + hang(); +} + +/** + * of_get_restart_priority() - get the desired restart priority from device tree + * @node: The device_node to read the property from + * + * return: The priority + */ +unsigned int of_get_restart_priority(struct device_node *node) +{ + unsigned int priority = RESTART_DEFAULT_PRIORITY; + + of_property_read_u32(node, "restart-priority", &priority); + + return priority; +} diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c index 76879db1f1..bf28f7c22a 100644 --- a/drivers/usb/gadget/f_fastboot.c +++ b/drivers/usb/gadget/f_fastboot.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -520,7 +521,7 @@ static int fastboot_tx_print(struct f_fastboot *f_fb, const char *fmt, ...) static void compl_do_reset(struct usb_ep *ep, struct usb_request *req) { - reset_cpu(0); + restart_machine(); } static void cb_reboot(struct usb_ep *ep, struct usb_request *req, const char *cmd) diff --git a/drivers/watchdog/imxwd.c b/drivers/watchdog/imxwd.c index 9f09f6ecd0..4621d4125a 100644 --- a/drivers/watchdog/imxwd.c +++ b/drivers/watchdog/imxwd.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -33,6 +34,7 @@ struct imx_wd { void __iomem *base; struct device_d *dev; const struct imx_wd_ops *ops; + struct restart_handler restart; }; #define to_imx_wd(h) container_of(h, struct imx_wd, wd) @@ -121,12 +123,11 @@ static int imx_watchdog_set_timeout(struct watchdog *wd, unsigned timeout) return priv->ops->set_timeout(priv, timeout); } -static struct imx_wd *reset_wd; - -void __noreturn reset_cpu(unsigned long addr) +static void __noreturn imxwd_force_soc_reset(struct restart_handler *rst) { - if (reset_wd) - reset_wd->ops->set_timeout(reset_wd, -1); + struct imx_wd *priv = container_of(rst, struct imx_wd, restart); + + priv->ops->set_timeout(priv, -1); mdelay(1000); @@ -187,9 +188,6 @@ static int imx_wd_probe(struct device_d *dev) priv->wd.set_timeout = imx_watchdog_set_timeout; priv->dev = dev; - if (!reset_wd) - reset_wd = priv; - if (IS_ENABLED(CONFIG_WATCHDOG_IMX)) { ret = watchdog_register(&priv->wd); if (ret) @@ -206,14 +204,18 @@ static int imx_wd_probe(struct device_d *dev) dev->priv = priv; + priv->restart.name = "imxwd"; + priv->restart.restart = imxwd_force_soc_reset; + + restart_handler_register(&priv->restart); + return 0; error_unregister: if (IS_ENABLED(CONFIG_WATCHDOG_IMX)) watchdog_deregister(&priv->wd); on_error: - if (reset_wd && reset_wd != priv) - free(priv); + free(priv); return ret; } diff --git a/drivers/watchdog/jz4740.c b/drivers/watchdog/jz4740.c index 8ac51e060a..3d45b46ee2 100644 --- a/drivers/watchdog/jz4740.c +++ b/drivers/watchdog/jz4740.c @@ -16,6 +16,7 @@ #include #include +#include #include #define JZ_REG_WDT_TIMER_DATA 0x0 @@ -39,33 +40,30 @@ #define JZ_EXTAL 24000000 struct jz4740_wdt_drvdata { + struct restart_handler restart; void __iomem *base; }; -static struct jz4740_wdt_drvdata *reset_wd; - -void __noreturn reset_cpu(unsigned long addr) +static void __noreturn jz4740_reset_soc(struct restart_handler *rst) { - if (reset_wd) { - void __iomem *base = reset_wd->base; + struct jz4740_wdt_drvdata *priv = + container_of(rst, struct jz4740_wdt_drvdata, restart); + void __iomem *base = priv->base; - writew(JZ_WDT_CLOCK_DIV_4 | JZ_WDT_CLOCK_EXT, - base + JZ_REG_WDT_TIMER_CONTROL); - writew(0, base + JZ_REG_WDT_TIMER_COUNTER); + writew(JZ_WDT_CLOCK_DIV_4 | JZ_WDT_CLOCK_EXT, + base + JZ_REG_WDT_TIMER_CONTROL); + writew(0, base + JZ_REG_WDT_TIMER_COUNTER); - /* reset after 4ms */ - writew(JZ_EXTAL / 1000, base + JZ_REG_WDT_TIMER_DATA); + /* reset after 4ms */ + writew(JZ_EXTAL / 1000, base + JZ_REG_WDT_TIMER_DATA); - /* start wdt */ - writeb(0x1, base + JZ_REG_WDT_COUNTER_ENABLE); + /* start wdt */ + writeb(0x1, base + JZ_REG_WDT_COUNTER_ENABLE); - mdelay(1000); - } else - pr_err("%s: can't reset cpu\n", __func__); + mdelay(1000); hang(); } -EXPORT_SYMBOL(reset_cpu); static int jz4740_wdt_probe(struct device_d *dev) { @@ -78,11 +76,12 @@ static int jz4740_wdt_probe(struct device_d *dev) return -ENODEV; } - if (!reset_wd) - reset_wd = priv; - dev->priv = priv; + priv->restart.name = "jz4740-wdt"; + priv->restart.restart = jz4740_reset_soc; + restart_handler_register(&priv->restart); + return 0; } diff --git a/include/common.h b/include/common.h index 6b9dd4d799..553a7f4f44 100644 --- a/include/common.h +++ b/include/common.h @@ -67,7 +67,6 @@ int readline (const char *prompt, char *buf, int len); long get_ram_size (volatile long *, long); /* $(CPU)/cpu.c */ -void __noreturn reset_cpu(unsigned long addr); void __noreturn poweroff(void); /* lib_$(ARCH)/time.c */ diff --git a/include/restart.h b/include/restart.h new file mode 100644 index 0000000000..79b57c8e11 --- /dev/null +++ b/include/restart.h @@ -0,0 +1,21 @@ +#ifndef __INCLUDE_RESTART_H +#define __INCLUDE_RESTART_H + +void __noreturn restart_machine(void); + +struct restart_handler { + void (*restart)(struct restart_handler *); + int priority; + const char *name; + struct list_head list; +}; + +int restart_handler_register(struct restart_handler *); +int restart_handler_register_fn(void (*restart_fn)(struct restart_handler *)); + +#define RESTART_DEFAULT_PRIORITY 100 +#define RESTART_DEFAULT_NAME "default" + +unsigned int of_get_restart_priority(struct device_node *node); + +#endif /* __INCLUDE_RESTART_H */ -- cgit v1.2.3 From 8f4cf30903cf6daaed0be1e8911363a3984abf72 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 26 Aug 2015 09:48:05 +0200 Subject: watchdog: Allow multiple watchdogs Put watchdogs on a list to allow multiple watchdogs. Add a priority field to be able to pick the highest priority watchdog. This patch also provides a of_get_watchdog_priority() function to allow configuring the watchdog priority from the device tree. Signed-off-by: Sascha Hauer --- drivers/watchdog/wd_core.c | 57 ++++++++++++++++++++++++++++++++++++---------- include/watchdog.h | 6 +++++ 2 files changed, 51 insertions(+), 12 deletions(-) diff --git a/drivers/watchdog/wd_core.c b/drivers/watchdog/wd_core.c index 3d0cfc635d..b8473b7da3 100644 --- a/drivers/watchdog/wd_core.c +++ b/drivers/watchdog/wd_core.c @@ -11,6 +11,7 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +#define pr_fmt(fmt) "watchdog: " fmt #include #include @@ -18,40 +19,72 @@ #include #include -/* - * Note: this simple framework supports one watchdog only. - */ -static struct watchdog *watchdog; +static LIST_HEAD(watchdog_list); int watchdog_register(struct watchdog *wd) { - if (watchdog != NULL) - return -EBUSY; + if (!wd->priority) + wd->priority = WATCHDOG_DEFAULT_PRIORITY; + + list_add_tail(&wd->list, &watchdog_list); + + pr_debug("registering watchdog with priority %d\n", wd->priority); - watchdog = wd; return 0; } EXPORT_SYMBOL(watchdog_register); int watchdog_deregister(struct watchdog *wd) { - if (watchdog == NULL || wd != watchdog) - return -ENODEV; + list_del(&wd->list); - watchdog = NULL; return 0; } EXPORT_SYMBOL(watchdog_deregister); +static struct watchdog *watchdog_get_default(void) +{ + struct watchdog *tmp, *wd = NULL; + int priority = 0; + + list_for_each_entry(tmp, &watchdog_list, list) { + if (tmp->priority > priority) { + priority = tmp->priority; + wd = tmp; + } + } + + return wd; +} + /* * start, stop or retrigger the watchdog * timeout in [seconds]. timeout of '0' will disable the watchdog (if possible) */ int watchdog_set_timeout(unsigned timeout) { - if (watchdog == NULL) + struct watchdog *wd; + + wd = watchdog_get_default(); + + if (!wd) return -ENODEV; - return watchdog->set_timeout(watchdog, timeout); + return wd->set_timeout(wd, timeout); } EXPORT_SYMBOL(watchdog_set_timeout); + +/** + * of_get_watchdog_priority() - get the desired watchdog priority from device tree + * @node: The device_node to read the property from + * + * return: The priority + */ +unsigned int of_get_watchdog_priority(struct device_node *node) +{ + unsigned int priority = WATCHDOG_DEFAULT_PRIORITY; + + of_property_read_u32(node, "watchdog-priority", &priority); + + return priority; +} diff --git a/include/watchdog.h b/include/watchdog.h index 7e37b7c22a..a833aeae8c 100644 --- a/include/watchdog.h +++ b/include/watchdog.h @@ -15,6 +15,8 @@ struct watchdog { int (*set_timeout)(struct watchdog *, unsigned); + unsigned int priority; + struct list_head list; }; #ifdef CONFIG_WATCHDOG @@ -38,4 +40,8 @@ int watchdog_set_timeout(unsigned t) } #endif +#define WATCHDOG_DEFAULT_PRIORITY 100 + +unsigned int of_get_watchdog_priority(struct device_node *node); + #endif /* INCLUDE_WATCHDOG_H */ -- cgit v1.2.3 From 62fe28cf0b06ad526e5ef2fcfd3f02c20cfb0bd8 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 26 Aug 2015 12:05:07 +0200 Subject: watchdog: Give watchdogs a name This adds a dev and name member to struct watchdog which helps distinguishing between different watchdogs. Also add some debugging aids. Signed-off-by: Sascha Hauer --- drivers/watchdog/davinci_wdt.c | 1 + drivers/watchdog/im28wd.c | 1 + drivers/watchdog/imxwd.c | 1 + drivers/watchdog/wd_core.c | 15 ++++++++++++++- include/watchdog.h | 2 ++ 5 files changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/watchdog/davinci_wdt.c b/drivers/watchdog/davinci_wdt.c index ecf6e89b47..dfabee230c 100644 --- a/drivers/watchdog/davinci_wdt.c +++ b/drivers/watchdog/davinci_wdt.c @@ -147,6 +147,7 @@ static int davinci_wdt_probe(struct device_d *dev) clk_enable(davinci_wdt->clk); davinci_wdt->wd.set_timeout = davinci_wdt_set_timeout; + davinci_wdt->wd.dev = dev; ret = watchdog_register(&davinci_wdt->wd); if (ret < 0) diff --git a/drivers/watchdog/im28wd.c b/drivers/watchdog/im28wd.c index a9093a7b51..3510776a3a 100644 --- a/drivers/watchdog/im28wd.c +++ b/drivers/watchdog/im28wd.c @@ -197,6 +197,7 @@ static int imx28_wd_probe(struct device_d *dev) if (IS_ERR(priv->regs)) return PTR_ERR(priv->regs); priv->wd.set_timeout = imx28_watchdog_set_timeout; + priv->wd.dev = dev; if (!(readl(priv->regs + MXS_RTC_STAT) & MXS_RTC_STAT_WD_PRESENT)) { rc = -ENODEV; diff --git a/drivers/watchdog/imxwd.c b/drivers/watchdog/imxwd.c index 4621d4125a..dd11a62613 100644 --- a/drivers/watchdog/imxwd.c +++ b/drivers/watchdog/imxwd.c @@ -186,6 +186,7 @@ static int imx_wd_probe(struct device_d *dev) } priv->ops = ops; priv->wd.set_timeout = imx_watchdog_set_timeout; + priv->wd.dev = dev; priv->dev = dev; if (IS_ENABLED(CONFIG_WATCHDOG_IMX)) { diff --git a/drivers/watchdog/wd_core.c b/drivers/watchdog/wd_core.c index b8473b7da3..3a3f519648 100644 --- a/drivers/watchdog/wd_core.c +++ b/drivers/watchdog/wd_core.c @@ -21,6 +21,16 @@ static LIST_HEAD(watchdog_list); +static const char *watchdog_name(struct watchdog *wd) +{ + if (wd->dev) + return dev_name(wd->dev); + if (wd->name) + return wd->name; + + return "unknown"; +} + int watchdog_register(struct watchdog *wd) { if (!wd->priority) @@ -28,7 +38,8 @@ int watchdog_register(struct watchdog *wd) list_add_tail(&wd->list, &watchdog_list); - pr_debug("registering watchdog with priority %d\n", wd->priority); + pr_debug("registering watchdog %s with priority %d\n", watchdog_name(wd), + wd->priority); return 0; } @@ -70,6 +81,8 @@ int watchdog_set_timeout(unsigned timeout) if (!wd) return -ENODEV; + pr_debug("setting timeout on %s to %ds\n", watchdog_name(wd), timeout); + return wd->set_timeout(wd, timeout); } EXPORT_SYMBOL(watchdog_set_timeout); diff --git a/include/watchdog.h b/include/watchdog.h index a833aeae8c..fd24b5b79e 100644 --- a/include/watchdog.h +++ b/include/watchdog.h @@ -15,6 +15,8 @@ struct watchdog { int (*set_timeout)(struct watchdog *, unsigned); + const char *name; + struct device_d *dev; unsigned int priority; struct list_head list; }; -- cgit v1.2.3 From ff2a4a0a138d6cb6addb5a855ea57a0332626d3c Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 26 Aug 2015 12:01:04 +0200 Subject: reset-source: Use globalvar_add_simple_enum Signed-off-by: Sascha Hauer --- common/reset_source.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/common/reset_source.c b/common/reset_source.c index 80002a93e6..f9ee99b933 100644 --- a/common/reset_source.c +++ b/common/reset_source.c @@ -40,15 +40,13 @@ EXPORT_SYMBOL(reset_source_get); void reset_source_set(enum reset_src_type st) { reset_source = st; - - globalvar_add_simple("system.reset", reset_src_names[reset_source]); } EXPORT_SYMBOL(reset_source_set); -/* ensure this runs after the 'global' device is already registerd */ static int reset_source_init(void) { - reset_source_set(reset_source); + globalvar_add_simple_enum("system.reset", (unsigned int *)&reset_source, + reset_src_names, ARRAY_SIZE(reset_src_names)); return 0; } -- cgit v1.2.3 From 4a7534bf07ee0fb56cf48501d988234382567481 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 26 Aug 2015 10:13:22 +0200 Subject: reset-source: Allow different priorities Different devices may report the reset source with different levels of certainty. For example a SoC may see a power-on reset, but this may only be because an external PMIC has power cycled the SoC. This means the PMIC knows the real reason better and thus the reset reason from the PMIC should be preferred. This patch introduces priorities for the reset_source to handle the above scenario. Also add a of_get_reset_source_priority() function to retrieve the desired priority from the device tree. Signed-off-by: Sascha Hauer --- common/reset_source.c | 23 ++++++++++++++++++++++- include/reset_source.h | 14 ++++++++++++-- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/common/reset_source.c b/common/reset_source.c index f9ee99b933..b02a694f9d 100644 --- a/common/reset_source.c +++ b/common/reset_source.c @@ -30,6 +30,7 @@ static const char * const reset_src_names[] = { }; static enum reset_src_type reset_source; +static unsigned int reset_source_priority; enum reset_src_type reset_source_get(void) { @@ -37,9 +38,13 @@ enum reset_src_type reset_source_get(void) } EXPORT_SYMBOL(reset_source_get); -void reset_source_set(enum reset_src_type st) +void reset_source_set_priority(enum reset_src_type st, unsigned int priority) { + if (priority <= reset_source_priority) + return; + reset_source = st; + reset_source_priority = priority; } EXPORT_SYMBOL(reset_source_set); @@ -52,3 +57,19 @@ static int reset_source_init(void) } coredevice_initcall(reset_source_init); + +/** + * of_get_reset_source_priority() - get the desired reset source priority from + * device tree + * @node: The device_node to read the property from + * + * return: The priority + */ +unsigned int of_get_reset_source_priority(struct device_node *node) +{ + unsigned int priority = RESET_SOURCE_DEFAULT_PRIORITY; + + of_property_read_u32(node, "reset-source-priority", &priority); + + return priority; +} diff --git a/include/reset_source.h b/include/reset_source.h index 367f93b2ad..d484836dff 100644 --- a/include/reset_source.h +++ b/include/reset_source.h @@ -25,10 +25,11 @@ enum reset_src_type { }; #ifdef CONFIG_RESET_SOURCE -void reset_source_set(enum reset_src_type); +void reset_source_set_priority(enum reset_src_type, unsigned int priority); enum reset_src_type reset_source_get(void); #else -static inline void reset_source_set(enum reset_src_type unused) +static inline void reset_source_set_priority(enum reset_src_type type, + unsigned int priority) { } @@ -38,4 +39,13 @@ static inline enum reset_src_type reset_source_get(void) } #endif +#define RESET_SOURCE_DEFAULT_PRIORITY 100 + +static inline void reset_source_set(enum reset_src_type type) +{ + reset_source_set_priority(type, RESET_SOURCE_DEFAULT_PRIORITY); +} + +unsigned int of_get_reset_source_priority(struct device_node *node); + #endif /* __INCLUDE_RESET_SOURCE_H */ -- cgit v1.2.3 From 96786e4dad75b307222afb0ee616b3d6b011fbe1 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 11 Jun 2015 15:48:43 +0200 Subject: mfd: da9063: add da9063 watchdog and system restart driver Signed-off-by: Philipp Zabel --- drivers/mfd/Kconfig | 4 ++ drivers/mfd/Makefile | 1 + drivers/mfd/da9063.c | 169 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 174 insertions(+) create mode 100644 drivers/mfd/da9063.c diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 3af904dd6d..3eb26b53fe 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -4,6 +4,10 @@ config MFD_ACT8846 depends on I2C bool "ACT8846 driver" +config MFD_DA9063 + depends on I2C + bool "DA9063 PMIC driver" + config MFD_LP3972 depends on I2C bool "LP3972 driver" diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 49b9e35663..4eed247c69 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -1,4 +1,5 @@ obj-$(CONFIG_MFD_ACT8846) += act8846.o +obj-$(CONFIG_MFD_DA9063) += da9063.o obj-$(CONFIG_MFD_LP3972) += lp3972.o obj-$(CONFIG_MFD_MC13XXX) += mc13xxx.o obj-$(CONFIG_MFD_MC34704) += mc34704.o diff --git a/drivers/mfd/da9063.c b/drivers/mfd/da9063.c new file mode 100644 index 0000000000..4a335c9983 --- /dev/null +++ b/drivers/mfd/da9063.c @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2015 Pengutronix, Philipp Zabel + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct da9063 { + struct restart_handler restart; + struct watchdog wd; + struct i2c_client *client; + struct device_d *dev; +}; + +/* System Control and Event Registers */ +#define DA9063_REG_FAULT_LOG 0x05 +#define DA9063_REG_CONTROL_D 0x11 +#define DA9063_REG_CONTROL_F 0x13 + +/* DA9063_REG_FAULT_LOG (addr=0x05) */ +#define DA9063_TWD_ERROR 0x01 +#define DA9063_POR 0x02 +#define DA9063_NSHUTDOWN 0x40 + +/* DA9063_REG_CONTROL_D (addr=0x11) */ +#define DA9063_TWDSCALE_MASK 0x07 + +/* DA9063_REG_CONTROL_F (addr=0x13) */ +#define DA9063_SHUTDOWN 0x02 + +static int da9063_watchdog_set_timeout(struct watchdog *wd, unsigned timeout) +{ + struct da9063 *priv = container_of(wd, struct da9063, wd); + struct device_d *dev = priv->dev; + unsigned int scale = 0; + int ret; + u8 val; + + if (timeout > 131) + return -EINVAL; + + if (timeout) { + timeout *= 1000; /* convert to ms */ + scale = 0; + while (timeout > (2048 << scale) && scale <= 6) + scale++; + dev_dbg(dev, "calculated TWDSCALE=%u (req=%ims calc=%ims)\n", + scale, timeout, 2048 << scale); + scale++; /* scale 0 disables the WD */ + } + + ret = i2c_read_reg(priv->client, DA9063_REG_CONTROL_D, &val, 1); + if (ret < 0) + return ret; + + val &= ~DA9063_TWDSCALE_MASK; + val |= scale; + + ret = i2c_write_reg(priv->client, DA9063_REG_CONTROL_D, &val, 1); + if (ret < 0) + return ret; + + return 0; +} + +static void da9063_detect_reset_source(struct da9063 *priv) +{ + int ret; + u8 val; + unsigned int priority; + enum reset_src_type type; + + ret = i2c_read_reg(priv->client, DA9063_REG_FAULT_LOG, &val, 1); + if (ret < 0) + return; + + /* Write one to clear */ + i2c_write_reg(priv->client, DA9063_REG_FAULT_LOG, &val, 1); + + if (val & DA9063_TWD_ERROR) + type = RESET_WDG; + else if (val & DA9063_POR) + type = RESET_POR; + else if (val & DA9063_NSHUTDOWN) + type = RESET_RST; + else + return; + + priority = of_get_reset_source_priority(priv->dev->device_node); + + reset_source_set_priority(type, priority); +} + +static void da9063_restart(struct restart_handler *rst) +{ + struct da9063 *priv = container_of(rst, struct da9063, restart); + + u8 val = DA9063_SHUTDOWN; + + i2c_write_reg(priv->client, DA9063_REG_CONTROL_F, &val, 1); +} + +static int da9063_probe(struct device_d *dev) +{ + struct da9063 *priv = NULL; + int ret; + + priv = xzalloc(sizeof(struct da9063)); + priv->wd.priority = of_get_watchdog_priority(dev->device_node); + priv->wd.set_timeout = da9063_watchdog_set_timeout; + priv->wd.dev = dev; + priv->client = to_i2c_client(dev); + priv->dev = dev; + + ret = watchdog_register(&priv->wd); + if (ret) + goto on_error; + + da9063_detect_reset_source(priv); + + priv->restart.priority = of_get_restart_priority(dev->device_node); + priv->restart.name = "da9063"; + priv->restart.restart = &da9063_restart; + + restart_handler_register(&priv->restart); + + return 0; + +on_error: + if (priv) + free(priv); + return ret; +} + +static struct platform_device_id da9063_id[] = { + { "da9063", }, + { } +}; + +static struct driver_d da9063_driver = { + .name = "da9063", + .probe = da9063_probe, + .id_table = da9063_id, +}; + +static int da9063_init(void) +{ + return i2c_driver_register(&da9063_driver); +} + +device_initcall(da9063_init); -- cgit v1.2.3 From 87af8d8dd44c7a3fac2b36298b698a1766ba655e Mon Sep 17 00:00:00 2001 From: Juergen Borleis Date: Thu, 25 Jun 2015 09:34:37 +0200 Subject: mfd: da9053: add da9053 watchdog and system restart driver Signed-off-by: Jan Luebbe Signed-off-by: Juergen Borleis Signed-off-by: Sascha Hauer --- drivers/mfd/Kconfig | 7 ++ drivers/mfd/Makefile | 1 + drivers/mfd/da9053.c | 308 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 316 insertions(+) create mode 100644 drivers/mfd/da9053.c diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 3eb26b53fe..417c9ce96c 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -4,6 +4,13 @@ config MFD_ACT8846 depends on I2C bool "ACT8846 driver" +config MFD_DA9053 + depends on I2C + bool "DA9053 PMIC driver" + help + This power management controller provides configurable power supplies, + a machine restart feature and a watchdog. + config MFD_DA9063 depends on I2C bool "DA9063 PMIC driver" diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 4eed247c69..041915a7c6 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -1,4 +1,5 @@ obj-$(CONFIG_MFD_ACT8846) += act8846.o +obj-$(CONFIG_MFD_DA9053) += da9053.o obj-$(CONFIG_MFD_DA9063) += da9063.o obj-$(CONFIG_MFD_LP3972) += lp3972.o obj-$(CONFIG_MFD_MC13XXX) += mc13xxx.o diff --git a/drivers/mfd/da9053.c b/drivers/mfd/da9053.c new file mode 100644 index 0000000000..3fb5295cf9 --- /dev/null +++ b/drivers/mfd/da9053.c @@ -0,0 +1,308 @@ +/* + * Copyright (C) 2013 Jan Luebbe + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * 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. + * + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define DRIVERNAME "da9053" + +/* STATUS REGISTERS */ +#define DA9053_STATUS_A_REG 1 +#define DA9053_STATUS_B_REG 2 +#define DA9053_STATUS_C_REG 3 +#define DA9053_STATUS_D_REG 4 + +/* PARK REGISTER */ +#define DA9053_PARK_REGISTER DA9053_STATUS_D_REG + +/* EVENT REGISTERS */ +#define DA9053_EVENT_A_REG 5 +#define DA9053_EVENT_B_REG 6 +#define DA9053_EVENT_C_REG 7 +#define DA9053_EVENT_D_REG 8 +#define DA9053_FAULTLOG_REG 9 + +/* IRQ REGISTERS */ +#define DA9053_IRQ_MASK_A_REG 10 +#define DA9053_IRQ_MASK_B_REG 11 +#define DA9053_IRQ_MASK_C_REG 12 +#define DA9053_IRQ_MASK_D_REG 13 + +/* CONTROL REGISTERS */ +#define DA9053_CONTROL_A_REG 14 +#define DA9053_CONTROL_B_REG 15 +#define DA9053_CONTROL_C_REG 16 +#define DA9053_CONTROL_D_REG 17 + +#define DA9053_PDDIS_REG 18 +#define DA9053_INTERFACE_REG 19 +#define DA9053_RESET_REG 20 + +/* FAULT LOG REGISTER BITS */ +#define DA9053_FAULTLOG_WAITSET 0X80 +#define DA9053_FAULTLOG_NSDSET 0X40 +#define DA9053_FAULTLOG_KEYSHUT 0X20 +#define DA9053_FAULTLOG_TEMPOVER 0X08 +#define DA9053_FAULTLOG_VDDSTART 0X04 +#define DA9053_FAULTLOG_VDDFAULT 0X02 +#define DA9053_FAULTLOG_TWDERROR 0X01 + +/* CONTROL REGISTER B BITS */ +#define DA9053_CONTROLB_SHUTDOWN 0X80 +#define DA9053_CONTROLB_DEEPSLEEP 0X40 +#define DA9053_CONTROLB_WRITEMODE 0X20 +#define DA9053_CONTROLB_BBATEN 0X10 +#define DA9053_CONTROLB_OTPREADEN 0X08 +#define DA9053_CONTROLB_AUTOBOOT 0X04 +#define DA9053_CONTROLB_ACTDIODE 0X02 +#define DA9053_CONTROLB_BUCKMERGE 0X01 + +/* CONTROL REGISTER D BITS */ +#define DA9053_CONTROLD_WATCHDOG 0X80 +#define DA9053_CONTROLD_ACCDETEN 0X40 +#define DA9053_CONTROLD_GPI1415SD 0X20 +#define DA9053_CONTROLD_NONKEYSD 0X10 +#define DA9053_CONTROLD_KEEPACTEN 0X08 +#define DA9053_CONTROLD_TWDSCALE 0X07 + +struct da9053_priv { + struct watchdog wd; + struct i2c_client *client; + struct device_d *dev; + struct restart_handler restart; +}; + +#define wd_to_da9053_priv(x) container_of(x, struct da9053_priv, wd) + +static int da9053_reg_read(struct da9053_priv *da9053, u32 reg, u8 *val) +{ + int ret; + + ret = i2c_read_reg(da9053->client, reg, val, 1); + + return ret == 1 ? 0 : ret; +} + +static int da9053_reg_write(struct da9053_priv *da9053, u32 reg, u8 val) +{ + int ret; + + ret = i2c_write_reg(da9053->client, reg, &val, 1); + + return ret == 1 ? 0 : ret; +} + +static int da9053_park(struct da9053_priv *da9053) +{ + int ret; + u8 val; + + ret = i2c_read_reg(da9053->client, DA9053_PARK_REGISTER, &val, 1); + + return ret == 1 ? 0 : ret; +} + +static int da9053_enable_multiwrite(struct da9053_priv *da9053) +{ + int ret; + u8 val; + + ret = da9053_reg_read(da9053, DA9053_CONTROL_B_REG, &val); + if (ret < 0) + return ret; + + if (val & DA9053_CONTROLB_WRITEMODE) { + val &= ~DA9053_CONTROLB_WRITEMODE; + ret = da9053_reg_write(da9053, DA9053_CONTROL_B_REG, val); + if (ret < 0) + return ret; + } + + ret = da9053_park(da9053); + if (ret < 0) + return ret; + + return 0; +} + +static int da9053_set_timeout(struct watchdog *wd, unsigned timeout) +{ + struct da9053_priv *da9053 = wd_to_da9053_priv(wd); + struct device_d *dev = da9053->cdev.dev; + unsigned scale = 0; + int ret; + u8 val; + + if (timeout > 131) + return -EINVAL; + + if (timeout) { + timeout *= 1000; /* convert to ms */ + scale = 0; + while (timeout > (2048 << scale) && scale <= 6) + scale++; + dev_dbg(dev, "calculated TWDSCALE=%u (req=%ims calc=%ims)\n", + scale, timeout, 2048 << scale); + scale++; /* scale 0 disables the WD */ + } + + ret = da9053_reg_read(da9053, DA9053_CONTROL_D_REG, &val); + if (ret < 0) + return ret; + + dev_dbg(dev, "read watchdog (val=0x%02x)\n", val); + + if (scale && scale == (val & DA9053_CONTROLD_TWDSCALE)) { + /* trigger WD */ + val |= DA9053_CONTROLD_WATCHDOG; + ret = da9053_reg_write(da9053, DA9053_CONTROL_D_REG, val); + if (ret < 0) + return ret; + dev_dbg(dev, "triggered watchdog (val=0x%02x)\n", val); + } else { + /* disable WD first */ + val &= ~DA9053_CONTROLD_TWDSCALE; + ret = da9053_reg_write(da9053, DA9053_CONTROL_D_REG, val); + if (ret < 0) + return ret; + + dev_dbg(dev, "disabled watchdog (val=0x%02x)\n", val); + if (scale) { + /* park before waiting */ + ret = da9053_park(da9053); + if (ret < 0) + return ret; + + /* wait required time */ + udelay(150); + + /* enable WD with new timeout */ + val |= scale; + ret = da9053_reg_write(da9053, DA9053_CONTROL_D_REG, val); + if (ret < 0) + return ret; + dev_dbg(dev, "enabled watchdog (val=0x%02x)\n", val); + } + } + + ret = da9053_park(da9053); + if (ret < 0) + return ret; + + return 0; +} + +static void da9053_detect_reset_source(struct da9053_priv *da9053) +{ + unsigned int priority; + enum reset_src_type type; + int ret; + u8 val; + + ret = da9053_reg_read(da9053, DA9053_FAULTLOG_REG, &val); + if (ret < 0) + return; + + ret = da9053_park(da9053); + if (ret < 0) + return; + + if (val & DA9053_FAULTLOG_TWDERROR) + type = RESET_WDG; + else if (val & DA9053_FAULTLOG_VDDFAULT) + type = RESET_POR; + else if (val & DA9053_FAULTLOG_NSDSET) + type = RESET_RST; + else + return; + + priority = of_get_reset_source_priority(da9053->dev->device_node); + + reset_source_set_priority(type, priority); +} + +static void __noreturn da9053_force_system_reset(struct restart_handler *rst) +{ + struct da9053_priv *da9053 = container_of(rst, struct da9053_priv, restart); + u8 val; + int ret; + + ret = da9053_reg_read(da9053, DA9053_CONTROL_B_REG, &val); + if (ret < 0) + hang(); + + val |= DA9053_CONTROLB_SHUTDOWN; + ret = da9053_reg_write(da9053, DA9053_CONTROL_B_REG, val); + if (ret < 0) + hang(); + + da9053_park(da9053); + + hang(); +} + +static int da9053_probe(struct device_d *dev) +{ + struct da9053_priv *da9053; + int ret; + + da9053 = xzalloc(sizeof(*da9053)); + da9053->dev = dev; + da9053->cdev.name = DRIVERNAME; + da9053->client = to_i2c_client(dev); + da9053->wd.set_timeout = da9053_set_timeout; + da9053->wd.priority = of_get_watchdog_priority(dev->device_node); + da9053->wd.dev = dev; + + ret = da9053_enable_multiwrite(da9053); + if (ret < 0) + return ret; + + ret = watchdog_register(&da9053->wd); + if (ret) + return ret; + + da9053_detect_reset_source(da9053); + + da9053->restart.priority = of_get_restart_priority(dev->device_node); + da9053->restart.name = "da9063"; + da9053->restart.restart = &da9053_force_system_reset; + + restart_handler_register(&da9053->restart); + + return 0; +} + +static struct driver_d da9053_driver = { + .name = DRIVERNAME, + .probe = da9053_probe, +}; + +static int da9053_init(void) +{ + i2c_driver_register(&da9053_driver); + return 0; +} + +device_initcall(da9053_init); -- cgit v1.2.3 From ce36b4a05e275dcc12e74e96ddae99c21faad466 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 26 Aug 2015 12:01:51 +0200 Subject: reset-source: Add some debugging aids Signed-off-by: Sascha Hauer --- common/reset_source.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/common/reset_source.c b/common/reset_source.c index b02a694f9d..0a69f90a6e 100644 --- a/common/reset_source.c +++ b/common/reset_source.c @@ -11,6 +11,7 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +#define pr_fmt(fmt) "reset-source: " fmt #include #include @@ -45,6 +46,9 @@ void reset_source_set_priority(enum reset_src_type st, unsigned int priority) reset_source = st; reset_source_priority = priority; + + pr_debug("Setting reset source to %s with priority %d\n", + reset_src_names[reset_source], priority); } EXPORT_SYMBOL(reset_source_set); -- cgit v1.2.3