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#include <linux/types.h>
  21#include <linux/i8253.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/irqchip/mips-gic.h>
  28#include <linux/timex.h>
  29#include <linux/mc146818rtc.h>
  30
  31#include <asm/cpu.h>
  32#include <asm/mipsregs.h>
  33#include <asm/mipsmtregs.h>
  34#include <asm/hardirq.h>
  35#include <asm/irq.h>
  36#include <asm/div64.h>
  37#include <asm/setup.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/maltaint.h>
  44
  45static int mips_cpu_timer_irq;
  46static int mips_cpu_perf_irq;
  47extern int cp0_perfcount_irq;
  48
  49static unsigned int gic_frequency;
  50
  51static void mips_timer_dispatch(void)
  52{
  53        do_IRQ(mips_cpu_timer_irq);
  54}
  55
  56static void mips_perf_dispatch(void)
  57{
  58        do_IRQ(mips_cpu_perf_irq);
  59}
  60
  61static unsigned int freqround(unsigned int freq, unsigned int amount)
  62{
  63        freq += amount;
  64        freq -= freq % (amount*2);
  65        return freq;
  66}
  67
  68/*
  69 * Estimate CPU and GIC frequencies.
  70 */
  71static void __init estimate_frequencies(void)
  72{
  73        unsigned long flags;
  74        unsigned int count, start;
  75        cycle_t giccount = 0, gicstart = 0;
  76
  77#if defined(CONFIG_KVM_GUEST) && CONFIG_KVM_GUEST_TIMER_FREQ
  78        mips_hpt_frequency = CONFIG_KVM_GUEST_TIMER_FREQ * 1000000;
  79        return;
  80#endif
  81
  82        local_irq_save(flags);
  83
  84        /* Start counter exactly on falling edge of update flag. */
  85        while (CMOS_READ(RTC_REG_A) & RTC_UIP);
  86        while (!(CMOS_READ(RTC_REG_A) & RTC_UIP));
  87
  88        /* Initialize counters. */
  89        start = read_c0_count();
  90        if (gic_present) {
  91                gic_start_count();
  92                gicstart = gic_read_count();
  93        }
  94
  95        /* Read counter exactly on falling edge of update flag. */
  96        while (CMOS_READ(RTC_REG_A) & RTC_UIP);
  97        while (!(CMOS_READ(RTC_REG_A) & RTC_UIP));
  98
  99        count = read_c0_count();
 100        if (gic_present)
 101                giccount = gic_read_count();
 102
 103        local_irq_restore(flags);
 104
 105        count -= start;
 106        mips_hpt_frequency = count;
 107
 108        if (gic_present) {
 109                giccount -= gicstart;
 110                gic_frequency = giccount;
 111        }
 112}
 113
 114void read_persistent_clock(struct timespec *ts)
 115{
 116        ts->tv_sec = mc146818_get_cmos_time();
 117        ts->tv_nsec = 0;
 118}
 119
 120int get_c0_fdc_int(void)
 121{
 122        /*
 123         * Some cores claim the FDC is routable through the GIC, but it doesn't
 124         * actually seem to be connected for those Malta bitstreams.
 125         */
 126        switch (current_cpu_type()) {
 127        case CPU_INTERAPTIV:
 128        case CPU_PROAPTIV:
 129                return -1;
 130        };
 131
 132        if (cpu_has_veic)
 133                return -1;
 134        else if (gic_present)
 135                return gic_get_c0_fdc_int();
 136        else if (cp0_fdc_irq >= 0)
 137                return MIPS_CPU_IRQ_BASE + cp0_fdc_irq;
 138        else
 139                return -1;
 140}
 141
 142int get_c0_perfcount_int(void)
 143{
 144        if (cpu_has_veic) {
 145                set_vi_handler(MSC01E_INT_PERFCTR, mips_perf_dispatch);
 146                mips_cpu_perf_irq = MSC01E_INT_BASE + MSC01E_INT_PERFCTR;
 147        } else if (gic_present) {
 148                mips_cpu_perf_irq = gic_get_c0_perfcount_int();
 149        } else if (cp0_perfcount_irq >= 0) {
 150                mips_cpu_perf_irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq;
 151        } else {
 152                mips_cpu_perf_irq = -1;
 153        }
 154
 155        return mips_cpu_perf_irq;
 156}
 157EXPORT_SYMBOL_GPL(get_c0_perfcount_int);
 158
 159unsigned int get_c0_compare_int(void)
 160{
 161        if (cpu_has_veic) {
 162                set_vi_handler(MSC01E_INT_CPUCTR, mips_timer_dispatch);
 163                mips_cpu_timer_irq = MSC01E_INT_BASE + MSC01E_INT_CPUCTR;
 164        } else if (gic_present) {
 165                mips_cpu_timer_irq = gic_get_c0_compare_int();
 166        } else {
 167                mips_cpu_timer_irq = MIPS_CPU_IRQ_BASE + cp0_compare_irq;
 168        }
 169
 170        return mips_cpu_timer_irq;
 171}
 172
 173static void __init init_rtc(void)
 174{
 175        unsigned char freq, ctrl;
 176
 177        /* Set 32KHz time base if not already set */
 178        freq = CMOS_READ(RTC_FREQ_SELECT);
 179        if ((freq & RTC_DIV_CTL) != RTC_REF_CLCK_32KHZ)
 180                CMOS_WRITE(RTC_REF_CLCK_32KHZ, RTC_FREQ_SELECT);
 181
 182        /* Ensure SET bit is clear so RTC can run */
 183        ctrl = CMOS_READ(RTC_CONTROL);
 184        if (ctrl & RTC_SET)
 185                CMOS_WRITE(ctrl & ~RTC_SET, RTC_CONTROL);
 186}
 187
 188void __init plat_time_init(void)
 189{
 190        unsigned int prid = read_c0_prid() & (PRID_COMP_MASK | PRID_IMP_MASK);
 191        unsigned int freq;
 192
 193        init_rtc();
 194        estimate_frequencies();
 195
 196        freq = mips_hpt_frequency;
 197        if ((prid != (PRID_COMP_MIPS | PRID_IMP_20KC)) &&
 198            (prid != (PRID_COMP_MIPS | PRID_IMP_25KF)))
 199                freq *= 2;
 200        freq = freqround(freq, 5000);
 201        printk("CPU frequency %d.%02d MHz\n", freq/1000000,
 202               (freq%1000000)*100/1000000);
 203
 204        mips_scroll_message();
 205
 206#ifdef CONFIG_I8253
 207        /* Only Malta has a PIT. */
 208        setup_pit_timer();
 209#endif
 210
 211#ifdef CONFIG_MIPS_GIC
 212        if (gic_present) {
 213                freq = freqround(gic_frequency, 5000);
 214                printk("GIC frequency %d.%02d MHz\n", freq/1000000,
 215                       (freq%1000000)*100/1000000);
 216#ifdef CONFIG_CLKSRC_MIPS_GIC
 217                gic_clocksource_init(gic_frequency);
 218#endif
 219        }
 220#endif
 221}
 222