allow coexistance of N build and AC build.
[tomato.git] / release / src-rt-6.x / linux / linux-2.6 / arch / i386 / kernel / hpet.c
blobcbb47519e0cf5dd554426d2cdbec38acf741b476
1 #include <linux/clocksource.h>
2 #include <linux/clockchips.h>
3 #include <linux/errno.h>
4 #include <linux/hpet.h>
5 #include <linux/init.h>
6 #include <linux/sysdev.h>
7 #include <linux/pm.h>
9 #include <asm/hpet.h>
10 #include <asm/io.h>
12 extern struct clock_event_device *global_clock_event;
14 #define HPET_MASK CLOCKSOURCE_MASK(32)
15 #define HPET_SHIFT 22
17 /* FSEC = 10^-15 NSEC = 10^-9 */
18 #define FSEC_PER_NSEC 1000000
21 * HPET address is set in acpi/boot.c, when an ACPI entry exists
23 unsigned long hpet_address;
24 static void __iomem * hpet_virt_address;
26 static inline unsigned long hpet_readl(unsigned long a)
28 return readl(hpet_virt_address + a);
31 static inline void hpet_writel(unsigned long d, unsigned long a)
33 writel(d, hpet_virt_address + a);
37 * HPET command line enable / disable
39 static int boot_hpet_disable;
41 static int __init hpet_setup(char* str)
43 if (str) {
44 if (!strncmp("disable", str, 7))
45 boot_hpet_disable = 1;
47 return 1;
49 __setup("hpet=", hpet_setup);
51 static inline int is_hpet_capable(void)
53 return (!boot_hpet_disable && hpet_address);
57 * HPET timer interrupt enable / disable
59 static int hpet_legacy_int_enabled;
61 /**
62 * is_hpet_enabled - check whether the hpet timer interrupt is enabled
64 int is_hpet_enabled(void)
66 return is_hpet_capable() && hpet_legacy_int_enabled;
70 * When the hpet driver (/dev/hpet) is enabled, we need to reserve
71 * timer 0 and timer 1 in case of RTC emulation.
73 #ifdef CONFIG_HPET
74 static void hpet_reserve_platform_timers(unsigned long id)
76 struct hpet __iomem *hpet = hpet_virt_address;
77 struct hpet_timer __iomem *timer = &hpet->hpet_timers[2];
78 unsigned int nrtimers, i;
79 struct hpet_data hd;
81 nrtimers = ((id & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT) + 1;
83 memset(&hd, 0, sizeof (hd));
84 hd.hd_phys_address = hpet_address;
85 hd.hd_address = hpet_virt_address;
86 hd.hd_nirqs = nrtimers;
87 hd.hd_flags = HPET_DATA_PLATFORM;
88 hpet_reserve_timer(&hd, 0);
90 #ifdef CONFIG_HPET_EMULATE_RTC
91 hpet_reserve_timer(&hd, 1);
92 #endif
94 hd.hd_irq[0] = HPET_LEGACY_8254;
95 hd.hd_irq[1] = HPET_LEGACY_RTC;
97 for (i = 2; i < nrtimers; timer++, i++)
98 hd.hd_irq[i] = (timer->hpet_config & Tn_INT_ROUTE_CNF_MASK) >>
99 Tn_INT_ROUTE_CNF_SHIFT;
101 hpet_alloc(&hd);
104 #else
105 static void hpet_reserve_platform_timers(unsigned long id) { }
106 #endif
109 * Common hpet info
111 static unsigned long hpet_period;
113 static void hpet_set_mode(enum clock_event_mode mode,
114 struct clock_event_device *evt);
115 static int hpet_next_event(unsigned long delta,
116 struct clock_event_device *evt);
119 * The hpet clock event device
121 static struct clock_event_device hpet_clockevent = {
122 .name = "hpet",
123 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
124 .set_mode = hpet_set_mode,
125 .set_next_event = hpet_next_event,
126 .shift = 32,
127 .irq = 0,
130 static void hpet_start_counter(void)
132 unsigned long cfg = hpet_readl(HPET_CFG);
134 cfg &= ~HPET_CFG_ENABLE;
135 hpet_writel(cfg, HPET_CFG);
136 hpet_writel(0, HPET_COUNTER);
137 hpet_writel(0, HPET_COUNTER + 4);
138 cfg |= HPET_CFG_ENABLE;
139 hpet_writel(cfg, HPET_CFG);
142 static void hpet_enable_int(void)
144 unsigned long cfg = hpet_readl(HPET_CFG);
146 cfg |= HPET_CFG_LEGACY;
147 hpet_writel(cfg, HPET_CFG);
148 hpet_legacy_int_enabled = 1;
151 static void hpet_set_mode(enum clock_event_mode mode,
152 struct clock_event_device *evt)
154 unsigned long cfg, cmp, now;
155 uint64_t delta;
157 switch(mode) {
158 case CLOCK_EVT_MODE_PERIODIC:
159 delta = ((uint64_t)(NSEC_PER_SEC/HZ)) * hpet_clockevent.mult;
160 delta >>= hpet_clockevent.shift;
161 now = hpet_readl(HPET_COUNTER);
162 cmp = now + (unsigned long) delta;
163 cfg = hpet_readl(HPET_T0_CFG);
164 cfg |= HPET_TN_ENABLE | HPET_TN_PERIODIC |
165 HPET_TN_SETVAL | HPET_TN_32BIT;
166 hpet_writel(cfg, HPET_T0_CFG);
168 * The first write after writing TN_SETVAL to the
169 * config register sets the counter value, the second
170 * write sets the period.
172 hpet_writel(cmp, HPET_T0_CMP);
173 udelay(1);
174 hpet_writel((unsigned long) delta, HPET_T0_CMP);
175 break;
177 case CLOCK_EVT_MODE_ONESHOT:
178 cfg = hpet_readl(HPET_T0_CFG);
179 cfg &= ~HPET_TN_PERIODIC;
180 cfg |= HPET_TN_ENABLE | HPET_TN_32BIT;
181 hpet_writel(cfg, HPET_T0_CFG);
182 break;
184 case CLOCK_EVT_MODE_UNUSED:
185 case CLOCK_EVT_MODE_SHUTDOWN:
186 cfg = hpet_readl(HPET_T0_CFG);
187 cfg &= ~HPET_TN_ENABLE;
188 hpet_writel(cfg, HPET_T0_CFG);
189 break;
193 static int hpet_next_event(unsigned long delta,
194 struct clock_event_device *evt)
196 unsigned long cnt;
198 cnt = hpet_readl(HPET_COUNTER);
199 cnt += delta;
200 hpet_writel(cnt, HPET_T0_CMP);
202 return ((long)(hpet_readl(HPET_COUNTER) - cnt ) > 0) ? -ETIME : 0;
206 * Clock source related code
208 static cycle_t read_hpet(void)
210 return (cycle_t)hpet_readl(HPET_COUNTER);
213 static struct clocksource clocksource_hpet = {
214 .name = "hpet",
215 .rating = 250,
216 .read = read_hpet,
217 .mask = HPET_MASK,
218 .shift = HPET_SHIFT,
219 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
223 * Try to setup the HPET timer
225 int __init hpet_enable(void)
227 unsigned long id;
228 uint64_t hpet_freq;
229 u64 tmp, start, now;
230 cycle_t t1;
232 if (!is_hpet_capable())
233 return 0;
235 hpet_virt_address = ioremap_nocache(hpet_address, HPET_MMAP_SIZE);
238 * Read the period and check for a sane value:
240 hpet_period = hpet_readl(HPET_PERIOD);
241 if (hpet_period < HPET_MIN_PERIOD || hpet_period > HPET_MAX_PERIOD)
242 goto out_nohpet;
245 * The period is a femto seconds value. We need to calculate the
246 * scaled math multiplication factor for nanosecond to hpet tick
247 * conversion.
249 hpet_freq = 1000000000000000ULL;
250 do_div(hpet_freq, hpet_period);
251 hpet_clockevent.mult = div_sc((unsigned long) hpet_freq,
252 NSEC_PER_SEC, 32);
253 /* Calculate the min / max delta */
254 hpet_clockevent.max_delta_ns = clockevent_delta2ns(0x7FFFFFFF,
255 &hpet_clockevent);
256 hpet_clockevent.min_delta_ns = clockevent_delta2ns(0x30,
257 &hpet_clockevent);
260 * Read the HPET ID register to retrieve the IRQ routing
261 * information and the number of channels
263 id = hpet_readl(HPET_ID);
265 #ifdef CONFIG_HPET_EMULATE_RTC
267 * The legacy routing mode needs at least two channels, tick timer
268 * and the rtc emulation channel.
270 if (!(id & HPET_ID_NUMBER))
271 goto out_nohpet;
272 #endif
274 /* Start the counter */
275 hpet_start_counter();
277 /* Verify whether hpet counter works */
278 t1 = read_hpet();
279 rdtscll(start);
282 * We don't know the TSC frequency yet, but waiting for
283 * 200000 TSC cycles is safe:
284 * 4 GHz == 50us
285 * 1 GHz == 200us
287 do {
288 rep_nop();
289 rdtscll(now);
290 } while ((now - start) < 200000UL);
292 if (t1 == read_hpet()) {
293 printk(KERN_WARNING
294 "HPET counter not counting. HPET disabled\n");
295 goto out_nohpet;
298 /* Initialize and register HPET clocksource
300 * hpet period is in femto seconds per cycle
301 * so we need to convert this to ns/cyc units
302 * aproximated by mult/2^shift
304 * fsec/cyc * 1nsec/1000000fsec = nsec/cyc = mult/2^shift
305 * fsec/cyc * 1ns/1000000fsec * 2^shift = mult
306 * fsec/cyc * 2^shift * 1nsec/1000000fsec = mult
307 * (fsec/cyc << shift)/1000000 = mult
308 * (hpet_period << shift)/FSEC_PER_NSEC = mult
310 tmp = (u64)hpet_period << HPET_SHIFT;
311 do_div(tmp, FSEC_PER_NSEC);
312 clocksource_hpet.mult = (u32)tmp;
314 clocksource_register(&clocksource_hpet);
317 if (id & HPET_ID_LEGSUP) {
318 hpet_enable_int();
319 hpet_reserve_platform_timers(id);
321 * Start hpet with the boot cpu mask and make it
322 * global after the IO_APIC has been initialized.
324 hpet_clockevent.cpumask =cpumask_of_cpu(0);
325 clockevents_register_device(&hpet_clockevent);
326 global_clock_event = &hpet_clockevent;
327 return 1;
329 return 0;
331 out_nohpet:
332 iounmap(hpet_virt_address);
333 hpet_virt_address = NULL;
334 boot_hpet_disable = 1;
335 return 0;
339 #ifdef CONFIG_HPET_EMULATE_RTC
341 /* HPET in LegacyReplacement Mode eats up RTC interrupt line. When, HPET
342 * is enabled, we support RTC interrupt functionality in software.
343 * RTC has 3 kinds of interrupts:
344 * 1) Update Interrupt - generate an interrupt, every sec, when RTC clock
345 * is updated
346 * 2) Alarm Interrupt - generate an interrupt at a specific time of day
347 * 3) Periodic Interrupt - generate periodic interrupt, with frequencies
348 * 2Hz-8192Hz (2Hz-64Hz for non-root user) (all freqs in powers of 2)
349 * (1) and (2) above are implemented using polling at a frequency of
350 * 64 Hz. The exact frequency is a tradeoff between accuracy and interrupt
351 * overhead. (DEFAULT_RTC_INT_FREQ)
352 * For (3), we use interrupts at 64Hz or user specified periodic
353 * frequency, whichever is higher.
355 #include <linux/mc146818rtc.h>
356 #include <linux/rtc.h>
358 #define DEFAULT_RTC_INT_FREQ 64
359 #define DEFAULT_RTC_SHIFT 6
360 #define RTC_NUM_INTS 1
362 static unsigned long hpet_rtc_flags;
363 static unsigned long hpet_prev_update_sec;
364 static struct rtc_time hpet_alarm_time;
365 static unsigned long hpet_pie_count;
366 static unsigned long hpet_t1_cmp;
367 static unsigned long hpet_default_delta;
368 static unsigned long hpet_pie_delta;
369 static unsigned long hpet_pie_limit;
372 * Timer 1 for RTC emulation. We use one shot mode, as periodic mode
373 * is not supported by all HPET implementations for timer 1.
375 * hpet_rtc_timer_init() is called when the rtc is initialized.
377 int hpet_rtc_timer_init(void)
379 unsigned long cfg, cnt, delta, flags;
381 if (!is_hpet_enabled())
382 return 0;
384 if (!hpet_default_delta) {
385 uint64_t clc;
387 clc = (uint64_t) hpet_clockevent.mult * NSEC_PER_SEC;
388 clc >>= hpet_clockevent.shift + DEFAULT_RTC_SHIFT;
389 hpet_default_delta = (unsigned long) clc;
392 if (!(hpet_rtc_flags & RTC_PIE) || hpet_pie_limit)
393 delta = hpet_default_delta;
394 else
395 delta = hpet_pie_delta;
397 local_irq_save(flags);
399 cnt = delta + hpet_readl(HPET_COUNTER);
400 hpet_writel(cnt, HPET_T1_CMP);
401 hpet_t1_cmp = cnt;
403 cfg = hpet_readl(HPET_T1_CFG);
404 cfg &= ~HPET_TN_PERIODIC;
405 cfg |= HPET_TN_ENABLE | HPET_TN_32BIT;
406 hpet_writel(cfg, HPET_T1_CFG);
408 local_irq_restore(flags);
410 return 1;
414 * The functions below are called from rtc driver.
415 * Return 0 if HPET is not being used.
416 * Otherwise do the necessary changes and return 1.
418 int hpet_mask_rtc_irq_bit(unsigned long bit_mask)
420 if (!is_hpet_enabled())
421 return 0;
423 hpet_rtc_flags &= ~bit_mask;
424 return 1;
427 int hpet_set_rtc_irq_bit(unsigned long bit_mask)
429 unsigned long oldbits = hpet_rtc_flags;
431 if (!is_hpet_enabled())
432 return 0;
434 hpet_rtc_flags |= bit_mask;
436 if (!oldbits)
437 hpet_rtc_timer_init();
439 return 1;
442 int hpet_set_alarm_time(unsigned char hrs, unsigned char min,
443 unsigned char sec)
445 if (!is_hpet_enabled())
446 return 0;
448 hpet_alarm_time.tm_hour = hrs;
449 hpet_alarm_time.tm_min = min;
450 hpet_alarm_time.tm_sec = sec;
452 return 1;
455 int hpet_set_periodic_freq(unsigned long freq)
457 uint64_t clc;
459 if (!is_hpet_enabled())
460 return 0;
462 if (freq <= DEFAULT_RTC_INT_FREQ)
463 hpet_pie_limit = DEFAULT_RTC_INT_FREQ / freq;
464 else {
465 clc = (uint64_t) hpet_clockevent.mult * NSEC_PER_SEC;
466 do_div(clc, freq);
467 clc >>= hpet_clockevent.shift;
468 hpet_pie_delta = (unsigned long) clc;
470 return 1;
473 int hpet_rtc_dropped_irq(void)
475 return is_hpet_enabled();
478 static void hpet_rtc_timer_reinit(void)
480 unsigned long cfg, delta;
481 int lost_ints = -1;
483 if (unlikely(!hpet_rtc_flags)) {
484 cfg = hpet_readl(HPET_T1_CFG);
485 cfg &= ~HPET_TN_ENABLE;
486 hpet_writel(cfg, HPET_T1_CFG);
487 return;
490 if (!(hpet_rtc_flags & RTC_PIE) || hpet_pie_limit)
491 delta = hpet_default_delta;
492 else
493 delta = hpet_pie_delta;
496 * Increment the comparator value until we are ahead of the
497 * current count.
499 do {
500 hpet_t1_cmp += delta;
501 hpet_writel(hpet_t1_cmp, HPET_T1_CMP);
502 lost_ints++;
503 } while ((long)(hpet_readl(HPET_COUNTER) - hpet_t1_cmp) > 0);
505 if (lost_ints) {
506 if (hpet_rtc_flags & RTC_PIE)
507 hpet_pie_count += lost_ints;
508 if (printk_ratelimit())
509 printk(KERN_WARNING "rtc: lost %d interrupts\n",
510 lost_ints);
514 irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id)
516 struct rtc_time curr_time;
517 unsigned long rtc_int_flag = 0;
519 hpet_rtc_timer_reinit();
521 if (hpet_rtc_flags & (RTC_UIE | RTC_AIE))
522 rtc_get_rtc_time(&curr_time);
524 if (hpet_rtc_flags & RTC_UIE &&
525 curr_time.tm_sec != hpet_prev_update_sec) {
526 rtc_int_flag = RTC_UF;
527 hpet_prev_update_sec = curr_time.tm_sec;
530 if (hpet_rtc_flags & RTC_PIE &&
531 ++hpet_pie_count >= hpet_pie_limit) {
532 rtc_int_flag |= RTC_PF;
533 hpet_pie_count = 0;
536 if (hpet_rtc_flags & RTC_PIE &&
537 (curr_time.tm_sec == hpet_alarm_time.tm_sec) &&
538 (curr_time.tm_min == hpet_alarm_time.tm_min) &&
539 (curr_time.tm_hour == hpet_alarm_time.tm_hour))
540 rtc_int_flag |= RTC_AF;
542 if (rtc_int_flag) {
543 rtc_int_flag |= (RTC_IRQF | (RTC_NUM_INTS << 8));
544 rtc_interrupt(rtc_int_flag, dev_id);
546 return IRQ_HANDLED;
548 #endif
552 * Suspend/resume part
555 #ifdef CONFIG_PM
557 static int hpet_suspend(struct sys_device *sys_device, pm_message_t state)
559 unsigned long cfg = hpet_readl(HPET_CFG);
561 cfg &= ~(HPET_CFG_ENABLE|HPET_CFG_LEGACY);
562 hpet_writel(cfg, HPET_CFG);
564 return 0;
567 static int hpet_resume(struct sys_device *sys_device)
569 unsigned int id;
571 hpet_start_counter();
573 id = hpet_readl(HPET_ID);
575 if (id & HPET_ID_LEGSUP)
576 hpet_enable_int();
578 return 0;
581 static struct sysdev_class hpet_class = {
582 set_kset_name("hpet"),
583 .suspend = hpet_suspend,
584 .resume = hpet_resume,
587 static struct sys_device hpet_device = {
588 .id = 0,
589 .cls = &hpet_class,
593 static __init int hpet_register_sysfs(void)
595 int err;
597 if (!is_hpet_capable())
598 return 0;
600 err = sysdev_class_register(&hpet_class);
602 if (!err) {
603 err = sysdev_register(&hpet_device);
604 if (err)
605 sysdev_class_unregister(&hpet_class);
608 return err;
611 device_initcall(hpet_register_sysfs);
613 #endif