2 * rtc.c, RTC(has only timer function) routines for NEC VR4100 series.
4 * Copyright (C) 2003-2004 Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 #include <linux/init.h>
21 #include <linux/irq.h>
22 #include <linux/smp.h>
23 #include <linux/types.h>
27 #include <asm/vr41xx/vr41xx.h>
29 static uint32_t rtc1_base;
30 static uint32_t rtc2_base;
32 static uint64_t previous_elapsedtime;
33 static unsigned int remainder_per_sec;
34 static unsigned int cycles_per_sec;
35 static unsigned int cycles_per_jiffy;
36 static unsigned long epoch_time;
38 #define CYCLES_PER_JIFFY (CLOCK_TICK_RATE / HZ)
39 #define REMAINDER_PER_SEC (CLOCK_TICK_RATE - (CYCLES_PER_JIFFY * HZ))
40 #define CYCLES_PER_100USEC ((CLOCK_TICK_RATE + (10000 / 2)) / 10000)
42 #define ETIMELREG_TYPE1 KSEG1ADDR(0x0b0000c0)
43 #define TCLKLREG_TYPE1 KSEG1ADDR(0x0b0001c0)
45 #define ETIMELREG_TYPE2 KSEG1ADDR(0x0f000100)
46 #define TCLKLREG_TYPE2 KSEG1ADDR(0x0f000120)
49 #define ETIMELREG 0x00
50 #define ETIMEMREG 0x02
51 #define ETIMEHREG 0x04
57 #define RTCL1LREG 0x10
58 #define RTCL1HREG 0x12
59 #define RTCL1CNTLREG 0x14
60 #define RTCL1CNTHREG 0x16
61 #define RTCL2LREG 0x18
62 #define RTCL2HREG 0x1a
63 #define RTCL2CNTLREG 0x1c
64 #define RTCL2CNTHREG 0x1e
69 #define TCLKCNTLREG 0x04
70 #define TCLKCNTHREG 0x06
72 #define RTCINTREG 0x1e
73 #define TCLOCK_INT 0x08
74 #define RTCLONG2_INT 0x04
75 #define RTCLONG1_INT 0x02
76 #define ELAPSEDTIME_INT 0x01
78 #define read_rtc1(offset) readw(rtc1_base + (offset))
79 #define write_rtc1(val, offset) writew((val), rtc1_base + (offset))
81 #define read_rtc2(offset) readw(rtc2_base + (offset))
82 #define write_rtc2(val, offset) writew((val), rtc2_base + (offset))
84 static inline uint64_t read_elapsedtime_counter(void)
86 uint64_t first, second;
87 uint32_t first_mid, first_low;
88 uint32_t second_mid, second_low;
91 first_low = (uint32_t)read_rtc1(ETIMELREG);
92 first_mid = (uint32_t)read_rtc1(ETIMEMREG);
93 first = (uint64_t)read_rtc1(ETIMEHREG);
94 second_low = (uint32_t)read_rtc1(ETIMELREG);
95 second_mid = (uint32_t)read_rtc1(ETIMEMREG);
96 second = (uint64_t)read_rtc1(ETIMEHREG);
97 } while (first_low != second_low || first_mid != second_mid ||
100 return (first << 32) | (uint64_t)((first_mid << 16) | first_low);
103 static inline void write_elapsedtime_counter(uint64_t time)
105 write_rtc1((uint16_t)time, ETIMELREG);
106 write_rtc1((uint16_t)(time >> 16), ETIMEMREG);
107 write_rtc1((uint16_t)(time >> 32), ETIMEHREG);
110 static inline void write_elapsedtime_compare(uint64_t time)
112 write_rtc1((uint16_t)time, ECMPLREG);
113 write_rtc1((uint16_t)(time >> 16), ECMPMREG);
114 write_rtc1((uint16_t)(time >> 32), ECMPHREG);
117 void vr41xx_set_rtclong1_cycle(uint32_t cycles)
119 write_rtc1((uint16_t)cycles, RTCL1LREG);
120 write_rtc1((uint16_t)(cycles >> 16), RTCL1HREG);
123 uint32_t vr41xx_read_rtclong1_counter(void)
125 uint32_t first_high, first_low;
126 uint32_t second_high, second_low;
129 first_low = (uint32_t)read_rtc1(RTCL1CNTLREG);
130 first_high = (uint32_t)read_rtc1(RTCL1CNTHREG);
131 second_low = (uint32_t)read_rtc1(RTCL1CNTLREG);
132 second_high = (uint32_t)read_rtc1(RTCL1CNTHREG);
133 } while (first_low != second_low || first_high != second_high);
135 return (first_high << 16) | first_low;
138 void vr41xx_set_rtclong2_cycle(uint32_t cycles)
140 write_rtc1((uint16_t)cycles, RTCL2LREG);
141 write_rtc1((uint16_t)(cycles >> 16), RTCL2HREG);
144 uint32_t vr41xx_read_rtclong2_counter(void)
146 uint32_t first_high, first_low;
147 uint32_t second_high, second_low;
150 first_low = (uint32_t)read_rtc1(RTCL2CNTLREG);
151 first_high = (uint32_t)read_rtc1(RTCL2CNTHREG);
152 second_low = (uint32_t)read_rtc1(RTCL2CNTLREG);
153 second_high = (uint32_t)read_rtc1(RTCL2CNTHREG);
154 } while (first_low != second_low || first_high != second_high);
156 return (first_high << 16) | first_low;
159 void vr41xx_set_tclock_cycle(uint32_t cycles)
161 write_rtc2((uint16_t)cycles, TCLKLREG);
162 write_rtc2((uint16_t)(cycles >> 16), TCLKHREG);
165 uint32_t vr41xx_read_tclock_counter(void)
167 uint32_t first_high, first_low;
168 uint32_t second_high, second_low;
171 first_low = (uint32_t)read_rtc2(TCLKCNTLREG);
172 first_high = (uint32_t)read_rtc2(TCLKCNTHREG);
173 second_low = (uint32_t)read_rtc2(TCLKCNTLREG);
174 second_high = (uint32_t)read_rtc2(TCLKCNTHREG);
175 } while (first_low != second_low || first_high != second_high);
177 return (first_high << 16) | first_low;
180 static void vr41xx_timer_ack(void)
184 write_rtc2(ELAPSEDTIME_INT, RTCINTREG);
186 previous_elapsedtime += (uint64_t)cycles_per_jiffy;
187 cycles_per_sec += cycles_per_jiffy;
189 if (cycles_per_sec >= CLOCK_TICK_RATE) {
191 remainder_per_sec = REMAINDER_PER_SEC;
194 cycles_per_jiffy = 0;
197 cycles_per_jiffy += CYCLES_PER_JIFFY;
198 if (remainder_per_sec > 0) {
203 cur = read_elapsedtime_counter();
204 } while (cur >= previous_elapsedtime + (uint64_t)cycles_per_jiffy);
206 write_elapsedtime_compare(previous_elapsedtime + (uint64_t)cycles_per_jiffy);
209 static void vr41xx_hpt_init(unsigned int count)
213 static unsigned int vr41xx_hpt_read(void)
217 cur = read_elapsedtime_counter();
219 return (unsigned int)cur;
222 static unsigned long vr41xx_gettimeoffset(void)
227 cur = read_elapsedtime_counter();
228 gap = (unsigned long)(cur - previous_elapsedtime);
229 gap = gap / CYCLES_PER_100USEC * 100; /* usec */
234 static unsigned long vr41xx_get_time(void)
238 counts = read_elapsedtime_counter();
241 return epoch_time + (unsigned long)counts;
245 static int vr41xx_set_time(unsigned long sec)
247 if (sec < epoch_time)
252 write_elapsedtime_counter((uint64_t)sec << 15);
257 void vr41xx_set_epoch_time(unsigned long time)
262 static void __init vr41xx_time_init(void)
264 switch (current_cpu_data.cputype) {
267 rtc1_base = ETIMELREG_TYPE1;
268 rtc2_base = TCLKLREG_TYPE1;
273 rtc1_base = ETIMELREG_TYPE2;
274 rtc2_base = TCLKLREG_TYPE2;
277 panic("Unexpected CPU of NEC VR4100 series");
281 mips_timer_ack = vr41xx_timer_ack;
283 mips_hpt_init = vr41xx_hpt_init;
284 mips_hpt_read = vr41xx_hpt_read;
285 mips_hpt_frequency = CLOCK_TICK_RATE;
288 epoch_time = mktime(1970, 1, 1, 0, 0, 0);
290 rtc_get_time = vr41xx_get_time;
291 rtc_set_time = vr41xx_set_time;
294 static void __init vr41xx_timer_setup(struct irqaction *irq)
296 do_gettimeoffset = vr41xx_gettimeoffset;
298 remainder_per_sec = REMAINDER_PER_SEC;
299 cycles_per_jiffy = CYCLES_PER_JIFFY;
301 if (remainder_per_sec > 0) {
306 previous_elapsedtime = read_elapsedtime_counter();
307 write_elapsedtime_compare(previous_elapsedtime + (uint64_t)cycles_per_jiffy);
308 write_rtc2(ELAPSEDTIME_INT, RTCINTREG);
310 setup_irq(ELAPSEDTIME_IRQ, irq);
313 static int __init vr41xx_rtc_init(void)
315 board_time_init = vr41xx_time_init;
316 board_timer_setup = vr41xx_timer_setup;
321 early_initcall(vr41xx_rtc_init);