tlk: 6/19 update
[3rdparty/ote_partner/tlk.git] / platform / tegra / common / timer.c
1 /*
2  * Copyright (c) 2008 Travis Geiselbrecht
3  * Copyright (c) 2012-2013, NVIDIA CORPORATION. All rights reserved
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining
6  * a copy of this software and associated documentation files
7  * (the "Software"), to deal in the Software without restriction,
8  * including without limitation the rights to use, copy, modify, merge,
9  * publish, distribute, sublicense, and/or sell copies of the Software,
10  * and to permit persons to whom the Software is furnished to do so,
11  * subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be
14  * included in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */
24 #include <sys/types.h>
25 #include <err.h>
26 #include <reg.h>
27 #include <debug.h>
28 #include <kernel/thread.h>
29 #include <platform.h>
30 #include <platform/interrupts.h>
31 #include <platform/timer.h>
32 #include <platform/memmap.h>
33 #include <platform/platform_p.h>
34
35 static lk_time_t tick_interval_ms;
36 static platform_timer_callback t_callback;
37 static void *callback_arg;
38
39 /* timer 10 */
40 static const unsigned int system_timer_irq = 157;
41
42 #define MSEC_PER_SEC            1000000
43
44 #define TIMER_PTV               0x0
45 #define TIMER_PCR               0x4
46
47 #define RTC_SECONDS             0x08
48 #define RTC_MILLISECONDS        0x10
49 #define RTC_SHADOW_SECONDS      0x0C
50
51 #define TIMERUS_CNTR_1US        0x10
52
53 static inline void write_timer_reg(uint32_t reg, unsigned int data)
54 {
55         *(volatile uint32_t *)(TEGRA_TMR10_BASE + (reg)) = data;
56 }
57
58 static inline uint32_t read_timer_reg(uint32_t reg)
59 {
60         return *(volatile uint32_t *)(TEGRA_TMR10_BASE + (reg));
61 }
62
63 status_t platform_set_periodic_timer(platform_timer_callback callback, void *arg, lk_time_t interval_ms)
64 {
65         enter_critical_section();
66
67         t_callback = callback;
68         callback_arg = arg;
69         tick_interval_ms = interval_ms;
70
71         write_timer_reg(TIMER_PTV, 0);
72         write_timer_reg(TIMER_PTV, 0xC0000000 | (interval_ms*1000));
73
74         unmask_interrupt(system_timer_irq);
75
76         exit_critical_section();
77
78         return NO_ERROR;
79 }
80
81 lk_time_t current_time(void)
82 {
83         uint32_t ms = *(volatile uint32_t *)(TEGRA_RTC_BASE + RTC_MILLISECONDS);
84         uint32_t s = *(volatile uint32_t *)(TEGRA_RTC_BASE + RTC_SHADOW_SECONDS);
85
86         return (lk_time_t)((uint64_t)s * MSEC_PER_SEC + ms);
87 }
88
89 lk_bigtime_t current_time_hires(void)
90 {
91         static uint32_t upper;
92         static uint32_t prev, now;
93         uint64_t retval;
94
95         now = *(volatile uint32_t *)(TEGRA_TMR1_BASE + TIMERUS_CNTR_1US);
96         if (now < prev) {
97                 upper++;
98         }
99         prev = now;
100         retval = ((uint64_t)upper << 32) | now;
101
102         return (lk_bigtime_t)retval;
103 }
104
105 static enum handler_return os_timer_tick(void *arg)
106 {
107         write_timer_reg(TIMER_PCR, 1 << 30);
108         return t_callback(callback_arg, current_time());
109 }
110
111 void platform_init_timer(void)
112 {
113         write_timer_reg(TIMER_PTV, 0);
114         register_int_handler(system_timer_irq, os_timer_tick, NULL);
115 }
116
117 void platform_halt_timers(void)
118 {
119         uint32_t timer_val = read_timer_reg(TIMER_PTV);
120         write_timer_reg(TIMER_PTV, timer_val & ~0x80000000);
121 }