time.c 3.7 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5
/*
 * Copyright 2001 MontaVista Software Inc.
 * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
 * Copyright (c) 2003, 2004  Maciej W. Rozycki
 *
A
Atsushi Nemoto 已提交
6
 * Common time service routines for MIPS machines.
L
Linus Torvalds 已提交
7 8 9 10 11 12
 *
 * This program is free software; you can redistribute  it and/or modify it
 * under  the terms of  the GNU General  Public License as published by the
 * Free Software Foundation;  either version 2 of the  License, or (at your
 * option) any later version.
 */
13
#include <linux/bug.h>
14
#include <linux/clockchips.h>
L
Linus Torvalds 已提交
15 16 17 18 19 20 21 22 23 24 25 26 27
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/param.h>
#include <linux/time.h>
#include <linux/timex.h>
#include <linux/smp.h>
#include <linux/spinlock.h>
#include <linux/module.h>

#include <asm/cpu-features.h>
#include <asm/div64.h>
R
Ralf Baechle 已提交
28
#include <asm/smtc_ipi.h>
L
Linus Torvalds 已提交
29 30 31 32 33 34
#include <asm/time.h>

/*
 * forward reference
 */
DEFINE_SPINLOCK(rtc_lock);
35
EXPORT_SYMBOL(rtc_lock);
L
Linus Torvalds 已提交
36

37
int __weak rtc_mips_set_time(unsigned long sec)
L
Linus Torvalds 已提交
38
{
39
	return 0;
L
Linus Torvalds 已提交
40
}
41
EXPORT_SYMBOL(rtc_mips_set_time);
L
Linus Torvalds 已提交
42

43
int __weak rtc_mips_set_mmss(unsigned long nowtime)
L
Linus Torvalds 已提交
44
{
45
	return rtc_mips_set_time(nowtime);
L
Linus Torvalds 已提交
46 47
}

48 49 50 51
int update_persistent_clock(struct timespec now)
{
	return rtc_mips_set_mmss(now.tv_sec);
}
L
Linus Torvalds 已提交
52 53 54

int (*mips_timer_state)(void);

55
int null_perf_irq(void)
56 57 58 59
{
	return 0;
}

60 61
EXPORT_SYMBOL(null_perf_irq);

62
int (*perf_irq)(void) = null_perf_irq;
63 64 65

EXPORT_SYMBOL(perf_irq);

L
Linus Torvalds 已提交
66 67 68
/*
 * time_init() - it does the following things.
 *
69
 * 1) plat_time_init() -
L
Linus Torvalds 已提交
70 71
 * 	a) (optional) set up RTC routines,
 *      b) (optional) calibrate and set the mips_hpt_frequency
72 73
 *	    (only needed if you intended to use cpu counter as timer interrupt
 *	     source)
74
 * 2) calculate a couple of cached variables for later usage
L
Linus Torvalds 已提交
75 76 77 78
 */

unsigned int mips_hpt_frequency;

79
void __init clocksource_set_clock(struct clocksource *cs, unsigned int clock)
80 81 82 83
{
	u64 temp;
	u32 shift;

84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
	/* Find a shift value */
	for (shift = 32; shift > 0; shift--) {
		temp = (u64) NSEC_PER_SEC << shift;
		do_div(temp, clock);
		if ((temp >> 32) == 0)
			break;
	}
	cs->shift = shift;
	cs->mult = (u32) temp;
}

void __cpuinit clockevent_set_clock(struct clock_event_device *cd,
	unsigned int clock)
{
	u64 temp;
	u32 shift;
100 101 102

	/* Find a shift value */
	for (shift = 32; shift > 0; shift--) {
103 104
		temp = (u64) clock << shift;
		do_div(temp, NSEC_PER_SEC);
105 106 107
		if ((temp >> 32) == 0)
			break;
	}
108 109 110 111
	cd->shift = shift;
	cd->mult = (u32) temp;
}

112
void __init __weak plat_time_init(void)
L
Linus Torvalds 已提交
113
{
114
}
L
Linus Torvalds 已提交
115

116 117 118 119 120 121 122 123 124
/*
 * This function exists in order to cause an error due to a duplicate
 * definition if platform code should have its own implementation.  The hook
 * to use instead is plat_time_init.  plat_time_init does not receive the
 * irqaction pointer argument anymore.  This is because any function which
 * initializes an interrupt timer now takes care of its own request_irq rsp.
 * setup_irq calls and each clock_event_device should use its own
 * struct irqrequest.
 */
A
Atsushi Nemoto 已提交
125
void __init plat_timer_setup(void)
126
{
127
	BUG();
128 129
}

130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
static __init int cpu_has_mfc0_count_bug(void)
{
	switch (current_cpu_type()) {
	case CPU_R4000PC:
	case CPU_R4000SC:
	case CPU_R4000MC:
		/*
		 * V3.0 is documented as suffering from the mfc0 from count bug.
		 * Afaik this is the last version of the R4000.  Later versions
		 * were marketed as R4400.
		 */
		return 1;

	case CPU_R4400PC:
	case CPU_R4400SC:
	case CPU_R4400MC:
		/*
		 * The published errata for the R4400 upto 3.0 say the CPU
		 * has the mfc0 from count bug.
		 */
		if ((current_cpu_data.processor_id & 0xff) <= 0x30)
			return 1;

		/*
		 * I don't have erratas for newer R4400 so be paranoid.
		 */
		return 1;
	}

	return 0;
}

162 163 164
void __init time_init(void)
{
	plat_time_init();
L
Linus Torvalds 已提交
165

166
	if (mips_clockevent_init() || !cpu_has_mfc0_count_bug())
A
Atsushi Nemoto 已提交
167
		init_mips_clocksource();
L
Linus Torvalds 已提交
168
}