| /* Copyright (c) 2014 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. |
| */ |
| /* tiny substitute of the runtime layer */ |
| |
| #include "common.h" |
| #include "cpu.h" |
| #include "debug.h" |
| #include "master_slave.h" |
| #include "registers.h" |
| #include "task.h" |
| #include "timer.h" |
| #include "util.h" |
| |
| volatile uint32_t last_event; |
| |
| static uint32_t last_deadline; |
| static uint8_t need_wfi; |
| |
| timestamp_t get_time(void) |
| { |
| timestamp_t t; |
| uint32_t hi, lo; |
| |
| do { |
| hi = STM32_TIM_CNT(3); |
| lo = STM32_TIM_CNT(2); |
| } while (hi != STM32_TIM_CNT(3)); |
| |
| t.le.lo = (hi << 16) | lo; |
| t.le.hi = 0; |
| |
| return t; |
| } |
| |
| void udelay(unsigned us) |
| { |
| unsigned t0 = get_time().le.lo; |
| while ((get_time().le.lo - t0) < us) |
| ; |
| } |
| |
| void task_enable_irq(int irq) |
| { |
| CPU_NVIC_EN(0) = 1 << irq; |
| } |
| |
| void task_disable_irq(int irq) |
| { |
| CPU_NVIC_DIS(0) = 1 << irq; |
| } |
| |
| void task_clear_pending_irq(int irq) |
| { |
| CPU_NVIC_UNPEND(0) = 1 << irq; |
| } |
| |
| uint32_t task_set_event(task_id_t tskid, uint32_t event, int wait) |
| { |
| last_event = event; |
| |
| return 0; |
| } |
| |
| void tim2_interrupt(void) |
| { |
| if (STM32_TIM_CNT(3) == last_deadline >> 16) { |
| STM32_TIM_DIER(2) = 0; |
| task_clear_pending_irq(STM32_IRQ_TIM2); |
| last_event = TASK_EVENT_TIMER; |
| need_wfi = 0; |
| } else { |
| need_wfi = 1; |
| } |
| } |
| DECLARE_IRQ(STM32_IRQ_TIM2, tim2_interrupt, 1); |
| |
| void __hw_clock_event_set(uint32_t deadline) |
| { |
| last_deadline = deadline; |
| STM32_TIM_CCR1(2) = deadline & 0xffff; |
| STM32_TIM_SR(2) = ~2; |
| STM32_TIM_DIER(2) |= 2; |
| } |
| |
| uint32_t task_wait_event(int timeout_us) |
| { |
| uint32_t evt; |
| |
| /* the event already happened */ |
| if (last_event || !timeout_us) { |
| evt = last_event; |
| last_event = 0; |
| |
| return evt; |
| } |
| |
| /* set timeout on timer */ |
| if (timeout_us > 0) |
| __hw_clock_event_set(get_time().le.lo + timeout_us); |
| |
| do { |
| /* sleep until next interrupt */ |
| asm volatile("wfi"); |
| } while (need_wfi); |
| STM32_TIM_DIER(2) = 0; /* disable match interrupt */ |
| evt = last_event; |
| last_event = 0; |
| |
| return evt; |
| } |
| |
| void system_reboot(void) |
| { |
| if (master_slave_is_master()) { |
| /* Ask the slave to reboot as well */ |
| STM32_GPIO_BSRR(GPIO_A) = 1 << (6 + 16); |
| udelay(10 * MSEC); /* The slave reboots in 5 ms */ |
| } |
| |
| /* Ask the watchdog to trigger a hard reboot */ |
| STM32_IWDG_KR = 0x5555; |
| STM32_IWDG_RLR = 0x1; |
| STM32_IWDG_KR = 0xcccc; |
| /* wait for the watchdog */ |
| while (1) |
| ; |
| } |
| |
| /* Unhandled exception panic */ |
| void exception_panic(void) |
| { |
| debug_printf("PANIC\n"); |
| system_reboot(); |
| } |
| |
| /* --- stubs --- */ |
| void __hw_timer_enable_clock(int n, int enable) |
| { /* Done in hardware init */ } |
| |
| void usleep(unsigned us) |
| { /* Used only as a workaround */ } |