ip27-timer.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. /*
  2. * Copytight (C) 1999, 2000, 05, 06 Ralf Baechle (ralf@linux-mips.org)
  3. * Copytight (C) 1999, 2000 Silicon Graphics, Inc.
  4. */
  5. #include <linux/bcd.h>
  6. #include <linux/init.h>
  7. #include <linux/kernel.h>
  8. #include <linux/sched.h>
  9. #include <linux/interrupt.h>
  10. #include <linux/kernel_stat.h>
  11. #include <linux/param.h>
  12. #include <linux/time.h>
  13. #include <linux/timex.h>
  14. #include <linux/mm.h>
  15. #include <asm/time.h>
  16. #include <asm/pgtable.h>
  17. #include <asm/sgialib.h>
  18. #include <asm/sn/ioc3.h>
  19. #include <asm/m48t35.h>
  20. #include <asm/sn/klconfig.h>
  21. #include <asm/sn/arch.h>
  22. #include <asm/sn/addrs.h>
  23. #include <asm/sn/sn_private.h>
  24. #include <asm/sn/sn0/ip27.h>
  25. #include <asm/sn/sn0/hub.h>
  26. /*
  27. * This is a hack; we really need to figure these values out dynamically
  28. *
  29. * Since 800 ns works very well with various HUB frequencies, such as
  30. * 360, 380, 390 and 400 MHZ, we use 800 ns rtc cycle time.
  31. *
  32. * Ralf: which clock rate is used to feed the counter?
  33. */
  34. #define NSEC_PER_CYCLE 800
  35. #define CYCLES_PER_SEC (NSEC_PER_SEC/NSEC_PER_CYCLE)
  36. #define CYCLES_PER_JIFFY (CYCLES_PER_SEC/HZ)
  37. #define TICK_SIZE (tick_nsec / 1000)
  38. static unsigned long ct_cur[NR_CPUS]; /* What counter should be at next timer irq */
  39. #if 0
  40. static int set_rtc_mmss(unsigned long nowtime)
  41. {
  42. int retval = 0;
  43. int real_seconds, real_minutes, cmos_minutes;
  44. struct m48t35_rtc *rtc;
  45. nasid_t nid;
  46. nid = get_nasid();
  47. rtc = (struct m48t35_rtc *)(KL_CONFIG_CH_CONS_INFO(nid)->memory_base +
  48. IOC3_BYTEBUS_DEV0);
  49. rtc->control |= M48T35_RTC_READ;
  50. cmos_minutes = BCD2BIN(rtc->min);
  51. rtc->control &= ~M48T35_RTC_READ;
  52. /*
  53. * Since we're only adjusting minutes and seconds, don't interfere with
  54. * hour overflow. This avoids messing with unknown time zones but
  55. * requires your RTC not to be off by more than 15 minutes
  56. */
  57. real_seconds = nowtime % 60;
  58. real_minutes = nowtime / 60;
  59. if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
  60. real_minutes += 30; /* correct for half hour time zone */
  61. real_minutes %= 60;
  62. if (abs(real_minutes - cmos_minutes) < 30) {
  63. real_seconds = BIN2BCD(real_seconds);
  64. real_minutes = BIN2BCD(real_minutes);
  65. rtc->control |= M48T35_RTC_SET;
  66. rtc->sec = real_seconds;
  67. rtc->min = real_minutes;
  68. rtc->control &= ~M48T35_RTC_SET;
  69. } else {
  70. printk(KERN_WARNING
  71. "set_rtc_mmss: can't update from %d to %d\n",
  72. cmos_minutes, real_minutes);
  73. retval = -1;
  74. }
  75. return retval;
  76. }
  77. #endif
  78. static unsigned int rt_timer_irq;
  79. void ip27_rt_timer_interrupt(void)
  80. {
  81. int cpu = smp_processor_id();
  82. int cpuA = cputoslice(cpu) == 0;
  83. unsigned int irq = rt_timer_irq;
  84. irq_enter();
  85. write_seqlock(&xtime_lock);
  86. again:
  87. LOCAL_HUB_S(cpuA ? PI_RT_PEND_A : PI_RT_PEND_B, 0); /* Ack */
  88. ct_cur[cpu] += CYCLES_PER_JIFFY;
  89. LOCAL_HUB_S(cpuA ? PI_RT_COMPARE_A : PI_RT_COMPARE_B, ct_cur[cpu]);
  90. if (LOCAL_HUB_L(PI_RT_COUNT) >= ct_cur[cpu])
  91. goto again;
  92. kstat_this_cpu.irqs[irq]++; /* kstat only for bootcpu? */
  93. if (cpu == 0)
  94. do_timer(1);
  95. update_process_times(user_mode(get_irq_regs()));
  96. write_sequnlock(&xtime_lock);
  97. irq_exit();
  98. }
  99. /* Includes for ioc3_init(). */
  100. #include <asm/sn/types.h>
  101. #include <asm/sn/sn0/addrs.h>
  102. #include <asm/sn/sn0/hubni.h>
  103. #include <asm/sn/sn0/hubio.h>
  104. #include <asm/pci/bridge.h>
  105. unsigned long read_persistent_clock(void)
  106. {
  107. unsigned int year, month, date, hour, min, sec;
  108. struct m48t35_rtc *rtc;
  109. nasid_t nid;
  110. nid = get_nasid();
  111. rtc = (struct m48t35_rtc *)(KL_CONFIG_CH_CONS_INFO(nid)->memory_base +
  112. IOC3_BYTEBUS_DEV0);
  113. rtc->control |= M48T35_RTC_READ;
  114. sec = rtc->sec;
  115. min = rtc->min;
  116. hour = rtc->hour;
  117. date = rtc->date;
  118. month = rtc->month;
  119. year = rtc->year;
  120. rtc->control &= ~M48T35_RTC_READ;
  121. sec = BCD2BIN(sec);
  122. min = BCD2BIN(min);
  123. hour = BCD2BIN(hour);
  124. date = BCD2BIN(date);
  125. month = BCD2BIN(month);
  126. year = BCD2BIN(year);
  127. year += 1970;
  128. return mktime(year, month, date, hour, min, sec);
  129. }
  130. static void enable_rt_irq(unsigned int irq)
  131. {
  132. }
  133. static void disable_rt_irq(unsigned int irq)
  134. {
  135. }
  136. static struct irq_chip rt_irq_type = {
  137. .name = "SN HUB RT timer",
  138. .ack = disable_rt_irq,
  139. .mask = disable_rt_irq,
  140. .mask_ack = disable_rt_irq,
  141. .unmask = enable_rt_irq,
  142. .eoi = enable_rt_irq,
  143. };
  144. static struct irqaction rt_irqaction = {
  145. .handler = (irq_handler_t) ip27_rt_timer_interrupt,
  146. .flags = IRQF_DISABLED,
  147. .mask = CPU_MASK_NONE,
  148. .name = "timer"
  149. };
  150. void __init plat_timer_setup(struct irqaction *irq)
  151. {
  152. int irqno = allocate_irqno();
  153. if (irqno < 0)
  154. panic("Can't allocate interrupt number for timer interrupt");
  155. set_irq_chip_and_handler(irqno, &rt_irq_type, handle_percpu_irq);
  156. /* over-write the handler, we use our own way */
  157. irq->handler = no_action;
  158. /* setup irqaction */
  159. irq_desc[irqno].status |= IRQ_PER_CPU;
  160. rt_timer_irq = irqno;
  161. /*
  162. * Only needed to get /proc/interrupt to display timer irq stats
  163. */
  164. setup_irq(irqno, &rt_irqaction);
  165. }
  166. static cycle_t hub_rt_read(void)
  167. {
  168. return REMOTE_HUB_L(cputonasid(0), PI_RT_COUNT);
  169. }
  170. struct clocksource ht_rt_clocksource = {
  171. .name = "HUB",
  172. .rating = 200,
  173. .read = hub_rt_read,
  174. .mask = CLOCKSOURCE_MASK(52),
  175. .shift = 32,
  176. .flags = CLOCK_SOURCE_IS_CONTINUOUS,
  177. };
  178. void __init plat_time_init(void)
  179. {
  180. clocksource_register(&ht_rt_clocksource);
  181. }
  182. void __init cpu_time_init(void)
  183. {
  184. lboard_t *board;
  185. klcpu_t *cpu;
  186. int cpuid;
  187. /* Don't use ARCS. ARCS is fragile. Klconfig is simple and sane. */
  188. board = find_lboard(KL_CONFIG_INFO(get_nasid()), KLTYPE_IP27);
  189. if (!board)
  190. panic("Can't find board info for myself.");
  191. cpuid = LOCAL_HUB_L(PI_CPU_NUM) ? IP27_CPU0_INDEX : IP27_CPU1_INDEX;
  192. cpu = (klcpu_t *) KLCF_COMP(board, cpuid);
  193. if (!cpu)
  194. panic("No information about myself?");
  195. printk("CPU %d clock is %dMHz.\n", smp_processor_id(), cpu->cpu_speed);
  196. set_c0_status(SRB_TIMOCLK);
  197. }
  198. void __init hub_rtc_init(cnodeid_t cnode)
  199. {
  200. /*
  201. * We only need to initialize the current node.
  202. * If this is not the current node then it is a cpuless
  203. * node and timeouts will not happen there.
  204. */
  205. if (get_compact_nodeid() == cnode) {
  206. int cpu = smp_processor_id();
  207. LOCAL_HUB_S(PI_RT_EN_A, 1);
  208. LOCAL_HUB_S(PI_RT_EN_B, 1);
  209. LOCAL_HUB_S(PI_PROF_EN_A, 0);
  210. LOCAL_HUB_S(PI_PROF_EN_B, 0);
  211. ct_cur[cpu] = CYCLES_PER_JIFFY;
  212. LOCAL_HUB_S(PI_RT_COMPARE_A, ct_cur[cpu]);
  213. LOCAL_HUB_S(PI_RT_COUNT, 0);
  214. LOCAL_HUB_S(PI_RT_PEND_A, 0);
  215. LOCAL_HUB_S(PI_RT_COMPARE_B, ct_cur[cpu]);
  216. LOCAL_HUB_S(PI_RT_COUNT, 0);
  217. LOCAL_HUB_S(PI_RT_PEND_B, 0);
  218. }
  219. }