summaryrefslogtreecommitdiffstats
path: root/firmware/target/arm/imx233
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm/imx233')
-rw-r--r--firmware/target/arm/imx233/icoll-imx233.c3
-rw-r--r--firmware/target/arm/imx233/system-imx233.c52
-rw-r--r--firmware/target/arm/imx233/system-target.h3
-rw-r--r--firmware/target/arm/imx233/timrot-imx233.h1
4 files changed, 58 insertions, 1 deletions
diff --git a/firmware/target/arm/imx233/icoll-imx233.c b/firmware/target/arm/imx233/icoll-imx233.c
index e42e0f3291..e23af602db 100644
--- a/firmware/target/arm/imx233/icoll-imx233.c
+++ b/firmware/target/arm/imx233/icoll-imx233.c
@@ -146,6 +146,7 @@ struct imx233_icoll_irq_info_t imx233_icoll_get_irq_info(int src)
static void do_irq_stat(void)
{
+ imx233_keep_alive();
static unsigned counter = 0;
if(counter++ >= HZ)
{
@@ -180,6 +181,8 @@ void irq_handler(void)
asm volatile(
"sub lr, lr, #4 \n" /* Create return address */
"stmfd sp!, { r0-r5, r12, lr } \n" /* Save what gets clobbered */
+ "ldr r5, =0x8001c290 \n" /* Save pointer to instruction */
+ "str lr, [r5] \n" /* in HW_DIGCTL_SCRATCH0 */
"ldr r4, =0x80000000 \n" /* Read HW_ICOLL_VECTOR */
"ldr r0, [r4] \n" /* and notify as side-effect */
"mrs lr, spsr \n" /* Save SPSR_irq */
diff --git a/firmware/target/arm/imx233/system-imx233.c b/firmware/target/arm/imx233/system-imx233.c
index b25ccb5c47..5298f7cff9 100644
--- a/firmware/target/arm/imx233/system-imx233.c
+++ b/firmware/target/arm/imx233/system-imx233.c
@@ -45,6 +45,55 @@
#include "fmradio_i2c.h"
#include "powermgmt-imx233.h"
+#define WATCHDOG_HW_DELAY (10 * HZ)
+#define WATCHDOG_SW_DELAY (5 * HZ)
+
+static void woof_woof(void)
+{
+ /* stop hadrware watchdog, we catched the error */
+ imx233_rtc_enable_watchdog(false);
+ uint32_t pc = HW_DIGCTL_SCRATCH0;
+ /* write a "SWI #0xdead" instruction at the faulty instruction so that it
+ * will trigger a proper backtrace */
+ *(uint32_t *)pc = 0xef00dead;
+ commit_discard_idcache();
+}
+
+static void good_dog(void)
+{
+ imx233_rtc_reset_watchdog(WATCHDOG_HW_DELAY * 1000 / HZ); /* ms */
+ imx233_rtc_enable_watchdog(true);
+ imx233_timrot_setup(TIMER_WATCHDOG, false, WATCHDOG_SW_DELAY * 1000 / HZ,
+ BV_TIMROT_TIMCTRLn_SELECT__1KHZ_XTAL, BV_TIMROT_TIMCTRLn_PRESCALE__DIV_BY_1,
+ false, &woof_woof);
+ imx233_timrot_set_priority(TIMER_WATCHDOG, ICOLL_PRIO_WATCHDOG);
+}
+
+void imx233_keep_alive(void)
+{
+ /* setting up a timer is not exactly a cheap operation so only do so
+ * every second */
+ static uint32_t last_alive = 0;
+ if(imx233_us_elapsed(last_alive, 1000000))
+ {
+ good_dog();
+ last_alive = HW_DIGCTL_MICROSECONDS;
+ }
+}
+
+static void watchdog_init(void)
+{
+ /* setup two mechanisms:
+ * - hardware watchdog to reset the player after 10 seconds
+ * - software watchdog using a timer to panic after 5 seconds
+ * The hardware mechanism ensures reset when the player is completely
+ * dead and it actually resets the whole chip. On the contrary, the software
+ * mechanism allows partial recovery by panicing and printing (maybe) useful
+ * information, it uses a dedicated timer with the highest level of interrupt
+ * priority so it works even if the player is stuck in IRQ context */
+ good_dog();
+}
+
void imx233_chip_reset(void)
{
#if IMX233_SUBTARGET >= 3700
@@ -60,7 +109,6 @@ void system_reboot(void)
disable_irq();
- /* use watchdog to reset */
imx233_chip_reset();
while(1);
}
@@ -134,6 +182,8 @@ void system_init(void)
imx233_power_init();
imx233_i2c_init();
imx233_powermgmt_init();
+ /* setup watchdog */
+ watchdog_init();
/* make sure auto-slow is disable now, we don't know at which frequency we
* are running and auto-slow could violate constraints on {xbus,hbus} */
diff --git a/firmware/target/arm/imx233/system-target.h b/firmware/target/arm/imx233/system-target.h
index 33e8f12265..6272cf7a85 100644
--- a/firmware/target/arm/imx233/system-target.h
+++ b/firmware/target/arm/imx233/system-target.h
@@ -68,4 +68,7 @@ void usb_remove_int(void);
bool dbg_hw_target_info(void);
+/* for watchdog */
+void imx233_keep_alive(void);
+
#endif /* SYSTEM_TARGET_H */
diff --git a/firmware/target/arm/imx233/timrot-imx233.h b/firmware/target/arm/imx233/timrot-imx233.h
index f1a7780f34..e33de39390 100644
--- a/firmware/target/arm/imx233/timrot-imx233.h
+++ b/firmware/target/arm/imx233/timrot-imx233.h
@@ -32,6 +32,7 @@ enum
{
TIMER_TICK, /* for tick task */
TIMER_USER, /* for user timer */
+ TIMER_WATCHDOG, /* for watchdog */
};
struct imx233_timrot_info_t