2010-12-22 10:56:17 +08:00
|
|
|
/*
|
|
|
|
* OMAP2+ MPU WD_TIMER-specific code
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/io.h>
|
|
|
|
#include <linux/err.h>
|
|
|
|
|
|
|
|
#include <plat/omap_hwmod.h>
|
|
|
|
|
2011-01-07 11:49:29 +08:00
|
|
|
#include "wd_timer.h"
|
|
|
|
|
2010-12-22 10:56:17 +08:00
|
|
|
/*
|
|
|
|
* In order to avoid any assumptions from bootloader regarding WDT
|
|
|
|
* settings, WDT module is reset during init. This enables the watchdog
|
|
|
|
* timer. Hence it is required to disable the watchdog after the WDT reset
|
|
|
|
* during init. Otherwise the system would reboot as per the default
|
|
|
|
* watchdog timer registers settings.
|
|
|
|
*/
|
|
|
|
#define OMAP_WDT_WPS 0x34
|
|
|
|
#define OMAP_WDT_SPR 0x48
|
|
|
|
|
|
|
|
|
|
|
|
int omap2_wd_timer_disable(struct omap_hwmod *oh)
|
|
|
|
{
|
|
|
|
void __iomem *base;
|
|
|
|
|
|
|
|
if (!oh) {
|
|
|
|
pr_err("%s: Could not look up wdtimer_hwmod\n", __func__);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
base = omap_hwmod_get_mpu_rt_va(oh);
|
|
|
|
if (!base) {
|
|
|
|
pr_err("%s: Could not get the base address for %s\n",
|
|
|
|
oh->name, __func__);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* sequence required to disable watchdog */
|
|
|
|
__raw_writel(0xAAAA, base + OMAP_WDT_SPR);
|
|
|
|
while (__raw_readl(base + OMAP_WDT_WPS) & 0x10)
|
|
|
|
cpu_relax();
|
|
|
|
|
|
|
|
__raw_writel(0x5555, base + OMAP_WDT_SPR);
|
|
|
|
while (__raw_readl(base + OMAP_WDT_WPS) & 0x10)
|
|
|
|
cpu_relax();
|
|
|
|
|
OMAP2+: wd_timer: disable on boot via hwmod postsetup mechanism
The OMAP watchdog timer IP blocks require a specific set of register
writes to occur before they will be disabled[1], even if the device
clocks appear to be disabled in the CM_*CLKEN registers. In the MPU
watchdog case, failure to execute this reset sequence will eventually
cause the watchdog to reset the OMAP unexpectedly.
Previously, the code to disable this watchdog was manually called from
mach-omap2/devices.c during device initialization. This causes the
watchdog to be unconditionally disabled for a portion of kernel
initialization. This should be controllable by the board-*.c files,
since some system integrators will want full watchdog coverage of
kernel initialization. Also, the watchdog disable code was not
connected to the hwmod shutdown code. This means that calling
omap_hwmod_shutdown() will not, in fact, disable the watchdog, and the
goal of omap_hwmod_shutdown() is to be able to shutdown any on-chip
OMAP device.
To resolve the latter problem, populate the pre_shutdown pointer in
the watchdog timer hwmod classes with a function that executes the
watchdog shutdown sequence. This allows the hwmod code to fully
disable the watchdog.
Then, to allow some board files to support watchdog coverage
throughout kernel initialization, add common code to mach-omap2/io.c
to cause the MPU watchdog to be disabled on boot unless a board file
specifically requests it to remain enabled. Board files can do this
by changing the watchdog timer hwmod's postsetup state between the
omap2_init_common_infrastructure() and omap2_init_common_devices()
function calls.
1. OMAP34xx Multimedia Device Silicon Revision 3.1.x Rev. ZH
[SWPU222H], Section 16.4.3.6, "Start/Stop Sequence for WDTs (Using
WDTi.WSPR Register)"
Signed-off-by: Paul Walmsley <paul@pwsan.com>
Cc: Benoît Cousson <b-cousson@ti.com>
Cc: Kevin Hilman <khilman@deeprootsystems.com>
Cc: Charulatha Varadarajan <charu@ti.com>
2010-12-22 06:39:15 +08:00
|
|
|
return 0;
|
2010-12-22 10:56:17 +08:00
|
|
|
}
|
|
|
|
|