root/arch/mips/sgi-ip22/ip22-time.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. dosample
  2. plat_time_init
  3. indy_8254timer_irq

   1 /*
   2  * This file is subject to the terms and conditions of the GNU General Public
   3  * License.  See the file "COPYING" in the main directory of this archive
   4  * for more details.
   5  *
   6  * Time operations for IP22 machines. Original code may come from
   7  * Ralf Baechle or David S. Miller (sorry guys, i'm really not sure)
   8  *
   9  * Copyright (C) 2001 by Ladislav Michl
  10  * Copyright (C) 2003, 06 Ralf Baechle (ralf@linux-mips.org)
  11  */
  12 #include <linux/bcd.h>
  13 #include <linux/i8253.h>
  14 #include <linux/init.h>
  15 #include <linux/irq.h>
  16 #include <linux/kernel.h>
  17 #include <linux/interrupt.h>
  18 #include <linux/kernel_stat.h>
  19 #include <linux/time.h>
  20 #include <linux/ftrace.h>
  21 
  22 #include <asm/cpu.h>
  23 #include <asm/mipsregs.h>
  24 #include <asm/io.h>
  25 #include <asm/irq.h>
  26 #include <asm/time.h>
  27 #include <asm/sgialib.h>
  28 #include <asm/sgi/ioc.h>
  29 #include <asm/sgi/hpc3.h>
  30 #include <asm/sgi/ip22.h>
  31 
  32 static unsigned long dosample(void)
  33 {
  34         u32 ct0, ct1;
  35         u8 msb;
  36 
  37         /* Start the counter. */
  38         sgint->tcword = (SGINT_TCWORD_CNT2 | SGINT_TCWORD_CALL |
  39                          SGINT_TCWORD_MRGEN);
  40         sgint->tcnt2 = SGINT_TCSAMP_COUNTER & 0xff;
  41         sgint->tcnt2 = SGINT_TCSAMP_COUNTER >> 8;
  42 
  43         /* Get initial counter invariant */
  44         ct0 = read_c0_count();
  45 
  46         /* Latch and spin until top byte of counter2 is zero */
  47         do {
  48                 writeb(SGINT_TCWORD_CNT2 | SGINT_TCWORD_CLAT, &sgint->tcword);
  49                 (void) readb(&sgint->tcnt2);
  50                 msb = readb(&sgint->tcnt2);
  51                 ct1 = read_c0_count();
  52         } while (msb);
  53 
  54         /* Stop the counter. */
  55         writeb(SGINT_TCWORD_CNT2 | SGINT_TCWORD_CALL | SGINT_TCWORD_MSWST,
  56                &sgint->tcword);
  57         /*
  58          * Return the difference, this is how far the r4k counter increments
  59          * for every 1/HZ seconds. We round off the nearest 1 MHz of master
  60          * clock (= 1000000 / HZ / 2).
  61          */
  62 
  63         return (ct1 - ct0) / (500000/HZ) * (500000/HZ);
  64 }
  65 
  66 /*
  67  * Here we need to calibrate the cycle counter to at least be close.
  68  */
  69 __init void plat_time_init(void)
  70 {
  71         unsigned long r4k_ticks[3];
  72         unsigned long r4k_tick;
  73 
  74         /*
  75          * Figure out the r4k offset, the algorithm is very simple and works in
  76          * _all_ cases as long as the 8254 counter register itself works ok (as
  77          * an interrupt driving timer it does not because of bug, this is why
  78          * we are using the onchip r4k counter/compare register to serve this
  79          * purpose, but for r4k_offset calculation it will work ok for us).
  80          * There are other very complicated ways of performing this calculation
  81          * but this one works just fine so I am not going to futz around. ;-)
  82          */
  83         printk(KERN_INFO "Calibrating system timer... ");
  84         dosample();     /* Prime cache. */
  85         dosample();     /* Prime cache. */
  86         /* Zero is NOT an option. */
  87         do {
  88                 r4k_ticks[0] = dosample();
  89         } while (!r4k_ticks[0]);
  90         do {
  91                 r4k_ticks[1] = dosample();
  92         } while (!r4k_ticks[1]);
  93 
  94         if (r4k_ticks[0] != r4k_ticks[1]) {
  95                 printk("warning: timer counts differ, retrying... ");
  96                 r4k_ticks[2] = dosample();
  97                 if (r4k_ticks[2] == r4k_ticks[0]
  98                     || r4k_ticks[2] == r4k_ticks[1])
  99                         r4k_tick = r4k_ticks[2];
 100                 else {
 101                         printk("disagreement, using average... ");
 102                         r4k_tick = (r4k_ticks[0] + r4k_ticks[1]
 103                                    + r4k_ticks[2]) / 3;
 104                 }
 105         } else
 106                 r4k_tick = r4k_ticks[0];
 107 
 108         printk("%d [%d.%04d MHz CPU]\n", (int) r4k_tick,
 109                 (int) (r4k_tick / (500000 / HZ)),
 110                 (int) (r4k_tick % (500000 / HZ)));
 111 
 112         mips_hpt_frequency = r4k_tick * HZ;
 113 
 114         if (ip22_is_fullhouse())
 115                 setup_pit_timer();
 116 }
 117 
 118 /* Generic SGI handler for (spurious) 8254 interrupts */
 119 void __irq_entry indy_8254timer_irq(void)
 120 {
 121         int irq = SGI_8254_0_IRQ;
 122         ULONG cnt;
 123         char c;
 124 
 125         irq_enter();
 126         kstat_incr_irq_this_cpu(irq);
 127         printk(KERN_ALERT "Oops, got 8254 interrupt.\n");
 128         ArcRead(0, &c, 1, &cnt);
 129         ArcEnterInteractiveMode();
 130         irq_exit();
 131 }

/* [<][>][^][v][top][bottom][index][help] */