2 * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
26 * @APPLE_FREE_COPYRIGHT@
30 * Purpose: Routines for handling the machine dependent
34 #include <mach/mach_types.h>
36 #include <kern/clock.h>
37 #include <kern/thread.h>
38 #include <kern/processor.h>
39 #include <kern/macro_help.h>
42 #include <machine/commpage.h>
43 #include <machine/machine_routines.h>
44 #include <ppc/exception.h>
45 #include <ppc/proc_reg.h>
47 #include <ppc/rtclock.h>
49 #include <sys/kdebug.h>
51 int rtclock_config(void);
53 int rtclock_init(void);
55 #define NSEC_PER_HZ (NSEC_PER_SEC / 100)
57 static uint32_t rtclock_sec_divisor
;
59 static mach_timebase_info_data_t rtclock_timebase_const
;
61 static boolean_t rtclock_timebase_initialized
;
63 /* XXX this should really be in a header somewhere */
64 extern clock_timer_func_t rtclock_timer_expire
;
66 decl_simple_lock_data(static,rtclock_lock
)
69 * Macros to lock/unlock real-time clock device.
74 simple_lock(&rtclock_lock); \
77 #define UNLOCK_RTC(s) \
79 simple_unlock(&rtclock_lock); \
85 struct timebase_freq_t
*freq
)
87 uint32_t numer
, denom
;
91 if ( freq
->timebase_den
< 1 || freq
->timebase_den
> 4 ||
92 freq
->timebase_num
< freq
->timebase_den
)
93 panic("rtclock timebase_callback: invalid constant %d / %d",
94 freq
->timebase_num
, freq
->timebase_den
);
96 denom
= freq
->timebase_num
;
97 numer
= freq
->timebase_den
* NSEC_PER_SEC
;
100 if (!rtclock_timebase_initialized
) {
101 commpage_set_timestamp(0,0,0);
103 rtclock_timebase_const
.numer
= numer
;
104 rtclock_timebase_const
.denom
= denom
;
105 rtclock_sec_divisor
= freq
->timebase_num
/ freq
->timebase_den
;
107 nanoseconds_to_absolutetime(NSEC_PER_HZ
, &abstime
);
108 rtclock_tick_interval
= abstime
;
110 ml_init_lock_timeout();
114 printf("rtclock timebase_callback: late old %d / %d new %d / %d\n",
115 rtclock_timebase_const
.numer
, rtclock_timebase_const
.denom
,
121 clock_timebase_init();
125 * Configure the system clock device.
130 simple_lock_init(&rtclock_lock
, 0);
132 PE_register_timebase_callback(timebase_callback
);
138 * Initialize the system clock device.
144 struct per_proc_info
*pp
;
148 abstime
= mach_absolute_time();
149 pp
->rtclock_intr_deadline
= abstime
+ rtclock_tick_interval
; /* Get the time we need to pop */
151 etimer_resync_deadlines(); /* Start the timers going */
157 clock_get_system_microtime(
164 now
= mach_absolute_time();
166 *secs
= t64
= now
/ (divisor
= rtclock_sec_divisor
);
167 now
-= (t64
* divisor
);
168 *microsecs
= (now
* USEC_PER_SEC
) / divisor
;
172 clock_get_system_nanotime(
179 now
= mach_absolute_time();
181 *secs
= t64
= now
/ (divisor
= rtclock_sec_divisor
);
182 now
-= (t64
* divisor
);
183 *nanosecs
= (now
* NSEC_PER_SEC
) / divisor
;
187 clock_gettimeofday_set_commpage(
194 uint64_t t64
, now
= abstime
;
196 simple_lock(&rtclock_lock
);
200 *secs
= t64
= now
/ rtclock_sec_divisor
;
201 now
-= (t64
* rtclock_sec_divisor
);
202 *microsecs
= (now
* USEC_PER_SEC
) / rtclock_sec_divisor
;
206 commpage_set_timestamp(abstime
- now
, *secs
, rtclock_sec_divisor
);
208 simple_unlock(&rtclock_lock
);
213 mach_timebase_info_t info
)
218 *info
= rtclock_timebase_const
;
219 rtclock_timebase_initialized
= TRUE
;
224 clock_set_timer_func(
225 clock_timer_func_t func
)
230 if (rtclock_timer_expire
== NULL
)
231 rtclock_timer_expire
= func
;
236 clock_interval_to_absolutetime_interval(
238 uint32_t scale_factor
,
241 uint64_t nanosecs
= (uint64_t)interval
* scale_factor
;
245 *result
= (t64
= nanosecs
/ NSEC_PER_SEC
) *
246 (divisor
= rtclock_sec_divisor
);
247 nanosecs
-= (t64
* NSEC_PER_SEC
);
248 *result
+= (nanosecs
* divisor
) / NSEC_PER_SEC
;
252 absolutetime_to_microtime(
260 *secs
= t64
= abstime
/ (divisor
= rtclock_sec_divisor
);
261 abstime
-= (t64
* divisor
);
262 *microsecs
= (abstime
* USEC_PER_SEC
) / divisor
;
266 absolutetime_to_nanotime(
274 *secs
= t64
= abstime
/ (divisor
= rtclock_sec_divisor
);
275 abstime
-= (t64
* divisor
);
276 *nanosecs
= (abstime
* NSEC_PER_SEC
) / divisor
;
280 nanotime_to_absolutetime(
285 uint32_t divisor
= rtclock_sec_divisor
;
287 *result
= ((uint64_t)secs
* divisor
) +
288 ((uint64_t)nanosecs
* divisor
) / NSEC_PER_SEC
;
292 absolutetime_to_nanoseconds(
299 *result
= (t64
= abstime
/ (divisor
= rtclock_sec_divisor
)) * NSEC_PER_SEC
;
300 abstime
-= (t64
* divisor
);
301 *result
+= (abstime
* NSEC_PER_SEC
) / divisor
;
305 nanoseconds_to_absolutetime(
312 *result
= (t64
= nanosecs
/ NSEC_PER_SEC
) *
313 (divisor
= rtclock_sec_divisor
);
314 nanosecs
-= (t64
* NSEC_PER_SEC
);
315 *result
+= (nanosecs
* divisor
) / NSEC_PER_SEC
;
325 now
= mach_absolute_time();
326 } while (now
< deadline
);