summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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)
146 146
147static void do_irq_stat(void) 147static void do_irq_stat(void)
148{ 148{
149 imx233_keep_alive();
149 static unsigned counter = 0; 150 static unsigned counter = 0;
150 if(counter++ >= HZ) 151 if(counter++ >= HZ)
151 { 152 {
@@ -180,6 +181,8 @@ void irq_handler(void)
180 asm volatile( 181 asm volatile(
181 "sub lr, lr, #4 \n" /* Create return address */ 182 "sub lr, lr, #4 \n" /* Create return address */
182 "stmfd sp!, { r0-r5, r12, lr } \n" /* Save what gets clobbered */ 183 "stmfd sp!, { r0-r5, r12, lr } \n" /* Save what gets clobbered */
184 "ldr r5, =0x8001c290 \n" /* Save pointer to instruction */
185 "str lr, [r5] \n" /* in HW_DIGCTL_SCRATCH0 */
183 "ldr r4, =0x80000000 \n" /* Read HW_ICOLL_VECTOR */ 186 "ldr r4, =0x80000000 \n" /* Read HW_ICOLL_VECTOR */
184 "ldr r0, [r4] \n" /* and notify as side-effect */ 187 "ldr r0, [r4] \n" /* and notify as side-effect */
185 "mrs lr, spsr \n" /* Save SPSR_irq */ 188 "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 @@
45#include "fmradio_i2c.h" 45#include "fmradio_i2c.h"
46#include "powermgmt-imx233.h" 46#include "powermgmt-imx233.h"
47 47
48#define WATCHDOG_HW_DELAY (10 * HZ)
49#define WATCHDOG_SW_DELAY (5 * HZ)
50
51static void woof_woof(void)
52{
53 /* stop hadrware watchdog, we catched the error */
54 imx233_rtc_enable_watchdog(false);
55 uint32_t pc = HW_DIGCTL_SCRATCH0;
56 /* write a "SWI #0xdead" instruction at the faulty instruction so that it
57 * will trigger a proper backtrace */
58 *(uint32_t *)pc = 0xef00dead;
59 commit_discard_idcache();
60}
61
62static void good_dog(void)
63{
64 imx233_rtc_reset_watchdog(WATCHDOG_HW_DELAY * 1000 / HZ); /* ms */
65 imx233_rtc_enable_watchdog(true);
66 imx233_timrot_setup(TIMER_WATCHDOG, false, WATCHDOG_SW_DELAY * 1000 / HZ,
67 BV_TIMROT_TIMCTRLn_SELECT__1KHZ_XTAL, BV_TIMROT_TIMCTRLn_PRESCALE__DIV_BY_1,
68 false, &woof_woof);
69 imx233_timrot_set_priority(TIMER_WATCHDOG, ICOLL_PRIO_WATCHDOG);
70}
71
72void imx233_keep_alive(void)
73{
74 /* setting up a timer is not exactly a cheap operation so only do so
75 * every second */
76 static uint32_t last_alive = 0;
77 if(imx233_us_elapsed(last_alive, 1000000))
78 {
79 good_dog();
80 last_alive = HW_DIGCTL_MICROSECONDS;
81 }
82}
83
84static void watchdog_init(void)
85{
86 /* setup two mechanisms:
87 * - hardware watchdog to reset the player after 10 seconds
88 * - software watchdog using a timer to panic after 5 seconds
89 * The hardware mechanism ensures reset when the player is completely
90 * dead and it actually resets the whole chip. On the contrary, the software
91 * mechanism allows partial recovery by panicing and printing (maybe) useful
92 * information, it uses a dedicated timer with the highest level of interrupt
93 * priority so it works even if the player is stuck in IRQ context */
94 good_dog();
95}
96
48void imx233_chip_reset(void) 97void imx233_chip_reset(void)
49{ 98{
50#if IMX233_SUBTARGET >= 3700 99#if IMX233_SUBTARGET >= 3700
@@ -60,7 +109,6 @@ void system_reboot(void)
60 109
61 disable_irq(); 110 disable_irq();
62 111
63 /* use watchdog to reset */
64 imx233_chip_reset(); 112 imx233_chip_reset();
65 while(1); 113 while(1);
66} 114}
@@ -134,6 +182,8 @@ void system_init(void)
134 imx233_power_init(); 182 imx233_power_init();
135 imx233_i2c_init(); 183 imx233_i2c_init();
136 imx233_powermgmt_init(); 184 imx233_powermgmt_init();
185 /* setup watchdog */
186 watchdog_init();
137 187
138 /* make sure auto-slow is disable now, we don't know at which frequency we 188 /* make sure auto-slow is disable now, we don't know at which frequency we
139 * are running and auto-slow could violate constraints on {xbus,hbus} */ 189 * 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);
68 68
69bool dbg_hw_target_info(void); 69bool dbg_hw_target_info(void);
70 70
71/* for watchdog */
72void imx233_keep_alive(void);
73
71#endif /* SYSTEM_TARGET_H */ 74#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
32{ 32{
33 TIMER_TICK, /* for tick task */ 33 TIMER_TICK, /* for tick task */
34 TIMER_USER, /* for user timer */ 34 TIMER_USER, /* for user timer */
35 TIMER_WATCHDOG, /* for watchdog */
35}; 36};
36 37
37struct imx233_timrot_info_t 38struct imx233_timrot_info_t