]>
Commit | Line | Data |
---|---|---|
b2441318 | 1 | // SPDX-License-Identifier: GPL-2.0 |
1da177e4 LT |
2 | /* |
3 | * linux/arch/m32r/kernel/time.c | |
4 | * | |
5 | * Copyright (c) 2001, 2002 Hiroyuki Kondo, Hirokazu Takata, | |
6 | * Hitoshi Yamamoto | |
7 | * Taken from i386 version. | |
8 | * Copyright (C) 1991, 1992, 1995 Linus Torvalds | |
9 | * Copyright (C) 1996, 1997, 1998 Ralf Baechle | |
10 | * | |
11 | * This file contains the time handling details for PC-style clocks as | |
12 | * found in some MIPS systems. | |
13 | * | |
14 | * Some code taken from sh version. | |
15 | * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka | |
16 | * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> | |
17 | */ | |
18 | ||
19 | #undef DEBUG_TIMER | |
20 | ||
1da177e4 LT |
21 | #include <linux/errno.h> |
22 | #include <linux/init.h> | |
23 | #include <linux/module.h> | |
24 | #include <linux/sched.h> | |
25 | #include <linux/kernel.h> | |
26 | #include <linux/param.h> | |
27 | #include <linux/string.h> | |
28 | #include <linux/mm.h> | |
29 | #include <linux/interrupt.h> | |
30 | #include <linux/profile.h> | |
31 | ||
32 | #include <asm/io.h> | |
33 | #include <asm/m32r.h> | |
34 | ||
35 | #include <asm/hw_irq.h> | |
36 | ||
bac33bd5 HT |
37 | #if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE) |
38 | /* this needs a better home */ | |
39 | DEFINE_SPINLOCK(rtc_lock); | |
40 | ||
41 | #ifdef CONFIG_RTC_DRV_CMOS_MODULE | |
42 | EXPORT_SYMBOL(rtc_lock); | |
43 | #endif | |
44 | #endif /* pc-style 'CMOS' RTC support */ | |
45 | ||
1da177e4 | 46 | #ifdef CONFIG_SMP |
9c8e7f5c | 47 | extern void smp_local_timer_interrupt(void); |
1da177e4 LT |
48 | #endif |
49 | ||
1da177e4 LT |
50 | #define TICK_SIZE (tick_nsec / 1000) |
51 | ||
52 | /* | |
53 | * Change this if you have some constant time drift | |
54 | */ | |
55 | ||
56 | /* This is for machines which generate the exact clock. */ | |
57 | #define USECS_PER_JIFFY (1000000/HZ) | |
58 | ||
59 | static unsigned long latch; | |
60 | ||
7b1f6207 | 61 | static u32 m32r_gettimeoffset(void) |
1da177e4 LT |
62 | { |
63 | unsigned long elapsed_time = 0; /* [us] */ | |
64 | ||
65 | #if defined(CONFIG_CHIP_M32102) || defined(CONFIG_CHIP_XNUX2) \ | |
66 | || defined(CONFIG_CHIP_VDEC2) || defined(CONFIG_CHIP_M32700) \ | |
9287d95e | 67 | || defined(CONFIG_CHIP_OPSP) || defined(CONFIG_CHIP_M32104) |
1da177e4 LT |
68 | #ifndef CONFIG_SMP |
69 | ||
70 | unsigned long count; | |
71 | ||
72 | /* timer count may underflow right here */ | |
73 | count = inl(M32R_MFT2CUT_PORTL); | |
74 | ||
75 | if (inl(M32R_ICU_CR18_PORTL) & 0x00000100) /* underflow check */ | |
76 | count = 0; | |
77 | ||
78 | count = (latch - count) * TICK_SIZE; | |
56023585 | 79 | elapsed_time = DIV_ROUND_CLOSEST(count, latch); |
1da177e4 LT |
80 | /* NOTE: LATCH is equal to the "interval" value (= reload count). */ |
81 | ||
82 | #else /* CONFIG_SMP */ | |
83 | unsigned long count; | |
84 | static unsigned long p_jiffies = -1; | |
85 | static unsigned long p_count = 0; | |
86 | ||
87 | /* timer count may underflow right here */ | |
88 | count = inl(M32R_MFT2CUT_PORTL); | |
89 | ||
90 | if (jiffies == p_jiffies && count > p_count) | |
91 | count = 0; | |
92 | ||
93 | p_jiffies = jiffies; | |
94 | p_count = count; | |
95 | ||
96 | count = (latch - count) * TICK_SIZE; | |
56023585 | 97 | elapsed_time = DIV_ROUND_CLOSEST(count, latch); |
1da177e4 LT |
98 | /* NOTE: LATCH is equal to the "interval" value (= reload count). */ |
99 | #endif /* CONFIG_SMP */ | |
100 | #elif defined(CONFIG_CHIP_M32310) | |
101 | #warning do_gettimeoffse not implemented | |
102 | #else | |
103 | #error no chip configuration | |
104 | #endif | |
105 | ||
95ad759c | 106 | return elapsed_time * 1000; |
1da177e4 LT |
107 | } |
108 | ||
1da177e4 LT |
109 | /* |
110 | * timer_interrupt() needs to keep up the real-time clock, | |
7bde2ab7 | 111 | * as well as call the "xtime_update()" routine every clocktick |
1da177e4 | 112 | */ |
81e48073 | 113 | static irqreturn_t timer_interrupt(int irq, void *dev_id) |
1da177e4 LT |
114 | { |
115 | #ifndef CONFIG_SMP | |
9c8e7f5c | 116 | profile_tick(CPU_PROFILING); |
1da177e4 | 117 | #endif |
7bde2ab7 | 118 | xtime_update(1); |
1da177e4 LT |
119 | |
120 | #ifndef CONFIG_SMP | |
9c8e7f5c | 121 | update_process_times(user_mode(get_irq_regs())); |
1da177e4 | 122 | #endif |
1da177e4 LT |
123 | /* As we return to user mode fire off the other CPU schedulers.. |
124 | this is basically because we don't yet share IRQ's around. | |
125 | This message is rigged to be safe on the 386 - basically it's | |
126 | a hack, so don't look closely for now.. */ | |
127 | ||
128 | #ifdef CONFIG_SMP | |
9c8e7f5c | 129 | smp_local_timer_interrupt(); |
2757a71c | 130 | smp_send_timer(); |
1da177e4 | 131 | #endif |
1da177e4 LT |
132 | |
133 | return IRQ_HANDLED; | |
134 | } | |
135 | ||
81e48073 | 136 | static struct irqaction irq0 = { |
977676ac | 137 | .handler = timer_interrupt, |
977676ac TG |
138 | .name = "MFT2", |
139 | }; | |
1da177e4 | 140 | |
94469471 | 141 | void read_persistent_clock(struct timespec *ts) |
1da177e4 LT |
142 | { |
143 | unsigned int epoch, year, mon, day, hour, min, sec; | |
144 | ||
145 | sec = min = hour = day = mon = year = 0; | |
146 | epoch = 0; | |
147 | ||
148 | year = 23; | |
149 | mon = 4; | |
150 | day = 17; | |
151 | ||
152 | /* Attempt to guess the epoch. This is the same heuristic as in rtc.c | |
153 | so no stupid things will happen to timekeeping. Who knows, maybe | |
154 | Ultrix also uses 1952 as epoch ... */ | |
155 | if (year > 10 && year < 44) | |
156 | epoch = 1980; | |
157 | else if (year < 96) | |
158 | epoch = 1952; | |
159 | year += epoch; | |
160 | ||
94469471 JS |
161 | ts->tv_sec = mktime(year, mon, day, hour, min, sec); |
162 | ts->tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); | |
163 | } | |
1da177e4 | 164 | |
94469471 JS |
165 | |
166 | void __init time_init(void) | |
167 | { | |
7b1f6207 SW |
168 | arch_gettimeoffset = m32r_gettimeoffset; |
169 | ||
1da177e4 LT |
170 | #if defined(CONFIG_CHIP_M32102) || defined(CONFIG_CHIP_XNUX2) \ |
171 | || defined(CONFIG_CHIP_VDEC2) || defined(CONFIG_CHIP_M32700) \ | |
9287d95e | 172 | || defined(CONFIG_CHIP_OPSP) || defined(CONFIG_CHIP_M32104) |
1da177e4 LT |
173 | |
174 | /* M32102 MFT setup */ | |
175 | setup_irq(M32R_IRQ_MFT2, &irq0); | |
176 | { | |
177 | unsigned long bus_clock; | |
178 | unsigned short divide; | |
179 | ||
180 | bus_clock = boot_cpu_data.bus_clock; | |
181 | divide = boot_cpu_data.timer_divide; | |
56023585 | 182 | latch = DIV_ROUND_CLOSEST(bus_clock/divide, HZ); |
1da177e4 LT |
183 | |
184 | printk("Timer start : latch = %ld\n", latch); | |
185 | ||
186 | outl((M32R_MFTMOD_CC_MASK | M32R_MFTMOD_TCCR \ | |
187 | |M32R_MFTMOD_CSSEL011), M32R_MFT2MOD_PORTL); | |
188 | outl(latch, M32R_MFT2RLD_PORTL); | |
189 | outl(latch, M32R_MFT2CUT_PORTL); | |
190 | outl(0, M32R_MFT2CMPRLD_PORTL); | |
191 | outl((M32R_MFTCR_MFT2MSK|M32R_MFTCR_MFT2EN), M32R_MFTCR_PORTL); | |
192 | } | |
193 | ||
194 | #elif defined(CONFIG_CHIP_M32310) | |
195 | #warning time_init not implemented | |
196 | #else | |
197 | #error no chip configuration | |
198 | #endif | |
199 | } |