linux/arch/mips/mti-malta/malta-time.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Carsten Langgaard, carstenl@mips.com
   4 * Copyright (C) 1999,2000 MIPS Technologies, Inc.  All rights reserved.
   5 *
   6 * Setting up the clock on the MIPS boards.
   7 */
   8#include <linux/types.h>
   9#include <linux/i8253.h>
  10#include <linux/init.h>
  11#include <linux/kernel_stat.h>
  12#include <linux/libfdt.h>
  13#include <linux/math64.h>
  14#include <linux/sched.h>
  15#include <linux/spinlock.h>
  16#include <linux/interrupt.h>
  17#include <linux/timex.h>
  18#include <linux/mc146818rtc.h>
  19
  20#include <asm/cpu.h>
  21#include <asm/mipsregs.h>
  22#include <asm/mipsmtregs.h>
  23#include <asm/hardirq.h>
  24#include <asm/irq.h>
  25#include <asm/div64.h>
  26#include <asm/setup.h>
  27#include <asm/time.h>
  28#include <asm/mc146818-time.h>
  29#include <asm/msc01_ic.h>
  30#include <asm/mips-cps.h>
  31
  32#include <asm/mips-boards/generic.h>
  33#include <asm/mips-boards/maltaint.h>
  34
  35static int mips_cpu_timer_irq;
  36static int mips_cpu_perf_irq;
  37extern int cp0_perfcount_irq;
  38
  39static unsigned int gic_frequency;
  40
  41static void mips_timer_dispatch(void)
  42{
  43        do_IRQ(mips_cpu_timer_irq);
  44}
  45
  46static void mips_perf_dispatch(void)
  47{
  48        do_IRQ(mips_cpu_perf_irq);
  49}
  50
  51static unsigned int freqround(unsigned int freq, unsigned int amount)
  52{
  53        freq += amount;
  54        freq -= freq % (amount*2);
  55        return freq;
  56}
  57
  58/*
  59 * Estimate CPU and GIC frequencies.
  60 */
  61static void __init estimate_frequencies(void)
  62{
  63        unsigned long flags;
  64        unsigned int count, start;
  65        unsigned char secs1, secs2, ctrl;
  66        int secs;
  67        u64 giccount = 0, gicstart = 0;
  68
  69#if defined(CONFIG_KVM_GUEST) && CONFIG_KVM_GUEST_TIMER_FREQ
  70        mips_hpt_frequency = CONFIG_KVM_GUEST_TIMER_FREQ * 1000000;
  71        return;
  72#endif
  73
  74        local_irq_save(flags);
  75
  76        if (mips_gic_present())
  77                clear_gic_config(GIC_CONFIG_COUNTSTOP);
  78
  79        /*
  80         * Read counters exactly on rising edge of update flag.
  81         * This helps get an accurate reading under virtualisation.
  82         */
  83        while (CMOS_READ(RTC_REG_A) & RTC_UIP);
  84        while (!(CMOS_READ(RTC_REG_A) & RTC_UIP));
  85        start = read_c0_count();
  86        if (mips_gic_present())
  87                gicstart = read_gic_counter();
  88
  89        /* Wait for falling edge before reading RTC. */
  90        while (CMOS_READ(RTC_REG_A) & RTC_UIP);
  91        secs1 = CMOS_READ(RTC_SECONDS);
  92
  93        /* Read counters again exactly on rising edge of update flag. */
  94        while (!(CMOS_READ(RTC_REG_A) & RTC_UIP));
  95        count = read_c0_count();
  96        if (mips_gic_present())
  97                giccount = read_gic_counter();
  98
  99        /* Wait for falling edge before reading RTC again. */
 100        while (CMOS_READ(RTC_REG_A) & RTC_UIP);
 101        secs2 = CMOS_READ(RTC_SECONDS);
 102
 103        ctrl = CMOS_READ(RTC_CONTROL);
 104
 105        local_irq_restore(flags);
 106
 107        if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
 108                secs1 = bcd2bin(secs1);
 109                secs2 = bcd2bin(secs2);
 110        }
 111        secs = secs2 - secs1;
 112        if (secs < 1)
 113                secs += 60;
 114
 115        count -= start;
 116        count /= secs;
 117        mips_hpt_frequency = count;
 118
 119        if (mips_gic_present()) {
 120                giccount = div_u64(giccount - gicstart, secs);
 121                gic_frequency = giccount;
 122        }
 123}
 124
 125void read_persistent_clock64(struct timespec64 *ts)
 126{
 127        ts->tv_sec = mc146818_get_cmos_time();
 128        ts->tv_nsec = 0;
 129}
 130
 131int get_c0_fdc_int(void)
 132{
 133        /*
 134         * Some cores claim the FDC is routable through the GIC, but it doesn't
 135         * actually seem to be connected for those Malta bitstreams.
 136         */
 137        switch (current_cpu_type()) {
 138        case CPU_INTERAPTIV:
 139        case CPU_PROAPTIV:
 140                return -1;
 141        };
 142
 143        if (cpu_has_veic)
 144                return -1;
 145        else if (mips_gic_present())
 146                return gic_get_c0_fdc_int();
 147        else if (cp0_fdc_irq >= 0)
 148                return MIPS_CPU_IRQ_BASE + cp0_fdc_irq;
 149        else
 150                return -1;
 151}
 152
 153int get_c0_perfcount_int(void)
 154{
 155        if (cpu_has_veic) {
 156                set_vi_handler(MSC01E_INT_PERFCTR, mips_perf_dispatch);
 157                mips_cpu_perf_irq = MSC01E_INT_BASE + MSC01E_INT_PERFCTR;
 158        } else if (mips_gic_present()) {
 159                mips_cpu_perf_irq = gic_get_c0_perfcount_int();
 160        } else if (cp0_perfcount_irq >= 0) {
 161                mips_cpu_perf_irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq;
 162        } else {
 163                mips_cpu_perf_irq = -1;
 164        }
 165
 166        return mips_cpu_perf_irq;
 167}
 168EXPORT_SYMBOL_GPL(get_c0_perfcount_int);
 169
 170unsigned int get_c0_compare_int(void)
 171{
 172        if (cpu_has_veic) {
 173                set_vi_handler(MSC01E_INT_CPUCTR, mips_timer_dispatch);
 174                mips_cpu_timer_irq = MSC01E_INT_BASE + MSC01E_INT_CPUCTR;
 175        } else if (mips_gic_present()) {
 176                mips_cpu_timer_irq = gic_get_c0_compare_int();
 177        } else {
 178                mips_cpu_timer_irq = MIPS_CPU_IRQ_BASE + cp0_compare_irq;
 179        }
 180
 181        return mips_cpu_timer_irq;
 182}
 183
 184static void __init init_rtc(void)
 185{
 186        unsigned char freq, ctrl;
 187
 188        /* Set 32KHz time base if not already set */
 189        freq = CMOS_READ(RTC_FREQ_SELECT);
 190        if ((freq & RTC_DIV_CTL) != RTC_REF_CLCK_32KHZ)
 191                CMOS_WRITE(RTC_REF_CLCK_32KHZ, RTC_FREQ_SELECT);
 192
 193        /* Ensure SET bit is clear so RTC can run */
 194        ctrl = CMOS_READ(RTC_CONTROL);
 195        if (ctrl & RTC_SET)
 196                CMOS_WRITE(ctrl & ~RTC_SET, RTC_CONTROL);
 197}
 198
 199#ifdef CONFIG_CLKSRC_MIPS_GIC
 200static u32 gic_frequency_dt;
 201
 202static struct property gic_frequency_prop = {
 203        .name = "clock-frequency",
 204        .length = sizeof(u32),
 205        .value = &gic_frequency_dt,
 206};
 207
 208static void update_gic_frequency_dt(void)
 209{
 210        struct device_node *node;
 211
 212        gic_frequency_dt = cpu_to_be32(gic_frequency);
 213
 214        node = of_find_compatible_node(NULL, NULL, "mti,gic-timer");
 215        if (!node) {
 216                pr_err("mti,gic-timer device node not found\n");
 217                return;
 218        }
 219
 220        if (of_update_property(node, &gic_frequency_prop) < 0)
 221                pr_err("error updating gic frequency property\n");
 222}
 223
 224#endif
 225
 226void __init plat_time_init(void)
 227{
 228        unsigned int prid = read_c0_prid() & (PRID_COMP_MASK | PRID_IMP_MASK);
 229        unsigned int freq;
 230
 231        init_rtc();
 232        estimate_frequencies();
 233
 234        freq = mips_hpt_frequency;
 235        if ((prid != (PRID_COMP_MIPS | PRID_IMP_20KC)) &&
 236            (prid != (PRID_COMP_MIPS | PRID_IMP_25KF)))
 237                freq *= 2;
 238        freq = freqround(freq, 5000);
 239        printk("CPU frequency %d.%02d MHz\n", freq/1000000,
 240               (freq%1000000)*100/1000000);
 241
 242#ifdef CONFIG_I8253
 243        /* Only Malta has a PIT. */
 244        setup_pit_timer();
 245#endif
 246
 247        if (mips_gic_present()) {
 248                freq = freqround(gic_frequency, 5000);
 249                printk("GIC frequency %d.%02d MHz\n", freq/1000000,
 250                       (freq%1000000)*100/1000000);
 251#ifdef CONFIG_CLKSRC_MIPS_GIC
 252                update_gic_frequency_dt();
 253                timer_probe();
 254#endif
 255        }
 256}
 257