2 * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
32 * @APPLE_FREE_COPYRIGHT@
36 * Purpose: Routines for handling the machine dependent
40 #include <mach/mach_types.h>
42 #include <kern/clock.h>
43 #include <kern/thread.h>
44 #include <kern/processor.h>
45 #include <kern/macro_help.h>
49 #include <machine/commpage.h>
50 #include <machine/machine_routines.h>
51 #include <ppc/exception.h>
52 #include <ppc/proc_reg.h>
53 #include <ppc/rtclock.h>
55 #include <sys/kdebug.h>
57 int rtclock_config(void);
59 int rtclock_init(void);
61 #define NSEC_PER_HZ (NSEC_PER_SEC / 100)
63 static uint32_t rtclock_sec_divisor
;
65 static mach_timebase_info_data_t rtclock_timebase_const
;
67 static boolean_t rtclock_timebase_initialized
;
69 /* XXX this should really be in a header somewhere */
70 extern clock_timer_func_t rtclock_timer_expire
;
72 decl_simple_lock_data(static,rtclock_lock
)
75 * Macros to lock/unlock real-time clock device.
80 simple_lock(&rtclock_lock); \
83 #define UNLOCK_RTC(s) \
85 simple_unlock(&rtclock_lock); \
91 struct timebase_freq_t
*freq
)
93 uint32_t numer
, denom
;
96 if ( freq
->timebase_den
< 1 || freq
->timebase_den
> 4 ||
97 freq
->timebase_num
< freq
->timebase_den
)
98 panic("rtclock timebase_callback: invalid constant %lu / %lu",
99 freq
->timebase_num
, freq
->timebase_den
);
101 denom
= freq
->timebase_num
;
102 numer
= freq
->timebase_den
* NSEC_PER_SEC
;
105 if (!rtclock_timebase_initialized
) {
106 commpage_set_timestamp(0,0,0);
108 rtclock_timebase_const
.numer
= numer
;
109 rtclock_timebase_const
.denom
= denom
;
110 rtclock_sec_divisor
= freq
->timebase_num
/ freq
->timebase_den
;
112 ml_init_lock_timeout();
116 printf("rtclock timebase_callback: late old %d / %d new %d / %d\n",
117 rtclock_timebase_const
.numer
, rtclock_timebase_const
.denom
,
123 clock_timebase_init();
127 * Configure the system clock device.
132 simple_lock_init(&rtclock_lock
, 0);
134 PE_register_timebase_callback(timebase_callback
);
140 * Initialize the system clock device.
145 etimer_resync_deadlines(); /* Start the timers going */
151 clock_get_system_microtime(
158 now
= mach_absolute_time();
160 *secs
= t64
= now
/ (divisor
= rtclock_sec_divisor
);
161 now
-= (t64
* divisor
);
162 *microsecs
= (now
* USEC_PER_SEC
) / divisor
;
166 clock_get_system_nanotime(
173 now
= mach_absolute_time();
175 *secs
= t64
= now
/ (divisor
= rtclock_sec_divisor
);
176 now
-= (t64
* divisor
);
177 *nanosecs
= (now
* NSEC_PER_SEC
) / divisor
;
181 clock_gettimeofday_set_commpage(
188 uint64_t t64
, now
= abstime
;
190 simple_lock(&rtclock_lock
);
194 *secs
= t64
= now
/ rtclock_sec_divisor
;
195 now
-= (t64
* rtclock_sec_divisor
);
196 *microsecs
= (now
* USEC_PER_SEC
) / rtclock_sec_divisor
;
200 commpage_set_timestamp(abstime
- now
, *secs
, rtclock_sec_divisor
);
202 simple_unlock(&rtclock_lock
);
207 mach_timebase_info_t info
)
212 *info
= rtclock_timebase_const
;
213 rtclock_timebase_initialized
= TRUE
;
218 clock_set_timer_func(
219 clock_timer_func_t func
)
224 if (rtclock_timer_expire
== NULL
)
225 rtclock_timer_expire
= func
;
230 clock_interval_to_absolutetime_interval(
232 uint32_t scale_factor
,
235 uint64_t nanosecs
= (uint64_t)interval
* scale_factor
;
239 *result
= (t64
= nanosecs
/ NSEC_PER_SEC
) *
240 (divisor
= rtclock_sec_divisor
);
241 nanosecs
-= (t64
* NSEC_PER_SEC
);
242 *result
+= (nanosecs
* divisor
) / NSEC_PER_SEC
;
246 absolutetime_to_microtime(
254 *secs
= t64
= abstime
/ (divisor
= rtclock_sec_divisor
);
255 abstime
-= (t64
* divisor
);
256 *microsecs
= (abstime
* USEC_PER_SEC
) / divisor
;
260 absolutetime_to_nanotime(
268 *secs
= t64
= abstime
/ (divisor
= rtclock_sec_divisor
);
269 abstime
-= (t64
* divisor
);
270 *nanosecs
= (abstime
* NSEC_PER_SEC
) / divisor
;
274 nanotime_to_absolutetime(
279 uint32_t divisor
= rtclock_sec_divisor
;
281 *result
= ((uint64_t)secs
* divisor
) +
282 ((uint64_t)nanosecs
* divisor
) / NSEC_PER_SEC
;
286 absolutetime_to_nanoseconds(
293 *result
= (t64
= abstime
/ (divisor
= rtclock_sec_divisor
)) * NSEC_PER_SEC
;
294 abstime
-= (t64
* divisor
);
295 *result
+= (abstime
* NSEC_PER_SEC
) / divisor
;
299 nanoseconds_to_absolutetime(
306 *result
= (t64
= nanosecs
/ NSEC_PER_SEC
) *
307 (divisor
= rtclock_sec_divisor
);
308 nanosecs
-= (t64
* NSEC_PER_SEC
);
309 *result
+= (nanosecs
* divisor
) / NSEC_PER_SEC
;
319 now
= mach_absolute_time();
320 } while (now
< deadline
);