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>
8
9#include <asm/hpet.h>
10#include <asm/io.h>
11
12extern struct clock_event_device *global_clock_event;
13
14#define HPET_MASK CLOCKSOURCE_MASK(32)
15#define HPET_SHIFT 22
16
17
18#define FSEC_PER_NSEC 1000000
19
20
21
22
23unsigned long hpet_address;
24static void __iomem * hpet_virt_address;
25
26static inline unsigned long hpet_readl(unsigned long a)
27{
28 return readl(hpet_virt_address + a);
29}
30
31static inline void hpet_writel(unsigned long d, unsigned long a)
32{
33 writel(d, hpet_virt_address + a);
34}
35
36
37
38
39static int boot_hpet_disable;
40
41static int __init hpet_setup(char* str)
42{
43 if (str) {
44 if (!strncmp("disable", str, 7))
45 boot_hpet_disable = 1;
46 }
47 return 1;
48}
49__setup("hpet=", hpet_setup);
50
51static inline int is_hpet_capable(void)
52{
53 return (!boot_hpet_disable && hpet_address);
54}
55
56
57
58
59static int hpet_legacy_int_enabled;
60
61
62
63
64int is_hpet_enabled(void)
65{
66 return is_hpet_capable() && hpet_legacy_int_enabled;
67}
68
69
70
71
72
73#ifdef CONFIG_HPET
74static void hpet_reserve_platform_timers(unsigned long id)
75{
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;
80
81 nrtimers = ((id & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT) + 1;
82
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);
89
90#ifdef CONFIG_HPET_EMULATE_RTC
91 hpet_reserve_timer(&hd, 1);
92#endif
93
94 hd.hd_irq[0] = HPET_LEGACY_8254;
95 hd.hd_irq[1] = HPET_LEGACY_RTC;
96
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;
100
101 hpet_alloc(&hd);
102
103}
104#else
105static void hpet_reserve_platform_timers(unsigned long id) { }
106#endif
107
108
109
110
111static unsigned long hpet_period;
112
113static void hpet_set_mode(enum clock_event_mode mode,
114 struct clock_event_device *evt);
115static int hpet_next_event(unsigned long delta,
116 struct clock_event_device *evt);
117
118
119
120
121static 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,
128};
129
130static void hpet_start_counter(void)
131{
132 unsigned long cfg = hpet_readl(HPET_CFG);
133
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);
140}
141
142static void hpet_enable_int(void)
143{
144 unsigned long cfg = hpet_readl(HPET_CFG);
145
146 cfg |= HPET_CFG_LEGACY;
147 hpet_writel(cfg, HPET_CFG);
148 hpet_legacy_int_enabled = 1;
149}
150
151static void hpet_set_mode(enum clock_event_mode mode,
152 struct clock_event_device *evt)
153{
154 unsigned long cfg, cmp, now;
155 uint64_t delta;
156
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);
167
168
169
170
171
172 hpet_writel(cmp, HPET_T0_CMP);
173 udelay(1);
174 hpet_writel((unsigned long) delta, HPET_T0_CMP);
175 break;
176
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;
183
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;
190 }
191}
192
193static int hpet_next_event(unsigned long delta,
194 struct clock_event_device *evt)
195{
196 unsigned long cnt;
197
198 cnt = hpet_readl(HPET_COUNTER);
199 cnt += delta;
200 hpet_writel(cnt, HPET_T0_CMP);
201
202 return ((long)(hpet_readl(HPET_COUNTER) - cnt ) > 0) ? -ETIME : 0;
203}
204
205
206
207
208static cycle_t read_hpet(void)
209{
210 return (cycle_t)hpet_readl(HPET_COUNTER);
211}
212
213static 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,
220};
221
222
223
224
225int __init hpet_enable(void)
226{
227 unsigned long id;
228 uint64_t hpet_freq;
229 u64 tmp, start, now;
230 cycle_t t1;
231
232 if (!is_hpet_capable())
233 return 0;
234
235 hpet_virt_address = ioremap_nocache(hpet_address, HPET_MMAP_SIZE);
236
237
238
239
240 hpet_period = hpet_readl(HPET_PERIOD);
241 if (hpet_period < HPET_MIN_PERIOD || hpet_period > HPET_MAX_PERIOD)
242 goto out_nohpet;
243
244
245
246
247
248
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
254 hpet_clockevent.max_delta_ns = clockevent_delta2ns(0x7FFFFFFF,
255 &hpet_clockevent);
256 hpet_clockevent.min_delta_ns = clockevent_delta2ns(0x30,
257 &hpet_clockevent);
258
259
260
261
262
263 id = hpet_readl(HPET_ID);
264
265#ifdef CONFIG_HPET_EMULATE_RTC
266
267
268
269
270 if (!(id & HPET_ID_NUMBER))
271 goto out_nohpet;
272#endif
273
274
275 hpet_start_counter();
276
277
278 t1 = read_hpet();
279 rdtscll(start);
280
281
282
283
284
285
286
287 do {
288 rep_nop();
289 rdtscll(now);
290 } while ((now - start) < 200000UL);
291
292 if (t1 == read_hpet()) {
293 printk(KERN_WARNING
294 "HPET counter not counting. HPET disabled\n");
295 goto out_nohpet;
296 }
297
298
299
300
301
302
303
304
305
306
307
308
309
310 tmp = (u64)hpet_period << HPET_SHIFT;
311 do_div(tmp, FSEC_PER_NSEC);
312 clocksource_hpet.mult = (u32)tmp;
313
314 clocksource_register(&clocksource_hpet);
315
316
317 if (id & HPET_ID_LEGSUP) {
318 hpet_enable_int();
319 hpet_reserve_platform_timers(id);
320
321
322
323
324 hpet_clockevent.cpumask =cpumask_of_cpu(0);
325 clockevents_register_device(&hpet_clockevent);
326 global_clock_event = &hpet_clockevent;
327 return 1;
328 }
329 return 0;
330
331out_nohpet:
332 iounmap(hpet_virt_address);
333 hpet_virt_address = NULL;
334 boot_hpet_disable = 1;
335 return 0;
336}
337
338
339#ifdef CONFIG_HPET_EMULATE_RTC
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355#include <linux/mc146818rtc.h>
356#include <linux/rtc.h>
357
358#define DEFAULT_RTC_INT_FREQ 64
359#define DEFAULT_RTC_SHIFT 6
360#define RTC_NUM_INTS 1
361
362static unsigned long hpet_rtc_flags;
363static unsigned long hpet_prev_update_sec;
364static struct rtc_time hpet_alarm_time;
365static unsigned long hpet_pie_count;
366static unsigned long hpet_t1_cmp;
367static unsigned long hpet_default_delta;
368static unsigned long hpet_pie_delta;
369static unsigned long hpet_pie_limit;
370
371
372
373
374
375
376
377int hpet_rtc_timer_init(void)
378{
379 unsigned long cfg, cnt, delta, flags;
380
381 if (!is_hpet_enabled())
382 return 0;
383
384 if (!hpet_default_delta) {
385 uint64_t clc;
386
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;
390 }
391
392 if (!(hpet_rtc_flags & RTC_PIE) || hpet_pie_limit)
393 delta = hpet_default_delta;
394 else
395 delta = hpet_pie_delta;
396
397 local_irq_save(flags);
398
399 cnt = delta + hpet_readl(HPET_COUNTER);
400 hpet_writel(cnt, HPET_T1_CMP);
401 hpet_t1_cmp = cnt;
402
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);
407
408 local_irq_restore(flags);
409
410 return 1;
411}
412
413
414
415
416
417
418int hpet_mask_rtc_irq_bit(unsigned long bit_mask)
419{
420 if (!is_hpet_enabled())
421 return 0;
422
423 hpet_rtc_flags &= ~bit_mask;
424 return 1;
425}
426
427int hpet_set_rtc_irq_bit(unsigned long bit_mask)
428{
429 unsigned long oldbits = hpet_rtc_flags;
430
431 if (!is_hpet_enabled())
432 return 0;
433
434 hpet_rtc_flags |= bit_mask;
435
436 if (!oldbits)
437 hpet_rtc_timer_init();
438
439 return 1;
440}
441
442int hpet_set_alarm_time(unsigned char hrs, unsigned char min,
443 unsigned char sec)
444{
445 if (!is_hpet_enabled())
446 return 0;
447
448 hpet_alarm_time.tm_hour = hrs;
449 hpet_alarm_time.tm_min = min;
450 hpet_alarm_time.tm_sec = sec;
451
452 return 1;
453}
454
455int hpet_set_periodic_freq(unsigned long freq)
456{
457 uint64_t clc;
458
459 if (!is_hpet_enabled())
460 return 0;
461
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;
469 }
470 return 1;
471}
472
473int hpet_rtc_dropped_irq(void)
474{
475 return is_hpet_enabled();
476}
477
478static void hpet_rtc_timer_reinit(void)
479{
480 unsigned long cfg, delta;
481 int lost_ints = -1;
482
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;
488 }
489
490 if (!(hpet_rtc_flags & RTC_PIE) || hpet_pie_limit)
491 delta = hpet_default_delta;
492 else
493 delta = hpet_pie_delta;
494
495
496
497
498
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);
504
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);
511 }
512}
513
514irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id)
515{
516 struct rtc_time curr_time;
517 unsigned long rtc_int_flag = 0;
518
519 hpet_rtc_timer_reinit();
520
521 if (hpet_rtc_flags & (RTC_UIE | RTC_AIE))
522 rtc_get_rtc_time(&curr_time);
523
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;
528 }
529
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;
534 }
535
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;
541
542 if (rtc_int_flag) {
543 rtc_int_flag |= (RTC_IRQF | (RTC_NUM_INTS << 8));
544 rtc_interrupt(rtc_int_flag, dev_id);
545 }
546 return IRQ_HANDLED;
547}
548#endif
549
550
551
552
553
554
555#ifdef CONFIG_PM
556
557static int hpet_suspend(struct sys_device *sys_device, pm_message_t state)
558{
559 unsigned long cfg = hpet_readl(HPET_CFG);
560
561 cfg &= ~(HPET_CFG_ENABLE|HPET_CFG_LEGACY);
562 hpet_writel(cfg, HPET_CFG);
563
564 return 0;
565}
566
567static int hpet_resume(struct sys_device *sys_device)
568{
569 unsigned int id;
570
571 hpet_start_counter();
572
573 id = hpet_readl(HPET_ID);
574
575 if (id & HPET_ID_LEGSUP)
576 hpet_enable_int();
577
578 return 0;
579}
580
581static struct sysdev_class hpet_class = {
582 set_kset_name("hpet"),
583 .suspend = hpet_suspend,
584 .resume = hpet_resume,
585};
586
587static struct sys_device hpet_device = {
588 .id = 0,
589 .cls = &hpet_class,
590};
591
592
593static __init int hpet_register_sysfs(void)
594{
595 int err;
596
597 if (!is_hpet_capable())
598 return 0;
599
600 err = sysdev_class_register(&hpet_class);
601
602 if (!err) {
603 err = sysdev_register(&hpet_device);
604 if (err)
605 sysdev_class_unregister(&hpet_class);
606 }
607
608 return err;
609}
610
611device_initcall(hpet_register_sysfs);
612
613#endif
614