linux/arch/mips/mti-malta/malta-time.c
<<
>>
Prefs
   1/*
   2 * Carsten Langgaard, carstenl@mips.com
   3 * Copyright (C) 1999,2000 MIPS Technologies, Inc.  All rights reserved.
   4 *
   5 *  This program is free software; you can distribute it and/or modify it
   6 *  under the terms of the GNU General Public License (Version 2) as
   7 *  published by the Free Software Foundation.
   8 *
   9 *  This program is distributed in the hope it will be useful, but WITHOUT
  10 *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11 *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12 *  for more details.
  13 *
  14 *  You should have received a copy of the GNU General Public License along
  15 *  with this program; if not, write to the Free Software Foundation, Inc.,
  16 *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
  17 *
  18 * Setting up the clock on the MIPS boards.
  19 */
  20
  21#include <linux/types.h>
  22#include <linux/init.h>
  23#include <linux/kernel_stat.h>
  24#include <linux/sched.h>
  25#include <linux/spinlock.h>
  26#include <linux/interrupt.h>
  27#include <linux/time.h>
  28#include <linux/timex.h>
  29#include <linux/mc146818rtc.h>
  30
  31#include <asm/mipsregs.h>
  32#include <asm/mipsmtregs.h>
  33#include <asm/hardirq.h>
  34#include <asm/i8253.h>
  35#include <asm/irq.h>
  36#include <asm/div64.h>
  37#include <asm/cpu.h>
  38#include <asm/time.h>
  39#include <asm/mc146818-time.h>
  40#include <asm/msc01_ic.h>
  41
  42#include <asm/mips-boards/generic.h>
  43#include <asm/mips-boards/prom.h>
  44
  45#include <asm/mips-boards/maltaint.h>
  46
  47unsigned long cpu_khz;
  48
  49static int mips_cpu_timer_irq;
  50static int mips_cpu_perf_irq;
  51extern int cp0_perfcount_irq;
  52
  53static void mips_timer_dispatch(void)
  54{
  55        do_IRQ(mips_cpu_timer_irq);
  56}
  57
  58static void mips_perf_dispatch(void)
  59{
  60        do_IRQ(mips_cpu_perf_irq);
  61}
  62
  63/*
  64 * Estimate CPU frequency.  Sets mips_hpt_frequency as a side-effect
  65 */
  66static unsigned int __init estimate_cpu_frequency(void)
  67{
  68        unsigned int prid = read_c0_prid() & 0xffff00;
  69        unsigned int count;
  70
  71        unsigned long flags;
  72        unsigned int start;
  73
  74        local_irq_save(flags);
  75
  76        /* Start counter exactly on falling edge of update flag */
  77        while (CMOS_READ(RTC_REG_A) & RTC_UIP);
  78        while (!(CMOS_READ(RTC_REG_A) & RTC_UIP));
  79
  80        /* Start r4k counter. */
  81        start = read_c0_count();
  82
  83        /* Read counter exactly on falling edge of update flag */
  84        while (CMOS_READ(RTC_REG_A) & RTC_UIP);
  85        while (!(CMOS_READ(RTC_REG_A) & RTC_UIP));
  86
  87        count = read_c0_count() - start;
  88
  89        /* restore interrupts */
  90        local_irq_restore(flags);
  91
  92        mips_hpt_frequency = count;
  93        if ((prid != (PRID_COMP_MIPS | PRID_IMP_20KC)) &&
  94            (prid != (PRID_COMP_MIPS | PRID_IMP_25KF)))
  95                count *= 2;
  96
  97        count += 5000;    /* round */
  98        count -= count%10000;
  99
 100        return count;
 101}
 102
 103void read_persistent_clock(struct timespec *ts)
 104{
 105        ts->tv_sec = mc146818_get_cmos_time();
 106        ts->tv_nsec = 0;
 107}
 108
 109static void __init plat_perf_setup(void)
 110{
 111#ifdef MSC01E_INT_BASE
 112        if (cpu_has_veic) {
 113                set_vi_handler(MSC01E_INT_PERFCTR, mips_perf_dispatch);
 114                mips_cpu_perf_irq = MSC01E_INT_BASE + MSC01E_INT_PERFCTR;
 115        } else
 116#endif
 117        if (cp0_perfcount_irq >= 0) {
 118                if (cpu_has_vint)
 119                        set_vi_handler(cp0_perfcount_irq, mips_perf_dispatch);
 120                mips_cpu_perf_irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq;
 121#ifdef CONFIG_SMP
 122                set_irq_handler(mips_cpu_perf_irq, handle_percpu_irq);
 123#endif
 124        }
 125}
 126
 127unsigned int __cpuinit get_c0_compare_int(void)
 128{
 129#ifdef MSC01E_INT_BASE
 130        if (cpu_has_veic) {
 131                set_vi_handler(MSC01E_INT_CPUCTR, mips_timer_dispatch);
 132                mips_cpu_timer_irq = MSC01E_INT_BASE + MSC01E_INT_CPUCTR;
 133        } else
 134#endif
 135        {
 136                if (cpu_has_vint)
 137                        set_vi_handler(cp0_compare_irq, mips_timer_dispatch);
 138                mips_cpu_timer_irq = MIPS_CPU_IRQ_BASE + cp0_compare_irq;
 139        }
 140
 141        return mips_cpu_timer_irq;
 142}
 143
 144void __init plat_time_init(void)
 145{
 146        unsigned int est_freq;
 147
 148        /* Set Data mode - binary. */
 149        CMOS_WRITE(CMOS_READ(RTC_CONTROL) | RTC_DM_BINARY, RTC_CONTROL);
 150
 151        est_freq = estimate_cpu_frequency();
 152
 153        printk("CPU frequency %d.%02d MHz\n", est_freq/1000000,
 154               (est_freq%1000000)*100/1000000);
 155
 156        cpu_khz = est_freq / 1000;
 157
 158        mips_scroll_message();
 159#ifdef CONFIG_I8253             /* Only Malta has a PIT */
 160        setup_pit_timer();
 161#endif
 162
 163        plat_perf_setup();
 164}
 165