1 #include <aros/debug.h>
2 #include <asm/amcc440.h>
4 #include "../kernel/syscall.h"
6 #include <aros/asmcall.h>
7 #include <hardware/intbits.h>
8 #include <exec/execbase.h>
11 #include <proto/exec.h>
12 #include <proto/timer.h>
16 uint32_t tbc_expected
;
17 uint32_t tbc_achieved
;
20 inline uint32_t __attribute__((const)) tick2usec(uint32_t tick
)
23 uint64_t tmp
= ((uint64_t)tick
) * 64424510;
25 retval
= (tmp
+ 0x7fffffff) >> 32;
30 inline uint32_t __attribute__((const)) usec2tick(uint32_t usec
)
33 uint64_t tmp
= ((uint64_t)usec
) * 286331150203ULL;
35 retval
= (tmp
+ 0x7fffffff) >> 32;
40 void EClockUpdate(struct TimerBase
*TimerBase
)
47 diff
= (time
- TimerBase
->tb_prev_tick
);
48 TimerBase
->tb_prev_tick
= time
;
50 TimerBase
->tb_ticks_total
+= diff
;
52 TimerBase
->tb_ticks_sec
+= diff
;
53 TimerBase
->tb_ticks_elapsed
+= diff
;
55 if (TimerBase
->tb_ticks_sec
>= 66666666)
57 TimerBase
->tb_ticks_sec
-= 66666666;
58 TimerBase
->tb_CurrentTime
.tv_secs
++;
62 if (TimerBase
->tb_ticks_elapsed
>= 66666666)
64 TimerBase
->tb_ticks_elapsed
-= 66666666;
65 TimerBase
->tb_Elapsed
.tv_secs
++;
68 TimerBase
->tb_Elapsed
.tv_micro
= tick2usec(TimerBase
->tb_ticks_elapsed
);
69 TimerBase
->tb_CurrentTime
.tv_micro
= tick2usec(TimerBase
->tb_ticks_sec
);
72 // bug("[timer] CurrentTime: %d:%06d\n", TimerBase->tb_CurrentTime.tv_secs, TimerBase->tb_CurrentTime.tv_micro);
73 //bug("[timer] %08x %08x %d \n", tbc_expected, tbc_achieved, corr);
76 void EClockSet(struct TimerBase
*TimerBase
)
78 TimerBase
->tb_ticks_sec
= usec2tick(TimerBase
->tb_CurrentTime
.tv_micro
);
81 void TimerSetup(struct TimerBase
*TimerBase
, uint32_t waste
)
83 int32_t delay
= 1333333; /* 50Hz in worst case */
85 struct timerequest
*tr
;
86 uint32_t current_time
;
88 tr
= (struct timerequest
*)GetHead(&TimerBase
->tb_Lists
[TL_WAITVBL
]);
92 time
.tv_micro
= tr
->tr_time
.tv_micro
;
93 time
.tv_secs
= tr
->tr_time
.tv_secs
;
95 SubTime(&time
, &TimerBase
->tb_CurrentTime
);
97 if ((LONG
)time
.tv_secs
< 0)
101 else if (time
.tv_secs
== 0)
103 if (time
.tv_micro
< 20000)
105 if (delay
> usec2tick(time
.tv_micro
))
106 delay
= usec2tick(time
.tv_micro
);
111 tr
= (struct timerequest
*)GetHead(&TimerBase
->tb_Lists
[TL_VBLANK
]);
115 time
.tv_micro
= tr
->tr_time
.tv_micro
;
116 time
.tv_secs
= tr
->tr_time
.tv_secs
;
118 SubTime(&time
, &TimerBase
->tb_Elapsed
);
120 if ((LONG
)time
.tv_secs
< 0)
124 else if (time
.tv_secs
== 0)
126 if (time
.tv_micro
< 20000)
128 if (delay
> usec2tick(time
.tv_micro
))
129 delay
= usec2tick(time
.tv_micro
);
134 current_time
= inl(GPT0_TBC
);
135 delay
-= current_time
- waste
+ corr
;
137 if (delay
< 100) delay
= 100;
139 tbc_expected
= current_time
+ delay
;
141 outl(delay
, GPT0_DCT0
);
145 This is a slightly faster version of AddTime() that we use here. It
146 also saves the function call overhead...
148 #define FastAddTime(d, s)\
149 (d)->tv_micro += (s)->tv_micro;\
150 (d)->tv_secs += (s)->tv_secs;\
151 if((d)->tv_micro > 999999) {\
153 (d)->tv_micro -= 1000000;\
156 BOOL
timer_addToWaitList(struct TimerBase
*, struct MinList
*, struct timerequest
*);
158 void GPTHandler(struct TimerBase
*TimerBase
, struct ExecBase
*SysBase
)
160 uint32_t startup_time
= inl(GPT0_TBC
);
162 if (inl(GPT0_DCIS
) & GPT0_DCIS_DCIS
)
164 struct timerequest
*tr
, *next
;
165 outl(GPT0_DCIS_DCIS
, GPT0_DCIS
);
166 EClockUpdate(TimerBase
);
168 tbc_achieved
= startup_time
;
170 /* Timer errors bigger than approx 15 microseconds shouldn't be taken into account */
171 if (tbc_achieved
> tbc_expected
&& (tbc_achieved
- tbc_expected
) < 1000)
173 corr
= ((int32_t)(tbc_achieved
- tbc_expected
))-1;
178 Go through the "wait for x seconds" list and return requests
179 that have completed. A completed request is one whose time
180 is less than that of the elapsed time.
182 ForeachNodeSafe(&TimerBase
->tb_Lists
[TL_VBLANK
], tr
, next
)
184 if(CmpTime(&TimerBase
->tb_Elapsed
, &tr
->tr_time
) <= 0)
186 if (tr
== &TimerBase
->tb_vblank_timerequest
)
188 struct IntVector
*iv
= &SysBase
->IntVects
[INTB_VERTB
];
194 AROS_UFC5(void, iv
->iv_Code
,
195 AROS_UFCA(ULONG
, 0, D1
),
196 AROS_UFCA(ULONG
, 0, A0
),
197 AROS_UFCA(APTR
, iv
->iv_Data
, A1
),
198 AROS_UFCA(APTR
, iv
->iv_Code
, A5
),
199 AROS_UFCA(struct ExecBase
*, SysBase
, A6
)
202 /* Automatically requeue/reactivate request */
204 Remove((struct Node
*)tr
);
205 tr
->tr_node
.io_Command
= TR_ADDREQUEST
;
206 tr
->tr_time
.tv_secs
= 0;
207 tr
->tr_time
.tv_micro
= 1000000 / SysBase
->VBlankFrequency
;
208 AddTime(&tr
->tr_time
, &TimerBase
->tb_Elapsed
);
210 timer_addToWaitList(TimerBase
, &TimerBase
->tb_Lists
[TL_VBLANK
], tr
);
212 if (--SysBase
->Elapsed
== 0)
214 SysBase
->SysFlags
|= 0x2000;
215 SysBase
->AttnResched
|= 0x80;
220 /* This request has finished */
221 Remove((struct Node
*)tr
);
222 tr
->tr_time
.tv_secs
= tr
->tr_time
.tv_micro
= 0;
223 tr
->tr_node
.io_Error
= 0;
224 ReplyMsg((struct Message
*)tr
);
230 The first request hasn't finished, as all requests are in
231 order, we don't bother searching through the remaining
238 The other this is the "wait until a specified time". Here a request
239 is complete if the time we are waiting for is before the current time.
241 ForeachNodeSafe(&TimerBase
->tb_Lists
[TL_WAITVBL
], tr
, next
)
243 if(CmpTime(&TimerBase
->tb_CurrentTime
, &tr
->tr_time
) <= 0)
245 /* This request has finished */
246 Remove((struct Node
*)tr
);
247 tr
->tr_time
.tv_secs
= tr
->tr_time
.tv_micro
= 0;
248 tr
->tr_node
.io_Error
= 0;
249 ReplyMsg((struct Message
*)tr
);
254 The first request hasn't finished, as all requests are in
255 order, we don't bother searching through the remaining
260 TimerSetup(TimerBase
, startup_time
);