1 /*
2  *  rtc.c, RTC(has only timer function) routines for NEC VR4100 series.
3  *
4  *  Copyright (C) 2003  Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
5  *
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.
10  *
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.
15  *
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
19  */
20 #include <linux/init.h>
21 #include <linux/irq.h>
22 #include <linux/types.h>
23 
24 #include <asm/io.h>
25 #include <asm/time.h>
26 #include <asm/vr41xx/vr41xx.h>
27 
28 static uint32_t rtc1_base;
29 static uint32_t rtc2_base;
30 
31 static uint64_t previous_elapsedtime;
32 static unsigned int remainder_per_sec;
33 static unsigned int cycles_per_sec;
34 static unsigned int cycles_per_jiffy;
35 static unsigned long epoch_time;
36 
37 #define CLOCK_TICK_RATE		32768	/* 32.768kHz */
38 
39 #define CYCLES_PER_JIFFY	(CLOCK_TICK_RATE / HZ)
40 #define REMAINDER_PER_SEC	(CLOCK_TICK_RATE - (CYCLES_PER_JIFFY * HZ))
41 #define CYCLES_PER_100USEC	((CLOCK_TICK_RATE + (10000 / 2)) / 10000)
42 
43 #define ETIMELREG_TYPE1		KSEG1ADDR(0x0b0000c0)
44 #define TCLKLREG_TYPE1		KSEG1ADDR(0x0b0001c0)
45 
46 #define ETIMELREG_TYPE2		KSEG1ADDR(0x0f000100)
47 #define TCLKLREG_TYPE2		KSEG1ADDR(0x0f000120)
48 
49 /* RTC 1 registers */
50 #define ETIMELREG		0x00
51 #define ETIMEMREG		0x02
52 #define ETIMEHREG		0x04
53 /* RFU */
54 #define ECMPLREG		0x08
55 #define ECMPMREG		0x0a
56 #define ECMPHREG		0x0c
57 /* RFU */
58 #define RTCL1LREG		0x10
59 #define RTCL1HREG		0x12
60 #define RTCL1CNTLREG		0x14
61 #define RTCL1CNTHREG		0x16
62 #define RTCL2LREG		0x18
63 #define RTCL2HREG		0x1a
64 #define RTCL2CNTLREG		0x1c
65 #define RTCL2CNTHREG		0x1e
66 
67 /* RTC 2 registers */
68 #define TCLKLREG		0x00
69 #define TCLKHREG		0x02
70 #define TCLKCNTLREG		0x04
71 #define TCLKCNTHREG		0x06
72 /* RFU */
73 #define RTCINTREG		0x1e
74  #define TCLOCK_INT		0x08
75  #define RTCLONG2_INT		0x04
76  #define RTCLONG1_INT		0x02
77  #define ELAPSEDTIME_INT	0x01
78 
79 #define read_rtc1(offset)	readw(rtc1_base + (offset))
80 #define write_rtc1(val, offset)	writew((val), rtc1_base + (offset))
81 
82 #define read_rtc2(offset)	readw(rtc2_base + (offset))
83 #define write_rtc2(val, offset)	writew((val), rtc2_base + (offset))
84 
read_elapsedtime_counter(void)85 static inline uint64_t read_elapsedtime_counter(void)
86 {
87 	uint64_t first, second;
88 	uint32_t first_mid, first_low;
89 	uint32_t second_mid, second_low;
90 
91 	do {
92 		first_low = (uint32_t)read_rtc1(ETIMELREG);
93 		first_mid = (uint32_t)read_rtc1(ETIMEMREG);
94 		first = (uint64_t)read_rtc1(ETIMEHREG);
95 		second_low = (uint32_t)read_rtc1(ETIMELREG);
96 		second_mid = (uint32_t)read_rtc1(ETIMEMREG);
97 		second = (uint64_t)read_rtc1(ETIMEHREG);
98 	} while (first_low != second_low || first_mid != second_mid ||
99 	         first != second);
100 
101 	return (first << 32) | (uint64_t)((first_mid << 16) | first_low);
102 }
103 
write_elapsedtime_counter(uint64_t time)104 static inline void write_elapsedtime_counter(uint64_t time)
105 {
106 	write_rtc1((uint16_t)time, ETIMELREG);
107 	write_rtc1((uint16_t)(time >> 16), ETIMEMREG);
108 	write_rtc1((uint16_t)(time >> 32), ETIMEHREG);
109 }
110 
write_elapsedtime_compare(uint64_t time)111 static inline void write_elapsedtime_compare(uint64_t time)
112 {
113 	write_rtc1((uint16_t)time, ECMPLREG);
114 	write_rtc1((uint16_t)(time >> 16), ECMPMREG);
115 	write_rtc1((uint16_t)(time >> 32), ECMPHREG);
116 }
117 
vr41xx_set_rtclong1_cycle(uint32_t cycles)118 void vr41xx_set_rtclong1_cycle(uint32_t cycles)
119 {
120 	write_rtc1((uint16_t)cycles, RTCL1LREG);
121 	write_rtc1((uint16_t)(cycles >> 16), RTCL1HREG);
122 }
123 
vr41xx_read_rtclong1_counter(void)124 uint32_t vr41xx_read_rtclong1_counter(void)
125 {
126 	uint32_t first_high, first_low;
127 	uint32_t second_high, second_low;
128 
129 	do {
130 		first_low = (uint32_t)read_rtc1(RTCL1CNTLREG);
131 		first_high = (uint32_t)read_rtc1(RTCL1CNTHREG);
132 		second_low = (uint32_t)read_rtc1(RTCL1CNTLREG);
133 		second_high = (uint32_t)read_rtc1(RTCL1CNTHREG);
134 	} while (first_low != second_low || first_high != second_high);
135 
136 	return (first_high << 16) | first_low;
137 }
138 
vr41xx_set_rtclong2_cycle(uint32_t cycles)139 void vr41xx_set_rtclong2_cycle(uint32_t cycles)
140 {
141 	write_rtc1((uint16_t)cycles, RTCL2LREG);
142 	write_rtc1((uint16_t)(cycles >> 16), RTCL2HREG);
143 }
144 
vr41xx_read_rtclong2_counter(void)145 uint32_t vr41xx_read_rtclong2_counter(void)
146 {
147 	uint32_t first_high, first_low;
148 	uint32_t second_high, second_low;
149 
150 	do {
151 		first_low = (uint32_t)read_rtc1(RTCL2CNTLREG);
152 		first_high = (uint32_t)read_rtc1(RTCL2CNTHREG);
153 		second_low = (uint32_t)read_rtc1(RTCL2CNTLREG);
154 		second_high = (uint32_t)read_rtc1(RTCL2CNTHREG);
155 	} while (first_low != second_low || first_high != second_high);
156 
157 	return (first_high << 16) | first_low;
158 }
159 
vr41xx_set_tclock_cycle(uint32_t cycles)160 void vr41xx_set_tclock_cycle(uint32_t cycles)
161 {
162 	write_rtc2((uint16_t)cycles, TCLKLREG);
163 	write_rtc2((uint16_t)(cycles >> 16), TCLKHREG);
164 }
165 
vr41xx_read_tclock_counter(void)166 uint32_t vr41xx_read_tclock_counter(void)
167 {
168 	uint32_t first_high, first_low;
169 	uint32_t second_high, second_low;
170 
171 	do {
172 		first_low = (uint32_t)read_rtc2(TCLKCNTLREG);
173 		first_high = (uint32_t)read_rtc2(TCLKCNTHREG);
174 		second_low = (uint32_t)read_rtc2(TCLKCNTLREG);
175 		second_high = (uint32_t)read_rtc2(TCLKCNTHREG);
176 	} while (first_low != second_low || first_high != second_high);
177 
178 	return (first_high << 16) | first_low;
179 }
180 
vr41xx_timer_ack(void)181 static void vr41xx_timer_ack(void)
182 {
183 	uint64_t cur;
184 
185 	write_rtc2(ELAPSEDTIME_INT, RTCINTREG);
186 
187 	previous_elapsedtime += (uint64_t)cycles_per_jiffy;
188 	cycles_per_sec += cycles_per_jiffy;
189 
190 	if (cycles_per_sec >= CLOCK_TICK_RATE) {
191 		cycles_per_sec = 0;
192 		remainder_per_sec = REMAINDER_PER_SEC;
193 	}
194 
195 	cycles_per_jiffy = 0;
196 
197 	do {
198 		cycles_per_jiffy += CYCLES_PER_JIFFY;
199 		if (remainder_per_sec > 0) {
200 			cycles_per_jiffy++;
201 			remainder_per_sec--;
202 		}
203 
204 		cur = read_elapsedtime_counter();
205 	} while (cur >= previous_elapsedtime + (uint64_t)cycles_per_jiffy);
206 
207 	write_elapsedtime_compare(previous_elapsedtime + (uint64_t)cycles_per_jiffy);
208 }
209 
vr41xx_hpt_init(unsigned int count)210 static void vr41xx_hpt_init(unsigned int count)
211 {
212 }
213 
vr41xx_hpt_read(void)214 static unsigned int vr41xx_hpt_read(void)
215 {
216 	uint64_t cur;
217 
218 	cur = read_elapsedtime_counter();
219 
220 	return (unsigned int)cur;
221 }
222 
vr41xx_gettimeoffset(void)223 static unsigned long vr41xx_gettimeoffset(void)
224 {
225 	uint64_t cur;
226 	unsigned long gap;
227 
228 	cur = read_elapsedtime_counter();
229 	gap = (unsigned long)(cur - previous_elapsedtime);
230 	gap = gap / CYCLES_PER_100USEC * 100;	/* usec */
231 
232 	return gap;
233 }
234 
vr41xx_get_time(void)235 static unsigned long vr41xx_get_time(void)
236 {
237 	uint64_t counts;
238 
239 	counts = read_elapsedtime_counter();
240 	counts >>= 15;
241 
242 	return epoch_time + (unsigned long)counts;
243 
244 }
245 
vr41xx_set_time(unsigned long sec)246 static int vr41xx_set_time(unsigned long sec)
247 {
248 	if (sec < epoch_time)
249 		return -EINVAL;
250 
251 	sec -= epoch_time;
252 
253 	write_elapsedtime_counter((uint64_t)sec << 15);
254 
255 	return 0;
256 }
257 
vr41xx_set_epoch_time(unsigned long time)258 void vr41xx_set_epoch_time(unsigned long time)
259 {
260 	epoch_time = time;
261 }
262 
vr41xx_time_init(void)263 void __init vr41xx_time_init(void)
264 {
265 	switch (current_cpu_data.cputype) {
266 	case CPU_VR4111:
267 	case CPU_VR4121:
268 		rtc1_base = ETIMELREG_TYPE1;
269 		rtc2_base = TCLKLREG_TYPE1;
270 		break;
271 	case CPU_VR4122:
272 	case CPU_VR4131:
273 	case CPU_VR4133:
274 		rtc1_base = ETIMELREG_TYPE2;
275 		rtc2_base = TCLKLREG_TYPE2;
276 		break;
277 	default:
278 		panic("Unexpected CPU of NEC VR4100 series");
279 		break;
280 	}
281 
282 	mips_timer_ack = vr41xx_timer_ack;
283 
284 	mips_hpt_init = vr41xx_hpt_init;
285 	mips_hpt_read = vr41xx_hpt_read;
286 	mips_hpt_frequency = CLOCK_TICK_RATE;
287 
288 	if (epoch_time == 0)
289 		epoch_time = mktime(1970, 1, 1, 0, 0, 0);
290 
291 	rtc_get_time = vr41xx_get_time;
292 	rtc_set_time = vr41xx_set_time;
293 }
294 
vr41xx_timer_setup(struct irqaction * irq)295 void __init vr41xx_timer_setup(struct irqaction *irq)
296 {
297 	do_gettimeoffset = vr41xx_gettimeoffset;
298 
299 	remainder_per_sec = REMAINDER_PER_SEC;
300 	cycles_per_jiffy = CYCLES_PER_JIFFY;
301 
302 	if (remainder_per_sec > 0) {
303 		cycles_per_jiffy++;
304 		remainder_per_sec--;
305 	}
306 
307 	previous_elapsedtime = read_elapsedtime_counter();
308 	write_elapsedtime_compare(previous_elapsedtime + (uint64_t)cycles_per_jiffy);
309 	write_rtc2(ELAPSEDTIME_INT, RTCINTREG);
310 
311 	setup_irq(ELAPSEDTIME_IRQ, irq);
312 }
313