time.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. /*
  2. * arch/arm/plat-iop/time.c
  3. *
  4. * Timer code for IOP32x and IOP33x based systems
  5. *
  6. * Author: Deepak Saxena <dsaxena@mvista.com>
  7. *
  8. * Copyright 2002-2003 MontaVista Software Inc.
  9. *
  10. * This program is free software; you can redistribute it and/or modify it
  11. * under the terms of the GNU General Public License as published by the
  12. * Free Software Foundation; either version 2 of the License, or (at your
  13. * option) any later version.
  14. */
  15. #include <linux/kernel.h>
  16. #include <linux/interrupt.h>
  17. #include <linux/time.h>
  18. #include <linux/init.h>
  19. #include <linux/timex.h>
  20. #include <linux/io.h>
  21. #include <linux/clocksource.h>
  22. #include <mach/hardware.h>
  23. #include <asm/irq.h>
  24. #include <asm/uaccess.h>
  25. #include <asm/mach/irq.h>
  26. #include <asm/mach/time.h>
  27. #include <mach/time.h>
  28. /*
  29. * IOP clocksource (free-running timer 1).
  30. */
  31. static cycle_t iop_clocksource_read(struct clocksource *unused)
  32. {
  33. return 0xffffffffu - read_tcr1();
  34. }
  35. static struct clocksource iop_clocksource = {
  36. .name = "iop_timer1",
  37. .rating = 300,
  38. .read = iop_clocksource_read,
  39. .mask = CLOCKSOURCE_MASK(32),
  40. .flags = CLOCK_SOURCE_IS_CONTINUOUS,
  41. };
  42. static void __init iop_clocksource_set_hz(struct clocksource *cs, unsigned int hz)
  43. {
  44. u64 temp;
  45. u32 shift;
  46. /* Find shift and mult values for hz. */
  47. shift = 32;
  48. do {
  49. temp = (u64) NSEC_PER_SEC << shift;
  50. do_div(temp, hz);
  51. if ((temp >> 32) == 0)
  52. break;
  53. } while (--shift != 0);
  54. cs->shift = shift;
  55. cs->mult = (u32) temp;
  56. printk(KERN_INFO "clocksource: %s uses shift %u mult %#x\n",
  57. cs->name, cs->shift, cs->mult);
  58. }
  59. static unsigned long ticks_per_jiffy;
  60. static unsigned long ticks_per_usec;
  61. static unsigned long next_jiffy_time;
  62. unsigned long iop_gettimeoffset(void)
  63. {
  64. unsigned long offset, temp;
  65. /* enable cp6, if necessary, to avoid taking the overhead of an
  66. * undefined instruction trap
  67. */
  68. asm volatile (
  69. "mrc p15, 0, %0, c15, c1, 0\n\t"
  70. "tst %0, #(1 << 6)\n\t"
  71. "orreq %0, %0, #(1 << 6)\n\t"
  72. "mcreq p15, 0, %0, c15, c1, 0\n\t"
  73. #ifdef CONFIG_CPU_XSCALE
  74. "mrceq p15, 0, %0, c15, c1, 0\n\t"
  75. "moveq %0, %0\n\t"
  76. "subeq pc, pc, #4\n\t"
  77. #endif
  78. : "=r"(temp) : : "cc");
  79. offset = next_jiffy_time - read_tcr1();
  80. return offset / ticks_per_usec;
  81. }
  82. static irqreturn_t
  83. iop_timer_interrupt(int irq, void *dev_id)
  84. {
  85. write_tisr(1);
  86. while ((signed long)(next_jiffy_time - read_tcr1())
  87. >= ticks_per_jiffy) {
  88. timer_tick();
  89. next_jiffy_time -= ticks_per_jiffy;
  90. }
  91. return IRQ_HANDLED;
  92. }
  93. static struct irqaction iop_timer_irq = {
  94. .name = "IOP Timer Tick",
  95. .handler = iop_timer_interrupt,
  96. .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
  97. };
  98. static unsigned long iop_tick_rate;
  99. unsigned long get_iop_tick_rate(void)
  100. {
  101. return iop_tick_rate;
  102. }
  103. EXPORT_SYMBOL(get_iop_tick_rate);
  104. void __init iop_init_time(unsigned long tick_rate)
  105. {
  106. u32 timer_ctl;
  107. ticks_per_jiffy = DIV_ROUND_CLOSEST(tick_rate, HZ);
  108. ticks_per_usec = tick_rate / 1000000;
  109. next_jiffy_time = 0xffffffff;
  110. iop_tick_rate = tick_rate;
  111. timer_ctl = IOP_TMR_EN | IOP_TMR_PRIVILEGED |
  112. IOP_TMR_RELOAD | IOP_TMR_RATIO_1_1;
  113. /*
  114. * We use timer 0 for our timer interrupt, and timer 1 as
  115. * monotonic counter for tracking missed jiffies.
  116. */
  117. write_trr0(ticks_per_jiffy - 1);
  118. write_tmr0(timer_ctl);
  119. /*
  120. * Set up free-running clocksource timer 1.
  121. */
  122. write_trr1(0xffffffff);
  123. write_tcr1(0xffffffff);
  124. write_tmr1(timer_ctl);
  125. iop_clocksource_set_hz(&iop_clocksource, tick_rate);
  126. clocksource_register(&iop_clocksource);
  127. setup_irq(IRQ_IOP_TIMER0, &iop_timer_irq);
  128. }