diff --git a/arch/arm/lib/bootm.c b/arch/arm/lib/bootm.c index 8327c3f..7bb9b43 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 @@ start_linux((void *)kernel, swap, initrd_start, initrd_size, data->oftree); - reset_cpu(0); + restart_machine(); return -ERESTARTSYS; } @@ -378,7 +379,7 @@ start_linux(barebox, 0, 0, 0, data->oftree); - reset_cpu(0); + restart_machine(); } static struct image_handler barebox_handler = { @@ -518,7 +519,7 @@ 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 ae0172b..fd11223 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 @@ /* * 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 @@ 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 3a3e77a..890545e 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 e70d733..2cb113c 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 2d18dd6..1baf732 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_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 341979a..1fa50ac 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 @@ } 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 @@ 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 5d08012..64f3781 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 @@ } 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 @@ } #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 @@ 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 859d8ae..03f40b7 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 @@ 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 60f0d19..4d1b570 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 @@ 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 @@ 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 820eb10..16a2186 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 b1caec0..0000000 --- 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 f396d0a..83c05ce 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 @@ 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 @@ writel(value, &syscon->devicecfg); /* Dying... */ - while (1) - ; /* noop */ + hang(); } -EXPORT_SYMBOL(reset_cpu); + +static int restart_register_feature(void) +{ + restart_handler_register_fn(ep92xx_restart_soc); + + return 0; +} +coredevice_initcall(restart_register_feature); diff --git a/arch/arm/mach-highbank/reset.c b/arch/arm/mach-highbank/reset.c index b9664e4..929ded5 100644 --- a/arch/arm/mach-highbank/reset.c +++ b/arch/arm/mach-highbank/reset.c @@ -6,18 +6,28 @@ #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() { shutdown_barebox(); diff --git a/arch/arm/mach-mvebu/armada-370-xp.c b/arch/arm/mach-mvebu/armada-370-xp.c index 2405629..c362cfd 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 @@ 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 @@ 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 7d28d9c..cb40d0c 100644 --- a/arch/arm/mach-mvebu/common.c +++ b/arch/arm/mach-mvebu/common.c @@ -123,16 +123,3 @@ 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 a7284fd..ba4af3a 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 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 @@ 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 5ce33fd..602af8f 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 19c6f07..72a6b0d 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 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 @@ 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 339c577..d471c8e 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 @@ 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 b4ec38d..dc6020a 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 @@ 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 6127dde..6c3b953 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 @@ return COMMAND_ERROR_USAGE; } -void __noreturn reset_cpu(unsigned long addr) -{ - SYSTEM_REG(SYSTEM_RES_CR) = 0x01000008; - - /* Not reached */ - while (1); -} - - 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 */ + hang(); +} + +static int restart_register_feature(void) +{ + restart_handler_register_fn(netx_restart_soc); + + return 0; +} +coredevice_initcall(restart_register_feature); diff --git a/arch/arm/mach-nomadik/reset.c b/arch/arm/mach-nomadik/reset.c index bb5696a..8bdaada 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 @@ 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 7ce32f0..ae0ee58 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 @@ { 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 03418b0..7e64e74 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_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 ab53b98..177862e 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_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 e246e36..7ec41d8 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 @@ 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 0f2e9ce..5c29fea 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 @@ { 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 0b683da..a3f370d 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 @@ { 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 334cf8d..165487c 100644 --- a/arch/arm/mach-omap/omap_generic.c +++ b/arch/arm/mach-omap/omap_generic.c @@ -150,17 +150,6 @@ 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 2c27d81..c0281d6 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 @@ 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 bab06df..2428fee 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 75965d7..4f13fce 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 @@ 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 a9e7e14..04522da 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 @@ } /* 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 @@ * 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 eaa5ac7..02f0bf7 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 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 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 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 f3cc668..16a2186 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 00ae0be..0000000 --- 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 c671aa6..7c6e952 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 @@ 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 @@ __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 @@ 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 ad6e06f..3164ae3 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 bd29e13..a0a8d0d 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 @@ 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 9d4c6e3..34b93e7 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 @@ ); /* 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 c2dda73..2111d25 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 @@ 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 @@ 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 d3f520f..ed449dc 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 @@ } 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 0e03aa9..84f72f5 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 @@ 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 0788add..318f772 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 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 a0e9b34..0665788 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 @@ * 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 00aee19..6287adb 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 8975392..7a8f1d6 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 f1dc68a..ff29cd5 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 fdbe9f9..b2164af 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 d73a418..d52b021 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 @@ 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 e25efec..409c0cf 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 @@ */ 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 3f826e4..33835e7 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 @@ /* ------------------------------------------------------------------------- */ -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 @@ /* 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 7c183c1..42464e8 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 @@ 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 4601163..333638c 100644 --- a/arch/sandbox/board/Makefile +++ b/arch/sandbox/board/Makefile @@ -4,5 +4,6 @@ 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 0000000..79bf79a --- /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 990173e..1e53f69 100644 --- a/arch/sandbox/mach-sandbox/include/mach/linux.h +++ b/arch/sandbox/mach-sandbox/include/mach/linux.h @@ -15,6 +15,7 @@ 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 d627391..67667d4 100644 --- a/arch/sandbox/os/common.c +++ b/arch/sandbox/os/common.c @@ -115,7 +115,7 @@ return now; } -void __attribute__((noreturn)) reset_cpu(unsigned long addr) +void __attribute__((noreturn)) linux_exit(void) { cookmode(); exit(0); @@ -133,7 +133,7 @@ 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 @@ 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 e46aa5b..225b481 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 65f7d35..0000000 --- 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 4f42b91..8300480 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 @@ if (shutdown_flag) shutdown_barebox(); - reset_cpu(0); + restart_machine(); /* Not reached */ return 1; diff --git a/common/Makefile b/common/Makefile index ed131c8..1e7a081 100644 --- a/common/Makefile +++ b/common/Makefile @@ -8,6 +8,7 @@ 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 6da71c7..5532349 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 @@ hang(); } else { udelay(100000); /* allow messages to go out */ - reset_cpu(0); + restart_machine(); } } EXPORT_SYMBOL(panic); diff --git a/common/reset_source.c b/common/reset_source.c index 80002a9..0a69f90 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 @@ -30,6 +31,7 @@ }; static enum reset_src_type reset_source; +static unsigned int reset_source_priority; enum reset_src_type reset_source_get(void) { @@ -37,20 +39,41 @@ } 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) { - reset_source = st; + if (priority <= reset_source_priority) + return; - globalvar_add_simple("system.reset", reset_src_names[reset_source]); + 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); -/* 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; } 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/common/restart.c b/common/restart.c new file mode 100644 index 0000000..8fd5ffd --- /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/mfd/Kconfig b/drivers/mfd/Kconfig index 3af904d..417c9ce 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -4,6 +4,17 @@ 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" + config MFD_LP3972 depends on I2C bool "LP3972 driver" diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 49b9e35..041915a 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -1,4 +1,6 @@ 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 obj-$(CONFIG_MFD_MC34704) += mc34704.o diff --git a/drivers/mfd/da9053.c b/drivers/mfd/da9053.c new file mode 100644 index 0000000..3fb5295 --- /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); diff --git a/drivers/mfd/da9063.c b/drivers/mfd/da9063.c new file mode 100644 index 0000000..4a335c9 --- /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); diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c index 76879db..bf28f7c 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 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/davinci_wdt.c b/drivers/watchdog/davinci_wdt.c index ecf6e89..dfabee2 100644 --- a/drivers/watchdog/davinci_wdt.c +++ b/drivers/watchdog/davinci_wdt.c @@ -147,6 +147,7 @@ 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 a9093a7..3510776 100644 --- a/drivers/watchdog/im28wd.c +++ b/drivers/watchdog/im28wd.c @@ -197,6 +197,7 @@ 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 5ffbac7..dd11a62 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 @@ 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 @@ 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); @@ -185,11 +186,9 @@ } priv->ops = ops; priv->wd.set_timeout = imx_watchdog_set_timeout; + priv->wd.dev = dev; priv->dev = dev; - if (!reset_wd) - reset_wd = priv; - if (IS_ENABLED(CONFIG_WATCHDOG_IMX)) { ret = watchdog_register(&priv->wd); if (ret) @@ -206,28 +205,21 @@ 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; } -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 +256,6 @@ 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, }; diff --git a/drivers/watchdog/jz4740.c b/drivers/watchdog/jz4740.c index 8ac51e0..3d45b46 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 @@ 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/drivers/watchdog/wd_core.c b/drivers/watchdog/wd_core.c index 3d0cfc6..3a3f519 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,85 @@ #include #include -/* - * Note: this simple framework supports one watchdog only. - */ -static struct watchdog *watchdog; +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 (watchdog != NULL) - return -EBUSY; + if (!wd->priority) + wd->priority = WATCHDOG_DEFAULT_PRIORITY; - watchdog = wd; + list_add_tail(&wd->list, &watchdog_list); + + pr_debug("registering watchdog %s with priority %d\n", watchdog_name(wd), + wd->priority); + 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); + pr_debug("setting timeout on %s to %ds\n", watchdog_name(wd), 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/common.h b/include/common.h index 6b9dd4d..553a7f4 100644 --- a/include/common.h +++ b/include/common.h @@ -67,7 +67,6 @@ 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/reset_source.h b/include/reset_source.h index 367f93b..d484836 100644 --- a/include/reset_source.h +++ b/include/reset_source.h @@ -25,10 +25,11 @@ }; #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 @@ } #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 */ diff --git a/include/restart.h b/include/restart.h new file mode 100644 index 0000000..79b57c8 --- /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 */ diff --git a/include/watchdog.h b/include/watchdog.h index 7a98ae4..6fd8967 100644 --- a/include/watchdog.h +++ b/include/watchdog.h @@ -15,6 +15,10 @@ struct watchdog { int (*set_timeout)(struct watchdog *, unsigned); + const char *name; + struct device_d *dev; + unsigned int priority; + struct list_head list; }; #ifdef CONFIG_WATCHDOG @@ -38,4 +42,8 @@ } #endif +#define WATCHDOG_DEFAULT_PRIORITY 100 + +unsigned int of_get_watchdog_priority(struct device_node *node); + #endif /* INCLUDE_WATCHDOG_H */