2 * Copyright (c) 2000-2008 Apple 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 decl_simple_lock_data(static,rtclock_lock
)
72 * Macros to lock/unlock real-time clock device.
77 simple_lock(&rtclock_lock); \
80 #define UNLOCK_RTC(s) \
82 simple_unlock(&rtclock_lock); \
88 struct timebase_freq_t
*freq
)
90 uint32_t numer
, denom
;
93 if ( freq
->timebase_den
< 1 || freq
->timebase_den
> 4 ||
94 freq
->timebase_num
< freq
->timebase_den
)
95 panic("rtclock timebase_callback: invalid constant %lu / %lu",
96 freq
->timebase_num
, freq
->timebase_den
);
98 denom
= freq
->timebase_num
;
99 numer
= freq
->timebase_den
* NSEC_PER_SEC
;
102 if (!rtclock_timebase_initialized
) {
103 commpage_set_timestamp(0,0,0);
105 rtclock_timebase_const
.numer
= numer
;
106 rtclock_timebase_const
.denom
= denom
;
107 rtclock_sec_divisor
= freq
->timebase_num
/ freq
->timebase_den
;
109 ml_init_lock_timeout();
113 printf("rtclock timebase_callback: late old %d / %d new %d / %d\n",
114 rtclock_timebase_const
.numer
, rtclock_timebase_const
.denom
,
120 clock_timebase_init();
124 * Configure the system clock device.
129 simple_lock_init(&rtclock_lock
, 0);
131 PE_register_timebase_callback(timebase_callback
);
137 * Initialize the system clock device.
142 etimer_resync_deadlines(); /* Start the timers going */
148 clock_get_system_microtime(
155 now
= mach_absolute_time();
157 *secs
= t64
= now
/ (divisor
= rtclock_sec_divisor
);
158 now
-= (t64
* divisor
);
159 *microsecs
= (now
* USEC_PER_SEC
) / divisor
;
163 clock_get_system_nanotime(
170 now
= mach_absolute_time();
172 *secs
= t64
= now
/ (divisor
= rtclock_sec_divisor
);
173 now
-= (t64
* divisor
);
174 *nanosecs
= (now
* NSEC_PER_SEC
) / divisor
;
178 clock_gettimeofday_set_commpage(
185 uint64_t t64
, now
= abstime
;
187 simple_lock(&rtclock_lock
);
191 *secs
= t64
= now
/ rtclock_sec_divisor
;
192 now
-= (t64
* rtclock_sec_divisor
);
193 *microsecs
= (now
* USEC_PER_SEC
) / rtclock_sec_divisor
;
197 commpage_set_timestamp(abstime
- now
, *secs
, rtclock_sec_divisor
);
199 simple_unlock(&rtclock_lock
);
204 mach_timebase_info_t info
)
209 *info
= rtclock_timebase_const
;
210 rtclock_timebase_initialized
= TRUE
;
215 clock_interval_to_absolutetime_interval(
217 uint32_t scale_factor
,
220 uint64_t nanosecs
= (uint64_t)interval
* scale_factor
;
224 *result
= (t64
= nanosecs
/ NSEC_PER_SEC
) *
225 (divisor
= rtclock_sec_divisor
);
226 nanosecs
-= (t64
* NSEC_PER_SEC
);
227 *result
+= (nanosecs
* divisor
) / NSEC_PER_SEC
;
231 absolutetime_to_microtime(
239 *secs
= t64
= abstime
/ (divisor
= rtclock_sec_divisor
);
240 abstime
-= (t64
* divisor
);
241 *microsecs
= (abstime
* USEC_PER_SEC
) / divisor
;
245 absolutetime_to_nanotime(
253 *secs
= t64
= abstime
/ (divisor
= rtclock_sec_divisor
);
254 abstime
-= (t64
* divisor
);
255 *nanosecs
= (abstime
* NSEC_PER_SEC
) / divisor
;
259 nanotime_to_absolutetime(
264 uint32_t divisor
= rtclock_sec_divisor
;
266 *result
= ((uint64_t)secs
* divisor
) +
267 ((uint64_t)nanosecs
* divisor
) / NSEC_PER_SEC
;
271 absolutetime_to_nanoseconds(
278 *result
= (t64
= abstime
/ (divisor
= rtclock_sec_divisor
)) * NSEC_PER_SEC
;
279 abstime
-= (t64
* divisor
);
280 *result
+= (abstime
* NSEC_PER_SEC
) / divisor
;
284 nanoseconds_to_absolutetime(
291 *result
= (t64
= nanosecs
/ NSEC_PER_SEC
) *
292 (divisor
= rtclock_sec_divisor
);
293 nanosecs
-= (t64
* NSEC_PER_SEC
);
294 *result
+= (nanosecs
* divisor
) / NSEC_PER_SEC
;
304 now
= mach_absolute_time();
305 } while (now
< deadline
);