Skip to content

Commit

Permalink
ARM: bcm2835: implement machine restart hook
Browse files Browse the repository at this point in the history
Implement the machine restart hook using the SoC's watchdog timer module.
To support this, define a DT binding for the watchdog module, and add it
to the device tree.

The downstream rpi-split branch contains a full watchdog timer driver
implementation, which also implements the restart hook. However, the
restart function is largely separate from the watchdog driver, so for
simplicity, the restart hook is implemented here directly in the main
machine source file.

Overall structure (separate setup/restart) functions derived from the
picoxcell ARM support.

Watchdog register IO sequence taken from code by Simon Arlott. Note that
the watchdog module is not documented in BCM2835-ARM-Peripherals.pdf.

Signed-off-by: Stephen Warren <swarren@wwwdotorg.org>
  • Loading branch information
Stephen Warren committed Oct 26, 2012
1 parent 6f0c058 commit d0f1c7f
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
BCM2835 Watchdog timer

Required properties:

- compatible : should be "brcm,bcm2835-pm-wdt"
- reg : Specifies base physical address and size of the registers.

Example:

watchdog {
compatible = "brcm,bcm2835-pm-wdt";
reg = <0x7e100000 0x28>;
};
5 changes: 5 additions & 0 deletions arch/arm/boot/dts/bcm2835.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@
#interrupt-cells = <2>;
};

watchdog {
compatible = "brcm,bcm2835-pm-wdt";
reg = <0x7e100000 0x28>;
};

uart@20201000 {
compatible = "brcm,bcm2835-pl011", "arm,pl011", "arm,primecell";
reg = <0x7e201000 0x1000>;
Expand Down
46 changes: 46 additions & 0 deletions arch/arm/mach-bcm2835/bcm2835.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@
* GNU General Public License for more details.
*/

#include <linux/delay.h>
#include <linux/init.h>
#include <linux/irqchip/bcm2835.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/bcm2835_timer.h>
#include <linux/clk/bcm2835.h>
Expand All @@ -23,6 +25,48 @@

#include <mach/bcm2835_soc.h>

#define PM_RSTC 0x1c
#define PM_WDOG 0x24

#define PM_PASSWORD 0x5a000000
#define PM_RSTC_WRCFG_MASK 0x00000030
#define PM_RSTC_WRCFG_FULL_RESET 0x00000020

static void __iomem *wdt_regs;

/*
* The machine restart method can be called from an atomic context so we won't
* be able to ioremap the regs then.
*/
static void bcm2835_setup_restart(void)
{
struct device_node *np = of_find_compatible_node(NULL, NULL,
"brcm,bcm2835-pm-wdt");
if (WARN(!np, "unable to setup watchdog restart"))
return;

wdt_regs = of_iomap(np, 0);
WARN(!wdt_regs, "failed to remap watchdog regs");
}

static void bcm2835_restart(char mode, const char *cmd)
{
u32 val;

if (!wdt_regs)
return;

/* use a timeout of 10 ticks (~150us) */
writel_relaxed(10 | PM_PASSWORD, wdt_regs + PM_WDOG);
val = readl_relaxed(wdt_regs + PM_RSTC);
val &= ~PM_RSTC_WRCFG_MASK;
val |= PM_PASSWORD | PM_RSTC_WRCFG_FULL_RESET;
writel_relaxed(val, wdt_regs + PM_RSTC);

/* No sleeping, possibly atomic. */
mdelay(1);
}

static struct map_desc io_map __initdata = {
.virtual = BCM2835_PERIPH_VIRT,
.pfn = __phys_to_pfn(BCM2835_PERIPH_PHYS),
Expand All @@ -39,6 +83,7 @@ void __init bcm2835_init(void)
{
int ret;

bcm2835_setup_restart();
bcm2835_init_clocks();

ret = of_platform_populate(NULL, of_default_bus_match_table, NULL,
Expand All @@ -60,5 +105,6 @@ DT_MACHINE_START(BCM2835, "BCM2835")
.handle_irq = bcm2835_handle_irq,
.init_machine = bcm2835_init,
.timer = &bcm2835_timer,
.restart = bcm2835_restart,
.dt_compat = bcm2835_compat
MACHINE_END

0 comments on commit d0f1c7f

Please sign in to comment.