| /* Copyright (c) 2013 The Chromium OS Authors. All rights reserved. |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| /* Watchdog driver */ |
| |
| #include "hooks.h" |
| #include "registers.h" |
| #include "task.h" |
| #include "watchdog.h" |
| |
| void watchdog_reload(void) |
| { |
| MEC1322_WDG_KICK = 1; |
| |
| #ifdef CONFIG_WATCHDOG_HELP |
| /* Reload the auxiliary timer */ |
| MEC1322_TMR16_CTL(0) &= ~(1 << 5); |
| MEC1322_TMR16_CNT(0) = CONFIG_AUX_TIMER_PERIOD_MS; |
| MEC1322_TMR16_CTL(0) |= 1 << 5; |
| #endif |
| } |
| DECLARE_HOOK(HOOK_TICK, watchdog_reload, HOOK_PRIO_DEFAULT); |
| |
| int watchdog_init(void) |
| { |
| #ifdef CONFIG_WATCHDOG_HELP |
| uint32_t val; |
| |
| /* |
| * Watchdog does not warn us before expiring. Let's use a 16-bit |
| * timer as an auxiliary timer. |
| */ |
| |
| /* Stop the auxiliary timer if it's running */ |
| MEC1322_TMR16_CTL(0) &= ~(1 << 5); |
| |
| /* Enable auxiliary timer */ |
| MEC1322_TMR16_CTL(0) |= 1 << 0; |
| |
| val = MEC1322_TMR16_CTL(0); |
| |
| /* Pre-scale = 48000 -> 1kHz -> Period = 1ms */ |
| val = (val & 0xffff) | (47999 << 16); |
| |
| /* No auto restart */ |
| val &= ~(1 << 3); |
| |
| /* Count down */ |
| val &= ~(1 << 2); |
| |
| MEC1322_TMR16_CTL(0) = val; |
| |
| /* Enable interrupt from auxiliary timer */ |
| MEC1322_TMR16_IEN(0) |= 1; |
| task_enable_irq(MEC1322_IRQ_TIMER16_0); |
| MEC1322_INT_ENABLE(23) |= 1 << 0; |
| MEC1322_INT_BLK_EN |= 1 << 23; |
| |
| /* Load and start the auxiliary timer */ |
| MEC1322_TMR16_CNT(0) = CONFIG_AUX_TIMER_PERIOD_MS; |
| MEC1322_TMR16_CNT(0) |= 1 << 5; |
| #endif |
| |
| /* Set timeout. It takes 1007us to decrement WDG_CNT by 1. */ |
| MEC1322_WDG_LOAD = CONFIG_WATCHDOG_PERIOD_MS * 1000 / 1007; |
| |
| /* Start watchdog */ |
| MEC1322_WDG_CTL |= 1; |
| |
| return EC_SUCCESS; |
| } |
| |
| #ifdef CONFIG_WATCHDOG_HELP |
| void __keep watchdog_check(uint32_t excep_lr, uint32_t excep_sp) |
| { |
| /* Clear status */ |
| MEC1322_TMR16_STS(0) |= 1; |
| |
| watchdog_trace(excep_lr, excep_sp); |
| } |
| |
| void IRQ_HANDLER(MEC1322_IRQ_TIMER16_0)(void) __attribute__((naked)); |
| void IRQ_HANDLER(MEC1322_IRQ_TIMER16_0)(void) |
| { |
| /* Naked call so we can extract raw LR and SP */ |
| asm volatile("mov r0, lr\n" |
| "mov r1, sp\n" |
| /* Must push registers in pairs to keep 64-bit aligned |
| * stack for ARM EABI. This also conveninently saves |
| * R0=LR so we can pass it to task_resched_if_needed. */ |
| "push {r0, lr}\n" |
| "bl watchdog_check\n" |
| "pop {r0, lr}\n" |
| "b task_resched_if_needed\n"); |
| } |
| const struct irq_priority IRQ_PRIORITY(MEC1322_IRQ_TIMER16_0) |
| __attribute__((section(".rodata.irqprio"))) |
| = {MEC1322_IRQ_TIMER16_0, 0}; /* put the watchdog at the |
| highest priority */ |
| #endif |