Fixed a few warnings.
[tangerine.git] / arch / ppc-chrp / efika / timer / lowlevel.c
blob726d3b1071bbb3771a7e5ea7bb8fa2707f7819bc
1 #define DEBUG 1
3 #include <aros/debug.h>
4 #include <asm/mpc5200b.h>
5 #include <asm/io.h>
7 #include <aros/asmcall.h>
8 #include <hardware/intbits.h>
9 #include <exec/execbase.h>
11 #include <inttypes.h>
12 #include <proto/exec.h>
13 #include <proto/timer.h>
15 #include "lowlevel.h"
17 uint32_t tbc_expected;
18 uint32_t tbc_achieved;
19 int32_t corr;
21 volatile slt_t *slice_timer;
23 // tick2usec - 64424510 for 66.666666MHz
24 // tick2usec - 130150524 for 33.000000MHz
26 inline uint32_t __attribute__((const)) tick2usec(uint32_t tick)
28 uint32_t retval;
29 uint64_t tmp = ((uint64_t)tick) * 130150524;
31 retval = (tmp + 0x7fffffff) >> 32;
33 return retval;
36 inline uint32_t __attribute__((const)) usec2tick(uint32_t usec)
38 uint32_t retval;
39 // uint64_t tmp = ((uint64_t)usec) * 286331150203ULL;
41 // retval = (tmp + 0x7fffffff) >> 32;
43 retval = usec * 33;
45 return retval;
48 void EClockUpdate(struct TimerBase *TimerBase)
50 uint32_t time;
51 uint32_t diff;
52 int show = 0;
54 time = mftbl();
55 diff = (time - TimerBase->tb_prev_tick);
56 TimerBase->tb_prev_tick = time;
58 TimerBase->tb_ticks_total += diff;
60 TimerBase->tb_ticks_sec += diff;
61 TimerBase->tb_ticks_elapsed += diff;
63 if (TimerBase->tb_ticks_sec >= 33000000)
65 TimerBase->tb_ticks_sec -= 33000000;
66 TimerBase->tb_CurrentTime.tv_secs++;
68 show = 1;
71 if (TimerBase->tb_ticks_elapsed >= 33000000)
73 TimerBase->tb_ticks_elapsed -= 33000000;
74 TimerBase->tb_Elapsed.tv_secs++;
77 TimerBase->tb_Elapsed.tv_micro = tick2usec(TimerBase->tb_ticks_elapsed);
78 TimerBase->tb_CurrentTime.tv_micro = tick2usec(TimerBase->tb_ticks_sec);
80 // if (show)
81 // {
82 // bug("[timer] CurrentTime: %d:%06d\n", TimerBase->tb_CurrentTime.tv_secs, TimerBase->tb_CurrentTime.tv_micro);
83 // bug("[timer] %08x %08x %d %d \n", tbc_expected, tbc_achieved, tbc_achieved-tbc_expected, corr);
84 // }
87 void EClockSet(struct TimerBase *TimerBase)
89 TimerBase->tb_ticks_sec = usec2tick(TimerBase->tb_CurrentTime.tv_micro);
92 void TimerSetup(struct TimerBase *TimerBase, uint32_t waste)
94 int32_t delay = 660000; /* 50Hz in worst case */
95 struct timeval time;
96 struct timerequest *tr;
97 uint32_t current_time;
99 tr = (struct timerequest *)GetHead(&TimerBase->tb_Lists[TL_WAITVBL]);
101 if (tr)
103 time.tv_micro = tr->tr_time.tv_micro;
104 time.tv_secs = tr->tr_time.tv_secs;
106 SubTime(&time, &TimerBase->tb_CurrentTime);
108 if ((LONG)time.tv_secs < 0)
110 delay = 0;
112 else if (time.tv_secs == 0)
114 // if (time.tv_micro < 20000)
115 // {
116 if (delay > usec2tick(time.tv_micro))
117 delay = usec2tick(time.tv_micro);
118 // }
122 tr = (struct timerequest *)GetHead(&TimerBase->tb_Lists[TL_VBLANK]);
124 if (tr)
126 time.tv_micro = tr->tr_time.tv_micro;
127 time.tv_secs = tr->tr_time.tv_secs;
129 SubTime(&time, &TimerBase->tb_Elapsed);
131 if ((LONG)time.tv_secs < 0)
133 delay = 0;
135 else if (time.tv_secs == 0)
137 // if (time.tv_micro < 20000)
138 // {
139 if (delay > usec2tick(time.tv_micro))
140 delay = usec2tick(time.tv_micro);
141 // }
145 current_time = mftbl();
146 delay -= ((int32_t)(current_time - waste)) + corr;
148 if (delay < 256) delay = 256;
150 tbc_expected = current_time + delay;
152 /* Stop the timer */
153 outl(SLT_CF_INTRENA, &slice_timer->slt_cf);
154 /* Set the delay */
155 outl(delay, &slice_timer->slt_tc);
156 /* Let timer go */
157 outl(SLT_CF_INTRENA | SLT_CF_ENABLE, &slice_timer->slt_cf);
158 /* Clear interrupt request. */
159 outl(SLT_TS_ST, &slice_timer->slt_ts);
163 This is a slightly faster version of AddTime() that we use here. It
164 also saves the function call overhead...
166 #define FastAddTime(d, s)\
167 (d)->tv_micro += (s)->tv_micro;\
168 (d)->tv_secs += (s)->tv_secs;\
169 if((d)->tv_micro > 999999) {\
170 (d)->tv_secs++;\
171 (d)->tv_micro -= 1000000;\
174 BOOL timer_addToWaitList(struct TimerBase *, struct MinList *, struct timerequest *);
176 void SliceHandler(struct TimerBase *TimerBase, struct ExecBase *SysBase)
178 uint32_t startup_time = mftbl();
180 if (inl(&slice_timer->slt_ts) & SLT_TS_ST)
182 struct timerequest *tr, *next;
184 /* Clear interrupt request. */
185 outl(SLT_TS_ST, &slice_timer->slt_ts);
186 sync();
187 /* Stop the timer */
188 outl(0, &slice_timer->slt_cf);
189 // outl(SLT_CF_RUNWAIT | SLT_CF_INTRENA | SLT_CF_ENABLE, &slice_timer->slt_cf);
191 // D(bug("[timer] SliceHandler on %08x%08x slt->cv=%08x\n", (uint32_t)(mftb() >> 32),mftbl(),inl(&slice_timer->slt_cv)));
193 EClockUpdate(TimerBase);
195 tbc_achieved = startup_time;
197 /* Timer errors bigger than approx 15 microseconds shouldn't be taken into account */
198 //if (tbc_achieved > tbc_expected) // && (tbc_achieved - tbc_expected) < 1000)
200 corr = ((int32_t)(tbc_achieved - tbc_expected))-1;
205 Go through the "wait for x seconds" list and return requests
206 that have completed. A completed request is one whose time
207 is less than that of the elapsed time.
209 ForeachNodeSafe(&TimerBase->tb_Lists[TL_VBLANK], tr, next)
211 if(CmpTime(&TimerBase->tb_Elapsed, &tr->tr_time) <= 0)
213 if (tr == &TimerBase->tb_vblank_timerequest)
215 struct IntVector *iv = &SysBase->IntVects[INTB_VERTB];
217 /* VBlank Emu */
219 if (iv->iv_Code)
221 AROS_UFC5(void, iv->iv_Code,
222 AROS_UFCA(ULONG, 0, D1),
223 AROS_UFCA(ULONG, 0, A0),
224 AROS_UFCA(APTR, iv->iv_Data, A1),
225 AROS_UFCA(APTR, iv->iv_Code, A5),
226 AROS_UFCA(struct ExecBase *, SysBase, A6)
229 /* Automatically requeue/reactivate request */
231 Remove((struct Node *)tr);
232 tr->tr_node.io_Command = TR_ADDREQUEST;
233 tr->tr_time.tv_secs = 0;
234 tr->tr_time.tv_micro = 1000000 / SysBase->VBlankFrequency;
235 AddTime(&tr->tr_time, &TimerBase->tb_Elapsed);
237 timer_addToWaitList(TimerBase, &TimerBase->tb_Lists[TL_VBLANK], tr);
239 else
241 /* This request has finished */
242 Remove((struct Node *)tr);
243 tr->tr_time.tv_secs = tr->tr_time.tv_micro = 0;
244 tr->tr_node.io_Error = 0;
245 ReplyMsg((struct Message *)tr);
248 else
251 The first request hasn't finished, as all requests are in
252 order, we don't bother searching through the remaining
254 break;
259 The other this is the "wait until a specified time". Here a request
260 is complete if the time we are waiting for is before the current time.
262 ForeachNodeSafe(&TimerBase->tb_Lists[TL_WAITVBL], tr, next)
264 if(CmpTime(&TimerBase->tb_CurrentTime, &tr->tr_time) <= 0)
266 /* This request has finished */
267 Remove((struct Node *)tr);
268 tr->tr_time.tv_secs = tr->tr_time.tv_micro = 0;
269 tr->tr_node.io_Error = 0;
270 ReplyMsg((struct Message *)tr);
272 else
275 The first request hasn't finished, as all requests are in
276 order, we don't bother searching through the remaining
278 break;
281 TimerSetup(TimerBase, startup_time);