bump up min IOS version
[libogc.git] / libogc / timesupp.c
blob933bce67940edd5e38d990e8999f00bef3c0df1b
1 #include <_ansi.h>
2 #include <_syslist.h>
4 #include "asm.h"
5 #include "processor.h"
6 #include "lwp.h"
7 #include "lwp_threadq.h"
8 #include "timesupp.h"
9 #include "exi.h"
10 #include "system.h"
11 #include "conf.h"
13 #include <stdio.h>
14 #include <sys/time.h>
16 /* time variables */
17 static u32 exi_wait_inited = 0;
18 static lwpq_t time_exi_wait;
20 extern u32 __SYS_GetRTC(u32 *gctime);
21 extern syssram* __SYS_LockSram();
22 extern u32 __SYS_UnlockSram(u32 write);
26 u32 _DEFUN(gettick,(),
27 _NOARGS)
30 u32 result;
31 __asm__ __volatile__ (
32 "mftb %0\n"
33 : "=r" (result)
35 return result;
39 u64 _DEFUN(gettime,(),
40 _NOARGS)
42 u32 tmp;
43 union uulc {
44 u64 ull;
45 u32 ul[2];
46 } v;
48 __asm__ __volatile__(
49 "1: mftbu %0\n\
50 mftb %1\n\
51 mftbu %2\n\
52 cmpw %0,%2\n\
53 bne 1b\n"
54 : "=r" (v.ul[0]), "=r" (v.ul[1]), "=&r" (tmp)
56 return v.ull;
59 void _DEFUN(settime,(t),
60 u64 t)
62 u32 tmp;
63 union uulc {
64 u64 ull;
65 u32 ul[2];
66 } v;
68 v.ull = t;
69 __asm__ __volatile__ (
70 "li %0,0\n\
71 mttbl %0\n\
72 mttbu %1\n\
73 mttbl %2\n"
74 : "=&r" (tmp)
75 : "r" (v.ul[0]), "r" (v.ul[1])
79 u32 diff_sec(u64 start,u64 end)
81 u64 diff;
83 diff = diff_ticks(start,end);
84 return ticks_to_secs(diff);
87 u32 diff_msec(u64 start,u64 end)
89 u64 diff;
91 diff = diff_ticks(start,end);
92 return ticks_to_millisecs(diff);
95 u32 diff_usec(u64 start,u64 end)
97 u64 diff;
99 diff = diff_ticks(start,end);
100 return ticks_to_microsecs(diff);
103 u32 diff_nsec(u64 start,u64 end)
105 u64 diff;
107 diff = diff_ticks(start,end);
108 return ticks_to_nanosecs(diff);
111 void __timesystem_init()
113 if(!exi_wait_inited) {
114 exi_wait_inited = 1;
115 LWP_InitQueue(&time_exi_wait);
119 void timespec_subtract(const struct timespec *tp_start,const struct timespec *tp_end,struct timespec *result)
121 struct timespec start_st = *tp_start;
122 struct timespec *start = &start_st;
123 u32 nsecpersec = TB_NSPERSEC;
125 if(tp_end->tv_nsec<start->tv_nsec) {
126 int secs = (start->tv_nsec - tp_end->tv_nsec)/nsecpersec+1;
127 start->tv_nsec -= nsecpersec * secs;
128 start->tv_sec += secs;
130 if((tp_end->tv_nsec - start->tv_nsec)>nsecpersec) {
131 int secs = (start->tv_nsec - tp_end->tv_nsec)/nsecpersec;
132 start->tv_nsec += nsecpersec * secs;
133 start->tv_sec -= secs;
136 result->tv_sec = (tp_end->tv_sec - start->tv_sec);
137 result->tv_nsec = (tp_end->tv_nsec - start->tv_nsec);
140 unsigned long long timespec_to_ticks(const struct timespec *tp)
142 return __lwp_wd_calc_ticks(tp);
145 int clock_gettime(struct timespec *tp)
147 u32 gctime;
148 #if defined(HW_RVL)
149 u32 wii_bias = 0;
150 #endif
152 if(!tp) return -1;
154 if(!__SYS_GetRTC(&gctime)) return -1;
156 #if defined(HW_DOL)
157 syssram* sram = __SYS_LockSram();
158 gctime += sram->counter_bias;
159 __SYS_UnlockSram(0);
160 #else
161 if(CONF_GetCounterBias(&wii_bias)>=0) gctime += wii_bias;
162 #endif
163 gctime += 946684800;
165 tp->tv_sec = gctime;
166 tp->tv_nsec = ticks_to_nanosecs(gettick());
168 return 0;
171 // this function spins till timeout is reached
172 void _DEFUN(udelay,(us),
173 unsigned us)
175 unsigned long long start, end;
176 start = gettime();
177 while (1)
179 end = gettime();
180 if (diff_usec(start,end) >= us)
181 break;
185 unsigned int _DEFUN(nanosleep,(tb),
186 struct timespec *tb)
188 u64 timeout;
190 __lwp_thread_dispatchdisable();
192 timeout = __lwp_wd_calc_ticks(tb);
193 __lwp_thread_setstate(_thr_executing,LWP_STATES_DELAYING|LWP_STATES_INTERRUPTIBLE_BY_SIGNAL);
194 __lwp_wd_initialize(&_thr_executing->timer,__lwp_thread_delayended,_thr_executing->object.id,_thr_executing);
195 __lwp_wd_insert_ticks(&_thr_executing->timer,timeout);
197 __lwp_thread_dispatchenable();
198 return TB_SUCCESSFUL;
201 static u32 __getrtc(u32 *gctime)
203 u32 ret;
204 u32 cmd;
205 u32 time;
207 if(EXI_Select(EXI_CHANNEL_0,EXI_DEVICE_1,EXI_SPEED8MHZ)==0) {
208 return 0;
211 ret = 0;
212 time = 0;
213 cmd = 0x20000000;
214 if(EXI_Imm(EXI_CHANNEL_0,&cmd,4,EXI_WRITE,NULL)==0) ret |= 0x01;
215 if(EXI_Sync(EXI_CHANNEL_0)==0) ret |= 0x02;
216 if(EXI_Imm(EXI_CHANNEL_0,&time,4,EXI_READ,NULL)==0) ret |= 0x04;
217 if(EXI_Sync(EXI_CHANNEL_0)==0) ret |= 0x08;
218 if(EXI_Deselect(EXI_CHANNEL_0)==0) ret |= 0x10;
220 *gctime = time;
221 if(ret) return 0;
223 return 1;
226 static s32 __time_exi_unlock(s32 chn,s32 dev)
228 LWP_ThreadBroadcast(time_exi_wait);
229 return 1;
232 static void __time_exi_wait()
234 u32 ret;
236 do {
237 if((ret=EXI_Lock(EXI_CHANNEL_0,EXI_DEVICE_1,__time_exi_unlock))==1) break;
238 LWP_ThreadSleep(time_exi_wait);
239 }while(ret==0);
242 static u32 __getRTC(u32 *gctime)
244 u32 cnt,ret;
245 u32 time1,time2;
247 __time_exi_wait();
249 cnt = 0;
250 ret = 0;
251 while(cnt<16) {
252 if(__getrtc(&time1)==0
253 || __getrtc(&time2)==0) {
254 EXI_Unlock(EXI_CHANNEL_0);
255 break;
257 if(time1==time2) {
258 *gctime = time1;
259 EXI_Unlock(EXI_CHANNEL_0);
260 return 1;
262 cnt++;
264 return 0;
267 time_t _DEFUN(time,(timer),
268 time_t *timer)
270 time_t gctime = 0;
271 #if defined(HW_RVL)
272 u32 wii_bias = 0;
273 #endif
275 if(__getRTC((u32*)&gctime)==0) return (time_t)0;
277 #if defined(HW_DOL)
278 syssram* sram = __SYS_LockSram();
279 gctime += sram->counter_bias;
280 __SYS_UnlockSram(0);
281 #else
282 if(CONF_GetCounterBias(&wii_bias)>=0) gctime += wii_bias;
283 #endif
285 gctime += 946684800;
287 if(timer) *timer = gctime;
288 return gctime;
291 unsigned int _DEFUN(sleep,(s),
292 unsigned int s)
294 struct timespec tb;
296 tb.tv_sec = s;
297 tb.tv_nsec = 0;
298 return nanosleep(&tb);
301 unsigned int _DEFUN(usleep,(us),
302 unsigned int us)
304 u32 sec,rem;
305 struct timespec tb;
307 sec = us/TB_USPERSEC;
308 rem = us - (sec*TB_USPERSEC);
310 tb.tv_sec = sec;
311 tb.tv_nsec = rem*TB_NSPERUS;
312 return nanosleep(&tb);
315 clock_t clock(void) {
316 return -1;
319 int __libogc_gettod_r(struct _reent *ptr, struct timeval *tp, struct timezone *tz) {
321 if (tp != NULL) {
322 tp->tv_sec = time(NULL);
323 tp->tv_usec = tick_microsecs(gettick());
325 if (tz != NULL) {
326 tz->tz_minuteswest = 0;
327 tz->tz_dsttime = 0;
330 return 0;