Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | /*
* Copyright (C) 2010 Broadcom
*
* 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 <linux/delay.h>
#include <linux/init.h>
#include <linux/irqchip.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/clk/bcm2835.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#define PM_RSTC 0x1c
#define PM_RSTS 0x20
#define PM_WDOG 0x24
#define PM_PASSWORD 0x5a000000
#define PM_RSTC_WRCFG_MASK 0x00000030
#define PM_RSTC_WRCFG_FULL_RESET 0x00000020
#define PM_RSTS_HADWRH_SET 0x00000040
#define BCM2835_PERIPH_PHYS 0x20000000
#define BCM2835_PERIPH_VIRT 0xf0000000
#define BCM2835_PERIPH_SIZE SZ_16M
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(enum reboot_mode 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);
}
/*
* We can't really power off, but if we do the normal reset scheme, and
* indicate to bootcode.bin not to reboot, then most of the chip will be
* powered off.
*/
static void bcm2835_power_off(void)
{
u32 val;
/*
* We set the watchdog hard reset bit here to distinguish this reset
* from the normal (full) reset. bootcode.bin will not reboot after a
* hard reset.
*/
val = readl_relaxed(wdt_regs + PM_RSTS);
val &= ~PM_RSTC_WRCFG_MASK;
val |= PM_PASSWORD | PM_RSTS_HADWRH_SET;
writel_relaxed(val, wdt_regs + PM_RSTS);
/* Continue with normal reset mechanism */
bcm2835_restart(REBOOT_HARD, "");
}
static struct map_desc io_map __initdata = {
.virtual = BCM2835_PERIPH_VIRT,
.pfn = __phys_to_pfn(BCM2835_PERIPH_PHYS),
.length = BCM2835_PERIPH_SIZE,
.type = MT_DEVICE
};
static void __init bcm2835_map_io(void)
{
iotable_init(&io_map, 1);
}
static void __init bcm2835_init(void)
{
int ret;
bcm2835_setup_restart();
if (wdt_regs)
pm_power_off = bcm2835_power_off;
bcm2835_init_clocks();
ret = of_platform_populate(NULL, of_default_bus_match_table, NULL,
NULL);
if (ret) {
pr_err("of_platform_populate failed: %d\n", ret);
BUG();
}
}
static const char * const bcm2835_compat[] = {
"brcm,bcm2835",
NULL
};
DT_MACHINE_START(BCM2835, "BCM2835")
.map_io = bcm2835_map_io,
.init_irq = irqchip_init,
.init_machine = bcm2835_init,
.restart = bcm2835_restart,
.dt_compat = bcm2835_compat
MACHINE_END
|