diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/ppc/syslib/todc_time.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'arch/ppc/syslib/todc_time.c')
-rw-r--r-- | arch/ppc/syslib/todc_time.c | 513 |
1 files changed, 513 insertions, 0 deletions
diff --git a/arch/ppc/syslib/todc_time.c b/arch/ppc/syslib/todc_time.c new file mode 100644 index 000000000000..1323c641c19d --- /dev/null +++ b/arch/ppc/syslib/todc_time.c | |||
@@ -0,0 +1,513 @@ | |||
1 | /* | ||
2 | * arch/ppc/syslib/todc_time.c | ||
3 | * | ||
4 | * Time of Day Clock support for the M48T35, M48T37, M48T59, and MC146818 | ||
5 | * Real Time Clocks/Timekeepers. | ||
6 | * | ||
7 | * Author: Mark A. Greer | ||
8 | * mgreer@mvista.com | ||
9 | * | ||
10 | * 2001-2004 (c) MontaVista, Software, Inc. This file is licensed under | ||
11 | * the terms of the GNU General Public License version 2. This program | ||
12 | * is licensed "as is" without any warranty of any kind, whether express | ||
13 | * or implied. | ||
14 | */ | ||
15 | #include <linux/errno.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/time.h> | ||
19 | #include <linux/timex.h> | ||
20 | #include <linux/bcd.h> | ||
21 | #include <linux/mc146818rtc.h> | ||
22 | |||
23 | #include <asm/machdep.h> | ||
24 | #include <asm/io.h> | ||
25 | #include <asm/time.h> | ||
26 | #include <asm/todc.h> | ||
27 | |||
28 | /* | ||
29 | * Depending on the hardware on your board and your board design, the | ||
30 | * RTC/NVRAM may be accessed either directly (like normal memory) or via | ||
31 | * address/data registers. If your board uses the direct method, set | ||
32 | * 'nvram_data' to the base address of your nvram and leave 'nvram_as0' and | ||
33 | * 'nvram_as1' NULL. If your board uses address/data regs to access nvram, | ||
34 | * set 'nvram_as0' to the address of the lower byte, set 'nvram_as1' to the | ||
35 | * address of the upper byte (leave NULL if using mc146818), and set | ||
36 | * 'nvram_data' to the address of the 8-bit data register. | ||
37 | * | ||
38 | * In order to break the assumption that the RTC and NVRAM are accessed by | ||
39 | * the same mechanism, you need to explicitly set 'ppc_md.rtc_read_val' and | ||
40 | * 'ppc_md.rtc_write_val', otherwise the values of 'ppc_md.rtc_read_val' | ||
41 | * and 'ppc_md.rtc_write_val' will be used. | ||
42 | * | ||
43 | * Note: Even though the documentation for the various RTC chips say that it | ||
44 | * take up to a second before it starts updating once the 'R' bit is | ||
45 | * cleared, they always seem to update even though we bang on it many | ||
46 | * times a second. This is true, except for the Dallas Semi 1746/1747 | ||
47 | * (possibly others). Those chips seem to have a real problem whenever | ||
48 | * we set the 'R' bit before reading them, they basically stop counting. | ||
49 | * --MAG | ||
50 | */ | ||
51 | |||
52 | /* | ||
53 | * 'todc_info' should be initialized in your *_setup.c file to | ||
54 | * point to a fully initialized 'todc_info_t' structure. | ||
55 | * This structure holds all the register offsets for your particular | ||
56 | * TODC/RTC chip. | ||
57 | * TODC_ALLOC()/TODC_INIT() will allocate and initialize this table for you. | ||
58 | */ | ||
59 | |||
60 | #ifdef RTC_FREQ_SELECT | ||
61 | #undef RTC_FREQ_SELECT | ||
62 | #define RTC_FREQ_SELECT control_b /* Register A */ | ||
63 | #endif | ||
64 | |||
65 | #ifdef RTC_CONTROL | ||
66 | #undef RTC_CONTROL | ||
67 | #define RTC_CONTROL control_a /* Register B */ | ||
68 | #endif | ||
69 | |||
70 | #ifdef RTC_INTR_FLAGS | ||
71 | #undef RTC_INTR_FLAGS | ||
72 | #define RTC_INTR_FLAGS watchdog /* Register C */ | ||
73 | #endif | ||
74 | |||
75 | #ifdef RTC_VALID | ||
76 | #undef RTC_VALID | ||
77 | #define RTC_VALID interrupts /* Register D */ | ||
78 | #endif | ||
79 | |||
80 | /* Access routines when RTC accessed directly (like normal memory) */ | ||
81 | u_char | ||
82 | todc_direct_read_val(int addr) | ||
83 | { | ||
84 | return readb((void __iomem *)(todc_info->nvram_data + addr)); | ||
85 | } | ||
86 | |||
87 | void | ||
88 | todc_direct_write_val(int addr, unsigned char val) | ||
89 | { | ||
90 | writeb(val, (void __iomem *)(todc_info->nvram_data + addr)); | ||
91 | return; | ||
92 | } | ||
93 | |||
94 | /* Access routines for accessing m48txx type chips via addr/data regs */ | ||
95 | u_char | ||
96 | todc_m48txx_read_val(int addr) | ||
97 | { | ||
98 | outb(addr, todc_info->nvram_as0); | ||
99 | outb(addr>>todc_info->as0_bits, todc_info->nvram_as1); | ||
100 | return inb(todc_info->nvram_data); | ||
101 | } | ||
102 | |||
103 | void | ||
104 | todc_m48txx_write_val(int addr, unsigned char val) | ||
105 | { | ||
106 | outb(addr, todc_info->nvram_as0); | ||
107 | outb(addr>>todc_info->as0_bits, todc_info->nvram_as1); | ||
108 | outb(val, todc_info->nvram_data); | ||
109 | return; | ||
110 | } | ||
111 | |||
112 | /* Access routines for accessing mc146818 type chips via addr/data regs */ | ||
113 | u_char | ||
114 | todc_mc146818_read_val(int addr) | ||
115 | { | ||
116 | outb_p(addr, todc_info->nvram_as0); | ||
117 | return inb_p(todc_info->nvram_data); | ||
118 | } | ||
119 | |||
120 | void | ||
121 | todc_mc146818_write_val(int addr, unsigned char val) | ||
122 | { | ||
123 | outb_p(addr, todc_info->nvram_as0); | ||
124 | outb_p(val, todc_info->nvram_data); | ||
125 | } | ||
126 | |||
127 | |||
128 | /* | ||
129 | * Routines to make RTC chips with NVRAM buried behind an addr/data pair | ||
130 | * have the NVRAM and clock regs appear at the same level. | ||
131 | * The NVRAM will appear to start at addr 0 and the clock regs will appear | ||
132 | * to start immediately after the NVRAM (actually, start at offset | ||
133 | * todc_info->nvram_size). | ||
134 | */ | ||
135 | static inline u_char | ||
136 | todc_read_val(int addr) | ||
137 | { | ||
138 | u_char val; | ||
139 | |||
140 | if (todc_info->sw_flags & TODC_FLAG_2_LEVEL_NVRAM) { | ||
141 | if (addr < todc_info->nvram_size) { /* NVRAM */ | ||
142 | ppc_md.rtc_write_val(todc_info->nvram_addr_reg, addr); | ||
143 | val = ppc_md.rtc_read_val(todc_info->nvram_data_reg); | ||
144 | } | ||
145 | else { /* Clock Reg */ | ||
146 | addr -= todc_info->nvram_size; | ||
147 | val = ppc_md.rtc_read_val(addr); | ||
148 | } | ||
149 | } | ||
150 | else { | ||
151 | val = ppc_md.rtc_read_val(addr); | ||
152 | } | ||
153 | |||
154 | return val; | ||
155 | } | ||
156 | |||
157 | static inline void | ||
158 | todc_write_val(int addr, u_char val) | ||
159 | { | ||
160 | if (todc_info->sw_flags & TODC_FLAG_2_LEVEL_NVRAM) { | ||
161 | if (addr < todc_info->nvram_size) { /* NVRAM */ | ||
162 | ppc_md.rtc_write_val(todc_info->nvram_addr_reg, addr); | ||
163 | ppc_md.rtc_write_val(todc_info->nvram_data_reg, val); | ||
164 | } | ||
165 | else { /* Clock Reg */ | ||
166 | addr -= todc_info->nvram_size; | ||
167 | ppc_md.rtc_write_val(addr, val); | ||
168 | } | ||
169 | } | ||
170 | else { | ||
171 | ppc_md.rtc_write_val(addr, val); | ||
172 | } | ||
173 | } | ||
174 | |||
175 | /* | ||
176 | * TODC routines | ||
177 | * | ||
178 | * There is some ugly stuff in that there are assumptions for the mc146818. | ||
179 | * | ||
180 | * Assumptions: | ||
181 | * - todc_info->control_a has the offset as mc146818 Register B reg | ||
182 | * - todc_info->control_b has the offset as mc146818 Register A reg | ||
183 | * - m48txx control reg's write enable or 'W' bit is same as | ||
184 | * mc146818 Register B 'SET' bit (i.e., 0x80) | ||
185 | * | ||
186 | * These assumptions were made to make the code simpler. | ||
187 | */ | ||
188 | long __init | ||
189 | todc_time_init(void) | ||
190 | { | ||
191 | u_char cntl_b; | ||
192 | |||
193 | if (!ppc_md.rtc_read_val) | ||
194 | ppc_md.rtc_read_val = ppc_md.nvram_read_val; | ||
195 | if (!ppc_md.rtc_write_val) | ||
196 | ppc_md.rtc_write_val = ppc_md.nvram_write_val; | ||
197 | |||
198 | cntl_b = todc_read_val(todc_info->control_b); | ||
199 | |||
200 | if (todc_info->rtc_type == TODC_TYPE_MC146818) { | ||
201 | if ((cntl_b & 0x70) != 0x20) { | ||
202 | printk(KERN_INFO "TODC %s %s\n", | ||
203 | "real-time-clock was stopped.", | ||
204 | "Now starting..."); | ||
205 | cntl_b &= ~0x70; | ||
206 | cntl_b |= 0x20; | ||
207 | } | ||
208 | |||
209 | todc_write_val(todc_info->control_b, cntl_b); | ||
210 | } else if (todc_info->rtc_type == TODC_TYPE_DS17285) { | ||
211 | u_char mode; | ||
212 | |||
213 | mode = todc_read_val(TODC_TYPE_DS17285_CNTL_A); | ||
214 | /* Make sure countdown clear is not set */ | ||
215 | mode &= ~0x40; | ||
216 | /* Enable oscillator, extended register set */ | ||
217 | mode |= 0x30; | ||
218 | todc_write_val(TODC_TYPE_DS17285_CNTL_A, mode); | ||
219 | |||
220 | } else if (todc_info->rtc_type == TODC_TYPE_DS1501) { | ||
221 | u_char month; | ||
222 | |||
223 | todc_info->enable_read = TODC_DS1501_CNTL_B_TE; | ||
224 | todc_info->enable_write = TODC_DS1501_CNTL_B_TE; | ||
225 | |||
226 | month = todc_read_val(todc_info->month); | ||
227 | |||
228 | if ((month & 0x80) == 0x80) { | ||
229 | printk(KERN_INFO "TODC %s %s\n", | ||
230 | "real-time-clock was stopped.", | ||
231 | "Now starting..."); | ||
232 | month &= ~0x80; | ||
233 | todc_write_val(todc_info->month, month); | ||
234 | } | ||
235 | |||
236 | cntl_b &= ~TODC_DS1501_CNTL_B_TE; | ||
237 | todc_write_val(todc_info->control_b, cntl_b); | ||
238 | } else { /* must be a m48txx type */ | ||
239 | u_char cntl_a; | ||
240 | |||
241 | todc_info->enable_read = TODC_MK48TXX_CNTL_A_R; | ||
242 | todc_info->enable_write = TODC_MK48TXX_CNTL_A_W; | ||
243 | |||
244 | cntl_a = todc_read_val(todc_info->control_a); | ||
245 | |||
246 | /* Check & clear STOP bit in control B register */ | ||
247 | if (cntl_b & TODC_MK48TXX_DAY_CB) { | ||
248 | printk(KERN_INFO "TODC %s %s\n", | ||
249 | "real-time-clock was stopped.", | ||
250 | "Now starting..."); | ||
251 | |||
252 | cntl_a |= todc_info->enable_write; | ||
253 | cntl_b &= ~TODC_MK48TXX_DAY_CB;/* Start Oscil */ | ||
254 | |||
255 | todc_write_val(todc_info->control_a, cntl_a); | ||
256 | todc_write_val(todc_info->control_b, cntl_b); | ||
257 | } | ||
258 | |||
259 | /* Make sure READ & WRITE bits are cleared. */ | ||
260 | cntl_a &= ~(todc_info->enable_write | | ||
261 | todc_info->enable_read); | ||
262 | todc_write_val(todc_info->control_a, cntl_a); | ||
263 | } | ||
264 | |||
265 | return 0; | ||
266 | } | ||
267 | |||
268 | /* | ||
269 | * There is some ugly stuff in that there are assumptions that for a mc146818, | ||
270 | * the todc_info->control_a has the offset of the mc146818 Register B reg and | ||
271 | * that the register'ss 'SET' bit is the same as the m48txx's write enable | ||
272 | * bit in the control register of the m48txx (i.e., 0x80). | ||
273 | * | ||
274 | * It was done to make the code look simpler. | ||
275 | */ | ||
276 | ulong | ||
277 | todc_get_rtc_time(void) | ||
278 | { | ||
279 | uint year = 0, mon = 0, day = 0, hour = 0, min = 0, sec = 0; | ||
280 | uint limit, i; | ||
281 | u_char save_control, uip = 0; | ||
282 | |||
283 | spin_lock(&rtc_lock); | ||
284 | save_control = todc_read_val(todc_info->control_a); | ||
285 | |||
286 | if (todc_info->rtc_type != TODC_TYPE_MC146818) { | ||
287 | limit = 1; | ||
288 | |||
289 | switch (todc_info->rtc_type) { | ||
290 | case TODC_TYPE_DS1553: | ||
291 | case TODC_TYPE_DS1557: | ||
292 | case TODC_TYPE_DS1743: | ||
293 | case TODC_TYPE_DS1746: /* XXXX BAD HACK -> FIX */ | ||
294 | case TODC_TYPE_DS1747: | ||
295 | case TODC_TYPE_DS17285: | ||
296 | break; | ||
297 | default: | ||
298 | todc_write_val(todc_info->control_a, | ||
299 | (save_control | todc_info->enable_read)); | ||
300 | } | ||
301 | } | ||
302 | else { | ||
303 | limit = 100000000; | ||
304 | } | ||
305 | |||
306 | for (i=0; i<limit; i++) { | ||
307 | if (todc_info->rtc_type == TODC_TYPE_MC146818) { | ||
308 | uip = todc_read_val(todc_info->RTC_FREQ_SELECT); | ||
309 | } | ||
310 | |||
311 | sec = todc_read_val(todc_info->seconds) & 0x7f; | ||
312 | min = todc_read_val(todc_info->minutes) & 0x7f; | ||
313 | hour = todc_read_val(todc_info->hours) & 0x3f; | ||
314 | day = todc_read_val(todc_info->day_of_month) & 0x3f; | ||
315 | mon = todc_read_val(todc_info->month) & 0x1f; | ||
316 | year = todc_read_val(todc_info->year) & 0xff; | ||
317 | |||
318 | if (todc_info->rtc_type == TODC_TYPE_MC146818) { | ||
319 | uip |= todc_read_val(todc_info->RTC_FREQ_SELECT); | ||
320 | if ((uip & RTC_UIP) == 0) break; | ||
321 | } | ||
322 | } | ||
323 | |||
324 | if (todc_info->rtc_type != TODC_TYPE_MC146818) { | ||
325 | switch (todc_info->rtc_type) { | ||
326 | case TODC_TYPE_DS1553: | ||
327 | case TODC_TYPE_DS1557: | ||
328 | case TODC_TYPE_DS1743: | ||
329 | case TODC_TYPE_DS1746: /* XXXX BAD HACK -> FIX */ | ||
330 | case TODC_TYPE_DS1747: | ||
331 | case TODC_TYPE_DS17285: | ||
332 | break; | ||
333 | default: | ||
334 | save_control &= ~(todc_info->enable_read); | ||
335 | todc_write_val(todc_info->control_a, | ||
336 | save_control); | ||
337 | } | ||
338 | } | ||
339 | spin_unlock(&rtc_lock); | ||
340 | |||
341 | if ((todc_info->rtc_type != TODC_TYPE_MC146818) || | ||
342 | ((save_control & RTC_DM_BINARY) == 0) || | ||
343 | RTC_ALWAYS_BCD) { | ||
344 | |||
345 | BCD_TO_BIN(sec); | ||
346 | BCD_TO_BIN(min); | ||
347 | BCD_TO_BIN(hour); | ||
348 | BCD_TO_BIN(day); | ||
349 | BCD_TO_BIN(mon); | ||
350 | BCD_TO_BIN(year); | ||
351 | } | ||
352 | |||
353 | year = year + 1900; | ||
354 | if (year < 1970) { | ||
355 | year += 100; | ||
356 | } | ||
357 | |||
358 | return mktime(year, mon, day, hour, min, sec); | ||
359 | } | ||
360 | |||
361 | int | ||
362 | todc_set_rtc_time(unsigned long nowtime) | ||
363 | { | ||
364 | struct rtc_time tm; | ||
365 | u_char save_control, save_freq_select = 0; | ||
366 | |||
367 | spin_lock(&rtc_lock); | ||
368 | to_tm(nowtime, &tm); | ||
369 | |||
370 | save_control = todc_read_val(todc_info->control_a); | ||
371 | |||
372 | /* Assuming MK48T59_RTC_CA_WRITE & RTC_SET are equal */ | ||
373 | todc_write_val(todc_info->control_a, | ||
374 | (save_control | todc_info->enable_write)); | ||
375 | save_control &= ~(todc_info->enable_write); /* in case it was set */ | ||
376 | |||
377 | if (todc_info->rtc_type == TODC_TYPE_MC146818) { | ||
378 | save_freq_select = todc_read_val(todc_info->RTC_FREQ_SELECT); | ||
379 | todc_write_val(todc_info->RTC_FREQ_SELECT, | ||
380 | save_freq_select | RTC_DIV_RESET2); | ||
381 | } | ||
382 | |||
383 | |||
384 | tm.tm_year = (tm.tm_year - 1900) % 100; | ||
385 | |||
386 | if ((todc_info->rtc_type != TODC_TYPE_MC146818) || | ||
387 | ((save_control & RTC_DM_BINARY) == 0) || | ||
388 | RTC_ALWAYS_BCD) { | ||
389 | |||
390 | BIN_TO_BCD(tm.tm_sec); | ||
391 | BIN_TO_BCD(tm.tm_min); | ||
392 | BIN_TO_BCD(tm.tm_hour); | ||
393 | BIN_TO_BCD(tm.tm_mon); | ||
394 | BIN_TO_BCD(tm.tm_mday); | ||
395 | BIN_TO_BCD(tm.tm_year); | ||
396 | } | ||
397 | |||
398 | todc_write_val(todc_info->seconds, tm.tm_sec); | ||
399 | todc_write_val(todc_info->minutes, tm.tm_min); | ||
400 | todc_write_val(todc_info->hours, tm.tm_hour); | ||
401 | todc_write_val(todc_info->month, tm.tm_mon); | ||
402 | todc_write_val(todc_info->day_of_month, tm.tm_mday); | ||
403 | todc_write_val(todc_info->year, tm.tm_year); | ||
404 | |||
405 | todc_write_val(todc_info->control_a, save_control); | ||
406 | |||
407 | if (todc_info->rtc_type == TODC_TYPE_MC146818) { | ||
408 | todc_write_val(todc_info->RTC_FREQ_SELECT, save_freq_select); | ||
409 | } | ||
410 | spin_unlock(&rtc_lock); | ||
411 | |||
412 | return 0; | ||
413 | } | ||
414 | |||
415 | /* | ||
416 | * Manipulates read bit to reliably read seconds at a high rate. | ||
417 | */ | ||
418 | static unsigned char __init todc_read_timereg(int addr) | ||
419 | { | ||
420 | unsigned char save_control = 0, val; | ||
421 | |||
422 | switch (todc_info->rtc_type) { | ||
423 | case TODC_TYPE_DS1553: | ||
424 | case TODC_TYPE_DS1557: | ||
425 | case TODC_TYPE_DS1746: /* XXXX BAD HACK -> FIX */ | ||
426 | case TODC_TYPE_DS1747: | ||
427 | case TODC_TYPE_DS17285: | ||
428 | case TODC_TYPE_MC146818: | ||
429 | break; | ||
430 | default: | ||
431 | save_control = todc_read_val(todc_info->control_a); | ||
432 | todc_write_val(todc_info->control_a, | ||
433 | (save_control | todc_info->enable_read)); | ||
434 | } | ||
435 | val = todc_read_val(addr); | ||
436 | |||
437 | switch (todc_info->rtc_type) { | ||
438 | case TODC_TYPE_DS1553: | ||
439 | case TODC_TYPE_DS1557: | ||
440 | case TODC_TYPE_DS1746: /* XXXX BAD HACK -> FIX */ | ||
441 | case TODC_TYPE_DS1747: | ||
442 | case TODC_TYPE_DS17285: | ||
443 | case TODC_TYPE_MC146818: | ||
444 | break; | ||
445 | default: | ||
446 | save_control &= ~(todc_info->enable_read); | ||
447 | todc_write_val(todc_info->control_a, save_control); | ||
448 | } | ||
449 | |||
450 | return val; | ||
451 | } | ||
452 | |||
453 | /* | ||
454 | * This was taken from prep_setup.c | ||
455 | * Use the NVRAM RTC to time a second to calibrate the decrementer. | ||
456 | */ | ||
457 | void __init | ||
458 | todc_calibrate_decr(void) | ||
459 | { | ||
460 | ulong freq; | ||
461 | ulong tbl, tbu; | ||
462 | long i, loop_count; | ||
463 | u_char sec; | ||
464 | |||
465 | todc_time_init(); | ||
466 | |||
467 | /* | ||
468 | * Actually this is bad for precision, we should have a loop in | ||
469 | * which we only read the seconds counter. todc_read_val writes | ||
470 | * the address bytes on every call and this takes a lot of time. | ||
471 | * Perhaps an nvram_wait_change method returning a time | ||
472 | * stamp with a loop count as parameter would be the solution. | ||
473 | */ | ||
474 | /* | ||
475 | * Need to make sure the tbl doesn't roll over so if tbu increments | ||
476 | * during this test, we need to do it again. | ||
477 | */ | ||
478 | loop_count = 0; | ||
479 | |||
480 | sec = todc_read_timereg(todc_info->seconds) & 0x7f; | ||
481 | |||
482 | do { | ||
483 | tbu = get_tbu(); | ||
484 | |||
485 | for (i = 0 ; i < 10000000 ; i++) {/* may take up to 1 second */ | ||
486 | tbl = get_tbl(); | ||
487 | |||
488 | if ((todc_read_timereg(todc_info->seconds) & 0x7f) != sec) { | ||
489 | break; | ||
490 | } | ||
491 | } | ||
492 | |||
493 | sec = todc_read_timereg(todc_info->seconds) & 0x7f; | ||
494 | |||
495 | for (i = 0 ; i < 10000000 ; i++) { /* Should take 1 second */ | ||
496 | freq = get_tbl(); | ||
497 | |||
498 | if ((todc_read_timereg(todc_info->seconds) & 0x7f) != sec) { | ||
499 | break; | ||
500 | } | ||
501 | } | ||
502 | |||
503 | freq -= tbl; | ||
504 | } while ((get_tbu() != tbu) && (++loop_count < 2)); | ||
505 | |||
506 | printk("time_init: decrementer frequency = %lu.%.6lu MHz\n", | ||
507 | freq/1000000, freq%1000000); | ||
508 | |||
509 | tb_ticks_per_jiffy = freq / HZ; | ||
510 | tb_to_us = mulhwu_scale_factor(freq, 1000000); | ||
511 | |||
512 | return; | ||
513 | } | ||