blob: 3b499b10cead3c5094459bae130b51fa76ac418d [file] [log] [blame]
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +01001/*
2 * Copyright (c) 2016, Intel Corporation
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the Intel Corporation nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
29 */
30
31#include <xtensa/xtruntime.h>
32#include <xtensa/hal.h>
33#include <arch/timer.h>
34#include <platform/memory.h>
35#include <platform/interrupt.h>
36#include <platform/timer.h>
Pierre-Louis Bossart81708a52018-04-04 18:46:50 -050037#include <sof/mailbox.h>
38#include <sof/debug.h>
39#include <sof/timer.h>
40#include <sof/interrupt.h>
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +010041#include <stdint.h>
42#include <errno.h>
43
Liam Girdwood488f02d2017-09-13 23:17:17 +010044struct timer_data {
45 void (*handler2)(void *arg);
46 void *arg2;
47};
48
49static struct timer_data xtimer[3] = {};
50
51void timer_64_handler(void *arg)
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +010052{
Liam Girdwood488f02d2017-09-13 23:17:17 +010053 struct timer *timer = arg;
54 struct timer_data *tdata = timer->timer_data;
55 uint32_t ccompare;
56
57 /* get comparator value - will tell us timeout reason */
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +010058 switch (timer->id) {
59 case TIMER0:
Liam Girdwood488f02d2017-09-13 23:17:17 +010060 ccompare = xthal_get_ccompare(0);
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +010061 break;
62 case TIMER1:
Liam Girdwood488f02d2017-09-13 23:17:17 +010063 ccompare = xthal_get_ccompare(1);
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +010064 break;
65 case TIMER2:
Liam Girdwood488f02d2017-09-13 23:17:17 +010066 ccompare = xthal_get_ccompare(2);
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +010067 break;
68 default:
Liam Girdwood488f02d2017-09-13 23:17:17 +010069 return;
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +010070 }
Liam Girdwood488f02d2017-09-13 23:17:17 +010071
72 /* is this a 32 bit rollover ? */
73 if (ccompare == 1) {
74 /* roll over the timer */
75 timer->hitime++;
76 arch_timer_clear(timer);
77 } else {
78 /* no roll over, run the handler */
79 tdata->handler2(tdata->arg2);
80 }
81
82 /* get next timeout value */
Liam Girdwood915354c2018-03-23 14:18:05 +000083 if (timer->hitimeout == timer->hitime) {
Liam Girdwood488f02d2017-09-13 23:17:17 +010084 /* timeout is in this 32 bit period */
85 ccompare = timer->lowtimeout;
86 } else {
87 /* timeout is in another 32 bit period */
88 ccompare = 1;
89 }
90
91 switch (timer->id) {
92 case TIMER0:
93 xthal_set_ccompare(0, ccompare);
94 break;
95 case TIMER1:
96 xthal_set_ccompare(1, ccompare);
97 break;
98 case TIMER2:
99 xthal_set_ccompare(2, ccompare);
100 break;
101 default:
102 return;
103 }
104}
105
106int timer64_register(struct timer *timer, void(*handler)(void *arg), void *arg)
107{
108 struct timer_data *tdata;
109
110 switch (timer->id) {
111 case TIMER0:
112 tdata = &xtimer[0];
113 break;
114 case TIMER1:
115 tdata = &xtimer[1];
116 break;
117 case TIMER2:
118 tdata = &xtimer[2];
119 break;
120 default:
121 return -EINVAL;
122 }
123
124 tdata->handler2 = handler;
125 tdata->arg2 = arg;
126 timer->timer_data = tdata;
127 timer->hitime = 0;
128 timer->hitimeout = 0;
129 return 0;
130}
131
132uint64_t arch_timer_get_system(struct timer *timer)
133{
134 uint64_t time;
Pierre-Louis Bossart4ccf81d2017-09-25 14:52:09 -0500135 uint32_t flags;
136 uint32_t low;
137 uint32_t high;
138 uint32_t ccompare;
Liam Girdwood488f02d2017-09-13 23:17:17 +0100139
140 switch (timer->id) {
141 case TIMER0:
142 ccompare = xthal_get_ccompare(0);
143 break;
144 case TIMER1:
145 ccompare = xthal_get_ccompare(1);
146 break;
147 case TIMER2:
148 ccompare = xthal_get_ccompare(2);
149 break;
150 default:
151 return 0;
152 }
153
154 flags = arch_interrupt_global_disable();
155
156 /* read low 32 bits */
157 low = xthal_get_ccount();
158
159 /* check and see whether 32bit IRQ is pending for timer */
160 if (arch_interrupt_get_status() & (1 << timer->irq) && ccompare == 1) {
161 /* yes, overflow has occured but handler has not run */
162 high = timer->hitime + 1;
163 } else {
164 /* no overflow */
165 high = timer->hitime;
166 }
167
168 time = ((uint64_t)high << 32) | low;
169
170 arch_interrupt_global_enable(flags);
171
172 return time;
173}
174
175int arch_timer_set(struct timer *timer, uint64_t ticks)
176{
Pierre-Louis Bossart4ccf81d2017-09-25 14:52:09 -0500177 uint32_t time = 1;
178 uint32_t hitimeout = ticks >> 32;
179 uint32_t flags;
Liam Girdwood488f02d2017-09-13 23:17:17 +0100180
181 /* value of 1 represents rollover */
182 if ((ticks & 0xffffffff) == 0x1)
183 ticks++;
184
185 flags = arch_interrupt_global_disable();
186
187 /* same hi 64 bit context as ticks ? */
Liam Girdwood915354c2018-03-23 14:18:05 +0000188 if (hitimeout < timer->hitime) {
Liam Girdwood488f02d2017-09-13 23:17:17 +0100189 /* cant be in the past */
190 arch_interrupt_global_enable(flags);
191 return -EINVAL;
192 } else {
193 /* set for checking at next timeout */
Liam Girdwood915354c2018-03-23 14:18:05 +0000194 time = ticks;
Liam Girdwood488f02d2017-09-13 23:17:17 +0100195 timer->hitimeout = hitimeout;
196 timer->lowtimeout = ticks;
197 }
198
199 switch (timer->id) {
200 case TIMER0:
201 xthal_set_ccompare(0, time);
202 break;
203 case TIMER1:
204 xthal_set_ccompare(1, time);
205 break;
206 case TIMER2:
207 xthal_set_ccompare(2, time);
208 break;
209 default:
210 return -EINVAL;
211 }
212
213 arch_interrupt_global_enable(flags);
214 return 0;
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100215}
Keyon Jiebd010012018-02-23 16:56:10 +0800216
217void timer_unregister(struct timer *timer)
218{
219 interrupt_unregister(timer->irq);
220}
221
222void timer_enable(struct timer *timer)
223{
224 interrupt_enable(timer->irq);
225}
226
227void timer_disable(struct timer *timer)
228{
229 interrupt_disable(timer->irq);
230}
231