/* 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. */ /* Hardware timers driver */ #include "clock.h" #include "common.h" #include "hooks.h" #include "hwtimer.h" #include "registers.h" #include "task.h" #include "timer.h" void __hw_clock_event_set(uint32_t deadline) { MEC1322_TMR32_CNT(1) = MEC1322_TMR32_CNT(0) - (0xffffffff - deadline); MEC1322_TMR32_CTL(1) |= (1 << 5); } uint32_t __hw_clock_event_get(void) { return MEC1322_TMR32_CNT(1) - MEC1322_TMR32_CNT(0) + 0xffffffff; } void __hw_clock_event_clear(void) { MEC1322_TMR32_CTL(1) &= ~(1 << 5); } uint32_t __hw_clock_source_read(void) { return 0xffffffff - MEC1322_TMR32_CNT(0); } void __hw_clock_source_set(uint32_t ts) { MEC1322_TMR32_CTL(0) &= ~(1 << 5); MEC1322_TMR32_CNT(0) = 0xffffffff - ts; MEC1322_TMR32_CTL(0) |= (1 << 5); } static void __hw_clock_source_irq(int timer_id) { if (timer_id == 1) MEC1322_TMR32_STS(1) |= 1; /* If IRQ is from timer 0, 32-bit timer overflowed */ process_timers(timer_id == 0); } void __hw_clock_source_irq_0(void) { __hw_clock_source_irq(0); } DECLARE_IRQ(MEC1322_IRQ_TIMER32_0, __hw_clock_source_irq_0, 1); void __hw_clock_source_irq_1(void) { __hw_clock_source_irq(1); } DECLARE_IRQ(MEC1322_IRQ_TIMER32_1, __hw_clock_source_irq_1, 1); static void configure_timer(int timer_id) { uint32_t val; /* Ensure timer is not running */ MEC1322_TMR32_CTL(timer_id) &= ~(1 << 5); /* Enable timer */ MEC1322_TMR32_CTL(timer_id) |= (1 << 0); val = MEC1322_TMR32_CTL(timer_id); /* Pre-scale = 48 -> 1MHz -> Period = 1us */ val = (val & 0xffff) | (47 << 16); MEC1322_TMR32_CTL(timer_id) = val; /* Set preload to use the full 32 bits of the timer */ MEC1322_TMR32_PRE(timer_id) = 0xffffffff; /* Enable interrupt */ MEC1322_TMR32_IEN(timer_id) |= 1; } int __hw_clock_source_init(uint32_t start_t) { /* * The timer can only fire interrupt when its value reaches zero. * Therefore we need two timers: * - Timer 0 as free running timer * - Timer 1 as event timer */ configure_timer(0); configure_timer(1); /* Override the count */ MEC1322_TMR32_CNT(0) = 0xffffffff - start_t; /* Auto restart */ MEC1322_TMR32_CTL(0) |= (1 << 3); /* Start counting in timer 0 */ MEC1322_TMR32_CTL(0) |= (1 << 5); /* Enable interrupt */ task_enable_irq(MEC1322_IRQ_TIMER32_0); task_enable_irq(MEC1322_IRQ_TIMER32_1); MEC1322_INT_ENABLE(23) |= (1 << 4) | (1 << 5); MEC1322_INT_BLK_EN |= (1 << 23); return MEC1322_IRQ_TIMER32_1; }